From 0de103c1cdf1e4c40cfad4e233a42a6d1165953d Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Tue, 6 Nov 2007 22:29:20 +0000 Subject: [PATCH] Filling in branch from trunk --- CMake/macros.cmake | 81 + CMakeLists.txt | 408 + COPYING | 3 + Makefile | 61 + README | 45 + SConstruct | 447 + bin/.blender/.Blanguages | 21 + bin/.blender/.bfont.ttf | Bin 0 -> 65932 bytes blenderplayer/CMakeLists.txt | 124 + config/darwin-config.py | 185 + config/linux2-config.py | 175 + config/linuxcross-config.py | 139 + config/openbsd3-config.py | 160 + config/sunos5-config.py | 171 + config/win32-mingw-config.py | 160 + config/win32-vc-config.py | 175 + doc/BL-license.txt | 35 + doc/Doxyfile | 943 + doc/GPL-license.txt | 340 + doc/README.windows-gcc | 123 + doc/bf-members.txt | 1393 ++ doc/blender-cmake.txt | 156 + doc/blender-guardedalloc.txt | 57 + doc/blender-scons-dev.txt | 194 + doc/blender-scons.txt | 236 + doc/doxygen.main | 63 + doc/interface_API.txt | 515 + extern/CMakeLists.txt | 45 + extern/Makefile | 76 + extern/SConscript | 18 + extern/bFTGL/CMakeLists.txt | 35 + extern/bFTGL/COPYING.txt | 481 + extern/bFTGL/README.txt | 51 + extern/bFTGL/SConscript | 30 + extern/bFTGL/cleanup | 4 + extern/bFTGL/include/FTBBox.h | 124 + extern/bFTGL/include/FTBitmapGlyph.h | 76 + extern/bFTGL/include/FTBufferGlyph.h | 76 + extern/bFTGL/include/FTCharToGlyphIndexMap.h | 130 + extern/bFTGL/include/FTCharmap.h | 136 + extern/bFTGL/include/FTContour.h | 88 + extern/bFTGL/include/FTExtrdGlyph.h | 71 + extern/bFTGL/include/FTFace.h | 149 + extern/bFTGL/include/FTFont.h | 260 + extern/bFTGL/include/FTGL.h | 96 + extern/bFTGL/include/FTGLBitmapFont.h | 65 + extern/bFTGL/include/FTGLBufferFont.h | 76 + extern/bFTGL/include/FTGLExtrdFont.h | 55 + extern/bFTGL/include/FTGLOutlineFont.h | 64 + extern/bFTGL/include/FTGLPixmapFont.h | 68 + extern/bFTGL/include/FTGLPolygonFont.h | 53 + extern/bFTGL/include/FTGLTextureFont.h | 151 + extern/bFTGL/include/FTGlyph.h | 89 + extern/bFTGL/include/FTGlyphContainer.h | 127 + extern/bFTGL/include/FTLibrary.h | 97 + extern/bFTGL/include/FTList.h | 112 + extern/bFTGL/include/FTOutlineGlyph.h | 54 + extern/bFTGL/include/FTPixmapGlyph.h | 68 + extern/bFTGL/include/FTPoint.h | 85 + extern/bFTGL/include/FTPolyGlyph.h | 55 + extern/bFTGL/include/FTSize.h | 132 + extern/bFTGL/include/FTTextureGlyph.h | 89 + extern/bFTGL/include/FTVector.h | 190 + extern/bFTGL/include/FTVectoriser.h | 275 + extern/bFTGL/license.txt | 27 + .../make/msvc_7_0/ftgl_static_lib.vcproj | 406 + extern/bFTGL/src/FTBitmapGlyph.cpp | 66 + extern/bFTGL/src/FTBufferGlyph.cpp | 59 + extern/bFTGL/src/FTCharmap.cpp | 62 + extern/bFTGL/src/FTContour.cpp | 149 + extern/bFTGL/src/FTExtrdGlyph.cpp | 141 + extern/bFTGL/src/FTFace.cpp | 154 + extern/bFTGL/src/FTFont.cpp | 271 + extern/bFTGL/src/FTGLBitmapFont.cpp | 66 + extern/bFTGL/src/FTGLBufferFont.cpp | 53 + extern/bFTGL/src/FTGLExtrdFont.cpp | 35 + extern/bFTGL/src/FTGLOutlineFont.cpp | 66 + extern/bFTGL/src/FTGLPixmapFont.cpp | 68 + extern/bFTGL/src/FTGLPolygonFont.cpp | 33 + extern/bFTGL/src/FTGLTextureFont.cpp | 178 + extern/bFTGL/src/FTGlyph.cpp | 17 + extern/bFTGL/src/FTGlyphContainer.cpp | 93 + extern/bFTGL/src/FTLibrary.cpp | 64 + extern/bFTGL/src/FTOutlineGlyph.cpp | 57 + extern/bFTGL/src/FTPixmapGlyph.cpp | 109 + extern/bFTGL/src/FTPoint.cpp | 14 + extern/bFTGL/src/FTPolyGlyph.cpp | 62 + extern/bFTGL/src/FTSize.cpp | 105 + extern/bFTGL/src/FTTextureGlyph.cpp | 87 + extern/bFTGL/src/FTVectoriser.cpp | 229 + extern/bFTGL/src/Makefile | 62 + extern/bFTGL/win32_vcpp/README_WIN32.txt | 206 + extern/bFTGL/win32_vcpp/ftgl.dsw | 92 + extern/bFTGL/win32_vcpp/ftgl_dll/ftgl_dll.dsp | 357 + .../ftgl_static_lib/ftgl_static_lib.dsp | 342 + .../win32_vcpp/unit_tests/unit_tests.dsp | 168 + extern/bullet2/CMakeLists.txt | 46 + extern/bullet2/Makefile | 64 + .../bullet2/make/msvc_7_0/Bullet_vc7.vcproj | 921 + extern/bullet2/readme.txt | 12 + .../BroadphaseCollision/btAxisSweep3.cpp | 660 + .../BroadphaseCollision/btAxisSweep3.h | 138 + .../btBroadphaseInterface.h | 40 + .../BroadphaseCollision/btBroadphaseProxy.cpp | 17 + .../BroadphaseCollision/btBroadphaseProxy.h | 204 + .../btCollisionAlgorithm.cpp | 23 + .../btCollisionAlgorithm.h | 77 + .../BroadphaseCollision/btDispatcher.cpp | 22 + .../BroadphaseCollision/btDispatcher.h | 93 + .../btOverlappingPairCache.cpp | 196 + .../btOverlappingPairCache.h | 120 + .../btSimpleBroadphase.cpp | 222 + .../BroadphaseCollision/btSimpleBroadphase.h | 95 + .../src/BulletCollision/CMakeLists.txt | 60 + .../SphereTriangleDetector.cpp | 200 + .../SphereTriangleDetector.h | 49 + .../CollisionDispatch/btCollisionCreateFunc.h | 46 + .../btCollisionDispatcher.cpp | 367 + .../CollisionDispatch/btCollisionDispatcher.h | 135 + .../CollisionDispatch/btCollisionObject.cpp | 57 + .../CollisionDispatch/btCollisionObject.h | 346 + .../CollisionDispatch/btCollisionWorld.cpp | 362 + .../CollisionDispatch/btCollisionWorld.h | 255 + .../btCompoundCollisionAlgorithm.cpp | 140 + .../btCompoundCollisionAlgorithm.h | 64 + .../btConvexConcaveCollisionAlgorithm.cpp | 312 + .../btConvexConcaveCollisionAlgorithm.h | 111 + .../btConvexConvexAlgorithm.cpp | 254 + .../btConvexConvexAlgorithm.h | 76 + .../btEmptyCollisionAlgorithm.cpp | 34 + .../btEmptyCollisionAlgorithm.h | 48 + .../CollisionDispatch/btManifoldResult.cpp | 109 + .../CollisionDispatch/btManifoldResult.h | 77 + .../btSimulationIslandManager.cpp | 357 + .../btSimulationIslandManager.h | 61 + .../btSphereBoxCollisionAlgorithm.cpp | 249 + .../btSphereBoxCollisionAlgorithm.h | 64 + .../btSphereSphereCollisionAlgorithm.cpp | 85 + .../btSphereSphereCollisionAlgorithm.h | 56 + .../btSphereTriangleCollisionAlgorithm.cpp | 76 + .../btSphereTriangleCollisionAlgorithm.h | 59 + .../CollisionDispatch/btUnionFind.cpp | 83 + .../CollisionDispatch/btUnionFind.h | 124 + .../CollisionShapes/btBoxShape.cpp | 57 + .../CollisionShapes/btBoxShape.h | 293 + .../btBvhTriangleMeshShape.cpp | 173 + .../CollisionShapes/btBvhTriangleMeshShape.h | 75 + .../CollisionShapes/btCapsuleShape.cpp | 146 + .../CollisionShapes/btCapsuleShape.h | 60 + .../CollisionShapes/btCollisionMargin.h | 26 + .../CollisionShapes/btCollisionShape.cpp | 85 + .../CollisionShapes/btCollisionShape.h | 94 + .../CollisionShapes/btCompoundShape.cpp | 100 + .../CollisionShapes/btCompoundShape.h | 117 + .../CollisionShapes/btConcaveShape.cpp | 28 + .../CollisionShapes/btConcaveShape.h | 50 + .../CollisionShapes/btConeShape.cpp | 133 + .../CollisionShapes/btConeShape.h | 103 + .../CollisionShapes/btConvexHullShape.cpp | 179 + .../CollisionShapes/btConvexHullShape.h | 76 + .../CollisionShapes/btConvexShape.cpp | 77 + .../CollisionShapes/btConvexShape.h | 127 + .../btConvexTriangleMeshShape.cpp | 205 + .../btConvexTriangleMeshShape.h | 51 + .../CollisionShapes/btCylinderShape.cpp | 206 + .../CollisionShapes/btCylinderShape.h | 138 + .../CollisionShapes/btEmptyShape.cpp | 49 + .../CollisionShapes/btEmptyShape.h | 70 + .../btHeightfieldTerrainShape.cpp | 339 + .../btHeightfieldTerrainShape.h | 88 + .../CollisionShapes/btMinkowskiSumShape.cpp | 57 + .../CollisionShapes/btMinkowskiSumShape.h | 62 + .../CollisionShapes/btMultiSphereShape.cpp | 148 + .../CollisionShapes/btMultiSphereShape.h | 74 + .../CollisionShapes/btOptimizedBvh.cpp | 845 + .../CollisionShapes/btOptimizedBvh.h | 330 + .../btPolyhedralConvexShape.cpp | 148 + .../CollisionShapes/btPolyhedralConvexShape.h | 93 + .../CollisionShapes/btSphereShape.cpp | 77 + .../CollisionShapes/btSphereShape.h | 63 + .../CollisionShapes/btStaticPlaneShape.cpp | 105 + .../CollisionShapes/btStaticPlaneShape.h | 61 + .../btStridingMeshInterface.cpp | 124 + .../CollisionShapes/btStridingMeshInterface.h | 89 + .../CollisionShapes/btTetrahedronShape.cpp | 195 + .../CollisionShapes/btTetrahedronShape.h | 75 + .../CollisionShapes/btTriangleBuffer.cpp | 42 + .../CollisionShapes/btTriangleBuffer.h | 61 + .../CollisionShapes/btTriangleCallback.cpp | 28 + .../CollisionShapes/btTriangleCallback.h | 40 + .../btTriangleIndexVertexArray.cpp | 65 + .../btTriangleIndexVertexArray.h | 97 + .../CollisionShapes/btTriangleMesh.cpp | 60 + .../CollisionShapes/btTriangleMesh.h | 75 + .../CollisionShapes/btTriangleMeshShape.cpp | 203 + .../CollisionShapes/btTriangleMeshShape.h | 78 + .../CollisionShapes/btTriangleShape.h | 179 + extern/bullet2/src/BulletCollision/Doxyfile | 746 + .../btContinuousConvexCollision.cpp | 200 + .../btContinuousConvexCollision.h | 52 + .../NarrowPhaseCollision/btConvexCast.cpp | 20 + .../NarrowPhaseCollision/btConvexCast.h | 71 + .../btConvexPenetrationDepthSolver.h | 43 + .../btDiscreteCollisionDetectorInterface.h | 88 + .../NarrowPhaseCollision/btGjkConvexCast.cpp | 174 + .../NarrowPhaseCollision/btGjkConvexCast.h | 50 + .../NarrowPhaseCollision/btGjkEpa.cpp | 628 + .../NarrowPhaseCollision/btGjkEpa.h | 53 + .../btGjkEpaPenetrationDepthSolver.cpp | 50 + .../btGjkEpaPenetrationDepthSolver.h | 39 + .../btGjkPairDetector.cpp | 299 + .../NarrowPhaseCollision/btGjkPairDetector.h | 85 + .../NarrowPhaseCollision/btManifoldPoint.h | 99 + .../btMinkowskiPenetrationDepthSolver.cpp | 334 + .../btMinkowskiPenetrationDepthSolver.h | 37 + .../btPersistentManifold.cpp | 246 + .../btPersistentManifold.h | 161 + .../NarrowPhaseCollision/btPointCollector.h | 61 + .../btRaycastCallback.cpp | 101 + .../NarrowPhaseCollision/btRaycastCallback.h | 42 + .../btSimplexSolverInterface.h | 64 + .../btSubSimplexConvexCast.cpp | 139 + .../btSubSimplexConvexCast.h | 50 + .../btVoronoiSimplexSolver.cpp | 607 + .../btVoronoiSimplexSolver.h | 157 + .../bullet2/src/BulletDynamics/CMakeLists.txt | 19 + .../btConeTwistConstraint.cpp | 286 + .../ConstraintSolver/btConeTwistConstraint.h | 123 + .../ConstraintSolver/btConstraintSolver.h | 45 + .../ConstraintSolver/btContactConstraint.cpp | 417 + .../ConstraintSolver/btContactConstraint.h | 122 + .../ConstraintSolver/btContactSolverInfo.h | 47 + .../btGeneric6DofConstraint.cpp | 389 + .../btGeneric6DofConstraint.h | 120 + .../ConstraintSolver/btHingeConstraint.cpp | 229 + .../ConstraintSolver/btHingeConstraint.h | 81 + .../ConstraintSolver/btJacobianEntry.h | 156 + .../btPoint2PointConstraint.cpp | 116 + .../btPoint2PointConstraint.h | 77 + .../btSequentialImpulseConstraintSolver.cpp | 1158 ++ .../btSequentialImpulseConstraintSolver.h | 109 + .../btSolve2LinearConstraint.cpp | 255 + .../btSolve2LinearConstraint.h | 107 + .../ConstraintSolver/btSolverBody.h | 71 + .../ConstraintSolver/btSolverConstraint.h | 63 + .../ConstraintSolver/btTypedConstraint.cpp | 53 + .../ConstraintSolver/btTypedConstraint.h | 96 + .../Dynamics/btDiscreteDynamicsWorld.cpp | 954 + .../Dynamics/btDiscreteDynamicsWorld.h | 157 + .../BulletDynamics/Dynamics/btDynamicsWorld.h | 78 + .../BulletDynamics/Dynamics/btRigidBody.cpp | 345 + .../src/BulletDynamics/Dynamics/btRigidBody.h | 357 + .../Dynamics/btSimpleDynamicsWorld.cpp | 211 + .../Dynamics/btSimpleDynamicsWorld.h | 82 + .../Vehicle/btRaycastVehicle.cpp | 733 + .../BulletDynamics/Vehicle/btRaycastVehicle.h | 201 + .../Vehicle/btVehicleRaycaster.h | 35 + .../BulletDynamics/Vehicle/btWheelInfo.cpp | 56 + .../src/BulletDynamics/Vehicle/btWheelInfo.h | 116 + extern/bullet2/src/CMakeLists.txt | 1 + extern/bullet2/src/LinearMath/CMakeLists.txt | 10 + extern/bullet2/src/LinearMath/btAabbUtil2.h | 127 + .../src/LinearMath/btAlignedAllocator.cpp | 70 + .../src/LinearMath/btAlignedAllocator.h | 80 + .../src/LinearMath/btAlignedObjectArray.h | 367 + .../src/LinearMath/btDefaultMotionState.h | 38 + .../bullet2/src/LinearMath/btGeometryUtil.cpp | 178 + .../bullet2/src/LinearMath/btGeometryUtil.h | 41 + extern/bullet2/src/LinearMath/btIDebugDraw.h | 100 + extern/bullet2/src/LinearMath/btList.h | 73 + extern/bullet2/src/LinearMath/btMatrix3x3.h | 410 + extern/bullet2/src/LinearMath/btMinMax.h | 69 + extern/bullet2/src/LinearMath/btMotionState.h | 40 + extern/bullet2/src/LinearMath/btPoint3.h | 24 + extern/bullet2/src/LinearMath/btQuadWord.h | 139 + extern/bullet2/src/LinearMath/btQuaternion.h | 321 + extern/bullet2/src/LinearMath/btQuickprof.cpp | 38 + extern/bullet2/src/LinearMath/btQuickprof.h | 712 + extern/bullet2/src/LinearMath/btRandom.h | 42 + extern/bullet2/src/LinearMath/btScalar.h | 181 + extern/bullet2/src/LinearMath/btSimdMinMax.h | 41 + extern/bullet2/src/LinearMath/btStackAlloc.h | 106 + extern/bullet2/src/LinearMath/btTransform.h | 206 + .../bullet2/src/LinearMath/btTransformUtil.h | 138 + extern/bullet2/src/LinearMath/btVector3.h | 402 + extern/bullet2/src/Makefile | 71 + extern/bullet2/src/SConscript | 97 + extern/bullet2/src/btBulletCollisionCommon.h | 61 + extern/bullet2/src/btBulletDynamicsCommon.h | 42 + extern/make/msvc_7_0/build_install_all.vcproj | 85 + extern/make/msvc_7_0/extern.sln | 180 + extern/ode/Makefile | 113 + extern/ode/dist/INSTALL | 44 + extern/ode/dist/LICENSE-BSD.TXT | 34 + extern/ode/dist/LICENSE.TXT | 502 + extern/ode/dist/Makefile | 280 + extern/ode/dist/Makefile.deps | 456 + extern/ode/dist/README | 30 + extern/ode/dist/README_BLENDER | 18 + extern/ode/dist/config/README | 41 + extern/ode/dist/config/makefile.cygwin | 28 + extern/ode/dist/config/makefile.mingw | 28 + extern/ode/dist/config/makefile.msvc | 27 + extern/ode/dist/config/makefile.msvc-dll | 29 + extern/ode/dist/config/makefile.osx | 26 + extern/ode/dist/config/makefile.unix-gcc | 29 + extern/ode/dist/config/makefile.unix-generic | 24 + extern/ode/dist/config/msvcdefs.def | 228 + extern/ode/dist/config/user-settings | 31 + extern/ode/dist/config/user-settings.example | 31 + extern/ode/dist/configurator.c | 437 + extern/ode/dist/include/ode/README | 18 + extern/ode/dist/include/ode/common.h | 307 + extern/ode/dist/include/ode/contact.h | 91 + extern/ode/dist/include/ode/error.h | 64 + extern/ode/dist/include/ode/geom.h | 153 + extern/ode/dist/include/ode/mass.h | 98 + extern/ode/dist/include/ode/matrix.h | 195 + extern/ode/dist/include/ode/memory.h | 64 + extern/ode/dist/include/ode/misc.h | 86 + extern/ode/dist/include/ode/objects.h | 202 + extern/ode/dist/include/ode/ode.h | 45 + extern/ode/dist/include/ode/odecpp.h | 797 + extern/ode/dist/include/ode/odecpp_old.h | 317 + extern/ode/dist/include/ode/odemath.h | 217 + extern/ode/dist/include/ode/rotation.h | 65 + extern/ode/dist/include/ode/space.h | 78 + extern/ode/dist/include/ode/timer.h | 77 + extern/ode/dist/ode/README | 158 + extern/ode/dist/ode/fbuild/BuildDot | 148 + extern/ode/dist/ode/fbuild/BuildLDLT | 654 + extern/ode/dist/ode/fbuild/BuildMultidot | 174 + extern/ode/dist/ode/fbuild/BuildUtil | 99 + extern/ode/dist/ode/fbuild/Dependencies | 16 + extern/ode/dist/ode/fbuild/Makefile | 77 + extern/ode/dist/ode/fbuild/OptimizeDot | 71 + extern/ode/dist/ode/fbuild/OptimizeLDLT | 91 + extern/ode/dist/ode/fbuild/OptimizeLSolve | 76 + extern/ode/dist/ode/fbuild/OptimizeLTSolve | 76 + extern/ode/dist/ode/fbuild/OptimizeMultidot | 73 + extern/ode/dist/ode/fbuild/OptimizeUtil | 86 + .../ode/dist/ode/fbuild/ParametersD.example | 32 + .../ode/dist/ode/fbuild/ParametersF.example | 30 + .../ode/dist/ode/fbuild/ParametersM.example | 32 + .../ode/dist/ode/fbuild/ParametersS.example | 30 + .../ode/dist/ode/fbuild/ParametersT.example | 30 + extern/ode/dist/ode/fbuild/README | 41 + extern/ode/dist/ode/fbuild/ldlt.m | 26 + extern/ode/dist/ode/fbuild/test_dot.cpp | 124 + extern/ode/dist/ode/fbuild/test_ldlt.cpp | 299 + extern/ode/dist/ode/fbuild/test_multidot.cpp | 144 + extern/ode/dist/ode/src/array.cpp | 80 + extern/ode/dist/ode/src/array.h | 135 + extern/ode/dist/ode/src/error.cpp | 172 + extern/ode/dist/ode/src/fastdot.c | 30 + extern/ode/dist/ode/src/fastldlt.c | 381 + extern/ode/dist/ode/src/fastlsolve.c | 298 + extern/ode/dist/ode/src/fastltsolve.c | 199 + extern/ode/dist/ode/src/geom.cpp | 2207 +++ extern/ode/dist/ode/src/geom_internal.h | 83 + extern/ode/dist/ode/src/joint.cpp | 2160 +++ extern/ode/dist/ode/src/joint.h | 260 + extern/ode/dist/ode/src/lcp.cpp | 1455 ++ extern/ode/dist/ode/src/lcp.h | 59 + extern/ode/dist/ode/src/mass.cpp | 261 + extern/ode/dist/ode/src/mat.cpp | 230 + extern/ode/dist/ode/src/mat.h | 72 + extern/ode/dist/ode/src/matrix.cpp | 358 + extern/ode/dist/ode/src/memory.cpp | 278 + extern/ode/dist/ode/src/misc.cpp | 147 + extern/ode/dist/ode/src/objects.h | 91 + extern/ode/dist/ode/src/obstack.cpp | 130 + extern/ode/dist/ode/src/obstack.h | 69 + extern/ode/dist/ode/src/ode.cpp | 1341 ++ extern/ode/dist/ode/src/odemath.cpp | 173 + extern/ode/dist/ode/src/rotation.cpp | 283 + extern/ode/dist/ode/src/scrapbook.cpp | 270 + extern/ode/dist/ode/src/space.cpp | 621 + extern/ode/dist/ode/src/stack.cpp | 114 + extern/ode/dist/ode/src/stack.h | 139 + extern/ode/dist/ode/src/step.cpp | 1085 ++ extern/ode/dist/ode/src/step.h | 37 + extern/ode/dist/ode/src/testing.cpp | 243 + extern/ode/dist/ode/src/testing.h | 66 + extern/ode/dist/ode/src/timer.cpp | 397 + extern/ode/dist/tools/build4 | 42 + extern/ode/dist/tools/build4.bat | 43 + extern/ode/dist/tools/make_distribution | 45 + extern/ode/dist/tools/process_deps | 11 + extern/ode/patchfile.FreeBSD | 22 + extern/qhull/CMakeLists.txt | 48 + extern/qhull/COPYING.txt | 37 + extern/qhull/README.txt | 318 + extern/qhull/REGISTER.txt | 37 + extern/qhull/SConscript | 35 + extern/qhull/VisualC6/qhull.dsw | 29 + extern/qhull/VisualC6/qhull/qhull.dsp | 192 + extern/qhull/include/qhull/geom.h | 177 + extern/qhull/include/qhull/io.h | 149 + extern/qhull/include/qhull/mem.h | 174 + extern/qhull/include/qhull/merge.h | 171 + extern/qhull/include/qhull/poly.h | 290 + extern/qhull/include/qhull/qhull.h | 1048 ++ extern/qhull/include/qhull/qhull_a.h | 127 + extern/qhull/include/qhull/qset.h | 468 + extern/qhull/include/qhull/stat.h | 520 + extern/qhull/include/qhull/user.h | 762 + extern/qhull/make/msvc_7_0/qhull.vcproj | 677 + extern/qhull/src/Make-config.sh | 285 + extern/qhull/src/Makefile | 59 + extern/qhull/src/Makefile.txt | 190 + extern/qhull/src/geom.c | 1230 ++ extern/qhull/src/geom.h | 177 + extern/qhull/src/geom2.c | 2160 +++ extern/qhull/src/global.c | 2018 +++ extern/qhull/src/io.c | 4089 +++++ extern/qhull/src/io.h | 149 + extern/qhull/src/mem.c | 447 + extern/qhull/src/mem.h | 174 + extern/qhull/src/merge.c | 3626 ++++ extern/qhull/src/merge.h | 171 + extern/qhull/src/poly.c | 1180 ++ extern/qhull/src/poly.h | 290 + extern/qhull/src/poly2.c | 3070 ++++ extern/qhull/src/qconvex.c | 334 + extern/qhull/src/qdelaun.c | 323 + extern/qhull/src/qhalf.c | 324 + extern/qhull/src/qhull.c | 1395 ++ extern/qhull/src/qhull.h | 1048 ++ extern/qhull/src/qhull_a.h | 127 + extern/qhull/src/qhull_interface.cpp | 96 + extern/qhull/src/qset.c | 1301 ++ extern/qhull/src/qset.h | 468 + extern/qhull/src/qvoronoi.c | 318 + extern/qhull/src/rbox.c | 788 + extern/qhull/src/stat.c | 700 + extern/qhull/src/stat.h | 520 + extern/qhull/src/unix.c | 376 + extern/qhull/src/user.c | 324 + extern/qhull/src/user.h | 762 + extern/qhull/src/user_eg.c | 310 + extern/qhull/src/user_eg2.c | 532 + extern/solid/CMakeLists.txt | 37 + extern/solid/LICENSE_GPL.txt | 349 + extern/solid/LICENSE_QPL.txt | 110 + extern/solid/Makefile | 60 + extern/solid/README.txt | 55 + extern/solid/SConscript | 34 + extern/solid/SOLID/SOLID.h | 279 + extern/solid/SOLID/SOLID_broad.h | 75 + extern/solid/SOLID/SOLID_types.h | 53 + extern/solid/VisualC6/broad/broad.dsp | 132 + extern/solid/VisualC6/complex/complex.dsp | 116 + extern/solid/VisualC6/convex/convex.dsp | 232 + extern/solid/VisualC6/dynamics/dynamics.dsp | 120 + extern/solid/VisualC6/gldemo/gldemo.dsp | 102 + extern/solid/VisualC6/mnm/mnm.dsp | 100 + extern/solid/VisualC6/physics/physics.dsp | 100 + extern/solid/VisualC6/sample/sample.dsp | 102 + extern/solid/VisualC6/solid.dsw | 89 + extern/solid/VisualC6/solid/solid.dsp | 148 + extern/solid/VisualC6/solid_dll/solid_dll.dsp | 147 + extern/solid/include/GEN_MinMax.h | 76 + extern/solid/include/GEN_random.h | 49 + extern/solid/include/MT/Interval.h | 180 + extern/solid/include/MT/Matrix3x3.h | 380 + extern/solid/include/MT/Quaternion.h | 316 + extern/solid/include/MT/Transform.h | 189 + extern/solid/include/MT/Tuple3.h | 120 + extern/solid/include/MT/Tuple4.h | 112 + extern/solid/include/MT/Vector3.h | 283 + extern/solid/include/MT_BBox.h | 119 + extern/solid/include/MT_Interval.h | 33 + extern/solid/include/MT_Matrix3x3.h | 34 + extern/solid/include/MT_Point3.h | 31 + extern/solid/include/MT_Quaternion.h | 35 + extern/solid/include/MT_Scalar.h | 158 + extern/solid/include/MT_Transform.h | 38 + extern/solid/include/MT_Vector3.h | 50 + extern/solid/include/SOLID.h | 279 + extern/solid/include/SOLID_broad.h | 75 + extern/solid/include/SOLID_types.h | 53 + extern/solid/make/msvc_7_0/broad/broad.vcproj | 262 + .../make/msvc_7_0/complex/complex.vcproj | 252 + .../solid/make/msvc_7_0/convex/convex.vcproj | 337 + extern/solid/make/msvc_7_0/solid.vcproj | 462 + extern/solid/src/DT_AlgoTable.h | 47 + extern/solid/src/DT_C-api.cpp | 581 + extern/solid/src/DT_Encounter.cpp | 111 + extern/solid/src/DT_Encounter.h | 84 + extern/solid/src/DT_Object.cpp | 276 + extern/solid/src/DT_Object.h | 157 + extern/solid/src/DT_RespTable.cpp | 184 + extern/solid/src/DT_RespTable.h | 139 + extern/solid/src/DT_Response.h | 63 + extern/solid/src/DT_Scene.cpp | 183 + extern/solid/src/DT_Scene.h | 57 + extern/solid/src/Makefile | 48 + extern/solid/src/broad/BP_C-api.cpp | 77 + extern/solid/src/broad/BP_Endpoint.h | 108 + extern/solid/src/broad/BP_EndpointList.cpp | 237 + extern/solid/src/broad/BP_EndpointList.h | 109 + extern/solid/src/broad/BP_Proxy.cpp | 120 + extern/solid/src/broad/BP_Proxy.h | 78 + extern/solid/src/broad/BP_ProxyList.h | 69 + extern/solid/src/broad/BP_Scene.cpp | 151 + extern/solid/src/broad/BP_Scene.h | 79 + extern/solid/src/broad/Makefile | 44 + extern/solid/src/complex/DT_BBoxTree.cpp | 90 + extern/solid/src/complex/DT_BBoxTree.h | 540 + extern/solid/src/complex/DT_CBox.h | 134 + extern/solid/src/complex/DT_Complex.cpp | 327 + extern/solid/src/complex/DT_Complex.h | 94 + extern/solid/src/complex/Makefile | 45 + extern/solid/src/convex/DT_Accuracy.cpp | 30 + extern/solid/src/convex/DT_Accuracy.h | 47 + extern/solid/src/convex/DT_Array.h | 75 + extern/solid/src/convex/DT_Box.cpp | 112 + extern/solid/src/convex/DT_Box.h | 62 + extern/solid/src/convex/DT_Cone.cpp | 48 + extern/solid/src/convex/DT_Cone.h | 45 + extern/solid/src/convex/DT_Convex.cpp | 426 + extern/solid/src/convex/DT_Convex.h | 64 + extern/solid/src/convex/DT_Cylinder.cpp | 39 + extern/solid/src/convex/DT_Cylinder.h | 42 + extern/solid/src/convex/DT_Facet.cpp | 80 + extern/solid/src/convex/DT_Facet.h | 134 + extern/solid/src/convex/DT_GJK.h | 438 + extern/solid/src/convex/DT_Hull.h | 53 + extern/solid/src/convex/DT_IndexArray.h | 33 + extern/solid/src/convex/DT_LineSegment.cpp | 36 + extern/solid/src/convex/DT_LineSegment.h | 52 + extern/solid/src/convex/DT_Minkowski.h | 51 + extern/solid/src/convex/DT_PenDepth.cpp | 376 + extern/solid/src/convex/DT_PenDepth.h | 36 + extern/solid/src/convex/DT_Point.cpp | 36 + extern/solid/src/convex/DT_Point.h | 46 + extern/solid/src/convex/DT_Polyhedron.cpp | 415 + extern/solid/src/convex/DT_Polyhedron.h | 76 + extern/solid/src/convex/DT_Polytope.cpp | 69 + extern/solid/src/convex/DT_Polytope.h | 51 + extern/solid/src/convex/DT_Shape.h | 72 + extern/solid/src/convex/DT_Sphere.cpp | 90 + extern/solid/src/convex/DT_Sphere.h | 43 + extern/solid/src/convex/DT_Transform.h | 53 + extern/solid/src/convex/DT_Triangle.cpp | 96 + extern/solid/src/convex/DT_Triangle.h | 63 + extern/solid/src/convex/DT_VertexBase.h | 84 + extern/solid/src/convex/Makefile | 44 + extern/verse/CMakeLists.txt | 31 + extern/verse/Makefile | 58 + extern/verse/dist/BUGS | 8 + extern/verse/dist/CMakeLists.txt | 93 + extern/verse/dist/MAINTAINERS | 15 + extern/verse/dist/Makefile | 15 + extern/verse/dist/Makefile.win32 | 102 + extern/verse/dist/README.html | 173 + extern/verse/dist/SConstruct | 146 + extern/verse/dist/examples/list-nodes.c | 39 + extern/verse/dist/mkprot_cmd/CMakeLists.txt | 55 + extern/verse/dist/resources/Makefile.win32 | 11 + extern/verse/dist/resources/verse.ico | Bin 0 -> 17814 bytes extern/verse/dist/resources/verse.rc | 1 + extern/verse/dist/resources/verse.res | Bin 0 -> 18060 bytes extern/verse/dist/v_bignum.c | 860 + extern/verse/dist/v_bignum.h | 89 + extern/verse/dist/v_cmd_buf.c | 119 + extern/verse/dist/v_cmd_buf.h | 74 + extern/verse/dist/v_cmd_def_a.c | 94 + extern/verse/dist/v_cmd_def_b.c | 44 + extern/verse/dist/v_cmd_def_c.c | 35 + extern/verse/dist/v_cmd_def_g.c | 183 + extern/verse/dist/v_cmd_def_m.c | 273 + extern/verse/dist/v_cmd_def_o.c | 517 + extern/verse/dist/v_cmd_def_s.c | 211 + extern/verse/dist/v_cmd_def_t.c | 36 + extern/verse/dist/v_cmd_gen.c | 939 + extern/verse/dist/v_cmd_gen.h | 42 + extern/verse/dist/v_connect.c | 490 + extern/verse/dist/v_connection.c | 490 + extern/verse/dist/v_connection.h | 73 + extern/verse/dist/v_encryption.c | 255 + extern/verse/dist/v_encryption.h | 32 + extern/verse/dist/v_func_storage.c | 194 + extern/verse/dist/v_gen_pack_a_node.c | 521 + extern/verse/dist/v_gen_pack_b_node.c | 238 + extern/verse/dist/v_gen_pack_c_node.c | 189 + extern/verse/dist/v_gen_pack_g_node.c | 1154 ++ extern/verse/dist/v_gen_pack_init.c | 95 + extern/verse/dist/v_gen_pack_m_node.c | 352 + extern/verse/dist/v_gen_pack_o_node.c | 1297 ++ extern/verse/dist/v_gen_pack_s_node.c | 711 + extern/verse/dist/v_gen_pack_t_node.c | 226 + extern/verse/dist/v_gen_unpack_func.h | 63 + extern/verse/dist/v_gen_unpack_funcs.h | 0 extern/verse/dist/v_internal_verse.h | 2 + extern/verse/dist/v_man_pack_node.c | 498 + extern/verse/dist/v_network.c | 274 + extern/verse/dist/v_network.h | 24 + extern/verse/dist/v_network_in_que.c | 140 + extern/verse/dist/v_network_in_que.h | 24 + extern/verse/dist/v_network_out_que.c | 396 + extern/verse/dist/v_network_out_que.h | 17 + extern/verse/dist/v_pack.c | 386 + extern/verse/dist/v_pack.h | 59 + extern/verse/dist/v_pack_method.c | 219 + extern/verse/dist/v_prime.c | 165 + extern/verse/dist/v_randgen.c | 101 + extern/verse/dist/v_randgen.h | 14 + extern/verse/dist/v_util.c | 98 + extern/verse/dist/v_util.h | 21 + extern/verse/dist/verse.h | 530 + extern/verse/dist/verse_header.h | 409 + extern/verse/dist/verse_ms.c | 286 + extern/verse/dist/verse_ms.h | 72 + extern/verse/dist/vs_connection.c | 179 + extern/verse/dist/vs_main.c | 180 + extern/verse/dist/vs_master.c | 131 + extern/verse/dist/vs_node_audio.c | 420 + extern/verse/dist/vs_node_bitmap.c | 560 + extern/verse/dist/vs_node_curve.c | 258 + extern/verse/dist/vs_node_geometry.c | 1047 ++ extern/verse/dist/vs_node_head.c | 414 + extern/verse/dist/vs_node_material.c | 116 + extern/verse/dist/vs_node_object.c | 837 + extern/verse/dist/vs_node_particle.c | 52 + extern/verse/dist/vs_node_storage.c | 245 + extern/verse/dist/vs_node_text.c | 274 + extern/verse/dist/vs_server.h | 62 + extern/verse/make/msvc_7_0/libverse.vcproj | 279 + extern/verse/make/msvc_7_0/verse.vcproj | 481 + intern/CMakeLists.txt | 36 + intern/Makefile | 50 + intern/SConscript | 29 + intern/SoundSystem/CMakeLists.txt | 45 + intern/SoundSystem/Makefile | 72 + intern/SoundSystem/SConscript | 16 + intern/SoundSystem/SND_C-api.h | 357 + intern/SoundSystem/SND_CDObject.h | 86 + intern/SoundSystem/SND_DependKludge.h | 56 + intern/SoundSystem/SND_DeviceManager.h | 82 + intern/SoundSystem/SND_IAudioDevice.h | 346 + intern/SoundSystem/SND_Object.h | 57 + intern/SoundSystem/SND_Scene.h | 107 + intern/SoundSystem/SND_SoundListener.h | 85 + intern/SoundSystem/SND_SoundObject.h | 162 + intern/SoundSystem/SND_Utils.h | 114 + intern/SoundSystem/SND_WaveCache.h | 69 + intern/SoundSystem/SND_WaveSlot.h | 95 + intern/SoundSystem/SND_test/Makefile | 51 + intern/SoundSystem/SND_test/SND_test.c | 157 + intern/SoundSystem/SoundDefines.h | 120 + intern/SoundSystem/dummy/Makefile | 45 + intern/SoundSystem/dummy/SND_DummyDevice.cpp | 55 + intern/SoundSystem/dummy/SND_DummyDevice.h | 96 + intern/SoundSystem/fmod/Makefile | 46 + intern/SoundSystem/fmod/SND_FmodDevice.cpp | 577 + intern/SoundSystem/fmod/SND_FmodDevice.h | 106 + intern/SoundSystem/intern/Makefile | 49 + intern/SoundSystem/intern/SND_AudioDevice.cpp | 245 + intern/SoundSystem/intern/SND_AudioDevice.h | 118 + intern/SoundSystem/intern/SND_C-api.cpp | 395 + intern/SoundSystem/intern/SND_CDObject.cpp | 185 + .../SoundSystem/intern/SND_DeviceManager.cpp | 144 + intern/SoundSystem/intern/SND_IdObject.cpp | 79 + intern/SoundSystem/intern/SND_IdObject.h | 61 + intern/SoundSystem/intern/SND_Scene.cpp | 563 + .../SoundSystem/intern/SND_SoundListener.cpp | 188 + intern/SoundSystem/intern/SND_SoundObject.cpp | 508 + intern/SoundSystem/intern/SND_Utils.cpp | 447 + intern/SoundSystem/intern/SND_WaveCache.cpp | 141 + intern/SoundSystem/intern/SND_WaveSlot.cpp | 183 + .../SoundSystem/make/msvc_6_0/SoundSystem.dsp | 206 + .../make/msvc_6_0/dummy/DummySoundSystem.dsp | 103 + .../msvc_6_0/openal/OpenALSoundSystem.dsp | 106 + .../make/msvc_7_0/SoundSystem.vcproj | 339 + .../msvc_7_0/dummy/DummySoundSystem.vcproj | 243 + .../msvc_7_0/openal/OpenALSoundSystem.vcproj | 249 + intern/SoundSystem/openal/Makefile | 47 + .../SoundSystem/openal/SND_OpenALDevice.cpp | 799 + intern/SoundSystem/openal/SND_OpenALDevice.h | 110 + intern/SoundSystem/openal/pthread_cancel.cpp | 70 + intern/SoundSystem/sdl/Makefile | 46 + intern/SoundSystem/sdl/SND_SDLCDDevice.cpp | 155 + intern/SoundSystem/sdl/SND_SDLCDDevice.h | 61 + intern/bmfont/BMF_Api.h | 164 + intern/bmfont/BMF_Fonts.h | 77 + intern/bmfont/BMF_Settings.h | 70 + intern/bmfont/CMakeLists.txt | 35 + intern/bmfont/Makefile | 56 + intern/bmfont/SConscript | 10 + intern/bmfont/intern/BMF_Api.cpp | 186 + intern/bmfont/intern/BMF_BitmapFont.cpp | 322 + intern/bmfont/intern/BMF_BitmapFont.h | 142 + intern/bmfont/intern/BMF_FontData.h | 58 + intern/bmfont/intern/BMF_font_helv10.cpp | 497 + intern/bmfont/intern/BMF_font_helv12.cpp | 528 + intern/bmfont/intern/BMF_font_helvb10.cpp | 495 + intern/bmfont/intern/BMF_font_helvb12.cpp | 568 + intern/bmfont/intern/BMF_font_helvb14.cpp | 626 + intern/bmfont/intern/BMF_font_helvb8.cpp | 458 + intern/bmfont/intern/BMF_font_scr12.cpp | 487 + intern/bmfont/intern/BMF_font_scr14.cpp | 513 + intern/bmfont/intern/BMF_font_scr15.cpp | 528 + intern/bmfont/intern/Makefile | 44 + intern/bmfont/make/msvc_6_0/bmfont.dsp | 176 + intern/bmfont/make/msvc_6_0/bmfont.dsw | 29 + intern/bmfont/make/msvc_7_0/bmfont.sln | 21 + intern/bmfont/make/msvc_7_0/bmfont.vcproj | 314 + intern/bmfont/test/Makefile | 63 + intern/bmfont/test/make/msvc_6_0/BMF_Test.dsp | 109 + intern/bmfont/test/make/msvc_6_0/BMF_Test.dsw | 44 + intern/bmfont/test/simpletest/BMF_Test.cpp | 229 + intern/bmfont/test/simpletest/Makefile | 45 + intern/boolop/CMakeLists.txt | 35 + intern/boolop/Makefile | 59 + intern/boolop/SConscript | 14 + intern/boolop/extern/BOP_Interface.h | 46 + intern/boolop/intern/BOP_BBox.cpp | 62 + intern/boolop/intern/BOP_BBox.h | 96 + intern/boolop/intern/BOP_BSPNode.cpp | 717 + intern/boolop/intern/BOP_BSPNode.h | 105 + intern/boolop/intern/BOP_BSPTree.cpp | 189 + intern/boolop/intern/BOP_BSPTree.h | 74 + intern/boolop/intern/BOP_Chrono.h | 52 + intern/boolop/intern/BOP_Edge.cpp | 81 + intern/boolop/intern/BOP_Edge.h | 55 + intern/boolop/intern/BOP_Face.cpp | 426 + intern/boolop/intern/BOP_Face.h | 116 + intern/boolop/intern/BOP_Face2Face.cpp | 1245 ++ intern/boolop/intern/BOP_Face2Face.h | 44 + intern/boolop/intern/BOP_Indexs.h | 41 + intern/boolop/intern/BOP_Interface.cpp | 505 + intern/boolop/intern/BOP_MathUtils.cpp | 471 + intern/boolop/intern/BOP_MathUtils.h | 82 + intern/boolop/intern/BOP_Merge.cpp | 807 + intern/boolop/intern/BOP_Merge.h | 74 + intern/boolop/intern/BOP_Mesh.cpp | 1080 ++ intern/boolop/intern/BOP_Mesh.h | 124 + intern/boolop/intern/BOP_Segment.cpp | 247 + intern/boolop/intern/BOP_Segment.h | 73 + intern/boolop/intern/BOP_Splitter.cpp | 193 + intern/boolop/intern/BOP_Splitter.h | 44 + intern/boolop/intern/BOP_Tag.cpp | 142 + intern/boolop/intern/BOP_Tag.h | 145 + intern/boolop/intern/BOP_Triangulator.cpp | 572 + intern/boolop/intern/BOP_Triangulator.h | 44 + intern/boolop/intern/BOP_Vertex.cpp | 94 + intern/boolop/intern/BOP_Vertex.h | 60 + intern/boolop/intern/Makefile | 51 + intern/boolop/make/msvc_6_0/boolop.dsp | 222 + intern/boolop/make/msvc_7_0/boolop.vcproj | 363 + intern/bsp/CMakeLists.txt | 35 + intern/bsp/Makefile | 59 + intern/bsp/SConscript | 12 + intern/bsp/extern/CSG_BooleanOps.h | 360 + intern/bsp/intern/BSP_CSGException.h | 58 + intern/bsp/intern/BSP_CSGMesh.cpp | 655 + intern/bsp/intern/BSP_CSGMesh.h | 249 + intern/bsp/intern/BSP_CSGMesh_CFIterator.h | 270 + intern/bsp/intern/BSP_MeshPrimitives.cpp | 301 + intern/bsp/intern/BSP_MeshPrimitives.h | 279 + intern/bsp/intern/CSG_BooleanOps.cpp | 183 + intern/bsp/intern/Makefile | 48 + intern/bsp/make/msvc6_0/bsplib.dsp | 138 + intern/bsp/make/msvc6_0/bsplib.dsw | 29 + intern/bsp/make/msvc_7_0/bsplib.sln | 21 + intern/bsp/make/msvc_7_0/bsplib.vcproj | 282 + .../bsp/test/BSP_GhostTest/BSP_GhostTest.dsp | 126 + .../bsp/test/BSP_GhostTest/BSP_GhostTest.dsw | 125 + .../test/BSP_GhostTest/BSP_GhostTest3D.cpp | 658 + .../bsp/test/BSP_GhostTest/BSP_GhostTest3D.h | 163 + .../bsp/test/BSP_GhostTest/BSP_MeshDrawer.cpp | 164 + .../bsp/test/BSP_GhostTest/BSP_MeshDrawer.h | 75 + .../bsp/test/BSP_GhostTest/BSP_PlyLoader.cpp | 200 + intern/bsp/test/BSP_GhostTest/BSP_PlyLoader.h | 64 + intern/bsp/test/BSP_GhostTest/BSP_TMesh.h | 401 + intern/bsp/test/BSP_GhostTest/Makefile | 56 + intern/bsp/test/BSP_GhostTest/main.cpp | 151 + intern/bsp/test/BSP_GhostTest/ply.h | 200 + intern/bsp/test/BSP_GhostTest/plyfile.c | 2552 +++ intern/bsp/test/Makefile | 72 + intern/container/CMakeLists.txt | 35 + intern/container/CTR_List.h | 142 + intern/container/CTR_Map.h | 149 + intern/container/CTR_TaggedIndex.h | 201 + intern/container/CTR_TaggedSetOps.h | 300 + intern/container/CTR_UHeap.h | 305 + intern/container/Makefile | 52 + intern/container/SConscript | 7 + intern/container/intern/CTR_List.cpp | 153 + intern/container/intern/Makefile | 42 + intern/container/make/msvc_6_0/container.dsp | 133 + intern/container/make/msvc_6_0/container.dsw | 29 + intern/container/make/msvc_7_0/container.sln | 21 + .../container/make/msvc_7_0/container.vcproj | 292 + intern/decimation/CMakeLists.txt | 35 + intern/decimation/Makefile | 56 + intern/decimation/SConscript | 8 + intern/decimation/extern/LOD_decimation.h | 116 + .../decimation/intern/LOD_DecimationClass.h | 117 + .../decimation/intern/LOD_EdgeCollapser.cpp | 413 + intern/decimation/intern/LOD_EdgeCollapser.h | 116 + .../intern/LOD_ExternBufferEditor.h | 164 + .../intern/LOD_ExternNormalEditor.cpp | 267 + .../intern/LOD_ExternNormalEditor.h | 134 + .../intern/LOD_FaceNormalEditor.cpp | 294 + .../decimation/intern/LOD_FaceNormalEditor.h | 143 + intern/decimation/intern/LOD_ManMesh2.cpp | 621 + intern/decimation/intern/LOD_ManMesh2.h | 264 + intern/decimation/intern/LOD_MeshBounds.h | 132 + intern/decimation/intern/LOD_MeshException.h | 54 + .../decimation/intern/LOD_MeshPrimitives.cpp | 407 + intern/decimation/intern/LOD_MeshPrimitives.h | 220 + intern/decimation/intern/LOD_QSDecimator.cpp | 328 + intern/decimation/intern/LOD_QSDecimator.h | 128 + intern/decimation/intern/LOD_Quadric.h | 166 + .../decimation/intern/LOD_QuadricEditor.cpp | 282 + intern/decimation/intern/LOD_QuadricEditor.h | 119 + intern/decimation/intern/LOD_decimation.cpp | 158 + intern/decimation/intern/Makefile | 45 + .../decimation/make/msvc_6_0/decimation.dsp | 186 + .../decimation/make/msvc_6_0/decimation.dsw | 33 + .../decimation/make/msvc_7_0/decimation.sln | 21 + .../make/msvc_7_0/decimation.vcproj | 321 + intern/elbeem/CMakeLists.txt | 40 + intern/elbeem/COPYING | 358 + intern/elbeem/COPYING_trimesh2 | 303 + intern/elbeem/Makefile | 58 + intern/elbeem/SConscript | 13 + intern/elbeem/extern/LBM_fluidsim.h | 77 + intern/elbeem/extern/elbeem.h | 240 + intern/elbeem/intern/Makefile | 53 + intern/elbeem/intern/attributes.cpp | 359 + intern/elbeem/intern/attributes.h | 220 + intern/elbeem/intern/elbeem.cpp | 386 + intern/elbeem/intern/elbeem.h | 240 + intern/elbeem/intern/isosurface.cpp | 1126 ++ intern/elbeem/intern/isosurface.h | 230 + intern/elbeem/intern/loop_tools.h | 109 + intern/elbeem/intern/mcubes_tables.h | 298 + intern/elbeem/intern/ntl_blenderdumper.cpp | 264 + intern/elbeem/intern/ntl_blenderdumper.h | 31 + intern/elbeem/intern/ntl_bsptree.cpp | 942 + intern/elbeem/intern/ntl_bsptree.h | 125 + intern/elbeem/intern/ntl_geometryclass.h | 115 + intern/elbeem/intern/ntl_geometrymodel.cpp | 478 + intern/elbeem/intern/ntl_geometrymodel.h | 92 + intern/elbeem/intern/ntl_geometryobject.cpp | 792 + intern/elbeem/intern/ntl_geometryobject.h | 211 + intern/elbeem/intern/ntl_geometryshader.h | 60 + intern/elbeem/intern/ntl_lighting.cpp | 181 + intern/elbeem/intern/ntl_lighting.h | 238 + intern/elbeem/intern/ntl_matrices.h | 780 + intern/elbeem/intern/ntl_ray.cpp | 912 + intern/elbeem/intern/ntl_ray.h | 416 + intern/elbeem/intern/ntl_vector3dim.h | 1081 ++ intern/elbeem/intern/ntl_world.cpp | 910 + intern/elbeem/intern/ntl_world.h | 389 + intern/elbeem/intern/parametrizer.cpp | 594 + intern/elbeem/intern/parametrizer.h | 310 + intern/elbeem/intern/particletracer.cpp | 468 + intern/elbeem/intern/particletracer.h | 278 + intern/elbeem/intern/simulation_object.cpp | 458 + intern/elbeem/intern/simulation_object.h | 194 + intern/elbeem/intern/solver_adap.cpp | 1279 ++ intern/elbeem/intern/solver_class.h | 1007 ++ intern/elbeem/intern/solver_init.cpp | 2320 +++ intern/elbeem/intern/solver_interface.cpp | 739 + intern/elbeem/intern/solver_interface.h | 606 + intern/elbeem/intern/solver_main.cpp | 1698 ++ intern/elbeem/intern/solver_relax.h | 1213 ++ intern/elbeem/intern/solver_util.cpp | 1966 +++ intern/elbeem/intern/utilities.cpp | 496 + intern/elbeem/intern/utilities.h | 204 + intern/elbeem/make/msvc_6_0/elbeem.dsp | 290 + intern/elbeem/make/msvc_7_0/elbeem.vcproj | 367 + intern/ghost/CMakeLists.txt | 60 + intern/ghost/GHOST_C-api.h | 765 + intern/ghost/GHOST_IEvent.h | 92 + intern/ghost/GHOST_IEventConsumer.h | 71 + intern/ghost/GHOST_ISystem.h | 357 + intern/ghost/GHOST_ITimerTask.h | 92 + intern/ghost/GHOST_IWindow.h | 261 + intern/ghost/GHOST_Rect.h | 234 + intern/ghost/GHOST_Types.h | 372 + intern/ghost/Makefile | 56 + intern/ghost/SConscript | 32 + intern/ghost/doc/ghost_interface.cfg | 626 + intern/ghost/intern/GHOST_Buttons.cpp | 81 + intern/ghost/intern/GHOST_Buttons.h | 81 + intern/ghost/intern/GHOST_C-api.cpp | 804 + .../intern/GHOST_CallbackEventConsumer.cpp | 59 + .../intern/GHOST_CallbackEventConsumer.h | 82 + intern/ghost/intern/GHOST_Debug.h | 68 + intern/ghost/intern/GHOST_DisplayManager.cpp | 222 + intern/ghost/intern/GHOST_DisplayManager.h | 140 + .../intern/GHOST_DisplayManagerCarbon.cpp | 181 + .../ghost/intern/GHOST_DisplayManagerCarbon.h | 119 + .../intern/GHOST_DisplayManagerWin32.cpp | 191 + .../ghost/intern/GHOST_DisplayManagerWin32.h | 104 + .../ghost/intern/GHOST_DisplayManagerX11.cpp | 128 + intern/ghost/intern/GHOST_DisplayManagerX11.h | 126 + intern/ghost/intern/GHOST_Event.h | 110 + intern/ghost/intern/GHOST_EventButton.h | 70 + intern/ghost/intern/GHOST_EventCursor.h | 71 + intern/ghost/intern/GHOST_EventKey.h | 84 + intern/ghost/intern/GHOST_EventManager.cpp | 261 + intern/ghost/intern/GHOST_EventManager.h | 181 + intern/ghost/intern/GHOST_EventPrinter.cpp | 282 + intern/ghost/intern/GHOST_EventPrinter.h | 67 + intern/ghost/intern/GHOST_EventWheel.h | 71 + intern/ghost/intern/GHOST_ISystem.cpp | 102 + intern/ghost/intern/GHOST_ModifierKeys.cpp | 142 + intern/ghost/intern/GHOST_ModifierKeys.h | 107 + intern/ghost/intern/GHOST_Rect.cpp | 144 + intern/ghost/intern/GHOST_System.cpp | 331 + intern/ghost/intern/GHOST_System.h | 318 + intern/ghost/intern/GHOST_SystemCarbon.cpp | 1067 ++ intern/ghost/intern/GHOST_SystemCarbon.h | 258 + intern/ghost/intern/GHOST_SystemWin32.cpp | 871 + intern/ghost/intern/GHOST_SystemWin32.h | 291 + intern/ghost/intern/GHOST_SystemX11.cpp | 878 + intern/ghost/intern/GHOST_SystemX11.h | 245 + intern/ghost/intern/GHOST_TimerManager.cpp | 167 + intern/ghost/intern/GHOST_TimerManager.h | 132 + intern/ghost/intern/GHOST_TimerTask.h | 191 + intern/ghost/intern/GHOST_Window.cpp | 129 + intern/ghost/intern/GHOST_Window.h | 284 + intern/ghost/intern/GHOST_WindowCarbon.cpp | 742 + intern/ghost/intern/GHOST_WindowCarbon.h | 314 + intern/ghost/intern/GHOST_WindowManager.cpp | 198 + intern/ghost/intern/GHOST_WindowManager.h | 164 + intern/ghost/intern/GHOST_WindowWin32.cpp | 886 + intern/ghost/intern/GHOST_WindowWin32.h | 311 + intern/ghost/intern/GHOST_WindowX11.cpp | 1032 ++ intern/ghost/intern/GHOST_WindowX11.h | 334 + intern/ghost/intern/Makefile | 66 + intern/ghost/make/msvc/ghost.dsp | 292 + intern/ghost/make/msvc/ghost.dsw | 29 + intern/ghost/make/msvc_7_0/ghost.sln | 21 + intern/ghost/make/msvc_7_0/ghost.vcproj | 401 + intern/ghost/test/Makefile | 86 + intern/ghost/test/gears/GHOST_C-Test.c | 564 + intern/ghost/test/gears/GHOST_Test.cpp | 761 + intern/ghost/test/gears/Makefile | 48 + intern/ghost/test/make/msvc_6_0/gears.dsp | 102 + intern/ghost/test/make/msvc_6_0/gears_C.dsp | 102 + .../ghost/test/make/msvc_6_0/ghost_test.dsw | 77 + intern/ghost/test/multitest/Basic.c | 71 + intern/ghost/test/multitest/Basic.h | 45 + intern/ghost/test/multitest/EventToBuf.c | 240 + intern/ghost/test/multitest/EventToBuf.h | 34 + intern/ghost/test/multitest/GL.h | 44 + intern/ghost/test/multitest/Makefile | 60 + intern/ghost/test/multitest/MultiTest.c | 866 + intern/ghost/test/multitest/ScrollBar.c | 149 + intern/ghost/test/multitest/ScrollBar.h | 57 + intern/ghost/test/multitest/Util.c | 77 + intern/ghost/test/multitest/Util.h | 36 + intern/ghost/test/multitest/WindowData.c | 63 + intern/ghost/test/multitest/WindowData.h | 40 + intern/guardedalloc/CMakeLists.txt | 35 + intern/guardedalloc/MEM_guardedalloc.h | 128 + intern/guardedalloc/Makefile | 56 + intern/guardedalloc/SConscript | 8 + intern/guardedalloc/intern/Makefile | 42 + intern/guardedalloc/intern/mallocn.c | 576 + .../make/msvc_6_0/guardedalloc.dsp | 114 + .../make/msvc_7_0/guardedalloc.sln | 21 + .../make/msvc_7_0/guardedalloc.vcproj | 269 + intern/guardedalloc/test/Makefile | 55 + intern/guardedalloc/test/simpletest/Makefile | 44 + intern/guardedalloc/test/simpletest/memtest.c | 162 + intern/iksolver/CMakeLists.txt | 35 + intern/iksolver/Makefile | 56 + intern/iksolver/SConscript | 8 + intern/iksolver/extern/IK_solver.h | 172 + intern/iksolver/intern/IK_QJacobian.cpp | 443 + intern/iksolver/intern/IK_QJacobian.h | 118 + intern/iksolver/intern/IK_QJacobianSolver.cpp | 394 + intern/iksolver/intern/IK_QJacobianSolver.h | 101 + intern/iksolver/intern/IK_QSegment.cpp | 1052 ++ intern/iksolver/intern/IK_QSegment.h | 351 + intern/iksolver/intern/IK_QTask.cpp | 239 + intern/iksolver/intern/IK_QTask.h | 156 + intern/iksolver/intern/IK_Solver.cpp | 380 + intern/iksolver/intern/MT_ExpMap.cpp | 251 + intern/iksolver/intern/MT_ExpMap.h | 212 + intern/iksolver/intern/Makefile | 45 + intern/iksolver/intern/TNT/cholesky.h | 99 + intern/iksolver/intern/TNT/cmat.h | 615 + intern/iksolver/intern/TNT/fcscmat.h | 168 + intern/iksolver/intern/TNT/fmat.h | 570 + intern/iksolver/intern/TNT/fortran.h | 70 + intern/iksolver/intern/TNT/fspvec.h | 172 + intern/iksolver/intern/TNT/index.h | 88 + intern/iksolver/intern/TNT/lapack.h | 190 + intern/iksolver/intern/TNT/lu.h | 209 + intern/iksolver/intern/TNT/qr.h | 234 + intern/iksolver/intern/TNT/region1d.h | 376 + intern/iksolver/intern/TNT/region2d.h | 472 + intern/iksolver/intern/TNT/stopwatch.h | 84 + intern/iksolver/intern/TNT/subscript.h | 64 + intern/iksolver/intern/TNT/svd.h | 429 + intern/iksolver/intern/TNT/tnt.h | 94 + intern/iksolver/intern/TNT/tntmath.h | 153 + intern/iksolver/intern/TNT/tntreqs.h | 74 + intern/iksolver/intern/TNT/transv.h | 165 + intern/iksolver/intern/TNT/triang.h | 638 + intern/iksolver/intern/TNT/trisolve.h | 189 + intern/iksolver/intern/TNT/vec.h | 492 + intern/iksolver/intern/TNT/vecadaptor.h | 285 + intern/iksolver/intern/TNT/version.h | 26 + intern/iksolver/make/msvc_6_0/iksolver.dsp | 260 + intern/iksolver/make/msvc_6_0/iksolver.dsw | 35 + intern/iksolver/make/msvc_7_0/iksolver.sln | 21 + intern/iksolver/make/msvc_7_0/iksolver.vcproj | 370 + intern/iksolver/test/Makefile | 71 + intern/iksolver/test/ik_glut_test/Makefile | 42 + .../test/ik_glut_test/common/GlutDrawer.cpp | 99 + .../test/ik_glut_test/common/GlutDrawer.h | 99 + .../common/GlutKeyboardManager.cpp | 92 + .../ik_glut_test/common/GlutKeyboardManager.h | 105 + .../ik_glut_test/common/GlutMouseManager.cpp | 107 + .../ik_glut_test/common/GlutMouseManager.h | 115 + .../test/ik_glut_test/common/Makefile | 44 + .../test/ik_glut_test/intern/ChainDrawer.h | 379 + .../test/ik_glut_test/intern/Makefile | 51 + .../ik_glut_test/intern/MyGlutKeyHandler.h | 84 + .../ik_glut_test/intern/MyGlutMouseHandler.h | 210 + .../test/ik_glut_test/intern/main.cpp | 364 + .../make/msvc_6_0/ik_glut_test.dsp | 130 + .../make/msvc_6_0/ik_glut_test.dsw | 49 + intern/make/msvc_6_0/build_install_all.dsp | 68 + intern/make/msvc_6_0/intern.dsw | 302 + intern/make/msvc_7_0/build_install_all.vcproj | 84 + intern/make/msvc_7_0/intern.sln | 252 + intern/memutil/CMakeLists.txt | 35 + intern/memutil/MEM_Allocator.h | 111 + intern/memutil/MEM_CacheLimiter.h | 170 + intern/memutil/MEM_CacheLimiterC-Api.h | 144 + intern/memutil/MEM_NonCopyable.h | 61 + intern/memutil/MEM_RefCountPtr.h | 293 + intern/memutil/MEM_RefCounted.h | 115 + intern/memutil/MEM_RefCountedC-Api.h | 78 + intern/memutil/MEM_SmartPtr.h | 240 + intern/memutil/Makefile | 56 + intern/memutil/SConscript | 8 + .../memutil/intern/MEM_CacheLimiterC-Api.cpp | 195 + intern/memutil/intern/MEM_RefCountedC-Api.cpp | 56 + intern/memutil/intern/Makefile | 42 + intern/memutil/make/msvc_60/memutil.dsp | 150 + intern/memutil/make/msvc_60/memutil.dsw | 29 + intern/memutil/make/msvc_7_0/memutil.sln | 21 + intern/memutil/make/msvc_7_0/memutil.vcproj | 292 + intern/moto/CMakeLists.txt | 35 + intern/moto/Makefile | 56 + intern/moto/SConscript | 8 + intern/moto/include/GEN_List.h | 117 + intern/moto/include/GEN_Map.h | 149 + intern/moto/include/MT_CmMatrix4x4.h | 147 + intern/moto/include/MT_Matrix3x3.h | 224 + intern/moto/include/MT_Matrix3x3.inl | 128 + intern/moto/include/MT_Matrix4x4.h | 251 + intern/moto/include/MT_Matrix4x4.inl | 108 + intern/moto/include/MT_MinMax.h | 70 + intern/moto/include/MT_Optimize.h | 42 + intern/moto/include/MT_Plane3.h | 136 + intern/moto/include/MT_Plane3.inl | 128 + intern/moto/include/MT_Point2.h | 82 + intern/moto/include/MT_Point2.inl | 54 + intern/moto/include/MT_Point3.h | 83 + intern/moto/include/MT_Point3.inl | 59 + intern/moto/include/MT_Quaternion.h | 113 + intern/moto/include/MT_Quaternion.inl | 92 + intern/moto/include/MT_Scalar.h | 96 + intern/moto/include/MT_Stream.h | 58 + intern/moto/include/MT_Transform.h | 189 + intern/moto/include/MT_Tuple2.h | 110 + intern/moto/include/MT_Tuple3.h | 115 + intern/moto/include/MT_Tuple4.h | 125 + intern/moto/include/MT_Vector2.h | 113 + intern/moto/include/MT_Vector2.inl | 89 + intern/moto/include/MT_Vector3.h | 120 + intern/moto/include/MT_Vector3.inl | 134 + intern/moto/include/MT_Vector4.h | 103 + intern/moto/include/MT_Vector4.inl | 80 + intern/moto/include/MT_assert.h | 102 + intern/moto/include/MT_random.h | 43 + intern/moto/include/NM_Scalar.h | 158 + intern/moto/intern/MT_Assert.cpp | 67 + intern/moto/intern/MT_CmMatrix4x4.cpp | 240 + intern/moto/intern/MT_Matrix3x3.cpp | 41 + intern/moto/intern/MT_Matrix4x4.cpp | 41 + intern/moto/intern/MT_Plane3.cpp | 71 + intern/moto/intern/MT_Point3.cpp | 41 + intern/moto/intern/MT_Quaternion.cpp | 41 + intern/moto/intern/MT_Transform.cpp | 142 + intern/moto/intern/MT_Vector2.cpp | 41 + intern/moto/intern/MT_Vector3.cpp | 41 + intern/moto/intern/MT_Vector4.cpp | 41 + intern/moto/intern/MT_random.cpp | 146 + intern/moto/intern/Makefile | 42 + intern/moto/make/msvc_6_0/MoTo.dsp | 379 + intern/moto/make/msvc_6_0/MoTo.dsw | 29 + intern/moto/make/msvc_7_0/moto.sln | 21 + intern/moto/make/msvc_7_0/moto.vcproj | 543 + intern/opennl/CMakeLists.txt | 36 + intern/opennl/Makefile | 67 + intern/opennl/SConscript | 12 + intern/opennl/doc/OpenNL_License.txt | 341 + intern/opennl/doc/OpenNL_Readme.txt | 13 + intern/opennl/doc/SuperLU_License.txt | 31 + intern/opennl/doc/SuperLU_Readme.txt | 52 + intern/opennl/extern/ONL_opennl.h | 147 + intern/opennl/intern/Makefile | 43 + intern/opennl/intern/opennl.c | 1263 ++ intern/opennl/make/msvc_6_0/OpenNL.dsp | 252 + intern/opennl/make/msvc_6_0/OpenNL.dsw | 29 + intern/opennl/make/msvc_7_0/opennl.vcproj | 742 + intern/opennl/superlu/Cnames.h | 281 + intern/opennl/superlu/Makefile | 40 + intern/opennl/superlu/colamd.c | 2583 +++ intern/opennl/superlu/colamd.h | 67 + intern/opennl/superlu/get_perm_c.c | 453 + intern/opennl/superlu/heap_relax_snode.c | 116 + intern/opennl/superlu/lsame.c | 73 + intern/opennl/superlu/memory.c | 211 + intern/opennl/superlu/mmd.c | 1025 ++ intern/opennl/superlu/relax_snode.c | 71 + intern/opennl/superlu/scolumn_bmod.c | 353 + intern/opennl/superlu/scolumn_dfs.c | 270 + intern/opennl/superlu/scopy_to_ucol.c | 105 + intern/opennl/superlu/sgssv.c | 221 + intern/opennl/superlu/sgstrf.c | 433 + intern/opennl/superlu/sgstrs.c | 331 + intern/opennl/superlu/smemory.c | 676 + intern/opennl/superlu/smyblas2.c | 232 + intern/opennl/superlu/sp_coletree.c | 332 + intern/opennl/superlu/sp_ienv.c | 65 + intern/opennl/superlu/sp_preorder.c | 206 + intern/opennl/superlu/spanel_bmod.c | 449 + intern/opennl/superlu/spanel_dfs.c | 249 + intern/opennl/superlu/spivotL.c | 173 + intern/opennl/superlu/spruneL.c | 149 + intern/opennl/superlu/ssnode_bmod.c | 117 + intern/opennl/superlu/ssnode_dfs.c | 106 + intern/opennl/superlu/ssp_blas2.c | 472 + intern/opennl/superlu/ssp_blas3.c | 121 + intern/opennl/superlu/ssp_defs.h | 237 + intern/opennl/superlu/strsv.c | 333 + intern/opennl/superlu/superlu_timer.c | 58 + intern/opennl/superlu/supermatrix.h | 140 + intern/opennl/superlu/sutil.c | 486 + intern/opennl/superlu/util.c | 397 + intern/opennl/superlu/util.h | 267 + intern/opennl/superlu/xerbla.c | 44 + intern/string/CMakeLists.txt | 35 + intern/string/Makefile | 56 + intern/string/SConscript | 7 + intern/string/STR_HashedString.h | 154 + intern/string/STR_String.h | 203 + intern/string/intern/Makefile | 42 + intern/string/intern/STR_String.cpp | 746 + intern/string/make/msvc_6_0/string.dsp | 122 + intern/string/make/msvc_6_0/string.dsw | 29 + intern/string/make/msvc_7_0/string.sln | 21 + intern/string/make/msvc_7_0/string.vcproj | 269 + po/Makefile | 62 + .../BLO_readblenfile/BLO_readblenfile.dsp | 155 + .../blender/BPY_python/BPY_python.dsp | 588 + projectfiles/blender/avi/BL_avi.dsp | 199 + projectfiles/blender/blender.dsp | 124 + projectfiles/blender/blender.dsw | 743 + .../blender/blenkernel/BKE_blenkernel.dsp | 564 + projectfiles/blender/blenlib/BLI_blenlib.dsp | 318 + .../blenpluginapi/blenpluginapi.dsp | 119 + projectfiles/blender/ftfont/FTF_ftfont.dsp | 118 + projectfiles/blender/glut/BL_glut.dsp | 324 + projectfiles/blender/imbuf/BL_imbuf.dsp | 438 + projectfiles/blender/img/BL_img.dsp | 171 + projectfiles/blender/loader/BLO_loader.dsp | 186 + .../blender/makesdna/DNA_makesdna.dsp | 373 + .../blender/radiosity/BRA_radiosity.dsp | 133 + projectfiles/blender/render/BRE_render.dsp | 192 + .../renderconverter/BRE_renderconverter.dsp | 102 + projectfiles/blender/src/BL_src.dsp | 1040 ++ projectfiles/blender/src/BL_src_cre.dsp | 102 + projectfiles/blender/yafray/BRE_yafray.dsp | 134 + projectfiles/datatoc/datatoc.dsp | 100 + .../gameengine/blenderhook/KX_blenderhook.dsp | 161 + .../gameengine/converter/KX_converter.dsp | 278 + .../gameengine/expression/EXP_expressions.dsp | 302 + .../gameengine/gamelogic/SCA_gamelogic.dsp | 406 + .../gameengine/gameplayer/axctl/GP_axctl.dsp | 253 + .../gameplayer/common/GP_common.dsp | 255 + .../gameengine/gameplayer/ghost/GP_ghost.dsp | 156 + .../gameengine/gameplayer/glut/GP_glut.dsp | 205 + .../loader/BlenderLoader/BlenderLoader.dsp | 206 + .../gameplayer/netscape/GP_netscape.dsp | 173 + .../gameplayer/netscape2/GP_netscape.dsp | 181 + .../gameengine/gameplayer/ps2/GP_ps2.dsp | 182 + projectfiles/gameengine/gameplayer/qt/gp.dsp | 164 + .../gameengine/gameplayer/qt/gpplugin.dsp | 824 + .../gameengine/gameplayer/qt/qtgp.dsw | 323 + .../gameengine/gameplayer/sdl/GP_sdl.dsp | 205 + projectfiles/gameengine/ketsji/KX_ketsji.dsp | 690 + .../gameengine/ketsji/network/KX_network.dsp | 186 + .../loopbacknetwork/NG_loopbacknetwork.dsp | 155 + .../gameengine/network/network/NG_network.dsp | 174 + .../terraplaynetwork/NG_terraplaynetwork.dsp | 180 + .../PHY_Physics/PHY_Dummy/PHY_Dummy.dsp | 154 + .../physics/PHY_Physics/PHY_Ode/PHY_Ode.dsp | 162 + .../physics/PHY_Physics/PHY_Physics.dsp | 178 + .../physics/PHY_Physics/PHY_Sumo/PHY_Sumo.dsp | 162 + .../gameengine/rasterizer/RAS_rasterizer.dsp | 243 + .../openglrasterizer/RAS_openglrasterizer.dsp | 183 + .../gameengine/scenegraph/SG_scenegraph.dsp | 199 + .../kernel/gen_messaging/gen_messaging.dsp | 155 + projectfiles/kernel/system/SYS_system.dsp | 183 + projectfiles/sumo/fuzzics/SM_fuzzics.dsp | 216 + projectfiles/sumo/moto/SM_moto.dsp | 332 + projectfiles/sumo/solid/SM_solid.dsp | 340 + .../BLO_readblenfile/BLO_readblenfile.vcproj | 343 + .../blender/BPY_python/BPY_python.vcproj | 561 + projectfiles_vc7/blender/avi/BL_avi.vcproj | 379 + projectfiles_vc7/blender/blender.sln | 815 + projectfiles_vc7/blender/blender.vcproj | 227 + projectfiles_vc7/blender/blendercompact.sln | 28 + .../blender/blendercompactNG.vcproj | 3561 ++++ .../blender/blenkernel/BKE_blenkernel.vcproj | 685 + .../blender/blenlib/BLI_blenlib.vcproj | 486 + .../blenpluginapi/blenpluginapi.vcproj | 361 + .../blender/ftfont/FTF_ftfont.vcproj | 151 + .../blender/imbuf/BL_imbuf.vcproj | 648 + projectfiles_vc7/blender/img/BL_img.vcproj | 287 + .../blender/loader/BLO_loader.vcproj | 475 + .../blender/makesdna/DNA_makesdna.vcproj | 596 + .../blender/makesdnacompact.vcproj | 124 + projectfiles_vc7/blender/nodes/nodes.vcproj | 449 + .../blender/radiosity/BRA_radiosity.vcproj | 159 + .../blender/render/BRE_render.vcproj | 252 + .../BRE_renderconverter.vcproj | 132 + projectfiles_vc7/blender/src/BL_src.vcproj | 894 + .../blender/src/BL_src_cre.vcproj | 145 + .../blender/yafray/BRE_yafray.vcproj | 164 + .../blenderhook/KX_blenderhook.vcproj | 186 + .../gameengine/converter/KX_converter.vcproj | 433 + .../expression/EXP_expressions.vcproj | 457 + .../gameengine/gamelogic/SCA_GameLogic.vcproj | 529 + .../gameplayer/axctl/GP_axctl.vcproj | 324 + .../gameplayer/common/GP_common.vcproj | 315 + .../gameplayer/ghost/GP_ghost.vcproj | 234 + .../gameengine/ketsji/KX_ketsji.vcproj | 760 + .../ketsji/network/KX_network.vcproj | 370 + .../loopbacknetwork/NG_loopbacknetwork.vcproj | 346 + .../network/network/NG_network.vcproj | 361 + .../PHY_Physics/PHY_Bullet/PHY_Bullet.vcproj | 317 + .../PHY_Physics/PHY_Dummy/PHY_Dummy.vcproj | 343 + .../PHY_Physics/PHY_Ode/PHY_Ode.vcproj | 246 + .../physics/PHY_Physics/PHY_Physics.vcproj | 367 + .../PHY_Physics/PHY_Sumo/PHY_Sumo.vcproj | 380 + .../rasterizer/RAS_rasterizer.vcproj | 412 + .../RAS_openglrasterizer.vcproj | 373 + .../scenegraph/SG_SceneGraph.vcproj | 379 + .../kernel/gen_messaging/gen_messaging.vcproj | 343 + .../kernel/system/SYS_system.vcproj | 367 + .../sumo/fuzzics/SM_fuzzics.vcproj | 376 + projectfiles_vc7/sumo/fuzzics/fuzzics.vcproj | 102 + projectfiles_vc7/sumo/moto/SM_moto.dsp | 332 + projectfiles_vc7/sumo/solid/SM_solid.dsp | 340 + release/Makefile | 206 + release/VERSION | 1 + release/beos-4.5-i386/specific.sh | 39 + release/beos-5.0-i386/specific.sh | 39 + release/datafiles/.Bfont | Bin 0 -> 25316 bytes release/datafiles/.Bfs | 2 + release/datafiles/DejaVuSans-Lite.sfd.bz2 | Bin 0 -> 182524 bytes release/datafiles/LICENSE-bfont.ttf.txt | 101 + release/datafiles/bfont.ttf | Bin 0 -> 191532 bytes release/datafiles/blenderbuttons | Bin 0 -> 66284 bytes release/datafiles/datatoc.c | 105 + release/datafiles/preview.blend | Bin 0 -> 459544 bytes release/datafiles/prvicons | Bin 0 -> 13732 bytes release/datafiles/splash.jpg | Bin 0 -> 79258 bytes release/freedesktop/icons/16x16/blender.png | Bin 0 -> 746 bytes .../freedesktop/icons/16x16/blender.xcf.bz2 | Bin 0 -> 1405 bytes release/freedesktop/icons/22x22/blender.png | Bin 0 -> 1219 bytes .../freedesktop/icons/22x22/blender.xcf.bz2 | Bin 0 -> 1792 bytes release/freedesktop/icons/32x32/blender.png | Bin 0 -> 1929 bytes release/freedesktop/icons/32x32/blender.svg | 238 + .../freedesktop/icons/scalable/blender.svg | 235 + release/irix-6.2-mips/extra/blender.icon | Bin 0 -> 638 bytes release/irix-6.2-mips/specific.sh | 37 + release/plugins/Makefile | 42 + release/plugins/bmake | 146 + release/plugins/sequence/Makefile | 38 + release/plugins/sequence/blur.c | 288 + .../plugins/sequence/color-correction-hsv.c | 291 + .../plugins/sequence/color-correction-yuv.c | 235 + release/plugins/sequence/dnr.c | 149 + release/plugins/sequence/gamma.c | 182 + release/plugins/sequence/scatter.c | 263 + release/plugins/texture/Makefile | 38 + release/plugins/texture/clouds2.c | 182 + release/plugins/texture/tiles.c | 181 + release/scripts/3ds_export.py | 1013 ++ release/scripts/3ds_import.py | 982 ++ release/scripts/Axiscopy.py | 125 + release/scripts/DirectX8Exporter.py | 1167 ++ release/scripts/DirectX8Importer.py | 238 + release/scripts/IDPropBrowser.py | 523 + release/scripts/ac3d_export.py | 828 + release/scripts/ac3d_import.py | 771 + release/scripts/add_mesh_empty.py | 13 + release/scripts/add_mesh_torus.py | 64 + release/scripts/animation_trajectory.py | 575 + release/scripts/armature_symmetry.py | 325 + release/scripts/bevel_center.py | 474 + release/scripts/blenderLipSynchro.py | 729 + release/scripts/bpydata/KUlang.txt | 121 + release/scripts/bpydata/config/readme.txt | 6 + release/scripts/bpydata/readme.txt | 9 + release/scripts/bpymodules/BPyAddMesh.py | 152 + release/scripts/bpymodules/BPyArmature.py | 137 + release/scripts/bpymodules/BPyBlender.py | 36 + release/scripts/bpymodules/BPyCurve.py | 79 + release/scripts/bpymodules/BPyImage.py | 301 + release/scripts/bpymodules/BPyMathutils.py | 239 + release/scripts/bpymodules/BPyMesh.py | 1328 ++ release/scripts/bpymodules/BPyMesh_octree.py | 332 + release/scripts/bpymodules/BPyMesh_redux.py | 653 + release/scripts/bpymodules/BPyMessages.py | 59 + release/scripts/bpymodules/BPyNMesh.py | 48 + release/scripts/bpymodules/BPyObject.py | 108 + release/scripts/bpymodules/BPyRegistry.py | 258 + release/scripts/bpymodules/BPyRender.py | 498 + release/scripts/bpymodules/BPySys.py | 14 + release/scripts/bpymodules/BPyWindow.py | 206 + release/scripts/bpymodules/defaultdoodads.py | 941 + release/scripts/bpymodules/dxfColorMap.py | 282 + .../scripts/bpymodules/dxfImportObjects.py | 1326 ++ release/scripts/bpymodules/dxfReader.py | 382 + release/scripts/bpymodules/mesh_gradient.py | 229 + release/scripts/bpymodules/meshtools.py | 355 + release/scripts/bpymodules/paths_ai2obj.py | 502 + release/scripts/bpymodules/paths_eps2obj.py | 452 + release/scripts/bpymodules/paths_gimp2obj.py | 359 + release/scripts/bpymodules/paths_svg2obj.py | 1585 ++ release/scripts/bvh_import.py | 752 + release/scripts/camera_changer.py | 121 + release/scripts/config.py | 797 + release/scripts/console.py | 849 + release/scripts/discombobulator.py | 1526 ++ release/scripts/envelope_symmetry.py | 174 + release/scripts/export-iv-0.1.py | 304 + release/scripts/export_cal3d.py | 1112 ++ release/scripts/export_fbx.py | 2976 ++++ release/scripts/export_lightwave_motion.py | 156 + release/scripts/export_m3g.py | 3047 ++++ release/scripts/export_map.py | 449 + release/scripts/export_mdd.py | 153 + release/scripts/export_obj.py | 649 + release/scripts/faceselect_same_weights.py | 111 + release/scripts/flt_export.py | 722 + release/scripts/flt_filewalker.py | 279 + release/scripts/flt_import.py | 1890 ++ release/scripts/help_bpy_api.py | 41 + release/scripts/help_browser.py | 789 + release/scripts/help_getting_started.py | 43 + release/scripts/help_manual.py | 41 + release/scripts/help_release_notes.py | 41 + release/scripts/help_tutorials.py | 42 + release/scripts/help_web_blender.py | 42 + release/scripts/help_web_devcomm.py | 41 + release/scripts/help_web_eshop.py | 41 + release/scripts/help_web_usercomm.py | 41 + release/scripts/hotkeys.py | 921 + release/scripts/image_auto_layout.py | 451 + release/scripts/image_billboard.py | 280 + release/scripts/image_edit.py | 136 + release/scripts/image_find_paths.py | 167 + release/scripts/import_dxf.py | 4139 +++++ release/scripts/import_mdd.py | 158 + release/scripts/import_obj.py | 880 + release/scripts/lightwave_export.py | 688 + release/scripts/lightwave_import.py | 1694 ++ release/scripts/md2_export.py | 1247 ++ release/scripts/md2_import.py | 598 + release/scripts/mesh_boneweight_copy.py | 287 + release/scripts/mesh_cleanup.py | 452 + release/scripts/mesh_edges2curves.py | 174 + release/scripts/mesh_mirror_tool.py | 352 + release/scripts/mesh_poly_reduce.py | 143 + release/scripts/mesh_skin.py | 639 + release/scripts/mesh_solidify.py | 345 + release/scripts/mesh_unfolder.py | 1582 ++ release/scripts/mesh_wire.py | 285 + release/scripts/obdatacopier.py | 215 + release/scripts/object_apply_def.py | 174 + release/scripts/object_batch_name_edit.py | 274 + release/scripts/object_cookie_cutter.py | 667 + release/scripts/object_drop.py | 224 + release/scripts/object_find.py | 208 + release/scripts/object_random_loc_sz_rot.py | 129 + release/scripts/object_sel2dupgroup.py | 84 + release/scripts/off_export.py | 106 + release/scripts/off_import.py | 177 + release/scripts/paths_import.py | 95 + release/scripts/ply_export.py | 222 + release/scripts/ply_import.py | 323 + release/scripts/raw_export.py | 100 + release/scripts/raw_import.py | 120 + release/scripts/renameobjectbyblock.py | 178 + release/scripts/rvk1_torvk2.py | 273 + release/scripts/save_theme.py | 139 + release/scripts/scripttemplate_mesh_edit.py | 98 + release/scripts/scripttemplate_object_edit.py | 81 + .../scripts/scripttemplate_pyconstraint.py | 114 + release/scripts/slp_import.py | 116 + release/scripts/sysinfo.py | 285 + release/scripts/unweld.py | 247 + release/scripts/uv_export.py | 498 + release/scripts/uv_from_adjacent.py | 129 + release/scripts/uv_seams_from_islands.py | 79 + .../scripts/uvcalc_follow_active_coords.py | 253 + release/scripts/uvcalc_lightmap.py | 569 + release/scripts/uvcalc_quad_clickproj.py | 267 + release/scripts/uvcalc_smart_project.py | 1132 ++ release/scripts/uvcopy.py | 114 + release/scripts/vertexpaint_from_material.py | 98 + release/scripts/vertexpaint_gradient.py | 46 + release/scripts/vertexpaint_selfshadow_ao.py | 186 + release/scripts/vrml97_export.py | 1238 ++ release/scripts/weightpaint_average.py | 122 + release/scripts/weightpaint_clean.py | 120 + release/scripts/weightpaint_copy.py | 101 + .../scripts/weightpaint_envelope_assign.py | 240 + release/scripts/weightpaint_gradient.py | 59 + release/scripts/weightpaint_grow_shrink.py | 131 + release/scripts/weightpaint_normalize.py | 120 + release/scripts/widgetwizard.py | 917 + release/scripts/x3d_export.py | 1008 ++ release/scripts/xfig_export.py | 234 + release/scripts/xsi_export.py | 1227 ++ release/text/GPL-license.txt | 340 + release/text/Python-license.txt | 48 + release/text/blender.html | 560 + release/text/copyright.txt | 120 + release/windows/contrib/vfapi/README | 26 + release/windows/contrib/vfapi/vfapi-plugin.c | 418 + release/windows/extra/Help.url | 4 + release/windows/installer/00.blender.nsi | 450 + release/windows/installer/00.checked.bmp | Bin 0 -> 2610 bytes release/windows/installer/00.header.bmp | Bin 0 -> 25818 bytes release/windows/installer/00.installer.adx | 314 + release/windows/installer/00.installer.ico | Bin 0 -> 25214 bytes release/windows/installer/00.sconsblender.nsi | 419 + release/windows/installer/00.unchecked.bmp | Bin 0 -> 358 bytes release/windows/installer/01.installer.bmp | Bin 0 -> 154542 bytes release/windows/installer/01.welcome.rtf | Bin 0 -> 471 bytes release/windows/installer/02.copyright.txt | 56 + release/windows/installer/03.readme.txt | 54 + release/windows/installer/04.folder.rtf | Bin 0 -> 416 bytes release/windows/installer/05.progress.rtf | Bin 0 -> 214 bytes release/windows/installer/06.complete.rtf | Bin 0 -> 361 bytes release/windows/installer/data.ini | 34 + .../windows/installer/input/24bits-image.bmp | Bin 0 -> 2786 bytes .../windows/publ_installer/00.installer.adx | 308 + .../windows/publ_installer/00.installer.ico | Bin 0 -> 1078 bytes .../windows/publ_installer/01.installer.bmp | Bin 0 -> 612 bytes release/windows/publ_installer/01.welcome.rtf | Bin 0 -> 624 bytes .../windows/publ_installer/02.copyright.txt | 56 + release/windows/publ_installer/03.readme.txt | 54 + release/windows/publ_installer/04.folder.rtf | Bin 0 -> 418 bytes .../windows/publ_installer/05.progress.rtf | Bin 0 -> 216 bytes .../windows/publ_installer/06.complete.rtf | Bin 0 -> 431 bytes release/windows/specific.sh | 102 + source/CMakeLists.txt | 38 + source/Makefile | 648 + source/SConscript | 11 + source/blender/CMakeLists.txt | 42 + source/blender/Makefile | 53 + source/blender/SConscript | 33 + source/blender/avi/AVI_avi.h | 309 + source/blender/avi/CMakeLists.txt | 38 + source/blender/avi/Makefile | 37 + source/blender/avi/SConscript | 10 + source/blender/avi/intern/Makefile | 54 + source/blender/avi/intern/avi.c | 843 + source/blender/avi/intern/avi_intern.h | 54 + source/blender/avi/intern/avirgb.c | 153 + source/blender/avi/intern/avirgb.h | 35 + source/blender/avi/intern/codecs.c | 147 + source/blender/avi/intern/endian.c | 216 + source/blender/avi/intern/endian.h | 55 + source/blender/avi/intern/mjpeg.c | 458 + source/blender/avi/intern/mjpeg.h | 35 + source/blender/avi/intern/options.c | 130 + source/blender/avi/intern/rgb32.c | 91 + source/blender/avi/intern/rgb32.h | 35 + source/blender/blenkernel/BKE_DerivedMesh.h | 461 + source/blender/blenkernel/BKE_action.h | 164 + source/blender/blenkernel/BKE_anim.h | 61 + source/blender/blenkernel/BKE_armature.h | 122 + .../blender/blenkernel/BKE_bad_level_calls.h | 235 + source/blender/blenkernel/BKE_blender.h | 79 + source/blender/blenkernel/BKE_bmfont.h | 65 + source/blender/blenkernel/BKE_bmfont_types.h | 62 + source/blender/blenkernel/BKE_booleanops.h | 52 + .../blender/blenkernel/BKE_booleanops_mesh.h | 120 + source/blender/blenkernel/BKE_brush.h | 77 + source/blender/blenkernel/BKE_cdderivedmesh.h | 109 + source/blender/blenkernel/BKE_colortools.h | 62 + source/blender/blenkernel/BKE_constraint.h | 140 + source/blender/blenkernel/BKE_curve.h | 91 + source/blender/blenkernel/BKE_customdata.h | 244 + source/blender/blenkernel/BKE_deform.h | 53 + source/blender/blenkernel/BKE_depsgraph.h | 113 + source/blender/blenkernel/BKE_displist.h | 127 + source/blender/blenkernel/BKE_effect.h | 79 + source/blender/blenkernel/BKE_endian.h | 47 + source/blender/blenkernel/BKE_exotic.h | 56 + source/blender/blenkernel/BKE_font.h | 74 + source/blender/blenkernel/BKE_global.h | 264 + source/blender/blenkernel/BKE_group.h | 57 + source/blender/blenkernel/BKE_icons.h | 88 + source/blender/blenkernel/BKE_idprop.h | 177 + source/blender/blenkernel/BKE_image.h | 156 + source/blender/blenkernel/BKE_ipo.h | 118 + source/blender/blenkernel/BKE_key.h | 65 + source/blender/blenkernel/BKE_lattice.h | 74 + source/blender/blenkernel/BKE_library.h | 77 + source/blender/blenkernel/BKE_main.h | 85 + source/blender/blenkernel/BKE_material.h | 78 + source/blender/blenkernel/BKE_mball.h | 182 + source/blender/blenkernel/BKE_mesh.h | 127 + source/blender/blenkernel/BKE_modifier.h | 295 + source/blender/blenkernel/BKE_nla.h | 47 + source/blender/blenkernel/BKE_node.h | 347 + source/blender/blenkernel/BKE_object.h | 118 + source/blender/blenkernel/BKE_packedFile.h | 64 + source/blender/blenkernel/BKE_plugin_types.h | 72 + source/blender/blenkernel/BKE_property.h | 55 + source/blender/blenkernel/BKE_sca.h | 75 + source/blender/blenkernel/BKE_scene.h | 84 + source/blender/blenkernel/BKE_screen.h | 40 + source/blender/blenkernel/BKE_script.h | 49 + source/blender/blenkernel/BKE_softbody.h | 58 + source/blender/blenkernel/BKE_sound.h | 55 + source/blender/blenkernel/BKE_subsurf.h | 49 + source/blender/blenkernel/BKE_text.h | 144 + source/blender/blenkernel/BKE_texture.h | 80 + source/blender/blenkernel/BKE_utildefines.h | 192 + source/blender/blenkernel/BKE_verse.h | 586 + source/blender/blenkernel/BKE_world.h | 45 + source/blender/blenkernel/BKE_writeavi.h | 62 + source/blender/blenkernel/BKE_writeffmpeg.h | 76 + .../blender/blenkernel/BKE_writeframeserver.h | 50 + source/blender/blenkernel/CMakeLists.txt | 77 + source/blender/blenkernel/Makefile | 37 + source/blender/blenkernel/SConscript | 47 + .../bad_level_call_stubs/CMakeLists.txt | 46 + .../blenkernel/bad_level_call_stubs/Makefile | 51 + .../bad_level_call_stubs/SConscript | 14 + .../blenkernel/bad_level_call_stubs/stubs.c | 338 + source/blender/blenkernel/depsgraph_private.h | 133 + source/blender/blenkernel/intern/CCGSubSurf.c | 2294 +++ source/blender/blenkernel/intern/CCGSubSurf.h | 152 + .../blender/blenkernel/intern/DerivedMesh.c | 3310 ++++ source/blender/blenkernel/intern/Makefile | 109 + source/blender/blenkernel/intern/action.c | 1373 ++ source/blender/blenkernel/intern/anim.c | 844 + source/blender/blenkernel/intern/armature.c | 2130 +++ source/blender/blenkernel/intern/blender.c | 735 + source/blender/blenkernel/intern/bmfont.c | 297 + source/blender/blenkernel/intern/brush.c | 882 + .../blender/blenkernel/intern/cdderivedmesh.c | 1130 ++ source/blender/blenkernel/intern/colortools.c | 719 + source/blender/blenkernel/intern/constraint.c | 3422 ++++ source/blender/blenkernel/intern/curve.c | 2595 +++ source/blender/blenkernel/intern/customdata.c | 1482 ++ source/blender/blenkernel/intern/deform.c | 225 + source/blender/blenkernel/intern/depsgraph.c | 2236 +++ source/blender/blenkernel/intern/displist.c | 1589 ++ source/blender/blenkernel/intern/effect.c | 2110 +++ source/blender/blenkernel/intern/exotic.c | 4943 ++++++ source/blender/blenkernel/intern/font.c | 1189 ++ source/blender/blenkernel/intern/group.c | 327 + source/blender/blenkernel/intern/icons.c | 302 + source/blender/blenkernel/intern/idprop.c | 443 + source/blender/blenkernel/intern/image.c | 1805 ++ source/blender/blenkernel/intern/ipo.c | 2432 +++ source/blender/blenkernel/intern/key.c | 1408 ++ source/blender/blenkernel/intern/lattice.c | 915 + source/blender/blenkernel/intern/library.c | 1098 ++ source/blender/blenkernel/intern/material.c | 1110 ++ source/blender/blenkernel/intern/mball.c | 2088 +++ source/blender/blenkernel/intern/mesh.c | 1250 ++ source/blender/blenkernel/intern/modifier.c | 5765 +++++++ source/blender/blenkernel/intern/nla.c | 190 + source/blender/blenkernel/intern/node.c | 2414 +++ source/blender/blenkernel/intern/object.c | 2080 +++ source/blender/blenkernel/intern/packedFile.c | 614 + source/blender/blenkernel/intern/property.c | 269 + source/blender/blenkernel/intern/sca.c | 638 + source/blender/blenkernel/intern/scene.c | 564 + source/blender/blenkernel/intern/screen.c | 57 + source/blender/blenkernel/intern/script.c | 71 + source/blender/blenkernel/intern/softbody.c | 3420 ++++ source/blender/blenkernel/intern/sound.c | 138 + .../blender/blenkernel/intern/subsurf_ccg.c | 2540 +++ source/blender/blenkernel/intern/text.c | 2393 +++ source/blender/blenkernel/intern/texture.c | 820 + .../blenkernel/intern/verse_bitmap_node.c | 451 + .../blenkernel/intern/verse_geometry_node.c | 2101 +++ .../blender/blenkernel/intern/verse_method.c | 523 + source/blender/blenkernel/intern/verse_node.c | 750 + .../blenkernel/intern/verse_object_node.c | 620 + .../blender/blenkernel/intern/verse_session.c | 480 + source/blender/blenkernel/intern/world.c | 187 + source/blender/blenkernel/intern/writeavi.c | 223 + .../blender/blenkernel/intern/writeffmpeg.c | 827 + .../blenkernel/intern/writeframeserver.c | 381 + source/blender/blenlib/BLI_arithb.h | 385 + source/blender/blenlib/BLI_blenlib.h | 406 + source/blender/blenlib/BLI_boxpack2d.h | 69 + source/blender/blenlib/BLI_dynamiclist.h | 58 + source/blender/blenlib/BLI_dynstr.h | 90 + source/blender/blenlib/BLI_edgehash.h | 99 + source/blender/blenlib/BLI_editVert.h | 190 + source/blender/blenlib/BLI_ghash.h | 118 + source/blender/blenlib/BLI_gsqueue.h | 96 + source/blender/blenlib/BLI_heap.h | 74 + source/blender/blenlib/BLI_jitter.h | 40 + source/blender/blenlib/BLI_linklist.h | 62 + source/blender/blenlib/BLI_memarena.h | 61 + source/blender/blenlib/BLI_rand.h | 99 + source/blender/blenlib/BLI_storage_types.h | 83 + source/blender/blenlib/BLI_threads.h | 54 + source/blender/blenlib/BLI_vfontdata.h | 103 + source/blender/blenlib/BLI_winstuff.h | 119 + source/blender/blenlib/CMakeLists.txt | 56 + source/blender/blenlib/MTC_matrixops.h | 165 + source/blender/blenlib/MTC_vectorops.h | 61 + source/blender/blenlib/Makefile | 37 + source/blender/blenlib/PIL_dynlib.h | 55 + source/blender/blenlib/PIL_time.h | 62 + source/blender/blenlib/SConscript | 26 + source/blender/blenlib/intern/BLI_callbacks.h | 44 + source/blender/blenlib/intern/BLI_dynstr.c | 118 + source/blender/blenlib/intern/BLI_fileops.h | 50 + source/blender/blenlib/intern/BLI_ghash.c | 295 + source/blender/blenlib/intern/BLI_heap.c | 220 + source/blender/blenlib/intern/BLI_linklist.c | 119 + source/blender/blenlib/intern/BLI_memarena.c | 96 + source/blender/blenlib/intern/BLI_scanfill.h | 41 + source/blender/blenlib/intern/BLI_storage.h | 41 + source/blender/blenlib/intern/BLI_util.h | 45 + source/blender/blenlib/intern/Makefile | 61 + source/blender/blenlib/intern/arithb.c | 3672 ++++ source/blender/blenlib/intern/boxpack2d.c | 416 + source/blender/blenlib/intern/dynlib.c | 343 + source/blender/blenlib/intern/edgehash.c | 220 + source/blender/blenlib/intern/fileops.c | 364 + source/blender/blenlib/intern/freetypefont.c | 634 + source/blender/blenlib/intern/gsqueue.c | 122 + source/blender/blenlib/intern/jitter.c | 178 + source/blender/blenlib/intern/matrixops.c | 441 + source/blender/blenlib/intern/noise.c | 1392 ++ source/blender/blenlib/intern/psfont.c | 2126 +++ source/blender/blenlib/intern/rand.c | 192 + source/blender/blenlib/intern/rct.c | 171 + source/blender/blenlib/intern/scanfill.c | 1056 ++ source/blender/blenlib/intern/storage.c | 540 + source/blender/blenlib/intern/threads.c | 221 + source/blender/blenlib/intern/time.c | 105 + source/blender/blenlib/intern/util.c | 1691 ++ source/blender/blenlib/intern/vectorops.c | 169 + source/blender/blenlib/intern/winstuff.c | 209 + source/blender/blenloader/BLO_genfile.h | 38 + source/blender/blenloader/BLO_readfile.h | 250 + source/blender/blenloader/BLO_soundfile.h | 44 + source/blender/blenloader/BLO_sys_types.h | 102 + source/blender/blenloader/BLO_undofile.h | 58 + source/blender/blenloader/BLO_writefile.h | 44 + source/blender/blenloader/CMakeLists.txt | 46 + source/blender/blenloader/Makefile | 37 + source/blender/blenloader/SConscript | 18 + source/blender/blenloader/intern/Makefile | 76 + source/blender/blenloader/intern/genfile.c | 1102 ++ source/blender/blenloader/intern/genfile.h | 49 + .../blender/blenloader/intern/readblenentry.c | 456 + source/blender/blenloader/intern/readfile.c | 8134 +++++++++ source/blender/blenloader/intern/readfile.h | 127 + source/blender/blenloader/intern/undofile.c | 146 + source/blender/blenloader/intern/writefile.c | 2202 +++ source/blender/blenpluginapi/CMakeLists.txt | 42 + source/blender/blenpluginapi/Makefile | 37 + source/blender/blenpluginapi/SConscript | 14 + source/blender/blenpluginapi/documentation.h | 72 + source/blender/blenpluginapi/externdef.h | 43 + source/blender/blenpluginapi/floatpatch.h | 90 + source/blender/blenpluginapi/iff.h | 215 + source/blender/blenpluginapi/intern/Makefile | 57 + .../blender/blenpluginapi/intern/pluginapi.c | 365 + source/blender/blenpluginapi/plugin.DEF | 40 + source/blender/blenpluginapi/plugin.h | 103 + source/blender/blenpluginapi/util.h | 100 + source/blender/ftfont/CMakeLists.txt | 46 + source/blender/ftfont/FTF_Api.h | 166 + source/blender/ftfont/FTF_Settings.h | 49 + source/blender/ftfont/Makefile | 37 + source/blender/ftfont/SConscript | 16 + source/blender/ftfont/intern/FTF_Api.cpp | 208 + source/blender/ftfont/intern/FTF_TTFont.cpp | 448 + source/blender/ftfont/intern/FTF_TTFont.h | 139 + source/blender/ftfont/intern/Makefile | 59 + source/blender/imbuf/CMakeLists.txt | 61 + source/blender/imbuf/IMB_imbuf.h | 583 + source/blender/imbuf/IMB_imbuf_types.h | 242 + source/blender/imbuf/IMB_thumbs.h | 74 + source/blender/imbuf/Makefile | 37 + source/blender/imbuf/SConscript | 34 + source/blender/imbuf/intern/IMB_allocimbuf.h | 59 + source/blender/imbuf/intern/IMB_amiga.h | 50 + source/blender/imbuf/intern/IMB_anim.h | 193 + source/blender/imbuf/intern/IMB_anim5.h | 20 + source/blender/imbuf/intern/IMB_bitplanes.h | 50 + source/blender/imbuf/intern/IMB_bmp.h | 50 + source/blender/imbuf/intern/IMB_cmap.h | 49 + source/blender/imbuf/intern/IMB_divers.h | 48 + source/blender/imbuf/intern/IMB_dpxcineon.h | 47 + source/blender/imbuf/intern/IMB_filter.h | 48 + source/blender/imbuf/intern/IMB_ham.h | 48 + source/blender/imbuf/intern/IMB_hamx.h | 50 + source/blender/imbuf/intern/IMB_iff.h | 49 + source/blender/imbuf/intern/IMB_imginfo.h | 85 + source/blender/imbuf/intern/IMB_iris.h | 49 + source/blender/imbuf/intern/IMB_jpeg.h | 52 + source/blender/imbuf/intern/IMB_png.h | 51 + .../blender/imbuf/intern/IMB_radiance_hdr.h | 42 + source/blender/imbuf/intern/IMB_targa.h | 51 + source/blender/imbuf/intern/IMB_tiff.h | 48 + source/blender/imbuf/intern/Makefile | 82 + source/blender/imbuf/intern/allocimbuf.c | 573 + source/blender/imbuf/intern/amiga.c | 538 + source/blender/imbuf/intern/anim.c | 932 + source/blender/imbuf/intern/anim5.c | 534 + source/blender/imbuf/intern/antialias.c | 469 + source/blender/imbuf/intern/bitplanes.c | 359 + source/blender/imbuf/intern/bmp.c | 248 + .../imbuf/intern/cineon/CMakeLists.txt | 44 + source/blender/imbuf/intern/cineon/Makefile | 60 + source/blender/imbuf/intern/cineon/README | 8 + source/blender/imbuf/intern/cineon/SConscript | 17 + .../imbuf/intern/cineon/cin_debug_stuff.h | 1 + .../blender/imbuf/intern/cineon/cineon_dpx.c | 193 + .../blender/imbuf/intern/cineon/cineonfile.h | 143 + .../blender/imbuf/intern/cineon/cineonlib.c | 802 + .../blender/imbuf/intern/cineon/cineonlib.h | 68 + source/blender/imbuf/intern/cineon/dpxfile.h | 124 + source/blender/imbuf/intern/cineon/dpxlib.c | 625 + source/blender/imbuf/intern/cineon/dpxlib.h | 56 + .../imbuf/intern/cineon/logImageCore.c | 212 + .../imbuf/intern/cineon/logImageCore.h | 109 + .../blender/imbuf/intern/cineon/logImageLib.c | 158 + .../blender/imbuf/intern/cineon/logImageLib.h | 86 + .../blender/imbuf/intern/cineon/logmemfile.c | 77 + .../blender/imbuf/intern/cineon/logmemfile.h | 29 + source/blender/imbuf/intern/cmap.c | 583 + source/blender/imbuf/intern/cspace.c | 179 + source/blender/imbuf/intern/data.c | 145 + source/blender/imbuf/intern/dds/BlockDXT.cpp | 523 + source/blender/imbuf/intern/dds/BlockDXT.h | 227 + source/blender/imbuf/intern/dds/Color.h | 99 + .../blender/imbuf/intern/dds/ColorBlock.cpp | 310 + source/blender/imbuf/intern/dds/ColorBlock.h | 115 + source/blender/imbuf/intern/dds/Common.h | 44 + .../imbuf/intern/dds/DirectDrawSurface.cpp | 924 + .../imbuf/intern/dds/DirectDrawSurface.h | 162 + source/blender/imbuf/intern/dds/Image.cpp | 132 + source/blender/imbuf/intern/dds/Image.h | 103 + source/blender/imbuf/intern/dds/Makefile | 63 + source/blender/imbuf/intern/dds/SConscript | 19 + source/blender/imbuf/intern/dds/Stream.cpp | 99 + source/blender/imbuf/intern/dds/Stream.h | 49 + source/blender/imbuf/intern/dds/dds_api.cpp | 132 + source/blender/imbuf/intern/dds/dds_api.h | 43 + source/blender/imbuf/intern/dither.c | 133 + source/blender/imbuf/intern/divers.c | 258 + source/blender/imbuf/intern/dynlibtiff.c | 197 + source/blender/imbuf/intern/dynlibtiff.h | 58 + source/blender/imbuf/intern/filter.c | 329 + source/blender/imbuf/intern/gen_dynlibtiff.py | 254 + source/blender/imbuf/intern/ham.c | 279 + source/blender/imbuf/intern/hamx.c | 583 + source/blender/imbuf/intern/iff.c | 226 + source/blender/imbuf/intern/imageprocess.c | 301 + source/blender/imbuf/intern/imbuf.h | 171 + source/blender/imbuf/intern/imbuf_patch.h | 114 + source/blender/imbuf/intern/imginfo.c | 158 + source/blender/imbuf/intern/iris.c | 653 + source/blender/imbuf/intern/jpeg.c | 620 + source/blender/imbuf/intern/matrix.h | 87 + source/blender/imbuf/intern/md5.c | 361 + source/blender/imbuf/intern/md5.h | 116 + .../imbuf/intern/openexr/CMakeLists.txt | 45 + source/blender/imbuf/intern/openexr/Makefile | 48 + .../blender/imbuf/intern/openexr/SConscript | 18 + .../imbuf/intern/openexr/openexr_api.cpp | 967 ++ .../imbuf/intern/openexr/openexr_api.h | 59 + .../imbuf/intern/openexr/openexr_multi.h | 93 + source/blender/imbuf/intern/png.c | 461 + source/blender/imbuf/intern/radiance_hdr.c | 366 + source/blender/imbuf/intern/readimage.c | 311 + source/blender/imbuf/intern/rectop.c | 601 + source/blender/imbuf/intern/rotate.c | 120 + source/blender/imbuf/intern/scaling.c | 1267 ++ source/blender/imbuf/intern/targa.c | 647 + source/blender/imbuf/intern/thumbs.c | 459 + source/blender/imbuf/intern/tiff.c | 547 + source/blender/imbuf/intern/util.c | 397 + source/blender/imbuf/intern/writeimage.c | 185 + source/blender/imbuf/readme.txt | 50 + source/blender/include/BDR_drawaction.h | 88 + source/blender/include/BDR_drawmesh.h | 84 + source/blender/include/BDR_drawobject.h | 82 + source/blender/include/BDR_editcurve.h | 102 + source/blender/include/BDR_editface.h | 61 + source/blender/include/BDR_editmball.h | 56 + source/blender/include/BDR_editobject.h | 125 + source/blender/include/BDR_imagepaint.h | 44 + source/blender/include/BDR_sculptmode.h | 142 + source/blender/include/BDR_unwrapper.h | 51 + source/blender/include/BDR_vpaint.h | 58 + source/blender/include/BIF_butspace.h | 139 + source/blender/include/BIF_cursors.h | 103 + source/blender/include/BIF_drawimage.h | 74 + source/blender/include/BIF_drawoops.h | 41 + source/blender/include/BIF_drawscene.h | 35 + source/blender/include/BIF_drawscript.h | 41 + source/blender/include/BIF_drawseq.h | 46 + source/blender/include/BIF_drawtext.h | 54 + source/blender/include/BIF_editaction.h | 162 + source/blender/include/BIF_editarmature.h | 142 + source/blender/include/BIF_editconstraint.h | 72 + source/blender/include/BIF_editdeform.h | 74 + source/blender/include/BIF_editfont.h | 73 + source/blender/include/BIF_editgroup.h | 40 + source/blender/include/BIF_editkey.h | 70 + source/blender/include/BIF_editlattice.h | 45 + source/blender/include/BIF_editmesh.h | 265 + source/blender/include/BIF_editmode_undo.h | 59 + source/blender/include/BIF_editnla.h | 65 + source/blender/include/BIF_editoops.h | 47 + source/blender/include/BIF_editsca.h | 41 + source/blender/include/BIF_editseq.h | 134 + source/blender/include/BIF_editsima.h | 124 + source/blender/include/BIF_editsound.h | 87 + source/blender/include/BIF_editview.h | 60 + source/blender/include/BIF_filelist.h | 87 + source/blender/include/BIF_fsmenu.h | 76 + source/blender/include/BIF_gl.h | 82 + source/blender/include/BIF_glutil.h | 225 + source/blender/include/BIF_graphics.h | 59 + source/blender/include/BIF_imasel.h | 51 + source/blender/include/BIF_interface.h | 331 + source/blender/include/BIF_interface_icons.h | 72 + source/blender/include/BIF_keyval.h | 39 + source/blender/include/BIF_language.h | 69 + source/blender/include/BIF_mainqueue.h | 47 + source/blender/include/BIF_meshlaplacian.h | 87 + source/blender/include/BIF_meshtools.h | 50 + source/blender/include/BIF_mywindow.h | 145 + source/blender/include/BIF_oops.h | 71 + source/blender/include/BIF_outliner.h | 106 + source/blender/include/BIF_poseobject.h | 71 + source/blender/include/BIF_previewrender.h | 94 + source/blender/include/BIF_renderwin.h | 67 + source/blender/include/BIF_resources.h | 599 + source/blender/include/BIF_retopo.h | 110 + source/blender/include/BIF_scrarea.h | 54 + source/blender/include/BIF_screen.h | 137 + source/blender/include/BIF_space.h | 148 + source/blender/include/BIF_spacetypes.h | 67 + source/blender/include/BIF_tbcallback.h | 42 + source/blender/include/BIF_toets.h | 41 + source/blender/include/BIF_toolbox.h | 68 + source/blender/include/BIF_transform.h | 108 + source/blender/include/BIF_usiblender.h | 54 + source/blender/include/BIF_verse.h | 142 + source/blender/include/BIF_writeavicodec.h | 44 + source/blender/include/BIF_writeimage.h | 45 + source/blender/include/BIF_writemovie.h | 41 + source/blender/include/BPI_script.h | 71 + source/blender/include/BSE_drawimasel.h | 60 + source/blender/include/BSE_drawipo.h | 76 + source/blender/include/BSE_drawnla.h | 52 + source/blender/include/BSE_drawoops.h | 50 + source/blender/include/BSE_drawview.h | 88 + source/blender/include/BSE_edit.h | 55 + source/blender/include/BSE_editaction_types.h | 77 + source/blender/include/BSE_editipo.h | 178 + source/blender/include/BSE_editipo_types.h | 53 + source/blender/include/BSE_editnla_types.h | 41 + source/blender/include/BSE_filesel.h | 66 + source/blender/include/BSE_headerbuttons.h | 158 + source/blender/include/BSE_node.h | 137 + source/blender/include/BSE_seqaudio.h | 53 + source/blender/include/BSE_seqeffects.h | 96 + source/blender/include/BSE_seqscopes.h | 38 + source/blender/include/BSE_sequence.h | 85 + source/blender/include/BSE_time.h | 71 + source/blender/include/BSE_trans_types.h | 90 + source/blender/include/BSE_types.h | 69 + source/blender/include/BSE_view.h | 97 + source/blender/include/LOD_DependKludge.h | 40 + source/blender/include/blendef.h | 460 + source/blender/include/butspace.h | 723 + source/blender/include/datatoc.h | 63 + source/blender/include/editlattice_ext.h | 42 + source/blender/include/editmesh.h | 110 + source/blender/include/interface.h | 236 + source/blender/include/keyed_functions.h | 58 + source/blender/include/license_key.h | 95 + source/blender/include/multires.h | 81 + source/blender/include/mydevice.h | 260 + source/blender/include/nla.h | 59 + source/blender/include/objfnt.h | 105 + source/blender/include/particle_effect.h | 47 + source/blender/include/playanim_ext.h | 41 + source/blender/include/transform.h | 452 + source/blender/makesdna/CMakeLists.txt | 30 + source/blender/makesdna/DNA_ID.h | 229 + source/blender/makesdna/DNA_action_types.h | 225 + source/blender/makesdna/DNA_actuator_types.h | 395 + source/blender/makesdna/DNA_armature_types.h | 154 + source/blender/makesdna/DNA_brush_types.h | 91 + source/blender/makesdna/DNA_camera_types.h | 91 + source/blender/makesdna/DNA_color_types.h | 81 + .../blender/makesdna/DNA_constraint_types.h | 493 + .../blender/makesdna/DNA_controller_types.h | 79 + source/blender/makesdna/DNA_curve_types.h | 290 + .../blender/makesdna/DNA_customdata_types.h | 102 + source/blender/makesdna/DNA_documentation.h | 79 + source/blender/makesdna/DNA_effect_types.h | 144 + .../blender/makesdna/DNA_fileglobal_types.h | 60 + source/blender/makesdna/DNA_group_types.h | 65 + source/blender/makesdna/DNA_image_types.h | 124 + source/blender/makesdna/DNA_ipo_types.h | 401 + source/blender/makesdna/DNA_key_types.h | 91 + source/blender/makesdna/DNA_lamp_types.h | 174 + source/blender/makesdna/DNA_lattice_types.h | 67 + source/blender/makesdna/DNA_listBase.h | 64 + source/blender/makesdna/DNA_material_types.h | 294 + source/blender/makesdna/DNA_mesh_types.h | 139 + source/blender/makesdna/DNA_meshdata_types.h | 250 + source/blender/makesdna/DNA_meta_types.h | 120 + source/blender/makesdna/DNA_modifier_types.h | 366 + source/blender/makesdna/DNA_nla_types.h | 105 + source/blender/makesdna/DNA_node_types.h | 257 + source/blender/makesdna/DNA_object_fluidsim.h | 157 + source/blender/makesdna/DNA_object_force.h | 154 + source/blender/makesdna/DNA_object_types.h | 442 + source/blender/makesdna/DNA_oops_types.h | 86 + .../blender/makesdna/DNA_packedFile_types.h | 65 + source/blender/makesdna/DNA_property_types.h | 68 + source/blender/makesdna/DNA_radio_types.h | 53 + source/blender/makesdna/DNA_scene_types.h | 672 + source/blender/makesdna/DNA_screen_types.h | 171 + .../blender/makesdna/DNA_scriptlink_types.h | 77 + source/blender/makesdna/DNA_sdna_types.h | 83 + source/blender/makesdna/DNA_sensor_types.h | 253 + source/blender/makesdna/DNA_sequence_types.h | 239 + source/blender/makesdna/DNA_sound_types.h | 183 + source/blender/makesdna/DNA_space_types.h | 649 + source/blender/makesdna/DNA_text_types.h | 80 + source/blender/makesdna/DNA_texture_types.h | 377 + source/blender/makesdna/DNA_userdef_types.h | 288 + source/blender/makesdna/DNA_vec_types.h | 91 + source/blender/makesdna/DNA_vfont_types.h | 63 + source/blender/makesdna/DNA_view2d_types.h | 67 + source/blender/makesdna/DNA_view3d_types.h | 212 + source/blender/makesdna/DNA_wave_types.h | 53 + source/blender/makesdna/DNA_world_types.h | 181 + source/blender/makesdna/Makefile | 42 + source/blender/makesdna/SConscript | 11 + source/blender/makesdna/intern/CMakeLists.txt | 37 + source/blender/makesdna/intern/Makefile | 86 + source/blender/makesdna/intern/SConscript | 41 + source/blender/makesdna/intern/makesdna.c | 1149 ++ source/blender/nodes/CMP_node.h | 105 + source/blender/nodes/CMakeLists.txt | 71 + source/blender/nodes/Makefile | 37 + source/blender/nodes/SConscript | 46 + source/blender/nodes/SHD_node.h | 68 + .../nodes/intern/CMP_nodes/CMP_alphaOver.c | 128 + .../blender/nodes/intern/CMP_nodes/CMP_blur.c | 687 + .../nodes/intern/CMP_nodes/CMP_brightness.c | 113 + .../nodes/intern/CMP_nodes/CMP_channelMatte.c | 207 + .../nodes/intern/CMP_nodes/CMP_chromaMatte.c | 192 + .../nodes/intern/CMP_nodes/CMP_colorSpill.c | 144 + .../nodes/intern/CMP_nodes/CMP_composite.c | 105 + .../blender/nodes/intern/CMP_nodes/CMP_crop.c | 119 + .../nodes/intern/CMP_nodes/CMP_curves.c | 206 + .../nodes/intern/CMP_nodes/CMP_defocus.c | 855 + .../nodes/intern/CMP_nodes/CMP_diffMatte.c | 217 + .../nodes/intern/CMP_nodes/CMP_dilate.c | 163 + .../nodes/intern/CMP_nodes/CMP_displace.c | 163 + .../nodes/intern/CMP_nodes/CMP_filter.c | 235 + .../blender/nodes/intern/CMP_nodes/CMP_flip.c | 105 + .../nodes/intern/CMP_nodes/CMP_gamma.c | 91 + .../nodes/intern/CMP_nodes/CMP_glare.c | 498 + .../nodes/intern/CMP_nodes/CMP_hueSatVal.c | 122 + .../nodes/intern/CMP_nodes/CMP_idMask.c | 104 + .../nodes/intern/CMP_nodes/CMP_image.c | 352 + .../nodes/intern/CMP_nodes/CMP_invert.c | 134 + .../nodes/intern/CMP_nodes/CMP_lensdist.c | 192 + .../nodes/intern/CMP_nodes/CMP_lummaMatte.c | 122 + .../nodes/intern/CMP_nodes/CMP_mapUV.c | 149 + .../nodes/intern/CMP_nodes/CMP_mapValue.c | 101 + .../blender/nodes/intern/CMP_nodes/CMP_math.c | 187 + .../nodes/intern/CMP_nodes/CMP_mixrgb.c | 96 + .../nodes/intern/CMP_nodes/CMP_normal.c | 97 + .../nodes/intern/CMP_nodes/CMP_normalize.c | 113 + .../nodes/intern/CMP_nodes/CMP_outputFile.c | 112 + .../blender/nodes/intern/CMP_nodes/CMP_rgb.c | 64 + .../nodes/intern/CMP_nodes/CMP_rotate.c | 150 + .../nodes/intern/CMP_nodes/CMP_scale.c | 125 + .../nodes/intern/CMP_nodes/CMP_sepcombHSVA.c | 191 + .../nodes/intern/CMP_nodes/CMP_sepcombRGBA.c | 167 + .../nodes/intern/CMP_nodes/CMP_sepcombYCCA.c | 197 + .../nodes/intern/CMP_nodes/CMP_sepcombYUVA.c | 190 + .../nodes/intern/CMP_nodes/CMP_setalpha.c | 89 + .../nodes/intern/CMP_nodes/CMP_splitViewer.c | 164 + .../nodes/intern/CMP_nodes/CMP_texture.c | 149 + .../nodes/intern/CMP_nodes/CMP_tonemap.c | 173 + .../nodes/intern/CMP_nodes/CMP_translate.c | 75 + .../nodes/intern/CMP_nodes/CMP_valToRgb.c | 157 + .../nodes/intern/CMP_nodes/CMP_value.c | 61 + .../nodes/intern/CMP_nodes/CMP_vecBlur.c | 110 + .../nodes/intern/CMP_nodes/CMP_viewer.c | 144 + .../nodes/intern/CMP_nodes/CMP_zcombine.c | 155 + .../blender/nodes/intern/CMP_nodes/Makefile | 47 + source/blender/nodes/intern/CMP_util.c | 1166 ++ source/blender/nodes/intern/CMP_util.h | 221 + source/blender/nodes/intern/Makefile | 47 + .../blender/nodes/intern/SHD_nodes/Makefile | 47 + .../nodes/intern/SHD_nodes/SHD_camera.c | 68 + .../nodes/intern/SHD_nodes/SHD_curves.c | 119 + .../nodes/intern/SHD_nodes/SHD_dynamic.c | 247 + .../blender/nodes/intern/SHD_nodes/SHD_geom.c | 144 + .../nodes/intern/SHD_nodes/SHD_hueSatVal.c | 94 + .../nodes/intern/SHD_nodes/SHD_invert.c | 83 + .../nodes/intern/SHD_nodes/SHD_mapping.c | 89 + .../nodes/intern/SHD_nodes/SHD_material.c | 224 + .../blender/nodes/intern/SHD_nodes/SHD_math.c | 197 + .../nodes/intern/SHD_nodes/SHD_mixRgb.c | 79 + .../nodes/intern/SHD_nodes/SHD_normal.c | 76 + .../nodes/intern/SHD_nodes/SHD_output.c | 82 + .../blender/nodes/intern/SHD_nodes/SHD_rgb.c | 61 + .../nodes/intern/SHD_nodes/SHD_sepcombRGB.c | 105 + .../nodes/intern/SHD_nodes/SHD_squeeze.c | 73 + .../nodes/intern/SHD_nodes/SHD_texture.c | 130 + .../nodes/intern/SHD_nodes/SHD_valToRgb.c | 116 + .../nodes/intern/SHD_nodes/SHD_value.c | 64 + .../nodes/intern/SHD_nodes/SHD_vectMath.c | 118 + source/blender/nodes/intern/SHD_util.c | 208 + source/blender/nodes/intern/SHD_util.h | 140 + source/blender/nodes/intern/node_util.c | 52 + source/blender/nodes/intern/node_util.h | 42 + source/blender/python/BPY_extern.h | 136 + source/blender/python/BPY_interface.c | 2663 +++ source/blender/python/BPY_menus.c | 1118 ++ source/blender/python/BPY_menus.h | 128 + source/blender/python/CMakeLists.txt | 57 + source/blender/python/Makefile | 37 + source/blender/python/SConscript | 26 + source/blender/python/api2_2x/Armature.c | 1490 ++ source/blender/python/api2_2x/Armature.h | 70 + source/blender/python/api2_2x/BGL.c | 1590 ++ source/blender/python/api2_2x/BGL.h | 333 + source/blender/python/api2_2x/BezTriple.c | 716 + source/blender/python/api2_2x/BezTriple.h | 64 + source/blender/python/api2_2x/Blender.c | 982 ++ source/blender/python/api2_2x/Blender.h | 41 + source/blender/python/api2_2x/Bone.c | 1425 ++ source/blender/python/api2_2x/Bone.h | 76 + source/blender/python/api2_2x/Camera.c | 1057 ++ source/blender/python/api2_2x/Camera.h | 82 + source/blender/python/api2_2x/Constraint.c | 2678 +++ source/blender/python/api2_2x/Constraint.h | 76 + source/blender/python/api2_2x/CurNurb.c | 1078 ++ source/blender/python/api2_2x/CurNurb.h | 70 + source/blender/python/api2_2x/Curve.c | 1659 ++ source/blender/python/api2_2x/Curve.h | 78 + source/blender/python/api2_2x/Draw.c | 2210 +++ source/blender/python/api2_2x/Draw.h | 77 + .../blender/python/api2_2x/EXPP_interface.c | 230 + .../blender/python/api2_2x/EXPP_interface.h | 56 + source/blender/python/api2_2x/Effect.c | 1575 ++ source/blender/python/api2_2x/Effect.h | 58 + source/blender/python/api2_2x/Font.c | 403 + source/blender/python/api2_2x/Font.h | 53 + source/blender/python/api2_2x/Geometry.c | 433 + source/blender/python/api2_2x/Geometry.h | 42 + source/blender/python/api2_2x/Group.c | 813 + source/blender/python/api2_2x/Group.h | 66 + source/blender/python/api2_2x/IDProp.c | 895 + source/blender/python/api2_2x/IDProp.h | 61 + source/blender/python/api2_2x/Image.c | 1339 ++ source/blender/python/api2_2x/Image.h | 60 + source/blender/python/api2_2x/Ipo.c | 1842 ++ source/blender/python/api2_2x/Ipo.h | 63 + source/blender/python/api2_2x/Ipocurve.c | 1080 ++ source/blender/python/api2_2x/Ipocurve.h | 58 + source/blender/python/api2_2x/Key.c | 683 + source/blender/python/api2_2x/Key.h | 68 + source/blender/python/api2_2x/Lamp.c | 1570 ++ source/blender/python/api2_2x/Lamp.h | 61 + source/blender/python/api2_2x/Lattice.c | 813 + source/blender/python/api2_2x/Lattice.h | 60 + source/blender/python/api2_2x/Library.c | 1192 ++ source/blender/python/api2_2x/Library.h | 78 + source/blender/python/api2_2x/MTex.c | 827 + source/blender/python/api2_2x/MTex.h | 63 + source/blender/python/api2_2x/Makefile | 64 + source/blender/python/api2_2x/Material.c | 3048 ++++ source/blender/python/api2_2x/Material.h | 78 + source/blender/python/api2_2x/Mathutils.c | 1804 ++ source/blender/python/api2_2x/Mathutils.h | 85 + source/blender/python/api2_2x/Mesh.c | 8648 ++++++++++ source/blender/python/api2_2x/Mesh.h | 127 + source/blender/python/api2_2x/Metaball.c | 1189 ++ source/blender/python/api2_2x/Metaball.h | 81 + source/blender/python/api2_2x/Modifier.c | 1693 ++ source/blender/python/api2_2x/Modifier.h | 72 + source/blender/python/api2_2x/NLA.c | 1590 ++ source/blender/python/api2_2x/NLA.h | 77 + source/blender/python/api2_2x/NMesh.c | 4164 +++++ source/blender/python/api2_2x/NMesh.h | 157 + source/blender/python/api2_2x/Node.c | 1213 ++ source/blender/python/api2_2x/Node.h | 91 + source/blender/python/api2_2x/Noise.c | 713 + source/blender/python/api2_2x/Object.c | 5942 +++++++ source/blender/python/api2_2x/Object.h | 62 + source/blender/python/api2_2x/Particle.c | 1040 ++ source/blender/python/api2_2x/Particle.h | 67 + source/blender/python/api2_2x/Pose.c | 1395 ++ source/blender/python/api2_2x/Pose.h | 71 + source/blender/python/api2_2x/Registry.c | 245 + source/blender/python/api2_2x/Registry.h | 50 + source/blender/python/api2_2x/Scene.c | 1839 ++ source/blender/python/api2_2x/Scene.h | 70 + source/blender/python/api2_2x/Sound.c | 607 + source/blender/python/api2_2x/Sound.h | 57 + source/blender/python/api2_2x/SurfNurb.c | 857 + source/blender/python/api2_2x/SurfNurb.h | 68 + source/blender/python/api2_2x/Sys.c | 400 + source/blender/python/api2_2x/Sys.h | 40 + source/blender/python/api2_2x/Text.c | 576 + source/blender/python/api2_2x/Text.h | 52 + source/blender/python/api2_2x/Text3d.c | 1206 ++ source/blender/python/api2_2x/Text3d.h | 56 + source/blender/python/api2_2x/Texture.c | 2501 +++ source/blender/python/api2_2x/Texture.h | 64 + source/blender/python/api2_2x/Types.c | 262 + source/blender/python/api2_2x/Types.h | 41 + source/blender/python/api2_2x/Window.c | 1526 ++ source/blender/python/api2_2x/Window.h | 43 + source/blender/python/api2_2x/World.c | 1034 ++ source/blender/python/api2_2x/World.h | 58 + source/blender/python/api2_2x/bpy.c | 86 + source/blender/python/api2_2x/bpy.h | 41 + source/blender/python/api2_2x/bpy_config.c | 414 + source/blender/python/api2_2x/bpy_config.h | 52 + source/blender/python/api2_2x/bpy_data.c | 817 + source/blender/python/api2_2x/bpy_data.h | 55 + source/blender/python/api2_2x/bpy_types.h | 93 + source/blender/python/api2_2x/charRGBA.c | 475 + source/blender/python/api2_2x/charRGBA.h | 59 + source/blender/python/api2_2x/constant.c | 269 + source/blender/python/api2_2x/constant.h | 53 + .../blender/python/api2_2x/doc/API_intro.py | 247 + .../blender/python/api2_2x/doc/API_related.py | 564 + source/blender/python/api2_2x/doc/Armature.py | 368 + source/blender/python/api2_2x/doc/BGL.py | 1778 ++ .../blender/python/api2_2x/doc/BezTriple.py | 96 + source/blender/python/api2_2x/doc/Blender.py | 238 + .../python/api2_2x/doc/Blender_API.css | 44 + source/blender/python/api2_2x/doc/Bpy.py | 25 + .../blender/python/api2_2x/doc/Bpy_config.py | 38 + source/blender/python/api2_2x/doc/Bpy_data.py | 281 + source/blender/python/api2_2x/doc/Camera.py | 257 + .../blender/python/api2_2x/doc/Constraint.py | 248 + source/blender/python/api2_2x/doc/Curve.py | 721 + .../blender/python/api2_2x/doc/Curvedoc.txt | 105 + source/blender/python/api2_2x/doc/Draw.py | 880 + source/blender/python/api2_2x/doc/Effect.py | 590 + .../blender/python/api2_2x/doc/Effectdoc.txt | 257 + source/blender/python/api2_2x/doc/Font.py | 69 + source/blender/python/api2_2x/doc/Geometry.py | 97 + source/blender/python/api2_2x/doc/Group.py | 127 + source/blender/python/api2_2x/doc/IDProp.py | 130 + source/blender/python/api2_2x/doc/Image.py | 374 + source/blender/python/api2_2x/doc/Ipo.py | 437 + source/blender/python/api2_2x/doc/IpoCurve.py | 226 + source/blender/python/api2_2x/doc/Ipodoc.txt | 66 + source/blender/python/api2_2x/doc/Key.py | 124 + source/blender/python/api2_2x/doc/Lamp.py | 521 + source/blender/python/api2_2x/doc/Lattice.py | 209 + source/blender/python/api2_2x/doc/LibData.py | 137 + source/blender/python/api2_2x/doc/Library.py | 114 + source/blender/python/api2_2x/doc/Material.py | 1061 ++ .../blender/python/api2_2x/doc/Mathutils.py | 864 + source/blender/python/api2_2x/doc/Mesh.py | 1210 ++ .../python/api2_2x/doc/MeshPrimitives.py | 157 + source/blender/python/api2_2x/doc/Metaball.py | 246 + .../python/api2_2x/doc/Metaballdoc.txt | 58 + source/blender/python/api2_2x/doc/Modifier.py | 225 + source/blender/python/api2_2x/doc/NLA.py | 245 + source/blender/python/api2_2x/doc/NMesh.py | 823 + source/blender/python/api2_2x/doc/Noise.py | 300 + source/blender/python/api2_2x/doc/Object.py | 1754 ++ source/blender/python/api2_2x/doc/Pose.py | 245 + source/blender/python/api2_2x/doc/Radio.py | 351 + source/blender/python/api2_2x/doc/Registry.py | 122 + source/blender/python/api2_2x/doc/Render.py | 1192 ++ source/blender/python/api2_2x/doc/Scene.py | 392 + source/blender/python/api2_2x/doc/Sound.py | 147 + source/blender/python/api2_2x/doc/Sys.py | 167 + source/blender/python/api2_2x/doc/Text.py | 129 + source/blender/python/api2_2x/doc/Text3d.py | 302 + source/blender/python/api2_2x/doc/Texture.py | 555 + source/blender/python/api2_2x/doc/Theme.py | 211 + source/blender/python/api2_2x/doc/TimeLine.py | 80 + source/blender/python/api2_2x/doc/Types.py | 70 + source/blender/python/api2_2x/doc/Window.py | 524 + source/blender/python/api2_2x/doc/World.py | 351 + .../blender/python/api2_2x/doc/Worlddoc.txt | 55 + .../python/api2_2x/doc/epy_docgen-3.sh | 12 + .../blender/python/api2_2x/doc/epy_docgen.sh | 12 + .../blender/python/api2_2x/doc/id_generics.py | 30 + source/blender/python/api2_2x/doc/testbgl.py | 45 + .../blender/python/api2_2x/doc/testcamera.py | 137 + .../blender/python/api2_2x/doc/testcurve.py | 20 + .../blender/python/api2_2x/doc/testeffect.py | 65 + source/blender/python/api2_2x/doc/testipo.py | 24 + .../blender/python/api2_2x/doc/testmball.py | 37 + source/blender/python/api2_2x/doc/testtext.py | 29 + .../blender/python/api2_2x/doc/testworld.py | 21 + source/blender/python/api2_2x/euler.c | 502 + source/blender/python/api2_2x/euler.h | 67 + source/blender/python/api2_2x/gen_library.c | 332 + source/blender/python/api2_2x/gen_library.h | 94 + source/blender/python/api2_2x/gen_utils.c | 948 + source/blender/python/api2_2x/gen_utils.h | 176 + source/blender/python/api2_2x/logic.c | 529 + source/blender/python/api2_2x/logic.h | 61 + source/blender/python/api2_2x/matrix.c | 975 ++ source/blender/python/api2_2x/matrix.h | 80 + source/blender/python/api2_2x/meshPrimitive.c | 279 + source/blender/python/api2_2x/meshPrimitive.h | 46 + source/blender/python/api2_2x/modules.h | 65 + source/blender/python/api2_2x/point.c | 526 + source/blender/python/api2_2x/point.h | 67 + source/blender/python/api2_2x/quat.c | 668 + source/blender/python/api2_2x/quat.h | 73 + source/blender/python/api2_2x/rgbTuple.c | 420 + source/blender/python/api2_2x/rgbTuple.h | 56 + source/blender/python/api2_2x/sceneRadio.c | 893 + source/blender/python/api2_2x/sceneRadio.h | 51 + source/blender/python/api2_2x/sceneRender.c | 3216 ++++ source/blender/python/api2_2x/sceneRender.h | 52 + source/blender/python/api2_2x/sceneSequence.c | 1133 ++ source/blender/python/api2_2x/sceneSequence.h | 83 + source/blender/python/api2_2x/sceneTimeLine.c | 319 + source/blender/python/api2_2x/sceneTimeLine.h | 58 + source/blender/python/api2_2x/vector.c | 1264 ++ source/blender/python/api2_2x/vector.h | 61 + source/blender/python/api2_2x/windowTheme.c | 828 + source/blender/python/api2_2x/windowTheme.h | 60 + source/blender/quicktime/CMakeLists.txt | 58 + source/blender/quicktime/Makefile | 40 + source/blender/quicktime/SConscript | 29 + source/blender/quicktime/apple/Makefile | 60 + .../quicktime/apple/quicktime_export.c | 683 + .../quicktime/apple/quicktime_import.c | 779 + source/blender/quicktime/quicktime_export.h | 52 + source/blender/quicktime/quicktime_import.h | 105 + source/blender/radiosity/CMakeLists.txt | 39 + source/blender/radiosity/Makefile | 37 + source/blender/radiosity/SConscript | 12 + .../blender/radiosity/extern/include/radio.h | 174 + .../radiosity/extern/include/radio_types.h | 175 + source/blender/radiosity/intern/Makefile | 37 + .../blender/radiosity/intern/source/Makefile | 56 + .../radiosity/intern/source/raddisplay.c | 490 + .../radiosity/intern/source/radfactors.c | 946 + .../blender/radiosity/intern/source/radio.c | 397 + .../blender/radiosity/intern/source/radnode.c | 1106 ++ .../radiosity/intern/source/radpostprocess.c | 832 + .../radiosity/intern/source/radpreprocess.c | 842 + .../radiosity/intern/source/radrender.c | 501 + .../blender/readblenfile/BLO_readblenfile.h | 84 + source/blender/readblenfile/CMakeLists.txt | 37 + source/blender/readblenfile/Makefile | 37 + source/blender/readblenfile/SConscript | 8 + .../readblenfile/intern/BLO_readblenfile.c | 175 + source/blender/readblenfile/intern/Makefile | 50 + .../readblenfile/stub/BLO_readblenfileSTUB.c | 96 + source/blender/readblenfile/stub/Makefile | 47 + source/blender/readblenfile/test/Makefile | 49 + source/blender/readblenfile/test/test.c | 58 + source/blender/render/CMakeLists.txt | 56 + source/blender/render/Makefile | 37 + source/blender/render/SConscript | 31 + .../render/extern/include/RE_pipeline.h | 217 + .../render/extern/include/RE_raytrace.h | 90 + .../render/extern/include/RE_render_ext.h | 57 + .../render/extern/include/RE_shader_ext.h | 182 + source/blender/render/intern/Makefile | 37 + source/blender/render/intern/include/envmap.h | 51 + .../intern/include/gammaCorrectionTables.h | 54 + .../render/intern/include/initrender.h | 52 + .../render/intern/include/pixelblending.h | 68 + .../render/intern/include/pixelshading.h | 62 + .../render/intern/include/render_types.h | 420 + .../render/intern/include/rendercore.h | 108 + .../render/intern/include/renderdatabase.h | 116 + .../render/intern/include/renderpipeline.h | 43 + .../blender/render/intern/include/shadbuf.h | 110 + .../blender/render/intern/include/shading.h | 83 + source/blender/render/intern/include/sss.h | 65 + .../blender/render/intern/include/texture.h | 74 + source/blender/render/intern/include/zbuf.h | 111 + source/blender/render/intern/source/Makefile | 68 + .../render/intern/source/convertblender.c | 4336 +++++ source/blender/render/intern/source/envmap.c | 719 + .../intern/source/gammaCorrectionTables.c | 148 + .../render/intern/source/imagetexture.c | 972 ++ .../blender/render/intern/source/initrender.c | 680 + .../blender/render/intern/source/pipeline.c | 2402 +++ .../render/intern/source/pixelblending.c | 288 + .../render/intern/source/pixelshading.c | 571 + .../blender/render/intern/source/rayshade.c | 2025 +++ .../blender/render/intern/source/raytrace.c | 1353 ++ .../blender/render/intern/source/rendercore.c | 1961 +++ .../render/intern/source/renderdatabase.c | 938 + source/blender/render/intern/source/shadbuf.c | 2050 +++ .../blender/render/intern/source/shadeinput.c | 1016 ++ .../render/intern/source/shadeoutput.c | 1653 ++ source/blender/render/intern/source/sss.c | 1024 ++ source/blender/render/intern/source/texture.c | 2455 +++ source/blender/render/intern/source/zbuf.c | 3438 ++++ source/blender/src/.BCkey | 1 + source/blender/src/B.blend.c | 3076 ++++ source/blender/src/Bfont.c | 139 + source/blender/src/CMakeLists.txt | 85 + source/blender/src/Makefile | 149 + source/blender/src/SConscript | 64 + source/blender/src/bfont.ttf.c | 5992 +++++++ source/blender/src/blenderbuttons.c | 2078 +++ source/blender/src/booleanops.c | 566 + source/blender/src/booleanops_mesh.c | 296 + source/blender/src/butspace.c | 799 + source/blender/src/buttons_editing.c | 5624 ++++++ source/blender/src/buttons_logic.c | 2814 +++ source/blender/src/buttons_object.c | 3546 ++++ source/blender/src/buttons_scene.c | 2070 +++ source/blender/src/buttons_script.c | 384 + source/blender/src/buttons_shading.c | 4235 +++++ source/blender/src/cmap.tga.c | 92 + source/blender/src/cmovie.tga.c | 205 + source/blender/src/cre/license.jpeg.c | 38 + source/blender/src/cre/license_key.c | 197 + source/blender/src/cursors.c | 840 + source/blender/src/drawaction.c | 1291 ++ source/blender/src/drawarmature.c | 2080 +++ source/blender/src/drawdeps.c | 316 + source/blender/src/drawimage.c | 2703 +++ source/blender/src/drawimasel.c | 734 + source/blender/src/drawipo.c | 2728 +++ source/blender/src/drawmesh.c | 1220 ++ source/blender/src/drawnla.c | 824 + source/blender/src/drawnode.c | 2871 +++ source/blender/src/drawobject.c | 4645 +++++ source/blender/src/drawoops.c | 521 + source/blender/src/drawscene.c | 142 + source/blender/src/drawscript.c | 153 + source/blender/src/drawseq.c | 1487 ++ source/blender/src/drawsound.c | 241 + source/blender/src/drawtext.c | 2175 +++ source/blender/src/drawtime.c | 421 + source/blender/src/drawview.c | 3465 ++++ source/blender/src/edit.c | 1889 ++ source/blender/src/editaction.c | 2916 ++++ source/blender/src/editarmature.c | 3144 ++++ source/blender/src/editconstraint.c | 1103 ++ source/blender/src/editcurve.c | 4435 +++++ source/blender/src/editdeform.c | 897 + source/blender/src/editface.c | 1437 ++ source/blender/src/editfont.c | 1289 ++ source/blender/src/editgroup.c | 186 + source/blender/src/editimasel.c | 1137 ++ source/blender/src/editipo.c | 5625 ++++++ source/blender/src/editipo_lib.c | 390 + source/blender/src/editipo_mods.c | 1356 ++ source/blender/src/editkey.c | 773 + source/blender/src/editlattice.c | 327 + source/blender/src/editmball.c | 533 + source/blender/src/editmesh.c | 2205 +++ source/blender/src/editmesh_add.c | 1349 ++ source/blender/src/editmesh_lib.c | 2207 +++ source/blender/src/editmesh_loop.c | 954 + source/blender/src/editmesh_mods.c | 4132 +++++ source/blender/src/editmesh_tools.c | 6800 ++++++++ source/blender/src/editmode_undo.c | 348 + source/blender/src/editnla.c | 2029 +++ source/blender/src/editnode.c | 2244 +++ source/blender/src/editobject.c | 5554 ++++++ source/blender/src/editoops.c | 675 + source/blender/src/editscreen.c | 3819 ++++ source/blender/src/editseq.c | 3703 ++++ source/blender/src/editsima.c | 2343 +++ source/blender/src/editsound.c | 1063 ++ source/blender/src/edittime.c | 1008 ++ source/blender/src/editview.c | 2776 +++ source/blender/src/eventdebug.c | 195 + source/blender/src/filelist.c | 1141 ++ source/blender/src/filesel.c | 2597 +++ source/blender/src/fluidsim.c | 1147 ++ source/blender/src/fsmenu.c | 257 + source/blender/src/ghostwinlay.c | 835 + source/blender/src/glutil.c | 695 + source/blender/src/hddaudio.c | 577 + source/blender/src/header_action.c | 1240 ++ source/blender/src/header_buttonswin.c | 728 + source/blender/src/header_filesel.c | 194 + source/blender/src/header_image.c | 1305 ++ source/blender/src/header_imasel.c | 211 + source/blender/src/header_info.c | 2119 +++ source/blender/src/header_ipo.c | 1365 ++ source/blender/src/header_nla.c | 562 + source/blender/src/header_node.c | 673 + source/blender/src/header_oops.c | 578 + source/blender/src/header_script.c | 280 + source/blender/src/header_seq.c | 727 + source/blender/src/header_sound.c | 444 + source/blender/src/header_text.c | 821 + source/blender/src/header_time.c | 539 + source/blender/src/header_view3d.c | 5261 ++++++ source/blender/src/headerbuttons.c | 2080 +++ source/blender/src/imagepaint.c | 790 + source/blender/src/imasel.c | 85 + source/blender/src/interface.c | 6684 +++++++ source/blender/src/interface_draw.c | 2467 +++ source/blender/src/interface_icons.c | 1074 ++ source/blender/src/interface_panel.c | 1950 +++ source/blender/src/keyval.c | 354 + source/blender/src/language.c | 453 + source/blender/src/lorem.c | 516 + source/blender/src/mainqueue.c | 102 + source/blender/src/meshlaplacian.c | 1777 ++ source/blender/src/meshtools.c | 980 ++ source/blender/src/multires-firstlevel.c | 410 + source/blender/src/multires.c | 1650 ++ source/blender/src/mywindow.c | 744 + source/blender/src/oops.c | 1104 ++ source/blender/src/outliner.c | 3640 ++++ source/blender/src/parametrizer.c | 4203 +++++ source/blender/src/parametrizer.h | 85 + source/blender/src/parametrizer_intern.h | 192 + source/blender/src/playanim.c | 794 + source/blender/src/poseobject.c | 963 ++ source/blender/src/preview.blend.c | 14367 ++++++++++++++++ source/blender/src/previewrender.c | 912 + source/blender/src/prvicons.c | 436 + source/blender/src/pub/license_key.c | 447 + source/blender/src/renderwin.c | 1431 ++ source/blender/src/resources.c | 913 + source/blender/src/retopo.c | 924 + source/blender/src/scrarea.c | 69 + source/blender/src/screendump.c | 161 + source/blender/src/sculptmode-stroke.c | 279 + source/blender/src/sculptmode.c | 2193 +++ source/blender/src/seqaudio.c | 546 + source/blender/src/seqeffects.c | 3029 ++++ source/blender/src/seqscopes.c | 340 + source/blender/src/sequence.c | 1713 ++ source/blender/src/space.c | 6603 +++++++ source/blender/src/spacetypes.c | 161 + source/blender/src/splash.jpg.c | 2483 +++ source/blender/src/swapbuffers.c | 289 + source/blender/src/toets.c | 973 ++ source/blender/src/toolbox.c | 2245 +++ source/blender/src/transform.c | 3890 +++++ source/blender/src/transform_constraints.c | 1027 ++ source/blender/src/transform_conversions.c | 3242 ++++ source/blender/src/transform_generics.c | 1009 ++ source/blender/src/transform_manipulator.c | 1692 ++ source/blender/src/transform_numinput.c | 247 + source/blender/src/transform_snap.c | 710 + source/blender/src/unwrapper.c | 480 + source/blender/src/usiblender.c | 1039 ++ source/blender/src/verse_common.c | 298 + source/blender/src/verse_image.c | 343 + source/blender/src/verse_mesh.c | 1629 ++ source/blender/src/verse_object.c | 600 + source/blender/src/view.c | 1867 ++ source/blender/src/vpaint.c | 1621 ++ source/blender/src/winlay.h | 88 + source/blender/src/writeavicodec.c | 835 + source/blender/src/writeimage.c | 242 + source/blender/src/writemovie.c | 502 + .../blender/verify/BLO_sign_verify_Header.h | 83 + source/blender/verify/BLO_signer_info.h | 48 + source/blender/verify/BLO_verify.h | 79 + source/blender/verify/Makefile | 37 + source/blender/verify/intern/BLO_verify.c | 427 + source/blender/verify/intern/Makefile | 53 + source/blender/yafray/CMakeLists.txt | 38 + source/blender/yafray/Makefile | 34 + source/blender/yafray/SConscript | 9 + source/blender/yafray/YafRay_Api.h | 17 + source/blender/yafray/intern/Makefile | 46 + source/blender/yafray/intern/api.cpp | 16 + source/blender/yafray/intern/export_File.cpp | 2058 +++ source/blender/yafray/intern/export_File.h | 34 + .../blender/yafray/intern/export_Plugin.cpp | 1981 +++ source/blender/yafray/intern/export_Plugin.h | 78 + source/blender/yafray/intern/yafexternal.cpp | 155 + source/blender/yafray/intern/yafexternal.h | 186 + .../blender/yafray/intern/yafray_Render.cpp | 219 + source/blender/yafray/intern/yafray_Render.h | 107 + source/creator/CMakeLists.txt | 276 + source/creator/Makefile | 66 + source/creator/SConscript | 18 + source/creator/buildinfo.c | 46 + source/creator/creator.c | 734 + source/darwin/Makefile | 58 + source/darwin/blender.app/Contents/Info.plist | 53 + .../darwin/blender.app/Contents/MacOS/blender | 1 + source/darwin/blender.app/Contents/PkgInfo | 1 + .../Contents/Resources/blender file icon.icns | Bin 0 -> 48363 bytes .../Contents/Resources/blender icon.icns | Bin 0 -> 43688 bytes .../blendercreator.app/Contents/Info.plist | 53 + .../Contents/MacOS/blendercreator | 1 + .../blendercreator.app/Contents/PkgInfo | 1 + .../Resources/blender creator icon.icns | Bin 0 -> 43688 bytes .../Contents/Resources/blender file icon.icns | Bin 0 -> 48363 bytes .../blenderplayer.app/Contents/Info.plist | 47 + .../Contents/MacOS/blenderplayer | 1 + .../darwin/blenderplayer.app/Contents/PkgInfo | 1 + .../Contents/Resources/blender file icon.icns | Bin 0 -> 48363 bytes .../Resources/blender player icon.icns | Bin 0 -> 43688 bytes .../blenderpublisher.app/Contents/Info.plist | 53 + .../Contents/MacOS/blenderpublisher | 1 + .../blenderpublisher.app/Contents/PkgInfo | 1 + .../Contents/Resources/blender file icon.icns | Bin 0 -> 1721 bytes .../Resources/blender publisher icon.icns | Bin 0 -> 1991 bytes .../BlenderRoutines/BL_KetsjiEmbedStart.cpp | 668 + .../gameengine/BlenderRoutines/CMakeLists.txt | 40 + .../BlenderRoutines/KX_BlenderCanvas.cpp | 165 + .../BlenderRoutines/KX_BlenderCanvas.h | 171 + .../BlenderRoutines/KX_BlenderGL.cpp | 316 + .../gameengine/BlenderRoutines/KX_BlenderGL.h | 65 + .../BlenderRoutines/KX_BlenderInputDevice.cpp | 37 + .../BlenderRoutines/KX_BlenderInputDevice.h | 223 + .../KX_BlenderKeyboardDevice.cpp | 172 + .../KX_BlenderKeyboardDevice.h | 52 + .../BlenderRoutines/KX_BlenderMouseDevice.cpp | 180 + .../BlenderRoutines/KX_BlenderMouseDevice.h | 50 + .../KX_BlenderPolyMaterial.cpp | 117 + .../BlenderRoutines/KX_BlenderPolyMaterial.h | 102 + .../BlenderRoutines/KX_BlenderRenderTools.cpp | 478 + .../BlenderRoutines/KX_BlenderRenderTools.h | 109 + .../BlenderRoutines/KX_BlenderSystem.cpp | 59 + .../BlenderRoutines/KX_BlenderSystem.h | 51 + source/gameengine/BlenderRoutines/Makefile | 77 + source/gameengine/BlenderRoutines/SConscript | 28 + source/gameengine/CMakeLists.txt | 50 + .../Converter/BL_ActionActuator.cpp | 907 + .../gameengine/Converter/BL_ActionActuator.h | 154 + .../Converter/BL_ArmatureObject.cpp | 207 + .../gameengine/Converter/BL_ArmatureObject.h | 92 + .../Converter/BL_BlenderDataConversion.cpp | 2270 +++ .../Converter/BL_BlenderDataConversion.h | 56 + .../Converter/BL_DeformableGameObject.cpp | 65 + .../Converter/BL_DeformableGameObject.h | 67 + .../gameengine/Converter/BL_MeshDeformer.cpp | 159 + source/gameengine/Converter/BL_MeshDeformer.h | 80 + .../gameengine/Converter/BL_SkinDeformer.cpp | 191 + source/gameengine/Converter/BL_SkinDeformer.h | 110 + .../Converter/BL_SkinMeshObject.cpp | 157 + .../gameengine/Converter/BL_SkinMeshObject.h | 181 + .../gameengine/Converter/BlenderWorldInfo.cpp | 237 + .../gameengine/Converter/BlenderWorldInfo.h | 103 + source/gameengine/Converter/CMakeLists.txt | 76 + .../KX_BlenderScalarInterpolator.cpp | 84 + .../Converter/KX_BlenderScalarInterpolator.h | 70 + .../Converter/KX_BlenderSceneConverter.cpp | 993 ++ .../Converter/KX_BlenderSceneConverter.h | 149 + .../Converter/KX_ConvertActuators.cpp | 862 + .../Converter/KX_ConvertActuators.h | 49 + .../Converter/KX_ConvertControllers.cpp | 182 + .../Converter/KX_ConvertControllers.h | 50 + .../Converter/KX_ConvertProperties.cpp | 137 + .../Converter/KX_ConvertProperties.h | 42 + .../Converter/KX_ConvertSensors.cpp | 740 + .../gameengine/Converter/KX_ConvertSensors.h | 47 + source/gameengine/Converter/KX_IpoConvert.cpp | 757 + source/gameengine/Converter/KX_IpoConvert.h | 58 + source/gameengine/Converter/Makefile | 66 + source/gameengine/Converter/SConscript | 25 + source/gameengine/Expressions/BoolValue.cpp | 214 + source/gameengine/Expressions/BoolValue.h | 52 + source/gameengine/Expressions/CMakeLists.txt | 41 + source/gameengine/Expressions/ConstExpr.cpp | 132 + source/gameengine/Expressions/ConstExpr.h | 47 + source/gameengine/Expressions/EXP_C-Api.cpp | 127 + source/gameengine/Expressions/EXP_C-Api.h | 68 + source/gameengine/Expressions/EmptyValue.cpp | 127 + source/gameengine/Expressions/EmptyValue.h | 40 + source/gameengine/Expressions/ErrorValue.cpp | 123 + source/gameengine/Expressions/ErrorValue.h | 39 + source/gameengine/Expressions/Expression.cpp | 76 + source/gameengine/Expressions/Expression.h | 132 + source/gameengine/Expressions/FloatValue.cpp | 316 + source/gameengine/Expressions/FloatValue.h | 48 + .../gameengine/Expressions/IdentifierExpr.cpp | 106 + .../gameengine/Expressions/IdentifierExpr.h | 55 + source/gameengine/Expressions/IfExpr.cpp | 144 + source/gameengine/Expressions/IfExpr.h | 50 + source/gameengine/Expressions/InputParser.cpp | 654 + source/gameengine/Expressions/InputParser.h | 106 + source/gameengine/Expressions/IntValue.cpp | 327 + source/gameengine/Expressions/IntValue.h | 60 + .../gameengine/Expressions/KX_HashedPtr.cpp | 66 + source/gameengine/Expressions/KX_HashedPtr.h | 53 + source/gameengine/Expressions/KX_Python.h | 58 + .../Expressions/KX_Python_dynamic.h | 39 + .../gameengine/Expressions/KX_Python_static.h | 39 + source/gameengine/Expressions/ListValue.cpp | 563 + source/gameengine/Expressions/ListValue.h | 77 + source/gameengine/Expressions/Makefile | 46 + .../gameengine/Expressions/Operator1Expr.cpp | 152 + source/gameengine/Expressions/Operator1Expr.h | 52 + .../gameengine/Expressions/Operator2Expr.cpp | 277 + source/gameengine/Expressions/Operator2Expr.h | 59 + .../gameengine/Expressions/PyObjectPlus.cpp | 178 + source/gameengine/Expressions/PyObjectPlus.h | 188 + source/gameengine/Expressions/SConscript | 9 + source/gameengine/Expressions/StringValue.cpp | 140 + source/gameengine/Expressions/StringValue.h | 52 + source/gameengine/Expressions/Value.cpp | 769 + source/gameengine/Expressions/Value.h | 442 + source/gameengine/Expressions/VectorValue.cpp | 217 + source/gameengine/Expressions/VectorValue.h | 85 + source/gameengine/Expressions/VoidValue.h | 68 + source/gameengine/GameLogic/CMakeLists.txt | 43 + source/gameengine/GameLogic/Joystick/Makefile | 47 + .../GameLogic/Joystick/SCA_Joystick.cpp | 374 + .../GameLogic/Joystick/SCA_Joystick.h | 388 + .../GameLogic/Joystick/SCA_JoystickDefines.h | 52 + .../GameLogic/Joystick/SCA_JoystickEvents.cpp | 73 + .../GameLogic/Joystick/SCA_JoystickPrivate.h | 52 + source/gameengine/GameLogic/Makefile | 50 + .../GameLogic/SCA_ANDController.cpp | 147 + .../gameengine/GameLogic/SCA_ANDController.h | 59 + .../GameLogic/SCA_AlwaysEventManager.cpp | 69 + .../GameLogic/SCA_AlwaysEventManager.h | 51 + .../gameengine/GameLogic/SCA_AlwaysSensor.cpp | 142 + .../gameengine/GameLogic/SCA_AlwaysSensor.h | 62 + .../gameengine/GameLogic/SCA_EventManager.cpp | 83 + .../gameengine/GameLogic/SCA_EventManager.h | 73 + .../GameLogic/SCA_ExpressionController.cpp | 164 + .../GameLogic/SCA_ExpressionController.h | 64 + source/gameengine/GameLogic/SCA_IActuator.cpp | 114 + source/gameengine/GameLogic/SCA_IActuator.h | 83 + .../gameengine/GameLogic/SCA_IController.cpp | 123 + source/gameengine/GameLogic/SCA_IController.h | 58 + .../gameengine/GameLogic/SCA_IInputDevice.cpp | 138 + .../gameengine/GameLogic/SCA_IInputDevice.h | 312 + .../gameengine/GameLogic/SCA_ILogicBrick.cpp | 324 + source/gameengine/GameLogic/SCA_ILogicBrick.h | 112 + source/gameengine/GameLogic/SCA_IObject.cpp | 354 + source/gameengine/GameLogic/SCA_IObject.h | 129 + source/gameengine/GameLogic/SCA_IScene.cpp | 69 + source/gameengine/GameLogic/SCA_IScene.h | 66 + source/gameengine/GameLogic/SCA_ISensor.cpp | 334 + source/gameengine/GameLogic/SCA_ISensor.h | 129 + .../GameLogic/SCA_JoystickManager.cpp | 84 + .../GameLogic/SCA_JoystickManager.h | 57 + .../GameLogic/SCA_JoystickSensor.cpp | 476 + .../gameengine/GameLogic/SCA_JoystickSensor.h | 127 + .../GameLogic/SCA_KeyboardManager.cpp | 90 + .../GameLogic/SCA_KeyboardManager.h | 66 + .../GameLogic/SCA_KeyboardSensor.cpp | 678 + .../gameengine/GameLogic/SCA_KeyboardSensor.h | 159 + .../gameengine/GameLogic/SCA_LogicManager.cpp | 487 + .../gameengine/GameLogic/SCA_LogicManager.h | 163 + .../gameengine/GameLogic/SCA_MouseManager.cpp | 120 + .../gameengine/GameLogic/SCA_MouseManager.h | 73 + .../gameengine/GameLogic/SCA_MouseSensor.cpp | 285 + source/gameengine/GameLogic/SCA_MouseSensor.h | 123 + .../gameengine/GameLogic/SCA_ORController.cpp | 139 + .../gameengine/GameLogic/SCA_ORController.h | 59 + .../GameLogic/SCA_PropertyActuator.cpp | 288 + .../GameLogic/SCA_PropertyActuator.h | 100 + .../GameLogic/SCA_PropertyEventManager.cpp | 69 + .../GameLogic/SCA_PropertyEventManager.h | 54 + .../GameLogic/SCA_PropertySensor.cpp | 433 + .../gameengine/GameLogic/SCA_PropertySensor.h | 111 + .../GameLogic/SCA_PythonController.cpp | 448 + .../GameLogic/SCA_PythonController.h | 92 + .../GameLogic/SCA_RandomActuator.cpp | 642 + .../gameengine/GameLogic/SCA_RandomActuator.h | 145 + .../GameLogic/SCA_RandomEventManager.cpp | 68 + .../GameLogic/SCA_RandomEventManager.h | 55 + .../GameLogic/SCA_RandomNumberGenerator.cpp | 129 + .../GameLogic/SCA_RandomNumberGenerator.h | 65 + .../gameengine/GameLogic/SCA_RandomSensor.cpp | 195 + .../gameengine/GameLogic/SCA_RandomSensor.h | 76 + .../GameLogic/SCA_TimeEventManager.cpp | 114 + .../GameLogic/SCA_TimeEventManager.h | 56 + source/gameengine/GameLogic/SConscript | 12 + source/gameengine/GamePlayer/CMakeLists.txt | 30 + source/gameengine/GamePlayer/Makefile | 60 + source/gameengine/GamePlayer/SConscript | 3 + .../GamePlayer/common/CMakeLists.txt | 82 + .../GamePlayer/common/GPC_Canvas.cpp | 493 + .../gameengine/GamePlayer/common/GPC_Canvas.h | 273 + .../GamePlayer/common/GPC_Engine.cpp | 342 + .../gameengine/GamePlayer/common/GPC_Engine.h | 129 + .../GamePlayer/common/GPC_KeyboardDevice.cpp | 127 + .../GamePlayer/common/GPC_KeyboardDevice.h | 91 + .../GamePlayer/common/GPC_MouseDevice.cpp | 216 + .../GamePlayer/common/GPC_MouseDevice.h | 107 + .../GamePlayer/common/GPC_PolygonMaterial.cpp | 421 + .../GamePlayer/common/GPC_PolygonMaterial.h | 92 + .../GamePlayer/common/GPC_RawImage.cpp | 138 + .../GamePlayer/common/GPC_RawImage.h | 122 + .../common/GPC_RawLoadDotBlendArray.cpp | 9313 ++++++++++ .../common/GPC_RawLoadDotBlendArray.h | 39 + .../GamePlayer/common/GPC_RawLogoArrays.cpp | 1463 ++ .../GamePlayer/common/GPC_RawLogoArrays.h | 43 + .../GamePlayer/common/GPC_RenderTools.cpp | 596 + .../GamePlayer/common/GPC_RenderTools.h | 178 + .../GamePlayer/common/GPC_System.cpp | 93 + .../gameengine/GamePlayer/common/GPC_System.h | 64 + source/gameengine/GamePlayer/common/Makefile | 89 + .../gameengine/GamePlayer/common/SConscript | 72 + .../gameengine/GamePlayer/common/bmfont.cpp | 305 + .../gameengine/GamePlayer/common/load.blend | Bin 0 -> 60988 bytes .../GamePlayer/common/logo_blender.raw | Bin 0 -> 14720 bytes .../GamePlayer/common/logo_blender3d.raw | Bin 0 -> 5984 bytes .../gameengine/GamePlayer/common/logo_nan.raw | Bin 0 -> 3968 bytes .../GamePlayer/common/unix/GPU_Canvas.cpp | 75 + .../GamePlayer/common/unix/GPU_Canvas.h | 61 + .../GamePlayer/common/unix/GPU_Engine.cpp | 309 + .../GamePlayer/common/unix/GPU_Engine.h | 64 + .../common/unix/GPU_KeyboardDevice.cpp | 136 + .../common/unix/GPU_KeyboardDevice.h | 64 + .../common/unix/GPU_PolygonMaterial.h | 56 + .../GamePlayer/common/unix/GPU_System.cpp | 58 + .../GamePlayer/common/unix/GPU_System.h | 49 + .../GamePlayer/common/unix/Makefile | 77 + .../GamePlayer/common/windows/GPW_Canvas.cpp | 178 + .../GamePlayer/common/windows/GPW_Canvas.h | 118 + .../GamePlayer/common/windows/GPW_Engine.cpp | 123 + .../GamePlayer/common/windows/GPW_Engine.h | 48 + .../common/windows/GPW_KeyboardDevice.cpp | 283 + .../common/windows/GPW_KeyboardDevice.h | 69 + .../GamePlayer/common/windows/GPW_System.cpp | 95 + .../GamePlayer/common/windows/GPW_System.h | 61 + .../GamePlayer/common/windows/Makefile | 66 + .../GamePlayer/ghost/CMakeLists.txt | 75 + .../GamePlayer/ghost/GPG_Application.cpp | 859 + .../GamePlayer/ghost/GPG_Application.h | 149 + .../GamePlayer/ghost/GPG_Canvas.cpp | 111 + .../gameengine/GamePlayer/ghost/GPG_Canvas.h | 65 + .../GamePlayer/ghost/GPG_KeyboardDevice.cpp | 158 + .../GamePlayer/ghost/GPG_KeyboardDevice.h | 58 + .../GamePlayer/ghost/GPG_System.cpp | 57 + .../gameengine/GamePlayer/ghost/GPG_System.h | 56 + .../gameengine/GamePlayer/ghost/GPG_ghost.cpp | 768 + source/gameengine/GamePlayer/ghost/Makefile | 83 + source/gameengine/GamePlayer/ghost/SConscript | 49 + source/gameengine/Ketsji/BL_Material.cpp | 152 + source/gameengine/Ketsji/BL_Material.h | 177 + source/gameengine/Ketsji/BL_Shader.cpp | 1470 ++ source/gameengine/Ketsji/BL_Shader.h | 234 + source/gameengine/Ketsji/BL_Texture.cpp | 723 + source/gameengine/Ketsji/BL_Texture.h | 64 + source/gameengine/Ketsji/CMakeLists.txt | 70 + .../Ketsji/KXNetwork/CMakeLists.txt | 44 + .../KXNetwork/KX_NetworkEventManager.cpp | 96 + .../Ketsji/KXNetwork/KX_NetworkEventManager.h | 60 + .../KXNetwork/KX_NetworkMessageActuator.cpp | 212 + .../KXNetwork/KX_NetworkMessageActuator.h | 77 + .../KXNetwork/KX_NetworkMessageSensor.cpp | 296 + .../KXNetwork/KX_NetworkMessageSensor.h | 89 + .../KXNetwork/KX_NetworkObjectActuator.cpp | 35 + .../KXNetwork/KX_NetworkObjectActuator.h | 32 + .../KXNetwork/KX_NetworkObjectSensor.cpp | 36 + .../Ketsji/KXNetwork/KX_NetworkObjectSensor.h | 32 + source/gameengine/Ketsji/KXNetwork/Makefile | 49 + source/gameengine/Ketsji/KXNetwork/SConscript | 12 + .../gameengine/Ketsji/KX_BlenderMaterial.cpp | 771 + source/gameengine/Ketsji/KX_BlenderMaterial.h | 118 + .../Ketsji/KX_BulletPhysicsController.cpp | 247 + .../Ketsji/KX_BulletPhysicsController.h | 70 + source/gameengine/Ketsji/KX_CDActuator.cpp | 256 + source/gameengine/Ketsji/KX_CDActuator.h | 97 + source/gameengine/Ketsji/KX_Camera.cpp | 761 + source/gameengine/Ketsji/KX_Camera.h | 261 + .../gameengine/Ketsji/KX_CameraActuator.cpp | 526 + source/gameengine/Ketsji/KX_CameraActuator.h | 140 + .../Ketsji/KX_CameraIpoSGController.cpp | 129 + .../Ketsji/KX_CameraIpoSGController.h | 93 + .../gameengine/Ketsji/KX_ClientObjectInfo.h | 83 + .../Ketsji/KX_ConstraintActuator.cpp | 377 + .../gameengine/Ketsji/KX_ConstraintActuator.h | 110 + .../Ketsji/KX_ConstraintWrapper.cpp | 137 + .../gameengine/Ketsji/KX_ConstraintWrapper.h | 58 + .../Ketsji/KX_ConvertPhysicsObject.h | 148 + .../Ketsji/KX_ConvertPhysicsObjects.cpp | 1205 ++ source/gameengine/Ketsji/KX_EmptyObject.cpp | 41 + source/gameengine/Ketsji/KX_EmptyObject.h | 47 + source/gameengine/Ketsji/KX_GameActuator.cpp | 221 + source/gameengine/Ketsji/KX_GameActuator.h | 88 + source/gameengine/Ketsji/KX_GameObject.cpp | 1174 ++ source/gameengine/Ketsji/KX_GameObject.h | 630 + source/gameengine/Ketsji/KX_IInterpolator.h | 47 + source/gameengine/Ketsji/KX_IPOTransform.h | 89 + .../gameengine/Ketsji/KX_IPO_SGController.cpp | 197 + .../gameengine/Ketsji/KX_IPO_SGController.h | 107 + .../Ketsji/KX_IPhysicsController.cpp | 53 + .../gameengine/Ketsji/KX_IPhysicsController.h | 103 + .../Ketsji/KX_IScalarInterpolator.h | 43 + source/gameengine/Ketsji/KX_ISceneConverter.h | 81 + source/gameengine/Ketsji/KX_ISystem.h | 56 + source/gameengine/Ketsji/KX_IpoActuator.cpp | 720 + source/gameengine/Ketsji/KX_IpoActuator.h | 158 + source/gameengine/Ketsji/KX_KetsjiEngine.cpp | 1469 ++ source/gameengine/Ketsji/KX_KetsjiEngine.h | 344 + source/gameengine/Ketsji/KX_Light.cpp | 263 + source/gameengine/Ketsji/KX_Light.h | 57 + .../Ketsji/KX_LightIpoSGController.cpp | 125 + .../Ketsji/KX_LightIpoSGController.h | 101 + .../Ketsji/KX_MaterialIpoController.cpp | 98 + .../Ketsji/KX_MaterialIpoController.h | 54 + source/gameengine/Ketsji/KX_MeshProxy.cpp | 233 + source/gameengine/Ketsji/KX_MeshProxy.h | 71 + source/gameengine/Ketsji/KX_MotionState.cpp | 97 + source/gameengine/Ketsji/KX_MotionState.h | 55 + .../gameengine/Ketsji/KX_MouseFocusSensor.cpp | 448 + .../gameengine/Ketsji/KX_MouseFocusSensor.h | 162 + source/gameengine/Ketsji/KX_NearSensor.cpp | 283 + source/gameengine/Ketsji/KX_NearSensor.h | 87 + .../Ketsji/KX_ObColorIpoSGController.cpp | 116 + .../Ketsji/KX_ObColorIpoSGController.h | 76 + .../gameengine/Ketsji/KX_ObjectActuator.cpp | 398 + source/gameengine/Ketsji/KX_ObjectActuator.h | 141 + .../Ketsji/KX_OdePhysicsController.cpp | 251 + .../Ketsji/KX_OdePhysicsController.h | 102 + .../Ketsji/KX_OrientationInterpolator.cpp | 58 + .../Ketsji/KX_OrientationInterpolator.h | 59 + .../gameengine/Ketsji/KX_PhysicsEngineEnums.h | 47 + .../Ketsji/KX_PhysicsObjectWrapper.cpp | 167 + .../Ketsji/KX_PhysicsObjectWrapper.h | 59 + .../Ketsji/KX_PhysicsPropertiesobsolete.h | 61 + .../gameengine/Ketsji/KX_PolygonMaterial.cpp | 425 + source/gameengine/Ketsji/KX_PolygonMaterial.h | 127 + .../Ketsji/KX_PositionInterpolator.cpp | 44 + .../Ketsji/KX_PositionInterpolator.h | 59 + .../Ketsji/KX_PyConstraintBinding.cpp | 553 + .../Ketsji/KX_PyConstraintBinding.h | 44 + source/gameengine/Ketsji/KX_PyMath.cpp | 114 + source/gameengine/Ketsji/KX_PyMath.h | 164 + source/gameengine/Ketsji/KX_PythonInit.cpp | 1157 ++ source/gameengine/Ketsji/KX_PythonInit.h | 61 + source/gameengine/Ketsji/KX_RadarSensor.cpp | 259 + source/gameengine/Ketsji/KX_RadarSensor.h | 96 + source/gameengine/Ketsji/KX_RayCast.cpp | 101 + source/gameengine/Ketsji/KX_RayCast.h | 107 + .../gameengine/Ketsji/KX_RayEventManager.cpp | 60 + source/gameengine/Ketsji/KX_RayEventManager.h | 55 + source/gameengine/Ketsji/KX_RaySensor.cpp | 392 + source/gameengine/Ketsji/KX_RaySensor.h | 85 + .../Ketsji/KX_SCA_AddObjectActuator.cpp | 361 + .../Ketsji/KX_SCA_AddObjectActuator.h | 130 + .../Ketsji/KX_SCA_EndObjectActuator.cpp | 139 + .../Ketsji/KX_SCA_EndObjectActuator.h | 78 + .../Ketsji/KX_SCA_ReplaceMeshActuator.cpp | 209 + .../Ketsji/KX_SCA_ReplaceMeshActuator.h | 89 + .../KX_SG_BoneParentNodeRelationship.cpp | 154 + .../Ketsji/KX_SG_BoneParentNodeRelationship.h | 109 + .../Ketsji/KX_SG_NodeRelationships.cpp | 339 + .../Ketsji/KX_SG_NodeRelationships.h | 204 + .../Ketsji/KX_ScalarInterpolator.cpp | 41 + .../gameengine/Ketsji/KX_ScalarInterpolator.h | 64 + .../Ketsji/KX_ScalingInterpolator.cpp | 44 + .../Ketsji/KX_ScalingInterpolator.h | 59 + source/gameengine/Ketsji/KX_Scene.cpp | 1350 ++ source/gameengine/Ketsji/KX_Scene.h | 557 + source/gameengine/Ketsji/KX_SceneActuator.cpp | 359 + source/gameengine/Ketsji/KX_SceneActuator.h | 116 + source/gameengine/Ketsji/KX_SoundActuator.cpp | 497 + source/gameengine/Ketsji/KX_SoundActuator.h | 109 + .../Ketsji/KX_SumoPhysicsController.cpp | 229 + .../Ketsji/KX_SumoPhysicsController.h | 112 + .../Ketsji/KX_TimeCategoryLogger.cpp | 145 + .../gameengine/Ketsji/KX_TimeCategoryLogger.h | 134 + source/gameengine/Ketsji/KX_TimeLogger.cpp | 121 + source/gameengine/Ketsji/KX_TimeLogger.h | 107 + .../Ketsji/KX_TouchEventManager.cpp | 154 + .../gameengine/Ketsji/KX_TouchEventManager.h | 80 + source/gameengine/Ketsji/KX_TouchSensor.cpp | 397 + source/gameengine/Ketsji/KX_TouchSensor.h | 125 + .../gameengine/Ketsji/KX_TrackToActuator.cpp | 532 + source/gameengine/Ketsji/KX_TrackToActuator.h | 93 + .../gameengine/Ketsji/KX_VehicleWrapper.cpp | 367 + source/gameengine/Ketsji/KX_VehicleWrapper.h | 58 + source/gameengine/Ketsji/KX_VertexProxy.cpp | 440 + source/gameengine/Ketsji/KX_VertexProxy.h | 79 + .../Ketsji/KX_VisibilityActuator.cpp | 162 + .../gameengine/Ketsji/KX_VisibilityActuator.h | 78 + source/gameengine/Ketsji/KX_WorldInfo.cpp | 41 + source/gameengine/Ketsji/KX_WorldInfo.h | 68 + .../Ketsji/KX_WorldIpoController.cpp | 120 + .../gameengine/Ketsji/KX_WorldIpoController.h | 99 + source/gameengine/Ketsji/Makefile | 74 + source/gameengine/Ketsji/SConscript | 34 + source/gameengine/Makefile | 47 + source/gameengine/Network/CMakeLists.txt | 40 + .../Network/LoopBackNetwork/CMakeLists.txt | 40 + .../Network/LoopBackNetwork/Makefile | 44 + .../NG_LoopBackNetworkDeviceInterface.cpp | 119 + .../NG_LoopBackNetworkDeviceInterface.h | 69 + .../Network/LoopBackNetwork/SConscript | 8 + source/gameengine/Network/Makefile | 51 + .../Network/NG_NetworkDeviceInterface.h | 85 + .../gameengine/Network/NG_NetworkMessage.cpp | 59 + source/gameengine/Network/NG_NetworkMessage.h | 131 + .../gameengine/Network/NG_NetworkObject.cpp | 50 + source/gameengine/Network/NG_NetworkObject.h | 48 + source/gameengine/Network/NG_NetworkScene.cpp | 275 + source/gameengine/Network/NG_NetworkScene.h | 104 + source/gameengine/Network/SConscript | 8 + .../Network/TerraplayNetwork/Makefile | 45 + .../NG_TerraplayNetworkDeviceInterface.cpp | 196 + .../NG_TerraplayNetworkDeviceInterface.h | 69 + source/gameengine/Physics/BlOde/Makefile | 51 + .../Physics/BlOde/OdePhysicsController.cpp | 622 + .../Physics/BlOde/OdePhysicsController.h | 157 + .../Physics/BlOde/OdePhysicsEnvironment.cpp | 278 + .../Physics/BlOde/OdePhysicsEnvironment.h | 93 + source/gameengine/Physics/BlOde/SConscript | 15 + .../gameengine/Physics/Bullet/CMakeLists.txt | 39 + .../Physics/Bullet/CcdPhysicsController.cpp | 636 + .../Physics/Bullet/CcdPhysicsController.h | 248 + .../Physics/Bullet/CcdPhysicsEnvironment.cpp | 1307 ++ .../Physics/Bullet/CcdPhysicsEnvironment.h | 242 + source/gameengine/Physics/Bullet/Makefile | 44 + source/gameengine/Physics/Bullet/SConscript | 15 + .../gameengine/Physics/Dummy/CMakeLists.txt | 38 + .../Physics/Dummy/DummyPhysicsEnvironment.cpp | 121 + .../Physics/Dummy/DummyPhysicsEnvironment.h | 96 + source/gameengine/Physics/Dummy/Makefile | 48 + source/gameengine/Physics/Dummy/SConscript | 8 + source/gameengine/Physics/Makefile | 41 + source/gameengine/Physics/Sumo/CMakeLists.txt | 49 + .../gameengine/Physics/Sumo/Fuzzics/Makefile | 37 + .../Sumo/Fuzzics/include/SM_Callback.h | 10 + .../Fuzzics/include/SM_ClientObjectInfo.h | 16 + .../Physics/Sumo/Fuzzics/include/SM_Debug.h | 26 + .../Sumo/Fuzzics/include/SM_FhObject.h | 59 + .../Sumo/Fuzzics/include/SM_MotionState.h | 80 + .../Physics/Sumo/Fuzzics/include/SM_Object.h | 396 + .../Physics/Sumo/Fuzzics/include/SM_Props.h | 61 + .../Physics/Sumo/Fuzzics/include/SM_Scene.h | 175 + .../Physics/Sumo/Fuzzics/sample/Makefile | 25 + .../Physics/Sumo/Fuzzics/sample/particle.cpp | 709 + .../Physics/Sumo/Fuzzics/sample/particle0.cpp | 695 + .../Physics/Sumo/Fuzzics/src/Makefile | 14 + .../Physics/Sumo/Fuzzics/src/SM_FhObject.cpp | 183 + .../Sumo/Fuzzics/src/SM_MotionState.cpp | 103 + .../Physics/Sumo/Fuzzics/src/SM_Object.cpp | 1301 ++ .../Physics/Sumo/Fuzzics/src/SM_Scene.cpp | 376 + source/gameengine/Physics/Sumo/Makefile | 53 + source/gameengine/Physics/Sumo/SConscript | 26 + .../Physics/Sumo/SumoPHYCallbackBridge.cpp | 66 + .../Physics/Sumo/SumoPHYCallbackBridge.h | 28 + .../Physics/Sumo/SumoPhysicsController.cpp | 493 + .../Physics/Sumo/SumoPhysicsController.h | 188 + .../Physics/Sumo/SumoPhysicsEnvironment.cpp | 257 + .../Physics/Sumo/SumoPhysicsEnvironment.h | 108 + source/gameengine/Physics/Sumo/convert.txt | 35 + .../Physics/Sumo/include/interpolator.h | 27 + .../gameengine/Physics/common/CMakeLists.txt | 39 + source/gameengine/Physics/common/Makefile | 61 + .../Physics/common/PHY_DynamicTypes.h | 93 + .../Physics/common/PHY_IMotionState.cpp | 41 + .../Physics/common/PHY_IMotionState.h | 57 + .../Physics/common/PHY_IPhysicsController.cpp | 42 + .../Physics/common/PHY_IPhysicsController.h | 103 + .../common/PHY_IPhysicsEnvironment.cpp | 49 + .../Physics/common/PHY_IPhysicsEnvironment.h | 117 + .../Physics/common/PHY_IVehicle.cpp | 7 + .../gameengine/Physics/common/PHY_IVehicle.h | 57 + source/gameengine/Physics/common/PHY_Pro.h | 61 + source/gameengine/Physics/common/SConscript | 8 + source/gameengine/PyDoc/BL_ActionActuator.py | 153 + source/gameengine/PyDoc/GameKeys.py | 166 + source/gameengine/PyDoc/GameLogic.py | 223 + source/gameengine/PyDoc/KX_CDActuator.py | 32 + source/gameengine/PyDoc/KX_Camera.py | 187 + source/gameengine/PyDoc/KX_CameraActuator.py | 86 + .../gameengine/PyDoc/KX_ConstraintActuator.py | 72 + source/gameengine/PyDoc/KX_GameActuator.py | 22 + source/gameengine/PyDoc/KX_GameObject.py | 158 + source/gameengine/PyDoc/KX_IpoActuator.py | 92 + source/gameengine/PyDoc/KX_Light.py | 45 + source/gameengine/PyDoc/KX_MeshProxy.py | 110 + .../gameengine/PyDoc/KX_MouseFocusSensor.py | 26 + source/gameengine/PyDoc/KX_NearSensor.py | 9 + .../PyDoc/KX_NetworkMessageActuator.py | 36 + .../PyDoc/KX_NetworkMessageSensor.py | 43 + source/gameengine/PyDoc/KX_ObjectActuator.py | 154 + source/gameengine/PyDoc/KX_PolygonMaterial.py | 281 + source/gameengine/PyDoc/KX_RadarSensor.py | 31 + source/gameengine/PyDoc/KX_RaySensor.py | 33 + .../PyDoc/KX_SCA_AddObjectActuator.py | 74 + .../PyDoc/KX_SCA_EndObjectActuator.py | 11 + .../PyDoc/KX_SCA_ReplaceMeshActuator.py | 73 + source/gameengine/PyDoc/KX_Scene.py | 70 + source/gameengine/PyDoc/KX_SceneActuator.py | 55 + source/gameengine/PyDoc/KX_SoundActuator.py | 145 + source/gameengine/PyDoc/KX_TouchSensor.py | 50 + source/gameengine/PyDoc/KX_TrackToActuator.py | 57 + source/gameengine/PyDoc/KX_VertexProxy.py | 122 + .../gameengine/PyDoc/KX_VisibilityActuator.py | 17 + source/gameengine/PyDoc/Makefile | 13 + source/gameengine/PyDoc/Rasterizer.py | 147 + source/gameengine/PyDoc/SCA_ANDController.py | 11 + source/gameengine/PyDoc/SCA_AlwaysSensor.py | 9 + source/gameengine/PyDoc/SCA_IActuator.py | 9 + source/gameengine/PyDoc/SCA_IController.py | 9 + source/gameengine/PyDoc/SCA_ILogicBrick.py | 32 + source/gameengine/PyDoc/SCA_ISensor.py | 62 + source/gameengine/PyDoc/SCA_KeyboardSensor.py | 58 + source/gameengine/PyDoc/SCA_MouseSensor.py | 23 + source/gameengine/PyDoc/SCA_ORController.py | 11 + .../gameengine/PyDoc/SCA_PropertyActuator.py | 38 + source/gameengine/PyDoc/SCA_PropertySensor.py | 57 + .../gameengine/PyDoc/SCA_PythonController.py | 49 + source/gameengine/PyDoc/SCA_RandomActuator.py | 143 + source/gameengine/PyDoc/SCA_RandomSensor.py | 28 + source/gameengine/PyDoc/WhatsNew.py | 34 + source/gameengine/Rasterizer/CMakeLists.txt | 40 + source/gameengine/Rasterizer/Makefile | 53 + .../Rasterizer/RAS_BucketManager.cpp | 197 + .../gameengine/Rasterizer/RAS_BucketManager.h | 73 + source/gameengine/Rasterizer/RAS_CameraData.h | 63 + source/gameengine/Rasterizer/RAS_Deformer.h | 56 + .../Rasterizer/RAS_FramingManager.cpp | 234 + .../Rasterizer/RAS_FramingManager.h | 256 + source/gameengine/Rasterizer/RAS_ICanvas.h | 174 + .../Rasterizer/RAS_IPolygonMaterial.cpp | 160 + .../Rasterizer/RAS_IPolygonMaterial.h | 166 + .../gameengine/Rasterizer/RAS_IRasterizer.h | 411 + .../Rasterizer/RAS_IRenderTools.cpp | 78 + .../gameengine/Rasterizer/RAS_IRenderTools.h | 202 + .../gameengine/Rasterizer/RAS_LightObject.h | 67 + .../Rasterizer/RAS_MaterialBucket.cpp | 332 + .../Rasterizer/RAS_MaterialBucket.h | 169 + .../gameengine/Rasterizer/RAS_MeshObject.cpp | 699 + source/gameengine/Rasterizer/RAS_MeshObject.h | 267 + .../gameengine/Rasterizer/RAS_ObjectColor.h | 42 + .../RAS_OpenGLRasterizer/ARB_multitexture.h | 150 + .../RAS_OpenGLRasterizer/CMakeLists.txt | 40 + .../EXT_separate_specular_color.h | 12 + .../Rasterizer/RAS_OpenGLRasterizer/Makefile | 49 + .../RAS_GLExtensionManager.cpp | 691 + .../RAS_GLExtensionManager.h | 537 + .../RAS_ListRasterizer.cpp | 210 + .../RAS_OpenGLRasterizer/RAS_ListRasterizer.h | 72 + .../RAS_OpenGLRasterizer.cpp | 1995 +++ .../RAS_OpenGLRasterizer.h | 318 + .../RAS_VAOpenGLRasterizer.cpp | 352 + .../RAS_VAOpenGLRasterizer.h | 78 + .../RAS_OpenGLRasterizer/SConscript | 9 + .../Rasterizer/RAS_OpenGLRasterizer/glext.h | 6495 +++++++ .../RAS_OpenGLRasterizer/mkglext.py | 630 + source/gameengine/Rasterizer/RAS_Polygon.cpp | 145 + source/gameengine/Rasterizer/RAS_Polygon.h | 93 + source/gameengine/Rasterizer/RAS_Rect.h | 98 + source/gameengine/Rasterizer/RAS_TexMatrix.h | 43 + source/gameengine/Rasterizer/RAS_TexVert.cpp | 180 + source/gameengine/Rasterizer/RAS_TexVert.h | 135 + .../gameengine/Rasterizer/RAS_texmatrix.cpp | 134 + source/gameengine/Rasterizer/SConscript | 13 + source/gameengine/SConscript | 27 + source/gameengine/SceneGraph/CMakeLists.txt | 38 + source/gameengine/SceneGraph/Makefile | 41 + source/gameengine/SceneGraph/SConscript | 9 + source/gameengine/SceneGraph/SG_BBox.cpp | 253 + source/gameengine/SceneGraph/SG_BBox.h | 134 + .../gameengine/SceneGraph/SG_Controller.cpp | 53 + source/gameengine/SceneGraph/SG_Controller.h | 120 + source/gameengine/SceneGraph/SG_IObject.cpp | 167 + source/gameengine/SceneGraph/SG_IObject.h | 235 + source/gameengine/SceneGraph/SG_Node.cpp | 239 + source/gameengine/SceneGraph/SG_Node.h | 211 + .../gameengine/SceneGraph/SG_ParentRelation.h | 117 + source/gameengine/SceneGraph/SG_Spatial.cpp | 330 + source/gameengine/SceneGraph/SG_Spatial.h | 229 + source/gameengine/SceneGraph/SG_Tree.cpp | 414 + source/gameengine/SceneGraph/SG_Tree.h | 156 + source/icons/Makefile | 39 + source/icons/SConscript | 6 + source/icons/winblender.ico | Bin 0 -> 25214 bytes source/icons/winblender.rc | 2 + source/icons/winblender.rcscons | 2 + source/icons/winblenderfile.ico | Bin 0 -> 25214 bytes source/icons/wincreator.ico | Bin 0 -> 4710 bytes source/icons/wincreator.rc | 2 + source/icons/winlockedfile.ico | Bin 0 -> 4710 bytes source/icons/winplayer.ico | Bin 0 -> 4710 bytes source/icons/winplayer.rc | 1 + source/icons/winpublisher.ico | Bin 0 -> 4710 bytes source/icons/winpublisher.rc | 3 + source/kernel/CMakeLists.txt | 41 + source/kernel/Makefile | 40 + source/kernel/SConscript | 10 + source/kernel/gen_messaging/GEN_messaging.h | 61 + source/kernel/gen_messaging/Makefile | 37 + source/kernel/gen_messaging/intern/Makefile | 43 + .../kernel/gen_messaging/intern/messaging.c | 48 + source/kernel/gen_system/GEN_DataCache.h | 79 + source/kernel/gen_system/GEN_HashedPtr.cpp | 61 + source/kernel/gen_system/GEN_HashedPtr.h | 48 + source/kernel/gen_system/GEN_Map.h | 150 + source/kernel/gen_system/GEN_Matrix4x4.cpp | 209 + source/kernel/gen_system/GEN_Matrix4x4.h | 79 + source/kernel/gen_system/GEN_SmartPtr.h | 236 + source/kernel/gen_system/Makefile | 43 + .../kernel/gen_system/SYS_SingletonSystem.cpp | 103 + .../kernel/gen_system/SYS_SingletonSystem.h | 66 + source/kernel/gen_system/SYS_System.cpp | 81 + source/kernel/gen_system/SYS_System.h | 71 + source/nan_compile.mk | 391 + source/nan_definitions.mk | 603 + source/nan_link.mk | 164 + source/nan_subdirs.mk | 79 + source/nan_warn.mk | 169 + tools/Blender.py | 458 + tools/__init__.py | 0 tools/bcolors.py | 16 + tools/btools.py | 488 + tools/crossmingw.py | 189 + tools/mstoolkit.py | 353 + 3166 files changed, 1082581 insertions(+) create mode 100644 CMake/macros.cmake create mode 100644 CMakeLists.txt create mode 100644 COPYING create mode 100644 Makefile create mode 100644 README create mode 100644 SConstruct create mode 100644 bin/.blender/.Blanguages create mode 100644 bin/.blender/.bfont.ttf create mode 100644 blenderplayer/CMakeLists.txt create mode 100644 config/darwin-config.py create mode 100644 config/linux2-config.py create mode 100644 config/linuxcross-config.py create mode 100644 config/openbsd3-config.py create mode 100644 config/sunos5-config.py create mode 100644 config/win32-mingw-config.py create mode 100644 config/win32-vc-config.py create mode 100644 doc/BL-license.txt create mode 100644 doc/Doxyfile create mode 100644 doc/GPL-license.txt create mode 100644 doc/README.windows-gcc create mode 100644 doc/bf-members.txt create mode 100644 doc/blender-cmake.txt create mode 100644 doc/blender-guardedalloc.txt create mode 100644 doc/blender-scons-dev.txt create mode 100644 doc/blender-scons.txt create mode 100644 doc/doxygen.main create mode 100644 doc/interface_API.txt create mode 100644 extern/CMakeLists.txt create mode 100644 extern/Makefile create mode 100644 extern/SConscript create mode 100644 extern/bFTGL/CMakeLists.txt create mode 100644 extern/bFTGL/COPYING.txt create mode 100644 extern/bFTGL/README.txt create mode 100644 extern/bFTGL/SConscript create mode 100755 extern/bFTGL/cleanup create mode 100644 extern/bFTGL/include/FTBBox.h create mode 100644 extern/bFTGL/include/FTBitmapGlyph.h create mode 100644 extern/bFTGL/include/FTBufferGlyph.h create mode 100644 extern/bFTGL/include/FTCharToGlyphIndexMap.h create mode 100644 extern/bFTGL/include/FTCharmap.h create mode 100644 extern/bFTGL/include/FTContour.h create mode 100644 extern/bFTGL/include/FTExtrdGlyph.h create mode 100644 extern/bFTGL/include/FTFace.h create mode 100644 extern/bFTGL/include/FTFont.h create mode 100644 extern/bFTGL/include/FTGL.h create mode 100644 extern/bFTGL/include/FTGLBitmapFont.h create mode 100644 extern/bFTGL/include/FTGLBufferFont.h create mode 100644 extern/bFTGL/include/FTGLExtrdFont.h create mode 100644 extern/bFTGL/include/FTGLOutlineFont.h create mode 100644 extern/bFTGL/include/FTGLPixmapFont.h create mode 100644 extern/bFTGL/include/FTGLPolygonFont.h create mode 100644 extern/bFTGL/include/FTGLTextureFont.h create mode 100644 extern/bFTGL/include/FTGlyph.h create mode 100644 extern/bFTGL/include/FTGlyphContainer.h create mode 100644 extern/bFTGL/include/FTLibrary.h create mode 100644 extern/bFTGL/include/FTList.h create mode 100644 extern/bFTGL/include/FTOutlineGlyph.h create mode 100644 extern/bFTGL/include/FTPixmapGlyph.h create mode 100644 extern/bFTGL/include/FTPoint.h create mode 100644 extern/bFTGL/include/FTPolyGlyph.h create mode 100644 extern/bFTGL/include/FTSize.h create mode 100644 extern/bFTGL/include/FTTextureGlyph.h create mode 100644 extern/bFTGL/include/FTVector.h create mode 100644 extern/bFTGL/include/FTVectoriser.h create mode 100644 extern/bFTGL/license.txt create mode 100644 extern/bFTGL/make/msvc_7_0/ftgl_static_lib.vcproj create mode 100644 extern/bFTGL/src/FTBitmapGlyph.cpp create mode 100644 extern/bFTGL/src/FTBufferGlyph.cpp create mode 100644 extern/bFTGL/src/FTCharmap.cpp create mode 100644 extern/bFTGL/src/FTContour.cpp create mode 100644 extern/bFTGL/src/FTExtrdGlyph.cpp create mode 100644 extern/bFTGL/src/FTFace.cpp create mode 100644 extern/bFTGL/src/FTFont.cpp create mode 100644 extern/bFTGL/src/FTGLBitmapFont.cpp create mode 100644 extern/bFTGL/src/FTGLBufferFont.cpp create mode 100644 extern/bFTGL/src/FTGLExtrdFont.cpp create mode 100644 extern/bFTGL/src/FTGLOutlineFont.cpp create mode 100644 extern/bFTGL/src/FTGLPixmapFont.cpp create mode 100644 extern/bFTGL/src/FTGLPolygonFont.cpp create mode 100644 extern/bFTGL/src/FTGLTextureFont.cpp create mode 100644 extern/bFTGL/src/FTGlyph.cpp create mode 100644 extern/bFTGL/src/FTGlyphContainer.cpp create mode 100644 extern/bFTGL/src/FTLibrary.cpp create mode 100644 extern/bFTGL/src/FTOutlineGlyph.cpp create mode 100644 extern/bFTGL/src/FTPixmapGlyph.cpp create mode 100644 extern/bFTGL/src/FTPoint.cpp create mode 100644 extern/bFTGL/src/FTPolyGlyph.cpp create mode 100644 extern/bFTGL/src/FTSize.cpp create mode 100644 extern/bFTGL/src/FTTextureGlyph.cpp create mode 100644 extern/bFTGL/src/FTVectoriser.cpp create mode 100644 extern/bFTGL/src/Makefile create mode 100644 extern/bFTGL/win32_vcpp/README_WIN32.txt create mode 100644 extern/bFTGL/win32_vcpp/ftgl.dsw create mode 100644 extern/bFTGL/win32_vcpp/ftgl_dll/ftgl_dll.dsp create mode 100644 extern/bFTGL/win32_vcpp/ftgl_static_lib/ftgl_static_lib.dsp create mode 100644 extern/bFTGL/win32_vcpp/unit_tests/unit_tests.dsp create mode 100644 extern/bullet2/CMakeLists.txt create mode 100644 extern/bullet2/Makefile create mode 100644 extern/bullet2/make/msvc_7_0/Bullet_vc7.vcproj create mode 100644 extern/bullet2/readme.txt create mode 100644 extern/bullet2/src/BulletCollision/BroadphaseCollision/btAxisSweep3.cpp create mode 100644 extern/bullet2/src/BulletCollision/BroadphaseCollision/btAxisSweep3.h create mode 100644 extern/bullet2/src/BulletCollision/BroadphaseCollision/btBroadphaseInterface.h create mode 100644 extern/bullet2/src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp create mode 100644 extern/bullet2/src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.h create mode 100644 extern/bullet2/src/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.cpp create mode 100644 extern/bullet2/src/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h create mode 100644 extern/bullet2/src/BulletCollision/BroadphaseCollision/btDispatcher.cpp create mode 100644 extern/bullet2/src/BulletCollision/BroadphaseCollision/btDispatcher.h create mode 100644 extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp create mode 100644 extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h create mode 100644 extern/bullet2/src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp create mode 100644 extern/bullet2/src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.h create mode 100644 extern/bullet2/src/BulletCollision/CMakeLists.txt create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/SphereTriangleDetector.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionCreateFunc.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btManifoldResult.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btManifoldResult.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btSimulationIslandManager.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btSimulationIslandManager.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btUnionFind.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionDispatch/btUnionFind.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btBoxShape.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btBoxShape.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btCapsuleShape.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btCapsuleShape.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionMargin.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionShape.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionShape.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btConcaveShape.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btConcaveShape.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btConeShape.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btConeShape.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btConvexHullShape.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btConvexHullShape.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btCylinderShape.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btCylinderShape.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btEmptyShape.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btEmptyShape.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btMinkowskiSumShape.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btMinkowskiSumShape.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btMultiSphereShape.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btOptimizedBvh.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btOptimizedBvh.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btSphereShape.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btSphereShape.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btStaticPlaneShape.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btStridingMeshInterface.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btStridingMeshInterface.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btTetrahedronShape.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btTetrahedronShape.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleBuffer.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleBuffer.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleCallback.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleCallback.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMesh.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMesh.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMeshShape.h create mode 100644 extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleShape.h create mode 100644 extern/bullet2/src/BulletCollision/Doxyfile create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.cpp create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btConvexCast.cpp create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btConvexCast.h create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.cpp create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpa.cpp create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpa.h create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.cpp create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPointCollector.h create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp create mode 100644 extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h create mode 100644 extern/bullet2/src/BulletDynamics/CMakeLists.txt create mode 100644 extern/bullet2/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp create mode 100644 extern/bullet2/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h create mode 100644 extern/bullet2/src/BulletDynamics/ConstraintSolver/btConstraintSolver.h create mode 100644 extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactConstraint.cpp create mode 100644 extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactConstraint.h create mode 100644 extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h create mode 100644 extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp create mode 100644 extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h create mode 100644 extern/bullet2/src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp create mode 100644 extern/bullet2/src/BulletDynamics/ConstraintSolver/btHingeConstraint.h create mode 100644 extern/bullet2/src/BulletDynamics/ConstraintSolver/btJacobianEntry.h create mode 100644 extern/bullet2/src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.cpp create mode 100644 extern/bullet2/src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h create mode 100644 extern/bullet2/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp create mode 100644 extern/bullet2/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h create mode 100644 extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.cpp create mode 100644 extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.h create mode 100644 extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolverBody.h create mode 100644 extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolverConstraint.h create mode 100644 extern/bullet2/src/BulletDynamics/ConstraintSolver/btTypedConstraint.cpp create mode 100644 extern/bullet2/src/BulletDynamics/ConstraintSolver/btTypedConstraint.h create mode 100644 extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp create mode 100644 extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h create mode 100644 extern/bullet2/src/BulletDynamics/Dynamics/btDynamicsWorld.h create mode 100644 extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.cpp create mode 100644 extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.h create mode 100644 extern/bullet2/src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.cpp create mode 100644 extern/bullet2/src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.h create mode 100644 extern/bullet2/src/BulletDynamics/Vehicle/btRaycastVehicle.cpp create mode 100644 extern/bullet2/src/BulletDynamics/Vehicle/btRaycastVehicle.h create mode 100644 extern/bullet2/src/BulletDynamics/Vehicle/btVehicleRaycaster.h create mode 100644 extern/bullet2/src/BulletDynamics/Vehicle/btWheelInfo.cpp create mode 100644 extern/bullet2/src/BulletDynamics/Vehicle/btWheelInfo.h create mode 100644 extern/bullet2/src/CMakeLists.txt create mode 100644 extern/bullet2/src/LinearMath/CMakeLists.txt create mode 100644 extern/bullet2/src/LinearMath/btAabbUtil2.h create mode 100644 extern/bullet2/src/LinearMath/btAlignedAllocator.cpp create mode 100644 extern/bullet2/src/LinearMath/btAlignedAllocator.h create mode 100644 extern/bullet2/src/LinearMath/btAlignedObjectArray.h create mode 100644 extern/bullet2/src/LinearMath/btDefaultMotionState.h create mode 100644 extern/bullet2/src/LinearMath/btGeometryUtil.cpp create mode 100644 extern/bullet2/src/LinearMath/btGeometryUtil.h create mode 100644 extern/bullet2/src/LinearMath/btIDebugDraw.h create mode 100644 extern/bullet2/src/LinearMath/btList.h create mode 100644 extern/bullet2/src/LinearMath/btMatrix3x3.h create mode 100644 extern/bullet2/src/LinearMath/btMinMax.h create mode 100644 extern/bullet2/src/LinearMath/btMotionState.h create mode 100644 extern/bullet2/src/LinearMath/btPoint3.h create mode 100644 extern/bullet2/src/LinearMath/btQuadWord.h create mode 100644 extern/bullet2/src/LinearMath/btQuaternion.h create mode 100644 extern/bullet2/src/LinearMath/btQuickprof.cpp create mode 100644 extern/bullet2/src/LinearMath/btQuickprof.h create mode 100644 extern/bullet2/src/LinearMath/btRandom.h create mode 100644 extern/bullet2/src/LinearMath/btScalar.h create mode 100644 extern/bullet2/src/LinearMath/btSimdMinMax.h create mode 100644 extern/bullet2/src/LinearMath/btStackAlloc.h create mode 100644 extern/bullet2/src/LinearMath/btTransform.h create mode 100644 extern/bullet2/src/LinearMath/btTransformUtil.h create mode 100644 extern/bullet2/src/LinearMath/btVector3.h create mode 100644 extern/bullet2/src/Makefile create mode 100644 extern/bullet2/src/SConscript create mode 100644 extern/bullet2/src/btBulletCollisionCommon.h create mode 100644 extern/bullet2/src/btBulletDynamicsCommon.h create mode 100644 extern/make/msvc_7_0/build_install_all.vcproj create mode 100644 extern/make/msvc_7_0/extern.sln create mode 100644 extern/ode/Makefile create mode 100644 extern/ode/dist/INSTALL create mode 100644 extern/ode/dist/LICENSE-BSD.TXT create mode 100644 extern/ode/dist/LICENSE.TXT create mode 100644 extern/ode/dist/Makefile create mode 100644 extern/ode/dist/Makefile.deps create mode 100644 extern/ode/dist/README create mode 100644 extern/ode/dist/README_BLENDER create mode 100644 extern/ode/dist/config/README create mode 100644 extern/ode/dist/config/makefile.cygwin create mode 100644 extern/ode/dist/config/makefile.mingw create mode 100644 extern/ode/dist/config/makefile.msvc create mode 100644 extern/ode/dist/config/makefile.msvc-dll create mode 100644 extern/ode/dist/config/makefile.osx create mode 100644 extern/ode/dist/config/makefile.unix-gcc create mode 100644 extern/ode/dist/config/makefile.unix-generic create mode 100644 extern/ode/dist/config/msvcdefs.def create mode 100644 extern/ode/dist/config/user-settings create mode 100644 extern/ode/dist/config/user-settings.example create mode 100644 extern/ode/dist/configurator.c create mode 100644 extern/ode/dist/include/ode/README create mode 100644 extern/ode/dist/include/ode/common.h create mode 100644 extern/ode/dist/include/ode/contact.h create mode 100644 extern/ode/dist/include/ode/error.h create mode 100644 extern/ode/dist/include/ode/geom.h create mode 100644 extern/ode/dist/include/ode/mass.h create mode 100644 extern/ode/dist/include/ode/matrix.h create mode 100644 extern/ode/dist/include/ode/memory.h create mode 100644 extern/ode/dist/include/ode/misc.h create mode 100644 extern/ode/dist/include/ode/objects.h create mode 100644 extern/ode/dist/include/ode/ode.h create mode 100644 extern/ode/dist/include/ode/odecpp.h create mode 100644 extern/ode/dist/include/ode/odecpp_old.h create mode 100644 extern/ode/dist/include/ode/odemath.h create mode 100644 extern/ode/dist/include/ode/rotation.h create mode 100644 extern/ode/dist/include/ode/space.h create mode 100644 extern/ode/dist/include/ode/timer.h create mode 100644 extern/ode/dist/ode/README create mode 100644 extern/ode/dist/ode/fbuild/BuildDot create mode 100644 extern/ode/dist/ode/fbuild/BuildLDLT create mode 100644 extern/ode/dist/ode/fbuild/BuildMultidot create mode 100644 extern/ode/dist/ode/fbuild/BuildUtil create mode 100644 extern/ode/dist/ode/fbuild/Dependencies create mode 100644 extern/ode/dist/ode/fbuild/Makefile create mode 100644 extern/ode/dist/ode/fbuild/OptimizeDot create mode 100644 extern/ode/dist/ode/fbuild/OptimizeLDLT create mode 100644 extern/ode/dist/ode/fbuild/OptimizeLSolve create mode 100644 extern/ode/dist/ode/fbuild/OptimizeLTSolve create mode 100644 extern/ode/dist/ode/fbuild/OptimizeMultidot create mode 100644 extern/ode/dist/ode/fbuild/OptimizeUtil create mode 100644 extern/ode/dist/ode/fbuild/ParametersD.example create mode 100644 extern/ode/dist/ode/fbuild/ParametersF.example create mode 100644 extern/ode/dist/ode/fbuild/ParametersM.example create mode 100644 extern/ode/dist/ode/fbuild/ParametersS.example create mode 100644 extern/ode/dist/ode/fbuild/ParametersT.example create mode 100644 extern/ode/dist/ode/fbuild/README create mode 100644 extern/ode/dist/ode/fbuild/ldlt.m create mode 100644 extern/ode/dist/ode/fbuild/test_dot.cpp create mode 100644 extern/ode/dist/ode/fbuild/test_ldlt.cpp create mode 100644 extern/ode/dist/ode/fbuild/test_multidot.cpp create mode 100644 extern/ode/dist/ode/src/array.cpp create mode 100644 extern/ode/dist/ode/src/array.h create mode 100644 extern/ode/dist/ode/src/error.cpp create mode 100644 extern/ode/dist/ode/src/fastdot.c create mode 100644 extern/ode/dist/ode/src/fastldlt.c create mode 100644 extern/ode/dist/ode/src/fastlsolve.c create mode 100644 extern/ode/dist/ode/src/fastltsolve.c create mode 100644 extern/ode/dist/ode/src/geom.cpp create mode 100644 extern/ode/dist/ode/src/geom_internal.h create mode 100644 extern/ode/dist/ode/src/joint.cpp create mode 100644 extern/ode/dist/ode/src/joint.h create mode 100644 extern/ode/dist/ode/src/lcp.cpp create mode 100644 extern/ode/dist/ode/src/lcp.h create mode 100644 extern/ode/dist/ode/src/mass.cpp create mode 100644 extern/ode/dist/ode/src/mat.cpp create mode 100644 extern/ode/dist/ode/src/mat.h create mode 100644 extern/ode/dist/ode/src/matrix.cpp create mode 100644 extern/ode/dist/ode/src/memory.cpp create mode 100644 extern/ode/dist/ode/src/misc.cpp create mode 100644 extern/ode/dist/ode/src/objects.h create mode 100644 extern/ode/dist/ode/src/obstack.cpp create mode 100644 extern/ode/dist/ode/src/obstack.h create mode 100644 extern/ode/dist/ode/src/ode.cpp create mode 100644 extern/ode/dist/ode/src/odemath.cpp create mode 100644 extern/ode/dist/ode/src/rotation.cpp create mode 100644 extern/ode/dist/ode/src/scrapbook.cpp create mode 100644 extern/ode/dist/ode/src/space.cpp create mode 100644 extern/ode/dist/ode/src/stack.cpp create mode 100644 extern/ode/dist/ode/src/stack.h create mode 100644 extern/ode/dist/ode/src/step.cpp create mode 100644 extern/ode/dist/ode/src/step.h create mode 100644 extern/ode/dist/ode/src/testing.cpp create mode 100644 extern/ode/dist/ode/src/testing.h create mode 100644 extern/ode/dist/ode/src/timer.cpp create mode 100755 extern/ode/dist/tools/build4 create mode 100755 extern/ode/dist/tools/build4.bat create mode 100755 extern/ode/dist/tools/make_distribution create mode 100755 extern/ode/dist/tools/process_deps create mode 100644 extern/ode/patchfile.FreeBSD create mode 100644 extern/qhull/CMakeLists.txt create mode 100644 extern/qhull/COPYING.txt create mode 100644 extern/qhull/README.txt create mode 100644 extern/qhull/REGISTER.txt create mode 100644 extern/qhull/SConscript create mode 100644 extern/qhull/VisualC6/qhull.dsw create mode 100644 extern/qhull/VisualC6/qhull/qhull.dsp create mode 100644 extern/qhull/include/qhull/geom.h create mode 100644 extern/qhull/include/qhull/io.h create mode 100644 extern/qhull/include/qhull/mem.h create mode 100644 extern/qhull/include/qhull/merge.h create mode 100644 extern/qhull/include/qhull/poly.h create mode 100644 extern/qhull/include/qhull/qhull.h create mode 100644 extern/qhull/include/qhull/qhull_a.h create mode 100644 extern/qhull/include/qhull/qset.h create mode 100644 extern/qhull/include/qhull/stat.h create mode 100644 extern/qhull/include/qhull/user.h create mode 100644 extern/qhull/make/msvc_7_0/qhull.vcproj create mode 100755 extern/qhull/src/Make-config.sh create mode 100644 extern/qhull/src/Makefile create mode 100644 extern/qhull/src/Makefile.txt create mode 100644 extern/qhull/src/geom.c create mode 100644 extern/qhull/src/geom.h create mode 100644 extern/qhull/src/geom2.c create mode 100644 extern/qhull/src/global.c create mode 100644 extern/qhull/src/io.c create mode 100644 extern/qhull/src/io.h create mode 100644 extern/qhull/src/mem.c create mode 100644 extern/qhull/src/mem.h create mode 100644 extern/qhull/src/merge.c create mode 100644 extern/qhull/src/merge.h create mode 100644 extern/qhull/src/poly.c create mode 100644 extern/qhull/src/poly.h create mode 100644 extern/qhull/src/poly2.c create mode 100644 extern/qhull/src/qconvex.c create mode 100644 extern/qhull/src/qdelaun.c create mode 100644 extern/qhull/src/qhalf.c create mode 100644 extern/qhull/src/qhull.c create mode 100644 extern/qhull/src/qhull.h create mode 100644 extern/qhull/src/qhull_a.h create mode 100644 extern/qhull/src/qhull_interface.cpp create mode 100644 extern/qhull/src/qset.c create mode 100644 extern/qhull/src/qset.h create mode 100644 extern/qhull/src/qvoronoi.c create mode 100644 extern/qhull/src/rbox.c create mode 100644 extern/qhull/src/stat.c create mode 100644 extern/qhull/src/stat.h create mode 100644 extern/qhull/src/unix.c create mode 100644 extern/qhull/src/user.c create mode 100644 extern/qhull/src/user.h create mode 100644 extern/qhull/src/user_eg.c create mode 100644 extern/qhull/src/user_eg2.c create mode 100644 extern/solid/CMakeLists.txt create mode 100644 extern/solid/LICENSE_GPL.txt create mode 100644 extern/solid/LICENSE_QPL.txt create mode 100644 extern/solid/Makefile create mode 100644 extern/solid/README.txt create mode 100644 extern/solid/SConscript create mode 100644 extern/solid/SOLID/SOLID.h create mode 100644 extern/solid/SOLID/SOLID_broad.h create mode 100644 extern/solid/SOLID/SOLID_types.h create mode 100644 extern/solid/VisualC6/broad/broad.dsp create mode 100644 extern/solid/VisualC6/complex/complex.dsp create mode 100644 extern/solid/VisualC6/convex/convex.dsp create mode 100644 extern/solid/VisualC6/dynamics/dynamics.dsp create mode 100644 extern/solid/VisualC6/gldemo/gldemo.dsp create mode 100644 extern/solid/VisualC6/mnm/mnm.dsp create mode 100644 extern/solid/VisualC6/physics/physics.dsp create mode 100644 extern/solid/VisualC6/sample/sample.dsp create mode 100644 extern/solid/VisualC6/solid.dsw create mode 100644 extern/solid/VisualC6/solid/solid.dsp create mode 100644 extern/solid/VisualC6/solid_dll/solid_dll.dsp create mode 100644 extern/solid/include/GEN_MinMax.h create mode 100644 extern/solid/include/GEN_random.h create mode 100644 extern/solid/include/MT/Interval.h create mode 100644 extern/solid/include/MT/Matrix3x3.h create mode 100644 extern/solid/include/MT/Quaternion.h create mode 100644 extern/solid/include/MT/Transform.h create mode 100644 extern/solid/include/MT/Tuple3.h create mode 100644 extern/solid/include/MT/Tuple4.h create mode 100644 extern/solid/include/MT/Vector3.h create mode 100644 extern/solid/include/MT_BBox.h create mode 100644 extern/solid/include/MT_Interval.h create mode 100644 extern/solid/include/MT_Matrix3x3.h create mode 100644 extern/solid/include/MT_Point3.h create mode 100644 extern/solid/include/MT_Quaternion.h create mode 100644 extern/solid/include/MT_Scalar.h create mode 100644 extern/solid/include/MT_Transform.h create mode 100644 extern/solid/include/MT_Vector3.h create mode 100644 extern/solid/include/SOLID.h create mode 100644 extern/solid/include/SOLID_broad.h create mode 100644 extern/solid/include/SOLID_types.h create mode 100644 extern/solid/make/msvc_7_0/broad/broad.vcproj create mode 100644 extern/solid/make/msvc_7_0/complex/complex.vcproj create mode 100644 extern/solid/make/msvc_7_0/convex/convex.vcproj create mode 100644 extern/solid/make/msvc_7_0/solid.vcproj create mode 100644 extern/solid/src/DT_AlgoTable.h create mode 100644 extern/solid/src/DT_C-api.cpp create mode 100644 extern/solid/src/DT_Encounter.cpp create mode 100644 extern/solid/src/DT_Encounter.h create mode 100644 extern/solid/src/DT_Object.cpp create mode 100644 extern/solid/src/DT_Object.h create mode 100644 extern/solid/src/DT_RespTable.cpp create mode 100644 extern/solid/src/DT_RespTable.h create mode 100644 extern/solid/src/DT_Response.h create mode 100644 extern/solid/src/DT_Scene.cpp create mode 100644 extern/solid/src/DT_Scene.h create mode 100644 extern/solid/src/Makefile create mode 100644 extern/solid/src/broad/BP_C-api.cpp create mode 100644 extern/solid/src/broad/BP_Endpoint.h create mode 100644 extern/solid/src/broad/BP_EndpointList.cpp create mode 100644 extern/solid/src/broad/BP_EndpointList.h create mode 100644 extern/solid/src/broad/BP_Proxy.cpp create mode 100644 extern/solid/src/broad/BP_Proxy.h create mode 100644 extern/solid/src/broad/BP_ProxyList.h create mode 100644 extern/solid/src/broad/BP_Scene.cpp create mode 100644 extern/solid/src/broad/BP_Scene.h create mode 100644 extern/solid/src/broad/Makefile create mode 100644 extern/solid/src/complex/DT_BBoxTree.cpp create mode 100644 extern/solid/src/complex/DT_BBoxTree.h create mode 100644 extern/solid/src/complex/DT_CBox.h create mode 100644 extern/solid/src/complex/DT_Complex.cpp create mode 100644 extern/solid/src/complex/DT_Complex.h create mode 100644 extern/solid/src/complex/Makefile create mode 100644 extern/solid/src/convex/DT_Accuracy.cpp create mode 100644 extern/solid/src/convex/DT_Accuracy.h create mode 100644 extern/solid/src/convex/DT_Array.h create mode 100644 extern/solid/src/convex/DT_Box.cpp create mode 100644 extern/solid/src/convex/DT_Box.h create mode 100644 extern/solid/src/convex/DT_Cone.cpp create mode 100644 extern/solid/src/convex/DT_Cone.h create mode 100644 extern/solid/src/convex/DT_Convex.cpp create mode 100644 extern/solid/src/convex/DT_Convex.h create mode 100644 extern/solid/src/convex/DT_Cylinder.cpp create mode 100644 extern/solid/src/convex/DT_Cylinder.h create mode 100644 extern/solid/src/convex/DT_Facet.cpp create mode 100644 extern/solid/src/convex/DT_Facet.h create mode 100644 extern/solid/src/convex/DT_GJK.h create mode 100644 extern/solid/src/convex/DT_Hull.h create mode 100644 extern/solid/src/convex/DT_IndexArray.h create mode 100644 extern/solid/src/convex/DT_LineSegment.cpp create mode 100644 extern/solid/src/convex/DT_LineSegment.h create mode 100644 extern/solid/src/convex/DT_Minkowski.h create mode 100644 extern/solid/src/convex/DT_PenDepth.cpp create mode 100644 extern/solid/src/convex/DT_PenDepth.h create mode 100644 extern/solid/src/convex/DT_Point.cpp create mode 100644 extern/solid/src/convex/DT_Point.h create mode 100644 extern/solid/src/convex/DT_Polyhedron.cpp create mode 100644 extern/solid/src/convex/DT_Polyhedron.h create mode 100644 extern/solid/src/convex/DT_Polytope.cpp create mode 100644 extern/solid/src/convex/DT_Polytope.h create mode 100644 extern/solid/src/convex/DT_Shape.h create mode 100644 extern/solid/src/convex/DT_Sphere.cpp create mode 100644 extern/solid/src/convex/DT_Sphere.h create mode 100644 extern/solid/src/convex/DT_Transform.h create mode 100644 extern/solid/src/convex/DT_Triangle.cpp create mode 100644 extern/solid/src/convex/DT_Triangle.h create mode 100644 extern/solid/src/convex/DT_VertexBase.h create mode 100644 extern/solid/src/convex/Makefile create mode 100644 extern/verse/CMakeLists.txt create mode 100644 extern/verse/Makefile create mode 100644 extern/verse/dist/BUGS create mode 100644 extern/verse/dist/CMakeLists.txt create mode 100644 extern/verse/dist/MAINTAINERS create mode 100644 extern/verse/dist/Makefile create mode 100644 extern/verse/dist/Makefile.win32 create mode 100644 extern/verse/dist/README.html create mode 100644 extern/verse/dist/SConstruct create mode 100644 extern/verse/dist/examples/list-nodes.c create mode 100644 extern/verse/dist/mkprot_cmd/CMakeLists.txt create mode 100644 extern/verse/dist/resources/Makefile.win32 create mode 100644 extern/verse/dist/resources/verse.ico create mode 100644 extern/verse/dist/resources/verse.rc create mode 100644 extern/verse/dist/resources/verse.res create mode 100644 extern/verse/dist/v_bignum.c create mode 100644 extern/verse/dist/v_bignum.h create mode 100644 extern/verse/dist/v_cmd_buf.c create mode 100644 extern/verse/dist/v_cmd_buf.h create mode 100644 extern/verse/dist/v_cmd_def_a.c create mode 100644 extern/verse/dist/v_cmd_def_b.c create mode 100644 extern/verse/dist/v_cmd_def_c.c create mode 100644 extern/verse/dist/v_cmd_def_g.c create mode 100644 extern/verse/dist/v_cmd_def_m.c create mode 100644 extern/verse/dist/v_cmd_def_o.c create mode 100644 extern/verse/dist/v_cmd_def_s.c create mode 100644 extern/verse/dist/v_cmd_def_t.c create mode 100644 extern/verse/dist/v_cmd_gen.c create mode 100644 extern/verse/dist/v_cmd_gen.h create mode 100644 extern/verse/dist/v_connect.c create mode 100644 extern/verse/dist/v_connection.c create mode 100644 extern/verse/dist/v_connection.h create mode 100644 extern/verse/dist/v_encryption.c create mode 100644 extern/verse/dist/v_encryption.h create mode 100644 extern/verse/dist/v_func_storage.c create mode 100644 extern/verse/dist/v_gen_pack_a_node.c create mode 100644 extern/verse/dist/v_gen_pack_b_node.c create mode 100644 extern/verse/dist/v_gen_pack_c_node.c create mode 100644 extern/verse/dist/v_gen_pack_g_node.c create mode 100644 extern/verse/dist/v_gen_pack_init.c create mode 100644 extern/verse/dist/v_gen_pack_m_node.c create mode 100644 extern/verse/dist/v_gen_pack_o_node.c create mode 100644 extern/verse/dist/v_gen_pack_s_node.c create mode 100644 extern/verse/dist/v_gen_pack_t_node.c create mode 100644 extern/verse/dist/v_gen_unpack_func.h create mode 100644 extern/verse/dist/v_gen_unpack_funcs.h create mode 100644 extern/verse/dist/v_internal_verse.h create mode 100644 extern/verse/dist/v_man_pack_node.c create mode 100644 extern/verse/dist/v_network.c create mode 100644 extern/verse/dist/v_network.h create mode 100644 extern/verse/dist/v_network_in_que.c create mode 100644 extern/verse/dist/v_network_in_que.h create mode 100644 extern/verse/dist/v_network_out_que.c create mode 100644 extern/verse/dist/v_network_out_que.h create mode 100644 extern/verse/dist/v_pack.c create mode 100644 extern/verse/dist/v_pack.h create mode 100644 extern/verse/dist/v_pack_method.c create mode 100644 extern/verse/dist/v_prime.c create mode 100644 extern/verse/dist/v_randgen.c create mode 100644 extern/verse/dist/v_randgen.h create mode 100644 extern/verse/dist/v_util.c create mode 100644 extern/verse/dist/v_util.h create mode 100644 extern/verse/dist/verse.h create mode 100644 extern/verse/dist/verse_header.h create mode 100644 extern/verse/dist/verse_ms.c create mode 100644 extern/verse/dist/verse_ms.h create mode 100644 extern/verse/dist/vs_connection.c create mode 100644 extern/verse/dist/vs_main.c create mode 100644 extern/verse/dist/vs_master.c create mode 100644 extern/verse/dist/vs_node_audio.c create mode 100644 extern/verse/dist/vs_node_bitmap.c create mode 100644 extern/verse/dist/vs_node_curve.c create mode 100644 extern/verse/dist/vs_node_geometry.c create mode 100644 extern/verse/dist/vs_node_head.c create mode 100644 extern/verse/dist/vs_node_material.c create mode 100644 extern/verse/dist/vs_node_object.c create mode 100644 extern/verse/dist/vs_node_particle.c create mode 100644 extern/verse/dist/vs_node_storage.c create mode 100644 extern/verse/dist/vs_node_text.c create mode 100644 extern/verse/dist/vs_server.h create mode 100644 extern/verse/make/msvc_7_0/libverse.vcproj create mode 100644 extern/verse/make/msvc_7_0/verse.vcproj create mode 100644 intern/CMakeLists.txt create mode 100644 intern/Makefile create mode 100644 intern/SConscript create mode 100644 intern/SoundSystem/CMakeLists.txt create mode 100644 intern/SoundSystem/Makefile create mode 100644 intern/SoundSystem/SConscript create mode 100644 intern/SoundSystem/SND_C-api.h create mode 100644 intern/SoundSystem/SND_CDObject.h create mode 100644 intern/SoundSystem/SND_DependKludge.h create mode 100644 intern/SoundSystem/SND_DeviceManager.h create mode 100644 intern/SoundSystem/SND_IAudioDevice.h create mode 100644 intern/SoundSystem/SND_Object.h create mode 100644 intern/SoundSystem/SND_Scene.h create mode 100644 intern/SoundSystem/SND_SoundListener.h create mode 100644 intern/SoundSystem/SND_SoundObject.h create mode 100644 intern/SoundSystem/SND_Utils.h create mode 100644 intern/SoundSystem/SND_WaveCache.h create mode 100644 intern/SoundSystem/SND_WaveSlot.h create mode 100644 intern/SoundSystem/SND_test/Makefile create mode 100644 intern/SoundSystem/SND_test/SND_test.c create mode 100644 intern/SoundSystem/SoundDefines.h create mode 100644 intern/SoundSystem/dummy/Makefile create mode 100644 intern/SoundSystem/dummy/SND_DummyDevice.cpp create mode 100644 intern/SoundSystem/dummy/SND_DummyDevice.h create mode 100644 intern/SoundSystem/fmod/Makefile create mode 100644 intern/SoundSystem/fmod/SND_FmodDevice.cpp create mode 100644 intern/SoundSystem/fmod/SND_FmodDevice.h create mode 100644 intern/SoundSystem/intern/Makefile create mode 100644 intern/SoundSystem/intern/SND_AudioDevice.cpp create mode 100644 intern/SoundSystem/intern/SND_AudioDevice.h create mode 100644 intern/SoundSystem/intern/SND_C-api.cpp create mode 100644 intern/SoundSystem/intern/SND_CDObject.cpp create mode 100644 intern/SoundSystem/intern/SND_DeviceManager.cpp create mode 100644 intern/SoundSystem/intern/SND_IdObject.cpp create mode 100644 intern/SoundSystem/intern/SND_IdObject.h create mode 100644 intern/SoundSystem/intern/SND_Scene.cpp create mode 100644 intern/SoundSystem/intern/SND_SoundListener.cpp create mode 100644 intern/SoundSystem/intern/SND_SoundObject.cpp create mode 100644 intern/SoundSystem/intern/SND_Utils.cpp create mode 100644 intern/SoundSystem/intern/SND_WaveCache.cpp create mode 100644 intern/SoundSystem/intern/SND_WaveSlot.cpp create mode 100644 intern/SoundSystem/make/msvc_6_0/SoundSystem.dsp create mode 100644 intern/SoundSystem/make/msvc_6_0/dummy/DummySoundSystem.dsp create mode 100644 intern/SoundSystem/make/msvc_6_0/openal/OpenALSoundSystem.dsp create mode 100644 intern/SoundSystem/make/msvc_7_0/SoundSystem.vcproj create mode 100644 intern/SoundSystem/make/msvc_7_0/dummy/DummySoundSystem.vcproj create mode 100644 intern/SoundSystem/make/msvc_7_0/openal/OpenALSoundSystem.vcproj create mode 100644 intern/SoundSystem/openal/Makefile create mode 100644 intern/SoundSystem/openal/SND_OpenALDevice.cpp create mode 100644 intern/SoundSystem/openal/SND_OpenALDevice.h create mode 100644 intern/SoundSystem/openal/pthread_cancel.cpp create mode 100644 intern/SoundSystem/sdl/Makefile create mode 100644 intern/SoundSystem/sdl/SND_SDLCDDevice.cpp create mode 100644 intern/SoundSystem/sdl/SND_SDLCDDevice.h create mode 100644 intern/bmfont/BMF_Api.h create mode 100644 intern/bmfont/BMF_Fonts.h create mode 100644 intern/bmfont/BMF_Settings.h create mode 100644 intern/bmfont/CMakeLists.txt create mode 100644 intern/bmfont/Makefile create mode 100644 intern/bmfont/SConscript create mode 100644 intern/bmfont/intern/BMF_Api.cpp create mode 100644 intern/bmfont/intern/BMF_BitmapFont.cpp create mode 100644 intern/bmfont/intern/BMF_BitmapFont.h create mode 100644 intern/bmfont/intern/BMF_FontData.h create mode 100644 intern/bmfont/intern/BMF_font_helv10.cpp create mode 100644 intern/bmfont/intern/BMF_font_helv12.cpp create mode 100644 intern/bmfont/intern/BMF_font_helvb10.cpp create mode 100644 intern/bmfont/intern/BMF_font_helvb12.cpp create mode 100644 intern/bmfont/intern/BMF_font_helvb14.cpp create mode 100644 intern/bmfont/intern/BMF_font_helvb8.cpp create mode 100644 intern/bmfont/intern/BMF_font_scr12.cpp create mode 100644 intern/bmfont/intern/BMF_font_scr14.cpp create mode 100644 intern/bmfont/intern/BMF_font_scr15.cpp create mode 100644 intern/bmfont/intern/Makefile create mode 100644 intern/bmfont/make/msvc_6_0/bmfont.dsp create mode 100644 intern/bmfont/make/msvc_6_0/bmfont.dsw create mode 100644 intern/bmfont/make/msvc_7_0/bmfont.sln create mode 100644 intern/bmfont/make/msvc_7_0/bmfont.vcproj create mode 100644 intern/bmfont/test/Makefile create mode 100644 intern/bmfont/test/make/msvc_6_0/BMF_Test.dsp create mode 100644 intern/bmfont/test/make/msvc_6_0/BMF_Test.dsw create mode 100644 intern/bmfont/test/simpletest/BMF_Test.cpp create mode 100644 intern/bmfont/test/simpletest/Makefile create mode 100644 intern/boolop/CMakeLists.txt create mode 100644 intern/boolop/Makefile create mode 100644 intern/boolop/SConscript create mode 100644 intern/boolop/extern/BOP_Interface.h create mode 100644 intern/boolop/intern/BOP_BBox.cpp create mode 100644 intern/boolop/intern/BOP_BBox.h create mode 100644 intern/boolop/intern/BOP_BSPNode.cpp create mode 100644 intern/boolop/intern/BOP_BSPNode.h create mode 100644 intern/boolop/intern/BOP_BSPTree.cpp create mode 100644 intern/boolop/intern/BOP_BSPTree.h create mode 100644 intern/boolop/intern/BOP_Chrono.h create mode 100644 intern/boolop/intern/BOP_Edge.cpp create mode 100644 intern/boolop/intern/BOP_Edge.h create mode 100644 intern/boolop/intern/BOP_Face.cpp create mode 100644 intern/boolop/intern/BOP_Face.h create mode 100644 intern/boolop/intern/BOP_Face2Face.cpp create mode 100644 intern/boolop/intern/BOP_Face2Face.h create mode 100644 intern/boolop/intern/BOP_Indexs.h create mode 100644 intern/boolop/intern/BOP_Interface.cpp create mode 100644 intern/boolop/intern/BOP_MathUtils.cpp create mode 100644 intern/boolop/intern/BOP_MathUtils.h create mode 100644 intern/boolop/intern/BOP_Merge.cpp create mode 100644 intern/boolop/intern/BOP_Merge.h create mode 100644 intern/boolop/intern/BOP_Mesh.cpp create mode 100644 intern/boolop/intern/BOP_Mesh.h create mode 100644 intern/boolop/intern/BOP_Segment.cpp create mode 100644 intern/boolop/intern/BOP_Segment.h create mode 100644 intern/boolop/intern/BOP_Splitter.cpp create mode 100644 intern/boolop/intern/BOP_Splitter.h create mode 100644 intern/boolop/intern/BOP_Tag.cpp create mode 100644 intern/boolop/intern/BOP_Tag.h create mode 100644 intern/boolop/intern/BOP_Triangulator.cpp create mode 100644 intern/boolop/intern/BOP_Triangulator.h create mode 100644 intern/boolop/intern/BOP_Vertex.cpp create mode 100644 intern/boolop/intern/BOP_Vertex.h create mode 100644 intern/boolop/intern/Makefile create mode 100644 intern/boolop/make/msvc_6_0/boolop.dsp create mode 100644 intern/boolop/make/msvc_7_0/boolop.vcproj create mode 100644 intern/bsp/CMakeLists.txt create mode 100644 intern/bsp/Makefile create mode 100644 intern/bsp/SConscript create mode 100644 intern/bsp/extern/CSG_BooleanOps.h create mode 100644 intern/bsp/intern/BSP_CSGException.h create mode 100644 intern/bsp/intern/BSP_CSGMesh.cpp create mode 100644 intern/bsp/intern/BSP_CSGMesh.h create mode 100644 intern/bsp/intern/BSP_CSGMesh_CFIterator.h create mode 100644 intern/bsp/intern/BSP_MeshPrimitives.cpp create mode 100644 intern/bsp/intern/BSP_MeshPrimitives.h create mode 100644 intern/bsp/intern/CSG_BooleanOps.cpp create mode 100644 intern/bsp/intern/Makefile create mode 100644 intern/bsp/make/msvc6_0/bsplib.dsp create mode 100644 intern/bsp/make/msvc6_0/bsplib.dsw create mode 100644 intern/bsp/make/msvc_7_0/bsplib.sln create mode 100644 intern/bsp/make/msvc_7_0/bsplib.vcproj create mode 100644 intern/bsp/test/BSP_GhostTest/BSP_GhostTest.dsp create mode 100644 intern/bsp/test/BSP_GhostTest/BSP_GhostTest.dsw create mode 100644 intern/bsp/test/BSP_GhostTest/BSP_GhostTest3D.cpp create mode 100644 intern/bsp/test/BSP_GhostTest/BSP_GhostTest3D.h create mode 100644 intern/bsp/test/BSP_GhostTest/BSP_MeshDrawer.cpp create mode 100644 intern/bsp/test/BSP_GhostTest/BSP_MeshDrawer.h create mode 100644 intern/bsp/test/BSP_GhostTest/BSP_PlyLoader.cpp create mode 100644 intern/bsp/test/BSP_GhostTest/BSP_PlyLoader.h create mode 100644 intern/bsp/test/BSP_GhostTest/BSP_TMesh.h create mode 100644 intern/bsp/test/BSP_GhostTest/Makefile create mode 100644 intern/bsp/test/BSP_GhostTest/main.cpp create mode 100644 intern/bsp/test/BSP_GhostTest/ply.h create mode 100644 intern/bsp/test/BSP_GhostTest/plyfile.c create mode 100644 intern/bsp/test/Makefile create mode 100644 intern/container/CMakeLists.txt create mode 100644 intern/container/CTR_List.h create mode 100644 intern/container/CTR_Map.h create mode 100644 intern/container/CTR_TaggedIndex.h create mode 100644 intern/container/CTR_TaggedSetOps.h create mode 100644 intern/container/CTR_UHeap.h create mode 100644 intern/container/Makefile create mode 100644 intern/container/SConscript create mode 100644 intern/container/intern/CTR_List.cpp create mode 100644 intern/container/intern/Makefile create mode 100644 intern/container/make/msvc_6_0/container.dsp create mode 100644 intern/container/make/msvc_6_0/container.dsw create mode 100644 intern/container/make/msvc_7_0/container.sln create mode 100644 intern/container/make/msvc_7_0/container.vcproj create mode 100644 intern/decimation/CMakeLists.txt create mode 100644 intern/decimation/Makefile create mode 100644 intern/decimation/SConscript create mode 100644 intern/decimation/extern/LOD_decimation.h create mode 100644 intern/decimation/intern/LOD_DecimationClass.h create mode 100644 intern/decimation/intern/LOD_EdgeCollapser.cpp create mode 100644 intern/decimation/intern/LOD_EdgeCollapser.h create mode 100644 intern/decimation/intern/LOD_ExternBufferEditor.h create mode 100644 intern/decimation/intern/LOD_ExternNormalEditor.cpp create mode 100644 intern/decimation/intern/LOD_ExternNormalEditor.h create mode 100644 intern/decimation/intern/LOD_FaceNormalEditor.cpp create mode 100644 intern/decimation/intern/LOD_FaceNormalEditor.h create mode 100644 intern/decimation/intern/LOD_ManMesh2.cpp create mode 100644 intern/decimation/intern/LOD_ManMesh2.h create mode 100644 intern/decimation/intern/LOD_MeshBounds.h create mode 100644 intern/decimation/intern/LOD_MeshException.h create mode 100644 intern/decimation/intern/LOD_MeshPrimitives.cpp create mode 100644 intern/decimation/intern/LOD_MeshPrimitives.h create mode 100644 intern/decimation/intern/LOD_QSDecimator.cpp create mode 100644 intern/decimation/intern/LOD_QSDecimator.h create mode 100644 intern/decimation/intern/LOD_Quadric.h create mode 100644 intern/decimation/intern/LOD_QuadricEditor.cpp create mode 100644 intern/decimation/intern/LOD_QuadricEditor.h create mode 100644 intern/decimation/intern/LOD_decimation.cpp create mode 100644 intern/decimation/intern/Makefile create mode 100644 intern/decimation/make/msvc_6_0/decimation.dsp create mode 100644 intern/decimation/make/msvc_6_0/decimation.dsw create mode 100644 intern/decimation/make/msvc_7_0/decimation.sln create mode 100644 intern/decimation/make/msvc_7_0/decimation.vcproj create mode 100644 intern/elbeem/CMakeLists.txt create mode 100644 intern/elbeem/COPYING create mode 100644 intern/elbeem/COPYING_trimesh2 create mode 100644 intern/elbeem/Makefile create mode 100644 intern/elbeem/SConscript create mode 100644 intern/elbeem/extern/LBM_fluidsim.h create mode 100644 intern/elbeem/extern/elbeem.h create mode 100644 intern/elbeem/intern/Makefile create mode 100644 intern/elbeem/intern/attributes.cpp create mode 100644 intern/elbeem/intern/attributes.h create mode 100644 intern/elbeem/intern/elbeem.cpp create mode 100644 intern/elbeem/intern/elbeem.h create mode 100644 intern/elbeem/intern/isosurface.cpp create mode 100644 intern/elbeem/intern/isosurface.h create mode 100644 intern/elbeem/intern/loop_tools.h create mode 100644 intern/elbeem/intern/mcubes_tables.h create mode 100644 intern/elbeem/intern/ntl_blenderdumper.cpp create mode 100644 intern/elbeem/intern/ntl_blenderdumper.h create mode 100644 intern/elbeem/intern/ntl_bsptree.cpp create mode 100644 intern/elbeem/intern/ntl_bsptree.h create mode 100644 intern/elbeem/intern/ntl_geometryclass.h create mode 100644 intern/elbeem/intern/ntl_geometrymodel.cpp create mode 100644 intern/elbeem/intern/ntl_geometrymodel.h create mode 100644 intern/elbeem/intern/ntl_geometryobject.cpp create mode 100644 intern/elbeem/intern/ntl_geometryobject.h create mode 100644 intern/elbeem/intern/ntl_geometryshader.h create mode 100644 intern/elbeem/intern/ntl_lighting.cpp create mode 100644 intern/elbeem/intern/ntl_lighting.h create mode 100644 intern/elbeem/intern/ntl_matrices.h create mode 100644 intern/elbeem/intern/ntl_ray.cpp create mode 100644 intern/elbeem/intern/ntl_ray.h create mode 100644 intern/elbeem/intern/ntl_vector3dim.h create mode 100644 intern/elbeem/intern/ntl_world.cpp create mode 100644 intern/elbeem/intern/ntl_world.h create mode 100644 intern/elbeem/intern/parametrizer.cpp create mode 100644 intern/elbeem/intern/parametrizer.h create mode 100644 intern/elbeem/intern/particletracer.cpp create mode 100644 intern/elbeem/intern/particletracer.h create mode 100644 intern/elbeem/intern/simulation_object.cpp create mode 100644 intern/elbeem/intern/simulation_object.h create mode 100644 intern/elbeem/intern/solver_adap.cpp create mode 100644 intern/elbeem/intern/solver_class.h create mode 100644 intern/elbeem/intern/solver_init.cpp create mode 100644 intern/elbeem/intern/solver_interface.cpp create mode 100644 intern/elbeem/intern/solver_interface.h create mode 100644 intern/elbeem/intern/solver_main.cpp create mode 100644 intern/elbeem/intern/solver_relax.h create mode 100644 intern/elbeem/intern/solver_util.cpp create mode 100644 intern/elbeem/intern/utilities.cpp create mode 100644 intern/elbeem/intern/utilities.h create mode 100644 intern/elbeem/make/msvc_6_0/elbeem.dsp create mode 100644 intern/elbeem/make/msvc_7_0/elbeem.vcproj create mode 100644 intern/ghost/CMakeLists.txt create mode 100644 intern/ghost/GHOST_C-api.h create mode 100644 intern/ghost/GHOST_IEvent.h create mode 100644 intern/ghost/GHOST_IEventConsumer.h create mode 100644 intern/ghost/GHOST_ISystem.h create mode 100644 intern/ghost/GHOST_ITimerTask.h create mode 100644 intern/ghost/GHOST_IWindow.h create mode 100644 intern/ghost/GHOST_Rect.h create mode 100644 intern/ghost/GHOST_Types.h create mode 100644 intern/ghost/Makefile create mode 100644 intern/ghost/SConscript create mode 100644 intern/ghost/doc/ghost_interface.cfg create mode 100644 intern/ghost/intern/GHOST_Buttons.cpp create mode 100644 intern/ghost/intern/GHOST_Buttons.h create mode 100644 intern/ghost/intern/GHOST_C-api.cpp create mode 100644 intern/ghost/intern/GHOST_CallbackEventConsumer.cpp create mode 100644 intern/ghost/intern/GHOST_CallbackEventConsumer.h create mode 100644 intern/ghost/intern/GHOST_Debug.h create mode 100644 intern/ghost/intern/GHOST_DisplayManager.cpp create mode 100644 intern/ghost/intern/GHOST_DisplayManager.h create mode 100644 intern/ghost/intern/GHOST_DisplayManagerCarbon.cpp create mode 100644 intern/ghost/intern/GHOST_DisplayManagerCarbon.h create mode 100644 intern/ghost/intern/GHOST_DisplayManagerWin32.cpp create mode 100644 intern/ghost/intern/GHOST_DisplayManagerWin32.h create mode 100644 intern/ghost/intern/GHOST_DisplayManagerX11.cpp create mode 100644 intern/ghost/intern/GHOST_DisplayManagerX11.h create mode 100644 intern/ghost/intern/GHOST_Event.h create mode 100644 intern/ghost/intern/GHOST_EventButton.h create mode 100644 intern/ghost/intern/GHOST_EventCursor.h create mode 100644 intern/ghost/intern/GHOST_EventKey.h create mode 100644 intern/ghost/intern/GHOST_EventManager.cpp create mode 100644 intern/ghost/intern/GHOST_EventManager.h create mode 100644 intern/ghost/intern/GHOST_EventPrinter.cpp create mode 100644 intern/ghost/intern/GHOST_EventPrinter.h create mode 100644 intern/ghost/intern/GHOST_EventWheel.h create mode 100644 intern/ghost/intern/GHOST_ISystem.cpp create mode 100644 intern/ghost/intern/GHOST_ModifierKeys.cpp create mode 100644 intern/ghost/intern/GHOST_ModifierKeys.h create mode 100644 intern/ghost/intern/GHOST_Rect.cpp create mode 100644 intern/ghost/intern/GHOST_System.cpp create mode 100644 intern/ghost/intern/GHOST_System.h create mode 100644 intern/ghost/intern/GHOST_SystemCarbon.cpp create mode 100644 intern/ghost/intern/GHOST_SystemCarbon.h create mode 100644 intern/ghost/intern/GHOST_SystemWin32.cpp create mode 100644 intern/ghost/intern/GHOST_SystemWin32.h create mode 100644 intern/ghost/intern/GHOST_SystemX11.cpp create mode 100644 intern/ghost/intern/GHOST_SystemX11.h create mode 100644 intern/ghost/intern/GHOST_TimerManager.cpp create mode 100644 intern/ghost/intern/GHOST_TimerManager.h create mode 100644 intern/ghost/intern/GHOST_TimerTask.h create mode 100644 intern/ghost/intern/GHOST_Window.cpp create mode 100644 intern/ghost/intern/GHOST_Window.h create mode 100644 intern/ghost/intern/GHOST_WindowCarbon.cpp create mode 100644 intern/ghost/intern/GHOST_WindowCarbon.h create mode 100644 intern/ghost/intern/GHOST_WindowManager.cpp create mode 100644 intern/ghost/intern/GHOST_WindowManager.h create mode 100644 intern/ghost/intern/GHOST_WindowWin32.cpp create mode 100644 intern/ghost/intern/GHOST_WindowWin32.h create mode 100644 intern/ghost/intern/GHOST_WindowX11.cpp create mode 100644 intern/ghost/intern/GHOST_WindowX11.h create mode 100644 intern/ghost/intern/Makefile create mode 100644 intern/ghost/make/msvc/ghost.dsp create mode 100644 intern/ghost/make/msvc/ghost.dsw create mode 100644 intern/ghost/make/msvc_7_0/ghost.sln create mode 100644 intern/ghost/make/msvc_7_0/ghost.vcproj create mode 100644 intern/ghost/test/Makefile create mode 100644 intern/ghost/test/gears/GHOST_C-Test.c create mode 100644 intern/ghost/test/gears/GHOST_Test.cpp create mode 100644 intern/ghost/test/gears/Makefile create mode 100644 intern/ghost/test/make/msvc_6_0/gears.dsp create mode 100644 intern/ghost/test/make/msvc_6_0/gears_C.dsp create mode 100644 intern/ghost/test/make/msvc_6_0/ghost_test.dsw create mode 100644 intern/ghost/test/multitest/Basic.c create mode 100644 intern/ghost/test/multitest/Basic.h create mode 100644 intern/ghost/test/multitest/EventToBuf.c create mode 100644 intern/ghost/test/multitest/EventToBuf.h create mode 100644 intern/ghost/test/multitest/GL.h create mode 100644 intern/ghost/test/multitest/Makefile create mode 100644 intern/ghost/test/multitest/MultiTest.c create mode 100644 intern/ghost/test/multitest/ScrollBar.c create mode 100644 intern/ghost/test/multitest/ScrollBar.h create mode 100644 intern/ghost/test/multitest/Util.c create mode 100644 intern/ghost/test/multitest/Util.h create mode 100644 intern/ghost/test/multitest/WindowData.c create mode 100644 intern/ghost/test/multitest/WindowData.h create mode 100644 intern/guardedalloc/CMakeLists.txt create mode 100644 intern/guardedalloc/MEM_guardedalloc.h create mode 100644 intern/guardedalloc/Makefile create mode 100644 intern/guardedalloc/SConscript create mode 100644 intern/guardedalloc/intern/Makefile create mode 100644 intern/guardedalloc/intern/mallocn.c create mode 100644 intern/guardedalloc/make/msvc_6_0/guardedalloc.dsp create mode 100644 intern/guardedalloc/make/msvc_7_0/guardedalloc.sln create mode 100644 intern/guardedalloc/make/msvc_7_0/guardedalloc.vcproj create mode 100644 intern/guardedalloc/test/Makefile create mode 100644 intern/guardedalloc/test/simpletest/Makefile create mode 100644 intern/guardedalloc/test/simpletest/memtest.c create mode 100644 intern/iksolver/CMakeLists.txt create mode 100644 intern/iksolver/Makefile create mode 100644 intern/iksolver/SConscript create mode 100644 intern/iksolver/extern/IK_solver.h create mode 100644 intern/iksolver/intern/IK_QJacobian.cpp create mode 100644 intern/iksolver/intern/IK_QJacobian.h create mode 100644 intern/iksolver/intern/IK_QJacobianSolver.cpp create mode 100644 intern/iksolver/intern/IK_QJacobianSolver.h create mode 100644 intern/iksolver/intern/IK_QSegment.cpp create mode 100644 intern/iksolver/intern/IK_QSegment.h create mode 100644 intern/iksolver/intern/IK_QTask.cpp create mode 100644 intern/iksolver/intern/IK_QTask.h create mode 100644 intern/iksolver/intern/IK_Solver.cpp create mode 100644 intern/iksolver/intern/MT_ExpMap.cpp create mode 100644 intern/iksolver/intern/MT_ExpMap.h create mode 100644 intern/iksolver/intern/Makefile create mode 100644 intern/iksolver/intern/TNT/cholesky.h create mode 100644 intern/iksolver/intern/TNT/cmat.h create mode 100644 intern/iksolver/intern/TNT/fcscmat.h create mode 100644 intern/iksolver/intern/TNT/fmat.h create mode 100644 intern/iksolver/intern/TNT/fortran.h create mode 100644 intern/iksolver/intern/TNT/fspvec.h create mode 100644 intern/iksolver/intern/TNT/index.h create mode 100644 intern/iksolver/intern/TNT/lapack.h create mode 100644 intern/iksolver/intern/TNT/lu.h create mode 100644 intern/iksolver/intern/TNT/qr.h create mode 100644 intern/iksolver/intern/TNT/region1d.h create mode 100644 intern/iksolver/intern/TNT/region2d.h create mode 100644 intern/iksolver/intern/TNT/stopwatch.h create mode 100644 intern/iksolver/intern/TNT/subscript.h create mode 100644 intern/iksolver/intern/TNT/svd.h create mode 100644 intern/iksolver/intern/TNT/tnt.h create mode 100644 intern/iksolver/intern/TNT/tntmath.h create mode 100644 intern/iksolver/intern/TNT/tntreqs.h create mode 100644 intern/iksolver/intern/TNT/transv.h create mode 100644 intern/iksolver/intern/TNT/triang.h create mode 100644 intern/iksolver/intern/TNT/trisolve.h create mode 100644 intern/iksolver/intern/TNT/vec.h create mode 100644 intern/iksolver/intern/TNT/vecadaptor.h create mode 100644 intern/iksolver/intern/TNT/version.h create mode 100644 intern/iksolver/make/msvc_6_0/iksolver.dsp create mode 100644 intern/iksolver/make/msvc_6_0/iksolver.dsw create mode 100644 intern/iksolver/make/msvc_7_0/iksolver.sln create mode 100644 intern/iksolver/make/msvc_7_0/iksolver.vcproj create mode 100644 intern/iksolver/test/Makefile create mode 100644 intern/iksolver/test/ik_glut_test/Makefile create mode 100644 intern/iksolver/test/ik_glut_test/common/GlutDrawer.cpp create mode 100644 intern/iksolver/test/ik_glut_test/common/GlutDrawer.h create mode 100644 intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.cpp create mode 100644 intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.h create mode 100644 intern/iksolver/test/ik_glut_test/common/GlutMouseManager.cpp create mode 100644 intern/iksolver/test/ik_glut_test/common/GlutMouseManager.h create mode 100644 intern/iksolver/test/ik_glut_test/common/Makefile create mode 100644 intern/iksolver/test/ik_glut_test/intern/ChainDrawer.h create mode 100644 intern/iksolver/test/ik_glut_test/intern/Makefile create mode 100644 intern/iksolver/test/ik_glut_test/intern/MyGlutKeyHandler.h create mode 100644 intern/iksolver/test/ik_glut_test/intern/MyGlutMouseHandler.h create mode 100644 intern/iksolver/test/ik_glut_test/intern/main.cpp create mode 100644 intern/iksolver/test/ik_glut_test/make/msvc_6_0/ik_glut_test.dsp create mode 100644 intern/iksolver/test/ik_glut_test/make/msvc_6_0/ik_glut_test.dsw create mode 100644 intern/make/msvc_6_0/build_install_all.dsp create mode 100644 intern/make/msvc_6_0/intern.dsw create mode 100644 intern/make/msvc_7_0/build_install_all.vcproj create mode 100644 intern/make/msvc_7_0/intern.sln create mode 100644 intern/memutil/CMakeLists.txt create mode 100644 intern/memutil/MEM_Allocator.h create mode 100644 intern/memutil/MEM_CacheLimiter.h create mode 100644 intern/memutil/MEM_CacheLimiterC-Api.h create mode 100644 intern/memutil/MEM_NonCopyable.h create mode 100644 intern/memutil/MEM_RefCountPtr.h create mode 100644 intern/memutil/MEM_RefCounted.h create mode 100644 intern/memutil/MEM_RefCountedC-Api.h create mode 100644 intern/memutil/MEM_SmartPtr.h create mode 100644 intern/memutil/Makefile create mode 100644 intern/memutil/SConscript create mode 100644 intern/memutil/intern/MEM_CacheLimiterC-Api.cpp create mode 100644 intern/memutil/intern/MEM_RefCountedC-Api.cpp create mode 100644 intern/memutil/intern/Makefile create mode 100644 intern/memutil/make/msvc_60/memutil.dsp create mode 100644 intern/memutil/make/msvc_60/memutil.dsw create mode 100644 intern/memutil/make/msvc_7_0/memutil.sln create mode 100644 intern/memutil/make/msvc_7_0/memutil.vcproj create mode 100644 intern/moto/CMakeLists.txt create mode 100644 intern/moto/Makefile create mode 100644 intern/moto/SConscript create mode 100644 intern/moto/include/GEN_List.h create mode 100644 intern/moto/include/GEN_Map.h create mode 100644 intern/moto/include/MT_CmMatrix4x4.h create mode 100644 intern/moto/include/MT_Matrix3x3.h create mode 100644 intern/moto/include/MT_Matrix3x3.inl create mode 100644 intern/moto/include/MT_Matrix4x4.h create mode 100644 intern/moto/include/MT_Matrix4x4.inl create mode 100644 intern/moto/include/MT_MinMax.h create mode 100644 intern/moto/include/MT_Optimize.h create mode 100644 intern/moto/include/MT_Plane3.h create mode 100644 intern/moto/include/MT_Plane3.inl create mode 100644 intern/moto/include/MT_Point2.h create mode 100644 intern/moto/include/MT_Point2.inl create mode 100644 intern/moto/include/MT_Point3.h create mode 100644 intern/moto/include/MT_Point3.inl create mode 100644 intern/moto/include/MT_Quaternion.h create mode 100644 intern/moto/include/MT_Quaternion.inl create mode 100644 intern/moto/include/MT_Scalar.h create mode 100644 intern/moto/include/MT_Stream.h create mode 100644 intern/moto/include/MT_Transform.h create mode 100644 intern/moto/include/MT_Tuple2.h create mode 100644 intern/moto/include/MT_Tuple3.h create mode 100644 intern/moto/include/MT_Tuple4.h create mode 100644 intern/moto/include/MT_Vector2.h create mode 100644 intern/moto/include/MT_Vector2.inl create mode 100644 intern/moto/include/MT_Vector3.h create mode 100644 intern/moto/include/MT_Vector3.inl create mode 100644 intern/moto/include/MT_Vector4.h create mode 100644 intern/moto/include/MT_Vector4.inl create mode 100644 intern/moto/include/MT_assert.h create mode 100644 intern/moto/include/MT_random.h create mode 100644 intern/moto/include/NM_Scalar.h create mode 100644 intern/moto/intern/MT_Assert.cpp create mode 100644 intern/moto/intern/MT_CmMatrix4x4.cpp create mode 100644 intern/moto/intern/MT_Matrix3x3.cpp create mode 100644 intern/moto/intern/MT_Matrix4x4.cpp create mode 100644 intern/moto/intern/MT_Plane3.cpp create mode 100644 intern/moto/intern/MT_Point3.cpp create mode 100644 intern/moto/intern/MT_Quaternion.cpp create mode 100644 intern/moto/intern/MT_Transform.cpp create mode 100644 intern/moto/intern/MT_Vector2.cpp create mode 100644 intern/moto/intern/MT_Vector3.cpp create mode 100644 intern/moto/intern/MT_Vector4.cpp create mode 100644 intern/moto/intern/MT_random.cpp create mode 100644 intern/moto/intern/Makefile create mode 100644 intern/moto/make/msvc_6_0/MoTo.dsp create mode 100644 intern/moto/make/msvc_6_0/MoTo.dsw create mode 100644 intern/moto/make/msvc_7_0/moto.sln create mode 100644 intern/moto/make/msvc_7_0/moto.vcproj create mode 100644 intern/opennl/CMakeLists.txt create mode 100644 intern/opennl/Makefile create mode 100644 intern/opennl/SConscript create mode 100644 intern/opennl/doc/OpenNL_License.txt create mode 100644 intern/opennl/doc/OpenNL_Readme.txt create mode 100644 intern/opennl/doc/SuperLU_License.txt create mode 100644 intern/opennl/doc/SuperLU_Readme.txt create mode 100644 intern/opennl/extern/ONL_opennl.h create mode 100644 intern/opennl/intern/Makefile create mode 100644 intern/opennl/intern/opennl.c create mode 100644 intern/opennl/make/msvc_6_0/OpenNL.dsp create mode 100644 intern/opennl/make/msvc_6_0/OpenNL.dsw create mode 100644 intern/opennl/make/msvc_7_0/opennl.vcproj create mode 100644 intern/opennl/superlu/Cnames.h create mode 100644 intern/opennl/superlu/Makefile create mode 100644 intern/opennl/superlu/colamd.c create mode 100644 intern/opennl/superlu/colamd.h create mode 100644 intern/opennl/superlu/get_perm_c.c create mode 100644 intern/opennl/superlu/heap_relax_snode.c create mode 100644 intern/opennl/superlu/lsame.c create mode 100644 intern/opennl/superlu/memory.c create mode 100644 intern/opennl/superlu/mmd.c create mode 100644 intern/opennl/superlu/relax_snode.c create mode 100644 intern/opennl/superlu/scolumn_bmod.c create mode 100644 intern/opennl/superlu/scolumn_dfs.c create mode 100644 intern/opennl/superlu/scopy_to_ucol.c create mode 100644 intern/opennl/superlu/sgssv.c create mode 100644 intern/opennl/superlu/sgstrf.c create mode 100644 intern/opennl/superlu/sgstrs.c create mode 100644 intern/opennl/superlu/smemory.c create mode 100644 intern/opennl/superlu/smyblas2.c create mode 100644 intern/opennl/superlu/sp_coletree.c create mode 100644 intern/opennl/superlu/sp_ienv.c create mode 100644 intern/opennl/superlu/sp_preorder.c create mode 100644 intern/opennl/superlu/spanel_bmod.c create mode 100644 intern/opennl/superlu/spanel_dfs.c create mode 100644 intern/opennl/superlu/spivotL.c create mode 100644 intern/opennl/superlu/spruneL.c create mode 100644 intern/opennl/superlu/ssnode_bmod.c create mode 100644 intern/opennl/superlu/ssnode_dfs.c create mode 100644 intern/opennl/superlu/ssp_blas2.c create mode 100644 intern/opennl/superlu/ssp_blas3.c create mode 100644 intern/opennl/superlu/ssp_defs.h create mode 100644 intern/opennl/superlu/strsv.c create mode 100644 intern/opennl/superlu/superlu_timer.c create mode 100644 intern/opennl/superlu/supermatrix.h create mode 100644 intern/opennl/superlu/sutil.c create mode 100644 intern/opennl/superlu/util.c create mode 100644 intern/opennl/superlu/util.h create mode 100644 intern/opennl/superlu/xerbla.c create mode 100644 intern/string/CMakeLists.txt create mode 100644 intern/string/Makefile create mode 100644 intern/string/SConscript create mode 100644 intern/string/STR_HashedString.h create mode 100644 intern/string/STR_String.h create mode 100644 intern/string/intern/Makefile create mode 100644 intern/string/intern/STR_String.cpp create mode 100644 intern/string/make/msvc_6_0/string.dsp create mode 100644 intern/string/make/msvc_6_0/string.dsw create mode 100644 intern/string/make/msvc_7_0/string.sln create mode 100644 intern/string/make/msvc_7_0/string.vcproj create mode 100644 po/Makefile create mode 100644 projectfiles/blender/BLO_readblenfile/BLO_readblenfile.dsp create mode 100644 projectfiles/blender/BPY_python/BPY_python.dsp create mode 100644 projectfiles/blender/avi/BL_avi.dsp create mode 100644 projectfiles/blender/blender.dsp create mode 100644 projectfiles/blender/blender.dsw create mode 100644 projectfiles/blender/blenkernel/BKE_blenkernel.dsp create mode 100644 projectfiles/blender/blenlib/BLI_blenlib.dsp create mode 100644 projectfiles/blender/blenpluginapi/blenpluginapi/blenpluginapi.dsp create mode 100644 projectfiles/blender/ftfont/FTF_ftfont.dsp create mode 100644 projectfiles/blender/glut/BL_glut.dsp create mode 100644 projectfiles/blender/imbuf/BL_imbuf.dsp create mode 100644 projectfiles/blender/img/BL_img.dsp create mode 100644 projectfiles/blender/loader/BLO_loader.dsp create mode 100644 projectfiles/blender/makesdna/DNA_makesdna.dsp create mode 100644 projectfiles/blender/radiosity/BRA_radiosity.dsp create mode 100644 projectfiles/blender/render/BRE_render.dsp create mode 100644 projectfiles/blender/renderconverter/BRE_renderconverter.dsp create mode 100644 projectfiles/blender/src/BL_src.dsp create mode 100644 projectfiles/blender/src/BL_src_cre.dsp create mode 100644 projectfiles/blender/yafray/BRE_yafray.dsp create mode 100644 projectfiles/datatoc/datatoc.dsp create mode 100644 projectfiles/gameengine/blenderhook/KX_blenderhook.dsp create mode 100644 projectfiles/gameengine/converter/KX_converter.dsp create mode 100644 projectfiles/gameengine/expression/EXP_expressions.dsp create mode 100644 projectfiles/gameengine/gamelogic/SCA_gamelogic.dsp create mode 100644 projectfiles/gameengine/gameplayer/axctl/GP_axctl.dsp create mode 100644 projectfiles/gameengine/gameplayer/common/GP_common.dsp create mode 100644 projectfiles/gameengine/gameplayer/ghost/GP_ghost.dsp create mode 100644 projectfiles/gameengine/gameplayer/glut/GP_glut.dsp create mode 100644 projectfiles/gameengine/gameplayer/loader/BlenderLoader/BlenderLoader.dsp create mode 100644 projectfiles/gameengine/gameplayer/netscape/GP_netscape.dsp create mode 100644 projectfiles/gameengine/gameplayer/netscape2/GP_netscape.dsp create mode 100644 projectfiles/gameengine/gameplayer/ps2/GP_ps2.dsp create mode 100644 projectfiles/gameengine/gameplayer/qt/gp.dsp create mode 100644 projectfiles/gameengine/gameplayer/qt/gpplugin.dsp create mode 100644 projectfiles/gameengine/gameplayer/qt/qtgp.dsw create mode 100644 projectfiles/gameengine/gameplayer/sdl/GP_sdl.dsp create mode 100644 projectfiles/gameengine/ketsji/KX_ketsji.dsp create mode 100644 projectfiles/gameengine/ketsji/network/KX_network.dsp create mode 100644 projectfiles/gameengine/network/loopbacknetwork/NG_loopbacknetwork.dsp create mode 100644 projectfiles/gameengine/network/network/NG_network.dsp create mode 100644 projectfiles/gameengine/network/terraplaynetwork/NG_terraplaynetwork.dsp create mode 100644 projectfiles/gameengine/physics/PHY_Physics/PHY_Dummy/PHY_Dummy.dsp create mode 100644 projectfiles/gameengine/physics/PHY_Physics/PHY_Ode/PHY_Ode.dsp create mode 100644 projectfiles/gameengine/physics/PHY_Physics/PHY_Physics.dsp create mode 100644 projectfiles/gameengine/physics/PHY_Physics/PHY_Sumo/PHY_Sumo.dsp create mode 100644 projectfiles/gameengine/rasterizer/RAS_rasterizer.dsp create mode 100644 projectfiles/gameengine/rasterizer/openglrasterizer/RAS_openglrasterizer.dsp create mode 100644 projectfiles/gameengine/scenegraph/SG_scenegraph.dsp create mode 100644 projectfiles/kernel/gen_messaging/gen_messaging.dsp create mode 100644 projectfiles/kernel/system/SYS_system.dsp create mode 100644 projectfiles/sumo/fuzzics/SM_fuzzics.dsp create mode 100644 projectfiles/sumo/moto/SM_moto.dsp create mode 100644 projectfiles/sumo/solid/SM_solid.dsp create mode 100644 projectfiles_vc7/blender/BLO_readblenfile/BLO_readblenfile.vcproj create mode 100644 projectfiles_vc7/blender/BPY_python/BPY_python.vcproj create mode 100644 projectfiles_vc7/blender/avi/BL_avi.vcproj create mode 100644 projectfiles_vc7/blender/blender.sln create mode 100644 projectfiles_vc7/blender/blender.vcproj create mode 100644 projectfiles_vc7/blender/blendercompact.sln create mode 100644 projectfiles_vc7/blender/blendercompactNG.vcproj create mode 100644 projectfiles_vc7/blender/blenkernel/BKE_blenkernel.vcproj create mode 100644 projectfiles_vc7/blender/blenlib/BLI_blenlib.vcproj create mode 100644 projectfiles_vc7/blender/blenpluginapi/blenpluginapi/blenpluginapi.vcproj create mode 100644 projectfiles_vc7/blender/ftfont/FTF_ftfont.vcproj create mode 100644 projectfiles_vc7/blender/imbuf/BL_imbuf.vcproj create mode 100644 projectfiles_vc7/blender/img/BL_img.vcproj create mode 100644 projectfiles_vc7/blender/loader/BLO_loader.vcproj create mode 100644 projectfiles_vc7/blender/makesdna/DNA_makesdna.vcproj create mode 100644 projectfiles_vc7/blender/makesdnacompact.vcproj create mode 100644 projectfiles_vc7/blender/nodes/nodes.vcproj create mode 100644 projectfiles_vc7/blender/radiosity/BRA_radiosity.vcproj create mode 100644 projectfiles_vc7/blender/render/BRE_render.vcproj create mode 100644 projectfiles_vc7/blender/renderconverter/BRE_renderconverter.vcproj create mode 100644 projectfiles_vc7/blender/src/BL_src.vcproj create mode 100644 projectfiles_vc7/blender/src/BL_src_cre.vcproj create mode 100644 projectfiles_vc7/blender/yafray/BRE_yafray.vcproj create mode 100644 projectfiles_vc7/gameengine/blenderhook/KX_blenderhook.vcproj create mode 100644 projectfiles_vc7/gameengine/converter/KX_converter.vcproj create mode 100644 projectfiles_vc7/gameengine/expression/EXP_expressions.vcproj create mode 100644 projectfiles_vc7/gameengine/gamelogic/SCA_GameLogic.vcproj create mode 100644 projectfiles_vc7/gameengine/gameplayer/axctl/GP_axctl.vcproj create mode 100644 projectfiles_vc7/gameengine/gameplayer/common/GP_common.vcproj create mode 100644 projectfiles_vc7/gameengine/gameplayer/ghost/GP_ghost.vcproj create mode 100644 projectfiles_vc7/gameengine/ketsji/KX_ketsji.vcproj create mode 100644 projectfiles_vc7/gameengine/ketsji/network/KX_network.vcproj create mode 100644 projectfiles_vc7/gameengine/network/loopbacknetwork/NG_loopbacknetwork.vcproj create mode 100644 projectfiles_vc7/gameengine/network/network/NG_network.vcproj create mode 100644 projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Bullet/PHY_Bullet.vcproj create mode 100644 projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Dummy/PHY_Dummy.vcproj create mode 100644 projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Ode/PHY_Ode.vcproj create mode 100644 projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Physics.vcproj create mode 100644 projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Sumo/PHY_Sumo.vcproj create mode 100644 projectfiles_vc7/gameengine/rasterizer/RAS_rasterizer.vcproj create mode 100644 projectfiles_vc7/gameengine/rasterizer/openglrasterizer/RAS_openglrasterizer.vcproj create mode 100644 projectfiles_vc7/gameengine/scenegraph/SG_SceneGraph.vcproj create mode 100644 projectfiles_vc7/kernel/gen_messaging/gen_messaging.vcproj create mode 100644 projectfiles_vc7/kernel/system/SYS_system.vcproj create mode 100644 projectfiles_vc7/sumo/fuzzics/SM_fuzzics.vcproj create mode 100644 projectfiles_vc7/sumo/fuzzics/fuzzics.vcproj create mode 100644 projectfiles_vc7/sumo/moto/SM_moto.dsp create mode 100644 projectfiles_vc7/sumo/solid/SM_solid.dsp create mode 100644 release/Makefile create mode 100644 release/VERSION create mode 100644 release/beos-4.5-i386/specific.sh create mode 100644 release/beos-5.0-i386/specific.sh create mode 100644 release/datafiles/.Bfont create mode 100644 release/datafiles/.Bfs create mode 100644 release/datafiles/DejaVuSans-Lite.sfd.bz2 create mode 100644 release/datafiles/LICENSE-bfont.ttf.txt create mode 100644 release/datafiles/bfont.ttf create mode 100644 release/datafiles/blenderbuttons create mode 100644 release/datafiles/datatoc.c create mode 100644 release/datafiles/preview.blend create mode 100644 release/datafiles/prvicons create mode 100644 release/datafiles/splash.jpg create mode 100644 release/freedesktop/icons/16x16/blender.png create mode 100644 release/freedesktop/icons/16x16/blender.xcf.bz2 create mode 100644 release/freedesktop/icons/22x22/blender.png create mode 100644 release/freedesktop/icons/22x22/blender.xcf.bz2 create mode 100644 release/freedesktop/icons/32x32/blender.png create mode 100644 release/freedesktop/icons/32x32/blender.svg create mode 100644 release/freedesktop/icons/scalable/blender.svg create mode 100644 release/irix-6.2-mips/extra/blender.icon create mode 100644 release/irix-6.2-mips/specific.sh create mode 100644 release/plugins/Makefile create mode 100644 release/plugins/bmake create mode 100644 release/plugins/sequence/Makefile create mode 100644 release/plugins/sequence/blur.c create mode 100644 release/plugins/sequence/color-correction-hsv.c create mode 100644 release/plugins/sequence/color-correction-yuv.c create mode 100644 release/plugins/sequence/dnr.c create mode 100644 release/plugins/sequence/gamma.c create mode 100644 release/plugins/sequence/scatter.c create mode 100644 release/plugins/texture/Makefile create mode 100644 release/plugins/texture/clouds2.c create mode 100644 release/plugins/texture/tiles.c create mode 100644 release/scripts/3ds_export.py create mode 100644 release/scripts/3ds_import.py create mode 100644 release/scripts/Axiscopy.py create mode 100644 release/scripts/DirectX8Exporter.py create mode 100644 release/scripts/DirectX8Importer.py create mode 100644 release/scripts/IDPropBrowser.py create mode 100644 release/scripts/ac3d_export.py create mode 100644 release/scripts/ac3d_import.py create mode 100644 release/scripts/add_mesh_empty.py create mode 100644 release/scripts/add_mesh_torus.py create mode 100644 release/scripts/animation_trajectory.py create mode 100644 release/scripts/armature_symmetry.py create mode 100644 release/scripts/bevel_center.py create mode 100644 release/scripts/blenderLipSynchro.py create mode 100644 release/scripts/bpydata/KUlang.txt create mode 100644 release/scripts/bpydata/config/readme.txt create mode 100644 release/scripts/bpydata/readme.txt create mode 100644 release/scripts/bpymodules/BPyAddMesh.py create mode 100644 release/scripts/bpymodules/BPyArmature.py create mode 100644 release/scripts/bpymodules/BPyBlender.py create mode 100644 release/scripts/bpymodules/BPyCurve.py create mode 100644 release/scripts/bpymodules/BPyImage.py create mode 100644 release/scripts/bpymodules/BPyMathutils.py create mode 100644 release/scripts/bpymodules/BPyMesh.py create mode 100644 release/scripts/bpymodules/BPyMesh_octree.py create mode 100644 release/scripts/bpymodules/BPyMesh_redux.py create mode 100644 release/scripts/bpymodules/BPyMessages.py create mode 100644 release/scripts/bpymodules/BPyNMesh.py create mode 100644 release/scripts/bpymodules/BPyObject.py create mode 100644 release/scripts/bpymodules/BPyRegistry.py create mode 100644 release/scripts/bpymodules/BPyRender.py create mode 100644 release/scripts/bpymodules/BPySys.py create mode 100644 release/scripts/bpymodules/BPyWindow.py create mode 100644 release/scripts/bpymodules/defaultdoodads.py create mode 100644 release/scripts/bpymodules/dxfColorMap.py create mode 100644 release/scripts/bpymodules/dxfImportObjects.py create mode 100644 release/scripts/bpymodules/dxfReader.py create mode 100644 release/scripts/bpymodules/mesh_gradient.py create mode 100644 release/scripts/bpymodules/meshtools.py create mode 100644 release/scripts/bpymodules/paths_ai2obj.py create mode 100644 release/scripts/bpymodules/paths_eps2obj.py create mode 100644 release/scripts/bpymodules/paths_gimp2obj.py create mode 100644 release/scripts/bpymodules/paths_svg2obj.py create mode 100644 release/scripts/bvh_import.py create mode 100644 release/scripts/camera_changer.py create mode 100644 release/scripts/config.py create mode 100644 release/scripts/console.py create mode 100644 release/scripts/discombobulator.py create mode 100644 release/scripts/envelope_symmetry.py create mode 100644 release/scripts/export-iv-0.1.py create mode 100644 release/scripts/export_cal3d.py create mode 100644 release/scripts/export_fbx.py create mode 100644 release/scripts/export_lightwave_motion.py create mode 100644 release/scripts/export_m3g.py create mode 100644 release/scripts/export_map.py create mode 100644 release/scripts/export_mdd.py create mode 100644 release/scripts/export_obj.py create mode 100644 release/scripts/faceselect_same_weights.py create mode 100644 release/scripts/flt_export.py create mode 100644 release/scripts/flt_filewalker.py create mode 100644 release/scripts/flt_import.py create mode 100644 release/scripts/help_bpy_api.py create mode 100644 release/scripts/help_browser.py create mode 100644 release/scripts/help_getting_started.py create mode 100644 release/scripts/help_manual.py create mode 100644 release/scripts/help_release_notes.py create mode 100644 release/scripts/help_tutorials.py create mode 100644 release/scripts/help_web_blender.py create mode 100644 release/scripts/help_web_devcomm.py create mode 100644 release/scripts/help_web_eshop.py create mode 100644 release/scripts/help_web_usercomm.py create mode 100644 release/scripts/hotkeys.py create mode 100644 release/scripts/image_auto_layout.py create mode 100644 release/scripts/image_billboard.py create mode 100644 release/scripts/image_edit.py create mode 100644 release/scripts/image_find_paths.py create mode 100644 release/scripts/import_dxf.py create mode 100644 release/scripts/import_mdd.py create mode 100644 release/scripts/import_obj.py create mode 100644 release/scripts/lightwave_export.py create mode 100644 release/scripts/lightwave_import.py create mode 100644 release/scripts/md2_export.py create mode 100644 release/scripts/md2_import.py create mode 100644 release/scripts/mesh_boneweight_copy.py create mode 100644 release/scripts/mesh_cleanup.py create mode 100644 release/scripts/mesh_edges2curves.py create mode 100644 release/scripts/mesh_mirror_tool.py create mode 100644 release/scripts/mesh_poly_reduce.py create mode 100644 release/scripts/mesh_skin.py create mode 100644 release/scripts/mesh_solidify.py create mode 100644 release/scripts/mesh_unfolder.py create mode 100644 release/scripts/mesh_wire.py create mode 100644 release/scripts/obdatacopier.py create mode 100644 release/scripts/object_apply_def.py create mode 100644 release/scripts/object_batch_name_edit.py create mode 100644 release/scripts/object_cookie_cutter.py create mode 100644 release/scripts/object_drop.py create mode 100644 release/scripts/object_find.py create mode 100644 release/scripts/object_random_loc_sz_rot.py create mode 100644 release/scripts/object_sel2dupgroup.py create mode 100644 release/scripts/off_export.py create mode 100644 release/scripts/off_import.py create mode 100644 release/scripts/paths_import.py create mode 100644 release/scripts/ply_export.py create mode 100644 release/scripts/ply_import.py create mode 100644 release/scripts/raw_export.py create mode 100644 release/scripts/raw_import.py create mode 100644 release/scripts/renameobjectbyblock.py create mode 100644 release/scripts/rvk1_torvk2.py create mode 100644 release/scripts/save_theme.py create mode 100644 release/scripts/scripttemplate_mesh_edit.py create mode 100644 release/scripts/scripttemplate_object_edit.py create mode 100644 release/scripts/scripttemplate_pyconstraint.py create mode 100644 release/scripts/slp_import.py create mode 100644 release/scripts/sysinfo.py create mode 100644 release/scripts/unweld.py create mode 100644 release/scripts/uv_export.py create mode 100644 release/scripts/uv_from_adjacent.py create mode 100644 release/scripts/uv_seams_from_islands.py create mode 100644 release/scripts/uvcalc_follow_active_coords.py create mode 100644 release/scripts/uvcalc_lightmap.py create mode 100644 release/scripts/uvcalc_quad_clickproj.py create mode 100644 release/scripts/uvcalc_smart_project.py create mode 100644 release/scripts/uvcopy.py create mode 100644 release/scripts/vertexpaint_from_material.py create mode 100644 release/scripts/vertexpaint_gradient.py create mode 100644 release/scripts/vertexpaint_selfshadow_ao.py create mode 100644 release/scripts/vrml97_export.py create mode 100644 release/scripts/weightpaint_average.py create mode 100644 release/scripts/weightpaint_clean.py create mode 100644 release/scripts/weightpaint_copy.py create mode 100644 release/scripts/weightpaint_envelope_assign.py create mode 100644 release/scripts/weightpaint_gradient.py create mode 100644 release/scripts/weightpaint_grow_shrink.py create mode 100644 release/scripts/weightpaint_normalize.py create mode 100644 release/scripts/widgetwizard.py create mode 100644 release/scripts/x3d_export.py create mode 100644 release/scripts/xfig_export.py create mode 100644 release/scripts/xsi_export.py create mode 100644 release/text/GPL-license.txt create mode 100644 release/text/Python-license.txt create mode 100644 release/text/blender.html create mode 100644 release/text/copyright.txt create mode 100644 release/windows/contrib/vfapi/README create mode 100644 release/windows/contrib/vfapi/vfapi-plugin.c create mode 100644 release/windows/extra/Help.url create mode 100644 release/windows/installer/00.blender.nsi create mode 100644 release/windows/installer/00.checked.bmp create mode 100644 release/windows/installer/00.header.bmp create mode 100644 release/windows/installer/00.installer.adx create mode 100644 release/windows/installer/00.installer.ico create mode 100644 release/windows/installer/00.sconsblender.nsi create mode 100644 release/windows/installer/00.unchecked.bmp create mode 100644 release/windows/installer/01.installer.bmp create mode 100644 release/windows/installer/01.welcome.rtf create mode 100644 release/windows/installer/02.copyright.txt create mode 100644 release/windows/installer/03.readme.txt create mode 100644 release/windows/installer/04.folder.rtf create mode 100644 release/windows/installer/05.progress.rtf create mode 100644 release/windows/installer/06.complete.rtf create mode 100644 release/windows/installer/data.ini create mode 100644 release/windows/installer/input/24bits-image.bmp create mode 100644 release/windows/publ_installer/00.installer.adx create mode 100644 release/windows/publ_installer/00.installer.ico create mode 100644 release/windows/publ_installer/01.installer.bmp create mode 100644 release/windows/publ_installer/01.welcome.rtf create mode 100644 release/windows/publ_installer/02.copyright.txt create mode 100644 release/windows/publ_installer/03.readme.txt create mode 100644 release/windows/publ_installer/04.folder.rtf create mode 100644 release/windows/publ_installer/05.progress.rtf create mode 100644 release/windows/publ_installer/06.complete.rtf create mode 100755 release/windows/specific.sh create mode 100644 source/CMakeLists.txt create mode 100644 source/Makefile create mode 100644 source/SConscript create mode 100644 source/blender/CMakeLists.txt create mode 100644 source/blender/Makefile create mode 100644 source/blender/SConscript create mode 100644 source/blender/avi/AVI_avi.h create mode 100644 source/blender/avi/CMakeLists.txt create mode 100644 source/blender/avi/Makefile create mode 100644 source/blender/avi/SConscript create mode 100644 source/blender/avi/intern/Makefile create mode 100644 source/blender/avi/intern/avi.c create mode 100644 source/blender/avi/intern/avi_intern.h create mode 100644 source/blender/avi/intern/avirgb.c create mode 100644 source/blender/avi/intern/avirgb.h create mode 100644 source/blender/avi/intern/codecs.c create mode 100644 source/blender/avi/intern/endian.c create mode 100644 source/blender/avi/intern/endian.h create mode 100644 source/blender/avi/intern/mjpeg.c create mode 100644 source/blender/avi/intern/mjpeg.h create mode 100644 source/blender/avi/intern/options.c create mode 100644 source/blender/avi/intern/rgb32.c create mode 100644 source/blender/avi/intern/rgb32.h create mode 100644 source/blender/blenkernel/BKE_DerivedMesh.h create mode 100644 source/blender/blenkernel/BKE_action.h create mode 100644 source/blender/blenkernel/BKE_anim.h create mode 100644 source/blender/blenkernel/BKE_armature.h create mode 100644 source/blender/blenkernel/BKE_bad_level_calls.h create mode 100644 source/blender/blenkernel/BKE_blender.h create mode 100644 source/blender/blenkernel/BKE_bmfont.h create mode 100644 source/blender/blenkernel/BKE_bmfont_types.h create mode 100644 source/blender/blenkernel/BKE_booleanops.h create mode 100644 source/blender/blenkernel/BKE_booleanops_mesh.h create mode 100644 source/blender/blenkernel/BKE_brush.h create mode 100644 source/blender/blenkernel/BKE_cdderivedmesh.h create mode 100644 source/blender/blenkernel/BKE_colortools.h create mode 100644 source/blender/blenkernel/BKE_constraint.h create mode 100644 source/blender/blenkernel/BKE_curve.h create mode 100644 source/blender/blenkernel/BKE_customdata.h create mode 100644 source/blender/blenkernel/BKE_deform.h create mode 100644 source/blender/blenkernel/BKE_depsgraph.h create mode 100644 source/blender/blenkernel/BKE_displist.h create mode 100644 source/blender/blenkernel/BKE_effect.h create mode 100644 source/blender/blenkernel/BKE_endian.h create mode 100644 source/blender/blenkernel/BKE_exotic.h create mode 100644 source/blender/blenkernel/BKE_font.h create mode 100644 source/blender/blenkernel/BKE_global.h create mode 100644 source/blender/blenkernel/BKE_group.h create mode 100644 source/blender/blenkernel/BKE_icons.h create mode 100644 source/blender/blenkernel/BKE_idprop.h create mode 100644 source/blender/blenkernel/BKE_image.h create mode 100644 source/blender/blenkernel/BKE_ipo.h create mode 100644 source/blender/blenkernel/BKE_key.h create mode 100644 source/blender/blenkernel/BKE_lattice.h create mode 100644 source/blender/blenkernel/BKE_library.h create mode 100644 source/blender/blenkernel/BKE_main.h create mode 100644 source/blender/blenkernel/BKE_material.h create mode 100644 source/blender/blenkernel/BKE_mball.h create mode 100644 source/blender/blenkernel/BKE_mesh.h create mode 100644 source/blender/blenkernel/BKE_modifier.h create mode 100644 source/blender/blenkernel/BKE_nla.h create mode 100644 source/blender/blenkernel/BKE_node.h create mode 100644 source/blender/blenkernel/BKE_object.h create mode 100644 source/blender/blenkernel/BKE_packedFile.h create mode 100644 source/blender/blenkernel/BKE_plugin_types.h create mode 100644 source/blender/blenkernel/BKE_property.h create mode 100644 source/blender/blenkernel/BKE_sca.h create mode 100644 source/blender/blenkernel/BKE_scene.h create mode 100644 source/blender/blenkernel/BKE_screen.h create mode 100644 source/blender/blenkernel/BKE_script.h create mode 100644 source/blender/blenkernel/BKE_softbody.h create mode 100644 source/blender/blenkernel/BKE_sound.h create mode 100644 source/blender/blenkernel/BKE_subsurf.h create mode 100644 source/blender/blenkernel/BKE_text.h create mode 100644 source/blender/blenkernel/BKE_texture.h create mode 100644 source/blender/blenkernel/BKE_utildefines.h create mode 100644 source/blender/blenkernel/BKE_verse.h create mode 100644 source/blender/blenkernel/BKE_world.h create mode 100644 source/blender/blenkernel/BKE_writeavi.h create mode 100644 source/blender/blenkernel/BKE_writeffmpeg.h create mode 100644 source/blender/blenkernel/BKE_writeframeserver.h create mode 100644 source/blender/blenkernel/CMakeLists.txt create mode 100644 source/blender/blenkernel/Makefile create mode 100644 source/blender/blenkernel/SConscript create mode 100644 source/blender/blenkernel/bad_level_call_stubs/CMakeLists.txt create mode 100644 source/blender/blenkernel/bad_level_call_stubs/Makefile create mode 100644 source/blender/blenkernel/bad_level_call_stubs/SConscript create mode 100644 source/blender/blenkernel/bad_level_call_stubs/stubs.c create mode 100644 source/blender/blenkernel/depsgraph_private.h create mode 100644 source/blender/blenkernel/intern/CCGSubSurf.c create mode 100644 source/blender/blenkernel/intern/CCGSubSurf.h create mode 100644 source/blender/blenkernel/intern/DerivedMesh.c create mode 100644 source/blender/blenkernel/intern/Makefile create mode 100644 source/blender/blenkernel/intern/action.c create mode 100644 source/blender/blenkernel/intern/anim.c create mode 100644 source/blender/blenkernel/intern/armature.c create mode 100644 source/blender/blenkernel/intern/blender.c create mode 100644 source/blender/blenkernel/intern/bmfont.c create mode 100644 source/blender/blenkernel/intern/brush.c create mode 100644 source/blender/blenkernel/intern/cdderivedmesh.c create mode 100644 source/blender/blenkernel/intern/colortools.c create mode 100644 source/blender/blenkernel/intern/constraint.c create mode 100644 source/blender/blenkernel/intern/curve.c create mode 100644 source/blender/blenkernel/intern/customdata.c create mode 100644 source/blender/blenkernel/intern/deform.c create mode 100644 source/blender/blenkernel/intern/depsgraph.c create mode 100644 source/blender/blenkernel/intern/displist.c create mode 100644 source/blender/blenkernel/intern/effect.c create mode 100644 source/blender/blenkernel/intern/exotic.c create mode 100644 source/blender/blenkernel/intern/font.c create mode 100644 source/blender/blenkernel/intern/group.c create mode 100644 source/blender/blenkernel/intern/icons.c create mode 100644 source/blender/blenkernel/intern/idprop.c create mode 100644 source/blender/blenkernel/intern/image.c create mode 100644 source/blender/blenkernel/intern/ipo.c create mode 100644 source/blender/blenkernel/intern/key.c create mode 100644 source/blender/blenkernel/intern/lattice.c create mode 100644 source/blender/blenkernel/intern/library.c create mode 100644 source/blender/blenkernel/intern/material.c create mode 100644 source/blender/blenkernel/intern/mball.c create mode 100644 source/blender/blenkernel/intern/mesh.c create mode 100644 source/blender/blenkernel/intern/modifier.c create mode 100644 source/blender/blenkernel/intern/nla.c create mode 100644 source/blender/blenkernel/intern/node.c create mode 100644 source/blender/blenkernel/intern/object.c create mode 100644 source/blender/blenkernel/intern/packedFile.c create mode 100644 source/blender/blenkernel/intern/property.c create mode 100644 source/blender/blenkernel/intern/sca.c create mode 100644 source/blender/blenkernel/intern/scene.c create mode 100644 source/blender/blenkernel/intern/screen.c create mode 100644 source/blender/blenkernel/intern/script.c create mode 100644 source/blender/blenkernel/intern/softbody.c create mode 100644 source/blender/blenkernel/intern/sound.c create mode 100644 source/blender/blenkernel/intern/subsurf_ccg.c create mode 100644 source/blender/blenkernel/intern/text.c create mode 100644 source/blender/blenkernel/intern/texture.c create mode 100644 source/blender/blenkernel/intern/verse_bitmap_node.c create mode 100644 source/blender/blenkernel/intern/verse_geometry_node.c create mode 100644 source/blender/blenkernel/intern/verse_method.c create mode 100644 source/blender/blenkernel/intern/verse_node.c create mode 100644 source/blender/blenkernel/intern/verse_object_node.c create mode 100644 source/blender/blenkernel/intern/verse_session.c create mode 100644 source/blender/blenkernel/intern/world.c create mode 100644 source/blender/blenkernel/intern/writeavi.c create mode 100644 source/blender/blenkernel/intern/writeffmpeg.c create mode 100644 source/blender/blenkernel/intern/writeframeserver.c create mode 100644 source/blender/blenlib/BLI_arithb.h create mode 100644 source/blender/blenlib/BLI_blenlib.h create mode 100644 source/blender/blenlib/BLI_boxpack2d.h create mode 100644 source/blender/blenlib/BLI_dynamiclist.h create mode 100644 source/blender/blenlib/BLI_dynstr.h create mode 100644 source/blender/blenlib/BLI_edgehash.h create mode 100644 source/blender/blenlib/BLI_editVert.h create mode 100644 source/blender/blenlib/BLI_ghash.h create mode 100644 source/blender/blenlib/BLI_gsqueue.h create mode 100644 source/blender/blenlib/BLI_heap.h create mode 100644 source/blender/blenlib/BLI_jitter.h create mode 100644 source/blender/blenlib/BLI_linklist.h create mode 100644 source/blender/blenlib/BLI_memarena.h create mode 100644 source/blender/blenlib/BLI_rand.h create mode 100644 source/blender/blenlib/BLI_storage_types.h create mode 100644 source/blender/blenlib/BLI_threads.h create mode 100644 source/blender/blenlib/BLI_vfontdata.h create mode 100644 source/blender/blenlib/BLI_winstuff.h create mode 100644 source/blender/blenlib/CMakeLists.txt create mode 100644 source/blender/blenlib/MTC_matrixops.h create mode 100644 source/blender/blenlib/MTC_vectorops.h create mode 100644 source/blender/blenlib/Makefile create mode 100644 source/blender/blenlib/PIL_dynlib.h create mode 100644 source/blender/blenlib/PIL_time.h create mode 100644 source/blender/blenlib/SConscript create mode 100644 source/blender/blenlib/intern/BLI_callbacks.h create mode 100644 source/blender/blenlib/intern/BLI_dynstr.c create mode 100644 source/blender/blenlib/intern/BLI_fileops.h create mode 100644 source/blender/blenlib/intern/BLI_ghash.c create mode 100644 source/blender/blenlib/intern/BLI_heap.c create mode 100644 source/blender/blenlib/intern/BLI_linklist.c create mode 100644 source/blender/blenlib/intern/BLI_memarena.c create mode 100644 source/blender/blenlib/intern/BLI_scanfill.h create mode 100644 source/blender/blenlib/intern/BLI_storage.h create mode 100644 source/blender/blenlib/intern/BLI_util.h create mode 100644 source/blender/blenlib/intern/Makefile create mode 100644 source/blender/blenlib/intern/arithb.c create mode 100644 source/blender/blenlib/intern/boxpack2d.c create mode 100644 source/blender/blenlib/intern/dynlib.c create mode 100644 source/blender/blenlib/intern/edgehash.c create mode 100644 source/blender/blenlib/intern/fileops.c create mode 100644 source/blender/blenlib/intern/freetypefont.c create mode 100644 source/blender/blenlib/intern/gsqueue.c create mode 100644 source/blender/blenlib/intern/jitter.c create mode 100644 source/blender/blenlib/intern/matrixops.c create mode 100644 source/blender/blenlib/intern/noise.c create mode 100644 source/blender/blenlib/intern/psfont.c create mode 100644 source/blender/blenlib/intern/rand.c create mode 100644 source/blender/blenlib/intern/rct.c create mode 100644 source/blender/blenlib/intern/scanfill.c create mode 100644 source/blender/blenlib/intern/storage.c create mode 100644 source/blender/blenlib/intern/threads.c create mode 100644 source/blender/blenlib/intern/time.c create mode 100644 source/blender/blenlib/intern/util.c create mode 100644 source/blender/blenlib/intern/vectorops.c create mode 100644 source/blender/blenlib/intern/winstuff.c create mode 100644 source/blender/blenloader/BLO_genfile.h create mode 100644 source/blender/blenloader/BLO_readfile.h create mode 100644 source/blender/blenloader/BLO_soundfile.h create mode 100644 source/blender/blenloader/BLO_sys_types.h create mode 100644 source/blender/blenloader/BLO_undofile.h create mode 100644 source/blender/blenloader/BLO_writefile.h create mode 100644 source/blender/blenloader/CMakeLists.txt create mode 100644 source/blender/blenloader/Makefile create mode 100644 source/blender/blenloader/SConscript create mode 100644 source/blender/blenloader/intern/Makefile create mode 100644 source/blender/blenloader/intern/genfile.c create mode 100644 source/blender/blenloader/intern/genfile.h create mode 100644 source/blender/blenloader/intern/readblenentry.c create mode 100644 source/blender/blenloader/intern/readfile.c create mode 100644 source/blender/blenloader/intern/readfile.h create mode 100644 source/blender/blenloader/intern/undofile.c create mode 100644 source/blender/blenloader/intern/writefile.c create mode 100644 source/blender/blenpluginapi/CMakeLists.txt create mode 100644 source/blender/blenpluginapi/Makefile create mode 100644 source/blender/blenpluginapi/SConscript create mode 100644 source/blender/blenpluginapi/documentation.h create mode 100644 source/blender/blenpluginapi/externdef.h create mode 100644 source/blender/blenpluginapi/floatpatch.h create mode 100644 source/blender/blenpluginapi/iff.h create mode 100644 source/blender/blenpluginapi/intern/Makefile create mode 100644 source/blender/blenpluginapi/intern/pluginapi.c create mode 100644 source/blender/blenpluginapi/plugin.DEF create mode 100644 source/blender/blenpluginapi/plugin.h create mode 100644 source/blender/blenpluginapi/util.h create mode 100644 source/blender/ftfont/CMakeLists.txt create mode 100644 source/blender/ftfont/FTF_Api.h create mode 100644 source/blender/ftfont/FTF_Settings.h create mode 100644 source/blender/ftfont/Makefile create mode 100644 source/blender/ftfont/SConscript create mode 100644 source/blender/ftfont/intern/FTF_Api.cpp create mode 100644 source/blender/ftfont/intern/FTF_TTFont.cpp create mode 100644 source/blender/ftfont/intern/FTF_TTFont.h create mode 100644 source/blender/ftfont/intern/Makefile create mode 100644 source/blender/imbuf/CMakeLists.txt create mode 100644 source/blender/imbuf/IMB_imbuf.h create mode 100644 source/blender/imbuf/IMB_imbuf_types.h create mode 100644 source/blender/imbuf/IMB_thumbs.h create mode 100644 source/blender/imbuf/Makefile create mode 100644 source/blender/imbuf/SConscript create mode 100644 source/blender/imbuf/intern/IMB_allocimbuf.h create mode 100644 source/blender/imbuf/intern/IMB_amiga.h create mode 100644 source/blender/imbuf/intern/IMB_anim.h create mode 100644 source/blender/imbuf/intern/IMB_anim5.h create mode 100644 source/blender/imbuf/intern/IMB_bitplanes.h create mode 100644 source/blender/imbuf/intern/IMB_bmp.h create mode 100644 source/blender/imbuf/intern/IMB_cmap.h create mode 100644 source/blender/imbuf/intern/IMB_divers.h create mode 100644 source/blender/imbuf/intern/IMB_dpxcineon.h create mode 100644 source/blender/imbuf/intern/IMB_filter.h create mode 100644 source/blender/imbuf/intern/IMB_ham.h create mode 100644 source/blender/imbuf/intern/IMB_hamx.h create mode 100644 source/blender/imbuf/intern/IMB_iff.h create mode 100644 source/blender/imbuf/intern/IMB_imginfo.h create mode 100644 source/blender/imbuf/intern/IMB_iris.h create mode 100644 source/blender/imbuf/intern/IMB_jpeg.h create mode 100644 source/blender/imbuf/intern/IMB_png.h create mode 100644 source/blender/imbuf/intern/IMB_radiance_hdr.h create mode 100644 source/blender/imbuf/intern/IMB_targa.h create mode 100644 source/blender/imbuf/intern/IMB_tiff.h create mode 100644 source/blender/imbuf/intern/Makefile create mode 100644 source/blender/imbuf/intern/allocimbuf.c create mode 100644 source/blender/imbuf/intern/amiga.c create mode 100644 source/blender/imbuf/intern/anim.c create mode 100644 source/blender/imbuf/intern/anim5.c create mode 100644 source/blender/imbuf/intern/antialias.c create mode 100644 source/blender/imbuf/intern/bitplanes.c create mode 100644 source/blender/imbuf/intern/bmp.c create mode 100644 source/blender/imbuf/intern/cineon/CMakeLists.txt create mode 100644 source/blender/imbuf/intern/cineon/Makefile create mode 100644 source/blender/imbuf/intern/cineon/README create mode 100644 source/blender/imbuf/intern/cineon/SConscript create mode 100644 source/blender/imbuf/intern/cineon/cin_debug_stuff.h create mode 100644 source/blender/imbuf/intern/cineon/cineon_dpx.c create mode 100644 source/blender/imbuf/intern/cineon/cineonfile.h create mode 100644 source/blender/imbuf/intern/cineon/cineonlib.c create mode 100644 source/blender/imbuf/intern/cineon/cineonlib.h create mode 100644 source/blender/imbuf/intern/cineon/dpxfile.h create mode 100644 source/blender/imbuf/intern/cineon/dpxlib.c create mode 100644 source/blender/imbuf/intern/cineon/dpxlib.h create mode 100644 source/blender/imbuf/intern/cineon/logImageCore.c create mode 100644 source/blender/imbuf/intern/cineon/logImageCore.h create mode 100644 source/blender/imbuf/intern/cineon/logImageLib.c create mode 100644 source/blender/imbuf/intern/cineon/logImageLib.h create mode 100644 source/blender/imbuf/intern/cineon/logmemfile.c create mode 100644 source/blender/imbuf/intern/cineon/logmemfile.h create mode 100644 source/blender/imbuf/intern/cmap.c create mode 100644 source/blender/imbuf/intern/cspace.c create mode 100644 source/blender/imbuf/intern/data.c create mode 100644 source/blender/imbuf/intern/dds/BlockDXT.cpp create mode 100644 source/blender/imbuf/intern/dds/BlockDXT.h create mode 100644 source/blender/imbuf/intern/dds/Color.h create mode 100644 source/blender/imbuf/intern/dds/ColorBlock.cpp create mode 100644 source/blender/imbuf/intern/dds/ColorBlock.h create mode 100644 source/blender/imbuf/intern/dds/Common.h create mode 100644 source/blender/imbuf/intern/dds/DirectDrawSurface.cpp create mode 100644 source/blender/imbuf/intern/dds/DirectDrawSurface.h create mode 100644 source/blender/imbuf/intern/dds/Image.cpp create mode 100644 source/blender/imbuf/intern/dds/Image.h create mode 100644 source/blender/imbuf/intern/dds/Makefile create mode 100644 source/blender/imbuf/intern/dds/SConscript create mode 100644 source/blender/imbuf/intern/dds/Stream.cpp create mode 100644 source/blender/imbuf/intern/dds/Stream.h create mode 100644 source/blender/imbuf/intern/dds/dds_api.cpp create mode 100644 source/blender/imbuf/intern/dds/dds_api.h create mode 100644 source/blender/imbuf/intern/dither.c create mode 100644 source/blender/imbuf/intern/divers.c create mode 100644 source/blender/imbuf/intern/dynlibtiff.c create mode 100644 source/blender/imbuf/intern/dynlibtiff.h create mode 100644 source/blender/imbuf/intern/filter.c create mode 100755 source/blender/imbuf/intern/gen_dynlibtiff.py create mode 100644 source/blender/imbuf/intern/ham.c create mode 100644 source/blender/imbuf/intern/hamx.c create mode 100644 source/blender/imbuf/intern/iff.c create mode 100644 source/blender/imbuf/intern/imageprocess.c create mode 100644 source/blender/imbuf/intern/imbuf.h create mode 100644 source/blender/imbuf/intern/imbuf_patch.h create mode 100644 source/blender/imbuf/intern/imginfo.c create mode 100644 source/blender/imbuf/intern/iris.c create mode 100644 source/blender/imbuf/intern/jpeg.c create mode 100644 source/blender/imbuf/intern/matrix.h create mode 100644 source/blender/imbuf/intern/md5.c create mode 100644 source/blender/imbuf/intern/md5.h create mode 100644 source/blender/imbuf/intern/openexr/CMakeLists.txt create mode 100644 source/blender/imbuf/intern/openexr/Makefile create mode 100644 source/blender/imbuf/intern/openexr/SConscript create mode 100644 source/blender/imbuf/intern/openexr/openexr_api.cpp create mode 100644 source/blender/imbuf/intern/openexr/openexr_api.h create mode 100644 source/blender/imbuf/intern/openexr/openexr_multi.h create mode 100644 source/blender/imbuf/intern/png.c create mode 100644 source/blender/imbuf/intern/radiance_hdr.c create mode 100644 source/blender/imbuf/intern/readimage.c create mode 100644 source/blender/imbuf/intern/rectop.c create mode 100644 source/blender/imbuf/intern/rotate.c create mode 100644 source/blender/imbuf/intern/scaling.c create mode 100644 source/blender/imbuf/intern/targa.c create mode 100644 source/blender/imbuf/intern/thumbs.c create mode 100644 source/blender/imbuf/intern/tiff.c create mode 100644 source/blender/imbuf/intern/util.c create mode 100644 source/blender/imbuf/intern/writeimage.c create mode 100644 source/blender/imbuf/readme.txt create mode 100644 source/blender/include/BDR_drawaction.h create mode 100644 source/blender/include/BDR_drawmesh.h create mode 100644 source/blender/include/BDR_drawobject.h create mode 100644 source/blender/include/BDR_editcurve.h create mode 100644 source/blender/include/BDR_editface.h create mode 100644 source/blender/include/BDR_editmball.h create mode 100644 source/blender/include/BDR_editobject.h create mode 100644 source/blender/include/BDR_imagepaint.h create mode 100644 source/blender/include/BDR_sculptmode.h create mode 100644 source/blender/include/BDR_unwrapper.h create mode 100644 source/blender/include/BDR_vpaint.h create mode 100644 source/blender/include/BIF_butspace.h create mode 100644 source/blender/include/BIF_cursors.h create mode 100644 source/blender/include/BIF_drawimage.h create mode 100644 source/blender/include/BIF_drawoops.h create mode 100644 source/blender/include/BIF_drawscene.h create mode 100644 source/blender/include/BIF_drawscript.h create mode 100644 source/blender/include/BIF_drawseq.h create mode 100644 source/blender/include/BIF_drawtext.h create mode 100644 source/blender/include/BIF_editaction.h create mode 100644 source/blender/include/BIF_editarmature.h create mode 100644 source/blender/include/BIF_editconstraint.h create mode 100644 source/blender/include/BIF_editdeform.h create mode 100644 source/blender/include/BIF_editfont.h create mode 100644 source/blender/include/BIF_editgroup.h create mode 100644 source/blender/include/BIF_editkey.h create mode 100644 source/blender/include/BIF_editlattice.h create mode 100644 source/blender/include/BIF_editmesh.h create mode 100644 source/blender/include/BIF_editmode_undo.h create mode 100644 source/blender/include/BIF_editnla.h create mode 100644 source/blender/include/BIF_editoops.h create mode 100644 source/blender/include/BIF_editsca.h create mode 100644 source/blender/include/BIF_editseq.h create mode 100644 source/blender/include/BIF_editsima.h create mode 100644 source/blender/include/BIF_editsound.h create mode 100644 source/blender/include/BIF_editview.h create mode 100644 source/blender/include/BIF_filelist.h create mode 100644 source/blender/include/BIF_fsmenu.h create mode 100644 source/blender/include/BIF_gl.h create mode 100644 source/blender/include/BIF_glutil.h create mode 100644 source/blender/include/BIF_graphics.h create mode 100644 source/blender/include/BIF_imasel.h create mode 100644 source/blender/include/BIF_interface.h create mode 100644 source/blender/include/BIF_interface_icons.h create mode 100644 source/blender/include/BIF_keyval.h create mode 100644 source/blender/include/BIF_language.h create mode 100644 source/blender/include/BIF_mainqueue.h create mode 100644 source/blender/include/BIF_meshlaplacian.h create mode 100644 source/blender/include/BIF_meshtools.h create mode 100644 source/blender/include/BIF_mywindow.h create mode 100644 source/blender/include/BIF_oops.h create mode 100644 source/blender/include/BIF_outliner.h create mode 100644 source/blender/include/BIF_poseobject.h create mode 100644 source/blender/include/BIF_previewrender.h create mode 100644 source/blender/include/BIF_renderwin.h create mode 100644 source/blender/include/BIF_resources.h create mode 100644 source/blender/include/BIF_retopo.h create mode 100644 source/blender/include/BIF_scrarea.h create mode 100644 source/blender/include/BIF_screen.h create mode 100644 source/blender/include/BIF_space.h create mode 100644 source/blender/include/BIF_spacetypes.h create mode 100644 source/blender/include/BIF_tbcallback.h create mode 100644 source/blender/include/BIF_toets.h create mode 100644 source/blender/include/BIF_toolbox.h create mode 100644 source/blender/include/BIF_transform.h create mode 100644 source/blender/include/BIF_usiblender.h create mode 100644 source/blender/include/BIF_verse.h create mode 100644 source/blender/include/BIF_writeavicodec.h create mode 100644 source/blender/include/BIF_writeimage.h create mode 100644 source/blender/include/BIF_writemovie.h create mode 100644 source/blender/include/BPI_script.h create mode 100644 source/blender/include/BSE_drawimasel.h create mode 100644 source/blender/include/BSE_drawipo.h create mode 100644 source/blender/include/BSE_drawnla.h create mode 100644 source/blender/include/BSE_drawoops.h create mode 100644 source/blender/include/BSE_drawview.h create mode 100644 source/blender/include/BSE_edit.h create mode 100644 source/blender/include/BSE_editaction_types.h create mode 100644 source/blender/include/BSE_editipo.h create mode 100644 source/blender/include/BSE_editipo_types.h create mode 100644 source/blender/include/BSE_editnla_types.h create mode 100644 source/blender/include/BSE_filesel.h create mode 100644 source/blender/include/BSE_headerbuttons.h create mode 100644 source/blender/include/BSE_node.h create mode 100644 source/blender/include/BSE_seqaudio.h create mode 100644 source/blender/include/BSE_seqeffects.h create mode 100644 source/blender/include/BSE_seqscopes.h create mode 100644 source/blender/include/BSE_sequence.h create mode 100644 source/blender/include/BSE_time.h create mode 100644 source/blender/include/BSE_trans_types.h create mode 100644 source/blender/include/BSE_types.h create mode 100644 source/blender/include/BSE_view.h create mode 100644 source/blender/include/LOD_DependKludge.h create mode 100644 source/blender/include/blendef.h create mode 100644 source/blender/include/butspace.h create mode 100644 source/blender/include/datatoc.h create mode 100644 source/blender/include/editlattice_ext.h create mode 100644 source/blender/include/editmesh.h create mode 100644 source/blender/include/interface.h create mode 100644 source/blender/include/keyed_functions.h create mode 100644 source/blender/include/license_key.h create mode 100644 source/blender/include/multires.h create mode 100644 source/blender/include/mydevice.h create mode 100644 source/blender/include/nla.h create mode 100644 source/blender/include/objfnt.h create mode 100644 source/blender/include/particle_effect.h create mode 100644 source/blender/include/playanim_ext.h create mode 100644 source/blender/include/transform.h create mode 100644 source/blender/makesdna/CMakeLists.txt create mode 100644 source/blender/makesdna/DNA_ID.h create mode 100644 source/blender/makesdna/DNA_action_types.h create mode 100644 source/blender/makesdna/DNA_actuator_types.h create mode 100644 source/blender/makesdna/DNA_armature_types.h create mode 100644 source/blender/makesdna/DNA_brush_types.h create mode 100644 source/blender/makesdna/DNA_camera_types.h create mode 100644 source/blender/makesdna/DNA_color_types.h create mode 100644 source/blender/makesdna/DNA_constraint_types.h create mode 100644 source/blender/makesdna/DNA_controller_types.h create mode 100644 source/blender/makesdna/DNA_curve_types.h create mode 100644 source/blender/makesdna/DNA_customdata_types.h create mode 100644 source/blender/makesdna/DNA_documentation.h create mode 100644 source/blender/makesdna/DNA_effect_types.h create mode 100644 source/blender/makesdna/DNA_fileglobal_types.h create mode 100644 source/blender/makesdna/DNA_group_types.h create mode 100644 source/blender/makesdna/DNA_image_types.h create mode 100644 source/blender/makesdna/DNA_ipo_types.h create mode 100644 source/blender/makesdna/DNA_key_types.h create mode 100644 source/blender/makesdna/DNA_lamp_types.h create mode 100644 source/blender/makesdna/DNA_lattice_types.h create mode 100644 source/blender/makesdna/DNA_listBase.h create mode 100644 source/blender/makesdna/DNA_material_types.h create mode 100644 source/blender/makesdna/DNA_mesh_types.h create mode 100644 source/blender/makesdna/DNA_meshdata_types.h create mode 100644 source/blender/makesdna/DNA_meta_types.h create mode 100644 source/blender/makesdna/DNA_modifier_types.h create mode 100644 source/blender/makesdna/DNA_nla_types.h create mode 100644 source/blender/makesdna/DNA_node_types.h create mode 100644 source/blender/makesdna/DNA_object_fluidsim.h create mode 100644 source/blender/makesdna/DNA_object_force.h create mode 100644 source/blender/makesdna/DNA_object_types.h create mode 100644 source/blender/makesdna/DNA_oops_types.h create mode 100644 source/blender/makesdna/DNA_packedFile_types.h create mode 100644 source/blender/makesdna/DNA_property_types.h create mode 100644 source/blender/makesdna/DNA_radio_types.h create mode 100644 source/blender/makesdna/DNA_scene_types.h create mode 100644 source/blender/makesdna/DNA_screen_types.h create mode 100644 source/blender/makesdna/DNA_scriptlink_types.h create mode 100644 source/blender/makesdna/DNA_sdna_types.h create mode 100644 source/blender/makesdna/DNA_sensor_types.h create mode 100644 source/blender/makesdna/DNA_sequence_types.h create mode 100644 source/blender/makesdna/DNA_sound_types.h create mode 100644 source/blender/makesdna/DNA_space_types.h create mode 100644 source/blender/makesdna/DNA_text_types.h create mode 100644 source/blender/makesdna/DNA_texture_types.h create mode 100644 source/blender/makesdna/DNA_userdef_types.h create mode 100644 source/blender/makesdna/DNA_vec_types.h create mode 100644 source/blender/makesdna/DNA_vfont_types.h create mode 100644 source/blender/makesdna/DNA_view2d_types.h create mode 100644 source/blender/makesdna/DNA_view3d_types.h create mode 100644 source/blender/makesdna/DNA_wave_types.h create mode 100644 source/blender/makesdna/DNA_world_types.h create mode 100644 source/blender/makesdna/Makefile create mode 100644 source/blender/makesdna/SConscript create mode 100644 source/blender/makesdna/intern/CMakeLists.txt create mode 100644 source/blender/makesdna/intern/Makefile create mode 100644 source/blender/makesdna/intern/SConscript create mode 100644 source/blender/makesdna/intern/makesdna.c create mode 100644 source/blender/nodes/CMP_node.h create mode 100644 source/blender/nodes/CMakeLists.txt create mode 100644 source/blender/nodes/Makefile create mode 100644 source/blender/nodes/SConscript create mode 100644 source/blender/nodes/SHD_node.h create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_alphaOver.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_blur.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_brightness.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_channelMatte.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_chromaMatte.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_colorSpill.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_composite.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_crop.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_curves.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_defocus.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_diffMatte.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_dilate.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_displace.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_filter.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_flip.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_gamma.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_glare.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_hueSatVal.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_idMask.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_image.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_invert.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_lensdist.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_lummaMatte.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_mapUV.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_mapValue.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_math.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_mixrgb.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_normal.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_normalize.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_outputFile.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_rgb.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_rotate.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_scale.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_sepcombHSVA.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_sepcombRGBA.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_sepcombYCCA.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_sepcombYUVA.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_setalpha.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_splitViewer.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_texture.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_tonemap.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_translate.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_valToRgb.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_value.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_vecBlur.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_viewer.c create mode 100644 source/blender/nodes/intern/CMP_nodes/CMP_zcombine.c create mode 100644 source/blender/nodes/intern/CMP_nodes/Makefile create mode 100644 source/blender/nodes/intern/CMP_util.c create mode 100644 source/blender/nodes/intern/CMP_util.h create mode 100644 source/blender/nodes/intern/Makefile create mode 100644 source/blender/nodes/intern/SHD_nodes/Makefile create mode 100644 source/blender/nodes/intern/SHD_nodes/SHD_camera.c create mode 100644 source/blender/nodes/intern/SHD_nodes/SHD_curves.c create mode 100644 source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c create mode 100644 source/blender/nodes/intern/SHD_nodes/SHD_geom.c create mode 100644 source/blender/nodes/intern/SHD_nodes/SHD_hueSatVal.c create mode 100644 source/blender/nodes/intern/SHD_nodes/SHD_invert.c create mode 100644 source/blender/nodes/intern/SHD_nodes/SHD_mapping.c create mode 100644 source/blender/nodes/intern/SHD_nodes/SHD_material.c create mode 100644 source/blender/nodes/intern/SHD_nodes/SHD_math.c create mode 100644 source/blender/nodes/intern/SHD_nodes/SHD_mixRgb.c create mode 100644 source/blender/nodes/intern/SHD_nodes/SHD_normal.c create mode 100644 source/blender/nodes/intern/SHD_nodes/SHD_output.c create mode 100644 source/blender/nodes/intern/SHD_nodes/SHD_rgb.c create mode 100644 source/blender/nodes/intern/SHD_nodes/SHD_sepcombRGB.c create mode 100644 source/blender/nodes/intern/SHD_nodes/SHD_squeeze.c create mode 100644 source/blender/nodes/intern/SHD_nodes/SHD_texture.c create mode 100644 source/blender/nodes/intern/SHD_nodes/SHD_valToRgb.c create mode 100644 source/blender/nodes/intern/SHD_nodes/SHD_value.c create mode 100644 source/blender/nodes/intern/SHD_nodes/SHD_vectMath.c create mode 100644 source/blender/nodes/intern/SHD_util.c create mode 100644 source/blender/nodes/intern/SHD_util.h create mode 100644 source/blender/nodes/intern/node_util.c create mode 100644 source/blender/nodes/intern/node_util.h create mode 100644 source/blender/python/BPY_extern.h create mode 100644 source/blender/python/BPY_interface.c create mode 100644 source/blender/python/BPY_menus.c create mode 100644 source/blender/python/BPY_menus.h create mode 100644 source/blender/python/CMakeLists.txt create mode 100644 source/blender/python/Makefile create mode 100644 source/blender/python/SConscript create mode 100644 source/blender/python/api2_2x/Armature.c create mode 100644 source/blender/python/api2_2x/Armature.h create mode 100644 source/blender/python/api2_2x/BGL.c create mode 100644 source/blender/python/api2_2x/BGL.h create mode 100644 source/blender/python/api2_2x/BezTriple.c create mode 100644 source/blender/python/api2_2x/BezTriple.h create mode 100644 source/blender/python/api2_2x/Blender.c create mode 100644 source/blender/python/api2_2x/Blender.h create mode 100644 source/blender/python/api2_2x/Bone.c create mode 100644 source/blender/python/api2_2x/Bone.h create mode 100644 source/blender/python/api2_2x/Camera.c create mode 100644 source/blender/python/api2_2x/Camera.h create mode 100644 source/blender/python/api2_2x/Constraint.c create mode 100644 source/blender/python/api2_2x/Constraint.h create mode 100644 source/blender/python/api2_2x/CurNurb.c create mode 100644 source/blender/python/api2_2x/CurNurb.h create mode 100644 source/blender/python/api2_2x/Curve.c create mode 100644 source/blender/python/api2_2x/Curve.h create mode 100644 source/blender/python/api2_2x/Draw.c create mode 100644 source/blender/python/api2_2x/Draw.h create mode 100644 source/blender/python/api2_2x/EXPP_interface.c create mode 100644 source/blender/python/api2_2x/EXPP_interface.h create mode 100644 source/blender/python/api2_2x/Effect.c create mode 100644 source/blender/python/api2_2x/Effect.h create mode 100644 source/blender/python/api2_2x/Font.c create mode 100644 source/blender/python/api2_2x/Font.h create mode 100644 source/blender/python/api2_2x/Geometry.c create mode 100644 source/blender/python/api2_2x/Geometry.h create mode 100644 source/blender/python/api2_2x/Group.c create mode 100644 source/blender/python/api2_2x/Group.h create mode 100644 source/blender/python/api2_2x/IDProp.c create mode 100644 source/blender/python/api2_2x/IDProp.h create mode 100644 source/blender/python/api2_2x/Image.c create mode 100644 source/blender/python/api2_2x/Image.h create mode 100644 source/blender/python/api2_2x/Ipo.c create mode 100644 source/blender/python/api2_2x/Ipo.h create mode 100644 source/blender/python/api2_2x/Ipocurve.c create mode 100644 source/blender/python/api2_2x/Ipocurve.h create mode 100644 source/blender/python/api2_2x/Key.c create mode 100644 source/blender/python/api2_2x/Key.h create mode 100644 source/blender/python/api2_2x/Lamp.c create mode 100644 source/blender/python/api2_2x/Lamp.h create mode 100644 source/blender/python/api2_2x/Lattice.c create mode 100644 source/blender/python/api2_2x/Lattice.h create mode 100644 source/blender/python/api2_2x/Library.c create mode 100644 source/blender/python/api2_2x/Library.h create mode 100644 source/blender/python/api2_2x/MTex.c create mode 100644 source/blender/python/api2_2x/MTex.h create mode 100644 source/blender/python/api2_2x/Makefile create mode 100644 source/blender/python/api2_2x/Material.c create mode 100644 source/blender/python/api2_2x/Material.h create mode 100644 source/blender/python/api2_2x/Mathutils.c create mode 100644 source/blender/python/api2_2x/Mathutils.h create mode 100644 source/blender/python/api2_2x/Mesh.c create mode 100644 source/blender/python/api2_2x/Mesh.h create mode 100644 source/blender/python/api2_2x/Metaball.c create mode 100644 source/blender/python/api2_2x/Metaball.h create mode 100644 source/blender/python/api2_2x/Modifier.c create mode 100644 source/blender/python/api2_2x/Modifier.h create mode 100644 source/blender/python/api2_2x/NLA.c create mode 100644 source/blender/python/api2_2x/NLA.h create mode 100644 source/blender/python/api2_2x/NMesh.c create mode 100644 source/blender/python/api2_2x/NMesh.h create mode 100644 source/blender/python/api2_2x/Node.c create mode 100644 source/blender/python/api2_2x/Node.h create mode 100644 source/blender/python/api2_2x/Noise.c create mode 100644 source/blender/python/api2_2x/Object.c create mode 100644 source/blender/python/api2_2x/Object.h create mode 100644 source/blender/python/api2_2x/Particle.c create mode 100644 source/blender/python/api2_2x/Particle.h create mode 100644 source/blender/python/api2_2x/Pose.c create mode 100644 source/blender/python/api2_2x/Pose.h create mode 100644 source/blender/python/api2_2x/Registry.c create mode 100644 source/blender/python/api2_2x/Registry.h create mode 100644 source/blender/python/api2_2x/Scene.c create mode 100644 source/blender/python/api2_2x/Scene.h create mode 100644 source/blender/python/api2_2x/Sound.c create mode 100644 source/blender/python/api2_2x/Sound.h create mode 100644 source/blender/python/api2_2x/SurfNurb.c create mode 100644 source/blender/python/api2_2x/SurfNurb.h create mode 100644 source/blender/python/api2_2x/Sys.c create mode 100644 source/blender/python/api2_2x/Sys.h create mode 100644 source/blender/python/api2_2x/Text.c create mode 100644 source/blender/python/api2_2x/Text.h create mode 100644 source/blender/python/api2_2x/Text3d.c create mode 100644 source/blender/python/api2_2x/Text3d.h create mode 100644 source/blender/python/api2_2x/Texture.c create mode 100644 source/blender/python/api2_2x/Texture.h create mode 100644 source/blender/python/api2_2x/Types.c create mode 100644 source/blender/python/api2_2x/Types.h create mode 100644 source/blender/python/api2_2x/Window.c create mode 100644 source/blender/python/api2_2x/Window.h create mode 100644 source/blender/python/api2_2x/World.c create mode 100644 source/blender/python/api2_2x/World.h create mode 100644 source/blender/python/api2_2x/bpy.c create mode 100644 source/blender/python/api2_2x/bpy.h create mode 100644 source/blender/python/api2_2x/bpy_config.c create mode 100644 source/blender/python/api2_2x/bpy_config.h create mode 100644 source/blender/python/api2_2x/bpy_data.c create mode 100644 source/blender/python/api2_2x/bpy_data.h create mode 100644 source/blender/python/api2_2x/bpy_types.h create mode 100644 source/blender/python/api2_2x/charRGBA.c create mode 100644 source/blender/python/api2_2x/charRGBA.h create mode 100644 source/blender/python/api2_2x/constant.c create mode 100644 source/blender/python/api2_2x/constant.h create mode 100644 source/blender/python/api2_2x/doc/API_intro.py create mode 100644 source/blender/python/api2_2x/doc/API_related.py create mode 100644 source/blender/python/api2_2x/doc/Armature.py create mode 100644 source/blender/python/api2_2x/doc/BGL.py create mode 100644 source/blender/python/api2_2x/doc/BezTriple.py create mode 100644 source/blender/python/api2_2x/doc/Blender.py create mode 100644 source/blender/python/api2_2x/doc/Blender_API.css create mode 100644 source/blender/python/api2_2x/doc/Bpy.py create mode 100644 source/blender/python/api2_2x/doc/Bpy_config.py create mode 100644 source/blender/python/api2_2x/doc/Bpy_data.py create mode 100644 source/blender/python/api2_2x/doc/Camera.py create mode 100644 source/blender/python/api2_2x/doc/Constraint.py create mode 100644 source/blender/python/api2_2x/doc/Curve.py create mode 100644 source/blender/python/api2_2x/doc/Curvedoc.txt create mode 100644 source/blender/python/api2_2x/doc/Draw.py create mode 100644 source/blender/python/api2_2x/doc/Effect.py create mode 100644 source/blender/python/api2_2x/doc/Effectdoc.txt create mode 100644 source/blender/python/api2_2x/doc/Font.py create mode 100644 source/blender/python/api2_2x/doc/Geometry.py create mode 100644 source/blender/python/api2_2x/doc/Group.py create mode 100644 source/blender/python/api2_2x/doc/IDProp.py create mode 100644 source/blender/python/api2_2x/doc/Image.py create mode 100644 source/blender/python/api2_2x/doc/Ipo.py create mode 100644 source/blender/python/api2_2x/doc/IpoCurve.py create mode 100644 source/blender/python/api2_2x/doc/Ipodoc.txt create mode 100644 source/blender/python/api2_2x/doc/Key.py create mode 100644 source/blender/python/api2_2x/doc/Lamp.py create mode 100644 source/blender/python/api2_2x/doc/Lattice.py create mode 100644 source/blender/python/api2_2x/doc/LibData.py create mode 100644 source/blender/python/api2_2x/doc/Library.py create mode 100644 source/blender/python/api2_2x/doc/Material.py create mode 100644 source/blender/python/api2_2x/doc/Mathutils.py create mode 100644 source/blender/python/api2_2x/doc/Mesh.py create mode 100644 source/blender/python/api2_2x/doc/MeshPrimitives.py create mode 100644 source/blender/python/api2_2x/doc/Metaball.py create mode 100644 source/blender/python/api2_2x/doc/Metaballdoc.txt create mode 100644 source/blender/python/api2_2x/doc/Modifier.py create mode 100644 source/blender/python/api2_2x/doc/NLA.py create mode 100644 source/blender/python/api2_2x/doc/NMesh.py create mode 100644 source/blender/python/api2_2x/doc/Noise.py create mode 100644 source/blender/python/api2_2x/doc/Object.py create mode 100644 source/blender/python/api2_2x/doc/Pose.py create mode 100644 source/blender/python/api2_2x/doc/Radio.py create mode 100644 source/blender/python/api2_2x/doc/Registry.py create mode 100644 source/blender/python/api2_2x/doc/Render.py create mode 100644 source/blender/python/api2_2x/doc/Scene.py create mode 100644 source/blender/python/api2_2x/doc/Sound.py create mode 100644 source/blender/python/api2_2x/doc/Sys.py create mode 100644 source/blender/python/api2_2x/doc/Text.py create mode 100644 source/blender/python/api2_2x/doc/Text3d.py create mode 100644 source/blender/python/api2_2x/doc/Texture.py create mode 100644 source/blender/python/api2_2x/doc/Theme.py create mode 100644 source/blender/python/api2_2x/doc/TimeLine.py create mode 100644 source/blender/python/api2_2x/doc/Types.py create mode 100644 source/blender/python/api2_2x/doc/Window.py create mode 100644 source/blender/python/api2_2x/doc/World.py create mode 100644 source/blender/python/api2_2x/doc/Worlddoc.txt create mode 100644 source/blender/python/api2_2x/doc/epy_docgen-3.sh create mode 100644 source/blender/python/api2_2x/doc/epy_docgen.sh create mode 100644 source/blender/python/api2_2x/doc/id_generics.py create mode 100644 source/blender/python/api2_2x/doc/testbgl.py create mode 100644 source/blender/python/api2_2x/doc/testcamera.py create mode 100644 source/blender/python/api2_2x/doc/testcurve.py create mode 100644 source/blender/python/api2_2x/doc/testeffect.py create mode 100644 source/blender/python/api2_2x/doc/testipo.py create mode 100644 source/blender/python/api2_2x/doc/testmball.py create mode 100644 source/blender/python/api2_2x/doc/testtext.py create mode 100644 source/blender/python/api2_2x/doc/testworld.py create mode 100644 source/blender/python/api2_2x/euler.c create mode 100644 source/blender/python/api2_2x/euler.h create mode 100644 source/blender/python/api2_2x/gen_library.c create mode 100644 source/blender/python/api2_2x/gen_library.h create mode 100644 source/blender/python/api2_2x/gen_utils.c create mode 100644 source/blender/python/api2_2x/gen_utils.h create mode 100644 source/blender/python/api2_2x/logic.c create mode 100644 source/blender/python/api2_2x/logic.h create mode 100644 source/blender/python/api2_2x/matrix.c create mode 100644 source/blender/python/api2_2x/matrix.h create mode 100644 source/blender/python/api2_2x/meshPrimitive.c create mode 100644 source/blender/python/api2_2x/meshPrimitive.h create mode 100644 source/blender/python/api2_2x/modules.h create mode 100644 source/blender/python/api2_2x/point.c create mode 100644 source/blender/python/api2_2x/point.h create mode 100644 source/blender/python/api2_2x/quat.c create mode 100644 source/blender/python/api2_2x/quat.h create mode 100644 source/blender/python/api2_2x/rgbTuple.c create mode 100644 source/blender/python/api2_2x/rgbTuple.h create mode 100644 source/blender/python/api2_2x/sceneRadio.c create mode 100644 source/blender/python/api2_2x/sceneRadio.h create mode 100644 source/blender/python/api2_2x/sceneRender.c create mode 100644 source/blender/python/api2_2x/sceneRender.h create mode 100644 source/blender/python/api2_2x/sceneSequence.c create mode 100644 source/blender/python/api2_2x/sceneSequence.h create mode 100644 source/blender/python/api2_2x/sceneTimeLine.c create mode 100644 source/blender/python/api2_2x/sceneTimeLine.h create mode 100644 source/blender/python/api2_2x/vector.c create mode 100644 source/blender/python/api2_2x/vector.h create mode 100644 source/blender/python/api2_2x/windowTheme.c create mode 100644 source/blender/python/api2_2x/windowTheme.h create mode 100644 source/blender/quicktime/CMakeLists.txt create mode 100644 source/blender/quicktime/Makefile create mode 100644 source/blender/quicktime/SConscript create mode 100644 source/blender/quicktime/apple/Makefile create mode 100644 source/blender/quicktime/apple/quicktime_export.c create mode 100644 source/blender/quicktime/apple/quicktime_import.c create mode 100644 source/blender/quicktime/quicktime_export.h create mode 100644 source/blender/quicktime/quicktime_import.h create mode 100644 source/blender/radiosity/CMakeLists.txt create mode 100644 source/blender/radiosity/Makefile create mode 100644 source/blender/radiosity/SConscript create mode 100644 source/blender/radiosity/extern/include/radio.h create mode 100644 source/blender/radiosity/extern/include/radio_types.h create mode 100644 source/blender/radiosity/intern/Makefile create mode 100644 source/blender/radiosity/intern/source/Makefile create mode 100644 source/blender/radiosity/intern/source/raddisplay.c create mode 100644 source/blender/radiosity/intern/source/radfactors.c create mode 100644 source/blender/radiosity/intern/source/radio.c create mode 100644 source/blender/radiosity/intern/source/radnode.c create mode 100644 source/blender/radiosity/intern/source/radpostprocess.c create mode 100644 source/blender/radiosity/intern/source/radpreprocess.c create mode 100644 source/blender/radiosity/intern/source/radrender.c create mode 100644 source/blender/readblenfile/BLO_readblenfile.h create mode 100644 source/blender/readblenfile/CMakeLists.txt create mode 100644 source/blender/readblenfile/Makefile create mode 100644 source/blender/readblenfile/SConscript create mode 100644 source/blender/readblenfile/intern/BLO_readblenfile.c create mode 100644 source/blender/readblenfile/intern/Makefile create mode 100644 source/blender/readblenfile/stub/BLO_readblenfileSTUB.c create mode 100644 source/blender/readblenfile/stub/Makefile create mode 100644 source/blender/readblenfile/test/Makefile create mode 100644 source/blender/readblenfile/test/test.c create mode 100644 source/blender/render/CMakeLists.txt create mode 100644 source/blender/render/Makefile create mode 100644 source/blender/render/SConscript create mode 100644 source/blender/render/extern/include/RE_pipeline.h create mode 100644 source/blender/render/extern/include/RE_raytrace.h create mode 100644 source/blender/render/extern/include/RE_render_ext.h create mode 100644 source/blender/render/extern/include/RE_shader_ext.h create mode 100644 source/blender/render/intern/Makefile create mode 100644 source/blender/render/intern/include/envmap.h create mode 100644 source/blender/render/intern/include/gammaCorrectionTables.h create mode 100644 source/blender/render/intern/include/initrender.h create mode 100644 source/blender/render/intern/include/pixelblending.h create mode 100644 source/blender/render/intern/include/pixelshading.h create mode 100644 source/blender/render/intern/include/render_types.h create mode 100644 source/blender/render/intern/include/rendercore.h create mode 100644 source/blender/render/intern/include/renderdatabase.h create mode 100644 source/blender/render/intern/include/renderpipeline.h create mode 100644 source/blender/render/intern/include/shadbuf.h create mode 100644 source/blender/render/intern/include/shading.h create mode 100644 source/blender/render/intern/include/sss.h create mode 100644 source/blender/render/intern/include/texture.h create mode 100644 source/blender/render/intern/include/zbuf.h create mode 100644 source/blender/render/intern/source/Makefile create mode 100644 source/blender/render/intern/source/convertblender.c create mode 100644 source/blender/render/intern/source/envmap.c create mode 100644 source/blender/render/intern/source/gammaCorrectionTables.c create mode 100644 source/blender/render/intern/source/imagetexture.c create mode 100644 source/blender/render/intern/source/initrender.c create mode 100644 source/blender/render/intern/source/pipeline.c create mode 100644 source/blender/render/intern/source/pixelblending.c create mode 100644 source/blender/render/intern/source/pixelshading.c create mode 100644 source/blender/render/intern/source/rayshade.c create mode 100644 source/blender/render/intern/source/raytrace.c create mode 100644 source/blender/render/intern/source/rendercore.c create mode 100644 source/blender/render/intern/source/renderdatabase.c create mode 100644 source/blender/render/intern/source/shadbuf.c create mode 100644 source/blender/render/intern/source/shadeinput.c create mode 100644 source/blender/render/intern/source/shadeoutput.c create mode 100644 source/blender/render/intern/source/sss.c create mode 100644 source/blender/render/intern/source/texture.c create mode 100644 source/blender/render/intern/source/zbuf.c create mode 100644 source/blender/src/.BCkey create mode 100644 source/blender/src/B.blend.c create mode 100644 source/blender/src/Bfont.c create mode 100644 source/blender/src/CMakeLists.txt create mode 100644 source/blender/src/Makefile create mode 100644 source/blender/src/SConscript create mode 100644 source/blender/src/bfont.ttf.c create mode 100644 source/blender/src/blenderbuttons.c create mode 100644 source/blender/src/booleanops.c create mode 100644 source/blender/src/booleanops_mesh.c create mode 100644 source/blender/src/butspace.c create mode 100644 source/blender/src/buttons_editing.c create mode 100644 source/blender/src/buttons_logic.c create mode 100644 source/blender/src/buttons_object.c create mode 100644 source/blender/src/buttons_scene.c create mode 100644 source/blender/src/buttons_script.c create mode 100644 source/blender/src/buttons_shading.c create mode 100644 source/blender/src/cmap.tga.c create mode 100644 source/blender/src/cmovie.tga.c create mode 100644 source/blender/src/cre/license.jpeg.c create mode 100644 source/blender/src/cre/license_key.c create mode 100644 source/blender/src/cursors.c create mode 100644 source/blender/src/drawaction.c create mode 100644 source/blender/src/drawarmature.c create mode 100644 source/blender/src/drawdeps.c create mode 100644 source/blender/src/drawimage.c create mode 100644 source/blender/src/drawimasel.c create mode 100644 source/blender/src/drawipo.c create mode 100644 source/blender/src/drawmesh.c create mode 100644 source/blender/src/drawnla.c create mode 100644 source/blender/src/drawnode.c create mode 100644 source/blender/src/drawobject.c create mode 100644 source/blender/src/drawoops.c create mode 100644 source/blender/src/drawscene.c create mode 100644 source/blender/src/drawscript.c create mode 100644 source/blender/src/drawseq.c create mode 100644 source/blender/src/drawsound.c create mode 100644 source/blender/src/drawtext.c create mode 100644 source/blender/src/drawtime.c create mode 100644 source/blender/src/drawview.c create mode 100644 source/blender/src/edit.c create mode 100644 source/blender/src/editaction.c create mode 100644 source/blender/src/editarmature.c create mode 100644 source/blender/src/editconstraint.c create mode 100644 source/blender/src/editcurve.c create mode 100644 source/blender/src/editdeform.c create mode 100644 source/blender/src/editface.c create mode 100644 source/blender/src/editfont.c create mode 100644 source/blender/src/editgroup.c create mode 100644 source/blender/src/editimasel.c create mode 100644 source/blender/src/editipo.c create mode 100644 source/blender/src/editipo_lib.c create mode 100644 source/blender/src/editipo_mods.c create mode 100644 source/blender/src/editkey.c create mode 100644 source/blender/src/editlattice.c create mode 100644 source/blender/src/editmball.c create mode 100644 source/blender/src/editmesh.c create mode 100644 source/blender/src/editmesh_add.c create mode 100644 source/blender/src/editmesh_lib.c create mode 100644 source/blender/src/editmesh_loop.c create mode 100644 source/blender/src/editmesh_mods.c create mode 100644 source/blender/src/editmesh_tools.c create mode 100644 source/blender/src/editmode_undo.c create mode 100644 source/blender/src/editnla.c create mode 100644 source/blender/src/editnode.c create mode 100644 source/blender/src/editobject.c create mode 100644 source/blender/src/editoops.c create mode 100644 source/blender/src/editscreen.c create mode 100644 source/blender/src/editseq.c create mode 100644 source/blender/src/editsima.c create mode 100644 source/blender/src/editsound.c create mode 100644 source/blender/src/edittime.c create mode 100644 source/blender/src/editview.c create mode 100644 source/blender/src/eventdebug.c create mode 100644 source/blender/src/filelist.c create mode 100644 source/blender/src/filesel.c create mode 100644 source/blender/src/fluidsim.c create mode 100644 source/blender/src/fsmenu.c create mode 100644 source/blender/src/ghostwinlay.c create mode 100644 source/blender/src/glutil.c create mode 100644 source/blender/src/hddaudio.c create mode 100644 source/blender/src/header_action.c create mode 100644 source/blender/src/header_buttonswin.c create mode 100644 source/blender/src/header_filesel.c create mode 100644 source/blender/src/header_image.c create mode 100644 source/blender/src/header_imasel.c create mode 100644 source/blender/src/header_info.c create mode 100644 source/blender/src/header_ipo.c create mode 100644 source/blender/src/header_nla.c create mode 100644 source/blender/src/header_node.c create mode 100644 source/blender/src/header_oops.c create mode 100644 source/blender/src/header_script.c create mode 100644 source/blender/src/header_seq.c create mode 100644 source/blender/src/header_sound.c create mode 100644 source/blender/src/header_text.c create mode 100644 source/blender/src/header_time.c create mode 100644 source/blender/src/header_view3d.c create mode 100644 source/blender/src/headerbuttons.c create mode 100644 source/blender/src/imagepaint.c create mode 100644 source/blender/src/imasel.c create mode 100644 source/blender/src/interface.c create mode 100644 source/blender/src/interface_draw.c create mode 100644 source/blender/src/interface_icons.c create mode 100644 source/blender/src/interface_panel.c create mode 100644 source/blender/src/keyval.c create mode 100644 source/blender/src/language.c create mode 100644 source/blender/src/lorem.c create mode 100644 source/blender/src/mainqueue.c create mode 100644 source/blender/src/meshlaplacian.c create mode 100644 source/blender/src/meshtools.c create mode 100644 source/blender/src/multires-firstlevel.c create mode 100644 source/blender/src/multires.c create mode 100644 source/blender/src/mywindow.c create mode 100644 source/blender/src/oops.c create mode 100644 source/blender/src/outliner.c create mode 100644 source/blender/src/parametrizer.c create mode 100644 source/blender/src/parametrizer.h create mode 100644 source/blender/src/parametrizer_intern.h create mode 100644 source/blender/src/playanim.c create mode 100644 source/blender/src/poseobject.c create mode 100644 source/blender/src/preview.blend.c create mode 100644 source/blender/src/previewrender.c create mode 100644 source/blender/src/prvicons.c create mode 100644 source/blender/src/pub/license_key.c create mode 100644 source/blender/src/renderwin.c create mode 100644 source/blender/src/resources.c create mode 100644 source/blender/src/retopo.c create mode 100644 source/blender/src/scrarea.c create mode 100644 source/blender/src/screendump.c create mode 100644 source/blender/src/sculptmode-stroke.c create mode 100644 source/blender/src/sculptmode.c create mode 100644 source/blender/src/seqaudio.c create mode 100644 source/blender/src/seqeffects.c create mode 100644 source/blender/src/seqscopes.c create mode 100644 source/blender/src/sequence.c create mode 100644 source/blender/src/space.c create mode 100644 source/blender/src/spacetypes.c create mode 100644 source/blender/src/splash.jpg.c create mode 100644 source/blender/src/swapbuffers.c create mode 100644 source/blender/src/toets.c create mode 100644 source/blender/src/toolbox.c create mode 100644 source/blender/src/transform.c create mode 100644 source/blender/src/transform_constraints.c create mode 100644 source/blender/src/transform_conversions.c create mode 100644 source/blender/src/transform_generics.c create mode 100644 source/blender/src/transform_manipulator.c create mode 100644 source/blender/src/transform_numinput.c create mode 100644 source/blender/src/transform_snap.c create mode 100644 source/blender/src/unwrapper.c create mode 100644 source/blender/src/usiblender.c create mode 100644 source/blender/src/verse_common.c create mode 100644 source/blender/src/verse_image.c create mode 100644 source/blender/src/verse_mesh.c create mode 100644 source/blender/src/verse_object.c create mode 100644 source/blender/src/view.c create mode 100644 source/blender/src/vpaint.c create mode 100644 source/blender/src/winlay.h create mode 100644 source/blender/src/writeavicodec.c create mode 100644 source/blender/src/writeimage.c create mode 100644 source/blender/src/writemovie.c create mode 100644 source/blender/verify/BLO_sign_verify_Header.h create mode 100644 source/blender/verify/BLO_signer_info.h create mode 100644 source/blender/verify/BLO_verify.h create mode 100644 source/blender/verify/Makefile create mode 100644 source/blender/verify/intern/BLO_verify.c create mode 100644 source/blender/verify/intern/Makefile create mode 100644 source/blender/yafray/CMakeLists.txt create mode 100644 source/blender/yafray/Makefile create mode 100644 source/blender/yafray/SConscript create mode 100644 source/blender/yafray/YafRay_Api.h create mode 100644 source/blender/yafray/intern/Makefile create mode 100644 source/blender/yafray/intern/api.cpp create mode 100644 source/blender/yafray/intern/export_File.cpp create mode 100644 source/blender/yafray/intern/export_File.h create mode 100644 source/blender/yafray/intern/export_Plugin.cpp create mode 100644 source/blender/yafray/intern/export_Plugin.h create mode 100644 source/blender/yafray/intern/yafexternal.cpp create mode 100644 source/blender/yafray/intern/yafexternal.h create mode 100644 source/blender/yafray/intern/yafray_Render.cpp create mode 100644 source/blender/yafray/intern/yafray_Render.h create mode 100644 source/creator/CMakeLists.txt create mode 100644 source/creator/Makefile create mode 100644 source/creator/SConscript create mode 100644 source/creator/buildinfo.c create mode 100644 source/creator/creator.c create mode 100644 source/darwin/Makefile create mode 100644 source/darwin/blender.app/Contents/Info.plist create mode 100644 source/darwin/blender.app/Contents/MacOS/blender create mode 100644 source/darwin/blender.app/Contents/PkgInfo create mode 100644 source/darwin/blender.app/Contents/Resources/blender file icon.icns create mode 100644 source/darwin/blender.app/Contents/Resources/blender icon.icns create mode 100644 source/darwin/blendercreator.app/Contents/Info.plist create mode 100644 source/darwin/blendercreator.app/Contents/MacOS/blendercreator create mode 100644 source/darwin/blendercreator.app/Contents/PkgInfo create mode 100644 source/darwin/blendercreator.app/Contents/Resources/blender creator icon.icns create mode 100644 source/darwin/blendercreator.app/Contents/Resources/blender file icon.icns create mode 100644 source/darwin/blenderplayer.app/Contents/Info.plist create mode 100644 source/darwin/blenderplayer.app/Contents/MacOS/blenderplayer create mode 100644 source/darwin/blenderplayer.app/Contents/PkgInfo create mode 100644 source/darwin/blenderplayer.app/Contents/Resources/blender file icon.icns create mode 100644 source/darwin/blenderplayer.app/Contents/Resources/blender player icon.icns create mode 100644 source/darwin/blenderpublisher.app/Contents/Info.plist create mode 100644 source/darwin/blenderpublisher.app/Contents/MacOS/blenderpublisher create mode 100644 source/darwin/blenderpublisher.app/Contents/PkgInfo create mode 100644 source/darwin/blenderpublisher.app/Contents/Resources/blender file icon.icns create mode 100644 source/darwin/blenderpublisher.app/Contents/Resources/blender publisher icon.icns create mode 100644 source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp create mode 100644 source/gameengine/BlenderRoutines/CMakeLists.txt create mode 100644 source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp create mode 100644 source/gameengine/BlenderRoutines/KX_BlenderCanvas.h create mode 100644 source/gameengine/BlenderRoutines/KX_BlenderGL.cpp create mode 100644 source/gameengine/BlenderRoutines/KX_BlenderGL.h create mode 100644 source/gameengine/BlenderRoutines/KX_BlenderInputDevice.cpp create mode 100644 source/gameengine/BlenderRoutines/KX_BlenderInputDevice.h create mode 100644 source/gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.cpp create mode 100644 source/gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.h create mode 100644 source/gameengine/BlenderRoutines/KX_BlenderMouseDevice.cpp create mode 100644 source/gameengine/BlenderRoutines/KX_BlenderMouseDevice.h create mode 100644 source/gameengine/BlenderRoutines/KX_BlenderPolyMaterial.cpp create mode 100644 source/gameengine/BlenderRoutines/KX_BlenderPolyMaterial.h create mode 100644 source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp create mode 100644 source/gameengine/BlenderRoutines/KX_BlenderRenderTools.h create mode 100644 source/gameengine/BlenderRoutines/KX_BlenderSystem.cpp create mode 100644 source/gameengine/BlenderRoutines/KX_BlenderSystem.h create mode 100644 source/gameengine/BlenderRoutines/Makefile create mode 100644 source/gameengine/BlenderRoutines/SConscript create mode 100644 source/gameengine/CMakeLists.txt create mode 100644 source/gameengine/Converter/BL_ActionActuator.cpp create mode 100644 source/gameengine/Converter/BL_ActionActuator.h create mode 100644 source/gameengine/Converter/BL_ArmatureObject.cpp create mode 100644 source/gameengine/Converter/BL_ArmatureObject.h create mode 100644 source/gameengine/Converter/BL_BlenderDataConversion.cpp create mode 100644 source/gameengine/Converter/BL_BlenderDataConversion.h create mode 100644 source/gameengine/Converter/BL_DeformableGameObject.cpp create mode 100644 source/gameengine/Converter/BL_DeformableGameObject.h create mode 100644 source/gameengine/Converter/BL_MeshDeformer.cpp create mode 100644 source/gameengine/Converter/BL_MeshDeformer.h create mode 100644 source/gameengine/Converter/BL_SkinDeformer.cpp create mode 100644 source/gameengine/Converter/BL_SkinDeformer.h create mode 100644 source/gameengine/Converter/BL_SkinMeshObject.cpp create mode 100644 source/gameengine/Converter/BL_SkinMeshObject.h create mode 100644 source/gameengine/Converter/BlenderWorldInfo.cpp create mode 100644 source/gameengine/Converter/BlenderWorldInfo.h create mode 100644 source/gameengine/Converter/CMakeLists.txt create mode 100644 source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp create mode 100644 source/gameengine/Converter/KX_BlenderScalarInterpolator.h create mode 100644 source/gameengine/Converter/KX_BlenderSceneConverter.cpp create mode 100644 source/gameengine/Converter/KX_BlenderSceneConverter.h create mode 100644 source/gameengine/Converter/KX_ConvertActuators.cpp create mode 100644 source/gameengine/Converter/KX_ConvertActuators.h create mode 100644 source/gameengine/Converter/KX_ConvertControllers.cpp create mode 100644 source/gameengine/Converter/KX_ConvertControllers.h create mode 100644 source/gameengine/Converter/KX_ConvertProperties.cpp create mode 100644 source/gameengine/Converter/KX_ConvertProperties.h create mode 100644 source/gameengine/Converter/KX_ConvertSensors.cpp create mode 100644 source/gameengine/Converter/KX_ConvertSensors.h create mode 100644 source/gameengine/Converter/KX_IpoConvert.cpp create mode 100644 source/gameengine/Converter/KX_IpoConvert.h create mode 100644 source/gameengine/Converter/Makefile create mode 100644 source/gameengine/Converter/SConscript create mode 100644 source/gameengine/Expressions/BoolValue.cpp create mode 100644 source/gameengine/Expressions/BoolValue.h create mode 100644 source/gameengine/Expressions/CMakeLists.txt create mode 100644 source/gameengine/Expressions/ConstExpr.cpp create mode 100644 source/gameengine/Expressions/ConstExpr.h create mode 100644 source/gameengine/Expressions/EXP_C-Api.cpp create mode 100644 source/gameengine/Expressions/EXP_C-Api.h create mode 100644 source/gameengine/Expressions/EmptyValue.cpp create mode 100644 source/gameengine/Expressions/EmptyValue.h create mode 100644 source/gameengine/Expressions/ErrorValue.cpp create mode 100644 source/gameengine/Expressions/ErrorValue.h create mode 100644 source/gameengine/Expressions/Expression.cpp create mode 100644 source/gameengine/Expressions/Expression.h create mode 100644 source/gameengine/Expressions/FloatValue.cpp create mode 100644 source/gameengine/Expressions/FloatValue.h create mode 100644 source/gameengine/Expressions/IdentifierExpr.cpp create mode 100644 source/gameengine/Expressions/IdentifierExpr.h create mode 100644 source/gameengine/Expressions/IfExpr.cpp create mode 100644 source/gameengine/Expressions/IfExpr.h create mode 100644 source/gameengine/Expressions/InputParser.cpp create mode 100644 source/gameengine/Expressions/InputParser.h create mode 100644 source/gameengine/Expressions/IntValue.cpp create mode 100644 source/gameengine/Expressions/IntValue.h create mode 100644 source/gameengine/Expressions/KX_HashedPtr.cpp create mode 100644 source/gameengine/Expressions/KX_HashedPtr.h create mode 100644 source/gameengine/Expressions/KX_Python.h create mode 100644 source/gameengine/Expressions/KX_Python_dynamic.h create mode 100644 source/gameengine/Expressions/KX_Python_static.h create mode 100644 source/gameengine/Expressions/ListValue.cpp create mode 100644 source/gameengine/Expressions/ListValue.h create mode 100644 source/gameengine/Expressions/Makefile create mode 100644 source/gameengine/Expressions/Operator1Expr.cpp create mode 100644 source/gameengine/Expressions/Operator1Expr.h create mode 100644 source/gameengine/Expressions/Operator2Expr.cpp create mode 100644 source/gameengine/Expressions/Operator2Expr.h create mode 100644 source/gameengine/Expressions/PyObjectPlus.cpp create mode 100644 source/gameengine/Expressions/PyObjectPlus.h create mode 100644 source/gameengine/Expressions/SConscript create mode 100644 source/gameengine/Expressions/StringValue.cpp create mode 100644 source/gameengine/Expressions/StringValue.h create mode 100644 source/gameengine/Expressions/Value.cpp create mode 100644 source/gameengine/Expressions/Value.h create mode 100644 source/gameengine/Expressions/VectorValue.cpp create mode 100644 source/gameengine/Expressions/VectorValue.h create mode 100644 source/gameengine/Expressions/VoidValue.h create mode 100644 source/gameengine/GameLogic/CMakeLists.txt create mode 100644 source/gameengine/GameLogic/Joystick/Makefile create mode 100644 source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp create mode 100644 source/gameengine/GameLogic/Joystick/SCA_Joystick.h create mode 100644 source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h create mode 100644 source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp create mode 100644 source/gameengine/GameLogic/Joystick/SCA_JoystickPrivate.h create mode 100644 source/gameengine/GameLogic/Makefile create mode 100644 source/gameengine/GameLogic/SCA_ANDController.cpp create mode 100644 source/gameengine/GameLogic/SCA_ANDController.h create mode 100644 source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp create mode 100644 source/gameengine/GameLogic/SCA_AlwaysEventManager.h create mode 100644 source/gameengine/GameLogic/SCA_AlwaysSensor.cpp create mode 100644 source/gameengine/GameLogic/SCA_AlwaysSensor.h create mode 100644 source/gameengine/GameLogic/SCA_EventManager.cpp create mode 100644 source/gameengine/GameLogic/SCA_EventManager.h create mode 100644 source/gameengine/GameLogic/SCA_ExpressionController.cpp create mode 100644 source/gameengine/GameLogic/SCA_ExpressionController.h create mode 100644 source/gameengine/GameLogic/SCA_IActuator.cpp create mode 100644 source/gameengine/GameLogic/SCA_IActuator.h create mode 100644 source/gameengine/GameLogic/SCA_IController.cpp create mode 100644 source/gameengine/GameLogic/SCA_IController.h create mode 100644 source/gameengine/GameLogic/SCA_IInputDevice.cpp create mode 100644 source/gameengine/GameLogic/SCA_IInputDevice.h create mode 100644 source/gameengine/GameLogic/SCA_ILogicBrick.cpp create mode 100644 source/gameengine/GameLogic/SCA_ILogicBrick.h create mode 100644 source/gameengine/GameLogic/SCA_IObject.cpp create mode 100644 source/gameengine/GameLogic/SCA_IObject.h create mode 100644 source/gameengine/GameLogic/SCA_IScene.cpp create mode 100644 source/gameengine/GameLogic/SCA_IScene.h create mode 100644 source/gameengine/GameLogic/SCA_ISensor.cpp create mode 100644 source/gameengine/GameLogic/SCA_ISensor.h create mode 100644 source/gameengine/GameLogic/SCA_JoystickManager.cpp create mode 100644 source/gameengine/GameLogic/SCA_JoystickManager.h create mode 100644 source/gameengine/GameLogic/SCA_JoystickSensor.cpp create mode 100644 source/gameengine/GameLogic/SCA_JoystickSensor.h create mode 100644 source/gameengine/GameLogic/SCA_KeyboardManager.cpp create mode 100644 source/gameengine/GameLogic/SCA_KeyboardManager.h create mode 100644 source/gameengine/GameLogic/SCA_KeyboardSensor.cpp create mode 100644 source/gameengine/GameLogic/SCA_KeyboardSensor.h create mode 100644 source/gameengine/GameLogic/SCA_LogicManager.cpp create mode 100644 source/gameengine/GameLogic/SCA_LogicManager.h create mode 100644 source/gameengine/GameLogic/SCA_MouseManager.cpp create mode 100644 source/gameengine/GameLogic/SCA_MouseManager.h create mode 100644 source/gameengine/GameLogic/SCA_MouseSensor.cpp create mode 100644 source/gameengine/GameLogic/SCA_MouseSensor.h create mode 100644 source/gameengine/GameLogic/SCA_ORController.cpp create mode 100644 source/gameengine/GameLogic/SCA_ORController.h create mode 100644 source/gameengine/GameLogic/SCA_PropertyActuator.cpp create mode 100644 source/gameengine/GameLogic/SCA_PropertyActuator.h create mode 100644 source/gameengine/GameLogic/SCA_PropertyEventManager.cpp create mode 100644 source/gameengine/GameLogic/SCA_PropertyEventManager.h create mode 100644 source/gameengine/GameLogic/SCA_PropertySensor.cpp create mode 100644 source/gameengine/GameLogic/SCA_PropertySensor.h create mode 100644 source/gameengine/GameLogic/SCA_PythonController.cpp create mode 100644 source/gameengine/GameLogic/SCA_PythonController.h create mode 100644 source/gameengine/GameLogic/SCA_RandomActuator.cpp create mode 100644 source/gameengine/GameLogic/SCA_RandomActuator.h create mode 100644 source/gameengine/GameLogic/SCA_RandomEventManager.cpp create mode 100644 source/gameengine/GameLogic/SCA_RandomEventManager.h create mode 100644 source/gameengine/GameLogic/SCA_RandomNumberGenerator.cpp create mode 100644 source/gameengine/GameLogic/SCA_RandomNumberGenerator.h create mode 100644 source/gameengine/GameLogic/SCA_RandomSensor.cpp create mode 100644 source/gameengine/GameLogic/SCA_RandomSensor.h create mode 100644 source/gameengine/GameLogic/SCA_TimeEventManager.cpp create mode 100644 source/gameengine/GameLogic/SCA_TimeEventManager.h create mode 100644 source/gameengine/GameLogic/SConscript create mode 100644 source/gameengine/GamePlayer/CMakeLists.txt create mode 100644 source/gameengine/GamePlayer/Makefile create mode 100644 source/gameengine/GamePlayer/SConscript create mode 100644 source/gameengine/GamePlayer/common/CMakeLists.txt create mode 100644 source/gameengine/GamePlayer/common/GPC_Canvas.cpp create mode 100644 source/gameengine/GamePlayer/common/GPC_Canvas.h create mode 100644 source/gameengine/GamePlayer/common/GPC_Engine.cpp create mode 100644 source/gameengine/GamePlayer/common/GPC_Engine.h create mode 100644 source/gameengine/GamePlayer/common/GPC_KeyboardDevice.cpp create mode 100644 source/gameengine/GamePlayer/common/GPC_KeyboardDevice.h create mode 100644 source/gameengine/GamePlayer/common/GPC_MouseDevice.cpp create mode 100644 source/gameengine/GamePlayer/common/GPC_MouseDevice.h create mode 100644 source/gameengine/GamePlayer/common/GPC_PolygonMaterial.cpp create mode 100644 source/gameengine/GamePlayer/common/GPC_PolygonMaterial.h create mode 100644 source/gameengine/GamePlayer/common/GPC_RawImage.cpp create mode 100644 source/gameengine/GamePlayer/common/GPC_RawImage.h create mode 100644 source/gameengine/GamePlayer/common/GPC_RawLoadDotBlendArray.cpp create mode 100644 source/gameengine/GamePlayer/common/GPC_RawLoadDotBlendArray.h create mode 100644 source/gameengine/GamePlayer/common/GPC_RawLogoArrays.cpp create mode 100644 source/gameengine/GamePlayer/common/GPC_RawLogoArrays.h create mode 100644 source/gameengine/GamePlayer/common/GPC_RenderTools.cpp create mode 100644 source/gameengine/GamePlayer/common/GPC_RenderTools.h create mode 100644 source/gameengine/GamePlayer/common/GPC_System.cpp create mode 100644 source/gameengine/GamePlayer/common/GPC_System.h create mode 100644 source/gameengine/GamePlayer/common/Makefile create mode 100644 source/gameengine/GamePlayer/common/SConscript create mode 100644 source/gameengine/GamePlayer/common/bmfont.cpp create mode 100644 source/gameengine/GamePlayer/common/load.blend create mode 100644 source/gameengine/GamePlayer/common/logo_blender.raw create mode 100644 source/gameengine/GamePlayer/common/logo_blender3d.raw create mode 100644 source/gameengine/GamePlayer/common/logo_nan.raw create mode 100644 source/gameengine/GamePlayer/common/unix/GPU_Canvas.cpp create mode 100644 source/gameengine/GamePlayer/common/unix/GPU_Canvas.h create mode 100644 source/gameengine/GamePlayer/common/unix/GPU_Engine.cpp create mode 100644 source/gameengine/GamePlayer/common/unix/GPU_Engine.h create mode 100644 source/gameengine/GamePlayer/common/unix/GPU_KeyboardDevice.cpp create mode 100644 source/gameengine/GamePlayer/common/unix/GPU_KeyboardDevice.h create mode 100644 source/gameengine/GamePlayer/common/unix/GPU_PolygonMaterial.h create mode 100644 source/gameengine/GamePlayer/common/unix/GPU_System.cpp create mode 100644 source/gameengine/GamePlayer/common/unix/GPU_System.h create mode 100644 source/gameengine/GamePlayer/common/unix/Makefile create mode 100644 source/gameengine/GamePlayer/common/windows/GPW_Canvas.cpp create mode 100644 source/gameengine/GamePlayer/common/windows/GPW_Canvas.h create mode 100644 source/gameengine/GamePlayer/common/windows/GPW_Engine.cpp create mode 100644 source/gameengine/GamePlayer/common/windows/GPW_Engine.h create mode 100644 source/gameengine/GamePlayer/common/windows/GPW_KeyboardDevice.cpp create mode 100644 source/gameengine/GamePlayer/common/windows/GPW_KeyboardDevice.h create mode 100644 source/gameengine/GamePlayer/common/windows/GPW_System.cpp create mode 100644 source/gameengine/GamePlayer/common/windows/GPW_System.h create mode 100644 source/gameengine/GamePlayer/common/windows/Makefile create mode 100644 source/gameengine/GamePlayer/ghost/CMakeLists.txt create mode 100644 source/gameengine/GamePlayer/ghost/GPG_Application.cpp create mode 100644 source/gameengine/GamePlayer/ghost/GPG_Application.h create mode 100644 source/gameengine/GamePlayer/ghost/GPG_Canvas.cpp create mode 100644 source/gameengine/GamePlayer/ghost/GPG_Canvas.h create mode 100644 source/gameengine/GamePlayer/ghost/GPG_KeyboardDevice.cpp create mode 100644 source/gameengine/GamePlayer/ghost/GPG_KeyboardDevice.h create mode 100644 source/gameengine/GamePlayer/ghost/GPG_System.cpp create mode 100644 source/gameengine/GamePlayer/ghost/GPG_System.h create mode 100644 source/gameengine/GamePlayer/ghost/GPG_ghost.cpp create mode 100644 source/gameengine/GamePlayer/ghost/Makefile create mode 100644 source/gameengine/GamePlayer/ghost/SConscript create mode 100644 source/gameengine/Ketsji/BL_Material.cpp create mode 100644 source/gameengine/Ketsji/BL_Material.h create mode 100644 source/gameengine/Ketsji/BL_Shader.cpp create mode 100644 source/gameengine/Ketsji/BL_Shader.h create mode 100644 source/gameengine/Ketsji/BL_Texture.cpp create mode 100644 source/gameengine/Ketsji/BL_Texture.h create mode 100644 source/gameengine/Ketsji/CMakeLists.txt create mode 100644 source/gameengine/Ketsji/KXNetwork/CMakeLists.txt create mode 100644 source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp create mode 100644 source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h create mode 100644 source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp create mode 100644 source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.h create mode 100644 source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp create mode 100644 source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h create mode 100644 source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectActuator.cpp create mode 100644 source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectActuator.h create mode 100644 source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectSensor.cpp create mode 100644 source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectSensor.h create mode 100644 source/gameengine/Ketsji/KXNetwork/Makefile create mode 100644 source/gameengine/Ketsji/KXNetwork/SConscript create mode 100644 source/gameengine/Ketsji/KX_BlenderMaterial.cpp create mode 100644 source/gameengine/Ketsji/KX_BlenderMaterial.h create mode 100644 source/gameengine/Ketsji/KX_BulletPhysicsController.cpp create mode 100644 source/gameengine/Ketsji/KX_BulletPhysicsController.h create mode 100644 source/gameengine/Ketsji/KX_CDActuator.cpp create mode 100644 source/gameengine/Ketsji/KX_CDActuator.h create mode 100644 source/gameengine/Ketsji/KX_Camera.cpp create mode 100644 source/gameengine/Ketsji/KX_Camera.h create mode 100644 source/gameengine/Ketsji/KX_CameraActuator.cpp create mode 100644 source/gameengine/Ketsji/KX_CameraActuator.h create mode 100644 source/gameengine/Ketsji/KX_CameraIpoSGController.cpp create mode 100644 source/gameengine/Ketsji/KX_CameraIpoSGController.h create mode 100644 source/gameengine/Ketsji/KX_ClientObjectInfo.h create mode 100644 source/gameengine/Ketsji/KX_ConstraintActuator.cpp create mode 100644 source/gameengine/Ketsji/KX_ConstraintActuator.h create mode 100644 source/gameengine/Ketsji/KX_ConstraintWrapper.cpp create mode 100644 source/gameengine/Ketsji/KX_ConstraintWrapper.h create mode 100644 source/gameengine/Ketsji/KX_ConvertPhysicsObject.h create mode 100644 source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp create mode 100644 source/gameengine/Ketsji/KX_EmptyObject.cpp create mode 100644 source/gameengine/Ketsji/KX_EmptyObject.h create mode 100644 source/gameengine/Ketsji/KX_GameActuator.cpp create mode 100644 source/gameengine/Ketsji/KX_GameActuator.h create mode 100644 source/gameengine/Ketsji/KX_GameObject.cpp create mode 100644 source/gameengine/Ketsji/KX_GameObject.h create mode 100644 source/gameengine/Ketsji/KX_IInterpolator.h create mode 100644 source/gameengine/Ketsji/KX_IPOTransform.h create mode 100644 source/gameengine/Ketsji/KX_IPO_SGController.cpp create mode 100644 source/gameengine/Ketsji/KX_IPO_SGController.h create mode 100644 source/gameengine/Ketsji/KX_IPhysicsController.cpp create mode 100644 source/gameengine/Ketsji/KX_IPhysicsController.h create mode 100644 source/gameengine/Ketsji/KX_IScalarInterpolator.h create mode 100644 source/gameengine/Ketsji/KX_ISceneConverter.h create mode 100644 source/gameengine/Ketsji/KX_ISystem.h create mode 100644 source/gameengine/Ketsji/KX_IpoActuator.cpp create mode 100644 source/gameengine/Ketsji/KX_IpoActuator.h create mode 100644 source/gameengine/Ketsji/KX_KetsjiEngine.cpp create mode 100644 source/gameengine/Ketsji/KX_KetsjiEngine.h create mode 100644 source/gameengine/Ketsji/KX_Light.cpp create mode 100644 source/gameengine/Ketsji/KX_Light.h create mode 100644 source/gameengine/Ketsji/KX_LightIpoSGController.cpp create mode 100644 source/gameengine/Ketsji/KX_LightIpoSGController.h create mode 100644 source/gameengine/Ketsji/KX_MaterialIpoController.cpp create mode 100644 source/gameengine/Ketsji/KX_MaterialIpoController.h create mode 100644 source/gameengine/Ketsji/KX_MeshProxy.cpp create mode 100644 source/gameengine/Ketsji/KX_MeshProxy.h create mode 100644 source/gameengine/Ketsji/KX_MotionState.cpp create mode 100644 source/gameengine/Ketsji/KX_MotionState.h create mode 100644 source/gameengine/Ketsji/KX_MouseFocusSensor.cpp create mode 100644 source/gameengine/Ketsji/KX_MouseFocusSensor.h create mode 100644 source/gameengine/Ketsji/KX_NearSensor.cpp create mode 100644 source/gameengine/Ketsji/KX_NearSensor.h create mode 100644 source/gameengine/Ketsji/KX_ObColorIpoSGController.cpp create mode 100644 source/gameengine/Ketsji/KX_ObColorIpoSGController.h create mode 100644 source/gameengine/Ketsji/KX_ObjectActuator.cpp create mode 100644 source/gameengine/Ketsji/KX_ObjectActuator.h create mode 100644 source/gameengine/Ketsji/KX_OdePhysicsController.cpp create mode 100644 source/gameengine/Ketsji/KX_OdePhysicsController.h create mode 100644 source/gameengine/Ketsji/KX_OrientationInterpolator.cpp create mode 100644 source/gameengine/Ketsji/KX_OrientationInterpolator.h create mode 100644 source/gameengine/Ketsji/KX_PhysicsEngineEnums.h create mode 100644 source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp create mode 100644 source/gameengine/Ketsji/KX_PhysicsObjectWrapper.h create mode 100644 source/gameengine/Ketsji/KX_PhysicsPropertiesobsolete.h create mode 100644 source/gameengine/Ketsji/KX_PolygonMaterial.cpp create mode 100644 source/gameengine/Ketsji/KX_PolygonMaterial.h create mode 100644 source/gameengine/Ketsji/KX_PositionInterpolator.cpp create mode 100644 source/gameengine/Ketsji/KX_PositionInterpolator.h create mode 100644 source/gameengine/Ketsji/KX_PyConstraintBinding.cpp create mode 100644 source/gameengine/Ketsji/KX_PyConstraintBinding.h create mode 100644 source/gameengine/Ketsji/KX_PyMath.cpp create mode 100644 source/gameengine/Ketsji/KX_PyMath.h create mode 100644 source/gameengine/Ketsji/KX_PythonInit.cpp create mode 100644 source/gameengine/Ketsji/KX_PythonInit.h create mode 100644 source/gameengine/Ketsji/KX_RadarSensor.cpp create mode 100644 source/gameengine/Ketsji/KX_RadarSensor.h create mode 100644 source/gameengine/Ketsji/KX_RayCast.cpp create mode 100644 source/gameengine/Ketsji/KX_RayCast.h create mode 100644 source/gameengine/Ketsji/KX_RayEventManager.cpp create mode 100644 source/gameengine/Ketsji/KX_RayEventManager.h create mode 100644 source/gameengine/Ketsji/KX_RaySensor.cpp create mode 100644 source/gameengine/Ketsji/KX_RaySensor.h create mode 100644 source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp create mode 100644 source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h create mode 100644 source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp create mode 100644 source/gameengine/Ketsji/KX_SCA_EndObjectActuator.h create mode 100644 source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp create mode 100644 source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h create mode 100644 source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp create mode 100644 source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.h create mode 100644 source/gameengine/Ketsji/KX_SG_NodeRelationships.cpp create mode 100644 source/gameengine/Ketsji/KX_SG_NodeRelationships.h create mode 100644 source/gameengine/Ketsji/KX_ScalarInterpolator.cpp create mode 100644 source/gameengine/Ketsji/KX_ScalarInterpolator.h create mode 100644 source/gameengine/Ketsji/KX_ScalingInterpolator.cpp create mode 100644 source/gameengine/Ketsji/KX_ScalingInterpolator.h create mode 100644 source/gameengine/Ketsji/KX_Scene.cpp create mode 100644 source/gameengine/Ketsji/KX_Scene.h create mode 100644 source/gameengine/Ketsji/KX_SceneActuator.cpp create mode 100644 source/gameengine/Ketsji/KX_SceneActuator.h create mode 100644 source/gameengine/Ketsji/KX_SoundActuator.cpp create mode 100644 source/gameengine/Ketsji/KX_SoundActuator.h create mode 100644 source/gameengine/Ketsji/KX_SumoPhysicsController.cpp create mode 100644 source/gameengine/Ketsji/KX_SumoPhysicsController.h create mode 100644 source/gameengine/Ketsji/KX_TimeCategoryLogger.cpp create mode 100644 source/gameengine/Ketsji/KX_TimeCategoryLogger.h create mode 100644 source/gameengine/Ketsji/KX_TimeLogger.cpp create mode 100644 source/gameengine/Ketsji/KX_TimeLogger.h create mode 100644 source/gameengine/Ketsji/KX_TouchEventManager.cpp create mode 100644 source/gameengine/Ketsji/KX_TouchEventManager.h create mode 100644 source/gameengine/Ketsji/KX_TouchSensor.cpp create mode 100644 source/gameengine/Ketsji/KX_TouchSensor.h create mode 100644 source/gameengine/Ketsji/KX_TrackToActuator.cpp create mode 100644 source/gameengine/Ketsji/KX_TrackToActuator.h create mode 100644 source/gameengine/Ketsji/KX_VehicleWrapper.cpp create mode 100644 source/gameengine/Ketsji/KX_VehicleWrapper.h create mode 100644 source/gameengine/Ketsji/KX_VertexProxy.cpp create mode 100644 source/gameengine/Ketsji/KX_VertexProxy.h create mode 100644 source/gameengine/Ketsji/KX_VisibilityActuator.cpp create mode 100644 source/gameengine/Ketsji/KX_VisibilityActuator.h create mode 100644 source/gameengine/Ketsji/KX_WorldInfo.cpp create mode 100644 source/gameengine/Ketsji/KX_WorldInfo.h create mode 100644 source/gameengine/Ketsji/KX_WorldIpoController.cpp create mode 100644 source/gameengine/Ketsji/KX_WorldIpoController.h create mode 100644 source/gameengine/Ketsji/Makefile create mode 100644 source/gameengine/Ketsji/SConscript create mode 100644 source/gameengine/Makefile create mode 100644 source/gameengine/Network/CMakeLists.txt create mode 100644 source/gameengine/Network/LoopBackNetwork/CMakeLists.txt create mode 100644 source/gameengine/Network/LoopBackNetwork/Makefile create mode 100644 source/gameengine/Network/LoopBackNetwork/NG_LoopBackNetworkDeviceInterface.cpp create mode 100644 source/gameengine/Network/LoopBackNetwork/NG_LoopBackNetworkDeviceInterface.h create mode 100644 source/gameengine/Network/LoopBackNetwork/SConscript create mode 100644 source/gameengine/Network/Makefile create mode 100644 source/gameengine/Network/NG_NetworkDeviceInterface.h create mode 100644 source/gameengine/Network/NG_NetworkMessage.cpp create mode 100644 source/gameengine/Network/NG_NetworkMessage.h create mode 100644 source/gameengine/Network/NG_NetworkObject.cpp create mode 100644 source/gameengine/Network/NG_NetworkObject.h create mode 100644 source/gameengine/Network/NG_NetworkScene.cpp create mode 100644 source/gameengine/Network/NG_NetworkScene.h create mode 100644 source/gameengine/Network/SConscript create mode 100644 source/gameengine/Network/TerraplayNetwork/Makefile create mode 100644 source/gameengine/Network/TerraplayNetwork/NG_TerraplayNetworkDeviceInterface.cpp create mode 100644 source/gameengine/Network/TerraplayNetwork/NG_TerraplayNetworkDeviceInterface.h create mode 100644 source/gameengine/Physics/BlOde/Makefile create mode 100644 source/gameengine/Physics/BlOde/OdePhysicsController.cpp create mode 100644 source/gameengine/Physics/BlOde/OdePhysicsController.h create mode 100644 source/gameengine/Physics/BlOde/OdePhysicsEnvironment.cpp create mode 100644 source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h create mode 100644 source/gameengine/Physics/BlOde/SConscript create mode 100644 source/gameengine/Physics/Bullet/CMakeLists.txt create mode 100644 source/gameengine/Physics/Bullet/CcdPhysicsController.cpp create mode 100644 source/gameengine/Physics/Bullet/CcdPhysicsController.h create mode 100644 source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp create mode 100644 source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h create mode 100644 source/gameengine/Physics/Bullet/Makefile create mode 100644 source/gameengine/Physics/Bullet/SConscript create mode 100644 source/gameengine/Physics/Dummy/CMakeLists.txt create mode 100644 source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp create mode 100644 source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h create mode 100644 source/gameengine/Physics/Dummy/Makefile create mode 100644 source/gameengine/Physics/Dummy/SConscript create mode 100644 source/gameengine/Physics/Makefile create mode 100644 source/gameengine/Physics/Sumo/CMakeLists.txt create mode 100644 source/gameengine/Physics/Sumo/Fuzzics/Makefile create mode 100644 source/gameengine/Physics/Sumo/Fuzzics/include/SM_Callback.h create mode 100644 source/gameengine/Physics/Sumo/Fuzzics/include/SM_ClientObjectInfo.h create mode 100644 source/gameengine/Physics/Sumo/Fuzzics/include/SM_Debug.h create mode 100644 source/gameengine/Physics/Sumo/Fuzzics/include/SM_FhObject.h create mode 100644 source/gameengine/Physics/Sumo/Fuzzics/include/SM_MotionState.h create mode 100644 source/gameengine/Physics/Sumo/Fuzzics/include/SM_Object.h create mode 100644 source/gameengine/Physics/Sumo/Fuzzics/include/SM_Props.h create mode 100644 source/gameengine/Physics/Sumo/Fuzzics/include/SM_Scene.h create mode 100644 source/gameengine/Physics/Sumo/Fuzzics/sample/Makefile create mode 100644 source/gameengine/Physics/Sumo/Fuzzics/sample/particle.cpp create mode 100644 source/gameengine/Physics/Sumo/Fuzzics/sample/particle0.cpp create mode 100644 source/gameengine/Physics/Sumo/Fuzzics/src/Makefile create mode 100644 source/gameengine/Physics/Sumo/Fuzzics/src/SM_FhObject.cpp create mode 100644 source/gameengine/Physics/Sumo/Fuzzics/src/SM_MotionState.cpp create mode 100644 source/gameengine/Physics/Sumo/Fuzzics/src/SM_Object.cpp create mode 100644 source/gameengine/Physics/Sumo/Fuzzics/src/SM_Scene.cpp create mode 100644 source/gameengine/Physics/Sumo/Makefile create mode 100644 source/gameengine/Physics/Sumo/SConscript create mode 100644 source/gameengine/Physics/Sumo/SumoPHYCallbackBridge.cpp create mode 100644 source/gameengine/Physics/Sumo/SumoPHYCallbackBridge.h create mode 100644 source/gameengine/Physics/Sumo/SumoPhysicsController.cpp create mode 100644 source/gameengine/Physics/Sumo/SumoPhysicsController.h create mode 100644 source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp create mode 100644 source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h create mode 100644 source/gameengine/Physics/Sumo/convert.txt create mode 100644 source/gameengine/Physics/Sumo/include/interpolator.h create mode 100644 source/gameengine/Physics/common/CMakeLists.txt create mode 100644 source/gameengine/Physics/common/Makefile create mode 100644 source/gameengine/Physics/common/PHY_DynamicTypes.h create mode 100644 source/gameengine/Physics/common/PHY_IMotionState.cpp create mode 100644 source/gameengine/Physics/common/PHY_IMotionState.h create mode 100644 source/gameengine/Physics/common/PHY_IPhysicsController.cpp create mode 100644 source/gameengine/Physics/common/PHY_IPhysicsController.h create mode 100644 source/gameengine/Physics/common/PHY_IPhysicsEnvironment.cpp create mode 100644 source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h create mode 100644 source/gameengine/Physics/common/PHY_IVehicle.cpp create mode 100644 source/gameengine/Physics/common/PHY_IVehicle.h create mode 100644 source/gameengine/Physics/common/PHY_Pro.h create mode 100644 source/gameengine/Physics/common/SConscript create mode 100644 source/gameengine/PyDoc/BL_ActionActuator.py create mode 100644 source/gameengine/PyDoc/GameKeys.py create mode 100644 source/gameengine/PyDoc/GameLogic.py create mode 100644 source/gameengine/PyDoc/KX_CDActuator.py create mode 100644 source/gameengine/PyDoc/KX_Camera.py create mode 100644 source/gameengine/PyDoc/KX_CameraActuator.py create mode 100644 source/gameengine/PyDoc/KX_ConstraintActuator.py create mode 100644 source/gameengine/PyDoc/KX_GameActuator.py create mode 100644 source/gameengine/PyDoc/KX_GameObject.py create mode 100644 source/gameengine/PyDoc/KX_IpoActuator.py create mode 100644 source/gameengine/PyDoc/KX_Light.py create mode 100644 source/gameengine/PyDoc/KX_MeshProxy.py create mode 100644 source/gameengine/PyDoc/KX_MouseFocusSensor.py create mode 100644 source/gameengine/PyDoc/KX_NearSensor.py create mode 100644 source/gameengine/PyDoc/KX_NetworkMessageActuator.py create mode 100644 source/gameengine/PyDoc/KX_NetworkMessageSensor.py create mode 100644 source/gameengine/PyDoc/KX_ObjectActuator.py create mode 100644 source/gameengine/PyDoc/KX_PolygonMaterial.py create mode 100644 source/gameengine/PyDoc/KX_RadarSensor.py create mode 100644 source/gameengine/PyDoc/KX_RaySensor.py create mode 100644 source/gameengine/PyDoc/KX_SCA_AddObjectActuator.py create mode 100644 source/gameengine/PyDoc/KX_SCA_EndObjectActuator.py create mode 100644 source/gameengine/PyDoc/KX_SCA_ReplaceMeshActuator.py create mode 100644 source/gameengine/PyDoc/KX_Scene.py create mode 100644 source/gameengine/PyDoc/KX_SceneActuator.py create mode 100644 source/gameengine/PyDoc/KX_SoundActuator.py create mode 100644 source/gameengine/PyDoc/KX_TouchSensor.py create mode 100644 source/gameengine/PyDoc/KX_TrackToActuator.py create mode 100644 source/gameengine/PyDoc/KX_VertexProxy.py create mode 100644 source/gameengine/PyDoc/KX_VisibilityActuator.py create mode 100644 source/gameengine/PyDoc/Makefile create mode 100644 source/gameengine/PyDoc/Rasterizer.py create mode 100644 source/gameengine/PyDoc/SCA_ANDController.py create mode 100644 source/gameengine/PyDoc/SCA_AlwaysSensor.py create mode 100644 source/gameengine/PyDoc/SCA_IActuator.py create mode 100644 source/gameengine/PyDoc/SCA_IController.py create mode 100644 source/gameengine/PyDoc/SCA_ILogicBrick.py create mode 100644 source/gameengine/PyDoc/SCA_ISensor.py create mode 100644 source/gameengine/PyDoc/SCA_KeyboardSensor.py create mode 100644 source/gameengine/PyDoc/SCA_MouseSensor.py create mode 100644 source/gameengine/PyDoc/SCA_ORController.py create mode 100644 source/gameengine/PyDoc/SCA_PropertyActuator.py create mode 100644 source/gameengine/PyDoc/SCA_PropertySensor.py create mode 100644 source/gameengine/PyDoc/SCA_PythonController.py create mode 100644 source/gameengine/PyDoc/SCA_RandomActuator.py create mode 100644 source/gameengine/PyDoc/SCA_RandomSensor.py create mode 100644 source/gameengine/PyDoc/WhatsNew.py create mode 100644 source/gameengine/Rasterizer/CMakeLists.txt create mode 100644 source/gameengine/Rasterizer/Makefile create mode 100644 source/gameengine/Rasterizer/RAS_BucketManager.cpp create mode 100644 source/gameengine/Rasterizer/RAS_BucketManager.h create mode 100644 source/gameengine/Rasterizer/RAS_CameraData.h create mode 100644 source/gameengine/Rasterizer/RAS_Deformer.h create mode 100644 source/gameengine/Rasterizer/RAS_FramingManager.cpp create mode 100644 source/gameengine/Rasterizer/RAS_FramingManager.h create mode 100644 source/gameengine/Rasterizer/RAS_ICanvas.h create mode 100644 source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp create mode 100644 source/gameengine/Rasterizer/RAS_IPolygonMaterial.h create mode 100644 source/gameengine/Rasterizer/RAS_IRasterizer.h create mode 100644 source/gameengine/Rasterizer/RAS_IRenderTools.cpp create mode 100644 source/gameengine/Rasterizer/RAS_IRenderTools.h create mode 100644 source/gameengine/Rasterizer/RAS_LightObject.h create mode 100644 source/gameengine/Rasterizer/RAS_MaterialBucket.cpp create mode 100644 source/gameengine/Rasterizer/RAS_MaterialBucket.h create mode 100644 source/gameengine/Rasterizer/RAS_MeshObject.cpp create mode 100644 source/gameengine/Rasterizer/RAS_MeshObject.h create mode 100644 source/gameengine/Rasterizer/RAS_ObjectColor.h create mode 100644 source/gameengine/Rasterizer/RAS_OpenGLRasterizer/ARB_multitexture.h create mode 100644 source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt create mode 100644 source/gameengine/Rasterizer/RAS_OpenGLRasterizer/EXT_separate_specular_color.h create mode 100644 source/gameengine/Rasterizer/RAS_OpenGLRasterizer/Makefile create mode 100644 source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.cpp create mode 100644 source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.h create mode 100644 source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp create mode 100644 source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h create mode 100644 source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp create mode 100644 source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h create mode 100644 source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.cpp create mode 100644 source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.h create mode 100644 source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript create mode 100644 source/gameengine/Rasterizer/RAS_OpenGLRasterizer/glext.h create mode 100644 source/gameengine/Rasterizer/RAS_OpenGLRasterizer/mkglext.py create mode 100644 source/gameengine/Rasterizer/RAS_Polygon.cpp create mode 100644 source/gameengine/Rasterizer/RAS_Polygon.h create mode 100644 source/gameengine/Rasterizer/RAS_Rect.h create mode 100644 source/gameengine/Rasterizer/RAS_TexMatrix.h create mode 100644 source/gameengine/Rasterizer/RAS_TexVert.cpp create mode 100644 source/gameengine/Rasterizer/RAS_TexVert.h create mode 100644 source/gameengine/Rasterizer/RAS_texmatrix.cpp create mode 100644 source/gameengine/Rasterizer/SConscript create mode 100644 source/gameengine/SConscript create mode 100644 source/gameengine/SceneGraph/CMakeLists.txt create mode 100644 source/gameengine/SceneGraph/Makefile create mode 100644 source/gameengine/SceneGraph/SConscript create mode 100644 source/gameengine/SceneGraph/SG_BBox.cpp create mode 100644 source/gameengine/SceneGraph/SG_BBox.h create mode 100644 source/gameengine/SceneGraph/SG_Controller.cpp create mode 100644 source/gameengine/SceneGraph/SG_Controller.h create mode 100644 source/gameengine/SceneGraph/SG_IObject.cpp create mode 100644 source/gameengine/SceneGraph/SG_IObject.h create mode 100644 source/gameengine/SceneGraph/SG_Node.cpp create mode 100644 source/gameengine/SceneGraph/SG_Node.h create mode 100644 source/gameengine/SceneGraph/SG_ParentRelation.h create mode 100644 source/gameengine/SceneGraph/SG_Spatial.cpp create mode 100644 source/gameengine/SceneGraph/SG_Spatial.h create mode 100644 source/gameengine/SceneGraph/SG_Tree.cpp create mode 100644 source/gameengine/SceneGraph/SG_Tree.h create mode 100644 source/icons/Makefile create mode 100644 source/icons/SConscript create mode 100644 source/icons/winblender.ico create mode 100644 source/icons/winblender.rc create mode 100644 source/icons/winblender.rcscons create mode 100644 source/icons/winblenderfile.ico create mode 100644 source/icons/wincreator.ico create mode 100644 source/icons/wincreator.rc create mode 100644 source/icons/winlockedfile.ico create mode 100644 source/icons/winplayer.ico create mode 100644 source/icons/winplayer.rc create mode 100644 source/icons/winpublisher.ico create mode 100644 source/icons/winpublisher.rc create mode 100644 source/kernel/CMakeLists.txt create mode 100644 source/kernel/Makefile create mode 100644 source/kernel/SConscript create mode 100644 source/kernel/gen_messaging/GEN_messaging.h create mode 100644 source/kernel/gen_messaging/Makefile create mode 100644 source/kernel/gen_messaging/intern/Makefile create mode 100644 source/kernel/gen_messaging/intern/messaging.c create mode 100644 source/kernel/gen_system/GEN_DataCache.h create mode 100644 source/kernel/gen_system/GEN_HashedPtr.cpp create mode 100644 source/kernel/gen_system/GEN_HashedPtr.h create mode 100644 source/kernel/gen_system/GEN_Map.h create mode 100644 source/kernel/gen_system/GEN_Matrix4x4.cpp create mode 100644 source/kernel/gen_system/GEN_Matrix4x4.h create mode 100644 source/kernel/gen_system/GEN_SmartPtr.h create mode 100644 source/kernel/gen_system/Makefile create mode 100644 source/kernel/gen_system/SYS_SingletonSystem.cpp create mode 100644 source/kernel/gen_system/SYS_SingletonSystem.h create mode 100644 source/kernel/gen_system/SYS_System.cpp create mode 100644 source/kernel/gen_system/SYS_System.h create mode 100644 source/nan_compile.mk create mode 100644 source/nan_definitions.mk create mode 100644 source/nan_link.mk create mode 100644 source/nan_subdirs.mk create mode 100644 source/nan_warn.mk create mode 100644 tools/Blender.py create mode 100644 tools/__init__.py create mode 100755 tools/bcolors.py create mode 100755 tools/btools.py create mode 100755 tools/crossmingw.py create mode 100755 tools/mstoolkit.py diff --git a/CMake/macros.cmake b/CMake/macros.cmake new file mode 100644 index 00000000000..6b6837d25f0 --- /dev/null +++ b/CMake/macros.cmake @@ -0,0 +1,81 @@ +MACRO(BLENDERLIB_NOLIST + name + sources + includes) + + # Gather all headers + FILE(GLOB_RECURSE INC_ALL *.h) + + INCLUDE_DIRECTORIES(${includes}) + ADD_LIBRARY(${name} ${INC_ALL} ${sources}) + + # Group by location on disk + SOURCE_GROUP(Files FILES CMakeLists.txt) + SET(ALL_FILES ${sources} ${INC_ALL}) + FOREACH(SRC ${ALL_FILES}) + STRING(REGEX REPLACE ${CMAKE_CURRENT_SOURCE_DIR} "Files" REL_DIR "${SRC}") + STRING(REGEX REPLACE "[\\\\/][^\\\\/]*$" "" REL_DIR "${REL_DIR}") + STRING(REGEX REPLACE "^[\\\\/]" "" REL_DIR "${REL_DIR}") + IF(REL_DIR) + SOURCE_GROUP(${REL_DIR} FILES ${SRC}) + ELSE(REL_DIR) + SOURCE_GROUP(Files FILES ${SRC}) + ENDIF(REL_DIR) + ENDFOREACH(SRC) + + MESSAGE(STATUS "Configuring library ${name}") +ENDMACRO(BLENDERLIB_NOLIST) + +MACRO(BLENDERLIB + name + sources + includes) + + BLENDERLIB_NOLIST(${name} "${sources}" "${includes}") + + # Add to blender's list of libraries + FILE(APPEND ${CMAKE_BINARY_DIR}/cmake_blender_libs.txt "${name};") +ENDMACRO(BLENDERLIB) + +MACRO(SETUP_LIBDIRS) + LINK_DIRECTORIES(${PYTHON_LIBPATH} ${SDL_LIBPATH} ${JPEG_LIBPATH} ${PNG_LIBPATH} ${ZLIB_LIBPATH} ${ICONV_LIBPATH} ${OPENEXR_LIBPATH} ${QUICKTIME_LIBPATH} ${FFMPEG_LIBPATH}) + IF(WITH_INTERNATIONAL) + LINK_DIRECTORIES(${GETTEXT_LIBPATH}) + LINK_DIRECTORIES(${FREETYPE_LIBPATH}) + ENDIF(WITH_INTERNATIONAL) + IF(WITH_OPENAL) + LINK_DIRECTORIES(${OPENAL_LIBPATH}) + ENDIF(WITH_OPENAL) + + IF(WIN32) + LINK_DIRECTORIES(${PTHREADS_LIBPATH}) + ENDIF(WIN32) +ENDMACRO(SETUP_LIBDIRS) + +MACRO(SETUP_LIBLINKS + target) + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS} ") + TARGET_LINK_LIBRARIES(${target} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} ${PYTHON_LIB} ${PYTHON_LINKFLAGS} ${JPEG_LIB} ${PNG_LIB} ${ZLIB_LIB} ${SDL_LIB} ${LLIBS}) + IF(WITH_INTERNATIONAL) + TARGET_LINK_LIBRARIES(${target} ${FREETYPE_LIB}) + TARGET_LINK_LIBRARIES(${target} ${GETTEXT_LIB}) + ENDIF(WITH_INTERNATIONAL) + IF(WITH_OPENAL) + TARGET_LINK_LIBRARIES(${target} ${OPENAL_LIB}) + ENDIF(WITH_OPENAL) + IF(WIN32) + TARGET_LINK_LIBRARIES(${target} ${ICONV_LIB}) + ENDIF(WIN32) + IF(WITH_QUICKTIME) + TARGET_LINK_LIBRARIES(${target} ${QUICKTIME_LIB}) + ENDIF(WITH_QUICKTIME) + IF(WITH_OPENEXR) + TARGET_LINK_LIBRARIES(${target} ${OPENEXR_LIB}) + ENDIF(WITH_OPENEXR) + IF(WITH_FFMPEG) + TARGET_LINK_LIBRARIES(${target} ${FFMPEG_LIB}) + ENDIF(WITH_FFMPEG) + IF(WIN32) + TARGET_LINK_LIBRARIES(${target} ${PTHREADS_LIB}) + ENDIF(WIN32) +ENDMACRO(SETUP_LIBLINKS) diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000000..0227c51f39d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,408 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +#----------------------------------------------------------------------------- +# We don't allow in-source builds. This causes no end of troubles because +# all out-of-source builds will use the CMakeCache.txt file there and even +# build the libs and objects in it. It will also conflict with the current +# Makefile system for Blender + +IF(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) +MESSAGE(FATAL_ERROR "CMake generation for blender is not allowed within the source directory! +Remove the CMakeCache.txt file and try again from another folder, e.g.: + + rm CMakeCache.txt + cd .. + mkdir cmake-make + cd cmake-make + cmake -G \"Unix Makefiles\" ../blender +") +ENDIF(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) + +CMAKE_MINIMUM_REQUIRED(VERSION 2.4) +PROJECT(Blender) + +#----------------------------------------------------------------------------- +# Redirect output files + +SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) +SET(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib) + +#----------------------------------------------------------------------------- +# Set default config options +OPTION(WITH_PLAYER "Build Player" OFF) +OPTION(WITH_GAMEENGINE "Enable Game Engine" ON) +OPTION(WITH_BULLET "Enable Bullet (Physics Engine)" ON) +OPTION(WITH_INTERNATIONAL "Enable I18N (International fonts and text)" ON) +OPTION(WITH_VERSE "Enable Verse (http://verse.blender.org)" OFF) +OPTION(WITH_ELBEEM "Enable Elbeem (Fluid Simulation)" ON) +OPTION(WITH_QUICKTIME "Enable Quicktime Support" OFF) +OPTION(WITH_OPENEXR "Enable OpenEXR Support (http://www.openexr.com)" OFF) +OPTION(WITH_FFMPEG "Enable FFMPeg Support (http://ffmpeg.mplayerhq.hu/)" OFF) +OPTION(WITH_OPENAL "Enable OpenAL Support (http://www.openal.org)" ON) +OPTION(YESIAMSTUPID "Enable execution on 64-bit platforms" OFF) + +IF(NOT WITH_GAMEENGINE AND WITH_PLAYER) + MESSAGE("WARNING: WITH_PLAYER needs WITH_GAMEENGINE") +ENDIF(NOT WITH_GAMEENGINE AND WITH_PLAYER) + +# For alternate Python locations the commandline can be used to override detected/default cache settings, e.g: +# On Unix: +# cmake -D PYTHON_LIB=/usr/local/lib/python2.3/config/libpython2.3.so -D PYTHON_INC=/usr/local/include/python2.3 -D PYTHON_BINARY=/usr/local/bin/python2.3 -G "Unix Makefiles" ../blender +# On Macs: +# cmake -D PYTHON_INC=/System/Library/Frameworks/Python.framework/Versions/2.5/include/python2.5 -D PYTHON_LIBPATH=/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/config -D PYTHON_BINARY=/System/Library/Frameworks/Python.framework/Versions/2.5/bin/python2.5 -G Xcode ../blender +# +# When changing any of this remember to update the notes in doc/blender-cmake.txt + +#----------------------------------------------------------------------------- +# Load some macros. +INCLUDE(CMake/macros.cmake) + +#----------------------------------------------------------------------------- +#Platform specifics + +IF(UNIX) + INCLUDE(${CMAKE_ROOT}/Modules/FindOpenAL.cmake) + IF(OPENAL_FOUND) + SET(WITH_OPENAL ON) + SET(OPENAL_LIB ${OPENAL_LIBRARY}) + SET(OPENAL_INC ${OPENAL_INCLUDE_DIR}) + ELSE(OPENAL_FOUND) + SET(WITH_OPENAL OFF) + ENDIF(OPENAL_FOUND) + + FIND_LIBRARY(ALUT_LIBRARY + NAMES alut + PATHS + /usr/local/lib + /usr/lib + /sw/lib + /opt/local/lib + /opt/csw/lib + /opt/lib + ) + IF(ALUT_LIBRARY) + SET(OPENAL_LIB ${OPENAL_LIB} ${ALUT_LIBRARY}) + ENDIF(ALUT_LIBRARY) + + FIND_LIBRARY(INTL_LIBRARY + NAMES intl + PATHS + /usr/local/lib + /usr/lib + /sw/lib + /opt/local/lib + /opt/csw/lib + /opt/lib + ) + FIND_LIBRARY(ICONV_LIBRARY + NAMES iconv + PATHS + /usr/local/lib + /usr/lib + /sw/lib + /opt/local/lib + /opt/csw/lib + /opt/lib + ) + IF(INTL_LIBRARY AND ICONV_LIBRARY) + SET(GETTEXT_LIB ${INTL_LIBRARY} ${ICONV_LIBRARY}) + ENDIF(INTL_LIBRARY AND ICONV_LIBRARY) + + FIND_PATH(FREETYPE_INC + freetype + PATHS + /usr/local/include/freetype2 + /usr/include/freetype2 + /sw/include/freetype2 + /opt/local/include/freetype2 + /opt/csw/include/freetype2 + /opt/include/freetype2 + NO_DEFAULT_PATH + ) + SET(FREETYPE_LIB freetype) + + INCLUDE(${CMAKE_ROOT}/Modules/FindPythonLibs.cmake) + SET(PYTHON_INC "${PYTHON_INCLUDE_PATH}" CACHE STRING "") + SET(PYTHON_LIB "${PYTHON_LIBRARIES}" CACHE STRING "") + INCLUDE(${CMAKE_ROOT}/Modules/FindPythonInterp.cmake) + SET(PYTHON_BINARY ${PYTHON_EXECUTABLE} CACHE STRING "") + SET(PYTHON_LINKFLAGS "-Xlinker -export-dynamic") + + INCLUDE(${CMAKE_ROOT}/Modules/FindSDL.cmake) + SET(SDL_INC ${SDL_INCLUDE_DIR}) + SET(SDL_LIB ${SDL_LIBRARY}) + + FIND_PATH(OPENEXR_INC + ImfXdr.h + PATHS + /usr/local/include/OpenEXR + /usr/include/OpenEXR + /sw/include/OpenEXR + /opt/local/include/OpenEXR + /opt/csw/include/OpenEXR + /opt/include/OpenEXR + ) + SET(OPENEXR_LIB Half IlmImf Iex Imath) + + SET(FFMPEG /usr) + SET(FFMPEG_INC ${FFMPEG}/include) + SET(FFMPEG_LIB avformat avcodec avutil) + SET(FFMPEG_LIBPATH ${FFMPEG}/lib) + + SET(JPEG_LIB jpeg) + + SET(PNG_LIB png) + + SET(ZLIB_LIB z) + + SET(LLIBS "-lXi -lutil -lc -lm -lpthread -lstdc++") + + SET(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing -DXP_UNIX -Wno-char-subscripts") + + SET(PLATFORM_LINKFLAGS "-pthread") + + INCLUDE_DIRECTORIES(/usr/include /usr/local/include) +ENDIF(UNIX) + +IF(WIN32) + INCLUDE(${CMAKE_ROOT}/Modules/Platform/Windows-cl.cmake) + + SET(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/windows) + + SET(PYTHON ${LIBDIR}/python) + SET(PYTHON_VERSION 2.5) + SET(PYTHON_INC "${PYTHON}/include/python${PYTHON_VERSION}") + SET(PYTHON_BINARY python) + SET(PYTHON_LIB python25) + SET(PYTHON_LIBPATH ${PYTHON}/lib) + + #SET(WITH_OPENAL ON) + SET(OPENAL ${LIBDIR}/openal) + SET(OPENAL_INC ${OPENAL}/include ${OPENAL}/include/AL) + SET(OPENAL_LIB openal_static) + SET(OPENAL_LIBPATH ${OPENAL}/lib) + + SET(PNG_LIB libpng_st) + SET(JPEG_LIB libjpeg) + + SET(ZLIB ${LIBDIR}/zlib) + SET(ZLIB_INC ${ZLIB}/include) + SET(ZLIB_LIB libz) + SET(ZLIB_LIBPATH ${ZLIB}/lib) + + SET(PTHREADS ${LIBDIR}/pthreads) + SET(PTHREADS_INC ${PTHREADS}/include) + SET(PTHREADS_LIB pthreadVC2) + SET(PTHREADS_LIBPATH ${PTHREADS}/lib) + + SET(ICONV ${LIBDIR}/iconv) + SET(ICONV_INC ${ICONV}/include) + SET(ICONV_LIB iconv) + SET(ICONV_LIBPATH ${ICONV}/lib) + + SET(GETTEXT ${LIBDIR}/gettext) + SET(GETTEXT_INC ${GETTEXT}/include) + SET(GETTEXT_LIB gnu_gettext) + SET(GETTEXT_LIBPATH ${GETTEXT}/lib) + + SET(FREETYPE ${LIBDIR}/freetype) + SET(FREETYPE_INC ${FREETYPE}/include ${FREETYPE}/include/freetype2) + SET(FREETYPE_LIBPATH ${FREETYPE}/lib) + SET(FREETYPE_LIB freetype2ST) + + SET(OPENEXR ${LIBDIR}/openexr) + SET(OPENEXR_INC ${OPENEXR}/include ${OPENEXR}/include/IlmImf ${OPENEXR}/include/Iex ${OPENEXR}/include/Imath) + SET(OPENEXR_LIB Iex Half IlmImf Imath IlmThread) + IF (MSVC80) + SET(OPENEXR_LIBPATH ${OPENEXR}/lib_vs2005) + ELSE (MSVC80) + SET(OPENEXR_LIBPATH ${OPENEXR}/lib_msvc) + ENDIF(MSVC80) + + SET(QUICKTIME ${LIBDIR}/QTDevWin) + SET(QUICKTIME_INC ${QUICKTIME}/CIncludes) + SET(QUICKTIME_LIB qtmlClient) + SET(QUICKTIME_LIBPATH ${QUICKTIME}/Libraries) + + SET(FFMPEG ${LIBDIR}/ffmpeg) + SET(FFMPEG_INC ${FFMPEG}/include) + SET(FFMPEG_LIB avcodec-51 avformat-51 avutil-49) + SET(FFMPEG_LIBPATH ${FFMPEG}/lib) + + SET(LLIBS kernel32 user32 gdi32 comdlg32 advapi32 shell32 ole32 oleaut32 uuid ws2_32 vfw32 winmm) + IF(WITH_OPENAL) + SET(LLIBS ${LLIBS} dxguid) + ENDIF(WITH_OPENAL) + + SET(CMAKE_CXX_FLAGS_DEBUG "/D_CRT_NONSTDC_NO_DEPRECATE /D_CRT_SECURE_NO_DEPRECATE /D_SCL_SECURE_NO_DEPRECATE /wd4800 /wd4244 /wd4305 /D_DEBUG /Od /Gm /EHsc /RTC1 /MTd /W3 /nologo /ZI /J" CACHE STRING "MSVC MT flags " FORCE) + SET(CMAKE_CXX_FLAGS_RELEASE "/D_CRT_NONSTDC_NO_DEPRECATE /D_CRT_SECURE_NO_DEPRECATE /D_SCL_SECURE_NO_DEPRECATE /wd4800 /wd4244 /wd4305 /O2 /Ob2 /DNDEBUG /EHsc /MT /W3 /nologo /J" CACHE STRING "MSVC MT flags " FORCE) + SET(CMAKE_CXX_FLAGS_MINSIZEREL "/D_CRT_NONSTDC_NO_DEPRECATE /D_CRT_SECURE_NO_DEPRECATE /D_SCL_SECURE_NO_DEPRECATE /wd4800 /wd4244 /wd4305 /O1 /Ob1 /DNDEBUG /EHsc /MT /W3 /nologo /J" CACHE STRING "MSVC MT flags " FORCE) + SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "/D_CRT_NONSTDC_NO_DEPRECATE /D_CRT_SECURE_NO_DEPRECATE /D_SCL_SECURE_NO_DEPRECATE /wd4800 /wd4244 /wd4305 /O2 /Ob1 /DNDEBUG /EHsc /MT /W3 /nologo /Zi /J" CACHE STRING "MSVC MT flags " FORCE) + SET(CMAKE_C_FLAGS_DEBUG "/D_CRT_NONSTDC_NO_DEPRECATE /D_CRT_SECURE_NO_DEPRECATE /D_SCL_SECURE_NO_DEPRECATE /wd4800 /wd4244 /wd4305 /D_DEBUG /Od /Gm /EHsc /RTC1 /MTd /W3 /nologo /ZI /J" CACHE STRING "MSVC MT flags " FORCE) + SET(CMAKE_C_FLAGS_RELEASE "/D_CRT_NONSTDC_NO_DEPRECATE /D_CRT_SECURE_NO_DEPRECATE /D_SCL_SECURE_NO_DEPRECATE /wd4800 /wd4244 /wd4305 /O2 /Ob2 /DNDEBUG /EHsc /MT /W3 /nologo /J" CACHE STRING "MSVC MT flags " FORCE) + SET(CMAKE_C_FLAGS_MINSIZEREL "/D_CRT_NONSTDC_NO_DEPRECATE /D_CRT_SECURE_NO_DEPRECATE /D_SCL_SECURE_NO_DEPRECATE /wd4800 /wd4244 /wd4305 /O1 /Ob1 /DNDEBUG /EHsc /MT /W3 /nologo /J" CACHE STRING "MSVC MT flags " FORCE) + SET(CMAKE_C_FLAGS_RELWITHDEBINFO "/D_CRT_NONSTDC_NO_DEPRECATE /D_CRT_SECURE_NO_DEPRECATE /D_SCL_SECURE_NO_DEPRECATE /wd4800 /wd4244 /wd4305 /O2 /Ob1 /DNDEBUG /EHsc /MT /W3 /nologo /Zi /J" CACHE STRING "MSVC MT flags " FORCE) + + SET(SDL ${LIBDIR}/sdl) + SET(SDL_INC ${SDL}/include) + SET(SDL_LIB SDL) + SET(SDL_LIBPATH ${SDL}/lib) + + SET(PNG "${LIBDIR}/png") + SET(PNG_INC "${PNG}/include") + SET(PNG_LIBPATH ${PNG}/lib) + + SET(JPEG "${LIBDIR}/jpeg") + SET(JPEG_INC "${JPEG}/include") + SET(JPEG_LIBPATH ${JPEG}/lib) + + SET(TIFF ${LIBDIR}/tiff) + SET(TIFF_INC ${TIFF}/include) + + SET(WINTAB_INC ${LIBDIR}/wintab/include) + + SET(PLATFORM_LINKFLAGS "/NODEFAULTLIB:libc.lib") + SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /NODEFAULTLIB:libcmt.lib ") +ENDIF(WIN32) + +IF(APPLE) + IF(CMAKE_OSX_ARCHITECTURES MATCHES i386) + SET(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin-8.x.i386) + ELSE(CMAKE_OSX_ARCHITECTURES MATCHES i386) + SET(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin-6.1-powerpc) + ENDIF(CMAKE_OSX_ARCHITECTURES MATCHES i386) + + INCLUDE(${CMAKE_ROOT}/Modules/FindOpenAL.cmake) + IF(OPENAL_FOUND) + SET(WITH_OPENAL ON) + SET(OPENAL_LIB ${OPENAL_LIBRARY}) + SET(OPENAL_INC ${OPENAL_INCLUDE_DIR}) + ELSE(OPENAL_FOUND) + SET(WITH_OPENAL OFF) + ENDIF(OPENAL_FOUND) + + SET(PYTHON /System/Library/Frameworks/Python.framework/Versions/) + SET(PYTHON_VERSION 2.3) + SET(PYTHON_INC "${PYTHON}${PYTHON_VERSION}/include/python${PYTHON_VERSION}" CACHE STRING "") + SET(PYTHON_BINARY ${PYTHON}${PYTHON_VERSION}/bin/python${PYTHON_VERSION} CACHE STRING "") + SET(PYTHON_LIB "") + SET(PYTHON_LIBPATH ${PYTHON}${PYTHON_VERSION}/lib/python${PYTHON_VERSION}/config CACHE STRING "") + SET(PYTHON_LINKFLAGS "-u __dummy -u _PyMac_Error -framework System -framework Python") + + SET(GETTEXT ${LIBDIR}/gettext) + SET(GETTEXT_INC "${GETTEXT}/include") + SET(GETTEXT_LIB intl iconv) + SET(GETTEXT_LIBPATH ${GETTEXT}/lib) + + SET(PNG_LIB png) + SET(JPEG_LIB jpeg) + + SET(ZLIB /usr) + SET(ZLIB_INC "${ZLIB}/include") + SET(ZLIB_LIB z) + + SET(FREETYPE ${LIBDIR}/freetype) + SET(FREETYPE_INC ${FREETYPE}/include ${FREETYPE}/include/freetype2) + SET(FREETYPE_LIBPATH ${FREETYPE}/lib) + SET(FREETYPE_LIB freetype) + + SET(OPENEXR ${LIBDIR}/openexr) + SET(OPENEXR_INC ${OPENEXR}/include/OpenEXR ${OPENEXR}/include) + IF(CMAKE_OSX_ARCHITECTURES MATCHES i386) + SET(OPENEXR_LIB Iex Half IlmImf Imath IlmThread) + ELSE(CMAKE_OSX_ARCHITECTURES MATCHES i386) + SET(OPENEXR_LIB Iex Half IlmImf Imath) + ENDIF(CMAKE_OSX_ARCHITECTURES MATCHES i386) + SET(OPENEXR_LIBPATH ${OPENEXR}/lib) + + SET(LLIBS stdc++ SystemStubs) + + SET(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing") + SET(PLATFORM_LINKFLAGS "-fexceptions -framework CoreServices -framework Foundation -framework IOKit -framework AppKit -framework Carbon -framework AGL -framework AudioUnit -framework AudioToolbox -framework CoreAudio -framework QuickTime") + + SET(SDL ${LIBDIR}/sdl) + SET(SDL_INC ${SDL}/include) + SET(SDL_LIB SDL) + SET(SDL_LIBPATH ${SDL}/lib) + + SET(PNG "${LIBDIR}/png") + SET(PNG_INC "${PNG}/include") + SET(PNG_LIBPATH ${PNG}/lib) + + SET(JPEG "${LIBDIR}/jpeg") + SET(JPEG_INC "${JPEG}/include") + SET(JPEG_LIBPATH ${JPEG}/lib) + + SET(TIFF ${LIBDIR}/tiff) + SET(TIFF_INC ${TIFF}/include) + + SET(EXETYPE MACOSX_BUNDLE) +ENDIF(APPLE) + +#----------------------------------------------------------------------------- +# Common. +SET(VERSE_INC ${CMAKE_SOURCE_DIR}/extern/verse/dist) + +SET(FTGL ${CMAKE_SOURCE_DIR}/extern/bFTGL) +SET(FTGL_INC ${FTGL}/include) +SET(FTGL_LIB extern_ftgl) + + +#----------------------------------------------------------------------------- +# Configure OpenGL. +INCLUDE(${CMAKE_ROOT}/Modules/FindOpenGL.cmake) +INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR}) +#----------------------------------------------------------------------------- +# Extra compile flags +IF(WITH_GAMEENGINE) + SET(PLATFORM_CFLAGS "${PLATFORM_CFLAGS} -DGAMEBLENDER ") +ENDIF(WITH_GAMEENGINE) +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${PLATFORM_CFLAGS} ") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PLATFORM_CFLAGS} ") + +#----------------------------------------------------------------------------- +# Libraries +FILE(WRITE ${CMAKE_BINARY_DIR}/cmake_blender_libs.txt "") +SUBDIRS( + intern + extern + source +) + + +#----------------------------------------------------------------------------- +# Blender Application +SUBDIRS(source/creator) + +#----------------------------------------------------------------------------- +# Blender Player +IF(WITH_PLAYER) + SUBDIRS(blenderplayer) +ENDIF(WITH_PLAYER) diff --git a/COPYING b/COPYING new file mode 100644 index 00000000000..232ee776d87 --- /dev/null +++ b/COPYING @@ -0,0 +1,3 @@ +Please read over both of the following files: +doc/GPL-license.txt +doc/BL-license.txt diff --git a/Makefile b/Makefile new file mode 100644 index 00000000000..b77adf82cfb --- /dev/null +++ b/Makefile @@ -0,0 +1,61 @@ +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2002 by Wouter van Heyst +# All rights reserved. +# +# The Original Code is: revision 1.1 +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# Toplevel Makefile for blender. Bounces make to subdirectories. +# Available targets: 'all' 'debug' 'release' + +# If the user wants to override some of the build +# vars they can put it in the file user-def.mk which +# will get included if it exists (please do not commit +# user-def.mk to cvs). + +sinclude user-def.mk + +# To build without openAL, uncomment the following line, or set it as +# an environment variable, or put it uncommented in user-def.mk: +# export NAN_NO_OPENAL=true + +export NANBLENDERHOME=$(shell pwd) +MAKEFLAGS=-I$(NANBLENDERHOME)/source --no-print-directory + +SOURCEDIR = +ifeq ($(FREE_WINDOWS),true) + DIRS ?= dlltool extern intern source po +endif + +DIRS ?= extern intern source po +include source/nan_subdirs.mk + +.PHONY: release +release: + @echo "====> $(MAKE) $@ in $(SOURCEDIR)/$@" ;\ + $(MAKE) -C $@ $@ || exit 1; + + diff --git a/README b/README new file mode 100644 index 00000000000..d123a90ba48 --- /dev/null +++ b/README @@ -0,0 +1,45 @@ +Welcome to the fun world of open source. + +For instructions on building and installing Blender, please see the file named +INSTALL. + + +---------------------.Blanguages and the .blender directory--------------------- + +The .blender directory holds various data files for Blender. +In the 2.28a release those are the .Blanguages file containing a list of +translations, the translations themselves and a default ttf font. + +Blender checks for the presence of this directory in several locations: + - the current directory + - your home directory + - On OSX, the blender bundle is also checked + - On Windows, the installation dir is checked. + +If you get a 'File ".Blanguages" not found' warning, try to copy the .blender +dir to one of these locations (your home directory being recommended). + + + +-------------------------------------Links-------------------------------------- + +Getting Involved: +http://www.blender.org/docs/get_involved.html + +Community: +http://www.blender3d.org/Community/ + +Main blender development site: +http://www.blender.org/ + +The Blender project homepage: +http://projects.blender.org/projects/bf-blender/ + +Documentation: +http://www.blender.org/modules.php?op=modload&name=documentation&file=index + +Bug tracker: +http://projects.blender.org/tracker/?atid=125&group_id=9&func=browse + +Feature request tracker: +http://projects.blender.org/tracker/?atid=128&group_id=9&func=browse diff --git a/SConstruct b/SConstruct new file mode 100644 index 00000000000..2cacb91d103 --- /dev/null +++ b/SConstruct @@ -0,0 +1,447 @@ +#!/usr/bin/env python +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Nathan Letwory. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# Main entry-point for the SCons building system +# Set up some custom actions and target/argument handling +# Then read all SConscripts and build + +import sys +import os +import os.path +import string +import shutil +import glob +import re + +import tools.Blender +import tools.btools +import tools.bcolors + +BlenderEnvironment = tools.Blender.BlenderEnvironment +btools = tools.btools +B = tools.Blender + +### globals ### +platform = sys.platform +quickie = None +quickdebug = None +nsis_build = None + +##### BEGIN SETUP ##### + +B.possible_types = ['core', 'common', 'blender', 'intern', + 'international', 'game', 'game2', + 'player', 'player2', 'system'] + +B.binarykind = ['blender' , 'blenderplayer'] +################################## +# target and argument validation # +################################## +# XX cheating for BF_FANCY, we check for BF_FANCY before args are validated +use_color = ARGUMENTS.get('BF_FANCY', '1') +if platform=='win32': + use_color = None + +if not use_color=='1': + B.bc.disable() + + #on defaut white Os X terminal, some colors are totally unlegible +if platform=='darwin': + B.bc.OKGREEN = '\033[34m' + B.bc.WARNING = '\033[36m' + +# arguments +print B.bc.HEADER+'Command-line arguments'+B.bc.ENDC +B.arguments = btools.validate_arguments(ARGUMENTS, B.bc) +btools.print_arguments(B.arguments, B.bc) + +# targets +print B.bc.HEADER+'Command-line targets'+B.bc.ENDC +B.targets = btools.validate_targets(COMMAND_LINE_TARGETS, B.bc) +btools.print_targets(B.targets, B.bc) + +########################## +# setting up environment # +########################## + +# handling cmd line arguments & config file + +# first check cmdline for toolset and we create env to work on +quickie = B.arguments.get('BF_QUICK', None) +quickdebug = B.arguments.get('BF_QUICKDEBUG', None) + +if quickdebug: + B.quickdebug=string.split(quickdebug, ',') +else: + B.quickdebug=[] + +if quickie: + B.quickie=string.split(quickie,',') +else: + B.quickie=[] + +toolset = B.arguments.get('BF_TOOLSET', None) +if toolset: + print "Using " + toolset + if toolset=='mstoolkit': + env = BlenderEnvironment(ENV = os.environ) + env.Tool('mstoolkit', ['tools']) + else: + env = BlenderEnvironment(tools=[toolset], ENV = os.environ) + if env: + btools.SetupSpawn(env) +else: + env = BlenderEnvironment(ENV = os.environ) + +if not env: + print "Could not create a build environment" + Exit() + + +cc = B.arguments.get('CC', None) +cxx = B.arguments.get('CXX', None) +if cc: + env['CC'] = cc +if cxx: + env['CXX'] = cxx + +if env['CC'] in ['cl', 'cl.exe'] and sys.platform=='win32': + platform = 'win32-vc' +elif env['CC'] in ['gcc'] and sys.platform=='win32': + platform = 'win32-mingw' + +env.SConscriptChdir(0) + +crossbuild = B.arguments.get('BF_CROSS', None) +if crossbuild and platform!='win32': + platform = 'linuxcross' + +env['OURPLATFORM'] = platform + +configfile = B.arguments.get('BF_CONFIG', 'config'+os.sep+platform+'-config.py') + +if os.path.exists(configfile): + print B.bc.OKGREEN + "Using config file: " + B.bc.ENDC + configfile +else: + print B.bc.FAIL + configfile + " doesn't exist" + B.bc.ENDC + +if crossbuild and env['PLATFORM'] != 'win32': + print B.bc.HEADER+"Preparing for crossbuild"+B.bc.ENDC + env.Tool('crossmingw', ['tools']) + # todo: determine proper libs/includes etc. + # Needed for gui programs, console programs should do without it + env.Append(LINKFLAGS=['-mwindows']) + +# first read platform config. B.arguments will override +optfiles = [configfile] +if os.path.exists('user-config.py'): + print B.bc.OKGREEN + "Using config file: " + B.bc.ENDC + 'user-config.py' + optfiles += ['user-config.py'] +else: + print B.bc.WARNING + 'user-config.py' + " not found, no user overrides" + B.bc.ENDC + +opts = btools.read_opts(optfiles, B.arguments) +opts.Update(env) + +# disable elbeem (fluidsim) compilation? +if env['BF_NO_ELBEEM'] == 1: + env['CPPFLAGS'].append('-DDISABLE_ELBEEM') + env['CXXFLAGS'].append('-DDISABLE_ELBEEM') + env['CCFLAGS'].append('-DDISABLE_ELBEEM') + +#check for additional debug libnames + +if env.has_key('BF_DEBUG_LIBS'): + B.quickdebug += env['BF_DEBUG_LIBS'] + +printdebug = B.arguments.get('BF_LISTDEBUG', 0) + +# see if this linux distro has libalut + +if env['OURPLATFORM'] == 'linux2' : + if env['WITH_BF_OPENAL']: + mylib_test_source_file = """ + #include "AL/alut.h" + int main(int argc, char **argv) + { + alutGetMajorVersion(); + return 0; + } + """ + + def CheckFreeAlut(context,env): + context.Message( B.bc.OKGREEN + "Linux platform detected:\n checking for FreeAlut... " + B.bc.ENDC ) + env['LIBS'] = 'alut' + result = context.TryLink(mylib_test_source_file, '.c') + context.Result(result) + return result + + env2 = env.Copy( LIBPATH = env['BF_OPENAL'] ) + conf = Configure( env2, {'CheckFreeAlut' : CheckFreeAlut}, '.sconf_temp', '/dev/null' ) + if conf.CheckFreeAlut( env2 ): + env['BF_OPENAL_LIB'] += ' alut' + del env2 + for root, dirs, files in os.walk('.sconf_temp', topdown=False): + for name in files: + os.remove(os.path.join(root, name)) + for name in dirs: + os.rmdir(os.path.join(root, name)) + os.rmdir(root) + +if len(B.quickdebug) > 0 and printdebug != 0: + print B.bc.OKGREEN + "Buildings these libs with debug symbols:" + B.bc.ENDC + for l in B.quickdebug: + print "\t" + l + +# check target for blenderplayer. Set WITH_BF_PLAYER if found on cmdline +if 'blenderplayer' in B.targets: + env['WITH_BF_PLAYER'] = True + +if 'blendernogame' in B.targets: + env['WITH_BF_GAMEENGINE'] = False + +# lastly we check for root_build_dir ( we should not do before, otherwise we might do wrong builddir +#B.root_build_dir = B.arguments.get('BF_BUILDDIR', '..'+os.sep+'build'+os.sep+platform+os.sep) +B.root_build_dir = env['BF_BUILDDIR'] +env['BUILDDIR'] = B.root_build_dir +if not B.root_build_dir[-1]==os.sep: + B.root_build_dir += os.sep + +# We do a shortcut for clean when no quicklist is given: just delete +# builddir without reading in SConscripts +do_clean = None +if 'clean' in B.targets: + do_clean = True + +if not quickie and do_clean: + if os.path.exists(B.root_build_dir): + print B.bc.HEADER+'Cleaning...'+B.bc.ENDC + dirs = os.listdir(B.root_build_dir) + for dir in dirs: + if os.path.isdir(B.root_build_dir + dir) == 1: + print "clean dir %s"%(B.root_build_dir+dir) + shutil.rmtree(B.root_build_dir+dir) + print B.bc.OKGREEN+'...done'+B.bc.ENDC + else: + print B.bc.HEADER+'Already Clean, nothing to do.'+B.bc.ENDC + Exit() + +if not os.path.isdir ( B.root_build_dir): + os.makedirs ( B.root_build_dir ) + os.makedirs ( B.root_build_dir + 'source' ) + os.makedirs ( B.root_build_dir + 'intern' ) + os.makedirs ( B.root_build_dir + 'extern' ) + os.makedirs ( B.root_build_dir + 'lib' ) + os.makedirs ( B.root_build_dir + 'bin' ) + +Help(opts.GenerateHelpText(env)) + +# default is new quieter output, but if you need to see the +# commands, do 'scons BF_QUIET=0' +bf_quietoutput = B.arguments.get('BF_QUIET', '1') +if bf_quietoutput=='1': + B.set_quiet_output(env) +else: + if toolset=='msvc': + B.msvc_hack(env) + +print B.bc.HEADER+'Building in '+B.bc.ENDC+B.root_build_dir +env.SConsignFile(B.root_build_dir+'scons-signatures') +B.init_lib_dict() + +##### END SETUP ########## + +Export('env') + +BuildDir(B.root_build_dir+'/intern', 'intern', duplicate=0) +SConscript(B.root_build_dir+'/intern/SConscript') +BuildDir(B.root_build_dir+'/extern', 'extern', duplicate=0) +SConscript(B.root_build_dir+'/extern/SConscript') +BuildDir(B.root_build_dir+'/source', 'source', duplicate=0) +SConscript(B.root_build_dir+'/source/SConscript') + +# now that we have read all SConscripts, we know what +# libraries will be built. Create list of +# libraries to give as objects to linking phase +mainlist = [] +for tp in B.possible_types: + if not tp == 'player' and not tp == 'player2': + mainlist += B.create_blender_liblist(env, tp) + +if B.arguments.get('BF_PRIORITYLIST', '0')=='1': + B.propose_priorities() + +dobj = B.buildinfo(env, "dynamic") + B.resources +thestatlibs, thelibincs = B.setup_staticlibs(env) +thesyslibs = B.setup_syslibs(env) + +env.BlenderProg(B.root_build_dir, "blender", dobj + mainlist + thestatlibs, [], thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blender') +if env['WITH_BF_PLAYER']: + playerlist = B.create_blender_liblist(env, 'player') + env.BlenderProg(B.root_build_dir, "blenderplayer", dobj + playerlist + thestatlibs, [], thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blenderplayer') + +##### Now define some targets + + +#------------ INSTALL + +#-- binaries +blenderinstall = [] +if env['OURPLATFORM']=='darwin': + for prg in B.program_list: + bundle = '%s.app' % prg[0] + bundledir = os.path.dirname(bundle) + for dp, dn, df in os.walk(bundle): + if 'CVS' in dn: + dn.remove('CVS') + if '.svn' in dn: + dn.remove('.svn') + dir=env['BF_INSTALLDIR']+dp[len(bundledir):] + source=[dp+os.sep+f for f in df] + blenderinstall.append(env.Install(dir=dir,source=source)) +else: + blenderinstall = env.Install(dir=env['BF_INSTALLDIR'], source=B.program_list) + +#-- .blender +dotblendlist = [] +dottargetlist = [] +for dp, dn, df in os.walk('bin/.blender'): + if 'CVS' in dn: + dn.remove('CVS') + if '.svn' in dn: + dn.remove('.svn') + for f in df: + dotblendlist.append(dp+os.sep+f) + dottargetlist.append(env['BF_INSTALLDIR']+dp[3:]+os.sep+f) + +dotblenderinstall = [] +for targetdir,srcfile in zip(dottargetlist, dotblendlist): + td, tf = os.path.split(targetdir) + dotblenderinstall.append(env.Install(dir=td, source=srcfile)) + +#-- .blender/scripts +scriptinstall = [] +scriptpath='release/scripts' +for dp, dn, df in os.walk(scriptpath): + if 'CVS' in dn: + dn.remove('CVS') + if '.svn' in dn: + dn.remove('.svn') + dir=env['BF_INSTALLDIR']+'/.blender/scripts'+dp[len(scriptpath):] + source=[dp+os.sep+f for f in df] + scriptinstall.append(env.Install(dir=dir,source=source)) + +#-- plugins +pluglist = [] +plugtargetlist = [] +for tp, tn, tf in os.walk('release/plugins'): + if 'CVS' in tn: + tn.remove('CVS') + if '.svn' in tn: + tn.remove('.svn') + for f in tf: + pluglist.append(tp+os.sep+f) + plugtargetlist.append(env['BF_INSTALLDIR']+tp[7:]+os.sep+f) + +plugininstall = [] +for targetdir,srcfile in zip(plugtargetlist, pluglist): + td, tf = os.path.split(targetdir) + plugininstall.append(env.Install(dir=td, source=srcfile)) + +textlist = [] +texttargetlist = [] +for tp, tn, tf in os.walk('release/text'): + if 'CVS' in tn: + tn.remove('CVS') + if '.svn' in tn: + tn.remove('.svn') + for f in tf: + textlist.append(tp+os.sep+f) + +textinstall = env.Install(dir=env['BF_INSTALLDIR'], source=textlist) + +allinstall = [blenderinstall, dotblenderinstall, scriptinstall, plugininstall, textinstall] + +if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw'): + dllsources = ['${LCGDIR}/gettext/lib/gnu_gettext.dll', + '${LCGDIR}/png/lib/libpng.dll', + '#release/windows/extra/python25.zip', + '#release/windows/extra/zlib.pyd', + '${LCGDIR}/sdl/lib/SDL.dll', + '${LCGDIR}/zlib/lib/zlib.dll', + '${LCGDIR}/tiff/lib/libtiff.dll'] + if env['BF_DEBUG']: + dllsources.append('${LCGDIR}/python/lib/${BF_PYTHON_LIB}.dll') + else: + dllsources.append('${LCGDIR}/python/lib/${BF_PYTHON_LIB}.dll') + if env['OURPLATFORM'] == 'win32-mingw': + dllsources += ['${LCGDIR}/pthreads/lib/pthreadGC2.dll'] + else: + dllsources += ['${LCGDIR}/pthreads/lib/pthreadVC2.dll'] + if env['WITH_BF_ICONV']: + dllsources += ['${LCGDIR}/iconv/lib/iconv.dll'] + if env['WITH_BF_FFMPEG']: + dllsources += ['${LCGDIR}/ffmpeg/lib/avcodec-51.dll', + '${LCGDIR}/ffmpeg/lib/avformat-51.dll', + '${LCGDIR}/ffmpeg/lib/avutil-49.dll'] + windlls = env.Install(dir=env['BF_INSTALLDIR'], source = dllsources) + allinstall += windlls + +installtarget = env.Alias('install', allinstall) +bininstalltarget = env.Alias('install-bin', blenderinstall) + +nsisaction = env.Action(btools.NSIS_Installer, btools.NSIS_print) +nsiscmd = env.Command('nsisinstaller', None, nsisaction) +nsisalias = env.Alias('nsis', nsiscmd) + +if env['WITH_BF_PLAYER']: + blenderplayer = env.Alias('blenderplayer', B.program_list) + Depends(blenderplayer,installtarget) + +if not env['WITH_BF_GAMEENGINE']: + blendernogame = env.Alias('blendernogame', B.program_list) + Depends(blendernogame,installtarget) + +Depends(nsiscmd, allinstall) + +Default(B.program_list) + +if not env['WITHOUT_BF_INSTALL']: + Default(installtarget) + +#------------ RELEASE +# TODO: zipup the installation + +#------------ BLENDERPLAYER +# TODO: build stubs and link into blenderplayer + +#------------ EPYDOC +# TODO: run epydoc + diff --git a/bin/.blender/.Blanguages b/bin/.blender/.Blanguages new file mode 100644 index 00000000000..b50b3097eca --- /dev/null +++ b/bin/.blender/.Blanguages @@ -0,0 +1,21 @@ +English:en_US +Japanese:ja_JP +Dutch:nl_NL +Italian:it_IT +German:de_DE +Finnish:fi_FI +Swedish:sv_SE +French:fr_FR +Spanish:es_ES +Catalan:ca_ES +Czech:cs_CZ +Brazilian Portuguese:pt_BR +Simplified Chinese:zh_CN +Russian:ru_RU +Croatian:hr_HR +Serbian:sr +Ukrainian:uk +Polish:pl_PL +Romanian:ro +Arabic:ar +Bulgarian:bg diff --git a/bin/.blender/.bfont.ttf b/bin/.blender/.bfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..58cd6b5e61eff273e920942e28041f8ddcf1e1b5 GIT binary patch literal 65932 zcmdSC33yaR)<0Zz>)zY@nsoN1vlF(2gndgBNFXdBLRb|{$O1t~ViMNKut@^41ca~) zQ2_xF5g81KJAw$z=m0v5IF5?TyfVl*%#1>E`Ty$P?kuP?@AEzX?|Ht@raQN5JzJe~ z>eQ*0P(p|UA0n}j9-EYM?BUx5gnU@tBt8%AS5MEcEGIg=C>@6H=IOH*6q~CC z{T}r<2zlZ+GYV(V?|v)FN(jCZ*RUBy`Guc8{>%qxpNoQ?Gf-g9(3fHUk@y}vV|LYi z!V;FBa=Wf%KNM%$>as^vz}P>v%JqH5@cBJ zeYP0Whxb`W@{IrV zKI=(XNTv7LM3Tdv_C8yj@y6=GW#tPhN~X`Ka(5_5bf+XIr@E&taHp44RaR9L<K-&}mU|3uRp}m6R9RFpx2UjdOB?t2qKbU?*!u4R!KooDG==toyl87Ct|QdcYbAM zSwTrY=5rU870j7kR9cl^#o;L~nN?Kj?!ZS>JGjS|6<5v6uPBO6R3U-jR+JUaDJW8h zDJ%g?N~X=JDpFzKGqiN*>@F!Sm^G)6Lo%lgcXGl||q^T9*J+FZ%aQ&2hxApcy9gl1`my-i)%@ zKZljGp?FS3DJBF((6O-0U0K%IT{&mk%%XxSUZT->)~vF59HD};(!vr>u*$xip}9aN ze_GkxA{7Tsc2y8s1fjI73XA}QIAEMFDrlMvXm#$&8TmkKT9KD-0HmbU&5K$wEh~j& zRJdoCRj3leVQPoCyJ|ssQE@&d>goflef{kG1$>6tWrZchC0y9@XH`M`@PJ|S3ky~3 zRXX#@%kwJ$^_*Gx6)O6LMU^GfOI4CX!Isa!Q-vy}`2`rHlK1dIRO!BNCQa%JHKOIu za{uB0-abA!T1NwTrLz{eOWKJ#Xi!naHLc1q{!r-#DLHR^OQZ;LSEKZScfz1C8SbpH?wm2B$7c=67~+l|G#1~ZJG&=jR8|K1Wx7XYj2S!(BM(Z?8kvs{unTbIMxpM}M$;}!(Zsedb z?woOBaz>BMz!*a?Y<5<5<`~S9F)9N{V4%UHb0&?+8agbuGdks>u(LaN%%C9|qXvx` z(V0UyI(Jyc7`NJ_E1<*}?u_xg^Vng7Mvio+XXTE~9g{I=6mN^B?xESEM{ydB%N{Z) zH*0jZJ3Rxa3`!r#3jrIbFnHvktWllaLk5i+G?b&`n}j#>qSHza-eG7)cE*@NBRjjt z=41@c;t!x>)|iaJfEF!5dr$(U7-{h6?6DaSj6(t1`KACvhGnRD0D(dHH&}&CML!$p z@^NxUj{!lvpiIabo6*@lXiU~v&XLS9qX91GCwg!k$AO+`nw9N^m-C31@w)cXfmXb? zmx@C&293mk5R&Ylw^ijUV}3zVIaXYyZ;@+CQdOv$7KM?*%G8trq0}0}B5u-w6p%#xO@Wh{Oj7YQ4K3Ux z9c`*eCEgXJh~$&mq%%shNGaNP#nT`%3okbr(=t}2`mG3kiqK~+J`2(E=i|7^c(p}7 z+Ktqvb5&t94rQsz|8jM-O79G17_|y@C8*`^>1sZC9~M;@lh07B_T%!yM=Vg=&4%o0qx(kStu@$Z;co$Ya#`U0JCJCS*)m47Dxth@ zp*kMNy$tP3FrJ2=8#TOS4(Q59;jmVrUZYPjp18blXgZ)=gRyl6E{B{8Rb(Feae3!6 zw$g-`l%u>1v&>Q9)ab;aDa6>?Dk%Yt=3opCzi$p74nLoPkIv~(0LbR3qi9r}hf?0V zOdZRO+7jTz%i3b(8^3iWbKEoz&QWQ|$M>L95A`hM^l&=1^)<*NV|Rl^(M(&wro6w;GCp zVFl>Rxx@L*d8N(BC52;Brs7?xQeq}r6rkSM#y1a_V~%ebB*Q1Q9CI#-oF|%uRbrd( zTcNq?Y@BY>(2i@tRz9?H%STr}A77{KH9{$R^0E1f;8bX(m~XwbQmw5XXxoot$k(^V zt!XM8ZRJg)2ruE||2j`Ot{exA|FhM<+IOzCe02JCj`KDPRK6Bt9u1?eKcm)v>d$pP zw@4Ze90E>zzNUSejl<8^9bc!KuG669bmf%w@xE1_wYA6Pjjwl&)^jil|JI5X@5{C9 zbkLwx%BQ0p$7qJPjQ8;AQjVbp32(1a_kJ4jn*WSbE5|hqS|yER>IOXjTL{|Eb3Z*= zG4;{EQe6|A=X?f^L0c~K)xdSDCX<}nZk6Vxpc~gOK03S6N-N^46lzQPd8(Whsxw9Zf^CdOPmRYu>iT-Pp}T#)Lp1z?w(C-}H6t-&TU*2Bimz#o zfd(&^1Wsq)x|@sIk~Y}+<}4!fRc>>vcJLE{S7 z_HK0rbC@`c+^%uSX)ph+P-@uyk{;)LnSpc$xqYbBtP-g)%pMyD_L44E8LW(Tn52+mFIK*9&Pb%3Eh`4;3F-n~y^_ z3g5OTH47t*Lofb~myW~V9JCvY zUK$*nejM6tw9UpCW7NMxQO_aJIHA#MFk0ncZr)-j;L25@;4^XTcuNjdF6sw?BD_DJ zb%a`~LB?sqxy)f{9fj|b_}m&Coc`mz<8c|__>aVk)0We5tU5ymN=Kng8&@0E4X8LK z9Bz#ovY4EY$mj&p_6b7V_Pjc%GOaGnlAi%}}%yg$c;Q>0ZI+G64xtvz>s zNjiMe#>e7(b`BTv`e5&*h3s{$OCxDsh_Jb9(#QYEteoQlS+KKGp=46RrHvIKUy~a=~Zx(X5sGd`=Ft4<0VfT*`cWXr&5Ye_Y1+Ok4{1 zH$DSjBV5Kfmw26TeQI;~_&84O>l>B#YcKs=%J@3+we$7+Pr5^+k#BB3b}Q~&S~)E> z2sxKEYW(+cTeW=#Y#g_io z-?r^qOF3ovZiw5j);$n!>$A^4-#c?mwMYeT*VYsEc_W%PsqK}xebnIR9uoK2HJ_0C zewvq}`5N3S*LK-_H=ylQeY+UGJLI;x{r;~KFmgYDL!r&(v;VDQ@x2$1WpK}d&&DaN zLBnU$sQI64?fpAOzEkDhYm;ziO+tQ0Sbd156^WzR_CrG0q!Vebk~a*jljM*10uc#{2< zrLt4v5Yb9LV;9*$@)c$gG5&c{NA{3vz~WEK$YP;d7=x0t(nYczuQJqMq`T-PKzEWZ zCs)W;CJMvIE_wxcohSby%UQ0l80Yn=LNVY!i?J@E|8`O-66p#x5=H2QGC+^Hrm3Id ztc!F-ecd99F>@~2BR9(ax){vDDYlQkLvP3%NdvjW9%7HOPv{CUM%*tBBXt@DSRSdv z*xPv@xtJ~h?)+8FM;GRadGsLptC**ohOyt}7-8mP!WdvwOitlFPqqW6esl#}1xR^q zIJu}BE+(NrM$jz+)`XO?9%Lq-s>xw;lyqU6NgYN~@s)c?|3c55;^)A*j;ld`H$iLSPa1_Ko_lu{cE_Ln6vuu{VgKID{$*wVRM>5W{UeV3U}b;b%x=Z8@1GbX zeXp>ao7vwsvm1BVcX!zTDD1C&*|+KJ8-;zH!oIpbR{Cl)yN-s}$FeWKNRqz1!@fvj zpDXMy3i~XD{n?*=x|v;5*e6c*r$y}QtL%>o`v}cHTEwng9x7c~#4ZnIm;MkcT~gQ| zLfMB3`#@p8SJ>|qc5ySia6Ur1ps@21?EMsWPGM(OIHWUS?A-u%T4C=f>}`d;rLZ>@ z_J+bsdldHUGgj%@6!wgjJzdBe(4=8A+pVx&Pno4%3VX`TcJ2t4b{4W7+wIbhV7A@P zwi(%0g>Bhvk+vvovxU{8Q~hSPX`@xz)PZfZvM2Ab4eMW(HYjX;-4tp4t8D!ev2Iu1l(pV+$3wKw|v66+F1`1>mI>UEi9#*NlH;zHxo-vGD*o6mSkdGyBMUdcGktfI;XHs z9pj`wX0$d3Fq6WJc4knR9?kR$)A=*Gkcp@iAptIiQl>Bg--RxW+8I$8 zZKQ=O*3wS@fB295e;UZ}zOV50lINl{%o-}lvR*SU|7oFkS6 z?#6rfawdwQ(xf9&*bx?|KO)A(eEw^dpLgjzB4?ueNOQ&z@2DAhLr^w$A|}8;UX0l? zhIE1HA;rpOu~^!Jye1t9@tDQCM7~S)(qcg*NvAL0=tk_9Z(P2S?B|Gb#6>xxibc{? z$wHgHQa0r+=iLPN7jO%0#35QdyJ>k9f!UsqY?9eo=Uf zfy$@3G;YWY8e7sZo%U9q9zzEzJ7zRYS3a5k^bF-)nwP7*PD_f}3gsxPRr2X>C4ake zbel4b?&9xlGq490k;GDHwE^;eI49Mx_;yIIW@ozf2^>2>A zJ}rO5zfFn;GYwpBl2tz90N2Y$l$*h1d+viHj@VRAqXv@2k9a+*WYHMbl_vCvpn;CA zv`6=zy?Ug&@Wq8fM+9~G%R1(;;%`8pV<76|g=2-Zz7+@CHKPB}bw?28Y5 z`O%jj6;>^L^z+3_tCdT%i_oRZG0z}M--|u8`Poy}@4giyLtpIJRaC~s9NT%|9UIaU zw_9dT9G`bZ8SN;YJQ1mr5_$CAm%2ph7BL~?F@_|-Tdw!?jJ3tZ$Hm(cViVHIljevg zyRHp-GFE=lyf)ssrbFz8?g>$$aRz2_Sq&Cjl%TYj3edG2G`^|sdT(X zb?VjKyHA`HHf(x)S$+Mo<@JlNz541WpS*hN6CuBT+2flwJ-&4F;-CH@TRwU9wLg7w z>f|-P?v~#BQc^%M14*VAJ)14mYOZlO9i|$i$?0?$YKXxV;L=f9UlS1E5-6iJ;Su4a z#y}z>!rhTVRD{FmXT-8(LH-UuqfRf#28W-YQJ?}NT9pvwLJeyDjOk93fyu-e!8*9C za)$)DKB!ZD!lu{_L2Imj#;zu-fpm4c608xdt1}_W>abx|Iz#Q<>`jp8%Qx(2G+scS zxk&Tne&+hWzJ`q3&u}S+hzEK_9GsCf32*nO-50z5XX}8Mw3JSYK59#$bc*Mw&Ll+} z62nLsjT8b+9Z5$T@9ayuJBOI2l1X&3ah!8<$mGaL$rES7^#S$K z+qy&=Oa`;wVNNi22ogdK!KPqyup`Vr%oPwGnUX*fXrdv;+0n0~e+O4mNb&xLl>AAIyRDxbc;|g?bPkm@78ZO z>@aONuTN=6Ig-+63YkLHB?lSnWuOCTuT)vk(U=4)jfp0FjjAg(H6?&A(->9k=noH$ zyWH^bzAUAhHuX!FPnu^;p@B_xGp;ZHyYjo5n&gx}H;&yqZo;l1CCmGnQB$iJx2OC zS&E&YAd28DHzqgQn-Wo7F4)ofOo_!K-XRhH{^7lLeQ* zGcYDz=+WKTOQ^0{wtPjy=K4)rWarn)z;C`$`hE2sJ@c2(=;<4PV-MgcQ{jk&mF95h zC^0!jKcrgQul2v(3Wr~6fYaqK=wf<0dvq7}V95H-4J(!}mz_71{-6Ct>HFPR^xbd1 zp>Jc<0m5+h4%VoHWP3W>EhZwG4LT9Vm~E3B=50o5-Qd)ljm#iB7-a(Sw}~c$zeRT1 zFZaKmat&{;{JD9w-@XjHefkCp@I9GIk}eJgSxShD>m|V_h{NV?8=c-)IZ~k<=}V_8 z+xpU+3YsH+_Vzo|&MUQa!TD+Lyj^gfE>LRE1G1}7x}QiQ^lgmCK@4=Kj!A+`B!NcR zr8nEJHNh5hdvqCpPbX6cOfB~TdPF(cVWCU&rTxv9;0ue*mk#oWgNS)hvg@9czC#pf z^I(se?IO!%c+SBjNCx{ZU(mSNE7b*)ee2SmrDK#s%A1sXI)(HzVX?3rHrH{S>=Z;w zMEf<~o;z2VxKIdf{z_QBhs(<+_&AI?(DoIwT;RiNqL_3e8DqzMa_N$ypdGoFE*w>* zwu{G~gixrp5Jp(Kup0s_5XzEHtAYgqRxN9bL4fWS^aq=NgpB?)o9o%ydtZumKFj3s zlN+3*!Mwq_Cdd$Gi(p}{&>*09n=gjz-0CFLXu)B3rl!Ez5fV~}!%nbn@hPm{`P5VR z_taB&sX_Vo-Mh-asX@w7E-DxBzDQH?>P}M|luD&WsZ}cJTDpKPq-#0WpW_C@WME?? zBRsBj)*uQE(o!91Fz6%YFgRY+1X`WuD>CUu%5CnH0x8uoP?v^DT^c4ZTQmE|Y|JJK zQ+h=?q#kjpoVN-c4)G~^pAK)@b5N`t);R3Wm4kfd&6s&Oun!}9Jqf`fp)4rO0kLsN zl9+CP+Of&f;J-mc1dP~WIgDX}b|#0z0AIfG=9{YRRpDtvWL1x=kh$QR1b9s@mT$Pa ztiwsTPjjS<6UR&AbqmFX(%jJ6U>%f7uowbQKdg$(mFI+1hE|0wBQ?RxLY9Rt3)@fj zhdQ7;JdeD2&LD%y$t|2wJ$$@=*Rxy4zFtvzZqnD(ypF|1o?idy4{>qtbW7P>_jvujdF7SW zvGK>;?hlVX_B^D%5PaVQi4&li*LcFIg;@w=mUO~Qx(4iCmKvzpNWx^jXoh~g+#i}r zHS5>8nrd-Z&%w(&r*hi_6g7|Pe*Nv~Xd)ePTr&xw*Lma#q6?s%NIdPtdeUq<+C17a zo)*(NbRk2n?e}7KY839HC0C{q#+~nE7f3pA@*_ zkmUAkicr}UK_c$6LHLeYQSM!6TzkQDPE8>$Y$Vz;j`QnN7Tny>d1B`~G*-E+d_VP_ z8I#|9l_zaB<>vqVUHPZmeZE`r@tr%5$HsGwR0pg!s~RbmO!UP1 z$;47)CJg~{Ls-CGdxLpZ^oFoCapq`4Sa5`27>kMwjf0AU3|?22)b*z8e0QOtAVbj9E}jBV5il_p{1&)Aut~%F>bEVqEZ5cJu7$bUWqp~jNCEuy-T)! zM<4l|O3JM-lxF27&7q+qcd&jZpLzP#SD$|7q_ChdHeUHb`F_F_<@@ixR{lp-antDD z2+phhkhmG(l}rjeL6SpY0&|GaG7|X2Bt~HtWF0n(r&W(2sf|wYdGZ0=4bZ8q!9_CP z3UW>qsLVp7KGHC0Iy*v+$U2A-I74G-)PDA6^B0$>(wr(?8GmP~gdHs-t3lt@Dt%+H z^Be4m3j%c$7f40FYX*$mMCFaoxyQ0(Ne?Klk!0K)o~y85jT zgr^NL#0sb4;NpQ{m#hB<=l=%6!6%Y+!_4>Vg*RS8VSJ}I4!@WO$rfgXH}-+P8_SiWrI#%0Sl2=8vMt=+z(rgr;y_t7OUfAGP}OOCpu&(vN0_S>siVb8{KxBh`L%^CiU07I@Uj&Jc4zs8Ng9YHT zYF{h=^vO%W>EO3R-VA*+?9K4EBTh%^4mwXc|LSCrm|m(@a{754Rg$VnNpw6_cS}GE zJEzY_?i>L*>3ek6UzEGl{ss0W4&^1~tC2hDK(8!CLQ1HGI>$dmZQp%O15|^!TX`@- z*y58Uj?*m&%{yWY_@yIZ9;>`u+y{q14Xgwq*a0=fts%sOy9Hcf+`5GS6h(|t&|CFY z)ZPXX=kbI0q1z=cC;PAwl4!7q`)}$Hs@rnCiQ9EQZ5Y*ixy1b!4Agwp=fhkjQ>9M; zfsDvYM`0%u8QqC%c>Iq*C0QanWhq?}5!{m4e)%~a6-cZY19?XL2dnb-4e$Pk@9=$l z8NRnS2rk-#N}t^QQPkg2B!S&hHYgj9(+~I24>=XC(md%C_KcSb7PwFHP7x@GB!&~= zG>G7hQb85*7Y?BKICm8G%>G*kvF=(SAMNQR?<8>An6wj+`{8rlQ12=$|;UN}-BpM^AB`ib?17}Hmh+mxj8XO&LDfuendq=** zPrCUp<@QbcMHF%8nD6DG3gT2%5J%#?s^Itn!$RXiw-!h9i@};p!~O~z`4;2J*Q5>G zFCBJZwD$b@ci-qed2*lB<+Db=oImxg>5ZQan>;ZoK`+aSLN{zLS~h-CkEz`zm1Yh; z)u;E{yGO1XKR&5Pu&aM}&Y4MB9oRP~I7YZVBu#EvcDopp~@uU)@zL7foQf5-Gg zAOG?B={x(?J-Ii{Gefy@r231zr(UX@T|)hzTKdzB$%~Y$TTdvBOP18E{LNB2=C#Z8 zk?IknmA92|h2Xkp_pDp9caJh`RMt=Ly?1BC$mPxMfX`lf$T%__@c$Nha0ASU9J42d?0iB+xe|r)q^pTlb%8R-ZIRIz&%&$ zFft=?2=Hi(I=HhkFEluqQO_&jSwr5cbnNJeD}^QIt-?08Sq#+t9c&C@7^0lQDdnaRr&NC>^!dZe=7(2ak*v+Z?C_mVbg{A& zE9o38=nY`3$9~fdyA=~m>Wzka=Tcg4d?C_d(hGjUkrJ_n1xUeRT@576DMoPx#FrCy zPx(UPZi4-0pX8&qXuytrpQgK89^zp2x#3b>(U>T@kq&wGsi&S*PSH-AHf-3Wm;~{g zJ4+s`->clZ+x)F?uKCm2)oWG=#md04ibu=$z4_9rXZ+pgx4!o$Xr4+$uo9pHf=N$L zh~;VPVPn06K1~jbSpJSRA-Z4-N%psga1gzQh{N`;o5{y)p^>2iz~g?2*B9y8%LNhk zIVMs<@i)uv5#<)OQ?l%v;+cPYTzNrRNNecWn!icYt~@+dIjj6pxvHF<`tYS;!{}}b zKG5AmAvd6+bi_-=t{xYuH-LV2yo_vbv++F2BRBDqQ~hSU3>xNLLC|=j}NVxO<266HdEVyW6rV3&E-N)^O5)Yn8OY> z_u_sV=OXu(!bu;Gn@FLwo`u%yoliRsyXvhQ^lKsn66WYGrUnI@>~OGeG+l4P6nwJ` zZYq~m6&9yP7NA{6YC$oQAp7Po-;TkH5ZNcmYQvMufM+ zq}~Qx@Yl!+^npC0E(kXr%~7d}-7%so>gmV1_k};d|9*2cuy5We6yE8?Daw#d$H5dvapi9M`O5nGZaEi_gq?M7hC50jjGA4A{iMCiTEO0hbk z3EqUCNg%p<=?GbBmh^HTAF$U|9}}(#Hvzs`%<3#={DOd2-CL3^9!riT&r)aEZBb{j z%icZXx%V%AIV!ED6jN?gez<*b^V?orq?y3QNWS-U&^zF{=o~VPKX=7d-I=b36T--g z1{qFY(o>^pv{mhYFd} zVEs5@x-eImCoLCNN_F~8!Vdj6f(zPGGRUDUSSLX@>w;JZsgvAM*Hi2%^^|+)lFfsd zN6e5svPb7JPh)x5LrmArlgiDj*=lK>T&JruZ)Z=*Pw9@c-|F6F@9I8gAL+hje-*!# z{zv{d`%(Hy?mXpDGUZWlfJR|=iL)+ndKVR&Ls^LOujW+F?^VLQ=3z}=3cqje=B1Lz zsU*R7H1j1Y(lFMSh&-^f2g+(26QGawNtu zlQ%rwnM0@72@Wdg`5z`2j0PAfqaod>6PO<4)|+6Ba5gF#gp1)c~UkfwqIUPd}l1)`En zbwZffQwJQmMp7l5>- z&!iCft9O!mE%Fy^OJ%_>JCFRSVQ^pMk8g{y*~e#srpeS#mT*mJrtI1^N|k%pXkR*C zS*e^+-sMqQX{6Gqe5HJ?G}2)-goe^#dz1&2T?+O)bPt_|*IvygiEBYIJ^!5$PY~=8 zH%m^tQIE4|Sfw-vH%tBi2dYaG2{j7nG1**^t~A%ft`}VrH|O495v({uVqz!oi*8ib zZr{FE=}q6e%i+7Lye}m+|NhC^nkV;t`N^kWH1Fq>P=54MBAkrzbVOv+M$Hzpm0B$3 zbX$a3B~1{5qLv6ts12TOaHvWkRo`&s zoYKHeU4We2PN3EvIW)lf^F(kdO<(9oB_dG?4xmnS5f}9r0$8Ak{Rxc|;#qLMYxhye!r@l#vQJ4ck8J7X&d1#xM&?BjHbv? z9f=MNwsz44`$u=c<_s(1IyPl0U0~(C=dNd3)KlB@YY@iEO_6)x zWqBmM{W9WYP&>D^YzZSb;y+82@FRvuVuu2W)Y*|TQEu36FihcT37j{w_uBE0@5Xa}j)oR?G#DgK6 z#Od44M*7wH?e=5bx@bE&Xf%Z7uxO5+Km5+yhtDgYL9u+Ldce0_=&z<5R`H2!HF+mp<0_9 zJ(u=rgmq*?#i7zlzYrpZNF5R4jTaKdL@7>o>w6QNehB@={!%X) zS14$PkR@i}*O(@e@p7?HB9=%C$y{ub7KjU^Ir0)c&gbMrtcEC>YQXMD7~Xv561__Q z^oQoN(BXmNU%3~BYXL;J57ai(YEPCFB1^EUVu;beLXgNI;7ka495Oe&SoxCI@WOYZ z4*dL7x)E-U40~kKn@vW8Udvc9>4?RC*_*F|B$Zz_xh*?E%@RY%iE4p=kOf&1kk>t5atqH`e3u&>K3CUx9rxr^)ZH6W1PutbzA!jeOV7NRZ7

B-* zC^QzD=7A5@!hAMQtdbVU3v~1J<@)*N#pcD<8ljf06jwpfN)(KwZpZzF^0u2a0p-|!ObcW!}m_*E{=TZbfN8XRDk9()43 z^bP|YgmykD6|i~dJ`>KjIO|O5Cb*~wU%^FHpFlKXG(&K&oz_fa8y~g3ucYqeTf%SN z{1Bc(gOdw2D+D^=XD)Ul1RKt5us+a~pieM$7kcY^nnvg+N)PIbg-7)Bgn6bKVTn*H zt=6wFZ4%ZCTcoG-n@yqcQkY(+GawWI=Qhw_x5U#9LL!ToI_MG%i6*zD2jN~o=NqTVAwyT6x1cLziBqm2}Qk#f_k%@{ls=PlC&v=#|>^ zqfp(vf`vn4HbG;4gEgfmn>-!7yMh)DKqff{^y%D@L)L=mk)TU;2341;ak^hu8^p-f zMt@207kUWELNcT^Q}75L$)kTjctCnUUnD#(Y!vJPG=xPO<7p!6MSC-k5&L#FpOqVT z8~N!FQzZ@BSG<(Jc``@lvoS78Pzkp`_uJ29xQTQkS-A(w&s@((;Fma(i2kv z3(?z6Nv0mGk3P*blnvL9HjQJG^u?@1UuK%e=Ia-mcAEk?XK+3NJJN$jRf_dZIqdA+ z0qjWAbm_|WyJZKriyJs5Ja=LuGSqZrtj8uEkdF!n$V=GFv%y4<6Z{K2_R9kmEdfy^ z_@NuP#Uk}!7=FXv9km8sKhZKgGE_QSnPj|$9;S#*su^0-{f}qemoF9!2Y?1 zP^L`${(IT~$3NG}B8T-V+m9>9kL6!KYIHDj2H!2_{UBOk>`|Q z%CK_+groTqU9HSPQUfIZh7vCND~GVVxBZqJfK?RjJo<7OWCedj|GR%w4%O9hYz~UI zgjI4eT6Xgo=rQuL$c9j)GH@io1#g@d$z?#{{&)aifwYWjcN16f+R&pRvK4EpZYa&mEorr04tO+!eKo(>%=uMGK@1GG5dR@2-+oXvu zeC{U1Sy-f$cxB}%yZ{Ol}D6Emb=TNmP9OxT;g65 z71Z`DaRBWFHnoJBquRyZh1Wkjw6tv7iN?mXQ!5XhZ@x=~=eFb>&nS<}K77x+HXc zXhSI9ytTN-JPyx;o$9U$@mTgv_ER}8pE>h#&QsZ=_D*SrgV%-1fs|Bi({63DFBf9ZpjQrxyHQ9u(84 zb-Eq3cwkIrrk3y$(DpomJ=56O_oc_q-@AAIv6q_9f^7TugLLe;F!iS!`wR2w5UR&( zNWS9ol84cfS8g#Js!WJsBZ5Z5d%I zh^N(4AWl5(X#2K$Wba8#3oj3E2>&4bR=AW#(rB8H=1L2dI_r}3NrukGGEzp%gfdrI zsA0;ZoWN0PT19Ih89P!PBFs1f5f?WdHD7#X=GkclA3UPmR?gDIrZ1?jQP{h3`w6Qs zb@J_SdZhAmXW_>q1*2$^^5KaiM-IOx`)|vcQBc>E#6GOce)V~k z2g-PHGI(G@w##swA(+Dr&Kkdf6E=1tKBh6@l;MQ!wUF@mV4^n-IxB7~zS_RQY;O?&rls^8nFD0lJ?J@CM; zF~2?5=jdanv=1?6LYoCr+flJm;-5!k*@bgk8ILy}qZpR`ze+RaE#rr{7y(`U1?$&!szI zSNXd55;=u)X}w4?Th65sx5fJAdqyqI9_yP&fcY`?TaEZn%)8ql`~MZ=-TOotua0LT zHZsH$W)gJ7`np+HE4@ZenP0N&?UFp&LiJ{nX;+V|uS3a0k$?~UjFdA06FEGN97mp` z+@Ve6?+XHJ6F&Rf%x)zk)mhhk^ybd|ZE}adLZUbYcLEb5tWV;v$AV9hExur|o@BNU z24DB>kocK!yI`rx3ev}gX}r!xb9uuN4kHrTkPNBEir^gc6neI zZXpj&o;)GMeb;Z%=vT-VfdZSBIKIbX_r~kX zrCSJ5s_X)*WdEP=d&DZObm3Sv(PXkGUUnLSY(x&%xy-fUZq^ujD%h?g4x3&t=Q#AX zoUkC6q8Mndl%^)c>r~IUfB);Z)i5p>L62W@Y)))>?E2USyxxfYEcRZk0Wzsdp{uQA zwu-1r6Vb$sHl+eR?MsSYg*QJKlJ< zxmL_OJbl_@UJS%SVBm+-xOVI1)Gx0WZa&rZaxBmFdnB0Ow_?2D{OXFq#C*YMI)9F; zZvvrj{Nxi(a>Crm^DCXU2bj~9abJF=CnhbpnpDe+b&K_jvDaB_sx~jSEVeGTEw(Rq zR684jZv{I5O`DXPc4?TEn+`o+zwywajkl;%xq0jF%JR!NLdJLL> z@s|i31n`{QRFyP5Jru4*JC~#K#EBNqLg?*tH}*FlmW>D7_!jg#pUDLETC}wao6qlQ zw5h%nT|I@~n`(T6X(+;+_=KDUKj4*MM&x8w=Eq1+cV`Gc=(|ov%Q7=6B z)4#kj#fF1&4wCHgmk~X2;JT%?(QryP>kVR# zMKseJ#DovFO7yRBtqS5kSR8yXUlempsNSm6`$uPV;80y|7sZ5Ah772G-sFo@-3e+@ zO!bq;cM|yKb#|CB%oJws3fH2usk6DCp`Wpzsh`>8CTb@WT}PjYn(=n&B% zGSQtF6`N3FtTEM?Yb;IzdI^GTlugXcEX>Mm%+7*Y2n%IlxK5Rjl$e(IaN^>`C5h`3 z8xn6N24R!EnLb|&DiSf{gYR%nzkwJ^xl8}aq>H}iqGUPTT}GB z=lQLF`CaibG3{`N4!OCWtSD>8ZL4-3kBND`M~_JljL3md zcoYiWXdc3CPEW%9u?`uz1=iaodL%ppG!Q^5Ueb>{rB!F8#- z!=EKFt{aBHAP))hP|^lrkD%xC8<0uD4-!IHh!~H6Y9dP%-TEG+2kp!HiU^<}%$LQo z#7t?J?9q=W&Bp;PJ9ca(?jhKjBw-PoFD?Sp7t0HEixD|oU|4LZ zHqJFIGS~7Gc^q!>6=H1qPWFOrl>|xJ~&r1j71G?w+d(1Cd ze=EGiUK8=#0fslMr-gUe1@V1pfhs7WG!_47jETmKZ~XeJt6zWBsC;tu?>}6H$ZTda z`TK4I+uSr0#O{YRhhKm|D0i|aQ{utfK#8aPI%<^^8cgAuMz7J_a?nJC?P`-n)}1Q5HNqf2SdgMV8ZEv zPgJ%VMbQ`{x{UG00b)1fIB|k*qOsUGmo60N>Z*)u#bw5A;%;$^?n&c%<34&od{Nx1 zd)C-s3`3ww!cm0@L4C<(2r==HaGaqd0>X%zvtCkn9S`FtTe4WDlwlZd@>p<8LMI86 z*aT_3JV`fRKi)9Olw&Eg%%_VjJLo3e^K_5yh~@W|&n)*WNnnXV;1ORnEH4%+kI;ix zm6OWJtMp~1;wnv~iDF*!XU%WXMrD{VTnJDer97540GEgXk6jfGjY_V z2B%u0tgS~%>S+qjiBr^j1e_;&l@oS#`P$)?wJcwi6Zj5jQSRf!E!=EIDpwZvtZw|4B*b+!A zOt@QgONmH^h%?5TV$BJbj@FJgx1$&IEkf2}veety)6~=4+tSC{$Cm6EL_8D$Y^0}n zyvsG+kYOBZ$+BkIJdRxQ0DV9h$8y9RaBUp8Ho-6fOLm-jl68_T$5Bj+g&D>YYl$t- zQLUeEoo`!3o-nL1tuU{$tg^1MZ8OxH>do7&+iiPHd(6*UpSK-x{NC}I5)v$PqHwFKf!s7g%2QJcLMcf}2$4XJ}@8MQEX5*(|-W;WL zu2kcNp+c5UGU;umAQr0cq<5QoB1oQW;xx=qX*gIv0ip7TO?fm=C}w$Lo-_^N@+GDh zO`%-Pv;@o_Wiy*c3dfoj3CEg?#Jv4YpKRREkOM}EauheT{gH9J%+o#C<}%4~h7h|e z+$6c97%?3%AiVpg!F9mzr8u*}D8&W@lW?QtC-@V0@L;1&io>lu9-)DA15cH2t@#^! zZCrBYn{7CU{KmGgvL)<}{9|AY{qDv1C`|PfiMv1p;QniT!c$MxEke9TO|QhCfK)MX z;7#wn7JNY`L2Zc(L53drIm$S=}GE%efc z(?xZG?$6Igxf;*jV~Ot{FGEtZeeQHJNEYJvVFJz=7*# zJ@-@E>*MQw+_^3^c->P!uA5M|@zY!Nm338HzW;O+_;QtALI!;|w1TXq5EU9aG02VBL<69@0+~m^5(I*rTH}`m2v4$-R5fR>)P>WeZR<;0lhd zDI=%o9Pm)9nT=?il|+&Ao?NrTVh#-pwK~E=Bk&G)goTA#98tC?v%_k(*`nMITT~?f zo^B4cSq$tgmm#9wVp!)6iwF-3az{p4oU#?$!ca0kD9k30cZNkpa|?MR#eVrF4h`_~ z2{8{t_W$~$o2cNpw;uTWPEEZ59sJQsuoH6Q7-NdZ9b&FD?=bU>v(TKFVoQm2j-}eV zAZ$VST=(3lB{60!*tR=ghO|4L+TptvqvboZ+(~Jk2@})OCT&%22~o<#0RwkeRy>{7 zU+~xRpXJGElO_yGn>bPV2NI#P6DzYS8=kJnoSS%OwVDzQ%2q0Kc#bhBi-ZqOS@J2x zu?}i@F6?UEBdF=1)j+g&(K%X;l&YJGnr_}2i70A~nh~b*DaBjEXo6a!W_GAGy?r(0 zrdp$(;vkD5f#)OOKOI?%p9tg-{JduHuhx9rt_C+tTSi;guBKO;nm@L!K^A{&pKIQl zN0mAJbOJS*Uf4dxFJW=m)JVJv^{^JGSN}@QVDf7 zQAYz;@E_+7e)Y>sgZ4Fpf3@c0b~PLV-)QUF)o=)WHGlNhsQX(L0@z?L1o#~@K=AXL z!TcA_ezE4`b~PLV-)QT24K!V!d;J*lW1veCkOM8AFycofn?mt4ylnqCe4gBW-l!vz6eO8>Z4Fo6eusLjinkN}T+#ZMg zj_Wje$GjobFxmMan;aCXUSxq9y^YMKc30u>0~&$+1{@DtVDSqir?fODr?hOeXKtsi zT~E~19&41!%5p}}o;`YW`Ori18U&^Va!5IgT=uOv+l?X*cslt7_!FC% znshiYGTCcvE6peT1578vBf}a4)9q16xb31!EQvCt~gnb+L>=Eq4R}P_>tA-6)HLCdU z{6_cRi)q%XmirWhpe# zG|(@U&;>V*%Z9NZf>v=i@~G|GNZ~^94OVm%{33iwJ z<1&z%NDmXLUVREvT@L*2h1cac#&Ze7 z5V|x)-Z*>qqi+Xnk&YctOx$t#<2ohj;6eIf-AyX}Ba+kqp?d@H`-D6@b|Bf{>7SI` z5&yTk@Z_GNCE%{*vX?KfqgE#khOi{ zgiU>mAN@4=qa{-w?APzTeOcSs{;rd|j$BdO<-x8aRtg*UBqZbvom^?t&)Z%!c})+$DV)wu|w|s1V zs(uI_a}wF^N$!#mWfoZ(w z&(kv_eQ;XJxnarY`V1fZzPZo)&dL_?J_sOqu%7 z)Gr_3N_Dem&zd!Rw(`@~t;$c@Gu17st}dN0vG~a0lDwe7T~{4i+AphT`VOgh>eQ)U zEnE8K)Ts|YJax(!%U66kW$M)FrRaTU`&Q-d?AfJwrqb5!RK~M1O}Q~}#K^Si^A?OR zcj!lDefD8qsxO@$=rE_yOk!_PsFZ{n&2jle=FS`hL(k@?PvYbFcg%1Cpn9 zG{{4y;^wGxI5K+Fi;D z1)ob_mR|qd^E*5X(+980{Nvrbf6Q7bUHmnYO#dYU{&Q)R`^BerAC8P(93FQ2gAacQ zgWjbHY@?is^=`(A|3FU^#ie+o=(HlZc+LWYj+6;$8Z%5YSqf~^{0bZ{HTmu`bgP-F7Q!R*Z%lE^L{@wc|+a_353Li5CTC)L<^{hC8O==)e2QFYBg{zy;UlYO#a{Xotf~^d++alKL3GPIdjh5 zXYak%+H0-7_TFn(NRTxz_{h&mXT*~OALL_}P8G?u)bN#lTw=YGu4layW!L|<-bws{y0zix&Yxqs(?g<9 z-ZNgUFGeg^nKyr2R%5?wP=B^))0J^Lg4Z3v5DYR5)=7mdq!Kq!ES$upYqF^U&#&0L z=7kh`Bfhg_Ok8`{ypR@qNacYEsf5eOI}JXDX;}EWNL!>^WL#vj+^S(}UgGcRroR1l zbotwFn>=s5^_IxU4^$C$ejml`#O1+Uc)0Ysy$0;|cI^>YuBo z`=@8l?XyBH_1}|O-^UJJWW}xp*~fz5aH4J$rkzsE*euOx87b8%W{788W0uZbWO${k z^75x|!>*vBqqjUW%P{fW*5H-0MQG8h zuLiG_JwuCL8?kYwX4x$JTduoi*Q7URMNe_x&^6cWnh3ldRY#3`^{Xf( zu)@!kpK1uWi*f=P?woQ5e)&u#zTV|AC%No55W@q;rJ#cTEO2JTWAc~-mVh;26OU=SC(E1V%krlur3ccJ^L6?9e0Wc@ zu{1s3l8=cE@tu}<%DiR1G6Ya7!K7%Ft_sW4vGCVaZmzOaS*vV=U4z|&J;S`ie8c>M zlLiL{Ctn3$;8k&d>Q$Dj;7=Xx8toqKx!!xd?|T2}q|t%V$rH9^y^#Gv&I`FO6uwaO zLZ5BL=)AITCZ+<#X%n*qI3ozNp+~;MT7;C34M+4px$ME4W~{tt(zplqT=u~DnN7HQ zu=(m=PJL)6A_x6^uY2jjho}?fzEn{e3sN-THtJ5r4fi{aAaS>6~dZ&M@oKNHYkPiWBTEGIS9u7b+Ga6kn0- z-!rSh$qWwF(l}I0!wS*3KfKR_?q>IM?#=F(-Nqu!G8DOrJ$<}=eATWR&uYg*zUQ33 zcC~t1ye@H~$;v)ximDy#&sA3M}7#@w@5s6OIHs2K8rdgtIyskB9%XdZpi0hYc z!bbFPv_=azRQ{p?duK-IUh8_L;TM&Hp%7+yKEo^kj%W!MAY6bx*`&8R^qS9YTAi6J zQ|{{bIcZj(OuJ{vygMTZVD*L=_gGniNSi0P&w@*XUdhUxmb*6>%l|H#f@jZ*EnzKW zT*Ja5Z|K#BS3mLOt9b?1?9Ad(c~^~dSFEd>`B+JGg2~o3a@`ZpKd*cA+%vT`cE=Mb z$z#S|fBl#-UGE8h&F=oYez&m{{@Y?z7fe${Io1qQQNV{I-X4U<7 z^~<`vF8US%SG*X#`u$(MscE--d{<*My7#UIxFkW7wCKIq4YM1P{MKNS&EU`(&Dav| zupwA7Vj`Ikt}hmv!h6-Ln z)HGP{vOlJK3^!MrM0rUF0qo>OFS2UYhR$Y-Jf)yG_)d8e;z#Bm)UiJtlpR%{Hr@XS$&ZEzWZ>hqjyGnT55_Z--lp~ zIzwJ^z?hrmbL9DE8}qXAVW-HZOHfeMcp_3F_V3G@Wq1KELmUL^L7pq^e z7(kzrlpOG4K$V%AndZ&wBb_o2YfZ@m1FI29CdMe$j8iPyCl6{S$FTa9Ic|4ZwYPsk z@7~qv_bdS%h(}UF|gB&KSXP(Po@cw?!^)p5c z%_(==Y|%5i7w)Xl>9yBxx?!?S4Qg9TzYClT-Ti~eeD%F|gLGUZBkJmKMaA#`n zJZA}-fRSBA1;YsnslioWe=1uV_I&l97~;vy1Xuus7VgFLR#ne{4a=R;y!aFi7H!CY zS!{r+wYnF&#_B>(_G`X%HF%&&HkZoY=iFAXmHW6 z5vv!ke%Nr!ExEZ(nVBz~yz=_sbdHq&&+wEJo zuGLCj#gf&BqxVMN{$uogM6%S&oQHWK*65iK;rVh+AH1@tv|y;qsRpzZBtIB<$fsId zgMB+P)A~PHy0b*T!_{uS%=T(l+9L(S22>ZC+^V2D(_H8dD2sDwp~YQVZOOfA7{tsw zhtAa^0w&rMpTHuc>=AXe=hJft-wJktNbq21g?JdH;pM?q<$cThm6w+HFE1-E5B3fA z3zi1^2g`!xWBZQnH@0+a|FLCb%OB|bK>5mGb8vI;h2S58`+^_i-^pMvcp6Q^oWoqh z+{VN^68RH(vAw{w(7DjH&^@i+w9;w)riZp*?(nOFK#=aHENCp z*Mno0hU!JiQF`XZTV?bKh8e1vUeSKN=I1+HBSs(k(SK+bY*Tn=`|LkWpT2MIZ@#^5 z)ccS9{=kJBX?}e8AF)j~x+i3Rf>u6xYV_!t$-DkkRfXLP%kN#bto`}(J8PyzQ{%gC zK)I3K&lolsUW<>zJ`L9P?N^x9EB!m;upNcY9qF%rXB>u6STD0L?}lQJFXbv3hk@lP z;$sXUM_e(3QeRy(4vWpFmj@U1(T0^yN}7;4zSo58xq+EEIBUkxWNf-%9dMJQ!C4<@ zNN>t$%53V@)VnFGDZ3%3DYq%FDZi3VX`zhY#`l`sXO5cbpMf!4 zy}FBIxHY|>OkJPxGg&U;OF%yVn;NA3r#9 zLI0m!*Kx0gmBy6=p1=O3>)u=@tB(g%K0gMw4I(}2e+PRt8*1ypU|DuLHny756sI>- z&i#3gC;gA)ttv3(rX^dAno7?_r~)lFGp7)N36l{i?ZhF*c49{dj$<|&P#pa;dIE3` z`yRHB2ab@$;y5haxODnGXuk`aeeW{eWxglVD1MMwjI_9d<3=P=9uiAU!mc8)TBY{& z>(!Gd53am_{+Mmkrv72ps~?Y=G_kx8;k5R=^_F48h8aJ+dE)m*P8+DX5S{O$QxocV zYJzT+!GaL5dbBbYnU4!hzy2RiO+drqI|dWy99+8cq~}}(O%|f&dHt1sox-^afoGBo z??n;c=P_+Y^cSLOKhUzUMqnz&zbQeRVS^4q@={=WA@C{v^m|04iy@BD$Ma{O(@(|X zsV61h(C+t)X{JVu!%Bjw*hP+m4`9aV6n2#J3X(*|t?L?sw`WBsAeclFtfz;AK@23_4sTlTG}*0g zFnfFVP8*))Kw$UYTDq;p;(yrpd2)+edsuyLXvz7RJJXWiyBCZrhaI)DDIbifSS|Kc zAjF*X!c*demVSwEVg!>?A-gzWSe+lfTxwUvXPC@9oIz)j&Jl}NTMfp@@pFi6)D@2H zH*HB;EvCTUXd3+5&cV~m2HakD`~2KB-)bqt^56Vf6?E&fy)x^66pcLA^+5F4!9enJ zIXP>d)3rUOjo$u-PsWuvgylp1*RcDCU~gSk|E!u4RhsLU6&$@wHe6P-As5Ry92@+# zy;Z5Z7Q?ijScu|Fqz{NbGaFZjOlZ+9 zd}+*8L*N)R4ZZdzxisoBH$7Eihnv}$Kg@F&>YmV-B(W&|oUH|x4 zcjcM&*nPjp=sq(HZ{DaLH54E&CSuA$;*8RNA#tC+i0$zH0#(JTW6TVhY+vAD4(k^d zt3&?StWLAj@`c B$Rw4SzSQ=Ui5YQD@exg+`lsp<{syr;k8E%leX-35St!f~_w0 zE+oQ7#)2sDcnf$J5l7M=`(r4OGbW;a^J0GtdAqP3@9SOKGvl;pdM;&LxEn1QdA=o% zFL3gR&1(MwQI(uuV8y5dO~9H_;}?j@pw}6`z#eAP7wA<+G+EQsa0lW|u_X?RW>l7i zHnX-+uNI*twdXLfj~h=sP9@P2S+scGFOg_LqD2UZDecg-g4mzk+TmzlH020fO#yvM<9Eh0h*iLr84cnyC5N%zvrpX`>Y%TJrOgttP z<>IVPeDyy)bV%27`0$yw!-u2%$Qpv!+9Fv2lUQ|Rl2u1NPha(E z1*}vu$_g0Z8*3&k4(KWmJQ+iRS@1N&&#YFZikI1%idaPfxR<@~G6&L}4C)65GdKd> zFSb{J27$y+Pk4(1ITHRy<)q}r{#KgLB%<1#eJ^@_^a^d4_TsEn(OnWoUb_M=Qzhg(TzmI;0r9HPG>(w;> zBLhq-IrlQF8zDBXxy)z1p|3CVssS)rWGgjo%$Opjafx+P3DXj+T^=kLR&`s|qN+_* zd#mZQ=es>BY}1@jlo zPwZ`4c;~!D(W9#qd!IyODeX&x(k%zZJg*>}z?YbQD0`D5`Ev2$5)vrQVG^Lrbup7)PrwzOV&qegm zyE3=~^Oi#)c4E$hDCR`5rXF~dAC)+(S$I0R+~A^q+#YH4KwMm zf!^^P`Ramq^8^C)3`FwP)cJQC4>OkU?-CJx@ouaPlzOKI?P{Zb6$0a;wov-#7!?>J zrdTy&6^vI+Ftb%3)!s|w#5o9(Q(G+NLhKj>$r&r&AjKOGKNa1r4U^H)2kNJoOInC4 z>E*@2B-N=ibsBV*4F;P77Tyx9zC@FFD1+d7&pAXVmp+5OE?YUpd87O26h2*N#2sr` zcq;1qMt6mHg-y{s{Z}SgQ;2{~K`%tP1@Zf0@l6p?1wNaE8N!v=RB zyol1GYr2o={>+hc-=H6>$r1exM*``G>mE_-44@k7fu?=>X~O0Ziv#9{%omn!J~w5v z@#N`$iF}``#u;8SY=!kxrtXKPvStJfrM*>ArY@(K!&jPQx9RB)uu+h6lkOhy&!aS z+_Jn_arP+69u0Y+UKHA6PrYF@EZ+ch%`bv|>`AF+>_+pfcBQ_a{G#h;R`r@u!+fV9 z86IkPlEGq0Q8v@H2(kbpP*!lu@(Peubmiw2UtvW`+}7>!7N*l%n6A>}-a-r}xHK8R z(PZ3D%oL}4l07L11ej(h&lsDr(!J8N65$&5W&9(KZY@KMa8W2CgYkkeBGb)=! zZ_#Y9WIUSBb#1aVG1kKK4V3m>6i6VMtxHzPm$VMQQ6TOoTIVfK8Jn`ww$i>bWpm2D zlz*gPDvbl3OT!9apNQHK-F`l@fb5GlHe4KA;QR_inJdrsnRY0TWrq#=#$|J?()}^X zttNS$Sc_Xe7y&n7Cs#LUyk$kIPW2IAK2UnvFFXvhvTagWrZTw zDryTqicZm0FdMH^K4Aw-4+=IPu_)UBz~R^v{JWEKcD%i@u-#VcTgXhshcj=N;2UV ze^KmpI_kRUOi>Q8m&TP6Kf$?RQGjexN_{*A_&QeLwjN| zG-UWkvB!BGm^uiH3tJ~PEWAWE%N{6+h;++^>+&v$nRPAs3g_G>=1?xMXf8TL?E;@@ z4g|jcf^=9g8FN}+;xDy)ee?9`7ap#5`mXqKYK8(Hu9i4zZEO7SwN3HE*mU1>+SJrO^j?Y#9o{{kD?9Ji5UE6e3cpSbQb$5)nr*Wxx@lt=Vs zB9H$3YV=Fisl$Y#mHrGwVHQ`g_luWf=q{5d-BCQ5W|kTxo|t1#Fs@U&iPX!9C;Ir4 zArR&}FM69P{v>Ae%Qzun^Bdx;-eXUsoWv9JMNclwV~RhCt(2E1iIwt(_)7WM6M0+W ziTR=@7v?d^6ZFyDsP%HpSL#*vcC|~VT@Cbb)@mxf{Wl1WwL zY)_-CU&7H`cVi$OTP_LrWKV4U*cwwa#pVTDb}RjPML6gBl_$PgyKUQAS;+LwH+b_a z#$Ni-rfSR!+!4%IKC{bi(0pdM-Qarz#~8g4u>WT!4jEA9z=Y&`vG41iOs&0Lqa#U?dLDzvM!DwFz>hT5N*wYd8gBFNNdr(i7ZJSdRxUw)^tZvxEGV z7q&KhkNx(WCroqRW81iH-A2>MYpxl6?PJZ&SgE$&I6^m*Ys>ltt-5#BpAA@77MJ>o zR-poy2IZnBZv8v&m^|-@)$x_#6TJ_SEM-N_Z9y-#*8G=sxBH)|YJy`KHqxX*FMKU} zL?W9fFcqU&Dmf<=>kfMMD#{AB#Icho`a3BuuoSBk3*=!z>YkbyyyE7YuLw@8-?Vh; zCixn_9yal2+?*I(x_PtQ1MamvgfBziz?!M7pv!8qIsb(t^^~VbZ^a6H=?10wJ-k^qu8+l~{y`ukPH|Z&$Bs{Rm;y zq7O-&WNFK_J#EPjy6rBT`CqQD!Cp2)krzgS1df0qcP`eLO0J8Q9?-LLQ+xH^(!SLL zvoFso9MQXeY1Pn)S^fLF-4EDoH{V)52QRuv66n=7gZ2_m!@C>7PUDgQ3-m6o{&ysS zzA~k{Qm?&2LGX>?D{a{~-=OkZ_kY1sy&GdeCw!E>5lK|seaZyChz0h5-Gw75v`mM2 zFhXIwWaulVTSDt1iZ~p4<=e{LW8Dadfu))SDH=^3j4KYlt<{W;-iv_ZQ=ho*6GW_g z>cfT6uMp*5H)QUDjneycVA+wdk?m?~5J6961)>RIQ&FrHYyIjGkjPda+w<}1x!O;A z3Y9fKoD%?3erHp&-xCifztm7~Tjc!MdD3Z>iecyjdkobIzuI_h+{~a;`$ieQF~VDBH0iL66t)(6s5r{F7t)VvV?QKz zHayj3)15LXfzsEpt=YH}baP;YF)Ntuv9{QqpqlSVm)&gE(qM)=lhX_pHm@_&qL!!A zZ6TXLV`qfCSrNCBf_<_xnlfI<&~LJCvTd?&!tVJ^?oFOe-d)yRwq5pJj$N)@?p>Z; zUJut_(9u~lbzb90BMcA z-6n_6cZ127Dxtt2`=H5sR#yVq@y)RqN6Rod7Ci+A!&%~Am;C)tvnw7TiU+3*E0G1I z_aqne&FYg|mRFWvTu@qAT2#_!V8PV|6SF7gOhcr>nYnjo-<@-JuD>7;!)UC2FX}Te z9|`iWDwv!-Ij1hW4s(P}T9d9`-@rIQO&7!oYVtMto01v=^%?b?E0leS%W^lDoGdAl zaa&@#FScgTFN^ABS{#$(;+8AIv71GeDFrD;{nZr{i+{5t^!U2aKm)oU2JxKqcw1yAA^HVAvQurU@I3c2N_=<+M#Mvd8LlU-&L_dg ztLy={6&>D}hPi5+hJgAQAHp}>6C++`2N49wosyL@EakS8*hvLEE|Ia}v1luH{7d95 z9M%;J4*wRy#sB=r;JI% z`~EmdCt`7uE{#RRI7tk;_J4|#WPZKtnePph1bO%Y&MW;;_a5ZJ`BO$?yL)2`GPrV3 z_nxd1#E@_pj=<`G?0g`2ooz!b!o&v578r1{7lKh3H(&#XVM8n;#RiE;fy2I(Z381x z47bU#L70}YAn2=AqDPx$r4|-gG8hF`efKQ?PV@)yeo9%+Q}Nzy7=@;)(XenE5i>uf(PT0V$JD0ls9PP?{o8)j?OT_o zT$cN^fD5Z65lk21!nk@zBE)lSnHWW4R*^0~n2%Kh5l!L3Wjlc+&4k&I=et^ShiMaM zj~`G!^126V)`g-k57N7qEXW$9T{d<24S9JDnVCPjb8Ym~a@4L)_b5G#ebmTck(}0f z)S7iP+kZ6RJZk;c^zY20+27`^D^B*Sq_q1AJ@?5uoyDjiW+P;i1dVX`_+%_BixFfL zT&{iBNXmndj`fb7HAWbq>Ks#My#8WMkAtg?CPvI`#JHxAmEM!>ED#4k?~<7kLAD3^ReWKYrn4{ljP(>@TysV(5juz-Jy~* zcQ`$dB)@9>nO&FVK(ug+#b)|Jn$LfgoRx`HL+4UzvGuxZW|JkdhU=PT7#+PZC z!NJ+SgSno*=7ZL>r_)2pPxjJy{8rhzUXK)8EBfZ<6z3IU=1z}YB9?yHg?_Ww0)r<_ z6_(_b)gIbYagNbS;|}te&S&@8Q-L*@J&OpA3hrQ2_MB2j*AOG?U~|qjFQjr4P6fwE z74Rg)7iiYwEN{)OvtM>o(j3Q~t_ALeo`v3pzJ>ldN%OK6W-rWHn7c4U4<24-d1!~}?K8a3ybb7EUbaSK+Fg$ik z%gkTCm94v?y6bbD?D2hlQ1s#Kw|+UZ<(5f1ru}F1?LG&q*J|1yt2gw~2A-(ffpf^_ zO#V}QLu&uL?Ea|@?QczG^lrB z%qF%*$^K5UX~m6*A+rku%h+i7d$vZ&Lt_8G-4*3UitpbQg?Fd&6busTd=&BEcXvyn zgP>=~>~mtfl<@;Btbu05o-y4?dKa272ZebbOeE@uE8Q7P{b23~+fGCgy%Sdr@$-XG zGMCCW!z5xA`aI|_^q>XWTCDA$Ex5U72O2gTy2&Pv$<|93rA&_sWJ@*(W8bK zZdUL3^ykJ?(QlzOUIC6r8^6SQlDmUB$sV`f@4yl8dP|Dq4TJxU49l6`9?gx@i6^9* zCs+{}B(5x|(rWRe0@f`Ty(emW>0!W$+Fp8i@HUS?(t;wb~-AHP1Eo70Mia&dMz=% zCWteZaDInGX;<3+znI3RZU3(V?c7HHeQWKB=}7@Gh~bA0?zfoxgI#z6X!U( zMhoxx`R9Uj`06yZ7k-4xjNifwcP~~}$uW{}!pUNmJu$@Y;mDiRzjV-@z~`mG@)C13 zm!=Q;g#{c2VS-**bY7;F8m#E(aWCF8uN_?b+;eM<-$qYu-Fi{Y9*o6~KLe)#4?u}o zF){C;M2w^38)pH~p#yfjwBY}HMbRhpm@ig7y~mWTa`o9Jsc78E@C@sD5Kac$)~!*F zR)@hJ`xz83#Kn))uhq+{cWl*C?9}f77LiqHN270RRmsn- zUfmq6GtP|Os>|&9bpFnr%f&VgJ=N{YU$C@`8za3apJ?P$sdejb{NSAJ=@x$0CM5JEA zxeA$=a5ox1{4;GY9a#&iM-#E?T@~ z>0NiWBCL=z#}UKeXoIwU0ddt(Z7B4u`=i`N1F$$YzY2zb)V|i%$irr!bvt?-7;9A5O+ z%C#%BaR_C(Olw5mH+AnbuOE49m{*tUX5MMYt6_!(TVT4s!S{W9H+N$c-hE~F>~4ho zSL)oUa~~@8@lQW~;NuA&&6PWUTl}}%l=|yGjJrrYncYC78Z4!e4_5W@b0+p%>!GNY zt#K|$8y-*bJM}Aci3im0)lb#m)q_}Tu~z+3wWw!7^oOx_~?@Cy7)J*3`% z6@C({0b13+P}(=@8Px_qL0E-Uow`FctLf@(HADSLy`}c5chsNNyXp%yQyozI)PA)^ z%~JnR>(pU&P#sdURVUV;txS@&k>a0|&)N%Enh``f@Inmgs8>@r-{tHtB9!*zYQv)n;ir*41=>Xm}=eZGKzrl>3Iyn0}|E(~rjQzG|U9PgUbt z$nYBQwN_2Q-yw2ss8kb;STL>IiYOzpa2n;a-O_fnTiTpxlhj}8^u1ryQR;W$7ximK z{lfVE4d1U5b(8vC_?3EH_(j`m@O=aH`JK=R*Ha9yYL&R&XvB%pFitY!-y(y8-Kx}k zQg5{10^H9uwW^~DTCzPUY8>*0uo7mrak@&wzN`&~SGqp|Udr?xYAL?cOuf_?^M`2L zXKEzq|CsO|^QNhx$eYFM$=zr0d?UWQ!5=4ZUnOuQG`Bp4ZyDMK9>#NJC_tI`f+yv> zRo;PB(I(;@wAUs?*Wevf^_5t|R;hNQZDsOB{u=Tz@=1Q%YoMplLuirsi)--TGvL1{ z{+jR|B6Uc7$!o%I_zIuko$`GJ-^2KZfw%Se`xXA?;qOWOy%v9W8=AWROLw)>fp=C5 z-w1ySj|hK&?`@drR2N8a8k?J{k{Sy@$T4Zc(HtuyadYvSKJ=`X^I(qDSs3*I7M zC;rOwc>fi=qAu^nX^T3;G*qxh@x{A`;VenmH>vUP!`zIxV3X8jbql=6x59sXo0_Je)S(lm zs~M1uvmo#1K-SNLoSzR#zYtP>G3ESSkn|$wmqEtYs|LvUM#%RjB@+IJ&_1G@9)x^; z2)g27=%z=YiGB>MHA9m;4&4Ol3(fU2$nBp)V*f&IfcDy`HbIv>4ej(R^{o1}dQSaD zJrAAMs(!0}2aOeiE_y+|s6;1-77&f_s@ef<(yp)-S-q}ysXt&9z#pOS_CQCx2@Urr z=()Gl+i|V7ml{p<*kS0L_n=`uh-;gp&@~@H_k5!MgL>#Q^*QwF7tmv!&{!v+v%Z2B zJV~AUFKE!O)hXyL(OPGrt3{i2YcS~~DlxoQMpzPN9BE^PFU<~@rPI1}=3TRwFPc4L zfosu>C36-|zhlONyJjqzG2L+0-Afi4?-)3ssz%_za>C09D+ntI2NG5j4kD}}+vS2= zccRdbR+^Roi$T2K1JZ0Esc+2oNL~FRp_(PM?bf4)H^R?#f=5v-Amc5p* ztjX4K)}_{vEz96vkn&M#M(UNRD^tHsOHR8t z?Ij%XI4=F^^!GDXXY4@~vS0SviF2gx&H5tymh2_j|H7iJ;W_`2^N*Z!xz^ldOgNS2 z4$U2%dvose+{L-~<*vOey(Q$(McW`yT8!qTgfv zUMwA3y1Bor|G56GWvk1tDF6Ls#>;Xp8++N_ijfud6(3bzUAYMV8Y>^J{8{Da1L_An zHsDtS_7CW;%B-rXnpL%~YGc)JtM(4OW#CT+{<-?f>Xz!`gVdnRL8EKjHJLTVH3Ms| ztQlK#Yt7u6dux7Fv#w@i&2MX7t?8&aQ1g$$nS&b!Zyx;F5X+FMLw-DD&ycTcb8By_ z{Y~w*+TFG9)_zzU9eT&*LoOeA`S{D9y8Q2#cMZFJ*rUUa1P2GN2~G*l57q})2cHN& z9SjBAgMSJh4*tg#!7Cm-)!&`^{`^wv{+5r8$_4*?GDZUY?By&kZ(+X*OhwI0YIff8-e1L;!;IG)#&x+A!r%n^~2#Fah>=tY`*)r&A6@5xt%ye=WEARIs_KJk2D>~=u0 z{E@o55pZyKGay!70oL;A)lB~b!jXidK(%}|j@LI4-b^@=xh4Vs`D!xopO0vKcLUb3 zCexW_7U68BT*&K1go_E65H2NLPFPRaK)8aik?=mgp^0!M;VQxw)(z8TD7TH}h6uMX z*Eaan^3}`Th&O{Ma#FW;wy^`8l@A#$7>f|@WBUDs2M7=Horeey6JoT5^qqXealY*o zQ=aDiv%Ee>*hPqAwxLV0+De-LgA1? z)Isjo@w$cAQhFh9D^Ej&+X!FA??T{Hp311G5cm`rArxE{0$1`>@KeOHu#*ROiokmU z2lKwPx(K~b?nsG6N=ht3ZxR?H+y-th0v#iO(&{4Bfxcg)!h9Mbl$I8=lw#$LZpU>m zP^uUujsO&F7lZ!=j^Leb7yq?JWQ<$cXa1P;I!g+*u63!=FK)8sx z785QZTuQi{Z>}e7AY4J%NO&L9G!d>OTt(Od%oM}=5ZK1|hX@4^#jro*{!ZTM!1|tI z;6d6LAr!h7tK+;DikA>4C8Tl*Ft8nW1oI`J^?E>|bqO(FLd=(t)+MBM3Ha?Gp1w@j z&h#CiLJ4VILRy!A%IhJ!g_rtLBK3tuDc919zHCKbyk|SEUj{$-1?{#&%6kZfA4*C6 zQr4lAbtonEOG*7w<}GF3Qsiw$dZBwM+Is|g!qZ(0DDUZyUe*j)K`64WzZ!(v_Gka< zkM?fI^$4aMi8}WO-33l0oC50iXHEK}56XLH5zgit<}lY>!g+*u63!=FK)8tSSxmTu za4F$(!g|66!WD##g!d6P5w0X$Mc4xQ+@IL%Pi*ujHu|eAtkpJPvOjUsADkdHZ)fYI zC-x_P`p5CJkLmXl9w0o(79AoyOxVf1$N8SKOw$Ee2HYN@q=cIqSltd-9sL||5NcS4 zUYrFu7@St7YNICsN1*gF?9rE8;|M1bN^dFyr^$O}@jbKohB-_x-l;NJ`U3AHoKJ{J ze%uj#fsrQR5<<}zWlHo#nG$_bhIkGFMPHOD(HCXvKEfu#m4vGZg(u61)iUt8)F(u^ zg|*riy&b<^?vgf2|0+}MY?olQ3_LICBZT{yem~&>!h>wlA;QCioy;peu>!rL2G9#x zT|s?aL5_uGgIZOTpays8IhbiY0&Lg~&a6aJz z!bQxxm~aWpw|dMFYN7V&?^ftA6lat^m+(Ttc7Yd zBH9Lcb@W-lk%ZTRvejxFug6CZ;(7wpOpHcwJ(<^2(C@0zN91kO`L;Q{KbLSG;hlu@ z2^SD9 zau+F7LuV`Q2x}=Zm*%;UPHUR29{d{(pe5TL%L(+X1Jb^ufT4q@Tm|a|!1W-bpy0 zZ~@^WzF{%p62hf~%L(fV8wghrHWJ>)vYH5260RZ?i7}W~++g5Du0w>|SSztz2Ll^Y zL*cibP7Wb=4MES6r?dD}`j`dUhlT3VsCv_fkkJwC_%k$ieB@KX!9At@(Hc3 zIZQv7a30~Eg!2g(5H8{y785QZTuQi{u%57ia0Ou_;e9NziEt(1D#8}Xy;{&qS|swJ zmhz#Nc4jT`(~LV}Z`6`rwUiIFln=GQk31FIvKHJcP^`yVj4qque-Z0(C^hC#;(sXK zCU@j*LxJrh@DbkvI0`A70llchC~*6BK=Ck)f>%MH@bf6pQSOT-8ik&91)%WKDDu)M zye)uh;h!1O0a3!JmdB&6a zGSg2c2Tlggi!qNOezRM^b-Mw_5sJU-7VwhX zSxmTua4F$(!g|66!WD##gy)!7JV;a6kETG*$aODp$Q0IO3TrZjHJQSiOhL^LLNbcw zUq_y)BlYVbOQ9(tmyQ6I5Q>JaQv(Ra)~bVamH8JL9l(DF{;7kF+6*YZ!8%x~@>JSb zM=q*EOXXU8gLP=HTno3(!y($sHN%)p4v>$FW`=$9i=f>(z0rSBKdjd4upw9eJh>GeL4K5~GehQwPZ} z<%(~xj@r3SiEpqD6xRcaZ?F#IDQTnl2J4^&Bqc2j>gYP^=sN1?I;=;K_sgiEj-!S; z%-qPe_y+4Bh2(AGbE~7xSqG^o*Fw`edfw`kP{pI zbZV~Y)Lhd^@#&y=A<~HdZ94sL)2X?pQ*%vceWug@Hl1~tg|c8Lfh*boMJCLGwh|~K z&{-UT&O+(UxE5dBES5ft*qa5tAa}$UHw)6{AfU+bSsa1R0{@S|wfJOaK`#iD5$J5T zYc_4d*|Z5~qxA~+#g{mnZJEtF&t{!x(6ha@yKzS(=W^y+&RolpYdh|Ut8x(tAV*1m}>=dtzfPd%(a5KRxsBJ z=32pAE0}8qb2TzoBXcz}S0i&ZGFKyWH8NKtb2T#88s=KVG;5e<4bn7YhEy=N25H(b zhanhlW}0TEX+|2k|1$8|j5P90tg;r&;~W7LdD5ba2#a}NWJ?P?e3GV=*D{aOf*vJM z#&<0kVGEQ|UJFK(0;~CE85g%e=ExgF=Cptt=K&7owP>prXhnhJ2*(pnVtTO?T4*P< zkjGjmVOqe6l71QCa>9DT2ErADjf86mn=vokLjG(af3{%WSKc7@Y74ks>LXt67IJJ0 z=5*y+#+xlzvm{XFaS*VGu#@S3+fkgo4jj;b^GWzBcNb^GWzBcNb^GWzBcNRmy04A8 zuZ_B|jk>Rmy04A8uZ_B|jk>Rmy04A8uZ_B|jk>Rmy04A8uMK#T_lxe6H4Fj;|83NL zZRpo}T#N2&11+SDqWjvY`(%}#q!)^`QTMe`_q9>?wNdxAQTMe`*R)ahwNdxAkR7|+yp|b_ zZE6`)E@!TK!Un<>gpGu2Sd-=`G_-2t8$yIK`>+l471+-Dgn2(gD0275)wv?IL} z^$^cSJ3Sli^lY?)7R|UL^K0$&Y_!v}(GE}4cH9xqMms$l?euK4qX$V!nMZ4#k0`?NhNdMqP07SlMe8wTo)4xe|D(8gr(@G9jZUC%LoN~9jcPo z19)Asl7tclq_*38{w6_Bi3_co2FnPat z&O3Yx?WLH_JeolGzO{|@k{ykGdUgZS(qKEu=nVd{b~B}|yQ0A--P zVQTF#bwQZAAWU5lrY;Cm7htpoT@a=&2vZk?sSCo?1!3xfFm*wgeLPHE5T-5&Qx}A( z3&PX|Vd{b~bwQZAAWU5lrY;Cm7lf$`!qf#}>VhzJL72KAOkEJBE(lW>gsBU{)CFPc zf-rSKn7SZLT@a=&2vc%~sS9MCJp9Gf1z~FKFm*wgx*$wl5C$$~Zc;|9Vd{b~bwQZA zAWU5lrY;Cm7lf$`!qf#}>VhzJL72KAOkEJBE(lW>gsBU{)CE{G1sNV8r6QzMgp>jw zfKpf&Kq&TAgp`VqQkWG%&x(*zuqr?)c(}n25mG8bN<~Pi2q_gIr6QzMgp`VqQV~)r zLQ27x1L++hr6QzMgp`VqQV~)rLP|wQsR$_*A*CXuRD_g@kWvv+Dnd#{NT~=Z6(OY} zq*R2IijYzfQYu19MM$X#DHS25BBWG=l!}m25mG8bO3CgAc>nQFpx9RtQYu19MM$X# zDHS25BBWG=l!}m25mG8bN<~Pi2q_gIr6Q!%K5FfK)Y|(3_|QETs`*4{_0 zy^k7UA6vAKT6-V0_C9LueUy{?sI~V|Ywx4h-bbyyk6L>_OWe;A_p`+PED@{R(8m2N zaX(Ak&l2~u#QiLBKTF)t68E#j{VZ`mOWe;A_p`+PEO9?eJirnUu*3r_@c>K2iaL~d zfF&Mai3eEX0hV}xB_3dj2Uy|(mUw_A9$<+FSmFVecz`7yV2QHkPJu!)&vlSCgLvBH zT6`J@!2<$igebj4plIqt%yo#l4l&mu<~qb&hnVXSa~)!?L(FxUxehbeVdgr_T!)$K zFmoMduEWfAn7NK2S0Ok?=2eez{CJGx?qeJw9%FwzhWALC=}aSIKN( z5ea_`Zx$%y++!T)9^*Lo7=FnenO8kVK0L;G)nlAj{fzd;XBg=!XaX67dyV9WSTFL=2_ekkHnWqvmNW7#SZDD9nwiVq?2|?Cv|Qo?T}8|A)T~C zI%$V=(hljQ9nwiVq?3BElX|d|c1S1fkWShmowP$bX@_*u4(X&F(n&j{lXgfa?T}8| zA)T~CI%$V=(hljQ9nwiVq?2|?C+(0<+993bx-7Ip?2t~{A)T~CI;mAV(duU07tD0h z4(X&F(n&j{le)E&y0w$KwUc_YlX~+w@qCLh%%xCdZy8$DSs~ zo+ihhrdQ`QIrcO;_B1*6G&%M(IrcO;_B1*6G&%M(IrcQlmp7j#JWJRGc$O_a%a)#H ziD%KqBe*YZJj*toWgE}3jc3`$v&8UOdScI_jgnqg3Y}#e&$5kYS?*c1RGvz?T`a4M zWp%NvE|%5BvbtDS7t88mSzRovi)D4OtS*+-#j?6sRu{|aVp&}*tBYlEnrkiQe>Fg%G-eS<{3@eq|;!)Y7C7*nT&$(+U%F8~B^C6;1+IsVRP2>j3 zCdEV=#0+ZQa2r;tcQ-2)Lxa$v=vapmO-FXJZ(FYzF@ zKQ<`qabTzw2TmJ|7W~kgdOoO=#bUIX%!rf&fJa6PF7eMO(1>U_28+?i^vI^y8}(NC zfujZxh#C*Dd%=R7u@_wM+6xPj{PMM0twy88YDSUBgPpHbf8is+@bc#XwiFrXkaZmXB!+8-sAL0YQY&IM4VH0%V6h%bhlZqm?i4oMoTaW-~wb*S&Btyl3u=DtE z#;^cR7 zNOJ@eF??9fpdtQQ&1OjsstL=OkqxNCes+9}_$B0&zetAEIJ<-&;S{7x&{2LdKknP@ zcJP25)C2wSM!~1iVh1UuBqWqqBTADA$xy7|!z`5*CUMJ)_+Dg2Z7<+)lO9zCPFYE- z)EEU>&A4j;$>a?&%7B6jQRuM`9h_nV-oaxgo8TjcVu1z&aA|Vl3hl941s^t)Cp>~< z7J(RW85lxX#)52kuD44*^cD0#v*aSZjxyp=C(iW@JX+kno3~1D$ug37<;j0ACf=$%4hx^cri4QsA2Co5c8Bq{u zi>k;!G&hzOoU4@6Yau@D7Ka`9Fx$cD7vTfAG&@lM>H`kKOYEqu4Ryr<9ylN#_=xqU z9()M$h!2t!_z;4l9Im6K9Eq-CFm%>&FOc~ie1L#PkOk!k3z|@n-KqzXgs?_~bVYoCUxkqERweSxX>-}Z zV-}}~AYzz+xU}FHLLdP>7udHr?GCF0C%f2fZUD$fFobj=w4C^GOU2MJtrif$0^#RG zZmXPO!_W8NL%0}06s$M`54^j#j0Uts!2ad=&|2fas zk~oeJo5uqw;PePOfB*~dj#@fAc(dRGRQI4O;lObVlA&T~o!|p0fscS494Oo>odGDh z03TKZDr+^eHa6k|1>uNO5DEXFzAnUvH%0Jawz%vbCpwVT1=VCi1L7a@memUuMt$U6 z4yzlLbs`j>)9!QH9N;o=G3o@dYeV0(8NI@;5LCiHXq3tB0y6DvA{#G2>MhB@cKDzZ zpk8*n*Xu=}@HoNF$YX^h5t#veAnY^VVzYUX*y;0Hk<4gxp-53?U_PVKn!*Z;U=(aR zofq_Z8^jNUvaqSmCSB4Dd^l|;x$6*h9_L*2CZ&9-cANuiwz%zHCsdc!4IO+|{0Cvf-zKDY}>0(`iDUj)F$TaW;Baryl?LKt$xjXo&&KuUC)R0og_Jxl_k zuuJgaw3;B7PzI!r*$l+HP%(?s>a;?gUx*KXy5IvxA~<|5;KSw-e274ceM~rM+hg+s z;i!*W@L~730W(lm-ZwS z02FxK;6}UG?QwWqPKVnCe7K-Ly=afq?sOm<@MTIu&72TbNQw4BIeL-XiNkVZ7$yeD z*ZeKTKscc1Ih{#KN$3+v9+1x~oze}NWp(=jLQln#Qi`ZfIgArMUg%*hsy&gW%DFC?G~RCZ$Sbi_a-OXk<4uN0gDFWLpn`n z4?ciQ!3VjIzyTs6RB=pB`+UF$5HI+U&`S=OHzM%y0jDXI+*|NrwfS5DFH~0yA0TM_ zgJOL?M=}cVx`123hoAUxIX&)VoRbWlF8Bba;0Sf}C#NYHHFH65yIeqo!)12)go8ca zSbe@99}r2%l#Hg@eF5SFcidjlDc%4y6W-(lK9eC@ys61{Btyj@#SD<;z$Ng}8z(kP z`QRI`7c6oSKJYGw8Pq||L_}GEc&`frMeqTNp6|&@rDP#GKTIFLJJ|<(IQ(M5q5<&_ zdCQT40#F~H*KBq>K|hzz<92y*7>vsUo$iM$krSkmjrfr63kBzP`GF4@3x45XuTQ!S zKI90gw>wpxLBpBo*>1Lf|vNKcXv>%*Fk#rs(X0ywb3QD;# z3URxW+(47XorK(OpFdWg7(T=t{0=_csi~=u5h;EYiL4F}x(M)*;&R&XGYQR21wQ=g zsSYGV#ehWvR60_^O3CiQ2apMrm}6}eNPIXge&Sw4lnsdY3qH{C!QqxTJ|NYVO3TI3 za2A^*;7Lt_Dt871A0TM_W3hm@oM}L~-vitNAFgD7k~_)kar?Y!Ubh!gC;(XkPH|g3 z9^k_)Sn|M}^bjA2M;Q((^pTN3u7K_(+za2pSOokhfgvC;;?HO0rnIf)7s;LOc6?={}DS zhG{a|gExDuUew2JP6Io55$fOL4xsfgo|2Ip_>gXck4pgYAs75Wd4Nt{PkMSfWJFpL z*f|+@d`WH>_$A%rvf*bknwt*Ml9ZX@L^6vd87MSBx5e<0hq_Rg3PXcMF2IM|?1d=9 z;RzrVq%rUT#3vyfD(?DFLD63FAwDwlJqlvfk>X7cz_f9t$S@#*4Y3!&TdoXr>3|oS z4yxOok`(X+{2-Js!|(OOo=Abv2d8*#qRTv%bjb~Y?!|Fa9>GV7&*%3h1(ITKMMCO4 zOYEmW$q#|+&B(}rj7UcaxRey!0SQE>WWaX9&lE_74B#WsE7OH!s2HdKV;EK~ez@{| zkWivag`t5G2=~Otjh6deR zx*

  ---------------------------------
+
+  geom.h 
+    header file for geometric routines
+
+   see qh-geom.htm and geom.c
+
+   copyright (c) 1993-2002 The Geometry Center        
+*/
+
+#ifndef qhDEFgeom
+#define qhDEFgeom 1
+
+/* ============ -macros- ======================== */
+
+/*----------------------------------
+   
+  fabs_(a)
+    returns the absolute value of a
+*/
+#define fabs_( a ) ((( a ) < 0 ) ? -( a ):( a ))
+               
+/*----------------------------------
+  
+  fmax_(a,b)
+    returns the maximum value of a and b
+*/
+#define fmax_( a,b )  ( ( a ) < ( b ) ? ( b ) : ( a ) )
+
+/*----------------------------------
+
+  fmin_(a,b)
+    returns the minimum value of a and b
+*/
+#define fmin_( a,b )  ( ( a ) > ( b ) ? ( b ) : ( a ) )
+
+/*----------------------------------
+
+  maximize_(maxval, val)
+    set maxval to val if val is greater than maxval
+*/
+#define maximize_( maxval, val ) {if (( maxval ) < ( val )) ( maxval )= ( val );}
+
+/*----------------------------------
+
+  minimize_(minval, val)
+    set minval to val if val is less than minval
+*/
+#define minimize_( minval, val ) {if (( minval ) > ( val )) ( minval )= ( val );}
+
+/*----------------------------------
+
+  det2_(a1, a2,     
+        b1, b2)
+  
+    compute a 2-d determinate
+*/
+#define det2_( a1,a2,b1,b2 ) (( a1 )*( b2 ) - ( a2 )*( b1 ))
+
+/*----------------------------------
+  
+  det3_(a1, a2, a3,    
+       b1, b2, b3,
+       c1, c2, c3)
+  
+    compute a 3-d determinate
+*/
+#define det3_( a1,a2,a3,b1,b2,b3,c1,c2,c3 ) ( ( a1 )*det2_( b2,b3,c2,c3 ) \
+                - ( b1 )*det2_( a2,a3,c2,c3 ) + ( c1 )*det2_( a2,a3,b2,b3 ) )
+
+/*----------------------------------
+  
+  dX( p1, p2 )
+  dY( p1, p2 )
+  dZ( p1, p2 )
+  
+    given two indices into rows[],
+
+    compute the difference between X, Y, or Z coordinates
+*/
+#define dX( p1,p2 )  ( *( rows[p1] ) - *( rows[p2] ))
+#define dY( p1,p2 )  ( *( rows[p1]+1 ) - *( rows[p2]+1 ))
+#define dZ( p1,p2 )  ( *( rows[p1]+2 ) - *( rows[p2]+2 ))
+#define dW( p1,p2 )  ( *( rows[p1]+3 ) - *( rows[p2]+3 ))
+
+/*============= prototypes in alphabetical order, infrequent at end ======= */
+
+void    qh_backnormal (realT **rows, int numrow, int numcol, boolT sign, coordT *normal, boolT *nearzero);
+void	qh_distplane (pointT *point, facetT *facet, realT *dist);
+facetT *qh_findbest (pointT *point, facetT *startfacet,
+		     boolT bestoutside, boolT isnewfacets, boolT noupper,
+		     realT *dist, boolT *isoutside, int *numpart);
+facetT *qh_findbesthorizon (boolT ischeckmax, pointT *point, 
+	             facetT *startfacet, boolT noupper, realT *bestdist, int *numpart);
+facetT *qh_findbestnew (pointT *point, facetT *startfacet, realT *dist, 
+		     boolT bestoutside, boolT *isoutside, int *numpart);
+void 	qh_gausselim(realT **rows, int numrow, int numcol, boolT *sign, boolT *nearzero);
+realT   qh_getangle(pointT *vect1, pointT *vect2);
+pointT *qh_getcenter(setT *vertices);
+pointT *qh_getcentrum(facetT *facet);
+realT   qh_getdistance(facetT *facet, facetT *neighbor, realT *mindist, realT *maxdist);
+void    qh_normalize (coordT *normal, int dim, boolT toporient);
+void    qh_normalize2 (coordT *normal, int dim, boolT toporient, 
+            realT *minnorm, boolT *ismin);
+pointT *qh_projectpoint(pointT *point, facetT *facet, realT dist);
+
+void    qh_setfacetplane(facetT *newfacets);
+void 	qh_sethyperplane_det (int dim, coordT **rows, coordT *point0, 
+              boolT toporient, coordT *normal, realT *offset, boolT *nearzero);
+void 	qh_sethyperplane_gauss (int dim, coordT **rows, pointT *point0, 
+	     boolT toporient, coordT *normal, coordT *offset, boolT *nearzero);
+boolT   qh_sharpnewfacets (void);
+
+/*========= infrequently used code in geom2.c =============*/
+
+
+coordT *qh_copypoints (coordT *points, int numpoints, int dimension);
+void    qh_crossproduct (int dim, realT vecA[3], realT vecB[3], realT vecC[3]);
+realT 	qh_determinant (realT **rows, int dim, boolT *nearzero);
+realT   qh_detjoggle (pointT *points, int numpoints, int dimension);
+void    qh_detroundoff (void);
+realT   qh_detsimplex(pointT *apex, setT *points, int dim, boolT *nearzero);
+realT   qh_distnorm (int dim, pointT *point, pointT *normal, realT *offsetp);
+realT   qh_distround (int dimension, realT maxabs, realT maxsumabs);
+realT   qh_divzero(realT numer, realT denom, realT mindenom1, boolT *zerodiv);
+realT   qh_facetarea (facetT *facet);
+realT   qh_facetarea_simplex (int dim, coordT *apex, setT *vertices, 
+          vertexT *notvertex,  boolT toporient, coordT *normal, realT *offset);
+pointT *qh_facetcenter (setT *vertices);
+facetT *qh_findgooddist (pointT *point, facetT *facetA, realT *distp, facetT **facetlist);
+void    qh_getarea (facetT *facetlist);
+boolT   qh_gram_schmidt(int dim, realT **rows);
+boolT   qh_inthresholds (coordT *normal, realT *angle);
+void    qh_joggleinput (void);
+realT  *qh_maxabsval (realT *normal, int dim);
+setT   *qh_maxmin(pointT *points, int numpoints, int dimension);
+realT   qh_maxouter (void);
+void    qh_maxsimplex (int dim, setT *maxpoints, pointT *points, int numpoints, setT **simplex);
+realT   qh_minabsval (realT *normal, int dim);
+int     qh_mindiff (realT *vecA, realT *vecB, int dim);
+boolT   qh_orientoutside (facetT *facet);
+void    qh_outerinner (facetT *facet, realT *outerplane, realT *innerplane);
+coordT  qh_pointdist(pointT *point1, pointT *point2, int dim);
+void    qh_printmatrix (FILE *fp, char *string, realT **rows, int numrow, int numcol);
+void    qh_printpoints (FILE *fp, char *string, setT *points);
+void    qh_projectinput (void);
+void 	qh_projectpoints (signed char *project, int n, realT *points, 
+             int numpoints, int dim, realT *newpoints, int newdim);
+int     qh_rand( void);
+void    qh_srand( int seed);
+realT   qh_randomfactor (void);
+void    qh_randommatrix (realT *buffer, int dim, realT **row);
+void    qh_rotateinput (realT **rows);
+void    qh_rotatepoints (realT *points, int numpoints, int dim, realT **rows);
+void    qh_scaleinput (void);
+void    qh_scalelast (coordT *points, int numpoints, int dim, coordT low,
+		   coordT high, coordT newhigh);
+void 	qh_scalepoints (pointT *points, int numpoints, int dim,
+  		realT *newlows, realT *newhighs);
+boolT   qh_sethalfspace (int dim, coordT *coords, coordT **nextp, 
+              coordT *normal, coordT *offset, coordT *feasible);
+coordT *qh_sethalfspace_all (int dim, int count, coordT *halfspaces, pointT *feasible);
+pointT *qh_voronoi_center (int dim, setT *points);
+
+#endif /* qhDEFgeom */
+
+
+
diff --git a/extern/qhull/include/qhull/io.h b/extern/qhull/include/qhull/io.h
new file mode 100644
index 00000000000..351d56b3708
--- /dev/null
+++ b/extern/qhull/include/qhull/io.h
@@ -0,0 +1,149 @@
+/*
  ---------------------------------
+
+   io.h 
+   declarations of Input/Output functions
+
+   see README, qhull.h and io.c
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFio
+#define qhDEFio 1
+
+/*============ constants and flags ==================*/
+
+/*----------------------------------
+  
+  qh_MAXfirst
+    maximum length of first two lines of stdin
+*/
+#define qh_MAXfirst  200
+
+/*----------------------------------
+  
+  qh_MINradius
+    min radius for Gp and Gv, fraction of maxcoord
+*/
+#define qh_MINradius 0.02
+
+/*----------------------------------
+  
+  qh_GEOMepsilon
+    adjust outer planes for 'lines closer' and geomview roundoff.  
+    This prevents bleed through.
+*/
+#define qh_GEOMepsilon 2e-3
+
+/*----------------------------------
+  
+  qh_WHITESPACE
+    possible values of white space
+*/
+#define qh_WHITESPACE " \n\t\v\r\f"
+
+
+/*----------------------------------
+  
+  qh_RIDGE
+    to select which ridges to print in qh_eachvoronoi
+*/
+typedef enum
+{
+    qh_RIDGEall = 0, qh_RIDGEinner, qh_RIDGEouter
+}
+qh_RIDGE;
+
+/*----------------------------------
+  
+  printvridgeT
+    prints results of qh_printvdiagram
+
+  see:
+    qh_printvridge for an example
+*/
+typedef void (*printvridgeT)(FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
+
+/*============== -prototypes in alphabetical order =========*/
+
+void    dfacet( unsigned id);
+void    dvertex( unsigned id);
+void    qh_countfacets (facetT *facetlist, setT *facets, boolT printall, 
+              int *numfacetsp, int *numsimplicialp, int *totneighborsp, 
+              int *numridgesp, int *numcoplanarsp, int *numnumtricoplanarsp);
+pointT *qh_detvnorm (vertexT *vertex, vertexT *vertexA, setT *centers, realT *offsetp);
+setT   *qh_detvridge (vertexT *vertex);
+setT   *qh_detvridge3 (vertexT *atvertex, vertexT *vertex);
+int     qh_eachvoronoi (FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder);
+int     qh_eachvoronoi_all (FILE *fp, printvridgeT printvridge, boolT isupper, qh_RIDGE innerouter, boolT inorder);
+void	qh_facet2point(facetT *facet, pointT **point0, pointT **point1, realT *mindist);
+setT   *qh_facetvertices (facetT *facetlist, setT *facets, boolT allfacets);
+void    qh_geomplanes (facetT *facet, realT *outerplane, realT *innerplane);
+void    qh_markkeep (facetT *facetlist);
+setT   *qh_markvoronoi (facetT *facetlist, setT *facets, boolT printall, boolT *islowerp, int *numcentersp);
+void    qh_order_vertexneighbors(vertexT *vertex);
+void	qh_printafacet(FILE *fp, int format, facetT *facet, boolT printall);
+void    qh_printbegin (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall);
+void 	qh_printcenter (FILE *fp, int format, char *string, facetT *facet);
+void    qh_printcentrum (FILE *fp, facetT *facet, realT radius);
+void    qh_printend (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall);
+void    qh_printend4geom (FILE *fp, facetT *facet, int *num, boolT printall);
+void    qh_printextremes (FILE *fp, facetT *facetlist, setT *facets, int printall);
+void    qh_printextremes_2d (FILE *fp, facetT *facetlist, setT *facets, int printall);
+void    qh_printextremes_d (FILE *fp, facetT *facetlist, setT *facets, int printall);
+void	qh_printfacet(FILE *fp, facetT *facet);
+void	qh_printfacet2math(FILE *fp, facetT *facet, int notfirst);
+void	qh_printfacet2geom(FILE *fp, facetT *facet, realT color[3]);
+void    qh_printfacet2geom_points(FILE *fp, pointT *point1, pointT *point2,
+			       facetT *facet, realT offset, realT color[3]);
+void	qh_printfacet3math (FILE *fp, facetT *facet, int notfirst);
+void	qh_printfacet3geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]);
+void	qh_printfacet3geom_points(FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]);
+void	qh_printfacet3geom_simplicial(FILE *fp, facetT *facet, realT color[3]);
+void	qh_printfacet3vertex(FILE *fp, facetT *facet, int format);
+void	qh_printfacet4geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]);
+void	qh_printfacet4geom_simplicial(FILE *fp, facetT *facet, realT color[3]);
+void	qh_printfacetNvertex_nonsimplicial(FILE *fp, facetT *facet, int id, int format);
+void	qh_printfacetNvertex_simplicial(FILE *fp, facetT *facet, int format);
+void    qh_printfacetheader(FILE *fp, facetT *facet);
+void    qh_printfacetridges(FILE *fp, facetT *facet);
+void	qh_printfacets(FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall);
+void	qh_printhelp_degenerate(FILE *fp);
+void	qh_printhelp_singular(FILE *fp);
+void	qh_printhyperplaneintersection(FILE *fp, facetT *facet1, facetT *facet2,
+  		   setT *vertices, realT color[3]);
+void	qh_printneighborhood (FILE *fp, int format, facetT *facetA, facetT *facetB, boolT printall);
+void    qh_printline3geom (FILE *fp, pointT *pointA, pointT *pointB, realT color[3]);
+void	qh_printpoint(FILE *fp, char *string, pointT *point);
+void	qh_printpointid(FILE *fp, char *string, int dim, pointT *point, int id);
+void    qh_printpoint3 (FILE *fp, pointT *point);
+void    qh_printpoints_out (FILE *fp, facetT *facetlist, setT *facets, int printall);
+void    qh_printpointvect (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]);
+void    qh_printpointvect2 (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius);
+void	qh_printridge(FILE *fp, ridgeT *ridge);
+void    qh_printspheres(FILE *fp, setT *vertices, realT radius);
+void    qh_printvdiagram (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall);
+int     qh_printvdiagram2 (FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder);
+void	qh_printvertex(FILE *fp, vertexT *vertex);
+void	qh_printvertexlist (FILE *fp, char* string, facetT *facetlist,
+                         setT *facets, boolT printall);
+void	qh_printvertices (FILE *fp, char* string, setT *vertices);
+void    qh_printvneighbors (FILE *fp, facetT* facetlist, setT *facets, boolT printall);
+void    qh_printvoronoi (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall);
+void    qh_printvnorm (FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
+void    qh_printvridge (FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
+void	qh_produce_output(void);
+void    qh_projectdim3 (pointT *source, pointT *destination);
+int     qh_readfeasible (int dim, char *remainder);
+coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc);
+void    qh_setfeasible (int dim);
+boolT	qh_skipfacet(facetT *facet);
+
+#endif /* qhDEFio */
diff --git a/extern/qhull/include/qhull/mem.h b/extern/qhull/include/qhull/mem.h
new file mode 100644
index 00000000000..e9ebd1bb9bc
--- /dev/null
+++ b/extern/qhull/include/qhull/mem.h
@@ -0,0 +1,174 @@
+/*
  ---------------------------------
+
+   mem.h 
+     prototypes for memory management functions
+
+   see qh-mem.htm, mem.c and qset.h
+
+   for error handling, writes message and calls
+     qh_errexit (qhmem_ERRmem, NULL, NULL) if insufficient memory
+       and
+     qh_errexit (qhmem_ERRqhull, NULL, NULL) otherwise
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFmem
+#define qhDEFmem
+
+/*---------------------------------
+  
+  qh_NOmem
+    turn off quick-fit memory allocation
+
+  notes:
+    mem.c implements Quickfit memory allocation for about 20% time
+    savings.  If it fails on your machine, try to locate the
+    problem, and send the answer to qhull@geom.umn.edu.  If this can
+    not be done, define qh_NOmem to use malloc/free instead.
+
+   #define qh_NOmem
+*/
+
+/*-------------------------------------------
+    to avoid bus errors, memory allocation must consider alignment requirements.
+    malloc() automatically takes care of alignment.   Since mem.c manages
+    its own memory, we need to explicitly specify alignment in
+    qh_meminitbuffers().
+
+    A safe choice is sizeof(double).  sizeof(float) may be used if doubles 
+    do not occur in data structures and pointers are the same size.  Be careful
+    of machines (e.g., DEC Alpha) with large pointers.  If gcc is available, 
+    use __alignof__(double) or fmax_(__alignof__(float), __alignof__(void *)).
+
+   see qh_MEMalign in user.h for qhull's alignment
+*/
+
+#define qhmem_ERRmem 4    /* matches qh_ERRmem in qhull.h */
+#define qhmem_ERRqhull 5  /* matches qh_ERRqhull in qhull.h */
+
+/*----------------------------------
+  
+  ptr_intT
+    for casting a void* to an integer-type
+  
+  notes:
+    On 64-bit machines, a pointer may be larger than an 'int'.  
+    qh_meminit() checks that 'long' holds a 'void*'
+*/
+typedef unsigned long ptr_intT;
+
+/*----------------------------------
+ 
+  qhmemT
+    global memory structure for mem.c
+ 
+ notes:
+   users should ignore qhmem except for writing extensions
+   qhmem is allocated in mem.c 
+   
+   qhmem could be swapable like qh and qhstat, but then
+   multiple qh's and qhmem's would need to keep in synch.  
+   A swapable qhmem would also waste memory buffers.  As long
+   as memory operations are atomic, there is no problem with
+   multiple qh structures being active at the same time.
+   If you need separate address spaces, you can swap the
+   contents of qhmem.
+*/
+typedef struct qhmemT qhmemT;
+extern qhmemT qhmem; 
+
+struct qhmemT {               /* global memory management variables */
+  int      BUFsize;	      /* size of memory allocation buffer */
+  int      BUFinit;	      /* initial size of memory allocation buffer */
+  int      TABLEsize;         /* actual number of sizes in free list table */
+  int      NUMsizes;          /* maximum number of sizes in free list table */
+  int      LASTsize;          /* last size in free list table */
+  int      ALIGNmask;         /* worst-case alignment, must be 2^n-1 */
+  void	 **freelists;          /* free list table, linked by offset 0 */
+  int     *sizetable;         /* size of each freelist */
+  int     *indextable;        /* size->index table */
+  void    *curbuffer;         /* current buffer, linked by offset 0 */
+  void    *freemem;           /*   free memory in curbuffer */
+  int 	   freesize;          /*   size of free memory in bytes */
+  void 	  *tempstack;         /* stack of temporary memory, managed by users */
+  FILE    *ferr;              /* file for reporting errors */
+  int      IStracing;         /* =5 if tracing memory allocations */
+  int      cntquick;          /* count of quick allocations */
+                              /* remove statistics doesn't effect speed */
+  int      cntshort;          /* count of short allocations */
+  int      cntlong;           /* count of long allocations */
+  int      curlong;           /* current count of inuse, long allocations */
+  int      freeshort;	      /* count of short memfrees */
+  int      freelong;	      /* count of long memfrees */
+  int      totshort;          /* total size of short allocations */
+  int      totlong;           /* total size of long allocations */
+  int      maxlong;           /* maximum totlong */
+  int      cntlarger;         /* count of setlarger's */
+  int      totlarger;         /* total copied by setlarger */
+};
+
+
+/*==================== -macros ====================*/
+
+/*----------------------------------
+   
+  qh_memalloc_(size, object, type)  
+    returns object of size bytes 
+	assumes size<=qhmem.LASTsize and void **freelistp is a temp
+*/
+
+#ifdef qh_NOmem
+#define qh_memalloc_(size, freelistp, object, type) {\
+  object= (type*)qh_memalloc (size); }
+#else /* !qh_NOmem */
+
+#define qh_memalloc_(size, freelistp, object, type) {\
+  freelistp= qhmem.freelists + qhmem.indextable[size];\
+  if ((object= (type*)*freelistp)) {\
+    qhmem.cntquick++;  \
+    *freelistp= *((void **)*freelistp);\
+  }else object= (type*)qh_memalloc (size);}
+#endif
+
+/*----------------------------------
+   
+  qh_memfree_(object, size) 
+    free up an object
+
+  notes:
+    object may be NULL
+    assumes size<=qhmem.LASTsize and void **freelistp is a temp
+*/
+#ifdef qh_NOmem
+#define qh_memfree_(object, size, freelistp) {\
+  qh_memfree (object, size); }
+#else /* !qh_NOmem */
+
+#define qh_memfree_(object, size, freelistp) {\
+  if (object) { \
+    qhmem .freeshort++;\
+    freelistp= qhmem.freelists + qhmem.indextable[size];\
+    *((void **)object)= *freelistp;\
+    *freelistp= object;}}
+#endif
+
+/*=============== prototypes in alphabetical order ============*/
+
+void *qh_memalloc(int insize);
+void qh_memfree (void *object, int size);
+void qh_memfreeshort (int *curlong, int *totlong);
+void qh_meminit (FILE *ferr);
+void qh_meminitbuffers (int tracelevel, int alignment, int numsizes,
+			int bufsize, int bufinit);
+void qh_memsetup (void);
+void qh_memsize(int size);
+void qh_memstatistics (FILE *fp);
+
+#endif /* qhDEFmem */
diff --git a/extern/qhull/include/qhull/merge.h b/extern/qhull/include/qhull/merge.h
new file mode 100644
index 00000000000..7fc2afa5967
--- /dev/null
+++ b/extern/qhull/include/qhull/merge.h
@@ -0,0 +1,171 @@
+/*
  ---------------------------------
+
+   merge.h 
+   header file for merge.c
+
+   see qh-merge.htm and merge.c
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFmerge
+#define qhDEFmerge 1
+
+
+/*============ -constants- ==============*/
+
+/*----------------------------------
+
+  qh_ANGLEredundant
+    indicates redundant merge in mergeT->angle
+*/
+#define qh_ANGLEredundant 6.0
+
+/*----------------------------------
+  
+  qh_ANGLEdegen
+    indicates degenerate facet in mergeT->angle
+*/
+#define qh_ANGLEdegen     5.0
+
+/*----------------------------------
+  
+  qh_ANGLEconcave
+    offset to indicate concave facets in mergeT->angle
+  
+  notes:
+    concave facets are assigned the range of [2,4] in mergeT->angle
+    roundoff error may make the angle less than 2
+*/
+#define qh_ANGLEconcave  1.5
+
+/*----------------------------------
+  
+  MRG... (mergeType)
+    indicates the type of a merge (mergeT->type)
+*/
+typedef enum {	/* in sort order for facet_mergeset */
+  MRGnone= 0,
+  MRGcoplanar,		/* centrum coplanar */
+  MRGanglecoplanar,	/* angle coplanar */
+  			/* could detect half concave ridges */
+  MRGconcave,		/* concave ridge */
+  MRGflip,		/* flipped facet. facet1 == facet2 */
+  MRGridge,		/* duplicate ridge (qh_MERGEridge) */
+                        /* degen and redundant go onto degen_mergeset */
+  MRGdegen,		/* degenerate facet (not enough neighbors) facet1 == facet2 */
+  MRGredundant,		/* redundant facet (vertex subset) */
+  			/* merge_degenredundant assumes degen < redundant */
+  MRGmirror,	        /* mirror facet from qh_triangulate */
+  ENDmrg
+} mergeType;
+
+/*----------------------------------
+  
+  qh_MERGEapex
+    flag for qh_mergefacet() to indicate an apex merge  
+*/
+#define qh_MERGEapex     True
+
+/*============ -structures- ====================*/
+
+/*----------------------------------
+     
+  mergeT
+    structure used to merge facets
+*/
+
+typedef struct mergeT mergeT;
+struct mergeT {		/* initialize in qh_appendmergeset */
+  realT   angle;        /* angle between normals of facet1 and facet2 */
+  facetT *facet1; 	/* will merge facet1 into facet2 */
+  facetT *facet2;
+  mergeType type;
+};
+
+
+/*=========== -macros- =========================*/
+
+/*----------------------------------
+     
+  FOREACHmerge_( merges ) {...}
+    assign 'merge' to each merge in merges
+       
+  notes:
+    uses 'mergeT *merge, **mergep;'
+    if qh_mergefacet(),
+      restart since qh.facet_mergeset may change
+    see FOREACHsetelement_
+*/
+#define FOREACHmerge_( merges ) FOREACHsetelement_(mergeT, merges, merge)
+
+/*============ prototypes in alphabetical order after pre/postmerge =======*/
+
+void    qh_premerge (vertexT *apex, realT maxcentrum, realT maxangle);
+void    qh_postmerge (char *reason, realT maxcentrum, realT maxangle, 
+             boolT vneighbors);
+void    qh_all_merges (boolT othermerge, boolT vneighbors);
+void    qh_appendmergeset(facetT *facet, facetT *neighbor, mergeType mergetype, realT *angle);
+setT   *qh_basevertices( facetT *samecycle);
+void    qh_checkconnect (void /* qh new_facets */);
+boolT   qh_checkzero (boolT testall);
+void    qh_copynonconvex (ridgeT *atridge);
+void    qh_degen_redundant_facet (facetT *facet);
+void   	qh_degen_redundant_neighbors (facetT *facet, facetT *delfacet);
+vertexT *qh_find_newvertex (vertexT *oldvertex, setT *vertices, setT *ridges);
+void    qh_findbest_test (boolT testcentrum, facetT *facet, facetT *neighbor,
+           facetT **bestfacet, realT *distp, realT *mindistp, realT *maxdistp);
+facetT *qh_findbestneighbor(facetT *facet, realT *distp, realT *mindistp, realT *maxdistp);
+void 	qh_flippedmerges(facetT *facetlist, boolT *wasmerge);
+void 	qh_forcedmerges( boolT *wasmerge);
+void	qh_getmergeset(facetT *facetlist);
+void 	qh_getmergeset_initial (facetT *facetlist);
+void    qh_hashridge (setT *hashtable, int hashsize, ridgeT *ridge, vertexT *oldvertex);
+ridgeT *qh_hashridge_find (setT *hashtable, int hashsize, ridgeT *ridge, 
+              vertexT *vertex, vertexT *oldvertex, int *hashslot);
+void 	qh_makeridges(facetT *facet);
+void    qh_mark_dupridges(facetT *facetlist);
+void    qh_maydropneighbor (facetT *facet);
+int     qh_merge_degenredundant (void);
+void    qh_merge_nonconvex( facetT *facet1, facetT *facet2, mergeType mergetype);
+void    qh_mergecycle (facetT *samecycle, facetT *newfacet);
+void    qh_mergecycle_all (facetT *facetlist, boolT *wasmerge);
+void    qh_mergecycle_facets( facetT *samecycle, facetT *newfacet);
+void    qh_mergecycle_neighbors(facetT *samecycle, facetT *newfacet);
+void    qh_mergecycle_ridges(facetT *samecycle, facetT *newfacet);
+void    qh_mergecycle_vneighbors( facetT *samecycle, facetT *newfacet);
+void 	qh_mergefacet(facetT *facet1, facetT *facet2, realT *mindist, realT *maxdist, boolT mergeapex);
+void    qh_mergefacet2d (facetT *facet1, facetT *facet2);
+void 	qh_mergeneighbors(facetT *facet1, facetT *facet2);
+void 	qh_mergeridges(facetT *facet1, facetT *facet2);
+void    qh_mergesimplex(facetT *facet1, facetT *facet2, boolT mergeapex);
+void    qh_mergevertex_del (vertexT *vertex, facetT *facet1, facetT *facet2);
+void    qh_mergevertex_neighbors(facetT *facet1, facetT *facet2);
+void	qh_mergevertices(setT *vertices1, setT **vertices);
+setT   *qh_neighbor_intersections (vertexT *vertex);
+void    qh_newvertices (setT *vertices);
+boolT   qh_reducevertices (void);
+vertexT *qh_redundant_vertex (vertexT *vertex);
+boolT   qh_remove_extravertices (facetT *facet);
+vertexT *qh_rename_sharedvertex (vertexT *vertex, facetT *facet);
+void	qh_renameridgevertex(ridgeT *ridge, vertexT *oldvertex, vertexT *newvertex);
+void    qh_renamevertex(vertexT *oldvertex, vertexT *newvertex, setT *ridges,
+			facetT *oldfacet, facetT *neighborA);
+boolT 	qh_test_appendmerge (facetT *facet, facetT *neighbor);
+boolT   qh_test_vneighbors (void /* qh newfacet_list */);
+void    qh_tracemerge (facetT *facet1, facetT *facet2);
+void    qh_tracemerging (void);
+void    qh_updatetested( facetT *facet1, facetT *facet2);
+setT   *qh_vertexridges (vertexT *vertex);
+void    qh_vertexridges_facet (vertexT *vertex, facetT *facet, setT **ridges);
+void    qh_willdelete (facetT *facet, facetT *replace);
+
+#endif /* qhDEFmerge */
diff --git a/extern/qhull/include/qhull/poly.h b/extern/qhull/include/qhull/poly.h
new file mode 100644
index 00000000000..294ec9527fc
--- /dev/null
+++ b/extern/qhull/include/qhull/poly.h
@@ -0,0 +1,290 @@
+/*
  ---------------------------------
+
+   poly.h 
+   header file for poly.c and poly2.c
+
+   see qh-poly.htm, qhull.h and poly.c
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFpoly
+#define qhDEFpoly 1
+
+/*===============   constants ========================== */
+
+/*----------------------------------
+  
+  ALGORITHMfault   
+    use as argument to checkconvex() to report errors during buildhull
+*/
+#define qh_ALGORITHMfault 0
+
+/*----------------------------------
+  
+  DATAfault        
+    use as argument to checkconvex() to report errors during initialhull
+*/
+#define qh_DATAfault 1
+
+/*----------------------------------
+  
+  DUPLICATEridge
+    special value for facet->neighbor to indicate a duplicate ridge
+  
+  notes:
+    set by matchneighbor, used by matchmatch and mark_dupridge
+*/
+#define qh_DUPLICATEridge ( facetT * ) 1L
+
+/*----------------------------------
+  
+  MERGEridge       flag in facet
+    special value for facet->neighbor to indicate a merged ridge
+  
+  notes:
+    set by matchneighbor, used by matchmatch and mark_dupridge
+*/
+#define qh_MERGEridge ( facetT * ) 2L
+
+
+/*============ -structures- ====================*/
+
+/*=========== -macros- =========================*/
+
+/*----------------------------------
+  
+  FORALLfacet_( facetlist ) { ... }
+    assign 'facet' to each facet in facetlist
+    
+  notes:
+    uses 'facetT *facet;'
+    assumes last facet is a sentinel
+    
+  see:
+    FORALLfacets
+*/
+#define FORALLfacet_( facetlist ) if ( facetlist ) for( facet=( facetlist );facet && facet->next;facet=facet->next )
+
+/*----------------------------------
+  
+  FORALLnew_facets { ... } 
+    assign 'newfacet' to each facet in qh.newfacet_list
+    
+  notes:
+    uses 'facetT *newfacet;'
+    at exit, newfacet==NULL
+*/
+#define FORALLnew_facets for( newfacet=qh newfacet_list;newfacet && newfacet->next;newfacet=newfacet->next )
+
+/*----------------------------------
+  
+  FORALLvertex_( vertexlist ) { ... }
+    assign 'vertex' to each vertex in vertexlist
+    
+  notes:
+    uses 'vertexT *vertex;'
+    at exit, vertex==NULL
+*/
+#define FORALLvertex_( vertexlist ) for ( vertex=( vertexlist );vertex && vertex->next;vertex= vertex->next )
+
+/*----------------------------------
+  
+  FORALLvisible_facets { ... }
+    assign 'visible' to each visible facet in qh.visible_list
+    
+  notes:
+    uses 'vacetT *visible;'
+    at exit, visible==NULL
+*/
+#define FORALLvisible_facets for (visible=qh visible_list; visible && visible->visible; visible= visible->next)
+
+/*----------------------------------
+  
+  FORALLsame_( newfacet ) { ... } 
+    assign 'same' to each facet in newfacet->f.samecycle
+    
+  notes:
+    uses 'facetT *same;'
+    stops when it returns to newfacet
+*/
+#define FORALLsame_(newfacet) for (same= newfacet->f.samecycle; same != newfacet; same= same->f.samecycle)
+
+/*----------------------------------
+  
+  FORALLsame_cycle_( newfacet ) { ... } 
+    assign 'same' to each facet in newfacet->f.samecycle
+    
+  notes:
+    uses 'facetT *same;'
+    at exit, same == NULL
+*/
+#define FORALLsame_cycle_(newfacet) \
+     for (same= newfacet->f.samecycle; \
+         same; same= (same == newfacet ?  NULL : same->f.samecycle))
+
+/*----------------------------------
+  
+  FOREACHneighborA_( facet ) { ... }
+    assign 'neighborA' to each neighbor in facet->neighbors
+  
+  FOREACHneighborA_( vertex ) { ... }
+    assign 'neighborA' to each neighbor in vertex->neighbors
+  
+  declare:
+    facetT *neighborA, **neighborAp;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHneighborA_(facet)  FOREACHsetelement_(facetT, facet->neighbors, neighborA)
+
+/*----------------------------------
+  
+  FOREACHvisible_( facets ) { ... } 
+    assign 'visible' to each facet in facets
+    
+  notes:
+    uses 'facetT *facet, *facetp;'
+    see FOREACHsetelement_
+*/
+#define FOREACHvisible_(facets) FOREACHsetelement_(facetT, facets, visible)
+
+/*----------------------------------
+  
+  FOREACHnewfacet_( facets ) { ... } 
+    assign 'newfacet' to each facet in facets
+    
+  notes:
+    uses 'facetT *newfacet, *newfacetp;'
+    see FOREACHsetelement_
+*/
+#define FOREACHnewfacet_(facets) FOREACHsetelement_(facetT, facets, newfacet)
+
+/*----------------------------------
+  
+  FOREACHvertexA_( vertices ) { ... } 
+    assign 'vertexA' to each vertex in vertices
+    
+  notes:
+    uses 'vertexT *vertexA, *vertexAp;'
+    see FOREACHsetelement_
+*/
+#define FOREACHvertexA_(vertices) FOREACHsetelement_(vertexT, vertices, vertexA)
+
+/*----------------------------------
+  
+  FOREACHvertexreverse12_( vertices ) { ... } 
+    assign 'vertex' to each vertex in vertices
+    reverse order of first two vertices
+    
+  notes:
+    uses 'vertexT *vertex, *vertexp;'
+    see FOREACHsetelement_
+*/
+#define FOREACHvertexreverse12_(vertices) FOREACHsetelementreverse12_(vertexT, vertices, vertex)
+
+
+/*=============== prototypes poly.c in alphabetical order ================*/
+
+void    qh_appendfacet(facetT *facet);
+void    qh_appendvertex(vertexT *vertex);
+void 	qh_attachnewfacets (void);
+boolT   qh_checkflipped (facetT *facet, realT *dist, boolT allerror);
+void	qh_delfacet(facetT *facet);
+void 	qh_deletevisible(void /*qh visible_list, qh horizon_list*/);
+setT   *qh_facetintersect (facetT *facetA, facetT *facetB, int *skipAp,int *skipBp, int extra);
+unsigned qh_gethash (int hashsize, setT *set, int size, int firstindex, void *skipelem);
+facetT *qh_makenewfacet(setT *vertices, boolT toporient, facetT *facet);
+void    qh_makenewplanes ( void /* newfacet_list */);
+facetT *qh_makenew_nonsimplicial (facetT *visible, vertexT *apex, int *numnew);
+facetT *qh_makenew_simplicial (facetT *visible, vertexT *apex, int *numnew);
+void    qh_matchneighbor (facetT *newfacet, int newskip, int hashsize,
+			  int *hashcount);
+void	qh_matchnewfacets (void);
+boolT   qh_matchvertices (int firstindex, setT *verticesA, int skipA, 
+			  setT *verticesB, int *skipB, boolT *same);
+facetT *qh_newfacet(void);
+ridgeT *qh_newridge(void);
+int     qh_pointid (pointT *point);
+void 	qh_removefacet(facetT *facet);
+void 	qh_removevertex(vertexT *vertex);
+void    qh_updatevertices (void);
+
+
+/*========== -prototypes poly2.c in alphabetical order ===========*/
+
+void    qh_addhash (void* newelem, setT *hashtable, int hashsize, unsigned hash);
+void 	qh_check_bestdist (void);
+void    qh_check_maxout (void);
+void    qh_check_output (void);
+void    qh_check_point (pointT *point, facetT *facet, realT *maxoutside, realT *maxdist, facetT **errfacet1, facetT **errfacet2);
+void   	qh_check_points(void);
+void 	qh_checkconvex(facetT *facetlist, int fault);
+void    qh_checkfacet(facetT *facet, boolT newmerge, boolT *waserrorp);
+void 	qh_checkflipped_all (facetT *facetlist);
+void 	qh_checkpolygon(facetT *facetlist);
+void    qh_checkvertex (vertexT *vertex);
+void 	qh_clearcenters (qh_CENTER type);
+void 	qh_createsimplex(setT *vertices);
+void 	qh_delridge(ridgeT *ridge);
+void    qh_delvertex (vertexT *vertex);
+setT   *qh_facet3vertex (facetT *facet);
+facetT *qh_findbestfacet (pointT *point, boolT bestoutside,
+           realT *bestdist, boolT *isoutside);
+facetT *qh_findfacet_all (pointT *point, realT *bestdist, boolT *isoutside,
+			  int *numpart);
+int 	qh_findgood (facetT *facetlist, int goodhorizon);
+void 	qh_findgood_all (facetT *facetlist);
+void    qh_furthestnext (void /* qh facet_list */);
+void    qh_furthestout (facetT *facet);
+void    qh_infiniteloop (facetT *facet);
+void 	qh_initbuild(void);
+void 	qh_initialhull(setT *vertices);
+setT   *qh_initialvertices(int dim, setT *maxpoints, pointT *points, int numpoints);
+vertexT *qh_isvertex (pointT *point, setT *vertices);
+vertexT *qh_makenewfacets (pointT *point /*horizon_list, visible_list*/);
+void    qh_matchduplicates (facetT *atfacet, int atskip, int hashsize, int *hashcount);
+void    qh_nearcoplanar ( void /* qh.facet_list */);
+vertexT *qh_nearvertex (facetT *facet, pointT *point, realT *bestdistp);
+int 	qh_newhashtable(int newsize);
+vertexT *qh_newvertex(pointT *point);
+ridgeT *qh_nextridge3d (ridgeT *atridge, facetT *facet, vertexT **vertexp);
+void    qh_outcoplanar (void /* facet_list */);
+pointT *qh_point (int id);
+void 	qh_point_add (setT *set, pointT *point, void *elem);
+setT   *qh_pointfacet (void /*qh facet_list*/);
+setT   *qh_pointvertex (void /*qh facet_list*/);
+void 	qh_prependfacet(facetT *facet, facetT **facetlist);
+void	qh_printhashtable(FILE *fp);
+void    qh_printlists (void);
+void    qh_resetlists (boolT stats, boolT resetVisible /*qh newvertex_list newfacet_list visible_list*/);
+void    qh_setvoronoi_all (void);
+void	qh_triangulate (void /*qh facet_list*/);
+void    qh_triangulate_facet (facetT *facetA, vertexT **first_vertex);
+void    qh_triangulate_link (facetT *oldfacetA, facetT *facetA, facetT *oldfacetB, facetT *facetB);
+void	qh_triangulate_mirror (facetT *facetA, facetT *facetB);
+void    qh_triangulate_null (facetT *facetA);
+void    qh_vertexintersect(setT **vertexsetA,setT *vertexsetB);
+setT   *qh_vertexintersect_new(setT *vertexsetA,setT *vertexsetB);
+void    qh_vertexneighbors (void /*qh facet_list*/);
+boolT 	qh_vertexsubset(setT *vertexsetA, setT *vertexsetB);
+
+
+#endif /* qhDEFpoly */
diff --git a/extern/qhull/include/qhull/qhull.h b/extern/qhull/include/qhull/qhull.h
new file mode 100644
index 00000000000..896ec1e9c18
--- /dev/null
+++ b/extern/qhull/include/qhull/qhull.h
@@ -0,0 +1,1048 @@
+/*
  ---------------------------------
+
+   qhull.h
+   user-level header file for using qhull.a library
+
+   see qh-qhull.htm, qhull_a.h
+
+   copyright (c) 1993-2002, The Geometry Center
+
+   NOTE: access to qh_qh is via the 'qh' macro.  This allows
+   qh_qh to be either a pointer or a structure.  An example
+   of using qh is "qh DROPdim" which accesses the DROPdim
+   field of qh_qh.  Similarly, access to qh_qhstat is via
+   the 'qhstat' macro.
+
+   includes function prototypes for qhull.c, geom.c, global.c, io.c, user.c
+
+   use mem.h for mem.c
+   use qset.h for qset.c
+
+   see unix.c for an example of using qhull.h
+
+   recompile qhull if you change this file
+*/
+
+#ifndef qhDEFqhull
+#define qhDEFqhull 1
+
+/*=========================== -included files ==============*/
+
+#include 
+#include 
+#include 
+
+#if __MWERKS__ && __POWERPC__
+#include  
+#include  
+#include	
+#endif
+
+#ifndef __STDC__
+#ifndef __cplusplus
+#if     !_MSC_VER
+#error  Neither __STDC__ nor __cplusplus is defined.  Please use strict ANSI C or C++ to compile
+#error  Qhull.  You may need to turn off compiler extensions in your project configuration.  If
+#error  your compiler is a standard C compiler, you can delete this warning from qhull.h
+#endif
+#endif
+#endif
+
+#include "user.h"      /* user defineable constants */
+
+/*============ constants and basic types ====================*/
+
+/*----------------------------------
+
+  qh_VERSION
+    version string by year and date
+
+    the revision increases on code changes only
+
+  notes:
+    change date:    Changes.txt, Announce.txt, README.txt, qhull.man
+                    qhull-news.html, Eudora signatures, 
+    change version: README.txt, qhull.html, file_id.diz, Makefile
+    change year:    Copying.txt
+    check download size
+    recompile user_eg.c, rbox.c, qhull.c, qconvex.c, qdelaun.c qvoronoi.c, qhalf.c
+    make copy of qhull-news.html as qh-news.htm
+*/
+
+#define qh_VERSION "2002.1 2002/8/20"
+
+/*----------------------------------
+
+  coordT
+    coordinates and coefficients are stored as realT (i.e., double)
+
+  notes:
+    could use 'float' for data and 'double' for calculations (realT vs. coordT)
+      This requires many type casts, and adjusted error bounds.
+      Also C compilers may do expressions in double anyway.
+*/
+#define coordT realT
+
+/*----------------------------------
+
+  pointT
+    a point is an array of DIM3 coordinates
+*/
+#define pointT coordT
+
+/*----------------------------------
+
+  flagT
+    Boolean flag as a bit
+*/
+#define flagT unsigned int
+
+/*----------------------------------
+
+  boolT
+    boolean value, either True or False
+
+  notes:
+    needed for portability
+*/
+#define boolT unsigned int
+#ifdef False
+#undef False
+#endif
+#ifdef True
+#undef True
+#endif
+#define False 0
+#define True 1
+
+/*----------------------------------
+
+  qh_CENTER
+    to distinguish facet->center
+*/
+typedef enum
+{
+    qh_ASnone = 0, qh_ASvoronoi, qh_AScentrum
+}
+qh_CENTER;
+
+/*----------------------------------
+
+  qh_PRINT
+    output formats for printing (qh.PRINTout).
+    'Fa' 'FV' 'Fc' 'FC' 
+       
+
+   notes:
+   some of these names are similar to qh names.  The similar names are only
+   used in switch statements in qh_printbegin() etc.
+*/
+typedef enum {qh_PRINTnone= 0, 
+  qh_PRINTarea, qh_PRINTaverage,           /* 'Fa' 'FV' 'Fc' 'FC' */
+  qh_PRINTcoplanars, qh_PRINTcentrums, 
+  qh_PRINTfacets, qh_PRINTfacets_xridge,   /* 'f' 'FF' 'G' 'FI' 'Fi' 'Fn' */
+  qh_PRINTgeom, qh_PRINTids, qh_PRINTinner, qh_PRINTneighbors, 
+  qh_PRINTnormals, qh_PRINTouter,          /* 'n' 'Fo' 'i' 'm' 'Fm' 'o' */
+  qh_PRINTincidences, qh_PRINTmathematica, qh_PRINTmerges, qh_PRINToff, 
+  qh_PRINToptions, qh_PRINTpointintersect, /* 'FO' 'Fp' 'FP' 'p' 'FQ' 'FS' */
+  qh_PRINTpointnearest, qh_PRINTpoints, qh_PRINTqhull, qh_PRINTsize, 
+  qh_PRINTsummary, qh_PRINTtriangles,      /* 'Fs' 'Ft' 'Fv' 'FN' 'Fx' */
+  qh_PRINTvertices, qh_PRINTvneighbors, qh_PRINTextremes,
+  qh_PRINTEND} qh_PRINT;
+
+/*----------------------------------
+
+  qh_ALL
+    argument flag for selecting everything
+*/
+#define qh_ALL      True
+#define qh_NOupper  True     /* argument for qh_findbest */
+#define qh_IScheckmax  True     /* argument for qh_findbesthorizon */
+#define qh_ISnewfacets  True     /* argument for qh_findbest */
+#define qh_RESETvisible  True     /* argument for qh_resetlists */
+
+/*----------------------------------
+
+  qh_ERR
+    Qhull exit codes, for indicating errors
+*/
+#define qh_ERRnone  0    /* no error occurred during qhull */
+#define qh_ERRinput 1    /* input inconsistency */
+#define qh_ERRsingular 2 /* singular input data */
+#define qh_ERRprec  3    /* precision error */
+#define qh_ERRmem   4    /* insufficient memory, matches mem.h */
+#define qh_ERRqhull 5    /* internal error detected, matches mem.h */
+
+/* ============ -structures- ====================
+   each of the following structures is defined by a typedef
+   all realT and coordT fields occur at the beginning of a structure
+        (otherwise space may be wasted due to alignment)
+   define all flags together and pack into 32-bit number
+*/
+
+typedef struct vertexT vertexT;
+typedef struct ridgeT ridgeT;
+typedef struct facetT facetT;
+#ifndef DEFsetT
+#define DEFsetT 1
+typedef struct setT setT;          /* defined in qset.h */
+#endif
+
+/*----------------------------------
+
+  facetT
+    defines a facet
+
+  notes:
+   qhull() generates the hull as a list of facets.
+
+  topological information:
+    f.previous,next     doubly-linked list of facets
+    f.vertices          set of vertices
+    f.ridges            set of ridges
+    f.neighbors         set of neighbors
+    f.toporient         True if facet has top-orientation (else bottom)
+
+  geometric information:
+    f.offset,normal     hyperplane equation
+    f.maxoutside        offset to outer plane -- all points inside
+    f.center            centrum for testing convexity
+    f.simplicial        True if facet is simplicial
+    f.flipped           True if facet does not include qh.interior_point
+
+  for constructing hull:
+    f.visible           True if facet on list of visible facets (will be deleted)
+    f.newfacet          True if facet on list of newly created facets
+    f.coplanarset       set of points coplanar with this facet
+                        (includes near-inside points for later testing)
+    f.outsideset        set of points outside of this facet
+    f.furthestdist      distance to furthest point of outside set
+    f.visitid           marks visited facets during a loop
+    f.replace           replacement facet for to-be-deleted, visible facets
+    f.samecycle,newcycle cycle of facets for merging into horizon facet
+
+  see below for other flags and fields
+*/
+struct facetT {
+#if !qh_COMPUTEfurthest
+  coordT   furthestdist;/* distance to furthest point of outsideset */
+#endif
+#if qh_MAXoutside
+  coordT   maxoutside;  /* max computed distance of point to facet
+  			Before QHULLfinished this is an approximation
+  			since maxdist not always set for mergefacet
+			Actual outer plane is +DISTround and
+			computed outer plane is +2*DISTround */
+#endif
+  coordT   offset;      /* exact offset of hyperplane from origin */
+  coordT  *normal;      /* normal of hyperplane, hull_dim coefficients */
+			/*   if tricoplanar, shared with a neighbor */
+  union {               /* in order of testing */
+   realT   area;        /* area of facet, only in io.c if  ->isarea */
+   facetT *replace;	/*  replacement facet if ->visible and NEWfacets
+  			     is NULL only if qh_mergedegen_redundant or interior */
+   facetT *samecycle;   /*  cycle of facets from the same visible/horizon intersection,
+   			     if ->newfacet */
+   facetT *newcycle;    /*  in horizon facet, current samecycle of new facets */ 
+   facetT *trivisible;  /* visible facet for ->tricoplanar facets during qh_triangulate() */
+   facetT *triowner;    /* owner facet for ->tricoplanar, !isarea facets w/ ->keepcentrum */
+  }f;
+  coordT  *center;      /*  centrum for convexity, qh CENTERtype == qh_AScentrum */
+      			/*  Voronoi center, qh CENTERtype == qh_ASvoronoi */
+			/*   if tricoplanar, shared with a neighbor */
+  facetT  *previous;    /* previous facet in the facet_list */
+  facetT  *next;        /* next facet in the facet_list */
+  setT    *vertices;    /* vertices for this facet, inverse sorted by ID 
+                           if simplicial, 1st vertex was apex/furthest */
+  setT    *ridges;      /* explicit ridges for nonsimplicial facets.
+  			   for simplicial facets, neighbors defines ridge */
+  setT    *neighbors;   /* neighbors of the facet.  If simplicial, the kth
+			   neighbor is opposite the kth vertex, and the first
+			   neighbor is the horizon facet for the first vertex*/
+  setT    *outsideset;  /* set of points outside this facet
+		           if non-empty, last point is furthest
+			   if NARROWhull, includes coplanars for partitioning*/
+  setT    *coplanarset; /* set of points coplanar with this facet
+  			   > qh.min_vertex and <= facet->max_outside
+                           a point is assigned to the furthest facet
+		           if non-empty, last point is furthest away */
+  unsigned visitid;     /* visit_id, for visiting all neighbors,
+			   all uses are independent */
+  unsigned id;	        /* unique identifier from qh facet_id */
+  unsigned nummerge:9;  /* number of merges */
+#define qh_MAXnummerge 511 /*     2^9-1, 32 flags total, see "flags:" in io.c */
+  flagT    tricoplanar:1; /* True if TRIangulate and simplicial and coplanar with a neighbor */
+			  /*   all tricoplanars share the same ->center, ->normal, ->offset, ->maxoutside */
+			  /*   all tricoplanars share the same apex */
+                          /*   if ->degenerate, does not span facet (one logical ridge) */
+                          /*   one tricoplanar has ->keepcentrum and ->coplanarset */
+                          /*   during qh_triangulate, f.trivisible points to original facet */
+  flagT	   newfacet:1;  /* True if facet on qh newfacet_list (new or merged) */
+  flagT	   visible:1;   /* True if visible facet (will be deleted) */
+  flagT    toporient:1; /* True if created with top orientation
+			   after merging, use ridge orientation */
+  flagT    simplicial:1;/* True if simplicial facet, ->ridges may be implicit */
+  flagT    seen:1;      /* used to perform operations only once, like visitid */
+  flagT    seen2:1;     /* used to perform operations only once, like visitid */
+  flagT	   flipped:1;   /* True if facet is flipped */
+  flagT    upperdelaunay:1; /* True if facet is upper envelope of Delaunay triangulation */
+  flagT    notfurthest:1; /* True if last point of outsideset is not furthest*/
+
+/*-------- flags primarily for output ---------*/
+  flagT	   good:1;      /* True if a facet marked good for output */
+  flagT    isarea:1;    /* True if facet->f.area is defined */
+
+/*-------- flags for merging ------------------*/
+  flagT    dupridge:1;  /* True if duplicate ridge in facet */
+  flagT    mergeridge:1; /* True if facet or neighbor contains a qh_MERGEridge
+                            ->normal defined (also defined for mergeridge2) */
+  flagT    mergeridge2:1; /* True if neighbor contains a qh_MERGEridge (mark_dupridges */
+  flagT    coplanar:1;  /* True if horizon facet is coplanar at last use */
+  flagT     mergehorizon:1; /* True if will merge into horizon (->coplanar) */
+  flagT	    cycledone:1;/* True if mergecycle_all already done */
+  flagT    tested:1;    /* True if facet convexity has been tested (false after merge */
+  flagT    keepcentrum:1; /* True if keep old centrum after a merge, or marks owner for ->tricoplanar */
+  flagT	   newmerge:1;  /* True if facet is newly merged for reducevertices */
+  flagT	   degenerate:1; /* True if facet is degenerate (degen_mergeset or ->tricoplanar) */
+  flagT	   redundant:1;  /* True if facet is redundant (degen_mergeset) */
+};
+
+
+/*----------------------------------
+
+  ridgeT
+    defines a ridge
+
+  notes:
+  a ridge is DIM3-1 simplex between two neighboring facets.  If the
+  facets are non-simplicial, there may be more than one ridge between
+  two facets.  E.G. a 4-d hypercube has two triangles between each pair
+  of neighboring facets.
+
+  topological information:
+    vertices            a set of vertices
+    top,bottom          neighboring facets with orientation
+
+  geometric information:
+    tested              True if ridge is clearly convex
+    nonconvex           True if ridge is non-convex
+*/
+struct ridgeT {
+  setT    *vertices;    /* vertices belonging to this ridge, inverse sorted by ID 
+                           NULL if a degen ridge (matchsame) */
+  facetT  *top;         /* top facet this ridge is part of */
+  facetT  *bottom;      /* bottom facet this ridge is part of */
+  unsigned id:24;       /* unique identifier, =>room for 8 flags */
+  flagT    seen:1;      /* used to perform operations only once */
+  flagT    tested:1;    /* True when ridge is tested for convexity */
+  flagT    nonconvex:1; /* True if getmergeset detected a non-convex neighbor
+			   only one ridge between neighbors may have nonconvex */
+};
+
+/*----------------------------------
+
+  vertexT
+     defines a vertex
+
+  topological information:
+    next,previous       doubly-linked list of all vertices
+    neighbors           set of adjacent facets (only if qh.VERTEXneighbors)
+
+  geometric information:
+    point               array of DIM3 coordinates
+*/
+struct vertexT {
+  vertexT *next;        /* next vertex in vertex_list */
+  vertexT *previous;    /* previous vertex in vertex_list */
+  pointT  *point;       /* hull_dim coordinates (coordT) */
+  setT    *neighbors;   /* neighboring facets of vertex, qh_vertexneighbors()
+			   inits in io.c or after first merge */
+  unsigned visitid; /* for use with qh vertex_visit */
+  unsigned id:24;   /* unique identifier, =>room for 8 flags */
+  flagT    seen:1;      /* used to perform operations only once */
+  flagT    seen2:1;     /* another seen flag */
+  flagT    delridge:1;  /* vertex was part of a deleted ridge */
+  flagT	   deleted:1;   /* true if vertex on qh del_vertices */
+  flagT    newlist:1;   /* true if vertex on qh newvertex_list */
+};
+
+/*======= -global variables -qh ============================*/
+
+/*----------------------------------
+
+  qh
+   all global variables for qhull are in qh, qhmem, and qhstat
+
+  notes:
+   qhmem is defined in mem.h and qhstat is defined in stat.h
+   access to qh_qh is via the "qh" macro.  See qh_QHpointer in user.h
+*/
+typedef struct qhT qhT;
+#if qh_QHpointer
+#define qh qh_qh->
+extern qhT *qh_qh;     /* allocated in global.c */
+#else
+#define qh qh_qh.
+extern qhT qh_qh;
+#endif
+
+struct qhT {
+
+/*----------------------------------
+
+  qh constants
+    configuration flags and constants for Qhull
+
+  notes:
+    The user configures Qhull by defining flags.  They are
+    copied into qh by qh_setflags().  qh-quick.htm#options defines the flags.
+*/
+  boolT ALLpoints;        /* true 'Qs' if search all points for initial simplex */
+  boolT ANGLEmerge;	  /* true 'Qa' if sort potential merges by angle */
+  boolT APPROXhull;       /* true 'Wn' if MINoutside set */
+  realT MINoutside;       /*   'Wn' min. distance for an outside point */
+  boolT ATinfinity;       /* true 'Qz' if point num_points-1 is "at-infinity"
+                             for improving precision in Delaunay triangulations */
+  boolT AVOIDold;         /* true 'Q4' if avoid old->new merges */
+  boolT BESToutside;      /* true 'Qf' if partition points into best outsideset */
+  boolT CDDinput;         /* true 'Pc' if input uses CDD format (1.0/offset first) */
+  boolT CDDoutput;        /* true 'PC' if print normals in CDD format (offset first) */
+  boolT CHECKfrequently;  /* true 'Tc' if checking frequently */
+  realT premerge_cos;     /*   'A-n'   cos_max when pre merging */
+  realT postmerge_cos;    /*   'An'    cos_max when post merging */
+  boolT DELAUNAY;         /* true 'd' if computing DELAUNAY triangulation */
+  boolT DOintersections;  /* true 'Gh' if print hyperplane intersections */
+  int   DROPdim;          /* drops dim 'GDn' for 4-d -> 3-d output */
+  boolT FORCEoutput;      /* true 'Po' if forcing output despite degeneracies */
+  int   GOODpoint;        /* 1+n for 'QGn', good facet if visible/not(-) from point n*/
+  pointT *GOODpointp;     /*   the actual point */
+  boolT GOODthreshold;    /* true if qh lower_threshold/upper_threshold defined
+  			     false if qh SPLITthreshold */
+  int   GOODvertex;       /* 1+n, good facet if vertex for point n */
+  pointT *GOODvertexp;     /*   the actual point */
+  boolT HALFspace;        /* true 'Hn,n,n' if halfspace intersection */
+  int   IStracing;        /* trace execution, 0=none, 1=least, 4=most, -1=events */
+  int   KEEParea;         /* 'PAn' number of largest facets to keep */
+  boolT KEEPcoplanar;     /* true 'Qc' if keeping nearest facet for coplanar points */
+  boolT KEEPinside;       /* true 'Qi' if keeping nearest facet for inside points
+			      set automatically if 'd Qc' */
+  int   KEEPmerge;        /* 'PMn' number of facets to keep with most merges */
+  realT KEEPminArea;      /* 'PFn' minimum facet area to keep */
+  realT MAXcoplanar;      /* 'Un' max distance below a facet to be coplanar*/
+  boolT MERGEexact;	  /* true 'Qx' if exact merges (coplanar, degen, dupridge, flipped) */
+  boolT MERGEindependent; /* true 'Q2' if merging independent sets */
+  boolT MERGING;          /* true if exact-, pre- or post-merging, with angle and centrum tests */
+  realT   premerge_centrum;  /*   'C-n' centrum_radius when pre merging.  Default is round-off */
+  realT   postmerge_centrum; /*   'Cn' centrum_radius when post merging.  Default is round-off */
+  boolT MERGEvertices;	  /* true 'Q3' if merging redundant vertices */
+  realT MINvisible;       /* 'Vn' min. distance for a facet to be visible */
+  boolT NOnarrow;         /* true 'Q10' if no special processing for narrow distributions */
+  boolT NOnearinside;     /* true 'Q8' if ignore near-inside points when partitioning */
+  boolT NOpremerge;       /* true 'Q0' if no defaults for C-0 or Qx */
+  boolT ONLYgood; 	  /* true 'Qg' if process points with good visible or horizon facets */
+  boolT ONLYmax; 	  /* true 'Qm' if only process points that increase max_outside */
+  boolT PICKfurthest;     /* true 'Q9' if process furthest of furthest points*/
+  boolT POSTmerge;        /* true if merging after buildhull (Cn or An) */
+  boolT PREmerge;         /* true if merging during buildhull (C-n or A-n) */
+  			/* NOTE: some of these names are similar to qh_PRINT names */
+  boolT PRINTcentrums;	  /* true 'Gc' if printing centrums */
+  boolT PRINTcoplanar;    /* true 'Gp' if printing coplanar points */
+  int	PRINTdim;      	  /* print dimension for Geomview output */
+  boolT PRINTdots;        /* true 'Ga' if printing all points as dots */
+  boolT PRINTgood;        /* true 'Pg' if printing good facets */
+  boolT PRINTinner;	  /* true 'Gi' if printing inner planes */
+  boolT PRINTneighbors;	  /* true 'PG' if printing neighbors of good facets */
+  boolT PRINTnoplanes;	  /* true 'Gn' if printing no planes */
+  boolT PRINToptions1st;  /* true 'FO' if printing options to stderr */
+  boolT PRINTouter;	  /* true 'Go' if printing outer planes */
+  boolT PRINTprecision;   /* false 'Pp' if not reporting precision problems */
+  qh_PRINT PRINTout[qh_PRINTEND]; /* list of output formats to print */
+  boolT PRINTridges;      /* true 'Gr' if print ridges */
+  boolT PRINTspheres;     /* true 'Gv' if print vertices as spheres */
+  boolT PRINTstatistics;  /* true 'Ts' if printing statistics to stderr */
+  boolT PRINTsummary;     /* true 's' if printing summary to stderr */
+  boolT PRINTtransparent; /* true 'Gt' if print transparent outer ridges */
+  boolT PROJECTdelaunay;  /* true if DELAUNAY, no readpoints() and
+			     need projectinput() for Delaunay in qh_init_B */
+  int   PROJECTinput;     /* number of projected dimensions 'bn:0Bn:0' */
+  boolT QUICKhelp;	  /* true if quick help message for degen input */
+  boolT RANDOMdist;       /* true if randomly change distplane and setfacetplane */
+  realT RANDOMfactor;     /*    maximum random perturbation */
+  realT RANDOMa;         /*  qh_randomfactor is randr * RANDOMa + RANDOMb */
+  realT RANDOMb;
+  boolT RANDOMoutside;    /* true if select a random outside point */
+  int	REPORTfreq;       /* buildtracing reports every n facets */
+  int   REPORTfreq2;	  /* tracemerging reports every REPORTfreq/2 facets */
+  int	RERUN;            /* 'TRn' rerun qhull n times (qh.build_cnt) */
+  int	ROTATErandom;	  /* 'QRn' seed, 0 time, >= rotate input */
+  boolT SCALEinput;       /* true 'Qbk' if scaling input */
+  boolT SCALElast;        /* true 'Qbb' if scale last coord to max prev coord */
+  boolT SETroundoff;      /* true 'E' if qh DISTround is predefined */
+  boolT SKIPcheckmax;	  /* true 'Q5' if skip qh_check_maxout */
+  boolT SKIPconvex;       /* true 'Q6' if skip convexity testing during pre-merge */
+  boolT SPLITthresholds;  /* true if upper_/lower_threshold defines a region
+                               used only for printing (not for qh ONLYgood) */
+  int	STOPcone;         /* 'TCn' 1+n for stopping after cone for point n*/
+			  /*       also used by qh_build_withresart for err exit*/
+  int	STOPpoint;        /* 'TVn' 'TV-n' 1+n for stopping after/before(-)
+			                adding point n */
+  int	TESTpoints;	  /* 'QTn' num of test points after qh.num_points.  Test points always coplanar. */
+  boolT TESTvneighbors;   /*  true 'Qv' if test vertex neighbors at end */
+  int   TRACElevel;       /* 'Tn' conditional IStracing level */
+  int	TRACElastrun;	  /*  qh.TRACElevel applies to last qh.RERUN */
+  int   TRACEpoint;       /* 'TPn' start tracing when point n is a vertex */
+  realT TRACEdist;        /* 'TWn' start tracing when merge distance too big */
+  int   TRACEmerge;       /* 'TMn' start tracing before this merge */
+  boolT TRIangulate;	  /* true 'Qt' if triangulate non-simplicial facets */
+  boolT TRInormals;	  /* true 'Q11' if triangulate duplicates normals (sets Qt) */
+  boolT UPPERdelaunay;    /* true 'Qu' if computing furthest-site Delaunay */
+  boolT VERIFYoutput;     /* true 'Tv' if verify output at end of qhull */
+  boolT VIRTUALmemory;    /* true 'Q7' if depth-first processing in buildhull */
+  boolT VORONOI;	  /* true 'v' if computing Voronoi diagram */
+
+  /*--------input constants ---------*/
+  realT AREAfactor;       /* 1/(hull_dim-1)! for converting det's to area */
+  boolT DOcheckmax;       /* true if calling qh_check_maxout (qh_initqhull_globals) */
+  char	*feasible_string;  /* feasible point 'Hn,n,n' for halfspace intersection */
+  coordT *feasible_point;  /*    as coordinates, both malloc'd */
+  boolT GETarea;          /* true 'Fa', 'FA', 'FS', 'PAn', 'PFn' if compute facet area/Voronoi volume in io.c */
+  boolT KEEPnearinside;   /* true if near-inside points in coplanarset */
+  int 	hull_dim;         /* dimension of hull, set by initbuffers */
+  int 	input_dim;	  /* dimension of input, set by initbuffers */
+  int 	num_points;       /* number of input points */
+  pointT *first_point;    /* array of input points, see POINTSmalloc */
+  boolT POINTSmalloc;     /*   true if qh first_point/num_points allocated */
+  pointT *input_points;   /* copy of original qh.first_point for input points for qh_joggleinput */
+  boolT input_malloc;     /* true if qh input_points malloc'd */
+  char 	qhull_command[256];/* command line that invoked this program */
+  char 	rbox_command[256]; /* command line that produced the input points */
+  char  qhull_options[512];/* descriptive list of options */
+  int   qhull_optionlen;  /*    length of last line */
+  int   qhull_optionsiz;  /*     size of qhull_options before qh_initbuild */
+  boolT VERTEXneighbors;  /* true if maintaining vertex neighbors */
+  boolT ZEROcentrum;      /* true if 'C-0' or 'C-0 Qx'.  sets ZEROall_ok */
+  realT *upper_threshold; /* don't print if facet->normal[k]>=upper_threshold[k]
+                             must set either GOODthreshold or SPLITthreshold
+  			     if Delaunay, default is 0.0 for upper envelope */
+  realT *lower_threshold; /* don't print if facet->normal[k] <=lower_threshold[k] */
+  realT *upper_bound;     /* scale point[k] to new upper bound */
+  realT *lower_bound;     /* scale point[k] to new lower bound
+  			     project if both upper_ and lower_bound == 0 */
+
+/*----------------------------------
+
+  qh precision constants
+    precision constants for Qhull
+
+  notes:
+    qh_detroundoff() computes the maximum roundoff error for distance
+    and other computations.  It also sets default values for the
+    qh constants above.
+*/
+  realT ANGLEround;       /* max round off error for angles */
+  realT centrum_radius;   /* max centrum radius for convexity (roundoff added) */
+  realT cos_max;	  /* max cosine for convexity (roundoff added) */
+  realT DISTround;        /* max round off error for distances, 'E' overrides */
+  realT MAXabs_coord;     /* max absolute coordinate */
+  realT MAXlastcoord;     /* max last coordinate for qh_scalelast */
+  realT MAXsumcoord;      /* max sum of coordinates */
+  realT MAXwidth;         /* max rectilinear width of point coordinates */
+  realT MINdenom_1;       /* min. abs. value for 1/x */
+  realT MINdenom;         /*    use divzero if denominator < MINdenom */
+  realT MINdenom_1_2;     /* min. abs. val for 1/x that allows normalization */
+  realT MINdenom_2;       /*    use divzero if denominator < MINdenom_2 */
+  realT MINlastcoord;     /* min. last coordinate for qh_scalelast */
+  boolT NARROWhull;       /* set in qh_initialhull if angle < qh_MAXnarrow */
+  realT *NEARzero;        /* hull_dim array for near zero in gausselim */
+  realT NEARinside;       /* keep points for qh_check_maxout if close to facet */
+  realT ONEmerge;         /* max distance for merging simplicial facets */
+  realT outside_err;      /* application's epsilon for coplanar points
+                             qh_check_bestdist() qh_check_points() reports error if point outside */
+  realT WIDEfacet;        /* size of wide facet for skipping ridge in
+			     area computation and locking centrum */
+  
+/*----------------------------------
+
+  qh internal constants
+    internal constants for Qhull
+*/
+  char qhull[sizeof("qhull")]; /* for checking ownership */
+  void *old_stat;         /* pointer to saved qh_qhstat, qh_save_qhull */
+  jmp_buf errexit;        /* exit label for qh_errexit, defined by setjmp() */
+  char jmpXtra[40];       /* extra bytes in case jmp_buf is defined wrong by compiler */
+  jmp_buf restartexit;    /* restart label for qh_errexit, defined by setjmp() */
+  char jmpXtra2[40];      /* extra bytes in case jmp_buf is defined wrong by compiler*/
+  FILE *fin;              /* pointer to input file, init by qh_meminit */
+  FILE *fout;             /* pointer to output file */
+  FILE *ferr;             /* pointer to error file */
+  pointT *interior_point; /* center point of the initial simplex*/
+  int   normal_size;      /* size in bytes for facet normals and point coords*/
+  int   center_size;      /* size in bytes for Voronoi centers */
+  int   TEMPsize;         /* size for small, temporary sets (in quick mem) */
+
+/*----------------------------------
+
+  qh facet and vertex lists
+    defines lists of facets, new facets, visible facets, vertices, and
+    new vertices.  Includes counts, next ids, and trace ids.
+  see:
+    qh_resetlists()
+*/
+  facetT *facet_list;     /* first facet */
+  facetT  *facet_tail;     /* end of facet_list (dummy facet) */
+  facetT *facet_next;     /* next facet for buildhull()
+    			     previous facets do not have outside sets
+                             NARROWhull: previous facets may have coplanar outside sets for qh_outcoplanar */
+  facetT *newfacet_list;  /* list of new facets to end of facet_list */
+  facetT *visible_list;   /* list of visible facets preceeding newfacet_list,
+                             facet->visible set */
+  int       num_visible;  /* current number of visible facets */
+  unsigned tracefacet_id;  /* set at init, then can print whenever */
+  facetT *tracefacet;     /*   set in newfacet/mergefacet, undone in delfacet*/
+  unsigned tracevertex_id;  /* set at buildtracing, can print whenever */
+  vertexT *tracevertex;     /*   set in newvertex, undone in delvertex*/
+  vertexT *vertex_list;     /* list of all vertices, to vertex_tail */
+  vertexT  *vertex_tail;    /*      end of vertex_list (dummy vertex) */
+  vertexT *newvertex_list; /* list of vertices in newfacet_list, to vertex_tail
+                             all vertices have 'newlist' set */
+  int 	num_facets;	  /* number of facets in facet_list
+			     includes visble faces (num_visible) */
+  int 	num_vertices;     /* number of vertices in facet_list */
+  int   num_outside;      /* number of points in outsidesets (for tracing and RANDOMoutside)
+                               includes coplanar outsideset points for NARROWhull/qh_outcoplanar() */
+  int   num_good;         /* number of good facets (after findgood_all) */
+  unsigned facet_id;      /* ID of next, new facet from newfacet() */
+  unsigned ridge_id;      /* ID of next, new ridge from newridge() */
+  unsigned vertex_id;     /* ID of next, new vertex from newvertex() */
+
+/*----------------------------------
+
+  qh global variables
+    defines minimum and maximum distances, next visit ids, several flags,
+    and other global variables.
+    initialize in qh_initbuild or qh_maxmin if used in qh_buildhull
+*/
+  unsigned long hulltime; /* ignore time to set up input and randomize */
+                          /*   use unsigned to avoid wrap-around errors */
+  boolT ALLOWrestart;     /* true if qh_precision can use qh.restartexit */
+  int   build_cnt;        /* number of calls to qh_initbuild */
+  qh_CENTER CENTERtype;   /* current type of facet->center, qh_CENTER */
+  int 	furthest_id;      /* pointid of furthest point, for tracing */
+  facetT *GOODclosest;    /* closest facet to GOODthreshold in qh_findgood */
+  realT JOGGLEmax;        /* set 'QJn' if randomly joggle input */
+  boolT maxoutdone;       /* set qh_check_maxout(), cleared by qh_addpoint() */
+  realT max_outside;      /* maximum distance from a point to a facet,
+			       before roundoff, not simplicial vertices
+			       actual outer plane is +DISTround and
+			       computed outer plane is +2*DISTround */
+  realT max_vertex;       /* maximum distance (>0) from vertex to a facet,
+			       before roundoff, due to a merge */
+  realT min_vertex;       /* minimum distance (<0) from vertex to a facet,
+			       before roundoff, due to a merge
+			       if qh.JOGGLEmax, qh_makenewplanes sets it
+  			       recomputed if qh.DOcheckmax, default -qh.DISTround */
+  boolT NEWfacets;        /* true while visible facets invalid due to new or merge
+			      from makecone/attachnewfacets to deletevisible */
+  boolT findbestnew;	  /* true if partitioning calls qh_findbestnew */
+  boolT findbest_notsharp; /* true if new facets are at least 90 degrees */
+  boolT NOerrexit;        /* true if qh.errexit is not available */
+  realT PRINTcradius;     /* radius for printing centrums */
+  realT PRINTradius;      /* radius for printing vertex spheres and points */
+  boolT POSTmerging;      /* true when post merging */
+  int 	printoutvar;	  /* temporary variable for qh_printbegin, etc. */
+  int 	printoutnum;	  /* number of facets printed */
+  boolT QHULLfinished;    /* True after qhull() is finished */
+  realT totarea;          /* 'FA': total facet area computed by qh_getarea */
+  realT totvol;           /* 'FA': total volume computed by qh_getarea */
+  unsigned int visit_id;  /* unique ID for searching neighborhoods, */
+  unsigned int vertex_visit; /* unique ID for searching vertices */
+  boolT ZEROall_ok;       /* True if qh_checkzero always succeeds */
+  boolT WAScoplanar;      /* True if qh_partitioncoplanar (qh_check_maxout) */
+  
+/*----------------------------------
+
+  qh global sets
+    defines sets for merging, initial simplex, hashing, extra input points,
+    and deleted vertices
+*/
+  setT *facet_mergeset;   /* temporary set of merges to be done */
+  setT *degen_mergeset;   /* temporary set of degenerate and redundant merges */
+  setT *hash_table;	  /* hash table for matching ridges in qh_matchfacets
+                             size is setsize() */
+  setT *other_points;     /* additional points (first is qh interior_point) */
+  setT *del_vertices;     /* vertices to partition and delete with visible
+                             facets.  Have deleted set for checkfacet */
+
+/*----------------------------------
+
+  qh global buffers
+    defines buffers for maxtrix operations, input, and error messages
+*/
+  coordT *gm_matrix;      /* (dim+1)Xdim matrix for geom.c */
+  coordT **gm_row;        /* array of gm_matrix rows */
+  char* line;             /* malloc'd input line of maxline+1 chars */
+  int maxline;
+  coordT *half_space;     /* malloc'd input array for halfspace (qh normal_size+coordT) */
+  coordT *temp_malloc;    /* malloc'd input array for points */
+  
+/*----------------------------------
+
+  qh static variables
+    defines static variables for individual functions
+
+  notes:
+    do not use 'static' within a function.  Multiple instances of qhull
+    may exist.
+
+    do not assume zero initialization, 'QPn' may cause a restart
+*/
+  boolT ERREXITcalled;    /* true during errexit (prevents duplicate calls */
+  boolT firstcentrum; 	  /* for qh_printcentrum */
+  realT last_low;         /* qh_scalelast parameters for qh_setdelaunay */
+  realT last_high;
+  realT last_newhigh;
+  unsigned lastreport;    /* for qh_buildtracing */
+  int mergereport;        /* for qh_tracemerging */
+  boolT old_randomdist;   /* save RANDOMdist when io, tracing, or statistics */
+  int   ridgeoutnum;      /* number of ridges in 4OFF output */
+  void *old_qhstat;       /* for saving qh_qhstat in save_qhull() */
+  setT *old_tempstack;     /* for saving qhmem.tempstack in save_qhull */
+  setT *coplanarset;      /* set of coplanar facets for searching qh_findbesthorizon() */
+};
+
+/*=========== -macros- =========================*/
+
+/*----------------------------------
+
+  otherfacet_(ridge, facet)
+    return neighboring facet for a ridge in facet
+*/
+#define otherfacet_(ridge, facet) \
+                        (((ridge)->top == (facet)) ? (ridge)->bottom : (ridge)->top)
+
+/*----------------------------------
+
+  getid_(p)
+    return ID for facet, ridge, or vertex
+    return MAXINT if NULL (-1 causes type conversion error )
+*/
+#define getid_(p)       ((p) ? (p)->id : -1)
+
+/*============== FORALL macros ===================*/
+
+/*----------------------------------
+
+  FORALLfacets { ... }
+    assign 'facet' to each facet in qh.facet_list
+
+  notes:
+    uses 'facetT *facet;'
+    assumes last facet is a sentinel
+
+  see:
+    FORALLfacet_( facetlist )
+*/
+#define FORALLfacets for (facet=qh facet_list;facet && facet->next;facet=facet->next)
+
+/*----------------------------------
+
+  FORALLpoints { ... }
+    assign 'point' to each point in qh.first_point, qh.num_points
+
+  declare:
+    coordT *point, *pointtemp;
+*/
+#define FORALLpoints FORALLpoint_(qh first_point, qh num_points)
+
+/*----------------------------------
+
+  FORALLpoint_( points, num) { ... }
+    assign 'point' to each point in points array of num points
+
+  declare:
+    coordT *point, *pointtemp;
+*/
+#define FORALLpoint_(points, num) for(point= (points), \
+      pointtemp= (points)+qh hull_dim*(num); point < pointtemp; point += qh hull_dim)
+
+/*----------------------------------
+
+  FORALLvertices { ... }
+    assign 'vertex' to each vertex in qh.vertex_list
+
+  declare:
+    vertexT *vertex;
+
+  notes:
+    assumes qh.vertex_list terminated with a sentinel
+*/
+#define FORALLvertices for (vertex=qh vertex_list;vertex && vertex->next;vertex= vertex->next)
+
+/*----------------------------------
+
+  FOREACHfacet_( facets ) { ... }
+    assign 'facet' to each facet in facets
+
+  declare:
+    facetT *facet, **facetp;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHfacet_(facets)    FOREACHsetelement_(facetT, facets, facet)
+
+/*----------------------------------
+
+  FOREACHneighbor_( facet ) { ... }
+    assign 'neighbor' to each neighbor in facet->neighbors
+
+  FOREACHneighbor_( vertex ) { ... }
+    assign 'neighbor' to each neighbor in vertex->neighbors
+
+  declare:
+    facetT *neighbor, **neighborp;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHneighbor_(facet)  FOREACHsetelement_(facetT, facet->neighbors, neighbor)
+
+/*----------------------------------
+
+  FOREACHpoint_( points ) { ... }
+    assign 'point' to each point in points set
+
+  declare:
+    pointT *point, **pointp;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHpoint_(points)    FOREACHsetelement_(pointT, points, point)
+
+/*----------------------------------
+
+  FOREACHridge_( ridges ) { ... }
+    assign 'ridge' to each ridge in ridges set
+
+  declare:
+    ridgeT *ridge, **ridgep;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHridge_(ridges)    FOREACHsetelement_(ridgeT, ridges, ridge)
+
+/*----------------------------------
+
+  FOREACHvertex_( vertices ) { ... }
+    assign 'vertex' to each vertex in vertices set
+
+  declare:
+    vertexT *vertex, **vertexp;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHvertex_(vertices) FOREACHsetelement_(vertexT, vertices,vertex)
+
+/*----------------------------------
+
+  FOREACHfacet_i_( facets ) { ... }
+    assign 'facet' and 'facet_i' for each facet in facets set
+
+  declare:
+    facetT *facet;
+    int     facet_n, facet_i;
+
+  see:
+    FOREACHsetelement_i_
+*/
+#define FOREACHfacet_i_(facets)    FOREACHsetelement_i_(facetT, facets, facet)
+
+/*----------------------------------
+
+  FOREACHneighbor_i_( facet ) { ... }
+    assign 'neighbor' and 'neighbor_i' for each neighbor in facet->neighbors
+
+  FOREACHneighbor_i_( vertex ) { ... }
+    assign 'neighbor' and 'neighbor_i' for each neighbor in vertex->neighbors
+
+  declare:
+    facetT *neighbor;
+    int     neighbor_n, neighbor_i;
+
+  see:
+    FOREACHsetelement_i_
+*/
+#define FOREACHneighbor_i_(facet)  FOREACHsetelement_i_(facetT, facet->neighbors, neighbor)
+
+/*----------------------------------
+
+  FOREACHpoint_i_( points ) { ... }
+    assign 'point' and 'point_i' for each point in points set
+
+  declare:
+    pointT *point;
+    int     point_n, point_i;
+
+  see:
+    FOREACHsetelement_i_
+*/
+#define FOREACHpoint_i_(points)    FOREACHsetelement_i_(pointT, points, point)
+
+/*----------------------------------
+
+  FOREACHridge_i_( ridges ) { ... }
+    assign 'ridge' and 'ridge_i' for each ridge in ridges set
+
+  declare:
+    ridgeT *ridge;
+    int     ridge_n, ridge_i;
+
+  see:
+    FOREACHsetelement_i_
+*/
+#define FOREACHridge_i_(ridges)    FOREACHsetelement_i_(ridgeT, ridges, ridge)
+
+/*----------------------------------
+
+  FOREACHvertex_i_( vertices ) { ... }
+    assign 'vertex' and 'vertex_i' for each vertex in vertices set
+
+  declare:
+    vertexT *vertex;
+    int     vertex_n, vertex_i;
+
+  see:
+    FOREACHsetelement_i_
+ */
+#define FOREACHvertex_i_(vertices) FOREACHsetelement_i_(vertexT, vertices,vertex)
+
+/********* -qhull.c prototypes (duplicated from qhull_a.h) **********************/
+
+void    qh_qhull (void);
+boolT   qh_addpoint (pointT *furthest, facetT *facet, boolT checkdist);
+void	qh_printsummary(FILE *fp);
+
+/********* -user.c prototypes (alphabetical) **********************/
+
+void 	qh_errexit(int exitcode, facetT *facet, ridgeT *ridge);
+void 	qh_errprint(char* string, facetT *atfacet, facetT *otherfacet, ridgeT *atridge, vertexT *atvertex);
+int     qh_new_qhull (int dim, int numpoints, coordT *points, boolT ismalloc,
+		char *qhull_cmd, FILE *outfile, FILE *errfile);
+void    qh_printfacetlist(facetT *facetlist, setT *facets, boolT printall);
+void 	qh_user_memsizes (void);
+
+/***** -geom.c/geom2.c prototypes (duplicated from geom.h) ****************/
+
+facetT *qh_findbest (pointT *point, facetT *startfacet,
+		     boolT bestoutside, boolT newfacets, boolT noupper,
+		     realT *dist, boolT *isoutside, int *numpart);
+facetT *qh_findbestnew (pointT *point, facetT *startfacet,
+                     realT *dist, boolT bestoutside, boolT *isoutside, int *numpart);
+boolT   qh_gram_schmidt(int dim, realT **rows);
+void    qh_outerinner (facetT *facet, realT *outerplane, realT *innerplane);
+void	qh_printsummary(FILE *fp);
+void    qh_projectinput (void);
+void    qh_randommatrix (realT *buffer, int dim, realT **row);
+void    qh_rotateinput (realT **rows);
+void    qh_scaleinput (void);
+void    qh_setdelaunay (int dim, int count, pointT *points);
+coordT  *qh_sethalfspace_all (int dim, int count, coordT *halfspaces, pointT *feasible);
+
+/***** -global.c prototypes (alphabetical) ***********************/
+
+unsigned long qh_clock (void);
+void 	qh_checkflags (char *command, char *hiddenflags);
+void 	qh_freebuffers (void);
+void    qh_freeqhull (boolT allmem);
+void    qh_init_A (FILE *infile, FILE *outfile, FILE *errfile, int argc, char *argv[]);
+void    qh_init_B (coordT *points, int numpoints, int dim, boolT ismalloc);
+void 	qh_init_qhull_command (int argc, char *argv[]);
+void    qh_initbuffers (coordT *points, int numpoints, int dim, boolT ismalloc);
+void 	qh_initflags (char *command);
+void 	qh_initqhull_buffers (void);
+void 	qh_initqhull_globals (coordT *points, int numpoints, int dim, boolT ismalloc);
+void    qh_initqhull_mem (void);
+void 	qh_initqhull_start (FILE *infile, FILE *outfile, FILE *errfile);
+void 	qh_initthresholds (char *command);
+void    qh_option (char *option, int *i, realT *r);
+#if qh_QHpointer
+void 	qh_restore_qhull (qhT **oldqh);
+qhT    *qh_save_qhull (void);
+#endif
+
+/***** -io.c prototypes (duplicated from io.h) ***********************/
+
+void    dfacet( unsigned id);
+void    dvertex( unsigned id);
+void	qh_printneighborhood (FILE *fp, int format, facetT *facetA, facetT *facetB, boolT printall);
+void	qh_produce_output(void);
+coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc);
+
+
+/********* -mem.c prototypes (duplicated from mem.h) **********************/
+
+void qh_meminit (FILE *ferr);
+void qh_memfreeshort (int *curlong, int *totlong);
+
+/********* -poly.c/poly2.c prototypes (duplicated from poly.h) **********************/
+
+void    qh_check_output (void);
+void    qh_check_points (void);
+setT   *qh_facetvertices (facetT *facetlist, setT *facets, boolT allfacets);
+facetT *qh_findbestfacet (pointT *point, boolT bestoutside,
+           realT *bestdist, boolT *isoutside);
+vertexT *qh_nearvertex (facetT *facet, pointT *point, realT *bestdistp);
+pointT *qh_point (int id);
+setT   *qh_pointfacet (void /*qh.facet_list*/);
+int     qh_pointid (pointT *point);
+setT   *qh_pointvertex (void /*qh.facet_list*/);
+void    qh_setvoronoi_all (void);
+void	qh_triangulate (void /*qh facet_list*/);
+
+/********* -stat.c prototypes (duplicated from stat.h) **********************/
+
+void    qh_collectstatistics (void);
+void    qh_printallstatistics (FILE *fp, char *string);
+
+#endif /* qhDEFqhull */
diff --git a/extern/qhull/include/qhull/qhull_a.h b/extern/qhull/include/qhull/qhull_a.h
new file mode 100644
index 00000000000..d4e69b071be
--- /dev/null
+++ b/extern/qhull/include/qhull/qhull_a.h
@@ -0,0 +1,127 @@
+/*
  ---------------------------------
+
+   qhull_a.h 
+   all header files for compiling qhull
+
+   see qh-qhull.htm
+
+   see qhull.h for user-level definitions
+   
+   see user.h for user-defineable constants
+   
+   defines internal functions for qhull.c global.c
+
+   copyright (c) 1993-2002, The Geometry Center
+
+   Notes:  grep for ((" and (" to catch fprintf("lkasdjf");
+           full parens around (x?y:z)
+	   use '#include qhull/qhull_a.h' to avoid name clashes
+*/
+
+#ifndef qhDEFqhulla
+#define qhDEFqhulla
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include     /* some compilers will not need float.h */
+#include 
+#include 
+#include 
+/*** uncomment here and qset.c
+     if string.h does not define memcpy()
+#include 
+*/
+#include "qhull.h"
+#include "mem.h"
+#include "qset.h"
+#include "geom.h"
+#include "merge.h"
+#include "poly.h"
+#include "io.h"
+#include "stat.h"
+
+#if qh_CLOCKtype == 2  /* defined in user.h from qhull.h */
+#include 
+#include 
+#include 
+#endif
+
+#ifdef _MSC_VER  /* Microsoft Visual C++ */
+#pragma warning( disable : 4056)  /* float constant expression.  Looks like a compiler bug */
+#pragma warning( disable : 4146)  /* unary minus applied to unsigned type */
+#pragma warning( disable : 4244)  /* conversion from 'unsigned long' to 'real' */
+#pragma warning( disable : 4305)  /* conversion from 'const double' to 'float' */
+#endif
+
+/* ======= -macros- =========== */
+
+/*----------------------------------
+  
+  traceN((fp.ferr, "format\n", vars));  
+    calls fprintf if qh.IStracing >= N
+  
+  notes:
+    removing tracing reduces code size but doesn't change execution speed
+*/
+#ifndef qh_NOtrace
+#define trace0(args) {if (qh IStracing) fprintf args;}
+#define trace1(args) {if (qh IStracing >= 1) fprintf args;}
+#define trace2(args) {if (qh IStracing >= 2) fprintf args;}
+#define trace3(args) {if (qh IStracing >= 3) fprintf args;}
+#define trace4(args) {if (qh IStracing >= 4) fprintf args;}
+#define trace5(args) {if (qh IStracing >= 5) fprintf args;}
+#else /* qh_NOtrace */
+#define trace0(args) {}
+#define trace1(args) {}
+#define trace2(args) {}
+#define trace3(args) {}
+#define trace4(args) {}
+#define trace5(args) {}
+#endif /* qh_NOtrace */
+
+/***** -qhull.c prototypes (alphabetical after qhull) ********************/
+
+void 	qh_qhull (void);
+boolT   qh_addpoint (pointT *furthest, facetT *facet, boolT checkdist);
+void 	qh_buildhull(void);
+void    qh_buildtracing (pointT *furthest, facetT *facet);
+void    qh_build_withrestart (void);
+void 	qh_errexit2(int exitcode, facetT *facet, facetT *otherfacet);
+void    qh_findhorizon(pointT *point, facetT *facet, int *goodvisible,int *goodhorizon);
+pointT *qh_nextfurthest (facetT **visible);
+void 	qh_partitionall(setT *vertices, pointT *points,int npoints);
+void    qh_partitioncoplanar (pointT *point, facetT *facet, realT *dist);
+void    qh_partitionpoint (pointT *point, facetT *facet);
+void 	qh_partitionvisible(boolT allpoints, int *numpoints);
+void    qh_precision (char *reason);
+void	qh_printsummary(FILE *fp);
+
+/***** -global.c internal prototypes (alphabetical) ***********************/
+
+void    qh_appendprint (qh_PRINT format);
+void 	qh_freebuild (boolT allmem);
+void 	qh_freebuffers (void);
+void    qh_initbuffers (coordT *points, int numpoints, int dim, boolT ismalloc);
+int     qh_strtol (const char *s, char **endp);
+double  qh_strtod (const char *s, char **endp);
+
+/***** -stat.c internal prototypes (alphabetical) ***********************/
+
+void	qh_allstatA (void);
+void	qh_allstatB (void);
+void	qh_allstatC (void);
+void	qh_allstatD (void);
+void	qh_allstatE (void);
+void	qh_allstatE2 (void);
+void	qh_allstatF (void);
+void	qh_allstatG (void);
+void	qh_allstatH (void);
+void 	qh_freebuffers (void);
+void    qh_initbuffers (coordT *points, int numpoints, int dim, boolT ismalloc);
+
+#endif /* qhDEFqhulla */
diff --git a/extern/qhull/include/qhull/qset.h b/extern/qhull/include/qhull/qset.h
new file mode 100644
index 00000000000..6c0ff758de4
--- /dev/null
+++ b/extern/qhull/include/qhull/qset.h
@@ -0,0 +1,468 @@
+/*
  ---------------------------------
+
+   qset.h
+     header file for qset.c that implements set
+
+   see qh-set.htm and qset.c
+   
+   only uses mem.c, malloc/free
+
+   for error handling, writes message and calls
+      qh_errexit (qhmem_ERRqhull, NULL, NULL);
+   
+   set operations satisfy the following properties:
+    - sets have a max size, the actual size (if different) is stored at the end
+    - every set is NULL terminated
+    - sets may be sorted or unsorted, the caller must distinguish this
+   
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFset
+#define qhDEFset 1
+
+/*================= -structures- ===============*/
+
+#ifndef DEFsetT
+#define DEFsetT 1
+typedef struct setT setT;   /* a set is a sorted or unsorted array of pointers */
+#endif
+
+/*------------------------------------------
+   
+setT
+  a set or list of pointers with maximum size and actual size.
+
+variations:
+  unsorted, unique   -- a list of unique pointers with NULL terminator
+  			   user guarantees uniqueness
+  sorted	     -- a sorted list of unique pointers with NULL terminator
+  			   qset.c guarantees uniqueness
+  unsorted           -- a list of pointers terminated with NULL
+  indexed  	     -- an array of pointers with NULL elements 
+
+structure for set of n elements:
+
+	--------------
+	|  maxsize 
+	--------------
+	|  e[0] - a pointer, may be NULL for indexed sets
+	--------------
+	|  e[1]
+	
+	--------------
+	|  ...
+	--------------
+	|  e[n-1]
+	--------------
+	|  e[n] = NULL
+	--------------
+	|  ...
+	--------------
+	|  e[maxsize] - n+1 or NULL (determines actual size of set)
+	--------------
+
+*/
+
+/*-- setelemT -- internal type to allow both pointers and indices
+*/
+typedef union setelemT setelemT;
+union setelemT {
+  void    *p;
+  int      i;         /* integer used for e[maxSize] */
+};
+
+struct setT {
+  int maxsize;          /* maximum number of elements (except NULL) */
+  setelemT e[1];        /* array of pointers, tail is NULL */
+                        /* last slot (unless NULL) is actual size+1 
+                           e[maxsize]==NULL or e[e[maxsize]-1]==NULL */
+                        /* this may generate a warning since e[] contains
+			   maxsize elements */
+};
+
+/*=========== -constants- =========================*/
+
+/*-------------------------------------
+   
+  SETelemsize
+    size of a set element in bytes
+*/
+#define SETelemsize sizeof(setelemT) 
+
+
+/*=========== -macros- =========================*/
+
+/*-------------------------------------
+   
+   FOREACHsetelement_(type, set, variable)
+     define FOREACH iterator
+
+   declare:  
+     assumes *variable and **variablep are declared
+     no space in "variable)" [DEC Alpha cc compiler]
+
+   each iteration:
+     variable is set element
+     variablep is one beyond variable.  
+
+   to repeat an element:
+     variablep--; / *repeat* /
+
+   at exit:
+     variable is NULL at end of loop
+
+   example:  
+     #define FOREACHfacet_( facets ) FOREACHsetelement_( facetT, facets, facet )
+
+   notes:
+     use FOREACHsetelement_i_() if need index or include NULLs
+
+   WARNING: 
+     nested loops can't use the same variable (define another FOREACH)
+   
+     needs braces if nested inside another FOREACH
+     this includes intervening blocks, e.g. FOREACH...{ if () FOREACH...} )
+*/
+#define FOREACHsetelement_(type, set, variable) \
+        if (((variable= NULL), set)) for(\
+          variable##p= (type **)&((set)->e[0].p); \
+	  (variable= *variable##p++);)
+
+/*------------------------------------------
+
+   FOREACHsetelement_i_(type, set, variable)
+     define indexed FOREACH iterator
+
+   declare:  
+     type *variable, variable_n, variable_i;
+
+   each iteration:
+     variable is set element, may be NULL
+     variable_i is index, variable_n is qh_setsize()
+
+   to repeat an element:
+     variable_i--; variable_n-- repeats for deleted element
+
+   at exit:
+     variable==NULL and variable_i==variable_n
+
+   example:
+     #define FOREACHfacet_i_( facets ) FOREACHsetelement_i_( facetT, facets, facet )
+   
+   WARNING: 
+     nested loops can't use the same variable (define another FOREACH)
+   
+     needs braces if nested inside another FOREACH
+     this includes intervening blocks, e.g. FOREACH...{ if () FOREACH...} )
+*/
+#define FOREACHsetelement_i_(type, set, variable) \
+        if (((variable= NULL), set)) for (\
+          variable##_i= 0, variable= (type *)((set)->e[0].p), \
+                   variable##_n= qh_setsize(set);\
+          variable##_i < variable##_n;\
+          variable= (type *)((set)->e[++variable##_i].p) )
+
+/*----------------------------------------
+
+   FOREACHsetelementreverse_(type, set, variable)- 
+     define FOREACH iterator in reverse order
+
+   declare:  
+     assumes *variable and **variablep are declared
+     also declare 'int variabletemp'
+
+   each iteration:
+     variable is set element
+
+   to repeat an element:
+     variabletemp++; / *repeat* /
+
+   at exit:
+     variable is NULL
+
+   example:
+     #define FOREACHvertexreverse_( vertices ) FOREACHsetelementreverse_( vertexT, vertices, vertex )
+  
+   notes:
+     use FOREACHsetelementreverse12_() to reverse first two elements
+     WARNING: needs braces if nested inside another FOREACH
+*/
+#define FOREACHsetelementreverse_(type, set, variable) \
+        if (((variable= NULL), set)) for(\
+	   variable##temp= qh_setsize(set)-1, variable= qh_setlast(set);\
+	   variable; variable= \
+	   ((--variable##temp >= 0) ? SETelemt_(set, variable##temp, type) : NULL))
+
+/*-------------------------------------
+
+   FOREACHsetelementreverse12_(type, set, variable)- 
+     define FOREACH iterator with e[1] and e[0] reversed
+
+   declare:  
+     assumes *variable and **variablep are declared
+
+   each iteration:
+     variable is set element
+     variablep is one after variable.  
+
+   to repeat an element:
+     variablep--; / *repeat* /
+
+   at exit:
+     variable is NULL at end of loop
+  
+   example
+     #define FOREACHvertexreverse12_( vertices ) FOREACHsetelementreverse12_( vertexT, vertices, vertex )
+
+   notes:
+     WARNING: needs braces if nested inside another FOREACH
+*/
+#define FOREACHsetelementreverse12_(type, set, variable) \
+        if (((variable= NULL), set)) for(\
+          variable##p= (type **)&((set)->e[1].p); \
+	  (variable= *variable##p); \
+          variable##p == ((type **)&((set)->e[0].p))?variable##p += 2: \
+	      (variable##p == ((type **)&((set)->e[1].p))?variable##p--:variable##p++))
+
+/*-------------------------------------
+
+   FOREACHelem_( set )- 
+     iterate elements in a set
+
+   declare:  
+     void *elem, *elemp;
+
+   each iteration:
+     elem is set element
+     elemp is one beyond
+
+   to repeat an element:
+     elemp--; / *repeat* /
+
+   at exit:
+     elem == NULL at end of loop
+  
+   example:
+     FOREACHelem_(set) {
+     
+   notes:
+     WARNING: needs braces if nested inside another FOREACH
+*/
+#define FOREACHelem_(set) FOREACHsetelement_(void, set, elem)
+
+/*-------------------------------------
+
+   FOREACHset_( set )- 
+     iterate a set of sets
+
+   declare:  
+     setT *set, **setp;
+
+   each iteration:
+     set is set element
+     setp is one beyond
+
+   to repeat an element:
+     setp--; / *repeat* /
+
+   at exit:
+     set == NULL at end of loop
+  
+   example
+     FOREACHset_(sets) {
+     
+   notes:
+     WARNING: needs braces if nested inside another FOREACH
+*/
+#define FOREACHset_(sets) FOREACHsetelement_(setT, sets, set)
+
+/*-------------------------------------------
+
+   SETindex_( set, elem )
+     return index of elem in set
+
+   notes:   
+     for use with FOREACH iteration
+
+   example:
+     i= SETindex_(ridges, ridge)
+*/
+#define SETindex_(set, elem) ((void **)elem##p - (void **)&(set)->e[1].p)
+
+/*-----------------------------------------
+
+   SETref_( elem )
+     l.h.s. for modifying the current element in a FOREACH iteration
+
+   example:
+     SETref_(ridge)= anotherridge;
+*/
+#define SETref_(elem) (elem##p[-1])
+
+/*-----------------------------------------
+
+   SETelem_(set, n)
+     return the n'th element of set
+   
+   notes:
+      assumes that n is valid [0..size] and that set is defined
+      use SETelemt_() for type cast
+*/
+#define SETelem_(set, n)           ((set)->e[n].p)
+
+/*-----------------------------------------
+
+   SETelemt_(set, n, type)
+     return the n'th element of set as a type
+   
+   notes:
+      assumes that n is valid [0..size] and that set is defined
+*/
+#define SETelemt_(set, n, type)    ((type*)((set)->e[n].p))
+
+/*-----------------------------------------
+
+   SETelemaddr_(set, n, type)
+     return address of the n'th element of a set
+   
+   notes:
+      assumes that n is valid [0..size] and set is defined 
+*/
+#define SETelemaddr_(set, n, type) ((type **)(&((set)->e[n].p)))
+
+/*-----------------------------------------
+
+   SETfirst_(set)
+     return first element of set
+   
+*/
+#define SETfirst_(set)             ((set)->e[0].p)
+
+/*-----------------------------------------
+
+   SETfirstt_(set, type)
+     return first element of set as a type
+   
+*/
+#define SETfirstt_(set, type)      ((type*)((set)->e[0].p))
+
+/*-----------------------------------------
+
+   SETsecond_(set)
+     return second element of set
+   
+*/
+#define SETsecond_(set)            ((set)->e[1].p)
+
+/*-----------------------------------------
+
+   SETsecondt_(set, type)
+     return second element of set as a type
+*/
+#define SETsecondt_(set, type)     ((type*)((set)->e[1].p))
+
+/*-----------------------------------------
+
+   SETaddr_(set, type)
+       return address of set's elements
+*/
+#define SETaddr_(set,type)	   ((type **)(&((set)->e[0].p)))
+
+/*-----------------------------------------
+
+   SETreturnsize_(set, size) 
+     return size of a set
+   
+   notes:
+      set must be defined
+      use qh_setsize(set) unless speed is critical
+*/
+#define SETreturnsize_(set, size) (((size)= ((set)->e[(set)->maxsize].i))?(--(size)):((size)= (set)->maxsize))
+
+/*-----------------------------------------
+
+   SETempty_(set) 
+     return true (1) if set is empty
+   
+   notes:
+      set may be NULL
+*/
+#define SETempty_(set) 	          (!set || (SETfirst_(set) ? 0:1))
+
+/*-----------------------------------------
+
+   SETtruncate_(set)
+     return first element of set
+
+   see:
+     qh_settruncate()
+   
+*/
+#define SETtruncate_(set, size) {set->e[set->maxsize].i= size+1; /* maybe overwritten */ \
+      set->e[size].p= NULL;}
+
+/*======= prototypes in alphabetical order ============*/
+
+void  qh_setaddsorted(setT **setp, void *elem);
+void  qh_setaddnth(setT **setp, int nth, void *newelem);
+void  qh_setappend(setT **setp, void *elem);
+void  qh_setappend_set(setT **setp, setT *setA);
+void  qh_setappend2ndlast(setT **setp, void *elem);
+void  qh_setcheck(setT *set, char *tname, int id);
+void  qh_setcompact(setT *set);
+setT *qh_setcopy(setT *set, int extra);
+void *qh_setdel(setT *set, void *elem);
+void *qh_setdellast(setT *set);
+void *qh_setdelnth(setT *set, int nth);
+void *qh_setdelnthsorted(setT *set, int nth);
+void *qh_setdelsorted(setT *set, void *newelem);
+setT *qh_setduplicate( setT *set, int elemsize);
+int   qh_setequal(setT *setA, setT *setB);
+int   qh_setequal_except (setT *setA, void *skipelemA, setT *setB, void *skipelemB);
+int   qh_setequal_skip (setT *setA, int skipA, setT *setB, int skipB);
+void  qh_setfree(setT **set);
+void  qh_setfree2( setT **setp, int elemsize);
+void  qh_setfreelong(setT **set);
+int   qh_setin(setT *set, void *setelem);
+int   qh_setindex(setT *set, void *setelem);
+void  qh_setlarger(setT **setp);
+void *qh_setlast(setT *set);
+setT *qh_setnew(int size);
+setT *qh_setnew_delnthsorted(setT *set, int size, int nth, int prepend);
+void  qh_setprint(FILE *fp, char* string, setT *set);
+void  qh_setreplace(setT *set, void *oldelem, void *newelem);
+int   qh_setsize(setT *set);
+setT *qh_settemp(int setsize);
+void  qh_settempfree(setT **set);
+void  qh_settempfree_all(void);
+setT *qh_settemppop(void);
+void  qh_settemppush(setT *set);
+void  qh_settruncate (setT *set, int size);
+int   qh_setunique (setT **set, void *elem);
+void  qh_setzero (setT *set, int index, int size);
+
+
+#endif /* qhDEFset */
diff --git a/extern/qhull/include/qhull/stat.h b/extern/qhull/include/qhull/stat.h
new file mode 100644
index 00000000000..1dae54ed21d
--- /dev/null
+++ b/extern/qhull/include/qhull/stat.h
@@ -0,0 +1,520 @@
+  /*
  ---------------------------------
+
+   stat.h 
+     contains all statistics that are collected for qhull
+
+   see qh-stat.htm and stat.c
+
+   copyright (c) 1993-2002, The Geometry Center
+
+   recompile qhull if you change this file
+
+   Integer statistics are Z* while real statistics are W*.  
+
+   define maydebugx to call a routine at every statistic event
+
+*/
+
+#ifndef qhDEFstat
+#define qhDEFstat 1
+
+
+/*---------------------------------
+
+  qh_KEEPstatistics
+    0 turns off statistic gathering (except zzdef/zzinc/zzadd/zzval/wwval)
+*/
+#ifndef qh_KEEPstatistics
+#define qh_KEEPstatistics 1
+#endif
+
+/*---------------------------------
+
+  Zxxx for integers, Wxxx for reals
+
+  notes:
+    be sure that all statistics are defined in stat.c
+      otherwise initialization may core dump
+    can pick up all statistics by:
+      grep '[zw].*_[(][ZW]' *.c >z.x
+    remove trailers with query">-
+    remove leaders with  query-replace-regexp [ ^I]+  (
+*/
+#if qh_KEEPstatistics
+enum statistics {     /* alphabetical after Z/W */
+    Zacoplanar,
+    Wacoplanarmax,
+    Wacoplanartot,
+    Zangle,
+    Wangle,
+    Wanglemax,
+    Wanglemin,
+    Zangletests,
+    Wareatot,
+    Wareamax,
+    Wareamin,
+    Zavoidold,
+    Wavoidoldmax,
+    Wavoidoldtot,
+    Zback0,
+    Zbestcentrum,
+    Zbestdist,
+    Zcentrumtests,
+    Zcheckpart,
+    Zcomputefurthest,
+    Zconcave,
+    Wconcavemax,
+    Wconcavetot,
+    Zconcaveridges,
+    Zconcaveridge,
+    Zcoplanar,
+    Wcoplanarmax,
+    Wcoplanartot,
+    Zcoplanarangle,
+    Zcoplanarcentrum,
+    Zcoplanarhorizon,
+    Zcoplanarinside,
+    Zcoplanarpart,
+    Zcoplanarridges,
+    Wcpu,
+    Zcyclefacetmax,
+    Zcyclefacettot,
+    Zcyclehorizon,
+    Zcyclevertex,
+    Zdegen,
+    Wdegenmax,
+    Wdegentot,
+    Zdegenvertex,
+    Zdelfacetdup, 
+    Zdelridge,
+    Zdelvertextot,
+    Zdelvertexmax,
+    Zdetsimplex,
+    Zdistcheck,
+    Zdistconvex,
+    Zdistgood,
+    Zdistio,
+    Zdistplane,
+    Zdiststat,
+    Zdistvertex,
+    Zdistzero,
+    Zdoc1,
+    Zdoc2,
+    Zdoc3,
+    Zdoc4,
+    Zdoc5,
+    Zdoc6,
+    Zdoc7,
+    Zdoc8,
+    Zdoc9,
+    Zdoc10,
+    Zdoc11,
+    Zdoc12,
+    Zdropdegen,
+    Zdropneighbor,
+    Zdupflip,
+    Zduplicate,
+    Wduplicatemax,
+    Wduplicatetot,
+    Zdupridge,
+    Zdupsame,
+    Zflipped, 
+    Wflippedmax, 
+    Wflippedtot, 
+    Zflippedfacets,
+    Zfindbest,
+    Zfindbestmax,
+    Zfindbesttot,
+    Zfindcoplanar,
+    Zfindfail,
+    Zfindhorizon,
+    Zfindhorizonmax,
+    Zfindhorizontot,
+    Zfindjump,
+    Zfindnew,
+    Zfindnewmax,
+    Zfindnewtot,
+    Zfindnewjump,
+    Zfindnewsharp,
+    Zgauss0,
+    Zgoodfacet,
+    Zhashlookup,
+    Zhashridge,
+    Zhashridgetest,
+    Zhashtests,
+    Zinsidevisible,
+    Zintersect,
+    Zintersectfail,
+    Zintersectmax,
+    Zintersectnum,
+    Zintersecttot,
+    Zmaxneighbors,
+    Wmaxout,
+    Wmaxoutside,
+    Zmaxridges,
+    Zmaxvertex,
+    Zmaxvertices,
+    Zmaxvneighbors,
+    Zmemfacets,
+    Zmempoints,
+    Zmemridges,
+    Zmemvertices,
+    Zmergeflipdup,
+    Zmergehorizon,
+    Zmergeinittot,
+    Zmergeinitmax,
+    Zmergeinittot2,
+    Zmergeintohorizon,
+    Zmergenew,
+    Zmergesettot,
+    Zmergesetmax,
+    Zmergesettot2,
+    Zmergesimplex,
+    Zmergevertex,
+    Wmindenom,
+    Wminvertex,
+    Zminnorm,
+    Zmultiridge,
+    Znearlysingular,
+    Zneighbor,
+    Wnewbalance,
+    Wnewbalance2,
+    Znewfacettot,
+    Znewfacetmax,
+    Znewvertex,
+    Wnewvertex,
+    Wnewvertexmax,
+    Znoarea,
+    Znonsimplicial,
+    Znowsimplicial,
+    Znotgood,
+    Znotgoodnew,
+    Znotmax,
+    Znumfacets,
+    Znummergemax,
+    Znummergetot,
+    Znumneighbors,
+    Znumridges,
+    Znumvertices,
+    Znumvisibility,
+    Znumvneighbors,
+    Zonehorizon,
+    Zpartangle,
+    Zpartcoplanar,
+    Zpartflip,
+    Zparthorizon,
+    Zpartinside,
+    Zpartition, 
+    Zpartitionall,
+    Zpartnear,
+    Zpbalance,
+    Wpbalance,
+    Wpbalance2, 
+    Zpostfacets, 
+    Zpremergetot,
+    Zprocessed,
+    Zremvertex,
+    Zremvertexdel,
+    Zrenameall,
+    Zrenamepinch,
+    Zrenameshare,
+    Zretry,
+    Wretrymax,
+    Zridge,
+    Wridge,
+    Wridgemax,
+    Zridge0,
+    Wridge0,
+    Wridge0max,
+    Zridgemid,
+    Wridgemid,
+    Wridgemidmax,
+    Zridgeok,
+    Wridgeok,
+    Wridgeokmax,
+    Zsearchpoints,
+    Zsetplane,
+    Ztestvneighbor,
+    Ztotcheck,
+    Ztothorizon,
+    Ztotmerge,
+    Ztotpartcoplanar,
+    Ztotpartition,
+    Ztotridges,
+    Ztotvertices,
+    Ztotvisible,
+    Ztricoplanar,
+    Ztricoplanarmax,
+    Ztricoplanartot,
+    Ztridegen,
+    Ztrimirror,
+    Ztrinull,
+    Wvertexmax,
+    Wvertexmin,
+    Zvertexridge,
+    Zvertexridgetot,
+    Zvertexridgemax,
+    Zvertices,
+    Zvisfacettot,
+    Zvisfacetmax,
+    Zvisvertextot,
+    Zvisvertexmax,
+    Zwidefacet,
+    Zwidevertices,
+    ZEND};
+
+/*---------------------------------
+
+  Zxxx/Wxxx statistics that remain defined if qh_KEEPstatistics=0
+
+  notes:
+    be sure to use zzdef, zzinc, etc. with these statistics (no double checking!)
+*/
+#else
+enum statistics {     /* for zzdef etc. macros */
+  Zback0,
+  Zbestdist,
+  Zcentrumtests,
+  Zcheckpart,
+  Zconcaveridges,
+  Zcoplanarhorizon,
+  Zcoplanarpart,
+  Zcoplanarridges,
+  Zcyclefacettot,
+  Zcyclehorizon,
+  Zdelvertextot,
+  Zdistcheck,
+  Zdistconvex,
+  Zdistzero,
+  Zdoc1,
+  Zdoc2,
+  Zdoc3,
+  Zdoc11,
+  Zflippedfacets,
+  Zgauss0,
+  Zminnorm,
+  Zmultiridge,
+  Znearlysingular,
+  Wnewvertexmax,
+  Znumvisibility,
+  Zpartcoplanar,
+  Zpartition,
+  Zpartitionall,
+  Zprocessed,
+  Zretry,
+  Zridge,
+  Wridge,
+  Wridgemax,
+  Zridge0,
+  Wridge0,
+  Wridge0max,
+  Zridgemid,
+  Wridgemid,
+  Wridgemidmax,
+  Zridgeok,
+  Wridgeok,
+  Wridgeokmax,
+  Zsetplane,
+  Ztotmerge,
+    ZEND};
+#endif
+
+/*---------------------------------
+  
+  ztype
+    the type of a statistic sets its initial value.  
+
+  notes:
+    The type should be the same as the macro for collecting the statistic
+*/
+enum ztypes {zdoc,zinc,zadd,zmax,zmin,ZTYPEreal,wadd,wmax,wmin,ZTYPEend};
+
+/*========== macros and constants =============*/
+
+/*----------------------------------
+  
+  MAYdebugx
+    define as maydebug() to be called frequently for error trapping
+*/
+#define MAYdebugx 
+
+/*----------------------------------
+  
+  zzdef_, zdef_( type, name, doc, -1)
+    define a statistic (assumes 'qhstat.next= 0;')
+
+  zdef_( type, name, doc, count)
+    define an averaged statistic
+    printed as name/count
+*/
+#define zzdef_(stype,name,string,cnt) qhstat id[qhstat next++]=name; \
+   qhstat doc[name]= string; qhstat count[name]= cnt; qhstat type[name]= stype
+#if qh_KEEPstatistics
+#define zdef_(stype,name,string,cnt) qhstat id[qhstat next++]=name; \
+   qhstat doc[name]= string; qhstat count[name]= cnt; qhstat type[name]= stype
+#else
+#define zdef_(type,name,doc,count)
+#endif
+
+/*----------------------------------
+  
+  zzinc_( name ), zinc_( name)
+    increment an integer statistic
+*/
+#define zzinc_(id) {MAYdebugx; qhstat stats[id].i++;}
+#if qh_KEEPstatistics
+#define zinc_(id) {MAYdebugx; qhstat stats[id].i++;}
+#else
+#define zinc_(id) {}
+#endif
+
+/*----------------------------------
+  
+  zzadd_( name, value ), zadd_( name, value ), wadd_( name, value )
+    add value to an integer or real statistic
+*/
+#define zzadd_(id, val) {MAYdebugx; qhstat stats[id].i += (val);}
+#define wwadd_(id, val) {MAYdebugx; qhstat stats[id].r += (val);}
+#if qh_KEEPstatistics
+#define zadd_(id, val) {MAYdebugx; qhstat stats[id].i += (val);}
+#define wadd_(id, val) {MAYdebugx; qhstat stats[id].r += (val);}
+#else
+#define zadd_(id, val) {}
+#define wadd_(id, val) {}
+#endif
+
+/*----------------------------------
+
+  zzval_( name ), zval_( name ), wwval_( name )
+    set or return value of a statistic
+*/
+#define zzval_(id) ((qhstat stats[id]).i)
+#define wwval_(id) ((qhstat stats[id]).r)
+#if qh_KEEPstatistics
+#define zval_(id) ((qhstat stats[id]).i)
+#define wval_(id) ((qhstat stats[id]).r)
+#else
+#define zval_(id) qhstat tempi
+#define wval_(id) qhstat tempr
+#endif
+
+/*----------------------------------
+
+  zmax_( id, val ), wmax_( id, value )
+    maximize id with val
+*/
+#define wwmax_(id, val) {MAYdebugx; maximize_(qhstat stats[id].r,(val));}
+#if qh_KEEPstatistics
+#define zmax_(id, val) {MAYdebugx; maximize_(qhstat stats[id].i,(val));}
+#define wmax_(id, val) {MAYdebugx; maximize_(qhstat stats[id].r,(val));}
+#else
+#define zmax_(id, val) {}
+#define wmax_(id, val) {}
+#endif
+
+/*----------------------------------
+
+  zmin_( id, val ), wmin_( id, value )
+    minimize id with val
+*/
+#if qh_KEEPstatistics
+#define zmin_(id, val) {MAYdebugx; minimize_(qhstat stats[id].i,(val));}
+#define wmin_(id, val) {MAYdebugx; minimize_(qhstat stats[id].r,(val));}
+#else
+#define zmin_(id, val) {}
+#define wmin_(id, val) {}
+#endif
+
+/*================== stat.h types ==============*/
+
+
+/*----------------------------------
+ 
+  intrealT
+    union of integer and real, used for statistics
+*/
+typedef union intrealT intrealT;    /* union of int and realT */
+union intrealT {
+    int i;
+    realT r;
+};
+
+/*----------------------------------
+  
+  qhstat
+    global data structure for statistics
+  
+  notes:
+   access to qh_qhstat is via the "qhstat" macro.  There are two choices
+   qh_QHpointer = 1     access globals via a pointer
+                        enables qh_saveqhull() and qh_restoreqhull()
+		= 0     qh_qhstat is a static data structure
+		        only one instance of qhull() can be active at a time
+			default value
+   qh_QHpointer is defined in qhull.h
+
+   allocated in stat.c
+*/
+typedef struct qhstatT qhstatT; 
+#if qh_QHpointer
+#define qhstat qh_qhstat->
+extern qhstatT *qh_qhstat;
+#else
+#define qhstat qh_qhstat.
+extern qhstatT qh_qhstat; 
+#endif
+struct qhstatT {  
+  intrealT   stats[ZEND];     /* integer and real statistics */
+  unsigned   char id[ZEND+10]; /* id's in print order */
+  char      *doc[ZEND];       /* array of documentation strings */
+  short int  count[ZEND];     /* -1 if none, else index of count to use */
+  char       type[ZEND];      /* type, see ztypes above */
+  char       printed[ZEND];   /* true, if statistic has been printed */
+  intrealT   init[ZTYPEend];  /* initial values by types, set initstatistics */
+
+  int        next;            /* next index for zdef_ */
+  int        precision;       /* index for precision problems */
+  int        vridges;         /* index for Voronoi ridges */
+  int        tempi;
+  realT      tempr;
+};
+
+/*========== function prototypes ===========*/
+
+void    qh_allstatA(void);
+void    qh_allstatB(void);
+void    qh_allstatC(void);
+void    qh_allstatD(void);
+void    qh_allstatE(void);
+void    qh_allstatE2(void);
+void    qh_allstatF(void);
+void    qh_allstatG(void);
+void    qh_allstatH(void);
+void    qh_allstatI(void);
+void    qh_allstatistics (void);
+void    qh_collectstatistics (void);
+void	qh_freestatistics (void);
+void    qh_initstatistics (void);
+boolT 	qh_newstats (int index, int *nextindex);
+boolT 	qh_nostatistic (int i);
+void    qh_printallstatistics (FILE *fp, char *string);
+void    qh_printstatistics (FILE *fp, char *string);
+void  	qh_printstatlevel (FILE *fp, int id, int start);
+void  	qh_printstats (FILE *fp, int index, int *nextindex);
+realT   qh_stddev (int num, realT tot, realT tot2, realT *ave);
+
+#endif   /* qhDEFstat */
diff --git a/extern/qhull/include/qhull/user.h b/extern/qhull/include/qhull/user.h
new file mode 100644
index 00000000000..79558967a52
--- /dev/null
+++ b/extern/qhull/include/qhull/user.h
@@ -0,0 +1,762 @@
+/*
  ---------------------------------
+
+   user.h
+   user redefinable constants
+
+   see qh-user.htm.  see COPYING for copyright information.
+
+   before reading any code, review qhull.h for data structure definitions and 
+   the "qh" macro.
+*/
+
+#ifndef qhDEFuser
+#define qhDEFuser 1
+
+/*============= data types and configuration macros ==========*/
+
+/*----------------------------------
+  
+  realT
+    set the size of floating point numbers
+  
+  qh_REALdigits 
+    maximimum number of significant digits
+  
+  qh_REAL_1, qh_REAL_2n, qh_REAL_3n
+    format strings for printf
+  
+  qh_REALmax, qh_REALmin
+    maximum and minimum (near zero) values  
+  
+  qh_REALepsilon
+    machine roundoff.  Maximum roundoff error for addition and multiplication.
+    
+  notes:
+   Select whether to store floating point numbers in single precision (float)
+   or double precision (double).
+   
+   Use 'float' to save about 8% in time and 25% in space.  This is particularly
+   help if high-d where convex hulls are space limited.  Using 'float' also
+   reduces the printed size of Qhull's output since numbers have 8 digits of 
+   precision.
+   
+   Use 'double' when greater arithmetic precision is needed.  This is needed
+   for Delaunay triangulations and Voronoi diagrams when you are not merging 
+   facets.
+
+   If 'double' gives insufficient precision, your data probably includes
+   degeneracies.  If so you should use facet merging (done by default)
+   or exact arithmetic (see imprecision section of manual, qh-impre.htm).  
+   You may also use option 'Po' to force output despite precision errors.
+
+   You may use 'long double', but many format statements need to be changed
+   and you may need a 'long double' square root routine.  S. Grundmann
+   (sg@eeiwzb.et.tu-dresden.de) has done this.  He reports that the code runs 
+   much slower with little gain in precision.    
+
+   WARNING: on some machines,    int f(){realT a= REALmax;return (a == REALmax);}
+      returns False.  Use (a > REALmax/2) instead of (a == REALmax).
+
+   REALfloat =   1      all numbers are 'float' type
+             =   0      all numbers are 'double' type
+*/
+#define REALfloat 0
+
+#if (REALfloat == 1)
+#define realT float
+#define REALmax FLT_MAX
+#define REALmin FLT_MIN
+#define REALepsilon FLT_EPSILON
+#define qh_REALdigits 8   /* maximum number of significant digits */
+#define qh_REAL_1 "%6.8g "
+#define qh_REAL_2n "%6.8g %6.8g\n"
+#define qh_REAL_3n "%6.8g %6.8g %6.8g\n"
+
+#elif (REALfloat == 0)
+#define realT double
+#define REALmax DBL_MAX
+#define REALmin DBL_MIN
+#define REALepsilon DBL_EPSILON
+#define qh_REALdigits 16    /* maximum number of significant digits */
+#define qh_REAL_1 "%6.16g "
+#define qh_REAL_2n "%6.16g %6.16g\n"
+#define qh_REAL_3n "%6.16g %6.16g %6.16g\n"
+
+#else
+#error unknown float option
+#endif
+
+/*----------------------------------
+  
+  qh_CPUclock
+    define the clock() function for reporting the total time spent by Qhull
+    returns CPU ticks as a 'long int'
+    qh_CPUclock is only used for reporting the total time spent by Qhull
+
+  qh_SECticks 
+    the number of clock ticks per second
+
+  notes:
+    looks for CLOCKS_PER_SEC, CLOCKS_PER_SECOND, or assumes microseconds
+    to define a custom clock, set qh_CLOCKtype to 0
+
+    if your system does not use clock() to return CPU ticks, replace
+    qh_CPUclock with the corresponding function.  It is converted
+    to unsigned long to prevent wrap-around during long runs.
+   
+
+   Set qh_CLOCKtype to
+   
+     1	   	for CLOCKS_PER_SEC, CLOCKS_PER_SECOND, or microsecond
+                Note:  may fail if more than 1 hour elapsed time
+
+     2	   	use qh_clock() with POSIX times() (see global.c)
+*/
+#define qh_CLOCKtype 1  /* change to the desired number */
+
+#if (qh_CLOCKtype == 1)
+
+#if defined (CLOCKS_PER_SECOND)
+#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock */
+#define qh_SECticks CLOCKS_PER_SECOND
+
+#elif defined (CLOCKS_PER_SEC)
+#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock */
+#define qh_SECticks CLOCKS_PER_SEC
+
+#elif defined (CLK_TCK)
+#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock */
+#define qh_SECticks CLK_TCK
+
+#else
+#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock */
+#define qh_SECticks 1E6
+#endif
+
+#elif (qh_CLOCKtype == 2)
+#define qh_CPUclock    qh_clock()  /* return CPU clock */
+#define qh_SECticks 100
+
+#else /* qh_CLOCKtype == ? */
+#error unknown clock option
+#endif
+
+/*----------------------------------
+  
+  qh_RANDOMtype, qh_RANDOMmax, qh_RANDOMseed
+    define random number generator
+
+    qh_RANDOMint generates a random integer between 0 and qh_RANDOMmax.  
+    qh_RANDOMseed sets the random number seed for qh_RANDOMint
+
+  Set qh_RANDOMtype (default 5) to:
+    1       for random() with 31 bits (UCB)
+    2       for rand() with RAND_MAX or 15 bits (system 5)
+    3       for rand() with 31 bits (Sun)
+    4       for lrand48() with 31 bits (Solaris)
+    5       for qh_rand() with 31 bits (included with Qhull)
+  
+  notes:
+    Random numbers are used by rbox to generate point sets.  Random
+    numbers are used by Qhull to rotate the input ('QRn' option),
+    simulate a randomized algorithm ('Qr' option), and to simulate
+    roundoff errors ('Rn' option).
+
+    Random number generators differ between systems.  Most systems provide
+    rand() but the period varies.  The period of rand() is not critical
+    since qhull does not normally use random numbers.  
+
+    The default generator is Park & Miller's minimal standard random
+    number generator [CACM 31:1195 '88].  It is included with Qhull.
+
+    If qh_RANDOMmax is wrong, qhull will report a warning and Geomview 
+    output will likely be invisible.
+*/
+#define qh_RANDOMtype 5   /* *** change to the desired number *** */
+
+#if (qh_RANDOMtype == 1)
+#define qh_RANDOMmax ((realT)0x7fffffffUL)  /* 31 bits, random()/MAX */
+#define qh_RANDOMint random()
+#define qh_RANDOMseed_(seed) srandom(seed);
+
+#elif (qh_RANDOMtype == 2)
+#ifdef RAND_MAX
+#define qh_RANDOMmax ((realT)RAND_MAX)
+#else
+#define qh_RANDOMmax ((realT)32767)   /* 15 bits (System 5) */
+#endif
+#define qh_RANDOMint  rand()
+#define qh_RANDOMseed_(seed) srand((unsigned)seed);
+  
+#elif (qh_RANDOMtype == 3)
+#define qh_RANDOMmax ((realT)0x7fffffffUL)  /* 31 bits, Sun */
+#define qh_RANDOMint  rand()
+#define qh_RANDOMseed_(seed) srand((unsigned)seed);
+
+#elif (qh_RANDOMtype == 4)
+#define qh_RANDOMmax ((realT)0x7fffffffUL)  /* 31 bits, lrand38()/MAX */
+#define qh_RANDOMint lrand48()
+#define qh_RANDOMseed_(seed) srand48(seed);
+
+#elif (qh_RANDOMtype == 5)
+#define qh_RANDOMmax ((realT)2147483646UL)  /* 31 bits, qh_rand/MAX */
+#define qh_RANDOMint qh_rand()
+#define qh_RANDOMseed_(seed) qh_srand(seed);
+/* unlike rand(), never returns 0 */
+
+#else
+#error: unknown random option
+#endif
+
+/*----------------------------------
+  
+  qh_ORIENTclock
+    0 for inward pointing normals by Geomview convention
+*/
+#define qh_ORIENTclock 0 
+
+
+/*========= performance related constants =========*/
+
+/*----------------------------------
+  
+  qh_HASHfactor
+    total hash slots / used hash slots.  Must be at least 1.1.
+      
+  notes:
+    =2 for at worst 50% occupancy for qh hash_table and normally 25% occupancy
+*/
+#define qh_HASHfactor 2
+
+/*----------------------------------
+  
+  qh_VERIFYdirect
+    with 'Tv' verify all points against all facets if op count is smaller
+
+  notes:
+    if greater, calls qh_check_bestdist() instead
+*/
+#define qh_VERIFYdirect 1000000 
+
+/*----------------------------------
+  
+  qh_INITIALsearch
+     if qh_INITIALmax, search points up to this dimension
+*/
+#define qh_INITIALsearch 6
+
+/*----------------------------------
+  
+  qh_INITIALmax
+    if dim >= qh_INITIALmax, use min/max coordinate points for initial simplex
+      
+  notes:
+    from points with non-zero determinants
+    use option 'Qs' to override (much slower)
+*/
+#define qh_INITIALmax 8
+
+/*----------------------------------
+  
+  qh_JOGGLEdefault
+    default qh.JOGGLEmax is qh.DISTround * qh_JOGGLEdefault
+
+  notes:
+    rbox s r 100 | qhull QJ1e-15 QR0 generates 90% faults at distround 7e-16
+    rbox s r 100 | qhull QJ1e-14 QR0 generates 70% faults
+    rbox s r 100 | qhull QJ1e-13 QR0 generates 35% faults
+    rbox s r 100 | qhull QJ1e-12 QR0 generates 8% faults
+    rbox s r 100 | qhull QJ1e-11 QR0 generates 1% faults
+    rbox s r 100 | qhull QJ1e-10 QR0 generates 0% faults
+    rbox 1000 W0 | qhull QJ1e-12 QR0 generates 86% faults
+    rbox 1000 W0 | qhull QJ1e-11 QR0 generates 20% faults
+    rbox 1000 W0 | qhull QJ1e-10 QR0 generates 2% faults
+    the later have about 20 points per facet, each of which may interfere
+
+    pick a value large enough to avoid retries on most inputs
+*/
+#define qh_JOGGLEdefault 30000.0
+
+/*----------------------------------
+  
+  qh_JOGGLEincrease
+    factor to increase qh.JOGGLEmax on qh_JOGGLEretry or qh_JOGGLEagain
+*/
+#define qh_JOGGLEincrease 10.0
+
+/*----------------------------------
+  
+  qh_JOGGLEretry
+    if ZZretry = qh_JOGGLEretry, increase qh.JOGGLEmax
+
+  notes:
+    try twice at the original value in case of bad luck the first time
+*/
+#define qh_JOGGLEretry 2
+
+/*----------------------------------
+  
+  qh_JOGGLEagain
+    every following qh_JOGGLEagain, increase qh.JOGGLEmax
+
+  notes:
+    1 is OK since it's already failed qh_JOGGLEretry times
+*/
+#define qh_JOGGLEagain 1
+
+/*----------------------------------
+  
+  qh_JOGGLEmaxincrease
+    maximum qh.JOGGLEmax due to qh_JOGGLEincrease
+    relative to qh.MAXwidth
+
+  notes:
+    qh.joggleinput will retry at this value until qh_JOGGLEmaxretry
+*/
+#define qh_JOGGLEmaxincrease 1e-2
+
+/*----------------------------------
+  
+  qh_JOGGLEmaxretry
+    stop after qh_JOGGLEmaxretry attempts
+*/
+#define qh_JOGGLEmaxretry 100
+
+/*========= memory constants =========*/
+
+/*----------------------------------
+  
+  qh_MEMalign
+    memory alignment for qh_meminitbuffers() in global.c
+    
+  notes:
+    to avoid bus errors, memory allocation must consider alignment requirements.
+    malloc() automatically takes care of alignment.   Since mem.c manages
+    its own memory, we need to explicitly specify alignment in
+    qh_meminitbuffers().
+
+    A safe choice is sizeof(double).  sizeof(float) may be used if doubles 
+    do not occur in data structures and pointers are the same size.  Be careful
+    of machines (e.g., DEC Alpha) with large pointers. 
+
+    If using gcc, best alignment is
+              #define qh_MEMalign fmax_(__alignof__(realT),__alignof__(void *))
+*/
+#define qh_MEMalign fmax_(sizeof(realT), sizeof(void *))
+
+/*----------------------------------
+  
+  qh_MEMbufsize
+    size of additional memory buffers
+    
+  notes:
+    used for qh_meminitbuffers() in global.c
+*/
+#define qh_MEMbufsize 0x10000       /* allocate 64K memory buffers */
+
+/*----------------------------------
+  
+  qh_MEMinitbuf
+    size of initial memory buffer
+    
+  notes:
+    use for qh_meminitbuffers() in global.c
+*/
+#define qh_MEMinitbuf 0x20000      /* initially allocate 128K buffer */
+
+/*----------------------------------
+  
+  qh_INFINITE
+    on output, indicates Voronoi center at infinity
+*/
+#define qh_INFINITE  -10.101
+
+/*----------------------------------
+  
+  qh_DEFAULTbox
+    default box size (Geomview expects 0.5)
+*/
+#define qh_DEFAULTbox 0.5 
+
+/*======= conditional compilation ============================*/
+
+/*----------------------------------
+
+  __cplusplus
+    defined by C++ compilers
+
+  __MSC_VER
+    defined by Microsoft Visual C++
+  
+  __MWERKS__ && __POWERPC__
+    defined by Metrowerks when compiling for the Power Macintosh
+
+  __STDC__
+    defined for strict ANSI C 
+*/
+
+/*----------------------------------
+ 
+  qh_COMPUTEfurthest 
+    compute furthest distance to an outside point instead of storing it with the facet
+    =1 to compute furthest
+  
+  notes:
+    computing furthest saves memory but costs time
+      about 40% more distance tests for partitioning
+      removes facet->furthestdist 
+*/
+#define qh_COMPUTEfurthest 0
+                         
+/*----------------------------------
+ 
+  qh_KEEPstatistics   
+    =0 removes most of statistic gathering and reporting
+
+  notes:
+    if 0, code size is reduced by about 4%.
+*/
+#define qh_KEEPstatistics 1
+                       
+/*----------------------------------
+ 
+  qh_MAXoutside 
+    record outer plane for each facet
+    =1 to record facet->maxoutside
+  
+  notes:
+    this takes a realT per facet and slightly slows down qhull
+    it produces better outer planes for geomview output 
+*/
+#define qh_MAXoutside 1
+
+/*----------------------------------
+ 
+  qh_NOmerge
+    disables facet merging if defined
+    
+  notes:
+    This saves about 10% space.
+    
+    Unless 'Q0'
+      qh_NOmerge sets 'QJ' to avoid precision errors
+
+    #define qh_NOmerge    
+
+  see:
+    qh_NOmem in mem.c
+    
+    see user.c/user_eg.c for removing io.o
+*/  
+    
+/*----------------------------------
+ 
+  qh_NOtrace
+    no tracing if defined 
+  
+  notes:
+    This saves about 5% space.
+
+    #define qh_NOtrace
+*/    
+
+/*----------------------------------
+  
+  qh_QHpointer
+    access global data with pointer or static structure
+
+  qh_QHpointer  = 1     access globals via a pointer to allocated memory
+                        enables qh_saveqhull() and qh_restoreqhull()
+			costs about 8% in time and 2% in space
+
+		= 0     qh_qh and qh_qhstat are static data structures
+		        only one instance of qhull() can be active at a time
+			default value
+
+  notes:
+    all global variables for qhull are in qh, qhmem, and qhstat
+    qh is defined in qhull.h
+    qhmem is defined in mem.h
+    qhstat is defined in stat.h
+
+  see:
+    user_eg.c for an example
+*/
+#define qh_QHpointer 0
+#if 0  /* sample code */
+    qhT *oldqhA, *oldqhB;
+
+    exitcode= qh_new_qhull (dim, numpoints, points, ismalloc,
+                      flags, outfile, errfile); 
+    /* use results from first call to qh_new_qhull */
+    oldqhA= qh_save_qhull();
+    exitcode= qh_new_qhull (dimB, numpointsB, pointsB, ismalloc,
+                      flags, outfile, errfile); 
+    /* use results from second call to qh_new_qhull */
+    oldqhB= qh_save_qhull();
+    qh_restore_qhull (&oldqhA);
+    /* use results from first call to qh_new_qhull */
+    qh_freeqhull (qh_ALL);  /* frees all memory used by first call */
+    qh_restore_qhull (&oldqhB);
+    /* use results from second call to qh_new_qhull */
+    qh_freeqhull (!qh_ALL); /* frees long memory used by second call */
+    qh_memfreeshort (&curlong, &totlong);  /* frees short memory and memory allocator */
+#endif
+
+/*----------------------------------
+ 
+  qh_QUICKhelp        
+    =1 to use abbreviated help messages, e.g., for degenerate inputs
+*/
+#define qh_QUICKhelp    0  
+
+/* ============ -merge constants- ====================
+
+   These constants effect facet merging.  You probably will not need
+   to modify these.  They effect the performance of facet merging.
+*/
+
+/*----------------------------------
+  
+  qh_DIMmergeVertex
+    max dimension for vertex merging (it is not effective in high-d)
+*/
+#define qh_DIMmergeVertex 6
+
+/*----------------------------------
+  
+  qh_DIMreduceBuild
+     max dimension for vertex reduction during build (slow in high-d)
+*/
+#define qh_DIMreduceBuild 5
+
+/*----------------------------------
+     
+  qh_BESTcentrum
+     if > 2*dim+n vertices, qh_findbestneighbor() tests centrums (faster)
+     else, qh_findbestneighbor() tests all vertices (much better merges)
+
+  qh_BESTcentrum2
+     if qh_BESTcentrum2 * DIM3 + BESTcentrum < #vertices tests centrums
+*/
+#define qh_BESTcentrum 20
+#define qh_BESTcentrum2 2
+
+/*----------------------------------
+  
+  qh_BESTnonconvex
+    if > dim+n neighbors, qh_findbestneighbor() tests nonconvex ridges.
+    
+  notes:
+    It is needed because qh_findbestneighbor is slow for large facets
+*/
+#define qh_BESTnonconvex 15 
+
+/*----------------------------------
+  
+  qh_MAXnewmerges
+    if >n newmerges, qh_merge_nonconvex() calls qh_reducevertices_centrums.
+     
+  notes:
+    It is needed because postmerge can merge many facets at once
+*/
+#define qh_MAXnewmerges 2
+
+/*----------------------------------
+  
+  qh_MAXnewcentrum
+    if <= dim+n vertices (n approximates the number of merges),
+      reset the centrum in qh_updatetested() and qh_mergecycle_facets()
+    
+  notes:
+    needed to reduce cost and because centrums may move too much if 
+    many vertices in high-d
+*/
+#define qh_MAXnewcentrum 5
+
+/*----------------------------------
+  
+  qh_COPLANARratio
+    for 3-d+ merging, qh.MINvisible is n*premerge_centrum
+
+  notes:
+    for non-merging, it's DISTround
+*/
+#define qh_COPLANARratio 3
+
+/*----------------------------------
+  
+  qh_DISToutside
+    When is a point clearly outside of a facet?  
+    Stops search in qh_findbestnew or qh_partitionall
+    qh_findbest uses qh.MINoutside since since it is only called if no merges.
+     
+  notes:
+    'Qf' always searches for best facet
+    if !qh.MERGING, same as qh.MINoutside. 
+    if qh_USEfindbestnew, increase value since neighboring facets may be ill-behaved
+      [Note: Zdelvertextot occurs normally with interior points]
+            RBOX 1000 s Z1 G1e-13 t1001188774 | QHULL Tv
+    When there is a sharp edge, need to move points to a
+    clearly good facet; otherwise may be lost in another partitioning.
+    if too big then O(n^2) behavior for partitioning in cone
+    if very small then important points not processed
+    Needed in qh_partitionall for
+      RBOX 1000 s Z1 G1e-13 t1001032651 | QHULL Tv
+    Needed in qh_findbestnew for many instances of
+      RBOX 1000 s Z1 G1e-13 t | QHULL Tv
+
+  See:  
+    qh_DISToutside -- when is a point clearly outside of a facet
+    qh_SEARCHdist -- when is facet coplanar with the best facet?
+    qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint()
+*/
+#define qh_DISToutside ((qh_USEfindbestnew ? 2 : 1) * \
+     fmax_((qh MERGING ? 2 : 1)*qh MINoutside, qh max_outside))
+
+/*----------------------------------
+  
+  qh_RATIOnearinside
+    ratio of qh.NEARinside to qh.ONEmerge for retaining inside points for
+    qh_check_maxout().  
+  
+  notes:
+    This is overkill since do not know the correct value.
+    It effects whether 'Qc' reports all coplanar points
+    Not used for 'd' since non-extreme points are coplanar
+*/
+#define qh_RATIOnearinside 5
+
+/*----------------------------------
+  
+  qh_SEARCHdist
+    When is a facet coplanar with the best facet?  
+    qh_findbesthorizon: all coplanar facets of the best facet need to be searched.
+
+  See:
+    qh_DISToutside -- when is a point clearly outside of a facet
+    qh_SEARCHdist -- when is facet coplanar with the best facet?
+    qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint()
+*/
+#define qh_SEARCHdist ((qh_USEfindbestnew ? 2 : 1) * \
+      (qh max_outside + 2 * qh DISTround + fmax_( qh MINvisible, qh MAXcoplanar)));
+
+/*----------------------------------
+  
+  qh_USEfindbestnew
+     Always use qh_findbestnew for qh_partitionpoint, otherwise use
+     qh_findbestnew if merged new facet or sharpnewfacets.
+  
+  See:
+    qh_DISToutside -- when is a point clearly outside of a facet
+    qh_SEARCHdist -- when is facet coplanar with the best facet?
+    qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint()
+*/
+#define qh_USEfindbestnew (zzval_(Ztotmerge) > 50)
+
+/*----------------------------------
+  
+  qh_WIDEcoplanar
+    n*MAXcoplanar or n*MINvisible for a WIDEfacet 
+    
+    if vertex is further than qh.WIDEfacet from the hyperplane
+    then its ridges are not counted in computing the area, and
+    the facet's centrum is frozen. 
+    
+  notes:
+   qh.WIDEfacet= max(qh.MAXoutside,qh_WIDEcoplanar*qh.MAXcoplanar,
+      qh_WIDEcoplanar * qh.MINvisible);
+*/
+#define qh_WIDEcoplanar 6
+
+/*----------------------------------
+  
+  qh_MAXnarrow
+    max. cosine in initial hull that sets qh.NARROWhull
+       
+  notes:
+    If qh.NARROWhull, the initial partition does not make 
+    coplanar points.  If narrow, a coplanar point can be 
+    coplanar to two facets of opposite orientations and
+    distant from the exact convex hull.
+
+    Conservative estimate.  Don't actually see problems until it is -1.0
+*/
+#define qh_MAXnarrow -0.99999999
+
+/*----------------------------------
+  
+  qh_WARNnarrow
+    max. cosine in initial hull to warn about qh.NARROWhull
+      
+  notes:
+    this is a conservative estimate.  
+    Don't actually see problems until it is -1.0.  See qh-impre.htm
+*/
+#define qh_WARNnarrow -0.999999999999999
+
+/*----------------------------------
+  
+  qh_ZEROdelaunay
+    a zero Delaunay facet occurs for input sites coplanar with their convex hull
+    the last normal coefficient of a zero Delaunay facet is within
+        qh_ZEROdelaunay * qh.ANGLEround of 0
+      
+  notes:
+    qh_ZEROdelaunay does not allow for joggled input ('QJ').
+
+    You can avoid zero Delaunay facets by surrounding the input with a box.
+
+    Use option 'PDk:-n' to explicitly define zero Delaunay facets
+      k= dimension of input sites (e.g., 3 for 3-d Delaunay triangulation)
+      n= the cutoff for zero Delaunay facets (e.g., 'PD3:-1e-12')
+*/
+#define qh_ZEROdelaunay 2
+
+#endif /* qh_DEFuser */
+
+
+
diff --git a/extern/qhull/make/msvc_7_0/qhull.vcproj b/extern/qhull/make/msvc_7_0/qhull.vcproj
new file mode 100644
index 00000000000..1b754d8e076
--- /dev/null
+++ b/extern/qhull/make/msvc_7_0/qhull.vcproj
@@ -0,0 +1,677 @@
+
+
+	
+		
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+	
+		
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+
diff --git a/extern/qhull/src/Make-config.sh b/extern/qhull/src/Make-config.sh
new file mode 100755
index 00000000000..90bbb958599
--- /dev/null
+++ b/extern/qhull/src/Make-config.sh
@@ -0,0 +1,285 @@
+#!/bin/sh -e
+#
+# Make-config.sh
+#
+#     Setup for Debian build
+#
+#     Writes configure.in and Makefile.am files
+#     and runs automake and autoconfig
+#
+#     Use 'make dist' to build Unix distribution.
+#     Use 'configure; make' to build Qhull
+#
+#note:
+#     'configure; make' does not work under cygwin.
+#	src/unix.c:354: variable 'qh_qh' can't be auto-imported.
+#	Please read the documentation for ld's --enable-auto-import for details.
+
+###################################################
+###########  ../configure.in ######################
+###################################################
+
+echo Create ../configure.in
+cat >../configure.in <<\HERE-CONFIGURE
+dnl configure.in for the qhull package
+dnl Author: Rafael Laboissiere 
+dnl Created: Mon Dec  3 21:36:21 CET 2001
+
+AC_INIT(src/qhull.c)
+AM_INIT_AUTOMAKE(qhull, 2002.1)
+
+AC_PROG_CC
+AC_PROG_LIBTOOL
+
+AC_OUTPUT([Makefile src/Makefile html/Makefile eg/Makefile])
+
+HERE-CONFIGURE
+
+###################################################
+###########  ../Makefile.am #######################
+###################################################
+
+echo Create ../Makefile.am
+cat >../Makefile.am <<\HERE-TOP
+### Makefile.am for the qhull package (main)
+### Author: Rafael Laboissiere 
+### Created: Mon Dec  3 21:36:21 CET 2001
+
+### Documentation files
+
+# to:
+docdir = $(prefix)/share/doc/$(PACKAGE)
+
+# which:
+doc_DATA = \
+  Announce.txt \
+  COPYING.txt \
+  README.txt \
+  REGISTER.txt
+
+### Extra files to be included in the tarball
+
+EXTRA_DIST = \
+  $(doc_DATA) \
+  File_id.diz \
+  QHULL-GO.pif
+
+### Subdirectories for Automaking
+
+SUBDIRS = src html eg
+
+HERE-TOP
+
+###################################################
+###########  ../eg/Makefile.am ####################
+###################################################
+
+echo Create ../eg/Makefile.am
+cat >../eg/Makefile.am <<\HERE-AM
+### Makefile.am for the qhull package (eg)
+### Author: Rafael Laboissiere 
+### Created: Mon Dec  3 21:36:21 CET 2001
+
+### Documentation files
+
+# to:
+docdir = $(prefix)/share/doc/$(PACKAGE)
+examplesdir = $(docdir)/examples
+
+# which:
+examples_DATA = \
+  q_eg \
+  q_egtest \
+  q_test \
+  Qhull-go.bat \
+  q_test.bat
+
+### Extra files to be included in the tarball
+
+EXTRA_DIST = $(examples_DATA)
+
+HERE-AM
+
+###################################################
+###########  ../html/Makefile.am ##################
+###################################################
+
+echo Create ../html/Makefile.am
+cat >../html/Makefile.am <<\HERE-HTML
+### Makefile.am for the qhull package (html)
+### Author: Rafael Laboissiere 
+### Created: Mon Dec  3 21:36:21 CET 2001
+
+### Man pages (trick to get around .man extension)
+
+%.1: %.man
+	cp $< $@
+CLEANFILES = *.1
+man_MANS = rbox.1 qhull.1
+
+### Documentation files
+
+# to:
+docdir = $(prefix)/share/doc/$(PACKAGE)
+htmldir = $(docdir)/html
+
+# which:
+html_DATA = \
+  index.htm \
+  qconvex.htm \
+  qdelau_f.htm \
+  qdelaun.htm \
+  qh--4d.gif \
+  qh--cone.gif \
+  qh--dt.gif \
+  qh--geom.gif \
+  qh--half.gif \
+  qh--rand.gif \
+  qh-eg.htm \
+  qh-faq.htm \
+  qh-get.htm \
+  qh-home.htm \
+  qh-impre.htm \
+  qh-in.htm \
+  qh-optc.htm \
+  qh-optf.htm \
+  qh-optg.htm \
+  qh-opto.htm \
+  qh-optp.htm \
+  qh-optq.htm \
+  qh-optt.htm \
+  qh-quick.htm \
+  qhalf.htm \
+  qhull.htm \
+  qvoron_f.htm \
+  qvoronoi.htm \
+  rbox.htm
+
+### Extra files to be included in the tarball
+
+EXTRA_DIST = \
+  $(html_DATA) \
+  qhull.man \
+  qhull.txt \
+  rbox.man \
+  rbox.txt
+
+HERE-HTML
+
+###################################################
+###########  ../src/Makefile.am ###################
+###################################################
+
+echo Create ../src/Makefile.am
+cat >../src/Makefile.am <<\HERE-SRC
+### Makefile.am for the qhull package (src)
+### Author: Rafael Laboissiere 
+### Created: Mon Dec  3 21:36:21 CET 2001
+
+### Shared Library
+
+# to:
+lib_LTLIBRARIES = libqhull.la
+
+# from:
+libqhull_la_SOURCES = \
+  user.c \
+  global.c \
+  stat.c \
+  io.c \
+  geom2.c \
+  poly2.c \
+  merge.c \
+  qhull.c \
+  geom.c \
+  poly.c \
+  qset.c \
+  mem.c
+
+# how:
+libqhull_la_LDFLAGS = -version-info 0:0:0 -lm
+
+### Utility programs
+
+# to:
+bin_PROGRAMS = qhull rbox qconvex qdelaunay qvoronoi qhalf
+
+# from:
+qhull_SOURCES = unix.c
+rbox_SOURCES = rbox.c
+qconvex_SOURCES = qconvex.c
+qdelaunay_SOURCES = qdelaun.c
+qvoronoi_SOURCES = qvoronoi.c
+qhalf_SOURCES = qhalf.c
+
+# how:
+qhull_LDADD = libqhull.la
+rbox_LDADD = libqhull.la
+qconvex_LDADD = libqhull.la
+qdelaunay_LDADD = libqhull.la
+qvoronoi_LDADD = libqhull.la
+qhalf_LDADD = libqhull.la
+
+### Include files
+
+pkginclude_HEADERS = \
+  geom.h \
+  mem.h \
+  poly.h \
+  qhull_a.h \
+  stat.h \
+  io.h \
+  merge.h \
+  qhull.h  \
+  qset.h \
+  user.h
+
+
+### Example programs
+
+# to:
+docdir = $(prefix)/share/doc/$(PACKAGE)
+examplesdir = $(docdir)/examples
+
+# which:
+examples_DATA = \
+  user_eg.c \
+  user_eg2.c \
+  qhull_interface.cpp \
+  Makefile.txt \
+  Make-config.sh \
+  MBorland
+
+doc_DATA = Changes.txt \
+    index.htm \
+    qh-geom.htm \
+    qh-globa.htm \
+    qh-io.htm \
+    qh-mem.htm \
+    qh-merge.htm \
+    qh-poly.htm \
+    qh-qhull.htm \
+    qh-set.htm \
+    qh-stat.htm \
+    qh-user.htm
+
+
+### Extra files to be included in the tarball
+
+EXTRA_DIST = \
+  $(doc_DATA) \
+  $(examples_DATA)
+
+HERE-SRC
+
+###################################################
+###########  run automake autoconf ################
+###################################################
+
+
+echo Run automake, libtoolize, and autoconf
+cd ..; aclocal &&\
+  automake --foreign --add-missing --force-missing && \
+  libtoolize --force && \
+  autoconf
+
diff --git a/extern/qhull/src/Makefile b/extern/qhull/src/Makefile
new file mode 100644
index 00000000000..a4f2aa4b5b9
--- /dev/null
+++ b/extern/qhull/src/Makefile
@@ -0,0 +1,59 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# 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. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License.  See http://www.blender.org/BL/ for information
+# about this.
+#
+# 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.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = qhull
+DIR = $(OCGDIR)/extern/$(LIBNAME)
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I../include
+
+CSRCS = user.c global.c stat.c io.c geom2.c poly2.c \
+       merge.c qhull.c geom.c poly.c qset.c mem.c
+CCSRCS = 
+include nan_compile.mk 
+
+install: all debug
+	@[ -d $(NAN_QHULL) ] || mkdir -p $(NAN_QHULL)
+	@[ -d $(NAN_QHULL)/include/qhull ] || mkdir -p $(NAN_QHULL)/include/qhull
+	@[ -d $(NAN_QHULL)/lib ] || mkdir -p $(NAN_QHULL)/lib
+	@[ -d $(NAN_QHULL)/lib/debug ] || mkdir -p $(NAN_QHULL)/lib/debug
+	@$(NANBLENDERHOME)/intern/tools/cpifdiff.sh $(DIR)/lib$(LIBNAME).a $(NAN_QHULL)/lib/
+#	@$(NANBLENDERHOME)/intern/tools/cpifdiff.sh $(DIR)/debug/lib$(LIBNAME).a $(NAN_QHULL)/lib/debug/
+ifeq ($(OS),darwin)
+	ranlib $(NAN_QHULL)/lib/lib$(LIBNAME).a
+#	ranlib $(NAN_QHULL)/lib/debug/lib$(LIBNAME).a
+endif
+	@$(NANBLENDERHOME)/intern/tools/cpifdiff.sh ../include/qhull/*.h $(NAN_QHULL)/include/qhull
+
+
diff --git a/extern/qhull/src/Makefile.txt b/extern/qhull/src/Makefile.txt
new file mode 100644
index 00000000000..e87b66b49bc
--- /dev/null
+++ b/extern/qhull/src/Makefile.txt
@@ -0,0 +1,190 @@
+# Unix Makefile for qhull and rbox
+#
+#       see README.txt
+#
+#       make           to produce qhull qconvex qdelaunay qhalf qvoronoi rbox
+#       make qvoronoi  to produce qvoronoi (etc.)
+#       make qhullx    to produce qhull qconvex etc.  w/o using libqhull.a
+#       make doc       to print documentation
+#       make install   to copy qhull, rbox, qhull.1, rbox.1 to BINDIR, MANDIR
+#       make new       to rebuild qhull and rbox from source
+#
+#       make printall  to print all files
+#       make user_eg   to produce user_eg
+#       make user_eg2  to produce user_eg2
+#       make clean     to remove object files and core
+#       make cleanall  to remove all generated files
+#
+#       PRINTMAN --  command for printing manual pages
+#       PRINTC --  command for printing C files
+#       BINDIR -- directory where to copy executables
+#       MANDIR -- directory where to copy manual pages
+#       CC --     ANSI C or C++ compiler
+#       CCOPTS1 - options used to compile .c files
+#       CCOPTS2 -- options used to link .o files
+#
+#       CFILES -- .c files for printing
+#       HFILES -- .h files for printing
+#       DFILES -- documentation files
+#       MFILES -- man pages and html files
+#       TFILES -- .txt versions of html html files
+#       FILES -- all other files
+#       OBJS -- specifies the object files of libqhull.a
+#
+BINDIR  = /usr/local/bin
+MANDIR  = /usr/local/man/man1
+
+# if you do not have enscript, try a2ps or just use lpr.  The files are text.
+PRINTMAN = enscript -2rl
+PRINTC = enscript -2r
+# PRINTMAN = lpr
+# PRINTC = lpr
+
+#for Gnu's gcc compiler -O2 for optimization, -g for debugging, -Wall for check
+#
+CC     = gcc
+CCOPTS1 = -O2 -ansi 
+
+# for Sun's cc compiler, -fast or O2 for optimization, -g for debugging, -Xc for ANSI
+#CC = cc
+#CCOPTS1 = -Xc -v -fast
+
+# for Silicon Graphics cc compiler, -O2 for optimization, -g for debugging
+#CC = cc
+#CCOPTS1 = -ansi -O2
+
+# for Next cc compiler with fat executable
+#CC = cc
+#CCOPTS1 = -ansi -O2 -arch m68k -arch i386 -arch hppa
+
+# for loader, ld
+CCOPTS2 = $(CCOPTS1)
+
+# OBJS in execution frequency order.  CFILES after qhull.c are alphabetical
+OBJS = user.o global.o stat.o io.o geom2.o poly2.o \
+       merge.o qhull.o geom.o poly.o qset.o mem.o
+
+CFILES= unix.c qhull.c geom.c geom2.c global.c io.c mem.c merge.c poly.c \
+        poly2.c qset.c stat.c user.c qconvex.c qdelaun.c qhalf.c qvoronoi.c
+HFILES= user.h qhull.h qhull_a.h geom.h io.h mem.h merge.h poly.h qset.h stat.h
+TXTFILES= ../Announce.txt ../REGISTER.txt ../COPYING.txt ../README.txt Changes.txt
+DOCFILES= ../html/rbox.txt ../html/qhull.txt
+FILES=  Makefile rbox.c user_eg.c ../eg/q_test ../eg/q_egtest ../eg/q_eg
+HTMFILES= qhull.man rbox.man qh-in.htm qh-optg.htm qh-optt.htm qh-optp.htm \
+        index.htm qh-quick.htm qh-impre.htm qh-eg.htm \
+        qh-optc.htm qh-opto.htm qh-optf.htm qh-optq.htm \
+	    qh-c.htm qh-faq.htm qhull.htm qconvex.htm qdelaun.htm \
+		qh-geom.htm qh-globa.htm qh-io.htm qh-mem.htm qh-merge.htm \
+		qh-poly.htm qh-qhull.htm qh-set.htm qh-stat.htm qh-user.htm \
+		qdelau_f.htm qhalf.htm qvoronoi.htm qvoron_f.htm rbox.htm 
+
+all: rbox qconvex qdelaunay qhalf qvoronoi qhull
+
+unix.o:   qhull.h user.h mem.h
+qconvex.o:   qhull.h user.h mem.h
+qdelaun.o:   qhull.h user.h mem.h
+qhalf.o:   qhull.h user.h mem.h
+qvoronoi.o:   qhull.h user.h mem.h
+qhull.o:  $(HFILES)
+geom.o:   $(HFILES)
+geom2.o:  $(HFILES)
+global.o: $(HFILES)
+io.o:     $(HFILES)
+mem.o:    mem.h 
+merge.o:  $(HFILES)
+poly.o:   $(HFILES)
+poly2.o:  $(HFILES)
+qset.o:   qset.h mem.h 
+stat.o:   $(HFILES)
+user.o:   $(HFILES)
+
+.c.o:
+	$(CC) -c $(CCOPTS1) $<
+
+clean:
+	rm -f *.o ../core qconvex qdelaunay qhalf qvoronoi qhull libqhull.a \
+	    *.exe
+
+cleanall: clean
+	rm -f *~ ../rbox ../qhull ../qhalf ../qconvex ../qdelaunay ../qhalf\
+	   ../qvoronoi ../user_eg ../user_eg2 ../*.exe >/dev/null
+
+doc: 
+	$(PRINTMAN) $(TXTFILES) $(DOCFILES)
+
+install: all 
+	cp ../qconvex $(BINDIR)/qconvex
+	cp ../qdelaunay $(BINDIR)/qdelaunay
+	cp ../qhalf $(BINDIR)/qhalf
+	cp ../qhull $(BINDIR)/qhull
+	cp ../qvoronoi $(BINDIR)/qvoronoi
+	cp ../rbox $(BINDIR)/rbox
+	cp ../html/qhull.man $(MANDIR)/qhull.1
+	cp ../html/rbox.man $(MANDIR)/rbox.1
+
+new:    cleanall all
+
+printall: doc printh printc printf
+
+printh:
+	$(PRINTC) $(HFILES)
+
+printc:
+	$(PRINTC) $(CFILES)
+
+printf:
+	$(PRINTC) $(FILES) 
+
+libqhull.a: $(OBJS)
+	@echo if 'ar' or 'ranlib' fails, try 'make qhullx'
+	ar r libqhull.a $(OBJS)
+	@echo the next line may need to be removed.
+	-test -x /bin/ranlib -o -x /usr/bin/ranlib && ranlib libqhull.a
+
+# don't use ../qconvex.  Does not work on Red Hat Linux
+qconvex: qconvex.o libqhull.a
+	$(CC) -o qconvex $(CCOPTS2) qconvex.o -L. -lqhull -lm 
+	cp qconvex ..
+
+qdelaunay: qdelaun.o libqhull.a
+	$(CC) -o qdelaunay $(CCOPTS2) qdelaun.o -L. -lqhull -lm 
+	cp qdelaunay ..
+
+qhalf: qhalf.o libqhull.a
+	$(CC) -o qhalf $(CCOPTS2) qhalf.o -L. -lqhull -lm 
+	cp qhalf ..
+
+qvoronoi: qvoronoi.o libqhull.a
+	$(CC) -o qvoronoi $(CCOPTS2) qvoronoi.o -L. -lqhull -lm 
+	cp qvoronoi ..
+
+qhull: unix.o libqhull.a
+	$(CC) -o qhull $(CCOPTS2) unix.o -L. -lqhull -lm 
+	cp qhull ..
+	-chmod +x ../eg/q_test ../eg/q_eg ../eg/q_egtest
+	-cd ..; ./rbox D4 | ./qhull
+
+# compile qhull without using libqhull.a
+qhullx: qconvex.o qdelaun.o qhalf.o qvoronoi.o unix.o $(OBJS)
+	$(CC) -o qconvex $(CCOPTS2) qconvex.o $(OBJS) -lm 
+	$(CC) -o qdelaunay $(CCOPTS2) qdelaun.o $(OBJS) -lm 
+	$(CC) -o qhalf $(CCOPTS2) qhalf.o $(OBJS) -lm 
+	$(CC) -o qvoronoi $(CCOPTS2) qvoronoi.o $(OBJS) -lm 
+	$(CC) -o qhull $(CCOPTS2) unix.o $(OBJS) -lm 
+	cp qconvex qdelaunay qhalf qvoronoi qhull ..
+	-chmod +x ../eg/q_test ../eg/q_eg ../eg/q_egtest
+	-cd ..; ./rbox D4 | ./qhull
+
+rbox: rbox.o
+	$(CC) -o rbox rbox.o $(CCOPTS2) -lm
+	cp rbox ..
+
+user_eg: user_eg.o libqhull.a 
+	$(CC)  -o user_eg $(CCOPTS2) user_eg.o  -L. -lqhull -lm 
+	cp user_eg ..
+
+user_eg2: user_eg2.o libqhull.a 
+	$(CC)  -o user_eg2 $(CCOPTS2) user_eg2.o  -L. -lqhull -lm 
+	cp user_eg2 ..
+
+# end of Makefile
diff --git a/extern/qhull/src/geom.c b/extern/qhull/src/geom.c
new file mode 100644
index 00000000000..ca4bcaf2541
--- /dev/null
+++ b/extern/qhull/src/geom.c
@@ -0,0 +1,1230 @@
+/*
  ---------------------------------
+
+   geom.c 
+   geometric routines of qhull
+
+   see qh-geom.htm and geom.h
+
+   copyright (c) 1993-2002 The Geometry Center        
+
+   infrequent code goes into geom2.c
+*/
+   
+#include "qhull_a.h"
+   
+/*---------------------------------
+  
+  qh_distplane( point, facet, dist )
+    return distance from point to facet
+
+  returns:
+    dist
+    if qh.RANDOMdist, joggles result
+  
+  notes:  
+    dist > 0 if point is above facet (i.e., outside)
+    does not error (for sortfacets)
+    
+  see:
+    qh_distnorm in geom2.c
+*/
+void qh_distplane (pointT *point, facetT *facet, realT *dist) {
+  coordT *normal= facet->normal, *coordp, randr;
+  int k;
+  
+  switch(qh hull_dim){
+  case 2:
+    *dist= facet->offset + point[0] * normal[0] + point[1] * normal[1];
+    break;
+  case 3:
+    *dist= facet->offset + point[0] * normal[0] + point[1] * normal[1] + point[2] * normal[2];
+    break;
+  case 4:
+    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3];
+    break;
+  case 5:
+    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4];
+    break;
+  case 6:
+    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5];
+    break;
+  case 7:  
+    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6];
+    break;
+  case 8:
+    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6]+point[7]*normal[7];
+    break;
+  default:
+    *dist= facet->offset;
+    coordp= point;
+    for (k= qh hull_dim; k--; )
+      *dist += *coordp++ * *normal++;
+    break;
+  }
+  zinc_(Zdistplane);
+  if (!qh RANDOMdist && qh IStracing < 4)
+    return;
+  if (qh RANDOMdist) {
+    randr= qh_RANDOMint;
+    *dist += (2.0 * randr / qh_RANDOMmax - 1.0) *
+      qh RANDOMfactor * qh MAXabs_coord;
+  }
+  if (qh IStracing >= 4) {
+    fprintf (qh ferr, "qh_distplane: ");
+    fprintf (qh ferr, qh_REAL_1, *dist);
+    fprintf (qh ferr, "from p%d to f%d\n", qh_pointid(point), facet->id);
+  }
+  return;
+} /* distplane */
+
+
+/*---------------------------------
+  
+  qh_findbest( point, startfacet, bestoutside, qh_ISnewfacets, qh_NOupper, dist, isoutside, numpart )
+    find facet that is furthest below a point 
+    for upperDelaunay facets
+      returns facet only if !qh_NOupper and clearly above
+
+  input:
+    starts search at 'startfacet' (can not be flipped)
+    if !bestoutside (qh_ALL), stops at qh.MINoutside
+
+  returns:
+    best facet (reports error if NULL)
+    early out if isoutside defined and bestdist > qh.MINoutside
+    dist is distance to facet
+    isoutside is true if point is outside of facet
+    numpart counts the number of distance tests
+
+  see also:
+    qh_findbestnew()
+    
+  notes:
+    If merging (testhorizon), searches horizon facets of coplanar best facets because
+    after qh_distplane, this and qh_partitionpoint are the most expensive in 3-d
+      avoid calls to distplane, function calls, and real number operations.
+    caller traces result
+    Optimized for outside points.   Tried recording a search set for qh_findhorizon.
+    Made code more complicated.
+
+  when called by qh_partitionvisible():
+    indicated by qh_ISnewfacets
+    qh.newfacet_list is list of simplicial, new facets
+    qh_findbestnew set if qh_sharpnewfacets returns True (to use qh_findbestnew)
+    qh.bestfacet_notsharp set if qh_sharpnewfacets returns False
+
+  when called by qh_findfacet(), qh_partitionpoint(), qh_partitioncoplanar(), 
+                 qh_check_bestdist(), qh_addpoint()
+    indicated by !qh_ISnewfacets
+    returns best facet in neighborhood of given facet
+      this is best facet overall if dist > -   qh.MAXcoplanar 
+        or hull has at least a "spherical" curvature
+
+  design:
+    initialize and test for early exit
+    repeat while there are better facets
+      for each neighbor of facet
+        exit if outside facet found
+	test for better facet
+    if point is inside and partitioning
+      test for new facets with a "sharp" intersection
+      if so, future calls go to qh_findbestnew()
+    test horizon facets
+*/
+facetT *qh_findbest (pointT *point, facetT *startfacet, 
+		     boolT bestoutside, boolT isnewfacets, boolT noupper,
+		     realT *dist, boolT *isoutside, int *numpart) {
+  realT bestdist= -REALmax/2 /* avoid underflow */;
+  facetT *facet, *neighbor, **neighborp, *bestfacet= NULL;
+ /* facetT *bestfacet_all= startfacet; */
+  int oldtrace= qh IStracing;
+  unsigned int visitid= ++qh visit_id;
+  int numpartnew=0;
+  boolT testhorizon = True; /* needed if precise, e.g., rbox c D6 | qhull Q0 Tv */
+
+  zinc_(Zfindbest);
+  if (qh IStracing >= 3 || (qh TRACElevel && qh TRACEpoint >= 0 && qh TRACEpoint == qh_pointid (point))) {
+    if (qh TRACElevel > qh IStracing)
+      qh IStracing= qh TRACElevel;
+    fprintf (qh ferr, "qh_findbest: point p%d starting at f%d isnewfacets? %d, unless %d exit if > %2.2g\n",
+	     qh_pointid(point), startfacet->id, isnewfacets, bestoutside, qh MINoutside);
+    fprintf(qh ferr, "  testhorizon? %d noupper? %d", testhorizon, noupper);
+    fprintf (qh ferr, "  Last point added was p%d.", qh furthest_id);
+    fprintf(qh ferr, "  Last merge was #%d.  max_outside %2.2g\n", zzval_(Ztotmerge), qh max_outside);
+  }
+  if (isoutside)
+    *isoutside= True;
+  if (!startfacet->flipped) {  /* test startfacet */
+    *numpart= 1;
+    qh_distplane (point, startfacet, dist);  /* this code is duplicated below */
+    if (!bestoutside && *dist >= qh MINoutside 
+    && (!startfacet->upperdelaunay || !noupper)) {
+      bestfacet= startfacet;
+      goto LABELreturn_best;
+    }
+    bestdist= *dist;
+    if (!startfacet->upperdelaunay) {
+      bestfacet= startfacet;
+    } 
+  }else 
+    *numpart= 0;
+  startfacet->visitid= visitid;
+  facet= startfacet;
+  while (facet) {
+    trace4((qh ferr, "qh_findbest: neighbors of f%d, bestdist %2.2g f%d\n", 
+                facet->id, bestdist, getid_(bestfacet)));
+    FOREACHneighbor_(facet) {
+      if (!neighbor->newfacet && isnewfacets)
+        continue;
+      if (neighbor->visitid == visitid)
+	continue;
+      neighbor->visitid= visitid;
+      if (!neighbor->flipped) {  /* code duplicated above */
+	(*numpart)++;
+	qh_distplane (point, neighbor, dist);
+	if (*dist > bestdist) {
+	  if (!bestoutside && *dist >= qh MINoutside 
+	  && (!neighbor->upperdelaunay || !noupper)) {
+	    bestfacet= neighbor;
+	    goto LABELreturn_best;
+	  }
+	  if (!neighbor->upperdelaunay) {
+	    bestfacet= neighbor;
+	    bestdist= *dist;
+	  }
+	  break; /* switch to neighor */
+	} /* end of *dist>bestdist */
+      } /* end of !flipped */
+    } /* end of FOREACHneighbor */
+    facet= neighbor;  /* non-NULL only if *dist>bestdist */
+  } /* end of while facet (directed search) */
+  if (isnewfacets) { 
+    if (!bestfacet) {
+      bestdist= -REALmax/2; 
+      bestfacet= qh_findbestnew (point, startfacet->next, &bestdist, bestoutside, isoutside, &numpartnew);
+      testhorizon= False; /* qh_findbestnew calls qh_findbesthorizon */
+    }else if (!qh findbest_notsharp && bestdist < - qh DISTround) {
+      if (qh_sharpnewfacets()) { 
+	/* seldom used, qh_findbestnew will retest all facets */
+	zinc_(Zfindnewsharp);
+	bestfacet= qh_findbestnew (point, bestfacet, &bestdist, bestoutside, isoutside, &numpartnew);
+	testhorizon= False; /* qh_findbestnew calls qh_findbesthorizon */
+	qh findbestnew= True;
+      }else
+	qh findbest_notsharp= True;
+    }
+  }
+  if (!bestfacet) {
+    fprintf(qh ferr, "\n\
+qh_findbest: all neighbors of facet %d are flipped or upper Delaunay.\n\
+Please report this error to qhull_bug@geom.umn.edu with the input and all of the output.\n",
+       startfacet->id);
+    qh_errexit (qh_ERRqhull, startfacet, NULL);
+  }
+  if (testhorizon) 
+    bestfacet= qh_findbesthorizon (!qh_IScheckmax, point, bestfacet, noupper, &bestdist, &numpartnew);
+  *dist= bestdist;
+  if (isoutside && bestdist < qh MINoutside)
+    *isoutside= False;
+LABELreturn_best:
+  zadd_(Zfindbesttot, *numpart);
+  zmax_(Zfindbestmax, *numpart);
+  (*numpart) += numpartnew;
+  qh IStracing= oldtrace;
+  return bestfacet;
+}  /* findbest */
+
+
+/*---------------------------------
+  
+  qh_findbesthorizon( qh_IScheckmax, point, startfacet, qh_NOupper, &bestdist, &numpart )
+    search coplanar and better horizon facets from startfacet/bestdist
+    ischeckmax turns off statistics and minsearch update
+    all arguments must be initialized
+  returns (ischeckmax):
+    best facet
+  returns (!ischeckmax):
+    best facet that is not upperdelaunay
+    allows upperdelaunay that is clearly outside
+  returns:
+    bestdist is distance to bestfacet
+    numpart -- updates number of distance tests
+
+  notes:
+    no early out -- use qh_findbest() or qh_findbestnew()
+    Searches coplanar or better horizon facets
+
+  when called by qh_check_maxout() (qh_IScheckmax)
+    startfacet must be closest to the point
+      Otherwise, if point is beyond and below startfacet, startfacet may be a local minimum
+      even though other facets are below the point.
+    updates facet->maxoutside for good, visited facets
+    may return NULL
+
+    searchdist is qh.max_outside + 2 * DISTround
+      + max( MINvisible('Vn'), MAXcoplanar('Un'));
+    This setting is a guess.  It must be at least max_outside + 2*DISTround 
+    because a facet may have a geometric neighbor across a vertex
+
+  design:
+    for each horizon facet of coplanar best facets
+      continue if clearly inside
+      unless upperdelaunay or clearly outside
+         update best facet
+*/
+facetT *qh_findbesthorizon (boolT ischeckmax, pointT* point, facetT *startfacet, boolT noupper, realT *bestdist, int *numpart) {
+  facetT *bestfacet= startfacet;
+  realT dist;
+  facetT *neighbor, **neighborp, *facet;
+  facetT *nextfacet= NULL; /* optimize last facet of coplanarset */
+  int numpartinit= *numpart, coplanarset_size;
+  unsigned int visitid= ++qh visit_id;
+  boolT newbest= False; /* for tracing */
+  realT minsearch, searchdist;  /* skip facets that are too far from point */
+
+  if (!ischeckmax) {
+    zinc_(Zfindhorizon);
+  }else {
+#if qh_MAXoutside
+    if ((!qh ONLYgood || startfacet->good) && *bestdist > startfacet->maxoutside)
+      startfacet->maxoutside= *bestdist;
+#endif
+  }
+  searchdist= qh_SEARCHdist; /* multiple of qh.max_outside and precision constants */
+  minsearch= *bestdist - searchdist;
+  if (ischeckmax) {
+    /* Always check coplanar facets.  Needed for RBOX 1000 s Z1 G1e-13 t996564279 | QHULL Tv */
+    minimize_(minsearch, -searchdist);
+  }
+  coplanarset_size= 0;
+  facet= startfacet;
+  while (True) {
+    trace4((qh ferr, "qh_findbesthorizon: neighbors of f%d bestdist %2.2g f%d ischeckmax? %d noupper? %d minsearch %2.2g searchdist %2.2g\n", 
+		facet->id, *bestdist, getid_(bestfacet), ischeckmax, noupper,
+		minsearch, searchdist));
+    FOREACHneighbor_(facet) {
+      if (neighbor->visitid == visitid) 
+	continue;
+      neighbor->visitid= visitid;
+      if (!neighbor->flipped) { 
+	qh_distplane (point, neighbor, &dist);
+	(*numpart)++;
+	if (dist > *bestdist) {
+	  if (!neighbor->upperdelaunay || ischeckmax || (!noupper && dist >= qh MINoutside)) {
+	    bestfacet= neighbor;
+	    *bestdist= dist;
+	    newbest= True;
+	    if (!ischeckmax) {
+	      minsearch= dist - searchdist;
+	      if (dist > *bestdist + searchdist) {
+		zinc_(Zfindjump);  /* everything in qh.coplanarset at least searchdist below */
+		coplanarset_size= 0;
+	      }
+	    }
+	  }
+	}else if (dist < minsearch) 
+	  continue;  /* if ischeckmax, dist can't be positive */
+#if qh_MAXoutside
+	if (ischeckmax && dist > neighbor->maxoutside)
+	  neighbor->maxoutside= dist;
+#endif      
+      } /* end of !flipped */
+      if (nextfacet) {
+	if (!coplanarset_size++) {
+	  SETfirst_(qh coplanarset)= nextfacet;
+	  SETtruncate_(qh coplanarset, 1);
+	}else
+  	  qh_setappend (&qh coplanarset, nextfacet); /* Was needed for RBOX 1000 s W1e-13 P0 t996547055 | QHULL d Qbb Qc Tv
+						 and RBOX 1000 s Z1 G1e-13 t996564279 | qhull Tv  */
+      }
+      nextfacet= neighbor;
+    } /* end of EACHneighbor */
+    facet= nextfacet;
+    if (facet) 
+      nextfacet= NULL;
+    else if (!coplanarset_size)
+      break; 
+    else if (!--coplanarset_size) {
+      facet= SETfirst_(qh coplanarset);
+      SETtruncate_(qh coplanarset, 0);
+    }else
+      facet= (facetT*)qh_setdellast (qh coplanarset);
+  } /* while True, for each facet in qh.coplanarset */
+  if (!ischeckmax) {
+    zadd_(Zfindhorizontot, *numpart - numpartinit);
+    zmax_(Zfindhorizonmax, *numpart - numpartinit);
+    if (newbest)
+      zinc_(Zparthorizon);
+  }
+  trace4((qh ferr, "qh_findbesthorizon: newbest? %d bestfacet f%d bestdist %2.2g\n", newbest, getid_(bestfacet), *bestdist));
+  return bestfacet;
+}  /* findbesthorizon */
+
+/*---------------------------------
+  
+  qh_findbestnew( point, startfacet, dist, isoutside, numpart )
+    find best newfacet for point
+    searches all of qh.newfacet_list starting at startfacet
+    searches horizon facets of coplanar best newfacets
+    searches all facets if startfacet == qh.facet_list
+  returns:
+    best new or horizon facet that is not upperdelaunay
+    early out if isoutside and not 'Qf'
+    dist is distance to facet
+    isoutside is true if point is outside of facet
+    numpart is number of distance tests
+
+  notes:
+    Always used for merged new facets (see qh_USEfindbestnew)
+    Avoids upperdelaunay facet unless (isoutside and outside)
+
+    Uses qh.visit_id, qh.coplanarset.  
+    If share visit_id with qh_findbest, coplanarset is incorrect.
+
+    If merging (testhorizon), searches horizon facets of coplanar best facets because
+    a point maybe coplanar to the bestfacet, below its horizon facet,
+    and above a horizon facet of a coplanar newfacet.  For example,
+      rbox 1000 s Z1 G1e-13 | qhull
+      rbox 1000 s W1e-13 P0 t992110337 | QHULL d Qbb Qc
+
+    qh_findbestnew() used if
+       qh_sharpnewfacets -- newfacets contains a sharp angle
+       if many merges, qh_premerge found a merge, or 'Qf' (qh.findbestnew)
+
+  see also:
+    qh_partitionall() and qh_findbest()
+
+  design:
+    for each new facet starting from startfacet
+      test distance from point to facet
+      return facet if clearly outside
+      unless upperdelaunay and a lowerdelaunay exists
+         update best facet
+    test horizon facets
+*/
+facetT *qh_findbestnew (pointT *point, facetT *startfacet,
+	   realT *dist, boolT bestoutside, boolT *isoutside, int *numpart) {
+  realT bestdist= -REALmax/2; /*, minsearch= -REALmax/2;*/
+  facetT *bestfacet= NULL, *facet;
+  int oldtrace= qh IStracing, i;
+  unsigned int visitid= ++qh visit_id;
+  realT distoutside= 0.0;
+  boolT isdistoutside; /* True if distoutside is defined */
+  boolT testhorizon = True; /* needed if precise, e.g., rbox c D6 | qhull Q0 Tv */
+
+  if (!startfacet) {
+    if (qh MERGING)
+      fprintf(qh ferr, "qhull precision error (qh_findbestnew): merging has formed and deleted a cone of new facets.  Can not continue.\n");
+    else
+      fprintf(qh ferr, "qhull internal error (qh_findbestnew): no new facets for point p%d\n",
+      	      qh furthest_id);      
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  zinc_(Zfindnew);
+  if (qh BESToutside || bestoutside)
+    isdistoutside= False;
+  else {
+    isdistoutside= True;
+    distoutside= qh_DISToutside; /* multiple of qh.MINoutside & qh.max_outside, see user.h */
+  }
+  if (isoutside)
+    *isoutside= True;
+  *numpart= 0;
+  if (qh IStracing >= 3 || (qh TRACElevel && qh TRACEpoint >= 0 && qh TRACEpoint == qh_pointid (point))) {
+    if (qh TRACElevel > qh IStracing)
+      qh IStracing= qh TRACElevel;
+    fprintf(qh ferr, "qh_findbestnew: point p%d facet f%d. Stop? %d if dist > %2.2g\n",
+	     qh_pointid(point), startfacet->id, isdistoutside, distoutside);
+    fprintf(qh ferr, "  Last point added p%d visitid %d.",  qh furthest_id, visitid);
+    fprintf(qh ferr, "  Last merge was #%d.\n", zzval_(Ztotmerge));
+  }
+  /* visit all new facets starting with startfacet, maybe qh facet_list */
+  for (i= 0, facet= startfacet; i < 2; i++, facet= qh newfacet_list) {
+    FORALLfacet_(facet) {
+      if (facet == startfacet && i)
+	break;
+      facet->visitid= visitid;
+      if (!facet->flipped) {
+	qh_distplane (point, facet, dist);
+	(*numpart)++;
+	if (*dist > bestdist) {
+	  if (!facet->upperdelaunay || *dist >= qh MINoutside) {
+	    bestfacet= facet;
+	    if (isdistoutside && *dist >= distoutside)
+	      goto LABELreturn_bestnew;
+	    bestdist= *dist;
+  	  }
+	}
+      } /* end of !flipped */
+    } /* FORALLfacet from startfacet or qh newfacet_list */
+  }
+  if (testhorizon || !bestfacet)
+    bestfacet= qh_findbesthorizon (!qh_IScheckmax, point, bestfacet ? bestfacet : startfacet, 
+	                                !qh_NOupper, &bestdist, numpart);  
+  *dist= bestdist;
+  if (isoutside && *dist < qh MINoutside)
+    *isoutside= False;
+LABELreturn_bestnew:
+  zadd_(Zfindnewtot, *numpart);
+  zmax_(Zfindnewmax, *numpart);
+  trace4((qh ferr, "qh_findbestnew: bestfacet f%d bestdist %2.2g\n", getid_(bestfacet), *dist));
+  qh IStracing= oldtrace;
+  return bestfacet;
+}  /* findbestnew */
+
+/* ============ hyperplane functions -- keep code together [?] ============ */
+
+/*---------------------------------
+  
+  qh_backnormal( rows, numrow, numcol, sign, normal, nearzero )
+    given an upper-triangular rows array and a sign,
+    solve for normal equation x using back substitution over rows U
+
+  returns:
+     normal= x
+      
+     if will not be able to divzero() when normalized (qh.MINdenom_2 and qh.MINdenom_1_2),
+       if fails on last row
+         this means that the hyperplane intersects [0,..,1]
+         sets last coordinate of normal to sign
+       otherwise
+         sets tail of normal to [...,sign,0,...], i.e., solves for b= [0...0]
+         sets nearzero
+
+  notes:
+     assumes numrow == numcol-1
+
+     see Golub & van Loan 4.4-9 for back substitution
+
+     solves Ux=b where Ax=b and PA=LU
+     b= [0,...,0,sign or 0]  (sign is either -1 or +1)
+     last row of A= [0,...,0,1]
+
+     1) Ly=Pb == y=b since P only permutes the 0's of   b
+     
+  design:
+    for each row from end
+      perform back substitution
+      if near zero
+        use qh_divzero for division
+        if zero divide and not last row
+          set tail of normal to 0
+*/
+void qh_backnormal (realT **rows, int numrow, int numcol, boolT sign,
+  	coordT *normal, boolT *nearzero) {
+  int i, j;
+  coordT *normalp, *normal_tail, *ai, *ak;
+  realT diagonal;
+  boolT waszero;
+  int zerocol= -1;
+  
+  normalp= normal + numcol - 1;
+  *normalp--= (sign ? -1.0 : 1.0);
+  for(i= numrow; i--; ) {
+    *normalp= 0.0;
+    ai= rows[i] + i + 1;
+    ak= normalp+1;
+    for(j= i+1; j < numcol; j++)
+      *normalp -= *ai++ * *ak++;
+    diagonal= (rows[i])[i];
+    if (fabs_(diagonal) > qh MINdenom_2)
+      *(normalp--) /= diagonal;
+    else {
+      waszero= False;
+      *normalp= qh_divzero (*normalp, diagonal, qh MINdenom_1_2, &waszero);
+      if (waszero) {
+        zerocol= i;
+	*(normalp--)= (sign ? -1.0 : 1.0);
+	for (normal_tail= normalp+2; normal_tail < normal + numcol; normal_tail++)
+	  *normal_tail= 0.0;
+      }else
+	normalp--;
+    }
+  }
+  if (zerocol != -1) {
+    zzinc_(Zback0);
+    *nearzero= True;
+    trace4((qh ferr, "qh_backnormal: zero diagonal at column %d.\n", i));
+    qh_precision ("zero diagonal on back substitution");
+  }
+} /* backnormal */
+
+/*---------------------------------
+  
+  qh_gausselim( rows, numrow, numcol, sign )
+    Gaussian elimination with partial pivoting
+
+  returns:
+    rows is upper triangular (includes row exchanges)
+    flips sign for each row exchange
+    sets nearzero if pivot[k] < qh.NEARzero[k], else clears it
+
+  notes:
+    if nearzero, the determinant's sign may be incorrect.
+    assumes numrow <= numcol
+
+  design:
+    for each row
+      determine pivot and exchange rows if necessary
+      test for near zero
+      perform gaussian elimination step
+*/
+void qh_gausselim(realT **rows, int numrow, int numcol, boolT *sign, boolT *nearzero) {
+  realT *ai, *ak, *rowp, *pivotrow;
+  realT n, pivot, pivot_abs= 0.0, temp;
+  int i, j, k, pivoti, flip=0;
+  
+  *nearzero= False;
+  for(k= 0; k < numrow; k++) {
+    pivot_abs= fabs_((rows[k])[k]);
+    pivoti= k;
+    for(i= k+1; i < numrow; i++) {
+      if ((temp= fabs_((rows[i])[k])) > pivot_abs) {
+	pivot_abs= temp;
+	pivoti= i;
+      }
+    }
+    if (pivoti != k) {
+      rowp= rows[pivoti]; 
+      rows[pivoti]= rows[k]; 
+      rows[k]= rowp; 
+      *sign ^= 1;
+      flip ^= 1;
+    }
+    if (pivot_abs <= qh NEARzero[k]) {
+      *nearzero= True;
+      if (pivot_abs == 0.0) {   /* remainder of column == 0 */
+	if (qh IStracing >= 4) {
+	  fprintf (qh ferr, "qh_gausselim: 0 pivot at column %d. (%2.2g < %2.2g)\n", k, pivot_abs, qh DISTround);
+	  qh_printmatrix (qh ferr, "Matrix:", rows, numrow, numcol);
+	}
+	zzinc_(Zgauss0);
+        qh_precision ("zero pivot for Gaussian elimination");
+	goto LABELnextcol;
+      }
+    }
+    pivotrow= rows[k] + k;
+    pivot= *pivotrow++;  /* signed value of pivot, and remainder of row */
+    for(i= k+1; i < numrow; i++) {
+      ai= rows[i] + k;
+      ak= pivotrow;
+      n= (*ai++)/pivot;   /* divzero() not needed since |pivot| >= |*ai| */
+      for(j= numcol - (k+1); j--; )
+	*ai++ -= n * *ak++;
+    }
+  LABELnextcol:
+    ;
+  }
+  wmin_(Wmindenom, pivot_abs);  /* last pivot element */
+  if (qh IStracing >= 5)
+    qh_printmatrix (qh ferr, "qh_gausselem: result", rows, numrow, numcol);
+} /* gausselim */
+
+
+/*---------------------------------
+  
+  qh_getangle( vect1, vect2 )
+    returns the dot product of two vectors
+    if qh.RANDOMdist, joggles result
+
+  notes:
+    the angle may be > 1.0 or < -1.0 because of roundoff errors
+
+*/
+realT qh_getangle(pointT *vect1, pointT *vect2) {
+  realT angle= 0, randr;
+  int k;
+
+  for(k= qh hull_dim; k--; )
+    angle += *vect1++ * *vect2++;
+  if (qh RANDOMdist) {
+    randr= qh_RANDOMint;
+    angle += (2.0 * randr / qh_RANDOMmax - 1.0) *
+      qh RANDOMfactor;
+  }
+  trace4((qh ferr, "qh_getangle: %2.2g\n", angle));
+  return(angle);
+} /* getangle */
+
+
+/*---------------------------------
+  
+  qh_getcenter( vertices )
+    returns arithmetic center of a set of vertices as a new point
+
+  notes:
+    allocates point array for center
+*/
+pointT *qh_getcenter(setT *vertices) {
+  int k;
+  pointT *center, *coord;
+  vertexT *vertex, **vertexp;
+  int count= qh_setsize(vertices);
+
+  if (count < 2) {
+    fprintf (qh ferr, "qhull internal error (qh_getcenter): not defined for %d points\n", count);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  center= (pointT *)qh_memalloc(qh normal_size);
+  for (k=0; k < qh hull_dim; k++) {
+    coord= center+k;
+    *coord= 0.0;
+    FOREACHvertex_(vertices)
+      *coord += vertex->point[k];
+    *coord /= count;
+  }
+  return(center);
+} /* getcenter */
+
+
+/*---------------------------------
+  
+  qh_getcentrum( facet )
+    returns the centrum for a facet as a new point
+
+  notes:
+    allocates the centrum
+*/
+pointT *qh_getcentrum(facetT *facet) {
+  realT dist;
+  pointT *centrum, *point;
+
+  point= qh_getcenter(facet->vertices);
+  zzinc_(Zcentrumtests);
+  qh_distplane (point, facet, &dist);
+  centrum= qh_projectpoint(point, facet, dist);
+  qh_memfree(point, qh normal_size);
+  trace4((qh ferr, "qh_getcentrum: for f%d, %d vertices dist= %2.2g\n",
+	  facet->id, qh_setsize(facet->vertices), dist));
+  return centrum;
+} /* getcentrum */
+
+
+/*---------------------------------
+  
+  qh_getdistance( facet, neighbor, mindist, maxdist )
+    returns the maxdist and mindist distance of any vertex from neighbor
+
+  returns:
+    the max absolute value
+
+  design:
+    for each vertex of facet that is not in neighbor
+      test the distance from vertex to neighbor
+*/
+realT qh_getdistance(facetT *facet, facetT *neighbor, realT *mindist, realT *maxdist) {
+  vertexT *vertex, **vertexp;
+  realT dist, maxd, mind;
+  
+  FOREACHvertex_(facet->vertices)
+    vertex->seen= False;
+  FOREACHvertex_(neighbor->vertices)
+    vertex->seen= True;
+  mind= 0.0;
+  maxd= 0.0;
+  FOREACHvertex_(facet->vertices) {
+    if (!vertex->seen) {
+      zzinc_(Zbestdist);
+      qh_distplane(vertex->point, neighbor, &dist);
+      if (dist < mind)
+	mind= dist;
+      else if (dist > maxd)
+	maxd= dist;
+    }
+  }
+  *mindist= mind;
+  *maxdist= maxd;
+  mind= -mind;
+  if (maxd > mind)
+    return maxd;
+  else
+    return mind;
+} /* getdistance */
+
+
+/*---------------------------------
+
+  qh_normalize( normal, dim, toporient )
+    normalize a vector and report if too small
+    does not use min norm
+  
+  see:
+    qh_normalize2
+*/
+void qh_normalize (coordT *normal, int dim, boolT toporient) {
+  qh_normalize2( normal, dim, toporient, NULL, NULL);
+} /* normalize */
+
+/*---------------------------------
+  
+  qh_normalize2( normal, dim, toporient, minnorm, ismin )
+    normalize a vector and report if too small
+    qh.MINdenom/MINdenom1 are the upper limits for divide overflow
+
+  returns:
+    normalized vector
+    flips sign if !toporient
+    if minnorm non-NULL, 
+      sets ismin if normal < minnorm
+
+  notes:
+    if zero norm
+       sets all elements to sqrt(1.0/dim)
+    if divide by zero (divzero ())
+       sets largest element to   +/-1
+       bumps Znearlysingular
+      
+  design:
+    computes norm
+    test for minnorm
+    if not near zero
+      normalizes normal
+    else if zero norm
+      sets normal to standard value
+    else
+      uses qh_divzero to normalize
+      if nearzero
+        sets norm to direction of maximum value
+*/
+void qh_normalize2 (coordT *normal, int dim, boolT toporient, 
+            realT *minnorm, boolT *ismin) {
+  int k;
+  realT *colp, *maxp, norm= 0, temp, *norm1, *norm2, *norm3;
+  boolT zerodiv;
+
+  norm1= normal+1;
+  norm2= normal+2;
+  norm3= normal+3;
+  if (dim == 2)
+    norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1));
+  else if (dim == 3)
+    norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2));
+  else if (dim == 4) {
+    norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2) 
+               + (*norm3)*(*norm3));
+  }else if (dim > 4) {
+    norm= (*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2) 
+               + (*norm3)*(*norm3);
+    for (k= dim-4, colp= normal+4; k--; colp++)
+      norm += (*colp) * (*colp);
+    norm= sqrt(norm);
+  }
+  if (minnorm) {
+    if (norm < *minnorm) 
+      *ismin= True;
+    else
+      *ismin= False;
+  }
+  wmin_(Wmindenom, norm);
+  if (norm > qh MINdenom) {
+    if (!toporient)
+      norm= -norm;
+    *normal /= norm;
+    *norm1 /= norm;
+    if (dim == 2)
+      ; /* all done */
+    else if (dim == 3)
+      *norm2 /= norm;
+    else if (dim == 4) {
+      *norm2 /= norm;
+      *norm3 /= norm;
+    }else if (dim >4) {
+      *norm2 /= norm;
+      *norm3 /= norm;
+      for (k= dim-4, colp= normal+4; k--; )
+        *colp++ /= norm;
+    }
+  }else if (norm == 0.0) {
+    temp= sqrt (1.0/dim);
+    for (k= dim, colp= normal; k--; )
+      *colp++ = temp;
+  }else {
+    if (!toporient)
+      norm= -norm;
+    for (k= dim, colp= normal; k--; colp++) { /* k used below */
+      temp= qh_divzero (*colp, norm, qh MINdenom_1, &zerodiv);
+      if (!zerodiv)
+	*colp= temp;
+      else {
+	maxp= qh_maxabsval(normal, dim);
+	temp= ((*maxp * norm >= 0.0) ? 1.0 : -1.0);
+	for (k= dim, colp= normal; k--; colp++)
+	  *colp= 0.0;
+	*maxp= temp;
+	zzinc_(Znearlysingular);
+	trace0((qh ferr, "qh_normalize: norm=%2.2g too small during p%d\n", 
+	       norm, qh furthest_id));
+	return;
+      }
+    }
+  }
+} /* normalize */
+
+
+/*---------------------------------
+  
+  qh_projectpoint( point, facet, dist )
+    project point onto a facet by dist
+
+  returns:
+    returns a new point
+    
+  notes:
+    if dist= distplane(point,facet)
+      this projects point to hyperplane
+    assumes qh_memfree_() is valid for normal_size
+*/
+pointT *qh_projectpoint(pointT *point, facetT *facet, realT dist) {
+  pointT *newpoint, *np, *normal;
+  int normsize= qh normal_size,k;
+  void **freelistp; /* used !qh_NOmem */
+  
+  qh_memalloc_(normsize, freelistp, newpoint, pointT);
+  np= newpoint;
+  normal= facet->normal;
+  for(k= qh hull_dim; k--; )
+    *(np++)= *point++ - dist * *normal++;
+  return(newpoint);
+} /* projectpoint */
+
+  
+/*---------------------------------
+  
+  qh_setfacetplane( facet )
+    sets the hyperplane for a facet
+    if qh.RANDOMdist, joggles hyperplane
+
+  notes:
+    uses global buffers qh.gm_matrix and qh.gm_row
+    overwrites facet->normal if already defined
+    updates Wnewvertex if PRINTstatistics
+    sets facet->upperdelaunay if upper envelope of Delaunay triangulation
+
+  design:
+    copy vertex coordinates to qh.gm_matrix/gm_row
+    compute determinate
+    if nearzero
+      recompute determinate with gaussian elimination
+      if nearzero
+        force outside orientation by testing interior point
+*/
+void qh_setfacetplane(facetT *facet) {
+  pointT *point;
+  vertexT *vertex, **vertexp;
+  int k,i, normsize= qh normal_size, oldtrace= 0;
+  realT dist;
+  void **freelistp; /* used !qh_NOmem */
+  coordT *coord, *gmcoord;
+  pointT *point0= SETfirstt_(facet->vertices, vertexT)->point;
+  boolT nearzero= False;
+
+  zzinc_(Zsetplane);
+  if (!facet->normal)
+    qh_memalloc_(normsize, freelistp, facet->normal, coordT);
+  if (facet == qh tracefacet) {
+    oldtrace= qh IStracing;
+    qh IStracing= 5;
+    fprintf (qh ferr, "qh_setfacetplane: facet f%d created.\n", facet->id);
+    fprintf (qh ferr, "  Last point added to hull was p%d.", qh furthest_id);
+    if (zzval_(Ztotmerge))
+      fprintf(qh ferr, "  Last merge was #%d.", zzval_(Ztotmerge));
+    fprintf (qh ferr, "\n\nCurrent summary is:\n");
+      qh_printsummary (qh ferr);
+  }
+  if (qh hull_dim <= 4) {
+    i= 0;
+    if (qh RANDOMdist) {
+      gmcoord= qh gm_matrix;
+      FOREACHvertex_(facet->vertices) {
+        qh gm_row[i++]= gmcoord;
+	coord= vertex->point;
+	for (k= qh hull_dim; k--; )
+	  *(gmcoord++)= *coord++ * qh_randomfactor();
+      }	  
+    }else {
+      FOREACHvertex_(facet->vertices)
+       qh gm_row[i++]= vertex->point;
+    }
+    qh_sethyperplane_det(qh hull_dim, qh gm_row, point0, facet->toporient,
+                facet->normal, &facet->offset, &nearzero);
+  }
+  if (qh hull_dim > 4 || nearzero) {
+    i= 0;
+    gmcoord= qh gm_matrix;
+    FOREACHvertex_(facet->vertices) {
+      if (vertex->point != point0) {
+	qh gm_row[i++]= gmcoord;
+	coord= vertex->point;
+	point= point0;
+	for(k= qh hull_dim; k--; )
+	  *(gmcoord++)= *coord++ - *point++;
+      }
+    }
+    qh gm_row[i]= gmcoord;  /* for areasimplex */
+    if (qh RANDOMdist) {
+      gmcoord= qh gm_matrix;
+      for (i= qh hull_dim-1; i--; ) {
+	for (k= qh hull_dim; k--; )
+	  *(gmcoord++) *= qh_randomfactor();
+      }
+    }
+    qh_sethyperplane_gauss(qh hull_dim, qh gm_row, point0, facet->toporient,
+           	facet->normal, &facet->offset, &nearzero);
+    if (nearzero) { 
+      if (qh_orientoutside (facet)) {
+	trace0((qh ferr, "qh_setfacetplane: flipped orientation after testing interior_point during p%d\n", qh furthest_id));
+      /* this is part of using Gaussian Elimination.  For example in 5-d
+	   1 1 1 1 0
+	   1 1 1 1 1
+	   0 0 0 1 0
+	   0 1 0 0 0
+	   1 0 0 0 0
+	   norm= 0.38 0.38 -0.76 0.38 0
+	 has a determinate of 1, but g.e. after subtracting pt. 0 has
+	 0's in the diagonal, even with full pivoting.  It does work
+	 if you subtract pt. 4 instead. */
+      }
+    }
+  }
+  facet->upperdelaunay= False;
+  if (qh DELAUNAY) {
+    if (qh UPPERdelaunay) {     /* matches qh_triangulate_facet and qh.lower_threshold in qh_initbuild */
+      if (facet->normal[qh hull_dim -1] >= qh ANGLEround * qh_ZEROdelaunay)
+        facet->upperdelaunay= True;
+    }else {
+      if (facet->normal[qh hull_dim -1] > -qh ANGLEround * qh_ZEROdelaunay)
+        facet->upperdelaunay= True;
+    }
+  }
+  if (qh PRINTstatistics || qh IStracing || qh TRACElevel || qh JOGGLEmax < REALmax) {
+    qh old_randomdist= qh RANDOMdist;
+    qh RANDOMdist= False;
+    FOREACHvertex_(facet->vertices) {
+      if (vertex->point != point0) {
+	boolT istrace= False;
+	zinc_(Zdiststat);
+        qh_distplane(vertex->point, facet, &dist);
+        dist= fabs_(dist);
+        zinc_(Znewvertex);
+        wadd_(Wnewvertex, dist);
+        if (dist > wwval_(Wnewvertexmax)) {
+          wwval_(Wnewvertexmax)= dist;
+	  if (dist > qh max_outside) {
+	    qh max_outside= dist;  /* used by qh_maxouter() */
+	    if (dist > qh TRACEdist) 
+	      istrace= True;
+	  }
+	}else if (-dist > qh TRACEdist)
+	  istrace= True;
+	if (istrace) {
+	  fprintf (qh ferr, "qh_setfacetplane: ====== vertex p%d (v%d) increases max_outside to %2.2g for new facet f%d last p%d\n",
+	        qh_pointid(vertex->point), vertex->id, dist, facet->id, qh furthest_id);
+	  qh_errprint ("DISTANT", facet, NULL, NULL, NULL);
+	}
+      }
+    }
+    qh RANDOMdist= qh old_randomdist;
+  }
+  if (qh IStracing >= 3) {
+    fprintf (qh ferr, "qh_setfacetplane: f%d offset %2.2g normal: ",
+	     facet->id, facet->offset);
+    for (k=0; k < qh hull_dim; k++)
+      fprintf (qh ferr, "%2.2g ", facet->normal[k]);
+    fprintf (qh ferr, "\n");
+  }
+  if (facet == qh tracefacet)
+    qh IStracing= oldtrace;
+} /* setfacetplane */
+
+
+/*---------------------------------
+  
+  qh_sethyperplane_det( dim, rows, point0, toporient, normal, offset, nearzero )
+    given dim X dim array indexed by rows[], one row per point, 
+        toporient (flips all signs),
+        and point0 (any row)
+    set normalized hyperplane equation from oriented simplex
+
+  returns:
+    normal (normalized)
+    offset (places point0 on the hyperplane)
+    sets nearzero if hyperplane not through points
+
+  notes:
+    only defined for dim == 2..4
+    rows[] is not modified
+    solves det(P-V_0, V_n-V_0, ..., V_1-V_0)=0, i.e. every point is on hyperplane
+    see Bower & Woodworth, A programmer's geometry, Butterworths 1983.
+
+  derivation of 3-d minnorm
+    Goal: all vertices V_i within qh.one_merge of hyperplane
+    Plan: exactly translate the facet so that V_0 is the origin
+          exactly rotate the facet so that V_1 is on the x-axis and y_2=0.
+          exactly rotate the effective perturbation to only effect n_0
+	     this introduces a factor of sqrt(3)
+    n_0 = ((y_2-y_0)*(z_1-z_0) - (z_2-z_0)*(y_1-y_0)) / norm
+    Let M_d be the max coordinate difference
+    Let M_a be the greater of M_d and the max abs. coordinate
+    Let u be machine roundoff and distround be max error for distance computation
+    The max error for n_0 is sqrt(3) u M_a M_d / norm.  n_1 is approx. 1 and n_2 is approx. 0
+    The max error for distance of V_1 is sqrt(3) u M_a M_d M_d / norm.  Offset=0 at origin
+    Then minnorm = 1.8 u M_a M_d M_d / qh.ONEmerge
+    Note that qh.one_merge is approx. 45.5 u M_a and norm is usually about M_d M_d
+
+  derivation of 4-d minnorm
+    same as above except rotate the facet so that V_1 on x-axis and w_2, y_3, w_3=0
+     [if two vertices fixed on x-axis, can rotate the other two in yzw.]
+    n_0 = det3_(...) = y_2 det2_(z_1, w_1, z_3, w_3) = - y_2 w_1 z_3
+     [all other terms contain at least two factors nearly zero.]
+    The max error for n_0 is sqrt(4) u M_a M_d M_d / norm
+    Then minnorm = 2 u M_a M_d M_d M_d / qh.ONEmerge
+    Note that qh.one_merge is approx. 82 u M_a and norm is usually about M_d M_d M_d
+*/
+void qh_sethyperplane_det (int dim, coordT **rows, coordT *point0, 
+          boolT toporient, coordT *normal, realT *offset, boolT *nearzero) {
+  realT maxround, dist;
+  int i;
+  pointT *point;
+
+
+  if (dim == 2) {
+    normal[0]= dY(1,0);
+    normal[1]= dX(0,1);
+    qh_normalize2 (normal, dim, toporient, NULL, NULL);
+    *offset= -(point0[0]*normal[0]+point0[1]*normal[1]);
+    *nearzero= False;  /* since nearzero norm => incident points */
+  }else if (dim == 3) {
+    normal[0]= det2_(dY(2,0), dZ(2,0),
+		     dY(1,0), dZ(1,0));
+    normal[1]= det2_(dX(1,0), dZ(1,0),
+		     dX(2,0), dZ(2,0));
+    normal[2]= det2_(dX(2,0), dY(2,0),
+		     dX(1,0), dY(1,0));
+    qh_normalize2 (normal, dim, toporient, NULL, NULL);
+    *offset= -(point0[0]*normal[0] + point0[1]*normal[1]
+	       + point0[2]*normal[2]);
+    maxround= qh DISTround;
+    for (i=dim; i--; ) {
+      point= rows[i];
+      if (point != point0) {
+        dist= *offset + (point[0]*normal[0] + point[1]*normal[1]
+	       + point[2]*normal[2]);
+        if (dist > maxround || dist < -maxround) {
+  	  *nearzero= True;
+	  break;
+	}
+      }
+    }
+  }else if (dim == 4) {
+    normal[0]= - det3_(dY(2,0), dZ(2,0), dW(2,0),
+			dY(1,0), dZ(1,0), dW(1,0),
+			dY(3,0), dZ(3,0), dW(3,0));
+    normal[1]=   det3_(dX(2,0), dZ(2,0), dW(2,0),
+		        dX(1,0), dZ(1,0), dW(1,0),
+		        dX(3,0), dZ(3,0), dW(3,0));
+    normal[2]= - det3_(dX(2,0), dY(2,0), dW(2,0),
+			dX(1,0), dY(1,0), dW(1,0),
+			dX(3,0), dY(3,0), dW(3,0));
+    normal[3]=   det3_(dX(2,0), dY(2,0), dZ(2,0),
+		        dX(1,0), dY(1,0), dZ(1,0),
+		        dX(3,0), dY(3,0), dZ(3,0));
+    qh_normalize2 (normal, dim, toporient, NULL, NULL);
+    *offset= -(point0[0]*normal[0] + point0[1]*normal[1]
+	       + point0[2]*normal[2] + point0[3]*normal[3]);
+    maxround= qh DISTround;
+    for (i=dim; i--; ) {
+      point= rows[i];
+      if (point != point0) {
+        dist= *offset + (point[0]*normal[0] + point[1]*normal[1]
+	       + point[2]*normal[2] + point[3]*normal[3]);
+        if (dist > maxround || dist < -maxround) {
+  	  *nearzero= True;
+	  break;
+	}
+      }
+    }
+  }
+  if (*nearzero) {
+    zzinc_(Zminnorm);
+    trace0((qh ferr, "qh_sethyperplane_det: degenerate norm during p%d.\n", qh furthest_id));
+    zzinc_(Znearlysingular);
+  }
+} /* sethyperplane_det */
+
+
+/*---------------------------------
+  
+  qh_sethyperplane_gauss( dim, rows, point0, toporient, normal, offset, nearzero )
+    given (dim-1) X dim array of rows[i]= V_{i+1} - V_0 (point0)
+    set normalized hyperplane equation from oriented simplex
+
+  returns:
+    normal (normalized)
+    offset (places point0 on the hyperplane)
+
+  notes:
+    if nearzero
+      orientation may be incorrect because of incorrect sign flips in gausselim
+    solves [V_n-V_0,...,V_1-V_0, 0 .. 0 1] * N == [0 .. 0 1] 
+        or [V_n-V_0,...,V_1-V_0, 0 .. 0 1] * N == [0] 
+    i.e., N is normal to the hyperplane, and the unnormalized
+        distance to [0 .. 1] is either 1 or   0
+
+  design:
+    perform gaussian elimination
+    flip sign for negative values
+    perform back substitution 
+    normalize result
+    compute offset
+*/
+void qh_sethyperplane_gauss (int dim, coordT **rows, pointT *point0, 
+		boolT toporient, coordT *normal, coordT *offset, boolT *nearzero) {
+  coordT *pointcoord, *normalcoef;
+  int k;
+  boolT sign= toporient, nearzero2= False;
+  
+  qh_gausselim(rows, dim-1, dim, &sign, nearzero);
+  for(k= dim-1; k--; ) {
+    if ((rows[k])[k] < 0)
+      sign ^= 1;
+  }
+  if (*nearzero) {
+    zzinc_(Znearlysingular);
+    trace0((qh ferr, "qh_sethyperplane_gauss: nearly singular or axis parallel hyperplane during p%d.\n", qh furthest_id));
+    qh_backnormal(rows, dim-1, dim, sign, normal, &nearzero2);
+  }else {
+    qh_backnormal(rows, dim-1, dim, sign, normal, &nearzero2);
+    if (nearzero2) {
+      zzinc_(Znearlysingular);
+      trace0((qh ferr, "qh_sethyperplane_gauss: singular or axis parallel hyperplane at normalization during p%d.\n", qh furthest_id));
+    }
+  }
+  if (nearzero2)
+    *nearzero= True;
+  qh_normalize2(normal, dim, True, NULL, NULL);
+  pointcoord= point0;
+  normalcoef= normal;
+  *offset= -(*pointcoord++ * *normalcoef++);
+  for(k= dim-1; k--; )
+    *offset -= *pointcoord++ * *normalcoef++;
+} /* sethyperplane_gauss */
+
+  
+
diff --git a/extern/qhull/src/geom.h b/extern/qhull/src/geom.h
new file mode 100644
index 00000000000..32440cff56f
--- /dev/null
+++ b/extern/qhull/src/geom.h
@@ -0,0 +1,177 @@
+/*
  ---------------------------------
+
+  geom.h 
+    header file for geometric routines
+
+   see qh-geom.htm and geom.c
+
+   copyright (c) 1993-2002 The Geometry Center        
+*/
+
+#ifndef qhDEFgeom
+#define qhDEFgeom 1
+
+/* ============ -macros- ======================== */
+
+/*----------------------------------
+   
+  fabs_(a)
+    returns the absolute value of a
+*/
+#define fabs_( a ) ((( a ) < 0 ) ? -( a ):( a ))
+               
+/*----------------------------------
+  
+  fmax_(a,b)
+    returns the maximum value of a and b
+*/
+#define fmax_( a,b )  ( ( a ) < ( b ) ? ( b ) : ( a ) )
+
+/*----------------------------------
+
+  fmin_(a,b)
+    returns the minimum value of a and b
+*/
+#define fmin_( a,b )  ( ( a ) > ( b ) ? ( b ) : ( a ) )
+
+/*----------------------------------
+
+  maximize_(maxval, val)
+    set maxval to val if val is greater than maxval
+*/
+#define maximize_( maxval, val ) {if (( maxval ) < ( val )) ( maxval )= ( val );}
+
+/*----------------------------------
+
+  minimize_(minval, val)
+    set minval to val if val is less than minval
+*/
+#define minimize_( minval, val ) {if (( minval ) > ( val )) ( minval )= ( val );}
+
+/*----------------------------------
+
+  det2_(a1, a2,     
+        b1, b2)
+  
+    compute a 2-d determinate
+*/
+#define det2_( a1,a2,b1,b2 ) (( a1 )*( b2 ) - ( a2 )*( b1 ))
+
+/*----------------------------------
+  
+  det3_(a1, a2, a3,    
+       b1, b2, b3,
+       c1, c2, c3)
+  
+    compute a 3-d determinate
+*/
+#define det3_( a1,a2,a3,b1,b2,b3,c1,c2,c3 ) ( ( a1 )*det2_( b2,b3,c2,c3 ) \
+                - ( b1 )*det2_( a2,a3,c2,c3 ) + ( c1 )*det2_( a2,a3,b2,b3 ) )
+
+/*----------------------------------
+  
+  dX( p1, p2 )
+  dY( p1, p2 )
+  dZ( p1, p2 )
+  
+    given two indices into rows[],
+
+    compute the difference between X, Y, or Z coordinates
+*/
+#define dX( p1,p2 )  ( *( rows[p1] ) - *( rows[p2] ))
+#define dY( p1,p2 )  ( *( rows[p1]+1 ) - *( rows[p2]+1 ))
+#define dZ( p1,p2 )  ( *( rows[p1]+2 ) - *( rows[p2]+2 ))
+#define dW( p1,p2 )  ( *( rows[p1]+3 ) - *( rows[p2]+3 ))
+
+/*============= prototypes in alphabetical order, infrequent at end ======= */
+
+void    qh_backnormal (realT **rows, int numrow, int numcol, boolT sign, coordT *normal, boolT *nearzero);
+void	qh_distplane (pointT *point, facetT *facet, realT *dist);
+facetT *qh_findbest (pointT *point, facetT *startfacet,
+		     boolT bestoutside, boolT isnewfacets, boolT noupper,
+		     realT *dist, boolT *isoutside, int *numpart);
+facetT *qh_findbesthorizon (boolT ischeckmax, pointT *point, 
+	             facetT *startfacet, boolT noupper, realT *bestdist, int *numpart);
+facetT *qh_findbestnew (pointT *point, facetT *startfacet, realT *dist, 
+		     boolT bestoutside, boolT *isoutside, int *numpart);
+void 	qh_gausselim(realT **rows, int numrow, int numcol, boolT *sign, boolT *nearzero);
+realT   qh_getangle(pointT *vect1, pointT *vect2);
+pointT *qh_getcenter(setT *vertices);
+pointT *qh_getcentrum(facetT *facet);
+realT   qh_getdistance(facetT *facet, facetT *neighbor, realT *mindist, realT *maxdist);
+void    qh_normalize (coordT *normal, int dim, boolT toporient);
+void    qh_normalize2 (coordT *normal, int dim, boolT toporient, 
+            realT *minnorm, boolT *ismin);
+pointT *qh_projectpoint(pointT *point, facetT *facet, realT dist);
+
+void    qh_setfacetplane(facetT *newfacets);
+void 	qh_sethyperplane_det (int dim, coordT **rows, coordT *point0, 
+              boolT toporient, coordT *normal, realT *offset, boolT *nearzero);
+void 	qh_sethyperplane_gauss (int dim, coordT **rows, pointT *point0, 
+	     boolT toporient, coordT *normal, coordT *offset, boolT *nearzero);
+boolT   qh_sharpnewfacets (void);
+
+/*========= infrequently used code in geom2.c =============*/
+
+
+coordT *qh_copypoints (coordT *points, int numpoints, int dimension);
+void    qh_crossproduct (int dim, realT vecA[3], realT vecB[3], realT vecC[3]);
+realT 	qh_determinant (realT **rows, int dim, boolT *nearzero);
+realT   qh_detjoggle (pointT *points, int numpoints, int dimension);
+void    qh_detroundoff (void);
+realT   qh_detsimplex(pointT *apex, setT *points, int dim, boolT *nearzero);
+realT   qh_distnorm (int dim, pointT *point, pointT *normal, realT *offsetp);
+realT   qh_distround (int dimension, realT maxabs, realT maxsumabs);
+realT   qh_divzero(realT numer, realT denom, realT mindenom1, boolT *zerodiv);
+realT   qh_facetarea (facetT *facet);
+realT   qh_facetarea_simplex (int dim, coordT *apex, setT *vertices, 
+          vertexT *notvertex,  boolT toporient, coordT *normal, realT *offset);
+pointT *qh_facetcenter (setT *vertices);
+facetT *qh_findgooddist (pointT *point, facetT *facetA, realT *distp, facetT **facetlist);
+void    qh_getarea (facetT *facetlist);
+boolT   qh_gram_schmidt(int dim, realT **rows);
+boolT   qh_inthresholds (coordT *normal, realT *angle);
+void    qh_joggleinput (void);
+realT  *qh_maxabsval (realT *normal, int dim);
+setT   *qh_maxmin(pointT *points, int numpoints, int dimension);
+realT   qh_maxouter (void);
+void    qh_maxsimplex (int dim, setT *maxpoints, pointT *points, int numpoints, setT **simplex);
+realT   qh_minabsval (realT *normal, int dim);
+int     qh_mindiff (realT *vecA, realT *vecB, int dim);
+boolT   qh_orientoutside (facetT *facet);
+void    qh_outerinner (facetT *facet, realT *outerplane, realT *innerplane);
+coordT  qh_pointdist(pointT *point1, pointT *point2, int dim);
+void    qh_printmatrix (FILE *fp, char *string, realT **rows, int numrow, int numcol);
+void    qh_printpoints (FILE *fp, char *string, setT *points);
+void    qh_projectinput (void);
+void 	qh_projectpoints (signed char *project, int n, realT *points, 
+             int numpoints, int dim, realT *newpoints, int newdim);
+int     qh_rand( void);
+void    qh_srand( int seed);
+realT   qh_randomfactor (void);
+void    qh_randommatrix (realT *buffer, int dim, realT **row);
+void    qh_rotateinput (realT **rows);
+void    qh_rotatepoints (realT *points, int numpoints, int dim, realT **rows);
+void    qh_scaleinput (void);
+void    qh_scalelast (coordT *points, int numpoints, int dim, coordT low,
+		   coordT high, coordT newhigh);
+void 	qh_scalepoints (pointT *points, int numpoints, int dim,
+  		realT *newlows, realT *newhighs);
+boolT   qh_sethalfspace (int dim, coordT *coords, coordT **nextp, 
+              coordT *normal, coordT *offset, coordT *feasible);
+coordT *qh_sethalfspace_all (int dim, int count, coordT *halfspaces, pointT *feasible);
+pointT *qh_voronoi_center (int dim, setT *points);
+
+#endif /* qhDEFgeom */
+
+
+
diff --git a/extern/qhull/src/geom2.c b/extern/qhull/src/geom2.c
new file mode 100644
index 00000000000..bd58ce1282b
--- /dev/null
+++ b/extern/qhull/src/geom2.c
@@ -0,0 +1,2160 @@
+/*
  ---------------------------------
+
+
+   geom2.c 
+   infrequently used geometric routines of qhull
+
+   see qh-geom.htm and geom.h
+
+   copyright (c) 1993-2002 The Geometry Center        
+
+   frequently used code goes into geom.c
+*/
+   
+#include "qhull_a.h"
+   
+/*================== functions in alphabetic order ============*/
+
+/*---------------------------------
+
+  qh_copypoints( points, numpoints, dimension)
+    return malloc'd copy of points
+*/
+coordT *qh_copypoints (coordT *points, int numpoints, int dimension) {
+  int size;
+  coordT *newpoints;
+
+  size= numpoints * dimension * sizeof(coordT);
+  if (!(newpoints=(coordT*)malloc(size))) {
+    fprintf(qh ferr, "qhull error: insufficient memory to copy %d points\n",
+        numpoints);
+    qh_errexit(qh_ERRmem, NULL, NULL);
+  }
+  memcpy ((char *)newpoints, (char *)points, size);
+  return newpoints;
+} /* copypoints */
+
+/*---------------------------------
+  
+  qh_crossproduct( dim, vecA, vecB, vecC )
+    crossproduct of 2 dim vectors
+    C= A x B
+  
+  notes:
+    from Glasner, Graphics Gems I, p. 639
+    only defined for dim==3
+*/
+void qh_crossproduct (int dim, realT vecA[3], realT vecB[3], realT vecC[3]){
+
+  if (dim == 3) {
+    vecC[0]=   det2_(vecA[1], vecA[2],
+		     vecB[1], vecB[2]);
+    vecC[1]= - det2_(vecA[0], vecA[2],
+		     vecB[0], vecB[2]);
+    vecC[2]=   det2_(vecA[0], vecA[1],
+		     vecB[0], vecB[1]);
+  }
+} /* vcross */
+
+/*---------------------------------
+  
+  qh_determinant( rows, dim, nearzero )
+    compute signed determinant of a square matrix
+    uses qh.NEARzero to test for degenerate matrices
+
+  returns:
+    determinant
+    overwrites rows and the matrix
+    if dim == 2 or 3
+      nearzero iff determinant < qh NEARzero[dim-1]
+      (not quite correct, not critical)
+    if dim >= 4
+      nearzero iff diagonal[k] < qh NEARzero[k]
+*/
+realT qh_determinant (realT **rows, int dim, boolT *nearzero) {
+  realT det=0;
+  int i;
+  boolT sign= False;
+
+  *nearzero= False;
+  if (dim < 2) {
+    fprintf (qh ferr, "qhull internal error (qh_determinate): only implemented for dimension >= 2\n");
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }else if (dim == 2) {
+    det= det2_(rows[0][0], rows[0][1],
+		 rows[1][0], rows[1][1]);
+    if (fabs_(det) < qh NEARzero[1])  /* not really correct, what should this be? */
+      *nearzero= True;
+  }else if (dim == 3) {
+    det= det3_(rows[0][0], rows[0][1], rows[0][2],
+		 rows[1][0], rows[1][1], rows[1][2],
+		 rows[2][0], rows[2][1], rows[2][2]);
+    if (fabs_(det) < qh NEARzero[2])  /* not really correct, what should this be? */
+      *nearzero= True;
+  }else {	
+    qh_gausselim(rows, dim, dim, &sign, nearzero);  /* if nearzero, diagonal still ok*/
+    det= 1.0;
+    for (i= dim; i--; )
+      det *= (rows[i])[i];
+    if (sign)
+      det= -det;
+  }
+  return det;
+} /* determinant */
+
+/*---------------------------------
+  
+  qh_detjoggle( points, numpoints, dimension )
+    determine default max joggle for point array
+      as qh_distround * qh_JOGGLEdefault
+
+  returns:
+    initial value for JOGGLEmax from points and REALepsilon
+
+  notes:
+    computes DISTround since qh_maxmin not called yet
+    if qh SCALElast, last dimension will be scaled later to MAXwidth
+
+    loop duplicated from qh_maxmin
+*/
+realT qh_detjoggle (pointT *points, int numpoints, int dimension) {
+  realT abscoord, distround, joggle, maxcoord, mincoord;
+  pointT *point, *pointtemp;
+  realT maxabs= -REALmax;
+  realT sumabs= 0;
+  realT maxwidth= 0;
+  int k;
+
+  for (k= 0; k < dimension; k++) {
+    if (qh SCALElast && k == dimension-1)
+      abscoord= maxwidth;
+    else if (qh DELAUNAY && k == dimension-1) /* will qh_setdelaunay() */
+      abscoord= 2 * maxabs * maxabs;  /* may be low by qh hull_dim/2 */
+    else {
+      maxcoord= -REALmax;
+      mincoord= REALmax;
+      FORALLpoint_(points, numpoints) {
+	maximize_(maxcoord, point[k]);
+        minimize_(mincoord, point[k]);
+      }
+      maximize_(maxwidth, maxcoord-mincoord);
+      abscoord= fmax_(maxcoord, -mincoord);
+    }
+    sumabs += abscoord;
+    maximize_(maxabs, abscoord);
+  } /* for k */
+  distround= qh_distround (qh hull_dim, maxabs, sumabs);
+  joggle= distround * qh_JOGGLEdefault;
+  maximize_(joggle, REALepsilon * qh_JOGGLEdefault);
+  trace2((qh ferr, "qh_detjoggle: joggle=%2.2g maxwidth=%2.2g\n", joggle, maxwidth));
+  return joggle;
+} /* detjoggle */
+
+/*---------------------------------
+  
+  qh_detroundoff()
+    determine maximum roundoff errors from
+      REALepsilon, REALmax, REALmin, qh.hull_dim, qh.MAXabs_coord, 
+      qh.MAXsumcoord, qh.MAXwidth, qh.MINdenom_1
+
+    accounts for qh.SETroundoff, qh.RANDOMdist, qh MERGEexact
+      qh.premerge_cos, qh.postmerge_cos, qh.premerge_centrum,
+      qh.postmerge_centrum, qh.MINoutside,
+      qh_RATIOnearinside, qh_COPLANARratio, qh_WIDEcoplanar
+
+  returns:
+    sets qh.DISTround, etc. (see below)
+    appends precision constants to qh.qhull_options
+
+  see:
+    qh_maxmin() for qh.NEARzero
+
+  design:
+    determine qh.DISTround for distance computations
+    determine minimum denominators for qh_divzero
+    determine qh.ANGLEround for angle computations
+    adjust qh.premerge_cos,... for roundoff error
+    determine qh.ONEmerge for maximum error due to a single merge
+    determine qh.NEARinside, qh.MAXcoplanar, qh.MINvisible,
+      qh.MINoutside, qh.WIDEfacet
+    initialize qh.max_vertex and qh.minvertex
+*/
+void qh_detroundoff (void) {
+
+  qh_option ("_max-width", NULL, &qh MAXwidth);
+  if (!qh SETroundoff) {
+    qh DISTround= qh_distround (qh hull_dim, qh MAXabs_coord, qh MAXsumcoord);
+    if (qh RANDOMdist)
+      qh DISTround += qh RANDOMfactor * qh MAXabs_coord;
+    qh_option ("Error-roundoff", NULL, &qh DISTround);
+  }
+  qh MINdenom= qh MINdenom_1 * qh MAXabs_coord;
+  qh MINdenom_1_2= sqrt (qh MINdenom_1 * qh hull_dim) ;  /* if will be normalized */
+  qh MINdenom_2= qh MINdenom_1_2 * qh MAXabs_coord;
+                                              /* for inner product */
+  qh ANGLEround= 1.01 * qh hull_dim * REALepsilon;
+  if (qh RANDOMdist)
+    qh ANGLEround += qh RANDOMfactor;
+  if (qh premerge_cos < REALmax/2) {
+    qh premerge_cos -= qh ANGLEround;
+    if (qh RANDOMdist) 
+      qh_option ("Angle-premerge-with-random", NULL, &qh premerge_cos);
+  }
+  if (qh postmerge_cos < REALmax/2) {
+    qh postmerge_cos -= qh ANGLEround;
+    if (qh RANDOMdist)
+      qh_option ("Angle-postmerge-with-random", NULL, &qh postmerge_cos);
+  }
+  qh premerge_centrum += 2 * qh DISTround;    /*2 for centrum and distplane()*/
+  qh postmerge_centrum += 2 * qh DISTround;
+  if (qh RANDOMdist && (qh MERGEexact || qh PREmerge))
+    qh_option ("Centrum-premerge-with-random", NULL, &qh premerge_centrum);
+  if (qh RANDOMdist && qh POSTmerge)
+    qh_option ("Centrum-postmerge-with-random", NULL, &qh postmerge_centrum);
+  { /* compute ONEmerge, max vertex offset for merging simplicial facets */
+    realT maxangle= 1.0, maxrho;
+    
+    minimize_(maxangle, qh premerge_cos);
+    minimize_(maxangle, qh postmerge_cos);
+    /* max diameter * sin theta + DISTround for vertex to its hyperplane */
+    qh ONEmerge= sqrt (qh hull_dim) * qh MAXwidth *
+      sqrt (1.0 - maxangle * maxangle) + qh DISTround;  
+    maxrho= qh hull_dim * qh premerge_centrum + qh DISTround;
+    maximize_(qh ONEmerge, maxrho);
+    maxrho= qh hull_dim * qh postmerge_centrum + qh DISTround;
+    maximize_(qh ONEmerge, maxrho);
+    if (qh MERGING)
+      qh_option ("_one-merge", NULL, &qh ONEmerge);
+  }
+  qh NEARinside= qh ONEmerge * qh_RATIOnearinside; /* only used if qh KEEPnearinside */
+  if (qh JOGGLEmax < REALmax/2 && (qh KEEPcoplanar || qh KEEPinside)) {
+    realT maxdist;	       /* adjust qh.NEARinside for joggle */
+    qh KEEPnearinside= True;   
+    maxdist= sqrt (qh hull_dim) * qh JOGGLEmax + qh DISTround;
+    maxdist= 2*maxdist;        /* vertex and coplanar point can joggle in opposite directions */
+    maximize_(qh NEARinside, maxdist);  /* must agree with qh_nearcoplanar() */
+  }
+  if (qh KEEPnearinside)
+    qh_option ("_near-inside", NULL, &qh NEARinside);
+  if (qh JOGGLEmax < qh DISTround) {
+    fprintf (qh ferr, "qhull error: the joggle for 'QJn', %.2g, is below roundoff for distance computations, %.2g\n",
+         qh JOGGLEmax, qh DISTround);
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }
+  if (qh MINvisible > REALmax/2) {
+    if (!qh MERGING)
+      qh MINvisible= qh DISTround;
+    else if (qh hull_dim <= 3)
+      qh MINvisible= qh premerge_centrum;
+    else
+      qh MINvisible= qh_COPLANARratio * qh premerge_centrum;
+    if (qh APPROXhull && qh MINvisible > qh MINoutside)
+      qh MINvisible= qh MINoutside;
+    qh_option ("Visible-distance", NULL, &qh MINvisible);
+  }
+  if (qh MAXcoplanar > REALmax/2) {
+    qh MAXcoplanar= qh MINvisible;
+    qh_option ("U-coplanar-distance", NULL, &qh MAXcoplanar);
+  }
+  if (!qh APPROXhull) {             /* user may specify qh MINoutside */
+    qh MINoutside= 2 * qh MINvisible;
+    if (qh premerge_cos < REALmax/2) 
+      maximize_(qh MINoutside, (1- qh premerge_cos) * qh MAXabs_coord);
+    qh_option ("Width-outside", NULL, &qh MINoutside);
+  }
+  qh WIDEfacet= qh MINoutside;
+  maximize_(qh WIDEfacet, qh_WIDEcoplanar * qh MAXcoplanar); 
+  maximize_(qh WIDEfacet, qh_WIDEcoplanar * qh MINvisible); 
+  qh_option ("_wide-facet", NULL, &qh WIDEfacet);
+  if (qh MINvisible > qh MINoutside + 3 * REALepsilon 
+  && !qh BESToutside && !qh FORCEoutput)
+    fprintf (qh ferr, "qhull input warning: minimum visibility V%.2g is greater than \nminimum outside W%.2g.  Flipped facets are likely.\n",
+	     qh MINvisible, qh MINoutside);
+  qh max_vertex= qh DISTround;
+  qh min_vertex= -qh DISTround;
+  /* numeric constants reported in printsummary */
+} /* detroundoff */
+
+/*---------------------------------
+  
+  qh_detsimplex( apex, points, dim, nearzero )
+    compute determinant of a simplex with point apex and base points
+
+  returns:
+     signed determinant and nearzero from qh_determinant
+
+  notes:
+     uses qh.gm_matrix/qh.gm_row (assumes they're big enough)
+
+  design:
+    construct qm_matrix by subtracting apex from points
+    compute determinate
+*/
+realT qh_detsimplex(pointT *apex, setT *points, int dim, boolT *nearzero) {
+  pointT *coorda, *coordp, *gmcoord, *point, **pointp;
+  coordT **rows;
+  int k,  i=0;
+  realT det;
+
+  zinc_(Zdetsimplex);
+  gmcoord= qh gm_matrix;
+  rows= qh gm_row;
+  FOREACHpoint_(points) {
+    if (i == dim)
+      break;
+    rows[i++]= gmcoord;
+    coordp= point;
+    coorda= apex;
+    for (k= dim; k--; )
+      *(gmcoord++)= *coordp++ - *coorda++;
+  }
+  if (i < dim) {
+    fprintf (qh ferr, "qhull internal error (qh_detsimplex): #points %d < dimension %d\n", 
+               i, dim);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  det= qh_determinant (rows, dim, nearzero);
+  trace2((qh ferr, "qh_detsimplex: det=%2.2g for point p%d, dim %d, nearzero? %d\n",
+	  det, qh_pointid(apex), dim, *nearzero)); 
+  return det;
+} /* detsimplex */
+
+/*---------------------------------
+  
+  qh_distnorm( dim, point, normal, offset )
+    return distance from point to hyperplane at normal/offset
+
+  returns:
+    dist
+  
+  notes:  
+    dist > 0 if point is outside of hyperplane
+  
+  see:
+    qh_distplane in geom.c
+*/
+realT qh_distnorm (int dim, pointT *point, pointT *normal, realT *offsetp) {
+  coordT *normalp= normal, *coordp= point;
+  realT dist;
+  int k;
+
+  dist= *offsetp;
+  for (k= dim; k--; )
+    dist += *(coordp++) * *(normalp++);
+  return dist;
+} /* distnorm */
+
+/*---------------------------------
+
+  qh_distround ( dimension, maxabs, maxsumabs )
+    compute maximum round-off error for a distance computation
+      to a normalized hyperplane
+    maxabs is the maximum absolute value of a coordinate
+    maxsumabs is the maximum possible sum of absolute coordinate values
+
+  returns:
+    max dist round for REALepsilon
+
+  notes:
+    calculate roundoff error according to
+    Lemma 3.2-1 of Golub and van Loan "Matrix Computation"
+    use sqrt(dim) since one vector is normalized
+      or use maxsumabs since one vector is < 1
+*/
+realT qh_distround (int dimension, realT maxabs, realT maxsumabs) {
+  realT maxdistsum, maxround;
+
+  maxdistsum= sqrt (dimension) * maxabs;
+  minimize_( maxdistsum, maxsumabs);
+  maxround= REALepsilon * (dimension * maxdistsum * 1.01 + maxabs);
+              /* adds maxabs for offset */
+  trace4((qh ferr, "qh_distround: %2.2g maxabs %2.2g maxsumabs %2.2g maxdistsum %2.2g\n",
+	         maxround, maxabs, maxsumabs, maxdistsum));
+  return maxround;
+} /* distround */
+
+/*---------------------------------
+  
+  qh_divzero( numer, denom, mindenom1, zerodiv )
+    divide by a number that's nearly zero
+    mindenom1= minimum denominator for dividing into 1.0
+
+  returns:
+    quotient
+    sets zerodiv and returns 0.0 if it would overflow
+  
+  design:
+    if numer is nearly zero and abs(numer) < abs(denom)
+      return numer/denom
+    else if numer is nearly zero
+      return 0 and zerodiv
+    else if denom/numer non-zero
+      return numer/denom
+    else
+      return 0 and zerodiv
+*/
+realT qh_divzero (realT numer, realT denom, realT mindenom1, boolT *zerodiv) {
+  realT temp, numerx, denomx;
+  
+
+  if (numer < mindenom1 && numer > -mindenom1) {
+    numerx= fabs_(numer);
+    denomx= fabs_(denom);
+    if (numerx < denomx) {
+      *zerodiv= False;
+      return numer/denom;
+    }else {
+      *zerodiv= True;
+      return 0.0;
+    }
+  }
+  temp= denom/numer;
+  if (temp > mindenom1 || temp < -mindenom1) {
+    *zerodiv= False;
+    return numer/denom;
+  }else {
+    *zerodiv= True;
+    return 0.0;
+  }
+} /* divzero */
+  
+
+/*---------------------------------
+
+  qh_facetarea( facet )
+    return area for a facet
+  
+  notes:
+    if non-simplicial, 
+      uses centrum to triangulate facet and sums the projected areas.
+    if (qh DELAUNAY),
+      computes projected area instead for last coordinate
+    assumes facet->normal exists
+    projecting tricoplanar facets to the hyperplane does not appear to make a difference
+  
+  design:
+    if simplicial
+      compute area
+    else
+      for each ridge
+        compute area from centrum to ridge
+    negate area if upper Delaunay facet
+*/
+realT qh_facetarea (facetT *facet) {
+  vertexT *apex;
+  pointT *centrum;
+  realT area= 0.0;
+  ridgeT *ridge, **ridgep;
+
+  if (facet->simplicial) {
+    apex= SETfirstt_(facet->vertices, vertexT);
+    area= qh_facetarea_simplex (qh hull_dim, apex->point, facet->vertices, 
+                    apex, facet->toporient, facet->normal, &facet->offset);
+  }else {
+    if (qh CENTERtype == qh_AScentrum)
+      centrum= facet->center;
+    else
+      centrum= qh_getcentrum (facet);
+    FOREACHridge_(facet->ridges) 
+      area += qh_facetarea_simplex (qh hull_dim, centrum, ridge->vertices, 
+                 NULL, (ridge->top == facet),  facet->normal, &facet->offset);
+    if (qh CENTERtype != qh_AScentrum)
+      qh_memfree (centrum, qh normal_size);
+  }
+  if (facet->upperdelaunay && qh DELAUNAY)
+    area= -area;  /* the normal should be [0,...,1] */
+  trace4((qh ferr, "qh_facetarea: f%d area %2.2g\n", facet->id, area)); 
+  return area;
+} /* facetarea */
+
+/*---------------------------------
+
+  qh_facetarea_simplex( dim, apex, vertices, notvertex, toporient, normal, offset )
+    return area for a simplex defined by 
+      an apex, a base of vertices, an orientation, and a unit normal
+    if simplicial or tricoplanar facet, 
+      notvertex is defined and it is skipped in vertices
+  
+  returns:
+    computes area of simplex projected to plane [normal,offset]
+    returns 0 if vertex too far below plane (qh WIDEfacet)
+      vertex can't be apex of tricoplanar facet
+  
+  notes:
+    if (qh DELAUNAY),
+      computes projected area instead for last coordinate
+    uses qh gm_matrix/gm_row and qh hull_dim
+    helper function for qh_facetarea
+  
+  design:
+    if Notvertex
+      translate simplex to apex
+    else
+      project simplex to normal/offset
+      translate simplex to apex
+    if Delaunay
+      set last row/column to 0 with -1 on diagonal 
+    else
+      set last row to Normal
+    compute determinate
+    scale and flip sign for area
+*/
+realT qh_facetarea_simplex (int dim, coordT *apex, setT *vertices, 
+        vertexT *notvertex,  boolT toporient, coordT *normal, realT *offset) {
+  pointT *coorda, *coordp, *gmcoord;
+  coordT **rows, *normalp;
+  int k,  i=0;
+  realT area, dist;
+  vertexT *vertex, **vertexp;
+  boolT nearzero;
+
+  gmcoord= qh gm_matrix;
+  rows= qh gm_row;
+  FOREACHvertex_(vertices) {
+    if (vertex == notvertex)
+      continue;
+    rows[i++]= gmcoord;
+    coorda= apex;
+    coordp= vertex->point;
+    normalp= normal;
+    if (notvertex) {
+      for (k= dim; k--; )
+	*(gmcoord++)= *coordp++ - *coorda++;
+    }else {
+      dist= *offset;
+      for (k= dim; k--; )
+	dist += *coordp++ * *normalp++;
+      if (dist < -qh WIDEfacet) {
+	zinc_(Znoarea);
+	return 0.0;
+      }
+      coordp= vertex->point;
+      normalp= normal;
+      for (k= dim; k--; )
+	*(gmcoord++)= (*coordp++ - dist * *normalp++) - *coorda++;
+    }
+  }
+  if (i != dim-1) {
+    fprintf (qh ferr, "qhull internal error (qh_facetarea_simplex): #points %d != dim %d -1\n", 
+               i, dim);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  rows[i]= gmcoord;
+  if (qh DELAUNAY) {
+    for (i= 0; i < dim-1; i++)
+      rows[i][dim-1]= 0.0;
+    for (k= dim; k--; )
+      *(gmcoord++)= 0.0;
+    rows[dim-1][dim-1]= -1.0;
+  }else {
+    normalp= normal;
+    for (k= dim; k--; )
+      *(gmcoord++)= *normalp++;
+  }
+  zinc_(Zdetsimplex);
+  area= qh_determinant (rows, dim, &nearzero);
+  if (toporient)
+    area= -area;
+  area *= qh AREAfactor;
+  trace4((qh ferr, "qh_facetarea_simplex: area=%2.2g for point p%d, toporient %d, nearzero? %d\n",
+	  area, qh_pointid(apex), toporient, nearzero)); 
+  return area;
+} /* facetarea_simplex */
+
+/*---------------------------------
+  
+  qh_facetcenter( vertices )
+    return Voronoi center (Voronoi vertex) for a facet's vertices
+
+  returns:
+    return temporary point equal to the center
+    
+  see:
+    qh_voronoi_center()
+*/
+pointT *qh_facetcenter (setT *vertices) {
+  setT *points= qh_settemp (qh_setsize (vertices));
+  vertexT *vertex, **vertexp;
+  pointT *center;
+  
+  FOREACHvertex_(vertices) 
+    qh_setappend (&points, vertex->point);
+  center= qh_voronoi_center (qh hull_dim-1, points);
+  qh_settempfree (&points);
+  return center;
+} /* facetcenter */
+
+/*---------------------------------
+  
+  qh_findgooddist( point, facetA, dist, facetlist )
+    find best good facet visible for point from facetA
+    assumes facetA is visible from point
+
+  returns:
+    best facet, i.e., good facet that is furthest from point
+      distance to best facet
+      NULL if none
+      
+    moves good, visible facets (and some other visible facets)
+      to end of qh facet_list
+
+  notes:
+    uses qh visit_id
+
+  design:
+    initialize bestfacet if facetA is good
+    move facetA to end of facetlist
+    for each facet on facetlist
+      for each unvisited neighbor of facet
+        move visible neighbors to end of facetlist
+        update best good neighbor
+        if no good neighbors, update best facet
+*/
+facetT *qh_findgooddist (pointT *point, facetT *facetA, realT *distp, 
+               facetT **facetlist) {
+  realT bestdist= -REALmax, dist;
+  facetT *neighbor, **neighborp, *bestfacet=NULL, *facet;
+  boolT goodseen= False;  
+
+  if (facetA->good) {
+    zinc_(Zcheckpart);  /* calls from check_bestdist occur after print stats */
+    qh_distplane (point, facetA, &bestdist);
+    bestfacet= facetA;
+    goodseen= True;
+  }
+  qh_removefacet (facetA);
+  qh_appendfacet (facetA);
+  *facetlist= facetA;
+  facetA->visitid= ++qh visit_id;
+  FORALLfacet_(*facetlist) {
+    FOREACHneighbor_(facet) {
+      if (neighbor->visitid == qh visit_id)
+        continue;
+      neighbor->visitid= qh visit_id;
+      if (goodseen && !neighbor->good)
+        continue;
+      zinc_(Zcheckpart); 
+      qh_distplane (point, neighbor, &dist);
+      if (dist > 0) {
+        qh_removefacet (neighbor);
+        qh_appendfacet (neighbor);
+        if (neighbor->good) {
+          goodseen= True;
+          if (dist > bestdist) {
+            bestdist= dist;
+            bestfacet= neighbor;
+          }
+        }
+      }
+    }
+  }
+  if (bestfacet) {
+    *distp= bestdist;
+    trace2((qh ferr, "qh_findgooddist: p%d is %2.2g above good facet f%d\n",
+      qh_pointid(point), bestdist, bestfacet->id));
+    return bestfacet;
+  }
+  trace4((qh ferr, "qh_findgooddist: no good facet for p%d above f%d\n", 
+      qh_pointid(point), facetA->id));
+  return NULL;
+}  /* findgooddist */
+    
+/*---------------------------------
+  
+  qh_getarea( facetlist )
+    set area of all facets in facetlist
+    collect statistics
+
+  returns:
+    sets qh totarea/totvol to total area and volume of convex hull
+    for Delaunay triangulation, computes projected area of the lower or upper hull
+      ignores upper hull if qh ATinfinity
+  
+  notes:
+    could compute outer volume by expanding facet area by rays from interior
+    the following attempt at perpendicular projection underestimated badly:
+      qh.totoutvol += (-dist + facet->maxoutside + qh DISTround) 
+                            * area/ qh hull_dim;
+  design:
+    for each facet on facetlist
+      compute facet->area
+      update qh.totarea and qh.totvol
+*/
+void qh_getarea (facetT *facetlist) {
+  realT area;
+  realT dist;
+  facetT *facet;
+
+  if (qh REPORTfreq)
+    fprintf (qh ferr, "computing area of each facet and volume of the convex hull\n");
+  else 
+    trace1((qh ferr, "qh_getarea: computing volume and area for each facet\n"));
+  qh totarea= qh totvol= 0.0;
+  FORALLfacet_(facetlist) {
+    if (!facet->normal)
+      continue;
+    if (facet->upperdelaunay && qh ATinfinity)
+      continue;
+    facet->f.area= area= qh_facetarea (facet);
+    facet->isarea= True;
+    if (qh DELAUNAY) {
+      if (facet->upperdelaunay == qh UPPERdelaunay)
+	qh totarea += area;
+    }else {
+      qh totarea += area;
+      qh_distplane (qh interior_point, facet, &dist);
+      qh totvol += -dist * area/ qh hull_dim;
+    }
+    if (qh PRINTstatistics) {
+      wadd_(Wareatot, area);
+      wmax_(Wareamax, area);
+      wmin_(Wareamin, area);
+    }
+  }
+} /* getarea */
+
+/*---------------------------------
+  
+  qh_gram_schmidt( dim, row )
+    implements Gram-Schmidt orthogonalization by rows
+
+  returns:
+    false if zero norm
+    overwrites rows[dim][dim]
+
+  notes:
+    see Golub & van Loan Algorithm 6.2-2
+    overflow due to small divisors not handled
+
+  design:
+    for each row
+      compute norm for row
+      if non-zero, normalize row
+      for each remaining rowA
+        compute inner product of row and rowA
+        reduce rowA by row * inner product
+*/
+boolT qh_gram_schmidt(int dim, realT **row) {
+  realT *rowi, *rowj, norm;
+  int i, j, k;
+  
+  for(i=0; i < dim; i++) {
+    rowi= row[i];
+    for (norm= 0.0, k= dim; k--; rowi++)
+      norm += *rowi * *rowi;
+    norm= sqrt(norm);
+    wmin_(Wmindenom, norm);
+    if (norm == 0.0)  /* either 0 or overflow due to sqrt */
+      return False;
+    for(k= dim; k--; )
+      *(--rowi) /= norm;  
+    for(j= i+1; j < dim; j++) {
+      rowj= row[j];
+      for(norm= 0.0, k=dim; k--; )
+	norm += *rowi++ * *rowj++;
+      for(k=dim; k--; )
+	*(--rowj) -= *(--rowi) * norm;
+    }
+  }
+  return True;
+} /* gram_schmidt */
+
+
+/*---------------------------------
+  
+  qh_inthresholds( normal, angle )
+    return True if normal within qh.lower_/upper_threshold
+
+  returns:
+    estimate of angle by summing of threshold diffs
+      angle may be NULL
+      smaller "angle" is better
+  
+  notes:
+    invalid if qh.SPLITthresholds
+
+  see:
+    qh.lower_threshold in qh_initbuild()
+    qh_initthresholds()
+
+  design:
+    for each dimension
+      test threshold
+*/
+boolT qh_inthresholds (coordT *normal, realT *angle) {
+  boolT within= True;
+  int k;
+  realT threshold;
+
+  if (angle)
+    *angle= 0.0;
+  for(k= 0; k < qh hull_dim; k++) {
+    threshold= qh lower_threshold[k];
+    if (threshold > -REALmax/2) {
+      if (normal[k] < threshold)
+        within= False;
+      if (angle) {
+	threshold -= normal[k];
+	*angle += fabs_(threshold);
+      }
+    }
+    if (qh upper_threshold[k] < REALmax/2) {
+      threshold= qh upper_threshold[k];
+      if (normal[k] > threshold)
+        within= False;
+      if (angle) {
+	threshold -= normal[k];
+	*angle += fabs_(threshold);
+      }
+    }
+  }
+  return within;
+} /* inthresholds */
+    
+
+/*---------------------------------
+  
+  qh_joggleinput()
+    randomly joggle input to Qhull by qh.JOGGLEmax
+    initial input is qh.first_point/qh.num_points of qh.hull_dim
+      repeated calls use qh.input_points/qh.num_points
+ 
+  returns:
+    joggles points at qh.first_point/qh.num_points
+    copies data to qh.input_points/qh.input_malloc if first time
+    determines qh.JOGGLEmax if it was zero
+    if qh.DELAUNAY
+      computes the Delaunay projection of the joggled points
+
+  notes:
+    if qh.DELAUNAY, unnecessarily joggles the last coordinate
+    the initial 'QJn' may be set larger than qh_JOGGLEmaxincrease
+
+  design:
+    if qh.DELAUNAY
+      set qh.SCALElast for reduced precision errors
+    if first call
+      initialize qh.input_points to the original input points
+      if qh.JOGGLEmax == 0
+        determine default qh.JOGGLEmax
+    else
+      increase qh.JOGGLEmax according to qh.build_cnt
+    joggle the input by adding a random number in [-qh.JOGGLEmax,qh.JOGGLEmax]
+    if qh.DELAUNAY
+      sets the Delaunay projection
+*/
+void qh_joggleinput (void) {
+  int size, i, seed;
+  coordT *coordp, *inputp;
+  realT randr, randa, randb;
+
+  if (!qh input_points) { /* first call */
+    qh input_points= qh first_point;
+    qh input_malloc= qh POINTSmalloc;
+    size= qh num_points * qh hull_dim * sizeof(coordT);
+    if (!(qh first_point=(coordT*)malloc(size))) {
+      fprintf(qh ferr, "qhull error: insufficient memory to joggle %d points\n",
+          qh num_points);
+      qh_errexit(qh_ERRmem, NULL, NULL);
+    }
+    qh POINTSmalloc= True;
+    if (qh JOGGLEmax == 0.0) {
+      qh JOGGLEmax= qh_detjoggle (qh input_points, qh num_points, qh hull_dim);
+      qh_option ("QJoggle", NULL, &qh JOGGLEmax);
+    }
+  }else {                 /* repeated call */
+    if (!qh RERUN && qh build_cnt > qh_JOGGLEretry) {
+      if (((qh build_cnt-qh_JOGGLEretry-1) % qh_JOGGLEagain) == 0) {
+	realT maxjoggle= qh MAXwidth * qh_JOGGLEmaxincrease;
+	if (qh JOGGLEmax < maxjoggle) {
+	  qh JOGGLEmax *= qh_JOGGLEincrease;
+	  minimize_(qh JOGGLEmax, maxjoggle); 
+	}
+      }
+    }
+    qh_option ("QJoggle", NULL, &qh JOGGLEmax);
+  }
+  if (qh build_cnt > 1 && qh JOGGLEmax > fmax_(qh MAXwidth/4, 0.1)) {
+      fprintf (qh ferr, "qhull error: the current joggle for 'QJn', %.2g, is too large for the width\nof the input.  If possible, recompile Qhull with higher-precision reals.\n",
+	        qh JOGGLEmax);
+      qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  /* for some reason, using qh ROTATErandom and qh_RANDOMseed does not repeat the run. Use 'TRn' instead */
+  seed= qh_RANDOMint;
+  qh_option ("_joggle-seed", &seed, NULL);
+  trace0((qh ferr, "qh_joggleinput: joggle input by %2.2g with seed %d\n", 
+    qh JOGGLEmax, seed));
+  inputp= qh input_points;
+  coordp= qh first_point;
+  randa= 2.0 * qh JOGGLEmax/qh_RANDOMmax;
+  randb= -qh JOGGLEmax;
+  size= qh num_points * qh hull_dim;
+  for (i= size; i--; ) {
+    randr= qh_RANDOMint;
+    *(coordp++)= *(inputp++) + (randr * randa + randb);
+  }
+  if (qh DELAUNAY) {
+    qh last_low= qh last_high= qh last_newhigh= REALmax;
+    qh_setdelaunay (qh hull_dim, qh num_points, qh first_point);
+  }
+} /* joggleinput */
+
+/*---------------------------------
+  
+  qh_maxabsval( normal, dim )
+    return pointer to maximum absolute value of a dim vector
+    returns NULL if dim=0
+*/
+realT *qh_maxabsval (realT *normal, int dim) {
+  realT maxval= -REALmax;
+  realT *maxp= NULL, *colp, absval;
+  int k;
+
+  for (k= dim, colp= normal; k--; colp++) {
+    absval= fabs_(*colp);
+    if (absval > maxval) {
+      maxval= absval;
+      maxp= colp;
+    }
+  }
+  return maxp;
+} /* maxabsval */
+
+
+/*---------------------------------
+  
+  qh_maxmin( points, numpoints, dimension )
+    return max/min points for each dimension      
+    determine max and min coordinates
+
+  returns:
+    returns a temporary set of max and min points
+      may include duplicate points. Does not include qh.GOODpoint
+    sets qh.NEARzero, qh.MAXabs_coord, qh.MAXsumcoord, qh.MAXwidth
+         qh.MAXlastcoord, qh.MINlastcoord
+    initializes qh.max_outside, qh.min_vertex, qh.WAScoplanar, qh.ZEROall_ok
+
+  notes:
+    loop duplicated in qh_detjoggle()
+
+  design:
+    initialize global precision variables
+    checks definition of REAL...
+    for each dimension
+      for each point
+        collect maximum and minimum point
+      collect maximum of maximums and minimum of minimums
+      determine qh.NEARzero for Gaussian Elimination
+*/
+setT *qh_maxmin(pointT *points, int numpoints, int dimension) {
+  int k;
+  realT maxcoord, temp;
+  pointT *minimum, *maximum, *point, *pointtemp;
+  setT *set;
+
+  qh max_outside= 0.0;
+  qh MAXabs_coord= 0.0;
+  qh MAXwidth= -REALmax;
+  qh MAXsumcoord= 0.0;
+  qh min_vertex= 0.0;
+  qh WAScoplanar= False;
+  if (qh ZEROcentrum)
+    qh ZEROall_ok= True;
+  if (REALmin < REALepsilon && REALmin < REALmax && REALmin > -REALmax
+  && REALmax > 0.0 && -REALmax < 0.0)
+    ; /* all ok */
+  else {
+    fprintf (qh ferr, "qhull error: floating point constants in user.h are wrong\n\
+REALepsilon %g REALmin %g REALmax %g -REALmax %g\n",
+	     REALepsilon, REALmin, REALmax, -REALmax);
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }
+  set= qh_settemp(2*dimension);
+  for(k= 0; k < dimension; k++) {
+    if (points == qh GOODpointp)
+      minimum= maximum= points + dimension;
+    else
+      minimum= maximum= points;
+    FORALLpoint_(points, numpoints) {
+      if (point == qh GOODpointp)
+	continue;
+      if (maximum[k] < point[k])
+	maximum= point;
+      else if (minimum[k] > point[k])
+	minimum= point;
+    }
+    if (k == dimension-1) {
+      qh MINlastcoord= minimum[k];
+      qh MAXlastcoord= maximum[k];
+    }
+    if (qh SCALElast && k == dimension-1)
+      maxcoord= qh MAXwidth;
+    else {
+      maxcoord= fmax_(maximum[k], -minimum[k]);
+      if (qh GOODpointp) {
+        temp= fmax_(qh GOODpointp[k], -qh GOODpointp[k]);
+        maximize_(maxcoord, temp);
+      }
+      temp= maximum[k] - minimum[k];
+      maximize_(qh MAXwidth, temp);
+    }
+    maximize_(qh MAXabs_coord, maxcoord);
+    qh MAXsumcoord += maxcoord;
+    qh_setappend (&set, maximum);
+    qh_setappend (&set, minimum);
+    /* calculation of qh NEARzero is based on error formula 4.4-13 of
+       Golub & van Loan, authors say n^3 can be ignored and 10 be used in
+       place of rho */
+    qh NEARzero[k]= 80 * qh MAXsumcoord * REALepsilon;
+  }
+  if (qh IStracing >=1)
+    qh_printpoints (qh ferr, "qh_maxmin: found the max and min points (by dim):", set);
+  return(set);
+} /* maxmin */
+
+/*---------------------------------
+
+  qh_maxouter()
+    return maximum distance from facet to outer plane
+    normally this is qh.max_outside+qh.DISTround
+    does not include qh.JOGGLEmax
+
+  see:
+    qh_outerinner()
+    
+  notes:
+    need to add another qh.DISTround if testing actual point with computation
+
+  for joggle:
+    qh_setfacetplane() updated qh.max_outer for Wnewvertexmax (max distance to vertex)
+    need to use Wnewvertexmax since could have a coplanar point for a high 
+      facet that is replaced by a low facet
+    need to add qh.JOGGLEmax if testing input points
+*/
+realT qh_maxouter (void) {
+  realT dist;
+
+  dist= fmax_(qh max_outside, qh DISTround);
+  dist += qh DISTround;
+  trace4((qh ferr, "qh_maxouter: max distance from facet to outer plane is %2.2g max_outside is %2.2g\n", dist, qh max_outside));
+  return dist;
+} /* maxouter */
+
+/*---------------------------------
+  
+  qh_maxsimplex( dim, maxpoints, points, numpoints, simplex )
+    determines maximum simplex for a set of points 
+    starts from points already in simplex
+    skips qh.GOODpointp (assumes that it isn't in maxpoints)
+  
+  returns:
+    simplex with dim+1 points
+
+  notes:
+    assumes at least pointsneeded points in points
+    maximizes determinate for x,y,z,w, etc.
+    uses maxpoints as long as determinate is clearly non-zero
+
+  design:
+    initialize simplex with at least two points
+      (find points with max or min x coordinate)
+    for each remaining dimension
+      add point that maximizes the determinate
+        (use points from maxpoints first)    
+*/
+void qh_maxsimplex (int dim, setT *maxpoints, pointT *points, int numpoints, setT **simplex) {
+  pointT *point, **pointp, *pointtemp, *maxpoint, *minx=NULL, *maxx=NULL;
+  boolT nearzero, maxnearzero= False;
+  int k, sizinit;
+  realT maxdet= -REALmax, det, mincoord= REALmax, maxcoord= -REALmax;
+
+  sizinit= qh_setsize (*simplex);
+  if (sizinit < 2) {
+    if (qh_setsize (maxpoints) >= 2) {
+      FOREACHpoint_(maxpoints) {
+        if (maxcoord < point[0]) {
+          maxcoord= point[0];
+          maxx= point;
+        }
+	if (mincoord > point[0]) {
+          mincoord= point[0];
+          minx= point;
+        }
+      }
+    }else {
+      FORALLpoint_(points, numpoints) {
+	if (point == qh GOODpointp)
+	  continue;
+        if (maxcoord < point[0]) {
+	  maxcoord= point[0];
+          maxx= point;
+        }
+	if (mincoord > point[0]) {
+          mincoord= point[0];
+          minx= point;
+	}
+      }
+    }
+    qh_setunique (simplex, minx);
+    if (qh_setsize (*simplex) < 2)
+      qh_setunique (simplex, maxx);
+    sizinit= qh_setsize (*simplex);
+    if (sizinit < 2) {
+      qh_precision ("input has same x coordinate");
+      if (zzval_(Zsetplane) > qh hull_dim+1) {
+	fprintf (qh ferr, "qhull precision error (qh_maxsimplex for voronoi_center):\n%d points with the same x coordinate.\n",
+		 qh_setsize(maxpoints)+numpoints);
+	qh_errexit (qh_ERRprec, NULL, NULL);
+      }else {
+	fprintf (qh ferr, "qhull input error: input is less than %d-dimensional since it has the same x coordinate\n", qh hull_dim);
+	qh_errexit (qh_ERRinput, NULL, NULL);
+      }
+    }
+  }
+  for(k= sizinit; k < dim+1; k++) {
+    maxpoint= NULL;
+    maxdet= -REALmax;
+    FOREACHpoint_(maxpoints) {
+      if (!qh_setin (*simplex, point)) {
+        det= qh_detsimplex(point, *simplex, k, &nearzero);
+        if ((det= fabs_(det)) > maxdet) {
+	  maxdet= det;
+          maxpoint= point;
+	  maxnearzero= nearzero;
+        }
+      }
+    }
+    if (!maxpoint || maxnearzero) {
+      zinc_(Zsearchpoints);
+      if (!maxpoint) {
+        trace0((qh ferr, "qh_maxsimplex: searching all points for %d-th initial vertex.\n", k+1));
+      }else {
+        trace0((qh ferr, "qh_maxsimplex: searching all points for %d-th initial vertex, better than p%d det %2.2g\n",
+		k+1, qh_pointid(maxpoint), maxdet));
+      }
+      FORALLpoint_(points, numpoints) {
+	if (point == qh GOODpointp)
+	  continue;
+        if (!qh_setin (*simplex, point)) {
+          det= qh_detsimplex(point, *simplex, k, &nearzero);
+          if ((det= fabs_(det)) > maxdet) {
+	    maxdet= det;
+            maxpoint= point;
+	    maxnearzero= nearzero;
+	  }
+        }
+      }
+    } /* !maxpoint */
+    if (!maxpoint) {
+      fprintf (qh ferr, "qhull internal error (qh_maxsimplex): not enough points available\n");
+      qh_errexit (qh_ERRqhull, NULL, NULL);
+    }
+    qh_setappend(simplex, maxpoint);
+    trace1((qh ferr, "qh_maxsimplex: selected point p%d for %d`th initial vertex, det=%2.2g\n",
+	    qh_pointid(maxpoint), k+1, maxdet));
+  } /* k */ 
+} /* maxsimplex */
+
+/*---------------------------------
+  
+  qh_minabsval( normal, dim )
+    return minimum absolute value of a dim vector
+*/
+realT qh_minabsval (realT *normal, int dim) {
+  realT minval= 0;
+  realT maxval= 0;
+  realT *colp;
+  int k;
+
+  for (k= dim, colp= normal; k--; colp++) {
+    maximize_(maxval, *colp);
+    minimize_(minval, *colp);
+  }
+  return fmax_(maxval, -minval);
+} /* minabsval */
+
+
+/*---------------------------------
+  
+  qh_mindif( vecA, vecB, dim )
+    return index of min abs. difference of two vectors
+*/
+int qh_mindiff (realT *vecA, realT *vecB, int dim) {
+  realT mindiff= REALmax, diff;
+  realT *vecAp= vecA, *vecBp= vecB;
+  int k, mink= 0;
+
+  for (k= 0; k < dim; k++) {
+    diff= *vecAp++ - *vecBp++;
+    diff= fabs_(diff);
+    if (diff < mindiff) {
+      mindiff= diff;
+      mink= k;
+    }
+  }
+  return mink;
+} /* mindiff */
+
+
+
+/*---------------------------------
+  
+  qh_orientoutside( facet  )
+    make facet outside oriented via qh.interior_point
+
+  returns:
+    True if facet reversed orientation.
+*/
+boolT qh_orientoutside (facetT *facet) {
+  int k;
+  realT dist;
+
+  qh_distplane (qh interior_point, facet, &dist);
+  if (dist > 0) {
+    for (k= qh hull_dim; k--; )
+      facet->normal[k]= -facet->normal[k];
+    facet->offset= -facet->offset;
+    return True;
+  }
+  return False;
+} /* orientoutside */
+
+/*---------------------------------
+  
+  qh_outerinner( facet, outerplane, innerplane  )
+    if facet and qh.maxoutdone (i.e., qh_check_maxout)
+      returns outer and inner plane for facet
+    else
+      returns maximum outer and inner plane
+    accounts for qh.JOGGLEmax
+
+  see:
+    qh_maxouter(), qh_check_bestdist(), qh_check_points()
+
+  notes:
+    outerplaner or innerplane may be NULL
+    
+    includes qh.DISTround for actual points
+    adds another qh.DISTround if testing with floating point arithmetic
+*/
+void qh_outerinner (facetT *facet, realT *outerplane, realT *innerplane) {
+  realT dist, mindist;
+  vertexT *vertex, **vertexp;
+
+  if (outerplane) {
+    if (!qh_MAXoutside || !facet || !qh maxoutdone) {
+      *outerplane= qh_maxouter();       /* includes qh.DISTround */
+    }else { /* qh_MAXoutside ... */
+#if qh_MAXoutside 
+      *outerplane= facet->maxoutside + qh DISTround;
+#endif
+      
+    }
+    if (qh JOGGLEmax < REALmax/2)
+      *outerplane += qh JOGGLEmax * sqrt (qh hull_dim);
+  }
+  if (innerplane) {
+    if (facet) {
+      mindist= REALmax;
+      FOREACHvertex_(facet->vertices) {
+        zinc_(Zdistio);
+        qh_distplane (vertex->point, facet, &dist);
+        minimize_(mindist, dist);
+      }
+      *innerplane= mindist - qh DISTround;
+    }else 
+      *innerplane= qh min_vertex - qh DISTround;
+    if (qh JOGGLEmax < REALmax/2)
+      *innerplane -= qh JOGGLEmax * sqrt (qh hull_dim);
+  }
+} /* outerinner */
+
+/*---------------------------------
+  
+  qh_pointdist( point1, point2, dim )
+    return distance between two points
+
+  notes:
+    returns distance squared if 'dim' is negative
+*/
+coordT qh_pointdist(pointT *point1, pointT *point2, int dim) {
+  coordT dist, diff;
+  int k;
+  
+  dist= 0.0;
+  for (k= (dim > 0 ? dim : -dim); k--; ) {
+    diff= *point1++ - *point2++;
+    dist += diff * diff;
+  }
+  if (dim > 0)
+    return(sqrt(dist));
+  return dist;
+} /* pointdist */
+
+
+/*---------------------------------
+  
+  qh_printmatrix( fp, string, rows, numrow, numcol )
+    print matrix to fp given by row vectors
+    print string as header
+
+  notes:
+    print a vector by qh_printmatrix(fp, "", &vect, 1, len)
+*/
+void qh_printmatrix (FILE *fp, char *string, realT **rows, int numrow, int numcol) {
+  realT *rowp;
+  realT r; /*bug fix*/
+  int i,k;
+
+  fprintf (fp, "%s\n", string);
+  for (i= 0; i < numrow; i++) {
+    rowp= rows[i];
+    for (k= 0; k < numcol; k++) {
+      r= *rowp++;
+      fprintf (fp, "%6.3g ", r);
+    }
+    fprintf (fp, "\n");
+  }
+} /* printmatrix */
+
+  
+/*---------------------------------
+  
+  qh_printpoints( fp, string, points )
+    print pointids to fp for a set of points
+    if string, prints string and 'p' point ids
+*/
+void qh_printpoints (FILE *fp, char *string, setT *points) {
+  pointT *point, **pointp;
+
+  if (string) {
+    fprintf (fp, "%s", string);
+    FOREACHpoint_(points) 
+      fprintf (fp, " p%d", qh_pointid(point));
+    fprintf (fp, "\n");
+  }else {
+    FOREACHpoint_(points) 
+      fprintf (fp, " %d", qh_pointid(point));
+    fprintf (fp, "\n");
+  }
+} /* printpoints */
+
+  
+/*---------------------------------
+  
+  qh_projectinput()
+    project input points using qh.lower_bound/upper_bound and qh DELAUNAY
+    if qh.lower_bound[k]=qh.upper_bound[k]= 0, 
+      removes dimension k 
+    if halfspace intersection
+      removes dimension k from qh.feasible_point
+    input points in qh first_point, num_points, input_dim
+
+  returns:
+    new point array in qh first_point of qh hull_dim coordinates
+    sets qh POINTSmalloc
+    if qh DELAUNAY 
+      projects points to paraboloid
+      lowbound/highbound is also projected
+    if qh ATinfinity
+      adds point "at-infinity"
+    if qh POINTSmalloc 
+      frees old point array
+
+  notes:
+    checks that qh.hull_dim agrees with qh.input_dim, PROJECTinput, and DELAUNAY
+
+
+  design:
+    sets project[k] to -1 (delete), 0 (keep), 1 (add for Delaunay)
+    determines newdim and newnum for qh hull_dim and qh num_points
+    projects points to newpoints
+    projects qh.lower_bound to itself
+    projects qh.upper_bound to itself
+    if qh DELAUNAY
+      if qh ATINFINITY
+        projects points to paraboloid
+        computes "infinity" point as vertex average and 10% above all points 
+      else
+        uses qh_setdelaunay to project points to paraboloid
+*/
+void qh_projectinput (void) {
+  int k,i;
+  int newdim= qh input_dim, newnum= qh num_points;
+  signed char *project;
+  int size= (qh input_dim+1)*sizeof(*project);
+  pointT *newpoints, *coord, *infinity;
+  realT paraboloid, maxboloid= 0;
+  
+  project= (signed char*)qh_memalloc (size);
+  memset ((char*)project, 0, size);
+  for (k= 0; k < qh input_dim; k++) {   /* skip Delaunay bound */
+    if (qh lower_bound[k] == 0 && qh upper_bound[k] == 0) {
+      project[k]= -1;
+      newdim--;
+    }
+  }
+  if (qh DELAUNAY) {
+    project[k]= 1;
+    newdim++;
+    if (qh ATinfinity)
+      newnum++;
+  }
+  if (newdim != qh hull_dim) {
+    fprintf(qh ferr, "qhull internal error (qh_projectinput): dimension after projection %d != hull_dim %d\n", newdim, qh hull_dim);
+    qh_errexit(qh_ERRqhull, NULL, NULL);
+  }
+  if (!(newpoints=(coordT*)malloc(newnum*newdim*sizeof(coordT)))){
+    fprintf(qh ferr, "qhull error: insufficient memory to project %d points\n",
+           qh num_points);
+    qh_errexit(qh_ERRmem, NULL, NULL);
+  }
+  qh_projectpoints (project, qh input_dim+1, qh first_point,
+                    qh num_points, qh input_dim, newpoints, newdim);
+  trace1((qh ferr, "qh_projectinput: updating lower and upper_bound\n"));
+  qh_projectpoints (project, qh input_dim+1, qh lower_bound,
+                    1, qh input_dim+1, qh lower_bound, newdim+1);
+  qh_projectpoints (project, qh input_dim+1, qh upper_bound,
+                    1, qh input_dim+1, qh upper_bound, newdim+1);
+  if (qh HALFspace) {
+    if (!qh feasible_point) {
+      fprintf(qh ferr, "qhull internal error (qh_projectinput): HALFspace defined without qh.feasible_point\n");
+      qh_errexit(qh_ERRqhull, NULL, NULL);
+    }
+    qh_projectpoints (project, qh input_dim, qh feasible_point,
+		      1, qh input_dim, qh feasible_point, newdim);
+  }
+  qh_memfree(project, ((qh input_dim+1)*sizeof(*project)));
+  if (qh POINTSmalloc)
+    free (qh first_point);
+  qh first_point= newpoints;
+  qh POINTSmalloc= True;
+  if (qh DELAUNAY && qh ATinfinity) {
+    coord= qh first_point;
+    infinity= qh first_point + qh hull_dim * qh num_points;
+    for (k=qh hull_dim-1; k--; )
+      infinity[k]= 0.0;
+    for (i=qh num_points; i--; ) {
+      paraboloid= 0.0;
+      for (k=qh hull_dim-1; k--; ) {
+        paraboloid += *coord * *coord;
+	infinity[k] += *coord;
+        coord++;
+      }
+      *(coord++)= paraboloid;
+      maximize_(maxboloid, paraboloid);
+    }
+    /* coord == infinity */
+    for (k=qh hull_dim-1; k--; )
+      *(coord++) /= qh num_points;
+    *(coord++)= maxboloid * 1.1;
+    qh num_points++;
+    trace0((qh ferr, "qh_projectinput: projected points to paraboloid for Delaunay\n"));
+  }else if (qh DELAUNAY)  /* !qh ATinfinity */
+    qh_setdelaunay( qh hull_dim, qh num_points, qh first_point);
+} /* projectinput */
+
+  
+/*---------------------------------
+  
+  qh_projectpoints( project, n, points, numpoints, dim, newpoints, newdim )
+    project points/numpoints/dim to newpoints/newdim
+    if project[k] == -1
+      delete dimension k 
+    if project[k] == 1 
+      add dimension k by duplicating previous column
+    n is size of project
+
+  notes:
+    newpoints may be points if only adding dimension at end
+
+  design:
+    check that 'project' and 'newdim' agree
+    for each dimension
+      if project == -1
+        skip dimension
+      else
+        determine start of column in newpoints
+        determine start of column in points 
+          if project == +1, duplicate previous column
+        copy dimension (column) from points to newpoints
+*/
+void qh_projectpoints (signed char *project, int n, realT *points, 
+        int numpoints, int dim, realT *newpoints, int newdim) {
+  int testdim= dim, oldk=0, newk=0, i,j=0,k;
+  realT *newp, *oldp;
+  
+  for (k= 0; k < n; k++)
+    testdim += project[k];
+  if (testdim != newdim) {
+    fprintf (qh ferr, "qhull internal error (qh_projectpoints): newdim %d should be %d after projection\n",
+      newdim, testdim);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  for (j= 0; j= dim)
+	  continue;
+	oldp= points+oldk;
+      }else 
+	oldp= points+oldk++;
+      for (i=numpoints; i--; ) {
+        *newp= *oldp;
+        newp += newdim;
+        oldp += dim;
+      }
+    }
+    if (oldk >= dim)
+      break;
+  }
+  trace1((qh ferr, "qh_projectpoints: projected %d points from dim %d to dim %d\n", 
+    numpoints, dim, newdim));
+} /* projectpoints */
+        
+
+/*---------------------------------
+  
+  qh_rand() 
+  qh_srand( seed )
+    generate pseudo-random number between 1 and 2^31 -2
+
+  notes:
+    from Park & Miller's minimimal standard random number generator
+       Communications of the ACM, 31:1192-1201, 1988.
+    does not use 0 or 2^31 -1
+       this is silently enforced by qh_srand()
+    can make 'Rn' much faster by moving qh_rand to qh_distplane
+*/
+int qh_rand_seed= 1;  /* define as global variable instead of using qh */
+
+int qh_rand( void) {
+#define qh_rand_a 16807
+#define qh_rand_m 2147483647
+#define qh_rand_q 127773  /* m div a */
+#define qh_rand_r 2836    /* m mod a */
+  int lo, hi, test;
+  int seed = qh_rand_seed;
+
+  hi = seed / qh_rand_q;  /* seed div q */
+  lo = seed % qh_rand_q;  /* seed mod q */
+  test = qh_rand_a * lo - qh_rand_r * hi;
+  if (test > 0)
+    seed= test;
+  else
+    seed= test + qh_rand_m;
+  qh_rand_seed= seed;
+  /* seed = seed < qh_RANDOMmax/2 ? 0 : qh_RANDOMmax;  for testing */
+  /* seed = qh_RANDOMmax;  for testing */
+  return seed;
+} /* rand */
+
+void qh_srand( int seed) {
+  if (seed < 1)
+    qh_rand_seed= 1;
+  else if (seed >= qh_rand_m)
+    qh_rand_seed= qh_rand_m - 1;
+  else
+    qh_rand_seed= seed;
+} /* qh_srand */
+
+/*---------------------------------
+  
+  qh_randomfactor()
+    return a random factor within qh.RANDOMmax of 1.0
+
+  notes:
+    qh.RANDOMa/b are defined in global.c
+*/
+realT qh_randomfactor (void) {
+  realT randr;
+
+  randr= qh_RANDOMint;
+  return randr * qh RANDOMa + qh RANDOMb;
+} /* randomfactor */
+
+/*---------------------------------
+  
+  qh_randommatrix( buffer, dim, rows )
+    generate a random dim X dim matrix in range [-1,1]
+    assumes buffer is [dim+1, dim]
+
+  returns:
+    sets buffer to random numbers
+    sets rows to rows of buffer
+      sets row[dim] as scratch row
+*/
+void qh_randommatrix (realT *buffer, int dim, realT **rows) {
+  int i, k;
+  realT **rowi, *coord, realr;
+
+  coord= buffer;
+  rowi= rows;
+  for (i=0; i < dim; i++) {
+    *(rowi++)= coord;
+    for (k=0; k < dim; k++) {
+      realr= qh_RANDOMint;
+      *(coord++)= 2.0 * realr/(qh_RANDOMmax+1) - 1.0;
+    }
+  }
+  *rowi= coord;
+} /* randommatrix */
+
+        
+/*---------------------------------
+  
+  qh_rotateinput( rows )
+    rotate input using row matrix
+    input points given by qh first_point, num_points, hull_dim
+    assumes rows[dim] is a scratch buffer
+    if qh POINTSmalloc, overwrites input points, else mallocs a new array
+
+  returns:
+    rotated input
+    sets qh POINTSmalloc
+
+  design:
+    see qh_rotatepoints
+*/
+void qh_rotateinput (realT **rows) {
+
+  if (!qh POINTSmalloc) {
+    qh first_point= qh_copypoints (qh first_point, qh num_points, qh hull_dim);
+    qh POINTSmalloc= True;
+  }
+  qh_rotatepoints (qh first_point, qh num_points, qh hull_dim, rows);
+}  /* rotateinput */
+
+/*---------------------------------
+  
+  qh_rotatepoints( points, numpoints, dim, row )
+    rotate numpoints points by a d-dim row matrix
+    assumes rows[dim] is a scratch buffer
+
+  returns:
+    rotated points in place
+
+  design:
+    for each point
+      for each coordinate
+        use row[dim] to compute partial inner product
+      for each coordinate
+        rotate by partial inner product
+*/
+void qh_rotatepoints (realT *points, int numpoints, int dim, realT **row) {
+  realT *point, *rowi, *coord= NULL, sum, *newval;
+  int i,j,k;
+
+  if (qh IStracing >= 1)
+    qh_printmatrix (qh ferr, "qh_rotatepoints: rotate points by", row, dim, dim);
+  for (point= points, j= numpoints; j--; point += dim) {
+    newval= row[dim];
+    for (i= 0; i < dim; i++) {
+      rowi= row[i];
+      coord= point;
+      for (sum= 0.0, k= dim; k--; )
+        sum += *rowi++ * *coord++;
+      *(newval++)= sum;
+    }
+    for (k= dim; k--; )
+      *(--coord)= *(--newval);
+  }
+} /* rotatepoints */  
+  
+
+/*---------------------------------
+  
+  qh_scaleinput()
+    scale input points using qh low_bound/high_bound
+    input points given by qh first_point, num_points, hull_dim
+    if qh POINTSmalloc, overwrites input points, else mallocs a new array
+
+  returns:
+    scales coordinates of points to low_bound[k], high_bound[k]
+    sets qh POINTSmalloc
+
+  design:
+    see qh_scalepoints
+*/
+void qh_scaleinput (void) {
+
+  if (!qh POINTSmalloc) {
+    qh first_point= qh_copypoints (qh first_point, qh num_points, qh hull_dim);
+    qh POINTSmalloc= True;
+  }
+  qh_scalepoints (qh first_point, qh num_points, qh hull_dim,
+       qh lower_bound, qh upper_bound);
+}  /* scaleinput */
+  
+/*---------------------------------
+  
+  qh_scalelast( points, numpoints, dim, low, high, newhigh )
+    scale last coordinate to [0,m] for Delaunay triangulations
+    input points given by points, numpoints, dim
+
+  returns:
+    changes scale of last coordinate from [low, high] to [0, newhigh]
+    overwrites last coordinate of each point
+    saves low/high/newhigh in qh.last_low, etc. for qh_setdelaunay()
+
+  notes:
+    when called by qh_setdelaunay, low/high may not match actual data
+    
+  design:
+    compute scale and shift factors
+    apply to last coordinate of each point
+*/
+void qh_scalelast (coordT *points, int numpoints, int dim, coordT low,
+		   coordT high, coordT newhigh) {
+  realT scale, shift;
+  coordT *coord;
+  int i;
+  boolT nearzero= False;
+
+  trace4((qh ferr, "qh_scalelast: scale last coordinate from [%2.2g, %2.2g] to [0,%2.2g]\n",
+    low, high, newhigh));
+  qh last_low= low;
+  qh last_high= high;
+  qh last_newhigh= newhigh;
+  scale= qh_divzero (newhigh, high - low,
+                  qh MINdenom_1, &nearzero);
+  if (nearzero) {
+    if (qh DELAUNAY)
+      fprintf (qh ferr, "qhull input error: can not scale last coordinate.  Input is cocircular\n   or cospherical.   Use option 'Qz' to add a point at infinity.\n");
+    else
+      fprintf (qh ferr, "qhull input error: can not scale last coordinate.  New bounds [0, %2.2g] are too wide for\nexisting bounds [%2.2g, %2.2g] (width %2.2g)\n",
+		newhigh, low, high, high-low);
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }
+  shift= - low * newhigh / (high-low);
+  coord= points + dim - 1;
+  for (i= numpoints; i--; coord += dim)
+    *coord= *coord * scale + shift;
+} /* scalelast */
+
+/*---------------------------------
+  
+  qh_scalepoints( points, numpoints, dim, newlows, newhighs )
+    scale points to new lowbound and highbound
+    retains old bound when newlow= -REALmax or newhigh= +REALmax
+
+  returns:
+    scaled points
+    overwrites old points
+
+  design:
+    for each coordinate
+      compute current low and high bound
+      compute scale and shift factors
+      scale all points
+      enforce new low and high bound for all points
+*/
+void qh_scalepoints (pointT *points, int numpoints, int dim,
+	realT *newlows, realT *newhighs) {
+  int i,k;
+  realT shift, scale, *coord, low, high, newlow, newhigh, mincoord, maxcoord;
+  boolT nearzero= False;
+     
+  for (k= 0; k < dim; k++) {
+    newhigh= newhighs[k];
+    newlow= newlows[k];
+    if (newhigh > REALmax/2 && newlow < -REALmax/2)
+      continue;
+    low= REALmax;
+    high= -REALmax;
+    for (i= numpoints, coord= points+k; i--; coord += dim) {
+      minimize_(low, *coord);
+      maximize_(high, *coord);
+    }
+    if (newhigh > REALmax/2)
+      newhigh= high;
+    if (newlow < -REALmax/2)
+      newlow= low;
+    if (qh DELAUNAY && k == dim-1 && newhigh < newlow) {
+      fprintf (qh ferr, "qhull input error: 'Qb%d' or 'QB%d' inverts paraboloid since high bound %.2g < low bound %.2g\n",
+	       k, k, newhigh, newlow);
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }
+    scale= qh_divzero (newhigh - newlow, high - low,
+                  qh MINdenom_1, &nearzero);
+    if (nearzero) {
+      fprintf (qh ferr, "qhull input error: %d'th dimension's new bounds [%2.2g, %2.2g] too wide for\nexisting bounds [%2.2g, %2.2g]\n",
+              k, newlow, newhigh, low, high);
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }
+    shift= (newlow * high - low * newhigh)/(high-low);
+    coord= points+k;
+    for (i= numpoints; i--; coord += dim)
+      *coord= *coord * scale + shift;
+    coord= points+k;
+    if (newlow < newhigh) {
+      mincoord= newlow;
+      maxcoord= newhigh;
+    }else {
+      mincoord= newhigh;
+      maxcoord= newlow;
+    }
+    for (i= numpoints; i--; coord += dim) {
+      minimize_(*coord, maxcoord);  /* because of roundoff error */
+      maximize_(*coord, mincoord);
+    }
+    trace0((qh ferr, "qh_scalepoints: scaled %d'th coordinate [%2.2g, %2.2g] to [%.2g, %.2g] for %d points by %2.2g and shifted %2.2g\n",
+      k, low, high, newlow, newhigh, numpoints, scale, shift));
+  }
+} /* scalepoints */    
+
+       
+/*---------------------------------
+  
+  qh_setdelaunay( dim, count, points )
+    project count points to dim-d paraboloid for Delaunay triangulation
+    
+    dim is one more than the dimension of the input set
+    assumes dim is at least 3 (i.e., at least a 2-d Delaunay triangulation)
+
+    points is a dim*count realT array.  The first dim-1 coordinates
+    are the coordinates of the first input point.  array[dim] is
+    the first coordinate of the second input point.  array[2*dim] is
+    the first coordinate of the third input point.
+
+    if qh.last_low defined (i.e., 'Qbb' called qh_scalelast)
+      calls qh_scalelast to scale the last coordinate the same as the other points
+
+  returns:
+    for each point
+      sets point[dim-1] to sum of squares of coordinates
+    scale points to 'Qbb' if needed
+      
+  notes:
+    to project one point, use
+      qh_setdelaunay (qh hull_dim, 1, point)
+      
+    Do not use options 'Qbk', 'QBk', or 'QbB' since they scale 
+    the coordinates after the original projection.
+
+*/
+void qh_setdelaunay (int dim, int count, pointT *points) {
+  int i, k;
+  coordT *coordp, coord;
+  realT paraboloid;
+
+  trace0((qh ferr, "qh_setdelaunay: project %d points to paraboloid for Delaunay triangulation\n", count));
+  coordp= points;
+  for (i= 0; i < count; i++) {
+    coord= *coordp++;
+    paraboloid= coord*coord;
+    for (k= dim-2; k--; ) {
+      coord= *coordp++;
+      paraboloid += coord*coord;
+    }
+    *coordp++ = paraboloid;
+  }
+  if (qh last_low < REALmax/2) 
+    qh_scalelast (points, count, dim, qh last_low, qh last_high, qh last_newhigh);
+} /* setdelaunay */
+
+  
+/*---------------------------------
+  
+  qh_sethalfspace( dim, coords, nextp, normal, offset, feasible )
+    set point to dual of halfspace relative to feasible point
+    halfspace is normal coefficients and offset.
+
+  returns:
+    false if feasible point is outside of hull (error message already reported)
+    overwrites coordinates for point at dim coords
+    nextp= next point (coords)
+
+  design:
+    compute distance from feasible point to halfspace
+    divide each normal coefficient by -dist
+*/
+boolT qh_sethalfspace (int dim, coordT *coords, coordT **nextp, 
+         coordT *normal, coordT *offset, coordT *feasible) {
+  coordT *normp= normal, *feasiblep= feasible, *coordp= coords;
+  realT dist;
+  realT r; /*bug fix*/
+  int k;
+  boolT zerodiv;
+
+  dist= *offset;
+  for (k= dim; k--; )
+    dist += *(normp++) * *(feasiblep++);
+  if (dist > 0)
+    goto LABELerroroutside;
+  normp= normal;
+  if (dist < -qh MINdenom) {
+    for (k= dim; k--; )
+      *(coordp++)= *(normp++) / -dist;
+  }else {
+    for (k= dim; k--; ) {
+      *(coordp++)= qh_divzero (*(normp++), -dist, qh MINdenom_1, &zerodiv);
+      if (zerodiv) 
+        goto LABELerroroutside;
+    }
+  }
+  *nextp= coordp;
+  if (qh IStracing >= 4) {
+    fprintf (qh ferr, "qh_sethalfspace: halfspace at offset %6.2g to point: ", *offset);
+    for (k= dim, coordp= coords; k--; ) {
+      r= *coordp++;
+      fprintf (qh ferr, " %6.2g", r);
+    }
+    fprintf (qh ferr, "\n");
+  }
+  return True;
+LABELerroroutside:
+  feasiblep= feasible;
+  normp= normal;
+  fprintf(qh ferr, "qhull input error: feasible point is not clearly inside halfspace\nfeasible point: ");
+  for (k= dim; k--; )
+    fprintf (qh ferr, qh_REAL_1, r=*(feasiblep++));
+  fprintf (qh ferr, "\n     halfspace: "); 
+  for (k= dim; k--; )
+    fprintf (qh ferr, qh_REAL_1, r=*(normp++));
+  fprintf (qh ferr, "\n     at offset: ");
+  fprintf (qh ferr, qh_REAL_1, *offset);
+  fprintf (qh ferr, " and distance: ");
+  fprintf (qh ferr, qh_REAL_1, dist);
+  fprintf (qh ferr, "\n");
+  return False;
+} /* sethalfspace */
+
+/*---------------------------------
+  
+  qh_sethalfspace_all( dim, count, halfspaces, feasible )
+    generate dual for halfspace intersection with feasible point
+    array of count halfspaces
+      each halfspace is normal coefficients followed by offset 
+      the origin is inside the halfspace if the offset is negative
+
+  returns:
+    malloc'd array of count X dim-1 points
+
+  notes:
+    call before qh_init_B or qh_initqhull_globals 
+    unused/untested code: please email bradb@shore.net if this works ok for you
+    If using option 'Fp', also set qh feasible_point. It is a malloc'd array 
+      that is freed by qh_freebuffers.
+
+  design:
+    see qh_sethalfspace
+*/
+coordT *qh_sethalfspace_all (int dim, int count, coordT *halfspaces, pointT *feasible) {
+  int i, newdim;
+  pointT *newpoints;
+  coordT *coordp, *normalp, *offsetp;
+
+  trace0((qh ferr, "qh_sethalfspace_all: compute dual for halfspace intersection\n"));
+  newdim= dim - 1;
+  if (!(newpoints=(coordT*)malloc(count*newdim*sizeof(coordT)))){
+    fprintf(qh ferr, "qhull error: insufficient memory to compute dual of %d halfspaces\n",
+          count);
+    qh_errexit(qh_ERRmem, NULL, NULL);
+  }
+  coordp= newpoints;
+  normalp= halfspaces;
+  for (i= 0; i < count; i++) {
+    offsetp= normalp + newdim;
+    if (!qh_sethalfspace (newdim, coordp, &coordp, normalp, offsetp, feasible)) {
+      fprintf (qh ferr, "The halfspace was at index %d\n", i);
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }
+    normalp= offsetp + 1;
+  }
+  return newpoints;
+} /* sethalfspace_all */
+
+  
+/*---------------------------------
+  
+  qh_sharpnewfacets()
+
+  returns:
+    true if could be an acute angle (facets in different quadrants)
+ 
+  notes:
+    for qh_findbest
+
+  design:
+    for all facets on qh.newfacet_list
+      if two facets are in different quadrants
+        set issharp
+*/
+boolT qh_sharpnewfacets () {
+  facetT *facet;
+  boolT issharp = False;
+  int *quadrant, k;
+  
+  quadrant= (int*)qh_memalloc (qh hull_dim * sizeof(int));
+  FORALLfacet_(qh newfacet_list) {
+    if (facet == qh newfacet_list) {
+      for (k= qh hull_dim; k--; )
+      	quadrant[ k]= (facet->normal[ k] > 0);
+    }else {
+      for (k= qh hull_dim; k--; ) {
+        if (quadrant[ k] != (facet->normal[ k] > 0)) {
+          issharp= True;
+          break;
+        }
+      }
+    }
+    if (issharp)
+      break;
+  }
+  qh_memfree( quadrant, qh hull_dim * sizeof(int));
+  trace3((qh ferr, "qh_sharpnewfacets: %d\n", issharp));
+  return issharp;
+} /* sharpnewfacets */
+
+/*---------------------------------
+  
+  qh_voronoi_center( dim, points )
+    return Voronoi center for a set of points
+    dim is the orginal dimension of the points
+    gh.gm_matrix/qh.gm_row are scratch buffers
+
+  returns:
+    center as a temporary point
+    if non-simplicial, 
+      returns center for max simplex of points
+
+  notes:
+    from Bowyer & Woodwark, A Programmer's Geometry, 1983, p. 65
+
+  design:
+    if non-simplicial
+      determine max simplex for points
+    translate point0 of simplex to origin
+    compute sum of squares of diagonal
+    compute determinate
+    compute Voronoi center (see Bowyer & Woodwark)
+*/
+pointT *qh_voronoi_center (int dim, setT *points) {
+  pointT *point, **pointp, *point0;
+  pointT *center= (pointT*)qh_memalloc (qh center_size);
+  setT *simplex;
+  int i, j, k, size= qh_setsize(points);
+  coordT *gmcoord;
+  realT *diffp, sum2, *sum2row, *sum2p, det, factor;
+  boolT nearzero, infinite;
+
+  if (size == dim+1)
+    simplex= points;
+  else if (size < dim+1) {
+    fprintf (qh ferr, "qhull internal error (qh_voronoi_center):\n  need at least %d points to construct a Voronoi center\n",
+	     dim+1);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }else {
+    simplex= qh_settemp (dim+1);
+    qh_maxsimplex (dim, points, NULL, 0, &simplex);
+  }
+  point0= SETfirstt_(simplex, pointT);
+  gmcoord= qh gm_matrix;
+  for (k=0; k < dim; k++) {
+    qh gm_row[k]= gmcoord;
+    FOREACHpoint_(simplex) {
+      if (point != point0)
+        *(gmcoord++)= point[k] - point0[k];
+    }
+  }
+  sum2row= gmcoord;
+  for (i=0; i < dim; i++) {
+    sum2= 0.0;
+    for (k= 0; k < dim; k++) {
+      diffp= qh gm_row[k] + i;
+      sum2 += *diffp * *diffp;
+    }
+    *(gmcoord++)= sum2;
+  }
+  det= qh_determinant (qh gm_row, dim, &nearzero);
+  factor= qh_divzero (0.5, det, qh MINdenom, &infinite);
+  if (infinite) {
+    for (k=dim; k--; )
+      center[k]= qh_INFINITE;
+    if (qh IStracing)
+      qh_printpoints (qh ferr, "qh_voronoi_center: at infinity for ", simplex);
+  }else {
+    for (i=0; i < dim; i++) {
+      gmcoord= qh gm_matrix;
+      sum2p= sum2row;
+      for (k=0; k < dim; k++) {
+	qh gm_row[k]= gmcoord;
+	if (k == i) {
+	  for (j= dim; j--; )
+	    *(gmcoord++)= *sum2p++;
+	}else {
+	  FOREACHpoint_(simplex) {
+	    if (point != point0)
+	      *(gmcoord++)= point[k] - point0[k];
+	  }
+	}
+      }
+      center[i]= qh_determinant (qh gm_row, dim, &nearzero)*factor + point0[i];
+    }
+#ifndef qh_NOtrace
+    if (qh IStracing >= 3) {
+      fprintf (qh ferr, "qh_voronoi_center: det %2.2g factor %2.2g ", det, factor);
+      qh_printmatrix (qh ferr, "center:", ¢er, 1, dim);
+      if (qh IStracing >= 5) {
+	qh_printpoints (qh ferr, "points", simplex);
+	FOREACHpoint_(simplex)
+	  fprintf (qh ferr, "p%d dist %.2g, ", qh_pointid (point),
+		   qh_pointdist (point, center, dim));
+	fprintf (qh ferr, "\n");
+      }
+    }
+#endif
+  }
+  if (simplex != points)
+    qh_settempfree (&simplex);
+  return center;
+} /* voronoi_center */
+
diff --git a/extern/qhull/src/global.c b/extern/qhull/src/global.c
new file mode 100644
index 00000000000..d3e141aa985
--- /dev/null
+++ b/extern/qhull/src/global.c
@@ -0,0 +1,2018 @@
+/*
  ---------------------------------
+
+   global.c
+   initializes all the globals of the qhull application
+
+   see README
+
+   see qhull.h for qh.globals and function prototypes
+
+   see qhull_a.h for internal functions
+
+   copyright (c) 1993-2002, The Geometry Center
+ */
+
+#include "qhull_a.h"
+
+/*========= qh definition =======================*/
+
+#if qh_QHpointer
+qhT *qh_qh= NULL;	/* pointer to all global variables */
+#else
+qhT qh_qh;     		/* all global variables.
+			   Add "= {0}" if this causes a compiler error.
+			   Also qh_qhstat in stat.c and qhmem in mem.c.  */
+#endif
+
+/*---------------------------------
+
+  qh_appendprint( printFormat )
+    append printFormat to qh.PRINTout unless already defined
+*/
+void qh_appendprint (qh_PRINT format) {
+  int i;
+
+  for (i=0; i < qh_PRINTEND; i++) {
+    if (qh PRINTout[i] == format && format != qh_PRINTqhull)
+      break;
+    if (!qh PRINTout[i]) {
+      qh PRINTout[i]= format;
+      break;
+    }
+  }
+} /* appendprint */
+     
+/*---------------------------------
+  
+  qh_checkflags( commandStr, hiddenFlags )
+    errors if commandStr contains hiddenFlags
+    hiddenFlags starts and ends with a space and is space deliminated (checked)
+
+  notes:
+    ignores first word (e.g., "qconvex i")
+    use qh_strtol/strtod since strtol/strtod may or may not skip trailing spaces
+  
+  see:
+    qh_initflags() initializes Qhull according to commandStr
+*/
+void qh_checkflags(char *command, char *hiddenflags) {
+  char *s= command, *t, *chkerr, key, opt, prevopt;
+  char chkkey[]= "   ";
+  char chkopt[]=  "    ";
+  char chkopt2[]= "     ";
+
+  if (*hiddenflags != ' ' || hiddenflags[strlen(hiddenflags)-1] != ' ') {
+    fprintf(qh ferr, "qhull error (qh_checkflags): hiddenflags must start and end with a space: \"%s\"", hiddenflags);
+    qh_errexit(qh_ERRinput, NULL, NULL);
+  }
+  if (strpbrk(hiddenflags, ",\n\r\t")) { 
+    fprintf(qh ferr, "qhull error (qh_checkflags): hiddenflags contains commas, newlines, or tabs: \"%s\"", hiddenflags);
+    qh_errexit(qh_ERRinput, NULL, NULL);
+  }
+  while (*s && !isspace(*s))  /* skip program name */
+    s++;
+  while (*s) {
+    while (*s && isspace(*s))
+      s++;
+    if (*s == '-')
+      s++;
+    if (!*s)
+      break;
+    key = *s++;
+    chkerr = NULL;
+    if (key == '\'') {         /* TO 'file name' */
+      t= strchr(s, '\'');
+      if (!t) {
+	fprintf(qh ferr, "qhull error (qh_checkflags): missing the 2nd single-quote for:\n%s\n", s-1);
+	qh_errexit(qh_ERRinput, NULL, NULL);
+      }
+      s= t+1;
+      continue;
+    }
+    chkkey[1]= key;
+    if (strstr(hiddenflags, chkkey)) {
+      chkerr= chkkey;
+    }else if (isupper(key)) {
+      opt= ' ';
+      prevopt= ' ';
+      chkopt[1]= key;
+      chkopt2[1]= key;
+      while (!chkerr && *s && !isspace(*s)) {
+	opt= *s++;
+	if (isalpha(opt)) {
+	  chkopt[2]= opt;
+	  if (strstr(hiddenflags, chkopt))
+	    chkerr= chkopt;
+	  if (prevopt != ' ') {
+ 	    chkopt2[2]= prevopt;
+ 	    chkopt2[3]= opt;
+	    if (strstr(hiddenflags, chkopt2))
+	      chkerr= chkopt2;
+	  }
+	}else if (key == 'Q' && isdigit(opt) && prevopt != 'b' 
+	      && (prevopt == ' ' || islower(prevopt))) {
+  	    chkopt[2]= opt;
+	    if (strstr(hiddenflags, chkopt))
+	      chkerr= chkopt;
+	}else {
+	  qh_strtod (s-1, &t);
+	  if (s < t)
+	    s= t;
+	}
+        prevopt= opt;
+      }
+    }
+    if (chkerr) {
+      *chkerr= '\'';
+      chkerr[strlen(chkerr)-1]=  '\'';
+      fprintf(qh ferr, "qhull error: option %s is not used with this program.\n             It may be used with qhull.\n", chkerr);
+      qh_errexit(qh_ERRinput, NULL, NULL);
+    }
+  }
+} /* checkflags */
+    
+/*---------------------------------
+  
+  qh_clock()
+    return user CPU time in 100ths (qh_SECtick)
+    only defined for qh_CLOCKtype == 2
+
+  notes:
+    use first value to determine time 0
+    from Stevens '92 8.15
+*/
+unsigned long qh_clock (void) {
+
+#if (qh_CLOCKtype == 2)
+  struct tms time;
+  static long clktck;  /* initialized first call */
+  double ratio, cpu;
+  unsigned long ticks;
+
+  if (!clktck) {
+    if ((clktck= sysconf (_SC_CLK_TCK)) < 0) {
+      fprintf (qh ferr, "qhull internal error (qh_clock): sysconf() failed.  Use qh_CLOCKtype 1 in user.h\n");
+      qh_errexit (qh_ERRqhull, NULL, NULL);
+    }
+  }
+  if (times (&time) == -1) {
+    fprintf (qh ferr, "qhull internal error (qh_clock): times() failed.  Use qh_CLOCKtype 1 in user.h\n");
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  ratio= qh_SECticks / (double)clktck;
+  ticks= time.tms_utime * ratio;
+  return ticks;
+#else
+  fprintf (qh ferr, "qhull internal error (qh_clock): use qh_CLOCKtype 2 in user.h\n");
+  qh_errexit (qh_ERRqhull, NULL, NULL); /* never returns */
+  return 0;
+#endif
+} /* clock */
+
+/*---------------------------------
+
+  qh_freebuffers()
+    free up global memory buffers
+
+  notes:
+    must match qh_initbuffers()
+*/
+void qh_freebuffers (void) {
+
+  trace5((qh ferr, "qh_freebuffers: freeing up global memory buffers\n"));
+  /* allocated by qh_initqhull_buffers */
+  qh_memfree (qh NEARzero, qh hull_dim * sizeof(realT));
+  qh_memfree (qh lower_threshold, (qh input_dim+1) * sizeof(realT));
+  qh_memfree (qh upper_threshold, (qh input_dim+1) * sizeof(realT));
+  qh_memfree (qh lower_bound, (qh input_dim+1) * sizeof(realT));
+  qh_memfree (qh upper_bound, (qh input_dim+1) * sizeof(realT));
+  qh_memfree (qh gm_matrix, (qh hull_dim+1) * qh hull_dim * sizeof(coordT));
+  qh_memfree (qh gm_row, (qh hull_dim+1) * sizeof(coordT *));
+  qh NEARzero= qh lower_threshold= qh upper_threshold= NULL;
+  qh lower_bound= qh upper_bound= NULL;
+  qh gm_matrix= NULL;
+  qh gm_row= NULL;
+  qh_setfree (&qh other_points);
+  qh_setfree (&qh del_vertices);
+  qh_setfree (&qh coplanarset);
+  if (qh line)                /* allocated by qh_readinput, freed if no error */
+    free (qh line);
+  if (qh half_space)
+    free (qh half_space);
+  if (qh temp_malloc)
+    free (qh temp_malloc);
+  if (qh feasible_point)      /* allocated by qh_readfeasible */
+    free (qh feasible_point);
+  if (qh feasible_string)     /* allocated by qh_initflags */
+    free (qh feasible_string);
+  qh line= qh feasible_string= NULL;
+  qh half_space= qh feasible_point= qh temp_malloc= NULL;
+  /* usually allocated by qh_readinput */
+  if (qh first_point && qh POINTSmalloc) {
+    free(qh first_point);
+    qh first_point= NULL;
+  }
+  if (qh input_points && qh input_malloc) { /* set by qh_joggleinput */
+    free (qh input_points);
+    qh input_points= NULL;
+  }
+  trace5((qh ferr, "qh_freebuffers: finished\n"));
+} /* freebuffers */
+
+
+/*---------------------------------
+
+  qh_freebuild( allmem )
+    free global memory used by qh_initbuild and qh_buildhull
+    if !allmem,
+      does not free short memory (freed by qh_memfreeshort)
+
+  design:
+    free centrums
+    free each vertex
+    mark unattached ridges
+    for each facet
+      free ridges
+      free outside set, coplanar set, neighbor set, ridge set, vertex set
+      free facet
+    free hash table
+    free interior point
+    free merge set
+    free temporary sets
+*/
+void qh_freebuild (boolT allmem) {
+  facetT *facet;
+  vertexT *vertex;
+  ridgeT *ridge, **ridgep;
+  mergeT *merge, **mergep;
+
+  trace1((qh ferr, "qh_freebuild: free memory from qh_inithull and qh_buildhull\n"));
+  if (qh del_vertices)
+    qh_settruncate (qh del_vertices, 0);
+  if (allmem) {
+    qh_clearcenters (qh_ASnone);
+    while ((vertex= qh vertex_list)) {
+      if (vertex->next)
+        qh_delvertex (vertex);
+      else {
+        qh_memfree (vertex, sizeof(vertexT));
+        qh newvertex_list= qh vertex_list= NULL;
+      }
+    }
+  }else if (qh VERTEXneighbors) {
+    FORALLvertices
+      qh_setfreelong (&(vertex->neighbors));
+  }
+  qh VERTEXneighbors= False;
+  qh GOODclosest= NULL;
+  if (allmem) {
+    FORALLfacets {
+      FOREACHridge_(facet->ridges)
+        ridge->seen= False;
+    }
+    FORALLfacets {
+      if (facet->visible) {
+	FOREACHridge_(facet->ridges) {
+	  if (!otherfacet_(ridge, facet)->visible)
+	    ridge->seen= True;  /* an unattached ridge */
+	}
+      }
+    }
+    while ((facet= qh facet_list)) {
+      FOREACHridge_(facet->ridges) {
+        if (ridge->seen) {
+          qh_setfree(&(ridge->vertices));
+          qh_memfree(ridge, sizeof(ridgeT));
+        }else
+          ridge->seen= True;
+      }
+      qh_setfree (&(facet->outsideset));
+      qh_setfree (&(facet->coplanarset));
+      qh_setfree (&(facet->neighbors));
+      qh_setfree (&(facet->ridges));
+      qh_setfree (&(facet->vertices));
+      if (facet->next)
+        qh_delfacet (facet);
+      else {
+        qh_memfree (facet, sizeof(facetT));
+        qh visible_list= qh newfacet_list= qh facet_list= NULL;
+      }
+    }
+  }else {
+    FORALLfacets {
+      qh_setfreelong (&(facet->outsideset));
+      qh_setfreelong (&(facet->coplanarset));
+      if (!facet->simplicial) {
+        qh_setfreelong (&(facet->neighbors));
+        qh_setfreelong (&(facet->ridges));
+        qh_setfreelong (&(facet->vertices));
+      }
+    }
+  }
+  qh_setfree (&(qh hash_table));
+  qh_memfree (qh interior_point, qh normal_size);
+  qh interior_point= NULL;
+  FOREACHmerge_(qh facet_mergeset)  /* usually empty */
+    qh_memfree (merge, sizeof(mergeT));
+  qh facet_mergeset= NULL;  /* temp set */
+  qh degen_mergeset= NULL;  /* temp set */
+  qh_settempfree_all();
+} /* freebuild */
+
+/*---------------------------------
+
+  qh_freeqhull( allmem )
+    free global memory
+    if !allmem,
+      does not free short memory (freed by qh_memfreeshort)
+
+  notes:
+    sets qh.NOerrexit in case caller forgets to
+
+  design:
+    free global and temporary memory from qh_initbuild and qh_buildhull
+    free buffers
+    free statistics
+*/
+void qh_freeqhull (boolT allmem) {
+
+  trace1((qh ferr, "qh_freeqhull: free global memory\n"));
+  qh NOerrexit= True;  /* no more setjmp since called at exit */
+  qh_freebuild (allmem);
+  qh_freebuffers();
+  qh_freestatistics();
+#if qh_QHpointer
+  free (qh_qh);
+  qh_qh= NULL;
+#else
+  memset((char *)&qh_qh, 0, sizeof(qhT));
+  qh NOerrexit= True;
+#endif
+} /* freeqhull */
+
+/*---------------------------------
+
+  qh_init_A( infile, outfile, errfile, argc, argv )
+    initialize memory and stdio files
+    convert input options to option string (qh.qhull_command)
+
+  notes:
+    infile may be NULL if qh_readpoints() is not called
+
+    errfile should always be defined.  It is used for reporting
+    errors.  outfile is used for output and format options.
+
+    argc/argv may be 0/NULL
+
+    called before error handling initialized
+    qh_errexit() may not be used
+*/
+void qh_init_A (FILE *infile, FILE *outfile, FILE *errfile, int argc, char *argv[]) {
+  qh_meminit (errfile);
+  qh_initqhull_start (infile, outfile, errfile);
+  qh_init_qhull_command (argc, argv);
+} /* init_A */
+
+/*---------------------------------
+
+  qh_init_B( points, numpoints, dim, ismalloc )
+    initialize globals for points array
+
+    points has numpoints dim-dimensional points
+      points[0] is the first coordinate of the first point
+      points[1] is the second coordinate of the first point
+      points[dim] is the first coordinate of the second point
+
+    ismalloc=True
+      Qhull will call free(points) on exit or input transformation
+    ismalloc=False
+      Qhull will allocate a new point array if needed for input transformation
+
+    qh.qhull_command
+      is the option string.
+      It is defined by qh_init_B(), qh_qhull_command(), or qh_initflags
+
+  returns:
+    if qh.PROJECTinput or (qh.DELAUNAY and qh.PROJECTdelaunay)
+      projects the input to a new point array
+
+        if qh.DELAUNAY,
+          qh.hull_dim is increased by one
+        if qh.ATinfinity,
+          qh_projectinput adds point-at-infinity for Delaunay tri.
+
+    if qh.SCALEinput
+      changes the upper and lower bounds of the input, see qh_scaleinput()
+
+    if qh.ROTATEinput
+      rotates the input by a random rotation, see qh_rotateinput()
+      if qh.DELAUNAY
+        rotates about the last coordinate
+
+  notes:
+    called after points are defined
+    qh_errexit() may be used
+*/
+void qh_init_B (coordT *points, int numpoints, int dim, boolT ismalloc) {
+  qh_initqhull_globals (points, numpoints, dim, ismalloc);
+  if (qhmem.LASTsize == 0)
+    qh_initqhull_mem();
+  /* mem.c and qset.c are initialized */
+  qh_initqhull_buffers();
+  qh_initthresholds (qh qhull_command);
+  if (qh PROJECTinput || (qh DELAUNAY && qh PROJECTdelaunay))
+    qh_projectinput();
+  if (qh SCALEinput)
+    qh_scaleinput();
+  if (qh ROTATErandom >= 0) {
+    qh_randommatrix (qh gm_matrix, qh hull_dim, qh gm_row);
+    if (qh DELAUNAY) {
+      int k, lastk= qh hull_dim-1;
+      for (k= 0; k < lastk; k++) {
+        qh gm_row[k][lastk]= 0.0;
+        qh gm_row[lastk][k]= 0.0;
+      }
+      qh gm_row[lastk][lastk]= 1.0;
+    }
+    qh_gram_schmidt (qh hull_dim, qh gm_row);
+    qh_rotateinput (qh gm_row);
+  }
+} /* init_B */
+
+/*---------------------------------
+
+  qh_init_qhull_command( argc, argv )
+    build qh.qhull_command from argc/argv
+
+  returns:
+    a space-deliminated string of options (just as typed)
+
+  notes:
+    makes option string easy to input and output
+
+    argc/argv may be 0/NULL
+*/
+void qh_init_qhull_command(int argc, char *argv[]) {
+  int i;
+  char *s;
+
+  if (argc) {
+    if ((s= strrchr( argv[0], '\\'))) /* Borland gives full path */
+      strcpy (qh qhull_command, s+1);
+    else
+      strcpy (qh qhull_command, argv[0]);
+    if ((s= strstr (qh qhull_command, ".EXE"))
+    ||  (s= strstr (qh qhull_command, ".exe")))
+      *s= '\0';
+  }
+  for (i=1; i < argc; i++) {
+    if (strlen (qh qhull_command) + strlen(argv[i]) + 1 < sizeof(qh qhull_command)) {
+      strcat (qh qhull_command, " ");
+      strcat (qh qhull_command, argv[i]);
+    }else {
+      fprintf (qh ferr, "qhull input error: more than %d characters in command line\n",
+        (int)sizeof(qh qhull_command));
+      exit (1);  /* can not use qh_errexit */
+    }
+  }
+} /* init_qhull_command */
+
+/*---------------------------------
+
+  qh_initflags( commandStr )
+    set flags and initialized constants from commandStr
+
+  returns:
+    sets qh.qhull_command to command if needed
+
+  notes:
+    ignores first word (e.g., "qhull d")
+    use qh_strtol/strtod since strtol/strtod may or may not skip trailing spaces
+
+  see:
+    qh_initthresholds() continues processing of 'Pdn' and 'PDn'
+    'prompt' in unix.c for documentation
+
+  design:
+    for each space-deliminated option group
+      if top-level option
+        check syntax
+        append approriate option to option string
+        set appropriate global variable or append printFormat to print options
+      else
+        for each sub-option
+          check syntax
+          append approriate option to option string
+          set appropriate global variable or append printFormat to print options
+
+
+*/
+void qh_initflags(char *command) {
+  int k, i, lastproject;
+  char *s= command, *t, *prev_s, *start, key;
+  boolT isgeom= False, wasproject;
+  realT r;
+
+  if (command != &qh qhull_command[0]) {
+    *qh qhull_command= '\0';
+    strncat( qh qhull_command, command, sizeof( qh qhull_command));
+  }
+  while (*s && !isspace(*s))  /* skip program name */
+    s++;
+  while (*s) {
+    while (*s && isspace(*s))
+      s++;
+    if (*s == '-')
+      s++;
+    if (!*s)
+      break;
+    prev_s= s;
+    switch (*s++) {
+    case 'd':
+      qh_option ("delaunay", NULL, NULL);
+      qh DELAUNAY= True;
+      break;
+    case 'f':
+      qh_option ("facets", NULL, NULL);
+      qh_appendprint (qh_PRINTfacets);
+      break;
+    case 'i':
+      qh_option ("incidence", NULL, NULL);
+      qh_appendprint (qh_PRINTincidences);
+      break;
+    case 'm':
+      qh_option ("mathematica", NULL, NULL);
+      qh_appendprint (qh_PRINTmathematica);
+      break;
+    case 'n':
+      qh_option ("normals", NULL, NULL);
+      qh_appendprint (qh_PRINTnormals);
+      break;
+    case 'o':
+      qh_option ("offFile", NULL, NULL);
+      qh_appendprint (qh_PRINToff);
+      break;
+    case 'p':
+      qh_option ("points", NULL, NULL);
+      qh_appendprint (qh_PRINTpoints);
+      break;
+    case 's':
+      qh_option ("summary", NULL, NULL);
+      qh PRINTsummary= True;
+      break;
+    case 'v':
+      qh_option ("voronoi", NULL, NULL);
+      qh VORONOI= True;
+      qh DELAUNAY= True;
+      break;
+    case 'A':
+      if (!isdigit(*s) && *s != '.' && *s != '-')
+	fprintf(qh ferr, "qhull warning: no maximum cosine angle given for option 'An'.  Ignored.\n");
+      else {
+	if (*s == '-') {
+	  qh premerge_cos= -qh_strtod (s, &s);
+          qh_option ("Angle-premerge-", NULL, &qh premerge_cos);
+	  qh PREmerge= True;
+	}else {
+	  qh postmerge_cos= qh_strtod (s, &s);
+          qh_option ("Angle-postmerge", NULL, &qh postmerge_cos);
+	  qh POSTmerge= True;
+	}
+	qh MERGING= True;
+      }
+      break;
+    case 'C':
+      if (!isdigit(*s) && *s != '.' && *s != '-')
+	fprintf(qh ferr, "qhull warning: no centrum radius given for option 'Cn'.  Ignored.\n");
+      else {
+	if (*s == '-') {
+	  qh premerge_centrum= -qh_strtod (s, &s);
+          qh_option ("Centrum-premerge-", NULL, &qh premerge_centrum);
+	  qh PREmerge= True;
+	}else {
+	  qh postmerge_centrum= qh_strtod (s, &s);
+          qh_option ("Centrum-postmerge", NULL, &qh postmerge_centrum);
+	  qh POSTmerge= True;
+	}
+	qh MERGING= True;
+      }
+      break;
+    case 'E':
+      if (*s == '-')
+	fprintf(qh ferr, "qhull warning: negative maximum roundoff given for option 'An'.  Ignored.\n");
+      else if (!isdigit(*s))
+	fprintf(qh ferr, "qhull warning: no maximum roundoff given for option 'En'.  Ignored.\n");
+      else {
+	qh DISTround= qh_strtod (s, &s);
+        qh_option ("Distance-roundoff", NULL, &qh DISTround);
+	qh SETroundoff= True;
+      }
+      break;
+    case 'H':
+      start= s;
+      qh HALFspace= True;
+      qh_strtod (s, &t);
+      while (t > s)  {
+        if (*t && !isspace (*t)) {
+	  if (*t == ',')
+	    t++;
+	  else
+	    fprintf (qh ferr, "qhull warning: origin for Halfspace intersection should be 'Hn,n,n,...'\n");
+	}
+        s= t;
+	qh_strtod (s, &t);
+      }
+      if (start < t) {
+        if (!(qh feasible_string= (char*)calloc (t-start+1, 1))) {
+          fprintf(qh ferr, "qhull error: insufficient memory for 'Hn,n,n'\n");
+          qh_errexit(qh_ERRmem, NULL, NULL);
+        }
+        strncpy (qh feasible_string, start, t-start);
+        qh_option ("Halfspace-about", NULL, NULL);
+        qh_option (qh feasible_string, NULL, NULL);
+      }else
+        qh_option ("Halfspace", NULL, NULL);
+      break;
+    case 'R':
+      if (!isdigit(*s))
+	fprintf(qh ferr, "qhull warning: missing random perturbation for option 'Rn'.  Ignored\n");
+      else {
+	qh RANDOMfactor= qh_strtod (s, &s);
+        qh_option ("Random_perturb", NULL, &qh RANDOMfactor);
+        qh RANDOMdist= True;
+      }
+      break;
+    case 'V':
+      if (!isdigit(*s) && *s != '-')
+	fprintf(qh ferr, "qhull warning: missing visible distance for option 'Vn'.  Ignored\n");
+      else {
+	qh MINvisible= qh_strtod (s, &s);
+        qh_option ("Visible", NULL, &qh MINvisible);
+      }
+      break;
+    case 'U':
+      if (!isdigit(*s) && *s != '-')
+	fprintf(qh ferr, "qhull warning: missing coplanar distance for option 'Un'.  Ignored\n");
+      else {
+	qh MAXcoplanar= qh_strtod (s, &s);
+        qh_option ("U-coplanar", NULL, &qh MAXcoplanar);
+      }
+      break;
+    case 'W':
+      if (*s == '-')
+	fprintf(qh ferr, "qhull warning: negative outside width for option 'Wn'.  Ignored.\n");
+      else if (!isdigit(*s))
+	fprintf(qh ferr, "qhull warning: missing outside width for option 'Wn'.  Ignored\n");
+      else {
+	qh MINoutside= qh_strtod (s, &s);
+        qh_option ("W-outside", NULL, &qh MINoutside);
+        qh APPROXhull= True;
+      }
+      break;
+    /************  sub menus ***************/
+    case 'F':
+      while (*s && !isspace(*s)) {
+	switch(*s++) {
+	case 'a':
+	  qh_option ("Farea", NULL, NULL);
+	  qh_appendprint (qh_PRINTarea);
+	  qh GETarea= True;
+	  break;
+	case 'A':
+	  qh_option ("FArea-total", NULL, NULL);
+	  qh GETarea= True;
+	  break;
+        case 'c':
+          qh_option ("Fcoplanars", NULL, NULL);
+          qh_appendprint (qh_PRINTcoplanars);
+          break;
+        case 'C':
+          qh_option ("FCentrums", NULL, NULL);
+          qh_appendprint (qh_PRINTcentrums);
+          break;
+	case 'd':
+          qh_option ("Fd-cdd-in", NULL, NULL);
+	  qh CDDinput= True;
+	  break;
+	case 'D':
+          qh_option ("FD-cdd-out", NULL, NULL);
+	  qh CDDoutput= True;
+	  break;
+	case 'F':
+	  qh_option ("FFacets-xridge", NULL, NULL);
+          qh_appendprint (qh_PRINTfacets_xridge);
+	  break;
+        case 'i':
+          qh_option ("Finner", NULL, NULL);
+          qh_appendprint (qh_PRINTinner);
+          break;
+        case 'I':
+          qh_option ("FIDs", NULL, NULL);
+          qh_appendprint (qh_PRINTids);
+          break;
+        case 'm':
+          qh_option ("Fmerges", NULL, NULL);
+          qh_appendprint (qh_PRINTmerges);
+          break;
+        case 'n':
+          qh_option ("Fneighbors", NULL, NULL);
+          qh_appendprint (qh_PRINTneighbors);
+          break;
+        case 'N':
+          qh_option ("FNeighbors-vertex", NULL, NULL);
+          qh_appendprint (qh_PRINTvneighbors);
+          break;
+        case 'o':
+          qh_option ("Fouter", NULL, NULL);
+          qh_appendprint (qh_PRINTouter);
+          break;
+	case 'O':
+	  if (qh PRINToptions1st) {
+	    qh_option ("FOptions", NULL, NULL);
+	    qh_appendprint (qh_PRINToptions);
+	  }else
+	    qh PRINToptions1st= True;
+	  break;
+	case 'p':
+	  qh_option ("Fpoint-intersect", NULL, NULL);
+	  qh_appendprint (qh_PRINTpointintersect);
+	  break;
+	case 'P':
+	  qh_option ("FPoint-nearest", NULL, NULL);
+	  qh_appendprint (qh_PRINTpointnearest);
+	  break;
+	case 'Q':
+	  qh_option ("FQhull", NULL, NULL);
+	  qh_appendprint (qh_PRINTqhull);
+	  break;
+        case 's':
+          qh_option ("Fsummary", NULL, NULL);
+          qh_appendprint (qh_PRINTsummary);
+          break;
+        case 'S':
+          qh_option ("FSize", NULL, NULL);
+          qh_appendprint (qh_PRINTsize);
+          qh GETarea= True;
+          break;
+        case 't':
+          qh_option ("Ftriangles", NULL, NULL);
+          qh_appendprint (qh_PRINTtriangles);
+          break;
+        case 'v':
+          /* option set in qh_initqhull_globals */
+          qh_appendprint (qh_PRINTvertices);
+          break;
+        case 'V':
+          qh_option ("FVertex-average", NULL, NULL);
+          qh_appendprint (qh_PRINTaverage);
+          break;
+	case 'x':
+	  qh_option ("Fxtremes", NULL, NULL);
+	  qh_appendprint (qh_PRINTextremes);
+	  break;
+	default:
+	  s--;
+	  fprintf (qh ferr, "qhull warning: unknown 'F' output option %c, rest ignored\n", (int)s[0]);
+	  while (*++s && !isspace(*s));
+	  break;
+	}
+      }
+      break;
+    case 'G':
+      isgeom= True;
+      qh_appendprint (qh_PRINTgeom);
+      while (*s && !isspace(*s)) {
+	switch(*s++) {
+        case 'a':
+          qh_option ("Gall-points", NULL, NULL);
+          qh PRINTdots= True;
+          break;
+        case 'c':
+          qh_option ("Gcentrums", NULL, NULL);
+          qh PRINTcentrums= True;
+          break;
+	case 'h':
+          qh_option ("Gintersections", NULL, NULL);
+	  qh DOintersections= True;
+	  break;
+	case 'i':
+          qh_option ("Ginner", NULL, NULL);
+	  qh PRINTinner= True;
+	  break;
+	case 'n':
+          qh_option ("Gno-planes", NULL, NULL);
+	  qh PRINTnoplanes= True;
+	  break;
+	case 'o':
+          qh_option ("Gouter", NULL, NULL);
+	  qh PRINTouter= True;
+	  break;
+	case 'p':
+          qh_option ("Gpoints", NULL, NULL);
+	  qh PRINTcoplanar= True;
+	  break;
+	case 'r':
+          qh_option ("Gridges", NULL, NULL);
+	  qh PRINTridges= True;
+	  break;
+	case 't':
+          qh_option ("Gtransparent", NULL, NULL);
+	  qh PRINTtransparent= True;
+	  break;
+	case 'v':
+          qh_option ("Gvertices", NULL, NULL);
+	  qh PRINTspheres= True;
+	  break;
+	case 'D':
+	  if (!isdigit (*s))
+	    fprintf (qh ferr, "qhull input error: missing dimension for option 'GDn'\n");
+	  else {
+	    if (qh DROPdim >= 0)
+	      fprintf (qh ferr, "qhull warning: can only drop one dimension.  Previous 'GD%d' ignored\n",
+	           qh DROPdim);
+  	    qh DROPdim= qh_strtol (s, &s);
+            qh_option ("GDrop-dim", &qh DROPdim, NULL);
+          }
+	  break;
+	default:
+	  s--;
+	  fprintf (qh ferr, "qhull warning: unknown 'G' print option %c, rest ignored\n", (int)s[0]);
+	  while (*++s && !isspace(*s));
+	  break;
+	}
+      }
+      break;
+    case 'P':
+      while (*s && !isspace(*s)) {
+	switch(*s++) {
+	case 'd': case 'D':  /* see qh_initthresholds() */
+	  key= s[-1];
+	  i= qh_strtol (s, &s);
+	  r= 0;
+	  if (*s == ':') {
+	    s++;
+	    r= qh_strtod (s, &s);
+	  }
+	  if (key == 'd')
+  	    qh_option ("Pdrop-facets-dim-less", &i, &r);
+  	  else
+  	    qh_option ("PDrop-facets-dim-more", &i, &r);
+	  break;
+        case 'g':
+          qh_option ("Pgood-facets", NULL, NULL);
+          qh PRINTgood= True;
+          break;
+        case 'G':
+          qh_option ("PGood-facet-neighbors", NULL, NULL);
+          qh PRINTneighbors= True;
+          break;
+        case 'o':
+          qh_option ("Poutput-forced", NULL, NULL);
+          qh FORCEoutput= True;
+          break;
+        case 'p':
+          qh_option ("Pprecision-ignore", NULL, NULL);
+          qh PRINTprecision= False;
+          break;
+	case 'A':
+	  if (!isdigit (*s))
+	    fprintf (qh ferr, "qhull input error: missing facet count for keep area option 'PAn'\n");
+	  else {
+  	    qh KEEParea= qh_strtol (s, &s);
+            qh_option ("PArea-keep", &qh KEEParea, NULL);
+            qh GETarea= True;
+          }
+	  break;
+	case 'F':
+	  if (!isdigit (*s))
+	    fprintf (qh ferr, "qhull input error: missing facet area for option 'PFn'\n");
+	  else {
+  	    qh KEEPminArea= qh_strtod (s, &s);
+            qh_option ("PFacet-area-keep", NULL, &qh KEEPminArea);
+            qh GETarea= True;
+          }
+	  break;
+	case 'M':
+	  if (!isdigit (*s))
+	    fprintf (qh ferr, "qhull input error: missing merge count for option 'PMn'\n");
+	  else {
+  	    qh KEEPmerge= qh_strtol (s, &s);
+            qh_option ("PMerge-keep", &qh KEEPmerge, NULL);
+          }
+	  break;
+	default:
+	  s--;
+	  fprintf (qh ferr, "qhull warning: unknown 'P' print option %c, rest ignored\n", (int)s[0]);
+	  while (*++s && !isspace(*s));
+	  break;
+	}
+      }
+      break;
+    case 'Q':
+      lastproject= -1;
+      while (*s && !isspace(*s)) {
+	switch(*s++) {
+	case 'b': case 'B':  /* handled by qh_initthresholds */
+	  key= s[-1];
+	  if (key == 'b' && *s == 'B') {
+	    s++;
+	    r= qh_DEFAULTbox;
+	    qh SCALEinput= True;
+	    qh_option ("QbBound-unit-box", NULL, &r);
+	    break;
+	  }
+	  if (key == 'b' && *s == 'b') {
+	    s++;
+	    qh SCALElast= True;
+	    qh_option ("Qbbound-last", NULL, NULL);
+	    break;
+	  }
+	  k= qh_strtol (s, &s);
+	  r= 0.0;
+	  wasproject= False;
+	  if (*s == ':') {
+	    s++;
+	    if ((r= qh_strtod(s, &s)) == 0.0) {
+ 	      t= s;            /* need true dimension for memory allocation */
+	      while (*t && !isspace(*t)) {
+	        if (toupper(*t++) == 'B'
+	         && k == qh_strtol (t, &t)
+	         && *t++ == ':'
+	         && qh_strtod(t, &t) == 0.0) {
+	          qh PROJECTinput++;
+	          trace2((qh ferr, "qh_initflags: project dimension %d\n", k));
+	          qh_option ("Qb-project-dim", &k, NULL);
+		  wasproject= True;
+	          lastproject= k;
+	          break;
+		}
+	      }
+	    }
+  	  }
+	  if (!wasproject) {
+	    if (lastproject == k && r == 0.0)
+	      lastproject= -1;  /* doesn't catch all possible sequences */
+	    else if (key == 'b') {
+	      qh SCALEinput= True;
+	      if (r == 0.0)
+		r= -qh_DEFAULTbox;
+	      qh_option ("Qbound-dim-low", &k, &r);
+	    }else {
+	      qh SCALEinput= True;
+	      if (r == 0.0)
+		r= qh_DEFAULTbox;
+	      qh_option ("QBound-dim-high", &k, &r);
+	    }
+	  }
+	  break;
+	case 'c':
+	  qh_option ("Qcoplanar-keep", NULL, NULL);
+	  qh KEEPcoplanar= True;
+	  break;
+	case 'f':
+	  qh_option ("Qfurthest-outside", NULL, NULL);
+	  qh BESToutside= True;
+	  break;
+	case 'g':
+	  qh_option ("Qgood-facets-only", NULL, NULL);
+	  qh ONLYgood= True;
+	  break;
+	case 'i':
+	  qh_option ("Qinterior-keep", NULL, NULL);
+	  qh KEEPinside= True;
+	  break;
+	case 'm':
+	  qh_option ("Qmax-outside-only", NULL, NULL);
+	  qh ONLYmax= True;
+	  break;
+	case 'r':
+	  qh_option ("Qrandom-outside", NULL, NULL);
+	  qh RANDOMoutside= True;
+	  break;
+	case 's':
+	  qh_option ("Qsearch-initial-simplex", NULL, NULL);
+	  qh ALLpoints= True;
+	  break;
+	case 't':
+	  qh_option ("Qtriangulate", NULL, NULL);
+	  qh TRIangulate= True;
+	  break;
+	case 'T':
+	  qh_option ("QTestPoints", NULL, NULL);
+	  if (!isdigit (*s))
+	    fprintf (qh ferr, "qhull input error: missing number of test points for option 'QTn'\n");
+	  else {
+  	    qh TESTpoints= qh_strtol (s, &s);
+            qh_option ("QTestPoints", &qh TESTpoints, NULL);
+          }
+	  break;
+	case 'u':
+	  qh_option ("QupperDelaunay", NULL, NULL);
+	  qh UPPERdelaunay= True;
+	  break;
+	case 'v':
+	  qh_option ("Qvertex-neighbors-convex", NULL, NULL);
+	  qh TESTvneighbors= True;
+	  break;
+	case 'x':
+	  qh_option ("Qxact-merge", NULL, NULL);
+	  qh MERGEexact= True;
+	  break;
+	case 'z':
+	  qh_option ("Qz-infinity-point", NULL, NULL);
+	  qh ATinfinity= True;
+	  break;
+	case '0':
+	  qh_option ("Q0-no-premerge", NULL, NULL);
+	  qh NOpremerge= True;
+	  break;
+	case '1':
+	  if (!isdigit(*s)) {
+	    qh_option ("Q1-no-angle-sort", NULL, NULL);
+	    qh ANGLEmerge= False;
+	    break; 
+	  }
+	  switch(*s++) {
+  	  case '0':
+	    qh_option ("Q10-no-narrow", NULL, NULL);
+	    qh NOnarrow= True;
+	    break; 
+  	  case '1':
+	    qh_option ("Q11-trinormals Qtriangulate", NULL, NULL);
+	    qh TRInormals= True;
+	    qh TRIangulate= True;
+	    break; 
+	  default:
+	    s--;
+	    fprintf (qh ferr, "qhull warning: unknown 'Q' qhull option 1%c, rest ignored\n", (int)s[0]);
+	    while (*++s && !isspace(*s));
+	    break;
+	  }
+	  break;
+	case '2':
+	  qh_option ("Q2-no-merge-independent", NULL, NULL);
+	  qh MERGEindependent= False;
+	  goto LABELcheckdigit;
+	  break; /* no warnings */
+	case '3':
+	  qh_option ("Q3-no-merge-vertices", NULL, NULL);
+	  qh MERGEvertices= False;
+	LABELcheckdigit:
+	  if (isdigit(*s))
+	    fprintf (qh ferr, "qhull warning: can not follow '1', '2', or '3' with a digit.  '%c' skipped.\n",
+	             *s++);
+	  break;
+	case '4':
+	  qh_option ("Q4-avoid-old-into-new", NULL, NULL);
+	  qh AVOIDold= True;
+	  break;
+	case '5':
+	  qh_option ("Q5-no-check-outer", NULL, NULL);
+	  qh SKIPcheckmax= True;
+	  break;
+	case '6':
+	  qh_option ("Q6-no-concave-merge", NULL, NULL);
+	  qh SKIPconvex= True;
+	  break;
+	case '7':
+	  qh_option ("Q7-no-breadth-first", NULL, NULL);
+	  qh VIRTUALmemory= True;
+	  break;
+	case '8':
+	  qh_option ("Q8-no-near-inside", NULL, NULL);
+	  qh NOnearinside= True;
+	  break;
+	case '9':
+	  qh_option ("Q9-pick-furthest", NULL, NULL);
+	  qh PICKfurthest= True;
+	  break;
+	case 'G':
+	  i= qh_strtol (s, &t);
+	  if (qh GOODpoint)
+	    fprintf (qh ferr, "qhull warning: good point already defined for option 'QGn'.  Ignored\n");
+          else if (s == t)
+	    fprintf (qh ferr, "qhull warning: missing good point id for option 'QGn'.  Ignored\n");
+	  else if (i < 0 || *s == '-') {
+ 	    qh GOODpoint= i-1;
+  	    qh_option ("QGood-if-dont-see-point", &i, NULL);
+	  }else {
+ 	    qh GOODpoint= i+1;
+  	    qh_option ("QGood-if-see-point", &i, NULL);
+  	  }
+ 	  s= t;
+	  break;
+	case 'J':
+          if (!isdigit(*s) && *s != '-')
+   	    qh JOGGLEmax= 0.0;
+	  else {
+ 	    qh JOGGLEmax= (realT) qh_strtod (s, &s);
+            qh_option ("QJoggle", NULL, &qh JOGGLEmax);
+	  }
+	  break;
+	case 'R':
+          if (!isdigit(*s) && *s != '-')
+	    fprintf (qh ferr, "qhull warning: missing random seed for option 'QRn'.  Ignored\n");
+	  else {
+ 	    qh ROTATErandom= i= qh_strtol(s, &s);
+   	    if (i > 0)
+   	      qh_option ("QRotate-id", &i, NULL );
+	    else if (i < -1)
+   	      qh_option ("QRandom-seed", &i, NULL );
+          }
+	  break;
+	case 'V':
+	  i= qh_strtol (s, &t);
+	  if (qh GOODvertex)
+	    fprintf (qh ferr, "qhull warning: good vertex already defined for option 'QVn'.  Ignored\n");
+          else if (s == t)
+	    fprintf (qh ferr, "qhull warning: no good point id given for option 'QVn'.  Ignored\n");
+	  else if (i < 0) {
+ 	    qh GOODvertex= i - 1;
+ 	    qh_option ("QV-good-facets-not-point", &i, NULL);
+	  }else {
+  	    qh_option ("QV-good-facets-point", &i, NULL);
+	    qh GOODvertex= i + 1;
+          }
+ 	  s= t;
+	  break;
+	default:
+	  s--;
+	  fprintf (qh ferr, "qhull warning: unknown 'Q' qhull option %c, rest ignored\n", (int)s[0]);
+	  while (*++s && !isspace(*s));
+	  break;
+	}
+      }
+      break;
+    case 'T':
+      while (*s && !isspace(*s)) {
+	if (isdigit(*s) || *s == '-')
+	  qh IStracing= qh_strtol(s, &s);
+	else switch(*s++) {
+	case 'c':
+          qh_option ("Tcheck-frequently", NULL, NULL);
+	  qh CHECKfrequently= True;
+	  break;
+	case 's':
+          qh_option ("Tstatistics", NULL, NULL);
+	  qh PRINTstatistics= True;
+	  break;
+	case 'v':
+          qh_option ("Tverify", NULL, NULL);
+	  qh VERIFYoutput= True;
+	  break;
+	case 'z':
+	  if (!qh fout)
+	    fprintf (qh ferr, "qhull warning: output file undefined (stdout).  Option 'Tz' ignored.\n");
+	  else {
+	    qh_option ("Tz-stdout", NULL, NULL);
+  	    qh ferr= qh fout;
+  	    qhmem.ferr= qh fout;
+	  }
+	  break;
+	case 'C':
+	  if (!isdigit(*s))
+	    fprintf (qh ferr, "qhull warning: missing point id for cone for trace option 'TCn'.  Ignored\n");
+	  else {
+	    i= qh_strtol (s, &s);
+	    qh_option ("TCone-stop", &i, NULL);
+	    qh STOPcone= i + 1;
+          }
+	  break;
+	case 'F':
+	  if (!isdigit(*s))
+	    fprintf (qh ferr, "qhull warning: missing frequency count for trace option 'TFn'.  Ignored\n");
+	  else {
+	    qh REPORTfreq= qh_strtol (s, &s);
+            qh_option ("TFacet-log", &qh REPORTfreq, NULL);
+	    qh REPORTfreq2= qh REPORTfreq/2;  /* for tracemerging() */
+	  }
+	  break;
+	case 'I':
+	  if (s[0] != ' ' || s[1] == '\"' || s[1] == '\'' ||isspace (s[1])) {
+	    s++;
+	    fprintf (qh ferr, "qhull warning: option 'TI' mistyped.\nUse 'TI', one space, file name, and space or end-of-line.\nDo not use quotes.  Option 'FI' ignored.\n");
+	  }else {  /* not a procedure because of qh_option (filename, NULL, NULL); */
+	    char filename[500], *t= filename;
+
+	    s++;
+	    while (*s) {
+	      if (t - filename >= sizeof (filename)-2) {
+		fprintf (qh ferr, "qhull error: filename for 'TI' too long.\n");
+		qh_errexit (qh_ERRinput, NULL, NULL);
+	      }
+	      if (isspace (*s))
+		break;
+	      *(t++)= *s++;
+	    }
+	    *t= '\0';
+	    if (!freopen (filename, "r", stdin)) {
+	      fprintf (qh ferr, "qhull error: could not open file \"%s\".", filename);
+	      qh_errexit (qh_ERRinput, NULL, NULL);
+	    }else {
+	      qh_option ("TInput-file", NULL, NULL);
+	      qh_option (filename, NULL, NULL);
+	    }
+	  }
+	  break;
+	case 'O':
+	  if (s[0] != ' ' || s[1] == '\"' || isspace (s[1])) {
+	    s++;
+	    fprintf (qh ferr, "qhull warning: option 'TO' mistyped.\nUse 'TO', one space, file name, and space or end-of-line.\nThe file name may be enclosed in single quotes.\nDo not use double quotes.  Option 'FO' ignored.\n");
+	  }else {  /* not a procedure because of qh_option (filename, NULL, NULL); */
+	    char filename[500], *t= filename;
+	    boolT isquote= False;
+
+	    s++;
+	    if (*s == '\'') {
+	      isquote= True;
+	      s++;
+	    }
+	    while (*s) {
+	      if (t - filename >= sizeof (filename)-2) {
+		fprintf (qh ferr, "qhull error: filename for 'TO' too long.\n");
+		qh_errexit (qh_ERRinput, NULL, NULL);
+	      }
+	      if (isquote) {
+		if (*s == '\'') {
+		  s++;
+		  isquote= False;
+		  break;
+		}
+	      }else if (isspace (*s))
+		break;
+	      *(t++)= *s++;
+	    }
+	    *t= '\0';
+	    if (isquote)
+	      fprintf (qh ferr, "qhull error: missing end quote for option 'TO'.  Rest of line ignored.\n");
+	    else if (!freopen (filename, "w", stdout)) {
+	      fprintf (qh ferr, "qhull error: could not open file \"%s\".", filename);
+	      qh_errexit (qh_ERRinput, NULL, NULL);
+	    }else {
+	      qh_option ("TOutput-file", NULL, NULL);
+	      qh_option (filename, NULL, NULL);
+	    }
+	  }
+	  break;
+	case 'P':
+	  if (!isdigit(*s))
+	    fprintf (qh ferr, "qhull warning: missing point id for trace option 'TPn'.  Ignored\n");
+	  else {
+	    qh TRACEpoint= qh_strtol (s, &s);
+            qh_option ("Trace-point", &qh TRACEpoint, NULL);
+          }
+	  break;
+	case 'M':
+	  if (!isdigit(*s))
+	    fprintf (qh ferr, "qhull warning: missing merge id for trace option 'TMn'.  Ignored\n");
+	  else {
+	    qh TRACEmerge= qh_strtol (s, &s);
+            qh_option ("Trace-merge", &qh TRACEmerge, NULL);
+          }
+	  break;
+	case 'R':
+	  if (!isdigit(*s))
+	    fprintf (qh ferr, "qhull warning: missing rerun count for trace option 'TRn'.  Ignored\n");
+	  else {
+	    qh RERUN= qh_strtol (s, &s);
+            qh_option ("TRerun", &qh RERUN, NULL);
+          }
+	  break;
+	case 'V':
+	  i= qh_strtol (s, &t);
+	  if (s == t)
+	    fprintf (qh ferr, "qhull warning: missing furthest point id for trace option 'TVn'.  Ignored\n");
+	  else if (i < 0) {
+	    qh STOPpoint= i - 1;
+            qh_option ("TV-stop-before-point", &i, NULL);
+	  }else {
+	    qh STOPpoint= i + 1;
+            qh_option ("TV-stop-after-point", &i, NULL);
+          }
+          s= t;
+	  break;
+	case 'W':
+	  if (!isdigit(*s))
+	    fprintf (qh ferr, "qhull warning: missing max width for trace option 'TWn'.  Ignored\n");
+	  else {
+ 	    qh TRACEdist= (realT) qh_strtod (s, &s);
+            qh_option ("TWide-trace", NULL, &qh TRACEdist);
+          }
+	  break;
+	default:
+	  s--;
+	  fprintf (qh ferr, "qhull warning: unknown 'T' trace option %c, rest ignored\n", (int)s[0]);
+	  while (*++s && !isspace(*s));
+	  break;
+	}
+      }
+      break;
+    default:
+      fprintf (qh ferr, "qhull warning: unknown flag %c (%x)\n", (int)s[-1],
+	       (int)s[-1]);
+      break;
+    }
+    if (s-1 == prev_s && *s && !isspace(*s)) {
+      fprintf (qh ferr, "qhull warning: missing space after flag %c (%x); reserved for menu. Skipped.\n",
+	       (int)*prev_s, (int)*prev_s);
+      while (*s && !isspace(*s))
+	s++;
+    }
+  }
+  if (isgeom && !qh FORCEoutput && qh PRINTout[1])
+    fprintf (qh ferr, "qhull warning: additional output formats are not compatible with Geomview\n");
+  /* set derived values in qh_initqhull_globals */
+} /* initflags */
+
+
+/*---------------------------------
+
+  qh_initqhull_buffers()
+    initialize global memory buffers
+
+  notes:
+    must match qh_freebuffers()
+*/
+void qh_initqhull_buffers (void) {
+  int k;
+
+  qh TEMPsize= (qhmem.LASTsize - sizeof (setT))/SETelemsize;
+  if (qh TEMPsize <= 0 || qh TEMPsize > qhmem.LASTsize)
+    qh TEMPsize= 8;  /* e.g., if qh_NOmem */
+  qh other_points= qh_setnew (qh TEMPsize);
+  qh del_vertices= qh_setnew (qh TEMPsize);
+  qh coplanarset= qh_setnew (qh TEMPsize);
+  qh NEARzero= (realT *)qh_memalloc(qh hull_dim * sizeof(realT));
+  qh lower_threshold= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT));
+  qh upper_threshold= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT));
+  qh lower_bound= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT));
+  qh upper_bound= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT));
+  for(k= qh input_dim+1; k--; ) {
+    qh lower_threshold[k]= -REALmax;
+    qh upper_threshold[k]= REALmax;
+    qh lower_bound[k]= -REALmax;
+    qh upper_bound[k]= REALmax;
+  }
+  qh gm_matrix= (coordT *)qh_memalloc((qh hull_dim+1) * qh hull_dim * sizeof(coordT));
+  qh gm_row= (coordT **)qh_memalloc((qh hull_dim+1) * sizeof(coordT *));
+} /* initqhull_buffers */
+
+/*---------------------------------
+
+  qh_initqhull_globals( points, numpoints, dim, ismalloc )
+    initialize globals
+    if ismalloc
+      points were malloc'd and qhull should free at end
+
+  returns:
+    sets qh.first_point, num_points, input_dim, hull_dim and others
+    seeds random number generator (seed=1 if tracing)
+    modifies qh.hull_dim if ((qh.DELAUNAY and qh.PROJECTdelaunay) or qh.PROJECTinput)
+    adjust user flags as needed
+    also checks DIM3 dependencies and constants
+
+  notes:
+    do not use qh_point() since an input transformation may move them elsewhere
+
+  see:
+    qh_initqhull_start() sets default values for non-zero globals
+
+  design:
+    initialize points array from input arguments
+    test for qh.ZEROcentrum
+      (i.e., use opposite vertex instead of cetrum for convexity testing)
+    test for qh.PRINTgood (i.e., only print 'good' facets)
+    initialize qh.CENTERtype, qh.normal_size,
+      qh.center_size, qh.TRACEpoint/level,
+    initialize and test random numbers
+    check for conflicting print output options
+*/
+void qh_initqhull_globals (coordT *points, int numpoints, int dim, boolT ismalloc) {
+  int seed, pointsneeded, extra= 0, i, randi, k;
+  boolT printgeom= False, printmath= False, printcoplanar= False;
+  realT randr;
+  realT factorial;
+
+  time_t timedata;
+
+  trace0((qh ferr, "qh_initqhull_globals: for %s | %s\n", qh rbox_command,
+      qh qhull_command));
+  qh POINTSmalloc= ismalloc;
+  qh first_point= points;
+  qh num_points= numpoints;
+  qh hull_dim= qh input_dim= dim;
+  if (!qh NOpremerge && !qh MERGEexact && !qh PREmerge && qh JOGGLEmax > REALmax/2) {
+    qh MERGING= True;
+    if (qh hull_dim <= 4) {
+      qh PREmerge= True;
+      qh_option ("_pre-merge", NULL, NULL);
+    }else {
+      qh MERGEexact= True;
+      qh_option ("Qxact_merge", NULL, NULL);
+    }
+  }else if (qh MERGEexact) 
+    qh MERGING= True;
+  if (!qh NOpremerge && qh JOGGLEmax > REALmax/2) {
+#ifdef qh_NOmerge
+    qh JOGGLEmax= 0.0;
+#endif
+  }
+  if (qh TRIangulate && qh JOGGLEmax < REALmax/2 && qh PRINTprecision)
+    fprintf(qh ferr, "qhull warning: joggle ('QJ') always produces simplicial output.  Triangulated output ('Qt') does nothing.\n");
+  if (qh JOGGLEmax < REALmax/2 && qh DELAUNAY && !qh SCALEinput && !qh SCALElast) {
+    qh SCALElast= True;
+    qh_option ("Qbbound-last-qj", NULL, NULL);
+  }
+  if (qh MERGING && !qh POSTmerge && qh premerge_cos > REALmax/2
+  && qh premerge_centrum == 0) {
+    qh ZEROcentrum= True;
+    qh ZEROall_ok= True;
+    qh_option ("_zero-centrum", NULL, NULL);
+  }
+  if (qh JOGGLEmax < REALmax/2 && REALepsilon > 2e-8 && qh PRINTprecision)
+    fprintf(qh ferr, "qhull warning: real epsilon, %2.2g, is probably too large for joggle ('QJn')\nRecompile with double precision reals (see user.h).\n",
+          REALepsilon);
+#ifdef qh_NOmerge
+  if (qh MERGING) {
+    fprintf (qh ferr, "qhull input error: merging not installed (qh_NOmerge + 'Qx', 'Cn' or 'An')\n");
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }
+#endif
+  if (!(qh PRINTgood || qh PRINTneighbors)) {
+    if (qh KEEParea || qh KEEPminArea < REALmax/2 || qh KEEPmerge || qh DELAUNAY
+	|| (!qh ONLYgood && (qh GOODvertex || qh GOODpoint))) {
+      qh PRINTgood= True;
+      qh_option ("Pgood", NULL, NULL);
+    }
+  }
+  if (qh DELAUNAY && qh KEEPcoplanar && !qh KEEPinside) {
+    qh KEEPinside= True;
+    qh_option ("Qinterior-keep", NULL, NULL);
+  }
+  if (qh DELAUNAY && qh HALFspace) {
+    fprintf (qh ferr, "qhull input error: can not use Delaunay ('d') or Voronoi ('v') with halfspace intersection ('H')\n");
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }
+  if (!qh DELAUNAY && (qh UPPERdelaunay || qh ATinfinity)) {
+    fprintf (qh ferr, "qhull input error: use upper-Delaunay ('Qu') or infinity-point ('Qz') with Delaunay ('d') or Voronoi ('v')\n");
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }
+  if (qh UPPERdelaunay && qh ATinfinity) {
+    fprintf (qh ferr, "qhull input error: can not use infinity-point ('Qz') with upper-Delaunay ('Qu')\n");
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }
+  if (qh SCALElast && !qh DELAUNAY && qh PRINTprecision)
+    fprintf (qh ferr, "qhull input warning: option 'Qbb' (scale-last-coordinate) is normally used with 'd' or 'v'\n");
+  qh DOcheckmax= (!qh SKIPcheckmax && qh MERGING );
+  qh KEEPnearinside= (qh DOcheckmax && !(qh KEEPinside && qh KEEPcoplanar) 
+                          && !qh NOnearinside);
+  if (qh MERGING)
+    qh CENTERtype= qh_AScentrum;
+  else if (qh VORONOI)
+    qh CENTERtype= qh_ASvoronoi;
+  if (qh TESTvneighbors && !qh MERGING) {
+    fprintf(qh ferr, "qhull input error: test vertex neighbors ('Qv') needs a merge option\n");
+    qh_errexit (qh_ERRinput, NULL ,NULL);
+  }
+  if (qh PROJECTinput || (qh DELAUNAY && qh PROJECTdelaunay)) {
+    qh hull_dim -= qh PROJECTinput;
+    if (qh DELAUNAY) {
+      qh hull_dim++;
+      extra= 1;
+    }
+  }
+  if (qh hull_dim <= 1) {
+    fprintf(qh ferr, "qhull error: dimension %d must be > 1\n", qh hull_dim);
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }
+  for (k= 2, factorial=1.0; k < qh hull_dim; k++)
+    factorial *= k;
+  qh AREAfactor= 1.0 / factorial;
+  trace2((qh ferr, "qh_initqhull_globals: initialize globals.  dim %d numpoints %d malloc? %d projected %d to hull_dim %d\n",
+	dim, numpoints, ismalloc, qh PROJECTinput, qh hull_dim));
+  qh normal_size= qh hull_dim * sizeof(coordT);
+  qh center_size= qh normal_size - sizeof(coordT);
+  pointsneeded= qh hull_dim+1;
+  if (qh hull_dim > qh_DIMmergeVertex) {
+    qh MERGEvertices= False;
+    qh_option ("Q3-no-merge-vertices-dim-high", NULL, NULL);
+  }
+  if (qh GOODpoint)
+    pointsneeded++;
+#ifdef qh_NOtrace
+  if (qh IStracing) {
+    fprintf (qh ferr, "qhull input error: tracing is not installed (qh_NOtrace in user.h)");
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+#endif
+  if (qh RERUN > 1) {
+    qh TRACElastrun= qh IStracing; /* qh_build_withrestart duplicates next conditional */
+    if (qh IStracing != -1)
+      qh IStracing= 0;
+  }else if (qh TRACEpoint != -1 || qh TRACEdist < REALmax/2 || qh TRACEmerge) {
+    qh TRACElevel= (qh IStracing? qh IStracing : 3);
+    qh IStracing= 0;
+  }
+  if (qh ROTATErandom == 0 || qh ROTATErandom == -1) {
+    seed= time (&timedata);
+    if (qh ROTATErandom  == -1) {
+      seed= -seed;
+      qh_option ("QRandom-seed", &seed, NULL );
+    }else
+      qh_option ("QRotate-random", &seed, NULL);
+    qh ROTATErandom= seed;
+  }
+  seed= qh ROTATErandom;
+  if (seed == INT_MIN)    /* default value */
+    seed= 1;
+  else if (seed < 0)
+    seed= -seed;
+  qh_RANDOMseed_(seed);
+  randr= 0.0;
+  for (i= 1000; i--; ) {
+    randi= qh_RANDOMint;
+    randr += randi;
+    if (randi > qh_RANDOMmax) {
+      fprintf (qh ferr, "\
+qhull configuration error (qh_RANDOMmax in user.h):\n\
+   random integer %d > qh_RANDOMmax (%.8g)\n",
+	       randi, qh_RANDOMmax);
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }
+  }
+  qh_RANDOMseed_(seed);
+  randr = randr/1000;
+  if (randr < qh_RANDOMmax/10
+  || randr > qh_RANDOMmax * 5)
+    fprintf (qh ferr, "\
+qhull configuration warning (qh_RANDOMmax in user.h):\n\
+   average of 1000 random integers (%.2g) is much different than expected (%.2g).\n\
+   Is qh_RANDOMmax (%.2g) wrong?\n",
+	     randr, qh_RANDOMmax/2.0, qh_RANDOMmax);
+  qh RANDOMa= 2.0 * qh RANDOMfactor/qh_RANDOMmax;
+  qh RANDOMb= 1.0 - qh RANDOMfactor;
+  if (qh_HASHfactor < 1.1) {
+    fprintf(qh ferr, "qhull internal error (qh_initqhull_globals): qh_HASHfactor %d must be at least 1.1.  Qhull uses linear hash probing\n",
+      qh_HASHfactor);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  if (numpoints+extra < pointsneeded) {
+    fprintf(qh ferr,"qhull input error: not enough points (%d) to construct initial simplex (need %d)\n",
+	    numpoints, pointsneeded);
+    qh_errexit(qh_ERRinput, NULL, NULL);
+  }
+  if (qh PRINTtransparent) {
+    if (qh hull_dim != 4 || !qh DELAUNAY || qh VORONOI || qh DROPdim >= 0) {
+      fprintf(qh ferr,"qhull input error: transparent Delaunay ('Gt') needs 3-d Delaunay ('d') w/o 'GDn'\n");
+      qh_errexit(qh_ERRinput, NULL, NULL);
+    }
+    qh DROPdim = 3;
+    qh PRINTridges = True;
+  }
+  for (i= qh_PRINTEND; i--; ) {
+    if (qh PRINTout[i] == qh_PRINTgeom)
+      printgeom= True;
+    else if (qh PRINTout[i] == qh_PRINTmathematica)
+      printmath= True;
+    else if (qh PRINTout[i] == qh_PRINTcoplanars)
+      printcoplanar= True;
+    else if (qh PRINTout[i] == qh_PRINTpointnearest)
+      printcoplanar= True;
+    else if (qh PRINTout[i] == qh_PRINTpointintersect && !qh HALFspace) {
+      fprintf (qh ferr, "qhull input error: option 'Fp' is only used for \nhalfspace intersection ('Hn,n,n').\n");
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }else if (qh PRINTout[i] == qh_PRINTtriangles && (qh HALFspace || qh VORONOI)) {
+      fprintf (qh ferr, "qhull input error: option 'Ft' is not available for Voronoi vertices or halfspace intersection\n");
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }else if (qh PRINTout[i] == qh_PRINTcentrums && qh VORONOI) {
+      fprintf (qh ferr, "qhull input error: option 'FC' is not available for Voronoi vertices ('v')\n");
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }else if (qh PRINTout[i] == qh_PRINTvertices) {
+      if (qh VORONOI)
+        qh_option ("Fvoronoi", NULL, NULL);
+      else 
+        qh_option ("Fvertices", NULL, NULL);
+    }
+  }
+  if (printcoplanar && qh DELAUNAY && qh JOGGLEmax < REALmax/2) {
+    if (qh PRINTprecision) 
+      fprintf (qh ferr, "qhull input warning: 'QJ' (joggle) will usually prevent coincident input sites for options 'Fc' and 'FP'\n");
+  }
+  if (!qh KEEPcoplanar && !qh KEEPinside && !qh ONLYgood) {
+    if ((qh PRINTcoplanar && qh PRINTspheres) || printcoplanar) {
+      qh KEEPcoplanar = True;
+      qh_option ("Qcoplanar", NULL, NULL);
+    }
+  }
+  if (printmath && (qh hull_dim > 3 || qh VORONOI)) {
+    fprintf (qh ferr, "qhull input error: Mathematica output is only available for 2-d and 3-d convex hulls and 2-d Delaunay triangulations\n");
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }
+  if (printgeom) {
+    if (qh hull_dim > 4) {
+      fprintf (qh ferr, "qhull input error: Geomview output is only available for 2-d, 3-d and 4-d\n");
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }
+    if (qh PRINTnoplanes && !(qh PRINTcoplanar + qh PRINTcentrums
+     + qh PRINTdots + qh PRINTspheres + qh DOintersections + qh PRINTridges)) {
+      fprintf (qh ferr, "qhull input error: no output specified for Geomview\n");
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }
+    if (qh VORONOI && (qh hull_dim > 3 || qh DROPdim >= 0)) {
+      fprintf (qh ferr, "qhull input error: Geomview output for Voronoi diagrams only for 2-d\n");
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }
+    /* can not warn about furthest-site Geomview output: no lower_threshold */
+    if (qh hull_dim == 4 && qh DROPdim == -1 &&
+	(qh PRINTcoplanar || qh PRINTspheres || qh PRINTcentrums)) {
+      fprintf (qh ferr, "qhull input warning: coplanars, vertices, and centrums output not\n\
+available for 4-d output (ignored).  Could use 'GDn' instead.\n");
+      qh PRINTcoplanar= qh PRINTspheres= qh PRINTcentrums= False;
+    }
+  }
+  qh PRINTdim= qh hull_dim;
+  if (qh DROPdim >=0) {    /* after Geomview checks */
+    if (qh DROPdim < qh hull_dim) {
+      qh PRINTdim--;
+      if (!printgeom || qh hull_dim < 3)
+        fprintf (qh ferr, "qhull input warning: drop dimension 'GD%d' is only available for 3-d/4-d Geomview\n", qh DROPdim);
+    }else
+      qh DROPdim= -1;
+  }else if (qh VORONOI) {
+    qh DROPdim= qh hull_dim-1;
+    qh PRINTdim= qh hull_dim-1;
+  }
+} /* initqhull_globals */
+ 
+/*---------------------------------
+
+  qh_initqhull_mem(  )
+    initialize mem.c for qhull
+    qh.hull_dim and qh.normal_size determine some of the allocation sizes
+    if qh.MERGING,
+      includes ridgeT
+    calls qh_user_memsizes() to add up to 10 additional sizes for quick allocation
+      (see numsizes below)
+
+  returns:
+    mem.c already for qh_memalloc/qh_memfree (errors if called beforehand)
+
+  notes:
+    qh_produceoutput() prints memsizes
+
+*/
+void qh_initqhull_mem (void) {
+  int numsizes;
+  int i;
+
+  numsizes= 8+10;
+  qh_meminitbuffers (qh IStracing, qh_MEMalign, numsizes,
+                     qh_MEMbufsize,qh_MEMinitbuf);
+  qh_memsize(sizeof(vertexT));
+  if (qh MERGING) {
+    qh_memsize(sizeof(ridgeT));
+    qh_memsize(sizeof(mergeT));
+  }
+  qh_memsize(sizeof(facetT));
+  i= sizeof(setT) + (qh hull_dim - 1) * SETelemsize;  /* ridge.vertices */
+  qh_memsize(i);
+  qh_memsize(qh normal_size);        /* normal */
+  i += SETelemsize;                 /* facet.vertices, .ridges, .neighbors */
+  qh_memsize(i);
+  qh_user_memsizes();
+  qh_memsetup();
+} /* initqhull_mem */
+
+/*---------------------------------
+
+  qh_initqhull_start( infile, outfile, errfile )
+    start initialization of qhull
+    initialize statistics, stdio, default values for global variables
+
+  see:
+    qh_maxmin() determines the precision constants
+*/
+void qh_initqhull_start (FILE *infile, FILE *outfile, FILE *errfile) {
+
+  qh_CPUclock; /* start the clock */
+#if qh_QHpointer
+  if (!(qh_qh= (qhT *)malloc (sizeof(qhT)))) {
+    fprintf (errfile, "qhull error (qh_initqhull_globals): insufficient memory\n");
+    exit (qh_ERRmem);  /* no error handler */
+  }
+  memset((char *)qh_qh, 0, sizeof(qhT));   /* every field is 0, FALSE, NULL */
+#else
+  memset((char *)&qh_qh, 0, sizeof(qhT));
+#endif
+  strcat (qh qhull, "qhull");
+  qh_initstatistics();
+  qh ANGLEmerge= True;
+  qh DROPdim= -1;
+  qh ferr= errfile;
+  qh fin= infile;
+  qh fout= outfile;
+  qh furthest_id= -1;
+  qh JOGGLEmax= REALmax;
+  qh KEEPminArea = REALmax;
+  qh last_low= REALmax;
+  qh last_high= REALmax;
+  qh last_newhigh= REALmax;
+  qh max_outside= 0.0;
+  qh max_vertex= 0.0;
+  qh MAXabs_coord= 0.0;
+  qh MAXsumcoord= 0.0;
+  qh MAXwidth= -REALmax;
+  qh MERGEindependent= True;
+  qh MINdenom_1= fmax_(1.0/REALmax, REALmin); /* used by qh_scalepoints */
+  qh MINoutside= 0.0;
+  qh MINvisible= REALmax;
+  qh MAXcoplanar= REALmax;
+  qh outside_err= REALmax;
+  qh premerge_centrum= 0.0;
+  qh premerge_cos= REALmax;
+  qh PRINTprecision= True;
+  qh PRINTradius= 0.0;
+  qh postmerge_cos= REALmax;
+  qh postmerge_centrum= 0.0;
+  qh ROTATErandom= INT_MIN;
+  qh MERGEvertices= True;
+  qh totarea= 0.0;
+  qh totvol= 0.0;
+  qh TRACEdist= REALmax;
+  qh TRACEpoint= -1; /* recompile or use 'TPn' */
+  qh tracefacet_id= UINT_MAX;  /* recompile to trace a facet */
+  qh tracevertex_id= UINT_MAX; /* recompile to trace a vertex */
+  qh_RANDOMseed_(1);
+} /* initqhull_start */
+
+/*---------------------------------
+
+  qh_initthresholds( commandString )
+    set thresholds for printing and scaling from commandString
+
+  returns:
+    sets qh.GOODthreshold or qh.SPLITthreshold if 'Pd0D1' used
+
+  see:
+    qh_initflags(), 'Qbk' 'QBk' 'Pdk' and 'PDk'
+    qh_inthresholds()
+
+  design:
+    for each 'Pdn' or 'PDn' option
+      check syntax
+      set qh.lower_threshold or qh.upper_threshold
+    set qh.GOODthreshold if an unbounded threshold is used
+    set qh.SPLITthreshold if a bounded threshold is used
+*/
+void qh_initthresholds(char *command) {
+  realT value;
+  int index, maxdim, k;
+  char *s= command;
+  char key;
+
+  maxdim= qh input_dim;
+  if (qh DELAUNAY && (qh PROJECTdelaunay || qh PROJECTinput))
+    maxdim++;
+  while (*s) {
+    if (*s == '-')
+      s++;
+    if (*s == 'P') {
+      s++;
+      while (*s && !isspace(key= *s++)) {
+	if (key == 'd' || key == 'D') {
+	  if (!isdigit(*s)) {
+	    fprintf(qh ferr, "qhull warning: no dimension given for Print option '%c' at: %s.  Ignored\n",
+		    key, s-1);
+	    continue;
+	  }
+	  index= qh_strtol (s, &s);
+	  if (index >= qh hull_dim) {
+	    fprintf(qh ferr, "qhull warning: dimension %d for Print option '%c' is >= %d.  Ignored\n",
+	        index, key, qh hull_dim);
+	    continue;
+	  }
+	  if (*s == ':') {
+	    s++;
+	    value= qh_strtod(s, &s);
+	    if (fabs((double)value) > 1.0) {
+	      fprintf(qh ferr, "qhull warning: value %2.4g for Print option %c is > +1 or < -1.  Ignored\n",
+	              value, key);
+	      continue;
+	    }
+	  }else
+	    value= 0.0;
+	  if (key == 'd')
+	    qh lower_threshold[index]= value;
+	  else
+	    qh upper_threshold[index]= value;
+	}
+      }
+    }else if (*s == 'Q') {
+      s++;
+      while (*s && !isspace(key= *s++)) {
+	if (key == 'b' && *s == 'B') {
+	  s++;
+	  for (k=maxdim; k--; ) {
+	    qh lower_bound[k]= -qh_DEFAULTbox;
+	    qh upper_bound[k]= qh_DEFAULTbox;
+	  }
+	}else if (key == 'b' && *s == 'b')
+	  s++;
+	else if (key == 'b' || key == 'B') {
+	  if (!isdigit(*s)) {
+	    fprintf(qh ferr, "qhull warning: no dimension given for Qhull option %c.  Ignored\n",
+		    key);
+	    continue;
+	  }
+	  index= qh_strtol (s, &s);
+	  if (index >= maxdim) {
+	    fprintf(qh ferr, "qhull warning: dimension %d for Qhull option %c is >= %d.  Ignored\n",
+	        index, key, maxdim);
+	    continue;
+	  }
+	  if (*s == ':') {
+	    s++;
+	    value= qh_strtod(s, &s);
+	  }else if (key == 'b')
+	    value= -qh_DEFAULTbox;
+	  else
+	    value= qh_DEFAULTbox;
+	  if (key == 'b')
+	    qh lower_bound[index]= value;
+	  else
+	    qh upper_bound[index]= value;
+	}
+      }
+    }else {
+      while (*s && !isspace (*s))
+        s++;
+    }
+    while (isspace (*s))
+      s++;
+  }
+  for (k= qh hull_dim; k--; ) {
+    if (qh lower_threshold[k] > -REALmax/2) {
+      qh GOODthreshold= True;
+      if (qh upper_threshold[k] < REALmax/2) {
+        qh SPLITthresholds= True;
+        qh GOODthreshold= False;
+        break;
+      }
+    }else if (qh upper_threshold[k] < REALmax/2)
+      qh GOODthreshold= True;
+  }
+} /* initthresholds */
+
+/*---------------------------------
+
+  qh_option( option, intVal, realVal )
+    add an option description to qh.qhull_options
+
+  notes:
+    will be printed with statistics ('Ts') and errors
+    strlen(option) < 40
+*/
+void qh_option (char *option, int *i, realT *r) {
+  char buf[200];
+  int len, maxlen;
+
+  sprintf (buf, "  %s", option);
+  if (i)
+    sprintf (buf+strlen(buf), " %d", *i);
+  if (r)
+    sprintf (buf+strlen(buf), " %2.2g", *r);
+  len= strlen(buf);
+  qh qhull_optionlen += len;
+  maxlen= sizeof (qh qhull_options) - len -1;
+  maximize_(maxlen, 0);
+  if (qh qhull_optionlen >= 80 && maxlen > 0) {
+    qh qhull_optionlen= len;
+    strncat (qh qhull_options, "\n", maxlen--);
+  }
+  strncat (qh qhull_options, buf, maxlen);
+} /* option */
+
+#if qh_QHpointer
+/*---------------------------------
+
+  qh_restore_qhull( oldqh )
+    restores a previously saved qhull
+    also restores qh_qhstat and qhmem.tempstack
+
+  notes:
+    errors if current qhull hasn't been saved or freed
+    uses qhmem for error reporting
+
+  NOTE 1998/5/11:
+    Freeing memory after qh_save_qhull and qh_restore_qhull
+    is complicated.  The procedures will be redesigned.
+
+  see:
+    qh_save_qhull()
+*/
+void qh_restore_qhull (qhT **oldqh) {
+
+  if (*oldqh && strcmp ((*oldqh)->qhull, "qhull")) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_restore_qhull): %p is not a qhull data structure\n",
+                  *oldqh);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  if (qh_qh) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_restore_qhull): did not save or free existing qhull\n");
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  if (!*oldqh || !(*oldqh)->old_qhstat) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_restore_qhull): did not previously save qhull %p\n",
+                  *oldqh);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  qh_qh= *oldqh;
+  *oldqh= NULL;
+  qh_qhstat= qh old_qhstat;
+  qhmem.tempstack= qh old_tempstack;
+  trace1((qh ferr, "qh_restore_qhull: restored qhull from %p\n", *oldqh));
+} /* restore_qhull */
+
+/*---------------------------------
+
+  qh_save_qhull(  )
+    saves qhull for a later qh_restore_qhull
+    also saves qh_qhstat and qhmem.tempstack
+
+  returns:
+    qh_qh=NULL
+
+  notes:
+    need to initialize qhull or call qh_restore_qhull before continuing
+
+  NOTE 1998/5/11:
+    Freeing memory after qh_save_qhull and qh_restore_qhull
+    is complicated.  The procedures will be redesigned.
+
+  see:
+    qh_restore_qhull()
+*/
+qhT *qh_save_qhull (void) {
+  qhT *oldqh;
+
+  trace1((qhmem.ferr, "qh_save_qhull: save qhull %p\n", qh_qh));
+  if (!qh_qh) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_save_qhull): qhull not initialized\n");
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  qh old_qhstat= qh_qhstat;
+  qh_qhstat= NULL;
+  qh old_tempstack= qhmem.tempstack;
+  qhmem.tempstack= NULL;
+  oldqh= qh_qh;
+  qh_qh= NULL;
+  return oldqh;
+} /* save_qhull */
+
+#endif
+
+/*---------------------------------
+
+  qh_strtol( s, endp) qh_strtod( s, endp)
+    internal versions of strtol() and strtod()
+    does not skip trailing spaces
+  notes:
+    some implementations of strtol()/strtod() skip trailing spaces
+*/
+double qh_strtod (const char *s, char **endp) {
+  double result;
+
+  result= strtod (s, endp);
+  if (s < (*endp) && (*endp)[-1] == ' ')
+    (*endp)--;
+  return result;
+} /* strtod */
+
+int qh_strtol (const char *s, char **endp) {
+  int result;
+
+  result= (int) strtol (s, endp, 10);
+  if (s< (*endp) && (*endp)[-1] == ' ')
+    (*endp)--;
+  return result;
+} /* strtol */
diff --git a/extern/qhull/src/io.c b/extern/qhull/src/io.c
new file mode 100644
index 00000000000..9b0ccdd0b24
--- /dev/null
+++ b/extern/qhull/src/io.c
@@ -0,0 +1,4089 @@
+/*
  ---------------------------------
+
+   io.c 
+   Input/Output routines of qhull application
+
+   see qh-io.htm and io.h
+
+   see user.c for qh_errprint and qh_printfacetlist
+
+   unix.c calls qh_readpoints and qh_produce_output
+
+   unix.c and user.c are the only callers of io.c functions
+   This allows the user to avoid loading io.o from qhull.a
+
+   copyright (c) 1993-2002 The Geometry Center        
+*/
+
+#include "qhull_a.h"
+
+/*========= -prototypes for internal functions ========= */
+
+static int qh_compare_facetarea(const void *p1, const void *p2);
+static int qh_compare_facetmerge(const void *p1, const void *p2);
+static int qh_compare_facetvisit(const void *p1, const void *p2);
+int qh_compare_vertexpoint(const void *p1, const void *p2); /* not used */
+
+/*========= -functions in alphabetical order after qh_produce_output()  =====*/
+
+/*---------------------------------
+  
+  qh_produce_output()
+    prints out the result of qhull in desired format
+    if qh.GETarea
+      computes and prints area and volume
+    qh.PRINTout[] is an array of output formats
+
+  notes:
+    prints output in qh.PRINTout order
+*/
+void qh_produce_output(void) {
+  int i, tempsize= qh_setsize ((setT*)qhmem.tempstack), d_1;
+
+  if (qh VORONOI) {
+    qh_clearcenters (qh_ASvoronoi);
+    qh_vertexneighbors();
+  }
+  if (qh TRIangulate) {
+    qh_triangulate(); 
+    if (qh VERIFYoutput && !qh CHECKfrequently) 
+      qh_checkpolygon (qh facet_list);
+  }
+  qh_findgood_all (qh facet_list); 
+  if (qh GETarea)
+    qh_getarea(qh facet_list);
+  if (qh KEEParea || qh KEEPmerge || qh KEEPminArea < REALmax/2)
+    qh_markkeep (qh facet_list);
+  if (qh PRINTsummary)
+    qh_printsummary(qh ferr);
+  else if (qh PRINTout[0] == qh_PRINTnone)
+    qh_printsummary(qh fout);
+  for (i= 0; i < qh_PRINTEND; i++)
+    qh_printfacets (qh fout, qh PRINTout[i], qh facet_list, NULL, !qh_ALL);
+  qh_allstatistics();
+  if (qh PRINTprecision && !qh MERGING && (qh JOGGLEmax > REALmax/2 || qh RERUN))
+    qh_printstats (qh ferr, qhstat precision, NULL);
+  if (qh VERIFYoutput && (zzval_(Zridge) > 0 || zzval_(Zridgemid) > 0)) 
+    qh_printstats (qh ferr, qhstat vridges, NULL);
+  if (qh PRINTstatistics) {
+    qh_collectstatistics();
+    qh_printstatistics(qh ferr, "");
+    qh_memstatistics (qh ferr);
+    d_1= sizeof(setT) + (qh hull_dim - 1) * SETelemsize;
+    fprintf(qh ferr, "\
+    size in bytes: merge %ld ridge %ld vertex %ld facet %ld\n\
+         normal %d ridge vertices %d facet vertices or neighbors %ld\n",
+	    sizeof(mergeT), sizeof(ridgeT),
+	    sizeof(vertexT), sizeof(facetT),
+	    qh normal_size, d_1, d_1 + SETelemsize);
+  }
+  if (qh_setsize ((setT*)qhmem.tempstack) != tempsize) {
+    fprintf (qh ferr, "qhull internal error (qh_produce_output): temporary sets not empty (%d)\n",
+	     qh_setsize ((setT*)qhmem.tempstack));
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+} /* produce_output */
+
+
+/*---------------------------------
+  
+  dfacet( id )
+    print facet by id, for debugging
+
+*/
+void dfacet (unsigned id) {
+  facetT *facet;
+
+  FORALLfacets {
+    if (facet->id == id) {
+      qh_printfacet (qh fout, facet);
+      break;
+    }
+  }
+} /* dfacet */
+
+
+/*---------------------------------
+  
+  dvertex( id )
+    print vertex by id, for debugging
+*/
+void dvertex (unsigned id) {
+  vertexT *vertex;
+
+  FORALLvertices {
+    if (vertex->id == id) {
+      qh_printvertex (qh fout, vertex);
+      break;
+    }
+  }
+} /* dvertex */
+
+
+/*---------------------------------
+  
+  qh_compare_vertexpoint( p1, p2 )
+    used by qsort() to order vertices by point id 
+*/
+int qh_compare_vertexpoint(const void *p1, const void *p2) {
+  vertexT *a= *((vertexT **)p1), *b= *((vertexT **)p2);
+ 
+  return ((qh_pointid(a->point) > qh_pointid(b->point)?1:-1));
+} /* compare_vertexpoint */
+
+/*---------------------------------
+  
+  qh_compare_facetarea( p1, p2 )
+    used by qsort() to order facets by area
+*/
+static int qh_compare_facetarea(const void *p1, const void *p2) {
+  facetT *a= *((facetT **)p1), *b= *((facetT **)p2);
+
+  if (!a->isarea)
+    return -1;
+  if (!b->isarea)
+    return 1; 
+  if (a->f.area > b->f.area)
+    return 1;
+  else if (a->f.area == b->f.area)
+    return 0;
+  return -1;
+} /* compare_facetarea */
+
+/*---------------------------------
+  
+  qh_compare_facetmerge( p1, p2 )
+    used by qsort() to order facets by number of merges
+*/
+static int qh_compare_facetmerge(const void *p1, const void *p2) {
+  facetT *a= *((facetT **)p1), *b= *((facetT **)p2);
+ 
+  return (a->nummerge - b->nummerge);
+} /* compare_facetvisit */
+
+/*---------------------------------
+  
+  qh_compare_facetvisit( p1, p2 )
+    used by qsort() to order facets by visit id or id
+*/
+static int qh_compare_facetvisit(const void *p1, const void *p2) {
+  facetT *a= *((facetT **)p1), *b= *((facetT **)p2);
+  int i,j;
+
+  if (!(i= a->visitid))
+    i= - a->id; /* do not convert to int */
+  if (!(j= b->visitid))
+    j= - b->id;
+  return (i - j);
+} /* compare_facetvisit */
+
+/*---------------------------------
+  
+  qh_countfacets( facetlist, facets, printall, 
+          numfacets, numsimplicial, totneighbors, numridges, numcoplanar, numtricoplanars  )
+    count good facets for printing and set visitid
+    if allfacets, ignores qh_skipfacet()
+
+  notes:
+    qh_printsummary and qh_countfacets must match counts
+
+  returns:
+    numfacets, numsimplicial, total neighbors, numridges, coplanars
+    each facet with ->visitid indicating 1-relative position
+      ->visitid==0 indicates not good
+  
+  notes
+    numfacets >= numsimplicial
+    if qh.NEWfacets, 
+      does not count visible facets (matches qh_printafacet)
+
+  design:
+    for all facets on facetlist and in facets set
+      unless facet is skipped or visible (i.e., will be deleted)
+        mark facet->visitid
+        update counts
+*/
+void qh_countfacets (facetT *facetlist, setT *facets, boolT printall,
+    int *numfacetsp, int *numsimplicialp, int *totneighborsp, int *numridgesp, int *numcoplanarsp, int *numtricoplanarsp) {
+  facetT *facet, **facetp;
+  int numfacets= 0, numsimplicial= 0, numridges= 0, totneighbors= 0, numcoplanars= 0, numtricoplanars= 0;
+
+  FORALLfacet_(facetlist) {
+    if ((facet->visible && qh NEWfacets)
+    || (!printall && qh_skipfacet(facet)))
+      facet->visitid= 0;
+    else {
+      facet->visitid= ++numfacets;
+      totneighbors += qh_setsize (facet->neighbors);
+      if (facet->simplicial) {
+        numsimplicial++;
+	if (facet->keepcentrum && facet->tricoplanar)
+	  numtricoplanars++;
+      }else
+        numridges += qh_setsize (facet->ridges);
+      if (facet->coplanarset)
+        numcoplanars += qh_setsize (facet->coplanarset);
+    }
+  }
+  FOREACHfacet_(facets) {
+    if ((facet->visible && qh NEWfacets)
+    || (!printall && qh_skipfacet(facet)))
+      facet->visitid= 0;
+    else {
+      facet->visitid= ++numfacets;
+      totneighbors += qh_setsize (facet->neighbors);
+      if (facet->simplicial){
+        numsimplicial++;
+	if (facet->keepcentrum && facet->tricoplanar)
+	  numtricoplanars++;
+      }else
+        numridges += qh_setsize (facet->ridges);
+      if (facet->coplanarset)
+        numcoplanars += qh_setsize (facet->coplanarset);
+    }
+  }
+  qh visit_id += numfacets+1;
+  *numfacetsp= numfacets;
+  *numsimplicialp= numsimplicial;
+  *totneighborsp= totneighbors;
+  *numridgesp= numridges;
+  *numcoplanarsp= numcoplanars;
+  *numtricoplanarsp= numtricoplanars;
+} /* countfacets */
+
+/*---------------------------------
+  
+  qh_detvnorm( vertex, vertexA, centers, offset )
+    compute separating plane of the Voronoi diagram for a pair of input sites
+    centers= set of facets (i.e., Voronoi vertices)
+      facet->visitid= 0 iff vertex-at-infinity (i.e., unbounded)
+        
+  assumes:
+    qh_ASvoronoi and qh_vertexneighbors() already set
+  
+  returns:
+    norm
+      a pointer into qh.gm_matrix to qh.hull_dim-1 reals
+      copy the data before reusing qh.gm_matrix
+    offset
+      if 'QVn'
+        sign adjusted so that qh.GOODvertexp is inside
+      else
+        sign adjusted so that vertex is inside
+      
+    qh.gm_matrix= simplex of points from centers relative to first center
+    
+  notes:
+    in io.c so that code for 'v Tv' can be removed by removing io.c
+    returns pointer into qh.gm_matrix to avoid tracking of temporary memory
+  
+  design:
+    determine midpoint of input sites
+    build points as the set of Voronoi vertices
+    select a simplex from points (if necessary)
+      include midpoint if the Voronoi region is unbounded
+    relocate the first vertex of the simplex to the origin
+    compute the normalized hyperplane through the simplex
+    orient the hyperplane toward 'QVn' or 'vertex'
+    if 'Tv' or 'Ts'
+      if bounded
+        test that hyperplane is the perpendicular bisector of the input sites
+      test that Voronoi vertices not in the simplex are still on the hyperplane
+    free up temporary memory
+*/
+pointT *qh_detvnorm (vertexT *vertex, vertexT *vertexA, setT *centers, realT *offsetp) {
+  facetT *facet, **facetp;
+  int  i, k, pointid, pointidA, point_i, point_n;
+  setT *simplex= NULL;
+  pointT *point, **pointp, *point0, *midpoint, *normal, *inpoint;
+  coordT *coord, *gmcoord, *normalp;
+  setT *points= qh_settemp (qh TEMPsize);
+  boolT nearzero= False;
+  boolT unbounded= False;
+  int numcenters= 0;
+  int dim= qh hull_dim - 1;
+  realT dist, offset, angle, zero= 0.0;
+
+  midpoint= qh gm_matrix + qh hull_dim * qh hull_dim;  /* last row */
+  for (k= 0; k < dim; k++)
+    midpoint[k]= (vertex->point[k] + vertexA->point[k])/2;
+  FOREACHfacet_(centers) {
+    numcenters++;
+    if (!facet->visitid)
+      unbounded= True;
+    else {
+      if (!facet->center)
+        facet->center= qh_facetcenter (facet->vertices);
+      qh_setappend (&points, facet->center);
+    }
+  }
+  if (numcenters > dim) {
+    simplex= qh_settemp (qh TEMPsize);
+    qh_setappend (&simplex, vertex->point);
+    if (unbounded)
+      qh_setappend (&simplex, midpoint);
+    qh_maxsimplex (dim, points, NULL, 0, &simplex);
+    qh_setdelnth (simplex, 0);
+  }else if (numcenters == dim) {
+    if (unbounded)
+      qh_setappend (&points, midpoint);
+    simplex= points; 
+  }else {
+    fprintf(qh ferr, "qh_detvnorm: too few points (%d) to compute separating plane\n", numcenters);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  i= 0;
+  gmcoord= qh gm_matrix;
+  point0= SETfirstt_(simplex, pointT);
+  FOREACHpoint_(simplex) {
+    if (qh IStracing >= 4)
+      qh_printmatrix(qh ferr, "qh_detvnorm: Voronoi vertex or midpoint", 
+                              &point, 1, dim);
+    if (point != point0) {
+      qh gm_row[i++]= gmcoord;
+      coord= point0;
+      for (k= dim; k--; )
+        *(gmcoord++)= *point++ - *coord++;
+    }
+  }
+  qh gm_row[i]= gmcoord;  /* does not overlap midpoint, may be used later for qh_areasimplex */
+  normal= gmcoord;
+  qh_sethyperplane_gauss (dim, qh gm_row, point0, True,
+           	normal, &offset, &nearzero);
+  if (qh GOODvertexp == vertexA->point)
+    inpoint= vertexA->point;
+  else
+    inpoint= vertex->point;
+  zinc_(Zdistio);
+  dist= qh_distnorm (dim, inpoint, normal, &offset);
+  if (dist > 0) {
+    offset= -offset;
+    normalp= normal;
+    for (k= dim; k--; ) {
+      *normalp= -(*normalp);
+      normalp++;
+    }
+  }
+  if (qh VERIFYoutput || qh PRINTstatistics) {
+    pointid= qh_pointid (vertex->point);
+    pointidA= qh_pointid (vertexA->point);
+    if (!unbounded) {
+      zinc_(Zdiststat);
+      dist= qh_distnorm (dim, midpoint, normal, &offset);
+      if (dist < 0)
+        dist= -dist;
+      zzinc_(Zridgemid);
+      wwmax_(Wridgemidmax, dist);
+      wwadd_(Wridgemid, dist);
+      trace4((qh ferr, "qh_detvnorm: points %d %d midpoint dist %2.2g\n",
+                 pointid, pointidA, dist));
+      for (k= 0; k < dim; k++) 
+        midpoint[k]= vertexA->point[k] - vertex->point[k];  /* overwrites midpoint! */
+      qh_normalize (midpoint, dim, False);
+      angle= qh_distnorm (dim, midpoint, normal, &zero); /* qh_detangle uses dim+1 */
+      if (angle < 0.0)
+	angle= angle + 1.0;
+      else
+	angle= angle - 1.0;
+      if (angle < 0.0)
+	angle -= angle;
+      trace4((qh ferr, "qh_detvnorm: points %d %d angle %2.2g nearzero %d\n",
+                 pointid, pointidA, angle, nearzero));
+      if (nearzero) {
+        zzinc_(Zridge0);
+        wwmax_(Wridge0max, angle);
+        wwadd_(Wridge0, angle);
+      }else {
+        zzinc_(Zridgeok)
+        wwmax_(Wridgeokmax, angle);
+        wwadd_(Wridgeok, angle);
+      }
+    }
+    if (simplex != points) {
+      FOREACHpoint_i_(points) {
+        if (!qh_setin (simplex, point)) {
+          facet= SETelemt_(centers, point_i, facetT);
+	  zinc_(Zdiststat);
+  	  dist= qh_distnorm (dim, point, normal, &offset);
+          if (dist < 0)
+            dist= -dist;
+	  zzinc_(Zridge);
+          wwmax_(Wridgemax, dist);
+          wwadd_(Wridge, dist);
+          trace4((qh ferr, "qh_detvnorm: points %d %d Voronoi vertex %d dist %2.2g\n",
+                             pointid, pointidA, facet->visitid, dist));
+        }
+      }
+    }
+  }
+  *offsetp= offset;
+  if (simplex != points)
+    qh_settempfree (&simplex);
+  qh_settempfree (&points);
+  return normal;
+} /* detvnorm */
+
+/*---------------------------------
+
+  qh_detvridge( vertexA )
+    determine Voronoi ridge from 'seen' neighbors of vertexA
+    include one vertex-at-infinite if an !neighbor->visitid
+
+  returns:
+    temporary set of centers (facets, i.e., Voronoi vertices)
+    sorted by center id
+*/
+setT *qh_detvridge (vertexT *vertex) {
+  setT *centers= qh_settemp (qh TEMPsize);
+  setT *tricenters= qh_settemp (qh TEMPsize);
+  facetT *neighbor, **neighborp;
+  boolT firstinf= True;
+  
+  FOREACHneighbor_(vertex) {
+    if (neighbor->seen) {
+      if (neighbor->visitid) {
+	if (!neighbor->tricoplanar || qh_setunique (&tricenters, neighbor->center)) 
+	  qh_setappend (¢ers, neighbor);
+      }else if (firstinf) {
+        firstinf= False;
+        qh_setappend (¢ers, neighbor);
+      }
+    }
+  }
+  qsort (SETaddr_(centers, facetT), qh_setsize (centers),
+             sizeof (facetT *), qh_compare_facetvisit);
+  qh_settempfree (&tricenters);
+  return centers;
+} /* detvridge */      
+
+/*---------------------------------
+
+  qh_detvridge3( atvertex, vertex )
+    determine 3-d Voronoi ridge from 'seen' neighbors of atvertex and vertex
+    include one vertex-at-infinite for !neighbor->visitid
+    assumes all facet->seen2= True
+
+  returns:
+    temporary set of centers (facets, i.e., Voronoi vertices)
+    listed in adjacency order (not oriented)
+    all facet->seen2= True
+
+  design:
+    mark all neighbors of atvertex
+    for each adjacent neighbor of both atvertex and vertex
+      if neighbor selected
+        add neighbor to set of Voronoi vertices
+*/
+setT *qh_detvridge3 (vertexT *atvertex, vertexT *vertex) {
+  setT *centers= qh_settemp (qh TEMPsize);
+  setT *tricenters= qh_settemp (qh TEMPsize);
+  facetT *neighbor, **neighborp, *facet= NULL;
+  boolT firstinf= True;
+  
+  FOREACHneighbor_(atvertex)
+    neighbor->seen2= False;
+  FOREACHneighbor_(vertex) {
+    if (!neighbor->seen2) {
+      facet= neighbor;
+      break;
+    }
+  }
+  while (facet) { 
+    facet->seen2= True;
+    if (neighbor->seen) {
+      if (facet->visitid) {
+	if (!facet->tricoplanar || qh_setunique (&tricenters, facet->center)) 
+	  qh_setappend (¢ers, facet);
+      }else if (firstinf) {
+        firstinf= False;
+        qh_setappend (¢ers, facet);
+      }
+    }
+    FOREACHneighbor_(facet) {
+      if (!neighbor->seen2) {
+	if (qh_setin (vertex->neighbors, neighbor))
+          break;
+	else
+	  neighbor->seen2= True;
+      }
+    }
+    facet= neighbor;
+  }
+  if (qh CHECKfrequently) {
+    FOREACHneighbor_(vertex) {
+      if (!neighbor->seen2) {
+	fprintf (stderr, "qh_detvridge3: neigbors of vertex p%d are not connected at facet %d\n",
+	         qh_pointid (vertex->point), neighbor->id);
+	qh_errexit (qh_ERRqhull, neighbor, NULL);
+      }
+    }
+  }
+  FOREACHneighbor_(atvertex) 
+    neighbor->seen2= True;
+  qh_settempfree (&tricenters);
+  return centers;
+} /* detvridge3 */      
+
+/*---------------------------------
+  
+  qh_eachvoronoi( fp, printvridge, vertex, visitall, innerouter, inorder )
+    if visitall,
+      visit all Voronoi ridges for vertex (i.e., an input site)
+    else
+      visit all unvisited Voronoi ridges for vertex
+      all vertex->seen= False if unvisited
+    assumes
+      all facet->seen= False
+      all facet->seen2= True (for qh_detvridge3)
+      all facet->visitid == 0 if vertex_at_infinity
+                         == index of Voronoi vertex 
+                         >= qh.num_facets if ignored
+    innerouter:
+      qh_RIDGEall--  both inner (bounded) and outer (unbounded) ridges
+      qh_RIDGEinner- only inner
+      qh_RIDGEouter- only outer
+      
+    if inorder
+      orders vertices for 3-d Voronoi diagrams
+  
+  returns:
+    number of visited ridges (does not include previously visited ridges)
+    
+    if printvridge,
+      calls printvridge( fp, vertex, vertexA, centers)
+        fp== any pointer (assumes FILE*)
+        vertex,vertexA= pair of input sites that define a Voronoi ridge
+        centers= set of facets (i.e., Voronoi vertices)
+                 ->visitid == index or 0 if vertex_at_infinity
+                 ordered for 3-d Voronoi diagram
+  notes:
+    uses qh.vertex_visit
+  
+  see:
+    qh_eachvoronoi_all()
+  
+  design:
+    mark selected neighbors of atvertex
+    for each selected neighbor (either Voronoi vertex or vertex-at-infinity)
+      for each unvisited vertex 
+        if atvertex and vertex share more than d-1 neighbors
+          bump totalcount
+          if printvridge defined
+            build the set of shared neighbors (i.e., Voronoi vertices)
+            call printvridge
+*/
+int qh_eachvoronoi (FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder) {
+  boolT unbounded;
+  int count;
+  facetT *neighbor, **neighborp, *neighborA, **neighborAp;
+  setT *centers;
+  setT *tricenters= qh_settemp (qh TEMPsize);
+
+  vertexT *vertex, **vertexp;
+  boolT firstinf;
+  unsigned int numfacets= (unsigned int)qh num_facets;
+  int totridges= 0;
+
+  qh vertex_visit++;
+  atvertex->seen= True;
+  if (visitall) {
+    FORALLvertices 
+      vertex->seen= False;
+  }
+  FOREACHneighbor_(atvertex) {
+    if (neighbor->visitid < numfacets) 
+      neighbor->seen= True;
+  }
+  FOREACHneighbor_(atvertex) {
+    if (neighbor->seen) {
+      FOREACHvertex_(neighbor->vertices) {
+        if (vertex->visitid != qh vertex_visit && !vertex->seen) {
+	  vertex->visitid= qh vertex_visit;
+          count= 0;
+          firstinf= True;
+	  qh_settruncate (tricenters, 0);
+          FOREACHneighborA_(vertex) {
+            if (neighborA->seen) {
+	      if (neighborA->visitid) {
+		if (!neighborA->tricoplanar || qh_setunique (&tricenters, neighborA->center))
+		  count++;
+              }else if (firstinf) {
+                count++;
+                firstinf= False;
+	      }
+	    }
+          }
+          if (count >= qh hull_dim - 1) {  /* e.g., 3 for 3-d Voronoi */
+            if (firstinf) {
+              if (innerouter == qh_RIDGEouter)
+                continue;
+              unbounded= False;
+            }else {
+              if (innerouter == qh_RIDGEinner)
+                continue;
+              unbounded= True;
+            }
+            totridges++;
+            trace4((qh ferr, "qh_eachvoronoi: Voronoi ridge of %d vertices between sites %d and %d\n",
+                  count, qh_pointid (atvertex->point), qh_pointid (vertex->point)));
+            if (printvridge) { 
+	      if (inorder && qh hull_dim == 3+1) /* 3-d Voronoi diagram */
+                centers= qh_detvridge3 (atvertex, vertex);
+	      else
+                centers= qh_detvridge (vertex);
+              (*printvridge) (fp, atvertex, vertex, centers, unbounded);
+              qh_settempfree (¢ers);
+            }
+          }
+        }
+      }
+    }
+  }
+  FOREACHneighbor_(atvertex) 
+    neighbor->seen= False;
+  qh_settempfree (&tricenters);
+  return totridges;
+} /* eachvoronoi */
+  
+
+/*---------------------------------
+  
+  qh_eachvoronoi_all( fp, printvridge, isupper, innerouter, inorder )
+    visit all Voronoi ridges
+    
+    innerouter:
+      see qh_eachvoronoi()
+      
+    if inorder
+      orders vertices for 3-d Voronoi diagrams
+    
+  returns
+    total number of ridges 
+
+    if isupper == facet->upperdelaunay  (i.e., a Vornoi vertex)
+      facet->visitid= Voronoi vertex index (same as 'o' format)
+    else 
+      facet->visitid= 0
+
+    if printvridge,
+      calls printvridge( fp, vertex, vertexA, centers)
+      [see qh_eachvoronoi]
+      
+  notes:
+    Not used for qhull.exe
+    same effect as qh_printvdiagram but ridges not sorted by point id
+*/
+int qh_eachvoronoi_all (FILE *fp, printvridgeT printvridge, boolT isupper, qh_RIDGE innerouter, boolT inorder) {
+  facetT *facet;
+  vertexT *vertex;
+  int numcenters= 1;  /* vertex 0 is vertex-at-infinity */
+  int totridges= 0;
+
+  qh_clearcenters (qh_ASvoronoi);
+  qh_vertexneighbors();
+  maximize_(qh visit_id, (unsigned) qh num_facets);
+  FORALLfacets {
+    facet->visitid= 0;
+    facet->seen= False;
+    facet->seen2= True;
+  }
+  FORALLfacets {
+    if (facet->upperdelaunay == isupper)
+      facet->visitid= numcenters++;
+  }
+  FORALLvertices 
+    vertex->seen= False;
+  FORALLvertices {
+    if (qh GOODvertex > 0 && qh_pointid(vertex->point)+1 != qh GOODvertex)
+      continue;
+    totridges += qh_eachvoronoi (fp, printvridge, vertex, 
+                   !qh_ALL, innerouter, inorder);
+  }
+  return totridges;
+} /* eachvoronoi_all */
+      
+/*---------------------------------
+  
+  qh_facet2point( facet, point0, point1, mindist )
+    return two projected temporary vertices for a 2-d facet
+    may be non-simplicial
+
+  returns:
+    point0 and point1 oriented and projected to the facet
+    returns mindist (maximum distance below plane)
+*/
+void qh_facet2point(facetT *facet, pointT **point0, pointT **point1, realT *mindist) {
+  vertexT *vertex0, *vertex1;
+  realT dist;
+  
+  if (facet->toporient ^ qh_ORIENTclock) {
+    vertex0= SETfirstt_(facet->vertices, vertexT);
+    vertex1= SETsecondt_(facet->vertices, vertexT);
+  }else {
+    vertex1= SETfirstt_(facet->vertices, vertexT);
+    vertex0= SETsecondt_(facet->vertices, vertexT);
+  }
+  zadd_(Zdistio, 2);
+  qh_distplane(vertex0->point, facet, &dist);
+  *mindist= dist;
+  *point0= qh_projectpoint(vertex0->point, facet, dist);
+  qh_distplane(vertex1->point, facet, &dist);
+  minimize_(*mindist, dist);		
+  *point1= qh_projectpoint(vertex1->point, facet, dist);
+} /* facet2point */
+
+
+/*---------------------------------
+  
+  qh_facetvertices( facetlist, facets, allfacets )
+    returns temporary set of vertices in a set and/or list of facets
+    if allfacets, ignores qh_skipfacet()
+
+  returns:
+    vertices with qh.vertex_visit
+    
+  notes:
+    optimized for allfacets of facet_list
+
+  design:
+    if allfacets of facet_list
+      create vertex set from vertex_list
+    else
+      for each selected facet in facets or facetlist
+        append unvisited vertices to vertex set
+*/
+setT *qh_facetvertices (facetT *facetlist, setT *facets, boolT allfacets) {
+  setT *vertices;
+  facetT *facet, **facetp;
+  vertexT *vertex, **vertexp;
+
+  qh vertex_visit++;
+  if (facetlist == qh facet_list && allfacets && !facets) {
+    vertices= qh_settemp (qh num_vertices);
+    FORALLvertices {
+      vertex->visitid= qh vertex_visit; 
+      qh_setappend (&vertices, vertex);
+    }
+  }else {
+    vertices= qh_settemp (qh TEMPsize);
+    FORALLfacet_(facetlist) {
+      if (!allfacets && qh_skipfacet (facet))
+        continue;
+      FOREACHvertex_(facet->vertices) {
+        if (vertex->visitid != qh vertex_visit) {
+          vertex->visitid= qh vertex_visit;
+          qh_setappend (&vertices, vertex);
+        }
+      }
+    }
+  }
+  FOREACHfacet_(facets) {
+    if (!allfacets && qh_skipfacet (facet))
+      continue;
+    FOREACHvertex_(facet->vertices) {
+      if (vertex->visitid != qh vertex_visit) {
+        vertex->visitid= qh vertex_visit;
+        qh_setappend (&vertices, vertex);
+      }
+    }
+  }
+  return vertices;
+} /* facetvertices */
+
+/*---------------------------------
+  
+  qh_geomplanes( facet, outerplane, innerplane )
+    return outer and inner planes for Geomview 
+    qh.PRINTradius is size of vertices and points (includes qh.JOGGLEmax)
+
+  notes:
+    assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
+*/
+void qh_geomplanes (facetT *facet, realT *outerplane, realT *innerplane) {
+  realT radius;
+
+  if (qh MERGING || qh JOGGLEmax < REALmax/2) {
+    qh_outerinner (facet, outerplane, innerplane);
+    radius= qh PRINTradius;
+    if (qh JOGGLEmax < REALmax/2)
+      radius -= qh JOGGLEmax * sqrt (qh hull_dim);  /* already accounted for in qh_outerinner() */
+    *outerplane += radius;
+    *innerplane -= radius;
+    if (qh PRINTcoplanar || qh PRINTspheres) {
+      *outerplane += qh MAXabs_coord * qh_GEOMepsilon;
+      *innerplane -= qh MAXabs_coord * qh_GEOMepsilon;
+    }
+  }else 
+    *innerplane= *outerplane= 0;
+} /* geomplanes */
+
+
+/*---------------------------------
+  
+  qh_markkeep( facetlist )
+    mark good facets that meet qh.KEEParea, qh.KEEPmerge, and qh.KEEPminArea
+    ignores visible facets (not part of convex hull)
+
+  returns:
+    may clear facet->good
+    recomputes qh.num_good
+
+  design:
+    get set of good facets
+    if qh.KEEParea
+      sort facets by area
+      clear facet->good for all but n largest facets
+    if qh.KEEPmerge
+      sort facets by merge count
+      clear facet->good for all but n most merged facets
+    if qh.KEEPminarea
+      clear facet->good if area too small
+    update qh.num_good    
+*/
+void qh_markkeep (facetT *facetlist) {
+  facetT *facet, **facetp;
+  setT *facets= qh_settemp (qh num_facets);
+  int size, count;
+
+  trace2((qh ferr, "qh_markkeep: only keep %d largest and/or %d most merged facets and/or min area %.2g\n",
+          qh KEEParea, qh KEEPmerge, qh KEEPminArea));
+  FORALLfacet_(facetlist) {
+    if (!facet->visible && facet->good)
+      qh_setappend (&facets, facet);
+  }
+  size= qh_setsize (facets);
+  if (qh KEEParea) {
+    qsort (SETaddr_(facets, facetT), size,
+             sizeof (facetT *), qh_compare_facetarea);
+    if ((count= size - qh KEEParea) > 0) {
+      FOREACHfacet_(facets) {
+        facet->good= False;
+        if (--count == 0)
+          break;
+      }
+    }
+  }
+  if (qh KEEPmerge) {
+    qsort (SETaddr_(facets, facetT), size,
+             sizeof (facetT *), qh_compare_facetmerge);
+    if ((count= size - qh KEEPmerge) > 0) {
+      FOREACHfacet_(facets) {
+        facet->good= False;
+        if (--count == 0)
+          break;
+      }
+    }
+  }
+  if (qh KEEPminArea < REALmax/2) {
+    FOREACHfacet_(facets) {
+      if (!facet->isarea || facet->f.area < qh KEEPminArea)
+	facet->good= False;
+    }
+  }
+  qh_settempfree (&facets);
+  count= 0;
+  FORALLfacet_(facetlist) {
+    if (facet->good)
+      count++;
+  }
+  qh num_good= count;
+} /* markkeep */
+
+
+/*---------------------------------
+  
+  qh_markvoronoi( facetlist, facets, printall, islower, numcenters )
+    mark voronoi vertices for printing by site pairs
+  
+  returns:
+    temporary set of vertices indexed by pointid
+    islower set if printing lower hull (i.e., at least one facet is lower hull)
+    numcenters= total number of Voronoi vertices
+    bumps qh.printoutnum for vertex-at-infinity
+    clears all facet->seen and sets facet->seen2
+    
+    if selected
+      facet->visitid= Voronoi vertex id
+    else if upper hull (or 'Qu' and lower hull)
+      facet->visitid= 0
+    else
+      facet->visitid >= qh num_facets
+  
+  notes:
+    ignores qh.ATinfinity, if defined
+*/
+setT *qh_markvoronoi (facetT *facetlist, setT *facets, boolT printall, boolT *islowerp, int *numcentersp) {
+  int numcenters=0;
+  facetT *facet, **facetp;
+  setT *vertices;
+  boolT islower= False;
+
+  qh printoutnum++;
+  qh_clearcenters (qh_ASvoronoi);  /* in case, qh_printvdiagram2 called by user */
+  qh_vertexneighbors();
+  vertices= qh_pointvertex();
+  if (qh ATinfinity) 
+    SETelem_(vertices, qh num_points-1)= NULL;
+  qh visit_id++;
+  maximize_(qh visit_id, (unsigned) qh num_facets);
+  FORALLfacet_(facetlist) { 
+    if (printall || !qh_skipfacet (facet)) {
+      if (!facet->upperdelaunay) {
+        islower= True;
+	break;
+      }
+    }
+  }
+  FOREACHfacet_(facets) {
+    if (printall || !qh_skipfacet (facet)) {
+      if (!facet->upperdelaunay) {
+        islower= True;
+	break;
+      }
+    }
+  }
+  FORALLfacets {
+    if (facet->normal && (facet->upperdelaunay == islower))
+      facet->visitid= 0;  /* facetlist or facets may overwrite */
+    else
+      facet->visitid= qh visit_id;
+    facet->seen= False;
+    facet->seen2= True;
+  }
+  numcenters++;  /* qh_INFINITE */
+  FORALLfacet_(facetlist) {
+    if (printall || !qh_skipfacet (facet))
+      facet->visitid= numcenters++;
+  }
+  FOREACHfacet_(facets) {
+    if (printall || !qh_skipfacet (facet))
+      facet->visitid= numcenters++;  
+  }
+  *islowerp= islower;
+  *numcentersp= numcenters;
+  trace2((qh ferr, "qh_markvoronoi: islower %d numcenters %d\n", islower, numcenters));
+  return vertices;
+} /* markvoronoi */
+
+/*---------------------------------
+  
+  qh_order_vertexneighbors( vertex )
+    order facet neighbors of a 2-d or 3-d vertex by adjacency
+
+  notes:
+    does not orient the neighbors
+
+  design:
+    initialize a new neighbor set with the first facet in vertex->neighbors
+    while vertex->neighbors non-empty
+      select next neighbor in the previous facet's neighbor set
+    set vertex->neighbors to the new neighbor set
+*/
+void qh_order_vertexneighbors(vertexT *vertex) {
+  setT *newset;
+  facetT *facet, *neighbor, **neighborp;
+
+  trace4((qh ferr, "qh_order_vertexneighbors: order neighbors of v%d for 3-d\n", vertex->id));
+  newset= qh_settemp (qh_setsize (vertex->neighbors));
+  facet= (facetT*)qh_setdellast (vertex->neighbors);
+  qh_setappend (&newset, facet);
+  while (qh_setsize (vertex->neighbors)) {
+    FOREACHneighbor_(vertex) {
+      if (qh_setin (facet->neighbors, neighbor)) {
+        qh_setdel(vertex->neighbors, neighbor);
+        qh_setappend (&newset, neighbor);
+        facet= neighbor;
+        break;
+      }
+    }
+    if (!neighbor) {
+      fprintf (qh ferr, "qhull internal error (qh_order_vertexneighbors): no neighbor of v%d for f%d\n",
+        vertex->id, facet->id);
+      qh_errexit (qh_ERRqhull, facet, NULL);
+    }
+  }
+  qh_setfree (&vertex->neighbors);
+  qh_settemppop ();
+  vertex->neighbors= newset;
+} /* order_vertexneighbors */
+
+/*---------------------------------
+  
+  qh_printafacet( fp, format, facet, printall )
+    print facet to fp in given output format (see qh.PRINTout)
+
+  returns:
+    nop if !printall and qh_skipfacet()
+    nop if visible facet and NEWfacets and format != PRINTfacets
+    must match qh_countfacets
+
+  notes
+    preserves qh.visit_id
+    facet->normal may be null if PREmerge/MERGEexact and STOPcone before merge
+
+  see
+    qh_printbegin() and qh_printend()
+
+  design:
+    test for printing facet
+    call appropriate routine for format
+    or output results directly
+*/
+void qh_printafacet(FILE *fp, int format, facetT *facet, boolT printall) {
+  realT color[4], offset, dist, outerplane, innerplane;
+  boolT zerodiv;
+  coordT *point, *normp, *coordp, **pointp, *feasiblep;
+  int k;
+  vertexT *vertex, **vertexp;
+  facetT *neighbor, **neighborp;
+
+  if (!printall && qh_skipfacet (facet))
+    return;
+  if (facet->visible && qh NEWfacets && format != qh_PRINTfacets)
+    return;
+  qh printoutnum++;
+  switch (format) {
+  case qh_PRINTarea:
+    if (facet->isarea) {
+      fprintf (fp, qh_REAL_1, facet->f.area);
+      fprintf (fp, "\n");
+    }else
+      fprintf (fp, "0\n");
+    break;
+  case qh_PRINTcoplanars:
+    fprintf (fp, "%d", qh_setsize (facet->coplanarset));
+    FOREACHpoint_(facet->coplanarset)
+      fprintf (fp, " %d", qh_pointid (point));
+    fprintf (fp, "\n");
+    break;
+  case qh_PRINTcentrums:
+    qh_printcenter (fp, format, NULL, facet);
+    break;
+  case qh_PRINTfacets:
+    qh_printfacet (fp, facet);
+    break;
+  case qh_PRINTfacets_xridge:
+    qh_printfacetheader (fp, facet);
+    break;
+  case qh_PRINTgeom:  /* either 2 , 3, or 4-d by qh_printbegin */
+    if (!facet->normal)
+      break;
+    for (k= qh hull_dim; k--; ) {
+      color[k]= (facet->normal[k]+1.0)/2.0;
+      maximize_(color[k], -1.0);
+      minimize_(color[k], +1.0);
+    }
+    qh_projectdim3 (color, color);
+    if (qh PRINTdim != qh hull_dim)
+      qh_normalize2 (color, 3, True, NULL, NULL);
+    if (qh hull_dim <= 2)
+      qh_printfacet2geom (fp, facet, color);
+    else if (qh hull_dim == 3) {
+      if (facet->simplicial)
+        qh_printfacet3geom_simplicial (fp, facet, color);
+      else
+        qh_printfacet3geom_nonsimplicial (fp, facet, color);
+    }else {
+      if (facet->simplicial)
+        qh_printfacet4geom_simplicial (fp, facet, color);
+      else
+        qh_printfacet4geom_nonsimplicial (fp, facet, color);
+    }
+    break;
+  case qh_PRINTids:
+    fprintf (fp, "%d\n", facet->id);
+    break;
+  case qh_PRINTincidences:
+  case qh_PRINToff:
+  case qh_PRINTtriangles:
+    if (qh hull_dim == 3 && format != qh_PRINTtriangles) 
+      qh_printfacet3vertex (fp, facet, format);
+    else if (facet->simplicial || qh hull_dim == 2 || format == qh_PRINToff)
+      qh_printfacetNvertex_simplicial (fp, facet, format);
+    else
+      qh_printfacetNvertex_nonsimplicial (fp, facet, qh printoutvar++, format);
+    break;
+  case qh_PRINTinner:
+    qh_outerinner (facet, NULL, &innerplane);
+    offset= facet->offset - innerplane;
+    goto LABELprintnorm;
+    break; /* prevent warning */
+  case qh_PRINTmerges:
+    fprintf (fp, "%d\n", facet->nummerge);
+    break;
+  case qh_PRINTnormals:
+    offset= facet->offset;
+    goto LABELprintnorm;
+    break; /* prevent warning */
+  case qh_PRINTouter:
+    qh_outerinner (facet, &outerplane, NULL);
+    offset= facet->offset - outerplane;
+  LABELprintnorm:
+    if (!facet->normal) {
+      fprintf (fp, "no normal for facet f%d\n", facet->id);
+      break;
+    }
+    if (qh CDDoutput) {
+      fprintf (fp, qh_REAL_1, -offset);
+      for (k=0; k < qh hull_dim; k++) 
+	fprintf (fp, qh_REAL_1, -facet->normal[k]);
+    }else {
+      for (k=0; k < qh hull_dim; k++) 
+	fprintf (fp, qh_REAL_1, facet->normal[k]);
+      fprintf (fp, qh_REAL_1, offset);
+    }
+    fprintf (fp, "\n");
+    break;
+  case qh_PRINTmathematica:  /* either 2 or 3-d by qh_printbegin */
+    if (qh hull_dim == 2)
+      qh_printfacet2math (fp, facet, qh printoutvar++);
+    else 
+      qh_printfacet3math (fp, facet, qh printoutvar++);
+    break;
+  case qh_PRINTneighbors:
+    fprintf (fp, "%d", qh_setsize (facet->neighbors));
+    FOREACHneighbor_(facet)
+      fprintf (fp, " %d", 
+	       neighbor->visitid ? neighbor->visitid - 1: - neighbor->id);
+    fprintf (fp, "\n");
+    break;
+  case qh_PRINTpointintersect:
+    if (!qh feasible_point) {
+      fprintf (fp, "qhull input error (qh_printafacet): option 'Fp' needs qh feasible_point\n");
+      qh_errexit( qh_ERRinput, NULL, NULL);
+    }
+    if (facet->offset > 0)
+      goto LABELprintinfinite;
+    point= coordp= (coordT*)qh_memalloc (qh normal_size);
+    normp= facet->normal;
+    feasiblep= qh feasible_point;
+    if (facet->offset < -qh MINdenom) {
+      for (k= qh hull_dim; k--; )
+        *(coordp++)= (*(normp++) / - facet->offset) + *(feasiblep++);
+    }else {
+      for (k= qh hull_dim; k--; ) {
+        *(coordp++)= qh_divzero (*(normp++), facet->offset, qh MINdenom_1,
+				 &zerodiv) + *(feasiblep++);
+        if (zerodiv) {
+          qh_memfree (point, qh normal_size);
+          goto LABELprintinfinite;
+        }
+      }
+    }
+    qh_printpoint (fp, NULL, point);
+    qh_memfree (point, qh normal_size);
+    break;
+  LABELprintinfinite:
+    for (k= qh hull_dim; k--; )
+      fprintf (fp, qh_REAL_1, qh_INFINITE);
+    fprintf (fp, "\n");   
+    break;
+  case qh_PRINTpointnearest:
+    FOREACHpoint_(facet->coplanarset) {
+      int id, id2;
+      vertex= qh_nearvertex (facet, point, &dist);
+      id= qh_pointid (vertex->point);
+      id2= qh_pointid (point);
+      fprintf (fp, "%d %d %d " qh_REAL_1 "\n", id, id2, facet->id, dist);
+    }
+    break;
+  case qh_PRINTpoints:  /* VORONOI only by qh_printbegin */
+    if (qh CDDoutput)
+      fprintf (fp, "1 ");
+    qh_printcenter (fp, format, NULL, facet);
+    break;
+  case qh_PRINTvertices:
+    fprintf (fp, "%d", qh_setsize (facet->vertices));
+    FOREACHvertex_(facet->vertices)
+      fprintf (fp, " %d", qh_pointid (vertex->point));
+    fprintf (fp, "\n");
+    break;
+  }
+} /* printafacet */
+
+/*---------------------------------
+  
+  qh_printbegin(  )
+    prints header for all output formats
+
+  returns:
+    checks for valid format
+  
+  notes:
+    uses qh.visit_id for 3/4off
+    changes qh.interior_point if printing centrums
+    qh_countfacets clears facet->visitid for non-good facets
+    
+  see
+    qh_printend() and qh_printafacet()
+    
+  design:
+    count facets and related statistics
+    print header for format
+*/
+void qh_printbegin (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
+  int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;
+  int i, num;
+  facetT *facet, **facetp;
+  vertexT *vertex, **vertexp;
+  setT *vertices;
+  pointT *point, **pointp, *pointtemp;
+
+  qh printoutnum= 0;
+  qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial, 
+      &totneighbors, &numridges, &numcoplanars, &numtricoplanars);
+  switch (format) {
+  case qh_PRINTnone:
+    break;
+  case qh_PRINTarea:
+    fprintf (fp, "%d\n", numfacets);
+    break;
+  case qh_PRINTcoplanars:
+    fprintf (fp, "%d\n", numfacets);
+    break;
+  case qh_PRINTcentrums:
+    if (qh CENTERtype == qh_ASnone)
+      qh_clearcenters (qh_AScentrum);
+    fprintf (fp, "%d\n%d\n", qh hull_dim, numfacets);
+    break;
+  case qh_PRINTfacets:
+  case qh_PRINTfacets_xridge:
+    if (facetlist)
+      qh_printvertexlist (fp, "Vertices and facets:\n", facetlist, facets, printall);
+    break;
+  case qh_PRINTgeom: 
+    if (qh hull_dim > 4)  /* qh_initqhull_globals also checks */
+      goto LABELnoformat;
+    if (qh VORONOI && qh hull_dim > 3)  /* PRINTdim == DROPdim == hull_dim-1 */
+      goto LABELnoformat;
+    if (qh hull_dim == 2 && (qh PRINTridges || qh DOintersections))
+      fprintf (qh ferr, "qhull warning: output for ridges and intersections not implemented in 2-d\n");
+    if (qh hull_dim == 4 && (qh PRINTinner || qh PRINTouter ||
+			     (qh PRINTdim == 4 && qh PRINTcentrums)))
+      fprintf (qh ferr, "qhull warning: output for outer/inner planes and centrums not implemented in 4-d\n");
+    if (qh PRINTdim == 4 && (qh PRINTspheres))
+      fprintf (qh ferr, "qhull warning: output for vertices not implemented in 4-d\n");
+    if (qh PRINTdim == 4 && qh DOintersections && qh PRINTnoplanes)
+      fprintf (qh ferr, "qhull warning: 'Gnh' generates no output in 4-d\n");
+    if (qh PRINTdim == 2) {
+      fprintf(fp, "{appearance {linewidth 3} LIST # %s | %s\n",
+	      qh rbox_command, qh qhull_command);
+    }else if (qh PRINTdim == 3) {
+      fprintf(fp, "{appearance {+edge -evert linewidth 2} LIST # %s | %s\n",
+	      qh rbox_command, qh qhull_command);
+    }else if (qh PRINTdim == 4) {
+      qh visit_id++;
+      num= 0;
+      FORALLfacet_(facetlist)    /* get number of ridges to be printed */
+        qh_printend4geom (NULL, facet, &num, printall);
+      FOREACHfacet_(facets)
+        qh_printend4geom (NULL, facet, &num, printall);
+      qh ridgeoutnum= num;
+      qh printoutvar= 0;  /* counts number of ridges in output */
+      fprintf (fp, "LIST # %s | %s\n", qh rbox_command, qh qhull_command);
+    }
+    if (qh PRINTdots) {
+      qh printoutnum++;
+      num= qh num_points + qh_setsize (qh other_points);
+      if (qh DELAUNAY && qh ATinfinity)
+	num--;
+      if (qh PRINTdim == 4)
+        fprintf (fp, "4VECT %d %d 1\n", num, num);
+      else
+	fprintf (fp, "VECT %d %d 1\n", num, num);
+      for (i= num; i--; ) {
+        if (i % 20 == 0)
+          fprintf (fp, "\n");
+	fprintf (fp, "1 ");
+      }
+      fprintf (fp, "# 1 point per line\n1 ");
+      for (i= num-1; i--; ) {
+        if (i % 20 == 0)
+          fprintf (fp, "\n");
+	fprintf (fp, "0 ");
+      }
+      fprintf (fp, "# 1 color for all\n");
+      FORALLpoints {
+        if (!qh DELAUNAY || !qh ATinfinity || qh_pointid(point) != qh num_points-1) {
+	  if (qh PRINTdim == 4)
+	    qh_printpoint (fp, NULL, point);
+	  else
+	    qh_printpoint3 (fp, point);
+	}
+      }
+      FOREACHpoint_(qh other_points) {
+	if (qh PRINTdim == 4)
+	  qh_printpoint (fp, NULL, point);
+	else
+	  qh_printpoint3 (fp, point);
+      }
+      fprintf (fp, "0 1 1 1  # color of points\n");
+    }
+    if (qh PRINTdim == 4  && !qh PRINTnoplanes)
+      /* 4dview loads up multiple 4OFF objects slowly */
+      fprintf(fp, "4OFF %d %d 1\n", 3*qh ridgeoutnum, qh ridgeoutnum);
+    qh PRINTcradius= 2 * qh DISTround;  /* include test DISTround */
+    if (qh PREmerge) {
+      maximize_(qh PRINTcradius, qh premerge_centrum + qh DISTround);
+    }else if (qh POSTmerge)
+      maximize_(qh PRINTcradius, qh postmerge_centrum + qh DISTround);
+    qh PRINTradius= qh PRINTcradius;
+    if (qh PRINTspheres + qh PRINTcoplanar)
+      maximize_(qh PRINTradius, qh MAXabs_coord * qh_MINradius);
+    if (qh premerge_cos < REALmax/2) {
+      maximize_(qh PRINTradius, (1- qh premerge_cos) * qh MAXabs_coord);
+    }else if (!qh PREmerge && qh POSTmerge && qh postmerge_cos < REALmax/2) {
+      maximize_(qh PRINTradius, (1- qh postmerge_cos) * qh MAXabs_coord);
+    }
+    maximize_(qh PRINTradius, qh MINvisible); 
+    if (qh JOGGLEmax < REALmax/2)
+      qh PRINTradius += qh JOGGLEmax * sqrt (qh hull_dim);
+    if (qh PRINTdim != 4 &&
+	(qh PRINTcoplanar || qh PRINTspheres || qh PRINTcentrums)) {
+      vertices= qh_facetvertices (facetlist, facets, printall);
+      if (qh PRINTspheres && qh PRINTdim <= 3)
+         qh_printspheres (fp, vertices, qh PRINTradius);
+      if (qh PRINTcoplanar || qh PRINTcentrums) {
+        qh firstcentrum= True;
+        if (qh PRINTcoplanar&& !qh PRINTspheres) {
+          FOREACHvertex_(vertices) 
+            qh_printpointvect2 (fp, vertex->point, NULL,
+				qh interior_point, qh PRINTradius);
+	}
+        FORALLfacet_(facetlist) {
+	  if (!printall && qh_skipfacet(facet))
+	    continue;
+	  if (!facet->normal)
+	    continue;
+          if (qh PRINTcentrums && qh PRINTdim <= 3)
+            qh_printcentrum (fp, facet, qh PRINTcradius);
+	  if (!qh PRINTcoplanar)
+	    continue;
+          FOREACHpoint_(facet->coplanarset)
+            qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
+          FOREACHpoint_(facet->outsideset)
+            qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
+        }
+        FOREACHfacet_(facets) {
+	  if (!printall && qh_skipfacet(facet))
+	    continue;
+	  if (!facet->normal)
+	    continue;
+          if (qh PRINTcentrums && qh PRINTdim <= 3)
+            qh_printcentrum (fp, facet, qh PRINTcradius);
+	  if (!qh PRINTcoplanar)
+	    continue;
+          FOREACHpoint_(facet->coplanarset)
+            qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
+          FOREACHpoint_(facet->outsideset)
+            qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
+        }
+      }
+      qh_settempfree (&vertices);
+    }
+    qh visit_id++; /* for printing hyperplane intersections */
+    break;
+  case qh_PRINTids:
+    fprintf (fp, "%d\n", numfacets);
+    break;
+  case qh_PRINTincidences:
+    if (qh VORONOI && qh PRINTprecision)
+      fprintf (qh ferr, "qhull warning: writing Delaunay.  Use 'p' or 'o' for Voronoi centers\n");
+    qh printoutvar= qh vertex_id;  /* centrum id for non-simplicial facets */
+    if (qh hull_dim <= 3)
+      fprintf(fp, "%d\n", numfacets);
+    else
+      fprintf(fp, "%d\n", numsimplicial+numridges);
+    break;
+  case qh_PRINTinner:
+  case qh_PRINTnormals:
+  case qh_PRINTouter:
+    if (qh CDDoutput)
+      fprintf (fp, "%s | %s\nbegin\n    %d %d real\n", qh rbox_command, 
+              qh qhull_command, numfacets, qh hull_dim+1);
+    else
+      fprintf (fp, "%d\n%d\n", qh hull_dim+1, numfacets);
+    break;
+  case qh_PRINTmathematica:  
+    if (qh hull_dim > 3)  /* qh_initbuffers also checks */
+      goto LABELnoformat;
+    if (qh VORONOI)
+      fprintf (qh ferr, "qhull warning: output is the Delaunay triangulation\n");
+    fprintf(fp, "{\n");
+    qh printoutvar= 0;   /* counts number of facets for notfirst */
+    break;
+  case qh_PRINTmerges:
+    fprintf (fp, "%d\n", numfacets);
+    break;
+  case qh_PRINTpointintersect:
+    fprintf (fp, "%d\n%d\n", qh hull_dim, numfacets);
+    break;
+  case qh_PRINTneighbors:
+    fprintf (fp, "%d\n", numfacets);
+    break;
+  case qh_PRINToff:
+  case qh_PRINTtriangles:
+    if (qh VORONOI)
+      goto LABELnoformat;
+    num = qh hull_dim;
+    if (format == qh_PRINToff || qh hull_dim == 2)
+      fprintf (fp, "%d\n%d %d %d\n", num, 
+        qh num_points+qh_setsize (qh other_points), numfacets, totneighbors/2);
+    else { /* qh_PRINTtriangles */
+      qh printoutvar= qh num_points+qh_setsize (qh other_points); /* first centrum */
+      if (qh DELAUNAY)
+        num--;  /* drop last dimension */
+      fprintf (fp, "%d\n%d %d %d\n", num, qh printoutvar 
+	+ numfacets - numsimplicial, numsimplicial + numridges, totneighbors/2);
+    }
+    FORALLpoints
+      qh_printpointid (qh fout, NULL, num, point, -1);
+    FOREACHpoint_(qh other_points)
+      qh_printpointid (qh fout, NULL, num, point, -1);
+    if (format == qh_PRINTtriangles && qh hull_dim > 2) {
+      FORALLfacets {
+	if (!facet->simplicial && facet->visitid)
+          qh_printcenter (qh fout, format, NULL, facet);
+      }
+    }
+    break;
+  case qh_PRINTpointnearest:
+    fprintf (fp, "%d\n", numcoplanars);
+    break;
+  case qh_PRINTpoints:
+    if (!qh VORONOI)
+      goto LABELnoformat;
+    if (qh CDDoutput)
+      fprintf (fp, "%s | %s\nbegin\n%d %d real\n", qh rbox_command,
+             qh qhull_command, numfacets, qh hull_dim);
+    else
+      fprintf (fp, "%d\n%d\n", qh hull_dim-1, numfacets);
+    break;
+  case qh_PRINTvertices:
+    fprintf (fp, "%d\n", numfacets);
+    break;
+  case qh_PRINTsummary:
+  default:
+  LABELnoformat:
+    fprintf (qh ferr, "qhull internal error (qh_printbegin): can not use this format for dimension %d\n",
+         qh hull_dim);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+} /* printbegin */
+
+/*---------------------------------
+  
+  qh_printcenter( fp, string, facet )
+    print facet->center as centrum or Voronoi center
+    string may be NULL.  Don't include '%' codes.
+    nop if qh CENTERtype neither CENTERvoronoi nor CENTERcentrum
+    if upper envelope of Delaunay triangulation and point at-infinity
+      prints qh_INFINITE instead;
+
+  notes:
+    defines facet->center if needed
+    if format=PRINTgeom, adds a 0 if would otherwise be 2-d
+*/
+void qh_printcenter (FILE *fp, int format, char *string, facetT *facet) {
+  int k, num;
+
+  if (qh CENTERtype != qh_ASvoronoi && qh CENTERtype != qh_AScentrum)
+    return;
+  if (string)
+    fprintf (fp, string, facet->id);
+  if (qh CENTERtype == qh_ASvoronoi) {
+    num= qh hull_dim-1;
+    if (!facet->normal || !facet->upperdelaunay || !qh ATinfinity) {
+      if (!facet->center)
+        facet->center= qh_facetcenter (facet->vertices);
+      for (k=0; k < num; k++)
+        fprintf (fp, qh_REAL_1, facet->center[k]);
+    }else {
+      for (k=0; k < num; k++)
+        fprintf (fp, qh_REAL_1, qh_INFINITE);
+    }
+  }else /* qh CENTERtype == qh_AScentrum */ {
+    num= qh hull_dim;
+    if (format == qh_PRINTtriangles && qh DELAUNAY) 
+      num--;
+    if (!facet->center) 
+      facet->center= qh_getcentrum (facet);
+    for (k=0; k < num; k++)
+      fprintf (fp, qh_REAL_1, facet->center[k]);
+  }
+  if (format == qh_PRINTgeom && num == 2)
+    fprintf (fp, " 0\n");
+  else
+    fprintf (fp, "\n");
+} /* printcenter */
+
+/*---------------------------------
+  
+  qh_printcentrum( fp, facet, radius )
+    print centrum for a facet in OOGL format
+    radius defines size of centrum
+    2-d or 3-d only
+
+  returns:
+    defines facet->center if needed
+*/
+void qh_printcentrum (FILE *fp, facetT *facet, realT radius) {
+  pointT *centrum, *projpt;
+  boolT tempcentrum= False;
+  realT xaxis[4], yaxis[4], normal[4], dist;
+  realT green[3]={0, 1, 0};
+  vertexT *apex;
+  int k;
+  
+  if (qh CENTERtype == qh_AScentrum) {
+    if (!facet->center)
+      facet->center= qh_getcentrum (facet);
+    centrum= facet->center;
+  }else {
+    centrum= qh_getcentrum (facet);
+    tempcentrum= True;
+  }
+  fprintf (fp, "{appearance {-normal -edge normscale 0} ");
+  if (qh firstcentrum) {
+    qh firstcentrum= False;
+    fprintf (fp, "{INST geom { define centrum CQUAD  # f%d\n\
+-0.3 -0.3 0.0001     0 0 1 1\n\
+ 0.3 -0.3 0.0001     0 0 1 1\n\
+ 0.3  0.3 0.0001     0 0 1 1\n\
+-0.3  0.3 0.0001     0 0 1 1 } transform { \n", facet->id);
+  }else
+    fprintf (fp, "{INST geom { : centrum } transform { # f%d\n", facet->id);
+  apex= SETfirstt_(facet->vertices, vertexT);
+  qh_distplane(apex->point, facet, &dist);
+  projpt= qh_projectpoint(apex->point, facet, dist);
+  for (k= qh hull_dim; k--; ) {
+    xaxis[k]= projpt[k] - centrum[k];
+    normal[k]= facet->normal[k];
+  }
+  if (qh hull_dim == 2) {
+    xaxis[2]= 0;
+    normal[2]= 0;
+  }else if (qh hull_dim == 4) {
+    qh_projectdim3 (xaxis, xaxis);
+    qh_projectdim3 (normal, normal);
+    qh_normalize2 (normal, qh PRINTdim, True, NULL, NULL);
+  }
+  qh_crossproduct (3, xaxis, normal, yaxis);
+  fprintf (fp, "%8.4g %8.4g %8.4g 0\n", xaxis[0], xaxis[1], xaxis[2]);
+  fprintf (fp, "%8.4g %8.4g %8.4g 0\n", yaxis[0], yaxis[1], yaxis[2]);
+  fprintf (fp, "%8.4g %8.4g %8.4g 0\n", normal[0], normal[1], normal[2]);
+  qh_printpoint3 (fp, centrum);
+  fprintf (fp, "1 }}}\n"); 
+  qh_memfree (projpt, qh normal_size);
+  qh_printpointvect (fp, centrum, facet->normal, NULL, radius, green);
+  if (tempcentrum)
+    qh_memfree (centrum, qh normal_size);
+} /* printcentrum */
+  
+/*---------------------------------
+  
+  qh_printend( fp, format )
+    prints trailer for all output formats
+
+  see:
+    qh_printbegin() and qh_printafacet()
+      
+*/
+void qh_printend (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
+  int num;
+  facetT *facet, **facetp;
+
+  if (!qh printoutnum)
+    fprintf (qh ferr, "qhull warning: no facets printed\n");
+  switch (format) {
+  case qh_PRINTgeom:
+    if (qh hull_dim == 4 && qh DROPdim < 0  && !qh PRINTnoplanes) {
+      qh visit_id++;
+      num= 0;
+      FORALLfacet_(facetlist)
+        qh_printend4geom (fp, facet,&num, printall);
+      FOREACHfacet_(facets) 
+        qh_printend4geom (fp, facet, &num, printall);
+      if (num != qh ridgeoutnum || qh printoutvar != qh ridgeoutnum) {
+	fprintf (qh ferr, "qhull internal error (qh_printend): number of ridges %d != number printed %d and at end %d\n", qh ridgeoutnum, qh printoutvar, num);
+	qh_errexit (qh_ERRqhull, NULL, NULL);
+      }
+    }else
+      fprintf(fp, "}\n");
+    break;
+  case qh_PRINTinner:
+  case qh_PRINTnormals:
+  case qh_PRINTouter:
+    if (qh CDDoutput) 
+      fprintf (fp, "end\n");
+    break;
+  case qh_PRINTmathematica:
+    fprintf(fp, "}\n");
+    break;
+  case qh_PRINTpoints:
+    if (qh CDDoutput)
+      fprintf (fp, "end\n");
+    break;
+  }
+} /* printend */
+
+/*---------------------------------
+  
+  qh_printend4geom( fp, facet, numridges, printall )
+    helper function for qh_printbegin/printend
+
+  returns:
+    number of printed ridges
+  
+  notes:
+    just counts printed ridges if fp=NULL
+    uses facet->visitid
+    must agree with qh_printfacet4geom...
+
+  design:
+    computes color for facet from its normal
+    prints each ridge of facet 
+*/
+void qh_printend4geom (FILE *fp, facetT *facet, int *nump, boolT printall) {
+  realT color[3];
+  int i, num= *nump;
+  facetT *neighbor, **neighborp;
+  ridgeT *ridge, **ridgep;
+  
+  if (!printall && qh_skipfacet(facet))
+    return;
+  if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
+    return;
+  if (!facet->normal)
+    return;
+  if (fp) {
+    for (i=0; i < 3; i++) {
+      color[i]= (facet->normal[i]+1.0)/2.0;
+      maximize_(color[i], -1.0);
+      minimize_(color[i], +1.0);
+    }
+  }
+  facet->visitid= qh visit_id;
+  if (facet->simplicial) {
+    FOREACHneighbor_(facet) {
+      if (neighbor->visitid != qh visit_id) {
+	if (fp)
+          fprintf (fp, "3 %d %d %d %8.4g %8.4g %8.4g 1 # f%d f%d\n",
+		 3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],
+		 facet->id, neighbor->id);
+	num++;
+      }
+    }
+  }else {
+    FOREACHridge_(facet->ridges) {
+      neighbor= otherfacet_(ridge, facet);
+      if (neighbor->visitid != qh visit_id) {
+	if (fp)
+          fprintf (fp, "3 %d %d %d %8.4g %8.4g %8.4g 1 #r%d f%d f%d\n",
+		 3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],
+		 ridge->id, facet->id, neighbor->id);
+	num++;
+      }
+    }
+  }
+  *nump= num;
+} /* printend4geom */
+
+/*---------------------------------
+  
+  qh_printextremes( fp, facetlist, facets, printall )
+    print extreme points for convex hulls or halfspace intersections
+
+  notes:
+    #points, followed by ids, one per line
+    
+    sorted by id
+    same order as qh_printpoints_out if no coplanar/interior points
+*/
+void qh_printextremes (FILE *fp, facetT *facetlist, setT *facets, int printall) {
+  setT *vertices, *points;
+  pointT *point;
+  vertexT *vertex, **vertexp;
+  int id;
+  int numpoints=0, point_i, point_n;
+  int allpoints= qh num_points + qh_setsize (qh other_points);
+
+  points= qh_settemp (allpoints);
+  qh_setzero (points, 0, allpoints);
+  vertices= qh_facetvertices (facetlist, facets, printall);
+  FOREACHvertex_(vertices) {
+    id= qh_pointid (vertex->point);
+    if (id >= 0) {
+      SETelem_(points, id)= vertex->point;
+      numpoints++;
+    }
+  }
+  qh_settempfree (&vertices);
+  fprintf (fp, "%d\n", numpoints);
+  FOREACHpoint_i_(points) {
+    if (point) 
+      fprintf (fp, "%d\n", point_i);
+  }
+  qh_settempfree (&points);
+} /* printextremes */
+
+/*---------------------------------
+  
+  qh_printextremes_2d( fp, facetlist, facets, printall )
+    prints point ids for facets in qh_ORIENTclock order
+
+  notes:
+    #points, followed by ids, one per line
+    if facetlist/facets are disjoint than the output includes skips
+    errors if facets form a loop
+    does not print coplanar points
+*/
+void qh_printextremes_2d (FILE *fp, facetT *facetlist, setT *facets, int printall) {
+  int numfacets, numridges, totneighbors, numcoplanars, numsimplicial, numtricoplanars;
+  setT *vertices;
+  facetT *facet, *startfacet, *nextfacet;
+  vertexT *vertexA, *vertexB;
+
+  qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial, 
+      &totneighbors, &numridges, &numcoplanars, &numtricoplanars); /* marks qh visit_id */
+  vertices= qh_facetvertices (facetlist, facets, printall);
+  fprintf(fp, "%d\n", qh_setsize (vertices));
+  qh_settempfree (&vertices);
+  if (!numfacets)
+    return;
+  facet= startfacet= facetlist ? facetlist : SETfirstt_(facets, facetT);
+  qh vertex_visit++;
+  qh visit_id++;
+  do {
+    if (facet->toporient ^ qh_ORIENTclock) {
+      vertexA= SETfirstt_(facet->vertices, vertexT);
+      vertexB= SETsecondt_(facet->vertices, vertexT);
+      nextfacet= SETfirstt_(facet->neighbors, facetT);
+    }else {
+      vertexA= SETsecondt_(facet->vertices, vertexT);
+      vertexB= SETfirstt_(facet->vertices, vertexT);
+      nextfacet= SETsecondt_(facet->neighbors, facetT);
+    }
+    if (facet->visitid == qh visit_id) {
+      fprintf(qh ferr, "qh_printextremes_2d: loop in facet list.  facet %d nextfacet %d\n",
+                 facet->id, nextfacet->id);
+      qh_errexit2 (qh_ERRqhull, facet, nextfacet);
+    }
+    if (facet->visitid) {
+      if (vertexA->visitid != qh vertex_visit) {
+	vertexA->visitid= qh vertex_visit;
+	fprintf(fp, "%d\n", qh_pointid (vertexA->point));
+      }
+      if (vertexB->visitid != qh vertex_visit) {
+	vertexB->visitid= qh vertex_visit;
+	fprintf(fp, "%d\n", qh_pointid (vertexB->point));
+      }
+    }
+    facet->visitid= qh visit_id;
+    facet= nextfacet;
+  }while (facet && facet != startfacet);
+} /* printextremes_2d */
+
+/*---------------------------------
+  
+  qh_printextremes_d( fp, facetlist, facets, printall )
+    print extreme points of input sites for Delaunay triangulations
+
+  notes:
+    #points, followed by ids, one per line
+    
+    unordered
+*/
+void qh_printextremes_d (FILE *fp, facetT *facetlist, setT *facets, int printall) {
+  setT *vertices;
+  vertexT *vertex, **vertexp;
+  boolT upperseen, lowerseen;
+  facetT *neighbor, **neighborp;
+  int numpoints=0;
+
+  vertices= qh_facetvertices (facetlist, facets, printall);
+  qh_vertexneighbors();
+  FOREACHvertex_(vertices) {
+    upperseen= lowerseen= False;
+    FOREACHneighbor_(vertex) {
+      if (neighbor->upperdelaunay)
+        upperseen= True;
+      else
+        lowerseen= True;
+    }
+    if (upperseen && lowerseen) {
+      vertex->seen= True;
+      numpoints++;
+    }else
+      vertex->seen= False;
+  }
+  fprintf (fp, "%d\n", numpoints);
+  FOREACHvertex_(vertices) {
+    if (vertex->seen)
+      fprintf (fp, "%d\n", qh_pointid (vertex->point));
+  }
+  qh_settempfree (&vertices);
+} /* printextremes_d */
+
+/*---------------------------------
+  
+  qh_printfacet( fp, facet )
+    prints all fields of a facet to fp
+
+  notes:
+    ridges printed in neighbor order
+*/
+void qh_printfacet(FILE *fp, facetT *facet) {
+
+  qh_printfacetheader (fp, facet);
+  if (facet->ridges)
+    qh_printfacetridges (fp, facet);
+} /* printfacet */
+
+
+/*---------------------------------
+  
+  qh_printfacet2geom( fp, facet, color )
+    print facet as part of a 2-d VECT for Geomview
+  
+    notes:
+      assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
+      mindist is calculated within io.c.  maxoutside is calculated elsewhere
+      so a DISTround error may have occured.
+*/
+void qh_printfacet2geom(FILE *fp, facetT *facet, realT color[3]) {
+  pointT *point0, *point1;
+  realT mindist, innerplane, outerplane;
+  int k;
+
+  qh_facet2point (facet, &point0, &point1, &mindist);
+  qh_geomplanes (facet, &outerplane, &innerplane);
+  if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
+    qh_printfacet2geom_points(fp, point0, point1, facet, outerplane, color);
+  if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
+                outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) {
+    for(k= 3; k--; )
+      color[k]= 1.0 - color[k];
+    qh_printfacet2geom_points(fp, point0, point1, facet, innerplane, color);
+  }
+  qh_memfree (point1, qh normal_size);
+  qh_memfree (point0, qh normal_size); 
+} /* printfacet2geom */
+
+/*---------------------------------
+  
+  qh_printfacet2geom_points( fp, point1, point2, facet, offset, color )
+    prints a 2-d facet as a VECT with 2 points at some offset.   
+    The points are on the facet's plane.
+*/
+void qh_printfacet2geom_points(FILE *fp, pointT *point1, pointT *point2,
+			       facetT *facet, realT offset, realT color[3]) {
+  pointT *p1= point1, *p2= point2;
+
+  fprintf(fp, "VECT 1 2 1 2 1 # f%d\n", facet->id);
+  if (offset != 0.0) {
+    p1= qh_projectpoint (p1, facet, -offset);
+    p2= qh_projectpoint (p2, facet, -offset);
+  }
+  fprintf(fp, "%8.4g %8.4g %8.4g\n%8.4g %8.4g %8.4g\n",
+           p1[0], p1[1], 0.0, p2[0], p2[1], 0.0);
+  if (offset != 0.0) {
+    qh_memfree (p1, qh normal_size);
+    qh_memfree (p2, qh normal_size);
+  }
+  fprintf(fp, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
+} /* printfacet2geom_points */
+
+
+/*---------------------------------
+  
+  qh_printfacet2math( fp, facet, notfirst )
+    print 2-d Mathematica output for a facet
+    may be non-simplicial
+
+  notes:
+    use %16.8f since Mathematica 2.2 does not handle exponential format
+*/
+void qh_printfacet2math(FILE *fp, facetT *facet, int notfirst) {
+  pointT *point0, *point1;
+  realT mindist;
+  
+  qh_facet2point (facet, &point0, &point1, &mindist);
+  if (notfirst)
+    fprintf(fp, ",");
+  fprintf(fp, "Line[{{%16.8f, %16.8f}, {%16.8f, %16.8f}}]\n",
+	  point0[0], point0[1], point1[0], point1[1]);
+  qh_memfree (point1, qh normal_size);
+  qh_memfree (point0, qh normal_size);
+} /* printfacet2math */
+
+
+/*---------------------------------
+  
+  qh_printfacet3geom_nonsimplicial( fp, facet, color )
+    print Geomview OFF for a 3-d nonsimplicial facet.
+    if DOintersections, prints ridges to unvisited neighbors (qh visit_id) 
+
+  notes
+    uses facet->visitid for intersections and ridges
+*/
+void qh_printfacet3geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]) {
+  ridgeT *ridge, **ridgep;
+  setT *projectedpoints, *vertices;
+  vertexT *vertex, **vertexp, *vertexA, *vertexB;
+  pointT *projpt, *point, **pointp;
+  facetT *neighbor;
+  realT dist, outerplane, innerplane;
+  int cntvertices, k;
+  realT black[3]={0, 0, 0}, green[3]={0, 1, 0};
+
+  qh_geomplanes (facet, &outerplane, &innerplane); 
+  vertices= qh_facet3vertex (facet); /* oriented */
+  cntvertices= qh_setsize(vertices);
+  projectedpoints= qh_settemp(cntvertices);
+  FOREACHvertex_(vertices) {
+    zinc_(Zdistio);
+    qh_distplane(vertex->point, facet, &dist);
+    projpt= qh_projectpoint(vertex->point, facet, dist);
+    qh_setappend (&projectedpoints, projpt);
+  }
+  if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
+    qh_printfacet3geom_points(fp, projectedpoints, facet, outerplane, color);
+  if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
+                outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) {
+    for (k=3; k--; )
+      color[k]= 1.0 - color[k];
+    qh_printfacet3geom_points(fp, projectedpoints, facet, innerplane, color);
+  }
+  FOREACHpoint_(projectedpoints)
+    qh_memfree (point, qh normal_size);
+  qh_settempfree(&projectedpoints);
+  qh_settempfree(&vertices);
+  if ((qh DOintersections || qh PRINTridges)
+  && (!facet->visible || !qh NEWfacets)) {
+    facet->visitid= qh visit_id;
+    FOREACHridge_(facet->ridges) {
+      neighbor= otherfacet_(ridge, facet);
+      if (neighbor->visitid != qh visit_id) {
+        if (qh DOintersections)
+          qh_printhyperplaneintersection(fp, facet, neighbor, ridge->vertices, black);
+        if (qh PRINTridges) {
+          vertexA= SETfirstt_(ridge->vertices, vertexT);
+          vertexB= SETsecondt_(ridge->vertices, vertexT);
+          qh_printline3geom (fp, vertexA->point, vertexB->point, green);
+        }
+      }
+    }
+  }
+} /* printfacet3geom_nonsimplicial */
+
+/*---------------------------------
+  
+  qh_printfacet3geom_points( fp, points, facet, offset )
+    prints a 3-d facet as OFF Geomview object. 
+    offset is relative to the facet's hyperplane
+    Facet is determined as a list of points
+*/
+void qh_printfacet3geom_points(FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]) {
+  int k, n= qh_setsize(points), i;
+  pointT *point, **pointp;
+  setT *printpoints;
+
+  fprintf(fp, "{ OFF %d 1 1 # f%d\n", n, facet->id);
+  if (offset != 0.0) {
+    printpoints= qh_settemp (n);
+    FOREACHpoint_(points) 
+      qh_setappend (&printpoints, qh_projectpoint(point, facet, -offset));
+  }else
+    printpoints= points;
+  FOREACHpoint_(printpoints) {
+    for (k=0; k < qh hull_dim; k++) {
+      if (k == qh DROPdim)
+        fprintf(fp, "0 ");
+      else
+        fprintf(fp, "%8.4g ", point[k]);
+    }
+    if (printpoints != points)
+      qh_memfree (point, qh normal_size);
+    fprintf (fp, "\n");
+  }
+  if (printpoints != points)
+    qh_settempfree (&printpoints);
+  fprintf(fp, "%d ", n);
+  for(i= 0; i < n; i++)
+    fprintf(fp, "%d ", i);
+  fprintf(fp, "%8.4g %8.4g %8.4g 1.0 }\n", color[0], color[1], color[2]);
+} /* printfacet3geom_points */
+
+
+/*---------------------------------
+  
+  qh_printfacet3geom_simplicial(  )
+    print Geomview OFF for a 3-d simplicial facet.
+
+  notes:
+    may flip color
+    uses facet->visitid for intersections and ridges
+
+    assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
+    innerplane may be off by qh DISTround.  Maxoutside is calculated elsewhere
+    so a DISTround error may have occured.
+*/
+void qh_printfacet3geom_simplicial(FILE *fp, facetT *facet, realT color[3]) {
+  setT *points, *vertices;
+  vertexT *vertex, **vertexp, *vertexA, *vertexB;
+  facetT *neighbor, **neighborp;
+  realT outerplane, innerplane;
+  realT black[3]={0, 0, 0}, green[3]={0, 1, 0};
+  int k;
+
+  qh_geomplanes (facet, &outerplane, &innerplane); 
+  vertices= qh_facet3vertex (facet);
+  points= qh_settemp (qh TEMPsize);
+  FOREACHvertex_(vertices)
+    qh_setappend(&points, vertex->point);
+  if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
+    qh_printfacet3geom_points(fp, points, facet, outerplane, color);
+  if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
+              outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) {
+    for (k= 3; k--; )
+      color[k]= 1.0 - color[k];
+    qh_printfacet3geom_points(fp, points, facet, innerplane, color);
+  }
+  qh_settempfree(&points);
+  qh_settempfree(&vertices);
+  if ((qh DOintersections || qh PRINTridges)
+  && (!facet->visible || !qh NEWfacets)) {
+    facet->visitid= qh visit_id;
+    FOREACHneighbor_(facet) {
+      if (neighbor->visitid != qh visit_id) {
+	vertices= qh_setnew_delnthsorted (facet->vertices, qh hull_dim,
+	                  SETindex_(facet->neighbors, neighbor), 0);
+        if (qh DOintersections)
+	   qh_printhyperplaneintersection(fp, facet, neighbor, vertices, black); 
+        if (qh PRINTridges) {
+          vertexA= SETfirstt_(vertices, vertexT);
+          vertexB= SETsecondt_(vertices, vertexT);
+          qh_printline3geom (fp, vertexA->point, vertexB->point, green);
+        }
+	qh_setfree(&vertices);
+      }
+    }
+  }
+} /* printfacet3geom_simplicial */
+
+/*---------------------------------
+  
+  qh_printfacet3math( fp, facet, notfirst )
+    print 3-d Mathematica output for a facet
+
+  notes:
+    may be non-simplicial
+    use %16.8f since Mathematica 2.2 does not handle exponential format
+*/
+void qh_printfacet3math (FILE *fp, facetT *facet, int notfirst) {
+  vertexT *vertex, **vertexp;
+  setT *points, *vertices;
+  pointT *point, **pointp;
+  boolT firstpoint= True;
+  realT dist;
+  
+  if (notfirst)
+    fprintf(fp, ",\n");
+  vertices= qh_facet3vertex (facet);
+  points= qh_settemp (qh_setsize (vertices));
+  FOREACHvertex_(vertices) {
+    zinc_(Zdistio);
+    qh_distplane(vertex->point, facet, &dist);
+    point= qh_projectpoint(vertex->point, facet, dist);
+    qh_setappend (&points, point);
+  }
+  fprintf(fp, "Polygon[{");
+  FOREACHpoint_(points) {
+    if (firstpoint)
+      firstpoint= False;
+    else
+      fprintf(fp, ",\n");
+    fprintf(fp, "{%16.8f, %16.8f, %16.8f}", point[0], point[1], point[2]);
+  }
+  FOREACHpoint_(points)
+    qh_memfree (point, qh normal_size);
+  qh_settempfree(&points);
+  qh_settempfree(&vertices);
+  fprintf(fp, "}]");
+} /* printfacet3math */
+
+
+/*---------------------------------
+  
+  qh_printfacet3vertex( fp, facet, format )
+    print vertices in a 3-d facet as point ids
+
+  notes:
+    prints number of vertices first if format == qh_PRINToff
+    the facet may be non-simplicial
+*/
+void qh_printfacet3vertex(FILE *fp, facetT *facet, int format) {
+  vertexT *vertex, **vertexp;
+  setT *vertices;
+
+  vertices= qh_facet3vertex (facet);
+  if (format == qh_PRINToff)
+    fprintf (fp, "%d ", qh_setsize (vertices));
+  FOREACHvertex_(vertices) 
+    fprintf (fp, "%d ", qh_pointid(vertex->point));
+  fprintf (fp, "\n");
+  qh_settempfree(&vertices);
+} /* printfacet3vertex */
+
+
+/*---------------------------------
+  
+  qh_printfacet4geom_nonsimplicial(  )
+    print Geomview 4OFF file for a 4d nonsimplicial facet
+    prints all ridges to unvisited neighbors (qh.visit_id)
+    if qh.DROPdim
+      prints in OFF format
+  
+  notes:
+    must agree with printend4geom()
+*/
+void qh_printfacet4geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]) {
+  facetT *neighbor;
+  ridgeT *ridge, **ridgep;
+  vertexT *vertex, **vertexp;
+  pointT *point;
+  int k;
+  realT dist;
+  
+  facet->visitid= qh visit_id;
+  if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
+    return;
+  FOREACHridge_(facet->ridges) {
+    neighbor= otherfacet_(ridge, facet);
+    if (neighbor->visitid == qh visit_id) 
+      continue;
+    if (qh PRINTtransparent && !neighbor->good)
+      continue;  
+    if (qh DOintersections)
+      qh_printhyperplaneintersection(fp, facet, neighbor, ridge->vertices, color);
+    else {
+      if (qh DROPdim >= 0) 
+	fprintf(fp, "OFF 3 1 1 # f%d\n", facet->id);
+      else {
+	qh printoutvar++;
+	fprintf (fp, "# r%d between f%d f%d\n", ridge->id, facet->id, neighbor->id);
+      }
+      FOREACHvertex_(ridge->vertices) {
+	zinc_(Zdistio);
+	qh_distplane(vertex->point,facet, &dist);
+	point=qh_projectpoint(vertex->point,facet, dist);
+	for(k= 0; k < qh hull_dim; k++) {
+	  if (k != qh DROPdim)
+  	    fprintf(fp, "%8.4g ", point[k]);
+  	}
+	fprintf (fp, "\n");
+	qh_memfree (point, qh normal_size);
+      }
+      if (qh DROPdim >= 0)
+        fprintf(fp, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
+    }
+  }
+} /* printfacet4geom_nonsimplicial */
+
+
+/*---------------------------------
+  
+  qh_printfacet4geom_simplicial( fp, facet, color )
+    print Geomview 4OFF file for a 4d simplicial facet
+    prints triangles for unvisited neighbors (qh.visit_id)
+
+  notes:
+    must agree with printend4geom()
+*/
+void qh_printfacet4geom_simplicial(FILE *fp, facetT *facet, realT color[3]) {
+  setT *vertices;
+  facetT *neighbor, **neighborp;
+  vertexT *vertex, **vertexp;
+  int k;
+  
+  facet->visitid= qh visit_id;
+  if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
+    return;
+  FOREACHneighbor_(facet) {
+    if (neighbor->visitid == qh visit_id)
+      continue;
+    if (qh PRINTtransparent && !neighbor->good)
+      continue;  
+    vertices= qh_setnew_delnthsorted (facet->vertices, qh hull_dim,
+	                  SETindex_(facet->neighbors, neighbor), 0);
+    if (qh DOintersections)
+      qh_printhyperplaneintersection(fp, facet, neighbor, vertices, color);
+    else {
+      if (qh DROPdim >= 0) 
+	fprintf(fp, "OFF 3 1 1 # ridge between f%d f%d\n",
+		facet->id, neighbor->id);
+      else {
+	qh printoutvar++;
+	fprintf (fp, "# ridge between f%d f%d\n", facet->id, neighbor->id);
+      }
+      FOREACHvertex_(vertices) {
+	for(k= 0; k < qh hull_dim; k++) {
+	  if (k != qh DROPdim)
+  	    fprintf(fp, "%8.4g ", vertex->point[k]);
+  	}
+	fprintf (fp, "\n");
+      }
+      if (qh DROPdim >= 0) 
+        fprintf(fp, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
+    }
+    qh_setfree(&vertices);
+  }
+} /* printfacet4geom_simplicial */
+
+
+/*---------------------------------
+  
+  qh_printfacetNvertex_nonsimplicial( fp, facet, id, format )
+    print vertices for an N-d non-simplicial facet
+    triangulates each ridge to the id
+*/
+void qh_printfacetNvertex_nonsimplicial(FILE *fp, facetT *facet, int id, int format) {
+  vertexT *vertex, **vertexp;
+  ridgeT *ridge, **ridgep;
+
+  if (facet->visible && qh NEWfacets)
+    return;
+  FOREACHridge_(facet->ridges) {
+    if (format == qh_PRINTtriangles)
+      fprintf(fp, "%d ", qh hull_dim);
+    fprintf(fp, "%d ", id);
+    if ((ridge->top == facet) ^ qh_ORIENTclock) {
+      FOREACHvertex_(ridge->vertices)
+        fprintf(fp, "%d ", qh_pointid(vertex->point));
+    }else {
+      FOREACHvertexreverse12_(ridge->vertices)
+        fprintf(fp, "%d ", qh_pointid(vertex->point));
+    }
+    fprintf(fp, "\n");
+  }
+} /* printfacetNvertex_nonsimplicial */
+
+
+/*---------------------------------
+  
+  qh_printfacetNvertex_simplicial( fp, facet, format )
+    print vertices for an N-d simplicial facet
+    prints vertices for non-simplicial facets
+      2-d facets (orientation preserved by qh_mergefacet2d)
+      PRINToff ('o') for 4-d and higher
+*/
+void qh_printfacetNvertex_simplicial(FILE *fp, facetT *facet, int format) {
+  vertexT *vertex, **vertexp;
+
+  if (format == qh_PRINToff || format == qh_PRINTtriangles)
+    fprintf (fp, "%d ", qh_setsize (facet->vertices));
+  if ((facet->toporient ^ qh_ORIENTclock) 
+  || (qh hull_dim > 2 && !facet->simplicial)) {
+    FOREACHvertex_(facet->vertices)
+      fprintf(fp, "%d ", qh_pointid(vertex->point));
+  }else {
+    FOREACHvertexreverse12_(facet->vertices)
+      fprintf(fp, "%d ", qh_pointid(vertex->point));
+  }
+  fprintf(fp, "\n");
+} /* printfacetNvertex_simplicial */
+
+
+/*---------------------------------
+  
+  qh_printfacetheader( fp, facet )
+    prints header fields of a facet to fp
+    
+  notes:
+    for 'f' output and debugging
+*/
+void qh_printfacetheader(FILE *fp, facetT *facet) {
+  pointT *point, **pointp, *furthest;
+  facetT *neighbor, **neighborp;
+  realT dist;
+
+  if (facet == qh_MERGEridge) {
+    fprintf (fp, " MERGEridge\n");
+    return;
+  }else if (facet == qh_DUPLICATEridge) {
+    fprintf (fp, " DUPLICATEridge\n");
+    return;
+  }else if (!facet) {
+    fprintf (fp, " NULLfacet\n");
+    return;
+  }
+  qh old_randomdist= qh RANDOMdist;
+  qh RANDOMdist= False;
+  fprintf(fp, "- f%d\n", facet->id);
+  fprintf(fp, "    - flags:");
+  if (facet->toporient) 
+    fprintf(fp, " top");
+  else
+    fprintf(fp, " bottom");
+  if (facet->simplicial)
+    fprintf(fp, " simplicial");
+  if (facet->tricoplanar)
+    fprintf(fp, " tricoplanar");
+  if (facet->upperdelaunay)
+    fprintf(fp, " upperDelaunay");
+  if (facet->visible)
+    fprintf(fp, " visible");
+  if (facet->newfacet)
+    fprintf(fp, " new");
+  if (facet->tested)
+    fprintf(fp, " tested");
+  if (!facet->good)
+    fprintf(fp, " notG");
+  if (facet->seen)
+    fprintf(fp, " seen");
+  if (facet->coplanar)
+    fprintf(fp, " coplanar");
+  if (facet->mergehorizon)
+    fprintf(fp, " mergehorizon");
+  if (facet->keepcentrum)
+    fprintf(fp, " keepcentrum");
+  if (facet->dupridge)
+    fprintf(fp, " dupridge");
+  if (facet->mergeridge && !facet->mergeridge2)
+    fprintf(fp, " mergeridge1");
+  if (facet->mergeridge2)
+    fprintf(fp, " mergeridge2");
+  if (facet->newmerge)
+    fprintf(fp, " newmerge");
+  if (facet->flipped) 
+    fprintf(fp, " flipped");
+  if (facet->notfurthest) 
+    fprintf(fp, " notfurthest");
+  if (facet->degenerate)
+    fprintf(fp, " degenerate");
+  if (facet->redundant)
+    fprintf(fp, " redundant");
+  fprintf(fp, "\n");
+  if (facet->isarea)
+    fprintf(fp, "    - area: %2.2g\n", facet->f.area);
+  else if (qh NEWfacets && facet->visible && facet->f.replace)
+    fprintf(fp, "    - replacement: f%d\n", facet->f.replace->id);
+  else if (facet->newfacet) {
+    if (facet->f.samecycle && facet->f.samecycle != facet)
+      fprintf(fp, "    - shares same visible/horizon as f%d\n", facet->f.samecycle->id);
+  }else if (facet->tricoplanar /* !isarea */) {
+    if (facet->f.triowner)
+      fprintf(fp, "    - owner of normal & centrum is facet f%d\n", facet->f.triowner->id);
+  }else if (facet->f.newcycle)
+    fprintf(fp, "    - was horizon to f%d\n", facet->f.newcycle->id);
+  if (facet->nummerge)
+    fprintf(fp, "    - merges: %d\n", facet->nummerge);
+  qh_printpointid(fp, "    - normal: ", qh hull_dim, facet->normal, -1);
+  fprintf(fp, "    - offset: %10.7g\n", facet->offset);
+  if (qh CENTERtype == qh_ASvoronoi || facet->center)
+    qh_printcenter (fp, qh_PRINTfacets, "    - center: ", facet);
+#if qh_MAXoutside
+  if (facet->maxoutside > qh DISTround)
+    fprintf(fp, "    - maxoutside: %10.7g\n", facet->maxoutside);
+#endif
+  if (!SETempty_(facet->outsideset)) {
+    furthest= (pointT*)qh_setlast(facet->outsideset);
+    if (qh_setsize (facet->outsideset) < 6) {
+      fprintf(fp, "    - outside set (furthest p%d):\n", qh_pointid(furthest));
+      FOREACHpoint_(facet->outsideset)
+	qh_printpoint(fp, "     ", point);
+    }else if (qh_setsize (facet->outsideset) < 21) {
+      qh_printpoints(fp, "    - outside set:", facet->outsideset);
+    }else {
+      fprintf(fp, "    - outside set:  %d points.", qh_setsize(facet->outsideset));
+      qh_printpoint(fp, "  Furthest", furthest);
+    }
+#if !qh_COMPUTEfurthest
+    fprintf(fp, "    - furthest distance= %2.2g\n", facet->furthestdist);
+#endif
+  }
+  if (!SETempty_(facet->coplanarset)) {
+    furthest= (pointT*)qh_setlast(facet->coplanarset);
+    if (qh_setsize (facet->coplanarset) < 6) {
+      fprintf(fp, "    - coplanar set (furthest p%d):\n", qh_pointid(furthest));
+      FOREACHpoint_(facet->coplanarset)
+	qh_printpoint(fp, "     ", point);
+    }else if (qh_setsize (facet->coplanarset) < 21) {
+      qh_printpoints(fp, "    - coplanar set:", facet->coplanarset);
+    }else {
+      fprintf(fp, "    - coplanar set:  %d points.", qh_setsize(facet->coplanarset));
+      qh_printpoint(fp, "  Furthest", furthest);
+    }
+    zinc_(Zdistio);
+    qh_distplane (furthest, facet, &dist);
+    fprintf(fp, "      furthest distance= %2.2g\n", dist);
+  }
+  qh_printvertices (fp, "    - vertices:", facet->vertices);
+  fprintf(fp, "    - neighboring facets: ");
+  FOREACHneighbor_(facet) {
+    if (neighbor == qh_MERGEridge)
+      fprintf(fp, " MERGE");
+    else if (neighbor == qh_DUPLICATEridge)
+      fprintf(fp, " DUP");
+    else
+      fprintf(fp, " f%d", neighbor->id);
+  }
+  fprintf(fp, "\n");
+  qh RANDOMdist= qh old_randomdist;
+} /* printfacetheader */
+
+
+/*---------------------------------
+  
+  qh_printfacetridges( fp, facet )
+    prints ridges of a facet to fp
+
+  notes:
+    ridges printed in neighbor order
+    assumes the ridges exist
+    for 'f' output
+*/
+void qh_printfacetridges(FILE *fp, facetT *facet) {
+  facetT *neighbor, **neighborp;
+  ridgeT *ridge, **ridgep;
+  int numridges= 0;
+
+
+  if (facet->visible && qh NEWfacets) {
+    fprintf(fp, "    - ridges (ids may be garbage):");
+    FOREACHridge_(facet->ridges)
+      fprintf(fp, " r%d", ridge->id);
+    fprintf(fp, "\n");
+  }else {
+    fprintf(fp, "    - ridges:\n");
+    FOREACHridge_(facet->ridges)
+      ridge->seen= False;
+    if (qh hull_dim == 3) {
+      ridge= SETfirstt_(facet->ridges, ridgeT);
+      while (ridge && !ridge->seen) {
+	ridge->seen= True;
+	qh_printridge(fp, ridge);
+	numridges++;
+	ridge= qh_nextridge3d (ridge, facet, NULL);
+	}
+    }else {
+      FOREACHneighbor_(facet) {
+	FOREACHridge_(facet->ridges) {
+	  if (otherfacet_(ridge,facet) == neighbor) {
+	    ridge->seen= True;
+	    qh_printridge(fp, ridge);
+	    numridges++;
+	  }
+	}
+      }
+    }
+    if (numridges != qh_setsize (facet->ridges)) {
+      fprintf (fp, "     - all ridges:");
+      FOREACHridge_(facet->ridges) 
+	fprintf (fp, " r%d", ridge->id);
+        fprintf (fp, "\n");
+    }
+    FOREACHridge_(facet->ridges) {
+      if (!ridge->seen) 
+	qh_printridge(fp, ridge);
+    }
+  }
+} /* printfacetridges */
+
+/*---------------------------------
+  
+  qh_printfacets( fp, format, facetlist, facets, printall )
+    prints facetlist and/or facet set in output format
+  
+  notes:
+    also used for specialized formats ('FO' and summary)
+    turns off 'Rn' option since want actual numbers
+*/
+void qh_printfacets(FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
+  int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;
+  facetT *facet, **facetp;
+  setT *vertices;
+  coordT *center;
+  realT outerplane, innerplane;
+
+  qh old_randomdist= qh RANDOMdist;
+  qh RANDOMdist= False;
+  if (qh CDDoutput && (format == qh_PRINTcentrums || format == qh_PRINTpointintersect || format == qh_PRINToff))
+    fprintf (qh ferr, "qhull warning: CDD format is not available for centrums, halfspace\nintersections, and OFF file format.\n");
+  if (format == qh_PRINTnone)
+    ; /* print nothing */
+  else if (format == qh_PRINTaverage) {
+    vertices= qh_facetvertices (facetlist, facets, printall);
+    center= qh_getcenter (vertices);
+    fprintf (fp, "%d 1\n", qh hull_dim);
+    qh_printpointid (fp, NULL, qh hull_dim, center, -1);
+    qh_memfree (center, qh normal_size);
+    qh_settempfree (&vertices);
+  }else if (format == qh_PRINTextremes) {
+    if (qh DELAUNAY)
+      qh_printextremes_d (fp, facetlist, facets, printall);
+    else if (qh hull_dim == 2)
+      qh_printextremes_2d (fp, facetlist, facets, printall);
+    else 
+      qh_printextremes (fp, facetlist, facets, printall);
+  }else if (format == qh_PRINToptions)
+    fprintf(fp, "Options selected for Qhull %s:\n%s\n", qh_VERSION, qh qhull_options);
+  else if (format == qh_PRINTpoints && !qh VORONOI)
+    qh_printpoints_out (fp, facetlist, facets, printall);
+  else if (format == qh_PRINTqhull)
+    fprintf (fp, "%s | %s\n", qh rbox_command, qh qhull_command);
+  else if (format == qh_PRINTsize) {
+    fprintf (fp, "0\n2 ");
+    fprintf (fp, qh_REAL_1, qh totarea);
+    fprintf (fp, qh_REAL_1, qh totvol);
+    fprintf (fp, "\n");
+  }else if (format == qh_PRINTsummary) {
+    qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial, 
+      &totneighbors, &numridges, &numcoplanars, &numtricoplanars);
+    vertices= qh_facetvertices (facetlist, facets, printall); 
+    fprintf (fp, "10 %d %d %d %d %d %d %d %d %d %d\n2 ", qh hull_dim, 
+                qh num_points + qh_setsize (qh other_points),
+                qh num_vertices, qh num_facets - qh num_visible,
+                qh_setsize (vertices), numfacets, numcoplanars, 
+		numfacets - numsimplicial, zzval_(Zdelvertextot), 
+		numtricoplanars);
+    qh_settempfree (&vertices);
+    qh_outerinner (NULL, &outerplane, &innerplane);
+    fprintf (fp, qh_REAL_2n, outerplane, innerplane);
+  }else if (format == qh_PRINTvneighbors)
+    qh_printvneighbors (fp, facetlist, facets, printall);
+  else if (qh VORONOI && format == qh_PRINToff)
+    qh_printvoronoi (fp, format, facetlist, facets, printall);
+  else if (qh VORONOI && format == qh_PRINTgeom) {
+    qh_printbegin (fp, format, facetlist, facets, printall);
+    qh_printvoronoi (fp, format, facetlist, facets, printall);
+    qh_printend (fp, format, facetlist, facets, printall);
+  }else if (qh VORONOI 
+  && (format == qh_PRINTvertices || format == qh_PRINTinner || format == qh_PRINTouter))
+    qh_printvdiagram (fp, format, facetlist, facets, printall);
+  else {
+    qh_printbegin (fp, format, facetlist, facets, printall);
+    FORALLfacet_(facetlist)
+      qh_printafacet (fp, format, facet, printall);
+    FOREACHfacet_(facets) 
+      qh_printafacet (fp, format, facet, printall);
+    qh_printend (fp, format, facetlist, facets, printall);
+  }
+  qh RANDOMdist= qh old_randomdist;
+} /* printfacets */
+
+
+/*---------------------------------
+  
+  qh_printhelp_degenerate( fp )
+    prints descriptive message for precision error
+
+  notes:
+    no message if qh_QUICKhelp
+*/
+void qh_printhelp_degenerate(FILE *fp) {
+  
+  if (qh MERGEexact || qh PREmerge || qh JOGGLEmax < REALmax/2) 
+    fprintf(fp, "\n\
+A Qhull error has occurred.  Qhull should have corrected the above\n\
+precision error.  Please send the input and all of the output to\n\
+qhull_bug@geom.umn.edu\n");
+  else if (!qh_QUICKhelp) {
+    fprintf(fp, "\n\
+Precision problems were detected during construction of the convex hull.\n\
+This occurs because convex hull algorithms assume that calculations are\n\
+exact, but floating-point arithmetic has roundoff errors.\n\
+\n\
+To correct for precision problems, do not use 'Q0'.  By default, Qhull\n\
+selects 'C-0' or 'Qx' and merges non-convex facets.  With option 'QJ',\n\
+Qhull joggles the input to prevent precision problems.  See \"Imprecision\n\
+in Qhull\" (qh-impre.htm).\n\
+\n\
+If you use 'Q0', the output may include\n\
+coplanar ridges, concave ridges, and flipped facets.  In 4-d and higher,\n\
+Qhull may produce a ridge with four neighbors or two facets with the same \n\
+vertices.  Qhull reports these events when they occur.  It stops when a\n\
+concave ridge, flipped facet, or duplicate facet occurs.\n");
+#if REALfloat
+    fprintf (fp, "\
+\n\
+Qhull is currently using single precision arithmetic.  The following\n\
+will probably remove the precision problems:\n\
+  - recompile qhull for double precision (#define REALfloat 0 in user.h).\n");
+#endif
+    if (qh DELAUNAY && !qh SCALElast && qh MAXabs_coord > 1e4)
+      fprintf( fp, "\
+\n\
+When computing the Delaunay triangulation of coordinates > 1.0,\n\
+  - use 'Qbb' to scale the last coordinate to [0,m] (max previous coordinate)\n");
+    if (qh DELAUNAY && !qh ATinfinity) 
+      fprintf( fp, "\
+When computing the Delaunay triangulation:\n\
+  - use 'Qz' to add a point at-infinity.  This reduces precision problems.\n");
+ 
+    fprintf(fp, "\
+\n\
+If you need triangular output:\n\
+  - use option 'Qt' to triangulate the output\n\
+  - use option 'QJ' to joggle the input points and remove precision errors\n\
+  - use option 'Ft'.  It triangulates non-simplicial facets with added points.\n\
+\n\
+If you must use 'Q0',\n\
+try one or more of the following options.  They can not guarantee an output.\n\
+  - use 'QbB' to scale the input to a cube.\n\
+  - use 'Po' to produce output and prevent partitioning for flipped facets\n\
+  - use 'V0' to set min. distance to visible facet as 0 instead of roundoff\n\
+  - use 'En' to specify a maximum roundoff error less than %2.2g.\n\
+  - options 'Qf', 'Qbb', and 'QR0' may also help\n",
+               qh DISTround);
+    fprintf(fp, "\
+\n\
+To guarantee simplicial output:\n\
+  - use option 'Qt' to triangulate the output\n\
+  - use option 'QJ' to joggle the input points and remove precision errors\n\
+  - use option 'Ft' to triangulate the output by adding points\n\
+  - use exact arithmetic (see \"Imprecision in Qhull\", qh-impre.htm)\n\
+");
+  }
+} /* printhelp_degenerate */
+
+
+/*---------------------------------
+  
+  qh_printhelp_singular( fp )
+    prints descriptive message for singular input
+*/
+void qh_printhelp_singular(FILE *fp) {
+  facetT *facet;
+  vertexT *vertex, **vertexp;
+  realT min, max, *coord, dist;
+  int i,k;
+  
+  fprintf(fp, "\n\
+The input to qhull appears to be less than %d dimensional, or a\n\
+computation has overflowed.\n\n\
+Qhull could not construct a clearly convex simplex from points:\n",
+           qh hull_dim);
+  qh_printvertexlist (fp, "", qh facet_list, NULL, qh_ALL);
+  if (!qh_QUICKhelp)
+    fprintf(fp, "\n\
+The center point is coplanar with a facet, or a vertex is coplanar\n\
+with a neighboring facet.  The maximum round off error for\n\
+computing distances is %2.2g.  The center point, facets and distances\n\
+to the center point are as follows:\n\n", qh DISTround);
+  qh_printpointid (fp, "center point", qh hull_dim, qh interior_point, -1);
+  fprintf (fp, "\n");
+  FORALLfacets {
+    fprintf (fp, "facet");
+    FOREACHvertex_(facet->vertices)
+      fprintf (fp, " p%d", qh_pointid(vertex->point));
+    zinc_(Zdistio);
+    qh_distplane(qh interior_point, facet, &dist);
+    fprintf (fp, " distance= %4.2g\n", dist);
+  }
+  if (!qh_QUICKhelp) {
+    if (qh HALFspace) 
+      fprintf (fp, "\n\
+These points are the dual of the given halfspaces.  They indicate that\n\
+the intersection is degenerate.\n");
+    fprintf (fp,"\n\
+These points either have a maximum or minimum x-coordinate, or\n\
+they maximize the determinant for k coordinates.  Trial points\n\
+are first selected from points that maximize a coordinate.\n");
+    if (qh hull_dim >= qh_INITIALmax)
+      fprintf (fp, "\n\
+Because of the high dimension, the min x-coordinate and max-coordinate\n\
+points are used if the determinant is non-zero.  Option 'Qs' will\n\
+do a better, though much slower, job.  Instead of 'Qs', you can change\n\
+the points by randomly rotating the input with 'QR0'.\n");
+  }
+  fprintf (fp, "\nThe min and max coordinates for each dimension are:\n");
+  for (k=0; k < qh hull_dim; k++) {
+    min= REALmax;
+    max= -REALmin;
+    for (i=qh num_points, coord= qh first_point+k; i--; coord += qh hull_dim) {
+      maximize_(max, *coord);
+      minimize_(min, *coord);
+    }
+    fprintf (fp, "  %d:  %8.4g  %8.4g  difference= %4.4g\n", k, min, max, max-min);
+  }
+  if (!qh_QUICKhelp) {
+    fprintf (fp, "\n\
+If the input should be full dimensional, you have several options that\n\
+may determine an initial simplex:\n\
+  - use 'QJ'  to joggle the input and make it full dimensional\n\
+  - use 'QbB' to scale the points to the unit cube\n\
+  - use 'QR0' to randomly rotate the input for different maximum points\n\
+  - use 'Qs'  to search all points for the initial simplex\n\
+  - use 'En'  to specify a maximum roundoff error less than %2.2g.\n\
+  - trace execution with 'T3' to see the determinant for each point.\n",
+                     qh DISTround);
+#if REALfloat
+    fprintf (fp, "\
+  - recompile qhull for double precision (#define REALfloat 0 in qhull.h).\n");
+#endif
+    fprintf (fp, "\n\
+If the input is lower dimensional:\n\
+  - use 'QJ' to joggle the input and make it full dimensional\n\
+  - use 'Qbk:0Bk:0' to delete coordinate k from the input.  You should\n\
+    pick the coordinate with the least range.  The hull will have the\n\
+    correct topology.\n\
+  - determine the flat containing the points, rotate the points\n\
+    into a coordinate plane, and delete the other coordinates.\n\
+  - add one or more points to make the input full dimensional.\n\
+");
+    if (qh DELAUNAY && !qh ATinfinity)
+      fprintf (fp, "\n\n\
+This is a Delaunay triangulation and the input is co-circular or co-spherical:\n\
+  - use 'Qz' to add a point \"at infinity\" (i.e., above the paraboloid)\n\
+  - or use 'QJ' to joggle the input and avoid co-circular data\n");
+  }
+} /* printhelp_singular */
+
+/*---------------------------------
+  
+  qh_printhyperplaneintersection( fp, facet1, facet2, vertices, color )
+    print Geomview OFF or 4OFF for the intersection of two hyperplanes in 3-d or 4-d
+*/
+void qh_printhyperplaneintersection(FILE *fp, facetT *facet1, facetT *facet2,
+		   setT *vertices, realT color[3]) {
+  realT costheta, denominator, dist1, dist2, s, t, mindenom, p[4];
+  vertexT *vertex, **vertexp;
+  int i, k;
+  boolT nearzero1, nearzero2;
+  
+  costheta= qh_getangle(facet1->normal, facet2->normal);
+  denominator= 1 - costheta * costheta;
+  i= qh_setsize(vertices);
+  if (qh hull_dim == 3)
+    fprintf(fp, "VECT 1 %d 1 %d 1 ", i, i);
+  else if (qh hull_dim == 4 && qh DROPdim >= 0)
+    fprintf(fp, "OFF 3 1 1 ");
+  else
+    qh printoutvar++;
+  fprintf (fp, "# intersect f%d f%d\n", facet1->id, facet2->id);
+  mindenom= 1 / (10.0 * qh MAXabs_coord);
+  FOREACHvertex_(vertices) {
+    zadd_(Zdistio, 2);
+    qh_distplane(vertex->point, facet1, &dist1);
+    qh_distplane(vertex->point, facet2, &dist2);
+    s= qh_divzero (-dist1 + costheta * dist2, denominator,mindenom,&nearzero1);
+    t= qh_divzero (-dist2 + costheta * dist1, denominator,mindenom,&nearzero2);
+    if (nearzero1 || nearzero2)
+      s= t= 0.0;
+    for(k= qh hull_dim; k--; )
+      p[k]= vertex->point[k] + facet1->normal[k] * s + facet2->normal[k] * t;
+    if (qh PRINTdim <= 3) {
+      qh_projectdim3 (p, p);
+      fprintf(fp, "%8.4g %8.4g %8.4g # ", p[0], p[1], p[2]);
+    }else 
+      fprintf(fp, "%8.4g %8.4g %8.4g %8.4g # ", p[0], p[1], p[2], p[3]);
+    if (nearzero1+nearzero2)
+      fprintf (fp, "p%d (coplanar facets)\n", qh_pointid (vertex->point));
+    else
+      fprintf (fp, "projected p%d\n", qh_pointid (vertex->point));
+  }
+  if (qh hull_dim == 3)
+    fprintf(fp, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]); 
+  else if (qh hull_dim == 4 && qh DROPdim >= 0)  
+    fprintf(fp, "3 0 1 2 %8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
+} /* printhyperplaneintersection */
+
+/*---------------------------------
+  
+  qh_printline3geom( fp, pointA, pointB, color )
+    prints a line as a VECT
+    prints 0's for qh.DROPdim
+  
+  notes:
+    if pointA == pointB, 
+      it's a 1 point VECT
+*/
+void qh_printline3geom (FILE *fp, pointT *pointA, pointT *pointB, realT color[3]) {
+  int k;
+  realT pA[4], pB[4];
+
+  qh_projectdim3(pointA, pA);
+  qh_projectdim3(pointB, pB);
+  if ((fabs(pA[0] - pB[0]) > 1e-3) || 
+      (fabs(pA[1] - pB[1]) > 1e-3) || 
+      (fabs(pA[2] - pB[2]) > 1e-3)) {
+    fprintf (fp, "VECT 1 2 1 2 1\n");
+    for (k= 0; k < 3; k++)
+       fprintf (fp, "%8.4g ", pB[k]);
+    fprintf (fp, " # p%d\n", qh_pointid (pointB));
+  }else
+    fprintf (fp, "VECT 1 1 1 1 1\n");
+  for (k=0; k < 3; k++)
+    fprintf (fp, "%8.4g ", pA[k]);
+  fprintf (fp, " # p%d\n", qh_pointid (pointA));
+  fprintf (fp, "%8.4g %8.4g %8.4g 1\n", color[0], color[1], color[2]);
+}
+
+/*---------------------------------
+  
+  qh_printneighborhood( fp, format, facetA, facetB, printall )
+    print neighborhood of one or two facets
+
+  notes:
+    calls qh_findgood_all() 
+    bumps qh.visit_id
+*/
+void qh_printneighborhood (FILE *fp, int format, facetT *facetA, facetT *facetB, boolT printall) {
+  facetT *neighbor, **neighborp, *facet;
+  setT *facets;
+
+  if (format == qh_PRINTnone)
+    return;
+  qh_findgood_all (qh facet_list);
+  if (facetA == facetB)
+    facetB= NULL;
+  facets= qh_settemp (2*(qh_setsize (facetA->neighbors)+1));
+  qh visit_id++;
+  for (facet= facetA; facet; facet= ((facet == facetA) ? facetB : NULL)) {
+    if (facet->visitid != qh visit_id) {
+      facet->visitid= qh visit_id;
+      qh_setappend (&facets, facet);
+    }
+    FOREACHneighbor_(facet) {
+      if (neighbor->visitid == qh visit_id)
+        continue;
+      neighbor->visitid= qh visit_id;
+      if (printall || !qh_skipfacet (neighbor))
+        qh_setappend (&facets, neighbor);
+    }
+  }
+  qh_printfacets (fp, format, NULL, facets, printall);
+  qh_settempfree (&facets);
+} /* printneighborhood */
+
+/*---------------------------------
+  
+  qh_printpoint( fp, string, point )
+  qh_printpointid( fp, string, dim, point, id )
+    prints the coordinates of a point
+
+  returns:
+    if string is defined
+      prints 'string p%d' (skips p%d if id=-1)
+
+  notes:
+    nop if point is NULL
+    prints id unless it is undefined (-1)
+*/
+void qh_printpoint(FILE *fp, char *string, pointT *point) {
+  int id= qh_pointid( point);
+
+  qh_printpointid( fp, string, qh hull_dim, point, id);
+} /* printpoint */
+
+void qh_printpointid(FILE *fp, char *string, int dim, pointT *point, int id) {
+  int k;
+  realT r; /*bug fix*/
+  
+  if (!point)
+    return;
+  if (string) {
+    fputs (string, fp);
+   if (id != -1)
+      fprintf(fp, " p%d: ", id);
+  }
+  for(k= dim; k--; ) {
+    r= *point++;
+    if (string)
+      fprintf(fp, " %8.4g", r);
+    else
+      fprintf(fp, qh_REAL_1, r);
+  }
+  fprintf(fp, "\n");
+} /* printpointid */
+
+/*---------------------------------
+  
+  qh_printpoint3( fp, point )
+    prints 2-d, 3-d, or 4-d point as Geomview 3-d coordinates
+*/
+void qh_printpoint3 (FILE *fp, pointT *point) {
+  int k;
+  realT p[4];
+  
+  qh_projectdim3 (point, p);
+  for (k=0; k < 3; k++)
+    fprintf (fp, "%8.4g ", p[k]);
+  fprintf (fp, " # p%d\n", qh_pointid (point));
+} /* printpoint3 */
+
+/*----------------------------------------
+-printpoints- print pointids for a set of points starting at index 
+   see geom.c
+*/
+
+/*---------------------------------
+  
+  qh_printpoints_out( fp, facetlist, facets, printall )
+    prints vertices, coplanar/inside points, for facets by their point coordinates
+    allows qh.CDDoutput
+
+  notes:
+    same format as qhull input
+    if no coplanar/interior points,
+      same order as qh_printextremes
+*/
+void qh_printpoints_out (FILE *fp, facetT *facetlist, setT *facets, int printall) {
+  int allpoints= qh num_points + qh_setsize (qh other_points);
+  int numpoints=0, point_i, point_n;
+  setT *vertices, *points;
+  facetT *facet, **facetp;
+  pointT *point, **pointp;
+  vertexT *vertex, **vertexp;
+  int id;
+
+  points= qh_settemp (allpoints);
+  qh_setzero (points, 0, allpoints);
+  vertices= qh_facetvertices (facetlist, facets, printall);
+  FOREACHvertex_(vertices) {
+    id= qh_pointid (vertex->point);
+    if (id >= 0)
+      SETelem_(points, id)= vertex->point;
+  }
+  if (qh KEEPinside || qh KEEPcoplanar || qh KEEPnearinside) {
+    FORALLfacet_(facetlist) {
+      if (!printall && qh_skipfacet(facet))
+        continue;
+      FOREACHpoint_(facet->coplanarset) {
+        id= qh_pointid (point);
+        if (id >= 0)
+          SETelem_(points, id)= point;
+      }
+    }
+    FOREACHfacet_(facets) {
+      if (!printall && qh_skipfacet(facet))
+        continue;
+      FOREACHpoint_(facet->coplanarset) {
+        id= qh_pointid (point);
+        if (id >= 0)
+          SETelem_(points, id)= point;
+      }
+    }
+  }
+  qh_settempfree (&vertices);
+  FOREACHpoint_i_(points) {
+    if (point)
+      numpoints++;
+  }
+  if (qh CDDoutput)
+    fprintf (fp, "%s | %s\nbegin\n%d %d real\n", qh rbox_command,
+             qh qhull_command, numpoints, qh hull_dim + 1);
+  else
+    fprintf (fp, "%d\n%d\n", qh hull_dim, numpoints);
+  FOREACHpoint_i_(points) {
+    if (point) {
+      if (qh CDDoutput)
+	fprintf (fp, "1 ");
+      qh_printpoint (fp, NULL, point);
+    }
+  }
+  if (qh CDDoutput)
+    fprintf (fp, "end\n");
+  qh_settempfree (&points);
+} /* printpoints_out */
+  
+
+/*---------------------------------
+  
+  qh_printpointvect( fp, point, normal, center, radius, color )
+    prints a 2-d, 3-d, or 4-d point as 3-d VECT's relative to normal or to center point
+*/
+void qh_printpointvect (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]) {
+  realT diff[4], pointA[4];
+  int k;
+  
+  for (k= qh hull_dim; k--; ) {
+    if (center)
+      diff[k]= point[k]-center[k];
+    else if (normal) 
+      diff[k]= normal[k];
+    else
+      diff[k]= 0;
+  }
+  if (center)
+    qh_normalize2 (diff, qh hull_dim, True, NULL, NULL);
+  for (k= qh hull_dim; k--; ) 
+    pointA[k]= point[k]+diff[k] * radius;
+  qh_printline3geom (fp, point, pointA, color);
+} /* printpointvect */  
+
+/*---------------------------------
+  
+  qh_printpointvect2( fp, point, normal, center, radius )
+    prints a 2-d, 3-d, or 4-d point as 2 3-d VECT's for an imprecise point
+*/
+void qh_printpointvect2 (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius) {
+  realT red[3]={1, 0, 0}, yellow[3]={1, 1, 0};
+
+  qh_printpointvect (fp, point, normal, center, radius, red);
+  qh_printpointvect (fp, point, normal, center, -radius, yellow);
+} /* printpointvect2 */
+
+/*---------------------------------
+  
+  qh_printridge( fp, ridge )
+    prints the information in a ridge
+
+  notes:
+    for qh_printfacetridges()
+*/
+void qh_printridge(FILE *fp, ridgeT *ridge) {
+  
+  fprintf(fp, "     - r%d", ridge->id);
+  if (ridge->tested)
+    fprintf (fp, " tested");
+  if (ridge->nonconvex)
+    fprintf (fp, " nonconvex");
+  fprintf (fp, "\n");
+  qh_printvertices (fp, "           vertices:", ridge->vertices);
+  if (ridge->top && ridge->bottom)
+    fprintf(fp, "           between f%d and f%d\n",
+	    ridge->top->id, ridge->bottom->id);
+} /* printridge */
+
+/*---------------------------------
+  
+  qh_printspheres( fp, vertices, radius )
+    prints 3-d vertices as OFF spheres
+
+  notes:
+    inflated octahedron from Stuart Levy earth/mksphere2
+*/
+void qh_printspheres(FILE *fp, setT *vertices, realT radius) {
+  vertexT *vertex, **vertexp;
+
+  qh printoutnum++;
+  fprintf (fp, "{appearance {-edge -normal normscale 0} {\n\
+INST geom {define vsphere OFF\n\
+18 32 48\n\
+\n\
+0 0 1\n\
+1 0 0\n\
+0 1 0\n\
+-1 0 0\n\
+0 -1 0\n\
+0 0 -1\n\
+0.707107 0 0.707107\n\
+0 -0.707107 0.707107\n\
+0.707107 -0.707107 0\n\
+-0.707107 0 0.707107\n\
+-0.707107 -0.707107 0\n\
+0 0.707107 0.707107\n\
+-0.707107 0.707107 0\n\
+0.707107 0.707107 0\n\
+0.707107 0 -0.707107\n\
+0 0.707107 -0.707107\n\
+-0.707107 0 -0.707107\n\
+0 -0.707107 -0.707107\n\
+\n\
+3 0 6 11\n\
+3 0 7 6	\n\
+3 0 9 7	\n\
+3 0 11 9\n\
+3 1 6 8	\n\
+3 1 8 14\n\
+3 1 13 6\n\
+3 1 14 13\n\
+3 2 11 13\n\
+3 2 12 11\n\
+3 2 13 15\n\
+3 2 15 12\n\
+3 3 9 12\n\
+3 3 10 9\n\
+3 3 12 16\n\
+3 3 16 10\n\
+3 4 7 10\n\
+3 4 8 7\n\
+3 4 10 17\n\
+3 4 17 8\n\
+3 5 14 17\n\
+3 5 15 14\n\
+3 5 16 15\n\
+3 5 17 16\n\
+3 6 13 11\n\
+3 7 8 6\n\
+3 9 10 7\n\
+3 11 12 9\n\
+3 14 8 17\n\
+3 15 13 14\n\
+3 16 12 15\n\
+3 17 10 16\n} transforms { TLIST\n");
+  FOREACHvertex_(vertices) {
+    fprintf(fp, "%8.4g 0 0 0 # v%d\n 0 %8.4g 0 0\n0 0 %8.4g 0\n",
+      radius, vertex->id, radius, radius);
+    qh_printpoint3 (fp, vertex->point);
+    fprintf (fp, "1\n");
+  }
+  fprintf (fp, "}}}\n");
+} /* printspheres */
+
+
+/*----------------------------------------------
+-printsummary-
+                see qhull.c
+*/
+
+/*---------------------------------
+  
+  qh_printvdiagram( fp, format, facetlist, facets, printall )
+    print voronoi diagram
+      # of pairs of input sites
+      #indices site1 site2 vertex1 ...
+    
+    sites indexed by input point id
+      point 0 is the first input point
+    vertices indexed by 'o' and 'p' order
+      vertex 0 is the 'vertex-at-infinity'
+      vertex 1 is the first Voronoi vertex
+
+  see:
+    qh_printvoronoi()
+    qh_eachvoronoi_all()
+
+  notes:
+    if all facets are upperdelaunay, 
+      prints upper hull (furthest-site Voronoi diagram)
+*/
+void qh_printvdiagram (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
+  setT *vertices;
+  int totcount, numcenters;
+  boolT islower;
+  qh_RIDGE innerouter= qh_RIDGEall;
+  printvridgeT printvridge= NULL;
+
+  if (format == qh_PRINTvertices) {
+    innerouter= qh_RIDGEall;
+    printvridge= qh_printvridge;
+  }else if (format == qh_PRINTinner) {
+    innerouter= qh_RIDGEinner;
+    printvridge= qh_printvnorm;
+  }else if (format == qh_PRINTouter) {
+    innerouter= qh_RIDGEouter;
+    printvridge= qh_printvnorm;
+  }else {
+    fprintf(qh ferr, "qh_printvdiagram: unknown print format %d.\n", format);
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }
+  vertices= qh_markvoronoi (facetlist, facets, printall, &islower, &numcenters);
+  totcount= qh_printvdiagram2 (NULL, NULL, vertices, innerouter, False);
+  fprintf (fp, "%d\n", totcount);
+  totcount= qh_printvdiagram2 (fp, printvridge, vertices, innerouter, True /* inorder*/);
+  qh_settempfree (&vertices);
+#if 0  /* for testing qh_eachvoronoi_all */
+  fprintf (fp, "\n");
+  totcount= qh_eachvoronoi_all(fp, printvridge, qh UPPERdelaunay, innerouter, True /* inorder*/);
+  fprintf (fp, "%d\n", totcount);
+#endif
+} /* printvdiagram */
+  
+/*---------------------------------
+  
+  qh_printvdiagram2( fp, printvridge, vertices, innerouter, inorder )
+    visit all pairs of input sites (vertices) for selected Voronoi vertices
+    vertices may include NULLs
+  
+  innerouter:
+    qh_RIDGEall   print inner ridges (bounded) and outer ridges (unbounded)
+    qh_RIDGEinner print only inner ridges
+    qh_RIDGEouter print only outer ridges
+  
+  inorder:
+    print 3-d Voronoi vertices in order
+  
+  assumes:
+    qh_markvoronoi marked facet->visitid for Voronoi vertices
+    all facet->seen= False
+    all facet->seen2= True
+  
+  returns:
+    total number of Voronoi ridges 
+    if printvridge,
+      calls printvridge( fp, vertex, vertexA, centers) for each ridge
+      [see qh_eachvoronoi()]
+  
+  see:
+    qh_eachvoronoi_all()
+*/
+int qh_printvdiagram2 (FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder) {
+  int totcount= 0;
+  int vertex_i, vertex_n;
+  vertexT *vertex;
+
+  FORALLvertices 
+    vertex->seen= False;
+  FOREACHvertex_i_(vertices) {
+    if (vertex) {
+      if (qh GOODvertex > 0 && qh_pointid(vertex->point)+1 != qh GOODvertex)
+	continue;
+      totcount += qh_eachvoronoi (fp, printvridge, vertex, !qh_ALL, innerouter, inorder);
+    }
+  }
+  return totcount;
+} /* printvdiagram2 */
+  
+/*---------------------------------
+  
+  qh_printvertex( fp, vertex )
+    prints the information in a vertex
+*/
+void qh_printvertex(FILE *fp, vertexT *vertex) {
+  pointT *point;
+  int k, count= 0;
+  facetT *neighbor, **neighborp;
+  realT r; /*bug fix*/
+
+  if (!vertex) {
+    fprintf (fp, "  NULLvertex\n");
+    return;
+  }
+  fprintf(fp, "- p%d (v%d):", qh_pointid(vertex->point), vertex->id);
+  point= vertex->point;
+  if (point) {
+    for(k= qh hull_dim; k--; ) {
+      r= *point++;
+      fprintf(fp, " %5.2g", r);
+    }
+  }
+  if (vertex->deleted)
+    fprintf(fp, " deleted");
+  if (vertex->delridge)
+    fprintf (fp, " ridgedeleted");
+  fprintf(fp, "\n");
+  if (vertex->neighbors) {
+    fprintf(fp, "  neighbors:");
+    FOREACHneighbor_(vertex) {
+      if (++count % 100 == 0)
+	fprintf (fp, "\n     ");
+      fprintf(fp, " f%d", neighbor->id);
+    }
+    fprintf(fp, "\n");
+  }
+} /* printvertex */
+
+
+/*---------------------------------
+  
+  qh_printvertexlist( fp, string, facetlist, facets, printall )
+    prints vertices used by a facetlist or facet set
+    tests qh_skipfacet() if !printall
+*/
+void qh_printvertexlist (FILE *fp, char* string, facetT *facetlist, 
+                         setT *facets, boolT printall) {
+  vertexT *vertex, **vertexp;
+  setT *vertices;
+  
+  vertices= qh_facetvertices (facetlist, facets, printall);
+  fputs (string, fp);
+  FOREACHvertex_(vertices)
+    qh_printvertex(fp, vertex);
+  qh_settempfree (&vertices);
+} /* printvertexlist */
+
+
+/*---------------------------------
+  
+  qh_printvertices( fp, string, vertices )
+    prints vertices in a set
+*/
+void qh_printvertices(FILE *fp, char* string, setT *vertices) {
+  vertexT *vertex, **vertexp;
+  
+  fputs (string, fp);
+  FOREACHvertex_(vertices) 
+    fprintf (fp, " p%d (v%d)", qh_pointid(vertex->point), vertex->id);
+  fprintf(fp, "\n");
+} /* printvertices */
+
+/*---------------------------------
+  
+  qh_printvneighbors( fp, facetlist, facets, printall )
+    print vertex neighbors of vertices in facetlist and facets ('FN')
+
+  notes:
+    qh_countfacets clears facet->visitid for non-printed facets
+
+  design:
+    collect facet count and related statistics
+    if necessary, build neighbor sets for each vertex
+    collect vertices in facetlist and facets
+    build a point array for point->vertex and point->coplanar facet
+    for each point
+      list vertex neighbors or coplanar facet
+*/
+void qh_printvneighbors (FILE *fp, facetT* facetlist, setT *facets, boolT printall) {
+  int numfacets, numsimplicial, numridges, totneighbors, numneighbors, numcoplanars, numtricoplanars;
+  setT *vertices, *vertex_points, *coplanar_points;
+  int numpoints= qh num_points + qh_setsize (qh other_points);
+  vertexT *vertex, **vertexp;
+  int vertex_i, vertex_n;
+  facetT *facet, **facetp, *neighbor, **neighborp;
+  pointT *point, **pointp;
+
+  qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial, 
+      &totneighbors, &numridges, &numcoplanars, &numtricoplanars);  /* sets facet->visitid */
+  fprintf (fp, "%d\n", numpoints);
+  qh_vertexneighbors();
+  vertices= qh_facetvertices (facetlist, facets, printall);
+  vertex_points= qh_settemp (numpoints);
+  coplanar_points= qh_settemp (numpoints);
+  qh_setzero (vertex_points, 0, numpoints);
+  qh_setzero (coplanar_points, 0, numpoints);
+  FOREACHvertex_(vertices)
+    qh_point_add (vertex_points, vertex->point, vertex);
+  FORALLfacet_(facetlist) {
+    FOREACHpoint_(facet->coplanarset)
+      qh_point_add (coplanar_points, point, facet);
+  }
+  FOREACHfacet_(facets) {
+    FOREACHpoint_(facet->coplanarset)
+      qh_point_add (coplanar_points, point, facet);
+  }
+  FOREACHvertex_i_(vertex_points) {
+    if (vertex) { 
+      numneighbors= qh_setsize (vertex->neighbors);
+      fprintf (fp, "%d", numneighbors);
+      if (qh hull_dim == 3)
+        qh_order_vertexneighbors (vertex);
+      else if (qh hull_dim >= 4)
+        qsort (SETaddr_(vertex->neighbors, facetT), numneighbors,
+             sizeof (facetT *), qh_compare_facetvisit);
+      FOREACHneighbor_(vertex) 
+        fprintf (fp, " %d", 
+		 neighbor->visitid ? neighbor->visitid - 1 : - neighbor->id);
+      fprintf (fp, "\n");
+    }else if ((facet= SETelemt_(coplanar_points, vertex_i, facetT)))
+      fprintf (fp, "1 %d\n",
+                  facet->visitid ? facet->visitid - 1 : - facet->id);
+    else
+      fprintf (fp, "0\n");
+  }
+  qh_settempfree (&coplanar_points);
+  qh_settempfree (&vertex_points);
+  qh_settempfree (&vertices);
+} /* printvneighbors */
+
+/*---------------------------------
+  
+  qh_printvoronoi( fp, format, facetlist, facets, printall )
+    print voronoi diagram in 'o' or 'G' format
+    for 'o' format
+      prints voronoi centers for each facet and for infinity
+      for each vertex, lists ids of printed facets or infinity
+      assumes facetlist and facets are disjoint
+    for 'G' format
+      prints an OFF object
+      adds a 0 coordinate to center
+      prints infinity but does not list in vertices
+
+  see:
+    qh_printvdiagram()
+
+  notes:
+    if 'o', 
+      prints a line for each point except "at-infinity"
+    if all facets are upperdelaunay, 
+      reverses lower and upper hull
+*/
+void qh_printvoronoi (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
+  int k, numcenters, numvertices= 0, numneighbors, numinf, vid=1, vertex_i, vertex_n;
+  facetT *facet, **facetp, *neighbor, **neighborp;
+  setT *vertices;
+  vertexT *vertex;
+  boolT islower;
+  unsigned int numfacets= (unsigned int) qh num_facets;
+
+  vertices= qh_markvoronoi (facetlist, facets, printall, &islower, &numcenters);
+  FOREACHvertex_i_(vertices) {
+    if (vertex) {
+      numvertices++;
+      numneighbors = numinf = 0;
+      FOREACHneighbor_(vertex) {
+        if (neighbor->visitid == 0)
+	  numinf= 1;
+        else if (neighbor->visitid < numfacets)
+          numneighbors++;
+      }
+      if (numinf && !numneighbors) {
+	SETelem_(vertices, vertex_i)= NULL;
+	numvertices--;
+      }
+    }
+  }
+  if (format == qh_PRINTgeom) 
+    fprintf (fp, "{appearance {+edge -face} OFF %d %d 1 # Voronoi centers and cells\n", 
+                numcenters, numvertices);
+  else
+    fprintf (fp, "%d\n%d %d 1\n", qh hull_dim-1, numcenters, qh_setsize(vertices));
+  if (format == qh_PRINTgeom) {
+    for (k= qh hull_dim-1; k--; )
+      fprintf (fp, qh_REAL_1, 0.0);
+    fprintf (fp, " 0 # infinity not used\n");
+  }else {
+    for (k= qh hull_dim-1; k--; )
+      fprintf (fp, qh_REAL_1, qh_INFINITE);
+    fprintf (fp, "\n");
+  }
+  FORALLfacet_(facetlist) {
+    if (facet->visitid && facet->visitid < numfacets) {
+      if (format == qh_PRINTgeom)
+        fprintf (fp, "# %d f%d\n", vid++, facet->id);
+      qh_printcenter (fp, format, NULL, facet);
+    }
+  }
+  FOREACHfacet_(facets) {
+    if (facet->visitid && facet->visitid < numfacets) {
+      if (format == qh_PRINTgeom)
+        fprintf (fp, "# %d f%d\n", vid++, facet->id);
+      qh_printcenter (fp, format, NULL, facet);
+    }
+  }
+  FOREACHvertex_i_(vertices) {
+    numneighbors= 0;
+    numinf=0;
+    if (vertex) {
+      if (qh hull_dim == 3)
+        qh_order_vertexneighbors(vertex);
+      else if (qh hull_dim >= 4)
+        qsort (SETaddr_(vertex->neighbors, vertexT), 
+	     qh_setsize (vertex->neighbors),
+	     sizeof (facetT *), qh_compare_facetvisit);
+      FOREACHneighbor_(vertex) {
+        if (neighbor->visitid == 0)
+	  numinf= 1;
+	else if (neighbor->visitid < numfacets)
+          numneighbors++;
+      }
+    }
+    if (format == qh_PRINTgeom) {
+      if (vertex) {
+	fprintf (fp, "%d", numneighbors);
+	if (vertex) {
+	  FOREACHneighbor_(vertex) {
+	    if (neighbor->visitid && neighbor->visitid < numfacets)
+	      fprintf (fp, " %d", neighbor->visitid);
+	  }
+	}
+	fprintf (fp, " # p%d (v%d)\n", vertex_i, vertex->id);
+      }else
+	fprintf (fp, " # p%d is coplanar or isolated\n", vertex_i);
+    }else {
+      if (numinf)
+	numneighbors++;
+      fprintf (fp, "%d", numneighbors);
+      if (vertex) {
+        FOREACHneighbor_(vertex) {
+  	  if (neighbor->visitid == 0) {
+  	    if (numinf) {
+  	      numinf= 0;
+	      fprintf (fp, " %d", neighbor->visitid);
+	    }
+	  }else if (neighbor->visitid < numfacets)
+	    fprintf (fp, " %d", neighbor->visitid);
+	}
+      }
+      fprintf (fp, "\n");
+    }
+  }
+  if (format == qh_PRINTgeom)
+    fprintf (fp, "}\n");
+  qh_settempfree (&vertices);
+} /* printvoronoi */
+  
+/*---------------------------------
+  
+  qh_printvnorm( fp, vertex, vertexA, centers, unbounded )
+    print one separating plane of the Voronoi diagram for a pair of input sites
+    unbounded==True if centers includes vertex-at-infinity
+  
+  assumes:
+    qh_ASvoronoi and qh_vertexneighbors() already set
+    
+  see:
+    qh_printvdiagram()
+    qh_eachvoronoi()
+*/
+void qh_printvnorm (FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {
+  pointT *normal;
+  realT offset;
+  int k;
+  
+  normal= qh_detvnorm (vertex, vertexA, centers, &offset);
+  fprintf (fp, "%d %d %d ", 
+      2+qh hull_dim, qh_pointid (vertex->point), qh_pointid (vertexA->point));
+  for (k= 0; k< qh hull_dim-1; k++)
+    fprintf (fp, qh_REAL_1, normal[k]);
+  fprintf (fp, qh_REAL_1, offset);
+  fprintf (fp, "\n");
+} /* printvnorm */
+
+/*---------------------------------
+  
+  qh_printvridge( fp, vertex, vertexA, centers, unbounded )
+    print one ridge of the Voronoi diagram for a pair of input sites
+    unbounded==True if centers includes vertex-at-infinity
+  
+  see:
+    qh_printvdiagram()
+  
+  notes:
+    the user may use a different function
+*/
+void qh_printvridge (FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {
+  facetT *facet, **facetp;
+
+  fprintf (fp, "%d %d %d", qh_setsize (centers)+2, 
+       qh_pointid (vertex->point), qh_pointid (vertexA->point));
+  FOREACHfacet_(centers) 
+    fprintf (fp, " %d", facet->visitid);
+  fprintf (fp, "\n");
+} /* printvridge */
+
+/*---------------------------------
+  
+  qh_projectdim3( source, destination )
+    project 2-d 3-d or 4-d point to a 3-d point
+    uses qh.DROPdim and qh.hull_dim
+    source and destination may be the same
+    
+  notes:
+    allocate 4 elements to destination just in case
+*/
+void qh_projectdim3 (pointT *source, pointT *destination) {
+  int i,k;
+
+  for (k= 0, i=0; k < qh hull_dim; k++) {
+    if (qh hull_dim == 4) {
+      if (k != qh DROPdim)
+        destination[i++]= source[k];
+    }else if (k == qh DROPdim)
+      destination[i++]= 0;
+    else
+      destination[i++]= source[k];
+  }
+  while (i < 3)
+    destination[i++]= 0.0;
+} /* projectdim3 */
+
+/*---------------------------------
+  
+  qh_readfeasible( dim, remainder )
+    read feasible point from remainder string and qh.fin
+
+  returns:
+    number of lines read from qh.fin
+    sets qh.FEASIBLEpoint with malloc'd coordinates
+
+  notes:
+    checks for qh.HALFspace
+    assumes dim > 1
+
+  see:
+    qh_setfeasible
+*/
+int qh_readfeasible (int dim, char *remainder) {
+  boolT isfirst= True;
+  int linecount= 0, tokcount= 0;
+  char *s, *t, firstline[qh_MAXfirst+1];
+  coordT *coords, value;
+
+  if (!qh HALFspace) {
+    fprintf  (qh ferr, "qhull input error: feasible point (dim 1 coords) is only valid for halfspace intersection\n");
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }  
+  if (qh feasible_string)
+    fprintf  (qh ferr, "qhull input warning: feasible point (dim 1 coords) overrides 'Hn,n,n' feasible point for halfspace intersection\n");
+  if (!(qh feasible_point= (coordT*)malloc (dim* sizeof(coordT)))) {
+    fprintf(qh ferr, "qhull error: insufficient memory for feasible point\n");
+    qh_errexit(qh_ERRmem, NULL, NULL);
+  }
+  coords= qh feasible_point;
+  while ((s= (isfirst ?  remainder : fgets(firstline, qh_MAXfirst, qh fin)))) {
+    if (isfirst)
+      isfirst= False;
+    else
+      linecount++;
+    while (*s) {
+      while (isspace(*s))
+        s++;
+      value= qh_strtod (s, &t);
+      if (s == t)
+        break;
+      s= t;
+      *(coords++)= value;
+      if (++tokcount == dim) {
+        while (isspace (*s))
+          s++;
+        qh_strtod (s, &t);
+        if (s != t) {
+          fprintf (qh ferr, "qhull input error: coordinates for feasible point do not finish out the line: %s\n",
+               s);
+          qh_errexit (qh_ERRinput, NULL, NULL);
+        }
+        return linecount;
+      }
+    }
+  }
+  fprintf (qh ferr, "qhull input error: only %d coordinates.  Could not read %d-d feasible point.\n",
+           tokcount, dim);
+  qh_errexit (qh_ERRinput, NULL, NULL);
+  return 0;
+} /* readfeasible */
+
+/*---------------------------------
+  
+  qh_readpoints( numpoints, dimension, ismalloc )
+    read points from qh.fin into qh.first_point, qh.num_points
+    qh.fin is lines of coordinates, one per vertex, first line number of points
+    if 'rbox D4',
+      gives message
+    if qh.ATinfinity,
+      adds point-at-infinity for Delaunay triangulations
+
+  returns:
+    number of points, array of point coordinates, dimension, ismalloc True
+    if qh.DELAUNAY & !qh.PROJECTinput, projects points to paraboloid
+        and clears qh.PROJECTdelaunay
+    if qh.HALFspace, reads optional feasible point, reads halfspaces,
+        converts to dual.
+
+  for feasible point in "cdd format" in 3-d:
+    3 1
+    coordinates
+    comments
+    begin
+    n 4 real/integer
+    ...
+    end
+
+  notes:
+    dimension will change in qh_initqhull_globals if qh.PROJECTinput
+    uses malloc() since qh_mem not initialized
+    FIXUP: this routine needs rewriting
+*/
+coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc) {
+  coordT *points, *coords, *infinity= NULL;
+  realT paraboloid, maxboloid= -REALmax, value;
+  realT *coordp= NULL, *offsetp= NULL, *normalp= NULL;
+  char *s, *t, firstline[qh_MAXfirst+1];
+  int diminput=0, numinput=0, dimfeasible= 0, newnum, k, tempi;
+  int firsttext=0, firstshort=0, firstlong=0, firstpoint=0;
+  int tokcount= 0, linecount=0, maxcount, coordcount=0;
+  boolT islong, isfirst= True, wasbegin= False;
+  boolT isdelaunay= qh DELAUNAY && !qh PROJECTinput;
+
+  if (qh CDDinput) {
+    while ((s= fgets(firstline, qh_MAXfirst, qh fin))) {
+      linecount++;
+      if (qh HALFspace && linecount == 1 && isdigit(*s)) {
+	dimfeasible= qh_strtol (s, &s);	
+	while (isspace(*s))
+          s++;
+        if (qh_strtol (s, &s) == 1)
+          linecount += qh_readfeasible (dimfeasible, s);
+        else
+          dimfeasible= 0;
+      }else if (!memcmp (firstline, "begin", 5) || !memcmp (firstline, "BEGIN", 5))
+        break;
+      else if (!*qh rbox_command)
+	strncat(qh rbox_command, s, sizeof (qh rbox_command)-1);
+    }
+    if (!s) {
+      fprintf (qh ferr, "qhull input error: missing \"begin\" for cdd-formated input\n");
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }
+  }
+  while(!numinput && (s= fgets(firstline, qh_MAXfirst, qh fin))) {
+    linecount++;
+    if (!memcmp (s, "begin", 5) || !memcmp (s, "BEGIN", 5))
+      wasbegin= True;
+    while (*s) {
+      while (isspace(*s))
+        s++;
+      if (!*s)
+        break;
+      if (!isdigit(*s)) {
+        if (!*qh rbox_command) {
+          strncat(qh rbox_command, s, sizeof (qh rbox_command)-1);
+	  firsttext= linecount;
+        }
+        break;
+      }
+      if (!diminput) 
+        diminput= qh_strtol (s, &s);
+      else {
+        numinput= qh_strtol (s, &s);
+        if (numinput == 1 && diminput >= 2 && qh HALFspace && !qh CDDinput) {
+          linecount += qh_readfeasible (diminput, s); /* checks if ok */
+          dimfeasible= diminput;
+          diminput= numinput= 0;
+        }else 
+          break;
+      }
+    }
+  }
+  if (!s) {
+    fprintf(qh ferr, "qhull input error: short input file.  Did not find dimension and number of points\n");
+    qh_errexit(qh_ERRinput, NULL, NULL);
+  }
+  if (diminput > numinput) {
+    tempi= diminput;	/* exchange dim and n, e.g., for cdd input format */
+    diminput= numinput;
+    numinput= tempi;
+  }
+  if (diminput < 2) {
+    fprintf(qh ferr,"qhull input error: dimension %d (first number) should be at least 2\n",
+	    diminput);
+    qh_errexit(qh_ERRinput, NULL, NULL);
+  }
+  if (isdelaunay) {
+    qh PROJECTdelaunay= False;
+    if (qh CDDinput)
+      *dimension= diminput;
+    else
+      *dimension= diminput+1;
+    *numpoints= numinput;
+    if (qh ATinfinity)
+      (*numpoints)++;
+  }else if (qh HALFspace) {
+    *dimension= diminput - 1;
+    *numpoints= numinput;
+    if (diminput < 3) {
+      fprintf(qh ferr,"qhull input error: dimension %d (first number, includes offset) should be at least 3 for halfspaces\n",
+  	    diminput);
+      qh_errexit(qh_ERRinput, NULL, NULL);
+    }
+    if (dimfeasible) {
+      if (dimfeasible != *dimension) {
+        fprintf(qh ferr,"qhull input error: dimension %d of feasible point is not one less than dimension %d for halfspaces\n",
+          dimfeasible, diminput);
+        qh_errexit(qh_ERRinput, NULL, NULL);
+      }
+    }else 
+      qh_setfeasible (*dimension);
+  }else {
+    if (qh CDDinput) 
+      *dimension= diminput-1;
+    else
+      *dimension= diminput;
+    *numpoints= numinput;
+  }
+  qh normal_size= *dimension * sizeof(coordT); /* for tracing with qh_printpoint */
+  if (qh HALFspace) {
+    qh half_space= coordp= (coordT*) malloc (qh normal_size + sizeof(coordT));
+    if (qh CDDinput) {
+      offsetp= qh half_space;
+      normalp= offsetp + 1;
+    }else {
+      normalp= qh half_space;
+      offsetp= normalp + *dimension;
+    }
+  } 
+  qh maxline= diminput * (qh_REALdigits + 5);
+  maximize_(qh maxline, 500);
+  qh line= (char*)malloc ((qh maxline+1) * sizeof (char));
+  *ismalloc= True;  /* use malloc since memory not setup */
+  coords= points= qh temp_malloc= 
+        (coordT*)malloc((*numpoints)*(*dimension)*sizeof(coordT));
+  if (!coords || !qh line || (qh HALFspace && !qh half_space)) {
+    fprintf(qh ferr, "qhull error: insufficient memory to read %d points\n",
+	    numinput);
+    qh_errexit(qh_ERRmem, NULL, NULL);
+  }
+  if (isdelaunay && qh ATinfinity) {
+    infinity= points + numinput * (*dimension);
+    for (k= (*dimension) - 1; k--; )
+      infinity[k]= 0.0;
+  }
+  maxcount= numinput * diminput;
+  paraboloid= 0.0;
+  while ((s= (isfirst ?  s : fgets(qh line, qh maxline, qh fin)))) {
+    if (!isfirst) {
+      linecount++;
+      if (*s == 'e' || *s == 'E') {
+	if (!memcmp (s, "end", 3) || !memcmp (s, "END", 3)) {
+	  if (qh CDDinput )
+	    break;
+	  else if (wasbegin) 
+	    fprintf (qh ferr, "qhull input warning: the input appears to be in cdd format.  If so, use 'Fd'\n");
+	}
+      }
+    }
+    islong= False;
+    while (*s) {
+      while (isspace(*s))
+        s++;
+      value= qh_strtod (s, &t);
+      if (s == t) {
+        if (!*qh rbox_command)
+ 	 strncat(qh rbox_command, s, sizeof (qh rbox_command)-1);
+        if (*s && !firsttext) 
+          firsttext= linecount;
+        if (!islong && !firstshort && coordcount)
+          firstshort= linecount;
+        break;
+      }
+      if (!firstpoint)
+	firstpoint= linecount;
+      s= t;
+      if (++tokcount > maxcount)
+        continue;
+      if (qh HALFspace) {
+	if (qh CDDinput) 
+	  *(coordp++)= -value; /* both coefficients and offset */
+	else
+	  *(coordp++)= value;
+      }else {
+        *(coords++)= value;
+        if (qh CDDinput && !coordcount) {
+          if (value != 1.0) {
+            fprintf (qh ferr, "qhull input error: for cdd format, point at line %d does not start with '1'\n",
+                   linecount);
+            qh_errexit (qh_ERRinput, NULL, NULL);
+          }
+          coords--;
+        }else if (isdelaunay) {
+	  paraboloid += value * value;
+	  if (qh ATinfinity) {
+	    if (qh CDDinput)
+	      infinity[coordcount-1] += value;
+	    else
+	      infinity[coordcount] += value;
+	  }
+	}
+      }
+      if (++coordcount == diminput) {
+        coordcount= 0;
+        if (isdelaunay) {
+          *(coords++)= paraboloid;
+          maximize_(maxboloid, paraboloid);
+          paraboloid= 0.0;
+        }else if (qh HALFspace) {
+          if (!qh_sethalfspace (*dimension, coords, &coords, normalp, offsetp, qh feasible_point)) {
+	    fprintf (qh ferr, "The halfspace was on line %d\n", linecount);
+	    if (wasbegin)
+	      fprintf (qh ferr, "The input appears to be in cdd format.  If so, you should use option 'Fd'\n");
+	    qh_errexit (qh_ERRinput, NULL, NULL);
+	  }
+          coordp= qh half_space;
+        }          
+        while (isspace(*s))
+          s++;
+        if (*s) {
+          islong= True;
+          if (!firstlong)
+            firstlong= linecount;
+	}
+      }
+    }
+    if (!islong && !firstshort && coordcount)
+      firstshort= linecount;
+    if (!isfirst && s - qh line >= qh maxline) {
+      fprintf(qh ferr, "qhull input error: line %d contained more than %d characters\n", 
+	      linecount, (int) (s - qh line));
+      qh_errexit(qh_ERRinput, NULL, NULL);
+    }
+    isfirst= False;
+  }
+  if (tokcount != maxcount) {
+    newnum= fmin_(numinput, tokcount/diminput);
+    fprintf(qh ferr,"\
+qhull warning: instead of %d %d-dimensional points, input contains\n\
+%d points and %d extra coordinates.  Line %d is the first\npoint",
+       numinput, diminput, tokcount/diminput, tokcount % diminput, firstpoint);
+    if (firsttext)
+      fprintf(qh ferr, ", line %d is the first comment", firsttext);
+    if (firstshort)
+      fprintf(qh ferr, ", line %d is the first short\nline", firstshort);
+    if (firstlong)
+      fprintf(qh ferr, ", line %d is the first long line", firstlong);
+    fprintf(qh ferr, ".  Continue with %d points.\n", newnum);
+    numinput= newnum;
+    if (isdelaunay && qh ATinfinity) {
+      for (k= tokcount % diminput; k--; )
+	infinity[k] -= *(--coords);
+      *numpoints= newnum+1;
+    }else {
+      coords -= tokcount % diminput;
+      *numpoints= newnum;
+    }
+  }
+  if (isdelaunay && qh ATinfinity) {
+    for (k= (*dimension) -1; k--; )
+      infinity[k] /= numinput;
+    if (coords == infinity)
+      coords += (*dimension) -1;
+    else {
+      for (k= 0; k < (*dimension) -1; k++)
+	*(coords++)= infinity[k];
+    }
+    *(coords++)= maxboloid * 1.1;
+  }
+  if (qh rbox_command[0]) {
+    qh rbox_command[strlen(qh rbox_command)-1]= '\0';
+    if (!strcmp (qh rbox_command, "./rbox D4")) 
+      fprintf (qh ferr, "\n\
+This is the qhull test case.  If any errors or core dumps occur,\n\
+recompile qhull with 'make new'.  If errors still occur, there is\n\
+an incompatibility.  You should try a different compiler.  You can also\n\
+change the choices in user.h.  If you discover the source of the problem,\n\
+please send mail to qhull_bug@geom.umn.edu.\n\
+\n\
+Type 'qhull' for a short list of options.\n");
+  }
+  free (qh line);
+  qh line= NULL;
+  if (qh half_space) {
+    free (qh half_space);
+    qh half_space= NULL;
+  }
+  qh temp_malloc= NULL;
+  trace1((qh ferr,"qh_readpoints: read in %d %d-dimensional points\n",
+	  numinput, diminput));
+  return(points);
+} /* readpoints */
+
+
+/*---------------------------------
+  
+  qh_setfeasible( dim )
+    set qh.FEASIBLEpoint from qh.feasible_string in "n,n,n" or "n n n" format
+
+  notes:
+    "n,n,n" already checked by qh_initflags()
+    see qh_readfeasible()
+*/
+void qh_setfeasible (int dim) {
+  int tokcount= 0;
+  char *s;
+  coordT *coords, value;
+
+  if (!(s= qh feasible_string)) {
+    fprintf(qh ferr, "\
+qhull input error: halfspace intersection needs a feasible point.\n\
+Either prepend the input with 1 point or use 'Hn,n,n'.  See manual.\n");
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }
+  if (!(qh feasible_point= (pointT*)malloc (dim* sizeof(coordT)))) {
+    fprintf(qh ferr, "qhull error: insufficient memory for 'Hn,n,n'\n");
+    qh_errexit(qh_ERRmem, NULL, NULL);
+  }
+  coords= qh feasible_point;
+  while (*s) {
+    value= qh_strtod (s, &s);
+    if (++tokcount > dim) {
+      fprintf (qh ferr, "qhull input warning: more coordinates for 'H%s' than dimension %d\n",
+          qh feasible_string, dim);
+      break;
+    }
+    *(coords++)= value;
+    if (*s)
+      s++;
+  }
+  while (++tokcount <= dim)    
+    *(coords++)= 0.0;
+} /* setfeasible */
+
+/*---------------------------------
+  
+  qh_skipfacet( facet )
+    returns 'True' if this facet is not to be printed 
+
+  notes:
+    based on the user provided slice thresholds and 'good' specifications
+*/
+boolT qh_skipfacet(facetT *facet) {
+  facetT *neighbor, **neighborp;
+
+  if (qh PRINTneighbors) {
+    if (facet->good)
+      return !qh PRINTgood;
+    FOREACHneighbor_(facet) {
+      if (neighbor->good)
+	return False;
+    }
+    return True;
+  }else if (qh PRINTgood)
+    return !facet->good;
+  else if (!facet->normal)
+    return True;
+  return (!qh_inthresholds (facet->normal, NULL));
+} /* skipfacet */
+
diff --git a/extern/qhull/src/io.h b/extern/qhull/src/io.h
new file mode 100644
index 00000000000..351d56b3708
--- /dev/null
+++ b/extern/qhull/src/io.h
@@ -0,0 +1,149 @@
+/*
  ---------------------------------
+
+   io.h 
+   declarations of Input/Output functions
+
+   see README, qhull.h and io.c
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFio
+#define qhDEFio 1
+
+/*============ constants and flags ==================*/
+
+/*----------------------------------
+  
+  qh_MAXfirst
+    maximum length of first two lines of stdin
+*/
+#define qh_MAXfirst  200
+
+/*----------------------------------
+  
+  qh_MINradius
+    min radius for Gp and Gv, fraction of maxcoord
+*/
+#define qh_MINradius 0.02
+
+/*----------------------------------
+  
+  qh_GEOMepsilon
+    adjust outer planes for 'lines closer' and geomview roundoff.  
+    This prevents bleed through.
+*/
+#define qh_GEOMepsilon 2e-3
+
+/*----------------------------------
+  
+  qh_WHITESPACE
+    possible values of white space
+*/
+#define qh_WHITESPACE " \n\t\v\r\f"
+
+
+/*----------------------------------
+  
+  qh_RIDGE
+    to select which ridges to print in qh_eachvoronoi
+*/
+typedef enum
+{
+    qh_RIDGEall = 0, qh_RIDGEinner, qh_RIDGEouter
+}
+qh_RIDGE;
+
+/*----------------------------------
+  
+  printvridgeT
+    prints results of qh_printvdiagram
+
+  see:
+    qh_printvridge for an example
+*/
+typedef void (*printvridgeT)(FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
+
+/*============== -prototypes in alphabetical order =========*/
+
+void    dfacet( unsigned id);
+void    dvertex( unsigned id);
+void    qh_countfacets (facetT *facetlist, setT *facets, boolT printall, 
+              int *numfacetsp, int *numsimplicialp, int *totneighborsp, 
+              int *numridgesp, int *numcoplanarsp, int *numnumtricoplanarsp);
+pointT *qh_detvnorm (vertexT *vertex, vertexT *vertexA, setT *centers, realT *offsetp);
+setT   *qh_detvridge (vertexT *vertex);
+setT   *qh_detvridge3 (vertexT *atvertex, vertexT *vertex);
+int     qh_eachvoronoi (FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder);
+int     qh_eachvoronoi_all (FILE *fp, printvridgeT printvridge, boolT isupper, qh_RIDGE innerouter, boolT inorder);
+void	qh_facet2point(facetT *facet, pointT **point0, pointT **point1, realT *mindist);
+setT   *qh_facetvertices (facetT *facetlist, setT *facets, boolT allfacets);
+void    qh_geomplanes (facetT *facet, realT *outerplane, realT *innerplane);
+void    qh_markkeep (facetT *facetlist);
+setT   *qh_markvoronoi (facetT *facetlist, setT *facets, boolT printall, boolT *islowerp, int *numcentersp);
+void    qh_order_vertexneighbors(vertexT *vertex);
+void	qh_printafacet(FILE *fp, int format, facetT *facet, boolT printall);
+void    qh_printbegin (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall);
+void 	qh_printcenter (FILE *fp, int format, char *string, facetT *facet);
+void    qh_printcentrum (FILE *fp, facetT *facet, realT radius);
+void    qh_printend (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall);
+void    qh_printend4geom (FILE *fp, facetT *facet, int *num, boolT printall);
+void    qh_printextremes (FILE *fp, facetT *facetlist, setT *facets, int printall);
+void    qh_printextremes_2d (FILE *fp, facetT *facetlist, setT *facets, int printall);
+void    qh_printextremes_d (FILE *fp, facetT *facetlist, setT *facets, int printall);
+void	qh_printfacet(FILE *fp, facetT *facet);
+void	qh_printfacet2math(FILE *fp, facetT *facet, int notfirst);
+void	qh_printfacet2geom(FILE *fp, facetT *facet, realT color[3]);
+void    qh_printfacet2geom_points(FILE *fp, pointT *point1, pointT *point2,
+			       facetT *facet, realT offset, realT color[3]);
+void	qh_printfacet3math (FILE *fp, facetT *facet, int notfirst);
+void	qh_printfacet3geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]);
+void	qh_printfacet3geom_points(FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]);
+void	qh_printfacet3geom_simplicial(FILE *fp, facetT *facet, realT color[3]);
+void	qh_printfacet3vertex(FILE *fp, facetT *facet, int format);
+void	qh_printfacet4geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]);
+void	qh_printfacet4geom_simplicial(FILE *fp, facetT *facet, realT color[3]);
+void	qh_printfacetNvertex_nonsimplicial(FILE *fp, facetT *facet, int id, int format);
+void	qh_printfacetNvertex_simplicial(FILE *fp, facetT *facet, int format);
+void    qh_printfacetheader(FILE *fp, facetT *facet);
+void    qh_printfacetridges(FILE *fp, facetT *facet);
+void	qh_printfacets(FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall);
+void	qh_printhelp_degenerate(FILE *fp);
+void	qh_printhelp_singular(FILE *fp);
+void	qh_printhyperplaneintersection(FILE *fp, facetT *facet1, facetT *facet2,
+  		   setT *vertices, realT color[3]);
+void	qh_printneighborhood (FILE *fp, int format, facetT *facetA, facetT *facetB, boolT printall);
+void    qh_printline3geom (FILE *fp, pointT *pointA, pointT *pointB, realT color[3]);
+void	qh_printpoint(FILE *fp, char *string, pointT *point);
+void	qh_printpointid(FILE *fp, char *string, int dim, pointT *point, int id);
+void    qh_printpoint3 (FILE *fp, pointT *point);
+void    qh_printpoints_out (FILE *fp, facetT *facetlist, setT *facets, int printall);
+void    qh_printpointvect (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]);
+void    qh_printpointvect2 (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius);
+void	qh_printridge(FILE *fp, ridgeT *ridge);
+void    qh_printspheres(FILE *fp, setT *vertices, realT radius);
+void    qh_printvdiagram (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall);
+int     qh_printvdiagram2 (FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder);
+void	qh_printvertex(FILE *fp, vertexT *vertex);
+void	qh_printvertexlist (FILE *fp, char* string, facetT *facetlist,
+                         setT *facets, boolT printall);
+void	qh_printvertices (FILE *fp, char* string, setT *vertices);
+void    qh_printvneighbors (FILE *fp, facetT* facetlist, setT *facets, boolT printall);
+void    qh_printvoronoi (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall);
+void    qh_printvnorm (FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
+void    qh_printvridge (FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
+void	qh_produce_output(void);
+void    qh_projectdim3 (pointT *source, pointT *destination);
+int     qh_readfeasible (int dim, char *remainder);
+coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc);
+void    qh_setfeasible (int dim);
+boolT	qh_skipfacet(facetT *facet);
+
+#endif /* qhDEFio */
diff --git a/extern/qhull/src/mem.c b/extern/qhull/src/mem.c
new file mode 100644
index 00000000000..72934626684
--- /dev/null
+++ b/extern/qhull/src/mem.c
@@ -0,0 +1,447 @@
+/*
  ---------------------------------
+
+  mem.c 
+    memory management routines for qhull
+
+  This is a standalone program.
+   
+  To initialize memory:
+
+    qh_meminit (stderr);  
+    qh_meminitbuffers (qh IStracing, qh_MEMalign, 7, qh_MEMbufsize,qh_MEMinitbuf);
+    qh_memsize(sizeof(facetT));
+    qh_memsize(sizeof(facetT));
+    ...
+    qh_memsetup();
+    
+  To free up all memory buffers:
+    qh_memfreeshort (&curlong, &totlong);
+         
+  if qh_NOmem, 
+    malloc/free is used instead of mem.c
+
+  notes: 
+    uses Quickfit algorithm (freelists for commonly allocated sizes)
+    assumes small sizes for freelists (it discards the tail of memory buffers)
+   
+  see:
+    qh-mem.htm and mem.h
+    global.c (qh_initbuffers) for an example of using mem.c 
+   
+  copyright (c) 1993-2002 The Geometry Center
+*/
+
+#include 
+#include 
+#include 
+#include "mem.h"
+
+#ifndef qhDEFqhull
+typedef struct ridgeT ridgeT;
+typedef struct facetT facetT;
+void    qh_errexit(int exitcode, facetT *, ridgeT *);
+#endif
+
+/*============ -global data structure ==============
+    see mem.h for definition
+*/
+
+qhmemT qhmem= {0};     /* remove "= {0}" if this causes a compiler error */
+
+#ifndef qh_NOmem
+
+/*============= internal functions ==============*/
+  
+static int qh_intcompare(const void *i, const void *j);
+
+/*========== functions in alphabetical order ======== */
+
+/*---------------------------------
+  
+  qh_intcompare( i, j )
+    used by qsort and bsearch to compare two integers
+*/
+static int qh_intcompare(const void *i, const void *j) {
+  return(*((int *)i) - *((int *)j));
+} /* intcompare */
+
+
+/*----------------------------------
+   
+  qh_memalloc( insize )  
+    returns object of insize bytes
+    qhmem is the global memory structure 
+    
+  returns:
+    pointer to allocated memory 
+    errors if insufficient memory
+
+  notes:
+    use explicit type conversion to avoid type warnings on some compilers
+    actual object may be larger than insize
+    use qh_memalloc_() for inline code for quick allocations
+    logs allocations if 'T5'
+  
+  design:
+    if size < qhmem.LASTsize
+      if qhmem.freelists[size] non-empty
+        return first object on freelist
+      else
+        round up request to size of qhmem.freelists[size]
+        allocate new allocation buffer if necessary
+        allocate object from allocation buffer
+    else
+      allocate object with malloc()
+*/
+void *qh_memalloc(int insize) {
+  void **freelistp, *newbuffer;
+  int index, size;
+  int outsize, bufsize;
+  void *object;
+
+  if ((unsigned) insize <= (unsigned) qhmem.LASTsize) {
+    index= qhmem.indextable[insize];
+    freelistp= qhmem.freelists+index;
+    if ((object= *freelistp)) {
+      qhmem.cntquick++;  
+      *freelistp= *((void **)*freelistp);  /* replace freelist with next object */
+      return (object);
+    }else {
+      outsize= qhmem.sizetable[index];
+      qhmem.cntshort++;
+      if (outsize > qhmem .freesize) {
+	if (!qhmem.curbuffer)
+	  bufsize= qhmem.BUFinit;
+        else
+	  bufsize= qhmem.BUFsize;
+        qhmem.totshort += bufsize;
+	if (!(newbuffer= malloc(bufsize))) {
+	  fprintf(qhmem.ferr, "qhull error (qh_memalloc): insufficient memory\n");
+	  qh_errexit(qhmem_ERRmem, NULL, NULL);
+	} 
+	*((void **)newbuffer)= qhmem.curbuffer;  /* prepend newbuffer to curbuffer 
+						    list */
+	qhmem.curbuffer= newbuffer;
+        size= (sizeof(void **) + qhmem.ALIGNmask) & ~qhmem.ALIGNmask;
+	qhmem.freemem= (void *)((char *)newbuffer+size);
+	qhmem.freesize= bufsize - size;
+      }
+      object= qhmem.freemem;
+      qhmem.freemem= (void *)((char *)qhmem.freemem + outsize);
+      qhmem.freesize -= outsize;
+      return object;
+    }
+  }else {                     /* long allocation */
+    if (!qhmem.indextable) {
+      fprintf (qhmem.ferr, "qhull internal error (qh_memalloc): qhmem has not been initialized.\n");
+      qh_errexit(qhmem_ERRqhull, NULL, NULL);
+    }
+    outsize= insize;
+    qhmem .cntlong++;
+    qhmem .curlong++;
+    qhmem .totlong += outsize;
+    if (qhmem.maxlong < qhmem.totlong)
+      qhmem.maxlong= qhmem.totlong;
+    if (!(object= malloc(outsize))) {
+      fprintf(qhmem.ferr, "qhull error (qh_memalloc): insufficient memory\n");
+      qh_errexit(qhmem_ERRmem, NULL, NULL);
+    }
+    if (qhmem.IStracing >= 5)
+      fprintf (qhmem.ferr, "qh_memalloc long: %d bytes at %p\n", outsize, object);
+  }
+  return (object);
+} /* memalloc */
+
+
+/*----------------------------------
+   
+  qh_memfree( object, size ) 
+    free up an object of size bytes
+    size is insize from qh_memalloc
+
+  notes:
+    object may be NULL
+    type checking warns if using (void **)object
+    use qh_memfree_() for quick free's of small objects
+ 
+  design:
+    if size <= qhmem.LASTsize
+      append object to corresponding freelist
+    else
+      call free(object)
+*/
+void qh_memfree(void *object, int size) {
+  void **freelistp;
+
+  if (!object)
+    return;
+  if (size <= qhmem.LASTsize) {
+    qhmem .freeshort++;
+    freelistp= qhmem.freelists + qhmem.indextable[size];
+    *((void **)object)= *freelistp;
+    *freelistp= object;
+  }else {
+    qhmem .freelong++;
+    qhmem .totlong -= size;
+    free (object);
+    if (qhmem.IStracing >= 5)
+      fprintf (qhmem.ferr, "qh_memfree long: %d bytes at %p\n", size, object);
+  }
+} /* memfree */
+
+
+/*---------------------------------
+  
+  qh_memfreeshort( curlong, totlong )
+    frees up all short and qhmem memory allocations
+
+  returns:
+    number and size of current long allocations
+*/
+void qh_memfreeshort (int *curlong, int *totlong) {
+  void *buffer, *nextbuffer;
+
+  *curlong= qhmem .cntlong - qhmem .freelong;
+  *totlong= qhmem .totlong;
+  for(buffer= qhmem.curbuffer; buffer; buffer= nextbuffer) {
+    nextbuffer= *((void **) buffer);
+    free(buffer);
+  }
+  qhmem.curbuffer= NULL;
+  if (qhmem .LASTsize) {
+    free (qhmem .indextable);
+    free (qhmem .freelists);
+    free (qhmem .sizetable);
+  }
+  memset((char *)&qhmem, 0, sizeof qhmem);  /* every field is 0, FALSE, NULL */
+} /* memfreeshort */
+
+
+/*----------------------------------
+   
+  qh_meminit( ferr )
+    initialize qhmem and test sizeof( void*)
+*/
+void qh_meminit (FILE *ferr) {
+  
+  memset((char *)&qhmem, 0, sizeof qhmem);  /* every field is 0, FALSE, NULL */
+  qhmem.ferr= ferr;
+  if (sizeof(void*) < sizeof(int)) {
+    fprintf (ferr, "qhull internal error (qh_meminit): sizeof(void*) < sizeof(int).  qset.c will not work\n");
+    exit (1);  /* can not use qh_errexit() */
+  }
+} /* meminit */
+
+/*---------------------------------
+  
+  qh_meminitbuffers( tracelevel, alignment, numsizes, bufsize, bufinit )
+    initialize qhmem
+    if tracelevel >= 5, trace memory allocations
+    alignment= desired address alignment for memory allocations
+    numsizes= number of freelists
+    bufsize=  size of additional memory buffers for short allocations
+    bufinit=  size of initial memory buffer for short allocations
+*/
+void qh_meminitbuffers (int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) {
+
+  qhmem.IStracing= tracelevel;
+  qhmem.NUMsizes= numsizes;
+  qhmem.BUFsize= bufsize;
+  qhmem.BUFinit= bufinit;
+  qhmem.ALIGNmask= alignment-1;
+  if (qhmem.ALIGNmask & ~qhmem.ALIGNmask) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_meminit): memory alignment %d is not a power of 2\n", alignment);
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+  qhmem.sizetable= (int *) calloc (numsizes, sizeof(int));
+  qhmem.freelists= (void **) calloc (numsizes, sizeof(void *));
+  if (!qhmem.sizetable || !qhmem.freelists) {
+    fprintf(qhmem.ferr, "qhull error (qh_meminit): insufficient memory\n");
+    qh_errexit (qhmem_ERRmem, NULL, NULL);
+  }
+  if (qhmem.IStracing >= 1)
+    fprintf (qhmem.ferr, "qh_meminitbuffers: memory initialized with alignment %d\n", alignment);
+} /* meminitbuffers */
+
+/*---------------------------------
+  
+  qh_memsetup()
+    set up memory after running memsize()
+*/
+void qh_memsetup (void) {
+  int k,i;
+
+  qsort(qhmem.sizetable, qhmem.TABLEsize, sizeof(int), qh_intcompare);
+  qhmem.LASTsize= qhmem.sizetable[qhmem.TABLEsize-1];
+  if (qhmem .LASTsize >= qhmem .BUFsize || qhmem.LASTsize >= qhmem .BUFinit) {
+    fprintf (qhmem.ferr, "qhull error (qh_memsetup): largest mem size %d is >= buffer size %d or initial buffer size %d\n",
+            qhmem .LASTsize, qhmem .BUFsize, qhmem .BUFinit);
+    qh_errexit(qhmem_ERRmem, NULL, NULL);
+  }
+  if (!(qhmem.indextable= (int *)malloc((qhmem.LASTsize+1) * sizeof(int)))) {
+    fprintf(qhmem.ferr, "qhull error (qh_memsetup): insufficient memory\n");
+    qh_errexit(qhmem_ERRmem, NULL, NULL);
+  }
+  for(k=qhmem.LASTsize+1; k--; )
+    qhmem.indextable[k]= k;
+  i= 0;
+  for(k= 0; k <= qhmem.LASTsize; k++) {
+    if (qhmem.indextable[k] <= qhmem.sizetable[i])
+      qhmem.indextable[k]= i;
+    else
+      qhmem.indextable[k]= ++i;
+  }
+} /* memsetup */
+
+/*---------------------------------
+  
+  qh_memsize( size )
+    define a free list for this size
+*/
+void qh_memsize(int size) {
+  int k;
+
+  if (qhmem .LASTsize) {
+    fprintf (qhmem .ferr, "qhull error (qh_memsize): called after qhmem_setup\n");
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+  size= (size + qhmem.ALIGNmask) & ~qhmem.ALIGNmask;
+  for(k= qhmem.TABLEsize; k--; ) {
+    if (qhmem.sizetable[k] == size)
+      return;
+  }
+  if (qhmem.TABLEsize < qhmem.NUMsizes)
+    qhmem.sizetable[qhmem.TABLEsize++]= size;
+  else
+    fprintf(qhmem.ferr, "qhull warning (memsize): free list table has room for only %d sizes\n", qhmem.NUMsizes);
+} /* memsize */
+
+
+/*---------------------------------
+  
+  qh_memstatistics( fp )
+    print out memory statistics
+
+  notes:
+    does not account for wasted memory at the end of each block
+*/
+void qh_memstatistics (FILE *fp) {
+  int i, count, totfree= 0;
+  void *object;
+  
+  for (i=0; i < qhmem.TABLEsize; i++) {
+    count=0;
+    for (object= qhmem .freelists[i]; object; object= *((void **)object))
+      count++;
+    totfree += qhmem.sizetable[i] * count;
+  }
+  fprintf (fp, "\nmemory statistics:\n\
+%7d quick allocations\n\
+%7d short allocations\n\
+%7d long allocations\n\
+%7d short frees\n\
+%7d long frees\n\
+%7d bytes of short memory in use\n\
+%7d bytes of short memory in freelists\n\
+%7d bytes of long memory allocated (except for input)\n\
+%7d bytes of long memory in use (in %d pieces)\n\
+%7d bytes per memory buffer (initially %d bytes)\n",
+	   qhmem .cntquick, qhmem.cntshort, qhmem.cntlong,
+	   qhmem .freeshort, qhmem.freelong, 
+	   qhmem .totshort - qhmem .freesize - totfree,
+	   totfree,
+	   qhmem .maxlong, qhmem .totlong, qhmem .cntlong - qhmem .freelong,
+	   qhmem .BUFsize, qhmem .BUFinit);
+  if (qhmem.cntlarger) {
+    fprintf (fp, "%7d calls to qh_setlarger\n%7.2g     average copy size\n",
+	   qhmem.cntlarger, ((float) qhmem.totlarger)/ qhmem.cntlarger);
+    fprintf (fp, "  freelists (bytes->count):");
+  }
+  for (i=0; i < qhmem.TABLEsize; i++) {
+    count=0;
+    for (object= qhmem .freelists[i]; object; object= *((void **)object))
+      count++;
+    fprintf (fp, " %d->%d", qhmem.sizetable[i], count);
+  }
+  fprintf (fp, "\n\n");
+} /* memstatistics */
+
+
+/*---------------------------------
+  
+  qh_NOmem
+    turn off quick-fit memory allocation
+
+  notes:
+    uses malloc() and free() instead
+*/
+#else /* qh_NOmem */
+
+void *qh_memalloc(int insize) {
+  void *object;
+
+  if (!(object= malloc(insize))) {
+    fprintf(qhmem.ferr, "qhull error (qh_memalloc): insufficient memory\n");
+    qh_errexit(qhmem_ERRmem, NULL, NULL);
+  }
+  if (qhmem.IStracing >= 5)
+    fprintf (qhmem.ferr, "qh_memalloc long: %d bytes at %p\n", insize, object);
+  return object;
+}
+
+void qh_memfree(void *object, int size) {
+
+  if (!object)
+    return;
+  free (object);
+  if (qhmem.IStracing >= 5)
+    fprintf (qhmem.ferr, "qh_memfree long: %d bytes at %p\n", size, object);
+}
+
+void qh_memfreeshort (int *curlong, int *totlong) {
+
+  memset((char *)&qhmem, 0, sizeof qhmem);  /* every field is 0, FALSE, NULL */
+  *curlong= 0;
+  *totlong= 0;
+}
+
+void qh_meminit (FILE *ferr) {
+
+  memset((char *)&qhmem, 0, sizeof qhmem);  /* every field is 0, FALSE, NULL */
+  qhmem.ferr= ferr;
+  if (sizeof(void*) < sizeof(int)) {
+    fprintf (ferr, "qhull internal error (qh_meminit): sizeof(void*) < sizeof(int).  qset.c will not work\n");
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+}
+
+void qh_meminitbuffers (int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) {
+
+  qhmem.IStracing= tracelevel;
+
+}
+
+void qh_memsetup (void) {
+
+}
+
+void qh_memsize(int size) {
+
+}
+
+void qh_memstatistics (FILE *fp) {
+
+}
+
+#endif /* qh_NOmem */
diff --git a/extern/qhull/src/mem.h b/extern/qhull/src/mem.h
new file mode 100644
index 00000000000..e9ebd1bb9bc
--- /dev/null
+++ b/extern/qhull/src/mem.h
@@ -0,0 +1,174 @@
+/*
  ---------------------------------
+
+   mem.h 
+     prototypes for memory management functions
+
+   see qh-mem.htm, mem.c and qset.h
+
+   for error handling, writes message and calls
+     qh_errexit (qhmem_ERRmem, NULL, NULL) if insufficient memory
+       and
+     qh_errexit (qhmem_ERRqhull, NULL, NULL) otherwise
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFmem
+#define qhDEFmem
+
+/*---------------------------------
+  
+  qh_NOmem
+    turn off quick-fit memory allocation
+
+  notes:
+    mem.c implements Quickfit memory allocation for about 20% time
+    savings.  If it fails on your machine, try to locate the
+    problem, and send the answer to qhull@geom.umn.edu.  If this can
+    not be done, define qh_NOmem to use malloc/free instead.
+
+   #define qh_NOmem
+*/
+
+/*-------------------------------------------
+    to avoid bus errors, memory allocation must consider alignment requirements.
+    malloc() automatically takes care of alignment.   Since mem.c manages
+    its own memory, we need to explicitly specify alignment in
+    qh_meminitbuffers().
+
+    A safe choice is sizeof(double).  sizeof(float) may be used if doubles 
+    do not occur in data structures and pointers are the same size.  Be careful
+    of machines (e.g., DEC Alpha) with large pointers.  If gcc is available, 
+    use __alignof__(double) or fmax_(__alignof__(float), __alignof__(void *)).
+
+   see qh_MEMalign in user.h for qhull's alignment
+*/
+
+#define qhmem_ERRmem 4    /* matches qh_ERRmem in qhull.h */
+#define qhmem_ERRqhull 5  /* matches qh_ERRqhull in qhull.h */
+
+/*----------------------------------
+  
+  ptr_intT
+    for casting a void* to an integer-type
+  
+  notes:
+    On 64-bit machines, a pointer may be larger than an 'int'.  
+    qh_meminit() checks that 'long' holds a 'void*'
+*/
+typedef unsigned long ptr_intT;
+
+/*----------------------------------
+ 
+  qhmemT
+    global memory structure for mem.c
+ 
+ notes:
+   users should ignore qhmem except for writing extensions
+   qhmem is allocated in mem.c 
+   
+   qhmem could be swapable like qh and qhstat, but then
+   multiple qh's and qhmem's would need to keep in synch.  
+   A swapable qhmem would also waste memory buffers.  As long
+   as memory operations are atomic, there is no problem with
+   multiple qh structures being active at the same time.
+   If you need separate address spaces, you can swap the
+   contents of qhmem.
+*/
+typedef struct qhmemT qhmemT;
+extern qhmemT qhmem; 
+
+struct qhmemT {               /* global memory management variables */
+  int      BUFsize;	      /* size of memory allocation buffer */
+  int      BUFinit;	      /* initial size of memory allocation buffer */
+  int      TABLEsize;         /* actual number of sizes in free list table */
+  int      NUMsizes;          /* maximum number of sizes in free list table */
+  int      LASTsize;          /* last size in free list table */
+  int      ALIGNmask;         /* worst-case alignment, must be 2^n-1 */
+  void	 **freelists;          /* free list table, linked by offset 0 */
+  int     *sizetable;         /* size of each freelist */
+  int     *indextable;        /* size->index table */
+  void    *curbuffer;         /* current buffer, linked by offset 0 */
+  void    *freemem;           /*   free memory in curbuffer */
+  int 	   freesize;          /*   size of free memory in bytes */
+  void 	  *tempstack;         /* stack of temporary memory, managed by users */
+  FILE    *ferr;              /* file for reporting errors */
+  int      IStracing;         /* =5 if tracing memory allocations */
+  int      cntquick;          /* count of quick allocations */
+                              /* remove statistics doesn't effect speed */
+  int      cntshort;          /* count of short allocations */
+  int      cntlong;           /* count of long allocations */
+  int      curlong;           /* current count of inuse, long allocations */
+  int      freeshort;	      /* count of short memfrees */
+  int      freelong;	      /* count of long memfrees */
+  int      totshort;          /* total size of short allocations */
+  int      totlong;           /* total size of long allocations */
+  int      maxlong;           /* maximum totlong */
+  int      cntlarger;         /* count of setlarger's */
+  int      totlarger;         /* total copied by setlarger */
+};
+
+
+/*==================== -macros ====================*/
+
+/*----------------------------------
+   
+  qh_memalloc_(size, object, type)  
+    returns object of size bytes 
+	assumes size<=qhmem.LASTsize and void **freelistp is a temp
+*/
+
+#ifdef qh_NOmem
+#define qh_memalloc_(size, freelistp, object, type) {\
+  object= (type*)qh_memalloc (size); }
+#else /* !qh_NOmem */
+
+#define qh_memalloc_(size, freelistp, object, type) {\
+  freelistp= qhmem.freelists + qhmem.indextable[size];\
+  if ((object= (type*)*freelistp)) {\
+    qhmem.cntquick++;  \
+    *freelistp= *((void **)*freelistp);\
+  }else object= (type*)qh_memalloc (size);}
+#endif
+
+/*----------------------------------
+   
+  qh_memfree_(object, size) 
+    free up an object
+
+  notes:
+    object may be NULL
+    assumes size<=qhmem.LASTsize and void **freelistp is a temp
+*/
+#ifdef qh_NOmem
+#define qh_memfree_(object, size, freelistp) {\
+  qh_memfree (object, size); }
+#else /* !qh_NOmem */
+
+#define qh_memfree_(object, size, freelistp) {\
+  if (object) { \
+    qhmem .freeshort++;\
+    freelistp= qhmem.freelists + qhmem.indextable[size];\
+    *((void **)object)= *freelistp;\
+    *freelistp= object;}}
+#endif
+
+/*=============== prototypes in alphabetical order ============*/
+
+void *qh_memalloc(int insize);
+void qh_memfree (void *object, int size);
+void qh_memfreeshort (int *curlong, int *totlong);
+void qh_meminit (FILE *ferr);
+void qh_meminitbuffers (int tracelevel, int alignment, int numsizes,
+			int bufsize, int bufinit);
+void qh_memsetup (void);
+void qh_memsize(int size);
+void qh_memstatistics (FILE *fp);
+
+#endif /* qhDEFmem */
diff --git a/extern/qhull/src/merge.c b/extern/qhull/src/merge.c
new file mode 100644
index 00000000000..34ecda1865f
--- /dev/null
+++ b/extern/qhull/src/merge.c
@@ -0,0 +1,3626 @@
+/*
  ---------------------------------
+
+   merge.c 
+   merges non-convex facets
+
+   see qh-merge.htm and merge.h
+
+   other modules call qh_premerge() and qh_postmerge()
+
+   the user may call qh_postmerge() to perform additional merges.
+
+   To remove deleted facets and vertices (qhull() in qhull.c):
+     qh_partitionvisible (!qh_ALL, &numoutside);  // visible_list, newfacet_list
+     qh_deletevisible ();         // qh.visible_list
+     qh_resetlists (False, qh_RESETvisible);       // qh.visible_list newvertex_list newfacet_list 
+
+   assumes qh.CENTERtype= centrum
+
+   merges occur in qh_mergefacet and in qh_mergecycle
+   vertex->neighbors not set until the first merge occurs
+
+   copyright (c) 1993-2002 The Geometry Center        
+*/
+
+#include "qhull_a.h"
+
+#ifndef qh_NOmerge
+
+/*=========== internal prototypes =========*/
+
+static int qh_compareangle(const void *p1, const void *p2);
+static int qh_comparemerge(const void *p1, const void *p2);
+static int qh_comparevisit (const void *p1, const void *p2);
+
+																														
+/*===== functions (alphabetical after premerge and postmerge) ======*/
+
+/*---------------------------------
+  
+  qh_premerge( apex, maxcentrum )
+    pre-merge nonconvex facets in qh.newfacet_list for apex
+    maxcentrum defines coplanar and concave (qh_test_appendmerge)
+
+  returns:
+    deleted facets added to qh.visible_list with facet->visible set
+
+  notes:
+    uses globals, qh.MERGEexact, qh.PREmerge
+
+  design:
+    mark duplicate ridges in qh.newfacet_list
+    merge facet cycles in qh.newfacet_list
+    merge duplicate ridges and concave facets in qh.newfacet_list
+    check merged facet cycles for degenerate and redundant facets
+    merge degenerate and redundant facets
+    collect coplanar and concave facets
+    merge concave, coplanar, degenerate, and redundant facets
+*/
+void qh_premerge (vertexT *apex, realT maxcentrum, realT maxangle) {
+  boolT othermerge= False;
+  facetT *newfacet;
+  
+  if (qh ZEROcentrum && qh_checkzero(!qh_ALL))
+    return;    
+  trace2((qh ferr, "qh_premerge: premerge centrum %2.2g angle %2.2g for apex v%d facetlist f%d\n",
+	    maxcentrum, maxangle, apex->id, getid_(qh newfacet_list)));
+  if (qh IStracing >= 4 && qh num_facets < 50)
+    qh_printlists();
+  qh centrum_radius= maxcentrum;
+  qh cos_max= maxangle;
+  qh degen_mergeset= qh_settemp (qh TEMPsize);
+  qh facet_mergeset= qh_settemp (qh TEMPsize);
+  if (qh hull_dim >=3) { 
+    qh_mark_dupridges (qh newfacet_list); /* facet_mergeset */
+    qh_mergecycle_all (qh newfacet_list, &othermerge);
+    qh_forcedmerges (&othermerge /* qh facet_mergeset */); 
+    FORALLnew_facets {  /* test samecycle merges */
+      if (!newfacet->simplicial && !newfacet->mergeridge)
+	qh_degen_redundant_neighbors (newfacet, NULL);
+    }
+    if (qh_merge_degenredundant())
+      othermerge= True;
+  }else /* qh hull_dim == 2 */
+    qh_mergecycle_all (qh newfacet_list, &othermerge);
+  qh_flippedmerges (qh newfacet_list, &othermerge);
+  if (!qh MERGEexact || zzval_(Ztotmerge)) {
+    zinc_(Zpremergetot);
+    qh POSTmerging= False;
+    qh_getmergeset_initial (qh newfacet_list);
+    qh_all_merges (othermerge, False);
+  }
+  qh_settempfree(&qh facet_mergeset);
+  qh_settempfree(&qh degen_mergeset);
+} /* premerge */
+  
+/*---------------------------------
+  
+  qh_postmerge( reason, maxcentrum, maxangle, vneighbors )
+    post-merge nonconvex facets as defined by maxcentrum and maxangle
+    'reason' is for reporting progress
+    if vneighbors, 
+      calls qh_test_vneighbors at end of qh_all_merge 
+    if firstmerge, 
+      calls qh_reducevertices before qh_getmergeset
+
+  returns:
+    if first call (qh.visible_list != qh.facet_list), 
+      builds qh.facet_newlist, qh.newvertex_list
+    deleted facets added to qh.visible_list with facet->visible
+    qh.visible_list == qh.facet_list
+
+  notes:
+
+
+  design:
+    if first call
+      set qh.visible_list and qh.newfacet_list to qh.facet_list
+      add all facets to qh.newfacet_list
+      mark non-simplicial facets, facet->newmerge
+      set qh.newvertext_list to qh.vertex_list
+      add all vertices to qh.newvertex_list
+      if a pre-merge occured
+        set vertex->delridge {will retest the ridge}
+        if qh.MERGEexact
+          call qh_reducevertices()
+      if no pre-merging 
+        merge flipped facets
+    determine non-convex facets
+    merge all non-convex facets
+*/
+void qh_postmerge (char *reason, realT maxcentrum, realT maxangle, 
+                      boolT vneighbors) {
+  facetT *newfacet;
+  boolT othermerges= False;
+  vertexT *vertex;
+
+  if (qh REPORTfreq || qh IStracing) {
+    qh_buildtracing (NULL, NULL);
+    qh_printsummary (qh ferr);
+    if (qh PRINTstatistics) 
+      qh_printallstatistics (qh ferr, "reason");
+    fprintf (qh ferr, "\n%s with 'C%.2g' and 'A%.2g'\n", 
+        reason, maxcentrum, maxangle);
+  }
+  trace2((qh ferr, "qh_postmerge: postmerge.  test vneighbors? %d\n",
+	    vneighbors));
+  qh centrum_radius= maxcentrum;
+  qh cos_max= maxangle;
+  qh POSTmerging= True;
+  qh degen_mergeset= qh_settemp (qh TEMPsize);
+  qh facet_mergeset= qh_settemp (qh TEMPsize);
+  if (qh visible_list != qh facet_list) {  /* first call */
+    qh NEWfacets= True;
+    qh visible_list= qh newfacet_list= qh facet_list;
+    FORALLnew_facets {
+      newfacet->newfacet= True;
+       if (!newfacet->simplicial)
+        newfacet->newmerge= True;
+     zinc_(Zpostfacets);
+    }
+    qh newvertex_list= qh vertex_list;
+    FORALLvertices
+      vertex->newlist= True;
+    if (qh VERTEXneighbors) { /* a merge has occurred */
+      FORALLvertices
+	vertex->delridge= True; /* test for redundant, needed? */
+      if (qh MERGEexact) {
+	if (qh hull_dim <= qh_DIMreduceBuild)
+	  qh_reducevertices(); /* was skipped during pre-merging */
+      }
+    }
+    if (!qh PREmerge && !qh MERGEexact) 
+      qh_flippedmerges (qh newfacet_list, &othermerges);
+  }
+  qh_getmergeset_initial (qh newfacet_list);
+  qh_all_merges (False, vneighbors);
+  qh_settempfree(&qh facet_mergeset);
+  qh_settempfree(&qh degen_mergeset);
+} /* post_merge */
+
+/*---------------------------------
+  
+  qh_all_merges( othermerge, vneighbors )
+    merge all non-convex facets
+    
+    set othermerge if already merged facets (for qh_reducevertices)
+    if vneighbors
+      tests vertex neighbors for convexity at end
+    qh.facet_mergeset lists the non-convex ridges in qh_newfacet_list
+    qh.degen_mergeset is defined
+    if qh.MERGEexact && !qh.POSTmerging, 
+      does not merge coplanar facets
+
+  returns:
+    deleted facets added to qh.visible_list with facet->visible
+    deleted vertices added qh.delvertex_list with vertex->delvertex
+  
+  notes:
+    unless !qh.MERGEindependent, 
+      merges facets in independent sets
+    uses qh.newfacet_list as argument since merges call qh_removefacet()
+
+  design:
+    while merges occur
+      for each merge in qh.facet_mergeset
+        unless one of the facets was already merged in this pass
+          merge the facets
+        test merged facets for additional merges
+        add merges to qh.facet_mergeset
+      if vertices record neighboring facets
+        rename redundant vertices
+          update qh.facet_mergeset
+    if vneighbors ??
+      tests vertex neighbors for convexity at end
+*/
+void qh_all_merges (boolT othermerge, boolT vneighbors) {
+  facetT *facet1, *facet2;
+  mergeT *merge;
+  boolT wasmerge= True, isreduce;
+  void **freelistp;  /* used !qh_NOmem */
+  vertexT *vertex;
+  mergeType mergetype;
+  int numcoplanar=0, numconcave=0, numdegenredun= 0, numnewmerges= 0;
+  
+  trace2((qh ferr, "qh_all_merges: starting to merge facets beginning from f%d\n",
+	    getid_(qh newfacet_list)));
+  while (True) {
+    wasmerge= False;
+    while (qh_setsize (qh facet_mergeset)) {
+      while ((merge= (mergeT*)qh_setdellast(qh facet_mergeset))) {
+	facet1= merge->facet1;
+	facet2= merge->facet2;
+	mergetype= merge->type;
+	qh_memfree_(merge, sizeof(mergeT), freelistp);
+	if (facet1->visible || facet2->visible) /*deleted facet*/
+	  continue;  
+	if ((facet1->newfacet && !facet1->tested)
+	        || (facet2->newfacet && !facet2->tested)) {
+	  if (qh MERGEindependent && mergetype <= MRGanglecoplanar)
+	    continue;      /* perform independent sets of merges */
+	}
+	qh_merge_nonconvex (facet1, facet2, mergetype);
+        numdegenredun += qh_merge_degenredundant();
+        numnewmerges++;
+        wasmerge= True;
+	if (mergetype == MRGconcave)
+	  numconcave++;
+	else /* MRGcoplanar or MRGanglecoplanar */
+	  numcoplanar++;
+      } /* while setdellast */
+      if (qh POSTmerging && qh hull_dim <= qh_DIMreduceBuild 
+      && numnewmerges > qh_MAXnewmerges) {
+	numnewmerges= 0;
+	qh_reducevertices();  /* otherwise large post merges too slow */
+      }
+      qh_getmergeset (qh newfacet_list); /* facet_mergeset */
+    } /* while mergeset */
+    if (qh VERTEXneighbors) {
+      isreduce= False;
+      if (qh hull_dim >=4 && qh POSTmerging) {
+	FORALLvertices  
+	  vertex->delridge= True;
+	isreduce= True;
+      }
+      if ((wasmerge || othermerge) && (!qh MERGEexact || qh POSTmerging) 
+	  && qh hull_dim <= qh_DIMreduceBuild) {
+	othermerge= False;
+	isreduce= True;
+      }
+      if (isreduce) {
+	if (qh_reducevertices()) {
+	  qh_getmergeset (qh newfacet_list); /* facet_mergeset */
+	  continue;
+	}
+      }
+    }
+    if (vneighbors && qh_test_vneighbors(/* qh newfacet_list */)) 
+      continue;
+    break;
+  } /* while (True) */
+  if (qh CHECKfrequently && !qh MERGEexact) {
+    qh old_randomdist= qh RANDOMdist;
+    qh RANDOMdist= False;
+    qh_checkconvex (qh newfacet_list, qh_ALGORITHMfault);
+    /* qh_checkconnect (); [this is slow and it changes the facet order] */
+    qh RANDOMdist= qh old_randomdist;
+  }
+  trace1((qh ferr, "qh_all_merges: merged %d coplanar facets %d concave facets and %d degen or redundant facets.\n",
+    numcoplanar, numconcave, numdegenredun));
+  if (qh IStracing >= 4 && qh num_facets < 50)
+    qh_printlists ();
+} /* all_merges */
+
+
+/*---------------------------------
+  
+  qh_appendmergeset( facet, neighbor, mergetype, angle )
+    appends an entry to qh.facet_mergeset or qh.degen_mergeset
+
+    angle ignored if NULL or !qh.ANGLEmerge
+
+  returns:
+    merge appended to facet_mergeset or degen_mergeset
+      sets ->degenerate or ->redundant if degen_mergeset
+  
+  see:
+    qh_test_appendmerge()
+
+  design:
+    allocate merge entry
+    if regular merge
+      append to qh.facet_mergeset
+    else if degenerate merge and qh.facet_mergeset is all degenerate
+      append to qh.degen_mergeset 
+    else if degenerate merge
+      prepend to qh.degen_mergeset 
+    else if redundant merge
+      append to qh.degen_mergeset 
+*/
+void qh_appendmergeset(facetT *facet, facetT *neighbor, mergeType mergetype, realT *angle) {
+  mergeT *merge, *lastmerge;
+  void **freelistp; /* used !qh_NOmem */
+
+  if (facet->redundant)
+    return;
+  if (facet->degenerate && mergetype == MRGdegen)
+    return;
+  qh_memalloc_(sizeof(mergeT), freelistp, merge, mergeT);
+  merge->facet1= facet;
+  merge->facet2= neighbor;
+  merge->type= mergetype;
+  if (angle && qh ANGLEmerge)
+    merge->angle= *angle;
+  if (mergetype < MRGdegen)
+    qh_setappend (&(qh facet_mergeset), merge);
+  else if (mergetype == MRGdegen) {
+    facet->degenerate= True;
+    if (!(lastmerge= (mergeT*)qh_setlast (qh degen_mergeset)) 
+    || lastmerge->type == MRGdegen)
+      qh_setappend (&(qh degen_mergeset), merge);
+    else
+      qh_setaddnth (&(qh degen_mergeset), 0, merge);
+  }else if (mergetype == MRGredundant) {
+    facet->redundant= True;
+    qh_setappend (&(qh degen_mergeset), merge);
+  }else /* mergetype == MRGmirror */ {
+    if (facet->redundant || neighbor->redundant) {
+      fprintf(qh ferr, "qhull error (qh_appendmergeset): facet f%d or f%d is already a mirrored facet\n",
+	   facet->id, neighbor->id);
+      qh_errexit2 (qh_ERRqhull, facet, neighbor);
+    }
+    if (!qh_setequal (facet->vertices, neighbor->vertices)) {
+      fprintf(qh ferr, "qhull error (qh_appendmergeset): mirrored facets f%d and f%d do not have the same vertices\n",
+	   facet->id, neighbor->id);
+      qh_errexit2 (qh_ERRqhull, facet, neighbor);
+    }
+    facet->redundant= True;
+    neighbor->redundant= True;
+    qh_setappend (&(qh degen_mergeset), merge);
+  }
+} /* appendmergeset */
+
+
+/*---------------------------------
+  
+  qh_basevertices( samecycle )
+    return temporary set of base vertices for samecycle
+    samecycle is first facet in the cycle
+    assumes apex is SETfirst_( samecycle->vertices )
+
+  returns:
+    vertices (settemp)
+    all ->seen are cleared
+
+  notes:
+    uses qh_vertex_visit;
+
+  design:
+    for each facet in samecycle
+      for each unseen vertex in facet->vertices
+        append to result  
+*/
+setT *qh_basevertices (facetT *samecycle) {
+  facetT *same;
+  vertexT *apex, *vertex, **vertexp;
+  setT *vertices= qh_settemp (qh TEMPsize);
+  
+  apex= SETfirstt_(samecycle->vertices, vertexT);
+  apex->visitid= ++qh vertex_visit;
+  FORALLsame_cycle_(samecycle) {
+    if (same->mergeridge)
+      continue;
+    FOREACHvertex_(same->vertices) {
+      if (vertex->visitid != qh vertex_visit) {
+        qh_setappend (&vertices, vertex);
+        vertex->visitid= qh vertex_visit;
+        vertex->seen= False;
+      }
+    }
+  }
+  trace4((qh ferr, "qh_basevertices: found %d vertices\n", 
+         qh_setsize (vertices)));
+  return vertices;
+} /* basevertices */
+
+/*---------------------------------
+  
+  qh_checkconnect()
+    check that new facets are connected
+    new facets are on qh.newfacet_list
+    
+  notes:
+    this is slow and it changes the order of the facets
+    uses qh.visit_id
+
+  design:
+    move first new facet to end of qh.facet_list
+    for all newly appended facets
+      append unvisited neighbors to end of qh.facet_list
+    for all new facets
+      report error if unvisited
+*/
+void qh_checkconnect (void /* qh newfacet_list */) {
+  facetT *facet, *newfacet, *errfacet= NULL, *neighbor, **neighborp;
+
+  facet= qh newfacet_list;
+  qh_removefacet (facet);
+  qh_appendfacet (facet);
+  facet->visitid= ++qh visit_id;
+  FORALLfacet_(facet) {
+    FOREACHneighbor_(facet) {
+      if (neighbor->visitid != qh visit_id) {
+        qh_removefacet (neighbor);
+        qh_appendfacet (neighbor);
+        neighbor->visitid= qh visit_id;
+      }
+    }
+  }
+  FORALLnew_facets {
+    if (newfacet->visitid == qh visit_id)
+      break;
+    fprintf(qh ferr, "qhull error: f%d is not attached to the new facets\n",
+         newfacet->id);
+    errfacet= newfacet;
+  }
+  if (errfacet)
+    qh_errexit (qh_ERRqhull, errfacet, NULL);
+} /* checkconnect */
+
+/*---------------------------------
+  
+  qh_checkzero( testall )
+    check that facets are clearly convex for qh.DISTround with qh.MERGEexact
+
+    if testall, 
+      test all facets for qh.MERGEexact post-merging
+    else 
+      test qh.newfacet_list
+      
+    if qh.MERGEexact, 
+      allows coplanar ridges
+      skips convexity test while qh.ZEROall_ok
+
+  returns:
+    True if all facets !flipped, !dupridge, normal
+         if all horizon facets are simplicial
+         if all vertices are clearly below neighbor
+         if all opposite vertices of horizon are below 
+    clears qh.ZEROall_ok if any problems or coplanar facets
+
+  notes:
+    uses qh.vertex_visit
+    horizon facets may define multiple new facets
+
+  design:
+    for all facets in qh.newfacet_list or qh.facet_list
+      check for flagged faults (flipped, etc.)
+    for all facets in qh.newfacet_list or qh.facet_list
+      for each neighbor of facet
+        skip horizon facets for qh.newfacet_list
+        test the opposite vertex
+      if qh.newfacet_list
+        test the other vertices in the facet's horizon facet
+*/
+boolT qh_checkzero (boolT testall) {
+  facetT *facet, *neighbor, **neighborp;
+  facetT *horizon, *facetlist;
+  int neighbor_i;
+  vertexT *vertex, **vertexp;
+  realT dist;
+
+  if (testall) 
+    facetlist= qh facet_list;
+  else {
+    facetlist= qh newfacet_list;
+    FORALLfacet_(facetlist) {
+      horizon= SETfirstt_(facet->neighbors, facetT);
+      if (!horizon->simplicial)
+        goto LABELproblem;
+      if (facet->flipped || facet->dupridge || !facet->normal)
+        goto LABELproblem;
+    }
+    if (qh MERGEexact && qh ZEROall_ok) {
+      trace2((qh ferr, "qh_checkzero: skip convexity check until first pre-merge\n"));
+      return True;
+    }
+  }
+  FORALLfacet_(facetlist) {
+    qh vertex_visit++;
+    neighbor_i= 0;
+    horizon= NULL;
+    FOREACHneighbor_(facet) {
+      if (!neighbor_i && !testall) {
+        horizon= neighbor;
+	neighbor_i++;
+        continue; /* horizon facet tested in qh_findhorizon */
+      }
+      vertex= SETelemt_(facet->vertices, neighbor_i++, vertexT);
+      vertex->visitid= qh vertex_visit;
+      zzinc_(Zdistzero);
+      qh_distplane (vertex->point, neighbor, &dist);
+      if (dist >= -qh DISTround) {
+        qh ZEROall_ok= False;
+        if (!qh MERGEexact || testall || dist > qh DISTround)
+          goto LABELnonconvex;
+      }
+    }
+    if (!testall) {
+      FOREACHvertex_(horizon->vertices) {
+	if (vertex->visitid != qh vertex_visit) {
+	  zzinc_(Zdistzero);
+	  qh_distplane (vertex->point, facet, &dist);
+	  if (dist >= -qh DISTround) {
+	    qh ZEROall_ok= False;
+	    if (!qh MERGEexact || dist > qh DISTround)
+	      goto LABELnonconvex;
+	  }
+	  break;
+	}
+      }
+    }
+  }
+  trace2((qh ferr, "qh_checkzero: testall %d, facets are %s\n", testall,
+        (qh MERGEexact && !testall) ? 
+           "not concave, flipped, or duplicate ridged" : "clearly convex"));
+  return True;
+
+ LABELproblem:
+  qh ZEROall_ok= False;
+  trace2((qh ferr, "qh_checkzero: facet f%d needs pre-merging\n",
+       facet->id));
+  return False;
+
+ LABELnonconvex:
+  trace2((qh ferr, "qh_checkzero: facet f%d and f%d are not clearly convex.  v%d dist %.2g\n",
+         facet->id, neighbor->id, vertex->id, dist));
+  return False;
+} /* checkzero */
+
+/*---------------------------------
+  
+  qh_compareangle( angle1, angle2 )
+    used by qsort() to order merges by angle
+*/
+static int qh_compareangle(const void *p1, const void *p2) {
+  mergeT *a= *((mergeT **)p1), *b= *((mergeT **)p2);
+ 
+  return ((a->angle > b->angle) ? 1 : -1);
+} /* compareangle */
+
+/*---------------------------------
+  
+  qh_comparemerge( merge1, merge2 )
+    used by qsort() to order merges
+*/
+static int qh_comparemerge(const void *p1, const void *p2) {
+  mergeT *a= *((mergeT **)p1), *b= *((mergeT **)p2);
+ 
+  return (a->type - b->type);
+} /* comparemerge */
+
+/*---------------------------------
+  
+  qh_comparevisit( vertex1, vertex2 )
+    used by qsort() to order vertices by their visitid
+*/
+static int qh_comparevisit (const void *p1, const void *p2) {
+  vertexT *a= *((vertexT **)p1), *b= *((vertexT **)p2);
+ 
+  return (a->visitid - b->visitid);
+} /* comparevisit */
+
+/*---------------------------------
+  
+  qh_copynonconvex( atridge )
+    set non-convex flag on other ridges (if any) between same neighbors
+
+  notes:
+    may be faster if use smaller ridge set
+
+  design:
+    for each ridge of atridge's top facet
+      if ridge shares the same neighbor
+        set nonconvex flag
+*/
+void qh_copynonconvex (ridgeT *atridge) {
+  facetT *facet, *otherfacet;
+  ridgeT *ridge, **ridgep;
+
+  facet= atridge->top;
+  otherfacet= atridge->bottom;
+  FOREACHridge_(facet->ridges) {
+    if (otherfacet == otherfacet_(ridge, facet) && ridge != atridge) {
+      ridge->nonconvex= True;
+      trace4((qh ferr, "qh_copynonconvex: moved nonconvex flag from r%d to r%d\n",
+	      atridge->id, ridge->id));
+      break;
+    }
+  }
+} /* copynonconvex */
+
+/*---------------------------------
+  
+  qh_degen_redundant_facet( facet )
+    check facet for degen. or redundancy
+
+  notes:
+    bumps vertex_visit
+    called if a facet was redundant but no longer is (qh_merge_degenredundant)
+    qh_appendmergeset() only appends first reference to facet (i.e., redundant)
+
+  see:
+    qh_degen_redundant_neighbors()
+
+  design:
+    test for redundant neighbor
+    test for degenerate facet
+*/
+void qh_degen_redundant_facet (facetT *facet) {
+  vertexT *vertex, **vertexp;
+  facetT *neighbor, **neighborp;
+
+  trace4((qh ferr, "qh_degen_redundant_facet: test facet f%d for degen/redundant\n",
+	  facet->id));
+  FOREACHneighbor_(facet) {
+    qh vertex_visit++;
+    FOREACHvertex_(neighbor->vertices)
+      vertex->visitid= qh vertex_visit;
+    FOREACHvertex_(facet->vertices) {
+      if (vertex->visitid != qh vertex_visit)
+	break;
+    }
+    if (!vertex) {
+      qh_appendmergeset (facet, neighbor, MRGredundant, NULL);
+      trace2((qh ferr, "qh_degen_redundant_facet: f%d is contained in f%d.  merge\n", facet->id, neighbor->id)); 
+      return;
+    }
+  }
+  if (qh_setsize (facet->neighbors) < qh hull_dim) {
+    qh_appendmergeset (facet, facet, MRGdegen, NULL);
+    trace2((qh ferr, "qh_degen_redundant_neighbors: f%d is degenerate.\n", facet->id));
+  }
+} /* degen_redundant_facet */
+
+
+/*---------------------------------
+  
+  qh_degen_redundant_neighbors( facet, delfacet,  )
+    append degenerate and redundant neighbors to facet_mergeset
+    if delfacet, 
+      only checks neighbors of both delfacet and facet
+    also checks current facet for degeneracy
+
+  notes:
+    bumps vertex_visit
+    called for each qh_mergefacet() and qh_mergecycle()
+    merge and statistics occur in merge_nonconvex
+    qh_appendmergeset() only appends first reference to facet (i.e., redundant)
+      it appends redundant facets after degenerate ones
+
+    a degenerate facet has fewer than hull_dim neighbors
+    a redundant facet's vertices is a subset of its neighbor's vertices
+    tests for redundant merges first (appendmergeset is nop for others)
+    in a merge, only needs to test neighbors of merged facet
+  
+  see:
+    qh_merge_degenredundant() and qh_degen_redundant_facet()
+
+  design:
+    test for degenerate facet
+    test for redundant neighbor
+    test for degenerate neighbor
+*/
+void qh_degen_redundant_neighbors (facetT *facet, facetT *delfacet) {
+  vertexT *vertex, **vertexp;
+  facetT *neighbor, **neighborp;
+  int size;
+
+  trace4((qh ferr, "qh_degen_redundant_neighbors: test neighbors of f%d with delfacet f%d\n", 
+	  facet->id, getid_(delfacet)));
+  if ((size= qh_setsize (facet->neighbors)) < qh hull_dim) {
+    qh_appendmergeset (facet, facet, MRGdegen, NULL);
+    trace2((qh ferr, "qh_degen_redundant_neighbors: f%d is degenerate with %d neighbors.\n", facet->id, size));
+  }
+  if (!delfacet)
+    delfacet= facet;
+  qh vertex_visit++;
+  FOREACHvertex_(facet->vertices)
+    vertex->visitid= qh vertex_visit;
+  FOREACHneighbor_(delfacet) {
+    /* uses early out instead of checking vertex count */
+    if (neighbor == facet)
+      continue;
+    FOREACHvertex_(neighbor->vertices) {
+      if (vertex->visitid != qh vertex_visit)
+        break;
+    }
+    if (!vertex) {
+      qh_appendmergeset (neighbor, facet, MRGredundant, NULL);
+      trace2((qh ferr, "qh_degen_redundant_neighbors: f%d is contained in f%d.  merge\n", neighbor->id, facet->id)); 
+    }
+  }
+  FOREACHneighbor_(delfacet) {   /* redundant merges occur first */
+    if (neighbor == facet)
+      continue;
+    if ((size= qh_setsize (neighbor->neighbors)) < qh hull_dim) {
+      qh_appendmergeset (neighbor, neighbor, MRGdegen, NULL);
+      trace2((qh ferr, "qh_degen_redundant_neighbors: f%d is degenerate with %d neighbors.  Neighbor of f%d.\n", neighbor->id, size, facet->id)); 
+    }
+  }
+} /* degen_redundant_neighbors */
+
+
+/*---------------------------------
+  
+  qh_find_newvertex( oldvertex, vertices, ridges )
+    locate new vertex for renaming old vertex
+    vertices is a set of possible new vertices
+      vertices sorted by number of deleted ridges
+
+  returns:
+    newvertex or NULL
+      each ridge includes both vertex and oldvertex
+    vertices sorted by number of deleted ridges
+      
+  notes:
+    modifies vertex->visitid
+    new vertex is in one of the ridges
+    renaming will not cause a duplicate ridge
+    renaming will minimize the number of deleted ridges
+    newvertex may not be adjacent in the dual (though unlikely)
+
+  design:
+    for each vertex in vertices
+      set vertex->visitid to number of references in ridges
+    remove unvisited vertices 
+    set qh.vertex_visit above all possible values
+    sort vertices by number of references in ridges
+    add each ridge to qh.hash_table
+    for each vertex in vertices
+      look for a vertex that would not cause a duplicate ridge after a rename
+*/
+vertexT *qh_find_newvertex (vertexT *oldvertex, setT *vertices, setT *ridges) {
+  vertexT *vertex, **vertexp;
+  setT *newridges;
+  ridgeT *ridge, **ridgep;
+  int size, hashsize;
+  int hash;
+
+#ifndef qh_NOtrace
+  if (qh IStracing >= 4) {
+    fprintf (qh ferr, "qh_find_newvertex: find new vertex for v%d from ",
+	     oldvertex->id);
+    FOREACHvertex_(vertices) 
+      fprintf (qh ferr, "v%d ", vertex->id);
+    FOREACHridge_(ridges)
+      fprintf (qh ferr, "r%d ", ridge->id);
+    fprintf (qh ferr, "\n");
+  }
+#endif
+  FOREACHvertex_(vertices) 
+    vertex->visitid= 0;
+  FOREACHridge_(ridges) {
+    FOREACHvertex_(ridge->vertices) 
+      vertex->visitid++;
+  }
+  FOREACHvertex_(vertices) {
+    if (!vertex->visitid) {
+      qh_setdelnth (vertices, SETindex_(vertices,vertex));
+      vertexp--; /* repeat since deleted this vertex */
+    }
+  }
+  qh vertex_visit += qh_setsize (ridges);
+  if (!qh_setsize (vertices)) {
+    trace4((qh ferr, "qh_find_newvertex: vertices not in ridges for v%d\n",
+	    oldvertex->id));
+    return NULL;
+  }
+  qsort (SETaddr_(vertices, vertexT), qh_setsize (vertices),
+	        sizeof (vertexT *), qh_comparevisit);
+  /* can now use qh vertex_visit */
+  if (qh PRINTstatistics) {
+    size= qh_setsize (vertices);
+    zinc_(Zintersect);
+    zadd_(Zintersecttot, size);
+    zmax_(Zintersectmax, size);
+  }
+  hashsize= qh_newhashtable (qh_setsize (ridges));
+  FOREACHridge_(ridges)
+    qh_hashridge (qh hash_table, hashsize, ridge, oldvertex);
+  FOREACHvertex_(vertices) {
+    newridges= qh_vertexridges (vertex);
+    FOREACHridge_(newridges) {
+      if (qh_hashridge_find (qh hash_table, hashsize, ridge, vertex, oldvertex, &hash)) {
+	zinc_(Zdupridge);
+	break;
+      }
+    }
+    qh_settempfree (&newridges);
+    if (!ridge)
+      break;  /* found a rename */
+  }
+  if (vertex) {
+    /* counted in qh_renamevertex */
+    trace2((qh ferr, "qh_find_newvertex: found v%d for old v%d from %d vertices and %d ridges.\n",
+      vertex->id, oldvertex->id, qh_setsize (vertices), qh_setsize (ridges)));
+  }else {
+    zinc_(Zfindfail);
+    trace0((qh ferr, "qh_find_newvertex: no vertex for renaming v%d (all duplicated ridges) during p%d\n",
+      oldvertex->id, qh furthest_id));
+  }
+  qh_setfree (&qh hash_table);
+  return vertex;
+} /* find_newvertex */
+
+/*---------------------------------
+  
+  qh_findbest_test( testcentrum, facet, neighbor, bestfacet, dist, mindist, maxdist )
+    test neighbor of facet for qh_findbestneighbor()
+    if testcentrum,
+      tests centrum (assumes it is defined)
+    else 
+      tests vertices
+
+  returns:
+    if a better facet (i.e., vertices/centrum of facet closer to neighbor)
+      updates bestfacet, dist, mindist, and maxdist
+*/
+void qh_findbest_test (boolT testcentrum, facetT *facet, facetT *neighbor,
+      facetT **bestfacet, realT *distp, realT *mindistp, realT *maxdistp) {
+  realT dist, mindist, maxdist;
+
+  if (testcentrum) {
+    zzinc_(Zbestdist);
+    qh_distplane(facet->center, neighbor, &dist);
+    dist *= qh hull_dim; /* estimate furthest vertex */
+    if (dist < 0) {
+      maxdist= 0;
+      mindist= dist;
+      dist= -dist;
+    }else
+      maxdist= dist;
+  }else
+    dist= qh_getdistance (facet, neighbor, &mindist, &maxdist);
+  if (dist < *distp) {
+    *bestfacet= neighbor;
+    *mindistp= mindist;
+    *maxdistp= maxdist;
+    *distp= dist;
+  }
+} /* findbest_test */
+
+/*---------------------------------
+  
+  qh_findbestneighbor( facet, dist, mindist, maxdist )
+    finds best neighbor (least dist) of a facet for merging
+
+  returns:
+    returns min and max distances and their max absolute value
+  
+  notes:
+    avoids merging old into new
+    assumes ridge->nonconvex only set on one ridge between a pair of facets
+    could use an early out predicate but not worth it
+
+  design:
+    if a large facet
+      will test centrum
+    else
+      will test vertices
+    if a large facet
+      test nonconvex neighbors for best merge
+    else
+      test all neighbors for the best merge
+    if testing centrum
+      get distance information
+*/
+facetT *qh_findbestneighbor(facetT *facet, realT *distp, realT *mindistp, realT *maxdistp) {
+  facetT *neighbor, **neighborp, *bestfacet= NULL;
+  ridgeT *ridge, **ridgep;
+  boolT nonconvex= True, testcentrum= False;
+  int size= qh_setsize (facet->vertices);
+
+  *distp= REALmax;
+  if (size > qh_BESTcentrum2 * qh hull_dim + qh_BESTcentrum) {
+    testcentrum= True;
+    zinc_(Zbestcentrum);
+    if (!facet->center)
+       facet->center= qh_getcentrum (facet);
+  }
+  if (size > qh hull_dim + qh_BESTnonconvex) {
+    FOREACHridge_(facet->ridges) {
+      if (ridge->nonconvex) {
+        neighbor= otherfacet_(ridge, facet);
+	qh_findbest_test (testcentrum, facet, neighbor,
+			  &bestfacet, distp, mindistp, maxdistp);
+      }
+    }
+  }
+  if (!bestfacet) {     
+    nonconvex= False;
+    FOREACHneighbor_(facet)
+      qh_findbest_test (testcentrum, facet, neighbor,
+			&bestfacet, distp, mindistp, maxdistp);
+  }
+  if (!bestfacet) {
+    fprintf (qh ferr, "qhull internal error (qh_findbestneighbor): no neighbors for f%d\n", facet->id);
+    
+    qh_errexit (qh_ERRqhull, facet, NULL);
+  }
+  if (testcentrum) 
+    qh_getdistance (facet, bestfacet, mindistp, maxdistp);
+  trace3((qh ferr, "qh_findbestneighbor: f%d is best neighbor for f%d testcentrum? %d nonconvex? %d dist %2.2g min %2.2g max %2.2g\n",
+     bestfacet->id, facet->id, testcentrum, nonconvex, *distp, *mindistp, *maxdistp));
+  return(bestfacet);
+} /* findbestneighbor */
+
+
+/*---------------------------------
+  
+  qh_flippedmerges( facetlist, wasmerge )
+    merge flipped facets into best neighbor
+    assumes qh.facet_mergeset at top of temporary stack
+
+  returns:
+    no flipped facets on facetlist
+    sets wasmerge if merge occurred
+    degen/redundant merges passed through
+
+  notes:
+    othermerges not needed since qh.facet_mergeset is empty before & after
+      keep it in case of change
+
+  design:
+    append flipped facets to qh.facetmergeset
+    for each flipped merge
+      find best neighbor
+      merge facet into neighbor
+      merge degenerate and redundant facets
+    remove flipped merges from qh.facet_mergeset
+*/
+void qh_flippedmerges(facetT *facetlist, boolT *wasmerge) {
+  facetT *facet, *neighbor, *facet1;
+  realT dist, mindist, maxdist;
+  mergeT *merge, **mergep;
+  setT *othermerges;
+  int nummerge=0;
+
+  trace4((qh ferr, "qh_flippedmerges: begin\n"));
+  FORALLfacet_(facetlist) {
+    if (facet->flipped && !facet->visible) 
+      qh_appendmergeset (facet, facet, MRGflip, NULL);
+  }
+  othermerges= qh_settemppop(); /* was facet_mergeset */
+  qh facet_mergeset= qh_settemp (qh TEMPsize);
+  qh_settemppush (othermerges);
+  FOREACHmerge_(othermerges) {
+    facet1= merge->facet1;
+    if (merge->type != MRGflip || facet1->visible) 
+      continue;
+    if (qh TRACEmerge-1 == zzval_(Ztotmerge))
+      qhmem.IStracing= qh IStracing= qh TRACElevel;
+    neighbor= qh_findbestneighbor (facet1, &dist, &mindist, &maxdist);
+    trace0((qh ferr, "qh_flippedmerges: merge flipped f%d into f%d dist %2.2g during p%d\n",
+      facet1->id, neighbor->id, dist, qh furthest_id));
+    qh_mergefacet (facet1, neighbor, &mindist, &maxdist, !qh_MERGEapex);
+    nummerge++;
+    if (qh PRINTstatistics) {
+      zinc_(Zflipped);
+      wadd_(Wflippedtot, dist);
+      wmax_(Wflippedmax, dist);
+    }
+    qh_merge_degenredundant();
+  }
+  FOREACHmerge_(othermerges) {
+    if (merge->facet1->visible || merge->facet2->visible)
+      qh_memfree (merge, sizeof(mergeT));
+    else
+      qh_setappend (&qh facet_mergeset, merge);
+  }
+  qh_settempfree (&othermerges);
+  if (nummerge)
+    *wasmerge= True;
+  trace1((qh ferr, "qh_flippedmerges: merged %d flipped facets into a good neighbor\n", nummerge));
+} /* flippedmerges */
+
+
+/*---------------------------------
+  
+  qh_forcedmerges( wasmerge )
+    merge duplicated ridges
+
+  returns:
+    removes all duplicate ridges on facet_mergeset
+    wasmerge set if merge
+    qh.facet_mergeset may include non-forced merges (none for now)
+    qh.degen_mergeset includes degen/redun merges
+
+  notes: 
+    duplicate ridges occur when the horizon is pinched,
+        i.e. a subridge occurs in more than two horizon ridges.
+     could rename vertices that pinch the horizon
+    assumes qh_merge_degenredundant() has not be called
+    othermerges isn't needed since facet_mergeset is empty afterwards
+      keep it in case of change
+
+  design:
+    for each duplicate ridge
+      find current facets by chasing f.replace links
+      determine best direction for facet
+      merge one facet into the other
+      remove duplicate ridges from qh.facet_mergeset
+*/
+void qh_forcedmerges(boolT *wasmerge) {
+  facetT *facet1, *facet2;
+  mergeT *merge, **mergep;
+  realT dist1, dist2, mindist1, mindist2, maxdist1, maxdist2;
+  setT *othermerges;
+  int nummerge=0, numflip=0;
+
+  if (qh TRACEmerge-1 == zzval_(Ztotmerge))
+    qhmem.IStracing= qh IStracing= qh TRACElevel;
+  trace4((qh ferr, "qh_forcedmerges: begin\n"));  
+  othermerges= qh_settemppop(); /* was facet_mergeset */
+  qh facet_mergeset= qh_settemp (qh TEMPsize);
+  qh_settemppush (othermerges);
+  FOREACHmerge_(othermerges) {
+    if (merge->type != MRGridge) 
+    	continue;
+    facet1= merge->facet1;
+    facet2= merge->facet2;
+    while (facet1->visible)    	 /* must exist, no qh_merge_degenredunant */
+      facet1= facet1->f.replace; /* previously merged facet */
+    while (facet2->visible)
+      facet2= facet2->f.replace; /* previously merged facet */
+    if (facet1 == facet2)
+      continue;
+    if (!qh_setin (facet2->neighbors, facet1)) {
+      fprintf (qh ferr, "qhull internal error (qh_forcedmerges): f%d and f%d had a duplicate ridge but as f%d and f%d they are no longer neighbors\n",
+	       merge->facet1->id, merge->facet2->id, facet1->id, facet2->id);
+      qh_errexit2 (qh_ERRqhull, facet1, facet2);
+    }
+    if (qh TRACEmerge-1 == zzval_(Ztotmerge))
+      qhmem.IStracing= qh IStracing= qh TRACElevel;
+    dist1= qh_getdistance (facet1, facet2, &mindist1, &maxdist1);
+    dist2= qh_getdistance (facet2, facet1, &mindist2, &maxdist2);
+    trace0((qh ferr, "qh_forcedmerges: duplicate ridge between f%d and f%d, dist %2.2g and reverse dist %2.2g during p%d\n",
+	    facet1->id, facet2->id, dist1, dist2, qh furthest_id));
+    if (dist1 < dist2) 
+      qh_mergefacet (facet1, facet2, &mindist1, &maxdist1, !qh_MERGEapex);
+    else {
+      qh_mergefacet (facet2, facet1, &mindist2, &maxdist2, !qh_MERGEapex);
+      dist1= dist2;
+      facet1= facet2;
+    }
+    if (facet1->flipped) {
+      zinc_(Zmergeflipdup);
+      numflip++;
+    }else
+      nummerge++;
+    if (qh PRINTstatistics) {
+      zinc_(Zduplicate);
+      wadd_(Wduplicatetot, dist1);
+      wmax_(Wduplicatemax, dist1);
+    }
+  }
+  FOREACHmerge_(othermerges) {
+    if (merge->type == MRGridge)
+      qh_memfree (merge, sizeof(mergeT));
+    else
+      qh_setappend (&qh facet_mergeset, merge);
+  }
+  qh_settempfree (&othermerges);
+  if (nummerge)
+    *wasmerge= True;
+  trace1((qh ferr, "qh_forcedmerges: merged %d facets and %d flipped facets across duplicated ridges\n", 
+                nummerge, numflip));
+} /* forcedmerges */
+
+
+/*---------------------------------
+  
+  qh_getmergeset( facetlist )
+    determines nonconvex facets on facetlist
+    tests !tested ridges and nonconvex ridges of !tested facets
+
+  returns:
+    returns sorted qh.facet_mergeset of facet-neighbor pairs to be merged
+    all ridges tested
+  
+  notes:
+    assumes no nonconvex ridges with both facets tested
+    uses facet->tested/ridge->tested to prevent duplicate tests
+    can not limit tests to modified ridges since the centrum changed
+    uses qh.visit_id
+  
+  see:
+    qh_getmergeset_initial()
+
+  design:
+    for each facet on facetlist
+      for each ridge of facet
+        if untested ridge
+          test ridge for convexity
+          if non-convex
+            append ridge to qh.facet_mergeset
+    sort qh.facet_mergeset by angle  
+*/
+void qh_getmergeset(facetT *facetlist) {
+  facetT *facet, *neighbor, **neighborp;
+  ridgeT *ridge, **ridgep;
+  int nummerges;
+  
+  nummerges= qh_setsize (qh facet_mergeset);
+  trace4((qh ferr, "qh_getmergeset: started.\n"));
+  qh visit_id++;
+  FORALLfacet_(facetlist) {
+    if (facet->tested)
+      continue;
+    facet->visitid= qh visit_id;
+    facet->tested= True;  /* must be non-simplicial due to merge */
+    FOREACHneighbor_(facet)
+      neighbor->seen= False;
+    FOREACHridge_(facet->ridges) {
+      if (ridge->tested && !ridge->nonconvex)
+	continue;
+      /* if tested & nonconvex, need to append merge */
+      neighbor= otherfacet_(ridge, facet);
+      if (neighbor->seen) {
+	ridge->tested= True;
+	ridge->nonconvex= False;
+      }else if (neighbor->visitid != qh visit_id) {
+        ridge->tested= True;
+        ridge->nonconvex= False;
+	neighbor->seen= True;      /* only one ridge is marked nonconvex */
+	if (qh_test_appendmerge (facet, neighbor))
+	  ridge->nonconvex= True;
+      }
+    }
+  }
+  nummerges= qh_setsize (qh facet_mergeset);
+  if (qh ANGLEmerge)
+    qsort(SETaddr_(qh facet_mergeset, mergeT), nummerges,sizeof(mergeT *),qh_compareangle);
+  else
+    qsort(SETaddr_(qh facet_mergeset, mergeT), nummerges,sizeof(mergeT *),qh_comparemerge);
+  if (qh POSTmerging) {
+    zadd_(Zmergesettot2, nummerges);
+  }else {
+    zadd_(Zmergesettot, nummerges);
+    zmax_(Zmergesetmax, nummerges);
+  }
+  trace2((qh ferr, "qh_getmergeset: %d merges found\n", nummerges));
+} /* getmergeset */
+
+
+/*---------------------------------
+  
+  qh_getmergeset_initial( facetlist )
+    determine initial qh.facet_mergeset for facets
+    tests all facet/neighbor pairs on facetlist
+
+  returns:
+    sorted qh.facet_mergeset with nonconvex ridges
+    sets facet->tested, ridge->tested, and ridge->nonconvex
+
+  notes:
+    uses visit_id, assumes ridge->nonconvex is False
+
+  see:
+    qh_getmergeset()
+
+  design:
+    for each facet on facetlist
+      for each untested neighbor of facet
+        test facet and neighbor for convexity
+        if non-convex
+          append merge to qh.facet_mergeset
+          mark one of the ridges as nonconvex
+    sort qh.facet_mergeset by angle
+*/
+void qh_getmergeset_initial (facetT *facetlist) {
+  facetT *facet, *neighbor, **neighborp;
+  ridgeT *ridge, **ridgep;
+  int nummerges;
+
+  qh visit_id++;
+  FORALLfacet_(facetlist) {
+    facet->visitid= qh visit_id;
+    facet->tested= True;
+    FOREACHneighbor_(facet) {
+      if (neighbor->visitid != qh visit_id) {
+        if (qh_test_appendmerge (facet, neighbor)) {
+          FOREACHridge_(neighbor->ridges) {
+            if (facet == otherfacet_(ridge, neighbor)) {
+              ridge->nonconvex= True;
+              break;	/* only one ridge is marked nonconvex */
+            }
+          }
+        }
+      }
+    }
+    FOREACHridge_(facet->ridges)
+      ridge->tested= True;
+  }
+  nummerges= qh_setsize (qh facet_mergeset);
+  if (qh ANGLEmerge)
+    qsort(SETaddr_(qh facet_mergeset, mergeT), nummerges,sizeof(mergeT *),qh_compareangle);
+  else
+    qsort(SETaddr_(qh facet_mergeset, mergeT), nummerges,sizeof(mergeT *),qh_comparemerge);
+  if (qh POSTmerging) {
+    zadd_(Zmergeinittot2, nummerges);
+  }else {
+    zadd_(Zmergeinittot, nummerges);
+    zmax_(Zmergeinitmax, nummerges);
+  }
+  trace2((qh ferr, "qh_getmergeset_initial: %d merges found\n", nummerges));
+} /* getmergeset_initial */
+
+
+/*---------------------------------
+  
+  qh_hashridge( hashtable, hashsize, ridge, oldvertex )
+    add ridge to hashtable without oldvertex
+
+  notes:
+    assumes hashtable is large enough
+
+  design:
+    determine hash value for ridge without oldvertex
+    find next empty slot for ridge
+*/
+void qh_hashridge (setT *hashtable, int hashsize, ridgeT *ridge, vertexT *oldvertex) {
+  int hash;
+  ridgeT *ridgeA;
+
+  hash= (int)qh_gethash (hashsize, ridge->vertices, qh hull_dim-1, 0, oldvertex);
+  while (True) {
+    if (!(ridgeA= SETelemt_(hashtable, hash, ridgeT))) {
+      SETelem_(hashtable, hash)= ridge;
+      break;
+    }else if (ridgeA == ridge)
+      break;
+    if (++hash == hashsize)
+      hash= 0;
+  }
+} /* hashridge */
+
+
+/*---------------------------------
+  
+  qh_hashridge_find( hashtable, hashsize, ridge, vertex, oldvertex, hashslot )
+    returns matching ridge without oldvertex in hashtable 
+      for ridge without vertex
+    if oldvertex is NULL 
+      matches with any one skip
+
+  returns:
+    matching ridge or NULL
+    if no match,
+      if ridge already in   table
+        hashslot= -1 
+      else 
+        hashslot= next NULL index
+        
+  notes:
+    assumes hashtable is large enough
+    can't match ridge to itself
+
+  design:
+    get hash value for ridge without vertex
+    for each hashslot
+      return match if ridge matches ridgeA without oldvertex
+*/
+ridgeT *qh_hashridge_find (setT *hashtable, int hashsize, ridgeT *ridge, 
+              vertexT *vertex, vertexT *oldvertex, int *hashslot) {
+  int hash;
+  ridgeT *ridgeA;
+
+  *hashslot= 0;
+  zinc_(Zhashridge);
+  hash= (int)qh_gethash (hashsize, ridge->vertices, qh hull_dim-1, 0, vertex);
+  while ((ridgeA= SETelemt_(hashtable, hash, ridgeT))) {
+    if (ridgeA == ridge)
+      *hashslot= -1;      
+    else {
+      zinc_(Zhashridgetest);
+      if (qh_setequal_except (ridge->vertices, vertex, ridgeA->vertices, oldvertex))
+        return ridgeA;
+    }
+    if (++hash == hashsize)
+      hash= 0;
+  }
+  if (!*hashslot)
+    *hashslot= hash;
+  return NULL;
+} /* hashridge_find */
+
+
+/*---------------------------------
+  
+  qh_makeridges( facet )
+    creates explicit ridges between simplicial facets
+
+  returns:
+    facet with ridges and without qh_MERGEridge
+    ->simplicial is False
+  
+  notes:
+    allows qh_MERGEridge flag
+    uses existing ridges
+    duplicate neighbors ok if ridges already exist (qh_mergecycle_ridges)
+
+  see:
+    qh_mergecycle_ridges()
+
+  design:
+    look for qh_MERGEridge neighbors
+    mark neighbors that already have ridges
+    for each unprocessed neighbor of facet    
+      create a ridge for neighbor and facet
+    if any qh_MERGEridge neighbors
+      delete qh_MERGEridge flags (already handled by qh_mark_dupridges)
+*/
+void qh_makeridges(facetT *facet) {
+  facetT *neighbor, **neighborp;
+  ridgeT *ridge, **ridgep;
+  int neighbor_i, neighbor_n;
+  boolT toporient, mergeridge= False;
+  
+  if (!facet->simplicial)
+    return;
+  trace4((qh ferr, "qh_makeridges: make ridges for f%d\n", facet->id));
+  facet->simplicial= False;
+  FOREACHneighbor_(facet) {
+    if (neighbor == qh_MERGEridge)
+      mergeridge= True;
+    else
+      neighbor->seen= False;
+  }
+  FOREACHridge_(facet->ridges)
+    otherfacet_(ridge, facet)->seen= True;
+  FOREACHneighbor_i_(facet) {
+    if (neighbor == qh_MERGEridge)
+      continue;  /* fixed by qh_mark_dupridges */
+    else if (!neighbor->seen) {  /* no current ridges */
+      ridge= qh_newridge();
+      ridge->vertices= qh_setnew_delnthsorted (facet->vertices, qh hull_dim,
+					                  neighbor_i, 0);
+      toporient= facet->toporient ^ (neighbor_i & 0x1);
+      if (toporient) {
+        ridge->top= facet;
+        ridge->bottom= neighbor;
+      }else {
+        ridge->top= neighbor;
+        ridge->bottom= facet;
+      }
+#if 0 /* this also works */
+      flip= (facet->toporient ^ neighbor->toporient)^(skip1 & 0x1) ^ (skip2 & 0x1);
+      if (facet->toporient ^ (skip1 & 0x1) ^ flip) {
+        ridge->top= neighbor;
+        ridge->bottom= facet;
+      }else {
+        ridge->top= facet;
+        ridge->bottom= neighbor;
+      }
+#endif
+      qh_setappend(&(facet->ridges), ridge);
+      qh_setappend(&(neighbor->ridges), ridge);
+    }
+  }
+  if (mergeridge) {
+    while (qh_setdel (facet->neighbors, qh_MERGEridge))
+      ; /* delete each one */
+  }
+} /* makeridges */
+
+
+/*---------------------------------
+  
+  qh_mark_dupridges( facetlist )
+    add duplicated ridges to qh.facet_mergeset
+    facet->dupridge is true
+
+  returns:
+    duplicate ridges on qh.facet_mergeset
+    ->mergeridge/->mergeridge2 set
+    duplicate ridges marked by qh_MERGEridge and both sides facet->dupridge
+    no MERGEridges in neighbor sets
+    
+  notes:
+    duplicate ridges occur when the horizon is pinched,
+        i.e. a subridge occurs in more than two horizon ridges.
+    could rename vertices that pinch the horizon
+    uses qh.visit_id
+
+  design:
+    for all facets on facetlist
+      if facet contains a duplicate ridge
+        for each neighbor of facet
+          if neighbor marked qh_MERGEridge (one side of the merge)
+            set facet->mergeridge      
+          else
+            if neighbor contains a duplicate ridge 
+            and the back link is qh_MERGEridge
+              append duplicate ridge to qh.facet_mergeset
+   for each duplicate ridge
+     make ridge sets in preparation for merging
+     remove qh_MERGEridge from neighbor set
+   for each duplicate ridge
+     restore the missing neighbor from the neighbor set that was qh_MERGEridge
+     add the missing ridge for this neighbor
+*/
+void qh_mark_dupridges(facetT *facetlist) {
+  facetT *facet, *neighbor, **neighborp;
+  int nummerge=0;
+  mergeT *merge, **mergep;
+  
+
+  trace4((qh ferr, "qh_mark_dupridges: identify duplicate ridges\n"));  
+  FORALLfacet_(facetlist) {
+    if (facet->dupridge) {
+      FOREACHneighbor_(facet) {
+        if (neighbor == qh_MERGEridge) {
+	  facet->mergeridge= True;
+	  continue;
+	}
+        if (neighbor->dupridge
+	&& !qh_setin (neighbor->neighbors, facet)) { /* qh_MERGEridge */
+	  qh_appendmergeset (facet, neighbor, MRGridge, NULL);
+	  facet->mergeridge2= True;
+	  facet->mergeridge= True;
+	  nummerge++;
+	}
+      }
+    }
+  }
+  if (!nummerge)
+    return;
+  FORALLfacet_(facetlist) {            /* gets rid of qh_MERGEridge */
+    if (facet->mergeridge && !facet->mergeridge2)   
+      qh_makeridges (facet);
+  }
+  FOREACHmerge_(qh facet_mergeset) {   /* restore the missing neighbors */
+    if (merge->type == MRGridge) {
+      qh_setappend (&merge->facet2->neighbors, merge->facet1);
+      qh_makeridges (merge->facet1);   /* and the missing ridges */
+    }
+  }
+  trace1((qh ferr, "qh_mark_dupridges: found %d duplicated ridges\n", 
+                nummerge));
+} /* mark_dupridges */
+
+/*---------------------------------
+  
+  qh_maydropneighbor( facet )
+    drop neighbor relationship if no ridge between facet and neighbor
+
+  returns:
+    neighbor sets updated
+    appends degenerate facets to qh.facet_mergeset
+  
+  notes:
+    won't cause redundant facets since vertex inclusion is the same
+    may drop vertex and neighbor if no ridge
+    uses qh.visit_id
+
+  design:
+    visit all neighbors with ridges
+    for each unvisited neighbor of facet
+      delete neighbor and facet from the neighbor sets
+      if neighbor becomes degenerate
+        append neighbor to qh.degen_mergeset
+    if facet is degenerate
+      append facet to qh.degen_mergeset
+*/
+void qh_maydropneighbor (facetT *facet) {
+  ridgeT *ridge, **ridgep;
+  realT angledegen= qh_ANGLEdegen;
+  facetT *neighbor, **neighborp;
+
+  qh visit_id++;
+  trace4((qh ferr, "qh_maydropneighbor: test f%d for no ridges to a neighbor\n",
+	  facet->id));
+  FOREACHridge_(facet->ridges) {
+    ridge->top->visitid= qh visit_id;
+    ridge->bottom->visitid= qh visit_id;
+  }
+  FOREACHneighbor_(facet) {
+    if (neighbor->visitid != qh visit_id) {
+      trace0((qh ferr, "qh_maydropneighbor: facets f%d and f%d are no longer neighbors during p%d\n",
+	    facet->id, neighbor->id, qh furthest_id));
+      zinc_(Zdropneighbor);
+      qh_setdel (facet->neighbors, neighbor);
+      neighborp--;  /* repeat, deleted a neighbor */
+      qh_setdel (neighbor->neighbors, facet);
+      if (qh_setsize (neighbor->neighbors) < qh hull_dim) {
+        zinc_(Zdropdegen);
+        qh_appendmergeset (neighbor, neighbor, MRGdegen, &angledegen);
+        trace2((qh ferr, "qh_maydropneighbors: f%d is degenerate.\n", neighbor->id));
+      }
+    }
+  }
+  if (qh_setsize (facet->neighbors) < qh hull_dim) {
+    zinc_(Zdropdegen);
+    qh_appendmergeset (facet, facet, MRGdegen, &angledegen);
+    trace2((qh ferr, "qh_maydropneighbors: f%d is degenerate.\n", facet->id));
+  }
+} /* maydropneighbor */
+
+
+/*---------------------------------
+  
+  qh_merge_degenredundant()
+    merge all degenerate and redundant facets
+    qh.degen_mergeset contains merges from qh_degen_redundant_neighbors()
+
+  returns:
+    number of merges performed
+    resets facet->degenerate/redundant
+    if deleted (visible) facet has no neighbors
+      sets ->f.replace to NULL
+
+  notes:
+    redundant merges happen before degenerate ones
+    merging and renaming vertices can result in degen/redundant facets
+
+  design:
+    for each merge on qh.degen_mergeset
+      if redundant merge
+        if non-redundant facet merged into redundant facet
+          recheck facet for redundancy
+        else
+          merge redundant facet into other facet
+*/
+int qh_merge_degenredundant (void) {
+  int size;
+  mergeT *merge;
+  facetT *bestneighbor, *facet1, *facet2;
+  realT dist, mindist, maxdist;
+  vertexT *vertex, **vertexp;
+  int nummerges= 0;
+  mergeType mergetype;
+
+  while ((merge= (mergeT*)qh_setdellast (qh degen_mergeset))) {
+    facet1= merge->facet1;
+    facet2= merge->facet2;
+    mergetype= merge->type;
+    qh_memfree (merge, sizeof(mergeT));
+    if (facet1->visible)
+      continue;
+    facet1->degenerate= False; 
+    facet1->redundant= False; 
+    if (qh TRACEmerge-1 == zzval_(Ztotmerge))
+      qhmem.IStracing= qh IStracing= qh TRACElevel;
+    if (mergetype == MRGredundant) {
+      zinc_(Zneighbor);
+      while (facet2->visible) {
+        if (!facet2->f.replace) {
+          fprintf (qh ferr, "qhull internal error (qh_merge_degenredunant): f%d redundant but f%d has no replacement\n",
+	       facet1->id, facet2->id);
+          qh_errexit2 (qh_ERRqhull, facet1, facet2);
+        }
+        facet2= facet2->f.replace;
+      }
+      if (facet1 == facet2) {
+	qh_degen_redundant_facet (facet1); /* in case of others */
+	continue;
+      }
+      trace2((qh ferr, "qh_merge_degenredundant: facet f%d is contained in f%d, will merge\n",
+	    facet1->id, facet2->id));
+      qh_mergefacet(facet1, facet2, NULL, NULL, !qh_MERGEapex);
+      /* merge distance is already accounted for */
+      nummerges++;
+    }else {  /* mergetype == MRGdegen, other merges may have fixed */
+      if (!(size= qh_setsize (facet1->neighbors))) {
+        zinc_(Zdelfacetdup);
+        trace2((qh ferr, "qh_merge_degenredundant: facet f%d has no neighbors.  Deleted\n", facet1->id));
+        qh_willdelete (facet1, NULL);
+        FOREACHvertex_(facet1->vertices) {
+  	  qh_setdel (vertex->neighbors, facet1);
+	  if (!SETfirst_(vertex->neighbors)) {
+	    zinc_(Zdegenvertex);
+	    trace2((qh ferr, "qh_merge_degenredundant: deleted v%d because f%d has no neighbors\n",
+         	 vertex->id, facet1->id));
+	    vertex->deleted= True;
+	    qh_setappend (&qh del_vertices, vertex);
+	  }
+        }
+        nummerges++;
+      }else if (size < qh hull_dim) {
+        bestneighbor= qh_findbestneighbor(facet1, &dist, &mindist, &maxdist);
+        trace2((qh ferr, "qh_merge_degenredundant: facet f%d has %d neighbors, merge into f%d dist %2.2g\n",
+	      facet1->id, size, bestneighbor->id, dist));
+        qh_mergefacet(facet1, bestneighbor, &mindist, &maxdist, !qh_MERGEapex);
+        nummerges++;
+        if (qh PRINTstatistics) {
+	  zinc_(Zdegen);
+	  wadd_(Wdegentot, dist);
+	  wmax_(Wdegenmax, dist);
+        }
+      }	/* else, another merge fixed the degeneracy and redundancy tested */
+    }
+  }
+  return nummerges;
+} /* merge_degenredundant */
+
+/*---------------------------------
+  
+  qh_merge_nonconvex( facet1, facet2, mergetype )
+    remove non-convex ridge between facet1 into facet2 
+    mergetype gives why the facet's are non-convex
+
+  returns:
+    merges one of the facets into the best neighbor
+    
+  design:
+    if one of the facets is a new facet
+      prefer merging new facet into old facet
+    find best neighbors for both facets
+    merge the nearest facet into its best neighbor
+    update the statistics
+*/
+void qh_merge_nonconvex (facetT *facet1, facetT *facet2, mergeType mergetype) {
+  facetT *bestfacet, *bestneighbor, *neighbor;
+  realT dist, dist2, mindist, mindist2, maxdist, maxdist2;
+
+  if (qh TRACEmerge-1 == zzval_(Ztotmerge))
+    qhmem.IStracing= qh IStracing= qh TRACElevel;
+  trace3((qh ferr, "qh_merge_nonconvex: merge #%d for f%d and f%d type %d\n",
+      zzval_(Ztotmerge) + 1, facet1->id, facet2->id, mergetype));
+  /* concave or coplanar */
+  if (!facet1->newfacet) {
+    bestfacet= facet2;   /* avoid merging old facet if new is ok */
+    facet2= facet1;
+    facet1= bestfacet;
+  }else
+    bestfacet= facet1;
+  bestneighbor= qh_findbestneighbor(bestfacet, &dist, &mindist, &maxdist);
+  neighbor= qh_findbestneighbor(facet2, &dist2, &mindist2, &maxdist2);
+  if (dist < dist2) {
+    qh_mergefacet(bestfacet, bestneighbor, &mindist, &maxdist, !qh_MERGEapex);
+  }else if (qh AVOIDold && !facet2->newfacet
+  && ((mindist >= -qh MAXcoplanar && maxdist <= qh max_outside)
+       || dist * 1.5 < dist2)) {
+    zinc_(Zavoidold);
+    wadd_(Wavoidoldtot, dist);
+    wmax_(Wavoidoldmax, dist);
+    trace2((qh ferr, "qh_merge_nonconvex: avoid merging old facet f%d dist %2.2g.  Use f%d dist %2.2g instead\n",
+           facet2->id, dist2, facet1->id, dist2));
+    qh_mergefacet(bestfacet, bestneighbor, &mindist, &maxdist, !qh_MERGEapex);
+  }else {
+    qh_mergefacet(facet2, neighbor, &mindist2, &maxdist2, !qh_MERGEapex);
+    dist= dist2;
+  }
+  if (qh PRINTstatistics) {
+    if (mergetype == MRGanglecoplanar) {
+      zinc_(Zacoplanar);
+      wadd_(Wacoplanartot, dist);
+      wmax_(Wacoplanarmax, dist);
+    }else if (mergetype == MRGconcave) {
+      zinc_(Zconcave);
+      wadd_(Wconcavetot, dist);
+      wmax_(Wconcavemax, dist);
+    }else { /* MRGcoplanar */
+      zinc_(Zcoplanar);
+      wadd_(Wcoplanartot, dist);
+      wmax_(Wcoplanarmax, dist);
+    }
+  }
+} /* merge_nonconvex */
+
+/*---------------------------------
+  
+  qh_mergecycle( samecycle, newfacet )
+    merge a cycle of facets starting at samecycle into a newfacet 
+    newfacet is a horizon facet with ->normal
+    samecycle facets are simplicial from an apex
+
+  returns:
+    initializes vertex neighbors on first merge
+    samecycle deleted (placed on qh.visible_list)
+    newfacet at end of qh.facet_list
+    deleted vertices on qh.del_vertices
+
+  see:
+    qh_mergefacet()
+    called by qh_mergecycle_all() for multiple, same cycle facets
+
+  design:
+    make vertex neighbors if necessary
+    make ridges for newfacet
+    merge neighbor sets of samecycle into newfacet
+    merge ridges of samecycle into newfacet
+    merge vertex neighbors of samecycle into newfacet
+    make apex of samecycle the apex of newfacet
+    if newfacet wasn't a new facet
+      add its vertices to qh.newvertex_list
+    delete samecycle facets a make newfacet a newfacet
+*/
+void qh_mergecycle (facetT *samecycle, facetT *newfacet) {
+  int traceonce= False, tracerestore= 0;
+  vertexT *apex;
+#ifndef qh_NOtrace
+  facetT *same;
+#endif
+
+  if (newfacet->tricoplanar) {
+    if (!qh TRInormals) {
+      fprintf (qh ferr, "qh_mergecycle: does not work for tricoplanar facets.  Use option 'Q11'\n");
+      qh_errexit (qh_ERRqhull, newfacet, NULL);
+    }
+    newfacet->tricoplanar= False;
+    newfacet->keepcentrum= False;
+  }
+  if (!qh VERTEXneighbors)
+    qh_vertexneighbors();
+  zzinc_(Ztotmerge);
+  if (qh REPORTfreq2 && qh POSTmerging) {
+    if (zzval_(Ztotmerge) > qh mergereport + qh REPORTfreq2)
+      qh_tracemerging();
+  }
+#ifndef qh_NOtrace
+  if (qh TRACEmerge == zzval_(Ztotmerge))
+    qhmem.IStracing= qh IStracing= qh TRACElevel;
+  trace2((qh ferr, "qh_mergecycle: merge #%d for facets from cycle f%d into coplanar horizon f%d\n", 
+        zzval_(Ztotmerge), samecycle->id, newfacet->id));
+  if (newfacet == qh tracefacet) {
+    tracerestore= qh IStracing;
+    qh IStracing= 4;
+    fprintf (qh ferr, "qh_mergecycle: ========= trace merge %d of samecycle %d into trace f%d, furthest is p%d\n",
+	       zzval_(Ztotmerge), samecycle->id, newfacet->id,  qh furthest_id);
+    traceonce= True;
+  }
+  if (qh IStracing >=4) {
+    fprintf (qh ferr, "  same cycle:");
+    FORALLsame_cycle_(samecycle)
+      fprintf(qh ferr, " f%d", same->id);
+    fprintf (qh ferr, "\n");
+  }
+  if (qh IStracing >=4)
+    qh_errprint ("MERGING CYCLE", samecycle, newfacet, NULL, NULL);
+#endif /* !qh_NOtrace */
+  apex= SETfirstt_(samecycle->vertices, vertexT);
+  qh_makeridges (newfacet);
+  qh_mergecycle_neighbors (samecycle, newfacet);
+  qh_mergecycle_ridges (samecycle, newfacet);
+  qh_mergecycle_vneighbors (samecycle, newfacet);
+  if (SETfirstt_(newfacet->vertices, vertexT) != apex) 
+    qh_setaddnth (&newfacet->vertices, 0, apex);  /* apex has last id */
+  if (!newfacet->newfacet)
+    qh_newvertices (newfacet->vertices);
+  qh_mergecycle_facets (samecycle, newfacet);
+  qh_tracemerge (samecycle, newfacet);
+  /* check for degen_redundant_neighbors after qh_forcedmerges() */
+  if (traceonce) {
+    fprintf (qh ferr, "qh_mergecycle: end of trace facet\n");
+    qh IStracing= tracerestore;
+  }
+} /* mergecycle */
+
+/*---------------------------------
+  
+  qh_mergecycle_all( facetlist, wasmerge )
+    merge all samecycles of coplanar facets into horizon
+    don't merge facets with ->mergeridge (these already have ->normal)
+    all facets are simplicial from apex
+    all facet->cycledone == False
+
+  returns:
+    all newfacets merged into coplanar horizon facets
+    deleted vertices on  qh.del_vertices
+    sets wasmerge if any merge
+
+  see:
+    calls qh_mergecycle for multiple, same cycle facets
+
+  design:
+    for each facet on facetlist
+      skip facets with duplicate ridges and normals
+      check that facet is in a samecycle (->mergehorizon)
+      if facet only member of samecycle
+	sets vertex->delridge for all vertices except apex
+        merge facet into horizon
+      else
+        mark all facets in samecycle
+        remove facets with duplicate ridges from samecycle
+        merge samecycle into horizon (deletes facets from facetlist)
+*/
+void qh_mergecycle_all (facetT *facetlist, boolT *wasmerge) {
+  facetT *facet, *same, *prev, *horizon;
+  facetT *samecycle= NULL, *nextfacet, *nextsame;
+  vertexT *apex, *vertex, **vertexp;
+  int cycles=0, total=0, facets, nummerge;
+
+  trace2((qh ferr, "qh_mergecycle_all: begin\n"));
+  for (facet= facetlist; facet && (nextfacet= facet->next); facet= nextfacet) {
+    if (facet->normal)
+      continue;
+    if (!facet->mergehorizon) {
+      fprintf (qh ferr, "qh_mergecycle_all: f%d without normal\n", facet->id);
+      qh_errexit (qh_ERRqhull, facet, NULL);
+    }
+    horizon= SETfirstt_(facet->neighbors, facetT);
+    if (facet->f.samecycle == facet) {
+      zinc_(Zonehorizon);  
+      /* merge distance done in qh_findhorizon */
+      apex= SETfirstt_(facet->vertices, vertexT);
+      FOREACHvertex_(facet->vertices) {
+	if (vertex != apex)
+          vertex->delridge= True;
+      }
+      horizon->f.newcycle= NULL;
+      qh_mergefacet (facet, horizon, NULL, NULL, qh_MERGEapex);
+    }else {
+      samecycle= facet;
+      facets= 0;
+      prev= facet;
+      for (same= facet->f.samecycle; same;  /* FORALLsame_cycle_(facet) */
+	   same= (same == facet ? NULL :nextsame)) { /* ends at facet */
+	nextsame= same->f.samecycle;
+        if (same->cycledone || same->visible)
+          qh_infiniteloop (same);
+        same->cycledone= True;
+        if (same->normal) { 
+          prev->f.samecycle= same->f.samecycle; /* unlink ->mergeridge */
+	  same->f.samecycle= NULL;
+        }else {
+          prev= same;
+	  facets++;
+	}
+      }
+      while (nextfacet && nextfacet->cycledone)  /* will delete samecycle */
+	nextfacet= nextfacet->next;
+      horizon->f.newcycle= NULL;
+      qh_mergecycle (samecycle, horizon);
+      nummerge= horizon->nummerge + facets;
+      if (nummerge > qh_MAXnummerge) 
+      	horizon->nummerge= qh_MAXnummerge;
+      else
+        horizon->nummerge= nummerge;
+      zzinc_(Zcyclehorizon);
+      total += facets;
+      zzadd_(Zcyclefacettot, facets);
+      zmax_(Zcyclefacetmax, facets);
+    }
+    cycles++;
+  }
+  if (cycles)
+    *wasmerge= True;
+  trace1((qh ferr, "qh_mergecycle_all: merged %d same cycles or facets into coplanar horizons\n", cycles));
+} /* mergecycle_all */
+
+/*---------------------------------
+  
+  qh_mergecycle_facets( samecycle, newfacet )
+    finish merge of samecycle into newfacet
+
+  returns:
+    samecycle prepended to visible_list for later deletion and partitioning
+      each facet->f.replace == newfacet
+      
+    newfacet moved to end of qh.facet_list
+      makes newfacet a newfacet (get's facet1->id if it was old)
+      sets newfacet->newmerge
+      clears newfacet->center (unless merging into a large facet)
+      clears newfacet->tested and ridge->tested for facet1
+      
+    adds neighboring facets to facet_mergeset if redundant or degenerate
+
+  design:
+    make newfacet a new facet and set its flags
+    move samecycle facets to qh.visible_list for later deletion
+    unless newfacet is large
+      remove its centrum
+*/
+void qh_mergecycle_facets (facetT *samecycle, facetT *newfacet) {
+  facetT *same, *next;
+  
+  trace4((qh ferr, "qh_mergecycle_facets: make newfacet new and samecycle deleted\n"));  
+  qh_removefacet(newfacet);  /* append as a newfacet to end of qh facet_list */
+  qh_appendfacet(newfacet);
+  newfacet->newfacet= True;
+  newfacet->simplicial= False;
+  newfacet->newmerge= True;
+  
+  for (same= samecycle->f.samecycle; same; same= (same == samecycle ?  NULL : next)) {
+    next= same->f.samecycle;  /* reused by willdelete */
+    qh_willdelete (same, newfacet);
+  }
+  if (newfacet->center 
+      && qh_setsize (newfacet->vertices) <= qh hull_dim + qh_MAXnewcentrum) {
+    qh_memfree (newfacet->center, qh normal_size);
+    newfacet->center= NULL;
+  }
+  trace3((qh ferr, "qh_mergecycle_facets: merged facets from cycle f%d into f%d\n", 
+             samecycle->id, newfacet->id));
+} /* mergecycle_facets */
+
+/*---------------------------------
+  
+  qh_mergecycle_neighbors( samecycle, newfacet )
+    add neighbors for samecycle facets to newfacet
+
+  returns:
+    newfacet with updated neighbors and vice-versa
+    newfacet has ridges
+    all neighbors of newfacet marked with qh.visit_id
+    samecycle facets marked with qh.visit_id-1
+    ridges updated for simplicial neighbors of samecycle with a ridge
+
+  notes:
+    assumes newfacet not in samecycle
+    usually, samecycle facets are new, simplicial facets without internal ridges 
+      not so if horizon facet is coplanar to two different samecycles
+  
+  see:
+    qh_mergeneighbors()
+
+  design:
+    check samecycle
+    delete neighbors from newfacet that are also in samecycle
+    for each neighbor of a facet in samecycle
+      if neighbor is simplicial
+        if first visit
+          move the neighbor relation to newfacet
+          update facet links for its ridges
+        else
+          make ridges for neighbor
+          remove samecycle reference
+      else
+        update neighbor sets
+*/
+void qh_mergecycle_neighbors(facetT *samecycle, facetT *newfacet) {
+  facetT *same, *neighbor, **neighborp;
+  int delneighbors= 0, newneighbors= 0;
+  unsigned int samevisitid;
+  ridgeT *ridge, **ridgep;
+
+  samevisitid= ++qh visit_id;
+  FORALLsame_cycle_(samecycle) {
+    if (same->visitid == samevisitid || same->visible)
+      qh_infiniteloop (samecycle);
+    same->visitid= samevisitid;
+  }
+  newfacet->visitid= ++qh visit_id;
+  trace4((qh ferr, "qh_mergecycle_neighbors: delete shared neighbors from newfacet\n"));  
+  FOREACHneighbor_(newfacet) {
+    if (neighbor->visitid == samevisitid) {
+      SETref_(neighbor)= NULL;  /* samecycle neighbors deleted */
+      delneighbors++;
+    }else
+      neighbor->visitid= qh visit_id;
+  }
+  qh_setcompact (newfacet->neighbors);
+
+  trace4((qh ferr, "qh_mergecycle_neighbors: update neighbors\n"));  
+  FORALLsame_cycle_(samecycle) {
+    FOREACHneighbor_(same) {
+      if (neighbor->visitid == samevisitid)
+	continue;
+      if (neighbor->simplicial) {
+	if (neighbor->visitid != qh visit_id) {
+	  qh_setappend (&newfacet->neighbors, neighbor);
+	  qh_setreplace (neighbor->neighbors, same, newfacet);
+	  newneighbors++;
+	  neighbor->visitid= qh visit_id;
+	  FOREACHridge_(neighbor->ridges) { /* update ridge in case of qh_makeridges */
+	    if (ridge->top == same) {
+	      ridge->top= newfacet;
+	      break;
+	    }else if (ridge->bottom == same) {
+	      ridge->bottom= newfacet;
+	      break;
+	    }
+	  }
+	}else {
+	  qh_makeridges (neighbor);
+	  qh_setdel (neighbor->neighbors, same);
+	  /* same can't be horizon facet for neighbor */
+	}
+      }else { /* non-simplicial neighbor */
+        qh_setdel (neighbor->neighbors, same);
+        if (neighbor->visitid != qh visit_id) {
+          qh_setappend (&neighbor->neighbors, newfacet);
+          qh_setappend (&newfacet->neighbors, neighbor);
+          neighbor->visitid= qh visit_id;
+          newneighbors++;
+        } 
+      }
+    }
+  }
+  trace2((qh ferr, "qh_mergecycle_neighbors: deleted %d neighbors and added %d\n", 
+             delneighbors, newneighbors));
+} /* mergecycle_neighbors */
+
+/*---------------------------------
+  
+  qh_mergecycle_ridges( samecycle, newfacet )
+    add ridges/neighbors for facets in samecycle to newfacet
+    all new/old neighbors of newfacet marked with qh.visit_id
+    facets in samecycle marked with qh.visit_id-1
+    newfacet marked with qh.visit_id
+
+  returns:
+    newfacet has merged ridges
+  
+  notes:
+    ridge already updated for simplicial neighbors of samecycle with a ridge
+
+  see:
+    qh_mergeridges()
+    qh_makeridges()
+
+  design:
+    remove ridges between newfacet and samecycle
+    for each facet in samecycle
+      for each ridge in facet
+        update facet pointers in ridge
+        skip ridges processed in qh_mergecycle_neighors
+        free ridges between newfacet and samecycle
+        free ridges between facets of samecycle (on 2nd visit)
+        append remaining ridges to newfacet
+      if simpilicial facet
+        for each neighbor of facet
+          if simplicial facet
+          and not samecycle facet or newfacet
+            make ridge between neighbor and newfacet
+*/
+void qh_mergecycle_ridges(facetT *samecycle, facetT *newfacet) {
+  facetT *same, *neighbor= NULL;
+  int numold=0, numnew=0;
+  int neighbor_i, neighbor_n;
+  unsigned int samevisitid;
+  ridgeT *ridge, **ridgep;
+  boolT toporient;
+  void **freelistp; /* used !qh_NOmem */
+
+  trace4((qh ferr, "qh_mergecycle_ridges: delete shared ridges from newfacet\n"));  
+  samevisitid= qh visit_id -1;
+  FOREACHridge_(newfacet->ridges) {
+    neighbor= otherfacet_(ridge, newfacet);
+    if (neighbor->visitid == samevisitid)
+      SETref_(ridge)= NULL; /* ridge free'd below */  
+  }
+  qh_setcompact (newfacet->ridges);
+  
+  trace4((qh ferr, "qh_mergecycle_ridges: add ridges to newfacet\n"));  
+  FORALLsame_cycle_(samecycle) {
+    FOREACHridge_(same->ridges) {
+      if (ridge->top == same) {
+        ridge->top= newfacet;
+	neighbor= ridge->bottom;
+      }else if (ridge->bottom == same) {
+	ridge->bottom= newfacet;
+	neighbor= ridge->top;
+      }else if (ridge->top == newfacet || ridge->bottom == newfacet) {
+        qh_setappend (&newfacet->ridges, ridge);
+        numold++;  /* already set by qh_mergecycle_neighbors */
+	continue;  
+      }else {
+	fprintf (qh ferr, "qhull internal error (qh_mergecycle_ridges): bad ridge r%d\n", ridge->id);
+	qh_errexit (qh_ERRqhull, NULL, ridge);
+      }
+      if (neighbor == newfacet) {
+        qh_setfree(&(ridge->vertices)); 
+        qh_memfree_(ridge, sizeof(ridgeT), freelistp);
+        numold++;
+      }else if (neighbor->visitid == samevisitid) {
+	qh_setdel (neighbor->ridges, ridge);
+	qh_setfree(&(ridge->vertices)); 
+	qh_memfree_(ridge, sizeof(ridgeT), freelistp);
+	numold++;
+      }else {
+        qh_setappend (&newfacet->ridges, ridge);
+        numold++;
+      }
+    }
+    if (same->ridges)
+      qh_settruncate (same->ridges, 0);
+    if (!same->simplicial)
+      continue;
+    FOREACHneighbor_i_(same) {       /* note: !newfact->simplicial */
+      if (neighbor->visitid != samevisitid && neighbor->simplicial) {
+        ridge= qh_newridge();
+        ridge->vertices= qh_setnew_delnthsorted (same->vertices, qh hull_dim,
+  					                  neighbor_i, 0);
+        toporient= same->toporient ^ (neighbor_i & 0x1);
+        if (toporient) {
+          ridge->top= newfacet;
+          ridge->bottom= neighbor;
+        }else {
+          ridge->top= neighbor;
+          ridge->bottom= newfacet;
+        }
+        qh_setappend(&(newfacet->ridges), ridge);
+        qh_setappend(&(neighbor->ridges), ridge);
+        numnew++;
+      }
+    }
+  }
+
+  trace2((qh ferr, "qh_mergecycle_ridges: found %d old ridges and %d new ones\n", 
+             numold, numnew));
+} /* mergecycle_ridges */
+
+/*---------------------------------
+  
+  qh_mergecycle_vneighbors( samecycle, newfacet )
+    create vertex neighbors for newfacet from vertices of facets in samecycle
+    samecycle marked with visitid == qh.visit_id - 1
+
+  returns:
+    newfacet vertices with updated neighbors
+    marks newfacet with qh.visit_id-1
+    deletes vertices that are merged away
+    sets delridge on all vertices (faster here than in mergecycle_ridges)
+
+  see:
+    qh_mergevertex_neighbors()
+
+  design:
+    for each vertex of samecycle facet
+      set vertex->delridge
+      delete samecycle facets from vertex neighbors
+      append newfacet to vertex neighbors
+      if vertex only in newfacet
+        delete it from newfacet
+        add it to qh.del_vertices for later deletion
+*/
+void qh_mergecycle_vneighbors (facetT *samecycle, facetT *newfacet) {
+  facetT *neighbor, **neighborp;
+  unsigned int mergeid;
+  vertexT *vertex, **vertexp, *apex;
+  setT *vertices;
+  
+  trace4((qh ferr, "qh_mergecycle_vneighbors: update vertex neighbors for newfacet\n"));  
+  mergeid= qh visit_id - 1;
+  newfacet->visitid= mergeid;
+  vertices= qh_basevertices (samecycle); /* temp */
+  apex= SETfirstt_(samecycle->vertices, vertexT);
+  qh_setappend (&vertices, apex);
+  FOREACHvertex_(vertices) {
+    vertex->delridge= True;
+    FOREACHneighbor_(vertex) {
+      if (neighbor->visitid == mergeid)
+        SETref_(neighbor)= NULL;
+    }
+    qh_setcompact (vertex->neighbors);
+    qh_setappend (&vertex->neighbors, newfacet);
+    if (!SETsecond_(vertex->neighbors)) {
+      zinc_(Zcyclevertex);
+      trace2((qh ferr, "qh_mergecycle_vneighbors: deleted v%d when merging cycle f%d into f%d\n",
+        vertex->id, samecycle->id, newfacet->id));
+      qh_setdelsorted (newfacet->vertices, vertex);
+      vertex->deleted= True;
+      qh_setappend (&qh del_vertices, vertex);
+    }
+  }
+  qh_settempfree (&vertices);
+  trace3((qh ferr, "qh_mergecycle_vneighbors: merged vertices from cycle f%d into f%d\n", 
+             samecycle->id, newfacet->id));
+} /* mergecycle_vneighbors */
+
+/*---------------------------------
+  
+  qh_mergefacet( facet1, facet2, mindist, maxdist, mergeapex )
+    merges facet1 into facet2
+    mergeapex==qh_MERGEapex if merging new facet into coplanar horizon
+    
+  returns:
+    qh.max_outside and qh.min_vertex updated
+    initializes vertex neighbors on first merge
+
+  returns:
+    facet2 contains facet1's vertices, neighbors, and ridges
+      facet2 moved to end of qh.facet_list
+      makes facet2 a newfacet
+      sets facet2->newmerge set
+      clears facet2->center (unless merging into a large facet)
+      clears facet2->tested and ridge->tested for facet1
+
+    facet1 prepended to visible_list for later deletion and partitioning
+      facet1->f.replace == facet2
+
+    adds neighboring facets to facet_mergeset if redundant or degenerate
+
+  notes: 
+    mindist/maxdist may be NULL
+    traces merge if fmax_(maxdist,-mindist) > TRACEdist
+
+  see: 
+    qh_mergecycle()
+
+  design:
+    trace merge and check for degenerate simplex
+    make ridges for both facets
+    update qh.max_outside, qh.max_vertex, qh.min_vertex
+    update facet2->maxoutside and keepcentrum
+    update facet2->nummerge
+    update tested flags for facet2
+    if facet1 is simplicial
+      merge facet1 into facet2
+    else
+      merge facet1's neighbors into facet2
+      merge facet1's ridges into facet2
+      merge facet1's vertices into facet2
+      merge facet1's vertex neighbors into facet2
+      add facet2's vertices to qh.new_vertexlist
+      unless qh_MERGEapex
+        test facet2 for degenerate or redundant neighbors
+      move facet1 to qh.visible_list for later deletion
+      move facet2 to end of qh.newfacet_list
+*/
+void qh_mergefacet(facetT *facet1, facetT *facet2, realT *mindist, realT *maxdist, boolT mergeapex) {
+  boolT traceonce= False;
+  vertexT *vertex, **vertexp;
+  int tracerestore=0, nummerge;
+
+  if (facet1->tricoplanar || facet2->tricoplanar) {
+    if (!qh TRInormals) {
+      fprintf (qh ferr, "qh_mergefacet: does not work for tricoplanar facets.  Use option 'Q11'\n");
+      qh_errexit2 (qh_ERRqhull, facet1, facet2);
+    }
+    if (facet2->tricoplanar) {
+      facet2->tricoplanar= False;
+      facet2->keepcentrum= False;
+    }
+  }
+  zzinc_(Ztotmerge);
+  if (qh REPORTfreq2 && qh POSTmerging) {
+    if (zzval_(Ztotmerge) > qh mergereport + qh REPORTfreq2)
+      qh_tracemerging();
+  }
+#ifndef qh_NOtrace
+  if (qh build_cnt >= qh RERUN) {
+    if (mindist && (-*mindist > qh TRACEdist || *maxdist > qh TRACEdist)) {
+      tracerestore= 0;
+      qh IStracing= qh TRACElevel;
+      traceonce= True;
+      fprintf (qh ferr, "qh_mergefacet: ========= trace wide merge #%d (%2.2g) for f%d into f%d, last point was p%d\n", zzval_(Ztotmerge),
+	     fmax_(-*mindist, *maxdist), facet1->id, facet2->id, qh furthest_id);
+    }else if (facet1 == qh tracefacet || facet2 == qh tracefacet) {
+      tracerestore= qh IStracing;
+      qh IStracing= 4;
+      traceonce= True;
+      fprintf (qh ferr, "qh_mergefacet: ========= trace merge #%d involving f%d, furthest is p%d\n",
+		 zzval_(Ztotmerge), qh tracefacet_id,  qh furthest_id);
+    }
+  }
+  if (qh IStracing >= 2) {
+    realT mergemin= -2;
+    realT mergemax= -2;
+    
+    if (mindist) {
+      mergemin= *mindist;
+      mergemax= *maxdist;
+    }
+    fprintf (qh ferr, "qh_mergefacet: #%d merge f%d into f%d, mindist= %2.2g, maxdist= %2.2g\n", 
+    zzval_(Ztotmerge), facet1->id, facet2->id, mergemin, mergemax);
+  }
+#endif /* !qh_NOtrace */
+  if (facet1 == facet2 || facet1->visible || facet2->visible) {
+    fprintf (qh ferr, "qhull internal error (qh_mergefacet): either f%d and f%d are the same or one is a visible facet\n",
+	     facet1->id, facet2->id);
+    qh_errexit2 (qh_ERRqhull, facet1, facet2);
+  }
+  if (qh num_facets - qh num_visible <= qh hull_dim + 1) {
+    fprintf(qh ferr, "\n\
+qhull precision error: Only %d facets remain.  Can not merge another\n\
+pair.  The input is too degenerate or the convexity constraints are\n\
+too strong.\n", qh hull_dim+1);
+    if (qh hull_dim >= 5 && !qh MERGEexact)
+      fprintf(qh ferr, "Option 'Qx' may avoid this problem.\n");
+    qh_errexit(qh_ERRinput, NULL, NULL);
+  }
+  if (!qh VERTEXneighbors)
+    qh_vertexneighbors();
+  qh_makeridges(facet1);
+  qh_makeridges(facet2);
+  if (qh IStracing >=4)
+    qh_errprint ("MERGING", facet1, facet2, NULL, NULL);
+  if (mindist) {
+    maximize_(qh max_outside, *maxdist);
+    maximize_(qh max_vertex, *maxdist);
+#if qh_MAXoutside
+    maximize_(facet2->maxoutside, *maxdist);
+#endif
+    minimize_(qh min_vertex, *mindist);
+    if (!facet2->keepcentrum 
+    && (*maxdist > qh WIDEfacet || *mindist < -qh WIDEfacet)) {
+      facet2->keepcentrum= True;
+      zinc_(Zwidefacet);
+    }
+  }
+  nummerge= facet1->nummerge + facet2->nummerge + 1;
+  if (nummerge >= qh_MAXnummerge) 
+    facet2->nummerge= qh_MAXnummerge;
+  else
+    facet2->nummerge= nummerge;
+  facet2->newmerge= True;
+  facet2->dupridge= False;
+  qh_updatetested  (facet1, facet2);
+  if (qh hull_dim > 2 && qh_setsize (facet1->vertices) == qh hull_dim)
+    qh_mergesimplex (facet1, facet2, mergeapex);
+  else {
+    qh vertex_visit++;
+    FOREACHvertex_(facet2->vertices)
+      vertex->visitid= qh vertex_visit;
+    if (qh hull_dim == 2) 
+      qh_mergefacet2d(facet1, facet2);
+    else {
+      qh_mergeneighbors(facet1, facet2);
+      qh_mergevertices(facet1->vertices, &facet2->vertices);
+    }
+    qh_mergeridges(facet1, facet2);
+    qh_mergevertex_neighbors(facet1, facet2);
+    if (!facet2->newfacet)
+      qh_newvertices (facet2->vertices);
+  }
+  if (!mergeapex)
+    qh_degen_redundant_neighbors (facet2, facet1);
+  if (facet2->coplanar || !facet2->newfacet) {
+    zinc_(Zmergeintohorizon);
+  }else if (!facet1->newfacet && facet2->newfacet) {
+    zinc_(Zmergehorizon);
+  }else {
+    zinc_(Zmergenew);
+  }
+  qh_willdelete (facet1, facet2);
+  qh_removefacet(facet2);  /* append as a newfacet to end of qh facet_list */
+  qh_appendfacet(facet2);
+  facet2->newfacet= True;
+  facet2->tested= False;
+  qh_tracemerge (facet1, facet2);
+  if (traceonce) {
+    fprintf (qh ferr, "qh_mergefacet: end of wide tracing\n");
+    qh IStracing= tracerestore;
+  }
+} /* mergefacet */
+
+
+/*---------------------------------
+  
+  qh_mergefacet2d( facet1, facet2 )
+    in 2d, merges neighbors and vertices of facet1 into facet2
+    
+  returns:
+    build ridges for neighbors if necessary
+    facet2 looks like a simplicial facet except for centrum, ridges
+      neighbors are opposite the corresponding vertex
+      maintains orientation of facet2
+
+  notes:
+    qh_mergefacet() retains non-simplicial structures
+      they are not needed in 2d, but later routines may use them
+    preserves qh.vertex_visit for qh_mergevertex_neighbors()
+  
+  design:
+    get vertices and neighbors
+    determine new vertices and neighbors
+    set new vertices and neighbors and adjust orientation
+    make ridges for new neighbor if needed
+*/
+void qh_mergefacet2d (facetT *facet1, facetT *facet2) {
+  vertexT *vertex1A, *vertex1B, *vertex2A, *vertex2B, *vertexA, *vertexB;
+  facetT *neighbor1A, *neighbor1B, *neighbor2A, *neighbor2B, *neighborA, *neighborB;
+
+  vertex1A= SETfirstt_(facet1->vertices, vertexT);
+  vertex1B= SETsecondt_(facet1->vertices, vertexT);
+  vertex2A= SETfirstt_(facet2->vertices, vertexT);
+  vertex2B= SETsecondt_(facet2->vertices, vertexT);
+  neighbor1A= SETfirstt_(facet1->neighbors, facetT);
+  neighbor1B= SETsecondt_(facet1->neighbors, facetT);
+  neighbor2A= SETfirstt_(facet2->neighbors, facetT);
+  neighbor2B= SETsecondt_(facet2->neighbors, facetT);
+  if (vertex1A == vertex2A) {
+    vertexA= vertex1B;
+    vertexB= vertex2B;
+    neighborA= neighbor2A;
+    neighborB= neighbor1A;
+  }else if (vertex1A == vertex2B) {
+    vertexA= vertex1B;
+    vertexB= vertex2A;
+    neighborA= neighbor2B;
+    neighborB= neighbor1A;
+  }else if (vertex1B == vertex2A) {
+    vertexA= vertex1A;
+    vertexB= vertex2B;
+    neighborA= neighbor2A;
+    neighborB= neighbor1B;
+  }else { /* 1B == 2B */
+    vertexA= vertex1A;
+    vertexB= vertex2A;
+    neighborA= neighbor2B;
+    neighborB= neighbor1B;
+  }
+  /* vertexB always from facet2, neighborB always from facet1 */
+  if (vertexA->id > vertexB->id) {
+    SETfirst_(facet2->vertices)= vertexA;
+    SETsecond_(facet2->vertices)= vertexB;
+    if (vertexB == vertex2A)
+      facet2->toporient= !facet2->toporient;
+    SETfirst_(facet2->neighbors)= neighborA;
+    SETsecond_(facet2->neighbors)= neighborB;
+  }else {
+    SETfirst_(facet2->vertices)= vertexB;
+    SETsecond_(facet2->vertices)= vertexA;
+    if (vertexB == vertex2B)
+      facet2->toporient= !facet2->toporient;
+    SETfirst_(facet2->neighbors)= neighborB;
+    SETsecond_(facet2->neighbors)= neighborA;
+  }
+  qh_makeridges (neighborB);
+  qh_setreplace(neighborB->neighbors, facet1, facet2);
+  trace4((qh ferr, "qh_mergefacet2d: merged v%d and neighbor f%d of f%d into f%d\n",
+       vertexA->id, neighborB->id, facet1->id, facet2->id));
+} /* mergefacet2d */
+
+
+/*---------------------------------
+  
+  qh_mergeneighbors( facet1, facet2 )
+    merges the neighbors of facet1 into facet2
+
+  see: 
+    qh_mergecycle_neighbors()
+
+  design:
+    for each neighbor of facet1
+      if neighbor is also a neighbor of facet2
+        if neighbor is simpilicial
+          make ridges for later deletion as a degenerate facet
+        update its neighbor set
+      else
+        move the neighbor relation to facet2
+    remove the neighbor relation for facet1 and facet2
+*/
+void qh_mergeneighbors(facetT *facet1, facetT *facet2) {
+  facetT *neighbor, **neighborp;
+
+  trace4((qh ferr, "qh_mergeneighbors: merge neighbors of f%d and f%d\n",
+	  facet1->id, facet2->id));
+  qh visit_id++;
+  FOREACHneighbor_(facet2) {
+    neighbor->visitid= qh visit_id;
+  }
+  FOREACHneighbor_(facet1) {
+    if (neighbor->visitid == qh visit_id) {
+      if (neighbor->simplicial)    /* is degen, needs ridges */
+	qh_makeridges (neighbor);
+      if (SETfirstt_(neighbor->neighbors, facetT) != facet1) /*keep newfacet->horizon*/
+	qh_setdel (neighbor->neighbors, facet1);
+      else {
+        qh_setdel(neighbor->neighbors, facet2);
+        qh_setreplace(neighbor->neighbors, facet1, facet2);
+      }
+    }else if (neighbor != facet2) {
+      qh_setappend(&(facet2->neighbors), neighbor);
+      qh_setreplace(neighbor->neighbors, facet1, facet2);
+    }
+  }
+  qh_setdel(facet1->neighbors, facet2);  /* here for makeridges */
+  qh_setdel(facet2->neighbors, facet1);
+} /* mergeneighbors */
+
+
+/*---------------------------------
+  
+  qh_mergeridges( facet1, facet2 )
+    merges the ridge set of facet1 into facet2
+
+  returns:
+    may delete all ridges for a vertex
+    sets vertex->delridge on deleted ridges
+
+  see:
+    qh_mergecycle_ridges()
+
+  design:
+    delete ridges between facet1 and facet2
+      mark (delridge) vertices on these ridges for later testing   
+    for each remaining ridge
+      rename facet1 to facet2  
+*/
+void qh_mergeridges(facetT *facet1, facetT *facet2) {
+  ridgeT *ridge, **ridgep;
+  vertexT *vertex, **vertexp;
+
+  trace4((qh ferr, "qh_mergeridges: merge ridges of f%d and f%d\n",
+	  facet1->id, facet2->id));
+  FOREACHridge_(facet2->ridges) {
+    if ((ridge->top == facet1) || (ridge->bottom == facet1)) {
+      FOREACHvertex_(ridge->vertices)
+        vertex->delridge= True;
+      qh_delridge(ridge);  /* expensive in high-d, could rebuild */
+      ridgep--; /*repeat*/
+    }
+  }
+  FOREACHridge_(facet1->ridges) {
+    if (ridge->top == facet1)
+      ridge->top= facet2;
+    else
+      ridge->bottom= facet2;
+    qh_setappend(&(facet2->ridges), ridge);
+  }
+} /* mergeridges */
+
+
+/*---------------------------------
+  
+  qh_mergesimplex( facet1, facet2, mergeapex )
+    merge simplicial facet1 into facet2
+    mergeapex==qh_MERGEapex if merging samecycle into horizon facet
+      vertex id is latest (most recently created)
+    facet1 may be contained in facet2
+    ridges exist for both facets
+
+  returns:
+    facet2 with updated vertices, ridges, neighbors
+    updated neighbors for facet1's vertices
+    facet1 not deleted
+    sets vertex->delridge on deleted ridges
+  
+  notes:
+    special case code since this is the most common merge
+    called from qh_mergefacet()
+
+  design:
+    if qh_MERGEapex
+      add vertices of facet2 to qh.new_vertexlist if necessary
+      add apex to facet2
+    else
+      for each ridge between facet1 and facet2
+        set vertex->delridge
+      determine the apex for facet1 (i.e., vertex to be merged)
+      unless apex already in facet2
+        insert apex into vertices for facet2
+      add vertices of facet2 to qh.new_vertexlist if necessary
+      add apex to qh.new_vertexlist if necessary
+      for each vertex of facet1
+        if apex
+          rename facet1 to facet2 in its vertex neighbors
+        else
+          delete facet1 from vertex neighors
+          if only in facet2
+            add vertex to qh.del_vertices for later deletion
+      for each ridge of facet1
+        delete ridges between facet1 and facet2
+        append other ridges to facet2 after renaming facet to facet2
+*/
+void qh_mergesimplex(facetT *facet1, facetT *facet2, boolT mergeapex) {
+  vertexT *vertex, **vertexp, *apex;
+  ridgeT *ridge, **ridgep;
+  boolT issubset= False;
+  int vertex_i= -1, vertex_n;
+  facetT *neighbor, **neighborp, *otherfacet;
+
+  if (mergeapex) {
+    if (!facet2->newfacet)
+      qh_newvertices (facet2->vertices);  /* apex is new */
+    apex= SETfirstt_(facet1->vertices, vertexT);
+    if (SETfirstt_(facet2->vertices, vertexT) != apex) 
+      qh_setaddnth (&facet2->vertices, 0, apex);  /* apex has last id */
+    else
+      issubset= True;
+  }else {
+    zinc_(Zmergesimplex);
+    FOREACHvertex_(facet1->vertices)
+      vertex->seen= False;
+    FOREACHridge_(facet1->ridges) {
+      if (otherfacet_(ridge, facet1) == facet2) {
+	FOREACHvertex_(ridge->vertices) {
+	  vertex->seen= True;
+	  vertex->delridge= True;
+	}
+	break;
+      }
+    }
+    FOREACHvertex_(facet1->vertices) {
+      if (!vertex->seen)
+	break;  /* must occur */
+    }
+    apex= vertex;
+    trace4((qh ferr, "qh_mergesimplex: merge apex v%d of f%d into facet f%d\n",
+	  apex->id, facet1->id, facet2->id));
+    FOREACHvertex_i_(facet2->vertices) {
+      if (vertex->id < apex->id) {
+	break;
+      }else if (vertex->id == apex->id) {
+	issubset= True;
+	break;
+      }
+    }
+    if (!issubset)
+      qh_setaddnth (&facet2->vertices, vertex_i, apex);
+    if (!facet2->newfacet)
+      qh_newvertices (facet2->vertices);
+    else if (!apex->newlist) {
+      qh_removevertex (apex);
+      qh_appendvertex (apex);
+    }
+  }
+  trace4((qh ferr, "qh_mergesimplex: update vertex neighbors of f%d\n",
+	  facet1->id));
+  FOREACHvertex_(facet1->vertices) {
+    if (vertex == apex && !issubset)
+      qh_setreplace (vertex->neighbors, facet1, facet2);
+    else {
+      qh_setdel (vertex->neighbors, facet1);
+      if (!SETsecond_(vertex->neighbors))
+	qh_mergevertex_del (vertex, facet1, facet2);
+    }
+  }
+  trace4((qh ferr, "qh_mergesimplex: merge ridges and neighbors of f%d into f%d\n",
+	  facet1->id, facet2->id));
+  qh visit_id++;
+  FOREACHneighbor_(facet2)
+    neighbor->visitid= qh visit_id;
+  FOREACHridge_(facet1->ridges) {
+    otherfacet= otherfacet_(ridge, facet1);
+    if (otherfacet == facet2) {
+      qh_setdel (facet2->ridges, ridge);
+      qh_setfree(&(ridge->vertices)); 
+      qh_memfree (ridge, sizeof(ridgeT));
+      qh_setdel (facet2->neighbors, facet1);
+    }else {
+      qh_setappend (&facet2->ridges, ridge);
+      if (otherfacet->visitid != qh visit_id) {
+	qh_setappend (&facet2->neighbors, otherfacet);
+	qh_setreplace (otherfacet->neighbors, facet1, facet2);
+	otherfacet->visitid= qh visit_id;
+      }else {
+	if (otherfacet->simplicial)    /* is degen, needs ridges */
+	  qh_makeridges (otherfacet);
+	if (SETfirstt_(otherfacet->neighbors, facetT) != facet1)
+	  qh_setdel (otherfacet->neighbors, facet1);
+	else {   /*keep newfacet->neighbors->horizon*/
+	  qh_setdel(otherfacet->neighbors, facet2);
+	  qh_setreplace(otherfacet->neighbors, facet1, facet2);
+	}
+      }
+      if (ridge->top == facet1) /* wait until after qh_makeridges */
+	ridge->top= facet2;
+      else 
+	ridge->bottom= facet2;
+    }
+  }
+  SETfirst_(facet1->ridges)= NULL; /* it will be deleted */
+  trace3((qh ferr, "qh_mergesimplex: merged simplex f%d apex v%d into facet f%d\n",
+	  facet1->id, getid_(apex), facet2->id));
+} /* mergesimplex */
+
+/*---------------------------------
+  
+  qh_mergevertex_del( vertex, facet1, facet2 )
+    delete a vertex because of merging facet1 into facet2
+
+  returns:
+    deletes vertex from facet2
+    adds vertex to qh.del_vertices for later deletion 
+*/
+void qh_mergevertex_del (vertexT *vertex, facetT *facet1, facetT *facet2) {
+
+  zinc_(Zmergevertex);
+  trace2((qh ferr, "qh_mergevertex_del: deleted v%d when merging f%d into f%d\n",
+          vertex->id, facet1->id, facet2->id));
+  qh_setdelsorted (facet2->vertices, vertex);
+  vertex->deleted= True;
+  qh_setappend (&qh del_vertices, vertex);
+} /* mergevertex_del */
+
+/*---------------------------------
+  
+  qh_mergevertex_neighbors( facet1, facet2 )
+    merge the vertex neighbors of facet1 to facet2
+
+  returns:
+    if vertex is current qh.vertex_visit
+      deletes facet1 from vertex->neighbors
+    else
+      renames facet1 to facet2 in vertex->neighbors 
+    deletes vertices if only one neighbor
+  
+  notes:
+    assumes vertex neighbor sets are good
+*/
+void qh_mergevertex_neighbors(facetT *facet1, facetT *facet2) {
+  vertexT *vertex, **vertexp;
+
+  trace4((qh ferr, "qh_mergevertex_neighbors: merge vertex neighbors of f%d and f%d\n",
+	  facet1->id, facet2->id));
+  if (qh tracevertex) {
+    fprintf (qh ferr, "qh_mergevertex_neighbors: of f%d and f%d at furthest p%d f0= %p\n",
+	     facet1->id, facet2->id, qh furthest_id, qh tracevertex->neighbors->e[0].p);
+    qh_errprint ("TRACE", NULL, NULL, NULL, qh tracevertex);
+  }
+  FOREACHvertex_(facet1->vertices) {
+    if (vertex->visitid != qh vertex_visit) 
+      qh_setreplace(vertex->neighbors, facet1, facet2);
+    else {
+      qh_setdel(vertex->neighbors, facet1);
+      if (!SETsecond_(vertex->neighbors))
+	qh_mergevertex_del (vertex, facet1, facet2);
+    }
+  }
+  if (qh tracevertex) 
+    qh_errprint ("TRACE", NULL, NULL, NULL, qh tracevertex);
+} /* mergevertex_neighbors */
+
+
+/*---------------------------------
+  
+  qh_mergevertices( vertices1, vertices2 )
+    merges the vertex set of facet1 into facet2
+
+  returns:
+    replaces vertices2 with merged set
+    preserves vertex_visit for qh_mergevertex_neighbors
+    updates qh.newvertex_list
+
+  design:
+    create a merged set of both vertices (in inverse id order)
+*/
+void qh_mergevertices(setT *vertices1, setT **vertices2) {
+  int newsize= qh_setsize(vertices1)+qh_setsize(*vertices2) - qh hull_dim + 1;
+  setT *mergedvertices;
+  vertexT *vertex, **vertexp, **vertex2= SETaddr_(*vertices2, vertexT);
+
+  mergedvertices= qh_settemp (newsize);
+  FOREACHvertex_(vertices1) {
+    if (!*vertex2 || vertex->id > (*vertex2)->id)
+      qh_setappend (&mergedvertices, vertex);
+    else {
+      while (*vertex2 && (*vertex2)->id > vertex->id)
+	qh_setappend (&mergedvertices, *vertex2++);
+      if (!*vertex2 || (*vertex2)->id < vertex->id)
+	qh_setappend (&mergedvertices, vertex);
+      else
+	qh_setappend (&mergedvertices, *vertex2++);
+    }
+  }
+  while (*vertex2)
+    qh_setappend (&mergedvertices, *vertex2++);
+  if (newsize < qh_setsize (mergedvertices)) {
+    fprintf (qh ferr, "qhull internal error (qh_mergevertices): facets did not share a ridge\n");
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  qh_setfree(vertices2);
+  *vertices2= mergedvertices;
+  qh_settemppop ();
+} /* mergevertices */
+
+
+/*---------------------------------
+  
+  qh_neighbor_intersections( vertex )
+    return intersection of all vertices in vertex->neighbors except for vertex
+
+  returns:
+    returns temporary set of vertices
+    does not include vertex
+    NULL if a neighbor is simplicial
+    NULL if empty set
+    
+  notes:
+    used for renaming vertices
+
+  design:
+    initialize the intersection set with vertices of the first two neighbors
+    delete vertex from the intersection
+    for each remaining neighbor
+      intersect its vertex set with the intersection set
+      return NULL if empty
+    return the intersection set  
+*/
+setT *qh_neighbor_intersections (vertexT *vertex) {
+  facetT *neighbor, **neighborp, *neighborA, *neighborB;
+  setT *intersect;
+  int neighbor_i, neighbor_n;
+
+  FOREACHneighbor_(vertex) {
+    if (neighbor->simplicial)
+      return NULL;
+  }
+  neighborA= SETfirstt_(vertex->neighbors, facetT);
+  neighborB= SETsecondt_(vertex->neighbors, facetT);
+  zinc_(Zintersectnum);
+  if (!neighborA)
+    return NULL;
+  if (!neighborB)
+    intersect= qh_setcopy (neighborA->vertices, 0);
+  else
+    intersect= qh_vertexintersect_new (neighborA->vertices, neighborB->vertices);
+  qh_settemppush (intersect);
+  qh_setdelsorted (intersect, vertex);
+  FOREACHneighbor_i_(vertex) {
+    if (neighbor_i >= 2) {
+      zinc_(Zintersectnum);
+      qh_vertexintersect (&intersect, neighbor->vertices);
+      if (!SETfirst_(intersect)) {
+        zinc_(Zintersectfail);
+        qh_settempfree (&intersect);
+        return NULL;
+      }
+    }
+  }
+  trace3((qh ferr, "qh_neighbor_intersections: %d vertices in neighbor intersection of v%d\n", 
+          qh_setsize (intersect), vertex->id));
+  return intersect;
+} /* neighbor_intersections */
+
+/*---------------------------------
+  
+  qh_newvertices( vertices )
+    add vertices to end of qh.vertex_list (marks as new vertices)
+
+  returns:
+    vertices on qh.newvertex_list
+    vertex->newlist set
+*/
+void qh_newvertices (setT *vertices) {
+  vertexT *vertex, **vertexp;
+
+  FOREACHvertex_(vertices) {
+    if (!vertex->newlist) {
+      qh_removevertex (vertex);
+      qh_appendvertex (vertex);
+    }
+  }
+} /* newvertices */
+
+/*---------------------------------
+  
+  qh_reducevertices()
+    reduce extra vertices, shared vertices, and redundant vertices
+    facet->newmerge is set if merged since last call
+    if !qh.MERGEvertices, only removes extra vertices
+
+  returns:
+    True if also merged degen_redundant facets
+    vertices are renamed if possible
+    clears facet->newmerge and vertex->delridge
+
+  notes:
+    ignored if 2-d
+
+  design:
+    merge any degenerate or redundant facets
+    for each newly merged facet
+      remove extra vertices
+    if qh.MERGEvertices
+      for each newly merged facet
+        for each vertex
+          if vertex was on a deleted ridge
+            rename vertex if it is shared
+      remove delridge flag from new vertices
+*/
+boolT qh_reducevertices (void) {
+  int numshare=0, numrename= 0;
+  boolT degenredun= False;
+  facetT *newfacet;
+  vertexT *vertex, **vertexp;
+
+  if (qh hull_dim == 2) 
+    return False;
+  if (qh_merge_degenredundant())
+    degenredun= True;
+ LABELrestart:
+  FORALLnew_facets {
+    if (newfacet->newmerge) { 
+      if (!qh MERGEvertices)
+        newfacet->newmerge= False;
+      qh_remove_extravertices (newfacet);
+    }
+  }
+  if (!qh MERGEvertices)
+    return False;
+  FORALLnew_facets {
+    if (newfacet->newmerge) {
+      newfacet->newmerge= False;
+      FOREACHvertex_(newfacet->vertices) {
+	if (vertex->delridge) {
+	  if (qh_rename_sharedvertex (vertex, newfacet)) {
+	    numshare++;
+	    vertexp--; /* repeat since deleted vertex */
+	  }
+        }
+      }
+    }
+  }
+  FORALLvertex_(qh newvertex_list) {
+    if (vertex->delridge && !vertex->deleted) {
+      vertex->delridge= False;
+      if (qh hull_dim >= 4 && qh_redundant_vertex (vertex)) {
+	numrename++;
+	if (qh_merge_degenredundant()) {
+	  degenredun= True;
+	  goto LABELrestart;
+	}
+      }
+    }
+  }
+  trace1((qh ferr, "qh_reducevertices: renamed %d shared vertices and %d redundant vertices. Degen? %d\n",
+	  numshare, numrename, degenredun));
+  return degenredun;
+} /* reducevertices */
+      
+/*---------------------------------
+  
+  qh_redundant_vertex( vertex )
+    detect and rename a redundant vertex
+    vertices have full vertex->neighbors 
+
+  returns:
+    returns true if find a redundant vertex
+      deletes vertex (vertex->deleted)
+  
+  notes:
+    only needed if vertex->delridge and hull_dim >= 4
+    may add degenerate facets to qh.facet_mergeset
+    doesn't change vertex->neighbors or create redundant facets
+
+  design:
+    intersect vertices of all facet neighbors of vertex
+    determine ridges for these vertices
+    if find a new vertex for vertex amoung these ridges and vertices
+      rename vertex to the new vertex
+*/
+vertexT *qh_redundant_vertex (vertexT *vertex) {
+  vertexT *newvertex= NULL;
+  setT *vertices, *ridges;
+
+  trace3((qh ferr, "qh_redundant_vertex: check if v%d can be renamed\n", vertex->id));  
+  if ((vertices= qh_neighbor_intersections (vertex))) {
+    ridges= qh_vertexridges (vertex);
+    if ((newvertex= qh_find_newvertex (vertex, vertices, ridges)))
+      qh_renamevertex (vertex, newvertex, ridges, NULL, NULL);
+    qh_settempfree (&ridges);
+    qh_settempfree (&vertices);
+  }
+  return newvertex;
+} /* redundant_vertex */
+
+/*---------------------------------
+  
+  qh_remove_extravertices( facet )
+    remove extra vertices from non-simplicial facets
+
+  returns:
+    returns True if it finds them
+
+  design:
+    for each vertex in facet
+      if vertex not in a ridge (i.e., no longer used)
+        delete vertex from facet
+        delete facet from vertice's neighbors
+        unless vertex in another facet
+          add vertex to qh.del_vertices for later deletion
+*/
+boolT qh_remove_extravertices (facetT *facet) {
+  ridgeT *ridge, **ridgep;
+  vertexT *vertex, **vertexp;
+  boolT foundrem= False;
+
+  trace4((qh ferr, "qh_remove_extravertices: test f%d for extra vertices\n",
+	  facet->id));
+  FOREACHvertex_(facet->vertices)
+    vertex->seen= False;
+  FOREACHridge_(facet->ridges) { 
+    FOREACHvertex_(ridge->vertices)
+      vertex->seen= True;
+  }
+  FOREACHvertex_(facet->vertices) {
+    if (!vertex->seen) {
+      foundrem= True;
+      zinc_(Zremvertex);
+      qh_setdelsorted (facet->vertices, vertex);
+      qh_setdel (vertex->neighbors, facet);
+      if (!qh_setsize (vertex->neighbors)) {
+	vertex->deleted= True;
+	qh_setappend (&qh del_vertices, vertex);
+	zinc_(Zremvertexdel);
+	trace2((qh ferr, "qh_remove_extravertices: v%d deleted because it's lost all ridges\n", vertex->id));
+      }else
+	trace3((qh ferr, "qh_remove_extravertices: v%d removed from f%d because it's lost all ridges\n", vertex->id, facet->id));
+      vertexp--; /*repeat*/
+    }
+  }
+  return foundrem;
+} /* remove_extravertices */
+
+/*---------------------------------
+  
+  qh_rename_sharedvertex( vertex, facet )
+    detect and rename if shared vertex in facet
+    vertices have full ->neighbors
+
+  returns:
+    newvertex or NULL
+    the vertex may still exist in other facets (i.e., a neighbor was pinched)
+    does not change facet->neighbors
+    updates vertex->neighbors
+  
+  notes:
+    a shared vertex for a facet is only in ridges to one neighbor
+    this may undo a pinched facet
+ 
+    it does not catch pinches involving multiple facets.  These appear
+      to be difficult to detect, since an exhaustive search is too expensive.
+
+  design:
+    if vertex only has two neighbors
+      determine the ridges that contain the vertex
+      determine the vertices shared by both neighbors
+      if can find a new vertex in this set
+        rename the vertex to the new vertex
+*/
+vertexT *qh_rename_sharedvertex (vertexT *vertex, facetT *facet) {
+  facetT *neighbor, **neighborp, *neighborA= NULL;
+  setT *vertices, *ridges;
+  vertexT *newvertex;
+
+  if (qh_setsize (vertex->neighbors) == 2) {
+    neighborA= SETfirstt_(vertex->neighbors, facetT);
+    if (neighborA == facet)
+      neighborA= SETsecondt_(vertex->neighbors, facetT);
+  }else if (qh hull_dim == 3)
+    return NULL;
+  else {
+    qh visit_id++;
+    FOREACHneighbor_(facet)
+      neighbor->visitid= qh visit_id;
+    FOREACHneighbor_(vertex) {
+      if (neighbor->visitid == qh visit_id) {
+        if (neighborA)
+          return NULL;
+        neighborA= neighbor;
+      }
+    }
+    if (!neighborA) {
+      fprintf (qh ferr, "qhull internal error (qh_rename_sharedvertex): v%d's neighbors not in f%d\n",
+        vertex->id, facet->id);
+      qh_errprint ("ERRONEOUS", facet, NULL, NULL, vertex);
+      qh_errexit (qh_ERRqhull, NULL, NULL);
+    }
+  }
+  /* the vertex is shared by facet and neighborA */
+  ridges= qh_settemp (qh TEMPsize);
+  neighborA->visitid= ++qh visit_id;
+  qh_vertexridges_facet (vertex, facet, &ridges);
+  trace2((qh ferr, "qh_rename_sharedvertex: p%d (v%d) is shared by f%d (%d ridges) and f%d\n",
+    qh_pointid(vertex->point), vertex->id, facet->id, qh_setsize (ridges), neighborA->id));
+  zinc_(Zintersectnum);
+  vertices= qh_vertexintersect_new (facet->vertices, neighborA->vertices);
+  qh_setdel (vertices, vertex);
+  qh_settemppush (vertices);
+  if ((newvertex= qh_find_newvertex (vertex, vertices, ridges))) 
+    qh_renamevertex (vertex, newvertex, ridges, facet, neighborA);
+  qh_settempfree (&vertices);
+  qh_settempfree (&ridges);
+  return newvertex;
+} /* rename_sharedvertex */
+
+/*---------------------------------
+  
+  qh_renameridgevertex( ridge, oldvertex, newvertex )
+    renames oldvertex as newvertex in ridge
+
+  returns:
+  
+  design:
+    delete oldvertex from ridge
+    if newvertex already in ridge
+      copy ridge->noconvex to another ridge if possible
+      delete the ridge
+    else
+      insert newvertex into the ridge
+      adjust the ridge's orientation
+*/
+void qh_renameridgevertex(ridgeT *ridge, vertexT *oldvertex, vertexT *newvertex) {
+  int nth= 0, oldnth;
+  facetT *temp;
+  vertexT *vertex, **vertexp;
+
+  oldnth= qh_setindex (ridge->vertices, oldvertex);
+  qh_setdelnthsorted (ridge->vertices, oldnth);
+  FOREACHvertex_(ridge->vertices) {
+    if (vertex == newvertex) {
+      zinc_(Zdelridge);
+      if (ridge->nonconvex) /* only one ridge has nonconvex set */
+	qh_copynonconvex (ridge);
+      qh_delridge (ridge);
+      trace2((qh ferr, "qh_renameridgevertex: ridge r%d deleted.  It contained both v%d and v%d\n",
+        ridge->id, oldvertex->id, newvertex->id));
+      return;
+    }
+    if (vertex->id < newvertex->id)
+      break;
+    nth++;
+  }
+  qh_setaddnth(&ridge->vertices, nth, newvertex);
+  if (abs(oldnth - nth)%2) {
+    trace3((qh ferr, "qh_renameridgevertex: swapped the top and bottom of ridge r%d\n", 
+	    ridge->id));
+    temp= ridge->top;
+    ridge->top= ridge->bottom;
+    ridge->bottom= temp;
+  }
+} /* renameridgevertex */
+
+
+/*---------------------------------
+  
+  qh_renamevertex( oldvertex, newvertex, ridges, oldfacet, neighborA )
+    renames oldvertex as newvertex in ridges 
+    gives oldfacet/neighborA if oldvertex is shared between two facets
+
+  returns:
+    oldvertex may still exist afterwards
+    
+
+  notes:
+    can not change neighbors of newvertex (since it's a subset)
+
+  design:
+    for each ridge in ridges
+      rename oldvertex to newvertex and delete degenerate ridges
+    if oldfacet not defined
+      for each neighbor of oldvertex
+        delete oldvertex from neighbor's vertices
+        remove extra vertices from neighbor
+      add oldvertex to qh.del_vertices
+    else if oldvertex only between oldfacet and neighborA
+      delete oldvertex from oldfacet and neighborA
+      add oldvertex to qh.del_vertices
+    else oldvertex is in oldfacet and neighborA and other facets (i.e., pinched)
+      delete oldvertex from oldfacet
+      delete oldfacet from oldvertice's neighbors
+      remove extra vertices (e.g., oldvertex) from neighborA
+*/
+void qh_renamevertex(vertexT *oldvertex, vertexT *newvertex, setT *ridges, facetT *oldfacet, facetT *neighborA) {
+  facetT *neighbor, **neighborp;
+  ridgeT *ridge, **ridgep;
+  boolT istrace= False;
+
+  if (qh IStracing >= 2 || oldvertex->id == qh tracevertex_id ||
+	newvertex->id == qh tracevertex_id)
+    istrace= True;
+  FOREACHridge_(ridges) 
+    qh_renameridgevertex (ridge, oldvertex, newvertex);
+  if (!oldfacet) {
+    zinc_(Zrenameall);
+    if (istrace)
+      fprintf (qh ferr, "qh_renamevertex: renamed v%d to v%d in several facets\n",
+               oldvertex->id, newvertex->id);
+    FOREACHneighbor_(oldvertex) {
+      qh_maydropneighbor (neighbor);
+      qh_setdelsorted (neighbor->vertices, oldvertex);
+      if (qh_remove_extravertices (neighbor))
+        neighborp--; /* neighbor may be deleted */
+    }
+    if (!oldvertex->deleted) {
+      oldvertex->deleted= True;
+      qh_setappend (&qh del_vertices, oldvertex);
+    }
+  }else if (qh_setsize (oldvertex->neighbors) == 2) {
+    zinc_(Zrenameshare);
+    if (istrace)
+      fprintf (qh ferr, "qh_renamevertex: renamed v%d to v%d in oldfacet f%d\n", 
+               oldvertex->id, newvertex->id, oldfacet->id);
+    FOREACHneighbor_(oldvertex)
+      qh_setdelsorted (neighbor->vertices, oldvertex);
+    oldvertex->deleted= True;
+    qh_setappend (&qh del_vertices, oldvertex);
+  }else {
+    zinc_(Zrenamepinch);
+    if (istrace || qh IStracing)
+      fprintf (qh ferr, "qh_renamevertex: renamed pinched v%d to v%d between f%d and f%d\n", 
+               oldvertex->id, newvertex->id, oldfacet->id, neighborA->id);
+    qh_setdelsorted (oldfacet->vertices, oldvertex);
+    qh_setdel (oldvertex->neighbors, oldfacet);
+    qh_remove_extravertices (neighborA);
+  }
+} /* renamevertex */
+
+
+/*---------------------------------
+  
+  qh_test_appendmerge( facet, neighbor )
+    tests facet/neighbor for convexity
+    appends to mergeset if non-convex
+    if pre-merging, 
+      nop if qh.SKIPconvex, or qh.MERGEexact and coplanar
+
+  returns:
+    true if appends facet/neighbor to mergeset
+    sets facet->center as needed
+    does not change facet->seen
+
+  design:
+    if qh.cos_max is defined
+      if the angle between facet normals is too shallow
+        append an angle-coplanar merge to qh.mergeset
+        return True
+    make facet's centrum if needed
+    if facet's centrum is above the neighbor
+      set isconcave
+    else
+      if facet's centrum is not below the neighbor
+        set iscoplanar
+      make neighbor's centrum if needed
+      if neighbor's centrum is above the facet
+        set isconcave
+      else if neighbor's centrum is not below the facet
+        set iscoplanar
+   if isconcave or iscoplanar
+     get angle if needed
+     append concave or coplanar merge to qh.mergeset
+*/
+boolT qh_test_appendmerge (facetT *facet, facetT *neighbor) {
+  realT dist, dist2= -REALmax, angle= -REALmax;
+  boolT isconcave= False, iscoplanar= False, okangle= False;
+
+  if (qh SKIPconvex && !qh POSTmerging)
+    return False;
+  if ((!qh MERGEexact || qh POSTmerging) && qh cos_max < REALmax/2) {
+    angle= qh_getangle(facet->normal, neighbor->normal);
+    zinc_(Zangletests);
+    if (angle > qh cos_max) {
+      zinc_(Zcoplanarangle);
+      qh_appendmergeset(facet, neighbor, MRGanglecoplanar, &angle);
+      trace2((qh ferr, "qh_test_appendmerge: coplanar angle %4.4g between f%d and f%d\n",
+         angle, facet->id, neighbor->id));
+      return True;
+    }else
+      okangle= True;
+  }
+  if (!facet->center)
+    facet->center= qh_getcentrum (facet);
+  zzinc_(Zcentrumtests);
+  qh_distplane(facet->center, neighbor, &dist);
+  if (dist > qh centrum_radius)
+    isconcave= True;
+  else {
+    if (dist > -qh centrum_radius)
+      iscoplanar= True;
+    if (!neighbor->center)
+      neighbor->center= qh_getcentrum (neighbor);
+    zzinc_(Zcentrumtests);
+    qh_distplane(neighbor->center, facet, &dist2);
+    if (dist2 > qh centrum_radius)
+      isconcave= True;
+    else if (!iscoplanar && dist2 > -qh centrum_radius)
+      iscoplanar= True;
+  }
+  if (!isconcave && (!iscoplanar || (qh MERGEexact && !qh POSTmerging)))
+    return False;
+  if (!okangle && qh ANGLEmerge) {
+    angle= qh_getangle(facet->normal, neighbor->normal);
+    zinc_(Zangletests);
+  }
+  if (isconcave) {
+    zinc_(Zconcaveridge);
+    if (qh ANGLEmerge)
+      angle += qh_ANGLEconcave + 0.5;
+    qh_appendmergeset(facet, neighbor, MRGconcave, &angle);
+    trace0((qh ferr, "qh_test_appendmerge: concave f%d to f%d dist %4.4g and reverse dist %4.4g angle %4.4g during p%d\n",
+	   facet->id, neighbor->id, dist, dist2, angle, qh furthest_id));
+  }else /* iscoplanar */ {
+    zinc_(Zcoplanarcentrum);
+    qh_appendmergeset(facet, neighbor, MRGcoplanar, &angle);
+    trace2((qh ferr, "qh_test_appendmerge: coplanar f%d to f%d dist %4.4g, reverse dist %4.4g angle %4.4g\n",
+	      facet->id, neighbor->id, dist, dist2, angle));
+  }
+  return True;
+} /* test_appendmerge */
+
+/*---------------------------------
+  
+  qh_test_vneighbors()
+    test vertex neighbors for convexity
+    tests all facets on qh.newfacet_list
+
+  returns:
+    true if non-convex vneighbors appended to qh.facet_mergeset
+    initializes vertex neighbors if needed
+
+  notes:
+    assumes all facet neighbors have been tested
+    this can be expensive
+    this does not guarantee that a centrum is below all facets
+      but it is unlikely
+    uses qh.visit_id
+
+  design:
+    build vertex neighbors if necessary
+    for all new facets
+      for all vertices
+        for each unvisited facet neighbor of the vertex
+          test new facet and neighbor for convexity
+*/
+boolT qh_test_vneighbors (void /* qh newfacet_list */) {
+  facetT *newfacet, *neighbor, **neighborp;
+  vertexT *vertex, **vertexp;
+  int nummerges= 0;
+
+  trace1((qh ferr, "qh_test_vneighbors: testing vertex neighbors for convexity\n"));
+  if (!qh VERTEXneighbors)
+    qh_vertexneighbors();
+  FORALLnew_facets 
+    newfacet->seen= False;
+  FORALLnew_facets {
+    newfacet->seen= True;
+    newfacet->visitid= qh visit_id++;
+    FOREACHneighbor_(newfacet)
+      newfacet->visitid= qh visit_id;
+    FOREACHvertex_(newfacet->vertices) {
+      FOREACHneighbor_(vertex) {
+      	if (neighbor->seen || neighbor->visitid == qh visit_id)
+      	  continue;
+      	if (qh_test_appendmerge (newfacet, neighbor))
+          nummerges++;
+      }
+    }
+  }
+  zadd_(Ztestvneighbor, nummerges);
+  trace1((qh ferr, "qh_test_vneighbors: found %d non-convex, vertex neighbors\n",
+           nummerges));
+  return (nummerges > 0);    
+} /* test_vneighbors */
+
+/*---------------------------------
+  
+  qh_tracemerge( facet1, facet2 )
+    print trace message after merge
+*/
+void qh_tracemerge (facetT *facet1, facetT *facet2) {
+  boolT waserror= False;
+
+#ifndef qh_NOtrace
+  if (qh IStracing >= 4) 
+    qh_errprint ("MERGED", facet2, NULL, NULL, NULL);
+  if (facet2 == qh tracefacet || (qh tracevertex && qh tracevertex->newlist)) {
+    fprintf (qh ferr, "qh_tracemerge: trace facet and vertex after merge of f%d and f%d, furthest p%d\n", facet1->id, facet2->id, qh furthest_id);
+    if (facet2 != qh tracefacet)
+      qh_errprint ("TRACE", qh tracefacet, 
+        (qh tracevertex && qh tracevertex->neighbors) ? 
+           SETfirstt_(qh tracevertex->neighbors, facetT) : NULL,
+        NULL, qh tracevertex);      
+  }
+  if (qh tracevertex) {
+    if (qh tracevertex->deleted)
+      fprintf (qh ferr, "qh_tracemerge: trace vertex deleted at furthest p%d\n",
+	    qh furthest_id);
+    else
+      qh_checkvertex (qh tracevertex);
+  }
+  if (qh tracefacet) {
+    qh_checkfacet (qh tracefacet, True, &waserror);
+    if (waserror)
+      qh_errexit (qh_ERRqhull, qh tracefacet, NULL);
+  }
+#endif /* !qh_NOtrace */
+  if (qh CHECKfrequently || qh IStracing >= 4) { /* can't check polygon here */
+    qh_checkfacet (facet2, True, &waserror);
+    if (waserror)
+      qh_errexit(qh_ERRqhull, NULL, NULL);
+  }
+} /* tracemerge */
+
+/*---------------------------------
+  
+  qh_tracemerging()
+    print trace message during POSTmerging
+
+  returns:
+    updates qh.mergereport
+  
+  notes:
+    called from qh_mergecycle() and qh_mergefacet()
+  
+  see:
+    qh_buildtracing()
+*/
+void qh_tracemerging (void) {
+  realT cpu;
+  int total;
+  time_t timedata;
+  struct tm *tp;
+
+  qh mergereport= zzval_(Ztotmerge);
+  time (&timedata);
+  tp= localtime (&timedata);
+  cpu= qh_CPUclock;
+  cpu /= qh_SECticks;
+  total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
+  fprintf (qh ferr, "\n\
+At %d:%d:%d & %2.5g CPU secs, qhull has merged %d facets.  The hull\n\
+  contains %d facets and %d vertices.\n",
+      tp->tm_hour, tp->tm_min, tp->tm_sec, cpu,
+      total, qh num_facets - qh num_visible,
+      qh num_vertices-qh_setsize (qh del_vertices));
+} /* tracemerging */
+
+/*---------------------------------
+  
+  qh_updatetested( facet1, facet2 )
+    clear facet2->tested and facet1->ridge->tested for merge
+
+  returns:
+    deletes facet2->center unless it's already large
+      if so, clears facet2->ridge->tested
+
+  design:
+    clear facet2->tested
+    clear ridge->tested for facet1's ridges
+    if facet2 has a centrum
+      if facet2 is large
+        set facet2->keepcentrum 
+      else if facet2 has 3 vertices due to many merges, or not large and post merging
+        clear facet2->keepcentrum
+      unless facet2->keepcentrum
+        clear facet2->center to recompute centrum later
+        clear ridge->tested for facet2's ridges
+*/
+void qh_updatetested (facetT *facet1, facetT *facet2) {
+  ridgeT *ridge, **ridgep;
+  int size;
+  
+  facet2->tested= False;
+  FOREACHridge_(facet1->ridges)
+    ridge->tested= False;
+  if (!facet2->center)
+    return;
+  size= qh_setsize (facet2->vertices);
+  if (!facet2->keepcentrum) {
+    if (size > qh hull_dim + qh_MAXnewcentrum) {
+      facet2->keepcentrum= True;
+      zinc_(Zwidevertices);
+    }
+  }else if (size <= qh hull_dim + qh_MAXnewcentrum) {
+    /* center and keepcentrum was set */
+    if (size == qh hull_dim || qh POSTmerging)
+      facet2->keepcentrum= False; /* if many merges need to recompute centrum */
+  }
+  if (!facet2->keepcentrum) {
+    qh_memfree (facet2->center, qh normal_size);
+    facet2->center= NULL;
+    FOREACHridge_(facet2->ridges)
+      ridge->tested= False;
+  }
+} /* updatetested */
+
+/*---------------------------------
+  
+  qh_vertexridges( vertex )
+    return temporary set of ridges adjacent to a vertex
+    vertex->neighbors defined
+
+  ntoes:
+    uses qh.visit_id
+    does not include implicit ridges for simplicial facets
+
+  design:
+    for each neighbor of vertex
+      add ridges that include the vertex to ridges  
+*/
+setT *qh_vertexridges (vertexT *vertex) {
+  facetT *neighbor, **neighborp;
+  setT *ridges= qh_settemp (qh TEMPsize);
+  int size;
+
+  qh visit_id++;
+  FOREACHneighbor_(vertex)
+    neighbor->visitid= qh visit_id;
+  FOREACHneighbor_(vertex) {
+    if (*neighborp)   /* no new ridges in last neighbor */
+      qh_vertexridges_facet (vertex, neighbor, &ridges);
+  }
+  if (qh PRINTstatistics || qh IStracing) {
+    size= qh_setsize (ridges);
+    zinc_(Zvertexridge);
+    zadd_(Zvertexridgetot, size);
+    zmax_(Zvertexridgemax, size);
+    trace3((qh ferr, "qh_vertexridges: found %d ridges for v%d\n",
+             size, vertex->id));
+  }
+  return ridges;
+} /* vertexridges */
+
+/*---------------------------------
+  
+  qh_vertexridges_facet( vertex, facet, ridges )
+    add adjacent ridges for vertex in facet
+    neighbor->visitid==qh.visit_id if it hasn't been visited
+
+  returns:
+    ridges updated
+    sets facet->visitid to qh.visit_id-1
+
+  design:
+    for each ridge of facet
+      if ridge of visited neighbor (i.e., unprocessed)
+        if vertex in ridge
+          append ridge to vertex
+    mark facet processed
+*/
+void qh_vertexridges_facet (vertexT *vertex, facetT *facet, setT **ridges) {
+  ridgeT *ridge, **ridgep;
+  facetT *neighbor;
+
+  FOREACHridge_(facet->ridges) {
+    neighbor= otherfacet_(ridge, facet);
+    if (neighbor->visitid == qh visit_id 
+    && qh_setin (ridge->vertices, vertex))
+      qh_setappend (ridges, ridge);
+  }
+  facet->visitid= qh visit_id-1;
+} /* vertexridges_facet */
+
+/*---------------------------------
+  
+  qh_willdelete( facet, replace )
+    moves facet to visible list
+    sets facet->f.replace to replace (may be NULL)
+
+  returns:
+    bumps qh.num_visible
+*/
+void qh_willdelete (facetT *facet, facetT *replace) {
+
+  qh_removefacet(facet);
+  qh_prependfacet (facet, &qh visible_list);
+  qh num_visible++;
+  facet->visible= True;
+  facet->f.replace= replace;
+} /* willdelete */
+
+#else /* qh_NOmerge */
+void qh_premerge (vertexT *apex, realT maxcentrum, realT maxangle) {
+}
+void qh_postmerge (char *reason, realT maxcentrum, realT maxangle, 
+                      boolT vneighbors) {
+}
+boolT qh_checkzero (boolT testall) {
+   }
+#endif /* qh_NOmerge */
+
diff --git a/extern/qhull/src/merge.h b/extern/qhull/src/merge.h
new file mode 100644
index 00000000000..7fc2afa5967
--- /dev/null
+++ b/extern/qhull/src/merge.h
@@ -0,0 +1,171 @@
+/*
  ---------------------------------
+
+   merge.h 
+   header file for merge.c
+
+   see qh-merge.htm and merge.c
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFmerge
+#define qhDEFmerge 1
+
+
+/*============ -constants- ==============*/
+
+/*----------------------------------
+
+  qh_ANGLEredundant
+    indicates redundant merge in mergeT->angle
+*/
+#define qh_ANGLEredundant 6.0
+
+/*----------------------------------
+  
+  qh_ANGLEdegen
+    indicates degenerate facet in mergeT->angle
+*/
+#define qh_ANGLEdegen     5.0
+
+/*----------------------------------
+  
+  qh_ANGLEconcave
+    offset to indicate concave facets in mergeT->angle
+  
+  notes:
+    concave facets are assigned the range of [2,4] in mergeT->angle
+    roundoff error may make the angle less than 2
+*/
+#define qh_ANGLEconcave  1.5
+
+/*----------------------------------
+  
+  MRG... (mergeType)
+    indicates the type of a merge (mergeT->type)
+*/
+typedef enum {	/* in sort order for facet_mergeset */
+  MRGnone= 0,
+  MRGcoplanar,		/* centrum coplanar */
+  MRGanglecoplanar,	/* angle coplanar */
+  			/* could detect half concave ridges */
+  MRGconcave,		/* concave ridge */
+  MRGflip,		/* flipped facet. facet1 == facet2 */
+  MRGridge,		/* duplicate ridge (qh_MERGEridge) */
+                        /* degen and redundant go onto degen_mergeset */
+  MRGdegen,		/* degenerate facet (not enough neighbors) facet1 == facet2 */
+  MRGredundant,		/* redundant facet (vertex subset) */
+  			/* merge_degenredundant assumes degen < redundant */
+  MRGmirror,	        /* mirror facet from qh_triangulate */
+  ENDmrg
+} mergeType;
+
+/*----------------------------------
+  
+  qh_MERGEapex
+    flag for qh_mergefacet() to indicate an apex merge  
+*/
+#define qh_MERGEapex     True
+
+/*============ -structures- ====================*/
+
+/*----------------------------------
+     
+  mergeT
+    structure used to merge facets
+*/
+
+typedef struct mergeT mergeT;
+struct mergeT {		/* initialize in qh_appendmergeset */
+  realT   angle;        /* angle between normals of facet1 and facet2 */
+  facetT *facet1; 	/* will merge facet1 into facet2 */
+  facetT *facet2;
+  mergeType type;
+};
+
+
+/*=========== -macros- =========================*/
+
+/*----------------------------------
+     
+  FOREACHmerge_( merges ) {...}
+    assign 'merge' to each merge in merges
+       
+  notes:
+    uses 'mergeT *merge, **mergep;'
+    if qh_mergefacet(),
+      restart since qh.facet_mergeset may change
+    see FOREACHsetelement_
+*/
+#define FOREACHmerge_( merges ) FOREACHsetelement_(mergeT, merges, merge)
+
+/*============ prototypes in alphabetical order after pre/postmerge =======*/
+
+void    qh_premerge (vertexT *apex, realT maxcentrum, realT maxangle);
+void    qh_postmerge (char *reason, realT maxcentrum, realT maxangle, 
+             boolT vneighbors);
+void    qh_all_merges (boolT othermerge, boolT vneighbors);
+void    qh_appendmergeset(facetT *facet, facetT *neighbor, mergeType mergetype, realT *angle);
+setT   *qh_basevertices( facetT *samecycle);
+void    qh_checkconnect (void /* qh new_facets */);
+boolT   qh_checkzero (boolT testall);
+void    qh_copynonconvex (ridgeT *atridge);
+void    qh_degen_redundant_facet (facetT *facet);
+void   	qh_degen_redundant_neighbors (facetT *facet, facetT *delfacet);
+vertexT *qh_find_newvertex (vertexT *oldvertex, setT *vertices, setT *ridges);
+void    qh_findbest_test (boolT testcentrum, facetT *facet, facetT *neighbor,
+           facetT **bestfacet, realT *distp, realT *mindistp, realT *maxdistp);
+facetT *qh_findbestneighbor(facetT *facet, realT *distp, realT *mindistp, realT *maxdistp);
+void 	qh_flippedmerges(facetT *facetlist, boolT *wasmerge);
+void 	qh_forcedmerges( boolT *wasmerge);
+void	qh_getmergeset(facetT *facetlist);
+void 	qh_getmergeset_initial (facetT *facetlist);
+void    qh_hashridge (setT *hashtable, int hashsize, ridgeT *ridge, vertexT *oldvertex);
+ridgeT *qh_hashridge_find (setT *hashtable, int hashsize, ridgeT *ridge, 
+              vertexT *vertex, vertexT *oldvertex, int *hashslot);
+void 	qh_makeridges(facetT *facet);
+void    qh_mark_dupridges(facetT *facetlist);
+void    qh_maydropneighbor (facetT *facet);
+int     qh_merge_degenredundant (void);
+void    qh_merge_nonconvex( facetT *facet1, facetT *facet2, mergeType mergetype);
+void    qh_mergecycle (facetT *samecycle, facetT *newfacet);
+void    qh_mergecycle_all (facetT *facetlist, boolT *wasmerge);
+void    qh_mergecycle_facets( facetT *samecycle, facetT *newfacet);
+void    qh_mergecycle_neighbors(facetT *samecycle, facetT *newfacet);
+void    qh_mergecycle_ridges(facetT *samecycle, facetT *newfacet);
+void    qh_mergecycle_vneighbors( facetT *samecycle, facetT *newfacet);
+void 	qh_mergefacet(facetT *facet1, facetT *facet2, realT *mindist, realT *maxdist, boolT mergeapex);
+void    qh_mergefacet2d (facetT *facet1, facetT *facet2);
+void 	qh_mergeneighbors(facetT *facet1, facetT *facet2);
+void 	qh_mergeridges(facetT *facet1, facetT *facet2);
+void    qh_mergesimplex(facetT *facet1, facetT *facet2, boolT mergeapex);
+void    qh_mergevertex_del (vertexT *vertex, facetT *facet1, facetT *facet2);
+void    qh_mergevertex_neighbors(facetT *facet1, facetT *facet2);
+void	qh_mergevertices(setT *vertices1, setT **vertices);
+setT   *qh_neighbor_intersections (vertexT *vertex);
+void    qh_newvertices (setT *vertices);
+boolT   qh_reducevertices (void);
+vertexT *qh_redundant_vertex (vertexT *vertex);
+boolT   qh_remove_extravertices (facetT *facet);
+vertexT *qh_rename_sharedvertex (vertexT *vertex, facetT *facet);
+void	qh_renameridgevertex(ridgeT *ridge, vertexT *oldvertex, vertexT *newvertex);
+void    qh_renamevertex(vertexT *oldvertex, vertexT *newvertex, setT *ridges,
+			facetT *oldfacet, facetT *neighborA);
+boolT 	qh_test_appendmerge (facetT *facet, facetT *neighbor);
+boolT   qh_test_vneighbors (void /* qh newfacet_list */);
+void    qh_tracemerge (facetT *facet1, facetT *facet2);
+void    qh_tracemerging (void);
+void    qh_updatetested( facetT *facet1, facetT *facet2);
+setT   *qh_vertexridges (vertexT *vertex);
+void    qh_vertexridges_facet (vertexT *vertex, facetT *facet, setT **ridges);
+void    qh_willdelete (facetT *facet, facetT *replace);
+
+#endif /* qhDEFmerge */
diff --git a/extern/qhull/src/poly.c b/extern/qhull/src/poly.c
new file mode 100644
index 00000000000..6319e43d66a
--- /dev/null
+++ b/extern/qhull/src/poly.c
@@ -0,0 +1,1180 @@
+/*
  ---------------------------------
+
+   poly.c 
+   implements polygons and simplices
+
+   see qh-poly.htm, poly.h and qhull.h
+
+   infrequent code is in poly2.c 
+   (all but top 50 and their callers 12/3/95)
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#include "qhull_a.h"
+
+/*======== functions in alphabetical order ==========*/
+
+/*---------------------------------
+  
+  qh_appendfacet( facet )
+    appends facet to end of qh.facet_list,
+
+  returns:
+    updates qh.newfacet_list, facet_next, facet_list
+    increments qh.numfacets
+  
+  notes:
+    assumes qh.facet_list/facet_tail is defined (createsimplex)
+
+  see:
+    qh_removefacet()
+
+*/
+void qh_appendfacet(facetT *facet) {
+  facetT *tail= qh facet_tail;
+
+  if (tail == qh newfacet_list)
+    qh newfacet_list= facet;
+  if (tail == qh facet_next)
+    qh facet_next= facet;
+  facet->previous= tail->previous;
+  facet->next= tail;
+  if (tail->previous)
+    tail->previous->next= facet;
+  else
+    qh facet_list= facet;
+  tail->previous= facet;
+  qh num_facets++;
+  trace4((qh ferr, "qh_appendfacet: append f%d to facet_list\n", facet->id));
+} /* appendfacet */
+
+
+/*---------------------------------
+  
+  qh_appendvertex( vertex )
+    appends vertex to end of qh.vertex_list,
+
+  returns:
+    sets vertex->newlist
+    updates qh.vertex_list, newvertex_list
+    increments qh.num_vertices
+
+  notes:
+    assumes qh.vertex_list/vertex_tail is defined (createsimplex)
+
+*/
+void qh_appendvertex (vertexT *vertex) {
+  vertexT *tail= qh vertex_tail;
+
+  if (tail == qh newvertex_list)
+    qh newvertex_list= vertex;
+  vertex->newlist= True;
+  vertex->previous= tail->previous;
+  vertex->next= tail;
+  if (tail->previous)
+    tail->previous->next= vertex;
+  else
+    qh vertex_list= vertex;
+  tail->previous= vertex;
+  qh num_vertices++;
+  trace4((qh ferr, "qh_appendvertex: append v%d to vertex_list\n", vertex->id));
+} /* appendvertex */
+
+
+/*---------------------------------
+  
+  qh_attachnewfacets( )
+    attach horizon facets to new facets in qh.newfacet_list
+    newfacets have neighbor and ridge links to horizon but not vice versa
+    only needed for qh.ONLYgood
+
+  returns:
+    set qh.NEWfacets
+    horizon facets linked to new facets 
+      ridges changed from visible facets to new facets
+      simplicial ridges deleted
+    qh.visible_list, no ridges valid
+    facet->f.replace is a newfacet (if any)
+
+  design:
+    delete interior ridges and neighbor sets by
+      for each visible, non-simplicial facet
+        for each ridge
+          if last visit or if neighbor is simplicial
+            if horizon neighbor
+              delete ridge for horizon's ridge set
+            delete ridge
+        erase neighbor set
+    attach horizon facets and new facets by
+      for all new facets
+        if corresponding horizon facet is simplicial
+          locate corresponding visible facet {may be more than one}
+          link visible facet to new facet
+          replace visible facet with new facet in horizon
+        else it's non-simplicial
+          for all visible neighbors of the horizon facet
+            link visible neighbor to new facet
+            delete visible neighbor from horizon facet
+          append new facet to horizon's neighbors
+          the first ridge of the new facet is the horizon ridge
+          link the new facet into the horizon ridge
+*/
+void qh_attachnewfacets (void ) {
+  facetT *newfacet= NULL, *neighbor, **neighborp, *horizon, *visible;
+  ridgeT *ridge, **ridgep;
+
+  qh NEWfacets= True;
+  trace3((qh ferr, "qh_attachnewfacets: delete interior ridges\n"));
+  qh visit_id++;
+  FORALLvisible_facets {
+    visible->visitid= qh visit_id;
+    if (visible->ridges) {
+      FOREACHridge_(visible->ridges) {
+	neighbor= otherfacet_(ridge, visible);
+	if (neighbor->visitid == qh visit_id
+	    || (!neighbor->visible && neighbor->simplicial)) {
+	  if (!neighbor->visible)  /* delete ridge for simplicial horizon */
+	    qh_setdel (neighbor->ridges, ridge);
+	  qh_setfree (&(ridge->vertices)); /* delete on 2nd visit */
+	  qh_memfree (ridge, sizeof(ridgeT));
+	}
+      }
+      SETfirst_(visible->ridges)= NULL;
+    }
+    SETfirst_(visible->neighbors)= NULL;
+  }
+  trace1((qh ferr, "qh_attachnewfacets: attach horizon facets to new facets\n"));
+  FORALLnew_facets {
+    horizon= SETfirstt_(newfacet->neighbors, facetT);
+    if (horizon->simplicial) {
+      visible= NULL;
+      FOREACHneighbor_(horizon) {   /* may have more than one horizon ridge */
+	if (neighbor->visible) {
+	  if (visible) {
+	    if (qh_setequal_skip (newfacet->vertices, 0, horizon->vertices,
+				  SETindex_(horizon->neighbors, neighbor))) {
+	      visible= neighbor;
+	      break;
+	    }
+	  }else
+	    visible= neighbor;
+	}
+      }
+      if (visible) {
+	visible->f.replace= newfacet;
+	qh_setreplace (horizon->neighbors, visible, newfacet);
+      }else {
+	fprintf (qh ferr, "qhull internal error (qh_attachnewfacets): couldn't find visible facet for horizon f%d of newfacet f%d\n",
+		 horizon->id, newfacet->id);
+	qh_errexit2 (qh_ERRqhull, horizon, newfacet);
+      }
+    }else { /* non-simplicial, with a ridge for newfacet */
+      FOREACHneighbor_(horizon) {    /* may hold for many new facets */
+	if (neighbor->visible) {
+	  neighbor->f.replace= newfacet;
+	  qh_setdelnth (horizon->neighbors,
+			SETindex_(horizon->neighbors, neighbor));
+	  neighborp--; /* repeat */
+	}
+      }
+      qh_setappend (&horizon->neighbors, newfacet);
+      ridge= SETfirstt_(newfacet->ridges, ridgeT);
+      if (ridge->top == horizon)
+	ridge->bottom= newfacet;
+      else
+	ridge->top= newfacet;
+      }
+  } /* newfacets */
+  if (qh PRINTstatistics) {
+    FORALLvisible_facets {
+      if (!visible->f.replace) 
+	zinc_(Zinsidevisible);
+    }
+  }
+} /* attachnewfacets */
+
+/*---------------------------------
+  
+  qh_checkflipped( facet, dist, allerror )
+    checks facet orientation to interior point
+
+    if allerror set,
+      tests against qh.DISTround
+    else
+      tests against 0 since tested against DISTround before
+
+  returns:
+    False if it flipped orientation (sets facet->flipped)
+    distance if non-NULL
+*/
+boolT qh_checkflipped (facetT *facet, realT *distp, boolT allerror) {
+  realT dist;
+
+  if (facet->flipped && !distp)
+    return False;
+  zzinc_(Zdistcheck);
+  qh_distplane(qh interior_point, facet, &dist);
+  if (distp)
+    *distp= dist;
+  if ((allerror && dist > -qh DISTround)|| (!allerror && dist >= 0.0)) {
+    facet->flipped= True;
+    zzinc_(Zflippedfacets);
+    trace0((qh ferr, "qh_checkflipped: facet f%d is flipped, distance= %6.12g during p%d\n",
+              facet->id, dist, qh furthest_id));
+    qh_precision ("flipped facet");
+    return False;
+  }
+  return True;
+} /* checkflipped */
+
+/*---------------------------------
+  
+  qh_delfacet( facet )
+    removes facet from facet_list and frees up its memory
+
+  notes:
+    assumes vertices and ridges already freed
+*/
+void qh_delfacet(facetT *facet) {
+  void **freelistp; /* used !qh_NOmem */
+
+  trace4((qh ferr, "qh_delfacet: delete f%d\n", facet->id));
+  if (facet == qh tracefacet)
+    qh tracefacet= NULL;
+  if (facet == qh GOODclosest)
+    qh GOODclosest= NULL;
+  qh_removefacet(facet);
+  if (!facet->tricoplanar || facet->keepcentrum) {
+    qh_memfree_(facet->normal, qh normal_size, freelistp);
+    if (qh CENTERtype == qh_ASvoronoi) {   /* uses macro calls */
+      qh_memfree_(facet->center, qh center_size, freelistp);
+    }else /* AScentrum */ {
+      qh_memfree_(facet->center, qh normal_size, freelistp);
+    }
+  }
+  qh_setfree(&(facet->neighbors));
+  if (facet->ridges)
+    qh_setfree(&(facet->ridges));
+  qh_setfree(&(facet->vertices));
+  if (facet->outsideset)
+    qh_setfree(&(facet->outsideset));
+  if (facet->coplanarset)
+    qh_setfree(&(facet->coplanarset));
+  qh_memfree_(facet, sizeof(facetT), freelistp);
+} /* delfacet */
+
+
+/*---------------------------------
+  
+  qh_deletevisible()
+    delete visible facets and vertices
+
+  returns:
+    deletes each facet and removes from facetlist
+    at exit, qh.visible_list empty (== qh.newfacet_list)
+
+  notes:
+    ridges already deleted
+    horizon facets do not reference facets on qh.visible_list
+    new facets in qh.newfacet_list
+    uses   qh.visit_id;
+*/
+void qh_deletevisible (void /*qh visible_list*/) {
+  facetT *visible, *nextfacet;
+  vertexT *vertex, **vertexp;
+  int numvisible= 0, numdel= qh_setsize(qh del_vertices);
+
+  trace1((qh ferr, "qh_deletevisible: delete %d visible facets and %d vertices\n",
+         qh num_visible, numdel));
+  for (visible= qh visible_list; visible && visible->visible; 
+                visible= nextfacet) { /* deleting current */
+    nextfacet= visible->next;        
+    numvisible++;
+    qh_delfacet(visible);
+  }
+  if (numvisible != qh num_visible) {
+    fprintf (qh ferr, "qhull internal error (qh_deletevisible): qh num_visible %d is not number of visible facets %d\n",
+             qh num_visible, numvisible);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  qh num_visible= 0;
+  zadd_(Zvisfacettot, numvisible);
+  zmax_(Zvisfacetmax, numvisible);
+  zzadd_(Zdelvertextot, numdel);
+  zmax_(Zdelvertexmax, numdel);
+  FOREACHvertex_(qh del_vertices) 
+    qh_delvertex (vertex);
+  qh_settruncate (qh del_vertices, 0);
+} /* deletevisible */
+
+/*---------------------------------
+  
+  qh_facetintersect( facetA, facetB, skipa, skipB, prepend )
+    return vertices for intersection of two simplicial facets
+    may include 1 prepended entry (if more, need to settemppush)
+    
+  returns:
+    returns set of qh.hull_dim-1 + prepend vertices
+    returns skipped index for each test and checks for exactly one
+
+  notes:
+    does not need settemp since set in quick memory
+  
+  see also:
+    qh_vertexintersect and qh_vertexintersect_new
+    use qh_setnew_delnthsorted to get nth ridge (no skip information)
+
+  design:
+    locate skipped vertex by scanning facet A's neighbors
+    locate skipped vertex by scanning facet B's neighbors
+    intersect the vertex sets
+*/
+setT *qh_facetintersect (facetT *facetA, facetT *facetB,
+			 int *skipA,int *skipB, int prepend) {
+  setT *intersect;
+  int dim= qh hull_dim, i, j;
+  facetT **neighborsA, **neighborsB;
+
+  neighborsA= SETaddr_(facetA->neighbors, facetT);
+  neighborsB= SETaddr_(facetB->neighbors, facetT);
+  i= j= 0;
+  if (facetB == *neighborsA++)
+    *skipA= 0;
+  else if (facetB == *neighborsA++)
+    *skipA= 1;
+  else if (facetB == *neighborsA++)
+    *skipA= 2;
+  else {
+    for (i= 3; i < dim; i++) {
+      if (facetB == *neighborsA++) {
+        *skipA= i;
+        break;
+      }
+    }
+  }
+  if (facetA == *neighborsB++)
+    *skipB= 0;
+  else if (facetA == *neighborsB++)
+    *skipB= 1;
+  else if (facetA == *neighborsB++)
+    *skipB= 2;
+  else {
+    for (j= 3; j < dim; j++) {
+      if (facetA == *neighborsB++) {
+        *skipB= j;
+        break;
+      }
+    }
+  }
+  if (i >= dim || j >= dim) {
+    fprintf (qh ferr, "qhull internal error (qh_facetintersect): f%d or f%d not in others neighbors\n",
+            facetA->id, facetB->id);
+    qh_errexit2 (qh_ERRqhull, facetA, facetB);
+  }
+  intersect= qh_setnew_delnthsorted (facetA->vertices, qh hull_dim, *skipA, prepend);
+  trace4((qh ferr, "qh_facetintersect: f%d skip %d matches f%d skip %d\n",
+	  facetA->id, *skipA, facetB->id, *skipB));
+  return(intersect);
+} /* facetintersect */
+
+/*---------------------------------
+  
+  qh_gethash( hashsize, set, size, firstindex, skipelem )
+    return hashvalue for a set with firstindex and skipelem
+
+  notes:
+    assumes at least firstindex+1 elements
+    assumes skipelem is NULL, in set, or part of hash
+    
+    hashes memory addresses which may change over different runs of the same data
+    using sum for hash does badly in high d
+*/
+unsigned qh_gethash (int hashsize, setT *set, int size, int firstindex, void *skipelem) {
+  void **elemp= SETelemaddr_(set, firstindex, void);
+  ptr_intT hash = 0, elem;
+  int i;
+
+  switch (size-firstindex) {
+  case 1:
+    hash= (ptr_intT)(*elemp) - (ptr_intT) skipelem;
+    break;
+  case 2:
+    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] - (ptr_intT) skipelem;
+    break;
+  case 3:
+    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
+      - (ptr_intT) skipelem;
+    break;
+  case 4:
+    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
+      + (ptr_intT)elemp[3] - (ptr_intT) skipelem;
+    break;
+  case 5:
+    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
+      + (ptr_intT)elemp[3] + (ptr_intT)elemp[4] - (ptr_intT) skipelem;
+    break;
+  case 6:
+    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
+      + (ptr_intT)elemp[3] + (ptr_intT)elemp[4]+ (ptr_intT)elemp[5]
+      - (ptr_intT) skipelem;
+    break;
+  default:
+    hash= 0;
+    i= 3;
+    do {     /* this is about 10% in 10-d */
+      if ((elem= (ptr_intT)*elemp++) != (ptr_intT)skipelem) {
+        hash ^= (elem << i) + (elem >> (32-i));
+	i += 3;
+	if (i >= 32)
+	  i -= 32;
+      }
+    }while(*elemp);
+    break;
+  }
+  hash %= (ptr_intT) hashsize;
+  /* hash= 0; for debugging purposes */
+  return hash;
+} /* gethash */
+
+/*---------------------------------
+  
+  qh_makenewfacet( vertices, toporient, horizon )
+    creates a toporient? facet from vertices
+
+  returns:
+    returns newfacet
+      adds newfacet to qh.facet_list
+      newfacet->vertices= vertices
+      if horizon
+        newfacet->neighbor= horizon, but not vice versa
+    newvertex_list updated with vertices
+*/
+facetT *qh_makenewfacet(setT *vertices, boolT toporient,facetT *horizon) {
+  facetT *newfacet;
+  vertexT *vertex, **vertexp;
+
+  FOREACHvertex_(vertices) {
+    if (!vertex->newlist) {
+      qh_removevertex (vertex);
+      qh_appendvertex (vertex);
+    }
+  }
+  newfacet= qh_newfacet();
+  newfacet->vertices= vertices;
+  newfacet->toporient= toporient;
+  if (horizon)
+    qh_setappend(&(newfacet->neighbors), horizon);
+  qh_appendfacet(newfacet);
+  return(newfacet);
+} /* makenewfacet */
+
+
+/*---------------------------------
+  
+  qh_makenewplanes()
+    make new hyperplanes for facets on qh.newfacet_list
+
+  returns:
+    all facets have hyperplanes or are marked for   merging
+    doesn't create hyperplane if horizon is coplanar (will merge)
+    updates qh.min_vertex if qh.JOGGLEmax
+
+  notes:
+    facet->f.samecycle is defined for facet->mergehorizon facets
+*/
+void qh_makenewplanes (void /* newfacet_list */) {
+  facetT *newfacet;
+
+  FORALLnew_facets {
+    if (!newfacet->mergehorizon)
+      qh_setfacetplane (newfacet);  
+  }
+  if (qh JOGGLEmax < REALmax/2)  
+    minimize_(qh min_vertex, -wwval_(Wnewvertexmax));
+} /* makenewplanes */
+
+/*---------------------------------
+  
+  qh_makenew_nonsimplicial( visible, apex, numnew )
+    make new facets for ridges of a visible facet
+    
+  returns:
+    first newfacet, bumps numnew as needed
+    attaches new facets if !qh.ONLYgood
+    marks ridge neighbors for simplicial visible
+    if (qh.ONLYgood)
+      ridges on newfacet, horizon, and visible
+    else
+      ridge and neighbors between newfacet and   horizon
+      visible facet's ridges are deleted    
+
+  notes:
+    qh.visit_id if visible has already been processed
+    sets neighbor->seen for building f.samecycle
+      assumes all 'seen' flags initially false
+    
+  design:
+    for each ridge of visible facet
+      get neighbor of visible facet
+      if neighbor was already processed
+        delete the ridge (will delete all visible facets later)
+      if neighbor is a horizon facet
+        create a new facet
+        if neighbor coplanar
+          adds newfacet to f.samecycle for later merging
+        else 
+          updates neighbor's neighbor set
+          (checks for non-simplicial facet with multiple ridges to visible facet)
+        updates neighbor's ridge set
+        (checks for simplicial neighbor to non-simplicial visible facet)
+	(deletes ridge if neighbor is simplicial)
+          
+*/
+#ifndef qh_NOmerge
+facetT *qh_makenew_nonsimplicial (facetT *visible, vertexT *apex, int *numnew) {
+  void **freelistp; /* used !qh_NOmem */
+  ridgeT *ridge, **ridgep;
+  facetT *neighbor, *newfacet= NULL, *samecycle;
+  setT *vertices;
+  boolT toporient;
+  int ridgeid;
+
+  FOREACHridge_(visible->ridges) {
+    ridgeid= ridge->id;
+    neighbor= otherfacet_(ridge, visible);
+    if (neighbor->visible) {
+      if (!qh ONLYgood) {
+        if (neighbor->visitid == qh visit_id) {
+          qh_setfree (&(ridge->vertices));  /* delete on 2nd visit */
+	  qh_memfree_(ridge, sizeof(ridgeT), freelistp);
+	}
+      }
+    }else {  /* neighbor is an horizon facet */
+      toporient= (ridge->top == visible);
+      vertices= qh_setnew (qh hull_dim); /* makes sure this is quick */
+      qh_setappend (&vertices, apex);
+      qh_setappend_set (&vertices, ridge->vertices);
+      newfacet= qh_makenewfacet(vertices, toporient, neighbor);
+      (*numnew)++;
+      if (neighbor->coplanar) {
+	newfacet->mergehorizon= True;
+        if (!neighbor->seen) {
+          newfacet->f.samecycle= newfacet;
+          neighbor->f.newcycle= newfacet;
+        }else {
+          samecycle= neighbor->f.newcycle;
+          newfacet->f.samecycle= samecycle->f.samecycle;
+          samecycle->f.samecycle= newfacet;
+	}
+      }
+      if (qh ONLYgood) {
+        if (!neighbor->simplicial)
+ 	  qh_setappend(&(newfacet->ridges), ridge);
+      }else {  /* qh_attachnewfacets */
+        if (neighbor->seen) {
+	  if (neighbor->simplicial) {
+	    fprintf (qh ferr, "qhull internal error (qh_makenew_nonsimplicial): simplicial f%d sharing two ridges with f%d\n", 
+	           neighbor->id, visible->id);
+	    qh_errexit2 (qh_ERRqhull, neighbor, visible);
+	  }
+	  qh_setappend (&(neighbor->neighbors), newfacet);
+	}else
+          qh_setreplace (neighbor->neighbors, visible, newfacet);
+        if (neighbor->simplicial) {
+          qh_setdel (neighbor->ridges, ridge);
+          qh_setfree (&(ridge->vertices)); 
+	  qh_memfree (ridge, sizeof(ridgeT));
+	}else {
+ 	  qh_setappend(&(newfacet->ridges), ridge);
+ 	  if (toporient)
+ 	    ridge->top= newfacet;
+ 	  else
+ 	    ridge->bottom= newfacet;
+ 	}
+      trace4((qh ferr, "qh_makenew_nonsimplicial: created facet f%d from v%d and r%d of horizon f%d\n",
+	    newfacet->id, apex->id, ridgeid, neighbor->id));
+      }
+    }
+    neighbor->seen= True;        
+  } /* for each ridge */
+  if (!qh ONLYgood)
+    SETfirst_(visible->ridges)= NULL;
+  return newfacet;
+} /* makenew_nonsimplicial */
+#else /* qh_NOmerge */
+facetT *qh_makenew_nonsimplicial (facetT *visible, vertexT *apex, int *numnew) {
+  return NULL;
+}
+#endif /* qh_NOmerge */
+
+/*---------------------------------
+  
+  qh_makenew_simplicial( visible, apex, numnew )
+    make new facets for simplicial visible facet and apex
+
+  returns:
+    attaches new facets if (!qh.ONLYgood)
+      neighbors between newfacet and horizon
+
+  notes:
+    nop if neighbor->seen or neighbor->visible (see qh_makenew_nonsimplicial)
+
+  design:
+    locate neighboring horizon facet for visible facet
+    determine vertices and orientation
+    create new facet
+    if coplanar,
+      add new facet to f.samecycle
+    update horizon facet's neighbor list        
+*/
+facetT *qh_makenew_simplicial (facetT *visible, vertexT *apex, int *numnew) {
+  facetT *neighbor, **neighborp, *newfacet= NULL;
+  setT *vertices;
+  boolT flip, toporient;
+  int horizonskip, visibleskip;
+
+  FOREACHneighbor_(visible) {
+    if (!neighbor->seen && !neighbor->visible) {
+      vertices= qh_facetintersect(neighbor,visible, &horizonskip, &visibleskip, 1);
+      SETfirst_(vertices)= apex;
+      flip= ((horizonskip & 0x1) ^ (visibleskip & 0x1));
+      if (neighbor->toporient)         
+	toporient= horizonskip & 0x1;
+      else
+	toporient= (horizonskip & 0x1) ^ 0x1;
+      newfacet= qh_makenewfacet(vertices, toporient, neighbor);
+      (*numnew)++;
+      if (neighbor->coplanar && (qh PREmerge || qh MERGEexact)) {
+#ifndef qh_NOmerge
+	newfacet->f.samecycle= newfacet;
+	newfacet->mergehorizon= True;
+#endif
+      }
+      if (!qh ONLYgood)
+        SETelem_(neighbor->neighbors, horizonskip)= newfacet;
+      trace4((qh ferr, "qh_makenew_simplicial: create facet f%d top %d from v%d and horizon f%d skip %d top %d and visible f%d skip %d, flip? %d\n",
+	    newfacet->id, toporient, apex->id, neighbor->id, horizonskip,
+	      neighbor->toporient, visible->id, visibleskip, flip));
+    }
+  }
+  return newfacet;
+} /* makenew_simplicial */
+
+/*---------------------------------
+  
+  qh_matchneighbor( newfacet, newskip, hashsize, hashcount )
+    either match subridge of newfacet with neighbor or add to hash_table
+
+  returns:
+    duplicate ridges are unmatched and marked by qh_DUPLICATEridge
+
+  notes:
+    ridge is newfacet->vertices w/o newskip vertex
+    do not allocate memory (need to free hash_table cleanly)
+    uses linear hash chains
+  
+  see also:
+    qh_matchduplicates
+
+  design:
+    for each possible matching facet in qh.hash_table
+      if vertices match
+        set ismatch, if facets have opposite orientation
+        if ismatch and matching facet doesn't have a match
+          match the facets by updating their neighbor sets
+        else
+          indicate a duplicate ridge
+          set facet hyperplane for later testing
+          add facet to hashtable
+          unless the other facet was already a duplicate ridge
+            mark both facets with a duplicate ridge
+            add other facet (if defined) to hash table
+*/
+void qh_matchneighbor (facetT *newfacet, int newskip, int hashsize, int *hashcount) {
+  boolT newfound= False;   /* True, if new facet is already in hash chain */
+  boolT same, ismatch;
+  int hash, scan;
+  facetT *facet, *matchfacet;
+  int skip, matchskip;
+
+  hash= (int)qh_gethash (hashsize, newfacet->vertices, qh hull_dim, 1, 
+                     SETelem_(newfacet->vertices, newskip));
+  trace4((qh ferr, "qh_matchneighbor: newfacet f%d skip %d hash %d hashcount %d\n",
+	  newfacet->id, newskip, hash, *hashcount));
+  zinc_(Zhashlookup);
+  for (scan= hash; (facet= SETelemt_(qh hash_table, scan, facetT)); 
+       scan= (++scan >= hashsize ? 0 : scan)) {
+    if (facet == newfacet) {
+      newfound= True;
+      continue;
+    }
+    zinc_(Zhashtests);
+    if (qh_matchvertices (1, newfacet->vertices, newskip, facet->vertices, &skip, &same)) {
+      if (SETelem_(newfacet->vertices, newskip) == 
+          SETelem_(facet->vertices, skip)) {
+        qh_precision ("two facets with the same vertices");
+        fprintf (qh ferr, "qhull precision error: Vertex sets are the same for f%d and f%d.  Can not force output.\n",
+          facet->id, newfacet->id);
+        qh_errexit2 (qh_ERRprec, facet, newfacet);
+      }
+      ismatch= (same == (newfacet->toporient ^ facet->toporient));
+      matchfacet= SETelemt_(facet->neighbors, skip, facetT);
+      if (ismatch && !matchfacet) {
+        SETelem_(facet->neighbors, skip)= newfacet;
+        SETelem_(newfacet->neighbors, newskip)= facet;
+        (*hashcount)--;
+        trace4((qh ferr, "qh_matchneighbor: f%d skip %d matched with new f%d skip %d\n",
+           facet->id, skip, newfacet->id, newskip));
+        return;
+      }
+      if (!qh PREmerge && !qh MERGEexact) {
+        qh_precision ("a ridge with more than two neighbors");
+	fprintf (qh ferr, "qhull precision error: facets f%d, f%d and f%d meet at a ridge with more than 2 neighbors.  Can not continue.\n",
+		 facet->id, newfacet->id, getid_(matchfacet));
+	qh_errexit2 (qh_ERRprec, facet, newfacet);
+      }
+      SETelem_(newfacet->neighbors, newskip)= qh_DUPLICATEridge;
+      newfacet->dupridge= True;
+      if (!newfacet->normal)
+	qh_setfacetplane (newfacet);
+      qh_addhash (newfacet, qh hash_table, hashsize, hash);
+      (*hashcount)++;
+      if (!facet->normal)
+	qh_setfacetplane (facet);
+      if (matchfacet != qh_DUPLICATEridge) {
+	SETelem_(facet->neighbors, skip)= qh_DUPLICATEridge;
+	facet->dupridge= True;
+	if (!facet->normal)
+	  qh_setfacetplane (facet);
+	if (matchfacet) {
+	  matchskip= qh_setindex (matchfacet->neighbors, facet);
+	  SETelem_(matchfacet->neighbors, matchskip)= qh_DUPLICATEridge;
+	  matchfacet->dupridge= True;
+	  if (!matchfacet->normal)
+	    qh_setfacetplane (matchfacet);
+	  qh_addhash (matchfacet, qh hash_table, hashsize, hash);
+	  *hashcount += 2;
+	}
+      }
+      trace4((qh ferr, "qh_matchneighbor: new f%d skip %d duplicates ridge for f%d skip %d matching f%d ismatch %d at hash %d\n",
+	   newfacet->id, newskip, facet->id, skip, 
+	   (matchfacet == qh_DUPLICATEridge ? -2 : getid_(matchfacet)), 
+	   ismatch, hash));
+      return; /* end of duplicate ridge */
+    }
+  }
+  if (!newfound) 
+    SETelem_(qh hash_table, scan)= newfacet;  /* same as qh_addhash */
+  (*hashcount)++;
+  trace4((qh ferr, "qh_matchneighbor: no match for f%d skip %d at hash %d\n",
+           newfacet->id, newskip, hash));
+} /* matchneighbor */
+
+
+/*---------------------------------
+  
+  qh_matchnewfacets()
+    match newfacets in qh.newfacet_list to their newfacet neighbors
+
+  returns:
+    qh.newfacet_list with full neighbor sets
+      get vertices with nth neighbor by deleting nth vertex
+    if qh.PREmerge/MERGEexact or qh.FORCEoutput 
+      sets facet->flippped if flipped normal (also prevents point partitioning)
+    if duplicate ridges and qh.PREmerge/MERGEexact
+      sets facet->dupridge
+      missing neighbor links identifies extra ridges to be merging (qh_MERGEridge)
+
+  notes:
+    newfacets already have neighbor[0] (horizon facet)
+    assumes qh.hash_table is NULL
+    vertex->neighbors has not been updated yet
+    do not allocate memory after qh.hash_table (need to free it cleanly)
+
+  design:
+    delete neighbor sets for all new facets
+    initialize a hash table
+    for all new facets
+      match facet with neighbors
+    if unmatched facets (due to duplicate ridges)
+      for each new facet with a duplicate ridge
+        match it with a facet
+    check for flipped facets
+*/
+void qh_matchnewfacets (void /* qh newfacet_list */) {
+  int numnew=0, hashcount=0, newskip;
+  facetT *newfacet, *neighbor;
+  int dim= qh hull_dim, hashsize, neighbor_i, neighbor_n;
+  setT *neighbors;
+#ifndef qh_NOtrace
+  int facet_i, facet_n, numfree= 0;
+  facetT *facet;
+#endif
+  
+  trace1((qh ferr, "qh_matchnewfacets: match neighbors for new facets.\n"));
+  FORALLnew_facets {
+    numnew++;
+    {  /* inline qh_setzero (newfacet->neighbors, 1, qh hull_dim); */
+      neighbors= newfacet->neighbors;
+      neighbors->e[neighbors->maxsize].i= dim+1; /*may be overwritten*/
+      memset ((char *)SETelemaddr_(neighbors, 1, void), 0, dim * SETelemsize);
+    }    
+  }
+  qh_newhashtable (numnew*(qh hull_dim-1)); /* twice what is normally needed,
+                                     but every ridge could be DUPLICATEridge */
+  hashsize= qh_setsize (qh hash_table);
+  FORALLnew_facets {
+    for (newskip=1; newskipneighbors, k, facetT);
+	  if (!neighbor || neighbor == qh_DUPLICATEridge)
+	    count++;
+	}
+	if (facet == newfacet)
+	  break;
+      }
+      if (count != hashcount) {
+	fprintf (qh ferr, "qh_matchnewfacets: after adding facet %d, hashcount %d != count %d\n",
+		 newfacet->id, hashcount, count);
+	qh_errexit (qh_ERRqhull, newfacet, NULL);
+      }
+    }
+#endif  /* end of trap code */
+  }
+  if (hashcount) {
+    FORALLnew_facets {
+      if (newfacet->dupridge) {
+        FOREACHneighbor_i_(newfacet) {
+          if (neighbor == qh_DUPLICATEridge) {
+            qh_matchduplicates (newfacet, neighbor_i, hashsize, &hashcount);
+         	    /* this may report MERGEfacet */
+	  }
+        }
+      }
+    }
+  }
+  if (hashcount) {
+    fprintf (qh ferr, "qhull internal error (qh_matchnewfacets): %d neighbors did not match up\n",
+        hashcount);
+    qh_printhashtable (qh ferr);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+#ifndef qh_NOtrace
+  if (qh IStracing >= 2) {
+    FOREACHfacet_i_(qh hash_table) {
+      if (!facet)
+        numfree++;
+    }
+    fprintf (qh ferr, "qh_matchnewfacets: %d new facets, %d unused hash entries .  hashsize %d\n",
+	     numnew, numfree, qh_setsize (qh hash_table));
+  }
+#endif /* !qh_NOtrace */
+  qh_setfree (&qh hash_table);
+  if (qh PREmerge || qh MERGEexact) {
+    if (qh IStracing >= 4)
+      qh_printfacetlist (qh newfacet_list, NULL, qh_ALL);
+    FORALLnew_facets {
+      if (newfacet->normal)
+	qh_checkflipped (newfacet, NULL, qh_ALL);
+    }
+  }else if (qh FORCEoutput)
+    qh_checkflipped_all (qh newfacet_list);  /* prints warnings for flipped */
+} /* matchnewfacets */
+
+    
+/*---------------------------------
+  
+  qh_matchvertices( firstindex, verticesA, skipA, verticesB, skipB, same )
+    tests whether vertices match with a single skip
+    starts match at firstindex since all new facets have a common vertex
+
+  returns:
+    true if matched vertices
+    skip index for each set
+    sets same iff vertices have the same orientation
+
+  notes:
+    assumes skipA is in A and both sets are the same size
+
+  design:
+    set up pointers
+    scan both sets checking for a match
+    test orientation
+*/
+boolT qh_matchvertices (int firstindex, setT *verticesA, int skipA, 
+       setT *verticesB, int *skipB, boolT *same) {
+  vertexT **elemAp, **elemBp, **skipBp=NULL, **skipAp;
+
+  elemAp= SETelemaddr_(verticesA, firstindex, vertexT);
+  elemBp= SETelemaddr_(verticesB, firstindex, vertexT);
+  skipAp= SETelemaddr_(verticesA, skipA, vertexT);
+  do if (elemAp != skipAp) {
+    while (*elemAp != *elemBp++) {
+      if (skipBp)
+        return False;
+      skipBp= elemBp;  /* one extra like FOREACH */
+    }
+  }while(*(++elemAp));
+  if (!skipBp)
+    skipBp= ++elemBp;
+  *skipB= SETindex_(verticesB, skipB);
+  *same= !(((ptr_intT)skipA & 0x1) ^ ((ptr_intT)*skipB & 0x1));
+  trace4((qh ferr, "qh_matchvertices: matched by skip %d (v%d) and skip %d (v%d) same? %d\n",
+	  skipA, (*skipAp)->id, *skipB, (*(skipBp-1))->id, *same));
+  return (True);
+} /* matchvertices */
+
+/*---------------------------------
+  
+  qh_newfacet()
+    return a new facet 
+
+  returns:
+    all fields initialized or cleared   (NULL)
+    preallocates neighbors set
+*/
+facetT *qh_newfacet(void) {
+  facetT *facet;
+  void **freelistp; /* used !qh_NOmem */
+  
+  qh_memalloc_(sizeof(facetT), freelistp, facet, facetT);
+  memset ((char *)facet, 0, sizeof(facetT));
+  if (qh facet_id == qh tracefacet_id)
+    qh tracefacet= facet;
+  facet->id= qh facet_id++;
+  facet->neighbors= qh_setnew(qh hull_dim);
+#if !qh_COMPUTEfurthest
+  facet->furthestdist= 0.0;
+#endif
+#if qh_MAXoutside
+  if (qh FORCEoutput && qh APPROXhull)
+    facet->maxoutside= qh MINoutside;
+  else
+    facet->maxoutside= qh DISTround;
+#endif
+  facet->simplicial= True;
+  facet->good= True;
+  facet->newfacet= True;
+  trace4((qh ferr, "qh_newfacet: created facet f%d\n", facet->id));
+  return (facet);
+} /* newfacet */
+
+
+/*---------------------------------
+  
+  qh_newridge()
+    return a new ridge
+*/
+ridgeT *qh_newridge(void) {
+  ridgeT *ridge;
+  void **freelistp;   /* used !qh_NOmem */
+
+  qh_memalloc_(sizeof(ridgeT), freelistp, ridge, ridgeT);
+  memset ((char *)ridge, 0, sizeof(ridgeT));
+  zinc_(Ztotridges);
+  if (qh ridge_id == 0xFFFFFF) {
+    fprintf(qh ferr, "\
+qhull warning: more than %d ridges.  ID field overflows and two ridges\n\
+may have the same identifier.  Otherwise output ok.\n", 0xFFFFFF);
+  }
+  ridge->id= qh ridge_id++;     
+  trace4((qh ferr, "qh_newridge: created ridge r%d\n", ridge->id));
+  return (ridge);
+} /* newridge */
+
+
+/*---------------------------------
+  
+  qh_pointid(  )
+    return id for a point, 
+    returns -3 if null, -2 if interior, or -1 if not known
+
+  alternative code:
+    unsigned long id;
+    id= ((unsigned long)point - (unsigned long)qh.first_point)/qh.normal_size;
+
+  notes:
+    if point not in point array
+      the code does a comparison of unrelated pointers.
+*/
+int qh_pointid (pointT *point) {
+  long offset, id;
+
+  if (!point)
+    id= -3;
+  else if (point == qh interior_point)
+    id= -2;
+  else if (point >= qh first_point
+  && point < qh first_point + qh num_points * qh hull_dim) {
+    offset= point - qh first_point;
+    id= offset / qh hull_dim;
+  }else if ((id= qh_setindex (qh other_points, point)) != -1)
+    id += qh num_points;
+  else
+    id= -1;
+  return (int) id;
+} /* pointid */
+  
+/*---------------------------------
+  
+  qh_removefacet( facet )
+    unlinks facet from qh.facet_list,
+
+  returns:
+    updates qh.facet_list .newfacet_list .facet_next visible_list
+    decrements qh.num_facets
+
+  see:
+    qh_appendfacet
+*/
+void qh_removefacet(facetT *facet) {
+  facetT *next= facet->next, *previous= facet->previous;
+  
+  if (facet == qh newfacet_list)
+    qh newfacet_list= next;
+  if (facet == qh facet_next)
+    qh facet_next= next;
+  if (facet == qh visible_list)
+    qh visible_list= next; 
+  if (previous) {
+    previous->next= next;
+    next->previous= previous;
+  }else {  /* 1st facet in qh facet_list */
+    qh facet_list= next;
+    qh facet_list->previous= NULL;
+  }
+  qh num_facets--;
+  trace4((qh ferr, "qh_removefacet: remove f%d from facet_list\n", facet->id));
+} /* removefacet */
+
+
+/*---------------------------------
+  
+  qh_removevertex( vertex )
+    unlinks vertex from qh.vertex_list,
+
+  returns:
+    updates qh.vertex_list .newvertex_list 
+    decrements qh.num_vertices
+*/
+void qh_removevertex(vertexT *vertex) {
+  vertexT *next= vertex->next, *previous= vertex->previous;
+  
+  if (vertex == qh newvertex_list)
+    qh newvertex_list= next;
+  if (previous) {
+    previous->next= next;
+    next->previous= previous;
+  }else {  /* 1st vertex in qh vertex_list */
+    qh vertex_list= vertex->next;
+    qh vertex_list->previous= NULL;
+  }
+  qh num_vertices--;
+  trace4((qh ferr, "qh_removevertex: remove v%d from vertex_list\n", vertex->id));
+} /* removevertex */
+
+
+/*---------------------------------
+  
+  qh_updatevertices()
+    update vertex neighbors and delete interior vertices
+
+  returns:
+    if qh.VERTEXneighbors, updates neighbors for each vertex
+      if qh.newvertex_list, 
+         removes visible neighbors  from vertex neighbors
+      if qh.newfacet_list
+         adds new facets to vertex neighbors
+    if qh.visible_list
+       interior vertices added to qh.del_vertices for later partitioning
+
+  design:
+    if qh.VERTEXneighbors
+      deletes references to visible facets from vertex neighbors
+      appends new facets to the neighbor list for each vertex
+      checks all vertices of visible facets
+        removes visible facets from neighbor lists
+        marks unused vertices for deletion
+*/
+void qh_updatevertices (void /*qh newvertex_list, newfacet_list, visible_list*/) {
+  facetT *newfacet= NULL, *neighbor, **neighborp, *visible;
+  vertexT *vertex, **vertexp;
+
+  trace3((qh ferr, "qh_updatevertices: delete interior vertices and update vertex->neighbors\n"));
+  if (qh VERTEXneighbors) {
+    FORALLvertex_(qh newvertex_list) {
+      FOREACHneighbor_(vertex) {
+	if (neighbor->visible) 
+	  SETref_(neighbor)= NULL;
+      }
+      qh_setcompact (vertex->neighbors);
+    }
+    FORALLnew_facets {
+      FOREACHvertex_(newfacet->vertices)
+        qh_setappend (&vertex->neighbors, newfacet);
+    }
+    FORALLvisible_facets {
+      FOREACHvertex_(visible->vertices) {
+        if (!vertex->newlist && !vertex->deleted) {
+  	  FOREACHneighbor_(vertex) { /* this can happen under merging */
+	    if (!neighbor->visible)
+	      break;
+	  }
+	  if (neighbor)
+	    qh_setdel (vertex->neighbors, visible);
+	  else {
+	    vertex->deleted= True;
+	    qh_setappend (&qh del_vertices, vertex);
+	    trace2((qh ferr, "qh_updatevertices: delete vertex p%d (v%d) in f%d\n",
+		  qh_pointid(vertex->point), vertex->id, visible->id));
+  	  }
+        }
+      }
+    }
+  }else {  /* !VERTEXneighbors */
+    FORALLvisible_facets {
+      FOREACHvertex_(visible->vertices) {
+        if (!vertex->newlist && !vertex->deleted) {
+          vertex->deleted= True;
+	  qh_setappend (&qh del_vertices, vertex);
+	  trace2((qh ferr, "qh_updatevertices: delete vertex p%d (v%d) in f%d\n",
+		  qh_pointid(vertex->point), vertex->id, visible->id));
+  	}
+      }
+    }
+  }
+} /* updatevertices */
+
+
+
diff --git a/extern/qhull/src/poly.h b/extern/qhull/src/poly.h
new file mode 100644
index 00000000000..294ec9527fc
--- /dev/null
+++ b/extern/qhull/src/poly.h
@@ -0,0 +1,290 @@
+/*
  ---------------------------------
+
+   poly.h 
+   header file for poly.c and poly2.c
+
+   see qh-poly.htm, qhull.h and poly.c
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFpoly
+#define qhDEFpoly 1
+
+/*===============   constants ========================== */
+
+/*----------------------------------
+  
+  ALGORITHMfault   
+    use as argument to checkconvex() to report errors during buildhull
+*/
+#define qh_ALGORITHMfault 0
+
+/*----------------------------------
+  
+  DATAfault        
+    use as argument to checkconvex() to report errors during initialhull
+*/
+#define qh_DATAfault 1
+
+/*----------------------------------
+  
+  DUPLICATEridge
+    special value for facet->neighbor to indicate a duplicate ridge
+  
+  notes:
+    set by matchneighbor, used by matchmatch and mark_dupridge
+*/
+#define qh_DUPLICATEridge ( facetT * ) 1L
+
+/*----------------------------------
+  
+  MERGEridge       flag in facet
+    special value for facet->neighbor to indicate a merged ridge
+  
+  notes:
+    set by matchneighbor, used by matchmatch and mark_dupridge
+*/
+#define qh_MERGEridge ( facetT * ) 2L
+
+
+/*============ -structures- ====================*/
+
+/*=========== -macros- =========================*/
+
+/*----------------------------------
+  
+  FORALLfacet_( facetlist ) { ... }
+    assign 'facet' to each facet in facetlist
+    
+  notes:
+    uses 'facetT *facet;'
+    assumes last facet is a sentinel
+    
+  see:
+    FORALLfacets
+*/
+#define FORALLfacet_( facetlist ) if ( facetlist ) for( facet=( facetlist );facet && facet->next;facet=facet->next )
+
+/*----------------------------------
+  
+  FORALLnew_facets { ... } 
+    assign 'newfacet' to each facet in qh.newfacet_list
+    
+  notes:
+    uses 'facetT *newfacet;'
+    at exit, newfacet==NULL
+*/
+#define FORALLnew_facets for( newfacet=qh newfacet_list;newfacet && newfacet->next;newfacet=newfacet->next )
+
+/*----------------------------------
+  
+  FORALLvertex_( vertexlist ) { ... }
+    assign 'vertex' to each vertex in vertexlist
+    
+  notes:
+    uses 'vertexT *vertex;'
+    at exit, vertex==NULL
+*/
+#define FORALLvertex_( vertexlist ) for ( vertex=( vertexlist );vertex && vertex->next;vertex= vertex->next )
+
+/*----------------------------------
+  
+  FORALLvisible_facets { ... }
+    assign 'visible' to each visible facet in qh.visible_list
+    
+  notes:
+    uses 'vacetT *visible;'
+    at exit, visible==NULL
+*/
+#define FORALLvisible_facets for (visible=qh visible_list; visible && visible->visible; visible= visible->next)
+
+/*----------------------------------
+  
+  FORALLsame_( newfacet ) { ... } 
+    assign 'same' to each facet in newfacet->f.samecycle
+    
+  notes:
+    uses 'facetT *same;'
+    stops when it returns to newfacet
+*/
+#define FORALLsame_(newfacet) for (same= newfacet->f.samecycle; same != newfacet; same= same->f.samecycle)
+
+/*----------------------------------
+  
+  FORALLsame_cycle_( newfacet ) { ... } 
+    assign 'same' to each facet in newfacet->f.samecycle
+    
+  notes:
+    uses 'facetT *same;'
+    at exit, same == NULL
+*/
+#define FORALLsame_cycle_(newfacet) \
+     for (same= newfacet->f.samecycle; \
+         same; same= (same == newfacet ?  NULL : same->f.samecycle))
+
+/*----------------------------------
+  
+  FOREACHneighborA_( facet ) { ... }
+    assign 'neighborA' to each neighbor in facet->neighbors
+  
+  FOREACHneighborA_( vertex ) { ... }
+    assign 'neighborA' to each neighbor in vertex->neighbors
+  
+  declare:
+    facetT *neighborA, **neighborAp;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHneighborA_(facet)  FOREACHsetelement_(facetT, facet->neighbors, neighborA)
+
+/*----------------------------------
+  
+  FOREACHvisible_( facets ) { ... } 
+    assign 'visible' to each facet in facets
+    
+  notes:
+    uses 'facetT *facet, *facetp;'
+    see FOREACHsetelement_
+*/
+#define FOREACHvisible_(facets) FOREACHsetelement_(facetT, facets, visible)
+
+/*----------------------------------
+  
+  FOREACHnewfacet_( facets ) { ... } 
+    assign 'newfacet' to each facet in facets
+    
+  notes:
+    uses 'facetT *newfacet, *newfacetp;'
+    see FOREACHsetelement_
+*/
+#define FOREACHnewfacet_(facets) FOREACHsetelement_(facetT, facets, newfacet)
+
+/*----------------------------------
+  
+  FOREACHvertexA_( vertices ) { ... } 
+    assign 'vertexA' to each vertex in vertices
+    
+  notes:
+    uses 'vertexT *vertexA, *vertexAp;'
+    see FOREACHsetelement_
+*/
+#define FOREACHvertexA_(vertices) FOREACHsetelement_(vertexT, vertices, vertexA)
+
+/*----------------------------------
+  
+  FOREACHvertexreverse12_( vertices ) { ... } 
+    assign 'vertex' to each vertex in vertices
+    reverse order of first two vertices
+    
+  notes:
+    uses 'vertexT *vertex, *vertexp;'
+    see FOREACHsetelement_
+*/
+#define FOREACHvertexreverse12_(vertices) FOREACHsetelementreverse12_(vertexT, vertices, vertex)
+
+
+/*=============== prototypes poly.c in alphabetical order ================*/
+
+void    qh_appendfacet(facetT *facet);
+void    qh_appendvertex(vertexT *vertex);
+void 	qh_attachnewfacets (void);
+boolT   qh_checkflipped (facetT *facet, realT *dist, boolT allerror);
+void	qh_delfacet(facetT *facet);
+void 	qh_deletevisible(void /*qh visible_list, qh horizon_list*/);
+setT   *qh_facetintersect (facetT *facetA, facetT *facetB, int *skipAp,int *skipBp, int extra);
+unsigned qh_gethash (int hashsize, setT *set, int size, int firstindex, void *skipelem);
+facetT *qh_makenewfacet(setT *vertices, boolT toporient, facetT *facet);
+void    qh_makenewplanes ( void /* newfacet_list */);
+facetT *qh_makenew_nonsimplicial (facetT *visible, vertexT *apex, int *numnew);
+facetT *qh_makenew_simplicial (facetT *visible, vertexT *apex, int *numnew);
+void    qh_matchneighbor (facetT *newfacet, int newskip, int hashsize,
+			  int *hashcount);
+void	qh_matchnewfacets (void);
+boolT   qh_matchvertices (int firstindex, setT *verticesA, int skipA, 
+			  setT *verticesB, int *skipB, boolT *same);
+facetT *qh_newfacet(void);
+ridgeT *qh_newridge(void);
+int     qh_pointid (pointT *point);
+void 	qh_removefacet(facetT *facet);
+void 	qh_removevertex(vertexT *vertex);
+void    qh_updatevertices (void);
+
+
+/*========== -prototypes poly2.c in alphabetical order ===========*/
+
+void    qh_addhash (void* newelem, setT *hashtable, int hashsize, unsigned hash);
+void 	qh_check_bestdist (void);
+void    qh_check_maxout (void);
+void    qh_check_output (void);
+void    qh_check_point (pointT *point, facetT *facet, realT *maxoutside, realT *maxdist, facetT **errfacet1, facetT **errfacet2);
+void   	qh_check_points(void);
+void 	qh_checkconvex(facetT *facetlist, int fault);
+void    qh_checkfacet(facetT *facet, boolT newmerge, boolT *waserrorp);
+void 	qh_checkflipped_all (facetT *facetlist);
+void 	qh_checkpolygon(facetT *facetlist);
+void    qh_checkvertex (vertexT *vertex);
+void 	qh_clearcenters (qh_CENTER type);
+void 	qh_createsimplex(setT *vertices);
+void 	qh_delridge(ridgeT *ridge);
+void    qh_delvertex (vertexT *vertex);
+setT   *qh_facet3vertex (facetT *facet);
+facetT *qh_findbestfacet (pointT *point, boolT bestoutside,
+           realT *bestdist, boolT *isoutside);
+facetT *qh_findfacet_all (pointT *point, realT *bestdist, boolT *isoutside,
+			  int *numpart);
+int 	qh_findgood (facetT *facetlist, int goodhorizon);
+void 	qh_findgood_all (facetT *facetlist);
+void    qh_furthestnext (void /* qh facet_list */);
+void    qh_furthestout (facetT *facet);
+void    qh_infiniteloop (facetT *facet);
+void 	qh_initbuild(void);
+void 	qh_initialhull(setT *vertices);
+setT   *qh_initialvertices(int dim, setT *maxpoints, pointT *points, int numpoints);
+vertexT *qh_isvertex (pointT *point, setT *vertices);
+vertexT *qh_makenewfacets (pointT *point /*horizon_list, visible_list*/);
+void    qh_matchduplicates (facetT *atfacet, int atskip, int hashsize, int *hashcount);
+void    qh_nearcoplanar ( void /* qh.facet_list */);
+vertexT *qh_nearvertex (facetT *facet, pointT *point, realT *bestdistp);
+int 	qh_newhashtable(int newsize);
+vertexT *qh_newvertex(pointT *point);
+ridgeT *qh_nextridge3d (ridgeT *atridge, facetT *facet, vertexT **vertexp);
+void    qh_outcoplanar (void /* facet_list */);
+pointT *qh_point (int id);
+void 	qh_point_add (setT *set, pointT *point, void *elem);
+setT   *qh_pointfacet (void /*qh facet_list*/);
+setT   *qh_pointvertex (void /*qh facet_list*/);
+void 	qh_prependfacet(facetT *facet, facetT **facetlist);
+void	qh_printhashtable(FILE *fp);
+void    qh_printlists (void);
+void    qh_resetlists (boolT stats, boolT resetVisible /*qh newvertex_list newfacet_list visible_list*/);
+void    qh_setvoronoi_all (void);
+void	qh_triangulate (void /*qh facet_list*/);
+void    qh_triangulate_facet (facetT *facetA, vertexT **first_vertex);
+void    qh_triangulate_link (facetT *oldfacetA, facetT *facetA, facetT *oldfacetB, facetT *facetB);
+void	qh_triangulate_mirror (facetT *facetA, facetT *facetB);
+void    qh_triangulate_null (facetT *facetA);
+void    qh_vertexintersect(setT **vertexsetA,setT *vertexsetB);
+setT   *qh_vertexintersect_new(setT *vertexsetA,setT *vertexsetB);
+void    qh_vertexneighbors (void /*qh facet_list*/);
+boolT 	qh_vertexsubset(setT *vertexsetA, setT *vertexsetB);
+
+
+#endif /* qhDEFpoly */
diff --git a/extern/qhull/src/poly2.c b/extern/qhull/src/poly2.c
new file mode 100644
index 00000000000..713faab8bed
--- /dev/null
+++ b/extern/qhull/src/poly2.c
@@ -0,0 +1,3070 @@
+/*
  ---------------------------------
+
+   poly2.c 
+   implements polygons and simplices
+
+   see qh-poly.htm, poly.h and qhull.h
+
+   frequently used code is in poly.c
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#include "qhull_a.h"
+
+/*======== functions in alphabetical order ==========*/
+
+/*---------------------------------
+  
+  qh_addhash( newelem, hashtable, hashsize, hash )
+    add newelem to linear hash table at hash if not already there
+*/
+void qh_addhash (void* newelem, setT *hashtable, int hashsize, unsigned hash) {
+  int scan;
+  void *elem;
+
+  for (scan= (int)hash; (elem= SETelem_(hashtable, scan)); 
+       scan= (++scan >= hashsize ? 0 : scan)) {
+    if (elem == newelem)
+      break;
+  }
+  /* loop terminates because qh_HASHfactor >= 1.1 by qh_initbuffers */
+  if (!elem)
+    SETelem_(hashtable, scan)= newelem;
+} /* addhash */
+
+/*---------------------------------
+  
+  qh_check_bestdist()
+    check that all points are within max_outside of the nearest facet
+    if qh.ONLYgood,
+      ignores !good facets
+
+  see: 
+    qh_check_maxout(), qh_outerinner()
+
+  notes:
+    only called from qh_check_points()
+      seldom used since qh.MERGING is almost always set
+    if notverified>0 at end of routine
+      some points were well inside the hull.  If the hull contains
+      a lens-shaped component, these points were not verified.  Use
+      options 'Qi Tv' to verify all points.  (Exhaustive check also verifies)
+
+  design:
+    determine facet for each point (if any)
+    for each point
+      start with the assigned facet or with the first facet
+      find the best facet for the point and check all coplanar facets
+      error if point is outside of facet
+*/
+void qh_check_bestdist (void) {
+  boolT waserror= False, unassigned;
+  facetT *facet, *bestfacet, *errfacet1= NULL, *errfacet2= NULL;
+  facetT *facetlist; 
+  realT dist, maxoutside, maxdist= -REALmax;
+  pointT *point;
+  int numpart= 0, facet_i, facet_n, notgood= 0, notverified= 0;
+  setT *facets;
+
+  trace1((qh ferr, "qh_check_bestdist: check points below nearest facet.  Facet_list f%d\n",
+      qh facet_list->id));
+  maxoutside= qh_maxouter();
+  maxoutside += qh DISTround;
+  /* one more qh.DISTround for check computation */
+  trace1((qh ferr, "qh_check_bestdist: check that all points are within %2.2g of best facet\n", maxoutside));
+  facets= qh_pointfacet (/*qh facet_list*/);
+  if (!qh_QUICKhelp && qh PRINTprecision)
+    fprintf (qh ferr, "\n\
+qhull output completed.  Verifying that %d points are\n\
+below %2.2g of the nearest %sfacet.\n",
+	     qh_setsize(facets), maxoutside, (qh ONLYgood ?  "good " : ""));
+  FOREACHfacet_i_(facets) {  /* for each point with facet assignment */
+    if (facet)
+      unassigned= False;
+    else {
+      unassigned= True;
+      facet= qh facet_list;
+    }
+    point= qh_point(facet_i);
+    if (point == qh GOODpointp)
+      continue;
+    qh_distplane(point, facet, &dist);
+    numpart++;
+    bestfacet= qh_findbesthorizon (!qh_IScheckmax, point, facet, qh_NOupper, &dist, &numpart);
+    /* occurs after statistics reported */
+    maximize_(maxdist, dist);
+    if (dist > maxoutside) {
+      if (qh ONLYgood && !bestfacet->good 
+	  && !((bestfacet= qh_findgooddist (point, bestfacet, &dist, &facetlist))
+	       && dist > maxoutside))
+	notgood++;
+      else {
+	waserror= True;
+	fprintf(qh ferr, "qhull precision error: point p%d is outside facet f%d, distance= %6.8g maxoutside= %6.8g\n", 
+		facet_i, bestfacet->id, dist, maxoutside);
+	if (errfacet1 != bestfacet) {
+	  errfacet2= errfacet1;
+	  errfacet1= bestfacet;
+	}
+      }
+    }else if (unassigned && dist < -qh MAXcoplanar)
+      notverified++;
+  }
+  qh_settempfree (&facets);
+  if (notverified && !qh DELAUNAY && !qh_QUICKhelp && qh PRINTprecision) 
+    fprintf(qh ferr, "\n%d points were well inside the hull.  If the hull contains\n\
+a lens-shaped component, these points were not verified.  Use\n\
+options 'Qci Tv' to verify all points.\n", notverified); 
+  if (maxdist > qh outside_err) {
+    fprintf( qh ferr, "qhull precision error (qh_check_bestdist): a coplanar point is %6.2g from convex hull.  The maximum value (qh.outside_err) is %6.2g\n",
+              maxdist, qh outside_err);
+    qh_errexit2 (qh_ERRprec, errfacet1, errfacet2);
+  }else if (waserror && qh outside_err > REALmax/2)
+    qh_errexit2 (qh_ERRprec, errfacet1, errfacet2);
+  else if (waserror)
+    ;                       /* the error was logged to qh.ferr but does not effect the output */
+  trace0((qh ferr, "qh_check_bestdist: max distance outside %2.2g\n", maxdist));
+} /* check_bestdist */
+
+/*---------------------------------
+  
+  qh_check_maxout()
+    updates qh.max_outside by checking all points against bestfacet
+    if qh.ONLYgood, ignores !good facets
+
+  returns:
+    updates facet->maxoutside via qh_findbesthorizon()
+    sets qh.maxoutdone
+    if printing qh.min_vertex (qh_outerinner), 
+      it is updated to the current vertices
+    removes inside/coplanar points from coplanarset as needed
+
+  notes:
+    defines coplanar as min_vertex instead of MAXcoplanar 
+    may not need to check near-inside points because of qh.MAXcoplanar 
+      and qh.KEEPnearinside (before it was -DISTround)
+
+  see also:
+    qh_check_bestdist()
+
+  design:
+    if qh.min_vertex is needed
+      for all neighbors of all vertices
+        test distance from vertex to neighbor
+    determine facet for each point (if any)
+    for each point with an assigned facet
+      find the best facet for the point and check all coplanar facets
+        (updates outer planes)
+    remove near-inside points from coplanar sets
+*/
+#ifndef qh_NOmerge
+void qh_check_maxout (void) {
+  facetT *facet, *bestfacet, *neighbor, **neighborp, *facetlist;
+  realT dist, maxoutside, minvertex, old_maxoutside;
+  pointT *point;
+  int numpart= 0, facet_i, facet_n, notgood= 0;
+  setT *facets, *vertices;
+  vertexT *vertex;
+
+  trace1((qh ferr, "qh_check_maxout: check and update maxoutside for each facet.\n"));
+  maxoutside= minvertex= 0;
+  if (qh VERTEXneighbors 
+  && (qh PRINTsummary || qh KEEPinside || qh KEEPcoplanar 
+	|| qh TRACElevel || qh PRINTstatistics
+	|| qh PRINTout[0] == qh_PRINTsummary || qh PRINTout[0] == qh_PRINTnone)) { 
+    trace1((qh ferr, "qh_check_maxout: determine actual maxoutside and minvertex\n"));
+    vertices= qh_pointvertex (/*qh facet_list*/);
+    FORALLvertices {
+      FOREACHneighbor_(vertex) {
+        zinc_(Zdistvertex);  /* distance also computed by main loop below */
+	qh_distplane (vertex->point, neighbor, &dist);
+	minimize_(minvertex, dist);
+	if (-dist > qh TRACEdist || dist > qh TRACEdist 
+	|| neighbor == qh tracefacet || vertex == qh tracevertex)
+	  fprintf (qh ferr, "qh_check_maxout: p%d (v%d) is %.2g from f%d\n",
+		    qh_pointid (vertex->point), vertex->id, dist, neighbor->id);
+      }
+    }
+    if (qh MERGING) {
+      wmin_(Wminvertex, qh min_vertex);
+    }
+    qh min_vertex= minvertex;
+    qh_settempfree (&vertices);  
+  }
+  facets= qh_pointfacet (/*qh facet_list*/);
+  do {
+    old_maxoutside= fmax_(qh max_outside, maxoutside);
+    FOREACHfacet_i_(facets) {     /* for each point with facet assignment */
+      if (facet) { 
+	point= qh_point(facet_i);
+	if (point == qh GOODpointp)
+	  continue;
+	zinc_(Ztotcheck);
+	qh_distplane(point, facet, &dist);
+	numpart++;
+	bestfacet= qh_findbesthorizon (qh_IScheckmax, point, facet, !qh_NOupper, &dist, &numpart);
+	if (bestfacet && dist > maxoutside) {
+	  if (qh ONLYgood && !bestfacet->good 
+	  && !((bestfacet= qh_findgooddist (point, bestfacet, &dist, &facetlist))
+	       && dist > maxoutside))
+	    notgood++;
+	  else
+	    maxoutside= dist;
+	}
+	if (dist > qh TRACEdist || (bestfacet && bestfacet == qh tracefacet))
+	  fprintf (qh ferr, "qh_check_maxout: p%d is %.2g above f%d\n",
+		     qh_pointid (point), dist, bestfacet->id);
+      }
+    }
+  }while 
+    (maxoutside > 2*old_maxoutside);
+    /* if qh.maxoutside increases substantially, qh_SEARCHdist is not valid 
+          e.g., RBOX 5000 s Z1 G1e-13 t1001200614 | qhull */
+  zzadd_(Zcheckpart, numpart);
+  qh_settempfree (&facets);
+  wval_(Wmaxout)= maxoutside - qh max_outside;
+  wmax_(Wmaxoutside, qh max_outside);
+  qh max_outside= maxoutside;
+  qh_nearcoplanar (/*qh.facet_list*/);
+  qh maxoutdone= True;
+  trace1((qh ferr, "qh_check_maxout: maxoutside %2.2g, min_vertex %2.2g, outside of not good %d\n",
+       maxoutside, qh min_vertex, notgood));
+} /* check_maxout */
+#else /* qh_NOmerge */
+void qh_check_maxout (void) {
+}
+#endif
+
+/*---------------------------------
+  
+  qh_check_output()
+    performs the checks at the end of qhull algorithm
+    Maybe called after voronoi output.  Will recompute otherwise centrums are Voronoi centers instead
+*/
+void qh_check_output (void) {
+  int i;
+
+  if (qh STOPcone)
+    return;
+  if (qh VERIFYoutput | qh IStracing | qh CHECKfrequently) {
+    qh_checkpolygon (qh facet_list);
+    qh_checkflipped_all (qh facet_list);
+    qh_checkconvex (qh facet_list, qh_ALGORITHMfault);
+  }else if (!qh MERGING && qh_newstats (qhstat precision, &i)) {
+    qh_checkflipped_all (qh facet_list);
+    qh_checkconvex (qh facet_list, qh_ALGORITHMfault);
+  }
+} /* check_output */
+
+
+
+/*---------------------------------
+  
+  qh_check_point( point, facet, maxoutside, maxdist, errfacet1, errfacet2 )
+    check that point is less than maxoutside from facet
+*/
+void qh_check_point (pointT *point, facetT *facet, realT *maxoutside, realT *maxdist, facetT **errfacet1, facetT **errfacet2) {
+  realT dist;
+
+  /* occurs after statistics reported */
+  qh_distplane(point, facet, &dist);
+  if (dist > *maxoutside) {
+    if (*errfacet1 != facet) {
+      *errfacet2= *errfacet1;
+      *errfacet1= facet;
+    }
+    fprintf(qh ferr, "qhull precision error: point p%d is outside facet f%d, distance= %6.8g maxoutside= %6.8g\n", 
+	      qh_pointid(point), facet->id, dist, *maxoutside);
+  }
+  maximize_(*maxdist, dist);
+} /* qh_check_point */
+
+
+/*---------------------------------
+  
+  qh_check_points()
+    checks that all points are inside all facets
+
+  notes:
+    if many points and qh_check_maxout not called (i.e., !qh.MERGING), 
+       calls qh_findbesthorizon (seldom done).
+    ignores flipped facets
+    maxoutside includes 2 qh.DISTrounds
+      one qh.DISTround for the computed distances in qh_check_points
+    qh_printafacet and qh_printsummary needs only one qh.DISTround
+    the computation for qh.VERIFYdirect does not account for qh.other_points
+
+  design:
+    if many points
+      use qh_check_bestdist()
+    else
+      for all facets
+        for all points
+          check that point is inside facet
+*/
+void qh_check_points (void) {
+  facetT *facet, *errfacet1= NULL, *errfacet2= NULL;
+  realT total, maxoutside, maxdist= -REALmax;
+  pointT *point, **pointp, *pointtemp;
+  boolT testouter;
+
+  maxoutside= qh_maxouter();
+  maxoutside += qh DISTround;
+  /* one more qh.DISTround for check computation */
+  trace1((qh ferr, "qh_check_points: check all points below %2.2g of all facet planes\n",
+	  maxoutside));
+  if (qh num_good)   /* miss counts other_points and !good facets */
+     total= (float) qh num_good * qh num_points;
+  else
+     total= (float) qh num_facets * qh num_points;
+  if (total >= qh_VERIFYdirect && !qh maxoutdone) {
+    if (!qh_QUICKhelp && qh SKIPcheckmax && qh MERGING)
+      fprintf (qh ferr, "\n\
+qhull input warning: merging without checking outer planes ('Q5' or 'Po').\n\
+Verify may report that a point is outside of a facet.\n");
+    qh_check_bestdist();
+  }else {
+    if (qh_MAXoutside && qh maxoutdone)
+      testouter= True;
+    else
+      testouter= False;
+    if (!qh_QUICKhelp) {
+      if (qh MERGEexact)
+	fprintf (qh ferr, "\n\
+qhull input warning: exact merge ('Qx').  Verify may report that a point\n\
+is outside of a facet.  See qh-optq.htm#Qx\n");
+      else if (qh SKIPcheckmax || qh NOnearinside)
+	fprintf (qh ferr, "\n\
+qhull input warning: no outer plane check ('Q5') or no processing of\n\
+near-inside points ('Q8').  Verify may report that a point is outside\n\
+of a facet.\n");
+    }
+    if (qh PRINTprecision) {
+      if (testouter)
+	fprintf (qh ferr, "\n\
+Output completed.  Verifying that all points are below outer planes of\n\
+all %sfacets.  Will make %2.0f distance computations.\n", 
+	      (qh ONLYgood ?  "good " : ""), total);
+      else
+	fprintf (qh ferr, "\n\
+Output completed.  Verifying that all points are below %2.2g of\n\
+all %sfacets.  Will make %2.0f distance computations.\n", 
+	      maxoutside, (qh ONLYgood ?  "good " : ""), total);
+    }
+    FORALLfacets {
+      if (!facet->good && qh ONLYgood)
+        continue;
+      if (facet->flipped)
+        continue;
+      if (!facet->normal) {
+	fprintf( qh ferr, "qhull warning (qh_check_points): missing normal for facet f%d\n", facet->id);
+        continue;
+      }
+      if (testouter) {
+#if qh_MAXoutside
+	maxoutside= facet->maxoutside + 2* qh DISTround;
+	/* one DISTround to actual point and another to computed point */
+#endif
+      }
+      FORALLpoints {
+	if (point != qh GOODpointp)
+	  qh_check_point (point, facet, &maxoutside, &maxdist, &errfacet1, &errfacet2);
+      }
+      FOREACHpoint_(qh other_points) {
+	if (point != qh GOODpointp)
+	  qh_check_point (point, facet, &maxoutside, &maxdist, &errfacet1, &errfacet2);
+      }
+    }
+    if (maxdist > qh outside_err) {
+      fprintf( qh ferr, "qhull precision error (qh_check_points): a coplanar point is %6.2g from convex hull.  The maximum value (qh.outside_err) is %6.2g\n",
+                maxdist, qh outside_err );
+      qh_errexit2( qh_ERRprec, errfacet1, errfacet2 );
+    }else if (errfacet1 && qh outside_err > REALmax/2)
+        qh_errexit2( qh_ERRprec, errfacet1, errfacet2 );
+    else if (errfacet1)
+        ;  /* the error was logged to qh.ferr but does not effect the output */
+    trace0((qh ferr, "qh_check_points: max distance outside %2.2g\n", maxdist));
+  }
+} /* check_points */
+
+
+/*---------------------------------
+  
+  qh_checkconvex( facetlist, fault )
+    check that each ridge in facetlist is convex
+    fault = qh_DATAfault if reporting errors
+          = qh_ALGORITHMfault otherwise
+
+  returns:
+    counts Zconcaveridges and Zcoplanarridges
+    errors if concaveridge or if merging an coplanar ridge
+
+  note:
+    if not merging, 
+      tests vertices for neighboring simplicial facets
+    else if ZEROcentrum, 
+      tests vertices for neighboring simplicial   facets
+    else 
+      tests centrums of neighboring facets
+
+  design:
+    for all facets
+      report flipped facets
+      if ZEROcentrum and simplicial neighbors
+        test vertices for neighboring simplicial facets
+      else
+        test centrum against all neighbors 
+*/
+void qh_checkconvex(facetT *facetlist, int fault) {
+  facetT *facet, *neighbor, **neighborp, *errfacet1=NULL, *errfacet2=NULL;
+  vertexT *vertex;
+  realT dist;
+  pointT *centrum;
+  boolT waserror= False, centrum_warning= False, tempcentrum= False, allsimplicial;
+  int neighbor_i;
+
+  trace1((qh ferr, "qh_checkconvex: check all ridges are convex\n"));
+  if (!qh RERUN) {
+    zzval_(Zconcaveridges)= 0;
+    zzval_(Zcoplanarridges)= 0;
+  }
+  FORALLfacet_(facetlist) {
+    if (facet->flipped) {
+      qh_precision ("flipped facet");
+      fprintf (qh ferr, "qhull precision error: f%d is flipped (interior point is outside)\n",
+	       facet->id);
+      errfacet1= facet;
+      waserror= True;
+      continue;
+    }
+    if (qh MERGING && (!qh ZEROcentrum || !facet->simplicial || facet->tricoplanar))
+      allsimplicial= False;
+    else {
+      allsimplicial= True;
+      neighbor_i= 0;
+      FOREACHneighbor_(facet) {
+        vertex= SETelemt_(facet->vertices, neighbor_i++, vertexT);
+	if (!neighbor->simplicial || neighbor->tricoplanar) {
+	  allsimplicial= False;
+	  continue;
+	}
+        qh_distplane (vertex->point, neighbor, &dist);
+        if (dist > -qh DISTround) {
+	  if (fault == qh_DATAfault) {
+            qh_precision ("coplanar or concave ridge");
+	    fprintf (qh ferr, "qhull precision error: initial simplex is not convex. Distance=%.2g\n", dist);
+	    qh_errexit(qh_ERRsingular, NULL, NULL);
+	  }
+          if (dist > qh DISTround) {
+            zzinc_(Zconcaveridges);
+            qh_precision ("concave ridge");
+            fprintf (qh ferr, "qhull precision error: f%d is concave to f%d, since p%d (v%d) is %6.4g above\n",
+              facet->id, neighbor->id, qh_pointid(vertex->point), vertex->id, dist);
+            errfacet1= facet;
+            errfacet2= neighbor;
+            waserror= True;
+          }else if (qh ZEROcentrum) {
+            if (dist > 0) {     /* qh_checkzero checks that dist < - qh DISTround */
+              zzinc_(Zcoplanarridges); 
+              qh_precision ("coplanar ridge");
+              fprintf (qh ferr, "qhull precision error: f%d is clearly not convex to f%d, since p%d (v%d) is %6.4g above\n",
+                facet->id, neighbor->id, qh_pointid(vertex->point), vertex->id, dist);
+              errfacet1= facet;
+              errfacet2= neighbor;
+              waserror= True;
+	    }
+	  }else {              
+            zzinc_(Zcoplanarridges);
+            qh_precision ("coplanar ridge");
+            trace0((qh ferr, "qhull precision error: f%d may be coplanar to f%d, since p%d (v%d) is within %6.4g during p%d\n",
+              facet->id, neighbor->id, qh_pointid(vertex->point), vertex->id, dist, qh furthest_id));
+          }
+        }
+      }
+    }
+    if (!allsimplicial) {
+      if (qh CENTERtype == qh_AScentrum) {
+        if (!facet->center)
+          facet->center= qh_getcentrum (facet);
+        centrum= facet->center;
+      }else {
+	if (!centrum_warning && (!facet->simplicial || facet->tricoplanar)) {
+	   centrum_warning= True;
+	   fprintf (qh ferr, "qhull note: recomputing centrums for convexity test.  This may lead to false, precision errors.\n");
+	}
+        centrum= qh_getcentrum(facet);
+        tempcentrum= True;
+      }
+      FOREACHneighbor_(facet) {
+	if (qh ZEROcentrum && facet->simplicial && neighbor->simplicial)
+	  continue;
+	if (facet->tricoplanar || neighbor->tricoplanar)
+	  continue;
+        zzinc_(Zdistconvex);
+        qh_distplane (centrum, neighbor, &dist);
+        if (dist > qh DISTround) {
+          zzinc_(Zconcaveridges);
+          qh_precision ("concave ridge");
+          fprintf (qh ferr, "qhull precision error: f%d is concave to f%d.  Centrum of f%d is %6.4g above f%d\n",
+            facet->id, neighbor->id, facet->id, dist, neighbor->id);
+          errfacet1= facet;
+          errfacet2= neighbor;
+          waserror= True;
+	}else if (dist >= 0.0) {   /* if arithmetic always rounds the same,
+				     can test against centrum radius instead */
+          zzinc_(Zcoplanarridges);
+          qh_precision ("coplanar ridge");
+          fprintf (qh ferr, "qhull precision error: f%d is coplanar or concave to f%d.  Centrum of f%d is %6.4g above f%d\n",
+            facet->id, neighbor->id, facet->id, dist, neighbor->id);
+	  errfacet1= facet;
+	  errfacet2= neighbor;
+	  waserror= True;
+        }
+      }
+      if (tempcentrum)
+        qh_memfree(centrum, qh normal_size);
+    }
+  }
+  if (waserror && !qh FORCEoutput)
+    qh_errexit2 (qh_ERRprec, errfacet1, errfacet2);
+} /* checkconvex */
+
+
+/*---------------------------------
+  
+  qh_checkfacet( facet, newmerge, waserror )
+    checks for consistency errors in facet
+    newmerge set if from merge.c
+
+  returns:
+    sets waserror if any error occurs
+
+  checks:
+    vertex ids are inverse sorted
+    unless newmerge, at least hull_dim neighbors and vertices (exactly if simplicial)
+    if non-simplicial, at least as many ridges as neighbors
+    neighbors are not duplicated
+    ridges are not duplicated
+    in 3-d, ridges=verticies
+    (qh.hull_dim-1) ridge vertices
+    neighbors are reciprocated
+    ridge neighbors are facet neighbors and a ridge for every neighbor
+    simplicial neighbors match facetintersect
+    vertex intersection matches vertices of common ridges 
+    vertex neighbors and facet vertices agree
+    all ridges have distinct vertex sets
+
+  notes:  
+    uses neighbor->seen
+
+  design:
+    check sets
+    check vertices
+    check sizes of neighbors and vertices
+    check for qh_MERGEridge and qh_DUPLICATEridge flags
+    check neighbor set
+    check ridge set
+    check ridges, neighbors, and vertices
+*/
+void qh_checkfacet(facetT *facet, boolT newmerge, boolT *waserrorp) {
+  facetT *neighbor, **neighborp, *errother=NULL;
+  ridgeT *ridge, **ridgep, *errridge= NULL, *ridge2;
+  vertexT *vertex, **vertexp;
+  unsigned previousid= INT_MAX;
+  int numneighbors, numvertices, numridges=0, numRvertices=0;
+  boolT waserror= False;
+  int skipA, skipB, ridge_i, ridge_n, i;
+  setT *intersection;
+
+  if (facet->visible) {
+    fprintf (qh ferr, "qhull internal error (qh_checkfacet): facet f%d is on the visible_list\n",
+      facet->id);
+    qh_errexit (qh_ERRqhull, facet, NULL);
+  }
+  if (!facet->normal) {
+    fprintf (qh ferr, "qhull internal error (qh_checkfacet): facet f%d does not have  a normal\n",
+      facet->id);
+    waserror= True;
+  }
+  qh_setcheck (facet->vertices, "vertices for f", facet->id);
+  qh_setcheck (facet->ridges, "ridges for f", facet->id);
+  qh_setcheck (facet->outsideset, "outsideset for f", facet->id);
+  qh_setcheck (facet->coplanarset, "coplanarset for f", facet->id);
+  qh_setcheck (facet->neighbors, "neighbors for f", facet->id);
+  FOREACHvertex_(facet->vertices) {
+    if (vertex->deleted) {
+      fprintf(qh ferr, "qhull internal error (qh_checkfacet): deleted vertex v%d in f%d\n", vertex->id, facet->id);
+      qh_errprint ("ERRONEOUS", NULL, NULL, NULL, vertex);
+      waserror= True;
+    }
+    if (vertex->id >= previousid) {
+      fprintf(qh ferr, "qhull internal error (qh_checkfacet): vertices of f%d are not in descending id order at v%d\n", facet->id, vertex->id);
+      waserror= True;
+      break;
+    }
+    previousid= vertex->id;
+  }
+  numneighbors= qh_setsize(facet->neighbors);
+  numvertices= qh_setsize(facet->vertices);
+  numridges= qh_setsize(facet->ridges);
+  if (facet->simplicial) {
+    if (numvertices+numneighbors != 2*qh hull_dim 
+    && !facet->degenerate && !facet->redundant) {
+      fprintf(qh ferr, "qhull internal error (qh_checkfacet): for simplicial facet f%d, #vertices %d + #neighbors %d != 2*qh hull_dim\n", 
+                facet->id, numvertices, numneighbors);
+      qh_setprint (qh ferr, "", facet->neighbors);
+      waserror= True;
+    }
+  }else { /* non-simplicial */
+    if (!newmerge 
+    &&(numvertices < qh hull_dim || numneighbors < qh hull_dim)
+    && !facet->degenerate && !facet->redundant) {
+      fprintf(qh ferr, "qhull internal error (qh_checkfacet): for facet f%d, #vertices %d or #neighbors %d < qh hull_dim\n",
+         facet->id, numvertices, numneighbors);
+       waserror= True;
+    }
+    /* in 3-d, can get a vertex twice in an edge list, e.g., RBOX 1000 s W1e-13 t995849315 D2 | QHULL d Tc Tv TP624 TW1e-13 T4 */
+    if (numridges < numneighbors
+    ||(qh hull_dim == 3 && numvertices > numridges && !qh NEWfacets)
+    ||(qh hull_dim == 2 && numridges + numvertices + numneighbors != 6)) {
+      if (!facet->degenerate && !facet->redundant) {
+	fprintf(qh ferr, "qhull internal error (qh_checkfacet): for facet f%d, #ridges %d < #neighbors %d or (3-d) > #vertices %d or (2-d) not all 2\n",
+	    facet->id, numridges, numneighbors, numvertices);
+	waserror= True;
+      }
+    }
+  }
+  FOREACHneighbor_(facet) {
+    if (neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge) {
+      fprintf(qh ferr, "qhull internal error (qh_checkfacet): facet f%d still has a MERGE or DUP neighbor\n", facet->id);
+      qh_errexit (qh_ERRqhull, facet, NULL);
+    }
+    neighbor->seen= True;
+  }
+  FOREACHneighbor_(facet) {
+    if (!qh_setin(neighbor->neighbors, facet)) {
+      fprintf(qh ferr, "qhull internal error (qh_checkfacet): facet f%d has neighbor f%d, but f%d does not have neighbor f%d\n",
+	      facet->id, neighbor->id, neighbor->id, facet->id);
+      errother= neighbor;
+      waserror= True;
+    }
+    if (!neighbor->seen) {
+      fprintf(qh ferr, "qhull internal error (qh_checkfacet): facet f%d has a duplicate neighbor f%d\n",
+	      facet->id, neighbor->id);
+      errother= neighbor;
+      waserror= True;
+    }    
+    neighbor->seen= False;
+  }
+  FOREACHridge_(facet->ridges) {
+    qh_setcheck (ridge->vertices, "vertices for r", ridge->id);
+    ridge->seen= False;
+  }
+  FOREACHridge_(facet->ridges) {
+    if (ridge->seen) {
+      fprintf(qh ferr, "qhull internal error (qh_checkfacet): facet f%d has a duplicate ridge r%d\n",
+	      facet->id, ridge->id);
+      errridge= ridge;
+      waserror= True;
+    }    
+    ridge->seen= True;
+    numRvertices= qh_setsize(ridge->vertices);
+    if (numRvertices != qh hull_dim - 1) {
+      fprintf(qh ferr, "qhull internal error (qh_checkfacet): ridge between f%d and f%d has %d vertices\n", 
+                ridge->top->id, ridge->bottom->id, numRvertices);
+      errridge= ridge;
+      waserror= True;
+    }
+    neighbor= otherfacet_(ridge, facet);
+    neighbor->seen= True;
+    if (!qh_setin(facet->neighbors, neighbor)) {
+      fprintf(qh ferr, "qhull internal error (qh_checkfacet): for facet f%d, neighbor f%d of ridge r%d not in facet\n",
+           facet->id, neighbor->id, ridge->id);
+      errridge= ridge;
+      waserror= True;
+    }
+  }
+  if (!facet->simplicial) {
+    FOREACHneighbor_(facet) {
+      if (!neighbor->seen) {
+        fprintf(qh ferr, "qhull internal error (qh_checkfacet): facet f%d does not have a ridge for neighbor f%d\n",
+	      facet->id, neighbor->id);
+	errother= neighbor;
+        waserror= True;
+      }
+      intersection= qh_vertexintersect_new(facet->vertices, neighbor->vertices);
+      qh_settemppush (intersection);
+      FOREACHvertex_(facet->vertices) {
+	vertex->seen= False;
+	vertex->seen2= False;
+      }
+      FOREACHvertex_(intersection)
+	vertex->seen= True;
+      FOREACHridge_(facet->ridges) {
+	if (neighbor != otherfacet_(ridge, facet))
+	    continue;
+	FOREACHvertex_(ridge->vertices) {
+	  if (!vertex->seen) {
+	    fprintf (qh ferr, "qhull internal error (qh_checkfacet): vertex v%d in r%d not in f%d intersect f%d\n",
+  	          vertex->id, ridge->id, facet->id, neighbor->id);
+	    qh_errexit (qh_ERRqhull, facet, ridge);
+	  }
+	  vertex->seen2= True;
+	}
+      }
+      if (!newmerge) {
+	FOREACHvertex_(intersection) {
+	  if (!vertex->seen2) {
+	    if (qh IStracing >=3 || !qh MERGING) {
+	      fprintf (qh ferr, "qhull precision error (qh_checkfacet): vertex v%d in f%d intersect f%d but\n\
+ not in a ridge.  This is ok under merging.  Last point was p%d\n",
+		     vertex->id, facet->id, neighbor->id, qh furthest_id);
+	      if (!qh FORCEoutput && !qh MERGING) {
+		qh_errprint ("ERRONEOUS", facet, neighbor, NULL, vertex);
+		if (!qh MERGING)
+		  qh_errexit (qh_ERRqhull, NULL, NULL);
+	      }
+	    }
+	  }
+	}
+      }      
+      qh_settempfree (&intersection);
+    }
+  }else { /* simplicial */
+    FOREACHneighbor_(facet) {
+      if (neighbor->simplicial) {    
+	skipA= SETindex_(facet->neighbors, neighbor);
+	skipB= qh_setindex (neighbor->neighbors, facet);
+	if (!qh_setequal_skip (facet->vertices, skipA, neighbor->vertices, skipB)) {
+	  fprintf (qh ferr, "qhull internal error (qh_checkfacet): facet f%d skip %d and neighbor f%d skip %d do not match \n",
+		   facet->id, skipA, neighbor->id, skipB);
+	  errother= neighbor;
+	  waserror= True;
+	}
+      }
+    }
+  }
+  if (qh hull_dim < 5 && (qh IStracing > 2 || qh CHECKfrequently)) {
+    FOREACHridge_i_(facet->ridges) {           /* expensive */
+      for (i= ridge_i+1; i < ridge_n; i++) {
+	ridge2= SETelemt_(facet->ridges, i, ridgeT);
+	if (qh_setequal (ridge->vertices, ridge2->vertices)) {
+	  fprintf (qh ferr, "qh_checkfacet: ridges r%d and r%d have the same vertices\n",
+		  ridge->id, ridge2->id);
+	  errridge= ridge;
+	  waserror= True;
+	}
+      }
+    }
+  }
+  if (waserror) {
+    qh_errprint("ERRONEOUS", facet, errother, errridge, NULL);
+    *waserrorp= True;
+  }
+} /* checkfacet */
+
+
+/*---------------------------------
+  
+  qh_checkflipped_all( facetlist )
+    checks orientation of facets in list against interior point
+*/
+void qh_checkflipped_all (facetT *facetlist) {
+  facetT *facet;
+  boolT waserror= False;
+  realT dist;
+
+  if (facetlist == qh facet_list)
+    zzval_(Zflippedfacets)= 0;
+  FORALLfacet_(facetlist) {
+    if (facet->normal && !qh_checkflipped (facet, &dist, !qh_ALL)) {
+      fprintf(qh ferr, "qhull precision error: facet f%d is flipped, distance= %6.12g\n",
+	      facet->id, dist);
+      if (!qh FORCEoutput) {
+	qh_errprint("ERRONEOUS", facet, NULL, NULL, NULL);
+	waserror= True;
+      }
+    }
+  }
+  if (waserror) {
+    fprintf (qh ferr, "\n\
+A flipped facet occurs when its distance to the interior point is\n\
+greater than %2.2g, the maximum roundoff error.\n", -qh DISTround);
+    qh_errexit(qh_ERRprec, NULL, NULL);
+  }
+} /* checkflipped_all */
+
+/*---------------------------------
+  
+  qh_checkpolygon( facetlist )
+    checks the correctness of the structure
+
+  notes:
+    call with either qh.facet_list or qh.newfacet_list
+    checks num_facets and num_vertices if qh.facet_list
+
+  design:
+    for each facet
+      checks facet and outside set
+    initializes vertexlist
+    for each facet
+      checks vertex set
+    if checking all facets (qh.facetlist)
+      check facet count
+      if qh.VERTEXneighbors
+        check vertex neighbors and count
+      check vertex count
+*/
+void qh_checkpolygon(facetT *facetlist) {
+  facetT *facet;
+  vertexT *vertex, **vertexp, *vertexlist;
+  int numfacets= 0, numvertices= 0, numridges= 0;
+  int totvneighbors= 0, totvertices= 0;
+  boolT waserror= False, nextseen= False, visibleseen= False;
+  
+  trace1((qh ferr, "qh_checkpolygon: check all facets from f%d\n", facetlist->id));
+  if (facetlist != qh facet_list || qh ONLYgood)
+    nextseen= True;
+  FORALLfacet_(facetlist) {
+    if (facet == qh visible_list)
+      visibleseen= True;
+    if (!facet->visible) {
+      if (!nextseen) {
+	if (facet == qh facet_next)
+	  nextseen= True;
+	else if (qh_setsize (facet->outsideset)) {
+	  if (!qh NARROWhull
+#if !qh_COMPUTEfurthest
+	       || facet->furthestdist >= qh MINoutside
+#endif
+			) {
+	    fprintf (qh ferr, "qhull internal error (qh_checkpolygon): f%d has outside points before qh facet_next\n",
+		     facet->id);
+	    qh_errexit (qh_ERRqhull, facet, NULL);
+	  }
+	}
+      }
+      numfacets++;
+      qh_checkfacet(facet, False, &waserror);
+    }
+  }
+  if (qh visible_list && !visibleseen && facetlist == qh facet_list) {
+    fprintf (qh ferr, "qhull internal error (qh_checkpolygon): visible list f%d no longer on facet list\n", qh visible_list->id);
+    qh_printlists();
+    qh_errexit (qh_ERRqhull, qh visible_list, NULL);
+  }
+  if (facetlist == qh facet_list)
+    vertexlist= qh vertex_list;
+  else if (facetlist == qh newfacet_list)
+    vertexlist= qh newvertex_list;
+  else
+    vertexlist= NULL;
+  FORALLvertex_(vertexlist) {
+    vertex->seen= False;
+    vertex->visitid= 0;
+  }  
+  FORALLfacet_(facetlist) {
+    if (facet->visible)
+      continue;
+    if (facet->simplicial)
+      numridges += qh hull_dim;
+    else
+      numridges += qh_setsize (facet->ridges);
+    FOREACHvertex_(facet->vertices) {
+      vertex->visitid++;
+      if (!vertex->seen) {
+	vertex->seen= True;
+	numvertices++;
+	if (qh_pointid (vertex->point) == -1) {
+	  fprintf (qh ferr, "qhull internal error (qh_checkpolygon): unknown point %p for vertex v%d first_point %p\n",
+		   vertex->point, vertex->id, qh first_point);
+	  waserror= True;
+	}
+      }
+    }
+  }
+  qh vertex_visit += numfacets;
+  if (facetlist == qh facet_list) {
+    if (numfacets != qh num_facets - qh num_visible) {
+      fprintf(qh ferr, "qhull internal error (qh_checkpolygon): actual number of facets is %d, cumulative facet count is %d - %d visible facets\n",
+	      numfacets, qh num_facets, qh num_visible);
+      waserror= True;
+    }
+    qh vertex_visit++;
+    if (qh VERTEXneighbors) {
+      FORALLvertices {
+	qh_setcheck (vertex->neighbors, "neighbors for v", vertex->id);
+	if (vertex->deleted)
+	  continue;
+	totvneighbors += qh_setsize (vertex->neighbors);
+      }
+      FORALLfacet_(facetlist)
+	totvertices += qh_setsize (facet->vertices);
+      if (totvneighbors != totvertices) {
+	fprintf(qh ferr, "qhull internal error (qh_checkpolygon): vertex neighbors inconsistent.  Totvneighbors %d, totvertices %d\n",
+		totvneighbors, totvertices);
+	waserror= True;
+      }
+    }
+    if (numvertices != qh num_vertices - qh_setsize(qh del_vertices)) {
+      fprintf(qh ferr, "qhull internal error (qh_checkpolygon): actual number of vertices is %d, cumulative vertex count is %d\n",
+	      numvertices, qh num_vertices - qh_setsize(qh del_vertices));
+      waserror= True;
+    }
+    if (qh hull_dim == 2 && numvertices != numfacets) {
+      fprintf (qh ferr, "qhull internal error (qh_checkpolygon): #vertices %d != #facets %d\n",
+        numvertices, numfacets);
+      waserror= True;
+    }
+    if (qh hull_dim == 3 && numvertices + numfacets - numridges/2 != 2) {
+      fprintf (qh ferr, "qhull warning: #vertices %d + #facets %d - #edges %d != 2\n\
+	A vertex appears twice in a edge list.  May occur during merging.",
+        numvertices, numfacets, numridges/2);
+      /* occurs if lots of merging and a vertex ends up twice in an edge list.  e.g., RBOX 1000 s W1e-13 t995849315 D2 | QHULL d Tc Tv */
+    }
+  }
+  if (waserror) 
+    qh_errexit(qh_ERRqhull, NULL, NULL);
+} /* checkpolygon */
+
+
+/*---------------------------------
+  
+  qh_checkvertex( vertex )
+    check vertex for consistency
+    checks vertex->neighbors
+
+  notes:
+    neighbors checked efficiently in checkpolygon
+*/
+void qh_checkvertex (vertexT *vertex) {
+  boolT waserror= False;
+  facetT *neighbor, **neighborp, *errfacet=NULL;
+
+  if (qh_pointid (vertex->point) == -1) {
+    fprintf (qh ferr, "qhull internal error (qh_checkvertex): unknown point id %p\n", vertex->point);
+    waserror= True;
+  }
+  if (vertex->id >= qh vertex_id) {
+    fprintf (qh ferr, "qhull internal error (qh_checkvertex): unknown vertex id %d\n", vertex->id);
+    waserror= True;
+  }
+  if (!waserror && !vertex->deleted) {
+    if (qh_setsize (vertex->neighbors)) {
+      FOREACHneighbor_(vertex) {
+        if (!qh_setin (neighbor->vertices, vertex)) {
+          fprintf (qh ferr, "qhull internal error (qh_checkvertex): neighbor f%d does not contain v%d\n", neighbor->id, vertex->id);
+	  errfacet= neighbor;
+	  waserror= True;
+	}
+      }
+    }
+  }
+  if (waserror) {
+    qh_errprint ("ERRONEOUS", NULL, NULL, NULL, vertex);
+    qh_errexit (qh_ERRqhull, errfacet, NULL);
+  }
+} /* checkvertex */
+  
+/*---------------------------------
+  
+  qh_clearcenters( type )
+    clear old data from facet->center
+
+  notes:
+    sets new centertype
+    nop if CENTERtype is the same
+*/
+void qh_clearcenters (qh_CENTER type) {
+  facetT *facet;
+  
+  if (qh CENTERtype != type) {
+    FORALLfacets {
+      if (qh CENTERtype == qh_ASvoronoi){
+        if (facet->center) {
+          qh_memfree (facet->center, qh center_size);
+          facet->center= NULL;
+        }
+      }else /* qh CENTERtype == qh_AScentrum */ {
+        if (facet->center) {
+          qh_memfree (facet->center, qh normal_size);
+	  facet->center= NULL;
+        }
+      }
+    }
+    qh CENTERtype= type;
+  }
+  trace2((qh ferr, "qh_clearcenters: switched to center type %d\n", type));
+} /* clearcenters */
+
+/*---------------------------------
+  
+  qh_createsimplex( vertices )
+    creates a simplex from a set of vertices
+
+  returns:
+    initializes qh.facet_list to the simplex
+    initializes qh.newfacet_list, .facet_tail
+    initializes qh.vertex_list, .newvertex_list, .vertex_tail
+
+  design:
+    initializes lists
+    for each vertex
+      create a new facet
+    for each new facet
+      create its neighbor set
+*/
+void qh_createsimplex(setT *vertices) {
+  facetT *facet= NULL, *newfacet;
+  boolT toporient= True;
+  int vertex_i, vertex_n, nth;
+  setT *newfacets= qh_settemp (qh hull_dim+1);
+  vertexT *vertex;
+  
+  qh facet_list= qh newfacet_list= qh facet_tail= qh_newfacet();
+  qh num_facets= qh num_vertices= qh num_visible= 0;
+  qh vertex_list= qh newvertex_list= qh vertex_tail= qh_newvertex(NULL);
+  FOREACHvertex_i_(vertices) {
+    newfacet= qh_newfacet();
+    newfacet->vertices= qh_setnew_delnthsorted (vertices, vertex_n,
+						vertex_i, 0);
+    newfacet->toporient= toporient;
+    qh_appendfacet(newfacet);
+    newfacet->newfacet= True;
+    qh_appendvertex (vertex);
+    qh_setappend (&newfacets, newfacet);
+    toporient ^= True;
+  }
+  FORALLnew_facets {
+    nth= 0;
+    FORALLfacet_(qh newfacet_list) {
+      if (facet != newfacet) 
+        SETelem_(newfacet->neighbors, nth++)= facet;
+    }
+    qh_settruncate (newfacet->neighbors, qh hull_dim);
+  }
+  qh_settempfree (&newfacets);
+  trace1((qh ferr, "qh_createsimplex: created simplex\n"));
+} /* createsimplex */
+
+/*---------------------------------
+  
+  qh_delridge( ridge )
+    deletes ridge from data structures it belongs to
+    frees up its memory
+
+  notes:
+    in merge.c, caller sets vertex->delridge for each vertex
+    ridges also freed in qh_freeqhull
+*/
+void qh_delridge(ridgeT *ridge) {
+  void **freelistp; /* used !qh_NOmem */
+  
+  qh_setdel(ridge->top->ridges, ridge);
+  qh_setdel(ridge->bottom->ridges, ridge);
+  qh_setfree(&(ridge->vertices));
+  qh_memfree_(ridge, sizeof(ridgeT), freelistp);
+} /* delridge */
+
+
+/*---------------------------------
+  
+  qh_delvertex( vertex )
+    deletes a vertex and frees its memory
+
+  notes:
+    assumes vertex->adjacencies have been updated if needed
+    unlinks from vertex_list
+*/
+void qh_delvertex (vertexT *vertex) {
+
+  if (vertex == qh tracevertex)
+    qh tracevertex= NULL;
+  qh_removevertex (vertex);
+  qh_setfree (&vertex->neighbors);
+  qh_memfree(vertex, sizeof(vertexT));
+} /* delvertex */
+
+
+/*---------------------------------
+  
+  qh_facet3vertex(  )
+    return temporary set of 3-d vertices in qh_ORIENTclock order
+
+  design:
+    if simplicial facet
+      build set from facet->vertices with facet->toporient
+    else
+      for each ridge in order
+        build set from ridge's vertices
+*/
+setT *qh_facet3vertex (facetT *facet) {
+  ridgeT *ridge, *firstridge;
+  vertexT *vertex;
+  int cntvertices, cntprojected=0;
+  setT *vertices;
+
+  cntvertices= qh_setsize(facet->vertices);
+  vertices= qh_settemp (cntvertices);
+  if (facet->simplicial) {
+    if (cntvertices != 3) {
+      fprintf (qh ferr, "qhull internal error (qh_facet3vertex): only %d vertices for simplicial facet f%d\n", 
+                  cntvertices, facet->id);
+      qh_errexit(qh_ERRqhull, facet, NULL);
+    }
+    qh_setappend (&vertices, SETfirst_(facet->vertices));
+    if (facet->toporient ^ qh_ORIENTclock)
+      qh_setappend (&vertices, SETsecond_(facet->vertices));
+    else
+      qh_setaddnth (&vertices, 0, SETsecond_(facet->vertices));
+    qh_setappend (&vertices, SETelem_(facet->vertices, 2));
+  }else {
+    ridge= firstridge= SETfirstt_(facet->ridges, ridgeT);   /* no infinite */
+    while ((ridge= qh_nextridge3d (ridge, facet, &vertex))) {
+      qh_setappend (&vertices, vertex);
+      if (++cntprojected > cntvertices || ridge == firstridge)
+        break;
+    }
+    if (!ridge || cntprojected != cntvertices) {
+      fprintf (qh ferr, "qhull internal error (qh_facet3vertex): ridges for facet %d don't match up.  got at least %d\n", 
+                  facet->id, cntprojected);
+      qh_errexit(qh_ERRqhull, facet, ridge);
+    }
+  }
+  return vertices;
+} /* facet3vertex */
+
+/*---------------------------------
+  
+  qh_findbestfacet( point, bestoutside, bestdist, isoutside )
+    find facet that is furthest below a point 
+
+    for Delaunay triangulations, 
+      Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
+      Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates. 
+
+  returns:
+    if bestoutside is set (e.g., qh_ALL)
+      returns best facet that is not upperdelaunay
+      if Delaunay and inside, point is outside circumsphere of bestfacet
+    else
+      returns first facet below point
+      if point is inside, returns nearest, !upperdelaunay facet
+    distance to facet
+    isoutside set if outside of facet
+    
+  notes:
+    this works for all distributions
+    if inside, qh_findbestfacet performs an exhaustive search
+       this may be too conservative.  Sometimes it is clearly required.
+    qh_findbestfacet is not used by qhull.
+    uses qh.visit_id and qh.coplanarset
+    
+  see:
+    qh_findbest
+*/
+facetT *qh_findbestfacet (pointT *point, boolT bestoutside,
+           realT *bestdist, boolT *isoutside) {
+  facetT *bestfacet= NULL;
+  int numpart, totpart= 0;
+  
+  bestfacet= qh_findbest (point, qh facet_list, 
+			    bestoutside, !qh_ISnewfacets, bestoutside /* qh_NOupper */,
+			    bestdist, isoutside, &totpart);
+  if (*bestdist < -qh DISTround) {
+    bestfacet= qh_findfacet_all (point, bestdist, isoutside, &numpart);
+    totpart += numpart;
+    if ((isoutside && bestoutside)
+    || (!isoutside && bestfacet->upperdelaunay)) {
+      bestfacet= qh_findbest (point, bestfacet, 
+			    bestoutside, False, bestoutside,
+			    bestdist, isoutside, &totpart);
+      totpart += numpart;
+    }
+  }
+  trace3((qh ferr, "qh_findbestfacet: f%d dist %2.2g isoutside %d totpart %d\n",
+	  bestfacet->id, *bestdist, *isoutside, totpart));
+  return bestfacet;
+} /* findbestfacet */ 
+ 
+/*---------------------------------
+  
+  qh_findfacet_all( point, bestdist, isoutside, numpart )
+    exhaustive search for facet below a point 
+
+    for Delaunay triangulations, 
+      Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
+      Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates. 
+
+  returns:
+    returns first facet below point
+    if point is inside, 
+      returns nearest facet
+    distance to facet
+    isoutside if point is outside of the hull
+    number of distance tests
+*/
+facetT *qh_findfacet_all (pointT *point, realT *bestdist, boolT *isoutside,
+			  int *numpart) {
+  facetT *bestfacet= NULL, *facet;
+  realT dist;
+  int totpart= 0;
+  
+  *bestdist= REALmin;
+  *isoutside= False;
+  FORALLfacets {
+    if (facet->flipped || !facet->normal)
+      continue;
+    totpart++;
+    qh_distplane (point, facet, &dist);
+    if (dist > *bestdist) {
+      *bestdist= dist;
+      bestfacet= facet;
+      if (dist > qh MINoutside) {
+        *isoutside= True;
+        break;
+      }
+    }
+  }
+  *numpart= totpart;
+  trace3((qh ferr, "qh_findfacet_all: f%d dist %2.2g isoutside %d totpart %d\n",
+	  getid_(bestfacet), *bestdist, *isoutside, totpart));
+  return bestfacet;
+} /* findfacet_all */ 
+ 
+/*---------------------------------
+  
+  qh_findgood( facetlist, goodhorizon )
+    identify good facets for qh.PRINTgood
+    if qh.GOODvertex>0
+      facet includes point as vertex
+      if !match, returns goodhorizon
+      inactive if qh.MERGING
+    if qh.GOODpoint
+      facet is visible or coplanar (>0) or not visible (<0) 
+    if qh.GOODthreshold
+      facet->normal matches threshold
+    if !goodhorizon and !match, 
+      selects facet with closest angle
+      sets GOODclosest
+      
+  returns:
+    number of new, good facets found
+    determines facet->good
+    may update qh.GOODclosest
+    
+  notes:
+    qh_findgood_all further reduces the good region
+
+  design:
+    count good facets
+    mark good facets for qh.GOODpoint  
+    mark good facets for qh.GOODthreshold
+    if necessary
+      update qh.GOODclosest  
+*/
+int qh_findgood (facetT *facetlist, int goodhorizon) {
+  facetT *facet, *bestfacet= NULL;
+  realT angle, bestangle= REALmax, dist;
+  int  numgood=0;
+
+  FORALLfacet_(facetlist) {
+    if (facet->good)
+      numgood++;
+  }
+  if (qh GOODvertex>0 && !qh MERGING) {
+    FORALLfacet_(facetlist) {
+      if (!qh_isvertex (qh GOODvertexp, facet->vertices)) {
+        facet->good= False;
+        numgood--;
+      }
+    }
+  }
+  if (qh GOODpoint && numgood) {
+    FORALLfacet_(facetlist) {
+      if (facet->good && facet->normal) {
+        zinc_(Zdistgood);
+        qh_distplane (qh GOODpointp, facet, &dist);
+        if ((qh GOODpoint > 0) ^ (dist > 0.0)) {
+          facet->good= False;
+          numgood--;
+        }
+      }
+    }
+  }
+  if (qh GOODthreshold && (numgood || goodhorizon || qh GOODclosest)) {
+    FORALLfacet_(facetlist) {
+      if (facet->good && facet->normal) {
+        if (!qh_inthresholds (facet->normal, &angle)) {
+          facet->good= False;
+          numgood--;
+          if (angle < bestangle) {
+            bestangle= angle;
+            bestfacet= facet;
+          }
+        }
+      }
+    }
+    if (!numgood && (!goodhorizon || qh GOODclosest)) {
+      if (qh GOODclosest) {
+	if (qh GOODclosest->visible)
+	  qh GOODclosest= NULL;
+	else {
+	  qh_inthresholds (qh GOODclosest->normal, &angle);
+	  if (angle < bestangle)
+	    bestfacet= qh GOODclosest;
+	}
+      }
+      if (bestfacet && bestfacet != qh GOODclosest) {
+	if (qh GOODclosest)
+	  qh GOODclosest->good= False;
+	qh GOODclosest= bestfacet;
+	bestfacet->good= True;
+	numgood++;
+	trace2((qh ferr, "qh_findgood: f%d is closest (%2.2g) to thresholds\n", 
+           bestfacet->id, bestangle));
+	return numgood;
+      }
+    }else if (qh GOODclosest) { /* numgood > 0 */
+      qh GOODclosest->good= False;
+      qh GOODclosest= NULL;
+    }
+  }
+  zadd_(Zgoodfacet, numgood);
+  trace2((qh ferr, "qh_findgood: found %d good facets with %d good horizon\n",
+               numgood, goodhorizon));
+  if (!numgood && qh GOODvertex>0 && !qh MERGING) 
+    return goodhorizon;
+  return numgood;
+} /* findgood */
+
+/*---------------------------------
+  
+  qh_findgood_all( facetlist )
+    apply other constraints for good facets (used by qh.PRINTgood)
+    if qh.GOODvertex 
+      facet includes (>0) or doesn't include (<0) point as vertex
+      if last good facet and ONLYgood, prints warning and continues
+    if qh.SPLITthresholds
+      facet->normal matches threshold, or if none, the closest one
+    calls qh_findgood
+    nop if good not used
+
+  returns:
+    clears facet->good if not good
+    sets qh.num_good
+
+  notes:
+    this is like qh_findgood but more restrictive
+
+  design:
+    uses qh_findgood to mark good facets
+    marks facets for qh.GOODvertex
+    marks facets for qh.SPLITthreholds  
+*/
+void qh_findgood_all (facetT *facetlist) {
+  facetT *facet, *bestfacet=NULL;
+  realT angle, bestangle= REALmax;
+  int  numgood=0, startgood;
+
+  if (!qh GOODvertex && !qh GOODthreshold && !qh GOODpoint 
+  && !qh SPLITthresholds)
+    return;
+  if (!qh ONLYgood)
+    qh_findgood (qh facet_list, 0);
+  FORALLfacet_(facetlist) {
+    if (facet->good)
+      numgood++;
+  }
+  if (qh GOODvertex <0 || (qh GOODvertex > 0 && qh MERGING)) {
+    FORALLfacet_(facetlist) {
+      if (facet->good && ((qh GOODvertex > 0) ^ !!qh_isvertex (qh GOODvertexp, facet->vertices))) {
+        if (!--numgood) {
+	  if (qh ONLYgood) {
+            fprintf (qh ferr, "qhull warning: good vertex p%d does not match last good facet f%d.  Ignored.\n",
+               qh_pointid(qh GOODvertexp), facet->id);
+	    return;
+	  }else if (qh GOODvertex > 0)
+            fprintf (qh ferr, "qhull warning: point p%d is not a vertex ('QV%d').\n",
+		qh GOODvertex-1, qh GOODvertex-1);
+	  else
+            fprintf (qh ferr, "qhull warning: point p%d is a vertex for every facet ('QV-%d').\n",
+	        -qh GOODvertex - 1, -qh GOODvertex - 1);
+        }
+        facet->good= False;
+      }
+    }
+  }
+  startgood= numgood;
+  if (qh SPLITthresholds) {
+    FORALLfacet_(facetlist) {
+      if (facet->good) {
+        if (!qh_inthresholds (facet->normal, &angle)) {
+          facet->good= False;
+          numgood--;
+          if (angle < bestangle) {
+            bestangle= angle;
+            bestfacet= facet;
+          }
+        }
+      }
+    }
+    if (!numgood && bestfacet) {
+      bestfacet->good= True;
+      numgood++;
+      trace0((qh ferr, "qh_findgood_all: f%d is closest (%2.2g) to thresholds\n", 
+           bestfacet->id, bestangle));
+      return;
+    }
+  }
+  qh num_good= numgood;
+  trace0((qh ferr, "qh_findgood_all: %d good facets remain out of %d facets\n",
+        numgood, startgood));
+} /* findgood_all */
+
+/*---------------------------------
+  
+  qh_furthestnext()
+    set qh.facet_next to facet with furthest of all furthest points
+    searches all facets on qh.facet_list
+
+  notes:
+    this may help avoid precision problems
+*/
+void qh_furthestnext (void /* qh facet_list */) {
+  facetT *facet, *bestfacet= NULL;
+  realT dist, bestdist= -REALmax;
+
+  FORALLfacets {
+    if (facet->outsideset) {
+#if qh_COMPUTEfurthest
+      pointT *furthest;
+      furthest= (pointT*)qh_setlast (facet->outsideset);
+      zinc_(Zcomputefurthest);
+      qh_distplane (furthest, facet, &dist);
+#else
+      dist= facet->furthestdist;
+#endif
+      if (dist > bestdist) {
+	bestfacet= facet;
+	bestdist= dist;
+      }
+    }
+  }
+  if (bestfacet) {
+    qh_removefacet (bestfacet);
+    qh_prependfacet (bestfacet, &qh facet_next);
+    trace1((qh ferr, "qh_furthestnext: made f%d next facet (dist %.2g)\n",
+	    bestfacet->id, bestdist));
+  }
+} /* furthestnext */
+
+/*---------------------------------
+  
+  qh_furthestout( facet )
+    make furthest outside point the last point of outsideset
+
+  returns:
+    updates facet->outsideset
+    clears facet->notfurthest
+    sets facet->furthestdist
+
+  design:
+    determine best point of outsideset
+    make it the last point of outsideset
+*/
+void qh_furthestout (facetT *facet) {
+  pointT *point, **pointp, *bestpoint= NULL;
+  realT dist, bestdist= -REALmax;
+
+  FOREACHpoint_(facet->outsideset) {
+    qh_distplane (point, facet, &dist);
+    zinc_(Zcomputefurthest);
+    if (dist > bestdist) {
+      bestpoint= point;
+      bestdist= dist;
+    }
+  }
+  if (bestpoint) {
+    qh_setdel (facet->outsideset, point);
+    qh_setappend (&facet->outsideset, point);
+#if !qh_COMPUTEfurthest
+    facet->furthestdist= bestdist;
+#endif
+  }
+  facet->notfurthest= False;
+  trace3((qh ferr, "qh_furthestout: p%d is furthest outside point of f%d\n",
+	  qh_pointid (point), facet->id));
+} /* furthestout */
+
+
+/*---------------------------------
+  
+  qh_infiniteloop( facet )
+    report infinite loop error due to facet
+*/
+void qh_infiniteloop (facetT *facet) {
+
+  fprintf (qh ferr, "qhull internal error (qh_infiniteloop): potential infinite loop detected\n");
+  qh_errexit (qh_ERRqhull, facet, NULL);
+} /* qh_infiniteloop */
+
+/*---------------------------------
+  
+  qh_initbuild()
+    initialize hull and outside sets with point array
+    qh.FIRSTpoint/qh.NUMpoints is point array
+    if qh.GOODpoint
+      adds qh.GOODpoint to initial hull
+
+  returns:
+    qh_facetlist with initial hull
+    points partioned into outside sets, coplanar sets, or inside
+    initializes qh.GOODpointp, qh.GOODvertexp,
+
+  design:
+    initialize global variables used during qh_buildhull
+    determine precision constants and points with max/min coordinate values
+      if qh.SCALElast, scale last coordinate (for 'd')
+    build initial simplex
+    partition input points into facets of initial simplex
+    set up lists
+    if qh.ONLYgood
+      check consistency  
+      add qh.GOODvertex if defined
+*/
+void qh_initbuild( void) {
+  setT *maxpoints, *vertices;
+  facetT *facet;
+  int i, numpart;
+  realT dist;
+  boolT isoutside;
+
+  qh furthest_id= -1;
+  qh lastreport= 0;
+  qh facet_id= qh vertex_id= qh ridge_id= 0;
+  qh visit_id= qh vertex_visit= 0;
+  qh maxoutdone= False;
+
+  if (qh GOODpoint > 0) 
+    qh GOODpointp= qh_point (qh GOODpoint-1);
+  else if (qh GOODpoint < 0) 
+    qh GOODpointp= qh_point (-qh GOODpoint-1);
+  if (qh GOODvertex > 0)
+    qh GOODvertexp= qh_point (qh GOODvertex-1);
+  else if (qh GOODvertex < 0) 
+    qh GOODvertexp= qh_point (-qh GOODvertex-1);
+  if ((qh GOODpoint  
+       && (qh GOODpointp < qh first_point  /* also catches !GOODpointp */
+	   || qh GOODpointp > qh_point (qh num_points-1)))
+    || (qh GOODvertex
+	&& (qh GOODvertexp < qh first_point  /* also catches !GOODvertexp */
+	    || qh GOODvertexp > qh_point (qh num_points-1)))) {
+    fprintf (qh ferr, "qhull input error: either QGn or QVn point is > p%d\n",
+	     qh num_points-1);
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }
+  maxpoints= qh_maxmin(qh first_point, qh num_points, qh hull_dim);
+  if (qh SCALElast)
+    qh_scalelast (qh first_point, qh num_points, qh hull_dim,
+               qh MINlastcoord, qh MAXlastcoord, qh MAXwidth);
+  qh_detroundoff();
+  if (qh DELAUNAY && qh upper_threshold[qh hull_dim-1] > REALmax/2
+                  && qh lower_threshold[qh hull_dim-1] < -REALmax/2) {
+    for (i= qh_PRINTEND; i--; ) {
+      if (qh PRINTout[i] == qh_PRINTgeom && qh DROPdim < 0 
+ 	  && !qh GOODthreshold && !qh SPLITthresholds)
+	break;  /* in this case, don't set upper_threshold */
+    }
+    if (i < 0) {
+      if (qh UPPERdelaunay) { /* matches qh.upperdelaunay in qh_setfacetplane */
+	qh lower_threshold[qh hull_dim-1]= qh ANGLEround * qh_ZEROdelaunay;
+	qh GOODthreshold= True;
+      }else { 
+	qh upper_threshold[qh hull_dim-1]= -qh ANGLEround * qh_ZEROdelaunay;
+        if (!qh GOODthreshold) 
+	  qh SPLITthresholds= True; /* build upper-convex hull even if Qg */
+          /* qh_initqhull_globals errors if Qg without Pdk/etc. */
+      }
+    }
+  }
+  vertices= qh_initialvertices(qh hull_dim, maxpoints, qh first_point, qh num_points); 
+  qh_initialhull (vertices);  /* initial qh facet_list */
+  qh_partitionall (vertices, qh first_point, qh num_points);
+  if (qh PRINToptions1st || qh TRACElevel || qh IStracing) {
+    if (qh TRACElevel || qh IStracing)
+      fprintf (qh ferr, "\nTrace level %d for %s | %s\n", 
+         qh IStracing ? qh IStracing : qh TRACElevel, qh rbox_command, qh qhull_command);
+    fprintf (qh ferr, "Options selected for Qhull %s:\n%s\n", qh_VERSION, qh qhull_options);
+  }
+  qh_resetlists (False, qh_RESETvisible /*qh visible_list newvertex_list newfacet_list */);
+  qh facet_next= qh facet_list;
+  qh_furthestnext (/* qh facet_list */);
+  if (qh PREmerge) {
+    qh cos_max= qh premerge_cos;
+    qh centrum_radius= qh premerge_centrum;
+  }
+  if (qh ONLYgood) {
+    if (qh GOODvertex > 0 && qh MERGING) {
+      fprintf (qh ferr, "qhull input error: 'Qg QVn' (only good vertex) does not work with merging.\nUse 'QJ' to joggle the input or 'Q0' to turn off merging.\n");
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }
+    if (!(qh GOODthreshold || qh GOODpoint
+         || (!qh MERGEexact && !qh PREmerge && qh GOODvertexp))) {
+      fprintf (qh ferr, "qhull input error: 'Qg' (ONLYgood) needs a good threshold ('Pd0D0'), a\n\
+good point (QGn or QG-n), or a good vertex with 'QJ' or 'Q0' (QVn).\n");
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }
+    if (qh GOODvertex > 0  && !qh MERGING  /* matches qh_partitionall */
+	&& !qh_isvertex (qh GOODvertexp, vertices)) {
+      facet= qh_findbestnew (qh GOODvertexp, qh facet_list, 
+			  &dist, !qh_ALL, &isoutside, &numpart);
+      zadd_(Zdistgood, numpart);
+      if (!isoutside) {
+        fprintf (qh ferr, "qhull input error: point for QV%d is inside initial simplex.  It can not be made a vertex.\n",
+	       qh_pointid(qh GOODvertexp));
+        qh_errexit (qh_ERRinput, NULL, NULL);
+      }
+      if (!qh_addpoint (qh GOODvertexp, facet, False)) {
+	qh_settempfree(&vertices);
+	qh_settempfree(&maxpoints);
+	return;
+      }
+    }
+    qh_findgood (qh facet_list, 0);
+  }
+  qh_settempfree(&vertices);
+  qh_settempfree(&maxpoints);
+  trace1((qh ferr, "qh_initbuild: initial hull created and points partitioned\n"));
+} /* initbuild */
+
+/*---------------------------------
+  
+  qh_initialhull( vertices )
+    constructs the initial hull as a DIM3 simplex of vertices
+
+  design:
+    creates a simplex (initializes lists)
+    determines orientation of simplex
+    sets hyperplanes for facets
+    doubles checks orientation (in case of axis-parallel facets with Gaussian elimination)
+    checks for flipped facets and qh.NARROWhull
+    checks the result   
+*/
+void qh_initialhull(setT *vertices) {
+  facetT *facet, *firstfacet, *neighbor, **neighborp;
+  realT dist, angle, minangle= REALmax;
+#ifndef qh_NOtrace
+  int k;
+#endif
+
+  qh_createsimplex(vertices);  /* qh facet_list */
+  qh_resetlists (False, qh_RESETvisible);
+  qh facet_next= qh facet_list;      /* advance facet when processed */
+  qh interior_point= qh_getcenter(vertices);
+  firstfacet= qh facet_list;
+  qh_setfacetplane(firstfacet);
+  zinc_(Znumvisibility); /* needs to be in printsummary */
+  qh_distplane(qh interior_point, firstfacet, &dist);
+  if (dist > 0) {  
+    FORALLfacets
+      facet->toporient ^= True;
+  }
+  FORALLfacets
+    qh_setfacetplane(facet);
+  FORALLfacets {
+    if (!qh_checkflipped (facet, NULL, qh_ALL)) {/* due to axis-parallel facet */
+      trace1((qh ferr, "qh_initialhull: initial orientation incorrect.  Correct all facets\n"));
+      facet->flipped= False;
+      FORALLfacets {
+	facet->toporient ^= True;
+	qh_orientoutside (facet);
+      }
+      break;
+    }
+  }
+  FORALLfacets {
+    if (!qh_checkflipped (facet, NULL, !qh_ALL)) {  /* can happen with 'R0.1' */
+      qh_precision ("initial facet is coplanar with interior point");
+      fprintf (qh ferr, "qhull precision error: initial facet %d is coplanar with the interior point\n",
+                   facet->id);
+      qh_errexit (qh_ERRsingular, facet, NULL);
+    }
+    FOREACHneighbor_(facet) {
+      angle= qh_getangle (facet->normal, neighbor->normal);
+      minimize_( minangle, angle);
+    }
+  }
+  if (minangle < qh_MAXnarrow && !qh NOnarrow) { 
+    realT diff= 1.0 + minangle;
+
+    qh NARROWhull= True;
+    qh_option ("_narrow-hull", NULL, &diff);
+    if (minangle < qh_WARNnarrow && !qh RERUN && qh PRINTprecision)
+      fprintf (qh ferr, "qhull precision warning: \n\
+The initial hull is narrow (cosine of min. angle is %.16f).\n\
+A coplanar point may lead to a wide facet.  Options 'QbB' (scale to unit box)\n\
+or 'Qbb' (scale last coordinate) may remove this warning.  Use 'Pp' to skip\n\
+this warning.  See 'Limitations' in qh-impre.htm.\n",
+          -minangle);   /* convert from angle between normals to angle between facets */
+  }
+  zzval_(Zprocessed)= qh hull_dim+1;
+  qh_checkpolygon (qh facet_list);
+  qh_checkconvex(qh facet_list,   qh_DATAfault);
+#ifndef qh_NOtrace
+  if (qh IStracing >= 1) {
+    fprintf(qh ferr, "qh_initialhull: simplex constructed, interior point:");
+    for (k=0; k < qh hull_dim; k++) 
+      fprintf (qh ferr, " %6.4g", qh interior_point[k]);
+    fprintf (qh ferr, "\n");
+  }
+#endif
+} /* initialhull */
+
+/*---------------------------------
+  
+  qh_initialvertices( dim, maxpoints, points, numpoints )
+    determines a non-singular set of initial vertices
+    maxpoints may include duplicate points
+
+  returns:
+    temporary set of dim+1 vertices in descending order by vertex id
+    if qh.RANDOMoutside && !qh.ALLpoints
+      picks random points
+    if dim >= qh_INITIALmax, 
+      uses min/max x and max points with non-zero determinants
+
+  notes:
+    unless qh.ALLpoints, 
+      uses maxpoints as long as determinate is non-zero
+*/
+setT *qh_initialvertices(int dim, setT *maxpoints, pointT *points, int numpoints) {
+  pointT *point, **pointp;
+  setT *vertices, *simplex, *tested;
+  realT randr;
+  int index, point_i, point_n, k;
+  boolT nearzero= False;
+  
+  vertices= qh_settemp (dim + 1);
+  simplex= qh_settemp (dim+1);
+  if (qh ALLpoints) 
+    qh_maxsimplex (dim, NULL, points, numpoints, &simplex);
+  else if (qh RANDOMoutside) {
+    while (qh_setsize (simplex) != dim+1) {
+      randr= qh_RANDOMint;
+      randr= randr/(qh_RANDOMmax+1);
+      index= (int)floor(qh num_points * randr);
+      while (qh_setin (simplex, qh_point (index))) {
+	index++; /* in case qh_RANDOMint always returns the same value */
+        index= index < qh num_points ? index : 0;
+      }
+      qh_setappend (&simplex, qh_point (index));
+    }
+  }else if (qh hull_dim >= qh_INITIALmax) {
+    tested= qh_settemp (dim+1);
+    qh_setappend (&simplex, SETfirst_(maxpoints));   /* max and min X coord */
+    qh_setappend (&simplex, SETsecond_(maxpoints));
+    qh_maxsimplex (fmin_(qh_INITIALsearch, dim), maxpoints, points, numpoints, &simplex);
+    k= qh_setsize (simplex);
+    FOREACHpoint_i_(maxpoints) { 
+      if (point_i & 0x1) {     /* first pick up max. coord. points */
+      	if (!qh_setin (simplex, point) && !qh_setin (tested, point)){
+	  qh_detsimplex(point, simplex, k, &nearzero);
+          if (nearzero)
+            qh_setappend (&tested, point);
+          else {
+            qh_setappend (&simplex, point);
+            if (++k == dim)  /* use search for last point */
+	      break;
+	  }
+	}
+      }
+    }
+    while (k != dim && (point= (pointT*)qh_setdellast (maxpoints))) {
+      if (!qh_setin (simplex, point) && !qh_setin (tested, point)){
+        qh_detsimplex (point, simplex, k, &nearzero);
+        if (nearzero)
+          qh_setappend (&tested, point);
+        else {
+          qh_setappend (&simplex, point);
+          k++;
+	}
+      }
+    }
+    index= 0;
+    while (k != dim && (point= qh_point (index++))) {
+      if (!qh_setin (simplex, point) && !qh_setin (tested, point)){
+        qh_detsimplex (point, simplex, k, &nearzero);
+        if (!nearzero){
+          qh_setappend (&simplex, point);
+          k++;
+	}
+      }
+    }
+    qh_settempfree (&tested);
+    qh_maxsimplex (dim, maxpoints, points, numpoints, &simplex);
+  }else
+    qh_maxsimplex (dim, maxpoints, points, numpoints, &simplex);
+  FOREACHpoint_(simplex) 
+    qh_setaddnth (&vertices, 0, qh_newvertex(point)); /* descending order */
+  qh_settempfree (&simplex);
+  return vertices;
+} /* initialvertices */
+
+
+/*---------------------------------
+  
+  qh_isvertex(  )
+    returns vertex if point is in vertex set, else returns NULL
+
+  notes:
+    for qh.GOODvertex
+*/
+vertexT *qh_isvertex (pointT *point, setT *vertices) {
+  vertexT *vertex, **vertexp;
+
+  FOREACHvertex_(vertices) {
+    if (vertex->point == point)
+      return vertex;
+  }
+  return NULL;
+} /* isvertex */
+
+/*---------------------------------
+  
+  qh_makenewfacets( point )
+    make new facets from point and qh.visible_list
+
+  returns:
+    qh.newfacet_list= list of new facets with hyperplanes and ->newfacet
+    qh.newvertex_list= list of vertices in new facets with ->newlist set
+    
+    if (qh.ONLYgood)
+      newfacets reference horizon facets, but not vice versa
+      ridges reference non-simplicial horizon ridges, but not vice versa
+      does not change existing facets
+    else
+      sets qh.NEWfacets
+      new facets attached to horizon facets and ridges
+      for visible facets, 
+        visible->r.replace is corresponding new facet
+
+  see also: 
+    qh_makenewplanes() -- make hyperplanes for facets
+    qh_attachnewfacets() -- attachnewfacets if not done here (qh ONLYgood)
+    qh_matchnewfacets() -- match up neighbors
+    qh_updatevertices() -- update vertex neighbors and delvertices
+    qh_deletevisible() -- delete visible facets
+    qh_checkpolygon() --check the result
+    qh_triangulate() -- triangulate a non-simplicial facet
+
+  design:
+    for each visible facet
+      make new facets to its horizon facets
+      update its f.replace 
+      clear its neighbor set
+*/
+vertexT *qh_makenewfacets (pointT *point /*visible_list*/) {
+  facetT *visible, *newfacet= NULL, *newfacet2= NULL, *neighbor, **neighborp;
+  vertexT *apex;
+  int numnew=0;
+
+  qh newfacet_list= qh facet_tail;
+  qh newvertex_list= qh vertex_tail;
+  apex= qh_newvertex(point);
+  qh_appendvertex (apex);  
+  qh visit_id++;
+  if (!qh ONLYgood)
+    qh NEWfacets= True;
+  FORALLvisible_facets {
+    FOREACHneighbor_(visible) 
+      neighbor->seen= False;
+    if (visible->ridges) {
+      visible->visitid= qh visit_id;
+      newfacet2= qh_makenew_nonsimplicial (visible, apex, &numnew);
+    }
+    if (visible->simplicial)
+      newfacet= qh_makenew_simplicial (visible, apex, &numnew);
+    if (!qh ONLYgood) {
+      if (newfacet2)  /* newfacet is null if all ridges defined */
+        newfacet= newfacet2;
+      if (newfacet)
+      	visible->f.replace= newfacet;
+      else
+        zinc_(Zinsidevisible);
+      SETfirst_(visible->neighbors)= NULL;
+    }
+  }
+  trace1((qh ferr, "qh_makenewfacets: created %d new facets from point p%d to horizon\n",
+	  numnew, qh_pointid(point)));
+  if (qh IStracing >= 4)
+    qh_printfacetlist (qh newfacet_list, NULL, qh_ALL);
+  return apex;
+} /* makenewfacets */
+
+/*---------------------------------
+  
+  qh_matchduplicates( atfacet, atskip, hashsize, hashcount )
+    match duplicate ridges in qh.hash_table for atfacet/atskip
+    duplicates marked with ->dupridge and qh_DUPLICATEridge
+
+  returns:
+    picks match with worst merge (min distance apart)
+    updates hashcount
+  
+  see also:
+    qh_matchneighbor
+
+  notes:
+
+  design:
+    compute hash value for atfacet and atskip
+    repeat twice -- once to make best matches, once to match the rest
+      for each possible facet in qh.hash_table
+        if it is a matching facet and pass 2
+          make match 
+	  unless tricoplanar, mark match for merging (qh_MERGEridge)
+          [e.g., tricoplanar RBOX s 1000 t993602376 | QHULL C-1e-3 d Qbb FA Qt]
+        if it is a matching facet and pass 1
+          test if this is a better match
+      if pass 1,
+        make best match (it will not be merged)
+*/
+#ifndef qh_NOmerge
+void qh_matchduplicates (facetT *atfacet, int atskip, int hashsize, int *hashcount) {
+  boolT same, ismatch;
+  int hash, scan;
+  facetT *facet, *newfacet, *maxmatch= NULL, *maxmatch2= NULL, *nextfacet;
+  int skip, newskip, nextskip= 0, maxskip= 0, maxskip2= 0, makematch;
+  realT maxdist= -REALmax, mindist, dist2, low, high;
+
+  hash= (int)qh_gethash (hashsize, atfacet->vertices, qh hull_dim, 1, 
+                     SETelem_(atfacet->vertices, atskip));
+  trace2((qh ferr, "qh_matchduplicates: find duplicate matches for f%d skip %d hash %d hashcount %d\n",
+	  atfacet->id, atskip, hash, *hashcount));
+  for (makematch= 0; makematch < 2; makematch++) {
+    qh visit_id++;
+    for (newfacet= atfacet, newskip= atskip; newfacet; newfacet= nextfacet, newskip= nextskip) {
+      zinc_(Zhashlookup);
+      nextfacet= NULL;
+      newfacet->visitid= qh visit_id;
+      for (scan= hash; (facet= SETelemt_(qh hash_table, scan, facetT)); 
+	   scan= (++scan >= hashsize ? 0 : scan)) {
+	if (!facet->dupridge || facet->visitid == qh visit_id)
+	  continue;
+	zinc_(Zhashtests);
+	if (qh_matchvertices (1, newfacet->vertices, newskip, facet->vertices, &skip, &same)) {
+	  ismatch= (same == (newfacet->toporient ^ facet->toporient));
+	  if (SETelemt_(facet->neighbors, skip, facetT) != qh_DUPLICATEridge) {
+	    if (!makematch) {
+	      fprintf (qh ferr, "qhull internal error (qh_matchduplicates): missing dupridge at f%d skip %d for new f%d skip %d hash %d\n",
+		     facet->id, skip, newfacet->id, newskip, hash);
+	      qh_errexit2 (qh_ERRqhull, facet, newfacet);
+	    }
+	  }else if (ismatch && makematch) {
+	    if (SETelemt_(newfacet->neighbors, newskip, facetT) == qh_DUPLICATEridge) {
+	      SETelem_(facet->neighbors, skip)= newfacet;
+	      if (newfacet->tricoplanar)
+  		SETelem_(newfacet->neighbors, newskip)= facet;
+	      else
+		SETelem_(newfacet->neighbors, newskip)= qh_MERGEridge;
+	      *hashcount -= 2; /* removed two unmatched facets */
+	      trace4((qh ferr, "qh_matchduplicates: duplicate f%d skip %d matched with new f%d skip %d merge\n",
+		    facet->id, skip, newfacet->id, newskip));
+	    }
+	  }else if (ismatch) {
+	    mindist= qh_getdistance (facet, newfacet, &low, &high);
+	    dist2= qh_getdistance (newfacet, facet, &low, &high);
+	    minimize_(mindist, dist2);
+	    if (mindist > maxdist) {
+	      maxdist= mindist;
+	      maxmatch= facet;
+	      maxskip= skip;
+	      maxmatch2= newfacet;
+	      maxskip2= newskip;
+	    }
+	    trace3((qh ferr, "qh_matchduplicates: duplicate f%d skip %d new f%d skip %d at dist %2.2g, max is now f%d f%d\n",
+		    facet->id, skip, newfacet->id, newskip, mindist, 
+		    maxmatch->id, maxmatch2->id));
+	  }else { /* !ismatch */
+	    nextfacet= facet;
+	    nextskip= skip;
+	  }
+	}
+	if (makematch && !facet 
+        && SETelemt_(facet->neighbors, skip, facetT) == qh_DUPLICATEridge) {
+	  fprintf (qh ferr, "qhull internal error (qh_matchduplicates): no MERGEridge match for duplicate f%d skip %d at hash %d\n",
+		     newfacet->id, newskip, hash);
+	  qh_errexit (qh_ERRqhull, newfacet, NULL);
+	}
+      }
+    } /* end of for each new facet at hash */
+    if (!makematch) {
+      if (!maxmatch) {
+	fprintf (qh ferr, "qhull internal error (qh_matchduplicates): no maximum match at duplicate f%d skip %d at hash %d\n",
+		     atfacet->id, atskip, hash);
+	qh_errexit (qh_ERRqhull, atfacet, NULL);
+      }
+      SETelem_(maxmatch->neighbors, maxskip)= maxmatch2;
+      SETelem_(maxmatch2->neighbors, maxskip2)= maxmatch;
+      *hashcount -= 2; /* removed two unmatched facets */
+      zzinc_(Zmultiridge);
+      trace0((qh ferr, "qh_matchduplicates: duplicate f%d skip %d matched with new f%d skip %d keep\n",
+	      maxmatch->id, maxskip, maxmatch2->id, maxskip2));
+      qh_precision ("ridge with multiple neighbors");
+      if (qh IStracing >= 4)
+	qh_errprint ("DUPLICATED/MATCH", maxmatch, maxmatch2, NULL, NULL);
+    }
+  }
+} /* matchduplicates */
+
+/*---------------------------------
+  
+  qh_nearcoplanar()
+    for all facets, remove near-inside points from facet->coplanarset
+    coplanar points defined by innerplane from qh_outerinner()
+
+  returns:
+    if qh KEEPcoplanar && !qh KEEPinside
+      facet->coplanarset only contains coplanar points
+    if qh.JOGGLEmax
+      drops inner plane by another qh.JOGGLEmax diagonal since a
+        vertex could shift out while a coplanar point shifts in
+  
+  notes:
+    used for qh.PREmerge and qh.JOGGLEmax
+    must agree with computation of qh.NEARcoplanar in qh_detroundoff()
+  design:
+    if not keeping coplanar or inside points
+      free all coplanar sets
+    else if not keeping both coplanar and inside points
+      remove !coplanar or !inside points from coplanar sets
+*/
+void qh_nearcoplanar ( void /* qh.facet_list */) {
+  facetT *facet;
+  pointT *point, **pointp;
+  int numpart;
+  realT dist, innerplane;
+
+  if (!qh KEEPcoplanar && !qh KEEPinside) {
+    FORALLfacets {
+      if (facet->coplanarset) 
+        qh_setfree( &facet->coplanarset);
+    }
+  }else if (!qh KEEPcoplanar || !qh KEEPinside) {
+    qh_outerinner (NULL, NULL, &innerplane);
+    if (qh JOGGLEmax < REALmax/2)
+      innerplane -= qh JOGGLEmax * sqrt (qh hull_dim);
+    numpart= 0;
+    FORALLfacets { 
+      if (facet->coplanarset) {
+        FOREACHpoint_(facet->coplanarset) {
+          numpart++;
+	  qh_distplane (point, facet, &dist); 
+  	  if (dist < innerplane) {
+	    if (!qh KEEPinside)
+              SETref_(point)= NULL;
+          }else if (!qh KEEPcoplanar)
+            SETref_(point)= NULL;
+        }
+	qh_setcompact (facet->coplanarset);
+      }
+    }
+    zzadd_(Zcheckpart, numpart);
+  }
+} /* nearcoplanar */
+
+/*---------------------------------
+  
+  qh_nearvertex( facet, point, bestdist )
+    return nearest vertex in facet to point
+
+  returns:
+    vertex and its distance
+    
+  notes:
+    if qh.DELAUNAY
+      distance is measured in the input set
+    searches neighboring tricoplanar facets (requires vertexneighbors)
+      Slow implementation.  Recomputes vertex set for each point.
+    The vertex set could be stored in the qh.keepcentrum facet.
+*/
+vertexT *qh_nearvertex (facetT *facet, pointT *point, realT *bestdistp) {
+  realT bestdist= REALmax, dist;
+  vertexT *bestvertex= NULL, *vertex, **vertexp, *apex;
+  coordT *center;
+  facetT *neighbor, **neighborp;
+  setT *vertices;
+  int dim= qh hull_dim;
+
+  if (qh DELAUNAY)
+    dim--;
+  if (facet->tricoplanar) {
+    if (!qh VERTEXneighbors || !facet->center) {
+      fprintf(qh ferr, "qhull internal error (qh_nearvertex): qh.VERTEXneighbors and facet->center required for tricoplanar facets\n");
+      qh_errexit(qh_ERRqhull, NULL, NULL);
+    }
+    vertices= qh_settemp (qh TEMPsize);
+    apex= SETfirst_(facet->vertices);
+    center= facet->center;
+    FOREACHneighbor_(apex) {
+      if (neighbor->center == center) {
+	FOREACHvertex_(neighbor->vertices) 
+	  qh_setappend(&vertices, vertex);
+      }
+    }
+  }else 
+    vertices= facet->vertices;
+  FOREACHvertex_(vertices) {
+    dist= qh_pointdist (vertex->point, point, -dim);
+    if (dist < bestdist) {
+      bestdist= dist;
+      bestvertex= vertex;
+    }
+  }
+  if (facet->tricoplanar)
+    qh_settempfree (&vertices);
+  *bestdistp= sqrt (bestdist);
+  return bestvertex;
+} /* nearvertex */
+
+/*---------------------------------
+  
+  qh_newhashtable( newsize )
+    returns size of qh.hash_table of at least newsize slots
+
+  notes:
+    assumes qh.hash_table is NULL
+    qh_HASHfactor determines the number of extra slots
+    size is not divisible by 2, 3, or 5
+*/
+int qh_newhashtable(int newsize) {
+  int size;
+
+  size= ((newsize+1)*qh_HASHfactor) | 0x1;  /* odd number */
+  while (True) { 
+    if ((size%3) && (size%5))
+      break;
+    size += 2;
+    /* loop terminates because there is an infinite number of primes */
+  }
+  qh hash_table= qh_setnew (size);
+  qh_setzero (qh hash_table, 0, size);
+  return size;
+} /* newhashtable */
+
+/*---------------------------------
+  
+  qh_newvertex( point )
+    returns a new vertex for point
+*/
+vertexT *qh_newvertex(pointT *point) {
+  vertexT *vertex;
+
+  zinc_(Ztotvertices);
+  vertex= (vertexT *)qh_memalloc(sizeof(vertexT));
+  memset ((char *) vertex, 0, sizeof (vertexT));
+  if (qh vertex_id == 0xFFFFFF) {
+    fprintf(qh ferr, "qhull input error: more than %d vertices.  ID field overflows and two vertices\n\
+may have the same identifier.  Vertices not sorted correctly.\n", 0xFFFFFF);
+    qh_errexit(qh_ERRinput, NULL, NULL);
+  }
+  if (qh vertex_id == qh tracevertex_id)
+    qh tracevertex= vertex;
+  vertex->id= qh vertex_id++;
+  vertex->point= point;
+  trace4((qh ferr, "qh_newvertex: vertex p%d (v%d) created\n", qh_pointid(vertex->point), 
+	  vertex->id));
+  return (vertex);
+} /* newvertex */
+
+/*---------------------------------
+  
+  qh_nextridge3d( atridge, facet, vertex )
+    return next ridge and vertex for a 3d facet
+
+  notes:
+    in qh_ORIENTclock order
+    this is a O(n^2) implementation to trace all ridges
+    be sure to stop on any 2nd visit
+  
+  design:
+    for each ridge
+      exit if it is the ridge after atridge
+*/
+ridgeT *qh_nextridge3d (ridgeT *atridge, facetT *facet, vertexT **vertexp) {
+  vertexT *atvertex, *vertex, *othervertex;
+  ridgeT *ridge, **ridgep;
+
+  if ((atridge->top == facet) ^ qh_ORIENTclock)
+    atvertex= SETsecondt_(atridge->vertices, vertexT);
+  else
+    atvertex= SETfirstt_(atridge->vertices, vertexT);
+  FOREACHridge_(facet->ridges) {
+    if (ridge == atridge)
+      continue;
+    if ((ridge->top == facet) ^ qh_ORIENTclock) {
+      othervertex= SETsecondt_(ridge->vertices, vertexT);
+      vertex= SETfirstt_(ridge->vertices, vertexT);
+    }else {
+      vertex= SETsecondt_(ridge->vertices, vertexT);
+      othervertex= SETfirstt_(ridge->vertices, vertexT);
+    }
+    if (vertex == atvertex) {
+      if (vertexp)
+        *vertexp= othervertex;
+      return ridge;
+    }
+  }
+  return NULL;
+} /* nextridge3d */
+#else /* qh_NOmerge */
+void qh_matchduplicates (facetT *atfacet, int atskip, int hashsize, int *hashcount) {
+}
+ridgeT *qh_nextridge3d (ridgeT *atridge, facetT *facet, vertexT **vertexp) {
+
+  return NULL;
+}
+#endif /* qh_NOmerge */
+  
+/*---------------------------------
+  
+  qh_outcoplanar()
+    move points from all facets' outsidesets to their coplanarsets
+
+  notes:
+    for post-processing under qh.NARROWhull
+
+  design:
+    for each facet
+      for each outside point for facet
+        partition point into coplanar set
+*/
+void qh_outcoplanar (void /* facet_list */) {
+  pointT *point, **pointp;
+  facetT *facet;
+  realT dist;
+
+  trace1((qh ferr, "qh_outcoplanar: move outsideset to coplanarset for qh NARROWhull\n"));
+  FORALLfacets {
+    FOREACHpoint_(facet->outsideset) {
+      qh num_outside--;
+      if (qh KEEPcoplanar || qh KEEPnearinside) {
+	qh_distplane (point, facet, &dist);
+        zinc_(Zpartition);
+	qh_partitioncoplanar (point, facet, &dist);
+      }
+    }
+    qh_setfree (&facet->outsideset);
+  }
+} /* outcoplanar */
+
+/*---------------------------------
+  
+  qh_point( id )
+    return point for a point id, or NULL if unknown
+
+  alternative code:
+    return ((pointT *)((unsigned   long)qh.first_point
+           + (unsigned long)((id)*qh.normal_size)));
+*/
+pointT *qh_point (int id) {
+
+  if (id < 0)
+    return NULL;
+  if (id < qh num_points)
+    return qh first_point + id * qh hull_dim;
+  id -= qh num_points;
+  if (id < qh_setsize (qh other_points))
+    return SETelemt_(qh other_points, id, pointT);
+  return NULL;
+} /* point */
+  
+/*---------------------------------
+  
+  qh_point_add( set, point, elem )
+    stores elem at set[point.id]
+  
+  returns:
+    access function for qh_pointfacet and qh_pointvertex
+
+  notes:
+    checks point.id
+*/
+void qh_point_add (setT *set, pointT *point, void *elem) {
+  int id, size;
+
+  SETreturnsize_(set, size);
+  if ((id= qh_pointid(point)) < 0)
+    fprintf (qh ferr, "qhull internal warning (point_add): unknown point %p id %d\n", 
+      point, id);
+  else if (id >= size) {
+    fprintf (qh ferr, "qhull internal errror (point_add): point p%d is out of bounds (%d)\n",
+	     id, size);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }else
+    SETelem_(set, id)= elem;
+} /* point_add */
+
+
+/*---------------------------------
+  
+  qh_pointfacet()
+    return temporary set of facet for each point
+    the set is indexed by point id
+
+  notes:
+    vertices assigned to one of the facets
+    coplanarset assigned to the facet
+    outside set assigned to the facet
+    NULL if no facet for point (inside)
+      includes qh.GOODpointp
+
+  access:
+    FOREACHfacet_i_(facets) { ... }
+    SETelem_(facets, i)
+  
+  design:
+    for each facet
+      add each vertex
+      add each coplanar point
+      add each outside point
+*/
+setT *qh_pointfacet (void /*qh facet_list*/) {
+  int numpoints= qh num_points + qh_setsize (qh other_points);
+  setT *facets;
+  facetT *facet;
+  vertexT *vertex, **vertexp;
+  pointT *point, **pointp;
+  
+  facets= qh_settemp (numpoints);
+  qh_setzero (facets, 0, numpoints);
+  qh vertex_visit++;
+  FORALLfacets {
+    FOREACHvertex_(facet->vertices) {
+      if (vertex->visitid != qh vertex_visit) {
+        vertex->visitid= qh vertex_visit;
+        qh_point_add (facets, vertex->point, facet);
+      }
+    }
+    FOREACHpoint_(facet->coplanarset) 
+      qh_point_add (facets, point, facet);
+    FOREACHpoint_(facet->outsideset) 
+      qh_point_add (facets, point, facet);
+  }
+  return facets;
+} /* pointfacet */
+
+/*---------------------------------
+  
+  qh_pointvertex(  )
+    return temporary set of vertices indexed by point id
+    entry is NULL if no vertex for a point
+      this will include qh.GOODpointp
+
+  access:
+    FOREACHvertex_i_(vertices) { ... }
+    SETelem_(vertices, i)
+*/
+setT *qh_pointvertex (void /*qh facet_list*/) {
+  int numpoints= qh num_points + qh_setsize (qh other_points);
+  setT *vertices;
+  vertexT *vertex;
+  
+  vertices= qh_settemp (numpoints);
+  qh_setzero (vertices, 0, numpoints);
+  FORALLvertices 
+    qh_point_add (vertices, vertex->point, vertex);
+  return vertices;
+} /* pointvertex */
+
+
+/*---------------------------------
+  
+  qh_prependfacet( facet, facetlist )
+    prepend facet to the start of a facetlist
+
+  returns:
+    increments qh.numfacets
+    updates facetlist, qh.facet_list, facet_next
+  
+  notes:
+    be careful of prepending since it can lose a pointer.
+      e.g., can lose _next by deleting and then prepending before _next
+*/
+void qh_prependfacet(facetT *facet, facetT **facetlist) {
+  facetT *prevfacet, *list;
+  
+
+  trace4((qh ferr, "qh_prependfacet: prepend f%d before f%d\n",
+	  facet->id, getid_(*facetlist)));
+  if (!*facetlist)
+    (*facetlist)= qh facet_tail;
+  list= *facetlist;
+  prevfacet= list->previous;
+  facet->previous= prevfacet;
+  if (prevfacet)
+    prevfacet->next= facet;
+  list->previous= facet;
+  facet->next= *facetlist;
+  if (qh facet_list == list)  /* this may change *facetlist */
+    qh facet_list= facet;
+  if (qh facet_next == list)
+    qh facet_next= facet;
+  *facetlist= facet;
+  qh num_facets++;
+} /* prependfacet */
+
+
+/*---------------------------------
+  
+  qh_printhashtable( fp )
+    print hash table to fp
+
+  notes:
+    not in I/O to avoid bringing io.c in
+  
+  design:
+    for each hash entry
+      if defined
+        if unmatched or will merge (NULL, qh_MERGEridge, qh_DUPLICATEridge)
+          print entry and neighbors
+*/
+void qh_printhashtable(FILE *fp) {
+  facetT *facet, *neighbor;
+  int id, facet_i, facet_n, neighbor_i= 0, neighbor_n= 0;
+  vertexT *vertex, **vertexp;
+
+  FOREACHfacet_i_(qh hash_table) {
+    if (facet) {
+      FOREACHneighbor_i_(facet) {
+        if (!neighbor || neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge) 
+          break;
+      }
+      if (neighbor_i == neighbor_n)
+        continue;
+      fprintf (fp, "hash %d f%d ", facet_i, facet->id);
+      FOREACHvertex_(facet->vertices)
+        fprintf (fp, "v%d ", vertex->id);
+      fprintf (fp, "\n neighbors:");
+      FOREACHneighbor_i_(facet) {
+	if (neighbor == qh_MERGEridge)
+	  id= -3;
+	else if (neighbor == qh_DUPLICATEridge)
+	  id= -2;
+	else
+	  id= getid_(neighbor);
+        fprintf (fp, " %d", id);
+      }
+      fprintf (fp, "\n");
+    }
+  }
+} /* printhashtable */
+     
+
+/*---------------------------------
+  
+  qh_printlists( fp )
+    print out facet and vertex list for debugging (without 'f/v' tags)
+*/
+void qh_printlists (void) {
+  facetT *facet;
+  vertexT *vertex;
+  int count= 0;
+  
+  fprintf (qh ferr, "qh_printlists: facets:");
+  FORALLfacets {
+    if (++count % 100 == 0)
+      fprintf (qh ferr, "\n     ");
+    fprintf (qh ferr, " %d", facet->id);
+  }
+  fprintf (qh ferr, "\n  new facets %d visible facets %d next facet for qh_addpoint %d\n  vertices (new %d):",
+     getid_(qh newfacet_list), getid_(qh visible_list), getid_(qh facet_next),
+     getid_(qh newvertex_list));
+  count = 0;
+  FORALLvertices {
+    if (++count % 100 == 0)
+      fprintf (qh ferr, "\n     ");
+    fprintf (qh ferr, " %d", vertex->id);
+  }
+  fprintf (qh ferr, "\n");
+} /* printlists */
+  
+/*---------------------------------
+  
+  qh_resetlists( stats, qh_RESETvisible )
+    reset newvertex_list, newfacet_list, visible_list
+    if stats, 
+      maintains statistics
+
+  returns:
+    visible_list is empty if qh_deletevisible was called
+*/
+void qh_resetlists (boolT stats, boolT resetVisible /*qh newvertex_list newfacet_list visible_list*/) {
+  vertexT *vertex;
+  facetT *newfacet, *visible;
+  int totnew=0, totver=0;
+  
+  if (stats) {
+    FORALLvertex_(qh newvertex_list)
+      totver++;
+    FORALLnew_facets 
+      totnew++;
+    zadd_(Zvisvertextot, totver);
+    zmax_(Zvisvertexmax, totver);
+    zadd_(Znewfacettot, totnew);
+    zmax_(Znewfacetmax, totnew);
+  }
+  FORALLvertex_(qh newvertex_list)
+    vertex->newlist= False;
+  qh newvertex_list= NULL;
+  FORALLnew_facets
+    newfacet->newfacet= False;
+  qh newfacet_list= NULL;
+  if (resetVisible) {
+    FORALLvisible_facets {
+      visible->f.replace= NULL;
+      visible->visible= False;
+    }
+    qh num_visible= 0;
+  }
+  qh visible_list= NULL; /* may still have visible facets via qh_triangulate */
+  qh NEWfacets= False;
+} /* resetlists */
+
+/*---------------------------------
+  
+  qh_setvoronoi_all()
+    compute Voronoi centers for all facets
+    includes upperDelaunay facets if qh.UPPERdelaunay ('Qu')
+
+  returns:
+    facet->center is the Voronoi center
+    
+  notes:
+    this is unused/untested code
+      please email bradb@shore.net if this works ok for you
+  
+  use:
+    FORALLvertices {...} to locate the vertex for a point.  
+    FOREACHneighbor_(vertex) {...} to visit the Voronoi centers for a Voronoi cell.
+*/
+void qh_setvoronoi_all (void) {
+  facetT *facet;
+
+  qh_clearcenters (qh_ASvoronoi);
+  qh_vertexneighbors();
+  
+  FORALLfacets {
+    if (!facet->normal || !facet->upperdelaunay || qh UPPERdelaunay) {
+      if (!facet->center)
+        facet->center= qh_facetcenter (facet->vertices);
+    }
+  }
+} /* setvoronoi_all */
+
+#ifndef qh_NOmerge
+
+/*---------------------------------
+  
+  qh_triangulate()
+    triangulate non-simplicial facets on qh.facet_list, 
+    if qh.CENTERtype=qh_ASvoronoi, sets Voronoi centers of non-simplicial facets
+
+  returns:
+    all facets simplicial
+    each tricoplanar facet has ->f.triowner == owner of ->center,normal,etc.
+
+  notes:
+    call after qh_check_output since may switch to Voronoi centers
+    Output may overwrite ->f.triowner with ->f.area
+*/
+void qh_triangulate (void /*qh facet_list*/) {
+  facetT *facet, *nextfacet, *owner;
+  int onlygood= qh ONLYgood;
+  facetT *neighbor, *visible= NULL, *facet1, *facet2, *new_facet_list= NULL;
+  facetT *orig_neighbor= NULL, *otherfacet;
+  vertexT *new_vertex_list= NULL;
+  mergeT *merge; 
+  mergeType mergetype;
+  int neighbor_i, neighbor_n;
+
+  trace1((qh ferr, "qh_triangulate: triangulate non-simplicial facets\n"));
+  if (qh hull_dim == 2)
+    return;
+  if (qh VORONOI) {  /* otherwise lose Voronoi centers [could rebuild vertex set from tricoplanar] */
+    qh_clearcenters (qh_ASvoronoi);
+    qh_vertexneighbors();
+  }
+  qh ONLYgood= False; /* for makenew_nonsimplicial */
+  qh visit_id++;
+  qh NEWfacets= True;
+  qh degen_mergeset= qh_settemp (qh TEMPsize);
+  qh newvertex_list= qh vertex_tail;
+  for (facet= qh facet_list; facet && facet->next; facet= nextfacet) { /* non-simplicial facets moved to end */
+    nextfacet= facet->next;
+    if (facet->visible || facet->simplicial)
+      continue;
+    /* triangulate all non-simplicial facets, otherwise merging does not work, e.g., RBOX c P-0.1 P+0.1 P+0.1 D3 | QHULL d Qt Tv */
+    if (!new_facet_list)
+      new_facet_list= facet;  /* will be moved to end */
+    qh_triangulate_facet (facet, &new_vertex_list);
+  }
+  trace2((qh ferr, "qh_triangulate: delete null facets from f%d -- apex same as second vertex\n", getid_(new_facet_list)));
+  for (facet= new_facet_list; facet && facet->next; facet= nextfacet) { /* null facets moved to end */
+    nextfacet= facet->next;
+    if (facet->visible) 
+      continue;
+    if (facet->ridges) {
+      if (qh_setsize(facet->ridges) > 0) {
+	fprintf( qh ferr, "qhull error (qh_triangulate): ridges still defined for f%d\n", facet->id);
+	qh_errexit (qh_ERRqhull, facet, NULL);
+      }
+      qh_setfree (&facet->ridges);
+    }
+    if (SETfirst_(facet->vertices) == SETsecond_(facet->vertices)) {
+      zinc_(Ztrinull);
+      qh_triangulate_null (facet);
+    }
+  }
+  trace2((qh ferr, "qh_triangulate: delete %d or more mirror facets -- same vertices and neighbors\n", qh_setsize(qh degen_mergeset)));
+  qh visible_list= qh facet_tail;
+  while ((merge= (mergeT*)qh_setdellast (qh degen_mergeset))) {
+    facet1= merge->facet1;
+    facet2= merge->facet2;
+    mergetype= merge->type;
+    qh_memfree (merge, sizeof(mergeT));
+    if (mergetype == MRGmirror) {
+      zinc_(Ztrimirror);
+      qh_triangulate_mirror (facet1, facet2);
+    }
+  }
+  qh_settempfree(&qh degen_mergeset);
+  trace2((qh ferr, "qh_triangulate: update neighbor lists for vertices from v%d\n", getid_(new_vertex_list)));
+  qh newvertex_list= new_vertex_list;  /* all vertices of new facets */
+  qh visible_list= NULL;
+  qh_updatevertices(/*qh newvertex_list, empty newfacet_list and visible_list*/);
+  qh_resetlists (False, !qh_RESETvisible /*qh newvertex_list, empty newfacet_list and visible_list*/);
+
+  trace2((qh ferr, "qh_triangulate: identify degenerate tricoplanar facets from f%d\n", getid_(new_facet_list)));
+  trace2((qh ferr, "qh_triangulate: and replace facet->f.triowner with tricoplanar facets that own center, normal, etc.\n"));
+  FORALLfacet_(new_facet_list) {
+    if (facet->tricoplanar && !facet->visible) {
+      FOREACHneighbor_i_(facet) {
+	if (neighbor_i == 0) {  /* first iteration */
+	  if (neighbor->tricoplanar)
+            orig_neighbor= neighbor->f.triowner;
+	  else
+	    orig_neighbor= neighbor;
+	}else {
+	  if (neighbor->tricoplanar)
+  	    otherfacet= neighbor->f.triowner;
+	  else
+	    otherfacet= neighbor;
+	  if (orig_neighbor == otherfacet) {
+	    zinc_(Ztridegen);
+	    facet->degenerate= True;
+	    break;
+	  }
+	}
+      }
+    }
+  }
+
+  trace2((qh ferr, "qh_triangulate: delete visible facets -- non-simplicial, null, and mirrored facets\n"));
+  owner= NULL;
+  visible= NULL;
+  for (facet= new_facet_list; facet && facet->next; facet= nextfacet) { /* may delete facet */
+    nextfacet= facet->next;
+    if (facet->visible) {
+      if (facet->tricoplanar) { /* a null or mirrored facet */
+	qh_delfacet(facet);
+	qh num_visible--;
+      }else {  /* a non-simplicial facet followed by its tricoplanars */
+	if (visible && !owner) {
+	  /*  RBOX 200 s D5 t1001471447 | QHULL Qt C-0.01 Qx Qc Tv Qt -- f4483 had 6 vertices/neighbors and 8 ridges */
+	  trace2((qh ferr, "qh_triangulate: all tricoplanar facets degenerate for non-simplicial facet f%d\n",
+		       visible->id));
+	  qh_delfacet(visible);
+	  qh num_visible--;
+	}
+	visible= facet;
+	owner= NULL;
+      }
+    }else if (facet->tricoplanar) {
+      if (facet->f.triowner != visible) { 
+	fprintf( qh ferr, "qhull error (qh_triangulate): tricoplanar facet f%d not owned by its visible, non-simplicial facet f%d\n", facet->id, getid_(visible));
+	qh_errexit2 (qh_ERRqhull, facet, visible);
+      }
+      if (owner) 
+	facet->f.triowner= owner;
+      else if (!facet->degenerate) {
+	owner= facet;
+	nextfacet= visible->next; /* rescan tricoplanar facets with owner */
+	facet->keepcentrum= True;  /* one facet owns ->normal, etc. */
+	facet->coplanarset= visible->coplanarset;
+	facet->outsideset= visible->outsideset;
+  	visible->coplanarset= NULL;
+	visible->outsideset= NULL;
+        if (!qh TRInormals) { /* center and normal copied to tricoplanar facets */
+	  visible->center= NULL;
+	  visible->normal= NULL;
+	}
+	qh_delfacet(visible);
+	qh num_visible--;
+      }
+    }
+  }
+  if (visible && !owner) {
+    trace2((qh ferr, "qh_triangulate: all tricoplanar facets degenerate for last non-simplicial facet f%d\n",
+	         visible->id));
+    qh_delfacet(visible);
+    qh num_visible--;
+  }
+  qh NEWfacets= False;
+  qh ONLYgood= onlygood; /* restore value */
+  if (qh CHECKfrequently) 
+    qh_checkpolygon (qh facet_list);
+} /* triangulate */
+
+
+/*---------------------------------
+  
+  qh_triangulate_facet (facetA)
+    triangulate a non-simplicial facet
+      if qh.CENTERtype=qh_ASvoronoi, sets its Voronoi center
+  returns:
+    qh.newfacet_list == simplicial facets
+      facet->tricoplanar set and ->keepcentrum false
+      facet->degenerate set if duplicated apex
+      facet->f.trivisible set to facetA
+      facet->center copied from facetA (created if qh_ASvoronoi)
+	qh_eachvoronoi, qh_detvridge, qh_detvridge3 assume centers copied
+      facet->normal,offset,maxoutside copied from facetA
+
+  notes:
+      qh_makenew_nonsimplicial uses neighbor->seen for the same
+
+  see also:
+      qh_addpoint() -- add a point
+      qh_makenewfacets() -- construct a cone of facets for a new vertex
+
+  design:
+      if qh_ASvoronoi, 
+	 compute Voronoi center (facet->center)
+      select first vertex (highest ID to preserve ID ordering of ->vertices)
+      triangulate from vertex to ridges
+      copy facet->center, normal, offset
+      update vertex neighbors
+*/
+void qh_triangulate_facet (facetT *facetA, vertexT **first_vertex) {
+  facetT *newfacet;
+  facetT *neighbor, **neighborp;
+  vertexT *apex;
+  int numnew=0;
+
+  trace3((qh ferr, "qh_triangulate_facet: triangulate facet f%d\n", facetA->id));
+
+  if (qh IStracing >= 4)
+    qh_printfacet (qh ferr, facetA);
+  FOREACHneighbor_(facetA) {
+    neighbor->seen= False;
+    neighbor->coplanar= False;
+  }
+  if (qh CENTERtype == qh_ASvoronoi && !facetA->center  /* matches upperdelaunay in qh_setfacetplane() */
+        && fabs_(facetA->normal[qh hull_dim -1]) >= qh ANGLEround * qh_ZEROdelaunay) {
+    facetA->center= qh_facetcenter (facetA->vertices);
+  }
+  qh_willdelete (facetA, NULL);
+  qh newfacet_list= qh facet_tail;
+  facetA->visitid= qh visit_id;
+  apex= SETfirst_(facetA->vertices);
+  qh_makenew_nonsimplicial (facetA, apex, &numnew);
+  SETfirst_(facetA->neighbors)= NULL;
+  FORALLnew_facets {
+    newfacet->tricoplanar= True;
+    newfacet->f.trivisible= facetA;
+    newfacet->degenerate= False;
+    newfacet->upperdelaunay= facetA->upperdelaunay;
+    newfacet->good= facetA->good;
+    if (qh TRInormals) { 
+      newfacet->keepcentrum= True;
+      newfacet->normal= qh_copypoints (facetA->normal, 1, qh hull_dim);
+      if (qh CENTERtype == qh_AScentrum) 
+	newfacet->center= qh_getcentrum (newfacet);
+      else
+	newfacet->center= qh_copypoints (facetA->center, 1, qh hull_dim);
+    }else {
+      newfacet->keepcentrum= False;
+      newfacet->normal= facetA->normal;
+      newfacet->center= facetA->center;
+    }
+    newfacet->offset= facetA->offset;
+#if qh_MAXoutside
+    newfacet->maxoutside= facetA->maxoutside;
+#endif
+  }
+  qh_matchnewfacets(/*qh newfacet_list*/);
+  zinc_(Ztricoplanar);
+  zadd_(Ztricoplanartot, numnew);
+  zmax_(Ztricoplanarmax, numnew);
+  qh visible_list= NULL;
+  if (!(*first_vertex))
+    (*first_vertex)= qh newvertex_list;
+  qh newvertex_list= NULL;
+  qh_updatevertices(/*qh newfacet_list, empty visible_list and newvertex_list*/);
+  qh_resetlists (False, !qh_RESETvisible /*qh newfacet_list, empty visible_list and newvertex_list*/);
+} /* triangulate_facet */
+
+/*---------------------------------
+  
+  qh_triangulate_link (oldfacetA, facetA, oldfacetB, facetB)
+    relink facetA to facetB via oldfacets
+  returns:
+    adds mirror facets to qh degen_mergeset (4-d and up only)
+  design:
+    if they are already neighbors, the opposing neighbors become MRGmirror facets
+*/
+void qh_triangulate_link (facetT *oldfacetA, facetT *facetA, facetT *oldfacetB, facetT *facetB) {
+  int errmirror= False;
+
+  trace3((qh ferr, "qh_triangulate_link: relink old facets f%d and f%d between neighbors f%d and f%d\n", 
+         oldfacetA->id, oldfacetB->id, facetA->id, facetB->id));
+  if (qh_setin (facetA->neighbors, facetB)) {
+    if (!qh_setin (facetB->neighbors, facetA)) 
+      errmirror= True;
+    else
+      qh_appendmergeset (facetA, facetB, MRGmirror, NULL);
+  }else if (qh_setin (facetB->neighbors, facetA)) 
+    errmirror= True;
+  if (errmirror) {
+    fprintf( qh ferr, "qhull error (qh_triangulate_link): mirror facets f%d and f%d do not match for old facets f%d and f%d\n",
+       facetA->id, facetB->id, oldfacetA->id, oldfacetB->id);
+    qh_errexit2 (qh_ERRqhull, facetA, facetB);
+  }
+  qh_setreplace (facetB->neighbors, oldfacetB, facetA);
+  qh_setreplace (facetA->neighbors, oldfacetA, facetB);
+} /* triangulate_link */
+
+/*---------------------------------
+  
+  qh_triangulate_mirror (facetA, facetB)
+    delete mirrored facets from qh_triangulate_null() and qh_triangulate_mirror
+      a mirrored facet shares the same vertices of a logical ridge
+  design:
+    since a null facet duplicates the first two vertices, the opposing neighbors absorb the null facet
+    if they are already neighbors, the opposing neighbors become MRGmirror facets
+*/
+void qh_triangulate_mirror (facetT *facetA, facetT *facetB) {
+  facetT *neighbor, *neighborB;
+  int neighbor_i, neighbor_n;
+
+  trace3((qh ferr, "qh_triangulate_mirror: delete mirrored facets f%d and f%d\n", 
+         facetA->id, facetB->id));
+  FOREACHneighbor_i_(facetA) {
+    neighborB= SETelemt_(facetB->neighbors, neighbor_i, facetT);
+    if (neighbor == neighborB)
+      continue; /* occurs twice */
+    qh_triangulate_link (facetA, neighbor, facetB, neighborB);
+  }
+  qh_willdelete (facetA, NULL);
+  qh_willdelete (facetB, NULL);
+} /* triangulate_mirror */
+
+/*---------------------------------
+  
+  qh_triangulate_null (facetA)
+    remove null facetA from qh_triangulate_facet()
+      a null facet has vertex #1 (apex) == vertex #2
+  returns:
+    adds facetA to ->visible for deletion after qh_updatevertices
+    qh degen_mergeset contains mirror facets (4-d and up only)
+  design:
+    since a null facet duplicates the first two vertices, the opposing neighbors absorb the null facet
+    if they are already neighbors, the opposing neighbors become MRGmirror facets
+*/
+void qh_triangulate_null (facetT *facetA) {
+  facetT *neighbor, *otherfacet;
+
+  trace3((qh ferr, "qh_triangulate_null: delete null facet f%d\n", facetA->id));
+  neighbor= SETfirst_(facetA->neighbors);
+  otherfacet= SETsecond_(facetA->neighbors);
+  qh_triangulate_link (facetA, neighbor, facetA, otherfacet);
+  qh_willdelete (facetA, NULL);
+} /* triangulate_null */
+
+#else /* qh_NOmerge */
+void qh_triangulate (void) {
+}
+#endif /* qh_NOmerge */
+
+   /*---------------------------------
+  
+  qh_vertexintersect( vertexsetA, vertexsetB )
+    intersects two vertex sets (inverse id ordered)
+    vertexsetA is a temporary set at the top of qhmem.tempstack
+
+  returns:
+    replaces vertexsetA with the intersection
+  
+  notes:
+    could overwrite vertexsetA if currently too slow
+*/
+void qh_vertexintersect(setT **vertexsetA,setT *vertexsetB) {
+  setT *intersection;
+
+  intersection= qh_vertexintersect_new (*vertexsetA, vertexsetB);
+  qh_settempfree (vertexsetA);
+  *vertexsetA= intersection;
+  qh_settemppush (intersection);
+} /* vertexintersect */
+
+/*---------------------------------
+  
+  qh_vertexintersect_new(  )
+    intersects two vertex sets (inverse id ordered)
+
+  returns:
+    a new set
+*/
+setT *qh_vertexintersect_new (setT *vertexsetA,setT *vertexsetB) {
+  setT *intersection= qh_setnew (qh hull_dim - 1);
+  vertexT **vertexA= SETaddr_(vertexsetA, vertexT); 
+  vertexT **vertexB= SETaddr_(vertexsetB, vertexT); 
+
+  while (*vertexA && *vertexB) {
+    if (*vertexA  == *vertexB) {
+      qh_setappend(&intersection, *vertexA);
+      vertexA++; vertexB++;
+    }else {
+      if ((*vertexA)->id > (*vertexB)->id)
+        vertexA++;
+      else
+        vertexB++;
+    }
+  }
+  return intersection;
+} /* vertexintersect_new */
+
+/*---------------------------------
+  
+  qh_vertexneighbors()
+    for each vertex in qh.facet_list, 
+      determine its neighboring facets 
+
+  returns:
+    sets qh.VERTEXneighbors
+      nop if qh.VERTEXneighbors already set
+      qh_addpoint() will maintain them
+
+  notes:
+    assumes all vertex->neighbors are NULL
+
+  design:
+    for each facet
+      for each vertex
+        append facet to vertex->neighbors
+*/
+void qh_vertexneighbors (void /*qh facet_list*/) {
+  facetT *facet;
+  vertexT *vertex, **vertexp;
+
+  if (qh VERTEXneighbors)
+    return;
+  trace1((qh ferr, "qh_vertexneighbors: determing neighboring facets for each vertex\n"));
+  qh vertex_visit++;
+  FORALLfacets {
+    if (facet->visible)
+      continue;
+    FOREACHvertex_(facet->vertices) {
+      if (vertex->visitid != qh vertex_visit) {
+        vertex->visitid= qh vertex_visit;
+        vertex->neighbors= qh_setnew (qh hull_dim);
+      }
+      qh_setappend (&vertex->neighbors, facet);
+    }
+  }
+  qh VERTEXneighbors= True;
+} /* vertexneighbors */
+
+/*---------------------------------
+  
+  qh_vertexsubset( vertexsetA, vertexsetB )
+    returns True if vertexsetA is a subset of vertexsetB
+    assumes vertexsets are sorted
+
+  note:    
+    empty set is a subset of any other set
+*/
+boolT qh_vertexsubset(setT *vertexsetA, setT *vertexsetB) {
+  vertexT **vertexA= (vertexT **) SETaddr_(vertexsetA, vertexT);
+  vertexT **vertexB= (vertexT **) SETaddr_(vertexsetB, vertexT);
+
+  while (True) {
+    if (!*vertexA)
+      return True;
+    if (!*vertexB)
+      return False;
+    if ((*vertexA)->id > (*vertexB)->id)
+      return False;
+    if (*vertexA  == *vertexB)
+      vertexA++;
+    vertexB++; 
+  }
+  return False; /* avoid warnings */
+} /* vertexsubset */
diff --git a/extern/qhull/src/qconvex.c b/extern/qhull/src/qconvex.c
new file mode 100644
index 00000000000..67b78646e50
--- /dev/null
+++ b/extern/qhull/src/qconvex.c
@@ -0,0 +1,334 @@
+/*
  ---------------------------------
+
+   qconvex.c
+      compute convex hulls using qhull
+
+   see unix.c for full interface
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "qhull.h"
+#include "mem.h"
+#include "qset.h"
+
+#if __MWERKS__ && __POWERPC__
+#include 
+#include 
+#include 
+#include 
+
+#elif __cplusplus
+extern "C" {
+  int isatty (int);
+}
+
+#elif _MSC_VER
+#include 
+#define isatty _isatty
+
+#else
+int isatty (int);  /* returns 1 if stdin is a tty
+		   if "Undefined symbol" this can be deleted along with call in main() */
+#endif
+
+/*---------------------------------
+
+  qh_prompt
+    long prompt for qconvex
+    
+  notes:
+    restricted version of qhull.c
+
+  see:
+    concise prompt below
+*/  
+
+/* duplicated in qconvex.htm */
+char hidden_options[]=" d v H Qbb Qf Qg Qm Qr Qu Qv Qx Qz TR E V Fp Gt Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 ";
+	       
+char qh_prompta[]= "\n\
+qconvex- compute the convex hull\n\
+    http://www.geom.umn.edu/software/qhull  %s\n\
+\n\
+input (stdin):\n\
+    first lines: dimension and number of points (or vice-versa).\n\
+    other lines: point coordinates, best if one point per line\n\
+    comments:    start with a non-numeric character\n\
+\n\
+options:\n\
+    Qt   - triangulated output\n\
+    QJ   - joggled input instead of merged facets\n\
+    Qc   - keep coplanar points with nearest facet\n\
+    Qi   - keep interior points with nearest facet\n\
+\n\
+Qhull control options:\n\
+    Qbk:n   - scale coord k so that low bound is n\n\
+      QBk:n - scale coord k so that upper bound is n (QBk is %2.2g)\n\
+    QbB  - scale input to unit cube centered at the origin\n\
+    Qbk:0Bk:0 - remove k-th coordinate from input\n\
+    QJn  - randomly joggle input in range [-n,n]\n\
+    QRn  - random rotation (n=seed, n=0 time, n=-1 time/no rotate)\n\
+%s%s%s%s";  /* split up qh_prompt for Visual C++ */
+char qh_promptb[]= "\
+    Qs   - search all points for the initial simplex\n\
+    QGn  - good facet if visible from point n, -n for not visible\n\
+    QVn  - good facet if it includes point n, -n if not\n\
+\n\
+";
+char qh_promptc[]= "\
+Trace options:\n\
+    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
+    Tc   - check frequently during execution\n\
+    Ts   - print statistics\n\
+    Tv   - verify result: structure, convexity, and point inclusion\n\
+    Tz   - send all output to stdout\n\
+    TFn  - report summary when n or more facets created\n\
+    TI file - input data from file, no spaces or single quotes\n\
+    TO file - output results to file, may be enclosed in single quotes\n\
+    TPn  - turn on tracing when point n added to hull\n\
+     TMn - turn on tracing at merge n\n\
+     TWn - trace merge facets when width > n\n\
+    TVn  - stop qhull after adding point n, -n for before (see TCn)\n\
+     TCn - stop qhull after building cone for point n (see TVn)\n\
+\n\
+Precision options:\n\
+    Cn   - radius of centrum (roundoff added).  Merge facets if non-convex\n\
+     An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex\n\
+           C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge\n\
+    Rn   - randomly perturb computations by a factor of [1-n,1+n]\n\
+    Un   - max distance below plane for a new, coplanar point\n\
+    Wn   - min facet width for outside point (before roundoff)\n\
+\n\
+Output formats (may be combined; if none, produces a summary to stdout):\n\
+    f    - facet dump\n\
+    G    - Geomview output (see below)\n\
+    i    - vertices incident to each facet\n\
+    m    - Mathematica output (2-d and 3-d)\n\
+    n    - normals with offsets\n\
+    o    - OFF file format (dim, points and facets; Voronoi regions)\n\
+    p    - point coordinates \n\
+    s    - summary (stderr)\n\
+\n\
+";
+char qh_promptd[]= "\
+More formats:\n\
+    Fa   - area for each facet\n\
+    FA   - compute total area and volume for option 's'\n\
+    Fc   - count plus coplanar points for each facet\n\
+           use 'Qc' (default) for coplanar and 'Qi' for interior\n\
+    FC   - centrum for each facet\n\
+    Fd   - use cdd format for input (homogeneous with offset first)\n\
+    FD   - use cdd format for numeric output (offset first)\n\
+    FF   - facet dump without ridges\n\
+    Fi   - inner plane for each facet\n\
+    FI   - ID for each facet\n\
+    Fm   - merge count for each facet (511 max)\n\
+    Fn   - count plus neighboring facets for each facet\n\
+    FN   - count plus neighboring facets for each point\n\
+    Fo   - outer plane (or max_outside) for each facet\n\
+    FO   - options and precision constants\n\
+    FP   - nearest vertex for each coplanar point\n\
+    FQ   - command used for qconvex\n\
+    Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,\n\
+                      for output: #vertices, #facets,\n\
+                                  #coplanar points, #non-simplicial facets\n\
+                    #real (2), max outer plane, min vertex\n\
+    FS   - sizes:   #int (0) \n\
+                    #real(2) tot area, tot volume\n\
+    Ft   - triangulation with centrums for non-simplicial facets (OFF format)\n\
+    Fv   - count plus vertices for each facet\n\
+    FV   - average of vertices (a feasible point for 'H')\n\
+    Fx   - extreme points (in order for 2-d)\n\
+\n\
+";
+char qh_prompte[]= "\
+Geomview output (2-d, 3-d, and 4-d)\n\
+    Ga   - all points as dots\n\
+     Gp  -  coplanar points and vertices as radii\n\
+     Gv  -  vertices as spheres\n\
+    Gi   - inner planes only\n\
+     Gn  -  no planes\n\
+     Go  -  outer planes only\n\
+    Gc   - centrums\n\
+    Gh   - hyperplane intersections\n\
+    Gr   - ridges\n\
+    GDn  - drop dimension n in 3-d and 4-d output\n\
+\n\
+Print options:\n\
+    PAn  - keep n largest facets by area\n\
+    Pdk:n - drop facet if normal[k] <= n (default 0.0)\n\
+    PDk:n - drop facet if normal[k] >= n\n\
+    Pg   - print good facets (needs 'QGn' or 'QVn')\n\
+    PFn  - keep facets whose area is at least n\n\
+    PG   - print neighbors of good facets\n\
+    PMn  - keep n facets with most merges\n\
+    Po   - force output.  If error, output neighborhood of facet\n\
+    Pp   - do not report precision problems\n\
+\n\
+    .    - list of all options\n\
+    -    - one line descriptions of all options\n\
+";
+/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
+
+/*---------------------------------
+
+  qh_prompt2
+    synopsis for qhull 
+*/  
+char qh_prompt2[]= "\n\
+qconvex- compute the convex hull.  Qhull %s\n\
+    input (stdin): dimension, number of points, point coordinates\n\
+    comments start with a non-numeric character\n\
+\n\
+options (qconvex.htm):\n\
+    Qt   - triangulated output\n\
+    QJ   - joggled input instead of merged facets\n\
+    Tv   - verify result: structure, convexity, and point inclusion\n\
+    .    - concise list of all options\n\
+    -    - one-line description of all options\n\
+\n\
+output options (subset):\n\
+    s    - summary of results (default)\n\
+    i    - vertices incident to each facet\n\
+    n    - normals with offsets\n\
+    p    - vertex coordinates (includes coplanar points if 'Qc')\n\
+    Fx   - extreme points (convex hull vertices)\n\
+    FA   - compute total area and volume\n\
+    o    - OFF format (dim, n, points, facets)\n\
+    G    - Geomview output (2-d, 3-d, and 4-d)\n\
+    m    - Mathematica output (2-d and 3-d)\n\
+    QVn  - print facets that include point n, -n if not\n\
+    TO file- output results to file, may be enclosed in single quotes\n\
+\n\
+examples:\n\
+    rbox c D2 | qconvex s n                    rbox c D2 | qconvex i\n\
+    rbox c D2 | qconvex o                      rbox 1000 s | qconvex s Tv FA\n\
+    rbox c d D2 | qconvex s Qc Fx              rbox y 1000 W0 | qconvex s n\n\
+    rbox y 1000 W0 | qconvex s QJ              rbox d G1 D12 | qconvex QR0 FA Pp\n\
+    rbox c D7 | qconvex FA TF1000\n\
+\n\
+";
+/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
+
+/*---------------------------------
+
+  qh_prompt3
+    concise prompt for qhull 
+*/  
+char qh_prompt3[]= "\n\
+Qhull %s.\n\
+Except for 'F.' and 'PG', upper-case options take an argument.\n\
+\n\
+ incidences     mathematica    normals        OFF_format     points\n\
+ summary        facet_dump\n\
+\n\
+ Farea          FArea_total    Fcoplanars     FCentrums      Fd_cdd_in\n\
+ FD_cdd_out     FFacet_xridge  Finner         FIDs           Fmerges\n\
+ Fneighbors     FNeigh_vertex  Fouter         FOptions       FPoint_near\n\
+ FQhull         Fsummary       FSize          Fvertices      FVertex_ave\n\
+ Fxtremes\n\
+\n\
+ Gvertices      Gpoints        Gall_points    Gno_planes     Ginner\n\
+ Gcentrums      Ghyperplanes   Gridges        Gouter         GDrop_dim\n\
+\n\
+ PArea_keep     Pdrop d0:0D0   PFacet_area_keep Pgood        PGood_neighbors\n\
+ PMerge_keep    Poutput_forced Pprecision_not\n\
+\n\
+ QbBound 0:0.5  QbB_scale_box  Qcoplanar      QGood_point    Qinterior\n\
+ QJoggle        Qrandom        QRotate        Qsearch_1st    Qtriangulate\n\
+ QVertex_good\n\
+\n\
+ T4_trace       Tcheck_often   Tstatistics    Tverify        Tz_stdout\n\
+ TFacet_log     TInput_file    TPoint_trace   TMerge_trace   TOutput_file\n\
+ TWide_trace    TVertex_stop   TCone_stop\n\
+\n\
+ Angle_max      Centrum_size   Random_dist    Ucoplanar_max  Wide_outside\n\
+";
+
+/*---------------------------------
+  
+  main( argc, argv )
+    processes the command line, calls qhull() to do the work, and exits
+  
+  design:
+    initializes data structures
+    reads points
+    finishes initialization
+    computes convex hull and other structures
+    checks the result
+    writes the output
+    frees memory
+*/
+int main(int argc, char *argv[]) {
+  int curlong, totlong; /* used !qh_NOmem */
+  int exitcode, numpoints, dim;
+  coordT *points;
+  boolT ismalloc;
+
+#if __MWERKS__ && __POWERPC__
+  char inBuf[BUFSIZ], outBuf[BUFSIZ], errBuf[BUFSIZ];
+  SIOUXSettings.showstatusline= false;
+  SIOUXSettings.tabspaces= 1;
+  SIOUXSettings.rows= 40;
+  if (setvbuf (stdin, inBuf, _IOFBF, sizeof(inBuf)) < 0   /* w/o, SIOUX I/O is slow*/
+  || setvbuf (stdout, outBuf, _IOFBF, sizeof(outBuf)) < 0
+  || (stdout != stderr && setvbuf (stderr, errBuf, _IOFBF, sizeof(errBuf)) < 0)) 
+    fprintf (stderr, "qhull internal warning (main): could not change stdio to fully buffered.\n");
+  argc= ccommand(&argv);
+#endif
+
+  if ((argc == 1) && isatty( 0 /*stdin*/)) {      
+    fprintf(stdout, qh_prompt2, qh_VERSION);
+    exit(qh_ERRnone);
+  }
+  if (argc > 1 && *argv[1] == '-' && !*(argv[1]+1)) {
+    fprintf(stdout, qh_prompta, qh_VERSION, qh_DEFAULTbox, 
+		qh_promptb, qh_promptc, qh_promptd, qh_prompte);
+    exit(qh_ERRnone);
+  }
+  if (argc >1 && *argv[1] == '.' && !*(argv[1]+1)) {
+    fprintf(stdout, qh_prompt3, qh_VERSION);
+    exit(qh_ERRnone);
+  }
+  qh_init_A (stdin, stdout, stderr, argc, argv);  /* sets qh qhull_command */
+  exitcode= setjmp (qh errexit); /* simple statement for CRAY J916 */
+  if (!exitcode) {
+    qh_checkflags (qh qhull_command, hidden_options);
+    qh_initflags (qh qhull_command);
+    points= qh_readpoints (&numpoints, &dim, &ismalloc);
+    if (dim >= 5) {
+      qh_option ("Qxact_merge", NULL, NULL);
+      qh MERGEexact= True; /* 'Qx' always */
+    }
+    qh_init_B (points, numpoints, dim, ismalloc);
+    qh_qhull();
+    qh_check_output();
+    qh_produce_output();
+    if (qh VERIFYoutput && !qh FORCEoutput && !qh STOPpoint && !qh STOPcone)
+      qh_check_points();
+    exitcode= qh_ERRnone;
+  }
+  qh NOerrexit= True;  /* no more setjmp */
+#ifdef qh_NOmem
+  qh_freeqhull( True);
+#else
+  qh_freeqhull( False);
+  qh_memfreeshort (&curlong, &totlong);
+  if (curlong || totlong) 
+    fprintf (stderr, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n",
+       totlong, curlong);
+#endif
+  return exitcode;
+} /* main */
+
diff --git a/extern/qhull/src/qdelaun.c b/extern/qhull/src/qdelaun.c
new file mode 100644
index 00000000000..0e49d9c381e
--- /dev/null
+++ b/extern/qhull/src/qdelaun.c
@@ -0,0 +1,323 @@
+/*
  ---------------------------------
+
+   qdelaun.c
+     compute Delaunay triangulations and furthest-point Delaunay
+     triangulations using qhull
+
+   see unix.c for full interface
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "qhull.h"
+#include "mem.h"
+#include "qset.h"
+
+#if __MWERKS__ && __POWERPC__
+#include 
+#include 
+#include 
+#include 
+
+#elif __cplusplus
+extern "C" {
+  int isatty (int);
+}
+
+#elif _MSC_VER
+#include 
+#define isatty _isatty
+
+#else
+int isatty (int);  /* returns 1 if stdin is a tty
+		   if "Undefined symbol" this can be deleted along with call in main() */
+#endif
+
+/*---------------------------------
+
+  qh_prompt 
+    long prompt for qhull
+    
+  notes:
+    restricted version of qhull.c
+ 
+  see:
+    concise prompt below
+*/  
+
+/* duplicated in qdelau_f.htm and qdelaun.htm */
+char hidden_options[]=" d n v H U Qb QB Qc Qf Qg Qi Qm Qr QR Qv Qx TR E V FC Fi Fo Ft Fp FV Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 ";
+
+char qh_prompta[]= "\n\
+qdelaunay- compute the Delaunay triangulation\n\
+    http://www.geom.umn.edu/software/qhull  %s\n\
+\n\
+input (stdin):\n\
+    first lines: dimension and number of points (or vice-versa).\n\
+    other lines: point coordinates, best if one point per line\n\
+    comments:    start with a non-numeric character\n\
+\n\
+options:\n\
+    Qu   - compute furthest-site Delaunay triangulation\n\
+    Qt   - triangulated output\n\
+    QJ   - joggled input instead of merged facets\n\
+\n\
+Qhull control options:\n\
+    QJn  - randomly joggle input in range [-n,n]\n\
+%s%s%s%s";  /* split up qh_prompt for Visual C++ */
+char qh_promptb[]= "\
+    Qs   - search all points for the initial simplex\n\
+    Qz   - add point-at-infinity to Delaunay triangulation\n\
+    QGn  - print Delaunay region if visible from point n, -n if not\n\
+    QVn  - print Delaunay regions that include point n, -n if not\n\
+\n\
+";
+char qh_promptc[]= "\
+Trace options:\n\
+    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
+    Tc   - check frequently during execution\n\
+    Ts   - print statistics\n\
+    Tv   - verify result: structure, convexity, and in-circle test\n\
+    Tz   - send all output to stdout\n\
+    TFn  - report summary when n or more facets created\n\
+    TI file - input data from file, no spaces or single quotes\n\
+    TO file - output results to file, may be enclosed in single quotes\n\
+    TPn  - turn on tracing when point n added to hull\n\
+     TMn - turn on tracing at merge n\n\
+     TWn - trace merge facets when width > n\n\
+    TVn  - stop qhull after adding point n, -n for before (see TCn)\n\
+     TCn - stop qhull after building cone for point n (see TVn)\n\
+\n\
+Precision options:\n\
+    Cn   - radius of centrum (roundoff added).  Merge facets if non-convex\n\
+     An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex\n\
+           C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge\n\
+    Rn   - randomly perturb computations by a factor of [1-n,1+n]\n\
+    Wn   - min facet width for outside point (before roundoff)\n\
+\n\
+Output formats (may be combined; if none, produces a summary to stdout):\n\
+    f    - facet dump\n\
+    G    - Geomview output (see below)\n\
+    i    - vertices incident to each Delaunay region\n\
+    m    - Mathematica output (2-d only, lifted to a paraboloid)\n\
+    o    - OFF format (dim, points, and facets as a paraboloid)\n\
+    p    - point coordinates (lifted to a paraboloid)\n\
+    s    - summary (stderr)\n\
+\n\
+";
+char qh_promptd[]= "\
+More formats:\n\
+    Fa   - area for each Delaunay region\n\
+    FA   - compute total area for option 's'\n\
+    Fc   - count plus coincident points for each Delaunay region\n\
+    Fd   - use cdd format for input (homogeneous with offset first)\n\
+    FD   - use cdd format for numeric output (offset first)\n\
+    FF   - facet dump without ridges\n\
+    FI   - ID of each Delaunay region\n\
+    Fm   - merge count for each Delaunay region (511 max)\n\
+    Fn   - count plus neighboring region for each Delaunay region\n\
+    FN   - count plus neighboring region for each point\n\
+    FO   - options and precision constants\n\
+    FP   - nearest point and distance for each coincident point\n\
+    FQ   - command used for qdelaunay\n\
+    Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,\n\
+                    for output: #vertices, #Delaunay regions,\n\
+                                #coincident points, #non-simplicial regions\n\
+                    #real (2), max outer plane, min vertex\n\
+    FS   - sizes:   #int (0)\n\
+                    #real(2) tot area, 0\n\
+    Fv   - count plus vertices for each Delaunay region\n\
+    Fx   - extreme points of Delaunay triangulation (on convex hull)\n\
+\n\
+";
+char qh_prompte[]= "\
+Geomview options (2-d and 3-d)\n\
+    Ga   - all points as dots\n\
+     Gp  -  coplanar points and vertices as radii\n\
+     Gv  -  vertices as spheres\n\
+    Gi   - inner planes only\n\
+     Gn  -  no planes\n\
+     Go  -  outer planes only\n\
+    Gc	   - centrums\n\
+    Gh   - hyperplane intersections\n\
+    Gr   - ridges\n\
+    GDn  - drop dimension n in 3-d and 4-d output\n\
+    Gt   - transparent outer ridges to view 3-d Delaunay\n\
+\n\
+Print options:\n\
+    PAn  - keep n largest Delaunay regions by area\n\
+    Pdk:n - drop facet if normal[k] <= n (default 0.0)\n\
+    PDk:n - drop facet if normal[k] >= n\n\
+    Pg   - print good Delaunay regions (needs 'QGn' or 'QVn')\n\
+    PFn  - keep Delaunay regions whose area is at least n\n\
+    PG   - print neighbors of good regions (needs 'QGn' or 'QVn')\n\
+    PMn  - keep n Delaunay regions with most merges\n\
+    Po   - force output.  If error, output neighborhood of facet\n\
+    Pp   - do not report precision problems\n\
+\n\
+    .    - list of all options\n\
+    -    - one line descriptions of all options\n\
+";
+/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
+
+/*---------------------------------
+
+  qh_prompt2
+    synopsis for qhull 
+*/  
+char qh_prompt2[]= "\n\
+qdelaunay- compute the Delaunay triangulation. Qhull %s\n\
+    input (stdin): dimension, number of points, point coordinates\n\
+    comments start with a non-numeric character\n\
+\n\
+options (qdelaun.htm):\n\
+    Qu   - furthest-site Delaunay triangulation\n\
+    Qt   - triangulated output\n\
+    QJ   - joggled input instead of merged facets\n\
+    Tv   - verify result: structure, convexity, and in-circle test\n\
+    .    - concise list of all options\n\
+    -    - one-line description of all options\n\
+\n\
+output options (subset):\n\
+    s    - summary of results (default)\n\
+    i    - vertices incident to each Delaunay region\n\
+    Fx   - extreme points (vertices of the convex hull)\n\
+    o    - OFF format (shows the points lifted to a paraboloid)\n\
+    G    - Geomview output (2-d and 3-d points lifted to a paraboloid)\n\
+    m    - Mathematica output (2-d inputs lifted to a paraboloid)\n\
+    QVn  - print Delaunay regions that include point n, -n if not\n\
+    TO file- output results to file, may be enclosed in single quotes\n\
+\n\
+examples:\n\
+    rbox c P0 D2 | qdelaunay s o          rbox c P0 D2 | qdelaunay i\n\
+    rbox c P0 D2 | qdelaunay Fv           rbox c P0 D2 | qdelaunay s Qu Fv\n\
+    rbox c G1 d D2 | qdelaunay s i        rbox c G1 d D2 | qdelaunay Qt\n\
+    rbox M3,4 z 100 D2 | qdelaunay s      rbox M3,4 z 100 D2 | qdelaunay s Qt\n\
+\n\
+";
+/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
+
+/*---------------------------------
+
+  qh_prompt3
+    concise prompt for qhull 
+*/  
+char qh_prompt3[]= "\n\
+Qhull %s.\n\
+Except for 'F.' and 'PG', upper-case options take an argument.\n\
+\n\
+ incidences     mathematica    OFF_format     points_lifted  summary\n\
+ facet_dump\n\
+\n\
+ Farea          FArea_total    Fcoincident    Fd_cdd_in      FD_cdd_out\n\
+ FF_dump_xridge FIDs           Fmerges        Fneighbors     FNeigh_vertex\n\
+ FOptions       FPoint_near    FQdelaun       Fsummary       FSize\n\
+ Fvertices      Fxtremes\n\
+\n\
+ Gvertices      Gpoints        Gall_points    Gno_planes     Ginner\n\
+ Gcentrums      Ghyperplanes   Gridges        Gouter         GDrop_dim\n\
+ Gtransparent\n\
+\n\
+ PArea_keep     Pdrop d0:0D0   Pgood          PFacet_area_keep\n\
+ PGood_neighbors PMerge_keep   Poutput_forced Pprecision_not\n\
+\n\
+ QGood_point    QJoggle        Qsearch_1st    Qtriangulate   QupperDelaunay\n\
+ QVertex_good   Qzinfinite\n\
+\n\
+ T4_trace       Tcheck_often   Tstatistics    Tverify        Tz_stdout\n\
+ TFacet_log     TInput_file    TPoint_trace   TMerge_trace   TOutput_file\n\
+ TWide_trace    TVertex_stop   TCone_stop\n\
+\n\
+ Angle_max      Centrum_size   Random_dist    Wide_outside\n\
+";
+
+/*---------------------------------
+  
+  main( argc, argv )
+    processes the command line, calls qhull() to do the work, and exits
+  
+  design:
+    initializes data structures
+    reads points
+    finishes initialization
+    computes convex hull and other structures
+    checks the result
+    writes the output
+    frees memory
+*/
+int main(int argc, char *argv[]) {
+  int curlong, totlong; /* used !qh_NOmem */
+  int exitcode, numpoints, dim;
+  coordT *points;
+  boolT ismalloc;
+
+#if __MWERKS__ && __POWERPC__
+  char inBuf[BUFSIZ], outBuf[BUFSIZ], errBuf[BUFSIZ];
+  SIOUXSettings.showstatusline= false;
+  SIOUXSettings.tabspaces= 1;
+  SIOUXSettings.rows= 40;
+  if (setvbuf (stdin, inBuf, _IOFBF, sizeof(inBuf)) < 0   /* w/o, SIOUX I/O is slow*/
+  || setvbuf (stdout, outBuf, _IOFBF, sizeof(outBuf)) < 0
+  || (stdout != stderr && setvbuf (stderr, errBuf, _IOFBF, sizeof(errBuf)) < 0)) 
+    fprintf (stderr, "qhull internal warning (main): could not change stdio to fully buffered.\n");
+  argc= ccommand(&argv);
+#endif
+
+  if ((argc == 1) && isatty( 0 /*stdin*/)) {      
+    fprintf(stdout, qh_prompt2, qh_VERSION);
+    exit(qh_ERRnone);
+  }
+  if (argc > 1 && *argv[1] == '-' && !*(argv[1]+1)) {
+    fprintf(stdout, qh_prompta, qh_VERSION,  
+		qh_promptb, qh_promptc, qh_promptd, qh_prompte);
+    exit(qh_ERRnone);
+  }
+  if (argc >1 && *argv[1] == '.' && !*(argv[1]+1)) {
+    fprintf(stdout, qh_prompt3, qh_VERSION);
+    exit(qh_ERRnone);
+  }
+  qh_init_A (stdin, stdout, stderr, argc, argv);  /* sets qh qhull_command */
+  exitcode= setjmp (qh errexit); /* simple statement for CRAY J916 */
+  if (!exitcode) {
+    qh_option ("delaunay  Qbbound-last", NULL, NULL);
+    qh DELAUNAY= True;     /* 'd'   */
+    qh SCALElast= True;    /* 'Qbb' */
+    qh KEEPcoplanar= True; /* 'Qc', to keep coplanars in 'p' */
+    qh_checkflags (qh qhull_command, hidden_options);
+    qh_initflags (qh qhull_command);
+    points= qh_readpoints (&numpoints, &dim, &ismalloc);
+    if (dim >= 5) {
+      qh_option ("Qxact_merge", NULL, NULL);
+      qh MERGEexact= True; /* 'Qx' always */
+    }
+    qh_init_B (points, numpoints, dim, ismalloc);
+    qh_qhull();
+    qh_check_output();
+    qh_produce_output();
+    if (qh VERIFYoutput && !qh FORCEoutput && !qh STOPpoint && !qh STOPcone)
+      qh_check_points();
+    exitcode= qh_ERRnone;
+  }
+  qh NOerrexit= True;  /* no more setjmp */
+#ifdef qh_NOmem
+  qh_freeqhull( True);
+#else
+  qh_freeqhull( False);
+  qh_memfreeshort (&curlong, &totlong);
+  if (curlong || totlong) 
+    fprintf (stderr, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n",
+       totlong, curlong);
+#endif
+  return exitcode;
+} /* main */
+
diff --git a/extern/qhull/src/qhalf.c b/extern/qhull/src/qhalf.c
new file mode 100644
index 00000000000..a2b3875dd7f
--- /dev/null
+++ b/extern/qhull/src/qhalf.c
@@ -0,0 +1,324 @@
+/*
  ---------------------------------
+
+   qhalf.c
+     compute the intersection of halfspaces about a point
+
+   see unix.c for full interface
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "qhull.h"
+#include "mem.h"
+#include "qset.h"
+
+#if __MWERKS__ && __POWERPC__
+#include 
+#include 
+#include 
+#include 
+
+#elif __cplusplus
+extern "C" {
+  int isatty (int);
+}
+
+#elif _MSC_VER
+#include 
+#define isatty _isatty
+
+#else
+int isatty (int);  /* returns 1 if stdin is a tty
+		   if "Undefined symbol" this can be deleted along with call in main() */
+#endif
+
+/*---------------------------------
+
+  qh_prompt 
+    long prompt for qhull
+    
+  notes:
+    restricted version of qhull.c
+ 
+  see:
+    concise prompt below
+*/  
+
+/* duplicated in qhalf.htm */
+char hidden_options[]=" d n v Qbb QbB Qf Qg Qm Qr QR Qv Qx Qz TR E V Fa FA FC FD FS Ft FV Gt Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 ";
+
+char qh_prompta[]= "\n\
+qhalf- compute the intersection of halfspaces about a point\n\
+    http://www.geom.umn.edu/software/qhull  %s\n\
+\n\
+input (stdin):\n\
+    optional interior point: dimension, 1, coordinates\n\
+    first lines: dimension+1 and number of halfspaces\n\
+    other lines: halfspace coefficients followed by offset\n\
+    comments:    start with a non-numeric character\n\
+\n\
+options:\n\
+    Hn,n - specify coordinates of interior point\n\
+    Qt   - triangulated output\n\
+    QJ   - joggled input instead of merged facets\n\
+    Qc   - keep coplanar halfspaces\n\
+    Qi   - keep other redundant halfspaces\n\
+\n\
+Qhull control options:\n\
+    QJn  - randomly joggle input in range [-n,n]\n\
+%s%s%s%s";  /* split up qh_prompt for Visual C++ */
+char qh_promptb[]= "\
+    Qbk:0Bk:0 - remove k-th coordinate from input\n\
+    Qs   - search all halfspaces for the initial simplex\n\
+    QGn  - print intersection if visible to halfspace n, -n for not\n\
+    QVn  - print intersections for halfspace n, -n if not\n\
+\n\
+";
+char qh_promptc[]= "\
+Trace options:\n\
+    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
+    Tc   - check frequently during execution\n\
+    Ts   - print statistics\n\
+    Tv   - verify result: structure, convexity, and redundancy\n\
+    Tz   - send all output to stdout\n\
+    TFn  - report summary when n or more facets created\n\
+    TI file - input data from file, no spaces or single quotes\n\
+    TO file - output results to file, may be enclosed in single quotes\n\
+    TPn  - turn on tracing when halfspace n added to intersection\n\
+    TMn  - turn on tracing at merge n\n\
+    TWn  - trace merge facets when width > n\n\
+    TVn  - stop qhull after adding halfspace n, -n for before (see TCn)\n\
+    TCn  - stop qhull after building cone for halfspace n (see TVn)\n\
+\n\
+Precision options:\n\
+    Cn   - radius of centrum (roundoff added).  Merge facets if non-convex\n\
+     An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex\n\
+           C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge\n\
+    Rn   - randomly perturb computations by a factor of [1-n,1+n]\n\
+    Un   - max distance below plane for a new, coplanar halfspace\n\
+    Wn   - min facet width for outside halfspace (before roundoff)\n\
+\n\
+Output formats (may be combined; if none, produces a summary to stdout):\n\
+    f    - facet dump\n\
+    G    - Geomview output (dual convex hull)\n\
+    i    - non-redundant halfspaces incident to each intersection\n\
+    m    - Mathematica output (dual convex hull)\n\
+    o    - OFF format (dual convex hull: dimension, points, and facets)\n\
+    p    - vertex coordinates of dual convex hull (coplanars if 'Qc' or 'Qi')\n\
+    s    - summary (stderr)\n\
+\n\
+";
+char qh_promptd[]= "\
+More formats:\n\
+    Fc   - count plus redundant halfspaces for each intersection\n\
+         -   Qc (default) for coplanar and Qi for other redundant\n\
+    Fd   - use cdd format for input (homogeneous with offset first)\n\
+    FF   - facet dump without ridges\n\
+    FI   - ID of each intersection\n\
+    Fm   - merge count for each intersection (511 max)\n\
+    Fn   - count plus neighboring intersections for each intersection\n\
+    FN   - count plus intersections for each non-redundant halfspace\n\
+    FO   - options and precision constants\n\
+    Fp   - dim, count, and intersection coordinates\n\
+    FP   - nearest halfspace and distance for each redundant halfspace\n\
+    FQ   - command used for qhalf\n\
+    Fs   - summary: #int (8), dim, #halfspaces, #non-redundant, #intersections\n\
+                      for output: #non-redundant, #intersections, #coplanar\n\
+                                  halfspaces, #non-simplicial intersections\n\
+                    #real (2), max outer plane, min vertex\n\
+    Fv   - count plus non-redundant halfspaces for each intersection\n\
+    Fx   - non-redundant halfspaces\n\
+\n\
+";
+char qh_prompte[]= "\
+Geomview output (2-d, 3-d and 4-d; dual convex hull)\n\
+    Ga   - all points (i.e., transformed halfspaces) as dots\n\
+     Gp  -  coplanar points and vertices as radii\n\
+     Gv  -  vertices (i.e., non-redundant halfspaces) as spheres\n\
+    Gi   - inner planes (i.e., halfspace intersections) only\n\
+     Gn  -  no planes\n\
+     Go  -  outer planes only\n\
+    Gc	 - centrums\n\
+    Gh   - hyperplane intersections\n\
+    Gr   - ridges\n\
+    GDn  - drop dimension n in 3-d and 4-d output\n\
+\n\
+Print options:\n\
+    PAn  - keep n largest facets (i.e., intersections) by area\n\
+    Pdk:n- drop facet if normal[k] <= n (default 0.0)\n\
+    PDk:n- drop facet if normal[k] >= n\n\
+    Pg   - print good facets (needs 'QGn' or 'QVn')\n\
+    PFn  - keep facets whose area is at least n\n\
+    PG   - print neighbors of good facets\n\
+    PMn  - keep n facets with most merges\n\
+    Po   - force output.  If error, output neighborhood of facet\n\
+    Pp   - do not report precision problems\n\
+\n\
+    .    - list of all options\n\
+    -    - one line descriptions of all options\n\
+";
+/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
+
+/*---------------------------------
+
+  qh_prompt2
+    synopsis for qhull 
+*/  
+char qh_prompt2[]= "\n\
+qhalf- halfspace intersection about a point. Qhull %s\n\
+    input (stdin): [dim, 1, interior point], dim+1, n, coefficients+offset\n\
+    comments start with a non-numeric character\n\
+\n\
+options (qhalf.htm):\n\
+    Hn,n - specify coordinates of interior point\n\
+    Qt   - triangulated output\n\
+    QJ   - joggled input instead of merged facets\n\
+    Tv   - verify result: structure, convexity, and redundancy\n\
+    .    - concise list of all options\n\
+    -    - one-line description of all options\n\
+\n\
+output options (subset):\n\
+    s    - summary of results (default)\n\
+    Fp   - intersection coordinates\n\
+    Fv   - non-redundant halfspaces incident to each intersection\n\
+    Fx   - non-redundant halfspaces\n\
+    o    - OFF file format (dual convex hull)\n\
+    G    - Geomview output (dual convex hull)\n\
+    m    - Mathematica output (dual convex hull)\n\
+    QVn  - print intersections for halfspace n, -n if not\n\
+    TO file - output results to file, may be enclosed in single quotes\n\
+\n\
+examples:\n\
+    rbox d | qconvex FQ n | qhalf s H0,0,0 Fp\n\
+    rbox c | qconvex FQ FV n | qhalf s i\n\
+    rbox c | qconvex FQ FV n | qhalf s o\n\
+\n\
+";
+/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
+
+/*---------------------------------
+
+  qh_prompt3
+    concise prompt for qhull 
+*/  
+char qh_prompt3[]= "\n\
+Qhull %s.\n\
+Except for 'F.' and 'PG', upper_case options take an argument.\n\
+\n\
+ incidences     Geomview       mathematica    OFF_format     point_dual\n\
+ summary        facet_dump\n\
+\n\
+ Fc_redundant   Fd_cdd_in      FF_dump_xridge FIDs           Fmerges\n\
+ Fneighbors     FN_intersect   FOptions       Fp_coordinates FP_nearest\n\
+ FQhalf         Fsummary       Fv_halfspace   Fx_non_redundant\n\
+\n\
+ Gvertices      Gpoints        Gall_points    Gno_planes     Ginner\n\
+ Gcentrums      Ghyperplanes   Gridges        Gouter         GDrop_dim\n\
+\n\
+ PArea_keep     Pdrop d0:0D0   Pgood          PFacet_area_keep\n\
+ PGood_neighbors PMerge_keep   Poutput_forced Pprecision_not\n\
+\n\
+ Qbk:0Bk:0_drop Qcoplanar      QG_half_good   Qi_redundant   QJoggle\n\
+ Qsearch_1st    Qtriangulate   QVertex_good\n\
+\n\
+ T4_trace       Tcheck_often   Tstatistics    Tverify        Tz_stdout\n\
+ TFacet_log     TInput_file    TPoint_trace   TMerge_trace   TOutput_file\n\
+ TWide_trace    TVertex_stop   TCone_stop\n\
+\n\
+ Angle_max      Centrum_size   Random_dist    Ucoplanar_max  Wide_outside\n\
+";
+
+/*---------------------------------
+  
+  main( argc, argv )
+    processes the command line, calls qhull() to do the work, and exits
+  
+  design:
+    initializes data structures
+    reads points
+    finishes initialization
+    computes convex hull and other structures
+    checks the result
+    writes the output
+    frees memory
+*/
+int main(int argc, char *argv[]) {
+  int curlong, totlong; /* used !qh_NOmem */
+  int exitcode, numpoints, dim;
+  coordT *points;
+  boolT ismalloc;
+
+#if __MWERKS__ && __POWERPC__
+  char inBuf[BUFSIZ], outBuf[BUFSIZ], errBuf[BUFSIZ];
+  SIOUXSettings.showstatusline= false;
+  SIOUXSettings.tabspaces= 1;
+  SIOUXSettings.rows= 40;
+  if (setvbuf (stdin, inBuf, _IOFBF, sizeof(inBuf)) < 0   /* w/o, SIOUX I/O is slow*/
+  || setvbuf (stdout, outBuf, _IOFBF, sizeof(outBuf)) < 0
+  || (stdout != stderr && setvbuf (stderr, errBuf, _IOFBF, sizeof(errBuf)) < 0)) 
+    fprintf (stderr, "qhull internal warning (main): could not change stdio to fully buffered.\n");
+  argc= ccommand(&argv);
+#endif
+
+  if ((argc == 1) && isatty( 0 /*stdin*/)) {      
+    fprintf(stdout, qh_prompt2, qh_VERSION);
+    exit(qh_ERRnone);
+  }
+  if (argc > 1 && *argv[1] == '-' && !*(argv[1]+1)) {
+    fprintf(stdout, qh_prompta, qh_VERSION, 
+        qh_promptb, qh_promptc, qh_promptd, qh_prompte);
+    exit(qh_ERRnone);
+  }
+  if (argc >1 && *argv[1] == '.' && !*(argv[1]+1)) {
+    fprintf(stdout, qh_prompt3, qh_VERSION);
+    exit(qh_ERRnone);
+  }
+  qh_init_A (stdin, stdout, stderr, argc, argv);  /* sets qh qhull_command */
+  exitcode= setjmp (qh errexit); /* simple statement for CRAY J916 */
+  if (!exitcode) {
+    qh_option ("Halfspace", NULL, NULL);
+    qh HALFspace= True;    /* 'H'   */
+    qh_checkflags (qh qhull_command, hidden_options);
+    qh_initflags (qh qhull_command);
+    if (qh SCALEinput) {
+      fprintf(qh ferr, "\
+qhull error: options 'Qbk:n' and 'QBk:n' are not used with qhalf.\n\
+             Use 'Qbk:0Bk:0 to drop dimension k.\n");
+      qh_errexit(qh_ERRinput, NULL, NULL);
+    }
+    points= qh_readpoints (&numpoints, &dim, &ismalloc);
+    if (dim >= 5) {
+      qh_option ("Qxact_merge", NULL, NULL);
+      qh MERGEexact= True; /* 'Qx' always */
+    }
+    qh_init_B (points, numpoints, dim, ismalloc);
+    qh_qhull();
+    qh_check_output();
+    qh_produce_output();
+    if (qh VERIFYoutput && !qh FORCEoutput && !qh STOPpoint && !qh STOPcone)
+      qh_check_points();
+    exitcode= qh_ERRnone;
+  }
+  qh NOerrexit= True;  /* no more setjmp */
+#ifdef qh_NOmem
+  qh_freeqhull( True);
+#else
+  qh_freeqhull( False);
+  qh_memfreeshort (&curlong, &totlong);
+  if (curlong || totlong) 
+    fprintf (stderr, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n",
+       totlong, curlong);
+#endif
+  return exitcode;
+} /* main */
+
diff --git a/extern/qhull/src/qhull.c b/extern/qhull/src/qhull.c
new file mode 100644
index 00000000000..dc835bb4f28
--- /dev/null
+++ b/extern/qhull/src/qhull.c
@@ -0,0 +1,1395 @@
+/*
  ---------------------------------
+
+   qhull.c
+   Quickhull algorithm for convex hulls
+
+   qhull() and top-level routines
+
+   see qh-qhull.htm, qhull.h, unix.c
+
+   see qhull_a.h for internal functions
+
+   copyright (c) 1993-2002 The Geometry Center        
+*/
+
+#include "qhull_a.h" 
+
+/*============= functions in alphabetic order after qhull() =======*/
+
+/*---------------------------------
+  
+  qh_qhull()
+    compute DIM3 convex hull of qh.num_points starting at qh.first_point
+    qh contains all global options and variables
+
+  returns:
+    returns polyhedron
+      qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices,
+    
+    returns global variables
+      qh.hulltime, qh.max_outside, qh.interior_point, qh.max_vertex, qh.min_vertex
+    
+    returns precision constants
+      qh.ANGLEround, centrum_radius, cos_max, DISTround, MAXabs_coord, ONEmerge
+
+  notes:
+    unless needed for output
+      qh.max_vertex and qh.min_vertex are max/min due to merges
+      
+  see:
+    to add individual points to either qh.num_points
+      use qh_addpoint()
+      
+    if qh.GETarea
+      qh_produceoutput() returns qh.totarea and qh.totvol via qh_getarea()
+
+  design:
+    record starting time
+    initialize hull and partition points
+    build convex hull
+    unless early termination
+      update facet->maxoutside for vertices, coplanar, and near-inside points
+    error if temporary sets exist
+    record end time
+*/
+void qh_qhull (void) {
+  int numoutside;
+
+  qh hulltime= qh_CPUclock;
+  if (qh RERUN || qh JOGGLEmax < REALmax/2) 
+    qh_build_withrestart();
+  else {
+    qh_initbuild();
+    qh_buildhull();
+  }
+  if (!qh STOPpoint && !qh STOPcone) {
+    if (qh ZEROall_ok && !qh TESTvneighbors && qh MERGEexact)
+      qh_checkzero( qh_ALL);
+    if (qh ZEROall_ok && !qh TESTvneighbors && !qh WAScoplanar) {
+      trace2((qh ferr, "qh_qhull: all facets are clearly convex and no coplanar points.  Post-merging and check of maxout not needed.\n"));
+      qh DOcheckmax= False;
+    }else {
+      if (qh MERGEexact || (qh hull_dim > qh_DIMreduceBuild && qh PREmerge))
+        qh_postmerge ("First post-merge", qh premerge_centrum, qh premerge_cos, 
+             (qh POSTmerge ? False : qh TESTvneighbors));
+      else if (!qh POSTmerge && qh TESTvneighbors) 
+        qh_postmerge ("For testing vertex neighbors", qh premerge_centrum,
+             qh premerge_cos, True); 
+      if (qh POSTmerge)
+        qh_postmerge ("For post-merging", qh postmerge_centrum, 
+             qh postmerge_cos, qh TESTvneighbors);
+      if (qh visible_list == qh facet_list) { /* i.e., merging done */
+        qh findbestnew= True;
+        qh_partitionvisible (/*visible_list, newfacet_list*/ !qh_ALL, &numoutside);
+        qh findbestnew= False;
+        qh_deletevisible (/*qh visible_list*/);
+        qh_resetlists (False, qh_RESETvisible /*qh visible_list newvertex_list newfacet_list */);
+      }
+    }
+    if (qh DOcheckmax){
+      if (qh REPORTfreq) {
+	qh_buildtracing (NULL, NULL); 
+	fprintf (qh ferr, "\nTesting all coplanar points.\n");
+      }
+      qh_check_maxout();
+    }
+    if (qh KEEPnearinside && !qh maxoutdone)  
+      qh_nearcoplanar();
+  }
+  if (qh_setsize ((setT*)qhmem.tempstack) != 0) {
+    fprintf (qh ferr, "qhull internal error (qh_qhull): temporary sets not empty (%d)\n",
+	     qh_setsize ((setT*)qhmem.tempstack));
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  qh hulltime= qh_CPUclock - qh hulltime;
+  qh QHULLfinished= True;
+  trace1((qh ferr, "qh_qhull: algorithm completed\n"));
+} /* qhull */
+
+/*---------------------------------
+  
+  qh_addpoint( furthest, facet, checkdist )
+    add point (usually furthest point) above facet to hull 
+    if checkdist, 
+      check that point is above facet.
+      if point is not outside of the hull, uses qh_partitioncoplanar()
+      assumes that facet is defined by qh_findbestfacet()
+    else if facet specified,
+      assumes that point is above facet (major damage if below)
+    for Delaunay triangulations, 
+      Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
+      Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates. 
+
+  returns:
+    returns False if user requested an early termination
+     qh.visible_list, newfacet_list, delvertex_list, NEWfacets may be defined
+    updates qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices
+    clear qh.maxoutdone (will need to call qh_check_maxout() for facet->maxoutside)
+    if unknown point, adds a pointer to qh.other_points
+      do not deallocate the point's coordinates
+  
+  notes:
+    assumes point is near its best facet and not at a local minimum of a lens
+      distributions.  Use qh_findbestfacet to avoid this case.
+    uses qh.visible_list, qh.newfacet_list, qh.delvertex_list, qh.NEWfacets
+
+  see also:
+    qh_triangulate() -- triangulate non-simplicial facets
+
+  design:
+    check point in qh.first_point/.num_points
+    if checkdist
+      if point not above facet
+        partition coplanar point 
+        exit
+    exit if pre STOPpoint requested
+    find horizon and visible facets for point
+    make new facets for point to horizon
+    make hyperplanes for point
+    compute balance statistics
+    match neighboring new facets
+    update vertex neighbors and delete interior vertices
+    exit if STOPcone requested
+    merge non-convex new facets
+    if merge found, many merges, or 'Qf'
+       use qh_findbestnew() instead of qh_findbest()
+    partition outside points from visible facets
+    delete visible facets
+    check polyhedron if requested
+    exit if post STOPpoint requested
+    reset working lists of facets and vertices
+*/
+boolT qh_addpoint (pointT *furthest, facetT *facet, boolT checkdist) {
+  int goodvisible, goodhorizon;
+  vertexT *vertex;
+  facetT *newfacet;
+  realT dist, newbalance, pbalance;
+  boolT isoutside= False;
+  int numpart, numpoints, numnew, firstnew;
+
+  qh maxoutdone= False;
+  if (qh_pointid (furthest) == -1)
+    qh_setappend (&qh other_points, furthest);
+  if (!facet) {
+    fprintf (qh ferr, "qh_addpoint: NULL facet.  Need to call qh_findbestfacet first\n");
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  if (checkdist) {
+    facet= qh_findbest (furthest, facet, !qh_ALL, !qh_ISnewfacets, !qh_NOupper,
+			&dist, &isoutside, &numpart);
+    zzadd_(Zpartition, numpart);
+    if (!isoutside) {
+      zinc_(Znotmax);  /* last point of outsideset is no longer furthest. */
+      facet->notfurthest= True;
+      qh_partitioncoplanar (furthest, facet, &dist);
+      return True;
+    }
+  }
+  qh_buildtracing (furthest, facet);
+  if (qh STOPpoint < 0 && qh furthest_id == -qh STOPpoint-1) {
+    facet->notfurthest= True;
+    return False;
+  }
+  qh_findhorizon (furthest, facet, &goodvisible, &goodhorizon); 
+  if (qh ONLYgood && !(goodvisible+goodhorizon) && !qh GOODclosest) {
+    zinc_(Znotgood);  
+    facet->notfurthest= True;
+    /* last point of outsideset is no longer furthest.  This is ok
+       since all points of the outside are likely to be bad */
+    qh_resetlists (False, qh_RESETvisible /*qh visible_list newvertex_list newfacet_list */);
+    return True;
+  }
+  zzinc_(Zprocessed);
+  firstnew= qh facet_id;
+  vertex= qh_makenewfacets (furthest /*visible_list, attaches if !ONLYgood */);
+  qh_makenewplanes (/* newfacet_list */);
+  numnew= qh facet_id - firstnew;
+  newbalance= numnew - (realT) (qh num_facets-qh num_visible)
+                         * qh hull_dim/qh num_vertices;
+  wadd_(Wnewbalance, newbalance);
+  wadd_(Wnewbalance2, newbalance * newbalance);
+  if (qh ONLYgood 
+  && !qh_findgood (qh newfacet_list, goodhorizon) && !qh GOODclosest) {
+    FORALLnew_facets 
+      qh_delfacet (newfacet);
+    qh_delvertex (vertex);
+    qh_resetlists (True, qh_RESETvisible /*qh visible_list newvertex_list newfacet_list */);
+    zinc_(Znotgoodnew);
+    facet->notfurthest= True;
+    return True;
+  }
+  if (qh ONLYgood)
+    qh_attachnewfacets(/*visible_list*/);
+  qh_matchnewfacets();
+  qh_updatevertices();
+  if (qh STOPcone && qh furthest_id == qh STOPcone-1) {
+    facet->notfurthest= True;
+    return False;  /* visible_list etc. still defined */
+  }
+  qh findbestnew= False;
+  if (qh PREmerge || qh MERGEexact) {
+    qh_premerge (vertex, qh premerge_centrum, qh premerge_cos);
+    if (qh_USEfindbestnew)
+      qh findbestnew= True;
+    else {
+      FORALLnew_facets {
+	if (!newfacet->simplicial) {
+	  qh findbestnew= True;  /* use qh_findbestnew instead of qh_findbest*/
+	  break;
+	}
+      }
+    }
+  }else if (qh BESToutside)
+    qh findbestnew= True;
+  qh_partitionvisible (/*visible_list, newfacet_list*/ !qh_ALL, &numpoints);
+  qh findbestnew= False;
+  qh findbest_notsharp= False;
+  zinc_(Zpbalance);
+  pbalance= numpoints - (realT) qh hull_dim /* assumes all points extreme */
+                * (qh num_points - qh num_vertices)/qh num_vertices;
+  wadd_(Wpbalance, pbalance);
+  wadd_(Wpbalance2, pbalance * pbalance);
+  qh_deletevisible (/*qh visible_list*/);
+  zmax_(Zmaxvertex, qh num_vertices);
+  qh NEWfacets= False;
+  if (qh IStracing >= 4) {
+    if (qh num_facets < 2000)
+      qh_printlists();
+    qh_printfacetlist (qh newfacet_list, NULL, True);
+    qh_checkpolygon (qh facet_list);
+  }else if (qh CHECKfrequently) {
+    if (qh num_facets < 50)
+      qh_checkpolygon (qh facet_list);
+    else
+      qh_checkpolygon (qh newfacet_list);
+  }
+  if (qh STOPpoint > 0 && qh furthest_id == qh STOPpoint-1) 
+    return False; 
+  qh_resetlists (True, qh_RESETvisible /*qh visible_list newvertex_list newfacet_list */);
+  /* qh_triangulate(); to test qh.TRInormals */
+  trace2((qh ferr, "qh_addpoint: added p%d new facets %d new balance %2.2g point balance %2.2g\n",
+    qh_pointid (furthest), numnew, newbalance, pbalance));
+  return True;
+} /* addpoint */
+
+/*---------------------------------
+  
+  qh_build_withrestart()
+    allow restarts due to qh.JOGGLEmax while calling qh_buildhull()
+    qh.FIRSTpoint/qh.NUMpoints is point array
+        it may be moved by qh_joggleinput()
+*/
+void qh_build_withrestart (void) {
+  int restart;
+
+  qh ALLOWrestart= True;
+  while (True) {
+    restart= setjmp (qh restartexit); /* simple statement for CRAY J916 */
+    if (restart) {       /* only from qh_precision() */
+      zzinc_(Zretry);
+      wmax_(Wretrymax, qh JOGGLEmax);
+      qh ERREXITcalled= False;
+      qh STOPcone= True; /* if break, prevents normal output */
+    }
+    if (!qh RERUN && qh JOGGLEmax < REALmax/2) {
+      if (qh build_cnt > qh_JOGGLEmaxretry) {
+	fprintf(qh ferr, "\n\
+qhull precision error: %d attempts to construct a convex hull\n\
+        with joggled input.  Increase joggle above 'QJ%2.2g'\n\
+	or modify qh_JOGGLE... parameters in user.h\n",
+	   qh build_cnt, qh JOGGLEmax);
+	qh_errexit (qh_ERRqhull, NULL, NULL);
+      }
+      if (qh build_cnt && !restart)
+	break;
+    }else if (qh build_cnt && qh build_cnt >= qh RERUN)
+      break;
+    qh STOPcone= False;
+    qh_freebuild (True);  /* first call is a nop */
+    qh build_cnt++;
+    if (!qh qhull_optionsiz)
+      qh qhull_optionsiz= strlen (qh qhull_options);
+    else { 
+      qh qhull_options [qh qhull_optionsiz]= '\0';
+      qh qhull_optionlen= 80;
+    }
+    qh_option("_run", &qh build_cnt, NULL);
+    if (qh build_cnt == qh RERUN) {
+      qh IStracing= qh TRACElastrun;  /* duplicated from qh_initqhull_globals */
+      if (qh TRACEpoint != -1 || qh TRACEdist < REALmax/2 || qh TRACEmerge) {
+        qh TRACElevel= (qh IStracing? qh IStracing : 3);
+        qh IStracing= 0;
+      }
+      qhmem.IStracing= qh IStracing;
+    }
+    if (qh JOGGLEmax < REALmax/2)
+      qh_joggleinput();
+    qh_initbuild();
+    qh_buildhull();
+    if (qh JOGGLEmax < REALmax/2 && !qh MERGING)
+      qh_checkconvex (qh facet_list, qh_ALGORITHMfault);
+  }
+  qh ALLOWrestart= False;
+} /* qh_build_withrestart */
+
+/*---------------------------------
+  
+  qh_buildhull()
+    construct a convex hull by adding outside points one at a time
+
+  returns:
+  
+  notes:
+    may be called multiple times
+    checks facet and vertex lists for incorrect flags
+    to recover from STOPcone, call qh_deletevisible and qh_resetlists
+
+  design:
+    check visible facet and newfacet flags
+    check newlist vertex flags and qh.STOPcone/STOPpoint
+    for each facet with a furthest outside point
+      add point to facet
+      exit if qh.STOPcone or qh.STOPpoint requested
+    if qh.NARROWhull for initial simplex
+      partition remaining outside points to coplanar sets
+*/
+void qh_buildhull(void) {
+  facetT *facet;
+  pointT *furthest;
+  vertexT *vertex;
+  int id;
+  
+  trace1((qh ferr, "qh_buildhull: start build hull\n"));
+  FORALLfacets {
+    if (facet->visible || facet->newfacet) {
+      fprintf (qh ferr, "qhull internal error (qh_buildhull): visible or new facet f%d in facet list\n",
+                   facet->id);    
+      qh_errexit (qh_ERRqhull, facet, NULL);
+    }
+  }
+  FORALLvertices {
+    if (vertex->newlist) {
+      fprintf (qh ferr, "qhull internal error (qh_buildhull): new vertex f%d in vertex list\n",
+                   vertex->id);
+      qh_errprint ("ERRONEOUS", NULL, NULL, NULL, vertex);
+      qh_errexit (qh_ERRqhull, NULL, NULL);
+    }
+    id= qh_pointid (vertex->point);
+    if ((qh STOPpoint>0 && id == qh STOPpoint-1) ||
+	(qh STOPpoint<0 && id == -qh STOPpoint-1) ||
+	(qh STOPcone>0 && id == qh STOPcone-1)) {
+      trace1((qh ferr,"qh_buildhull: stop point or cone P%d in initial hull\n", id));
+      return;
+    }
+  }
+  qh facet_next= qh facet_list;      /* advance facet when processed */
+  while ((furthest= qh_nextfurthest (&facet))) {
+    qh num_outside--;  /* if ONLYmax, furthest may not be outside */
+    if (!qh_addpoint (furthest, facet, qh ONLYmax))
+      break;
+  }
+  if (qh NARROWhull) /* move points from outsideset to coplanarset */
+    qh_outcoplanar( /* facet_list */ );
+  if (qh num_outside && !furthest) {
+    fprintf (qh ferr, "qhull internal error (qh_buildhull): %d outside points were never processed.\n", qh num_outside);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  trace1((qh ferr, "qh_buildhull: completed the hull construction\n"));
+} /* buildhull */
+  
+
+/*---------------------------------
+  
+  qh_buildtracing( furthest, facet )
+    trace an iteration of qh_buildhull() for furthest point and facet
+    if !furthest, prints progress message
+
+  returns:
+    tracks progress with qh.lastreport
+    updates qh.furthest_id (-3 if furthest is NULL)
+    also resets visit_id, vertext_visit on wrap around
+
+  see:
+    qh_tracemerging()
+
+  design:
+    if !furthest
+      print progress message
+      exit
+    if 'TFn' iteration
+      print progress message
+    else if tracing
+      trace furthest point and facet
+    reset qh.visit_id and qh.vertex_visit if overflow may occur
+    set qh.furthest_id for tracing
+*/
+void qh_buildtracing (pointT *furthest, facetT *facet) {
+  realT dist= 0;
+  float cpu;
+  int total, furthestid;
+  time_t timedata;
+  struct tm *tp;
+  vertexT *vertex;
+
+  qh old_randomdist= qh RANDOMdist;
+  qh RANDOMdist= False;
+  if (!furthest) {
+    time (&timedata);
+    tp= localtime (&timedata);
+    cpu= qh_CPUclock - qh hulltime;
+    cpu /= qh_SECticks;
+    total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
+    fprintf (qh ferr, "\n\
+At %02d:%02d:%02d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\
+ The current hull contains %d facets and %d vertices.  Last point was p%d\n",
+      tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, qh facet_id -1,
+      total, qh num_facets, qh num_vertices, qh furthest_id);
+    return;
+  }
+  furthestid= qh_pointid (furthest);
+  if (qh TRACEpoint == furthestid) {
+    qh IStracing= qh TRACElevel;
+    qhmem.IStracing= qh TRACElevel;
+  }else if (qh TRACEpoint != -1 && qh TRACEdist < REALmax/2) {
+    qh IStracing= 0;
+    qhmem.IStracing= 0;
+  }
+  if (qh REPORTfreq && (qh facet_id-1 > qh lastreport+qh REPORTfreq)) {
+    qh lastreport= qh facet_id-1;
+    time (&timedata);
+    tp= localtime (&timedata);
+    cpu= qh_CPUclock - qh hulltime;
+    cpu /= qh_SECticks;
+    total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
+    zinc_(Zdistio);
+    qh_distplane (furthest, facet, &dist);
+    fprintf (qh ferr, "\n\
+At %02d:%02d:%02d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\
+ The current hull contains %d facets and %d vertices.  There are %d\n\
+ outside points.  Next is point p%d (v%d), %2.2g above f%d.\n",
+      tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, qh facet_id -1,
+      total, qh num_facets, qh num_vertices, qh num_outside+1,
+      furthestid, qh vertex_id, dist, getid_(facet));
+  }else if (qh IStracing >=1) {
+    cpu= qh_CPUclock - qh hulltime;
+    cpu /= qh_SECticks;
+    qh_distplane (furthest, facet, &dist);
+    fprintf (qh ferr, "qh_addpoint: add p%d (v%d) to hull of %d facets (%2.2g above f%d) and %d outside at %4.4g CPU secs.  Previous was p%d.\n",
+      furthestid, qh vertex_id, qh num_facets, dist,
+      getid_(facet), qh num_outside+1, cpu, qh furthest_id);
+  }
+  if (qh visit_id > (unsigned) INT_MAX) {
+    qh visit_id= 0;
+    FORALLfacets
+      facet->visitid= qh visit_id;
+  }
+  if (qh vertex_visit > (unsigned) INT_MAX) {
+    qh vertex_visit= 0;
+    FORALLvertices
+      vertex->visitid= qh vertex_visit;
+  }
+  qh furthest_id= furthestid;
+  qh RANDOMdist= qh old_randomdist;
+} /* buildtracing */
+
+/*---------------------------------
+  
+  qh_errexit2( exitcode, facet, otherfacet )
+    return exitcode to system after an error
+    report two facets
+
+  returns:
+    assumes exitcode non-zero
+
+  see:
+    normally use qh_errexit() in user.c (reports a facet and a ridge)
+*/
+void qh_errexit2(int exitcode, facetT *facet, facetT *otherfacet) {
+  
+  qh_errprint("ERRONEOUS", facet, otherfacet, NULL, NULL);
+  qh_errexit (exitcode, NULL, NULL);
+} /* errexit2 */
+
+
+/*---------------------------------
+  
+  qh_findhorizon( point, facet, goodvisible, goodhorizon )
+    given a visible facet, find the point's horizon and visible facets
+    for all facets, !facet-visible
+
+  returns:
+    returns qh.visible_list/num_visible with all visible facets 
+      marks visible facets with ->visible 
+    updates count of good visible and good horizon facets
+    updates qh.max_outside, qh.max_vertex, facet->maxoutside
+
+  see:
+    similar to qh_delpoint()
+
+  design:
+    move facet to qh.visible_list at end of qh.facet_list
+    for all visible facets
+     for each unvisited neighbor of a visible facet
+       compute distance of point to neighbor
+       if point above neighbor
+         move neighbor to end of qh.visible_list
+       else if point is coplanar with neighbor
+         update qh.max_outside, qh.max_vertex, neighbor->maxoutside
+         mark neighbor coplanar (will create a samecycle later)
+         update horizon statistics         
+*/
+void qh_findhorizon(pointT *point, facetT *facet, int *goodvisible, int *goodhorizon) {
+  facetT *neighbor, **neighborp, *visible;
+  int numhorizon= 0, coplanar= 0;
+  realT dist;
+  
+  trace1((qh ferr,"qh_findhorizon: find horizon for point p%d facet f%d\n",qh_pointid(point),facet->id));
+  *goodvisible= *goodhorizon= 0;
+  zinc_(Ztotvisible);
+  qh_removefacet(facet);  /* visible_list at end of qh facet_list */
+  qh_appendfacet(facet);
+  qh num_visible= 1;
+  if (facet->good)
+    (*goodvisible)++;
+  qh visible_list= facet;
+  facet->visible= True;
+  facet->f.replace= NULL;
+  if (qh IStracing >=4)
+    qh_errprint ("visible", facet, NULL, NULL, NULL);
+  qh visit_id++;
+  FORALLvisible_facets {
+    if (visible->tricoplanar && !qh TRInormals) {
+      fprintf (qh ferr, "qh_findhorizon: does not work for tricoplanar facets.  Use option 'Q11'\n");
+      qh_errexit (qh_ERRqhull, visible, NULL);
+    }
+    visible->visitid= qh visit_id;
+    FOREACHneighbor_(visible) {
+      if (neighbor->visitid == qh visit_id) 
+        continue;
+      neighbor->visitid= qh visit_id;
+      zzinc_(Znumvisibility);
+      qh_distplane(point, neighbor, &dist);
+      if (dist > qh MINvisible) {
+        zinc_(Ztotvisible);
+	qh_removefacet(neighbor);  /* append to end of qh visible_list */
+	qh_appendfacet(neighbor);
+	neighbor->visible= True;
+        neighbor->f.replace= NULL;
+	qh num_visible++;
+	if (neighbor->good)
+	  (*goodvisible)++;
+        if (qh IStracing >=4)
+          qh_errprint ("visible", neighbor, NULL, NULL, NULL);
+      }else {
+ 	if (dist > - qh MAXcoplanar) {
+    	  neighbor->coplanar= True;
+          zzinc_(Zcoplanarhorizon);
+          qh_precision ("coplanar horizon");
+	  coplanar++;
+	  if (qh MERGING) {
+	    if (dist > 0) {
+	      maximize_(qh max_outside, dist);
+	      maximize_(qh max_vertex, dist);
+#if qh_MAXoutside
+	      maximize_(neighbor->maxoutside, dist);
+#endif
+	    }else
+	      minimize_(qh min_vertex, dist);  /* due to merge later */
+	  }
+      	  trace2((qh ferr, "qh_findhorizon: point p%d is coplanar to horizon f%d, dist=%2.7g < qh MINvisible (%2.7g)\n",
+	      qh_pointid(point), neighbor->id, dist, qh MINvisible));
+	}else
+    	  neighbor->coplanar= False;
+    	zinc_(Ztothorizon);
+        numhorizon++;
+	if (neighbor->good)
+	  (*goodhorizon)++;
+        if (qh IStracing >=4)
+          qh_errprint ("horizon", neighbor, NULL, NULL, NULL);
+      }
+    }
+  }
+  if (!numhorizon) {
+    qh_precision ("empty horizon");
+    fprintf(qh ferr, "qhull precision error (qh_findhorizon): empty horizon\n\
+Point p%d was above all facets.\n", qh_pointid(point));
+    qh_printfacetlist (qh facet_list, NULL, True);
+    qh_errexit(qh_ERRprec, NULL, NULL);
+  }
+  trace1((qh ferr, "qh_findhorizon: %d horizon facets (good %d), %d visible (good %d), %d coplanar\n", 
+       numhorizon, *goodhorizon, qh num_visible, *goodvisible, coplanar));
+  if (qh IStracing >= 4 && qh num_facets < 50) 
+    qh_printlists ();
+} /* findhorizon */
+
+/*---------------------------------
+  
+  qh_nextfurthest( visible )
+    returns next furthest point and visible facet for qh_addpoint()
+    starts search at qh.facet_next
+
+  returns:
+    removes furthest point from outside set
+    NULL if none available
+    advances qh.facet_next over facets with empty outside sets  
+
+  design:
+    for each facet from qh.facet_next
+      if empty outside set
+        advance qh.facet_next
+      else if qh.NARROWhull
+        determine furthest outside point
+        if furthest point is not outside
+          advance qh.facet_next (point will be coplanar)
+    remove furthest point from outside set
+*/
+pointT *qh_nextfurthest (facetT **visible) {
+  facetT *facet;
+  int size, index;
+  realT randr, dist;
+  pointT *furthest;
+
+  while ((facet= qh facet_next) != qh facet_tail) {
+    if (!facet->outsideset) {
+      qh facet_next= facet->next;
+      continue;
+    }
+    SETreturnsize_(facet->outsideset, size);
+    if (!size) {
+      qh_setfree (&facet->outsideset);
+      qh facet_next= facet->next;
+      continue;
+    }
+    if (qh NARROWhull) {
+      if (facet->notfurthest) 
+	qh_furthestout (facet);
+      furthest= (pointT*)qh_setlast (facet->outsideset);
+#if qh_COMPUTEfurthest
+      qh_distplane (furthest, facet, &dist);
+      zinc_(Zcomputefurthest);
+#else
+      dist= facet->furthestdist;
+#endif
+      if (dist < qh MINoutside) { /* remainder of outside set is coplanar for qh_outcoplanar */
+	qh facet_next= facet->next;
+	continue;
+      }
+    }
+    if (!qh RANDOMoutside && !qh VIRTUALmemory) {
+      if (qh PICKfurthest) {
+	qh_furthestnext (/* qh facet_list */);
+	facet= qh facet_next;
+      }
+      *visible= facet;
+      return ((pointT*)qh_setdellast (facet->outsideset));
+    }
+    if (qh RANDOMoutside) {
+      int outcoplanar = 0;
+      if (qh NARROWhull) {
+        FORALLfacets {
+	  if (facet == qh facet_next)
+	    break;
+	  if (facet->outsideset)
+  	    outcoplanar += qh_setsize( facet->outsideset);
+	}
+      }
+      randr= qh_RANDOMint;
+      randr= randr/(qh_RANDOMmax+1);
+      index= (int)floor((qh num_outside - outcoplanar) * randr);
+      FORALLfacet_(qh facet_next) {
+        if (facet->outsideset) {
+          SETreturnsize_(facet->outsideset, size);
+          if (!size)
+            qh_setfree (&facet->outsideset);
+          else if (size > index) {
+            *visible= facet;
+            return ((pointT*)qh_setdelnth (facet->outsideset, index));
+          }else
+            index -= size;
+        }
+      }
+      fprintf (qh ferr, "qhull internal error (qh_nextfurthest): num_outside %d is too low\nby at least %d, or a random real %g >= 1.0\n",
+              qh num_outside, index+1, randr);
+      qh_errexit (qh_ERRqhull, NULL, NULL);
+    }else { /* VIRTUALmemory */
+      facet= qh facet_tail->previous;
+      if (!(furthest= (pointT*)qh_setdellast(facet->outsideset))) {
+        if (facet->outsideset)
+          qh_setfree (&facet->outsideset);
+        qh_removefacet (facet);
+        qh_prependfacet (facet, &qh facet_list);
+        continue;
+      }
+      *visible= facet;
+      return furthest;
+    }
+  }
+  return NULL;
+} /* nextfurthest */
+
+/*---------------------------------
+  
+  qh_partitionall( vertices, points, numpoints )
+    partitions all points in points/numpoints to the outsidesets of facets
+    vertices= vertices in qh.facet_list (not partitioned)
+
+  returns:
+    builds facet->outsideset
+    does not partition qh.GOODpoint
+    if qh.ONLYgood && !qh.MERGING, 
+      does not partition qh.GOODvertex
+
+  notes:
+    faster if qh.facet_list sorted by anticipated size of outside set
+
+  design:
+    initialize pointset with all points
+    remove vertices from pointset
+    remove qh.GOODpointp from pointset (unless it's qh.STOPcone or qh.STOPpoint)
+    for all facets
+      for all remaining points in pointset
+        compute distance from point to facet
+        if point is outside facet
+          remove point from pointset (by not reappending)
+          update bestpoint
+          append point or old bestpoint to facet's outside set
+      append bestpoint to facet's outside set (furthest)
+    for all points remaining in pointset
+      partition point into facets' outside sets and coplanar sets
+*/
+void qh_partitionall(setT *vertices, pointT *points, int numpoints){
+  setT *pointset;
+  vertexT *vertex, **vertexp;
+  pointT *point, **pointp, *bestpoint;
+  int size, point_i, point_n, point_end, remaining, i, id;
+  facetT *facet;
+  realT bestdist= -REALmax, dist, distoutside;
+    
+  trace1((qh ferr, "qh_partitionall: partition all points into outside sets\n"));
+  pointset= qh_settemp (numpoints);
+  qh num_outside= 0;
+  pointp= SETaddr_(pointset, pointT);
+  for (i=numpoints, point= points; i--; point += qh hull_dim)
+    *(pointp++)= point;
+  qh_settruncate (pointset, numpoints);
+  FOREACHvertex_(vertices) {
+    if ((id= qh_pointid(vertex->point)) >= 0)
+      SETelem_(pointset, id)= NULL;
+  }
+  id= qh_pointid (qh GOODpointp);
+  if (id >=0 && qh STOPcone-1 != id && -qh STOPpoint-1 != id)
+    SETelem_(pointset, id)= NULL;
+  if (qh GOODvertexp && qh ONLYgood && !qh MERGING) { /* matches qhull()*/
+    if ((id= qh_pointid(qh GOODvertexp)) >= 0)
+      SETelem_(pointset, id)= NULL;
+  }
+  if (!qh BESToutside) {  /* matches conditional for qh_partitionpoint below */
+    distoutside= qh_DISToutside; /* multiple of qh.MINoutside & qh.max_outside, see user.h */
+    zval_(Ztotpartition)= qh num_points - qh hull_dim - 1; /*misses GOOD... */
+    remaining= qh num_facets;
+    point_end= numpoints;
+    FORALLfacets {
+      size= point_end/(remaining--) + 100;
+      facet->outsideset= qh_setnew (size);
+      bestpoint= NULL;
+      point_end= 0;
+      FOREACHpoint_i_(pointset) {
+        if (point) {
+          zzinc_(Zpartitionall);
+          qh_distplane (point, facet, &dist);
+          if (dist < distoutside)
+            SETelem_(pointset, point_end++)= point;
+          else {
+	    qh num_outside++;
+            if (!bestpoint) {
+              bestpoint= point;
+              bestdist= dist;
+            }else if (dist > bestdist) {
+              qh_setappend (&facet->outsideset, bestpoint);
+              bestpoint= point;
+              bestdist= dist;
+            }else 
+              qh_setappend (&facet->outsideset, point);
+          }
+        }
+      }
+      if (bestpoint) {
+        qh_setappend (&facet->outsideset, bestpoint);
+#if !qh_COMPUTEfurthest
+	facet->furthestdist= bestdist;
+#endif
+      }else
+        qh_setfree (&facet->outsideset);
+      qh_settruncate (pointset, point_end);
+    }
+  }
+  /* if !qh BESToutside, pointset contains points not assigned to outsideset */
+  if (qh BESToutside || qh MERGING || qh KEEPcoplanar || qh KEEPinside) {
+    qh findbestnew= True;
+    FOREACHpoint_i_(pointset) { 
+      if (point)
+        qh_partitionpoint(point, qh facet_list);
+    }
+    qh findbestnew= False;
+  }
+  zzadd_(Zpartitionall, zzval_(Zpartition));
+  zzval_(Zpartition)= 0;
+  qh_settempfree(&pointset);
+  if (qh IStracing >= 4)
+    qh_printfacetlist (qh facet_list, NULL, True);
+} /* partitionall */
+
+
+/*---------------------------------
+  
+  qh_partitioncoplanar( point, facet, dist )
+    partition coplanar point to a facet
+    dist is distance from point to facet
+    if dist NULL, 
+      searches for bestfacet and does nothing if inside
+    if qh.findbestnew set, 
+      searches new facets instead of using qh_findbest()
+
+  returns:
+    qh.max_ouside updated
+    if qh.KEEPcoplanar or qh.KEEPinside
+      point assigned to best coplanarset
+  
+  notes:
+    facet->maxoutside is updated at end by qh_check_maxout
+
+  design:
+    if dist undefined
+      find best facet for point
+      if point sufficiently below facet (depends on qh.NEARinside and qh.KEEPinside)
+        exit
+    if keeping coplanar/nearinside/inside points
+      if point is above furthest coplanar point
+        append point to coplanar set (it is the new furthest)
+        update qh.max_outside
+      else
+        append point one before end of coplanar set
+    else if point is clearly outside of qh.max_outside and bestfacet->coplanarset
+    and bestfacet is more than perpendicular to facet
+      repartition the point using qh_findbest() -- it may be put on an outsideset
+    else
+      update qh.max_outside
+*/
+void qh_partitioncoplanar (pointT *point, facetT *facet, realT *dist) {
+  facetT *bestfacet;
+  pointT *oldfurthest;
+  realT bestdist, dist2, angle;
+  int numpart= 0, oldfindbest;
+  boolT isoutside;
+
+  qh WAScoplanar= True;
+  if (!dist) {
+    if (qh findbestnew)
+      bestfacet= qh_findbestnew (point, facet, &bestdist, qh_ALL, &isoutside, &numpart);
+    else
+      bestfacet= qh_findbest (point, facet, qh_ALL, !qh_ISnewfacets, qh DELAUNAY, 
+                          &bestdist, &isoutside, &numpart);
+    zinc_(Ztotpartcoplanar);
+    zzadd_(Zpartcoplanar, numpart);
+    if (!qh DELAUNAY && !qh KEEPinside) { /*  for 'd', bestdist skips upperDelaunay facets */
+      if (qh KEEPnearinside) {
+        if (bestdist < -qh NEARinside) { 
+          zinc_(Zcoplanarinside);
+	  trace4((qh ferr, "qh_partitioncoplanar: point p%d is more than near-inside facet f%d dist %2.2g findbestnew %d\n",
+		  qh_pointid(point), bestfacet->id, bestdist, qh findbestnew));
+          return;
+        }
+      }else if (bestdist < -qh MAXcoplanar) {
+	  trace4((qh ferr, "qh_partitioncoplanar: point p%d is inside facet f%d dist %2.2g findbestnew %d\n",
+		  qh_pointid(point), bestfacet->id, bestdist, qh findbestnew));
+        zinc_(Zcoplanarinside);
+        return;
+      }
+    }
+  }else {
+    bestfacet= facet;
+    bestdist= *dist;
+  }
+  if (bestdist > qh max_outside) {
+    if (!dist && facet != bestfacet) { 
+      zinc_(Zpartangle);
+      angle= qh_getangle(facet->normal, bestfacet->normal);
+      if (angle < 0) {
+	/* typically due to deleted vertex and coplanar facets, e.g.,
+	     RBOX 1000 s Z1 G1e-13 t1001185205 | QHULL Tv */
+	zinc_(Zpartflip);
+	trace2((qh ferr, "qh_partitioncoplanar: repartition point p%d from f%d.  It is above flipped facet f%d dist %2.2g\n",
+		qh_pointid(point), facet->id, bestfacet->id, bestdist));
+	oldfindbest= qh findbestnew;
+        qh findbestnew= False;
+	qh_partitionpoint(point, bestfacet);
+        qh findbestnew= oldfindbest;
+	return;
+      }
+    }
+    qh max_outside= bestdist;
+    if (bestdist > qh TRACEdist) {
+      fprintf (qh ferr, "qh_partitioncoplanar: ====== p%d from f%d increases max_outside to %2.2g of f%d last p%d\n",
+		     qh_pointid(point), facet->id, bestdist, bestfacet->id, qh furthest_id);
+      qh_errprint ("DISTANT", facet, bestfacet, NULL, NULL);
+    }
+  }
+  if (qh KEEPcoplanar + qh KEEPinside + qh KEEPnearinside) {
+    oldfurthest= (pointT*)qh_setlast (bestfacet->coplanarset);
+    if (oldfurthest) {
+      zinc_(Zcomputefurthest);
+      qh_distplane (oldfurthest, bestfacet, &dist2);
+    }
+    if (!oldfurthest || dist2 < bestdist) 
+      qh_setappend(&bestfacet->coplanarset, point);
+    else 
+      qh_setappend2ndlast(&bestfacet->coplanarset, point);
+  }
+  trace4((qh ferr, "qh_partitioncoplanar: point p%d is coplanar with facet f%d (or inside) dist %2.2g\n",
+	  qh_pointid(point), bestfacet->id, bestdist));
+} /* partitioncoplanar */
+
+/*---------------------------------
+  
+  qh_partitionpoint( point, facet )
+    assigns point to an outside set, coplanar set, or inside set (i.e., dropt)
+    if qh.findbestnew
+      uses qh_findbestnew() to search all new facets
+    else
+      uses qh_findbest()
+  
+  notes:
+    after qh_distplane(), this and qh_findbest() are most expensive in 3-d
+
+  design:
+    find best facet for point 
+      (either exhaustive search of new facets or directed search from facet)
+    if qh.NARROWhull
+      retain coplanar and nearinside points as outside points
+    if point is outside bestfacet
+      if point above furthest point for bestfacet
+        append point to outside set (it becomes the new furthest)
+        if outside set was empty
+          move bestfacet to end of qh.facet_list (i.e., after qh.facet_next)
+        update bestfacet->furthestdist
+      else
+        append point one before end of outside set
+    else if point is coplanar to bestfacet
+      if keeping coplanar points or need to update qh.max_outside
+        partition coplanar point into bestfacet
+    else if near-inside point        
+      partition as coplanar point into bestfacet
+    else is an inside point
+      if keeping inside points 
+        partition as coplanar point into bestfacet
+*/
+void qh_partitionpoint (pointT *point, facetT *facet) {
+  realT bestdist;
+  boolT isoutside;
+  facetT *bestfacet;
+  int numpart;
+#if qh_COMPUTEfurthest
+  realT dist;
+#endif
+
+  if (qh findbestnew)
+    bestfacet= qh_findbestnew (point, facet, &bestdist, qh BESToutside, &isoutside, &numpart);
+  else
+    bestfacet= qh_findbest (point, facet, qh BESToutside, qh_ISnewfacets, !qh_NOupper,
+			  &bestdist, &isoutside, &numpart);
+  zinc_(Ztotpartition);
+  zzadd_(Zpartition, numpart);
+  if (qh NARROWhull) {
+    if (qh DELAUNAY && !isoutside && bestdist >= -qh MAXcoplanar)
+      qh_precision ("nearly incident point (narrow hull)");
+    if (qh KEEPnearinside) {
+      if (bestdist >= -qh NEARinside)
+	isoutside= True;
+    }else if (bestdist >= -qh MAXcoplanar)
+      isoutside= True;
+  }
+
+  if (isoutside) {
+    if (!bestfacet->outsideset 
+    || !qh_setlast (bestfacet->outsideset)) {
+      qh_setappend(&(bestfacet->outsideset), point);
+      if (!bestfacet->newfacet) {
+        qh_removefacet (bestfacet);  /* make sure it's after qh facet_next */
+        qh_appendfacet (bestfacet);
+      }
+#if !qh_COMPUTEfurthest
+      bestfacet->furthestdist= bestdist;
+#endif
+    }else {
+#if qh_COMPUTEfurthest
+      zinc_(Zcomputefurthest);
+      qh_distplane (oldfurthest, bestfacet, &dist);
+      if (dist < bestdist) 
+	qh_setappend(&(bestfacet->outsideset), point);
+      else
+	qh_setappend2ndlast(&(bestfacet->outsideset), point);
+#else
+      if (bestfacet->furthestdist < bestdist) {
+	qh_setappend(&(bestfacet->outsideset), point);
+	bestfacet->furthestdist= bestdist;
+      }else
+	qh_setappend2ndlast(&(bestfacet->outsideset), point);
+#endif
+    }
+    qh num_outside++;
+    trace4((qh ferr, "qh_partitionpoint: point p%d is outside facet f%d new? %d(or narrowhull)\n",
+	  qh_pointid(point), bestfacet->id, bestfacet->newfacet));
+  }else if (qh DELAUNAY || bestdist >= -qh MAXcoplanar) { /* for 'd', bestdist skips upperDelaunay facets */
+    zzinc_(Zcoplanarpart);
+    if (qh DELAUNAY)
+      qh_precision ("nearly incident point");
+    if ((qh KEEPcoplanar + qh KEEPnearinside) || bestdist > qh max_outside) 
+      qh_partitioncoplanar (point, bestfacet, &bestdist);
+    else {
+      trace4((qh ferr, "qh_partitionpoint: point p%d is coplanar to facet f%d (dropped)\n",
+	  qh_pointid(point), bestfacet->id));
+    }
+  }else if (qh KEEPnearinside && bestdist > -qh NEARinside) {
+    zinc_(Zpartnear);
+    qh_partitioncoplanar (point, bestfacet, &bestdist);
+  }else {
+    zinc_(Zpartinside);
+    trace4((qh ferr, "qh_partitionpoint: point p%d is inside all facets, closest to f%d dist %2.2g\n",
+	  qh_pointid(point), bestfacet->id, bestdist));
+    if (qh KEEPinside)
+      qh_partitioncoplanar (point, bestfacet, &bestdist);
+  }
+} /* partitionpoint */
+
+/*---------------------------------
+  
+  qh_partitionvisible( allpoints, numoutside )
+    partitions points in visible facets to qh.newfacet_list
+    qh.visible_list= visible facets
+    for visible facets
+      1st neighbor (if any) points to a horizon facet or a new facet
+    if allpoints (not used),
+      repartitions coplanar points
+
+  returns:
+    updates outside sets and coplanar sets of qh.newfacet_list
+    updates qh.num_outside (count of outside points)
+  
+  notes:
+    qh.findbest_notsharp should be clear (extra work if set)
+
+  design:
+    for all visible facets with outside set or coplanar set
+      select a newfacet for visible facet
+      if outside set
+        partition outside set into new facets
+      if coplanar set and keeping coplanar/near-inside/inside points
+        if allpoints
+          partition coplanar set into new facets, may be assigned outside
+        else
+          partition coplanar set into coplanar sets of new facets
+    for each deleted vertex
+      if allpoints
+        partition vertex into new facets, may be assigned outside
+      else
+        partition vertex into coplanar sets of new facets
+*/
+void qh_partitionvisible(/*visible_list*/ boolT allpoints, int *numoutside) {
+  facetT *visible, *newfacet;
+  pointT *point, **pointp;
+  int coplanar=0, size;
+  unsigned count;
+  vertexT *vertex, **vertexp;
+  
+  if (qh ONLYmax)
+    maximize_(qh MINoutside, qh max_vertex);
+  *numoutside= 0;
+  FORALLvisible_facets {
+    if (!visible->outsideset && !visible->coplanarset)
+      continue;
+    newfacet= visible->f.replace;
+    count= 0;
+    while (newfacet && newfacet->visible) {
+      newfacet= newfacet->f.replace;
+      if (count++ > qh facet_id)
+	qh_infiniteloop (visible);
+    }
+    if (!newfacet)
+      newfacet= qh newfacet_list;
+    if (newfacet == qh facet_tail) {
+      fprintf (qh ferr, "qhull precision error (qh_partitionvisible): all new facets deleted as\n        degenerate facets. Can not continue.\n");
+      qh_errexit (qh_ERRprec, NULL, NULL);
+    }
+    if (visible->outsideset) {
+      size= qh_setsize (visible->outsideset);
+      *numoutside += size;
+      qh num_outside -= size;
+      FOREACHpoint_(visible->outsideset) 
+        qh_partitionpoint (point, newfacet);
+    }
+    if (visible->coplanarset && (qh KEEPcoplanar + qh KEEPinside + qh KEEPnearinside)) {
+      size= qh_setsize (visible->coplanarset);
+      coplanar += size;
+      FOREACHpoint_(visible->coplanarset) {
+        if (allpoints) /* not used */
+          qh_partitionpoint (point, newfacet);
+        else
+          qh_partitioncoplanar (point, newfacet, NULL);
+      }
+    }
+  }
+  FOREACHvertex_(qh del_vertices) {
+    if (vertex->point) {
+      if (allpoints) /* not used */
+        qh_partitionpoint (vertex->point, qh newfacet_list);
+      else
+        qh_partitioncoplanar (vertex->point, qh newfacet_list, NULL);
+    }
+  }
+  trace1((qh ferr,"qh_partitionvisible: partitioned %d points from outsidesets and %d points from coplanarsets\n", *numoutside, coplanar));
+} /* partitionvisible */
+
+
+
+/*---------------------------------
+  
+  qh_precision( reason )
+    restart on precision errors if not merging and if 'QJn'
+*/
+void qh_precision (char *reason) {
+
+  if (qh ALLOWrestart && !qh PREmerge && !qh MERGEexact) {
+    if (qh JOGGLEmax < REALmax/2) {
+      trace0((qh ferr, "qh_precision: qhull restart because of %s\n", reason));
+      longjmp(qh restartexit, qh_ERRprec);
+    }
+  }
+} /* qh_precision */
+
+/*---------------------------------
+  
+  qh_printsummary( fp )
+    prints summary to fp
+
+  notes:
+    not in io.c so that user_eg.c can prevent io.c from loading
+    qh_printsummary and qh_countfacets must match counts
+
+  design:
+    determine number of points, vertices, and coplanar points
+    print summary
+*/
+void qh_printsummary(FILE *fp) {
+  realT ratio, outerplane, innerplane;
+  float cpu;
+  int size, id, nummerged, numvertices, numcoplanars= 0, nonsimplicial=0;
+  int goodused;
+  facetT *facet;
+  char *s;
+  int numdel= zzval_(Zdelvertextot);
+  int numtricoplanars= 0;
+
+  size= qh num_points + qh_setsize (qh other_points);
+  numvertices= qh num_vertices - qh_setsize (qh del_vertices);
+  id= qh_pointid (qh GOODpointp);
+  FORALLfacets {
+    if (facet->coplanarset)
+      numcoplanars += qh_setsize( facet->coplanarset);
+    if (facet->good) {
+      if (facet->simplicial) {
+	if (facet->keepcentrum && facet->tricoplanar)
+	  numtricoplanars++;
+      }else if (qh_setsize(facet->vertices) != qh hull_dim)
+	nonsimplicial++;
+    }
+  }
+  if (id >=0 && qh STOPcone-1 != id && -qh STOPpoint-1 != id)
+    size--;
+  if (qh STOPcone || qh STOPpoint)
+      fprintf (fp, "\nAt a premature exit due to 'TVn', 'TCn', 'TRn', or precision error.");
+  if (qh UPPERdelaunay)
+    goodused= qh GOODvertex + qh GOODpoint + qh SPLITthresholds;
+  else if (qh DELAUNAY)
+    goodused= qh GOODvertex + qh GOODpoint + qh GOODthreshold;
+  else
+    goodused= qh num_good;
+  nummerged= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
+  if (qh VORONOI) {
+    if (qh UPPERdelaunay)
+      fprintf (fp, "\n\
+Furthest-site Voronoi vertices by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
+    else
+      fprintf (fp, "\n\
+Voronoi diagram by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
+    fprintf(fp, "  Number of Voronoi regions%s: %d\n",
+              qh ATinfinity ? " and at-infinity" : "", numvertices);
+    if (numdel)
+      fprintf(fp, "  Total number of deleted points due to merging: %d\n", numdel); 
+    if (numcoplanars - numdel > 0) 
+      fprintf(fp, "  Number of nearly incident points: %d\n", numcoplanars - numdel); 
+    else if (size - numvertices - numdel > 0) 
+      fprintf(fp, "  Total number of nearly incident points: %d\n", size - numvertices - numdel); 
+    fprintf(fp, "  Number of%s Voronoi vertices: %d\n", 
+              goodused ? " 'good'" : "", qh num_good);
+    if (nonsimplicial) 
+      fprintf(fp, "  Number of%s non-simplicial Voronoi vertices: %d\n", 
+              goodused ? " 'good'" : "", nonsimplicial);
+  }else if (qh DELAUNAY) {
+    if (qh UPPERdelaunay)
+      fprintf (fp, "\n\
+Furthest-site Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
+    else
+      fprintf (fp, "\n\
+Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
+    fprintf(fp, "  Number of input sites%s: %d\n", 
+              qh ATinfinity ? " and at-infinity" : "", numvertices);
+    if (numdel)
+      fprintf(fp, "  Total number of deleted points due to merging: %d\n", numdel); 
+    if (numcoplanars - numdel > 0) 
+      fprintf(fp, "  Number of nearly incident points: %d\n", numcoplanars - numdel); 
+    else if (size - numvertices - numdel > 0)
+      fprintf(fp, "  Total number of nearly incident points: %d\n", size - numvertices - numdel); 
+    fprintf(fp, "  Number of%s Delaunay regions: %d\n", 
+              goodused ? " 'good'" : "", qh num_good);
+    if (nonsimplicial) 
+      fprintf(fp, "  Number of%s non-simplicial Delaunay regions: %d\n", 
+              goodused ? " 'good'" : "", nonsimplicial);
+  }else if (qh HALFspace) {
+    fprintf (fp, "\n\
+Halfspace intersection by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
+    fprintf(fp, "  Number of halfspaces: %d\n", size);
+    fprintf(fp, "  Number of non-redundant halfspaces: %d\n", numvertices);
+    if (numcoplanars) {
+      if (qh KEEPinside && qh KEEPcoplanar)
+      	s= "similar and redundant";
+      else if (qh KEEPinside)
+        s= "redundant";
+      else
+        s= "similar"; 
+      fprintf(fp, "  Number of %s halfspaces: %d\n", s, numcoplanars);
+    } 
+    fprintf(fp, "  Number of intersection points: %d\n", qh num_facets - qh num_visible);
+    if (goodused)
+      fprintf(fp, "  Number of 'good' intersection points: %d\n", qh num_good);
+    if (nonsimplicial) 
+      fprintf(fp, "  Number of%s non-simplicial intersection points: %d\n", 
+              goodused ? " 'good'" : "", nonsimplicial);
+  }else {
+    fprintf (fp, "\n\
+Convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
+    fprintf(fp, "  Number of vertices: %d\n", numvertices);
+    if (numcoplanars) {
+      if (qh KEEPinside && qh KEEPcoplanar)
+      	s= "coplanar and interior";
+      else if (qh KEEPinside)
+        s= "interior";
+      else
+        s= "coplanar"; 
+      fprintf(fp, "  Number of %s points: %d\n", s, numcoplanars);
+    } 
+    fprintf(fp, "  Number of facets: %d\n", qh num_facets - qh num_visible);
+    if (goodused)
+      fprintf(fp, "  Number of 'good' facets: %d\n", qh num_good);
+    if (nonsimplicial) 
+      fprintf(fp, "  Number of%s non-simplicial facets: %d\n", 
+              goodused ? " 'good'" : "", nonsimplicial);
+  }
+  if (numtricoplanars)
+      fprintf(fp, "  Number of triangulated facets: %d\n", numtricoplanars);
+  fprintf(fp, "\nStatistics for: %s | %s", 
+                      qh rbox_command, qh qhull_command);
+  if (qh ROTATErandom != INT_MIN)
+    fprintf(fp, " QR%d\n\n", qh ROTATErandom);
+  else
+    fprintf(fp, "\n\n");
+  fprintf(fp, "  Number of points processed: %d\n", zzval_(Zprocessed));
+  fprintf(fp, "  Number of hyperplanes created: %d\n", zzval_(Zsetplane));
+  if (qh DELAUNAY)
+    fprintf(fp, "  Number of facets in hull: %d\n", qh num_facets - qh num_visible);
+  fprintf(fp, "  Number of distance tests for qhull: %d\n", zzval_(Zpartition)+
+      zzval_(Zpartitionall)+zzval_(Znumvisibility)+zzval_(Zpartcoplanar));
+#if 0  /* NOTE: must print before printstatistics() */
+  {realT stddev, ave;
+  fprintf(fp, "  average new facet balance: %2.2g\n",
+	  wval_(Wnewbalance)/zval_(Zprocessed));
+  stddev= qh_stddev (zval_(Zprocessed), wval_(Wnewbalance), 
+                                 wval_(Wnewbalance2), &ave);
+  fprintf(fp, "  new facet standard deviation: %2.2g\n", stddev);
+  fprintf(fp, "  average partition balance: %2.2g\n",
+	  wval_(Wpbalance)/zval_(Zpbalance));
+  stddev= qh_stddev (zval_(Zpbalance), wval_(Wpbalance), 
+                                 wval_(Wpbalance2), &ave);
+  fprintf(fp, "  partition standard deviation: %2.2g\n", stddev);
+  }
+#endif
+  if (nummerged) {
+    fprintf(fp,"  Number of distance tests for merging: %d\n",zzval_(Zbestdist)+
+          zzval_(Zcentrumtests)+zzval_(Zdistconvex)+zzval_(Zdistcheck)+
+          zzval_(Zdistzero));
+    fprintf(fp,"  Number of distance tests for checking: %d\n",zzval_(Zcheckpart));
+    fprintf(fp,"  Number of merged facets: %d\n", nummerged);
+  }
+  if (!qh RANDOMoutside && qh QHULLfinished) {
+    cpu= qh hulltime;
+    cpu /= qh_SECticks;
+    wval_(Wcpu)= cpu;
+    fprintf (fp, "  CPU seconds to compute hull (after input): %2.4g\n", cpu);
+  }
+  if (qh RERUN) {
+    if (!qh PREmerge && !qh MERGEexact)
+      fprintf(fp, "  Percentage of runs with precision errors: %4.1f\n",
+	   zzval_(Zretry)*100.0/qh build_cnt);  /* careful of order */
+  }else if (qh JOGGLEmax < REALmax/2) {
+    if (zzval_(Zretry))
+      fprintf(fp, "  After %d retries, input joggled by: %2.2g\n",
+         zzval_(Zretry), qh JOGGLEmax);
+    else
+      fprintf(fp, "  Input joggled by: %2.2g\n", qh JOGGLEmax);
+  }
+  if (qh totarea != 0.0) 
+    fprintf(fp, "  %s facet area:   %2.8g\n", 
+	    zzval_(Ztotmerge) ? "Approximate" : "Total", qh totarea);
+  if (qh totvol != 0.0) 
+    fprintf(fp, "  %s volume:       %2.8g\n", 
+	    zzval_(Ztotmerge) ? "Approximate" : "Total", qh totvol);
+  if (qh MERGING) {
+    qh_outerinner (NULL, &outerplane, &innerplane);
+    if (outerplane > 2 * qh DISTround) {
+      fprintf(fp, "  Maximum distance of %spoint above facet: %2.2g", 
+	    (qh QHULLfinished ? "" : "merged "), outerplane);
+      ratio= outerplane/(qh ONEmerge + qh DISTround);
+      /* don't report ratio if MINoutside is large */
+      if (ratio > 0.05 && 2* qh ONEmerge > qh MINoutside && qh JOGGLEmax > REALmax/2)
+        fprintf (fp, " (%.1fx)\n", ratio);
+      else
+        fprintf (fp, "\n");
+    }
+    if (innerplane < -2 * qh DISTround) {
+      fprintf(fp, "  Maximum distance of %svertex below facet: %2.2g", 
+	    (qh QHULLfinished ? "" : "merged "), innerplane);
+      ratio= -innerplane/(qh ONEmerge+qh DISTround);
+      if (ratio > 0.05 && qh JOGGLEmax > REALmax/2)
+        fprintf (fp, " (%.1fx)\n", ratio);
+      else
+        fprintf (fp, "\n");
+    }
+  }
+  fprintf(fp, "\n");
+} /* printsummary */
+
+
diff --git a/extern/qhull/src/qhull.h b/extern/qhull/src/qhull.h
new file mode 100644
index 00000000000..896ec1e9c18
--- /dev/null
+++ b/extern/qhull/src/qhull.h
@@ -0,0 +1,1048 @@
+/*
  ---------------------------------
+
+   qhull.h
+   user-level header file for using qhull.a library
+
+   see qh-qhull.htm, qhull_a.h
+
+   copyright (c) 1993-2002, The Geometry Center
+
+   NOTE: access to qh_qh is via the 'qh' macro.  This allows
+   qh_qh to be either a pointer or a structure.  An example
+   of using qh is "qh DROPdim" which accesses the DROPdim
+   field of qh_qh.  Similarly, access to qh_qhstat is via
+   the 'qhstat' macro.
+
+   includes function prototypes for qhull.c, geom.c, global.c, io.c, user.c
+
+   use mem.h for mem.c
+   use qset.h for qset.c
+
+   see unix.c for an example of using qhull.h
+
+   recompile qhull if you change this file
+*/
+
+#ifndef qhDEFqhull
+#define qhDEFqhull 1
+
+/*=========================== -included files ==============*/
+
+#include 
+#include 
+#include 
+
+#if __MWERKS__ && __POWERPC__
+#include  
+#include  
+#include	
+#endif
+
+#ifndef __STDC__
+#ifndef __cplusplus
+#if     !_MSC_VER
+#error  Neither __STDC__ nor __cplusplus is defined.  Please use strict ANSI C or C++ to compile
+#error  Qhull.  You may need to turn off compiler extensions in your project configuration.  If
+#error  your compiler is a standard C compiler, you can delete this warning from qhull.h
+#endif
+#endif
+#endif
+
+#include "user.h"      /* user defineable constants */
+
+/*============ constants and basic types ====================*/
+
+/*----------------------------------
+
+  qh_VERSION
+    version string by year and date
+
+    the revision increases on code changes only
+
+  notes:
+    change date:    Changes.txt, Announce.txt, README.txt, qhull.man
+                    qhull-news.html, Eudora signatures, 
+    change version: README.txt, qhull.html, file_id.diz, Makefile
+    change year:    Copying.txt
+    check download size
+    recompile user_eg.c, rbox.c, qhull.c, qconvex.c, qdelaun.c qvoronoi.c, qhalf.c
+    make copy of qhull-news.html as qh-news.htm
+*/
+
+#define qh_VERSION "2002.1 2002/8/20"
+
+/*----------------------------------
+
+  coordT
+    coordinates and coefficients are stored as realT (i.e., double)
+
+  notes:
+    could use 'float' for data and 'double' for calculations (realT vs. coordT)
+      This requires many type casts, and adjusted error bounds.
+      Also C compilers may do expressions in double anyway.
+*/
+#define coordT realT
+
+/*----------------------------------
+
+  pointT
+    a point is an array of DIM3 coordinates
+*/
+#define pointT coordT
+
+/*----------------------------------
+
+  flagT
+    Boolean flag as a bit
+*/
+#define flagT unsigned int
+
+/*----------------------------------
+
+  boolT
+    boolean value, either True or False
+
+  notes:
+    needed for portability
+*/
+#define boolT unsigned int
+#ifdef False
+#undef False
+#endif
+#ifdef True
+#undef True
+#endif
+#define False 0
+#define True 1
+
+/*----------------------------------
+
+  qh_CENTER
+    to distinguish facet->center
+*/
+typedef enum
+{
+    qh_ASnone = 0, qh_ASvoronoi, qh_AScentrum
+}
+qh_CENTER;
+
+/*----------------------------------
+
+  qh_PRINT
+    output formats for printing (qh.PRINTout).
+    'Fa' 'FV' 'Fc' 'FC' 
+       
+
+   notes:
+   some of these names are similar to qh names.  The similar names are only
+   used in switch statements in qh_printbegin() etc.
+*/
+typedef enum {qh_PRINTnone= 0, 
+  qh_PRINTarea, qh_PRINTaverage,           /* 'Fa' 'FV' 'Fc' 'FC' */
+  qh_PRINTcoplanars, qh_PRINTcentrums, 
+  qh_PRINTfacets, qh_PRINTfacets_xridge,   /* 'f' 'FF' 'G' 'FI' 'Fi' 'Fn' */
+  qh_PRINTgeom, qh_PRINTids, qh_PRINTinner, qh_PRINTneighbors, 
+  qh_PRINTnormals, qh_PRINTouter,          /* 'n' 'Fo' 'i' 'm' 'Fm' 'o' */
+  qh_PRINTincidences, qh_PRINTmathematica, qh_PRINTmerges, qh_PRINToff, 
+  qh_PRINToptions, qh_PRINTpointintersect, /* 'FO' 'Fp' 'FP' 'p' 'FQ' 'FS' */
+  qh_PRINTpointnearest, qh_PRINTpoints, qh_PRINTqhull, qh_PRINTsize, 
+  qh_PRINTsummary, qh_PRINTtriangles,      /* 'Fs' 'Ft' 'Fv' 'FN' 'Fx' */
+  qh_PRINTvertices, qh_PRINTvneighbors, qh_PRINTextremes,
+  qh_PRINTEND} qh_PRINT;
+
+/*----------------------------------
+
+  qh_ALL
+    argument flag for selecting everything
+*/
+#define qh_ALL      True
+#define qh_NOupper  True     /* argument for qh_findbest */
+#define qh_IScheckmax  True     /* argument for qh_findbesthorizon */
+#define qh_ISnewfacets  True     /* argument for qh_findbest */
+#define qh_RESETvisible  True     /* argument for qh_resetlists */
+
+/*----------------------------------
+
+  qh_ERR
+    Qhull exit codes, for indicating errors
+*/
+#define qh_ERRnone  0    /* no error occurred during qhull */
+#define qh_ERRinput 1    /* input inconsistency */
+#define qh_ERRsingular 2 /* singular input data */
+#define qh_ERRprec  3    /* precision error */
+#define qh_ERRmem   4    /* insufficient memory, matches mem.h */
+#define qh_ERRqhull 5    /* internal error detected, matches mem.h */
+
+/* ============ -structures- ====================
+   each of the following structures is defined by a typedef
+   all realT and coordT fields occur at the beginning of a structure
+        (otherwise space may be wasted due to alignment)
+   define all flags together and pack into 32-bit number
+*/
+
+typedef struct vertexT vertexT;
+typedef struct ridgeT ridgeT;
+typedef struct facetT facetT;
+#ifndef DEFsetT
+#define DEFsetT 1
+typedef struct setT setT;          /* defined in qset.h */
+#endif
+
+/*----------------------------------
+
+  facetT
+    defines a facet
+
+  notes:
+   qhull() generates the hull as a list of facets.
+
+  topological information:
+    f.previous,next     doubly-linked list of facets
+    f.vertices          set of vertices
+    f.ridges            set of ridges
+    f.neighbors         set of neighbors
+    f.toporient         True if facet has top-orientation (else bottom)
+
+  geometric information:
+    f.offset,normal     hyperplane equation
+    f.maxoutside        offset to outer plane -- all points inside
+    f.center            centrum for testing convexity
+    f.simplicial        True if facet is simplicial
+    f.flipped           True if facet does not include qh.interior_point
+
+  for constructing hull:
+    f.visible           True if facet on list of visible facets (will be deleted)
+    f.newfacet          True if facet on list of newly created facets
+    f.coplanarset       set of points coplanar with this facet
+                        (includes near-inside points for later testing)
+    f.outsideset        set of points outside of this facet
+    f.furthestdist      distance to furthest point of outside set
+    f.visitid           marks visited facets during a loop
+    f.replace           replacement facet for to-be-deleted, visible facets
+    f.samecycle,newcycle cycle of facets for merging into horizon facet
+
+  see below for other flags and fields
+*/
+struct facetT {
+#if !qh_COMPUTEfurthest
+  coordT   furthestdist;/* distance to furthest point of outsideset */
+#endif
+#if qh_MAXoutside
+  coordT   maxoutside;  /* max computed distance of point to facet
+  			Before QHULLfinished this is an approximation
+  			since maxdist not always set for mergefacet
+			Actual outer plane is +DISTround and
+			computed outer plane is +2*DISTround */
+#endif
+  coordT   offset;      /* exact offset of hyperplane from origin */
+  coordT  *normal;      /* normal of hyperplane, hull_dim coefficients */
+			/*   if tricoplanar, shared with a neighbor */
+  union {               /* in order of testing */
+   realT   area;        /* area of facet, only in io.c if  ->isarea */
+   facetT *replace;	/*  replacement facet if ->visible and NEWfacets
+  			     is NULL only if qh_mergedegen_redundant or interior */
+   facetT *samecycle;   /*  cycle of facets from the same visible/horizon intersection,
+   			     if ->newfacet */
+   facetT *newcycle;    /*  in horizon facet, current samecycle of new facets */ 
+   facetT *trivisible;  /* visible facet for ->tricoplanar facets during qh_triangulate() */
+   facetT *triowner;    /* owner facet for ->tricoplanar, !isarea facets w/ ->keepcentrum */
+  }f;
+  coordT  *center;      /*  centrum for convexity, qh CENTERtype == qh_AScentrum */
+      			/*  Voronoi center, qh CENTERtype == qh_ASvoronoi */
+			/*   if tricoplanar, shared with a neighbor */
+  facetT  *previous;    /* previous facet in the facet_list */
+  facetT  *next;        /* next facet in the facet_list */
+  setT    *vertices;    /* vertices for this facet, inverse sorted by ID 
+                           if simplicial, 1st vertex was apex/furthest */
+  setT    *ridges;      /* explicit ridges for nonsimplicial facets.
+  			   for simplicial facets, neighbors defines ridge */
+  setT    *neighbors;   /* neighbors of the facet.  If simplicial, the kth
+			   neighbor is opposite the kth vertex, and the first
+			   neighbor is the horizon facet for the first vertex*/
+  setT    *outsideset;  /* set of points outside this facet
+		           if non-empty, last point is furthest
+			   if NARROWhull, includes coplanars for partitioning*/
+  setT    *coplanarset; /* set of points coplanar with this facet
+  			   > qh.min_vertex and <= facet->max_outside
+                           a point is assigned to the furthest facet
+		           if non-empty, last point is furthest away */
+  unsigned visitid;     /* visit_id, for visiting all neighbors,
+			   all uses are independent */
+  unsigned id;	        /* unique identifier from qh facet_id */
+  unsigned nummerge:9;  /* number of merges */
+#define qh_MAXnummerge 511 /*     2^9-1, 32 flags total, see "flags:" in io.c */
+  flagT    tricoplanar:1; /* True if TRIangulate and simplicial and coplanar with a neighbor */
+			  /*   all tricoplanars share the same ->center, ->normal, ->offset, ->maxoutside */
+			  /*   all tricoplanars share the same apex */
+                          /*   if ->degenerate, does not span facet (one logical ridge) */
+                          /*   one tricoplanar has ->keepcentrum and ->coplanarset */
+                          /*   during qh_triangulate, f.trivisible points to original facet */
+  flagT	   newfacet:1;  /* True if facet on qh newfacet_list (new or merged) */
+  flagT	   visible:1;   /* True if visible facet (will be deleted) */
+  flagT    toporient:1; /* True if created with top orientation
+			   after merging, use ridge orientation */
+  flagT    simplicial:1;/* True if simplicial facet, ->ridges may be implicit */
+  flagT    seen:1;      /* used to perform operations only once, like visitid */
+  flagT    seen2:1;     /* used to perform operations only once, like visitid */
+  flagT	   flipped:1;   /* True if facet is flipped */
+  flagT    upperdelaunay:1; /* True if facet is upper envelope of Delaunay triangulation */
+  flagT    notfurthest:1; /* True if last point of outsideset is not furthest*/
+
+/*-------- flags primarily for output ---------*/
+  flagT	   good:1;      /* True if a facet marked good for output */
+  flagT    isarea:1;    /* True if facet->f.area is defined */
+
+/*-------- flags for merging ------------------*/
+  flagT    dupridge:1;  /* True if duplicate ridge in facet */
+  flagT    mergeridge:1; /* True if facet or neighbor contains a qh_MERGEridge
+                            ->normal defined (also defined for mergeridge2) */
+  flagT    mergeridge2:1; /* True if neighbor contains a qh_MERGEridge (mark_dupridges */
+  flagT    coplanar:1;  /* True if horizon facet is coplanar at last use */
+  flagT     mergehorizon:1; /* True if will merge into horizon (->coplanar) */
+  flagT	    cycledone:1;/* True if mergecycle_all already done */
+  flagT    tested:1;    /* True if facet convexity has been tested (false after merge */
+  flagT    keepcentrum:1; /* True if keep old centrum after a merge, or marks owner for ->tricoplanar */
+  flagT	   newmerge:1;  /* True if facet is newly merged for reducevertices */
+  flagT	   degenerate:1; /* True if facet is degenerate (degen_mergeset or ->tricoplanar) */
+  flagT	   redundant:1;  /* True if facet is redundant (degen_mergeset) */
+};
+
+
+/*----------------------------------
+
+  ridgeT
+    defines a ridge
+
+  notes:
+  a ridge is DIM3-1 simplex between two neighboring facets.  If the
+  facets are non-simplicial, there may be more than one ridge between
+  two facets.  E.G. a 4-d hypercube has two triangles between each pair
+  of neighboring facets.
+
+  topological information:
+    vertices            a set of vertices
+    top,bottom          neighboring facets with orientation
+
+  geometric information:
+    tested              True if ridge is clearly convex
+    nonconvex           True if ridge is non-convex
+*/
+struct ridgeT {
+  setT    *vertices;    /* vertices belonging to this ridge, inverse sorted by ID 
+                           NULL if a degen ridge (matchsame) */
+  facetT  *top;         /* top facet this ridge is part of */
+  facetT  *bottom;      /* bottom facet this ridge is part of */
+  unsigned id:24;       /* unique identifier, =>room for 8 flags */
+  flagT    seen:1;      /* used to perform operations only once */
+  flagT    tested:1;    /* True when ridge is tested for convexity */
+  flagT    nonconvex:1; /* True if getmergeset detected a non-convex neighbor
+			   only one ridge between neighbors may have nonconvex */
+};
+
+/*----------------------------------
+
+  vertexT
+     defines a vertex
+
+  topological information:
+    next,previous       doubly-linked list of all vertices
+    neighbors           set of adjacent facets (only if qh.VERTEXneighbors)
+
+  geometric information:
+    point               array of DIM3 coordinates
+*/
+struct vertexT {
+  vertexT *next;        /* next vertex in vertex_list */
+  vertexT *previous;    /* previous vertex in vertex_list */
+  pointT  *point;       /* hull_dim coordinates (coordT) */
+  setT    *neighbors;   /* neighboring facets of vertex, qh_vertexneighbors()
+			   inits in io.c or after first merge */
+  unsigned visitid; /* for use with qh vertex_visit */
+  unsigned id:24;   /* unique identifier, =>room for 8 flags */
+  flagT    seen:1;      /* used to perform operations only once */
+  flagT    seen2:1;     /* another seen flag */
+  flagT    delridge:1;  /* vertex was part of a deleted ridge */
+  flagT	   deleted:1;   /* true if vertex on qh del_vertices */
+  flagT    newlist:1;   /* true if vertex on qh newvertex_list */
+};
+
+/*======= -global variables -qh ============================*/
+
+/*----------------------------------
+
+  qh
+   all global variables for qhull are in qh, qhmem, and qhstat
+
+  notes:
+   qhmem is defined in mem.h and qhstat is defined in stat.h
+   access to qh_qh is via the "qh" macro.  See qh_QHpointer in user.h
+*/
+typedef struct qhT qhT;
+#if qh_QHpointer
+#define qh qh_qh->
+extern qhT *qh_qh;     /* allocated in global.c */
+#else
+#define qh qh_qh.
+extern qhT qh_qh;
+#endif
+
+struct qhT {
+
+/*----------------------------------
+
+  qh constants
+    configuration flags and constants for Qhull
+
+  notes:
+    The user configures Qhull by defining flags.  They are
+    copied into qh by qh_setflags().  qh-quick.htm#options defines the flags.
+*/
+  boolT ALLpoints;        /* true 'Qs' if search all points for initial simplex */
+  boolT ANGLEmerge;	  /* true 'Qa' if sort potential merges by angle */
+  boolT APPROXhull;       /* true 'Wn' if MINoutside set */
+  realT MINoutside;       /*   'Wn' min. distance for an outside point */
+  boolT ATinfinity;       /* true 'Qz' if point num_points-1 is "at-infinity"
+                             for improving precision in Delaunay triangulations */
+  boolT AVOIDold;         /* true 'Q4' if avoid old->new merges */
+  boolT BESToutside;      /* true 'Qf' if partition points into best outsideset */
+  boolT CDDinput;         /* true 'Pc' if input uses CDD format (1.0/offset first) */
+  boolT CDDoutput;        /* true 'PC' if print normals in CDD format (offset first) */
+  boolT CHECKfrequently;  /* true 'Tc' if checking frequently */
+  realT premerge_cos;     /*   'A-n'   cos_max when pre merging */
+  realT postmerge_cos;    /*   'An'    cos_max when post merging */
+  boolT DELAUNAY;         /* true 'd' if computing DELAUNAY triangulation */
+  boolT DOintersections;  /* true 'Gh' if print hyperplane intersections */
+  int   DROPdim;          /* drops dim 'GDn' for 4-d -> 3-d output */
+  boolT FORCEoutput;      /* true 'Po' if forcing output despite degeneracies */
+  int   GOODpoint;        /* 1+n for 'QGn', good facet if visible/not(-) from point n*/
+  pointT *GOODpointp;     /*   the actual point */
+  boolT GOODthreshold;    /* true if qh lower_threshold/upper_threshold defined
+  			     false if qh SPLITthreshold */
+  int   GOODvertex;       /* 1+n, good facet if vertex for point n */
+  pointT *GOODvertexp;     /*   the actual point */
+  boolT HALFspace;        /* true 'Hn,n,n' if halfspace intersection */
+  int   IStracing;        /* trace execution, 0=none, 1=least, 4=most, -1=events */
+  int   KEEParea;         /* 'PAn' number of largest facets to keep */
+  boolT KEEPcoplanar;     /* true 'Qc' if keeping nearest facet for coplanar points */
+  boolT KEEPinside;       /* true 'Qi' if keeping nearest facet for inside points
+			      set automatically if 'd Qc' */
+  int   KEEPmerge;        /* 'PMn' number of facets to keep with most merges */
+  realT KEEPminArea;      /* 'PFn' minimum facet area to keep */
+  realT MAXcoplanar;      /* 'Un' max distance below a facet to be coplanar*/
+  boolT MERGEexact;	  /* true 'Qx' if exact merges (coplanar, degen, dupridge, flipped) */
+  boolT MERGEindependent; /* true 'Q2' if merging independent sets */
+  boolT MERGING;          /* true if exact-, pre- or post-merging, with angle and centrum tests */
+  realT   premerge_centrum;  /*   'C-n' centrum_radius when pre merging.  Default is round-off */
+  realT   postmerge_centrum; /*   'Cn' centrum_radius when post merging.  Default is round-off */
+  boolT MERGEvertices;	  /* true 'Q3' if merging redundant vertices */
+  realT MINvisible;       /* 'Vn' min. distance for a facet to be visible */
+  boolT NOnarrow;         /* true 'Q10' if no special processing for narrow distributions */
+  boolT NOnearinside;     /* true 'Q8' if ignore near-inside points when partitioning */
+  boolT NOpremerge;       /* true 'Q0' if no defaults for C-0 or Qx */
+  boolT ONLYgood; 	  /* true 'Qg' if process points with good visible or horizon facets */
+  boolT ONLYmax; 	  /* true 'Qm' if only process points that increase max_outside */
+  boolT PICKfurthest;     /* true 'Q9' if process furthest of furthest points*/
+  boolT POSTmerge;        /* true if merging after buildhull (Cn or An) */
+  boolT PREmerge;         /* true if merging during buildhull (C-n or A-n) */
+  			/* NOTE: some of these names are similar to qh_PRINT names */
+  boolT PRINTcentrums;	  /* true 'Gc' if printing centrums */
+  boolT PRINTcoplanar;    /* true 'Gp' if printing coplanar points */
+  int	PRINTdim;      	  /* print dimension for Geomview output */
+  boolT PRINTdots;        /* true 'Ga' if printing all points as dots */
+  boolT PRINTgood;        /* true 'Pg' if printing good facets */
+  boolT PRINTinner;	  /* true 'Gi' if printing inner planes */
+  boolT PRINTneighbors;	  /* true 'PG' if printing neighbors of good facets */
+  boolT PRINTnoplanes;	  /* true 'Gn' if printing no planes */
+  boolT PRINToptions1st;  /* true 'FO' if printing options to stderr */
+  boolT PRINTouter;	  /* true 'Go' if printing outer planes */
+  boolT PRINTprecision;   /* false 'Pp' if not reporting precision problems */
+  qh_PRINT PRINTout[qh_PRINTEND]; /* list of output formats to print */
+  boolT PRINTridges;      /* true 'Gr' if print ridges */
+  boolT PRINTspheres;     /* true 'Gv' if print vertices as spheres */
+  boolT PRINTstatistics;  /* true 'Ts' if printing statistics to stderr */
+  boolT PRINTsummary;     /* true 's' if printing summary to stderr */
+  boolT PRINTtransparent; /* true 'Gt' if print transparent outer ridges */
+  boolT PROJECTdelaunay;  /* true if DELAUNAY, no readpoints() and
+			     need projectinput() for Delaunay in qh_init_B */
+  int   PROJECTinput;     /* number of projected dimensions 'bn:0Bn:0' */
+  boolT QUICKhelp;	  /* true if quick help message for degen input */
+  boolT RANDOMdist;       /* true if randomly change distplane and setfacetplane */
+  realT RANDOMfactor;     /*    maximum random perturbation */
+  realT RANDOMa;         /*  qh_randomfactor is randr * RANDOMa + RANDOMb */
+  realT RANDOMb;
+  boolT RANDOMoutside;    /* true if select a random outside point */
+  int	REPORTfreq;       /* buildtracing reports every n facets */
+  int   REPORTfreq2;	  /* tracemerging reports every REPORTfreq/2 facets */
+  int	RERUN;            /* 'TRn' rerun qhull n times (qh.build_cnt) */
+  int	ROTATErandom;	  /* 'QRn' seed, 0 time, >= rotate input */
+  boolT SCALEinput;       /* true 'Qbk' if scaling input */
+  boolT SCALElast;        /* true 'Qbb' if scale last coord to max prev coord */
+  boolT SETroundoff;      /* true 'E' if qh DISTround is predefined */
+  boolT SKIPcheckmax;	  /* true 'Q5' if skip qh_check_maxout */
+  boolT SKIPconvex;       /* true 'Q6' if skip convexity testing during pre-merge */
+  boolT SPLITthresholds;  /* true if upper_/lower_threshold defines a region
+                               used only for printing (not for qh ONLYgood) */
+  int	STOPcone;         /* 'TCn' 1+n for stopping after cone for point n*/
+			  /*       also used by qh_build_withresart for err exit*/
+  int	STOPpoint;        /* 'TVn' 'TV-n' 1+n for stopping after/before(-)
+			                adding point n */
+  int	TESTpoints;	  /* 'QTn' num of test points after qh.num_points.  Test points always coplanar. */
+  boolT TESTvneighbors;   /*  true 'Qv' if test vertex neighbors at end */
+  int   TRACElevel;       /* 'Tn' conditional IStracing level */
+  int	TRACElastrun;	  /*  qh.TRACElevel applies to last qh.RERUN */
+  int   TRACEpoint;       /* 'TPn' start tracing when point n is a vertex */
+  realT TRACEdist;        /* 'TWn' start tracing when merge distance too big */
+  int   TRACEmerge;       /* 'TMn' start tracing before this merge */
+  boolT TRIangulate;	  /* true 'Qt' if triangulate non-simplicial facets */
+  boolT TRInormals;	  /* true 'Q11' if triangulate duplicates normals (sets Qt) */
+  boolT UPPERdelaunay;    /* true 'Qu' if computing furthest-site Delaunay */
+  boolT VERIFYoutput;     /* true 'Tv' if verify output at end of qhull */
+  boolT VIRTUALmemory;    /* true 'Q7' if depth-first processing in buildhull */
+  boolT VORONOI;	  /* true 'v' if computing Voronoi diagram */
+
+  /*--------input constants ---------*/
+  realT AREAfactor;       /* 1/(hull_dim-1)! for converting det's to area */
+  boolT DOcheckmax;       /* true if calling qh_check_maxout (qh_initqhull_globals) */
+  char	*feasible_string;  /* feasible point 'Hn,n,n' for halfspace intersection */
+  coordT *feasible_point;  /*    as coordinates, both malloc'd */
+  boolT GETarea;          /* true 'Fa', 'FA', 'FS', 'PAn', 'PFn' if compute facet area/Voronoi volume in io.c */
+  boolT KEEPnearinside;   /* true if near-inside points in coplanarset */
+  int 	hull_dim;         /* dimension of hull, set by initbuffers */
+  int 	input_dim;	  /* dimension of input, set by initbuffers */
+  int 	num_points;       /* number of input points */
+  pointT *first_point;    /* array of input points, see POINTSmalloc */
+  boolT POINTSmalloc;     /*   true if qh first_point/num_points allocated */
+  pointT *input_points;   /* copy of original qh.first_point for input points for qh_joggleinput */
+  boolT input_malloc;     /* true if qh input_points malloc'd */
+  char 	qhull_command[256];/* command line that invoked this program */
+  char 	rbox_command[256]; /* command line that produced the input points */
+  char  qhull_options[512];/* descriptive list of options */
+  int   qhull_optionlen;  /*    length of last line */
+  int   qhull_optionsiz;  /*     size of qhull_options before qh_initbuild */
+  boolT VERTEXneighbors;  /* true if maintaining vertex neighbors */
+  boolT ZEROcentrum;      /* true if 'C-0' or 'C-0 Qx'.  sets ZEROall_ok */
+  realT *upper_threshold; /* don't print if facet->normal[k]>=upper_threshold[k]
+                             must set either GOODthreshold or SPLITthreshold
+  			     if Delaunay, default is 0.0 for upper envelope */
+  realT *lower_threshold; /* don't print if facet->normal[k] <=lower_threshold[k] */
+  realT *upper_bound;     /* scale point[k] to new upper bound */
+  realT *lower_bound;     /* scale point[k] to new lower bound
+  			     project if both upper_ and lower_bound == 0 */
+
+/*----------------------------------
+
+  qh precision constants
+    precision constants for Qhull
+
+  notes:
+    qh_detroundoff() computes the maximum roundoff error for distance
+    and other computations.  It also sets default values for the
+    qh constants above.
+*/
+  realT ANGLEround;       /* max round off error for angles */
+  realT centrum_radius;   /* max centrum radius for convexity (roundoff added) */
+  realT cos_max;	  /* max cosine for convexity (roundoff added) */
+  realT DISTround;        /* max round off error for distances, 'E' overrides */
+  realT MAXabs_coord;     /* max absolute coordinate */
+  realT MAXlastcoord;     /* max last coordinate for qh_scalelast */
+  realT MAXsumcoord;      /* max sum of coordinates */
+  realT MAXwidth;         /* max rectilinear width of point coordinates */
+  realT MINdenom_1;       /* min. abs. value for 1/x */
+  realT MINdenom;         /*    use divzero if denominator < MINdenom */
+  realT MINdenom_1_2;     /* min. abs. val for 1/x that allows normalization */
+  realT MINdenom_2;       /*    use divzero if denominator < MINdenom_2 */
+  realT MINlastcoord;     /* min. last coordinate for qh_scalelast */
+  boolT NARROWhull;       /* set in qh_initialhull if angle < qh_MAXnarrow */
+  realT *NEARzero;        /* hull_dim array for near zero in gausselim */
+  realT NEARinside;       /* keep points for qh_check_maxout if close to facet */
+  realT ONEmerge;         /* max distance for merging simplicial facets */
+  realT outside_err;      /* application's epsilon for coplanar points
+                             qh_check_bestdist() qh_check_points() reports error if point outside */
+  realT WIDEfacet;        /* size of wide facet for skipping ridge in
+			     area computation and locking centrum */
+  
+/*----------------------------------
+
+  qh internal constants
+    internal constants for Qhull
+*/
+  char qhull[sizeof("qhull")]; /* for checking ownership */
+  void *old_stat;         /* pointer to saved qh_qhstat, qh_save_qhull */
+  jmp_buf errexit;        /* exit label for qh_errexit, defined by setjmp() */
+  char jmpXtra[40];       /* extra bytes in case jmp_buf is defined wrong by compiler */
+  jmp_buf restartexit;    /* restart label for qh_errexit, defined by setjmp() */
+  char jmpXtra2[40];      /* extra bytes in case jmp_buf is defined wrong by compiler*/
+  FILE *fin;              /* pointer to input file, init by qh_meminit */
+  FILE *fout;             /* pointer to output file */
+  FILE *ferr;             /* pointer to error file */
+  pointT *interior_point; /* center point of the initial simplex*/
+  int   normal_size;      /* size in bytes for facet normals and point coords*/
+  int   center_size;      /* size in bytes for Voronoi centers */
+  int   TEMPsize;         /* size for small, temporary sets (in quick mem) */
+
+/*----------------------------------
+
+  qh facet and vertex lists
+    defines lists of facets, new facets, visible facets, vertices, and
+    new vertices.  Includes counts, next ids, and trace ids.
+  see:
+    qh_resetlists()
+*/
+  facetT *facet_list;     /* first facet */
+  facetT  *facet_tail;     /* end of facet_list (dummy facet) */
+  facetT *facet_next;     /* next facet for buildhull()
+    			     previous facets do not have outside sets
+                             NARROWhull: previous facets may have coplanar outside sets for qh_outcoplanar */
+  facetT *newfacet_list;  /* list of new facets to end of facet_list */
+  facetT *visible_list;   /* list of visible facets preceeding newfacet_list,
+                             facet->visible set */
+  int       num_visible;  /* current number of visible facets */
+  unsigned tracefacet_id;  /* set at init, then can print whenever */
+  facetT *tracefacet;     /*   set in newfacet/mergefacet, undone in delfacet*/
+  unsigned tracevertex_id;  /* set at buildtracing, can print whenever */
+  vertexT *tracevertex;     /*   set in newvertex, undone in delvertex*/
+  vertexT *vertex_list;     /* list of all vertices, to vertex_tail */
+  vertexT  *vertex_tail;    /*      end of vertex_list (dummy vertex) */
+  vertexT *newvertex_list; /* list of vertices in newfacet_list, to vertex_tail
+                             all vertices have 'newlist' set */
+  int 	num_facets;	  /* number of facets in facet_list
+			     includes visble faces (num_visible) */
+  int 	num_vertices;     /* number of vertices in facet_list */
+  int   num_outside;      /* number of points in outsidesets (for tracing and RANDOMoutside)
+                               includes coplanar outsideset points for NARROWhull/qh_outcoplanar() */
+  int   num_good;         /* number of good facets (after findgood_all) */
+  unsigned facet_id;      /* ID of next, new facet from newfacet() */
+  unsigned ridge_id;      /* ID of next, new ridge from newridge() */
+  unsigned vertex_id;     /* ID of next, new vertex from newvertex() */
+
+/*----------------------------------
+
+  qh global variables
+    defines minimum and maximum distances, next visit ids, several flags,
+    and other global variables.
+    initialize in qh_initbuild or qh_maxmin if used in qh_buildhull
+*/
+  unsigned long hulltime; /* ignore time to set up input and randomize */
+                          /*   use unsigned to avoid wrap-around errors */
+  boolT ALLOWrestart;     /* true if qh_precision can use qh.restartexit */
+  int   build_cnt;        /* number of calls to qh_initbuild */
+  qh_CENTER CENTERtype;   /* current type of facet->center, qh_CENTER */
+  int 	furthest_id;      /* pointid of furthest point, for tracing */
+  facetT *GOODclosest;    /* closest facet to GOODthreshold in qh_findgood */
+  realT JOGGLEmax;        /* set 'QJn' if randomly joggle input */
+  boolT maxoutdone;       /* set qh_check_maxout(), cleared by qh_addpoint() */
+  realT max_outside;      /* maximum distance from a point to a facet,
+			       before roundoff, not simplicial vertices
+			       actual outer plane is +DISTround and
+			       computed outer plane is +2*DISTround */
+  realT max_vertex;       /* maximum distance (>0) from vertex to a facet,
+			       before roundoff, due to a merge */
+  realT min_vertex;       /* minimum distance (<0) from vertex to a facet,
+			       before roundoff, due to a merge
+			       if qh.JOGGLEmax, qh_makenewplanes sets it
+  			       recomputed if qh.DOcheckmax, default -qh.DISTround */
+  boolT NEWfacets;        /* true while visible facets invalid due to new or merge
+			      from makecone/attachnewfacets to deletevisible */
+  boolT findbestnew;	  /* true if partitioning calls qh_findbestnew */
+  boolT findbest_notsharp; /* true if new facets are at least 90 degrees */
+  boolT NOerrexit;        /* true if qh.errexit is not available */
+  realT PRINTcradius;     /* radius for printing centrums */
+  realT PRINTradius;      /* radius for printing vertex spheres and points */
+  boolT POSTmerging;      /* true when post merging */
+  int 	printoutvar;	  /* temporary variable for qh_printbegin, etc. */
+  int 	printoutnum;	  /* number of facets printed */
+  boolT QHULLfinished;    /* True after qhull() is finished */
+  realT totarea;          /* 'FA': total facet area computed by qh_getarea */
+  realT totvol;           /* 'FA': total volume computed by qh_getarea */
+  unsigned int visit_id;  /* unique ID for searching neighborhoods, */
+  unsigned int vertex_visit; /* unique ID for searching vertices */
+  boolT ZEROall_ok;       /* True if qh_checkzero always succeeds */
+  boolT WAScoplanar;      /* True if qh_partitioncoplanar (qh_check_maxout) */
+  
+/*----------------------------------
+
+  qh global sets
+    defines sets for merging, initial simplex, hashing, extra input points,
+    and deleted vertices
+*/
+  setT *facet_mergeset;   /* temporary set of merges to be done */
+  setT *degen_mergeset;   /* temporary set of degenerate and redundant merges */
+  setT *hash_table;	  /* hash table for matching ridges in qh_matchfacets
+                             size is setsize() */
+  setT *other_points;     /* additional points (first is qh interior_point) */
+  setT *del_vertices;     /* vertices to partition and delete with visible
+                             facets.  Have deleted set for checkfacet */
+
+/*----------------------------------
+
+  qh global buffers
+    defines buffers for maxtrix operations, input, and error messages
+*/
+  coordT *gm_matrix;      /* (dim+1)Xdim matrix for geom.c */
+  coordT **gm_row;        /* array of gm_matrix rows */
+  char* line;             /* malloc'd input line of maxline+1 chars */
+  int maxline;
+  coordT *half_space;     /* malloc'd input array for halfspace (qh normal_size+coordT) */
+  coordT *temp_malloc;    /* malloc'd input array for points */
+  
+/*----------------------------------
+
+  qh static variables
+    defines static variables for individual functions
+
+  notes:
+    do not use 'static' within a function.  Multiple instances of qhull
+    may exist.
+
+    do not assume zero initialization, 'QPn' may cause a restart
+*/
+  boolT ERREXITcalled;    /* true during errexit (prevents duplicate calls */
+  boolT firstcentrum; 	  /* for qh_printcentrum */
+  realT last_low;         /* qh_scalelast parameters for qh_setdelaunay */
+  realT last_high;
+  realT last_newhigh;
+  unsigned lastreport;    /* for qh_buildtracing */
+  int mergereport;        /* for qh_tracemerging */
+  boolT old_randomdist;   /* save RANDOMdist when io, tracing, or statistics */
+  int   ridgeoutnum;      /* number of ridges in 4OFF output */
+  void *old_qhstat;       /* for saving qh_qhstat in save_qhull() */
+  setT *old_tempstack;     /* for saving qhmem.tempstack in save_qhull */
+  setT *coplanarset;      /* set of coplanar facets for searching qh_findbesthorizon() */
+};
+
+/*=========== -macros- =========================*/
+
+/*----------------------------------
+
+  otherfacet_(ridge, facet)
+    return neighboring facet for a ridge in facet
+*/
+#define otherfacet_(ridge, facet) \
+                        (((ridge)->top == (facet)) ? (ridge)->bottom : (ridge)->top)
+
+/*----------------------------------
+
+  getid_(p)
+    return ID for facet, ridge, or vertex
+    return MAXINT if NULL (-1 causes type conversion error )
+*/
+#define getid_(p)       ((p) ? (p)->id : -1)
+
+/*============== FORALL macros ===================*/
+
+/*----------------------------------
+
+  FORALLfacets { ... }
+    assign 'facet' to each facet in qh.facet_list
+
+  notes:
+    uses 'facetT *facet;'
+    assumes last facet is a sentinel
+
+  see:
+    FORALLfacet_( facetlist )
+*/
+#define FORALLfacets for (facet=qh facet_list;facet && facet->next;facet=facet->next)
+
+/*----------------------------------
+
+  FORALLpoints { ... }
+    assign 'point' to each point in qh.first_point, qh.num_points
+
+  declare:
+    coordT *point, *pointtemp;
+*/
+#define FORALLpoints FORALLpoint_(qh first_point, qh num_points)
+
+/*----------------------------------
+
+  FORALLpoint_( points, num) { ... }
+    assign 'point' to each point in points array of num points
+
+  declare:
+    coordT *point, *pointtemp;
+*/
+#define FORALLpoint_(points, num) for(point= (points), \
+      pointtemp= (points)+qh hull_dim*(num); point < pointtemp; point += qh hull_dim)
+
+/*----------------------------------
+
+  FORALLvertices { ... }
+    assign 'vertex' to each vertex in qh.vertex_list
+
+  declare:
+    vertexT *vertex;
+
+  notes:
+    assumes qh.vertex_list terminated with a sentinel
+*/
+#define FORALLvertices for (vertex=qh vertex_list;vertex && vertex->next;vertex= vertex->next)
+
+/*----------------------------------
+
+  FOREACHfacet_( facets ) { ... }
+    assign 'facet' to each facet in facets
+
+  declare:
+    facetT *facet, **facetp;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHfacet_(facets)    FOREACHsetelement_(facetT, facets, facet)
+
+/*----------------------------------
+
+  FOREACHneighbor_( facet ) { ... }
+    assign 'neighbor' to each neighbor in facet->neighbors
+
+  FOREACHneighbor_( vertex ) { ... }
+    assign 'neighbor' to each neighbor in vertex->neighbors
+
+  declare:
+    facetT *neighbor, **neighborp;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHneighbor_(facet)  FOREACHsetelement_(facetT, facet->neighbors, neighbor)
+
+/*----------------------------------
+
+  FOREACHpoint_( points ) { ... }
+    assign 'point' to each point in points set
+
+  declare:
+    pointT *point, **pointp;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHpoint_(points)    FOREACHsetelement_(pointT, points, point)
+
+/*----------------------------------
+
+  FOREACHridge_( ridges ) { ... }
+    assign 'ridge' to each ridge in ridges set
+
+  declare:
+    ridgeT *ridge, **ridgep;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHridge_(ridges)    FOREACHsetelement_(ridgeT, ridges, ridge)
+
+/*----------------------------------
+
+  FOREACHvertex_( vertices ) { ... }
+    assign 'vertex' to each vertex in vertices set
+
+  declare:
+    vertexT *vertex, **vertexp;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHvertex_(vertices) FOREACHsetelement_(vertexT, vertices,vertex)
+
+/*----------------------------------
+
+  FOREACHfacet_i_( facets ) { ... }
+    assign 'facet' and 'facet_i' for each facet in facets set
+
+  declare:
+    facetT *facet;
+    int     facet_n, facet_i;
+
+  see:
+    FOREACHsetelement_i_
+*/
+#define FOREACHfacet_i_(facets)    FOREACHsetelement_i_(facetT, facets, facet)
+
+/*----------------------------------
+
+  FOREACHneighbor_i_( facet ) { ... }
+    assign 'neighbor' and 'neighbor_i' for each neighbor in facet->neighbors
+
+  FOREACHneighbor_i_( vertex ) { ... }
+    assign 'neighbor' and 'neighbor_i' for each neighbor in vertex->neighbors
+
+  declare:
+    facetT *neighbor;
+    int     neighbor_n, neighbor_i;
+
+  see:
+    FOREACHsetelement_i_
+*/
+#define FOREACHneighbor_i_(facet)  FOREACHsetelement_i_(facetT, facet->neighbors, neighbor)
+
+/*----------------------------------
+
+  FOREACHpoint_i_( points ) { ... }
+    assign 'point' and 'point_i' for each point in points set
+
+  declare:
+    pointT *point;
+    int     point_n, point_i;
+
+  see:
+    FOREACHsetelement_i_
+*/
+#define FOREACHpoint_i_(points)    FOREACHsetelement_i_(pointT, points, point)
+
+/*----------------------------------
+
+  FOREACHridge_i_( ridges ) { ... }
+    assign 'ridge' and 'ridge_i' for each ridge in ridges set
+
+  declare:
+    ridgeT *ridge;
+    int     ridge_n, ridge_i;
+
+  see:
+    FOREACHsetelement_i_
+*/
+#define FOREACHridge_i_(ridges)    FOREACHsetelement_i_(ridgeT, ridges, ridge)
+
+/*----------------------------------
+
+  FOREACHvertex_i_( vertices ) { ... }
+    assign 'vertex' and 'vertex_i' for each vertex in vertices set
+
+  declare:
+    vertexT *vertex;
+    int     vertex_n, vertex_i;
+
+  see:
+    FOREACHsetelement_i_
+ */
+#define FOREACHvertex_i_(vertices) FOREACHsetelement_i_(vertexT, vertices,vertex)
+
+/********* -qhull.c prototypes (duplicated from qhull_a.h) **********************/
+
+void    qh_qhull (void);
+boolT   qh_addpoint (pointT *furthest, facetT *facet, boolT checkdist);
+void	qh_printsummary(FILE *fp);
+
+/********* -user.c prototypes (alphabetical) **********************/
+
+void 	qh_errexit(int exitcode, facetT *facet, ridgeT *ridge);
+void 	qh_errprint(char* string, facetT *atfacet, facetT *otherfacet, ridgeT *atridge, vertexT *atvertex);
+int     qh_new_qhull (int dim, int numpoints, coordT *points, boolT ismalloc,
+		char *qhull_cmd, FILE *outfile, FILE *errfile);
+void    qh_printfacetlist(facetT *facetlist, setT *facets, boolT printall);
+void 	qh_user_memsizes (void);
+
+/***** -geom.c/geom2.c prototypes (duplicated from geom.h) ****************/
+
+facetT *qh_findbest (pointT *point, facetT *startfacet,
+		     boolT bestoutside, boolT newfacets, boolT noupper,
+		     realT *dist, boolT *isoutside, int *numpart);
+facetT *qh_findbestnew (pointT *point, facetT *startfacet,
+                     realT *dist, boolT bestoutside, boolT *isoutside, int *numpart);
+boolT   qh_gram_schmidt(int dim, realT **rows);
+void    qh_outerinner (facetT *facet, realT *outerplane, realT *innerplane);
+void	qh_printsummary(FILE *fp);
+void    qh_projectinput (void);
+void    qh_randommatrix (realT *buffer, int dim, realT **row);
+void    qh_rotateinput (realT **rows);
+void    qh_scaleinput (void);
+void    qh_setdelaunay (int dim, int count, pointT *points);
+coordT  *qh_sethalfspace_all (int dim, int count, coordT *halfspaces, pointT *feasible);
+
+/***** -global.c prototypes (alphabetical) ***********************/
+
+unsigned long qh_clock (void);
+void 	qh_checkflags (char *command, char *hiddenflags);
+void 	qh_freebuffers (void);
+void    qh_freeqhull (boolT allmem);
+void    qh_init_A (FILE *infile, FILE *outfile, FILE *errfile, int argc, char *argv[]);
+void    qh_init_B (coordT *points, int numpoints, int dim, boolT ismalloc);
+void 	qh_init_qhull_command (int argc, char *argv[]);
+void    qh_initbuffers (coordT *points, int numpoints, int dim, boolT ismalloc);
+void 	qh_initflags (char *command);
+void 	qh_initqhull_buffers (void);
+void 	qh_initqhull_globals (coordT *points, int numpoints, int dim, boolT ismalloc);
+void    qh_initqhull_mem (void);
+void 	qh_initqhull_start (FILE *infile, FILE *outfile, FILE *errfile);
+void 	qh_initthresholds (char *command);
+void    qh_option (char *option, int *i, realT *r);
+#if qh_QHpointer
+void 	qh_restore_qhull (qhT **oldqh);
+qhT    *qh_save_qhull (void);
+#endif
+
+/***** -io.c prototypes (duplicated from io.h) ***********************/
+
+void    dfacet( unsigned id);
+void    dvertex( unsigned id);
+void	qh_printneighborhood (FILE *fp, int format, facetT *facetA, facetT *facetB, boolT printall);
+void	qh_produce_output(void);
+coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc);
+
+
+/********* -mem.c prototypes (duplicated from mem.h) **********************/
+
+void qh_meminit (FILE *ferr);
+void qh_memfreeshort (int *curlong, int *totlong);
+
+/********* -poly.c/poly2.c prototypes (duplicated from poly.h) **********************/
+
+void    qh_check_output (void);
+void    qh_check_points (void);
+setT   *qh_facetvertices (facetT *facetlist, setT *facets, boolT allfacets);
+facetT *qh_findbestfacet (pointT *point, boolT bestoutside,
+           realT *bestdist, boolT *isoutside);
+vertexT *qh_nearvertex (facetT *facet, pointT *point, realT *bestdistp);
+pointT *qh_point (int id);
+setT   *qh_pointfacet (void /*qh.facet_list*/);
+int     qh_pointid (pointT *point);
+setT   *qh_pointvertex (void /*qh.facet_list*/);
+void    qh_setvoronoi_all (void);
+void	qh_triangulate (void /*qh facet_list*/);
+
+/********* -stat.c prototypes (duplicated from stat.h) **********************/
+
+void    qh_collectstatistics (void);
+void    qh_printallstatistics (FILE *fp, char *string);
+
+#endif /* qhDEFqhull */
diff --git a/extern/qhull/src/qhull_a.h b/extern/qhull/src/qhull_a.h
new file mode 100644
index 00000000000..d4e69b071be
--- /dev/null
+++ b/extern/qhull/src/qhull_a.h
@@ -0,0 +1,127 @@
+/*
  ---------------------------------
+
+   qhull_a.h 
+   all header files for compiling qhull
+
+   see qh-qhull.htm
+
+   see qhull.h for user-level definitions
+   
+   see user.h for user-defineable constants
+   
+   defines internal functions for qhull.c global.c
+
+   copyright (c) 1993-2002, The Geometry Center
+
+   Notes:  grep for ((" and (" to catch fprintf("lkasdjf");
+           full parens around (x?y:z)
+	   use '#include qhull/qhull_a.h' to avoid name clashes
+*/
+
+#ifndef qhDEFqhulla
+#define qhDEFqhulla
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include     /* some compilers will not need float.h */
+#include 
+#include 
+#include 
+/*** uncomment here and qset.c
+     if string.h does not define memcpy()
+#include 
+*/
+#include "qhull.h"
+#include "mem.h"
+#include "qset.h"
+#include "geom.h"
+#include "merge.h"
+#include "poly.h"
+#include "io.h"
+#include "stat.h"
+
+#if qh_CLOCKtype == 2  /* defined in user.h from qhull.h */
+#include 
+#include 
+#include 
+#endif
+
+#ifdef _MSC_VER  /* Microsoft Visual C++ */
+#pragma warning( disable : 4056)  /* float constant expression.  Looks like a compiler bug */
+#pragma warning( disable : 4146)  /* unary minus applied to unsigned type */
+#pragma warning( disable : 4244)  /* conversion from 'unsigned long' to 'real' */
+#pragma warning( disable : 4305)  /* conversion from 'const double' to 'float' */
+#endif
+
+/* ======= -macros- =========== */
+
+/*----------------------------------
+  
+  traceN((fp.ferr, "format\n", vars));  
+    calls fprintf if qh.IStracing >= N
+  
+  notes:
+    removing tracing reduces code size but doesn't change execution speed
+*/
+#ifndef qh_NOtrace
+#define trace0(args) {if (qh IStracing) fprintf args;}
+#define trace1(args) {if (qh IStracing >= 1) fprintf args;}
+#define trace2(args) {if (qh IStracing >= 2) fprintf args;}
+#define trace3(args) {if (qh IStracing >= 3) fprintf args;}
+#define trace4(args) {if (qh IStracing >= 4) fprintf args;}
+#define trace5(args) {if (qh IStracing >= 5) fprintf args;}
+#else /* qh_NOtrace */
+#define trace0(args) {}
+#define trace1(args) {}
+#define trace2(args) {}
+#define trace3(args) {}
+#define trace4(args) {}
+#define trace5(args) {}
+#endif /* qh_NOtrace */
+
+/***** -qhull.c prototypes (alphabetical after qhull) ********************/
+
+void 	qh_qhull (void);
+boolT   qh_addpoint (pointT *furthest, facetT *facet, boolT checkdist);
+void 	qh_buildhull(void);
+void    qh_buildtracing (pointT *furthest, facetT *facet);
+void    qh_build_withrestart (void);
+void 	qh_errexit2(int exitcode, facetT *facet, facetT *otherfacet);
+void    qh_findhorizon(pointT *point, facetT *facet, int *goodvisible,int *goodhorizon);
+pointT *qh_nextfurthest (facetT **visible);
+void 	qh_partitionall(setT *vertices, pointT *points,int npoints);
+void    qh_partitioncoplanar (pointT *point, facetT *facet, realT *dist);
+void    qh_partitionpoint (pointT *point, facetT *facet);
+void 	qh_partitionvisible(boolT allpoints, int *numpoints);
+void    qh_precision (char *reason);
+void	qh_printsummary(FILE *fp);
+
+/***** -global.c internal prototypes (alphabetical) ***********************/
+
+void    qh_appendprint (qh_PRINT format);
+void 	qh_freebuild (boolT allmem);
+void 	qh_freebuffers (void);
+void    qh_initbuffers (coordT *points, int numpoints, int dim, boolT ismalloc);
+int     qh_strtol (const char *s, char **endp);
+double  qh_strtod (const char *s, char **endp);
+
+/***** -stat.c internal prototypes (alphabetical) ***********************/
+
+void	qh_allstatA (void);
+void	qh_allstatB (void);
+void	qh_allstatC (void);
+void	qh_allstatD (void);
+void	qh_allstatE (void);
+void	qh_allstatE2 (void);
+void	qh_allstatF (void);
+void	qh_allstatG (void);
+void	qh_allstatH (void);
+void 	qh_freebuffers (void);
+void    qh_initbuffers (coordT *points, int numpoints, int dim, boolT ismalloc);
+
+#endif /* qhDEFqhulla */
diff --git a/extern/qhull/src/qhull_interface.cpp b/extern/qhull/src/qhull_interface.cpp
new file mode 100644
index 00000000000..6ecc640e82b
--- /dev/null
+++ b/extern/qhull/src/qhull_interface.cpp
@@ -0,0 +1,96 @@
+/*
  ---------------------------------
+*/
+
+#include 
+#include 
+
+//--- Include qhull, so it works from with in a C++ source file
+//---
+//--- In MVC one cannot just do:
+//---
+//---    extern "C"
+//---    {
+//---      #include "qhull_a.h"
+//---    }
+//---
+//--- Because qhull_a.h includes math.h, which can not appear
+//--- inside a extern "C" declaration.
+//---
+//--- Maybe that why Numerical recipes in C avoid this problem, by removing
+//--- standard include headers from its header files and add them in the
+//--- respective source files instead.
+//---
+//--- [K. Erleben]
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#if defined(__cplusplus)
+}
+#endif
+
+/*********************************************************************/
+/*                                                                   */
+/*                                                                   */
+/*                                                                   */
+/*                                                                   */
+/*********************************************************************/
+
+void compute_convex_hull(void)
+{  
+	int dim;  	              /* dimension of points */
+	int numpoints;            /* number of points */
+	coordT *points;           /* array of coordinates for each point */ 
+	boolT ismalloc;           /* True if qhull should free points in qh_freeqhull() or reallocation */ 
+	char flags[]= "qhull Tv"; /* option flags for qhull, see qh_opt.htm */
+	FILE *outfile= stdout;    /* output from qh_produce_output()			
+	                             use NULL to skip qh_produce_output() */ 
+	FILE *errfile= stderr;    /* error messages from qhull code */ 
+	int exitcode;             /* 0 if no error from qhull */
+	facetT *facet;	          /* set by FORALLfacets */
+	int curlong, totlong;	  /* memory remaining after qh_memfreeshort */
+
+   	/* initialize dim, numpoints, points[], ismalloc here */
+	exitcode= qh_new_qhull (dim, numpoints, points, ismalloc,
+							flags, outfile, errfile);
+	if (!exitcode) { /* if no error */ 
+		/* 'qh facet_list' contains the convex hull */
+		FORALLfacets {
+			/* ... your code ... */ 
+		}
+	}
+	qh_freeqhull(!qh_ALL);  
+	qh_memfreeshort (&curlong, &totlong);
+	if (curlong || totlong)
+		fprintf (errfile, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n", 
+		             totlong, curlong);
+};
+
+/*********************************************************************/
+/*                                                                   */
+/*                                                                   */
+/*                                                                   */
+/*                                                                   */
+/*********************************************************************/
+
+void main() 
+{ 
+	cout << "Hello world" << endl;
+	
+	cout << "Press any key..." << endl;  
+	
+	while(!_kbhit());
+
+};
diff --git a/extern/qhull/src/qset.c b/extern/qhull/src/qset.c
new file mode 100644
index 00000000000..9e78464c07e
--- /dev/null
+++ b/extern/qhull/src/qset.c
@@ -0,0 +1,1301 @@
+/*
  ---------------------------------
+
+   qset.c 
+   implements set manipulations needed for quickhull 
+
+   see qh-set.htm and qset.h
+
+   copyright (c) 1993-2002 The Geometry Center        
+*/
+
+#include 
+#include 
+/*** uncomment here and qhull_a.h 
+     if string.h does not define memcpy()
+#include 
+*/
+#include "qset.h"
+#include "mem.h"
+
+#ifndef qhDEFqhull
+typedef struct ridgeT ridgeT;
+typedef struct facetT facetT;
+void    qh_errexit(int exitcode, facetT *, ridgeT *);
+#endif
+
+/*=============== internal macros ===========================*/
+
+/*---------------------------------
+   
+  SETsizeaddr_(set) 
+    return pointer to actual size+1 of set (set CANNOT be NULL!!)
+      
+  notes:
+    *SETsizeaddr==NULL or e[*SETsizeaddr-1].p==NULL
+*/
+#define SETsizeaddr_(set) (&((set)->e[(set)->maxsize].i))
+
+/*============ functions in alphabetical order ===================*/
+  
+/*----------------------------------
+   
+  qh_setaddnth( setp, nth, newelem)
+    adds newelem as n'th element of sorted or unsorted *setp
+      
+  notes:
+    *setp and newelem must be defined
+    *setp may be a temp set
+    nth=0 is first element
+    errors if nth is out of bounds
+   
+  design:
+    expand *setp if empty or full
+    move tail of *setp up one
+    insert newelem
+*/
+void qh_setaddnth(setT **setp, int nth, void *newelem) {
+  int *sizep, oldsize, i;
+  void **oldp, **newp;
+
+  if (!*setp || !*(sizep= SETsizeaddr_(*setp))) {
+    qh_setlarger(setp);
+    sizep= SETsizeaddr_(*setp);
+  }
+  oldsize= *sizep - 1;
+  if (nth < 0 || nth > oldsize) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_setaddnth): nth %d is out-of-bounds for set:\n", nth);
+    qh_setprint (qhmem.ferr, "", *setp);
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+  (*sizep)++;
+  oldp= SETelemaddr_(*setp, oldsize, void);   /* NULL */
+  newp= oldp+1;
+  for (i= oldsize-nth+1; i--; )  /* move at least NULL  */
+    *(newp--)= *(oldp--);       /* may overwrite *sizep */
+  *newp= newelem;
+} /* setaddnth */
+
+
+/*----------------------------------
+   
+  setaddsorted( setp, newelem )
+    adds an newelem into sorted *setp
+      
+  notes:
+    *setp and newelem must be defined
+    *setp may be a temp set
+    nop if newelem already in set
+  
+  design:
+    find newelem's position in *setp
+    insert newelem
+*/
+void qh_setaddsorted(setT **setp, void *newelem) {
+  int newindex=0;
+  void *elem, **elemp;
+
+  FOREACHelem_(*setp) {          /* could use binary search instead */
+    if (elem < newelem)
+      newindex++;
+    else if (elem == newelem)
+      return;
+    else
+      break;
+  }
+  qh_setaddnth(setp, newindex, newelem);
+} /* setaddsorted */
+
+
+/*---------------------------------
+  
+  qh_setappend( setp, newelem)
+    append newelem to *setp
+
+  notes:
+    *setp may be a temp set
+    *setp and newelem may be NULL
+
+  design:
+    expand *setp if empty or full
+    append newelem to *setp
+    
+*/
+void qh_setappend(setT **setp, void *newelem) {
+  int *sizep;
+  void **endp;
+
+  if (!newelem)
+    return;
+  if (!*setp || !*(sizep= SETsizeaddr_(*setp))) {
+    qh_setlarger(setp);
+    sizep= SETsizeaddr_(*setp);
+  }
+  *(endp= &((*setp)->e[(*sizep)++ - 1].p))= newelem;
+  *(++endp)= NULL;
+} /* setappend */
+
+/*---------------------------------
+  
+  qh_setappend_set( setp, setA) 
+    appends setA to *setp
+
+  notes:
+    *setp can not be a temp set
+    *setp and setA may be NULL
+
+  design:
+    setup for copy
+    expand *setp if it is too small
+    append all elements of setA to *setp 
+*/
+void qh_setappend_set(setT **setp, setT *setA) {
+  int *sizep, sizeA, size;
+  setT *oldset;
+
+  if (!setA)
+    return;
+  SETreturnsize_(setA, sizeA);
+  if (!*setp)
+    *setp= qh_setnew (sizeA);
+  sizep= SETsizeaddr_(*setp);
+  if (!(size= *sizep))
+    size= (*setp)->maxsize;
+  else
+    size--;
+  if (size + sizeA > (*setp)->maxsize) {
+    oldset= *setp;
+    *setp= qh_setcopy (oldset, sizeA);
+    qh_setfree (&oldset);
+    sizep= SETsizeaddr_(*setp);
+  }
+  *sizep= size+sizeA+1;   /* memcpy may overwrite */
+  if (sizeA > 0) 
+    memcpy((char *)&((*setp)->e[size].p), (char *)&(setA->e[0].p), SETelemsize *(sizeA+1));
+} /* setappend_set */
+
+
+/*---------------------------------
+  
+  qh_setappend2ndlast( setp, newelem )
+    makes newelem the next to the last element in *setp
+
+  notes:
+    *setp must have at least one element
+    newelem must be defined
+    *setp may be a temp set
+
+  design:
+    expand *setp if empty or full
+    move last element of *setp up one
+    insert newelem
+*/
+void qh_setappend2ndlast(setT **setp, void *newelem) {
+  int *sizep;
+  void **endp, **lastp;
+  
+  if (!*setp || !*(sizep= SETsizeaddr_(*setp))) {
+    qh_setlarger(setp);
+    sizep= SETsizeaddr_(*setp);
+  }
+  endp= SETelemaddr_(*setp, (*sizep)++ -1, void); /* NULL */
+  lastp= endp-1;
+  *(endp++)= *lastp;
+  *endp= NULL;    /* may overwrite *sizep */
+  *lastp= newelem;
+} /* setappend2ndlast */
+
+
+/*---------------------------------
+  
+  qh_setcheck( set, typename, id ) 
+    check set for validity
+    report errors with typename and id
+
+  design:
+    checks that maxsize, actual size, and NULL terminator agree
+*/
+void qh_setcheck(setT *set, char *tname, int id) {
+  int maxsize, size;
+  int waserr= 0;
+
+  if (!set)
+    return;
+  SETreturnsize_(set, size);
+  maxsize= set->maxsize;
+  if (size > maxsize || !maxsize) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_setcheck): actual size %d of %s%d is greater than max size %d\n",
+	     size, tname, id, maxsize);
+    waserr= 1;
+  }else if (set->e[size].p) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_setcheck): %s%d (size %d max %d) is not null terminated.\n",
+	     tname, id, maxsize, size-1);
+    waserr= 1;
+  }
+  if (waserr) {
+    qh_setprint (qhmem.ferr, "ERRONEOUS", set);
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+} /* setcheck */
+
+
+/*---------------------------------
+  
+  qh_setcompact( set )
+    remove internal NULLs from an unsorted set
+
+  returns:
+    updated set
+
+  notes:
+    set may be NULL
+    it would be faster to swap tail of set into holes, like qh_setdel
+
+  design:
+    setup pointers into set
+    skip NULLs while copying elements to start of set 
+    update the actual size
+*/
+void qh_setcompact(setT *set) {
+  int size;
+  void **destp, **elemp, **endp, **firstp;
+
+  if (!set)
+    return;
+  SETreturnsize_(set, size);
+  destp= elemp= firstp= SETaddr_(set, void);
+  endp= destp + size;
+  while (1) {
+    if (!(*destp++ = *elemp++)) {
+      destp--;
+      if (elemp > endp)
+	break;
+    }
+  }
+  qh_settruncate (set, destp-firstp);
+} /* setcompact */
+
+
+/*---------------------------------
+  
+  qh_setcopy( set, extra )
+    make a copy of a sorted or unsorted set with extra slots
+
+  returns:
+    new set
+
+  design:
+    create a newset with extra slots
+    copy the elements to the newset
+    
+*/
+setT *qh_setcopy(setT *set, int extra) {
+  setT *newset;
+  int size;
+
+  if (extra < 0)
+    extra= 0;
+  SETreturnsize_(set, size);
+  newset= qh_setnew(size+extra);
+  *SETsizeaddr_(newset)= size+1;    /* memcpy may overwrite */
+  memcpy((char *)&(newset->e[0].p), (char *)&(set->e[0].p), SETelemsize *(size+1));
+  return (newset);
+} /* setcopy */
+
+
+/*---------------------------------
+  
+  qh_setdel( set, oldelem )
+    delete oldelem from an unsorted set
+
+  returns:
+    returns oldelem if found
+    returns NULL otherwise
+    
+  notes:
+    set may be NULL
+    oldelem must not be NULL;
+    only deletes one copy of oldelem in set
+     
+  design:
+    locate oldelem
+    update actual size if it was full
+    move the last element to the oldelem's location
+*/
+void *qh_setdel(setT *set, void *oldelem) {
+  void **elemp, **lastp;
+  int *sizep;
+
+  if (!set)
+    return NULL;
+  elemp= SETaddr_(set, void);
+  while (*elemp != oldelem && *elemp)
+    elemp++;
+  if (*elemp) {
+    sizep= SETsizeaddr_(set);
+    if (!(*sizep)--)         /*  if was a full set */
+      *sizep= set->maxsize;  /*     *sizep= (maxsize-1)+ 1 */
+    lastp= SETelemaddr_(set, *sizep-1, void);
+    *elemp= *lastp;      /* may overwrite itself */
+    *lastp= NULL;
+    return oldelem;
+  }
+  return NULL;
+} /* setdel */
+
+
+/*---------------------------------
+  
+  qh_setdellast( set) 
+    return last element of set or NULL
+
+  notes:
+    deletes element from set
+    set may be NULL
+
+  design:
+    return NULL if empty
+    if full set
+      delete last element and set actual size
+    else
+      delete last element and update actual size 
+*/
+void *qh_setdellast(setT *set) {
+  int setsize;  /* actually, actual_size + 1 */
+  int maxsize;
+  int *sizep;
+  void *returnvalue;
+  
+  if (!set || !(set->e[0].p))
+    return NULL;
+  sizep= SETsizeaddr_(set);
+  if ((setsize= *sizep)) {
+    returnvalue= set->e[setsize - 2].p;
+    set->e[setsize - 2].p= NULL;
+    (*sizep)--;
+  }else {
+    maxsize= set->maxsize;
+    returnvalue= set->e[maxsize - 1].p;
+    set->e[maxsize - 1].p= NULL;
+    *sizep= maxsize;
+  }
+  return returnvalue;
+} /* setdellast */
+
+
+/*---------------------------------
+  
+  qh_setdelnth( set, nth )
+    deletes nth element from unsorted set 
+    0 is first element
+
+  returns:
+    returns the element (needs type conversion)
+
+  notes:
+    errors if nth invalid
+
+  design:
+    setup points and check nth
+    delete nth element and overwrite with last element
+*/
+void *qh_setdelnth(setT *set, int nth) {
+  void **elemp, **lastp, *elem;
+  int *sizep;
+
+
+  elemp= SETelemaddr_(set, nth, void);
+  sizep= SETsizeaddr_(set);
+  if (!(*sizep)--)         /*  if was a full set */
+    *sizep= set->maxsize;  /*     *sizep= (maxsize-1)+ 1 */
+  if (nth < 0 || nth >= *sizep) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_setaddnth): nth %d is out-of-bounds for set:\n", nth);
+    qh_setprint (qhmem.ferr, "", set);
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+  lastp= SETelemaddr_(set, *sizep-1, void);
+  elem= *elemp;
+  *elemp= *lastp;      /* may overwrite itself */
+  *lastp= NULL;
+  return elem;
+} /* setdelnth */
+
+/*---------------------------------
+  
+  qh_setdelnthsorted( set, nth )
+    deletes nth element from sorted set
+
+  returns:
+    returns the element (use type conversion)
+  
+  notes:
+    errors if nth invalid
+    
+  see also: 
+    setnew_delnthsorted
+
+  design:
+    setup points and check nth
+    copy remaining elements down one
+    update actual size  
+*/
+void *qh_setdelnthsorted(setT *set, int nth) {
+  void **newp, **oldp, *elem;
+  int *sizep;
+
+  sizep= SETsizeaddr_(set);
+  if (nth < 0 || (*sizep && nth >= *sizep-1) || nth >= set->maxsize) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_setaddnth): nth %d is out-of-bounds for set:\n", nth);
+    qh_setprint (qhmem.ferr, "", set);
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+  newp= SETelemaddr_(set, nth, void);
+  elem= *newp;
+  oldp= newp+1;
+  while ((*(newp++)= *(oldp++)))
+    ; /* copy remaining elements and NULL */
+  if (!(*sizep)--)         /*  if was a full set */
+    *sizep= set->maxsize;  /*     *sizep= (max size-1)+ 1 */
+  return elem;
+} /* setdelnthsorted */
+
+
+/*---------------------------------
+  
+  qh_setdelsorted( set, oldelem )
+    deletes oldelem from sorted set
+
+  returns:
+    returns oldelem if it was deleted
+  
+  notes:
+    set may be NULL
+
+  design:
+    locate oldelem in set
+    copy remaining elements down one
+    update actual size  
+*/
+void *qh_setdelsorted(setT *set, void *oldelem) {
+  void **newp, **oldp;
+  int *sizep;
+
+  if (!set)
+    return NULL;
+  newp= SETaddr_(set, void);
+  while(*newp != oldelem && *newp)
+    newp++;
+  if (*newp) {
+    oldp= newp+1;
+    while ((*(newp++)= *(oldp++)))
+      ; /* copy remaining elements */
+    sizep= SETsizeaddr_(set);
+    if (!(*sizep)--)    /*  if was a full set */
+      *sizep= set->maxsize;  /*     *sizep= (max size-1)+ 1 */
+    return oldelem;
+  }
+  return NULL;
+} /* setdelsorted */
+
+
+/*---------------------------------
+  
+  qh_setduplicate( set, elemsize )
+    duplicate a set of elemsize elements
+
+  notes:
+    use setcopy if retaining old elements
+
+  design:
+    create a new set
+    for each elem of the old set
+      create a newelem
+      append newelem to newset
+*/
+setT *qh_setduplicate (setT *set, int elemsize) {
+  void		*elem, **elemp, *newElem;
+  setT		*newSet;
+  int		size;
+  
+  if (!(size= qh_setsize (set)))
+    return NULL;
+  newSet= qh_setnew (size);
+  FOREACHelem_(set) {
+    newElem= qh_memalloc (elemsize);
+    memcpy (newElem, elem, elemsize);
+    qh_setappend (&newSet, newElem);
+  }
+  return newSet;
+} /* setduplicate */
+
+
+/*---------------------------------
+  
+  qh_setequal(  )
+    returns 1 if two sorted sets are equal, otherwise returns 0
+
+  notes:
+    either set may be NULL
+
+  design:
+    check size of each set
+    setup pointers
+    compare elements of each set
+*/
+int qh_setequal(setT *setA, setT *setB) {
+  void **elemAp, **elemBp;
+  int sizeA, sizeB;
+  
+  SETreturnsize_(setA, sizeA);
+  SETreturnsize_(setB, sizeB);
+  if (sizeA != sizeB)
+    return 0;
+  if (!sizeA)
+    return 1;
+  elemAp= SETaddr_(setA, void);
+  elemBp= SETaddr_(setB, void);
+  if (!memcmp((char *)elemAp, (char *)elemBp, sizeA*SETelemsize))
+    return 1;
+  return 0;
+} /* setequal */
+
+
+/*---------------------------------
+  
+  qh_setequal_except( setA, skipelemA, setB, skipelemB )
+    returns 1 if sorted setA and setB are equal except for skipelemA & B
+
+  returns:
+    false if either skipelemA or skipelemB are missing
+  
+  notes:
+    neither set may be NULL
+
+    if skipelemB is NULL, 
+      can skip any one element of setB
+
+  design:
+    setup pointers
+    search for skipelemA, skipelemB, and mismatches
+    check results
+*/
+int qh_setequal_except (setT *setA, void *skipelemA, setT *setB, void *skipelemB) {
+  void **elemA, **elemB;
+  int skip=0;
+
+  elemA= SETaddr_(setA, void);
+  elemB= SETaddr_(setB, void);
+  while (1) {
+    if (*elemA == skipelemA) {
+      skip++;
+      elemA++;
+    }
+    if (skipelemB) {
+      if (*elemB == skipelemB) {
+        skip++;
+        elemB++;
+      }
+    }else if (*elemA != *elemB) {
+      skip++;
+      if (!(skipelemB= *elemB++))
+        return 0;
+    }
+    if (!*elemA)
+      break;
+    if (*elemA++ != *elemB++) 
+      return 0;
+  }
+  if (skip != 2 || *elemB)
+    return 0;
+  return 1;
+} /* setequal_except */
+  
+
+/*---------------------------------
+  
+  qh_setequal_skip( setA, skipA, setB, skipB )
+    returns 1 if sorted setA and setB are equal except for elements skipA & B
+
+  returns:
+    false if different size
+
+  notes:
+    neither set may be NULL
+
+  design:
+    setup pointers
+    search for mismatches while skipping skipA and skipB
+*/
+int qh_setequal_skip (setT *setA, int skipA, setT *setB, int skipB) {
+  void **elemA, **elemB, **skipAp, **skipBp;
+
+  elemA= SETaddr_(setA, void);
+  elemB= SETaddr_(setB, void);
+  skipAp= SETelemaddr_(setA, skipA, void);
+  skipBp= SETelemaddr_(setB, skipB, void);
+  while (1) {
+    if (elemA == skipAp)
+      elemA++;
+    if (elemB == skipBp)
+      elemB++;
+    if (!*elemA)
+      break;
+    if (*elemA++ != *elemB++) 
+      return 0;
+  }
+  if (*elemB)
+    return 0;
+  return 1;
+} /* setequal_skip */
+  
+
+/*---------------------------------
+  
+  qh_setfree( setp )
+    frees the space occupied by a sorted or unsorted set
+
+  returns:
+    sets setp to NULL
+    
+  notes:
+    set may be NULL
+
+  design:
+    free array
+    free set
+*/
+void qh_setfree(setT **setp) {
+  int size;
+  void **freelistp;  /* used !qh_NOmem */
+  
+  if (*setp) {
+    size= sizeof(setT) + ((*setp)->maxsize)*SETelemsize; 
+    if (size <= qhmem.LASTsize) {
+      qh_memfree_(*setp, size, freelistp);
+    }else
+      qh_memfree (*setp, size);
+    *setp= NULL;
+  }
+} /* setfree */
+
+
+/*---------------------------------
+  
+  qh_setfree2( setp, elemsize )
+    frees the space occupied by a set and its elements
+
+  notes:
+    set may be NULL
+
+  design:
+    free each element
+    free set 
+*/
+void qh_setfree2 (setT **setp, int elemsize) {
+  void		*elem, **elemp;
+  
+  FOREACHelem_(*setp)
+    qh_memfree (elem, elemsize);
+  qh_setfree (setp);
+} /* setfree2 */
+
+
+      
+/*---------------------------------
+  
+  qh_setfreelong( setp )
+    frees a set only if it's in long memory
+
+  returns:
+    sets setp to NULL if it is freed
+    
+  notes:
+    set may be NULL
+
+  design:
+    if set is large
+      free it    
+*/
+void qh_setfreelong(setT **setp) {
+  int size;
+  
+  if (*setp) {
+    size= sizeof(setT) + ((*setp)->maxsize)*SETelemsize; 
+    if (size > qhmem.LASTsize) {
+      qh_memfree (*setp, size);
+      *setp= NULL;
+    }
+  }
+} /* setfreelong */
+
+
+/*---------------------------------
+  
+  qh_setin( set, setelem )
+    returns 1 if setelem is in a set, 0 otherwise
+
+  notes:
+    set may be NULL or unsorted
+
+  design:
+    scans set for setelem
+*/
+int qh_setin(setT *set, void *setelem) {
+  void *elem, **elemp;
+
+  FOREACHelem_(set) {
+    if (elem == setelem)
+      return 1;
+  }
+  return 0;
+} /* setin */
+
+
+/*---------------------------------
+  
+  qh_setindex( set, atelem )
+    returns the index of atelem in set.   
+    returns -1, if not in set or maxsize wrong
+
+  notes:
+    set may be NULL and may contain nulls.
+
+  design:
+    checks maxsize
+    scans set for atelem
+*/
+int qh_setindex(setT *set, void *atelem) {
+  void **elem;
+  int size, i;
+
+  SETreturnsize_(set, size);
+  if (size > set->maxsize)
+    return -1;
+  elem= SETaddr_(set, void);
+  for (i=0; i < size; i++) {
+    if (*elem++ == atelem)
+      return i;
+  }
+  return -1;
+} /* setindex */
+
+
+/*---------------------------------
+  
+  qh_setlarger( oldsetp )
+    returns a larger set that contains all elements of *oldsetp
+
+  notes:
+    the set is at least twice as large
+    if temp set, updates qhmem.tempstack
+
+  design:
+    creates a new set
+    copies the old set to the new set
+    updates pointers in tempstack
+    deletes the old set
+*/
+void qh_setlarger(setT **oldsetp) {
+  int size= 1, *sizep;
+  setT *newset, *set, **setp, *oldset;
+  void **oldp, **newp;
+
+  if (*oldsetp) {
+    oldset= *oldsetp;
+    SETreturnsize_(oldset, size);
+    qhmem.cntlarger++;
+    qhmem.totlarger += size+1;
+    newset= qh_setnew(2 * size);
+    oldp= SETaddr_(oldset, void);
+    newp= SETaddr_(newset, void);
+    memcpy((char *)newp, (char *)oldp, (size+1) * SETelemsize);
+    sizep= SETsizeaddr_(newset);
+    *sizep= size+1;
+    FOREACHset_((setT *)qhmem.tempstack) {
+      if (set == oldset)
+	*(setp-1)= newset;
+    }
+    qh_setfree(oldsetp);
+  }else 
+    newset= qh_setnew(3);
+  *oldsetp= newset;
+} /* setlarger */
+
+
+/*---------------------------------
+  
+  qh_setlast(  )
+    return last element of set or NULL (use type conversion)
+
+  notes:
+    set may be NULL
+
+  design:
+    return last element  
+*/
+void *qh_setlast(setT *set) {
+  int size;
+
+  if (set) {
+    size= *SETsizeaddr_(set);
+    if (!size) 
+      return SETelem_(set, set->maxsize - 1);
+    else if (size > 1)
+      return SETelem_(set, size - 2);
+  }
+  return NULL;
+} /* setlast */
+
+
+/*---------------------------------
+  
+  qh_setnew( setsize )
+    creates and allocates space for a set
+
+  notes:
+    setsize means the number of elements (NOT including the NULL terminator)
+    use qh_settemp/qh_setfreetemp if set is temporary
+
+  design:
+    allocate memory for set
+    roundup memory if small set
+    initialize as empty set
+*/
+setT *qh_setnew(int setsize) {
+  setT *set;
+  int sizereceived; /* used !qh_NOmem */
+  int size;
+  void **freelistp; /* used !qh_NOmem */
+
+  if (!setsize)
+    setsize++;
+  size= sizeof(setT) + setsize * SETelemsize;
+  if ((unsigned) size <= (unsigned) qhmem.LASTsize) {
+    qh_memalloc_(size, freelistp, set, setT);
+#ifndef qh_NOmem
+    sizereceived= qhmem.sizetable[ qhmem.indextable[size]];
+    if (sizereceived > size) 
+      setsize += (sizereceived - size)/SETelemsize;
+#endif
+  }else
+    set= (setT*)qh_memalloc (size);
+  set->maxsize= setsize;
+  set->e[setsize].i= 1;
+  set->e[0].p= NULL;
+  return (set);
+} /* setnew */
+
+
+/*---------------------------------
+  
+  qh_setnew_delnthsorted( set, size, nth, prepend )
+    creates a sorted set not containing nth element
+    if prepend, the first prepend elements are undefined
+
+  notes:
+    set must be defined
+    checks nth
+    see also: setdelnthsorted
+
+  design:
+    create new set
+    setup pointers and allocate room for prepend'ed entries
+    append head of old set to new set
+    append tail of old set to new set
+*/
+setT *qh_setnew_delnthsorted(setT *set, int size, int nth, int prepend) {
+  setT *newset;
+  void **oldp, **newp;
+  int tailsize= size - nth -1, newsize;
+
+  if (tailsize < 0) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_setaddnth): nth %d is out-of-bounds for set:\n", nth);
+    qh_setprint (qhmem.ferr, "", set);
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+  newsize= size-1 + prepend;
+  newset= qh_setnew(newsize);
+  newset->e[newset->maxsize].i= newsize+1;  /* may be overwritten */
+  oldp= SETaddr_(set, void);
+  newp= SETaddr_(newset, void) + prepend;
+  switch (nth) {
+  case 0:
+    break;
+  case 1:
+    *(newp++)= *oldp++;
+    break;
+  case 2:
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    break;
+  case 3:
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    break;
+  case 4:
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    break;
+  default:
+    memcpy((char *)newp, (char *)oldp, nth * SETelemsize);
+    newp += nth;
+    oldp += nth;
+    break;
+  }
+  oldp++;
+  switch (tailsize) {
+  case 0:
+    break;
+  case 1:
+    *(newp++)= *oldp++;
+    break;
+  case 2:
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    break;
+  case 3:
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    break;
+  case 4:
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    break;
+  default:
+    memcpy((char *)newp, (char *)oldp, tailsize * SETelemsize);
+    newp += tailsize;
+  }
+  *newp= NULL;
+  return(newset);
+} /* setnew_delnthsorted */
+
+
+/*---------------------------------
+  
+  qh_setprint( fp, string, set )
+    print set elements to fp with identifying string
+
+  notes:
+    never errors
+*/
+void qh_setprint(FILE *fp, char* string, setT *set) {
+  int size, k;
+
+  if (!set)
+    fprintf (fp, "%s set is null\n", string);
+  else {
+    SETreturnsize_(set, size);
+    fprintf (fp, "%s set=%p maxsize=%d size=%d elems=",
+	     string, set, set->maxsize, size);
+    if (size > set->maxsize)
+      size= set->maxsize+1;
+    for (k=0; k < size; k++)
+      fprintf(fp, " %p", set->e[k].p);
+    fprintf(fp, "\n");
+  }
+} /* setprint */
+
+/*---------------------------------
+  
+  qh_setreplace( set, oldelem, newelem )
+    replaces oldelem in set with newelem
+
+  notes:
+    errors if oldelem not in the set
+    newelem may be NULL, but it turns the set into an indexed set (no FOREACH)
+
+  design:
+    find oldelem
+    replace with newelem
+*/
+void qh_setreplace(setT *set, void *oldelem, void *newelem) {
+  void **elemp;
+  
+  elemp= SETaddr_(set, void);
+  while(*elemp != oldelem && *elemp)
+    elemp++;
+  if (*elemp)
+    *elemp= newelem;
+  else {
+    fprintf (qhmem.ferr, "qhull internal error (qh_setreplace): elem %p not found in set\n",
+       oldelem);
+    qh_setprint (qhmem.ferr, "", set);
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+} /* setreplace */
+
+
+/*---------------------------------
+  
+  qh_setsize( set )
+    returns the size of a set
+
+  notes:
+    errors if set's maxsize is incorrect
+    same as SETreturnsize_(set)
+
+  design:
+    determine actual size of set from maxsize
+*/
+int qh_setsize(setT *set) {
+  int size, *sizep;
+  
+  if (!set)
+    return (0);
+  sizep= SETsizeaddr_(set);
+  if ((size= *sizep)) {
+    size--;
+    if (size > set->maxsize) {
+      fprintf (qhmem.ferr, "qhull internal error (qh_setsize): current set size %d is greater than maximum size %d\n",
+	       size, set->maxsize);
+      qh_setprint (qhmem.ferr, "set: ", set);
+      qh_errexit (qhmem_ERRqhull, NULL, NULL);
+    }
+  }else
+    size= set->maxsize;
+  return size;
+} /* setsize */
+
+/*---------------------------------
+  
+  qh_settemp( setsize )
+    return a stacked, temporary set of upto setsize elements
+
+  notes:
+    use settempfree or settempfree_all to release from qhmem.tempstack
+    see also qh_setnew
+
+  design:
+    allocate set
+    append to qhmem.tempstack
+    
+*/
+setT *qh_settemp(int setsize) {
+  setT *newset;
+  
+  newset= qh_setnew (setsize);
+  qh_setappend ((setT **)&qhmem.tempstack, newset);
+  if (qhmem.IStracing >= 5)
+    fprintf (qhmem.ferr, "qh_settemp: temp set %p of %d elements, depth %d\n",
+       newset, newset->maxsize, qh_setsize ((setT*)qhmem.tempstack));
+  return newset;
+} /* settemp */
+
+/*---------------------------------
+  
+  qh_settempfree( set )
+    free temporary set at top of qhmem.tempstack
+
+  notes:
+    nop if set is NULL
+    errors if set not from previous   qh_settemp
+  
+  to locate errors:
+    use 'T2' to find source and then find mis-matching qh_settemp
+
+  design:
+    check top of qhmem.tempstack
+    free it
+*/
+void qh_settempfree(setT **set) {
+  setT *stackedset;
+
+  if (!*set)
+    return;
+  stackedset= qh_settemppop ();
+  if (stackedset != *set) {
+    qh_settemppush(stackedset);
+    fprintf (qhmem.ferr, "qhull internal error (qh_settempfree): set %p (size %d) was not last temporary allocated (depth %d, set %p, size %d)\n",
+	     *set, qh_setsize(*set), qh_setsize((setT*)qhmem.tempstack)+1,
+	     stackedset, qh_setsize(stackedset));
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+  qh_setfree (set);
+} /* settempfree */
+
+/*---------------------------------
+  
+  qh_settempfree_all(  )
+    free all temporary sets in qhmem.tempstack
+
+  design:
+    for each set in tempstack
+      free set
+    free qhmem.tempstack
+*/
+void qh_settempfree_all(void) {
+  setT *set, **setp;
+
+  FOREACHset_((setT *)qhmem.tempstack) 
+    qh_setfree(&set);
+  qh_setfree((setT **)&qhmem.tempstack);
+} /* settempfree_all */
+
+/*---------------------------------
+  
+  qh_settemppop(  )
+    pop and return temporary set from qhmem.tempstack 
+
+  notes:
+    the returned set is permanent
+    
+  design:
+    pop and check top of qhmem.tempstack
+*/
+setT *qh_settemppop(void) {
+  setT *stackedset;
+  
+  stackedset= (setT*)qh_setdellast((setT *)qhmem.tempstack);
+  if (!stackedset) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_settemppop): pop from empty temporary stack\n");
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+  if (qhmem.IStracing >= 5)
+    fprintf (qhmem.ferr, "qh_settemppop: depth %d temp set %p of %d elements\n",
+       qh_setsize((setT*)qhmem.tempstack)+1, stackedset, qh_setsize(stackedset));
+  return stackedset;
+} /* settemppop */
+
+/*---------------------------------
+  
+  qh_settemppush( set )
+    push temporary set unto qhmem.tempstack (makes it temporary)
+
+  notes:
+    duplicates settemp() for tracing
+
+  design:
+    append set to tempstack  
+*/
+void qh_settemppush(setT *set) {
+  
+  qh_setappend ((setT**)&qhmem.tempstack, set);
+  if (qhmem.IStracing >= 5)
+    fprintf (qhmem.ferr, "qh_settemppush: depth %d temp set %p of %d elements\n",
+    qh_setsize((setT*)qhmem.tempstack), set, qh_setsize(set));
+} /* settemppush */
+
+ 
+/*---------------------------------
+  
+  qh_settruncate( set, size )
+    truncate set to size elements
+
+  notes:
+    set must be defined
+  
+  see:
+    SETtruncate_
+
+  design:
+    check size
+    update actual size of set
+*/
+void qh_settruncate (setT *set, int size) {
+
+  if (size < 0 || size > set->maxsize) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_settruncate): size %d out of bounds for set:\n", size);
+    qh_setprint (qhmem.ferr, "", set);
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+  set->e[set->maxsize].i= size+1;   /* maybe overwritten */
+  set->e[size].p= NULL;
+} /* settruncate */
+    
+/*---------------------------------
+  
+  qh_setunique( set, elem )
+    add elem to unsorted set unless it is already in set
+
+  notes:
+    returns 1 if it is appended
+
+  design:
+    if elem not in set
+      append elem to set
+*/
+int qh_setunique (setT **set, void *elem) {
+
+  if (!qh_setin (*set, elem)) {
+    qh_setappend (set, elem);
+    return 1;
+  }
+  return 0;
+} /* setunique */
+    
+/*---------------------------------
+  
+  qh_setzero( set, index, size )
+    zero elements from index on
+    set actual size of set to size
+
+  notes:
+    set must be defined
+    the set becomes an indexed set (can not use FOREACH...)
+  
+  see also:
+    qh_settruncate
+    
+  design:
+    check index and size
+    update actual size
+    zero elements starting at e[index]   
+*/
+void qh_setzero (setT *set, int index, int size) {
+  int count;
+
+  if (index < 0 || index >= size || size > set->maxsize) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_setzero): index %d or size %d out of bounds for set:\n", index, size);
+    qh_setprint (qhmem.ferr, "", set);
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+  set->e[set->maxsize].i=  size+1;  /* may be overwritten */
+  count= size - index + 1;   /* +1 for NULL terminator */
+  memset ((char *)SETelemaddr_(set, index, void), 0, count * SETelemsize);
+} /* setzero */
+
+    
diff --git a/extern/qhull/src/qset.h b/extern/qhull/src/qset.h
new file mode 100644
index 00000000000..6c0ff758de4
--- /dev/null
+++ b/extern/qhull/src/qset.h
@@ -0,0 +1,468 @@
+/*
  ---------------------------------
+
+   qset.h
+     header file for qset.c that implements set
+
+   see qh-set.htm and qset.c
+   
+   only uses mem.c, malloc/free
+
+   for error handling, writes message and calls
+      qh_errexit (qhmem_ERRqhull, NULL, NULL);
+   
+   set operations satisfy the following properties:
+    - sets have a max size, the actual size (if different) is stored at the end
+    - every set is NULL terminated
+    - sets may be sorted or unsorted, the caller must distinguish this
+   
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFset
+#define qhDEFset 1
+
+/*================= -structures- ===============*/
+
+#ifndef DEFsetT
+#define DEFsetT 1
+typedef struct setT setT;   /* a set is a sorted or unsorted array of pointers */
+#endif
+
+/*------------------------------------------
+   
+setT
+  a set or list of pointers with maximum size and actual size.
+
+variations:
+  unsorted, unique   -- a list of unique pointers with NULL terminator
+  			   user guarantees uniqueness
+  sorted	     -- a sorted list of unique pointers with NULL terminator
+  			   qset.c guarantees uniqueness
+  unsorted           -- a list of pointers terminated with NULL
+  indexed  	     -- an array of pointers with NULL elements 
+
+structure for set of n elements:
+
+	--------------
+	|  maxsize 
+	--------------
+	|  e[0] - a pointer, may be NULL for indexed sets
+	--------------
+	|  e[1]
+	
+	--------------
+	|  ...
+	--------------
+	|  e[n-1]
+	--------------
+	|  e[n] = NULL
+	--------------
+	|  ...
+	--------------
+	|  e[maxsize] - n+1 or NULL (determines actual size of set)
+	--------------
+
+*/
+
+/*-- setelemT -- internal type to allow both pointers and indices
+*/
+typedef union setelemT setelemT;
+union setelemT {
+  void    *p;
+  int      i;         /* integer used for e[maxSize] */
+};
+
+struct setT {
+  int maxsize;          /* maximum number of elements (except NULL) */
+  setelemT e[1];        /* array of pointers, tail is NULL */
+                        /* last slot (unless NULL) is actual size+1 
+                           e[maxsize]==NULL or e[e[maxsize]-1]==NULL */
+                        /* this may generate a warning since e[] contains
+			   maxsize elements */
+};
+
+/*=========== -constants- =========================*/
+
+/*-------------------------------------
+   
+  SETelemsize
+    size of a set element in bytes
+*/
+#define SETelemsize sizeof(setelemT) 
+
+
+/*=========== -macros- =========================*/
+
+/*-------------------------------------
+   
+   FOREACHsetelement_(type, set, variable)
+     define FOREACH iterator
+
+   declare:  
+     assumes *variable and **variablep are declared
+     no space in "variable)" [DEC Alpha cc compiler]
+
+   each iteration:
+     variable is set element
+     variablep is one beyond variable.  
+
+   to repeat an element:
+     variablep--; / *repeat* /
+
+   at exit:
+     variable is NULL at end of loop
+
+   example:  
+     #define FOREACHfacet_( facets ) FOREACHsetelement_( facetT, facets, facet )
+
+   notes:
+     use FOREACHsetelement_i_() if need index or include NULLs
+
+   WARNING: 
+     nested loops can't use the same variable (define another FOREACH)
+   
+     needs braces if nested inside another FOREACH
+     this includes intervening blocks, e.g. FOREACH...{ if () FOREACH...} )
+*/
+#define FOREACHsetelement_(type, set, variable) \
+        if (((variable= NULL), set)) for(\
+          variable##p= (type **)&((set)->e[0].p); \
+	  (variable= *variable##p++);)
+
+/*------------------------------------------
+
+   FOREACHsetelement_i_(type, set, variable)
+     define indexed FOREACH iterator
+
+   declare:  
+     type *variable, variable_n, variable_i;
+
+   each iteration:
+     variable is set element, may be NULL
+     variable_i is index, variable_n is qh_setsize()
+
+   to repeat an element:
+     variable_i--; variable_n-- repeats for deleted element
+
+   at exit:
+     variable==NULL and variable_i==variable_n
+
+   example:
+     #define FOREACHfacet_i_( facets ) FOREACHsetelement_i_( facetT, facets, facet )
+   
+   WARNING: 
+     nested loops can't use the same variable (define another FOREACH)
+   
+     needs braces if nested inside another FOREACH
+     this includes intervening blocks, e.g. FOREACH...{ if () FOREACH...} )
+*/
+#define FOREACHsetelement_i_(type, set, variable) \
+        if (((variable= NULL), set)) for (\
+          variable##_i= 0, variable= (type *)((set)->e[0].p), \
+                   variable##_n= qh_setsize(set);\
+          variable##_i < variable##_n;\
+          variable= (type *)((set)->e[++variable##_i].p) )
+
+/*----------------------------------------
+
+   FOREACHsetelementreverse_(type, set, variable)- 
+     define FOREACH iterator in reverse order
+
+   declare:  
+     assumes *variable and **variablep are declared
+     also declare 'int variabletemp'
+
+   each iteration:
+     variable is set element
+
+   to repeat an element:
+     variabletemp++; / *repeat* /
+
+   at exit:
+     variable is NULL
+
+   example:
+     #define FOREACHvertexreverse_( vertices ) FOREACHsetelementreverse_( vertexT, vertices, vertex )
+  
+   notes:
+     use FOREACHsetelementreverse12_() to reverse first two elements
+     WARNING: needs braces if nested inside another FOREACH
+*/
+#define FOREACHsetelementreverse_(type, set, variable) \
+        if (((variable= NULL), set)) for(\
+	   variable##temp= qh_setsize(set)-1, variable= qh_setlast(set);\
+	   variable; variable= \
+	   ((--variable##temp >= 0) ? SETelemt_(set, variable##temp, type) : NULL))
+
+/*-------------------------------------
+
+   FOREACHsetelementreverse12_(type, set, variable)- 
+     define FOREACH iterator with e[1] and e[0] reversed
+
+   declare:  
+     assumes *variable and **variablep are declared
+
+   each iteration:
+     variable is set element
+     variablep is one after variable.  
+
+   to repeat an element:
+     variablep--; / *repeat* /
+
+   at exit:
+     variable is NULL at end of loop
+  
+   example
+     #define FOREACHvertexreverse12_( vertices ) FOREACHsetelementreverse12_( vertexT, vertices, vertex )
+
+   notes:
+     WARNING: needs braces if nested inside another FOREACH
+*/
+#define FOREACHsetelementreverse12_(type, set, variable) \
+        if (((variable= NULL), set)) for(\
+          variable##p= (type **)&((set)->e[1].p); \
+	  (variable= *variable##p); \
+          variable##p == ((type **)&((set)->e[0].p))?variable##p += 2: \
+	      (variable##p == ((type **)&((set)->e[1].p))?variable##p--:variable##p++))
+
+/*-------------------------------------
+
+   FOREACHelem_( set )- 
+     iterate elements in a set
+
+   declare:  
+     void *elem, *elemp;
+
+   each iteration:
+     elem is set element
+     elemp is one beyond
+
+   to repeat an element:
+     elemp--; / *repeat* /
+
+   at exit:
+     elem == NULL at end of loop
+  
+   example:
+     FOREACHelem_(set) {
+     
+   notes:
+     WARNING: needs braces if nested inside another FOREACH
+*/
+#define FOREACHelem_(set) FOREACHsetelement_(void, set, elem)
+
+/*-------------------------------------
+
+   FOREACHset_( set )- 
+     iterate a set of sets
+
+   declare:  
+     setT *set, **setp;
+
+   each iteration:
+     set is set element
+     setp is one beyond
+
+   to repeat an element:
+     setp--; / *repeat* /
+
+   at exit:
+     set == NULL at end of loop
+  
+   example
+     FOREACHset_(sets) {
+     
+   notes:
+     WARNING: needs braces if nested inside another FOREACH
+*/
+#define FOREACHset_(sets) FOREACHsetelement_(setT, sets, set)
+
+/*-------------------------------------------
+
+   SETindex_( set, elem )
+     return index of elem in set
+
+   notes:   
+     for use with FOREACH iteration
+
+   example:
+     i= SETindex_(ridges, ridge)
+*/
+#define SETindex_(set, elem) ((void **)elem##p - (void **)&(set)->e[1].p)
+
+/*-----------------------------------------
+
+   SETref_( elem )
+     l.h.s. for modifying the current element in a FOREACH iteration
+
+   example:
+     SETref_(ridge)= anotherridge;
+*/
+#define SETref_(elem) (elem##p[-1])
+
+/*-----------------------------------------
+
+   SETelem_(set, n)
+     return the n'th element of set
+   
+   notes:
+      assumes that n is valid [0..size] and that set is defined
+      use SETelemt_() for type cast
+*/
+#define SETelem_(set, n)           ((set)->e[n].p)
+
+/*-----------------------------------------
+
+   SETelemt_(set, n, type)
+     return the n'th element of set as a type
+   
+   notes:
+      assumes that n is valid [0..size] and that set is defined
+*/
+#define SETelemt_(set, n, type)    ((type*)((set)->e[n].p))
+
+/*-----------------------------------------
+
+   SETelemaddr_(set, n, type)
+     return address of the n'th element of a set
+   
+   notes:
+      assumes that n is valid [0..size] and set is defined 
+*/
+#define SETelemaddr_(set, n, type) ((type **)(&((set)->e[n].p)))
+
+/*-----------------------------------------
+
+   SETfirst_(set)
+     return first element of set
+   
+*/
+#define SETfirst_(set)             ((set)->e[0].p)
+
+/*-----------------------------------------
+
+   SETfirstt_(set, type)
+     return first element of set as a type
+   
+*/
+#define SETfirstt_(set, type)      ((type*)((set)->e[0].p))
+
+/*-----------------------------------------
+
+   SETsecond_(set)
+     return second element of set
+   
+*/
+#define SETsecond_(set)            ((set)->e[1].p)
+
+/*-----------------------------------------
+
+   SETsecondt_(set, type)
+     return second element of set as a type
+*/
+#define SETsecondt_(set, type)     ((type*)((set)->e[1].p))
+
+/*-----------------------------------------
+
+   SETaddr_(set, type)
+       return address of set's elements
+*/
+#define SETaddr_(set,type)	   ((type **)(&((set)->e[0].p)))
+
+/*-----------------------------------------
+
+   SETreturnsize_(set, size) 
+     return size of a set
+   
+   notes:
+      set must be defined
+      use qh_setsize(set) unless speed is critical
+*/
+#define SETreturnsize_(set, size) (((size)= ((set)->e[(set)->maxsize].i))?(--(size)):((size)= (set)->maxsize))
+
+/*-----------------------------------------
+
+   SETempty_(set) 
+     return true (1) if set is empty
+   
+   notes:
+      set may be NULL
+*/
+#define SETempty_(set) 	          (!set || (SETfirst_(set) ? 0:1))
+
+/*-----------------------------------------
+
+   SETtruncate_(set)
+     return first element of set
+
+   see:
+     qh_settruncate()
+   
+*/
+#define SETtruncate_(set, size) {set->e[set->maxsize].i= size+1; /* maybe overwritten */ \
+      set->e[size].p= NULL;}
+
+/*======= prototypes in alphabetical order ============*/
+
+void  qh_setaddsorted(setT **setp, void *elem);
+void  qh_setaddnth(setT **setp, int nth, void *newelem);
+void  qh_setappend(setT **setp, void *elem);
+void  qh_setappend_set(setT **setp, setT *setA);
+void  qh_setappend2ndlast(setT **setp, void *elem);
+void  qh_setcheck(setT *set, char *tname, int id);
+void  qh_setcompact(setT *set);
+setT *qh_setcopy(setT *set, int extra);
+void *qh_setdel(setT *set, void *elem);
+void *qh_setdellast(setT *set);
+void *qh_setdelnth(setT *set, int nth);
+void *qh_setdelnthsorted(setT *set, int nth);
+void *qh_setdelsorted(setT *set, void *newelem);
+setT *qh_setduplicate( setT *set, int elemsize);
+int   qh_setequal(setT *setA, setT *setB);
+int   qh_setequal_except (setT *setA, void *skipelemA, setT *setB, void *skipelemB);
+int   qh_setequal_skip (setT *setA, int skipA, setT *setB, int skipB);
+void  qh_setfree(setT **set);
+void  qh_setfree2( setT **setp, int elemsize);
+void  qh_setfreelong(setT **set);
+int   qh_setin(setT *set, void *setelem);
+int   qh_setindex(setT *set, void *setelem);
+void  qh_setlarger(setT **setp);
+void *qh_setlast(setT *set);
+setT *qh_setnew(int size);
+setT *qh_setnew_delnthsorted(setT *set, int size, int nth, int prepend);
+void  qh_setprint(FILE *fp, char* string, setT *set);
+void  qh_setreplace(setT *set, void *oldelem, void *newelem);
+int   qh_setsize(setT *set);
+setT *qh_settemp(int setsize);
+void  qh_settempfree(setT **set);
+void  qh_settempfree_all(void);
+setT *qh_settemppop(void);
+void  qh_settemppush(setT *set);
+void  qh_settruncate (setT *set, int size);
+int   qh_setunique (setT **set, void *elem);
+void  qh_setzero (setT *set, int index, int size);
+
+
+#endif /* qhDEFset */
diff --git a/extern/qhull/src/qvoronoi.c b/extern/qhull/src/qvoronoi.c
new file mode 100644
index 00000000000..ebeb7367b87
--- /dev/null
+++ b/extern/qhull/src/qvoronoi.c
@@ -0,0 +1,318 @@
+/*
  ---------------------------------
+
+   qvoronoi.c
+     compute Voronoi diagrams and furthest-point Voronoi
+     diagrams using qhull
+
+   see unix.c for full interface
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "qhull.h"
+#include "mem.h"
+#include "qset.h"
+
+#if __MWERKS__ && __POWERPC__
+#include 
+#include 
+#include 
+#include 
+
+#elif __cplusplus
+extern "C" {
+  int isatty (int);
+}
+
+#elif _MSC_VER
+#include 
+#define isatty _isatty
+
+#else
+int isatty (int);  /* returns 1 if stdin is a tty
+		   if "Undefined symbol" this can be deleted along with call in main() */
+#endif
+
+/*---------------------------------
+
+  qh_prompt 
+    long prompt for qhull
+    
+  notes:
+    restricted version of qhull.c
+ 
+  see:
+    concise prompt below
+*/  
+
+/* duplicated in qvoron_f.htm and qvoronoi.htm */
+char hidden_options[]=" d n m v H U Qb QB Qc Qf Qg Qi Qm Qr QR Qv Qx TR E V Fa FA FC Fp FS Ft FV Pv Gt Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 ";
+
+char qh_prompta[]= "\n\
+qvoronoi- compute the Voronoi diagram\n\
+    http://www.geom.umn.edu/software/qhull  %s\n\
+\n\
+input (stdin):\n\
+    first lines: dimension and number of points (or vice-versa).\n\
+    other lines: point coordinates, best if one point per line\n\
+    comments:    start with a non-numeric character\n\
+\n\
+options:\n\
+    Qu   - compute furthest-site Voronoi diagram\n\
+    Qt   - triangulated output\n\
+    QJ   - joggled input instead of merged facets\n\
+\n\
+Qhull control options:\n\
+    Qz   - add point-at-infinity to Voronoi diagram\n\
+    QJn  - randomly joggle input in range [-n,n]\n\
+%s%s%s%s";  /* split up qh_prompt for Visual C++ */
+char qh_promptb[]= "\
+    Qs   - search all points for the initial simplex\n\
+    QGn  - Voronoi vertices if visible from point n, -n if not\n\
+    QVn  - Voronoi vertices for input point n, -n if not\n\
+\n\
+";
+char qh_promptc[]= "\
+Trace options:\n\
+    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
+    Tc   - check frequently during execution\n\
+    Ts   - statistics\n\
+    Tv   - verify result: structure, convexity, and in-circle test\n\
+    Tz   - send all output to stdout\n\
+    TFn  - report summary when n or more facets created\n\
+    TI file - input data from file, no spaces or single quotes\n\
+    TO file - output results to file, may be enclosed in single quotes\n\
+    TPn  - turn on tracing when point n added to hull\n\
+     TMn - turn on tracing at merge n\n\
+     TWn - trace merge facets when width > n\n\
+    TVn  - stop qhull after adding point n, -n for before (see TCn)\n\
+     TCn - stop qhull after building cone for point n (see TVn)\n\
+\n\
+Precision options:\n\
+    Cn   - radius of centrum (roundoff added).  Merge facets if non-convex\n\
+     An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex\n\
+           C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge\n\
+    Rn   - randomly perturb computations by a factor of [1-n,1+n]\n\
+    Wn   - min facet width for non-coincident point (before roundoff)\n\
+\n\
+Output formats (may be combined; if none, produces a summary to stdout):\n\
+    s    - summary to stderr\n\
+    p    - Voronoi vertices\n\
+    o    - OFF format (dim, Voronoi vertices, and Voronoi regions)\n\
+    i    - Delaunay regions (use 'Pp' to avoid warning)\n\
+    f    - facet dump\n\
+\n\
+";
+char qh_promptd[]= "\
+More formats:\n\
+    Fc   - count plus coincident points (by Voronoi vertex)\n\
+    Fd   - use cdd format for input (homogeneous with offset first)\n\
+    FD   - use cdd format for output (offset first)\n\
+    FF   - facet dump without ridges\n\
+    Fi   - separating hyperplanes for bounded Voronoi regions\n\
+    FI   - ID for each Voronoi vertex\n\
+    Fm   - merge count for each Voronoi vertex (511 max)\n\
+    Fn   - count plus neighboring Voronoi vertices for each Voronoi vertex\n\
+    FN   - count and Voronoi vertices for each Voronoi region\n\
+    Fo   - separating hyperplanes for unbounded Voronoi regions\n\
+    FO   - options and precision constants\n\
+    FP   - nearest point and distance for each coincident point\n\
+    FQ   - command used for qvoronoi\n\
+    Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,\n\
+                    for output: #Voronoi regions, #Voronoi vertices,\n\
+                                #coincident points, #non-simplicial regions\n\
+                    #real (2), max outer plane and min vertex\n\
+    Fv   - Voronoi diagram as Voronoi vertices between adjacent input sites\n\
+    Fx   - extreme points of Delaunay triangulation (on convex hull)\n\
+\n\
+";
+char qh_prompte[]= "\
+Geomview options (2-d only)\n\
+    Ga   - all points as dots\n\
+     Gp  -  coplanar points and vertices as radii\n\
+     Gv  -  vertices as spheres\n\
+    Gi   - inner planes only\n\
+     Gn  -  no planes\n\
+     Go  -  outer planes only\n\
+    Gc	 - centrums\n\
+    Gh   - hyperplane intersections\n\
+    Gr   - ridges\n\
+    GDn  - drop dimension n in 3-d and 4-d output\n\
+\n\
+Print options:\n\
+    PAn  - keep n largest Voronoi vertices by 'area'\n\
+    Pdk:n - drop facet if normal[k] <= n (default 0.0)\n\
+    PDk:n - drop facet if normal[k] >= n\n\
+    Pg   - print good Voronoi vertices (needs 'QGn' or 'QVn')\n\
+    PFn  - keep Voronoi vertices whose 'area' is at least n\n\
+    PG   - print neighbors of good Voronoi vertices\n\
+    PMn  - keep n Voronoi vertices with most merges\n\
+    Po   - force output.  If error, output neighborhood of facet\n\
+    Pp   - do not report precision problems\n\
+\n\
+    .    - list of all options\n\
+    -    - one line descriptions of all options\n\
+";
+/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
+
+/*---------------------------------
+
+  qh_prompt2
+    synopsis for qhull 
+*/  
+char qh_prompt2[]= "\n\
+qvoronoi- compute the Voronoi diagram. Qhull %s\n\
+    input (stdin): dimension, number of points, point coordinates\n\
+    comments start with a non-numeric character\n\
+\n\
+options (qvoronoi.htm):\n\
+    Qu   - compute furthest-site Voronoi diagram\n\
+    Qt   - triangulated output\n\
+    QJ   - joggled input instead of merged facets\n\
+    Tv   - verify result: structure, convexity, and in-circle test\n\
+    .    - concise list of all options\n\
+    -    - one-line description of all options\n\
+\n\
+output options (subset):\n\
+    s    - summary of results (default)\n\
+    p    - Voronoi vertices\n\
+    o    - OFF file format (dim, Voronoi vertices, and Voronoi regions)\n\
+    FN   - count and Voronoi vertices for each Voronoi region\n\
+    Fv   - Voronoi diagram as Voronoi vertices between adjacent input sites\n\
+    Fi   - separating hyperplanes for bounded regions, 'Fo' for unbounded\n\
+    G    - Geomview output (2-d only)\n\
+    QVn  - Voronoi vertices for input point n, -n if not\n\
+    TO file- output results to file, may be enclosed in single quotes\n\
+\n\
+examples:\n\
+rbox c P0 D2 | qvoronoi s o         rbox c P0 D2 | qvoronoi Fi\n\
+rbox c P0 D2 | qvoronoi Fo          rbox c P0 D2 | qvoronoi Fv\n\
+rbox c P0 D2 | qvoronoi s Qu Fv     rbox c P0 D2 | qvoronoi Qu Fo\n\
+rbox c G1 d D2 | qvoronoi s p       rbox c G1 d D2 | qvoronoi QJ s p\n\
+rbox c P0 D2 | qvoronoi s Fv QV0\n\
+\n\
+";
+/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
+
+/*---------------------------------
+
+  qh_prompt3
+    concise prompt for qhull 
+*/  
+char qh_prompt3[]= "\n\
+Qhull %s.\n\
+Except for 'F.' and 'PG', upper-case options take an argument.\n\
+\n\
+ OFF_format     p_vertices     i_delaunay     summary        facet_dump\n\
+\n\
+ Fcoincident    Fd_cdd_in      FD_cdd_out     FF-dump-xridge Fi_bounded\n\
+ Fxtremes       Fmerges        Fneighbors     FNeigh_region  FOptions\n\
+ Fo_unbounded   FPoint_near    FQvoronoi      Fsummary       Fvoronoi\n\
+ FIDs\n\
+\n\
+ Gvertices      Gpoints        Gall_points    Gno_planes     Ginner\n\
+ Gcentrums      Ghyperplanes   Gridges        Gouter         GDrop_dim\n\
+\n\
+ PArea_keep     Pdrop d0:0D0   Pgood          PFacet_area_keep\n\
+ PGood_neighbors PMerge_keep   Poutput_forced Pprecision_not\n\
+\n\
+ QG_vertex_good QJoggle        Qsearch_1st    Qtriangulate   Qupper_voronoi\n\
+ QV_point_good  Qzinfinite\n\
+\n\
+ T4_trace       Tcheck_often   Tstatistics    Tverify        Tz_stdout\n\
+ TFacet_log     TInput_file    TPoint_trace   TMerge_trace   TOutput_file\n\
+ TWide_trace    TVertex_stop   TCone_stop\n\
+\n\
+ Angle_max      Centrum_size   Random_dist    Wide_outside\n\
+";
+
+/*---------------------------------
+  
+  main( argc, argv )
+    processes the command line, calls qhull() to do the work, and exits
+  
+  design:
+    initializes data structures
+    reads points
+    finishes initialization
+    computes convex hull and other structures
+    checks the result
+    writes the output
+    frees memory
+*/
+int main(int argc, char *argv[]) {
+  int curlong, totlong; /* used !qh_NOmem */
+  int exitcode, numpoints, dim;
+  coordT *points;
+  boolT ismalloc;
+
+#if __MWERKS__ && __POWERPC__
+  char inBuf[BUFSIZ], outBuf[BUFSIZ], errBuf[BUFSIZ];
+  SIOUXSettings.showstatusline= false;
+  SIOUXSettings.tabspaces= 1;
+  SIOUXSettings.rows= 40;
+  if (setvbuf (stdin, inBuf, _IOFBF, sizeof(inBuf)) < 0   /* w/o, SIOUX I/O is slow*/
+  || setvbuf (stdout, outBuf, _IOFBF, sizeof(outBuf)) < 0
+  || (stdout != stderr && setvbuf (stderr, errBuf, _IOFBF, sizeof(errBuf)) < 0)) 
+    fprintf (stderr, "qhull internal warning (main): could not change stdio to fully buffered.\n");
+  argc= ccommand(&argv);
+#endif
+
+  if ((argc == 1) && isatty( 0 /*stdin*/)) {      
+    fprintf(stdout, qh_prompt2, qh_VERSION);
+    exit(qh_ERRnone);
+  }
+  if (argc > 1 && *argv[1] == '-' && !*(argv[1]+1)) {
+    fprintf(stdout, qh_prompta, qh_VERSION,  
+		qh_promptb, qh_promptc, qh_promptd, qh_prompte);
+    exit(qh_ERRnone);
+  }
+  if (argc >1 && *argv[1] == '.' && !*(argv[1]+1)) {
+    fprintf(stdout, qh_prompt3, qh_VERSION);
+    exit(qh_ERRnone);
+  }
+  qh_init_A (stdin, stdout, stderr, argc, argv);  /* sets qh qhull_command */
+  exitcode= setjmp (qh errexit); /* simple statement for CRAY J916 */
+  if (!exitcode) {
+    qh_option ("voronoi  _bbound-last  _coplanar-keep", NULL, NULL);
+    qh DELAUNAY= True;     /* 'v'   */
+    qh VORONOI= True; 
+    qh SCALElast= True;    /* 'Qbb' */
+    qh_checkflags (qh qhull_command, hidden_options);
+    qh_initflags (qh qhull_command);
+    points= qh_readpoints (&numpoints, &dim, &ismalloc);
+    if (dim >= 5) {
+      qh_option ("_merge-exact", NULL, NULL);
+      qh MERGEexact= True; /* 'Qx' always */
+    }
+    qh_init_B (points, numpoints, dim, ismalloc);
+    qh_qhull();
+    qh_check_output();
+    qh_produce_output();
+    if (qh VERIFYoutput && !qh FORCEoutput && !qh STOPpoint && !qh STOPcone)
+      qh_check_points();
+    exitcode= qh_ERRnone;
+  }
+  qh NOerrexit= True;  /* no more setjmp */
+#ifdef qh_NOmem
+  qh_freeqhull( True);
+#else
+  qh_freeqhull( False);
+  qh_memfreeshort (&curlong, &totlong);
+  if (curlong || totlong) 
+    fprintf (stderr, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n",
+       totlong, curlong);
+#endif
+  return exitcode;
+} /* main */
+
diff --git a/extern/qhull/src/rbox.c b/extern/qhull/src/rbox.c
new file mode 100644
index 00000000000..1c288bddc96
--- /dev/null
+++ b/extern/qhull/src/rbox.c
@@ -0,0 +1,788 @@
+/*
  ---------------------------------
+
+   rbox.c
+     Generate input points for qhull.
+   
+   notes:
+     50 points generated for 'rbox D4'
+
+     This code needs a full rewrite.  It needs separate procedures for each 
+     distribution with common, helper procedures.
+   
+   WARNING: 
+     incorrect range if qh_RANDOMmax is defined wrong (user.h)
+*/
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "user.h"
+#if __MWERKS__ && __POWERPC__
+#include 
+#include 
+#include 
+#include 
+#endif
+
+#ifdef _MSC_VER  /* Microsoft Visual C++ */
+#pragma warning( disable : 4244)  /* conversion from double to int */
+#endif
+
+#define MINVALUE 0.8
+#define MAXdim 200
+#define PI 3.1415926535897932384
+#define DEFAULTzbox 1e6
+
+char prompt[]= "\n\
+-rbox- generate various point distributions.  Default is random in cube.\n\
+\n\
+args (any order, space separated):                    Version: 2001/06/24\n\
+  3000    number of random points in cube, lens, spiral, sphere or grid\n\
+  D3      dimension 3-d\n\
+  c       add a unit cube to the output ('c G2.0' sets size)\n\
+  d       add a unit diamond to the output ('d G2.0' sets size)\n\
+  l       generate a regular 3-d spiral\n\
+  r       generate a regular polygon, ('r s Z1 G0.1' makes a cone)\n\
+  s       generate cospherical points\n\
+  x       generate random points in simplex, may use 'r' or 'Wn'\n\
+  y       same as 'x', plus simplex\n\
+  Pn,m,r  add point [n,m,r] first, pads with 0\n\
+\n\
+  Ln      lens distribution of radius n.  Also 's', 'r', 'G', 'W'.\n\
+  Mn,m,r  lattice (Mesh) rotated by [n,-m,0], [m,n,0], [0,0,r], ...\n\
+          '27 M1,0,1' is {0,1,2} x {0,1,2} x {0,1,2}.  Try 'M3,4 z'.\n\
+  W0.1    random distribution within 0.1 of the cube's or sphere's surface\n\
+  Z0.5 s  random points in a 0.5 disk projected to a sphere\n\
+  Z0.5 s G0.6 same as Z0.5 within a 0.6 gap\n\
+\n\
+  Bn      bounding box coordinates, default %2.2g\n\
+  h       output as homogeneous coordinates for cdd\n\
+  n       remove command line from the first line of output\n\
+  On      offset coordinates by n\n\
+  t       use time as the random number seed (default is command line)\n\
+  tn      use n as the random number seed\n\
+  z       print integer coordinates, default 'Bn' is %2.2g\n\
+";
+
+/* ------------------------------ prototypes ----------------*/
+int roundi( double a);
+void out1( double a);
+void out2n( double a, double b);
+void out3n( double a, double b, double c);
+int     qh_rand( void);
+void    qh_srand( int seed);
+
+
+/* ------------------------------ globals -------------------*/
+
+    FILE *fp;
+    int isinteger= 0;
+    double out_offset= 0.0;
+
+
+/*--------------------------------------------
+-rbox-  main procedure of rbox application
+*/
+int main(int argc, char **argv) {
+    int i,j,k;
+    int gendim;
+    int cubesize, diamondsize, seed=0, count, apex;
+    int dim=3 , numpoints= 0, totpoints, addpoints=0;
+    int issphere=0, isaxis=0,  iscdd= 0, islens= 0, isregular=0, iswidth=0, addcube=0;
+    int isgap=0, isspiral=0, NOcommand= 0, adddiamond=0, istime=0;
+    int isbox=0, issimplex=0, issimplex2=0, ismesh=0;
+    double width=0.0, gap=0.0, radius= 0.0;
+    double coord[MAXdim], offset, meshm=3.0, meshn=4.0, meshr=5.0;
+    double *simplex, *simplexp;
+    int nthroot, mult[MAXdim];
+    double norm, factor, randr, rangap, lensangle= 0, lensbase= 1;
+    double anglediff, angle, x, y, cube= 0.0, diamond= 0.0;
+    double box= qh_DEFAULTbox; /* scale all numbers before output */
+    double randmax= qh_RANDOMmax;
+    char command[200], *s, seedbuf[200];    
+    time_t timedata;
+
+#if __MWERKS__ && __POWERPC__
+    char inBuf[BUFSIZ], outBuf[BUFSIZ], errBuf[BUFSIZ];
+    SIOUXSettings.showstatusline= False;
+    SIOUXSettings.tabspaces= 1;
+    SIOUXSettings.rows= 40;
+    if (setvbuf (stdin, inBuf, _IOFBF, sizeof(inBuf)) < 0   /* w/o, SIOUX I/O is slow*/
+    || setvbuf (stdout, outBuf, _IOFBF, sizeof(outBuf)) < 0
+    || (stdout != stderr && setvbuf (stderr, errBuf, _IOFBF, sizeof(errBuf)) < 0)) 
+      	fprintf ( stderr, "qhull internal warning (main): could not change stdio to fully buffered.\n");
+    argc= ccommand(&argv);
+#endif
+    if (argc == 1) {
+ 	printf (prompt, box, DEFAULTzbox);
+    	exit(1);
+    }
+    if ((s = strrchr( argv[0], '\\'))) /* Borland gives full path */
+      strcpy (command, s+1);
+    else
+      strcpy (command, argv[0]);
+    if ((s= strstr (command, ".EXE"))
+    ||  (s= strstr (command, ".exe")))
+      *s= '\0';
+    /* ============= read flags =============== */
+    for (i=1; i < argc; i++) {
+  	if (strlen (command) + strlen(argv[i]) + 1 < sizeof(command) ) {
+	    strcat (command, " ");
+	    strcat (command, argv[i]);
+	}
+        if (isdigit (argv[i][0])) {
+      	    numpoints= atoi (argv[i]);
+      	    continue;
+	}
+	if (argv[i][0] == '-')
+	  (argv[i])++;
+        switch (argv[i][0]) {
+	  case 'c':
+	    addcube= 1;
+	    if (i+1 < argc && argv[i+1][0] == 'G')
+	      cube= (double) atof (&argv[++i][1]);
+	    break;
+	  case 'd':
+	    adddiamond= 1;
+	    if (i+1 < argc && argv[i+1][0] == 'G')
+	      diamond= (double) atof (&argv[++i][1]);
+	    break;
+	  case 'h':
+	    iscdd= 1;
+            break;
+	  case 'l':
+	    isspiral= 1;
+            break;
+	  case 'n':
+	    NOcommand= 1;
+	    break;
+	  case 'r':
+	    isregular= 1;
+	    break;
+	  case 's':
+	    issphere= 1;
+            break;
+	  case 't':
+	    istime= 1;
+	    if (isdigit (argv[i][1]))
+	      seed= atoi (&argv[i][1]);
+	    else {
+	      seed= time (&timedata);
+	      sprintf (seedbuf, "%d", seed);
+	      strcat (command, seedbuf);
+	    }
+            break;
+	  case 'x':
+	    issimplex= 1;
+	    break;
+	  case 'y':
+	    issimplex2= 1;
+	    break;
+	  case 'z':
+	    isinteger= 1;
+	    break;
+	  case 'B':
+	    box= (double) atof (&argv[i][1]);
+	    isbox= 1;
+	    break;
+	  case 'D':
+	    dim= atoi (&argv[i][1]);
+	    if (dim < 1
+	    || dim > MAXdim) {
+		fprintf (stderr, "rbox error: dim %d too large or too small\n", dim);
+		exit (1);
+	    }
+            break;
+	  case 'G':
+	    if (argv[i][1])
+	      gap= (double) atof (&argv[i][1]);
+	    else
+	      gap= 0.5;
+	    isgap= 1;
+	    break;
+	  case 'L':
+	    if (argv[i][1])
+	      radius= (double) atof (&argv[i][1]);
+	    else
+	      radius= 10;
+	    islens= 1;
+	    break;
+	  case 'M':
+	    ismesh= 1;
+    	    s= argv[i]+1;
+	    if (*s)
+	      meshn= strtod (s, &s);
+	    if (*s == ',')
+	      meshm= strtod (++s, &s);
+	    else
+	      meshm= 0.0;
+	    if (*s == ',')
+	      meshr= strtod (++s, &s);
+	    else
+	      meshr= sqrt (meshn*meshn + meshm*meshm);
+	    if (*s) {
+	      fprintf (stderr, "rbox warning: assuming 'M3,4,5' since mesh args are not integers or reals\n");
+	      meshn= 3.0, meshm=4.0, meshr=5.0;
+	    }
+	    break;
+	  case 'O':
+	    out_offset= (double) atof (&argv[i][1]);
+	    break;
+	  case 'P':
+	    addpoints++;
+	    break;
+	  case 'W':
+	    width= (double) atof (&argv[i][1]);
+	    iswidth= 1;
+	    break;
+	  case 'Z':
+	    if (argv[i][1])
+	      radius= (double) atof (&argv[i][1]);
+	    else
+	      radius= 1.0;
+	    isaxis= 1;
+	    break;
+	  default:
+            fprintf (stderr, "rbox warning: unknown flag %s.\nExecute 'rbox' without arguments for documentation.\n", argv[i]);
+	}
+    }
+    /* ============= defaults, constants, and sizes =============== */
+    if (isinteger && !isbox)
+      box= DEFAULTzbox;
+    if (addcube) {
+      cubesize= floor(ldexp(1.0,dim)+0.5);
+      if (cube == 0.0)
+        cube= box;
+    }else
+      cubesize= 0;
+    if (adddiamond) {
+      diamondsize= 2*dim;
+      if (diamond == 0.0)
+        diamond= box;
+    }else
+      diamondsize= 0;
+    if (islens) {
+      if (isaxis) {
+  	fprintf (stderr, "rbox error: can not combine 'Ln' with 'Zn'\n");
+  	exit(1);
+      }
+      if (radius <= 1.0) {
+  	fprintf (stderr, "rbox error: lens radius %.2g should be greater than 1.0\n",
+  	       radius);
+  	exit(1);
+      }
+      lensangle= asin (1.0/radius);
+      lensbase= radius * cos (lensangle);
+    }
+    if (!numpoints) {
+      if (issimplex2)
+	; /* ok */
+      else if (isregular + issimplex + islens + issphere + isaxis + isspiral + iswidth + ismesh) {
+	fprintf (stderr, "rbox error: missing count\n");
+	exit(1);
+      }else if (adddiamond + addcube + addpoints)
+	; /* ok */
+      else { 
+	numpoints= 50;  /* ./rbox D4 is the test case */
+	issphere= 1;
+      }
+    }
+    if ((issimplex + islens + isspiral + ismesh > 1) 
+    || (issimplex + issphere + isspiral + ismesh > 1)) {
+      fprintf (stderr, "rbox error: can only specify one of 'l', 's', 'x', 'Ln', or 'Mn,m,r' ('Ln s' is ok).\n");
+      exit(1);
+    }
+    fp= stdout;
+    /* ============= print header with total points =============== */
+    if (issimplex || ismesh)
+      totpoints= numpoints;
+    else if (issimplex2)
+      totpoints= numpoints+dim+1;
+    else if (isregular) {
+      totpoints= numpoints;
+      if (dim == 2) {
+      	if (islens)
+      	  totpoints += numpoints - 2;
+      }else if (dim == 3) {
+      	if (islens)
+      	  totpoints += 2 * numpoints;
+        else if (isgap)
+          totpoints += 1 + numpoints;
+        else
+          totpoints += 2;
+      }
+    }else
+      totpoints= numpoints + isaxis;
+    totpoints += cubesize + diamondsize + addpoints;
+    if (iscdd) 
+      fprintf(fp, "%s\nbegin\n        %d %d %s\n", 
+            NOcommand ? "" : command, 
+            totpoints, dim+1,
+            isinteger ? "integer" : "real");
+    else if (NOcommand)
+      fprintf(fp,  "%d\n%d\n", dim, totpoints);
+    else
+      fprintf(fp,  "%d %s\n%d\n", dim, command, totpoints);
+    /* ============= seed randoms =============== */
+    if (istime == 0) {
+      for (s=command; *s; s++) {
+	if (issimplex2 && *s == 'y') /* make 'y' same seed as 'x' */
+	  i= 'x';
+	else
+	  i= *s;
+	seed= 11*seed + i;
+      }
+    } /* else, seed explicitly set to n or to time */
+    qh_RANDOMseed_(seed);
+    /* ============= explicit points =============== */
+    for (i=1; i < argc; i++) {
+      if (argv[i][0] == 'P') {
+	s= argv[i]+1;
+	count= 0;
+	if (iscdd)
+	  out1( 1.0);
+	while (*s) {
+	  out1( strtod (s, &s));
+	  count++;
+	  if (*s) { 
+	    if (*s++ != ',') {
+	      fprintf (stderr, "rbox error: missing comma after coordinate in %s\n\n", argv[i]);
+	      exit (1);
+	    }
+          }
+	}
+	if (count < dim) {
+	  for (k= dim-count; k--; )
+	    out1( 0.0);
+	}else if (count > dim) {
+	  fprintf (stderr, "rbox error: %d coordinates instead of %d coordinates in %s\n\n", 
+                 count, dim, argv[i]);
+	  exit (1);
+	}
+	fprintf (fp, "\n");
+      }
+    }
+    /* ============= simplex distribution =============== */
+    if (issimplex+issimplex2) {
+      if (!(simplex= malloc( dim * (dim+1) * sizeof(double)))) {
+	fprintf (stderr, "insufficient memory for simplex\n");
+	exit(0);
+      }
+      simplexp= simplex;
+      if (isregular) {
+        for (i= 0; i randmax/2)
+	    coord[dim-1]= -coord[dim-1];
+	/* ============= project 'Wn' point toward boundary =============== */
+	}else if (iswidth && !issphere) {
+	  j= qh_RANDOMint % gendim;
+	  if (coord[j] < 0)
+	    coord[j]= -1.0 - coord[j] * width;
+	  else
+	    coord[j]= 1.0 - coord[j] * width;
+	}
+	/* ============= write point =============== */
+	if (iscdd)
+	  out1( 1.0);
+	for (k=0; k < dim; k++) 
+	  out1( coord[k] * box);
+	fprintf (fp, "\n");
+      }
+    }
+    /* ============= write cube vertices =============== */
+    if (addcube) {
+      for (j=0; j=0; k--) {
+	  if (j & ( 1 << k))
+	    out1( cube);
+	  else
+	    out1( -cube);
+	}
+	fprintf (fp, "\n");
+      }
+    }
+    /* ============= write diamond vertices =============== */
+    if (adddiamond) {
+      for (j=0; j=0; k--) {
+	  if (j/2 != k)
+	    out1( 0.0);
+	  else if (j & 0x1)
+	    out1( diamond);
+	  else
+	    out1( -diamond);
+	}
+	fprintf (fp, "\n");
+      }
+    }
+    if (iscdd)
+      fprintf (fp, "end\nhull\n");
+    return 0;
+  } /* rbox */
+
+/*------------------------------------------------
+-outxxx - output functions
+*/
+int roundi( double a) {
+  if (a < 0.0) {
+    if (a - 0.5 < INT_MIN) {
+      fprintf(stderr, "rbox input error: coordinate %2.2g is too large.  Reduce 'Bn'\n", a);
+      exit (1);
+    }
+    return a - 0.5;
+  }else {
+    if (a + 0.5 > INT_MAX) {
+      fprintf(stderr, "rbox input error: coordinate %2.2g is too large.  Reduce 'Bn'\n", a);
+      exit (1);
+    }
+    return a + 0.5;
+  }
+} /* roundi */
+
+void out1(double a) {
+
+  if (isinteger) 
+    fprintf(fp, "%d ", roundi( a+out_offset));
+  else
+    fprintf(fp, qh_REAL_1, a+out_offset);
+} /* out1 */
+
+void out2n( double a, double b) {
+
+  if (isinteger)
+    fprintf(fp, "%d %d\n", roundi(a+out_offset), roundi(b+out_offset));
+  else
+    fprintf(fp, qh_REAL_2n, a+out_offset, b+out_offset);
+} /* out2n */
+
+void out3n( double a, double b, double c) { 
+
+  if (isinteger)
+    fprintf(fp, "%d %d %d\n", roundi(a+out_offset), roundi(b+out_offset), roundi(c+out_offset));
+  else
+    fprintf(fp, qh_REAL_3n, a+out_offset, b+out_offset, c+out_offset);
+} /* out3n */
+
+/*-------------------------------------------------
+-rand & srand- generate pseudo-random number between 1 and 2^31 -2
+  from Park & Miller's minimimal standard random number generator
+  Communications of the ACM, 31:1192-1201, 1988.
+notes:
+  does not use 0 or 2^31 -1
+  this is silently enforced by qh_srand()
+  copied from geom2.c
+*/
+static int seed = 1;  /* global static */
+
+int qh_rand( void) {
+#define qh_rand_a 16807
+#define qh_rand_m 2147483647
+#define qh_rand_q 127773  /* m div a */
+#define qh_rand_r 2836    /* m mod a */
+  int lo, hi, test;
+
+  hi = seed / qh_rand_q;  /* seed div q */
+  lo = seed % qh_rand_q;  /* seed mod q */
+  test = qh_rand_a * lo - qh_rand_r * hi;
+  if (test > 0)
+    seed= test;
+  else
+    seed= test + qh_rand_m;
+  return seed;
+} /* rand */
+
+void qh_srand( int newseed) {
+  if (newseed < 1)
+    seed= 1;
+  else if (newseed >= qh_rand_m)
+    seed= qh_rand_m - 1;
+  else
+    seed= newseed;
+} /* qh_srand */
+
diff --git a/extern/qhull/src/stat.c b/extern/qhull/src/stat.c
new file mode 100644
index 00000000000..ede0323cb88
--- /dev/null
+++ b/extern/qhull/src/stat.c
@@ -0,0 +1,700 @@
+/*
  ---------------------------------
+
+   stat.c 
+   contains all statistics that are collected for qhull
+
+   see qh-stat.htm and stat.h
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#include "qhull_a.h"
+
+/*============ global data structure ==========*/
+
+#if qh_QHpointer
+qhstatT *qh_qhstat=NULL;  /* global data structure */
+#else
+qhstatT qh_qhstat;   /* add "={0}" if this causes a compiler error */
+#endif
+
+/*========== functions in alphabetic order ================*/
+
+/*---------------------------------
+  
+  qh_allstatA()
+    define statistics in groups of 20
+
+  notes:
+    (otherwise, 'gcc -O2' uses too much memory)
+    uses qhstat.next
+*/
+void qh_allstatA (void) {
+  
+   /* zdef_(type,name,doc,average) */
+  zzdef_(zdoc, Zdoc2, "precision statistics", -1);
+  zdef_(zinc, Znewvertex, NULL, -1);
+  zdef_(wadd, Wnewvertex, "ave. distance of a new vertex to a facet (not 0s)", Znewvertex);
+  zzdef_(wmax, Wnewvertexmax, "max. distance of a new vertex to a facet", -1);
+  zdef_(wmax, Wvertexmax, "max. distance of an output vertex to a facet", -1);
+  zdef_(wmin, Wvertexmin, "min. distance of an output vertex to a facet", -1);
+  zdef_(wmin, Wmindenom, "min. denominator in hyperplane computation", -1);
+
+  qhstat precision= qhstat next;  /* call qh_precision for each of these */
+  zzdef_(zdoc, Zdoc3, "precision problems (corrected unless 'Q0' or an error)", -1);
+  zzdef_(zinc, Zcoplanarridges, "coplanar half ridges in output", -1);
+  zzdef_(zinc, Zconcaveridges, "concave half ridges in output", -1);
+  zzdef_(zinc, Zflippedfacets, "flipped facets", -1);
+  zzdef_(zinc, Zcoplanarhorizon, "coplanar horizon facets for new vertices", -1);
+  zzdef_(zinc, Zcoplanarpart, "coplanar points during partitioning", -1);
+  zzdef_(zinc, Zminnorm, "degenerate hyperplanes recomputed with gaussian elimination", -1);
+  zzdef_(zinc, Znearlysingular, "nearly singular or axis-parallel hyperplanes", -1);
+  zzdef_(zinc, Zback0, "zero divisors during back substitute", -1);
+  zzdef_(zinc, Zgauss0, "zero divisors during gaussian elimination", -1);
+  zzdef_(zinc, Zmultiridge, "ridges with multiple neighbors", -1);
+}
+void qh_allstatB (void) {
+  zzdef_(zdoc, Zdoc1, "summary information", -1);
+  zdef_(zinc, Zvertices, "number of vertices in output", -1);
+  zdef_(zinc, Znumfacets, "number of facets in output", -1);
+  zdef_(zinc, Znonsimplicial, "number of non-simplicial facets in output", -1);
+  zdef_(zinc, Znowsimplicial, "number of simplicial facets that were merged", -1);
+  zdef_(zinc, Znumridges, "number of ridges in output", -1);
+  zdef_(zadd, Znumridges, "average number of ridges per facet", Znumfacets);
+  zdef_(zmax, Zmaxridges, "maximum number of ridges", -1);
+  zdef_(zadd, Znumneighbors, "average number of neighbors per facet", Znumfacets);
+  zdef_(zmax, Zmaxneighbors, "maximum number of neighbors", -1);
+  zdef_(zadd, Znumvertices, "average number of vertices per facet", Znumfacets);
+  zdef_(zmax, Zmaxvertices, "maximum number of vertices", -1);
+  zdef_(zadd, Znumvneighbors, "average number of neighbors per vertex", Zvertices);
+  zdef_(zmax, Zmaxvneighbors, "maximum number of neighbors", -1);
+  zdef_(wadd, Wcpu, "cpu seconds for qhull after input", -1);
+  zdef_(zinc, Ztotvertices, "vertices created altogether", -1);
+  zzdef_(zinc, Zsetplane, "facets created altogether", -1);
+  zdef_(zinc, Ztotridges, "ridges created altogether", -1);
+  zdef_(zinc, Zpostfacets, "facets before post merge", -1);
+  zdef_(zadd, Znummergetot, "average merges per facet (at most 511)", Znumfacets);
+  zdef_(zmax, Znummergemax, "  maximum merges for a facet (at most 511)", -1);
+  zdef_(zinc, Zangle, NULL, -1);
+  zdef_(wadd, Wangle, "average angle (cosine) of facet normals for all ridges", Zangle);
+  zdef_(wmax, Wanglemax, "  maximum angle (cosine) of facet normals across a ridge", -1);
+  zdef_(wmin, Wanglemin, "  minimum angle (cosine) of facet normals across a ridge", -1);
+  zdef_(wadd, Wareatot, "total area of facets", -1);
+  zdef_(wmax, Wareamax, "  maximum facet area", -1);
+  zdef_(wmin, Wareamin, "  minimum facet area", -1);
+}  
+void qh_allstatC (void) {
+  zdef_(zdoc, Zdoc9, "build hull statistics", -1);
+  zzdef_(zinc, Zprocessed, "points processed", -1);
+  zzdef_(zinc, Zretry, "retries due to precision problems", -1);
+  zdef_(wmax, Wretrymax, "  max. random joggle", -1);
+  zdef_(zmax, Zmaxvertex, "max. vertices at any one time", -1);
+  zdef_(zinc, Ztotvisible, "ave. visible facets per iteration", Zprocessed);
+  zdef_(zinc, Zinsidevisible, "  ave. visible facets without an horizon neighbor", Zprocessed);
+  zdef_(zadd, Zvisfacettot,  "  ave. facets deleted per iteration", Zprocessed);
+  zdef_(zmax, Zvisfacetmax,  "    maximum", -1);
+  zdef_(zadd, Zvisvertextot, "ave. visible vertices per iteration", Zprocessed);
+  zdef_(zmax, Zvisvertexmax, "    maximum", -1);
+  zdef_(zinc, Ztothorizon, "ave. horizon facets per iteration", Zprocessed);
+  zdef_(zadd, Znewfacettot,  "ave. new or merged facets per iteration", Zprocessed);
+  zdef_(zmax, Znewfacetmax,  "    maximum (includes initial simplex)", -1);
+  zdef_(wadd, Wnewbalance, "average new facet balance", Zprocessed);
+  zdef_(wadd, Wnewbalance2, "  standard deviation", -1);
+  zdef_(wadd, Wpbalance, "average partition balance", Zpbalance);
+  zdef_(wadd, Wpbalance2, "  standard deviation", -1);
+  zdef_(zinc, Zpbalance, "  number of trials", -1);
+  zdef_(zinc, Zsearchpoints, "searches of all points for initial simplex", -1);
+  zdef_(zinc, Zdetsimplex, "determinants computed (area & initial hull)", -1);
+  zdef_(zinc, Znoarea, "determinants not computed because vertex too low", -1);
+  zdef_(zinc, Znotmax, "points ignored (not above max_outside)", -1);
+  zdef_(zinc, Znotgood, "points ignored (not above a good facet)", -1);
+  zdef_(zinc, Znotgoodnew, "points ignored (didn't create a good new facet)", -1);
+  zdef_(zinc, Zgoodfacet, "good facets found", -1);
+  zzdef_(zinc, Znumvisibility, "distance tests for facet visibility", -1);
+  zdef_(zinc, Zdistvertex, "distance tests to report minimum vertex", -1);
+  zdef_(zinc, Ztotcheck, "points checked for facets' outer planes", -1);
+  zzdef_(zinc, Zcheckpart, "  ave. distance tests per check", Ztotcheck);
+}
+void qh_allstatD(void) {
+  zdef_(zdoc, Zdoc4, "partitioning statistics (see previous for outer planes)", -1);
+  zzdef_(zadd, Zdelvertextot, "total vertices deleted", -1);
+  zdef_(zmax, Zdelvertexmax, "    maximum vertices deleted per iteration", -1);
+  zdef_(zinc, Zfindbest, "calls to findbest", -1);
+  zdef_(zadd, Zfindbesttot, " ave. facets tested", Zfindbest);
+  zdef_(zmax, Zfindbestmax, " max. facets tested", -1);
+  zdef_(zadd, Zfindcoplanar, " ave. coplanar search", Zfindbest);
+  zdef_(zinc, Zfindnew, "calls to findbestnew", -1);
+  zdef_(zadd, Zfindnewtot, " ave. facets tested", Zfindnew);
+  zdef_(zmax, Zfindnewmax, " max. facets tested", -1);
+  zdef_(zinc, Zfindnewjump, " ave. clearly better", Zfindnew);
+  zdef_(zinc, Zfindnewsharp, " calls due to qh_sharpnewfacets", -1);
+  zdef_(zinc, Zfindhorizon, "calls to findhorizon", -1);
+  zdef_(zadd, Zfindhorizontot, " ave. facets tested", Zfindhorizon);
+  zdef_(zmax, Zfindhorizonmax, " max. facets tested", -1);
+  zdef_(zinc, Zfindjump,       " ave. clearly better", Zfindhorizon);
+  zdef_(zinc, Zparthorizon, " horizon facets better than bestfacet", -1);
+  zdef_(zinc, Zpartangle, "angle tests for repartitioned coplanar points", -1);
+  zdef_(zinc, Zpartflip, "  repartitioned coplanar points for flipped orientation", -1);
+  zdef_(zinc, Zpartinside, "inside points", -1);
+  zdef_(zinc, Zpartnear, "  inside points kept with a facet", -1);
+  zdef_(zinc, Zcoplanarinside, "  inside points that were coplanar with a facet", -1);
+  zdef_(wadd, Wmaxout, "difference in max_outside at final check", -1);
+}
+void qh_allstatE(void) {
+  zzdef_(zinc, Zpartitionall, "distance tests for initial partition", -1);
+  zdef_(zinc, Ztotpartition, "partitions of a point", -1);
+  zzdef_(zinc, Zpartition, "distance tests for partitioning", -1);
+  zzdef_(zinc, Zdistcheck, "distance tests for checking flipped facets", -1); 
+  zzdef_(zinc, Zdistconvex, "distance tests for checking convexity", -1); 
+  zdef_(zinc, Zdistgood, "distance tests for checking good point", -1); 
+  zdef_(zinc, Zdistio, "distance tests for output", -1); 
+  zdef_(zinc, Zdiststat, "distance tests for statistics", -1); 
+  zdef_(zinc, Zdistplane, "total number of distance tests", -1);
+  zdef_(zinc, Ztotpartcoplanar, "partitions of coplanar points or deleted vertices", -1);
+  zzdef_(zinc, Zpartcoplanar, "   distance tests for these partitions", -1);
+  zdef_(zinc, Zcomputefurthest, "distance tests for computing furthest", -1);
+}
+void qh_allstatE2(void) {
+  zdef_(zdoc, Zdoc5, "statistics for matching ridges", -1);
+  zdef_(zinc, Zhashlookup, "total lookups for matching ridges of new facets", -1);
+  zdef_(zinc, Zhashtests, "average number of tests to match a ridge", Zhashlookup);
+  zdef_(zinc, Zhashridge, "total lookups of subridges (duplicates and boundary)", -1);
+  zdef_(zinc, Zhashridgetest, "average number of tests per subridge", Zhashridge);
+  zdef_(zinc, Zdupsame, "duplicated ridges in same merge cycle", -1);
+  zdef_(zinc, Zdupflip, "duplicated ridges with flipped facets", -1);
+
+  zdef_(zdoc, Zdoc6, "statistics for determining merges", -1);
+  zdef_(zinc, Zangletests, "angles computed for ridge convexity", -1);
+  zdef_(zinc, Zbestcentrum, "best merges used centrum instead of vertices",-1);
+  zzdef_(zinc, Zbestdist, "distance tests for best merge", -1);
+  zzdef_(zinc, Zcentrumtests, "distance tests for centrum convexity", -1);
+  zzdef_(zinc, Zdistzero, "distance tests for checking simplicial convexity", -1);
+  zdef_(zinc, Zcoplanarangle, "coplanar angles in getmergeset", -1);
+  zdef_(zinc, Zcoplanarcentrum, "coplanar centrums in getmergeset", -1);
+  zdef_(zinc, Zconcaveridge, "concave ridges in getmergeset", -1);
+}
+void qh_allstatF(void) {
+  zdef_(zdoc, Zdoc7, "statistics for merging", -1);
+  zdef_(zinc, Zpremergetot, "merge iterations", -1);
+  zdef_(zadd, Zmergeinittot, "ave. initial non-convex ridges per iteration", Zpremergetot);
+  zdef_(zadd, Zmergeinitmax, "  maximum", -1);
+  zdef_(zadd, Zmergesettot, "  ave. additional non-convex ridges per iteration", Zpremergetot);
+  zdef_(zadd, Zmergesetmax, "  maximum additional in one pass", -1);
+  zdef_(zadd, Zmergeinittot2, "initial non-convex ridges for post merging", -1);
+  zdef_(zadd, Zmergesettot2, "  additional non-convex ridges", -1);
+  zdef_(wmax, Wmaxoutside, "max distance of vertex or coplanar point above facet (w/roundoff)", -1);
+  zdef_(wmin, Wminvertex, "max distance of merged vertex below facet (or roundoff)", -1);
+  zdef_(zinc, Zwidefacet, "centrums frozen due to a wide merge", -1);
+  zdef_(zinc, Zwidevertices, "centrums frozen due to extra vertices", -1);
+  zzdef_(zinc, Ztotmerge, "total number of facets or cycles of facets merged", -1);
+  zdef_(zinc, Zmergesimplex, "merged a simplex", -1);
+  zdef_(zinc, Zonehorizon, "simplices merged into coplanar horizon", -1);
+  zzdef_(zinc, Zcyclehorizon, "cycles of facets merged into coplanar horizon", -1);
+  zzdef_(zadd, Zcyclefacettot, "  ave. facets per cycle", Zcyclehorizon);
+  zdef_(zmax, Zcyclefacetmax, "  max. facets", -1);
+  zdef_(zinc, Zmergeintohorizon, "new facets merged into horizon", -1);
+  zdef_(zinc, Zmergenew, "new facets merged", -1);
+  zdef_(zinc, Zmergehorizon, "horizon facets merged into new facets", -1);
+  zdef_(zinc, Zmergevertex, "vertices deleted by merging", -1);
+  zdef_(zinc, Zcyclevertex, "vertices deleted by merging into coplanar horizon", -1);
+  zdef_(zinc, Zdegenvertex, "vertices deleted by degenerate facet", -1);
+  zdef_(zinc, Zmergeflipdup, "merges due to flipped facets in duplicated ridge", -1);
+  zdef_(zinc, Zneighbor, "merges due to redundant neighbors", -1);
+  zdef_(zadd, Ztestvneighbor, "non-convex vertex neighbors", -1); 
+}
+void qh_allstatG(void) {
+  zdef_(zinc, Zacoplanar, "merges due to angle coplanar facets", -1);
+  zdef_(wadd, Wacoplanartot, "  average merge distance", Zacoplanar);
+  zdef_(wmax, Wacoplanarmax, "  maximum merge distance", -1);
+  zdef_(zinc, Zcoplanar, "merges due to coplanar facets", -1);
+  zdef_(wadd, Wcoplanartot, "  average merge distance", Zcoplanar);
+  zdef_(wmax, Wcoplanarmax, "  maximum merge distance", -1);
+  zdef_(zinc, Zconcave, "merges due to concave facets", -1);
+  zdef_(wadd, Wconcavetot, "  average merge distance", Zconcave);
+  zdef_(wmax, Wconcavemax, "  maximum merge distance", -1);
+  zdef_(zinc, Zavoidold, "coplanar/concave merges due to avoiding old merge", -1);
+  zdef_(wadd, Wavoidoldtot, "  average merge distance", Zavoidold);
+  zdef_(wmax, Wavoidoldmax, "  maximum merge distance", -1);
+  zdef_(zinc, Zdegen, "merges due to degenerate facets", -1);
+  zdef_(wadd, Wdegentot, "  average merge distance", Zdegen);
+  zdef_(wmax, Wdegenmax, "  maximum merge distance", -1);
+  zdef_(zinc, Zflipped, "merges due to removing flipped facets", -1);
+  zdef_(wadd, Wflippedtot, "  average merge distance", Zflipped);
+  zdef_(wmax, Wflippedmax, "  maximum merge distance", -1);
+  zdef_(zinc, Zduplicate, "merges due to duplicated ridges", -1);
+  zdef_(wadd, Wduplicatetot, "  average merge distance", Zduplicate);
+  zdef_(wmax, Wduplicatemax, "  maximum merge distance", -1);
+}
+void qh_allstatH(void) {
+  zdef_(zdoc, Zdoc8, "renamed vertex statistics", -1);
+  zdef_(zinc, Zrenameshare, "renamed vertices shared by two facets", -1);
+  zdef_(zinc, Zrenamepinch, "renamed vertices in a pinched facet", -1);
+  zdef_(zinc, Zrenameall, "renamed vertices shared by multiple facets", -1);
+  zdef_(zinc, Zfindfail, "rename failures due to duplicated ridges", -1);
+  zdef_(zinc, Zdupridge, "  duplicate ridges detected", -1);
+  zdef_(zinc, Zdelridge, "deleted ridges due to renamed vertices", -1);
+  zdef_(zinc, Zdropneighbor, "dropped neighbors due to renamed vertices", -1);
+  zdef_(zinc, Zdropdegen, "degenerate facets due to dropped neighbors", -1);
+  zdef_(zinc, Zdelfacetdup, "  facets deleted because of no neighbors", -1);
+  zdef_(zinc, Zremvertex, "vertices removed from facets due to no ridges", -1);
+  zdef_(zinc, Zremvertexdel, "  deleted", -1);
+  zdef_(zinc, Zintersectnum, "vertex intersections for locating redundant vertices", -1);
+  zdef_(zinc, Zintersectfail, "intersections failed to find a redundant vertex", -1);
+  zdef_(zinc, Zintersect, "intersections found redundant vertices", -1);
+  zdef_(zadd, Zintersecttot, "   ave. number found per vertex", Zintersect);
+  zdef_(zmax, Zintersectmax, "   max. found for a vertex", -1);
+  zdef_(zinc, Zvertexridge, NULL, -1);
+  zdef_(zadd, Zvertexridgetot, "  ave. number of ridges per tested vertex", Zvertexridge);
+  zdef_(zmax, Zvertexridgemax, "  max. number of ridges per tested vertex", -1);
+
+  zdef_(zdoc, Zdoc10, "memory usage statistics (in bytes)", -1);
+  zdef_(zadd, Zmemfacets, "for facets and their normals, neighbor and vertex sets", -1);
+  zdef_(zadd, Zmemvertices, "for vertices and their neighbor sets", -1);
+  zdef_(zadd, Zmempoints, "for input points and outside and coplanar sets",-1);
+  zdef_(zadd, Zmemridges, "for ridges and their vertex sets", -1);
+} /* allstat */
+
+void qh_allstatI(void) {
+  qhstat vridges= qhstat next;
+  zzdef_(zdoc, Zdoc11, "Voronoi ridge statistics", -1);
+  zzdef_(zinc, Zridge, "non-simplicial Voronoi vertices for all ridges", -1);
+  zzdef_(wadd, Wridge, "  ave. distance to ridge", Zridge);
+  zzdef_(wmax, Wridgemax, "  max. distance to ridge", -1);
+  zzdef_(zinc, Zridgemid, "bounded ridges", -1);
+  zzdef_(wadd, Wridgemid, "  ave. distance of midpoint to ridge", Zridgemid);
+  zzdef_(wmax, Wridgemidmax, "  max. distance of midpoint to ridge", -1);
+  zzdef_(zinc, Zridgeok, "bounded ridges with ok normal", -1);
+  zzdef_(wadd, Wridgeok, "  ave. angle to ridge", Zridgeok);
+  zzdef_(wmax, Wridgeokmax, "  max. angle to ridge", -1);
+  zzdef_(zinc, Zridge0, "bounded ridges with near-zero normal", -1);
+  zzdef_(wadd, Wridge0, "  ave. angle to ridge", Zridge0);
+  zzdef_(wmax, Wridge0max, "  max. angle to ridge", -1);
+
+  zdef_(zdoc, Zdoc12, "Triangulation statistics (Qt)", -1);
+  zdef_(zinc, Ztricoplanar, "non-simplicial facets triangulated", -1);
+  zdef_(zadd, Ztricoplanartot, "  ave. new facets created (may be deleted)", Ztricoplanar);
+  zdef_(zmax, Ztricoplanarmax, "  max. new facets created", -1);
+  zdef_(zinc, Ztrinull, "null new facets deleted (duplicated vertex)", -1);
+  zdef_(zinc, Ztrimirror, "mirrored pairs of new facets deleted (same vertices)", -1);
+  zdef_(zinc, Ztridegen, "degenerate new facets in output (same ridge)", -1);
+} /* allstat */
+
+/*---------------------------------
+  
+  qh_allstatistics()
+    reset printed flag for all statistics
+*/
+void qh_allstatistics (void) {
+  int i;
+  
+  for (i=ZEND; i--; ) 
+    qhstat printed[i]= False;
+} /* allstatistics */
+
+#if qh_KEEPstatistics
+/*---------------------------------
+  
+  qh_collectstatistics()
+    collect statistics for qh.facet_list
+
+*/
+void qh_collectstatistics (void) {
+  facetT *facet, *neighbor, **neighborp;
+  vertexT *vertex, **vertexp;
+  realT dotproduct, dist;
+  int sizneighbors, sizridges, sizvertices, i;
+  
+  qh old_randomdist= qh RANDOMdist;
+  qh RANDOMdist= False;
+  zval_(Zmempoints)= qh num_points * qh normal_size + 
+                             sizeof (qhT) + sizeof (qhstatT);
+  zval_(Zmemfacets)= 0;
+  zval_(Zmemridges)= 0;
+  zval_(Zmemvertices)= 0;
+  zval_(Zangle)= 0;
+  wval_(Wangle)= 0.0;
+  zval_(Znumridges)= 0;
+  zval_(Znumfacets)= 0;
+  zval_(Znumneighbors)= 0;
+  zval_(Znumvertices)= 0;
+  zval_(Znumvneighbors)= 0;
+  zval_(Znummergetot)= 0;
+  zval_(Znummergemax)= 0;
+  zval_(Zvertices)= qh num_vertices - qh_setsize (qh del_vertices);
+  if (qh MERGING || qh APPROXhull || qh JOGGLEmax < REALmax/2)
+    wmax_(Wmaxoutside, qh max_outside);
+  if (qh MERGING)
+    wmin_(Wminvertex, qh min_vertex);
+  FORALLfacets
+    facet->seen= False;
+  if (qh DELAUNAY) {
+    FORALLfacets {
+      if (facet->upperdelaunay != qh UPPERdelaunay)
+        facet->seen= True; /* remove from angle statistics */
+    }
+  }
+  FORALLfacets {
+    if (facet->visible && qh NEWfacets)
+      continue;
+    sizvertices= qh_setsize (facet->vertices);
+    sizneighbors= qh_setsize (facet->neighbors);
+    sizridges= qh_setsize (facet->ridges);
+    zinc_(Znumfacets);
+    zadd_(Znumvertices, sizvertices);
+    zmax_(Zmaxvertices, sizvertices);
+    zadd_(Znumneighbors, sizneighbors);
+    zmax_(Zmaxneighbors, sizneighbors);
+    zadd_(Znummergetot, facet->nummerge);
+    i= facet->nummerge; /* avoid warnings */
+    zmax_(Znummergemax, i); 
+    if (!facet->simplicial) {
+      if (sizvertices == qh hull_dim) {
+	zinc_(Znowsimplicial);
+      }else {
+        zinc_(Znonsimplicial);
+      }
+    }
+    if (sizridges) {
+      zadd_(Znumridges, sizridges);
+      zmax_(Zmaxridges, sizridges);
+    }
+    zadd_(Zmemfacets, sizeof (facetT) + qh normal_size + 2*sizeof (setT) 
+       + SETelemsize * (sizneighbors + sizvertices));
+    if (facet->ridges) {
+      zadd_(Zmemridges,
+	 sizeof (setT) + SETelemsize * sizridges + sizridges * 
+         (sizeof (ridgeT) + sizeof (setT) + SETelemsize * (qh hull_dim-1))/2);
+    }
+    if (facet->outsideset)
+      zadd_(Zmempoints, sizeof (setT) + SETelemsize * qh_setsize (facet->outsideset));
+    if (facet->coplanarset)
+      zadd_(Zmempoints, sizeof (setT) + SETelemsize * qh_setsize (facet->coplanarset));
+    if (facet->seen) /* Delaunay upper envelope */
+      continue;
+    facet->seen= True;
+    FOREACHneighbor_(facet) {
+      if (neighbor == qh_DUPLICATEridge || neighbor == qh_MERGEridge
+	  || neighbor->seen || !facet->normal || !neighbor->normal)
+	continue;
+      dotproduct= qh_getangle(facet->normal, neighbor->normal);
+      zinc_(Zangle);
+      wadd_(Wangle, dotproduct);
+      wmax_(Wanglemax, dotproduct)
+      wmin_(Wanglemin, dotproduct)
+    }
+    if (facet->normal) {
+      FOREACHvertex_(facet->vertices) {
+        zinc_(Zdiststat);
+        qh_distplane(vertex->point, facet, &dist);
+        wmax_(Wvertexmax, dist);
+        wmin_(Wvertexmin, dist);
+      }
+    }
+  }
+  FORALLvertices {
+    if (vertex->deleted)
+      continue;
+    zadd_(Zmemvertices, sizeof (vertexT));
+    if (vertex->neighbors) {
+      sizneighbors= qh_setsize (vertex->neighbors);
+      zadd_(Znumvneighbors, sizneighbors);
+      zmax_(Zmaxvneighbors, sizneighbors);
+      zadd_(Zmemvertices, sizeof (vertexT) + SETelemsize * sizneighbors);
+    }
+  }
+  qh RANDOMdist= qh old_randomdist;
+} /* collectstatistics */
+#endif /* qh_KEEPstatistics */
+
+/*---------------------------------
+  
+  qh_freestatistics(  )
+    free memory used for statistics
+*/
+void qh_freestatistics (void) {
+
+#if qh_QHpointer
+  free (qh_qhstat);
+  qh_qhstat= NULL;
+#endif
+} /* freestatistics */
+
+/*---------------------------------
+  
+  qh_initstatistics(  )
+    allocate and initialize statistics
+
+  notes:
+    uses malloc() instead of qh_memalloc() since mem.c not set up yet
+*/
+void qh_initstatistics (void) {
+  int i;
+  realT realx;
+  int intx;
+
+#if qh_QHpointer
+  if (!(qh_qhstat= (qhstatT *)malloc (sizeof(qhstatT)))) {
+    fprintf (qhmem.ferr, "qhull error (qh_initstatistics): insufficient memory\n");
+    exit (1);  /* can not use qh_errexit() */
+  }
+#endif
+  
+  qhstat next= 0;
+  qh_allstatA();
+  qh_allstatB();
+  qh_allstatC();
+  qh_allstatD();
+  qh_allstatE();
+  qh_allstatE2();
+  qh_allstatF();
+  qh_allstatG();
+  qh_allstatH();
+  qh_allstatI();
+  if (qhstat next > sizeof(qhstat id)) {
+    fprintf (qhmem.ferr, "qhull error (qh_initstatistics): increase size of qhstat.id[].\n\
+      qhstat.next %d should be <= sizeof(qhstat id) %ld\n", qhstat next, sizeof(qhstat id));
+#if 0 /* for locating error, Znumridges should be duplicated */
+    for (i=0; i < ZEND; i++) {
+      int j;
+      for (j=i+1; j < ZEND; j++) {
+	if (qhstat id[i] == qhstat id[j]) {
+          fprintf (qhmem.ferr, "qhull error (qh_initstatistics): duplicated statistic %d at indices %d and %d\n", 
+	      qhstat id[i], i, j);
+	}
+      }
+    }
+#endif 
+    exit (1);  /* can not use qh_errexit() */
+  }
+  qhstat init[zinc].i= 0;
+  qhstat init[zadd].i= 0;
+  qhstat init[zmin].i= INT_MAX;
+  qhstat init[zmax].i= INT_MIN;
+  qhstat init[wadd].r= 0;
+  qhstat init[wmin].r= REALmax;
+  qhstat init[wmax].r= -REALmax;
+  for (i=0; i < ZEND; i++) {
+    if (qhstat type[i] > ZTYPEreal) {
+      realx= qhstat init[(unsigned char)(qhstat type[i])].r;
+      qhstat stats[i].r= realx;
+    }else if (qhstat type[i] != zdoc) {
+      intx= qhstat init[(unsigned char)(qhstat type[i])].i;
+      qhstat stats[i].i= intx;
+    }
+  }
+} /* initstatistics */
+
+/*---------------------------------
+  
+  qh_newstats(  )
+    returns True if statistics for zdoc
+
+  returns:
+    next zdoc
+*/
+boolT qh_newstats (int index, int *nextindex) {
+  boolT isnew= False;
+  int start, i;
+
+  if (qhstat type[qhstat id[index]] == zdoc) 
+    start= index+1;
+  else
+    start= index;
+  for (i= start; i < qhstat next && qhstat type[qhstat id[i]] != zdoc; i++) {
+    if (!qh_nostatistic(qhstat id[i]) && !qhstat printed[qhstat id[i]])
+	isnew= True;
+  }
+  *nextindex= i;
+  return isnew;
+} /* newstats */
+
+/*---------------------------------
+  
+  qh_nostatistic( index )
+    true if no statistic to print
+*/
+boolT qh_nostatistic (int i) {
+  
+  if ((qhstat type[i] > ZTYPEreal
+       &&qhstat stats[i].r == qhstat init[(unsigned char)(qhstat type[i])].r)
+      || (qhstat type[i] < ZTYPEreal
+	  &&qhstat stats[i].i == qhstat init[(unsigned char)(qhstat type[i])].i))
+    return True;
+  return False;
+} /* nostatistic */
+
+#if qh_KEEPstatistics
+/*---------------------------------
+  
+  qh_printallstatistics( fp, string )
+    print all statistics with header 'string'
+*/
+void qh_printallstatistics (FILE *fp, char *string) {
+
+  qh_allstatistics();
+  qh_collectstatistics();
+  qh_printstatistics (fp, string);
+  qh_memstatistics (fp);
+}
+
+
+/*---------------------------------
+  
+  qh_printstatistics( fp, string )
+    print statistics to a file with header 'string'
+    skips statistics with qhstat.printed[] (reset with qh_allstatistics)
+
+  see: 
+    qh_printallstatistics()
+*/
+void qh_printstatistics (FILE *fp, char *string) {
+  int i, k;
+  realT ave;
+  
+  if (qh num_points != qh num_vertices) {
+    wval_(Wpbalance)= 0;
+    wval_(Wpbalance2)= 0;
+  }else
+    wval_(Wpbalance2)= qh_stddev (zval_(Zpbalance), wval_(Wpbalance), 
+                                 wval_(Wpbalance2), &ave);
+  wval_(Wnewbalance2)= qh_stddev (zval_(Zprocessed), wval_(Wnewbalance), 
+                                 wval_(Wnewbalance2), &ave);
+  fprintf (fp, "\n\
+%s\n\
+ qhull invoked by: %s | %s\n%s with options:\n%s\n", string, qh rbox_command, 
+     qh qhull_command, qh_VERSION, qh qhull_options);
+  fprintf (fp, "\nprecision constants:\n\
+ %6.2g max. abs. coordinate in the (transformed) input ('Qbd:n')\n\
+ %6.2g max. roundoff error for distance computation ('En')\n\
+ %6.2g max. roundoff error for angle computations\n\
+ %6.2g min. distance for outside points ('Wn')\n\
+ %6.2g min. distance for visible facets ('Vn')\n\
+ %6.2g max. distance for coplanar facets ('Un')\n\
+ %6.2g max. facet width for recomputing centrum and area\n\
+", 
+  qh MAXabs_coord, qh DISTround, qh ANGLEround, qh MINoutside, 
+        qh MINvisible, qh MAXcoplanar, qh WIDEfacet);
+  if (qh KEEPnearinside)
+    fprintf(fp, "\
+ %6.2g max. distance for near-inside points\n", qh NEARinside);
+  if (qh premerge_cos < REALmax/2) fprintf (fp, "\
+ %6.2g max. cosine for pre-merge angle\n", qh premerge_cos);
+  if (qh PREmerge) fprintf (fp, "\
+ %6.2g radius of pre-merge centrum\n", qh premerge_centrum);
+  if (qh postmerge_cos < REALmax/2) fprintf (fp, "\
+ %6.2g max. cosine for post-merge angle\n", qh postmerge_cos);
+  if (qh POSTmerge) fprintf (fp, "\
+ %6.2g radius of post-merge centrum\n", qh postmerge_centrum);
+  fprintf (fp, "\
+ %6.2g max. distance for merging two simplicial facets\n\
+ %6.2g max. roundoff error for arithmetic operations\n\
+ %6.2g min. denominator for divisions\n\
+  zero diagonal for Gauss: ", qh ONEmerge, REALepsilon, qh MINdenom);
+  for (k=0; k < qh hull_dim; k++)
+    fprintf (fp, "%6.2e ", qh NEARzero[k]);
+  fprintf (fp, "\n\n");
+  for (i=0 ; i < qhstat next; ) 
+    qh_printstats (fp, i, &i);
+} /* printstatistics */
+#endif /* qh_KEEPstatistics */
+
+/*---------------------------------
+  
+  qh_printstatlevel( fp, id )
+    print level information for a statistic
+
+  notes:
+    nop if id >= ZEND, printed, or same as initial value
+*/
+void qh_printstatlevel (FILE *fp, int id, int start) {
+#define NULLfield "       "
+
+  if (id >= ZEND || qhstat printed[id])
+    return;
+  if (qhstat type[id] == zdoc) {
+    fprintf (fp, "%s\n", qhstat doc[id]);
+    return;
+  }
+  start= 0; /* not used */
+  if (qh_nostatistic(id) || !qhstat doc[id])
+    return;
+  qhstat printed[id]= True;
+  if (qhstat count[id] != -1 
+      && qhstat stats[(unsigned char)(qhstat count[id])].i == 0)
+    fprintf (fp, " *0 cnt*");
+  else if (qhstat type[id] >= ZTYPEreal && qhstat count[id] == -1)
+    fprintf (fp, "%7.2g", qhstat stats[id].r);
+  else if (qhstat type[id] >= ZTYPEreal && qhstat count[id] != -1)
+    fprintf (fp, "%7.2g", qhstat stats[id].r/ qhstat stats[(unsigned char)(qhstat count[id])].i);
+  else if (qhstat type[id] < ZTYPEreal && qhstat count[id] == -1)
+    fprintf (fp, "%7d", qhstat stats[id].i);
+  else if (qhstat type[id] < ZTYPEreal && qhstat count[id] != -1)
+    fprintf (fp, "%7.3g", (realT) qhstat stats[id].i / qhstat stats[(unsigned char)(qhstat count[id])].i);
+  fprintf (fp, " %s\n", qhstat doc[id]);
+} /* printstatlevel */
+
+
+/*---------------------------------
+  
+  qh_printstats( fp, index, nextindex )
+    print statistics for a zdoc group
+
+  returns:
+    next zdoc if non-null
+*/
+void qh_printstats (FILE *fp, int index, int *nextindex) {
+  int j, nexti;
+
+  if (qh_newstats (index, &nexti)) {
+    fprintf (fp, "\n");
+    for (j=index; j--------------------------------
+  
+  qh_stddev( num, tot, tot2, ave )
+    compute the standard deviation and average from statistics
+
+    tot2 is the sum of the squares
+  notes:
+    computes r.m.s.: 
+      (x-ave)^2 
+      == x^2 - 2x tot/num +   (tot/num)^2
+      == tot2 - 2 tot tot/num + tot tot/num 
+      == tot2 - tot ave
+*/
+realT qh_stddev (int num, realT tot, realT tot2, realT *ave) {
+  realT stddev;
+
+  *ave= tot/num;
+  stddev= sqrt (tot2/num - *ave * *ave);
+  return stddev;
+} /* stddev */
+
+#endif /* qh_KEEPstatistics */ 
+
+#if !qh_KEEPstatistics
+void    qh_collectstatistics (void) {}
+void    qh_printallstatistics (FILE *fp, char *string) {};
+void    qh_printstatistics (FILE *fp, char *string) {}
+#endif
+
diff --git a/extern/qhull/src/stat.h b/extern/qhull/src/stat.h
new file mode 100644
index 00000000000..1dae54ed21d
--- /dev/null
+++ b/extern/qhull/src/stat.h
@@ -0,0 +1,520 @@
+  /*
  ---------------------------------
+
+   stat.h 
+     contains all statistics that are collected for qhull
+
+   see qh-stat.htm and stat.c
+
+   copyright (c) 1993-2002, The Geometry Center
+
+   recompile qhull if you change this file
+
+   Integer statistics are Z* while real statistics are W*.  
+
+   define maydebugx to call a routine at every statistic event
+
+*/
+
+#ifndef qhDEFstat
+#define qhDEFstat 1
+
+
+/*---------------------------------
+
+  qh_KEEPstatistics
+    0 turns off statistic gathering (except zzdef/zzinc/zzadd/zzval/wwval)
+*/
+#ifndef qh_KEEPstatistics
+#define qh_KEEPstatistics 1
+#endif
+
+/*---------------------------------
+
+  Zxxx for integers, Wxxx for reals
+
+  notes:
+    be sure that all statistics are defined in stat.c
+      otherwise initialization may core dump
+    can pick up all statistics by:
+      grep '[zw].*_[(][ZW]' *.c >z.x
+    remove trailers with query">-
+    remove leaders with  query-replace-regexp [ ^I]+  (
+*/
+#if qh_KEEPstatistics
+enum statistics {     /* alphabetical after Z/W */
+    Zacoplanar,
+    Wacoplanarmax,
+    Wacoplanartot,
+    Zangle,
+    Wangle,
+    Wanglemax,
+    Wanglemin,
+    Zangletests,
+    Wareatot,
+    Wareamax,
+    Wareamin,
+    Zavoidold,
+    Wavoidoldmax,
+    Wavoidoldtot,
+    Zback0,
+    Zbestcentrum,
+    Zbestdist,
+    Zcentrumtests,
+    Zcheckpart,
+    Zcomputefurthest,
+    Zconcave,
+    Wconcavemax,
+    Wconcavetot,
+    Zconcaveridges,
+    Zconcaveridge,
+    Zcoplanar,
+    Wcoplanarmax,
+    Wcoplanartot,
+    Zcoplanarangle,
+    Zcoplanarcentrum,
+    Zcoplanarhorizon,
+    Zcoplanarinside,
+    Zcoplanarpart,
+    Zcoplanarridges,
+    Wcpu,
+    Zcyclefacetmax,
+    Zcyclefacettot,
+    Zcyclehorizon,
+    Zcyclevertex,
+    Zdegen,
+    Wdegenmax,
+    Wdegentot,
+    Zdegenvertex,
+    Zdelfacetdup, 
+    Zdelridge,
+    Zdelvertextot,
+    Zdelvertexmax,
+    Zdetsimplex,
+    Zdistcheck,
+    Zdistconvex,
+    Zdistgood,
+    Zdistio,
+    Zdistplane,
+    Zdiststat,
+    Zdistvertex,
+    Zdistzero,
+    Zdoc1,
+    Zdoc2,
+    Zdoc3,
+    Zdoc4,
+    Zdoc5,
+    Zdoc6,
+    Zdoc7,
+    Zdoc8,
+    Zdoc9,
+    Zdoc10,
+    Zdoc11,
+    Zdoc12,
+    Zdropdegen,
+    Zdropneighbor,
+    Zdupflip,
+    Zduplicate,
+    Wduplicatemax,
+    Wduplicatetot,
+    Zdupridge,
+    Zdupsame,
+    Zflipped, 
+    Wflippedmax, 
+    Wflippedtot, 
+    Zflippedfacets,
+    Zfindbest,
+    Zfindbestmax,
+    Zfindbesttot,
+    Zfindcoplanar,
+    Zfindfail,
+    Zfindhorizon,
+    Zfindhorizonmax,
+    Zfindhorizontot,
+    Zfindjump,
+    Zfindnew,
+    Zfindnewmax,
+    Zfindnewtot,
+    Zfindnewjump,
+    Zfindnewsharp,
+    Zgauss0,
+    Zgoodfacet,
+    Zhashlookup,
+    Zhashridge,
+    Zhashridgetest,
+    Zhashtests,
+    Zinsidevisible,
+    Zintersect,
+    Zintersectfail,
+    Zintersectmax,
+    Zintersectnum,
+    Zintersecttot,
+    Zmaxneighbors,
+    Wmaxout,
+    Wmaxoutside,
+    Zmaxridges,
+    Zmaxvertex,
+    Zmaxvertices,
+    Zmaxvneighbors,
+    Zmemfacets,
+    Zmempoints,
+    Zmemridges,
+    Zmemvertices,
+    Zmergeflipdup,
+    Zmergehorizon,
+    Zmergeinittot,
+    Zmergeinitmax,
+    Zmergeinittot2,
+    Zmergeintohorizon,
+    Zmergenew,
+    Zmergesettot,
+    Zmergesetmax,
+    Zmergesettot2,
+    Zmergesimplex,
+    Zmergevertex,
+    Wmindenom,
+    Wminvertex,
+    Zminnorm,
+    Zmultiridge,
+    Znearlysingular,
+    Zneighbor,
+    Wnewbalance,
+    Wnewbalance2,
+    Znewfacettot,
+    Znewfacetmax,
+    Znewvertex,
+    Wnewvertex,
+    Wnewvertexmax,
+    Znoarea,
+    Znonsimplicial,
+    Znowsimplicial,
+    Znotgood,
+    Znotgoodnew,
+    Znotmax,
+    Znumfacets,
+    Znummergemax,
+    Znummergetot,
+    Znumneighbors,
+    Znumridges,
+    Znumvertices,
+    Znumvisibility,
+    Znumvneighbors,
+    Zonehorizon,
+    Zpartangle,
+    Zpartcoplanar,
+    Zpartflip,
+    Zparthorizon,
+    Zpartinside,
+    Zpartition, 
+    Zpartitionall,
+    Zpartnear,
+    Zpbalance,
+    Wpbalance,
+    Wpbalance2, 
+    Zpostfacets, 
+    Zpremergetot,
+    Zprocessed,
+    Zremvertex,
+    Zremvertexdel,
+    Zrenameall,
+    Zrenamepinch,
+    Zrenameshare,
+    Zretry,
+    Wretrymax,
+    Zridge,
+    Wridge,
+    Wridgemax,
+    Zridge0,
+    Wridge0,
+    Wridge0max,
+    Zridgemid,
+    Wridgemid,
+    Wridgemidmax,
+    Zridgeok,
+    Wridgeok,
+    Wridgeokmax,
+    Zsearchpoints,
+    Zsetplane,
+    Ztestvneighbor,
+    Ztotcheck,
+    Ztothorizon,
+    Ztotmerge,
+    Ztotpartcoplanar,
+    Ztotpartition,
+    Ztotridges,
+    Ztotvertices,
+    Ztotvisible,
+    Ztricoplanar,
+    Ztricoplanarmax,
+    Ztricoplanartot,
+    Ztridegen,
+    Ztrimirror,
+    Ztrinull,
+    Wvertexmax,
+    Wvertexmin,
+    Zvertexridge,
+    Zvertexridgetot,
+    Zvertexridgemax,
+    Zvertices,
+    Zvisfacettot,
+    Zvisfacetmax,
+    Zvisvertextot,
+    Zvisvertexmax,
+    Zwidefacet,
+    Zwidevertices,
+    ZEND};
+
+/*---------------------------------
+
+  Zxxx/Wxxx statistics that remain defined if qh_KEEPstatistics=0
+
+  notes:
+    be sure to use zzdef, zzinc, etc. with these statistics (no double checking!)
+*/
+#else
+enum statistics {     /* for zzdef etc. macros */
+  Zback0,
+  Zbestdist,
+  Zcentrumtests,
+  Zcheckpart,
+  Zconcaveridges,
+  Zcoplanarhorizon,
+  Zcoplanarpart,
+  Zcoplanarridges,
+  Zcyclefacettot,
+  Zcyclehorizon,
+  Zdelvertextot,
+  Zdistcheck,
+  Zdistconvex,
+  Zdistzero,
+  Zdoc1,
+  Zdoc2,
+  Zdoc3,
+  Zdoc11,
+  Zflippedfacets,
+  Zgauss0,
+  Zminnorm,
+  Zmultiridge,
+  Znearlysingular,
+  Wnewvertexmax,
+  Znumvisibility,
+  Zpartcoplanar,
+  Zpartition,
+  Zpartitionall,
+  Zprocessed,
+  Zretry,
+  Zridge,
+  Wridge,
+  Wridgemax,
+  Zridge0,
+  Wridge0,
+  Wridge0max,
+  Zridgemid,
+  Wridgemid,
+  Wridgemidmax,
+  Zridgeok,
+  Wridgeok,
+  Wridgeokmax,
+  Zsetplane,
+  Ztotmerge,
+    ZEND};
+#endif
+
+/*---------------------------------
+  
+  ztype
+    the type of a statistic sets its initial value.  
+
+  notes:
+    The type should be the same as the macro for collecting the statistic
+*/
+enum ztypes {zdoc,zinc,zadd,zmax,zmin,ZTYPEreal,wadd,wmax,wmin,ZTYPEend};
+
+/*========== macros and constants =============*/
+
+/*----------------------------------
+  
+  MAYdebugx
+    define as maydebug() to be called frequently for error trapping
+*/
+#define MAYdebugx 
+
+/*----------------------------------
+  
+  zzdef_, zdef_( type, name, doc, -1)
+    define a statistic (assumes 'qhstat.next= 0;')
+
+  zdef_( type, name, doc, count)
+    define an averaged statistic
+    printed as name/count
+*/
+#define zzdef_(stype,name,string,cnt) qhstat id[qhstat next++]=name; \
+   qhstat doc[name]= string; qhstat count[name]= cnt; qhstat type[name]= stype
+#if qh_KEEPstatistics
+#define zdef_(stype,name,string,cnt) qhstat id[qhstat next++]=name; \
+   qhstat doc[name]= string; qhstat count[name]= cnt; qhstat type[name]= stype
+#else
+#define zdef_(type,name,doc,count)
+#endif
+
+/*----------------------------------
+  
+  zzinc_( name ), zinc_( name)
+    increment an integer statistic
+*/
+#define zzinc_(id) {MAYdebugx; qhstat stats[id].i++;}
+#if qh_KEEPstatistics
+#define zinc_(id) {MAYdebugx; qhstat stats[id].i++;}
+#else
+#define zinc_(id) {}
+#endif
+
+/*----------------------------------
+  
+  zzadd_( name, value ), zadd_( name, value ), wadd_( name, value )
+    add value to an integer or real statistic
+*/
+#define zzadd_(id, val) {MAYdebugx; qhstat stats[id].i += (val);}
+#define wwadd_(id, val) {MAYdebugx; qhstat stats[id].r += (val);}
+#if qh_KEEPstatistics
+#define zadd_(id, val) {MAYdebugx; qhstat stats[id].i += (val);}
+#define wadd_(id, val) {MAYdebugx; qhstat stats[id].r += (val);}
+#else
+#define zadd_(id, val) {}
+#define wadd_(id, val) {}
+#endif
+
+/*----------------------------------
+
+  zzval_( name ), zval_( name ), wwval_( name )
+    set or return value of a statistic
+*/
+#define zzval_(id) ((qhstat stats[id]).i)
+#define wwval_(id) ((qhstat stats[id]).r)
+#if qh_KEEPstatistics
+#define zval_(id) ((qhstat stats[id]).i)
+#define wval_(id) ((qhstat stats[id]).r)
+#else
+#define zval_(id) qhstat tempi
+#define wval_(id) qhstat tempr
+#endif
+
+/*----------------------------------
+
+  zmax_( id, val ), wmax_( id, value )
+    maximize id with val
+*/
+#define wwmax_(id, val) {MAYdebugx; maximize_(qhstat stats[id].r,(val));}
+#if qh_KEEPstatistics
+#define zmax_(id, val) {MAYdebugx; maximize_(qhstat stats[id].i,(val));}
+#define wmax_(id, val) {MAYdebugx; maximize_(qhstat stats[id].r,(val));}
+#else
+#define zmax_(id, val) {}
+#define wmax_(id, val) {}
+#endif
+
+/*----------------------------------
+
+  zmin_( id, val ), wmin_( id, value )
+    minimize id with val
+*/
+#if qh_KEEPstatistics
+#define zmin_(id, val) {MAYdebugx; minimize_(qhstat stats[id].i,(val));}
+#define wmin_(id, val) {MAYdebugx; minimize_(qhstat stats[id].r,(val));}
+#else
+#define zmin_(id, val) {}
+#define wmin_(id, val) {}
+#endif
+
+/*================== stat.h types ==============*/
+
+
+/*----------------------------------
+ 
+  intrealT
+    union of integer and real, used for statistics
+*/
+typedef union intrealT intrealT;    /* union of int and realT */
+union intrealT {
+    int i;
+    realT r;
+};
+
+/*----------------------------------
+  
+  qhstat
+    global data structure for statistics
+  
+  notes:
+   access to qh_qhstat is via the "qhstat" macro.  There are two choices
+   qh_QHpointer = 1     access globals via a pointer
+                        enables qh_saveqhull() and qh_restoreqhull()
+		= 0     qh_qhstat is a static data structure
+		        only one instance of qhull() can be active at a time
+			default value
+   qh_QHpointer is defined in qhull.h
+
+   allocated in stat.c
+*/
+typedef struct qhstatT qhstatT; 
+#if qh_QHpointer
+#define qhstat qh_qhstat->
+extern qhstatT *qh_qhstat;
+#else
+#define qhstat qh_qhstat.
+extern qhstatT qh_qhstat; 
+#endif
+struct qhstatT {  
+  intrealT   stats[ZEND];     /* integer and real statistics */
+  unsigned   char id[ZEND+10]; /* id's in print order */
+  char      *doc[ZEND];       /* array of documentation strings */
+  short int  count[ZEND];     /* -1 if none, else index of count to use */
+  char       type[ZEND];      /* type, see ztypes above */
+  char       printed[ZEND];   /* true, if statistic has been printed */
+  intrealT   init[ZTYPEend];  /* initial values by types, set initstatistics */
+
+  int        next;            /* next index for zdef_ */
+  int        precision;       /* index for precision problems */
+  int        vridges;         /* index for Voronoi ridges */
+  int        tempi;
+  realT      tempr;
+};
+
+/*========== function prototypes ===========*/
+
+void    qh_allstatA(void);
+void    qh_allstatB(void);
+void    qh_allstatC(void);
+void    qh_allstatD(void);
+void    qh_allstatE(void);
+void    qh_allstatE2(void);
+void    qh_allstatF(void);
+void    qh_allstatG(void);
+void    qh_allstatH(void);
+void    qh_allstatI(void);
+void    qh_allstatistics (void);
+void    qh_collectstatistics (void);
+void	qh_freestatistics (void);
+void    qh_initstatistics (void);
+boolT 	qh_newstats (int index, int *nextindex);
+boolT 	qh_nostatistic (int i);
+void    qh_printallstatistics (FILE *fp, char *string);
+void    qh_printstatistics (FILE *fp, char *string);
+void  	qh_printstatlevel (FILE *fp, int id, int start);
+void  	qh_printstats (FILE *fp, int index, int *nextindex);
+realT   qh_stddev (int num, realT tot, realT tot2, realT *ave);
+
+#endif   /* qhDEFstat */
diff --git a/extern/qhull/src/unix.c b/extern/qhull/src/unix.c
new file mode 100644
index 00000000000..5ec5feab16c
--- /dev/null
+++ b/extern/qhull/src/unix.c
@@ -0,0 +1,376 @@
+/*
  ---------------------------------
+
+   unix.c
+     command line interface to qhull
+	 includes SIOUX interface for Macintoshes
+
+   see qh-qhull.htm
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "qhull.h"
+#include "mem.h"
+#include "qset.h"
+
+#if __MWERKS__ && __POWERPC__
+#include 
+#include 
+#include 
+#include 
+
+#elif __cplusplus
+extern "C" {
+  int isatty (int);
+}
+
+#elif _MSC_VER
+#include 
+#define isatty _isatty
+
+#else
+int isatty (int);  /* returns 1 if stdin is a tty
+		   if "Undefined symbol" this can be deleted along with call in main() */
+#endif
+
+/*---------------------------------
+
+  qh_prompt 
+    long prompt for qhull
+    
+  see:
+    concise prompt below
+*/  
+char qh_prompta[]= "\n\
+qhull- compute convex hulls and related structures.\n\
+    http://www.geom.umn.edu/software/qhull  %s\n\
+\n\
+input (stdin):\n\
+    first lines: dimension and number of points (or vice-versa).\n\
+    other lines: point coordinates, best if one point per line\n\
+    comments:    start with a non-numeric character\n\
+    halfspaces:  use dim plus one and put offset after coefficients.\n\
+                 May be preceeded by a single interior point ('H').\n\
+\n\
+options:\n\
+    d    - Delaunay triangulation by lifting points to a paraboloid\n\
+    d Qu - furthest-site Delaunay triangulation (upper convex hull)\n\
+    v    - Voronoi diagram (dual of the Delaunay triangulation)\n\
+    v Qu - furthest-site Voronoi diagram\n\
+    Hn,n,... - halfspace intersection about point [n,n,0,...]\n\
+    Qt   - triangulated output\n\
+    QJ   - joggled input instead of merged facets\n\
+    Qc   - keep coplanar points with nearest facet\n\
+    Qi   - keep interior points with nearest facet\n\
+\n\
+Qhull control options:\n\
+    Qbk:n   - scale coord k so that low bound is n\n\
+      QBk:n - scale coord k so that upper bound is n (QBk is %2.2g)\n\
+    QbB  - scale input to unit cube centered at the origin\n\
+    Qbb  - scale last coordinate to [0,m] for Delaunay triangulations\n\
+    Qbk:0Bk:0 - remove k-th coordinate from input\n\
+    QJn  - randomly joggle input in range [-n,n]\n\
+    QRn  - random rotation (n=seed, n=0 time, n=-1 time/no rotate)\n\
+%s%s%s%s";  /* split up qh_prompt for Visual C++ */
+char qh_promptb[]= "\
+    Qf   - partition point to furthest outside facet\n\
+    Qg   - only build good facets (needs 'QGn', 'QVn', or 'PdD')\n\
+    Qm   - only process points that would increase max_outside\n\
+    Qr   - process random outside points instead of furthest ones\n\
+    Qs   - search all points for the initial simplex\n\
+    Qu   - for 'd' or 'v', compute upper hull without point at-infinity\n\
+              returns furthest-site Delaunay triangulation\n\
+    Qv   - test vertex neighbors for convexity\n\
+    Qx   - exact pre-merges (skips coplanar and angle-coplanar facets)\n\
+    Qz   - add point-at-infinity to Delaunay triangulation\n\
+    QGn  - good facet if visible from point n, -n for not visible\n\
+    QVn  - good facet if it includes point n, -n if not\n\
+    Q0   - turn off default premerge with 'C-0'/'Qx'\n\
+    Q1	   - sort merges by type instead of angle\n\
+    Q2   - merge all non-convex at once instead of independent sets\n\
+    Q3   - do not merge redundant vertices\n\
+    Q4   - avoid old->new merges\n\
+    Q5   - do not correct outer planes at end of qhull\n\
+    Q6   - do not pre-merge concave or coplanar facets\n\
+    Q7   - depth-first processing instead of breadth-first\n\
+    Q8   - do not process near-inside points\n\
+    Q9   - process furthest of furthest points\n\
+    Q10  - no special processing for narrow distributions\n\
+    Q11  - copy normals and recompute centrums for tricoplanar facets\n\
+\n\
+";
+char qh_promptc[]= "\
+Topts- Trace options:\n\
+    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
+    Tc   - check frequently during execution\n\
+    Ts   - print statistics\n\
+    Tv   - verify result: structure, convexity, and point inclusion\n\
+    Tz   - send all output to stdout\n\
+    TFn  - report summary when n or more facets created\n\
+    TI file - input data from file, no spaces or single quotes\n\
+    TO file - output results to file, may be enclosed in single quotes\n\
+    TPn  - turn on tracing when point n added to hull\n\
+     TMn - turn on tracing at merge n\n\
+     TWn - trace merge facets when width > n\n\
+    TRn  - rerun qhull n times.  Use with 'QJn'\n\
+    TVn  - stop qhull after adding point n, -n for before (see TCn)\n\
+     TCn - stop qhull after building cone for point n (see TVn)\n\
+\n\
+Precision options:\n\
+    Cn   - radius of centrum (roundoff added).  Merge facets if non-convex\n\
+     An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex\n\
+           C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge\n\
+    En   - max roundoff error for distance computation\n\
+    Rn   - randomly perturb computations by a factor of [1-n,1+n]\n\
+    Vn   - min distance above plane for a visible facet (default 3C-n or En)\n\
+    Un   - max distance below plane for a new, coplanar point (default Vn)\n\
+    Wn   - min facet width for outside point (before roundoff, default 2Vn)\n\
+\n\
+Output formats (may be combined; if none, produces a summary to stdout):\n\
+    f    - facet dump\n\
+    G    - Geomview output (see below)\n\
+    i    - vertices incident to each facet\n\
+    m    - Mathematica output (2-d and 3-d)\n\
+    o    - OFF format (dim, points and facets; Voronoi regions)\n\
+    n    - normals with offsets\n\
+    p    - vertex coordinates or Voronoi vertices (coplanar points if 'Qc')\n\
+    s    - summary (stderr)\n\
+\n\
+";
+char qh_promptd[]= "\
+More formats:\n\
+    Fa   - area for each facet\n\
+    FA   - compute total area and volume for option 's'\n\
+    Fc   - count plus coplanar points for each facet\n\
+           use 'Qc' (default) for coplanar and 'Qi' for interior\n\
+    FC   - centrum or Voronoi center for each facet\n\
+    Fd   - use cdd format for input (homogeneous with offset first)\n\
+    FD   - use cdd format for numeric output (offset first)\n\
+    FF   - facet dump without ridges\n\
+    Fi   - inner plane for each facet\n\
+           for 'v', separating hyperplanes for bounded Voronoi regions\n\
+    FI   - ID of each facet\n\
+    Fm   - merge count for each facet (511 max)\n\
+    Fn   - count plus neighboring facets for each facet\n\
+    FN   - count plus neighboring facets for each point\n\
+    Fo   - outer plane (or max_outside) for each facet\n\
+           for 'v', separating hyperplanes for unbounded Voronoi regions\n\
+    FO   - options and precision constants\n\
+    Fp   - dim, count, and intersection coordinates (halfspace only)\n\
+    FP   - nearest vertex and distance for each coplanar point\n\
+    FQ   - command used for qhull\n\
+    Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,\n\
+                      output: #vertices, #facets, #coplanars, #nonsimplicial\n\
+                    #real (2), max outer plane, min vertex\n\
+    FS   - sizes:   #int (0)\n\
+                    #real(2) tot area, tot volume\n\
+    Ft   - triangulation with centrums for non-simplicial facets (OFF format)\n\
+    Fv   - count plus vertices for each facet\n\
+           for 'v', Voronoi diagram as Voronoi vertices for pairs of sites\n\
+    FV   - average of vertices (a feasible point for 'H')\n\
+    Fx   - extreme points (in order for 2-d)\n\
+\n\
+";
+char qh_prompte[]= "\
+Geomview options (2-d, 3-d, and 4-d; 2-d Voronoi)\n\
+    Ga   - all points as dots\n\
+     Gp  -  coplanar points and vertices as radii\n\
+     Gv  -  vertices as spheres\n\
+    Gi   - inner planes only\n\
+     Gn  -  no planes\n\
+     Go  -  outer planes only\n\
+    Gc   - centrums\n\
+    Gh   - hyperplane intersections\n\
+    Gr   - ridges\n\
+    GDn  - drop dimension n in 3-d and 4-d output\n\
+    Gt   - for 3-d 'd', transparent outer ridges\n\
+\n\
+Print options:\n\
+    PAn  - keep n largest facets by area\n\
+    Pdk:n - drop facet if normal[k] <= n (default 0.0)\n\
+    PDk:n - drop facet if normal[k] >= n\n\
+    Pg   - print good facets (needs 'QGn' or 'QVn')\n\
+    PFn  - keep facets whose area is at least n\n\
+    PG   - print neighbors of good facets\n\
+    PMn  - keep n facets with most merges\n\
+    Po   - force output.  If error, output neighborhood of facet\n\
+    Pp   - do not report precision problems\n\
+\n\
+    .    - list of all options\n\
+    -    - one line descriptions of all options\n\
+";
+/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
+
+/*---------------------------------
+
+  qh_prompt2
+    synopsis for qhull
+*/
+char qh_prompt2[]= "\n\
+qhull- compute convex hulls and related structures.  %s\n\
+    input (stdin): dimension, n, point coordinates\n\
+    comments start with a non-numeric character\n\
+    halfspace: use dim+1 and put offsets after coefficients\n\
+\n\
+options (qh-quick.htm):\n\
+    d    - Delaunay triangulation by lifting points to a paraboloid\n\
+    d Qu - furthest-site Delaunay triangulation (upper convex hull)\n\
+    v    - Voronoi diagram as the dual of the Delaunay triangulation\n\
+    v Qu - furthest-site Voronoi diagram\n\
+    H1,1 - Halfspace intersection about [1,1,0,...] via polar duality\n\
+    Qt   - triangulated output\n\
+    QJ   - joggled input instead of merged facets\n\
+    Tv   - verify result: structure, convexity, and point inclusion\n\
+    .    - concise list of all options\n\
+    -    - one-line description of all options\n\
+\n\
+Output options (subset):\n\
+    s    - summary of results (default)\n\
+    i    - vertices incident to each facet\n\
+    n    - normals with offsets\n\
+    p    - vertex coordinates (if 'Qc', includes coplanar points)\n\
+           if 'v', Voronoi vertices\n\
+    Fp   - halfspace intersections\n\
+    Fx   - extreme points (convex hull vertices)\n\
+    FA   - compute total area and volume\n\
+    o    - OFF format (if 'v', outputs Voronoi regions)\n\
+    G    - Geomview output (2-d, 3-d and 4-d)\n\
+    m    - Mathematica output (2-d and 3-d)\n\
+    QVn  - print facets that include point n, -n if not\n\
+    TO file- output results to file, may be enclosed in single quotes\n\
+\n\
+examples:\n\
+    rbox c d D2 | qhull Qc s f Fx | more      rbox 1000 s | qhull Tv s FA\n\
+    rbox 10 D2 | qhull d QJ s i TO result     rbox 10 D2 | qhull v QJ p\n\
+    rbox 10 D2 | qhull d Qu QJ m              rbox 10 D2 | qhull v Qu QJ o\n\
+    rbox c | qhull n                          rbox c | qhull FV n | qhull H Fp\n\
+    rbox d D12 | qhull QR0 FA                 rbox c D7 | qhull FA TF1000\n\
+    rbox y 1000 W0 | qhull                    rbox 10 | qhull v QJ o Fv\n\
+\n\
+";
+/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
+
+/*---------------------------------
+
+  qh_prompt3
+    concise prompt for qhull
+*/
+char qh_prompt3[]= "\n\
+Qhull %s.\n\
+Except for 'F.' and 'PG', upper-case options take an argument.\n\
+\n\
+ delaunay       voronoi	       Geomview       Halfspace      facet_dump\n\
+ incidences     mathematica    normals        OFF_format     points\n\
+ summary\n\
+\n\
+ Farea          FArea-total    Fcoplanars     FCentrums      Fd-cdd-in\n\
+ FD-cdd-out     FF-dump-xridge Finner         FIDs           Fmerges\n\
+ Fneighbors     FNeigh-vertex  Fouter         FOptions       Fpoint-intersect\n\
+ FPoint_near    FQhull         Fsummary       FSize          Ftriangles\n\
+ Fvertices      Fvoronoi       FVertex-ave    Fxtremes\n\
+\n\
+ Gvertices      Gpoints        Gall_points    Gno_planes     Ginner\n\
+ Gcentrums      Ghyperplanes   Gridges        Gouter         GDrop_dim\n\
+ Gtransparent\n\
+\n\
+ PArea-keep     Pdrop d0:0D0   Pgood          PFacet_area_keep\n\
+ PGood_neighbors PMerge-keep   Poutput_forced Pprecision_not\n\
+\n\
+ QbBound 0:0.5  Qbk:0Bk:0_drop QbB-scale-box  Qbb-scale-last Qcoplanar\n\
+ Qfurthest      Qgood_only     QGood_point    Qinterior      Qmax_out\n\
+ QJoggle        Qrandom        QRotate        Qsearch_1st    Qtriangulate\n\
+ QupperDelaunay QVertex_good   Qvneighbors    Qxact_merge    Qzinfinite\n\
+\n\
+ Q0_no_premerge Q1_no_angle    Q2_no_independ Q3_no_redundant Q4_no_old\n\
+ Q5_no_check_out Q6_no_concave Q7_depth_first Q8_no_near_in  Q9_pick_furthest\n\
+ Q10_no_narrow  Q11_trinormals\n\
+\n\
+ T4_trace       Tcheck_often   Tstatistics    Tverify        Tz_stdout\n\
+ TFacet_log     TInput_file    TPoint_trace   TMerge_trace   TOutput_file\n\
+ TRerun         TWide_trace    TVertex_stop   TCone_stop\n\
+\n\
+ Angle_max      Centrum_size   Error_round    Random_dist    Visible_min\n\
+ Ucoplanar_max  Wide_outside\n\
+";
+
+/*---------------------------------
+
+  main( argc, argv )
+    processes the command line, calls qhull() to do the work, and exits
+
+  design:
+    initializes data structures
+    reads points
+    finishes initialization
+    computes convex hull and other structures
+    checks the result
+    writes the output
+    frees memory
+*/
+int main(int argc, char *argv[]) {
+  int curlong, totlong; /* used !qh_NOmem */
+  int exitcode, numpoints, dim;
+  coordT *points;
+  boolT ismalloc;
+
+#if __MWERKS__ && __POWERPC__
+  char inBuf[BUFSIZ], outBuf[BUFSIZ], errBuf[BUFSIZ];
+  SIOUXSettings.showstatusline= false;
+  SIOUXSettings.tabspaces= 1;
+  SIOUXSettings.rows= 40;
+  if (setvbuf (stdin, inBuf, _IOFBF, sizeof(inBuf)) < 0   /* w/o, SIOUX I/O is slow*/
+  || setvbuf (stdout, outBuf, _IOFBF, sizeof(outBuf)) < 0
+  || (stdout != stderr && setvbuf (stderr, errBuf, _IOFBF, sizeof(errBuf)) < 0))
+    fprintf (stderr, "qhull internal warning (main): could not change stdio to fully buffered.\n");
+  argc= ccommand(&argv);
+#endif
+
+  if ((argc == 1) && isatty( 0 /*stdin*/)) {
+    fprintf(stdout, qh_prompt2, qh_VERSION);
+    exit(qh_ERRnone);
+  }
+  if (argc > 1 && *argv[1] == '-' && !*(argv[1]+1)) {
+    fprintf(stdout, qh_prompta, qh_VERSION, qh_DEFAULTbox,
+		qh_promptb, qh_promptc, qh_promptd, qh_prompte);
+    exit(qh_ERRnone);
+  }
+  if (argc >1 && *argv[1] == '.' && !*(argv[1]+1)) {
+    fprintf(stdout, qh_prompt3, qh_VERSION);
+    exit(qh_ERRnone);
+  }
+  qh_init_A (stdin, stdout, stderr, argc, argv);  /* sets qh qhull_command */
+  exitcode= setjmp (qh errexit); /* simple statement for CRAY J916 */
+  if (!exitcode) {
+    qh_initflags (qh qhull_command);
+    points= qh_readpoints (&numpoints, &dim, &ismalloc);
+    qh_init_B (points, numpoints, dim, ismalloc);
+    qh_qhull();
+    qh_check_output();
+    qh_produce_output();
+    if (qh VERIFYoutput && !qh FORCEoutput && !qh STOPpoint && !qh STOPcone)
+      qh_check_points();
+    exitcode= qh_ERRnone;
+  }
+  qh NOerrexit= True;  /* no more setjmp */
+#ifdef qh_NOmem
+  qh_freeqhull( True);
+#else
+  qh_freeqhull( False);
+  qh_memfreeshort (&curlong, &totlong);
+  if (curlong || totlong)
+    fprintf (stderr, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n",
+       totlong, curlong);
+#endif
+  return exitcode;
+} /* main */
+
diff --git a/extern/qhull/src/user.c b/extern/qhull/src/user.c
new file mode 100644
index 00000000000..94b31aaf99f
--- /dev/null
+++ b/extern/qhull/src/user.c
@@ -0,0 +1,324 @@
+/*
  ---------------------------------
+
+   user.c 
+   user redefinable functions
+
+   see README.txt  see COPYING.txt for copyright information.
+
+   see qhull.h for data structures, macros, and user-callable functions.
+
+   see user_eg.c, unix.c, and qhull_interface.cpp for examples.
+
+   see user.h for user-definable constants
+
+      use qh_NOmem in mem.h to turn off memory management
+      use qh_NOmerge in user.h to turn off facet merging
+      set qh_KEEPstatistics in user.h to 0 to turn off statistics
+
+   This is unsupported software.  You're welcome to make changes,
+   but you're on your own if something goes wrong.  Use 'Tc' to
+   check frequently.  Usually qhull will report an error if 
+   a data structure becomes inconsistent.  If so, it also reports
+   the last point added to the hull, e.g., 102.  You can then trace
+   the execution of qhull with "T4P102".  
+
+   Please report any errors that you fix to qhull@geom.umn.edu
+
+   call_qhull is a template for calling qhull from within your application
+
+   if you recompile and load this module, then user.o will not be loaded
+   from qhull.a
+
+   you can add additional quick allocation sizes in qh_user_memsizes
+
+   if the other functions here are redefined to not use qh_print...,
+   then io.o will not be loaded from qhull.a.  See user_eg.c for an
+   example.  We recommend keeping io.o for the extra debugging 
+   information it supplies.
+*/
+
+#include "qhull_a.h" 
+
+/*---------------------------------
+
+  qh_call_qhull( void )
+    template for calling qhull from inside your program
+    remove #if 0, #endif to compile
+
+  returns: 
+    exit code (see qh_ERR... in qhull.h)
+    all memory freed
+
+  notes:
+    This can be called any number of times.  
+
+  see:
+    qh_call_qhull_once()
+    
+*/
+#if 0
+{
+  int dim;	            /* dimension of points */
+  int numpoints;            /* number of points */
+  coordT *points;           /* array of coordinates for each point */
+  boolT ismalloc;           /* True if qhull should free points in qh_freeqhull() or reallocation */
+  char flags[]= "qhull Tv"; /* option flags for qhull, see qh_opt.htm */
+  FILE *outfile= stdout;    /* output from qh_produce_output()
+			       use NULL to skip qh_produce_output() */
+  FILE *errfile= stderr;    /* error messages from qhull code */
+  int exitcode;             /* 0 if no error from qhull */
+  facetT *facet;	    /* set by FORALLfacets */
+  int curlong, totlong;	    /* memory remaining after qh_memfreeshort */
+
+  /* initialize dim, numpoints, points[], ismalloc here */
+  exitcode= qh_new_qhull (dim, numpoints, points, ismalloc,
+                      flags, outfile, errfile); 
+  if (!exitcode) {                  /* if no error */
+    /* 'qh facet_list' contains the convex hull */
+    FORALLfacets {
+       /* ... your code ... */
+    }
+  }
+  qh_freeqhull(!qh_ALL);
+  qh_memfreeshort (&curlong, &totlong);
+  if (curlong || totlong) 
+    fprintf (errfile, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n", totlong, curlong);
+}
+#endif
+
+/*---------------------------------
+
+  qh_new_qhull( dim, numpoints, points, ismalloc, qhull_cmd, outfile, errfile )
+    build new qhull data structure and return exitcode (0 if no errors)
+
+  notes:
+    do not modify points until finished with results.
+      The qhull data structure contains pointers into the points array.
+    do not call qhull functions before qh_new_qhull().
+      The qhull data structure is not initialized until qh_new_qhull().
+
+    outfile may be null
+    qhull_cmd must start with "qhull "
+    projects points to a new point array for Delaunay triangulations ('d' and 'v')
+    transforms points into a new point array for halfspace intersection ('H')
+       
+
+  To allow multiple, concurrent calls to qhull() 
+    - set qh_QHpointer in user.h
+    - use qh_save_qhull and qh_restore_qhull to swap the global data structure between calls.
+    - use qh_freeqhull(qh_ALL) to free intermediate convex hulls
+
+  see:
+    user_eg.c for an example
+*/
+int qh_new_qhull (int dim, int numpoints, coordT *points, boolT ismalloc, 
+		char *qhull_cmd, FILE *outfile, FILE *errfile) {
+  int exitcode, hulldim;
+  boolT new_ismalloc;
+  static boolT firstcall = True;
+  coordT *new_points;
+
+  if (firstcall) {
+    qh_meminit (errfile);
+    firstcall= False;
+  }
+  if (strncmp (qhull_cmd,"qhull ", 6)) {
+    fprintf (errfile, "qh_new_qhull: start qhull_cmd argument with \"qhull \"\n");
+    exit(1);
+  }
+  qh_initqhull_start (NULL, outfile, errfile);
+  trace1(( qh ferr, "qh_new_qhull: build new Qhull for %d %d-d points with %s\n", numpoints, dim, qhull_cmd));
+  exitcode = setjmp (qh errexit);
+  if (!exitcode)
+  {
+    qh NOerrexit = False;
+    qh_initflags (qhull_cmd);
+    if (qh DELAUNAY)
+      qh PROJECTdelaunay= True;
+    if (qh HALFspace) {
+      /* points is an array of halfspaces, 
+         the last coordinate of each halfspace is its offset */
+      hulldim= dim-1;
+      qh_setfeasible (hulldim); 
+      new_points= qh_sethalfspace_all (dim, numpoints, points, qh feasible_point);
+      new_ismalloc= True;
+      if (ismalloc)
+	free (points);
+    }else {
+      hulldim= dim;
+      new_points= points;
+      new_ismalloc= ismalloc;
+    }
+    qh_init_B (new_points, numpoints, hulldim, new_ismalloc);
+    qh_qhull();
+    qh_check_output();
+    if (outfile)
+      qh_produce_output(); 
+    if (qh VERIFYoutput && !qh STOPpoint && !qh STOPcone)
+      qh_check_points();
+  }
+  qh NOerrexit = True;
+  return exitcode;
+} /* new_qhull */
+
+/*---------------------------------
+  
+  qh_errexit( exitcode, facet, ridge )
+    report and exit from an error
+    report facet and ridge if non-NULL
+    reports useful information such as last point processed
+    set qh.FORCEoutput to print neighborhood of facet
+
+  see: 
+    qh_errexit2() in qhull.c for printing 2 facets
+
+  design:
+    check for error within error processing
+    compute qh.hulltime
+    print facet and ridge (if any)
+    report commandString, options, qh.furthest_id
+    print summary and statistics (including precision statistics)
+    if qh_ERRsingular
+      print help text for singular data set
+    exit program via long jump (if defined) or exit()      
+*/
+void qh_errexit(int exitcode, facetT *facet, ridgeT *ridge) {
+
+  if (qh ERREXITcalled) {
+    fprintf (qh ferr, "\nqhull error while processing previous error.  Exit program\n");
+    exit(1);
+  }
+  qh ERREXITcalled= True;
+  if (!qh QHULLfinished)
+    qh hulltime= qh_CPUclock - qh hulltime;
+  qh_errprint("ERRONEOUS", facet, NULL, ridge, NULL);
+  fprintf (qh ferr, "\nWhile executing: %s | %s\n", qh rbox_command, qh qhull_command);
+  fprintf(qh ferr, "Options selected for Qhull %s:\n%s\n", qh_VERSION, qh qhull_options);
+  if (qh furthest_id >= 0) {
+    fprintf(qh ferr, "Last point added to hull was p%d.", qh furthest_id);
+    if (zzval_(Ztotmerge))
+      fprintf(qh ferr, "  Last merge was #%d.", zzval_(Ztotmerge));
+    if (qh QHULLfinished)
+      fprintf(qh ferr, "\nQhull has finished constructing the hull.");
+    else if (qh POSTmerging)
+      fprintf(qh ferr, "\nQhull has started post-merging.");
+    fprintf (qh ferr, "\n");
+  }
+  if (qh FORCEoutput && (qh QHULLfinished || (!facet && !ridge)))
+    qh_produce_output();
+  else {
+    if (exitcode != qh_ERRsingular && zzval_(Zsetplane) > qh hull_dim+1) {
+      fprintf (qh ferr, "\nAt error exit:\n");
+      qh_printsummary (qh ferr);
+      if (qh PRINTstatistics) {
+	qh_collectstatistics();
+	qh_printstatistics(qh ferr, "at error exit");
+	qh_memstatistics (qh ferr);
+      }
+    }
+    if (qh PRINTprecision)
+      qh_printstats (qh ferr, qhstat precision, NULL);
+  }
+  if (!exitcode)
+    exitcode= qh_ERRqhull;
+  else if (exitcode == qh_ERRsingular)
+    qh_printhelp_singular(qh ferr);
+  else if (exitcode == qh_ERRprec && !qh PREmerge)
+    qh_printhelp_degenerate (qh ferr);
+  if (qh NOerrexit) {
+    fprintf (qh ferr, "qhull error while ending program.  Exit program\n");
+    exit(1);
+  }
+  qh NOerrexit= True;
+  longjmp(qh errexit, exitcode);
+} /* errexit */
+
+
+/*---------------------------------
+  
+  qh_errprint( fp, string, atfacet, otherfacet, atridge, atvertex )
+    prints out the information of facets and ridges to fp
+    also prints neighbors and geomview output
+    
+  notes:
+    except for string, any parameter may be NULL
+*/
+void qh_errprint(char *string, facetT *atfacet, facetT *otherfacet, ridgeT *atridge, vertexT *atvertex) {
+  int i;
+
+  if (atfacet) {
+    fprintf(qh ferr, "%s FACET:\n", string);
+    qh_printfacet(qh ferr, atfacet);
+  }
+  if (otherfacet) {
+    fprintf(qh ferr, "%s OTHER FACET:\n", string);
+    qh_printfacet(qh ferr, otherfacet);
+  }
+  if (atridge) {
+    fprintf(qh ferr, "%s RIDGE:\n", string);
+    qh_printridge(qh ferr, atridge);
+    if (atridge->top && atridge->top != atfacet && atridge->top != otherfacet)
+      qh_printfacet(qh ferr, atridge->top);
+    if (atridge->bottom
+	&& atridge->bottom != atfacet && atridge->bottom != otherfacet)
+      qh_printfacet(qh ferr, atridge->bottom);
+    if (!atfacet)
+      atfacet= atridge->top;
+    if (!otherfacet)
+      otherfacet= otherfacet_(atridge, atfacet);
+  }
+  if (atvertex) {
+    fprintf(qh ferr, "%s VERTEX:\n", string);
+    qh_printvertex (qh ferr, atvertex);
+  }
+  if (qh fout && qh FORCEoutput && atfacet && !qh QHULLfinished && !qh IStracing) {
+    fprintf(qh ferr, "ERRONEOUS and NEIGHBORING FACETS to output\n");
+    for (i= 0; i < qh_PRINTEND; i++)  /* use fout for geomview output */
+      qh_printneighborhood (qh fout, qh PRINTout[i], atfacet, otherfacet,
+			    !qh_ALL);
+  }
+} /* errprint */
+
+
+/*---------------------------------
+  
+  qh_printfacetlist( fp, facetlist, facets, printall )
+    print all fields for a facet list and/or set of facets to fp
+    if !printall, 
+      only prints good facets
+
+  notes:
+    also prints all vertices
+*/
+void qh_printfacetlist(facetT *facetlist, setT *facets, boolT printall) {
+  facetT *facet, **facetp;
+
+  qh_printbegin (qh ferr, qh_PRINTfacets, facetlist, facets, printall);
+  FORALLfacet_(facetlist)
+    qh_printafacet(qh ferr, qh_PRINTfacets, facet, printall);
+  FOREACHfacet_(facets)
+    qh_printafacet(qh ferr, qh_PRINTfacets, facet, printall);
+  qh_printend (qh ferr, qh_PRINTfacets, facetlist, facets, printall);
+} /* printfacetlist */
+
+
+/*---------------------------------
+  
+  qh_user_memsizes()
+    allocate up to 10 additional, quick allocation sizes
+
+  notes:
+    increase maximum number of allocations in qh_initqhull_mem()
+*/
+void qh_user_memsizes (void) {
+
+  /* qh_memsize (size); */
+} /* user_memsizes */
+
diff --git a/extern/qhull/src/user.h b/extern/qhull/src/user.h
new file mode 100644
index 00000000000..79558967a52
--- /dev/null
+++ b/extern/qhull/src/user.h
@@ -0,0 +1,762 @@
+/*
  ---------------------------------
+
+   user.h
+   user redefinable constants
+
+   see qh-user.htm.  see COPYING for copyright information.
+
+   before reading any code, review qhull.h for data structure definitions and 
+   the "qh" macro.
+*/
+
+#ifndef qhDEFuser
+#define qhDEFuser 1
+
+/*============= data types and configuration macros ==========*/
+
+/*----------------------------------
+  
+  realT
+    set the size of floating point numbers
+  
+  qh_REALdigits 
+    maximimum number of significant digits
+  
+  qh_REAL_1, qh_REAL_2n, qh_REAL_3n
+    format strings for printf
+  
+  qh_REALmax, qh_REALmin
+    maximum and minimum (near zero) values  
+  
+  qh_REALepsilon
+    machine roundoff.  Maximum roundoff error for addition and multiplication.
+    
+  notes:
+   Select whether to store floating point numbers in single precision (float)
+   or double precision (double).
+   
+   Use 'float' to save about 8% in time and 25% in space.  This is particularly
+   help if high-d where convex hulls are space limited.  Using 'float' also
+   reduces the printed size of Qhull's output since numbers have 8 digits of 
+   precision.
+   
+   Use 'double' when greater arithmetic precision is needed.  This is needed
+   for Delaunay triangulations and Voronoi diagrams when you are not merging 
+   facets.
+
+   If 'double' gives insufficient precision, your data probably includes
+   degeneracies.  If so you should use facet merging (done by default)
+   or exact arithmetic (see imprecision section of manual, qh-impre.htm).  
+   You may also use option 'Po' to force output despite precision errors.
+
+   You may use 'long double', but many format statements need to be changed
+   and you may need a 'long double' square root routine.  S. Grundmann
+   (sg@eeiwzb.et.tu-dresden.de) has done this.  He reports that the code runs 
+   much slower with little gain in precision.    
+
+   WARNING: on some machines,    int f(){realT a= REALmax;return (a == REALmax);}
+      returns False.  Use (a > REALmax/2) instead of (a == REALmax).
+
+   REALfloat =   1      all numbers are 'float' type
+             =   0      all numbers are 'double' type
+*/
+#define REALfloat 0
+
+#if (REALfloat == 1)
+#define realT float
+#define REALmax FLT_MAX
+#define REALmin FLT_MIN
+#define REALepsilon FLT_EPSILON
+#define qh_REALdigits 8   /* maximum number of significant digits */
+#define qh_REAL_1 "%6.8g "
+#define qh_REAL_2n "%6.8g %6.8g\n"
+#define qh_REAL_3n "%6.8g %6.8g %6.8g\n"
+
+#elif (REALfloat == 0)
+#define realT double
+#define REALmax DBL_MAX
+#define REALmin DBL_MIN
+#define REALepsilon DBL_EPSILON
+#define qh_REALdigits 16    /* maximum number of significant digits */
+#define qh_REAL_1 "%6.16g "
+#define qh_REAL_2n "%6.16g %6.16g\n"
+#define qh_REAL_3n "%6.16g %6.16g %6.16g\n"
+
+#else
+#error unknown float option
+#endif
+
+/*----------------------------------
+  
+  qh_CPUclock
+    define the clock() function for reporting the total time spent by Qhull
+    returns CPU ticks as a 'long int'
+    qh_CPUclock is only used for reporting the total time spent by Qhull
+
+  qh_SECticks 
+    the number of clock ticks per second
+
+  notes:
+    looks for CLOCKS_PER_SEC, CLOCKS_PER_SECOND, or assumes microseconds
+    to define a custom clock, set qh_CLOCKtype to 0
+
+    if your system does not use clock() to return CPU ticks, replace
+    qh_CPUclock with the corresponding function.  It is converted
+    to unsigned long to prevent wrap-around during long runs.
+   
+
+   Set qh_CLOCKtype to
+   
+     1	   	for CLOCKS_PER_SEC, CLOCKS_PER_SECOND, or microsecond
+                Note:  may fail if more than 1 hour elapsed time
+
+     2	   	use qh_clock() with POSIX times() (see global.c)
+*/
+#define qh_CLOCKtype 1  /* change to the desired number */
+
+#if (qh_CLOCKtype == 1)
+
+#if defined (CLOCKS_PER_SECOND)
+#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock */
+#define qh_SECticks CLOCKS_PER_SECOND
+
+#elif defined (CLOCKS_PER_SEC)
+#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock */
+#define qh_SECticks CLOCKS_PER_SEC
+
+#elif defined (CLK_TCK)
+#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock */
+#define qh_SECticks CLK_TCK
+
+#else
+#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock */
+#define qh_SECticks 1E6
+#endif
+
+#elif (qh_CLOCKtype == 2)
+#define qh_CPUclock    qh_clock()  /* return CPU clock */
+#define qh_SECticks 100
+
+#else /* qh_CLOCKtype == ? */
+#error unknown clock option
+#endif
+
+/*----------------------------------
+  
+  qh_RANDOMtype, qh_RANDOMmax, qh_RANDOMseed
+    define random number generator
+
+    qh_RANDOMint generates a random integer between 0 and qh_RANDOMmax.  
+    qh_RANDOMseed sets the random number seed for qh_RANDOMint
+
+  Set qh_RANDOMtype (default 5) to:
+    1       for random() with 31 bits (UCB)
+    2       for rand() with RAND_MAX or 15 bits (system 5)
+    3       for rand() with 31 bits (Sun)
+    4       for lrand48() with 31 bits (Solaris)
+    5       for qh_rand() with 31 bits (included with Qhull)
+  
+  notes:
+    Random numbers are used by rbox to generate point sets.  Random
+    numbers are used by Qhull to rotate the input ('QRn' option),
+    simulate a randomized algorithm ('Qr' option), and to simulate
+    roundoff errors ('Rn' option).
+
+    Random number generators differ between systems.  Most systems provide
+    rand() but the period varies.  The period of rand() is not critical
+    since qhull does not normally use random numbers.  
+
+    The default generator is Park & Miller's minimal standard random
+    number generator [CACM 31:1195 '88].  It is included with Qhull.
+
+    If qh_RANDOMmax is wrong, qhull will report a warning and Geomview 
+    output will likely be invisible.
+*/
+#define qh_RANDOMtype 5   /* *** change to the desired number *** */
+
+#if (qh_RANDOMtype == 1)
+#define qh_RANDOMmax ((realT)0x7fffffffUL)  /* 31 bits, random()/MAX */
+#define qh_RANDOMint random()
+#define qh_RANDOMseed_(seed) srandom(seed);
+
+#elif (qh_RANDOMtype == 2)
+#ifdef RAND_MAX
+#define qh_RANDOMmax ((realT)RAND_MAX)
+#else
+#define qh_RANDOMmax ((realT)32767)   /* 15 bits (System 5) */
+#endif
+#define qh_RANDOMint  rand()
+#define qh_RANDOMseed_(seed) srand((unsigned)seed);
+  
+#elif (qh_RANDOMtype == 3)
+#define qh_RANDOMmax ((realT)0x7fffffffUL)  /* 31 bits, Sun */
+#define qh_RANDOMint  rand()
+#define qh_RANDOMseed_(seed) srand((unsigned)seed);
+
+#elif (qh_RANDOMtype == 4)
+#define qh_RANDOMmax ((realT)0x7fffffffUL)  /* 31 bits, lrand38()/MAX */
+#define qh_RANDOMint lrand48()
+#define qh_RANDOMseed_(seed) srand48(seed);
+
+#elif (qh_RANDOMtype == 5)
+#define qh_RANDOMmax ((realT)2147483646UL)  /* 31 bits, qh_rand/MAX */
+#define qh_RANDOMint qh_rand()
+#define qh_RANDOMseed_(seed) qh_srand(seed);
+/* unlike rand(), never returns 0 */
+
+#else
+#error: unknown random option
+#endif
+
+/*----------------------------------
+  
+  qh_ORIENTclock
+    0 for inward pointing normals by Geomview convention
+*/
+#define qh_ORIENTclock 0 
+
+
+/*========= performance related constants =========*/
+
+/*----------------------------------
+  
+  qh_HASHfactor
+    total hash slots / used hash slots.  Must be at least 1.1.
+      
+  notes:
+    =2 for at worst 50% occupancy for qh hash_table and normally 25% occupancy
+*/
+#define qh_HASHfactor 2
+
+/*----------------------------------
+  
+  qh_VERIFYdirect
+    with 'Tv' verify all points against all facets if op count is smaller
+
+  notes:
+    if greater, calls qh_check_bestdist() instead
+*/
+#define qh_VERIFYdirect 1000000 
+
+/*----------------------------------
+  
+  qh_INITIALsearch
+     if qh_INITIALmax, search points up to this dimension
+*/
+#define qh_INITIALsearch 6
+
+/*----------------------------------
+  
+  qh_INITIALmax
+    if dim >= qh_INITIALmax, use min/max coordinate points for initial simplex
+      
+  notes:
+    from points with non-zero determinants
+    use option 'Qs' to override (much slower)
+*/
+#define qh_INITIALmax 8
+
+/*----------------------------------
+  
+  qh_JOGGLEdefault
+    default qh.JOGGLEmax is qh.DISTround * qh_JOGGLEdefault
+
+  notes:
+    rbox s r 100 | qhull QJ1e-15 QR0 generates 90% faults at distround 7e-16
+    rbox s r 100 | qhull QJ1e-14 QR0 generates 70% faults
+    rbox s r 100 | qhull QJ1e-13 QR0 generates 35% faults
+    rbox s r 100 | qhull QJ1e-12 QR0 generates 8% faults
+    rbox s r 100 | qhull QJ1e-11 QR0 generates 1% faults
+    rbox s r 100 | qhull QJ1e-10 QR0 generates 0% faults
+    rbox 1000 W0 | qhull QJ1e-12 QR0 generates 86% faults
+    rbox 1000 W0 | qhull QJ1e-11 QR0 generates 20% faults
+    rbox 1000 W0 | qhull QJ1e-10 QR0 generates 2% faults
+    the later have about 20 points per facet, each of which may interfere
+
+    pick a value large enough to avoid retries on most inputs
+*/
+#define qh_JOGGLEdefault 30000.0
+
+/*----------------------------------
+  
+  qh_JOGGLEincrease
+    factor to increase qh.JOGGLEmax on qh_JOGGLEretry or qh_JOGGLEagain
+*/
+#define qh_JOGGLEincrease 10.0
+
+/*----------------------------------
+  
+  qh_JOGGLEretry
+    if ZZretry = qh_JOGGLEretry, increase qh.JOGGLEmax
+
+  notes:
+    try twice at the original value in case of bad luck the first time
+*/
+#define qh_JOGGLEretry 2
+
+/*----------------------------------
+  
+  qh_JOGGLEagain
+    every following qh_JOGGLEagain, increase qh.JOGGLEmax
+
+  notes:
+    1 is OK since it's already failed qh_JOGGLEretry times
+*/
+#define qh_JOGGLEagain 1
+
+/*----------------------------------
+  
+  qh_JOGGLEmaxincrease
+    maximum qh.JOGGLEmax due to qh_JOGGLEincrease
+    relative to qh.MAXwidth
+
+  notes:
+    qh.joggleinput will retry at this value until qh_JOGGLEmaxretry
+*/
+#define qh_JOGGLEmaxincrease 1e-2
+
+/*----------------------------------
+  
+  qh_JOGGLEmaxretry
+    stop after qh_JOGGLEmaxretry attempts
+*/
+#define qh_JOGGLEmaxretry 100
+
+/*========= memory constants =========*/
+
+/*----------------------------------
+  
+  qh_MEMalign
+    memory alignment for qh_meminitbuffers() in global.c
+    
+  notes:
+    to avoid bus errors, memory allocation must consider alignment requirements.
+    malloc() automatically takes care of alignment.   Since mem.c manages
+    its own memory, we need to explicitly specify alignment in
+    qh_meminitbuffers().
+
+    A safe choice is sizeof(double).  sizeof(float) may be used if doubles 
+    do not occur in data structures and pointers are the same size.  Be careful
+    of machines (e.g., DEC Alpha) with large pointers. 
+
+    If using gcc, best alignment is
+              #define qh_MEMalign fmax_(__alignof__(realT),__alignof__(void *))
+*/
+#define qh_MEMalign fmax_(sizeof(realT), sizeof(void *))
+
+/*----------------------------------
+  
+  qh_MEMbufsize
+    size of additional memory buffers
+    
+  notes:
+    used for qh_meminitbuffers() in global.c
+*/
+#define qh_MEMbufsize 0x10000       /* allocate 64K memory buffers */
+
+/*----------------------------------
+  
+  qh_MEMinitbuf
+    size of initial memory buffer
+    
+  notes:
+    use for qh_meminitbuffers() in global.c
+*/
+#define qh_MEMinitbuf 0x20000      /* initially allocate 128K buffer */
+
+/*----------------------------------
+  
+  qh_INFINITE
+    on output, indicates Voronoi center at infinity
+*/
+#define qh_INFINITE  -10.101
+
+/*----------------------------------
+  
+  qh_DEFAULTbox
+    default box size (Geomview expects 0.5)
+*/
+#define qh_DEFAULTbox 0.5 
+
+/*======= conditional compilation ============================*/
+
+/*----------------------------------
+
+  __cplusplus
+    defined by C++ compilers
+
+  __MSC_VER
+    defined by Microsoft Visual C++
+  
+  __MWERKS__ && __POWERPC__
+    defined by Metrowerks when compiling for the Power Macintosh
+
+  __STDC__
+    defined for strict ANSI C 
+*/
+
+/*----------------------------------
+ 
+  qh_COMPUTEfurthest 
+    compute furthest distance to an outside point instead of storing it with the facet
+    =1 to compute furthest
+  
+  notes:
+    computing furthest saves memory but costs time
+      about 40% more distance tests for partitioning
+      removes facet->furthestdist 
+*/
+#define qh_COMPUTEfurthest 0
+                         
+/*----------------------------------
+ 
+  qh_KEEPstatistics   
+    =0 removes most of statistic gathering and reporting
+
+  notes:
+    if 0, code size is reduced by about 4%.
+*/
+#define qh_KEEPstatistics 1
+                       
+/*----------------------------------
+ 
+  qh_MAXoutside 
+    record outer plane for each facet
+    =1 to record facet->maxoutside
+  
+  notes:
+    this takes a realT per facet and slightly slows down qhull
+    it produces better outer planes for geomview output 
+*/
+#define qh_MAXoutside 1
+
+/*----------------------------------
+ 
+  qh_NOmerge
+    disables facet merging if defined
+    
+  notes:
+    This saves about 10% space.
+    
+    Unless 'Q0'
+      qh_NOmerge sets 'QJ' to avoid precision errors
+
+    #define qh_NOmerge    
+
+  see:
+    qh_NOmem in mem.c
+    
+    see user.c/user_eg.c for removing io.o
+*/  
+    
+/*----------------------------------
+ 
+  qh_NOtrace
+    no tracing if defined 
+  
+  notes:
+    This saves about 5% space.
+
+    #define qh_NOtrace
+*/    
+
+/*----------------------------------
+  
+  qh_QHpointer
+    access global data with pointer or static structure
+
+  qh_QHpointer  = 1     access globals via a pointer to allocated memory
+                        enables qh_saveqhull() and qh_restoreqhull()
+			costs about 8% in time and 2% in space
+
+		= 0     qh_qh and qh_qhstat are static data structures
+		        only one instance of qhull() can be active at a time
+			default value
+
+  notes:
+    all global variables for qhull are in qh, qhmem, and qhstat
+    qh is defined in qhull.h
+    qhmem is defined in mem.h
+    qhstat is defined in stat.h
+
+  see:
+    user_eg.c for an example
+*/
+#define qh_QHpointer 0
+#if 0  /* sample code */
+    qhT *oldqhA, *oldqhB;
+
+    exitcode= qh_new_qhull (dim, numpoints, points, ismalloc,
+                      flags, outfile, errfile); 
+    /* use results from first call to qh_new_qhull */
+    oldqhA= qh_save_qhull();
+    exitcode= qh_new_qhull (dimB, numpointsB, pointsB, ismalloc,
+                      flags, outfile, errfile); 
+    /* use results from second call to qh_new_qhull */
+    oldqhB= qh_save_qhull();
+    qh_restore_qhull (&oldqhA);
+    /* use results from first call to qh_new_qhull */
+    qh_freeqhull (qh_ALL);  /* frees all memory used by first call */
+    qh_restore_qhull (&oldqhB);
+    /* use results from second call to qh_new_qhull */
+    qh_freeqhull (!qh_ALL); /* frees long memory used by second call */
+    qh_memfreeshort (&curlong, &totlong);  /* frees short memory and memory allocator */
+#endif
+
+/*----------------------------------
+ 
+  qh_QUICKhelp        
+    =1 to use abbreviated help messages, e.g., for degenerate inputs
+*/
+#define qh_QUICKhelp    0  
+
+/* ============ -merge constants- ====================
+
+   These constants effect facet merging.  You probably will not need
+   to modify these.  They effect the performance of facet merging.
+*/
+
+/*----------------------------------
+  
+  qh_DIMmergeVertex
+    max dimension for vertex merging (it is not effective in high-d)
+*/
+#define qh_DIMmergeVertex 6
+
+/*----------------------------------
+  
+  qh_DIMreduceBuild
+     max dimension for vertex reduction during build (slow in high-d)
+*/
+#define qh_DIMreduceBuild 5
+
+/*----------------------------------
+     
+  qh_BESTcentrum
+     if > 2*dim+n vertices, qh_findbestneighbor() tests centrums (faster)
+     else, qh_findbestneighbor() tests all vertices (much better merges)
+
+  qh_BESTcentrum2
+     if qh_BESTcentrum2 * DIM3 + BESTcentrum < #vertices tests centrums
+*/
+#define qh_BESTcentrum 20
+#define qh_BESTcentrum2 2
+
+/*----------------------------------
+  
+  qh_BESTnonconvex
+    if > dim+n neighbors, qh_findbestneighbor() tests nonconvex ridges.
+    
+  notes:
+    It is needed because qh_findbestneighbor is slow for large facets
+*/
+#define qh_BESTnonconvex 15 
+
+/*----------------------------------
+  
+  qh_MAXnewmerges
+    if >n newmerges, qh_merge_nonconvex() calls qh_reducevertices_centrums.
+     
+  notes:
+    It is needed because postmerge can merge many facets at once
+*/
+#define qh_MAXnewmerges 2
+
+/*----------------------------------
+  
+  qh_MAXnewcentrum
+    if <= dim+n vertices (n approximates the number of merges),
+      reset the centrum in qh_updatetested() and qh_mergecycle_facets()
+    
+  notes:
+    needed to reduce cost and because centrums may move too much if 
+    many vertices in high-d
+*/
+#define qh_MAXnewcentrum 5
+
+/*----------------------------------
+  
+  qh_COPLANARratio
+    for 3-d+ merging, qh.MINvisible is n*premerge_centrum
+
+  notes:
+    for non-merging, it's DISTround
+*/
+#define qh_COPLANARratio 3
+
+/*----------------------------------
+  
+  qh_DISToutside
+    When is a point clearly outside of a facet?  
+    Stops search in qh_findbestnew or qh_partitionall
+    qh_findbest uses qh.MINoutside since since it is only called if no merges.
+     
+  notes:
+    'Qf' always searches for best facet
+    if !qh.MERGING, same as qh.MINoutside. 
+    if qh_USEfindbestnew, increase value since neighboring facets may be ill-behaved
+      [Note: Zdelvertextot occurs normally with interior points]
+            RBOX 1000 s Z1 G1e-13 t1001188774 | QHULL Tv
+    When there is a sharp edge, need to move points to a
+    clearly good facet; otherwise may be lost in another partitioning.
+    if too big then O(n^2) behavior for partitioning in cone
+    if very small then important points not processed
+    Needed in qh_partitionall for
+      RBOX 1000 s Z1 G1e-13 t1001032651 | QHULL Tv
+    Needed in qh_findbestnew for many instances of
+      RBOX 1000 s Z1 G1e-13 t | QHULL Tv
+
+  See:  
+    qh_DISToutside -- when is a point clearly outside of a facet
+    qh_SEARCHdist -- when is facet coplanar with the best facet?
+    qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint()
+*/
+#define qh_DISToutside ((qh_USEfindbestnew ? 2 : 1) * \
+     fmax_((qh MERGING ? 2 : 1)*qh MINoutside, qh max_outside))
+
+/*----------------------------------
+  
+  qh_RATIOnearinside
+    ratio of qh.NEARinside to qh.ONEmerge for retaining inside points for
+    qh_check_maxout().  
+  
+  notes:
+    This is overkill since do not know the correct value.
+    It effects whether 'Qc' reports all coplanar points
+    Not used for 'd' since non-extreme points are coplanar
+*/
+#define qh_RATIOnearinside 5
+
+/*----------------------------------
+  
+  qh_SEARCHdist
+    When is a facet coplanar with the best facet?  
+    qh_findbesthorizon: all coplanar facets of the best facet need to be searched.
+
+  See:
+    qh_DISToutside -- when is a point clearly outside of a facet
+    qh_SEARCHdist -- when is facet coplanar with the best facet?
+    qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint()
+*/
+#define qh_SEARCHdist ((qh_USEfindbestnew ? 2 : 1) * \
+      (qh max_outside + 2 * qh DISTround + fmax_( qh MINvisible, qh MAXcoplanar)));
+
+/*----------------------------------
+  
+  qh_USEfindbestnew
+     Always use qh_findbestnew for qh_partitionpoint, otherwise use
+     qh_findbestnew if merged new facet or sharpnewfacets.
+  
+  See:
+    qh_DISToutside -- when is a point clearly outside of a facet
+    qh_SEARCHdist -- when is facet coplanar with the best facet?
+    qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint()
+*/
+#define qh_USEfindbestnew (zzval_(Ztotmerge) > 50)
+
+/*----------------------------------
+  
+  qh_WIDEcoplanar
+    n*MAXcoplanar or n*MINvisible for a WIDEfacet 
+    
+    if vertex is further than qh.WIDEfacet from the hyperplane
+    then its ridges are not counted in computing the area, and
+    the facet's centrum is frozen. 
+    
+  notes:
+   qh.WIDEfacet= max(qh.MAXoutside,qh_WIDEcoplanar*qh.MAXcoplanar,
+      qh_WIDEcoplanar * qh.MINvisible);
+*/
+#define qh_WIDEcoplanar 6
+
+/*----------------------------------
+  
+  qh_MAXnarrow
+    max. cosine in initial hull that sets qh.NARROWhull
+       
+  notes:
+    If qh.NARROWhull, the initial partition does not make 
+    coplanar points.  If narrow, a coplanar point can be 
+    coplanar to two facets of opposite orientations and
+    distant from the exact convex hull.
+
+    Conservative estimate.  Don't actually see problems until it is -1.0
+*/
+#define qh_MAXnarrow -0.99999999
+
+/*----------------------------------
+  
+  qh_WARNnarrow
+    max. cosine in initial hull to warn about qh.NARROWhull
+      
+  notes:
+    this is a conservative estimate.  
+    Don't actually see problems until it is -1.0.  See qh-impre.htm
+*/
+#define qh_WARNnarrow -0.999999999999999
+
+/*----------------------------------
+  
+  qh_ZEROdelaunay
+    a zero Delaunay facet occurs for input sites coplanar with their convex hull
+    the last normal coefficient of a zero Delaunay facet is within
+        qh_ZEROdelaunay * qh.ANGLEround of 0
+      
+  notes:
+    qh_ZEROdelaunay does not allow for joggled input ('QJ').
+
+    You can avoid zero Delaunay facets by surrounding the input with a box.
+
+    Use option 'PDk:-n' to explicitly define zero Delaunay facets
+      k= dimension of input sites (e.g., 3 for 3-d Delaunay triangulation)
+      n= the cutoff for zero Delaunay facets (e.g., 'PD3:-1e-12')
+*/
+#define qh_ZEROdelaunay 2
+
+#endif /* qh_DEFuser */
+
+
+
diff --git a/extern/qhull/src/user_eg.c b/extern/qhull/src/user_eg.c
new file mode 100644
index 00000000000..97e4aa7a89a
--- /dev/null
+++ b/extern/qhull/src/user_eg.c
@@ -0,0 +1,310 @@
+/*
  ---------------------------------
+
+  user_eg.c
+  sample code for calling qhull() from an application
+  
+  call with:
+
+     user_eg "cube/diamond options" "delaunay options" "halfspace options"
+
+  for example:
+
+     user_eg                             # return summaries
+
+     user_eg "n" "o" "Fp"                # return normals, OFF, points
+
+     user_eg "n Qt" "o" "Fp"             # triangulated cube
+
+     user_eg "QR0 p" "QR0 v p" "QR0 Fp"  # rotate input and return points
+                                         # 'v' returns Voronoi
+					 # transform is rotated for halfspaces
+
+   main() makes three runs of qhull.
+
+     1) compute the convex hull of a cube
+
+     2a) compute the Delaunay triangulation of random points
+
+     2b) find the Delaunay triangle closest to a point.
+
+     3) compute the halfspace intersection of a diamond
+
+ notes:
+ 
+   For another example, see main() in unix.c and user_eg2.c.
+   These examples, call qh_qhull() directly.  They allow
+   tighter control on the code loaded with Qhull.
+
+   For a simple C++ example, see qhull_interface.cpp
+
+   Summaries are sent to stderr if other output formats are used
+
+   compiled by 'make user_eg'
+
+   see qhull.h for data structures, macros, and user-callable functions.
+*/
+
+#include "qhull_a.h"
+
+/*-------------------------------------------------
+-internal function prototypes
+*/
+void print_summary (void);
+void makecube (coordT *points, int numpoints, int dim);
+void makeDelaunay (coordT *points, int numpoints, int dim, int seed);
+void findDelaunay (int dim);
+void makehalf (coordT *points, int numpoints, int dim);
+
+/*-------------------------------------------------
+-print_summary()
+*/
+void print_summary (void) {
+  facetT *facet;
+  int k;
+
+  printf ("\n%d vertices and %d facets with normals:\n", 
+                 qh num_vertices, qh num_facets);
+  FORALLfacets {
+    for (k=0; k < qh hull_dim; k++) 
+      printf ("%6.2g ", facet->normal[k]);
+    printf ("\n");
+  }
+}
+
+/*--------------------------------------------------
+-makecube- set points to vertices of cube
+  points is numpoints X dim
+*/
+void makecube (coordT *points, int numpoints, int dim) {
+  int j,k;
+  coordT *point;
+
+  for (j=0; jvertices) {
+    for (k=0; k < dim; k++)
+      printf ("%5.2f ", vertex->point[k]);
+    printf ("\n");
+  }
+} /*.findDelaunay.*/
+
+/*--------------------------------------------------
+-makehalf- set points to halfspaces for a (dim)-dimensional diamond
+  points is numpoints X dim+1
+
+  each halfspace consists of dim coefficients followed by an offset
+*/
+void makehalf (coordT *points, int numpoints, int dim) {
+  int j,k;
+  coordT *point;
+
+  for (j=0; j= 2 ? argv[1] : "");
+  numpoints= SIZEcube;
+  makecube (points, numpoints, DIM);
+  for (i=numpoints; i--; )
+    rows[i]= points+dim*i;
+  qh_printmatrix (outfile, "input", rows, numpoints, dim);
+  exitcode= qh_new_qhull (dim, numpoints, points, ismalloc,
+                      flags, outfile, errfile); 
+  if (!exitcode) {                  /* if no error */
+    /* 'qh facet_list' contains the convex hull */
+    print_summary();
+    FORALLfacets {
+       /* ... your code ... */
+    }
+  }
+  qh_freeqhull(!qh_ALL);                   /* free long memory  */
+  qh_memfreeshort (&curlong, &totlong);    /* free short memory and memory allocator */
+  if (curlong || totlong) 
+    fprintf (errfile, "qhull internal warning (user_eg, #1): did not free %d bytes of long memory (%d pieces)\n", totlong, curlong);
+
+  /*
+    Run 2: Delaunay triangulation
+  */
+
+  printf( "\ncompute 3-d Delaunay triangulation\n");
+  sprintf (flags, "qhull s d Tcv %s", argc >= 3 ? argv[2] : "");
+  numpoints= SIZEcube;
+  makeDelaunay (points, numpoints, dim, time(NULL));
+  for (i=numpoints; i--; )
+    rows[i]= points+dim*i;
+  qh_printmatrix (outfile, "input", rows, numpoints, dim);
+  exitcode= qh_new_qhull (dim, numpoints, points, ismalloc,
+                      flags, outfile, errfile); 
+  if (!exitcode) {                  /* if no error */
+    /* 'qh facet_list' contains the convex hull */
+    /* If you want a Voronoi diagram ('v') and do not request output (i.e., outfile=NULL), 
+       call qh_setvoronoi_all() after qh_new_qhull(). */
+    print_summary();
+    FORALLfacets {
+       /* ... your code ... */
+    }
+    printf( "\nfind 3-d Delaunay triangle closest to [0.5, 0.5, ...]\n");
+    exitcode= setjmp (qh errexit);  
+    if (!exitcode) {
+      /* Trap Qhull errors in findDelaunay().  Without the setjmp(), Qhull
+         will exit() after reporting an error */
+      qh NOerrexit= False;
+      findDelaunay (DIM);
+    }
+    qh NOerrexit= True;
+  }
+#if qh_QHpointer  /* see user.h */
+  {
+    qhT *oldqhA, *oldqhB;
+    coordT pointsB[DIM*TOTpoints]; /* array of coordinates for each point */
+
+
+    printf( "\nsave first triangulation and compute a new triangulation\n");
+    oldqhA= qh_save_qhull();
+    sprintf (flags, "qhull s d Tcv %s", argc >= 3 ? argv[2] : "");
+    numpoints= SIZEcube;
+    makeDelaunay (pointsB, numpoints, dim, time(NULL)+1);
+    for (i=numpoints; i--; )
+      rows[i]= pointsB+dim*i;
+    qh_printmatrix (outfile, "input", rows, numpoints, dim);
+    exitcode= qh_new_qhull (dim, numpoints, pointsB, ismalloc,
+                      flags, outfile, errfile); 
+    if (!exitcode)
+      print_summary();
+    printf( "\nsave second triangulation and restore first one\n");
+    oldqhB= qh_save_qhull();
+    qh_restore_qhull (&oldqhA);
+    print_summary();
+    printf( "\nfree first triangulation and restore second one.\n");
+    qh_freeqhull (qh_ALL);               /* free short and long memory used by first call */
+			                 /* do not use qh_memfreeshort */
+    qh_restore_qhull (&oldqhB);
+    print_summary();
+  }
+#endif
+  qh_freeqhull(!qh_ALL);                 /* free long memory */
+  qh_memfreeshort (&curlong, &totlong);  /* free short memory and memory allocator */
+  if (curlong || totlong) 
+    fprintf (errfile, "qhull internal warning (user_eg, #2): did not free %d bytes of long memory (%d pieces)\n", totlong, curlong);
+
+  /*
+    Run 3: halfspace intersection about the origin
+  */
+  printf( "\ncompute halfspace intersection about the origin for a diamond\n");
+  sprintf (flags, "qhull H0 s Tcv %s", argc >= 4 ? argv[3] : "Fp");
+  numpoints= SIZEcube;
+  makehalf (points, numpoints, dim);
+  for (i=numpoints; i--; )
+    rows[i]= points+(dim+1)*i;
+  qh_printmatrix (outfile, "input as halfspace coefficients + offsets", rows, numpoints, dim+1);
+  /* use qh_sethalfspace_all to transform the halfspaces yourself.  
+     If so, set 'qh feasible_point and do not use option 'Hn,...' [it would retransform the halfspaces]
+  */
+  exitcode= qh_new_qhull (dim+1, numpoints, points, ismalloc,
+                      flags, outfile, errfile); 
+  if (!exitcode) 
+    print_summary();
+  qh_freeqhull (!qh_ALL);
+  qh_memfreeshort (&curlong, &totlong);
+  if (curlong || totlong)  /* could also check previous runs */
+    fprintf (stderr, "qhull internal warning (user_eg, #3): did not free %d bytes of long memory (%d pieces)\n",
+       totlong, curlong);
+  return exitcode;
+} /* main */
+
diff --git a/extern/qhull/src/user_eg2.c b/extern/qhull/src/user_eg2.c
new file mode 100644
index 00000000000..1eb42ccfe8a
--- /dev/null
+++ b/extern/qhull/src/user_eg2.c
@@ -0,0 +1,532 @@
+/*
  ---------------------------------
+
+  user_eg2.c
+
+  sample code for calling qhull() from an application.
+
+  See user_eg.c for a simpler method using qh_new_qhull().
+  The method used here and in unix.c gives you additional
+  control over Qhull. 
+  
+  call with:
+
+     user_eg2 "triangulated cube/diamond options" "delaunay options" "halfspace options"
+
+  for example:
+
+     user_eg2                             # return summaries
+
+     user_eg2 "n" "o" "Fp"                # return normals, OFF, points
+
+     user_eg2 "QR0 p" "QR0 v p" "QR0 Fp"  # rotate input and return points
+                                         # 'v' returns Voronoi
+					 # transform is rotated for halfspaces
+
+   main() makes three runs of qhull.
+
+     1) compute the convex hull of a cube, and incrementally add a diamond
+
+     2a) compute the Delaunay triangulation of random points, and add points.
+
+     2b) find the Delaunay triangle closest to a point.
+
+     3) compute the halfspace intersection of a diamond, and add a cube
+
+ notes:
+ 
+   summaries are sent to stderr if other output formats are used
+
+   derived from unix.c and compiled by 'make user_eg2'
+
+   see qhull.h for data structures, macros, and user-callable functions.
+   
+   If you want to control all output to stdio and input to stdin,
+   set the #if below to "1" and delete all lines that contain "io.c".  
+   This prevents the loading of io.o.  Qhull will
+   still write to 'qh ferr' (stderr) for error reporting and tracing.
+
+   Defining #if 1, also prevents user.o from being loaded.
+*/
+
+#include "qhull_a.h"
+
+/*-------------------------------------------------
+-internal function prototypes
+*/
+void print_summary (void);
+void makecube (coordT *points, int numpoints, int dim);
+void adddiamond (coordT *points, int numpoints, int numnew, int dim);
+void makeDelaunay (coordT *points, int numpoints, int dim);
+void addDelaunay (coordT *points, int numpoints, int numnew, int dim);
+void findDelaunay (int dim);
+void makehalf (coordT *points, int numpoints, int dim);
+void addhalf (coordT *points, int numpoints, int numnew, int dim, coordT *feasible);
+
+/*-------------------------------------------------
+-print_summary()
+*/
+void print_summary (void) {
+  facetT *facet;
+  int k;
+
+  printf ("\n%d vertices and %d facets with normals:\n", 
+                 qh num_vertices, qh num_facets);
+  FORALLfacets {
+    for (k=0; k < qh hull_dim; k++) 
+      printf ("%6.2g ", facet->normal[k]);
+    printf ("\n");
+  }
+}
+
+/*--------------------------------------------------
+-makecube- set points to vertices of cube
+  points is numpoints X dim
+*/
+void makecube (coordT *points, int numpoints, int dim) {
+  int j,k;
+  coordT *point;
+
+  for (j=0; jvertices) {
+    for (k=0; k < dim-1; k++)
+      printf ("%5.2f ", vertex->point[k]);
+    printf ("\n");
+  }
+} /*.findDelaunay.*/
+
+/*--------------------------------------------------
+-makehalf- set points to halfspaces for a (dim)-d diamond
+  points is numpoints X dim+1
+
+  each halfspace consists of dim coefficients followed by an offset
+*/
+void makehalf (coordT *points, int numpoints, int dim) {
+  int j,k;
+  coordT *point;
+
+  for (j=0; j= 2 ? argv[1] : "");
+    qh_initflags (options);
+    printf( "\ncompute triangulated convex hull of cube after rotating input\n");
+    makecube (array[0], SIZEcube, DIM);
+    qh_init_B (array[0], SIZEcube, DIM, ismalloc);
+    qh_qhull();
+    qh_check_output();
+    qh_triangulate();  /* requires option 'Q11' if want to add points */ 
+    print_summary ();
+    if (qh VERIFYoutput && !qh STOPpoint && !qh STOPcone)
+      qh_check_points ();
+    printf( "\nadd points in a diamond\n");
+    adddiamond (array[0], SIZEcube, SIZEdiamond, DIM);
+    qh_check_output();
+    print_summary (); 
+    qh_produce_output();  /* delete this line to help avoid io.c */
+    if (qh VERIFYoutput && !qh STOPpoint && !qh STOPcone)
+      qh_check_points ();
+  }
+  qh NOerrexit= True;
+  qh_freeqhull (!qh_ALL);
+  qh_memfreeshort (&curlong, &totlong);
+  /*
+    Run 2: Delaunay triangulation
+  */
+  qh_init_A (stdin, stdout, stderr, 0, NULL);
+  exitcode= setjmp (qh errexit);
+  if (!exitcode) {
+    coordT array[TOTpoints][DIM];
+
+    strcat (qh rbox_command, "user_eg Delaunay");
+    sprintf (options, "qhull s d Tcv %s", argc >= 3 ? argv[2] : "");
+    qh_initflags (options);
+    printf( "\ncompute 2-d Delaunay triangulation\n");
+    makeDelaunay (array[0], SIZEcube, DIM);
+    /* Instead of makeDelaunay with qh_setdelaunay, you may
+       produce a 2-d array of points, set DIM to 2, and set 
+       qh PROJECTdelaunay to True.  qh_init_B will call 
+       qh_projectinput to project the points to the paraboloid
+       and add a point "at-infinity".
+    */
+    qh_init_B (array[0], SIZEcube, DIM, ismalloc);
+    qh_qhull();
+    /* If you want Voronoi ('v') without qh_produce_output(), call
+       qh_setvoronoi_all() after qh_qhull() */
+    qh_check_output();
+    print_summary ();
+    qh_produce_output();  /* delete this line to help avoid io.c */
+    if (qh VERIFYoutput && !qh STOPpoint && !qh STOPcone)
+      qh_check_points ();
+    printf( "\nadd points to triangulation\n");
+    addDelaunay (array[0], SIZEcube, SIZEdiamond, DIM); 
+    qh_check_output();
+    qh_produce_output();  /* delete this line to help avoid io.c */
+    if (qh VERIFYoutput && !qh STOPpoint && !qh STOPcone)
+      qh_check_points ();
+    printf( "\nfind Delaunay triangle closest to [0.5, 0.5, ...]\n");
+    findDelaunay (DIM);
+  }
+  qh NOerrexit= True;
+  qh_freeqhull (!qh_ALL);
+  qh_memfreeshort (&curlong, &totlong);
+  /*
+    Run 3: halfspace intersection
+  */
+  qh_init_A (stdin, stdout, stderr, 0, NULL);
+  exitcode= setjmp (qh errexit);
+  if (!exitcode) {
+    coordT array[TOTpoints][DIM+1];  /* +1 for halfspace offset */
+    pointT *points;
+
+    strcat (qh rbox_command, "user_eg halfspaces");
+    sprintf (options, "qhull H0 s Tcv %s", argc >= 4 ? argv[3] : "");
+    qh_initflags (options);
+    printf( "\ncompute halfspace intersection about the origin for a diamond\n");
+    makehalf (array[0], SIZEcube, DIM);
+    qh_setfeasible (DIM); /* from io.c, sets qh feasible_point from 'Hn,n' */
+    /* you may malloc and set qh feasible_point directly.  It is only used for
+       option 'Fp' */
+    points= qh_sethalfspace_all ( DIM+1, SIZEcube, array[0], qh feasible_point); 
+    qh_init_B (points, SIZEcube, DIM, True); /* qh_freeqhull frees points */
+    qh_qhull();
+    qh_check_output();
+    qh_produce_output();  /* delete this line to help avoid io.c */
+    if (qh VERIFYoutput && !qh STOPpoint && !qh STOPcone)
+      qh_check_points ();
+    printf( "\nadd halfspaces for cube to intersection\n");
+    addhalf (array[0], SIZEcube, SIZEdiamond, DIM, qh feasible_point); 
+    qh_check_output();
+    qh_produce_output();  /* delete this line to help avoid io.c */
+    if (qh VERIFYoutput && !qh STOPpoint && !qh STOPcone)
+      qh_check_points ();
+  }
+  qh NOerrexit= True;
+  qh NOerrexit= True;
+  qh_freeqhull (!qh_ALL);
+  qh_memfreeshort (&curlong, &totlong);
+  if (curlong || totlong)  /* could also check previous runs */
+    fprintf (stderr, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n",
+       totlong, curlong);
+  return exitcode;
+} /* main */
+
+#if 1    /* use 1 to prevent loading of io.o and user.o */
+/*-------------------------------------------
+-errexit- return exitcode to system after an error
+  assumes exitcode non-zero
+  prints useful information
+  see qh_errexit2() in qhull.c for 2 facets
+*/
+void qh_errexit(int exitcode, facetT *facet, ridgeT *ridge) {
+
+  if (qh ERREXITcalled) {
+    fprintf (qh ferr, "qhull error while processing previous error.  Exit program\n");
+    exit(1);
+  }
+  qh ERREXITcalled= True;
+  if (!qh QHULLfinished)
+    qh hulltime= (unsigned)clock() - qh hulltime;
+  fprintf (qh ferr, "\nWhile executing: %s | %s\n", qh rbox_command, qh qhull_command);
+  fprintf(qh ferr, "Options selected:\n%s\n", qh qhull_options);
+  if (qh furthest_id >= 0) {
+    fprintf(qh ferr, "\nLast point added to hull was p%d", qh furthest_id);
+    if (zzval_(Ztotmerge))
+      fprintf(qh ferr, "  Last merge was #%d.", zzval_(Ztotmerge));
+    if (qh QHULLfinished)
+      fprintf(qh ferr, "\nQhull has finished constructing the hull.");
+    else if (qh POSTmerging)
+      fprintf(qh ferr, "\nQhull has started post-merging");
+    fprintf(qh ferr, "\n\n");
+  }
+  if (qh NOerrexit) {
+    fprintf (qh ferr, "qhull error while ending program.  Exit program\n");
+    exit(1);
+  }
+  if (!exitcode)
+    exitcode= qh_ERRqhull;
+  qh NOerrexit= True;
+  longjmp(qh errexit, exitcode);
+} /* errexit */
+
+
+/*-------------------------------------------
+-errprint- prints out the information of the erroneous object
+    any parameter may be NULL, also prints neighbors and geomview output
+*/
+void qh_errprint(char *string, facetT *atfacet, facetT *otherfacet, ridgeT *atridge, vertexT *atvertex) {
+
+  fprintf (qh ferr, "%s facets f%d f%d ridge r%d vertex v%d\n",
+	   string, getid_(atfacet), getid_(otherfacet), getid_(atridge),
+	   getid_(atvertex));
+} /* errprint */
+
+
+void qh_printfacetlist(facetT *facetlist, setT *facets, boolT printall) {
+  facetT *facet, **facetp;
+
+  /* remove these calls to help avoid io.c */
+  qh_printbegin (qh ferr, qh_PRINTfacets, facetlist, facets, printall);/*io.c*/
+  FORALLfacet_(facetlist)                                              /*io.c*/
+    qh_printafacet(qh ferr, qh_PRINTfacets, facet, printall);          /*io.c*/
+  FOREACHfacet_(facets)                                                /*io.c*/
+    qh_printafacet(qh ferr, qh_PRINTfacets, facet, printall);          /*io.c*/
+  qh_printend (qh ferr, qh_PRINTfacets, facetlist, facets, printall);  /*io.c*/
+
+  FORALLfacet_(facetlist)
+    fprintf( qh ferr, "facet f%d\n", facet->id);
+} /* printfacetlist */
+
+
+
+/*-----------------------------------------
+-user_memsizes- allocate up to 10 additional, quick allocation sizes
+*/
+void qh_user_memsizes (void) {
+
+  /* qh_memsize (size); */
+} /* user_memsizes */
+
+#endif
diff --git a/extern/solid/CMakeLists.txt b/extern/solid/CMakeLists.txt
new file mode 100644
index 00000000000..496618c5914
--- /dev/null
+++ b/extern/solid/CMakeLists.txt
@@ -0,0 +1,37 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# 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. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License.  See http://www.blender.org/BL/ for information
+# about this.
+#
+# 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.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+SET(INC include src src/broad src/complex src/convex ../qhull/include)
+
+FILE(GLOB SRC src/*.cpp src/convex/*.cpp src/complex/*.cpp src/broad/*.cpp)
+
+ADD_DEFINITIONS(-DUSE_DOUBLES -DQHULL -D_LIB)
+
+BLENDERLIB(extern_solid "${SRC}" "${INC}")
+#, libtype=['game2','player'], priority=[45, 75]
diff --git a/extern/solid/LICENSE_GPL.txt b/extern/solid/LICENSE_GPL.txt
new file mode 100644
index 00000000000..07db89585a2
--- /dev/null
+++ b/extern/solid/LICENSE_GPL.txt
@@ -0,0 +1,349 @@
+
+ The SOLID library is Copyright (C) 2001-2003  Dtecta.
+
+ You may use, distribute and copy the SOLID library under the terms of
+ GNU General Public License version 2, which is displayed below.
+
+-------------------------------------------------------------------------
+
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 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.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  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
+this service 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 make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  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.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+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 Program or any portion
+of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+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 Program, 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 Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) 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; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, 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 executable.  However, as a
+special exception, the source code 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.
+
+If distribution of executable or 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 counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program 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.
+
+  5. 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 Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program 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 to
+this License.
+
+  7. 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 Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program 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 Program.
+
+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.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program 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.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the 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 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 Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, 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
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
+
+  12. 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 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.
+
+		     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
+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 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.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision 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, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  , 1 April 1989
+  Ty Coon, President of Vice
+
+This 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 Library General
+Public License instead of this License.
+
+-------------------------------------------------------------------------
diff --git a/extern/solid/LICENSE_QPL.txt b/extern/solid/LICENSE_QPL.txt
new file mode 100644
index 00000000000..3fca00466e2
--- /dev/null
+++ b/extern/solid/LICENSE_QPL.txt
@@ -0,0 +1,110 @@
+
+ The SOLID library is Copyright (C) 2001-2003  Dtecta.
+
+ You may use, distribute and copy the SOLID library under the terms of
+ the Q Public License, which is displayed below.
+
+-------------------------------------------------------------------------
+			     THE Q PUBLIC LICENSE
+				  version 1.0
+
+		   Copyright (C) 1999-2000 Trolltech AS, Norway.
+		       Everyone is permitted to copy and
+		       distribute this license document.
+
+The intent of this license is to establish freedom to share and change the
+software regulated by this license under the open source model.
+
+This license applies to any software containing a notice placed by the
+copyright holder saying that it may be distributed under the terms of
+the Q Public License version 1.0.  Such software is herein referred to as
+the Software.  This license covers modification and distribution of the
+Software, use of third-party application programs based on the Software,
+and development of free software which uses the Software.
+
+				 Granted Rights
+
+1. You are granted the non-exclusive rights set forth in this license
+   provided you agree to and comply with any and all conditions in this
+   license.  Whole or partial distribution of the Software, or software
+   items that link with the Software, in any form signifies acceptance of
+   this license.
+
+2. You may copy and distribute the Software in unmodified form provided
+   that the entire package, including - but not restricted to - copyright,
+   trademark notices and disclaimers, as released by the initial developer
+   of the Software, is distributed.
+
+3. You may make modifications to the Software and distribute your
+   modifications, in a form that is separate from the Software, such as
+   patches. The following restrictions apply to modifications:
+
+     a. Modifications must not alter or remove any copyright notices in
+        the Software.
+
+     b. When modifications to the Software are released under this
+        license, a non-exclusive royalty-free right is granted to the
+        initial developer of the Software to distribute your modification
+        in future versions of the Software provided such versions remain
+        available under these terms in addition to any other license(s) of
+        the initial developer.
+
+4. You may distribute machine-executable forms of the Software or
+   machine-executable forms of modified versions of the Software, provided
+   that you meet these restrictions:
+
+     a. You must include this license document in the distribution.
+
+     b. You must ensure that all recipients of the machine-executable forms
+        are also able to receive the complete machine-readable source code
+        to the distributed Software, including all modifications, without
+        any charge beyond the costs of data transfer, and place prominent
+        notices in the distribution explaining this.
+
+     c. You must ensure that all modifications included in the
+        machine-executable forms are available under the terms of this
+        license.
+
+5. You may use the original or modified versions of the Software to
+   compile, link and run application programs legally developed by you
+   or by others.
+
+6. You may develop application programs, reusable components and other
+   software items that link with the original or modified versions of the
+   Software.  These items, when distributed, are subject to the following
+   requirements:
+
+     a. You must ensure that all recipients of machine-executable forms of
+        these items are also able to receive and use the complete
+        machine-readable source code to the items without any charge
+        beyond the costs of data transfer.
+
+     b. You must explicitly license all recipients of your items to use
+        and re-distribute original and modified versions of the items in
+        both machine-executable and source code forms. The recipients must
+        be able to do so without any charges whatsoever, and they must be
+        able to re-distribute to anyone they choose.
+
+
+     c. If the items are not available to the general public, and the
+        initial developer of the Software requests a copy of the items,
+        then you must supply one.
+
+			    Limitations of Liability
+
+In no event shall the initial developers or copyright holders be liable
+for any damages whatsoever, including - but not restricted to - lost
+revenue or profits or other direct, indirect, special, incidental or
+consequential damages, even if they have been advised of the possibility
+of such damages, except to the extent invariable law, if any, provides
+otherwise.
+
+			          No Warranty
+
+The Software and this license document are provided AS IS with NO WARRANTY
+OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE.
+                                 Choice of Law
+
+This license is governed by the Laws of Norway. Disputes shall be settled
+by Oslo City Court.
diff --git a/extern/solid/Makefile b/extern/solid/Makefile
new file mode 100644
index 00000000000..ed5a1359cf4
--- /dev/null
+++ b/extern/solid/Makefile
@@ -0,0 +1,60 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# 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. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License.  See http://www.blender.org/BL/ for information
+# about this.
+#
+# 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.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+include nan_definitions.mk
+
+SOURCEDIR = extern/solid
+LIBNAMES = solid solid_broad solid_convex solid_complex
+DIR = $(OCGDIR)/extern/
+DIRS = src
+
+include nan_subdirs.mk
+
+install: all debug
+	@[ -d $(NAN_SOLID) ] || mkdir -p $(NAN_SOLID)
+	@[ -d $(NAN_SOLID)/include/SOLID ] || mkdir -p $(NAN_SOLID)/include/SOLID
+	@[ -d $(NAN_SOLID)/include/SOLID/MT ] || mkdir -p $(NAN_SOLID)/include/SOLID/MT
+	@[ -d $(NAN_SOLID)/lib ] || mkdir -p $(NAN_SOLID)/lib
+	@[ -d $(NAN_SOLID)/lib/debug ] || mkdir -p $(NAN_SOLID)/lib/debug
+	@for i in $(LIBNAMES); do \
+	    $(NANBLENDERHOME)/intern/tools/cpifdiff.sh $(DIR)/$$i/lib$$i.a $(NAN_SOLID)/lib/ ; \
+	    $(NANBLENDERHOME)/intern/tools/cpifdiff.sh $(DIR)/$$i/debug/lib$$i.a $(NAN_SOLID)/lib/debug/ ; \
+	    if [ $(OS) = darwin ] ; then \
+            ranlib $(NAN_SOLID)/lib/lib$$i.a ; \
+            ranlib $(NAN_SOLID)/lib/debug/lib$$i.a ; \
+        fi ; \
+	done
+	@$(NANBLENDERHOME)/intern/tools/cpifdiff.sh include/*.h $(NAN_SOLID)/include/SOLID
+	@$(NANBLENDERHOME)/intern/tools/cpifdiff.sh include/MT/*.h $(NAN_SOLID)/include/SOLID/MT
+
+
diff --git a/extern/solid/README.txt b/extern/solid/README.txt
new file mode 100644
index 00000000000..348d92b35cb
--- /dev/null
+++ b/extern/solid/README.txt
@@ -0,0 +1,55 @@
+
+		 SOLID - Software Library for Interference Detection
+
+SOLID is a software library containing functions for performing
+intersection tests and proximity queries that are useful in the context
+of collision detection. Collision detection is the process of detecting
+pairs of geometric objects that are intersecting or are within a given
+proximity of each other. In particular, SOLID is useful for detecting
+collisions between objects that are moving relatively of each other over
+time. The motions of objects are controlled by the client application,
+and are not determined or affected by SOLID. 
+
+This open-source edition of SOLID version 3 is released under the terms of
+either the GNU Public License (GPL) or the Q Public License (QPL). This means
+that for software created with SOLID version 3 you must comply with the terms
+of one of these licenses. You may choose wich of these licenses best suits
+your purpose. See the following files contained in this distribution for a
+complete list of terms and conditions of these licenses:  
+
+		 LICENSE_QPL.txt	 The Q Public License 
+		 LICENSE_GPL.txt	 The GNU General Public License
+
+These licenses do not permit the use of SOLID 3 in closed-source software
+products. For enquiries about commercial use of SOLID, please contact
+info@dtecta.com.    
+
+SOLID 3 uses Qhull from The Geometry Center of the University of Minnesota.
+Qhull is copyrighted as noted below.  Qhull is free software and may be
+obtained via anonymous ftp from geom.umn.edu.   
+        
+                    Qhull, Copyright (c) 1993-2002
+
+       The National Science and Technology Research Center for
+        Computation and Visualization of Geometric Structures
+                        (The Geometry Center)
+                       University of Minnesota
+                            400 Lind Hall
+                        207 Church Street S.E.
+                      Minneapolis, MN 55455  USA
+
+                       email: qhull@geom.umn.edu
+
+Installation
+
+For details on how to install SOLID see the documention in the 'doc' directory.
+
+Platforms
+
+SOLID 3 has been tested on the following platforms:
+
+    Linux IA32  gcc 2.95.3, gcc 3.3
+	Win32		MSVC++ 6.0 SP4, MSVC++ 7.1 
+
+  
+
diff --git a/extern/solid/SConscript b/extern/solid/SConscript
new file mode 100644
index 00000000000..7482014c0a4
--- /dev/null
+++ b/extern/solid/SConscript
@@ -0,0 +1,34 @@
+#!/usr/bin/python
+import sys
+
+Import('env')
+
+defs = 'USE_DOUBLES QHULL _LIB'
+cflags = []
+
+if env['OURPLATFORM']=='win32-vc':
+    defs += ' WIN32 NDEBUG _WINDOWS _LIB'
+    cflags += ['/MT', '/W3', '/GX', '/Og', '/Ot', '/Ob1', '/Op', '/G6']
+elif env['OURPLATFORM']=='win32-mingw':
+    defs += ' NDEBUG'
+    cflags += ['-O2']
+elif sys.platform=='linux2' or sys.platform=='linux-i386' or sys.platform=='freebsd4' or sys.platform=='freebsd5' or sys.platform=='openbsd3' or sys.platform=='sunos5':
+    defs += ' NDEBUG'
+    cflags += ['-O2']
+elif sys.platform=='darwin' :
+    defs += ' NDEBUG'
+    cflags += ['-O2','-pipe', '-fPIC', '-funsigned-char', '-ffast-math']
+
+else:
+    print "################################################"
+    print 
+    print "Check if solid builds on your platform correctly"
+    print "Add your platform specific defines"
+    print "and cflags / cxxflags to the"
+    print "extern/solid/SConscript file"
+
+sources = env.Glob('src/*.cpp') + env.Glob('src/convex/*.cpp') + env.Glob('src/complex/*.cpp') + env.Glob('src/broad/*.cpp')
+
+incs = 'include src src/broad src/complex src/convex ../qhull/include'
+
+env.BlenderLib ( libname='extern_solid', sources=sources, includes=Split(incs), defines=Split(defs), libtype=['game2','player'], priority=[45, 75] , compileflags = cflags)
diff --git a/extern/solid/SOLID/SOLID.h b/extern/solid/SOLID/SOLID.h
new file mode 100644
index 00000000000..37d74340f8c
--- /dev/null
+++ b/extern/solid/SOLID/SOLID.h
@@ -0,0 +1,279 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef SOLID_H
+#define SOLID_H
+
+#include "SOLID_types.h"
+
+#ifdef __cplusplus
+extern "C" { 
+#endif
+    
+	DT_DECLARE_HANDLE(DT_ObjectHandle);
+	DT_DECLARE_HANDLE(DT_SceneHandle);
+	DT_DECLARE_HANDLE(DT_ShapeHandle);
+	DT_DECLARE_HANDLE(DT_VertexBaseHandle);
+	DT_DECLARE_HANDLE(DT_RespTableHandle);
+	DT_DECLARE_HANDLE(DT_ArchiveHandle);
+
+	typedef unsigned int DT_ResponseClass;
+
+	typedef enum DT_ResponseType { 
+		DT_NO_RESPONSE,                  /* No response (obsolete) */        
+		DT_BROAD_RESPONSE,      
+		DT_SIMPLE_RESPONSE,              /* No collision data */
+		DT_WITNESSED_RESPONSE,           /* A point common to both objects
+											is returned as collision data
+										 */
+		DT_DEPTH_RESPONSE                /* The penetration depth is returned
+											as collision data. The penetration depth
+											is the shortest vector over which one 
+											object needs to be translated in order
+											to bring the objects in touching contact. 
+										 */ 
+	} DT_ResponseType;
+    
+/* For witnessed response, the following structure represents a common point. The world 
+   coordinates of 'point1' and 'point2' coincide. 'normal' is the zero vector.
+   
+   For depth response, the following structure represents the penetration depth. 
+   'point1' en 'point2' are the witness points of the penetration depth in world coordinates.
+   The penetration depth vector in world coordinates is represented by 'normal'.
+*/
+
+	typedef struct DT_CollData {
+		DT_Vector3 point1;               /* Point in object1 in world coordinates */ 
+		DT_Vector3 point2;               /* Point in object2 in world coordinates */
+		DT_Vector3 normal;               /* point2 - point1 */ 
+	} DT_CollData;
+
+/* A response callback is called by SOLID for each pair of collding objects. 'client-data'
+   is a pointer to an arbitrary structure in the client application. The client objects are
+   pointers to structures in the client application associated with the coliding objects.
+   'coll_data' is the collision data computed by SOLID.
+*/
+
+	typedef DT_Bool (*DT_ResponseCallback)(void *client_data,
+										   void *client_object1,
+										   void *client_object2,
+										   const DT_CollData *coll_data);
+										
+/* Shape definition */
+
+
+	extern DECLSPEC DT_ShapeHandle DT_NewBox(DT_Scalar x, DT_Scalar y, DT_Scalar z);
+	extern DECLSPEC DT_ShapeHandle DT_NewCone(DT_Scalar radius, DT_Scalar height);
+	extern DECLSPEC DT_ShapeHandle DT_NewCylinder(DT_Scalar radius, DT_Scalar height);
+	extern DECLSPEC DT_ShapeHandle DT_NewSphere(DT_Scalar radius);
+	extern DECLSPEC DT_ShapeHandle DT_NewPoint(const DT_Vector3 point);
+	extern DECLSPEC DT_ShapeHandle DT_NewLineSegment(const DT_Vector3 source, const DT_Vector3 target);
+	extern DECLSPEC DT_ShapeHandle DT_NewMinkowski(DT_ShapeHandle shape1, DT_ShapeHandle shape2);
+	extern DECLSPEC DT_ShapeHandle DT_NewHull(DT_ShapeHandle shape1, DT_ShapeHandle shape2);
+
+	extern DECLSPEC DT_VertexBaseHandle DT_NewVertexBase(const void *pointer, DT_Size stride);
+	extern DECLSPEC void DT_DeleteVertexBase(DT_VertexBaseHandle vertexBase);	
+	extern DECLSPEC void DT_ChangeVertexBase(DT_VertexBaseHandle vertexBase, const void *pointer);
+
+	extern DECLSPEC DT_ShapeHandle DT_NewComplexShape(DT_VertexBaseHandle vertexBase);
+	extern DECLSPEC void           DT_EndComplexShape();
+
+	extern DECLSPEC DT_ShapeHandle DT_NewPolytope(DT_VertexBaseHandle vertexBase);
+	extern DECLSPEC void           DT_EndPolytope();
+
+	extern DECLSPEC void DT_Begin();
+	extern DECLSPEC void DT_End();
+
+	extern DECLSPEC void DT_Vertex(const DT_Vector3 vertex);
+	extern DECLSPEC void DT_VertexIndex(DT_Index index);
+
+	extern DECLSPEC void DT_VertexIndices(DT_Count count, const DT_Index *indices);
+	extern DECLSPEC void DT_VertexRange(DT_Index first, DT_Count count); 
+
+	extern DECLSPEC void DT_DeleteShape(DT_ShapeHandle shape);
+
+/* Object  */
+
+	extern DECLSPEC DT_ObjectHandle DT_CreateObject(
+		void *client_object,      /* pointer to object in client memory */
+		DT_ShapeHandle shape  /* the shape or geometry of the object */
+		);
+
+	extern DECLSPEC void DT_DestroyObject(DT_ObjectHandle object);
+
+
+
+	extern DECLSPEC void DT_SetPosition(DT_ObjectHandle object, const DT_Vector3 position);
+	extern DECLSPEC void DT_SetOrientation(DT_ObjectHandle object, const DT_Quaternion orientation);
+	extern DECLSPEC void DT_SetScaling(DT_ObjectHandle object, const DT_Vector3 scaling);
+
+/* The margin is an offset from the actual shape. The actual geometry of an
+   object is the set of points whose distance to the transformed shape is at 
+   most the  margin. During the lifetime of an object the margin can be 
+   modified. 
+*/
+   
+	extern DECLSPEC void DT_SetMargin(DT_ObjectHandle object, DT_Scalar margin);
+
+
+/* These commands assume a column-major 4x4 OpenGL matrix representation */
+
+	extern DECLSPEC void DT_SetMatrixf(DT_ObjectHandle object, const float *m); 
+	extern DECLSPEC void DT_GetMatrixf(DT_ObjectHandle object, float *m); 
+
+	extern DECLSPEC void DT_SetMatrixd(DT_ObjectHandle object, const double *m); 
+	extern DECLSPEC void DT_GetMatrixd(DT_ObjectHandle object, double *m); 
+
+	extern DECLSPEC void DT_GetBBox(DT_ObjectHandle object, DT_Vector3 min, DT_Vector3 max);
+
+
+	extern DECLSPEC DT_Bool  DT_GetIntersect(DT_ObjectHandle object1, DT_ObjectHandle object2,
+												DT_Vector3 v);
+/* This next command returns the distance between the objects. De returned
+   closest points are given in world coordinates.
+*/
+	extern DECLSPEC DT_Scalar DT_GetClosestPair(DT_ObjectHandle object1, DT_ObjectHandle object2,
+												DT_Vector3 point1, DT_Vector3 point2);  
+
+	extern DECLSPEC DT_Bool   DT_GetCommonPoint(DT_ObjectHandle object1, DT_ObjectHandle object2,
+												DT_Vector3 point);
+
+	extern DECLSPEC DT_Bool   DT_GetPenDepth(DT_ObjectHandle object1, DT_ObjectHandle object2,
+											 DT_Vector3 point1, DT_Vector3 point2);  
+
+/* Scene */
+
+	extern DECLSPEC DT_SceneHandle DT_CreateScene(); 
+	extern DECLSPEC void           DT_DestroyScene(DT_SceneHandle scene);
+
+	extern DECLSPEC void DT_AddObject(DT_SceneHandle scene, DT_ObjectHandle object);
+	extern DECLSPEC void DT_RemoveObject(DT_SceneHandle scene, DT_ObjectHandle object);
+
+/* Note that objects can be assigned to multiple scenes! */
+
+/* Response */
+
+/* Response tables are defined independent of the scenes in which they are used.
+   Multiple response tables can be used in one scene, and a response table
+   can be shared among scenes.
+*/
+	extern DECLSPEC DT_RespTableHandle DT_CreateRespTable(); 
+	extern DECLSPEC void               DT_DestroyRespTable(DT_RespTableHandle respTable); 
+
+/* Responses are defined on (pairs of) response classes. Each response table 
+   maintains its set of response classes.
+*/
+	extern DECLSPEC DT_ResponseClass DT_GenResponseClass(DT_RespTableHandle respTable);
+
+/* To each object for which a response is defined in the response table a
+   response class needs to be assigned. 
+*/
+
+	extern DECLSPEC void DT_SetResponseClass(DT_RespTableHandle respTable,
+											 DT_ObjectHandle object,
+											 DT_ResponseClass responseClass);
+
+	extern DECLSPEC void DT_ClearResponseClass(DT_RespTableHandle respTable, 
+											   DT_ObjectHandle object);
+
+	extern DECLSPEC void DT_CallResponse(DT_RespTableHandle respTable,
+										 DT_ObjectHandle object1,
+										 DT_ObjectHandle object2,
+										 const DT_CollData *coll_data);
+
+/* For each pair of objects multiple responses can be defined. A response is a callback
+   together with its response type and client data. */
+    
+/* Responses can be defined for all pairs of response classes... */
+	extern DECLSPEC void DT_AddDefaultResponse(DT_RespTableHandle respTable,
+											   DT_ResponseCallback response, 
+											   DT_ResponseType type, void *client_data);
+
+	extern DECLSPEC void DT_RemoveDefaultResponse(DT_RespTableHandle respTable,
+												  DT_ResponseCallback response);
+/* ...per response class... */
+	extern DECLSPEC void DT_AddClassResponse(DT_RespTableHandle respTable,
+											 DT_ResponseClass responseClass,
+											 DT_ResponseCallback response,
+											 DT_ResponseType type, void *client_data);
+
+	extern DECLSPEC void DT_RemoveClassResponse(DT_RespTableHandle respTable,
+												DT_ResponseClass responseClass,
+												DT_ResponseCallback response);
+
+/* ... and per pair of response classes...*/
+	extern DECLSPEC void DT_AddPairResponse(DT_RespTableHandle respTable,
+											DT_ResponseClass responseClass1,
+											DT_ResponseClass responseClass2, 
+											DT_ResponseCallback response,
+											DT_ResponseType type, void *client_data);
+	extern DECLSPEC void DT_RemovePairResponse(DT_RespTableHandle respTable,
+											   DT_ResponseClass responseClass1,
+											   DT_ResponseClass responseClass2,
+											   DT_ResponseCallback response);
+
+/* The next command calls the response callbacks for all intersecting pairs of objects in a scene. 
+   'DT_Test' returns the number of pairs of objects for which callbacks have been called. 
+*/
+ 
+	extern DECLSPEC DT_Count DT_Test(DT_SceneHandle scene, DT_RespTableHandle respTable);
+
+/* Set the maximum relative error in the closest points and penetration depth
+   computation. The default for `max_error' is 1.0e-3. Larger errors result
+   in better performance. Non-positive error tolerances are ignored.
+*/ 
+
+	extern DECLSPEC void DT_SetAccuracy(DT_Scalar max_error);
+
+/* Set the maximum tolerance on relative errors due to rounding.  The default for `tol_error' 
+   is the machine epsilon. Very large tolerances result in false collisions. Setting tol_error too small 
+   results in missed collisions. Non-positive error tolerances are ignored. 
+*/ 
+    
+	extern DECLSPEC void DT_SetTolerance(DT_Scalar tol_error);
+
+
+/* This function returns the client pointer to the first object in a scene hit by the ray 
+   (actually a line segment) defined by the points 'from' en 'to'. The spot is the hit point 
+   on the object in local coordinates. 'normal' is the normal to the surface of the object in
+   world coordinates. The ignore_client pointer is used to make one of the objects transparent.
+
+   NB: Currently ray tests are implemented for spheres, boxes, and meshes only!!
+*/   
+
+	extern DECLSPEC void *DT_RayCast(DT_SceneHandle scene, void *ignore_client,
+									 const DT_Vector3 source, const DT_Vector3 target,
+									 DT_Scalar max_param, DT_Scalar *param, DT_Vector3 normal);
+
+/* Similar, only here a single object is tested and a boolean is returned */
+
+	extern DECLSPEC DT_Bool DT_ObjectRayCast(DT_ObjectHandle object,
+											 const DT_Vector3 source, const DT_Vector3 target,
+											 DT_Scalar max_param, DT_Scalar *param, DT_Vector3 normal);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/extern/solid/SOLID/SOLID_broad.h b/extern/solid/SOLID/SOLID_broad.h
new file mode 100644
index 00000000000..74e4214fa67
--- /dev/null
+++ b/extern/solid/SOLID/SOLID_broad.h
@@ -0,0 +1,75 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef SOLID_BROAD_H
+#define SOLID_BROAD_H
+
+#include "SOLID_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+    
+	DT_DECLARE_HANDLE(BP_SceneHandle);
+	DT_DECLARE_HANDLE(BP_ProxyHandle);
+	
+	typedef void (*BP_Callback)(void *client_data,
+								void *object1,
+								void *object2);
+
+	typedef bool (*BP_RayCastCallback)(void *client_data,
+									   void *object,
+									   const DT_Vector3 source,
+									   const DT_Vector3 target,
+									   DT_Scalar *lambda);
+	
+	extern DECLSPEC BP_SceneHandle BP_CreateScene(void *client_data,
+												  BP_Callback beginOverlap,
+												  BP_Callback endOverlap);
+	
+	extern DECLSPEC void           BP_DestroyScene(BP_SceneHandle scene);
+	
+	extern DECLSPEC BP_ProxyHandle BP_CreateProxy(BP_SceneHandle scene, 
+												  void *object,
+												  const DT_Vector3 min, 
+												  const DT_Vector3 max);
+	
+	extern DECLSPEC void           BP_DestroyProxy(BP_SceneHandle scene, 
+												  BP_ProxyHandle proxy);
+	
+	extern DECLSPEC void BP_SetBBox(BP_ProxyHandle proxy, 
+									const DT_Vector3 min, 
+									const DT_Vector3 max);
+	
+	extern DECLSPEC void *BP_RayCast(BP_SceneHandle scene, 
+									 BP_RayCastCallback objectRayCast, 
+									 void *client_data,
+									 const DT_Vector3 source,
+									 const DT_Vector3 target,
+									 DT_Scalar *lambda);		
+	
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/extern/solid/SOLID/SOLID_types.h b/extern/solid/SOLID/SOLID_types.h
new file mode 100644
index 00000000000..630594e447f
--- /dev/null
+++ b/extern/solid/SOLID/SOLID_types.h
@@ -0,0 +1,53 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef SOLID_TYPES_H
+#define SOLID_TYPES_H
+
+#ifndef DECLSPEC
+# ifdef WIN32
+#  define DECLSPEC __declspec(dllexport)
+# else
+#  define DECLSPEC
+# endif
+#endif
+
+#define DT_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name
+    
+
+typedef unsigned short DT_Index;
+typedef unsigned short DT_Count;
+typedef unsigned int   DT_Size;
+typedef float          DT_Scalar; 
+typedef int            DT_Bool;
+
+#define DT_FALSE 0
+#define DT_TRUE  1
+
+#define DT_CONTINUE 0
+#define DT_DONE 1
+
+typedef DT_Scalar DT_Vector3[3]; 
+typedef DT_Scalar DT_Quaternion[4]; 
+
+#endif
diff --git a/extern/solid/VisualC6/broad/broad.dsp b/extern/solid/VisualC6/broad/broad.dsp
new file mode 100644
index 00000000000..1161d68fcd6
--- /dev/null
+++ b/extern/solid/VisualC6/broad/broad.dsp
@@ -0,0 +1,132 @@
+# Microsoft Developer Studio Project File - Name="broad" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=broad - 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 "broad.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 "broad.mak" CFG="broad - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "broad - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "broad - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "broad - 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 ""
+LINK32=cwlink.exe
+MTL=midl.exe
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# 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
+
+!ELSEIF  "$(CFG)" == "broad - 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 ""
+LINK32=cwlink.exe
+MTL=midl.exe
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /MT /W3 /GX /Zd /Od /I "../../include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# 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
+
+!ENDIF 
+
+# Begin Target
+
+# Name "broad - Win32 Release"
+# Name "broad - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE="..\..\src\broad\BP_C-api.cpp"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\broad\BP_EndpointList.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\broad\BP_Proxy.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\broad\BP_Scene.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\src\broad\BP_Endpoint.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\broad\BP_EndpointList.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\broad\BP_Proxy.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\broad\BP_ProxyList.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\broad\BP_Scene.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/extern/solid/VisualC6/complex/complex.dsp b/extern/solid/VisualC6/complex/complex.dsp
new file mode 100644
index 00000000000..74ea67b9e23
--- /dev/null
+++ b/extern/solid/VisualC6/complex/complex.dsp
@@ -0,0 +1,116 @@
+# Microsoft Developer Studio Project File - Name="complex" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=complex - 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 "complex.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 "complex.mak" CFG="complex - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "complex - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "complex - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "complex - 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 ""
+LINK32=cwlink.exe
+MTL=midl.exe
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../include" /I "../../src/convex" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# 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
+
+!ELSEIF  "$(CFG)" == "complex - 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 ""
+LINK32=cwlink.exe
+MTL=midl.exe
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /MT /W3 /GX /Zd /Od /I "../../include" /I "../../src/convex" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# 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
+
+!ENDIF 
+
+# Begin Target
+
+# Name "complex - Win32 Release"
+# Name "complex - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\src\complex\DT_BBoxTree.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\complex\DT_Complex.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\src\complex\DT_BBoxTree.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\complex\DT_CBox.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\complex\DT_Complex.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/extern/solid/VisualC6/convex/convex.dsp b/extern/solid/VisualC6/convex/convex.dsp
new file mode 100644
index 00000000000..ec9caace9d9
--- /dev/null
+++ b/extern/solid/VisualC6/convex/convex.dsp
@@ -0,0 +1,232 @@
+# Microsoft Developer Studio Project File - Name="convex" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=convex - 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 "convex.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 "convex.mak" CFG="convex - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "convex - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "convex - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "convex - 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 ""
+LINK32=cwlink.exe
+MTL=midl.exe
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../include" /I "../../../qhull/include" /D "NDEBUG" /D "QHULL" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /c
+# 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
+
+!ELSEIF  "$(CFG)" == "convex - 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 ""
+LINK32=cwlink.exe
+MTL=midl.exe
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /MT /W3 /GX /Zd /Od /I "../../include" /I "../../../qhull/include" /D "_DEBUG" /D "QHULL" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# 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
+
+!ENDIF 
+
+# Begin Target
+
+# Name "convex - Win32 Release"
+# Name "convex - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Accuracy.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Box.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Cone.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Convex.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Cylinder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Facet.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_LineSegment.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_PenDepth.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Point.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Polyhedron.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Polytope.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Sphere.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Triangle.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Accuracy.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Array.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Box.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Cone.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Convex.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Cylinder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Facet.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_GJK.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Hull.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_IndexArray.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_LineSegment.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Minkowski.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_PenDepth.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Point.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Polyhedron.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Polytope.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Shape.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Sphere.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Transform.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Triangle.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_VertexBase.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/extern/solid/VisualC6/dynamics/dynamics.dsp b/extern/solid/VisualC6/dynamics/dynamics.dsp
new file mode 100644
index 00000000000..9659cbf8a56
--- /dev/null
+++ b/extern/solid/VisualC6/dynamics/dynamics.dsp
@@ -0,0 +1,120 @@
+# Microsoft Developer Studio Project File - Name="dynamics" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=dynamics - 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 "dynamics.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 "dynamics.mak" CFG="dynamics - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "dynamics - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "dynamics - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "dynamics - 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 ""
+LINK32=cwlink.exe
+MTL=midl.exe
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# 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
+
+!ELSEIF  "$(CFG)" == "dynamics - 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 ""
+LINK32=cwlink.exe
+MTL=midl.exe
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /MD /W3 /GX /Zd /Od /I "../../include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# 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
+
+!ENDIF 
+
+# Begin Target
+
+# Name "dynamics - Win32 Release"
+# Name "dynamics - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\examples\dynamics\Dynamic.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\examples\dynamics\Kinetic.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\examples\dynamics\RigidBody.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\examples\dynamics\Dynamic.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\examples\dynamics\Kinetic.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\examples\dynamics\RigidBody.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/extern/solid/VisualC6/gldemo/gldemo.dsp b/extern/solid/VisualC6/gldemo/gldemo.dsp
new file mode 100644
index 00000000000..f3cde286161
--- /dev/null
+++ b/extern/solid/VisualC6/gldemo/gldemo.dsp
@@ -0,0 +1,102 @@
+# Microsoft Developer Studio Project File - Name="gldemo" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=gldemo - 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 "gldemo.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 "gldemo.mak" CFG="gldemo - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "gldemo - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "gldemo - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "gldemo - 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 Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "gldemo - 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 Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MD /W3 /GX /Zd /Od /I "../../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "gldemo - Win32 Release"
+# Name "gldemo - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\examples\gldemo.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/extern/solid/VisualC6/mnm/mnm.dsp b/extern/solid/VisualC6/mnm/mnm.dsp
new file mode 100644
index 00000000000..2df6d951794
--- /dev/null
+++ b/extern/solid/VisualC6/mnm/mnm.dsp
@@ -0,0 +1,100 @@
+# Microsoft Developer Studio Project File - Name="mnm" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=mnm - 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 "mnm.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 "mnm.mak" CFG="mnm - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "mnm - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "mnm - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "mnm - 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 "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../include" /I "../../examples/dynamics" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "mnm - 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 "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MD /W3 /GX /Zd /Od /I "../../include" /I "../../examples/dynamics" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "mnm - Win32 Release"
+# Name "mnm - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\examples\mnm.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/extern/solid/VisualC6/physics/physics.dsp b/extern/solid/VisualC6/physics/physics.dsp
new file mode 100644
index 00000000000..dd69b6a35b2
--- /dev/null
+++ b/extern/solid/VisualC6/physics/physics.dsp
@@ -0,0 +1,100 @@
+# Microsoft Developer Studio Project File - Name="physics" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=physics - 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 "physics.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 "physics.mak" CFG="physics - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "physics - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "physics - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "physics - 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 "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../include" /I "../../examples/dynamics" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "physics - 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 "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MD /W3 /GX /Zd /Od /I "../../include" /I "../../examples/dynamics" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "physics - Win32 Release"
+# Name "physics - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\examples\physics.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/extern/solid/VisualC6/sample/sample.dsp b/extern/solid/VisualC6/sample/sample.dsp
new file mode 100644
index 00000000000..c6e0423cd04
--- /dev/null
+++ b/extern/solid/VisualC6/sample/sample.dsp
@@ -0,0 +1,102 @@
+# Microsoft Developer Studio Project File - Name="sample" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=sample - 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 "sample.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 "sample.mak" CFG="sample - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "sample - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "sample - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "sample - 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 Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "sample - 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 Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MD /W3 /GX /Zd /Od /I "../../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "sample - Win32 Release"
+# Name "sample - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\examples\sample.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/extern/solid/VisualC6/solid.dsw b/extern/solid/VisualC6/solid.dsw
new file mode 100644
index 00000000000..397cc4bf371
--- /dev/null
+++ b/extern/solid/VisualC6/solid.dsw
@@ -0,0 +1,89 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "broad"=".\broad\broad.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "complex"=".\complex\complex.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "convex"=".\convex\convex.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name qhull
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "qhull"="..\..\qhull\VisualC6\qhull\qhull.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "solid"=".\solid\solid.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name broad
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name complex
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name convex
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/extern/solid/VisualC6/solid/solid.dsp b/extern/solid/VisualC6/solid/solid.dsp
new file mode 100644
index 00000000000..4ac7459c2f9
--- /dev/null
+++ b/extern/solid/VisualC6/solid/solid.dsp
@@ -0,0 +1,148 @@
+# Microsoft Developer Studio Project File - Name="solid" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=solid - 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 "solid.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 "solid.mak" CFG="solid - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "solid - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "solid - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "solid - 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 ""
+LINK32=cwlink.exe
+MTL=midl.exe
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../include" /I "../../src/convex" /I "../../src/complex" /D "NDEBUG" /D "QHULL" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /c
+# 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
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PostBuild_Cmds=XCOPY   /Y   ..\..\include\SOLID*.h   ..\..\..\..\..\lib\windows\solid\include\solid\  	XCOPY   /Y   Release\*.lib   ..\..\..\..\..\lib\windows\solid\lib\ 
+# End Special Build Tool
+
+!ELSEIF  "$(CFG)" == "solid - 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 ""
+LINK32=cwlink.exe
+MTL=midl.exe
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /MT /W3 /GX /Zd /Od /I "../../include" /I "../../src/convex" /I "../../src/complex" /D "_DEBUG" /D "QHULL" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# 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
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PostBuild_Cmds=XCOPY   /Y   ..\..\include\SOLID*.h   ..\..\..\..\..\lib\windows\solid\include\solid\  	XCOPY   /Y   Debug\*.lib   ..\..\..\..\..\lib\windows\solid\lib\Debug\ 
+# End Special Build Tool
+
+!ENDIF 
+
+# Begin Target
+
+# Name "solid - Win32 Release"
+# Name "solid - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE="..\..\src\DT_C-api.cpp"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Encounter.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Object.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_RespTable.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Scene.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\src\DT_AlgoTable.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Encounter.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Object.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Response.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_RespTable.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Scene.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/extern/solid/VisualC6/solid_dll/solid_dll.dsp b/extern/solid/VisualC6/solid_dll/solid_dll.dsp
new file mode 100644
index 00000000000..eed092502e0
--- /dev/null
+++ b/extern/solid/VisualC6/solid_dll/solid_dll.dsp
@@ -0,0 +1,147 @@
+# Microsoft Developer Studio Project File - Name="solid_dll" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=solid_dll - 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 "solid_dll.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 "solid_dll.mak" CFG="solid_dll - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "solid_dll - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "solid_dll - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "solid_dll - 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 "../../lib/win32/vc6"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOLID_DLL_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../include" /I "../../src/convex" /I "../../src/complex" /D "NDEBUG" /D "USE_DOUBLES" /D "QHULL" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOLID_DLL_EXPORTS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"../../lib/win32/vc6/solid.dll"
+
+!ELSEIF  "$(CFG)" == "solid_dll - 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 "../../lib/win32/vc6"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOLID_DLL_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MD /W3 /GX /Zd /Od /I "../../include" /I "../../src/convex" /I "../../src/complex" /D "_DEBUG" /D "QHULL" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOLID_DLL_EXPORTS" /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"../../lib/win32/vc6/solidd.dll" /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "solid_dll - Win32 Release"
+# Name "solid_dll - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE="..\..\src\DT_C-api.cpp"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Encounter.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Object.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_RespTable.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Scene.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\src\DT_AlgoTable.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Encounter.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Object.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Response.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_RespTable.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Scene.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/extern/solid/include/GEN_MinMax.h b/extern/solid/include/GEN_MinMax.h
new file mode 100644
index 00000000000..9ea961cfe4f
--- /dev/null
+++ b/extern/solid/include/GEN_MinMax.h
@@ -0,0 +1,76 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef GEN_MINMAX_H
+#define GEN_MINMAX_H
+
+template 
+inline const T& GEN_min(const T& a, const T& b) 
+{
+  return b < a ? b : a;
+}
+
+template 
+inline const T& GEN_max(const T& a, const T& b) 
+{
+  return  a < b ? b : a;
+}
+
+template 
+inline const T& GEN_clamped(const T& a, const T& lb, const T& ub) 
+{
+	return a < lb ? lb : (ub < a ? ub : a); 
+}
+
+template 
+inline void GEN_set_min(T& a, const T& b) 
+{
+    if (b < a) 
+	{
+		a = b;
+	}
+}
+
+template 
+inline void GEN_set_max(T& a, const T& b) 
+{
+    if (a < b) 
+	{
+		a = b;
+	}
+}
+
+template 
+inline void GEN_clamp(T& a, const T& lb, const T& ub) 
+{
+	if (a < lb) 
+	{
+		a = lb; 
+	}
+	else if (ub < a) 
+	{
+		a = ub;
+	}
+}
+
+#endif
diff --git a/extern/solid/include/GEN_random.h b/extern/solid/include/GEN_random.h
new file mode 100644
index 00000000000..4690a05511a
--- /dev/null
+++ b/extern/solid/include/GEN_random.h
@@ -0,0 +1,49 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef GEN_RANDOM_H
+#define GEN_RANDOM_H
+
+#ifdef MT19937
+
+#include 
+#include 
+
+#define GEN_RAND_MAX UINT_MAX
+
+inline void         GEN_srand(unsigned int seed) { init_genrand(seed); }
+inline unsigned int GEN_rand()                   { return genrand_int32(); }
+
+#else
+
+#include 
+
+#define GEN_RAND_MAX RAND_MAX
+
+inline void         GEN_srand(unsigned int seed) { srand(seed); } 
+inline unsigned int GEN_rand()                   { return rand(); }
+
+#endif
+
+#endif
+
diff --git a/extern/solid/include/MT/Interval.h b/extern/solid/include/MT/Interval.h
new file mode 100644
index 00000000000..c6ba2fc1681
--- /dev/null
+++ b/extern/solid/include/MT/Interval.h
@@ -0,0 +1,180 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef INTERVAL_H
+#define INTERVAL_H
+
+#if defined (__sgi)
+#include 
+#else
+#include 
+#endif
+
+#include 
+#include 
+
+namespace MT {
+
+	template 
+	class Interval {
+	public:
+		Interval() {}
+		
+
+#if _MSC_VER <= 1200
+        explicit Interval(const Scalar& x) 
+		    : m_lb(x), m_ub(x)
+	    {}
+        
+ 
+		Interval(const Scalar& lb, const Scalar& ub) 
+			: m_lb(lb), m_ub(ub)
+		{
+			assert(lb <= ub);
+		}
+#else
+		template 
+		explicit Interval(const Scalar2& x) 
+			: m_lb(x), m_ub(x)
+		{}
+		
+		template 
+		Interval(const Scalar2& lb, const Scalar2& ub) 
+			: m_lb(lb), m_ub(ub)
+		{
+			assert(lb <= ub);
+		}
+		
+		template 
+		Interval(const Interval& z) 
+		{ 
+			*this = z; 
+		}
+		
+		template 
+		Interval& operator=(const Interval& z) 
+		{ 
+			m_lb = Scalar(z.lower()); 
+			m_ub = Scalar(z.upper()); 
+			return *this;
+		}
+#endif
+      
+		
+
+		Scalar&       lower()       { return m_lb; }
+		const Scalar& lower() const { return m_lb; }
+		
+		Scalar&       upper()       { return m_ub; }
+		const Scalar& upper() const { return m_ub; }
+		 
+		Scalar center() const { return (m_lb + m_ub) * Scalar(0.5); } 
+		Scalar extent() const { return (m_ub - m_lb) * Scalar(0.5); } 
+
+	
+	protected:
+		Scalar m_lb, m_ub;
+	};
+
+	template 
+	inline Interval 
+	operator+(const Interval& z1, const Interval& z2)
+	{
+		return Interval(z1.lower() + z2.lower(), 
+								z1.upper() + z2.upper());
+	}
+
+	template 
+	inline Interval 
+	operator-(const Interval& z1, const Interval& z2)
+	{
+		return Interval(z1.lower() - z2.upper(), 
+								z1.upper() - z2.lower());
+	}
+	
+	template 
+	inline std::ostream& 
+	operator<<(std::ostream& os, const Interval& z)
+	{
+		return os << '[' << z.lower() << ", " << z.upper() << ']';
+	}
+
+	template 
+	inline Scalar 
+	median(const Interval& z) 
+	{
+		return (z.lower() + z.upper()) * Scalar(0.5);
+	}
+	
+	template 
+	inline Scalar 
+	width(const Interval& z) 
+	{
+		return z.upper() - z.lower();
+	}
+	
+	template 
+	inline bool 
+	overlap(const Interval& z1, const Interval& z2) 
+	{
+		return z1.lower() <= z2.upper() && z2.lower() <= z1.upper();
+	}
+
+	template 
+	inline bool 
+	in(const Interval& z1, const Interval& z2) 
+	{
+		return z2.lower() <= z1.lower() && z1.upper() <= z2.upper();
+	}
+
+	template 
+	inline bool 
+	in(Scalar x, const Interval& z) 
+	{
+		return z.lower() <= x && x <= z.upper();
+	}
+	
+	template 
+	inline Interval 
+	widen(const Interval& z, const Scalar& x) 
+	{
+		return Interval(z.lower() - x, z.upper() + x);
+	}	
+		
+	template
+	inline Interval
+	hull(const Interval& z1, const Interval& z2)
+	{
+		return Interval(GEN_min(z1.lower(), z2.lower()), 
+								GEN_max(z1.upper(), z2.upper()));
+	}	
+   
+   template
+	inline Interval
+	operator+(Scalar x, const Interval& z)
+	{
+		return Interval(x + z.lower(), x + z.upper());
+	}
+}
+
+#endif
diff --git a/extern/solid/include/MT/Matrix3x3.h b/extern/solid/include/MT/Matrix3x3.h
new file mode 100644
index 00000000000..85e0d4cac84
--- /dev/null
+++ b/extern/solid/include/MT/Matrix3x3.h
@@ -0,0 +1,380 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef MATRIX3X3_H
+#define MATRIX3X3_H
+
+#if defined (__sgi)
+#include 
+#else
+#include 
+#endif
+
+#include "Vector3.h"
+#include "Quaternion.h"
+
+namespace MT {
+
+  // Row-major 3x3 matrix
+  
+	template 
+	class Matrix3x3 {
+	public:
+		Matrix3x3() {}
+		
+		template 
+		explicit Matrix3x3(const Scalar2 *m) { setValue(m); }
+		
+		explicit Matrix3x3(const Quaternion& q) { setRotation(q); }
+		
+		template 
+		Matrix3x3(const Scalar2& yaw, const Scalar2& pitch, const Scalar2& roll)
+		{ 
+			setEuler(yaw, pitch, roll);
+		}
+		
+		template 
+		Matrix3x3(const Scalar2& xx, const Scalar2& xy, const Scalar2& xz,
+				  const Scalar2& yx, const Scalar2& yy, const Scalar2& yz,
+				  const Scalar2& zx, const Scalar2& zy, const Scalar2& zz)
+		{ 
+			setValue(xx, xy, xz, 
+					 yx, yy, yz, 
+					 zx, zy, zz);
+		}
+		
+		Vector3&  operator[](int i)
+		{ 
+			assert(0 <= i && i < 3);
+			return m_el[i]; 
+		}
+		
+		const Vector3& operator[](int i) const
+		{
+			assert(0 <= i && i < 3);
+			return m_el[i]; 
+		}
+		
+		Matrix3x3& operator*=(const Matrix3x3& m); 
+		
+		template 
+		void setValue(const Scalar2 *m)
+		{
+			m_el[0][0] = Scalar(m[0]); 
+			m_el[1][0] = Scalar(m[1]); 
+			m_el[2][0] = Scalar(m[2]);
+			m_el[0][1] = Scalar(m[4]); 
+			m_el[1][1] = Scalar(m[5]); 
+			m_el[2][1] = Scalar(m[6]);
+			m_el[0][2] = Scalar(m[8]); 
+			m_el[1][2] = Scalar(m[9]); 
+			m_el[2][2] = Scalar(m[10]);
+		}
+
+		template 
+		void setValue(const Scalar2& xx, const Scalar2& xy, const Scalar2& xz, 
+					  const Scalar2& yx, const Scalar2& yy, const Scalar2& yz, 
+					  const Scalar2& zx, const Scalar2& zy, const Scalar2& zz)
+		{
+			m_el[0][0] = Scalar(xx); 
+			m_el[0][1] = Scalar(xy); 
+			m_el[0][2] = Scalar(xz);
+			m_el[1][0] = Scalar(yx); 
+			m_el[1][1] = Scalar(yy); 
+			m_el[1][2] = Scalar(yz);
+			m_el[2][0] = Scalar(zx); 
+			m_el[2][1] = Scalar(zy); 
+			m_el[2][2] = Scalar(zz);
+		}
+  
+		void setRotation(const Quaternion& q) 
+		{
+			Scalar d = q.length2();
+			assert(d != Scalar(0.0));
+			Scalar s = Scalar(2.0) / d;
+			Scalar xs = q[0] * s,   ys = q[1] * s,   zs = q[2] * s;
+			Scalar wx = q[3] * xs,  wy = q[3] * ys,  wz = q[3] * zs;
+			Scalar xx = q[0] * xs,  xy = q[0] * ys,  xz = q[0] * zs;
+			Scalar yy = q[1] * ys,  yz = q[1] * zs,  zz = q[2] * zs;
+			setValue(Scalar(1.0) - (yy + zz), xy - wz, xz + wy,
+					 xy + wz, Scalar(1.0) - (xx + zz), yz - wx,
+					 xz - wy, yz + wx, Scalar(1.0) - (xx + yy));
+		}
+		
+		template  
+		void setEuler(const Scalar2& yaw, const Scalar2& pitch, const Scalar2& roll) 
+		{
+			Scalar cy(Scalar_traits::cos(yaw)); 
+			Scalar sy(Scalar_traits::sin(yaw)); 
+			Scalar cp(Scalar_traits::cos(pitch)); 
+			Scalar sp(Scalar_traits::sin(pitch)); 
+			Scalar cr(Scalar_traits::cos(roll));
+			Scalar sr(Scalar_traits::sin(roll));
+			Scalar cc = cy * cr; 
+			Scalar cs = cy * sr; 
+			Scalar sc = sy * cr; 
+			Scalar ss = sy * sr;
+			setValue(cy * cp, -sc + sp * cs,  ss - sp * cc,
+					 sy * cp,  cc + sp * ss, -cs + sp * sc,
+					     -sp,       cp * sr,       cp * cr);
+		}
+		void setIdentity()
+		{ 
+			setValue(Scalar(1.0), Scalar(0.0), Scalar(0.0), 
+					 Scalar(0.0), Scalar(1.0), Scalar(0.0), 
+					 Scalar(0.0), Scalar(0.0), Scalar(1.0)); 
+		}
+    
+		template 
+		void getValue(Scalar2 *m) const 
+		{
+			m[0]  = Scalar2(m_el[0][0]); 
+			m[1]  = Scalar2(m_el[1][0]);
+			m[2]  = Scalar2(m_el[2][0]);
+			m[3]  = Scalar2(0.0); 
+			m[4]  = Scalar2(m_el[0][1]);
+			m[5]  = Scalar2(m_el[1][1]);
+			m[6]  = Scalar2(m_el[2][1]);
+			m[7]  = Scalar2(0.0); 
+			m[8]  = Scalar2(m_el[0][2]); 
+			m[9]  = Scalar2(m_el[1][2]);
+			m[10] = Scalar2(m_el[2][2]);
+			m[11] = Scalar2(0.0); 
+		}
+		
+		void getRotation(Quaternion& q) const
+		{
+			Scalar trace = m_el[0][0] + m_el[1][1] + m_el[2][2];
+			
+			if (trace > Scalar(0.0)) 
+			{
+				Scalar s = Scalar_traits::sqrt(trace + Scalar(1.0));
+				q[3] = s * Scalar(0.5);
+				s = Scalar(0.5) / s;
+				
+				q[0] = (m_el[2][1] - m_el[1][2]) * s;
+				q[1] = (m_el[0][2] - m_el[2][0]) * s;
+				q[2] = (m_el[1][0] - m_el[0][1]) * s;
+			} 
+			else 
+			{
+				int i = m_el[0][0] < m_el[1][1] ? 
+					(m_el[1][1] < m_el[2][2] ? 2 : 1) :
+					(m_el[0][0] < m_el[2][2] ? 2 : 0); 
+				int j = (i + 1) % 3;  
+				int k = (i + 2) % 3;
+				
+				Scalar s = Scalar_traits::sqrt(m_el[i][i] - m_el[j][j] - m_el[k][k] + Scalar(1.0));
+				q[i] = s * Scalar(0.5);
+				s = Scalar(0.5) / s;
+				
+				q[3] = (m_el[k][j] - m_el[j][k]) * s;
+				q[j] = (m_el[j][i] + m_el[i][j]) * s;
+				q[k] = (m_el[k][i] + m_el[i][k]) * s;
+			}
+		}
+
+
+		
+		template 
+		void getEuler(Scalar2& yaw, Scalar2& pitch, Scalar2& roll) const
+		{
+			pitch = Scalar2(Scalar_traits::asin(-m_el[2][0]));
+			if (pitch < Scalar_traits::TwoTimesPi())
+			{
+				if (pitch > Scalar_traits::TwoTimesPi())
+				{
+					yaw = Scalar2(Scalar_traits::atan2(m_el[1][0], m_el[0][0]));
+					roll = Scalar2(Scalar_traits::atan2(m_el[2][1], m_el[2][2]));
+				}
+				else 
+				{
+					yaw = Scalar2(-Scalar_traits::atan2(-m_el[0][1], m_el[0][2]));
+					roll = Scalar2(0.0);
+				}
+			}
+			else
+			{
+				yaw = Scalar2(Scalar_traits::atan2(-m_el[0][1], m_el[0][2]));
+				roll = Scalar2(0.0);
+			}
+		}
+
+		Vector3 getScaling() const
+		{
+			return Vector3(m_el[0][0] * m_el[0][0] + m_el[1][0] * m_el[1][0] + m_el[2][0] * m_el[2][0],
+								   m_el[0][1] * m_el[0][1] + m_el[1][1] * m_el[1][1] + m_el[2][1] * m_el[2][1],
+								   m_el[0][2] * m_el[0][2] + m_el[1][2] * m_el[1][2] + m_el[2][2] * m_el[2][2]);
+		}
+		
+		
+		Matrix3x3 scaled(const Vector3& s) const
+		{
+			return Matrix3x3(m_el[0][0] * s[0], m_el[0][1] * s[1], m_el[0][2] * s[2],
+									 m_el[1][0] * s[0], m_el[1][1] * s[1], m_el[1][2] * s[2],
+									 m_el[2][0] * s[0], m_el[2][1] * s[1], m_el[2][2] * s[2]);
+		}
+
+		Scalar            determinant() const;
+		Matrix3x3 adjoint() const;
+		Matrix3x3 absolute() const;
+		Matrix3x3 transpose() const;
+		Matrix3x3 inverse() const; 
+		
+		Matrix3x3 transposeTimes(const Matrix3x3& m) const;
+		Matrix3x3 timesTranspose(const Matrix3x3& m) const;
+		
+		Scalar tdot(int c, const Vector3& v) const 
+		{
+			return m_el[0][c] * v[0] + m_el[1][c] * v[1] + m_el[2][c] * v[2];
+		}
+		
+	protected:
+		Scalar cofac(int r1, int c1, int r2, int c2) const 
+		{
+			return m_el[r1][c1] * m_el[r2][c2] - m_el[r1][c2] * m_el[r2][c1];
+		}
+
+		Vector3 m_el[3];
+	};
+	
+	template 
+	inline std::ostream& 
+	operator<<(std::ostream& os, const Matrix3x3& m)
+	{
+		return os << m[0] << std::endl << m[1] << std::endl << m[2] << std::endl;
+	}
+	
+	template 
+	inline Matrix3x3& 
+	Matrix3x3::operator*=(const Matrix3x3& m)
+	{
+		setValue(m.tdot(0, m_el[0]), m.tdot(1, m_el[0]), m.tdot(2, m_el[0]),
+				 m.tdot(0, m_el[1]), m.tdot(1, m_el[1]), m.tdot(2, m_el[1]),
+				 m.tdot(0, m_el[2]), m.tdot(1, m_el[2]), m.tdot(2, m_el[2]));
+		return *this;
+	}
+	
+	template 
+	inline Scalar 
+	Matrix3x3::determinant() const
+	{ 
+		return triple((*this)[0], (*this)[1], (*this)[2]);
+	}
+	
+
+	template 
+	inline Matrix3x3 
+	Matrix3x3::absolute() const
+	{
+		return Matrix3x3(
+			Scalar_traits::abs(m_el[0][0]), Scalar_traits::abs(m_el[0][1]), Scalar_traits::abs(m_el[0][2]),
+			Scalar_traits::abs(m_el[1][0]), Scalar_traits::abs(m_el[1][1]), Scalar_traits::abs(m_el[1][2]),
+			Scalar_traits::abs(m_el[2][0]), Scalar_traits::abs(m_el[2][1]), Scalar_traits::abs(m_el[2][2]));
+	}
+
+	template 
+	inline Matrix3x3 
+	Matrix3x3::transpose() const 
+	{
+		return Matrix3x3(m_el[0][0], m_el[1][0], m_el[2][0],
+								 m_el[0][1], m_el[1][1], m_el[2][1],
+								 m_el[0][2], m_el[1][2], m_el[2][2]);
+	}
+	
+	template 
+	inline Matrix3x3 
+	Matrix3x3::adjoint() const 
+	{
+		return Matrix3x3(cofac(1, 1, 2, 2), cofac(0, 2, 2, 1), cofac(0, 1, 1, 2),
+								 cofac(1, 2, 2, 0), cofac(0, 0, 2, 2), cofac(0, 2, 1, 0),
+								 cofac(1, 0, 2, 1), cofac(0, 1, 2, 0), cofac(0, 0, 1, 1));
+	}
+	
+	template 
+	inline Matrix3x3 
+	Matrix3x3::inverse() const
+	{
+		Vector3 co(cofac(1, 1, 2, 2), cofac(1, 2, 2, 0), cofac(1, 0, 2, 1));
+		Scalar det = (*this)[0].dot(co);
+		assert(det != Scalar(0.0));
+		Scalar s = Scalar(1.0) / det;
+		return Matrix3x3(co[0] * s, cofac(0, 2, 2, 1) * s, cofac(0, 1, 1, 2) * s,
+								 co[1] * s, cofac(0, 0, 2, 2) * s, cofac(0, 2, 1, 0) * s,
+								 co[2] * s, cofac(0, 1, 2, 0) * s, cofac(0, 0, 1, 1) * s);
+	}
+	
+	template 
+	inline Matrix3x3 
+	Matrix3x3::transposeTimes(const Matrix3x3& m) const
+	{
+		return Matrix3x3(
+			m_el[0][0] * m[0][0] + m_el[1][0] * m[1][0] + m_el[2][0] * m[2][0],
+			m_el[0][0] * m[0][1] + m_el[1][0] * m[1][1] + m_el[2][0] * m[2][1],
+			m_el[0][0] * m[0][2] + m_el[1][0] * m[1][2] + m_el[2][0] * m[2][2],
+			m_el[0][1] * m[0][0] + m_el[1][1] * m[1][0] + m_el[2][1] * m[2][0],
+			m_el[0][1] * m[0][1] + m_el[1][1] * m[1][1] + m_el[2][1] * m[2][1],
+			m_el[0][1] * m[0][2] + m_el[1][1] * m[1][2] + m_el[2][1] * m[2][2],
+			m_el[0][2] * m[0][0] + m_el[1][2] * m[1][0] + m_el[2][2] * m[2][0],
+			m_el[0][2] * m[0][1] + m_el[1][2] * m[1][1] + m_el[2][2] * m[2][1],
+			m_el[0][2] * m[0][2] + m_el[1][2] * m[1][2] + m_el[2][2] * m[2][2]);
+	}
+	
+	template 
+	inline Matrix3x3 
+	Matrix3x3::timesTranspose(const Matrix3x3& m) const
+	{
+		return Matrix3x3(
+			m_el[0].dot(m[0]), m_el[0].dot(m[1]), m_el[0].dot(m[2]),
+			m_el[1].dot(m[0]), m_el[1].dot(m[1]), m_el[1].dot(m[2]),
+			m_el[2].dot(m[0]), m_el[2].dot(m[1]), m_el[2].dot(m[2]));
+		
+	}
+
+	template 
+	inline Vector3 
+	operator*(const Matrix3x3& m, const Vector3& v) 
+	{
+		return Vector3(m[0].dot(v), m[1].dot(v), m[2].dot(v));
+	}
+	
+
+	template 
+	inline Vector3
+	operator*(const Vector3& v, const Matrix3x3& m)
+	{
+		return Vector3(m.tdot(0, v), m.tdot(1, v), m.tdot(2, v));
+	}
+
+	template 
+	inline Matrix3x3 
+	operator*(const Matrix3x3& m1, const Matrix3x3& m2)
+	{
+		return Matrix3x3(
+			m2.tdot(0, m1[0]), m2.tdot(1, m1[0]), m2.tdot(2, m1[0]),
+			m2.tdot(0, m1[1]), m2.tdot(1, m1[1]), m2.tdot(2, m1[1]),
+			m2.tdot(0, m1[2]), m2.tdot(1, m1[2]), m2.tdot(2, m1[2]));
+	}
+}
+
+#endif
diff --git a/extern/solid/include/MT/Quaternion.h b/extern/solid/include/MT/Quaternion.h
new file mode 100644
index 00000000000..a925f21cd5d
--- /dev/null
+++ b/extern/solid/include/MT/Quaternion.h
@@ -0,0 +1,316 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef QUATERNION_H
+#define QUATERNION_H
+
+#if defined (__sgi)
+#include 
+#else
+#include 
+#endif
+
+#include "Tuple4.h"
+#include "Vector3.h"
+
+namespace MT {
+
+	template 	
+	class Quaternion : public Tuple4 {
+	public:
+		Quaternion() {}
+		
+		template 
+		explicit Quaternion(const Scalar2 *v) : Tuple4(v) {}
+		
+		template 
+		Quaternion(const Scalar2& x, const Scalar2& y, const Scalar2& z, const Scalar2& w) 
+			: Tuple4(x, y, z, w) 
+		{}
+		
+		Quaternion(const Vector3& axis, const Scalar& angle) 
+		{ 
+			setRotation(axis, angle); 
+		}
+
+		template 
+		Quaternion(const Scalar2& yaw, const Scalar2& pitch, const Scalar2& roll)
+		{ 
+			setEuler(yaw, pitch, roll); 
+		}
+
+		void setRotation(const Vector3& axis, const Scalar& angle)
+		{
+			Scalar d = axis.length();
+			assert(d != Scalar(0.0));
+			Scalar s = Scalar_traits::sin(angle * Scalar(0.5)) / d;
+			setValue(axis[0] * s, axis[1] * s, axis[2] * s, 
+					 Scalar_traits::cos(angle * Scalar(0.5)));
+		}
+
+		template 
+		void setEuler(const Scalar2& yaw, const Scalar2& pitch, const Scalar2& roll)
+		{
+			Scalar halfYaw = Scalar(yaw) * Scalar(0.5);  
+			Scalar halfPitch = Scalar(pitch) * Scalar(0.5);  
+			Scalar halfRoll = Scalar(roll) * Scalar(0.5);  
+			Scalar cosYaw = Scalar_traits::cos(halfYaw);
+			Scalar sinYaw = Scalar_traits::sin(halfYaw);
+			Scalar cosPitch = Scalar_traits::cos(halfPitch);
+			Scalar sinPitch = Scalar_traits::sin(halfPitch);
+			Scalar cosRoll = Scalar_traits::cos(halfRoll);
+			Scalar sinRoll = Scalar_traits::sin(halfRoll);
+			setValue(cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw,
+					 cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw,
+					 sinRoll * cosPitch * cosYaw - cosRoll * sinPitch * sinYaw,
+					 cosRoll * cosPitch * cosYaw + sinRoll * sinPitch * sinYaw);
+		}
+  
+		Quaternion& operator+=(const Quaternion& q)
+		{
+			this->m_co[0] += q[0]; this->m_co[1] += q[1]; this->m_co[2] += q[2]; this->m_co[3] += q[3];
+			return *this;
+		}
+		
+		Quaternion& operator-=(const Quaternion& q) 
+		{
+			this->m_co[0] -= q[0]; this->m_co[1] -= q[1]; this->m_co[2] -= q[2]; this->m_co[3] -= q[3];
+			return *this;
+		}
+
+		Quaternion& operator*=(const Scalar& s)
+		{
+			this->m_co[0] *= s; this->m_co[1] *= s; this->m_co[2] *= s; this->m_co[3] *= s;
+			return *this;
+		}
+		
+		Quaternion& operator/=(const Scalar& s) 
+		{
+			assert(s != Scalar(0.0));
+			return *this *= Scalar(1.0) / s;
+		}
+  
+		Quaternion& operator*=(const Quaternion& q)
+		{
+			setValue(this->m_co[3] * q[0] + this->m_co[0] * q[3] + this->m_co[1] * q[2] - this->m_co[2] * q[1],
+					 this->m_co[3] * q[1] + this->m_co[1] * q[3] + this->m_co[2] * q[0] - this->m_co[0] * q[2],
+					 this->m_co[3] * q[2] + this->m_co[2] * q[3] + this->m_co[0] * q[1] - this->m_co[1] * q[0],
+					 this->m_co[3] * q[3] - this->m_co[0] * q[0] - this->m_co[1] * q[1] - this->m_co[2] * q[2]);
+			return *this;
+		}
+	
+		Scalar dot(const Quaternion& q) const
+		{
+			return this->m_co[0] * q[0] + this->m_co[1] * q[1] + this->m_co[2] * q[2] + this->m_co[3] * q[3];
+		}
+
+		Scalar length2() const
+		{
+			return dot(*this);
+		}
+
+		Scalar length() const
+		{
+			return Scalar_traits::sqrt(length2());
+		}
+
+		Quaternion& normalize() 
+		{
+			return *this /= length();
+		}
+		
+		Quaternion normalized() const 
+		{
+			return *this / length();
+		} 
+
+		Scalar angle(const Quaternion& q) const 
+		{
+			Scalar s = Scalar_traits::sqrt(length2() * q.length2());
+			assert(s != Scalar(0.0));
+			return Scalar_traits::acos(dot(q) / s);
+		}
+   
+		Quaternion conjugate() const 
+		{
+			return Quaternion(-this->m_co[0], -this->m_co[1], -this->m_co[2], this->m_co[3]);
+		}
+
+		Quaternion inverse() const
+		{
+			return conjugate / length2();
+		}
+		
+		Quaternion slerp(const Quaternion& q, const Scalar& t) const
+		{
+			Scalar theta = angle(q);
+			if (theta != Scalar(0.0))
+			{
+				Scalar d = Scalar(1.0) / Scalar_traits::sin(theta);
+				Scalar s0 = Scalar_traits::sin((Scalar(1.0) - t) * theta);
+				Scalar s1 = Scalar_traits::sin(t * theta);   
+				return Quaternion((this->m_co[0] * s0 + q[0] * s1) * d,
+										  (this->m_co[1] * s0 + q[1] * s1) * d,
+										  (this->m_co[2] * s0 + q[2] * s1) * d,
+										  (this->m_co[3] * s0 + q[3] * s1) * d);
+			}
+			else
+			{
+				return *this;
+			}
+		}
+
+		static Quaternion random() 
+		{
+			// From: "Uniform Random Rotations", Ken Shoemake, Graphics Gems III, 
+            //       pg. 124-132
+			Scalar x0 = Scalar_traits::random();
+			Scalar r1 = Scalar_traits::sqrt(Scalar(1.0) - x0);
+			Scalar r2 = Scalar_traits::sqrt(x0);
+			Scalar t1 = Scalar_traits::TwoTimesPi() * Scalar_traits::random();
+			Scalar t2 = Scalar_traits::TwoTimesPi() * Scalar_traits::random();
+			Scalar c1 = Scalar_traits::cos(t1);
+			Scalar s1 = Scalar_traits::sin(t1);
+			Scalar c2 = Scalar_traits::cos(t2);
+			Scalar s2 = Scalar_traits::sin(t2);
+			return Quaternion(s1 * r1, c1 * r1, s2 * r2, c2 * r2);
+		}
+
+	};
+
+	template 
+	inline Quaternion
+	operator+(const Quaternion& q1, const Quaternion& q2)
+	{
+		return Quaternion(q1[0] + q2[0], q1[1] + q2[1], q1[2] + q2[2], q1[3] + q2[3]);
+	}
+	
+	template 
+	inline Quaternion
+	operator-(const Quaternion& q1, const Quaternion& q2)
+	{
+		return Quaternion(q1[0] - q2[0], q1[1] - q2[1], q1[2] - q2[2], q1[3] - q2[3]);
+	}
+	
+	template 
+	inline Quaternion
+	operator-(const Quaternion& q)
+	{
+		return Quaternion(-q[0], -q[1], -q[2], -q[3]);
+	}
+
+	template 
+	inline Quaternion
+	operator*(const Quaternion& q, const Scalar& s)
+	{
+		return Quaternion(q[0] * s, q[1] * s, q[2] * s, q[3] * s);
+	}
+	
+	template 
+	inline Quaternion
+	operator*(const Scalar& s, const Quaternion& q)
+	{
+		return q * s;
+	}
+	
+	template 
+	inline Quaternion
+	operator*(const Quaternion& q1, const Quaternion& q2) {
+		return Quaternion(q1[3] * q2[0] + q1[0] * q2[3] + q1[1] * q2[2] - q1[2] * q2[1],
+								  q1[3] * q2[1] + q1[1] * q2[3] + q1[2] * q2[0] - q1[0] * q2[2],
+								  q1[3] * q2[2] + q1[2] * q2[3] + q1[0] * q2[1] - q1[1] * q2[0],
+								  q1[3] * q2[3] - q1[0] * q2[0] - q1[1] * q2[1] - q1[2] * q2[2]); 
+	}
+	
+	template 
+	inline Quaternion
+	operator*(const Quaternion& q, const Vector3& w)
+	{
+		return Quaternion( q[3] * w[0] + q[1] * w[2] - q[2] * w[1],
+								   q[3] * w[1] + q[2] * w[0] - q[0] * w[2],
+								   q[3] * w[2] + q[0] * w[1] - q[1] * w[0],
+								  -q[0] * w[0] - q[1] * w[1] - q[2] * w[2]); 
+	}
+	
+	template 
+	inline Quaternion
+	operator*(const Vector3& w, const Quaternion& q)
+	{
+		return Quaternion( w[0] * q[3] + w[1] * q[2] - w[2] * q[1],
+								   w[1] * q[3] + w[2] * q[0] - w[0] * q[2],
+								   w[2] * q[3] + w[0] * q[1] - w[1] * q[0],
+								  -w[0] * q[0] - w[1] * q[1] - w[2] * q[2]); 
+	}
+	
+	template 
+	inline Scalar 
+	dot(const Quaternion& q1, const Quaternion& q2) 
+	{ 
+		return q1.dot(q2); 
+	}
+
+	template 
+	inline Scalar
+	length2(const Quaternion& q) 
+	{ 
+		return q.length2(); 
+	}
+
+	template 
+	inline Scalar
+	length(const Quaternion& q) 
+	{ 
+		return q.length(); 
+	}
+
+	template 
+	inline Scalar
+	angle(const Quaternion& q1, const Quaternion& q2) 
+	{ 
+		return q1.angle(q2); 
+	}
+
+	template 
+	inline Quaternion
+	conjugate(const Quaternion& q) 
+	{
+		return q.conjugate();
+	}
+
+	template 
+	inline Quaternion
+	inverse(const Quaternion& q) 
+	{
+		return q.inverse();
+	}
+
+	template 
+	inline Quaternion
+	slerp(const Quaternion& q1, const Quaternion& q2, const Scalar& t) 
+	{
+		return q1.slerp(q2, t);
+	}
+	
+}
+
+#endif
diff --git a/extern/solid/include/MT/Transform.h b/extern/solid/include/MT/Transform.h
new file mode 100644
index 00000000000..b80dc1bc18b
--- /dev/null
+++ b/extern/solid/include/MT/Transform.h
@@ -0,0 +1,189 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef TRANSFORM_H
+#define TRANSFORM_H
+
+#include "Vector3.h"
+#include "Matrix3x3.h"
+
+namespace MT {
+
+	template 
+	class Transform {
+		enum { 
+			TRANSLATION = 0x01,
+			ROTATION    = 0x02,
+			RIGID       = TRANSLATION | ROTATION,  
+			SCALING     = 0x04,
+			LINEAR      = ROTATION | SCALING,
+			AFFINE      = TRANSLATION | LINEAR
+		};
+    
+	public:
+		Transform() {}
+		
+		template 
+		explicit Transform(const Scalar2 *m) { setValue(m); }
+
+		explicit Transform(const Quaternion& q, 
+						   const Vector3& c = Vector3(Scalar(0), Scalar(0), Scalar(0))) 
+			: m_basis(q),
+			  m_origin(c),
+			  m_type(RIGID)
+		{}
+
+		explicit Transform(const Matrix3x3& b, 
+						   const Vector3& c = Vector3(Scalar(0), Scalar(0), Scalar(0)), 
+						   unsigned int type = AFFINE)
+			: m_basis(b),
+			  m_origin(c),
+			  m_type(type)
+		{}
+
+		Vector3 operator()(const Vector3& x) const
+		{
+			return Vector3(m_basis[0].dot(x) + m_origin[0], 
+								   m_basis[1].dot(x) + m_origin[1], 
+								   m_basis[2].dot(x) + m_origin[2]);
+		}
+    
+		Vector3 operator*(const Vector3& x) const
+		{
+			return (*this)(x);
+		}
+
+		Matrix3x3&       getBasis()          { return m_basis; }
+		const Matrix3x3& getBasis()    const { return m_basis; }
+
+		Vector3&         getOrigin()         { return m_origin; }
+		const Vector3&   getOrigin()   const { return m_origin; }
+
+		Quaternion getRotation() const { return m_basis.getRotation(); }
+		template 
+		void setValue(const Scalar2 *m) 
+		{
+			m_basis.setValue(m);
+			m_origin.setValue(&m[12]);
+			m_type = AFFINE;
+		}
+
+		template 
+		void getValue(Scalar2 *m) const 
+		{
+			m_basis.getValue(m);
+			m_origin.getValue(&m[12]);
+			m[15] = Scalar2(1.0);
+		}
+
+		void setOrigin(const Vector3& origin) 
+		{ 
+			m_origin = origin;
+			m_type |= TRANSLATION;
+		}
+
+		void setBasis(const Matrix3x3& basis)
+		{ 
+			m_basis = basis;
+			m_type |= LINEAR;
+		}
+
+		void setRotation(const Quaternion& q)
+		{
+			m_basis.setRotation(q);
+			m_type = (m_type & ~LINEAR) | ROTATION;
+		}
+
+    	void scale(const Vector3& scaling)
+		{
+			m_basis = m_basis.scaled(scaling);
+			m_type |= SCALING;
+		}
+    
+		void setIdentity()
+		{
+			m_basis.setIdentity();
+			m_origin.setValue(Scalar(0.0), Scalar(0.0), Scalar(0.0));
+			m_type = 0x0;
+		}
+		
+		bool isIdentity() const { return m_type == 0x0; }
+    
+		Transform& operator*=(const Transform& t) 
+		{
+			m_origin += m_basis * t.m_origin;
+			m_basis *= t.m_basis;
+			m_type |= t.m_type; 
+			return *this;
+		}
+
+		Transform inverse() const
+		{ 
+			Matrix3x3 inv = (m_type & SCALING) ? 
+				                    m_basis.inverse() : 
+				                    m_basis.transpose();
+			
+			return Transform(inv, inv * -m_origin, m_type);
+		}
+
+		Transform inverseTimes(const Transform& t) const;  
+
+		Transform operator*(const Transform& t) const;
+
+	private:
+		
+		Matrix3x3 m_basis;
+		Vector3   m_origin;
+		unsigned int      m_type;
+	};
+
+
+	template 
+	inline Transform 
+	Transform::inverseTimes(const Transform& t) const  
+	{
+		Vector3 v = t.getOrigin() - m_origin;
+		if (m_type & SCALING) 
+		{
+			Matrix3x3 inv = m_basis.inverse();
+			return Transform(inv * t.getBasis(), inv * v, 
+									 m_type | t.m_type);
+		}
+		else 
+		{
+			return Transform(m_basis.transposeTimes(t.m_basis),
+									 v * m_basis, m_type | t.m_type);
+		}
+	}
+
+	template 
+	inline Transform 
+	Transform::operator*(const Transform& t) const
+	{
+		return Transform(m_basis * t.m_basis, 
+								 (*this)(t.m_origin), 
+								 m_type | t.m_type);
+	}	
+}
+
+#endif
diff --git a/extern/solid/include/MT/Tuple3.h b/extern/solid/include/MT/Tuple3.h
new file mode 100644
index 00000000000..52ea33b7f58
--- /dev/null
+++ b/extern/solid/include/MT/Tuple3.h
@@ -0,0 +1,120 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef TUPLE3_H
+#define TUPLE3_H
+
+#if defined (__sgi)
+#include 
+#else
+#include 
+#endif
+
+#include 
+
+namespace MT {
+
+	template 
+	class Tuple3 {
+	public:
+		Tuple3() {}
+		
+		template 
+		explicit Tuple3(const Scalar2 *v) 
+		{ 
+			setValue(v);
+		}
+		
+		template 
+		Tuple3(const Scalar2& x, const Scalar2& y, const Scalar2& z) 
+		{ 
+			setValue(x, y, z); 
+		}
+		
+		template 
+		Tuple3(const Tuple3& t) 
+		{ 
+			*this = t; 
+		}
+		
+		template 
+		Tuple3& operator=(const Tuple3& t) 
+		{ 
+			m_co[0] = Scalar(t[0]); 
+			m_co[1] = Scalar(t[1]); 
+			m_co[2] = Scalar(t[2]);
+			return *this;
+		}
+		
+		operator       Scalar *()       { return m_co; }
+		operator const Scalar *() const { return m_co; }
+
+		Scalar&       operator[](int i)       { return m_co[i];	}      
+		const Scalar& operator[](int i) const { return m_co[i]; }
+
+		Scalar&       x()       { return m_co[0]; }
+		const Scalar& x() const { return m_co[0]; }
+		
+		Scalar&       y()       { return m_co[1]; }
+		const Scalar& y() const { return m_co[1]; }
+		
+		Scalar&       z()       { return m_co[2]; }
+		const Scalar& z() const { return m_co[2]; }
+
+		template 
+		void setValue(const Scalar2 *v) 
+		{
+			m_co[0] = Scalar(v[0]); 
+			m_co[1] = Scalar(v[1]); 
+			m_co[2] = Scalar(v[2]);
+		}
+
+		template 
+		void setValue(const Scalar2& x, const Scalar2& y, const Scalar2& z)
+		{
+			m_co[0] = Scalar(x); 
+			m_co[1] = Scalar(y); 
+			m_co[2] = Scalar(z);
+		}
+
+		template 
+		void getValue(Scalar2 *v) const 
+		{
+			v[0] = Scalar2(m_co[0]);
+			v[1] = Scalar2(m_co[1]);
+			v[2] = Scalar2(m_co[2]);
+		}
+    
+	protected:
+		Scalar m_co[3];                            
+	};
+
+	template 
+	inline std::ostream& 
+	operator<<(std::ostream& os, const Tuple3& t)
+	{
+		return os << t[0] << ' ' << t[1] << ' ' << t[2];
+	}
+}
+
+#endif
diff --git a/extern/solid/include/MT/Tuple4.h b/extern/solid/include/MT/Tuple4.h
new file mode 100644
index 00000000000..6930541271e
--- /dev/null
+++ b/extern/solid/include/MT/Tuple4.h
@@ -0,0 +1,112 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef TUPLE4_H
+#define TUPLE4_H
+
+#if defined (__sgi)
+#include 
+#else
+#include 
+#endif
+
+#include 
+
+namespace MT {
+
+	template 
+	class Tuple4 {
+	public:
+		Tuple4() {}
+		
+		template 
+		explicit Tuple4(const Scalar2 *v) 
+		{ 
+			setValue(v);
+		}
+		
+		template 
+		Tuple4(const Scalar2& x, const Scalar2& y, const Scalar2& z, const Scalar2& w) 
+		{ 
+			setValue(x, y, z, w); 
+		}
+		
+		operator       Scalar *()       { return m_co; }
+		operator const Scalar *() const { return m_co; }
+
+		Scalar&       operator[](int i)       { return m_co[i]; }      
+		const Scalar& operator[](int i) const {	return m_co[i];	}
+		
+		Scalar&       x()       { return m_co[0]; }
+		const Scalar& x() const { return m_co[0]; }
+		
+		Scalar&       y()       { return m_co[1]; }
+		const Scalar& y() const { return m_co[1]; }
+		
+		Scalar&       z()       { return m_co[2]; }
+		const Scalar& z() const { return m_co[2]; }
+
+		Scalar&       w()       { return m_co[3]; }
+		const Scalar& w() const { return m_co[3]; }
+    
+		template 
+		void setValue(const Scalar2 *v) 
+		{
+			m_co[0] = Scalar(v[0]); 
+			m_co[1] = Scalar(v[1]); 
+			m_co[2] = Scalar(v[2]);
+			m_co[3] = Scalar(v[3]);
+		}
+
+		template 
+		void setValue(const Scalar2& x, const Scalar2& y, const Scalar2& z, const Scalar2& w)
+		{
+			m_co[0] = Scalar(x); 
+			m_co[1] = Scalar(y); 
+			m_co[2] = Scalar(z);
+			m_co[3] = Scalar(w);
+		}
+
+		template 
+		void getValue(Scalar2 *v) const 
+		{
+			v[0] = Scalar2(m_co[0]);
+			v[1] = Scalar2(m_co[1]);
+			v[2] = Scalar2(m_co[2]);
+			v[3] = Scalar2(m_co[3]);
+		}
+
+	protected:
+		Scalar m_co[4];
+	};
+
+	template 
+	inline std::ostream&
+	operator<<(std::ostream& os, const Tuple4& t)
+	{
+		return os << t[0] << ' ' << t[1] << ' ' << t[2] << ' ' << t[3];
+	}
+
+}
+
+#endif
diff --git a/extern/solid/include/MT/Vector3.h b/extern/solid/include/MT/Vector3.h
new file mode 100644
index 00000000000..b569c003f59
--- /dev/null
+++ b/extern/solid/include/MT/Vector3.h
@@ -0,0 +1,283 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef VECTOR3_H
+#define VECTOR3_H
+
+#if defined (__sgi)
+#include 
+#else
+#include 
+#endif
+
+#include "Tuple3.h"
+
+namespace MT {
+
+	template 	
+	class Vector3 : public Tuple3 {
+	public:
+		Vector3() {}
+	
+		template 
+		explicit Vector3(const Scalar2 *v) : Tuple3(v) {}
+		
+		template 
+		Vector3(const Scalar2& x, const Scalar2& y, const Scalar2& z) 
+			: Tuple3(x, y, z) 
+		{}
+		
+		Vector3& operator+=(const Vector3& v)
+		{
+			this->m_co[0] += v[0]; this->m_co[1] += v[1]; this->m_co[2] += v[2];
+			return *this;
+		}
+		
+		Vector3& operator-=(const Vector3& v) 
+		{
+			this->m_co[0] -= v[0]; this->m_co[1] -= v[1]; this->m_co[2] -= v[2];
+			return *this;
+		}
+
+		Vector3& operator*=(const Scalar& s)
+		{
+			this->m_co[0] *= s; this->m_co[1] *= s; this->m_co[2] *= s;
+			return *this;
+		}
+		
+		Vector3& operator/=(const Scalar& s) 
+		{
+			assert(s != Scalar(0.0));
+			return *this *= Scalar(1.0) / s;
+		}
+  
+		Scalar dot(const Vector3& v) const
+		{
+			return this->m_co[0] * v[0] + this->m_co[1] * v[1] + this->m_co[2] * v[2];
+		}
+
+		Scalar length2() const
+		{
+			return dot(*this);
+		}
+
+		Scalar length() const
+		{
+			return Scalar_traits::sqrt(length2());
+		}
+
+		Scalar distance2(const Vector3& v) const 
+		{
+			return (v - *this).length2();
+		}
+
+		Scalar distance(const Vector3& v) const 
+		{
+			return (v - *this).length();
+		}
+		
+		Vector3& normalize() 
+		{
+			return *this /= length();
+		}
+		
+		Vector3 normalized() const 
+		{
+			return *this / length();
+		} 
+
+		Scalar angle(const Vector3& v) const 
+		{
+			Scalar s = Scalar_traits::sqrt(length2() * v.length2());
+			assert(s != Scalar(0.0));
+			return Scalar_traits::acos(dot(v) / s);
+		}
+   
+		Vector3 absolute() const 
+		{
+			return Vector3(Scalar_traits::abs(this->m_co[0]), 
+								   Scalar_traits::abs(this->m_co[1]), 
+								   Scalar_traits::abs(this->m_co[2]));
+		}
+
+		Vector3 cross(const Vector3& v) const
+		{
+			return Vector3(this->m_co[1] * v[2] - this->m_co[2] * v[1],
+								   this->m_co[2] * v[0] - this->m_co[0] * v[2],
+								   this->m_co[0] * v[1] - this->m_co[1] * v[0]);
+		}
+		
+		Scalar triple(const Vector3& v1, const Vector3& v2) const
+		{
+			return this->m_co[0] * (v1[1] * v2[2] - v1[2] * v2[1]) + 
+				   this->m_co[1] * (v1[2] * v2[0] - v1[0] * v2[2]) + 
+				   this->m_co[2] * (v1[0] * v2[1] - v1[1] * v2[0]);
+		}
+
+		int minAxis() const
+		{
+			return this->m_co[0] < this->m_co[1] ? (this->m_co[0] < this->m_co[2] ? 0 : 2) : (this->m_co[1] < this->m_co[2] ? 1 : 2);
+		}
+
+		int maxAxis() const 
+		{
+			return this->m_co[0] < this->m_co[1] ? (this->m_co[1] < this->m_co[2] ? 2 : 1) : (this->m_co[0] < this->m_co[2] ? 2 : 0);
+		}
+
+		int furthestAxis() const
+		{
+			return absolute().minAxis();
+		}
+
+		int closestAxis() const 
+		{
+			return absolute().maxAxis();
+		}
+
+		Vector3 lerp(const Vector3& v, const Scalar& t) const 
+		{
+			return Vector3(this->m_co[0] + (v[0] - this->m_co[0]) * t,
+								   this->m_co[1] + (v[1] - this->m_co[1]) * t,
+								   this->m_co[2] + (v[2] - this->m_co[2]) * t);
+		}
+    
+		static Vector3 random() 
+		{
+			Scalar z = Scalar(2.0) * Scalar_traits::random() - Scalar(1.0);
+			Scalar r = Scalar_traits::sqrt(Scalar(1.0) - z * z);
+			Scalar t = Scalar_traits::TwoTimesPi() * Scalar_traits::random();
+			return Vector3(r * Scalar_traits::cos(t), 
+								   r * Scalar_traits::sin(t), 
+								   z);
+		}
+	};
+
+	template 
+	inline Vector3 
+	operator+(const Vector3& v1, const Vector3& v2) 
+	{
+		return Vector3(v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2]);
+	}
+
+	template 
+	inline Vector3 
+	operator-(const Vector3& v1, const Vector3& v2)
+	{
+		return Vector3(v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2]);
+	}
+	
+	template 
+	inline Vector3 
+	operator-(const Vector3& v)
+	{
+		return Vector3(-v[0], -v[1], -v[2]);
+	}
+	
+	template 
+	inline Vector3 
+	operator*(const Vector3& v, const Scalar& s)
+	{
+		return Vector3(v[0] * s, v[1] * s, v[2] * s);
+	}
+	
+	template 
+	inline Vector3 
+	operator*(const Scalar& s, const Vector3& v)
+	{ 
+		return v * s; 
+	}
+	
+	template 
+	inline Vector3
+	operator/(const Vector3& v, const Scalar& s)
+	{
+		assert(s != Scalar(0.0));
+		return v * (Scalar(1.0) / s);
+	}
+	
+	template 
+	inline Scalar 
+	dot(const Vector3& v1, const Vector3& v2) 
+	{ 
+		return v1.dot(v2); 
+	}
+	
+	template 
+	inline Scalar
+	length2(const Vector3& v) 
+	{ 
+		return v.length2(); 
+	}
+
+	template 
+	inline Scalar
+	length(const Vector3& v) 
+	{ 
+		return v.length(); 
+	}
+
+	template 
+	inline Scalar
+	distance2(const Vector3& v1, const Vector3& v2) 
+	{ 
+		return v1.distance2(v2); 
+	}
+
+	template 
+	inline Scalar
+	distance(const Vector3& v1, const Vector3& v2) 
+	{ 
+		return v1.distance(v2); 
+	}
+
+	template 
+	inline Scalar
+	angle(const Vector3& v1, const Vector3& v2) 
+	{ 
+		return v1.angle(v2); 
+	}
+
+	template 
+	inline Vector3 
+	cross(const Vector3& v1, const Vector3& v2) 
+	{ 
+		return v1.cross(v2); 
+	}
+
+	template 
+	inline Scalar
+	triple(const Vector3& v1, const Vector3& v2, const Vector3& v3)
+	{
+		return v1.triple(v2, v3);
+	}
+
+	template 
+	inline Vector3 
+	lerp(const Vector3& v1, const Vector3& v2, const Scalar& t)
+	{
+		return v1.lerp(v2, t);
+	}
+
+}
+
+#endif
diff --git a/extern/solid/include/MT_BBox.h b/extern/solid/include/MT_BBox.h
new file mode 100644
index 00000000000..b5dc537e0d9
--- /dev/null
+++ b/extern/solid/include/MT_BBox.h
@@ -0,0 +1,119 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef MT_BBOX_H
+#define MT_BBOX_H
+
+#include "MT_Scalar.h"
+#include "MT_Point3.h"
+#include "MT_Vector3.h"
+
+#include  
+#include "MT_Interval.h" 
+
+
+
+class MT_BBox : public MT::Tuple3 {
+public:
+    MT_BBox() {}
+	MT_BBox(const MT_Point3& p)
+		: MT::Tuple3(MT_Interval(p[0]), 
+				                  MT_Interval(p[1]), 
+				                  MT_Interval(p[2]))
+	{}
+	MT_BBox(const MT_Point3& lb, const MT_Point3& ub)
+		: MT::Tuple3(MT_Interval(lb[0], ub[0]),
+				                  MT_Interval(lb[1], ub[1]),
+				                  MT_Interval(lb[2], ub[2]))
+	{}
+	MT_BBox(const MT_Interval& x, const MT_Interval& y, const MT_Interval& z) 
+		: MT::Tuple3(x, y, z) 
+	{}
+
+	MT_Point3 getMin() const 
+	{ 
+		return MT_Point3(m_co[0].lower(), m_co[1].lower(), m_co[2].lower());
+	}
+
+	MT_Point3 getMax() const 
+	{ 
+		return MT_Point3(m_co[0].upper(), m_co[1].upper(), m_co[2].upper());
+	}
+	
+	MT_Point3 getCenter() const
+	{
+		return MT_Point3(MT::median(m_co[0]), MT::median(m_co[1]), MT::median(m_co[2]));
+	}
+
+	MT_Vector3 getExtent() const
+	{
+		return MT_Vector3(MT::width(m_co[0]) * MT_Scalar(0.5), MT::width(m_co[1]) * MT_Scalar(0.5), MT::width(m_co[2]) * MT_Scalar(0.5));
+	}
+
+	void extend(const MT_Vector3& v) 
+	{
+		m_co[0] = MT::widen(m_co[0], v[0]);
+		m_co[1] = MT::widen(m_co[1], v[1]);
+		m_co[2] = MT::widen(m_co[2], v[2]);
+	}
+
+    bool overlaps(const MT_BBox& b) const 
+	{
+        return MT::overlap(m_co[0], b[0]) &&
+			   MT::overlap(m_co[1], b[1]) &&
+			   MT::overlap(m_co[2], b[2]);
+    }
+
+	bool inside(const MT_BBox& b) const 
+	{
+        return MT::in(m_co[0], b[0]) &&
+			   MT::in(m_co[1], b[1]) &&
+			   MT::in(m_co[2], b[2]);
+    }
+
+	MT_BBox hull(const MT_BBox& b) const 
+	{
+		return MT_BBox(MT::hull(m_co[0], b[0]), 
+					   MT::hull(m_co[1], b[1]), 
+					   MT::hull(m_co[2], b[2])); 
+	}
+
+	bool contains(const MT_Point3& p) const 
+	{
+		return MT::in(p[0], m_co[0]) && MT::in(p[1], m_co[1]) && MT::in(p[2], m_co[2]);
+	}
+};
+
+inline MT_BBox operator+(const MT_BBox& b1, const MT_BBox& b2) 
+{
+	return MT_BBox(b1[0] + b2[0], b1[1] + b2[1], b1[2] + b2[2]);
+}
+
+inline MT_BBox operator-(const MT_BBox& b1, const MT_BBox& b2) 
+{
+	return MT_BBox(b1[0] - b2[0], b1[1] - b2[1], b1[2] - b2[2]);
+}
+
+#endif
+
+
diff --git a/extern/solid/include/MT_Interval.h b/extern/solid/include/MT_Interval.h
new file mode 100644
index 00000000000..25ebfd0a67d
--- /dev/null
+++ b/extern/solid/include/MT_Interval.h
@@ -0,0 +1,33 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef MT_INTERVAL_H
+#define MT_INTERVAL_H
+
+#include 
+
+#include "MT_Scalar.h"
+
+typedef MT::Interval MT_Interval;
+
+#endif
diff --git a/extern/solid/include/MT_Matrix3x3.h b/extern/solid/include/MT_Matrix3x3.h
new file mode 100644
index 00000000000..f7572f90fa2
--- /dev/null
+++ b/extern/solid/include/MT_Matrix3x3.h
@@ -0,0 +1,34 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef MT_MATRIX3X3_H
+#define MT_MATRIX3X3_H
+
+#include "MT_Scalar.h"
+#include 
+
+typedef MT::Matrix3x3 MT_Matrix3x3;
+
+
+
+#endif
diff --git a/extern/solid/include/MT_Point3.h b/extern/solid/include/MT_Point3.h
new file mode 100644
index 00000000000..ca84f652b65
--- /dev/null
+++ b/extern/solid/include/MT_Point3.h
@@ -0,0 +1,31 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef MT_POINT3_H
+#define MT_POINT3_H
+
+#include "MT_Vector3.h"
+
+typedef MT_Vector3 MT_Point3;
+
+#endif
diff --git a/extern/solid/include/MT_Quaternion.h b/extern/solid/include/MT_Quaternion.h
new file mode 100644
index 00000000000..ca860db711c
--- /dev/null
+++ b/extern/solid/include/MT_Quaternion.h
@@ -0,0 +1,35 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef MT_QUATERNION_H
+#define MT_QUATERNION_H
+
+#include "MT_Scalar.h"
+#include 
+
+typedef MT::Quaternion MT_Quaternion;
+
+#endif
+
+
+
diff --git a/extern/solid/include/MT_Scalar.h b/extern/solid/include/MT_Scalar.h
new file mode 100644
index 00000000000..663a1f1839c
--- /dev/null
+++ b/extern/solid/include/MT_Scalar.h
@@ -0,0 +1,158 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef MT_SCALAR_H
+#define MT_SCALAR_H
+
+#if defined (__sun__) || defined ( __sun ) || defined (__sparc) || defined (__sparc__) || defined (__sgi)
+#include 
+#include 
+#else
+#include 
+#include 
+#include 
+#endif
+
+#undef max
+
+#include "SOLID_types.h"
+
+#include "GEN_MinMax.h"
+#include "GEN_random.h"
+
+template 
+struct Scalar_traits {};
+
+template<>
+struct Scalar_traits {
+	static float TwoTimesPi() { return 6.283185307179586232f; }
+	static float epsilon() { return FLT_EPSILON; }
+	static float max() { return FLT_MAX; }
+	
+	static float random() { return float(GEN_rand()) / float(GEN_RAND_MAX); }
+#if defined (__sun) || defined (__sun__) || defined (__sparc) || defined (__APPLE__)
+	static float sqrt(float x) { return ::sqrt(x); } 
+	static float abs(float x) { return ::fabs(x); } 
+
+	static float cos(float x) { return ::cos(x); } 
+	static float sin(float x) { return ::sin(x); } 
+	static float tan(float x) { return ::tan(x); } 
+
+	static float acos(float x) { return ::acos(x); } 
+	static float asin(float x) { return ::asin(x); } 
+	static float atan(float x) { return ::atan(x); } 
+	static float atan2(float x, float y) { return ::atan2(x, y); } 
+
+	static float exp(float x) { return ::exp(x); } 
+	static float log(float x) { return ::log(x); } 
+	static float pow(float x, float y) { return ::pow(x, y); } 
+
+#else
+	static float sqrt(float x) { return ::sqrtf(x); } 
+	static float abs(float x) { return ::fabsf(x); } 
+
+	static float cos(float x) { return ::cosf(x); } 
+	static float sin(float x) { return ::sinf(x); } 
+	static float tan(float x) { return ::tanf(x); } 
+
+	static float acos(float x) { return ::acosf(x); } 
+	static float asin(float x) { return ::asinf(x); } 
+	static float atan(float x) { return ::atanf(x); } 
+	static float atan2(float x, float y) { return ::atan2f(x, y); } 
+
+	static float exp(float x) { return ::expf(x); } 
+	static float log(float x) { return ::logf(x); } 
+	static float pow(float x, float y) { return ::powf(x, y); } 
+#endif
+};
+
+template<>
+struct Scalar_traits {
+	static double TwoTimesPi() { return 6.283185307179586232; }
+	static double epsilon() { return DBL_EPSILON; }
+	static double max() { return DBL_MAX; }
+	
+	static double random() { return double(GEN_rand()) / double(GEN_RAND_MAX); }
+	static double sqrt(double x) { return ::sqrt(x); } 
+	static double abs(double x) { return ::fabs(x); } 
+
+	static double cos(double x) { return ::cos(x); } 
+	static double sin(double x) { return ::sin(x); } 
+	static double tan(double x) { return ::tan(x); } 
+
+	static double acos(double x) { return ::acos(x); } 
+	static double asin(double x) { return ::asin(x); } 
+	static double atan(double x) { return ::atan(x); } 
+	static double atan2(double x, double y) { return ::atan2(x, y); } 
+
+	static double exp(double x) { return ::exp(x); } 
+	static double log(double x) { return ::log(x); } 
+	static double pow(double x, double y) { return ::pow(x, y); } 
+};
+
+#ifdef USE_TRACER
+#include "MT_ScalarTracer.h"
+
+#ifdef USE_DOUBLES
+typedef MT_ScalarTracer   MT_Scalar;
+#else
+typedef MT_ScalarTracer    MT_Scalar;
+#endif
+
+#else
+
+#ifdef USE_DOUBLES
+typedef double   MT_Scalar;
+#else
+typedef float    MT_Scalar;
+#endif
+
+#endif
+
+
+const MT_Scalar  MT_2_PI         = Scalar_traits::TwoTimesPi();
+const MT_Scalar  MT_PI           = MT_2_PI * MT_Scalar(0.5);
+const MT_Scalar  MT_HALF_PI		 = MT_2_PI * MT_Scalar(0.25);
+const MT_Scalar  MT_RADS_PER_DEG = MT_2_PI / MT_Scalar(360.0);
+const MT_Scalar  MT_DEGS_PER_RAD = MT_Scalar(360.0) / MT_2_PI;
+
+const MT_Scalar  MT_EPSILON      = Scalar_traits::epsilon();
+const MT_Scalar  MT_INFINITY     = Scalar_traits::max();
+
+inline MT_Scalar MT_random() { return  Scalar_traits::random(); }
+inline MT_Scalar MT_abs(MT_Scalar x) { return Scalar_traits::abs(x); }
+inline MT_Scalar MT_sqrt(MT_Scalar x) { return Scalar_traits::sqrt(x); }
+
+inline MT_Scalar MT_cos(MT_Scalar x) { return Scalar_traits::cos(x); }
+inline MT_Scalar MT_sin(MT_Scalar x) { return Scalar_traits::sin(x); }
+inline MT_Scalar MT_tan(MT_Scalar x) { return Scalar_traits::tan(x); }
+
+inline MT_Scalar MT_acos(MT_Scalar x) { return Scalar_traits::acos(x); }
+inline MT_Scalar MT_asin(MT_Scalar x) { return Scalar_traits::asin(x); }
+inline MT_Scalar MT_atan(MT_Scalar x) { return Scalar_traits::atan(x); }
+inline MT_Scalar MT_atan2(MT_Scalar x, MT_Scalar y) { return Scalar_traits::atan2(x, y); }
+
+inline MT_Scalar MT_radians(MT_Scalar x) { return x * MT_RADS_PER_DEG; }
+inline MT_Scalar MT_degrees(MT_Scalar x) { return x * MT_DEGS_PER_RAD; }
+
+#endif
diff --git a/extern/solid/include/MT_Transform.h b/extern/solid/include/MT_Transform.h
new file mode 100644
index 00000000000..66f92428054
--- /dev/null
+++ b/extern/solid/include/MT_Transform.h
@@ -0,0 +1,38 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef MT_TRANSFORM_H
+#define MT_TRANSFORM_H
+
+#include "MT_Scalar.h"
+#include 
+
+typedef MT::Matrix3x3 MT_Matrix3x3;
+typedef MT::Transform MT_Transform;
+
+#endif
+
+
+
+
+
diff --git a/extern/solid/include/MT_Vector3.h b/extern/solid/include/MT_Vector3.h
new file mode 100644
index 00000000000..d50e80dc287
--- /dev/null
+++ b/extern/solid/include/MT_Vector3.h
@@ -0,0 +1,50 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef MT_VECTOR3_H
+#define MT_VECTOR3_H
+
+#include "MT_Scalar.h"
+#include 
+
+typedef MT::Vector3 MT_Vector3;
+
+#ifdef CPU_CMP
+
+inline bool operator==(const MT_Vector3& p1, const MT_Vector3& p2) 
+{
+	const unsigned int *i1 = (const unsigned int *)&p1;
+	const unsigned int *i2 = (const unsigned int *)&p2;
+    return i1[0] == i2[0] && i1[1] == i2[1] && i1[2] == i2[2];
+}
+
+#else
+
+inline bool operator==(const MT_Vector3& p1, const MT_Vector3& p2) 
+{
+	return p1[0] == p2[0] && p1[1] == p2[1] && p1[2] == p2[2];
+}
+
+#endif
+
+#endif
diff --git a/extern/solid/include/SOLID.h b/extern/solid/include/SOLID.h
new file mode 100644
index 00000000000..96d40f1ea6b
--- /dev/null
+++ b/extern/solid/include/SOLID.h
@@ -0,0 +1,279 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef SOLID_H
+#define SOLID_H
+
+#include "SOLID_types.h"
+
+#ifdef __cplusplus
+extern "C" { 
+#endif
+    
+	DT_DECLARE_HANDLE(DT_ObjectHandle);
+	DT_DECLARE_HANDLE(DT_SceneHandle);
+	DT_DECLARE_HANDLE(DT_ShapeHandle);
+	DT_DECLARE_HANDLE(DT_VertexBaseHandle);
+	DT_DECLARE_HANDLE(DT_RespTableHandle);
+	DT_DECLARE_HANDLE(DT_ArchiveHandle);
+
+	typedef unsigned int DT_ResponseClass;
+
+	typedef enum DT_ResponseType { 
+		DT_NO_RESPONSE,                  /* No response (obsolete) */
+		DT_BROAD_RESPONSE,               /* Broad phase response is returned. */
+		DT_SIMPLE_RESPONSE,              /* No collision data */
+		DT_WITNESSED_RESPONSE,           /* A point common to both objects
+											is returned as collision data
+										 */
+		DT_DEPTH_RESPONSE                /* The penetration depth is returned
+											as collision data. The penetration depth
+											is the shortest vector over which one 
+											object needs to be translated in order
+											to bring the objects in touching contact. 
+										 */ 
+	} DT_ResponseType;
+    
+/* For witnessed response, the following structure represents a common point. The world 
+   coordinates of 'point1' and 'point2' coincide. 'normal' is the zero vector.
+   
+   For depth response, the following structure represents the penetration depth. 
+   'point1' en 'point2' are the witness points of the penetration depth in world coordinates.
+   The penetration depth vector in world coordinates is represented by 'normal'.
+*/
+
+	typedef struct DT_CollData {
+		DT_Vector3 point1;               /* Point in object1 in world coordinates */ 
+		DT_Vector3 point2;               /* Point in object2 in world coordinates */
+		DT_Vector3 normal;               /* point2 - point1 */ 
+	} DT_CollData;
+
+/* A response callback is called by SOLID for each pair of collding objects. 'client-data'
+   is a pointer to an arbitrary structure in the client application. The client objects are
+   pointers to structures in the client application associated with the coliding objects.
+   'coll_data' is the collision data computed by SOLID.
+*/
+
+	typedef DT_Bool (*DT_ResponseCallback)(void *client_data,
+										   void *client_object1,
+										   void *client_object2,
+										   const DT_CollData *coll_data);
+										
+/* Shape definition */
+
+
+	extern DECLSPEC DT_ShapeHandle DT_NewBox(DT_Scalar x, DT_Scalar y, DT_Scalar z);
+	extern DECLSPEC DT_ShapeHandle DT_NewCone(DT_Scalar radius, DT_Scalar height);
+	extern DECLSPEC DT_ShapeHandle DT_NewCylinder(DT_Scalar radius, DT_Scalar height);
+	extern DECLSPEC DT_ShapeHandle DT_NewSphere(DT_Scalar radius);
+	extern DECLSPEC DT_ShapeHandle DT_NewPoint(const DT_Vector3 point);
+	extern DECLSPEC DT_ShapeHandle DT_NewLineSegment(const DT_Vector3 source, const DT_Vector3 target);
+	extern DECLSPEC DT_ShapeHandle DT_NewMinkowski(DT_ShapeHandle shape1, DT_ShapeHandle shape2);
+	extern DECLSPEC DT_ShapeHandle DT_NewHull(DT_ShapeHandle shape1, DT_ShapeHandle shape2);
+
+	extern DECLSPEC DT_VertexBaseHandle DT_NewVertexBase(const void *pointer, DT_Size stride);
+	extern DECLSPEC void DT_DeleteVertexBase(DT_VertexBaseHandle vertexBase);	
+	extern DECLSPEC void DT_ChangeVertexBase(DT_VertexBaseHandle vertexBase, const void *pointer);
+
+	extern DECLSPEC DT_ShapeHandle DT_NewComplexShape(DT_VertexBaseHandle vertexBase);
+	extern DECLSPEC void           DT_EndComplexShape();
+
+	extern DECLSPEC DT_ShapeHandle DT_NewPolytope(DT_VertexBaseHandle vertexBase);
+	extern DECLSPEC void           DT_EndPolytope();
+
+	extern DECLSPEC void DT_Begin();
+	extern DECLSPEC void DT_End();
+
+	extern DECLSPEC void DT_Vertex(const DT_Vector3 vertex);
+	extern DECLSPEC void DT_VertexIndex(DT_Index index);
+
+	extern DECLSPEC void DT_VertexIndices(DT_Count count, const DT_Index *indices);
+	extern DECLSPEC void DT_VertexRange(DT_Index first, DT_Count count); 
+
+	extern DECLSPEC void DT_DeleteShape(DT_ShapeHandle shape);
+
+/* Object  */
+
+	extern DECLSPEC DT_ObjectHandle DT_CreateObject(
+		void *client_object,      /* pointer to object in client memory */
+		DT_ShapeHandle shape  /* the shape or geometry of the object */
+		);
+
+	extern DECLSPEC void DT_DestroyObject(DT_ObjectHandle object);
+
+
+
+	extern DECLSPEC void DT_SetPosition(DT_ObjectHandle object, const DT_Vector3 position);
+	extern DECLSPEC void DT_SetOrientation(DT_ObjectHandle object, const DT_Quaternion orientation);
+	extern DECLSPEC void DT_SetScaling(DT_ObjectHandle object, const DT_Vector3 scaling);
+
+/* The margin is an offset from the actual shape. The actual geometry of an
+   object is the set of points whose distance to the transformed shape is at 
+   most the  margin. During the lifetime of an object the margin can be 
+   modified. 
+*/
+   
+	extern DECLSPEC void DT_SetMargin(DT_ObjectHandle object, DT_Scalar margin);
+
+
+/* These commands assume a column-major 4x4 OpenGL matrix representation */
+
+	extern DECLSPEC void DT_SetMatrixf(DT_ObjectHandle object, const float *m); 
+	extern DECLSPEC void DT_GetMatrixf(DT_ObjectHandle object, float *m); 
+
+	extern DECLSPEC void DT_SetMatrixd(DT_ObjectHandle object, const double *m); 
+	extern DECLSPEC void DT_GetMatrixd(DT_ObjectHandle object, double *m); 
+
+	extern DECLSPEC void DT_GetBBox(DT_ObjectHandle object, DT_Vector3 min, DT_Vector3 max);
+
+	
+	extern DECLSPEC DT_Bool  DT_GetIntersect(DT_ObjectHandle object1, DT_ObjectHandle object2,
+												DT_Vector3 v);
+/* This next command returns the distance between the objects. De returned
+   closest points are given in world coordinates.
+*/
+	extern DECLSPEC DT_Scalar DT_GetClosestPair(DT_ObjectHandle object1, DT_ObjectHandle object2,
+												DT_Vector3 point1, DT_Vector3 point2);  
+
+	extern DECLSPEC DT_Bool   DT_GetCommonPoint(DT_ObjectHandle object1, DT_ObjectHandle object2,
+												DT_Vector3 point);
+
+	extern DECLSPEC DT_Bool   DT_GetPenDepth(DT_ObjectHandle object1, DT_ObjectHandle object2,
+											 DT_Vector3 point1, DT_Vector3 point2);  
+
+/* Scene */
+
+	extern DECLSPEC DT_SceneHandle DT_CreateScene(); 
+	extern DECLSPEC void           DT_DestroyScene(DT_SceneHandle scene);
+
+	extern DECLSPEC void DT_AddObject(DT_SceneHandle scene, DT_ObjectHandle object);
+	extern DECLSPEC void DT_RemoveObject(DT_SceneHandle scene, DT_ObjectHandle object);
+
+/* Note that objects can be assigned to multiple scenes! */
+
+/* Response */
+
+/* Response tables are defined independent of the scenes in which they are used.
+   Multiple response tables can be used in one scene, and a response table
+   can be shared among scenes.
+*/
+	extern DECLSPEC DT_RespTableHandle DT_CreateRespTable(); 
+	extern DECLSPEC void               DT_DestroyRespTable(DT_RespTableHandle respTable); 
+
+/* Responses are defined on (pairs of) response classes. Each response table 
+   maintains its set of response classes.
+*/
+	extern DECLSPEC DT_ResponseClass DT_GenResponseClass(DT_RespTableHandle respTable);
+
+/* To each object for which a response is defined in the response table a
+   response class needs to be assigned. 
+*/
+
+	extern DECLSPEC void DT_SetResponseClass(DT_RespTableHandle respTable,
+											 DT_ObjectHandle object,
+											 DT_ResponseClass responseClass);
+
+	extern DECLSPEC void DT_ClearResponseClass(DT_RespTableHandle respTable, 
+											   DT_ObjectHandle object);
+
+	extern DECLSPEC void DT_CallResponse(DT_RespTableHandle respTable,
+										 DT_ObjectHandle object1,
+										 DT_ObjectHandle object2,
+										 const DT_CollData *coll_data);
+
+/* For each pair of objects multiple responses can be defined. A response is a callback
+   together with its response type and client data. */
+    
+/* Responses can be defined for all pairs of response classes... */
+	extern DECLSPEC void DT_AddDefaultResponse(DT_RespTableHandle respTable,
+											   DT_ResponseCallback response, 
+											   DT_ResponseType type, void *client_data);
+
+	extern DECLSPEC void DT_RemoveDefaultResponse(DT_RespTableHandle respTable,
+												  DT_ResponseCallback response);
+/* ...per response class... */
+	extern DECLSPEC void DT_AddClassResponse(DT_RespTableHandle respTable,
+											 DT_ResponseClass responseClass,
+											 DT_ResponseCallback response,
+											 DT_ResponseType type, void *client_data);
+
+	extern DECLSPEC void DT_RemoveClassResponse(DT_RespTableHandle respTable,
+												DT_ResponseClass responseClass,
+												DT_ResponseCallback response);
+
+/* ... and per pair of response classes...*/
+	extern DECLSPEC void DT_AddPairResponse(DT_RespTableHandle respTable,
+											DT_ResponseClass responseClass1,
+											DT_ResponseClass responseClass2, 
+											DT_ResponseCallback response,
+											DT_ResponseType type, void *client_data);
+	extern DECLSPEC void DT_RemovePairResponse(DT_RespTableHandle respTable,
+											   DT_ResponseClass responseClass1,
+											   DT_ResponseClass responseClass2,
+											   DT_ResponseCallback response);
+
+/* The next command calls the response callbacks for all intersecting pairs of objects in a scene. 
+   'DT_Test' returns the number of pairs of objects for which callbacks have been called. 
+*/
+ 
+	extern DECLSPEC DT_Count DT_Test(DT_SceneHandle scene, DT_RespTableHandle respTable);
+
+/* Set the maximum relative error in the closest points and penetration depth
+   computation. The default for `max_error' is 1.0e-3. Larger errors result
+   in better performance. Non-positive error tolerances are ignored.
+*/ 
+
+	extern DECLSPEC void DT_SetAccuracy(DT_Scalar max_error);
+
+/* Set the maximum tolerance on relative errors due to rounding.  The default for `tol_error' 
+   is the machine epsilon. Very large tolerances result in false collisions. Setting tol_error too small 
+   results in missed collisions. Non-positive error tolerances are ignored. 
+*/ 
+    
+	extern DECLSPEC void DT_SetTolerance(DT_Scalar tol_error);
+
+
+/* This function returns the client pointer to the first object in a scene hit by the ray 
+   (actually a line segment) defined by the points 'from' en 'to'. The spot is the hit point 
+   on the object in local coordinates. 'normal' is the normal to the surface of the object in
+   world coordinates. The ignore_client pointer is used to make one of the objects transparent.
+
+   NB: Currently ray tests are implemented for spheres, boxes, and meshes only!!
+*/   
+
+	extern DECLSPEC void *DT_RayCast(DT_SceneHandle scene, void *ignore_client,
+									 const DT_Vector3 source, const DT_Vector3 target,
+									 DT_Scalar max_param, DT_Scalar *param, DT_Vector3 normal);
+
+/* Similar, only here a single object is tested and a boolean is returned */
+
+	extern DECLSPEC DT_Bool DT_ObjectRayCast(DT_ObjectHandle object,
+											 const DT_Vector3 source, const DT_Vector3 target,
+											 DT_Scalar max_param, DT_Scalar *param, DT_Vector3 normal);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/extern/solid/include/SOLID_broad.h b/extern/solid/include/SOLID_broad.h
new file mode 100644
index 00000000000..74e4214fa67
--- /dev/null
+++ b/extern/solid/include/SOLID_broad.h
@@ -0,0 +1,75 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef SOLID_BROAD_H
+#define SOLID_BROAD_H
+
+#include "SOLID_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+    
+	DT_DECLARE_HANDLE(BP_SceneHandle);
+	DT_DECLARE_HANDLE(BP_ProxyHandle);
+	
+	typedef void (*BP_Callback)(void *client_data,
+								void *object1,
+								void *object2);
+
+	typedef bool (*BP_RayCastCallback)(void *client_data,
+									   void *object,
+									   const DT_Vector3 source,
+									   const DT_Vector3 target,
+									   DT_Scalar *lambda);
+	
+	extern DECLSPEC BP_SceneHandle BP_CreateScene(void *client_data,
+												  BP_Callback beginOverlap,
+												  BP_Callback endOverlap);
+	
+	extern DECLSPEC void           BP_DestroyScene(BP_SceneHandle scene);
+	
+	extern DECLSPEC BP_ProxyHandle BP_CreateProxy(BP_SceneHandle scene, 
+												  void *object,
+												  const DT_Vector3 min, 
+												  const DT_Vector3 max);
+	
+	extern DECLSPEC void           BP_DestroyProxy(BP_SceneHandle scene, 
+												  BP_ProxyHandle proxy);
+	
+	extern DECLSPEC void BP_SetBBox(BP_ProxyHandle proxy, 
+									const DT_Vector3 min, 
+									const DT_Vector3 max);
+	
+	extern DECLSPEC void *BP_RayCast(BP_SceneHandle scene, 
+									 BP_RayCastCallback objectRayCast, 
+									 void *client_data,
+									 const DT_Vector3 source,
+									 const DT_Vector3 target,
+									 DT_Scalar *lambda);		
+	
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/extern/solid/include/SOLID_types.h b/extern/solid/include/SOLID_types.h
new file mode 100644
index 00000000000..630594e447f
--- /dev/null
+++ b/extern/solid/include/SOLID_types.h
@@ -0,0 +1,53 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef SOLID_TYPES_H
+#define SOLID_TYPES_H
+
+#ifndef DECLSPEC
+# ifdef WIN32
+#  define DECLSPEC __declspec(dllexport)
+# else
+#  define DECLSPEC
+# endif
+#endif
+
+#define DT_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name
+    
+
+typedef unsigned short DT_Index;
+typedef unsigned short DT_Count;
+typedef unsigned int   DT_Size;
+typedef float          DT_Scalar; 
+typedef int            DT_Bool;
+
+#define DT_FALSE 0
+#define DT_TRUE  1
+
+#define DT_CONTINUE 0
+#define DT_DONE 1
+
+typedef DT_Scalar DT_Vector3[3]; 
+typedef DT_Scalar DT_Quaternion[4]; 
+
+#endif
diff --git a/extern/solid/make/msvc_7_0/broad/broad.vcproj b/extern/solid/make/msvc_7_0/broad/broad.vcproj
new file mode 100644
index 00000000000..adb56424e60
--- /dev/null
+++ b/extern/solid/make/msvc_7_0/broad/broad.vcproj
@@ -0,0 +1,262 @@
+
+
+	
+		
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+
diff --git a/extern/solid/make/msvc_7_0/complex/complex.vcproj b/extern/solid/make/msvc_7_0/complex/complex.vcproj
new file mode 100644
index 00000000000..2a895fa28d3
--- /dev/null
+++ b/extern/solid/make/msvc_7_0/complex/complex.vcproj
@@ -0,0 +1,252 @@
+
+
+	
+		
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+	
+		
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+
diff --git a/extern/solid/make/msvc_7_0/convex/convex.vcproj b/extern/solid/make/msvc_7_0/convex/convex.vcproj
new file mode 100644
index 00000000000..da088b5972f
--- /dev/null
+++ b/extern/solid/make/msvc_7_0/convex/convex.vcproj
@@ -0,0 +1,337 @@
+
+
+	
+		
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+
diff --git a/extern/solid/make/msvc_7_0/solid.vcproj b/extern/solid/make/msvc_7_0/solid.vcproj
new file mode 100644
index 00000000000..d9e6332987c
--- /dev/null
+++ b/extern/solid/make/msvc_7_0/solid.vcproj
@@ -0,0 +1,462 @@
+
+
+	
+		
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+	
+		
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+
diff --git a/extern/solid/src/DT_AlgoTable.h b/extern/solid/src/DT_AlgoTable.h
new file mode 100644
index 00000000000..0749ca7fdd9
--- /dev/null
+++ b/extern/solid/src/DT_AlgoTable.h
@@ -0,0 +1,47 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_ALGOTABLE_H
+#define DT_ALGOTABLE_H
+
+#include "DT_Shape.h"
+
+template 
+class AlgoTable {
+public:
+  void addEntry(DT_ShapeType type1, DT_ShapeType type2, Function function) 
+  { 
+    table[type2][type1] = function;
+    table[type1][type2] = function;
+  }
+
+  Function lookup(DT_ShapeType type1, DT_ShapeType type2) const 
+  {
+    return table[type1][type2];
+  }
+
+private:
+  Function table[NUM_TYPES][NUM_TYPES];
+};
+
+#endif
diff --git a/extern/solid/src/DT_C-api.cpp b/extern/solid/src/DT_C-api.cpp
new file mode 100644
index 00000000000..ac16deda87d
--- /dev/null
+++ b/extern/solid/src/DT_C-api.cpp
@@ -0,0 +1,581 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+
+#include "SOLID.h"
+
+#include "DT_Box.h"
+#include "DT_Cone.h"
+#include "DT_Cylinder.h"
+#include "DT_Sphere.h"
+#include "DT_Complex.h"
+#include "DT_Polytope.h"
+#include "DT_Polyhedron.h"
+#include "DT_Point.h"
+#include "DT_LineSegment.h"
+#include "DT_Triangle.h"
+#include "DT_Minkowski.h"
+#include "DT_Hull.h"
+
+#include "DT_Response.h"
+#include "DT_RespTable.h"
+
+#include "DT_Scene.h"
+#include "DT_Object.h"
+
+#include "DT_VertexBase.h"
+
+#include "DT_Accuracy.h"
+
+typedef MT::Tuple3 T_Vertex;
+typedef std::vector T_VertexBuf;
+typedef std::vector T_IndexBuf;
+typedef std::vector T_PolyList;
+
+static T_VertexBuf vertexBuf;
+static T_IndexBuf indexBuf;
+static T_PolyList polyList; 
+
+static DT_Complex       *currentComplex    = 0;
+static DT_Polyhedron    *currentPolyhedron = 0;
+static DT_VertexBase    *currentBase = 0;
+
+
+
+
+
+		
+DT_VertexBaseHandle DT_NewVertexBase(const void *pointer, DT_Size stride) 
+{
+    return (DT_VertexBaseHandle)new DT_VertexBase(pointer, stride);
+}
+
+void DT_DeleteVertexBase(DT_VertexBaseHandle vertexBase) 
+{ 
+    delete (DT_VertexBase *)vertexBase; 
+}
+
+void DT_ChangeVertexBase(DT_VertexBaseHandle vertexBase, const void *pointer) 
+{ 
+	DT_VertexBase *base = (DT_VertexBase *)vertexBase;
+	base->setPointer(pointer);
+	const DT_ComplexList& complexList = base->getComplexList();
+	DT_ComplexList::const_iterator it;
+	for (it = complexList.begin(); it != complexList.end(); ++it)
+	{
+		(*it)->refit();
+	}
+}
+
+
+DT_ShapeHandle DT_NewBox(DT_Scalar x, DT_Scalar y, DT_Scalar z) 
+{
+    return (DT_ShapeHandle)new DT_Box(MT_Scalar(x) * MT_Scalar(0.5), 
+									  MT_Scalar(y) * MT_Scalar(0.5), 
+									  MT_Scalar(z) * MT_Scalar(0.5));
+}
+
+DT_ShapeHandle DT_NewCone(DT_Scalar radius, DT_Scalar height)
+{
+    return (DT_ShapeHandle)new DT_Cone(MT_Scalar(radius), MT_Scalar(height));
+}
+
+DT_ShapeHandle DT_NewCylinder(DT_Scalar radius, DT_Scalar height) 
+{
+    return (DT_ShapeHandle)new DT_Cylinder(MT_Scalar(radius), MT_Scalar(height));
+}
+
+DT_ShapeHandle DT_NewSphere(DT_Scalar radius) 
+{
+    return (DT_ShapeHandle)new DT_Sphere(MT_Scalar(radius));
+}
+
+DT_ShapeHandle DT_NewPoint(const DT_Vector3 point) 
+{
+	return (DT_ShapeHandle)new DT_Point(MT_Point3(point));
+}
+
+DT_ShapeHandle DT_NewLineSegment(const DT_Vector3 source, const DT_Vector3 target) 
+{
+	return (DT_ShapeHandle)new DT_LineSegment(MT_Point3(source), MT_Point3(target));
+}
+
+DT_ShapeHandle DT_NewMinkowski(DT_ShapeHandle shape1, DT_ShapeHandle shape2) 
+{
+	if (((DT_Shape *)shape1)->getType() != CONVEX ||
+		((DT_Shape *)shape2)->getType() != CONVEX) 
+	{
+		return 0;
+	}
+
+	return (DT_ShapeHandle)new DT_Minkowski(*(DT_Convex *)shape1, *(DT_Convex *)shape2);
+}
+	
+DT_ShapeHandle DT_NewHull(DT_ShapeHandle shape1, DT_ShapeHandle shape2)
+{
+	if (((DT_Shape *)shape1)->getType() != CONVEX ||
+		((DT_Shape *)shape2)->getType() != CONVEX) 
+	{
+		return 0;
+	}
+
+	return (DT_ShapeHandle)new DT_Hull(*(DT_Convex *)shape1, *(DT_Convex *)shape2);
+}
+
+DT_ShapeHandle DT_NewComplexShape(const DT_VertexBaseHandle vertexBase) 
+{
+    if (!currentComplex) 
+	{
+		currentBase = vertexBase ? (DT_VertexBase *)vertexBase : new DT_VertexBase;
+		currentComplex = new DT_Complex(currentBase);
+	}
+    return (DT_ShapeHandle)currentComplex;
+}
+
+void DT_EndComplexShape() 
+{
+    if (currentComplex) 
+	{
+        if (currentBase->getPointer() == 0) 
+		{
+            T_Vertex *vertexArray = new T_Vertex[vertexBuf.size()];   
+			assert(vertexArray);	
+            std::copy(vertexBuf.begin(), vertexBuf.end(), &vertexArray[0]);
+            currentBase->setPointer(vertexArray, true);		
+        }
+		
+		vertexBuf.clear();
+        
+        currentComplex->finish(polyList.size(), &polyList[0]);
+        polyList.clear();
+        currentComplex = 0;
+        currentBase = 0; 
+    }
+}
+
+DT_ShapeHandle DT_NewPolytope(const DT_VertexBaseHandle vertexBase) 
+{
+    if (!currentPolyhedron) 
+	{
+		currentBase = vertexBase ? (DT_VertexBase *)vertexBase : new DT_VertexBase;
+        currentPolyhedron = new DT_Polyhedron;
+		
+    }
+    return (DT_ShapeHandle)currentPolyhedron;
+}
+
+void DT_EndPolytope() 
+{
+    if (currentPolyhedron) 
+	{
+        if (currentBase->getPointer() == 0) 
+		{
+			currentBase->setPointer(&vertexBuf[0]);		
+			new (currentPolyhedron) DT_Polyhedron(currentBase, indexBuf.size(), &indexBuf[0]);
+			
+			delete currentBase;
+		}
+		else
+		{
+			new (currentPolyhedron) DT_Polyhedron(currentBase, indexBuf.size(), &indexBuf[0]);
+		}
+		vertexBuf.clear();
+        indexBuf.clear();
+        currentPolyhedron = 0;
+        currentBase = 0;
+    }
+}
+
+void DT_Begin() 
+{}
+
+void DT_End() 
+{ 
+	if (currentComplex) 
+	{
+		DT_VertexIndices(indexBuf.size(), &indexBuf[0]);
+		indexBuf.clear();
+	}
+}
+
+void DT_Vertex(const DT_Vector3 vertex)
+{
+    MT::Vector3 p(vertex);
+    int i = GEN_max((int)vertexBuf.size() - 20, 0);
+	int n = static_cast(vertexBuf.size());
+	
+    while (i != n  && !(vertexBuf[i] == p)) 
+	{
+		++i;
+	}
+
+    if (i == n) 
+	{
+		vertexBuf.push_back(p);
+	}
+    indexBuf.push_back(i);
+}
+
+
+void DT_VertexIndex(DT_Index index) { indexBuf.push_back(index); }
+
+void DT_VertexIndices(DT_Count count, const DT_Index *indices) 
+{
+    if (currentComplex) 
+	{
+		DT_Convex *poly = count == 3 ? 
+			              static_cast(new DT_Triangle(currentBase, indices[0], indices[1], indices[2])) :
+						  static_cast(new DT_Polytope(currentBase, count, indices));  
+		polyList.push_back(poly);
+      
+    }
+
+    if (currentPolyhedron) 
+	{
+		int i;
+		for (i = 0; i < count; ++i) 
+		{
+            indexBuf.push_back(indices[i]);
+        }
+    }   
+}
+
+void DT_VertexRange(DT_Index first, DT_Count count) 
+{
+    DT_Index *indices = new DT_Index[count];
+    
+	DT_Index i;
+    for (i = 0; i != count; ++i) 
+	{
+        indices[i] = first + i;
+    }
+    DT_VertexIndices(count, indices);
+
+    delete [] indices;	
+}
+
+void DT_DeleteShape(DT_ShapeHandle shape) 
+{ 
+    delete (DT_Shape *)shape; 
+}
+
+
+
+
+// Scene
+
+
+DT_SceneHandle DT_CreateScene() 
+{
+    return (DT_SceneHandle)new DT_Scene; 
+}
+
+void DT_DestroyScene(DT_SceneHandle scene) 
+{
+    delete (DT_Scene *)scene;
+}
+
+void DT_AddObject(DT_SceneHandle scene, DT_ObjectHandle object) 
+{
+    assert(scene);
+    assert(object);
+    ((DT_Scene *)scene)->addObject(*(DT_Object *)object);
+}
+
+void DT_RemoveObject(DT_SceneHandle scene, DT_ObjectHandle object) 
+{
+    assert(scene);
+    assert(object);
+    ((DT_Scene *)scene)->removeObject(*(DT_Object *)object);
+}
+
+
+// Object instantiation
+
+
+DT_ObjectHandle DT_CreateObject(void *client_object,
+                                DT_ShapeHandle shape)
+{
+	return (DT_ObjectHandle)new DT_Object(client_object, *(DT_Shape *)shape);
+}
+
+void DT_DestroyObject(DT_ObjectHandle object) 
+{
+    delete (DT_Object *)object;
+}
+
+void DT_SetMargin(DT_ObjectHandle object, DT_Scalar margin) 
+{
+    ((DT_Object *)object)->setMargin(MT_Scalar(margin));
+}
+
+
+void DT_SetScaling(DT_ObjectHandle object, const DT_Vector3 scaling) 
+{
+    ((DT_Object *)object)->setScaling(MT_Vector3(scaling));
+}
+
+void DT_SetPosition(DT_ObjectHandle object, const DT_Vector3 position) 
+{
+    ((DT_Object *)object)->setPosition(MT_Point3(position));
+}
+
+void DT_SetOrientation(DT_ObjectHandle object, const DT_Quaternion orientation) 
+{
+    ((DT_Object *)object)->setOrientation(MT_Quaternion(orientation));   
+}
+
+
+void DT_SetMatrixf(DT_ObjectHandle object, const float *m) 
+{
+    ((DT_Object *)object)->setMatrix(m);
+}
+
+void DT_GetMatrixf(DT_ObjectHandle object, float *m) 
+{
+    ((DT_Object *)object)->getMatrix(m);
+}
+
+void DT_SetMatrixd(DT_ObjectHandle object, const double *m) 
+{
+    ((DT_Object *)object)->setMatrix(m);
+}
+void DT_GetMatrixd(DT_ObjectHandle object, double *m) 
+{
+    ((DT_Object *)object)->getMatrix(m);
+}
+
+void DT_GetBBox(DT_ObjectHandle object, DT_Vector3 min, DT_Vector3 max) 
+{
+	const MT_BBox& bbox = ((DT_Object *)object)->getBBox();
+	bbox.getMin().getValue(min);
+	bbox.getMax().getValue(max);
+}
+
+DT_Bool DT_GetIntersect(DT_ObjectHandle object1, DT_ObjectHandle object2, DT_Vector3 vec)
+{
+	MT_Vector3 v;
+	DT_Bool result = intersect(*(DT_Object*)object1, *(DT_Object*)object2, v);
+	v.getValue(vec);
+	return result;
+}
+
+DT_Scalar DT_GetClosestPair(DT_ObjectHandle object1, DT_ObjectHandle object2,
+							DT_Vector3 point1, DT_Vector3 point2) 
+{
+    MT_Point3 p1, p2;
+    
+    MT_Scalar result = closest_points(*(DT_Object *)object1, 
+									  *(DT_Object *)object2,
+									  p1, p2);
+	p1.getValue(point1);
+	p2.getValue(point2);
+
+    return MT_sqrt(result);
+}
+
+DT_Bool DT_GetCommonPoint(DT_ObjectHandle object1, DT_ObjectHandle object2,
+						  DT_Vector3 point) 
+{
+    MT_Point3   p1, p2;
+	MT_Vector3  v(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0)); 
+    
+    bool result = common_point(*(DT_Object *)object1, *(DT_Object *)object2, v, p1, p2);
+
+	if (result) 
+	{
+		p1.getValue(point);
+	}
+
+    return result;
+}
+
+DT_Bool DT_GetPenDepth(DT_ObjectHandle object1, DT_ObjectHandle object2,
+				    DT_Vector3 point1, DT_Vector3 point2) 
+{
+    MT_Point3   p1, p2;
+	MT_Vector3  v(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0)); 
+    
+    bool result = penetration_depth(*(DT_Object *)object1, *(DT_Object *)object2, v, p1, p2);
+
+	if (result) 
+	{
+		p1.getValue(point1);
+		p2.getValue(point2);
+	}
+
+    return result;
+}
+
+// Response
+
+DT_RespTableHandle DT_CreateRespTable() 
+{
+    return (DT_RespTableHandle)new DT_RespTable;
+}    
+
+void DT_DestroyRespTable(DT_RespTableHandle respTable) 
+{
+    delete (DT_RespTable *)respTable;
+}
+
+DT_ResponseClass DT_GenResponseClass(DT_RespTableHandle respTable) 
+{
+	return ((DT_RespTable *)respTable)->genResponseClass();
+}
+
+void DT_SetResponseClass(DT_RespTableHandle respTable, DT_ObjectHandle object,
+						 DT_ResponseClass responseClass)
+{
+	((DT_RespTable *)respTable)->setResponseClass(object, responseClass);
+}
+
+void DT_ClearResponseClass(DT_RespTableHandle respTable, 
+						   DT_ObjectHandle object)
+{
+	((DT_RespTable *)respTable)->clearResponseClass(object);
+}
+
+void DT_CallResponse(DT_RespTableHandle respTable,
+					 DT_ObjectHandle object1,
+					 DT_ObjectHandle object2,
+					 const DT_CollData *coll_data)
+{
+	const DT_ResponseList& responseList =
+		((DT_RespTable *)respTable)->find(object1, object2);
+	
+	if (responseList.getType() != DT_NO_RESPONSE) 
+	{
+		responseList(((DT_Object *)object1)->getClientObject(), 
+					 ((DT_Object *)object2)->getClientObject(),
+					 coll_data);
+	}
+}
+
+
+void DT_AddDefaultResponse(DT_RespTableHandle respTable,
+                           DT_ResponseCallback response, 
+						   DT_ResponseType type, void *client_data)
+{
+    ((DT_RespTable *)respTable)->addDefault(DT_Response(response, type, client_data));
+}
+
+void DT_RemoveDefaultResponse(DT_RespTableHandle respTable,
+							  DT_ResponseCallback response)
+{
+      ((DT_RespTable *)respTable)->removeDefault(DT_Response(response));
+}
+
+void DT_AddClassResponse(DT_RespTableHandle respTable,
+						 DT_ResponseClass responseClass, 
+						 DT_ResponseCallback response, 
+						 DT_ResponseType type, void *client_data)
+{
+    ((DT_RespTable *)respTable)->addSingle(responseClass, 
+										   DT_Response(response, type, client_data));
+}
+
+void DT_RemoveClassResponse(DT_RespTableHandle respTable,
+							DT_ResponseClass responseClass, 
+							DT_ResponseCallback response) 
+{
+    ((DT_RespTable *)respTable)->removeSingle(responseClass, 
+											  DT_Response(response));
+}
+
+void DT_AddPairResponse(DT_RespTableHandle respTable,
+                        DT_ResponseClass responseClass1, 
+						DT_ResponseClass responseClass2, 
+                        DT_ResponseCallback response,
+						DT_ResponseType type, void *client_data)
+{
+    ((DT_RespTable *)respTable)->addPair(responseClass1, responseClass2, 
+										 DT_Response(response, type, client_data));
+}
+
+void DT_RemovePairResponse(DT_RespTableHandle respTable,
+						   DT_ResponseClass responseClass1, 
+						   DT_ResponseClass responseClass2, 
+						   DT_ResponseCallback response)
+{
+    ((DT_RespTable *)respTable)->removePair(responseClass1, responseClass2, 
+											DT_Response(response));
+}
+
+
+// Runtime
+
+void DT_SetAccuracy(DT_Scalar max_error) 
+{ 
+	if (max_error > MT_Scalar(0.0)) 
+	{
+		DT_Accuracy::setAccuracy(MT_Scalar(max_error)); 
+	}
+}
+
+void DT_SetTolerance(DT_Scalar tol_error) 
+{ 
+	if (tol_error > MT_Scalar(0.0)) 
+	{
+		DT_Accuracy::setTolerance(MT_Scalar(tol_error)); 
+	}
+}
+
+DT_Count DT_Test(DT_SceneHandle scene, DT_RespTableHandle respTable) 
+{ 
+    return ((DT_Scene *)scene)->handleCollisions((DT_RespTable *)respTable);
+}
+
+void *DT_RayCast(DT_SceneHandle scene, void *ignore_client,
+				 const DT_Vector3 source, const DT_Vector3 target,
+				 DT_Scalar max_param, DT_Scalar *param, DT_Vector3 normal) 
+{
+	DT_Scalar  lambda = max_param;
+
+	void *client_object = ((DT_Scene *)scene)->rayCast(ignore_client, source, target, 
+													   lambda, normal);
+   if (client_object)
+   {
+      *param = lambda;
+   }
+	return client_object;
+}
+
+DT_Bool DT_ObjectRayCast(DT_ObjectHandle object,
+	   				     const DT_Vector3 source, const DT_Vector3 target,
+					     DT_Scalar max_param, DT_Scalar *param, DT_Vector3 hit_normal) 
+{
+	MT_Scalar lambda = MT_Scalar(max_param);
+	MT_Vector3 normal;  
+
+	bool result = ((DT_Object *)object)->ray_cast(MT_Point3(source), MT_Point3(target), 
+												  lambda, normal);
+
+	if (result) 
+	{
+		*param = lambda;
+		normal.getValue(hit_normal);
+	}
+	return result;
+}
+
diff --git a/extern/solid/src/DT_Encounter.cpp b/extern/solid/src/DT_Encounter.cpp
new file mode 100644
index 00000000000..36de33154a3
--- /dev/null
+++ b/extern/solid/src/DT_Encounter.cpp
@@ -0,0 +1,111 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_RespTable.h"
+#include "DT_Encounter.h"
+#include "DT_Object.h"
+#include "GEN_MinMax.h"
+
+DT_Bool DT_Encounter::exactTest(const DT_RespTable *respTable, int& count) const 
+{
+	const DT_ResponseList& responseList = respTable->find(m_obj_ptr1, m_obj_ptr2);
+
+   switch (responseList.getType()) 
+   {
+   case DT_BROAD_RESPONSE:
+	   return (respTable->getResponseClass(m_obj_ptr1) < respTable->getResponseClass(m_obj_ptr2)) ?
+			   responseList(m_obj_ptr1->getClientObject(), m_obj_ptr2->getClientObject(), 0) :   
+			   responseList(m_obj_ptr2->getClientObject(), m_obj_ptr1->getClientObject(), 0);    
+   case DT_SIMPLE_RESPONSE: 
+	   if (intersect(*m_obj_ptr1, *m_obj_ptr2, m_sep_axis)) 
+	   {
+		   ++count;
+		   return (respTable->getResponseClass(m_obj_ptr1) < respTable->getResponseClass(m_obj_ptr2)) ?
+			   responseList(m_obj_ptr1->getClientObject(), m_obj_ptr2->getClientObject(), 0) :   
+			   responseList(m_obj_ptr2->getClientObject(), m_obj_ptr1->getClientObject(), 0);    
+ 
+	   }
+	   break;
+   case DT_WITNESSED_RESPONSE: {
+	   MT_Point3  p1, p2;
+	   
+	   if (common_point(*m_obj_ptr1, *m_obj_ptr2, m_sep_axis, p1, p2)) 
+	   { 
+		   ++count;
+           if (respTable->getResponseClass(m_obj_ptr1) < respTable->getResponseClass(m_obj_ptr2))
+           {
+			   DT_CollData coll_data;
+			   
+			   p1.getValue(coll_data.point1);
+			   p2.getValue(coll_data.point2);
+			   
+               return responseList(m_obj_ptr1->getClientObject(), m_obj_ptr2->getClientObject(), &coll_data);
+           }
+           else
+           {
+			   DT_CollData coll_data;
+			   
+			   p1.getValue(coll_data.point2);
+			   p2.getValue(coll_data.point1);
+			   
+               return responseList(m_obj_ptr2->getClientObject(), m_obj_ptr1->getClientObject(), &coll_data);
+           }
+	   }
+	   break;
+   }
+   case DT_DEPTH_RESPONSE: {
+	   MT_Point3  p1, p2;
+	   
+	   if (penetration_depth(*m_obj_ptr1, *m_obj_ptr2, m_sep_axis, p1, p2)) 
+	   { 
+		   ++count;
+           if (respTable->getResponseClass(m_obj_ptr1) < respTable->getResponseClass(m_obj_ptr2))
+           {
+			   DT_CollData coll_data;
+			   
+			   p1.getValue(coll_data.point1);
+			   p2.getValue(coll_data.point2);	
+               (p2 - p1).getValue(coll_data.normal);
+			   
+               return responseList(m_obj_ptr1->getClientObject(), m_obj_ptr2->getClientObject(), &coll_data);
+           }
+           else
+           {
+			   DT_CollData coll_data;
+			   
+			   p1.getValue(coll_data.point2);
+			   p2.getValue(coll_data.point1); 
+               (p1 - p2).getValue(coll_data.normal);
+			   
+               return responseList(m_obj_ptr2->getClientObject(), m_obj_ptr1->getClientObject(), &coll_data);
+           }
+	   }
+	   break;
+   }
+   case DT_NO_RESPONSE:
+	   break;
+   default:
+	   assert(false);
+   }
+   return DT_CONTINUE;
+}
diff --git a/extern/solid/src/DT_Encounter.h b/extern/solid/src/DT_Encounter.h
new file mode 100644
index 00000000000..f20ea3936b0
--- /dev/null
+++ b/extern/solid/src/DT_Encounter.h
@@ -0,0 +1,84 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_ENCOUNTER_H
+#define DT_ENCOUNTER_H
+
+#include 
+
+#include "MT_Vector3.h"
+#include "DT_Object.h"
+#include "DT_Shape.h"
+
+class DT_RespTable;
+
+class DT_Encounter {
+public:
+    DT_Encounter() {}
+    DT_Encounter(DT_Object *obj_ptr1, DT_Object *obj_ptr2) 
+        : m_sep_axis(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0)) 
+    {
+		assert(obj_ptr1 != obj_ptr2);
+        if (obj_ptr2->getType() < obj_ptr1->getType() || 
+            (obj_ptr2->getType() == obj_ptr1->getType() &&
+             obj_ptr2 < obj_ptr1))
+        { 
+            m_obj_ptr1 = obj_ptr2; 
+            m_obj_ptr2 = obj_ptr1; 
+        }
+        else 
+        { 
+            m_obj_ptr1 = obj_ptr1; 
+            m_obj_ptr2 = obj_ptr2; 
+        }
+    }
+
+    DT_Object         *first()          const { return m_obj_ptr1; }
+    DT_Object         *second()         const { return m_obj_ptr2; }
+    const MT_Vector3&  separatingAxis() const { return m_sep_axis; }
+
+ 	DT_Bool exactTest(const DT_RespTable *respTable, int& count) const;
+
+private:
+    DT_Object          *m_obj_ptr1;
+    DT_Object          *m_obj_ptr2;
+    mutable MT_Vector3  m_sep_axis;
+};
+
+inline bool operator<(const DT_Encounter& a, const DT_Encounter& b) 
+{ 
+    return a.first() < b.first() || 
+        (a.first() == b.first() && a.second() < b.second()); 
+}
+
+
+
+inline std::ostream& operator<<(std::ostream& os, const DT_Encounter& a) {
+    return os << '(' << a.first() << ", " << a.second() << ')';
+}
+
+
+
+typedef std::set DT_EncounterTable;
+
+#endif
diff --git a/extern/solid/src/DT_Object.cpp b/extern/solid/src/DT_Object.cpp
new file mode 100644
index 00000000000..ed43a7bdaf2
--- /dev/null
+++ b/extern/solid/src/DT_Object.cpp
@@ -0,0 +1,276 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_Object.h"
+#include "DT_AlgoTable.h"
+#include "DT_Convex.h" 
+#include "DT_Complex.h" 
+#include "DT_LineSegment.h" 
+#include "DT_Transform.h"
+#include "DT_Minkowski.h"
+#include "DT_Sphere.h"
+
+void DT_Object::setBBox() 
+{
+	m_bbox = m_shape.bbox(m_xform, m_margin); 
+	DT_Vector3 min, max;
+	m_bbox.getMin().getValue(min);
+	m_bbox.getMax().getValue(max);
+	
+	T_ProxyList::const_iterator it;
+	for (it = m_proxies.begin(); it != m_proxies.end(); ++it) 
+	{
+		BP_SetBBox(*it, min, max);
+	}
+}
+
+bool DT_Object::ray_cast(const MT_Point3& source, const MT_Point3& target, 
+						 MT_Scalar& lambda, MT_Vector3& normal) const 
+{	
+	MT_Transform inv_xform = m_xform.inverse();
+	MT_Point3 local_source = inv_xform(source);
+	MT_Point3 local_target = inv_xform(target);
+	MT_Vector3 local_normal;
+
+	bool result = m_shape.ray_cast(local_source, local_target, lambda, local_normal);
+    	
+	if (result) 
+	{
+		normal = local_normal * inv_xform.getBasis();
+      MT_Scalar len = normal.length();
+		if (len > MT_Scalar(0.0))
+      {
+         normal /= len;
+      }
+	}
+
+	return result;
+}
+
+
+typedef AlgoTable IntersectTable;
+typedef AlgoTable Common_pointTable;
+typedef AlgoTable Penetration_depthTable;
+typedef AlgoTable Closest_pointsTable;
+
+
+bool intersectConvexConvex(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+						   const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+                           MT_Vector3& v) 
+{
+	DT_Transform ta(a2w, (const DT_Convex&)a);
+	DT_Transform tb(b2w, (const DT_Convex&)b);
+    return intersect((a_margin > MT_Scalar(0.0) ? static_cast(DT_Minkowski(ta, DT_Sphere(a_margin))) : static_cast(ta)), 
+			         (b_margin > MT_Scalar(0.0) ? static_cast(DT_Minkowski(tb, DT_Sphere(b_margin))) : static_cast(tb)), v);
+}
+
+bool intersectComplexConvex(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+						    const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+                            MT_Vector3& v) 
+{
+	if (a.getType() == COMPLEX)
+	{
+		DT_Transform tb(b2w, (const DT_Convex&)b);
+		return intersect((const DT_Complex&)a, a2w, a_margin, 
+		             (b_margin > MT_Scalar(0.0) ? static_cast(DT_Minkowski(tb, DT_Sphere(b_margin))) : static_cast(tb)), v);
+	}
+	
+	bool r = intersectComplexConvex(b, b2w, b_margin, a, a2w, a_margin, v);
+	v *= -1.;
+	return r;
+}
+
+bool intersectComplexComplex(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+							 const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+                             MT_Vector3& v) 
+{
+    return intersect((const DT_Complex&)a, a2w, a_margin, 
+					 (const DT_Complex&)b, b2w, b_margin, v);
+}
+
+IntersectTable *intersectInitialize() 
+{
+    IntersectTable *p = new IntersectTable;
+    p->addEntry(COMPLEX, COMPLEX, intersectComplexComplex);
+    p->addEntry(COMPLEX, CONVEX, intersectComplexConvex);
+    p->addEntry(CONVEX, CONVEX, intersectConvexConvex);
+    return p;
+}
+
+bool intersect(const DT_Object& a, const DT_Object& b, MT_Vector3& v) 
+{
+    static IntersectTable *intersectTable = intersectInitialize();
+    Intersect intersect = intersectTable->lookup(a.getType(), b.getType());
+    return intersect(a.m_shape, a.m_xform, a.m_margin, 
+		             b.m_shape, b.m_xform, b.m_margin, v);
+}
+
+bool common_pointConvexConvex(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+							  const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+							  MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+	DT_Transform ta(a2w, (const DT_Convex&)a);
+	DT_Transform tb(b2w, (const DT_Convex&)b);
+    return common_point((a_margin > MT_Scalar(0.0) ? static_cast(DT_Minkowski(ta, DT_Sphere(a_margin))) : static_cast(ta)), 
+						(b_margin > MT_Scalar(0.0) ? static_cast(DT_Minkowski(tb, DT_Sphere(b_margin))) : static_cast(tb)), v, pa, pb);
+}
+
+bool common_pointComplexConvex(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+							   const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+							   MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+	if (a.getType() == COMPLEX)
+	{
+		DT_Transform tb(b2w, (const DT_Convex&)b);
+		return common_point((const DT_Complex&)a, a2w, a_margin,
+					(b_margin > MT_Scalar(0.0) ? static_cast(DT_Minkowski(tb, DT_Sphere(b_margin))) : static_cast(tb)), v, pa, pb);
+	}
+	
+	bool r = common_pointComplexConvex(b, b2w, b_margin, a, a2w, a_margin, v, pb, pa);
+	v *= -1.;
+	return r;
+}
+
+bool common_pointComplexComplex(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+								const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+								MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    return common_point((const DT_Complex&)a, a2w, a_margin, 
+						(const DT_Complex&)b, b2w, b_margin, v, pa, pb);
+}
+
+Common_pointTable *common_pointInitialize() 
+{
+    Common_pointTable *p = new Common_pointTable;
+    p->addEntry(COMPLEX, COMPLEX, common_pointComplexComplex);
+    p->addEntry(COMPLEX, CONVEX, common_pointComplexConvex);
+    p->addEntry(CONVEX, CONVEX, common_pointConvexConvex);
+    return p;
+}
+
+bool common_point(const DT_Object& a, const DT_Object& b, MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    static Common_pointTable *common_pointTable = common_pointInitialize();
+    Common_point common_point = common_pointTable->lookup(a.getType(), b.getType());
+    return common_point(a.m_shape, a.m_xform, a.m_margin, 
+						b.m_shape, b.m_xform, b.m_margin, v, pa, pb);
+}
+
+
+
+bool penetration_depthConvexConvex(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+								   const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+                                   MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    return hybrid_penetration_depth(DT_Transform(a2w, (const DT_Convex&)a), a_margin, 
+									DT_Transform(b2w, (const DT_Convex&)b), b_margin, v, pa, pb);
+}
+
+bool penetration_depthComplexConvex(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+									const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+                                    MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    if (a.getType() == COMPLEX)
+    	return penetration_depth((const DT_Complex&)a, a2w, a_margin,
+							 DT_Transform(b2w, (const DT_Convex&)b), b_margin, v, pa, pb);
+
+    bool r = penetration_depthComplexConvex(b, b2w, b_margin, a, a2w, a_margin, v, pb, pa);
+    v *= -1.;
+    return r;
+}
+
+bool penetration_depthComplexComplex(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+									 const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+                                     MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    return penetration_depth((const DT_Complex&)a, a2w, a_margin, (const DT_Complex&)b, b2w, b_margin, v, pa, pb);
+}
+
+Penetration_depthTable *penetration_depthInitialize() 
+{
+    Penetration_depthTable *p = new Penetration_depthTable;
+    p->addEntry(COMPLEX, COMPLEX, penetration_depthComplexComplex);
+    p->addEntry(COMPLEX, CONVEX, penetration_depthComplexConvex);
+    p->addEntry(CONVEX, CONVEX, penetration_depthConvexConvex);
+    return p;
+}
+
+bool penetration_depth(const DT_Object& a, const DT_Object& b, MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    static Penetration_depthTable *penetration_depthTable = penetration_depthInitialize();
+    Penetration_depth penetration_depth = penetration_depthTable->lookup(a.getType(), b.getType());
+    return penetration_depth(a.m_shape, a.m_xform, a.m_margin, 
+		                     b.m_shape, b.m_xform, b.m_margin, v, pa, pb);
+}
+
+
+MT_Scalar closest_pointsConvexConvex(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+									 const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+									 MT_Point3& pa, MT_Point3& pb)
+{
+	DT_Transform ta(a2w, (const DT_Convex&)a);
+	DT_Transform tb(b2w, (const DT_Convex&)b);
+    return closest_points((a_margin > MT_Scalar(0.0) ? static_cast(DT_Minkowski(ta, DT_Sphere(a_margin))) : static_cast(ta)), 
+						  (b_margin > MT_Scalar(0.0) ? static_cast(DT_Minkowski(tb, DT_Sphere(b_margin))) : static_cast(tb)), MT_INFINITY, pa, pb);
+}
+
+MT_Scalar closest_pointsComplexConvex(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+									  const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+									  MT_Point3& pa, MT_Point3& pb)
+{
+    if (a.getType() == COMPLEX)
+    {
+	DT_Transform tb(b2w, (const DT_Convex&)b);
+	return closest_points((const DT_Complex&)a, a2w, a_margin,
+							(b_margin > MT_Scalar(0.0) ? static_cast(DT_Minkowski(tb, DT_Sphere(b_margin))) : static_cast(tb)), pa, pb);
+    }
+    
+    return closest_pointsComplexConvex(b, b2w, b_margin, a, a2w, a_margin, pb, pa);
+}
+
+MT_Scalar closest_pointsComplexComplex(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+									   const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+									   MT_Point3& pa, MT_Point3& pb) 
+{
+    return closest_points((const DT_Complex&)a, a2w, a_margin, 
+						  (const DT_Complex&)b, b2w, b_margin, pa, pb);
+}
+
+Closest_pointsTable *closest_pointsInitialize()
+{
+    Closest_pointsTable *p = new Closest_pointsTable;
+    p->addEntry(COMPLEX, COMPLEX, closest_pointsComplexComplex);
+    p->addEntry(COMPLEX, CONVEX, closest_pointsComplexConvex);
+    p->addEntry(CONVEX, CONVEX, closest_pointsConvexConvex);
+    return p;
+}
+
+MT_Scalar closest_points(const DT_Object& a, const DT_Object& b,
+						 MT_Point3& pa, MT_Point3& pb) 
+{
+    static Closest_pointsTable *closest_pointsTable = closest_pointsInitialize();
+    Closest_points closest_points = closest_pointsTable->lookup(a.getType(), b.getType());
+    return closest_points(a.m_shape, a.m_xform, a.m_margin, 
+						  b.m_shape, b.m_xform, b.m_margin, pa, pb);
+}
+
diff --git a/extern/solid/src/DT_Object.h b/extern/solid/src/DT_Object.h
new file mode 100644
index 00000000000..78beee2ab57
--- /dev/null
+++ b/extern/solid/src/DT_Object.h
@@ -0,0 +1,157 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_OBJECT_H
+#define DT_OBJECT_H
+
+#include 
+
+#include "SOLID.h"
+#include "SOLID_broad.h"
+
+#include "MT_Transform.h"
+#include "MT_Quaternion.h"
+#include "MT_BBox.h"
+#include "DT_Shape.h"
+
+class DT_Convex;
+
+class DT_Object {
+public:
+    DT_Object(void *client_object, const DT_Shape& shape) :
+		m_client_object(client_object),
+		m_shape(shape), 
+		m_margin(MT_Scalar(0.0))
+	{
+		m_xform.setIdentity();
+		setBBox();
+	}
+
+	void setMargin(MT_Scalar margin) 
+	{ 
+		m_margin = margin; 
+		setBBox();
+	}
+
+	void setScaling(const MT_Vector3& scaling)
+	{
+        m_xform.scale(scaling);
+        setBBox();
+    }
+
+    void setPosition(const MT_Point3& pos) 
+	{ 
+        m_xform.setOrigin(pos);
+        setBBox();
+    }
+    
+    void setOrientation(const MT_Quaternion& orn)
+	{
+		m_xform.setRotation(orn);
+		setBBox();
+    }
+
+	void setMatrix(const float *m) 
+	{
+        m_xform.setValue(m);
+		assert(m_xform.getBasis().determinant() != MT_Scalar(0.0));
+        setBBox();
+    }
+
+    void setMatrix(const double *m)
+	{
+        m_xform.setValue(m);
+		assert(m_xform.getBasis().determinant() != MT_Scalar(0.0));
+        setBBox();
+    }
+
+    void getMatrix(float *m) const
+	{
+        m_xform.getValue(m);
+    }
+
+    void getMatrix(double *m) const 
+	{
+        m_xform.getValue(m);
+    }
+
+	void setBBox();
+
+	const MT_BBox& getBBox() const { return m_bbox; }	
+	
+    DT_ResponseClass getResponseClass() const { return m_responseClass; }
+    
+	void setResponseClass(DT_ResponseClass responseClass) 
+	{ 
+		m_responseClass = responseClass;
+	}
+
+    DT_ShapeType getType() const { return m_shape.getType(); }
+
+    void *getClientObject() const { return m_client_object; }
+
+	bool ray_cast(const MT_Point3& source, const MT_Point3& target, 
+				  MT_Scalar& param, MT_Vector3& normal) const; 
+
+	void addProxy(BP_ProxyHandle proxy) { m_proxies.push_back(proxy); }
+
+	void removeProxy(BP_ProxyHandle proxy) 
+	{ 
+		T_ProxyList::iterator it = std::find(m_proxies.begin(), m_proxies.end(), proxy);
+		if (it != m_proxies.end()) {
+			m_proxies.erase(it);
+		}
+	}
+
+
+	friend bool intersect(const DT_Object&, const DT_Object&, MT_Vector3& v);
+	
+	friend bool common_point(const DT_Object&, const DT_Object&, MT_Vector3&, 
+							 MT_Point3&, MT_Point3&);
+	
+	friend bool penetration_depth(const DT_Object&, const DT_Object&, 
+								  MT_Vector3&, MT_Point3&, MT_Point3&);
+	
+	friend MT_Scalar closest_points(const DT_Object&, const DT_Object&, 
+									MT_Point3&, MT_Point3&);
+
+private:
+	typedef std::vector T_ProxyList;
+
+	void              *m_client_object;
+	DT_ResponseClass   m_responseClass;
+    const DT_Shape&    m_shape;
+    MT_Scalar          m_margin;
+	MT_Transform       m_xform;
+	T_ProxyList		   m_proxies;
+	MT_BBox            m_bbox;
+};
+
+#endif
+
+
+
+
+
+
+
diff --git a/extern/solid/src/DT_RespTable.cpp b/extern/solid/src/DT_RespTable.cpp
new file mode 100644
index 00000000000..20fbfc06aac
--- /dev/null
+++ b/extern/solid/src/DT_RespTable.cpp
@@ -0,0 +1,184 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_RespTable.h"
+
+#include 
+
+DT_ResponseList DT_RespTable::g_emptyResponseList;
+
+DT_RespTable::~DT_RespTable()
+{
+	DT_ResponseClass i;
+	for (i = 0; i < m_responseClass; ++i) 
+	{
+		delete [] m_table[i];
+	}
+}
+
+DT_ResponseClass DT_RespTable::genResponseClass()
+{
+	DT_ResponseClass newClass = m_responseClass++;
+	DT_ResponseList *newList = new DT_ResponseList[m_responseClass];
+	assert(newList);
+	m_table.push_back(newList);
+	m_singleList.resize(m_responseClass);
+	DT_ResponseClass i;
+	for (i = 0; i < m_responseClass; ++i) 
+	{
+		newList[i].append(m_default);
+		newList[i].append(m_singleList[i]);
+	}
+	return newClass;
+}
+
+void DT_RespTable::setResponseClass(void *object, 
+									DT_ResponseClass responseClass) 
+{
+	assert(responseClass < m_responseClass);
+	m_objectMap[object] = responseClass;
+}
+
+DT_ResponseClass DT_RespTable::getResponseClass(void *object) const
+{
+	T_ObjectMap::const_iterator it = m_objectMap.find(object);
+	assert(it != m_objectMap.end());
+	return (*it).second;
+}
+
+void DT_RespTable::clearResponseClass(void *object) 
+{
+	m_objectMap.erase(object);
+}
+
+const DT_ResponseList& DT_RespTable::find(void *object1, void *object2) const
+{
+	T_ObjectMap::const_iterator it = m_objectMap.find(object1);
+	if (it != m_objectMap.end()) 
+	{
+		DT_ResponseClass responseClass1 = (*it).second;
+		it = m_objectMap.find(object2);
+		if (it != m_objectMap.end()) 
+		{
+			DT_ResponseClass responseClass2 = (*it).second;
+			if (responseClass1 < responseClass2) 
+			{
+				std::swap(responseClass1, responseClass2);
+			}
+			return m_table[responseClass1][responseClass2];
+		}
+	}
+	return g_emptyResponseList;
+}
+
+void DT_RespTable::addDefault(const DT_Response& response)
+{
+	m_default.addResponse(response);
+	DT_ResponseClass i;
+	for (i = 0; i < m_responseClass; ++i) 
+	{
+		DT_ResponseClass j;
+		for (j = 0; j <= i; ++j) 
+		{
+			m_table[i][j].addResponse(response);
+		}
+	}
+}
+
+void DT_RespTable::removeDefault(const DT_Response& response)
+{
+	m_default.removeResponse(response);
+	DT_ResponseClass i;
+	for (i = 0; i < m_responseClass; ++i) 
+	{
+		DT_ResponseClass j;
+		for (j = 0; j <= i; ++j) 
+		{
+			m_table[i][j].removeResponse(response);
+		}
+	}
+}
+
+void DT_RespTable::addSingle(DT_ResponseClass responseClass, 
+							 const DT_Response& response)
+{	
+	assert(responseClass < m_responseClass);
+	m_singleList[responseClass].addResponse(response);
+	DT_ResponseClass j;
+	for (j = 0; j < responseClass; ++j) 
+	{
+		m_table[responseClass][j].addResponse(response);
+	}
+	
+	DT_ResponseClass i;
+	for (i = responseClass; i < m_responseClass; ++i) 
+	{
+		m_table[i][responseClass].addResponse(response);
+	}
+}
+
+void DT_RespTable::removeSingle(DT_ResponseClass responseClass, 
+								const DT_Response& response)
+{	
+	assert(responseClass < m_responseClass);
+	m_singleList[responseClass].removeResponse(response);
+	DT_ResponseClass j;
+	for (j = 0; j < responseClass; ++j) 
+	{
+		m_table[responseClass][j].removeResponse(response);
+	}
+	
+	DT_ResponseClass i;
+	for (i = responseClass; i < m_responseClass; ++i) 
+	{
+		m_table[i][responseClass].removeResponse(response);
+	}
+}
+
+void DT_RespTable::addPair(DT_ResponseClass responseClass1,
+						   DT_ResponseClass responseClass2, 
+						   const DT_Response& response)
+{
+	assert(responseClass1 < m_responseClass);
+	assert(responseClass2 < m_responseClass);
+	if (responseClass1 < responseClass2) 
+	{
+		std::swap(responseClass1, responseClass2);
+	}
+	m_table[responseClass1][responseClass2].addResponse(response);
+}
+
+
+void DT_RespTable::removePair(DT_ResponseClass responseClass1,
+							  DT_ResponseClass responseClass2, 
+							  const DT_Response& response)
+{
+	assert(responseClass1 < m_responseClass);
+	assert(responseClass2 < m_responseClass);
+	if (responseClass1 < responseClass2) 
+	{
+		std::swap(responseClass1, responseClass2);
+	}
+	m_table[responseClass1][responseClass2].removeResponse(response);
+}
+
diff --git a/extern/solid/src/DT_RespTable.h b/extern/solid/src/DT_RespTable.h
new file mode 100644
index 00000000000..9a17f562937
--- /dev/null
+++ b/extern/solid/src/DT_RespTable.h
@@ -0,0 +1,139 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_RESPTABLE_H
+#define DT_RESPTABLE_H
+
+#include 
+#include 
+#include 
+#include 
+#include "GEN_MinMax.h"
+#include "DT_Response.h"
+
+class DT_ResponseList : public std::list {
+public:
+    DT_ResponseList() : m_type(DT_NO_RESPONSE) {}
+
+	DT_ResponseType getType() const { return m_type; }
+
+    void addResponse(const DT_Response& response) 
+	{
+        if (response.getType() != DT_NO_RESPONSE) 
+		{
+            push_back(response);
+            GEN_set_max(m_type, response.getType());
+        }
+    }
+
+    void removeResponse(const DT_Response& response) 
+	{
+		iterator it = std::find(begin(), end(), response);
+		if (it != end()) 
+		{
+			erase(it);
+			m_type = DT_NO_RESPONSE;
+			for (it = begin(); it != end(); ++it) 
+			{
+				GEN_set_max(m_type, (*it).getType());
+			}
+		}
+    }
+	
+    void append(const DT_ResponseList& responseList) 
+	{
+        if (responseList.getType() != DT_NO_RESPONSE) 
+		{
+			const_iterator it;
+			for (it = responseList.begin(); it != responseList.end(); ++it) 
+			{
+				addResponse(*it);
+			}
+		}
+	}
+
+    DT_Bool operator()(void *a, void *b, const DT_CollData *coll_data) const 
+	{
+		DT_Bool done = DT_CONTINUE;
+		const_iterator it;
+        for (it = begin(); !done && it != end(); ++it) 
+		{
+            done = (*it)(a, b, coll_data);
+        }
+		return done;
+    }
+    
+private:
+	DT_ResponseType    m_type;
+};
+
+class DT_RespTable {
+private:
+	typedef std::map T_ObjectMap; 
+	typedef std::vector T_PairTable;
+	typedef std::vector T_SingleList;
+
+public:
+	DT_RespTable() : m_responseClass(0) {}
+
+	~DT_RespTable();
+
+	DT_ResponseClass genResponseClass();
+	
+	void setResponseClass(void *object, DT_ResponseClass responseClass);
+	DT_ResponseClass getResponseClass(void *object) const;
+	
+	void clearResponseClass(void *object);
+	
+	const DT_ResponseList& find(void *object1, void *object2) const;
+
+    void addDefault(const DT_Response& response); 
+    void removeDefault(const DT_Response& response); 
+
+    void addSingle(DT_ResponseClass responseClass, 
+				   const DT_Response& response);
+    void removeSingle(DT_ResponseClass responseClass, 
+					  const DT_Response& response);
+	
+    void addPair(DT_ResponseClass responseClass1, 
+				 DT_ResponseClass responseClass2, 
+				 const DT_Response& response);
+    void removePair(DT_ResponseClass responseClass1, 
+					DT_ResponseClass responseClass2, 
+					const DT_Response& response);
+
+private:
+	static DT_ResponseList g_emptyResponseList;
+
+	T_ObjectMap      m_objectMap;
+	DT_ResponseClass m_responseClass;
+	T_PairTable      m_table;
+	T_SingleList     m_singleList;
+    DT_ResponseList  m_default;
+};
+
+#endif
+
+
+
+
diff --git a/extern/solid/src/DT_Response.h b/extern/solid/src/DT_Response.h
new file mode 100644
index 00000000000..e58d9bb9944
--- /dev/null
+++ b/extern/solid/src/DT_Response.h
@@ -0,0 +1,63 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_RESPONSE_H
+#define DT_RESPONSE_H
+
+#include "SOLID.h"
+
+class DT_Response {
+public:
+    DT_Response(DT_ResponseCallback response    = 0, 
+				DT_ResponseType     type        = DT_NO_RESPONSE, 
+				void               *client_data = 0) 
+	  : m_response(response), 
+		m_type(type), 
+		m_client_data(client_data) {}
+    
+	DT_ResponseType getType() const { return m_type; }
+
+	DT_Bool operator()(void *a, void *b, const DT_CollData *coll_data) const 
+	{  
+		return (*m_response)(m_client_data, a, b, coll_data); 
+	}
+
+	friend bool operator==(const DT_Response& a, const DT_Response& b) 
+	{
+		return a.m_response == b.m_response;
+	}
+    
+	friend bool operator!=(const DT_Response& a, const DT_Response& b) 
+	{
+		return a.m_response != b.m_response;
+	}
+    
+private:
+    DT_ResponseCallback  m_response;
+    DT_ResponseType      m_type;
+    void                *m_client_data;
+};
+
+#endif  
+
+
diff --git a/extern/solid/src/DT_Scene.cpp b/extern/solid/src/DT_Scene.cpp
new file mode 100644
index 00000000000..56cea1633ca
--- /dev/null
+++ b/extern/solid/src/DT_Scene.cpp
@@ -0,0 +1,183 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_Scene.h"
+#include "DT_Object.h"
+#include "DT_Convex.h"
+
+//#define DEBUG
+
+static void beginOverlap(void *client_data, void *object1, void *object2) 
+{
+	DT_Encounter e((DT_Object *)object1, (DT_Object *)object2);
+	DT_EncounterTable *encounterTable = static_cast(client_data);
+
+#ifdef DEBUG	
+	std::cout << "Begin: " << e << std::endl; 
+#endif
+
+	encounterTable->insert(e);
+}
+
+
+static void endOverlap(void *client_data, void *object1, void *object2) 
+{
+	DT_Encounter e((DT_Object *)object1, (DT_Object *)object2);
+	DT_EncounterTable *encounterTable = static_cast(client_data);
+
+#ifdef DEBUG
+	std::cout << "End:   " << e << std::endl; 
+#endif
+	
+	assert(encounterTable->find(e) != encounterTable->end()); 
+	encounterTable->erase(e);
+}
+
+struct DT_RayCastData {
+	DT_RayCastData(const void *ignore) 
+	  : m_ignore(ignore) 
+	{}
+
+	const void  *m_ignore;
+	MT_Vector3  m_normal;
+};
+
+static bool objectRayCast(void *client_data, 
+						  void *object,  
+						  const DT_Vector3 source,
+						  const DT_Vector3 target,
+						  DT_Scalar *lambda) 
+{
+	DT_RayCastData *data = static_cast(client_data); 
+	if (((DT_Object *)object)->getClientObject() != data->m_ignore)
+	{
+		MT_Scalar param = MT_Scalar(*lambda);
+		
+		if (((DT_Object *)object)->ray_cast(MT_Point3(source), MT_Point3(target),
+											param, data->m_normal))
+		{
+			*lambda = param;
+			return true;
+		}
+	}
+	return false;
+}
+
+DT_Scene::DT_Scene() 
+  : m_broadphase(BP_CreateScene(&m_encounterTable, &beginOverlap, &endOverlap))
+{}
+
+DT_Scene::~DT_Scene()
+{
+	BP_DestroyScene(m_broadphase);
+}
+
+void DT_Scene::addObject(DT_Object &object)
+{
+	const MT_BBox& bbox = object.getBBox();
+	DT_Vector3 min, max;
+	bbox.getMin().getValue(min);
+	bbox.getMax().getValue(max);
+    BP_ProxyHandle proxy = BP_CreateProxy(m_broadphase, &object, min, max);
+	
+#ifdef DEBUG
+	DT_EncounterTable::iterator it;	
+	std::cout << "Add " << &object << ':';
+	for (it = m_encounterTable.begin(); it != m_encounterTable.end(); ++it) {
+		std::cout << ' ' << (*it);
+	}
+	std::cout << std::endl;
+#endif
+	object.addProxy(proxy);
+    m_objectList.push_back(std::make_pair(&object, proxy));
+}
+
+
+
+void DT_Scene::removeObject(DT_Object& object)
+{
+    T_ObjectList::iterator it = m_objectList.begin();
+
+    while (it != m_objectList.end() && &object != (*it).first)
+	{
+        ++it;
+    }
+
+    if (it != m_objectList.end())
+	{
+		object.removeProxy((*it).second);
+        BP_DestroyProxy(m_broadphase, (*it).second);
+		m_objectList.erase(it);
+
+#ifdef DEBUG
+		std::cout << "Remove " << &object << ':';
+		DT_EncounterTable::iterator it;	
+		for (it = m_encounterTable.begin(); it != m_encounterTable.end(); ++it)
+		{
+			std::cout << ' ' << (*it);
+			assert((*it).first() != &object &&
+				   (*it).second() != &object);
+		}
+		std::cout << std::endl;
+#endif
+    }
+}
+
+
+
+int DT_Scene::handleCollisions(const DT_RespTable *respTable)
+{
+    int count = 0;
+
+    assert(respTable);
+
+	DT_EncounterTable::iterator it;	
+	for (it = m_encounterTable.begin(); it != m_encounterTable.end(); ++it)
+	{
+		if ((*it).exactTest(respTable, count))
+		{
+			break;
+        }
+	
+    }
+    return count;
+}
+
+void *DT_Scene::rayCast(const void *ignore_client,
+						const DT_Vector3 source, const DT_Vector3 target, 
+						DT_Scalar& lambda, DT_Vector3 normal) const 
+{
+	DT_RayCastData data(ignore_client);
+	DT_Object *object = (DT_Object *)BP_RayCast(m_broadphase, 
+												&objectRayCast, 
+												&data, 
+												source, target,
+												&lambda);
+	if (object)
+	{
+		data.m_normal.getValue(normal);
+		return object->getClientObject();
+	}
+	
+	return 0;
+}
diff --git a/extern/solid/src/DT_Scene.h b/extern/solid/src/DT_Scene.h
new file mode 100644
index 00000000000..9b061910312
--- /dev/null
+++ b/extern/solid/src/DT_Scene.h
@@ -0,0 +1,57 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_SCENE_H
+#define DT_SCENE_H
+
+#include 
+
+#include "SOLID_broad.h"
+#include "DT_Encounter.h"
+
+class DT_Object;
+class DT_RespTable;
+
+class DT_Scene {
+public:
+    DT_Scene();
+    ~DT_Scene();
+
+    void addObject(DT_Object& object);
+    void removeObject(DT_Object& object);
+
+    int  handleCollisions(const DT_RespTable *respTable);
+
+	void *rayCast(const void *ignore_client, 
+				  const DT_Vector3 source, const DT_Vector3 target, 
+				  DT_Scalar& lambda, DT_Vector3 normal) const;
+
+private:
+	typedef std::vector > T_ObjectList;
+
+	BP_SceneHandle      m_broadphase;
+	T_ObjectList        m_objectList;
+    DT_EncounterTable   m_encounterTable;
+};
+
+#endif
diff --git a/extern/solid/src/Makefile b/extern/solid/src/Makefile
new file mode 100644
index 00000000000..b45a1da9cd3
--- /dev/null
+++ b/extern/solid/src/Makefile
@@ -0,0 +1,48 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# 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. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License.  See http://www.blender.org/BL/ for information
+# about this.
+#
+# 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.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+SOURCEDIR = extern/solid/src
+LIBNAME = solid
+DIR = $(OCGDIR)/extern/$(LIBNAME)
+DIRS = broad complex convex
+
+include nan_subdirs.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I../include -I$(NAN_QHULL)/include
+CPPFLAGS += -Iconvex -Icomplex
+CPPFLAGS += -DQHULL -DUSE_DOUBLES
+
+include nan_compile.mk 
+
diff --git a/extern/solid/src/broad/BP_C-api.cpp b/extern/solid/src/broad/BP_C-api.cpp
new file mode 100644
index 00000000000..43e1172927b
--- /dev/null
+++ b/extern/solid/src/broad/BP_C-api.cpp
@@ -0,0 +1,77 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "SOLID_broad.h"
+
+#include "BP_Scene.h"
+#include "BP_Proxy.h"
+
+BP_SceneHandle BP_CreateScene(void *client_data,
+							  BP_Callback beginOverlap,
+							  BP_Callback endOverlap)
+{
+	return (BP_SceneHandle)new BP_Scene(client_data, 
+										beginOverlap, 
+										endOverlap);
+}
+
+ 
+void BP_DestroyScene(BP_SceneHandle scene)
+{
+	delete (BP_Scene *)scene;
+}
+	
+
+BP_ProxyHandle BP_CreateProxy(BP_SceneHandle scene, void *object,
+							  const DT_Vector3 min, const DT_Vector3 max)
+{
+	return (BP_ProxyHandle)
+		((BP_Scene *)scene)->createProxy(object, min, max);
+}
+
+
+void BP_DestroyProxy(BP_SceneHandle scene, BP_ProxyHandle proxy) 
+{
+	((BP_Scene *)scene)->destroyProxy((BP_Proxy *)proxy);
+}
+
+
+
+void BP_SetBBox(BP_ProxyHandle proxy, const DT_Vector3 min, const DT_Vector3 max)	
+{
+	((BP_Proxy *)proxy)->setBBox(min, max);
+}
+
+void *BP_RayCast(BP_SceneHandle scene, 
+				 BP_RayCastCallback objectRayCast,
+				 void *client_data,
+				 const DT_Vector3 source,
+				 const DT_Vector3 target,
+				 DT_Scalar *lambda) 
+{
+	return ((BP_Scene *)scene)->rayCast(objectRayCast,
+										client_data,
+										source,	target,
+										*lambda);
+}
+
diff --git a/extern/solid/src/broad/BP_Endpoint.h b/extern/solid/src/broad/BP_Endpoint.h
new file mode 100644
index 00000000000..8de6e67ce65
--- /dev/null
+++ b/extern/solid/src/broad/BP_Endpoint.h
@@ -0,0 +1,108 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef BP_ENDPOINT_H
+#define BP_ENDPOINT_H
+
+#include "SOLID_types.h"
+
+class BP_Proxy;
+
+class BP_Link {
+public:
+	BP_Link() {}
+	explicit BP_Link(BP_Proxy *proxy) :
+		m_proxy(proxy)
+	{}
+
+	DT_Index  m_index;
+	DT_Count  m_count;
+	BP_Proxy *m_proxy;
+};
+
+typedef unsigned int Uint32;
+
+class BP_Endpoint {
+public:
+    enum { 
+		MINIMUM = 0x00000000, 
+		MAXIMUM = 0x80000000,	
+		TYPEBIT = 0x00000001
+	};
+
+    BP_Endpoint() {}
+    BP_Endpoint(DT_Scalar pos, Uint32 type, BP_Link *link) 
+	  :	m_link(link)
+	{
+		setPos(pos, type);
+	}
+ 
+	DT_Scalar getPos()   const { return m_pos; }
+	DT_Index&   getIndex() const { return m_link->m_index; }
+	DT_Count&   getCount() const { return m_link->m_count; }
+	BP_Proxy *getProxy() const { return m_link->m_proxy; }
+	
+	DT_Index   getEndIndex()   const { return (m_link + 1)->m_index; }
+	
+	Uint32 getType() const 
+	{ 
+		return (m_bits & TYPEBIT) ? (~m_bits & MAXIMUM) : (m_bits & MAXIMUM);
+	}
+
+	void setPos(DT_Scalar pos, Uint32 type) 
+	{
+		m_pos = pos; 
+		if ((m_bits & MAXIMUM) == type) 
+		{
+			m_bits &= ~TYPEBIT;
+		}
+		else 
+		{
+			m_bits |= TYPEBIT;
+		}
+	}
+
+private:
+	union {
+		DT_Scalar    m_pos;
+		Uint32       m_bits;
+	};
+	BP_Link        *m_link;
+};
+
+inline bool operator<(const BP_Endpoint& a, const BP_Endpoint& b) 
+{
+    return a.getPos() < b.getPos(); 
+}
+
+#endif
+
+
+
+
+
+
+
+
+
+
diff --git a/extern/solid/src/broad/BP_EndpointList.cpp b/extern/solid/src/broad/BP_EndpointList.cpp
new file mode 100644
index 00000000000..aa094ffeb0a
--- /dev/null
+++ b/extern/solid/src/broad/BP_EndpointList.cpp
@@ -0,0 +1,237 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include 
+#include 
+
+#include "BP_EndpointList.h"
+#include "BP_Scene.h"
+#include "BP_Proxy.h"
+#include "BP_ProxyList.h"
+
+DT_Index BP_EndpointList::stab(const BP_Endpoint& pos, BP_ProxyList& proxies) const 
+{
+	DT_Index result = std::upper_bound(begin(), end(), pos) - begin();
+	
+	if (result != 0) 
+	{
+		DT_Index i = result - 1;
+		DT_Count count = (*this)[i].getCount(); 
+		while (count) 
+		{
+			const BP_Endpoint& endpoint = (*this)[i];
+			if (endpoint.getType() == BP_Endpoint::MINIMUM &&
+				pos < (*this)[endpoint.getEndIndex()]) 
+			{
+				proxies.add(endpoint.getProxy());
+				--count;
+			}
+			assert(i != 0 || count == 0);
+			--i;
+		}											
+	}
+	return result;
+}
+
+DT_Scalar BP_EndpointList::nextLambda(DT_Index& index, 
+									  DT_Scalar source, 
+									  DT_Scalar delta) const
+{
+	if (delta != 0.0f) 
+	{
+		if (delta < 0.0f) 
+		{
+			if (index != 0) 
+			{
+				return ((*this)[--index].getPos() - source) / delta;
+			}
+		}
+		else 
+		{
+			if (index != size()) 
+			{
+				return ((*this)[index++].getPos() - source) / delta;
+			}
+		}
+	}
+	return FLT_MAX;
+}
+
+
+void BP_EndpointList::range(const BP_Endpoint& min, 
+							const BP_Endpoint& max,
+							DT_Index& first, DT_Index& last,
+							BP_ProxyList& proxies) const 
+{
+	first = stab(min, proxies);
+	last  = std::upper_bound(begin(), end(), max) - begin();
+	
+	DT_Index i;
+	for (i = first; i != last; ++i) 
+	{
+		const BP_Endpoint& endpoint = (*this)[i];
+		if (endpoint.getType() == BP_Endpoint::MINIMUM) 
+		{
+			proxies.add(endpoint.getProxy());
+		}
+	}
+}
+
+void BP_EndpointList::addInterval(const BP_Endpoint& min, 
+								  const BP_Endpoint& max,
+								  BP_ProxyList& proxies) 
+{
+	assert(invariant());
+	DT_Index first, last;
+	range(min, max, first, last, proxies);
+	insert(begin() + last, max);
+	insert(begin() + first, min);
+	++last; 
+	
+	(*this)[first].getCount() = first != 0 ? (*this)[first - 1].getCount() : 0;
+	(*this)[last].getCount() = (*this)[last - 1].getCount();
+	
+	
+	DT_Index i;
+	for (i = first; i != last; ++i) 
+	{
+		++(*this)[i].getCount();
+		(*this)[i].getIndex() = i;
+	} 
+	for (; i != size(); ++i) 
+	{
+		(*this)[i].getIndex() = i;
+	} 
+	
+	assert(invariant());
+}
+
+void BP_EndpointList::removeInterval(DT_Index first, DT_Index last,
+									 BP_ProxyList& proxies) 
+{ 
+	assert(invariant());
+	
+	BP_Endpoint min = (*this)[first];
+	BP_Endpoint max = (*this)[last]; 
+	
+	erase(begin() + last);
+	erase(begin() + first);
+	--last;
+	
+	DT_Index i;
+	for (i = first; i != last; ++i) 
+	{
+		--(*this)[i].getCount();
+		(*this)[i].getIndex() = i;
+	} 
+	for (; i != size(); ++i) 
+	{
+		(*this)[i].getIndex() = i;
+	} 
+	
+	range(min, max, first, last, proxies);
+	
+	assert(invariant());
+}
+
+void BP_EndpointList::move(DT_Index index, DT_Scalar pos, Uint32 type,  
+						   BP_Scene& scene, T_Overlap overlap)
+{
+	assert(invariant());
+	
+	BP_Endpoint endpoint = (*this)[index];
+    DT_Scalar delta = pos - endpoint.getPos();
+	
+    if (delta != DT_Scalar(0.0)) 
+	{
+		endpoint.setPos(pos, type);
+		if (delta < DT_Scalar(0.0)) 
+		{
+			while (index != 0 && endpoint < (*this)[index - 1]) 
+			{
+				(*this)[index] = (*this)[index - 1];
+				(*this)[index].getIndex() = index;
+				encounters((*this)[index], endpoint, scene, overlap);
+				--index;
+			}
+		}
+		else 
+		{
+			DT_Index last = size() - 1;
+			while (index != last && (*this)[index + 1] < endpoint) 
+			{
+				(*this)[index] = (*this)[index + 1];
+				(*this)[index].getIndex() = index;
+				encounters(endpoint, (*this)[index], scene, overlap);
+				++index;
+			}
+		}
+		(*this)[index] = endpoint;
+		(*this)[index].getIndex() = index;
+    }
+
+	assert(invariant());
+}
+
+void BP_EndpointList::encounters(const BP_Endpoint& a, const BP_Endpoint& b,
+								 BP_Scene& scene, T_Overlap overlap)
+{
+	assert(a.getProxy() != b.getProxy());
+	
+	if (a.getType() != b.getType()) 
+	{
+		if (a.getType() == BP_Endpoint::MAXIMUM) 
+		{
+			if (overlap(*a.getProxy(), *b.getProxy())) 
+			{
+				scene.callBeginOverlap(a.getProxy()->getObject(), 
+									   b.getProxy()->getObject());
+			}
+			++a.getCount();
+			++b.getCount();
+		}
+		else 
+		{
+			if (overlap(*a.getProxy(), *b.getProxy())) 
+			{
+				scene.callEndOverlap(a.getProxy()->getObject(), 
+									 b.getProxy()->getObject());
+			}
+			--a.getCount();
+			--b.getCount();
+		}
+	}
+	else 
+	{
+		if (a.getType() == BP_Endpoint::MAXIMUM) 
+		{
+			--a.getCount();
+			++b.getCount();
+		}
+		else 
+		{
+			++a.getCount();
+			--b.getCount();
+		}
+	}
+}
diff --git a/extern/solid/src/broad/BP_EndpointList.h b/extern/solid/src/broad/BP_EndpointList.h
new file mode 100644
index 00000000000..6154991ed3d
--- /dev/null
+++ b/extern/solid/src/broad/BP_EndpointList.h
@@ -0,0 +1,109 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef BP_ENDPOINTLIST_H
+#define BP_ENDPOINTLIST_H
+
+//#define PARANOID
+
+#include 
+
+#include "BP_Endpoint.h"
+#include "BP_ProxyList.h"
+
+class BP_Scene;
+
+typedef bool (*T_Overlap)(const BP_Proxy& a, const BP_Proxy& b);
+
+class BP_EndpointList : public std::vector {
+public:
+	BP_EndpointList() {}
+	
+	DT_Index stab(const BP_Endpoint& pos, BP_ProxyList& proxies) const;
+	
+	DT_Index stab(DT_Scalar pos, BP_ProxyList& proxies) const
+	{
+		return stab(BP_Endpoint(pos, BP_Endpoint::MINIMUM, 0), proxies);
+	}
+	
+
+   void range(const BP_Endpoint& min, const BP_Endpoint& max, 
+			  DT_Index& first, DT_Index& last, BP_ProxyList& proxies) const;
+	
+	void range(DT_Scalar lb, DT_Scalar ub, DT_Index& first, DT_Index& last, BP_ProxyList& proxies) const 
+	{
+		range(BP_Endpoint(lb, BP_Endpoint::MINIMUM, 0), 
+			  BP_Endpoint(ub, BP_Endpoint::MAXIMUM, 0),
+			  first, last, proxies);
+	}
+	
+	void addInterval(const BP_Endpoint& min, const BP_Endpoint& max, BP_ProxyList& proxies);
+	void removeInterval(DT_Index first, DT_Index last, BP_ProxyList& proxies);
+
+	void move(DT_Index index, DT_Scalar pos, Uint32 type, BP_Scene& scene, T_Overlap overlap);	
+   
+   DT_Scalar nextLambda(DT_Index& index, DT_Scalar source, DT_Scalar target) const;
+	
+
+private:
+	void encounters(const BP_Endpoint& a, const BP_Endpoint& b,
+					    BP_Scene& scene, T_Overlap overlap);
+
+
+#ifdef PARANOID
+	bool invariant() const 
+	{
+		DT_Count count = 0;
+		DT_Index i;
+		for (i = 0; i != size(); ++i) 
+		{
+         const BP_Endpoint& endpoint = (*this)[i];
+
+			if (endpoint.getType() == BP_Endpoint::MINIMUM) 
+			{
+				++count;
+			}
+			else 
+			{
+				--count;
+			}
+			if (endpoint.getCount() != count)
+			{
+				return false;
+			}
+			if (endpoint.getIndex() != i) 
+			{
+				return false;
+			}
+		}
+		return true;
+	}
+#else
+	bool invariant() const { return true; }
+#endif
+
+};
+
+
+
+#endif
diff --git a/extern/solid/src/broad/BP_Proxy.cpp b/extern/solid/src/broad/BP_Proxy.cpp
new file mode 100644
index 00000000000..e8007df240d
--- /dev/null
+++ b/extern/solid/src/broad/BP_Proxy.cpp
@@ -0,0 +1,120 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include 
+
+#include "BP_Proxy.h"
+#include "BP_Scene.h"
+
+BP_Proxy::BP_Proxy(void *object, 
+				   BP_Scene& scene) 
+  :	m_object(object),
+	m_scene(scene)
+{
+	int i;
+	for (i = 0; i < 3; ++i) 
+	{
+		new (&m_interval[i]) BP_Interval(this);
+	}
+}
+
+void BP_Proxy::add(const DT_Vector3 min,
+				   const DT_Vector3 max,
+				   BP_ProxyList& proxies) 
+{
+	int i;
+	for (i = 0; i < 3; ++i) 
+	{
+		m_scene.getList(i).addInterval(
+			BP_Endpoint(min[i], BP_Endpoint::MINIMUM, &m_interval[i].m_min), 
+			BP_Endpoint(max[i], BP_Endpoint::MAXIMUM, &m_interval[i].m_max), 
+			proxies);
+	}
+}
+
+void BP_Proxy::remove(BP_ProxyList& proxies) 
+{
+	int i;
+	for (i = 0; i < 3; ++i) 
+	{
+		m_scene.getList(i).removeInterval(
+			m_interval[i].m_min.m_index,
+			m_interval[i].m_max.m_index,
+			proxies);
+	}
+}
+
+DT_Scalar BP_Proxy::getMin(int i) const 
+{ 
+	return m_scene.getList(i)[m_interval[i].m_min.m_index].getPos(); 
+}
+
+DT_Scalar BP_Proxy::getMax(int i) const 
+{ 
+	return m_scene.getList(i)[m_interval[i].m_max.m_index].getPos(); 
+}
+
+bool overlapXY(const BP_Proxy& a, const BP_Proxy& b)
+{
+	return a.getMin(0) <= b.getMax(0) && b.getMin(0) <= a.getMax(0) && 
+		   a.getMin(1) <= b.getMax(1) && b.getMin(1) <= a.getMax(1);
+}
+
+bool overlapXZ(const BP_Proxy& a, const BP_Proxy& b)
+{
+	return a.getMin(0) <= b.getMax(0) && b.getMin(0) <= a.getMax(0) && 
+		   a.getMin(2) <= b.getMax(2) && b.getMin(2) <= a.getMax(2); 
+}
+
+bool overlapYZ(const BP_Proxy& a, const BP_Proxy& b)
+{
+	return a.getMin(1) <= b.getMax(1) && b.getMin(1) <= a.getMax(1) && 
+		   a.getMin(2) <= b.getMax(2) && b.getMin(2) <= a.getMax(2); 
+}
+
+void BP_Proxy::setBBox(const DT_Vector3 min, const DT_Vector3 max)
+{	
+	static T_Overlap overlap[3] = { overlapYZ, overlapXZ, overlapXY };
+
+	int i;
+	for (i = 0; i < 3; ++i) 
+	{
+		if (min[i] > getMax(i)) 
+		{
+			m_scene.getList(i).move(m_interval[i].m_max.m_index, max[i], 
+									BP_Endpoint::MAXIMUM, m_scene, overlap[i]);
+			m_scene.getList(i).move(m_interval[i].m_min.m_index, min[i], 
+									BP_Endpoint::MINIMUM, m_scene, overlap[i]);
+		}
+		else 
+		{
+			m_scene.getList(i).move(m_interval[i].m_min.m_index, min[i], 
+									BP_Endpoint::MINIMUM, m_scene, overlap[i]);
+			m_scene.getList(i).move(m_interval[i].m_max.m_index, max[i], 
+									BP_Endpoint::MAXIMUM, m_scene, overlap[i]);
+		}
+	}
+}
+
+
+
diff --git a/extern/solid/src/broad/BP_Proxy.h b/extern/solid/src/broad/BP_Proxy.h
new file mode 100644
index 00000000000..b4500ddca44
--- /dev/null
+++ b/extern/solid/src/broad/BP_Proxy.h
@@ -0,0 +1,78 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef BP_PROXY_H
+#define BP_PROXY_H
+
+#include "BP_Endpoint.h"
+#include "BP_ProxyList.h"
+
+class BP_Interval {
+public:
+	BP_Interval() {}
+	BP_Interval(BP_Proxy *proxy) :
+		m_min(proxy),
+		m_max(proxy) 
+	{}
+
+	BP_Link m_min;
+	BP_Link m_max;
+};
+
+class BP_Scene;
+
+class BP_Proxy {
+public:
+    BP_Proxy(void *object, BP_Scene& scene);
+
+	void add(const DT_Vector3 min,
+			 const DT_Vector3 max,
+			 BP_ProxyList& proxies);
+	
+    void remove(BP_ProxyList& proxies);
+	
+	void setBBox(const DT_Vector3 min, const DT_Vector3 max);
+    
+    void *getObject() { return m_object; }
+
+	DT_Scalar getMin(int i) const;
+	DT_Scalar getMax(int i) const;
+
+private:
+	BP_Interval  m_interval[3];
+    void        *m_object;
+	BP_Scene&    m_scene;
+};
+
+inline bool BP_overlap(const BP_Proxy *a, const BP_Proxy *b)
+{
+	return a->getMin(0) <= b->getMax(0) && b->getMin(0) <= a->getMax(0) && 
+		   a->getMin(1) <= b->getMax(1) && b->getMin(1) <= a->getMax(1) &&
+		   a->getMin(2) <= b->getMax(2) && b->getMin(2) <= a->getMax(2);
+}
+
+#endif
+
+
+
+
diff --git a/extern/solid/src/broad/BP_ProxyList.h b/extern/solid/src/broad/BP_ProxyList.h
new file mode 100644
index 00000000000..2f449777d2d
--- /dev/null
+++ b/extern/solid/src/broad/BP_ProxyList.h
@@ -0,0 +1,69 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef BP_PROXYLIST_H
+#define BP_PROXYLIST_H
+
+#include 
+
+#include 
+#include 
+#include 
+
+class BP_Proxy;
+
+typedef std::pair BP_ProxyEntry; 
+
+inline bool operator<(const BP_ProxyEntry& a, const BP_ProxyEntry& b) 
+{
+	return a.first < b.first;
+}
+
+class BP_ProxyList : public std::vector {
+public:
+   BP_ProxyList(size_t n = 20) : std::vector(n) {}      
+
+	iterator add(BP_Proxy *proxy) 
+	{
+		BP_ProxyEntry entry = std::make_pair(proxy, (unsigned int)0);
+		iterator it = std::lower_bound(begin(), end(), entry);
+		if (it == end() || (*it).first != proxy) 
+		{
+			it = insert(it, entry);
+		}
+		++(*it).second;
+		return it;
+	}
+
+	void remove(BP_Proxy *proxy) 
+	{
+		BP_ProxyEntry entry = std::make_pair(proxy, (unsigned int)0);
+		iterator it = std::lower_bound(begin(), end(), entry);
+		if (it != end() && (*it).first == proxy && --(*it).second == 0) 
+		{
+			erase(it);	
+		}	
+	}
+};
+
+#endif
diff --git a/extern/solid/src/broad/BP_Scene.cpp b/extern/solid/src/broad/BP_Scene.cpp
new file mode 100644
index 00000000000..c0cd83ba311
--- /dev/null
+++ b/extern/solid/src/broad/BP_Scene.cpp
@@ -0,0 +1,151 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "BP_Scene.h"
+#include "BP_Proxy.h"
+
+#include 
+
+BP_Proxy *BP_Scene::createProxy(void *object, 
+								const DT_Vector3 min,
+								const DT_Vector3 max)
+{
+	BP_Proxy *proxy = new BP_Proxy(object, *this);
+
+	proxy->add(min, max, m_proxies);
+	
+	BP_ProxyList::iterator it;
+	for (it = m_proxies.begin(); it != m_proxies.end(); ++it)
+	{
+		if ((*it).second == 3)
+		{
+			callBeginOverlap(proxy->getObject(), (*it).first->getObject());
+		}
+	}
+
+	m_proxies.clear();
+
+	return proxy;
+}
+
+void BP_Scene::destroyProxy(BP_Proxy *proxy)
+{
+	proxy->remove(m_proxies);
+	
+	BP_ProxyList::iterator it;
+	for (it = m_proxies.begin(); it != m_proxies.end(); ++it)
+	{
+		if ((*it).second == 3)
+		{
+			callEndOverlap(proxy->getObject(), (*it).first->getObject());
+		}
+	}
+	
+	m_proxies.clear();
+
+	delete proxy;
+}
+
+void *BP_Scene::rayCast(BP_RayCastCallback objectRayCast,
+						void *client_data,
+						const DT_Vector3 source, 
+						const DT_Vector3 target, 
+						DT_Scalar& lambda) const 
+{
+	void *client_object = 0;
+	
+	DT_Index index[3];
+	index[0] = m_endpointList[0].stab(source[0], m_proxies);
+	index[1] = m_endpointList[1].stab(source[1], m_proxies);
+	index[2] = m_endpointList[2].stab(source[2], m_proxies);
+
+	BP_ProxyList::iterator it;
+	for (it = m_proxies.begin(); it != m_proxies.end(); ++it) 
+	{
+		if ((*it).second == 3 &&
+            (*objectRayCast)(client_data, (*it).first->getObject(), source, target, &lambda))
+		{
+			client_object = (*it).first->getObject();
+		}
+	}
+
+	DT_Vector3 delta;
+	delta[0] = target[0] - source[0];
+	delta[1] = target[1] - source[1];
+	delta[2] = target[2] - source[2];
+	
+	DT_Vector3 lambdas;
+	lambdas[0] = m_endpointList[0].nextLambda(index[0], source[0], delta[0]);
+	lambdas[1] = m_endpointList[1].nextLambda(index[1], source[1], delta[1]);
+	lambdas[2] = m_endpointList[2].nextLambda(index[2], source[2], delta[2]);
+	int closest = lambdas[0] < lambdas[1] ? (lambdas[0] < lambdas[2] ? 0 : 2) : (lambdas[1] < lambdas[2] ? 1 : 2);
+	
+	while (lambdas[closest] < lambda)
+	{
+		if (delta[closest] < 0.0f)
+		{
+			const BP_Endpoint& endpoint = m_endpointList[closest][index[closest]];
+
+			if (endpoint.getType() == BP_Endpoint::MAXIMUM) 
+			{
+				it = m_proxies.add(endpoint.getProxy());
+				if ((*it).second == 3 &&
+					(*objectRayCast)(client_data, (*it).first->getObject(), source, target, &lambda))
+				{
+					client_object = (*it).first->getObject();
+				}
+			}
+			else
+			{
+				m_proxies.remove(endpoint.getProxy());
+			}
+		}
+		else 
+		{
+			const BP_Endpoint& endpoint = m_endpointList[closest][index[closest] - 1];
+			
+			if (endpoint.getType() == BP_Endpoint::MINIMUM) 
+			{
+				it = m_proxies.add(endpoint.getProxy());
+				if ((*it).second == 3 &&
+					(*objectRayCast)(client_data, (*it).first->getObject(), source, target, &lambda))
+				{
+					client_object = (*it).first->getObject();
+				}
+			}
+			else
+			{
+				m_proxies.remove(endpoint.getProxy());
+			}
+		}
+
+		lambdas[closest] = m_endpointList[closest].nextLambda(index[closest], source[closest], delta[closest]);
+		closest = lambdas[0] < lambdas[1] ?	(lambdas[0] < lambdas[2] ? 0 : 2) : (lambdas[1] < lambdas[2] ? 1 : 2);
+	}
+
+	m_proxies.clear();
+
+	return client_object;
+}
+
+
diff --git a/extern/solid/src/broad/BP_Scene.h b/extern/solid/src/broad/BP_Scene.h
new file mode 100644
index 00000000000..ef55374c43b
--- /dev/null
+++ b/extern/solid/src/broad/BP_Scene.h
@@ -0,0 +1,79 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef BP_SCENE_H
+#define BP_SCENE_H
+
+#include 
+
+#include "BP_EndpointList.h"
+#include "BP_ProxyList.h"
+
+class BP_Proxy;
+
+class BP_Scene {
+public:
+    BP_Scene(void *client_data,
+			 BP_Callback beginOverlap,
+			 BP_Callback endOverlap) 
+      :	m_client_data(client_data),
+		m_beginOverlap(beginOverlap),
+		m_endOverlap(endOverlap),
+		m_proxies(20)
+	{}
+
+    ~BP_Scene() {}
+
+    BP_Proxy *createProxy(void *object, 
+						  const DT_Vector3 min,
+						  const DT_Vector3 max);
+
+    void destroyProxy(BP_Proxy *proxy);
+	
+	void *rayCast(BP_RayCastCallback objectRayCast,
+				  void *client_data,
+				  const DT_Vector3 source, 
+				  const DT_Vector3 target, 
+				  DT_Scalar& lambda) const;
+	
+  	void callBeginOverlap(void *object1, void *object2) 
+	{
+		(*m_beginOverlap)(m_client_data, object1, object2);
+	}
+	
+	void callEndOverlap(void *object1, void *object2) 
+	{
+		(*m_endOverlap)(m_client_data, object1, object2);
+	}
+	
+	BP_EndpointList& getList(int i) { return m_endpointList[i]; }
+
+private:
+	void                    *m_client_data;
+	BP_Callback              m_beginOverlap; 
+	BP_Callback              m_endOverlap; 
+    BP_EndpointList          m_endpointList[3];
+	mutable BP_ProxyList     m_proxies;
+};
+
+#endif
diff --git a/extern/solid/src/broad/Makefile b/extern/solid/src/broad/Makefile
new file mode 100644
index 00000000000..90445c3cd7a
--- /dev/null
+++ b/extern/solid/src/broad/Makefile
@@ -0,0 +1,44 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# 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. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License.  See http://www.blender.org/BL/ for information
+# about this.
+#
+# 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.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = solid_broad
+DIR = $(OCGDIR)/extern/$(LIBNAME)
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I../../include -I$(NAN_QHULL)/include
+CPPFLAGS += -DQHULL -DUSE_DOUBLES
+
+include nan_compile.mk 
+
+
diff --git a/extern/solid/src/complex/DT_BBoxTree.cpp b/extern/solid/src/complex/DT_BBoxTree.cpp
new file mode 100644
index 00000000000..4f10f61f2e2
--- /dev/null
+++ b/extern/solid/src/complex/DT_BBoxTree.cpp
@@ -0,0 +1,90 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_BBoxTree.h"
+
+inline DT_CBox getBBox(int first, int last, const DT_CBox *boxes, const DT_Index *indices) 
+{
+	assert(last - first >= 1);
+
+	DT_CBox bbox = boxes[indices[first]];
+	int i;
+	for (i = first; i < last; ++i) 
+	{
+		bbox = bbox.hull(boxes[indices[i]]);
+	}
+
+	return bbox;
+}
+
+DT_BBoxNode::DT_BBoxNode(int first, int last, int& node, DT_BBoxNode *free_nodes, const DT_CBox *boxes, DT_Index *indices, const DT_CBox& bbox)
+{
+	assert(last - first >= 2);
+	
+	int axis = bbox.longestAxis();
+	MT_Scalar abscissa = bbox.getCenter()[axis];
+	int i = first, mid = last;
+	while (i < mid) 
+	{
+		if (boxes[indices[i]].getCenter()[axis] < abscissa)
+		{
+			++i;
+		}
+		else
+		{
+			--mid;
+			std::swap(indices[i], indices[mid]);
+		}
+	}
+
+	if (mid == first || mid == last) 
+	{
+		mid = (first + last) / 2;
+	}
+	
+	m_lbox = getBBox(first, mid, boxes, indices);
+	m_rbox = getBBox(mid, last, boxes, indices);
+	m_flags = 0x0;
+
+	if (mid - first == 1)
+	{
+		m_flags |= LLEAF;
+		m_lchild = indices[first];
+	}
+	else 
+	{	
+		m_lchild = node++;
+		new(&free_nodes[m_lchild]) DT_BBoxNode(first, mid, node, free_nodes, boxes, indices, m_lbox);
+	}
+
+	if (last - mid == 1)
+	{
+		m_flags |= RLEAF;
+		m_rchild = indices[mid];
+	}
+	else 
+	{
+		m_rchild = node++;
+		new(&free_nodes[m_rchild]) DT_BBoxNode(mid, last, node, free_nodes, boxes, indices, m_rbox); 
+	}
+}
diff --git a/extern/solid/src/complex/DT_BBoxTree.h b/extern/solid/src/complex/DT_BBoxTree.h
new file mode 100644
index 00000000000..3d9da6e34ba
--- /dev/null
+++ b/extern/solid/src/complex/DT_BBoxTree.h
@@ -0,0 +1,540 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_BBOXTREE_H
+#define DT_BBOXTREE_H
+
+#include 
+#include 
+
+#include "DT_Convex.h"
+#include "DT_CBox.h"
+
+
+class DT_BBoxTree {
+public:
+    enum NodeType { INTERNAL = 0, LEAF = 1 };
+    
+    DT_BBoxTree() {}
+    DT_BBoxTree(const DT_CBox& cbox, DT_Index index, NodeType type) 
+      : m_cbox(cbox),
+        m_index(index),
+        m_type(type)
+    {}
+    
+    DT_CBox  m_cbox;
+    DT_Index m_index;
+    NodeType m_type;
+};
+
+
+
+class DT_BBoxNode {
+public:
+    DT_BBoxNode() {}    
+    DT_BBoxNode(int first, int last, int& node, DT_BBoxNode *free_nodes, const DT_CBox *boxes, DT_Index *indices, const DT_CBox& bbox);
+
+    void makeChildren(DT_BBoxTree& ltree, DT_BBoxTree& rtree) const;
+    void makeChildren(const DT_CBox& added, DT_BBoxTree& ltree, DT_BBoxTree& rtree) const;
+
+    DT_CBox hull() const { return m_lbox.hull(m_rbox); }  
+    
+    enum FlagType { LLEAF = 0x80, RLEAF = 0x40 };
+
+    DT_CBox              m_lbox;
+    DT_CBox              m_rbox;
+    DT_Index             m_lchild;
+    DT_Index             m_rchild;
+    unsigned char        m_flags;
+};
+
+inline void DT_BBoxNode::makeChildren(DT_BBoxTree& ltree, DT_BBoxTree& rtree) const
+{
+    new (<ree) DT_BBoxTree(m_lbox, m_lchild, (m_flags & LLEAF) ? DT_BBoxTree::LEAF : DT_BBoxTree::INTERNAL);
+    new (&rtree) DT_BBoxTree(m_rbox, m_rchild, (m_flags & RLEAF) ? DT_BBoxTree::LEAF : DT_BBoxTree::INTERNAL);
+
+}
+
+inline void DT_BBoxNode::makeChildren(const DT_CBox& added, DT_BBoxTree& ltree, DT_BBoxTree& rtree) const
+{ 
+    new (<ree) DT_BBoxTree(m_lbox + added, m_lchild, (m_flags & LLEAF) ? DT_BBoxTree::LEAF : DT_BBoxTree::INTERNAL);
+    new (&rtree) DT_BBoxTree(m_rbox + added, m_rchild, (m_flags & RLEAF) ? DT_BBoxTree::LEAF : DT_BBoxTree::INTERNAL);
+}
+
+
+template 
+class DT_RootData {
+public:
+    DT_RootData(const DT_BBoxNode *nodes, 
+                const Shape *leaves) 
+      : m_nodes(nodes),
+        m_leaves(leaves)
+    {}
+
+    const DT_BBoxNode   *m_nodes;
+    const Shape         *m_leaves;
+};
+
+template 
+class DT_ObjectData : public DT_RootData {
+public:
+    DT_ObjectData(const DT_BBoxNode *nodes, 
+                  const Shape1 *leaves, 
+                  const MT_Transform& xform, 
+                  Shape2 plus) 
+      : DT_RootData(nodes, leaves),
+        m_xform(xform),
+        m_inv_xform(xform.inverse()),   
+        m_plus(plus),
+        m_added(computeCBox(plus, m_inv_xform))
+    {}
+
+    const MT_Transform&  m_xform;
+    MT_Transform         m_inv_xform;
+    Shape2               m_plus;
+    DT_CBox              m_added;
+};
+
+template 
+class DT_Pack {
+public:
+    DT_Pack(const DT_ObjectData& a, const DT_Convex& b)
+      : m_a(a),
+        m_b(b),
+        m_b_cbox(b.bbox(m_a.m_inv_xform))
+    {}
+    
+    DT_ObjectData  m_a;
+    const DT_Convex&               m_b;
+    DT_CBox                        m_b_cbox;
+};
+
+template 
+class DT_HybridPack : public DT_Pack {
+public:
+    DT_HybridPack(const DT_ObjectData& a, const DT_Convex& b, MT_Scalar margin)
+      : DT_Pack(a, b),
+        m_margin(margin)
+    {
+        this->m_b_cbox += computeCBox(margin, this->m_a.m_inv_xform);
+    }
+    
+    MT_Scalar m_margin;
+};
+
+template 
+class DT_DuoPack {
+public:
+    DT_DuoPack(const DT_ObjectData& a, const DT_ObjectData& b) 
+      : m_a(a),
+        m_b(b)
+    {
+        m_b2a = a.m_inv_xform * b.m_xform;
+        m_a2b = b.m_inv_xform * a.m_xform;
+        m_abs_b2a = m_b2a.getBasis().absolute();
+        m_abs_a2b = m_a2b.getBasis().absolute();    
+    }
+    
+    DT_ObjectData  m_a, m_b;
+    MT_Transform                   m_b2a, m_a2b;
+    MT_Matrix3x3                   m_abs_b2a, m_abs_a2b;
+};
+
+
+template 
+inline void refit(DT_BBoxNode& node, const DT_RootData& rd)
+{
+    node.m_lbox = (node.m_flags & DT_BBoxNode::LLEAF) ? 
+                  computeCBox(rd.m_leaves[node.m_lchild]) : 
+                  rd.m_nodes[node.m_lchild].hull(); 
+    node.m_rbox = (node.m_flags & DT_BBoxNode::RLEAF) ? 
+                  computeCBox(rd.m_leaves[node.m_rchild]) : 
+                  rd.m_nodes[node.m_rchild].hull(); 
+}
+
+
+template 
+bool ray_cast(const DT_BBoxTree& a, const DT_RootData& rd,
+              const MT_Point3& source, const MT_Point3& target, 
+              MT_Scalar& lambda, MT_Vector3& normal) 
+{
+    if (!a.m_cbox.overlapsLineSegment(source, source.lerp(target, lambda))) 
+    {
+        return false;
+    }
+
+    if (a.m_type == DT_BBoxTree::LEAF) 
+    { 
+        return ray_cast(rd, a.m_index, source, target, lambda, normal); 
+    }
+    else 
+    {
+        DT_BBoxTree ltree, rtree;
+        rd.m_nodes[a.m_index].makeChildren(ltree, rtree);
+        
+        bool lresult = ray_cast(ltree, rd, source, target, lambda, normal);
+        bool rresult = ray_cast(rtree, rd, source, target, lambda, normal);
+        return lresult || rresult;
+    }
+}
+
+
+#ifdef STATISTICS
+int num_box_tests = 0;
+#endif
+
+template 
+inline bool intersect(const DT_CBox& a, const DT_CBox& b, const DT_DuoPack& pack)
+{
+#ifdef STATISTICS
+    ++num_box_tests;
+#endif
+
+    
+    MT_Vector3 abs_pos_b2a = (pack.m_b2a(b.getCenter()) - a.getCenter()).absolute();
+    MT_Vector3 abs_pos_a2b = (pack.m_a2b(a.getCenter()) - b.getCenter()).absolute();
+    return  (a.getExtent()[0] + pack.m_abs_b2a[0].dot(b.getExtent()) >=  abs_pos_b2a[0]) && 
+            (a.getExtent()[1] + pack.m_abs_b2a[1].dot(b.getExtent()) >=  abs_pos_b2a[1]) && 
+            (a.getExtent()[2] + pack.m_abs_b2a[2].dot(b.getExtent()) >=  abs_pos_b2a[2]) && 
+            (b.getExtent()[0] + pack.m_abs_a2b[0].dot(a.getExtent()) >=  abs_pos_a2b[0]) && 
+            (b.getExtent()[1] + pack.m_abs_a2b[1].dot(a.getExtent()) >=  abs_pos_a2b[1]) &&
+            (b.getExtent()[2] + pack.m_abs_a2b[2].dot(a.getExtent()) >=  abs_pos_a2b[2]);
+}
+
+
+
+
+template 
+bool intersect(const DT_BBoxTree& a, const DT_Pack& pack, MT_Vector3& v)
+{ 
+    if (!a.m_cbox.overlaps(pack.m_b_cbox)) 
+    {
+        return false;
+    }
+
+    if (a.m_type == DT_BBoxTree::LEAF) 
+    {
+        return intersect(pack, a.m_index, v);
+    }
+    else 
+    {
+        DT_BBoxTree a_ltree, a_rtree;
+        pack.m_a.m_nodes[a.m_index].makeChildren(pack.m_a.m_added, a_ltree, a_rtree);
+        return intersect(a_ltree, pack, v) || intersect(a_rtree, pack, v);
+    }
+}
+
+template 
+bool intersect(const DT_BBoxTree& a, const DT_BBoxTree& b, const DT_DuoPack& pack, MT_Vector3& v)
+{ 
+    if (!intersect(a.m_cbox, b.m_cbox, pack)) 
+    {
+        return false;
+    }
+
+    if (a.m_type == DT_BBoxTree::LEAF && b.m_type == DT_BBoxTree::LEAF) 
+    {
+        return intersect(pack, a.m_index, b.m_index, v);
+    }
+    else if (a.m_type == DT_BBoxTree::LEAF || 
+             (b.m_type != DT_BBoxTree::LEAF && a.m_cbox.size() < b.m_cbox.size())) 
+    {
+        DT_BBoxTree b_ltree, b_rtree;
+        pack.m_b.m_nodes[b.m_index].makeChildren(pack.m_b.m_added, b_ltree, b_rtree);
+
+        return intersect(a, b_ltree, pack, v) || intersect(a, b_rtree, pack, v);
+    }
+    else 
+    {
+        DT_BBoxTree a_ltree, a_rtree;
+        pack.m_a.m_nodes[a.m_index].makeChildren(pack.m_a.m_added, a_ltree, a_rtree);
+        return intersect(a_ltree, b, pack, v) || intersect(a_rtree, b, pack, v);
+    }
+}
+
+template 
+bool common_point(const DT_BBoxTree& a, const DT_Pack& pack,  
+                  MT_Vector3& v, MT_Point3& pa, MT_Point3& pb)
+{ 
+    if (!a.m_cbox.overlaps(pack.m_b_cbox))
+    {
+        return false;
+    }
+
+    if (a.m_type == DT_BBoxTree::LEAF) 
+    {
+        return common_point(pack, a.m_index, v, pa, pb);
+    }
+    else 
+    {
+        DT_BBoxTree a_ltree, a_rtree;
+        pack.m_a.m_nodes[a.m_index].makeChildren(pack.m_a.m_added, a_ltree, a_rtree);
+        return common_point(a_ltree, pack, v, pa, pb) ||
+               common_point(a_rtree, pack, v, pa ,pb);
+    }
+}
+
+template 
+bool common_point(const DT_BBoxTree& a, const DT_BBoxTree& b, const DT_DuoPack& pack,  
+                  MT_Vector3& v, MT_Point3& pa, MT_Point3& pb)
+{ 
+    if (!intersect(a.m_cbox, b.m_cbox, pack))
+    {
+        return false;
+    }
+
+    if (a.m_type == DT_BBoxTree::LEAF && b.m_type == DT_BBoxTree::LEAF) 
+    {
+        return common_point(pack, a.m_index, b.m_index, v, pa, pb);
+    }
+    else if (a.m_type == DT_BBoxTree::LEAF || 
+             (b.m_type != DT_BBoxTree::LEAF && a.m_cbox.size() < b.m_cbox.size())) 
+    {
+        DT_BBoxTree b_ltree, b_rtree;
+        pack.m_b.m_nodes[b.m_index].makeChildren(pack.m_b.m_added, b_ltree, b_rtree);
+        return common_point(a, b_ltree, pack, v, pa, pb) ||
+               common_point(a, b_rtree, pack, v, pa, pb);
+    }
+    else 
+    {
+        DT_BBoxTree a_ltree, a_rtree;
+        pack.m_a.m_nodes[a.m_index].makeChildren(pack.m_a.m_added, a_ltree, a_rtree);
+        return common_point(a_ltree, b, pack, v, pa, pb) ||
+               common_point(a_rtree, b, pack, v, pa ,pb);
+    }
+}
+
+
+template 
+bool penetration_depth(const DT_BBoxTree& a, const DT_HybridPack& pack, 
+                       MT_Vector3& v, MT_Point3& pa, MT_Point3& pb, MT_Scalar& max_pen_len) 
+{ 
+    if (!a.m_cbox.overlaps(pack.m_b_cbox))
+    {
+        return false;
+    }
+    
+    if (a.m_type == DT_BBoxTree::LEAF) 
+    {
+        if (penetration_depth(pack, a.m_index, v, pa, pb))
+        {
+            max_pen_len = pa.distance2(pb);
+            return true;
+        }
+        else 
+        {
+            return false;
+        }
+    }
+    else 
+    {
+        DT_BBoxTree a_ltree, a_rtree;
+        pack.m_a.m_nodes[a.m_index].makeChildren(pack.m_a.m_added, a_ltree, a_rtree);
+        if (penetration_depth(a_ltree, pack, v, pa, pb, max_pen_len)) 
+        {
+            MT_Vector3 rv;
+            MT_Point3 rpa, rpb;
+            MT_Scalar rmax_pen_len;
+            if (penetration_depth(a_rtree, pack, rv, rpa, rpb, rmax_pen_len) &&
+                (max_pen_len < rmax_pen_len))
+            {
+                max_pen_len = rmax_pen_len;
+                v = rv;
+                pa = rpa;
+                pb = rpb;
+            }
+            return true;
+        }
+        else 
+        {
+            return penetration_depth(a_rtree, pack, v, pa, pb, max_pen_len);
+        }
+    }
+}
+
+template 
+bool penetration_depth(const DT_BBoxTree& a, const DT_BBoxTree& b, const DT_DuoPack& pack, 
+                       MT_Vector3& v, MT_Point3& pa, MT_Point3& pb, MT_Scalar& max_pen_len) 
+{ 
+    if (!intersect(a.m_cbox, b.m_cbox, pack))
+    {
+        return false;
+    }
+  
+    if (a.m_type == DT_BBoxTree::LEAF && b.m_type == DT_BBoxTree::LEAF) 
+    {
+        if (penetration_depth(pack, a.m_index, b.m_index, v, pa, pb))
+        {
+            max_pen_len = pa.distance2(pb);
+            return true;
+        }
+        else 
+        {
+            return false;
+        }
+    }
+    else if (a.m_type == DT_BBoxTree::LEAF || 
+             (b.m_type != DT_BBoxTree::LEAF && a.m_cbox.size() < b.m_cbox.size())) 
+    {
+        DT_BBoxTree b_ltree, b_rtree;
+        pack.m_b.m_nodes[b.m_index].makeChildren(pack.m_b.m_added, b_ltree, b_rtree);
+        if (penetration_depth(a, b_ltree, pack, v, pa, pb, max_pen_len)) 
+        {
+            MT_Point3 rpa, rpb;
+            MT_Scalar rmax_pen_len;
+            if (penetration_depth(a, b_rtree, pack, v, rpa, rpb, rmax_pen_len) &&
+                (max_pen_len < rmax_pen_len))
+            {
+                max_pen_len = rmax_pen_len;
+                pa = rpa;
+                pb = rpb;
+            }
+            return true;
+        }
+        else
+        {
+            return penetration_depth(a, b_rtree, pack, v, pa, pb, max_pen_len);
+        }
+    }
+    else 
+    {
+        DT_BBoxTree a_ltree, a_rtree;
+        pack.m_a.m_nodes[a.m_index].makeChildren(pack.m_a.m_added, a_ltree, a_rtree);
+        if (penetration_depth(a_ltree, b, pack, v, pa, pb, max_pen_len)) 
+        {
+            MT_Point3 rpa, rpb;
+            MT_Scalar rmax_pen_len;
+            if (penetration_depth(a_rtree, b, pack, v, rpa, rpb, rmax_pen_len) &&
+                (max_pen_len < rmax_pen_len))
+            {
+                max_pen_len = rmax_pen_len;
+                pa = rpa;
+                pb = rpb;
+            }
+            return true;
+        }
+        else 
+        {
+            return penetration_depth(a_rtree, b, pack, v, pa, pb, max_pen_len);
+        }
+    }
+}
+
+
+// Returns a lower bound for the distance for quick rejection in closest_points
+inline MT_Scalar distance2(const DT_CBox& a, const MT_Transform& a2w,
+                           const DT_CBox& b, const MT_Transform& b2w)
+{
+    MT_Vector3 v = b2w(b.getCenter()) - a2w(a.getCenter());
+    MT_Scalar dist2 = v.length2();
+    if (dist2 > MT_Scalar(0.0))
+    {
+        MT_Vector3 w = b2w(b.support(-v * b2w.getBasis())) - a2w(a.support(v * a2w.getBasis()));
+        MT_Scalar delta = v.dot(w);
+        return delta > MT_Scalar(0.0) ? delta * delta / dist2 : MT_Scalar(0.0);
+    }
+    return MT_Scalar(0.0);
+}
+
+
+template 
+MT_Scalar closest_points(const DT_BBoxTree& a, const DT_Pack& pack, 
+                         MT_Scalar max_dist2, MT_Point3& pa, MT_Point3& pb) 
+{ 
+    if (a.m_type == DT_BBoxTree::LEAF) 
+    {
+        return closest_points(pack, a.m_index, max_dist2, pa, pb);
+    }
+    else 
+    {
+        DT_BBoxTree a_ltree, a_rtree;
+        pack.m_a.m_nodes[a.m_index].makeChildren(pack.m_a.m_added, a_ltree, a_rtree);
+        MT_Scalar ldist2 = distance2(a_ltree.m_cbox, pack.m_a.m_xform, pack.m_b_cbox, pack.m_a.m_xform);
+        MT_Scalar rdist2 = distance2(a_rtree.m_cbox, pack.m_a.m_xform, pack.m_b_cbox, pack.m_a.m_xform);
+        if (ldist2 < rdist2) 
+        {
+            MT_Scalar dist2 = ldist2 < max_dist2 ? closest_points(a_ltree, pack, max_dist2, pa, pb) : MT_INFINITY;
+            GEN_set_min(max_dist2, dist2);
+            return rdist2 < max_dist2 ? GEN_min(dist2, closest_points(a_rtree, pack, max_dist2, pa, pb)) : dist2;
+        }
+        else
+        {
+            MT_Scalar dist2 = rdist2 < max_dist2 ? closest_points(a_rtree, pack, max_dist2, pa, pb) : MT_INFINITY;
+            GEN_set_min(max_dist2, dist2);  
+            return ldist2 < max_dist2 ? GEN_min(dist2, closest_points(a_ltree, pack, max_dist2, pa, pb)) : dist2;       
+        }
+    }
+}
+
+    
+template 
+MT_Scalar closest_points(const DT_BBoxTree& a, const DT_BBoxTree& b, const DT_DuoPack& pack, 
+                         MT_Scalar max_dist2, MT_Point3& pa, MT_Point3& pb) 
+{   
+    if (a.m_type == DT_BBoxTree::LEAF && b.m_type == DT_BBoxTree::LEAF) 
+    {
+        return closest_points(pack, a.m_index, b.m_index, max_dist2, pa, pb);
+    }
+    else if (a.m_type == DT_BBoxTree::LEAF || 
+             (b.m_type != DT_BBoxTree::LEAF && a.m_cbox.size() < b.m_cbox.size())) 
+    {
+        DT_BBoxTree b_ltree, b_rtree;
+        pack.m_b.m_nodes[b.m_index].makeChildren(pack.m_b.m_added, b_ltree, b_rtree);
+        MT_Scalar ldist2 = distance2(a.m_cbox, pack.m_a.m_xform, b_ltree.m_cbox, pack.m_b.m_xform);
+        MT_Scalar rdist2 = distance2(a.m_cbox, pack.m_a.m_xform, b_rtree.m_cbox, pack.m_b.m_xform);
+        if (ldist2 < rdist2)
+        {
+            MT_Scalar dist2 = ldist2 < max_dist2 ? closest_points(a, b_ltree, pack, max_dist2, pa, pb): MT_INFINITY;;
+            GEN_set_min(max_dist2, dist2);
+            return rdist2 < max_dist2 ? GEN_min(dist2, closest_points(a, b_rtree, pack, max_dist2, pa, pb)) : dist2;        
+        }
+        else
+        {
+            MT_Scalar dist2 =  rdist2 < max_dist2 ? closest_points(a, b_rtree, pack, max_dist2, pa, pb) : MT_INFINITY;;
+            GEN_set_min(max_dist2, dist2);
+            return ldist2 < max_dist2 ? GEN_min(dist2, closest_points(a, b_ltree, pack, max_dist2, pa, pb)) : dist2;
+        }
+    }
+    else
+    {
+        DT_BBoxTree a_ltree, a_rtree;
+        pack.m_a.m_nodes[a.m_index].makeChildren(pack.m_a.m_added, a_ltree, a_rtree);
+        MT_Scalar ldist2 = distance2(a_ltree.m_cbox, pack.m_a.m_xform, b.m_cbox, pack.m_b.m_xform);
+        MT_Scalar rdist2 = distance2(a_rtree.m_cbox, pack.m_a.m_xform, b.m_cbox, pack.m_b.m_xform);
+        if (ldist2 < rdist2) 
+        {
+            MT_Scalar dist2 = ldist2 < max_dist2 ? closest_points(a_ltree, b, pack, max_dist2, pa, pb) : MT_INFINITY;;
+            GEN_set_min(max_dist2, dist2);
+            return rdist2 < max_dist2 ? GEN_min(dist2,closest_points(a_rtree, b, pack, max_dist2, pa, pb)) : dist2;
+        }
+        else
+        {
+            MT_Scalar dist2 = rdist2 < max_dist2 ? closest_points(a_rtree, b, pack, max_dist2, pa, pb) : MT_INFINITY;
+            GEN_set_min(max_dist2, dist2);
+            return ldist2 < max_dist2 ? GEN_min(dist2, closest_points(a_ltree, b, pack, max_dist2, pa, pb)) : dist2;
+        }
+    }
+}
+
+#endif
+
diff --git a/extern/solid/src/complex/DT_CBox.h b/extern/solid/src/complex/DT_CBox.h
new file mode 100644
index 00000000000..7fc7c5df4db
--- /dev/null
+++ b/extern/solid/src/complex/DT_CBox.h
@@ -0,0 +1,134 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_CBOX_H
+#define DT_CBOX_H
+
+#include "MT_BBox.h"
+
+struct DT_CBox {
+    DT_CBox() {}
+    DT_CBox(const MT_Point3& center, const MT_Vector3& extent) 
+      : m_center(center),
+        m_extent(extent)
+    {}
+
+    explicit DT_CBox(const MT_BBox& bbox) { set(bbox); }
+
+    const MT_Point3& getCenter() const { return m_center; }
+    const MT_Vector3& getExtent() const { return m_extent; }
+
+    void set(const MT_BBox& bbox)
+    {
+        m_center = bbox.getCenter();
+        m_extent = bbox.getExtent();
+    }
+ 
+    MT_BBox get() const
+    {
+        return MT_BBox(m_center - m_extent, m_center + m_extent);
+    }
+
+    MT_Scalar size() const  
+    {
+        return GEN_max(GEN_max(m_extent[0], m_extent[1]), m_extent[2]);
+    }
+
+
+    DT_CBox& operator+=(const DT_CBox& box)
+    {
+        m_center += box.getCenter();
+        m_extent += box.getExtent();
+        return *this;
+    }
+    
+    int longestAxis() const { return m_extent.closestAxis(); }
+        
+    DT_CBox hull(const DT_CBox& b) const 
+    {
+        return DT_CBox(this->get().hull(b.get()));
+    }
+
+    bool overlaps(const DT_CBox& b) const 
+    {
+        return MT_abs(m_center[0] - b.m_center[0]) <= m_extent[0] + b.m_extent[0] &&
+               MT_abs(m_center[1] - b.m_center[1]) <= m_extent[1] + b.m_extent[1] &&
+               MT_abs(m_center[2] - b.m_center[2]) <= m_extent[2] + b.m_extent[2];
+    }
+    
+    bool overlapsLineSegment(const MT_Point3& p, const MT_Point3& q) const 
+    {
+        MT_Vector3 r = q - p;   
+        MT_Vector3 r_abs = r.absolute();
+        
+        if (!overlaps(DT_CBox(p + r * MT_Scalar(0.5), r_abs * MT_Scalar(0.5))))
+        {
+            return false;
+        }
+        
+        MT_Vector3 s = p - m_center;
+
+        if (MT_abs(r[2] * s[1] - r[1] * s[2]) > r_abs[2] * m_extent[1] + r_abs[1] * m_extent[2])
+        {
+            return false;
+        }
+                    
+        if (MT_abs(r[0] * s[2] - r[2] * s[0]) > r_abs[0] * m_extent[2] + r_abs[2] * m_extent[0])
+        {
+            return false;
+        }
+                    
+        if (MT_abs(r[1] * s[0] - r[0] * s[1]) > r_abs[1] * m_extent[0] + r_abs[0] * m_extent[1])
+        {
+            return false;
+        }
+            
+        return true;
+    }
+    
+    MT_Point3 support(const MT_Vector3& v) const 
+    {
+        return m_center + MT_Vector3(v[0] < MT_Scalar(0.0) ? -m_extent[0] : m_extent[0],
+                                     v[1] < MT_Scalar(0.0) ? -m_extent[1] : m_extent[1],
+                                     v[2] < MT_Scalar(0.0) ? -m_extent[2] : m_extent[2]); 
+    
+    }
+
+private:
+    MT_Point3  m_center;
+    MT_Vector3 m_extent;
+};
+
+inline DT_CBox operator+(const DT_CBox& b1, const DT_CBox& b2) 
+{
+    return DT_CBox(b1.getCenter() + b2.getCenter(), 
+                   b1.getExtent() + b2.getExtent());
+}
+
+inline DT_CBox operator-(const DT_CBox& b1, const DT_CBox& b2) 
+{
+    return DT_CBox(b1.getCenter() - b2.getCenter(), 
+                   b1.getExtent() + b2.getExtent());
+}
+
+#endif
diff --git a/extern/solid/src/complex/DT_Complex.cpp b/extern/solid/src/complex/DT_Complex.cpp
new file mode 100644
index 00000000000..023383a8427
--- /dev/null
+++ b/extern/solid/src/complex/DT_Complex.cpp
@@ -0,0 +1,327 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include 
+#include 
+
+#include "DT_Complex.h"
+#include "DT_Minkowski.h"
+#include "DT_Sphere.h"
+#include "DT_Transform.h"
+
+DT_Complex::DT_Complex(const DT_VertexBase *base) 
+  : m_base(base),
+    m_count(0),
+    m_leaves(0),
+	m_nodes(0)
+{ 
+	assert(base);
+	base->addComplex(this);
+}
+
+
+DT_Complex::~DT_Complex()
+{
+    DT_Index i;
+    for (i = 0; i != m_count; ++i) 
+    {
+        delete m_leaves[i];
+    }
+    delete [] m_leaves;
+    delete [] m_nodes;
+    
+    m_base->removeComplex(this);
+    if (m_base->isOwner()) 
+    {
+        delete m_base;
+    }
+}
+
+void DT_Complex::finish(DT_Count n, const DT_Convex *p[]) 
+{
+	m_count = n;
+
+   
+    assert(n >= 1);
+
+    m_leaves = new const DT_Convex *[n];
+    assert(m_leaves);
+
+    DT_CBox *boxes = new DT_CBox[n];
+    DT_Index *indices = new DT_Index[n];
+    assert(boxes);
+       
+    DT_Index i;
+    for (i = 0; i != n; ++i) 
+    {
+        m_leaves[i] = p[i];
+        boxes[i].set(p[i]->bbox());
+        indices[i] = i;
+    }
+
+    m_cbox = boxes[0];
+    for (i = 1; i != n; ++i) 
+    {
+        m_cbox = m_cbox.hull(boxes[i]);
+    }
+
+    if (n == 1)
+    {
+        m_nodes = 0;
+        m_type = DT_BBoxTree::LEAF;
+    }
+    else 
+    {
+        m_nodes = new DT_BBoxNode[n - 1];
+        assert(m_nodes);
+    
+        int num_nodes = 0;
+        new(&m_nodes[num_nodes++]) DT_BBoxNode(0, n, num_nodes, m_nodes, boxes, indices, m_cbox);
+
+        assert(num_nodes == n - 1);
+        
+        m_type = DT_BBoxTree::INTERNAL;
+    }
+
+    delete [] boxes;
+}
+
+
+MT_BBox DT_Complex::bbox(const MT_Transform& t, MT_Scalar margin) const 
+{
+    MT_Matrix3x3 abs_b = t.getBasis().absolute();  
+    MT_Point3 center = t(m_cbox.getCenter());
+    MT_Vector3 extent(margin + abs_b[0].dot(m_cbox.getExtent()),
+                      margin + abs_b[1].dot(m_cbox.getExtent()),
+                      margin + abs_b[2].dot(m_cbox.getExtent()));
+    
+    return MT_BBox(center - extent, center + extent);
+}
+
+inline DT_CBox computeCBox(const DT_Convex *p)
+{
+    return DT_CBox(p->bbox()); 
+}
+
+inline DT_CBox computeCBox(MT_Scalar margin, const MT_Transform& xform) 
+{
+    const MT_Matrix3x3& basis = xform.getBasis();
+    return DT_CBox(MT_Point3(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0)), 
+                   MT_Vector3(basis[0].length() * margin, 
+                              basis[1].length() * margin, 
+                              basis[2].length() * margin));
+} 
+
+void DT_Complex::refit()
+{
+    DT_RootData rd(m_nodes, m_leaves);
+    DT_Index i = m_count - 1;
+    while (i--)
+    {
+        ::refit(m_nodes[i], rd);
+    }
+    m_cbox = m_type == DT_BBoxTree::LEAF ? computeCBox(m_leaves[0]) : m_nodes[0].hull();
+}
+
+inline bool ray_cast(const DT_RootData& rd, DT_Index index, const MT_Point3& source, const MT_Point3& target, 
+                     MT_Scalar& lambda, MT_Vector3& normal)
+{
+    return rd.m_leaves[index]->ray_cast(source, target, lambda, normal);
+}
+
+bool DT_Complex::ray_cast(const MT_Point3& source, const MT_Point3& target,
+                          MT_Scalar& lambda, MT_Vector3& normal) const 
+{
+    DT_RootData rd(m_nodes, m_leaves);
+
+    return ::ray_cast(DT_BBoxTree(m_cbox, 0, m_type), rd, source, target, lambda, normal);
+}
+
+inline bool intersect(const DT_Pack& pack, DT_Index a_index, MT_Vector3& v) 
+{
+    DT_Transform ta = DT_Transform(pack.m_a.m_xform, *pack.m_a.m_leaves[a_index]);
+    MT_Scalar a_margin = pack.m_a.m_plus;
+    return ::intersect((a_margin > MT_Scalar(0.0) ? 
+                        static_cast(DT_Minkowski(ta, DT_Sphere(a_margin))) :  
+                        static_cast(ta)), 
+                       pack.m_b, v); 
+}
+
+bool intersect(const DT_Complex& a,  const MT_Transform& a2w,  MT_Scalar a_margin, 
+               const DT_Convex& b, MT_Vector3& v) 
+{
+    DT_Pack pack(DT_ObjectData(a.m_nodes, a.m_leaves, a2w, a_margin), b);
+
+    return intersect(DT_BBoxTree(a.m_cbox + pack.m_a.m_added, 0, a.m_type), pack, v);
+}
+
+inline bool intersect(const DT_DuoPack& pack, DT_Index a_index, DT_Index b_index, MT_Vector3& v) 
+{
+    DT_Transform ta = DT_Transform(pack.m_a.m_xform, *pack.m_a.m_leaves[a_index]);
+    MT_Scalar a_margin = pack.m_a.m_plus;
+    DT_Transform tb = DT_Transform(pack.m_b.m_xform, *pack.m_b.m_leaves[b_index]);
+    MT_Scalar b_margin = pack.m_b.m_plus;
+    return ::intersect((a_margin > MT_Scalar(0.0) ?
+                        static_cast(DT_Minkowski(ta, DT_Sphere(a_margin))) : 
+                        static_cast(ta)), 
+                       (b_margin > MT_Scalar(0.0) ? 
+                        static_cast(DT_Minkowski(tb, DT_Sphere(b_margin))) : 
+                        static_cast(tb)), 
+                       v);   
+}
+
+bool intersect(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin,
+               const DT_Complex& b, const MT_Transform& b2w, MT_Scalar b_margin, MT_Vector3& v) 
+{
+    DT_DuoPack pack(DT_ObjectData(a.m_nodes, a.m_leaves, a2w, a_margin),
+                                                  DT_ObjectData(b.m_nodes, b.m_leaves, b2w, b_margin));
+
+
+    return intersect(DT_BBoxTree(a.m_cbox + pack.m_a.m_added, 0, a.m_type),
+                     DT_BBoxTree(b.m_cbox + pack.m_b.m_added, 0, b.m_type), pack, v);
+}
+
+inline bool common_point(const DT_Pack& pack, DT_Index a_index, MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    DT_Transform ta = DT_Transform(pack.m_a.m_xform, *pack.m_a.m_leaves[a_index]);
+    MT_Scalar a_margin = pack.m_a.m_plus;
+    return ::common_point((a_margin > MT_Scalar(0.0) ? 
+                           static_cast(DT_Minkowski(ta, DT_Sphere(a_margin))) :
+                           static_cast(ta)), 
+                          pack.m_b, v, pa, pb); 
+}
+    
+bool common_point(const DT_Complex& a,  const MT_Transform& a2w,  MT_Scalar a_margin, 
+                  const DT_Convex& b, MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+     DT_Pack pack(DT_ObjectData(a.m_nodes, a.m_leaves, a2w, a_margin), b);
+
+    return common_point(DT_BBoxTree(a.m_cbox + pack.m_a.m_added, 0, a.m_type), pack, v, pb, pa);
+}
+
+inline bool common_point(const DT_DuoPack& pack, DT_Index a_index, DT_Index b_index, MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    DT_Transform ta = DT_Transform(pack.m_a.m_xform, *pack.m_a.m_leaves[a_index]);
+    MT_Scalar a_margin = pack.m_a.m_plus;
+    DT_Transform tb = DT_Transform(pack.m_b.m_xform, *pack.m_b.m_leaves[b_index]);
+    MT_Scalar b_margin = pack.m_b.m_plus;
+    return ::common_point((a_margin > MT_Scalar(0.0) ? 
+                           static_cast(DT_Minkowski(ta, DT_Sphere(a_margin))) : 
+                           static_cast(ta)), 
+                          (b_margin > MT_Scalar(0.0) ? 
+                           static_cast(DT_Minkowski(tb, DT_Sphere(b_margin))) : 
+                           static_cast(tb)), 
+                          v, pa, pb);    
+}
+    
+bool common_point(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin,
+                  const DT_Complex& b, const MT_Transform& b2w, MT_Scalar b_margin, 
+                  MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    DT_DuoPack pack(DT_ObjectData(a.m_nodes, a.m_leaves, a2w, a_margin),
+                                                  DT_ObjectData(b.m_nodes, b.m_leaves, b2w, b_margin));
+
+    return common_point(DT_BBoxTree(a.m_cbox + pack.m_a.m_added, 0, a.m_type),
+                        DT_BBoxTree(b.m_cbox + pack.m_b.m_added, 0, b.m_type),  pack, v, pa, pb);
+}
+
+inline bool penetration_depth(const DT_HybridPack& pack, DT_Index a_index, MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    DT_Transform ta = DT_Transform(pack.m_a.m_xform, *pack.m_a.m_leaves[a_index]);
+    return ::hybrid_penetration_depth(ta, pack.m_a.m_plus, pack.m_b, pack.m_margin, v, pa, pb); 
+}
+
+bool penetration_depth(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin, 
+                       const DT_Convex& b, MT_Scalar b_margin, MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    DT_HybridPack pack(DT_ObjectData(a.m_nodes, a.m_leaves, a2w, a_margin), b, b_margin);
+     
+    MT_Scalar  max_pen_len = MT_Scalar(0.0);
+    return penetration_depth(DT_BBoxTree(a.m_cbox + pack.m_a.m_added, 0, a.m_type), pack, v, pa, pb, max_pen_len);
+}
+
+inline bool penetration_depth(const DT_DuoPack& pack, DT_Index a_index, DT_Index b_index, MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    DT_Transform ta = DT_Transform(pack.m_a.m_xform, *pack.m_a.m_leaves[a_index]);
+    DT_Transform tb = DT_Transform(pack.m_b.m_xform, *pack.m_b.m_leaves[b_index]);
+    return ::hybrid_penetration_depth(ta, pack.m_a.m_plus, tb, pack.m_a.m_plus, v, pa, pb);  
+}
+
+bool penetration_depth(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin,
+                       const DT_Complex& b, const MT_Transform& b2w, MT_Scalar b_margin, 
+                       MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    DT_DuoPack pack(DT_ObjectData(a.m_nodes, a.m_leaves, a2w, a_margin),
+                                                  DT_ObjectData(b.m_nodes, b.m_leaves, b2w, b_margin));
+
+    MT_Scalar  max_pen_len = MT_Scalar(0.0);
+    return penetration_depth(DT_BBoxTree(a.m_cbox + pack.m_a.m_added, 0, a.m_type),
+                             DT_BBoxTree(b.m_cbox + pack.m_b.m_added, 0, b.m_type), pack, v, pa, pb, max_pen_len);
+}
+
+
+
+inline MT_Scalar closest_points(const DT_Pack& pack, DT_Index a_index, MT_Scalar max_dist2, MT_Point3& pa, MT_Point3& pb) 
+{
+    DT_Transform ta = DT_Transform(pack.m_a.m_xform, *pack.m_a.m_leaves[a_index]);
+    MT_Scalar a_margin = pack.m_a.m_plus;
+    return ::closest_points((a_margin > MT_Scalar(0.0) ? 
+                             static_cast(DT_Minkowski(ta, DT_Sphere(a_margin))) :  
+                             static_cast(ta)), 
+                            pack.m_b, max_dist2, pa, pb); 
+}
+
+MT_Scalar closest_points(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin,
+                         const DT_Convex& b, MT_Point3& pa, MT_Point3& pb)
+{
+    DT_Pack pack(DT_ObjectData(a.m_nodes, a.m_leaves, a2w, a_margin), b);
+
+    return closest_points(DT_BBoxTree(a.m_cbox + pack.m_a.m_added, 0, a.m_type), pack, MT_INFINITY, pa, pb); 
+}
+
+inline MT_Scalar closest_points(const DT_DuoPack& pack, DT_Index a_index, DT_Index b_index, MT_Scalar max_dist2, MT_Point3& pa, MT_Point3& pb) 
+{
+    DT_Transform ta = DT_Transform(pack.m_a.m_xform, *pack.m_a.m_leaves[a_index]);
+    MT_Scalar a_margin = pack.m_a.m_plus;
+    DT_Transform tb = DT_Transform(pack.m_b.m_xform, *pack.m_b.m_leaves[b_index]);
+    MT_Scalar b_margin = pack.m_b.m_plus;
+    return ::closest_points((a_margin > MT_Scalar(0.0) ? 
+                             static_cast(DT_Minkowski(ta, DT_Sphere(a_margin))) : 
+                             static_cast(ta)), 
+                            (b_margin > MT_Scalar(0.0) ? 
+                             static_cast(DT_Minkowski(tb, DT_Sphere(b_margin))) : 
+                             static_cast(tb)), max_dist2, pa, pb);     
+}
+
+MT_Scalar closest_points(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin,
+                         const DT_Complex& b, const MT_Transform& b2w, MT_Scalar b_margin, 
+                         MT_Point3& pa, MT_Point3& pb) 
+{
+    DT_DuoPack pack(DT_ObjectData(a.m_nodes, a.m_leaves, a2w, a_margin),
+                               DT_ObjectData(b.m_nodes, b.m_leaves, b2w, b_margin));
+
+    return closest_points(DT_BBoxTree(a.m_cbox + pack.m_a.m_added, 0, a.m_type),
+                          DT_BBoxTree(b.m_cbox + pack.m_b.m_added, 0, b.m_type), pack, MT_INFINITY, pa, pb);
+}
+
+
diff --git a/extern/solid/src/complex/DT_Complex.h b/extern/solid/src/complex/DT_Complex.h
new file mode 100644
index 00000000000..ae08a05d4c9
--- /dev/null
+++ b/extern/solid/src/complex/DT_Complex.h
@@ -0,0 +1,94 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_COMPLEX_H
+#define DT_COMPLEX_H
+
+#include 
+
+#include "MT_Transform.h"
+#include "DT_VertexBase.h"
+
+#include "DT_Shape.h"
+#include "DT_CBox.h"
+#include "DT_BBoxTree.h"
+
+class DT_Convex;
+
+class DT_Complex : public DT_Shape  {
+public:
+	DT_Complex(const DT_VertexBase *base);
+	virtual ~DT_Complex();
+	
+	void finish(DT_Count n, const DT_Convex *p[]);
+    
+	virtual DT_ShapeType getType() const { return COMPLEX; }
+
+    virtual MT_BBox bbox(const MT_Transform& t, MT_Scalar margin) const;
+
+	virtual bool ray_cast(const MT_Point3& source, const MT_Point3& target, 
+						  MT_Scalar& lambda, MT_Vector3& normal) const; 
+
+	void refit();
+	
+
+    friend bool intersect(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin, 
+		                  const DT_Convex& b, MT_Vector3& v);
+    
+    friend bool intersect(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin, 
+		                  const DT_Complex& b, const MT_Transform& b2w, MT_Scalar b_margin,
+                          MT_Vector3& v);
+   
+    friend bool common_point(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin, 
+		                     const DT_Convex& b, MT_Vector3& v, MT_Point3& pa, MT_Point3& pb);
+    
+    friend bool common_point(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin, 
+		                     const DT_Complex& b, const MT_Transform& b2w, MT_Scalar b_margin,
+                             MT_Vector3& v, MT_Point3& pa, MT_Point3& pb);
+    
+    friend bool penetration_depth(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin, 
+								  const DT_Convex& b, MT_Scalar b_margin, MT_Vector3& v, MT_Point3& pa, MT_Point3& pb);
+    
+    friend bool penetration_depth(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin, 
+								  const DT_Complex& b, const MT_Transform& b2w, MT_Scalar b_margin,
+								  MT_Vector3& v, MT_Point3& pa, MT_Point3& pb);
+
+    friend MT_Scalar closest_points(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin, 
+		                            const DT_Convex& b, MT_Point3& pa, MT_Point3& pb);
+    
+    friend MT_Scalar closest_points(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin, 
+		                            const DT_Complex& b, const MT_Transform& b2w, MT_Scalar b_margin,
+									MT_Point3& pa, MT_Point3& pb);
+
+	const DT_VertexBase   *m_base;
+	DT_Count               m_count;
+	const DT_Convex      **m_leaves;
+	DT_BBoxNode           *m_nodes;
+	DT_CBox                m_cbox;
+	DT_BBoxTree::NodeType  m_type;
+};
+
+#endif
+
+
+
diff --git a/extern/solid/src/complex/Makefile b/extern/solid/src/complex/Makefile
new file mode 100644
index 00000000000..99e786276b0
--- /dev/null
+++ b/extern/solid/src/complex/Makefile
@@ -0,0 +1,45 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# 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. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License.  See http://www.blender.org/BL/ for information
+# about this.
+#
+# 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.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = solid_complex
+DIR = $(OCGDIR)/extern/$(LIBNAME)
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I../../include -I$(NAN_QHULL)/include
+CPPFLAGS += -I../convex
+CPPFLAGS += -DQHULL -DUSE_DOUBLES
+
+include nan_compile.mk 
+
+
diff --git a/extern/solid/src/convex/DT_Accuracy.cpp b/extern/solid/src/convex/DT_Accuracy.cpp
new file mode 100644
index 00000000000..113275b0dbd
--- /dev/null
+++ b/extern/solid/src/convex/DT_Accuracy.cpp
@@ -0,0 +1,30 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_Accuracy.h"
+
+static const MT_Scalar rel_error = MT_Scalar(1.0e-3);
+
+MT_Scalar DT_Accuracy::rel_error2 = rel_error * rel_error;
+MT_Scalar DT_Accuracy::depth_tolerance = MT_Scalar(1.0) + MT_Scalar(2.0) * rel_error; 
+MT_Scalar DT_Accuracy::tol_error = MT_EPSILON;
diff --git a/extern/solid/src/convex/DT_Accuracy.h b/extern/solid/src/convex/DT_Accuracy.h
new file mode 100644
index 00000000000..9759a6fd4c5
--- /dev/null
+++ b/extern/solid/src/convex/DT_Accuracy.h
@@ -0,0 +1,47 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_ACCURACY_H
+#define DT_ACCURACY_H
+
+#include "MT_Scalar.h"
+
+class DT_Accuracy {
+public:
+	static MT_Scalar rel_error2; // squared relative error in the computed distance
+	static MT_Scalar depth_tolerance; // terminate EPA if upper_bound <= depth_tolerance * dist2
+	static MT_Scalar tol_error; // error tolerance if the distance is almost zero
+	
+	static void setAccuracy(MT_Scalar rel_error) 
+	{ 
+		rel_error2 = rel_error * rel_error;
+		depth_tolerance = MT_Scalar(1.0) + MT_Scalar(2.0) * rel_error;
+	}	
+   
+	static void setTolerance(MT_Scalar epsilon) 
+	{ 
+		tol_error = epsilon;
+	}
+};
+
+#endif
diff --git a/extern/solid/src/convex/DT_Array.h b/extern/solid/src/convex/DT_Array.h
new file mode 100644
index 00000000000..1694f884e53
--- /dev/null
+++ b/extern/solid/src/convex/DT_Array.h
@@ -0,0 +1,75 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_ARRAY_H
+#define DT_ARRAY_H
+
+#if defined (__sgi)
+#include 
+#else
+#include 
+#endif
+
+template 
+class DT_Array {
+public:
+	DT_Array() 
+      :	m_count(0), 
+		m_data(0) 
+	{}
+
+	explicit DT_Array(Size count)
+	  :	m_count(count),
+		m_data(new Data[count]) 
+	{
+		assert(m_data);
+	}
+	
+	DT_Array(Size count, const Data *data) 
+	  :	m_count(count),
+		m_data(new Data[count]) 
+	{
+		assert(m_data);		
+		std::copy(&data[0], &data[count], m_data);
+	}
+	
+	~DT_Array() 
+	{ 
+		delete [] m_data; 
+	}
+	
+	const Data& operator[](int i) const { return m_data[i]; }
+	Data&       operator[](int i)       { return m_data[i]; }
+
+	Size size() const { return m_count; }
+	
+private:
+	DT_Array(const DT_Array&);
+	DT_Array& operator=(const DT_Array&);
+
+	Size  m_count;
+	Data *m_data;
+};
+  
+#endif
+
diff --git a/extern/solid/src/convex/DT_Box.cpp b/extern/solid/src/convex/DT_Box.cpp
new file mode 100644
index 00000000000..0b46f566fe8
--- /dev/null
+++ b/extern/solid/src/convex/DT_Box.cpp
@@ -0,0 +1,112 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_Box.h"
+
+MT_Scalar DT_Box::supportH(const MT_Vector3& v) const 
+{
+    return v.absolute().dot(m_extent);
+}
+
+MT_Point3 DT_Box::support(const MT_Vector3& v) const 
+{
+    return MT_Point3(v[0] < MT_Scalar(0.0) ? -m_extent[0] : m_extent[0],
+                     v[1] < MT_Scalar(0.0) ? -m_extent[1] : m_extent[1],
+                     v[2] < MT_Scalar(0.0) ? -m_extent[2] : m_extent[2]); 
+    
+}
+
+
+bool DT_Box::ray_cast(const MT_Point3& source, const MT_Point3& target,
+					  MT_Scalar& param, MT_Vector3& normal) const 
+{
+	T_Outcode source_bits = outcode(source);
+	T_Outcode target_bits = outcode(target);
+
+	if ((source_bits & target_bits) == 0x0)
+		// None of the side planes separate the ray from the box.
+	{
+		MT_Scalar lambda_enter = MT_Scalar(0.0);
+		MT_Scalar lambda_exit  = param;
+		MT_Vector3 r = target - source;
+		T_Outcode normal_bit = 0x0; // Indicates the axis that is returned as normal.
+		T_Outcode bit = 0x01;
+		int i;
+		for (i = 0; i != 3; ++i)
+		{
+			if (source_bits & bit)
+				// Point of intersection is entering
+			{
+				MT_Scalar lambda = (-source[i] - m_extent[i]) / r[i];
+				if (lambda_enter < lambda)
+				{
+					lambda_enter = lambda;
+					normal_bit = bit;
+				}
+			}
+			else if (target_bits & bit) 
+				// Point of intersection is exiting
+			{
+				MT_Scalar lambda = (-source[i] - m_extent[i]) / r[i];
+				GEN_set_min(lambda_exit, lambda);
+			}
+			bit <<=1;
+			if (source_bits & bit)
+				// Point of intersection is entering
+			{
+				MT_Scalar lambda =  (-source[i] + m_extent[i]) / r[i];
+				if (lambda_enter < lambda)
+				{
+					lambda_enter = lambda;
+					normal_bit = bit;
+				}
+			}
+			else if (target_bits & bit) 
+				// Point of intersection is exiting
+			{
+				MT_Scalar lambda =  (-source[i] + m_extent[i]) / r[i];
+				GEN_set_min(lambda_exit, lambda);
+			}
+			bit <<=1;
+		}
+		if (lambda_enter <= lambda_exit)
+			// The ray intersects the box
+		{
+			param = lambda_enter;
+			normal.setValue(normal_bit == 0x01 ? -MT_Scalar(1.0) : 
+							normal_bit == 0x02 ?  MT_Scalar(1.0) : 
+							MT_Scalar(0.0),
+							normal_bit == 0x04 ? -MT_Scalar(1.0) : 
+							normal_bit == 0x08 ?  MT_Scalar(1.0) : 
+							MT_Scalar(0.0),
+							normal_bit == 0x10 ? -MT_Scalar(1.0) : 
+							normal_bit == 0x20 ?  MT_Scalar(1.0) : 
+							MT_Scalar(0.0));
+			return true;
+		}
+	}
+
+	return false;
+}
+
+
diff --git a/extern/solid/src/convex/DT_Box.h b/extern/solid/src/convex/DT_Box.h
new file mode 100644
index 00000000000..ace9634b5e3
--- /dev/null
+++ b/extern/solid/src/convex/DT_Box.h
@@ -0,0 +1,62 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_BOX_H
+#define DT_BOX_H
+
+#include "DT_Convex.h"
+
+class DT_Box : public DT_Convex {
+public:
+    DT_Box(MT_Scalar x, MT_Scalar y, MT_Scalar z) : 
+        m_extent(x, y, z) 
+	{}
+
+    DT_Box(const MT_Vector3& e) : 
+		m_extent(e) 
+	{}
+
+    virtual MT_Scalar supportH(const MT_Vector3& v) const;
+    virtual MT_Point3 support(const MT_Vector3& v) const;
+	virtual bool ray_cast(const MT_Point3& source, const MT_Point3& target,
+						  MT_Scalar& param, MT_Vector3& normal) const;
+    
+    const MT_Vector3& getExtent() const { return m_extent; }
+	
+protected:
+	typedef unsigned int T_Outcode;
+	
+	T_Outcode outcode(const MT_Point3& p) const
+	{
+		return (p[0] < -m_extent[0] ? 0x01 : 0x0) |    
+			   (p[0] >  m_extent[0] ? 0x02 : 0x0) |
+			   (p[1] < -m_extent[1] ? 0x04 : 0x0) |    
+			   (p[1] >  m_extent[1] ? 0x08 : 0x0) |
+			   (p[2] < -m_extent[2] ? 0x10 : 0x0) |    
+			   (p[2] >  m_extent[2] ? 0x20 : 0x0);
+	}
+    
+    MT_Vector3 m_extent;
+};
+
+#endif
diff --git a/extern/solid/src/convex/DT_Cone.cpp b/extern/solid/src/convex/DT_Cone.cpp
new file mode 100644
index 00000000000..1dd6a7ddbbe
--- /dev/null
+++ b/extern/solid/src/convex/DT_Cone.cpp
@@ -0,0 +1,48 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_Cone.h"
+
+MT_Point3 DT_Cone::support(const MT_Vector3& v) const 
+{
+    MT_Scalar v_len = v.length();
+
+    if (v[1] > v_len * sinAngle)
+	{
+		return MT_Point3(MT_Scalar(0.0), halfHeight, MT_Scalar(0.0));
+	}
+    else
+	{
+        MT_Scalar s = MT_sqrt(v[0] * v[0] + v[2] * v[2]);
+        if (s != MT_Scalar(0.0))
+		{
+            MT_Scalar d = bottomRadius / s;  
+            return MT_Point3(v[0] * d, -halfHeight, v[2] * d);
+        }
+        else
+		{
+			return MT_Point3(bottomRadius, -halfHeight, MT_Scalar(0.0));
+		}
+    }
+}
+
diff --git a/extern/solid/src/convex/DT_Cone.h b/extern/solid/src/convex/DT_Cone.h
new file mode 100644
index 00000000000..85e416877dd
--- /dev/null
+++ b/extern/solid/src/convex/DT_Cone.h
@@ -0,0 +1,45 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_CONE_H
+#define DT_CONE_H
+
+#include "DT_Convex.h"
+
+class DT_Cone : public DT_Convex {
+public:
+	DT_Cone(MT_Scalar r, MT_Scalar h) : 
+        bottomRadius(r), 
+        halfHeight(h * MT_Scalar(0.5)), 
+        sinAngle(r / MT_sqrt(r * r + h * h))
+    {} 
+  
+    virtual MT_Point3 support(const MT_Vector3& v) const;
+  
+protected:
+    MT_Scalar bottomRadius;
+    MT_Scalar halfHeight;
+    MT_Scalar sinAngle;
+};
+
+#endif
diff --git a/extern/solid/src/convex/DT_Convex.cpp b/extern/solid/src/convex/DT_Convex.cpp
new file mode 100644
index 00000000000..3be47f6ed02
--- /dev/null
+++ b/extern/solid/src/convex/DT_Convex.cpp
@@ -0,0 +1,426 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_Convex.h"
+#include "GEN_MinMax.h"
+
+//#define DEBUG
+#define SAFE_EXIT
+
+#include "DT_GJK.h"
+#include "DT_PenDepth.h"
+
+#include 
+#include 
+
+#include "MT_BBox.h"
+#include "DT_Sphere.h"
+#include "DT_Minkowski.h"
+
+#include "DT_Accuracy.h"
+
+#ifdef STATISTICS
+int num_iterations = 0;
+int num_irregularities = 0;
+#endif
+
+MT_BBox DT_Convex::bbox() const 
+{
+	MT_Point3 min(-supportH(MT_Vector3(-1.0f, 0.0f, 0.0f)),
+                  -supportH(MT_Vector3(0.0f, -1.0f, 0.0f)),
+				  -supportH(MT_Vector3(0.0f, 0.0f, -1.0f)));
+	MT_Point3 max( supportH(MT_Vector3(1.0f, 0.0f, 0.0f)),
+                   supportH(MT_Vector3(0.0f, 1.0f, 0.0f)),
+				   supportH(MT_Vector3(0.0f, 0.0f, 1.0f)));
+
+	
+    return MT_BBox(min, max);
+}
+
+MT_BBox DT_Convex::bbox(const MT_Matrix3x3& basis) const 
+{
+    MT_Point3 min(-supportH(-basis[0]),
+                  -supportH(-basis[1]),
+		          -supportH(-basis[2])); 
+    MT_Point3 max( supportH( basis[0]),
+                   supportH( basis[1]),
+                   supportH( basis[2])); 
+    return MT_BBox(min, max);
+}
+
+MT_BBox DT_Convex::bbox(const MT_Transform& t, MT_Scalar margin) const 
+{
+    MT_Point3 min(t.getOrigin()[0] - supportH(-t.getBasis()[0]) - margin,
+                  t.getOrigin()[1] - supportH(-t.getBasis()[1]) - margin,
+		          t.getOrigin()[2] - supportH(-t.getBasis()[2]) - margin); 
+    MT_Point3 max(t.getOrigin()[0] + supportH( t.getBasis()[0]) + margin,
+                  t.getOrigin()[1] + supportH( t.getBasis()[1]) + margin,
+                  t.getOrigin()[2] + supportH( t.getBasis()[2]) + margin); 
+    return MT_BBox(min, max);
+}
+
+bool DT_Convex::ray_cast(const MT_Point3& source, const MT_Point3& target, MT_Scalar& lambda, MT_Vector3& normal) const
+{
+	// Still working on this one...
+    return false;
+}
+
+bool intersect(const DT_Convex& a, const DT_Convex& b, MT_Vector3& v)
+{
+	DT_GJK gjk;
+
+#ifdef STATISTICS
+    num_iterations = 0;
+#endif
+	MT_Scalar dist2 = MT_INFINITY;
+
+	do
+	{
+		MT_Point3  p = a.support(-v);	
+		MT_Point3  q = b.support(v);
+		MT_Vector3 w = p - q; 
+		
+        if (v.dot(w) > MT_Scalar(0.0)) 
+		{
+			return false;
+		}
+ 
+		gjk.addVertex(w);
+
+#ifdef STATISTICS
+        ++num_iterations;
+#endif
+        if (!gjk.closest(v)) 
+		{
+#ifdef STATISTICS
+            ++num_irregularities;
+#endif
+            return false;
+        }
+
+#ifdef SAFE_EXIT
+		MT_Scalar prev_dist2 = dist2;
+#endif
+
+		dist2 = v.length2();
+
+#ifdef SAFE_EXIT
+		if (prev_dist2 - dist2 <= MT_EPSILON * prev_dist2) 
+		{
+			return false;
+		}
+#endif
+    } 
+    while (!gjk.fullSimplex() && dist2 > DT_Accuracy::tol_error * gjk.maxVertex()); 
+
+    v.setValue(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0));
+
+    return true;
+}
+
+
+
+
+bool common_point(const DT_Convex& a, const DT_Convex& b,
+                  MT_Vector3& v, MT_Point3& pa, MT_Point3& pb)
+{
+	DT_GJK gjk;
+
+#ifdef STATISTICS
+    num_iterations = 0;
+#endif
+
+	MT_Scalar dist2 = MT_INFINITY;
+
+    do
+	{
+		MT_Point3  p = a.support(-v);	
+		MT_Point3  q = b.support(v);
+		MT_Vector3 w = p - q; 
+		
+        if (v.dot(w) > MT_Scalar(0.0)) 
+		{
+			return false;
+		}
+ 
+		gjk.addVertex(w, p, q);
+
+#ifdef STATISTICS
+        ++num_iterations;
+#endif
+        if (!gjk.closest(v)) 
+		{
+#ifdef STATISTICS
+            ++num_irregularities;
+#endif
+            return false;
+        }		
+		
+#ifdef SAFE_EXIT
+		MT_Scalar prev_dist2 = dist2;
+#endif
+
+		dist2 = v.length2();
+
+#ifdef SAFE_EXIT
+		if (prev_dist2 - dist2 <= MT_EPSILON * prev_dist2) 
+		{
+			return false;
+		}
+#endif
+    }
+    while (!gjk.fullSimplex() && dist2 > DT_Accuracy::tol_error * gjk.maxVertex()); 
+    
+	gjk.compute_points(pa, pb);
+
+    v.setValue(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0));
+
+    return true;
+}
+
+
+
+
+
+
+	
+bool penetration_depth(const DT_Convex& a, const DT_Convex& b,
+                       MT_Vector3& v, MT_Point3& pa, MT_Point3& pb)
+{
+	DT_GJK gjk;
+
+#ifdef STATISTICS
+    num_iterations = 0;
+#endif
+
+	MT_Scalar dist2 = MT_INFINITY;
+
+    do
+	{
+		MT_Point3  p = a.support(-v);	
+		MT_Point3  q = b.support(v);
+		MT_Vector3 w = p - q; 
+		
+        if (v.dot(w) > MT_Scalar(0.0)) 
+		{
+			return false;
+		}
+ 
+		gjk.addVertex(w, p, q);
+
+#ifdef STATISTICS
+        ++num_iterations;
+#endif
+        if (!gjk.closest(v)) 
+		{
+#ifdef STATISTICS
+            ++num_irregularities;
+#endif
+            return false;
+        }		
+		
+#ifdef SAFE_EXIT
+		MT_Scalar prev_dist2 = dist2;
+#endif
+
+		dist2 = v.length2();
+
+#ifdef SAFE_EXIT
+		if (prev_dist2 - dist2 <= MT_EPSILON * prev_dist2) 
+		{
+			return false;
+		}
+#endif
+    }
+    while (!gjk.fullSimplex() && dist2 > DT_Accuracy::tol_error * gjk.maxVertex()); 
+    
+
+	return penDepth(gjk, a, b, v, pa, pb);
+
+}
+
+bool hybrid_penetration_depth(const DT_Convex& a, MT_Scalar a_margin, 
+							  const DT_Convex& b, MT_Scalar b_margin,
+                              MT_Vector3& v, MT_Point3& pa, MT_Point3& pb)
+{
+	MT_Scalar margin = a_margin + b_margin;
+	if (margin > MT_Scalar(0.0))
+	{
+		MT_Scalar margin2 = margin * margin;
+
+		DT_GJK gjk;
+
+#ifdef STATISTICS
+		num_iterations = 0;
+#endif
+		MT_Scalar dist2 = MT_INFINITY;
+
+		do
+		{
+			MT_Point3  p = a.support(-v);	
+			MT_Point3  q = b.support(v);
+			
+			MT_Vector3 w = p - q; 
+			
+			MT_Scalar delta = v.dot(w);
+			
+			if (delta > MT_Scalar(0.0) && delta * delta > dist2 * margin2) 
+			{
+				return false;
+			}
+			
+			if (gjk.inSimplex(w) || dist2 - delta <= dist2 * DT_Accuracy::rel_error2)
+			{
+				gjk.compute_points(pa, pb);
+				MT_Scalar s = MT_sqrt(dist2);
+				assert(s > MT_Scalar(0.0));
+				pa -= v * (a_margin / s);
+				pb += v * (b_margin / s);
+				return true;
+			}
+			
+			gjk.addVertex(w, p, q);
+			
+#ifdef STATISTICS
+			++num_iterations;
+#endif
+			if (!gjk.closest(v)) 
+			{
+#ifdef STATISTICS
+				++num_irregularities;
+#endif
+				gjk.compute_points(pa, pb);
+				MT_Scalar s = MT_sqrt(dist2);
+				assert(s > MT_Scalar(0.0));
+				pa -= v * (a_margin / s);
+				pb += v * (b_margin / s);
+				return true;
+			}
+			
+#ifdef SAFE_EXIT
+			MT_Scalar prev_dist2 = dist2;
+#endif
+			
+			dist2 = v.length2();
+			
+#ifdef SAFE_EXIT
+			if (prev_dist2 - dist2 <= MT_EPSILON * prev_dist2) 
+			{ 
+				gjk.backup_closest(v);
+				dist2 = v.length2();
+				gjk.compute_points(pa, pb);
+				MT_Scalar s = MT_sqrt(dist2);
+				assert(s > MT_Scalar(0.0));
+				pa -= v * (a_margin / s);
+				pb += v * (b_margin / s);
+				return true;
+			}
+#endif
+		}
+		while (!gjk.fullSimplex() && dist2 > DT_Accuracy::tol_error * gjk.maxVertex()); 
+		
+	}
+	// Second GJK phase. compute points on the boundary of the offset object
+	
+	return penetration_depth((a_margin > MT_Scalar(0.0) ? 
+							  static_cast(DT_Minkowski(a, DT_Sphere(a_margin))) : 
+							  static_cast(a)), 
+							 (b_margin > MT_Scalar(0.0) ? 
+							  static_cast(DT_Minkowski(b, DT_Sphere(b_margin))) : 
+							  static_cast(b)), v, pa, pb);
+}
+
+
+MT_Scalar closest_points(const DT_Convex& a, const DT_Convex& b, MT_Scalar max_dist2,
+                         MT_Point3& pa, MT_Point3& pb) 
+{
+	MT_Vector3 v(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0));
+	
+    DT_GJK gjk;
+
+#ifdef STATISTICS
+    num_iterations = 0;
+#endif
+
+	MT_Scalar dist2 = MT_INFINITY;
+
+    do
+	{
+		MT_Point3  p = a.support(-v);	
+		MT_Point3  q = b.support(v);
+		MT_Vector3 w = p - q; 
+
+		MT_Scalar delta = v.dot(w);
+		if (delta > MT_Scalar(0.0) && delta * delta > dist2 * max_dist2) 
+		{
+			return MT_INFINITY;
+		}
+
+		if (gjk.inSimplex(w) || dist2 - delta <= dist2 * DT_Accuracy::rel_error2) 
+		{
+            break;
+		}
+
+		gjk.addVertex(w, p, q);
+
+#ifdef STATISTICS
+        ++num_iterations;
+        if (num_iterations > 1000) 
+		{
+			std::cout << "v: " << v << " w: " << w << std::endl;
+		}
+#endif
+        if (!gjk.closest(v)) 
+		{
+#ifdef STATISTICS
+            ++num_irregularities;
+#endif
+            break;
+        }
+
+#ifdef SAFE_EXIT
+		MT_Scalar prev_dist2 = dist2;
+#endif
+
+		dist2 = v.length2();
+
+#ifdef SAFE_EXIT
+		if (prev_dist2 - dist2 <= MT_EPSILON * prev_dist2) 
+		{
+         gjk.backup_closest(v);
+         dist2 = v.length2();
+			break;
+		}
+#endif
+    }
+    while (!gjk.fullSimplex() && dist2 > DT_Accuracy::tol_error * gjk.maxVertex()); 
+
+	assert(!gjk.emptySimplex());
+	
+	if (dist2 <= max_dist2)
+	{
+		gjk.compute_points(pa, pb);
+	}
+	
+	return dist2;
+}
diff --git a/extern/solid/src/convex/DT_Convex.h b/extern/solid/src/convex/DT_Convex.h
new file mode 100644
index 00000000000..dd620ac8b98
--- /dev/null
+++ b/extern/solid/src/convex/DT_Convex.h
@@ -0,0 +1,64 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_CONVEX_H
+#define DT_CONVEX_H
+
+#include "DT_Shape.h"
+
+#include "MT_Vector3.h"
+#include "MT_Point3.h"
+
+#include "MT_Matrix3x3.h"
+#include "MT_Transform.h"
+
+class DT_Convex : public DT_Shape {
+public:
+    virtual ~DT_Convex() {}
+	virtual DT_ShapeType getType() const { return CONVEX; } 
+    
+	virtual MT_Scalar supportH(const MT_Vector3& v) const {	return v.dot(support(v)); }
+    virtual MT_Point3 support(const MT_Vector3& v) const = 0;
+	virtual MT_BBox bbox() const;
+    virtual MT_BBox bbox(const MT_Matrix3x3& basis) const;
+    virtual MT_BBox bbox(const MT_Transform& t, MT_Scalar margin = MT_Scalar(0.0)) const;
+	virtual bool ray_cast(const MT_Point3& source, const MT_Point3& target, MT_Scalar& param, MT_Vector3& normal) const;
+	
+protected:
+	DT_Convex() {}
+};
+
+
+bool intersect(const DT_Convex& a, const DT_Convex& b, MT_Vector3& v);
+
+bool common_point(const DT_Convex& a, const DT_Convex& b, MT_Vector3& v, MT_Point3& pa, MT_Point3& pb);
+
+MT_Scalar closest_points(const DT_Convex&, const DT_Convex&, MT_Scalar max_dist2, MT_Point3& pa, MT_Point3& pb);
+
+bool penetration_depth(const DT_Convex& a, const DT_Convex& b, MT_Vector3& v, MT_Point3& pa, MT_Point3& pb);
+
+bool hybrid_penetration_depth(const DT_Convex& a, MT_Scalar a_margin, 
+							  const DT_Convex& b, MT_Scalar b_margin,
+                              MT_Vector3& v, MT_Point3& pa, MT_Point3& pb);
+
+#endif
diff --git a/extern/solid/src/convex/DT_Cylinder.cpp b/extern/solid/src/convex/DT_Cylinder.cpp
new file mode 100644
index 00000000000..cff5ebcefb1
--- /dev/null
+++ b/extern/solid/src/convex/DT_Cylinder.cpp
@@ -0,0 +1,39 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_Cylinder.h"
+
+MT_Point3 DT_Cylinder::support(const MT_Vector3& v) const 
+{
+    MT_Scalar s = MT_sqrt(v[0] * v[0] + v[2] * v[2]);
+    if (s != MT_Scalar(0.0))
+	{
+        MT_Scalar d = radius / s;  
+        return MT_Point3(v[0] * d, v[1] < 0.0 ? -halfHeight : halfHeight, v[2] * d);
+    }
+    else
+	{
+        return MT_Point3(radius, v[1] < 0.0 ? -halfHeight : halfHeight, MT_Scalar(0.0));
+    }
+}
+  
diff --git a/extern/solid/src/convex/DT_Cylinder.h b/extern/solid/src/convex/DT_Cylinder.h
new file mode 100644
index 00000000000..2a0c07fd579
--- /dev/null
+++ b/extern/solid/src/convex/DT_Cylinder.h
@@ -0,0 +1,42 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_CYLINDER_H
+#define DT_CYLINDER_H
+
+#include "DT_Convex.h"
+
+class DT_Cylinder : public DT_Convex {
+public:
+    DT_Cylinder(MT_Scalar r, MT_Scalar h) : 
+        radius(r), 
+        halfHeight(h * MT_Scalar(0.5)) {}
+    
+    virtual MT_Point3 support(const MT_Vector3& v) const;
+    
+protected:
+    MT_Scalar radius;
+    MT_Scalar halfHeight;
+};
+
+#endif
diff --git a/extern/solid/src/convex/DT_Facet.cpp b/extern/solid/src/convex/DT_Facet.cpp
new file mode 100644
index 00000000000..87ae5c3e0be
--- /dev/null
+++ b/extern/solid/src/convex/DT_Facet.cpp
@@ -0,0 +1,80 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_Facet.h"
+
+bool DT_Facet::link(int edge0, DT_Facet *facet, int edge1) 
+{
+    m_adjFacets[edge0] = facet;
+    m_adjEdges[edge0] = edge1;
+    facet->m_adjFacets[edge1] = this;
+    facet->m_adjEdges[edge1] = edge0;
+
+    bool b = m_indices[edge0] == facet->m_indices[incMod3(edge1)] &&
+	m_indices[incMod3(edge0)] == facet->m_indices[edge1];
+    return b;
+}
+
+bool DT_Facet::computeClosest(const MT_Vector3 *verts)
+{
+    const MT_Vector3& p0 = verts[m_indices[0]]; 
+
+    MT_Vector3 v1 = verts[m_indices[1]] - p0;
+    MT_Vector3 v2 = verts[m_indices[2]] - p0;
+    MT_Scalar v1dv1 = v1.length2();
+    MT_Scalar v1dv2 = v1.dot(v2);
+    MT_Scalar v2dv2 = v2.length2();
+    MT_Scalar p0dv1 = p0.dot(v1); 
+    MT_Scalar p0dv2 = p0.dot(v2);
+    
+    m_det = v1dv1 * v2dv2 - v1dv2 * v1dv2; // non-negative
+    m_lambda1 = p0dv2 * v1dv2 - p0dv1 * v2dv2;
+    m_lambda2 = p0dv1 * v1dv2 - p0dv2 * v1dv1; 
+    
+    if (m_det > MT_Scalar(0.0)) {	
+	m_closest = p0 + (m_lambda1 * v1 + m_lambda2 * v2) / m_det;
+	m_dist2 = m_closest.length2();
+	return true;
+    }
+    
+    return false;
+} 
+
+void DT_Facet::silhouette(int index, const MT_Vector3& w, 
+			  DT_EdgeBuffer& edgeBuffer) 
+{
+    if (!m_obsolete) {
+		if (m_closest.dot(w) < m_dist2) {
+			edgeBuffer.push_back(DT_Edge(this, index));
+		}	
+	else {
+	    m_obsolete = true; // Facet is visible 
+	    int next = incMod3(index);
+	    m_adjFacets[next]->silhouette(m_adjEdges[next], w, edgeBuffer);
+	    next = incMod3(next);
+	    m_adjFacets[next]->silhouette(m_adjEdges[next], w, edgeBuffer);
+	}
+    }
+}
+
+
diff --git a/extern/solid/src/convex/DT_Facet.h b/extern/solid/src/convex/DT_Facet.h
new file mode 100644
index 00000000000..873706346b8
--- /dev/null
+++ b/extern/solid/src/convex/DT_Facet.h
@@ -0,0 +1,134 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_FACET_H
+#define DT_FACET_H
+
+#include 
+#include 
+
+#include 
+#include 
+
+class DT_Facet;
+
+
+class DT_Edge {
+public:
+    DT_Edge() {}
+    DT_Edge(DT_Facet *facet, int index) : 
+	m_facet(facet), 
+	m_index(index) {}
+
+    DT_Facet *getFacet() const { return m_facet; }
+    int       getIndex() const { return m_index; }
+
+    int getSource() const;
+    int getTarget() const;
+
+private:    
+    DT_Facet *m_facet;
+    int       m_index;
+};
+
+typedef std::vector DT_EdgeBuffer;
+
+
+class DT_Facet {
+public:
+    DT_Facet() {}
+    DT_Facet(int i0, int i1, int i2) 
+	  :	m_obsolete(false) 
+    {
+		m_indices[0] = i0; 
+		m_indices[1] = i1; 
+		m_indices[2] = i2;
+    }
+	
+    int operator[](int i) const { return m_indices[i]; } 
+
+    bool link(int edge0, DT_Facet *facet, int edge1);
+
+    
+    bool isObsolete() const { return m_obsolete; }
+    
+
+    bool computeClosest(const MT_Vector3 *verts);
+    
+    const MT_Vector3& getClosest() const { return m_closest; } 
+    
+    bool isClosestInternal() const
+	{ 
+		return m_lambda1 >= MT_Scalar(0.0) && 
+			m_lambda2 >= MT_Scalar(0.0) && 
+			m_lambda1 + m_lambda2 <= m_det;
+    } 
+
+    MT_Scalar getDist2() const { return m_dist2; }
+	
+    MT_Point3 getClosestPoint(const MT_Point3 *points) const 
+	{
+		const MT_Point3& p0 = points[m_indices[0]];
+		
+		return p0 + (m_lambda1 * (points[m_indices[1]] - p0) + 
+					 m_lambda2 * (points[m_indices[2]] - p0)) / m_det;
+    }
+    
+    void silhouette(const MT_Vector3& w, DT_EdgeBuffer& edgeBuffer) 
+	{
+		edgeBuffer.clear();
+		m_obsolete = true;
+		m_adjFacets[0]->silhouette(m_adjEdges[0], w, edgeBuffer);
+		m_adjFacets[1]->silhouette(m_adjEdges[1], w, edgeBuffer);
+		m_adjFacets[2]->silhouette(m_adjEdges[2], w, edgeBuffer);
+    }
+	
+private:
+    void silhouette(int index, const MT_Vector3& w, DT_EdgeBuffer& edgeBuffer);
+	
+    int         m_indices[3];
+    bool        m_obsolete;
+    DT_Facet   *m_adjFacets[3];
+    int         m_adjEdges[3];
+	
+    MT_Scalar   m_det;
+    MT_Scalar   m_lambda1;
+    MT_Scalar   m_lambda2;
+    MT_Vector3  m_closest;
+    MT_Scalar   m_dist2;
+};
+
+
+inline int incMod3(int i) { return ++i % 3; } 
+
+inline int DT_Edge::getSource() const 
+{
+    return (*m_facet)[m_index];
+}
+
+inline int DT_Edge::getTarget() const 
+{
+    return (*m_facet)[incMod3(m_index)];
+}
+
+#endif
diff --git a/extern/solid/src/convex/DT_GJK.h b/extern/solid/src/convex/DT_GJK.h
new file mode 100644
index 00000000000..d8f44acf85e
--- /dev/null
+++ b/extern/solid/src/convex/DT_GJK.h
@@ -0,0 +1,438 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_GJK_H
+#define DT_GJK_H
+
+//#define USE_BACKUP_PROCEDURE
+#define JOHNSON_ROBUST
+#define FAST_CLOSEST
+
+#include "MT_Point3.h"
+#include "MT_Vector3.h"
+#include "GEN_MinMax.h"
+#include "DT_Accuracy.h"
+
+
+class DT_GJK {
+private:
+	typedef unsigned int T_Bits;
+	inline static bool subseteq(T_Bits a, T_Bits b) { return (a & b) == a; }
+	inline static bool contains(T_Bits a, T_Bits b) { return (a & b) != 0x0; }
+
+public:
+	DT_GJK() :
+		m_bits(0x0),
+		m_all_bits(0x0)
+	{}
+
+	bool emptySimplex() const { return m_bits == 0x0; }
+	bool fullSimplex() const { return m_bits == 0xf; }
+
+	void reset() 
+	{
+		m_bits = 0x0;
+		m_all_bits = 0x0;	
+	}
+
+	bool inSimplex(const MT_Vector3& w) 
+	{
+		int i;
+		T_Bits bit;
+		for (i = 0, bit = 0x1; i < 4; ++i, bit <<= 1)
+		{
+			if (contains(m_all_bits, bit) && w == m_y[i])
+			{
+				return true;
+			}
+		}
+		return false;
+	}
+
+	void addVertex(const MT_Vector3& w) 
+	{
+		assert(!fullSimplex());
+		m_last = 0;
+        m_last_bit = 0x1;
+        while (contains(m_bits, m_last_bit)) 
+		{ 
+			++m_last; 
+			m_last_bit <<= 1; 
+		}
+		m_y[m_last] = w;
+		m_ylen2[m_last] = w.length2();
+        m_all_bits = m_bits | m_last_bit;
+
+		update_cache();
+		compute_det();
+	}
+
+	void addVertex(const MT_Vector3& w, const MT_Point3& p, const MT_Point3& q)
+	{
+		addVertex(w);
+		m_p[m_last] = p;
+		m_q[m_last] = q;
+	}
+
+	int getSimplex(MT_Point3 *pBuf, MT_Point3 *qBuf, MT_Vector3 *yBuf) const 
+	{
+		int num_verts = 0;
+		int i;
+		T_Bits bit;
+		for (i = 0, bit = 0x1; i < 4; ++i, bit <<= 1) 
+		{
+			if (contains(m_bits, bit)) 
+			{
+				pBuf[num_verts] = m_p[i];
+				qBuf[num_verts] = m_q[i];
+				yBuf[num_verts] = m_y[i];
+				
+#ifdef DEBUG
+				std::cout << "Point " << i << " = " << m_y[i] << std::endl;
+#endif
+				
+				++num_verts;
+			}
+		}
+		return num_verts;
+    }
+
+	void compute_points(MT_Point3& p1, MT_Point3& p2) 
+	{
+		MT_Scalar sum = MT_Scalar(0.0);
+		p1.setValue(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0));
+		p2.setValue(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0));
+		int i;
+		T_Bits bit;
+		for (i = 0, bit = 0x1; i < 4; ++i, bit <<= 1) 
+		{
+			if (contains(m_bits, bit))
+			{
+				sum += m_det[m_bits][i];
+				p1 += m_p[i] * m_det[m_bits][i];
+				p2 += m_q[i] * m_det[m_bits][i];
+			}
+		}
+
+		assert(sum > MT_Scalar(0.0));
+		MT_Scalar s = MT_Scalar(1.0) / sum;
+		p1 *= s;
+		p2 *= s;
+	}
+
+	bool closest(MT_Vector3& v) 
+	{
+#ifdef FAST_CLOSEST
+		T_Bits s;
+		for (s = m_bits; s != 0x0; --s)
+		{
+			if (subseteq(s, m_bits) && valid(s | m_last_bit)) 
+			{
+				m_bits = s | m_last_bit;
+				compute_vector(m_bits, v);
+				return true;
+			}
+		}
+		if (valid(m_last_bit)) 
+		{
+			m_bits = m_last_bit;
+			m_maxlen2 = m_ylen2[m_last];
+			v = m_y[m_last];
+			return true;
+		}
+#else
+		T_Bits s;
+		for (s = m_all_bits; s != 0x0; --s)
+		{
+			if (subseteq(s, m_all_bits) && valid(s)) 
+			{
+				m_bits = s;
+				compute_vector(m_bits, v);
+				return true;
+			}
+		}
+#endif
+		
+		// Original GJK calls the backup procedure at this point.
+#ifdef USE_BACKUP_PROCEDURE
+		backup_closest(MT_Vector3& v); 
+#endif
+		return false;  
+	}
+
+	void backup_closest(MT_Vector3& v)
+	{ 		
+		MT_Scalar min_dist2 = MT_INFINITY;
+		
+      T_Bits s;
+		for (s = m_all_bits; s != 0x0; --s) 
+		{
+			if (subseteq(s, m_all_bits) && proper(s))
+			{	
+				MT_Vector3 u;
+				compute_vector(s, u);
+				MT_Scalar dist2 = u.length2();
+				if (dist2 < min_dist2)
+				{
+					min_dist2 = dist2;
+					m_bits = s;
+					v = u;
+				}
+			}
+		}
+	}
+	
+	MT_Scalar maxVertex() { return m_maxlen2; }
+
+
+private:
+	void update_cache();
+	void compute_det();
+
+	bool valid(T_Bits s) 
+	{
+		int i;
+		T_Bits bit;
+		for (i = 0, bit = 0x1; i < 4; ++i, bit <<= 1)
+		{
+			if (contains(m_all_bits, bit)) 
+			{
+				if (contains(s, bit)) 
+				{
+					if (m_det[s][i] <= MT_Scalar(0.0)) 
+					{
+						return false; 
+					}
+				}
+				else if (m_det[s | bit][i] > MT_Scalar(0.0))
+				{ 
+					return false;
+				}
+			}
+		}
+		return true;
+	}
+
+	bool proper(T_Bits s)
+	{ 
+		int i;
+		T_Bits bit;
+		for (i = 0, bit = 0x1; i < 4; ++i, bit <<= 1)
+		{
+			if (contains(s, bit) && m_det[s][i] <= MT_Scalar(0.0))
+			{
+				return false; 
+			}
+		}
+		return true;
+	}
+
+	void compute_vector(T_Bits s, MT_Vector3& v) 
+	{
+		m_maxlen2 = MT_Scalar(0.0);
+		MT_Scalar sum = MT_Scalar(0.0);
+		v .setValue(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0));
+
+		int i;
+		T_Bits bit;
+		for (i = 0, bit = 0x1; i < 4; ++i, bit <<= 1) 
+		{
+			if (contains(s, bit))
+			{
+				sum += m_det[s][i];
+				GEN_set_max(m_maxlen2, m_ylen2[i]);
+				v += m_y[i] * m_det[s][i];
+			}
+		}
+		
+		assert(sum > MT_Scalar(0.0));
+
+		v /= sum;
+	}
+ 
+private:
+	MT_Scalar	m_det[16][4]; // cached sub-determinants
+    MT_Vector3	m_edge[4][4];
+
+#ifdef JOHNSON_ROBUST
+    MT_Scalar	m_norm[4][4];
+#endif
+
+	MT_Point3	m_p[4];    // support points of object A in local coordinates 
+	MT_Point3	m_q[4];    // support points of object B in local coordinates 
+	MT_Vector3	m_y[4];   // support points of A - B in world coordinates
+	MT_Scalar	m_ylen2[4];   // Squared lengths support points y
+
+	MT_Scalar	m_maxlen2; // Maximum squared length to a vertex of the current 
+	                      // simplex
+	T_Bits		m_bits;      // identifies current simplex
+	T_Bits		m_last;      // identifies last found support point
+	T_Bits		m_last_bit;  // m_last_bit == 0x1 << last
+	T_Bits		m_all_bits;  // m_all_bits == m_bits  | m_last_bit 
+};
+
+
+
+
+inline void DT_GJK::update_cache() 
+{
+	int i;
+	T_Bits bit;
+    for (i = 0, bit = 0x1; i < 4; ++i, bit <<= 1)
+	{
+        if (contains(m_bits, bit)) 
+		{
+			m_edge[i][m_last] = m_y[i] - m_y[m_last];
+			m_edge[m_last][i] = -m_edge[i][m_last];
+
+#ifdef JOHNSON_ROBUST
+			m_norm[i][m_last] = m_norm[m_last][i] = m_edge[i][m_last].length2();
+#endif
+
+		}
+	}
+}
+
+#ifdef JOHNSON_ROBUST
+
+inline void DT_GJK::compute_det() 
+{
+    m_det[m_last_bit][m_last] = 1;
+
+	int i;
+	T_Bits si;
+    for (i = 0, si = 0x1; i < 4; ++i, si <<= 1) 
+	{
+        if (contains(m_bits, si)) 
+		{
+            T_Bits s2 = si | m_last_bit;
+            m_det[s2][i] = m_edge[m_last][i].dot(m_y[m_last]); 
+            m_det[s2][m_last] = m_edge[i][m_last].dot(m_y[i]);
+
+			int j;
+			T_Bits sj;
+            for (j = 0, sj = 0x1; j < i; ++j, sj <<= 1) 
+			{
+                if (contains(m_bits, sj)) 
+				{
+					int k;
+                    T_Bits s3 = sj | s2;			
+					
+					k = m_norm[i][j] < m_norm[m_last][j] ? i : m_last;
+                    m_det[s3][j] = m_det[s2][i] * m_edge[k][j].dot(m_y[i]) + 
+                                   m_det[s2][m_last] * m_edge[k][j].dot(m_y[m_last]);
+					k = m_norm[j][i] < m_norm[m_last][i] ? j : m_last;
+                    m_det[s3][i] = m_det[sj|m_last_bit][j] * m_edge[k][i].dot(m_y[j]) +  
+                                   m_det[sj|m_last_bit][m_last] * m_edge[k][i].dot(m_y[m_last]);
+					k = m_norm[i][m_last] < m_norm[j][m_last] ? i : j;
+                    m_det[s3][m_last] = m_det[sj|si][j] * m_edge[k][m_last].dot(m_y[j]) + 
+                                        m_det[sj|si][i] * m_edge[k][m_last].dot(m_y[i]);
+                }
+            }
+        }
+    }
+
+    if (m_all_bits == 0xf) 
+	{
+		int k;
+
+		k = m_norm[1][0] < m_norm[2][0] ? (m_norm[1][0] < m_norm[3][0] ? 1 : 3) : (m_norm[2][0] < m_norm[3][0] ? 2 : 3);
+		
+        m_det[0xf][0] = m_det[0xe][1] * m_edge[k][0].dot(m_y[1]) + 
+                        m_det[0xe][2] * m_edge[k][0].dot(m_y[2]) + 
+                        m_det[0xe][3] * m_edge[k][0].dot(m_y[3]);
+
+		k = m_norm[0][1] < m_norm[2][1] ? (m_norm[0][1] < m_norm[3][1] ? 0 : 3) : (m_norm[2][1] < m_norm[3][1] ? 2 : 3);
+		
+        m_det[0xf][1] = m_det[0xd][0] * m_edge[k][1].dot(m_y[0]) + 
+                        m_det[0xd][2] * m_edge[k][1].dot(m_y[2]) +
+                        m_det[0xd][3] * m_edge[k][1].dot(m_y[3]);
+
+		k = m_norm[0][2] < m_norm[1][2] ? (m_norm[0][2] < m_norm[3][2] ? 0 : 3) : (m_norm[1][2] < m_norm[3][2] ? 1 : 3);
+		
+        m_det[0xf][2] = m_det[0xb][0] * m_edge[k][2].dot(m_y[0]) + 
+                        m_det[0xb][1] * m_edge[k][2].dot(m_y[1]) +  
+                        m_det[0xb][3] * m_edge[k][2].dot(m_y[3]);
+
+		k = m_norm[0][3] < m_norm[1][3] ? (m_norm[0][3] < m_norm[2][3] ? 0 : 2) : (m_norm[1][3] < m_norm[2][3] ? 1 : 2);
+		
+        m_det[0xf][3] = m_det[0x7][0] * m_edge[k][3].dot(m_y[0]) + 
+                        m_det[0x7][1] * m_edge[k][3].dot(m_y[1]) + 
+                        m_det[0x7][2] * m_edge[k][3].dot(m_y[2]);
+    }
+}
+
+#else
+
+inline void DT_GJK::compute_det() 
+{
+    m_det[m_last_bit][m_last] = 1;
+
+	int i;
+	T_Bits si;
+    for (i = 0, si = 0x1; i < 4; ++i, si <<= 1) 
+	{
+        if (contains(m_bits, si)) 
+		{
+            T_Bits s2 = si | m_last_bit;
+            m_det[s2][i] = m_edge[m_last][i].dot(m_y[m_last]); 
+            m_det[s2][m_last] = m_edge[i][m_last].dot(m_y[i]);
+
+			int j;
+			T_Bits sj;
+            for (j = 0, sj = 0x1; j < i; ++j, sj <<= 1)
+			{
+                if (contains(m_bits, sj)) 
+				{
+                    T_Bits s3 = sj | s2;
+                    m_det[s3][j] = m_det[s2][i] * m_edge[i][j].dot(m_y[i]) + 
+                                   m_det[s2][m_last] * m_edge[i][j].dot(m_y[m_last]);
+                    m_det[s3][i] = m_det[sj|m_last_bit][j] * m_edge[j][i].dot(m_y[j]) +  
+                                   m_det[sj|m_last_bit][m_last] * m_edge[j][i].dot(m_y[m_last]);
+                    m_det[s3][m_last] = m_det[sj|si][j] * m_edge[j][m_last].dot(m_y[j]) + 
+                                        m_det[sj|si][i] * m_edge[j][m_last].dot(m_y[i]);
+                }
+            }
+        }
+    }
+
+    if (m_all_bits == 0xf) 
+	{
+        m_det[0xf][0] = m_det[0xe][1] * m_edge[1][0].dot(m_y[1]) + 
+                        m_det[0xe][2] * m_edge[1][0].dot(m_y[2]) + 
+                        m_det[0xe][3] * m_edge[1][0].dot(m_y[3]);
+        m_det[0xf][1] = m_det[0xd][0] * m_edge[0][1].dot(m_y[0]) + 
+                        m_det[0xd][2] * m_edge[0][1].dot(m_y[2]) +
+                        m_det[0xd][3] * m_edge[0][1].dot(m_y[3]);
+        m_det[0xf][2] = m_det[0xb][0] * m_edge[0][2].dot(m_y[0]) + 
+                        m_det[0xb][1] * m_edge[0][2].dot(m_y[1]) +  
+                        m_det[0xb][3] * m_edge[0][2].dot(m_y[3]);
+        m_det[0xf][3] = m_det[0x7][0] * m_edge[0][3].dot(m_y[0]) + 
+                        m_det[0x7][1] * m_edge[0][3].dot(m_y[1]) + 
+                        m_det[0x7][2] * m_edge[0][3].dot(m_y[2]);
+    }
+}
+
+#endif
+
+#endif
diff --git a/extern/solid/src/convex/DT_Hull.h b/extern/solid/src/convex/DT_Hull.h
new file mode 100644
index 00000000000..a5bf56ae59d
--- /dev/null
+++ b/extern/solid/src/convex/DT_Hull.h
@@ -0,0 +1,53 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_HULL_H
+#define DT_HULL_H
+
+#include "DT_Convex.h"
+
+class DT_Hull : public DT_Convex {
+public:
+	DT_Hull(const DT_Convex& lchild, const DT_Convex& rchild) :
+		m_lchild(lchild), 
+		m_rchild(rchild) 
+	{}
+
+	virtual MT_Scalar supportH(const MT_Vector3& v) const 
+	{
+		return GEN_max(m_lchild.supportH(v), m_rchild.supportH(v));
+	}
+
+	virtual MT_Point3 support(const MT_Vector3& v) const 
+	{
+		MT_Point3 lpnt = m_lchild.support(v);
+		MT_Point3 rpnt = m_rchild.support(v);
+		return v.dot(lpnt) > v.dot(rpnt) ? lpnt : rpnt;
+	}
+
+private:
+	const DT_Convex& m_lchild;
+	const DT_Convex& m_rchild;
+};
+
+#endif
diff --git a/extern/solid/src/convex/DT_IndexArray.h b/extern/solid/src/convex/DT_IndexArray.h
new file mode 100644
index 00000000000..95551fa8483
--- /dev/null
+++ b/extern/solid/src/convex/DT_IndexArray.h
@@ -0,0 +1,33 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_INDEXARRAY_H
+#define DT_INDEXARRAY_H
+
+#include "SOLID_types.h"
+#include "DT_Array.h"
+
+typedef DT_Array DT_IndexArray;
+
+#endif
+
diff --git a/extern/solid/src/convex/DT_LineSegment.cpp b/extern/solid/src/convex/DT_LineSegment.cpp
new file mode 100644
index 00000000000..6c7ccf6b9b7
--- /dev/null
+++ b/extern/solid/src/convex/DT_LineSegment.cpp
@@ -0,0 +1,36 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_LineSegment.h"
+
+MT_Scalar DT_LineSegment::supportH(const MT_Vector3& v) const
+{
+    return GEN_max(v.dot(m_source), v.dot(m_target));
+}
+
+MT_Point3 DT_LineSegment::support(const MT_Vector3& v) const
+{
+    return v.dot(m_source) > v.dot(m_target) ?	m_source : m_target;
+}
+
+
diff --git a/extern/solid/src/convex/DT_LineSegment.h b/extern/solid/src/convex/DT_LineSegment.h
new file mode 100644
index 00000000000..979ff8a18a9
--- /dev/null
+++ b/extern/solid/src/convex/DT_LineSegment.h
@@ -0,0 +1,52 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_LINESEGMENT_H
+#define DT_LINESEGMENT_H
+
+#include "DT_Convex.h"
+
+class DT_LineSegment : public DT_Convex {
+public:
+    DT_LineSegment(const MT_Point3& source, const MT_Point3& target) : 
+	   m_source(source), 
+	   m_target(target) {}
+
+    virtual MT_Scalar supportH(const MT_Vector3& v) const;
+    virtual MT_Point3 support(const MT_Vector3& v) const;
+
+	const MT_Point3& getSource() const { return m_source; }
+	const MT_Point3& getTarget() const { return m_target; }
+
+private:
+	MT_Point3 m_source;
+	MT_Point3 m_target;
+};
+
+#endif
+
+
+
+
+
+
diff --git a/extern/solid/src/convex/DT_Minkowski.h b/extern/solid/src/convex/DT_Minkowski.h
new file mode 100644
index 00000000000..e90fed6a8e0
--- /dev/null
+++ b/extern/solid/src/convex/DT_Minkowski.h
@@ -0,0 +1,51 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_MINKOWSKI_H
+#define DT_MINKOWSKI_H
+
+#include "DT_Convex.h"
+
+class DT_Minkowski : public DT_Convex {
+public:
+	DT_Minkowski(const DT_Convex& lchild, const DT_Convex& rchild) 
+     : m_lchild(lchild), 
+       m_rchild(rchild) 
+   {}
+
+	virtual MT_Scalar supportH(const MT_Vector3& v) const 
+	{
+		return m_lchild.supportH(v) + m_rchild.supportH(v); 
+	}
+
+	virtual MT_Point3 support(const MT_Vector3& v) const 
+	{
+		return m_lchild.support(v) + (MT_Vector3)m_rchild.support(v); 
+	}
+
+private:
+	const DT_Convex& m_lchild;
+	const DT_Convex& m_rchild;
+};
+
+#endif
diff --git a/extern/solid/src/convex/DT_PenDepth.cpp b/extern/solid/src/convex/DT_PenDepth.cpp
new file mode 100644
index 00000000000..e1c5c9a3949
--- /dev/null
+++ b/extern/solid/src/convex/DT_PenDepth.cpp
@@ -0,0 +1,376 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_PenDepth.h"
+
+#include "MT_Vector3.h"
+#include "MT_Point3.h"
+#include "MT_Quaternion.h"
+#include "DT_Convex.h"
+#include "DT_GJK.h"
+#include "DT_Facet.h"
+
+//#define DEBUG
+
+const int       MaxSupportPoints = 1000;
+const int       MaxFacets         = 2000;
+
+static MT_Point3  pBuf[MaxSupportPoints];
+static MT_Point3  qBuf[MaxSupportPoints];
+static MT_Vector3 yBuf[MaxSupportPoints];
+
+static DT_Facet facetBuf[MaxFacets];
+static int  freeFacet = 0;
+static DT_Facet *facetHeap[MaxFacets];
+static int  num_facets;
+
+class DT_FacetComp {
+public:
+    
+    bool operator()(const DT_Facet *face1, const DT_Facet *face2) 
+	{ 
+		return face1->getDist2() > face2->getDist2();
+    }
+    
+} facetComp;
+
+inline DT_Facet *addFacet(int i0, int i1, int i2,
+						  MT_Scalar lower2, MT_Scalar upper2) 
+{
+    assert(i0 != i1 && i0 != i2 && i1 != i2);
+    if (freeFacet < MaxFacets)
+	{
+		DT_Facet *facet = new(&facetBuf[freeFacet++]) DT_Facet(i0, i1, i2);
+#ifdef DEBUG
+		std::cout << "Facet " << i0 << ' ' << i1 << ' ' << i2;
+#endif
+		if (facet->computeClosest(yBuf)) 
+		{
+			if (facet->isClosestInternal() && 
+				lower2 <= facet->getDist2() && facet->getDist2() <= upper2) 
+			{
+				facetHeap[num_facets++] = facet;
+				std::push_heap(&facetHeap[0], &facetHeap[num_facets], facetComp);
+#ifdef DEBUG
+				std::cout << " accepted" << std::endl;
+#endif
+			}
+			else 
+			{
+#ifdef DEBUG
+				std::cout << " rejected, ";
+				if (!facet->isClosestInternal()) 
+				{
+					std::cout << "closest point not internal";
+				}
+				else if (lower2 > facet->getDist2()) 
+				{
+					std::cout << "facet is closer than orignal facet";
+				}
+				else 
+				{
+					std::cout << "facet is further than upper bound";
+				}
+				std::cout << std::endl;
+#endif
+			}
+			
+			return facet;
+		}
+    }
+    
+    return 0;
+}
+
+inline bool originInTetrahedron(const MT_Vector3& p1, const MT_Vector3& p2, 
+								const MT_Vector3& p3, const MT_Vector3& p4)
+{
+    MT_Vector3 normal1 = (p2 - p1).cross(p3 - p1);
+    MT_Vector3 normal2 = (p3 - p2).cross(p4 - p2);
+    MT_Vector3 normal3 = (p4 - p3).cross(p1 - p3);
+    MT_Vector3 normal4 = (p1 - p4).cross(p2 - p4);
+    
+    return 
+		normal1.dot(p1) > MT_Scalar(0.0) != normal1.dot(p4) > MT_Scalar(0.0) &&
+		normal2.dot(p2) > MT_Scalar(0.0) != normal2.dot(p1) > MT_Scalar(0.0) &&
+		normal3.dot(p3) > MT_Scalar(0.0) != normal3.dot(p2) > MT_Scalar(0.0) &&
+		normal4.dot(p4) > MT_Scalar(0.0) != normal4.dot(p3) > MT_Scalar(0.0);
+}
+
+
+bool penDepth(const DT_GJK& gjk, const DT_Convex& a, const DT_Convex& b,
+			  MT_Vector3& v, MT_Point3& pa, MT_Point3& pb)
+{
+	
+    int num_verts = gjk.getSimplex(pBuf, qBuf, yBuf);
+    
+    switch (num_verts) 
+	{
+	case 1:
+	    // Touching contact. Yes, we have a collision,
+	    // but no penetration.
+	    return false;
+	case 2:	
+	{
+	    // We have a line segment inside the Minkowski sum containing the
+	    // origin. Blow it up by adding three additional support points.
+	    
+	    MT_Vector3 dir  = (yBuf[1] - yBuf[0]).normalized();
+	    int        axis = dir.furthestAxis();
+	    
+	    static MT_Scalar sin_60 = MT_sqrt(MT_Scalar(3.0)) * MT_Scalar(0.5);
+	    
+	    MT_Quaternion rot(dir[0] * sin_60, dir[1] * sin_60, dir[2] * sin_60, MT_Scalar(0.5));
+	    MT_Matrix3x3 rot_mat(rot);
+	    
+	    MT_Vector3 aux1 = dir.cross(MT_Vector3(axis == 0, axis == 1, axis == 2));
+	    MT_Vector3 aux2 = rot_mat * aux1;
+	    MT_Vector3 aux3 = rot_mat * aux2;
+	    
+	    pBuf[2] = a.support(aux1);
+	    qBuf[2] = b.support(-aux1);
+	    yBuf[2] = pBuf[2] - qBuf[2];
+	    
+	    pBuf[3] = a.support(aux2);
+	    qBuf[3] = b.support(-aux2);
+	    yBuf[3] = pBuf[3] - qBuf[3];
+	    
+	    pBuf[4] = a.support(aux3);
+	    qBuf[4] = b.support(-aux3);
+	    yBuf[4] = pBuf[4] - qBuf[4];
+	    
+	    if (originInTetrahedron(yBuf[0], yBuf[2], yBuf[3], yBuf[4])) 
+		{
+			pBuf[1] = pBuf[4];
+			qBuf[1] = qBuf[4];
+			yBuf[1] = yBuf[4];
+	    }
+	    else if (originInTetrahedron(yBuf[1], yBuf[2], yBuf[3], yBuf[4])) 
+		{
+			pBuf[0] = pBuf[4];
+			qBuf[0] = qBuf[4];
+			yBuf[0] = yBuf[4];
+	    } 
+	    else 
+		{
+			// Origin not in initial polytope
+			return false;
+	    }
+	    
+	    num_verts = 4;
+	    
+	    break;
+	}
+	case 3: 
+	{
+	    // We have a triangle inside the Minkowski sum containing
+	    // the origin. First blow it up.
+	    
+	    MT_Vector3 v1     = yBuf[1] - yBuf[0];
+	    MT_Vector3 v2     = yBuf[2] - yBuf[0];
+	    MT_Vector3 vv     = v1.cross(v2);
+	    
+	    pBuf[3] = a.support(vv);
+	    qBuf[3] = b.support(-vv);
+	    yBuf[3] = pBuf[3] - qBuf[3];
+	    pBuf[4] = a.support(-vv);
+	    qBuf[4] = b.support(vv);
+	    yBuf[4] = pBuf[4] - qBuf[4];
+	    
+	   
+	    if (originInTetrahedron(yBuf[0], yBuf[1], yBuf[2], yBuf[4])) 
+		{
+			pBuf[3] = pBuf[4];
+			qBuf[3] = qBuf[4];
+			yBuf[3] = yBuf[4];
+	    }
+	    else if (!originInTetrahedron(yBuf[0], yBuf[1], yBuf[2], yBuf[3]))
+		{ 
+			// Origin not in initial polytope
+			return false;
+	    }
+	    
+	    num_verts = 4;
+	    
+	    break;
+	}
+    }
+    
+    // We have a tetrahedron inside the Minkowski sum containing
+    // the origin (if GJK did it's job right ;-)
+      
+    
+    if (!originInTetrahedron(yBuf[0], yBuf[1], yBuf[2], yBuf[3])) 
+	{
+		//	assert(false);
+		return false;
+	}
+    
+	num_facets = 0;
+    freeFacet = 0;
+
+    DT_Facet *f0 = addFacet(0, 1, 2, MT_Scalar(0.0), MT_INFINITY);
+    DT_Facet *f1 = addFacet(0, 3, 1, MT_Scalar(0.0), MT_INFINITY);
+    DT_Facet *f2 = addFacet(0, 2, 3, MT_Scalar(0.0), MT_INFINITY);
+    DT_Facet *f3 = addFacet(1, 3, 2, MT_Scalar(0.0), MT_INFINITY);
+    
+    if (!f0 || f0->getDist2() == MT_Scalar(0.0) ||
+		!f1 || f1->getDist2() == MT_Scalar(0.0) ||
+		!f2 || f2->getDist2() == MT_Scalar(0.0) ||
+		!f3 || f3->getDist2() == MT_Scalar(0.0)) 
+	{
+		return false;
+    }
+    
+    f0->link(0, f1, 2);
+    f0->link(1, f3, 2);
+    f0->link(2, f2, 0);
+    f1->link(0, f2, 2);
+    f1->link(1, f3, 0);
+    f2->link(1, f3, 1);
+    
+    if (num_facets == 0) 
+	{
+		return false;
+    }
+    
+    // at least one facet on the heap.	
+    
+    DT_EdgeBuffer edgeBuffer(20);
+
+    DT_Facet *facet = 0;
+    
+    MT_Scalar upper_bound2 = MT_INFINITY; 	
+    
+    do {
+        facet = facetHeap[0];
+        std::pop_heap(&facetHeap[0], &facetHeap[num_facets], facetComp);
+        --num_facets;
+		
+		if (!facet->isObsolete()) 
+		{
+			assert(facet->getDist2() > MT_Scalar(0.0));
+			
+			if (num_verts == MaxSupportPoints)
+			{
+#ifdef DEBUG
+				std::cout << "Ouch, no convergence!!!" << std::endl;
+#endif 
+				assert(false);	
+				break;
+			}
+			
+			pBuf[num_verts] = a.support(facet->getClosest());
+			qBuf[num_verts] = b.support(-facet->getClosest());
+			yBuf[num_verts] = pBuf[num_verts] - qBuf[num_verts];
+			
+			int index = num_verts++;
+			MT_Scalar far_dist2 = yBuf[index].dot(facet->getClosest());
+			
+			// Make sure the support mapping is OK.
+			assert(far_dist2 > MT_Scalar(0.0));
+			
+			GEN_set_min(upper_bound2, far_dist2 * far_dist2 / facet->getDist2());
+			
+			if (upper_bound2 <= DT_Accuracy::depth_tolerance * facet->getDist2()
+#define CHECK_NEW_SUPPORT
+#ifdef CHECK_NEW_SUPPORT
+				|| yBuf[index] == yBuf[(*facet)[0]] 
+				|| yBuf[index] == yBuf[(*facet)[1]]
+				|| yBuf[index] == yBuf[(*facet)[2]]
+#endif
+				) 
+			{
+				break;
+			}
+			
+			// Compute the silhouette cast by the new vertex
+			// Note that the new vertex is on the positive side
+			// of the current facet, so the current facet is will
+			// not be in the convex hull. Start local search
+			// from this facet.
+			
+			facet->silhouette(yBuf[index], edgeBuffer);
+			
+			if (edgeBuffer.empty()) 
+			{
+				return false;
+			}
+			
+			DT_EdgeBuffer::const_iterator it = edgeBuffer.begin();
+			DT_Facet *firstFacet = 
+				addFacet((*it).getTarget(), (*it).getSource(),
+						 index, facet->getDist2(), upper_bound2);
+			
+			if (!firstFacet) 
+			{
+				break;
+			}
+			
+			firstFacet->link(0, (*it).getFacet(), (*it).getIndex());
+			DT_Facet *lastFacet = firstFacet;
+			
+			++it;
+			for (; it != edgeBuffer.end(); ++it) 
+			{
+				DT_Facet *newFacet = 
+					addFacet((*it).getTarget(), (*it).getSource(),
+							 index, facet->getDist2(), upper_bound2);
+				
+				if (!newFacet) 
+				{
+					break;
+				}
+				
+				if (!newFacet->link(0, (*it).getFacet(), (*it).getIndex())) 
+				{
+					break;
+				}
+				
+				if (!newFacet->link(2, lastFacet, 1)) 
+				{
+					break;
+				}
+				
+				lastFacet = newFacet;				
+			}
+			if (it != edgeBuffer.end()) 
+			{
+				break;
+			}
+			
+			firstFacet->link(2, lastFacet, 1);
+		}
+    }
+    while (num_facets > 0 && facetHeap[0]->getDist2() <= upper_bound2);
+	
+#ifdef DEBUG    
+    std::cout << "#facets left = " << num_facets << std::endl;
+#endif
+    
+    v = facet->getClosest();
+    pa = facet->getClosestPoint(pBuf);    
+    pb = facet->getClosestPoint(qBuf);    
+    return true;
+}
+
diff --git a/extern/solid/src/convex/DT_PenDepth.h b/extern/solid/src/convex/DT_PenDepth.h
new file mode 100644
index 00000000000..97b3c6c0e0e
--- /dev/null
+++ b/extern/solid/src/convex/DT_PenDepth.h
@@ -0,0 +1,36 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_PENDEPTH_H
+#define DT_PENDEPTH_H
+
+#include "MT_Vector3.h"
+#include "MT_Point3.h"
+
+class DT_GJK;
+class DT_Convex;
+
+bool penDepth(const DT_GJK& gjk, const DT_Convex& a, const DT_Convex& b, 
+			  MT_Vector3& v, MT_Point3& pa, MT_Point3& pb);
+
+#endif
diff --git a/extern/solid/src/convex/DT_Point.cpp b/extern/solid/src/convex/DT_Point.cpp
new file mode 100644
index 00000000000..770fe7775b7
--- /dev/null
+++ b/extern/solid/src/convex/DT_Point.cpp
@@ -0,0 +1,36 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_Point.h"
+
+MT_Scalar DT_Point::supportH(const MT_Vector3& v) const
+{
+    return v.dot(m_point);
+}
+
+MT_Point3 DT_Point::support(const MT_Vector3& v) const
+{
+    return m_point;
+}
+
+
diff --git a/extern/solid/src/convex/DT_Point.h b/extern/solid/src/convex/DT_Point.h
new file mode 100644
index 00000000000..b35d158ee53
--- /dev/null
+++ b/extern/solid/src/convex/DT_Point.h
@@ -0,0 +1,46 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_POINT_H
+#define DT_POINT_H
+
+#include "DT_Convex.h"
+
+class DT_Point : public DT_Convex {
+public:
+    DT_Point(const MT_Point3& point) : m_point(point) {}
+
+    virtual MT_Scalar supportH(const MT_Vector3& v) const;
+    virtual MT_Point3 support(const MT_Vector3& v) const;
+
+private:
+	MT_Point3 m_point;
+};
+
+#endif
+
+
+
+
+
+
diff --git a/extern/solid/src/convex/DT_Polyhedron.cpp b/extern/solid/src/convex/DT_Polyhedron.cpp
new file mode 100644
index 00000000000..f48ac6e4b6d
--- /dev/null
+++ b/extern/solid/src/convex/DT_Polyhedron.cpp
@@ -0,0 +1,415 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_Polyhedron.h"
+
+#ifdef QHULL
+
+extern "C" {
+#include 
+}
+
+#include 
+#include   
+
+typedef std::vector T_VertexBuf;
+typedef std::vector T_IndexBuf;
+typedef std::vector T_MultiIndexBuf;
+
+static char options[] = "qhull Qts i Tv";
+
+#define DK_HIERARCHY
+
+T_IndexBuf *adjacency_graph(DT_Count count, const MT_Point3 *verts, const char *flags)
+{
+	int curlong, totlong, exitcode;
+	
+    facetT *facet;
+    vertexT *vertex;
+    vertexT **vertexp;
+    
+    std::vector > array;
+	T_IndexBuf index;
+    DT_Index i;
+    for (i = 0; i != count; ++i) 
+	{
+		if (flags == 0 || flags[i])
+		{
+            array.push_back(MT::Tuple3(verts[i]));
+			index.push_back(i);
+		}
+    }
+
+    qh_init_A(stdin, stdout, stderr, 0, NULL);
+    if ((exitcode = setjmp(qh errexit))) 
+	{
+		exit(exitcode);
+	}
+    qh_initflags(options);
+    qh_init_B(array[0], array.size(), 3, False);
+    qh_qhull();
+    qh_check_output();
+    
+    T_IndexBuf *indexBuf = new T_IndexBuf[count];
+    FORALLfacets 
+	{
+		setT *vertices = qh_facet3vertex(facet);
+		
+		T_IndexBuf  facetIndices;
+
+		FOREACHvertex_(vertices) 
+		{
+			facetIndices.push_back(index[qh_pointid(vertex->point)]);
+		}
+		int i, j;
+		for (i = 0, j = facetIndices.size()-1; i < (int)facetIndices.size(); j = i++)
+		{
+			indexBuf[facetIndices[j]].push_back(facetIndices[i]);
+		}
+    }
+
+    
+    qh NOerrexit = True;
+    qh_freeqhull(!qh_ALL);
+    qh_memfreeshort(&curlong, &totlong);
+
+	return indexBuf;
+}
+
+T_IndexBuf *simplex_adjacency_graph(DT_Count count, const char *flags)
+{
+	T_IndexBuf *indexBuf = new T_IndexBuf[count];
+
+	DT_Index index[4];
+	
+	DT_Index k = 0;
+	DT_Index i;
+	for (i = 0; i != count; ++i) 
+	{
+		if (flags == 0 || flags[i])
+		{
+			index[k++] = i;
+		}
+	}
+
+	assert(k <= 4);
+
+	for (i = 0; i != k; ++i)
+	{
+		DT_Index j;
+		for (j = 0; j != k; ++j)
+		{
+			if (i != j)
+			{
+				indexBuf[index[i]].push_back(index[j]);
+			}
+		}
+	}
+
+	return indexBuf;
+}
+
+#ifdef DK_HIERARCHY
+
+void prune(DT_Count count, T_MultiIndexBuf *cobound)
+{
+	DT_Index i;
+	for (i = 0; i != count; ++i)
+	{
+		assert(cobound[i].size());
+
+		DT_Index j;
+		for (j = 0; j != cobound[i].size() - 1; ++j)
+		{
+			T_IndexBuf::iterator it = cobound[i][j].begin();
+			while (it != cobound[i][j].end())
+			{
+				T_IndexBuf::iterator jt = 
+					std::find(cobound[i][j+1].begin(), cobound[i][j+1].end(), *it);
+
+				if (jt != cobound[i][j+1].end())
+				{
+					std::swap(*it, cobound[i][j].back());
+					cobound[i][j].pop_back();
+				}
+				else
+				{
+					++it;
+				}
+			}
+		}
+	}	
+}
+
+#endif
+
+DT_Polyhedron::DT_Polyhedron(const DT_VertexBase *base, DT_Count count, const DT_Index *indices)
+{
+	assert(count);
+
+	std::vector vertexBuf;
+	DT_Index i;
+	for (i = 0; i != count; ++i) 
+	{
+		vertexBuf.push_back((*base)[indices[i]]);
+	}
+
+	T_IndexBuf *indexBuf = count > 4 ? adjacency_graph(count, &vertexBuf[0], 0) : simplex_adjacency_graph(count, 0);
+	
+	std::vector pointBuf;
+	
+	for (i = 0; i != count; ++i) 
+	{
+		if (!indexBuf[i].empty()) 
+		{
+			pointBuf.push_back(vertexBuf[i]);
+		}
+	}
+			
+	delete [] indexBuf;
+
+	m_count = pointBuf.size();
+	m_verts = new MT_Point3[m_count];	
+	std::copy(pointBuf.begin(), pointBuf.end(), &m_verts[0]);
+
+	T_MultiIndexBuf *cobound = new T_MultiIndexBuf[m_count];
+    char *flags = new char[m_count];
+	std::fill(&flags[0], &flags[m_count], 1);
+
+	DT_Count num_layers = 0;
+	DT_Count layer_count = m_count;
+	while (layer_count > 4)
+	{
+		T_IndexBuf *indexBuf = adjacency_graph(m_count, m_verts, flags);
+		
+		DT_Index i;
+		for (i = 0; i != m_count; ++i) 
+		{
+			if (flags[i])
+			{
+				assert(!indexBuf[i].empty());
+				cobound[i].push_back(indexBuf[i]);
+			}
+		}
+			
+		++num_layers;
+
+		delete [] indexBuf;
+
+		std::fill(&flags[0], &flags[m_count], 0);
+
+		for (i = 0; i != m_count; ++i)
+		{
+			if (cobound[i].size() == num_layers) 
+			{
+				T_IndexBuf& curr_cobound = cobound[i].back();	
+				if (!flags[i] && curr_cobound.size() <= 8)
+				{	
+					DT_Index j;
+					for (j  = 0; j != curr_cobound.size(); ++j)
+					{
+						flags[curr_cobound[j]] = 1;
+					}
+				}
+			}
+		}
+		
+		layer_count = 0;
+		
+		for (i = 0; i != m_count; ++i)
+		{
+			if (flags[i])
+			{
+				++layer_count;
+			}
+		}	
+	}
+	
+	indexBuf = simplex_adjacency_graph(m_count, flags);
+		
+	for (i = 0; i != m_count; ++i) 
+	{
+		if (flags[i])
+		{
+			assert(!indexBuf[i].empty());
+			cobound[i].push_back(indexBuf[i]);
+		}
+	}
+	
+	++num_layers;
+
+	delete [] indexBuf;
+	delete [] flags;
+		
+
+
+#ifdef DK_HIERARCHY
+	prune(m_count, cobound);
+#endif
+
+	m_cobound = new T_MultiIndexArray[m_count];
+
+	for (i = 0; i != m_count; ++i)
+	{
+		new (&m_cobound[i]) T_MultiIndexArray(cobound[i].size());
+		
+		DT_Index j;
+		for (j = 0; j != cobound[i].size(); ++j)
+		{
+			new (&m_cobound[i][j]) DT_IndexArray(cobound[i][j].size(), &cobound[i][j][0]);
+		}
+	}
+		
+	delete [] cobound;
+
+	m_start_vertex = 0;
+	while (m_cobound[m_start_vertex].size() != num_layers) 
+	{
+		++m_start_vertex;
+		assert(m_start_vertex < m_count);
+	}
+
+	m_curr_vertex = m_start_vertex;
+} 
+
+
+DT_Polyhedron::~DT_Polyhedron() 
+{
+	delete [] m_verts;
+    delete [] m_cobound;
+}
+
+#ifdef DK_HIERARCHY
+
+MT_Scalar DT_Polyhedron::supportH(const MT_Vector3& v) const 
+{
+    m_curr_vertex = m_start_vertex;
+    MT_Scalar d = (*this)[m_curr_vertex].dot(v);
+    MT_Scalar h = d;
+	int curr_layer;
+	for (curr_layer = m_cobound[m_start_vertex].size(); curr_layer != 0; --curr_layer)
+	{
+		const DT_IndexArray& curr_cobound = m_cobound[m_curr_vertex][curr_layer-1];
+        DT_Index i;
+		for (i = 0; i != curr_cobound.size(); ++i) 
+		{
+			d = (*this)[curr_cobound[i]].dot(v);
+			if (d > h)
+			{
+				m_curr_vertex = curr_cobound[i];
+				h = d;
+			}
+		}
+	}
+	
+    return h;
+}
+
+MT_Point3 DT_Polyhedron::support(const MT_Vector3& v) const 
+{
+	m_curr_vertex = m_start_vertex;
+    MT_Scalar d = (*this)[m_curr_vertex].dot(v);
+    MT_Scalar h = d;
+	int curr_layer;
+	for (curr_layer = m_cobound[m_start_vertex].size(); curr_layer != 0; --curr_layer)
+	{
+		const DT_IndexArray& curr_cobound = m_cobound[m_curr_vertex][curr_layer-1];
+        DT_Index i;
+		for (i = 0; i != curr_cobound.size(); ++i) 
+		{
+			d = (*this)[curr_cobound[i]].dot(v);
+			if (d > h)
+			{
+				m_curr_vertex = curr_cobound[i];
+				h = d;
+			}
+		}
+	}
+	
+    return (*this)[m_curr_vertex];
+}
+
+#else
+
+MT_Scalar DT_Polyhedron::supportH(const MT_Vector3& v) const 
+{
+    int last_vertex = -1;
+    MT_Scalar d = (*this)[m_curr_vertex].dot(v);
+    MT_Scalar h = d;
+	
+	for (;;) 
+	{
+        DT_IndexArray& curr_cobound = m_cobound[m_curr_vertex][0];
+        int i = 0, n = curr_cobound.size(); 
+        while (i != n && 
+               (curr_cobound[i] == last_vertex || 
+				(d = (*this)[curr_cobound[i]].dot(v)) - h <= MT_abs(h) * MT_EPSILON)) 
+		{
+            ++i;
+		}
+		
+        if (i == n) 
+		{
+			break;
+		}
+		
+        last_vertex = m_curr_vertex;
+        m_curr_vertex = curr_cobound[i];
+        h = d;
+    }
+    return h;
+}
+
+MT_Point3 DT_Polyhedron::support(const MT_Vector3& v) const 
+{
+	int last_vertex = -1;
+    MT_Scalar d = (*this)[m_curr_vertex].dot(v);
+    MT_Scalar h = d;
+	
+    for (;;)
+	{
+        DT_IndexArray& curr_cobound = m_cobound[m_curr_vertex][0];
+        int i = 0, n = curr_cobound.size();
+        while (i != n && 
+               (curr_cobound[i] == last_vertex || 
+				(d = (*this)[curr_cobound[i]].dot(v)) - h <= MT_abs(h) * MT_EPSILON)) 
+		{
+            ++i;
+		}
+		
+        if (i == n)
+		{
+			break;
+		}
+		
+		last_vertex = m_curr_vertex;
+        m_curr_vertex = curr_cobound[i];
+        h = d;
+    }
+    return (*this)[m_curr_vertex];
+}
+
+#endif
+
+#endif
+
diff --git a/extern/solid/src/convex/DT_Polyhedron.h b/extern/solid/src/convex/DT_Polyhedron.h
new file mode 100644
index 00000000000..58c991bd152
--- /dev/null
+++ b/extern/solid/src/convex/DT_Polyhedron.h
@@ -0,0 +1,76 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_POLYHEDRON_H
+#define DT_POLYHEDRON_H
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+# if HAVE_QHULL_QHULL_A_H
+#  define QHULL
+# endif
+#endif
+
+
+#ifdef QHULL
+
+#include "DT_Convex.h"
+#include "DT_IndexArray.h"
+#include "DT_VertexBase.h"
+
+class DT_Polyhedron : public DT_Convex {
+	typedef DT_Array T_MultiIndexArray;
+public:
+	DT_Polyhedron() 
+		: m_verts(0),
+		  m_cobound(0)
+	{}
+		
+	DT_Polyhedron(const DT_VertexBase *base, DT_Count count, const DT_Index *indices);
+
+	virtual ~DT_Polyhedron();
+    
+    virtual MT_Scalar supportH(const MT_Vector3& v) const;
+    virtual MT_Point3 support(const MT_Vector3& v) const;
+
+	const MT_Point3& operator[](int i) const { return m_verts[i]; }
+    DT_Count numVerts() const { return m_count; }
+
+private:
+	DT_Count              m_count;
+	MT_Point3			 *m_verts;
+	T_MultiIndexArray    *m_cobound;
+    DT_Index              m_start_vertex;
+	mutable DT_Index      m_curr_vertex;
+};
+
+#else 
+
+#include "DT_Polytope.h"
+
+typedef DT_Polytope DT_Polyhedron;
+
+#endif
+
+#endif
+
diff --git a/extern/solid/src/convex/DT_Polytope.cpp b/extern/solid/src/convex/DT_Polytope.cpp
new file mode 100644
index 00000000000..e757c3bfdb4
--- /dev/null
+++ b/extern/solid/src/convex/DT_Polytope.cpp
@@ -0,0 +1,69 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_Polytope.h"
+
+MT_BBox DT_Polytope::bbox() const 
+{
+	MT_BBox bbox = (*this)[0];
+	DT_Index i;
+    for (i = 1; i < numVerts(); ++i) 
+	{
+        bbox = bbox.hull((*this)[i]);
+    }
+    return bbox;
+}
+
+MT_Scalar DT_Polytope::supportH(const MT_Vector3& v) const 
+{
+    int c = 0;
+    MT_Scalar h = (*this)[0].dot(v), d;
+	DT_Index i;
+    for (i = 1; i < numVerts(); ++i) 
+	{
+        if ((d = (*this)[i].dot(v)) > h) 
+		{ 
+			c = i; 
+			h = d; 
+		}
+    }
+    return h;
+}
+
+MT_Point3 DT_Polytope::support(const MT_Vector3& v) const 
+{
+    int c = 0;
+    MT_Scalar h = (*this)[0].dot(v), d;
+	DT_Index i;
+    for (i = 1; i < numVerts(); ++i)
+	{
+        if ((d = (*this)[i].dot(v)) > h)
+		{ 
+			c = i;
+			h = d; 
+		}
+    }
+    return (*this)[c];
+}
+
+
diff --git a/extern/solid/src/convex/DT_Polytope.h b/extern/solid/src/convex/DT_Polytope.h
new file mode 100644
index 00000000000..c715598defe
--- /dev/null
+++ b/extern/solid/src/convex/DT_Polytope.h
@@ -0,0 +1,51 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_POLYTOPE_H
+#define DT_POLYTOPE_H
+
+#include "DT_Convex.h"
+#include "DT_IndexArray.h"
+#include "DT_VertexBase.h"
+
+class DT_Polytope : public DT_Convex {
+public:	
+	DT_Polytope() {}
+    DT_Polytope(const DT_VertexBase *base, DT_Count count, const DT_Index *indices) 
+	  : m_base(base), 
+		m_index(count, indices) 
+	{}
+ 
+	virtual MT_BBox bbox() const;
+    virtual MT_Scalar supportH(const MT_Vector3& v) const;
+    virtual MT_Point3 support(const MT_Vector3& v) const;
+
+	MT_Point3 operator[](int i) const { return (*m_base)[m_index[i]]; }
+    DT_Count numVerts() const { return m_index.size(); }
+
+protected:
+    const DT_VertexBase *m_base;
+    DT_IndexArray        m_index;
+};
+
+#endif
diff --git a/extern/solid/src/convex/DT_Shape.h b/extern/solid/src/convex/DT_Shape.h
new file mode 100644
index 00000000000..d48942fe515
--- /dev/null
+++ b/extern/solid/src/convex/DT_Shape.h
@@ -0,0 +1,72 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_SHAPE_H
+#define DT_SHAPE_H
+
+#include 
+
+#include "MT_BBox.h"
+
+#include "MT_Transform.h"
+
+class DT_Object;
+
+enum DT_ShapeType {
+    COMPLEX,
+    CONVEX
+};
+
+class DT_Shape {
+public:
+    virtual ~DT_Shape() {}
+    virtual DT_ShapeType getType() const = 0;
+	virtual MT_BBox bbox(const MT_Transform& t, MT_Scalar margin) const = 0;
+	virtual bool ray_cast(const MT_Point3& source, const MT_Point3& target, MT_Scalar& param, MT_Vector3& normal) const = 0;
+
+protected:
+	DT_Shape()  {}
+};
+
+typedef bool (*Intersect)(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+						  const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+						  MT_Vector3&);
+
+typedef bool (*Common_point)(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+						     const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+			                 MT_Vector3&, MT_Point3&, MT_Point3&);
+
+typedef bool (*Penetration_depth)(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+						          const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+                                  MT_Vector3&, MT_Point3&, MT_Point3&);
+
+typedef MT_Scalar (*Closest_points)(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+						            const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+									MT_Point3&, MT_Point3&);
+
+#endif
+
+
+
+
+
diff --git a/extern/solid/src/convex/DT_Sphere.cpp b/extern/solid/src/convex/DT_Sphere.cpp
new file mode 100644
index 00000000000..3f2443dcf53
--- /dev/null
+++ b/extern/solid/src/convex/DT_Sphere.cpp
@@ -0,0 +1,90 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_Sphere.h"
+#include "GEN_MinMax.h"
+
+MT_Scalar DT_Sphere::supportH(const MT_Vector3& v) const 
+{
+	return m_radius * v.length();
+}
+
+MT_Point3 DT_Sphere::support(const MT_Vector3& v) const 
+{
+   MT_Scalar s = v.length();
+	
+	if (s > MT_Scalar(0.0))
+	{
+		s = m_radius / s;
+		return MT_Point3(v[0] * s, v[1] * s, v[2] * s);
+	}
+	else
+	{
+		return MT_Point3(m_radius, MT_Scalar(0.0), MT_Scalar(0.0));
+	}
+}
+
+bool DT_Sphere::ray_cast(const MT_Point3& source, const MT_Point3& target,
+						 MT_Scalar& param, MT_Vector3& normal) const 
+{
+	MT_Vector3 r = target - source;
+	MT_Scalar  delta = -source.dot(r);  
+	MT_Scalar  r_length2 = r.length2();
+	MT_Scalar  sigma = delta * delta - r_length2 * (source.length2() - m_radius * m_radius);
+
+	if (sigma >= MT_Scalar(0.0))
+		// The line trough source and target intersects the sphere.
+	{
+		MT_Scalar sqrt_sigma = MT_sqrt(sigma);
+		// We need only the sign of lambda2, so the division by the positive 
+		// r_length2 can be left out.
+		MT_Scalar lambda2 = (delta + sqrt_sigma) /* / r_length2 */ ;
+		if (lambda2 >= MT_Scalar(0.0))
+			// The ray points at the sphere
+		{
+			MT_Scalar lambda1 = (delta - sqrt_sigma) / r_length2;
+			if (lambda1 <= param)
+				// The ray hits the sphere, since 
+				// [lambda1, lambda2] overlaps [0, param]. 
+			{
+				if (lambda1 > MT_Scalar(0.0))
+				{
+					param = lambda1;
+					normal = (source + r * lambda1) / m_radius;
+					// NB: division by m_radius to normalize the normal.
+				}
+				else
+				{
+					param = MT_Scalar(0.0);
+					normal.setValue(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0));
+				}
+						
+				return true;
+			}
+		}
+	}
+
+	return false;
+}
+
+
diff --git a/extern/solid/src/convex/DT_Sphere.h b/extern/solid/src/convex/DT_Sphere.h
new file mode 100644
index 00000000000..92386a66f3a
--- /dev/null
+++ b/extern/solid/src/convex/DT_Sphere.h
@@ -0,0 +1,43 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_SPHERE_H
+#define DT_SPHERE_H
+
+#include "DT_Convex.h"
+
+class DT_Sphere : public DT_Convex {
+public:
+   DT_Sphere(MT_Scalar radius) : m_radius(radius) {}
+	
+    virtual MT_Scalar supportH(const MT_Vector3& v) const;
+	virtual MT_Point3 support(const MT_Vector3& v) const;
+	
+	virtual bool ray_cast(const MT_Point3& source, const MT_Point3& target,
+						  MT_Scalar& param, MT_Vector3& normal) const;
+
+protected:
+    MT_Scalar m_radius;
+};
+
+#endif
diff --git a/extern/solid/src/convex/DT_Transform.h b/extern/solid/src/convex/DT_Transform.h
new file mode 100644
index 00000000000..a976d48d22b
--- /dev/null
+++ b/extern/solid/src/convex/DT_Transform.h
@@ -0,0 +1,53 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_TRANSFORM_H
+#define DT_TRANSFORM_H
+
+#include "DT_Convex.h"
+
+class DT_Transform : public DT_Convex {
+public:
+	DT_Transform(const MT_Transform& xform, const DT_Convex& child) :
+		m_xform(xform), 
+		m_child(child)
+	{}
+
+	virtual MT_Scalar supportH(const MT_Vector3& v) const
+	{
+		return m_child.supportH(v * m_xform.getBasis()) + 
+			   v.dot(m_xform.getOrigin());
+	}
+
+	virtual MT_Point3 support(const MT_Vector3& v) const
+	{
+		return m_xform(m_child.support(v * m_xform.getBasis()));
+	}
+
+private:
+	const MT_Transform& m_xform;
+	const DT_Convex&    m_child;
+};
+
+
+#endif
diff --git a/extern/solid/src/convex/DT_Triangle.cpp b/extern/solid/src/convex/DT_Triangle.cpp
new file mode 100644
index 00000000000..1917910b39d
--- /dev/null
+++ b/extern/solid/src/convex/DT_Triangle.cpp
@@ -0,0 +1,96 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+//#define BACKFACE_CULLING
+
+#include "DT_Triangle.h"
+
+MT_BBox DT_Triangle::bbox() const 
+{
+	return MT_BBox((*this)[0]).hull((*this)[1]).hull((*this)[2]);
+}
+
+MT_Scalar DT_Triangle::supportH(const MT_Vector3& v) const
+{
+    return GEN_max(GEN_max(v.dot((*this)[0]), v.dot((*this)[1])), v.dot((*this)[2]));
+}
+
+MT_Point3 DT_Triangle::support(const MT_Vector3& v) const
+{
+    MT_Vector3 dots(v.dot((*this)[0]), v.dot((*this)[1]), v.dot((*this)[2]));
+
+	return (*this)[dots.maxAxis()];
+}
+
+bool DT_Triangle::ray_cast(const MT_Point3& source, const MT_Point3& target, 
+						   MT_Scalar& param, MT_Vector3& normal) const 
+{
+	MT_Vector3 d1 = (*this)[1] - (*this)[0];
+	MT_Vector3 d2 = (*this)[2] - (*this)[0];
+	MT_Vector3 n = d1.cross(d2);
+	MT_Vector3 r = target - source;
+	MT_Scalar delta = -r.dot(n);
+
+   MT_Scalar rounding_error = GEN_max(GEN_max(MT_abs(n[0]), MT_abs(n[1])), MT_abs(n[2])) * MT_EPSILON; 
+
+#ifdef BACKFACE_CULLING	
+   if (delta > rounding_error)
+#else
+	if (MT_abs(delta) > rounding_error)
+#endif      
+		// The ray is not parallel to the triangle's plane. 
+		// (Coplanar rays are ignored.)
+	{
+		MT_Vector3 b = source - (*this)[0];
+		MT_Scalar lambda = b.dot(n) / delta;
+
+		if (MT_Scalar(0.0) <= lambda && lambda <= param)
+			// The ray intersects the triangle's plane.
+		{
+			MT_Vector3 u = b.cross(r);
+			MT_Scalar mu1 = d2.dot(u) / delta;
+
+			if (MT_Scalar(0.0) <= mu1 && mu1 <= MT_Scalar(1.0)) 
+			{
+				MT_Scalar mu2 = -d1.dot(u) / delta;
+
+				if (MT_Scalar(0.0) <= mu2 && mu1 + mu2 <= MT_Scalar(1.0)) 
+					// The ray intersects the triangle.
+				{
+					param = lambda;
+					// Return a normal that points at the source.
+#ifdef BACKFACE_CULLING
+               normal = n;
+#else
+					normal = delta > MT_Scalar(0.0) ? n : -n;
+#endif
+					return true;
+				}
+			}
+		}
+	}
+
+	return false;
+}
+
+
diff --git a/extern/solid/src/convex/DT_Triangle.h b/extern/solid/src/convex/DT_Triangle.h
new file mode 100644
index 00000000000..4192b5629ac
--- /dev/null
+++ b/extern/solid/src/convex/DT_Triangle.h
@@ -0,0 +1,63 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_TRIANGLE_H
+#define DT_TRIANGLE_H
+
+#include "SOLID_types.h"
+
+#include "DT_Convex.h"
+#include "DT_IndexArray.h"
+#include "DT_VertexBase.h"
+
+class DT_Triangle : public DT_Convex {
+public:
+    DT_Triangle(const DT_VertexBase *base, DT_Index i0, DT_Index i1, DT_Index i2) : 
+        m_base(base)
+	{
+		m_index[0] = i0;
+		m_index[1] = i1;
+		m_index[2] = i2;
+	}
+
+    DT_Triangle(const DT_VertexBase *base, const DT_Index *index) : 
+        m_base(base)
+	{
+		m_index[0] = index[0];
+		m_index[1] = index[1];
+		m_index[2] = index[2];
+	}
+
+	virtual MT_BBox bbox() const;
+    virtual MT_Scalar supportH(const MT_Vector3& v) const;
+    virtual MT_Point3 support(const MT_Vector3& v) const;
+	virtual bool ray_cast(const MT_Point3& source, const MT_Point3& target, MT_Scalar& lambda, MT_Vector3& normal) const;
+
+    MT_Point3 operator[](int i) const { return (*m_base)[m_index[i]]; }
+
+private:
+    const DT_VertexBase *m_base;
+    DT_Index             m_index[3];
+};
+
+#endif
diff --git a/extern/solid/src/convex/DT_VertexBase.h b/extern/solid/src/convex/DT_VertexBase.h
new file mode 100644
index 00000000000..37646fdd935
--- /dev/null
+++ b/extern/solid/src/convex/DT_VertexBase.h
@@ -0,0 +1,84 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_VERTEXBASE_H
+#define DT_VERTEXBASE_H
+
+#include "MT_Point3.h"
+
+#include 
+
+class DT_Complex;
+
+typedef std::vectorDT_ComplexList;
+
+class DT_VertexBase {
+public:
+    explicit DT_VertexBase(const void *base = 0, DT_Size stride = 0, bool owner = false) : 
+        m_base((char *)base),
+		m_stride(stride ? stride : 3 * sizeof(DT_Scalar)),
+		m_owner(owner)
+	{}
+	
+	~DT_VertexBase()
+	{
+		if (m_owner)
+		{
+			delete [] m_base;
+		}
+	}
+    
+    MT_Point3 operator[](DT_Index i) const 
+	{ 
+        return MT_Point3(reinterpret_cast(m_base + i * m_stride));
+    }
+    
+    void setPointer(const void *base, bool owner = false)
+	{
+		m_base = (char *)base; 
+		m_owner = owner;
+	} 
+	
+    const void *getPointer() const { return m_base; }	
+	bool        isOwner() const { return m_owner; }
+    
+	void addComplex(DT_Complex *complex) const { m_complexList.push_back(complex); }
+	void removeComplex(DT_Complex *complex) const
+	{
+		DT_ComplexList::iterator it = std::find(m_complexList.begin(), m_complexList.end(), complex); 
+		if (it != m_complexList.end())
+		{
+			m_complexList.erase(it);
+		}
+	}
+	
+	const DT_ComplexList& getComplexList() const { return m_complexList; }
+	
+private:    
+    char                  *m_base;
+    DT_Size                m_stride;
+	bool                   m_owner;
+	mutable DT_ComplexList m_complexList;
+};
+
+#endif
diff --git a/extern/solid/src/convex/Makefile b/extern/solid/src/convex/Makefile
new file mode 100644
index 00000000000..406a89f2989
--- /dev/null
+++ b/extern/solid/src/convex/Makefile
@@ -0,0 +1,44 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# 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. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License.  See http://www.blender.org/BL/ for information
+# about this.
+#
+# 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.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = solid_convex
+DIR = $(OCGDIR)/extern/$(LIBNAME)
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I../../include -I$(NAN_QHULL)/include
+CPPFLAGS += -DQHULL -DUSE_DOUBLES
+
+include nan_compile.mk 
+
+
diff --git a/extern/verse/CMakeLists.txt b/extern/verse/CMakeLists.txt
new file mode 100644
index 00000000000..409372c10f6
--- /dev/null
+++ b/extern/verse/CMakeLists.txt
@@ -0,0 +1,31 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# 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. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License.  See http://www.blender.org/BL/ for information
+# about this.
+#
+# 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.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+SUBDIRS(dist)
+
diff --git a/extern/verse/Makefile b/extern/verse/Makefile
new file mode 100644
index 00000000000..2e88ee2223f
--- /dev/null
+++ b/extern/verse/Makefile
@@ -0,0 +1,58 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# 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. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License.  See http://www.blender.org/BL/ for information
+# about this.
+#
+# 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.
+#
+# The Original Code is Copyright (C) 2002 by Hans Lambermont
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jiri Hnidek
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+LIBNAME = verse
+SOURCEDIR = extern/$(LIBNAME)
+DIR = $(OCGDIR)/$(SOURCEDIR)
+DIRS = dist
+
+include nan_subdirs.mk
+include nan_compile.mk
+include nan_link.mk
+
+DISTDIR = dist
+CP = ../../intern/tools/cpifdiff.sh
+
+ifeq ($(OS),windows)
+    EXT = .exe
+endif
+
+install: all debug
+	@[ -d $(NAN_VERSE) ] || mkdir -p $(NAN_VERSE)
+	@[ -d $(NAN_VERSE)/include ] || mkdir -p $(NAN_VERSE)/include
+	@[ -d $(NAN_VERSE)/lib ] || mkdir -p $(NAN_VERSE)/lib
+	@[ -d $(OCGDIR)/bin ] || mkdir -p $(OCGDIR)/bin
+	@$(CP) $(DISTDIR)/*.h $(NAN_VERSE)/include
+	@$(CP) $(DIR)/libverse.a $(NAN_VERSE)/lib
+ifeq ($(OS),darwin)
+	ranlib $(NAN_VERSE)/lib/libverse.a
+endif
+	$(CCC) $(LDFLAGS) -o $(DIR)/verse$(EXT) $(DIR)/libverse.a $(LIBS) $(SLIBS) $(LLIBS) $(DADD) $(LOPTS)
+	@$(CP) $(DIR)/verse$(EXT) $(OCGDIR)/bin
diff --git a/extern/verse/dist/BUGS b/extern/verse/dist/BUGS
new file mode 100644
index 00000000000..8c3603a3a45
--- /dev/null
+++ b/extern/verse/dist/BUGS
@@ -0,0 +1,8 @@
+
+Known problems with Verse
+
+2004-03-03
+* The source code needs plenty of cleaning up in order to compile more
+  cleanly.
+* License information needs to be added all over the place.
+* Decent documentation is missing.
diff --git a/extern/verse/dist/CMakeLists.txt b/extern/verse/dist/CMakeLists.txt
new file mode 100644
index 00000000000..2f8fcd0b449
--- /dev/null
+++ b/extern/verse/dist/CMakeLists.txt
@@ -0,0 +1,93 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# 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. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License.  See http://www.blender.org/BL/ for information
+# about this.
+#
+# 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.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+SUBDIRS(mkprot_cmd)
+
+SET(SRC_MKPROT_OUT
+  v_gen_pack_init.c
+  v_gen_pack_a_node.c
+  v_gen_pack_b_node.c
+  v_gen_pack_c_node.c
+  v_gen_pack_g_node.c
+  v_gen_pack_m_node.c
+  v_gen_pack_o_node.c
+  v_gen_pack_s_node.c
+  v_gen_pack_t_node.c
+)
+
+SET(INC .)
+
+SET(SRC
+  v_cmd_buf.c
+  v_connect.c
+  v_connection.c
+  v_encryption.c
+  v_func_storage.c
+  v_man_pack_node.c
+  v_network.c
+  v_network_in_que.c
+  v_network_out_que.c
+  v_pack.c
+  v_pack_method.c
+  v_prime.c
+  v_randgen.c
+  v_util.c
+  v_bignum.c
+  verse_ms.c
+  ${SRC_MKPROT_OUT}
+)
+
+BLENDERLIB(verse "${SRC}" "${INC}")
+ADD_DEPENDENCIES(verse mkprot)
+#verselib = env.BlenderLib(libname='verse', sources=lib_source_files, includes=[], defines=defines, libtype=['core', 'intern'], priority = [5, 5])
+
+SET(SRC_VERSE
+  vs_connection.c
+  vs_main.c
+  vs_node_audio.c
+  vs_node_bitmap.c
+  vs_node_curve.c
+  vs_node_geometry.c
+  vs_node_head.c
+  vs_node_material.c
+  vs_node_object.c
+  vs_node_particle.c
+  vs_node_storage.c
+  vs_node_text.c
+  vs_master.c  
+)
+
+ADD_EXECUTABLE(verse_server ${SRC_VERSE})
+IF(WIN32)
+TARGET_LINK_LIBRARIES(verse_server verse ws2_32)
+ELSE(WIN32)
+TARGET_LINK_LIBRARIES(verse_server verse)
+ENDIF(WIN32)
+ADD_DEPENDENCIES(verse_server mkprot)
+MESSAGE(STATUS "Configuring verse_server")
diff --git a/extern/verse/dist/MAINTAINERS b/extern/verse/dist/MAINTAINERS
new file mode 100644
index 00000000000..c467d5309b8
--- /dev/null
+++ b/extern/verse/dist/MAINTAINERS
@@ -0,0 +1,15 @@
+
+			Verse Maintainers
+
+This file tries to list credits for the various parts of the
+Verse core distribution, and also identify who maintains what.
+
+We are deeply appreciative of any contributions and thank you
+all for your time and interest in helping make Verse a better
+thing.
+
+* All code was originally written by Eskil Steenberg, and is
+  being maintained by him and Emil Brink. Contact us through
+  the project page at http://www.blender.org/modules/verse/.
+
+* SCons build file by N. Letwory, http://www.jester-depot.net/.
diff --git a/extern/verse/dist/Makefile b/extern/verse/dist/Makefile
new file mode 100644
index 00000000000..69b5590b2bc
--- /dev/null
+++ b/extern/verse/dist/Makefile
@@ -0,0 +1,15 @@
+#
+# Makefile for Verse core; API and reference server.
+# This pretty much requires GNU Make, I think.
+#
+# This build is slightly complicated that part of the C code that
+# needs to go into the API implementation is generated by building
+# and running other C files (this is the protocol definition).
+#
+
+LIBNAME = verse
+DIR = $(OCGDIR)/extern/$(LIBNAME)
+
+include nan_compile.mk
+
+# TARGETS = verse
diff --git a/extern/verse/dist/Makefile.win32 b/extern/verse/dist/Makefile.win32
new file mode 100644
index 00000000000..548881c6a16
--- /dev/null
+++ b/extern/verse/dist/Makefile.win32
@@ -0,0 +1,102 @@
+#
+# Makefile for Verse core; API and reference server.
+# Written by modifying the main GNU Makefile, for nmake.
+#
+# It is more hard-coded, relying on less intelligence in
+# the make tool.
+#
+# This build is slightly complicated that part of the C code that
+# needs to go into the API implementation is generated by building
+# and running other C files (this is the protocol definition).
+#
+
+CC	= cl
+CFLAGS	= 
+LDFLAGS	= -pg
+
+AR	= ar
+ARFLAGS	= rus
+RANLIB	= ranlib
+
+TARGETS = verse.lib verse.exe
+
+# Automatically generated protocol things.
+PROT_DEF  = v_cmd_def_a.c v_cmd_def_b.c v_cmd_def_c.c v_cmd_def_g.c v_cmd_def_m.c v_cmd_def_o.c v_cmd_def_s.c v_cmd_def_t.c
+PROT_TOOL = v_cmd_gen.c $(PROT_DEF)
+PROT_OUT  = v_gen_pack_init.c v_gen_unpack_func.h verse.h \
+	    v_gen_pack_a_node.c v_gen_pack_b_node.c v_gen_pack_c_node.c v_gen_pack_g_node.c v_gen_pack_m_node.c v_gen_pack_o_node.c v_gen_pack_s_node.c v_gen_pack_t_node.c
+
+# The API implementation is the protocol code plus a few bits.
+LIBVERSE_SRC =  v_gen_pack_init.c v_gen_unpack_func.h verse.h v_gen_pack_a_node.c v_gen_pack_b_node.c v_gen_pack_c_node.c v_gen_pack_g_node.c \
+		v_gen_pack_m_node.c v_gen_pack_o_node.c v_gen_pack_s_node.c v_gen_pack_t_node.c \
+		v_bignum.c v_cmd_buf.c v_connect.c \
+		v_connection.c v_connection.h v_encryption.c \
+		v_func_storage.c v_internal_verse.h v_man_pack_node.c \
+		v_network.c v_network.h v_network_in_que.c v_network_out_que.c \
+		v_pack.c v_pack.h v_pack_method.c v_prime.c v_randgen.c v_util.c
+
+LIBVERSE_OBJ = v_gen_pack_init.obj v_gen_pack_a_node.obj v_gen_pack_b_node.obj v_gen_pack_c_node.obj v_gen_pack_g_node.obj \
+		v_gen_pack_m_node.obj v_gen_pack_o_node.obj v_gen_pack_s_node.obj v_gen_pack_t_node.obj \
+		v_bignum.obj v_cmd_buf.obj v_connect.obj \
+		v_connection.obj v_encryption.obj \
+		v_func_storage.obj v_man_pack_node.obj \
+		v_network.obj v_network_in_que.obj v_network_out_que.obj \
+		v_pack.obj v_pack_method.obj v_prime.obj v_randgen.obj v_util.obj
+
+# The server is a simple 1:1 mapping, but in Windows nmake ... That doesn't help much. :/
+VERSE_SRC = vs_connection.c vs_main.c vs_master.c vs_node_audio.c vs_node_bitmap.c vs_node_curve.c vs_node_geometry.c vs_node_head.c vs_node_material.c vs_node_object.c vs_node_particle.c vs_node_storage.c vs_node_text.c
+VERSE_OBJ = vs_connection.obj vs_main.obj vs_master.obj vs_node_audio.obj vs_node_bitmap.obj vs_node_curve.obj vs_node_geometry.obj \
+	vs_node_head.obj vs_node_material.obj vs_node_object.obj vs_node_particle.obj vs_node_storage.obj vs_node_text.obj
+
+# -----------------------------------------------------
+
+ALL:		verse.lib verse.exe
+
+verse.exe:	$(VERSE_OBJ) verse.lib resources\verse.res
+		cl /Fe$@ $** wsock32.lib
+
+verse.lib:	$(LIBVERSE_OBJ)
+		link /lib /nologo /out:$@ $**
+
+# -----------------------------------------------------
+
+# Here are the automatically generated pieces of the puzzle.	
+# Basically, we generate v_gen_pack_X_node.c files by compiling
+# the v_cmd_def_X.c files together with some driver glue and
+# running the result.
+#
+
+# The autogen outputs all depend on the tool.
+$(PROT_OUT):	mkprot.exe
+		mkprot.exe
+
+# Build the protocol maker, from the definitions themselves.
+mkprot.exe:	$(PROT_TOOL) verse_header.h
+		$(CC) /DV_GENERATE_FUNC_MODE /Fe$@ $(PROT_TOOL)
+
+# Clean away all the generated parts of the protocol implementation.
+cleanprot:	clean
+		del mkprot $(PROT_OUT) mkprot.exe
+
+# -----------------------------------------------------
+
+clean:
+	del *.obj $(TARGETS)
+
+# -----------------------------------------------------
+
+# Utter ugliness to create release archives. Needs to improve, but should work for a while.
+dist:
+	RELEASE=$$( \
+	R=`grep V_RELEASE_NUMBER verse.h | tr -s ' \t' | tr -d '"\r' | cut -d'	' -f3` ; \
+	P=`grep V_RELEASE_PATCH verse.h | tr -s ' \t' | tr -d '"\r' | cut -d'	' -f3` ; \
+	L=`grep V_RELEASE_LABEL verse.h | tr -s ' \t' | tr -d '"\r' | cut -d'	' -f3` ; echo r$${R}p$$P$$L ) ; \
+	if [ $$RELEASE ]; then ( \
+	 rm -rf  /tmp/verse; \
+	 mkdir -p /tmp/verse; \
+	 cp -a * /tmp/verse; \
+	 cd /tmp && zip verse-$$RELEASE.zip -r verse -x 'verse/*CVS*' -x 'verse/.*' ; \
+	 ); mv /tmp/verse-$$RELEASE.zip . \
+	;else \
+	  echo "Couldn't auto-set RELEASE from verse.h, something is fishy" \
+	;fi
diff --git a/extern/verse/dist/README.html b/extern/verse/dist/README.html
new file mode 100644
index 00000000000..b3b3050bf12
--- /dev/null
+++ b/extern/verse/dist/README.html
@@ -0,0 +1,173 @@
+
+
+
+
+Verse README
+
+
+
+
+

Verse

+ +

+This is the Verse protocol and sample server implementations. +

+

+For more information, see the Verse web site. +

+

Building the Verse Core

+

+Note: This section is only of interest to developers, who wish to build the Verse core themselves. +If you have chosen a binary download, you will already have the server and can skip the rest +of this section. +

+

+Running "make" here will build the API library, "libverse.a" (and its +header file, "verse.h"). These two will then be used to build the +reference Verse server binary, called "verse". +

+

+If you are more comfortable with SCons, and of course have it +installed on your system, you can type "scons" instead. +

+ +

Starting the Server

+

+The Verse server is a command-line program, without a graphical user interface. +You simply start it, and it will immediately begin listening for incoming +connections on a network socket. Here is how a typical invocation looks: +

+
~> verse
+
+

+If you don't ask it to do otherwise, the Verse server will start listening for UDP packets +on its default port. The port number currently used by Verse is 4950. +

+

+Note: This is not an official registered, port number. +It is possible that it gets assigned to someone else, in case Verse will need to change. +

+

+You can use the following command line options to control the server's operation: +

+
+
-h
+
+ Print a help text, that shows all understood options. +
+
-ms
+
+ Enables master server communications to the default, built-in address. Use the -h option to learn + what this address is. Please note that master server communication is disabled by default. +
+
-ms:ip=IP
+
+ Sets a new address to use for master server communication. This also implies -ms, i.e. the server + will try to register itself with the given master server. For details on the protocol used to do + this, please see the spec. +
+
-ms:de=DESC
+
+ Sets the description to use for this server, when registering with the the master server. This is + only used if master server communication is actually enabled. The description is expected to be a + human-readable string, like "A test server, run on a cable modem, and offline during local daytime" + or something. +
+
-ms:ta=TAGS
+
+ Sets the tags to use for this server, when registering with the the master server. This is only used + if master server communication is actually enabled. The tags consists of a comma-separated list of + single words. Each word must begin with a letter, and contain only letters, digits, or underscore + characters. For instance: home,r6p1,linux,sweden,open. +
+
-port=N
+
+ Use the indicated port number, rather than the default. Note that ports below 1024 are generally + off-limits to ordinary users. Running Verse on such a port is not recommended. +
+
-version
+
+ Prints the version string of the server to the terminal, and then exits (successfully). See + below for information how the version string is constructed. +
+
+

+For example, here is how to start the server, register it with the default master server, and run +on port number equal to 16333: +

+
~> ./server -ms -port=16333
+
+

+Here is a more complicated example, that uses an explicit master server address, and also sets both +the description and tags: +

+
~> ./server -ms:ip=master.example.net -ms:de="A test server, for the documentation" -ms:ta=example,docs
+
+

+Options can occur in any order, with later options overriding earlier ones, in case of conflicts. +

+ +

Release Labeling

+

+Verse uses a simple two-level numbering scheme to identify releases. +There is a "release number", and a "patch level" on each release. The +intent is that within a release, the API does not change and neither +should the network protocol. Between releases, we might improve the +API which will require application programmers to update their code +to stay in sync. We can do non-API-altering changes within a release +by increasing the patch level, for bug fixing and other things. +

+

+The symbols V_RELEASE_NUMBER and V_RELEASE_PATCH +are integer literals that hold the values for the API you have, and can be +used (and displayed) in application source code as you see fit. There is +also a string, V_RELEASE_LABEL, which is sometimes used. +

+

+To form a complete Verse version number, the above-mentioned symbols are +to be combined like so: +"r<V_RELEASE_NUMBER>p<V_RELEASE_PATCH><V_RELEASE_LABEL>". +So, the following variable values: +

    +
  • V_RELEASE_VERSION = 2 +
  • V_RELEASE_VERSION = 51 +
  • V_RELEASE_LABEL = "foo" +
+Would generate the version string "r2p51foo". +

+ + + diff --git a/extern/verse/dist/SConstruct b/extern/verse/dist/SConstruct new file mode 100644 index 00000000000..ecdc3178028 --- /dev/null +++ b/extern/verse/dist/SConstruct @@ -0,0 +1,146 @@ +#!/usr/bin/env python +# +# I think it is quite straight-forward to add new platforms, +# just look at the old makefile and at the existing platforms. +# +# This SConstruct creates a configuration file which can be +# used for tweaking a build. +# +# For more about SConstruct, see . +# + +import os +import os.path +import sys +import re +import time +import string +from distutils import sysconfig + +Import('env') + +defines = [] +cflags = [] +debug_flags = [] +extra_flags = [] +release_flags = [] +warn_flags = [] +platform_libs = [] +platform_libpath = [] +platform_linkflags = [] + +ourplatform = env['OURPLATFORM'] +if ourplatform == 'win32-vc': + print "Building on win32" + defines += ['_WIN32'] + warn_flags = ['/Wall'] + platform_libs = ['ws2_32'] +elif ourplatform == 'win32-mingw': + defines += ['_WIN32', 'WIN32'] + platform_libs = ['shell32', 'kernel32', 'gdi32', 'user32', 'ws2_32'] +elif ourplatform == 'linux2': + print "Building on linux2" +elif ourplatform == 'openbsd3': + print "Building on openbsd3" + +root_build_dir = env['BF_BUILDDIR'] + +if env['VERSE_BUILD_BINARY'] == 'release': + cflags = extra_flags + release_flags + warn_flags + if ourplatform == 'win32-vc': + defines += ['NDEBUG'] +else: + cflags = extra_flags + debug_flags + warn_flags + if ourplatform == 'win32-vc': + #defines += ['_DEBUG'] specifying this makes msvc want to link to python22_d.lib?? + platform_linkflags += ['/DEBUG','/PDB:verse.pdb'] + + +verse_env = env.Copy() + +cmd_gen_files = (['v_cmd_gen.c', + 'v_cmd_def_a.c', + 'v_cmd_def_b.c', + 'v_cmd_def_c.c', + 'v_cmd_def_g.c', + 'v_cmd_def_m.c', + 'v_cmd_def_o.c', + 'v_cmd_def_s.c', + 'v_cmd_def_t.c' + ]) + +cmd_gen_deps = (['v_gen_pack_init.c']) + +proto_env = env.Copy() +proto_env.Append(CPPDEFINES=['V_GENERATE_FUNC_MODE']) +mkprot_tool = proto_env.Program(target = 'mkprot', source = cmd_gen_files) + +mkprot_re = re.compile('v_cmd_def_([a-z]{1}).c') +def mkprot_emitter(target = None, source = None, env = None): + newtargets = list() + for s in source: + p, f = os.path.split(str(s)) + m = mkprot_re.match(f) + if m: + newtargets.append("v_gen_pack_"+m.group(1)+"_node.c") + newtargets.extend(['verse.h']) + env.Depends(newtargets, mkprot_tool) + return (newtargets, source) + +mkprot_bld = Builder(action = "\"" + mkprot_tool[0].abspath + "\" -src=\""+os.getcwd()+os.sep+"extern"+os.sep+"verse"+os.sep+"dist"+os.sep+os.sep+"\" -dst=\""+os.path.abspath(env['BF_BUILDDIR'])+os.sep+"extern"+os.sep+"verse"+os.sep+"dist"+os.sep+os.sep+"\"", + emitter = mkprot_emitter) + +verse_env['BUILDERS']['Protocol'] = mkprot_bld + +cmd_gen_deps.extend(verse_env.Protocol('do_mkprot', cmd_gen_files)) + +cmd_gen_deps.pop() + +lib_source_files = (['v_cmd_buf.c', + 'v_connect.c', + 'v_connection.c', + 'v_encryption.c', + 'v_func_storage.c', + 'v_man_pack_node.c', + 'v_network.c', + 'v_network_in_que.c', + 'v_network_out_que.c', + 'v_pack.c', + 'v_pack_method.c', + 'v_prime.c', + 'v_randgen.c', + 'v_util.c', + 'v_bignum.c', + 'verse_ms.c' + ]) +lib_source_files.extend(cmd_gen_deps) + +server_source_files = (['vs_connection.c', + 'vs_main.c', + 'vs_master.c', + 'vs_node_audio.c', + 'vs_node_bitmap.c', + 'vs_node_curve.c', + 'vs_node_geometry.c', + 'vs_node_head.c', + 'vs_node_material.c', + 'vs_node_object.c', + 'vs_node_particle.c', + 'vs_node_storage.c', + 'vs_node_text.c' + ]) + +verselib_env = verse_env.Copy() +verselib_env.Append(CPPDEFINES = defines) + +verseserver_env = verse_env.Copy() +verseserver_env.Append(CPPDEFINES = defines) +verseserver_env.Append (LIBPATH = ['.']) +verseserver_env.Append (LIBS= ['verse']) +verseserver_env.Append (LIBS= platform_libs) + +verselib_env.BlenderLib(libname='verse', sources=lib_source_files, includes=["."], defines = defines, libtype=['core', 'intern', 'player'], priority = [5, 5, 100]) +verseserver_env.BlenderProg(builddir="#"+root_build_dir+os.sep, progname='verse', sources=server_source_files, libs=[], +libpath='#'+env['BF_BUILDDIR']+'/lib') + + diff --git a/extern/verse/dist/examples/list-nodes.c b/extern/verse/dist/examples/list-nodes.c new file mode 100644 index 00000000000..6c9cc000d7c --- /dev/null +++ b/extern/verse/dist/examples/list-nodes.c @@ -0,0 +1,39 @@ +/* A minimalist Verse example. Ask server for nodes, print information. */ + +#include +#include + +#include "verse.h" /* Bring in the Verse API. */ + +/* A callback for connection acception: will be called when server accepts this client. */ +static void callback_accept_connect(void *user, uint32 avatar, void *address, void *connection, uint8 *host_id) +{ + uint32 i, mask = 0; + + printf("Connected to a Verse host!\n\nListing nodes:\n"); + + /* Build node subscription mask. */ + for(i = 0; i < V_NT_NUM_TYPES; i++) + mask |= 1 << i; + verse_send_node_index_subscribe(mask); /* Request listing of all nodes. */ +} + +/* A callback for node creation: is called to report information about existing nodes, too. */ +static void callback_node_create(void *user, VNodeID node_id, VNodeType type, VNodeOwner ownership) +{ + printf(" Node #%u has type %u\n", node_id, type); +} + +int main(void) +{ + /* Register callbacks for interesting commands. */ + verse_callback_set(verse_send_connect_accept, callback_accept_connect, NULL); + verse_callback_set(verse_send_node_create, callback_node_create, NULL); + + /* Kick off program by connecting to Verse host on local machine. */ + verse_send_connect("list-nodes", "", "localhost", NULL); + while(TRUE) + verse_callback_update(10000); /* Listen to network, get callbacks. */ + + return EXIT_SUCCESS; /* This is never reached. */ +} diff --git a/extern/verse/dist/mkprot_cmd/CMakeLists.txt b/extern/verse/dist/mkprot_cmd/CMakeLists.txt new file mode 100644 index 00000000000..c4e3128b7f8 --- /dev/null +++ b/extern/verse/dist/mkprot_cmd/CMakeLists.txt @@ -0,0 +1,55 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(SRC + ../v_cmd_gen.c + ../v_cmd_def_a.c + ../v_cmd_def_b.c + ../v_cmd_def_c.c + ../v_cmd_def_g.c + ../v_cmd_def_m.c + ../v_cmd_def_o.c + ../v_cmd_def_s.c + ../v_cmd_def_t.c +) + +ADD_DEFINITIONS(-DV_GENERATE_FUNC_MODE) +ADD_EXECUTABLE(mkprot ${SRC}) + +# Uncoment the following to get verse to generate the files using dependency +# tracking without having the generated files submitted in CVS. +# +#ADD_CUSTOM_COMMAND(TARGET mkprot +# POST_BUILD +# COMMAND mkprot -src=${CMAKE_CURRENT_SOURCE_DIR}/../ -dst=${CMAKE_CURRENT_SOURCE_DIR}/../ +# MAIN_DEPENDENCY ${EXECUTABLE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}/mkprot +# WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR} +#) +MESSAGE(STATUS "Configuring mkprot(verse)") + diff --git a/extern/verse/dist/resources/Makefile.win32 b/extern/verse/dist/resources/Makefile.win32 new file mode 100644 index 00000000000..8e7b4a09bbd --- /dev/null +++ b/extern/verse/dist/resources/Makefile.win32 @@ -0,0 +1,11 @@ +# +# This builds a resource file for the Verse server, for the icon. +# + +ALL: verse.res + +verse.res: verse.rc + + +clean: + del *.res diff --git a/extern/verse/dist/resources/verse.ico b/extern/verse/dist/resources/verse.ico new file mode 100644 index 0000000000000000000000000000000000000000..b30f4c927efe3f1ff1e18b5fbe65f27d3e67d4d3 GIT binary patch literal 17814 zcmeI333ON0oyYHc|Lo*ISY-($?7<);2oz*V*aOHGkVS>0$P&_eSY?eQ6&#$yDF`a+ zk%|s&85Pm#AeJgfl~z%Nj*4@tvJMIrrbetvNXVPd_vZip6HHMcfywl6;r{P?_uc#3 zf4}>?_q`b7m=Y$#4p^q_1z@*z`Q-#MC;QEE(De{3{`AP(#m4g*@O$*lHmOh zwa0_=cbBzA!M1RDq~H}5_IDBv8*?@o+Ew8Z^ti`Jx%Q0qNl%Gy6BCfNJd*{ju- zM#b6t(x`@Mx-W@aXz$O)<<-)CVMfQs&$fl0w?g+tp0`1*EtlSE zok^soQ~hEqE)ZH{Zr^1P^7UTL$1`K1XZ`QB?K-gk@a zT(+D@_3eBY*M9j&v2zarmFE9%E#dl4HH_Ki5X&NobAxD!XJ-}LMi_HuzcJr_p?FbN zFU&g=t#}H^S+AFiOW?*EZ!|aEbd%}Ut(y}a9UWj~s5WojT-VjQK%;5Zsug>b6cZ6q zZj%AkO`0^R*0hVbHf`EC?b@|7Lx&D+k1nRL_nI9Q6*UXm@23A&Vgc4)eGBvkYSpS` z8aHmd$Z?cSkZuHPOiaunuB$cu(C3DShnt2C8;<4r9QE5^Jy)Yfjcr`3R9ha9u}fu7 zp4iWIUCF+LT1@p~V`G0!t5R+K7~gg90n?&Ii%$4&DYTxaN)KM0I&~h#7YuPJjQeU? z+O}=$bm-8*Bqt}g3=0eU8$?P6mi~J6>fH7t_6acS9U8bLPx3Q>IKY+1c44#KidcX3d)AVdq;%j2ICK4|{lM z>4zuL-;22FHfYemZQs6qXx_ED(7JTXEw`9JAYfLlTIJ;B<(Y(pgg|_Jyw=>#_~uul z7h1jf^XJ!t&))>;FTs{d@auNUFYpl;K2<}c!;hPuo^HB!?HcO4k_+ixCAdz?PD8O; zekmTv5gg*pH1ku*E0T## zM)O!B3}d8ENBZd9ySM4osgu@l)3aw!gD;sLJ$e|~EX9Q;SNAHS<-0}meLF7y4BX7#e;0flrqk!)XGuv(-B_>As*h*Kkzp!&nHkI>O5yEI;7#@Cz>j!e zt$5n9Wy_J^ECTK_a2WI$1|MPMP*x{>`t%XrAv|BxzkmPew6rucdh}>ZQ~4i!PI-&w zM*{bVaDn$z=y(WOrpV5vXX%dX#>jjfF-GyxgWtvQFdexs2Uo;0E zUByP`WFSl7DH2>&_&LwBZ8zV1^Qd9NhSiV_BTobDp3wFRG?XH(rq!gHp?E+pCkYA zi|D7w&L#f`X|(2Oj@EyhztH-;ybmw)z>xsXFl=-fHJ&v$4chG(`1yTmYU+>tIgEXj zzJHh9U@!MDzb8IE6ua32z0VVqQlOzP^t}juMZVsGxRpcM3XGFu#*C>+HL^9oh4s`O!bkqn7H_h2_Gg0}oG@REeB-NO9$p>fHC2@@KC3L5 zZ3V|MVvp$eVXD>rx4`+Dv4gRL0&L(2ee#tOY;p;--^l(^dzjYPYYsdv;C`Uu8|z;? z(a!jDk}+emnDeaWQ@^H$Y&O{Ei7))+40f>_o*zPIl9Tc%hcUMJ^h1l^rPv$;jh*qw z9Qb{j`1u~XJu4XqH*F~}e~TZiWd1sAt^0|ND&l4dd?xUIw<=C`1?+&}Q=hzfbfl_97c~*?5l*lt-EsD^{2T z2M(Bn2M;P%w?d}l;d3>%@do;_IVSf-@VK9KXEb)-8aStcBbq{XAljIlg}tQdTF;s9 zA)?;M^;P`fS?W{BYb|#5B(|KcIHX#xh&G4ul7G4Gzkdn+?)dTJ16unu0(~2N)$YZi zGoDz~g)xJW*K+Wz*BEG+KqLAjV@qf7x&%JAW2X$Q_j~GU;$;?g2B_3tBS(%*h424{ zH^mGOd90)ry%EIikgZ@(bX|Js+qZ9MF!teqBN}@QhnA3}20Y4NBp>Sw z$Z-U=a1y@0!B4wzt=KENWj~_Hu2ICOpP?&*?-+P^g?_6a=6yum=#OlbD;>tK_QBte z(WUemiZhJA;sU)|<5cHjdoNLs0!(yD*Gur(0$r1%; z;tRRVo6PlQbhw`TNz5-rkBepB=q6+{^jEqdvjDP@KWzY*m78cJu52Z*>`Pp43*JKR z*F$SdYhSOQ2xcdb; z)FkMASNGV{QG7TV*?7$R9DZZ4vkUfjJ`I&=M~xa~cJAD1_UzfCb!Y%NU@SJHd^b@v zh!*T%8TXx`?RVI8G4blB>W8n#(aFQQrpk|x!_zo;`ZMD`V_z|pF;f|z!!yNk2Y+U0 z)fMsqbM&alG?Q`(Zg7`a@{-KObM!wTzk)0^-0FSE{A4`KK#docjmKOA~2|l#O6`>!+`t3YZZucH^Z$Z|n(AOE8 zQBJ9K!P*jfdKe!FV~*m3J)_}Sl@;t*`*iuLEB(^8gNIWfkQ_xv33UGz`eTSuGh`#k z@-B4qG5+}{T6=Dx7M^5(Pn4T$b5Z5vT9?sTKxa!@Bde-_PwSRLmA%)8mp_-oUo3i| zI~TczA?r_hRzhAmlG`Ha|B!pdau@p#Ab*G25Z#G?e}7cWSPz}vp}2tUh4Jiy98>pK zQm{>XCV<^I$S4BZUjvRWcgfxZ-#*C>-FIbe_>y{pHBFoBV(9;vHkNA7ceoG8kBB!j z=d%^@@x3>&V|h?t-}yK*H(gX2sY<2|V`H+D04=KvzS? zcB1_W&*ay|dkR}MVP!KZAj1e%RI==n5sHkNOI#}O7}@4%BimlCbeXwT8m zfsHNle--o+ke#55UvMkA2&UcZBKw`#Vk2~4Y5FHmo@~E?gb&5#!Qee6eDYarWV&Q8 zdGd^IV`)^p!v19|0oH_o&a20b8+SoYgD*=aio^BsWu3JvH`?<#B8uGLv~#JqX)YA8n;IB=lN(jH)W4 zUuXW^_dF{X3Oth*ixbP#k%TZ@&te?LVUn5wn zbyyiqZfp-&LxZm31^KvzuJzF`+IL;60{=F@ApaNu-bL&ybT*$&&SdkfYe0wHgOhta z2`=SlI^Q`$drbj>82c#y?LY+`LBGa^iuO?KQN!sE5NGZ~-d~Y3{)jwV z@4ZhjQ2YAP(5OAV&Jpj0hDVS|7i8mzfA$771(5gW0sJ%UrI%jP?FB`7yW$ym?0a8u z^&szEN#2;G{l1>DUziB~&$ORI22;5Hka>T=7If}+1c2w6qjw7Sof>p@=h+xy!)NS| z+iTAvyFqvLu-^sj!KO=Az;U5lX9}Xp+710r3l6-0L;q&r4py!Vj7Y|=V$MFk6&VKH z_3)Vm{&$f4dAe?iZqjQay{#&f-tXKTn`@04Fcqra~f zT)VeMzJ0a7fZuS&29SyJ-NxMSgwD@}H%NzVq47CzKL) zr7rXD&>ZM^4tTlc=lj>dK7(G~#g_(Z9|+uVWW-|=I+x|Fwl-sWLi-%>J%_wLX5MM= z?q}@l%=rTN^JtgLCM0Wc?!e{-1IF?yo2CD6@P3$QZ!>l+dK`k>n_6V$e&FBUDYlU+ z+3!@rWn&$5==`Auc>5D??x+9P&^-fOErpkf@_&0)hX7S?1_WtkvfK%UV>YLMW(ZKv3$l?%sy92w-!=5Ey;g+4)cUa(F zh&*&Qvk}^gpm!a8uk&1Xxei$fX4&FR=MNS6pZ0d}F_!CR8810+L@#e+C$AurpQ}%m z`wuwRi-)#J;C}*|Uq()gz;_53bGVL2&X;v&fxKYHRcx^5AmIHi{;zLurULI_oQ*sdFkbQ3K^B*_ABIPJHY^#47I@RXIt^Se zfb&!KlwF}O6TbBgPH*7v5e?YNi;Q^^-cQrYZY4v9`w(xJashw#y*+cofhqhmfN>7l zJ_Q{E>3axWtmOF?#_oWYyRkd#3&>?X^lyglTx6iNq{5o>eKbhcz*6kDXFK55yAZ)X z4-J1o?;XLr8@qb}S%1RyT;yI~_l&V?GIZWA8>Y36Cplh9!H(@W_Q=x#rp`)khJJm+ zVPhxpSMO{dMW-KuZyUU?7F>;m-!{^{KNk9P<-d%v$S;Kk;fF`P=am070*}^M@l*<* zuS+jH%O}p{LDyf9)vG)c{0N>)W=px2U)pa%h($xx4;}U!Hu}G}2tWE$zQeSbj~Fai z-#~jYI_?O38y9r`49^RQMR!Wh%#p5K+Gxp!Ig-~oc=3RhqItkme)GLW_<^f;3X#Bl zAQ)#A!yc4f08jdK`TouFBiocrBxiJ{vunlfVT`e{iFsSm8DuuO;M=B)5h46K!;;L9 zoqTo}df1N5)y5Va;9DMKpU59|2i%}eWNX50&rI=2efzW&+}1XP4`00)+6w)`FW9Vy z_SyFB+s&y{rz~9+1_wJNW1U;+EYUBw-+sHrFL;-O-=7Z;?%ut7ot&H;d)A9?{YMpA z#TwalmlE5`>rwur zf{n|6e}Y}*;oD}@rcLFCRk-%?&?@FxN`dhX@V?;QQMdf@V#W7a|2gBM!TUVzo58+- zd^RyLQSi%>Hh(ZJ^X+>R;@nVtyaV^o6L)q1V+V9J6%XX<_M6&r)2!bzry((HJ@oa$ zAMYe)>AQd@=o5^S^#6`{wVZJiY1=dAF|}F?;1-#pcMfXwH(Z7r_s~P_k zKK=~P_Q8+7XH?EMSv1kg|HHsnpEiU00$^_=W)%SQZR!E~HUR4x*0ufA&Cu0|xe-C! zmT$&cS{OSJdiSz6FJa6H`U{m~1A7C{US<9a$x662U)L(=DWEtFp1YxWJ~ZeXlohn= zfcGBr|Bbo~7%dsO_nixUqWyyT+&hew98xrn`>pU&3pq`u>iYrl`Iw%;!w_KF81CbT z9{UXq`mF_y``|fQ@Kk`Kbye@yZUFuY)}F?|sKC2o?01X!L`D_XRzO+b^vA=xz0^L3 j_d!v74`2l=x7DeUTkmRF)t}L*ikTwS|u0!8x3OprRg$ z=#Ye{h)xDEL_wk?iXvoGoD&sU289R{TZ~H6O~3j5@Ath<1EMSqVREQLef3_ws=MD? zx9YvdIp?C(Ac$2iPbry6;qwS%JbRXwmYNU_YQ#l4bqv*W@owgXB`v(LHrqM=x$Nv% z!!MWAY`1mmRvw55H9@T5H%6B_ua>J4C`JiPDMnbA2-N=r5-$*4o>eMRvkYySI(}u^oXCNsF=}1Q z#!jtYdWzb>C8TAGzMPblg+}KCDf`vtcPiys+p|<{d+sVHTYG18m)hLro%*W{?su{F zPtjU-Uw_OpwFN0@c3+TEIYamPX|wJAcv@B&-RGpo+I?B`4er+Y3nJ>@8U)tn1i@n6 z=LW%QwN}o(J?s}qHILq3qZ&dKhcJ;ZHV;4%e(Z*6_>a)pZDwTrJ-( zftcO$TaXb1a{aLC{si?HHN95wt)F^m|C`?8eT`i5KEG3PzKdoA+gwJlH4XQPE-)AP zC2nx+rhtBGZCr0k5Tr~A3TnLGWsRaC&J(3KoS#yviz`p+eu+lqX0l8KW&Xo-i%6&w3IcWjq)-+m#v#p-YB7nNgziRbiq zl1}d!s%O$9J}~EMIlBa|z4lsn-F4Twwr$&bsi~eZ{~($mvj zQc{sk3{+RER_%(WUBoqL(7eq1 zjD4z$Mx$MP-F;O`6nANJ#iQ^hpOse}xJa?t%6znSQTl&z_N4vu3#o6DCx^ z4-P}SbYS#fbImmqWLwmKn*DU?(#2J&QpMeJ%Pp=)4-$lUA=cQH=tJ(JF(o-U`C~dm z`4`lvQDabiO(?Rf2q9ehwsq^)u3fu!jyU3`O`GP%jT`62j2Tmim>6HZX3d&e*!hP3 z{re}w!*(7T{qQ9EI}%s@N|h@4O`A3?oOih{v@YFn!woJHiMXXpmwH)QS*}*CT9NA2 zt82||g>QZ(dZ9I#Idf(O`2200{(NjHAHQy_`~n~G;ZwDcbolW*b?W5Wv}se=cOe(j zy-IwYl${pFYWbyjAV=_sj~kKa!?dn^`SO0*vSq!}rAxob_o5#K6tp6ojO89G!; zrt>5dXdHu_XJQ+QBQ^vX`xPrzOalHL@UfT9kcXc&YSgGL>(z1f@$4WnY=K@T$8(4R zczXkQEx!HZW7+!JYU|mYuD6_j0`t; z@L;2<=np=pyhZbqfxAz*!22n5JcumQW#`hfbjNj7WWJIZqxcxW?_7A8fZP}ItQ#_J z$@3q_=?|Fy5`H_Iu^Rt1dI*rcXzB?Lo*{imr~Uf%D@QJVC-dIcGr>YG z1BefbZ@${FXbwF3ijB=FGTOtrfI7C2uswikAgjScLhPrj0mP0oY%YuP_)4^tm| z&4kBU+;>-eWBqF^+8KXBGG^>(<~*bM)UT<9HXH8?#25Z@47=C{&kv$A$w_&X#~3Ri z{m>G2DK?jY##Z=aCj34{{CpSP9+wP+o3;R$zrzofFn=XB@(#}f?lZBEuE4kT41l(# z@q8`up)CDx&}Xs*=BxOd0;I_(4)-hi-(%cw8GjG(dSaVZ3JK!^+AI$U`$WHDFS1dW z#d~z1Jkl**yx8sDz1!{Cvq!PI9x@#cpUbd~*U^vVnB3>W<1W^n!PtF$;2Z^xXezV= z(Z<}-*h_}4^_=+uBDxW|zJeb-Lwyo?t-!9Hz?M5H4yhI?qRnHxNA3l6| zL~EZ$pl^q-+Fl$ws}qY_Go}afS_Ga|8Uqa@Xhff6Y;?x2^Wk$7cFNESf1oZSUXI4j z0M(-7fB^$q!1w>cn_@KmPnSRp`^FAbQ zbVatxmGiZ<1=}tIPT%k3@yGwKH&E67n#oXG0H!{nJga2Um8I3fAdJ^Ja3_+`uJZ%^fLl^ zE4MsAzLt)R4>HE$Dm=f-o^&96M;Mbw{xTi^NJL*A@yym9;VQ18d|U-wiakE|l7NkB zudo1H*~q%o6kdLXExiw|?P#BchdRXHq4f7*Y!l>rr)(TB=J(j(CUV+-z_hg*zn=>% z<&ec1GmUV5kg;7tTST;Dt0NTi=u|%T0rDJ4e<|t;>L&DaFZQq-`i{^B*hCBH(;6Ti zY_Eo0J%!II588<@Re=ZFhZv$_{E?j~?*Nal79Y!iCdGHHmqrVESqmRp<8slDV*Mtb zDYttUy4NG?7SPuUn^8`wb-`>2Jw1dEBrr$u!Om!SR%``3);?Xn>Px@0jp5-42qZ_* zkq_N}gZ>i4sEM)>WO)a=`3V2~Gp(IlsD&rl-{VE*S}v-5TEQ4&XKy`aj@avE0Z0Bgo&QRz`Q?KinVXF*ZP_ zw<#`QdkH){CCAkLg%oVl&IGU<4;dvv`>VhSh&-wTM|kPJ@PcjV?8<|OY50`IN}yTXLC;5_v#NXpJf5&1 zdk>!MTuQV;qn)Fn1B)&4e--o+k)5E6UvMkA2&V0Ik^L5Iu?o7sX!^&F9n1T9TT>L5 zdx7_W@X2SfkqMH$0cu5f=sT>g1~uI3EdcHbo)$p3z?YF7$GI7y28P^C$|7 zeGeDQxljL&OV2w|JsZh)T(J~@o(nHweoy>OVlCHUW-7U}9l%~V)N`LnzHWoHeuhQ+ zvddNA-|`RglWyRh!@fgj_hZPZEDyU3bl4u9+~f&xDSy-X&pz7AQpoLn=>Yt5K&V_g z5B!_r$S;`;loPR!(!1USWUV~>PHC1G{C>PGmPTv!?Afyg%ig<%xgI*#c|bq< zP5#J2dkmFgJ3rBTC2UN&iBsMK|9W4p^Pg(i{vg`!$inys|2@(R)tp25g%NX(XZG3; z#EbN&{Q;mo%PU5W8l}BNl$_m>`;{YS-vgck`g+9Aj|#~1$J1|T1%jiqFy$o_Pw$Me zkD}ieoS`G=*Vw|MJr;Y|MEWDdnR}7N^~cm^JOFAT2s!T}J%OV%dOapMRND_~UxjRTF?JBoJJOCrmR&Rk znE!@e*D>aQpyv_B{Si3Bxt`Cn<>a@w%P*lZ+;i(_t+%J`3(g!S^@x{200)$v&|XG98W1=CY3|&-~jo2Rfbw-lU@Q!)st4Loe^( zOWn0k1a2ZS;;}0{x8*FiEMq!A`!w)9i@ZK!-cj)GV(e?o`2zSeXcx&QBx`VP#^!nf z#(0&@(*JjO-^;VN7`p;J_D1eC3|WyM__sU7Hc~13jul)M>!3sD6D7ghm3VU>{lA9p ziQuX$yiAn;+gT#=(RXH#0B1e;Z$Z9882=2k@1dQAZVk`8dGp-*_3Pc-xpVFQyMDl_ z?>Y5NYNBXhetTr`33|H?yUfC#C12r|o!C1raL+~_I=fi|ZMo39lD^k?F1uWbECe&Q zc+>eqMgFI~AAAhu`WePc&TG)iTiD6V$mHkhQ|11B&i$%G+bHlq4$Utir#ayJ1Q^q} zu8y3~>r4ZA!H%!kVCN*@{T=?VZ*#^2?;+%UH)llifcsPIaSpP2oxZi$%OPl(ij53| zXT29M#dC`#T>lW;h0o;^8jo$)0>=n^U;g?q@b_|_+#Y(~M+VEG?S=;%)0gXm%j&(||{Gql`=-I*^S zmsQZe4!S2H1Fa=ztU2FDgJcaX#eO^c0k__j2=+;6_$zvE4&H6p-Sf!$W3Hzo_lmk_ zjIGJgd7o^U)*MfAJePtU+c)^g(*vf?Qm%)7edA%VllZH5I**{!55cz)-j@lk#=>s{ z={_6_{gdRsj4|ZrLWA(bquztc|EhpTYpi%GfX~;Y7oII3&SXK?Uy;=-JQMsRo=ax) zxt3qrHzUNN-s*=A`^Js_?=8ZQ{*>=9t;B~67OZceJr5l>2foDxolnE_EMn2^k~4Fp zE1x!1vSE(obpl=jV5Msw@RZ+tZxMdr>YYO}aPN=DS;epiWEa4bK7GEAGk#>7l8NMu z&UCh|*xi>g7Mqy20i8i+wNt)*IvWwfuQM*m4B5$N`=W2p_(BHneB-3%_8q9@?`_n>M*4M~)a>XAF*aNX9zX(ph6z zZoTzZ!!LN}gFl=P5B`oFJG{)yOgjrkx8b8RTE!aW%sLO#ng00k<9)u#KCifUI#9*F zf8`Q8zv1_v^ml!kEDKQt96QH|{q51|=NLM+&=}8tIny}5rNrKypG)imMPZSDso(?h z@1J0IS@^zNyLN5inD4p>@z5$J8l}K^8+c!E@2Ok2X)P;j-nQ!l1h=YBI0nNC7j<~cL7@MJ^hIk;Cw{LQbOf$b`PGw@;D(LHozurzv z({}}r(Hj_PY!Tx|(l%wxqiVHQ$S)b+4IK792D}@IRrgX?(!Y=~%NYM8G2m&Q z?SvnF52>7PtZ1TDd`JLaMcSU+X9Ig9F)bUIZ&7#Cw;EVav+nJpu7j>B%uR~pHoh5W zv@o_i^zLBop2wI&^yerC2li^7y~6y7l9h04zOGf!Q$%qbJa<9!OlZ(IEQ@JZ0`Fbs z{|9v;Fl_a0*NT*<3s$=W8dJQ z-!kC17oM94o(gcZ?&{s#HNaoY+Ef)7XYj5Ve0mX|$SCGeMIHjmd^7BVb-UC)i1$e; zd{1D46N#M{X<+61Tn r9maFfXzWgZqwkyb>6!jgIl@RA;q>>m35<;25y}!78M{;Llhyqnc{3Bn literal 0 HcmV?d00001 diff --git a/extern/verse/dist/v_bignum.c b/extern/verse/dist/v_bignum.c new file mode 100644 index 00000000000..3f3ea7f9ccc --- /dev/null +++ b/extern/verse/dist/v_bignum.c @@ -0,0 +1,860 @@ +/* + * Routines for big (thousands of bits) unsigned integers, and + * doing simple maths operations on them. Written by Emil Brink. + * + * Part of the Verse core, see license details elsewhere. + * + * Bignums are represented as vectors of VBigDig (unsigned short), + * where the first element holds the length of the number in such + * digits. So a 32-bit number would be { 2, low, high }; digits are + * in little-endian format. + * + * Verse's uint16 and uint32 types are *not* used, since there is no + * need to limit the bits. If your machine has 32-bit shorts and 64- + * bit ints, this code should cope. + * + * By using unsigned shorts, which are assumed to be half the size of + * an unsigned int, we can easily do intermediary steps in int-sized + * variables, and thus get space for manual carry-management. + * + * This is the second incarnation of this code, the first one used + * a fixed 2,048-bit VBigNum structure passed by value. It had to be + * replaced since it was too weak for the desired functionality. Now, + * there's roughly 1,5 weeks of time gone into this code, which still + * means it's optimized for simplicity rather than speed. + * + * There has been neither time nor interest to meditate over FFTs and + * Karatsubas. Reasonable improvements are of course welcome, although + * this code *should* not be a bottleneck. Famous last words... + * + * In general, these routines do not do a lot of error checking, they + * assume you know what you're doing. Numbers must have >0 digits. + * Shifts should not be overly large (1e3 bits: safe, ~2e9+: avoid). +*/ + +#include +#include +#include +#include + +#include "v_randgen.h" + +#include "v_bignum.h" + +#define MAX_DIG ((1UL << V_BIGBITS) - 1) + +/* ----------------------------------------------------------------------------------------- */ + +/* Some routines need temporary storage to hold a term or two (the multi- + * plier, for instance). Since we don't want to use malloc()/free(), let's + * just have a bunch of digits that it's possible to allocate from in a + * stack-like manner. +*/ +static VBigDig heap[2048 + 32]; +static unsigned int heap_pos; + +/* Allocate a number of digits, returning it un-initialized. */ +static VBigDig * bignum_alloc(unsigned int n) +{ + VBigDig *y; + + if(heap_pos + n > sizeof heap / sizeof *heap) + { + printf("Out of memory in bignum heap -- unbalanced calls?\n"); + return NULL; + } + y = heap + heap_pos; + heap_pos += n + 1; + *y = n; + return y; +} + +/* Free a number previously allocated by bignum_allow() above. MUST match in sequences. */ +static void bignum_free(const VBigDig *x) +{ + heap_pos -= *x + 1; +} + +/* ----------------------------------------------------------------------------------------- */ + +/* Set x from bits. External representation is big-endian byte array. */ +void v_bignum_raw_import(VBigDig *x, const void *bits) +{ + const unsigned char *bytes = bits; + int i; + + for(i = *x++ - 1; i >= 0; i--) + { + x[i] = ((VBigDig) *bytes++) << 8; + x[i] |= *bytes++; + } +} + +/* Set bits to value of x. External representation is big-endian byte array. */ +void v_bignum_raw_export(const VBigDig *x, void *bits) +{ + unsigned char *bytes = bits; + int i; + + for(i = *x++ - 1; i >= 0; i--) + { + *bytes++ = x[i] >> 8; + *bytes++ = (unsigned char) x[i]; + } +} + +/* ----------------------------------------------------------------------------------------- */ + +/* Assigns x = 0. */ +void v_bignum_set_zero(VBigDig *x) +{ + memset(x + 1, 0, *x * sizeof *x); +} + +/* Assigns x = 1. */ +void v_bignum_set_one(VBigDig *x) +{ + int i; + + for(i = *x++ - 1, *x++ = 1; i > 0; i--) + *x++ = 0; +} + +/* Assigns x = y. */ +void v_bignum_set_digit(VBigDig *x, VBigDig y) +{ + v_bignum_set_zero(x); + x[1] = y; +} + +/* Assigns x = , with string in decimal ASCII. Kind of slow. */ +void v_bignum_set_string(VBigDig *x, const char *string) +{ + unsigned int d; + + v_bignum_set_zero(x); + for(; *string && isdigit(*string); string++) + { + v_bignum_mul_digit(x, 10); + d = *string - '0'; + v_bignum_add_digit(x, d); + } +} + +/* Assigns x = , with string in hexadecimal ASCII. */ +void v_bignum_set_string_hex(VBigDig *x, const char *string) +{ + unsigned int d; + + if(string[0] == '0' && (string[1] == 'x' || string[1] == 'X')) + string += 2; + v_bignum_set_zero(x); + for(; *string && isxdigit(*string); string++) + { + v_bignum_bit_shift_left(x, 4); + d = tolower(*string) - '0'; + if(d > 9) + d -= ('a' - '0') - 10; + x[1] |= (d & 0xF); + } +} + +/* Performs x = y, taking care to handle different precisions correctly by truncating. */ +void v_bignum_set_bignum(VBigDig *x, const VBigDig *y) +{ + int xs, ys, i, s; + + xs = x[0]; + ys = y[0]; + if(xs == ys) /* For same sizes, just memcpy() and be done. */ + { + memcpy(x + 1, y + 1, xs * sizeof *x); + return; + } + else if(ys > xs) + s = xs; + else + s = ys; + /* Copy as many digits as will fit, and clear any remaining high digits. */ + for(i = 1; i <= s; i++) + x[i] = y[i]; + for(; i <= xs; i++) + x[i] = 0; +} + +/* Performs x = y[msb:msb-bits], right-adjusting the result. */ +void v_bignum_set_bignum_part(VBigDig *x, const VBigDig *y, unsigned int msb, unsigned int bits) +{ + unsigned int i, bit; + + v_bignum_set_zero(x); + if(y == NULL || msb > (y[0] * (CHAR_BIT * sizeof *x))) + return; + for(i = 0; i < bits; i++) + { + bit = msb - (bits - 1) + i; + if(v_bignum_bit_test(y, bit)) + v_bignum_bit_set(x, i); + } +} + +/* Set x to a random bunch of bits. Should use a real random source. */ +void v_bignum_set_random(VBigDig *x, VRandGen *gen) +{ + unsigned int s = *x++; + + if(gen != NULL) + v_randgen_get(gen, x, s * sizeof *x); + else + { + fprintf(stderr, "** Warning: Calling v_bignum_set_random() without VRandGen is potentially expensive\n"); + if((gen = v_randgen_new()) != NULL) + { + v_randgen_get(gen, x, s * sizeof *x); + v_randgen_destroy(gen); + } + else + fprintf(stderr, __FILE__ ": Couldn't create random number generator\n"); + } +} + +/* Print x in hexadecimal, with 0x prefix but no linefeed. */ +void v_bignum_print_hex(const VBigDig *x) +{ + int i, s = *x; + + printf("0x"); + for(i = 0; i < s; i++) + printf("%04X", x[s - i]); +} + +/* Print x in hexadecimal, with linefeed. */ +void v_bignum_print_hex_lf(const VBigDig *x) +{ + v_bignum_print_hex(x); + printf("\n"); +} + +/* ----------------------------------------------------------------------------------------- */ + +/* x = ~x. */ +void v_bignum_not(VBigDig *x) +{ + unsigned int i, s = *x++; + + for(i = 0; i < s; i++) + x[i] = ~x[i]; +} + +int v_bignum_bit_test(const VBigDig *x, unsigned int bit) +{ + unsigned int slot = bit / (CHAR_BIT * sizeof *x), m = 1 << (bit % (CHAR_BIT * sizeof *x)); + + if(slot < x[0]) + return (x[slot + 1] & m) != 0; + return 0; +} + +/* Compute x |= (1 << bit). */ +void v_bignum_bit_set(VBigDig *x, unsigned int bit) +{ + unsigned int slot, m; + + if(bit >= (*x * (CHAR_BIT * sizeof *x))) + return; + slot = bit / (CHAR_BIT * sizeof *x); + m = 1 << (bit % (CHAR_BIT * sizeof *x)); + x[1 + slot] |= m; +} + +/* Returns index of most signifant '1' bit of x, or -1 if x == 0. */ +int v_bignum_bit_msb(const VBigDig *x) +{ + int i; + unsigned int s = *x++; + + for(i = s - 1; i >= 0; i--) + { + if(x[i] != 0) + { + int bit = (i + 1) * (CHAR_BIT * sizeof *x) - 1; + VBigDig d = x[i], mask; + + for(mask = 1 << (CHAR_BIT * sizeof *x - 1); mask != 0; mask >>= 1, bit--) + { + if(d & mask) + return bit; + } + } + } + return -1; +} + +int v_bignum_bit_size(const VBigDig *x) +{ + return *x * V_BIGBITS; +} + +/* Perform x <<= count. */ +void v_bignum_bit_shift_left(VBigDig *x, unsigned int count) +{ + unsigned int t, carry, s = *x++; + register int i; + + if(count >= CHAR_BIT * sizeof *x) /* Shift whole digits. */ + { + unsigned int places = count / (CHAR_BIT * sizeof *x); + + for(i = s - 1; i >= (int) places; i--) + x[i] = x[i - places]; + for(; i >= 0; i--) /* Clear out the LSBs. */ + x[i] = 0; + count -= places * (CHAR_BIT * sizeof *x); + if(count == 0) + return; + } + /* Shift bits. */ + for(i = carry = 0; i < (int) s; i++) + { + t = (x[i] << count) | carry; + x[i] = t; + carry = t >> (CHAR_BIT * sizeof *x); + } +} + +/* Perform x <<= 1. This is a frequent operation so it can have its own function. */ +void v_bignum_bit_shift_left_1(VBigDig *x) +{ + register unsigned int t, carry, s = *x++, i; + + /* Shift bits. */ + for(i = carry = 0; i < s; i++) + { + t = (x[i] << 1) | carry; + x[i] = t; + carry = t >> (CHAR_BIT * sizeof *x); + } +} + +/* Perform x >>= count. */ +void v_bignum_bit_shift_right(VBigDig *x, unsigned int count) +{ + unsigned int t, carry, s = *x++; + int i; + + /* Shift entire digits first. */ + if(count >= CHAR_BIT * sizeof *x) + { + unsigned int places = count / (CHAR_BIT * sizeof *x); + + if(places > s) + { + memset(x, 0, s * sizeof *x); + return; + } + for(i = 0; i < (int) (s - places); i++) + x[i] = x[i + places]; + for(; i < (int) s; i++) + x[i] = 0; + count -= places * CHAR_BIT * sizeof *x; + if(count == 0) + return; + } + /* Shift any remaining bits. */ + for(i = s - 1, carry = 0; i >= 0; i--) + { + t = x[i] << (CHAR_BIT * sizeof *x); + t >>= count; + t |= carry; + carry = (t & MAX_DIG) << (CHAR_BIT * sizeof *x); + x[i] = t >> (CHAR_BIT * sizeof *x); + } +} + +/* ----------------------------------------------------------------------------------------- */ + +/* Return x == 0. */ +int v_bignum_eq_zero(const VBigDig *x) +{ + unsigned int i, s = *x++; + + for(i = 0; i < s; i++) + if(x[i]) + return 0; + return 1; +} + +/* Return x == 1. */ +int v_bignum_eq_one(const VBigDig *x) +{ + unsigned int i, s = *x++; + + if(x[0] != 1) + return 0; + for(i = 1; i < s; i++) + if(x[i]) + return 0; + return 1; +} + +/* Returns x == y, handling different lengths properly. */ +int v_bignum_eq(const VBigDig *x, const VBigDig *y) +{ + unsigned int i, xs, ys, cs; + + if(x == y) /* Quick test thanks to pointer representation. */ + return 1; + xs = *x++; + ys = *y++; + + if(xs == ys) /* Same size? Then let's be quick about this. */ + return memcmp(x, y, xs * sizeof *x) == 0; + else + { + cs = xs < ys ? xs : ys; /* Common size. */ + if(memcmp(x, y, cs * sizeof *x) == 0) + { + const VBigDig *l; + + if(cs == xs) /* y is longer. */ + l = y, i = ys - 1; + else + l = x, i = xs - 1; + for(; i > cs; i--) + if(l[i]) + return 0; + return 1; + } + } + return 0; +} + +/* Returns x >= y. */ +int v_bignum_gte(const VBigDig *x, const VBigDig *y) +{ + unsigned int xs, ys; + int i, j, k; + + if(x == y) + return 1; + /* Find indexes of highest-most used digit in each of the numbers. */ + xs = *x++; + ys = *y++; + for(i = xs - 1; i >= 0; i--) + if(x[i] != 0) + break; + for(j = ys - 1; j >= 0; j--) + if(y[j] != 0) + break; + /* Both zero? */ + if(i < 0 && j < 0) + return 1; + /* Quick answers exists for different-sized numbers. Find them. */ + if(i < j) + return 0; + if(i > j) + return 1; + /* Compare digit by digit. */ + for(k = i; k >= 0; k--) + { + if(x[k] < y[k]) + return 0; + if(x[k] > y[k]) + return 1; + } + return x[k] >= y[k]; +} + +/* ----------------------------------------------------------------------------------------- */ + +/* Computes x += y. */ +void v_bignum_add_digit(VBigDig *x, VBigDig y) +{ + unsigned int i, s = *x++, t; + + t = x[0] + y; + x[0] = t; + if(t > MAX_DIG) + { + for(i = 1; i < s; i++) + { + if(++x[i]) + break; + } + } +} + +/* Computes x -= y. */ +void v_bignum_sub_digit(VBigDig *x, VBigDig y) +{ + unsigned int i, s = *x++, t; + + t = x[0] - y; + x[0] = t; + if(t > MAX_DIG) + { + for(i = 1; i < s; i++) + { + x[i]--; + if(x[i] < MAX_DIG) + break; + } + } +} + +/* Computes x *= y. */ +void v_bignum_mul_digit(VBigDig *x, VBigDig y) +{ + unsigned int i, s = *x++, carry, t; + + for(i = carry = 0; i < s; i++) + { + t = x[i] * y + carry; + x[i] = t; + carry = t >> (CHAR_BIT * sizeof *x); + } +} + +/* ----------------------------------------------------------------------------------------- */ + +/* Computes x += y. */ +void v_bignum_add(VBigDig *x, const VBigDig *y) +{ + unsigned int i, xs = *x++, ys = *y++, s, carry, t; + + s = xs < ys ? xs : ys; + for(i = carry = 0; i < s; i++) + { + t = x[i] + y[i] + carry; + x[i] = t; + carry = t > MAX_DIG; + } + for(; carry && i < xs; i++) + { + t = x[i] + carry; + x[i] = t; + carry = t > MAX_DIG; + } +} + +/* Computes x -= y. */ +void v_bignum_sub(VBigDig *x, const VBigDig *y) +{ + unsigned int i, xs = *x++, ys = *y++, s, carry, t; + + if(x == y) + { + v_bignum_set_zero(x - 1); + return; + } + s = xs < ys ? xs : ys; + for(i = carry = 0; i < s; i++) + { + t = x[i] - y[i] - carry; + x[i] = t; + carry = t > MAX_DIG; + } + for(; carry && i < xs; i++) + { + t = x[i] - carry; + x[i] = t; + carry = t > MAX_DIG; + } +} + +/* Compute x *= y, using as many digits as is necessary, then truncating the + * result down. This is Algorithm 14.12 from "Handbook of Applied Cryptography". +*/ +void v_bignum_mul(VBigDig *x, const VBigDig *y) +{ + int n = *x, t = *y, i, j; + VBigDigs uv = 0, c, w[2048]; + + memset(w, 0, (n + t + 1) * sizeof *w); + for(i = 0; i < t; i++) + { + c = 0; + for(j = 0; j < n; j++) + { + uv = w[i + j] + x[1 + j] * y[1 + i] + c; + w[i + j] = uv & ((1 << V_BIGBITS) - 1); + c = uv >> V_BIGBITS; + } + w[i + n + 1] = uv >> V_BIGBITS; + } + /* Write low words of w back into x. */ + for(i = 0; i < *x; i++) + x[1 + i] = w[i]; +} + +/* Computes x /= y and remainder = x % y. */ +void v_bignum_div(VBigDig *x, const VBigDig *y, VBigDig *remainder) +{ + VBigDig *q, *work; + int msbx = v_bignum_bit_msb(x), msby = v_bignum_bit_msb(y), next; + + /* Compare magnitudes of inputs, allows quick exits. */ + if(msby > msbx) + { + if(remainder != NULL) + v_bignum_set_bignum(remainder, x); + v_bignum_set_zero(x); + return; + } + if(msby < 0) + { + v_bignum_set_zero(x); + return; + } + q = bignum_alloc(*x); + v_bignum_set_zero(q); + work = bignum_alloc(*x); + v_bignum_set_bignum_part(work, x, msbx, msby + 1); + + for(next = msbx - (msby + 1); next >= -1; next--) + { + v_bignum_bit_shift_left_1(q); + if(v_bignum_gte(work, y)) + { + q[1] |= 1; + v_bignum_sub(work, y); + } + v_bignum_bit_shift_left_1(work); + if(v_bignum_bit_test(x, next)) + work[1] |= 1; + } + v_bignum_bit_shift_right(work, 1); /* Undo the last shift (when next==-1). */ + + if(remainder != NULL) + { +/* printf("div() got remainder "); + v_bignum_print_hex_lf(work); +*/ + v_bignum_set_bignum(remainder, work); + } + bignum_free(work); + v_bignum_set_bignum(x, q); + bignum_free(q); +} + +/* Computes x %= y. */ +void v_bignum_mod(VBigDig *x, const VBigDig *y) +{ + int digs; + VBigDig *tmp; + +/* printf("computing "); + v_bignum_print_hex(x); + printf("L %% "); + v_bignum_print_hex(y); +*/ + digs = *x > *y ? *x : *y; + tmp = bignum_alloc(digs); + v_bignum_div(x, y, tmp); + v_bignum_set_bignum(x, tmp); + bignum_free(tmp); +/* printf("L = "); + v_bignum_print_hex_lf(x); +*/ +} + +/* Initialize Barrett reduction by computing the "mu" helper value. Defined in + * Handbook of Applied Cryptography algorithm 14.42 as floor(b^2k / m). +*/ +const VBigDig * v_bignum_reduce_begin(const VBigDig *m) +{ + VBigDig *mu; + int k; + + for(k = *m; m[k] == 0; k--) + ; +/* printf("k=%d -> digits are 0..%u\n", k, k - 1); + printf("computing mu=floor(65536^%d/", 2 * k); + v_bignum_print_hex(m); + printf(")\n"); +*/ mu = bignum_alloc(2 * k + 1); + /* b ^ 2k is just 65536 << 2k, i.e. set bit 16 * 2k. */ + v_bignum_set_zero(mu); + v_bignum_bit_set(mu, V_BIGBITS * 2 * k); +/* v_bignum_print_hex_lf(mu);*/ + v_bignum_div(mu, m, NULL); + + return mu; +} + +void v_bignum_reduce_end(const VBigDig *mu) +{ + bignum_free(mu); +} + +/* Compute x % m, using mu as the helper quantity mu, precomputed by the + * routine above. +*/ +void v_bignum_reduce(VBigDig *x, const VBigDig *m, const VBigDig *mu) +{ + VBigDig *q, *r1, *r2, *r; + int i, k; + + for(k = *m; m[k] == 0; k--) + ; + /* Step 1, compute the q helper. */ + q = bignum_alloc(*x + *mu - (k - 1)); /* Tighter bound number length (was 2 * *x). */ + v_bignum_set_bignum(q, x); + v_bignum_bit_shift_right(q, V_BIGBITS * (k - 1)); + v_bignum_mul(q, mu); + v_bignum_bit_shift_right(q, V_BIGBITS * (k + 1)); + + /* Step 2, initialize. */ + r1 = bignum_alloc(*x); + r2 = bignum_alloc(*x); + v_bignum_set_bignum(r1, x); + for(i = k + 1; i < *r1; i++) + r1[i + 1] = 0; + v_bignum_set_bignum(r2, q); + v_bignum_mul(r2, m); + for(i = k + 1; i < *r2; i++) + r2[i + 1] = 0; + r = x; + v_bignum_set_bignum(r, r1); + v_bignum_sub(r, r2); + /* Step 3, make sure r is positive. */ + if(v_bignum_bit_test(r, V_BIGBITS * *r - 1)) + { + VBigDig *term; + + term = bignum_alloc(k + 1 * V_BIGBITS); + v_bignum_set_zero(term); + v_bignum_bit_set(term, V_BIGBITS * (k + 1)); + v_bignum_add(r, term); + bignum_free(term); + } + /* Step 4, loop. */ + while(v_bignum_gte(r, m)) + v_bignum_sub(r, m); + + bignum_free(r2); + bignum_free(r1); + bignum_free(q); +} + +/* Compute x * x using the algorithm 14.16 from "Handbook of Applied Cryptography". + * Note that since 'w' needs to be double-precision (i.e., 32-bit), we cannot allocate + * it using bignum_alloc() cleanly. Thus the static limit, which should be enough here. + * NOTE: This very much assumes V_BIGBITS == 16. +*/ +void v_bignum_square_half(VBigDig *x) +{ + VBigDigs w[256], uv, c, ouv; + int t = *x / 2, i, j, high; + + if(t == 0) + return; + for(; x[t] == 0; t--) + ; + memset(w, 0, 2 * t * sizeof *w); /* Clear digits of w. */ +/* printf("print %lu, ", ++count); + v_bignum_print_hex(x); + printf("*"); + v_bignum_print_hex(x); +*/ for(i = 0; i < t; i++) + { +/* printf("computing w[%d]: %lX + %lX * %lX\n", 2 * i, w[2 * i], x[1 + i], x[1 + i]);*/ + uv = w[2 * i] + x[1 + i] * x[1 + i]; +/* printf("setting w[%d]=%X [before]\n", 2 * i, uv & 0xffff);*/ + w[2 * i] = uv & 0xffff; + c = uv >> V_BIGBITS; +/* printf("uv before=%X, c=%X\n", uv, c);*/ + high = 0; + for(j = i + 1; j < t; j++) + { +/* printf("computing uv=%X+2*%X*%X+%X\n", w[i + j], x[1 + j], x[1 + i], c);*/ + uv = x[1 + j] * x[1 + i]; + high = (uv & 0x80000000) != 0; + uv *= 2; + ouv = uv; /* Addition below might wrap and generate high bit. */ + uv += w[i + j] + c; +/* printf("ouv=0x%lX uv=0x%lX\n", ouv, uv);*/ + high |= uv < ouv; +/* printf("setting w[%d]=%lX [inner] uv=%lX high=%d c=%X\n", i + j, uv & 0xffff, uv, high, c);*/ + w[i + j] = uv & 0xffff; + c = (uv >> V_BIGBITS) | (high << V_BIGBITS); + } +/* printf("setting w[%d] to %X [after]\n", i + t, (uv >> 16) | (high << 16));*/ + w[i + t] = (uv >> V_BIGBITS) | (high << V_BIGBITS); + } +/* printf("w=0x"); + for(i = *x - 1; i >= 0; i--) + printf("%04X.", w[i]); + printf("\n"); +*/ /* Write low words of w back into x, trashing it with the square. */ + for(i = 0; i < 2 * t; i++) + x[1 + i] = w[i]; + for(; i < *x; i++) + x[1 + i] = 0; +/* printf("=="); + v_bignum_print_hex_lf(x); +*/ +} + +/* Computes x = (x^y) % n, where ^ denotes exponentiation. */ +void v_bignum_pow_mod(VBigDig *x, const VBigDig *y, const VBigDig *n) +{ + VBigDig *tmp; + const VBigDig *mu; + int i, k; + +/* printf("computing pow("); + v_bignum_print_hex(x); + printf("L,"); + v_bignum_print_hex(y); + printf("L,"); + v_bignum_print_hex(n); + printf("L)\n"); +*/ + tmp = bignum_alloc(2 * *x); /* Squaring needs twice the bits, or lossage occurs. */ + v_bignum_set_bignum(tmp, x); + k = v_bignum_bit_msb(y); + mu = v_bignum_reduce_begin(n); + for(i = k - 1; i >= 0; i--) + { + v_bignum_square_half(tmp); + v_bignum_reduce(tmp, n, mu); + if(v_bignum_bit_test(y, i)) + { + v_bignum_mul(tmp, x); + v_bignum_reduce(tmp, n, mu); + } + } + v_bignum_set_bignum(x, tmp); + v_bignum_reduce_end(mu); + bignum_free(tmp); +} + +/* ----------------------------------------------------------------------------------------- */ + +#if defined STANDALONE + +int main(void) +{ + VBigDig VBIGNUM(x, 3648), VBIGNUM(y, 128), VBIGNUM(z, 128); + + printf("MAX_DIG=%u\n", MAX_DIG); + + v_bignum_set_string_hex(x, "0x433864FE0F8FAC180FF1BC3A5BFD0C5566F6B11679E27294EDCC43056EB73EE118415E0CD6E6519509476EB21341ED0328BA7B14E0ED80D5E100A4549C5202B57B4CF17A74987631B6BA896C0DBA2095A7EDE5B9C4B4EEFCD1B9EF8474BCB7FBD0F64B549625D444847ED1FCB7F8050EB4F22794F694A0FAC6DFFB781C264B227966840185F9216484F6A7954741CB11FC14DEC2937EAD2CE640FD9A4339706BDB5BC355079C2F2F7994669DFA5B20C50D957A676E67C86835037078323A0BDAD3686B8E638749F327A7AD433C0D18BCD2FC970D125914C7FBEE061290A0F0F3572E207"); + v_bignum_set_bignum(y, x); + v_bignum_set_digit(z, 77); + + printf("x:"); + v_bignum_print_hex_lf(x); + printf("y:"); + v_bignum_print_hex_lf(y); + printf("r:"); + v_bignum_print_hex_lf(z); + v_bignum_pow_mod(x, y, z); + printf(" ="); + v_bignum_print_hex_lf(x); + + return 0; +} + +#endif /* STANDALONE */ diff --git a/extern/verse/dist/v_bignum.h b/extern/verse/dist/v_bignum.h new file mode 100644 index 00000000000..06e58844452 --- /dev/null +++ b/extern/verse/dist/v_bignum.h @@ -0,0 +1,89 @@ +/* + * Verse routines for big integer operations. + * Handy in heavy encryption done during connect. +*/ + +#include + +#include "v_randgen.h" + +/* ----------------------------------------------------------------------------------------- */ + +typedef unsigned short VBigDig; /* Type used to hold one digit of a bignum. */ +typedef unsigned int VBigDigs; /* Should hold precisely two digits. */ + +#define V_BIGBITS (CHAR_BIT * sizeof (VBigDig)) + +/* Use this macro to initialize big number variables, like so: + * VBigDig BIGNUM(foo, 128), BIGNUM(bar, 256); + * Creates automatic variables 'foo' of 128 bits, and 'bar' of 256. + * + * Note that 'bits' must be a multiple of V_BIGBITS, completely + * arbitrary number sizes are not supported by this module. +*/ +#define VBIGNUM(n, bits) n[1 + (bits / V_BIGBITS)] = { bits / V_BIGBITS } + +/* ----------------------------------------------------------------------------------------- */ + +/* Import/export numbers from raw bits. The number x must have been allocated + * with the desired number of bits to read/write. +*/ +extern void v_bignum_raw_import(VBigDig *x, const void *bits); +extern void v_bignum_raw_export(const VBigDig *x, void *bits); + +/* Initializers. */ +extern void v_bignum_set_zero(VBigDig *x); +extern void v_bignum_set_one(VBigDig *x); +extern void v_bignum_set_digit(VBigDig *x, VBigDig y); +extern void v_bignum_set_string(VBigDig *x, const char *string); /* Decimal. */ +extern void v_bignum_set_string_hex(VBigDig *x, const char *string); +extern void v_bignum_set_bignum(VBigDig *x, const VBigDig *y); +/* x = most significant bits of , starting at . Right- + * adjusted in x, so that e.g. y=0xcafebabec001 msb=47 bits=16 gives x=0xcafe. +*/ +extern void v_bignum_set_bignum_part(VBigDig *x, const VBigDig *y, + unsigned int msb, unsigned int bits); +extern void v_bignum_set_random(VBigDig *x, VRandGen *gen); + +/* Handy during debugging. */ +extern void v_bignum_print_hex(const VBigDig *x); +extern void v_bignum_print_hex_lf(const VBigDig *x); + +/* Bit operators. */ +extern void v_bignum_not(VBigDig *x); +extern int v_bignum_bit_test(const VBigDig *x, unsigned int bit); +extern void v_bignum_bit_set(VBigDig *x, unsigned int bit); +extern int v_bignum_bit_msb(const VBigDig *x); +extern int v_bignum_bit_size(const VBigDig *x); +extern void v_bignum_bit_shift_left(VBigDig *x, unsigned int count); +extern void v_bignum_bit_shift_left_1(VBigDig *x); +extern void v_bignum_bit_shift_right(VBigDig *x, unsigned int count); + +/* Comparators. */ +extern int v_bignum_eq_zero(const VBigDig *x); /* x == 0. */ +extern int v_bignum_eq_one(const VBigDig *x); /* x == 1. */ +extern int v_bignum_eq(const VBigDig *x, const VBigDig *y); /* x == y. */ +extern int v_bignum_gte(const VBigDig *x, const VBigDig *y); /* x >= y. */ + +/* Number vs single-digit arithmetic. */ +extern void v_bignum_add_digit(VBigDig *x, VBigDig y); /* x += y. */ +extern void v_bignum_sub_digit(VBigDig *x, VBigDig y); /* x -= y. */ +extern void v_bignum_mul_digit(VBigDig *x, VBigDig y); /* x *= y. */ + +/* Arithmetic. */ +extern void v_bignum_add(VBigDig *x, const VBigDig *y); /* x += y. */ +extern void v_bignum_sub(VBigDig *x, const VBigDig *y); /* x -= y. */ +extern void v_bignum_mul(VBigDig *x, const VBigDig *y); /* x *= y. */ +extern void v_bignum_div(VBigDig *x, const VBigDig *y, VBigDig *remainder); +extern void v_bignum_mod(VBigDig *x, const VBigDig *y); /* x %= y. */ + +/* Barrett reducer for fast x % m computation. Requires precalcing step. */ +extern const VBigDig * v_bignum_reduce_begin(const VBigDig *m); +extern void v_bignum_reduce(VBigDig *x, const VBigDig *m, const VBigDig *mu); +extern void v_bignum_reduce_end(const VBigDig *mu); + +/* Compute x *= x, assuming x only uses half of its actual size. */ +extern void v_bignum_square_half(VBigDig *x); + +/* Compute pow(x, y, n) == (x raised to the y:th power) modulo n. */ +extern void v_bignum_pow_mod(VBigDig *x, const VBigDig *y, const VBigDig *n); diff --git a/extern/verse/dist/v_cmd_buf.c b/extern/verse/dist/v_cmd_buf.c new file mode 100644 index 00000000000..b7faf227352 --- /dev/null +++ b/extern/verse/dist/v_cmd_buf.c @@ -0,0 +1,119 @@ +/* +** +*/ + +#include +#include +#include + +#include "verse_header.h" +#include "v_pack.h" +#include "v_cmd_buf.h" + +static const size_t vcmdbuf_chunk_size[] = { 10000, 10000, 10000, 10000, 8000, 5000, 500 }; /* If you think memory is cheap, set this to a high value. */ + +/* Sizes of individual command buffers, indexable by VCMDBufSize values. Switch-killer. */ +static const size_t vcmdbuf_size[] = { + sizeof (VCMDBuffer10), sizeof (VCMDBuffer20), sizeof (VCMDBuffer30), sizeof (VCMDBuffer80), + sizeof (VCMDBuffer160), sizeof (VCMDBuffer320), sizeof (VCMDBuffer1500) +}; + +#define VCMDBUF_INIT_CHUNK_FACTOR 0.5 + +static struct { + VCMDBufHead *buffers[VCMDBS_COUNT]; + unsigned int available[VCMDBS_COUNT]; +} VCMDBufData; + +static boolean v_cmd_buf_initialized = FALSE; + +void cmd_buf_init(void) +{ + unsigned int i, j; + VCMDBufHead *buf, *b; + + for(i = 0; i < VCMDBS_COUNT; i++) + { + VCMDBufData.buffers[i] = NULL; + VCMDBufData.available[i] = (unsigned int) (vcmdbuf_chunk_size[i] * VCMDBUF_INIT_CHUNK_FACTOR); + for(j = 0, buf = NULL; j < VCMDBufData.available[i]; j++, buf = b) + { + b = v_cmd_buf_allocate(i); + b->next = buf; + } + VCMDBufData.buffers[i] = buf; + } + v_cmd_buf_initialized = TRUE; +} + +VCMDBufHead * v_cmd_buf_allocate(VCMDBufSize buf_size) +{ + VCMDBufHead *output = NULL; + + if(VCMDBufData.buffers[buf_size] != NULL) + { + output = VCMDBufData.buffers[buf_size]; + VCMDBufData.buffers[buf_size] = output->next; + VCMDBufData.available[buf_size]--; + } + else + { + if(buf_size < sizeof vcmdbuf_size / sizeof *vcmdbuf_size) + output = malloc(vcmdbuf_size[buf_size]); + else + { + fprintf(stderr, "v_cmd_buf.c: Can't handle buffer size %d\n", buf_size); + return NULL; + } + output->buf_size = buf_size; + } + output->next = NULL; + output->packet = 0; + output->size = 0; + output->address_size = -1; + return output; +} + +void v_cmd_buf_free(VCMDBufHead *head) +{ + if(VCMDBufData.available[head->buf_size] < vcmdbuf_chunk_size[head->buf_size]) + { + head->next = VCMDBufData.buffers[head->buf_size]; + VCMDBufData.buffers[head->buf_size] = head; + VCMDBufData.available[head->buf_size]++; + } + else + free(head); +} + +void v_cmd_buf_set_size(VCMDBufHead *head, unsigned int size) +{ + head->size = size; +} + +void v_cmd_buf_set_address_size(VCMDBufHead *head, unsigned int size) +{ + unsigned int i; + + head->address_size = size; + head->address_sum = 0; + for(i = 1; i < size + 1; i++) + head->address_sum += i * i * (uint32)(((VCMDBuffer1500 *)head)->buf[i - 1]); +} + +void v_cmd_buf_set_unique_address_size(VCMDBufHead *head, unsigned int size) +{ + static unsigned int i = 0; + + head->address_size = size; + head->address_sum = i++; +} + +boolean v_cmd_buf_compare(VCMDBufHead *a, VCMDBufHead *b) +{ + if(a->address_sum != b->address_sum) + return FALSE; + if(a->address_size != b->address_size) + return FALSE; + return memcmp(((VCMDBuffer1500 *)a)->buf, ((VCMDBuffer1500 *)b)->buf, a->address_size) == 0; +} diff --git a/extern/verse/dist/v_cmd_buf.h b/extern/verse/dist/v_cmd_buf.h new file mode 100644 index 00000000000..6eda7640bb1 --- /dev/null +++ b/extern/verse/dist/v_cmd_buf.h @@ -0,0 +1,74 @@ +/* +** +*/ + +#include + +#include "verse_header.h" +#include "v_pack.h" + +#define V_NOQ_MAX_PACKET_SIZE 1500 + +typedef enum { + VCMDBS_10 = 0, + VCMDBS_20 = 1, + VCMDBS_30 = 2, + VCMDBS_80 = 3, + VCMDBS_160 = 4, + VCMDBS_320 = 5, + VCMDBS_1500 = 6, + VCMDBS_COUNT = 7 +} VCMDBufSize; + +typedef struct { + void *next; + uint32 packet; + unsigned int address_size; + unsigned int address_sum; + VCMDBufSize buf_size; + unsigned int size; +} VCMDBufHead; + +typedef struct { + VCMDBufHead head; + uint8 buf[10]; +} VCMDBuffer10; + +typedef struct { + VCMDBufHead head; + uint8 buf[20]; +} VCMDBuffer20; + +typedef struct { + VCMDBufHead head; + uint8 buf[30]; +} VCMDBuffer30; + +typedef struct { + VCMDBufHead head; + uint8 buf[80]; +} VCMDBuffer80; + +typedef struct { + VCMDBufHead head; + uint8 buf[160]; +} VCMDBuffer160; + +typedef struct { + VCMDBufHead head; + uint8 buf[320]; +} VCMDBuffer320; + + +typedef struct { + VCMDBufHead head; + uint8 buf[1500]; +} VCMDBuffer1500; + +extern VCMDBufHead *v_cmd_buf_allocate(VCMDBufSize buf_size); +extern void v_cmd_buf_free(VCMDBufHead *head); + +extern void v_cmd_buf_set_size(VCMDBufHead *head, unsigned int size); +extern void v_cmd_buf_set_address_size(VCMDBufHead *head, unsigned int size); +extern void v_cmd_buf_set_unique_address_size(VCMDBufHead *head, unsigned int size); +extern boolean v_cmd_buf_compare(VCMDBufHead *a, VCMDBufHead *b); diff --git a/extern/verse/dist/v_cmd_def_a.c b/extern/verse/dist/v_cmd_def_a.c new file mode 100644 index 00000000000..8557601428b --- /dev/null +++ b/extern/verse/dist/v_cmd_def_a.c @@ -0,0 +1,94 @@ +/* + * Command definitions for audio node commands. +*/ + +#include +#include +#include "verse_header.h" +#include "v_cmd_gen.h" +#include "v_cmd_buf.h" + +#if defined(V_GENERATE_FUNC_MODE) + +void v_gen_audio_cmd_def(void) +{ + v_cg_new_cmd(V_NT_AUDIO, "a_buffer_create", 160, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_BUFFER_ID, "buffer_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NAME, "name"); + v_cg_add_param(VCGP_ENUM_NAME, "VNABlockType"); + v_cg_add_param(VCGP_ENUM, "type"); + v_cg_add_param(VCGP_REAL64, "frequency"); + v_cg_alias(FALSE, "a_buffer_destroy", "if(name[0] == 0)", 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_AUDIO, "a_buffer_subscribe", 161, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_BUFFER_ID, "layer_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_alias(TRUE, "a_buffer_unsubscribe", NULL, 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_AUDIO, "a_block_set", 162, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "buffer_id"); + v_cg_add_param(VCGP_UINT32, "block_index"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_ENUM_NAME, "VNABlockType"); + v_cg_add_param(VCGP_ENUM, "type"); + v_cg_add_param(VCGP_POINTER_TYPE, "VNABlock"); + v_cg_add_param(VCGP_POINTER, "samples"); + + v_cg_add_param(VCGP_PACK_INLINE, "\tbuffer_pos += vnp_pack_audio_block(&buf[buffer_pos], type, samples);\n"); + + v_cg_add_param(VCGP_UNPACK_INLINE, "\tif(type <= VN_A_BLOCK_REAL64)\n\t{\n" + "\t\tVNABlock\tblock;\n" + "\t\tbuffer_pos += vnp_unpack_audio_block(&buf[buffer_pos], type, &block);\n" + "\t\tif(func_a_block_set != NULL)\n" + "\t\t\tfunc_a_block_set(v_fs_get_user_data(162), node_id, buffer_id, block_index, (VNABlockType) type, &block);\n" + "\t\treturn buffer_pos;\n" + "\t}\n"); + v_cg_alias(FALSE, "a_block_clear", "if(type > VN_A_BLOCK_REAL64)", 3, NULL); + v_cg_end_cmd(); + + + v_cg_new_cmd(V_NT_AUDIO, "a_stream_create", 163, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "stream_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NAME, "name"); + v_cg_alias(FALSE, "a_stream_destroy", "if(name[0] == 0)", 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_AUDIO, "a_stream_subscribe", 164, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "stream_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_alias(TRUE, "a_stream_unsubscribe", NULL, 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_AUDIO, "a_stream", 165, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "stream_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT32, "time_s"); + v_cg_add_param(VCGP_UINT32, "time_f"); + v_cg_add_param(VCGP_ENUM_NAME, "VNABlockType"); + v_cg_add_param(VCGP_ENUM, "type"); + v_cg_add_param(VCGP_REAL64, "frequency"); + v_cg_add_param(VCGP_POINTER_TYPE, "VNABlock"); + v_cg_add_param(VCGP_POINTER, "samples"); + + v_cg_add_param(VCGP_PACK_INLINE, "\tbuffer_pos += vnp_pack_audio_block(&buf[buffer_pos], type, samples);\n"); + + v_cg_add_param(VCGP_UNPACK_INLINE, "\t{\n\t\tVNABlock\tblock;\n\tbuffer_pos += vnp_unpack_audio_block(&buf[buffer_pos], type, &block);\n" + "\t\tif(func_a_stream != NULL)\n" + "\t\t\tfunc_a_stream(v_fs_get_user_data(165), node_id, stream_id, time_s, time_f, (VNABlockType) type, frequency, &block);\n" + "\t\treturn buffer_pos;\n" + "\t}\n"); + + v_cg_end_cmd(); +} + +#endif diff --git a/extern/verse/dist/v_cmd_def_b.c b/extern/verse/dist/v_cmd_def_b.c new file mode 100644 index 00000000000..b266b03648c --- /dev/null +++ b/extern/verse/dist/v_cmd_def_b.c @@ -0,0 +1,44 @@ + +#include +#include + +#include "verse_header.h" +#include "v_cmd_gen.h" +#include "v_cmd_buf.h" + +#if defined(V_GENERATE_FUNC_MODE) + +void v_gen_bitmap_cmd_def(void) +{ + v_cg_new_cmd(V_NT_BITMAP, "b_dimensions_set", 80, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT16, "width"); + v_cg_add_param(VCGP_UINT16, "height"); + v_cg_add_param(VCGP_UINT16, "depth"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_BITMAP, "b_layer_create", 81, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NAME, "name"); + v_cg_add_param(VCGP_ENUM_NAME, "VNBLayerType"); + v_cg_add_param(VCGP_ENUM, "type"); + v_cg_alias(FALSE, "b_layer_destroy", "if(name[0] == 0)", 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_BITMAP, "b_layer_subscribe", 82, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT8, "level"); + v_cg_alias(FALSE, "b_layer_unsubscribe", "if(level == 255)", 2, NULL); + v_cg_end_cmd(); + + v_cg_new_manual_cmd(83, "b_tile_set", "void verse_send_b_tile_set(VNodeID node_id, VLayerID layer_id, " + "uint16 tile_x, uint16 tile_y, uint16 z, VNBLayerType type, const VNBTile *tile)", + NULL, NULL); +} + +#endif diff --git a/extern/verse/dist/v_cmd_def_c.c b/extern/verse/dist/v_cmd_def_c.c new file mode 100644 index 00000000000..317b45e1a27 --- /dev/null +++ b/extern/verse/dist/v_cmd_def_c.c @@ -0,0 +1,35 @@ + +#include +#include +#include "verse_header.h" +#include "v_cmd_gen.h" +#include "v_cmd_buf.h" + +#if defined(V_GENERATE_FUNC_MODE) + +void v_gen_curve_cmd_def(void) +{ + v_cg_new_cmd(V_NT_CURVE, "c_curve_create", 128, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "curve_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NAME, "name"); + v_cg_add_param(VCGP_UINT8, "dimensions"); + v_cg_alias(FALSE, "c_curve_destroy", "if(name[0] == 0)", 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_CURVE, "c_curve_subscribe", 129, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "curve_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_alias(TRUE, "c_curve_unsubscribe", "if(!alias_bool)", 2, NULL); + v_cg_end_cmd(); + + v_cg_new_manual_cmd(130, "c_key_set", "void verse_send_c_key_set(VNodeID node_id, VLayerID curve_id, " + "uint32 key_id, uint8 dimensions, const real64 *pre_value, const uint32 *pre_pos, " + "const real64 *value, real64 pos, const real64 *post_value, const uint32 *post_pos)", + "c_key_destroy", "void verse_send_c_key_destroy(VNodeID node_id, VLayerID curve_id, " + "uint32 key_id)"); +} + +#endif diff --git a/extern/verse/dist/v_cmd_def_g.c b/extern/verse/dist/v_cmd_def_g.c new file mode 100644 index 00000000000..5a4ea7202b4 --- /dev/null +++ b/extern/verse/dist/v_cmd_def_g.c @@ -0,0 +1,183 @@ + +#include +#include +#include "verse_header.h" +#include "v_cmd_gen.h" +#include "v_cmd_buf.h" + +#if defined(V_GENERATE_FUNC_MODE) + +void v_gen_geometry_cmd_def(void) +{ + unsigned int order[] = { 0, 2 }; + + v_cg_new_cmd(V_NT_GEOMETRY, "g_layer_create", 48, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NAME, "name"); + v_cg_add_param(VCGP_ENUM_NAME, "VNGLayerType"); + v_cg_add_param(VCGP_ENUM, "type"); + v_cg_add_param(VCGP_UINT32, "def_uint"); + v_cg_add_param(VCGP_REAL64, "def_real"); + v_cg_alias(FALSE, "g_layer_destroy", "if(name[0] == 0)", 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_layer_subscribe", 49, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_ENUM_NAME, "VNRealFormat"); + v_cg_add_param(VCGP_ENUM, "type"); + v_cg_alias(FALSE, "g_layer_unsubscribe", "if(type > VN_FORMAT_REAL64)", 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_vertex_set_xyz_real32", 50, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_UINT32, "vertex_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_REAL32, "x"); + v_cg_add_param(VCGP_REAL32, "y"); + v_cg_add_param(VCGP_REAL32, "z"); + v_cg_alias(FALSE, "g_vertex_delete_real32", "if(x == V_REAL32_MAX || y == V_REAL32_MAX || z == V_REAL32_MAX)", 2, order); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_vertex_set_xyz_real64", 51, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_UINT32, "vertex_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_REAL64, "x"); + v_cg_add_param(VCGP_REAL64, "y"); + v_cg_add_param(VCGP_REAL64, "z"); + v_cg_alias(FALSE, "g_vertex_delete_real64", "if(x == V_REAL64_MAX || y == V_REAL64_MAX || z == V_REAL64_MAX)", 2, order); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_vertex_set_uint32", 52, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_UINT32, "vertex_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT32, "value"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_vertex_set_real64", 53, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_UINT32, "vertex_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_REAL64, "value"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_vertex_set_real32", 54, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_UINT32, "vertex_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_REAL32, "value"); + v_cg_end_cmd(); +/* + v_cg_new_cmd(V_NT_GEOMETRY, "g_vertex_delete", VCGCT_NORMAL); + v_cg_add_param(VCGP_UINT32, "vertex_id"); + v_cg_end_cmd(); +*/ + v_cg_new_cmd(V_NT_GEOMETRY, "g_polygon_set_corner_uint32", 55, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_UINT32, "polygon_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT32, "v0"); + v_cg_add_param(VCGP_UINT32, "v1"); + v_cg_add_param(VCGP_UINT32, "v2"); + v_cg_add_param(VCGP_UINT32, "v3"); + v_cg_alias(FALSE, "g_polygon_delete", "if(layer_id == 1 && v0 == ~0u)", 2, order); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_polygon_set_corner_real64", 56, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_UINT32, "polygon_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_REAL64, "v0"); + v_cg_add_param(VCGP_REAL64, "v1"); + v_cg_add_param(VCGP_REAL64, "v2"); + v_cg_add_param(VCGP_REAL64, "v3"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_polygon_set_corner_real32", 57, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_UINT32, "polygon_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_REAL32, "v0"); + v_cg_add_param(VCGP_REAL32, "v1"); + v_cg_add_param(VCGP_REAL32, "v2"); + v_cg_add_param(VCGP_REAL32, "v3"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_polygon_set_face_uint8", 58, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_UINT32, "polygon_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT8, "value"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_polygon_set_face_uint32", 59, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_UINT32, "polygon_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT32, "value"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_polygon_set_face_real64", 60, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_UINT32, "polygon_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_REAL64, "value"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_polygon_set_face_real32", 61, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_UINT32, "polygon_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_REAL32, "value"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_crease_set_vertex", 62, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NAME, "layer"); + v_cg_add_param(VCGP_UINT32, "def_crease"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_crease_set_edge", 63, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NAME, "layer"); + v_cg_add_param(VCGP_UINT32, "def_crease"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_bone_create", 64, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_UINT16, "bone_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NAME, "weight"); + v_cg_add_param(VCGP_NAME, "reference"); + v_cg_add_param(VCGP_UINT16, "parent"); + v_cg_add_param(VCGP_REAL64, "pos_x"); + v_cg_add_param(VCGP_REAL64, "pos_y"); + v_cg_add_param(VCGP_REAL64, "pos_z"); + v_cg_add_param(VCGP_NAME, "position_label"); + v_cg_add_param(VCGP_NAME, "rotation_label"); + v_cg_add_param(VCGP_NAME, "scale_label"); + v_cg_alias(FALSE, "g_bone_destroy", "if(weight[0] == 0)", 2, NULL); + + v_cg_end_cmd(); +} + +#endif diff --git a/extern/verse/dist/v_cmd_def_m.c b/extern/verse/dist/v_cmd_def_m.c new file mode 100644 index 00000000000..3f4b9aa7178 --- /dev/null +++ b/extern/verse/dist/v_cmd_def_m.c @@ -0,0 +1,273 @@ + +#include +#include +#include "verse_header.h" +#include "v_cmd_gen.h" +#include "v_cmd_buf.h" + +#if defined(V_GENERATE_FUNC_MODE) + +void v_gen_material_cmd_def(void) +{ + v_cg_new_cmd(V_NT_MATERIAL, "m_fragment_create", 68, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_FRAGMENT_ID, "frag_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_ENUM_NAME, "VNMFragmentType"); + v_cg_add_param(VCGP_ENUM, "type"); + v_cg_add_param(VCGP_POINTER_TYPE, "VMatFrag"); + v_cg_add_param(VCGP_POINTER, "fragment"); + + v_cg_add_param(VCGP_PACK_INLINE, "\tswitch(type)\n" + "\t{\n" + "\tcase VN_M_FT_COLOR :\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->color.red);\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->color.green);\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->color.blue);\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_LIGHT :\n" + "\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->light.type);\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->light.normal_falloff);\n" + "\t\tbuffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], fragment->light.brdf);\n" + "\t\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->light.brdf_r, 16);\n" + "\t\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->light.brdf_g, 16);\n" + "\t\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->light.brdf_b, 16);\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_REFLECTION :\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->reflection.normal_falloff);\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_TRANSPARENCY :\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->transparency.normal_falloff);\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->transparency.refraction_index);\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_GEOMETRY :\n" + "\t\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->geometry.layer_r, 16);\n" + "\t\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->geometry.layer_g, 16);\n" + "\t\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->geometry.layer_b, 16);\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_VOLUME :\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->volume.diffusion);\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->volume.col_r);\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->volume.col_g);\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->volume.col_b);\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_VIEW :\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_TEXTURE :\n" + "\t\tbuffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], fragment->texture.bitmap);\n" + "\t\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->texture.layer_r, 16);\n" + "\t\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->texture.layer_g, 16);\n" + "\t\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->texture.layer_b, 16);\n" + "\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->texture.filtered);\n" + "\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->texture.mapping);\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_NOISE :\n" + "\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->noise.type);\n" + "\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->noise.mapping);\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_BLENDER :\n" + "\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->blender.type);\n" + "\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->blender.data_a);\n" + "\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->blender.data_b);\n" + "\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->blender.control);\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_CLAMP :\n" + "\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->clamp.min);\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->clamp.red);\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->clamp.green);\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->clamp.blue);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->clamp.data);\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_MATRIX :\n" + "\t\t{\n" + "\t\t\tunsigned int i;\n" + "\t\t\tfor(i = 0; i < 16; i++)\n" + "\t\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->matrix.matrix[i]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->matrix.data);\n" + "\t\t}\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_RAMP :\n" + "\t\tif(fragment->ramp.point_count == 0)\n" + "\t\t\treturn;\n" + "\t\t{\n" + "\t\t\tunsigned int i, pos;\n" + "\t\t\tdouble last;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->ramp.type);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->ramp.channel);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->ramp.mapping);\n" + "\t\t\tpos = buffer_pos;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], fragment->ramp.point_count);\n" + "\t\t\tlast = fragment->ramp.ramp[0].pos - 1;\n" + "\t\t\tfor(i = 0; i < fragment->ramp.point_count && fragment->ramp.ramp[i].pos > last && i < 48; i++)\n" + "\t\t\t{\n" + "\t\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->ramp.ramp[i].pos);\n" + "\t\t\t\tlast = fragment->ramp.ramp[i].pos;\n" + "\t\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->ramp.ramp[i].red);\n" + "\t\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->ramp.ramp[i].green);\n" + "\t\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->ramp.ramp[i].blue);\n" + "\t\t\t}\n\t\t\tif(i != fragment->ramp.point_count)\n" + "\t\t\t\tvnp_raw_pack_uint8(&buf[pos], i);\n" + "\t\t}\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_ANIMATION :\n" + "\t\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->animation.label, 16);\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_ALTERNATIVE :\n" + "\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->alternative.alt_a);\n" + "\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->alternative.alt_b);\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_OUTPUT :\n" + "\t\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->output.label, 16);\n" + "\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->output.front);\n" + "\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->output.back);\n" + "\t\tbreak;\n" + "\t}\n"); + + v_cg_add_param(VCGP_UNPACK_INLINE, "\tif(type <= VN_M_FT_OUTPUT)\n" + "\t{\n" + "\t\tVMatFrag frag;\n" + "\t\tuint8 temp;\n" + "\t\tswitch(type)\n" + "\t\t{\n" + "\t\tcase VN_M_FT_COLOR :\n" + "\t\t\tif(buffer_pos + 3 * 8 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.color.red);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.color.green);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.color.blue);\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_LIGHT :\n" + "\t\t\tif(buffer_pos + 13 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp);\n" + "\t\t\tfrag.light.type = (VNMLightType)temp;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.light.normal_falloff);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &frag.light.brdf);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.light.brdf_r, 16, buffer_length - buffer_pos);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.light.brdf_g, 16, buffer_length - buffer_pos);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.light.brdf_b, 16, buffer_length - buffer_pos);\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_REFLECTION :\n" + "\t\t\tif(buffer_pos + 8 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.reflection.normal_falloff);\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_TRANSPARENCY :\n" + "\t\t\tif(buffer_pos + 16 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.transparency.normal_falloff);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.transparency.refraction_index);\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_VOLUME :\n" + "\t\t\tif(buffer_pos + 32 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.volume.diffusion);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.volume.col_r);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.volume.col_g);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.volume.col_b);\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_VIEW :\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_GEOMETRY :\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.geometry.layer_r, 16, buffer_length - buffer_pos);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.geometry.layer_g, 16, buffer_length - buffer_pos);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.geometry.layer_b, 16, buffer_length - buffer_pos);\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_TEXTURE :\n" + "\t\t\tif(buffer_pos + 10 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &frag.texture.bitmap);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.texture.layer_r, 16, buffer_length - buffer_pos);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.texture.layer_g, 16, buffer_length - buffer_pos);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.texture.layer_b, 16, buffer_length - buffer_pos);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp);\n" + "\t\t\tfrag.texture.filtered = (VNMNoiseType)temp;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.texture.mapping);\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_NOISE :\n" + "\t\t\tif(buffer_pos + 3 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp);\n" + "\t\t\tfrag.noise.type = (VNMNoiseType)temp;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.noise.mapping);\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_BLENDER :\n" + "\t\t\tif(buffer_pos + 7 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp);\n" + "\t\t\tfrag.blender.type = (VNMBlendType)temp;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.blender.data_a);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.blender.data_b);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.blender.control);\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_CLAMP :\n" + "\t\t\tif(buffer_pos + 27 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp);\n" + "\t\t\tfrag.clamp.min = (VNMBlendType)temp;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.clamp.red);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.clamp.green);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.clamp.blue);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.clamp.data);\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_MATRIX :\n" + "\t\t\tif(buffer_pos + 8 * 16 + 2 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\telse\n" + "\t\t\t{\n" + "\t\t\t\tunsigned int i;\n" + "\t\t\t\tfor(i = 0; i < 16; i++)\n" + "\t\t\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.matrix.matrix[i]);\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.matrix.data);\n" + "\t\t\t}\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_RAMP :\n" + "\t\t\tif(buffer_pos + 5 + 4 * 8 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\telse\n" + "\t\t\t{\n" + "\t\t\t\tunsigned int i, pos;\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp);\n" + "\t\t\t\tfrag.ramp.type = (VNMRampType)temp;\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp);\n" + "\t\t\t\tfrag.ramp.channel = (VNMRampChannel)temp;\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.ramp.mapping);\n" + "\t\t\t\tpos = buffer_pos;\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &frag.ramp.point_count);\n" + "\t\t\t\tfor(i = 0; i < frag.ramp.point_count && buffer_pos + 8 * 4 <= buffer_length && i < 48; i++)\n" + "\t\t\t\t{\n" + "\t\t\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.ramp.ramp[i].pos);\n" + "\t\t\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.ramp.ramp[i].red);\n" + "\t\t\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.ramp.ramp[i].green);\n" + "\t\t\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.ramp.ramp[i].blue);\n" + "\t\t\t\t}if(i != frag.ramp.point_count)\n" + "\t\t\t\t\tfrag.ramp.point_count = i;\n" + "\t\t\t}\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_ANIMATION :\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.animation.label, 16, buffer_length - buffer_pos);\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_ALTERNATIVE :\n" + "\t\t\tif(buffer_pos + 4 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.alternative.alt_a);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.alternative.alt_b);\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_OUTPUT :\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.output.label, 16, buffer_length - buffer_pos);\n" + "\t\t\tif(buffer_pos + 4 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.output.front);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.output.back);\n" + "\t\t\tbreak;\n" + "\t\t}\n" + "\t\tif(func_m_fragment_create != NULL)\n" + "\t\t\tfunc_m_fragment_create(v_fs_get_user_data(68), node_id, frag_id, type, &frag);\n" + "\t\treturn buffer_pos;\n" + "\t}\n"); + v_cg_alias(FALSE, "m_fragment_destroy", "if(type > VN_M_FT_OUTPUT)", 2, NULL); + + v_cg_end_cmd(); +} + +#endif diff --git a/extern/verse/dist/v_cmd_def_o.c b/extern/verse/dist/v_cmd_def_o.c new file mode 100644 index 00000000000..a0135f2a4a7 --- /dev/null +++ b/extern/verse/dist/v_cmd_def_o.c @@ -0,0 +1,517 @@ + +#include +#include +#include "verse_header.h" +#include "v_cmd_gen.h" +#include "v_cmd_buf.h" + +#if defined(V_GENERATE_FUNC_MODE) + +void v_gen_object_cmd_def(void) +{ + v_cg_new_cmd(V_NT_OBJECT, "o_transform_pos_real32", 32, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT32, "time_s"); + v_cg_add_param(VCGP_UINT32, "time_f"); + v_cg_add_param(VCGP_POINTER_TYPE,"real32"); + v_cg_add_param(VCGP_POINTER, "pos"); + v_cg_add_param(VCGP_POINTER_TYPE,"real32"); + v_cg_add_param(VCGP_POINTER, "speed"); + v_cg_add_param(VCGP_POINTER_TYPE,"real32"); + v_cg_add_param(VCGP_POINTER, "accelerate"); + v_cg_add_param(VCGP_POINTER_TYPE,"real32"); + v_cg_add_param(VCGP_POINTER, "drag_normal"); + v_cg_add_param(VCGP_PACK_INLINE, "\t{\n" + "\t\tunsigned char mask = 0;\n" + "\t\tunsigned int cmd;\n" + "\t\tcmd = buffer_pos++;\n" + "\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], pos[0]);\n" + "\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], pos[1]);\n" + "\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], pos[2]);\n" + "\t\tif(speed != NULL && (speed[0] > 0.0000001 || speed[0] < -0.0000001 || speed[1] > 0.0000001 || speed[1] < -0.0000001 || speed[2] > 0.0000001 || speed[2] < -0.0000001))\n" + "\t\t{\n" + "\t\t\tmask |= 1;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], speed[0]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], speed[1]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], speed[2]);\n" + "\t\t}\n" + "\t\tif(accelerate != NULL && (accelerate[0] > 0.0000001 || accelerate[0] < -0.0000001 || accelerate[1] > 0.0000001 || accelerate[1] < -0.0000001 || accelerate[2] > 0.0000001 || accelerate[2] < -0.0000001))\n" + "\t\t{\n" + "\t\t\tmask |= 2;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], accelerate[0]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], accelerate[1]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], accelerate[2]);\n" + "\t\t}\n" + "\t\tif(drag_normal != NULL && (drag > 0.0000001 || drag < -0.0000001) && (drag_normal[0] > 0.0000001 || drag_normal[0] < -0.0000001 || drag_normal[1] > 0.0000001 || drag_normal[1] < -0.0000001 || drag_normal[2] > 0.0000001 || drag_normal[2] < -0.0000001))\n" + "\t\t{\n" + "\t\t\tmask |= 4;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], drag_normal[0]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], drag_normal[1]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], drag_normal[2]);\n" + "\t\t}\n" + "\t\tif(drag > 0.0000001 || drag < -0.0000001)\n" + "\t\t{\n" + "\t\t\tmask |= 8;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], drag);\n" + "\t\t}\n" + "\t\tvnp_raw_pack_uint8(&buf[cmd], mask);\n" + "\t}if(FALSE)\n"); + v_cg_add_param(VCGP_UNPACK_INLINE, "\t{\n" + "\t\tfloat output[4][3];\n" + "\t\tunsigned int i, j;\n" + "\t\tchar mask, pow = 1;\n" + "\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &mask);\n" + "\t\tfor(j = 0; j < 3; j++)\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &output[0][j]);\n" + "\t\tfor(i = 1; i < 4; i++)\n" + "\t\t{\n" + "\t\t\tif((mask & pow) != 0)\n" + "\t\t\t\tfor(j = 0; j < 3; j++)\n" + "\t\t\t\t\tbuffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &output[i][j]);\n" + "\t\t\telse\n" + "\t\t\t\tfor(j = 0; j < 3; j++)\n" + "\t\t\t\t\toutput[i][j] = 0;\n" + "\t\t\tpow *= 2;\n" + "\t\t}\n" + "\t\tif((mask & pow) != 0)\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &drag);\n" + "\t\telse\n" + "\t\t\tdrag = 0.0f;\n" + "\t\tif(func_o_transform_pos_real32 != NULL)\n" + "\t\t\tfunc_o_transform_pos_real32(v_fs_get_user_data(32), node_id, time_s, time_f, &output[0][0], &output[1][0], &output[2][0], &output[3][0], drag);\n" + "\t\treturn buffer_pos;\n" + "\t}\n"); + v_cg_add_param(VCGP_REAL32, "drag"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_transform_rot_real32", 33, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT32, "time_s"); + v_cg_add_param(VCGP_UINT32, "time_f"); + v_cg_add_param(VCGP_POINTER_TYPE, "VNQuat32"); + v_cg_add_param(VCGP_POINTER, "rot"); + v_cg_add_param(VCGP_POINTER_TYPE, "VNQuat32"); + v_cg_add_param(VCGP_POINTER, "speed"); + v_cg_add_param(VCGP_POINTER_TYPE, "VNQuat32"); + v_cg_add_param(VCGP_POINTER, "accelerate"); + v_cg_add_param(VCGP_POINTER_TYPE, "VNQuat32"); + v_cg_add_param(VCGP_POINTER, "drag_normal"); + v_cg_add_param(VCGP_PACK_INLINE, "\t{\n" + "\t\tuint8 mask = 0;\n" + "\t\tunsigned int maskpos;\n" + "\t\tmaskpos = buffer_pos++;\t\t/* Remember location, and reserve a byte for the mask. */\n" + "\t\tbuffer_pos += vnp_pack_quat32(&buf[buffer_pos], rot);\n" + "\t\tif(v_quat32_valid(speed))\n" + "\t\t{\n" + "\t\t\tmask |= 1;\n" + "\t\t\tbuffer_pos += vnp_pack_quat32(&buf[buffer_pos], speed);\n" + "\t\t}\n" + "\t\tif(v_quat32_valid(accelerate))\n" + "\t\t{\n" + "\t\t\tmask |= 2;\n" + "\t\t\tbuffer_pos += vnp_pack_quat32(&buf[buffer_pos], accelerate);\n" + "\t\t}\n" + "\t\tif(v_quat32_valid(drag_normal))\n" + "\t\t{\n" + "\t\t\tmask |= 4;\n" + "\t\t\tbuffer_pos += vnp_pack_quat32(&buf[buffer_pos], drag_normal);\n" + "\t\t}\n" + "\t\tif(drag > 0.0000001 || drag < -0.0000001)\n" + "\t\t{\n" + "\t\t\tmask |= 8;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], drag);\n" + "\t\t}\n" + "\t\tvnp_raw_pack_uint8(&buf[maskpos], mask);\t/* Write the mask into start of command. */\n" + "\t}\n" + "\tif(FALSE)\n"); + v_cg_add_param(VCGP_UNPACK_INLINE, "\t{\n" + "\t\tVNQuat32 trot, temp[3], *q[3];\n" + "\t\tunsigned int i;\n" + "\t\tuint8 mask, test;\n" + "\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &mask);\n" + "\t\tbuffer_pos += vnp_unpack_quat32(&buf[buffer_pos], &trot);\n" + "\t\tfor(i = 0, test = 1; i < sizeof temp / sizeof *temp; i++, test <<= 1)\n" + "\t\t{\n" + "\t\t\tif(mask & test)\t\t/* Field present? */\n" + "\t\t\t{\n" + "\t\t\t\tbuffer_pos += vnp_unpack_quat32(&buf[buffer_pos], &temp[i]);\n" + "\t\t\t\tq[i] = &temp[i];\n" + "\t\t\t}\n" + "\t\t\telse\n" + "\t\t\t\tq[i] = NULL;\n" + "\t\t}\n" + "\t\tif(mask & test)\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &drag);\n" + "\t\telse\n" + "\t\t\tdrag = 0.0;\n" + "\t\tif(func_o_transform_rot_real32 != NULL)\n" + "\t\t\tfunc_o_transform_rot_real32(v_fs_get_user_data(33), node_id, time_s, time_f, &trot, q[0], q[1], q[2], drag);\n" + "\t\treturn buffer_pos;\n" + "\t}\n"); + v_cg_add_param(VCGP_REAL32, "drag"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_transform_scale_real32", 34, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_REAL32, "scale_x"); + v_cg_add_param(VCGP_REAL32, "scale_y"); + v_cg_add_param(VCGP_REAL32, "scale_z"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_transform_pos_real64", 35, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT32, "time_s"); + v_cg_add_param(VCGP_UINT32, "time_f"); + v_cg_add_param(VCGP_POINTER_TYPE,"real64"); + v_cg_add_param(VCGP_POINTER, "pos"); + v_cg_add_param(VCGP_POINTER_TYPE,"real64"); + v_cg_add_param(VCGP_POINTER, "speed"); + v_cg_add_param(VCGP_POINTER_TYPE,"real64"); + v_cg_add_param(VCGP_POINTER, "accelerate"); + v_cg_add_param(VCGP_POINTER_TYPE,"real64"); + v_cg_add_param(VCGP_POINTER, "drag_normal"); + v_cg_add_param(VCGP_PACK_INLINE, "\t{\n" + "\t\tunsigned char mask = 0;\n" + "\t\tunsigned int cmd;\n" + "\t\tcmd = buffer_pos++;\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pos[0]);\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pos[1]);\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pos[2]);\n" + "\t\tif(speed != NULL && (speed[0] > 0.0000001 || speed[0] < -0.0000001 || speed[1] > 0.0000001 || speed[1] < -0.0000001 || speed[2] > 0.0000001 || speed[2] < -0.0000001))\n" + "\t\t{\n" + "\t\t\tmask |= 1;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], speed[0]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], speed[1]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], speed[2]);\n" + "\t\t}\n" + "\t\tif(accelerate != NULL && (accelerate[0] > 0.0000001 || accelerate[0] < -0.0000001 || accelerate[1] > 0.0000001 || accelerate[1] < -0.0000001 || accelerate[2] > 0.0000001 || accelerate[2] < -0.0000001))\n" + "\t\t{\n" + "\t\t\tmask |= 2;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], accelerate[0]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], accelerate[1]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], accelerate[2]);\n" + "\t\t}\n" + "\t\tif(drag_normal != NULL && (drag > 0.0000001 || drag < -0.0000001) && (drag_normal[0] > 0.0000001 || drag_normal[0] < -0.0000001 || drag_normal[1] > 0.0000001 || drag_normal[1] < -0.0000001 || drag_normal[2] > 0.0000001 || drag_normal[2] < -0.0000001))\n" + "\t\t{\n" + "\t\t\tmask |= 4;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], drag_normal[0]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], drag_normal[1]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], drag_normal[2]);\n" + "\t\t}\n" + "\t\tif(drag > 0.0000001 || drag < -0.0000001)\n" + "\t\t{\n" + "\t\t\tmask |= 8;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], drag);\n" + "\t\t}\n" + "\t\tvnp_raw_pack_uint8(&buf[cmd], mask);\n" + "\t}if(FALSE)\n"); + v_cg_add_param(VCGP_UNPACK_INLINE, "\t{\n" + "\t\tdouble output[4][3];\n" + "\t\tunsigned int i, j;\n" + "\t\tchar mask, pow = 1;\n" + "\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &mask);\n" + "\t\tfor(j = 0; j < 3; j++)\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &output[0][j]);\n" + "\t\tfor(i = 1; i < 4; i++)\n" + "\t\t{\n" + "\t\t\tif((mask & pow) != 0)\n" + "\t\t\t\tfor(j = 0; j < 3; j++)\n" + "\t\t\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &output[i][j]);\n" + "\t\t\telse\n" + "\t\t\t\tfor(j = 0; j < 3; j++)\n" + "\t\t\t\t\toutput[i][j] = 0;\n" + "\t\t\tpow *= 2;\n" + "\t\t}\n" + "\t\tif((mask & pow) != 0)\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &drag);\n" + "\t\telse\n" + "\t\t\tdrag = 0.0;\n" + "\t\tif(func_o_transform_pos_real64 != NULL)\n" + "\t\t\tfunc_o_transform_pos_real64(v_fs_get_user_data(35), node_id, time_s, time_f, &output[0][0], &output[1][0], &output[2][0], &output[3][0], drag);\n" + "\t\treturn buffer_pos;\n" + "\t}\n"); + v_cg_add_param(VCGP_REAL64, "drag"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_transform_rot_real64", 36, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT32, "time_s"); + v_cg_add_param(VCGP_UINT32, "time_f"); + v_cg_add_param(VCGP_POINTER_TYPE,"VNQuat64"); + v_cg_add_param(VCGP_POINTER, "rot"); + v_cg_add_param(VCGP_POINTER_TYPE,"VNQuat64"); + v_cg_add_param(VCGP_POINTER, "speed"); + v_cg_add_param(VCGP_POINTER_TYPE,"VNQuat64"); + v_cg_add_param(VCGP_POINTER, "accelerate"); + v_cg_add_param(VCGP_POINTER_TYPE,"VNQuat64"); + v_cg_add_param(VCGP_POINTER, "drag_normal"); + v_cg_add_param(VCGP_PACK_INLINE, "\t{\n" + "\t\tuint8 mask = 0;\n" + "\t\tunsigned int maskpos;\n" + "\t\tmaskpos = buffer_pos++;\t\t/* Remember location, and reserve a byte for the mask. */\n" + "\t\tbuffer_pos += vnp_pack_quat64(&buf[buffer_pos], rot);\n" + "\t\tif(v_quat64_valid(speed))\n" + "\t\t{\n" + "\t\t\tmask |= 1;\n" + "\t\t\tbuffer_pos += vnp_pack_quat64(&buf[buffer_pos], speed);\n" + "\t\t}\n" + "\t\tif(v_quat64_valid(accelerate))\n" + "\t\t{\n" + "\t\t\tmask |= 2;\n" + "\t\t\tbuffer_pos += vnp_pack_quat64(&buf[buffer_pos], accelerate);\n" + "\t\t}\n" + "\t\tif(v_quat64_valid(drag_normal))\n" + "\t\t{\n" + "\t\t\tmask |= 4;\n" + "\t\t\tbuffer_pos += vnp_pack_quat64(&buf[buffer_pos], drag_normal);\n" + "\t\t}\n" + "\t\tif(drag > 0.0000001 || drag < -0.0000001)\n" + "\t\t{\n" + "\t\t\tmask |= 8;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], drag);\n" + "\t\t}\n" + "\t\tvnp_raw_pack_uint8(&buf[maskpos], mask);\t/* Write the mask into start of command. */\n" + "\t}\n" + "\tif(FALSE)\n"); + v_cg_add_param(VCGP_UNPACK_INLINE, "\t{\n" + "\t\tVNQuat64 trot, temp[3], *q[3];\n" + "\t\tunsigned int i;\n" + "\t\tuint8 mask, test;\n" + "\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &mask);\n" + "\t\tbuffer_pos += vnp_unpack_quat64(&buf[buffer_pos], &trot);\n" + "\t\tfor(i = 0, test = 1; i < sizeof temp / sizeof *temp; i++, test <<= 1)\n" + "\t\t{\n" + "\t\t\tif(mask & test)\t\t/* Field present? */\n" + "\t\t\t{\n" + "\t\t\t\tbuffer_pos += vnp_unpack_quat64(&buf[buffer_pos], &temp[i]);\n" + "\t\t\t\tq[i] = &temp[i];\n" + "\t\t\t}\n" + "\t\t\telse\n" + "\t\t\t\tq[i] = NULL;\n" + "\t\t}\n" + "\t\tif(mask & test)\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &drag);\n" + "\t\telse\n" + "\t\t\tdrag = 0.0;\n" + "\t\tif(func_o_transform_rot_real64 != NULL)\n" + "\t\t\tfunc_o_transform_rot_real64(v_fs_get_user_data(36), node_id, time_s, time_f, &trot, q[0], q[1], q[2], drag);\n" + "\t\treturn buffer_pos;\n" + "\t}\n"); + v_cg_add_param(VCGP_REAL64, "drag"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_transform_scale_real64", 37, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_REAL64, "scale_x"); + v_cg_add_param(VCGP_REAL64, "scale_y"); + v_cg_add_param(VCGP_REAL64, "scale_z"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_transform_subscribe", 38, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_ENUM_NAME, "VNRealFormat"); + v_cg_add_param(VCGP_ENUM, "type"); + v_cg_alias(TRUE, "o_transform_unsubscribe", NULL, 4, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_light_set", 39, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_REAL64, "light_r"); + v_cg_add_param(VCGP_REAL64, "light_g"); + v_cg_add_param(VCGP_REAL64, "light_b"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_link_set", 40, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_UINT16, "link_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NODE_ID, "link"); + v_cg_add_param(VCGP_NAME, "label"); + v_cg_add_param(VCGP_UINT32, "target_id"); + v_cg_alias(TRUE, "o_link_destroy", NULL, 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_method_group_create", 41, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_UINT16, "group_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NAME, "name"); + v_cg_alias(FALSE, "o_method_group_destroy", "if(name[0] == 0)", 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_method_group_subscribe", 42, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_UINT16, "group_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_alias(TRUE, "o_method_group_unsubscribe", NULL, 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_method_create", 43, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_UINT16, "group_id"); + v_cg_add_param(VCGP_UINT16, "method_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_LONG_NAME, "name"); + v_cg_add_param(VCGP_UINT8, "param_count"); + v_cg_add_param(VCGP_POINTER_TYPE,"VNOParamType"); + v_cg_add_param(VCGP_POINTER, "param_types"); + v_cg_add_param(VCGP_POINTER_TYPE,"char *"); + v_cg_add_param(VCGP_POINTER, "param_names"); + v_cg_add_param(VCGP_PACK_INLINE, "\t{\n" + "\t\tunsigned int i, j, sum = 1;\n" + "\t\tfor(i = 0; i < param_count; i++)\n" + "\t\t{\n" + "\t\t\tsum += 3;\n" + "\t\t\tfor(j = 0; param_names[i][j] != 0; j++);\n" + "\t\t}\n" + "\t\tif(sum + buffer_pos > 1500)\n" + "\t\t\treturn;\n" + "\t\tfor(i = 0; i < param_count; i++)\n" + "\t\t{\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], param_types[i]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], param_names[i], 1500 - buffer_pos);\n" + "\t\t}\n" + "\t}\n"); + v_cg_add_param(VCGP_UNPACK_INLINE, "\tif(param_count != 255)\n" + "\t{\n" + "\t\tunsigned int i, size, text = 0;\n" + "\t\tVNOParamType types[256];\n" + "\t\tuint8 t;\n" + "\t\tchar name_buf[1500], *names[256];\n" + "\t\tfor(i = 0; i < param_count; i++)\n" + "\t\t{\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &t);\n" + "\t\t\ttypes[i] = t;\n" + "\t\t\tnames[i] = &name_buf[text];\n" + "\t\t\tsize = vnp_raw_unpack_string(&buf[buffer_pos], names[i], 1500 - buffer_pos, buffer_length - buffer_pos);\n" + "\t\t\tbuffer_pos += size;\n" + "\t\t\ttext += size;\n" + "\t\t}\n" + "\t\tif(func_o_method_create != NULL)\n" + "\t\t\tfunc_o_method_create(v_fs_get_user_data(43), node_id, group_id, method_id, name, param_count, types, (const char **) names);\n" + "\t\treturn buffer_pos;\n" + "\t}\n"); + v_cg_alias(FALSE, "o_method_destroy", "if(name[0] == 0)", 3, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_method_call", 44, VCGCT_UNIQUE); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_UINT16, "group_id"); + v_cg_add_param(VCGP_UINT16, "method_id"); + v_cg_add_param(VCGP_NODE_ID, "sender"); + v_cg_add_param(VCGP_POINTER_TYPE, "VNOPackedParams"); + v_cg_add_param(VCGP_POINTER, "params"); + v_cg_add_param(VCGP_PACK_INLINE, "\t{\n" + "\t\tunsigned int i;\n" + "\t\tuint16 size;\n" + "\t\tvnp_raw_unpack_uint16(params, &size);\n" + "\t\tfor(i = 0; i < size; i++)\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], ((uint8 *)params)[i]);\n" + "\t\tfree((void *) params);\t/* Drop the const. */\n" + "\t}\n"); + v_cg_add_param(VCGP_UNPACK_INLINE, "\t{\n" + "\t\tunsigned int i;\n" + "\t\tuint8 par[1500];\n" + "\t\tuint16 size;\n" + "\t\tvnp_raw_unpack_uint16(&buf[buffer_pos], &size);\n" + "\t\tfor(i = 0; i < size; i++)\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &par[i]);\n" + "\t\tif(func_o_method_call != NULL)\n" + "\t\t\tfunc_o_method_call(v_fs_get_user_data(44), node_id, group_id, method_id, sender, par);\n" + "\t\treturn buffer_pos;\n" + "\t}\n"); + + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_anim_run", 45, VCGCT_UNIQUE); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_UINT16, "link_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT32, "time_s"); + v_cg_add_param(VCGP_UINT32, "time_f"); + v_cg_add_param(VCGP_UINT8, "dimensions"); + v_cg_add_param(VCGP_POINTER_TYPE, "real64"); + v_cg_add_param(VCGP_POINTER, "pos"); + v_cg_add_param(VCGP_POINTER_TYPE, "real64"); + v_cg_add_param(VCGP_POINTER, "speed"); + v_cg_add_param(VCGP_POINTER_TYPE, "real64"); + v_cg_add_param(VCGP_POINTER, "accel"); + v_cg_add_param(VCGP_POINTER_TYPE, "real64"); + v_cg_add_param(VCGP_POINTER, "scale"); + v_cg_add_param(VCGP_POINTER_TYPE, "real64"); + v_cg_add_param(VCGP_POINTER, "scale_speed"); + v_cg_add_param(VCGP_PACK_INLINE, "\t{\n" + "\t\tunsigned char mask = 0;\n" + "\t\tunsigned int cmd, i;\n" + "\t\tcmd = buffer_pos++;\n" + "\t\tif(dimensions > 4)\n" + "\t\t\tdimensions = 4;\n" + "\t\tfor(i = 0; i < dimensions; i++)\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pos[i]);\n" + "\t\tif(speed != NULL)\n" + "\t\t{\n" + "\t\t\tmask |= 1;\n" + "\t\t\tfor(i = 0; i < dimensions; i++)\n" + "\t\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], speed[i]);\n" + "\t\t}\n" + "\t\tif(accel != NULL)\n" + "\t\t{\n" + "\t\t\tmask |= 2;\n" + "\t\t\tfor(i = 0; i < dimensions; i++)\n" + "\t\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], accel[i]);\n" + "\t\t}\n" + "\t\tif(scale != NULL)\n" + "\t\t{\n" + "\t\t\tmask |= 3;\n" + "\t\t\tfor(i = 0; i < dimensions; i++)\n" + "\t\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], scale[i]);\n" + "\t\t}\n" + "\t\tif(scale_speed != NULL)\n" + "\t\t{\n" + "\t\t\tmask |= 4;\n" + "\t\t\tfor(i = 0; i < dimensions; i++)\n" + "\t\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], scale_speed[i]);\n" + "\t\t}\n" + "\t\tvnp_raw_pack_uint8(&buf[cmd], mask);\n" + "\t}\n"); + v_cg_add_param(VCGP_UNPACK_INLINE, "\t{\n" + "\t\tdouble output[5][4];\n" + "\t\tunsigned int i, j;\n" + "\t\tchar mask, pow = 1;\n" + "\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &mask);\n" + "\t\tif(dimensions > 4)\n" + "\t\t\tdimensions = 4;\n" + "\t\tfor(j = 0; j < dimensions; j++)\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &output[0][j]);\n" + "\t\tfor(i = 1; i < 5; i++)\n" + "\t\t{\n" + "\t\t\tif((mask & pow) != 0)\n" + "\t\t\t\tfor(j = 0; j < dimensions; j++)\n" + "\t\t\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &output[i][j]);\n" + "\t\t\telse\n" + "\t\t\t\tfor(j = 0; j < dimensions; j++)\n" + "\t\t\t\t\toutput[i][j] = 0;\n" + "\t\t\tpow *= 2;\n" + "\t\t}\n" + "\t\tif(func_o_anim_run != NULL)\n" + "\t\t\tfunc_o_anim_run(v_fs_get_user_data(45), node_id, link_id, time_s, time_f, dimensions, &output[0][0], &output[1][0], &output[2][0], &output[3][0], &output[4][0]);\n" + "\t\treturn buffer_pos;\n" + "\t}\n"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_hide", 46, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT8, "hidden"); + v_cg_end_cmd(); +} + +#endif diff --git a/extern/verse/dist/v_cmd_def_s.c b/extern/verse/dist/v_cmd_def_s.c new file mode 100644 index 00000000000..1b8b69dcd6d --- /dev/null +++ b/extern/verse/dist/v_cmd_def_s.c @@ -0,0 +1,211 @@ + +#include +#include +#include "verse_header.h" +#include "v_cmd_gen.h" +#include "v_cmd_buf.h" + +#if defined(V_GENERATE_FUNC_MODE) + +void v_gen_system_cmd_def(void) +{ + v_cg_new_manual_cmd(0, "connect", "VSession verse_send_connect(const char *name, const char *pass, const char *address, const uint8 *expected_host_id)", NULL, NULL); + + v_cg_new_manual_cmd(1, "connect_accept", "VSession verse_send_connect_accept(VNodeID avatar, const char *address, uint8 *host_id)", NULL, NULL); + + v_cg_new_manual_cmd(2, "connect_terminate", "void verse_send_connect_terminate(const char *address, const char *bye)", NULL, NULL); + + v_cg_new_manual_cmd(5, "ping", "void verse_send_ping(const char *address, const char *message)", NULL, NULL); + + v_cg_new_cmd(V_NT_SYSTEM, "error_message", 6, VCGCT_UNIQUE); + v_cg_add_param(VCGP_LONG_NAME, "message"); + + v_cg_new_cmd(V_NT_SYSTEM, "packet_ack", 7, VCGCT_INVISIBLE_SYSTEM); + v_cg_add_param(VCGP_UINT32, "packet_id"); + v_cg_add_param(VCGP_PACK_INLINE, "\tv_cmd_buf_set_unique_address_size(head, buffer_pos);\n" + "\tv_cmd_buf_set_size(head, buffer_pos);\n" + "\tv_noq_send_ack_nak_buf(v_con_get_network_queue(), head);\n" + "\treturn;\n"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_SYSTEM, "packet_nak", 8, VCGCT_INVISIBLE_SYSTEM); + v_cg_add_param(VCGP_UINT32, "packet_id"); + v_cg_add_param(VCGP_PACK_INLINE, "\tv_cmd_buf_set_unique_address_size(head, buffer_pos);\n" + "\tv_cmd_buf_set_size(head, buffer_pos);\n" + "\tv_noq_send_ack_nak_buf(v_con_get_network_queue(), head);\n" + "\treturn;\n"); + v_cg_end_cmd(); + + + v_cg_new_cmd(V_NT_SYSTEM, "node_index_subscribe", 9, VCGCT_NORMAL); + v_cg_add_param(VCGP_UINT32, "mask"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_SYSTEM, "node_create", 10, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_ENUM_NAME, "VNodeType"); + v_cg_add_param(VCGP_ENUM, "type"); + v_cg_add_param(VCGP_ENUM_NAME, "VNodeOwner"); + v_cg_add_param(VCGP_ENUM, "owner"); + v_cg_alias(FALSE, "node_destroy", "if(owner == (uint8) ~0u || type >= V_NT_NUM_TYPES)", 1, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_SYSTEM, "node_subscribe", 11, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_alias(TRUE, "node_unsubscribe", NULL, 1, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_SYSTEM, "tag_group_create", 16, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_UINT16, "group_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NAME, "name"); + v_cg_alias(FALSE, "tag_group_destroy", "if(name[0] == 0)", 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_SYSTEM, "tag_group_subscribe", 17, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_UINT16, "group_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_alias(TRUE, "tag_group_unsubscribe", NULL, 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_SYSTEM, "tag_create", 18, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_UINT16, "group_id"); + v_cg_add_param(VCGP_UINT16, "tag_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NAME, "name"); + v_cg_add_param(VCGP_ENUM_NAME, "VNTagType"); + v_cg_add_param(VCGP_ENUM, "type"); + v_cg_add_param(VCGP_POINTER_TYPE, "VNTag"); + v_cg_add_param(VCGP_POINTER, "tag"); + v_cg_add_param(VCGP_PACK_INLINE, "\tif(type > VN_TAG_BLOB)\n" + "\t{\n" + "\t\tv_cmd_buf_free(head);\n" + "\t\treturn;\n" + "\t}\n" + "\tswitch(type)\n" + "\t{\n" + "\t\tcase VN_TAG_BOOLEAN :\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], ((VNTag *)tag)->vboolean);\n" + "\t\tbreak;\n" + "\t\tcase VN_TAG_UINT32 :\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], ((VNTag *)tag)->vuint32);\n" + "\t\tbreak;\n" + "\t\tcase VN_TAG_REAL64 :\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], ((VNTag *)tag)->vreal64);\n" + "\t\tbreak;\n" + "\t\tcase VN_TAG_STRING :\n" + "\t\t{\n" + "\t\t\tunsigned int i;\n" + "\t\t\tfor(i = 0; ((VNTag *)tag)->vstring[i] != 0 && i < VN_TAG_MAX_BLOB_SIZE; i++)\n" + "\t\t\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], ((VNTag *)tag)->vstring[i]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 0);\n" + "\t\t}\n" + "\t\tbreak;\n" + "\t\tcase VN_TAG_REAL64_VEC3 :\n" + "\t\t{\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], ((VNTag *)tag)->vreal64_vec3[0]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], ((VNTag *)tag)->vreal64_vec3[1]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], ((VNTag *)tag)->vreal64_vec3[2]);\n" + "\t\t}\n" + "\t\tbreak;\n" + "\t\tcase VN_TAG_LINK :\n" + "\t\t{\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], ((VNTag *)tag)->vlink);\n" + "\t\t}\n" + "\t\tbreak;\n" + "\t\tcase VN_TAG_ANIMATION :\n" + "\t\t{\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], ((VNTag *)tag)->vanimation.curve);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], ((VNTag *)tag)->vanimation.start);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], ((VNTag *)tag)->vanimation.end);\n" + "\t\t}\n" + "\t\tbreak;\n" + "\t\tcase VN_TAG_BLOB :\n" + "\t\t{\n" + "\t\t\tunsigned int i;\n" + "\t\t\tif(((VNTag *)tag)->vblob.size > VN_TAG_MAX_BLOB_SIZE)\n" + "\t\t\t\t((VNTag *)tag)->vblob.size = VN_TAG_MAX_BLOB_SIZE;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], ((VNTag *)tag)->vblob.size);\n" + "\t\t\tfor(i = 0; i < ((VNTag *)tag)->vblob.size; i++)\n" + "\t\t\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], ((uint8 *)((VNTag *)tag)->vblob.blob)[i]);\n" + "\t\t}\n" + "\t\tbreak;\n" + "\t\tdefault :\n" + "\t\t\t;\n" + "\t}\n"); + v_cg_add_param(VCGP_UNPACK_INLINE, "\tif(type < VN_TAG_TYPE_COUNT)\n" + "\t{\n" + "\t\tVNTag tag;\n" + "\t\tunsigned int i;\n" + "\t\tchar string[VN_TAG_MAX_BLOB_SIZE];\n" + "\t\tswitch(type)\n" + "\t\t{\n" + "\t\t\tcase VN_TAG_BOOLEAN :\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &tag.vboolean);\n" + "\t\t\tbreak;\n" + "\t\t\tcase VN_TAG_UINT32 :\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &tag.vuint32);\n" + "\t\t\tbreak;\n" + "\t\t\tcase VN_TAG_REAL64 :\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &tag.vreal64);\n" + "\t\t\tbreak;\n" + "\t\t\tcase VN_TAG_STRING :\n" + "\t\t\t{\n" + "\t\t\t\ttag.vstring = string;\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], string, VN_TAG_MAX_BLOB_SIZE, buffer_length - buffer_pos);\n" + "\t\t\t}\n" + "\t\t\tbreak;\n" + "\t\t\tcase VN_TAG_REAL64_VEC3 :\n" + "\t\t\t{\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &tag.vreal64_vec3[0]);\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &tag.vreal64_vec3[1]);\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &tag.vreal64_vec3[2]);\n" + "\t\t\t}\n" + "\t\t\tbreak;\n" + "\t\t\tcase VN_TAG_LINK :\n" + "\t\t\t{\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &tag.vlink);\n" + "\t\t\t}\n" + "\t\t\tbreak;\n" + "\t\t\tcase VN_TAG_ANIMATION :\n" + "\t\t\t{\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &tag.vanimation.curve);\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &tag.vanimation.start);\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &tag.vanimation.end);\n" + "\t\t\t}\n" + "\t\t\tbreak;\n" + "\t\t\tcase VN_TAG_BLOB :\n" + "\t\t\t{\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &tag.vblob.size);\n" + "\t\t\t\tif(tag.vblob.size > VN_TAG_MAX_BLOB_SIZE)\n" + "\t\t\t\t\ttag.vblob.size = VN_TAG_MAX_BLOB_SIZE;\n" + "\t\t\t\ttag.vblob.blob = string;\n" + "\t\t\t\tfor(i = 0; i < tag.vblob.size; i++)\n" + "\t\t\t\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &string[i]);\n" + "\t\t\t}\n" + "\t\t\tbreak;\n" + "\t\tdefault :\n" + "\t\t\t;\n" + "\t\t}\n" + "\t\tif(func_tag_create != NULL)\n" + "\t\tfunc_tag_create(v_fs_get_user_data(18), node_id, group_id, tag_id, name, type, &tag);\n" + "\t\treturn buffer_pos;\n" + "\t}\n"); + v_cg_alias(FALSE, "tag_destroy", "if(type >= VN_TAG_TYPE_COUNT)", 3, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_SYSTEM, "node_name_set", 19, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_LONG_NAME, "name"); + + v_cg_end_cmd(); +} + +#endif diff --git a/extern/verse/dist/v_cmd_def_t.c b/extern/verse/dist/v_cmd_def_t.c new file mode 100644 index 00000000000..3c568b42d7b --- /dev/null +++ b/extern/verse/dist/v_cmd_def_t.c @@ -0,0 +1,36 @@ + +#include +#include +#include "verse_header.h" +#include "v_cmd_gen.h" +#include "v_cmd_buf.h" + +#if defined(V_GENERATE_FUNC_MODE) + +void v_gen_text_cmd_def(void) +{ + v_cg_new_cmd(V_NT_TEXT, "t_language_set", 96, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_LONG_NAME, "language"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_TEXT, "t_buffer_create", 97, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_BUFFER_ID, "buffer_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NAME, "name"); + v_cg_alias(FALSE, "t_buffer_destroy", "if(name[0] == 0)", 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_TEXT, "t_buffer_subscribe", 98, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_BUFFER_ID, "buffer_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_alias(TRUE, "t_buffer_unsubscribe", NULL, 2, NULL); + v_cg_end_cmd(); + + v_cg_new_manual_cmd(99, "t_text_set", "void verse_send_t_text_set(VNodeID node_id, VBufferID buffer_id, uint32 pos, uint32 length, const char *text)", NULL, NULL); +} + +#endif diff --git a/extern/verse/dist/v_cmd_gen.c b/extern/verse/dist/v_cmd_gen.c new file mode 100644 index 00000000000..3d18f8cf1af --- /dev/null +++ b/extern/verse/dist/v_cmd_gen.c @@ -0,0 +1,939 @@ +/* +** +*/ + +#include +#include +#include + +#include "verse_header.h" +#include "v_cmd_buf.h" + +#include "v_cmd_gen.h" + +#if defined _WIN32 +#include +#define chdir _chdir +#define snprintf _snprintf +#endif + +#if defined V_GENERATE_FUNC_MODE + +#define MAX_PARAMS_PER_CMD 32 + +static struct { + FILE *nodes[V_NT_NUM_TYPES_NETPACK]; + FILE *init; + FILE *unpack; + FILE *verse_h; + FILE *internal_verse_h; + const char *func_name; + VNodeType type; + VCGCommandType command; + unsigned int param_count; + VCGParam param_type[MAX_PARAMS_PER_CMD]; + const char *param_name[MAX_PARAMS_PER_CMD]; + unsigned int cmd_id; + const char *alias_name; + const char *alias_qualifier; + unsigned int alias_param; + unsigned int *alias_param_array; + char alias_bool_switch; +} VCGData; + +extern void v_gen_system_cmd_def(void); +extern void v_gen_object_cmd_def(void); +extern void v_gen_geometry_cmd_def(void); +extern void v_gen_material_cmd_def(void); +extern void v_gen_bitmap_cmd_def(void); +extern void v_gen_text_cmd_def(void); +extern void v_gen_curve_cmd_def(void); +extern void v_gen_audio_cmd_def(void); + +static int v_cg_init(const char *src_path) +{ + char buf[1024]; + int i; + FILE *f; + + VCGData.nodes[V_NT_OBJECT] = fopen("v_gen_pack_o_node.c", "w"); + VCGData.nodes[V_NT_GEOMETRY] = fopen("v_gen_pack_g_node.c", "w"); + VCGData.nodes[V_NT_MATERIAL] = fopen("v_gen_pack_m_node.c", "w"); + VCGData.nodes[V_NT_BITMAP] = fopen("v_gen_pack_b_node.c", "w"); + VCGData.nodes[V_NT_TEXT] = fopen("v_gen_pack_t_node.c", "w"); + VCGData.nodes[V_NT_CURVE] = fopen("v_gen_pack_c_node.c", "w"); + VCGData.nodes[V_NT_AUDIO] = fopen("v_gen_pack_a_node.c", "w"); + VCGData.nodes[V_NT_SYSTEM] = fopen("v_gen_pack_s_node.c", "w"); + VCGData.init = fopen("v_gen_pack_init.c", "w"); + VCGData.unpack = fopen("v_gen_unpack_func.h", "w"); + VCGData.verse_h = fopen("verse.h", "w"); + VCGData.internal_verse_h = fopen("v_internal_verse.h", "w"); + for(i = 0; i < V_NT_NUM_TYPES_NETPACK + 1; i++) + { + if(i == V_NT_NUM_TYPES_NETPACK) + f = VCGData.init; + else + f = VCGData.nodes[i]; + fprintf(f, + "/*\n" + "** This is automatically generated source code -- do not edit.\n" + "** Changes are affected either by editing the corresponding protocol\n" + "** definition file (v_cmd_def_X.c where X=node type), or by editing\n" + "** the code generator itself, in v_cmd_gen.c.\n" + "*/\n\n"); + fprintf(f, "#include \n"); + fprintf(f, "#include \n\n"); + fprintf(f, "#include \"v_cmd_gen.h\"\n"); + fprintf(f, "#if !defined(V_GENERATE_FUNC_MODE)\n"); + fprintf(f, "#include \"verse.h\"\n"); + fprintf(f, "#include \"v_cmd_buf.h\"\n"); + fprintf(f, "#include \"v_network_out_que.h\"\n"); + fprintf(f, "#include \"v_network.h\"\n"); + fprintf(f, "#include \"v_connection.h\"\n"); + fprintf(f, "#include \"v_util.h\"\n\n"); + } + VCGData.cmd_id = 0; + fprintf(f, "#include \"v_gen_unpack_func.h\"\n\n"); + fprintf(f, + "#include \"verse.h\"\n\n\n" + "extern void verse_send_packet_ack(uint32 packet_id);\n" + "extern void verse_send_packet_nak(uint32 packet_id);\n\n"); + + fprintf(VCGData.init, "void init_pack_and_unpack(void)\n{\n"); + fprintf(VCGData.verse_h, + "/*\n" + "** Verse API Header file (for use with libverse.a).\n" + "** This is automatically generated code; do not edit.\n" + "*/\n\n" + "\n" + "#if !defined VERSE_H\n" + "\n" + "#if defined __cplusplus\t\t/* Declare as C symbols for C++ users. */\n" + "extern \"C\" {\n" + "#endif\n\n" + "#define\tVERSE_H\n\n"); + /* Copy contents of "verse_header.h" into output "verse.h". */ + snprintf(buf, sizeof buf, "%sverse_header.h", src_path); + f = fopen(buf, "r"); + if(f != NULL) + { + while((i = fgetc(f)) != EOF) + fputc(i, VCGData.verse_h); + fclose(f); + } + else + { + fprintf(stderr, "mkprot: Couldn't find \"%s\" input file\n", buf); + return 0; + } + fprintf(VCGData.verse_h, "\n/* Command sending functions begin. ----------------------------------------- */\n\n"); + return 1; +} + +static void v_cg_close(void) +{ + unsigned int i; + for(i = 0; i < V_NT_NUM_TYPES_NETPACK; i++) + { + fprintf(VCGData.nodes[i], "#endif\n\n"); + } + fprintf(VCGData.init, "}\n#endif\n\n"); + fprintf(VCGData.verse_h, + "\n#if defined __cplusplus\n" + "}\n" + "#endif\n"); + fprintf(VCGData.verse_h, "\n#endif\t\t/* VERSE_H */\n"); +} + +void v_cg_new_cmd(VCGCommandType type, const char *name, unsigned int cmd_id, VCGCommandType command) +{ + VCGData.param_count = 0; + VCGData.func_name = name; + VCGData.type = type; + VCGData.cmd_id = cmd_id; + VCGData.command = command; +/* printf("def: %u: %s\n", cmd_id, name);*/ +} + +void v_cg_new_manual_cmd(unsigned int cmd_id, const char *name, const char *def, const char *alias_name, const char *alias_def) +{ + fprintf(VCGData.verse_h, "extern %s;\n", def); + if(alias_def != NULL) + fprintf(VCGData.verse_h, "extern %s;\n", alias_def); + fprintf(VCGData.init, "\tv_fs_add_func(%i, v_unpack_%s, (void *) verse_send_%s, ", cmd_id, name, name); + if(alias_name != NULL) + fprintf(VCGData.init, "(void *) verse_send_%s);\n", alias_name); + else + fprintf(VCGData.init, "NULL);\n"); + fprintf(VCGData.unpack, "extern unsigned int v_unpack_%s(const char *data, size_t length);\n", name); +/* printf("def: %u: %s\n", cmd_id, name);*/ +} + +void v_cg_alias(char bool_switch, const char *name, const char *qualifier, unsigned int param, unsigned int *param_array) +{ + VCGData.alias_name = name; + VCGData.alias_qualifier = qualifier; + VCGData.alias_param = param; + VCGData.alias_param_array = param_array; + VCGData.alias_bool_switch = bool_switch; +} + +void v_cg_add_param(VCGParam type, const char *name) +{ + if(VCGData.param_count == MAX_PARAMS_PER_CMD) + exit(1); + VCGData.param_type[VCGData.param_count] = type; + VCGData.param_name[VCGData.param_count] = name; + VCGData.param_count++; +} + +static void v_cg_gen_func_params(FILE *f, boolean types, boolean alias) +{ + unsigned int i; + unsigned int length, active; + length = VCGData.param_count; + if(alias) + length = VCGData.alias_param; + for(i = 0; i < length; i++) + { + if(alias && VCGData.alias_param_array != NULL) + active = VCGData.alias_param_array[i]; + else + { + for(;(VCGData.param_type[i] == VCGP_PACK_INLINE || VCGData.param_type[i] == VCGP_UNPACK_INLINE || VCGData.param_type[i] == VCGP_POINTER_TYPE || VCGData.param_type[i] == VCGP_ENUM_NAME) && i < VCGData.param_count; i++); + if(i == VCGData.param_count) + break; + active = i; + } + + if(active < VCGData.param_count && VCGData.param_type[active] != VCGP_END_ADDRESS) + { + switch(VCGData.param_type[active]) + { + case VCGP_UINT8 : + fprintf(f, "uint8 %s", VCGData.param_name[active]); + break; + case VCGP_UINT16 : + fprintf(f, "uint16 %s", VCGData.param_name[active]); + break; + case VCGP_UINT32 : + fprintf(f, "uint32 %s", VCGData.param_name[active]); + break; + case VCGP_REAL32 : + fprintf(f, "real32 %s", VCGData.param_name[active]); + break; + case VCGP_REAL64 : + fprintf(f, "real64 %s", VCGData.param_name[active]); + break; + case VCGP_POINTER : + if(active != 0 && VCGData.param_type[active - 1] == VCGP_POINTER_TYPE) + fprintf(f, "const %s *%s", VCGData.param_name[active - 1], VCGData.param_name[active]); + else + fprintf(f, "const void *%s", VCGData.param_name[active]); + break; + case VCGP_NAME : + if(types) + fprintf(f, "char %s[16]", VCGData.param_name[active]); + else + fprintf(f, "const char *%s", VCGData.param_name[active]); + break; + case VCGP_LONG_NAME : + if(types) + fprintf(f, "char %s[512]", VCGData.param_name[active]); + else + fprintf(f, "const char *%s", VCGData.param_name[active]); + break; + case VCGP_NODE_ID : + fprintf(f, "VNodeID %s", VCGData.param_name[active]); + break; + case VCGP_LAYER_ID : + fprintf(f, "VLayerID %s", VCGData.param_name[active]); + break; + case VCGP_BUFFER_ID : + fprintf(f, "VBufferID %s", VCGData.param_name[active]); + break; + case VCGP_FRAGMENT_ID : + fprintf(f, "VNMFragmentID %s", VCGData.param_name[active]); + break; + case VCGP_ENUM : +/* if(types) + fprintf(f, "uint8 %s", VCGData.param_name[active]); + else +*/ fprintf(f, "%s %s", VCGData.param_name[active - 1], VCGData.param_name[active]); + break; + } + if(types) + fprintf(f, ";\n\t"); + else + { + for(;(VCGData.param_type[active + 1] == VCGP_END_ADDRESS || VCGData.param_type[active + 1] == VCGP_PACK_INLINE || VCGData.param_type[active + 1] == VCGP_UNPACK_INLINE || VCGData.param_type[active + 1] == VCGP_POINTER_TYPE) && active < VCGData.param_count; active++); + if(active + 1 < length) + fprintf(f, ", "); + } + } + } +} + +static void v_cg_create_print(FILE *f, boolean send, boolean alias) +{ + unsigned int i, length, active; + const char *name; + if(VCGData.command == VCGCT_INVISIBLE_SYSTEM) + return; + name = VCGData.func_name; + if(alias) + name = VCGData.alias_name; + if(send) + fprintf(f, "\tprintf(\"send: verse_send_%s(", name); + else + fprintf(f, "\tprintf(\"receive: verse_send_%s(", name); + + length = VCGData.param_count; + if(alias) + length = VCGData.alias_param; + for(i = 0; i < length; i++) + { + if(alias && VCGData.alias_param_array != NULL) + active = VCGData.alias_param_array[i]; + else + active = i; + + switch(VCGData.param_type[active]) + { + case VCGP_NODE_ID : + fprintf(f, "%s = %%u ", VCGData.param_name[active]); + break; + case VCGP_UINT8 : + case VCGP_UINT16 : + case VCGP_UINT32 : + case VCGP_LAYER_ID : + case VCGP_BUFFER_ID : + case VCGP_ENUM : + case VCGP_FRAGMENT_ID : + fprintf(f, "%s = %%u ", VCGData.param_name[active]); + break; + case VCGP_REAL32 : + case VCGP_REAL64 : + fprintf(f, "%s = %%f ", VCGData.param_name[active]); + break; + case VCGP_POINTER : + if(send) + fprintf(f, "%s = %%p ", VCGData.param_name[active]); + break; + case VCGP_NAME : + case VCGP_LONG_NAME : + fprintf(f, "%s = %%s ", VCGData.param_name[active]); + break; + } + } + if(send) + fprintf(f, ");\\n\""); + else + fprintf(f, "); callback = %%p\\n\""); + + for(i = 0; i < length; i++) + { + if(alias && VCGData.alias_param_array != NULL) + active = VCGData.alias_param_array[i]; + else + active = i; + switch(VCGData.param_type[active]) + { + case VCGP_NODE_ID : + fprintf(f, ", %s", VCGData.param_name[active]); + break; + case VCGP_POINTER : + if(!send) + break; + case VCGP_UINT8 : + case VCGP_UINT16 : + case VCGP_UINT32 : + case VCGP_LAYER_ID : + case VCGP_BUFFER_ID : + case VCGP_ENUM : + case VCGP_FRAGMENT_ID : + case VCGP_REAL32 : + case VCGP_REAL64 : + case VCGP_NAME : + case VCGP_LONG_NAME : + fprintf(f, ", %s", VCGData.param_name[active]); + break; + } + } + if(send) + fprintf(f, ");\n"); + else if(alias) + fprintf(f, ", v_fs_get_alias_user_func(%u));\n", VCGData.cmd_id); + else + fprintf(f, ", v_fs_get_user_func(%u));\n", VCGData.cmd_id); + +} + +static unsigned int v_cg_compute_command_size(unsigned int start, boolean end) +{ + unsigned int size = 0; + for(; start < VCGData.param_count; start++) + { + switch(VCGData.param_type[start]) + { + case VCGP_UINT8 : + case VCGP_ENUM : + size++; + break; + case VCGP_UINT16 : + case VCGP_LAYER_ID : + case VCGP_BUFFER_ID : + case VCGP_FRAGMENT_ID : + size += 2; + break; + case VCGP_NODE_ID : + case VCGP_UINT32 : + case VCGP_REAL32 : + size += 4; + break; + case VCGP_REAL64 : + size += 8; + break; + case VCGP_NAME : + if(end) + return size; + size += 16; + break; + case VCGP_LONG_NAME : + if(end) + return size; + size += 512; + break; + case VCGP_POINTER : + case VCGP_PACK_INLINE : + case VCGP_UNPACK_INLINE : + if(end) + return size; + size += 1500; + break; + case VCGP_END_ADDRESS : + if(end) + return size; + } + } + return size; +} + +void v_cg_set_command_address(FILE *f, boolean alias) +{ + unsigned int i, j, count = 0, length, size = 1, *param, def[] ={0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + + for(i = 0; i < VCGData.param_count; i++) + if(VCGData.param_type[i] == VCGP_END_ADDRESS) + break; + if(i == VCGData.param_count) + return; + if(alias) + length = VCGData.alias_param; + else + length = VCGData.param_count; + + if(alias && VCGData.alias_param_array != 0) + param = VCGData.alias_param_array; + else + param = def; + + if(i == VCGData.param_count) + return; + fprintf(f, "\tif("); + for(i = j = 0; i < VCGData.param_count; i++) + { + switch(VCGData.param_type[i]) + { + case VCGP_UINT8 : + case VCGP_ENUM : + size++; + break; + case VCGP_UINT16 : + case VCGP_LAYER_ID : + case VCGP_BUFFER_ID : + case VCGP_FRAGMENT_ID : + size += 2; + break; + case VCGP_NODE_ID : + case VCGP_UINT32 : + case VCGP_REAL32 : + size += 4; + break; + } + if(j < length && param[j] == i) + { + switch(VCGData.param_type[param[j]]) + { + case VCGP_UINT8 : + case VCGP_ENUM : + break; + case VCGP_UINT16 : + case VCGP_LAYER_ID : + case VCGP_BUFFER_ID : + case VCGP_FRAGMENT_ID : + if(count++ != 0) + fprintf(f, " || "); + fprintf(f, "%s == (uint16) ~0u", VCGData.param_name[param[j]]); + break; + case VCGP_NODE_ID : + case VCGP_UINT32 : + case VCGP_REAL32 : + if(count++ != 0) + fprintf(f, " || "); + fprintf(f, "%s == (uint32) ~0u", VCGData.param_name[param[j]]); + break; + } + j++; + } + if(VCGData.param_type[i] == VCGP_END_ADDRESS) + { + fprintf(f, ")\n"); + fprintf(f, "\t\tv_cmd_buf_set_unique_address_size(head, %u);\n", size); + fprintf(f, "\telse\n"); + fprintf(f, "\t\tv_cmd_buf_set_address_size(head, %u);\n", size); + return; + } + } + fprintf(f, ")\n"); + fprintf(f, "\t\tv_cmd_buf_set_unique_address_size(head, %u);\n", size); + fprintf(f, "\telse\n"); + fprintf(f, "\t\tv_cmd_buf_set_address_size(head, %u);\n", size); + return; +} + +static const char * v_cg_compute_buffer_size(void) +{ + unsigned int size; + size = v_cg_compute_command_size(0, FALSE) + 1; + if(size <= 10) + return "VCMDBS_10"; + else if(size <= 20) + return "VCMDBS_20"; + else if(size <= 30) + return "VCMDBS_30"; + else if(size <= 80) + return "VCMDBS_80"; + else if(size <= 160) + return "VCMDBS_160"; + else if(size <= 320) + return "VCMDBS_320"; + return "VCMDBS_1500"; +} + +static void v_cg_gen_pack(boolean alias) +{ + unsigned int i, j, size = 0, ad_size = 0; + boolean printed = FALSE; + boolean address = FALSE; + boolean no_param; + + FILE *f; + f = VCGData.nodes[VCGData.type]; + printf("generating function: verse_send_%s\n", VCGData.func_name); + if(alias) + fprintf(f, "void verse_send_%s(", VCGData.alias_name); + else + fprintf(f, "void verse_send_%s(", VCGData.func_name); + v_cg_gen_func_params(f, FALSE, alias); + fprintf(f, ")\n{\n\tuint8 *buf;\n"); + fprintf(f, "\tunsigned int buffer_pos = 0;\n"); + fprintf(f, "\tVCMDBufHead *head;\n"); + fprintf(f, "\thead = v_cmd_buf_allocate(%s);/* Allocating the buffer */\n", v_cg_compute_buffer_size()); + fprintf(f, "\tbuf = ((VCMDBuffer10 *)head)->buf;\n\n"); + + fprintf(f, "\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], %u);\t/* Pack the command. */\n", VCGData.cmd_id); + + fprintf(f, "#if defined V_PRINT_SEND_COMMANDS\n"); + v_cg_create_print(f, TRUE, alias); + fprintf(f, "#endif\n"); + + for(i = 0; i < VCGData.param_count; i++) + { + const char *param = VCGData.param_name[i]; + no_param = FALSE; + if(alias) + { + if(i >= VCGData.alias_param && VCGData.alias_param_array == NULL) + no_param = TRUE; + if(VCGData.alias_param_array != NULL) + { + for(j = 0; j < VCGData.alias_param; j++) + if(VCGData.alias_param_array[j] == i) + break; + if(j == VCGData.alias_param) + no_param = TRUE; + } + } + + if(no_param) + param = "-1"; + + switch(VCGData.param_type[i]) + { + case VCGP_UINT8 : + fprintf(f, "\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], %s);\n", param); + break; + case VCGP_UINT16 : + fprintf(f, "\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], %s);\n", param); + break; + case VCGP_UINT32 : + fprintf(f, "\tbuffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], %s);\n", param); + break; + case VCGP_ENUM : + fprintf(f, "\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)%s);\n", param); + break; + } + if(VCGData.param_type[i] == VCGP_REAL32) + { + if(no_param) + param = "V_REAL32_MAX"; + fprintf(f, "\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], %s);\n", param); + } + if(VCGData.param_type[i] == VCGP_REAL64) + { + if(no_param) + param = "V_REAL64_MAX"; + fprintf(f, "\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], %s);\n", param); + } + if(no_param) + param = "NULL"; + switch(VCGData.param_type[i]) + { + case VCGP_NAME : + fprintf(f, "\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], %s, 16);\n", param); + break; + case VCGP_LONG_NAME : + fprintf(f, "\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], %s, 512);\n", param); + break; + } + if(no_param) + { + /* Horrible work-around, that prevents vertex/polygon deletes from misbehaving. */ + if(strncmp(VCGData.alias_name, "g_vertex_delete_real", 20) == 0 && i == 1) + param = "0"; + else if(strncmp(VCGData.alias_name, "g_polygon_delete", 16) == 0 && i == 1) + param = "1"; + else + param = "-1"; + } + switch(VCGData.param_type[i]) + { + case VCGP_NODE_ID : + fprintf(f, "\tbuffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], %s);\n", param); + break; + case VCGP_LAYER_ID : + fprintf(f, "\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], %s);\n", param); + break; + case VCGP_BUFFER_ID : + fprintf(f, "\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], %s);\n", param); + break; + case VCGP_FRAGMENT_ID : + fprintf(f, "\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], %s);\n", param); + break; + } + if(!alias && VCGData.param_type[i] == VCGP_PACK_INLINE) + fprintf(f, "%s", VCGData.param_name[i]); + } + if(VCGData.alias_name != NULL && VCGData.alias_bool_switch) + { + if(alias) + fprintf(f, "\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], FALSE);\n"); + else + fprintf(f, "\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], TRUE);\n"); + } + v_cg_set_command_address(f, alias); + fprintf(f, "\tv_cmd_buf_set_size(head, buffer_pos);\n"); + + fprintf(f, "\tv_noq_send_buf(v_con_get_network_queue(), head);\n"); + fprintf(f, "}\n\n"); +} + +static void v_cg_gen_unpack(void) +{ + FILE *f; + unsigned int i; + boolean printed = FALSE; + + f = VCGData.nodes[VCGData.type]; + printf("generating function: v_unpack_%s\n", VCGData.func_name); + fprintf(f, "unsigned int v_unpack_%s(const char *buf, size_t buffer_length)\n", VCGData.func_name); + fprintf(f, "{\n"); + for(i = 0; i < VCGData.param_count && VCGData.param_type[i] != VCGP_ENUM; i++); + if(i < VCGData.param_count) + fprintf(f, "\tuint8 enum_temp;\n"); + fprintf(f, "\tunsigned int buffer_pos = 0;\n"); + fprintf(f, "\tvoid (* func_%s)(void *user_data, ", VCGData.func_name); + v_cg_gen_func_params(f, FALSE, FALSE); + fprintf(f, ");\n\t"); + v_cg_gen_func_params(f, TRUE, FALSE); + if(VCGData.alias_name != NULL && VCGData.alias_bool_switch) + fprintf(f, "uint8\talias_bool;\n"); + fprintf(f, "\n\tfunc_%s = v_fs_get_user_func(%u);\n", VCGData.func_name, VCGData.cmd_id); + fprintf(f, "\tif(buffer_length < %u)\n\t\treturn -1;\n", v_cg_compute_command_size(0, TRUE)); + for(i = 0; i < VCGData.param_count; i++) + { + switch(VCGData.param_type[i]) + { + case VCGP_UINT8 : + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &%s);\n", VCGData.param_name[i]); + break; + case VCGP_UINT16 : + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &%s);\n", VCGData.param_name[i]); + break; + case VCGP_UINT32 : + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &%s);\n", VCGData.param_name[i]); + break; + case VCGP_REAL32 : + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &%s);\n", VCGData.param_name[i]); + break; + case VCGP_REAL64 : + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &%s);\n", VCGData.param_name[i]); + break; + case VCGP_POINTER_TYPE : + break; + case VCGP_POINTER : + break; + case VCGP_NAME : + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], %s, 16, buffer_length - buffer_pos);\n", VCGData.param_name[i]); + if(i + 1 < VCGData.param_count) + fprintf(f, "\tif(buffer_length < %u + buffer_pos)\n\t\treturn -1;\n", v_cg_compute_command_size(i + 1, TRUE)); + break; + case VCGP_LONG_NAME : + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], %s, 512, buffer_length - buffer_pos);\n", VCGData.param_name[i]); + if(i + 1 < VCGData.param_count) + fprintf(f, "\tif(buffer_length < %u + buffer_pos)\n\t\treturn -1;\n", v_cg_compute_command_size(i + 1, TRUE)); + break; + case VCGP_NODE_ID : + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &%s);\n", VCGData.param_name[i]); + break; + case VCGP_LAYER_ID : + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &%s);\n", VCGData.param_name[i]); + break; + case VCGP_BUFFER_ID : + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &%s);\n", VCGData.param_name[i]); + break; + case VCGP_FRAGMENT_ID : + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &%s);\n", VCGData.param_name[i]); + break; + case VCGP_ENUM : + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp);\n"); + fprintf(f, "\t%s = (%s)enum_temp;\n", VCGData.param_name[i], VCGData.param_name[i - 1]); + break; + case VCGP_UNPACK_INLINE : + if(!printed) + { + fprintf(f, "#if defined V_PRINT_RECEIVE_COMMANDS\n"); + if(VCGData.alias_name != NULL) + { + fprintf(f, "\t%s\n\t", VCGData.alias_qualifier); + v_cg_create_print(f, FALSE, TRUE); + fprintf(f, "\telse\n\t"); + } + v_cg_create_print(f, FALSE, FALSE); + fprintf(f, "#endif\n"); + printed = TRUE; + } + fprintf(f, "%s\n", VCGData.param_name[i++]); + break; + } + } + if(VCGData.alias_name != NULL && VCGData.alias_bool_switch) + { + fprintf(f, "\tif(buffer_length < buffer_pos + 1)\n"); + fprintf(f, "\t\treturn -1;\n"); + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &alias_bool);\n"); + } + if(!printed) + { + fprintf(f, "#if defined V_PRINT_RECEIVE_COMMANDS\n"); + if(VCGData.alias_name != NULL) + { + if(VCGData.alias_qualifier != NULL) + fprintf(f, "\t%s\n\t", VCGData.alias_qualifier); + else + fprintf(f, "\tif(!alias_bool)\n\t"); + v_cg_create_print(f, FALSE, TRUE); + fprintf(f, "\telse\n\t"); + } + v_cg_create_print(f, FALSE, FALSE); + fprintf(f, "#endif\n"); + printed = TRUE; + } + + if(VCGData.alias_name != NULL) + { + unsigned int active; + + if(VCGData.alias_bool_switch) + fprintf(f, "\tif(!alias_bool)\n"); + else + fprintf(f, "\t%s\n", VCGData.alias_qualifier); + fprintf(f, "\t{\n"); + fprintf(f, "\t\tvoid (* alias_%s)(void *user_data, ", VCGData.alias_name); + v_cg_gen_func_params(f, FALSE, TRUE); + fprintf(f, ");\n"); + fprintf(f, "\t\talias_%s = v_fs_get_alias_user_func(%u);\n", VCGData.alias_name, VCGData.cmd_id); + fprintf(f, "\t\tif(alias_%s != NULL)\n", VCGData.alias_name); + fprintf(f, "\t\t\talias_%s(v_fs_get_alias_user_data(%u)", VCGData.alias_name, VCGData.cmd_id); + for(i = 0; i < VCGData.param_count && i < VCGData.alias_param; i++) + { + if(VCGData.alias_param_array != NULL) + active = VCGData.alias_param_array[i]; + else + active = i; + + if(VCGData.param_type[active] != VCGP_PACK_INLINE && + VCGData.param_type[active] != VCGP_UNPACK_INLINE && + VCGData.param_type[active] != VCGP_END_ADDRESS && + VCGData.param_type[active] != VCGP_POINTER_TYPE) + { + if(VCGData.param_type[active] == VCGP_ENUM_NAME) + { + fprintf(f, ", (%s)%s", VCGData.param_name[active], VCGData.param_name[active + 1]); + i++; + } + else + fprintf(f, ", %s", VCGData.param_name[active]); + } + } + fprintf(f, ");\n\t\treturn buffer_pos;\n\t}\n"); + } + + fprintf(f, "\tif(func_%s != NULL)\n", VCGData.func_name); + fprintf(f, "\t\tfunc_%s(v_fs_get_user_data(%u)", VCGData.func_name, VCGData.cmd_id); + for(i = 0; i < VCGData.param_count; i++) + { + if(VCGData.param_type[i] != VCGP_PACK_INLINE && VCGData.param_type[i] != VCGP_UNPACK_INLINE && VCGData.param_type[i] != VCGP_END_ADDRESS && VCGData.param_type[i] != VCGP_POINTER_TYPE) + { + if(VCGData.param_type[i] == VCGP_ENUM_NAME) + { + fprintf(f, ", (%s) %s", VCGData.param_name[i], VCGData.param_name[i + 1]); + i++; + } + else + fprintf(f, ", %s", VCGData.param_name[i]); + } + } + fprintf(f, ");\n"); + fprintf(f, "\n\treturn buffer_pos;\n"); + fprintf(f, "}\n\n"); +} + +static void v_cg_gen_alias(void) +{ + FILE *f; + unsigned int i; + f = VCGData.nodes[VCGData.type]; + fprintf(f, "void verse_send_%s(", VCGData.alias_name); + v_cg_gen_func_params(f, FALSE, TRUE); + fprintf(f, ")\n{\n"); + fprintf(f, "\tverse_send_%s(", VCGData.func_name); + for(i = 0; i < VCGData.param_count; i++) + if(VCGData.param_type[i] != VCGP_ENUM_NAME && VCGData.param_type[i] != VCGP_PACK_INLINE && VCGData.param_type[i] != VCGP_UNPACK_INLINE && VCGData.param_type[i] != VCGP_END_ADDRESS && VCGData.param_type[i] != VCGP_POINTER_TYPE) + fprintf(f, ", %s", VCGData.param_name[i]); + fprintf(f, "}\n\n"); +} + +static void v_cg_gen_init(void) +{ + FILE *f; + f = VCGData.init; + fprintf(f, "\tv_fs_add_func(%i, v_unpack_%s, verse_send_%s, ", VCGData.cmd_id, VCGData.func_name, VCGData.func_name); + if(VCGData.alias_name != NULL) + fprintf(f, "verse_send_%s);\n", VCGData.alias_name); + else + fprintf(f, "NULL);\n"); +} + +static void v_cg_gen_verse_h(void) +{ + FILE *f; + if(VCGData.command == VCGCT_INVISIBLE_SYSTEM) + f = VCGData.internal_verse_h; + else + f = VCGData.verse_h; + fprintf(f, "extern void verse_send_%s(", VCGData.func_name); + v_cg_gen_func_params(f, FALSE, FALSE); + fprintf(f, ");\n"); + if(VCGData.alias_name != NULL) + { + fprintf(f, "extern void verse_send_%s(", VCGData.alias_name); + v_cg_gen_func_params(f, FALSE, TRUE); + fprintf(f, ");\n"); + } +} + +static void v_cg_gen_unpack_h(void) +{ + fprintf(VCGData.unpack, "extern unsigned int v_unpack_%s(const char *data, size_t length);\n", VCGData.func_name); +} + +void v_cg_end_cmd(void) +{ + v_cg_gen_pack(FALSE); + if(VCGData.alias_name != NULL) + v_cg_gen_pack(TRUE); + v_cg_gen_unpack(); + v_cg_gen_init(); + v_cg_gen_verse_h(); + v_cg_gen_unpack_h(); + VCGData.alias_name = NULL; +} + +int main(int argc, char *argv[]) +{ + const char *src = ""; + int i; + + for(i = 1; argv[i] != NULL; i++) + { + if(strcmp(argv[i], "-h") == 0) + { + printf("Verse protocol generation tool.\nUsage:\n"); + printf(" -h\t\tPrint this usage information, and exit.\n"); + printf(" -src=PATH\tSets source path prefix to PATH. It must be possible to find\n"); + printf("\t\tthe \"verse_header.h\" input file by appending that name to PATH.\n"); + printf("\t\tThus, PATH must end with a proper directory separator character.\n"); + printf(" -dst=PATH\tSets output directory, where all output files are written.\n"); + printf("\t\tIf used, use -src to point to where \"verse_header.h\" is.\n"); + printf("\nThe -src and -dst options were added to simplify building of Verse-Blender.\n"); + return EXIT_SUCCESS; + } + else if(strncmp(argv[i], "-src=", 5) == 0) + src = argv[i] + 5; + else if(strncmp(argv[i], "-dst=", 5) == 0) + { + if(chdir(argv[i] + 5) != 0) + fprintf(stderr, "%s: Couldn't set output directory to \"%s\"\n", argv[0], argv[i] + 5); + } + else + fprintf(stderr, "%s: Ignoring unknown option \"%s\"\n", argv[0], argv[i]); + } + + printf("start\n"); + if(!v_cg_init(src)) + return EXIT_FAILURE; + v_gen_system_cmd_def(); + fprintf(VCGData.verse_h, "\n"); + v_gen_object_cmd_def(); + fprintf(VCGData.verse_h, "\n"); + v_gen_geometry_cmd_def(); + fprintf(VCGData.verse_h, "\n"); + v_gen_material_cmd_def(); + fprintf(VCGData.verse_h, "\n"); + v_gen_bitmap_cmd_def(); + fprintf(VCGData.verse_h, "\n"); + v_gen_text_cmd_def(); + fprintf(VCGData.verse_h, "\n"); + v_gen_curve_cmd_def(); + fprintf(VCGData.verse_h, "\n"); + v_gen_audio_cmd_def(); + fprintf(VCGData.verse_h, "\n"); + v_cg_close(); + printf("end\n"); + + return EXIT_SUCCESS; +} + +#endif diff --git a/extern/verse/dist/v_cmd_gen.h b/extern/verse/dist/v_cmd_gen.h new file mode 100644 index 00000000000..6cc19a84d19 --- /dev/null +++ b/extern/verse/dist/v_cmd_gen.h @@ -0,0 +1,42 @@ +/* +** +*/ + +/* Define this to at least build the code that regenerates the variable parts of the code. */ +/*#define V_GENERATE_FUNC_MODE*/ + +typedef enum { + VCGP_UINT8, + VCGP_UINT16, + VCGP_UINT32, + VCGP_REAL32, + VCGP_REAL64, + VCGP_POINTER_TYPE, + VCGP_POINTER, + VCGP_NAME, + VCGP_LONG_NAME, + VCGP_NODE_ID, + VCGP_LAYER_ID, + VCGP_BUFFER_ID, + VCGP_FRAGMENT_ID, + VCGP_ENUM_NAME, + VCGP_ENUM, + VCGP_PACK_INLINE, + VCGP_UNPACK_INLINE, + VCGP_END_ADDRESS +} VCGParam; + +typedef enum { + VCGCT_NORMAL, + VCGCT_UNIQUE, + VCGCT_ONCE, + VCGCT_INVISIBLE_SYSTEM, /* In the dark we are all invisible. */ + VCGCT_ORDERED +} VCGCommandType; + +extern void v_cg_new_cmd(VCGCommandType type, const char *name, unsigned int cmd_id, VCGCommandType command); +extern void v_cg_add_param(VCGParam type, const char *name); +extern void v_cg_alias(char bool_switch, const char *name, const char *qualifier, + unsigned int param, unsigned int *param_array); +extern void v_cg_end_cmd(void); +extern void v_cg_new_manual_cmd(unsigned int cmd_id, const char *name, const char *params, const char *alias_name, const char *alias_params); diff --git a/extern/verse/dist/v_connect.c b/extern/verse/dist/v_connect.c new file mode 100644 index 00000000000..31be90e2d47 --- /dev/null +++ b/extern/verse/dist/v_connect.c @@ -0,0 +1,490 @@ +/* +** +*/ + +#include +#include +#include +#include + +#include "v_cmd_gen.h" + +#if !defined V_GENERATE_FUNC_MODE + +#include "verse.h" +#include "v_cmd_buf.h" +#include "v_network_out_que.h" +#include "v_network.h" +#include "v_connection.h" +#include "v_encryption.h" +#include "v_util.h" + +extern void verse_send_packet_ack(uint32 packet_id); + +static void v_send_hidden_connect_contact(void) /* Stage 0: Clinets inital call to connect to host */ +{ + uint8 buf[V_ENCRYPTION_LOGIN_KEY_HALF_SIZE + 4 + 1 + 1], *key; + unsigned int i, buffer_pos = 0; + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], 0);/* Packing the packet id */ + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 0);/* Packing the command */ + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 0);/* Stage 0 */ + + key = v_con_get_my_key(); + for(i = 0; i < V_ENCRYPTION_LOGIN_KEY_SIZE; i++) + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], key[V_ENCRYPTION_LOGIN_PUBLIC_START + i]);/* Packing the command */ + for(i = 0; i < V_ENCRYPTION_LOGIN_KEY_SIZE; i++) + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], key[V_ENCRYPTION_LOGIN_N_START + i]);/* Packing the command */ + + v_n_send_data(v_con_get_network_address(), buf, buffer_pos); +} + +static void v_send_hidden_connect_send_key(void) /* Stage 1: Hosts reply to any atempt to connect */ +{ + uint8 buf[V_ENCRYPTION_LOGIN_KEY_SIZE * 3 + 4 + 1 + 1 + 1 + 4 + 4], *host_id; + unsigned int i, buffer_pos = 0, s, f; + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], 0);/* Packing the packet id */ + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 0);/* Packing the command */ + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 1);/* Stage 1 */ + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], V_RELEASE_NUMBER);/* version */ + v_n_get_current_time(&s, &f); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], s);/* time, seconds */ + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], f);/* time, fraction */ + host_id = v_con_get_host_id(); + for(i = 0; i < V_ENCRYPTION_LOGIN_KEY_SIZE; i++) + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], host_id[V_ENCRYPTION_LOGIN_PUBLIC_START + i]); + for(i = 0; i < V_ENCRYPTION_LOGIN_KEY_SIZE; i++) + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], host_id[V_ENCRYPTION_LOGIN_N_START + i]); + + v_n_send_data(v_con_get_network_address(), buf, buffer_pos); +} + +static void v_send_hidden_connect_login(void) /* Stage 2: clients sends encrypted name and password */ +{ + uint8 buf[1500], *key, name_pass[V_ENCRYPTION_LOGIN_KEY_SIZE], encrypted_key[V_ENCRYPTION_LOGIN_KEY_SIZE]; + const char *name, *pass; + unsigned int buffer_pos = 0, i; + + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], 1);/* Packing the packet id */ + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 0);/* Packing the command */ + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 2);/* Stage 2 */ + name = v_con_get_name(); + /* Pad data area with randomness. */ + for(i = 0; i < sizeof name_pass; i++) + name_pass[i] = rand() >> 13; + v_strlcpy(name_pass, name, V_ENCRYPTION_LOGIN_KEY_SIZE / 2); + pass = v_con_get_pass(); + v_strlcpy(name_pass + V_ENCRYPTION_LOGIN_KEY_SIZE / 2, pass, V_ENCRYPTION_LOGIN_KEY_SIZE / 2); + /* Make sure last (MSB) byte is clear, to guarantee that data < key for RSA math. */ + name_pass[sizeof name_pass - 1] = 0; + key = v_con_get_other_key(); + v_e_connect_encrypt(encrypted_key, name_pass, &key[V_ENCRYPTION_LOGIN_PUBLIC_START], &key[V_ENCRYPTION_LOGIN_N_START]); + + for(i = 0; i < V_ENCRYPTION_LOGIN_KEY_SIZE; i++) + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], encrypted_key[i]); + v_n_send_data(v_con_get_network_address(), buf, buffer_pos); +} + +static void v_send_hidden_connect_accept(void) /* Host accepts Clients connectionatempt and sends over data encryption key */ +{ + uint8 buf[1500], *client_key, encrypted[V_ENCRYPTION_DATA_KEY_SIZE]; + unsigned int i, buffer_pos = 0; + + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], 1);/* Packing the packet id */ + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 1);/* Packing the command */ + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], verse_session_get_avatar()); + client_key = v_con_get_other_key(); + v_e_connect_encrypt(encrypted, v_con_get_data_key(), &client_key[V_ENCRYPTION_LOGIN_PUBLIC_START], &client_key[V_ENCRYPTION_LOGIN_N_START]); + for(i = 0; i < V_ENCRYPTION_DATA_KEY_SIZE; i++) + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], encrypted[i]); + v_n_send_data(v_con_get_network_address(), buf, buffer_pos); +} + +static void v_send_hidden_connect_terminate(VNetworkAddress *address, unsigned int packet_id, const char *bye) /* Host accepts Clients connectionatempt and sends over data encryption key */ +{ + uint8 buf[1500]; + unsigned int buffer_pos = 0; + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], packet_id);/* Packing the packet id */ + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 2);/* Packing the command */ + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], bye, 512); /* pack message */ + v_e_data_encrypt_command(buf, sizeof (uint32), buf + sizeof (uint32), buffer_pos, v_con_get_data_key()); + v_n_send_data(address, buf, buffer_pos); +} + +VSession verse_send_connect(const char *name, const char *pass, const char *address, const uint8 *expected_key) +{ + uint8 *my_key, *key = NULL; + unsigned int i; + VNetworkAddress a; + VSession *session; + if(v_n_set_network_address(&a, address)) + { +#if defined(V_PRINT_SEND_COMMANDS) + char ip_string[32]; +#endif + session = v_con_connect(a.ip, a.port, V_CS_CONTACT); +#if defined(V_PRINT_SEND_COMMANDS) + v_n_get_address_string(&a, ip_string); + printf("send: %p = verse_send_connect(name = %s, pass = %s, address = %s (%s), expected_key = %p)\n", session, name, pass, address, ip_string, expected_key); +#endif + v_con_set_name_pass(name, pass); + if(expected_key != NULL) + { + key = malloc((sizeof *key) * V_ENCRYPTION_LOGIN_KEY_HALF_SIZE); + for(i = 0; i < V_ENCRYPTION_LOGIN_KEY_HALF_SIZE; i++) + key[i] = expected_key[i]; + *v_con_get_expected_key() = key; + } + my_key = v_con_get_my_key(); + v_e_connect_create_key(&my_key[V_ENCRYPTION_LOGIN_PRIVATE_START], &my_key[V_ENCRYPTION_LOGIN_PUBLIC_START], &my_key[V_ENCRYPTION_LOGIN_N_START]); + v_send_hidden_connect_contact(); + v_con_inqueue_timer_update(); /* Reset timer in connection's in queue, above takes a while. */ + return session; + } + else + { +#if defined(V_PRINT_SEND_COMMANDS) + printf("send: NULL = verse_send_connect(name = %s, pass = %s, address = %s (Unressolved DNS), key = %p);\n", name, pass, address, key); +#endif + return NULL; + } +} + +void v_update_connection_pending(boolean resend) +{ + VSession (* func_connect)(void *user_data, const char *name, const char *pass, const char *address, const uint8 *key) = NULL; + VSession (* func_connect_accept)(void *user_data, VNodeID avatar, char *address, uint8 *host_id); + void (* func_connect_terminate)(void *user_data, char *address, const char *bye); + char address_string[32]; + + switch(v_con_get_connect_stage()) + { + case V_CS_CONTACT : /* client tries to contact host */ + if(resend) + v_send_hidden_connect_contact(); + break; + case V_CS_CONTACTED : /* Host replies with challange */ + if(resend) + v_send_hidden_connect_send_key(); + break; + case V_CS_PENDING_ACCEPT : /* Client sends login */ + if(resend) + v_send_hidden_connect_login(); + break; + case V_CS_PENDING_HOST_CALLBACK : /* Host got login waits for accept connect callback */ + v_con_set_connect_stage(V_CS_PENDING_DECISION); + func_connect = v_fs_get_user_func(0); + v_n_get_address_string(v_con_get_network_address(), address_string); +#if defined(V_PRINT_RECEIVE_COMMANDS) + printf("receive: verse_send_connect(address = %s, name = %s, pass = %s, key = NULL); callback = %p\n", address_string, v_con_get_name(), v_con_get_pass(), func_connect); +#endif + if(func_connect != 0) + func_connect(v_fs_get_user_data(0), v_con_get_name(), v_con_get_pass(), address_string, NULL); + break; + case V_CS_PENDING_CLIENT_CALLBACK_ACCEPT : /* Host got login waits for accept connect callback */ + v_con_set_connect_stage(V_CS_CONNECTED); + func_connect_accept = v_fs_get_user_func(1); + v_n_get_address_string(v_con_get_network_address(), address_string); +#if defined(V_PRINT_RECEIVE_COMMANDS) + printf("receive: func_connect_accept(avatar = %u, address = %s, name = %s, pass = %s, key = NULL); callback = %p\n", + verse_session_get_avatar(), address_string, v_con_get_name(), v_con_get_pass(), func_connect); +#endif + if(func_connect_accept != 0) + func_connect_accept(v_fs_get_user_data(1), verse_session_get_avatar(), address_string, NULL); + break; + case V_CS_PENDING_CLIENT_CALLBACK_TERMINATE : /* Host got login waits for accept connect callback */ + v_con_set_connect_stage(V_CS_CONNECTED); + func_connect_terminate = v_fs_get_user_func(2); + v_n_get_address_string(v_con_get_network_address(), address_string); +#if defined(V_PRINT_RECEIVE_COMMANDS) + printf("receive: func_connect_terminate(address = %s, bye = %s); callback = %p\n", address_string, "no message", func_connect); +#endif + if(func_connect_terminate != 0) + func_connect_terminate(v_fs_get_user_data(2), address_string, "no message"); + break; + default: + ; + } +} + +void v_unpack_connection(const char *buf, unsigned int buffer_length) /* un packing all stages of connect command */ +{ + unsigned int buffer_pos, i, pack_id; + uint32 seconds, fractions, pre; + uint8 /*key[V_ENCRYPTION_LOGIN_KEY_SIZE], */stage, cmd_id, version; + + if(buffer_length < 5) + return; + + buffer_pos = vnp_raw_unpack_uint32(buf, &pack_id); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &cmd_id); + pre = v_con_get_connect_stage(); + if(cmd_id == 0) + { + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &stage); + printf(" Handling connection, stage %u\n", stage); + if(stage == V_CS_IDLE && V_CS_IDLE == v_con_get_connect_stage()) /* reseved by host */ + { + uint8 *other_key, *my_key; + + verse_send_packet_ack(pack_id); + my_key = v_con_get_my_key(); + v_con_set_data_key(v_e_data_create_key()); + other_key = v_con_get_other_key(); + for(i = 0; i < V_ENCRYPTION_LOGIN_KEY_SIZE; i++) + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &other_key[V_ENCRYPTION_LOGIN_PUBLIC_START + i]);/* Packing the command */ + for(i = 0; i < V_ENCRYPTION_LOGIN_KEY_SIZE; i++) + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &other_key[V_ENCRYPTION_LOGIN_N_START + i]);/* Packing the command */ + v_con_set_connect_stage(V_CS_CONTACTED); + v_send_hidden_connect_send_key(); + return; + } + if(stage == V_CS_CONTACT && V_CS_CONTACT == v_con_get_connect_stage()) + { + uint8 *other_key; /* *host_id, *my_key, a[V_ENCRYPTION_LOGIN_KEY_SIZE], b[V_ENCRYPTION_LOGIN_KEY_SIZE];*/ + verse_send_packet_ack(pack_id); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &version); + if(version != V_RELEASE_NUMBER) + { + /* char error_message[128]; + func_connect_deny = v_fs_get_user_func(2); + #if defined(V_PRINT_RECEIVE_COMMANDS) + printf("receive: verse_send_connect_deny(Host is running version %u you are running version %u); callback = %p\n", (uint32)version, (uint32)V_RELEASE_NUMBER func_connect_deny); + #endif + if(func_connect_deny != NULL) + { + sprintf(error_message, "Host is running version %u you are running version %u", (uint32)version, (uint32)V_RELEASE_NUMBER); + func_connect_deny(v_fs_get_user_data(2), error_message); + }*/ + return; + } + + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &seconds); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &fractions); + v_con_set_time(seconds, fractions); + + other_key = v_con_get_other_key(); + for(i = 0; i < V_ENCRYPTION_LOGIN_KEY_SIZE; i++) + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &other_key[V_ENCRYPTION_LOGIN_PUBLIC_START + i]); + for(i = 0; i < V_ENCRYPTION_DATA_KEY_SIZE; i++) + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &other_key[V_ENCRYPTION_LOGIN_N_START + i]); + + v_con_set_connect_stage(V_CS_PENDING_ACCEPT); + v_send_hidden_connect_login(); + return; + } +#if 0 + for(i = 0; i < V_ENCRYPTION_LOGIN_KEY_HALF_SIZE && encrypted_key[i] == 0; i++); + if(i < 0) + { + other_key = v_con_get_my_key(); + v_e_connect_encrypt(decrypted_key, encrypted_key, &other_key[V_ENCRYPTION_LOGIN_PUBLIC_START + i], &other_key[V_ENCRYPTION_LOGIN_N_START + i]); + for(i = 0; i < V_ENCRYPTION_LOGIN_KEY_HALF_SIZE && my_key[V_ENCRYPTION_LOGIN_PUBLIC_START + i] == decrypted_key[i]; i++); + if(i < 0) /* Host is not who it appers top be */ + { + func_connect_deny = v_fs_get_user_func(2); +#if defined(V_PRINT_RECEIVE_COMMANDS) + printf("receive: verse_send_connect_deny(Host failed identity check); callback = %p\n", func_connect_deny); +#endif + if(func_connect_deny != NULL) + func_connect_deny(v_fs_get_user_data(2), "Host failed identity check"); + return; + } + } +#endif + if(stage == V_CS_CONTACTED && V_CS_CONTACTED == v_con_get_connect_stage()) /* reseved by host */ + { + char *host_id, unpack[V_ENCRYPTION_LOGIN_KEY_SIZE], data[V_ENCRYPTION_LOGIN_KEY_SIZE]; + VNetworkAddress *address; + verse_send_packet_ack(pack_id); + address = v_con_get_network_address(); + for(i = 0; i < V_ENCRYPTION_LOGIN_KEY_SIZE; i++) + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &data[i]); + host_id = v_con_get_host_id(); + v_e_connect_encrypt(unpack, data, &host_id[V_ENCRYPTION_LOGIN_PRIVATE_START], &host_id[V_ENCRYPTION_LOGIN_N_START]); + v_con_set_name_pass(unpack, &unpack[V_ENCRYPTION_LOGIN_KEY_SIZE / 2]); + v_con_set_connect_stage(V_CS_PENDING_HOST_CALLBACK); + return; + } + } + if(cmd_id == 1 && V_CS_PENDING_ACCEPT == v_con_get_connect_stage()) /* reseved by client */ + { + uint8 *my_key, key[V_ENCRYPTION_DATA_KEY_SIZE], decrypted[V_ENCRYPTION_DATA_KEY_SIZE]; + uint32 avatar; + verse_send_packet_ack(pack_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &avatar); + v_con_set_avatar(avatar); + for(i = 0; i < V_ENCRYPTION_DATA_KEY_SIZE; i++) + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &key[i]); + my_key = v_con_get_my_key(); + v_e_connect_encrypt(decrypted, key, &my_key[V_ENCRYPTION_LOGIN_PRIVATE_START], &my_key[V_ENCRYPTION_LOGIN_N_START]); + v_con_set_data_key(decrypted); + v_con_set_connect_stage(V_CS_PENDING_CLIENT_CALLBACK_ACCEPT); + v_send_hidden_connect_send_key(); + return; + } + if(cmd_id == 2 && V_CS_PENDING_ACCEPT == v_con_get_connect_stage()) /* reseved by client */ + { + verse_send_packet_ack(pack_id); + /* buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], name, 512, buffer_length - buffer_pos); + */ v_con_set_connect_stage(V_CS_PENDING_CLIENT_CALLBACK_TERMINATE); + return; + } +} + +VSession verse_send_connect_accept(VNodeID avatar, const char *address, uint8 *host_id) +{ + VNetworkAddress a; +#if defined(V_PRINT_SEND_COMMANDS) + printf("send: verse_send_connect_accept(avatar = %u, address = %s, host_id = NULL);\n", avatar, address); +#endif + + if(!v_n_set_network_address(&a, address)) + return NULL; + if(v_co_switch_connection(a.ip, a.port)) + { + if(v_con_get_connect_stage() != V_CS_PENDING_DECISION) + return NULL; + v_con_set_avatar(avatar); + v_con_set_connect_stage(V_CS_CONNECTED); + v_send_hidden_connect_accept(); + return v_con_get_network_queue(); + } + return NULL; +} + +void v_callback_connect_terminate(const char *bye) +{ + void (* func_connect_terminate)(void *user_data, char *address, const char *bye); + char address_string[32]; + + printf("terminate (%s)\n", bye); + func_connect_terminate = v_fs_get_user_func(2); + v_n_get_address_string(v_con_get_network_address(), address_string); +#if defined(V_PRINT_RECEIVE_COMMANDS) + printf("receive: verse_send_connect_terminate(address = %s, bye = %s); callback = %p\n", address_string, bye, func_connect_terminate); +#endif + if(func_connect_terminate != 0) + func_connect_terminate(v_fs_get_user_data(2), address_string, bye); +} + +void verse_send_connect_terminate(const char *address, const char *bye) +{ + VNetworkAddress a; +#if defined(V_PRINT_RECEIVE_COMMANDS) + printf("send: verse_send_connect_terminate(address = %s, bye = %s);\n", address, bye); +#endif + + if(address == NULL) + v_send_hidden_connect_terminate(v_con_get_network_address(), v_noq_get_next_out_packet_id(v_con_get_network_queue()), bye); + else if(!v_n_set_network_address(&a, address)) + return; + else if(v_co_switch_connection(a.ip, a.port)) + v_send_hidden_connect_terminate(v_con_get_network_address(), v_noq_get_next_out_packet_id(v_con_get_network_queue()), bye); + + if(v_con_get_connect_stage() != V_CS_PENDING_DECISION) + verse_session_destroy(v_con_get_network_queue()); +} + +void verse_send_ping(const char *address, const char *message) +{ + VNetworkAddress a; + if(v_n_set_network_address(&a, address)) + { + unsigned int buffer_pos = 0; + uint8 buf[1500]; + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], 0);/* Packing the Packet id */ + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 5);/* Packing the command */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_ping(address = %s text = %s);\n", address, message); +#endif + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], message, 1400); + v_n_send_data(&a, buf, buffer_pos); + } +#if defined V_PRINT_SEND_COMMANDS + else + printf("send: verse_send_ping(address = %s (FAULTY) message = %s);\n", address, message); +#endif +} + +unsigned int v_unpack_ping(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_ping)(void *user_data, const char *address, const char *text); + char address[64]; + char message[1400]; + + func_ping = v_fs_get_user_func(5); + v_n_get_address_string(v_con_get_network_address(), address); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], message, 1400, buffer_length - buffer_pos); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_ping(address = %s message = %s ); callback = %p\n", address, message, v_fs_get_user_func(5)); +#endif + if(func_ping != NULL) + func_ping(v_fs_get_user_data(5), address, message); + return buffer_pos; +} + +typedef struct { + uint32 ip; + uint16 port; + char message[1400]; + void *next; +} VPingCommand; + +static VPingCommand *v_ping_commands = NULL; + +boolean v_connect_unpack_ping(const char *buf, size_t buffer_length, uint32 ip, uint16 port) +{ + if(buffer_length > 5) + { + unsigned int buffer_pos = 0; + uint8 cmd_id; + uint32 pack_id; + + buffer_pos = vnp_raw_unpack_uint32(&buf[buffer_pos], &pack_id); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &cmd_id); + if(cmd_id == 5) + { + if(NULL != v_fs_get_user_func(5)) + { + VPingCommand *pc; + + pc = malloc(sizeof *pc); + pc->ip = ip; + pc->port = port; + vnp_raw_unpack_string(&buf[buffer_pos], pc->message, + sizeof pc->message, buffer_length - buffer_pos); + pc->next = v_ping_commands; + v_ping_commands = pc; + } + return TRUE; + } + } + return FALSE; +} + +void v_ping_update(void) +{ + VPingCommand *cp; + void (* func_ping)(void *user_data, const char *address, const char *text); + VNetworkAddress a; + char address[64]; + func_ping = v_fs_get_user_func(5); + + while(v_ping_commands != NULL) + { + cp = v_ping_commands->next; + a.ip = v_ping_commands->ip; + a.port = v_ping_commands->port; + v_n_get_address_string(&a, address); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_ping(address = %s message = %s ); callback = %p\n", address, v_ping_commands->message, v_fs_get_user_func(5)); +#endif + if(func_ping != NULL) + func_ping(v_fs_get_user_data(5), address, v_ping_commands->message); + free(v_ping_commands); + v_ping_commands = cp; + } +} + +#endif diff --git a/extern/verse/dist/v_connection.c b/extern/verse/dist/v_connection.c new file mode 100644 index 00000000000..3bfafad5660 --- /dev/null +++ b/extern/verse/dist/v_connection.c @@ -0,0 +1,490 @@ +/* +** +*/ + +#include +#include +#include + +#include "v_cmd_buf.h" +#include "v_network_in_que.h" +#include "v_network_out_que.h" +#include "v_cmd_gen.h" +#include "v_connection.h" +#include "v_encryption.h" +#include "v_util.h" + +#if !defined(V_GENERATE_FUNC_MODE) +#include "verse.h" + +#define CONNECTION_CHUNK_SIZE 16 +#define V_MAX_CONNECT_PACKET_SIZE 1500 +#define V_CON_MAX_MICROSECOND_BETWEEN_SENDS 100 +#define V_RE_CONNECTON_TIME_OUT 4 +#define V_CONNECTON_TIME_OUT 30 + +typedef struct { + VNetOutQueue *out_queue; + VNetInQueue in_queue; + VNetworkAddress network_address; + boolean connected; + unsigned int avatar; +/* unsigned int packet_id;*/ + int32 timedelta_s; + uint32 timedelta_f; + boolean destroy_flag; + void *ordered_storage; + char name[V_ENCRYPTION_LOGIN_KEY_SIZE / 2]; + char pass[V_ENCRYPTION_LOGIN_KEY_SIZE / 2]; + VConnectStage connect_stage; + unsigned int stage_atempts; + uint8 key_my[V_ENCRYPTION_LOGIN_KEY_FULL_SIZE]; + uint8 key_other[V_ENCRYPTION_LOGIN_KEY_FULL_SIZE]; + uint8 key_data[V_ENCRYPTION_DATA_KEY_SIZE]; + uint8 *expected_key; +} VConnection; + +static struct { + VConnection *con; + unsigned int con_count; + unsigned int current_connection; + VNetworkAddress *connect_address; + void *unified_func_storage; + uint16 connect_port; + unsigned int pending_packets; + uint8 host_id[V_ENCRYPTION_LOGIN_KEY_FULL_SIZE]; +} VConData; + +extern void cmd_buf_init(void); + +void v_con_init(void) /* since verse doesnt have an init function this function is runned over an ove ard starts whit a check it it has run before */ +{ + static boolean v_con_initialized = FALSE; + + if(v_con_initialized) + return; + cmd_buf_init(); + v_con_initialized = TRUE; + VConData.con = malloc(CONNECTION_CHUNK_SIZE * sizeof *VConData.con); + memset(VConData.con, 0, CONNECTION_CHUNK_SIZE * sizeof *VConData.con); /* Clear the memory. */ + VConData.con_count = 0; + VConData.pending_packets = 0; +/* v_e_connect_create_key(&VConData.host_id[V_ENCRYPTION_LOGIN_PRIVATE_START], + &VConData.host_id[V_ENCRYPTION_LOGIN_PUBLIC_START], + &VConData.host_id[V_ENCRYPTION_LOGIN_N_START]);*/ /* default host id if none is set by user */ +} + +void verse_set_port(uint16 port) +{ + v_n_set_port(port); +} + +void verse_host_id_create(uint8 *id) +{ + v_e_connect_create_key(&id[V_ENCRYPTION_LOGIN_PRIVATE_START], + &id[V_ENCRYPTION_LOGIN_PUBLIC_START], &id[V_ENCRYPTION_LOGIN_N_START]); +} + +void verse_host_id_set(uint8 *id) +{ + memcpy(VConData.host_id, id, V_ENCRYPTION_LOGIN_KEY_FULL_SIZE); +} + +extern void *v_fs_create_func_storage(void); +extern void *v_create_ordered_storage(void); +extern void v_destroy_ordered_storage(void *data); + +void *v_con_connect(uint32 ip, uint16 port, VConnectStage stage) /* creates a new connection slot */ +{ + v_con_init(); /* init connections, if not done yet */ + if((VConData.con_count - 1) % CONNECTION_CHUNK_SIZE == 0) /* do we need more slots for connections, then reallocate more space */ + VConData.con = realloc(VConData.con, (sizeof *VConData.con) * (VConData.con_count + CONNECTION_CHUNK_SIZE)); + VConData.con[VConData.con_count].out_queue = v_noq_create_network_queue(); /* create a out queue fo all out going commands */ + v_niq_clear(&VConData.con[VConData.con_count].in_queue); /* clear and init the que of incomming packets.*/ + VConData.con[VConData.con_count].connected = FALSE; /* not yet propperly connected and should not accept commands yet */ + VConData.con[VConData.con_count].network_address.ip = ip; /* ip address of other side */ + VConData.con[VConData.con_count].network_address.port = port; /* port used by other side */ + VConData.con[VConData.con_count].avatar = 0; /* no avatar set yet*/ +/* VConData.con[VConData.con_count].packet_id = 2;*/ + VConData.con[VConData.con_count].destroy_flag = FALSE; /* this is a flag that is set once the connection is about to be destroyed.*/ + VConData.con[VConData.con_count].ordered_storage = v_create_ordered_storage(); + VConData.con[VConData.con_count].name[0] = 0; /* nouser name set yet */ + VConData.con[VConData.con_count].pass[0] = 0; /* no password set yet */ + VConData.con[VConData.con_count].connect_stage = stage; /* this is the stage of the connection, it show if the connection is ready, the init state depends if this is a client or host */ + VConData.con[VConData.con_count].stage_atempts = 0; /* each stage in the connection prosess is atempted multiple times to avoid failiure if packets get lost*/ + VConData.con[VConData.con_count].timedelta_s = 0; /* number of seconds since last incomming packet to the connection*/ + VConData.con[VConData.con_count].timedelta_f = 0; /* number of fractions of a second since last incomming packet to the connection*/ + VConData.con[VConData.con_count].expected_key = NULL; /* expected hist id if this is a client */ + VConData.current_connection = VConData.con_count; /* set the new connection to the current*/ + ++VConData.con_count; /* add one to the number of connections*/ + return VConData.con[VConData.current_connection].out_queue; +} + +void verse_session_destroy(VSession session) /* a session can not be destroyed right away, because this function might be called inside a call back from the session it tryes tpo destroy, therfor it only markes it*/ +{ + unsigned int i; + for(i = 0; i < VConData.con_count && VConData.con[i].out_queue != session; i++); + if(i < VConData.con_count) + { + VConData.con[i].destroy_flag = TRUE; + } +} + +void verse_session_set(VSession session) /* find a session and make it the current*/ +{ + unsigned int i; + for(i = 0; i < VConData.con_count && session != VConData.con[i].out_queue; i++); + if(i < VConData.con_count) + VConData.current_connection = i; +} + +VSession verse_session_get(void) +{ + if(VConData.current_connection < VConData.con_count) + return VConData.con[VConData.current_connection].out_queue; + return NULL; +} + +uint32 v_co_find_connection(uint32 ip, uint16 port) /* if a packet comes form a ip address what connection does it belong to? */ +{ + unsigned int i; + + for(i = 0; i < VConData.con_count; i++) + { + if(ip == VConData.con[i].network_address.ip && + port == VConData.con[i].network_address.port && + VConData.con[i].destroy_flag == 0) + { + return i; + } + } + return -1; +} + +boolean v_co_switch_connection(uint32 ip, uint16 port) /* switches to the current connection to one ip address if it exists */ +{ + unsigned int i; + for(i = 0; i < VConData.con_count; i++) + { + if(ip == VConData.con[i].network_address.ip && port == VConData.con[i].network_address.port) + { + VConData.current_connection = i; + return TRUE; + } + } + return FALSE; +} + +void v_con_inqueue_timer_update(void) +{ + if(VConData.current_connection < VConData.con_count) + { + v_niq_timer_update(&VConData.con[VConData.current_connection].in_queue); + } +} + +/* +extern void v_fs_buf_unpack(const uint8 *data, unsigned int length); +extern void v_fs_buf_store_pack(uint8 *data, unsigned int length); +extern boolean v_fs_buf_unpack_stored(void); +*/ +extern void v_unpack_connection(const char *buf, unsigned int buffer_length); + +extern void verse_send_packet_nak(uint32 packet_id); +extern void v_callback_connect_terminate(const char *bye); +extern boolean v_connect_unpack_ping(const char *buf, size_t buffer_length, uint32 ip, uint16 port); +extern void v_ping_update(void); +void v_fs_unpack_beginning(uint8 *data, unsigned int length); + +/* Main function that receives and distributes all incoming packets. */ +boolean v_con_network_listen(void) +{ + VNetworkAddress address; + uint8 buf[V_MAX_CONNECT_PACKET_SIZE], *store; + int size = 0; + unsigned int connection; + uint32 packet_id; + boolean ret = FALSE; + + v_con_init(); /* Init if needed. */ + connection = VConData.current_connection; /* Store current connection in a local variable so that we can restore it later. */ + size = v_n_receive_data(&address, buf, sizeof buf); /* Ask for incoming data from the network. */ + while(size != -1 && size != 0) /* Did we get any data? */ + { + VConData.current_connection = v_co_find_connection(address.ip, address.port); /* Is there a connection matching the IP and port? */ + vnp_raw_unpack_uint32(buf, &packet_id); /* Unpack the ID of the packet. */ +/* printf("got packet ID %u, %d bytes, connection %u\n", packet_id, size, VConData.current_connection);*/ + if(VConData.current_connection < VConData.con_count && + !(VConData.con[VConData.current_connection].connect_stage == V_CS_CONNECTED && packet_id == 0)) /* If this isn't a packet from an existing connection, disregard it. */ + { + if(VConData.con[VConData.current_connection].connect_stage == V_CS_CONNECTED) /* Is this connection initialized? */ + { + store = v_niq_store(&VConData.con[VConData.current_connection].in_queue, size, packet_id); /* Store the packet. */ + if(store != NULL) + { + VConData.pending_packets++; /* We now have one more packet pending unpack. */ + v_e_data_decrypt_packet(store, buf, size, VConData.con[VConData.current_connection].key_data); /* Decrypt the packet. */ + v_fs_unpack_beginning(store, size); + } + } + else + { + v_unpack_connection(buf, size); /* This is an ongoing connecton-attempt. */ + v_niq_timer_update(&VConData.con[VConData.current_connection].in_queue); + } + } + else if(v_connect_unpack_ping(buf, size, address.ip, address.port)) /* Ping handled. */ + ; + else if(v_fs_func_accept_connections()) /* Do we accept connection-attempts? */ + { + if(VConData.current_connection >= VConData.con_count || + V_RE_CONNECTON_TIME_OUT < v_niq_time_out(&VConData.con[VConData.current_connection].in_queue)) /* Is it a new client, or an old client that we haven't heard form in some time? */ + { + if(VConData.current_connection < VConData.con_count) + { + VConData.con[VConData.current_connection].network_address.ip = 0; + VConData.con[VConData.current_connection].destroy_flag = TRUE; /* Destroy old connection if there is one. */ + } + v_con_connect(address.ip, address.port, V_CS_IDLE); /* Create a new connection. */ + v_unpack_connection(buf, size); /* Unpack the connection-attempt. */ + } + } + else + { + fprintf(stderr, __FILE__ ": Unhandled packet--dropping\n"); + if(VConData.con_count > 0) + { + fprintf(stderr, __FILE__ ": State: connections=%u, current=%u (stage %u), packet_id=%u\n", + VConData.con_count, + VConData.current_connection, + (VConData.current_connection < VConData.con_count) ? VConData.con[VConData.current_connection].connect_stage : 0, + packet_id); + } + } + size = v_n_receive_data(&address, buf, sizeof buf); /* See if there are more incoming packets. */ + ret = TRUE; + } + VConData.current_connection = connection; /* Reset the current connection. */ + + return ret; +} + +extern void v_update_connection_pending(boolean resend); + +boolean v_con_callback_update(void) +{ + static unsigned int seconds; + boolean output = FALSE; + size_t size; + unsigned int connection, s; + VNetInPacked *p; + + v_n_get_current_time(&s, NULL); + connection = VConData.current_connection; + for(VConData.current_connection = 0; VConData.current_connection < VConData.con_count; VConData.current_connection++) + if(VConData.con[VConData.current_connection].connect_stage != V_CS_CONNECTED) + v_update_connection_pending(s != seconds); + seconds = s; + VConData.current_connection = connection; + if(VConData.pending_packets == 0) + return FALSE; + if(VConData.con[VConData.current_connection].connect_stage == V_CS_CONNECTED) + { + while((p = v_niq_get(&VConData.con[VConData.current_connection].in_queue, &size)) != NULL) + { + VConData.pending_packets--; + v_fs_unpack(p->data, size); + v_niq_release(&VConData.con[VConData.current_connection].in_queue, p); + output = TRUE; + } + v_con_network_listen(); + } + return output; +} + +void verse_callback_update(unsigned int microseconds) +{ + unsigned int connection, passed; + + v_ping_update(); /* Deliver any pending pings. */ + connection = VConData.current_connection; + for(VConData.current_connection = 0; VConData.current_connection < VConData.con_count; VConData.current_connection++) + { + if(VConData.con[VConData.current_connection].connect_stage == V_CS_CONNECTED) + v_noq_send_queue(VConData.con[VConData.current_connection].out_queue, &VConData.con[VConData.current_connection].network_address); + if(VConData.con[VConData.current_connection].destroy_flag == TRUE) + { + v_noq_destroy_network_queue(VConData.con[VConData.current_connection].out_queue); + VConData.pending_packets -= v_niq_free(&VConData.con[VConData.current_connection].in_queue); + v_destroy_ordered_storage(VConData.con[VConData.current_connection].ordered_storage); + if(VConData.con[VConData.current_connection].expected_key != NULL) + free(VConData.con[VConData.current_connection].expected_key); + if(VConData.con_count - 1 != VConData.current_connection) + VConData.con[VConData.current_connection] = VConData.con[VConData.con_count - 1]; + VConData.con_count--; + if(connection >= VConData.con_count) + VConData.current_connection = 0; + return; + } + } + VConData.current_connection = connection; + + if(VConData.con_count > 0) + { +/* printf("checking timeout of stage %d connection %u\n", + VConData.con[VConData.current_connection].connect_stage, VConData.current_connection); +*/ if(V_CONNECTON_TIME_OUT < v_niq_time_out(&VConData.con[VConData.current_connection].in_queue)) + { + if(VConData.con[VConData.current_connection].connect_stage != V_CS_CONNECTED) + { + VConData.con[VConData.current_connection].destroy_flag = TRUE; + } + else + v_callback_connect_terminate("connection timed out"); + } + } + + v_con_network_listen(); + if(VConData.con_count > 0) + if(v_con_callback_update()) + return; + for(passed = 0; passed < microseconds && VConData.pending_packets == 0;) + { + boolean update; + if(microseconds - passed > V_CON_MAX_MICROSECOND_BETWEEN_SENDS) /* Still a long way to go? */ + passed += v_n_wait_for_incoming(V_CON_MAX_MICROSECOND_BETWEEN_SENDS); + else + passed += v_n_wait_for_incoming(microseconds - passed); + do + { + update = v_con_network_listen(); + connection = VConData.current_connection; + for(VConData.current_connection = 0; VConData.current_connection < VConData.con_count; VConData.current_connection++) + { + if(VConData.con[VConData.current_connection].connect_stage == V_CS_CONNECTED) + { + if(v_noq_send_queue(VConData.con[VConData.current_connection].out_queue, &VConData.con[VConData.current_connection].network_address)) + update = TRUE; + } + } + VConData.current_connection = connection; + } while(update); + } + if(VConData.con_count > 0) + v_con_callback_update(); +} + +void v_con_set_name_pass(const char *name, const char *pass) +{ + v_strlcpy(VConData.con[VConData.current_connection].name, name, sizeof VConData.con[VConData.current_connection].name); + v_strlcpy(VConData.con[VConData.current_connection].pass, pass, sizeof VConData.con[VConData.current_connection].pass); +} + +const char * v_con_get_name(void) +{ + return VConData.con[VConData.current_connection].name; +} + +const char * v_con_get_pass(void) +{ + return VConData.con[VConData.current_connection].pass; +} + +void v_con_set_connect_stage(VConnectStage stage) +{ + VConData.con[VConData.current_connection].connect_stage = stage; + VConData.con[VConData.current_connection].stage_atempts = 0; +} + +VConnectStage v_con_get_connect_stage(void) +{ + return VConData.con[VConData.current_connection].connect_stage; +} + +uint8 *v_con_get_my_key(void) +{ + return VConData.con[VConData.current_connection].key_my; +} + +uint8 *v_con_get_other_key(void) +{ + return VConData.con[VConData.current_connection].key_other; +} + +uint8 **v_con_get_expected_key(void) +{ + return &VConData.con[VConData.current_connection].expected_key; +} + +uint8 * v_con_get_host_id(void) +{ + return VConData.host_id; +} + +void v_con_set_data_key(const uint8 *key) +{ + memcpy(VConData.con[VConData.current_connection].key_data, key, V_ENCRYPTION_DATA_KEY_SIZE); +} + +const uint8 * v_con_get_data_key(void) +{ + return VConData.con[VConData.current_connection].key_data; +} + +void * v_con_get_network_queue(void) +{ + return VConData.con[VConData.current_connection].out_queue; +} + +VNetworkAddress * v_con_get_network_address(void) +{ + return &VConData.con[VConData.current_connection].network_address; +} + +void * v_con_get_ordered_storage(void) +{ + return VConData.con[VConData.current_connection].ordered_storage; +} + +void v_con_set_avatar(uint32 avatar) +{ + VConData.con[VConData.current_connection].avatar = avatar; +} + +uint32 verse_session_get_avatar(void) +{ + return VConData.con[VConData.current_connection].avatar; +} + +void verse_session_get_time(uint32 *seconds, uint32 *fractions) +{ + uint32 s, f; + v_n_get_current_time(&s, &f); + if((uint32)~0 - f < VConData.con[VConData.current_connection].timedelta_f) + s++; + if(seconds != NULL) + { + if(VConData.con[VConData.current_connection].timedelta_s < 0) + *seconds = s - (uint32)(-VConData.con[VConData.current_connection].timedelta_s); + else + *seconds = s + VConData.con[VConData.current_connection].timedelta_s; + } + if(fractions != NULL) + *fractions = f + VConData.con[VConData.current_connection].timedelta_f; +} + +void v_con_set_time(uint32 seconds, uint32 fractions) +{ + uint32 s, f; + v_n_get_current_time(&s, &f); + + if(f < fractions) + s--; + if (s < seconds) + VConData.con[VConData.current_connection].timedelta_s = -(int)(seconds - s); + else + VConData.con[VConData.current_connection].timedelta_s = (int)(s - seconds); + VConData.con[VConData.current_connection].timedelta_f = f - fractions; +} + +#endif diff --git a/extern/verse/dist/v_connection.h b/extern/verse/dist/v_connection.h new file mode 100644 index 00000000000..1d2ac53d597 --- /dev/null +++ b/extern/verse/dist/v_connection.h @@ -0,0 +1,73 @@ +/* +** +*/ + +#include "v_network.h" + +typedef struct{ + char name[16]; + char pass[16]; + uint8 key; + VNodeID avatar; +}VSConnectionID; + +typedef enum{ + V_CS_IDLE = 0, /* Host connection waiting for connection */ + V_CS_CONTACT = 1, /* client tryes to contact host */ + V_CS_CONTACTED = 2, /* Host replyes whit challange */ + V_CS_PENDING_ACCEPT = 3, /* Client sends login */ + V_CS_PENDING_HOST_CALLBACK = 4, /* Host got login waits for accept connect callback */ + V_CS_PENDING_CLIENT_CALLBACK_ACCEPT = 5, /* Host got login waits for accept connect callback */ + V_CS_PENDING_CLIENT_CALLBACK_TERMINATE = 6, /* Host got login waits for connect terminate callback */ + V_CS_PENDING_DECISION = 7, /* Host got has executed Callback waits for accept command */ + V_CS_CONNECTED = 8 /* Connection establiched */ +}VConnectStage; + +/* Connection related functions (v_connection.c) */ + +extern boolean v_con_network_listen(void); + +extern void v_con_set_name_pass(const char *name, const char *pass); +extern const char * v_con_get_name(void); +extern const char * v_con_get_pass(void); + +extern void v_con_set_avatar(uint32 avatar); +extern void v_con_set_time(uint32 seconds, uint32 fractions); + +extern void v_con_set_connect_stage(VConnectStage stage); +extern VConnectStage v_con_get_connect_stage(void); + + +extern uint8 *v_con_get_my_key(void); +extern uint8 *v_con_get_other_key(void); +extern uint8 *v_con_get_host_id(void); +extern uint8 **v_con_get_expected_key(void); + +extern void v_con_set_data_key(const uint8 *key); +extern const uint8 * v_con_get_data_key(void); + + +extern void * v_con_get_network_queue(void); +extern VNetworkAddress *v_con_get_network_address(void); +extern void * v_con_get_network_address_id(unsigned int id); +extern unsigned int * v_con_get_network_expected_packet(void); +extern void * v_con_get_ordered_storage(void); +extern void * v_con_get_func_storage(void); +extern void * v_con_connect(uint32 ip, uint16 port, VConnectStage stage); +extern unsigned int v_con_get_network_address_count(void); + +extern boolean v_co_switch_connection(uint32 ip, uint16 port); + +extern void v_con_inqueue_timer_update(void); + + +/* Func storage related functions (v_func_storage.c)*/ +extern void v_fs_unpack(uint8 *data, unsigned int length); + +extern boolean v_fs_func_accept_connections(void); +extern void v_fs_add_func(unsigned int cmd_id, unsigned int (*unpack_func)(const char *buf, size_t buffer_length), void *pack_func, void *alias_func); + +extern void * v_fs_get_alias_user_func(unsigned int cmd_id); +extern void * v_fs_get_alias_user_data(unsigned int cmd_id); +extern void * v_fs_get_user_func(unsigned int cmd_id); +extern void * v_fs_get_user_data(unsigned int cmd_id); diff --git a/extern/verse/dist/v_encryption.c b/extern/verse/dist/v_encryption.c new file mode 100644 index 00000000000..aea0f8e6979 --- /dev/null +++ b/extern/verse/dist/v_encryption.c @@ -0,0 +1,255 @@ +/* + * Verse encryption routines. Implements RSA encryption/decryption plus fast XORx. +*/ + +#if !defined(V_GENERATE_FUNC_MODE) + +#include +#include +#include + +#include "verse.h" +#include "v_pack.h" +#include "v_bignum.h" +#include "v_encryption.h" + +#define BITS V_ENCRYPTION_LOGIN_KEY_BITS /* Save some typing. */ + +extern void v_prime_set_random(VBigDig *x); +extern void v_prime_set_table(VBigDig *x, int i); + +const uint8 * v_e_data_create_key(void) /* possibly the worst key gen ever */ +{ + static unsigned int counter = 0; + static uint8 buffer[V_ENCRYPTION_DATA_KEY_SIZE]; + unsigned int i, temp; + + for(i = 0; i < V_ENCRYPTION_DATA_KEY_SIZE; i++) + { + counter++; + temp = (counter << 13) ^ counter; + temp = (temp * (temp * temp * 15731 + 789221) + 1376312589) & 0x7fffffff; + buffer[i] = temp; + } + /* FIXME: This really isn't very pretty. */ + buffer[0] &= 0x3f; /* Make sure top word is... Low. For RSA compatibility. */ + +/* memset(buffer, 0, sizeof buffer); + fprintf(stderr, "**WARNING: XOR data encryption disabled\n"); +*/ + return buffer; +} + +void v_e_data_encrypt_command(uint8 *packet, size_t packet_size, const uint8 *command, size_t command_size, const uint8 *key) +{ + uint32 pos, i; + + vnp_raw_unpack_uint32(packet, &pos); +/* printf("encrypting packet %u", pos);*/ + pos = key[pos % V_ENCRYPTION_DATA_KEY_SIZE] + packet_size; +/* printf(" -> pos=%u (size %u)", pos, packet_size); + printf(", key begins: ["); + for(i = 0; i < 16; i++) + printf(" %02X", key[(pos + i) % V_ENCRYPTION_DATA_KEY_SIZE]); + printf(" ]\n"); +*/ + for(i = 0; i < command_size; i++) + packet[packet_size + i] = command[i] ^ key[(i + pos) % V_ENCRYPTION_DATA_KEY_SIZE]; +} + +void v_e_data_decrypt_packet(uint8 *to, const uint8 *from, size_t size, const uint8 *key) +{ + uint32 pos, i; + + vnp_raw_unpack_uint32(from, &pos); +/* printf("decrypting packet %u", pos);*/ + pos = key[pos % V_ENCRYPTION_DATA_KEY_SIZE]; +/* printf(" -> pos=%u", pos); + printf(", key begins: ["); + for(i = 0; i < 16; i++) + printf(" %02X", key[(i + pos) % V_ENCRYPTION_DATA_KEY_SIZE]); + printf(" ]\n"); +*/ for(i = 0; i < 4; i++) + to[i] = from[i]; + for(i = 4; i < size; i++) + to[i] = from[i] ^ key[(i + pos) % V_ENCRYPTION_DATA_KEY_SIZE]; +} + +#endif + +/* From Knuth. Computes multiplicative inverse of u, modulo v. */ +void v_e_math_inv(VBigDig *inv, const VBigDig *u, const VBigDig *v) +{ + VBigDig VBIGNUM(u1, 2*BITS), VBIGNUM(u3, 2*BITS), VBIGNUM(v1, 2*BITS), VBIGNUM(v3, 2 *BITS), + VBIGNUM(t1, 2*BITS), VBIGNUM(t3, 2*BITS), VBIGNUM(q, 2*BITS), VBIGNUM(w, 2*BITS); + int iter = 1; + + v_bignum_set_one(u1); + v_bignum_set_bignum(u3, u); + v_bignum_set_zero(v1); + v_bignum_set_bignum(v3, v); + + while(!v_bignum_eq_zero(v3)) + { + v_bignum_set_bignum(q, u3); + v_bignum_div(q, v3, t3); + v_bignum_set_bignum(w, q); + v_bignum_mul(w, v1); + v_bignum_set_bignum(t1, u1); + v_bignum_add(t1, w); + + v_bignum_set_bignum(u1, v1); + v_bignum_set_bignum(v1, t1); + v_bignum_set_bignum(u3, v3); + v_bignum_set_bignum(v3, t3); + iter = -iter; + } + if(iter < 0) + { + v_bignum_set_bignum(inv, v); + v_bignum_sub(inv, u1); + } + else + v_bignum_set_bignum(inv, u1); +} + +void v_e_connect_create_key(uint8 *private_key, uint8 *public_key, uint8 *n) +{ + VBigDig VBIGNUM(p, BITS / 2), VBIGNUM(q, BITS / 2), VBIGNUM(qmo, BITS / 2), VBIGNUM(phi, BITS), + VBIGNUM(pub, BITS), VBIGNUM(priv, BITS), VBIGNUM(mod, BITS); + +#if !defined _WIN32 + /* FIXME: This is a security backdoor. Intent is simply to save time during testing. */ + if(getenv("VERSE_NORSA") != NULL) + { + printf("VERSE: Found the NORSA envvar, using constant keys\n"); + v_prime_set_table(p, 0); + v_prime_set_table(q, 1); + goto compute_phi; + } +#endif +/* printf("find prime p\n");*/ + v_prime_set_random(p); +/* printf("find prime q\n");*/ + v_prime_set_random(q); +compute_phi: +/* printf("done, computing key\n");*/ +/* printf("p="); + v_bignum_print_hex_lf(p); + printf("q="); + v_bignum_print_hex_lf(q); +*/ v_bignum_set_bignum(phi, p); + v_bignum_sub_digit(phi, 1); + v_bignum_set_bignum(qmo, q); + v_bignum_sub_digit(qmo, 1); + v_bignum_mul(phi, qmo); +/* printf("phi="); + v_bignum_print_hex_lf(phi); +*/ v_bignum_set_string_hex(pub, "0x10001"); + v_e_math_inv(priv, pub, phi); +/* printf(" pub="); + v_bignum_print_hex_lf(pub); + printf("priv="); + v_bignum_print_hex_lf(priv); +*/ + v_bignum_set_bignum(mod, p); + v_bignum_mul(mod, q); +/* printf(" mod="); + v_bignum_print_hex_lf(mod); + printf("key-creation finished\n"); +*/ /* Write out the keys. */ + v_bignum_raw_export(pub, public_key); + v_bignum_raw_export(priv, private_key); + v_bignum_raw_export(mod, n); +} + +void v_e_connect_encrypt(uint8 *output, const uint8 *data, const uint8 *key, const uint8 *key_n) +{ + VBigDig VBIGNUM(packet, BITS), VBIGNUM(expo, BITS), VBIGNUM(mod, BITS); + + v_bignum_raw_import(packet, data); + v_bignum_raw_import(expo, key); + v_bignum_raw_import(mod, key_n); + + /* Verify that data is less than the modulo, this is a prerequisite for encryption. */ + if(!v_bignum_gte(mod, packet)) + { + printf("*** WARNING. Data is not less than modulo, as it should be--encryption will break!\n"); + printf(" RSA modulo: "); + v_bignum_print_hex_lf(mod); + printf(" RSA data: "); + v_bignum_print_hex_lf(packet); + } +/* printf("RSA key: "); + v_bignum_print_hex_lf(expo); + printf("RSA mod: "); + v_bignum_print_hex_lf(mod); + printf("RSA in: "); + v_bignum_print_hex_lf(packet); + printf("bits in packet: %d, ", v_bignum_bit_msb(packet) + 1); + printf("bits in modulo: %d\n", v_bignum_bit_msb(mod) + 1); +*/ v_bignum_pow_mod(packet, expo, mod); /* Blam. */ +/* printf("RSA out: "); + v_bignum_print_hex_lf(packet); +*/ v_bignum_raw_export(packet, output); +} + +#if defined CRYPTALONE +void v_encrypt_test(void) +{ + uint8 k_priv[BITS / 8], k_pub[BITS / 8], k_n[BITS / 8], cipher[BITS / 8], plain[BITS / 8], decode[BITS / 8], i; + + printf("testing RSA-crypto\n"); + v_e_connect_create_key(k_pub, k_priv, k_n); +/* exit(0);*/ + printf("key pair generated, encrypting something\n"); + memset(plain, 0, sizeof plain); + strcpy(plain, "This is some text to encrypt, to give it something to chew on."); + printf("plain: %02X (%u)\n", plain[0], strlen(plain)); + v_e_connect_encrypt(cipher, plain, k_pub, k_n); + printf("plain: %02X, cipher: %02X\n", plain[0], cipher[0]); + v_e_connect_encrypt(decode, cipher, k_priv, k_n); + printf("decoded: %02X: '", decode[0]); + for(i = 0; decode[i] != 0; i++) + putchar(decode[i]); + printf("'\n"); +/* printf("\npublic key: "); + v_bignum_print_hex_lf(k_public); + printf("private key: "); + v_bignum_print_hex_lf(k_private); + v_bignum_set_string(msg, "123"); + gettimeofday(&t1, NULL); + v_bignum_pow_mod(msg, k_private, k_n); + gettimeofday(&t2, NULL); + printf("encrypted: "); + v_bignum_print_hex_lf(msg); + printf("encrypted %u bits in %g s\n", BITS, t2.tv_sec - t1.tv_sec + 1.0E-6 * (t2.tv_usec - t1.tv_usec)); + + gettimeofday(&t1, NULL); + v_bignum_pow_mod(msg, k_public, k_n); + gettimeofday(&t2, NULL); + printf("decrypted: "); + v_bignum_print_hex_lf(msg); + printf("decrypted %u bits in %g s\n", BITS, t2.tv_sec - t1.tv_sec + 1.0E-6 * (t2.tv_usec - t1.tv_usec)); + exit(0); +*//* v_e_encrypt(cipher, plain, &k_private, &k_n); + printf("encrypted data: "); + for(i = 0; i < sizeof cipher; i++) + printf("%c", isalnum(cipher[i]) ? cipher[i] : '?'); + printf("\n\n"); + printf("decrypting\n"); + v_e_encrypt(decode, cipher, &k_public, &k_n); + printf("decrypted data: "); + for(i = 0; i < sizeof cipher; i++) + printf("%c", isalnum(decode[i]) ? decode[i] : '?'); + printf("\n\n"); +*/ +} + +int main(void) +{ + v_encrypt_test(); + + return 0; +} +#endif diff --git a/extern/verse/dist/v_encryption.h b/extern/verse/dist/v_encryption.h new file mode 100644 index 00000000000..cbfb5ff692f --- /dev/null +++ b/extern/verse/dist/v_encryption.h @@ -0,0 +1,32 @@ +/* + * Verse encryption routines. There are two distinct flavors of encryption + * in use: one "heavy" for login/connection establishment security, and + * a far lighter symmetrical one that is applied to each data packet after + * the key has been exchanged during connection. +*/ + +#include "verse.h" + +/* Internal key size definitions. *MUST* be kept in sync with V_HOST_ID_SIZE in verse_header.h! */ +#define V_ENCRYPTION_LOGIN_KEY_BITS 512 +#define V_ENCRYPTION_LOGIN_KEY_SIZE (V_ENCRYPTION_LOGIN_KEY_BITS / 8) +#define V_ENCRYPTION_LOGIN_KEY_FULL_SIZE (3 * V_ENCRYPTION_LOGIN_KEY_SIZE) +#define V_ENCRYPTION_LOGIN_KEY_HALF_SIZE (2 * V_ENCRYPTION_LOGIN_KEY_SIZE) + +#define V_ENCRYPTION_LOGIN_PUBLIC_START (0 * V_ENCRYPTION_LOGIN_KEY_SIZE) +#define V_ENCRYPTION_LOGIN_PRIVATE_START (1 * V_ENCRYPTION_LOGIN_KEY_SIZE) +#define V_ENCRYPTION_LOGIN_N_START (2 * V_ENCRYPTION_LOGIN_KEY_SIZE) + +#define V_ENCRYPTION_DATA_KEY_SIZE (V_ENCRYPTION_LOGIN_KEY_BITS / 8) + +/* Connection encryption. Heavy, and symmetrical, so encrypt() does both encryption + * and decryption given the proper key. Current algorithm used is RSA. +*/ +extern void v_e_connect_create_key(uint8 *private_key, uint8 *public_key, uint8 *n); +extern void v_e_connect_encrypt(uint8 *output, const uint8 *data, const uint8 *key, const uint8 *key_n); + +/* Actual data traffic encryption. Also symmetrical, with a single key. Uses XOR. */ +extern const uint8 * v_e_data_create_key(void); +extern void v_e_data_encrypt_command(uint8 *packet, size_t packet_length, + const uint8 *command, size_t command_length, const uint8 *key); +extern void v_e_data_decrypt_packet(uint8 *to, const uint8 *from, size_t size, const uint8 *key); diff --git a/extern/verse/dist/v_func_storage.c b/extern/verse/dist/v_func_storage.c new file mode 100644 index 00000000000..86c7815c2af --- /dev/null +++ b/extern/verse/dist/v_func_storage.c @@ -0,0 +1,194 @@ +/* + * +*/ + +#include +#include +#include "verse_header.h" +#include "v_pack.h" +#include "v_cmd_gen.h" +#include "v_connection.h" +#if !defined(V_GENERATE_FUNC_MODE) +#include "verse.h" +#include "v_cmd_buf.h" +#include "v_network_out_que.h" + +#define V_FS_MAX_CMDS 256 + +extern void init_pack_and_unpack(void); + +static struct { + unsigned int (*unpack_func[V_FS_MAX_CMDS])(const char *data, size_t length); + void *pack_func[V_FS_MAX_CMDS]; + void *user_func[V_FS_MAX_CMDS]; + void *user_data[V_FS_MAX_CMDS]; + void *alias_pack_func[V_FS_MAX_CMDS]; + void *alias_user_func[V_FS_MAX_CMDS]; + void *alias_user_data[V_FS_MAX_CMDS]; + boolean call; +} VCmdData; + +static boolean v_fs_initialized = FALSE; + +extern void verse_send_packet_ack(uint32 packet_id); +extern void callback_send_packet_ack(void *user, uint32 packet_id); +extern void verse_send_packet_nak(uint32 packet_id); +extern void callback_send_packet_nak(void *user, uint32 packet_id); + +void v_fs_init(void) +{ + unsigned int i; + if(v_fs_initialized) + return; + for(i = 0; i < V_FS_MAX_CMDS; i++) + { + VCmdData.unpack_func[i] = NULL; + VCmdData.pack_func[i] = NULL; + VCmdData.user_func[i] = NULL; + VCmdData.user_data[i] = NULL; + VCmdData.alias_pack_func[i] = NULL; + VCmdData.alias_user_func[i] = NULL; + VCmdData.alias_user_data[i] = NULL; + } + #if !defined(V_GENERATE_FUNC_MODE) + init_pack_and_unpack(); + #endif + for(i = 0; i < V_FS_MAX_CMDS && VCmdData.pack_func[i] != verse_send_packet_ack; i++); + VCmdData.user_func[i] = callback_send_packet_ack; + for(i = 0; i < V_FS_MAX_CMDS && VCmdData.pack_func[i] != verse_send_packet_nak; i++); + VCmdData.user_func[i] = callback_send_packet_nak; + + v_fs_initialized = TRUE; +} + + +void v_fs_add_func(unsigned int cmd_id, unsigned int (*unpack_func)(const char *data, size_t length), void *pack_func, void *alias_func) +{ + VCmdData.unpack_func[cmd_id] = unpack_func; + VCmdData.pack_func[cmd_id] = pack_func; + VCmdData.alias_pack_func[cmd_id] = alias_func; +} + +void *v_fs_get_user_func(unsigned int cmd_id) +{ +/* if(VCmdData.call)*/ + return VCmdData.user_func[cmd_id]; + return NULL; +} + +void *v_fs_get_user_data(unsigned int cmd_id) +{ + return VCmdData.user_data[cmd_id]; +} + +void *v_fs_get_alias_user_func(unsigned int cmd_id) +{ +/* if(VCmdData.call)*/ + return VCmdData.alias_user_func[cmd_id]; + return NULL; +} + +void *v_fs_get_alias_user_data(unsigned int cmd_id) +{ + return VCmdData.alias_user_data[cmd_id]; +} + +void verse_callback_set(void *command, void *callback, void *user) +{ + unsigned int i; + if(!v_fs_initialized) + v_fs_init(); + + for(i = 0; i < V_FS_MAX_CMDS; i++) + { + if(VCmdData.pack_func[i] == command) + { + VCmdData.user_data[i] = user; + VCmdData.user_func[i] = callback; + return; + } + if(VCmdData.alias_pack_func[i] == command) + { + VCmdData.alias_user_data[i] = user; + VCmdData.alias_user_func[i] = callback; + return; + } + } +} + +/* Do we accept incoming connections, i.e. are we a host implementation? */ +boolean v_fs_func_accept_connections(void) +{ + return VCmdData.user_func[0] != NULL; +} + +/* Inspect beginning of packet, looking for ACK or NAK commands. */ +void v_fs_unpack_beginning(const uint8 *data, unsigned int length) +{ + uint32 id, i = 4; + uint8 cmd_id; + + i += vnp_raw_unpack_uint8(&data[i], &cmd_id); + while(i < length && (cmd_id == 7 || cmd_id == 8)) + { + i += vnp_raw_unpack_uint32(&data[i], &id); + if(cmd_id == 7) + callback_send_packet_ack(NULL, id); + else + callback_send_packet_nak(NULL, id); + i += vnp_raw_unpack_uint8(&data[i], &cmd_id); + } +} + +void v_fs_unpack(uint8 *data, unsigned int length) +{ + uint32 i, output, pack_id; + uint8 cmd_id, last = 255; + + i = vnp_raw_unpack_uint32(data, &pack_id); /* each packet starts with a 32 bit id */ + vnp_raw_unpack_uint8(&data[i], &cmd_id); + while(i < length && (cmd_id == 7 || cmd_id == 8)) + { + i += 5; + vnp_raw_unpack_uint8(&data[i], &cmd_id); + } + while(i < length) + { + i += vnp_raw_unpack_uint8(&data[i], &cmd_id); + if(VCmdData.unpack_func[cmd_id] != NULL) + { + VCmdData.call = TRUE; + output = VCmdData.unpack_func[cmd_id](&data[i], length - i); + if(output == (unsigned int) -1) /* Can this happen? Should be size_t or int, depending. */ + { + printf("** Aborting decode, command %u unpacker returned failure\n", cmd_id); +/* verse_send_packet_nak(pack_id);*/ + return; + } + last = cmd_id; + i += output; + } + else /* If unknown command byte was found, complain loudly and stop parsing packet. */ + { + size_t j; + + printf("\n** Unknown command ID %u (0x%02X) encountered--aborting packet decode len=%u pos=%u last=%u\n", cmd_id, cmd_id, length, i, last); + printf(" decoded %u bytes: ", --i); + for(j = 0; j < i; j++) + printf("%02X ", data[j]); + printf("\n (packet id=%u)", pack_id); + printf(" remaining %u bytes: ", length - i); + for(j = i; j < length; j++) + printf("%02X ", data[j]); + printf("\n"); +/* *(char *) 0 = 0;*/ + break; + } + } +/* if(expected != NULL) + verse_send_packet_ack(pack_id);*/ +} + +extern unsigned int v_unpack_connection(const char *data, size_t length); + +#endif diff --git a/extern/verse/dist/v_gen_pack_a_node.c b/extern/verse/dist/v_gen_pack_a_node.c new file mode 100644 index 00000000000..dc8e53e1a7f --- /dev/null +++ b/extern/verse/dist/v_gen_pack_a_node.c @@ -0,0 +1,521 @@ +/* +** This is automatically generated source code -- do not edit. +** Changes are affected either by editing the corresponding protocol +** definition file (v_cmd_def_X.c where X=node type), or by editing +** the code generator itself, in v_cmd_gen.c. +*/ + +#include +#include + +#include "v_cmd_gen.h" +#if !defined(V_GENERATE_FUNC_MODE) +#include "verse.h" +#include "v_cmd_buf.h" +#include "v_network_out_que.h" +#include "v_network.h" +#include "v_connection.h" +#include "v_util.h" + +void verse_send_a_buffer_create(VNodeID node_id, VBufferID buffer_id, const char *name, VNABlockType type, real64 frequency) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_80);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 160); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_a_buffer_create(node_id = %u buffer_id = %u name = %s type = %u frequency = %f );\n", node_id, buffer_id, name, type, frequency); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], buffer_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], name, 16); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)type); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], frequency); + if(node_id == (uint32) ~0u || buffer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_a_buffer_destroy(VNodeID node_id, VBufferID buffer_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_80);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 160); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_a_buffer_destroy(node_id = %u buffer_id = %u );\n", node_id, buffer_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], buffer_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)-1); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], V_REAL64_MAX); + if(node_id == (uint32) ~0u || buffer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_a_buffer_create(const char *buf, size_t buffer_length) +{ + uint8 enum_temp; + unsigned int buffer_pos = 0; + void (* func_a_buffer_create)(void *user_data, VNodeID node_id, VBufferID buffer_id, const char *name, VNABlockType type, real64 frequency); + VNodeID node_id; + VBufferID buffer_id; + char name[16]; + VNABlockType type; + real64 frequency; + + func_a_buffer_create = v_fs_get_user_func(160); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &buffer_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], name, 16, buffer_length - buffer_pos); + if(buffer_length < 9 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp); + type = (VNABlockType)enum_temp; + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frequency); +#if defined V_PRINT_RECEIVE_COMMANDS + if(name[0] == 0) + printf("receive: verse_send_a_buffer_destroy(node_id = %u buffer_id = %u ); callback = %p\n", node_id, buffer_id, v_fs_get_alias_user_func(160)); + else + printf("receive: verse_send_a_buffer_create(node_id = %u buffer_id = %u name = %s type = %u frequency = %f ); callback = %p\n", node_id, buffer_id, name, type, frequency, v_fs_get_user_func(160)); +#endif + if(name[0] == 0) + { + void (* alias_a_buffer_destroy)(void *user_data, VNodeID node_id, VBufferID buffer_id); + alias_a_buffer_destroy = v_fs_get_alias_user_func(160); + if(alias_a_buffer_destroy != NULL) + alias_a_buffer_destroy(v_fs_get_alias_user_data(160), node_id, buffer_id); + return buffer_pos; + } + if(func_a_buffer_create != NULL) + func_a_buffer_create(v_fs_get_user_data(160), node_id, buffer_id, name, (VNABlockType) type, frequency); + + return buffer_pos; +} + +void verse_send_a_buffer_subscribe(VNodeID node_id, VBufferID layer_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 161); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_a_buffer_subscribe(node_id = %u layer_id = %u );\n", node_id, layer_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], TRUE); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_a_buffer_unsubscribe(VNodeID node_id, VBufferID layer_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 161); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_a_buffer_unsubscribe(node_id = %u layer_id = %u );\n", node_id, layer_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], FALSE); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_a_buffer_subscribe(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_a_buffer_subscribe)(void *user_data, VNodeID node_id, VBufferID layer_id); + VNodeID node_id; + VBufferID layer_id; + uint8 alias_bool; + + func_a_buffer_subscribe = v_fs_get_user_func(161); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + if(buffer_length < buffer_pos + 1) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &alias_bool); +#if defined V_PRINT_RECEIVE_COMMANDS + if(!alias_bool) + printf("receive: verse_send_a_buffer_unsubscribe(node_id = %u layer_id = %u ); callback = %p\n", node_id, layer_id, v_fs_get_alias_user_func(161)); + else + printf("receive: verse_send_a_buffer_subscribe(node_id = %u layer_id = %u ); callback = %p\n", node_id, layer_id, v_fs_get_user_func(161)); +#endif + if(!alias_bool) + { + void (* alias_a_buffer_unsubscribe)(void *user_data, VNodeID node_id, VBufferID layer_id); + alias_a_buffer_unsubscribe = v_fs_get_alias_user_func(161); + if(alias_a_buffer_unsubscribe != NULL) + alias_a_buffer_unsubscribe(v_fs_get_alias_user_data(161), node_id, layer_id); + return buffer_pos; + } + if(func_a_buffer_subscribe != NULL) + func_a_buffer_subscribe(v_fs_get_user_data(161), node_id, layer_id); + + return buffer_pos; +} + +void verse_send_a_block_set(VNodeID node_id, VLayerID buffer_id, uint32 block_index, VNABlockType type, const VNABlock *samples) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 162); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_a_block_set(node_id = %u buffer_id = %u block_index = %u type = %u samples = %p );\n", node_id, buffer_id, block_index, type, samples); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], buffer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], block_index); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)type); + buffer_pos += vnp_pack_audio_block(&buf[buffer_pos], type, samples); + if(node_id == (uint32) ~0u || buffer_id == (uint16) ~0u || block_index == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_a_block_clear(VNodeID node_id, VLayerID buffer_id, uint32 block_index) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 162); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_a_block_clear(node_id = %u buffer_id = %u block_index = %u );\n", node_id, buffer_id, block_index); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], buffer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], block_index); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)-1); + if(node_id == (uint32) ~0u || buffer_id == (uint16) ~0u || block_index == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_a_block_set(const char *buf, size_t buffer_length) +{ + uint8 enum_temp; + unsigned int buffer_pos = 0; + void (* func_a_block_set)(void *user_data, VNodeID node_id, VLayerID buffer_id, uint32 block_index, VNABlockType type, const VNABlock *samples); + VNodeID node_id; + VLayerID buffer_id; + uint32 block_index; + VNABlockType type; + const VNABlock *samples; + + func_a_block_set = v_fs_get_user_func(162); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &buffer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &block_index); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp); + type = (VNABlockType)enum_temp; +#if defined V_PRINT_RECEIVE_COMMANDS + if(type > VN_A_BLOCK_REAL64) + printf("receive: verse_send_a_block_clear(node_id = %u buffer_id = %u block_index = %u ); callback = %p\n", node_id, buffer_id, block_index, v_fs_get_alias_user_func(162)); + else + printf("receive: verse_send_a_block_set(node_id = %u buffer_id = %u block_index = %u type = %u ); callback = %p\n", node_id, buffer_id, block_index, type, v_fs_get_user_func(162)); +#endif + if(type <= VN_A_BLOCK_REAL64) + { + VNABlock block; + buffer_pos += vnp_unpack_audio_block(&buf[buffer_pos], type, &block); + if(func_a_block_set != NULL) + func_a_block_set(v_fs_get_user_data(162), node_id, buffer_id, block_index, (VNABlockType) type, &block); + return buffer_pos; + } + + if(type > VN_A_BLOCK_REAL64) + { + void (* alias_a_block_clear)(void *user_data, VNodeID node_id, VLayerID buffer_id, uint32 block_index); + alias_a_block_clear = v_fs_get_alias_user_func(162); + if(alias_a_block_clear != NULL) + alias_a_block_clear(v_fs_get_alias_user_data(162), node_id, buffer_id, block_index); + return buffer_pos; + } + if(func_a_block_set != NULL) + func_a_block_set(v_fs_get_user_data(162), node_id, buffer_id, block_index, (VNABlockType) type, samples); + + return buffer_pos; +} + +void verse_send_a_stream_create(VNodeID node_id, VLayerID stream_id, const char *name) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 163); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_a_stream_create(node_id = %u stream_id = %u name = %s );\n", node_id, stream_id, name); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], stream_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], name, 16); + if(node_id == (uint32) ~0u || stream_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_a_stream_destroy(VNodeID node_id, VLayerID stream_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 163); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_a_stream_destroy(node_id = %u stream_id = %u );\n", node_id, stream_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], stream_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + if(node_id == (uint32) ~0u || stream_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_a_stream_create(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_a_stream_create)(void *user_data, VNodeID node_id, VLayerID stream_id, const char *name); + VNodeID node_id; + VLayerID stream_id; + char name[16]; + + func_a_stream_create = v_fs_get_user_func(163); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &stream_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], name, 16, buffer_length - buffer_pos); +#if defined V_PRINT_RECEIVE_COMMANDS + if(name[0] == 0) + printf("receive: verse_send_a_stream_destroy(node_id = %u stream_id = %u ); callback = %p\n", node_id, stream_id, v_fs_get_alias_user_func(163)); + else + printf("receive: verse_send_a_stream_create(node_id = %u stream_id = %u name = %s ); callback = %p\n", node_id, stream_id, name, v_fs_get_user_func(163)); +#endif + if(name[0] == 0) + { + void (* alias_a_stream_destroy)(void *user_data, VNodeID node_id, VLayerID stream_id); + alias_a_stream_destroy = v_fs_get_alias_user_func(163); + if(alias_a_stream_destroy != NULL) + alias_a_stream_destroy(v_fs_get_alias_user_data(163), node_id, stream_id); + return buffer_pos; + } + if(func_a_stream_create != NULL) + func_a_stream_create(v_fs_get_user_data(163), node_id, stream_id, name); + + return buffer_pos; +} + +void verse_send_a_stream_subscribe(VNodeID node_id, VLayerID stream_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 164); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_a_stream_subscribe(node_id = %u stream_id = %u );\n", node_id, stream_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], stream_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], TRUE); + if(node_id == (uint32) ~0u || stream_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_a_stream_unsubscribe(VNodeID node_id, VLayerID stream_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 164); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_a_stream_unsubscribe(node_id = %u stream_id = %u );\n", node_id, stream_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], stream_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], FALSE); + if(node_id == (uint32) ~0u || stream_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_a_stream_subscribe(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_a_stream_subscribe)(void *user_data, VNodeID node_id, VLayerID stream_id); + VNodeID node_id; + VLayerID stream_id; + uint8 alias_bool; + + func_a_stream_subscribe = v_fs_get_user_func(164); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &stream_id); + if(buffer_length < buffer_pos + 1) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &alias_bool); +#if defined V_PRINT_RECEIVE_COMMANDS + if(!alias_bool) + printf("receive: verse_send_a_stream_unsubscribe(node_id = %u stream_id = %u ); callback = %p\n", node_id, stream_id, v_fs_get_alias_user_func(164)); + else + printf("receive: verse_send_a_stream_subscribe(node_id = %u stream_id = %u ); callback = %p\n", node_id, stream_id, v_fs_get_user_func(164)); +#endif + if(!alias_bool) + { + void (* alias_a_stream_unsubscribe)(void *user_data, VNodeID node_id, VLayerID stream_id); + alias_a_stream_unsubscribe = v_fs_get_alias_user_func(164); + if(alias_a_stream_unsubscribe != NULL) + alias_a_stream_unsubscribe(v_fs_get_alias_user_data(164), node_id, stream_id); + return buffer_pos; + } + if(func_a_stream_subscribe != NULL) + func_a_stream_subscribe(v_fs_get_user_data(164), node_id, stream_id); + + return buffer_pos; +} + +void verse_send_a_stream(VNodeID node_id, VLayerID stream_id, uint32 time_s, uint32 time_f, VNABlockType type, real64 frequency, const VNABlock *samples) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 165); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_a_stream(node_id = %u stream_id = %u time_s = %u time_f = %u type = %u frequency = %f samples = %p );\n", node_id, stream_id, time_s, time_f, type, frequency, samples); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], stream_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], time_s); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], time_f); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)type); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], frequency); + buffer_pos += vnp_pack_audio_block(&buf[buffer_pos], type, samples); + if(node_id == (uint32) ~0u || stream_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_a_stream(const char *buf, size_t buffer_length) +{ + uint8 enum_temp; + unsigned int buffer_pos = 0; + void (* func_a_stream)(void *user_data, VNodeID node_id, VLayerID stream_id, uint32 time_s, uint32 time_f, VNABlockType type, real64 frequency, const VNABlock *samples); + VNodeID node_id; + VLayerID stream_id; + uint32 time_s; + uint32 time_f; + VNABlockType type; + real64 frequency; + const VNABlock *samples; + + func_a_stream = v_fs_get_user_func(165); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &stream_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &time_s); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &time_f); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp); + type = (VNABlockType)enum_temp; + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frequency); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_a_stream(node_id = %u stream_id = %u time_s = %u time_f = %u type = %u frequency = %f ); callback = %p\n", node_id, stream_id, time_s, time_f, type, frequency, v_fs_get_user_func(165)); +#endif + { + VNABlock block; + buffer_pos += vnp_unpack_audio_block(&buf[buffer_pos], type, &block); + if(func_a_stream != NULL) + func_a_stream(v_fs_get_user_data(165), node_id, stream_id, time_s, time_f, (VNABlockType) type, frequency, &block); + return buffer_pos; + } + + if(func_a_stream != NULL) + func_a_stream(v_fs_get_user_data(165), node_id, stream_id, time_s, time_f, (VNABlockType) type, frequency, samples); + + return buffer_pos; +} + +#endif + diff --git a/extern/verse/dist/v_gen_pack_b_node.c b/extern/verse/dist/v_gen_pack_b_node.c new file mode 100644 index 00000000000..a4792a10fe4 --- /dev/null +++ b/extern/verse/dist/v_gen_pack_b_node.c @@ -0,0 +1,238 @@ +/* +** This is automatically generated source code -- do not edit. +** Changes are affected either by editing the corresponding protocol +** definition file (v_cmd_def_X.c where X=node type), or by editing +** the code generator itself, in v_cmd_gen.c. +*/ + +#include +#include + +#include "v_cmd_gen.h" +#if !defined(V_GENERATE_FUNC_MODE) +#include "verse.h" +#include "v_cmd_buf.h" +#include "v_network_out_que.h" +#include "v_network.h" +#include "v_connection.h" +#include "v_util.h" + +void verse_send_b_dimensions_set(VNodeID node_id, uint16 width, uint16 height, uint16 depth) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_20);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 80); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_b_dimensions_set(node_id = %u width = %u height = %u depth = %u );\n", node_id, width, height, depth); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], width); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], height); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], depth); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_b_dimensions_set(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_b_dimensions_set)(void *user_data, VNodeID node_id, uint16 width, uint16 height, uint16 depth); + VNodeID node_id; + uint16 width; + uint16 height; + uint16 depth; + + func_b_dimensions_set = v_fs_get_user_func(80); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &width); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &height); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &depth); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_b_dimensions_set(node_id = %u width = %u height = %u depth = %u ); callback = %p\n", node_id, width, height, depth, v_fs_get_user_func(80)); +#endif + if(func_b_dimensions_set != NULL) + func_b_dimensions_set(v_fs_get_user_data(80), node_id, width, height, depth); + + return buffer_pos; +} + +void verse_send_b_layer_create(VNodeID node_id, VLayerID layer_id, const char *name, VNBLayerType type) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 81); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_b_layer_create(node_id = %u layer_id = %u name = %s type = %u );\n", node_id, layer_id, name, type); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], name, 16); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)type); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_b_layer_destroy(VNodeID node_id, VLayerID layer_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 81); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_b_layer_destroy(node_id = %u layer_id = %u );\n", node_id, layer_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)-1); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_b_layer_create(const char *buf, size_t buffer_length) +{ + uint8 enum_temp; + unsigned int buffer_pos = 0; + void (* func_b_layer_create)(void *user_data, VNodeID node_id, VLayerID layer_id, const char *name, VNBLayerType type); + VNodeID node_id; + VLayerID layer_id; + char name[16]; + VNBLayerType type; + + func_b_layer_create = v_fs_get_user_func(81); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], name, 16, buffer_length - buffer_pos); + if(buffer_length < 1 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp); + type = (VNBLayerType)enum_temp; +#if defined V_PRINT_RECEIVE_COMMANDS + if(name[0] == 0) + printf("receive: verse_send_b_layer_destroy(node_id = %u layer_id = %u ); callback = %p\n", node_id, layer_id, v_fs_get_alias_user_func(81)); + else + printf("receive: verse_send_b_layer_create(node_id = %u layer_id = %u name = %s type = %u ); callback = %p\n", node_id, layer_id, name, type, v_fs_get_user_func(81)); +#endif + if(name[0] == 0) + { + void (* alias_b_layer_destroy)(void *user_data, VNodeID node_id, VLayerID layer_id); + alias_b_layer_destroy = v_fs_get_alias_user_func(81); + if(alias_b_layer_destroy != NULL) + alias_b_layer_destroy(v_fs_get_alias_user_data(81), node_id, layer_id); + return buffer_pos; + } + if(func_b_layer_create != NULL) + func_b_layer_create(v_fs_get_user_data(81), node_id, layer_id, name, (VNBLayerType) type); + + return buffer_pos; +} + +void verse_send_b_layer_subscribe(VNodeID node_id, VLayerID layer_id, uint8 level) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 82); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_b_layer_subscribe(node_id = %u layer_id = %u level = %u );\n", node_id, layer_id, level); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], level); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_b_layer_unsubscribe(VNodeID node_id, VLayerID layer_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 82); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_b_layer_unsubscribe(node_id = %u layer_id = %u );\n", node_id, layer_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], -1); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_b_layer_subscribe(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_b_layer_subscribe)(void *user_data, VNodeID node_id, VLayerID layer_id, uint8 level); + VNodeID node_id; + VLayerID layer_id; + uint8 level; + + func_b_layer_subscribe = v_fs_get_user_func(82); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &level); +#if defined V_PRINT_RECEIVE_COMMANDS + if(level == 255) + printf("receive: verse_send_b_layer_unsubscribe(node_id = %u layer_id = %u ); callback = %p\n", node_id, layer_id, v_fs_get_alias_user_func(82)); + else + printf("receive: verse_send_b_layer_subscribe(node_id = %u layer_id = %u level = %u ); callback = %p\n", node_id, layer_id, level, v_fs_get_user_func(82)); +#endif + if(level == 255) + { + void (* alias_b_layer_unsubscribe)(void *user_data, VNodeID node_id, VLayerID layer_id); + alias_b_layer_unsubscribe = v_fs_get_alias_user_func(82); + if(alias_b_layer_unsubscribe != NULL) + alias_b_layer_unsubscribe(v_fs_get_alias_user_data(82), node_id, layer_id); + return buffer_pos; + } + if(func_b_layer_subscribe != NULL) + func_b_layer_subscribe(v_fs_get_user_data(82), node_id, layer_id, level); + + return buffer_pos; +} + +#endif + diff --git a/extern/verse/dist/v_gen_pack_c_node.c b/extern/verse/dist/v_gen_pack_c_node.c new file mode 100644 index 00000000000..b75fa213383 --- /dev/null +++ b/extern/verse/dist/v_gen_pack_c_node.c @@ -0,0 +1,189 @@ +/* +** This is automatically generated source code -- do not edit. +** Changes are affected either by editing the corresponding protocol +** definition file (v_cmd_def_X.c where X=node type), or by editing +** the code generator itself, in v_cmd_gen.c. +*/ + +#include +#include + +#include "v_cmd_gen.h" +#if !defined(V_GENERATE_FUNC_MODE) +#include "verse.h" +#include "v_cmd_buf.h" +#include "v_network_out_que.h" +#include "v_network.h" +#include "v_connection.h" +#include "v_util.h" + +void verse_send_c_curve_create(VNodeID node_id, VLayerID curve_id, const char *name, uint8 dimensions) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 128); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_c_curve_create(node_id = %u curve_id = %u name = %s dimensions = %u );\n", node_id, curve_id, name, dimensions); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], curve_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], name, 16); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], dimensions); + if(node_id == (uint32) ~0u || curve_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_c_curve_destroy(VNodeID node_id, VLayerID curve_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 128); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_c_curve_destroy(node_id = %u curve_id = %u );\n", node_id, curve_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], curve_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], -1); + if(node_id == (uint32) ~0u || curve_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_c_curve_create(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_c_curve_create)(void *user_data, VNodeID node_id, VLayerID curve_id, const char *name, uint8 dimensions); + VNodeID node_id; + VLayerID curve_id; + char name[16]; + uint8 dimensions; + + func_c_curve_create = v_fs_get_user_func(128); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &curve_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], name, 16, buffer_length - buffer_pos); + if(buffer_length < 1 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &dimensions); +#if defined V_PRINT_RECEIVE_COMMANDS + if(name[0] == 0) + printf("receive: verse_send_c_curve_destroy(node_id = %u curve_id = %u ); callback = %p\n", node_id, curve_id, v_fs_get_alias_user_func(128)); + else + printf("receive: verse_send_c_curve_create(node_id = %u curve_id = %u name = %s dimensions = %u ); callback = %p\n", node_id, curve_id, name, dimensions, v_fs_get_user_func(128)); +#endif + if(name[0] == 0) + { + void (* alias_c_curve_destroy)(void *user_data, VNodeID node_id, VLayerID curve_id); + alias_c_curve_destroy = v_fs_get_alias_user_func(128); + if(alias_c_curve_destroy != NULL) + alias_c_curve_destroy(v_fs_get_alias_user_data(128), node_id, curve_id); + return buffer_pos; + } + if(func_c_curve_create != NULL) + func_c_curve_create(v_fs_get_user_data(128), node_id, curve_id, name, dimensions); + + return buffer_pos; +} + +void verse_send_c_curve_subscribe(VNodeID node_id, VLayerID curve_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 129); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_c_curve_subscribe(node_id = %u curve_id = %u );\n", node_id, curve_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], curve_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], TRUE); + if(node_id == (uint32) ~0u || curve_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_c_curve_unsubscribe(VNodeID node_id, VLayerID curve_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 129); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_c_curve_unsubscribe(node_id = %u curve_id = %u );\n", node_id, curve_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], curve_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], FALSE); + if(node_id == (uint32) ~0u || curve_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_c_curve_subscribe(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_c_curve_subscribe)(void *user_data, VNodeID node_id, VLayerID curve_id); + VNodeID node_id; + VLayerID curve_id; + uint8 alias_bool; + + func_c_curve_subscribe = v_fs_get_user_func(129); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &curve_id); + if(buffer_length < buffer_pos + 1) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &alias_bool); +#if defined V_PRINT_RECEIVE_COMMANDS + if(!alias_bool) + printf("receive: verse_send_c_curve_unsubscribe(node_id = %u curve_id = %u ); callback = %p\n", node_id, curve_id, v_fs_get_alias_user_func(129)); + else + printf("receive: verse_send_c_curve_subscribe(node_id = %u curve_id = %u ); callback = %p\n", node_id, curve_id, v_fs_get_user_func(129)); +#endif + if(!alias_bool) + { + void (* alias_c_curve_unsubscribe)(void *user_data, VNodeID node_id, VLayerID curve_id); + alias_c_curve_unsubscribe = v_fs_get_alias_user_func(129); + if(alias_c_curve_unsubscribe != NULL) + alias_c_curve_unsubscribe(v_fs_get_alias_user_data(129), node_id, curve_id); + return buffer_pos; + } + if(func_c_curve_subscribe != NULL) + func_c_curve_subscribe(v_fs_get_user_data(129), node_id, curve_id); + + return buffer_pos; +} + +#endif + diff --git a/extern/verse/dist/v_gen_pack_g_node.c b/extern/verse/dist/v_gen_pack_g_node.c new file mode 100644 index 00000000000..5a70173554d --- /dev/null +++ b/extern/verse/dist/v_gen_pack_g_node.c @@ -0,0 +1,1154 @@ +/* +** This is automatically generated source code -- do not edit. +** Changes are affected either by editing the corresponding protocol +** definition file (v_cmd_def_X.c where X=node type), or by editing +** the code generator itself, in v_cmd_gen.c. +*/ + +#include +#include + +#include "v_cmd_gen.h" +#if !defined(V_GENERATE_FUNC_MODE) +#include "verse.h" +#include "v_cmd_buf.h" +#include "v_network_out_que.h" +#include "v_network.h" +#include "v_connection.h" +#include "v_util.h" + +void verse_send_g_layer_create(VNodeID node_id, VLayerID layer_id, const char *name, VNGLayerType type, uint32 def_uint, real64 def_real) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_80);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 48); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_layer_create(node_id = %u layer_id = %u name = %s type = %u def_uint = %u def_real = %f );\n", node_id, layer_id, name, type, def_uint, def_real); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], name, 16); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)type); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], def_uint); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], def_real); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_g_layer_destroy(VNodeID node_id, VLayerID layer_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_80);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 48); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_layer_destroy(node_id = %u layer_id = %u );\n", node_id, layer_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)-1); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], -1); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], V_REAL64_MAX); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_layer_create(const char *buf, size_t buffer_length) +{ + uint8 enum_temp; + unsigned int buffer_pos = 0; + void (* func_g_layer_create)(void *user_data, VNodeID node_id, VLayerID layer_id, const char *name, VNGLayerType type, uint32 def_uint, real64 def_real); + VNodeID node_id; + VLayerID layer_id; + char name[16]; + VNGLayerType type; + uint32 def_uint; + real64 def_real; + + func_g_layer_create = v_fs_get_user_func(48); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], name, 16, buffer_length - buffer_pos); + if(buffer_length < 13 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp); + type = (VNGLayerType)enum_temp; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &def_uint); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &def_real); +#if defined V_PRINT_RECEIVE_COMMANDS + if(name[0] == 0) + printf("receive: verse_send_g_layer_destroy(node_id = %u layer_id = %u ); callback = %p\n", node_id, layer_id, v_fs_get_alias_user_func(48)); + else + printf("receive: verse_send_g_layer_create(node_id = %u layer_id = %u name = %s type = %u def_uint = %u def_real = %f ); callback = %p\n", node_id, layer_id, name, type, def_uint, def_real, v_fs_get_user_func(48)); +#endif + if(name[0] == 0) + { + void (* alias_g_layer_destroy)(void *user_data, VNodeID node_id, VLayerID layer_id); + alias_g_layer_destroy = v_fs_get_alias_user_func(48); + if(alias_g_layer_destroy != NULL) + alias_g_layer_destroy(v_fs_get_alias_user_data(48), node_id, layer_id); + return buffer_pos; + } + if(func_g_layer_create != NULL) + func_g_layer_create(v_fs_get_user_data(48), node_id, layer_id, name, (VNGLayerType) type, def_uint, def_real); + + return buffer_pos; +} + +void verse_send_g_layer_subscribe(VNodeID node_id, VLayerID layer_id, VNRealFormat type) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 49); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_layer_subscribe(node_id = %u layer_id = %u type = %u );\n", node_id, layer_id, type); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)type); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_g_layer_unsubscribe(VNodeID node_id, VLayerID layer_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 49); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_layer_unsubscribe(node_id = %u layer_id = %u );\n", node_id, layer_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)-1); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_layer_subscribe(const char *buf, size_t buffer_length) +{ + uint8 enum_temp; + unsigned int buffer_pos = 0; + void (* func_g_layer_subscribe)(void *user_data, VNodeID node_id, VLayerID layer_id, VNRealFormat type); + VNodeID node_id; + VLayerID layer_id; + VNRealFormat type; + + func_g_layer_subscribe = v_fs_get_user_func(49); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp); + type = (VNRealFormat)enum_temp; +#if defined V_PRINT_RECEIVE_COMMANDS + if(type > VN_FORMAT_REAL64) + printf("receive: verse_send_g_layer_unsubscribe(node_id = %u layer_id = %u ); callback = %p\n", node_id, layer_id, v_fs_get_alias_user_func(49)); + else + printf("receive: verse_send_g_layer_subscribe(node_id = %u layer_id = %u type = %u ); callback = %p\n", node_id, layer_id, type, v_fs_get_user_func(49)); +#endif + if(type > VN_FORMAT_REAL64) + { + void (* alias_g_layer_unsubscribe)(void *user_data, VNodeID node_id, VLayerID layer_id); + alias_g_layer_unsubscribe = v_fs_get_alias_user_func(49); + if(alias_g_layer_unsubscribe != NULL) + alias_g_layer_unsubscribe(v_fs_get_alias_user_data(49), node_id, layer_id); + return buffer_pos; + } + if(func_g_layer_subscribe != NULL) + func_g_layer_subscribe(v_fs_get_user_data(49), node_id, layer_id, (VNRealFormat) type); + + return buffer_pos; +} + +void verse_send_g_vertex_set_xyz_real32(VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real32 x, real32 y, real32 z) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 50); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_vertex_set_xyz_real32(node_id = %u layer_id = %u vertex_id = %u x = %f y = %f z = %f );\n", node_id, layer_id, vertex_id, x, y, z); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], vertex_id); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], x); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], y); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], z); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u || vertex_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_g_vertex_delete_real32(VNodeID node_id, uint32 vertex_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 50); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_vertex_delete_real32(node_id = %u vertex_id = %u );\n", node_id, vertex_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], 0); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], vertex_id); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], V_REAL32_MAX); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], V_REAL32_MAX); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], V_REAL32_MAX); + if(node_id == (uint32) ~0u || vertex_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_vertex_set_xyz_real32(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_vertex_set_xyz_real32)(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real32 x, real32 y, real32 z); + VNodeID node_id; + VLayerID layer_id; + uint32 vertex_id; + real32 x; + real32 y; + real32 z; + + func_g_vertex_set_xyz_real32 = v_fs_get_user_func(50); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &vertex_id); + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &x); + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &y); + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &z); +#if defined V_PRINT_RECEIVE_COMMANDS + if(x == V_REAL32_MAX || y == V_REAL32_MAX || z == V_REAL32_MAX) + printf("receive: verse_send_g_vertex_delete_real32(node_id = %u vertex_id = %u ); callback = %p\n", node_id, vertex_id, v_fs_get_alias_user_func(50)); + else + printf("receive: verse_send_g_vertex_set_xyz_real32(node_id = %u layer_id = %u vertex_id = %u x = %f y = %f z = %f ); callback = %p\n", node_id, layer_id, vertex_id, x, y, z, v_fs_get_user_func(50)); +#endif + if(x == V_REAL32_MAX || y == V_REAL32_MAX || z == V_REAL32_MAX) + { + void (* alias_g_vertex_delete_real32)(void *user_data, VNodeID node_id, uint32 vertex_id); + alias_g_vertex_delete_real32 = v_fs_get_alias_user_func(50); + if(alias_g_vertex_delete_real32 != NULL) + alias_g_vertex_delete_real32(v_fs_get_alias_user_data(50), node_id, vertex_id); + return buffer_pos; + } + if(func_g_vertex_set_xyz_real32 != NULL) + func_g_vertex_set_xyz_real32(v_fs_get_user_data(50), node_id, layer_id, vertex_id, x, y, z); + + return buffer_pos; +} + +void verse_send_g_vertex_set_xyz_real64(VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real64 x, real64 y, real64 z) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_80);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 51); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_vertex_set_xyz_real64(node_id = %u layer_id = %u vertex_id = %u x = %f y = %f z = %f );\n", node_id, layer_id, vertex_id, x, y, z); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], vertex_id); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], x); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], y); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], z); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u || vertex_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_g_vertex_delete_real64(VNodeID node_id, uint32 vertex_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_80);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 51); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_vertex_delete_real64(node_id = %u vertex_id = %u );\n", node_id, vertex_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], 0); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], vertex_id); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], V_REAL64_MAX); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], V_REAL64_MAX); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], V_REAL64_MAX); + if(node_id == (uint32) ~0u || vertex_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_vertex_set_xyz_real64(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_vertex_set_xyz_real64)(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real64 x, real64 y, real64 z); + VNodeID node_id; + VLayerID layer_id; + uint32 vertex_id; + real64 x; + real64 y; + real64 z; + + func_g_vertex_set_xyz_real64 = v_fs_get_user_func(51); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &vertex_id); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &x); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &y); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &z); +#if defined V_PRINT_RECEIVE_COMMANDS + if(x == V_REAL64_MAX || y == V_REAL64_MAX || z == V_REAL64_MAX) + printf("receive: verse_send_g_vertex_delete_real64(node_id = %u vertex_id = %u ); callback = %p\n", node_id, vertex_id, v_fs_get_alias_user_func(51)); + else + printf("receive: verse_send_g_vertex_set_xyz_real64(node_id = %u layer_id = %u vertex_id = %u x = %f y = %f z = %f ); callback = %p\n", node_id, layer_id, vertex_id, x, y, z, v_fs_get_user_func(51)); +#endif + if(x == V_REAL64_MAX || y == V_REAL64_MAX || z == V_REAL64_MAX) + { + void (* alias_g_vertex_delete_real64)(void *user_data, VNodeID node_id, uint32 vertex_id); + alias_g_vertex_delete_real64 = v_fs_get_alias_user_func(51); + if(alias_g_vertex_delete_real64 != NULL) + alias_g_vertex_delete_real64(v_fs_get_alias_user_data(51), node_id, vertex_id); + return buffer_pos; + } + if(func_g_vertex_set_xyz_real64 != NULL) + func_g_vertex_set_xyz_real64(v_fs_get_user_data(51), node_id, layer_id, vertex_id, x, y, z); + + return buffer_pos; +} + +void verse_send_g_vertex_set_uint32(VNodeID node_id, VLayerID layer_id, uint32 vertex_id, uint32 value) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_20);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 52); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_vertex_set_uint32(node_id = %u layer_id = %u vertex_id = %u value = %u );\n", node_id, layer_id, vertex_id, value); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], vertex_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], value); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u || vertex_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_vertex_set_uint32(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_vertex_set_uint32)(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, uint32 value); + VNodeID node_id; + VLayerID layer_id; + uint32 vertex_id; + uint32 value; + + func_g_vertex_set_uint32 = v_fs_get_user_func(52); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &vertex_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &value); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_g_vertex_set_uint32(node_id = %u layer_id = %u vertex_id = %u value = %u ); callback = %p\n", node_id, layer_id, vertex_id, value, v_fs_get_user_func(52)); +#endif + if(func_g_vertex_set_uint32 != NULL) + func_g_vertex_set_uint32(v_fs_get_user_data(52), node_id, layer_id, vertex_id, value); + + return buffer_pos; +} + +void verse_send_g_vertex_set_real64(VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real64 value) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_20);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 53); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_vertex_set_real64(node_id = %u layer_id = %u vertex_id = %u value = %f );\n", node_id, layer_id, vertex_id, value); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], vertex_id); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], value); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u || vertex_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_vertex_set_real64(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_vertex_set_real64)(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real64 value); + VNodeID node_id; + VLayerID layer_id; + uint32 vertex_id; + real64 value; + + func_g_vertex_set_real64 = v_fs_get_user_func(53); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &vertex_id); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &value); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_g_vertex_set_real64(node_id = %u layer_id = %u vertex_id = %u value = %f ); callback = %p\n", node_id, layer_id, vertex_id, value, v_fs_get_user_func(53)); +#endif + if(func_g_vertex_set_real64 != NULL) + func_g_vertex_set_real64(v_fs_get_user_data(53), node_id, layer_id, vertex_id, value); + + return buffer_pos; +} + +void verse_send_g_vertex_set_real32(VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real32 value) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_20);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 54); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_vertex_set_real32(node_id = %u layer_id = %u vertex_id = %u value = %f );\n", node_id, layer_id, vertex_id, value); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], vertex_id); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], value); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u || vertex_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_vertex_set_real32(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_vertex_set_real32)(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real32 value); + VNodeID node_id; + VLayerID layer_id; + uint32 vertex_id; + real32 value; + + func_g_vertex_set_real32 = v_fs_get_user_func(54); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &vertex_id); + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &value); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_g_vertex_set_real32(node_id = %u layer_id = %u vertex_id = %u value = %f ); callback = %p\n", node_id, layer_id, vertex_id, value, v_fs_get_user_func(54)); +#endif + if(func_g_vertex_set_real32 != NULL) + func_g_vertex_set_real32(v_fs_get_user_data(54), node_id, layer_id, vertex_id, value); + + return buffer_pos; +} + +void verse_send_g_polygon_set_corner_uint32(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 55); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_polygon_set_corner_uint32(node_id = %u layer_id = %u polygon_id = %u v0 = %u v1 = %u v2 = %u v3 = %u );\n", node_id, layer_id, polygon_id, v0, v1, v2, v3); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], polygon_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], v0); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], v1); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], v2); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], v3); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u || polygon_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_g_polygon_delete(VNodeID node_id, uint32 polygon_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 55); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_polygon_delete(node_id = %u polygon_id = %u );\n", node_id, polygon_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], 1); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], polygon_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], -1); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], -1); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], -1); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], -1); + if(node_id == (uint32) ~0u || polygon_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_polygon_set_corner_uint32(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_polygon_set_corner_uint32)(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3); + VNodeID node_id; + VLayerID layer_id; + uint32 polygon_id; + uint32 v0; + uint32 v1; + uint32 v2; + uint32 v3; + + func_g_polygon_set_corner_uint32 = v_fs_get_user_func(55); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &polygon_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &v0); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &v1); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &v2); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &v3); +#if defined V_PRINT_RECEIVE_COMMANDS + if(layer_id == 1 && v0 == ~0u) + printf("receive: verse_send_g_polygon_delete(node_id = %u polygon_id = %u ); callback = %p\n", node_id, polygon_id, v_fs_get_alias_user_func(55)); + else + printf("receive: verse_send_g_polygon_set_corner_uint32(node_id = %u layer_id = %u polygon_id = %u v0 = %u v1 = %u v2 = %u v3 = %u ); callback = %p\n", node_id, layer_id, polygon_id, v0, v1, v2, v3, v_fs_get_user_func(55)); +#endif + if(layer_id == 1 && v0 == ~0u) + { + void (* alias_g_polygon_delete)(void *user_data, VNodeID node_id, uint32 polygon_id); + alias_g_polygon_delete = v_fs_get_alias_user_func(55); + if(alias_g_polygon_delete != NULL) + alias_g_polygon_delete(v_fs_get_alias_user_data(55), node_id, polygon_id); + return buffer_pos; + } + if(func_g_polygon_set_corner_uint32 != NULL) + func_g_polygon_set_corner_uint32(v_fs_get_user_data(55), node_id, layer_id, polygon_id, v0, v1, v2, v3); + + return buffer_pos; +} + +void verse_send_g_polygon_set_corner_real64(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real64 v0, real64 v1, real64 v2, real64 v3) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_80);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 56); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_polygon_set_corner_real64(node_id = %u layer_id = %u polygon_id = %u v0 = %f v1 = %f v2 = %f v3 = %f );\n", node_id, layer_id, polygon_id, v0, v1, v2, v3); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], polygon_id); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], v0); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], v1); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], v2); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], v3); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u || polygon_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_polygon_set_corner_real64(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_polygon_set_corner_real64)(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real64 v0, real64 v1, real64 v2, real64 v3); + VNodeID node_id; + VLayerID layer_id; + uint32 polygon_id; + real64 v0; + real64 v1; + real64 v2; + real64 v3; + + func_g_polygon_set_corner_real64 = v_fs_get_user_func(56); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &polygon_id); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &v0); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &v1); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &v2); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &v3); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_g_polygon_set_corner_real64(node_id = %u layer_id = %u polygon_id = %u v0 = %f v1 = %f v2 = %f v3 = %f ); callback = %p\n", node_id, layer_id, polygon_id, v0, v1, v2, v3, v_fs_get_user_func(56)); +#endif + if(func_g_polygon_set_corner_real64 != NULL) + func_g_polygon_set_corner_real64(v_fs_get_user_data(56), node_id, layer_id, polygon_id, v0, v1, v2, v3); + + return buffer_pos; +} + +void verse_send_g_polygon_set_corner_real32(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real32 v0, real32 v1, real32 v2, real32 v3) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 57); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_polygon_set_corner_real32(node_id = %u layer_id = %u polygon_id = %u v0 = %f v1 = %f v2 = %f v3 = %f );\n", node_id, layer_id, polygon_id, v0, v1, v2, v3); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], polygon_id); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], v0); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], v1); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], v2); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], v3); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u || polygon_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_polygon_set_corner_real32(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_polygon_set_corner_real32)(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real32 v0, real32 v1, real32 v2, real32 v3); + VNodeID node_id; + VLayerID layer_id; + uint32 polygon_id; + real32 v0; + real32 v1; + real32 v2; + real32 v3; + + func_g_polygon_set_corner_real32 = v_fs_get_user_func(57); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &polygon_id); + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &v0); + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &v1); + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &v2); + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &v3); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_g_polygon_set_corner_real32(node_id = %u layer_id = %u polygon_id = %u v0 = %f v1 = %f v2 = %f v3 = %f ); callback = %p\n", node_id, layer_id, polygon_id, v0, v1, v2, v3, v_fs_get_user_func(57)); +#endif + if(func_g_polygon_set_corner_real32 != NULL) + func_g_polygon_set_corner_real32(v_fs_get_user_data(57), node_id, layer_id, polygon_id, v0, v1, v2, v3); + + return buffer_pos; +} + +void verse_send_g_polygon_set_face_uint8(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint8 value) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_20);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 58); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_polygon_set_face_uint8(node_id = %u layer_id = %u polygon_id = %u value = %u );\n", node_id, layer_id, polygon_id, value); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], polygon_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], value); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u || polygon_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_polygon_set_face_uint8(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_polygon_set_face_uint8)(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint8 value); + VNodeID node_id; + VLayerID layer_id; + uint32 polygon_id; + uint8 value; + + func_g_polygon_set_face_uint8 = v_fs_get_user_func(58); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &polygon_id); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &value); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_g_polygon_set_face_uint8(node_id = %u layer_id = %u polygon_id = %u value = %u ); callback = %p\n", node_id, layer_id, polygon_id, value, v_fs_get_user_func(58)); +#endif + if(func_g_polygon_set_face_uint8 != NULL) + func_g_polygon_set_face_uint8(v_fs_get_user_data(58), node_id, layer_id, polygon_id, value); + + return buffer_pos; +} + +void verse_send_g_polygon_set_face_uint32(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint32 value) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_20);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 59); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_polygon_set_face_uint32(node_id = %u layer_id = %u polygon_id = %u value = %u );\n", node_id, layer_id, polygon_id, value); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], polygon_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], value); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u || polygon_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_polygon_set_face_uint32(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_polygon_set_face_uint32)(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint32 value); + VNodeID node_id; + VLayerID layer_id; + uint32 polygon_id; + uint32 value; + + func_g_polygon_set_face_uint32 = v_fs_get_user_func(59); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &polygon_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &value); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_g_polygon_set_face_uint32(node_id = %u layer_id = %u polygon_id = %u value = %u ); callback = %p\n", node_id, layer_id, polygon_id, value, v_fs_get_user_func(59)); +#endif + if(func_g_polygon_set_face_uint32 != NULL) + func_g_polygon_set_face_uint32(v_fs_get_user_data(59), node_id, layer_id, polygon_id, value); + + return buffer_pos; +} + +void verse_send_g_polygon_set_face_real64(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real64 value) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_20);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 60); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_polygon_set_face_real64(node_id = %u layer_id = %u polygon_id = %u value = %f );\n", node_id, layer_id, polygon_id, value); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], polygon_id); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], value); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u || polygon_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_polygon_set_face_real64(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_polygon_set_face_real64)(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real64 value); + VNodeID node_id; + VLayerID layer_id; + uint32 polygon_id; + real64 value; + + func_g_polygon_set_face_real64 = v_fs_get_user_func(60); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &polygon_id); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &value); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_g_polygon_set_face_real64(node_id = %u layer_id = %u polygon_id = %u value = %f ); callback = %p\n", node_id, layer_id, polygon_id, value, v_fs_get_user_func(60)); +#endif + if(func_g_polygon_set_face_real64 != NULL) + func_g_polygon_set_face_real64(v_fs_get_user_data(60), node_id, layer_id, polygon_id, value); + + return buffer_pos; +} + +void verse_send_g_polygon_set_face_real32(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real32 value) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_20);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 61); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_polygon_set_face_real32(node_id = %u layer_id = %u polygon_id = %u value = %f );\n", node_id, layer_id, polygon_id, value); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], polygon_id); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], value); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u || polygon_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_polygon_set_face_real32(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_polygon_set_face_real32)(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real32 value); + VNodeID node_id; + VLayerID layer_id; + uint32 polygon_id; + real32 value; + + func_g_polygon_set_face_real32 = v_fs_get_user_func(61); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &polygon_id); + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &value); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_g_polygon_set_face_real32(node_id = %u layer_id = %u polygon_id = %u value = %f ); callback = %p\n", node_id, layer_id, polygon_id, value, v_fs_get_user_func(61)); +#endif + if(func_g_polygon_set_face_real32 != NULL) + func_g_polygon_set_face_real32(v_fs_get_user_data(61), node_id, layer_id, polygon_id, value); + + return buffer_pos; +} + +void verse_send_g_crease_set_vertex(VNodeID node_id, const char *layer, uint32 def_crease) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 62); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_crease_set_vertex(node_id = %u layer = %s def_crease = %u );\n", node_id, layer, def_crease); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], layer, 16); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], def_crease); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_crease_set_vertex(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_crease_set_vertex)(void *user_data, VNodeID node_id, const char *layer, uint32 def_crease); + VNodeID node_id; + char layer[16]; + uint32 def_crease; + + func_g_crease_set_vertex = v_fs_get_user_func(62); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], layer, 16, buffer_length - buffer_pos); + if(buffer_length < 4 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &def_crease); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_g_crease_set_vertex(node_id = %u layer = %s def_crease = %u ); callback = %p\n", node_id, layer, def_crease, v_fs_get_user_func(62)); +#endif + if(func_g_crease_set_vertex != NULL) + func_g_crease_set_vertex(v_fs_get_user_data(62), node_id, layer, def_crease); + + return buffer_pos; +} + +void verse_send_g_crease_set_edge(VNodeID node_id, const char *layer, uint32 def_crease) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 63); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_crease_set_edge(node_id = %u layer = %s def_crease = %u );\n", node_id, layer, def_crease); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], layer, 16); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], def_crease); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_crease_set_edge(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_crease_set_edge)(void *user_data, VNodeID node_id, const char *layer, uint32 def_crease); + VNodeID node_id; + char layer[16]; + uint32 def_crease; + + func_g_crease_set_edge = v_fs_get_user_func(63); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], layer, 16, buffer_length - buffer_pos); + if(buffer_length < 4 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &def_crease); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_g_crease_set_edge(node_id = %u layer = %s def_crease = %u ); callback = %p\n", node_id, layer, def_crease, v_fs_get_user_func(63)); +#endif + if(func_g_crease_set_edge != NULL) + func_g_crease_set_edge(v_fs_get_user_data(63), node_id, layer, def_crease); + + return buffer_pos; +} + +void verse_send_g_bone_create(VNodeID node_id, uint16 bone_id, const char *weight, const char *reference, uint16 parent, real64 pos_x, real64 pos_y, real64 pos_z, const char *position_label, const char *rotation_label, const char *scale_label) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_160);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 64); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_bone_create(node_id = %u bone_id = %u weight = %s reference = %s parent = %u pos_x = %f pos_y = %f pos_z = %f position_label = %s rotation_label = %s scale_label = %s );\n", node_id, bone_id, weight, reference, parent, pos_x, pos_y, pos_z, position_label, rotation_label, scale_label); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], bone_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], weight, 16); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], reference, 16); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], parent); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pos_x); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pos_y); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pos_z); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], position_label, 16); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], rotation_label, 16); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], scale_label, 16); + if(node_id == (uint32) ~0u || bone_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_g_bone_destroy(VNodeID node_id, uint16 bone_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_160);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 64); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_bone_destroy(node_id = %u bone_id = %u );\n", node_id, bone_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], bone_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], -1); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], V_REAL64_MAX); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], V_REAL64_MAX); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], V_REAL64_MAX); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + if(node_id == (uint32) ~0u || bone_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_bone_create(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_bone_create)(void *user_data, VNodeID node_id, uint16 bone_id, const char *weight, const char *reference, uint16 parent, real64 pos_x, real64 pos_y, real64 pos_z, const char *position_label, const char *rotation_label, const char *scale_label); + VNodeID node_id; + uint16 bone_id; + char weight[16]; + char reference[16]; + uint16 parent; + real64 pos_x; + real64 pos_y; + real64 pos_z; + char position_label[16]; + char rotation_label[16]; + char scale_label[16]; + + func_g_bone_create = v_fs_get_user_func(64); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &bone_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], weight, 16, buffer_length - buffer_pos); + if(buffer_length < 0 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], reference, 16, buffer_length - buffer_pos); + if(buffer_length < 26 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &parent); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &pos_x); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &pos_y); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &pos_z); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], position_label, 16, buffer_length - buffer_pos); + if(buffer_length < 0 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], rotation_label, 16, buffer_length - buffer_pos); + if(buffer_length < 0 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], scale_label, 16, buffer_length - buffer_pos); +#if defined V_PRINT_RECEIVE_COMMANDS + if(weight[0] == 0) + printf("receive: verse_send_g_bone_destroy(node_id = %u bone_id = %u ); callback = %p\n", node_id, bone_id, v_fs_get_alias_user_func(64)); + else + printf("receive: verse_send_g_bone_create(node_id = %u bone_id = %u weight = %s reference = %s parent = %u pos_x = %f pos_y = %f pos_z = %f position_label = %s rotation_label = %s scale_label = %s ); callback = %p\n", node_id, bone_id, weight, reference, parent, pos_x, pos_y, pos_z, position_label, rotation_label, scale_label, v_fs_get_user_func(64)); +#endif + if(weight[0] == 0) + { + void (* alias_g_bone_destroy)(void *user_data, VNodeID node_id, uint16 bone_id); + alias_g_bone_destroy = v_fs_get_alias_user_func(64); + if(alias_g_bone_destroy != NULL) + alias_g_bone_destroy(v_fs_get_alias_user_data(64), node_id, bone_id); + return buffer_pos; + } + if(func_g_bone_create != NULL) + func_g_bone_create(v_fs_get_user_data(64), node_id, bone_id, weight, reference, parent, pos_x, pos_y, pos_z, position_label, rotation_label, scale_label); + + return buffer_pos; +} + +#endif + diff --git a/extern/verse/dist/v_gen_pack_init.c b/extern/verse/dist/v_gen_pack_init.c new file mode 100644 index 00000000000..e568cb989cb --- /dev/null +++ b/extern/verse/dist/v_gen_pack_init.c @@ -0,0 +1,95 @@ +/* +** This is automatically generated source code -- do not edit. +** Changes are affected either by editing the corresponding protocol +** definition file (v_cmd_def_X.c where X=node type), or by editing +** the code generator itself, in v_cmd_gen.c. +*/ + +#include +#include + +#include "v_cmd_gen.h" +#if !defined(V_GENERATE_FUNC_MODE) +#include "verse.h" +#include "v_cmd_buf.h" +#include "v_network_out_que.h" +#include "v_network.h" +#include "v_connection.h" +#include "v_util.h" + +#include "v_gen_unpack_func.h" + +#include "verse.h" + + +extern void verse_send_packet_ack(uint32 packet_id); +extern void verse_send_packet_nak(uint32 packet_id); + +void init_pack_and_unpack(void) +{ + v_fs_add_func(0, v_unpack_connect, (void *) verse_send_connect, NULL); + v_fs_add_func(1, v_unpack_connect_accept, (void *) verse_send_connect_accept, NULL); + v_fs_add_func(2, v_unpack_connect_terminate, (void *) verse_send_connect_terminate, NULL); + v_fs_add_func(5, v_unpack_ping, (void *) verse_send_ping, NULL); + v_fs_add_func(7, v_unpack_packet_ack, verse_send_packet_ack, NULL); + v_fs_add_func(8, v_unpack_packet_nak, verse_send_packet_nak, NULL); + v_fs_add_func(9, v_unpack_node_index_subscribe, verse_send_node_index_subscribe, NULL); + v_fs_add_func(10, v_unpack_node_create, verse_send_node_create, verse_send_node_destroy); + v_fs_add_func(11, v_unpack_node_subscribe, verse_send_node_subscribe, verse_send_node_unsubscribe); + v_fs_add_func(16, v_unpack_tag_group_create, verse_send_tag_group_create, verse_send_tag_group_destroy); + v_fs_add_func(17, v_unpack_tag_group_subscribe, verse_send_tag_group_subscribe, verse_send_tag_group_unsubscribe); + v_fs_add_func(18, v_unpack_tag_create, verse_send_tag_create, verse_send_tag_destroy); + v_fs_add_func(19, v_unpack_node_name_set, verse_send_node_name_set, NULL); + v_fs_add_func(32, v_unpack_o_transform_pos_real32, verse_send_o_transform_pos_real32, NULL); + v_fs_add_func(33, v_unpack_o_transform_rot_real32, verse_send_o_transform_rot_real32, NULL); + v_fs_add_func(34, v_unpack_o_transform_scale_real32, verse_send_o_transform_scale_real32, NULL); + v_fs_add_func(35, v_unpack_o_transform_pos_real64, verse_send_o_transform_pos_real64, NULL); + v_fs_add_func(36, v_unpack_o_transform_rot_real64, verse_send_o_transform_rot_real64, NULL); + v_fs_add_func(37, v_unpack_o_transform_scale_real64, verse_send_o_transform_scale_real64, NULL); + v_fs_add_func(38, v_unpack_o_transform_subscribe, verse_send_o_transform_subscribe, verse_send_o_transform_unsubscribe); + v_fs_add_func(39, v_unpack_o_light_set, verse_send_o_light_set, NULL); + v_fs_add_func(40, v_unpack_o_link_set, verse_send_o_link_set, verse_send_o_link_destroy); + v_fs_add_func(41, v_unpack_o_method_group_create, verse_send_o_method_group_create, verse_send_o_method_group_destroy); + v_fs_add_func(42, v_unpack_o_method_group_subscribe, verse_send_o_method_group_subscribe, verse_send_o_method_group_unsubscribe); + v_fs_add_func(43, v_unpack_o_method_create, verse_send_o_method_create, verse_send_o_method_destroy); + v_fs_add_func(44, v_unpack_o_method_call, verse_send_o_method_call, NULL); + v_fs_add_func(45, v_unpack_o_anim_run, verse_send_o_anim_run, NULL); + v_fs_add_func(46, v_unpack_o_hide, verse_send_o_hide, NULL); + v_fs_add_func(48, v_unpack_g_layer_create, verse_send_g_layer_create, verse_send_g_layer_destroy); + v_fs_add_func(49, v_unpack_g_layer_subscribe, verse_send_g_layer_subscribe, verse_send_g_layer_unsubscribe); + v_fs_add_func(50, v_unpack_g_vertex_set_xyz_real32, verse_send_g_vertex_set_xyz_real32, verse_send_g_vertex_delete_real32); + v_fs_add_func(51, v_unpack_g_vertex_set_xyz_real64, verse_send_g_vertex_set_xyz_real64, verse_send_g_vertex_delete_real64); + v_fs_add_func(52, v_unpack_g_vertex_set_uint32, verse_send_g_vertex_set_uint32, NULL); + v_fs_add_func(53, v_unpack_g_vertex_set_real64, verse_send_g_vertex_set_real64, NULL); + v_fs_add_func(54, v_unpack_g_vertex_set_real32, verse_send_g_vertex_set_real32, NULL); + v_fs_add_func(55, v_unpack_g_polygon_set_corner_uint32, verse_send_g_polygon_set_corner_uint32, verse_send_g_polygon_delete); + v_fs_add_func(56, v_unpack_g_polygon_set_corner_real64, verse_send_g_polygon_set_corner_real64, NULL); + v_fs_add_func(57, v_unpack_g_polygon_set_corner_real32, verse_send_g_polygon_set_corner_real32, NULL); + v_fs_add_func(58, v_unpack_g_polygon_set_face_uint8, verse_send_g_polygon_set_face_uint8, NULL); + v_fs_add_func(59, v_unpack_g_polygon_set_face_uint32, verse_send_g_polygon_set_face_uint32, NULL); + v_fs_add_func(60, v_unpack_g_polygon_set_face_real64, verse_send_g_polygon_set_face_real64, NULL); + v_fs_add_func(61, v_unpack_g_polygon_set_face_real32, verse_send_g_polygon_set_face_real32, NULL); + v_fs_add_func(62, v_unpack_g_crease_set_vertex, verse_send_g_crease_set_vertex, NULL); + v_fs_add_func(63, v_unpack_g_crease_set_edge, verse_send_g_crease_set_edge, NULL); + v_fs_add_func(64, v_unpack_g_bone_create, verse_send_g_bone_create, verse_send_g_bone_destroy); + v_fs_add_func(68, v_unpack_m_fragment_create, verse_send_m_fragment_create, verse_send_m_fragment_destroy); + v_fs_add_func(80, v_unpack_b_dimensions_set, verse_send_b_dimensions_set, NULL); + v_fs_add_func(81, v_unpack_b_layer_create, verse_send_b_layer_create, verse_send_b_layer_destroy); + v_fs_add_func(82, v_unpack_b_layer_subscribe, verse_send_b_layer_subscribe, verse_send_b_layer_unsubscribe); + v_fs_add_func(83, v_unpack_b_tile_set, (void *) verse_send_b_tile_set, NULL); + v_fs_add_func(96, v_unpack_t_language_set, verse_send_t_language_set, NULL); + v_fs_add_func(97, v_unpack_t_buffer_create, verse_send_t_buffer_create, verse_send_t_buffer_destroy); + v_fs_add_func(98, v_unpack_t_buffer_subscribe, verse_send_t_buffer_subscribe, verse_send_t_buffer_unsubscribe); + v_fs_add_func(99, v_unpack_t_text_set, (void *) verse_send_t_text_set, NULL); + v_fs_add_func(128, v_unpack_c_curve_create, verse_send_c_curve_create, verse_send_c_curve_destroy); + v_fs_add_func(129, v_unpack_c_curve_subscribe, verse_send_c_curve_subscribe, verse_send_c_curve_unsubscribe); + v_fs_add_func(130, v_unpack_c_key_set, (void *) verse_send_c_key_set, (void *) verse_send_c_key_destroy); + v_fs_add_func(160, v_unpack_a_buffer_create, verse_send_a_buffer_create, verse_send_a_buffer_destroy); + v_fs_add_func(161, v_unpack_a_buffer_subscribe, verse_send_a_buffer_subscribe, verse_send_a_buffer_unsubscribe); + v_fs_add_func(162, v_unpack_a_block_set, verse_send_a_block_set, verse_send_a_block_clear); + v_fs_add_func(163, v_unpack_a_stream_create, verse_send_a_stream_create, verse_send_a_stream_destroy); + v_fs_add_func(164, v_unpack_a_stream_subscribe, verse_send_a_stream_subscribe, verse_send_a_stream_unsubscribe); + v_fs_add_func(165, v_unpack_a_stream, verse_send_a_stream, NULL); +} +#endif + diff --git a/extern/verse/dist/v_gen_pack_m_node.c b/extern/verse/dist/v_gen_pack_m_node.c new file mode 100644 index 00000000000..376b6c51c39 --- /dev/null +++ b/extern/verse/dist/v_gen_pack_m_node.c @@ -0,0 +1,352 @@ +/* +** This is automatically generated source code -- do not edit. +** Changes are affected either by editing the corresponding protocol +** definition file (v_cmd_def_X.c where X=node type), or by editing +** the code generator itself, in v_cmd_gen.c. +*/ + +#include +#include + +#include "v_cmd_gen.h" +#if !defined(V_GENERATE_FUNC_MODE) +#include "verse.h" +#include "v_cmd_buf.h" +#include "v_network_out_que.h" +#include "v_network.h" +#include "v_connection.h" +#include "v_util.h" + +void verse_send_m_fragment_create(VNodeID node_id, VNMFragmentID frag_id, VNMFragmentType type, const VMatFrag *fragment) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 68); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_m_fragment_create(node_id = %u frag_id = %u type = %u fragment = %p );\n", node_id, frag_id, type, fragment); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], frag_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)type); + switch(type) + { + case VN_M_FT_COLOR : + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->color.red); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->color.green); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->color.blue); + break; + case VN_M_FT_LIGHT : + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->light.type); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->light.normal_falloff); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], fragment->light.brdf); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->light.brdf_r, 16); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->light.brdf_g, 16); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->light.brdf_b, 16); + break; + case VN_M_FT_REFLECTION : + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->reflection.normal_falloff); + break; + case VN_M_FT_TRANSPARENCY : + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->transparency.normal_falloff); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->transparency.refraction_index); + break; + case VN_M_FT_GEOMETRY : + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->geometry.layer_r, 16); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->geometry.layer_g, 16); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->geometry.layer_b, 16); + break; + case VN_M_FT_VOLUME : + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->volume.diffusion); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->volume.col_r); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->volume.col_g); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->volume.col_b); + break; + case VN_M_FT_VIEW : + break; + case VN_M_FT_TEXTURE : + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], fragment->texture.bitmap); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->texture.layer_r, 16); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->texture.layer_g, 16); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->texture.layer_b, 16); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->texture.filtered); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->texture.mapping); + break; + case VN_M_FT_NOISE : + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->noise.type); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->noise.mapping); + break; + case VN_M_FT_BLENDER : + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->blender.type); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->blender.data_a); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->blender.data_b); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->blender.control); + break; + case VN_M_FT_CLAMP : + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->clamp.min); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->clamp.red); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->clamp.green); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->clamp.blue); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->clamp.data); + break; + case VN_M_FT_MATRIX : + { + unsigned int i; + for(i = 0; i < 16; i++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->matrix.matrix[i]); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->matrix.data); + } + break; + case VN_M_FT_RAMP : + if(fragment->ramp.point_count == 0) + return; + { + unsigned int i, pos; + double last; + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->ramp.type); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->ramp.channel); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->ramp.mapping); + pos = buffer_pos; + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], fragment->ramp.point_count); + last = fragment->ramp.ramp[0].pos - 1; + for(i = 0; i < fragment->ramp.point_count && fragment->ramp.ramp[i].pos > last && i < 48; i++) + { + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->ramp.ramp[i].pos); + last = fragment->ramp.ramp[i].pos; + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->ramp.ramp[i].red); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->ramp.ramp[i].green); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->ramp.ramp[i].blue); + } + if(i != fragment->ramp.point_count) + vnp_raw_pack_uint8(&buf[pos], i); + } + break; + case VN_M_FT_ANIMATION : + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->animation.label, 16); + break; + case VN_M_FT_ALTERNATIVE : + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->alternative.alt_a); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->alternative.alt_b); + break; + case VN_M_FT_OUTPUT : + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->output.label, 16); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->output.front); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->output.back); + break; + } + if(node_id == (uint32) ~0u || frag_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_m_fragment_destroy(VNodeID node_id, VNMFragmentID frag_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 68); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_m_fragment_destroy(node_id = %u frag_id = %u );\n", node_id, frag_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], frag_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)-1); + if(node_id == (uint32) ~0u || frag_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_m_fragment_create(const char *buf, size_t buffer_length) +{ + uint8 enum_temp; + unsigned int buffer_pos = 0; + void (* func_m_fragment_create)(void *user_data, VNodeID node_id, VNMFragmentID frag_id, VNMFragmentType type, const VMatFrag *fragment); + VNodeID node_id; + VNMFragmentID frag_id; + VNMFragmentType type; + const VMatFrag *fragment; + + func_m_fragment_create = v_fs_get_user_func(68); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag_id); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp); + type = (VNMFragmentType)enum_temp; +#if defined V_PRINT_RECEIVE_COMMANDS + if(type > VN_M_FT_OUTPUT) + printf("receive: verse_send_m_fragment_destroy(node_id = %u frag_id = %u ); callback = %p\n", node_id, frag_id, v_fs_get_alias_user_func(68)); + else + printf("receive: verse_send_m_fragment_create(node_id = %u frag_id = %u type = %u ); callback = %p\n", node_id, frag_id, type, v_fs_get_user_func(68)); +#endif + if(type <= VN_M_FT_OUTPUT) + { + VMatFrag frag; + uint8 temp; + switch(type) + { + case VN_M_FT_COLOR : + if(buffer_pos + 3 * 8 > buffer_length) + return -1; + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.color.red); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.color.green); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.color.blue); + break; + case VN_M_FT_LIGHT : + if(buffer_pos + 13 > buffer_length) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp); + frag.light.type = (VNMLightType)temp; + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.light.normal_falloff); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &frag.light.brdf); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.light.brdf_r, 16, buffer_length - buffer_pos); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.light.brdf_g, 16, buffer_length - buffer_pos); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.light.brdf_b, 16, buffer_length - buffer_pos); + break; + case VN_M_FT_REFLECTION : + if(buffer_pos + 8 > buffer_length) + return -1; + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.reflection.normal_falloff); + break; + case VN_M_FT_TRANSPARENCY : + if(buffer_pos + 16 > buffer_length) + return -1; + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.transparency.normal_falloff); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.transparency.refraction_index); + break; + case VN_M_FT_VOLUME : + if(buffer_pos + 32 > buffer_length) + return -1; + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.volume.diffusion); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.volume.col_r); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.volume.col_g); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.volume.col_b); + break; + case VN_M_FT_VIEW : + break; + case VN_M_FT_GEOMETRY : + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.geometry.layer_r, 16, buffer_length - buffer_pos); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.geometry.layer_g, 16, buffer_length - buffer_pos); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.geometry.layer_b, 16, buffer_length - buffer_pos); + break; + case VN_M_FT_TEXTURE : + if(buffer_pos + 10 > buffer_length) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &frag.texture.bitmap); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.texture.layer_r, 16, buffer_length - buffer_pos); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.texture.layer_g, 16, buffer_length - buffer_pos); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.texture.layer_b, 16, buffer_length - buffer_pos); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp); + frag.texture.filtered = (VNMNoiseType)temp; + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.texture.mapping); + break; + case VN_M_FT_NOISE : + if(buffer_pos + 3 > buffer_length) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp); + frag.noise.type = (VNMNoiseType)temp; + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.noise.mapping); + break; + case VN_M_FT_BLENDER : + if(buffer_pos + 7 > buffer_length) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp); + frag.blender.type = (VNMBlendType)temp; + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.blender.data_a); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.blender.data_b); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.blender.control); + break; + case VN_M_FT_CLAMP : + if(buffer_pos + 27 > buffer_length) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp); + frag.clamp.min = (VNMBlendType)temp; + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.clamp.red); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.clamp.green); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.clamp.blue); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.clamp.data); + break; + case VN_M_FT_MATRIX : + if(buffer_pos + 8 * 16 + 2 > buffer_length) + return -1; + else + { + unsigned int i; + for(i = 0; i < 16; i++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.matrix.matrix[i]); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.matrix.data); + } + break; + case VN_M_FT_RAMP : + if(buffer_pos + 5 + 4 * 8 > buffer_length) + return -1; + else + { + unsigned int i, pos; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp); + frag.ramp.type = (VNMRampType)temp; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp); + frag.ramp.channel = (VNMRampChannel)temp; + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.ramp.mapping); + pos = buffer_pos; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &frag.ramp.point_count); + for(i = 0; i < frag.ramp.point_count && buffer_pos + 8 * 4 <= buffer_length && i < 48; i++) + { + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.ramp.ramp[i].pos); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.ramp.ramp[i].red); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.ramp.ramp[i].green); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.ramp.ramp[i].blue); + }if(i != frag.ramp.point_count) + frag.ramp.point_count = i; + } + break; + case VN_M_FT_ANIMATION : + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.animation.label, 16, buffer_length - buffer_pos); + break; + case VN_M_FT_ALTERNATIVE : + if(buffer_pos + 4 > buffer_length) + return -1; + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.alternative.alt_a); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.alternative.alt_b); + break; + case VN_M_FT_OUTPUT : + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.output.label, 16, buffer_length - buffer_pos); + if(buffer_pos + 4 > buffer_length) + return -1; + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.output.front); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.output.back); + break; + } + if(func_m_fragment_create != NULL) + func_m_fragment_create(v_fs_get_user_data(68), node_id, frag_id, type, &frag); + return buffer_pos; + } + + if(type > VN_M_FT_OUTPUT) + { + void (* alias_m_fragment_destroy)(void *user_data, VNodeID node_id, VNMFragmentID frag_id); + alias_m_fragment_destroy = v_fs_get_alias_user_func(68); + if(alias_m_fragment_destroy != NULL) + alias_m_fragment_destroy(v_fs_get_alias_user_data(68), node_id, frag_id); + return buffer_pos; + } + if(func_m_fragment_create != NULL) + func_m_fragment_create(v_fs_get_user_data(68), node_id, frag_id, (VNMFragmentType) type, fragment); + + return buffer_pos; +} + +#endif + diff --git a/extern/verse/dist/v_gen_pack_o_node.c b/extern/verse/dist/v_gen_pack_o_node.c new file mode 100644 index 00000000000..5d60bafe1d0 --- /dev/null +++ b/extern/verse/dist/v_gen_pack_o_node.c @@ -0,0 +1,1297 @@ +/* +** This is automatically generated source code -- do not edit. +** Changes are affected either by editing the corresponding protocol +** definition file (v_cmd_def_X.c where X=node type), or by editing +** the code generator itself, in v_cmd_gen.c. +*/ + +#include +#include + +#include "v_cmd_gen.h" +#if !defined(V_GENERATE_FUNC_MODE) +#include "verse.h" +#include "v_cmd_buf.h" +#include "v_network_out_que.h" +#include "v_network.h" +#include "v_connection.h" +#include "v_util.h" + +void verse_send_o_transform_pos_real32(VNodeID node_id, uint32 time_s, uint32 time_f, const real32 *pos, const real32 *speed, const real32 *accelerate, const real32 *drag_normal, real32 drag) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 32); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_transform_pos_real32(node_id = %u time_s = %u time_f = %u pos = %p speed = %p accelerate = %p drag_normal = %p drag = %f );\n", node_id, time_s, time_f, pos, speed, accelerate, drag_normal, drag); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], time_s); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], time_f); + { + unsigned char mask = 0; + unsigned int cmd; + cmd = buffer_pos++; + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], pos[0]); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], pos[1]); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], pos[2]); + if(speed != NULL && (speed[0] > 0.0000001 || speed[0] < -0.0000001 || speed[1] > 0.0000001 || speed[1] < -0.0000001 || speed[2] > 0.0000001 || speed[2] < -0.0000001)) + { + mask |= 1; + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], speed[0]); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], speed[1]); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], speed[2]); + } + if(accelerate != NULL && (accelerate[0] > 0.0000001 || accelerate[0] < -0.0000001 || accelerate[1] > 0.0000001 || accelerate[1] < -0.0000001 || accelerate[2] > 0.0000001 || accelerate[2] < -0.0000001)) + { + mask |= 2; + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], accelerate[0]); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], accelerate[1]); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], accelerate[2]); + } + if(drag_normal != NULL && (drag > 0.0000001 || drag < -0.0000001) && (drag_normal[0] > 0.0000001 || drag_normal[0] < -0.0000001 || drag_normal[1] > 0.0000001 || drag_normal[1] < -0.0000001 || drag_normal[2] > 0.0000001 || drag_normal[2] < -0.0000001)) + { + mask |= 4; + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], drag_normal[0]); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], drag_normal[1]); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], drag_normal[2]); + } + if(drag > 0.0000001 || drag < -0.0000001) + { + mask |= 8; + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], drag); + } + vnp_raw_pack_uint8(&buf[cmd], mask); + }if(FALSE) + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], drag); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_transform_pos_real32(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_transform_pos_real32)(void *user_data, VNodeID node_id, uint32 time_s, uint32 time_f, const real32 *pos, const real32 *speed, const real32 *accelerate, const real32 *drag_normal, real32 drag); + VNodeID node_id; + uint32 time_s; + uint32 time_f; + const real32 *pos; + const real32 *speed; + const real32 *accelerate; + const real32 *drag_normal; + real32 drag; + + func_o_transform_pos_real32 = v_fs_get_user_func(32); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &time_s); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &time_f); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_o_transform_pos_real32(node_id = %u time_s = %u time_f = %u drag = %f ); callback = %p\n", node_id, time_s, time_f, drag, v_fs_get_user_func(32)); +#endif + { + float output[4][3]; + unsigned int i, j; + char mask, pow = 1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &mask); + for(j = 0; j < 3; j++) + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &output[0][j]); + for(i = 1; i < 4; i++) + { + if((mask & pow) != 0) + for(j = 0; j < 3; j++) + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &output[i][j]); + else + for(j = 0; j < 3; j++) + output[i][j] = 0; + pow *= 2; + } + if((mask & pow) != 0) + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &drag); + else + drag = 0.0f; + if(func_o_transform_pos_real32 != NULL) + func_o_transform_pos_real32(v_fs_get_user_data(32), node_id, time_s, time_f, &output[0][0], &output[1][0], &output[2][0], &output[3][0], drag); + return buffer_pos; + } + + if(func_o_transform_pos_real32 != NULL) + func_o_transform_pos_real32(v_fs_get_user_data(32), node_id, time_s, time_f, pos, speed, accelerate, drag_normal, drag); + + return buffer_pos; +} + +void verse_send_o_transform_rot_real32(VNodeID node_id, uint32 time_s, uint32 time_f, const VNQuat32 *rot, const VNQuat32 *speed, const VNQuat32 *accelerate, const VNQuat32 *drag_normal, real32 drag) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 33); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_transform_rot_real32(node_id = %u time_s = %u time_f = %u rot = %p speed = %p accelerate = %p drag_normal = %p drag = %f );\n", node_id, time_s, time_f, rot, speed, accelerate, drag_normal, drag); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], time_s); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], time_f); + { + uint8 mask = 0; + unsigned int maskpos; + maskpos = buffer_pos++; /* Remember location, and reserve a byte for the mask. */ + buffer_pos += vnp_pack_quat32(&buf[buffer_pos], rot); + if(v_quat32_valid(speed)) + { + mask |= 1; + buffer_pos += vnp_pack_quat32(&buf[buffer_pos], speed); + } + if(v_quat32_valid(accelerate)) + { + mask |= 2; + buffer_pos += vnp_pack_quat32(&buf[buffer_pos], accelerate); + } + if(v_quat32_valid(drag_normal)) + { + mask |= 4; + buffer_pos += vnp_pack_quat32(&buf[buffer_pos], drag_normal); + } + if(drag > 0.0000001 || drag < -0.0000001) + { + mask |= 8; + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], drag); + } + vnp_raw_pack_uint8(&buf[maskpos], mask); /* Write the mask into start of command. */ + } + if(FALSE) + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], drag); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_transform_rot_real32(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_transform_rot_real32)(void *user_data, VNodeID node_id, uint32 time_s, uint32 time_f, const VNQuat32 *rot, const VNQuat32 *speed, const VNQuat32 *accelerate, const VNQuat32 *drag_normal, real32 drag); + VNodeID node_id; + uint32 time_s; + uint32 time_f; + const VNQuat32 *rot; + const VNQuat32 *speed; + const VNQuat32 *accelerate; + const VNQuat32 *drag_normal; + real32 drag; + + func_o_transform_rot_real32 = v_fs_get_user_func(33); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &time_s); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &time_f); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_o_transform_rot_real32(node_id = %u time_s = %u time_f = %u drag = %f ); callback = %p\n", node_id, time_s, time_f, drag, v_fs_get_user_func(33)); +#endif + { + VNQuat32 trot, temp[3], *q[3]; + unsigned int i; + uint8 mask, test; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &mask); + buffer_pos += vnp_unpack_quat32(&buf[buffer_pos], &trot); + for(i = 0, test = 1; i < sizeof temp / sizeof *temp; i++, test <<= 1) + { + if(mask & test) /* Field present? */ + { + buffer_pos += vnp_unpack_quat32(&buf[buffer_pos], &temp[i]); + q[i] = &temp[i]; + } + else + q[i] = NULL; + } + if(mask & test) + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &drag); + else + drag = 0.0; + if(func_o_transform_rot_real32 != NULL) + func_o_transform_rot_real32(v_fs_get_user_data(33), node_id, time_s, time_f, &trot, q[0], q[1], q[2], drag); + return buffer_pos; + } + + if(func_o_transform_rot_real32 != NULL) + func_o_transform_rot_real32(v_fs_get_user_data(33), node_id, time_s, time_f, rot, speed, accelerate, drag_normal, drag); + + return buffer_pos; +} + +void verse_send_o_transform_scale_real32(VNodeID node_id, real32 scale_x, real32 scale_y, real32 scale_z) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_20);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 34); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_transform_scale_real32(node_id = %u scale_x = %f scale_y = %f scale_z = %f );\n", node_id, scale_x, scale_y, scale_z); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], scale_x); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], scale_y); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], scale_z); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_transform_scale_real32(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_transform_scale_real32)(void *user_data, VNodeID node_id, real32 scale_x, real32 scale_y, real32 scale_z); + VNodeID node_id; + real32 scale_x; + real32 scale_y; + real32 scale_z; + + func_o_transform_scale_real32 = v_fs_get_user_func(34); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &scale_x); + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &scale_y); + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &scale_z); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_o_transform_scale_real32(node_id = %u scale_x = %f scale_y = %f scale_z = %f ); callback = %p\n", node_id, scale_x, scale_y, scale_z, v_fs_get_user_func(34)); +#endif + if(func_o_transform_scale_real32 != NULL) + func_o_transform_scale_real32(v_fs_get_user_data(34), node_id, scale_x, scale_y, scale_z); + + return buffer_pos; +} + +void verse_send_o_transform_pos_real64(VNodeID node_id, uint32 time_s, uint32 time_f, const real64 *pos, const real64 *speed, const real64 *accelerate, const real64 *drag_normal, real64 drag) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 35); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_transform_pos_real64(node_id = %u time_s = %u time_f = %u pos = %p speed = %p accelerate = %p drag_normal = %p drag = %f );\n", node_id, time_s, time_f, pos, speed, accelerate, drag_normal, drag); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], time_s); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], time_f); + { + unsigned char mask = 0; + unsigned int cmd; + cmd = buffer_pos++; + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pos[0]); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pos[1]); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pos[2]); + if(speed != NULL && (speed[0] > 0.0000001 || speed[0] < -0.0000001 || speed[1] > 0.0000001 || speed[1] < -0.0000001 || speed[2] > 0.0000001 || speed[2] < -0.0000001)) + { + mask |= 1; + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], speed[0]); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], speed[1]); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], speed[2]); + } + if(accelerate != NULL && (accelerate[0] > 0.0000001 || accelerate[0] < -0.0000001 || accelerate[1] > 0.0000001 || accelerate[1] < -0.0000001 || accelerate[2] > 0.0000001 || accelerate[2] < -0.0000001)) + { + mask |= 2; + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], accelerate[0]); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], accelerate[1]); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], accelerate[2]); + } + if(drag_normal != NULL && (drag > 0.0000001 || drag < -0.0000001) && (drag_normal[0] > 0.0000001 || drag_normal[0] < -0.0000001 || drag_normal[1] > 0.0000001 || drag_normal[1] < -0.0000001 || drag_normal[2] > 0.0000001 || drag_normal[2] < -0.0000001)) + { + mask |= 4; + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], drag_normal[0]); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], drag_normal[1]); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], drag_normal[2]); + } + if(drag > 0.0000001 || drag < -0.0000001) + { + mask |= 8; + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], drag); + } + vnp_raw_pack_uint8(&buf[cmd], mask); + }if(FALSE) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], drag); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_transform_pos_real64(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_transform_pos_real64)(void *user_data, VNodeID node_id, uint32 time_s, uint32 time_f, const real64 *pos, const real64 *speed, const real64 *accelerate, const real64 *drag_normal, real64 drag); + VNodeID node_id; + uint32 time_s; + uint32 time_f; + const real64 *pos; + const real64 *speed; + const real64 *accelerate; + const real64 *drag_normal; + real64 drag; + + func_o_transform_pos_real64 = v_fs_get_user_func(35); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &time_s); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &time_f); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_o_transform_pos_real64(node_id = %u time_s = %u time_f = %u drag = %f ); callback = %p\n", node_id, time_s, time_f, drag, v_fs_get_user_func(35)); +#endif + { + double output[4][3]; + unsigned int i, j; + char mask, pow = 1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &mask); + for(j = 0; j < 3; j++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &output[0][j]); + for(i = 1; i < 4; i++) + { + if((mask & pow) != 0) + for(j = 0; j < 3; j++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &output[i][j]); + else + for(j = 0; j < 3; j++) + output[i][j] = 0; + pow *= 2; + } + if((mask & pow) != 0) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &drag); + else + drag = 0.0; + if(func_o_transform_pos_real64 != NULL) + func_o_transform_pos_real64(v_fs_get_user_data(35), node_id, time_s, time_f, &output[0][0], &output[1][0], &output[2][0], &output[3][0], drag); + return buffer_pos; + } + + if(func_o_transform_pos_real64 != NULL) + func_o_transform_pos_real64(v_fs_get_user_data(35), node_id, time_s, time_f, pos, speed, accelerate, drag_normal, drag); + + return buffer_pos; +} + +void verse_send_o_transform_rot_real64(VNodeID node_id, uint32 time_s, uint32 time_f, const VNQuat64 *rot, const VNQuat64 *speed, const VNQuat64 *accelerate, const VNQuat64 *drag_normal, real64 drag) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 36); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_transform_rot_real64(node_id = %u time_s = %u time_f = %u rot = %p speed = %p accelerate = %p drag_normal = %p drag = %f );\n", node_id, time_s, time_f, rot, speed, accelerate, drag_normal, drag); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], time_s); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], time_f); + { + uint8 mask = 0; + unsigned int maskpos; + maskpos = buffer_pos++; /* Remember location, and reserve a byte for the mask. */ + buffer_pos += vnp_pack_quat64(&buf[buffer_pos], rot); + if(v_quat64_valid(speed)) + { + mask |= 1; + buffer_pos += vnp_pack_quat64(&buf[buffer_pos], speed); + } + if(v_quat64_valid(accelerate)) + { + mask |= 2; + buffer_pos += vnp_pack_quat64(&buf[buffer_pos], accelerate); + } + if(v_quat64_valid(drag_normal)) + { + mask |= 4; + buffer_pos += vnp_pack_quat64(&buf[buffer_pos], drag_normal); + } + if(drag > 0.0000001 || drag < -0.0000001) + { + mask |= 8; + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], drag); + } + vnp_raw_pack_uint8(&buf[maskpos], mask); /* Write the mask into start of command. */ + } + if(FALSE) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], drag); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_transform_rot_real64(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_transform_rot_real64)(void *user_data, VNodeID node_id, uint32 time_s, uint32 time_f, const VNQuat64 *rot, const VNQuat64 *speed, const VNQuat64 *accelerate, const VNQuat64 *drag_normal, real64 drag); + VNodeID node_id; + uint32 time_s; + uint32 time_f; + const VNQuat64 *rot; + const VNQuat64 *speed; + const VNQuat64 *accelerate; + const VNQuat64 *drag_normal; + real64 drag; + + func_o_transform_rot_real64 = v_fs_get_user_func(36); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &time_s); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &time_f); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_o_transform_rot_real64(node_id = %u time_s = %u time_f = %u drag = %f ); callback = %p\n", node_id, time_s, time_f, drag, v_fs_get_user_func(36)); +#endif + { + VNQuat64 trot, temp[3], *q[3]; + unsigned int i; + uint8 mask, test; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &mask); + buffer_pos += vnp_unpack_quat64(&buf[buffer_pos], &trot); + for(i = 0, test = 1; i < sizeof temp / sizeof *temp; i++, test <<= 1) + { + if(mask & test) /* Field present? */ + { + buffer_pos += vnp_unpack_quat64(&buf[buffer_pos], &temp[i]); + q[i] = &temp[i]; + } + else + q[i] = NULL; + } + if(mask & test) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &drag); + else + drag = 0.0; + if(func_o_transform_rot_real64 != NULL) + func_o_transform_rot_real64(v_fs_get_user_data(36), node_id, time_s, time_f, &trot, q[0], q[1], q[2], drag); + return buffer_pos; + } + + if(func_o_transform_rot_real64 != NULL) + func_o_transform_rot_real64(v_fs_get_user_data(36), node_id, time_s, time_f, rot, speed, accelerate, drag_normal, drag); + + return buffer_pos; +} + +void verse_send_o_transform_scale_real64(VNodeID node_id, real64 scale_x, real64 scale_y, real64 scale_z) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 37); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_transform_scale_real64(node_id = %u scale_x = %f scale_y = %f scale_z = %f );\n", node_id, scale_x, scale_y, scale_z); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], scale_x); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], scale_y); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], scale_z); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_transform_scale_real64(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_transform_scale_real64)(void *user_data, VNodeID node_id, real64 scale_x, real64 scale_y, real64 scale_z); + VNodeID node_id; + real64 scale_x; + real64 scale_y; + real64 scale_z; + + func_o_transform_scale_real64 = v_fs_get_user_func(37); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &scale_x); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &scale_y); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &scale_z); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_o_transform_scale_real64(node_id = %u scale_x = %f scale_y = %f scale_z = %f ); callback = %p\n", node_id, scale_x, scale_y, scale_z, v_fs_get_user_func(37)); +#endif + if(func_o_transform_scale_real64 != NULL) + func_o_transform_scale_real64(v_fs_get_user_data(37), node_id, scale_x, scale_y, scale_z); + + return buffer_pos; +} + +void verse_send_o_transform_subscribe(VNodeID node_id, VNRealFormat type) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 38); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_transform_subscribe(node_id = %u type = %u );\n", node_id, type); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)type); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], TRUE); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_o_transform_unsubscribe(VNodeID node_id, VNRealFormat type) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 38); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_transform_unsubscribe(node_id = %u type = %u );\n", node_id, type); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)type); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], FALSE); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_transform_subscribe(const char *buf, size_t buffer_length) +{ + uint8 enum_temp; + unsigned int buffer_pos = 0; + void (* func_o_transform_subscribe)(void *user_data, VNodeID node_id, VNRealFormat type); + VNodeID node_id; + VNRealFormat type; + uint8 alias_bool; + + func_o_transform_subscribe = v_fs_get_user_func(38); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp); + type = (VNRealFormat)enum_temp; + if(buffer_length < buffer_pos + 1) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &alias_bool); +#if defined V_PRINT_RECEIVE_COMMANDS + if(!alias_bool) + printf("receive: verse_send_o_transform_unsubscribe(node_id = %u type = %u ); callback = %p\n", node_id, type, v_fs_get_alias_user_func(38)); + else + printf("receive: verse_send_o_transform_subscribe(node_id = %u type = %u ); callback = %p\n", node_id, type, v_fs_get_user_func(38)); +#endif + if(!alias_bool) + { + void (* alias_o_transform_unsubscribe)(void *user_data, VNodeID node_id, VNRealFormat type); + alias_o_transform_unsubscribe = v_fs_get_alias_user_func(38); + if(alias_o_transform_unsubscribe != NULL) + alias_o_transform_unsubscribe(v_fs_get_alias_user_data(38), node_id, (VNRealFormat)type); + return buffer_pos; + } + if(func_o_transform_subscribe != NULL) + func_o_transform_subscribe(v_fs_get_user_data(38), node_id, (VNRealFormat) type); + + return buffer_pos; +} + +void verse_send_o_light_set(VNodeID node_id, real64 light_r, real64 light_g, real64 light_b) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 39); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_light_set(node_id = %u light_r = %f light_g = %f light_b = %f );\n", node_id, light_r, light_g, light_b); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], light_r); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], light_g); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], light_b); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_light_set(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_light_set)(void *user_data, VNodeID node_id, real64 light_r, real64 light_g, real64 light_b); + VNodeID node_id; + real64 light_r; + real64 light_g; + real64 light_b; + + func_o_light_set = v_fs_get_user_func(39); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &light_r); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &light_g); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &light_b); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_o_light_set(node_id = %u light_r = %f light_g = %f light_b = %f ); callback = %p\n", node_id, light_r, light_g, light_b, v_fs_get_user_func(39)); +#endif + if(func_o_light_set != NULL) + func_o_light_set(v_fs_get_user_data(39), node_id, light_r, light_g, light_b); + + return buffer_pos; +} + +void verse_send_o_link_set(VNodeID node_id, uint16 link_id, VNodeID link, const char *label, uint32 target_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_80);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 40); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_link_set(node_id = %u link_id = %u link = %u label = %s target_id = %u );\n", node_id, link_id, link, label, target_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], link_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], link); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], label, 16); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], target_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], TRUE); + if(node_id == (uint32) ~0u || link_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_o_link_destroy(VNodeID node_id, uint16 link_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_80);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 40); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_link_destroy(node_id = %u link_id = %u );\n", node_id, link_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], link_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], -1); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], -1); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], FALSE); + if(node_id == (uint32) ~0u || link_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_link_set(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_link_set)(void *user_data, VNodeID node_id, uint16 link_id, VNodeID link, const char *label, uint32 target_id); + VNodeID node_id; + uint16 link_id; + VNodeID link; + char label[16]; + uint32 target_id; + uint8 alias_bool; + + func_o_link_set = v_fs_get_user_func(40); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &link_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &link); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], label, 16, buffer_length - buffer_pos); + if(buffer_length < 4 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &target_id); + if(buffer_length < buffer_pos + 1) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &alias_bool); +#if defined V_PRINT_RECEIVE_COMMANDS + if(!alias_bool) + printf("receive: verse_send_o_link_destroy(node_id = %u link_id = %u ); callback = %p\n", node_id, link_id, v_fs_get_alias_user_func(40)); + else + printf("receive: verse_send_o_link_set(node_id = %u link_id = %u link = %u label = %s target_id = %u ); callback = %p\n", node_id, link_id, link, label, target_id, v_fs_get_user_func(40)); +#endif + if(!alias_bool) + { + void (* alias_o_link_destroy)(void *user_data, VNodeID node_id, uint16 link_id); + alias_o_link_destroy = v_fs_get_alias_user_func(40); + if(alias_o_link_destroy != NULL) + alias_o_link_destroy(v_fs_get_alias_user_data(40), node_id, link_id); + return buffer_pos; + } + if(func_o_link_set != NULL) + func_o_link_set(v_fs_get_user_data(40), node_id, link_id, link, label, target_id); + + return buffer_pos; +} + +void verse_send_o_method_group_create(VNodeID node_id, uint16 group_id, const char *name) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 41); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_method_group_create(node_id = %u group_id = %u name = %s );\n", node_id, group_id, name); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], name, 16); + if(node_id == (uint32) ~0u || group_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_o_method_group_destroy(VNodeID node_id, uint16 group_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 41); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_method_group_destroy(node_id = %u group_id = %u );\n", node_id, group_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + if(node_id == (uint32) ~0u || group_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_method_group_create(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_method_group_create)(void *user_data, VNodeID node_id, uint16 group_id, const char *name); + VNodeID node_id; + uint16 group_id; + char name[16]; + + func_o_method_group_create = v_fs_get_user_func(41); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &group_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], name, 16, buffer_length - buffer_pos); +#if defined V_PRINT_RECEIVE_COMMANDS + if(name[0] == 0) + printf("receive: verse_send_o_method_group_destroy(node_id = %u group_id = %u ); callback = %p\n", node_id, group_id, v_fs_get_alias_user_func(41)); + else + printf("receive: verse_send_o_method_group_create(node_id = %u group_id = %u name = %s ); callback = %p\n", node_id, group_id, name, v_fs_get_user_func(41)); +#endif + if(name[0] == 0) + { + void (* alias_o_method_group_destroy)(void *user_data, VNodeID node_id, uint16 group_id); + alias_o_method_group_destroy = v_fs_get_alias_user_func(41); + if(alias_o_method_group_destroy != NULL) + alias_o_method_group_destroy(v_fs_get_alias_user_data(41), node_id, group_id); + return buffer_pos; + } + if(func_o_method_group_create != NULL) + func_o_method_group_create(v_fs_get_user_data(41), node_id, group_id, name); + + return buffer_pos; +} + +void verse_send_o_method_group_subscribe(VNodeID node_id, uint16 group_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 42); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_method_group_subscribe(node_id = %u group_id = %u );\n", node_id, group_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], TRUE); + if(node_id == (uint32) ~0u || group_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_o_method_group_unsubscribe(VNodeID node_id, uint16 group_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 42); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_method_group_unsubscribe(node_id = %u group_id = %u );\n", node_id, group_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], FALSE); + if(node_id == (uint32) ~0u || group_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_method_group_subscribe(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_method_group_subscribe)(void *user_data, VNodeID node_id, uint16 group_id); + VNodeID node_id; + uint16 group_id; + uint8 alias_bool; + + func_o_method_group_subscribe = v_fs_get_user_func(42); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &group_id); + if(buffer_length < buffer_pos + 1) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &alias_bool); +#if defined V_PRINT_RECEIVE_COMMANDS + if(!alias_bool) + printf("receive: verse_send_o_method_group_unsubscribe(node_id = %u group_id = %u ); callback = %p\n", node_id, group_id, v_fs_get_alias_user_func(42)); + else + printf("receive: verse_send_o_method_group_subscribe(node_id = %u group_id = %u ); callback = %p\n", node_id, group_id, v_fs_get_user_func(42)); +#endif + if(!alias_bool) + { + void (* alias_o_method_group_unsubscribe)(void *user_data, VNodeID node_id, uint16 group_id); + alias_o_method_group_unsubscribe = v_fs_get_alias_user_func(42); + if(alias_o_method_group_unsubscribe != NULL) + alias_o_method_group_unsubscribe(v_fs_get_alias_user_data(42), node_id, group_id); + return buffer_pos; + } + if(func_o_method_group_subscribe != NULL) + func_o_method_group_subscribe(v_fs_get_user_data(42), node_id, group_id); + + return buffer_pos; +} + +void verse_send_o_method_create(VNodeID node_id, uint16 group_id, uint16 method_id, const char *name, uint8 param_count, const VNOParamType *param_types, const char * *param_names) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 43); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_method_create(node_id = %u group_id = %u method_id = %u name = %s param_count = %u param_types = %p param_names = %p );\n", node_id, group_id, method_id, name, param_count, param_types, param_names); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], method_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], name, 512); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], param_count); + { + unsigned int i, j, sum = 1; + for(i = 0; i < param_count; i++) + { + sum += 3; + for(j = 0; param_names[i][j] != 0; j++); + } + if(sum + buffer_pos > 1500) + return; + for(i = 0; i < param_count; i++) + { + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], param_types[i]); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], param_names[i], 1500 - buffer_pos); + } + } + if(node_id == (uint32) ~0u || group_id == (uint16) ~0u || method_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 9); + else + v_cmd_buf_set_address_size(head, 9); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_o_method_destroy(VNodeID node_id, uint16 group_id, uint16 method_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 43); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_method_destroy(node_id = %u group_id = %u method_id = %u );\n", node_id, group_id, method_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], method_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 512); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], -1); + if(node_id == (uint32) ~0u || group_id == (uint16) ~0u || method_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 9); + else + v_cmd_buf_set_address_size(head, 9); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_method_create(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_method_create)(void *user_data, VNodeID node_id, uint16 group_id, uint16 method_id, const char *name, uint8 param_count, const VNOParamType *param_types, const char * *param_names); + VNodeID node_id; + uint16 group_id; + uint16 method_id; + char name[512]; + uint8 param_count; + const VNOParamType *param_types; + const char * *param_names; + + func_o_method_create = v_fs_get_user_func(43); + if(buffer_length < 8) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &group_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &method_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], name, 512, buffer_length - buffer_pos); + if(buffer_length < 1 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], ¶m_count); +#if defined V_PRINT_RECEIVE_COMMANDS + if(name[0] == 0) + printf("receive: verse_send_o_method_destroy(node_id = %u group_id = %u method_id = %u ); callback = %p\n", node_id, group_id, method_id, v_fs_get_alias_user_func(43)); + else + printf("receive: verse_send_o_method_create(node_id = %u group_id = %u method_id = %u name = %s param_count = %u ); callback = %p\n", node_id, group_id, method_id, name, param_count, v_fs_get_user_func(43)); +#endif + if(param_count != 255) + { + unsigned int i, size, text = 0; + VNOParamType types[256]; + uint8 t; + char name_buf[1500], *names[256]; + for(i = 0; i < param_count; i++) + { + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &t); + types[i] = t; + names[i] = &name_buf[text]; + size = vnp_raw_unpack_string(&buf[buffer_pos], names[i], 1500 - buffer_pos, buffer_length - buffer_pos); + buffer_pos += size; + text += size; + } + if(func_o_method_create != NULL) + func_o_method_create(v_fs_get_user_data(43), node_id, group_id, method_id, name, param_count, types, (const char **) names); + return buffer_pos; + } + + if(name[0] == 0) + { + void (* alias_o_method_destroy)(void *user_data, VNodeID node_id, uint16 group_id, uint16 method_id); + alias_o_method_destroy = v_fs_get_alias_user_func(43); + if(alias_o_method_destroy != NULL) + alias_o_method_destroy(v_fs_get_alias_user_data(43), node_id, group_id, method_id); + return buffer_pos; + } + if(func_o_method_create != NULL) + func_o_method_create(v_fs_get_user_data(43), node_id, group_id, method_id, name, param_count, param_types, param_names); + + return buffer_pos; +} + +void verse_send_o_method_call(VNodeID node_id, uint16 group_id, uint16 method_id, VNodeID sender, const VNOPackedParams *params) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 44); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_method_call(node_id = %u group_id = %u method_id = %u sender = %u params = %p );\n", node_id, group_id, method_id, sender, params); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], method_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], sender); + { + unsigned int i; + uint16 size; + vnp_raw_unpack_uint16(params, &size); + for(i = 0; i < size; i++) + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], ((uint8 *)params)[i]); + free((void *) params); /* Drop the const. */ + } + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_method_call(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_method_call)(void *user_data, VNodeID node_id, uint16 group_id, uint16 method_id, VNodeID sender, const VNOPackedParams *params); + VNodeID node_id; + uint16 group_id; + uint16 method_id; + VNodeID sender; + const VNOPackedParams *params; + + func_o_method_call = v_fs_get_user_func(44); + if(buffer_length < 12) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &group_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &method_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &sender); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_o_method_call(node_id = %u group_id = %u method_id = %u sender = %u ); callback = %p\n", node_id, group_id, method_id, sender, v_fs_get_user_func(44)); +#endif + { + unsigned int i; + uint8 par[1500]; + uint16 size; + vnp_raw_unpack_uint16(&buf[buffer_pos], &size); + for(i = 0; i < size; i++) + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &par[i]); + if(func_o_method_call != NULL) + func_o_method_call(v_fs_get_user_data(44), node_id, group_id, method_id, sender, par); + return buffer_pos; + } + + if(func_o_method_call != NULL) + func_o_method_call(v_fs_get_user_data(44), node_id, group_id, method_id, sender, params); + + return buffer_pos; +} + +void verse_send_o_anim_run(VNodeID node_id, uint16 link_id, uint32 time_s, uint32 time_f, uint8 dimensions, const real64 *pos, const real64 *speed, const real64 *accel, const real64 *scale, const real64 *scale_speed) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 45); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_anim_run(node_id = %u link_id = %u time_s = %u time_f = %u dimensions = %u pos = %p speed = %p accel = %p scale = %p scale_speed = %p );\n", node_id, link_id, time_s, time_f, dimensions, pos, speed, accel, scale, scale_speed); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], link_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], time_s); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], time_f); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], dimensions); + { + unsigned char mask = 0; + unsigned int cmd, i; + cmd = buffer_pos++; + if(dimensions > 4) + dimensions = 4; + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pos[i]); + if(speed != NULL) + { + mask |= 1; + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], speed[i]); + } + if(accel != NULL) + { + mask |= 2; + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], accel[i]); + } + if(scale != NULL) + { + mask |= 3; + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], scale[i]); + } + if(scale_speed != NULL) + { + mask |= 4; + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], scale_speed[i]); + } + vnp_raw_pack_uint8(&buf[cmd], mask); + } + if(node_id == (uint32) ~0u || link_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_anim_run(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_anim_run)(void *user_data, VNodeID node_id, uint16 link_id, uint32 time_s, uint32 time_f, uint8 dimensions, const real64 *pos, const real64 *speed, const real64 *accel, const real64 *scale, const real64 *scale_speed); + VNodeID node_id; + uint16 link_id; + uint32 time_s; + uint32 time_f; + uint8 dimensions; + const real64 *pos; + const real64 *speed; + const real64 *accel; + const real64 *scale; + const real64 *scale_speed; + + func_o_anim_run = v_fs_get_user_func(45); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &link_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &time_s); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &time_f); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &dimensions); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_o_anim_run(node_id = %u link_id = %u time_s = %u time_f = %u dimensions = %u ); callback = %p\n", node_id, link_id, time_s, time_f, dimensions, v_fs_get_user_func(45)); +#endif + { + double output[5][4]; + unsigned int i, j; + char mask, pow = 1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &mask); + if(dimensions > 4) + dimensions = 4; + for(j = 0; j < dimensions; j++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &output[0][j]); + for(i = 1; i < 5; i++) + { + if((mask & pow) != 0) + for(j = 0; j < dimensions; j++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &output[i][j]); + else + for(j = 0; j < dimensions; j++) + output[i][j] = 0; + pow *= 2; + } + if(func_o_anim_run != NULL) + func_o_anim_run(v_fs_get_user_data(45), node_id, link_id, time_s, time_f, dimensions, &output[0][0], &output[1][0], &output[2][0], &output[3][0], &output[4][0]); + return buffer_pos; + } + + if(func_o_anim_run != NULL) + func_o_anim_run(v_fs_get_user_data(45), node_id, link_id, time_s, time_f, dimensions, pos, speed, accel, scale, scale_speed); + + return buffer_pos; +} + +void verse_send_o_hide(VNodeID node_id, uint8 hidden) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 46); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_hide(node_id = %u hidden = %u );\n", node_id, hidden); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], hidden); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_hide(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_hide)(void *user_data, VNodeID node_id, uint8 hidden); + VNodeID node_id; + uint8 hidden; + + func_o_hide = v_fs_get_user_func(46); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &hidden); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_o_hide(node_id = %u hidden = %u ); callback = %p\n", node_id, hidden, v_fs_get_user_func(46)); +#endif + if(func_o_hide != NULL) + func_o_hide(v_fs_get_user_data(46), node_id, hidden); + + return buffer_pos; +} + +#endif + diff --git a/extern/verse/dist/v_gen_pack_s_node.c b/extern/verse/dist/v_gen_pack_s_node.c new file mode 100644 index 00000000000..6a9f4a05a0b --- /dev/null +++ b/extern/verse/dist/v_gen_pack_s_node.c @@ -0,0 +1,711 @@ +/* +** This is automatically generated source code -- do not edit. +** Changes are affected either by editing the corresponding protocol +** definition file (v_cmd_def_X.c where X=node type), or by editing +** the code generator itself, in v_cmd_gen.c. +*/ + +#include +#include + +#include "v_cmd_gen.h" +#if !defined(V_GENERATE_FUNC_MODE) +#include "verse.h" +#include "v_cmd_buf.h" +#include "v_network_out_que.h" +#include "v_network.h" +#include "v_connection.h" +#include "v_util.h" + +void verse_send_packet_ack(uint32 packet_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 7); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], packet_id); + v_cmd_buf_set_unique_address_size(head, buffer_pos); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_ack_nak_buf(v_con_get_network_queue(), head); + return; + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_packet_ack(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_packet_ack)(void *user_data, uint32 packet_id); + uint32 packet_id; + + func_packet_ack = v_fs_get_user_func(7); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &packet_id); +#if defined V_PRINT_RECEIVE_COMMANDS +#endif + if(func_packet_ack != NULL) + func_packet_ack(v_fs_get_user_data(7), packet_id); + + return buffer_pos; +} + +void verse_send_packet_nak(uint32 packet_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 8); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], packet_id); + v_cmd_buf_set_unique_address_size(head, buffer_pos); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_ack_nak_buf(v_con_get_network_queue(), head); + return; + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_packet_nak(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_packet_nak)(void *user_data, uint32 packet_id); + uint32 packet_id; + + func_packet_nak = v_fs_get_user_func(8); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &packet_id); +#if defined V_PRINT_RECEIVE_COMMANDS +#endif + if(func_packet_nak != NULL) + func_packet_nak(v_fs_get_user_data(8), packet_id); + + return buffer_pos; +} + +void verse_send_node_index_subscribe(uint32 mask) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 9); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_node_index_subscribe(mask = %u );\n", mask); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], mask); + if(mask == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_node_index_subscribe(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_node_index_subscribe)(void *user_data, uint32 mask); + uint32 mask; + + func_node_index_subscribe = v_fs_get_user_func(9); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &mask); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_node_index_subscribe(mask = %u ); callback = %p\n", mask, v_fs_get_user_func(9)); +#endif + if(func_node_index_subscribe != NULL) + func_node_index_subscribe(v_fs_get_user_data(9), mask); + + return buffer_pos; +} + +void verse_send_node_create(VNodeID node_id, VNodeType type, VNodeOwner owner) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 10); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_node_create(node_id = %u type = %u owner = %u );\n", node_id, type, owner); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)type); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)owner); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_node_destroy(VNodeID node_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 10); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_node_destroy(node_id = %u );\n", node_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)-1); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)-1); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_node_create(const char *buf, size_t buffer_length) +{ + uint8 enum_temp; + unsigned int buffer_pos = 0; + void (* func_node_create)(void *user_data, VNodeID node_id, VNodeType type, VNodeOwner owner); + VNodeID node_id; + VNodeType type; + VNodeOwner owner; + + func_node_create = v_fs_get_user_func(10); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp); + type = (VNodeType)enum_temp; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp); + owner = (VNodeOwner)enum_temp; +#if defined V_PRINT_RECEIVE_COMMANDS + if(owner == (uint8) ~0u || type >= V_NT_NUM_TYPES) + printf("receive: verse_send_node_destroy(node_id = %u ); callback = %p\n", node_id, v_fs_get_alias_user_func(10)); + else + printf("receive: verse_send_node_create(node_id = %u type = %u owner = %u ); callback = %p\n", node_id, type, owner, v_fs_get_user_func(10)); +#endif + if(owner == (uint8) ~0u || type >= V_NT_NUM_TYPES) + { + void (* alias_node_destroy)(void *user_data, VNodeID node_id); + alias_node_destroy = v_fs_get_alias_user_func(10); + if(alias_node_destroy != NULL) + alias_node_destroy(v_fs_get_alias_user_data(10), node_id); + return buffer_pos; + } + if(func_node_create != NULL) + func_node_create(v_fs_get_user_data(10), node_id, (VNodeType) type, (VNodeOwner) owner); + + return buffer_pos; +} + +void verse_send_node_subscribe(VNodeID node_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 11); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_node_subscribe(node_id = %u );\n", node_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], TRUE); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_node_unsubscribe(VNodeID node_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 11); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_node_unsubscribe(node_id = %u );\n", node_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], FALSE); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_node_subscribe(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_node_subscribe)(void *user_data, VNodeID node_id); + VNodeID node_id; + uint8 alias_bool; + + func_node_subscribe = v_fs_get_user_func(11); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + if(buffer_length < buffer_pos + 1) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &alias_bool); +#if defined V_PRINT_RECEIVE_COMMANDS + if(!alias_bool) + printf("receive: verse_send_node_unsubscribe(node_id = %u ); callback = %p\n", node_id, v_fs_get_alias_user_func(11)); + else + printf("receive: verse_send_node_subscribe(node_id = %u ); callback = %p\n", node_id, v_fs_get_user_func(11)); +#endif + if(!alias_bool) + { + void (* alias_node_unsubscribe)(void *user_data, VNodeID node_id); + alias_node_unsubscribe = v_fs_get_alias_user_func(11); + if(alias_node_unsubscribe != NULL) + alias_node_unsubscribe(v_fs_get_alias_user_data(11), node_id); + return buffer_pos; + } + if(func_node_subscribe != NULL) + func_node_subscribe(v_fs_get_user_data(11), node_id); + + return buffer_pos; +} + +void verse_send_tag_group_create(VNodeID node_id, uint16 group_id, const char *name) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 16); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_tag_group_create(node_id = %u group_id = %u name = %s );\n", node_id, group_id, name); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], name, 16); + if(node_id == (uint32) ~0u || group_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_tag_group_destroy(VNodeID node_id, uint16 group_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 16); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_tag_group_destroy(node_id = %u group_id = %u );\n", node_id, group_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + if(node_id == (uint32) ~0u || group_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_tag_group_create(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_tag_group_create)(void *user_data, VNodeID node_id, uint16 group_id, const char *name); + VNodeID node_id; + uint16 group_id; + char name[16]; + + func_tag_group_create = v_fs_get_user_func(16); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &group_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], name, 16, buffer_length - buffer_pos); +#if defined V_PRINT_RECEIVE_COMMANDS + if(name[0] == 0) + printf("receive: verse_send_tag_group_destroy(node_id = %u group_id = %u ); callback = %p\n", node_id, group_id, v_fs_get_alias_user_func(16)); + else + printf("receive: verse_send_tag_group_create(node_id = %u group_id = %u name = %s ); callback = %p\n", node_id, group_id, name, v_fs_get_user_func(16)); +#endif + if(name[0] == 0) + { + void (* alias_tag_group_destroy)(void *user_data, VNodeID node_id, uint16 group_id); + alias_tag_group_destroy = v_fs_get_alias_user_func(16); + if(alias_tag_group_destroy != NULL) + alias_tag_group_destroy(v_fs_get_alias_user_data(16), node_id, group_id); + return buffer_pos; + } + if(func_tag_group_create != NULL) + func_tag_group_create(v_fs_get_user_data(16), node_id, group_id, name); + + return buffer_pos; +} + +void verse_send_tag_group_subscribe(VNodeID node_id, uint16 group_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 17); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_tag_group_subscribe(node_id = %u group_id = %u );\n", node_id, group_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], TRUE); + if(node_id == (uint32) ~0u || group_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_tag_group_unsubscribe(VNodeID node_id, uint16 group_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 17); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_tag_group_unsubscribe(node_id = %u group_id = %u );\n", node_id, group_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], FALSE); + if(node_id == (uint32) ~0u || group_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_tag_group_subscribe(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_tag_group_subscribe)(void *user_data, VNodeID node_id, uint16 group_id); + VNodeID node_id; + uint16 group_id; + uint8 alias_bool; + + func_tag_group_subscribe = v_fs_get_user_func(17); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &group_id); + if(buffer_length < buffer_pos + 1) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &alias_bool); +#if defined V_PRINT_RECEIVE_COMMANDS + if(!alias_bool) + printf("receive: verse_send_tag_group_unsubscribe(node_id = %u group_id = %u ); callback = %p\n", node_id, group_id, v_fs_get_alias_user_func(17)); + else + printf("receive: verse_send_tag_group_subscribe(node_id = %u group_id = %u ); callback = %p\n", node_id, group_id, v_fs_get_user_func(17)); +#endif + if(!alias_bool) + { + void (* alias_tag_group_unsubscribe)(void *user_data, VNodeID node_id, uint16 group_id); + alias_tag_group_unsubscribe = v_fs_get_alias_user_func(17); + if(alias_tag_group_unsubscribe != NULL) + alias_tag_group_unsubscribe(v_fs_get_alias_user_data(17), node_id, group_id); + return buffer_pos; + } + if(func_tag_group_subscribe != NULL) + func_tag_group_subscribe(v_fs_get_user_data(17), node_id, group_id); + + return buffer_pos; +} + +void verse_send_tag_create(VNodeID node_id, uint16 group_id, uint16 tag_id, const char *name, VNTagType type, const VNTag *tag) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 18); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_tag_create(node_id = %u group_id = %u tag_id = %u name = %s type = %u tag = %p );\n", node_id, group_id, tag_id, name, type, tag); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], tag_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], name, 16); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)type); + if(type > VN_TAG_BLOB) + { + v_cmd_buf_free(head); + return; + } + switch(type) + { + case VN_TAG_BOOLEAN : + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], ((VNTag *)tag)->vboolean); + break; + case VN_TAG_UINT32 : + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], ((VNTag *)tag)->vuint32); + break; + case VN_TAG_REAL64 : + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], ((VNTag *)tag)->vreal64); + break; + case VN_TAG_STRING : + { + unsigned int i; + for(i = 0; ((VNTag *)tag)->vstring[i] != 0 && i < VN_TAG_MAX_BLOB_SIZE; i++) + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], ((VNTag *)tag)->vstring[i]); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 0); + } + break; + case VN_TAG_REAL64_VEC3 : + { + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], ((VNTag *)tag)->vreal64_vec3[0]); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], ((VNTag *)tag)->vreal64_vec3[1]); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], ((VNTag *)tag)->vreal64_vec3[2]); + } + break; + case VN_TAG_LINK : + { + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], ((VNTag *)tag)->vlink); + } + break; + case VN_TAG_ANIMATION : + { + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], ((VNTag *)tag)->vanimation.curve); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], ((VNTag *)tag)->vanimation.start); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], ((VNTag *)tag)->vanimation.end); + } + break; + case VN_TAG_BLOB : + { + unsigned int i; + if(((VNTag *)tag)->vblob.size > VN_TAG_MAX_BLOB_SIZE) + ((VNTag *)tag)->vblob.size = VN_TAG_MAX_BLOB_SIZE; + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], ((VNTag *)tag)->vblob.size); + for(i = 0; i < ((VNTag *)tag)->vblob.size; i++) + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], ((uint8 *)((VNTag *)tag)->vblob.blob)[i]); + } + break; + default : + ; + } + if(node_id == (uint32) ~0u || group_id == (uint16) ~0u || tag_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 9); + else + v_cmd_buf_set_address_size(head, 9); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_tag_destroy(VNodeID node_id, uint16 group_id, uint16 tag_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 18); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_tag_destroy(node_id = %u group_id = %u tag_id = %u );\n", node_id, group_id, tag_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], tag_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)-1); + if(node_id == (uint32) ~0u || group_id == (uint16) ~0u || tag_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 9); + else + v_cmd_buf_set_address_size(head, 9); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_tag_create(const char *buf, size_t buffer_length) +{ + uint8 enum_temp; + unsigned int buffer_pos = 0; + void (* func_tag_create)(void *user_data, VNodeID node_id, uint16 group_id, uint16 tag_id, const char *name, VNTagType type, const VNTag *tag); + VNodeID node_id; + uint16 group_id; + uint16 tag_id; + char name[16]; + VNTagType type; + const VNTag *tag; + + func_tag_create = v_fs_get_user_func(18); + if(buffer_length < 8) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &group_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &tag_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], name, 16, buffer_length - buffer_pos); + if(buffer_length < 1 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp); + type = (VNTagType)enum_temp; +#if defined V_PRINT_RECEIVE_COMMANDS + if(type >= VN_TAG_TYPE_COUNT) + printf("receive: verse_send_tag_destroy(node_id = %u group_id = %u tag_id = %u ); callback = %p\n", node_id, group_id, tag_id, v_fs_get_alias_user_func(18)); + else + printf("receive: verse_send_tag_create(node_id = %u group_id = %u tag_id = %u name = %s type = %u ); callback = %p\n", node_id, group_id, tag_id, name, type, v_fs_get_user_func(18)); +#endif + if(type < VN_TAG_TYPE_COUNT) + { + VNTag tag; + unsigned int i; + char string[VN_TAG_MAX_BLOB_SIZE]; + switch(type) + { + case VN_TAG_BOOLEAN : + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &tag.vboolean); + break; + case VN_TAG_UINT32 : + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &tag.vuint32); + break; + case VN_TAG_REAL64 : + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &tag.vreal64); + break; + case VN_TAG_STRING : + { + tag.vstring = string; + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], string, VN_TAG_MAX_BLOB_SIZE, buffer_length - buffer_pos); + } + break; + case VN_TAG_REAL64_VEC3 : + { + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &tag.vreal64_vec3[0]); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &tag.vreal64_vec3[1]); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &tag.vreal64_vec3[2]); + } + break; + case VN_TAG_LINK : + { + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &tag.vlink); + } + break; + case VN_TAG_ANIMATION : + { + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &tag.vanimation.curve); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &tag.vanimation.start); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &tag.vanimation.end); + } + break; + case VN_TAG_BLOB : + { + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &tag.vblob.size); + if(tag.vblob.size > VN_TAG_MAX_BLOB_SIZE) + tag.vblob.size = VN_TAG_MAX_BLOB_SIZE; + tag.vblob.blob = string; + for(i = 0; i < tag.vblob.size; i++) + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &string[i]); + } + break; + default : + ; + } + if(func_tag_create != NULL) + func_tag_create(v_fs_get_user_data(18), node_id, group_id, tag_id, name, type, &tag); + return buffer_pos; + } + + if(type >= VN_TAG_TYPE_COUNT) + { + void (* alias_tag_destroy)(void *user_data, VNodeID node_id, uint16 group_id, uint16 tag_id); + alias_tag_destroy = v_fs_get_alias_user_func(18); + if(alias_tag_destroy != NULL) + alias_tag_destroy(v_fs_get_alias_user_data(18), node_id, group_id, tag_id); + return buffer_pos; + } + if(func_tag_create != NULL) + func_tag_create(v_fs_get_user_data(18), node_id, group_id, tag_id, name, (VNTagType) type, tag); + + return buffer_pos; +} + +void verse_send_node_name_set(VNodeID node_id, const char *name) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 19); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_node_name_set(node_id = %u name = %s );\n", node_id, name); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], name, 512); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_node_name_set(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_node_name_set)(void *user_data, VNodeID node_id, const char *name); + VNodeID node_id; + char name[512]; + + func_node_name_set = v_fs_get_user_func(19); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], name, 512, buffer_length - buffer_pos); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_node_name_set(node_id = %u name = %s ); callback = %p\n", node_id, name, v_fs_get_user_func(19)); +#endif + if(func_node_name_set != NULL) + func_node_name_set(v_fs_get_user_data(19), node_id, name); + + return buffer_pos; +} + +#endif + diff --git a/extern/verse/dist/v_gen_pack_t_node.c b/extern/verse/dist/v_gen_pack_t_node.c new file mode 100644 index 00000000000..0cfbf8b7f21 --- /dev/null +++ b/extern/verse/dist/v_gen_pack_t_node.c @@ -0,0 +1,226 @@ +/* +** This is automatically generated source code -- do not edit. +** Changes are affected either by editing the corresponding protocol +** definition file (v_cmd_def_X.c where X=node type), or by editing +** the code generator itself, in v_cmd_gen.c. +*/ + +#include +#include + +#include "v_cmd_gen.h" +#if !defined(V_GENERATE_FUNC_MODE) +#include "verse.h" +#include "v_cmd_buf.h" +#include "v_network_out_que.h" +#include "v_network.h" +#include "v_connection.h" +#include "v_util.h" + +void verse_send_t_language_set(VNodeID node_id, const char *language) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 96); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_t_language_set(node_id = %u language = %s );\n", node_id, language); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], language, 512); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_t_language_set(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_t_language_set)(void *user_data, VNodeID node_id, const char *language); + VNodeID node_id; + char language[512]; + + func_t_language_set = v_fs_get_user_func(96); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], language, 512, buffer_length - buffer_pos); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_t_language_set(node_id = %u language = %s ); callback = %p\n", node_id, language, v_fs_get_user_func(96)); +#endif + if(func_t_language_set != NULL) + func_t_language_set(v_fs_get_user_data(96), node_id, language); + + return buffer_pos; +} + +void verse_send_t_buffer_create(VNodeID node_id, VBufferID buffer_id, const char *name) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 97); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_t_buffer_create(node_id = %u buffer_id = %u name = %s );\n", node_id, buffer_id, name); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], buffer_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], name, 16); + if(node_id == (uint32) ~0u || buffer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_t_buffer_destroy(VNodeID node_id, VBufferID buffer_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 97); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_t_buffer_destroy(node_id = %u buffer_id = %u );\n", node_id, buffer_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], buffer_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + if(node_id == (uint32) ~0u || buffer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_t_buffer_create(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_t_buffer_create)(void *user_data, VNodeID node_id, VBufferID buffer_id, const char *name); + VNodeID node_id; + VBufferID buffer_id; + char name[16]; + + func_t_buffer_create = v_fs_get_user_func(97); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &buffer_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], name, 16, buffer_length - buffer_pos); +#if defined V_PRINT_RECEIVE_COMMANDS + if(name[0] == 0) + printf("receive: verse_send_t_buffer_destroy(node_id = %u buffer_id = %u ); callback = %p\n", node_id, buffer_id, v_fs_get_alias_user_func(97)); + else + printf("receive: verse_send_t_buffer_create(node_id = %u buffer_id = %u name = %s ); callback = %p\n", node_id, buffer_id, name, v_fs_get_user_func(97)); +#endif + if(name[0] == 0) + { + void (* alias_t_buffer_destroy)(void *user_data, VNodeID node_id, VBufferID buffer_id); + alias_t_buffer_destroy = v_fs_get_alias_user_func(97); + if(alias_t_buffer_destroy != NULL) + alias_t_buffer_destroy(v_fs_get_alias_user_data(97), node_id, buffer_id); + return buffer_pos; + } + if(func_t_buffer_create != NULL) + func_t_buffer_create(v_fs_get_user_data(97), node_id, buffer_id, name); + + return buffer_pos; +} + +void verse_send_t_buffer_subscribe(VNodeID node_id, VBufferID buffer_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 98); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_t_buffer_subscribe(node_id = %u buffer_id = %u );\n", node_id, buffer_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], buffer_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], TRUE); + if(node_id == (uint32) ~0u || buffer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_t_buffer_unsubscribe(VNodeID node_id, VBufferID buffer_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 98); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_t_buffer_unsubscribe(node_id = %u buffer_id = %u );\n", node_id, buffer_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], buffer_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], FALSE); + if(node_id == (uint32) ~0u || buffer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_t_buffer_subscribe(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_t_buffer_subscribe)(void *user_data, VNodeID node_id, VBufferID buffer_id); + VNodeID node_id; + VBufferID buffer_id; + uint8 alias_bool; + + func_t_buffer_subscribe = v_fs_get_user_func(98); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &buffer_id); + if(buffer_length < buffer_pos + 1) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &alias_bool); +#if defined V_PRINT_RECEIVE_COMMANDS + if(!alias_bool) + printf("receive: verse_send_t_buffer_unsubscribe(node_id = %u buffer_id = %u ); callback = %p\n", node_id, buffer_id, v_fs_get_alias_user_func(98)); + else + printf("receive: verse_send_t_buffer_subscribe(node_id = %u buffer_id = %u ); callback = %p\n", node_id, buffer_id, v_fs_get_user_func(98)); +#endif + if(!alias_bool) + { + void (* alias_t_buffer_unsubscribe)(void *user_data, VNodeID node_id, VBufferID buffer_id); + alias_t_buffer_unsubscribe = v_fs_get_alias_user_func(98); + if(alias_t_buffer_unsubscribe != NULL) + alias_t_buffer_unsubscribe(v_fs_get_alias_user_data(98), node_id, buffer_id); + return buffer_pos; + } + if(func_t_buffer_subscribe != NULL) + func_t_buffer_subscribe(v_fs_get_user_data(98), node_id, buffer_id); + + return buffer_pos; +} + +#endif + diff --git a/extern/verse/dist/v_gen_unpack_func.h b/extern/verse/dist/v_gen_unpack_func.h new file mode 100644 index 00000000000..462777608c7 --- /dev/null +++ b/extern/verse/dist/v_gen_unpack_func.h @@ -0,0 +1,63 @@ +extern unsigned int v_unpack_connect(const char *data, size_t length); +extern unsigned int v_unpack_connect_accept(const char *data, size_t length); +extern unsigned int v_unpack_connect_terminate(const char *data, size_t length); +extern unsigned int v_unpack_ping(const char *data, size_t length); +extern unsigned int v_unpack_packet_ack(const char *data, size_t length); +extern unsigned int v_unpack_packet_nak(const char *data, size_t length); +extern unsigned int v_unpack_node_index_subscribe(const char *data, size_t length); +extern unsigned int v_unpack_node_create(const char *data, size_t length); +extern unsigned int v_unpack_node_subscribe(const char *data, size_t length); +extern unsigned int v_unpack_tag_group_create(const char *data, size_t length); +extern unsigned int v_unpack_tag_group_subscribe(const char *data, size_t length); +extern unsigned int v_unpack_tag_create(const char *data, size_t length); +extern unsigned int v_unpack_node_name_set(const char *data, size_t length); +extern unsigned int v_unpack_o_transform_pos_real32(const char *data, size_t length); +extern unsigned int v_unpack_o_transform_rot_real32(const char *data, size_t length); +extern unsigned int v_unpack_o_transform_scale_real32(const char *data, size_t length); +extern unsigned int v_unpack_o_transform_pos_real64(const char *data, size_t length); +extern unsigned int v_unpack_o_transform_rot_real64(const char *data, size_t length); +extern unsigned int v_unpack_o_transform_scale_real64(const char *data, size_t length); +extern unsigned int v_unpack_o_transform_subscribe(const char *data, size_t length); +extern unsigned int v_unpack_o_light_set(const char *data, size_t length); +extern unsigned int v_unpack_o_link_set(const char *data, size_t length); +extern unsigned int v_unpack_o_method_group_create(const char *data, size_t length); +extern unsigned int v_unpack_o_method_group_subscribe(const char *data, size_t length); +extern unsigned int v_unpack_o_method_create(const char *data, size_t length); +extern unsigned int v_unpack_o_method_call(const char *data, size_t length); +extern unsigned int v_unpack_o_anim_run(const char *data, size_t length); +extern unsigned int v_unpack_o_hide(const char *data, size_t length); +extern unsigned int v_unpack_g_layer_create(const char *data, size_t length); +extern unsigned int v_unpack_g_layer_subscribe(const char *data, size_t length); +extern unsigned int v_unpack_g_vertex_set_xyz_real32(const char *data, size_t length); +extern unsigned int v_unpack_g_vertex_set_xyz_real64(const char *data, size_t length); +extern unsigned int v_unpack_g_vertex_set_uint32(const char *data, size_t length); +extern unsigned int v_unpack_g_vertex_set_real64(const char *data, size_t length); +extern unsigned int v_unpack_g_vertex_set_real32(const char *data, size_t length); +extern unsigned int v_unpack_g_polygon_set_corner_uint32(const char *data, size_t length); +extern unsigned int v_unpack_g_polygon_set_corner_real64(const char *data, size_t length); +extern unsigned int v_unpack_g_polygon_set_corner_real32(const char *data, size_t length); +extern unsigned int v_unpack_g_polygon_set_face_uint8(const char *data, size_t length); +extern unsigned int v_unpack_g_polygon_set_face_uint32(const char *data, size_t length); +extern unsigned int v_unpack_g_polygon_set_face_real64(const char *data, size_t length); +extern unsigned int v_unpack_g_polygon_set_face_real32(const char *data, size_t length); +extern unsigned int v_unpack_g_crease_set_vertex(const char *data, size_t length); +extern unsigned int v_unpack_g_crease_set_edge(const char *data, size_t length); +extern unsigned int v_unpack_g_bone_create(const char *data, size_t length); +extern unsigned int v_unpack_m_fragment_create(const char *data, size_t length); +extern unsigned int v_unpack_b_dimensions_set(const char *data, size_t length); +extern unsigned int v_unpack_b_layer_create(const char *data, size_t length); +extern unsigned int v_unpack_b_layer_subscribe(const char *data, size_t length); +extern unsigned int v_unpack_b_tile_set(const char *data, size_t length); +extern unsigned int v_unpack_t_language_set(const char *data, size_t length); +extern unsigned int v_unpack_t_buffer_create(const char *data, size_t length); +extern unsigned int v_unpack_t_buffer_subscribe(const char *data, size_t length); +extern unsigned int v_unpack_t_text_set(const char *data, size_t length); +extern unsigned int v_unpack_c_curve_create(const char *data, size_t length); +extern unsigned int v_unpack_c_curve_subscribe(const char *data, size_t length); +extern unsigned int v_unpack_c_key_set(const char *data, size_t length); +extern unsigned int v_unpack_a_buffer_create(const char *data, size_t length); +extern unsigned int v_unpack_a_buffer_subscribe(const char *data, size_t length); +extern unsigned int v_unpack_a_block_set(const char *data, size_t length); +extern unsigned int v_unpack_a_stream_create(const char *data, size_t length); +extern unsigned int v_unpack_a_stream_subscribe(const char *data, size_t length); +extern unsigned int v_unpack_a_stream(const char *data, size_t length); diff --git a/extern/verse/dist/v_gen_unpack_funcs.h b/extern/verse/dist/v_gen_unpack_funcs.h new file mode 100644 index 00000000000..e69de29bb2d diff --git a/extern/verse/dist/v_internal_verse.h b/extern/verse/dist/v_internal_verse.h new file mode 100644 index 00000000000..ce838351437 --- /dev/null +++ b/extern/verse/dist/v_internal_verse.h @@ -0,0 +1,2 @@ +extern void verse_send_packet_ack(uint32 packet_id); +extern void verse_send_packet_nak(uint32 packet_id); diff --git a/extern/verse/dist/v_man_pack_node.c b/extern/verse/dist/v_man_pack_node.c new file mode 100644 index 00000000000..cc85c4383df --- /dev/null +++ b/extern/verse/dist/v_man_pack_node.c @@ -0,0 +1,498 @@ +/* +** +*/ + +#include +#include +#include + +#include "v_cmd_gen.h" + +#if !defined V_GENERATE_FUNC_MODE + +#include "verse.h" +#include "v_cmd_buf.h" +#include "v_network_out_que.h" +#include "v_network.h" +#include "v_connection.h" +#include "v_encryption.h" + +unsigned int v_unpack_connect(const char *buf, unsigned int buffer_length) +{ + return -1; /* this command is illegal to send */ +} + +unsigned int v_unpack_connect_accept(const char *buf, unsigned int buffer_length) +{ + return -1; /* this command is illegal to send */ +} + +extern void v_callback_connect_terminate(const char *bye); + +unsigned int v_unpack_connect_terminate(const char *buf, unsigned int buffer_length) +{ + unsigned int buffer_pos = 0; + char bye[512]; + + buffer_pos = vnp_raw_unpack_string(buf, bye, sizeof bye, buffer_length); + v_callback_connect_terminate(bye); + + return buffer_pos; +} + +static unsigned int pack_b_tile_set_head(VCMDBufHead *head, VNodeID node_id, VLayerID layer_id, uint16 tile_x, uint16 tile_y, uint16 z, VNBLayerType type, const VNBTile *tile) +{ + unsigned int buffer_pos = 0; + uint8 *buf; + buf = ((VCMDBuffer30 *)head)->buf; + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 83); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_b_tile_set(node_id = %u layer_id = %u tile_x = %u tile_y = %u z = %u type = %u tile = %p );\n", node_id, layer_id, tile_x, tile_y, z, type, tile); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], tile_x); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], tile_y); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], z); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)type); + return buffer_pos; + v_cmd_buf_set_address_size(head, 13); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_b_tile_set(VNodeID node_id, VLayerID layer_id, uint16 tile_x, uint16 tile_y, uint16 z, VNBLayerType type, const VNBTile *tile) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + + switch(type) + { + case VN_B_LAYER_UINT1 : + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer30 *)head)->buf; + buffer_pos += pack_b_tile_set_head(head, node_id, layer_id, tile_x, tile_y, z, type, tile); + buffer_pos += vnp_raw_pack_uint8_vector(&buf[buffer_pos], tile->vuint1, VN_B_TILE_SIZE * VN_B_TILE_SIZE / 8); + break; + case VN_B_LAYER_UINT8 : + head = v_cmd_buf_allocate(VCMDBS_80);/* Allocating the buffer */ + buf = ((VCMDBuffer80 *)head)->buf; + buffer_pos += pack_b_tile_set_head(head, node_id, layer_id, tile_x, tile_y, z, type, tile); + buffer_pos += vnp_raw_pack_uint8_vector(&buf[buffer_pos], tile->vuint8, VN_B_TILE_SIZE * VN_B_TILE_SIZE); + break; + case VN_B_LAYER_UINT16 : + head = v_cmd_buf_allocate(VCMDBS_160);/* Allocating the buffer */ + buf = ((VCMDBuffer160 *)head)->buf; + buffer_pos += pack_b_tile_set_head(head, node_id, layer_id, tile_x, tile_y, z, type, tile); + buffer_pos += vnp_raw_pack_uint16_vector(&buf[buffer_pos], tile->vuint16, VN_B_TILE_SIZE * VN_B_TILE_SIZE); + break; + case VN_B_LAYER_REAL32 : + head = v_cmd_buf_allocate(VCMDBS_320);/* Allocating the buffer */ + buf = ((VCMDBuffer320 *)head)->buf; + buffer_pos += pack_b_tile_set_head(head, node_id, layer_id, tile_x, tile_y, z, type, tile); + buffer_pos += vnp_raw_pack_real32_vector(&buf[buffer_pos], tile->vreal32, VN_B_TILE_SIZE * VN_B_TILE_SIZE); + break; + case VN_B_LAYER_REAL64 : + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + buffer_pos += pack_b_tile_set_head(head, node_id, layer_id, tile_x, tile_y, z, type, tile); + buffer_pos += vnp_raw_pack_real64_vector(&buf[buffer_pos], tile->vreal64, VN_B_TILE_SIZE * VN_B_TILE_SIZE); + break; + default: + head = NULL; + } + v_cmd_buf_set_address_size(head, 13); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_b_tile_set(const char *buf, size_t buffer_length) +{ + uint8 enum_temp; + unsigned int buffer_pos = 0; + void (* func_b_tile_set)(void *user_data, VNodeID node_id, VLayerID layer_id, uint16 tile_x, uint16 tile_y, uint16 z, VNBLayerType type, const VNBTile *tile); + VNodeID node_id; + VLayerID layer_id; + uint16 tile_x; + uint16 tile_y; + uint16 z; + VNBLayerType type; + const VNBTile *tile; + + func_b_tile_set = v_fs_get_user_func(83); + if(buffer_length < 12) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &tile_x); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &tile_y); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &z); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp); + type = (VNBLayerType)enum_temp; +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_b_tile_set(node_id = %u layer_id = %u tile_x = %u tile_y = %u z = %u type = %u ); callback = %p\n", node_id, layer_id, tile_x, tile_y, z, type, v_fs_get_user_func(83)); +#endif + { + VNBTile tile; + switch(type) + { + case VN_B_LAYER_UINT1 : + buffer_pos += vnp_raw_unpack_uint8_vector(&buf[buffer_pos], tile.vuint1, VN_B_TILE_SIZE * VN_B_TILE_SIZE / 8); + break; + case VN_B_LAYER_UINT8 : + buffer_pos += vnp_raw_unpack_uint8_vector(&buf[buffer_pos], tile.vuint8, VN_B_TILE_SIZE * VN_B_TILE_SIZE); + break; + case VN_B_LAYER_UINT16 : + buffer_pos += vnp_raw_unpack_uint16_vector(&buf[buffer_pos], tile.vuint16, VN_B_TILE_SIZE * VN_B_TILE_SIZE); + break; + case VN_B_LAYER_REAL32 : + buffer_pos += vnp_raw_unpack_real32_vector(&buf[buffer_pos], tile.vreal32, VN_B_TILE_SIZE * VN_B_TILE_SIZE); + break; + case VN_B_LAYER_REAL64 : + buffer_pos += vnp_raw_unpack_real64_vector(&buf[buffer_pos], tile.vreal64, VN_B_TILE_SIZE * VN_B_TILE_SIZE); + break; + } + if(func_b_tile_set != NULL && type <= VN_B_LAYER_REAL64) + func_b_tile_set(v_fs_get_user_data(83), node_id, layer_id, tile_x, tile_y, z, type, &tile); + return buffer_pos; + } + + if(func_b_tile_set != NULL) + func_b_tile_set(v_fs_get_user_data(83), node_id, layer_id, tile_x, tile_y, z, (VNBLayerType)type, tile); + + return buffer_pos; +} + +typedef struct VTempText VTempText; + +struct VTempText { + VNodeID node_id; + VBufferID buffer_id; + uint32 pos; + uint32 length; + uint16 index; + char *text; + VTempText *next; +}; + +typedef struct { + VTempText *text_temp; + uint16 text_send_id; + uint16 text_receive_id; +} VOrderedStorage; + +VOrderedStorage * v_create_ordered_storage(void) +{ + VOrderedStorage *s; + + s = malloc(sizeof *s); + s->text_temp = NULL; + s->text_send_id = 0; + s->text_receive_id = 0; + return s; +} + +void v_destroy_ordered_storage(VOrderedStorage *s) +{ + VTempText *line, *next; + + for(line = s->text_temp; line != NULL; line = next) + { + next = line->next; + if(line->text != NULL) + free(line->text); + free(line); + } + free(s); +} + +void verse_send_t_text_set(VNodeID node_id, VBufferID buffer_id, uint32 pos, uint32 length, const char *text) +{ + uint8 *buf; + VOrderedStorage *s; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 99);/* Packing the command */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_t_text_set(node_id = %u buffer_id = %u pos = %u length = %u text = %s );\n", node_id, buffer_id, pos, length, text); +#endif + s = v_con_get_ordered_storage(); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], buffer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], pos); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], length); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], s->text_send_id++); + if(text == NULL) + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 0); + else + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], text, VN_T_MAX_TEXT_CMD_SIZE); + v_cmd_buf_set_unique_address_size(head, buffer_pos); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +static void call_text_set(VTempText *line) +{ + const char *t; + void (* func_t_text_set)(void *user_data, VNodeID node_id, VBufferID buffer_id, uint32 pos, uint16 length, const char *text); + + func_t_text_set = v_fs_get_user_func(99); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_t_text_set(node_id = %u buffer_id = %u pos = %u length = %u text = %s ); callback = %p\n", line->node_id, line->buffer_id, line->pos, line->length, line->text, v_fs_get_user_func(99)); +#endif + if(line->text == NULL) + t = ""; + else + t = line->text; + if(func_t_text_set != NULL) + func_t_text_set(v_fs_get_user_data(99), line->node_id, line->buffer_id, line->pos, line->length, t); +} + +unsigned int v_unpack_t_text_set(const char *buf, size_t buffer_length) +{ + unsigned int i, buffer_pos = 0; + VOrderedStorage *s; + VTempText l, *line, *past = NULL; + char text[1500]; + + if(buffer_length < 12) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &l.node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &l.buffer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &l.pos); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &l.length); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &l.index); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], text, sizeof text, buffer_length - buffer_pos); + if(text[0] == 0) + l.text = NULL; + else + l.text = text; + s = v_con_get_ordered_storage(); + if(s->text_receive_id == l.index) + { + call_text_set(&l); + s->text_receive_id++; + line = s->text_temp; + while(line != NULL) + { + if(line->index == s->text_receive_id) + { + call_text_set(line); + if(past == NULL) + s->text_temp = line->next; + else + past->next = line->next; + if(line->text != NULL) + free(line->text); + past = NULL; + free(line); + line = s->text_temp; + s->text_receive_id++; + } + else + { + past = line; + line = line->next; + } + } + } + else + { + line = malloc(sizeof *line); + *line = l; + line->next = s->text_temp; + s->text_temp = line; + i = strlen(text); + if(i > 0) + { + line->text = malloc(i + 1); + strcpy(line->text, text); + } + else + line->text = NULL; + } + return buffer_pos; +} + +void verse_send_c_key_set(VNodeID node_id, VLayerID curve_id, uint32 key_id, uint8 dimensions, + const real64 *pre_value, const uint32 *pre_pos, + const real64 *value, real64 pos, + const real64 *post_value, const uint32 *post_pos) +{ + uint8 *buf; + unsigned int i, buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + if(dimensions == 0 || dimensions > 4) + return; + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 130);/* Packing the command */ +#if defined V_PRINT_SEND_COMMANDS + switch(dimensions) + { + case 1: + printf("send: verse_send_c_key_set(node_id = %u curve_id = %u key_id = %u dimensions = %u pre_value = %f pre_pos = %u value = %f pos = %f, pre_value = %f pre_pos = %u ); callback = %p\n", node_id, curve_id, key_id, dimensions, pre_value[0], pre_pos[0], value[0], pos, pre_value[0], pre_pos[0], v_fs_get_user_func(130)); + break; + case 2: + printf("sende: verse_send_c_key_set(node_id = %u curve_id = %u key_id = %u dimensions = %u pre_value = {%f, %f} pre_pos = {%u, %u} value = {%f, %f} pos = %f, pre_value = {%f, %f} pre_pos = {%u, %u}); callback = %p\n", + node_id, curve_id, key_id, dimensions, + pre_value[0], pre_value[1], + pre_pos[0], pre_pos[1], + value[0], value[1], pos, + pre_value[0], pre_value[1], + pre_pos[0], pre_pos[1], v_fs_get_user_func(130)); + break; + case 3: + printf("send: verse_send_c_key_set(node_id = %u curve_id = %u key_id = %u dimensions = %u pre_value = {%f, %f, %f} pre_pos = {%u, %u, %u} value = {%f, %f, %f} pos = %f, pre_value = {%f, %f, %f} pre_pos = {%u, %u, %u}); callback = %p\n", + node_id, curve_id, key_id, dimensions, + pre_value[0], pre_value[1], pre_value[2], + pre_pos[0], pre_pos[1], pre_pos[2], + value[0], value[1], value[2], pos, + pre_value[0], pre_value[1], pre_value[2], + pre_pos[0], pre_pos[1], pre_pos[2], v_fs_get_user_func(130)); + + break; + case 4: + printf("send: verse_send_c_key_set(node_id = %u curve_id = %u key_id = %u dimensions = %u pre_value = {%f, %f, %f, %f} pre_pos = {%u, %u, %u, %u} value = {%f, %f, %f, %f} pos = %f, pre_value = {%f, %f, %f, %f} pre_pos = {%u, %u, %u, %u}); callback = %p\n", + node_id, curve_id, key_id, dimensions, + pre_value[0], pre_value[1], pre_value[2], pre_value[3], + pre_pos[0], pre_pos[1], pre_pos[2], pre_pos[3], + value[0], value[1], value[2], value[3], pos, + pre_value[0], pre_value[1], pre_value[2], pre_value[3], + pre_pos[0], pre_pos[1], pre_pos[2], pre_pos[3], v_fs_get_user_func(130)); + break; + } +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], curve_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], key_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], dimensions); + + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pre_value[i]); + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], pre_pos[i]); + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], value[i]); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pos); + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], post_value[i]); + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], post_pos[i]); + + if(key_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_c_key_destroy(VNodeID node_id, VLayerID curve_id, uint32 key_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 130);/* Packing the command */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_c_key_destroy(node_id = %u curve_id = %u key_id = %u );\n", node_id, curve_id, key_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], curve_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], key_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 0); + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_c_key_set(const char *buf, size_t buffer_length) +{ + unsigned int i, buffer_pos = 0; + VNodeID node_id; + VLayerID curve_id; + uint32 key_id; + uint8 dimensions; + real64 pre_value[4], value[4], pos, post_value[4]; + uint32 post_pos[4], pre_pos[4]; + + if(buffer_length < 11) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &curve_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &key_id); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &dimensions); + if(dimensions != 0 && dimensions < 5) + { + void (* func_c_key_set)(void *user_data, VNodeID node_id, VLayerID curve_id, uint32 key_id, uint8 dimensions, real64 *pre_value, uint32 *pre_pos, real64 *value, real64 pos, real64 *post_value, uint32 *post_pos); + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &pre_value[i]); + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &pre_pos[i]); + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &value[i]); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &pos); + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &post_value[i]); + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &post_pos[i]); + #if defined V_PRINT_RECEIVE_COMMANDS + switch(dimensions) + { + case 1: + printf("receive: verse_send_c_key_set(node_id = %u curve_id = %u key_id = %u dimensions = %u pre_value = %f pre_pos = %u value = %f pos = %f, pre_value = %f pre_pos = %u ); callback = %p\n", node_id, curve_id, key_id, dimensions, pre_value[0], pre_pos[0], value[0], pos, pre_value[0], pre_pos[0], v_fs_get_user_func(130)); + break; + case 2: + printf("receive: verse_send_c_key_set(node_id = %u curve_id = %u key_id = %u dimensions = %u pre_value = {%f, %f} pre_pos = {%u, %u} value = {%f, %f} pos = %f, pre_value = {%f, %f} pre_pos = {%u, %u}); callback = %p\n", + node_id, curve_id, key_id, dimensions, + pre_value[0], pre_value[1], + pre_pos[0], pre_pos[1], + value[0], value[1], pos, + pre_value[0], pre_value[1], + pre_pos[0], pre_pos[1], v_fs_get_user_func(130)); + break; + case 3: + printf("receive: verse_send_c_key_set(node_id = %u curve_id = %u key_id = %u dimensions = %u pre_value = {%f, %f, %f} pre_pos = {%u, %u, %u} value = {%f, %f, %f} pos = %f, pre_value = {%f, %f, %f} pre_pos = {%u, %u, %u}); callback = %p\n", + node_id, curve_id, key_id, dimensions, + pre_value[0], pre_value[1], pre_value[2], + pre_pos[0], pre_pos[1], pre_pos[2], + value[0], value[1], value[2], pos, + pre_value[0], pre_value[1], pre_value[2], + pre_pos[0], pre_pos[1], pre_pos[2], v_fs_get_user_func(130)); + + break; + case 4: + printf("receive: verse_send_c_key_set(node_id = %u curve_id = %u key_id = %u dimensions = %u pre_value = {%f, %f, %f, %f} pre_pos = {%u, %u, %u, %u} value = {%f, %f, %f, %f} pos = %f, pre_value = {%f, %f, %f, %f} pre_pos = {%u, %u, %u, %u}); callback = %p\n", + node_id, curve_id, key_id, dimensions, + pre_value[0], pre_value[1], pre_value[2], pre_value[3], + pre_pos[0], pre_pos[1], pre_pos[2], pre_pos[3], + value[0], value[1], value[2], value[3], pos, + pre_value[0], pre_value[1], pre_value[2], pre_value[3], + pre_pos[0], pre_pos[1], pre_pos[2], pre_pos[3], v_fs_get_user_func(130)); + break; + } + #endif + func_c_key_set = v_fs_get_user_func(130); + if(func_c_key_set != NULL) + func_c_key_set(v_fs_get_user_data(130), node_id, curve_id, key_id, dimensions, pre_value, pre_pos, value, pos, post_value, post_pos); + return buffer_pos; + }else + { + void (* alias_c_key_destroy)(void *user_data, VNodeID node_id, VLayerID curve_id, uint32 key_id); + alias_c_key_destroy = v_fs_get_alias_user_func(130); + printf("receive: verse_send_c_key_destroy(node_id = %u curve_id = %u key_id = %u); callback = %p\n", node_id, curve_id, key_id, alias_c_key_destroy); + if(alias_c_key_destroy != NULL) + alias_c_key_destroy(v_fs_get_alias_user_data(130), node_id, curve_id, key_id); + return buffer_pos; + } +} + +#endif diff --git a/extern/verse/dist/v_network.c b/extern/verse/dist/v_network.c new file mode 100644 index 00000000000..3d67218bb7e --- /dev/null +++ b/extern/verse/dist/v_network.c @@ -0,0 +1,274 @@ +/* +** +*/ + +#if defined _WIN32 +#include +typedef unsigned int uint; +typedef SOCKET VSocket; +#else +typedef int VSocket; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif +#include +#include + +typedef unsigned int uint32; +typedef int int32; +typedef unsigned short uint16; +typedef short int16; +typedef unsigned char uint8; +typedef char int8; +typedef char boolean; + +#include "v_cmd_gen.h" +#include "v_network.h" + +#if !defined socklen_t +#define socklen_t int +#endif + +#define TRUE 1 +#define FALSE 0 + +typedef struct{ + struct sockaddr_in address; + struct hostent *he; +} VNetworkConnection; + +#define VERSE_STD_CONNECT_TO_PORT 4950 + +static VSocket my_socket = -1; +static uint16 my_port = 0; + +void v_n_set_port(unsigned short port) +{ + my_port = port; +} + +VSocket v_n_socket_create(void) +{ + static boolean initialized = FALSE; + struct sockaddr_in address; + int buffer_size = 1 << 20; + + if(my_socket != -1) + return my_socket; +#if defined _WIN32 + if(!initialized) + { + WSADATA wsaData; + + if(WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) + { + fprintf(stderr, "WSAStartup failed.\n"); + exit(1); + } + + } +#endif + initialized = TRUE; + if((my_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) + return -1; +#if defined _WIN32 + { + unsigned long one = 1UL; + if(ioctlsocket(my_socket, FIONBIO, &one) != 0) + return -1; + } +#else + if(fcntl(my_socket, F_SETFL, O_NONBLOCK) != 0) + { + fprintf(stderr, "v_network: Couldn't make socket non-blocking\n"); + return -1; + } +#endif + address.sin_family = AF_INET; /* host byte order */ + address.sin_port = htons(my_port); /* short, network byte order */ + address.sin_addr.s_addr = INADDR_ANY; + if(bind(my_socket, (struct sockaddr *) &address, sizeof(struct sockaddr)) != 0) + { + fprintf(stderr, "v_network: Failed to bind(), code %d (%s)\n", errno, strerror(errno)); + exit(0); /* FIX ME */ + } + if(setsockopt(my_socket, SOL_SOCKET, SO_SNDBUF, (const char *) &buffer_size, sizeof buffer_size) != 0) + fprintf(stderr, "v_network: Couldn't set send buffer size of socket to %d\n", buffer_size); + if(setsockopt(my_socket, SOL_SOCKET, SO_RCVBUF, (const char *) &buffer_size, sizeof buffer_size) != 0) + fprintf(stderr, "v_network: Couldn't set receive buffer size of socket to %d\n", buffer_size); + return my_socket; +} + +void v_n_socket_destroy(void) +{ +#if defined _WIN32 + closesocket(my_socket); +#else + close(my_socket); +#endif + my_socket = -1; +} + +boolean v_n_set_network_address(VNetworkAddress *address, const char *host_name) +{ + struct hostent *he; + char *colon = NULL, *buf = NULL; + boolean ok = FALSE; + + v_n_socket_create(); + address->port = VERSE_STD_CONNECT_TO_PORT; + /* If a port number is included, as indicated by a colon, we need to work a bit more. */ + if((colon = strchr(host_name, ':')) != NULL) + { + size_t hl = strlen(host_name); + + if((buf = malloc(hl + 1)) != NULL) + { + unsigned int tp; + + strcpy(buf, host_name); + colon = buf + (colon - host_name); + *colon = '\0'; + host_name = buf; + if(sscanf(colon + 1, "%u", &tp) == 1) + { + address->port = (unsigned short) tp; + if(address->port != tp) /* Protect against overflow. */ + host_name = NULL; + } + else + host_name = NULL; /* Protect against parse error. */ + } + else + return FALSE; + } + if(host_name != NULL && (he = gethostbyname(host_name)) != NULL) + { + memcpy(&address->ip, he->h_addr_list[0], he->h_length); + address->ip = ntohl(address->ip); + ok = TRUE; + } + if(buf != NULL) + free(buf); + + return ok; +} + +int v_n_send_data(VNetworkAddress *address, const char *data, size_t length) +{ + struct sockaddr_in address_in; + VSocket sock; + int ret; + + if((sock = v_n_socket_create()) == -1 || length == 0) + return 0; + address_in.sin_family = AF_INET; /* host byte order */ + address_in.sin_port = htons(address->port); /* short, network byte order */ + address_in.sin_addr.s_addr = htonl(address->ip); + memset(&address_in.sin_zero, 0, sizeof address_in.sin_zero); + ret = sendto(sock, data, length, 0, (struct sockaddr *) &address_in, sizeof(struct sockaddr_in)); + if(ret < 0) + fprintf(stderr, "Socket sendto() of %u bytes failed, code %d (%s)\n", (unsigned int) length, errno, strerror(errno)); + return ret; +} + +#if !defined V_GENERATE_FUNC_MODE + +extern void *v_con_get_network_address_id(unsigned int id); +extern unsigned int v_con_get_network_address_count(); + +unsigned int v_n_wait_for_incoming(unsigned int microseconds) +{ + struct timeval tv; + fd_set fd_select; + unsigned int s1, f1, s2, f2; + + if(microseconds == 0) + return 0; + v_n_socket_create(); + tv.tv_sec = microseconds / 1000000; + tv.tv_usec = microseconds % 1000000; + FD_ZERO(&fd_select); + FD_SET(my_socket, &fd_select); + v_n_get_current_time(&s1, &f1); + select(1, &fd_select, NULL, NULL, &tv); + v_n_get_current_time(&s2, &f2); + return (unsigned int) (1000000 * (s2 - s1) + (1000000.0 / 0xffffffffu) * (long) (f2 - f1)); /* Must cast to (long) for f1 > f2 case! */ +} + +#endif + +int v_n_receive_data(VNetworkAddress *address, char *data, size_t length) +{ + struct sockaddr_in address_in; + socklen_t from_length = sizeof address_in; + size_t len; + + if(v_n_socket_create() == -1) + return 0; + memset(&address_in, 0, sizeof address_in); + address_in.sin_family = AF_INET; + address_in.sin_port = htons(my_port); + address_in.sin_addr.s_addr = INADDR_ANY; + len = recvfrom(v_n_socket_create(), data, length, 0, (struct sockaddr *) &address_in, &from_length); + if(len > 0) + { + address->ip = ntohl(address_in.sin_addr.s_addr); + address->port = ntohs(address_in.sin_port); + } + return len; +} + +#if defined _WIN32 + +void v_n_get_current_time(uint32 *seconds, uint32 *fractions) +{ + static LARGE_INTEGER frequency; + static boolean init = FALSE; + LARGE_INTEGER counter; + + if(!init) + { + init = TRUE; + QueryPerformanceFrequency(&frequency); + } + + QueryPerformanceCounter(&counter); + if(seconds != NULL) + *seconds = (uint32) (counter.QuadPart / frequency.QuadPart); + if(fractions != NULL) + *fractions = (uint32) ((0xffffffffUL * (counter.QuadPart % frequency.QuadPart)) / frequency.QuadPart); +} + +#else + +void v_n_get_current_time(uint32 *seconds, uint32 *fractions) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + if(seconds != NULL) + *seconds = tv.tv_sec; + if(fractions != NULL) + *fractions = tv.tv_usec * 1E-6 * (double) (uint32)~0; +} + +#endif + +void v_n_get_address_string(const VNetworkAddress *address, char *string) +{ + sprintf(string, "%u.%u.%u.%u:%u", address->ip >> 24, (address->ip >> 16) & 0xff, + (address->ip >> 8) & 0xff, address->ip & 0xff, address->port); +} diff --git a/extern/verse/dist/v_network.h b/extern/verse/dist/v_network.h new file mode 100644 index 00000000000..52233cbe2bb --- /dev/null +++ b/extern/verse/dist/v_network.h @@ -0,0 +1,24 @@ +/* +** +*/ + +#if !defined V_NETWORK_H +#define V_NETWORK_H + +#define VERSE_STD_CONNECT_PORT 4950 + +typedef struct{ + unsigned int ip; + unsigned short port; +}VNetworkAddress; + +extern void v_n_set_port(unsigned short port); +extern unsigned int v_n_wait_for_incoming(unsigned int microseconds); +extern boolean v_n_set_network_address(VNetworkAddress *address, const char *host_name); +extern int v_n_send_data(VNetworkAddress *address, const char *data, size_t length); +extern int v_n_receive_data(VNetworkAddress *address, char *data, size_t length); +extern void v_n_get_address_string(const VNetworkAddress *address, char *string); + +extern void v_n_get_current_time(unsigned int *seconds, unsigned int *fractions); + +#endif /* V_NETWORK_H */ diff --git a/extern/verse/dist/v_network_in_que.c b/extern/verse/dist/v_network_in_que.c new file mode 100644 index 00000000000..d99a4ad11ec --- /dev/null +++ b/extern/verse/dist/v_network_in_que.c @@ -0,0 +1,140 @@ + +#include +#include +#include + +#include "verse_header.h" + +#include "v_cmd_buf.h" +#include "v_cmd_gen.h" +#include "v_connection.h" +#include "v_internal_verse.h" +#include "v_network.h" +#include "v_pack.h" + + +#if !defined(V_GENERATE_FUNC_MODE) + +#include "v_network_in_que.h" + +static VNetInPacked *v_niq_temp = NULL; + +void v_niq_clear(VNetInQueue *queue) +{ + queue->oldest = NULL; + queue->newest = NULL; + queue->packet_id = 2; + v_niq_timer_update(queue); +} + +/* Set queue's last-used timestamp to "now". */ +void v_niq_timer_update(VNetInQueue *queue) +{ + v_n_get_current_time(&queue->seconds, &queue->fractions); + queue->acc_seconds = queue->acc_fractions = 0; +} + +uint32 v_niq_time_out(VNetInQueue *queue) +{ + uint32 fractions, f; + + /* Magic code to disregard if the clock moves forward more than one second at a time. + * This should help keep Verse alive on e.g. a notebook that is suspended. + */ + v_n_get_current_time(NULL, &fractions); + if(fractions < queue->fractions) + f = 0xffffffffu - queue->fractions + fractions; + else + f = fractions - queue->fractions; +/* printf("now=%u last=%u -> f=%u\n", fractions, queue->fractions, f);*/ + if(queue->acc_fractions + f < queue->acc_fractions) + queue->acc_seconds += 1; + queue->acc_fractions += f; + queue->fractions = fractions; + +/* printf("queue at %p has seconds=%u, now=%u -> diff=%u\n", queue, queue->seconds, seconds, seconds - queue->seconds);*/ + return queue->acc_seconds; +} + +VNetInPacked * v_niq_get(VNetInQueue *queue, size_t *length) +{ + VNetInPacked *p; + + if(queue->oldest == NULL) + { + *length = 0; + return NULL; + } + /* pop oldest package */ + p = queue->oldest; + queue->oldest = p->newer; + if(queue->oldest == NULL) + queue->newest = NULL; + else + ((VNetInPacked *)queue->oldest)->older = NULL; + *length = p->size; + + return p; +} + +unsigned int v_niq_free(VNetInQueue *queue) +{ + unsigned int i; + size_t length; + + for(i = 0; v_niq_get(queue, &length) != NULL; i++) + ; + return i; +} + +void v_niq_release(VNetInQueue *queue, VNetInPacked *p) +{ + /* push on v_niq_temp for re-use */ + p->older = v_niq_temp; + v_niq_temp = p; +} + +char *v_niq_store(VNetInQueue *queue, size_t length, unsigned int packet_id) +{ + VNetInPacked *p; + + v_niq_timer_update(queue); + + if(packet_id < queue->packet_id) + return NULL; + + while(queue->packet_id != packet_id) + { + verse_send_packet_nak(queue->packet_id++); + if(queue->packet_id == 0) + queue->packet_id++; + } + queue->packet_id++; + if(queue->packet_id == 0) + queue->packet_id++; + verse_send_packet_ack(packet_id); + + if(v_niq_temp == NULL) + p = malloc(sizeof *p); + else + { + /* pop off v_niq_temp */ + p = v_niq_temp; + v_niq_temp = p->older; + } + /* push as newest */ + p->older = queue->newest; + p->newer = NULL; + + if(queue->newest == NULL) + queue->oldest = p; + else + ((VNetInPacked *)queue->newest)->newer = p; + queue->newest = p; + + p->size = length; + + return p->data; +} + +#endif diff --git a/extern/verse/dist/v_network_in_que.h b/extern/verse/dist/v_network_in_que.h new file mode 100644 index 00000000000..9241fe18fe8 --- /dev/null +++ b/extern/verse/dist/v_network_in_que.h @@ -0,0 +1,24 @@ + +typedef struct{ + void *oldest; + void *newest; + uint32 packet_id; + uint32 seconds, fractions; /* Current time. */ + uint32 acc_seconds, acc_fractions; /* Accumulated time. */ +}VNetInQueue; + +typedef struct{ + void *newer; + void *older; + char data[1500]; + size_t size; +}VNetInPacked; + +extern void v_niq_clear(VNetInQueue *queue); +extern void v_niq_timer_update(VNetInQueue *queue); + +extern VNetInPacked * v_niq_get(VNetInQueue *queue, size_t *length); +extern void v_niq_release(VNetInQueue *queue, VNetInPacked *p); +extern char * v_niq_store(VNetInQueue *queue, size_t length, unsigned int packet_id); +unsigned int v_niq_free(VNetInQueue *queue); +extern uint32 v_niq_time_out(VNetInQueue *queue); diff --git a/extern/verse/dist/v_network_out_que.c b/extern/verse/dist/v_network_out_que.c new file mode 100644 index 00000000000..10126a59779 --- /dev/null +++ b/extern/verse/dist/v_network_out_que.c @@ -0,0 +1,396 @@ +/* +** +*/ + +#include +#include +#include + +#include "verse_header.h" + +#include "v_cmd_buf.h" +#include "v_cmd_gen.h" +#include "v_connection.h" +#include "v_network.h" +#include "v_pack.h" +#include "v_encryption.h" +#include "v_network_out_que.h" +#include "v_util.h" + +#if !defined(V_GENERATE_FUNC_MODE) + +#define STD_QUE_SIZE 64 + +#define V_NOQ_OPTIMIZATION_SLOTS 2048 + +#define V_NOQ_WINDOW_SIZE 100000 +#define V_NOQ_MAX_SORTED_COMMANDS 5000 + +typedef struct{ + void *next; + char *data; + size_t size; +} NetPacked; + +struct VNetOutQueue{ + uint8 packet_buffer[V_NOQ_MAX_PACKET_SIZE]; + size_t packet_buffer_use; + NetPacked *packed; + NetPacked *last; + VCMDBufHead *unsent[V_NOQ_OPTIMIZATION_SLOTS]; + VCMDBufHead *history[V_NOQ_OPTIMIZATION_SLOTS]; + VCMDBufHead *ack_nak; + VCMDBufHead *unsorted; + VCMDBufHead *unsorted_end; + uint32 unsorted_count; /* debug only */ + uint32 unsent_comands; + size_t unsent_size; + size_t sent_size; + unsigned int packet_id; + unsigned int slot; + uint32 seconds; + uint32 fractions; +}; + +size_t verse_session_get_size(void) +{ + const VNetOutQueue *queue; + + queue = v_con_get_network_queue(); + return queue->unsent_size + queue->sent_size; +} + +VNetOutQueue * v_noq_create_network_queue(void) +{ + VNetOutQueue *queue; + unsigned int i; + + queue = malloc(sizeof *queue); + for(i = 0; i < V_NOQ_OPTIMIZATION_SLOTS; i++) + { + queue->unsent[i] = NULL; + queue->history[i] = NULL; + } + queue->unsent_comands = 0; + queue->unsent_size = 0; + queue->sent_size = 0; + queue->packet_id = 2; + queue->slot = 0; + queue->packed = NULL; + queue->last = NULL; + queue->ack_nak = NULL; + queue->unsorted = NULL; + queue->unsorted_end = NULL; + queue->unsorted_count = 0; + queue->packet_buffer_use = 0; + v_n_get_current_time(&queue->seconds, &queue->fractions); + return queue; +} + +unsigned int v_noq_get_next_out_packet_id(VNetOutQueue *queue) +{ + queue->packet_id++; + if(queue->packet_id == 0) + queue->packet_id++; + return queue->packet_id; +} + +void v_noq_destroy_network_queue(VNetOutQueue *queue) +{ + VCMDBufHead *buf, *b; + unsigned int i; + for(i = 0; i < V_NOQ_OPTIMIZATION_SLOTS; i++) + { + for(buf = queue->history[i]; buf != NULL; buf = b) + { + b = buf->next; + v_cmd_buf_free(buf); + } + for(buf = queue->unsent[i]; buf != NULL; buf = b) + { + b = buf->next; + v_cmd_buf_free(buf); + } + } + for(buf = queue->unsorted; buf != NULL; buf = b) + { + b = buf->next; + v_cmd_buf_free(buf); + } + free(queue); +} + + +void v_noq_sort_and_collapse_buf(VNetOutQueue *queue, VCMDBufHead *buf) +{ + VCMDBufHead *b, *last = NULL; + unsigned int slot; + + slot = buf->address_sum % V_NOQ_OPTIMIZATION_SLOTS; + queue->unsent_size += buf->size; + queue->unsent_comands++; + if(queue->unsent[slot] != NULL) + { + for(b = queue->unsent[slot]; !v_cmd_buf_compare(buf, b) && b->next != NULL; b = b->next) + last = b; + if(v_cmd_buf_compare(buf, b)) /* found a command to replace */ + { + queue->unsent_size -= b->size; + queue->unsent_comands--; + if(last != NULL) /* if its not the first */ + last->next = buf; + else + queue->unsent[slot] = buf; + buf->next = b->next; + v_cmd_buf_free(b); + }else /* inserting the command last in queue */ + { + buf->next = NULL; + b->next = buf; + } + }else /* inserting the first command */ + { + queue->unsent[slot] = buf; + buf->next = NULL; + } + if(queue->history[slot] != NULL) /* if there is a history clear it from any commnds with same address */ + { + last = NULL; + for(b = queue->history[slot]; b != NULL && !v_cmd_buf_compare(buf, b); b = b->next) + last = b; + if(b != NULL) /* found a command to replace */ + { + if(last == NULL) + queue->history[slot] = b->next; + else + last->next = b->next; + queue->sent_size -= b->size; + v_cmd_buf_free(b); + } + } +} + +void v_noq_send_buf(VNetOutQueue *queue, VCMDBufHead *buf) +{ + static int count = 0; +/* if(queue->unsent_comands > V_NOQ_MAX_SORTED_COMMANDS) + { + +*/ if(queue->unsorted == NULL) + { + queue->unsorted_end = buf; + queue->unsorted = buf; + }else + { + queue->unsorted_end->next = buf; + queue->unsorted_end = buf; + } + queue->unsorted_count++; +/* }else + v_noq_sort_and_colapse_buf(queue, buf); +*/ count = (count + 1) % 30; + if(count == 0) + { + v_con_network_listen(); + v_noq_send_queue(queue, v_con_get_network_address()); + } +} + +void v_noq_sort_unsorted(VNetOutQueue *queue) +{ + VCMDBufHead *buf; + + while(queue->unsent_comands < V_NOQ_MAX_SORTED_COMMANDS && queue->unsorted != NULL) + { + buf = queue->unsorted; + if(queue->unsorted == queue->unsorted_end) + { + queue->unsorted_end = NULL; + queue->unsorted = NULL; + }else + { + queue->unsorted = buf->next; + buf->next = NULL; + } + queue->unsorted_count--; + v_noq_sort_and_collapse_buf(queue, buf); + } +} + +boolean v_noq_send_queue(VNetOutQueue *queue, void *address) +{ + static unsigned int my_counter = 0; + VCMDBufHead *buf; + unsigned int size; + uint8 *data; + uint32 seconds, fractions; + double delta; + + data = queue->packet_buffer; + v_n_get_current_time(&seconds, &fractions); + delta = seconds - queue->seconds + (fractions - queue->fractions) / (double) 0xffffffff; + + if(queue->unsorted != NULL) + v_noq_sort_unsorted(queue); + + if(queue->unsent_size == 0 && delta < 1.0 && (queue->ack_nak == NULL || queue->ack_nak->next == NULL)) + return FALSE; + + if(delta > 3.0 && queue->unsent_size == 0 && queue->ack_nak == NULL && queue->packet_buffer_use != 0) + { +/* printf("A) re-sending last delta=%g\n", delta);*/ + v_n_send_data(address, data, queue->packet_buffer_use); + queue->seconds = seconds; + queue->fractions = fractions; + return TRUE; + } + + size = 4; + buf = queue->ack_nak; + while(buf != NULL && size + buf->size < V_NOQ_MAX_PACKET_SIZE) + { + vnp_raw_pack_uint32(data, queue->packet_id); + queue->ack_nak = buf->next; + buf->next = queue->history[queue->slot]; + queue->history[queue->slot] = buf; + buf->packet = queue->packet_id; + v_e_data_encrypt_command(data, size, ((VCMDBuffer1500 *)buf)->buf, buf->size, v_con_get_data_key()); + size += buf->size; + queue->sent_size += buf->size; + buf = queue->ack_nak; + } + if(queue->unsent_size == 0 || queue->sent_size >= V_NOQ_WINDOW_SIZE) + { + if(size > 5) + { +/* printf("ACK: sending actual size=%u id=%u\n", size, queue->packet_id);*/ + v_n_send_data(address, data, size); + queue->packet_buffer_use = size; + queue->seconds = seconds; + queue->fractions = fractions; + queue->packet_id++; + return TRUE; + } +/* printf("returning FALSE from send_queue()\n");*/ + return FALSE; + } +/* if(queue->sent_size < V_NOQ_WINDOW_SIZE && queue->unsent_size != 0)*/ + { + vnp_raw_pack_uint32(data, queue->packet_id); + while(queue->unsent_size != 0) + { + queue->slot = ((1 + queue->slot) % V_NOQ_OPTIMIZATION_SLOTS); + buf = queue->unsent[queue->slot]; + if(buf != NULL) + { + if(buf->size + size > V_NOQ_MAX_PACKET_SIZE) + break; + queue->unsent[queue->slot] = buf->next; + buf->next = queue->history[queue->slot]; + queue->history[queue->slot] = buf; + buf->packet = queue->packet_id; + + v_e_data_encrypt_command(data, size, ((VCMDBuffer1500 *)buf)->buf, buf->size, v_con_get_data_key()); + size += buf->size; + queue->unsent_comands--; + queue->unsent_size -= buf->size; + queue->sent_size += buf->size; + my_counter++; + } + } + v_n_send_data(address, data, size); + queue->packet_buffer_use = size; + queue->packet_id++; +/* size = vnp_raw_pack_uint32(data, queue->packet_id);*/ + queue->seconds = seconds; + queue->fractions = fractions; + } + return TRUE; +} + +void v_noq_send_ack_nak_buf(VNetOutQueue *queue, VCMDBufHead *buf) +{ + buf->next = queue->ack_nak; + queue->ack_nak = buf; +} + +void callback_send_packet_ack(void *user, uint32 packet_id) +{ + VNetOutQueue *queue; + VCMDBufHead *buf, *last; + unsigned int slot; + + queue = v_con_get_network_queue(); + for(slot = 0; slot < V_NOQ_OPTIMIZATION_SLOTS; slot++) + { + last = NULL; + for(buf = queue->history[slot]; buf != NULL && buf->packet != packet_id; buf = buf->next) + last = buf; + + if(buf != NULL) + { + if(last == NULL) + { + while(queue->history[slot] != NULL && queue->history[slot]->packet == packet_id) + { + queue->sent_size -= queue->history[slot]->size; + buf = queue->history[slot]->next; + v_cmd_buf_free(queue->history[slot]); + queue->history[slot] = buf; + } + }else + { + for(; buf != NULL && buf->packet == packet_id; buf = last->next) + { + queue->sent_size -= buf->size; + last->next = buf->next; + v_cmd_buf_free(buf); + } + } + } + } +} + +void callback_send_packet_nak(void *user, uint32 packet_id) +{ + VNetOutQueue *queue; + VCMDBufHead *buf, *last; + unsigned int slot; + + queue = v_con_get_network_queue(); + for(slot = 0; slot < V_NOQ_OPTIMIZATION_SLOTS; slot++) + { + last = NULL; + for(buf = queue->history[slot]; buf != NULL && buf->packet != packet_id; buf = buf->next) + last = buf; + if(buf != NULL) + { + if(last == NULL) + { + for(; queue->history[slot] != NULL && queue->history[slot]->packet == packet_id; queue->history[slot] = buf) + { + queue->unsent_comands++; + queue->unsent_size += queue->history[slot]->size; + queue->sent_size -= queue->history[slot]->size; + buf = queue->history[slot]->next; + queue->history[slot]->next = queue->unsent[slot]; + queue->unsent[slot] = queue->history[slot]; + } + }else + { + for(; last->next != NULL && ((VCMDBufHead *)last->next)->packet == packet_id;) + { + queue->unsent_comands++; + queue->unsent_size += ((VCMDBufHead *)last->next)->size; + queue->sent_size -= ((VCMDBufHead *)last->next)->size; + buf = last->next; + last->next = buf->next; + buf->next = queue->unsent[slot]; + queue->unsent[slot] = buf; + } + } + } + } +} + +#endif diff --git a/extern/verse/dist/v_network_out_que.h b/extern/verse/dist/v_network_out_que.h new file mode 100644 index 00000000000..6746475e84f --- /dev/null +++ b/extern/verse/dist/v_network_out_que.h @@ -0,0 +1,17 @@ +/* +** +*/ + +typedef struct VNetOutQueue VNetOutQueue; + +extern VNetOutQueue * v_noq_create_network_queue(void); +extern void v_noq_destroy_network_queue(VNetOutQueue *queue); +extern void v_noq_send_buf(VNetOutQueue *queue, VCMDBufHead *buf); +extern void v_noq_send_ack_nak_buf(VNetOutQueue *queue, VCMDBufHead *buf); + +extern void v_noq_send_ack(VNetOutQueue *queue, unsigned int id); +extern void v_noq_send_nak(VNetOutQueue *queue, unsigned int id); + +extern boolean v_noq_send_queue(VNetOutQueue *queue, void *address); + +extern unsigned int v_noq_get_next_out_packet_id(VNetOutQueue *queue); diff --git a/extern/verse/dist/v_pack.c b/extern/verse/dist/v_pack.c new file mode 100644 index 00000000000..f521360b11f --- /dev/null +++ b/extern/verse/dist/v_pack.c @@ -0,0 +1,386 @@ +/* +** v_pack.c +** +** These functions are used to pack and unpack various quantities to/from network +** packet buffers. They do not care about alignment, operating at byte level internally. +** The external byte-ordering used is big-endian (aka "network byte order") for all +** quantities larger than a single byte. +*/ + +#include +#include +#include + +#include "v_pack.h" + +size_t vnp_raw_pack_uint8(void *buffer, uint8 data) +{ + *(uint8 *) buffer = data; + + return sizeof data; +} + +size_t vnp_raw_unpack_uint8(const void *buffer, uint8 *data) +{ + *data = *(uint8 *) buffer; + + return sizeof *data; +} + +size_t vnp_raw_pack_uint8_vector(void *buffer, const uint8 *data, unsigned int length) +{ + memcpy(buffer, data, length); + return length; +} + +size_t vnp_raw_unpack_uint8_vector(const void *buffer, uint8 *data, unsigned int length) +{ + memcpy(data, buffer, length); + return length; +} + +size_t vnp_raw_pack_uint16(void *buffer, uint16 data) +{ + *(uint8 *) buffer = (data & 0xFF00) >> 8; + *((uint8 *) buffer + 1) = data & 0xFF; + return sizeof data; +} + +size_t vnp_raw_unpack_uint16(const void *buffer, uint16 *data) +{ + register const uint8 *b = buffer; + register uint16 tmp; + + tmp = ((uint16) *b++) << 8; + tmp |= (uint16) *b; + *data = tmp; + return sizeof *data; +} + +size_t vnp_raw_pack_uint16_vector(void *buffer, const uint16 *data, unsigned int length) +{ + register uint8 *b = buffer; + unsigned int i; + for(i = 0; i < length; i++) + { + *b++ = (*data & 0xFF00) >> 8; + *b++ = *data & 0xFF; + data++; + } + return length * 2; +} + +size_t vnp_raw_unpack_uint16_vector(const void *buffer, uint16 *data, unsigned int length) +{ + register const uint8 *b = buffer; + uint16 *end; + + for(end = data + length; end != data; data++) + { + *data = ((uint16) *b++) << 8; + *data |= (uint16) *b++; + } + return length * 2; +} + +size_t vnp_raw_pack_uint24(void *buffer, uint32 data) +{ + register uint8 *p = buffer; + + data >>= 8; + *(p++) = (data >> 24) & 0xFF; + *(p++) = (data >> 16) & 0xFF; + *(p++) = (data >> 8) & 0xFF; + + return 3; +} + +size_t vnp_raw_unpack_uint24(const void *buffer, uint32 *data) +{ + register const uint8 *p = buffer; + register uint32 tmp = 0; + + tmp |= ((uint32) *p++) << 24; + tmp |= ((uint32) *p++) << 16; + tmp |= ((uint32) *p++) << 8; + tmp |= tmp >> 24; + + return 3; +} + +size_t vnp_raw_pack_uint24_vector(void *buffer, const uint32 *data, unsigned int length) +{ + register uint8 *b = buffer; + unsigned int i; + + for(i = 0; i < length; i++) + { + *b++ = (*data >> 24) & 0xFF; + *b++ = (*data >> 16) & 0xFF; + *b++ = (*data >> 8) & 0xFF; + data++; + } + return length * 3; +} + +size_t vnp_raw_unpack_uint24_vector(const void *buffer, uint32 *data, unsigned int length) +{ + register const uint8 *b = buffer; + register uint32 tmp; + uint32 *end; + for(end = data + length; end != data; data++) + { + tmp = ((uint32) *b++) << 24; + tmp |= ((uint32) *b++) << 16; + tmp |= ((uint32) *b++) << 8; + tmp |= tmp >> 24; + *data = tmp; + } + return length * 3; +} + +size_t vnp_raw_pack_uint32(void *buffer, uint32 data) +{ + register uint8 *b = buffer; + + *b++ = (data >> 24) & 0xFF; + *b++ = (data >> 16) & 0xFF; + *b++ = (data >> 8) & 0xFF; + *b++ = data & 0xFF; + + return sizeof data; +} + +size_t vnp_raw_unpack_uint32(const void *buffer, uint32 *data) +{ + register const uint8 *b = buffer; + + *data = ((uint32) *b++) << 24; + *data |= ((uint32) *b++) << 16; + *data |= ((uint32) *b++) << 8; + *data |= *b; + return sizeof *data; +} + +size_t vnp_raw_pack_uint32_vector(void *buffer, const uint32 *data, unsigned int length) +{ + register uint8 *b = buffer; + unsigned int i; + + for(i = 0; i < length; i++) + { + *b++ = (*data >> 24) & 0xFF; + *b++ = (*data >> 16) & 0xFF; + *b++ = (*data >> 8) & 0xFF; + *b++ = *data & 0xFF; + data++; + } + return length * 4; +} + +size_t vnp_raw_unpack_uint32_vector(const void *buffer, uint32 *data, unsigned int length) +{ + register const uint8 *b = buffer; + uint32 *end; + for(end = data + length; end != data; data++) + { + *data = ((uint32) *b++) << 24; + *data |= ((uint32) *b++) << 16; + *data |= ((uint32) *b++) << 8; + *data |= ((uint32) *b++); + } + return length * 4; +} + +size_t vnp_raw_pack_real32(void *buffer, real32 data) +{ + union { uint32 uint; real32 real; } punt; + punt.real = data; + return vnp_raw_pack_uint32(buffer, punt.uint); +} + +size_t vnp_raw_unpack_real32(const void *buffer, real32 *data) +{ + return vnp_raw_unpack_uint32(buffer, (uint32 *) data); +} + +size_t vnp_raw_pack_real32_vector(void *buffer, const real32 *data, unsigned int length) +{ + uint32 i; + for(i = 0; i < length; i++) + vnp_raw_pack_real32(&((uint8 *)buffer)[i * 4], data[i]); + return length * 4; +} + +size_t vnp_raw_unpack_real32_vector(const void *buffer, real32 *data, unsigned int length) +{ + uint32 i; + for(i = 0; i < length; i++) + vnp_raw_unpack_real32(&((uint8 *)buffer)[i * 4], &data[i]); + return length * 4; +} + +size_t vnp_raw_pack_real64(void *buffer, real64 data) +{ + union { uint32 uint[2]; real64 real; } punt; + uint32 size; + + punt.real = data; + size = vnp_raw_pack_uint32(buffer, punt.uint[0]); + buffer = (uint8 *) buffer + size; + size += vnp_raw_pack_uint32(buffer, punt.uint[1]); + return size; +} + +size_t vnp_raw_unpack_real64(const void *buffer, real64 *data) +{ + union { uint32 uint[2]; real64 real; } punt; + uint32 size; + + size = vnp_raw_unpack_uint32(buffer, &punt.uint[0]); + size += vnp_raw_unpack_uint32(((uint8 *)buffer) + size, &punt.uint[1]); + *data = punt.real; + return size; +} + +size_t vnp_raw_pack_real64_vector(void *buffer, const real64 *data, unsigned int length) +{ + uint32 i; + for(i = 0; i < length; i++) + vnp_raw_pack_real64(&((uint8 *)buffer)[i * 8], data[i]); + return length * 8; +} + +size_t vnp_raw_unpack_real64_vector(const void *buffer, real64 *data, unsigned int length) +{ + uint32 i; + for(i = 0; i < length; i++) + vnp_raw_unpack_real64(&((uint8 *)buffer)[i * 8], &data[i]); + return length * 8; +} + +size_t vnp_raw_pack_string(void *buffer, const char *string, size_t max_size) +{ + unsigned int i = 0; + char *p = buffer; + if(string != 0) + for(; i < max_size && string[i] != 0; i++) + p[i] = string[i]; + p[i] = 0; + return ++i; +} + +size_t vnp_raw_unpack_string(const void *buffer, char *string, size_t max_size, size_t max_size2) +{ + unsigned int i; + const char *p = buffer; + + max_size--; + max_size2--; + for(i = 0; i < max_size && i < max_size2 && p[i] != 0; i++) + string[i] = p[i]; + string[i] = 0; + return ++i; +} + +/* --------------------------------------------------------------------------------------------------- */ + +size_t vnp_pack_quat32(void *buffer, const VNQuat32 *data) +{ + uint8 *out = buffer; + + if(data == NULL) + return 0; + out += vnp_raw_pack_real32(out, data->x); + out += vnp_raw_pack_real32(out, data->y); + out += vnp_raw_pack_real32(out, data->z); + out += vnp_raw_pack_real32(out, data->w); + + return out - (uint8 *) buffer; +} + +size_t vnp_unpack_quat32(const void *buffer, VNQuat32 *data) +{ + const uint8 *in = buffer; + + if(data == NULL) + return 0; + in += vnp_raw_unpack_real32(in, &data->x); + in += vnp_raw_unpack_real32(in, &data->y); + in += vnp_raw_unpack_real32(in, &data->z); + in += vnp_raw_unpack_real32(in, &data->w); + + return in - (uint8 *) buffer; +} + +size_t vnp_pack_quat64(void *buffer, const VNQuat64 *data) +{ + uint8 *out = buffer; + + if(data == NULL) + return 0; + out += vnp_raw_pack_real64(out, data->x); + out += vnp_raw_pack_real64(out, data->y); + out += vnp_raw_pack_real64(out, data->z); + out += vnp_raw_pack_real64(out, data->w); + + return out - (uint8 *) buffer; +} + +size_t vnp_unpack_quat64(const void *buffer, VNQuat64 *data) +{ + const uint8 *in = buffer; + + if(data == NULL) + return 0; + in += vnp_raw_unpack_real64(in, &data->x); + in += vnp_raw_unpack_real64(in, &data->y); + in += vnp_raw_unpack_real64(in, &data->z); + in += vnp_raw_unpack_real64(in, &data->w); + + return in - (uint8 *) buffer; +} + +size_t vnp_pack_audio_block(void *buffer, VNABlockType type, const VNABlock *block) +{ + if(block == NULL) + return 0; + switch(type) + { + case VN_A_BLOCK_INT8: + return vnp_raw_pack_uint8_vector(buffer, block->vint8, sizeof block->vint8 / sizeof *block->vint8); + case VN_A_BLOCK_INT16: + return vnp_raw_pack_uint16_vector(buffer, block->vint16, sizeof block->vint16 / sizeof *block->vint16); + case VN_A_BLOCK_INT24: + return vnp_raw_pack_uint24_vector(buffer, block->vint24, sizeof block->vint24 / sizeof *block->vint24); + case VN_A_BLOCK_INT32: + return vnp_raw_pack_uint32_vector(buffer, block->vint32, sizeof block->vint32 / sizeof *block->vint32); + case VN_A_BLOCK_REAL32: + return vnp_raw_pack_real32_vector(buffer, block->vreal32, sizeof block->vreal32 / sizeof *block->vreal32); + case VN_A_BLOCK_REAL64: + return vnp_raw_pack_real64_vector(buffer, block->vreal64, sizeof block->vreal64 / sizeof *block->vreal64); + } + return 0; +} + +size_t vnp_unpack_audio_block(const void *buffer, VNABlockType type, VNABlock *block) +{ + if(block == NULL) + return 0; + switch(type) + { + case VN_A_BLOCK_INT8: + return vnp_raw_unpack_uint8_vector(buffer, block->vint8, sizeof block->vint8 / sizeof *block->vint8); + case VN_A_BLOCK_INT16: + return vnp_raw_unpack_uint16_vector(buffer, block->vint16, sizeof block->vint16 / sizeof *block->vint16); + case VN_A_BLOCK_INT24: + return vnp_raw_unpack_uint24_vector(buffer, block->vint24, sizeof block->vint24 / sizeof *block->vint24); + case VN_A_BLOCK_INT32: + return vnp_raw_unpack_uint32_vector(buffer, block->vint32, sizeof block->vint32 / sizeof *block->vint32); + case VN_A_BLOCK_REAL32: + return vnp_raw_unpack_real32_vector(buffer, block->vreal32, sizeof block->vreal32 / sizeof *block->vreal32); + case VN_A_BLOCK_REAL64: + return vnp_raw_unpack_real64_vector(buffer, block->vreal64, sizeof block->vreal64 / sizeof *block->vreal64); + } + return 0; +} diff --git a/extern/verse/dist/v_pack.h b/extern/verse/dist/v_pack.h new file mode 100644 index 00000000000..60cb7225642 --- /dev/null +++ b/extern/verse/dist/v_pack.h @@ -0,0 +1,59 @@ +/* +** v_pack.h +** +** These functions are used to pack and unpack various quantities to/from network +** packet buffers. They do not care about alignment, operating at byte level internally. +** The external byte-ordering used is big-endian (aka "network byte order") for all +** quantities larger than a single byte. +*/ + +#include "verse_header.h" + +extern size_t vnp_raw_pack_uint8(void *buffer, uint8 data); +extern size_t vnp_raw_unpack_uint8(const void *buffer, uint8 *data); + +extern size_t vnp_raw_pack_uint16(void *buffer, uint16 data); +extern size_t vnp_raw_unpack_uint16(const void *buffer, uint16 *data); + +extern size_t vnp_raw_pack_uint24(void *buffer, uint32 data); +extern size_t vnp_raw_unpack_uint24(const void *buffer, uint32 *data); + +extern size_t vnp_raw_pack_uint32(void *buffer, uint32 data); +extern size_t vnp_raw_unpack_uint32(const void *buffer, uint32 *data); + +extern size_t vnp_raw_pack_real32(void *buffer, real32 data); +extern size_t vnp_raw_unpack_real32(const void *buffer, real32 *data); + +extern size_t vnp_raw_pack_real64(void *buffer, real64 data); +extern size_t vnp_raw_unpack_real64(const void *buffer, real64 *data); + +extern size_t vnp_raw_pack_string(void *buffer, const char *string, size_t max_size); +extern size_t vnp_raw_unpack_string(const void *buffer, char *string, size_t max_size, size_t max_size2); + +extern size_t vnp_raw_pack_uint8_vector(void *buffer, const uint8 *data, unsigned int length); +extern size_t vnp_raw_unpack_uint8_vector(const void *buffer, uint8 *data, unsigned int length); + +extern size_t vnp_raw_pack_uint16_vector(void *buffer, const uint16 *data, unsigned int length); +extern size_t vnp_raw_unpack_uint16_vector(const void *buffer, uint16 *data, unsigned int length); + +extern size_t vnp_raw_pack_uint24_vector(void *buffer, const uint32 *data, unsigned int length); +extern size_t vnp_raw_unpack_uint24_vector(const void *buffer, uint32 *data, unsigned int length); + +extern size_t vnp_raw_pack_uint32_vector(void *buffer, const uint32 *data, unsigned int length); +extern size_t vnp_raw_unpack_uint32_vector(const void *buffer, uint32 *data, unsigned int length); + +extern size_t vnp_raw_pack_real32_vector(void *buffer, const real32 *data, unsigned int length); +extern size_t vnp_raw_unpack_real32_vector(const void *buffer, real32 *data, unsigned int length); + +extern size_t vnp_raw_pack_real64_vector(void *buffer, const real64 *data, unsigned int length); +extern size_t vnp_raw_unpack_real64_vector(const void *buffer, real64 *data, unsigned int length); + +/* --------------------------------------------------------------------------------------------------- */ + +extern size_t vnp_pack_quat32(void *buffer, const VNQuat32 *data); +extern size_t vnp_unpack_quat32(const void *buffer, VNQuat32 *data); +extern size_t vnp_pack_quat64(void *buffer, const VNQuat64 *data); +extern size_t vnp_unpack_quat64(const void *buffer, VNQuat64 *data); + +extern size_t vnp_pack_audio_block(void *buffer, VNABlockType type, const VNABlock *block); +extern size_t vnp_unpack_audio_block(const void *buffer, VNABlockType type, VNABlock *block); diff --git a/extern/verse/dist/v_pack_method.c b/extern/verse/dist/v_pack_method.c new file mode 100644 index 00000000000..c79ae92ba31 --- /dev/null +++ b/extern/verse/dist/v_pack_method.c @@ -0,0 +1,219 @@ +/* +** +*/ + +#include + +#include "v_cmd_gen.h" + +#if !defined(V_GENERATE_FUNC_MODE) + +#include "verse.h" +#include "v_pack.h" + +VNOPackedParams * verse_method_call_pack(unsigned int param_count, const VNOParamType *param_type, const VNOParam *params) +{ + unsigned int i, j, buffer_pos; + uint8 *buf; + + buf = malloc(1500 + 8 * 16); + buffer_pos = vnp_raw_pack_uint16(buf, 0); + for(i = 0; i < param_count; i++) + { + switch(param_type[i]) + { + case VN_O_METHOD_PTYPE_INT8 : + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], params[i].vint8); + break; + case VN_O_METHOD_PTYPE_INT16 : + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], params[i].vint16); + break; + case VN_O_METHOD_PTYPE_INT32 : + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], params[i].vint32); + break; + case VN_O_METHOD_PTYPE_UINT8 : + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], params[i].vuint8); + break; + case VN_O_METHOD_PTYPE_UINT16 : + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], params[i].vuint16); + break; + case VN_O_METHOD_PTYPE_UINT32 : + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], params[i].vuint32); + break; + case VN_O_METHOD_PTYPE_REAL32 : + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], params[i].vreal32); + break; + case VN_O_METHOD_PTYPE_REAL64 : + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], params[i].vreal64); + break; + case VN_O_METHOD_PTYPE_STRING : + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], params[i].vstring, (1500 + 8 * 16) - buffer_pos); + break; + case VN_O_METHOD_PTYPE_NODE : + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], params[i].vnode); + break; + case VN_O_METHOD_PTYPE_LAYER : + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], params[i].vlayer); + break; + case VN_O_METHOD_PTYPE_REAL32_VEC2 : + for(j = 0; j < 2; j++) + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], params[i].vreal32_vec[j]); + break; + case VN_O_METHOD_PTYPE_REAL32_VEC3 : + for(j = 0; j < 3; j++) + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], params[i].vreal32_vec[j]); + break; + case VN_O_METHOD_PTYPE_REAL32_VEC4 : + for(j = 0; j < 4; j++) + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], params[i].vreal32_vec[j]); + break; + case VN_O_METHOD_PTYPE_REAL64_VEC2 : + for(j = 0; j < 2; j++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], params[i].vreal64_vec[j]); + break; + case VN_O_METHOD_PTYPE_REAL64_VEC3 : + for(j = 0; j < 3; j++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], params[i].vreal64_vec[j]); + break; + case VN_O_METHOD_PTYPE_REAL64_VEC4 : + for(j = 0; j < 4; j++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], params[i].vreal64_vec[j]); + break; + case VN_O_METHOD_PTYPE_REAL32_MAT4 : + for(j = 0; j < 4; j++) + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], params[i].vreal32_mat[j]); + break; + case VN_O_METHOD_PTYPE_REAL32_MAT9 : + for(j = 0; j < 9; j++) + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], params[i].vreal32_mat[j]); + break; + case VN_O_METHOD_PTYPE_REAL32_MAT16 : + for(j = 0; j < 16; j++) + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], params[i].vreal32_mat[j]); + break; + case VN_O_METHOD_PTYPE_REAL64_MAT4 : + for(j = 0; j < 4; j++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], params[i].vreal64_mat[j]); + break; + case VN_O_METHOD_PTYPE_REAL64_MAT9 : + for(j = 0; j < 9; j++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], params[i].vreal64_mat[j]); + break; + case VN_O_METHOD_PTYPE_REAL64_MAT16 : + for(j = 0; j < 16; j++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], params[i].vreal64_mat[j]); + break; + } + if(buffer_pos > 1500) + { + free(buf); + return NULL; + } + } + vnp_raw_pack_uint16(buf, buffer_pos); + return buf; +} + +boolean verse_method_call_unpack(const VNOPackedParams *data, unsigned int param_count, const VNOParamType *param_type, VNOParam *params) +{ + unsigned int i, j, buffer_pos = 0, len; + uint16 size; + const uint8 *buf; + static char string[2048]; + char *stringput = string; + + buf = data; + buffer_pos += vnp_raw_unpack_uint16(buf, &size); + for(i = 0; i < param_count; i++) + { + switch(param_type[i]) + { + case VN_O_METHOD_PTYPE_INT8 : + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], ¶ms[i].vint8); + break; + case VN_O_METHOD_PTYPE_INT16 : + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], ¶ms[i].vint16); + break; + case VN_O_METHOD_PTYPE_INT32 : + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], ¶ms[i].vint32); + break; + case VN_O_METHOD_PTYPE_UINT8 : + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], ¶ms[i].vuint8); + break; + case VN_O_METHOD_PTYPE_UINT16 : + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], ¶ms[i].vuint16); + break; + case VN_O_METHOD_PTYPE_UINT32 : + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], ¶ms[i].vuint32); + break; + case VN_O_METHOD_PTYPE_REAL32 : + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], ¶ms[i].vreal32); + break; + case VN_O_METHOD_PTYPE_REAL64 : + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], ¶ms[i].vreal64); + break; + case VN_O_METHOD_PTYPE_STRING : + params[i].vstring = stringput; + len = vnp_raw_unpack_string(&buf[buffer_pos], stringput, (1500 + 8 * 16) - buffer_pos, -1); + stringput += len; + buffer_pos += len; + break; + case VN_O_METHOD_PTYPE_NODE : + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], ¶ms[i].vnode); + break; + case VN_O_METHOD_PTYPE_LAYER : + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], ¶ms[i].vlayer); + break; + case VN_O_METHOD_PTYPE_REAL32_VEC2 : + for(j = 0; j < 2; j++) + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], ¶ms[i].vreal32_vec[j]); + break; + case VN_O_METHOD_PTYPE_REAL32_VEC3 : + for(j = 0; j < 3; j++) + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], ¶ms[i].vreal32_vec[j]); + break; + case VN_O_METHOD_PTYPE_REAL32_VEC4 : + for(j = 0; j < 4; j++) + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], ¶ms[i].vreal32_vec[j]); + break; + case VN_O_METHOD_PTYPE_REAL64_VEC2 : + for(j = 0; j < 2; j++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], ¶ms[i].vreal64_vec[j]); + break; + case VN_O_METHOD_PTYPE_REAL64_VEC3 : + for(j = 0; j < 3; j++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], ¶ms[i].vreal64_vec[j]); + break; + case VN_O_METHOD_PTYPE_REAL64_VEC4 : + for(j = 0; j < 4; j++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], ¶ms[i].vreal64_vec[j]); + break; + case VN_O_METHOD_PTYPE_REAL32_MAT4 : + for(j = 0; j < 4; j++) + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], ¶ms[i].vreal32_mat[j]); + break; + case VN_O_METHOD_PTYPE_REAL32_MAT9 : + for(j = 0; j < 9; j++) + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], ¶ms[i].vreal32_mat[j]); + break; + case VN_O_METHOD_PTYPE_REAL32_MAT16 : + for(j = 0; j < 16; j++) + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], ¶ms[i].vreal32_mat[j]); + break; + case VN_O_METHOD_PTYPE_REAL64_MAT4 : + for(j = 0; j < 4; j++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], ¶ms[i].vreal64_mat[j]); + break; + case VN_O_METHOD_PTYPE_REAL64_MAT9 : + for(j = 0; j < 9; j++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], ¶ms[i].vreal64_mat[j]); + break; + case VN_O_METHOD_PTYPE_REAL64_MAT16 : + for(j = 0; j < 16; j++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], ¶ms[i].vreal64_mat[j]); + break; + } + } + return TRUE; +} +#endif diff --git a/extern/verse/dist/v_prime.c b/extern/verse/dist/v_prime.c new file mode 100644 index 00000000000..cebdf4fb03d --- /dev/null +++ b/extern/verse/dist/v_prime.c @@ -0,0 +1,165 @@ +/* + * Program to generate primes of the form p = 2 * q + 1, + * where p and q are both primes. + * + * Originally written by Pontus Nyman , + * ported to Verse's bignums and rewritten from scratch by + * Emil Brink. + */ + +#include +#include +#include + +#include "v_bignum.h" +#include "v_encryption.h" +#include "verse_header.h" + +#define BITS V_ENCRYPTION_LOGIN_KEY_BITS /* Save some typing. */ + +#define CYCLES 10 /* Number of times to apply Miller-Rabin test. */ + +/* Test divisibility of against table of small known primes. Returns 1 if n looks prime, 0 if it IS not. */ +static int quick_filter(const VBigDig *n) +{ + VBigDig VBIGNUM(m, 16), VBIGNUM(tmp, BITS / 2); + const unsigned int prime[] = { 3, 5, 7, 11, 13, 17, 19, 23, 39, 31, 37, 41, 43, 47, 53 }; + unsigned int i; + + for(i = 0; i < sizeof prime / sizeof *prime; i++) + { + v_bignum_set_bignum(tmp, n); + v_bignum_set_digit(m, prime[i]); + v_bignum_mod(tmp, m); + if(v_bignum_eq_zero(tmp)) + return 0; + } + return 1; +} + +/* The Miller-Rabin primality test. Returns 1 if the candidate looks prime, 0 if + * it IS NOT prime. Assumes that n is BITS / 2 bits, so that its square fits in BITS. +*/ +static int miller_rabin(const VBigDig *n, VRandGen *gen) +{ + int i, k; + VBigDig VBIGNUM(a, BITS / 2), VBIGNUM(d, BITS), VBIGNUM(nmo, BITS / 2), VBIGNUM(x, BITS); + const VBigDig *mu; + + mu = v_bignum_reduce_begin(n); + + /* Pick a "witness", a number in the [1, n) range. */ + v_bignum_set_random(a, gen); + v_bignum_reduce(a, n, mu); + + v_bignum_set_one(d); + v_bignum_set_bignum(nmo, n); + v_bignum_sub_digit(nmo, 1); /* nmo = n - 1 (say it). */ + k = v_bignum_bit_msb(nmo); + for(i = k; i >= 0; i--) + { + v_bignum_set_bignum(x, d); + v_bignum_square_half(d); + v_bignum_reduce(d, n, mu); + if(v_bignum_eq_one(d) && !v_bignum_eq_one(x) && !v_bignum_eq(x, nmo)) + { + v_bignum_reduce_end(mu); + return 0; /* Composite found. */ + } + if(v_bignum_bit_test(nmo, i)) + { + v_bignum_mul(d, a); + v_bignum_reduce(d, n, mu); + } + } + v_bignum_reduce_end(mu); + return v_bignum_eq_one(d); /* It might be prime. */ +} + +/* Test q for primality, returning 1 if it seems prime, 0 if it certainly IS not. */ +int v_prime_test(const VBigDig *q, VRandGen *gen) +{ + int i; + + if(!quick_filter(q)) + return 0; + + for(i = 0; i < CYCLES; i++) + { + if(!miller_rabin(q, gen)) + return 0; + } + return 1; +} + +void v_prime_set_random(VBigDig *x) +{ + int bits = v_bignum_bit_size(x); + VRandGen *gen; + + gen = v_randgen_new(); + do + { + /* Create candidate, making sure it's both odd and non-zero. */ + v_bignum_set_random(x, gen); + /* Set topmost two bits, makes sure products are big. */ + v_bignum_bit_set(x, bits - 1); + v_bignum_bit_set(x, bits - 2); + /* Set lowermost bit, makes sure it is odd (better prime candidate that way). */ + v_bignum_bit_set(x, 0); + } while(!v_prime_test(x, gen)); +/* printf("Prime found after %d iterations: ", count); + v_bignum_print_hex_lf(x); +*/ + v_randgen_destroy(gen); +} + +/* Big (small?) primes from . */ +void v_prime_set_table(VBigDig *x, unsigned int i) +{ + if(i == 0) + v_bignum_set_string_hex(x, "0xCBC2C5536E3D6283FDAF36B1D0F91C3EAAB1D12892B961B866907930F6471851"); + else if(i == 1) + v_bignum_set_string_hex(x, "0xC14F93E7A1543BD57C1DFBE98C29F9E4C13077FD27A0FEC05CCBC913CD213F19"); + else + v_bignum_set_string(x, "65537"); /* It ain't big, but it's prime. */ +} + +#if PRIMEALONE +#include + +#define REPS 300 + +static double elapsed(const struct timeval *t1, const struct timeval *t2) +{ + return t2->tv_sec - t1->tv_sec + 1E-6 * (t2->tv_usec - t1->tv_usec); +} + +int main(void) +{ + struct timeval now, then; + VBigDig VBIGNUM(x, BITS / 2); + int i; + + srand(clock()); + +/* gettimeofday(&then, NULL); + for(i = 0; i < REPS; i++) + { + v_prime_set_random_incr(x); + } + gettimeofday(&now, NULL); + printf("incr: %g\n", elapsed(&then, &now)); +*/ + gettimeofday(&then, NULL); + for(i = 0; i < REPS; i++) + { + v_prime_set_random(x); + } + gettimeofday(&now, NULL); + printf("rand: %g\n", elapsed(&then, &now)); + + return EXIT_SUCCESS; +} + +#endif diff --git a/extern/verse/dist/v_randgen.c b/extern/verse/dist/v_randgen.c new file mode 100644 index 00000000000..c65b48be60b --- /dev/null +++ b/extern/verse/dist/v_randgen.c @@ -0,0 +1,101 @@ +/* + * Random number generator module. Defines a simple API to allocate, use and + * destroy a generator of randomness. Relies on platform-specific APIs. +*/ + +#include +#include + +#include "v_randgen.h" + +#if defined _WIN32 + +/* This is a fall-back to the old style of simply using rand(). It should + * be replaced by something using the proper Win32 cryptography APIs. + * The CryptAcquireContext() and CryptGenRandom() calls sound interesting. + * + * FIXME: Replace ASAP. +*/ + +VRandGen * v_randgen_new(void) +{ + return (VRandGen *) 1; /* Anything that isn't NULL. */ +} + +void v_randgen_get(VRandGen *gen, void *bytes, size_t num) +{ + if(gen != NULL && bytes != NULL) + { + unsigned char *put = bytes, *get; + size_t i; + int x; + + while(num > 0) + { + x = rand(); + get = (unsigned char *) &x; + for(i = 0; i < sizeof x && num > 0; i++, num--) + *put++ = *get++; + } + } +} + +void v_randgen_destroy(VRandGen *gen) +{ + /* Nothing to do here. */ +} + +#else + +/* On non-Win32 platforms (which is Linux and Darwin, at the moment), we + * read random data from a file, which is assumed to be one of the kernel's + * virtual files. +*/ + +#include +#include +#include +#include + +struct VRandGen { + int fd; +}; + +#define SOURCE "/dev/urandom" /* Name of file to read random bits from. */ + +VRandGen * v_randgen_new(void) +{ + VRandGen *gen; + + if((gen = malloc(sizeof *gen)) != NULL) + { + gen->fd = open(SOURCE, O_RDONLY); + if(gen->fd < 0) + { + fprintf(stderr, __FILE__ ": Couldn't open " SOURCE " for reading\n"); + free(gen); + gen = NULL; + } + } + return gen; +} + +void v_randgen_get(VRandGen *gen, void *bytes, size_t num) +{ + if(gen != NULL && bytes != NULL) + { + if(read(gen->fd, bytes, num) != (int) num) + fprintf(stderr, __FILE__ ": Failed to read %u bytes of random data from " SOURCE "\n", (unsigned int) num); + } +} + +void v_randgen_destroy(VRandGen *gen) +{ + if(gen != NULL) + { + close(gen->fd); + free(gen); + } +} + +#endif diff --git a/extern/verse/dist/v_randgen.h b/extern/verse/dist/v_randgen.h new file mode 100644 index 00000000000..ee14ce6c36f --- /dev/null +++ b/extern/verse/dist/v_randgen.h @@ -0,0 +1,14 @@ +/* + * Random number generator API. A way to improve over rand(). +*/ + +#if !defined V_RANDGEN_H +#define V_RANDGEN_H + +typedef struct VRandGen VRandGen; + +extern VRandGen * v_randgen_new(void); +extern void v_randgen_get(VRandGen *gen, void *bytes, size_t num); +extern void v_randgen_destroy(VRandGen *gen); + +#endif /* V_RANDGEN_H */ diff --git a/extern/verse/dist/v_util.c b/extern/verse/dist/v_util.c new file mode 100644 index 00000000000..a36f4c77791 --- /dev/null +++ b/extern/verse/dist/v_util.c @@ -0,0 +1,98 @@ +/* + * Utility functions. +*/ + +#include + +#include "verse_header.h" +#include "v_network.h" +#include "v_util.h" + +/* Safe string copy. Copies from to , not using more than + * bytes of destination space. Always 0-terminates the destination. Returns + * the beginning of the destination string. +*/ +char * v_strlcpy(char *dst, const char *src, size_t size) +{ + char *base = dst; + + if(size == 0) + return NULL; + for(size--; size > 0 && *src != '\0'; size--) + *dst++ = *src++; + *dst = '\0'; + + return base; +} + +void v_timer_start(VUtilTimer *timer) +{ + v_n_get_current_time(&timer->seconds, &timer->fractions); +} + +void v_timer_advance(VUtilTimer *timer, double seconds) +{ + if(timer == NULL) + return; + timer->seconds += (uint32) seconds; + timer->fractions += (uint32) ((seconds - (int) seconds) * (double) 0xffffffff); +} + +double v_timer_elapsed(const VUtilTimer *timer) +{ + uint32 cur_seconds, cur_fractions; + + v_n_get_current_time(&cur_seconds, &cur_fractions); + return (double)(cur_seconds - timer->seconds) + ((double)cur_fractions - (double)timer->fractions) / (double) 0xffffffff; +} + +void v_timer_print(const VUtilTimer *timer) +{ + uint32 cur_seconds, cur_fractions; + + v_n_get_current_time(&cur_seconds, &cur_fractions); + printf("%f", (double)(cur_seconds - timer->seconds) + ((double)cur_fractions - (double)timer->fractions) / (double) 0xffffffff); +} + +/* Compare |x| against built-in semi-magical constant, and return 1 if it's larger, 0 if not. */ +static int quat_valid(real64 x) +{ + const real64 EPSILON = 0.0000001; + return x > 0.0 ? x > EPSILON : x < -EPSILON; +} + +int v_quat32_valid(const VNQuat32 *q) +{ + if(q == NULL) + return 0; + return quat_valid(q->x) && quat_valid(q->y) && quat_valid(q->z) && quat_valid(q->w); +} + +int v_quat64_valid(const VNQuat64 *q) +{ + if(q == NULL) + return 0; + return quat_valid(q->x) && quat_valid(q->y) && quat_valid(q->z) && quat_valid(q->w); +} + +VNQuat32 * v_quat32_from_quat64(VNQuat32 *dst, const VNQuat64 *src) +{ + if(dst == NULL || src == NULL) + return NULL; + dst->x = (real32) src->x; + dst->y = (real32) src->y; + dst->z = (real32) src->z; + dst->w = (real32) src->w; + return dst; +} + +VNQuat64 * v_quat64_from_quat32(VNQuat64 *dst, const VNQuat32 *src) +{ + if(dst == NULL || src == NULL) + return NULL; + dst->x = src->x; + dst->y = src->y; + dst->z = src->z; + dst->w = src->w; + return dst; +} diff --git a/extern/verse/dist/v_util.h b/extern/verse/dist/v_util.h new file mode 100644 index 00000000000..d252d958549 --- /dev/null +++ b/extern/verse/dist/v_util.h @@ -0,0 +1,21 @@ +/* + * Miscellaneous utility routines for generic use throughout the code. +*/ + +/* Safe, buffer size limited, string copy. */ +extern char * v_strlcpy(char *dst, const char *src, size_t size); + +typedef struct { + uint32 seconds; + uint32 fractions; +} VUtilTimer; + +extern void v_timer_start(VUtilTimer *timer); +extern void v_timer_advance(VUtilTimer *timer, double seconds); +extern double v_timer_elapsed(const VUtilTimer *timer); +extern void v_timer_print(const VUtilTimer *timer); + +extern int v_quat32_valid(const VNQuat32 *q); +extern int v_quat64_valid(const VNQuat64 *q); +extern VNQuat32*v_quat32_from_quat64(VNQuat32 *dst, const VNQuat64 *src); +extern VNQuat64*v_quat64_from_quat32(VNQuat64 *dst, const VNQuat32 *src); diff --git a/extern/verse/dist/verse.h b/extern/verse/dist/verse.h new file mode 100644 index 00000000000..53ce674725a --- /dev/null +++ b/extern/verse/dist/verse.h @@ -0,0 +1,530 @@ +/* +** Verse API Header file (for use with libverse.a). +** This is automatically generated code; do not edit. +*/ + + +#if !defined VERSE_H + +#if defined __cplusplus /* Declare as C symbols for C++ users. */ +extern "C" { +#endif + +#define VERSE_H + +#if !defined VERSE_TYPES +#define VERSE_TYPES + +#include + +/* Release information. */ +#define V_RELEASE_NUMBER 6 +#define V_RELEASE_PATCH 1 +#define V_RELEASE_LABEL "" + +typedef unsigned char boolean; +typedef signed char int8; +typedef unsigned char uint8; +typedef short int16; +typedef unsigned short uint16; +typedef int int32; +typedef unsigned int uint32; +typedef float real32; +typedef double real64; + +#define V_REAL64_MAX 1.7976931348623158e+308 +#define V_REAL32_MAX 3.402823466e+38f + +#if !defined TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +#define V_HOST_ID_SIZE (3 * (512 / 8)) /* The size of host IDs (keys), in 8-bit bytes. */ + +typedef enum { + V_NT_OBJECT = 0, + V_NT_GEOMETRY, + V_NT_MATERIAL, + V_NT_BITMAP, + V_NT_TEXT, + V_NT_CURVE, + V_NT_AUDIO, + V_NT_NUM_TYPES, + V_NT_SYSTEM = V_NT_NUM_TYPES, + V_NT_NUM_TYPES_NETPACK +} VNodeType; + +typedef uint32 VNodeID; +typedef uint16 VLayerID; /* Commonly used to identify layers, nodes that have them. */ +typedef uint16 VBufferID; /* Commonly used to identify buffers, nodes that have them. */ +typedef uint16 VNMFragmentID; + +typedef void * VSession; + +#define V_MAX_NAME_LENGTH_SHORT 16 +#define V_MAX_NAME_LENGTH_LONG 48 +#define V_MAX_NAME_PASS_LENGTH 128 + +typedef enum { + VN_OWNER_OTHER = 0, + VN_OWNER_MINE +} VNodeOwner; + +typedef enum { + VN_O_METHOD_PTYPE_INT8 = 0, + VN_O_METHOD_PTYPE_INT16, + VN_O_METHOD_PTYPE_INT32, + + VN_O_METHOD_PTYPE_UINT8, + VN_O_METHOD_PTYPE_UINT16, + VN_O_METHOD_PTYPE_UINT32, + + VN_O_METHOD_PTYPE_REAL32, + VN_O_METHOD_PTYPE_REAL64, + + VN_O_METHOD_PTYPE_REAL32_VEC2, + VN_O_METHOD_PTYPE_REAL32_VEC3, + VN_O_METHOD_PTYPE_REAL32_VEC4, + + VN_O_METHOD_PTYPE_REAL64_VEC2, + VN_O_METHOD_PTYPE_REAL64_VEC3, + VN_O_METHOD_PTYPE_REAL64_VEC4, + + VN_O_METHOD_PTYPE_REAL32_MAT4, + VN_O_METHOD_PTYPE_REAL32_MAT9, + VN_O_METHOD_PTYPE_REAL32_MAT16, + + VN_O_METHOD_PTYPE_REAL64_MAT4, + VN_O_METHOD_PTYPE_REAL64_MAT9, + VN_O_METHOD_PTYPE_REAL64_MAT16, + + VN_O_METHOD_PTYPE_STRING, + + VN_O_METHOD_PTYPE_NODE, + VN_O_METHOD_PTYPE_LAYER +} VNOParamType; + +typedef union { + int8 vint8; + int16 vint16; + int32 vint32; + uint8 vuint8; + uint16 vuint16; + uint32 vuint32; + real32 vreal32; + real64 vreal64; + real32 vreal32_vec[4]; + real32 vreal32_mat[16]; + real64 vreal64_vec[4]; + real64 vreal64_mat[16]; + char *vstring; + VNodeID vnode; + VLayerID vlayer; +} VNOParam; + +#define VN_TAG_MAX_BLOB_SIZE 500 + +typedef enum { + VN_TAG_BOOLEAN = 0, + VN_TAG_UINT32, + VN_TAG_REAL64, + VN_TAG_STRING, + VN_TAG_REAL64_VEC3, + VN_TAG_LINK, + VN_TAG_ANIMATION, + VN_TAG_BLOB, + VN_TAG_TYPE_COUNT +} VNTagType; + +typedef enum { + VN_TAG_GROUP_SIZE = 16, + VN_TAG_NAME_SIZE = 16, + VN_TAG_FULL_NAME_SIZE = 64, + VN_TAG_STRING_SIZE = 128 +} VNTagConstants; + +typedef union { + boolean vboolean; + uint32 vuint32; + real64 vreal64; + char *vstring; + real64 vreal64_vec3[3]; + VNodeID vlink; + struct { + VNodeID curve; + uint32 start; + uint32 end; + } vanimation; + struct { + uint16 size; + void *blob; + } vblob; +} VNTag; + +typedef enum { + VN_S_CONNECT_NAME_SIZE = 32, + VN_S_CONNECT_KEY_SIZE = 4, + VN_S_CONNECT_DATA_SIZE = 32, + VS_S_CONNECT_HOSTID_PRIVATE_SIZE = 3 * 2048 / 8, + VS_S_CONNECT_HOSTID_PUBLIC_SIZE = 2 * 2048 / 8 +} VNSConnectConstants; + +typedef enum { + VN_FORMAT_REAL32, + VN_FORMAT_REAL64 +} VNRealFormat; + +typedef struct { + real32 x, y, z, w; +} VNQuat32; + +typedef struct { + real64 x, y, z, w; +} VNQuat64; + +typedef enum { + VN_O_METHOD_GROUP_NAME_SIZE = 16, + VN_O_METHOD_NAME_SIZE = 16, + VN_O_METHOD_SIG_SIZE = 256 +} VNOMethodConstants; + +typedef void VNOPackedParams; /* Opaque type. */ + +typedef enum { + VN_G_LAYER_VERTEX_XYZ = 0, + VN_G_LAYER_VERTEX_UINT32, + VN_G_LAYER_VERTEX_REAL, + VN_G_LAYER_POLYGON_CORNER_UINT32 = 128, + VN_G_LAYER_POLYGON_CORNER_REAL, + VN_G_LAYER_POLYGON_FACE_UINT8, + VN_G_LAYER_POLYGON_FACE_UINT32, + VN_G_LAYER_POLYGON_FACE_REAL +} VNGLayerType; + +typedef enum { + VN_M_LIGHT_DIRECT = 0, + VN_M_LIGHT_AMBIENT, + VN_M_LIGHT_DIRECT_AND_AMBIENT, + VN_M_LIGHT_BACK_DIRECT, + VN_M_LIGHT_BACK_AMBIENT, + VN_M_LIGHT_BACK_DIRECT_AND_AMBIENT +} VNMLightType; + +typedef enum { + VN_M_NOISE_PERLIN_ZERO_TO_ONE = 0, + VN_M_NOISE_PERLIN_MINUS_ONE_TO_ONE, + VN_M_NOISE_POINT_ZERO_TO_ONE, + VN_M_NOISE_POINT_MINUS_ONE_TO_ONE +} VNMNoiseType; + +typedef enum { + VN_M_RAMP_SQUARE = 0, + VN_M_RAMP_LINEAR, + VN_M_RAMP_SMOOTH +} VNMRampType; + +typedef enum { + VN_M_RAMP_RED = 0, + VN_M_RAMP_GREEN, + VN_M_RAMP_BLUE +} VNMRampChannel; + +typedef struct { + real64 pos; + real64 red; + real64 green; + real64 blue; +} VNMRampPoint; + +typedef enum { + VN_M_BLEND_FADE = 0, + VN_M_BLEND_ADD, + VN_M_BLEND_SUBTRACT, + VN_M_BLEND_MULTIPLY, + VN_M_BLEND_DIVIDE, +} VNMBlendType; + +typedef enum { + VN_M_FT_COLOR = 0, + VN_M_FT_LIGHT, + VN_M_FT_REFLECTION, + VN_M_FT_TRANSPARENCY, + VN_M_FT_VOLUME, + VN_M_FT_VIEW, + VN_M_FT_GEOMETRY, + VN_M_FT_TEXTURE, + VN_M_FT_NOISE, + VN_M_FT_BLENDER, + VN_M_FT_CLAMP, + VN_M_FT_MATRIX, + VN_M_FT_RAMP, + VN_M_FT_ANIMATION, + VN_M_FT_ALTERNATIVE, + VN_M_FT_OUTPUT +} VNMFragmentType; + +typedef union { + struct { + real64 red; + real64 green; + real64 blue; + } color; + struct { + uint8 type; + real64 normal_falloff; + VNodeID brdf; + char brdf_r[16]; + char brdf_g[16]; + char brdf_b[16]; + } light; + struct { + real64 normal_falloff; + } reflection; + struct { + real64 normal_falloff; + real64 refraction_index; + } transparency; + struct { + real64 diffusion; + real64 col_r; + real64 col_g; + real64 col_b; + } volume; + struct { + char layer_r[16]; + char layer_g[16]; + char layer_b[16]; + } geometry; + struct{ + VNodeID bitmap; + char layer_r[16]; + char layer_g[16]; + char layer_b[16]; + boolean filtered; + VNMFragmentID mapping; + } texture; + struct { + uint8 type; + VNMFragmentID mapping; + } noise; + struct { + uint8 type; + VNMFragmentID data_a; + VNMFragmentID data_b; + VNMFragmentID control; + } blender; + struct { + boolean min; + real64 red; + real64 green; + real64 blue; + VNMFragmentID data; + } clamp; + struct { + real64 matrix[16]; + VNMFragmentID data; + } matrix; + struct { + uint8 type; + uint8 channel; + VNMFragmentID mapping; + uint8 point_count; + VNMRampPoint ramp[48]; + } ramp; + struct { + char label[16]; + } animation; + struct { + VNMFragmentID alt_a; + VNMFragmentID alt_b; + } alternative; + struct { + char label[16]; + VNMFragmentID front; + VNMFragmentID back; + } output; +} VMatFrag; + +typedef enum { + VN_B_LAYER_UINT1 = 0, + VN_B_LAYER_UINT8, + VN_B_LAYER_UINT16, + VN_B_LAYER_REAL32, + VN_B_LAYER_REAL64 +} VNBLayerType; + +#define VN_B_TILE_SIZE 8 + +typedef union{ + uint8 vuint1[8]; + uint8 vuint8[64]; + uint16 vuint16[64]; + real32 vreal32[64]; + real64 vreal64[64]; +} VNBTile; + +typedef enum { + VN_T_CONTENT_LANGUAGE_SIZE = 32, + VN_T_CONTENT_INFO_SIZE = 256, + VN_T_BUFFER_NAME_SIZE = 16, + VN_T_MAX_TEXT_CMD_SIZE = 1450 +} VNTConstants; + +/* This is how many *samples* are included in a block of the given type. Not bytes. */ +typedef enum { + VN_A_BLOCK_SIZE_INT8 = 1024, + VN_A_BLOCK_SIZE_INT16 = 512, + VN_A_BLOCK_SIZE_INT24 = 384, + VN_A_BLOCK_SIZE_INT32 = 256, + VN_A_BLOCK_SIZE_REAL32 = 256, + VN_A_BLOCK_SIZE_REAL64 = 128 +} VNAConstants; + +typedef enum { + VN_A_BLOCK_INT8, + VN_A_BLOCK_INT16, + VN_A_BLOCK_INT24, + VN_A_BLOCK_INT32, + VN_A_BLOCK_REAL32, + VN_A_BLOCK_REAL64 +} VNABlockType; + +/* Audio commands take pointers to blocks of these. They are not packed as unions. */ +typedef union { + int8 vint8[VN_A_BLOCK_SIZE_INT8]; + int16 vint16[VN_A_BLOCK_SIZE_INT16]; + int32 vint24[VN_A_BLOCK_SIZE_INT24]; + int32 vint32[VN_A_BLOCK_SIZE_INT32]; + real32 vreal32[VN_A_BLOCK_SIZE_REAL32]; + real64 vreal64[VN_A_BLOCK_SIZE_REAL64]; +} VNABlock; + +extern void verse_set_port(uint16 port); +extern void verse_host_id_create(uint8 *id); +extern void verse_host_id_set(uint8 *id); +extern void verse_callback_set(void *send_func, void *callback, void *user_data); +extern void verse_callback_update(uint32 microseconds); +extern void verse_session_set(VSession session); +extern VSession verse_session_get(void); +extern void verse_session_destroy(VSession session); +extern size_t verse_session_get_size(void); +extern VNodeID verse_session_get_avatar(void); +extern void verse_session_get_time(uint32 *seconds, uint32 *fractions); + +extern VNOPackedParams * verse_method_call_pack(uint32 param_count, const VNOParamType *param_type, const VNOParam *params); +extern boolean verse_method_call_unpack(const VNOPackedParams *data, uint32 param_count, const VNOParamType *param_type, VNOParam *params); + +/* +#define V_PRINT_SEND_COMMANDS +#define V_PRINT_RECEIVE_COMMANDS +*/ + +#endif /* VERSE_TYPES */ + +/* Command sending functions begin. ----------------------------------------- */ + +extern VSession verse_send_connect(const char *name, const char *pass, const char *address, const uint8 *expected_host_id); +extern VSession verse_send_connect_accept(VNodeID avatar, const char *address, uint8 *host_id); +extern void verse_send_connect_terminate(const char *address, const char *bye); +extern void verse_send_ping(const char *address, const char *message); +extern void verse_send_node_index_subscribe(uint32 mask); +extern void verse_send_node_create(VNodeID node_id, VNodeType type, VNodeOwner owner); +extern void verse_send_node_destroy(VNodeID node_id); +extern void verse_send_node_subscribe(VNodeID node_id); +extern void verse_send_node_unsubscribe(VNodeID node_id); +extern void verse_send_tag_group_create(VNodeID node_id, uint16 group_id, const char *name); +extern void verse_send_tag_group_destroy(VNodeID node_id, uint16 group_id); +extern void verse_send_tag_group_subscribe(VNodeID node_id, uint16 group_id); +extern void verse_send_tag_group_unsubscribe(VNodeID node_id, uint16 group_id); +extern void verse_send_tag_create(VNodeID node_id, uint16 group_id, uint16 tag_id, const char *name, VNTagType type, const VNTag *tag); +extern void verse_send_tag_destroy(VNodeID node_id, uint16 group_id, uint16 tag_id); +extern void verse_send_node_name_set(VNodeID node_id, const char *name); + +extern void verse_send_o_transform_pos_real32(VNodeID node_id, uint32 time_s, uint32 time_f, const real32 *pos, const real32 *speed, const real32 *accelerate, const real32 *drag_normal, real32 drag); +extern void verse_send_o_transform_rot_real32(VNodeID node_id, uint32 time_s, uint32 time_f, const VNQuat32 *rot, const VNQuat32 *speed, const VNQuat32 *accelerate, const VNQuat32 *drag_normal, real32 drag); +extern void verse_send_o_transform_scale_real32(VNodeID node_id, real32 scale_x, real32 scale_y, real32 scale_z); +extern void verse_send_o_transform_pos_real64(VNodeID node_id, uint32 time_s, uint32 time_f, const real64 *pos, const real64 *speed, const real64 *accelerate, const real64 *drag_normal, real64 drag); +extern void verse_send_o_transform_rot_real64(VNodeID node_id, uint32 time_s, uint32 time_f, const VNQuat64 *rot, const VNQuat64 *speed, const VNQuat64 *accelerate, const VNQuat64 *drag_normal, real64 drag); +extern void verse_send_o_transform_scale_real64(VNodeID node_id, real64 scale_x, real64 scale_y, real64 scale_z); +extern void verse_send_o_transform_subscribe(VNodeID node_id, VNRealFormat type); +extern void verse_send_o_transform_unsubscribe(VNodeID node_id, VNRealFormat type); +extern void verse_send_o_light_set(VNodeID node_id, real64 light_r, real64 light_g, real64 light_b); +extern void verse_send_o_link_set(VNodeID node_id, uint16 link_id, VNodeID link, const char *label, uint32 target_id); +extern void verse_send_o_link_destroy(VNodeID node_id, uint16 link_id); +extern void verse_send_o_method_group_create(VNodeID node_id, uint16 group_id, const char *name); +extern void verse_send_o_method_group_destroy(VNodeID node_id, uint16 group_id); +extern void verse_send_o_method_group_subscribe(VNodeID node_id, uint16 group_id); +extern void verse_send_o_method_group_unsubscribe(VNodeID node_id, uint16 group_id); +extern void verse_send_o_method_create(VNodeID node_id, uint16 group_id, uint16 method_id, const char *name, uint8 param_count, const VNOParamType *param_types, const char * *param_names); +extern void verse_send_o_method_destroy(VNodeID node_id, uint16 group_id, uint16 method_id); +extern void verse_send_o_method_call(VNodeID node_id, uint16 group_id, uint16 method_id, VNodeID sender, const VNOPackedParams *params); +extern void verse_send_o_anim_run(VNodeID node_id, uint16 link_id, uint32 time_s, uint32 time_f, uint8 dimensions, const real64 *pos, const real64 *speed, const real64 *accel, const real64 *scale, const real64 *scale_speed); +extern void verse_send_o_hide(VNodeID node_id, uint8 hidden); + +extern void verse_send_g_layer_create(VNodeID node_id, VLayerID layer_id, const char *name, VNGLayerType type, uint32 def_uint, real64 def_real); +extern void verse_send_g_layer_destroy(VNodeID node_id, VLayerID layer_id); +extern void verse_send_g_layer_subscribe(VNodeID node_id, VLayerID layer_id, VNRealFormat type); +extern void verse_send_g_layer_unsubscribe(VNodeID node_id, VLayerID layer_id); +extern void verse_send_g_vertex_set_xyz_real32(VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real32 x, real32 y, real32 z); +extern void verse_send_g_vertex_delete_real32(VNodeID node_id, uint32 vertex_id); +extern void verse_send_g_vertex_set_xyz_real64(VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real64 x, real64 y, real64 z); +extern void verse_send_g_vertex_delete_real64(VNodeID node_id, uint32 vertex_id); +extern void verse_send_g_vertex_set_uint32(VNodeID node_id, VLayerID layer_id, uint32 vertex_id, uint32 value); +extern void verse_send_g_vertex_set_real64(VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real64 value); +extern void verse_send_g_vertex_set_real32(VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real32 value); +extern void verse_send_g_polygon_set_corner_uint32(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3); +extern void verse_send_g_polygon_delete(VNodeID node_id, uint32 polygon_id); +extern void verse_send_g_polygon_set_corner_real64(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real64 v0, real64 v1, real64 v2, real64 v3); +extern void verse_send_g_polygon_set_corner_real32(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real32 v0, real32 v1, real32 v2, real32 v3); +extern void verse_send_g_polygon_set_face_uint8(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint8 value); +extern void verse_send_g_polygon_set_face_uint32(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint32 value); +extern void verse_send_g_polygon_set_face_real64(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real64 value); +extern void verse_send_g_polygon_set_face_real32(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real32 value); +extern void verse_send_g_crease_set_vertex(VNodeID node_id, const char *layer, uint32 def_crease); +extern void verse_send_g_crease_set_edge(VNodeID node_id, const char *layer, uint32 def_crease); +extern void verse_send_g_bone_create(VNodeID node_id, uint16 bone_id, const char *weight, const char *reference, uint16 parent, real64 pos_x, real64 pos_y, real64 pos_z, const char *position_label, const char *rotation_label, const char *scale_label); +extern void verse_send_g_bone_destroy(VNodeID node_id, uint16 bone_id); + +extern void verse_send_m_fragment_create(VNodeID node_id, VNMFragmentID frag_id, VNMFragmentType type, const VMatFrag *fragment); +extern void verse_send_m_fragment_destroy(VNodeID node_id, VNMFragmentID frag_id); + +extern void verse_send_b_dimensions_set(VNodeID node_id, uint16 width, uint16 height, uint16 depth); +extern void verse_send_b_layer_create(VNodeID node_id, VLayerID layer_id, const char *name, VNBLayerType type); +extern void verse_send_b_layer_destroy(VNodeID node_id, VLayerID layer_id); +extern void verse_send_b_layer_subscribe(VNodeID node_id, VLayerID layer_id, uint8 level); +extern void verse_send_b_layer_unsubscribe(VNodeID node_id, VLayerID layer_id); +extern void verse_send_b_tile_set(VNodeID node_id, VLayerID layer_id, uint16 tile_x, uint16 tile_y, uint16 z, VNBLayerType type, const VNBTile *tile); + +extern void verse_send_t_language_set(VNodeID node_id, const char *language); +extern void verse_send_t_buffer_create(VNodeID node_id, VBufferID buffer_id, const char *name); +extern void verse_send_t_buffer_destroy(VNodeID node_id, VBufferID buffer_id); +extern void verse_send_t_buffer_subscribe(VNodeID node_id, VBufferID buffer_id); +extern void verse_send_t_buffer_unsubscribe(VNodeID node_id, VBufferID buffer_id); +extern void verse_send_t_text_set(VNodeID node_id, VBufferID buffer_id, uint32 pos, uint32 length, const char *text); + +extern void verse_send_c_curve_create(VNodeID node_id, VLayerID curve_id, const char *name, uint8 dimensions); +extern void verse_send_c_curve_destroy(VNodeID node_id, VLayerID curve_id); +extern void verse_send_c_curve_subscribe(VNodeID node_id, VLayerID curve_id); +extern void verse_send_c_curve_unsubscribe(VNodeID node_id, VLayerID curve_id); +extern void verse_send_c_key_set(VNodeID node_id, VLayerID curve_id, uint32 key_id, uint8 dimensions, const real64 *pre_value, const uint32 *pre_pos, const real64 *value, real64 pos, const real64 *post_value, const uint32 *post_pos); +extern void verse_send_c_key_destroy(VNodeID node_id, VLayerID curve_id, uint32 key_id); + +extern void verse_send_a_buffer_create(VNodeID node_id, VBufferID buffer_id, const char *name, VNABlockType type, real64 frequency); +extern void verse_send_a_buffer_destroy(VNodeID node_id, VBufferID buffer_id); +extern void verse_send_a_buffer_subscribe(VNodeID node_id, VBufferID layer_id); +extern void verse_send_a_buffer_unsubscribe(VNodeID node_id, VBufferID layer_id); +extern void verse_send_a_block_set(VNodeID node_id, VLayerID buffer_id, uint32 block_index, VNABlockType type, const VNABlock *samples); +extern void verse_send_a_block_clear(VNodeID node_id, VLayerID buffer_id, uint32 block_index); +extern void verse_send_a_stream_create(VNodeID node_id, VLayerID stream_id, const char *name); +extern void verse_send_a_stream_destroy(VNodeID node_id, VLayerID stream_id); +extern void verse_send_a_stream_subscribe(VNodeID node_id, VLayerID stream_id); +extern void verse_send_a_stream_unsubscribe(VNodeID node_id, VLayerID stream_id); +extern void verse_send_a_stream(VNodeID node_id, VLayerID stream_id, uint32 time_s, uint32 time_f, VNABlockType type, real64 frequency, const VNABlock *samples); + + +#if defined __cplusplus +} +#endif + +#endif /* VERSE_H */ diff --git a/extern/verse/dist/verse_header.h b/extern/verse/dist/verse_header.h new file mode 100644 index 00000000000..3f3403265fd --- /dev/null +++ b/extern/verse/dist/verse_header.h @@ -0,0 +1,409 @@ +#if !defined VERSE_TYPES +#define VERSE_TYPES + +#include + +/* Release information. */ +#define V_RELEASE_NUMBER 6 +#define V_RELEASE_PATCH 1 +#define V_RELEASE_LABEL "" + +typedef unsigned char boolean; +typedef signed char int8; +typedef unsigned char uint8; +typedef short int16; +typedef unsigned short uint16; +typedef int int32; +typedef unsigned int uint32; +typedef float real32; +typedef double real64; + +#define V_REAL64_MAX 1.7976931348623158e+308 +#define V_REAL32_MAX 3.402823466e+38f + +#if !defined TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +#define V_HOST_ID_SIZE (3 * (512 / 8)) /* The size of host IDs (keys), in 8-bit bytes. */ + +typedef enum { + V_NT_OBJECT = 0, + V_NT_GEOMETRY, + V_NT_MATERIAL, + V_NT_BITMAP, + V_NT_TEXT, + V_NT_CURVE, + V_NT_AUDIO, + V_NT_NUM_TYPES, + V_NT_SYSTEM = V_NT_NUM_TYPES, + V_NT_NUM_TYPES_NETPACK +} VNodeType; + +typedef uint32 VNodeID; +typedef uint16 VLayerID; /* Commonly used to identify layers, nodes that have them. */ +typedef uint16 VBufferID; /* Commonly used to identify buffers, nodes that have them. */ +typedef uint16 VNMFragmentID; + +typedef void * VSession; + +#define V_MAX_NAME_LENGTH_SHORT 16 +#define V_MAX_NAME_LENGTH_LONG 48 +#define V_MAX_NAME_PASS_LENGTH 128 + +typedef enum { + VN_OWNER_OTHER = 0, + VN_OWNER_MINE +} VNodeOwner; + +typedef enum { + VN_O_METHOD_PTYPE_INT8 = 0, + VN_O_METHOD_PTYPE_INT16, + VN_O_METHOD_PTYPE_INT32, + + VN_O_METHOD_PTYPE_UINT8, + VN_O_METHOD_PTYPE_UINT16, + VN_O_METHOD_PTYPE_UINT32, + + VN_O_METHOD_PTYPE_REAL32, + VN_O_METHOD_PTYPE_REAL64, + + VN_O_METHOD_PTYPE_REAL32_VEC2, + VN_O_METHOD_PTYPE_REAL32_VEC3, + VN_O_METHOD_PTYPE_REAL32_VEC4, + + VN_O_METHOD_PTYPE_REAL64_VEC2, + VN_O_METHOD_PTYPE_REAL64_VEC3, + VN_O_METHOD_PTYPE_REAL64_VEC4, + + VN_O_METHOD_PTYPE_REAL32_MAT4, + VN_O_METHOD_PTYPE_REAL32_MAT9, + VN_O_METHOD_PTYPE_REAL32_MAT16, + + VN_O_METHOD_PTYPE_REAL64_MAT4, + VN_O_METHOD_PTYPE_REAL64_MAT9, + VN_O_METHOD_PTYPE_REAL64_MAT16, + + VN_O_METHOD_PTYPE_STRING, + + VN_O_METHOD_PTYPE_NODE, + VN_O_METHOD_PTYPE_LAYER +} VNOParamType; + +typedef union { + int8 vint8; + int16 vint16; + int32 vint32; + uint8 vuint8; + uint16 vuint16; + uint32 vuint32; + real32 vreal32; + real64 vreal64; + real32 vreal32_vec[4]; + real32 vreal32_mat[16]; + real64 vreal64_vec[4]; + real64 vreal64_mat[16]; + char *vstring; + VNodeID vnode; + VLayerID vlayer; +} VNOParam; + +#define VN_TAG_MAX_BLOB_SIZE 500 + +typedef enum { + VN_TAG_BOOLEAN = 0, + VN_TAG_UINT32, + VN_TAG_REAL64, + VN_TAG_STRING, + VN_TAG_REAL64_VEC3, + VN_TAG_LINK, + VN_TAG_ANIMATION, + VN_TAG_BLOB, + VN_TAG_TYPE_COUNT +} VNTagType; + +typedef enum { + VN_TAG_GROUP_SIZE = 16, + VN_TAG_NAME_SIZE = 16, + VN_TAG_FULL_NAME_SIZE = 64, + VN_TAG_STRING_SIZE = 128 +} VNTagConstants; + +typedef union { + boolean vboolean; + uint32 vuint32; + real64 vreal64; + char *vstring; + real64 vreal64_vec3[3]; + VNodeID vlink; + struct { + VNodeID curve; + uint32 start; + uint32 end; + } vanimation; + struct { + uint16 size; + void *blob; + } vblob; +} VNTag; + +typedef enum { + VN_S_CONNECT_NAME_SIZE = 32, + VN_S_CONNECT_KEY_SIZE = 4, + VN_S_CONNECT_DATA_SIZE = 32, + VS_S_CONNECT_HOSTID_PRIVATE_SIZE = 3 * 2048 / 8, + VS_S_CONNECT_HOSTID_PUBLIC_SIZE = 2 * 2048 / 8 +} VNSConnectConstants; + +typedef enum { + VN_FORMAT_REAL32, + VN_FORMAT_REAL64 +} VNRealFormat; + +typedef struct { + real32 x, y, z, w; +} VNQuat32; + +typedef struct { + real64 x, y, z, w; +} VNQuat64; + +typedef enum { + VN_O_METHOD_GROUP_NAME_SIZE = 16, + VN_O_METHOD_NAME_SIZE = 16, + VN_O_METHOD_SIG_SIZE = 256 +} VNOMethodConstants; + +typedef void VNOPackedParams; /* Opaque type. */ + +typedef enum { + VN_G_LAYER_VERTEX_XYZ = 0, + VN_G_LAYER_VERTEX_UINT32, + VN_G_LAYER_VERTEX_REAL, + VN_G_LAYER_POLYGON_CORNER_UINT32 = 128, + VN_G_LAYER_POLYGON_CORNER_REAL, + VN_G_LAYER_POLYGON_FACE_UINT8, + VN_G_LAYER_POLYGON_FACE_UINT32, + VN_G_LAYER_POLYGON_FACE_REAL +} VNGLayerType; + +typedef enum { + VN_M_LIGHT_DIRECT = 0, + VN_M_LIGHT_AMBIENT, + VN_M_LIGHT_DIRECT_AND_AMBIENT, + VN_M_LIGHT_BACK_DIRECT, + VN_M_LIGHT_BACK_AMBIENT, + VN_M_LIGHT_BACK_DIRECT_AND_AMBIENT +} VNMLightType; + +typedef enum { + VN_M_NOISE_PERLIN_ZERO_TO_ONE = 0, + VN_M_NOISE_PERLIN_MINUS_ONE_TO_ONE, + VN_M_NOISE_POINT_ZERO_TO_ONE, + VN_M_NOISE_POINT_MINUS_ONE_TO_ONE +} VNMNoiseType; + +typedef enum { + VN_M_RAMP_SQUARE = 0, + VN_M_RAMP_LINEAR, + VN_M_RAMP_SMOOTH +} VNMRampType; + +typedef enum { + VN_M_RAMP_RED = 0, + VN_M_RAMP_GREEN, + VN_M_RAMP_BLUE +} VNMRampChannel; + +typedef struct { + real64 pos; + real64 red; + real64 green; + real64 blue; +} VNMRampPoint; + +typedef enum { + VN_M_BLEND_FADE = 0, + VN_M_BLEND_ADD, + VN_M_BLEND_SUBTRACT, + VN_M_BLEND_MULTIPLY, + VN_M_BLEND_DIVIDE, +} VNMBlendType; + +typedef enum { + VN_M_FT_COLOR = 0, + VN_M_FT_LIGHT, + VN_M_FT_REFLECTION, + VN_M_FT_TRANSPARENCY, + VN_M_FT_VOLUME, + VN_M_FT_VIEW, + VN_M_FT_GEOMETRY, + VN_M_FT_TEXTURE, + VN_M_FT_NOISE, + VN_M_FT_BLENDER, + VN_M_FT_CLAMP, + VN_M_FT_MATRIX, + VN_M_FT_RAMP, + VN_M_FT_ANIMATION, + VN_M_FT_ALTERNATIVE, + VN_M_FT_OUTPUT +} VNMFragmentType; + +typedef union { + struct { + real64 red; + real64 green; + real64 blue; + } color; + struct { + uint8 type; + real64 normal_falloff; + VNodeID brdf; + char brdf_r[16]; + char brdf_g[16]; + char brdf_b[16]; + } light; + struct { + real64 normal_falloff; + } reflection; + struct { + real64 normal_falloff; + real64 refraction_index; + } transparency; + struct { + real64 diffusion; + real64 col_r; + real64 col_g; + real64 col_b; + } volume; + struct { + char layer_r[16]; + char layer_g[16]; + char layer_b[16]; + } geometry; + struct{ + VNodeID bitmap; + char layer_r[16]; + char layer_g[16]; + char layer_b[16]; + boolean filtered; + VNMFragmentID mapping; + } texture; + struct { + uint8 type; + VNMFragmentID mapping; + } noise; + struct { + uint8 type; + VNMFragmentID data_a; + VNMFragmentID data_b; + VNMFragmentID control; + } blender; + struct { + boolean min; + real64 red; + real64 green; + real64 blue; + VNMFragmentID data; + } clamp; + struct { + real64 matrix[16]; + VNMFragmentID data; + } matrix; + struct { + uint8 type; + uint8 channel; + VNMFragmentID mapping; + uint8 point_count; + VNMRampPoint ramp[48]; + } ramp; + struct { + char label[16]; + } animation; + struct { + VNMFragmentID alt_a; + VNMFragmentID alt_b; + } alternative; + struct { + char label[16]; + VNMFragmentID front; + VNMFragmentID back; + } output; +} VMatFrag; + +typedef enum { + VN_B_LAYER_UINT1 = 0, + VN_B_LAYER_UINT8, + VN_B_LAYER_UINT16, + VN_B_LAYER_REAL32, + VN_B_LAYER_REAL64 +} VNBLayerType; + +#define VN_B_TILE_SIZE 8 + +typedef union{ + uint8 vuint1[8]; + uint8 vuint8[64]; + uint16 vuint16[64]; + real32 vreal32[64]; + real64 vreal64[64]; +} VNBTile; + +typedef enum { + VN_T_CONTENT_LANGUAGE_SIZE = 32, + VN_T_CONTENT_INFO_SIZE = 256, + VN_T_BUFFER_NAME_SIZE = 16, + VN_T_MAX_TEXT_CMD_SIZE = 1450 +} VNTConstants; + +/* This is how many *samples* are included in a block of the given type. Not bytes. */ +typedef enum { + VN_A_BLOCK_SIZE_INT8 = 1024, + VN_A_BLOCK_SIZE_INT16 = 512, + VN_A_BLOCK_SIZE_INT24 = 384, + VN_A_BLOCK_SIZE_INT32 = 256, + VN_A_BLOCK_SIZE_REAL32 = 256, + VN_A_BLOCK_SIZE_REAL64 = 128 +} VNAConstants; + +typedef enum { + VN_A_BLOCK_INT8, + VN_A_BLOCK_INT16, + VN_A_BLOCK_INT24, + VN_A_BLOCK_INT32, + VN_A_BLOCK_REAL32, + VN_A_BLOCK_REAL64 +} VNABlockType; + +/* Audio commands take pointers to blocks of these. They are not packed as unions. */ +typedef union { + int8 vint8[VN_A_BLOCK_SIZE_INT8]; + int16 vint16[VN_A_BLOCK_SIZE_INT16]; + int32 vint24[VN_A_BLOCK_SIZE_INT24]; + int32 vint32[VN_A_BLOCK_SIZE_INT32]; + real32 vreal32[VN_A_BLOCK_SIZE_REAL32]; + real64 vreal64[VN_A_BLOCK_SIZE_REAL64]; +} VNABlock; + +extern void verse_set_port(uint16 port); +extern void verse_host_id_create(uint8 *id); +extern void verse_host_id_set(uint8 *id); +extern void verse_callback_set(void *send_func, void *callback, void *user_data); +extern void verse_callback_update(uint32 microseconds); +extern void verse_session_set(VSession session); +extern VSession verse_session_get(void); +extern void verse_session_destroy(VSession session); +extern size_t verse_session_get_size(void); +extern VNodeID verse_session_get_avatar(void); +extern void verse_session_get_time(uint32 *seconds, uint32 *fractions); + +extern VNOPackedParams * verse_method_call_pack(uint32 param_count, const VNOParamType *param_type, const VNOParam *params); +extern boolean verse_method_call_unpack(const VNOPackedParams *data, uint32 param_count, const VNOParamType *param_type, VNOParam *params); + +/* +#define V_PRINT_SEND_COMMANDS +#define V_PRINT_RECEIVE_COMMANDS +*/ + +#endif /* VERSE_TYPES */ diff --git a/extern/verse/dist/verse_ms.c b/extern/verse/dist/verse_ms.c new file mode 100644 index 00000000000..84f3fdb837b --- /dev/null +++ b/extern/verse/dist/verse_ms.c @@ -0,0 +1,286 @@ +/* + * A helper library to send and parse master server pings. See the relevant + * header for details. + * + * This code was written in 2006 by Emil Brink. It is released as public domain. +*/ + +#include +#include +#include +#include + +#include "verse.h" +#include "verse_ms.h" + +/* Build and send a MS:GET packet. */ +void verse_ms_get_send(const char *address, int fields, const char *tags) +{ + char req[128]; + + strcpy(req, "MS:GET IP="); + if(fields & VERSE_MS_FIELD_DESCRIPTION) + strcat(req, "DE"); + if(tags != NULL) + { + strcat(req, " TA="); + strcat(req, tags); + } + verse_send_ping(address, req); +} + +/* Skip assign, i.e. "NAME=" string, at . Stores name into , and then updates + * it. Returns NULL on parse error, in which case the pointer is not advanced. +*/ +static const char * skip_assign(char **put, const char *msg) +{ + if(isalpha(*msg)) + { + char *p = put != NULL ? *put : NULL; + + if(p != NULL) + *p++ = *msg; + msg++; + while(*msg && (isalnum(*msg) || *msg == '_')) + { + if(p != NULL) + *p++ = *msg; + msg++; + } + if(*msg == '=') + { + if(p != NULL) + *p++ = '\0'; + if(put != NULL) + *put = p; + return msg + 1; + } + } + return NULL; +} + +/** Skip value at , optionally storing de-quoted version through , + * which is advanced. Returns NULL on parse error, without updating . +*/ +static const char * skip_value(char **put, const char *msg) +{ + char *p = (put != NULL) ? *put : NULL; + + if(*msg == '"') + { + msg++; + while(*msg != '\0' && *msg != '"') + { + if(*msg == '\\') + { + if(msg[1] != '\0') + msg++; + else + return NULL; + } + if(p != NULL) + *p++ = *msg; + msg++; + } + if(*msg == '"') + { + if(p != NULL) + *p++ = '\0'; + if(put != NULL) + *put = p; + msg++; + if(*msg == '\0' || isspace(*msg)) + return msg; + } + return NULL; + } + while(*msg && !isspace(*msg)) + { + if(*msg == '"') + return NULL; + if(p != NULL) + *p++ = *msg; + msg++; + } + if(p != NULL) + *p++ = '\0'; + if(put != NULL) + *put = p; + return msg; +} + +static const char * put_field(VMSField *field, char **put, const char *src) +{ + const char *ptr; + char *base = *put; + + if((ptr = skip_assign(put, src)) != NULL && ptr - src > 1) + { + field->name = base; + src = ptr; + base = *put; + if((ptr = skip_value(put, src)) != NULL) + { + field->value = base; + return ptr; + } + } + return NULL; +} + +static int cmp_fields(const void *a, const void *b) +{ + return strcmp(((const VMSField *) a)->name, ((const VMSField *) b)->name); +} + +VMSServer ** verse_ms_list_parse(const char *msg) +{ + const char *word[384]; /* Takes quite a lot of stack space. */ + const char *ptr; + char *put; + size_t num_word = 0, i, j, num_ip = 0, num_field, space = 0; + VMSServer **desc, *next; + VMSField *field; + + if(strncmp(msg, "MS:LIST", 7) == 0) + msg += 7; + if(*msg != ' ') + return NULL; + + /* Step one: split the string into words, at whitespace. Split is aware + * of quoting rules for value assignment, this is crucial. This split is + * non-invasive, meaning each "word" will be a suffix. + */ + while(*msg) + { + while(isspace(*msg)) + msg++; + ptr = skip_assign(NULL, msg); + if(ptr != NULL) + { + space += ptr - msg; + word[num_word++] = msg; + msg = ptr; + ptr = skip_value(NULL, msg); + if(ptr == NULL) + { + fprintf(stderr, "Parse error\n"); + return NULL; + } + space += ptr - msg + 1; + msg = ptr; + } + else if(*msg != '\0') + { + fprintf(stderr, "Parse error\n"); + return NULL; + } + } + /* Now, count how many words begin with "IP=". */ + for(i = 0; i < num_word; i++) + { + if(strncmp(word[i], "IP=", 3) == 0) + num_ip++; + } +/* printf("found %u IPs, %u bytes\n", num_ip, space); + printf("%u IP and %u words -> %u fields total\n", num_ip, num_word, num_word - num_ip); +*/ num_field = num_word - num_ip; + /* Allocate the descriptions. */ +/* printf("allocating %u bytes\n", (num_ip + 1) * (sizeof *desc) + num_ip * sizeof **desc + num_field * sizeof (VMSField) + space); + printf(" %u for pointers, %u for structs, %u for fields, %u string\n", + (num_ip + 1) * (sizeof *desc), num_ip * sizeof **desc, num_field * sizeof (VMSField), space); +*/ desc = malloc((num_ip + 1) * (sizeof *desc) + num_ip * sizeof **desc + num_field * sizeof (VMSField) + space); + next = (VMSServer *) (desc + (num_ip + 1)); +/* printf("desc store at %u\n", (char *) next - (char *) desc);*/ + field = (VMSField *) (next + num_ip); +/* printf("field store at %u\n", (char *) field - (char *) desc);*/ + put = (char *) (field + num_field); +/* printf("string store at %u\n", put - (char *) desc);*/ + for(i = j = 0; i < num_word;) + { + if(strncmp(word[i], "IP=", 3) == 0) + { + desc[j] = next; + next->ip = put; + ptr = skip_value(&put, word[i] + 3); + next->num_fields = 0; + next->field = field; + for(i++; i < num_word && strncmp(word[i], "IP=", 3) != 0; i++, next->num_fields++, field++) + put_field(&next->field[next->num_fields], &put, word[i]); + if(next->num_fields > 0) /* Sort the fields, for binary search later. */ + qsort(next->field, next->num_fields, sizeof *next->field, cmp_fields); + j++; + next++; + } + else + i++; + } + desc[j] = NULL; + return desc; +} + +/* A binary search, exploiting that the fields are sorted. */ +static const VMSField * field_find(const VMSServer *ms, const char *name) +{ + int lo, hi, mid, rel; + + if(ms == NULL || name == NULL) + return NULL; + lo = 0; + hi = ms->num_fields; + while(lo <= hi) + { + mid = (lo + hi) / 2; + rel = strcmp(name, ms->field[mid].name); + if(rel == 0) + return &ms->field[mid]; + if(rel < 0) + hi = mid - 1; + else + lo = mid + 1; + } + return NULL; +} + +int verse_ms_field_exists(const VMSServer *ms, const char *name) +{ + if(ms == NULL || name == NULL) + return 0; + return field_find(ms, name) != NULL; +} + +const char * verse_ms_field_value(const VMSServer *ms, const char *name) +{ + const VMSField *f; + + if((f = field_find(ms, name)) != NULL) + return f->value; + return NULL; +} + +#if defined VERSE_MS_STANDALONE + +int main(void) +{ + VMSServer **servers = verse_ms_list_parse("MS:LIST IP=127.0.0.1:4951 DE=\"A test server, mainly for Eskil\" COOL=yes BACKUP=daily LANG=sv_SE " + "IP=130.237.221.74 DE=\"Test server on a puny laptop\" COOL=yes DORKY=no OPEN=absolutely " + "IP=127.0.0.1:5151 DE=\"This is a back slash: '\\\\', cool huh?\" " + "IP=127.0.0.1:6676 DE=\"a quote looks like this: \\\"\" IP=127.0.0.1:1122 "); + + if(servers != NULL) + { + int i, j; + + printf("Server info:\n"); + for(i = 0; servers[i] != NULL; i++) + { + printf("%u: IP=%s\n", i, servers[i]->ip); + for(j = 0; j < servers[i]->num_fields; j++) + printf(" %s='%s'\n", servers[i]->field[j].name, servers[i]->field[j].value); + } + free(servers); + } + return EXIT_SUCCESS; +} + +#endif /* VERSE_MS_STANDALONE */ diff --git a/extern/verse/dist/verse_ms.h b/extern/verse/dist/verse_ms.h new file mode 100644 index 00000000000..5a27d3fd446 --- /dev/null +++ b/extern/verse/dist/verse_ms.h @@ -0,0 +1,72 @@ +/* + * This is Verse Master Server, a small help library to aid application developers + * make their applications interact with a Verse master server. + * + * There are two steps to the process: + * + * 1) Send a MS:GET request to a master server. This is done by the verse_ms_get_send() + * function, which calls verse_send_ping() internally. + * + * 2) Parse any returned MS:LIST packets. This is a two-step process. The application + * still owns the ping callback, and will need to check for received pings that + * start with MS:LIST, and call the verse_ms_list_parse() function to parse those. + * + * A successfully parsed MS:LIST packet will result in an array of VMSServer pointers + * being returned. Each VMSServer instance describes one server. Use the provided + * functions to query each server structure. + * + * The application should call free() on the returned vector, whenever it is done with + * the data (perhaps after copying it into application-defined data structures). + * + * For a lot more detail about the Verse master server protocol, please see + * the spec at . + * + * This code was written in 2006 by Emil Brink. It is released as public domain. + * +*/ + +#define VERSE_MS_VERSION "1.0" + +#if defined __cplusplus +extern "C" { +#endif + +typedef struct { + const char *name; /* Field name. Upper-case. */ + const char *value; /* Field value. Fully parsed, might contain spaces. */ +} VMSField; + +typedef struct { + const char *ip; /* IP address of server, in dotted decimal:port. */ + unsigned int num_fields; /* Number of fields of extra info. */ + VMSField *field; /* Vector of fields, or NULL if none. */ +} VMSServer; + +/* Formats and sends a MS:GET ping packet to the master server. The argument + * should be a combination of VERSE_MS_FIELD_ mask values. If is set, it should + * be a comma-separated set of include/exclude tags, like "a,b,-c,d,-e". +*/ +#define VERSE_MS_FIELD_DESCRIPTION (1 << 0) +extern void verse_ms_get_send(const char *address, int fields, const char *tags); + +/* Parses a master server response. This will be a string of the form "MS:LIST IP=blah ...", + * which is split into one struct per IP, and any additional fields parsed (unquoted etc). + * Returns an array of VMSServer pointers, which is NULL-terminated. Returns NULL if there + * was a parse error somewhere in the string, no partial success is possible. +*/ +extern VMSServer ** verse_ms_list_parse(const char *list); + +/* This is the only standard field name, currently. */ +#define VERSE_MS_FIELD_DESCRIPTION_NAME "DE" /* Human-readable server description. */ + +/* Checks wether the given server has a field with the given name. */ +extern int verse_ms_field_exists(const VMSServer *ms, const char *name); + +/* Returns the value for the named field in the given server, if present. + * If not, NULL is returned. +*/ +extern const char * verse_ms_field_value(const VMSServer *ms, const char *name); + +#if defined __cplusplus +} +#endif diff --git a/extern/verse/dist/vs_connection.c b/extern/verse/dist/vs_connection.c new file mode 100644 index 00000000000..06614a5dc66 --- /dev/null +++ b/extern/verse/dist/vs_connection.c @@ -0,0 +1,179 @@ +#include + +#include "v_cmd_gen.h" + +#if !defined(V_GENERATE_FUNC_MODE) + +#include "verse.h" +#include "v_util.h" + +#define VS_CONNECTION_CHUNK_SIZE 64 + +typedef struct{ + VSession *session; + unsigned int session_count; +} VSSubscriptionList; + +typedef struct{ + VSession session; + uint32 node_id; + char name[128]; + char pass[128]; +} VSConnection; + +static struct { + VSConnection *connection; + unsigned int connection_length; + VSSubscriptionList **list; + unsigned int list_length; + unsigned int current_session; +} VSConnectionStorage; + +void vs_init_connection_storage(void) +{ + VSConnectionStorage.connection = NULL; + VSConnectionStorage.connection_length = 0; + VSConnectionStorage.list = NULL; + VSConnectionStorage.list_length = 0; + VSConnectionStorage.current_session = 0; +} + +void vs_add_new_connection(VSession session, const char *name, const char *pass, VNodeID node_id) +{ + VSConnection *conn; + + if(VSConnectionStorage.connection_length % VS_CONNECTION_CHUNK_SIZE == 0) + VSConnectionStorage.connection = realloc(VSConnectionStorage.connection, (sizeof *VSConnectionStorage.connection) * (VSConnectionStorage.connection_length + VS_CONNECTION_CHUNK_SIZE)); + conn = &VSConnectionStorage.connection[VSConnectionStorage.connection_length]; + + conn->session = session; + conn->node_id = node_id; + v_strlcpy(conn->name, name, sizeof conn->name); + v_strlcpy(conn->pass, pass, sizeof conn->pass); + + VSConnectionStorage.connection_length++; +} + +uint32 vs_get_avatar(void) +{ + return VSConnectionStorage.connection[VSConnectionStorage.current_session].node_id; +} + +VSession vs_get_session(void) +{ + return VSConnectionStorage.connection[VSConnectionStorage.current_session].session; +} + +const char * vs_get_user_name(void) +{ + return VSConnectionStorage.connection[VSConnectionStorage.current_session].name; +} + +const char * vs_get_user_pass(void) +{ + return VSConnectionStorage.connection[VSConnectionStorage.current_session].pass; +} + + +void vs_remove_connection(void) +{ + unsigned int i, j; + VSession *session; + VSSubscriptionList *list; + + session = VSConnectionStorage.connection[VSConnectionStorage.current_session].session; + for(i = 0; i < VSConnectionStorage.list_length; i++) + { + list = VSConnectionStorage.list[i]; + for(j = 0; j < list->session_count && list->session[j] != session; j++); + if(j < list->session_count) + list->session[j] = list->session[--list->session_count]; + } + j = --VSConnectionStorage.connection_length; + + if(VSConnectionStorage.current_session < j) + { + VSConnectionStorage.connection[VSConnectionStorage.current_session].session = VSConnectionStorage.connection[j].session; + VSConnectionStorage.connection[VSConnectionStorage.current_session].node_id = VSConnectionStorage.connection[j].node_id; + } + else + VSConnectionStorage.current_session = 0; +} + +void vs_set_next_session(void) +{ + if(++VSConnectionStorage.current_session >= VSConnectionStorage.connection_length) + VSConnectionStorage.current_session = 0; + if(VSConnectionStorage.connection_length != 0) + verse_session_set(VSConnectionStorage.connection[VSConnectionStorage.current_session].session); +} + +VSSubscriptionList *vs_create_subscription_list(void) +{ + VSSubscriptionList *list; + list = malloc(sizeof *list); + if(VSConnectionStorage.list_length % VS_CONNECTION_CHUNK_SIZE == 0) + VSConnectionStorage.list = realloc(VSConnectionStorage.list, (sizeof *VSConnectionStorage.list) * (VSConnectionStorage.list_length + VS_CONNECTION_CHUNK_SIZE)); + VSConnectionStorage.list[VSConnectionStorage.list_length] = list; + list->session = NULL; + list->session_count = 0; + VSConnectionStorage.list_length++; + return list; +} + +void vs_destroy_subscription_list(VSSubscriptionList *list) +{ + unsigned int i; + + if(list == NULL) + return; + if(list->session != NULL) + free(list->session); + for(i = 0; i < VSConnectionStorage.list_length && VSConnectionStorage.list[i] != list; i++) + ; + if(i < VSConnectionStorage.list_length) + VSConnectionStorage.list[i] = VSConnectionStorage.list[--VSConnectionStorage.list_length]; + free(list); +} + +/* Returns 1 if subscriber was added, 0 if not (typically meaning it was already on the list). */ +int vs_add_new_subscriptor(VSSubscriptionList *list) +{ + unsigned int i; + if(list->session_count % VS_CONNECTION_CHUNK_SIZE == 0) + list->session = realloc(list->session, (sizeof *list->session) * (list->session_count + VS_CONNECTION_CHUNK_SIZE)); + for(i = 0; i < list->session_count; i++) + if(list->session[i] == VSConnectionStorage.connection[VSConnectionStorage.current_session].session) + return 0; + list->session[list->session_count] = VSConnectionStorage.connection[VSConnectionStorage.current_session].session; + list->session_count++; + return 1; +} + + +void vs_remove_subscriptor(VSSubscriptionList *list) +{ + unsigned int i; + VSession *session; + session = VSConnectionStorage.connection[VSConnectionStorage.current_session].session; + for(i = 0; i < list->session_count && list->session[i] != session; i++); + if(i < list->session_count) + list->session[i] = list->session[--list->session_count]; +} + +size_t vs_get_subscript_count(const VSSubscriptionList *list) +{ + return list != NULL ? list->session_count : 0; +} + +void vs_set_subscript_session(VSSubscriptionList *list, unsigned int session) +{ + verse_session_set(list->session[session]); +} + +void vs_reset_subscript_session(void) +{ + verse_session_set(VSConnectionStorage.connection[VSConnectionStorage.current_session].session); +} + +#endif diff --git a/extern/verse/dist/vs_main.c b/extern/verse/dist/vs_main.c new file mode 100644 index 00000000000..3b388eecc56 --- /dev/null +++ b/extern/verse/dist/vs_main.c @@ -0,0 +1,180 @@ +/* +** A simple Verse server. +*/ + +#include +#include +#include +#include + +#include "v_cmd_gen.h" + +#if !defined V_GENERATE_FUNC_MODE + +#include "verse.h" +#include "v_network.h" +#include "v_util.h" +#include "vs_server.h" + +extern VNodeID vs_node_create(VNodeID owner_id, unsigned int type); +extern void callback_send_node_destroy(void *user_data, VNodeID node_id); +extern void vs_reset_owner(VNodeID owner_id); + +static void callback_send_connect(void *user, const char *name, const char *pass, const char *address, const uint8 *host_id) +{ + VNodeID avatar; + VSession *session; + + printf("Connecting '%s'\n", name); + if(TRUE) + { + avatar = vs_node_create(~0, V_NT_OBJECT); + session = verse_send_connect_accept(avatar, address, NULL); + vs_add_new_connection(session, name, pass, avatar); +/* vs_avatar_init(avatar, name);*/ + } + else + { + verse_send_connect_terminate(address, "I'm sorry but you are not welcome here."); + } +} + +static void callback_send_connect_terminate(void *user, char *address, char *bye) +{ + printf("callback_send_connect_terminate\n"); + vs_reset_owner(vs_get_avatar()); + callback_send_node_destroy(NULL, vs_get_avatar()); + verse_session_destroy(vs_get_session()); + vs_remove_connection(); +} + +static void vs_load_host_id(const char *file_name) +{ + FILE *f; + uint8 id[V_HOST_ID_SIZE]; + size_t got; + + /* Attempt to read key from given filename. Fails silently. */ + if((f = fopen(file_name, "rb")) != NULL) + { + if((got = fread(id, 1, sizeof id, f)) > 0) + { + printf("Loaded %u-bit host ID key successfully\n", 8 * (got / 3)); + verse_host_id_set(id); + } + fclose(f); + if(got) + return; + } + /* If file didn't open, or reading failed, generate a new key and write it out. */ + verse_host_id_create(id); + verse_host_id_set(id); + if((f = fopen(file_name, "wb")) != NULL) + { + if(fwrite(id, sizeof id, 1, f) != 1) + fprintf(stderr, "Warning: Couldn't write host ID to \"%s\"\n", file_name); + fclose(f); + } + else + fprintf(stderr, "Warning: Couldn't open \"%s\" for host ID writing\n", file_name); +} + +static void cb_sigint_handler(int sig) +{ + if(sig == SIGINT) + { + printf("Verse server terminating\n"); + exit(EXIT_SUCCESS); + } +} + +static void callback_send_ping(void *user, const char *address, const char *message) +{ + if(strncmp(message, "DESCRIBE", 8) == 0 && message[8] == ' ') + vs_master_handle_describe(address, message + 9); +} + +static void usage(void) +{ + printf("Verse server usage:\n"); + printf(" -h\t\t\tShow this usage information.\n"); + printf(" -ms\t\t\tRegisters the server with a master server at the address\n"); + printf(" \t\t\tgiven with the -ms:ip= option. Off by default.\n"); + printf(" -ms:ip=IP[:PORT]\tSet master server to register with. Implies -ms.\n"); + printf(" \t\t\tThe default address is <%s>.\n", vs_master_get_address()); + printf(" -ms:de=DESC\t\tSet description, sent to master server.\n"); + printf(" -ms:ta=TAGS\t\tSet tags, sent to master server.\n"); + printf(" -port=PORT\t\tSet port to use for incoming connections.\n"); + printf(" -version\t\tPrint version information and exit.\n"); +} + +int main(int argc, char **argv) +{ + uint32 i, seconds, fractions, port = VERSE_STD_CONNECT_PORT; + + signal(SIGINT, cb_sigint_handler); + + vs_master_set_address("master.uni-verse.org"); /* The default master address. */ + vs_master_set_enabled(FALSE); /* Make sure master server support is disabled. */ + for(i = 1; i < (uint32) argc; i++) + { + if(strcmp(argv[i], "-h") == 0) + { + usage(); + return EXIT_SUCCESS; + } + else if(strcmp(argv[i], "-ms") == 0) + vs_master_set_enabled(TRUE); + else if(strncmp(argv[i], "-ms:ip=", 7) == 0) + { + vs_master_set_address(argv[i] + 7); + vs_master_set_enabled(TRUE); + } + else if(strncmp(argv[i], "-ms:de=", 7) == 0) + vs_master_set_desc(argv[i] + 7); + else if(strncmp(argv[i], "-ms:ta=", 7) == 0) + vs_master_set_tags(argv[i] + 7); + else if(strncmp(argv[i], "-port=", 6) == 0) + port = strtoul(argv[i] + 6, NULL, 0); + else if(strcmp(argv[i], "-version") == 0) + { + printf("r%up%u%s\n", V_RELEASE_NUMBER, V_RELEASE_PATCH, V_RELEASE_LABEL); + return EXIT_SUCCESS; + } + else + fprintf(stderr, "Ignoring unknown argument \"%s\", try -h for help\n", argv[i]); + } + + printf("Verse Server r%up%u%s by Eskil Steenberg \n", V_RELEASE_NUMBER, V_RELEASE_PATCH, V_RELEASE_LABEL); + verse_set_port(port); /* The Verse standard port. */ + printf(" Listening on port %d\n", port); + + /* Seed the random number generator. Still rather too weak for crypto, I guess. */ + v_n_get_current_time(&seconds, &fractions); + srand(seconds ^ fractions); + + vs_load_host_id("host_id.rsa"); + vs_init_node_storage(); + vs_o_callback_init(); + vs_g_callback_init(); + vs_m_callback_init(); + vs_b_callback_init(); + vs_t_callback_init(); + vs_c_callback_init(); + vs_a_callback_init(); + vs_h_callback_init(); + init_callback_node_storage(); + verse_callback_set(verse_send_ping, callback_send_ping, NULL); + verse_callback_set(verse_send_connect, callback_send_connect, NULL); + verse_callback_set(verse_send_connect_terminate, callback_send_connect_terminate, NULL); + + while(TRUE) + { + vs_set_next_session(); + verse_callback_update(1000000); + vs_master_update(); + } + return EXIT_SUCCESS; +} + +#endif /* V_GENERATE_FUNC_MODE */ diff --git a/extern/verse/dist/vs_master.c b/extern/verse/dist/vs_master.c new file mode 100644 index 00000000000..4fa020d58b6 --- /dev/null +++ b/extern/verse/dist/vs_master.c @@ -0,0 +1,131 @@ +/* + * Master server communication code. +*/ + +#include +#include + +#include "verse.h" +#include "v_util.h" +#include "vs_server.h" + +#define MASTER_SERVER_PERIOD (60.0) /* Period between ANNOUNCE to master server, in seconds. */ + +static struct { + boolean enabled; + boolean started; + const char *master; + char desc[64]; + const char *tags; + VUtilTimer timer; +} server_info; + +#define LEFT(d) (sizeof server_info.desc - (d - server_info.desc) - 1) + +void vs_master_set_enabled(boolean enabled) +{ + server_info.enabled = enabled; +} + +const char * vs_master_get_address(void) +{ + return server_info.master; +} + +void vs_master_set_address(const char *address) +{ + server_info.master = address; +} + +void vs_master_set_desc(const char *desc) +{ + const char *src = desc; + char *dst = server_info.desc; + + for(; *src != '\0' && LEFT(dst) > 0;) + { + if(*src == '"') + { + if(LEFT(dst) < 2) + break; + *dst++ = '\\'; + } + else if(*src == '\\') + { + if(LEFT(dst) < 2) + break; + *dst++ = '\\'; + } + *dst++ = *src++; + } + *dst = '\0'; +} + +void vs_master_set_tags(const char *tags) +{ + server_info.tags = tags; /* This needs more protection, instead of relying on the master server. */ +} + +void vs_master_update(void) +{ + if(!server_info.enabled || server_info.master == NULL) + return; + + if(!server_info.started) + { + v_timer_start(&server_info.timer); + v_timer_advance(&server_info.timer, MASTER_SERVER_PERIOD); + server_info.started = TRUE; + return; + } + if(v_timer_elapsed(&server_info.timer) < MASTER_SERVER_PERIOD) + return; + verse_send_ping(server_info.master, "MS:ANNOUNCE"); + v_timer_start(&server_info.timer); +/* printf("MS:ANNOUNCE sent to %s\n", server_info.master);*/ +} + +/* Check if a description request, of the form "A,B,C,...,D" includes the given keyword. This needs to + * do more than just a simple strstr(), since the keyword may be a prefix. Shades of OpenGL extensions. +*/ +static int desc_has_keyword(const char *desc, const char *keyword) +{ + const char *ptr; + + if(desc == NULL || *desc == '\0') /* Quick-check for empty description. */ + return 0; + + if((ptr = strstr(desc, keyword)) != NULL) + { + size_t kl = strlen(keyword); + + return ptr[kl] == ',' || ptr[kl] == '\0'; + } + return 0; +} + +static int keyword_fits(size_t used, size_t max, const char *key, const char *value) +{ + size_t vsize = 0; + + if(key != NULL && value != NULL) + vsize += 1 + strlen(key) + 1 + 1 + strlen(value) + 1; + + return max - 1 - used >= vsize; +} + +static char * append_desc(char *buf, const char *key, const char *value) +{ + return buf + sprintf(buf, " %s=\"%s\"", key, value); +} + +void vs_master_handle_describe(const char *address, const char *message) +{ + char desc[1380] = "DESCRIPTION", *put = desc + 11; + + if(desc_has_keyword(message, "DE") && server_info.desc != NULL && keyword_fits(put - desc, sizeof desc, "DE", server_info.desc)) + put = append_desc(put, "DE", server_info.desc); + if(desc_has_keyword(message, "TA") && server_info.tags != NULL && keyword_fits(put - desc, sizeof desc, "TA", server_info.tags)) + put = append_desc(put, "TA", server_info.tags); + verse_send_ping(address, desc); +} diff --git a/extern/verse/dist/vs_node_audio.c b/extern/verse/dist/vs_node_audio.c new file mode 100644 index 00000000000..e69d3d9b3ec --- /dev/null +++ b/extern/verse/dist/vs_node_audio.c @@ -0,0 +1,420 @@ +/* +** +*/ + +#include +#include +#include + +#include "v_cmd_gen.h" + +#if !defined V_GENERATE_FUNC_MODE + +#include "verse.h" +#include "vs_server.h" + +typedef struct { + void **data; + unsigned int length; + char name[16]; + VNABlockType type; + real64 frequency; + VSSubscriptionList *subscribers; +} VSNLayer; + +typedef struct { + char name[16]; + VSSubscriptionList *subscribers; +} VSNStream; + +typedef struct{ + VSNodeHead head; + VSNLayer *buffers; + unsigned int buffer_count; + VSNStream *streams; + unsigned int stream_count; +} VSNodeAudio; + +VSNodeAudio * vs_a_create_node(unsigned int owner) +{ + VSNodeAudio *node; + char name[48]; + unsigned int i; + + node = malloc(sizeof *node); + vs_add_new_node(&node->head, V_NT_AUDIO); + sprintf(name, "Audio_Node_%u", node->head.id); + create_node_head(&node->head, name, owner); + node->buffer_count = 16; + node->buffers = malloc((sizeof *node->buffers) * node->buffer_count); + for(i = 0; i < node->buffer_count; i++) + node->buffers[i].name[0] = 0; + node->stream_count = 16; + node->streams = malloc((sizeof *node->streams) * node->stream_count); + for(i = 0; i < node->stream_count; i++) + node->streams[i].name[0] = 0; + + return node; +} + +void vs_a_destroy_node(VSNodeAudio *node) +{ + unsigned int i, j; + destroy_node_head(&node->head); + + for(i = 0; i < node->buffer_count; i++) + { + if(node->buffers[i].name[0] != 0) + { + for(j = 0; j < node->buffers[i].length; j++) + if(node->buffers[i].data[j] != NULL) + free(node->buffers[i].data[j]); + free(node->buffers[i].data); + } + } + free(node->buffers); + free(node->streams); + free(node); +} + +void vs_a_subscribe(VSNodeAudio *node) +{ + unsigned int i; + if(node == NULL) + return; + for(i = 0; i < node->buffer_count; i++) + if(node->buffers[i].name[0] != 0) + verse_send_a_buffer_create(node->head.id, i, node->buffers[i].name, node->buffers[i].type, + node->buffers[i].frequency); + for(i = 0; i < node->stream_count; i++) + if(node->streams[i].name[0] != 0) + verse_send_a_stream_create(node->head.id, i, node->streams[i].name); +} + +void vs_a_unsubscribe(VSNodeAudio *node) +{ + unsigned int i; + for(i = 0; i < node->buffer_count; i++) + if(node->buffers[i].name[0] != 0) + vs_remove_subscriptor(node->buffers[i].subscribers); + for(i = 0; i < node->stream_count; i++) + if(node->streams[i].name[0] != 0) + vs_remove_subscriptor(node->streams[i].subscribers); +} + +static void callback_send_a_stream_create(void *user, VNodeID node_id, VLayerID stream_id, const char *name) +{ + VSNodeAudio *node; + unsigned int i, j, count; + + node = (VSNodeAudio *) vs_get_node(node_id, V_NT_AUDIO); + if(node == NULL) + return; + + for(i = 0; i < node->stream_count; i++) + { + if(stream_id != i) + { + for(j = 0; name[j] == node->streams[i].name[j] && name[j] != 0; j++); + if(name[j] == node->streams[i].name[j]) + return; + } + } + if(stream_id >= node->stream_count || node->streams[stream_id].name[0] == 0) + { + for(stream_id = 0; stream_id < node->stream_count && node->streams[stream_id].name[0] != 0; stream_id++); + if(stream_id == node->stream_count) + { + stream_id = node->stream_count; + node->stream_count += 16; + node->streams = realloc(node->streams, (sizeof *node->streams) * node->stream_count); + for(i = stream_id; i < node->stream_count; i++) + node->streams[i].name[0] = 0; + } + node->streams[stream_id].subscribers = vs_create_subscription_list(); + } + for(i = 0; name[i] != 0 && i < 15; i++) + node->streams[stream_id].name[i] = name[i]; + node->streams[stream_id].name[i] = 0; + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_a_stream_create(node_id, stream_id, name); + } + vs_reset_subscript_session(); +} + +static void callback_send_a_stream_destroy(void *user, VNodeID node_id, VLayerID stream_id) +{ + VSNodeAudio *node; + unsigned int i, count; + + node = (VSNodeAudio *)vs_get_node(node_id, V_NT_AUDIO); + if(node == NULL || stream_id >= node->stream_count || node->streams[stream_id].name[0] == 0) + return; + vs_remove_subscriptor(node->streams[stream_id].subscribers); + node->streams[stream_id].name[0] = 0; + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_a_stream_destroy(node_id, stream_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_a_buffer_create(void *user, VNodeID node_id, VBufferID buffer_id, const char *name, + VNABlockType type, real64 frequency) +{ + VSNodeAudio *node; + unsigned int i, j, count; + + if(frequency < 0.0) + return; + node = (VSNodeAudio *)vs_get_node(node_id, V_NT_AUDIO); + if(node == NULL) + return; + + for(i = 0; i < node->buffer_count; i++) + { + if(buffer_id != i) + { + for(j = 0; name[j] == node->buffers[i].name[j] && name[j] != 0; j++); + if(name[j] == node->buffers[i].name[j]) + return; + } + } + + if(buffer_id < node->buffer_count && node->buffers[buffer_id].name[0] != 0 && type != node->buffers[buffer_id].type) + { + free(node->buffers[buffer_id].data); + vs_destroy_subscription_list(node->buffers[buffer_id].subscribers); + node->buffers[buffer_id].name[0] = 0; + } + + if(buffer_id >= node->buffer_count || node->buffers[buffer_id].name[0] == 0) + { + for(buffer_id = 0; buffer_id < node->buffer_count && node->buffers[buffer_id].name[0] != 0; buffer_id++); + if(buffer_id == node->buffer_count) + { + buffer_id = node->buffer_count; + node->buffer_count += 16; + node->buffers = realloc(node->buffers, (sizeof *node->buffers) * node->buffer_count); + for(i = buffer_id; i < node->buffer_count; i++) + node->buffers[i].name[0] = 0; + } + node->buffers[buffer_id].subscribers = vs_create_subscription_list(); + node->buffers[buffer_id].type = type; + node->buffers[buffer_id].frequency = frequency; + node->buffers[buffer_id].length = 64; + node->buffers[buffer_id].data = malloc(sizeof(*node->buffers[buffer_id].data) * node->buffers[buffer_id].length); + for(i = 0; i < node->buffers[buffer_id].length; i++) + node->buffers[buffer_id].data[i] = NULL; + } + for(i = 0; name[i] != 0 && i < 15; i++) + node->buffers[buffer_id].name[i] = name[i]; + node->buffers[buffer_id].name[i] = 0; + + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_a_buffer_create(node_id, buffer_id, name, type, frequency); + } + vs_reset_subscript_session(); +} + +static void callback_send_a_buffer_destroy(void *user, VNodeID node_id, VBufferID buffer_id) +{ + VSNodeAudio *node; + unsigned int i, count; + + node = (VSNodeAudio *)vs_get_node(node_id, V_NT_AUDIO); + if(node == NULL || buffer_id >= node->buffer_count || node->buffers[buffer_id].name[0] == 0) + return; + vs_remove_subscriptor(node->buffers[buffer_id].subscribers); + node->buffers[buffer_id].name[0] = 0; + free(node->buffers[buffer_id].data); + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_a_buffer_destroy(node_id, buffer_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_a_buffer_subscribe(void *user, VNodeID node_id, VLayerID buffer_id) +{ + VSNodeAudio *node; + unsigned int i; + + node = (VSNodeAudio *)vs_get_node(node_id, V_NT_AUDIO); + if(node == NULL) + return; + if(node->buffer_count <= buffer_id) + return; + if(node->buffers[buffer_id].name[0] == 0) + return; + vs_add_new_subscriptor(node->buffers[buffer_id].subscribers); + for(i = 0; i < node->buffers[buffer_id].length; i++) + { + if(node->buffers[buffer_id].data[i] != NULL) + verse_send_a_block_set(node_id, buffer_id, i, node->buffers[buffer_id].type, node->buffers[buffer_id].data[i]); + } +} + +static void callback_send_a_buffer_unsubscribe(void *user, VNodeID node_id, VLayerID buffer_id) +{ + VSNodeAudio *node; + node = (VSNodeAudio *)vs_get_node(node_id, V_NT_AUDIO); + if(node == NULL) + return; + if(node->buffer_count <= buffer_id) + return; + if(node->buffers[buffer_id].name[0] == 0) + return; + vs_remove_subscriptor(node->buffers[buffer_id].subscribers); +} + +static void callback_send_a_block_set(void *user, VNodeID node_id, VLayerID buffer_id, uint32 block_index, + VNABlockType type, const VNABlock *data) +{ + static const size_t blocksize[] = { + VN_A_BLOCK_SIZE_INT8 * sizeof (int8), + VN_A_BLOCK_SIZE_INT16 * sizeof (int16), + VN_A_BLOCK_SIZE_INT24 * 3 * sizeof (int8), + VN_A_BLOCK_SIZE_INT32 * sizeof (int32), + VN_A_BLOCK_SIZE_REAL32 * sizeof (real32), + VN_A_BLOCK_SIZE_REAL64 * sizeof (real64) + }; + VSNodeAudio *node; + unsigned int i, count; + + if(type > VN_A_BLOCK_REAL64) /* Protect blocksize array. */ + return; + + node = (VSNodeAudio *)vs_get_node(node_id, V_NT_AUDIO); + if(node == NULL) + return; + if(node->buffers[buffer_id].name[0] == 0) + return; + if(type != node->buffers[buffer_id].type) /* Disregard attempts to set data of wrong type. */ + return; + if(block_index > node->buffers[buffer_id].length) + { + node->buffers[buffer_id].data = realloc(node->buffers[buffer_id].data, + (sizeof *node->buffers[buffer_id].data) * (block_index + 64)); + for(i = node->buffers[buffer_id].length; i < block_index + 64; i++) + node->buffers[buffer_id].data[i] = NULL; + node->buffers[buffer_id].length = block_index + 64; + } + + if(node->buffers[buffer_id].data[block_index] == NULL) + node->buffers[buffer_id].data[block_index] = malloc(blocksize[type]); + if(node->buffers[buffer_id].data[block_index] != NULL) + { + memcpy(node->buffers[buffer_id].data[block_index], data, blocksize[type]); + count = vs_get_subscript_count(node->buffers[buffer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->buffers[buffer_id].subscribers, i); + verse_send_a_block_set(node_id, buffer_id, block_index, type, data); + } + vs_reset_subscript_session(); + } +} + +static void callback_send_a_block_clear(void *user, VNodeID node_id, VLayerID buffer_id, uint32 id) +{ + VSNodeAudio *node; + unsigned int i, count; + node = (VSNodeAudio *)vs_get_node(node_id, V_NT_AUDIO); + if(node == NULL) + return; + if(node->buffer_count <= buffer_id) + return; + if(node->buffers[buffer_id].name[0] == 0) + return; + if(id >= node->buffers[buffer_id].length) + return; + if(node->buffers[buffer_id].data[id] == NULL) + return; + free(node->buffers[buffer_id].data[id]); + node->buffers[buffer_id].data[id] = NULL; + count = vs_get_subscript_count(node->buffers[buffer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->buffers[buffer_id].subscribers, i); + verse_send_a_block_clear(node_id, buffer_id, id); + } + vs_reset_subscript_session(); +} + +static void callback_send_a_stream_subscribe(void *user, VNodeID node_id, VLayerID stream_id) +{ + VSNodeAudio *node; + node = (VSNodeAudio *)vs_get_node(node_id, V_NT_AUDIO); + if(node == NULL) + return; + if(node->stream_count <= stream_id) + return; + if(node->streams[stream_id].name[0] == 0) + return; + vs_add_new_subscriptor(node->streams[stream_id].subscribers); +} + +static void callback_send_a_stream_unsubscribe(void *user, VNodeID node_id, VLayerID stream_id) +{ + VSNodeAudio *node; + node = (VSNodeAudio *)vs_get_node(node_id, V_NT_AUDIO); + if(node == NULL) + return; + if(node->stream_count <= stream_id) + return; + if(node->streams[stream_id].name[0] == 0) + return; + vs_remove_subscriptor(node->streams[stream_id].subscribers); +} + +static void callback_send_a_stream(void *user, VNodeID node_id, VLayerID stream_id, uint32 time_s, uint32 time_f, + VNABlockType type, real64 frequency, const VNABlock *data) +{ + VSNodeAudio *node; + unsigned int i, count; + + if(frequency < 0) + return; + node = (VSNodeAudio *)vs_get_node(node_id, V_NT_AUDIO); + if(node == NULL) + return; + if(node->stream_count <= stream_id) + return; + if(node->streams[stream_id].name[0] == 0) + return; + count = vs_get_subscript_count(node->streams[stream_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->streams[stream_id].subscribers, i); + verse_send_a_stream(node_id, stream_id, time_s, time_f, type, frequency, data); + } + vs_reset_subscript_session(); +} + +void vs_a_callback_init(void) +{ + verse_callback_set(verse_send_a_buffer_create, callback_send_a_buffer_create, NULL); + verse_callback_set(verse_send_a_buffer_destroy, callback_send_a_buffer_destroy, NULL); + verse_callback_set(verse_send_a_buffer_subscribe, callback_send_a_buffer_subscribe, NULL); + verse_callback_set(verse_send_a_buffer_unsubscribe, callback_send_a_buffer_unsubscribe, NULL); + verse_callback_set(verse_send_a_block_set, callback_send_a_block_set, NULL); + verse_callback_set(verse_send_a_block_clear, callback_send_a_block_clear, NULL); + verse_callback_set(verse_send_a_stream_create, callback_send_a_stream_create, NULL); + verse_callback_set(verse_send_a_stream_destroy, callback_send_a_stream_destroy, NULL); + verse_callback_set(verse_send_a_stream_subscribe, callback_send_a_stream_subscribe, NULL); + verse_callback_set(verse_send_a_stream_unsubscribe, callback_send_a_stream_unsubscribe, NULL); + verse_callback_set(verse_send_a_stream, callback_send_a_stream, NULL); +} + +#endif diff --git a/extern/verse/dist/vs_node_bitmap.c b/extern/verse/dist/vs_node_bitmap.c new file mode 100644 index 00000000000..566287a86d4 --- /dev/null +++ b/extern/verse/dist/vs_node_bitmap.c @@ -0,0 +1,560 @@ +/* +** +*/ + +#include +#include +#include + +#include "v_cmd_gen.h" + +#if !defined V_GENERATE_FUNC_MODE + +#include "verse.h" +#include "vs_server.h" + +typedef struct { + VNBLayerType type; + char name[16]; + void *layer; + VSSubscriptionList *subscribers; +} VSNBLayers; + +typedef struct { + VSNodeHead head; + uint16 size[3]; + uint32 partial_tile_col, partial_tile_row; /* These rows/columns are partial. ~0 for none. */ + VSNBLayers *layers; + unsigned int layer_count; +} VSNodeBitmap; + +static unsigned long tile_counter = 0; + +VSNodeBitmap * vs_b_create_node(unsigned int owner) +{ + VSNodeBitmap *node; + char name[48]; + node = malloc(sizeof *node); + vs_add_new_node(&node->head, V_NT_BITMAP); + sprintf(name, "Bitmap_Node_%u", node->head.id); + create_node_head(&node->head, name, owner); + + node->size[0] = 0; + node->size[1] = 0; + node->size[2] = 0; + node->partial_tile_col = ~0; + node->partial_tile_row = ~0; + node->layers = NULL; + node->layer_count = 0; + + return node; +} + +void vs_b_destroy_node(VSNodeBitmap *node) +{ + unsigned int i; + destroy_node_head(&node->head); + if(node->layers != NULL) + { + for(i = 0; i < node->layer_count; i++) + if(node->layers[i].layer != NULL) + free(node->layers[i].layer); + free(node->layers); + } + free(node); +} + +void vs_b_subscribe(VSNodeBitmap *node) +{ + unsigned int i; + verse_send_b_dimensions_set(node->head.id, node->size[0], node->size[1], node->size[2]); + for(i = 0; i < node->layer_count; i++) + if(node->layers[i].name[0] != 0) + verse_send_b_layer_create(node->head.id, (uint16)i, node->layers[i].name, (uint8)node->layers[i].type); +} + + +void vs_b_unsubscribe(VSNodeBitmap *node) +{ + unsigned int i; + for(i = 0; i < node->layer_count; i++) + if(node->layers[i].name[0] != 0) + vs_remove_subscriptor(node->layers[i].subscribers); +} + +static void callback_send_b_dimensions_set(void *user, VNodeID node_id, uint16 width, uint16 height, uint16 depth) +{ + VSNodeBitmap *node; + unsigned int i, j, k, count, tiles[2], read, write, end = 0; + + if((node = (VSNodeBitmap *)vs_get_node(node_id, V_NT_BITMAP)) == NULL) + return; + tiles[0] = (width + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE; + tiles[1] = (height + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE; + node->size[0] = (node->size[0] + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE; + node->size[1] = (node->size[1] + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE; + if(node->size[0] > tiles[0]) + node->size[0] = tiles[0]; + if(node->size[1] > tiles[1]) + node->size[1] = tiles[1]; + if(node->size[2] > depth) + node->size[2] = depth; + + for(i = 0; i < node->layer_count; i++) + { + if(node->layers[i].name[0] != 0) + { + switch(node->layers[i].type) + { + case VN_B_LAYER_UINT1 : + { + uint16 *array, *old; + write = 0; + old = node->layers[i].layer; + array = node->layers[i].layer = malloc((sizeof *array) * tiles[0] * tiles[1] * depth); + for(j = 0; j < node->size[2]; j++) + { + for(k = 0; k < node->size[1]; k++) + { + read = (j * node->size[1] * node->size[0] + k * node->size[0]); + + end = (j * tiles[1] * tiles[0] + k * tiles[0] + node->size[0]); + while(write < end) + array[write++] = old[read++]; + + end = (j * tiles[1] * tiles[0] + (k + 1) * tiles[0]); + while(write < end) + array[write++] = 0; + } + end = ((j + 1) * tiles[1] * tiles[0]); + while(write < end) + array[write++] = 0; + } + k = depth * tiles[1] * tiles[0]; + while(write < end) + array[write++] = 0; + } + break; + case VN_B_LAYER_UINT8 : + { + uint8 *array, *old; + write = 0; + old = node->layers[i].layer; + array = node->layers[i].layer = malloc((sizeof *array) * tiles[0] * tiles[1] * depth * VN_B_TILE_SIZE * VN_B_TILE_SIZE); + for(j = 0; j < node->size[2]; j++) + { + for(k = 0; k < node->size[1]; k++) + { + read = (j * node->size[1] * node->size[0] + k * node->size[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + + end = (j * tiles[1] * tiles[0] + k * tiles[0] + node->size[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = old[read++]; + + end = (j * tiles[1] * tiles[0] + (k + 1) * tiles[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = 0; + } + end = ((j + 1) * tiles[1] * tiles[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = 0; + } + end = depth * tiles[1] * tiles[0] * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = 0; + } + break; + case VN_B_LAYER_UINT16 : + { + uint16 *array, *old; + write = 0; + old = node->layers[i].layer; + array = node->layers[i].layer = malloc((sizeof *array) * tiles[0] * tiles[1] * depth * VN_B_TILE_SIZE * VN_B_TILE_SIZE); + for(j = 0; j < node->size[2]; j++) + { + for(k = 0; k < node->size[1]; k++) + { + read = (j * node->size[1] * node->size[0] + k * node->size[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + + end = (j * tiles[1] * tiles[0] + k * tiles[0] + node->size[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = old[read++]; + + end = (j * tiles[1] * tiles[0] + (k + 1) * tiles[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = 0; + } + end = ((j + 1) * tiles[1] * tiles[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = 0; + } + end = depth * tiles[1] * tiles[0] * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = 0; + } + break; + case VN_B_LAYER_REAL32 : + { + real32 *array, *old; + write = 0; + old = node->layers[i].layer; + array = node->layers[i].layer = malloc((sizeof *array) * tiles[0] * tiles[1] * depth * VN_B_TILE_SIZE * VN_B_TILE_SIZE); + for(j = 0; j < node->size[2]; j++) + { + for(k = 0; k < node->size[1]; k++) + { + read = (j * node->size[1] * node->size[0] + k * node->size[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + + end = (j * tiles[1] * tiles[0] + k * tiles[0] + node->size[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = old[read++]; + + end = (j * tiles[1] * tiles[0] + (k + 1) * tiles[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = 0; + } + end = ((j + 1) * tiles[1] * tiles[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = 0; + } + end = depth * tiles[1] * tiles[0] * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = 0; + } + break; + case VN_B_LAYER_REAL64 : + { + real64 *array, *old; + write = 0; + old = node->layers[i].layer; + array = node->layers[i].layer = malloc((sizeof *array) * tiles[0] * tiles[1] * depth * VN_B_TILE_SIZE * VN_B_TILE_SIZE); + for(j = 0; j < node->size[2]; j++) + { + for(k = 0; k < node->size[1]; k++) + { + read = (j * node->size[1] * node->size[0] + k * node->size[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + + end = (j * tiles[1] * tiles[0] + k * tiles[0] + node->size[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = old[read++]; + + end = (j * tiles[1] * tiles[0] + (k + 1) * tiles[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = 0; + } + end = ((j + 1) * tiles[1] * tiles[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = 0; + } + end = depth * tiles[1] * tiles[0] * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = 0; + } + break; + } + } + } + + node->size[0] = width; + node->size[1] = height; + node->size[2] = depth; + node->partial_tile_col = (width % VN_B_TILE_SIZE) != 0 ? (width + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE - 1 : ~0; + node->partial_tile_row = (height % VN_B_TILE_SIZE) != 0 ? (height + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE - 1 : ~0; + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_b_dimensions_set(node_id, width, height, depth); + } + vs_reset_subscript_session(); +} + +static void callback_send_b_layer_create(void *user, VNodeID node_id, VLayerID layer_id, char *name, uint8 type) +{ + VSNodeBitmap *node; + unsigned int i, count; + + if((node = (VSNodeBitmap *)vs_get_node(node_id, V_NT_BITMAP)) == NULL) + return; + if(node->layer_count <= layer_id || node->layers[layer_id].name[0] == 0) + { + for(layer_id = 0; layer_id < node->layer_count && node->layers[layer_id].name[0] != 0; layer_id++) + ; + if(layer_id == node->layer_count) + { + node->layers = realloc(node->layers, (sizeof *node->layers) * (node->layer_count + 16)); + for(i = node->layer_count; i < node->layer_count + 16; i++) + { + node->layers[i].layer = NULL; + node->layers[i].type = 0; + node->layers[i].name[0] = 0; + node->layers[i].subscribers = NULL; + } + node->layer_count += 16; + } + node->layers[layer_id].subscribers = vs_create_subscription_list(); + node->layers[layer_id].type = type + 1; + } + + if(node->layers[layer_id].type != type || node->layers[layer_id].name[0] == 0) + { + count = ((node->size[0] + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE) * ((node->size[1] + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE); + count *= VN_B_TILE_SIZE * VN_B_TILE_SIZE * node->size[2]; + if(node->layers[layer_id].layer != NULL) + free(node->layers[layer_id].layer); + if(count != 0) + { + switch(type) + { + case VN_B_LAYER_UINT1 : + node->layers[layer_id].layer = malloc(sizeof(uint8) * count / 8); + memset(node->layers[layer_id].layer, 0, count * sizeof(uint8) / 8); + break; + case VN_B_LAYER_UINT8 : + node->layers[layer_id].layer = malloc(sizeof(uint8) * count); + memset(node->layers[layer_id].layer, 0, count * sizeof(uint8)); + break; + case VN_B_LAYER_UINT16 : + node->layers[layer_id].layer = malloc(sizeof(uint16) * count); + memset(node->layers[layer_id].layer, 0, count * sizeof(uint16)); + break; + case VN_B_LAYER_REAL32 : + node->layers[layer_id].layer = malloc(sizeof(real32) * count); + memset(node->layers[layer_id].layer, 0, count * sizeof(real32)); + break; + case VN_B_LAYER_REAL64 : + node->layers[layer_id].layer = malloc(sizeof(real64) * count); + memset(node->layers[layer_id].layer, 0, count * sizeof(real64)); + break; + } + }else + node->layers[layer_id].layer = NULL; + } + node->layers[layer_id].type = type; + for(i = 0; i < 15 && name[i] != 0; i++) + node->layers[layer_id].name[i] = name[i]; + node->layers[layer_id].name[i] = 0; + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_b_layer_create(node_id, layer_id, name, type); + } + vs_reset_subscript_session(); +} + +static void callback_send_b_layer_destroy(void *user, VNodeID node_id, VLayerID layer_id) +{ + VSNodeBitmap *node; + unsigned int i, count; + if((node = (VSNodeBitmap *)vs_get_node(node_id, V_NT_BITMAP)) == NULL) + return; + if(layer_id >= node->layer_count || node->layers[layer_id].layer == NULL) + return; + if(node->layers[layer_id].layer != NULL) + free(node->layers[layer_id].layer); + node->layers[layer_id].layer = NULL; + node->layers[layer_id].type = 0; + node->layers[layer_id].name[0] = 0; + vs_destroy_subscription_list(node->layers[layer_id].subscribers); + node->layers[layer_id].subscribers = NULL; + + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_b_layer_destroy(node_id, layer_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_b_layer_subscribe(void *user, VNodeID node_id, VLayerID layer_id, uint8 level) +{ + VSNodeBitmap *node; + const void *data; + unsigned int i, j, k, tile[3]; + + if((node = (VSNodeBitmap *)vs_get_node(node_id, V_NT_BITMAP)) == NULL) + return; + if(layer_id >= node->layer_count || node->layers[layer_id].layer == NULL) + return; + if(vs_add_new_subscriptor(node->layers[layer_id].subscribers) == 0) + return; + tile[0] = ((node->size[0] + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE); + tile[1] = ((node->size[1] + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE); + tile[2] = node->size[2]; + data = node->layers[layer_id].layer; + switch(node->layers[layer_id].type) + { + case VN_B_LAYER_UINT1: + for(i = 0; i < tile[0]; i++) + for(j = 0; j < tile[1]; j++) + for(k = 0; k < tile[2]; k++) + verse_send_b_tile_set(node_id, layer_id, i, j, k, VN_B_LAYER_UINT1, (VNBTile *) &((uint8*)data)[(tile[0] * tile[1] * k + j * tile[0] + i) * VN_B_TILE_SIZE * VN_B_TILE_SIZE / 8]); + break; + case VN_B_LAYER_UINT8 : + for(i = 0; i < tile[0]; i++) + for(j = 0; j < tile[1]; j++) + for(k = 0; k < tile[2]; k++) + verse_send_b_tile_set(node_id, layer_id, i, j, k, VN_B_LAYER_UINT8, (VNBTile *) &((uint8*)data)[(tile[0] * tile[1] * k + j * tile[0] + i) * VN_B_TILE_SIZE * VN_B_TILE_SIZE]); + break; + case VN_B_LAYER_UINT16 : + for(i = 0; i < tile[0]; i++) + for(j = 0; j < tile[1]; j++) + for(k = 0; k < tile[2]; k++) + verse_send_b_tile_set(node_id, layer_id, i, j, k, VN_B_LAYER_UINT16, (VNBTile *) &((uint16*)data)[(tile[0] * tile[1] * k + j * tile[0] + i) * VN_B_TILE_SIZE * VN_B_TILE_SIZE]); + break; + case VN_B_LAYER_REAL32 : + for(i = 0; i < tile[0]; i++) + for(j = 0; j < tile[1]; j++) + for(k = 0; k < tile[2]; k++) + verse_send_b_tile_set(node_id, layer_id, i, j, k, VN_B_LAYER_REAL32, (VNBTile *) &((real32*)data)[(tile[0] * tile[1] * k + j * tile[0] + i) * VN_B_TILE_SIZE * VN_B_TILE_SIZE]); + break; + case VN_B_LAYER_REAL64 : + for(i = 0; i < tile[0]; i++) + for(j = 0; j < tile[1]; j++) + for(k = 0; k < tile[2]; k++) + verse_send_b_tile_set(node_id, layer_id, i, j, k, VN_B_LAYER_REAL64, (VNBTile *) &((real64*)data)[(tile[0] * tile[1] * k + j * tile[0] + i) * VN_B_TILE_SIZE * VN_B_TILE_SIZE]); + break; + } +} + +static void callback_send_b_layer_unsubscribe(void *user, VNodeID node_id, VLayerID layer_id) +{ + VSNodeBitmap *node; + if((node = (VSNodeBitmap *)vs_get_node(node_id, V_NT_BITMAP)) == NULL) + return; + if(layer_id >= node->layer_count || node->layers[layer_id].layer == NULL) + return; + vs_remove_subscriptor(node->layers[layer_id].subscribers); +} + +/* Clear any pixels that lie outside the image, so we don't violoate specs when + * sending (stored version of) the tile out to subscribers. +*/ +static void clear_outside(const VSNodeBitmap *node, uint16 tile_x, uint16 tile_y, uint8 type, VNBTile *tile) +{ + int x, y, bx, by, p; + + by = tile_y * VN_B_TILE_SIZE; + for(y = p = 0; y < VN_B_TILE_SIZE; y++, by++) + { + bx = tile_x * VN_B_TILE_SIZE; + for(x = 0; x < VN_B_TILE_SIZE; x++, bx++, p++) + { + /* Simply test current pixel against bitmap size. Not quick, but simple. */ + if(bx >= node->size[0] || by >= node->size[1]) + { + switch(type) + { + case VN_B_LAYER_UINT1: + tile->vuint1[y] &= ~(128 >> x); + break; + case VN_B_LAYER_UINT8: + tile->vuint8[p] = 0; + break; + case VN_B_LAYER_UINT16: + tile->vuint16[p] = 0; + break; + case VN_B_LAYER_REAL32: + tile->vreal32[p] = 0.0f; + break; + case VN_B_LAYER_REAL64: + tile->vreal64[p] = 0.0; + break; + } + } + } + } +} + +static void callback_send_b_tile_set(void *user, VNodeID node_id, VLayerID layer_id, + uint16 tile_x, uint16 tile_y, uint16 tile_z, uint8 type, VNBTile *data) +{ + VSNodeBitmap *node; + unsigned int i, count, tile[3]; + + if((node = (VSNodeBitmap *)vs_get_node(node_id, V_NT_BITMAP)) == NULL) + { + printf("got tile for unknown bitmpa node %u, aborting\n", node_id); + return; + } + if(layer_id >= node->layer_count || node->layers[layer_id].layer == NULL || node->layers[layer_id].type != type) + { + printf("node %u got tile for bad layer %u (have %u) %p\n", node_id, layer_id, node->layer_count, layer_id < node->layer_count ? node->layers[layer_id].layer : NULL); + return; + } + if(tile_x >= ((node->size[0] + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE) || tile_y >= ((node->size[1] + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE) || tile_z >= node->size[2]) + { + printf("got tile that is outside image, at (%u,%u,%u)\n", tile_x, tile_y, tile_z); + return; + } + + tile_counter++; + + tile[0] = ((node->size[0] + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE); + tile[1] = ((node->size[1] + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE); + tile[2] = node->size[2]; + + /* If tile is in a partial column or row, clear the "outside" pixels. */ + if((uint32) tile_x == node->partial_tile_col || (uint32) tile_y == node->partial_tile_row) + clear_outside(node, tile_x, tile_y, type, data); + + switch(node->layers[layer_id].type) + { + case VN_B_LAYER_UINT1 : + { + uint8 *p; + p = &((uint8 *)node->layers[layer_id].layer)[(tile[0] * tile[1] * tile_z + tile_y * tile[0] + tile_x) * VN_B_TILE_SIZE * VN_B_TILE_SIZE/8]; + memcpy(p, data->vuint1, VN_B_TILE_SIZE * sizeof(uint8)); + } + break; + case VN_B_LAYER_UINT8 : + { + uint8 *p; + p = &((uint8 *)node->layers[layer_id].layer)[(tile[0] * tile[1] * tile_z + tile_y * tile[0] + tile_x) * VN_B_TILE_SIZE * VN_B_TILE_SIZE]; + memcpy(p, data->vuint8, VN_B_TILE_SIZE * VN_B_TILE_SIZE * sizeof(uint8)); + } + break; + case VN_B_LAYER_UINT16 : + { + uint16 *p; + p = &((uint16 *)node->layers[layer_id].layer)[(tile[0] * tile[1] * tile_z + tile_y * tile[0] + tile_x) * VN_B_TILE_SIZE * VN_B_TILE_SIZE]; + memcpy(p, data->vuint16, VN_B_TILE_SIZE * VN_B_TILE_SIZE * sizeof(uint16)); + } + break; + case VN_B_LAYER_REAL32 : + { + real32 *p; + p = &((real32 *)node->layers[layer_id].layer)[(tile[0] * tile[1] * tile_z + tile_y * tile[0] + tile_x) * VN_B_TILE_SIZE * VN_B_TILE_SIZE]; + memcpy(p, data->vreal32, VN_B_TILE_SIZE * VN_B_TILE_SIZE * sizeof(real32)); + } + break; + case VN_B_LAYER_REAL64 : + { + real64 *p; + p = &((real64 *)node->layers[layer_id].layer)[(tile[0] * tile[1] * tile_z + tile_y * tile[0] + tile_x) * VN_B_TILE_SIZE * VN_B_TILE_SIZE]; + memcpy(p, data->vreal64, VN_B_TILE_SIZE * VN_B_TILE_SIZE * sizeof(real64)); + } + break; + } + count = vs_get_subscript_count(node->layers[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layers[layer_id].subscribers, i); + verse_send_b_tile_set(node_id, layer_id, tile_x, tile_y, tile_z, type, data); + } + vs_reset_subscript_session(); +} + +void vs_b_callback_init(void) +{ + verse_callback_set(verse_send_b_dimensions_set, callback_send_b_dimensions_set, NULL); + verse_callback_set(verse_send_b_layer_create, callback_send_b_layer_create, NULL); + verse_callback_set(verse_send_b_layer_destroy, callback_send_b_layer_destroy, NULL); + verse_callback_set(verse_send_b_layer_subscribe, callback_send_b_layer_subscribe, NULL); + verse_callback_set(verse_send_b_layer_unsubscribe, callback_send_b_layer_unsubscribe, NULL); + verse_callback_set(verse_send_b_tile_set, callback_send_b_tile_set, NULL); +} + +#endif diff --git a/extern/verse/dist/vs_node_curve.c b/extern/verse/dist/vs_node_curve.c new file mode 100644 index 00000000000..3787526202d --- /dev/null +++ b/extern/verse/dist/vs_node_curve.c @@ -0,0 +1,258 @@ +/* +** +*/ + +#include +#include + +#include "v_cmd_gen.h" + +#if !defined V_GENERATE_FUNC_MODE + +#include "verse.h" +#include "vs_server.h" + +typedef struct { + real64 pre_value[4]; + uint32 pre_pos[4]; + real64 value[4]; + real64 pos; + real64 post_value[4]; + uint32 post_pos[4]; +} VSNKey; + +typedef struct { + VSNKey *keys; + unsigned int length; + char name[16]; + uint8 dimensions; + VSSubscriptionList *subscribers; +} VSNCurve; + +typedef struct{ + VSNodeHead head; + VSNCurve *curves; + unsigned int curve_count; +} VSNodeCurve; + +VSNodeCurve * vs_c_create_node(unsigned int owner) +{ + VSNodeCurve *node; + char name[48]; + unsigned int i; + node = malloc(sizeof *node); + vs_add_new_node(&node->head, V_NT_CURVE); + sprintf(name, "Curve_Node_%u", node->head.id); + create_node_head(&node->head, name, owner); + node->curves = malloc((sizeof *node->curves) * 16); + node->curve_count = 16; + for(i = 0; i < 16; i++) + node->curves[i].name[0] = 0; + return node; +} + +void vs_c_destroy_node(VSNodeCurve *node) +{ + destroy_node_head(&node->head); + free(node); +} + +void vs_c_subscribe(VSNodeCurve *node) +{ + unsigned int i; + if(node == NULL) + return; + for(i = 0; i < node->curve_count; i++) + if(node->curves[i].name[0] != 0) + verse_send_c_curve_create(node->head.id, i, node->curves[i].name, node->curves[i].dimensions); + +} + +void vs_c_unsubscribe(VSNodeCurve *node) +{ + unsigned int i; + for(i = 0; i < node->curve_count; i++) + if(node->curves[i].name[0] != 0) + vs_remove_subscriptor(node->curves[i].subscribers); +} + +static void callback_send_c_curve_create(void *user, VNodeID node_id, VLayerID curve_id, const char *name, uint8 dimensions) +{ + VSNodeCurve *node; + unsigned int i, j, count; + node = (VSNodeCurve *)vs_get_node(node_id, V_NT_CURVE); + if(node == NULL) + return; + + for(i = 0; i < node->curve_count; i++) + { + if(curve_id != i) + { + for(j = 0; name[j] == node->curves[i].name[j] && name[j] != 0; j++); + if(name[j] == node->curves[i].name[j]) + return; + } + } + if(curve_id >= node->curve_count || node->curves[curve_id].name[0] == 0) + { + for(curve_id = 0; curve_id < node->curve_count && node->curves[curve_id].name[0] != 0; curve_id++); + if(curve_id == node->curve_count) + { + curve_id = node->curve_count; + node->curve_count += 16; + node->curves = realloc(node->curves, (sizeof *node->curves) * node->curve_count); + for(i = curve_id; i < node->curve_count; i++) + node->curves[i].name[0] = 0; + } + node->curves[curve_id].subscribers = vs_create_subscription_list(); + node->curves[curve_id].length = 64; + node->curves[curve_id].keys = malloc((sizeof *node->curves[curve_id].keys) * 64); + for(i = 0; i < 64; i++) + node->curves[curve_id].keys[i].pos = V_REAL64_MAX; + + }else if(node->curves[curve_id].dimensions != dimensions) + { + for(i = 0; i < node->curves[curve_id].length; i++) + { + if(node->curves[curve_id].keys[i].pos != V_REAL64_MAX) + { + for(j = node->curves[curve_id].dimensions; j < dimensions; j++) + { + node->curves[curve_id].keys[i].pre_value[j] = node->curves[curve_id].keys[i].pre_value[0]; + node->curves[curve_id].keys[i].pre_pos[j] = node->curves[curve_id].keys[i].pre_pos[0]; + node->curves[curve_id].keys[i].value[j] = node->curves[curve_id].keys[i].value[0]; + node->curves[curve_id].keys[i].post_value[j] = node->curves[curve_id].keys[i].post_value[0]; + node->curves[curve_id].keys[i].post_pos[j] = node->curves[curve_id].keys[i].post_pos[0]; + } + } + } + vs_destroy_subscription_list(node->curves[curve_id].subscribers); + node->curves[curve_id].subscribers = vs_create_subscription_list(); + } + for(i = 0; name[i] != 0 && i < 15; i++) + node->curves[curve_id].name[i] = name[i]; + node->curves[curve_id].name[i] = 0; + node->curves[curve_id].dimensions = dimensions; + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_c_curve_create(node_id, curve_id, name, dimensions); + } + vs_reset_subscript_session(); +} + +static void callback_send_c_curve_destroy(void *user, VNodeID node_id, VLayerID curve_id) +{ + VSNodeCurve *node; + unsigned int i, count; + node = (VSNodeCurve *)vs_get_node(node_id, V_NT_CURVE); + if(node == NULL || node->curve_count >= curve_id || node->curves[curve_id].name[0] == 0) + return; + vs_remove_subscriptor(node->curves[curve_id].subscribers); + node->curves[curve_id].name[0] = 0; + free(node->curves[curve_id].keys); + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_c_curve_destroy(node_id, curve_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_c_key_set(void *user, VNodeID node_id, VLayerID curve_id, uint32 key_id, uint8 dimensions, real64 *pre_value, uint32 *pre_pos, real64 *value, real64 pos, real64 *post_value, uint32 *post_pos) +{ + VSNodeCurve *node; + unsigned int i, count; + node = (VSNodeCurve *)vs_get_node(node_id, V_NT_CURVE); + if(node == NULL) + return; + if(node->curve_count <= curve_id) + return; + if(node->curves[curve_id].name[0] == 0) + return; + if(node == NULL || node->curve_count <= curve_id || node->curves[curve_id].name[0] == 0 || node->curves[curve_id].dimensions != dimensions) + return; + if(node->curves[curve_id].length <= key_id || node->curves[curve_id].keys[key_id].pos == V_REAL64_MAX) + { + for(key_id = 0; key_id < node->curves[curve_id].length && node->curves[curve_id].keys[key_id].pos != V_REAL64_MAX; key_id++); + if(key_id == node->curves[curve_id].length) + for(i = 0; i < 64; i++) + node->curves[curve_id].keys[node->curves[curve_id].length++].pos = V_REAL64_MAX; + } + for(i = 0; i < dimensions; i++) + node->curves[curve_id].keys[key_id].pre_value[i] = pre_value[i]; + for(i = 0; i < dimensions; i++) + node->curves[curve_id].keys[key_id].pre_pos[i] = pre_pos[i]; + for(i = 0; i < dimensions; i++) + node->curves[curve_id].keys[key_id].value[i] = value[i]; + node->curves[curve_id].keys[key_id].pos = pos; + for(i = 0; i < dimensions; i++) + node->curves[curve_id].keys[key_id].post_value[i] = post_value[i]; + for(i = 0; i < dimensions; i++) + node->curves[curve_id].keys[key_id].post_pos[i] = post_pos[i]; + count = vs_get_subscript_count(node->curves[curve_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->curves[curve_id].subscribers, i); + verse_send_c_key_set(node_id, curve_id, key_id, dimensions, pre_value, pre_pos, value, pos, post_value, post_pos); + } + vs_reset_subscript_session(); +} + +static void callback_send_c_key_destroy(void *user, VNodeID node_id, VLayerID curve_id, uint32 key_id) +{ + VSNodeCurve *node; + unsigned int i, count; + node = (VSNodeCurve *)vs_get_node(node_id, V_NT_CURVE); + if(node == NULL || node->curve_count <= curve_id || node->curves[curve_id].name[0] == 0) + return; + if(node->curves[curve_id].length <= key_id || node->curves[curve_id].keys[key_id].pos == V_REAL64_MAX) + return; + node->curves[curve_id].keys[key_id].pos = V_REAL64_MAX; + count = vs_get_subscript_count(node->curves[curve_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->curves[curve_id].subscribers, i); + verse_send_c_key_destroy(node_id, curve_id, key_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_c_curve_subscribe(void *user, VNodeID node_id, VLayerID curve_id) +{ + VSNodeCurve *node; + unsigned int i; + node = (VSNodeCurve *)vs_get_node(node_id, V_NT_CURVE); + if(node == NULL || node->curve_count <= curve_id || node->curves[curve_id].name[0] == 0) + return; + + vs_add_new_subscriptor(node->curves[curve_id].subscribers); + + for(i = 0; i < node->curves[curve_id].length; i++) + if(node->curves[curve_id].keys[i].pos != V_REAL64_MAX) + verse_send_c_key_set(node_id, curve_id, i, node->curves[curve_id].dimensions, node->curves[curve_id].keys[i].pre_value, node->curves[curve_id].keys[i].pre_pos, node->curves[curve_id].keys[i].value, node->curves[curve_id].keys[i].pos, node->curves[curve_id].keys[i].post_value, node->curves[curve_id].keys[i].post_pos); +} + +static void callback_send_c_curve_unsubscribe(void *user, VNodeID node_id, VLayerID curve_id) +{ + VSNodeCurve *node; + + node = (VSNodeCurve *)vs_get_node(node_id, V_NT_CURVE); + if(node == NULL || curve_id >= node->curve_count || node->curves[curve_id].name[0] == 0) + return; + vs_remove_subscriptor(node->curves[curve_id].subscribers); +} + +void vs_c_callback_init(void) +{ + verse_callback_set(verse_send_c_curve_create, callback_send_c_curve_create, NULL); + verse_callback_set(verse_send_c_curve_destroy, callback_send_c_curve_destroy, NULL); + verse_callback_set(verse_send_c_curve_subscribe, callback_send_c_curve_subscribe, NULL); + verse_callback_set(verse_send_c_curve_unsubscribe, callback_send_c_curve_unsubscribe, NULL); + verse_callback_set(verse_send_c_key_set, callback_send_c_key_set, NULL); + verse_callback_set(verse_send_c_key_destroy, callback_send_c_key_destroy, NULL); +} + +#endif diff --git a/extern/verse/dist/vs_node_geometry.c b/extern/verse/dist/vs_node_geometry.c new file mode 100644 index 00000000000..4b1f88c8ac2 --- /dev/null +++ b/extern/verse/dist/vs_node_geometry.c @@ -0,0 +1,1047 @@ +/* +** +*/ + +#include +#include +#include + +#include "v_cmd_gen.h" + +#if !defined V_GENERATE_FUNC_MODE + +#include "verse.h" +#include "v_util.h" +#include "vs_server.h" + +#define VS_G_LAYER_CHUNK 32 + +typedef struct { + VNGLayerType type; + char name[16]; + void *layer; + VSSubscriptionList *subscribers; + VSSubscriptionList *subscribersd; + union{ + uint32 integer; + real64 real; + } def; +} VSNGLayer; + +typedef struct { + char weight[16]; + char reference[16]; + uint16 parent; + real64 pos_x; + real64 pos_y; + real64 pos_z; + char position_label[16]; + char rotation_label[16]; + char scale_label[16]; +} VSNGBone; + +typedef struct { + VSNodeHead head; + VSNGLayer *layer; + uint16 layer_count; + uint32 vertex_size; + uint32 poly_size; + uint32 vertex_hole; + uint32 polygon_hole; + uint32 crease_vertex; + char crease_vertex_layer[16]; + uint32 crease_edge; + char crease_edge_layer[16]; + VSNGBone *bones; + uint32 bone_count; +} VSNodeGeometry; + +VSNodeGeometry * vs_g_create_node(unsigned int owner) +{ + VSNodeGeometry *node; + unsigned int i; + char name[48]; + node = malloc(sizeof *node); + vs_add_new_node(&node->head, V_NT_GEOMETRY); + sprintf(name, "Geometry_Node_%u", node->head.id); + create_node_head(&node->head, name, owner); + + node->bones = malloc((sizeof *node->bones) * 16); + node->bone_count = 16; + for(i = 0; i < node->bone_count; i++) + node->bones[i].weight[0] = '\0'; + + node->layer = malloc((sizeof *node->layer) * 16); + node->layer_count = 16; + node->vertex_size = VS_G_LAYER_CHUNK; + node->poly_size = VS_G_LAYER_CHUNK; + + strcpy(node->layer[0].name, "vertex"); + node->layer[0].type = VN_G_LAYER_VERTEX_XYZ; + node->layer[0].layer = malloc(sizeof(real64) * VS_G_LAYER_CHUNK * 3); + for(i = 0; i < VS_G_LAYER_CHUNK * 3; i++) + ((real64 *)node->layer[0].layer)[i] = V_REAL64_MAX; + node->layer[0].subscribers = NULL;/*vs_create_subscription_list();*/ + node->layer[0].subscribersd = NULL;/*vs_create_subscription_list();*/ + node->layer[0].def.real = 0; + + strcpy(node->layer[1].name, "polygon"); + node->layer[1].type = VN_G_LAYER_POLYGON_CORNER_UINT32; + node->layer[1].layer = malloc(sizeof(uint32) * VS_G_LAYER_CHUNK * 4); + for(i = 0; i < VS_G_LAYER_CHUNK * 4; i++) + ((uint32 *)node->layer[1].layer)[i] = -1; + node->layer[1].subscribers = NULL;/*vs_create_subscription_list();*/ + node->layer[1].subscribersd = NULL; + node->layer[1].def.integer = 0; + node->layer[1].def.real = 0.0; + + for(i = 2; i < 16; i++) + { + node->layer[i].type = -1; + node->layer[i].name[0] = 0; + node->layer[i].layer = NULL; + node->layer[i].subscribers = NULL; + node->layer[i].subscribersd = NULL; + node->layer[i].def.real = 0; + } + node->crease_vertex = 0; + node->crease_vertex_layer[0] = 0; + node->crease_edge = 0; + node->crease_edge_layer[0] = 0; + node->vertex_hole = 0; + node->polygon_hole = 0; + return node; +} + +void vs_g_destroy_node(VSNodeGeometry *node) +{ + destroy_node_head(&node->head); + free(node); +} + +void vs_g_subscribe(VSNodeGeometry *node) +{ + unsigned int i; + for(i = 0; i < node->layer_count; i++) + { + if(node->layer[i].layer != NULL) + { + verse_send_g_layer_create(node->head.id, (uint16)i, node->layer[i].name, node->layer[i].type, + node->layer[i].def.integer, node->layer[i].def.real); + } + } + verse_send_g_crease_set_vertex(node->head.id, node->crease_vertex_layer, node->crease_vertex); + verse_send_g_crease_set_edge(node->head.id, node->crease_edge_layer, node->crease_edge); + for(i = 0; i < node->bone_count; i++) + { + if(node->bones[i].weight[0] != 0) + verse_send_g_bone_create(node->head.id, (uint16)i, node->bones[i].weight, node->bones[i].reference, node->bones[i].parent, + node->bones[i].pos_x, node->bones[i].pos_y, node->bones[i].pos_z, node->bones[i].position_label, + node->bones[i].rotation_label, node->bones[i].scale_label); + } +} + + +void vs_g_unsubscribe(VSNodeGeometry *node) +{ + unsigned int i; + for(i = 0; i < node->layer_count; i++) { + if(node->layer[i].layer != NULL) { + if(node->layer[i].subscribers) + vs_remove_subscriptor(node->layer[i].subscribers); + if(node->layer[i].subscribersd) + vs_remove_subscriptor(node->layer[i].subscribersd); + } + } +} + +static void callback_send_g_layer_create(void *user, VNodeID node_id, VLayerID layer_id, char *name, uint8 type, uint32 def_uint, real64 def_real) +{ + VSNodeGeometry *node; + unsigned int i, j, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + + if(node == NULL) + return; + if((type < VN_G_LAYER_POLYGON_CORNER_UINT32 && type > VN_G_LAYER_VERTEX_REAL) || + (type > VN_G_LAYER_POLYGON_FACE_REAL)) + return; + + if(layer_id < 2) + layer_id = -1; + for(i = 0; i < node->layer_count; i++) + { + if(node->layer[i].layer != NULL && i != layer_id) + { + for(j = 0; name[j] == node->layer[i].name[j] && name[j] != 0; j++); + if(name[j] == node->layer[i].name[j]) + return; + } + } + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL) + { + for(layer_id = 0; layer_id < node->layer_count && node->layer[layer_id].layer != NULL; layer_id++); + if(layer_id == node->layer_count) + { + layer_id = node->layer_count; + node->layer_count += 16; + node->layer = realloc(node->layer, (sizeof *node->layer) * node->layer_count); + for(i = layer_id; i < node->layer_count; i++) + { + node->layer[i].type = -1; + node->layer[i].name[0] = 0; + node->layer[i].layer = 0; + node->layer[i].subscribers = NULL; + node->layer[i].subscribersd = NULL; + } + } + } + for(i = 0; i < 16; i++) + node->layer[layer_id].name[i] = name[i]; + + if(node->layer[layer_id].type != type) + { + if(node->layer[layer_id].subscribers) { + vs_destroy_subscription_list(node->layer[layer_id].subscribers); + node->layer[layer_id].subscribers = NULL; + } + if(node->layer[layer_id].subscribersd) { + vs_destroy_subscription_list(node->layer[layer_id].subscribersd); + node->layer[layer_id].subscribersd = NULL; + } + node->layer[layer_id].type = type; + free(node->layer[layer_id].layer); + switch(type) + { + case VN_G_LAYER_VERTEX_XYZ : + node->layer[layer_id].layer = malloc(sizeof(real64) * node->vertex_size * 3); + for(i = 0; i < node->vertex_size * 3; i++) + ((real64 *)node->layer[layer_id].layer)[i] = ((real64 *)node->layer[0].layer)[i]; + break; + case VN_G_LAYER_VERTEX_UINT32 : + node->layer[layer_id].layer = malloc(sizeof(uint32) * node->vertex_size); + for(i = 0; i < node->vertex_size; i++) + ((uint32 *)node->layer[layer_id].layer)[i] = def_uint; + node->layer[layer_id].def.integer = def_uint; + break; + case VN_G_LAYER_VERTEX_REAL : + node->layer[layer_id].layer = malloc(sizeof(real64) * node->vertex_size); + for(i = 0; i < node->vertex_size; i++) + ((real64 *)node->layer[layer_id].layer)[i] = def_real; + node->layer[layer_id].def.real = def_real; + break; + case VN_G_LAYER_POLYGON_CORNER_UINT32 : + node->layer[layer_id].layer = malloc(sizeof(uint32) * node->poly_size * 4); + for(i = 0; i < node->poly_size * 4; i++) + ((uint32 *)node->layer[layer_id].layer)[i] = def_uint; + node->layer[layer_id].def.integer = def_uint; + break; + case VN_G_LAYER_POLYGON_CORNER_REAL : + node->layer[layer_id].layer = malloc(sizeof(real64) * node->poly_size * 4); + for(i = 0; i < node->poly_size * 4; i++) + ((real64 *)node->layer[layer_id].layer)[i] = def_real; + node->layer[layer_id].def.real = def_real; + break; + case VN_G_LAYER_POLYGON_FACE_UINT8 : + node->layer[layer_id].layer = malloc(sizeof(uint8) * node->poly_size); + for(i = 0; i < node->poly_size; i++) + ((uint8 *)node->layer[layer_id].layer)[i] = def_uint; + node->layer[layer_id].def.integer = def_uint; + break; + case VN_G_LAYER_POLYGON_FACE_UINT32 : + node->layer[layer_id].layer = malloc(sizeof(uint32) * node->poly_size); + for(i = 0; i < node->poly_size; i++) + ((uint32 *)node->layer[layer_id].layer)[i] = def_uint; + node->layer[layer_id].def.integer = def_uint; + break; + case VN_G_LAYER_POLYGON_FACE_REAL : + node->layer[layer_id].layer = malloc(sizeof(real64) * node->poly_size); + for(i = 0; i < node->poly_size; i++) + ((real64 *)node->layer[layer_id].layer)[i] = def_real; + node->layer[layer_id].def.real = def_real; + break; + } + } + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_g_layer_create(node_id, layer_id, name, type, def_uint, def_real); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_layer_destroy(void *user, VNodeID node_id, VLayerID layer_id) +{ + VSNodeGeometry *node; + unsigned int i, count; + + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || layer_id < 2) + return; + free(node->layer[layer_id].layer); + node->layer[layer_id].layer = NULL; + node->layer[layer_id].name[0] = 0; + node->layer[layer_id].type = -1; + if(node->layer[layer_id].subscribers) { + vs_destroy_subscription_list(node->layer[layer_id].subscribers); + node->layer[layer_id].subscribers = NULL; + } + if(node->layer[layer_id].subscribersd) { + vs_destroy_subscription_list(node->layer[layer_id].subscribersd); + node->layer[layer_id].subscribersd = NULL; + } + + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_g_layer_destroy(node_id, layer_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_layer_subscribe(void *user, VNodeID node_id, VLayerID layer_id, uint8 type) +{ + VSNodeGeometry *node; + VSNGLayer *layer; + VSSubscriptionList **list = NULL; + unsigned int i; + + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL) + return; + /* Pick subscription list to add subscriber to. */ + layer = &node->layer[layer_id]; + if(type == VN_FORMAT_REAL64 && (layer->type == VN_G_LAYER_VERTEX_XYZ || layer->type == VN_G_LAYER_VERTEX_REAL || + layer->type == VN_G_LAYER_POLYGON_CORNER_REAL || layer->type == VN_G_LAYER_POLYGON_FACE_REAL)) + { + list = &node->layer[layer_id].subscribersd; + } + else + list = &node->layer[layer_id].subscribers; + + /* Add new subscriptor to whichever list was chosen by precision-test above. Create list if necessary. */ + if(list == NULL) + return; + if(*list == NULL) + *list = vs_create_subscription_list(); + vs_add_new_subscriptor(*list); + + switch(layer->type) + { + case VN_G_LAYER_VERTEX_XYZ : + if(type == VN_FORMAT_REAL64) + { + for(i = 0; i < node->vertex_size; i++) + if(((real64 *)node->layer[0].layer)[i * 3] != V_REAL64_MAX) + verse_send_g_vertex_set_xyz_real64(node_id, layer_id, i, ((real64 *)layer->layer)[i * 3], ((real64 *)layer->layer)[i * 3 + 1], ((real64 *)layer->layer)[i * 3 + 2]); + }else + { + for(i = 0; i < node->vertex_size; i++) + if(((real64 *)node->layer[0].layer)[i * 3] != V_REAL64_MAX) + verse_send_g_vertex_set_xyz_real32(node_id, layer_id, i, (float)((real64 *)layer->layer)[i * 3], (float)((real64 *)layer->layer)[i * 3 + 1], (float)((real64 *)layer->layer)[i * 3 + 2]); + } + break; + case VN_G_LAYER_VERTEX_UINT32 : + for(i = 0; i < node->vertex_size; i++) + if(((real64 *)node->layer[0].layer)[i * 3] != V_REAL64_MAX && ((uint32 *)layer->layer)[i] != layer->def.integer) + verse_send_g_vertex_set_uint32(node_id, layer_id, i, ((uint32 *)layer->layer)[i]); + break; + case VN_G_LAYER_VERTEX_REAL : + if(type == VN_FORMAT_REAL64) + { + for(i = 0; i < node->vertex_size; i++) + if(((real64 *)node->layer[0].layer)[i * 3] != V_REAL64_MAX && ((real64 *)layer->layer)[i] != layer->def.real) + verse_send_g_vertex_set_real64(node_id, layer_id, i, ((real64 *)layer->layer)[i]); + }else + { + for(i = 0; i < node->vertex_size; i++) + if(((real64 *)node->layer[0].layer)[i * 3] != V_REAL64_MAX && ((real64 *)layer->layer)[i] != layer->def.real) + verse_send_g_vertex_set_real32(node_id, layer_id, i, (float)((real64 *)layer->layer)[i]); + } + break; + case VN_G_LAYER_POLYGON_CORNER_UINT32 : + for(i = 0; i < node->poly_size; i++) + if(((uint32 *)node->layer[1].layer)[i * 4] != (uint32) ~0u && !(((uint32 *)layer->layer)[i * 4] == layer->def.integer && ((uint32 *)layer->layer)[i * 4 + 1] == layer->def.integer && ((uint32 *)layer->layer)[i * 4 + 2] == layer->def.integer && ((uint32 *)layer->layer)[i * 4 + 3] == layer->def.integer)) + verse_send_g_polygon_set_corner_uint32(node_id, layer_id, i, ((uint32 *)layer->layer)[i * 4], ((uint32 *)layer->layer)[i * 4 + 1], ((uint32 *)layer->layer)[i * 4 + 2], ((uint32 *)layer->layer)[i * 4 + 3]); + break; + case VN_G_LAYER_POLYGON_CORNER_REAL : + if(type == VN_FORMAT_REAL64) + { + for(i = 0; i < node->poly_size; i++) + if(((uint32 *)node->layer[1].layer)[i * 4] != (uint32) ~0u && !(((real64 *)layer->layer)[i * 4] == layer->def.real && ((real64 *)layer->layer)[i * 4 + 1] == layer->def.real && ((real64 *)layer->layer)[i * 4 + 2] == layer->def.real && ((real64 *)layer->layer)[i * 4 + 3] == layer->def.real)) + verse_send_g_polygon_set_corner_real64(node_id, layer_id, i, ((real64 *)layer->layer)[i * 4], ((real64 *)layer->layer)[i * 4 + 1], ((real64 *)layer->layer)[i * 4 + 2], ((real64 *)layer->layer)[i * 4 + 3]); + }else + { + for(i = 0; i < node->poly_size; i++) + if(((uint32 *)node->layer[1].layer)[i * 4] != (uint32) ~0u && !(((real64 *)layer->layer)[i * 4] == layer->def.real && ((real64 *)layer->layer)[i * 4 + 1] == layer->def.real && ((real64 *)layer->layer)[i * 4 + 2] == layer->def.real && ((real64 *)layer->layer)[i * 4 + 3] == layer->def.real)) + verse_send_g_polygon_set_corner_real32(node_id, layer_id, i, (float)((real64 *)layer->layer)[i * 4], (float)((real64 *)layer->layer)[i * 4 + 1], (float)((real64 *)layer->layer)[i * 4 + 2], (float)((real64 *)layer->layer)[i * 4 + 3]); + } + break; + case VN_G_LAYER_POLYGON_FACE_UINT8 : + for(i = 0; i < node->poly_size; i++) + if(((uint32 *)node->layer[1].layer)[i * 4] != (uint32) ~0u && ((uint8 *)layer->layer)[i] != layer->def.integer) + verse_send_g_polygon_set_face_uint8(node_id, layer_id, i, ((uint8 *)layer->layer)[i]); + break; + case VN_G_LAYER_POLYGON_FACE_UINT32 : + for(i = 0; i < node->poly_size; i++) + if(((uint32 *)node->layer[1].layer)[i * 4] != (uint32) ~0u && ((uint32 *)layer->layer)[i] != layer->def.integer) + verse_send_g_polygon_set_face_uint32(node_id, layer_id, i, ((uint32 *)layer->layer)[i]); + break; + case VN_G_LAYER_POLYGON_FACE_REAL : + if(type == VN_FORMAT_REAL64) + { + for(i = 0; i < node->poly_size; i++) + if(((uint32 *)node->layer[1].layer)[i * 4] != (uint32) ~0u && ((real64 *)layer->layer)[i] != layer->def.real) + verse_send_g_polygon_set_face_real64(node_id, layer_id, i, ((real64 *)layer->layer)[i]); + }else + { + for(i = 0; i < node->poly_size; i++) + if(((uint32 *)node->layer[1].layer)[i * 4] != (uint32) ~0u && ((real64 *)layer->layer)[i] != layer->def.real) + verse_send_g_polygon_set_face_real32(node_id, layer_id, i, (float)((real64 *)layer->layer)[i]); + } + break; + } +} + +static void callback_send_g_layer_unsubscribe(void *user, VNodeID node_id, VLayerID layer_id) +{ + VSNodeGeometry *node; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL) + return; + if(node->layer[layer_id].subscribers) + vs_remove_subscriptor(node->layer[layer_id].subscribers); + if(node->layer[layer_id].subscribersd) + vs_remove_subscriptor(node->layer[layer_id].subscribersd); +} + + +static unsigned int vs_g_extend_arrays(VSNodeGeometry *node, boolean vertex, boolean base_layer, unsigned int id) +{ + unsigned int i, j; + + if(base_layer && id == ~0u) + { + if(vertex) + { + while(node->vertex_hole < node->vertex_size && ((real64 *)node->layer[0].layer)[node->vertex_hole * 3] != V_REAL64_MAX) + node->vertex_hole++; + id = node->vertex_hole; + }else + { + while(node->polygon_hole < node->poly_size && ((uint32 *)node->layer[1].layer)[node->polygon_hole * 4] != ~0u) + node->polygon_hole++; + id = node->polygon_hole; + } + } + + if(vertex) + { + if(node->vertex_size + 4096 < id) + return -1; + if(node->vertex_size > id) + return id; + }else + { + if(node->poly_size + 4096 < id) + return -1; + if(node->poly_size > id) + return id; + } + + for(i = 0; i < node->layer_count; i++) + { + if((vertex && node->layer[i].type < VN_G_LAYER_POLYGON_CORNER_UINT32) || (!vertex && node->layer[i].type >= VN_G_LAYER_POLYGON_CORNER_UINT32)) + { + switch(node->layer[i].type) + { + case VN_G_LAYER_VERTEX_XYZ : + node->layer[i].layer = realloc(node->layer[i].layer, sizeof(real64) * (id + VS_G_LAYER_CHUNK) * 3); + for(j = node->vertex_size * 3; j < (id + VS_G_LAYER_CHUNK) * 3; j++) + ((real64 *)node->layer[i].layer)[j] = V_REAL64_MAX; + break; + case VN_G_LAYER_VERTEX_UINT32 : + node->layer[i].layer = realloc(node->layer[i].layer, sizeof(uint32) * (id + VS_G_LAYER_CHUNK)); + for(j = node->vertex_size; j < (id + VS_G_LAYER_CHUNK); j++) + ((uint32 *)node->layer[i].layer)[j] = node->layer[i].def.integer; + break; + case VN_G_LAYER_VERTEX_REAL : + node->layer[i].layer = realloc(node->layer[i].layer, sizeof(real64) * (id + VS_G_LAYER_CHUNK)); + for(j = node->vertex_size; j < (id + VS_G_LAYER_CHUNK); j++) + ((real64 *)node->layer[i].layer)[j] = node->layer[i].def.real; + break; + case VN_G_LAYER_POLYGON_CORNER_UINT32 : + node->layer[i].layer = realloc(node->layer[i].layer, sizeof(uint32) * (id + VS_G_LAYER_CHUNK) * 4); + for(j = node->poly_size * 4; j < (id + VS_G_LAYER_CHUNK) * 4; j++) + ((uint32 *)node->layer[i].layer)[j] = node->layer[i].def.integer; + break; + case VN_G_LAYER_POLYGON_CORNER_REAL : + node->layer[i].layer = realloc(node->layer[i].layer, sizeof(real64) * (id + VS_G_LAYER_CHUNK) * 4); + for(j = node->poly_size * 4; j < (id + VS_G_LAYER_CHUNK) * 4; j++) + ((real64 *)node->layer[i].layer)[j] = node->layer[i].def.real; + break; + case VN_G_LAYER_POLYGON_FACE_UINT8 : + node->layer[i].layer = realloc(node->layer[i].layer, sizeof(uint8) * (id + VS_G_LAYER_CHUNK)); + for(j = node->poly_size; j < (id + VS_G_LAYER_CHUNK); j++) + ((uint8 *)node->layer[i].layer)[j] = node->layer[i].def.integer; + break; + case VN_G_LAYER_POLYGON_FACE_UINT32 : + node->layer[i].layer = realloc(node->layer[i].layer, sizeof(uint32) * (id + VS_G_LAYER_CHUNK)); + for(j = node->poly_size; j < (id + VS_G_LAYER_CHUNK); j++) + ((uint32 *)node->layer[i].layer)[j] = node->layer[i].def.integer; + break; + case VN_G_LAYER_POLYGON_FACE_REAL : + node->layer[i].layer = realloc(node->layer[i].layer, sizeof(real64) * (id + VS_G_LAYER_CHUNK)); + for(j = node->poly_size; j < (id + VS_G_LAYER_CHUNK); j++) + ((real64 *)node->layer[i].layer)[j] = node->layer[i].def.real; + break; + } + } + } + if(vertex) + node->vertex_size = id + VS_G_LAYER_CHUNK; + else + node->poly_size = id + VS_G_LAYER_CHUNK; + return id; +} + + +static void callback_send_g_vertex_set_xyz_real32(void *user, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, float x, float y, float z) +{ + VSNodeGeometry *node; + unsigned int i, count; + + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || node->layer[layer_id].type != VN_G_LAYER_VERTEX_XYZ) + return; + if((vertex_id = vs_g_extend_arrays(node, TRUE, layer_id == 0, vertex_id)) == ~0u) + return; + if(((real64 *)node->layer[0].layer)[vertex_id * 3] == V_REAL64_MAX) + { + for(i = 0; i < node->layer_count; i++) + { + if(node->layer[i].name[0] != 0 && node->layer[i].type == VN_G_LAYER_VERTEX_XYZ && node->layer[i].layer != NULL) + { + ((real64 *)node->layer[i].layer)[vertex_id * 3] = x; + ((real64 *)node->layer[i].layer)[vertex_id * 3 + 1] = y; + ((real64 *)node->layer[i].layer)[vertex_id * 3 + 2] = z; + } + } + layer_id = 0; + }else + { + ((real64 *)node->layer[layer_id].layer)[vertex_id * 3] = x; + ((real64 *)node->layer[layer_id].layer)[vertex_id * 3 + 1] = y; + ((real64 *)node->layer[layer_id].layer)[vertex_id * 3 + 2] = z; + } + count = vs_get_subscript_count(node->layer[layer_id].subscribersd); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribersd, i); + verse_send_g_vertex_set_xyz_real64(node_id, layer_id, vertex_id, (real64)x, (real64)y, (real64)z); + } + count = vs_get_subscript_count(node->layer[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribers, i); + verse_send_g_vertex_set_xyz_real32(node_id, layer_id, vertex_id, x, y, z); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_vertex_set_xyz_real64(void *user, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real64 x, real64 y, real64 z) +{ + VSNodeGeometry *node; + unsigned int i, count; + + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || node->layer[layer_id].type != VN_G_LAYER_VERTEX_XYZ) + return; + if((vertex_id = vs_g_extend_arrays(node, TRUE, layer_id == 0, vertex_id)) == ~0u) + return; + if(((real64 *)node->layer[0].layer)[vertex_id * 3] == V_REAL64_MAX) + { + for(i = 0; i < node->layer_count; i++) + { + if(node->layer[i].name[0] != 0 && node->layer[i].type == VN_G_LAYER_VERTEX_XYZ && node->layer[i].layer != NULL) + { + ((real64 *)node->layer[i].layer)[vertex_id * 3] = x; + ((real64 *)node->layer[i].layer)[vertex_id * 3 + 1] = y; + ((real64 *)node->layer[i].layer)[vertex_id * 3 + 2] = z; + } + } + layer_id = 0; + }else + { + ((real64 *)node->layer[layer_id].layer)[vertex_id * 3] = x; + ((real64 *)node->layer[layer_id].layer)[vertex_id * 3 + 1] = y; + ((real64 *)node->layer[layer_id].layer)[vertex_id * 3 + 2] = z; + } + count = vs_get_subscript_count(node->layer[layer_id].subscribersd); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribersd, i); + verse_send_g_vertex_set_xyz_real64(node_id, layer_id, vertex_id, x, y, z); + } + count = vs_get_subscript_count(node->layer[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribers, i); + verse_send_g_vertex_set_xyz_real32(node_id, layer_id, vertex_id, (float)x, (float)y, (float)z); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_vertex_delete_real(void *user, VNodeID node_id, uint32 vertex_id) +{ + VSNodeGeometry *node; + unsigned int i, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(vertex_id >= node->vertex_size) + return; + if(vertex_id < node->vertex_hole) + node->vertex_hole = vertex_id; + for(i = 0; i < node->layer_count; i++) + if(node->layer[i].name[0] != 0 && node->layer[i].type == VN_G_LAYER_VERTEX_XYZ && node->layer[i].layer != NULL) + ((real64 *)node->layer[i].layer)[vertex_id * 3] = V_REAL64_MAX; + count = vs_get_subscript_count(node->layer[0].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[0].subscribers, i); + verse_send_g_vertex_delete_real32(node_id, vertex_id); + } + count = vs_get_subscript_count(node->layer[0].subscribersd); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[0].subscribersd, i); + verse_send_g_vertex_delete_real64(node_id, vertex_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_vertex_set_uint32(void *user, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, uint32 value) +{ + VSNodeGeometry *node; + unsigned int i, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || node->layer[layer_id].type != VN_G_LAYER_VERTEX_UINT32) + return; + if((vertex_id = vs_g_extend_arrays(node, TRUE, FALSE, vertex_id)) == ~0u) + return; + ((uint32 *)node->layer[layer_id].layer)[vertex_id] = value; + count = vs_get_subscript_count(node->layer[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribers, i); + verse_send_g_vertex_set_uint32(node_id, layer_id, vertex_id, value); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_vertex_set_real64(void *user, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real64 value) +{ + VSNodeGeometry *node; + unsigned int i, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || node->layer[layer_id].type != VN_G_LAYER_VERTEX_REAL) + return; + if((vertex_id = vs_g_extend_arrays(node, TRUE, FALSE, vertex_id)) == ~0u) + return; + ((real64 *)node->layer[layer_id].layer)[vertex_id] = value; + count = vs_get_subscript_count(node->layer[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribers, i); + verse_send_g_vertex_set_real32(node_id, layer_id, vertex_id, (float)value); + } + count = vs_get_subscript_count(node->layer[layer_id].subscribersd); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribersd, i); + verse_send_g_vertex_set_real64(node_id, layer_id, vertex_id, value); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_vertex_set_real32(void *user, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, float value) +{ + VSNodeGeometry *node; + unsigned int i, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || node->layer[layer_id].type != VN_G_LAYER_VERTEX_REAL) + return; + if((vertex_id = vs_g_extend_arrays(node, TRUE, FALSE, vertex_id)) == ~0u) + return; + ((real64 *)node->layer[layer_id].layer)[vertex_id] = (real64)value; + count = vs_get_subscript_count(node->layer[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribers, i); + verse_send_g_vertex_set_real32(node_id, layer_id, vertex_id, value); + } + count = vs_get_subscript_count(node->layer[layer_id].subscribersd); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribersd, i); + verse_send_g_vertex_set_real64(node_id, layer_id, vertex_id, (real64)value); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_polygon_set_corner_uint32(void *user, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3) +{ + VSNodeGeometry *node; + unsigned int i, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || node->layer[layer_id].type != VN_G_LAYER_POLYGON_CORNER_UINT32) + return; + if(layer_id == 1 && (v0 == v1 || v1 == v2 || v2 == v3 || v3 == v0 || v0 == v2 || v1 == v3)) + return; + if((polygon_id = vs_g_extend_arrays(node, FALSE, layer_id == 1, polygon_id)) == ~0u) + return; + ((uint32 *)node->layer[layer_id].layer)[polygon_id * 4] = v0; + ((uint32 *)node->layer[layer_id].layer)[polygon_id * 4 + 1] = v1; + ((uint32 *)node->layer[layer_id].layer)[polygon_id * 4 + 2] = v2; + ((uint32 *)node->layer[layer_id].layer)[polygon_id * 4 + 3] = v3; + count = vs_get_subscript_count(node->layer[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribers, i); + verse_send_g_polygon_set_corner_uint32(node_id, layer_id, polygon_id, v0, v1, v2, v3); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_polygon_set_corner_real64(void *user, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real64 v0, real64 v1, real64 v2, real64 v3) +{ + VSNodeGeometry *node; + unsigned int i, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || node->layer[layer_id].type != VN_G_LAYER_POLYGON_CORNER_REAL) + return; + if((polygon_id = vs_g_extend_arrays(node, FALSE, FALSE, polygon_id)) == ~0u) + return; + ((real64 *)node->layer[layer_id].layer)[polygon_id * 4] = v0; + ((real64 *)node->layer[layer_id].layer)[polygon_id * 4 + 1] = v1; + ((real64 *)node->layer[layer_id].layer)[polygon_id * 4 + 2] = v2; + ((real64 *)node->layer[layer_id].layer)[polygon_id * 4 + 3] = v3; + count = vs_get_subscript_count(node->layer[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribers, i); + verse_send_g_polygon_set_corner_real32(node_id, layer_id, polygon_id, (float)v0, (float)v1, (float)v2, (float)v3); + } + count = vs_get_subscript_count(node->layer[layer_id].subscribersd); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribersd, i); + verse_send_g_polygon_set_corner_real64(node_id, layer_id, polygon_id, v0, v1, v2, v3); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_polygon_set_corner_real32(void *user, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, float v0, float v1, float v2, float v3) +{ + VSNodeGeometry *node; + unsigned int i, count; + + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || node->layer[layer_id].type != VN_G_LAYER_POLYGON_CORNER_REAL) + return; + if((polygon_id = vs_g_extend_arrays(node, FALSE, FALSE, polygon_id)) == ~0u) + return; + ((real64 *)node->layer[layer_id].layer)[polygon_id * 4] = v0; + ((real64 *)node->layer[layer_id].layer)[polygon_id * 4 + 1] = v1; + ((real64 *)node->layer[layer_id].layer)[polygon_id * 4 + 2] = v2; + ((real64 *)node->layer[layer_id].layer)[polygon_id * 4 + 3] = v3; + count = vs_get_subscript_count(node->layer[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribers, i); + verse_send_g_polygon_set_corner_real32(node_id, layer_id, polygon_id, v0, v1, v2, v3); + } + count = vs_get_subscript_count(node->layer[layer_id].subscribersd); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribersd, i); + verse_send_g_polygon_set_corner_real64(node_id, layer_id, polygon_id, (real64)v0, (real64)v1, (real64)v2, (real64)v3); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_polygon_set_face_uint8(void *user, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint8 value) +{ + VSNodeGeometry *node; + unsigned int i, count; + + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || node->layer[layer_id].type != VN_G_LAYER_POLYGON_FACE_UINT8) + return; + if((polygon_id = vs_g_extend_arrays(node, FALSE, FALSE, polygon_id)) == ~0u) + return; + ((uint8 *)node->layer[layer_id].layer)[polygon_id] = value; + count = vs_get_subscript_count(node->layer[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribers, i); + verse_send_g_polygon_set_face_uint8(node_id, layer_id, polygon_id, value); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_polygon_set_face_uint32(void *user, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint32 value) +{ + VSNodeGeometry *node; + unsigned int i, count; + + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || node->layer[layer_id].type != VN_G_LAYER_POLYGON_FACE_UINT32) + return; + if((polygon_id = vs_g_extend_arrays(node, FALSE, FALSE, polygon_id)) == ~0u) + return; + ((uint32 *)node->layer[layer_id].layer)[polygon_id] = value; + count = vs_get_subscript_count(node->layer[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribers, i); + verse_send_g_polygon_set_face_uint32(node_id, layer_id, polygon_id, value); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_polygon_set_face_real64(void *user, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real64 value) +{ + VSNodeGeometry *node; + unsigned int i, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || node->layer[layer_id].type != VN_G_LAYER_POLYGON_FACE_REAL) + return; + if((polygon_id = vs_g_extend_arrays(node, FALSE, FALSE, polygon_id)) == ~0u) + return; + ((real64 *)node->layer[layer_id].layer)[polygon_id] = value; + count = vs_get_subscript_count(node->layer[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribers, i); + verse_send_g_polygon_set_face_real32(node_id, layer_id, polygon_id, (float)value); + } + count = vs_get_subscript_count(node->layer[layer_id].subscribersd); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribersd, i); + verse_send_g_polygon_set_face_real64(node_id, layer_id, polygon_id, value); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_polygon_set_face_real32(void *user, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, float value) +{ + VSNodeGeometry *node; + unsigned int i, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || node->layer[layer_id].type != VN_G_LAYER_POLYGON_FACE_REAL) + return; + if((polygon_id = vs_g_extend_arrays(node, FALSE, FALSE, polygon_id)) == ~0u) + return; + ((real64 *)node->layer[layer_id].layer)[polygon_id] = (real64)value; + count = vs_get_subscript_count(node->layer[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribers, i); + verse_send_g_polygon_set_face_real32(node_id, layer_id, polygon_id, value); + } + count = vs_get_subscript_count(node->layer[layer_id].subscribersd); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribersd, i); + verse_send_g_polygon_set_face_real64(node_id, layer_id, polygon_id, (real64)value); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_polygon_delete(void *user, VNodeID node_id, uint32 polygon_id) +{ + VSNodeGeometry *node; + unsigned int i, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + + if(polygon_id >= node->poly_size || ((uint32 *)node->layer[1].layer)[polygon_id * 4] == ~0u) + return; + if(polygon_id < node->polygon_hole) + node->polygon_hole = polygon_id; + + ((uint32 *)node->layer[1].layer)[polygon_id * 4] = ~0u; + count = vs_get_subscript_count(node->layer[1].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[1].subscribers, i); + verse_send_g_polygon_delete(node_id, polygon_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_crease_set_vertex(void *user, VNodeID node_id, const char *layer, uint32 def_crease) +{ + VSNodeGeometry *node; + unsigned int i, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + node->crease_vertex = def_crease; + v_strlcpy(node->crease_vertex_layer, layer, sizeof node->crease_vertex_layer); + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_g_crease_set_vertex(node_id, layer, def_crease); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_crease_set_edge(void *user, VNodeID node_id, const char *layer, uint32 def_crease) +{ + VSNodeGeometry *node; + unsigned int i, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + node->crease_edge = def_crease; + v_strlcpy(node->crease_edge_layer, layer, sizeof node->crease_edge_layer); + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_g_crease_set_edge(node_id, layer, def_crease); + } + vs_reset_subscript_session(); +} + +void callback_send_g_bone_create(void *user, VNodeID node_id, uint16 bone_id, const char *weight, + const char *reference, uint16 parent, + real64 pos_x, real64 pos_y, real64 pos_z, + const char *position_label, const char *rotation_label, const char *scale_label) +{ + VSNodeGeometry *node; + unsigned int i, count; + + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(bone_id >= node->bone_count || node->bones[bone_id].weight[0] == '\0') + { + /* Find free bone to re-use, if any. */ + for(bone_id = 0; bone_id < node->bone_count && node->bones[bone_id].weight[0] != '\0'; bone_id++) + ; + if(bone_id == node->bone_count) + { + bone_id = node->bone_count; + node->bone_count += 16; + node->bones = realloc(node->bones, (sizeof *node->bones) * node->bone_count); + for(i = bone_id; i < node->bone_count; i++) + node->bones[i].weight[0] = '\0'; + } + } + v_strlcpy(node->bones[bone_id].weight, weight, sizeof node->bones[bone_id].weight); + v_strlcpy(node->bones[bone_id].reference, reference, sizeof node->bones[bone_id].reference); + node->bones[bone_id].parent = parent; + node->bones[bone_id].pos_x = pos_x; + node->bones[bone_id].pos_y = pos_y; + node->bones[bone_id].pos_z = pos_z; + v_strlcpy(node->bones[bone_id].position_label, position_label, sizeof node->bones[bone_id].position_label); + v_strlcpy(node->bones[bone_id].rotation_label, rotation_label, sizeof node->bones[bone_id].rotation_label); + v_strlcpy(node->bones[bone_id].scale_label, scale_label, sizeof node->bones[bone_id].scale_label); + + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_g_bone_create(node_id, bone_id, weight, reference, parent, pos_x, pos_y, pos_z, position_label, rotation_label, scale_label); + } + vs_reset_subscript_session(); +} + +void callback_send_g_bone_destroy(void *user, VNodeID node_id, uint32 bone_id) +{ + VSNodeGeometry *node; + unsigned int i, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(bone_id >= node->bone_count || node->bones[bone_id].weight[0] == 0) + return; + node->bones[bone_id].weight[0] = 0; + + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_g_bone_destroy(node_id, bone_id); + } + vs_reset_subscript_session(); +} + +void vs_g_callback_init(void) +{ + verse_callback_set(verse_send_g_layer_create, callback_send_g_layer_create, NULL); + verse_callback_set(verse_send_g_layer_destroy, callback_send_g_layer_destroy, NULL); + verse_callback_set(verse_send_g_layer_subscribe, callback_send_g_layer_subscribe, NULL); + verse_callback_set(verse_send_g_layer_unsubscribe, callback_send_g_layer_unsubscribe, NULL); + verse_callback_set(verse_send_g_vertex_set_xyz_real32, callback_send_g_vertex_set_xyz_real32, NULL); + verse_callback_set(verse_send_g_vertex_set_xyz_real64, callback_send_g_vertex_set_xyz_real64, NULL); + verse_callback_set(verse_send_g_vertex_set_uint32, callback_send_g_vertex_set_uint32, NULL); + verse_callback_set(verse_send_g_vertex_set_real32, callback_send_g_vertex_set_real32, NULL); + verse_callback_set(verse_send_g_vertex_set_real64, callback_send_g_vertex_set_real64, NULL); + verse_callback_set(verse_send_g_vertex_delete_real32, callback_send_g_vertex_delete_real, NULL); + verse_callback_set(verse_send_g_vertex_delete_real64, callback_send_g_vertex_delete_real, NULL); + verse_callback_set(verse_send_g_polygon_set_corner_uint32, callback_send_g_polygon_set_corner_uint32, NULL); + verse_callback_set(verse_send_g_polygon_set_corner_real32, callback_send_g_polygon_set_corner_real32, NULL); + verse_callback_set(verse_send_g_polygon_set_corner_real64, callback_send_g_polygon_set_corner_real64, NULL); + verse_callback_set(verse_send_g_polygon_set_face_uint8, callback_send_g_polygon_set_face_uint8, NULL); + verse_callback_set(verse_send_g_polygon_set_face_uint32, callback_send_g_polygon_set_face_uint32, NULL); + verse_callback_set(verse_send_g_polygon_set_face_real32, callback_send_g_polygon_set_face_real32, NULL); + verse_callback_set(verse_send_g_polygon_set_face_real64, callback_send_g_polygon_set_face_real64, NULL); + verse_callback_set(verse_send_g_polygon_delete, callback_send_g_polygon_delete, NULL); + verse_callback_set(verse_send_g_crease_set_vertex, callback_send_g_crease_set_vertex, NULL); + verse_callback_set(verse_send_g_crease_set_edge, callback_send_g_crease_set_edge, NULL); + verse_callback_set(verse_send_g_bone_create, callback_send_g_bone_create, NULL); + verse_callback_set(verse_send_g_bone_destroy, callback_send_g_bone_destroy, NULL); +} + +#endif diff --git a/extern/verse/dist/vs_node_head.c b/extern/verse/dist/vs_node_head.c new file mode 100644 index 00000000000..9e926411542 --- /dev/null +++ b/extern/verse/dist/vs_node_head.c @@ -0,0 +1,414 @@ +/* +** +*/ + +#include +#include +#include + +#include "v_cmd_gen.h" + +#if !defined(V_GENERATE_FUNC_MODE) + +#include "verse.h" +#include "v_util.h" +#include "vs_server.h" + +typedef struct { + VNTag tag; + VNTagType type; + char tag_name[16]; +} VSTag; + +typedef struct { + VSTag *tags; + unsigned int tag_count; + char group_name[16]; + VSSubscriptionList *subscribers; +} VSTagGroup; + +void create_node_head(VSNodeHead *node, const char *name, unsigned int owner) +{ + size_t len; + + len = strlen(name) + 1; + node->name = malloc(len); + v_strlcpy(node->name, name, len); + node->owner = owner; + node->tag_groups = NULL; + node->group_count = 0; + node->subscribers = vs_create_subscription_list(); +} + +void destroy_node_head(VSNodeHead *node) +{ + unsigned int i, j; + if(node->name != NULL) + free(node->name); + if(node->tag_groups != NULL) + { + for(i = 0; i < node->group_count; i++) + { + for(j = 0; j < ((VSTagGroup *)node->tag_groups)[i].tag_count; j++) + { + if(((VSTagGroup *)node->tag_groups)[i].tags[j].type == VN_TAG_STRING) + free(((VSTagGroup *)node->tag_groups)[i].tags[j].tag.vstring); + if(((VSTagGroup *)node->tag_groups)[i].tags[j].type == VN_TAG_BLOB) + free(((VSTagGroup *)node->tag_groups)[i].tags[j].tag.vblob.blob); + } + if(((VSTagGroup *)node->tag_groups)[i].tags != NULL) + free(((VSTagGroup *)node->tag_groups)[i].tags); + } + if(node->tag_groups != NULL) + free(node->tag_groups); + } +} + + void callback_send_tag_group_create(void *user, VNodeID node_id, uint16 group_id, const char *name) +{ + VSNodeHead *node; + unsigned int count, i, j, element; + + if((node = vs_get_node_head(node_id)) == 0) + return; + if(name[0] == 0) + return; + + for(i = 0; i < node->group_count; i++) /* see if a tag group with this name alredy exists*/ + { + if(((VSTagGroup *)node->tag_groups)[i].group_name[0] != 0) + { + for(j = 0; name[j] == ((VSTagGroup *)node->tag_groups)[i].group_name[j] && name[j] != 0; j++); + if(name[j] == ((VSTagGroup *)node->tag_groups)[i].group_name[j]) + return; + } + } + if(group_id < node->group_count && ((VSTagGroup *)node->tag_groups)[group_id].group_name[0] != 0) /* rename existing group */ + { + element = group_id; + }else /* create new game group */ + { + for(element = 0; element < node->group_count && ((VSTagGroup *)node->tag_groups)[element].group_name[0] != 0; element++); + if(element == node->group_count) + { + node->tag_groups = realloc(node->tag_groups, sizeof(VSTagGroup) * (node->group_count + 16)); + for(i = node->group_count; i < node->group_count + 16U; i++) + { + ((VSTagGroup *)node->tag_groups)[i].group_name[0] = 0; + ((VSTagGroup *)node->tag_groups)[i].tags = NULL; + ((VSTagGroup *)node->tag_groups)[i].tag_count = 0; + ((VSTagGroup *)node->tag_groups)[i].subscribers = NULL; + } + node->group_count += 16; + } + ((VSTagGroup *)node->tag_groups)[element].subscribers = vs_create_subscription_list(); + } + v_strlcpy(((VSTagGroup *)node->tag_groups)[element].group_name, name, + sizeof ((VSTagGroup *)node->tag_groups)[element].group_name); + + count = vs_get_subscript_count(node->subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->subscribers, i); + verse_send_tag_group_create(node_id, element, name); + } + vs_reset_subscript_session(); +} + +static void callback_send_tag_group_destroy(void *user, VNodeID node_id, uint16 group_id) +{ + VSNodeHead *node; + unsigned int count, i; + if((node = vs_get_node_head(node_id)) == 0) + return; + + if(node->group_count <= group_id || ((VSTagGroup *)node->tag_groups)[group_id].group_name[0] == 0) + return; + + vs_destroy_subscription_list(((VSTagGroup *)node->tag_groups)[group_id].subscribers); + for(i = 0; i < ((VSTagGroup *)node->tag_groups)[group_id].tag_count; i++) + { + if(((VSTagGroup *)node->tag_groups)[group_id].tags[i].type == VN_TAG_STRING) + free(((VSTagGroup *)node->tag_groups)[group_id].tags[i].tag.vstring); + if(((VSTagGroup *)node->tag_groups)[group_id].tags[i].type == VN_TAG_BLOB) + free(((VSTagGroup *)node->tag_groups)[group_id].tags[i].tag.vblob.blob); + } + if(((VSTagGroup *)node->tag_groups)[group_id].tags != NULL) + free(((VSTagGroup *)node->tag_groups)[group_id].tags); + ((VSTagGroup *)node->tag_groups)[group_id].group_name[0] = 0; + ((VSTagGroup *)node->tag_groups)[group_id].tags = NULL; + ((VSTagGroup *)node->tag_groups)[group_id].tag_count = 0; + + count = vs_get_subscript_count(node->subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->subscribers, i); + verse_send_tag_group_destroy(node_id, group_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_tag_group_subscribe(void *user, VNodeID node_id, uint16 group_id) +{ + VSNodeHead *node; + unsigned int i; + if((node = vs_get_node_head(node_id)) == 0) + return; + + if(group_id < node->group_count && ((VSTagGroup *)node->tag_groups)[group_id].group_name[0] != 0) + { + vs_add_new_subscriptor(((VSTagGroup *)node->tag_groups)[group_id].subscribers); + for(i = 0; i < ((VSTagGroup *)node->tag_groups)[group_id].tag_count; i++) + { + if(((VSTagGroup *)node->tag_groups)[group_id].tags[i].tag_name[0] != 0) + { + verse_send_tag_create(node_id, group_id, (uint16)i, ((VSTagGroup *)node->tag_groups)[group_id].tags[i].tag_name, ((VSTagGroup *)node->tag_groups)[group_id].tags[i].type, &((VSTagGroup *)node->tag_groups)[group_id].tags[i].tag); + } + } + } +} + +static void callback_send_tag_group_unsubscribe(void *user, VNodeID node_id, uint16 group_id) +{ + VSNodeHead *node; + if((node = vs_get_node_head(node_id)) == 0) + return; + if(group_id < node->group_count && ((VSTagGroup *)node->tag_groups)[group_id].group_name[0] != 0) + vs_remove_subscriptor(((VSTagGroup *)node->tag_groups)[group_id].subscribers); +} + +static void callback_send_tag_create(void *user, VNodeID node_id, uint16 group_id, uint16 tag_id, char *name, uint8 type, void *tag) +{ + VSNodeHead *node; + VSTag *t = NULL; + unsigned int i, count; + + if((node = vs_get_node_head(node_id)) == 0) + return; + if(group_id >= node->group_count || ((VSTagGroup *)node->tag_groups)[group_id].group_name[0] == 0) + return; + +/* for(i = 0; i < ((VSTagGroup *)node->tag_groups)[group_id].tag_count; i++) + { + if(((VSTagGroup *)node->tag_groups)[group_id].tags[i].tag_name != NULL && i != tag_id) + { + for(j = 0; name[j] == ((VSTagGroup *)node->tag_groups)[group_id].tags[i].tag_name[j] && name[j] != 0; j++); + if(name[j] == ((VSTagGroup *)node->tag_groups)[group_id].tags[i].tag_name[j]) + return; + } + }*/ + if(tag_id < ((VSTagGroup *)node->tag_groups)[group_id].tag_count && ((VSTagGroup *)node->tag_groups)[group_id].tags[tag_id].tag_name[0] != 0) + ; + else + { + for(tag_id = 0; tag_id < ((VSTagGroup *)node->tag_groups)[group_id].tag_count && ((VSTagGroup *)node->tag_groups)[group_id].tags[tag_id].tag_name[0] != 0; tag_id++) + ; + if(tag_id == ((VSTagGroup *)node->tag_groups)[group_id].tag_count) + { + ((VSTagGroup *)node->tag_groups)[group_id].tags = realloc(((VSTagGroup *)node->tag_groups)[group_id].tags, sizeof(VSTag) * (((VSTagGroup *)node->tag_groups)[group_id].tag_count + 16)); + for(i = tag_id; i < ((VSTagGroup *)node->tag_groups)[group_id].tag_count + 16; i++) + ((VSTagGroup *)node->tag_groups)[group_id].tags[i].tag_name[0] = 0; + ((VSTagGroup *)node->tag_groups)[group_id].tag_count += 16; + } + } + t = &((VSTagGroup *)node->tag_groups)[group_id].tags[tag_id]; + if(t->tag_name[0] != '\0') /* Old tag being re-set? */ + { + if(t->type == VN_TAG_STRING) + free(t->tag.vstring); + else if(t->type == VN_TAG_BLOB) + free(t->tag.vblob.blob); + } + t->type = type; + v_strlcpy(t->tag_name, name, sizeof t->tag_name); + switch(type) + { + case VN_TAG_BOOLEAN : + t->tag.vboolean = ((VNTag *)tag)->vboolean; + break; + case VN_TAG_UINT32 : + t->tag.vuint32 = ((VNTag *)tag)->vuint32; + break; + case VN_TAG_REAL64 : + t->tag.vreal64 = ((VNTag *)tag)->vreal64; + break; + case VN_TAG_STRING : + i = strlen(((VNTag *) tag)->vstring); + t->tag.vstring = malloc(i + 1); + strcpy(t->tag.vstring, ((VNTag *) tag)->vstring); + break; + case VN_TAG_REAL64_VEC3 : + t->tag.vreal64_vec3[0] = ((VNTag *)tag)->vreal64_vec3[0]; + t->tag.vreal64_vec3[1] = ((VNTag *)tag)->vreal64_vec3[1]; + t->tag.vreal64_vec3[2] = ((VNTag *)tag)->vreal64_vec3[2]; + break; + case VN_TAG_LINK : + t->tag.vlink = ((VNTag *)tag)->vlink; + break; + case VN_TAG_ANIMATION : + t->tag.vanimation.curve = ((VNTag *)tag)->vanimation.curve; + t->tag.vanimation.start = ((VNTag *)tag)->vanimation.start; + t->tag.vanimation.end = ((VNTag *)tag)->vanimation.end; + break; + case VN_TAG_BLOB : + t->tag.vblob.blob = malloc(((VNTag *)tag)->vblob.size); + t->tag.vblob.size = ((VNTag *)tag)->vblob.size; + memcpy(t->tag.vblob.blob, ((VNTag *)tag)->vblob.blob, ((VNTag *)tag)->vblob.size); + break; + } + + count = vs_get_subscript_count(((VSTagGroup *) node->tag_groups)[group_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(((VSTagGroup *) node->tag_groups)[group_id].subscribers, i); + verse_send_tag_create(node_id, group_id, tag_id, name, type, tag); + } + vs_reset_subscript_session(); +} + +static void callback_send_tag_destroy(void *user, VNodeID node_id, uint16 group_id, uint16 tag_id) +{ + VSNodeHead *node; + unsigned int count, i; + if((node = vs_get_node_head(node_id)) == 0) + return; + + count = vs_get_subscript_count(((VSTagGroup *) node->tag_groups)[group_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(((VSTagGroup *) node->tag_groups)[group_id].subscribers, i); + verse_send_tag_destroy(node_id, group_id, tag_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_node_name_set(void *user, VNodeID node_id, char *name) +{ + VSNodeHead *node; + unsigned int count, i; + size_t len; + + if((node = vs_get_node_head(node_id)) == 0) + return; + len = strlen(name); + if(len == 0) + return; + free(node->name); + len++; + node->name = malloc(len); + v_strlcpy(node->name, name, len); + count = vs_get_subscript_count(node->subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->subscribers, i); + verse_send_node_name_set(node_id, name); + } + vs_reset_subscript_session(); +} + +extern void vs_o_subscribe(VSNodeHead *node); +extern void vs_g_subscribe(VSNodeHead *node); +extern void vs_m_subscribe(VSNodeHead *node); +extern void vs_b_subscribe(VSNodeHead *node); +extern void vs_t_subscribe(VSNodeHead *node); +extern void vs_c_subscribe(VSNodeHead *node); +extern void vs_a_subscribe(VSNodeHead *node); + +static void callback_send_node_subscribe(void *user, VNodeID node_id) +{ + unsigned int i; + VSNodeHead *node; + + if((node = vs_get_node_head(node_id)) == NULL) + return; + switch(node->type) + { + case V_NT_OBJECT : + vs_o_subscribe(node); + break; + case V_NT_GEOMETRY : + vs_g_subscribe(node); + break; + case V_NT_MATERIAL : + vs_m_subscribe(node); + break; + case V_NT_BITMAP : + vs_b_subscribe(node); + break; + case V_NT_TEXT: + vs_t_subscribe(node); + break; + case V_NT_CURVE: + vs_c_subscribe(node); + break; + case V_NT_AUDIO: + vs_a_subscribe(node); + break; + default: + fprintf(stderr, "Not subscribing to node type %d\n", node->type); + } + verse_send_node_name_set(node->id, node->name); + for(i = 0; i < node->group_count; i++) + if(((VSTagGroup *)node->tag_groups)[i].group_name[0] != 0) + verse_send_tag_group_create(node->id, (uint16)i, ((VSTagGroup *)node->tag_groups)[i].group_name); + vs_add_new_subscriptor(node->subscribers); +} + +extern void vs_o_unsubscribe(VSNodeHead *node); +extern void vs_g_unsubscribe(VSNodeHead *node); +extern void vs_m_unsubscribe(VSNodeHead *node); +extern void vs_b_unsubscribe(VSNodeHead *node); +extern void vs_t_unsubscribe(VSNodeHead *node); +extern void vs_c_unsubscribe(VSNodeHead *node); +extern void vs_a_unsubscribe(VSNodeHead *node); + +static void callback_send_node_unsubscribe(void *user, VNodeID node_id) +{ + VSNodeHead *node; + + if((node = vs_get_node_head(node_id)) == NULL) + return; + vs_remove_subscriptor(node->subscribers); + + switch(node->type) + { + case V_NT_OBJECT : + vs_o_unsubscribe(node); + break; + case V_NT_GEOMETRY : + vs_g_unsubscribe(node); + break; + case V_NT_MATERIAL : + vs_m_unsubscribe(node); + break; + case V_NT_BITMAP : + vs_b_unsubscribe(node); + break; + case V_NT_TEXT: + vs_t_unsubscribe(node); + break; + case V_NT_CURVE: + vs_c_unsubscribe(node); + break; + case V_NT_AUDIO: + vs_a_unsubscribe(node); + break; + default: + fprintf(stderr, "Not unsubscribing from node type %d\n", node->type); + } +} + +void vs_h_callback_init(void) +{ + verse_callback_set(verse_send_tag_group_create, callback_send_tag_group_create, NULL); + verse_callback_set(verse_send_tag_group_destroy, callback_send_tag_group_destroy, NULL); + verse_callback_set(verse_send_tag_group_subscribe, callback_send_tag_group_subscribe, NULL); + verse_callback_set(verse_send_tag_group_unsubscribe, callback_send_tag_group_unsubscribe, NULL); + verse_callback_set(verse_send_tag_create, callback_send_tag_create, NULL); + verse_callback_set(verse_send_tag_destroy, callback_send_tag_destroy, NULL); + verse_callback_set(verse_send_node_name_set, callback_send_node_name_set, NULL); + verse_callback_set(verse_send_node_subscribe, callback_send_node_subscribe, NULL); + verse_callback_set(verse_send_node_unsubscribe, callback_send_node_unsubscribe, NULL); +} + +#endif diff --git a/extern/verse/dist/vs_node_material.c b/extern/verse/dist/vs_node_material.c new file mode 100644 index 00000000000..b22c070e348 --- /dev/null +++ b/extern/verse/dist/vs_node_material.c @@ -0,0 +1,116 @@ +/* +** +*/ + +#include +#include + +#include "v_cmd_gen.h" + +#if !defined V_GENERATE_FUNC_MODE + +#include "verse.h" +#include "vs_server.h" + +typedef struct { + VNMFragmentType type; + VMatFrag frag; +} VSMatFrag; + +typedef struct{ + VSNodeHead head; + VSMatFrag *frag; + unsigned int frag_count; +} VSNodeMaterial; + +VSNodeMaterial * vs_m_create_node(unsigned int owner) +{ + VSNodeMaterial *node; + char name[48]; + node = malloc(sizeof *node); + vs_add_new_node(&node->head, V_NT_MATERIAL); + sprintf(name, "Material_Node_%u", node->head.id); + create_node_head(&node->head, name, owner); + node->frag = NULL; + node->frag_count = 0; + return node; +} + +void vs_m_destroy_node(VSNodeMaterial *node) +{ + destroy_node_head(&node->head); + free(node->frag); + free(node); +} + +void vs_m_subscribe(VSNodeMaterial *node) +{ + uint16 i; + for(i = 0; i < node->frag_count; i++) + if(node->frag[i].type <= VN_M_FT_OUTPUT) + verse_send_m_fragment_create(node->head.id, (uint16)i, (uint8)node->frag[i].type, &node->frag[i].frag); +} + +void vs_m_unsubscribe(VSNodeMaterial *node) +{ +} + +static void callback_send_m_fragment_create(void *user, VNodeID node_id, VNMFragmentID frag_id, uint8 type, VMatFrag *fragment) +{ + unsigned int count; + uint16 i; + VSNodeMaterial *node; + node = (VSNodeMaterial *)vs_get_node(node_id, V_NT_MATERIAL); + if(node == NULL) + return; + if(node->frag_count + 32 < frag_id) + frag_id = (uint16)-1; + if(frag_id == (uint16) ~0u) + for(frag_id = 0; frag_id < node->frag_count && node->frag[frag_id].type < VN_M_FT_OUTPUT + 1; frag_id++) + ; + if(frag_id >= node->frag_count) + { + node->frag = realloc(node->frag, (sizeof *node->frag) * (node->frag_count + 32)); + for(i = node->frag_count; i < (node->frag_count + 32); i++) + node->frag[i].type = 255; + node->frag_count += 32; + } + node->frag[frag_id].type = type; + node->frag[frag_id].frag = *fragment; + + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_m_fragment_create(node_id, frag_id, type, fragment); + } + vs_reset_subscript_session(); +} + +static void callback_send_m_fragment_destroy(void *user, VNodeID node_id, VNMFragmentID frag_id) +{ + unsigned int count, i; + VSNodeMaterial *node; + node = (VSNodeMaterial *)vs_get_node(node_id, V_NT_MATERIAL); + printf("callback_send_m_fragment_destroy %p\n", node); + if(node == NULL) + return; + if(node->frag_count <= frag_id || node->frag[frag_id].type > VN_M_FT_OUTPUT) + return; + node->frag[frag_id].type = 255; + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_m_fragment_destroy(node_id, frag_id); + } + vs_reset_subscript_session(); +} + +void vs_m_callback_init(void) +{ + verse_callback_set(verse_send_m_fragment_create, callback_send_m_fragment_create, NULL); + verse_callback_set(verse_send_m_fragment_destroy, callback_send_m_fragment_destroy, NULL); +} + +#endif diff --git a/extern/verse/dist/vs_node_object.c b/extern/verse/dist/vs_node_object.c new file mode 100644 index 00000000000..d269a8ddb99 --- /dev/null +++ b/extern/verse/dist/vs_node_object.c @@ -0,0 +1,837 @@ +/* +** +*/ + +#include +#include + +#include "v_cmd_gen.h" + +#if !defined V_GENERATE_FUNC_MODE + +#include "verse.h" +#include "v_util.h" +#include "vs_server.h" + +extern void verse_send_o_link_set(VNodeID node_id, uint16 link_id, VNodeID link, const char *name, uint32 target_id); +extern void verse_send_o_link_destroy(VNodeID node_id, uint16 link_id); + +typedef struct { + VNodeID link; + char name[16]; + uint32 target_id; + /* Animation parameters. */ + uint32 time_s; + uint32 time_f; + uint32 dimensions; + real64 pos[4]; + real64 speed[4]; + real64 accel[4]; + real64 scale[4]; + real64 scale_speed[4]; +} VSLink; + +typedef struct { + char name[16]; + uint8 param_count; + VNOParamType *param_types; + char *param_names; +} VSMethod; + +typedef struct { + char name[VN_O_METHOD_GROUP_NAME_SIZE]; + VSMethod *methods; + unsigned int method_count; + VSSubscriptionList *subscribers; +} VSMethodGroup; + +typedef struct { + real64 position[3]; + VNQuat64 rotation; + real64 scale[3]; +/* VSSubscriptionList *subscribers;*/ +} VSTransform; + +typedef struct { + VSNodeHead head; + VSTransform transform; + VSSubscriptionList *trans_sub64; + VSSubscriptionList *trans_sub32; + real64 light[3]; + VSMethodGroup *groups; + uint16 group_count; + VSLink *links; + uint16 link_count; + boolean hidden; +} VSNodeObject; + +VSNodeObject * vs_o_create_node(unsigned int owner) +{ + VSNodeObject *node; + unsigned int i, j; + char name[48]; + node = malloc(sizeof *node); + vs_add_new_node(&node->head, V_NT_OBJECT); + sprintf(name, "Object_Node_%u", node->head.id); + create_node_head(&node->head, name, owner); + node->trans_sub64 = vs_create_subscription_list(); + node->trans_sub32 = vs_create_subscription_list(); + node->transform.position[0] = node->transform.position[1] = node->transform.position[2] = 0; + node->transform.rotation.x = node->transform.rotation.y = node->transform.rotation.z = 0.0; + node->transform.rotation.w = 1.0; + node->transform.scale[0] = node->transform.scale[1] = node->transform.scale[2] = 1.0; + node->light[0] = node->light[1] = node->light[2] = V_REAL64_MAX; + node->groups = malloc((sizeof *node->groups) * 16); + node->group_count = 16; + for(i = 0; i < 16; i++) + { + node->groups[i].name[0] = 0; + node->groups[i].methods = NULL; + node->groups[i].method_count = 0; + node->groups[i].subscribers = NULL; + } + + node->link_count = 16; + node->links = malloc((sizeof *node->links) * node->link_count); + for(i = 0; i < node->link_count; i++) + { + node->links[i].link = -1; + node->links[i].name[0] = 0; + node->links[i].target_id = -1; + node->links[i].dimensions = 0; + for(j = 0; j < 4; j++) + { + node->links[i].pos[j] = 0.0; + node->links[i].speed[j] = 0.0; + node->links[i].accel[j] = 0.0; + node->links[i].scale[j] = 0.0; + node->links[i].scale_speed[j] = 0.0; + } + } + node->hidden = FALSE; + return node; +} + +void vs_o_destroy_node(VSNodeObject *node) +{ + unsigned int i, j; + destroy_node_head(&node->head); + for(i = 0; i < node->group_count; i++) + { + if(node->groups[i].name[0] != 0) + { + for(j = 0; j < node->groups[i].method_count; j++) + { + if(node->groups[i].methods[j].name[0] != 0 && node->groups[i].methods[j].param_count != 0) + { + free(node->groups[i].methods[j].param_types); + free(node->groups[i].methods[j].param_names); + } + } + if(node->groups[i].methods != NULL) + free(node->groups[i].methods); + } + } + free(node->groups); + free(node); +} + +void vs_o_subscribe(VSNodeObject *node) +{ + unsigned int i; + for(i = 0; i < node->link_count; i++) + { + const VSLink *lnk = node->links + i; + + if(lnk->name[0] != 0) + { + verse_send_o_link_set(node->head.id, i, lnk->link, lnk->name, lnk->target_id); + if(lnk->dimensions != 0) + { + verse_send_o_anim_run(node->head.id, i, lnk->time_s, lnk->time_f, lnk->dimensions, + lnk->pos, lnk->speed, lnk->accel, + lnk->scale, lnk->scale_speed); + } + } + } + if(node->light[0] != V_REAL64_MAX || node->light[1] != V_REAL64_MAX || node->light[2] != V_REAL64_MAX) + verse_send_o_light_set(node->head.id, node->light[0], node->light[1], node->light[2]); + for(i = 0; i < node->group_count; i++) + { + if(node->groups[i].name[0] != 0) + verse_send_o_method_group_create(node->head.id, i, node->groups[i].name); + } + if(node->hidden) + verse_send_o_hide(node->head.id, TRUE); +} + +void vs_o_unsubscribe(VSNodeObject *node) +{ + unsigned int i; + for(i = 0; i < node->group_count; i++) + if(node->groups[i].name[0] != 0) + vs_remove_subscriptor(node->groups[i].subscribers); + vs_remove_subscriptor(node->trans_sub64); + vs_remove_subscriptor(node->trans_sub32); +} + +static void callback_send_o_transform_pos_real32(void *user, VNodeID node_id, uint32 time_s, uint32 time_f, real32 *pos, real32 *speed, real32 *accelerate, real32 *drag_normal, real32 drag) +{ + VSNodeObject *node; + unsigned int i, count; + + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL) + return; + node->transform.position[0] = pos[0]; + node->transform.position[1] = pos[1]; + node->transform.position[2] = pos[2]; + + if((count = vs_get_subscript_count(node->trans_sub64)) > 0) /* Anyone listening at 64 bits? */ + { + real64 spd[3], acc[3], drn[3], *pspd = NULL, *pacc = NULL, *pdrn = NULL; + + pspd = (speed != NULL) ? spd : NULL; + pacc = (accelerate != NULL) ? acc : NULL; + pdrn = (drag_normal != NULL) ? drn : NULL; + /* Convert non-position values to 64-bit. */ + for(i = 0; i < 3; i++) + { + if(speed != NULL) + spd[i] = speed[i]; + if(accelerate != NULL) + acc[i] = accelerate[i]; + if(drag_normal != NULL) + drn[i] = drag_normal[i]; + } + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->trans_sub64, i); + verse_send_o_transform_pos_real64(node_id, time_s, time_f, node->transform.position, pspd, pacc, pdrn, drag); + } + } + count = vs_get_subscript_count(node->trans_sub32); + for(i = 0; i < count; i++) + { + + vs_set_subscript_session(node->trans_sub32, i); + verse_send_o_transform_pos_real32(node_id, time_s, time_f, pos, speed, accelerate, drag_normal, drag); + } + vs_reset_subscript_session(); +} + +static void callback_send_o_transform_rot_real32(void *user, VNodeID node_id, uint32 time_s, uint32 time_f, const VNQuat32 *rot, + const VNQuat32 *speed, const VNQuat32 *accelerate, const VNQuat32 *drag_normal, real32 drag) +{ + VSNodeObject *node; + unsigned int i, count; + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL) + return; + node->transform.rotation.x = rot->x; + node->transform.rotation.y = rot->y; + node->transform.rotation.z = rot->z; + node->transform.rotation.w = rot->w; + if((count = vs_get_subscript_count(node->trans_sub64)) > 0) + { + VNQuat64 spd, acc, drn, *p[3]; + + /* Convert 32-bit quaternions to 64-bit. Converter handles NULLs, has nice return semantics. */ + p[0] = v_quat64_from_quat32(&spd, speed); + p[1] = v_quat64_from_quat32(&acc, accelerate); + p[2] = v_quat64_from_quat32(&drn, drag_normal); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->trans_sub64, i); + verse_send_o_transform_rot_real64(node_id, time_s, time_f, &node->transform.rotation, p[0], p[1], p[2], drag); + } + } + count = vs_get_subscript_count(node->trans_sub32); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->trans_sub32, i); + verse_send_o_transform_rot_real32(node_id, time_s, time_f, rot, speed, accelerate, drag_normal, drag); + } + vs_reset_subscript_session(); +} + + +static void callback_send_o_transform_scale_real32(void *user, VNodeID node_id, real32 scale_x, real32 scale_y, real32 scale_z) +{ + VSNodeObject *node; + unsigned int i, count; + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL) + return; + node->transform.scale[0] = scale_x; + node->transform.scale[1] = scale_y; + node->transform.scale[2] = scale_z; + count = vs_get_subscript_count(node->trans_sub64); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->trans_sub64, i); + verse_send_o_transform_scale_real64(node_id, scale_x, scale_y, scale_z); + } + count = vs_get_subscript_count(node->trans_sub32); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->trans_sub32, i); + verse_send_o_transform_scale_real32(node_id, scale_x, scale_y, scale_z); + } + vs_reset_subscript_session(); +} + +static void callback_send_o_transform_pos_real64(void *user, VNodeID node_id, uint32 time_s, uint32 time_f, const real64 *pos, + const real64 *speed, const real64 *accelerate, const real64 *drag_normal, real64 drag) +{ + VSNodeObject *node; + unsigned int i, count; + + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL) + return; + node->transform.position[0] = pos[0]; + node->transform.position[1] = pos[1]; + node->transform.position[2] = pos[2]; + count = vs_get_subscript_count(node->trans_sub64); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->trans_sub64, i); + verse_send_o_transform_pos_real64(node_id, time_s, time_f, node->transform.position, speed, accelerate, drag_normal, drag); + } + if((count = vs_get_subscript_count(node->trans_sub32)) > 0) /* Anyone listening at 32 bits? */ + { + real32 ps[3], spd[3], acc[3], drn[3], *p[] = { NULL, NULL, NULL }; + + ps[0] = pos[0]; + ps[1] = pos[1]; + ps[2] = pos[2]; + if(speed != NULL) + { + p[0] = spd; + spd[0] = speed[0]; + spd[1] = speed[1]; + spd[2] = speed[2]; + } + else + p[0] = NULL; + if(accelerate != NULL) + { + p[1] = acc; + acc[0] = accelerate[0]; + acc[1] = accelerate[1]; + acc[2] = accelerate[2]; + } + else + p[1] = NULL; + if(drag_normal != NULL) + { + p[1] = drn; + drn[0] = drag_normal[0]; + drn[1] = drag_normal[1]; + drn[2] = drag_normal[2]; + } + else + p[2] = NULL; + + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->trans_sub32, i); + verse_send_o_transform_pos_real32(node_id, time_s, time_f, ps, p[0], p[1], p[2], (real32) drag); + } + } + vs_reset_subscript_session(); +} + +static void callback_send_o_transform_rot_real64(void *user, VNodeID node_id, uint32 time_s, uint32 time_f, const VNQuat64 *rot, + const VNQuat64 *speed, const VNQuat64 *accelerate, const VNQuat64 *drag_normal, real64 drag) +{ + VSNodeObject *node; + unsigned int i, count; + + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL) + return; + node->transform.rotation = *rot; + count = vs_get_subscript_count(node->trans_sub64); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->trans_sub64, i); + verse_send_o_transform_rot_real64(node_id, time_s, time_f, &node->transform.rotation, speed, accelerate, drag_normal, drag); + } + if((count = vs_get_subscript_count(node->trans_sub32)) > 0) /* Anyone listening at 32 bits? */ + { + VNQuat32 rt, spd, acc, drn, *p[3]; + + v_quat32_from_quat64(&rt, rot); + p[0] = v_quat32_from_quat64(&spd, speed); + p[1] = v_quat32_from_quat64(&acc, accelerate); + p[2] = v_quat32_from_quat64(&drn, drag_normal); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->trans_sub32, i); + verse_send_o_transform_rot_real32(node_id, time_s, time_f, &rt, p[0], p[1], p[2], (real32) drag); + } + } + vs_reset_subscript_session(); +} + +static void callback_send_o_transform_scale_real64(void *user, VNodeID node_id, real64 scale_x, real64 scale_y, real64 scale_z) +{ + VSNodeObject *node; + unsigned int i, count; + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL) + return; + node->transform.scale[0] = scale_x; + node->transform.scale[1] = scale_y; + node->transform.scale[2] = scale_z; + count = vs_get_subscript_count(node->trans_sub64); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->trans_sub64, i); + verse_send_o_transform_scale_real64(node_id, scale_x, scale_y, scale_z); + } + count = vs_get_subscript_count(node->trans_sub32); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->trans_sub32, i); + verse_send_o_transform_scale_real32(node_id, (real32) scale_x, (real32) scale_y, (real32) scale_z); + } + vs_reset_subscript_session(); +} + +static void callback_send_o_transform_subscribe(void *user, VNodeID node_id, VNRealFormat type) +{ + VSNodeObject *node; + uint32 time_s, time_f; + + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL) + return; + verse_session_get_time(&time_s, &time_f); + if(type == VN_FORMAT_REAL32) + { + real32 tpos[3]; + VNQuat32 rot; + + vs_add_new_subscriptor(node->trans_sub32); + tpos[0] = node->transform.position[0]; + tpos[1] = node->transform.position[1]; + tpos[2] = node->transform.position[2]; + verse_send_o_transform_pos_real32(node_id, time_s, time_f, tpos, NULL, NULL, NULL, 0.0f); + v_quat32_from_quat64(&rot, &node->transform.rotation); + verse_send_o_transform_rot_real32(node_id, time_s, time_f, &rot, NULL, NULL, NULL, 0.0f); + verse_send_o_transform_scale_real32(node_id, (real32) node->transform.scale[0], (real32) node->transform.scale[1], (real32) node->transform.scale[2]); + } + else + { + vs_add_new_subscriptor(node->trans_sub64); + verse_send_o_transform_pos_real64(node_id, time_s, time_f, node->transform.position, NULL, NULL, NULL, 0); + verse_send_o_transform_rot_real64(node_id, time_s, time_f, &node->transform.rotation, NULL, NULL, NULL, 0); + verse_send_o_transform_scale_real64(node_id, node->transform.scale[0], node->transform.scale[1], node->transform.scale[2]); + } +} + +static void callback_send_o_transform_unsubscribe(void *user, VNodeID node_id, VNRealFormat type) +{ + VSNodeObject *node; + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL) + return; + if(type == VN_FORMAT_REAL32) + vs_remove_subscriptor(node->trans_sub32); + else + vs_remove_subscriptor(node->trans_sub64); +} + +static void callback_send_o_light_set(void *user, VNodeID node_id, real64 light_r, real64 light_g, real64 light_b) +{ + VSNodeObject *node; + unsigned int i, count; + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL) + return; + node->light[0] = light_r; + node->light[1] = light_g; + node->light[2] = light_b; + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_o_light_set(node_id, light_r, light_g, light_b); + } + vs_reset_subscript_session(); +} + +static void callback_send_o_link_set(void *user, VNodeID node_id, uint16 link_id, VNodeID link, const char *name, uint32 target_id) +{ + VSNodeObject *node; + unsigned int i, count; + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + + if(node == NULL) + return; + + if(name[0] == 0) + return; + if(vs_get_node_head(link) == 0) + link = 0; + + if(link_id >= node->link_count || node->links[link_id].name[0] == 0) + { + for(link_id = 0; link_id < node->link_count && node->links[link_id].name[0] != 0; link_id++); + + if(link_id == node->link_count) + { + i = node->link_count; + node->link_count += 16; + node->links = realloc(node->links, (sizeof *node->links) * node->link_count); + for(; i < node->link_count; i++) + { + node->links[i].name[0] = 0; + node->links[i].dimensions = 0; + } + } + } + + node->links[link_id].link = link; + for(i = 0; i < 15 && name[i] != 0; i++) + node->links[link_id].name[i] = name[i]; + node->links[link_id].name[i] = 0; + node->links[link_id].target_id = target_id; + + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_o_link_set(node_id, link_id, link, name, target_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_o_link_destroy(void *user, VNodeID node_id, uint16 link_id) +{ + VSNodeObject *node; + unsigned int i, count; + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL) + return; + + if(link_id >= node->link_count || node->links[link_id].name[0] == 0) + return; + + node->links[link_id].name[0] = 0; + + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_o_link_destroy(node_id, link_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_o_method_group_create(void *user, VNodeID node_id, uint16 group_id, char *name) +{ + VSNodeObject *node; + unsigned int i, j, count; + + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL || vs_get_node(node_id, V_NT_OBJECT) == NULL) + return; + + for(i = 0; i < node->group_count; i++) + { + for(j = 0; node->groups[i].name[j] == name[j] && node->groups[i].name[j] != 0; j++); + if(node->groups[i].name[j] == name[j]) + return; + } + if(group_id >= node->group_count || node->groups[group_id].name[0] == 0) + { + for(group_id = 0; group_id < node->group_count && node->groups[group_id].name[0] != 0; group_id++) + if(group_id == node->group_count) + { + node->groups = realloc(node->groups, sizeof(*node->groups) * (node->group_count + 16)); + for(i = node->group_count; i < node->group_count + 16u; i++) + { + node->groups[i].name[0] = 0; + node->groups[i].methods = NULL; + node->groups[i].method_count = 0; + } + node->group_count += 16; + } + node->groups[group_id].subscribers = vs_create_subscription_list(); + } + for(i = 0; i < 15 && name[i] != 0; i++) + node->groups[group_id].name[i] = name[i]; + node->groups[group_id].name[i] = 0; + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_o_method_group_create(node_id, group_id, name); + } + vs_reset_subscript_session(); +} + +static void callback_send_o_method_group_destroy(void *user, VNodeID node_id, uint16 group_id) +{ + VSNodeObject *node; + unsigned int i, count; + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL || vs_get_node(node_id, V_NT_OBJECT) == NULL) + return; + + if(group_id >= node->group_count || node->groups[group_id].name[0] == 0) + return; + node->groups[group_id].name[0] = 0; + for(i = 0; i < node->groups[group_id].method_count; i++) + { + if(node->groups[group_id].methods[i].name[0] != 0 && node->groups[group_id].methods[i].param_count > 0) + { + free(node->groups[group_id].methods[i].param_names); + free(node->groups[group_id].methods[i].param_types); + } + } + free(node->groups[group_id].methods); + node->groups[group_id].methods = NULL; + node->groups[group_id].method_count = 0; + vs_destroy_subscription_list(node->groups[group_id].subscribers); + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_o_method_group_destroy(node_id, group_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_o_method_group_subscribe(void *user, VNodeID node_id, uint16 group_id) +{ + VSNodeObject *node; + unsigned int i, j; + + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL || vs_get_node(node_id, V_NT_OBJECT) == NULL) + return; + if(group_id < node->group_count && node->groups[group_id].name[0] != 0) + vs_add_new_subscriptor(node->groups[group_id].subscribers); + for(i = 0; i < node->groups[group_id].method_count; i++) + { + if(node->groups[group_id].methods[i].name[0] != 0) + { + char *names[255]; + for(j = 0; j < node->groups[group_id].methods[i].param_count; j++) + names[j] = &node->groups[group_id].methods[i].param_names[j * 16]; + verse_send_o_method_create(node_id, group_id, i, node->groups[group_id].methods[i].name, node->groups[group_id].methods[i].param_count, node->groups[group_id].methods[i].param_types, (const char **) names); + } + } +} + +static void callback_send_o_method_group_unsubscribe(void *user, VNodeID node_id, uint16 group_id) +{ + VSNodeObject *node; + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL || vs_get_node(node_id, V_NT_OBJECT) == NULL) + return; + if(group_id < node->group_count && node->groups[group_id].name[0] != 0) + vs_remove_subscriptor(node->groups[group_id].subscribers); +} + +static void callback_send_o_method_create(void *user, VNodeID node_id, uint16 group_id, uint16 method_id, char *name, uint8 param_count, VNOParamType *param_types, char * *param_names) +{ + VSNodeObject *node; + unsigned int i, j, count; + VSMethodGroup *group; + + node = (VSNodeObject *) vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL || vs_get_node(node_id, V_NT_OBJECT) == NULL) + return; + if(group_id >= node->group_count || node->groups[group_id].name[0] == 0) + return; + group = &node->groups[group_id]; + for(i = 0; i < group->method_count; i++) + { + if(i != method_id) + { + for(j = 0; group->methods[i].name[j] == name[j] && group->methods[i].name[j] != 0; j++); + if(group->methods[i].name[j] == name[j]) + return; + } + } + if(method_id < group->method_count && group->methods[method_id].name[0] != 0) + { + for(i = 0; i < 16; i++) + group->methods[method_id].name[i] = name[i]; + if(group->methods[method_id].param_count != 0) + { + free(group->methods[method_id].param_names); + free(group->methods[method_id].param_types); + } + }else + { + for(method_id = 0; method_id < group->method_count && group->methods[method_id].name[0] != 0; method_id++); + if(method_id == group->method_count) + { + group->methods = realloc(group->methods, sizeof(*group->methods) * (group->method_count + 16)); + for(i = group->method_count; i < group->method_count + 16; i++) + group->methods[i].name[0] = 0; + group->method_count += 16; + } + } + for(i = 0; i < VN_O_METHOD_NAME_SIZE && name[i] != 0; i++) + group->methods[method_id].name[i] = name[i]; + group->methods[method_id].name[i] = '\0'; + group->methods[method_id].param_count = param_count; + if(param_count > 0) + { + group->methods[method_id].param_types = malloc((sizeof *group->methods[method_id].param_types) * param_count); + group->methods[method_id].param_names = malloc((sizeof *group->methods[method_id].param_names) * param_count * 16); + } + for(i = 0; i < param_count; i++) + { + group->methods[method_id].param_types[i] = param_types[i]; + for(j = 0; j < 15 && param_names[i][j] != 0; j++) + group->methods[method_id].param_names[i * 16 + j] = param_names[i][j]; + group->methods[method_id].param_names[i * 16 + j] = 0; + } + count = vs_get_subscript_count(node->groups[group_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->groups[group_id].subscribers, i); + verse_send_o_method_create(node_id, group_id, method_id, name, param_count, param_types, (const char **) param_names); + } + vs_reset_subscript_session(); +} + +static void callback_send_o_method_destroy(void *user, VNodeID node_id, uint16 group_id, uint16 method_id) +{ + VSNodeObject *node; + unsigned int i, count; + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL || vs_get_node(node_id, V_NT_OBJECT) == NULL) + return; + if(group_id >= node->group_count || node->groups[group_id].name[0] == 0 || method_id >= node->groups[group_id].method_count || node->groups[group_id].methods[method_id].name[0] == 0) + return; + + node->groups[group_id].methods[method_id].name[0] = 0; + if(node->groups[group_id].methods[method_id].param_count != 0) + { + free(node->groups[group_id].methods[method_id].param_names); + free(node->groups[group_id].methods[method_id].param_types); + } + count = vs_get_subscript_count(node->groups[group_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->groups[group_id].subscribers, i); + verse_send_o_method_destroy(node_id, group_id, method_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_o_method_call(void *user, VNodeID node_id, uint16 group_id, uint16 method_id, VNodeID sender, void *params) +{ + VNOParam unpacked_params[255]; + void *data; + VSNodeObject *node; + unsigned int i, count; + + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL || vs_get_node(node_id, V_NT_OBJECT) == NULL) + return; + + if(group_id >= node->group_count || node->groups[group_id].name[0] == 0 || method_id >= node->groups[group_id].method_count || node->groups[group_id].methods[method_id].name[0] == 0) + return; + if(!verse_method_call_unpack(params, node->groups[group_id].methods[method_id].param_count, node->groups[group_id].methods[method_id].param_types, unpacked_params)) + return; + sender = vs_get_avatar(); + count = vs_get_subscript_count(node->groups[group_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->groups[group_id].subscribers, i); + data = verse_method_call_pack(node->groups[group_id].methods[method_id].param_count, node->groups[group_id].methods[method_id].param_types, unpacked_params); + if(data != NULL) + verse_send_o_method_call(node_id, group_id, method_id, sender, data); + } + vs_reset_subscript_session(); +} + +static void callback_send_o_anim_run(void *user, VNodeID node_id, uint16 link_id, uint32 time_s, uint32 time_f, uint8 dimensions, real64 *pos, + real64 *speed, real64 *accel, real64 *scale, real64 *scale_speed) +{ + VSNodeObject *node; + unsigned int i, count; + + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL) + return; + if(link_id >= node->link_count || node->links[link_id].name[0] == 0) + return; + if(NULL == vs_get_node(node->links[link_id].link, V_NT_CURVE)) + return; + node->links[link_id].time_s = time_s; + node->links[link_id].time_f = time_f; + node->links[link_id].dimensions = dimensions; + for(i = 0; i < dimensions && i < 4; i++) + { + node->links[link_id].pos[i] = pos[i]; + node->links[link_id].speed[i] = speed[i]; + node->links[link_id].accel[i] = accel[i]; + node->links[link_id].scale[i] = scale[i]; + node->links[link_id].scale_speed[i] = scale_speed[i]; + } + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_o_anim_run(node_id, link_id, time_s, time_f, dimensions, pos, speed, accel, scale, scale_speed); + } + vs_reset_subscript_session(); +} + +static void callback_send_o_hide(void *user, VNodeID node_id, uint8 hidden) +{ + VSNodeObject *node; + unsigned int i, count; + + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL || hidden == node->hidden) + return; + node->hidden = hidden; + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_o_hide(node_id, hidden); + } + vs_reset_subscript_session(); +} + +void vs_o_callback_init(void) +{ + + verse_callback_set(verse_send_o_transform_pos_real32, callback_send_o_transform_pos_real32, NULL); + verse_callback_set(verse_send_o_transform_rot_real32, callback_send_o_transform_rot_real32, NULL); + verse_callback_set(verse_send_o_transform_scale_real32, callback_send_o_transform_scale_real32, NULL); + verse_callback_set(verse_send_o_transform_pos_real64, callback_send_o_transform_pos_real64, NULL); + verse_callback_set(verse_send_o_transform_rot_real64, callback_send_o_transform_rot_real64, NULL); + verse_callback_set(verse_send_o_transform_scale_real64, callback_send_o_transform_scale_real64, NULL); + verse_callback_set(verse_send_o_transform_subscribe, callback_send_o_transform_subscribe, NULL); + verse_callback_set(verse_send_o_transform_unsubscribe, callback_send_o_transform_unsubscribe, NULL); + verse_callback_set(verse_send_o_link_set, callback_send_o_link_set, NULL); + verse_callback_set(verse_send_o_light_set, callback_send_o_light_set, NULL); + verse_callback_set(verse_send_o_link_set, callback_send_o_link_set, NULL); + verse_callback_set(verse_send_o_link_destroy, callback_send_o_link_destroy, NULL); + verse_callback_set(verse_send_o_method_group_create, callback_send_o_method_group_create, NULL); + verse_callback_set(verse_send_o_method_group_destroy, callback_send_o_method_group_destroy, NULL); + verse_callback_set(verse_send_o_method_group_subscribe, callback_send_o_method_group_subscribe, NULL); + verse_callback_set(verse_send_o_method_group_unsubscribe, callback_send_o_method_group_unsubscribe, NULL); + verse_callback_set(verse_send_o_method_create, callback_send_o_method_create, NULL); + verse_callback_set(verse_send_o_method_destroy, callback_send_o_method_destroy, NULL); + verse_callback_set(verse_send_o_method_call, callback_send_o_method_call, NULL); + verse_callback_set(verse_send_o_anim_run, callback_send_o_anim_run, NULL); + verse_callback_set(verse_send_o_hide, callback_send_o_hide, NULL); +} + +#endif diff --git a/extern/verse/dist/vs_node_particle.c b/extern/verse/dist/vs_node_particle.c new file mode 100644 index 00000000000..8c7b1ce3c82 --- /dev/null +++ b/extern/verse/dist/vs_node_particle.c @@ -0,0 +1,52 @@ +/* +** +*/ + +#include +#include + +#include "v_cmd_gen.h" + +#if !defined V_GENERATE_FUNC_MODE + +#include "verse.h" +#include "vs_server.h" + +/* +typedef struct { + VSNodeHead head; +} VSNodeObject; + +VSNodeObject *vs_o_create_node(unsigned int owner) +{ + VSNodeObject *node; + node = malloc(sizeof *node); + create_node_head(&node->head, name, owner); + vs_add_new_node(&node->head, V_NT_OBJECT); + return node; +} + +void vs_o_destroy_node(VSNodeObject *node) +{ + destroy_node_head(&node->head); + free(node); +} + +void vs_o_subscribe(VSNodeObject *node) +{ +} + +static void callback_send_o_unsubscribe(void *user, VNodeID node_id) +{ + VSNodeObject *node; + node = (VSNodeObject *)vs_get_node(node_id); + if(node == NULL) + return; + vs_remove_subscriptor(node->head.subscribers); +} + +void vs_o_callback_init(void) +{ +} +*/ +#endif diff --git a/extern/verse/dist/vs_node_storage.c b/extern/verse/dist/vs_node_storage.c new file mode 100644 index 00000000000..480ceb1f900 --- /dev/null +++ b/extern/verse/dist/vs_node_storage.c @@ -0,0 +1,245 @@ +/* +** +*/ + +#include +#include +#include "v_cmd_gen.h" + +#if !defined V_GENERATE_FUNC_MODE + +#include "verse.h" +#include "vs_server.h" + +#define VS_NODE_STORAGE_CHUNK_SIZE 16 + +static struct { + VSNodeHead **nodes; + unsigned int node_length; + unsigned int node_allocated; + VSSubscriptionList *list[V_NT_NUM_TYPES]; +} VSNodeStorage; + +extern void callback_send_tag_group_create(void *user, VNodeID node_id, uint16 group_id, const char *name); + +void vs_init_node_storage(void) +{ + unsigned int i; + VSNodeStorage.nodes = malloc((sizeof *VSNodeStorage.nodes) * VS_NODE_STORAGE_CHUNK_SIZE); + VSNodeStorage.nodes[0] = NULL; + VSNodeStorage.node_length = 0; + VSNodeStorage.node_allocated = VS_NODE_STORAGE_CHUNK_SIZE; + for(i = 0; i < V_NT_NUM_TYPES; i++) + VSNodeStorage.list[i] = vs_create_subscription_list(); +} + +unsigned int vs_add_new_node(VSNodeHead *node, VNodeType type) +{ + unsigned int i, j; + for(i = 0; i < VSNodeStorage.node_length && VSNodeStorage.nodes[i] != NULL; i++); + if(i >= VSNodeStorage.node_allocated) + { + j = VSNodeStorage.node_allocated; + VSNodeStorage.node_allocated += VS_NODE_STORAGE_CHUNK_SIZE; + VSNodeStorage.nodes = realloc(VSNodeStorage.nodes, (sizeof *VSNodeStorage.nodes) * VSNodeStorage.node_allocated); + while(j < VSNodeStorage.node_allocated) + VSNodeStorage.nodes[j++] = NULL; + } + VSNodeStorage.nodes[i] = node; + if(i >= VSNodeStorage.node_length) + VSNodeStorage.node_length = i + 1; + node->id = i; + node->type = type; + + return node->id; +} + +VSNodeHead *vs_get_node(unsigned int node_id, VNodeType type) +{ + if(VSNodeStorage.node_length > node_id) + { + VSNodeHead *node = VSNodeStorage.nodes[node_id]; + + if(node != NULL && node->type == type) + return node; + } + return NULL; +} + +VSNodeHead *vs_get_node_head(unsigned int node_id) +{ + if(VSNodeStorage.node_length > node_id) + return VSNodeStorage.nodes[node_id]; + return NULL; +} + +extern VSNodeHead *vs_o_create_node(unsigned int owner); +extern VSNodeHead *vs_g_create_node(unsigned int owner); +extern VSNodeHead *vs_m_create_node(unsigned int owner); +extern VSNodeHead *vs_b_create_node(unsigned int owner); +extern VSNodeHead *vs_t_create_node(unsigned int owner); +extern VSNodeHead *vs_c_create_node(unsigned int owner); +extern VSNodeHead *vs_p_create_node(unsigned int owner); +extern VSNodeHead *vs_a_create_node(unsigned int owner); + +extern void vs_o_destroy_node(VSNodeHead *node); +extern void vs_g_destroy_node(VSNodeHead *node); +extern void vs_m_destroy_node(VSNodeHead *node); +extern void vs_b_destroy_node(VSNodeHead *node); +extern void vs_t_destroy_node(VSNodeHead *node); +extern void vs_c_destroy_node(VSNodeHead *node); +extern void vs_p_destroy_node(VSNodeHead *node); +extern void vs_a_destroy_node(VSNodeHead *node); + + +VNodeID vs_node_create(VNodeID owner_id, unsigned int type) +{ + unsigned int count, i; + VSNodeHead *node; + VNodeID node_id; + + printf("vs_node_create(%u, %u)\n", owner_id, type); + switch(type) + { + case V_NT_OBJECT : + node = vs_o_create_node(owner_id); + break; + case V_NT_GEOMETRY : + node = vs_g_create_node(owner_id); + break; + case V_NT_MATERIAL : + node = vs_m_create_node(owner_id); + break; + case V_NT_BITMAP : + node = vs_b_create_node(owner_id); + break; + case V_NT_TEXT : + node = vs_t_create_node(owner_id); + break; + case V_NT_CURVE : + node = vs_c_create_node(owner_id); + break; + case V_NT_AUDIO : + node = vs_a_create_node(owner_id); + break; + default: + fprintf(stderr, "Can't create node of unknown type %u\n", type); + return 0U; + } + node_id = node->id; + + count = vs_get_subscript_count(VSNodeStorage.list[type]); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(VSNodeStorage.list[type], i); + if(owner_id != verse_session_get_avatar()) + verse_send_node_create(node_id, type, VN_OWNER_OTHER); + else + verse_send_node_create(node_id, type, VN_OWNER_MINE); + } + if(count != 0) + vs_reset_subscript_session(); + return node_id; +} + +/* Initialize an object node into being an avatar. */ +void vs_avatar_init(VNodeID id, const char *name) +{ + callback_send_tag_group_create(NULL, id, (short) ~0u, "avatar"); + /* FIXME: Populate the group, too. */ +} + +void vs_reset_owner(VNodeID owner_id) +{ + unsigned int i; + + for(i = 0; i < VSNodeStorage.node_length; i++) + if(VSNodeStorage.nodes[i] != NULL) + if(VSNodeStorage.nodes[i]->owner == owner_id) + VSNodeStorage.nodes[i]->owner = ~0; +} + +static void callback_send_node_create(void *user_data, VNodeID node_id, uint8 type, VNodeOwner owner_id) +{ + vs_node_create(vs_get_avatar(), type); +} + +void callback_send_node_destroy(void *user_data, VNodeID node_id) +{ + unsigned int count, i; + VSNodeHead *node; + VNodeType type; + node = vs_get_node_head(node_id); + if(node == NULL) + return; + VSNodeStorage.nodes[node_id] = NULL; + type = node->type; + switch(type) + { + case V_NT_OBJECT : + vs_o_destroy_node(node); + break; + case V_NT_GEOMETRY : + vs_g_destroy_node(node); + break; + case V_NT_MATERIAL : + vs_m_destroy_node(node); + break; + case V_NT_BITMAP : + vs_b_destroy_node(node); + break; + case V_NT_TEXT : + vs_t_destroy_node(node); + break; + case V_NT_CURVE : + vs_c_destroy_node(node); + break; + case V_NT_AUDIO : + vs_c_destroy_node(node); + break; + default: + fprintf(stderr, __FILE__ " Can't handle node_destroy for type %d--not implemented", type); + return; + } + count = vs_get_subscript_count(VSNodeStorage.list[type]); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(VSNodeStorage.list[type], i); + verse_send_node_destroy(node_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_node_index_subscribe(void *user_data, uint32 mask) +{ + unsigned int i, j, pow = 1; + + for(i = 0; i < V_NT_NUM_TYPES; i++, pow <<= 1) + { + if((mask & pow) != 0) + { + for(j = 0; j < VSNodeStorage.node_length; j++) + { + if(VSNodeStorage.nodes[j] != NULL && VSNodeStorage.nodes[j]->type == (VNodeType)i) + { + if(VSNodeStorage.nodes[j]->owner == verse_session_get_avatar()) + verse_send_node_create(VSNodeStorage.nodes[j]->id, i, VN_OWNER_MINE); + else + verse_send_node_create(VSNodeStorage.nodes[j]->id, i, VN_OWNER_OTHER); + } + } + vs_add_new_subscriptor(VSNodeStorage.list[i]); + } + else + vs_remove_subscriptor(VSNodeStorage.list[i]); + } +} + +void init_callback_node_storage(void) +{ + verse_callback_set(verse_send_node_index_subscribe, callback_send_node_index_subscribe, NULL); + verse_callback_set(verse_send_node_create, callback_send_node_create, NULL); + verse_callback_set(verse_send_node_destroy, callback_send_node_destroy, NULL); +} + +#endif diff --git a/extern/verse/dist/vs_node_text.c b/extern/verse/dist/vs_node_text.c new file mode 100644 index 00000000000..ae7c3c737c3 --- /dev/null +++ b/extern/verse/dist/vs_node_text.c @@ -0,0 +1,274 @@ +/* +** +*/ + +#include +#include +#include + +#include "v_cmd_gen.h" + +#if !defined V_GENERATE_FUNC_MODE + +#include "verse.h" +#include "vs_server.h" + +#define VS_TEXT_CHUNK_SIZE 4096 + +typedef struct { + char name[16]; + char *text; + size_t length; + size_t allocated; + VSSubscriptionList *subscribers; +} VSTextBuffer; + +typedef struct { + VSNodeHead head; + char language[512]; + VSTextBuffer *buffer; + unsigned int buffer_count; +} VSNodeText; + +VSNodeText * vs_t_create_node(unsigned int owner) +{ + VSNodeText *node; + char name[48]; + unsigned int i; + node = malloc(sizeof *node); + vs_add_new_node(&node->head, V_NT_TEXT); + sprintf(name, "Text_Node_%u", node->head.id); + create_node_head(&node->head, name, owner); + node->language[0] = 0; + node->buffer_count = 16; + node->buffer = malloc((sizeof *node->buffer) * node->buffer_count); + for(i = 0; i < node->buffer_count; i++) + node->buffer[i].name[0] = 0; + + return node; +} + +void vs_t_destroy_node(VSNodeText *node) +{ + unsigned int i; + destroy_node_head(&node->head); + for(i = 0; i < node->buffer_count; i++) + { + if(node->buffer[i].name[0] != 0) + { + free(node->buffer[i].text); + vs_destroy_subscription_list(node->buffer[i].subscribers); + } + } + free(node->buffer); + free(node); +} + +void vs_t_subscribe(VSNodeText *node) +{ + unsigned int i; + verse_send_t_language_set(node->head.id, node->language); + for(i = 0; i < node->buffer_count; i++) + if(node->buffer[i].name[0] != 0) + verse_send_t_buffer_create(node->head.id, i, node->buffer[i].name); +} + +void vs_t_unsubscribe(VSNodeText *node) +{ + unsigned int i; + for(i = 0; i < node->buffer_count; i++) + if(node->buffer[i].name[0] != 0) + vs_remove_subscriptor(node->buffer[i].subscribers); +} + +static void callback_send_t_language_set(void *user, VNodeID node_id, char *language) +{ + VSNodeText *node; + unsigned int i, count; + node = (VSNodeText *)vs_get_node(node_id, V_NT_TEXT); + if(node == NULL) + return; + for(i = 0; i < 511 && language[i]; i++) + node->language[i] = language[i]; + node->language[i] = 0; + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_t_language_set(node_id, language); + } + vs_reset_subscript_session(); + +} + +static void callback_send_t_buffer_create(void *user, VNodeID node_id, VBufferID buffer_id, const char *name) +{ + VSNodeText *node; + unsigned int i, count; + node = (VSNodeText *)vs_get_node(node_id, V_NT_TEXT); + if(node == NULL) + return; + + if(buffer_id >= node->buffer_count || node->buffer[buffer_id].name[0] != 0) + { + for(buffer_id = 0; buffer_id < node->buffer_count && node->buffer[buffer_id].name[0] != 0; buffer_id++) + ; + if(buffer_id == node->buffer_count) + { + node->buffer = realloc(node->buffer, (sizeof *node->buffer) * node->buffer_count); + for(i = node->buffer_count; i < node->buffer_count + 16; i++) + node->buffer[i].name[0] = 0; + node->buffer_count = i; + } + } + + if(node->buffer[buffer_id].name[0] == 0) + { + node->buffer[buffer_id].allocated = VS_TEXT_CHUNK_SIZE; + node->buffer[buffer_id].text = malloc(node->buffer[buffer_id].allocated); + node->buffer[buffer_id].length = 0; + node->buffer[buffer_id].subscribers = vs_create_subscription_list(); + } + for(i = 0; i < 15 && name[i] != 0; i++) + node->buffer[buffer_id].name[i] = name[i]; + node->buffer[buffer_id].name[i] = 0; + + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_t_buffer_create(node_id, buffer_id, name); + } + vs_reset_subscript_session(); +} + +void callback_send_t_buffer_destroy(void *user, VNodeID node_id, VBufferID buffer_id) +{ + VSNodeText *node; + unsigned int i, count; + node = (VSNodeText *)vs_get_node(node_id, V_NT_TEXT); + if(node == NULL) + return; + + if(buffer_id >= node->buffer_count || node->buffer[buffer_id].name[0] == 0) + return; + + node->buffer[buffer_id].name[0] = 0; + free(node->buffer[buffer_id].text); + vs_destroy_subscription_list(node->buffer[buffer_id].subscribers); + + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_t_buffer_destroy(node_id, buffer_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_t_buffer_subscribe(void *user, VNodeID node_id, VBufferID buffer_id) +{ + VSNodeText *node; + unsigned int i; + + node = (VSNodeText *)vs_get_node(node_id, V_NT_TEXT); + if(node == NULL) + return; + if(buffer_id >= node->buffer_count || node->buffer[buffer_id].name[0] == 0) + return; + if(vs_add_new_subscriptor(node->buffer[buffer_id].subscribers) == 0) + return; + for(i = 0; i < node->buffer[buffer_id].length; i += VN_T_MAX_TEXT_CMD_SIZE) + { + if(i + VN_T_MAX_TEXT_CMD_SIZE > node->buffer[buffer_id].length) + verse_send_t_text_set(node_id, buffer_id, i, node->buffer[buffer_id].length - i, &node->buffer[buffer_id].text[i]); + else + verse_send_t_text_set(node_id, buffer_id, i, VN_T_MAX_TEXT_CMD_SIZE, &node->buffer[buffer_id].text[i]); + } +} + +static void callback_send_t_buffer_unsubscribe(void *user, VNodeID node_id, VBufferID buffer_id) +{ + VSNodeText *node; + node = (VSNodeText *)vs_get_node(node_id, V_NT_TEXT); + if(node == NULL) + return; + if(buffer_id >= node->buffer_count || node->buffer[buffer_id].name[0] == 0) + return; + vs_remove_subscriptor(node->buffer[buffer_id].subscribers); +} + +static void callback_send_t_text_set(void *user, VNodeID node_id, VBufferID buffer_id, uint32 pos, uint32 length, const char *text) +{ + VSNodeText *node; + VSTextBuffer *tb; + unsigned int i, count, text_length; + char *buf; + + node = (VSNodeText *) vs_get_node(node_id, V_NT_TEXT); + if(node == NULL) + return; + if(buffer_id >= node->buffer_count || node->buffer[buffer_id].name[0] == 0) + return; + tb = &node->buffer[buffer_id]; + + text_length = strlen(text); + + /* Clamp position and length of deleted region. */ + if(pos > tb->length) + pos = tb->length; + if(pos + length > tb->length) + length = tb->length - pos; + + buf = tb->text; + + if(tb->length + text_length - length > tb->allocated) + { + buf = realloc(buf, tb->length + text_length - length + VS_TEXT_CHUNK_SIZE); + tb->allocated = tb->length + text_length - length + VS_TEXT_CHUNK_SIZE; + } + + if(text_length < length) /* Insert smaller than delete? */ + { + memmove(buf + pos + text_length, buf + pos + length, tb->length - (pos + length)); + memcpy(buf + pos, text, text_length); + } + else /* Insert is larger than delete. */ + { + memmove(buf + pos + text_length, buf + pos + length, tb->length - pos); + memcpy(buf + pos, text, text_length); + } + + tb->length += (int) text_length - length; + buf[tb->length] = '\0'; + + /* Buffer very much larger than content? Then shrink it. */ + if(tb->allocated > VS_TEXT_CHUNK_SIZE * 8 && tb->allocated * 2 > tb->length) + { + buf = realloc(buf, tb->length + VS_TEXT_CHUNK_SIZE); + tb->allocated = tb->length + VS_TEXT_CHUNK_SIZE; + } + + tb->text = buf; + + count = vs_get_subscript_count(tb->subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(tb->subscribers, i); + verse_send_t_text_set(node_id, buffer_id, pos, length, text); + } + vs_reset_subscript_session(); +} + + +void vs_t_callback_init(void) +{ + verse_callback_set(verse_send_t_language_set, callback_send_t_language_set, NULL); + verse_callback_set(verse_send_t_buffer_create, callback_send_t_buffer_create, NULL); + verse_callback_set(verse_send_t_buffer_destroy, callback_send_t_buffer_destroy, NULL); + verse_callback_set(verse_send_t_buffer_subscribe, callback_send_t_buffer_subscribe, NULL); + verse_callback_set(verse_send_t_buffer_unsubscribe, callback_send_t_buffer_unsubscribe, NULL); + verse_callback_set(verse_send_t_text_set, callback_send_t_text_set, NULL); +} + +#endif diff --git a/extern/verse/dist/vs_server.h b/extern/verse/dist/vs_server.h new file mode 100644 index 00000000000..76e1b482eb9 --- /dev/null +++ b/extern/verse/dist/vs_server.h @@ -0,0 +1,62 @@ +/* +** +*/ + +#include + +extern void vs_init_connection_storage(void); +extern void vs_add_new_connection(VSession session, const char *name, const char *pass, VNodeID node_id); +extern void vs_remove_connection(void); +extern void vs_set_next_session(void); + +typedef void VSSubscriptionList; + +extern VSSubscriptionList * vs_create_subscription_list(void); +extern void vs_destroy_subscription_list(VSSubscriptionList *list); +extern int vs_add_new_subscriptor(VSSubscriptionList *list); +extern void vs_remove_subscriptor(VSSubscriptionList *list); +extern unsigned int vs_get_subscript_count(const VSSubscriptionList *list); +extern void vs_set_subscript_session(VSSubscriptionList *list, unsigned int session); +extern void vs_reset_subscript_session(void); +extern uint32 vs_get_avatar(void); +extern VSession vs_get_session(void); +extern const char * vs_get_user_name(void); +extern const char * vs_get_user_pass(void); + + +typedef struct { + VNodeID id; + VNodeType type; + VNodeID owner; + char *name; + void *tag_groups; + uint16 group_count; + VSSubscriptionList *subscribers; +} VSNodeHead; + +extern void vs_init_node_storage(void); +extern uint32 vs_add_new_node(VSNodeHead *node, VNodeType type); +extern VSNodeHead * vs_get_node(unsigned int node_id, VNodeType type); +extern VSNodeHead * vs_get_node_head(unsigned int node_id); + +extern void create_node_head(VSNodeHead *node, const char *name, unsigned int owner); +extern void destroy_node_head(VSNodeHead *node); +extern void vs_send_node_head(VSNodeHead *node); + +extern void vs_h_callback_init(void); /* "Head", not an actual node type. */ +extern void vs_o_callback_init(void); +extern void vs_g_callback_init(void); +extern void vs_m_callback_init(void); +extern void vs_b_callback_init(void); +extern void vs_t_callback_init(void); +extern void vs_c_callback_init(void); +extern void vs_a_callback_init(void); +extern void init_callback_node_storage(void); + +extern void vs_master_set_enabled(boolean enabled); +extern void vs_master_set_address(const char *address); +extern const char * vs_master_get_address(void); +extern void vs_master_set_desc(const char *desc); +extern void vs_master_set_tags(const char *tags); +extern void vs_master_update(void); +extern void vs_master_handle_describe(const char *address, const char *message); diff --git a/extern/verse/make/msvc_7_0/libverse.vcproj b/extern/verse/make/msvc_7_0/libverse.vcproj new file mode 100644 index 00000000000..1c9bfbfce33 --- /dev/null +++ b/extern/verse/make/msvc_7_0/libverse.vcproj @@ -0,0 +1,279 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extern/verse/make/msvc_7_0/verse.vcproj b/extern/verse/make/msvc_7_0/verse.vcproj new file mode 100644 index 00000000000..563e33e7be9 --- /dev/null +++ b/extern/verse/make/msvc_7_0/verse.vcproj @@ -0,0 +1,481 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt new file mode 100644 index 00000000000..aa5b1a8531c --- /dev/null +++ b/intern/CMakeLists.txt @@ -0,0 +1,36 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SUBDIRS(SoundSystem string ghost guardedalloc bmfont moto container memutil decimation iksolver boolop opennl) + +IF(WITH_ELBEEM) + SUBDIRS(elbeem) +ENDIF(WITH_ELBEEM) + +SUBDIRS(bsp) diff --git a/intern/Makefile b/intern/Makefile new file mode 100644 index 00000000000..7eaabd5b6bb --- /dev/null +++ b/intern/Makefile @@ -0,0 +1,50 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# Bounces make to subdirectories. Also installs after succesful all target. + +SOURCEDIR = intern + +# include nan_subdirs.mk + +ALLDIRS = string ghost guardedalloc bmfont moto container memutil +ALLDIRS += decimation iksolver bsp SoundSystem opennl elbeem boolop + +all:: + @for i in $(ALLDIRS); do \ + echo "====> $(MAKE) $@ in $(SOURCEDIR)/$$i" ;\ + $(MAKE) -C $$i install || exit 1; \ + done +clean test debug:: + @for i in $(ALLDIRS); do \ + echo "====> $(MAKE) $@ in $(SOURCEDIR)/$$i" ;\ + $(MAKE) -C $$i $@ || exit 1; \ + done + diff --git a/intern/SConscript b/intern/SConscript new file mode 100644 index 00000000000..f6092b7bd02 --- /dev/null +++ b/intern/SConscript @@ -0,0 +1,29 @@ +#!/usr/bin/python +Import ('env') + +SConscript(['SoundSystem/SConscript', + 'string/SConscript', + 'ghost/SConscript', + 'guardedalloc/SConscript', + 'bmfont/SConscript', + 'moto/SConscript', + 'container/SConscript', + 'memutil/SConscript/', + 'decimation/SConscript', + 'iksolver/SConscript', + 'boolop/SConscript', + 'opennl/SConscript']) + +# NEW_CSG was intended for intern/csg, but +# getting it to compile is difficult +# intern/bsp has been used anyway, so +# perhaps get rid of intern/csg? +NEW_CSG='false' + +if env['BF_NO_ELBEEM'] == 0: + SConscript(['elbeem/SConscript']) + +if NEW_CSG=='false': + SConscript(['bsp/SConscript']) +else: + SConscript(['csg/SConscript']) diff --git a/intern/SoundSystem/CMakeLists.txt b/intern/SoundSystem/CMakeLists.txt new file mode 100644 index 00000000000..428b8db01ee --- /dev/null +++ b/intern/SoundSystem/CMakeLists.txt @@ -0,0 +1,45 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC . intern ../moto/include ../string dummy openal sdl) + +IF(WITH_OPENAL) + FILE(GLOB SRC dummy/*.cpp intern/*.cpp openal/*.cpp sdl/*.cpp) + INCLUDE_DIRECTORIES(${OPENAL_INC} ${SDL_INC}) + STRING(REGEX MATCH ".*ramework.*" FRAMEWORK ${OPENAL_INC}) + IF(FRAMEWORK) + ADD_DEFINITIONS(-DAPPLE_FRAMEWORK_FIX) + ENDIF(FRAMEWORK) +ELSE(WITH_OPENAL) + FILE(GLOB SRC dummy/*.cpp intern/*.cpp) + ADD_DEFINITIONS(-DNO_SOUND) +ENDIF(WITH_OPENAL) + +BLENDERLIB(bf_soundsystem "${SRC}" "${INC}") +#, libtype=['core','player'], priority = [20,140] ) diff --git a/intern/SoundSystem/Makefile b/intern/SoundSystem/Makefile new file mode 100644 index 00000000000..757301e4a35 --- /dev/null +++ b/intern/SoundSystem/Makefile @@ -0,0 +1,72 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +include nan_definitions.mk + +LIBNAME = SoundSystem +SOURCEDIR = intern/SoundSystem +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +DIRS += dummy + +ifneq ($(NAN_NO_OPENAL),true) + ifeq ($(OS),windows) + DIRS += fmod + DIRS += openal sdl + endif + ifeq ($(OS),darwin) + DIRS += openal + endif + ifeq ($(OS),$(findstring $(OS), "linux freebsd solaris")) + DIRS += openal sdl + endif +else + export CPPFLAGS += -DNO_SOUND +endif + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_SOUNDSYSTEM) ] || mkdir $(NAN_SOUNDSYSTEM) + @[ -d $(NAN_SOUNDSYSTEM)/include ] || mkdir $(NAN_SOUNDSYSTEM)/include + @[ -d $(NAN_SOUNDSYSTEM)/lib ] || mkdir $(NAN_SOUNDSYSTEM)/lib + @[ -d $(NAN_SOUNDSYSTEM)/lib/debug ] || mkdir $(NAN_SOUNDSYSTEM)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libSoundSystem.a $(NAN_SOUNDSYSTEM)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libSoundSystem.a $(NAN_SOUNDSYSTEM)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_SOUNDSYSTEM)/lib/libSoundSystem.a + ranlib $(NAN_SOUNDSYSTEM)/lib/debug/libSoundSystem.a +endif + @../tools/cpifdiff.sh *.h $(NAN_SOUNDSYSTEM)/include/ + + diff --git a/intern/SoundSystem/SConscript b/intern/SoundSystem/SConscript new file mode 100644 index 00000000000..a9c1110c09a --- /dev/null +++ b/intern/SoundSystem/SConscript @@ -0,0 +1,16 @@ +#!/usr/bin/python + +Import ('env') + +sources = env.Glob('dummy/*.cpp') + env.Glob('intern/*.cpp') + +incs = '. intern ../moto/include ../string dummy openal sdl' +defs = '' +if env['WITH_BF_OPENAL']: + sources += env.Glob('openal/*.cpp') + env.Glob('sdl/*.cpp') + incs += ' ' + env['BF_OPENAL_INC'] + incs += ' ' + env['BF_SDL_INC'] +else: + defs = 'NO_SOUND' + +env.BlenderLib ('bf_soundsystem', sources, Split(incs), Split(defs), libtype=['core','player'], priority = [20,140] ) diff --git a/intern/SoundSystem/SND_C-api.h b/intern/SoundSystem/SND_C-api.h new file mode 100644 index 00000000000..03470f7e998 --- /dev/null +++ b/intern/SoundSystem/SND_C-api.h @@ -0,0 +1,357 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef SND_BLENDER_H +#define SND_BLENDER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "SoundDefines.h" + +#define SND_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name + +SND_DECLARE_HANDLE(SND_AudioDeviceInterfaceHandle); +SND_DECLARE_HANDLE(SND_SceneHandle); +SND_DECLARE_HANDLE(SND_ObjectHandle); +SND_DECLARE_HANDLE(SND_ListenerHandle); + +/** + * set the specified type + */ +extern void SND_SetDeviceType(int device_type); + +/** + * get an audiodevice + */ +extern SND_AudioDeviceInterfaceHandle SND_GetAudioDevice(void); + +/** + * and let go of it + */ +extern void SND_ReleaseDevice(void); + +/** + * check if playback is desired + */ +extern int SND_IsPlaybackWanted(SND_SceneHandle scene); + +/** + * add memlocation to cache + */ +extern int SND_AddSample(SND_SceneHandle scene, + const char* filename, + void* memlocation, + int size); + +/** + * remove all samples + */ +extern void SND_RemoveAllSamples(SND_SceneHandle scene); + +/** + * forces the object to check its buffer, and fix it if it's wrong + */ +extern int SND_CheckBuffer(SND_SceneHandle scene, SND_ObjectHandle object); + +/** + * Creates a scene, initializes it and returns a handle to that scene. + * + * @param audiodevice: handle to the audiodevice. + */ +extern SND_SceneHandle SND_CreateScene(SND_AudioDeviceInterfaceHandle audiodevice); + +/** + * Stops all sounds, suspends the scene (so all resources will be freed) and deletes the scene. + * + * @param scene: handle to the soundscene. + */ +extern void SND_DeleteScene(SND_SceneHandle scene); + +/** + * Adds a soundobject to the scene, gets the buffer the sample is loaded into. + * + * @param scene: handle to the soundscene. + * @param object: handle to soundobject. + */ +extern void SND_AddSound(SND_SceneHandle scene, SND_ObjectHandle object); + +/** + * Removes a soundobject from the scene. + * + * @param scene: handle to the soundscene. + * @param object: handle to soundobject. + */ +extern void SND_RemoveSound(SND_SceneHandle scene, SND_ObjectHandle object); + +/** + * Removes all soundobjects from the scene. + * + * @param scene: handle to the soundscene. + */ +extern void SND_RemoveAllSounds(SND_SceneHandle scene); + +/** + * Stopss all soundobjects in the scene. + * + * @param scene: handle to the soundscene. + */ +extern void SND_StopAllSounds(SND_SceneHandle scene); + +/** + * Updates the listener, checks the status of all soundobjects, builds a list of all active + * objects, updates the active objects. + * + * @param audiodevice: handle to the audiodevice. + * @param scene: handle to the soundscene. + */ +extern void SND_Proceed(SND_AudioDeviceInterfaceHandle audiodevice, SND_SceneHandle scene); + +/** + * Returns a handle to the listener. + * + * @param scene: handle to the soundscene. + */ +extern SND_ListenerHandle SND_GetListener(SND_SceneHandle scene); + +/** + * Sets the gain of the listener. + * + * @param scene: handle to the soundscene. + * @param gain: factor the gain gets multiplied with. + */ +extern void SND_SetListenerGain(SND_SceneHandle scene, double gain); + +/** + * Sets a scaling to exaggerate or deemphasize the Doppler (pitch) shift resulting from the + * calculation. + * @attention $f' = dopplerfactor * f * frac{dopplervelocity - listener_velocity}{dopplervelocity + object_velocity}$ + * @attention f: frequency in sample (soundobject) + * @attention f': effective Doppler shifted frequency + * + * @param object: handle to soundobject. + * @param dopplerfactor: the dopplerfactor. + */ +extern void SND_SetDopplerFactor(SND_SceneHandle scene, double dopplerfactor); + +/** + * Sets the value of the propagation speed relative to which the source velocities are interpreted. + * @attention $f' = dopplerfactor * f * frac{dopplervelocity - listener_velocity}{dopplervelocity + object_velocity}$ + * @attention f: frequency in sample (soundobject) + * @attention f': effective Doppler shifted frequency + * + * @param object: handle to soundobject. + * @param dopplervelocity: the dopplervelocity. + */ +extern void SND_SetDopplerVelocity(SND_SceneHandle scene, double dopplervelocity); + +/** + * Creates a new soundobject and returns a handle to it. + */ +extern SND_ObjectHandle SND_CreateSound(void); + +/** + * Deletes a soundobject. + * + * @param object: handle to soundobject. + */ +extern void SND_DeleteSound(SND_ObjectHandle object); + +/** + * Sets a soundobject to SND_MUST_PLAY, so with the next proceed it will be updated and played. + * + * @param object: handle to soundobject. + */ +extern void SND_StartSound(SND_SceneHandle scene, SND_ObjectHandle object); + +/** + * Sets a soundobject to SND_MUST_STOP, so with the next proceed it will be stopped. + * + * @param object: handle to soundobject. + */ +extern void SND_StopSound(SND_SceneHandle scene, SND_ObjectHandle object); + +/** + * Sets a soundobject to SND_MUST_PAUSE, so with the next proceed it will be paused. + * + * @param object: handle to soundobject. + */ +extern void SND_PauseSound(SND_SceneHandle scene, SND_ObjectHandle object); + +/** + * Sets the name of the sample to reference the soundobject to it. + * + * @param object: handle to soundobject. + * @param samplename: the name of the sample + */ +extern void SND_SetSampleName(SND_ObjectHandle object, char* samplename); + +/** + * Sets the gain of a soundobject. + * + * @param object: handle to soundobject. + * @param gain: factor the gain gets multiplied with. + */ +extern void SND_SetGain(SND_ObjectHandle object, double gain); + +/** + * Sets the minimum gain of a soundobject. + * + * @param object: handle to soundobject. + * @param minimumgain: lower threshold for the gain. + */ +extern void SND_SetMinimumGain(SND_ObjectHandle object, double minimumgain); + +/** + * Sets the maximum gain of a soundobject. + * + * @param object: handle to soundobject. + * @param maximumgain: upper threshold for the gain. + */ +extern void SND_SetMaximumGain(SND_ObjectHandle object, double maximumgain); + +/** + * Sets the rollofffactor. The rollofffactor is a per-Source parameter the application + * can use to increase or decrease the range of a source by decreasing or increasing the + * attenuation, respectively. The default value is 1. The implementation is free to optimize + * for a rollofffactor value of 0, which indicates that the application does not wish any + * distance attenuation on the respective Source. + * + * @param object: handle to soundobject. + * @param rollofffactor: the rollofffactor. + */ +extern void SND_SetRollOffFactor(SND_ObjectHandle object, double rollofffactor); + +/** + * Sets the referencedistance at which the listener will experience gain. + * @attention G_dB = gain - 20 * log10(1 + rollofffactor * (dist - referencedistance)/referencedistance); + * + * @param object: handle to soundobject. + * @param distance: the reference distance. + */ +extern void SND_SetReferenceDistance(SND_ObjectHandle object, double referencedistance); + +/** + * Sets the pitch of a soundobject. + * + * @param object: handle to soundobject. + * @param pitch: pitchingfactor: 2.0 for doubling the frequency, 0.5 for half the frequency. + */ +extern void SND_SetPitch(SND_ObjectHandle object, double pitch); + +/** + * Sets the position a soundobject. + * + * @param object: handle to soundobject. + * @param position: position[3]. + */ +extern void SND_SetPosition(SND_ObjectHandle object, double* position); + +/** + * Sets the velocity of a soundobject. + * + * @param object: handle to soundobject. + * @param velocity: velocity[3]. + */ +extern void SND_SetVelocity(SND_ObjectHandle object, double* velocity); + +/** + * Sets the orientation of a soundobject. + * + * @param object: handle to soundobject. + * @param orientation: orientation[9]. + */ +extern void SND_SetOrientation(SND_ObjectHandle object, double* orientation); + +/** + * Sets the loopmode of a soundobject. + * + * @param object: handle to soundobject. + * @param loopmode type of the loop (SND_LOOP_OFF, SND_LOOP_NORMAL, SND_LOOP_BIDIRECTIONAL); + */ +extern void SND_SetLoopMode(SND_ObjectHandle object, int loopmode); + +/** + * Sets the looppoints of a soundobject. + * + * @param object: handle to soundobject. + * @param loopstart startpoint of the loop + * @param loopend endpoint of the loop + */ +extern void SND_SetLoopPoints(SND_ObjectHandle object, unsigned int loopstart, unsigned int loopend); + +/** + * Gets the gain of a soundobject. + * + * @param object: handle to soundobject. + */ +extern float SND_GetGain(SND_ObjectHandle object); + +/** + * Gets the pitch of a soundobject. + * + * @param object: handle to soundobject. + */ +extern float SND_GetPitch(SND_ObjectHandle object); + +/** + * Gets the looping of a soundobject. + * 0: SND_LOOP_OFF + * 1: SND_LOOP_NORMAL + * 2: SND_LOOP_BIDIRECTIONAL + * + * @param object: handle to soundobject. + */ +extern int SND_GetLoopMode(SND_ObjectHandle object); + +/** + * Gets the playstate of a soundobject. + * SND_UNKNOWN = -1 + * SND_INITIAL + * SND_MUST_PLAY + * SND_PLAYING + * SND_MUST_STOP + * SND_STOPPED + * SND_MUST_PAUSE + * SND_PAUSED + * SND_MUST_BE_DELETED + * + * @param object: handle to soundobject. + */ +extern int SND_GetPlaystate(SND_ObjectHandle object); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/intern/SoundSystem/SND_CDObject.h b/intern/SoundSystem/SND_CDObject.h new file mode 100644 index 00000000000..5af2005d34a --- /dev/null +++ b/intern/SoundSystem/SND_CDObject.h @@ -0,0 +1,86 @@ +/* + * SND_CDObject.h + * + * Implementation for CD playback + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __SND_CDOBJECT_H +#define __SND_CDOBJECT_H + +#include "SND_Object.h" + +class SND_CDObject : public SND_Object +{ +private: + + /** + * Private to enforce singleton + */ + SND_CDObject(); + SND_CDObject(const SND_CDObject&); + + static SND_CDObject* m_instance; + MT_Scalar m_gain; /* the gain of the object */ + int m_playmode; /* the way CD is played back (all, random, track, trackloop) */ + int m_track; /* the track for 'track' and 'trackloop' */ + int m_playstate; /* flag for current state of object */ + bool m_modified; + bool m_used; /* flag for checking if we used the cd, if not don't + call the stop cd at the end */ + +public: + static bool CreateSystem(); + static bool DisposeSystem(); + static SND_CDObject* Instance(); + + ~SND_CDObject(); + + void SetGain(MT_Scalar gain); + void SetPlaymode(int playmode); + void SetTrack(int track); + void SetPlaystate(int playstate); + void SetModified(bool modified); + void SetUsed(); + bool GetUsed(); + + bool IsModified() const; + + int GetTrack() const; + MT_Scalar GetGain() const; + int GetPlaymode() const; + int GetPlaystate() const; + +}; + +#endif //__SND_CDOBJECT_H + diff --git a/intern/SoundSystem/SND_DependKludge.h b/intern/SoundSystem/SND_DependKludge.h new file mode 100644 index 00000000000..71514a87ca2 --- /dev/null +++ b/intern/SoundSystem/SND_DependKludge.h @@ -0,0 +1,56 @@ +/* + * SND_DependKludge.h + * + * who needs what? + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef HAVE_CONFIG_H + +#ifndef NO_SOUND + +#if defined (_WIN32) && !defined(FREE_WINDOWS) +# define USE_OPENAL +#elif defined (__linux__) || (__FreeBSD__) || defined(__APPLE__) || defined(__sun) +# define USE_OPENAL +#else +# ifdef USE_OPENAL +# undef USE_OPENAL +# endif +# ifdef USE_FMOD +# undef USE_FMOD +# endif +#endif + +#endif /* NO_SOUND */ + +#endif /* HAVE_CONFIG_H */ diff --git a/intern/SoundSystem/SND_DeviceManager.h b/intern/SoundSystem/SND_DeviceManager.h new file mode 100644 index 00000000000..b0b2a28ffb8 --- /dev/null +++ b/intern/SoundSystem/SND_DeviceManager.h @@ -0,0 +1,82 @@ +/* + * SND_DeviceManager.h + * + * singleton for creating, switching and deleting audiodevices + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __SND_DEVICEMANAGER_H +#define __SND_DEVICEMANAGER_H + +#include "SND_IAudioDevice.h" + +class SND_DeviceManager +{ +public : + + /** + * a subscription is needed before instances are given away + * applications must call subscribe first, get an instance, and + * when they are finished with sound, unsubscribe + */ + static void Subscribe(); + static void Unsubscribe(); + + static SND_IAudioDevice* Instance(); + static void SetDeviceType(int device_type); + +private : + + /** + * Private to enforce singleton + */ + SND_DeviceManager(); + SND_DeviceManager(const SND_DeviceManager&); + ~SND_DeviceManager(); + + static SND_IAudioDevice* m_instance; + + /** + * The type of device to be created on a call + * to Instance(). + */ + static int m_device_type; + + /** + * Remember the number of subscriptions. + * if 0, delete the device + */ + static int m_subscriptions; +}; + +#endif //__SND_DEVICEMANAGER_H + diff --git a/intern/SoundSystem/SND_IAudioDevice.h b/intern/SoundSystem/SND_IAudioDevice.h new file mode 100644 index 00000000000..73d52e13c05 --- /dev/null +++ b/intern/SoundSystem/SND_IAudioDevice.h @@ -0,0 +1,346 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef SND_IAUDIODEVICE +#define SND_IAUDIODEVICE + +#include "SND_SoundObject.h" +#include "SND_CDObject.h" +#include "SND_WaveCache.h" +#include "SND_WaveSlot.h" +#include "MT_Matrix3x3.h" + +class SND_IAudioDevice +{ +public: + + /** + * constructor + */ + SND_IAudioDevice() {}; + + /** + * destructor + */ + virtual ~SND_IAudioDevice() {}; + + /** + * check to see if initialization was successfull + * + * @return indication of succes + */ + virtual bool IsInitialized()=0; + + /** + * get the wavecache (which does sample (un)loading) + * + * @return pointer to the wavecache + */ + virtual SND_WaveCache* GetWaveCache() const =0; + + /** + * loads a sample into the device + * + * @param samplename the name of the sample + * @param memlocation pointer where the sample is stored + * @param size size of the sample in memory + * + * @return pointer to the slot with sample data + */ + virtual SND_WaveSlot* LoadSample(const STR_String& samplename, + void* memlocation, + int size)=0; + + /** + * remove a sample from the wavecache + * + * @param filename pointer to filename + */ +// virtual void RemoveSample(const char* filename)=0; + + /** + * remove all samples from the wavecache + */ + virtual void RemoveAllSamples()=0; + + /** + * get a new id from the device + * + * @param pObject pointer to soundobject + * + * @return indication of success + */ + virtual bool GetNewId(SND_SoundObject* pObject)=0; + + /** + * clear an id + * + * @param pObject pointer to soundobject + */ + virtual void ClearId(SND_SoundObject* pObject)=0; + + /** + * initialize the listener + */ + virtual void InitListener()=0; + + /** + * set the value of the propagation speed relative to which the + * source velocities are interpreted. + * f' = DOPPLER_FACTOR * f * (DOPPLER_VELOCITY - Vl) / (DOPPLER_VELOCITY + Vo) + * f: frequency in sample (soundobject) + * f': effective Doppler shifted frequency + * Vl: velocity listener + * Vo: velocity soundobject + * + * @param dopplervelocity scaling factor for doppler effect + */ + virtual void SetDopplerVelocity(MT_Scalar dopplervelocity) const =0; + + /** + * set a scaling to exaggerate or deemphasize the Doppler (pitch) + * shift resulting from the calculation. + * f' = DOPPLER_FACTOR * f * (DOPPLER_VELOCITY - Listener_velocity )/(DOPPLER_VELOCITY + object_velocity ) + * + * @param dopplerfactor scaling factor for doppler effect + */ + virtual void SetDopplerFactor(MT_Scalar dopplerfactor) const =0; + + /** + * set the roll-off factor + * + * @param rollofffactor a global volume scaling factor + */ + virtual void SetListenerRollOffFactor(MT_Scalar rollofffactor) const =0; + + /** + * make the context the current one + */ + virtual void MakeCurrent() const =0; + + /** + * update the device + */ + virtual void NextFrame() const =0; + + /** + * set the volume of the listener. + * + * @param gain the mastergain + */ + virtual void SetListenerGain(float gain) const =0; + + /** + * connect the buffer with the source + * + * @param id the id of the object + * @param buffer the buffer the sample is stored in + */ + virtual void SetObjectBuffer(int id, unsigned int buffer)=0; + + /** + * pause playback of the cd + * @param id the id of the object + * + * @return the state the object is in + */ + virtual int GetPlayState(int id) =0; + + /** + * play a sound belonging to an object. + * + * @param id the id of the object + */ + virtual void PlayObject(int id) =0; + + /** + * stop a sound belonging to an object. + * + * @param id the id of the object + */ + virtual void StopObject(int id) const =0; + + /** + * stop all sounds. + */ + virtual void StopAllObjects()=0; + + /** + * pause the sound belonging to an object. + * + * @param id the id of the object + */ + virtual void PauseObject(int id) const =0; + + /** + * set the sound to looping or non-looping. + * + * @param id the id of the object + * @param loopmode type of looping (no loop, normal, bidirectional) + */ + virtual void SetObjectLoop(int id, unsigned int loopmode) const =0; + + /** + * set the looppoints of a sound + * + * @param id the id of the object + * @param loopstart the startpoint of the loop (in samples) + * @param loopend the endpoint of the loop (in samples) + */ + virtual void SetObjectLoopPoints(int id, unsigned int loopstart, unsigned int loopend) const =0; + + /** + * set the pitch of the sound. + * + * @param id the id of the object + * @param pitch the pitch + */ + virtual void SetObjectPitch(int id, MT_Scalar pitch) const =0; + + /** + * set the gain of the sound. + * + * @param id the id of the object + * @param gain the gain + */ + virtual void SetObjectGain(int id, MT_Scalar gain) const =0; + + /** + * ROLLOFF_FACTOR is per-Source parameter the application can use to increase or decrease + * the range of a source by decreasing or increasing the attenuation, respectively. The + * default value is 1. The implementation is free to optimize for a ROLLOFF_FACTOR value + * of 0, which indicates that the application does not wish any distance attenuation on + * the respective Source. + * + * @param id the id of the object + * @param rolloff a per-source volume scaling factor + */ + virtual void SetObjectRollOffFactor(int id, MT_Scalar rolloff) const =0; + + /** + * min_gain indicates the minimal gain which is always guaranteed for this sound + * + * @param id the id of the object + * @param mingain the minimum gain of the object + */ + virtual void SetObjectMinGain(int id, MT_Scalar mingain) const =0; + + /** + * max_gain indicates the maximal gain which is always guaranteed for this sound + * + * @param id the id of the object + * @param maxgain the maximum gain of the object + */ + virtual void SetObjectMaxGain(int id, MT_Scalar maxgain) const =0; + /** + * set the distance at which the Listener will experience gain. + * G_dB = GAIN - 20*log10(1 + ROLLOFF_FACTOR*(dist-REFERENCE_DISTANCE)/REFERENCE_DISTANCE ); + * + * @param id the id of the object + * @param referencedistance the distance at which the listener will start hearing + */ + virtual void SetObjectReferenceDistance(int id, MT_Scalar referencedistance) const =0; + + /** + * set the position, velocity and orientation of a sound. + * + * @param id the id of the object + * @param position the position of the object + * @param velocity the velocity of the object + * @param orientation the orientation of the object + * @param lisposition the position of the listener + * @param rollofffactor the rollofffactor of the object + */ + virtual void SetObjectTransform(int id, + const MT_Vector3& position, + const MT_Vector3& velocity, + const MT_Matrix3x3& orientation, + const MT_Vector3& lisposition, + const MT_Scalar& rollofffactor) const =0; + + /** + * make a sound 2D + * + * @param id the id of the object + */ + virtual void ObjectIs2D(int id) const =0; + + /** + * tell the device we want cd suppport + */ + virtual void UseCD() const =0; + + /** + * start playback of the cd + * + * @param track the tracknumber to start playback from + */ + virtual void PlayCD(int track) const =0; + + /** + * pause playback of the cd (true == pause, false == resume) + */ + virtual void PauseCD(bool pause) const =0; + + /** + * stop playback of the cd + */ + virtual void StopCD() const =0; + + /** + * set the playbackmode of the cd + * SND_CD_ALL play all tracks + * SND_CD_TRACK play one track + * SND_CD_TRACKLOOP play one track looped + * SND_CD_RANDOM play all tracks in random order + * + * @param playmode playmode + */ + virtual void SetCDPlaymode(int playmode) const =0; + + /** + * set the volume playback of the cd + * + * @param gain the gain + */ + virtual void SetCDGain(MT_Scalar gain) const =0; + + virtual void StartUsingDSP() =0; + virtual float* GetSpectrum() =0; + virtual void StopUsingDSP() =0; + +protected: + + virtual void RevokeSoundObject(SND_SoundObject* pObject)=0; +}; + +#endif //SND_IAUDIODEVICE + diff --git a/intern/SoundSystem/SND_Object.h b/intern/SoundSystem/SND_Object.h new file mode 100644 index 00000000000..b67ae3ee396 --- /dev/null +++ b/intern/SoundSystem/SND_Object.h @@ -0,0 +1,57 @@ +/* + * SND_Object.h + * + * Abstract sound object + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __SND_OBJECT_H +#define __SND_OBJECT_H + +#include "GEN_List.h" +#include "MT_Matrix3x3.h" +#include "SoundDefines.h" + +/** + * SND_Object is an interface class for soundobjects, listeners and other + * kinds of sound related thingies. + */ + +class SND_Object : public GEN_Link +{ +public: + SND_Object() {}; + virtual ~SND_Object() {}; +}; + +#endif //__SND_OBJECT_H + diff --git a/intern/SoundSystem/SND_Scene.h b/intern/SoundSystem/SND_Scene.h new file mode 100644 index 00000000000..49cb40de714 --- /dev/null +++ b/intern/SoundSystem/SND_Scene.h @@ -0,0 +1,107 @@ +/* + * SND_Scene.h + * + * The scene for sounds. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef WIN32 +#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning +#endif //WIN32 + +#ifndef __SND_SCENE_H +#define __SND_SCENE_H + +#include "SoundDefines.h" +#include "SND_SoundObject.h" +#include "SND_CDObject.h" +#include "SND_SoundListener.h" +#include "SND_WaveSlot.h" + +#include "MT_Vector3.h" +#include "MT_Matrix3x3.h" +#include "STR_String.h" + +#include + + +class SND_Scene +{ + std::set m_soundobjects; + + GEN_List m_activeobjects; + class SND_IAudioDevice* m_audiodevice; + class SND_WaveCache* m_wavecache; + class SND_SoundListener m_listener; + bool m_audio; // to check if audio works + bool m_audioplayback; // to check if audioplayback is wanted + + void UpdateListener(); + void BuildActiveList(MT_Scalar curtime); + void UpdateActiveObects(); + void UpdateCD(); + +public: + SND_Scene(SND_IAudioDevice* adi); + ~SND_Scene(); + + bool IsPlaybackWanted(); + + void AddActiveObject(SND_SoundObject* pObject, MT_Scalar curtime); + void RemoveActiveObject(SND_SoundObject* pObject); + void DeleteObjectWhenFinished(SND_SoundObject* pObject); + + void Proceed(); + + int LoadSample(const STR_String& samplename, + void* memlocation, + int size); + void RemoveAllSamples(); + bool CheckBuffer(SND_SoundObject* pObject); + bool IsSampleLoaded(STR_String& samplename); + + void AddObject(SND_SoundObject* pObject); + bool SetCDObject(SND_CDObject* cdobject); + void DeleteObject(SND_SoundObject* pObject); + void RemoveAllObjects(); + void StopAllObjects(); + int GetObjectStatus(SND_SoundObject* pObject) const; + + void SetListenerTransform(const MT_Vector3& pos, + const MT_Vector3& vel, + const MT_Matrix3x3& mat); + + SND_SoundListener* GetListener(); +}; + +#endif //__SND_SCENE_H + diff --git a/intern/SoundSystem/SND_SoundListener.h b/intern/SoundSystem/SND_SoundListener.h new file mode 100644 index 00000000000..ce8315e6375 --- /dev/null +++ b/intern/SoundSystem/SND_SoundListener.h @@ -0,0 +1,85 @@ +/* + * SND_SoundListener.h + * + * A SoundListener is for sound what a camera is for vision. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __SND_SOUNDLISTENER_H +#define __SND_SOUNDLISTENER_H + +#include "SND_Object.h" + +class SND_SoundListener : public SND_Object +{ +public: + SND_SoundListener(); + virtual ~SND_SoundListener(); + + void SetStateFlag(unsigned int stateflags); + void SetGain(MT_Scalar gain); + void SetPosition(const MT_Vector3& pos); + void SetVelocity(const MT_Vector3& vel); + void SetOrientation(const MT_Matrix3x3& ori); + void SetDopplerFactor(MT_Scalar dopplerfactor); + void SetDopplerVelocity(MT_Scalar dopplervelocity); + void SetScale(MT_Scalar scale); + + void SetModified(bool modified); + bool IsModified() const; + + unsigned int GetStateFlags() const; + MT_Scalar GetGain() const; + MT_Vector3 GetPosition() const; + MT_Vector3 GetVelocity() const; + MT_Matrix3x3 GetOrientation(); + + MT_Scalar GetDopplerFactor() const; + MT_Scalar GetDopplerVelocity() const; + MT_Scalar GetScale() const; + +private: + void* m_listener; + bool m_modified; + + MT_Scalar m_gain; /* overall gain */ + MT_Vector3 m_position; /* position; left/right, up/down, in/out */ + MT_Vector3 m_velocity; /* velocity of the listener */ + MT_Matrix3x3 m_orientation; /* orientation of the listener */ + + MT_Scalar m_dopplerfactor; /* scaling factor for the Doppler (pitch) shift */ + MT_Scalar m_dopplervelocity; /* factor for the reference velocity (for Dopplereffect) */ + MT_Scalar m_scale; +}; + +#endif //__SND_SOUNDLISTENER_H + diff --git a/intern/SoundSystem/SND_SoundObject.h b/intern/SoundSystem/SND_SoundObject.h new file mode 100644 index 00000000000..a6a98fba220 --- /dev/null +++ b/intern/SoundSystem/SND_SoundObject.h @@ -0,0 +1,162 @@ +/* + * SND_SoundObject.h + * + * Implementation of the abstract sound object + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __SND_SOUNDOBJECT_H +#define __SND_SOUNDOBJECT_H + +#include "SND_Object.h" +#include "STR_String.h" + +/** + * SND_SoundObject is a class for api independent sounddata storage conected to an actuator + */ + +class SND_SoundObject : public SND_Object +{ +private: + STR_String m_samplename; /* name of the sample */ + STR_String m_objectname; /* name of the object */ + unsigned int m_buffer; + + bool m_active; /* is the object active or not? */ + int m_id; + MT_Scalar m_lifespan; /* the lifespan of the sound seconds */ + MT_Scalar m_timestamp; + + MT_Scalar m_length; /* length of the sample in seconds */ + + MT_Scalar m_gain; /* the gain of the object */ + MT_Scalar m_rollofffactor; /* the scaling factor to increase or decrease the range + of a source by decreasing or increasing the + attenuation, respectively */ + MT_Scalar m_referencedistance;/* the distance at which the listener will experience + gain */ + MT_Scalar m_mingain; /* indicates the minimal gain which is always guaranteed + for this source */ + MT_Scalar m_maxgain; /* indicates the maximal gain which is always guaranteed + for this source */ + + MT_Scalar m_pitch; /* the pitch of the object */ + MT_Vector3 m_position; /* position; left/right, up/down, in/out */ + MT_Vector3 m_velocity; /* velocity of the object */ + MT_Matrix3x3 m_orientation; /* orientation of the object */ + unsigned int m_loopmode; /* loop normal or bidirectional? */ + unsigned int m_loopstart; /* start of looppoint in samples! */ + unsigned int m_loopend; /* end of looppoint in samples! */ + bool m_is3d; /* is the object 3D or 2D? */ + int m_playstate; /* flag for current state of object */ + bool m_modified; + unsigned int m_running; + bool m_highpriority; /* may the sound be ditched when we run out of voices? */ + +public: + + SND_SoundObject(); + ~SND_SoundObject(); + + void SetBuffer(unsigned int buffer); + void SetActive(bool active); + + void StartSound(); + void StopSound(); + void PauseSound(); + void DeleteWhenFinished(); + + void SetObjectName(STR_String objectname); + void SetSampleName(STR_String samplename); + void SetLength(MT_Scalar length); + + void SetPitch(MT_Scalar pitch); + void SetGain(MT_Scalar gain); + void SetMinGain(MT_Scalar mingain); + void SetMaxGain(MT_Scalar maxgain); + void SetRollOffFactor(MT_Scalar rollofffactor); + void SetReferenceDistance(MT_Scalar distance); + void SetPosition(const MT_Vector3& pos); + void SetVelocity(const MT_Vector3& vel); + void SetOrientation(const MT_Matrix3x3& orient); + void SetLoopMode(unsigned int loopmode); + void SetLoopStart(unsigned int loopstart); + void SetLoopEnd(unsigned int loopend); + void Set3D(bool threedee); + void SetPlaystate(int playstate); + void SetHighPriority(bool priority); + + void SetId(int id); + void SetLifeSpan(); + void SetTimeStamp(MT_Scalar timestamp); + + void SetModified(bool modified); + + bool IsLifeSpanOver(MT_Scalar curtime) const; + bool IsActive() const; + bool IsModified() const; + bool IsHighPriority() const; + + void InitRunning(); + bool IsRunning() const; + void AddRunning(); + + int GetId() const; + MT_Scalar GetLifeSpan() const; + MT_Scalar GetTimestamp() const; + + unsigned int GetBuffer(); + const STR_String& GetSampleName(); + const STR_String& GetObjectName(); + + MT_Scalar GetLength() const; + MT_Scalar GetGain() const; + MT_Scalar GetPitch() const; + + MT_Scalar GetMinGain() const; + MT_Scalar GetMaxGain() const; + MT_Scalar GetRollOffFactor() const; + MT_Scalar GetReferenceDistance() const; + + MT_Vector3 GetPosition() const; + MT_Vector3 GetVelocity() const; + MT_Matrix3x3 GetOrientation() const; + unsigned int GetLoopMode() const; + unsigned int GetLoopStart() const; + unsigned int GetLoopEnd() const; + bool Is3D() const; + int GetPlaystate() const; + +}; + +#endif //__SND_SOUNDOBJECT_H + diff --git a/intern/SoundSystem/SND_Utils.h b/intern/SoundSystem/SND_Utils.h new file mode 100644 index 00000000000..de36065c48f --- /dev/null +++ b/intern/SoundSystem/SND_Utils.h @@ -0,0 +1,114 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef SND_UTILS_H +#define SND_UTILS_H + +#include "SND_WaveSlot.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef struct +{ + unsigned char riff[4]; + signed int size; + unsigned char type[4]; +} WavFileHeader; + +typedef struct +{ + unsigned short format; + unsigned short numberofchannels; + unsigned int samplerate; + unsigned int bytespersec; + unsigned short blockalignment; + unsigned short bitrate; +} WavFmtHeader; + +typedef struct +{ + unsigned short size; + unsigned short samplesperblock; +} WavFmtExHeader; + +typedef struct +{ + unsigned int Manufacturer; + unsigned int Product; + unsigned int SamplePeriod; + unsigned int Note; + unsigned int FineTune; + unsigned int SMPTEFormat; + unsigned int SMPTEOffest; + unsigned int loops; + unsigned int SamplerData; + struct + { + unsigned int Identifier; + unsigned int Type; + unsigned int Start; + unsigned int End; + unsigned int Fraction; + unsigned int Count; + } Loop[1]; +} WavSampleHeader; + +typedef struct +{ + unsigned char id[4]; + unsigned int size; +} WavChunkHeader; + +/** + * loads a sample and returns a pointer + */ +extern void* SND_LoadSample(char *filename); + +extern bool SND_IsSampleValid(const STR_String& name, void* memlocation); +extern unsigned int SND_GetSampleFormat(void* sample); +extern unsigned int SND_GetNumberOfChannels(void* sample); +extern unsigned int SND_GetSampleRate(void* sample); +extern unsigned int SND_GetBitRate(void* sample); +extern unsigned int SND_GetNumberOfSamples(void* sample); +extern unsigned int SND_GetHeaderSize(void* sample); +extern unsigned int SND_GetExtraChunk(void* sample); + +extern void SND_GetSampleInfo(signed char* sample, SND_WaveSlot* waveslot); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/intern/SoundSystem/SND_WaveCache.h b/intern/SoundSystem/SND_WaveCache.h new file mode 100644 index 00000000000..1a6445be966 --- /dev/null +++ b/intern/SoundSystem/SND_WaveCache.h @@ -0,0 +1,69 @@ +/* + * SND_WaveCache.h + * + * abstract wavecache, a way to organize samples + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef WIN32 +#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning +#endif //WIN32 + +#ifndef __SND_WAVECACHE_H +#define __SND_WAVECACHE_H + +#include "SND_WaveSlot.h" +#include "SoundDefines.h" +#include "SND_SoundObject.h" +#include + +class SND_WaveCache +{ +public: + SND_WaveCache(); + virtual ~SND_WaveCache(); + + SND_WaveSlot* GetWaveSlot(const STR_String& samplename); + + void RemoveAllSamples(); + void RemoveSample(const STR_String& samplename, int buffer); + +private: + std::map m_samplecache; + + SND_WaveSlot* m_bufferList[NUM_BUFFERS]; + + void FreeSamples(); +}; + +#endif //__SND_WAVECACHE_H + diff --git a/intern/SoundSystem/SND_WaveSlot.h b/intern/SoundSystem/SND_WaveSlot.h new file mode 100644 index 00000000000..bc92829d3d3 --- /dev/null +++ b/intern/SoundSystem/SND_WaveSlot.h @@ -0,0 +1,95 @@ +/* + * SND_WaveSlot.cpp + * + * class for storing sample related information + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __SND_WAVESLOT_H +#define __SND_WAVESLOT_H + +#include "STR_String.h" + +class SND_WaveSlot +{ + STR_String m_samplename; + bool m_loaded; + void* m_data; + unsigned int m_buffer; + unsigned int m_sampleformat; + unsigned int m_numberofchannels; + unsigned int m_samplerate; + unsigned int m_bitrate; + unsigned int m_numberofsamples; + unsigned int m_filesize; + +public: + + SND_WaveSlot(): m_loaded(false), + m_data(NULL), + m_buffer(0), + m_sampleformat(0), + m_numberofchannels(0), + m_samplerate(0), + m_bitrate(0), + m_numberofsamples(0), + m_filesize(0) + {}; + ~SND_WaveSlot(); + + void SetSampleName(STR_String samplename); + void SetLoaded(bool loaded); + void SetData(void* data); + void SetBuffer(unsigned int buffer); + void SetSampleFormat(unsigned int sampleformat); + void SetNumberOfChannels(unsigned int numberofchannels); + void SetSampleRate(unsigned int samplerate); + void SetBitRate(unsigned int bitrate); + void SetNumberOfSamples(unsigned int numberofsamples); + void SetFileSize(unsigned int filesize); + + + const STR_String& GetSampleName(); + bool IsLoaded() const; + void* GetData(); + unsigned int GetBuffer() const; + unsigned int GetSampleFormat() const; + unsigned int GetNumberOfChannels() const; + unsigned int GetSampleRate() const; + unsigned int GetBitRate() const; + unsigned int GetNumberOfSamples() const; + unsigned int GetFileSize() const; + +}; + +#endif //__SND_WAVESLOT_H + diff --git a/intern/SoundSystem/SND_test/Makefile b/intern/SoundSystem/SND_test/Makefile new file mode 100644 index 00000000000..2fc531ae37e --- /dev/null +++ b/intern/SoundSystem/SND_test/Makefile @@ -0,0 +1,51 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = soundsystem +DIR = $(OCGDIR)/intern/SoundSystem +ALLTARGETS = $(OBJS) $(DIR)/$(DEBUG_DIR)SoundSystem + +include nan_compile.mk + +CPPFLAGS += $(NAN_LEVEL_1_WARNINGS) + +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I.. -I../SND_BlenderWaveCache -I../SND_OpenAL + +TESTLIB = $(OCGDIR)/gameengine/OpenALSoundSystem/$(DEBUG_DIR)libOpenALSoundSystem.a +TESTLIB += $(OCGDIR)/gameengine/BlenderWaveCache/$(DEBUG_DIR)libBlenderWaveCache.a +TESTLIB += $(OCGDIR)/intern/SoundSystem/$(DEBUG_DIR)libsoundsystem.a +TESTLIB += $(NAN_OPENAL)/lib/libopenal.a + +$(DIR)/$(DEBUG_DIR)SoundSystem: $(OBJS) $(TESTLIB) + $(CC) $(LDFLAGS) -o $@ $(OBJS) $(TESTLIB) -lm -pthread -ldl -lstdc++ diff --git a/intern/SoundSystem/SND_test/SND_test.c b/intern/SoundSystem/SND_test/SND_test.c new file mode 100644 index 00000000000..99de147c8a0 --- /dev/null +++ b/intern/SoundSystem/SND_test/SND_test.c @@ -0,0 +1,157 @@ +/* SND_test.c nov 2000 +* +* testfile for the SND module +* +* janco verduin +* +* $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#include "SND_C-api.h" +#include "BlenderWaveCacheCApi.h" +#include "OpenALC-Api.h" +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(WIN32) +#include +#else +#include +#endif +#include + +static int buf[3]; + +float oPos[3]={3.0, 0.0,-1.0}; +float oVel[3]={0.0, 0.0, 1.0}; +float oOri[6]={0.0, 0.0, 1.0, 0.0, 1.0, 0.0}; + +void* ReadFile(char *filename) +{ + int file, filelen; + void *data = NULL; + +#if defined(WIN32) + file = open(filename, O_BINARY|O_RDONLY); +#else + file = open(filename, 0|O_RDONLY); +#endif + + if (file == -1) { + printf("can't open file.\n"); + printf("press q for quit.\n"); + + } + else { + filelen = lseek(file, 0, SEEK_END); + lseek(file, 0, SEEK_SET); + + if (filelen != 0){ + data = malloc(filelen); + if (read(file, data, filelen) != filelen) { + free(data); + data = NULL; + } + } + close(file); + + } + return (data); +} + +int main(int argc, char* argv[]) +{ + int ch; + char* samplename = NULL; + void* sampleinmemory = NULL; + SND_CacheHandle wavecache = NULL; + SND_SceneHandle scene = NULL; + SND_ObjectHandle object = NULL; + + wavecache = SND_GetWaveCache(); + scene = SND_CreateOpenALScene(wavecache); + + samplename = "2.wav"; + sampleinmemory = ReadFile(samplename); + + if (sampleinmemory) { + + object = SND_CreateObject(); + SND_AddMemoryLocation(samplename, sampleinmemory); + SND_SetSampleName(object, samplename); + SND_AddObject(scene, object); + printf("go your gang...\n"); + printf("1: play\n"); + printf("2: stop\n"); + printf("q: quit\n"); + } + do + { + ch = getchar(); + ch = toupper(ch); + switch (ch) + { + case '1': + { + SND_SetPitch(object, 1.0); + SND_SetGain(object, 1.0); + SND_StartSound(object); + break; + } + case '2': + { + SND_StopSound(object); + break; + } + default: + break; + } + + SND_Proceed(scene); + + } while (ch != 'Q'); + + if (object) { + + SND_RemoveObject(scene, object); + SND_DeleteObject(object); + } + + SND_DeleteScene(scene); + SND_DeleteCache(); + + return 0; + +} diff --git a/intern/SoundSystem/SoundDefines.h b/intern/SoundSystem/SoundDefines.h new file mode 100644 index 00000000000..f7a3a3c6619 --- /dev/null +++ b/intern/SoundSystem/SoundDefines.h @@ -0,0 +1,120 @@ +/* + * SoundDefines.h + * + * this is where all kinds of defines are stored + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __SOUNDDEFINES_H +#define __SOUNDDEFINES_H + +/* the types of devices */ +enum +{ + snd_e_dummydevice = 0, + snd_e_fmoddevice, + snd_e_openaldevice +}; + +/* general stuff */ +#define NUM_BUFFERS 128 +#define NUM_SOURCES 16 + +/* openal related stuff */ +#define AL_LOOPING 0x1007 + +/* fmod related stuff */ +#ifdef WIN32 +#define MIXRATE 22050 +#else +#define MIXRATE 44100 +#endif +#define NUM_FMOD_MIN_HW_CHANNELS 16 +#define NUM_FMOD_MAX_HW_CHANNELS 16 + +/* activelist defines */ +enum +{ + SND_REMOVE_ACTIVE_OBJECT = 0, + SND_ADD_ACTIVE_OBJECT, + SND_DO_NOTHING +}; + +/* playstate flags */ +enum +{ + SND_UNKNOWN = -1, + SND_INITIAL, + SND_MUST_PLAY, + SND_PLAYING, + SND_MUST_STOP, + SND_STOPPED, + SND_MUST_PAUSE, + SND_PAUSED, + SND_MUST_RESUME, + SND_MUST_STOP_WHEN_FINISHED, + SND_MUST_BE_DELETED +}; + +/* loopmodes */ +enum +{ + SND_LOOP_OFF = 0, + SND_LOOP_NORMAL, + SND_LOOP_BIDIRECTIONAL +}; + + +/* cd playstate flags */ +enum +{ + SND_CD_ALL = 0, + SND_CD_TRACK, + SND_CD_TRACKLOOP +}; + +/* sample types */ +enum +{ + SND_WAVE_FORMAT_UNKNOWN = 0, + SND_WAVE_FORMAT_PCM, + SND_WAVE_FORMAT_ADPCM, + SND_WAVE_FORMAT_ALAW = 6, + SND_WAVE_FORMAT_MULAW, + SND_WAVE_FORMAT_DIALOGIC_OKI_ADPCM = 17, + SND_WAVE_FORMAT_CONTROL_RES_VQLPC = 34, + SND_WAVE_FORMAT_GSM_610 = 49, + SND_WAVE_FORMAT_MPEG3 = 85 +}; + +#endif //__SOUNDDEFINES_H + diff --git a/intern/SoundSystem/dummy/Makefile b/intern/SoundSystem/dummy/Makefile new file mode 100644 index 00000000000..5d23d1a8a6a --- /dev/null +++ b/intern/SoundSystem/dummy/Makefile @@ -0,0 +1,45 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = DummySoundSystem +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_1_CPP_WARNINGS) + +CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I../intern +CPPFLAGS += -I.. +CPPFLAGS += -I. diff --git a/intern/SoundSystem/dummy/SND_DummyDevice.cpp b/intern/SoundSystem/dummy/SND_DummyDevice.cpp new file mode 100644 index 00000000000..7b99ec461df --- /dev/null +++ b/intern/SoundSystem/dummy/SND_DummyDevice.cpp @@ -0,0 +1,55 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * SND_FmodDevice derived from SND_IAudioDevice + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef WIN32 +#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning +#endif //WIN32 + +#include "SND_DummyDevice.h" + +SND_DummyDevice::SND_DummyDevice() +{ +} + +SND_DummyDevice::~SND_DummyDevice() +{ +#ifdef ONTKEVER + printf("SND_DummyDevice destructor"); +#endif +} + + diff --git a/intern/SoundSystem/dummy/SND_DummyDevice.h b/intern/SoundSystem/dummy/SND_DummyDevice.h new file mode 100644 index 00000000000..6dff52d40d5 --- /dev/null +++ b/intern/SoundSystem/dummy/SND_DummyDevice.h @@ -0,0 +1,96 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef SND_DUMMYDEVICE +#define SND_DUMMYDEVICE + +#include "SND_AudioDevice.h" + +class SND_DummyDevice : public SND_AudioDevice +{ +public: + SND_DummyDevice(); + ~SND_DummyDevice(); + + bool Init() { return false; } + + SND_WaveSlot* LoadSample(const STR_String& samplename, + void* memlocation, + int size) { return NULL; } + + void InitListener() {}; + void SetListenerGain(float gain) const {}; + void SetDopplerVelocity(MT_Scalar dopplervelocity) const {}; + void SetDopplerFactor(MT_Scalar dopplerfactor) const {}; + void SetListenerRollOffFactor(MT_Scalar rollofffactor) const {}; + + void MakeCurrent() const {}; + + void NextFrame() const {}; + + void SetObjectBuffer(int id, unsigned int buffer) {}; + + int GetPlayState(int id) { return SND_UNKNOWN; } + void PlayObject(int id) {}; + void StopObject(int id) const {}; + void StopAllObjects() {}; + void PauseObject(int id) const {}; + + void SetObjectLoop(int id, unsigned int loopmode) const {}; + void SetObjectLoopPoints(int id, unsigned int loopstart, unsigned int loopend) const {}; + void SetObjectPitch(int id, MT_Scalar pitch) const {}; + void SetObjectGain(int id, MT_Scalar gain) const {}; + void SetObjectMinGain(int id, MT_Scalar mingain) const {}; + void SetObjectMaxGain(int id, MT_Scalar maxgain) const {}; + void SetObjectRollOffFactor(int id, MT_Scalar rolloff) const {}; + void SetObjectReferenceDistance(int id, MT_Scalar distance) const {}; + + void SetObjectTransform(int id, + const MT_Vector3& position, + const MT_Vector3& velocity, + const MT_Matrix3x3& orientation, + const MT_Vector3& lisposition, + const MT_Scalar& rollofffactor) const {}; + void ObjectIs2D(int id) const {}; + + void PlayCD(int track) const {}; + void PauseCD(bool pause) const {}; + void StopCD() const {}; + void SetCDPlaymode(int playmode) const {}; + void SetCDGain(MT_Scalar gain) const {}; + + void StartUsingDSP() {}; + float* GetSpectrum() { return NULL; } + void StopUsingDSP() {}; +}; + +#endif //SND_DUMMYDEVICE + diff --git a/intern/SoundSystem/fmod/Makefile b/intern/SoundSystem/fmod/Makefile new file mode 100644 index 00000000000..d2810e8fa2f --- /dev/null +++ b/intern/SoundSystem/fmod/Makefile @@ -0,0 +1,46 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = FmodSoundSystem +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_1_CPP_WARNINGS) + +CPPFLAGS += -I$(NAN_FMOD)/include +CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I../intern +CPPFLAGS += -I.. +CPPFLAGS += -I. diff --git a/intern/SoundSystem/fmod/SND_FmodDevice.cpp b/intern/SoundSystem/fmod/SND_FmodDevice.cpp new file mode 100644 index 00000000000..06bcbc2f393 --- /dev/null +++ b/intern/SoundSystem/fmod/SND_FmodDevice.cpp @@ -0,0 +1,577 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * SND_FmodDevice derived from SND_IAudioDevice + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef WIN32 +#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning +#endif //WIN32 + +#include "SND_FmodDevice.h" +#include "SoundDefines.h" +#include "SND_Utils.h" + +SND_FmodDevice::SND_FmodDevice() +{ + /* Removed the functionality for checking if noaudio was provided on */ + /* the commandline. */ + m_dspunit = NULL; + + m_audio = true; + + // let's check if we can get fmod to initialize... + if (m_audio) + { + signed char MinHardwareChannels = FSOUND_SetMinHardwareChannels(NUM_FMOD_MIN_HW_CHANNELS); + signed char MaxHardwareChannels = FSOUND_SetMaxHardwareChannels(NUM_FMOD_MAX_HW_CHANNELS); + + if (FSOUND_Init(MIXRATE, NUM_SOURCES, 0)) + { + m_max_channels = FSOUND_GetMaxChannels(); + m_num_hardware_channels = FSOUND_GetNumHardwareChannels(); + m_num_software_channels = NUM_SOURCES; + + // let's get us a wavecache + m_wavecache = new SND_WaveCache(); + + int i; + for (i = 0; i < NUM_BUFFERS; i++) + m_buffers[i] = NULL; + + for (i = 0; i < NUM_SOURCES; i++) + { + m_sources[i] = NULL; + m_frequencies[i] = 0; + m_channels[i] = 0; + } + } + else + { + m_audio = false; + } + } + +#ifdef ONTKEVER + int numdrivers = FSOUND_GetNumDrivers(); + int output = FSOUND_GetOutput(); + int oputputrate = FSOUND_GetOutputRate(); + int mixer = FSOUND_GetMixer(); + + printf("maxchannels is: %d\n", m_max_channels); + printf("num hw channels is: %d\n", m_num_hardware_channels); + printf("num sw channels is: %d\n", m_num_software_channels); + printf("numdrivers is: %d\n", numdrivers); + printf("output is: %d\n", output); + printf("oputputrate is: %d\n", oputputrate); + printf("mixer is: %d\n", mixer); +#endif +} + + + +SND_FmodDevice::~SND_FmodDevice() +{ + // let's see if we used the cd. if not, just leave it alone + SND_CDObject* pCD = SND_CDObject::Instance(); + + if (pCD) + { + this->StopCD(); + SND_CDObject::DisposeSystem(); + } + + StopUsingDSP(); + + FSOUND_Close(); +} + + + +void SND_FmodDevice::UseCD() const +{ + // only fmod has CD support, so only create it here + SND_CDObject::CreateSystem(); +} + + + +void SND_FmodDevice::MakeCurrent() const +{ + // empty +} + + + +SND_WaveSlot* SND_FmodDevice::LoadSample(const STR_String& name, + void* memlocation, + int size) +{ + SND_WaveSlot* waveslot = NULL; + STR_String samplename = name; + + if (m_audio) + { + /* first check if the sample is supported */ + if (SND_IsSampleValid(name, memlocation)) + { + /* create the waveslot */ + waveslot = m_wavecache->GetWaveSlot(samplename); + + if (waveslot) + { + int buffer = waveslot->GetBuffer(); + + /* load the sample from memory? */ + if (size && memlocation) + { + m_buffers[buffer] = FSOUND_Sample_Load(buffer, (char*)memlocation, FSOUND_LOADMEMORY, size); + + /* if the loading succeeded, fill the waveslot with info */ + if (m_buffers[buffer]) + { + int sampleformat = SND_GetSampleFormat(memlocation); + int numberofchannels = SND_GetNumberOfChannels(memlocation); + int samplerate = SND_GetSampleRate(memlocation); + int bitrate = SND_GetBitRate(memlocation); + int numberofsamples = SND_GetNumberOfSamples(memlocation); + + waveslot->SetFileSize(size); + waveslot->SetData(memlocation); + waveslot->SetSampleFormat(sampleformat); + waveslot->SetNumberOfChannels(numberofchannels); + waveslot->SetSampleRate(samplerate); + waveslot->SetBitRate(bitrate); + waveslot->SetNumberOfSamples(numberofsamples); + } + } + /* or from file? */ + else + { + m_buffers[buffer] = FSOUND_Sample_Load(buffer, samplename.Ptr(), FSOUND_LOOP_NORMAL, NULL); + } + +#ifdef ONTKEVER + int error = FSOUND_GetError(); + printf("sample load: errornumber is: %d\n", error); +#endif + + /* if the loading succeeded, mark the waveslot */ + if (m_buffers[buffer]) + { + waveslot->SetLoaded(true); + } + /* or when it failed, free the waveslot */ + else + { + m_wavecache->RemoveSample(waveslot->GetSampleName(), waveslot->GetBuffer()); + waveslot = NULL; + } + } + } + } + + return waveslot; +} + + + + +// listener's and general stuff ////////////////////////////////////////////////////// + + + +/* sets the global dopplervelocity */ +void SND_FmodDevice::SetDopplerVelocity(MT_Scalar dopplervelocity) const +{ + /* not supported by fmod */ + FSOUND_3D_Listener_SetDopplerFactor(dopplervelocity); +} + + + +/* sets the global dopplerfactor */ +void SND_FmodDevice::SetDopplerFactor(MT_Scalar dopplerfactor) const +{ + FSOUND_3D_Listener_SetDopplerFactor(dopplerfactor); +} + + + +/* sets the global rolloff factor */ +void SND_FmodDevice::SetListenerRollOffFactor(MT_Scalar rollofffactor) const +{ + // not implemented in openal +} + + + +void SND_FmodDevice::NextFrame() const +{ + FSOUND_3D_Update(); +} + + + +// set the gain for the listener +void SND_FmodDevice::SetListenerGain(float gain) const +{ + int fmod_gain = (int)(gain * 255); + FSOUND_SetSFXMasterVolume(fmod_gain); +} + + + +void SND_FmodDevice::InitListener() +{ + // initialize the listener with these values that won't change + // (as long as we can have only one listener) + // now we can superimpose all listeners on each other (for they + // have the same settings) + float lispos[3] = {0,0,0}; + float lisvel[3] = {0,0,0}; + + FSOUND_3D_Listener_SetAttributes(lispos, lisvel, 0, -1, 0, 0, 0, 1); +} + + + +// source playstate stuff //////////////////////////////////////////////////////////// + + + +// check if the sound's still playing +int SND_FmodDevice::GetPlayState(int id) +{ + int result = SND_STOPPED; + + // klopt niet, fixen + signed char isplaying = FSOUND_IsPlaying(id); + + if (isplaying) + { + result = SND_PLAYING; + } + +/* hi reevan, just swap // of these 2 lines */ +// return result; + return 0; +} + + + +/* sets the buffer */ +void SND_FmodDevice::SetObjectBuffer(int id, unsigned int buffer) +{ + m_sources[id] = m_buffers[buffer]; +} + + + +// make the source play +void SND_FmodDevice::PlayObject(int id) +{ + m_channels[id] = FSOUND_PlaySound(FSOUND_FREE, m_sources[id]); + m_frequencies[id] = FSOUND_GetFrequency(m_channels[id]); +// printf("fmod: play \n"); +} + + + +// make the source stop +void SND_FmodDevice::StopObject(int id) const +{ + FSOUND_StopSound(m_channels[id]); +// printf("fmod: stop \n"); +} + + + +// stop all sources +void SND_FmodDevice::StopAllObjects() +{ + FSOUND_StopSound(FSOUND_ALL); +} + + + +// pause the source +void SND_FmodDevice::PauseObject(int id) const +{ + FSOUND_StopSound(m_channels[id]); +} + + + +// source properties stuff //////////////////////////////////////////////////////////// + + + +// give openal the object's pitch +void SND_FmodDevice::SetObjectPitch(int id, MT_Scalar pitch) const +{ + pitch = pitch * m_frequencies[id]; + char result = FSOUND_SetFrequency(m_channels[id], (int)pitch); +} + + + +// give openal the object's gain +void SND_FmodDevice::SetObjectGain(int id, MT_Scalar gain) const +{ + int vol = (int)(gain * 255); + FSOUND_SetVolume(m_channels[id], vol); +} + + + +// give openal the object's looping +void SND_FmodDevice::SetObjectLoop(int id, unsigned int loopmode) const +{ +// printf("loopmode: %d\n", loopmode); + switch (loopmode) + { + case SND_LOOP_OFF: + { +#ifndef __APPLE__ + char result = FSOUND_Sample_SetLoopMode(m_sources[id], FSOUND_LOOP_OFF); +#else + char result = FSOUND_SetLoopMode(m_sources[id], FSOUND_LOOP_OFF); +#endif +// char result = FSOUND_SetLoopMode(m_channels[id], FSOUND_LOOP_OFF); + break; + } + case SND_LOOP_NORMAL: + { +#ifndef __APPLE__ + char result = FSOUND_Sample_SetLoopMode(m_sources[id], FSOUND_LOOP_NORMAL); +#else + char result = FSOUND_SetLoopMode(m_sources[id], FSOUND_LOOP_NORMAL); +#endif +// char result = FSOUND_SetLoopMode(m_channels[id], FSOUND_LOOP_NORMAL); + break; + } + case SND_LOOP_BIDIRECTIONAL: + { +#ifndef __APPLE__ + char result = FSOUND_Sample_SetLoopMode(m_sources[id], FSOUND_LOOP_BIDI); +#else + char result = FSOUND_SetLoopMode(m_sources[id], FSOUND_LOOP_BIDI); +#endif +// char result = FSOUND_SetLoopMode(m_channels[id], FSOUND_LOOP_NORMAL); + break; + } + default: + break; + } +} + + + +void SND_FmodDevice::SetObjectLoopPoints(int id, unsigned int loopstart, unsigned int loopend) const +{ + FSOUND_Sample_SetLoopPoints(m_sources[id], loopstart, loopend); +} + + + +void SND_FmodDevice::SetObjectMinGain(int id, MT_Scalar mingain) const +{ + /* not supported by fmod */ +} + + + +void SND_FmodDevice::SetObjectMaxGain(int id, MT_Scalar maxgain) const +{ + /* not supported by fmod */ +} + + + +void SND_FmodDevice::SetObjectRollOffFactor(int id, MT_Scalar rollofffactor) const +{ + /* not supported by fmod */ +} + + + +void SND_FmodDevice::SetObjectReferenceDistance(int id, MT_Scalar referencedistance) const +{ + /* not supported by fmod */ +} + + + +// give openal the object's position +void SND_FmodDevice::ObjectIs2D(int id) const +{ + float obpos[3] = {0,0,0}; + float obvel[3] = {0,0,0}; + + FSOUND_3D_SetAttributes(m_channels[id], obpos, obvel); +} + + + +void SND_FmodDevice::SetObjectTransform(int id, + const MT_Vector3& position, + const MT_Vector3& velocity, + const MT_Matrix3x3& orientation, + const MT_Vector3& lisposition, + const MT_Scalar& rollofffactor) const +{ + float obpos[3]; + float obvel[3]; + + obpos[0] = (float)position[0] * (float)rollofffactor; //x (l/r) + obpos[1] = (float)position[1] * (float)rollofffactor; + obpos[2] = (float)position[2] * (float)rollofffactor; + + velocity.getValue(obvel); + FSOUND_3D_SetAttributes(m_channels[id], obpos, obvel); +} + + + +// cd support stuff //////////////////////////////////////////////////////////// + + +void SND_FmodDevice::PlayCD(int track) const +{ +#ifndef __APPLE__ + signed char result = FSOUND_CD_Play(track); +#else + signed char result = FSOUND_CD_Play(0, track); +#endif + +#ifdef ONTKEVER + printf("SND_FmodDevice::PlayCD(): track=%d, result=%d\n", track, (int)result); +#endif +} + + + +void SND_FmodDevice::PauseCD(bool pause) const +{ +#ifndef __APPLE__ + signed char result = FSOUND_CD_SetPaused(pause); +#else + signed char result = FSOUND_CD_SetPaused(0, pause); +#endif + +#ifdef ONTKEVER + printf("SND_FmodDevice::PauseCD(): pause=%d, result=%d\n", pause, (int)result); +#endif +} + + + +void SND_FmodDevice::StopCD() const +{ + SND_CDObject* pCD = SND_CDObject::Instance(); + + if (pCD) + { + if (pCD->GetUsed()) + { +#ifndef __APPLE__ + signed char result = FSOUND_CD_Stop(); +#else + signed char result = FSOUND_CD_Stop(0); +#endif + +#ifdef ONTKEVER + printf("SND_FmodDevice::StopCD(): result=%d\n", (int)result); +#endif + } + } +} + + + +void SND_FmodDevice::SetCDPlaymode(int playmode) const +{ +#ifndef __APPLE__ + FSOUND_CD_SetPlayMode(playmode); +#else + FSOUND_CD_SetPlayMode(0, playmode); +#endif + +#ifdef ONTKEVER + printf("SND_FmodDevice::SetCDPlaymode(): playmode=%d,\n", playmode); +#endif +} + + + +void SND_FmodDevice::SetCDGain(MT_Scalar gain) const +{ + int volume = gain * 255; +#ifndef __APPLE__ + signed char result = FSOUND_CD_SetVolume(volume); +#else + signed char result = FSOUND_CD_SetVolume(0, volume); +#endif + +#ifdef ONTKEVER + printf("SND_FmodDevice::SetCDGain(): gain=%f, volume=%d, result=%d\n", gain, volume, (int)result); +#endif +} + + + +void SND_FmodDevice::StartUsingDSP() +{ + m_dspunit = FSOUND_DSP_GetFFTUnit(); + + FSOUND_DSP_SetActive(m_dspunit, true); +} + + + +float* SND_FmodDevice::GetSpectrum() +{ + m_spectrum = FSOUND_DSP_GetSpectrum(); + + return m_spectrum; +} + + + +void SND_FmodDevice::StopUsingDSP() +{ + if (m_dspunit) + FSOUND_DSP_SetActive(m_dspunit, false); +} diff --git a/intern/SoundSystem/fmod/SND_FmodDevice.h b/intern/SoundSystem/fmod/SND_FmodDevice.h new file mode 100644 index 00000000000..d44cfb9d937 --- /dev/null +++ b/intern/SoundSystem/fmod/SND_FmodDevice.h @@ -0,0 +1,106 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef SND_FMODDEVICE +#define SND_FMODDEVICE + +#include "fmod.h" +#include "SND_AudioDevice.h" +#include "SoundDefines.h" + +class SND_FmodDevice : public SND_AudioDevice +{ +public: + SND_FmodDevice(); + ~SND_FmodDevice(); + + SND_WaveSlot* LoadSample(const STR_String& samplename, + void* memlocation, + int size); + + void InitListener(); + void SetListenerGain(float gain) const; + void SetDopplerVelocity(MT_Scalar dopplervelocity) const; + void SetDopplerFactor(MT_Scalar dopplerfactor) const; + void SetListenerRollOffFactor(MT_Scalar rollofffactor) const; + + void MakeCurrent() const; + void NextFrame() const; + void UseCD() const; + + void SetObjectBuffer(int id, unsigned int buffer); + int GetPlayState(int id); + void PlayObject(int id); + void StopObject(int id) const; + void StopAllObjects(); + void PauseObject(int id) const; + + void SetObjectLoop(int id, unsigned int loopmode) const; + void SetObjectLoopPoints(int id, unsigned int loopstart, unsigned int loopend) const; + void SetObjectPitch(int id, MT_Scalar pitch) const; + void SetObjectGain(int id, MT_Scalar gain) const; + void SetObjectMinGain(int id, MT_Scalar mingain) const; + void SetObjectMaxGain(int id, MT_Scalar maxgain) const; + void SetObjectRollOffFactor(int id, MT_Scalar rolloff) const; + void SetObjectReferenceDistance(int id, MT_Scalar distance) const; + + void SetObjectTransform(int id, + const MT_Vector3& position, + const MT_Vector3& velocity, + const MT_Matrix3x3& orientation, + const MT_Vector3& lisposition, + const MT_Scalar& rollofffactor) const; + void ObjectIs2D(int id) const; + + void PlayCD(int track) const; + void PauseCD(bool pause) const; + void StopCD() const; + void SetCDPlaymode(int playmode) const; + void SetCDGain(MT_Scalar gain) const; + + void StartUsingDSP(); + float* GetSpectrum(); + void StopUsingDSP(); + +private: + FSOUND_SAMPLE* m_buffers[NUM_BUFFERS]; + FSOUND_SAMPLE* m_sources[NUM_SOURCES]; + FSOUND_DSPUNIT* m_dspunit; + int m_frequencies[NUM_SOURCES]; + int m_max_channels; + int m_num_hardware_channels; + int m_num_software_channels; + int m_channels[NUM_SOURCES]; + float* m_spectrum; +}; + +#endif //SND_FMODDEVICE + diff --git a/intern/SoundSystem/intern/Makefile b/intern/SoundSystem/intern/Makefile new file mode 100644 index 00000000000..cf793bdba25 --- /dev/null +++ b/intern/SoundSystem/intern/Makefile @@ -0,0 +1,49 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = SoundSystem +DIR = $(OCGDIR)/intern/SoundSystem + +include nan_compile.mk + +CCFLAGS += $(LEVEL_1_CPP_WARNINGS) + +CPPFLAGS += -I$(NAN_FMOD)/include +CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I../../../source/blender/include +CPPFLAGS += -I../dummy +CPPFLAGS += -I../fmod +CPPFLAGS += -I../openal +CPPFLAGS += -I.. +CPPFLAGS += -I. diff --git a/intern/SoundSystem/intern/SND_AudioDevice.cpp b/intern/SoundSystem/intern/SND_AudioDevice.cpp new file mode 100644 index 00000000000..828edaed4b4 --- /dev/null +++ b/intern/SoundSystem/intern/SND_AudioDevice.cpp @@ -0,0 +1,245 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "SND_AudioDevice.h" +#include "SND_SoundObject.h" + +#ifdef WIN32 +// This warning tells us about truncation of __long__ stl-generated names. +// It can occasionally cause DevStudio to have internal compiler warnings. +#pragma warning( disable : 4786 ) +#endif + + +SND_AudioDevice::SND_AudioDevice() +{ + m_wavecache = NULL; + m_audio = false; + + for (int i = 0; i < NUM_SOURCES; i++) + { + m_idObjectArray[i] = new SND_IdObject(); + m_idObjectArray[i]->SetId(i); + m_idObjectArray[i]->SetSoundObject(NULL); + m_idObjectList.addTail(m_idObjectArray[i]); + } +} + + + +SND_AudioDevice::~SND_AudioDevice() +{ + for (int i = 0; i < NUM_SOURCES; i++) + { + delete m_idObjectArray[i]; + m_idObjectArray[i] = NULL; + } + + if (m_wavecache) + { + delete m_wavecache; + m_wavecache = NULL; + } +} + + + +bool SND_AudioDevice::IsInitialized() +{ + return m_audio; +} + + + +SND_WaveCache* SND_AudioDevice::GetWaveCache() const +{ + return m_wavecache; +} + + + +/* seeks an unused id and returns it */ +bool SND_AudioDevice::GetNewId(SND_SoundObject* pObject) +{ +#ifdef ONTKEVER + printf("SND_AudioDevice::GetNewId\n"); +#endif + + bool result = false; + + // first, get the oldest (the first) idobject + SND_IdObject* pIdObject = (SND_IdObject*)m_idObjectList.getHead(); + + if (pIdObject->isTail()) + { + } + else + { + // find the first id object which doesn't have a high priority soundobject + bool ThisSoundMustStay = false; + bool OutOfIds = false; + + do + { + // if no soundobject present, it's seat may be taken + if (pIdObject->GetSoundObject()) + { + // and also if it ain't highprio + if (pIdObject->GetSoundObject()->IsHighPriority()) + { + ThisSoundMustStay = true; + pIdObject = (SND_IdObject*)pIdObject->getNext(); + + // if the last one is a priority sound too, then there are no id's left + // and we won't add any new sounds + if (pIdObject->isTail()) + OutOfIds = true; + } + else + { + ThisSoundMustStay = false; + } + } + else + { + ThisSoundMustStay = false; + } + + } while (ThisSoundMustStay && !OutOfIds); + + if (!OutOfIds) + { + SND_SoundObject* oldobject = pIdObject->GetSoundObject(); + + // revoke the old object if present + if (oldobject) + { +#ifdef ONTKEVER + printf("oldobject: %x\n", oldobject); +#endif + RevokeSoundObject(oldobject); + } + + // set the new soundobject into the idobject + pIdObject->SetSoundObject(pObject); + + // set the id into the soundobject + int id = pIdObject->GetId(); + pObject->SetId(id); + + // connect the new id to the buffer the sample is stored in + SetObjectBuffer(id, pObject->GetBuffer()); + + // remove the idobject from the list and add it in the back again + pIdObject->remove(); + m_idObjectList.addTail(pIdObject); + + result = true; + } + } + + return result; +} + + + +void SND_AudioDevice::ClearId(SND_SoundObject* pObject) +{ +#ifdef ONTKEVER + printf("SND_AudioDevice::ClearId\n"); +#endif + + if (pObject) + { + int id = pObject->GetId(); + + if (id != -1) + { + // lets get the idobject belonging to the soundobject + SND_IdObject* pIdObject = m_idObjectArray[id]; + SND_SoundObject* oldobject = pIdObject->GetSoundObject(); + + if (oldobject) + { + RevokeSoundObject(oldobject); + + // clear the idobject from the soundobject + pIdObject->SetSoundObject(NULL); + } + + // remove the idobject and place it in front + pIdObject->remove(); + m_idObjectList.addHead(pIdObject); + } + } +} + + + +void SND_AudioDevice::RevokeSoundObject(SND_SoundObject* pObject) +{ +#ifdef ONTKEVER + printf("SND_AudioDevice::RevokeSoundObject\n"); +#endif + + // stop the soundobject + int id = pObject->GetId(); + + if (id >= 0 && id < NUM_SOURCES) + { + StopObject(id); + + // remove the object from the 'activelist' + pObject->SetActive(false); + +#ifdef ONTKEVER + printf("pObject->remove();\n"); +#endif + } + + // make sure its id is invalid + pObject->SetId(-1); +} + +/* +void SND_AudioDevice::RemoveSample(const char* filename) +{ + if (m_wavecache) + m_wavecache->RemoveSample(filename); +} +*/ + +void SND_AudioDevice::RemoveAllSamples() +{ + if (m_wavecache) + m_wavecache->RemoveAllSamples(); +} + diff --git a/intern/SoundSystem/intern/SND_AudioDevice.h b/intern/SoundSystem/intern/SND_AudioDevice.h new file mode 100644 index 00000000000..6edd52955ae --- /dev/null +++ b/intern/SoundSystem/intern/SND_AudioDevice.h @@ -0,0 +1,118 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef SND_AUDIODEVICE +#define SND_AUDIODEVICE + +#include "SND_IAudioDevice.h" +#include "SoundDefines.h" +#include "SND_IdObject.h" + +class SND_AudioDevice : public SND_IAudioDevice +{ +public: + SND_AudioDevice(); + virtual ~SND_AudioDevice(); + + virtual bool IsInitialized(); + + SND_WaveCache* GetWaveCache() const; + + bool GetNewId(SND_SoundObject* pObject); + void ClearId(SND_SoundObject* pObject); + + void UseCD() const {}; + + /* to be implemented in derived class + + virtual SND_WaveSlot* LoadSample(const STR_String& samplename, + void* memlocation, + int size) =0; + */ +// void RemoveSample(const char* filename); + void RemoveAllSamples(); + + /* to be implemented in derived class + + virtual void InitListener()=0; + virtual void SetListenerGain(float gain) const =0; + virtual void SetDopplerVelocity(MT_Scalar dopplervelocity) const =0; + virtual void SetDopplerFactor(MT_Scalar dopplerfactor) const =0; + virtual void SetListenerRollOffFactor(MT_Scalar rollofffactor) const =0; + + virtual void MakeCurrent() const =0; + + virtual void UpdateDevice() const =0; + + virtual void SetObjectBuffer(int id, unsigned int buffer)=0; + virtual int GetPlayState(int id)=0; + virtual void PlayObject(int id)=0; + virtual void StopObject(int id) const =0; + virtual void StopAllObjects()=0; + virtual void PauseObject(int id) const =0; + + virtual void SetObjectLoop(int id, bool loop) const =0; + virtual void SetObjectLoopPoints(int id, unsigned int loopstart, unsigned int loopend) const =0; + virtual void SetObjectPitch(int id, MT_Scalar pitch) const =0; + virtual void SetObjectGain(int id, MT_Scalar gain) const =0; + virtual void SetObjectRollOffFactor(int id, MT_Scalar rolloff) const =0; + virtual void SetObjectMinGain(int id, MT_Scalar mingain) const =0; + virtual void SetObjectMaxGain(int id, MT_Scalar maxgain) const =0; + virtual void SetObjectReferenceDistance(int id, MT_Scalar referencedistance) const =0; + + virtual void SetObjectTransform(int id, + const MT_Vector3& position, + const MT_Vector3& velocity, + const MT_Matrix3x3& orientation, + const MT_Vector3& lisposition, + const MT_Scalar& rollofffactor) const =0; + virtual void ObjectIs2D(int id) const =0; + + virtual void PlayCD(int track) const =0; + virtual void PauseCD(bool pause) const =0; + virtual void StopCD() const =0; + virtual void SetCDPlaymode(int playmode) const =0; + virtual void SetCDGain(MT_Scalar gain) const =0; + virtual float* GetSpectrum() =0; + */ + +protected: + bool m_audio; + GEN_List m_idObjectList; + SND_IdObject* m_idObjectArray[NUM_SOURCES]; + SND_WaveCache* m_wavecache; + +private: + void RevokeSoundObject(SND_SoundObject* pObject); +}; + +#endif //SND_AUDIODEVICE + diff --git a/intern/SoundSystem/intern/SND_C-api.cpp b/intern/SoundSystem/intern/SND_C-api.cpp new file mode 100644 index 00000000000..1b03d66562c --- /dev/null +++ b/intern/SoundSystem/intern/SND_C-api.cpp @@ -0,0 +1,395 @@ +/* + * SND_C-Api.cpp + * + * C Api for soundmodule + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "SND_C-api.h" +#include "SND_DeviceManager.h" +#include "SND_Scene.h" + +#ifdef WIN32 +#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning +#endif //WIN32 + + + +void SND_SetDeviceType(int device_type) +{ + SND_DeviceManager::SetDeviceType(device_type); +} + + + +SND_AudioDeviceInterfaceHandle SND_GetAudioDevice() +{ + SND_IAudioDevice* audiodevice = NULL; + + SND_DeviceManager::Subscribe(); + audiodevice = SND_DeviceManager::Instance(); + + if (!audiodevice->IsInitialized()) + { + SND_DeviceManager::SetDeviceType(snd_e_dummydevice); + audiodevice = SND_DeviceManager::Instance(); + } + + return (SND_AudioDeviceInterfaceHandle)audiodevice; +} + + + +void SND_ReleaseDevice() +{ + SND_DeviceManager::Unsubscribe(); +} + + + +int SND_IsPlaybackWanted(SND_SceneHandle scene) +{ + assert(scene); + bool result = ((SND_Scene*)scene)->IsPlaybackWanted(); + + return (int)result; +} + + + +// create a scene +SND_SceneHandle SND_CreateScene(SND_AudioDeviceInterfaceHandle audiodevice) +{ + // initialize sound scene and object + SND_Scene* scene = new SND_Scene((SND_IAudioDevice*)audiodevice); + + return (SND_SceneHandle)scene; +} + + + +void SND_DeleteScene(SND_SceneHandle scene) +{ + assert(scene); + delete (SND_Scene*)scene; +} + + + +int SND_AddSample(SND_SceneHandle scene, + const char* filename, + void* memlocation, + int size) +{ + assert(scene); + assert(memlocation); + int buffer = ((SND_Scene*)scene)->LoadSample(filename, memlocation, size); + + return buffer; +} + + + +void SND_RemoveAllSamples(SND_SceneHandle scene) +{ + assert(scene); + ((SND_Scene*)scene)->RemoveAllSamples(); +} + + + +int SND_CheckBuffer(SND_SceneHandle scene, SND_ObjectHandle object) +{ + assert(scene); + assert(object); + int result = (int)((SND_Scene*)scene)->CheckBuffer((SND_SoundObject*)object); + + return result; +} + + + +void SND_AddSound(SND_SceneHandle scene, SND_ObjectHandle object) +{ + assert(scene); + assert(object); + ((SND_Scene*)scene)->AddObject((SND_SoundObject *)object); +} + + + +void SND_RemoveSound(SND_SceneHandle scene, SND_ObjectHandle object) +{ + assert(scene); + assert(object); + ((SND_Scene*)scene)->DeleteObject((SND_SoundObject *)object); +} + + + +void SND_RemoveAllSounds(SND_SceneHandle scene) +{ + assert(scene); + ((SND_Scene*)scene)->RemoveAllObjects(); +} + + + +void SND_StopAllSounds(SND_SceneHandle scene) +{ + assert(scene); + ((SND_Scene*)scene)->StopAllObjects(); +} + + + +void SND_Proceed(SND_AudioDeviceInterfaceHandle audiodevice, SND_SceneHandle scene) +{ + assert(scene); + ((SND_Scene*)scene)->Proceed(); + ((SND_IAudioDevice*)audiodevice)->NextFrame(); +} + + + +SND_ListenerHandle SND_GetListener(SND_SceneHandle scene) +{ + assert(scene); + return (SND_ListenerHandle)((SND_Scene*)scene)->GetListener(); +} + + + +void SND_SetListenerGain(SND_SceneHandle scene, double gain) +{ + assert(scene); + SND_SoundListener* listener = ((SND_Scene*)scene)->GetListener(); + listener->SetGain((MT_Scalar)gain); +} + + + +void SND_SetDopplerFactor(SND_SceneHandle scene, double dopplerfactor) +{ + assert(scene); + SND_SoundListener* listener = ((SND_Scene*)scene)->GetListener(); + listener->SetDopplerFactor(dopplerfactor); +} + + + +void SND_SetDopplerVelocity(SND_SceneHandle scene, double dopplervelocity) +{ + assert(scene); + SND_SoundListener* listener = ((SND_Scene*)scene)->GetListener(); + listener->SetDopplerVelocity(dopplervelocity); +} + + + +// Object instantiation +SND_ObjectHandle SND_CreateSound() +{ + return (SND_ObjectHandle)new SND_SoundObject(); +} + + + +void SND_DeleteSound(SND_ObjectHandle object) +{ + assert(object); + delete (SND_SoundObject*)object; +} + + + +// Object control +void SND_StartSound(SND_SceneHandle scene, SND_ObjectHandle object) +{ + assert(scene); + assert(object); + ((SND_Scene*)scene)->AddActiveObject((SND_SoundObject*)object, 0); +} + + + +void SND_StopSound(SND_SceneHandle scene, SND_ObjectHandle object) +{ + assert(scene); + assert(object); + ((SND_Scene*)scene)->RemoveActiveObject((SND_SoundObject*)object); +} + + + +void SND_PauseSound(SND_SceneHandle scene, SND_ObjectHandle object) +{ + assert(scene); + assert(object); + ((SND_Scene*)scene)->RemoveActiveObject((SND_SoundObject*)object); +} + + + +void SND_SetSampleName(SND_ObjectHandle object, char* samplename) +{ + assert(object); + STR_String name = samplename; + ((SND_SoundObject*)object)->SetSampleName(name); +} + + + +void SND_SetGain(SND_ObjectHandle object, double gain) +{ + assert(object); + ((SND_SoundObject*)object)->SetGain(gain); +} + + + +void SND_SetMinimumGain(SND_ObjectHandle object, double minimumgain) +{ + assert(object); + ((SND_SoundObject*)object)->SetMinGain(minimumgain); +} + + + +void SND_SetMaximumGain(SND_ObjectHandle object, double maximumgain) +{ + assert(object); + ((SND_SoundObject*)object)->SetMaxGain(maximumgain); +} + + + +void SND_SetRollOffFactor(SND_ObjectHandle object, double rollofffactor) +{ + assert(object); + ((SND_SoundObject*)object)->SetRollOffFactor(rollofffactor); +} + + + +void SND_SetReferenceDistance(SND_ObjectHandle object, double referencedistance) +{ + assert(object); + ((SND_SoundObject*)object)->SetReferenceDistance(referencedistance); +} + + + +void SND_SetPitch(SND_ObjectHandle object, double pitch) +{ + assert(object); + ((SND_SoundObject*)object)->SetPitch(pitch); +} + + + +void SND_SetPosition(SND_ObjectHandle object, double* position) +{ + assert(object); + ((SND_SoundObject*)object)->SetPosition(position); +} + + + +void SND_SetVelocity(SND_ObjectHandle object, double* velocity) +{ + assert(object); + ((SND_SoundObject*)object)->SetVelocity(velocity); +} + + + +void SND_SetOrientation(SND_ObjectHandle object, double* orientation) +{ + assert(object); + ((SND_SoundObject*)object)->SetOrientation(orientation); +} + + + +void SND_SetLoopMode(SND_ObjectHandle object, int loopmode) +{ + assert(object); + ((SND_SoundObject*)object)->SetLoopMode(loopmode); +} + + + +void SND_SetLoopPoints(SND_ObjectHandle object, unsigned int loopstart, unsigned int loopend) +{ + assert(object); + ((SND_SoundObject*)object)->SetLoopStart(loopstart); + ((SND_SoundObject*)object)->SetLoopEnd(loopend); +} + + + +float SND_GetGain(SND_ObjectHandle object) +{ + assert(object); + MT_Scalar gain = ((SND_SoundObject*)object)->GetGain(); + return (float) gain; +} + + + +float SND_GetPitch(SND_ObjectHandle object) +{ + assert(object); + MT_Scalar pitch = ((SND_SoundObject*)object)->GetPitch(); + return (float) pitch; +} + + + +int SND_GetLoopMode(SND_ObjectHandle object) +{ + assert(object); + return ((SND_SoundObject*)object)->GetLoopMode(); +} + + + +int SND_GetPlaystate(SND_ObjectHandle object) +{ + assert(object); + return ((SND_SoundObject*)object)->GetPlaystate(); +} diff --git a/intern/SoundSystem/intern/SND_CDObject.cpp b/intern/SoundSystem/intern/SND_CDObject.cpp new file mode 100644 index 00000000000..e4fcdfaceeb --- /dev/null +++ b/intern/SoundSystem/intern/SND_CDObject.cpp @@ -0,0 +1,185 @@ +/* + * SND_CDObject.cpp + * + * Implementation for CD playback + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "SND_CDObject.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +SND_CDObject* SND_CDObject::m_instance = NULL; + +bool SND_CDObject::CreateSystem() +{ + bool result = false; + + if (!m_instance) + { + m_instance = new SND_CDObject(); + result = true; + } + + return result; +} + + + +bool SND_CDObject::DisposeSystem() +{ + bool result = false; + + if (m_instance) + { + delete m_instance; + m_instance = NULL; + result = true; + } + + return result; +} + + + +SND_CDObject* SND_CDObject::Instance() +{ + return m_instance; +} + + + +SND_CDObject::SND_CDObject() +{ + m_gain = 1; + m_playmode = SND_CD_ALL; + m_track = 1; + m_playstate = SND_STOPPED; + m_used = false; + + // don't set the cd standard on modified: + // if not used, we don't wanna touch it (performance) + m_modified = false; +} + + + +SND_CDObject::~SND_CDObject() +{ +} + + + +void SND_CDObject::SetGain(MT_Scalar gain) +{ + m_gain = gain; + m_modified = true; +} + + + +void SND_CDObject::SetPlaymode(int playmode) +{ + m_playmode = playmode; +} + + + +void SND_CDObject::SetPlaystate(int playstate) +{ + m_playstate = playstate; +} + + + +void SND_CDObject::SetTrack(int track) +{ + m_track = track; +} + + + +int SND_CDObject::GetTrack() const +{ + return m_track; +} + + + +MT_Scalar SND_CDObject::GetGain() const +{ + return m_gain; +} + + +int SND_CDObject::GetPlaystate() const +{ + return m_playstate; +} + + + +bool SND_CDObject::IsModified() const +{ + return m_modified; +} + + + +void SND_CDObject::SetModified(bool modified) +{ + m_modified = modified; +} + + + +int SND_CDObject::GetPlaymode() const +{ + return m_playmode; +} + + + +void SND_CDObject::SetUsed() +{ + m_used = true; +} + + + +bool SND_CDObject::GetUsed() +{ + return m_used; +} + diff --git a/intern/SoundSystem/intern/SND_DeviceManager.cpp b/intern/SoundSystem/intern/SND_DeviceManager.cpp new file mode 100644 index 00000000000..37487686d71 --- /dev/null +++ b/intern/SoundSystem/intern/SND_DeviceManager.cpp @@ -0,0 +1,144 @@ +/* + * SND_DeviceManager.h + * + * singleton for creating, switching and deleting audiodevices + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "SND_DeviceManager.h" +#include "SND_DependKludge.h" +#include "SND_DummyDevice.h" +#ifdef USE_FMOD +#include "SND_FmodDevice.h" +#endif +#ifdef USE_OPENAL +#include "SND_OpenALDevice.h" +#endif + +SND_IAudioDevice* SND_DeviceManager::m_instance = NULL; +int SND_DeviceManager::m_subscriptions = 0; + +#ifdef USE_OPENAL +int SND_DeviceManager::m_device_type = snd_e_openaldevice; +#else +# ifdef USE_FMOD +int SND_DeviceManager::m_device_type = snd_e_fmoddevice; +# else +int SND_DeviceManager::m_device_type = snd_e_dummydevice; +# endif +#endif + +void SND_DeviceManager::Subscribe() +{ + ++m_subscriptions; +} + + + +void SND_DeviceManager::Unsubscribe() +{ + --m_subscriptions; + + // only release memory if there is a m_instance but no subscriptions left + if (m_subscriptions == 0 && m_instance) + { + delete m_instance; + m_instance = NULL; + } + + if (m_subscriptions < 0) + m_subscriptions = 0; +} + + + +SND_IAudioDevice* SND_DeviceManager::Instance() +{ + // only give away an instance if there are subscriptions + if (m_subscriptions) + { + // if there's no instance yet, set and create a new one + if (m_instance == NULL) + { + SetDeviceType(m_device_type); + } + + return m_instance; + } + else + { + return NULL; + } +} + + + +void SND_DeviceManager::SetDeviceType(int device_type) +{ + // if we want to change devicetype, first delete the old one + if (m_instance) + { + delete m_instance; + m_instance = NULL; + } + + // let's create the chosen device + switch (device_type) + { +#ifdef USE_FMOD + case snd_e_fmoddevice: + { + m_instance = new SND_FmodDevice(); + m_device_type = device_type; + break; + } +#endif +#ifdef USE_OPENAL + case snd_e_openaldevice: + { + m_instance = new SND_OpenALDevice(); + m_device_type = device_type; + break; + } +#endif + default: + { + m_instance = new SND_DummyDevice(); + m_device_type = device_type; + break; + } + } +} diff --git a/intern/SoundSystem/intern/SND_IdObject.cpp b/intern/SoundSystem/intern/SND_IdObject.cpp new file mode 100644 index 00000000000..eac95de64a4 --- /dev/null +++ b/intern/SoundSystem/intern/SND_IdObject.cpp @@ -0,0 +1,79 @@ +/* + * SND_IdObject.cpp + * + * Object for storing runtime data, like id's, soundobjects etc + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "SND_IdObject.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +SND_IdObject::SND_IdObject() +{ +} + + + +SND_IdObject::~SND_IdObject() +{ +} + + + +SND_SoundObject* SND_IdObject::GetSoundObject() +{ + return m_soundObject; +} + + + +void SND_IdObject::SetSoundObject(SND_SoundObject* pObject) +{ + m_soundObject = pObject; +} + + + +int SND_IdObject::GetId() +{ + return m_id; +} + + + +void SND_IdObject::SetId(int id) +{ + m_id = id; +} diff --git a/intern/SoundSystem/intern/SND_IdObject.h b/intern/SoundSystem/intern/SND_IdObject.h new file mode 100644 index 00000000000..fc9608b97bf --- /dev/null +++ b/intern/SoundSystem/intern/SND_IdObject.h @@ -0,0 +1,61 @@ +/* + * SND_IdObject.h + * + * Object for storing runtime data, like id's, soundobjects etc + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __SND_IDOBJECT_H +#define __SND_IDOBJECT_H + +#include "SND_SoundObject.h" +#include "GEN_List.h" +#include "SoundDefines.h" + +class SND_IdObject : public GEN_Link +{ + SND_SoundObject* m_soundObject; + int m_id; + +public: + SND_IdObject(); + virtual ~SND_IdObject(); + + SND_SoundObject* GetSoundObject(); + void SetSoundObject(SND_SoundObject* pObject); + + int GetId(); + void SetId(int id); +}; + +#endif //__SND_OBJECT_H + diff --git a/intern/SoundSystem/intern/SND_Scene.cpp b/intern/SoundSystem/intern/SND_Scene.cpp new file mode 100644 index 00000000000..ffb1cd44108 --- /dev/null +++ b/intern/SoundSystem/intern/SND_Scene.cpp @@ -0,0 +1,563 @@ +/* +* SND_Scene.cpp +* +* The scene for sounds. +* +* $Id$ +* + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef WIN32 +#pragma warning (disable:4786) // Get rid of stupid stl-visual compiler debug warning +#endif //WIN32 + +#include "SND_Scene.h" +#include "SND_DependKludge.h" +#include "SND_IAudioDevice.h" + +#include +#include + +//static unsigned int tijd = 0; + +SND_Scene::SND_Scene(SND_IAudioDevice* audiodevice) + : m_audiodevice(audiodevice) +{ + if (m_audiodevice) + m_wavecache = m_audiodevice->GetWaveCache(); + + if (!m_wavecache || !audiodevice) + { + m_audio = false; + } + else + { + //if so, go ahead! + m_audio = true; +#ifdef ONTKEVER + printf("SND_Scene::SND_Scene() m_audio == true\n"); +#endif + m_audiodevice->InitListener(); + } + + IsPlaybackWanted(); +} + + + +SND_Scene::~SND_Scene() +{ + StopAllObjects(); +} + + + +// check if audioplayback is wanted +bool SND_Scene::IsPlaybackWanted() +{ + /* Removed the functionality for checking if noaudio was provided on */ + /* the commandline. */ + if (m_audiodevice && m_wavecache) + { + m_audioplayback = true; + } + else + { + StopAllObjects(); + m_audioplayback = false; + } + + return m_audioplayback; +} + + + +int SND_Scene::LoadSample(const STR_String& samplename, + void* memlocation, + int size) +{ + int result = -1; + + if (m_audiodevice) + { + SND_WaveSlot* waveslot = m_audiodevice->LoadSample(samplename, memlocation, size); + + if (waveslot) + result = waveslot->GetBuffer(); + } + + return result; +} + + + +void SND_Scene::RemoveAllSamples() +{ + if (m_audio && m_audiodevice) + m_audiodevice->RemoveAllSamples(); +} + + + +bool SND_Scene::CheckBuffer(SND_SoundObject* pObject) +{ + bool result = false; + + if (pObject && m_wavecache) + { + SND_WaveSlot* waveslot = m_wavecache->GetWaveSlot(pObject->GetSampleName()); + + if (waveslot) + { + pObject->SetBuffer(waveslot->GetBuffer()); + + result = true; + } + } + + return result; +} + + + +bool SND_Scene::IsSampleLoaded(STR_String& samplename) +{ + bool result = false; + + if (samplename && m_wavecache) + { + SND_WaveSlot* waveslot = m_wavecache->GetWaveSlot(samplename); + + if (waveslot && waveslot->IsLoaded()) + result = true; + } + + return result; +} + + + +void SND_Scene::AddObject(SND_SoundObject* pObject) +{ + if (m_audio) + { + STR_String samplename = pObject->GetSampleName(); + SND_WaveSlot* slot = NULL; + + // don't add the object if no valid sample is referenced + if (samplename != "") + { + // check if the sample is already loaded + slot = m_wavecache->GetWaveSlot(samplename); + } + + if (slot) + { + pObject->SetBuffer(slot->GetBuffer()); + + // needed for expected lifespan of the sample, but ain't necesary anymore i think + MT_Scalar samplelength = slot->GetNumberOfSamples(); + MT_Scalar samplerate = slot->GetSampleRate(); + MT_Scalar soundlength = samplelength/samplerate; + pObject->SetLength(soundlength); + + // add the object to the list + m_soundobjects.insert((SND_SoundObject*)pObject); + } + } +} + + + +void SND_Scene::SetListenerTransform(const MT_Vector3& pos, + const MT_Vector3& vel, + const MT_Matrix3x3& ori) +{ + if (m_audio) + { + GetListener()->SetPosition(pos); + GetListener()->SetVelocity(vel); + GetListener()->SetOrientation(ori); + } +} + + + +void SND_Scene::UpdateListener() +{ + // process the listener if modified + if (m_listener.IsModified()) + { + m_audiodevice->SetListenerGain(m_listener.GetGain()); + + // fmod doesn't support dopplervelocity, so just use the dopplerfactor instead +#ifdef USE_FMOD + m_audiodevice->SetDopplerFactor(m_listener.GetDopplerVelocity()); +#else + m_audiodevice->SetDopplerVelocity(m_listener.GetDopplerVelocity()); + m_audiodevice->SetDopplerFactor(m_listener.GetDopplerFactor()); +#endif + m_listener.SetModified(false); + } +} + + + +void SND_Scene::AddActiveObject(SND_SoundObject* pObject, MT_Scalar curtime) +{ + if (m_audio) + { + if (pObject) + { +#ifdef ONTKEVER + printf("SND_Scene::AddActiveObject\n"); +#endif + + // first check if the object is already on the list + if (pObject->IsActive()) + { + pObject->SetTimeStamp(curtime); + pObject->StartSound(); + } + else + { + pObject->SetTimeStamp(curtime); + + // compute the expected lifespan + pObject->SetLifeSpan(); + + // lets give the new active-to-be object an id + if (m_audiodevice->GetNewId(pObject)) + { + // and add the object + m_activeobjects.addTail(pObject); + pObject->StartSound(); + pObject->SetActive(true); + } + } + } + } +} + + + +void SND_Scene::RemoveActiveObject(SND_SoundObject* pObject) +{ + if (m_audio) + { + if (pObject) + { +#ifdef ONTKEVER + printf("SND_Scene::RemoveActiveObject\n"); +#endif + // if inactive, remove it from the list + if (pObject->IsActive()) + { + // first make sure it is stopped + m_audiodevice->ClearId(pObject); + } + } + } +} + + + +void SND_Scene::UpdateActiveObects() +{ +// ++tijd; + + SND_SoundObject* pObject; + // update only the objects that need to be updated + for (pObject = (SND_SoundObject*)m_activeobjects.getHead(); + !pObject->isTail(); + pObject = (SND_SoundObject*)pObject->getNext()) + { + int id = pObject->GetId(); + + if (id >= 0) + { +#ifdef USE_FMOD + // fmod wants these set before playing the sample + if (pObject->IsModified()) + { + m_audiodevice->SetObjectLoop(id, pObject->GetLoopMode()); + m_audiodevice->SetObjectLoopPoints(id, pObject->GetLoopStart(), pObject->GetLoopEnd()); + } + + // ok, properties Set. now see if it must play + if (pObject->GetPlaystate() == SND_MUST_PLAY) + { + m_audiodevice->PlayObject(id); + pObject->SetPlaystate(SND_PLAYING); + pObject->InitRunning(); +// printf("start play: %d\n", tijd); + } +#endif + if (pObject->Is3D()) + { + // Get the global positions and velocity vectors + // of the listener and soundobject + MT_Vector3 op = pObject->GetPosition(); + MT_Vector3 lp = m_listener.GetPosition(); + MT_Vector3 position = op - lp; + + // Calculate relative velocity in global coordinates + // of the sound with respect to the listener. + MT_Vector3 ov = pObject->GetVelocity(); + MT_Vector3 lv = m_listener.GetVelocity(); + MT_Vector3 velocity = ov - lv; + + // Now map the object position and velocity into + // the local coordinates of the listener. + MT_Matrix3x3 lo = m_listener.GetOrientation(); + + MT_Vector3 local_sound_pos = position * lo; + MT_Vector3 local_sound_vel = velocity * lo; + + m_audiodevice->SetObjectTransform( + id, + local_sound_pos, + local_sound_vel, + pObject->GetOrientation(), // make relative to listener! + lp, + pObject->GetRollOffFactor()); + } + else + { + m_audiodevice->ObjectIs2D(id); + } + + // update the situation + if (pObject->IsModified()) + { + m_audiodevice->SetObjectPitch(id, pObject->GetPitch()); + m_audiodevice->SetObjectGain(id, pObject->GetGain()); + m_audiodevice->SetObjectMinGain(id, pObject->GetMinGain()); + m_audiodevice->SetObjectMaxGain(id, pObject->GetMaxGain()); + m_audiodevice->SetObjectReferenceDistance(id, pObject->GetReferenceDistance()); + m_audiodevice->SetObjectRollOffFactor(id, pObject->GetRollOffFactor()); + m_audiodevice->SetObjectLoop(id, pObject->GetLoopMode()); + m_audiodevice->SetObjectLoopPoints(id, pObject->GetLoopStart(), pObject->GetLoopEnd()); + pObject->SetModified(false); + } + + pObject->AddRunning(); + +#ifdef ONTKEVER + STR_String naam = pObject->GetObjectName(); + STR_String sample = pObject->GetSampleName(); + + int id = pObject->GetId(); + int buffer = pObject->GetBuffer(); + + float gain = pObject->GetGain(); + float pitch = pObject->GetPitch(); + float timestamp = pObject->GetTimestamp(); + + printf("naam: %s, sample: %s \n", naam.Ptr(), sample.Ptr()); + printf("id: %d, buffer: %d \n", id, buffer); + printf("gain: %f, pitch: %f, ts: %f \n\n", gain, pitch, timestamp); +#endif +#ifdef USE_OPENAL + // ok, properties Set. now see if it must play + if (pObject->GetPlaystate() == SND_MUST_PLAY) + { + m_audiodevice->PlayObject(id); + pObject->SetPlaystate(SND_PLAYING); + //break; + } +#endif + + // check to see if the sound is still playing + // if not: release its id + int playstate = m_audiodevice->GetPlayState(id); +#ifdef ONTKEVER + if (playstate != 2) + printf("%d - ",playstate); +#endif + + if ((playstate == SND_STOPPED) && !pObject->GetLoopMode()) + { + RemoveActiveObject(pObject); + } + } + } +} + + + +void SND_Scene::UpdateCD() +{ + if (m_audiodevice) + { + SND_CDObject* pCD = SND_CDObject::Instance(); + + if (pCD) + { + int playstate = pCD->GetPlaystate(); + + switch (playstate) + { + case SND_MUST_PLAY: + { + // initialize the cd only when you need it + m_audiodevice->SetCDGain(pCD->GetGain()); + m_audiodevice->SetCDPlaymode(pCD->GetPlaymode()); + m_audiodevice->PlayCD(pCD->GetTrack()); + pCD->SetPlaystate(SND_PLAYING); + pCD->SetUsed(); + break; + } + case SND_MUST_PAUSE: + { + m_audiodevice->PauseCD(true); + pCD->SetPlaystate(SND_PAUSED); + break; + } + case SND_MUST_RESUME: + { + m_audiodevice->PauseCD(false); + pCD->SetPlaystate(SND_PLAYING); + break; + } + case SND_MUST_STOP: + { + m_audiodevice->StopCD(); + pCD->SetPlaystate(SND_STOPPED); + break; + } + default: + { + } + } + + // this one is only for realtime modifying settings + if (pCD->IsModified()) + { + m_audiodevice->SetCDGain(pCD->GetGain()); + pCD->SetModified(false); + } + } + } +} + + + +void SND_Scene::Proceed() +{ + if (m_audio && m_audioplayback) + { + m_audiodevice->MakeCurrent(); + + UpdateListener(); + UpdateActiveObects(); + UpdateCD(); + +// m_audiodevice->UpdateDevice(); + } +} + + +void SND_Scene::DeleteObject(SND_SoundObject* pObject) +{ +#ifdef ONTKEVER + printf("SND_Scene::DeleteObject\n"); +#endif + + if (pObject) + { + if (m_audiodevice) + m_audiodevice->ClearId(pObject); + + // must remove object from m_activeList + std::set::iterator set_it; + set_it = m_soundobjects.find(pObject); + + if (set_it != m_soundobjects.end()) + m_soundobjects.erase(set_it); + + // release the memory + delete pObject; + pObject = NULL; + } +} + + + +void SND_Scene::RemoveAllObjects() +{ +#ifdef ONTKEVER + printf("SND_Scene::RemoveAllObjects\n"); +#endif + + StopAllObjects(); + + std::set::iterator it = m_soundobjects.begin(); + + while (it != m_soundobjects.end()) + { + delete (*it); + it++; + } + + m_soundobjects.clear(); +} + + + +void SND_Scene::StopAllObjects() +{ + if (m_audio) + { +#ifdef ONTKEVER + printf("SND_Scene::StopAllObjects\n"); +#endif + + SND_SoundObject* pObject; + + for (pObject = (SND_SoundObject*)m_activeobjects.getHead(); + !pObject->isTail(); + pObject = (SND_SoundObject*)pObject->getNext()) + { + m_audiodevice->ClearId(pObject); + } + } +} + + + +SND_SoundListener* SND_Scene::GetListener() +{ + return &m_listener; +} diff --git a/intern/SoundSystem/intern/SND_SoundListener.cpp b/intern/SoundSystem/intern/SND_SoundListener.cpp new file mode 100644 index 00000000000..0209ac5683a --- /dev/null +++ b/intern/SoundSystem/intern/SND_SoundListener.cpp @@ -0,0 +1,188 @@ +/* + * SND_SoundListener.cpp + * + * A SoundListener is for sound what a camera is for vision. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "SND_SoundListener.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +SND_SoundListener::SND_SoundListener() +{ + m_modified = true; + m_gain = 1.0; + m_dopplerfactor = 1.0; + m_dopplervelocity = 1.0; + m_scale = 1.0; + m_position[0] = 0.0; + m_position[1] = 0.0; + m_position[2] = 0.0; + m_velocity[0] = 0.0; + m_velocity[1] = 0.0; + m_velocity[2] = 0.0; + m_orientation[0][0] = 1.0; + m_orientation[0][1] = 0.0; + m_orientation[0][2] = 0.0; + m_orientation[1][0] = 0.0; + m_orientation[1][1] = 1.0; + m_orientation[1][2] = 0.0; + m_orientation[2][0] = 0.0; + m_orientation[2][1] = 0.0; + m_orientation[2][2] = 1.0; +} + + +SND_SoundListener::~SND_SoundListener() +{ + ; /* intentionally empty */ + +} + + + +void SND_SoundListener::SetGain(MT_Scalar gain) +{ + m_gain = gain; + m_modified = true; +} + + + +void SND_SoundListener::SetPosition (const MT_Vector3& pos) +{ + m_position = pos; +} + + + +void SND_SoundListener::SetVelocity(const MT_Vector3& vel) +{ + m_velocity = vel; +} + + + +void SND_SoundListener::SetOrientation(const MT_Matrix3x3& ori) +{ + m_orientation = ori; +} + + + +void SND_SoundListener::SetDopplerFactor(MT_Scalar dopplerfactor) +{ + m_dopplerfactor = dopplerfactor; + m_modified = true; +} + + + +void SND_SoundListener::SetDopplerVelocity(MT_Scalar dopplervelocity) +{ + m_dopplervelocity = dopplervelocity; + m_modified = true; +} + + + +void SND_SoundListener::SetScale(MT_Scalar scale) +{ + m_scale = scale; + m_modified = true; +} + + + +MT_Scalar SND_SoundListener::GetGain() const +{ + return m_gain; +} + + + +MT_Vector3 SND_SoundListener::GetPosition() const +{ + return m_position; +} + + + +MT_Vector3 SND_SoundListener::GetVelocity() const +{ + return m_velocity; +} + + + +MT_Matrix3x3 SND_SoundListener::GetOrientation() +{ + return m_orientation; +} + + + +MT_Scalar SND_SoundListener::GetDopplerFactor() const +{ + return m_dopplerfactor; +} + + + +MT_Scalar SND_SoundListener::GetDopplerVelocity() const +{ + return m_dopplervelocity; +} + + + +MT_Scalar SND_SoundListener::GetScale() const +{ + return m_scale; +} + + + +bool SND_SoundListener::IsModified() const +{ + return m_modified; +} + + + +void SND_SoundListener::SetModified(bool modified) +{ + m_modified = modified; +} diff --git a/intern/SoundSystem/intern/SND_SoundObject.cpp b/intern/SoundSystem/intern/SND_SoundObject.cpp new file mode 100644 index 00000000000..e835b012ac1 --- /dev/null +++ b/intern/SoundSystem/intern/SND_SoundObject.cpp @@ -0,0 +1,508 @@ +/* + * SND_SoundObject.cpp + * + * Implementation of the abstract sound object + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "SND_SoundObject.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +SND_SoundObject::SND_SoundObject()// : m_modified(true) +{ + m_samplename = ""; + m_length = 0; + m_buffer = 0; + + m_gain = 0.0; + m_pitch = 1.0; + + m_mingain = 0.0; + m_maxgain = 1.0; + m_rollofffactor = 1.0; + m_referencedistance = 1.0; + + m_position[0] = 0.0; + m_position[1] = 0.0; + m_position[2] = 0.0; + m_velocity[0] = 0.0; + m_velocity[1] = 0.0; + m_velocity[2] = 0.0; + m_orientation[0][0] = 1.0; + m_orientation[0][1] = 0.0; + m_orientation[0][2] = 0.0; + m_orientation[1][0] = 0.0; + m_orientation[1][1] = 1.0; + m_orientation[1][2] = 0.0; + m_orientation[2][0] = 0.0; + m_orientation[2][1] = 0.0; + m_orientation[2][2] = 1.0; + + m_loopstart = 0; + m_loopend = 0; + m_loopmode = SND_LOOP_NORMAL; + m_is3d = true; + m_playstate = SND_INITIAL; + m_active = false; + m_id = -1; + m_lifespan = 0; + m_timestamp = 0; + m_modified = true; + m_running = 0; + m_highpriority = false; +} + + + +SND_SoundObject::~SND_SoundObject() +{ +} + + + +void SND_SoundObject::StartSound() +{ + m_playstate = SND_MUST_PLAY; +} + + + +void SND_SoundObject::StopSound() +{ + m_playstate = SND_MUST_STOP; +} + + + +void SND_SoundObject::PauseSound() +{ + m_playstate = SND_MUST_PAUSE; +} + + + +void SND_SoundObject::DeleteWhenFinished() +{ + m_playstate = SND_MUST_BE_DELETED; +} + + + +void SND_SoundObject::SetGain(MT_Scalar gain) +{ + m_gain = gain; + m_modified = true; +} + + + +void SND_SoundObject::SetMinGain(MT_Scalar mingain) +{ + m_mingain = mingain; + m_modified = true; +} + + + +void SND_SoundObject::SetMaxGain(MT_Scalar maxgain) +{ + m_maxgain = maxgain; + m_modified = true; +} + + + +void SND_SoundObject::SetRollOffFactor(MT_Scalar rollofffactor) +{ + m_rollofffactor = rollofffactor; + m_modified = true; +} + + + +void SND_SoundObject::SetReferenceDistance(MT_Scalar referencedistance) +{ + m_referencedistance = referencedistance; + m_modified = true; +} + + + +void SND_SoundObject::SetPitch(MT_Scalar pitch) +{ + m_pitch = pitch; + m_modified = true; +} + + + +void SND_SoundObject::SetLoopMode(unsigned int loopmode) +{ + m_loopmode = loopmode; + m_modified = true; +} + + + +void SND_SoundObject::SetLoopStart(unsigned int loopstart) +{ + m_loopstart = loopstart; + m_modified = true; +} + + + +void SND_SoundObject::SetLoopEnd(unsigned int loopend) +{ + m_loopend = loopend; + m_modified = true; +} + + + +void SND_SoundObject::Set3D(bool threedee) +{ + m_is3d = threedee; +} + + + +void SND_SoundObject::SetLifeSpan() +{ + m_lifespan = m_length / m_pitch; +} + + + +bool SND_SoundObject::IsLifeSpanOver(MT_Scalar curtime) const +{ + bool result = false; + + if ((curtime - m_timestamp) > m_lifespan) + result = true; + + return result; +} + + + +void SND_SoundObject::SetActive(bool active) +{ + m_active = active; + + if (!active) + { + m_playstate = SND_STOPPED; + (this)->remove(); + } +} + + + +void SND_SoundObject::SetBuffer(unsigned int buffer) +{ + m_buffer = buffer; +} + + + +void SND_SoundObject::SetObjectName(STR_String objectname) +{ + m_objectname = objectname; +} + + + +void SND_SoundObject::SetSampleName(STR_String samplename) +{ + m_samplename = samplename; +} + + + +void SND_SoundObject::SetLength(MT_Scalar length) +{ + m_length = length; +} + + + +void SND_SoundObject::SetPosition(const MT_Vector3& pos) +{ + m_position = pos; +} + + + +void SND_SoundObject::SetVelocity(const MT_Vector3& vel) +{ + m_velocity = vel; +} + + + +void SND_SoundObject::SetOrientation(const MT_Matrix3x3& orient) +{ + m_orientation = orient; +} + + + +void SND_SoundObject::SetPlaystate(int playstate) +{ + m_playstate = playstate; +} + + + +void SND_SoundObject::SetId(int id) +{ + m_id = id; +} + + + +void SND_SoundObject::SetTimeStamp(MT_Scalar timestamp) +{ + m_timestamp = timestamp; +} + + + +void SND_SoundObject::SetHighPriority(bool priority) +{ + m_highpriority = priority; +} + + + +bool SND_SoundObject::IsHighPriority() const +{ + return m_highpriority; +} + + + +bool SND_SoundObject::IsActive()const +{ + return m_active; +} + + + +int SND_SoundObject::GetId()const +{ + return m_id; +} + + + +MT_Scalar SND_SoundObject::GetLifeSpan()const +{ + return m_lifespan; +} + + + +MT_Scalar SND_SoundObject::GetTimestamp()const +{ + return m_timestamp; +} + + + +unsigned int SND_SoundObject::GetBuffer() +{ + return m_buffer; +} + + + +const STR_String& SND_SoundObject::GetSampleName() +{ + return m_samplename; +} + + + +const STR_String& SND_SoundObject::GetObjectName() +{ + return m_objectname; +} + + + +MT_Scalar SND_SoundObject::GetLength() const +{ + return m_length; +} + + + +MT_Scalar SND_SoundObject::GetGain() const +{ + return m_gain; +} + + + +MT_Scalar SND_SoundObject::GetPitch() const +{ + return m_pitch; +} + + + +MT_Scalar SND_SoundObject::GetMinGain() const +{ + return m_mingain; +} + + + +MT_Scalar SND_SoundObject::GetMaxGain() const +{ + return m_maxgain; +} + + + +MT_Scalar SND_SoundObject::GetRollOffFactor() const +{ + return m_rollofffactor; +} + + + +MT_Scalar SND_SoundObject::GetReferenceDistance() const +{ + return m_referencedistance; +} + + + +MT_Vector3 SND_SoundObject::GetPosition() const +{ + return m_position; +} + + + +MT_Vector3 SND_SoundObject::GetVelocity() const +{ + return m_velocity; +} + + + +MT_Matrix3x3 SND_SoundObject::GetOrientation() const +{ + return m_orientation; +} + + + +unsigned int SND_SoundObject::GetLoopMode() const +{ + return m_loopmode; +} + + + +unsigned int SND_SoundObject::GetLoopStart() const +{ + return m_loopstart; +} + + + +unsigned int SND_SoundObject::GetLoopEnd() const +{ + return m_loopend; +} + + + +bool SND_SoundObject::Is3D() const +{ + return m_is3d; +} + + + +int SND_SoundObject::GetPlaystate() const +{ + return m_playstate; +} + + + +bool SND_SoundObject::IsModified() const +{ + return m_modified; +} + + + +void SND_SoundObject::SetModified(bool modified) +{ + m_modified = modified; +} + + + +void SND_SoundObject::InitRunning() +{ + m_running = 0; +} + + + +bool SND_SoundObject::IsRunning() const +{ + bool result = false; + + if (m_running > 100) + result = true; + + return result; +} + + + +void SND_SoundObject::AddRunning() +{ + ++m_running; +} diff --git a/intern/SoundSystem/intern/SND_Utils.cpp b/intern/SoundSystem/intern/SND_Utils.cpp new file mode 100644 index 00000000000..0880576c292 --- /dev/null +++ b/intern/SoundSystem/intern/SND_Utils.cpp @@ -0,0 +1,447 @@ +/* + * SND_Utils.cpp + * + * Util functions for soundthingies + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "SND_Utils.h" +#include "SoundDefines.h" +#include "SND_DependKludge.h" +/* +extern "C" { +#include "license_key.h" +} +*/ +#include +#include +#include +#include +#include + +#if defined(WIN32) +#include +#else +#include +#endif + +#define BUFFERSIZE 32 + + +/***************************************************************************** + * Begin of temporary Endian stuff. + * I think there should be a central place to handle endian conversion but for + * the time being it suffices. Note that the defines come from the Blender + * source. + *****************************************************************************/ +typedef enum +{ + SND_endianBig = 0, + SND_endianLittle +} SND_TEndian; + +#if defined(__BIG_ENDIAN__) || defined(__sparc) || defined(__sparc__) +const SND_TEndian SND_fEndian = SND_endianBig; +#else +const SND_TEndian SND_fEndian = SND_endianLittle; +#endif + +/* This one swaps the bytes in a short */ +#define SWITCH_SHORT(a) { \ + char s_i, *p_i; \ + p_i= (char *)&(a); \ + s_i=p_i[0]; \ + p_i[0] = p_i[1]; \ + p_i[1] = s_i; } + +/* This one rotates the bytes in an int */ +#define SWITCH_INT(a) { \ + char s_i, *p_i; \ + p_i= (char *)&(a); \ + s_i=p_i[0]; p_i[0]=p_i[3]; p_i[3]=s_i; \ + s_i=p_i[1]; p_i[1]=p_i[2]; p_i[2]=s_i; } +/***************************************************************************** + * End of temporary Endian stuff. + *****************************************************************************/ + + +/* loads a file */ +void* SND_LoadSample(char *filename) +{ + int file, filelen, buffersize = BUFFERSIZE; + void* data = NULL; + +#if defined(WIN32) + file = open(filename, O_BINARY|O_RDONLY); +#else + file = open(filename, 0|O_RDONLY); +#endif + + if (file == -1) + { + //printf("can't open file.\n"); + //printf("press q for quit.\n"); + } + else + { + filelen = lseek(file, 0, SEEK_END); + lseek(file, 0, SEEK_SET); + + if (filelen != 0) + { + data = malloc(buffersize); + + if (read(file, data, buffersize) != buffersize) + { + free(data); + data = NULL; + } + } + close(file); + + } + return (data); +} + + + +bool SND_IsSampleValid(const STR_String& name, void* memlocation) +{ + bool result = false; + bool loadedsample = false; + char buffer[BUFFERSIZE]; + + if (!memlocation) + { + STR_String samplename = name; + memlocation = SND_LoadSample(samplename.Ptr()); + + if (memlocation) + loadedsample = true; + } + + if (memlocation) + { + memcpy(&buffer, memlocation, BUFFERSIZE); + + if(!(memcmp(buffer, "RIFF", 4) && memcmp(&(buffer[8]), "WAVEfmt ", 8))) + { + /* This was endian unsafe. See top of the file for the define. */ + short shortbuf = *((short *) &buffer[20]); + if (SND_fEndian == SND_endianBig) SWITCH_SHORT(shortbuf); + + if (shortbuf == SND_WAVE_FORMAT_PCM) + result = true; + + /* only fmod supports compressed wav */ +#ifdef USE_FMOD + switch (shortbuf) + { + case SND_WAVE_FORMAT_ADPCM: + case SND_WAVE_FORMAT_ALAW: + case SND_WAVE_FORMAT_MULAW: + case SND_WAVE_FORMAT_DIALOGIC_OKI_ADPCM: + case SND_WAVE_FORMAT_CONTROL_RES_VQLPC: + case SND_WAVE_FORMAT_GSM_610: + case SND_WAVE_FORMAT_MPEG3: + result = true; + break; + default: + { + break; + } + } +#endif + } +#ifdef USE_FMOD + /* only valid publishers may use ogg vorbis */ + else if (!memcmp(buffer, "OggS", 4)) + { + result = true; + } + /* only valid publishers may use mp3 */ + else if (((!memcmp(buffer, "ID3", 3)) || (!memcmp(buffer, "ÿû", 2)))) + { + result = true; + } +#endif + } + if (loadedsample) + { + free(memlocation); + memlocation = NULL; + } + + return result; +} + + + +/* checks if the passed pointer is a valid sample */ +bool CheckSample(void* sample) +{ + bool valid = false; + char buffer[32]; + + memcpy(buffer, sample, 16); + + if(!(memcmp(buffer, "RIFF", 4) && memcmp(&(buffer[8]), "WAVEfmt ", 8))) + { + valid = true; + } + + return valid; +} + + + +/* gets the type of the sample (0 == unknown, 1 == PCM etc */ +unsigned int SND_GetSampleFormat(void* sample) +{ + short sampletype = 0; + + if (CheckSample(sample)) + { + memcpy(&sampletype, ((char*)sample) + 20, 2); + } + /* This was endian unsafe. See top of the file for the define. */ + if (SND_fEndian == SND_endianBig) SWITCH_SHORT(sampletype); + + return (unsigned int)sampletype; +} + + + +/* gets the number of channels in a sample */ +unsigned int SND_GetNumberOfChannels(void* sample) +{ + short numberofchannels = 0; + + if (CheckSample(sample)) + { + memcpy(&numberofchannels, ((char*)sample) + 22, 2); + } + /* This was endian unsafe. See top of the file for the define. */ + if (SND_fEndian == SND_endianBig) SWITCH_SHORT(numberofchannels); + + return (unsigned int)numberofchannels; +} + + + +/* gets the samplerate of a sample */ +unsigned int SND_GetSampleRate(void* sample) +{ + unsigned int samplerate = 0; + + if (CheckSample(sample)) + { + memcpy(&samplerate, ((char*)sample) + 24, 4); + } + /* This was endian unsafe. See top of the file for the define. */ + if (SND_fEndian == SND_endianBig) SWITCH_INT(samplerate); + + return samplerate; +} + + + +/* gets the bitrate of a sample */ +unsigned int SND_GetBitRate(void* sample) +{ + short bitrate = 0; + + if (CheckSample(sample)) + { + memcpy(&bitrate, ((char*)sample) + 34, 2); + } + /* This was endian unsafe. See top of the file for the define. */ + if (SND_fEndian == SND_endianBig) SWITCH_SHORT(bitrate); + + return (unsigned int)bitrate; +} + + + +/* gets the length of the actual sample data (without the header) */ +unsigned int SND_GetNumberOfSamples(void* sample) +{ + unsigned int chunklength, length = 0, offset = 16; + char data[4]; + + if (CheckSample(sample)) + { + memcpy(&chunklength, ((char*)sample) + offset, 4); + /* This was endian unsafe. See top of the file for the define. */ + if (SND_fEndian == SND_endianBig) SWITCH_INT(chunklength); + + offset = offset + chunklength + 4; + memcpy(data, ((char*)sample) + offset, 4); + + /* This seems very unsafe, what if data is never found (f.i. corrupt file)... */ + // lets find "data" + while (memcmp(data, "data", 4)) + { + offset += 4; + memcpy(data, ((char*)sample) + offset, 4); + } + offset += 4; + memcpy(&length, ((char*)sample) + offset, 4); + + /* This was endian unsafe. See top of the file for the define. */ + if (SND_fEndian == SND_endianBig) SWITCH_INT(length); + } + + return length; +} + + + +/* gets the size of the entire header (file - sampledata) */ +unsigned int SND_GetHeaderSize(void* sample) +{ + unsigned int chunklength, headersize = 0, offset = 16; + char data[4]; + + if (CheckSample(sample)) + { + memcpy(&chunklength, ((char*)sample) + offset, 4); + /* This was endian unsafe. See top of the file for the define. */ + if (SND_fEndian == SND_endianBig) SWITCH_INT(chunklength); + offset = offset + chunklength + 4; + memcpy(data, ((char*)sample) + offset, 4); + + // lets find "data" + while (memcmp(data, "data", 4)) + { + offset += 4; + memcpy(data, ((char*)sample) + offset, 4); + } + headersize = offset + 8; + } + + + return headersize; +} + + + +unsigned int SND_GetExtraChunk(void* sample) +{ + unsigned int extrachunk = 0, chunklength, offset = 16; + char data[4]; + + if (CheckSample(sample)) + { + memcpy(&chunklength, ((char*)sample) + offset, 4); + offset = offset + chunklength + 4; + memcpy(data, ((char*)sample) + offset, 4); + + // lets find "cue" + while (memcmp(data, "cue", 3)) + { + offset += 4; + memcpy(data, ((char*)sample) + offset, 4); + } + } + + return extrachunk; +} + + + +void SND_GetSampleInfo(signed char* sample, SND_WaveSlot* waveslot) +{ + WavFileHeader fileheader; + WavFmtHeader fmtheader; + WavFmtExHeader fmtexheader; + WavSampleHeader sampleheader; + WavChunkHeader chunkheader; + + if (CheckSample(sample)) + { + memcpy(&fileheader, sample, sizeof(WavFileHeader)); + fileheader.size = SND_GetHeaderSize(sample); + sample += sizeof(WavFileHeader); + fileheader.size = ((fileheader.size+1) & ~1) - 4; + + while ((fileheader.size > 0) && (memcpy(&chunkheader, sample, sizeof(WavChunkHeader)))) + { + sample += sizeof(WavChunkHeader); + if (!memcmp(chunkheader.id, "fmt ", 4)) + { + memcpy(&fmtheader, sample, sizeof(WavFmtHeader)); + waveslot->SetSampleFormat(fmtheader.format); + + if (fmtheader.format == 0x0001) + { + waveslot->SetNumberOfChannels(fmtheader.numberofchannels); + waveslot->SetBitRate(fmtheader.bitrate); + waveslot->SetSampleRate(fmtheader.samplerate); + sample += chunkheader.size; + } + else + { + memcpy(&fmtexheader, sample, sizeof(WavFmtExHeader)); + sample += chunkheader.size; + } + } + else if (!memcmp(chunkheader.id, "data", 4)) + { + if (fmtheader.format == 0x0001) + { + waveslot->SetNumberOfSamples(chunkheader.size); + sample += chunkheader.size; + } + else if (fmtheader.format == 0x0011) + { + //IMA ADPCM + } + else if (fmtheader.format == 0x0055) + { + //MP3 WAVE + } + } + else if (!memcmp(chunkheader.id, "smpl", 4)) + { + memcpy(&sampleheader, sample, sizeof(WavSampleHeader)); + //loop = sampleheader.loops; + sample += chunkheader.size; + } + else + sample += chunkheader.size; + + sample += chunkheader.size & 1; + fileheader.size -= (((chunkheader.size + 1) & ~1) + 8); + } + } +} diff --git a/intern/SoundSystem/intern/SND_WaveCache.cpp b/intern/SoundSystem/intern/SND_WaveCache.cpp new file mode 100644 index 00000000000..e9868f77f57 --- /dev/null +++ b/intern/SoundSystem/intern/SND_WaveCache.cpp @@ -0,0 +1,141 @@ +/* + * SND_WaveCache.cpp + * + * abstract wavecache, a way to organize samples + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef WIN32 +#pragma warning (disable:4786) // Get rid of stupid stl-visual compiler debug warning +#endif //WIN32 + +#include "SND_WaveCache.h" +#include + +#ifdef __APPLE__ +# include +#else +# ifdef __FreeBSD__ +# include +# else +# include +# endif +#endif + +SND_WaveCache::SND_WaveCache() +{ + // do the buffer administration + for (int i = 0; i < NUM_BUFFERS; i++) + m_bufferList[i] = NULL; +} + + + +SND_WaveCache::~SND_WaveCache() +{ + // clean up the mess + FreeSamples(); + RemoveAllSamples(); +} + + + +SND_WaveSlot* SND_WaveCache::GetWaveSlot(const STR_String& samplename) +{ + SND_WaveSlot* waveslot = NULL; + + std::map::iterator find_result = m_samplecache.find(samplename); + + // let's see if we have already loaded this sample + if (find_result != m_samplecache.end()) + { + waveslot = (*find_result).second; + } + else + { + // so the sample wasn't loaded, so do it here + for (int bufnum = 0; bufnum < NUM_BUFFERS; bufnum++) + { + // find an empty buffer + if (m_bufferList[bufnum] == NULL) + { + waveslot = new SND_WaveSlot(); + waveslot->SetSampleName(samplename); + waveslot->SetBuffer(bufnum); + m_bufferList[bufnum] = waveslot; + break; + } + } + m_samplecache.insert(std::pair(samplename, waveslot)); + } + + return waveslot; +} + + + +void SND_WaveCache::RemoveAllSamples() +{ + // remove all samples + m_samplecache.clear(); + + // reset the list of buffers + for (int i = 0; i < NUM_BUFFERS; i++) + m_bufferList[i] = NULL; +} + + + +void SND_WaveCache::RemoveSample(const STR_String& samplename, int buffer) +{ + m_samplecache.erase(samplename); + m_bufferList[buffer] = NULL; +} + + + +void SND_WaveCache::FreeSamples() +{ + // iterate through the bufferlist and delete the waveslot if present + for (int i = 0; i < NUM_BUFFERS; i++) + { + if (m_bufferList[i]) + { + delete m_bufferList[i]; + m_bufferList[i] = NULL; + } + } +} diff --git a/intern/SoundSystem/intern/SND_WaveSlot.cpp b/intern/SoundSystem/intern/SND_WaveSlot.cpp new file mode 100644 index 00000000000..6c74e326743 --- /dev/null +++ b/intern/SoundSystem/intern/SND_WaveSlot.cpp @@ -0,0 +1,183 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "SND_WaveSlot.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +SND_WaveSlot::~SND_WaveSlot() +{ +#ifdef ONTKEVER + printf("neeeeeee...\n"); +#endif +} + + + +void SND_WaveSlot::SetSampleName(STR_String samplename) +{ + m_samplename = samplename; +} + + + +void SND_WaveSlot::SetLoaded(bool loaded) +{ + m_loaded = loaded; +} + + + +void SND_WaveSlot::SetData(void* data) +{ + m_data = data; +} + + + +void SND_WaveSlot::SetBuffer(unsigned int buffer) +{ + m_buffer = buffer; +} + + + +void SND_WaveSlot::SetSampleFormat(unsigned int sampleformat) +{ + m_sampleformat = sampleformat; +} + + + +void SND_WaveSlot::SetNumberOfChannels(unsigned int numberofchannels) +{ + m_numberofchannels = numberofchannels; +} + + + +void SND_WaveSlot::SetSampleRate(unsigned int samplerate) +{ + m_samplerate = samplerate; +} + + + +void SND_WaveSlot::SetBitRate(unsigned int bitrate) +{ + m_bitrate = bitrate; +} + + + +void SND_WaveSlot::SetNumberOfSamples(unsigned int numberofsamples) +{ + m_numberofsamples = numberofsamples; +} + + + +void SND_WaveSlot::SetFileSize(unsigned int filesize) +{ + m_filesize = filesize; +} + + + +const STR_String& SND_WaveSlot::GetSampleName() +{ + return m_samplename; +} + + + +bool SND_WaveSlot::IsLoaded() const +{ + return m_loaded; +} + + + +void* SND_WaveSlot::GetData() +{ + return m_data; +} + + + +unsigned int SND_WaveSlot::GetBuffer() const +{ + return m_buffer; +} + + + +unsigned int SND_WaveSlot::GetSampleFormat() const +{ + return m_sampleformat; +} + + + +unsigned int SND_WaveSlot::GetNumberOfChannels() const +{ + return m_numberofchannels; +} + + + +unsigned int SND_WaveSlot::GetSampleRate() const +{ + return m_samplerate; +} + + + +unsigned int SND_WaveSlot::GetBitRate() const +{ + return m_bitrate; +} + + + +unsigned int SND_WaveSlot::GetNumberOfSamples() const +{ + return m_numberofsamples; +} + + + +unsigned int SND_WaveSlot::GetFileSize() const +{ + return m_filesize; +} diff --git a/intern/SoundSystem/make/msvc_6_0/SoundSystem.dsp b/intern/SoundSystem/make/msvc_6_0/SoundSystem.dsp new file mode 100644 index 00000000000..c7ce7aa7a70 --- /dev/null +++ b/intern/SoundSystem/make/msvc_6_0/SoundSystem.dsp @@ -0,0 +1,206 @@ +# Microsoft Developer Studio Project File - Name="SoundSystem" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=SoundSystem - Win32 Release +!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 "SoundSystem.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 "SoundSystem.mak" CFG="SoundSystem - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SoundSystem - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "SoundSystem - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SoundSystem - 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 "..\..\..\..\obj\windows\intern\soundsystem" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\soundsystem" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../" /I "../../../../../lib/windows/string/include" /I "../../../../../lib/windows/moto/include" /I "../../dummy" /I "../../openal" /I "..\..\..\string" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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:"..\..\..\..\obj\windows\intern\soundsystem\libSoundSystem.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\SoundSystem\include\*.h ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\soundsystem\*.lib ..\..\..\..\..\lib\windows\SoundSystem\lib\*.a ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "SoundSystem - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SoundSystem___Win32_Debug" +# PROP BASE Intermediate_Dir "SoundSystem___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\intern\soundsystem\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\soundsystem\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "../../" /I "../../../../../lib/windows/string/include" /I "../../../../../lib/windows/moto/include" /I "../../dummy" /I "../../openal" /I "..\..\..\string" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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:"..\..\..\..\obj\windows\intern\soundsystem\debug\libSoundSystem.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\SoundSystem\include\*.h ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\soundsystem\debug\*.lib ..\..\..\..\..\lib\windows\SoundSystem\lib\debug\*.a ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "SoundSystem - Win32 Release" +# Name "SoundSystem - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\intern\SND_AudioDevice.cpp +# End Source File +# Begin Source File + +SOURCE="..\..\intern\SND_C-api.cpp" +# End Source File +# Begin Source File + +SOURCE=..\..\intern\SND_CDObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\SND_DeviceManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\SND_IdObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\SND_Scene.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\SND_SoundListener.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\SND_SoundObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\SND_Utils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\SND_WaveCache.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\SND_WaveSlot.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\intern\SND_AudioDevice.h +# End Source File +# Begin Source File + +SOURCE="..\..\SND_C-api.h" +# End Source File +# Begin Source File + +SOURCE=..\..\SND_CDObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\SND_DependKludge.h +# End Source File +# Begin Source File + +SOURCE=..\..\SND_DeviceManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\SND_IAudioDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\SND_IdObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\SND_Object.h +# End Source File +# Begin Source File + +SOURCE=..\..\SND_Scene.h +# End Source File +# Begin Source File + +SOURCE=..\..\SND_SoundListener.h +# End Source File +# Begin Source File + +SOURCE=..\..\SND_SoundObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\SND_Utils.h +# End Source File +# Begin Source File + +SOURCE=..\..\SND_WaveCache.h +# End Source File +# Begin Source File + +SOURCE=..\..\SND_WaveSlot.h +# End Source File +# Begin Source File + +SOURCE=..\..\SoundDefines.h +# End Source File +# End Group +# End Target +# End Project diff --git a/intern/SoundSystem/make/msvc_6_0/dummy/DummySoundSystem.dsp b/intern/SoundSystem/make/msvc_6_0/dummy/DummySoundSystem.dsp new file mode 100644 index 00000000000..4a27fdfa6e3 --- /dev/null +++ b/intern/SoundSystem/make/msvc_6_0/dummy/DummySoundSystem.dsp @@ -0,0 +1,103 @@ +# Microsoft Developer Studio Project File - Name="DummySoundSystem" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=DummySoundSystem - Win32 Release +!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 "DummySoundSystem.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 "DummySoundSystem.mak" CFG="DummySoundSystem - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "DummySoundSystem - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "DummySoundSystem - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "DummySoundSystem - 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 "..\..\..\..\..\obj\windows\intern\soundsystem\dummy" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\intern\soundsystem\dummy" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\intern" /I "..\..\..\..\SoundSystem" /I "..\..\..\..\moto\include" /I "..\..\..\..\string" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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:"..\..\..\..\..\obj\windows\intern\soundsystem\dummy\libDummySoundSystem.lib" + +!ELSEIF "$(CFG)" == "DummySoundSystem - 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 "..\..\..\..\..\obj\windows\intern\soundsystem\dummy\debug" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\intern\soundsystem\dummy\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\intern" /I "..\..\..\..\SoundSystem" /I "..\..\..\..\moto\include" /I "..\..\..\..\string" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# SUBTRACT CPP /Fr +# 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:"..\..\..\..\..\obj\windows\intern\soundsystem\dummy\debug\libDummySoundSystem.lib" + +!ENDIF + +# Begin Target + +# Name "DummySoundSystem - Win32 Release" +# Name "DummySoundSystem - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\dummy\SND_DummyDevice.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\dummy\SND_DummyDevice.h +# End Source File +# End Group +# End Target +# End Project diff --git a/intern/SoundSystem/make/msvc_6_0/openal/OpenALSoundSystem.dsp b/intern/SoundSystem/make/msvc_6_0/openal/OpenALSoundSystem.dsp new file mode 100644 index 00000000000..67a6bd0bb5a --- /dev/null +++ b/intern/SoundSystem/make/msvc_6_0/openal/OpenALSoundSystem.dsp @@ -0,0 +1,106 @@ +# Microsoft Developer Studio Project File - Name="OpenALSoundSystem" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=OpenALSoundSystem - Win32 Release +!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 "OpenALSoundSystem.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 "OpenALSoundSystem.mak" CFG="OpenALSoundSystem - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "OpenALSoundSystem - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "OpenALSoundSystem - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "OpenALSoundSystem - 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 "..\..\..\..\..\obj\windows\intern\soundsystem\openal" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\intern\soundsystem\openal" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\intern" /I "..\..\..\..\SoundSystem" /I "..\..\..\..\SoundSystem\sdl" /I "..\..\..\..\moto\include" /I "..\..\..\..\string" /I "..\..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\..\..\lib\windows\sdl\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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:"..\..\..\..\..\obj\windows\intern\soundsystem\openal\libOpenALSoundSystem.lib" + +!ELSEIF "$(CFG)" == "OpenALSoundSystem - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "OpenALSoundSystem___Win32_Debug" +# PROP BASE Intermediate_Dir "OpenALSoundSystem___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\..\obj\windows\intern\soundsystem\openal\debug" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\intern\soundsystem\openal\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\intern" /I "..\..\..\..\SoundSystem" /I "..\..\..\..\SoundSystem\sdl" /I "..\..\..\..\moto\include" /I "..\..\..\..\string" /I "..\..\..\..\..\..\lib\windows\sdl\include" /I "..\..\..\..\..\..\lib\windows\openal\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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:"..\..\..\..\..\obj\windows\intern\soundsystem\openal\debug\libOpenALSoundSystem.lib" + +!ENDIF + +# Begin Target + +# Name "OpenALSoundSystem - Win32 Release" +# Name "OpenALSoundSystem - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\openal\SND_OpenALDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\sdl\SND_SDLCDDevice.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\openal\SND_OpenALDevice.h +# End Source File +# End Group +# End Target +# End Project diff --git a/intern/SoundSystem/make/msvc_7_0/SoundSystem.vcproj b/intern/SoundSystem/make/msvc_7_0/SoundSystem.vcproj new file mode 100644 index 00000000000..f0952c582b7 --- /dev/null +++ b/intern/SoundSystem/make/msvc_7_0/SoundSystem.vcproj @@ -0,0 +1,339 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/SoundSystem/make/msvc_7_0/dummy/DummySoundSystem.vcproj b/intern/SoundSystem/make/msvc_7_0/dummy/DummySoundSystem.vcproj new file mode 100644 index 00000000000..103b589e732 --- /dev/null +++ b/intern/SoundSystem/make/msvc_7_0/dummy/DummySoundSystem.vcproj @@ -0,0 +1,243 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/SoundSystem/make/msvc_7_0/openal/OpenALSoundSystem.vcproj b/intern/SoundSystem/make/msvc_7_0/openal/OpenALSoundSystem.vcproj new file mode 100644 index 00000000000..8ce971ac1aa --- /dev/null +++ b/intern/SoundSystem/make/msvc_7_0/openal/OpenALSoundSystem.vcproj @@ -0,0 +1,249 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/SoundSystem/openal/Makefile b/intern/SoundSystem/openal/Makefile new file mode 100644 index 00000000000..84ae9b007b6 --- /dev/null +++ b/intern/SoundSystem/openal/Makefile @@ -0,0 +1,47 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = OpenALSoundSystem +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_1_CPP_WARNINGS) + +CPPFLAGS += -I$(NAN_OPENAL)/include +CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I../intern +CPPFLAGS += -I.. +CPPFLAGS += -I. +CPPFLAGS += -I../sdl diff --git a/intern/SoundSystem/openal/SND_OpenALDevice.cpp b/intern/SoundSystem/openal/SND_OpenALDevice.cpp new file mode 100644 index 00000000000..a278384dfd8 --- /dev/null +++ b/intern/SoundSystem/openal/SND_OpenALDevice.cpp @@ -0,0 +1,799 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * SND_OpenALDevice derived from SND_IAudioDevice + */ + +#ifdef WIN32 +#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning +#endif //WIN32 + +#include "SND_OpenALDevice.h" +#ifndef __APPLE__ +#include "SND_SDLCDDevice.h" +#endif +#include "SoundDefines.h" + +#include "SND_Utils.h" + +#ifdef APPLE_FRAMEWORK_FIX +#include +#include +#include +#else +#include +#include +#include +#endif + +#include +#include +#if defined(WIN32) +#include +#else +#include +#endif +#include + +#include + +/* untill openal gets unified we need this hack for non-windows systems */ +#if !defined(WIN32) && !defined(ALC_MAJOR_VERSION) + +#include + +ALvoid alutLoadWAVMemory(ALbyte *memory,ALenum *format,ALvoid **data,ALsizei *size,ALsizei *freq,ALboolean *loop); +ALvoid alutUnloadWAV(ALenum format,ALvoid *data,ALsizei size,ALsizei freq); + +typedef struct /* WAV File-header */ +{ + ALubyte Id[4]; + ALsizei Size; + ALubyte Type[4]; +} WAVFileHdr_Struct; + +typedef struct /* WAV Fmt-header */ +{ + ALushort Format; + ALushort Channels; + ALuint SamplesPerSec; + ALuint BytesPerSec; + ALushort BlockAlign; + ALushort BitsPerSample; +} WAVFmtHdr_Struct; + +typedef struct /* WAV FmtEx-header */ +{ + ALushort Size; + ALushort SamplesPerBlock; +} WAVFmtExHdr_Struct; + +typedef struct /* WAV Smpl-header */ +{ + ALuint Manufacturer; + ALuint Product; + ALuint SamplePeriod; + ALuint Note; + ALuint FineTune; + ALuint SMPTEFormat; + ALuint SMPTEOffest; + ALuint Loops; + ALuint SamplerData; + struct + { + ALuint Identifier; + ALuint Type; + ALuint Start; + ALuint End; + ALuint Fraction; + ALuint Count; + } Loop[1]; +} WAVSmplHdr_Struct; + +typedef struct /* WAV Chunk-header */ +{ + ALubyte Id[4]; + ALuint Size; +} WAVChunkHdr_Struct; + +ALvoid alutLoadWAVMemory(ALbyte *memory,ALenum *format,ALvoid **data,ALsizei *size,ALsizei *freq,ALboolean *loop) +{ + WAVChunkHdr_Struct ChunkHdr; + WAVFmtExHdr_Struct FmtExHdr; + WAVFileHdr_Struct FileHdr; + WAVSmplHdr_Struct SmplHdr; + WAVFmtHdr_Struct FmtHdr; + ALbyte *Stream; + + *format=AL_FORMAT_MONO16; + *data=NULL; + *size=0; + *freq=22050; + *loop=AL_FALSE; + if (memory) + { + Stream=memory; + if (Stream) + { + memcpy(&FileHdr,Stream,sizeof(WAVFileHdr_Struct)); + Stream+=sizeof(WAVFileHdr_Struct); + FileHdr.Size=((FileHdr.Size+1)&~1)-4; + while ((FileHdr.Size!=0)&&(memcpy(&ChunkHdr,Stream,sizeof(WAVChunkHdr_Struct)))) + { + Stream+=sizeof(WAVChunkHdr_Struct); + if (!memcmp(ChunkHdr.Id,"fmt ",4)) + { + memcpy(&FmtHdr,Stream,sizeof(WAVFmtHdr_Struct)); + if (FmtHdr.Format==0x0001) + { + *format=(FmtHdr.Channels==1? + (FmtHdr.BitsPerSample==8?AL_FORMAT_MONO8:AL_FORMAT_MONO16): + (FmtHdr.BitsPerSample==8?AL_FORMAT_STEREO8:AL_FORMAT_STEREO16)); + *freq=FmtHdr.SamplesPerSec; + Stream+=ChunkHdr.Size; + } + else + { + memcpy(&FmtExHdr,Stream,sizeof(WAVFmtExHdr_Struct)); + Stream+=ChunkHdr.Size; + } + } + else if (!memcmp(ChunkHdr.Id,"data",4)) + { + if (FmtHdr.Format==0x0001) + { + *size=ChunkHdr.Size; + *data=malloc(ChunkHdr.Size+31); + if (*data) memcpy(*data,Stream,ChunkHdr.Size); + memset(((char *)*data)+ChunkHdr.Size,0,31); + Stream+=ChunkHdr.Size; + } + else if (FmtHdr.Format==0x0011) + { + //IMA ADPCM + } + else if (FmtHdr.Format==0x0055) + { + //MP3 WAVE + } + } + else if (!memcmp(ChunkHdr.Id,"smpl",4)) + { + memcpy(&SmplHdr,Stream,sizeof(WAVSmplHdr_Struct)); + *loop = (SmplHdr.Loops ? AL_TRUE : AL_FALSE); + Stream+=ChunkHdr.Size; + } + else Stream+=ChunkHdr.Size; + Stream+=ChunkHdr.Size&1; + FileHdr.Size-=(((ChunkHdr.Size+1)&~1)+8); + } + } + } +} + +ALvoid alutUnloadWAV(ALenum format,ALvoid *data,ALsizei size,ALsizei freq) +{ + if (data) + free(data); +} + +#endif /* WIN32 */ + +#ifdef __APPLE__ +#define OUDE_OPENAL 1 +#endif + + +SND_OpenALDevice::SND_OpenALDevice() + : SND_AudioDevice(), + m_context(NULL), + m_device(NULL) +{ + /* Removed the functionality for checking if noaudio was provided on */ + /* the commandline. */ + m_audio = true; + m_context = NULL; + m_buffersinitialized = false; + m_sourcesinitialized = false; + + // let's check if we can get openal to initialize... + if (m_audio) + { +#ifdef OUDE_OPENAL + m_audio = true; // openal_2.12 + alutInit(NULL, NULL); // openal_2.12 +#else + m_audio = false; + + ALCdevice *dev = alcOpenDevice(NULL); + if (dev) { + m_context = alcCreateContext(dev, NULL); + + if (m_context) { +#ifdef AL_VERSION_1_1 + alcMakeContextCurrent((ALCcontext*)m_context); +#else + alcMakeContextCurrent(m_context); +#endif + m_audio = true; + m_device = dev; +#ifdef __linux__ + /* + * SIGHUP Hack: + * + * On Linux, alcDestroyContext generates a SIGHUP (Hangup) when killing the OpenAL + * mixer thread, which kills Blender. + * + * So we set the signal to ignore.... + * + * TODO: check if this applies to other platforms. + * + */ + signal(SIGHUP, SIG_IGN); +#endif + } + } + +#endif + } + + // then try to generate some buffers + if (m_audio) + { + // let openal generate its buffers + alGenBuffers(NUM_BUFFERS, m_buffers); + m_buffersinitialized = true; + + for (int i = 0; i < NUM_BUFFERS; i++) + { + if (!alIsBuffer(m_buffers[i])) + { + //printf("\n\n WARNING: OpenAL returned with an error. Continuing without audio.\n\n"); + m_audio = false; + break; + } + } + } + + // next: the sources + if (m_audio) + { +#ifdef OUDE_OPENAL + ALenum alc_error = ALC_NO_ERROR; // openal_2.12 +#elif defined(_WIN32) + // alcGetError has no arguments on windows + ALenum alc_error = alcGetError(); // openal_2.14+ +#else + ALenum alc_error = alcGetError(NULL); // openal_2.14+ +#endif + + // let openal generate its sources + if (alc_error == ALC_NO_ERROR) + { + alGenSources(NUM_SOURCES, m_sources); + m_sourcesinitialized = true; + } + } + + // let's get us a wavecache + if (m_audio) + { + m_wavecache = new SND_WaveCache(); + } +#ifndef __APPLE__ + m_cdrom = new SND_SDLCDDevice(); +#endif +} + +void SND_OpenALDevice::UseCD(void) const +{ + // only fmod has CD support, so only create it here + SND_CDObject::CreateSystem(); + +} + +void SND_OpenALDevice::MakeCurrent() const +{ +#ifdef WIN32 + alcMakeContextCurrent(m_context); +#endif +} + + + +SND_OpenALDevice::~SND_OpenALDevice() +{ + MakeCurrent(); + + if (m_buffersinitialized) + { + alDeleteBuffers(NUM_BUFFERS, m_buffers); + m_buffersinitialized = false; + } + + if (m_sourcesinitialized) + { + for (int i = 0; i < NUM_SOURCES; i++) + alSourceStop(m_sources[i]); + + alDeleteSources(NUM_SOURCES, m_sources); + m_sourcesinitialized = false; + } + + if (m_context) { + MakeCurrent(); +#ifdef AL_VERSION_1_1 + alcDestroyContext((ALCcontext*)m_context); +#else + alcDestroyContext(m_context); +#endif + m_context = NULL; + } + +#ifdef __linux__ + // restore the signal state above. + signal(SIGHUP, SIG_DFL); +#endif + // let's see if we used the cd. if not, just leave it alone + SND_CDObject* pCD = SND_CDObject::Instance(); + + if (pCD) + { + this->StopCD(); + SND_CDObject::DisposeSystem(); + } +#ifndef __APPLE__ + if (m_cdrom) + delete m_cdrom; +#endif +#ifdef OUDE_OPENAL + if (m_audio) + alutExit(); +#else + if (m_device) + alcCloseDevice((ALCdevice*) m_device); +#endif +} + + + +SND_WaveSlot* SND_OpenALDevice::LoadSample(const STR_String& name, + void* memlocation, + int size) +{ + SND_WaveSlot* waveslot = NULL; + STR_String samplename = name; + + if (m_audio) + { + /* create the waveslot */ + waveslot = m_wavecache->GetWaveSlot(samplename); + + /* do we support this sample? */ + if (SND_IsSampleValid(name, memlocation)) + { + if (waveslot) + { + int buffer = waveslot->GetBuffer(); + void* data = NULL; +#ifndef __APPLE__ + char loop = 'a'; +#endif + int sampleformat, bitrate, numberofchannels; + ALenum al_error = alGetError(); + +#ifdef OUDE_OPENAL + ALsizei samplerate, numberofsamples; // openal_2.12 +#else + int samplerate, numberofsamples; // openal_2.14+ +#endif + + /* Give them some safe defaults just incase */ + bitrate = numberofchannels = 0; + + /* load the sample from memory? */ + if (size && memlocation) + { + waveslot->SetFileSize(size); + + /* what was (our) buffer? */ + int buffer = waveslot->GetBuffer(); + + /* get some info out of the sample */ + SND_GetSampleInfo((signed char*)memlocation, waveslot); + numberofchannels = SND_GetNumberOfChannels(memlocation); + bitrate = SND_GetBitRate(memlocation); + + /* load the sample into openal */ +#if defined(OUDE_OPENAL) || defined (__APPLE__) + alutLoadWAVMemory((char*)memlocation, &sampleformat, &data, &numberofsamples, &samplerate); // openal_2.12 +#else +#ifdef AL_VERSION_1_1 + alutLoadWAVMemory((ALbyte*)memlocation, &sampleformat, &data, &numberofsamples, &samplerate, &loop);// openal_2.14+ +#else + alutLoadWAVMemory((signed char*)memlocation, &sampleformat, &data, &numberofsamples, &samplerate, &loop);// openal_2.14+ + +#endif +#endif + /* put it in the buffer */ + alBufferData(m_buffers[buffer], sampleformat, data, numberofsamples, samplerate); + } + /* or from file? */ + else + { +#ifdef __APPLE__ + alutLoadWAVFile((ALbyte *)samplename.Ptr(), &sampleformat, &data, &numberofsamples, &samplerate); +#else + alutLoadWAVFile((ALbyte *)samplename.Ptr(), &sampleformat, &data, &numberofsamples, &samplerate, &loop); +#endif + /* put it in the buffer */ + alBufferData(m_buffers[buffer], sampleformat, data, numberofsamples, samplerate); + } + + /* fill the waveslot with info */ + al_error = alGetError(); + if (al_error == AL_NO_ERROR && m_buffers[buffer]) + { + waveslot->SetData(data); + waveslot->SetSampleFormat(sampleformat); + waveslot->SetNumberOfChannels(numberofchannels); + waveslot->SetSampleRate(samplerate); + waveslot->SetBitRate(bitrate); + waveslot->SetNumberOfSamples(numberofsamples); + + /* if the loading succeeded, mark the waveslot */ + waveslot->SetLoaded(true); + } + else + { + /* or when it failed, free the waveslot */ + m_wavecache->RemoveSample(waveslot->GetSampleName(), waveslot->GetBuffer()); + waveslot = NULL; + } + + /* and free the original stuff (copy was made in openal) */ + alutUnloadWAV(sampleformat, data, numberofsamples, samplerate); + } + } + else + { + /* sample not supported, remove waveslot */ + m_wavecache->RemoveSample(waveslot->GetSampleName(), waveslot->GetBuffer()); + waveslot = NULL; + } + } + return waveslot; +} + + + +// listener's and general stuff ////////////////////////////////////////////////////// + + + +/* sets the global dopplervelocity */ +void SND_OpenALDevice::SetDopplerVelocity(MT_Scalar dopplervelocity) const +{ + alDopplerVelocity ((float)dopplervelocity); +} + + + +/* sets the global dopplerfactor */ +void SND_OpenALDevice::SetDopplerFactor(MT_Scalar dopplerfactor) const +{ + alDopplerFactor ((float)dopplerfactor); +} + + + +/* sets the global rolloff factor */ +void SND_OpenALDevice::SetListenerRollOffFactor(MT_Scalar rollofffactor) const +{ + // not implemented in openal +} + + + +void SND_OpenALDevice::NextFrame() const +{ + // CD +#ifndef __APPLE__ + m_cdrom->NextFrame(); +#endif + // not needed by openal +} + + + +// set the gain for the listener +void SND_OpenALDevice::SetListenerGain(float gain) const +{ + alListenerf (AL_GAIN, gain); +} + + + +void SND_OpenALDevice::InitListener() +{ + // initialize the listener with these values that won't change + // (as long as we can have only one listener) + // now we can superimpose all listeners on each other (for they + // have the same settings) + float lispos[3] = {0,0,0}; + float lisvel[3] = {0,0,0}; +#ifdef WIN32 + float lisori[6] = {0,1,0,0,0,1}; +#else + float lisori[6] = {0,0,1,0,-1,0}; +#endif + + alListenerfv(AL_POSITION, lispos); + alListenerfv(AL_VELOCITY, lisvel); + alListenerfv(AL_ORIENTATION, lisori); +} + + + +// source playstate stuff //////////////////////////////////////////////////////////// + + + +/* sets the buffer */ +void SND_OpenALDevice::SetObjectBuffer(int id, unsigned int buffer) +{ + alSourcei (m_sources[id], AL_BUFFER, m_buffers[buffer]); +} + + + +// check if the sound's still playing +int SND_OpenALDevice::GetPlayState(int id) +{ + int alstate = 0; + int result = 0; + +#ifdef __APPLE__ + alGetSourcei(m_sources[id], AL_SOURCE_STATE, &alstate); +#else + alGetSourceiv(m_sources[id], AL_SOURCE_STATE, &alstate); +#endif + + switch(alstate) + { + case AL_INITIAL: + { + result = SND_INITIAL; + break; + } + case AL_PLAYING: + { + result = SND_PLAYING; + break; + } + case AL_PAUSED: + { + result = SND_PAUSED; + break; + } + case AL_STOPPED: + { + result = SND_STOPPED; + break; + } + default: + result = SND_UNKNOWN; + } + + return result; +} + + + +// make the source play +void SND_OpenALDevice::PlayObject(int id) +{ + alSourcePlay(m_sources[id]); +} + + + +// make the source stop +void SND_OpenALDevice::StopObject(int id) const +{ + float obpos[3] = {0,0,0}; + float obvel[3] = {0,0,0}; + + alSourcefv(m_sources[id], AL_POSITION, obpos); + alSourcefv(m_sources[id], AL_VELOCITY, obvel); + + alSourcef(m_sources[id], AL_GAIN, 1.0); + alSourcef(m_sources[id], AL_PITCH, 1.0); + alSourcei(m_sources[id], AL_LOOPING, AL_FALSE); + alSourceStop(m_sources[id]); +} + + + +// stop all sources +void SND_OpenALDevice::StopAllObjects() +{ + alSourceStopv(NUM_SOURCES, m_sources); +} + + + +// pause the source +void SND_OpenALDevice::PauseObject(int id) const +{ + alSourcePause(m_sources[id]); +} + + + +// source properties stuff //////////////////////////////////////////////////////////// + + + +// give openal the object's pitch +void SND_OpenALDevice::SetObjectPitch(int id, MT_Scalar pitch) const +{ + alSourcef (m_sources[id], AL_PITCH, (float)pitch); +} + + + +// give openal the object's gain +void SND_OpenALDevice::SetObjectGain(int id, MT_Scalar gain) const +{ + alSourcef (m_sources[id], AL_GAIN, (float)gain); +} + + + +// give openal the object's looping +void SND_OpenALDevice::SetObjectLoop(int id, unsigned int loopmode) const +{ + if (loopmode == SND_LOOP_OFF) + { + //printf("%d - ", id); + alSourcei (m_sources[id], AL_LOOPING, AL_FALSE); + } + else + alSourcei (m_sources[id], AL_LOOPING, AL_TRUE); +} + +void SND_OpenALDevice::SetObjectLoopPoints(int id, unsigned int loopstart, unsigned int loopend) const +{ + + +} + + +void SND_OpenALDevice::SetObjectMinGain(int id, MT_Scalar mingain) const +{ + alSourcef (m_sources[id], AL_MIN_GAIN, (float)mingain); +} + + + +void SND_OpenALDevice::SetObjectMaxGain(int id, MT_Scalar maxgain) const +{ + alSourcef (m_sources[id], AL_MAX_GAIN, (float)maxgain); +} + + + +void SND_OpenALDevice::SetObjectRollOffFactor(int id, MT_Scalar rollofffactor) const +{ + alSourcef (m_sources[id], AL_ROLLOFF_FACTOR, (float)rollofffactor); +} + + + +void SND_OpenALDevice::SetObjectReferenceDistance(int id, MT_Scalar referencedistance) const +{ + alSourcef (m_sources[id], AL_REFERENCE_DISTANCE, (float)referencedistance); +} + + + +// give openal the object's position +void SND_OpenALDevice::ObjectIs2D(int id) const +{ + float obpos[3] = {0,0,0}; + float obvel[3] = {0,0,0}; + + alSourcefv(m_sources[id], AL_POSITION, obpos); + alSourcefv(m_sources[id], AL_VELOCITY, obvel); +} + + + +void SND_OpenALDevice::SetObjectTransform(int id, + const MT_Vector3& position, + const MT_Vector3& velocity, + const MT_Matrix3x3& orientation, + const MT_Vector3& lisposition, + const MT_Scalar& rollofffactor) const +{ + float obpos[3]; + float obvel[3]; + + obpos[0] = (float)position[0] * (float)rollofffactor; //x (l/r) + obpos[1] = (float)position[1] * (float)rollofffactor; + obpos[2] = (float)position[2] * (float)rollofffactor; + + alSourcefv(m_sources[id], AL_POSITION, obpos); + + velocity.getValue(obvel); + alSourcefv(m_sources[id], AL_VELOCITY, obvel); +} + +void SND_OpenALDevice::PlayCD(int track) const +{ +#ifndef __APPLE__ + m_cdrom->PlayCD(track); +#endif +} + + +void SND_OpenALDevice::PauseCD(bool pause) const +{ +#ifndef __APPLE__ + m_cdrom->PauseCD(pause); +#endif +} + +void SND_OpenALDevice::StopCD() const +{ +#ifndef __APPLE__ + SND_CDObject* pCD = SND_CDObject::Instance(); + + if (pCD && pCD->GetUsed()) + { + m_cdrom->StopCD(); + } +#endif +} + +void SND_OpenALDevice::SetCDPlaymode(int playmode) const +{ +#ifndef __APPLE__ + m_cdrom->SetCDPlaymode(playmode); +#endif +} + +void SND_OpenALDevice::SetCDGain(MT_Scalar gain) const +{ +#ifndef __APPLE__ + m_cdrom->SetCDGain(gain); +#endif +} diff --git a/intern/SoundSystem/openal/SND_OpenALDevice.h b/intern/SoundSystem/openal/SND_OpenALDevice.h new file mode 100644 index 00000000000..e54c0443462 --- /dev/null +++ b/intern/SoundSystem/openal/SND_OpenALDevice.h @@ -0,0 +1,110 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef SND_OPENALDEVICE +#define SND_OPENALDEVICE + +#include "SND_AudioDevice.h" +#include "SoundDefines.h" + +typedef struct SDL_CD; + +class SND_OpenALDevice : public SND_AudioDevice +{ +public: + SND_OpenALDevice(); + virtual ~SND_OpenALDevice(); + + SND_WaveSlot* LoadSample(const STR_String& samplename, + void* memlocation, + int size); + + void InitListener(); + void SetListenerGain(float gain) const; + void SetDopplerVelocity(MT_Scalar dopplervelocity) const; + void SetDopplerFactor(MT_Scalar dopplerfactor) const; + void SetListenerRollOffFactor(MT_Scalar rollofffactor) const; + + void MakeCurrent() const; + + void NextFrame() const; + void UseCD() const; + + void SetObjectBuffer(int id, unsigned int buffer); + + int GetPlayState(int id); + void PlayObject(int id); + void StopObject(int id) const; + void StopAllObjects(); + void PauseObject(int id) const; + + void SetObjectLoop(int id, unsigned int loopmode) const; + void SetObjectLoopPoints(int id, unsigned int loopstart, unsigned int loopend) const; + void SetObjectPitch(int id, MT_Scalar pitch) const; + void SetObjectGain(int id, MT_Scalar gain) const; + void SetObjectMinGain(int id, MT_Scalar mingain) const; + void SetObjectMaxGain(int id, MT_Scalar maxgain) const; + void SetObjectRollOffFactor(int id, MT_Scalar rolloff) const; + void SetObjectReferenceDistance(int id, MT_Scalar distance) const; + + void SetObjectTransform(int id, + const MT_Vector3& position, + const MT_Vector3& velocity, + const MT_Matrix3x3& orientation, + const MT_Vector3& lisposition, + const MT_Scalar& rollofffactor) const; + void ObjectIs2D(int id) const; + + void PlayCD(int track) const; + void PauseCD(bool pause) const; + void StopCD() const; + void SetCDPlaymode(int playmode) const; + void SetCDGain(MT_Scalar gain) const; + + void StartUsingDSP() {}; + float* GetSpectrum() { return NULL; } + void StopUsingDSP() {}; + +private: + void* m_context; + void* m_device; + + unsigned int m_buffers[NUM_BUFFERS]; + unsigned int m_sources[NUM_SOURCES]; + bool m_buffersinitialized; + bool m_sourcesinitialized; +#ifndef __APPLE__ + class SND_SDLCDDevice* m_cdrom; +#endif +}; + +#endif //SND_OPENALDEVICE + diff --git a/intern/SoundSystem/openal/pthread_cancel.cpp b/intern/SoundSystem/openal/pthread_cancel.cpp new file mode 100644 index 00000000000..7651417db0b --- /dev/null +++ b/intern/SoundSystem/openal/pthread_cancel.cpp @@ -0,0 +1,70 @@ +/* $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * FreeBSD 3.4 does not yet have pthread_cancel (3.5 and above do) + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef __FreeBSD__ + +#include + +#if (__FreeBSD_version < 350000) +#include + +#define FD_READ 0x1 +#define _FD_LOCK(_fd,_type,_ts) _thread_fd_lock(_fd, _type, _ts) +#define _FD_UNLOCK(_fd,_type) _thread_fd_unlock(_fd, _type) + +int pthread_cancel(pthread_t pthread) { + pthread_exit(NULL); + return 0; +} + +long fpathconf(int fd, int name) +{ + long ret; + + if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) { + ret = _thread_sys_fpathconf(fd, name); + _FD_UNLOCK(fd, FD_READ); + } + return ret; +} + +#endif + +int pthread_atfork(void *a, void *b, void *c) { + return 0; +} + +#endif diff --git a/intern/SoundSystem/sdl/Makefile b/intern/SoundSystem/sdl/Makefile new file mode 100644 index 00000000000..0a1632c4a41 --- /dev/null +++ b/intern/SoundSystem/sdl/Makefile @@ -0,0 +1,46 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = SDLSoundSystem +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_1_CPP_WARNINGS) + +CPPFLAGS += $(NAN_SDLCFLAGS) +CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I../intern +CPPFLAGS += -I.. +CPPFLAGS += -I. diff --git a/intern/SoundSystem/sdl/SND_SDLCDDevice.cpp b/intern/SoundSystem/sdl/SND_SDLCDDevice.cpp new file mode 100644 index 00000000000..e2419b47269 --- /dev/null +++ b/intern/SoundSystem/sdl/SND_SDLCDDevice.cpp @@ -0,0 +1,155 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * SND_SDLCDDevice + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef WIN32 +#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning +#endif //WIN32 + +#include "MT_Scalar.h" + +#include "SND_SDLCDDevice.h" +#include "SoundDefines.h" + +#include + +SND_SDLCDDevice::SND_SDLCDDevice() : + m_cdrom(NULL), + m_cdplaying(false), + m_cdtrack(0), + m_cdplaymode(SND_CD_TRACK), + m_frame(0) +{ + init(); +} + +void SND_SDLCDDevice::init() +{ + if (SDL_InitSubSystem(SDL_INIT_CDROM)) + { + fprintf(stderr, "Error initializing CDROM\n"); + return; + } + + /* Check for CD drives */ + if(!SDL_CDNumDrives()) + { + /* None found */ + fprintf(stderr, "No CDROM devices available\n"); + return; + } + + /* Open the default drive */ + m_cdrom = SDL_CDOpen(0); + + /* Did if open? Check if cdrom is NULL */ + if(!m_cdrom) + { + fprintf(stderr, "Couldn't open drive: %s", SDL_GetError()); + return; + } +} + +SND_SDLCDDevice::~SND_SDLCDDevice() +{ + StopCD(); + SDL_CDClose(m_cdrom); +} + +void SND_SDLCDDevice::NextFrame() +{ + m_frame++; + m_frame &= 127; + + if (!m_frame && m_cdrom && m_cdplaying && SDL_CDStatus(m_cdrom) == CD_STOPPED) + { + switch (m_cdplaymode) + { + case SND_CD_ALL: + if (m_cdtrack < m_cdrom->numtracks) + PlayCD(m_cdtrack + 1); + else + m_cdplaying = false; + break; + default: + case SND_CD_TRACK: + m_cdplaying = false; + break; + case SND_CD_TRACKLOOP: + PlayCD(m_cdtrack); + break; + } + + } +} + +void SND_SDLCDDevice::PlayCD(int track) +{ + if ( m_cdrom && CD_INDRIVE(SDL_CDStatus(m_cdrom)) ) { + SDL_CDPlayTracks(m_cdrom, track-1, 0, track, 0); + m_cdplaying = true; + m_cdtrack = track; + } +} + + +void SND_SDLCDDevice::PauseCD(bool pause) +{ + if (!m_cdrom) + return; + + if (pause) + SDL_CDPause(m_cdrom); + else + SDL_CDResume(m_cdrom); +} + +void SND_SDLCDDevice::StopCD() +{ + if (m_cdrom) + SDL_CDStop(m_cdrom); + m_cdplaying = false; +} + +void SND_SDLCDDevice::SetCDPlaymode(int playmode) +{ + m_cdplaymode = playmode; +} + +void SND_SDLCDDevice::SetCDGain(MT_Scalar gain) +{ + +} diff --git a/intern/SoundSystem/sdl/SND_SDLCDDevice.h b/intern/SoundSystem/sdl/SND_SDLCDDevice.h new file mode 100644 index 00000000000..829f361ea22 --- /dev/null +++ b/intern/SoundSystem/sdl/SND_SDLCDDevice.h @@ -0,0 +1,61 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef SND_SDLCDDEVICE +#define SND_SDLCDDEVICE + +typedef struct SDL_CD; + +class SND_SDLCDDevice +{ +public: + SND_SDLCDDevice(); + ~SND_SDLCDDevice(); + + void NextFrame(); + + void PlayCD(int track); + void PauseCD(bool pause); + void StopCD(); + void SetCDPlaymode(int playmode); + void SetCDGain(MT_Scalar gain); + +private: + void init(); + /* CD Audio */ + SDL_CD* m_cdrom; + bool m_cdplaying; + int m_cdtrack; + unsigned char m_cdplaymode; + unsigned char m_frame; +}; + +#endif diff --git a/intern/bmfont/BMF_Api.h b/intern/bmfont/BMF_Api.h new file mode 100644 index 00000000000..1b4a4ee3129 --- /dev/null +++ b/intern/bmfont/BMF_Api.h @@ -0,0 +1,164 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * + * API of the OpenGL bitmap font library. + * Currently draws fonts using the glBitmap routine. + * This implies that drawing speed is heavyly dependant on + * the 2D capabilities of the graphics card. + */ + +#ifndef __BMF_API_H +#define __BMF_API_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "BMF_Fonts.h" + +/** + * Returns the font for a given font type. + * @param font The font to retrieve. + * @return The font (or nil if not found). + */ +BMF_Font* BMF_GetFont(BMF_FontType font); + +/** + * Draws a character at the current raster position. + * @param font The font to use. + * @param c The character to draw. + * @return Indication of success (0 == error). + */ +int BMF_DrawCharacter(BMF_Font* font, char c); + +/** + * Draws a string at the current raster position. + * @param font The font to use. + * @param str The string to draw. + * @return Indication of success (0 == error). + */ +int BMF_DrawString(BMF_Font* font, char* str); + +/** + * Returns the width of a character in pixels. + * @param font The font to use. + * @param c The character. + * @return The length. + */ +int BMF_GetCharacterWidth(BMF_Font* font, char c); + +/** + * Returns the width of a string of characters. + * @param font The font to use. + * @param str The string. + * @return The length. + */ +int BMF_GetStringWidth(BMF_Font* font, char* str); + +/** + * Returns the bounding box of a string of characters. + * @param font The font to use. + * @param str The string. + * @param llx Lower left x coord + * @param lly Lower left y coord + * @param urx Upper right x coord + * @param ury Upper right y coord + */ +void BMF_GetStringBoundingBox(BMF_Font* font, char* str, float*llx, float *lly, float *urx, float *ury); + + +/** + * Returns the bounding box of the font. The width and + * height represent the bounding box of the union of + * all glyps. The minimum and maximum values of the + * box represent the extent of the font and its positioning + * about the origin. + */ +void BMF_GetFontBoundingBox(BMF_Font* font, int *xmin_r, int *ymin_r, int *xmax_r, int *ymax_r); + +/** + * Same as GetFontBoundingBox but only returns the height + */ +int BMF_GetFontHeight(BMF_Font* font); + +/** + * Convert the given @a font to a texture, and return the GL texture + * ID of the texture. If the texture ID is bound, text can + * be drawn using the texture by calling DrawStringTexture. + * + * @param font The font to create the texture from. + * @return The GL texture ID of the new texture, or -1 if unable + * to create. + */ +int BMF_GetFontTexture(BMF_Font* font); + +/** + * Draw the given @a str at the point @a x, @a y, @a z, using + * texture coordinates. This assumes that an appropriate texture + * has been bound, see BMF_BitmapFont::GetTexture(). The string + * is drawn along the positive X axis. + * + * @param font The font to draw with. + * @param string The c-string to draw. + * @param x The x coordinate to start drawing at. + * @param y The y coordinate to start drawing at. + * @param z The z coordinate to start drawing at. + */ +void BMF_DrawStringTexture(BMF_Font* font, char* string, float x, float y, float z); + + /** + * Draw the given @a string at the point @a xpos, @a ypos using + * char and float buffers. + * + * @param string The c-string to draw. + * @param xpos The x coordinate to start drawing at. + * @param ypos The y coordinate to start drawing at. + * @param fgcol The forground color. + * @param bgcol The background color. + * @param buf Unsigned char image buffer, when NULL to not operate on it. + * @param fbuf float image buffer, when NULL to not operate on it. + * @param w image buffer width. + * @param h image buffer height. + */ +void BMF_DrawStringBuf(BMF_Font* font, char *str, int posx, int posy, float *col, unsigned char *buf, float *fbuf, int w, int h); + + +#ifdef __cplusplus +} +#endif + +#endif /* __BMF_API_H */ + diff --git a/intern/bmfont/BMF_Fonts.h b/intern/bmfont/BMF_Fonts.h new file mode 100644 index 00000000000..bf7c370e47e --- /dev/null +++ b/intern/bmfont/BMF_Fonts.h @@ -0,0 +1,77 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * Defines the names of the fonts in the library. + */ + +#ifndef __BMF_FONTS_H +#define __BMF_FONTS_H + +#include "BMF_Settings.h" + +typedef enum +{ + BMF_kHelvetica10 = 0, +#if BMF_INCLUDE_HELV12 + BMF_kHelvetica12, +#endif +#if BMF_INCLUDE_HELVB8 + BMF_kHelveticaBold8, +#endif +#if BMF_INCLUDE_HELVB10 + BMF_kHelveticaBold10, +#endif +#if BMF_INCLUDE_HELVB12 + BMF_kHelveticaBold12, +#endif +#if BMF_INCLUDE_HELVB14 + BMF_kHelveticaBold14, +#endif +#if BMF_INCLUDE_SCR12 + BMF_kScreen12, +#endif +#if BMF_INCLUDE_SCR14 + BMF_kScreen14, +#endif +#if BMF_INCLUDE_SCR15 + BMF_kScreen15, +#endif + BMF_kNumFonts +} BMF_FontType; + +typedef struct BMF_Font BMF_Font; + +#endif /* __BMF_FONTS_H */ + diff --git a/intern/bmfont/BMF_Settings.h b/intern/bmfont/BMF_Settings.h new file mode 100644 index 00000000000..247f9e474fc --- /dev/null +++ b/intern/bmfont/BMF_Settings.h @@ -0,0 +1,70 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * Allows you to determine which fonts to include in the library. + */ + +#ifndef __BMF_SETTINGS_H +#define __BMF_SETTINGS_H + +/* This font is included always */ +#define BMF_INCLUDE_HELV10 1 + +#ifndef BMF_MINIMAL + +/* These fonts are included with the minimal setting defined */ +#define BMF_INCLUDE_HELV12 1 +#define BMF_INCLUDE_HELVB8 1 +#define BMF_INCLUDE_HELVB10 1 +#define BMF_INCLUDE_HELVB12 1 +#define BMF_INCLUDE_HELVB14 1 +#define BMF_INCLUDE_SCR12 1 +#define BMF_INCLUDE_SCR14 1 +#define BMF_INCLUDE_SCR15 1 + +#else /* BMF_MINIMAL */ +#define BMF_INCLUDE_HELV12 0 +#define BMF_INCLUDE_HELVB8 0 +#define BMF_INCLUDE_HELVB10 0 +#define BMF_INCLUDE_HELVB12 0 +#define BMF_INCLUDE_HELVB14 0 +#define BMF_INCLUDE_SCR12 0 +#define BMF_INCLUDE_SCR14 0 +#define BMF_INCLUDE_SCR15 0 + +#endif /* BMF_MINIMAL */ + +#endif /* __BMF_SETTINGS_H */ + diff --git a/intern/bmfont/CMakeLists.txt b/intern/bmfont/CMakeLists.txt new file mode 100644 index 00000000000..e3b8242ceac --- /dev/null +++ b/intern/bmfont/CMakeLists.txt @@ -0,0 +1,35 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC . intern) + +FILE(GLOB SRC intern/*.cpp) + +BLENDERLIB(bf_bmfont "${SRC}" "${INC}") +#, libtype=['intern','player'], priority = [20, 185] ) diff --git a/intern/bmfont/Makefile b/intern/bmfont/Makefile new file mode 100644 index 00000000000..9c0193fee1b --- /dev/null +++ b/intern/bmfont/Makefile @@ -0,0 +1,56 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# bmfont main makefile. +# + +include nan_definitions.mk + +LIBNAME = bmfont +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +#not ready yet TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_BMFONT) ] || mkdir $(NAN_BMFONT) + @[ -d $(NAN_BMFONT)/include ] || mkdir $(NAN_BMFONT)/include + @[ -d $(NAN_BMFONT)/lib ] || mkdir $(NAN_BMFONT)/lib + @[ -d $(NAN_BMFONT)/lib/debug ] || mkdir $(NAN_BMFONT)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libbmfont.a $(NAN_BMFONT)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libbmfont.a $(NAN_BMFONT)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_BMFONT)/lib/libbmfont.a + ranlib $(NAN_BMFONT)/lib/debug/libbmfont.a +endif + @../tools/cpifdiff.sh *.h $(NAN_BMFONT)/include/ + diff --git a/intern/bmfont/SConscript b/intern/bmfont/SConscript new file mode 100644 index 00000000000..4febe2735e7 --- /dev/null +++ b/intern/bmfont/SConscript @@ -0,0 +1,10 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.cpp') + +incs = '. intern' +incs += ' ' + env['BF_OPENGL_INC'] +defs = '' + +env.BlenderLib ('bf_bmfont', sources, Split(incs), Split(defs), libtype=['intern','player'], priority = [20, 185] ) diff --git a/intern/bmfont/intern/BMF_Api.cpp b/intern/bmfont/intern/BMF_Api.cpp new file mode 100644 index 00000000000..eaa8ffb939d --- /dev/null +++ b/intern/bmfont/intern/BMF_Api.cpp @@ -0,0 +1,186 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * + * Implementation of the API of the OpenGL bitmap font library. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BMF_Api.h" + +#include "BMF_BitmapFont.h" + + +#if BMF_INCLUDE_HELV10 +extern BMF_FontData BMF_font_helv10; +static BMF_BitmapFont bmfHelv10(&BMF_font_helv10); +#endif // BMF_INCLUDE_HELV10 +#if BMF_INCLUDE_HELV12 +extern BMF_FontData BMF_font_helv12; +static BMF_BitmapFont bmfHelv12(&BMF_font_helv12); +#endif // BMF_INCLUDE_HELV12 +#if BMF_INCLUDE_HELVB8 +extern BMF_FontData BMF_font_helvb8; +static BMF_BitmapFont bmfHelvb8(&BMF_font_helvb8); +#endif // BMF_INCLUDE_HELVB8 +#if BMF_INCLUDE_HELVB10 +extern BMF_FontData BMF_font_helvb10; +static BMF_BitmapFont bmfHelvb10(&BMF_font_helvb10); +#endif // BMF_INCLUDE_HELVB10 +#if BMF_INCLUDE_HELVB12 +extern BMF_FontData BMF_font_helvb12; +static BMF_BitmapFont bmfHelvb12(&BMF_font_helvb12); +#endif // BMF_INCLUDE_HELVB12 +#if BMF_INCLUDE_HELVB14 +extern BMF_FontData BMF_font_helvb14; +static BMF_BitmapFont bmfHelvb14(&BMF_font_helvb14); +#endif // BMF_INCLUDE_HELVB14 +#if BMF_INCLUDE_SCR12 +extern BMF_FontData BMF_font_scr12; +static BMF_BitmapFont bmfScreen12(&BMF_font_scr12); +#endif // BMF_INCLUDE_SCR12 +#if BMF_INCLUDE_SCR14 +extern BMF_FontData BMF_font_scr14; +static BMF_BitmapFont bmfScreen14(&BMF_font_scr14); +#endif // BMF_INCLUDE_SCR14 +#if BMF_INCLUDE_SCR15 +extern BMF_FontData BMF_font_scr15; +static BMF_BitmapFont bmfScreen15(&BMF_font_scr15); +#endif // BMF_INCLUDE_SCR15 + + +BMF_Font* BMF_GetFont(BMF_FontType font) +{ + switch (font) + { +#if BMF_INCLUDE_HELV10 + case BMF_kHelvetica10: return (BMF_Font*) &bmfHelv10; +#endif // BMF_INCLUDE_HELV10 +#if BMF_INCLUDE_HELV12 + case BMF_kHelvetica12: return (BMF_Font*) &bmfHelv12; +#endif // BMF_INCLUDE_HELV12 +#if BMF_INCLUDE_HELVB8 + case BMF_kHelveticaBold8: return (BMF_Font*) &bmfHelvb8; +#endif // BMF_INCLUDE_HELVB8 +#if BMF_INCLUDE_HELVB10 + case BMF_kHelveticaBold10: return (BMF_Font*) &bmfHelvb10; +#endif // BMF_INCLUDE_HELVB10 +#if BMF_INCLUDE_HELVB12 + case BMF_kHelveticaBold12: return (BMF_Font*) &bmfHelvb12; +#endif // BMF_INCLUDE_HELVB12 +#if BMF_INCLUDE_HELVB14 + case BMF_kHelveticaBold14: return (BMF_Font*) &bmfHelvb14; +#endif // BMF_INCLUDE_HELVB12 +#if BMF_INCLUDE_SCR12 + case BMF_kScreen12: return (BMF_Font*) &bmfScreen12; +#endif // BMF_INCLUDE_SCR12 +#if BMF_INCLUDE_SCR14 + case BMF_kScreen14: return (BMF_Font*) &bmfScreen14; +#endif // BMF_INCLUDE_SCR14 +#if BMF_INCLUDE_SCR15 + case BMF_kScreen15: return (BMF_Font*) &bmfScreen15; +#endif // BMF_INCLUDE_SCR15 + default: + break; + } + return 0; +} + + +int BMF_DrawCharacter(BMF_Font* font, char c) +{ + char str[2] = {c, '\0'}; + return BMF_DrawString(font, str); +} + + +int BMF_DrawString(BMF_Font* font, char* str) +{ + if (!font) return 0; + ((BMF_BitmapFont*)font)->DrawString(str); + return 1; +} + + +int BMF_GetCharacterWidth(BMF_Font* font, char c) +{ + char str[2] = {c, '\0'}; + return BMF_GetStringWidth(font, str); +} + + +int BMF_GetStringWidth(BMF_Font* font, char* str) +{ + if (!font) return 0; + return ((BMF_BitmapFont*)font)->GetStringWidth(str); +} + +void BMF_GetStringBoundingBox(BMF_Font* font, char* str, float*llx, float *lly, float *urx, float *ury){ + if (!font){ + *llx = *lly = *urx = *ury = 0; + }else{ + ((BMF_BitmapFont*)font)->GetStringBoundingBox(str, llx, lly, urx, ury); + } +} + +void BMF_GetFontBoundingBox(BMF_Font* font, int *xmin_r, int *ymin_r, int *xmax_r, int *ymax_r) +{ + if (!font) return; + ((BMF_BitmapFont*)font)->GetFontBoundingBox(*xmin_r, *ymin_r, *xmax_r, *ymax_r); +} + +int BMF_GetFontHeight(BMF_Font* font) +{ + if (!font) return -1; + return ((BMF_BitmapFont*)font)->GetFontHeight(); +} + +int BMF_GetFontTexture(BMF_Font* font) { + if (!font) return -1; + return ((BMF_BitmapFont*)font)->GetTexture(); +} + +void BMF_DrawStringTexture(BMF_Font* font, char *string, float x, float y, float z) { + if (!font) return; + ((BMF_BitmapFont*)font)->DrawStringTexture(string, x, y, z); +} + +void BMF_DrawStringBuf(BMF_Font* font, char *str, int posx, int posy, float *col, unsigned char *buf, float *fbuf, int w, int h) { + if (!font) return; + ((BMF_BitmapFont*)font)->DrawStringBuf(str, posx, posy, col, buf, fbuf, w, h); +} diff --git a/intern/bmfont/intern/BMF_BitmapFont.cpp b/intern/bmfont/intern/BMF_BitmapFont.cpp new file mode 100644 index 00000000000..2ea14b4b203 --- /dev/null +++ b/intern/bmfont/intern/BMF_BitmapFont.cpp @@ -0,0 +1,322 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + */ + + +#include + + + +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(WIN32) || defined(__APPLE__) + #ifdef WIN32 + #if !defined(__CYGWIN32__) + #pragma warning(disable:4244) + #endif /* __CYGWIN32__ */ + #include + #include + #else // WIN32 + // __APPLE__ is defined + #include + #endif // WIN32 +#else // defined(WIN32) || defined(__APPLE__) + #include +#endif // defined(WIN32) || defined(__APPLE__) + +#include "BMF_BitmapFont.h" + + +BMF_BitmapFont::BMF_BitmapFont(BMF_FontData* fontData) +: m_fontData(fontData) +{ +} + + +BMF_BitmapFont::~BMF_BitmapFont(void) +{ +} + +void BMF_BitmapFont::DrawString(char* str) +{ + GLint alignment; + unsigned char c; + + glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + while ( (c = (unsigned char) *str++) ) { + BMF_CharData & cd = m_fontData->chars[c]; + + if (cd.data_offset==-1) { + GLubyte nullBitmap = 0; + + glBitmap(1, 1, 0, 0, cd.advance, 0, &nullBitmap); + } else { + GLubyte *bitmap = &m_fontData->bitmap_data[cd.data_offset]; + + glBitmap(cd.width, cd.height, cd.xorig, cd.yorig, cd.advance, 0, bitmap); + } + } + + glPixelStorei(GL_UNPACK_ALIGNMENT, alignment); +} + + +int BMF_BitmapFont::GetStringWidth(char* str) +{ + unsigned char c; + int length = 0; + + while ( (c = (unsigned char) *str++) ) { + length += m_fontData->chars[c].advance; + } + + return length; +} + +void BMF_BitmapFont::GetFontBoundingBox(int & xMin, int & yMin, int & xMax, int & yMax) +{ + xMin = m_fontData->xmin; + yMin = m_fontData->ymin; + xMax = m_fontData->xmax; + yMax = m_fontData->ymax; +} + +int BMF_BitmapFont::GetFontHeight( void ) +{ + return m_fontData->ymax - m_fontData->ymin; +} + +void BMF_BitmapFont::GetStringBoundingBox(char* str, float*llx, float *lly, float *urx, float *ury) +{ + unsigned char c; + int length = 0; + int ascent = 0; + int descent = 0; + + while ( (c = (unsigned char) *str++) ) { + length += m_fontData->chars[c].advance; + int d = m_fontData->chars[c].yorig; + int a = m_fontData->chars[c].height - m_fontData->chars[c].yorig; + if(a > ascent) ascent = a; + if(d > descent) descent = d; + } + *llx = (float)0; + *lly = (float)-descent; + *urx = (float)length; + *ury = (float)ascent; +} + + +int BMF_BitmapFont::GetTexture() +{ + int fWidth = m_fontData->xmax - m_fontData->xmin; + int fHeight = m_fontData->ymax - m_fontData->ymin; + + if (fWidth>=16 || fHeight>=16) { + return -1; + } + + int cRows = 16, cCols = 16; + int cWidth = 16, cHeight = 16; + int iWidth = cCols*cWidth; + int iHeight = cRows*cHeight; + GLubyte *img = new GLubyte [iHeight*iWidth]; + GLuint texId; + + int baseLine = -(m_fontData->ymin); + + memset(img, 0, iHeight*iWidth); + for (int i = 0; i<256; i++) { + BMF_CharData & cd = m_fontData->chars[i]; + + if (cd.data_offset != -1) { + int cellX = i%16; + int cellY = i/16; + + for (int y = 0; ybitmap_data[cd.data_offset + ((cd.width+7)/8)*y]; + + for (int x = 0; xymin); + + glBegin(GL_QUADS); + while ( (c = (unsigned char) *str++) ) { + BMF_CharData & cd = m_fontData->chars[c]; + + if (cd.data_offset != -1) { + float cellX = (c%16)/16.0; + float cellY = (c/16)/16.0; + + glTexCoord2f(cellX + 1.0/16.0, cellY); + glVertex3f(x + pos + 16.0, -baseLine + y + 0.0, z); + + glTexCoord2f(cellX + 1.0/16.0, cellY + 1.0/16.0); + glVertex3f(x + pos + 16.0, -baseLine + y + 16.0, z); + + glTexCoord2f(cellX, cellY + 1.0/16.0); + glVertex3f(x + pos + 0.0, -baseLine + y + 16.0, z); + + glTexCoord2f(cellX, cellY); + glVertex3f(x + pos + 0.0, -baseLine + y + 0.0, z); + } + + pos += cd.advance; + } + glEnd(); +} + +#define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.0f*val)) +void BMF_BitmapFont::DrawStringBuf(char *str, int posx, int posy, float *col, unsigned char *buf, float *fbuf, int w, int h) +{ + int x, y; + + if (buf==0 && fbuf==0) + return; + + /*offset for font*/ + posx -= m_fontData->xmin; + posy -= m_fontData->ymin; + + if (buf) { + unsigned char colch[4]; + unsigned char *max, *pixel; + unsigned char c; + + for (x=0; x<4; x++) { + colch[x] = FTOCHAR(col[x]); + } + + max = buf + (4 * (w * h)); + while ((c = (unsigned char) *str++)) { + BMF_CharData & cd = m_fontData->chars[c]; + if (cd.data_offset != -1) { + for (y = 0; y < cd.height; y++) { + unsigned char* chrRow = &m_fontData->bitmap_data[cd.data_offset + ((cd.width+7)/8)*y]; + for (x = cd.xorig; x < cd.width; x++) { + pixel = buf + 4 * (((posy + y - cd.yorig) * w) + (posx + x)); + if ((pixel < max) && (pixel > buf)) { + int byteIdx = x/8; + int bitIdx = 7 - (x%8); + + if (chrRow[byteIdx]&(1<chars[c]; + if (cd.data_offset != -1) { + for (y = 0; y < cd.height; y++) { + unsigned char* chrRow = &m_fontData->bitmap_data[cd.data_offset + ((cd.width+7)/8)*y]; + for (x = cd.xorig; x < cd.width; x++) { + pixel = fbuf + 4 * (((posy + y - cd.yorig) * w) + (posx + x)); + if ((pixel < max) && (pixel > fbuf)) { + int byteIdx = x/8; + int bitIdx = 7 - (x%8); + + if (chrRow[byteIdx]&(1< +#endif + +#include "BMF_FontData.h" + +#include "BMF_Settings.h" + +#if BMF_INCLUDE_HELV10 + +static unsigned char bitmap_data[]= { + 0x80,0x00,0x80,0x80,0x80,0x80,0x80,0x80, + 0xa0,0xa0,0x50,0x50,0xf8,0x28,0x7c,0x28, + 0x28,0x20,0x70,0xa8,0x28,0x70,0xa0,0xa8, + 0x70,0x20,0x26,0x29,0x16,0x10,0x08,0x68, + 0x94,0x64,0x64,0x98,0x98,0xa4,0x60,0x50, + 0x50,0x20,0x80,0x40,0x40,0x20,0x40,0x40, + 0x80,0x80,0x80,0x80,0x40,0x40,0x20,0x80, + 0x40,0x40,0x20,0x20,0x20,0x20,0x40,0x40, + 0x80,0xa0,0x40,0xa0,0x20,0x20,0xf8,0x20, + 0x20,0x80,0x40,0x40,0xf8,0x80,0x80,0x80, + 0x40,0x40,0x40,0x40,0x20,0x20,0x70,0x88, + 0x88,0x88,0x88,0x88,0x88,0x70,0x40,0x40, + 0x40,0x40,0x40,0x40,0xc0,0x40,0xf8,0x80, + 0x40,0x30,0x08,0x08,0x88,0x70,0x70,0x88, + 0x08,0x08,0x30,0x08,0x88,0x70,0x10,0x10, + 0xf8,0x90,0x50,0x50,0x30,0x10,0x70,0x88, + 0x08,0x08,0xf0,0x80,0x80,0xf8,0x70,0x88, + 0x88,0xc8,0xb0,0x80,0x88,0x70,0x40,0x40, + 0x20,0x20,0x10,0x10,0x08,0xf8,0x70,0x88, + 0x88,0x88,0x70,0x88,0x88,0x70,0x70,0x88, + 0x08,0x68,0x98,0x88,0x88,0x70,0x80,0x00, + 0x00,0x00,0x00,0x80,0x80,0x40,0x40,0x00, + 0x00,0x00,0x00,0x40,0x20,0x40,0x80,0x40, + 0x20,0xf0,0x00,0xf0,0x80,0x40,0x20,0x40, + 0x80,0x40,0x00,0x40,0x40,0x20,0x10,0x90, + 0x60,0x3e,0x00,0x40,0x00,0x9b,0x00,0xa4, + 0x80,0xa4,0x80,0xa2,0x40,0x92,0x40,0x4d, + 0x40,0x20,0x80,0x1f,0x00,0x82,0x82,0x7c, + 0x44,0x28,0x28,0x10,0x10,0xf0,0x88,0x88, + 0x88,0xf0,0x88,0x88,0xf0,0x78,0x84,0x80, + 0x80,0x80,0x80,0x84,0x78,0xf0,0x88,0x84, + 0x84,0x84,0x84,0x88,0xf0,0xf8,0x80,0x80, + 0x80,0xf8,0x80,0x80,0xf8,0x80,0x80,0x80, + 0x80,0xf0,0x80,0x80,0xf8,0x74,0x8c,0x84, + 0x8c,0x80,0x80,0x84,0x78,0x84,0x84,0x84, + 0x84,0xfc,0x84,0x84,0x84,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x60,0x90,0x10, + 0x10,0x10,0x10,0x10,0x10,0x88,0x88,0x90, + 0x90,0xe0,0xa0,0x90,0x88,0xf0,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x92,0x92,0x92, + 0xaa,0xaa,0xc6,0xc6,0x82,0x8c,0x8c,0x94, + 0x94,0xa4,0xa4,0xc4,0xc4,0x78,0x84,0x84, + 0x84,0x84,0x84,0x84,0x78,0x80,0x80,0x80, + 0x80,0xf0,0x88,0x88,0xf0,0x02,0x7c,0x8c, + 0x94,0x84,0x84,0x84,0x84,0x78,0x88,0x88, + 0x88,0x88,0xf0,0x88,0x88,0xf0,0x70,0x88, + 0x88,0x08,0x70,0x80,0x88,0x70,0x20,0x20, + 0x20,0x20,0x20,0x20,0x20,0xf8,0x78,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x10,0x28, + 0x28,0x44,0x44,0x44,0x82,0x82,0x22,0x00, + 0x22,0x00,0x22,0x00,0x55,0x00,0x49,0x00, + 0x49,0x00,0x88,0x80,0x88,0x80,0x88,0x88, + 0x50,0x50,0x20,0x50,0x88,0x88,0x10,0x10, + 0x10,0x28,0x28,0x44,0x44,0x82,0xf8,0x80, + 0x40,0x20,0x20,0x10,0x08,0xf8,0xc0,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0, + 0x20,0x20,0x40,0x40,0x40,0x40,0x80,0x80, + 0xc0,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0xc0,0x88,0x50,0x50,0x20,0x20,0xfc, + 0x80,0x80,0x40,0x68,0x90,0x90,0x70,0x10, + 0xe0,0xb0,0xc8,0x88,0x88,0xc8,0xb0,0x80, + 0x80,0x60,0x90,0x80,0x80,0x90,0x60,0x68, + 0x98,0x88,0x88,0x98,0x68,0x08,0x08,0x60, + 0x90,0x80,0xf0,0x90,0x60,0x40,0x40,0x40, + 0x40,0x40,0xe0,0x40,0x30,0x70,0x08,0x68, + 0x98,0x88,0x88,0x98,0x68,0x88,0x88,0x88, + 0x88,0xc8,0xb0,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x00,0x80,0x90,0x90, + 0xa0,0xc0,0xa0,0x90,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x92,0x92, + 0x92,0x92,0x92,0xec,0x88,0x88,0x88,0x88, + 0xc8,0xb0,0x70,0x88,0x88,0x88,0x88,0x70, + 0x80,0x80,0xb0,0xc8,0x88,0x88,0xc8,0xb0, + 0x08,0x08,0x68,0x98,0x88,0x88,0x98,0x68, + 0x80,0x80,0x80,0x80,0xc0,0xa0,0x60,0x90, + 0x10,0x60,0x90,0x60,0x60,0x40,0x40,0x40, + 0x40,0xe0,0x40,0x40,0x70,0x90,0x90,0x90, + 0x90,0x90,0x20,0x20,0x50,0x50,0x88,0x88, + 0x28,0x28,0x54,0x54,0x92,0x92,0x88,0x88, + 0x50,0x20,0x50,0x88,0x80,0x40,0x40,0x60, + 0xa0,0xa0,0x90,0x90,0xf0,0x80,0x40,0x20, + 0x10,0xf0,0x20,0x40,0x40,0x40,0x40,0x80, + 0x40,0x40,0x40,0x20,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x40, + 0x40,0x40,0x40,0x20,0x40,0x40,0x40,0x80, + 0x98,0x64,0x80,0x80,0x80,0x80,0x80,0x80, + 0x00,0x80,0x40,0x70,0xa8,0xa0,0xa0,0xa8, + 0x70,0x10,0xb0,0x48,0x40,0x40,0xe0,0x40, + 0x48,0x30,0x90,0x60,0x90,0x90,0x60,0x90, + 0x20,0xf8,0x20,0xf8,0x50,0x50,0x88,0x88, + 0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x80, + 0x80,0x80,0x70,0x88,0x18,0x70,0xc8,0x98, + 0x70,0xc0,0x88,0x70,0xa0,0x38,0x44,0x9a, + 0xa2,0x9a,0x44,0x38,0xe0,0x00,0xa0,0x20, + 0xe0,0x28,0x50,0xa0,0x50,0x28,0x08,0x08, + 0xf8,0xe0,0x38,0x44,0xaa,0xb2,0xba,0x44, + 0x38,0xe0,0x60,0x90,0x90,0x60,0xf8,0x00, + 0x20,0x20,0xf8,0x20,0x20,0xe0,0x40,0xa0, + 0x60,0xc0,0x20,0x40,0xe0,0x80,0x40,0x80, + 0x80,0xf0,0x90,0x90,0x90,0x90,0x90,0x28, + 0x28,0x28,0x28,0x28,0x68,0xe8,0xe8,0xe8, + 0x7c,0xc0,0xc0,0x40,0x40,0x40,0xc0,0x40, + 0xe0,0x00,0xe0,0xa0,0xe0,0xa0,0x50,0x28, + 0x50,0xa0,0x21,0x00,0x17,0x80,0x13,0x00, + 0x09,0x00,0x48,0x00,0x44,0x00,0xc4,0x00, + 0x42,0x00,0x27,0x12,0x15,0x0b,0x48,0x44, + 0xc4,0x42,0x21,0x00,0x17,0x80,0x13,0x00, + 0x09,0x00,0xc8,0x00,0x24,0x00,0x44,0x00, + 0xe2,0x00,0x60,0x90,0x80,0x40,0x20,0x20, + 0x00,0x20,0x82,0x82,0x7c,0x44,0x28,0x28, + 0x10,0x10,0x00,0x10,0x20,0x82,0x82,0x7c, + 0x44,0x28,0x28,0x10,0x10,0x00,0x10,0x08, + 0x82,0x82,0x7c,0x44,0x28,0x28,0x10,0x10, + 0x00,0x28,0x10,0x82,0x82,0x7c,0x44,0x28, + 0x28,0x10,0x10,0x00,0x28,0x14,0x82,0x82, + 0x7c,0x44,0x28,0x28,0x10,0x10,0x00,0x28, + 0x82,0x82,0x7c,0x44,0x28,0x28,0x10,0x10, + 0x10,0x28,0x10,0x8f,0x80,0x88,0x00,0x78, + 0x00,0x48,0x00,0x2f,0x80,0x28,0x00,0x18, + 0x00,0x1f,0x80,0x30,0x10,0x78,0x84,0x80, + 0x80,0x80,0x80,0x84,0x78,0xf8,0x80,0x80, + 0x80,0xf8,0x80,0x80,0xf8,0x00,0x20,0x40, + 0xf8,0x80,0x80,0x80,0xf8,0x80,0x80,0xf8, + 0x00,0x20,0x10,0xf8,0x80,0x80,0xf8,0x80, + 0x80,0x80,0xf8,0x00,0x50,0x20,0xf8,0x80, + 0x80,0x80,0xf8,0x80,0x80,0xf8,0x00,0x50, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x00,0x40,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x00,0x80,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x00,0xa0, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x00,0xa0,0x78,0x44,0x42,0x42,0xf2, + 0x42,0x44,0x78,0x8c,0x8c,0x94,0x94,0xa4, + 0xa4,0xc4,0xc4,0x00,0x50,0x28,0x78,0x84, + 0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x10, + 0x20,0x78,0x84,0x84,0x84,0x84,0x84,0x84, + 0x78,0x00,0x10,0x08,0x78,0x84,0x84,0x84, + 0x84,0x84,0x84,0x78,0x00,0x28,0x10,0x78, + 0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00, + 0x50,0x28,0x78,0x84,0x84,0x84,0x84,0x84, + 0x84,0x78,0x00,0x48,0x88,0x50,0x20,0x50, + 0x88,0x80,0x78,0xc4,0xa4,0xa4,0x94,0x94, + 0x8c,0x78,0x04,0x78,0x84,0x84,0x84,0x84, + 0x84,0x84,0x84,0x00,0x10,0x20,0x78,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x00,0x20, + 0x10,0x78,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x00,0x28,0x10,0x78,0x84,0x84,0x84, + 0x84,0x84,0x84,0x84,0x00,0x48,0x10,0x10, + 0x10,0x28,0x28,0x44,0x44,0x82,0x00,0x10, + 0x08,0x80,0x80,0xf0,0x88,0x88,0xf0,0x80, + 0x80,0xa0,0x90,0x90,0x90,0xa0,0x90,0x90, + 0x60,0x68,0x90,0x90,0x70,0x10,0xe0,0x00, + 0x20,0x40,0x68,0x90,0x90,0x70,0x10,0xe0, + 0x00,0x20,0x10,0x68,0x90,0x90,0x70,0x10, + 0xe0,0x00,0x50,0x20,0x68,0x90,0x90,0x70, + 0x10,0xe0,0x00,0xa0,0x50,0x68,0x90,0x90, + 0x70,0x10,0xe0,0x00,0x50,0x68,0x90,0x90, + 0x70,0x10,0xe0,0x20,0x50,0x20,0x6c,0x92, + 0x90,0x7e,0x12,0xec,0x60,0x20,0x60,0x90, + 0x80,0x80,0x90,0x60,0x60,0x90,0x80,0xf0, + 0x90,0x60,0x00,0x20,0x40,0x60,0x90,0x80, + 0xf0,0x90,0x60,0x00,0x40,0x20,0x60,0x90, + 0x80,0xf0,0x90,0x60,0x00,0x50,0x20,0x60, + 0x90,0x80,0xf0,0x90,0x60,0x00,0x50,0x40, + 0x40,0x40,0x40,0x40,0x40,0x00,0x40,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x80, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00, + 0xa0,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x00,0xa0,0x70,0x88,0x88,0x88,0x88,0x78, + 0x90,0x60,0x50,0x90,0x90,0x90,0x90,0x90, + 0xe0,0x00,0xa0,0x50,0x70,0x88,0x88,0x88, + 0x88,0x70,0x00,0x20,0x40,0x70,0x88,0x88, + 0x88,0x88,0x70,0x00,0x20,0x10,0x70,0x88, + 0x88,0x88,0x88,0x70,0x00,0x50,0x20,0x70, + 0x88,0x88,0x88,0x88,0x70,0x00,0x50,0x28, + 0x70,0x88,0x88,0x88,0x88,0x70,0x00,0x50, + 0x20,0x00,0xf8,0x00,0x20,0x70,0x88,0xc8, + 0xa8,0x98,0x74,0x70,0x90,0x90,0x90,0x90, + 0x90,0x00,0x20,0x40,0x70,0x90,0x90,0x90, + 0x90,0x90,0x00,0x40,0x20,0x70,0x90,0x90, + 0x90,0x90,0x90,0x00,0x50,0x20,0x70,0x90, + 0x90,0x90,0x90,0x90,0x00,0x50,0x80,0x40, + 0x40,0x60,0xa0,0xa0,0x90,0x90,0x00,0x20, + 0x10,0x80,0x80,0xb0,0xc8,0x88,0x88,0xc8, + 0xb0,0x80,0x80,0x80,0x40,0x40,0x60,0xa0, + 0xa0,0x90,0x90,0x00,0x50, +}; + +BMF_FontData BMF_font_helv10 = { + -1, -2, + 10, 11, + { + {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, -1}, + {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, 12, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 3, -1}, + {1, 8, -1, 0, 3, 0}, + {3, 2, -1, -6, 4, 8}, + {6, 7, 0, 0, 6, 10}, + {5, 9, 0, 1, 6, 17}, + {8, 8, 0, 0, 9, 26}, + {6, 8, -1, 0, 8, 34}, + {2, 3, -1, -5, 3, 42}, + {3, 10, 0, 2, 4, 45}, + {3, 10, -1, 2, 4, 55}, + {3, 3, 0, -5, 4, 65}, + {5, 5, 0, -1, 6, 68}, + {2, 3, 0, 2, 3, 73}, + {5, 1, -1, -3, 7, 76}, + {1, 1, -1, 0, 3, 77}, + {3, 8, 0, 0, 3, 78}, + {5, 8, 0, 0, 6, 86}, + {2, 8, -1, 0, 6, 94}, + {5, 8, 0, 0, 6, 102}, + {5, 8, 0, 0, 6, 110}, + {5, 8, 0, 0, 6, 118}, + {5, 8, 0, 0, 6, 126}, + {5, 8, 0, 0, 6, 134}, + {5, 8, 0, 0, 6, 142}, + {5, 8, 0, 0, 6, 150}, + {5, 8, 0, 0, 6, 158}, + {1, 6, -1, 0, 3, 166}, + {2, 8, 0, 2, 3, 172}, + {3, 5, -1, -1, 6, 180}, + {4, 3, 0, -2, 5, 185}, + {3, 5, -1, -1, 6, 188}, + {4, 8, -1, 0, 6, 193}, + {10, 10, 0, 2, 11, 201}, + {7, 8, 0, 0, 7, 221}, + {5, 8, -1, 0, 7, 229}, + {6, 8, -1, 0, 8, 237}, + {6, 8, -1, 0, 8, 245}, + {5, 8, -1, 0, 7, 253}, + {5, 8, -1, 0, 6, 261}, + {6, 8, -1, 0, 8, 269}, + {6, 8, -1, 0, 8, 277}, + {1, 8, -1, 0, 3, 285}, + {4, 8, 0, 0, 5, 293}, + {5, 8, -1, 0, 7, 301}, + {4, 8, -1, 0, 6, 309}, + {7, 8, -1, 0, 9, 317}, + {6, 8, -1, 0, 8, 325}, + {6, 8, -1, 0, 8, 333}, + {5, 8, -1, 0, 7, 341}, + {7, 9, -1, 1, 8, 349}, + {5, 8, -1, 0, 7, 358}, + {5, 8, -1, 0, 7, 366}, + {5, 8, 0, 0, 5, 374}, + {6, 8, -1, 0, 8, 382}, + {7, 8, 0, 0, 7, 390}, + {9, 8, 0, 0, 9, 398}, + {5, 8, -1, 0, 7, 414}, + {7, 8, 0, 0, 7, 422}, + {5, 8, -1, 0, 7, 430}, + {2, 10, -1, 2, 3, 438}, + {3, 8, 0, 0, 3, 448}, + {2, 10, 0, 2, 3, 456}, + {5, 5, 0, -3, 6, 466}, + {6, 1, 0, 2, 6, 471}, + {2, 3, 0, -5, 3, 472}, + {5, 6, 0, 0, 5, 475}, + {5, 8, 0, 0, 6, 481}, + {4, 6, 0, 0, 5, 489}, + {5, 8, 0, 0, 6, 495}, + {4, 6, 0, 0, 5, 503}, + {4, 8, 0, 0, 4, 509}, + {5, 8, 0, 2, 6, 517}, + {5, 8, 0, 0, 6, 525}, + {1, 8, 0, 0, 2, 533}, + {1, 9, 0, 1, 2, 541}, + {4, 8, 0, 0, 5, 550}, + {1, 8, 0, 0, 2, 558}, + {7, 6, 0, 0, 8, 566}, + {5, 6, 0, 0, 6, 572}, + {5, 6, 0, 0, 6, 578}, + {5, 8, 0, 2, 6, 584}, + {5, 8, 0, 2, 6, 592}, + {3, 6, 0, 0, 4, 600}, + {4, 6, 0, 0, 5, 606}, + {3, 8, 0, 0, 4, 612}, + {4, 6, 0, 0, 5, 620}, + {5, 6, 0, 0, 6, 626}, + {7, 6, 0, 0, 8, 632}, + {5, 6, 0, 0, 6, 638}, + {4, 8, 0, 2, 5, 644}, + {4, 6, 0, 0, 5, 652}, + {3, 10, 0, 2, 3, 658}, + {1, 10, -1, 2, 3, 668}, + {3, 10, 0, 2, 3, 678}, + {6, 2, 0, -3, 7, 688}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 3, -1}, + {1, 8, -1, 2, 3, 690}, + {5, 8, 0, 1, 6, 698}, + {5, 8, 0, 0, 6, 706}, + {4, 6, 0, -1, 5, 714}, + {5, 8, 0, 0, 6, 720}, + {1, 10, -1, 2, 3, 728}, + {5, 10, 0, 2, 6, 738}, + {3, 1, 0, -7, 3, 748}, + {7, 7, -1, 0, 9, 749}, + {3, 5, 0, -3, 4, 756}, + {5, 5, 0, 0, 6, 761}, + {5, 3, -1, -2, 7, 766}, + {3, 1, 0, -3, 4, 769}, + {7, 7, -1, 0, 9, 770}, + {3, 1, 0, -7, 3, 777}, + {4, 4, 0, -3, 4, 778}, + {5, 7, 0, 0, 6, 782}, + {3, 4, 0, -3, 3, 789}, + {3, 4, 0, -3, 3, 793}, + {2, 2, 0, -6, 3, 797}, + {4, 8, 0, 2, 5, 799}, + {6, 10, 0, 2, 6, 807}, + {2, 1, 0, -3, 3, 817}, + {2, 2, 0, 2, 3, 818}, + {2, 4, 0, -3, 3, 820}, + {3, 5, 0, -3, 4, 824}, + {5, 5, 0, 0, 6, 829}, + {9, 8, 0, 0, 9, 834}, + {8, 8, 0, 0, 9, 850}, + {9, 8, 0, 0, 9, 858}, + {4, 8, -1, 2, 6, 874}, + {7, 11, 0, 0, 7, 882}, + {7, 11, 0, 0, 7, 893}, + {7, 11, 0, 0, 7, 904}, + {7, 11, 0, 0, 7, 915}, + {7, 10, 0, 0, 7, 926}, + {7, 11, 0, 0, 7, 936}, + {9, 8, 0, 0, 10, 947}, + {6, 10, -1, 2, 8, 963}, + {5, 11, -1, 0, 7, 973}, + {5, 11, -1, 0, 7, 984}, + {5, 11, -1, 0, 7, 995}, + {5, 10, -1, 0, 7, 1006}, + {2, 11, 0, 0, 3, 1016}, + {2, 11, -1, 0, 3, 1027}, + {3, 11, 0, 0, 3, 1038}, + {3, 10, 0, 0, 3, 1049}, + {7, 8, 0, 0, 8, 1059}, + {6, 11, -1, 0, 8, 1067}, + {6, 11, -1, 0, 8, 1078}, + {6, 11, -1, 0, 8, 1089}, + {6, 11, -1, 0, 8, 1100}, + {6, 11, -1, 0, 8, 1111}, + {6, 10, -1, 0, 8, 1122}, + {5, 5, 0, -1, 6, 1132}, + {6, 10, -1, 1, 8, 1137}, + {6, 11, -1, 0, 8, 1147}, + {6, 11, -1, 0, 8, 1158}, + {6, 11, -1, 0, 8, 1169}, + {6, 10, -1, 0, 8, 1180}, + {7, 11, 0, 0, 7, 1190}, + {5, 8, -1, 0, 7, 1201}, + {4, 8, 0, 0, 5, 1209}, + {5, 9, 0, 0, 5, 1217}, + {5, 9, 0, 0, 5, 1226}, + {5, 9, 0, 0, 5, 1235}, + {5, 9, 0, 0, 5, 1244}, + {5, 8, 0, 0, 5, 1253}, + {5, 9, 0, 0, 5, 1261}, + {7, 6, 0, 0, 8, 1270}, + {4, 8, 0, 2, 5, 1276}, + {4, 9, 0, 0, 5, 1284}, + {4, 9, 0, 0, 5, 1293}, + {4, 9, 0, 0, 5, 1302}, + {4, 8, 0, 0, 5, 1311}, + {2, 9, 1, 0, 2, 1319}, + {2, 9, 0, 0, 2, 1328}, + {3, 9, 1, 0, 2, 1337}, + {3, 8, 0, 0, 2, 1346}, + {5, 9, 0, 0, 6, 1354}, + {4, 9, 0, 0, 5, 1363}, + {5, 9, 0, 0, 6, 1372}, + {5, 9, 0, 0, 6, 1381}, + {5, 9, 0, 0, 6, 1390}, + {5, 9, 0, 0, 6, 1399}, + {5, 8, 0, 0, 6, 1408}, + {5, 5, 0, -1, 6, 1416}, + {6, 6, 0, 0, 6, 1421}, + {4, 9, 0, 0, 5, 1427}, + {4, 9, 0, 0, 5, 1436}, + {4, 9, 0, 0, 5, 1445}, + {4, 8, 0, 0, 5, 1454}, + {4, 11, 0, 2, 5, 1462}, + {5, 10, 0, 2, 6, 1473}, + {4, 10, 0, 2, 5, 1483}, + }, + bitmap_data +}; + +#endif + diff --git a/intern/bmfont/intern/BMF_font_helv12.cpp b/intern/bmfont/intern/BMF_font_helv12.cpp new file mode 100644 index 00000000000..813d22475eb --- /dev/null +++ b/intern/bmfont/intern/BMF_font_helv12.cpp @@ -0,0 +1,528 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BMF_FontData.h" +#include "BMF_Settings.h" + +#if BMF_INCLUDE_HELV12 + +static unsigned char bitmap_data[]= { + 0x80,0x00,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0xa0,0xa0,0xa0,0x50,0x50,0x50,0xfc, + 0x28,0xfc,0x28,0x28,0x20,0x70,0xa8,0xa8, + 0x28,0x70,0xa0,0xa8,0x70,0x20,0x23,0x00, + 0x14,0x80,0x14,0x80,0x13,0x00,0x08,0x00, + 0x68,0x00,0x94,0x00,0x94,0x00,0x62,0x00, + 0x72,0x8c,0x84,0x8a,0x50,0x30,0x48,0x48, + 0x30,0x80,0x40,0xc0,0x20,0x40,0x40,0x80, + 0x80,0x80,0x80,0x80,0x80,0x40,0x40,0x20, + 0x80,0x40,0x40,0x20,0x20,0x20,0x20,0x20, + 0x20,0x40,0x40,0x80,0xa0,0x40,0xa0,0x20, + 0x20,0xf8,0x20,0x20,0x80,0x40,0x40,0xf8, + 0x80,0x80,0x80,0x40,0x40,0x40,0x20,0x20, + 0x10,0x10,0x70,0x88,0x88,0x88,0x88,0x88, + 0x88,0x88,0x70,0x20,0x20,0x20,0x20,0x20, + 0x20,0x20,0xe0,0x20,0xf8,0x80,0x80,0x40, + 0x20,0x10,0x08,0x88,0x70,0x70,0x88,0x88, + 0x08,0x08,0x30,0x08,0x88,0x70,0x08,0x08, + 0xfc,0x88,0x48,0x28,0x28,0x18,0x08,0x70, + 0x88,0x88,0x08,0x08,0xf0,0x80,0x80,0xf8, + 0x70,0x88,0x88,0x88,0xc8,0xb0,0x80,0x88, + 0x70,0x40,0x40,0x20,0x20,0x20,0x10,0x10, + 0x08,0xf8,0x70,0x88,0x88,0x88,0x88,0x70, + 0x88,0x88,0x70,0x70,0x88,0x08,0x08,0x78, + 0x88,0x88,0x88,0x70,0x80,0x00,0x00,0x00, + 0x00,0x80,0x80,0x40,0x40,0x00,0x00,0x00, + 0x00,0x40,0x0c,0x30,0xc0,0x30,0x0c,0xf8, + 0x00,0xf8,0xc0,0x30,0x0c,0x30,0xc0,0x20, + 0x00,0x20,0x20,0x10,0x10,0x88,0x88,0x70, + 0x3e,0x00,0x40,0x00,0x9b,0x00,0xa6,0x80, + 0xa2,0x40,0xa2,0x40,0x92,0x40,0x4d,0x40, + 0x60,0x80,0x1f,0x00,0x82,0x82,0x82,0x7c, + 0x44,0x44,0x28,0x28,0x10,0xf8,0x84,0x84, + 0x84,0xf8,0x84,0x84,0x84,0xf8,0x3c,0x42, + 0x80,0x80,0x80,0x80,0x80,0x42,0x3c,0xf8, + 0x84,0x82,0x82,0x82,0x82,0x82,0x84,0xf8, + 0xfc,0x80,0x80,0x80,0xfc,0x80,0x80,0x80, + 0xfc,0x80,0x80,0x80,0x80,0xf8,0x80,0x80, + 0x80,0xfc,0x3a,0x46,0x82,0x82,0x8e,0x80, + 0x80,0x42,0x3c,0x82,0x82,0x82,0x82,0xfe, + 0x82,0x82,0x82,0x82,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x70,0x88,0x88, + 0x08,0x08,0x08,0x08,0x08,0x08,0x82,0x84, + 0x88,0x90,0xe0,0xa0,0x90,0x88,0x84,0xf8, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x88,0x80,0x88,0x80,0x94,0x80,0x94,0x80, + 0xa2,0x80,0xa2,0x80,0xc1,0x80,0xc1,0x80, + 0x80,0x80,0x82,0x86,0x8a,0x8a,0x92,0xa2, + 0xa2,0xc2,0x82,0x3c,0x42,0x81,0x81,0x81, + 0x81,0x81,0x42,0x3c,0x80,0x80,0x80,0x80, + 0xf8,0x84,0x84,0x84,0xf8,0x3d,0x42,0x85, + 0x89,0x81,0x81,0x81,0x42,0x3c,0x84,0x84, + 0x84,0x88,0xf8,0x84,0x84,0x84,0xf8,0x78, + 0x84,0x84,0x04,0x18,0x60,0x80,0x84,0x78, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0xfe,0x78,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x84,0x10,0x10,0x28,0x28,0x44,0x44, + 0x44,0x82,0x82,0x22,0x00,0x22,0x00,0x22, + 0x00,0x55,0x00,0x55,0x00,0x49,0x00,0x88, + 0x80,0x88,0x80,0x88,0x80,0x82,0x44,0x44, + 0x28,0x10,0x28,0x44,0x44,0x82,0x10,0x10, + 0x10,0x10,0x28,0x44,0x44,0x82,0x82,0xfe, + 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0xfe, + 0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0xc0,0x10,0x10,0x20,0x20, + 0x20,0x40,0x40,0x80,0x80,0xc0,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0xc0,0x88,0x50,0x20,0xfe,0xc0,0x80,0x40, + 0x74,0x88,0x88,0x78,0x08,0x88,0x70,0xb0, + 0xc8,0x88,0x88,0x88,0xc8,0xb0,0x80,0x80, + 0x70,0x88,0x80,0x80,0x80,0x88,0x70,0x68, + 0x98,0x88,0x88,0x88,0x98,0x68,0x08,0x08, + 0x70,0x88,0x80,0xf8,0x88,0x88,0x70,0x40, + 0x40,0x40,0x40,0x40,0x40,0xe0,0x40,0x30, + 0x70,0x88,0x08,0x68,0x98,0x88,0x88,0x88, + 0x98,0x68,0x88,0x88,0x88,0x88,0x88,0xc8, + 0xb0,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x00,0x80,0x80,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x40, + 0x88,0x90,0xa0,0xc0,0xc0,0xa0,0x90,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x92,0x92,0x92,0x92,0x92,0xda, + 0xa4,0x88,0x88,0x88,0x88,0x88,0xc8,0xb0, + 0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x80, + 0x80,0x80,0xb0,0xc8,0x88,0x88,0x88,0xc8, + 0xb0,0x08,0x08,0x08,0x68,0x98,0x88,0x88, + 0x88,0x98,0x68,0x80,0x80,0x80,0x80,0x80, + 0xc0,0xa0,0x60,0x90,0x10,0x60,0x80,0x90, + 0x60,0x60,0x40,0x40,0x40,0x40,0x40,0xe0, + 0x40,0x40,0x68,0x98,0x88,0x88,0x88,0x88, + 0x88,0x20,0x20,0x50,0x50,0x88,0x88,0x88, + 0x22,0x00,0x22,0x00,0x55,0x00,0x49,0x00, + 0x49,0x00,0x88,0x80,0x88,0x80,0x84,0x84, + 0x48,0x30,0x30,0x48,0x84,0x80,0x40,0x20, + 0x20,0x50,0x50,0x90,0x88,0x88,0x88,0xf0, + 0x80,0x40,0x40,0x20,0x10,0xf0,0x30,0x40, + 0x40,0x40,0x40,0x40,0x80,0x40,0x40,0x40, + 0x40,0x30,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0xc0,0x20, + 0x20,0x20,0x20,0x20,0x10,0x20,0x20,0x20, + 0x20,0xc0,0x98,0x64,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x00,0x80,0x40,0x70, + 0xc8,0xa0,0xa0,0xa0,0xa8,0x70,0x10,0xb0, + 0x48,0x20,0x20,0xf0,0x40,0x40,0x48,0x30, + 0x84,0x78,0x48,0x48,0x78,0x84,0x20,0x20, + 0xf8,0x20,0xf8,0x20,0x50,0x88,0x88,0x80, + 0x80,0x80,0x80,0x00,0x00,0x00,0x80,0x80, + 0x80,0x80,0x70,0x88,0x08,0x30,0x48,0x88, + 0x88,0x90,0x60,0x80,0x88,0x70,0xa0,0x3e, + 0x00,0x41,0x00,0x9c,0x80,0xa2,0x80,0xa0, + 0x80,0xa2,0x80,0x9c,0x80,0x41,0x00,0x3e, + 0x00,0xe0,0x00,0xa0,0x20,0xe0,0x28,0x50, + 0xa0,0x50,0x28,0x04,0x04,0x04,0xfc,0xf0, + 0x3e,0x00,0x41,0x00,0x94,0x80,0x94,0x80, + 0x98,0x80,0x94,0x80,0x9c,0x80,0x41,0x00, + 0x3e,0x00,0xf0,0x60,0x90,0x90,0x60,0xf8, + 0x00,0x20,0x20,0xf8,0x20,0x20,0xf0,0x40, + 0x20,0x90,0x60,0xc0,0x20,0x40,0x20,0xe0, + 0x80,0x40,0x80,0x80,0x80,0xe8,0x98,0x88, + 0x88,0x88,0x88,0x88,0x28,0x28,0x28,0x28, + 0x28,0x28,0x68,0xe8,0xe8,0xe8,0x68,0x3c, + 0x80,0xc0,0x20,0x20,0x40,0x40,0x40,0x40, + 0xc0,0x40,0xe0,0x00,0xe0,0xa0,0xe0,0xa0, + 0x50,0x28,0x50,0xa0,0x41,0x00,0x27,0x80, + 0x15,0x00,0x13,0x00,0x49,0x00,0x44,0x00, + 0x44,0x00,0xc2,0x00,0x41,0x00,0x47,0x80, + 0x22,0x00,0x11,0x00,0x14,0x80,0x4b,0x00, + 0x48,0x00,0x44,0x00,0xc2,0x00,0x41,0x00, + 0x21,0x00,0x17,0x80,0x15,0x00,0x0b,0x00, + 0xc9,0x00,0x24,0x00,0x44,0x00,0x22,0x00, + 0xe1,0x00,0x70,0x88,0x88,0x40,0x40,0x20, + 0x20,0x00,0x20,0x82,0x82,0x82,0x7c,0x44, + 0x44,0x28,0x10,0x10,0x00,0x10,0x20,0x82, + 0x82,0x82,0x7c,0x44,0x44,0x28,0x10,0x10, + 0x00,0x10,0x08,0x82,0x82,0x82,0x7c,0x44, + 0x44,0x28,0x10,0x10,0x00,0x28,0x10,0x82, + 0x82,0x82,0x7c,0x44,0x44,0x28,0x10,0x10, + 0x00,0x28,0x14,0x82,0x82,0x82,0x7c,0x44, + 0x44,0x28,0x10,0x10,0x00,0x28,0x82,0x82, + 0x82,0x7c,0x44,0x44,0x28,0x10,0x10,0x10, + 0x28,0x10,0x8f,0x80,0x88,0x00,0x88,0x00, + 0x78,0x00,0x4f,0x80,0x48,0x00,0x28,0x00, + 0x28,0x00,0x1f,0x80,0x30,0x08,0x08,0x3c, + 0x42,0x80,0x80,0x80,0x80,0x80,0x42,0x3c, + 0xfc,0x80,0x80,0x80,0xfc,0x80,0x80,0x80, + 0xfc,0x00,0x10,0x20,0xfc,0x80,0x80,0x80, + 0xfc,0x80,0x80,0x80,0xfc,0x00,0x10,0x08, + 0xfc,0x80,0x80,0x80,0xfc,0x80,0x80,0x80, + 0xfc,0x00,0x28,0x10,0xfc,0x80,0x80,0x80, + 0xfc,0x80,0x80,0x80,0xfc,0x00,0x28,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x00,0x40,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x00,0x80,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x00,0xa0,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x00,0xa0,0x7c,0x42, + 0x41,0x41,0xf1,0x41,0x41,0x42,0x7c,0x82, + 0x86,0x8a,0x8a,0x92,0xa2,0xa2,0xc2,0x82, + 0x00,0x28,0x14,0x3c,0x42,0x81,0x81,0x81, + 0x81,0x81,0x42,0x3c,0x00,0x08,0x10,0x3c, + 0x42,0x81,0x81,0x81,0x81,0x81,0x42,0x3c, + 0x00,0x08,0x04,0x3c,0x42,0x81,0x81,0x81, + 0x81,0x81,0x42,0x3c,0x00,0x14,0x08,0x3c, + 0x42,0x81,0x81,0x81,0x81,0x81,0x42,0x3c, + 0x00,0x28,0x14,0x3c,0x42,0x81,0x81,0x81, + 0x81,0x81,0x42,0x3c,0x00,0x24,0x88,0x50, + 0x20,0x50,0x88,0x80,0x00,0x5e,0x00,0x21, + 0x00,0x50,0x80,0x48,0x80,0x44,0x80,0x44, + 0x80,0x42,0x80,0x21,0x00,0x1e,0x80,0x00, + 0x40,0x78,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x84,0x00,0x10,0x20,0x78,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x00,0x10, + 0x08,0x78,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x84,0x00,0x28,0x10,0x78,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x00,0x48, + 0x10,0x10,0x10,0x10,0x28,0x44,0x44,0x82, + 0x82,0x00,0x10,0x08,0x80,0x80,0xf8,0x84, + 0x84,0x84,0xf8,0x80,0x80,0xb0,0x88,0x88, + 0x88,0xb0,0x88,0x88,0x88,0x70,0x74,0x88, + 0x88,0x78,0x08,0x88,0x70,0x00,0x10,0x20, + 0x74,0x88,0x88,0x78,0x08,0x88,0x70,0x00, + 0x20,0x10,0x74,0x88,0x88,0x78,0x08,0x88, + 0x70,0x00,0x50,0x20,0x74,0x88,0x88,0x78, + 0x08,0x88,0x70,0x00,0x50,0x28,0x74,0x88, + 0x88,0x78,0x08,0x88,0x70,0x00,0x50,0x74, + 0x88,0x88,0x78,0x08,0x88,0x70,0x30,0x48, + 0x30,0x77,0x00,0x88,0x80,0x88,0x00,0x7f, + 0x80,0x08,0x80,0x88,0x80,0x77,0x00,0x60, + 0x10,0x20,0x70,0x88,0x80,0x80,0x80,0x88, + 0x70,0x70,0x88,0x80,0xf8,0x88,0x88,0x70, + 0x00,0x20,0x40,0x70,0x88,0x80,0xf8,0x88, + 0x88,0x70,0x00,0x20,0x10,0x70,0x88,0x80, + 0xf8,0x88,0x88,0x70,0x00,0x50,0x20,0x70, + 0x88,0x80,0xf8,0x88,0x88,0x70,0x00,0x50, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00, + 0x40,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x00,0x80,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x00,0xa0,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x00,0xa0,0x70, + 0x88,0x88,0x88,0x88,0x78,0x08,0x50,0x30, + 0x68,0x88,0x88,0x88,0x88,0x88,0xc8,0xb0, + 0x00,0x50,0x28,0x70,0x88,0x88,0x88,0x88, + 0x88,0x70,0x00,0x20,0x40,0x70,0x88,0x88, + 0x88,0x88,0x88,0x70,0x00,0x20,0x10,0x70, + 0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x50, + 0x20,0x70,0x88,0x88,0x88,0x88,0x88,0x70, + 0x00,0x50,0x28,0x70,0x88,0x88,0x88,0x88, + 0x88,0x70,0x00,0x50,0x20,0x00,0xf8,0x00, + 0x20,0xb8,0x44,0x64,0x54,0x4c,0x44,0x3a, + 0x68,0x98,0x88,0x88,0x88,0x88,0x88,0x00, + 0x20,0x40,0x68,0x98,0x88,0x88,0x88,0x88, + 0x88,0x00,0x20,0x10,0x68,0x98,0x88,0x88, + 0x88,0x88,0x88,0x00,0x50,0x20,0x68,0x98, + 0x88,0x88,0x88,0x88,0x88,0x00,0x50,0x80, + 0x40,0x20,0x20,0x50,0x50,0x90,0x88,0x88, + 0x88,0x00,0x20,0x10,0x80,0x80,0x80,0xb0, + 0xc8,0x88,0x88,0x88,0xc8,0xb0,0x80,0x80, + 0xc0,0x20,0x20,0x20,0x30,0x50,0x50,0x48, + 0x88,0x88,0x00,0x50, +}; + +BMF_FontData BMF_font_helv12 = { + 0, -3, + 11, 12, + { + {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, -1}, + {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, 16, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 4, -1}, + {1, 9, -1, 0, 3, 0}, + {3, 3, -1, -6, 5, 9}, + {6, 8, 0, 0, 7, 12}, + {5, 10, -1, 1, 7, 20}, + {9, 9, -1, 0, 11, 30}, + {7, 9, -1, 0, 9, 48}, + {2, 3, -1, -6, 3, 57}, + {3, 12, -1, 3, 4, 60}, + {3, 12, 0, 3, 4, 72}, + {3, 3, -1, -6, 5, 84}, + {5, 5, -1, -1, 7, 87}, + {2, 3, -1, 2, 4, 92}, + {5, 1, -1, -3, 8, 95}, + {1, 1, -1, 0, 3, 96}, + {4, 9, 0, 0, 4, 97}, + {5, 9, -1, 0, 7, 106}, + {3, 9, -1, 0, 7, 115}, + {5, 9, -1, 0, 7, 124}, + {5, 9, -1, 0, 7, 133}, + {6, 9, 0, 0, 7, 142}, + {5, 9, -1, 0, 7, 151}, + {5, 9, -1, 0, 7, 160}, + {5, 9, -1, 0, 7, 169}, + {5, 9, -1, 0, 7, 178}, + {5, 9, -1, 0, 7, 187}, + {1, 6, -1, 0, 3, 196}, + {2, 8, 0, 2, 3, 202}, + {6, 5, 0, -1, 7, 210}, + {5, 3, -1, -2, 7, 215}, + {6, 5, -1, -1, 7, 218}, + {5, 9, -1, 0, 7, 223}, + {10, 10, -1, 1, 12, 232}, + {7, 9, -1, 0, 9, 252}, + {6, 9, -1, 0, 8, 261}, + {7, 9, -1, 0, 9, 270}, + {7, 9, -1, 0, 9, 279}, + {6, 9, -1, 0, 8, 288}, + {6, 9, -1, 0, 8, 297}, + {7, 9, -1, 0, 9, 306}, + {7, 9, -1, 0, 9, 315}, + {1, 9, -1, 0, 3, 324}, + {5, 9, -1, 0, 7, 333}, + {7, 9, -1, 0, 8, 342}, + {5, 9, -1, 0, 7, 351}, + {9, 9, -1, 0, 11, 360}, + {7, 9, -1, 0, 9, 378}, + {8, 9, -1, 0, 10, 387}, + {6, 9, -1, 0, 8, 396}, + {8, 9, -1, 0, 10, 405}, + {6, 9, -1, 0, 8, 414}, + {6, 9, -1, 0, 8, 423}, + {7, 9, 0, 0, 7, 432}, + {6, 9, -1, 0, 8, 441}, + {7, 9, -1, 0, 9, 450}, + {9, 9, -1, 0, 11, 459}, + {7, 9, -1, 0, 9, 477}, + {7, 9, -1, 0, 9, 486}, + {7, 9, -1, 0, 9, 495}, + {2, 12, -1, 3, 3, 504}, + {4, 9, 0, 0, 4, 516}, + {2, 12, 0, 3, 3, 525}, + {5, 3, 0, -5, 6, 537}, + {7, 1, 0, 2, 7, 540}, + {2, 3, 0, -6, 3, 541}, + {6, 7, -1, 0, 7, 544}, + {5, 9, -1, 0, 7, 551}, + {5, 7, -1, 0, 7, 560}, + {5, 9, -1, 0, 7, 567}, + {5, 7, -1, 0, 7, 576}, + {4, 9, 0, 0, 3, 583}, + {5, 10, -1, 3, 7, 592}, + {5, 9, -1, 0, 7, 602}, + {1, 9, -1, 0, 3, 611}, + {2, 12, 0, 3, 3, 620}, + {5, 9, -1, 0, 6, 632}, + {1, 9, -1, 0, 3, 641}, + {7, 7, -1, 0, 9, 650}, + {5, 7, -1, 0, 7, 657}, + {5, 7, -1, 0, 7, 664}, + {5, 10, -1, 3, 7, 671}, + {5, 10, -1, 3, 7, 681}, + {3, 7, -1, 0, 4, 691}, + {4, 7, -1, 0, 6, 698}, + {3, 9, 0, 0, 3, 705}, + {5, 7, -1, 0, 7, 714}, + {5, 7, -1, 0, 7, 721}, + {9, 7, 0, 0, 9, 728}, + {6, 7, 0, 0, 6, 742}, + {5, 10, -1, 3, 7, 749}, + {4, 7, -1, 0, 6, 759}, + {4, 12, 0, 3, 4, 766}, + {1, 12, -1, 3, 3, 778}, + {4, 12, 0, 3, 4, 790}, + {6, 2, 0, -3, 7, 802}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 4, -1}, + {1, 10, -1, 3, 3, 804}, + {5, 9, -1, 1, 7, 814}, + {5, 9, -1, 0, 7, 823}, + {6, 6, 0, -1, 7, 832}, + {5, 9, -1, 0, 7, 838}, + {1, 11, -1, 2, 3, 847}, + {5, 12, 0, 3, 6, 858}, + {3, 1, 0, -8, 3, 870}, + {9, 9, -1, 0, 11, 871}, + {3, 5, -1, -4, 5, 889}, + {5, 5, -1, -1, 7, 894}, + {6, 4, -1, -2, 8, 899}, + {4, 1, 0, -3, 5, 903}, + {9, 9, -1, 0, 11, 904}, + {4, 1, 0, -8, 4, 922}, + {4, 4, 0, -4, 5, 923}, + {5, 7, -1, 0, 7, 927}, + {4, 5, 0, -3, 4, 934}, + {3, 5, 0, -3, 4, 939}, + {2, 2, 0, -8, 2, 944}, + {5, 10, -1, 3, 7, 946}, + {6, 12, 0, 3, 7, 956}, + {1, 1, -1, -3, 3, 968}, + {3, 4, 0, 3, 3, 969}, + {2, 5, -1, -3, 4, 973}, + {3, 5, -1, -4, 5, 978}, + {5, 5, -1, -1, 7, 983}, + {9, 9, 0, 0, 10, 988}, + {9, 9, 0, 0, 10, 1006}, + {9, 9, 0, 0, 10, 1024}, + {5, 9, -1, 3, 7, 1042}, + {7, 12, -1, 0, 9, 1051}, + {7, 12, -1, 0, 9, 1063}, + {7, 12, -1, 0, 9, 1075}, + {7, 12, -1, 0, 9, 1087}, + {7, 11, -1, 0, 9, 1099}, + {7, 12, -1, 0, 9, 1110}, + {9, 9, -1, 0, 11, 1122}, + {7, 12, -1, 3, 9, 1140}, + {6, 12, -1, 0, 8, 1152}, + {6, 12, -1, 0, 8, 1164}, + {6, 12, -1, 0, 8, 1176}, + {6, 11, -1, 0, 8, 1188}, + {2, 12, 0, 0, 3, 1199}, + {2, 12, -1, 0, 3, 1211}, + {3, 12, 0, 0, 3, 1223}, + {3, 11, 0, 0, 3, 1235}, + {8, 9, 0, 0, 9, 1246}, + {7, 12, -1, 0, 9, 1255}, + {8, 12, -1, 0, 10, 1267}, + {8, 12, -1, 0, 10, 1279}, + {8, 12, -1, 0, 10, 1291}, + {8, 12, -1, 0, 10, 1303}, + {8, 11, -1, 0, 10, 1315}, + {5, 5, -1, -1, 7, 1326}, + {10, 11, 0, 1, 10, 1331}, + {6, 12, -1, 0, 8, 1353}, + {6, 12, -1, 0, 8, 1365}, + {6, 12, -1, 0, 8, 1377}, + {6, 11, -1, 0, 8, 1389}, + {7, 12, -1, 0, 9, 1400}, + {6, 9, -1, 0, 8, 1412}, + {5, 9, -1, 0, 7, 1421}, + {6, 10, -1, 0, 7, 1430}, + {6, 10, -1, 0, 7, 1440}, + {6, 10, -1, 0, 7, 1450}, + {6, 10, -1, 0, 7, 1460}, + {6, 9, -1, 0, 7, 1470}, + {6, 10, -1, 0, 7, 1479}, + {9, 7, -1, 0, 11, 1489}, + {5, 10, -1, 3, 7, 1503}, + {5, 10, -1, 0, 7, 1513}, + {5, 10, -1, 0, 7, 1523}, + {5, 10, -1, 0, 7, 1533}, + {5, 9, -1, 0, 7, 1543}, + {2, 10, 0, 0, 3, 1552}, + {2, 10, -1, 0, 3, 1562}, + {3, 10, 0, 0, 3, 1572}, + {3, 9, 0, 0, 3, 1582}, + {5, 10, -1, 0, 7, 1591}, + {5, 10, -1, 0, 7, 1601}, + {5, 10, -1, 0, 7, 1611}, + {5, 10, -1, 0, 7, 1621}, + {5, 10, -1, 0, 7, 1631}, + {5, 10, -1, 0, 7, 1641}, + {5, 9, -1, 0, 7, 1651}, + {5, 5, -1, -1, 7, 1660}, + {7, 7, 0, 0, 7, 1665}, + {5, 10, -1, 0, 7, 1672}, + {5, 10, -1, 0, 7, 1682}, + {5, 10, -1, 0, 7, 1692}, + {5, 9, -1, 0, 7, 1702}, + {5, 13, -1, 3, 7, 1711}, + {5, 12, -1, 3, 7, 1724}, + {5, 12, -1, 3, 7, 1736}, + }, + bitmap_data +}; + +#endif + diff --git a/intern/bmfont/intern/BMF_font_helvb10.cpp b/intern/bmfont/intern/BMF_font_helvb10.cpp new file mode 100644 index 00000000000..66583767ffb --- /dev/null +++ b/intern/bmfont/intern/BMF_font_helvb10.cpp @@ -0,0 +1,495 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BMF_FontData.h" +#include "BMF_Settings.h" + +#if BMF_INCLUDE_HELVB10 + +static unsigned char bitmap_data[]= { + 0x00,0xc0,0x00,0x80,0x80,0xc0,0xc0,0xc0, + 0xc0,0xa0,0xa0,0xa0,0x50,0x50,0xfc,0x28, + 0x7e,0x28,0x28,0x20,0x70,0xa8,0x28,0x38, + 0x70,0xe0,0xa8,0x70,0x20,0x8c,0x56,0x2c, + 0x10,0x10,0x68,0xb4,0x62,0x76,0xdc,0xcc, + 0xde,0x70,0xd8,0xd8,0x70,0x80,0x40,0xc0, + 0xc0,0x20,0x60,0x40,0xc0,0xc0,0xc0,0xc0, + 0x40,0x60,0x20,0x80,0xc0,0x40,0x60,0x60, + 0x60,0x60,0x40,0xc0,0x80,0xa0,0x40,0xa0, + 0x30,0x30,0xfc,0x30,0x30,0x80,0x40,0xc0, + 0xc0,0xf8,0xc0,0xc0,0x80,0x80,0x40,0x40, + 0x20,0x20,0x10,0x10,0x70,0xd8,0xd8,0xd8, + 0xd8,0xd8,0xd8,0x70,0x60,0x60,0x60,0x60, + 0x60,0x60,0xe0,0x60,0xf8,0xc0,0x60,0x30, + 0x18,0x18,0xd8,0x70,0x70,0xd8,0x18,0x18, + 0x30,0x18,0xd8,0x70,0x18,0x18,0xfc,0x98, + 0x58,0x38,0x18,0x08,0x70,0xd8,0x98,0x18, + 0xf0,0xc0,0xc0,0xf8,0x70,0xd8,0xd8,0xd8, + 0xf0,0xc0,0xd8,0x70,0x60,0x60,0x60,0x30, + 0x30,0x18,0x18,0xf8,0x70,0xd8,0xd8,0xd8, + 0x70,0xd8,0xd8,0x70,0x70,0xd8,0x18,0x78, + 0xd8,0xd8,0xd8,0x70,0xc0,0xc0,0x00,0x00, + 0xc0,0xc0,0x80,0x40,0xc0,0xc0,0x00,0x00, + 0xc0,0xc0,0x30,0x60,0xc0,0x60,0x30,0xf8, + 0x00,0xf8,0xc0,0x60,0x30,0x60,0xc0,0x60, + 0x00,0x60,0x60,0x30,0x18,0xd8,0x70,0x3e, + 0x00,0x40,0x00,0x9b,0x00,0xa4,0x80,0xa2, + 0x40,0x92,0x40,0x4d,0x40,0x60,0x80,0x1f, + 0x00,0xc6,0xc6,0xfe,0x6c,0x6c,0x6c,0x38, + 0x38,0xf8,0xcc,0xcc,0xcc,0xf8,0xcc,0xcc, + 0xf8,0x3c,0x66,0xc2,0xc0,0xc0,0xc2,0x66, + 0x3c,0xf0,0xd8,0xcc,0xcc,0xcc,0xcc,0xd8, + 0xf0,0xf8,0xc0,0xc0,0xc0,0xf8,0xc0,0xc0, + 0xf8,0xc0,0xc0,0xc0,0xc0,0xf0,0xc0,0xc0, + 0xf8,0x3a,0x66,0xc6,0xce,0xc0,0xc2,0x66, + 0x3c,0xcc,0xcc,0xcc,0xcc,0xfc,0xcc,0xcc, + 0xcc,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0x70,0xd8,0x18,0x18,0x18,0x18,0x18, + 0x18,0xc6,0xcc,0xd8,0xf0,0xe0,0xf0,0xd8, + 0xcc,0xf8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc9,0x80,0xc9,0x80,0xdd,0x80,0xd5, + 0x80,0xf7,0x80,0xe3,0x80,0xe3,0x80,0xc1, + 0x80,0xc6,0xce,0xce,0xd6,0xd6,0xe6,0xe6, + 0xc6,0x38,0x6c,0xc6,0xc6,0xc6,0xc6,0x6c, + 0x38,0xc0,0xc0,0xc0,0xf8,0xcc,0xcc,0xcc, + 0xf8,0x02,0x3c,0x6c,0xd6,0xc6,0xc6,0xc6, + 0x6c,0x38,0xcc,0xcc,0xcc,0xf8,0xcc,0xcc, + 0xcc,0xf8,0x78,0xcc,0x8c,0x1c,0x78,0xe0, + 0xcc,0x78,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0xfc,0x78,0xcc,0xcc,0xcc,0xcc,0xcc, + 0xcc,0xcc,0x10,0x38,0x38,0x6c,0x6c,0x6c, + 0xc6,0xc6,0x33,0x00,0x33,0x00,0x7f,0x80, + 0x6d,0x80,0x6d,0x80,0xcc,0xc0,0xcc,0xc0, + 0xcc,0xc0,0xc6,0xc6,0x6c,0x38,0x38,0x6c, + 0xc6,0xc6,0x18,0x18,0x18,0x3c,0x66,0x66, + 0xc3,0xc3,0xfc,0xc0,0x60,0x70,0x30,0x18, + 0x0c,0xfc,0xe0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xe0,0x10,0x10,0x20,0x20, + 0x40,0x40,0x80,0x80,0xe0,0x60,0x60,0x60, + 0x60,0x60,0x60,0x60,0x60,0xe0,0x90,0x90, + 0xf0,0x60,0xfc,0xc0,0xc0,0x80,0x40,0x6c, + 0xd8,0xd8,0x78,0x98,0x70,0xf0,0xd8,0xd8, + 0xd8,0xd8,0xf0,0xc0,0xc0,0x70,0xd0,0xc0, + 0xc0,0xd0,0x70,0x78,0xd8,0xd8,0xd8,0xd8, + 0x78,0x18,0x18,0x70,0xd8,0xc0,0xf8,0xd8, + 0x70,0x60,0x60,0x60,0x60,0x60,0xf0,0x60, + 0x38,0x70,0x18,0x78,0xd8,0xd8,0xd8,0xd8, + 0x68,0xd8,0xd8,0xd8,0xd8,0xd8,0xf0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x00, + 0xc0,0xc0,0x60,0x60,0x60,0x60,0x60,0x60, + 0x60,0x00,0x60,0xcc,0xd8,0xf0,0xe0,0xf0, + 0xd8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xdb,0xdb,0xdb,0xdb,0xdb, + 0xb6,0xd8,0xd8,0xd8,0xd8,0xd8,0xb0,0x70, + 0xd8,0xd8,0xd8,0xd8,0x70,0xc0,0xc0,0xf0, + 0xd8,0xd8,0xd8,0xd8,0xb0,0x18,0x18,0x78, + 0xd8,0xd8,0xd8,0xd8,0x68,0xc0,0xc0,0xc0, + 0xc0,0xe0,0xb0,0x70,0xd8,0x18,0x70,0xd8, + 0x70,0x30,0x60,0x60,0x60,0x60,0xf0,0x60, + 0x60,0x68,0xd8,0xd8,0xd8,0xd8,0xd8,0x20, + 0x70,0x50,0xd8,0xd8,0xd8,0x6c,0x6c,0x6c, + 0xd6,0xd6,0xd6,0xcc,0xcc,0x78,0x30,0x78, + 0xcc,0x60,0x30,0x30,0x78,0xd8,0xd8,0xd8, + 0xd8,0xf8,0xc0,0x60,0x30,0x18,0xf8,0x30, + 0x60,0x60,0x60,0x60,0xc0,0x60,0x60,0x60, + 0x30,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0xc0,0x60,0x60,0x60,0x60, + 0x30,0x60,0x60,0x60,0xc0,0xb0,0x68,0x00, + 0xc0,0xc0,0xc0,0xc0,0x40,0x40,0x00,0xc0, + 0x40,0x70,0xd8,0xa0,0xa0,0xd8,0x70,0x10, + 0xd8,0x68,0x60,0x60,0xf0,0x60,0x68,0x38, + 0x84,0x78,0x48,0x48,0x78,0x84,0x30,0xfc, + 0x30,0xfc,0x48,0xcc,0x84,0x84,0x80,0x80, + 0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80, + 0x70,0x98,0x38,0x70,0xc8,0x98,0x70,0xe0, + 0xc8,0x70,0xa0,0x3c,0x42,0x9d,0xa1,0xa5, + 0x99,0x42,0x3c,0xe0,0x00,0xa0,0x20,0xe0, + 0x6c,0xd8,0x6c,0x08,0x08,0xf8,0xf0,0x3c, + 0x42,0xa5,0xb9,0xa5,0xbd,0x42,0x3c,0xe0, + 0xc0,0xa0,0x60,0xfc,0x00,0x30,0x30,0xfc, + 0x30,0x30,0xe0,0x40,0xa0,0x60,0xc0,0x20, + 0x40,0xe0,0x80,0x40,0xc0,0xc0,0xe8,0xd8, + 0xd8,0xd8,0xd8,0xd8,0x28,0x28,0x28,0x28, + 0x28,0x68,0xe8,0xe8,0xe8,0x7c,0xc0,0xc0, + 0x40,0x40,0x40,0xc0,0x40,0xe0,0x00,0xe0, + 0xa0,0xe0,0xd8,0x6c,0xd8,0x42,0x2f,0x26, + 0x12,0x48,0x48,0xc4,0x44,0x4e,0x24,0x2a, + 0x16,0x48,0x48,0xc4,0x44,0x42,0x2f,0x26, + 0x12,0xc8,0x28,0x44,0xe4,0x70,0xd8,0xc0, + 0x60,0x30,0x30,0x00,0x30,0xc6,0xc6,0xfe, + 0x6c,0x6c,0x6c,0x38,0x38,0x00,0x10,0x20, + 0xc6,0xc6,0xfe,0x6c,0x6c,0x6c,0x38,0x38, + 0x00,0x10,0x08,0xc6,0xc6,0xfe,0x6c,0x6c, + 0x6c,0x38,0x38,0x00,0x28,0x10,0xc6,0xc6, + 0xfe,0x6c,0x6c,0x6c,0x38,0x38,0x00,0x28, + 0x14,0xc6,0xc6,0xfe,0x6c,0x6c,0x6c,0x38, + 0x38,0x00,0x28,0xc6,0xc6,0xfe,0x6c,0x6c, + 0x6c,0x38,0x38,0x10,0x28,0x10,0xcf,0x80, + 0xcc,0x00,0xfc,0x00,0x6c,0x00,0x6f,0x80, + 0x6c,0x00,0x3c,0x00,0x3f,0x80,0x30,0x10, + 0x3c,0x66,0xc2,0xc0,0xc0,0xc2,0x66,0x3c, + 0xf8,0xc0,0xc0,0xc0,0xf8,0xc0,0xc0,0xf8, + 0x00,0x20,0x40,0xf8,0xc0,0xc0,0xc0,0xf8, + 0xc0,0xc0,0xf8,0x00,0x20,0x10,0xf8,0xc0, + 0xc0,0xc0,0xf8,0xc0,0xc0,0xf8,0x00,0x50, + 0x20,0xf8,0xc0,0xc0,0xc0,0xf8,0xc0,0xc0, + 0xf8,0x00,0x50,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0x00,0x40,0x80,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x00,0x80, + 0x40,0x60,0x60,0x60,0x60,0x60,0x60,0x60, + 0x60,0x00,0xa0,0x40,0x60,0x60,0x60,0x60, + 0x60,0x60,0x60,0x60,0x00,0x90,0x78,0x6c, + 0x66,0x66,0xf6,0x66,0x6c,0x78,0xc6,0xce, + 0xce,0xd6,0xd6,0xe6,0xe6,0xc6,0x00,0x28, + 0x14,0x38,0x6c,0xc6,0xc6,0xc6,0xc6,0x6c, + 0x38,0x00,0x08,0x10,0x38,0x6c,0xc6,0xc6, + 0xc6,0xc6,0x6c,0x38,0x00,0x10,0x08,0x38, + 0x6c,0xc6,0xc6,0xc6,0xc6,0x6c,0x38,0x00, + 0x28,0x10,0x38,0x6c,0xc6,0xc6,0xc6,0xc6, + 0x6c,0x38,0x00,0x28,0x14,0x38,0x6c,0xc6, + 0xc6,0xc6,0xc6,0x6c,0x38,0x00,0x28,0xcc, + 0x78,0x30,0x78,0xcc,0xb8,0x6c,0xe6,0xd6, + 0xd6,0xce,0x6c,0x3a,0x78,0xcc,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xcc,0x00,0x10,0x20,0x78, + 0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x00, + 0x10,0x08,0x78,0xcc,0xcc,0xcc,0xcc,0xcc, + 0xcc,0xcc,0x00,0x50,0x20,0x78,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xcc,0xcc,0x00,0x48,0x18, + 0x18,0x18,0x3c,0x66,0x66,0xc3,0xc3,0x00, + 0x08,0x04,0xc0,0xc0,0xf8,0xcc,0xcc,0xcc, + 0xf8,0xc0,0xd0,0xc8,0xc8,0xc8,0xd0,0xc8, + 0xc8,0x70,0x6c,0xd8,0xd8,0x78,0x98,0x70, + 0x00,0x10,0x20,0x6c,0xd8,0xd8,0x78,0x98, + 0x70,0x00,0x20,0x10,0x6c,0xd8,0xd8,0x78, + 0x98,0x70,0x00,0x50,0x20,0x6c,0xd8,0xd8, + 0x78,0x98,0x70,0x00,0x50,0x28,0x6c,0xd8, + 0xd8,0x78,0x98,0x70,0x00,0x50,0x6c,0xd8, + 0xd8,0x78,0x98,0x70,0x20,0x50,0x20,0x6e, + 0xdb,0xd8,0x7f,0x9b,0x7e,0x60,0x20,0x70, + 0xd0,0xc0,0xc0,0xd0,0x70,0x70,0xd8,0xc0, + 0xf8,0xd8,0x70,0x00,0x20,0x40,0x70,0xd8, + 0xc0,0xf8,0xd8,0x70,0x00,0x20,0x10,0x70, + 0xd8,0xc0,0xf8,0xd8,0x70,0x00,0x50,0x20, + 0x70,0xd8,0xc0,0xf8,0xd8,0x70,0x00,0x50, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x00,0x40, + 0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x00, + 0x80,0x40,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0x00,0xa0,0x40,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0x00,0xa0,0x70,0xd8,0xd8,0xd8,0xd8, + 0x70,0xa0,0x60,0x50,0xd8,0xd8,0xd8,0xd8, + 0xd8,0xb0,0x00,0xa0,0x50,0x70,0xd8,0xd8, + 0xd8,0xd8,0x70,0x00,0x20,0x40,0x70,0xd8, + 0xd8,0xd8,0xd8,0x70,0x00,0x20,0x10,0x70, + 0xd8,0xd8,0xd8,0xd8,0x70,0x00,0x50,0x20, + 0x70,0xd8,0xd8,0xd8,0xd8,0x70,0x00,0xa0, + 0x50,0x70,0xd8,0xd8,0xd8,0xd8,0x70,0x00, + 0x50,0x30,0x00,0xfc,0x00,0x30,0xb8,0x6c, + 0x6c,0x7c,0x6c,0x3a,0x68,0xd8,0xd8,0xd8, + 0xd8,0xd8,0x00,0x20,0x40,0x68,0xd8,0xd8, + 0xd8,0xd8,0xd8,0x00,0x20,0x10,0x68,0xd8, + 0xd8,0xd8,0xd8,0xd8,0x00,0x50,0x20,0x68, + 0xd8,0xd8,0xd8,0xd8,0xd8,0x00,0x50,0x60, + 0x30,0x30,0x78,0xd8,0xd8,0xd8,0xd8,0x00, + 0x20,0x10,0xc0,0xc0,0xf0,0xd8,0xc8,0xc8, + 0xd8,0xf0,0xc0,0xc0,0x60,0x30,0x30,0x78, + 0xd8,0xd8,0xd8,0xd8,0x00,0x50, +}; + +BMF_FontData BMF_font_helvb10 = { + -1, -2, + 10, 11, + { + {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, -1}, + {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, 12, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {1, 1, 0, 0, 3, 0}, + {2, 8, -1, 0, 4, 1}, + {3, 3, -1, -5, 5, 9}, + {7, 7, 1, 0, 6, 12}, + {5, 10, 0, 1, 6, 19}, + {7, 8, 0, 0, 8, 29}, + {7, 8, 0, 0, 8, 37}, + {2, 4, 0, -4, 3, 45}, + {3, 10, 0, 2, 4, 49}, + {3, 10, 0, 2, 4, 59}, + {3, 3, 0, -5, 4, 69}, + {6, 5, 0, -1, 6, 72}, + {2, 4, 0, 2, 3, 77}, + {5, 1, -1, -3, 7, 81}, + {2, 2, 0, 0, 3, 82}, + {4, 8, 0, 0, 4, 84}, + {5, 8, 0, 0, 6, 92}, + {3, 8, -1, 0, 6, 100}, + {5, 8, 0, 0, 6, 108}, + {5, 8, 0, 0, 6, 116}, + {6, 8, 0, 0, 6, 124}, + {5, 8, 0, 0, 6, 132}, + {5, 8, 0, 0, 6, 140}, + {5, 8, 0, 0, 6, 148}, + {5, 8, 0, 0, 6, 156}, + {5, 8, 0, 0, 6, 164}, + {2, 6, 0, 0, 3, 172}, + {2, 8, 0, 2, 3, 178}, + {4, 5, 0, -1, 5, 186}, + {5, 3, 0, -2, 6, 191}, + {4, 5, 0, -1, 5, 194}, + {5, 8, 0, 0, 6, 199}, + {10, 9, 0, 1, 11, 207}, + {7, 8, 0, 0, 8, 225}, + {6, 8, 0, 0, 7, 233}, + {7, 8, 0, 0, 8, 241}, + {6, 8, 0, 0, 7, 249}, + {5, 8, 0, 0, 6, 257}, + {5, 8, 0, 0, 6, 265}, + {7, 8, 0, 0, 8, 273}, + {6, 8, 0, 0, 7, 281}, + {2, 8, 0, 0, 3, 289}, + {5, 8, 0, 0, 6, 297}, + {7, 8, 0, 0, 7, 305}, + {5, 8, 0, 0, 6, 313}, + {9, 8, 0, 0, 10, 321}, + {7, 8, 0, 0, 8, 337}, + {7, 8, 0, 0, 8, 345}, + {6, 8, 0, 0, 7, 353}, + {7, 9, 0, 1, 8, 361}, + {6, 8, 0, 0, 7, 370}, + {6, 8, 0, 0, 7, 378}, + {6, 8, 0, 0, 7, 386}, + {6, 8, 0, 0, 7, 394}, + {7, 8, 0, 0, 8, 402}, + {10, 8, 0, 0, 11, 410}, + {7, 8, 0, 0, 8, 426}, + {8, 8, 0, 0, 9, 434}, + {6, 8, 0, 0, 7, 442}, + {3, 10, 0, 2, 4, 450}, + {4, 8, 0, 0, 4, 460}, + {3, 10, 0, 2, 4, 468}, + {4, 4, 0, -4, 5, 478}, + {6, 1, 0, 2, 6, 482}, + {2, 4, 0, -4, 3, 483}, + {6, 6, 0, 0, 6, 487}, + {5, 8, 0, 0, 6, 493}, + {4, 6, 0, 0, 5, 501}, + {5, 8, 0, 0, 6, 507}, + {5, 6, 0, 0, 6, 515}, + {5, 8, 1, 0, 4, 521}, + {5, 8, 0, 2, 6, 529}, + {5, 8, 0, 0, 6, 537}, + {2, 8, 0, 0, 3, 545}, + {3, 10, 1, 2, 3, 553}, + {6, 8, 0, 0, 6, 563}, + {2, 8, 0, 0, 3, 571}, + {8, 6, 0, 0, 9, 579}, + {5, 6, 0, 0, 6, 585}, + {5, 6, 0, 0, 6, 591}, + {5, 8, 0, 2, 6, 597}, + {5, 8, 0, 2, 6, 605}, + {4, 6, 0, 0, 4, 613}, + {5, 6, 0, 0, 6, 619}, + {4, 8, 1, 0, 4, 625}, + {5, 6, 0, 0, 6, 633}, + {5, 6, 0, 0, 6, 639}, + {7, 6, 0, 0, 8, 645}, + {6, 6, 0, 0, 7, 651}, + {5, 8, 0, 2, 6, 657}, + {5, 6, 0, 0, 6, 665}, + {4, 10, 0, 2, 5, 671}, + {1, 10, -1, 2, 3, 681}, + {4, 10, 0, 2, 5, 691}, + {5, 2, 0, -3, 6, 701}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {1, 1, 0, 0, 3, 703}, + {2, 8, -1, 2, 4, 704}, + {5, 8, 0, 1, 6, 712}, + {5, 8, 0, 0, 6, 720}, + {6, 6, 0, -1, 6, 728}, + {6, 8, 0, 0, 7, 734}, + {1, 10, -1, 2, 3, 742}, + {5, 10, 0, 2, 6, 752}, + {3, 1, 0, -7, 3, 762}, + {8, 8, -1, 0, 10, 763}, + {3, 5, -1, -3, 5, 771}, + {6, 3, 0, -1, 7, 776}, + {5, 3, -1, -2, 7, 779}, + {4, 1, 0, -3, 5, 782}, + {8, 8, -1, 0, 10, 783}, + {3, 1, 0, -7, 3, 791}, + {3, 3, 0, -5, 4, 792}, + {6, 7, 0, 0, 6, 795}, + {3, 4, 0, -4, 3, 802}, + {3, 4, 0, -4, 3, 806}, + {2, 2, 0, -7, 3, 810}, + {5, 8, 0, 2, 6, 812}, + {6, 10, 0, 2, 6, 820}, + {2, 1, 0, -3, 3, 830}, + {2, 2, 0, 2, 3, 831}, + {2, 4, 0, -4, 3, 833}, + {3, 5, -1, -3, 5, 837}, + {6, 3, 0, -1, 7, 842}, + {8, 8, 0, 0, 9, 845}, + {7, 8, 0, 0, 9, 853}, + {8, 8, 0, 0, 9, 861}, + {5, 8, 0, 2, 6, 869}, + {7, 11, 0, 0, 8, 877}, + {7, 11, 0, 0, 8, 888}, + {7, 11, 0, 0, 8, 899}, + {7, 11, 0, 0, 8, 910}, + {7, 10, 0, 0, 8, 921}, + {7, 11, 0, 0, 8, 931}, + {9, 8, 0, 0, 10, 942}, + {7, 10, 0, 2, 8, 958}, + {5, 11, 0, 0, 6, 968}, + {5, 11, 0, 0, 6, 979}, + {5, 11, 0, 0, 6, 990}, + {5, 10, 0, 0, 6, 1001}, + {2, 11, 0, 0, 3, 1011}, + {2, 11, 0, 0, 3, 1022}, + {3, 11, 1, 0, 3, 1033}, + {4, 10, 1, 0, 3, 1044}, + {7, 8, 1, 0, 7, 1054}, + {7, 11, 0, 0, 8, 1062}, + {7, 11, 0, 0, 8, 1073}, + {7, 11, 0, 0, 8, 1084}, + {7, 11, 0, 0, 8, 1095}, + {7, 11, 0, 0, 8, 1106}, + {7, 10, 0, 0, 8, 1117}, + {6, 5, 0, -1, 6, 1127}, + {7, 8, 0, 0, 8, 1132}, + {6, 11, 0, 0, 7, 1140}, + {6, 11, 0, 0, 7, 1151}, + {6, 11, 0, 0, 7, 1162}, + {6, 10, 0, 0, 7, 1173}, + {8, 11, 0, 0, 9, 1183}, + {6, 8, 0, 0, 7, 1194}, + {5, 8, 0, 0, 6, 1202}, + {6, 9, 0, 0, 6, 1210}, + {6, 9, 0, 0, 6, 1219}, + {6, 9, 0, 0, 6, 1228}, + {6, 9, 0, 0, 6, 1237}, + {6, 8, 0, 0, 6, 1246}, + {6, 9, 0, 0, 6, 1254}, + {8, 6, 0, 0, 9, 1263}, + {4, 8, 0, 2, 5, 1269}, + {5, 9, 0, 0, 6, 1277}, + {5, 9, 0, 0, 6, 1286}, + {5, 9, 0, 0, 6, 1295}, + {5, 8, 0, 0, 6, 1304}, + {2, 9, 0, 0, 3, 1312}, + {2, 9, 0, 0, 3, 1321}, + {3, 9, 0, 0, 3, 1330}, + {3, 8, 0, 0, 3, 1339}, + {5, 9, 0, 0, 6, 1347}, + {5, 9, 0, 0, 6, 1356}, + {5, 9, 0, 0, 6, 1365}, + {5, 9, 0, 0, 6, 1374}, + {5, 9, 0, 0, 6, 1383}, + {5, 9, 0, 0, 6, 1392}, + {5, 8, 0, 0, 6, 1401}, + {6, 5, 0, -1, 6, 1409}, + {7, 6, 1, 0, 6, 1414}, + {5, 9, 0, 0, 6, 1420}, + {5, 9, 0, 0, 6, 1429}, + {5, 9, 0, 0, 6, 1438}, + {5, 8, 0, 0, 6, 1447}, + {5, 11, 0, 2, 6, 1455}, + {5, 10, 0, 2, 6, 1466}, + {5, 10, 0, 2, 6, 1476}, + }, + bitmap_data +}; + +#endif + diff --git a/intern/bmfont/intern/BMF_font_helvb12.cpp b/intern/bmfont/intern/BMF_font_helvb12.cpp new file mode 100644 index 00000000000..69230d48ae8 --- /dev/null +++ b/intern/bmfont/intern/BMF_font_helvb12.cpp @@ -0,0 +1,568 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BMF_FontData.h" +#include "BMF_Settings.h" + +#if BMF_INCLUDE_HELVB12 + +static unsigned char bitmap_data[]= { + 0x00,0xc0,0xc0,0x00,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xa0,0xa0,0xa0,0x6c, + 0x00,0x6c,0x00,0x6c,0x00,0xff,0x00,0x36, + 0x00,0x36,0x00,0x36,0x00,0x7f,0x80,0x1b, + 0x00,0x1b,0x00,0x1b,0x00,0x30,0x30,0x78, + 0xec,0xac,0x3c,0x38,0x70,0xf0,0xd4,0xdc, + 0x78,0x30,0x63,0x80,0x37,0xc0,0x36,0xc0, + 0x1f,0xc0,0x1b,0x80,0x0c,0x00,0x76,0x00, + 0xfe,0x00,0xdb,0x00,0xfb,0x00,0x71,0x80, + 0x73,0x80,0xff,0x00,0xce,0x00,0xcf,0x00, + 0xdd,0x80,0x79,0x80,0x38,0x00,0x6c,0x00, + 0x6c,0x00,0x7c,0x00,0x38,0x00,0x80,0x40, + 0xc0,0xc0,0x30,0x60,0x60,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0x60,0x60,0x30, + 0xc0,0x60,0x60,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x60,0x60,0xc0,0xd8,0x70, + 0x70,0xf8,0x20,0x30,0x30,0xfc,0xfc,0x30, + 0x30,0x80,0x40,0xc0,0xc0,0xfc,0xfc,0xc0, + 0xc0,0xc0,0xc0,0xc0,0x60,0x60,0x60,0x20, + 0x30,0x30,0x30,0x18,0x18,0x18,0x78,0xfc, + 0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xfc, + 0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0xf0,0xf0,0x30,0xfc,0xfc,0xc0,0x60, + 0x70,0x38,0x18,0xcc,0xcc,0xfc,0x78,0x78, + 0xfc,0xcc,0xcc,0x0c,0x38,0x38,0x0c,0xcc, + 0xfc,0x78,0x0c,0x0c,0xfe,0xfe,0xcc,0x6c, + 0x6c,0x3c,0x3c,0x1c,0x1c,0x78,0xfc,0xcc, + 0xcc,0x0c,0xfc,0xf8,0xc0,0xc0,0xfc,0xfc, + 0x78,0xfc,0xcc,0xcc,0xcc,0xfc,0xf8,0xc0, + 0xcc,0xfc,0x78,0x60,0x60,0x60,0x30,0x30, + 0x30,0x18,0x18,0x0c,0xfc,0xfc,0x78,0xfc, + 0xcc,0xcc,0xcc,0x78,0x78,0xcc,0xcc,0xfc, + 0x78,0x78,0xfc,0xcc,0x0c,0x7c,0xfc,0xcc, + 0xcc,0xcc,0xfc,0x78,0xc0,0xc0,0x00,0x00, + 0x00,0x00,0xc0,0xc0,0x80,0x40,0xc0,0xc0, + 0x00,0x00,0x00,0x00,0xc0,0xc0,0x0c,0x38, + 0xe0,0xe0,0x38,0x0c,0xfc,0xfc,0x00,0xfc, + 0xfc,0xc0,0x70,0x1c,0x1c,0x70,0xc0,0x30, + 0x30,0x00,0x30,0x30,0x38,0x1c,0xcc,0xcc, + 0xfc,0x78,0x1f,0x00,0x71,0x80,0x40,0x00, + 0xdd,0x80,0xb6,0xc0,0xb2,0x40,0xb3,0x60, + 0xdb,0x20,0x4d,0xa0,0x60,0x40,0x39,0xc0, + 0x0f,0x00,0xc3,0xc3,0xff,0x7e,0x66,0x66, + 0x3c,0x3c,0x3c,0x18,0x18,0xf8,0xfc,0xcc, + 0xcc,0xcc,0xf8,0xf8,0xcc,0xcc,0xfc,0xf8, + 0x78,0xfc,0xcc,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xcc,0xfc,0x78,0xf8,0xfc,0xce,0xc6,0xc6, + 0xc6,0xc6,0xc6,0xce,0xfc,0xf8,0xfc,0xfc, + 0xc0,0xc0,0xc0,0xf8,0xf8,0xc0,0xc0,0xfc, + 0xfc,0xc0,0xc0,0xc0,0xc0,0xc0,0xf8,0xf8, + 0xc0,0xc0,0xfc,0xfc,0x76,0xfe,0xc6,0xc6, + 0xde,0xde,0xc0,0xc0,0xc6,0xfe,0x7c,0xc6, + 0xc6,0xc6,0xc6,0xc6,0xfe,0xfe,0xc6,0xc6, + 0xc6,0xc6,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0x70,0xf8,0xd8, + 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + 0xc6,0xce,0xcc,0xd8,0xf8,0xf0,0xf0,0xd8, + 0xcc,0xcc,0xc6,0xfc,0xfc,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc9,0x80, + 0xc9,0x80,0xdd,0x80,0xdd,0x80,0xf7,0x80, + 0xf7,0x80,0xe3,0x80,0xe3,0x80,0xe3,0x80, + 0xc1,0x80,0xc1,0x80,0xc6,0xc6,0xce,0xce, + 0xde,0xd6,0xf6,0xe6,0xe6,0xc6,0xc6,0x7c, + 0xfe,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6, + 0xfe,0x7c,0xc0,0xc0,0xc0,0xc0,0xfc,0xfe, + 0xc6,0xc6,0xc6,0xfe,0xfc,0x06,0x7e,0xfc, + 0xce,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xfe, + 0x7c,0xc6,0xc6,0xc6,0xce,0xfc,0xfc,0xc6, + 0xc6,0xc6,0xfe,0xfc,0x78,0xfc,0xcc,0x0c, + 0x1c,0x78,0xe0,0xc0,0xcc,0xfc,0x78,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0xfc,0xfc,0x7c,0xfe,0xc6,0xc6,0xc6,0xc6, + 0xc6,0xc6,0xc6,0xc6,0xc6,0x18,0x18,0x18, + 0x3c,0x3c,0x3c,0x66,0x66,0x66,0xc3,0xc3, + 0x33,0x00,0x33,0x00,0x33,0x00,0x3b,0x00, + 0x7f,0x80,0x6d,0x80,0x6d,0x80,0x6d,0x80, + 0xcc,0xc0,0xcc,0xc0,0xcc,0xc0,0xc3,0xc3, + 0x66,0x7e,0x3c,0x18,0x3c,0x7e,0x66,0xc3, + 0xc3,0x18,0x18,0x18,0x18,0x18,0x3c,0x3c, + 0x66,0x66,0xc3,0xc3,0xfe,0xfe,0xc0,0x60, + 0x60,0x30,0x18,0x18,0x0c,0xfe,0xfe,0xe0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xe0,0x30,0x30,0x30, + 0x70,0x60,0x60,0x60,0xe0,0xc0,0xc0,0xc0, + 0xe0,0x60,0x60,0x60,0x60,0x60,0x60,0x60, + 0x60,0x60,0x60,0x60,0x60,0xe0,0x88,0xd8, + 0x70,0x70,0x20,0xfe,0xc0,0xc0,0x80,0x40, + 0x76,0xfc,0xcc,0xfc,0x7c,0x8c,0xfc,0x78, + 0xd8,0xfc,0xcc,0xcc,0xcc,0xcc,0xfc,0xd8, + 0xc0,0xc0,0xc0,0x78,0xfc,0xcc,0xc0,0xc0, + 0xcc,0xfc,0x78,0x6c,0xfc,0xcc,0xcc,0xcc, + 0xcc,0xfc,0x6c,0x0c,0x0c,0x0c,0x78,0xfc, + 0xc0,0xfc,0xfc,0xcc,0xfc,0x78,0x60,0x60, + 0x60,0x60,0x60,0x60,0xf0,0xf0,0x60,0x70, + 0x30,0x78,0xfc,0x0c,0x6c,0xfc,0xcc,0xcc, + 0xcc,0xcc,0xfc,0x6c,0xcc,0xcc,0xcc,0xcc, + 0xcc,0xec,0xfc,0xd8,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x00, + 0xc0,0xc0,0xc0,0x60,0x60,0x60,0x60,0x60, + 0x60,0x60,0x60,0x60,0x60,0x00,0x60,0x60, + 0xcc,0xd8,0xd8,0xf0,0xe0,0xf0,0xd8,0xcc, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xcc,0xc0, + 0xcc,0xc0,0xcc,0xc0,0xcc,0xc0,0xcc,0xc0, + 0xee,0xc0,0xff,0xc0,0xbb,0x80,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xec,0xfc,0xd8,0x78,0xfc, + 0xcc,0xcc,0xcc,0xcc,0xfc,0x78,0xc0,0xc0, + 0xc0,0xd8,0xfc,0xcc,0xcc,0xcc,0xcc,0xfc, + 0xd8,0x0c,0x0c,0x0c,0x6c,0xfc,0xcc,0xcc, + 0xcc,0xcc,0xfc,0x6c,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xe0,0xb0,0x78,0xfc,0xcc,0x1c, + 0x78,0xe0,0xfc,0x78,0x30,0x70,0x60,0x60, + 0x60,0x60,0xf0,0xf0,0x60,0x60,0x6c,0xfc, + 0xdc,0xcc,0xcc,0xcc,0xcc,0xcc,0x30,0x30, + 0x78,0x78,0x78,0xcc,0xcc,0xcc,0x24,0x24, + 0x76,0x76,0x7e,0xdb,0xdb,0xdb,0xcc,0xcc, + 0x78,0x38,0x70,0x78,0xcc,0xcc,0xe0,0xf0, + 0x30,0x30,0x38,0x78,0x78,0x48,0xcc,0xcc, + 0xcc,0xfc,0xfc,0x60,0x30,0x30,0x18,0xfc, + 0xfc,0x30,0x60,0x60,0x60,0x60,0x60,0x40, + 0x80,0x40,0x60,0x60,0x60,0x60,0x30,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0xc0,0x60,0x60,0x60, + 0x60,0x60,0x20,0x10,0x20,0x60,0x60,0x60, + 0x60,0xc0,0x98,0xfc,0x64,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0x00,0xc0,0xc0, + 0xc0,0x78,0xfc,0xec,0xe0,0xd0,0xd4,0xfc, + 0x78,0x0c,0xdc,0xfe,0x60,0x30,0x30,0xfc, + 0x30,0x60,0x64,0x7c,0x38,0xcc,0x78,0xcc, + 0xcc,0x78,0xcc,0x18,0x18,0x18,0x7e,0x18, + 0x7e,0x3c,0x66,0x66,0xc3,0xc3,0x80,0x80, + 0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x80, + 0x80,0x80,0x80,0x78,0xfc,0xcc,0x1c,0x38, + 0x6c,0xcc,0xcc,0xd8,0x70,0xe0,0xcc,0xfc, + 0x78,0xd8,0xd8,0x1f,0x00,0x71,0xc0,0x6e, + 0xc0,0xdb,0x60,0xdb,0x60,0xd8,0x60,0xdb, + 0x60,0xdb,0x60,0x6e,0xc0,0x71,0xc0,0x1f, + 0x00,0xf0,0x00,0xd0,0xb0,0x70,0xb0,0x60, + 0x36,0x6c,0xd8,0x6c,0x36,0x0c,0x0c,0xfc, + 0xfc,0xe0,0xe0,0x1f,0x00,0x71,0xc0,0x7b, + 0xc0,0xdb,0x60,0xdf,0x60,0xde,0x60,0xdb, + 0x60,0xdb,0x60,0x7e,0xc0,0x71,0xc0,0x1f, + 0x00,0xf0,0xf0,0x60,0x90,0x90,0x60,0xfc, + 0xfc,0x00,0x30,0x30,0xfc,0xfc,0x30,0x30, + 0xf0,0x40,0x20,0x10,0x90,0x60,0x60,0x90, + 0x10,0x20,0x90,0x60,0xc0,0x70,0x30,0xc0, + 0xc0,0xc0,0xec,0xfc,0xdc,0xcc,0xcc,0xcc, + 0xcc,0xcc,0x36,0x36,0x36,0x36,0x36,0x36, + 0x36,0x36,0x76,0xf6,0xf6,0xf6,0xfe,0x7e, + 0xc0,0xc0,0xc0,0x60,0x40,0x40,0x40,0x40, + 0x40,0xc0,0x40,0xf8,0x00,0x70,0xd8,0xd8, + 0xd8,0x70,0xd8,0x6c,0x36,0x6c,0xd8,0x20, + 0x80,0x27,0xc0,0x12,0x80,0x12,0x80,0x09, + 0x80,0x4c,0x80,0x44,0x00,0x42,0x00,0x42, + 0x00,0xc1,0x00,0x41,0x00,0x23,0xc0,0x21, + 0x00,0x10,0x80,0x10,0x40,0x0a,0x40,0x4d, + 0x80,0x44,0x00,0x42,0x00,0x42,0x00,0xc1, + 0x00,0x41,0x00,0x20,0x80,0x27,0xc0,0x12, + 0x80,0x12,0x80,0x09,0x80,0x6c,0x80,0x94, + 0x00,0x12,0x00,0x22,0x00,0x91,0x00,0x61, + 0x00,0x78,0xfc,0xcc,0xcc,0xe0,0x70,0x30, + 0x30,0x00,0x30,0x30,0xc3,0xc3,0x7e,0x7e, + 0x24,0x3c,0x18,0x18,0x00,0x0c,0x38,0x30, + 0xc3,0xc3,0x7e,0x7e,0x24,0x3c,0x18,0x18, + 0x00,0x30,0x1c,0x0c,0xc3,0xc3,0x7e,0x7e, + 0x24,0x3c,0x18,0x18,0x00,0x66,0x3c,0x18, + 0xc3,0xc3,0x7e,0x7e,0x24,0x3c,0x18,0x18, + 0x00,0x2c,0x3e,0x1a,0xc3,0xc3,0x7e,0x7e, + 0x24,0x3c,0x18,0x18,0x00,0x6c,0x6c,0xc3, + 0xc3,0x7e,0x7e,0x24,0x3c,0x18,0x18,0x00, + 0x18,0x34,0x18,0xc7,0xe0,0xc7,0xe0,0xfe, + 0x00,0x7e,0x00,0x66,0x00,0x67,0xc0,0x37, + 0xc0,0x36,0x00,0x3e,0x00,0x1f,0xe0,0x1f, + 0xe0,0x60,0x30,0x20,0x78,0xfc,0xcc,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xcc,0xfc,0x78,0xfc, + 0xfc,0xc0,0xf8,0xf8,0xc0,0xfc,0xfc,0x00, + 0x18,0x70,0x60,0xfc,0xfc,0xc0,0xf8,0xf8, + 0xc0,0xfc,0xfc,0x00,0x60,0x38,0x18,0xfc, + 0xfc,0xc0,0xf8,0xf8,0xc0,0xfc,0xfc,0x00, + 0xcc,0x78,0x30,0xfc,0xfc,0xc0,0xf8,0xf8, + 0xc0,0xfc,0xfc,0x00,0xd8,0xd8,0x60,0x60, + 0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x30, + 0xe0,0xc0,0x60,0x60,0x60,0x60,0x60,0x60, + 0x60,0x60,0x00,0xc0,0x70,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x00,0xcc, + 0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x00,0xd8,0xd8,0x7c,0x7e,0x67, + 0x63,0x63,0xfb,0xfb,0x63,0x67,0x7e,0x7c, + 0xc6,0xce,0xce,0xde,0xf6,0xe6,0xe6,0xc6, + 0x00,0x58,0x7c,0x34,0x7c,0xfe,0xc6,0xc6, + 0xc6,0xc6,0xfe,0x7c,0x00,0x18,0x70,0x60, + 0x7c,0xfe,0xc6,0xc6,0xc6,0xc6,0xfe,0x7c, + 0x00,0x30,0x1c,0x0c,0x7c,0xfe,0xc6,0xc6, + 0xc6,0xc6,0xfe,0x7c,0x00,0xcc,0x78,0x30, + 0x7c,0xfe,0xc6,0xc6,0xc6,0xc6,0xfe,0x7c, + 0x00,0x58,0x7c,0x34,0x7c,0xfe,0xc6,0xc6, + 0xc6,0xc6,0xfe,0x7c,0x00,0x6c,0x6c,0xcc, + 0x78,0x30,0x30,0x78,0xcc,0xde,0x00,0x7f, + 0x00,0x63,0x00,0x73,0x00,0x7b,0x00,0x6b, + 0x00,0x6f,0x00,0x67,0x00,0x63,0x00,0x7f, + 0x00,0x3d,0x80,0x7c,0xfe,0xc6,0xc6,0xc6, + 0xc6,0xc6,0xc6,0x00,0x18,0x70,0x60,0x7c, + 0xfe,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x00, + 0x30,0x1c,0x0c,0x7c,0xfe,0xc6,0xc6,0xc6, + 0xc6,0xc6,0xc6,0x00,0xcc,0x78,0x30,0x7c, + 0xfe,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x00, + 0x6c,0x6c,0x18,0x18,0x18,0x18,0x3c,0x7e, + 0xe7,0xc3,0x00,0x30,0x1c,0x0c,0xc0,0xc0, + 0xfc,0xfe,0xc6,0xc6,0xc6,0xfe,0xfc,0xc0, + 0xc0,0xd8,0xdc,0xcc,0xcc,0xcc,0xd8,0xd8, + 0xcc,0xcc,0xfc,0x78,0x76,0xfc,0xcc,0xfc, + 0x7c,0x8c,0xfc,0x78,0x00,0x18,0x70,0x60, + 0x76,0xfc,0xcc,0xfc,0x7c,0x8c,0xfc,0x78, + 0x00,0x60,0x38,0x18,0x76,0xfc,0xcc,0xfc, + 0x7c,0x8c,0xfc,0x78,0x00,0xcc,0x78,0x30, + 0x76,0xfc,0xcc,0xfc,0x7c,0x8c,0xfc,0x78, + 0x00,0x58,0x7c,0x34,0x76,0xfc,0xcc,0xfc, + 0x7c,0x8c,0xfc,0x78,0x00,0xd8,0xd8,0x76, + 0xfc,0xcc,0xfc,0x7c,0x8c,0xfc,0x78,0x00, + 0x30,0x68,0x30,0x77,0x80,0xff,0xc0,0xcc, + 0x00,0xff,0xc0,0x7f,0xc0,0x8c,0xc0,0xff, + 0xc0,0x7b,0x80,0x60,0x30,0x20,0x78,0xfc, + 0xcc,0xc0,0xc0,0xcc,0xfc,0x78,0x78,0xfc, + 0xc0,0xfc,0xfc,0xcc,0xfc,0x78,0x00,0x18, + 0x70,0x60,0x78,0xfc,0xc0,0xfc,0xfc,0xcc, + 0xfc,0x78,0x00,0x60,0x38,0x18,0x78,0xfc, + 0xc0,0xfc,0xfc,0xcc,0xfc,0x78,0x00,0xcc, + 0x78,0x30,0x78,0xfc,0xc0,0xfc,0xfc,0xcc, + 0xfc,0x78,0x00,0xd8,0xd8,0x60,0x60,0x60, + 0x60,0x60,0x60,0x60,0x60,0x00,0x30,0xe0, + 0xc0,0x60,0x60,0x60,0x60,0x60,0x60,0x60, + 0x60,0x00,0xc0,0x70,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x00,0xcc,0x78, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x00,0xd8,0xd8,0x78,0xfc,0xcc,0xcc, + 0xcc,0xcc,0xfc,0x78,0xb0,0x60,0xd0,0xcc, + 0xcc,0xcc,0xcc,0xcc,0xec,0xfc,0xd8,0x00, + 0xb0,0xf8,0x68,0x78,0xfc,0xcc,0xcc,0xcc, + 0xcc,0xfc,0x78,0x00,0x18,0x70,0x60,0x78, + 0xfc,0xcc,0xcc,0xcc,0xcc,0xfc,0x78,0x00, + 0x60,0x38,0x18,0x78,0xfc,0xcc,0xcc,0xcc, + 0xcc,0xfc,0x78,0x00,0xcc,0x78,0x30,0x78, + 0xfc,0xcc,0xcc,0xcc,0xcc,0xfc,0x78,0x00, + 0xb0,0xf8,0x68,0x78,0xfc,0xcc,0xcc,0xcc, + 0xcc,0xfc,0x78,0x00,0xd8,0xd8,0x30,0x30, + 0x00,0xfc,0xfc,0x00,0x30,0x30,0xc0,0x78, + 0xfc,0xcc,0xec,0xdc,0xcc,0xfc,0x78,0x0c, + 0x6c,0xfc,0xdc,0xcc,0xcc,0xcc,0xcc,0xcc, + 0x00,0x18,0x70,0x60,0x6c,0xfc,0xdc,0xcc, + 0xcc,0xcc,0xcc,0xcc,0x00,0x60,0x38,0x18, + 0x6c,0xfc,0xdc,0xcc,0xcc,0xcc,0xcc,0xcc, + 0x00,0xcc,0x78,0x30,0x6c,0xfc,0xdc,0xcc, + 0xcc,0xcc,0xcc,0xcc,0x00,0xd8,0xd8,0xe0, + 0xf0,0x30,0x30,0x38,0x78,0x78,0x48,0xcc, + 0xcc,0xcc,0x00,0x60,0x38,0x18,0xc0,0xc0, + 0xc0,0xd8,0xfc,0xcc,0xcc,0xcc,0xcc,0xfc, + 0xd8,0xc0,0xc0,0xc0,0xe0,0xf0,0x30,0x30, + 0x38,0x78,0x78,0x48,0xcc,0xcc,0xcc,0x00, + 0xd8,0xd8, +}; + +BMF_FontData BMF_font_helvb12 = { + -1, -3, + 11, 12, + { + {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, -1}, + {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, 12, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {1, 1, 0, 0, 3, 0}, + {2, 11, -1, 0, 4, 1}, + {3, 3, 0, -8, 4, 12}, + {9, 11, 1, 0, 7, 15}, + {6, 13, 0, 2, 7, 37}, + {10, 11, 0, 0, 11, 50}, + {9, 11, 0, 0, 9, 72}, + {2, 4, 0, -7, 3, 94}, + {4, 14, 0, 3, 4, 98}, + {4, 14, 1, 3, 4, 112}, + {5, 5, 0, -6, 6, 126}, + {6, 6, 0, -1, 7, 131}, + {2, 4, 0, 2, 3, 137}, + {6, 2, -1, -3, 9, 141}, + {2, 2, 0, 0, 3, 143}, + {5, 13, 1, 2, 4, 145}, + {6, 11, 0, 0, 7, 158}, + {4, 11, 0, 0, 6, 169}, + {6, 11, 0, 0, 7, 180}, + {6, 11, 0, 0, 7, 191}, + {7, 11, 0, 0, 7, 202}, + {6, 11, 0, 0, 7, 213}, + {6, 11, 0, 0, 7, 224}, + {6, 11, 0, 0, 7, 235}, + {6, 11, 0, 0, 7, 246}, + {6, 11, 0, 0, 7, 257}, + {2, 8, -1, 0, 4, 268}, + {2, 10, -1, 2, 4, 276}, + {6, 6, 0, -1, 7, 286}, + {6, 5, 0, -2, 7, 292}, + {6, 6, 0, -1, 7, 297}, + {6, 11, 0, 0, 7, 303}, + {11, 12, 0, 1, 12, 314}, + {8, 11, 0, 0, 8, 338}, + {6, 11, -1, 0, 8, 349}, + {6, 11, -1, 0, 8, 360}, + {7, 11, -1, 0, 9, 371}, + {6, 11, -1, 0, 8, 382}, + {6, 11, -1, 0, 7, 393}, + {7, 11, -1, 0, 9, 404}, + {7, 11, -1, 0, 9, 415}, + {2, 11, -2, 0, 6, 426}, + {5, 11, 0, 0, 6, 437}, + {7, 11, -1, 0, 8, 448}, + {6, 11, -1, 0, 7, 459}, + {9, 11, -1, 0, 11, 470}, + {7, 11, -1, 0, 9, 492}, + {7, 11, -1, 0, 9, 503}, + {7, 11, -1, 0, 9, 514}, + {7, 12, -1, 1, 9, 525}, + {7, 11, -1, 0, 9, 537}, + {6, 11, -1, 0, 8, 548}, + {6, 11, 0, 0, 6, 559}, + {7, 11, -1, 0, 9, 570}, + {8, 11, 0, 0, 8, 581}, + {10, 11, 0, 0, 10, 592}, + {8, 11, 0, 0, 8, 614}, + {8, 11, 0, 0, 8, 625}, + {7, 11, 0, 0, 7, 636}, + {3, 14, 0, 3, 4, 647}, + {4, 11, 0, 0, 5, 661}, + {3, 14, 0, 3, 4, 672}, + {5, 5, 0, -6, 7, 686}, + {7, 1, 0, 2, 7, 691}, + {2, 4, 0, -7, 3, 692}, + {7, 8, 0, 0, 7, 696}, + {6, 11, 0, 0, 7, 704}, + {6, 8, 0, 0, 7, 715}, + {6, 11, 0, 0, 7, 723}, + {6, 8, 0, 0, 7, 734}, + {4, 11, 0, 0, 5, 742}, + {6, 11, 0, 3, 7, 753}, + {6, 11, 0, 0, 7, 764}, + {2, 11, -1, 0, 5, 775}, + {3, 14, 0, 3, 5, 786}, + {6, 11, 0, 0, 6, 800}, + {2, 11, -1, 0, 5, 811}, + {10, 8, 0, 0, 11, 822}, + {6, 8, 0, 0, 7, 838}, + {6, 8, 0, 0, 7, 846}, + {6, 11, 0, 3, 7, 854}, + {6, 11, 0, 3, 7, 865}, + {4, 8, 0, 0, 4, 876}, + {6, 8, 0, 0, 7, 884}, + {4, 10, 0, 0, 5, 892}, + {6, 8, 0, 0, 7, 902}, + {6, 8, 0, 0, 7, 910}, + {8, 8, 0, 0, 9, 918}, + {6, 8, 0, 0, 7, 926}, + {6, 11, 0, 3, 7, 934}, + {6, 8, 0, 0, 7, 945}, + {4, 14, 0, 3, 4, 953}, + {1, 13, -1, 2, 3, 967}, + {4, 14, 0, 3, 4, 980}, + {6, 3, 0, -3, 7, 994}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {2, 11, 0, 3, 3, 997}, + {6, 10, 0, 1, 7, 1008}, + {7, 11, 0, 0, 7, 1018}, + {6, 6, 0, -3, 7, 1029}, + {8, 11, 1, 0, 7, 1035}, + {1, 13, -1, 2, 3, 1046}, + {6, 14, 0, 3, 7, 1059}, + {5, 2, 0, -9, 5, 1073}, + {11, 11, 0, 0, 12, 1075}, + {4, 7, 0, -4, 5, 1097}, + {7, 5, 0, -2, 8, 1104}, + {6, 4, -1, -3, 9, 1109}, + {3, 2, 0, -3, 4, 1113}, + {11, 11, 0, 0, 12, 1115}, + {4, 2, 0, -9, 4, 1137}, + {4, 4, -1, -7, 6, 1139}, + {6, 9, 0, -1, 7, 1143}, + {4, 6, 0, -5, 4, 1152}, + {4, 6, 0, -5, 4, 1158}, + {4, 3, -1, -9, 4, 1164}, + {6, 11, 0, 3, 7, 1167}, + {7, 14, -1, 3, 10, 1178}, + {2, 2, 0, -5, 3, 1192}, + {3, 3, -1, 3, 5, 1194}, + {2, 6, 0, -5, 4, 1197}, + {5, 7, 0, -4, 6, 1203}, + {7, 5, 0, -2, 8, 1210}, + {10, 11, 0, 0, 11, 1215}, + {10, 11, 0, 0, 11, 1237}, + {10, 11, 0, 0, 11, 1259}, + {6, 11, 0, 3, 7, 1281}, + {8, 12, 0, 0, 8, 1292}, + {8, 12, 0, 0, 8, 1304}, + {8, 12, 0, 0, 8, 1316}, + {8, 12, 0, 0, 8, 1328}, + {8, 11, 0, 0, 8, 1340}, + {8, 12, 0, 0, 8, 1351}, + {11, 11, 0, 0, 12, 1363}, + {6, 14, -1, 3, 8, 1385}, + {6, 12, -1, 0, 8, 1399}, + {6, 12, -1, 0, 8, 1411}, + {6, 12, -1, 0, 8, 1423}, + {6, 11, -1, 0, 8, 1435}, + {4, 12, -1, 0, 6, 1446}, + {4, 12, -1, 0, 6, 1458}, + {6, 12, 0, 0, 6, 1470}, + {5, 11, 0, 0, 6, 1482}, + {8, 11, 0, 0, 9, 1493}, + {7, 12, -1, 0, 9, 1504}, + {7, 12, -1, 0, 9, 1516}, + {7, 12, -1, 0, 9, 1528}, + {7, 12, -1, 0, 9, 1540}, + {7, 12, -1, 0, 9, 1552}, + {7, 11, -1, 0, 9, 1564}, + {6, 6, 0, -1, 7, 1575}, + {9, 11, 0, 0, 9, 1581}, + {7, 12, -1, 0, 9, 1603}, + {7, 12, -1, 0, 9, 1615}, + {7, 12, -1, 0, 9, 1627}, + {7, 11, -1, 0, 9, 1639}, + {8, 12, 0, 0, 8, 1650}, + {7, 11, -1, 0, 9, 1662}, + {6, 11, 0, 0, 7, 1673}, + {7, 12, 0, 0, 7, 1684}, + {7, 12, 0, 0, 7, 1696}, + {7, 12, 0, 0, 7, 1708}, + {7, 12, 0, 0, 7, 1720}, + {7, 11, 0, 0, 7, 1732}, + {7, 12, 0, 0, 7, 1743}, + {10, 8, 0, 0, 11, 1755}, + {6, 11, 0, 3, 7, 1771}, + {6, 12, 0, 0, 7, 1782}, + {6, 12, 0, 0, 7, 1794}, + {6, 12, 0, 0, 7, 1806}, + {6, 11, 0, 0, 7, 1818}, + {4, 12, 0, 0, 5, 1829}, + {4, 12, 0, 0, 5, 1841}, + {6, 12, 1, 0, 5, 1853}, + {5, 11, 1, 0, 5, 1865}, + {6, 11, 0, 0, 7, 1876}, + {6, 12, 0, 0, 7, 1887}, + {6, 12, 0, 0, 7, 1899}, + {6, 12, 0, 0, 7, 1911}, + {6, 12, 0, 0, 7, 1923}, + {6, 12, 0, 0, 7, 1935}, + {6, 11, 0, 0, 7, 1947}, + {6, 8, 0, 0, 7, 1958}, + {6, 10, 0, 1, 7, 1966}, + {6, 12, 0, 0, 7, 1976}, + {6, 12, 0, 0, 7, 1988}, + {6, 12, 0, 0, 7, 2000}, + {6, 11, 0, 0, 7, 2012}, + {6, 15, 0, 3, 7, 2023}, + {6, 14, 0, 3, 7, 2038}, + {6, 14, 0, 3, 7, 2052}, + }, + bitmap_data +}; + +#endif + diff --git a/intern/bmfont/intern/BMF_font_helvb14.cpp b/intern/bmfont/intern/BMF_font_helvb14.cpp new file mode 100644 index 00000000000..e793295f295 --- /dev/null +++ b/intern/bmfont/intern/BMF_font_helvb14.cpp @@ -0,0 +1,626 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BMF_FontData.h" +#include "BMF_Settings.h" + +#if BMF_INCLUDE_HELVB14 + +static unsigned char bitmap_data[]= { + 0x00,0xc0,0xc0,0x00,0x00,0x80,0x80,0x80, + 0xc0,0xc0,0xc0,0xc0,0xc0,0x90,0xd8,0xd8, + 0xd8,0x48,0x48,0x48,0xfe,0xfe,0x24,0x24, + 0x7f,0x7f,0x12,0x12,0x12,0x10,0x10,0x38, + 0x7c,0xd6,0xd6,0x16,0x3c,0x78,0xd0,0xd6, + 0xd6,0x7c,0x38,0x10,0x30,0xc0,0x11,0xe0, + 0x19,0x20,0x09,0x20,0x0d,0xe0,0x64,0xc0, + 0xf6,0x00,0x92,0x00,0x93,0x00,0xf1,0x00, + 0x61,0x80,0x71,0x80,0xff,0x00,0xce,0x00, + 0xc6,0x00,0xcf,0x00,0x79,0x00,0x30,0x00, + 0x38,0x00,0x6c,0x00,0x6c,0x00,0x7c,0x00, + 0x38,0x00,0x80,0x40,0xc0,0xc0,0x30,0x20, + 0x60,0x40,0x40,0xc0,0xc0,0xc0,0xc0,0xc0, + 0x40,0x40,0x60,0x20,0x30,0xc0,0x40,0x60, + 0x20,0x20,0x30,0x30,0x30,0x30,0x30,0x20, + 0x20,0x60,0x40,0xc0,0xd8,0x50,0x20,0xf8, + 0x20,0x20,0x30,0x30,0x30,0xfc,0xfc,0x30, + 0x30,0x30,0x80,0x40,0x40,0xc0,0xc0,0xfe, + 0xfe,0xc0,0xc0,0x80,0x80,0xc0,0x40,0x40, + 0x60,0x20,0x20,0x30,0x10,0x10,0x30,0x78, + 0x48,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x48, + 0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0xf0,0x30,0x10,0xfc,0xfc, + 0x60,0x60,0x30,0x18,0x18,0x0c,0xcc,0xcc, + 0x78,0x30,0x30,0x78,0xcc,0xcc,0x0c,0x38, + 0x38,0x0c,0xcc,0xcc,0x78,0x30,0x18,0x18, + 0xfc,0xfc,0x98,0x58,0x58,0x38,0x38,0x38, + 0x18,0x18,0x70,0xf8,0xcc,0x0c,0x0c,0xcc, + 0xfc,0xd8,0x60,0x60,0x7c,0x7c,0x30,0x78, + 0xcc,0xcc,0xcc,0xcc,0xfc,0xd8,0xc0,0x4c, + 0x7c,0x38,0x60,0x60,0x60,0x20,0x30,0x30, + 0x10,0x18,0x08,0x0c,0xfc,0xfc,0x70,0xf8, + 0xcc,0xcc,0xcc,0x78,0x30,0x78,0xcc,0xcc, + 0x7c,0x38,0x70,0xf8,0xc8,0x0c,0x6c,0xfc, + 0xcc,0xcc,0xcc,0xcc,0x78,0x30,0xc0,0xc0, + 0x00,0x00,0x00,0x00,0xc0,0xc0,0x80,0x40, + 0x40,0xc0,0xc0,0x00,0x00,0x00,0x00,0xc0, + 0xc0,0x02,0x0e,0x3c,0xf0,0xf0,0x3c,0x0e, + 0x02,0xfc,0xfc,0x00,0x00,0xfc,0xfc,0x80, + 0xe0,0x78,0x1e,0x1e,0x78,0xe0,0x80,0x30, + 0x30,0x00,0x30,0x30,0x18,0x18,0x0c,0xcc, + 0xcc,0x7c,0x38,0x0f,0x80,0x38,0x60,0x60, + 0x00,0x4d,0xc0,0xd3,0x20,0x93,0x30,0x91, + 0x10,0x91,0x90,0xc9,0x90,0x46,0x90,0x60, + 0x30,0x30,0x20,0x1c,0xc0,0x07,0x80,0xe1, + 0xc0,0x61,0x80,0x7f,0x80,0x7f,0x80,0x33, + 0x00,0x33,0x00,0x33,0x00,0x1e,0x00,0x1e, + 0x00,0x1e,0x00,0x0c,0x00,0x0c,0x00,0xfc, + 0xfe,0xc7,0xc3,0xc7,0xfe,0xfc,0xc6,0xc3, + 0xc7,0xfe,0xfc,0x3c,0x7e,0x63,0xc3,0xc0, + 0xc0,0xc0,0xc0,0xc3,0x63,0x7e,0x3c,0xfc, + 0xfe,0xc6,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3, + 0xc6,0xfe,0xfc,0xfe,0xfe,0xc0,0xc0,0xc0, + 0xfe,0xfe,0xc0,0xc0,0xc0,0xfe,0xfe,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xfc,0xfc,0xc0,0xc0, + 0xc0,0xfe,0xfe,0x3e,0x80,0x7f,0x80,0x63, + 0x80,0xc1,0x80,0xc7,0x80,0xc7,0x80,0xc0, + 0x00,0xc0,0x00,0xc1,0x80,0x63,0x80,0x7f, + 0x00,0x3e,0x00,0xc3,0xc3,0xc3,0xc3,0xc3, + 0xff,0xff,0xc3,0xc3,0xc3,0xc3,0xc3,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0x78,0xfc,0xcc,0xcc,0xcc, + 0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0xc3, + 0x80,0xc7,0x00,0xc6,0x00,0xcc,0x00,0xdc, + 0x00,0xf8,0x00,0xf0,0x00,0xd8,0x00,0xcc, + 0x00,0xce,0x00,0xc7,0x00,0xc3,0x00,0xfe, + 0xfe,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xcc,0xc0,0xcc,0xc0,0xcc, + 0xc0,0xde,0xc0,0xde,0xc0,0xd2,0xc0,0xd2, + 0xc0,0xf3,0xc0,0xf3,0xc0,0xe1,0xc0,0xe1, + 0xc0,0xe1,0xc0,0xc3,0xc7,0xc7,0xcf,0xcf, + 0xdb,0xdb,0xf3,0xf3,0xe3,0xe3,0xc3,0x3e, + 0x00,0x7f,0x00,0x63,0x00,0xc1,0x80,0xc1, + 0x80,0xc1,0x80,0xc1,0x80,0xc1,0x80,0xc1, + 0x80,0x63,0x00,0x7f,0x00,0x3e,0x00,0xc0, + 0xc0,0xc0,0xc0,0xf8,0xfc,0xce,0xc6,0xc6, + 0xce,0xfc,0xf8,0x01,0x80,0x3d,0x80,0x7f, + 0x00,0x67,0x00,0xcd,0x80,0xcd,0x80,0xc1, + 0x80,0xc1,0x80,0xc1,0x80,0xc1,0x80,0x63, + 0x00,0x7f,0x00,0x3e,0x00,0xc3,0xc3,0xc3, + 0xc3,0xc7,0xfe,0xfe,0xc7,0xc3,0xc7,0xfe, + 0xfc,0x3c,0x7e,0xe7,0xc3,0x07,0x1e,0x78, + 0xe0,0xc3,0xe7,0x7e,0x3c,0x18,0x18,0x18, + 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xff, + 0xff,0x3c,0x7e,0xe7,0xc3,0xc3,0xc3,0xc3, + 0xc3,0xc3,0xc3,0xc3,0xc3,0x18,0x18,0x18, + 0x3c,0x3c,0x24,0x66,0x66,0x66,0xc3,0xc3, + 0xc3,0x30,0xc0,0x30,0xc0,0x30,0xc0,0x39, + 0xc0,0x79,0xe0,0x69,0x60,0x6f,0x60,0x6f, + 0x60,0xc6,0x30,0xc6,0x30,0xc6,0x30,0xc6, + 0x30,0xe3,0x80,0x63,0x00,0x63,0x00,0x36, + 0x00,0x36,0x00,0x1c,0x00,0x1c,0x00,0x36, + 0x00,0x36,0x00,0x63,0x00,0x63,0x00,0xe3, + 0x80,0x0c,0x00,0x0c,0x00,0x0c,0x00,0x0c, + 0x00,0x0c,0x00,0x1e,0x00,0x1e,0x00,0x33, + 0x00,0x33,0x00,0x61,0x80,0x61,0x80,0xe1, + 0xc0,0xff,0xff,0x60,0x70,0x30,0x18,0x18, + 0x0c,0x0e,0x06,0xff,0xff,0xe0,0xe0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xe0,0xe0,0x10,0x10,0x30,0x20, + 0x20,0x60,0x40,0x40,0xc0,0x80,0x80,0xe0, + 0xe0,0x60,0x60,0x60,0x60,0x60,0x60,0x60, + 0x60,0x60,0x60,0x60,0xe0,0xe0,0xcc,0xcc, + 0x48,0x78,0x78,0x30,0x30,0xfe,0xc0,0xc0, + 0x80,0x40,0x6c,0xfc,0xcc,0xcc,0x7c,0x1c, + 0xcc,0xfc,0x78,0xd8,0xfc,0xee,0xc6,0xc6, + 0xc6,0xee,0xfc,0xd8,0xc0,0xc0,0xc0,0x38, + 0x7c,0xec,0xc0,0xc0,0xc0,0xec,0x7c,0x38, + 0x36,0x7e,0xee,0xc6,0xc6,0xc6,0xee,0x7e, + 0x36,0x06,0x06,0x06,0x38,0x7c,0xcc,0xc0, + 0xfc,0xcc,0xcc,0x78,0x30,0x60,0x60,0x60, + 0x60,0x60,0x60,0x60,0xf0,0xf0,0x60,0x70, + 0x30,0x78,0xfc,0xc6,0x36,0x7e,0xee,0xc6, + 0xc6,0xc6,0xee,0x7e,0x36,0xc6,0xc6,0xc6, + 0xc6,0xc6,0xc6,0xe6,0xfe,0xdc,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0x00,0xc0,0xc0,0xc0,0xe0,0x60, + 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60, + 0x60,0x00,0x60,0x60,0xce,0xcc,0xd8,0xd8, + 0xf0,0xf0,0xd8,0xd8,0xcc,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xcc,0xc0,0xcc,0xc0, + 0xcc,0xc0,0xcc,0xc0,0xcc,0xc0,0xcc,0xc0, + 0xcc,0xc0,0xff,0xc0,0xdb,0x80,0xc6,0xc6, + 0xc6,0xc6,0xc6,0xc6,0xe6,0xfe,0xdc,0x38, + 0x7c,0xee,0xc6,0xc6,0xc6,0xee,0x7c,0x38, + 0xc0,0xc0,0xc0,0xd8,0xfc,0xee,0xc6,0xc6, + 0xc6,0xee,0xfc,0xd8,0x06,0x06,0x06,0x36, + 0x7e,0xee,0xc6,0xc6,0xc6,0xee,0x7e,0x36, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0,0xf8, + 0xd0,0x78,0xfc,0xcc,0x1c,0x78,0xe0,0xcc, + 0xfc,0x78,0x30,0x70,0x60,0x60,0x60,0x60, + 0x60,0xf0,0xf0,0x60,0x60,0x76,0xfe,0xce, + 0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x30,0x30, + 0x30,0x78,0x78,0x48,0xcc,0xcc,0xcc,0x33, + 0x00,0x33,0x00,0x33,0x00,0x73,0x80,0x7f, + 0x80,0x4c,0x80,0x4c,0x80,0xcc,0xc0,0xcc, + 0xc0,0xc6,0xee,0x6c,0x38,0x38,0x38,0x6c, + 0xee,0xc6,0x60,0x70,0x10,0x18,0x38,0x38, + 0x2c,0x6c,0x6c,0xc6,0xc6,0xc6,0xfc,0xfc, + 0x60,0x60,0x30,0x18,0x18,0xfc,0xfc,0x30, + 0x70,0x60,0x60,0x60,0x60,0x60,0xc0,0x60, + 0x60,0x60,0x60,0x60,0x70,0x30,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0xc0,0xe0,0x60, + 0x60,0x60,0x60,0x60,0x30,0x60,0x60,0x60, + 0x60,0x60,0xe0,0xc0,0x98,0xfc,0x64,0xc0, + 0xc0,0xc0,0xc0,0xc0,0x80,0x80,0x80,0x00, + 0x00,0xc0,0xc0,0x20,0x20,0x38,0x7c,0xec, + 0xe0,0xd0,0xd0,0xdc,0x7c,0x38,0x08,0x08, + 0xcc,0xfe,0x70,0x30,0x30,0xf8,0x60,0xc0, + 0xcc,0xcc,0x7c,0x38,0xcc,0x78,0xcc,0xcc, + 0xcc,0xcc,0x78,0xcc,0x18,0x18,0x18,0x7e, + 0x18,0x7e,0x18,0x3c,0x24,0x66,0x42,0xc3, + 0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00, + 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x38, + 0x7c,0x6c,0x0c,0x18,0x7c,0xe6,0xc6,0xce, + 0x7c,0x30,0x60,0x6c,0x7c,0x38,0xd8,0xd8, + 0x1e,0x00,0x33,0x00,0x40,0x80,0xde,0xc0, + 0xb3,0x40,0xa0,0x40,0xa0,0x40,0xb3,0x40, + 0xde,0xc0,0x40,0x80,0x33,0x00,0x1e,0x00, + 0xf0,0x00,0xd0,0xb0,0x70,0xb0,0x60,0x24, + 0x6c,0xd8,0xd8,0x6c,0x24,0x06,0x06,0x06, + 0xfe,0xfe,0xe0,0xe0,0x1e,0x00,0x33,0x00, + 0x40,0x80,0xd2,0xc0,0x96,0x40,0x9c,0x40, + 0x92,0x40,0x92,0x40,0xdc,0xc0,0x40,0x80, + 0x33,0x00,0x1e,0x00,0xf0,0x60,0x90,0x90, + 0x90,0x60,0xfc,0xfc,0x00,0x30,0x30,0x30, + 0xfc,0xfc,0x30,0x30,0x30,0xf0,0x80,0x40, + 0x20,0x90,0xb0,0x60,0x60,0xb0,0x10,0x60, + 0x30,0x90,0x60,0xc0,0x60,0xc0,0xc0,0xc0, + 0xf6,0xfe,0xce,0xc6,0xc6,0xc6,0xc6,0xc6, + 0xc6,0x14,0x14,0x14,0x14,0x14,0x14,0x14, + 0x14,0x74,0xf4,0xf4,0xf4,0xf4,0x74,0x3e, + 0xc0,0xc0,0xc0,0x60,0x40,0x20,0x20,0x20, + 0x20,0x20,0xe0,0x20,0xf0,0x00,0x60,0x90, + 0x90,0x90,0x60,0x90,0xd8,0x6c,0x6c,0xd8, + 0x90,0x20,0x40,0x10,0x40,0x13,0xe0,0x0a, + 0x40,0x09,0x40,0x24,0xc0,0x24,0x40,0x22, + 0x00,0x22,0x00,0x21,0x00,0xe1,0x00,0x20, + 0x80,0x21,0xe0,0x11,0x00,0x10,0x80,0x08, + 0x40,0x09,0x20,0x25,0x60,0x24,0xc0,0x22, + 0x00,0x22,0x00,0x21,0x00,0xe1,0x00,0x20, + 0x80,0x20,0x40,0x10,0x40,0x13,0xe0,0x0a, + 0x40,0x09,0x40,0x64,0xc0,0xb4,0x40,0x12, + 0x00,0x62,0x00,0x31,0x00,0x91,0x00,0x60, + 0x80,0x70,0xf8,0xcc,0xcc,0xc0,0x60,0x60, + 0x30,0x30,0x00,0x30,0x30,0xe1,0xc0,0x61, + 0x80,0x7f,0x80,0x3f,0x00,0x33,0x00,0x33, + 0x00,0x12,0x00,0x1e,0x00,0x1e,0x00,0x0c, + 0x00,0x0c,0x00,0x00,0x00,0x0c,0x00,0x18, + 0x00,0xe1,0xc0,0x61,0x80,0x7f,0x80,0x3f, + 0x00,0x33,0x00,0x33,0x00,0x12,0x00,0x1e, + 0x00,0x1e,0x00,0x0c,0x00,0x0c,0x00,0x00, + 0x00,0x0c,0x00,0x06,0x00,0xe1,0xc0,0x61, + 0x80,0x7f,0x80,0x3f,0x00,0x33,0x00,0x33, + 0x00,0x12,0x00,0x1e,0x00,0x1e,0x00,0x0c, + 0x00,0x0c,0x00,0x00,0x00,0x36,0x00,0x1c, + 0x00,0xe1,0xc0,0x61,0x80,0x7f,0x80,0x3f, + 0x00,0x33,0x00,0x33,0x00,0x12,0x00,0x1e, + 0x00,0x1e,0x00,0x0c,0x00,0x0c,0x00,0x00, + 0x00,0x16,0x00,0x0d,0x00,0xe1,0xc0,0x61, + 0x80,0x7f,0x80,0x3f,0x00,0x33,0x00,0x33, + 0x00,0x12,0x00,0x1e,0x00,0x1e,0x00,0x0c, + 0x00,0x0c,0x00,0x00,0x00,0x36,0x00,0x36, + 0x00,0xe1,0xc0,0x61,0x80,0x7f,0x80,0x3f, + 0x00,0x33,0x00,0x33,0x00,0x12,0x00,0x1e, + 0x00,0x1e,0x00,0x0c,0x00,0x0c,0x00,0x0c, + 0x00,0x0a,0x00,0x06,0x00,0xe3,0xf8,0x63, + 0xf8,0x7f,0x00,0x7f,0x00,0x33,0x00,0x33, + 0xf8,0x3b,0xf8,0x1b,0x00,0x1b,0x00,0x1f, + 0x00,0x0f,0xf8,0x0f,0xf8,0x18,0x0c,0x08, + 0x3c,0x7e,0x63,0xc3,0xc0,0xc0,0xc0,0xc0, + 0xc3,0x63,0x7e,0x3c,0xfe,0xfe,0xc0,0xc0, + 0xc0,0xfe,0xfe,0xc0,0xc0,0xfe,0xfe,0x00, + 0x18,0x30,0xfe,0xfe,0xc0,0xc0,0xc0,0xfe, + 0xfe,0xc0,0xc0,0xfe,0xfe,0x00,0x18,0x0c, + 0xfe,0xfe,0xc0,0xc0,0xc0,0xfe,0xfe,0xc0, + 0xc0,0xfe,0xfe,0x00,0x6c,0x38,0xfe,0xfe, + 0xc0,0xc0,0xc0,0xfe,0xfe,0xc0,0xc0,0xfe, + 0xfe,0x00,0x6c,0x6c,0x60,0x60,0x60,0x60, + 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x00, + 0x60,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0x00,0xc0,0x60, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x00,0xd8,0x70,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x00,0xd8,0xd8,0x7e,0x00,0x7f,0x00, + 0x63,0x00,0x61,0x80,0x61,0x80,0xf9,0x80, + 0xf9,0x80,0x61,0x80,0x61,0x80,0x63,0x00, + 0x7f,0x00,0x7e,0x00,0xc3,0xc7,0xc7,0xcf, + 0xcb,0xdb,0xd3,0xf3,0xe3,0xe3,0xc3,0x00, + 0x2c,0x1a,0x3e,0x00,0x7f,0x00,0x63,0x00, + 0xc1,0x80,0xc1,0x80,0xc1,0x80,0xc1,0x80, + 0xc1,0x80,0x63,0x00,0x7f,0x00,0x3e,0x00, + 0x00,0x00,0x0c,0x00,0x18,0x00,0x3e,0x00, + 0x7f,0x00,0x63,0x00,0xc1,0x80,0xc1,0x80, + 0xc1,0x80,0xc1,0x80,0xc1,0x80,0x63,0x00, + 0x7f,0x00,0x3e,0x00,0x00,0x00,0x18,0x00, + 0x0c,0x00,0x3e,0x00,0x7f,0x00,0x63,0x00, + 0xc1,0x80,0xc1,0x80,0xc1,0x80,0xc1,0x80, + 0xc1,0x80,0x63,0x00,0x7f,0x00,0x3e,0x00, + 0x00,0x00,0x36,0x00,0x1c,0x00,0x3e,0x00, + 0x7f,0x00,0x63,0x00,0xc1,0x80,0xc1,0x80, + 0xc1,0x80,0xc1,0x80,0xc1,0x80,0x63,0x00, + 0x7f,0x00,0x3e,0x00,0x00,0x00,0x2c,0x00, + 0x1a,0x00,0x3e,0x00,0x7f,0x00,0x63,0x00, + 0xc1,0x80,0xc1,0x80,0xc1,0x80,0xc1,0x80, + 0xc1,0x80,0x63,0x00,0x7f,0x00,0x3e,0x00, + 0x00,0x00,0x36,0x00,0x36,0x00,0x84,0xcc, + 0x78,0x30,0x30,0x78,0xcc,0x84,0xbe,0x00, + 0xff,0x00,0x63,0x00,0xf1,0x80,0xd1,0x80, + 0xc9,0x80,0xc9,0x80,0xc5,0x80,0xc7,0x80, + 0x63,0x00,0x7f,0x80,0x3e,0x80,0x3c,0x7e, + 0xe7,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3, + 0xc3,0x00,0x18,0x30,0x3c,0x7e,0xe7,0xc3, + 0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0x00, + 0x18,0x0c,0x3c,0x7e,0xe7,0xc3,0xc3,0xc3, + 0xc3,0xc3,0xc3,0xc3,0xc3,0x00,0x6c,0x38, + 0x3c,0x7e,0xe7,0xc3,0xc3,0xc3,0xc3,0xc3, + 0xc3,0xc3,0xc3,0x00,0x6c,0x6c,0x0c,0x00, + 0x0c,0x00,0x0c,0x00,0x0c,0x00,0x0c,0x00, + 0x1e,0x00,0x1e,0x00,0x33,0x00,0x33,0x00, + 0x61,0x80,0xe1,0xc0,0x00,0x00,0x0c,0x00, + 0x06,0x00,0xc0,0xc0,0xf8,0xfc,0xce,0xc6, + 0xc6,0xce,0xfc,0xf8,0xc0,0xc0,0xd8,0xdc, + 0xc6,0xc6,0xc6,0xdc,0xd8,0xcc,0xcc,0xcc, + 0x7c,0x38,0x6c,0xfc,0xcc,0xcc,0x7c,0x1c, + 0xcc,0xfc,0x78,0x00,0x30,0x60,0x6c,0xfc, + 0xcc,0xcc,0x7c,0x1c,0xcc,0xfc,0x78,0x00, + 0x30,0x18,0x6c,0xfc,0xcc,0xcc,0x7c,0x1c, + 0xcc,0xfc,0x78,0x00,0xd8,0x70,0x6c,0xfc, + 0xcc,0xcc,0x7c,0x1c,0xcc,0xfc,0x78,0x00, + 0x58,0x34,0x6c,0xfc,0xcc,0xcc,0x7c,0x1c, + 0xcc,0xfc,0x78,0x00,0xd8,0xd8,0x6c,0xfc, + 0xcc,0xcc,0x7c,0x1c,0xcc,0xfc,0x78,0x00, + 0x30,0x28,0x18,0x73,0x80,0xff,0xc0,0xcc, + 0xc0,0xcc,0x00,0x7f,0xc0,0x1c,0xc0,0xcc, + 0xc0,0xff,0xc0,0x73,0x80,0x30,0x18,0x10, + 0x38,0x7c,0xec,0xc0,0xc0,0xc0,0xec,0x7c, + 0x38,0x38,0x7c,0xcc,0xc0,0xfc,0xcc,0xcc, + 0x78,0x30,0x00,0x30,0x60,0x38,0x7c,0xcc, + 0xc0,0xfc,0xcc,0xcc,0x78,0x30,0x00,0x30, + 0x18,0x38,0x7c,0xcc,0xc0,0xfc,0xcc,0xcc, + 0x78,0x30,0x00,0x6c,0x38,0x38,0x7c,0xcc, + 0xc0,0xfc,0xcc,0xcc,0x78,0x30,0x00,0xd8, + 0xd8,0x60,0x60,0x60,0x60,0x60,0x60,0x60, + 0x60,0x60,0x00,0x60,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x00,0xc0, + 0x60,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x00,0xd8,0x70,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x00,0xd8, + 0xd8,0x38,0x7c,0xee,0xc6,0xc6,0xc6,0xee, + 0x7c,0x3c,0xf8,0x38,0x6c,0xc6,0xc6,0xc6, + 0xc6,0xc6,0xc6,0xe6,0xfe,0xdc,0x00,0x58, + 0x34,0x38,0x7c,0xee,0xc6,0xc6,0xc6,0xee, + 0x7c,0x38,0x00,0x18,0x30,0x38,0x7c,0xee, + 0xc6,0xc6,0xc6,0xee,0x7c,0x38,0x00,0x30, + 0x18,0x38,0x7c,0xee,0xc6,0xc6,0xc6,0xee, + 0x7c,0x38,0x00,0x6c,0x38,0x38,0x7c,0xee, + 0xc6,0xc6,0xc6,0xee,0x7c,0x38,0x00,0x58, + 0x34,0x38,0x7c,0xee,0xc6,0xc6,0xc6,0xee, + 0x7c,0x38,0x00,0x6c,0x6c,0x30,0x30,0x00, + 0xfc,0xfc,0x00,0x30,0x30,0xb8,0x7c,0xee, + 0xe6,0xd6,0xce,0xee,0x7c,0x3a,0x76,0xfe, + 0xce,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x00, + 0x18,0x30,0x76,0xfe,0xce,0xc6,0xc6,0xc6, + 0xc6,0xc6,0xc6,0x00,0x30,0x18,0x76,0xfe, + 0xce,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x00, + 0x6c,0x38,0x76,0xfe,0xce,0xc6,0xc6,0xc6, + 0xc6,0xc6,0xc6,0x00,0x6c,0x6c,0x60,0x70, + 0x10,0x18,0x38,0x38,0x2c,0x6c,0x6c,0xc6, + 0xc6,0xc6,0x00,0x30,0x18,0xc0,0xc0,0xc0, + 0xd8,0xfc,0xee,0xc6,0xc6,0xc6,0xee,0xfc, + 0xd8,0xc0,0xc0,0xc0,0x60,0x70,0x10,0x18, + 0x38,0x38,0x2c,0x6c,0x6c,0xc6,0xc6,0xc6, + 0x00,0x6c,0x6c, +}; + +BMF_FontData BMF_font_helvb14 = { + -2, -3, + 12, 14, + { + {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, -1}, + {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, 12, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {1, 1, 0, 0, 3, 0}, + {2, 12, -1, 0, 4, 1}, + {5, 4, 0, -8, 6, 13}, + {8, 12, 1, 0, 7, 17}, + {7, 15, 0, 2, 7, 29}, + {11, 11, 0, 0, 12, 44}, + {9, 12, 0, 0, 9, 66}, + {2, 4, -1, -8, 4, 90}, + {4, 15, 0, 3, 4, 94}, + {4, 15, 1, 3, 4, 109}, + {5, 6, 0, -6, 5, 124}, + {6, 8, -1, 0, 8, 130}, + {2, 5, 0, 3, 3, 138}, + {7, 2, 0, -3, 8, 143}, + {2, 2, 0, 0, 3, 145}, + {4, 11, 0, 0, 4, 147}, + {6, 12, 0, 0, 7, 158}, + {4, 12, 0, 0, 7, 170}, + {6, 12, 0, 0, 7, 182}, + {6, 12, 0, 0, 7, 194}, + {6, 12, 0, 0, 7, 206}, + {6, 12, 0, 0, 7, 218}, + {6, 12, 0, 0, 7, 230}, + {6, 12, 0, 0, 7, 242}, + {6, 12, 0, 0, 7, 254}, + {6, 12, 0, 0, 7, 266}, + {2, 8, -1, 0, 4, 278}, + {2, 11, -1, 3, 4, 286}, + {7, 8, 0, 0, 8, 297}, + {6, 6, -1, -1, 8, 305}, + {7, 8, 0, 0, 8, 311}, + {6, 12, -1, 0, 8, 319}, + {12, 14, 0, 2, 13, 331}, + {10, 12, 1, 0, 9, 359}, + {8, 12, 0, 0, 9, 383}, + {8, 12, 0, 0, 9, 395}, + {8, 12, 0, 0, 9, 407}, + {7, 12, 0, 0, 8, 419}, + {7, 12, -1, 0, 8, 431}, + {9, 12, 0, 0, 10, 443}, + {8, 12, 0, 0, 9, 467}, + {2, 12, -1, 0, 5, 479}, + {6, 12, 0, 0, 7, 491}, + {9, 12, -1, 0, 10, 503}, + {7, 12, -1, 0, 8, 527}, + {10, 12, 0, 0, 11, 539}, + {8, 12, 0, 0, 9, 563}, + {9, 12, 0, 0, 10, 575}, + {7, 12, -1, 0, 9, 599}, + {9, 13, 0, 1, 10, 611}, + {8, 12, 0, 0, 9, 637}, + {8, 12, 0, 0, 9, 649}, + {8, 12, 0, 0, 9, 661}, + {8, 12, 0, 0, 9, 673}, + {8, 12, 0, 0, 9, 685}, + {12, 12, 0, 0, 13, 697}, + {9, 12, 0, 0, 10, 721}, + {10, 12, 1, 0, 9, 745}, + {8, 12, 0, 0, 9, 769}, + {3, 15, 0, 3, 4, 781}, + {4, 11, 0, 0, 4, 796}, + {3, 15, 0, 3, 4, 807}, + {6, 7, -1, -4, 8, 822}, + {7, 1, 0, 3, 7, 829}, + {2, 4, -1, -8, 4, 830}, + {6, 9, 0, 0, 7, 834}, + {7, 12, 0, 0, 8, 843}, + {6, 9, 0, 0, 7, 855}, + {7, 12, 0, 0, 8, 864}, + {6, 9, 0, 0, 7, 876}, + {4, 12, 0, 0, 5, 885}, + {7, 12, 0, 3, 8, 897}, + {7, 12, 0, 0, 8, 909}, + {2, 12, 0, 0, 3, 921}, + {3, 15, 1, 3, 3, 933}, + {7, 12, 0, 0, 7, 948}, + {2, 12, 0, 0, 3, 960}, + {10, 9, 0, 0, 11, 972}, + {7, 9, 0, 0, 8, 990}, + {7, 9, 0, 0, 8, 999}, + {7, 12, 0, 3, 8, 1008}, + {7, 12, 0, 3, 8, 1020}, + {5, 9, 0, 0, 5, 1032}, + {6, 9, 0, 0, 7, 1041}, + {4, 11, 0, 0, 5, 1050}, + {7, 9, 0, 0, 8, 1061}, + {6, 9, 0, 0, 7, 1070}, + {10, 9, 0, 0, 11, 1079}, + {7, 9, 0, 0, 8, 1097}, + {7, 12, 0, 3, 8, 1106}, + {6, 9, 0, 0, 7, 1118}, + {4, 15, 0, 3, 5, 1127}, + {1, 15, -1, 3, 4, 1142}, + {4, 15, 0, 3, 5, 1157}, + {6, 3, -1, -3, 8, 1172}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {2, 12, -1, 3, 4, 1175}, + {6, 13, 0, 2, 7, 1187}, + {7, 12, 0, 0, 7, 1200}, + {6, 8, 0, -2, 7, 1212}, + {8, 12, 1, 0, 7, 1220}, + {1, 15, -1, 3, 4, 1232}, + {7, 15, 0, 3, 7, 1247}, + {5, 2, 1, -10, 4, 1262}, + {10, 12, 0, 0, 10, 1264}, + {4, 7, 0, -5, 5, 1288}, + {6, 6, 0, -1, 7, 1295}, + {7, 5, 0, -2, 8, 1301}, + {3, 2, 0, -3, 4, 1306}, + {10, 12, 0, 0, 10, 1308}, + {4, 1, 0, -11, 4, 1332}, + {4, 5, 0, -7, 5, 1333}, + {6, 11, -1, 0, 8, 1338}, + {4, 7, 0, -5, 4, 1349}, + {4, 7, 0, -5, 4, 1356}, + {3, 2, -1, -10, 4, 1363}, + {7, 12, 0, 3, 8, 1365}, + {7, 15, 0, 3, 7, 1377}, + {2, 2, 0, -5, 3, 1392}, + {3, 3, 0, 3, 4, 1394}, + {3, 7, 0, -5, 4, 1397}, + {4, 7, 0, -5, 5, 1404}, + {6, 6, 0, -1, 7, 1411}, + {11, 12, 1, 0, 11, 1417}, + {11, 12, 1, 0, 11, 1441}, + {11, 12, 0, 0, 11, 1465}, + {6, 12, -1, 3, 8, 1489}, + {10, 14, 1, 0, 9, 1501}, + {10, 14, 1, 0, 9, 1529}, + {10, 14, 1, 0, 9, 1557}, + {10, 14, 1, 0, 9, 1585}, + {10, 14, 1, 0, 9, 1613}, + {10, 14, 1, 0, 9, 1641}, + {13, 12, 1, 0, 13, 1669}, + {8, 15, 0, 3, 9, 1693}, + {7, 14, 0, 0, 8, 1708}, + {7, 14, 0, 0, 8, 1722}, + {7, 14, 0, 0, 8, 1736}, + {7, 14, 0, 0, 8, 1750}, + {3, 14, 0, 0, 5, 1764}, + {3, 14, -1, 0, 5, 1778}, + {5, 14, 1, 0, 5, 1792}, + {5, 14, 1, 0, 5, 1806}, + {9, 12, 1, 0, 9, 1820}, + {8, 14, 0, 0, 9, 1844}, + {9, 14, 0, 0, 10, 1858}, + {9, 14, 0, 0, 10, 1886}, + {9, 14, 0, 0, 10, 1914}, + {9, 14, 0, 0, 10, 1942}, + {9, 14, 0, 0, 10, 1970}, + {6, 8, -1, 0, 8, 1998}, + {9, 12, 0, 0, 10, 2006}, + {8, 14, 0, 0, 9, 2030}, + {8, 14, 0, 0, 9, 2044}, + {8, 14, 0, 0, 9, 2058}, + {8, 14, 0, 0, 9, 2072}, + {10, 14, 1, 0, 9, 2086}, + {7, 12, -1, 0, 9, 2114}, + {7, 12, 0, 0, 8, 2126}, + {6, 12, 0, 0, 7, 2138}, + {6, 12, 0, 0, 7, 2150}, + {6, 12, 0, 0, 7, 2162}, + {6, 12, 0, 0, 7, 2174}, + {6, 12, 0, 0, 7, 2186}, + {6, 13, 0, 0, 7, 2198}, + {10, 9, 0, 0, 11, 2211}, + {6, 12, 0, 3, 7, 2229}, + {6, 12, 0, 0, 7, 2241}, + {6, 12, 0, 0, 7, 2253}, + {6, 12, 0, 0, 7, 2265}, + {6, 12, 0, 0, 7, 2277}, + {3, 12, 1, 0, 3, 2289}, + {3, 12, 0, 0, 3, 2301}, + {5, 12, 2, 0, 3, 2313}, + {5, 12, 2, 0, 3, 2325}, + {7, 12, 0, 0, 8, 2337}, + {7, 12, 0, 0, 8, 2349}, + {7, 12, 0, 0, 8, 2361}, + {7, 12, 0, 0, 8, 2373}, + {7, 12, 0, 0, 8, 2385}, + {7, 12, 0, 0, 8, 2397}, + {7, 12, 0, 0, 8, 2409}, + {6, 8, -1, 0, 8, 2421}, + {7, 9, 0, 0, 8, 2429}, + {7, 12, 0, 0, 8, 2438}, + {7, 12, 0, 0, 8, 2450}, + {7, 12, 0, 0, 8, 2462}, + {7, 12, 0, 0, 8, 2474}, + {7, 15, 0, 3, 8, 2486}, + {7, 15, 0, 3, 8, 2501}, + {7, 15, 0, 3, 8, 2516}, + }, + bitmap_data +}; + +#endif + diff --git a/intern/bmfont/intern/BMF_font_helvb8.cpp b/intern/bmfont/intern/BMF_font_helvb8.cpp new file mode 100644 index 00000000000..79651b06519 --- /dev/null +++ b/intern/bmfont/intern/BMF_font_helvb8.cpp @@ -0,0 +1,458 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BMF_FontData.h" +#include "BMF_Settings.h" + +#if BMF_INCLUDE_HELVB8 + +static unsigned char bitmap_data[]= { + 0x00,0x80,0x00,0x80,0x80,0x80,0x80,0xa0, + 0xa0,0xa0,0x50,0xf8,0x50,0xf8,0x50,0x40, + 0xe0,0x10,0x60,0x80,0x70,0x20,0x5c,0x54, + 0x2c,0xd0,0xa8,0xe8,0x58,0xb0,0xa8,0x48, + 0xa0,0x40,0x80,0x80,0x80,0x40,0x80,0x80, + 0x80,0x80,0x80,0x40,0x80,0x40,0x40,0x40, + 0x40,0x40,0x80,0x40,0xe0,0x40,0x20,0x20, + 0xf8,0x20,0x20,0x80,0x40,0x40,0xf0,0x80, + 0x80,0x80,0x80,0x80,0x40,0x40,0x40,0x60, + 0x90,0x90,0x90,0x90,0x60,0x40,0x40,0x40, + 0x40,0xc0,0x40,0xf0,0x40,0x20,0x10,0x90, + 0x60,0xc0,0x20,0x20,0xc0,0x20,0xc0,0x20, + 0x20,0xf0,0x60,0x20,0x20,0xc0,0x20,0x20, + 0xc0,0x80,0xe0,0x60,0x90,0x90,0xe0,0x80, + 0x70,0x40,0x40,0x40,0x20,0x10,0xf0,0x60, + 0x90,0x90,0x60,0x90,0x60,0x60,0x10,0x70, + 0x90,0x90,0x60,0x80,0x00,0x00,0x80,0x80, + 0x40,0x40,0x00,0x00,0x40,0x20,0x40,0x80, + 0x40,0x20,0xe0,0x00,0xe0,0x80,0x40,0x20, + 0x40,0x80,0x40,0x00,0x40,0x20,0xc0,0x78, + 0x80,0x9e,0xa5,0x99,0x41,0x3e,0x88,0x88, + 0x70,0x50,0x20,0x20,0xe0,0x90,0x90,0xe0, + 0x90,0xe0,0x70,0x88,0x80,0x80,0x88,0x70, + 0xf0,0x88,0x88,0x88,0x88,0xf0,0xf0,0x80, + 0x80,0xe0,0x80,0xf0,0x80,0x80,0x80,0xe0, + 0x80,0xf0,0x70,0x88,0x88,0x98,0x80,0x70, + 0x88,0x88,0x88,0xf8,0x88,0x88,0x80,0x80, + 0x80,0x80,0x80,0x80,0x40,0xa0,0x20,0x20, + 0x20,0x20,0x90,0x90,0xe0,0xc0,0xa0,0x90, + 0xe0,0x80,0x80,0x80,0x80,0x80,0xa8,0xa8, + 0xa8,0xa8,0xd8,0x88,0x88,0x98,0xa8,0xa8, + 0xc8,0x88,0x70,0x88,0x88,0x88,0x88,0x70, + 0x80,0x80,0xe0,0x90,0x90,0xe0,0x10,0x20, + 0x70,0x88,0x88,0x88,0x88,0x70,0x90,0x90, + 0xe0,0x90,0x90,0xe0,0xe0,0x10,0x10,0xe0, + 0x80,0x70,0x40,0x40,0x40,0x40,0x40,0xe0, + 0x70,0x88,0x88,0x88,0x88,0x88,0x40,0xa0, + 0x90,0x90,0x90,0x90,0x48,0x48,0x6c,0x92, + 0x92,0x92,0x90,0x90,0x60,0x60,0x90,0x90, + 0x20,0x20,0x30,0x48,0x48,0xc8,0xf0,0x80, + 0x40,0x20,0x10,0xf0,0xc0,0x80,0x80,0x80, + 0x80,0x80,0xc0,0x40,0x40,0x40,0x40,0x80, + 0x80,0x80,0xc0,0x40,0x40,0x40,0x40,0x40, + 0xc0,0x88,0x50,0x20,0xf8,0x80,0x80,0x80, + 0xd0,0xa0,0xe0,0x20,0xc0,0xe0,0x90,0x90, + 0x90,0xe0,0x80,0x80,0x60,0x80,0x80,0x80, + 0x60,0x70,0x90,0x90,0x90,0x70,0x10,0x10, + 0x60,0x80,0xe0,0xa0,0x40,0x40,0x40,0x40, + 0x40,0xe0,0x40,0x20,0x60,0x10,0x70,0x90, + 0x90,0x70,0x90,0x90,0x90,0x90,0xe0,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x80, + 0x80,0x40,0x40,0x40,0x40,0x40,0x40,0x00, + 0x40,0xa0,0xa0,0xc0,0xc0,0xa0,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xa8, + 0xa8,0xa8,0xa8,0xf0,0x90,0x90,0x90,0x90, + 0xe0,0x60,0x90,0x90,0x90,0x60,0x80,0xe0, + 0x90,0x90,0x90,0xe0,0x10,0x70,0x90,0x90, + 0x90,0x70,0x80,0x80,0x80,0xc0,0xa0,0xc0, + 0x20,0x60,0x80,0x60,0x40,0x40,0x40,0x40, + 0xe0,0x40,0x40,0x60,0xa0,0xa0,0xa0,0xa0, + 0x40,0xa0,0x90,0x90,0x90,0x50,0x50,0xa8, + 0xa8,0xa8,0x90,0x90,0x60,0x90,0x90,0x80, + 0x40,0x60,0x90,0x90,0x90,0xe0,0x80,0x40, + 0x20,0xe0,0x20,0x40,0x40,0xc0,0x40,0x40, + 0x20,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x40,0x40,0x60,0x40,0x40,0x80,0xb0, + 0x48,0x00,0x80,0x80,0x80,0x80,0x80,0x00, + 0x80,0x40,0x40,0xa0,0x80,0xa0,0x40,0x40, + 0xf0,0x40,0x40,0xe0,0x40,0x30,0x88,0x70, + 0x50,0x70,0x88,0x20,0x20,0xf8,0x50,0x88, + 0x80,0x80,0x80,0x00,0x80,0x80,0x80,0xe0, + 0x10,0x30,0x60,0x90,0x60,0x80,0x70,0x90, + 0x78,0x84,0xb4,0xa4,0xb4,0x84,0x78,0xe0, + 0x00,0xe0,0x20,0xc0,0x50,0xa0,0x50,0x10, + 0x10,0xf0,0xc0,0x78,0x84,0xac,0xb4,0xb4, + 0x84,0x78,0xe0,0x40,0xa0,0x40,0xf0,0x00, + 0x20,0xf0,0x20,0xc0,0x80,0x40,0x80,0xc0, + 0x20,0x60,0xe0,0x80,0x40,0x80,0x80,0xe0, + 0xa0,0xa0,0xa0,0x50,0x50,0x50,0x50,0xd0, + 0xd0,0xd0,0x78,0x80,0x80,0x80,0x40,0x40, + 0x40,0xc0,0x40,0xe0,0x00,0xe0,0xa0,0xe0, + 0xa0,0x50,0xa0,0x04,0x5e,0x2c,0x54,0x48, + 0xc4,0x40,0x0e,0x44,0x22,0x5c,0x48,0xc4, + 0x40,0x04,0x5e,0x2c,0xd4,0x28,0x64,0xe0, + 0x60,0x90,0x40,0x20,0x00,0x20,0x88,0x88, + 0x70,0x50,0x20,0x20,0x00,0x20,0x40,0x88, + 0x88,0x70,0x50,0x20,0x20,0x00,0x20,0x10, + 0x88,0x88,0x70,0x50,0x20,0x20,0x00,0x50, + 0x20,0x88,0x88,0x70,0x50,0x20,0x20,0x00, + 0x50,0x28,0x88,0x88,0x70,0x50,0x20,0x20, + 0x00,0x50,0x88,0x88,0x70,0x50,0x20,0x20, + 0x20,0x50,0x20,0x9e,0x90,0x7c,0x50,0x30, + 0x3e,0x80,0x40,0x70,0x88,0x80,0x88,0x88, + 0x70,0xf0,0x80,0x80,0xe0,0x80,0xf0,0x00, + 0x20,0x40,0xf0,0x80,0x80,0xe0,0x80,0xf0, + 0x00,0x40,0x20,0xf0,0x80,0x80,0xe0,0x80, + 0xf0,0x00,0xa0,0x40,0xf0,0x80,0x80,0xe0, + 0x80,0xf0,0x00,0xa0,0x40,0x40,0x40,0x40, + 0x40,0x40,0x00,0x40,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x00,0x80,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x00,0xa0,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x00,0xa0,0x70, + 0x48,0x48,0xe8,0x48,0x70,0x88,0x98,0xa8, + 0xa8,0xc8,0x88,0x00,0x50,0x28,0x70,0x88, + 0x88,0x88,0x88,0x70,0x00,0x20,0x40,0x70, + 0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x10, + 0x70,0x88,0x88,0x88,0x88,0x70,0x00,0x50, + 0x20,0x70,0x88,0x88,0x88,0x88,0x70,0x00, + 0x50,0x28,0x70,0x88,0x88,0x88,0x88,0x70, + 0x00,0x50,0x90,0x60,0x60,0x90,0x80,0xf0, + 0xc8,0xa8,0x98,0x88,0x78,0x08,0x70,0x88, + 0x88,0x88,0x88,0x88,0x00,0x20,0x40,0x70, + 0x88,0x88,0x88,0x88,0x88,0x00,0x20,0x10, + 0x70,0x88,0x88,0x88,0x88,0x88,0x00,0x50, + 0x20,0x70,0x88,0x88,0x88,0x88,0x88,0x00, + 0x50,0x20,0x20,0x30,0x48,0x48,0xc8,0x00, + 0x10,0x08,0x80,0xf0,0x88,0x88,0xf0,0x80, + 0x80,0xa0,0x90,0x90,0xa0,0x90,0x60,0xd0, + 0xa0,0xe0,0x20,0xc0,0x00,0x40,0x80,0xd0, + 0xa0,0xe0,0x20,0xc0,0x00,0x40,0x20,0xd0, + 0xa0,0xe0,0x20,0xc0,0x00,0xa0,0x40,0x68, + 0x50,0x70,0x10,0x60,0x00,0xb0,0x68,0xd0, + 0xa0,0xe0,0x20,0xc0,0x00,0xa0,0xd0,0xa0, + 0xe0,0x20,0xc0,0x40,0xa0,0x40,0xd8,0xa0, + 0xf8,0x28,0xd0,0x80,0x40,0x60,0x80,0x80, + 0x80,0x60,0x60,0x80,0xe0,0xa0,0x40,0x00, + 0x20,0x40,0x60,0x80,0xe0,0xa0,0x40,0x00, + 0x40,0x20,0x60,0x80,0xe0,0xa0,0x40,0x00, + 0xa0,0x40,0x60,0x80,0xe0,0xa0,0x40,0x00, + 0xa0,0x40,0x40,0x40,0x40,0x40,0x00,0x40, + 0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x80, + 0x40,0x40,0x40,0x40,0x40,0x40,0x00,0xa0, + 0x40,0x40,0x40,0x40,0x40,0x40,0x00,0xa0, + 0x60,0x90,0x90,0x90,0x70,0xa0,0x60,0x90, + 0x90,0x90,0x90,0x90,0xe0,0x00,0xa0,0x50, + 0x60,0x90,0x90,0x90,0x60,0x00,0x20,0x40, + 0x60,0x90,0x90,0x90,0x60,0x00,0x20,0x10, + 0x60,0x90,0x90,0x90,0x60,0x00,0xa0,0x40, + 0x60,0x90,0x90,0x90,0x60,0x00,0xa0,0x50, + 0x60,0x90,0x90,0x90,0x60,0x00,0x90,0x20, + 0x00,0xf0,0x00,0x20,0x80,0x70,0x68,0x58, + 0x48,0x3c,0x02,0x60,0xa0,0xa0,0xa0,0xa0, + 0x00,0x40,0x80,0x60,0xa0,0xa0,0xa0,0xa0, + 0x00,0x40,0x20,0x60,0xa0,0xa0,0xa0,0xa0, + 0x00,0xa0,0x40,0x60,0xa0,0xa0,0xa0,0xa0, + 0x00,0xa0,0x80,0x40,0x60,0x90,0x90,0x90, + 0x00,0x20,0x10,0x80,0xe0,0x90,0x90,0x90, + 0xe0,0x80,0x80,0x40,0x60,0x90,0x90,0x90, + 0x00,0x50, +}; + +BMF_FontData BMF_font_helvb8 = { + 0, -2, + 9, 9, + { + {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, -1}, + {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, 8, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {1, 1, 0, 0, 2, 0}, + {1, 6, -1, 0, 2, 1}, + {3, 3, -1, -3, 3, 7}, + {5, 5, 0, 0, 5, 10}, + {4, 7, -1, 1, 5, 15}, + {6, 6, -1, 0, 7, 22}, + {5, 6, -1, 0, 6, 28}, + {1, 3, -1, -3, 2, 34}, + {2, 7, -1, 1, 3, 37}, + {2, 7, -1, 1, 3, 44}, + {3, 3, -1, -2, 3, 51}, + {5, 5, -1, 0, 5, 54}, + {2, 3, 0, 2, 2, 59}, + {4, 1, -2, -2, 6, 62}, + {1, 1, -1, 0, 2, 63}, + {2, 7, -1, 1, 2, 64}, + {4, 6, -1, 0, 5, 71}, + {2, 6, -2, 0, 5, 77}, + {4, 6, -1, 0, 5, 83}, + {3, 6, -2, 0, 5, 89}, + {4, 6, -1, 0, 5, 95}, + {3, 6, -2, 0, 5, 101}, + {4, 6, -1, 0, 5, 107}, + {4, 6, -1, 0, 5, 113}, + {4, 6, -1, 0, 5, 119}, + {4, 6, -1, 0, 5, 125}, + {1, 4, -1, 0, 2, 131}, + {2, 6, 0, 2, 2, 135}, + {3, 5, -1, 0, 5, 141}, + {3, 3, -1, -1, 4, 146}, + {3, 5, -2, 0, 5, 149}, + {3, 5, -2, 0, 5, 154}, + {8, 7, -1, 1, 9, 159}, + {5, 6, -1, 0, 6, 166}, + {4, 6, -2, 0, 6, 172}, + {5, 6, -1, 0, 6, 178}, + {5, 6, -1, 0, 6, 184}, + {4, 6, -2, 0, 6, 190}, + {4, 6, -2, 0, 5, 196}, + {5, 6, -1, 0, 6, 202}, + {5, 6, -1, 0, 6, 208}, + {1, 6, -1, 0, 2, 214}, + {3, 6, -1, 0, 4, 220}, + {4, 6, -2, 0, 6, 226}, + {3, 6, -2, 0, 5, 232}, + {5, 6, -2, 0, 7, 238}, + {5, 6, -1, 0, 6, 244}, + {5, 6, -1, 0, 6, 250}, + {4, 6, -2, 0, 6, 256}, + {5, 8, -1, 2, 6, 262}, + {4, 6, -2, 0, 6, 270}, + {4, 6, -2, 0, 6, 276}, + {3, 6, -1, 0, 4, 282}, + {5, 6, -1, 0, 6, 288}, + {4, 6, -2, 0, 6, 294}, + {7, 6, -1, 0, 7, 300}, + {4, 6, -2, 0, 6, 306}, + {5, 6, -1, 0, 6, 312}, + {4, 6, -2, 0, 6, 318}, + {2, 7, -1, 1, 2, 324}, + {2, 7, 0, 1, 2, 331}, + {2, 7, 0, 1, 2, 338}, + {5, 3, 0, -2, 5, 345}, + {5, 1, 0, 1, 5, 348}, + {1, 3, -1, -3, 2, 349}, + {4, 5, -1, 0, 4, 352}, + {4, 7, -1, 0, 5, 357}, + {3, 5, -1, 0, 4, 364}, + {4, 7, -1, 0, 5, 369}, + {3, 5, -1, 0, 4, 376}, + {3, 7, -1, 0, 3, 381}, + {4, 6, -1, 1, 5, 388}, + {4, 7, -1, 0, 5, 394}, + {1, 7, -1, 0, 2, 401}, + {2, 9, 0, 2, 2, 408}, + {3, 7, -1, 0, 4, 417}, + {1, 7, -1, 0, 2, 424}, + {5, 5, -1, 0, 6, 431}, + {4, 5, -1, 0, 5, 436}, + {4, 5, -1, 0, 5, 441}, + {4, 6, -1, 1, 5, 446}, + {4, 6, -1, 1, 5, 452}, + {3, 5, -1, 0, 3, 458}, + {3, 5, -1, 0, 4, 463}, + {3, 7, -1, 0, 3, 468}, + {3, 5, -1, 0, 4, 475}, + {4, 5, -1, 0, 5, 480}, + {5, 5, -1, 0, 6, 485}, + {4, 5, -1, 0, 5, 490}, + {4, 6, -1, 1, 4, 495}, + {3, 5, -1, 0, 4, 501}, + {3, 7, 0, 1, 2, 506}, + {1, 7, -1, 1, 2, 513}, + {3, 7, 0, 1, 2, 520}, + {5, 2, -1, -2, 6, 527}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {1, 1, 0, 0, 2, 529}, + {1, 7, -1, 2, 2, 530}, + {3, 7, -1, 1, 5, 537}, + {4, 6, -1, 0, 5, 544}, + {5, 5, 0, 0, 4, 550}, + {5, 5, -1, 0, 6, 555}, + {1, 7, -1, 1, 2, 560}, + {4, 8, -1, 2, 5, 567}, + {4, 1, 0, -5, 2, 575}, + {6, 7, -1, 1, 7, 576}, + {3, 5, 0, -1, 3, 583}, + {4, 3, -1, -1, 5, 588}, + {4, 3, -1, -1, 6, 591}, + {2, 1, 0, -2, 3, 594}, + {6, 7, -1, 1, 7, 595}, + {3, 1, 0, -5, 2, 602}, + {3, 3, -1, -3, 3, 603}, + {4, 5, -1, 0, 5, 606}, + {2, 4, -1, -2, 2, 611}, + {3, 4, 0, -2, 2, 615}, + {2, 2, 0, -4, 2, 619}, + {3, 6, -1, 2, 4, 621}, + {5, 8, 0, 2, 5, 627}, + {1, 2, -1, -1, 2, 635}, + {2, 2, 0, 2, 2, 637}, + {2, 4, 0, -2, 2, 639}, + {3, 5, 0, -1, 3, 643}, + {4, 3, -1, -1, 5, 648}, + {7, 7, 0, 1, 7, 651}, + {7, 7, 0, 1, 7, 658}, + {7, 7, 0, 1, 7, 665}, + {4, 6, -1, 1, 5, 672}, + {5, 9, -1, 0, 6, 678}, + {5, 9, -1, 0, 6, 687}, + {5, 9, -1, 0, 6, 696}, + {5, 9, -1, 0, 6, 705}, + {5, 8, -1, 0, 6, 714}, + {5, 9, -1, 0, 6, 722}, + {7, 6, -1, 0, 8, 731}, + {5, 8, -1, 2, 6, 737}, + {4, 9, -2, 0, 6, 745}, + {4, 9, -2, 0, 6, 754}, + {4, 9, -2, 0, 6, 763}, + {4, 8, -2, 0, 6, 772}, + {2, 9, 0, 0, 2, 780}, + {2, 9, -1, 0, 2, 789}, + {3, 9, 0, 0, 2, 798}, + {3, 8, 0, 0, 2, 807}, + {5, 6, -1, 0, 6, 815}, + {5, 9, -1, 0, 6, 821}, + {5, 9, -1, 0, 6, 830}, + {5, 9, -1, 0, 6, 839}, + {5, 9, -1, 0, 6, 848}, + {5, 9, -1, 0, 6, 857}, + {5, 8, -1, 0, 6, 866}, + {4, 4, -1, 0, 5, 874}, + {5, 8, -1, 1, 6, 878}, + {5, 9, -1, 0, 6, 886}, + {5, 9, -1, 0, 6, 895}, + {5, 9, -1, 0, 6, 904}, + {5, 8, -1, 0, 6, 913}, + {5, 9, -1, 0, 6, 921}, + {5, 6, -1, 0, 6, 930}, + {4, 7, -2, 1, 6, 936}, + {4, 8, -1, 0, 4, 943}, + {4, 8, -1, 0, 4, 951}, + {4, 8, -1, 0, 4, 959}, + {5, 8, 0, 0, 4, 967}, + {4, 7, -1, 0, 4, 975}, + {4, 8, -1, 0, 4, 982}, + {5, 5, -1, 0, 6, 990}, + {3, 7, -1, 2, 4, 995}, + {3, 8, -1, 0, 4, 1002}, + {3, 8, -1, 0, 4, 1010}, + {3, 8, -1, 0, 4, 1018}, + {3, 7, -1, 0, 4, 1026}, + {2, 8, 0, 0, 2, 1033}, + {2, 8, -1, 0, 2, 1041}, + {3, 8, 0, 0, 2, 1049}, + {3, 7, 0, 0, 2, 1057}, + {4, 8, -1, 0, 5, 1064}, + {4, 8, -1, 0, 5, 1072}, + {4, 8, -1, 0, 5, 1080}, + {4, 8, -1, 0, 5, 1088}, + {4, 8, -1, 0, 5, 1096}, + {4, 8, -1, 0, 5, 1104}, + {4, 7, -1, 0, 5, 1112}, + {4, 5, -1, 0, 5, 1119}, + {7, 7, 0, 1, 5, 1124}, + {3, 8, -1, 0, 4, 1131}, + {3, 8, -1, 0, 4, 1139}, + {3, 8, -1, 0, 4, 1147}, + {3, 7, -1, 0, 4, 1155}, + {4, 9, -1, 1, 4, 1162}, + {4, 7, -1, 1, 5, 1171}, + {4, 8, -1, 1, 4, 1178}, + }, + bitmap_data +}; + +#endif + diff --git a/intern/bmfont/intern/BMF_font_scr12.cpp b/intern/bmfont/intern/BMF_font_scr12.cpp new file mode 100644 index 00000000000..bcdb87fcc0b --- /dev/null +++ b/intern/bmfont/intern/BMF_font_scr12.cpp @@ -0,0 +1,487 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BMF_FontData.h" +#include "BMF_Settings.h" + +#if BMF_INCLUDE_SCR12 + +static unsigned char bitmap_data[]= { + 0x80,0x80,0x00,0x80,0x80,0x80,0x80,0x80, + 0xa0,0xa0,0xa0,0xa0,0x50,0x50,0xfc,0x28, + 0x28,0x7e,0x14,0x14,0x20,0x70,0xa8,0x28, + 0x70,0xa0,0xa8,0x70,0x20,0x98,0x54,0x54, + 0x2c,0xd0,0xa8,0xa8,0x64,0x74,0x88,0x8c, + 0x50,0x20,0x50,0x48,0x30,0x80,0x40,0x20, + 0x20,0x20,0x40,0x40,0x80,0x80,0x80,0x80, + 0x40,0x40,0x20,0x80,0x40,0x40,0x20,0x20, + 0x20,0x20,0x40,0x40,0x80,0x20,0xa8,0x70, + 0xa8,0x20,0x20,0x20,0xf8,0x20,0x20,0x80, + 0x40,0x40,0xc0,0xf8,0x80,0x80,0x80,0x80, + 0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08, + 0x70,0x88,0x88,0xc8,0xa8,0x98,0x88,0x70, + 0xe0,0x40,0x40,0x40,0x40,0x40,0xc0,0x40, + 0xf8,0x80,0x40,0x20,0x10,0x08,0x88,0x70, + 0x70,0x88,0x08,0x08,0x70,0x08,0x88,0x70, + 0x10,0x10,0x10,0xf8,0x90,0x50,0x30,0x10, + 0x70,0x88,0x08,0x08,0xf0,0x80,0x80,0xf8, + 0x70,0x88,0x88,0x88,0xf0,0x80,0x88,0x70, + 0x40,0x40,0x20,0x20,0x10,0x10,0x08,0xf8, + 0x70,0x88,0x88,0x88,0x70,0x88,0x88,0x70, + 0x70,0x88,0x08,0x78,0x88,0x88,0x88,0x70, + 0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x40, + 0x40,0xc0,0x00,0x00,0x40,0x40,0x08,0x10, + 0x20,0x40,0x80,0x40,0x20,0x10,0x08,0xf8, + 0x00,0xf8,0x80,0x40,0x20,0x10,0x08,0x10, + 0x20,0x40,0x80,0x20,0x00,0x20,0x20,0x10, + 0x88,0x88,0x70,0x38,0x40,0x98,0xa8,0xa8, + 0x98,0x48,0x30,0x88,0x88,0xf8,0x88,0x50, + 0x50,0x20,0x20,0xf0,0x88,0x88,0x88,0xf0, + 0x88,0x88,0xf0,0x70,0x88,0x80,0x80,0x80, + 0x80,0x88,0x70,0xf0,0x88,0x88,0x88,0x88, + 0x88,0x88,0xf0,0xf8,0x80,0x80,0x80,0xf0, + 0x80,0x80,0xf8,0x80,0x80,0x80,0x80,0xf0, + 0x80,0x80,0xf8,0x68,0x98,0x88,0x88,0x98, + 0x80,0x88,0x70,0x88,0x88,0x88,0x88,0xf8, + 0x88,0x88,0x88,0xe0,0x40,0x40,0x40,0x40, + 0x40,0x40,0xe0,0x70,0x88,0x88,0x08,0x08, + 0x08,0x08,0x08,0x88,0x88,0x90,0xa0,0xc0, + 0xa0,0x90,0x88,0xf8,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x88,0x88,0xa8,0xa8,0xd8, + 0xd8,0x88,0x88,0x88,0x98,0x98,0xa8,0xa8, + 0xc8,0xc8,0x88,0x70,0x88,0x88,0x88,0x88, + 0x88,0x88,0x70,0x80,0x80,0x80,0x80,0xf0, + 0x88,0x88,0xf0,0x08,0x10,0x70,0xa8,0x88, + 0x88,0x88,0x88,0x88,0x70,0x88,0x90,0x90, + 0xa0,0xf0,0x88,0x88,0xf0,0x70,0x88,0x88, + 0x08,0x70,0x80,0x88,0x70,0x20,0x20,0x20, + 0x20,0x20,0x20,0x20,0xf8,0x70,0x88,0x88, + 0x88,0x88,0x88,0x88,0x88,0x20,0x20,0x50, + 0x50,0x50,0x88,0x88,0x88,0x50,0x50,0xf8, + 0xa8,0xa8,0xa8,0x88,0x88,0x88,0x88,0x50, + 0x20,0x20,0x50,0x88,0x88,0x20,0x20,0x20, + 0x20,0x50,0x50,0x88,0x88,0xf8,0x80,0x40, + 0x40,0x20,0x10,0x08,0xf8,0xe0,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0xe0,0x08,0x08, + 0x10,0x10,0x20,0x20,0x40,0x40,0x80,0x80, + 0xe0,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 0xe0,0x88,0x50,0x20,0xfe,0x20,0x40,0x80, + 0x80,0x68,0x98,0x88,0x78,0x08,0x70,0xb0, + 0xc8,0x88,0x88,0xc8,0xb0,0x80,0x80,0x70, + 0x88,0x80,0x80,0x88,0x70,0x68,0x98,0x88, + 0x88,0x98,0x68,0x08,0x08,0x70,0x88,0x80, + 0xf8,0x88,0x70,0x40,0x40,0x40,0x40,0x40, + 0xf0,0x40,0x38,0xf0,0x08,0x68,0x98,0x88, + 0x88,0x98,0x68,0x88,0x88,0x88,0x88,0xc8, + 0xb0,0x80,0x80,0x20,0x20,0x20,0x20,0x20, + 0xe0,0x00,0x20,0x60,0x90,0x10,0x10,0x10, + 0x10,0x10,0x70,0x00,0x10,0x88,0x90,0xa0, + 0xc0,0xa0,0x90,0x80,0x80,0x20,0x20,0x20, + 0x20,0x20,0x20,0x20,0xe0,0xa8,0xa8,0xa8, + 0xa8,0xa8,0xd0,0x88,0x88,0x88,0x88,0xc8, + 0xb0,0x70,0x88,0x88,0x88,0x88,0x70,0x80, + 0x80,0xb0,0xc8,0x88,0x88,0xc8,0xb0,0x08, + 0x08,0x68,0x98,0x88,0x88,0x98,0x68,0x80, + 0x80,0x80,0x80,0xc8,0xb0,0x70,0x88,0x10, + 0x60,0x88,0x70,0x30,0x40,0x40,0x40,0x40, + 0xf0,0x40,0x68,0x98,0x88,0x88,0x88,0x88, + 0x20,0x20,0x50,0x50,0x88,0x88,0x50,0xa8, + 0xa8,0xa8,0x88,0x88,0x88,0x88,0x50,0x20, + 0x50,0x88,0xf0,0x08,0x68,0x98,0x88,0x88, + 0x88,0x88,0xf8,0x80,0x40,0x20,0x10,0xf8, + 0x18,0x20,0x20,0x20,0x20,0xc0,0x20,0x20, + 0x20,0x18,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0xc0,0x20,0x20,0x20, + 0x20,0x18,0x20,0x20,0x20,0xc0,0x98,0xb4, + 0x64,0x80,0x80,0x80,0x80,0x80,0x00,0x80, + 0x80,0x20,0x20,0x70,0x88,0x80,0x88,0x70, + 0x20,0x20,0xb0,0x48,0x40,0xf0,0x40,0x40, + 0x48,0x30,0x90,0x60,0x90,0x90,0x60,0x90, + 0x20,0x70,0x20,0x70,0x20,0x50,0x88,0x88, + 0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x80, + 0x80,0x80,0x70,0x88,0x10,0x28,0x48,0x90, + 0xa0,0x40,0x88,0x70,0xa0,0x78,0x84,0xb4, + 0xa4,0xb4,0x84,0x78,0xf0,0x90,0x70,0x10, + 0x60,0x14,0x28,0x50,0xa0,0x50,0x28,0x14, + 0x08,0xf8,0xf0,0x78,0x84,0xac,0xb4,0xb4, + 0x84,0x78,0xe0,0x60,0x90,0x60,0xf8,0x00, + 0x20,0x20,0xf8,0x20,0x20,0xe0,0x40,0x20, + 0xa0,0x40,0xc0,0x20,0x40,0x20,0xc0,0x80, + 0x40,0x80,0xe8,0x90,0x90,0x90,0x90,0x28, + 0x28,0x28,0x28,0x68,0xa8,0xa8,0xa8,0x7c, + 0x80,0x80,0xc0,0x40,0xe0,0x40,0x40,0xc0, + 0x40,0xf0,0x60,0x90,0x90,0x60,0xa0,0x50, + 0x28,0x14,0x28,0x50,0xa0,0x08,0x38,0xa8, + 0x58,0x28,0xf0,0x48,0x40,0xc0,0x40,0x38, + 0x10,0x88,0x68,0x30,0xf0,0x48,0x40,0xc0, + 0x40,0x08,0x38,0xa8,0x58,0x28,0xd0,0x28, + 0x40,0x20,0xc0,0x70,0x88,0x88,0x40,0x20, + 0x20,0x00,0x20,0x88,0x88,0xf8,0x88,0x50, + 0x50,0x20,0x00,0x20,0x40,0x88,0x88,0xf8, + 0x50,0x50,0x20,0x20,0x00,0x20,0x10,0x88, + 0x88,0xf8,0x50,0x50,0x20,0x20,0x00,0x50, + 0x20,0x88,0x88,0xf8,0x50,0x50,0x20,0x20, + 0x00,0xb0,0x68,0x88,0x88,0xf8,0x50,0x50, + 0x20,0x20,0x00,0x50,0x88,0x88,0xf8,0x50, + 0x50,0x20,0x20,0x20,0x50,0x20,0x9c,0x90, + 0xf0,0x50,0x5c,0x30,0x30,0x1c,0x60,0x20, + 0x70,0x88,0x80,0x80,0x80,0x80,0x88,0x70, + 0xf8,0x80,0x80,0xf0,0x80,0x80,0xf8,0x00, + 0x20,0x40,0xf8,0x80,0x80,0xf0,0x80,0x80, + 0xf8,0x00,0x20,0x10,0xf8,0x80,0x80,0xf0, + 0x80,0x80,0xf8,0x00,0x50,0x20,0xf8,0x80, + 0x80,0xf0,0x80,0x80,0xf8,0x00,0x50,0xe0, + 0x40,0x40,0x40,0x40,0x40,0xe0,0x00,0x40, + 0x80,0xe0,0x40,0x40,0x40,0x40,0x40,0xe0, + 0x00,0x40,0x20,0xe0,0x40,0x40,0x40,0x40, + 0x40,0xe0,0x00,0xa0,0x40,0xe0,0x40,0x40, + 0x40,0x40,0x40,0xe0,0x00,0xa0,0x78,0x44, + 0x44,0xf4,0x44,0x44,0x44,0x78,0x88,0x98, + 0x98,0xa8,0xc8,0xc8,0x88,0x00,0xb0,0x68, + 0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00, + 0x20,0x40,0x70,0x88,0x88,0x88,0x88,0x88, + 0x70,0x00,0x20,0x10,0x70,0x88,0x88,0x88, + 0x88,0x88,0x70,0x00,0x50,0x20,0x70,0x88, + 0x88,0x88,0x88,0x88,0x70,0x00,0xb0,0x68, + 0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00, + 0x50,0x88,0x50,0x20,0x50,0x88,0xb8,0x44, + 0x64,0x54,0x4c,0x44,0x3a,0x70,0x88,0x88, + 0x88,0x88,0x88,0x88,0x00,0x20,0x40,0x70, + 0x88,0x88,0x88,0x88,0x88,0x88,0x00,0x20, + 0x10,0x70,0x88,0x88,0x88,0x88,0x88,0x88, + 0x00,0x50,0x20,0x70,0x88,0x88,0x88,0x88, + 0x88,0x88,0x00,0x50,0x20,0x20,0x20,0x50, + 0x50,0x88,0x88,0x00,0x20,0x10,0x80,0x80, + 0xf0,0x88,0x88,0x88,0xf0,0x80,0x80,0xb0, + 0x88,0x88,0x88,0x90,0xa0,0x90,0x60,0x78, + 0x88,0x78,0x08,0x70,0x00,0x20,0x40,0x78, + 0x88,0x78,0x08,0x70,0x00,0x20,0x10,0x78, + 0x88,0x78,0x08,0x70,0x00,0x50,0x20,0x78, + 0x88,0x78,0x08,0x70,0x00,0xb0,0x68,0x78, + 0x88,0x78,0x08,0x70,0x00,0x50,0x78,0x88, + 0x78,0x08,0x70,0x00,0x20,0x50,0x20,0x6c, + 0x90,0x7c,0x12,0x6c,0x60,0x20,0x70,0x88, + 0x80,0x80,0x88,0x70,0x78,0x80,0xf8,0x88, + 0x70,0x00,0x20,0x40,0x78,0x80,0xf8,0x88, + 0x70,0x00,0x20,0x10,0x78,0x80,0xf8,0x88, + 0x70,0x00,0x50,0x20,0x78,0x80,0xf8,0x88, + 0x70,0x00,0x50,0x20,0x20,0x20,0x20,0xe0, + 0x00,0x40,0x80,0x20,0x20,0x20,0x20,0xe0, + 0x00,0x40,0x20,0x20,0x20,0x20,0x20,0xe0, + 0x00,0xa0,0x40,0x20,0x20,0x20,0x20,0xe0, + 0x00,0xa0,0x70,0x88,0x88,0x88,0x78,0x08, + 0x90,0x60,0xd0,0x88,0x88,0x88,0xc8,0xb0, + 0x00,0xb0,0x68,0x70,0x88,0x88,0x88,0x70, + 0x00,0x20,0x40,0x70,0x88,0x88,0x88,0x70, + 0x00,0x20,0x10,0x70,0x88,0x88,0x88,0x70, + 0x00,0x50,0x20,0x70,0x88,0x88,0x88,0x70, + 0x00,0xb0,0x68,0x70,0x88,0x88,0x88,0x70, + 0x00,0x50,0x20,0x00,0xf8,0x00,0x20,0xb8, + 0x64,0x54,0x4c,0x3a,0x68,0x98,0x88,0x88, + 0x88,0x00,0x20,0x40,0x68,0x98,0x88,0x88, + 0x88,0x00,0x20,0x10,0x68,0x98,0x88,0x88, + 0x88,0x00,0x50,0x20,0x68,0x98,0x88,0x88, + 0x88,0x00,0x50,0xf0,0x08,0x68,0x98,0x88, + 0x88,0x88,0x00,0x20,0x10,0x80,0x80,0xb0, + 0xc8,0x88,0x88,0xc8,0xb0,0x80,0x80,0xf0, + 0x08,0x68,0x98,0x88,0x88,0x88,0x00,0xd8, +}; + +BMF_FontData BMF_font_scr12 = { + 0, -2, + 7, 10, + { + {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, -1}, + {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, 16, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 7, -1}, + {1, 8, -3, 0, 7, 0}, + {3, 4, -2, -5, 7, 8}, + {7, 8, 0, 0, 7, 12}, + {5, 9, -1, 1, 7, 20}, + {6, 8, 0, 0, 7, 29}, + {6, 8, 0, 0, 7, 37}, + {3, 4, -2, -5, 7, 45}, + {3, 10, -2, 2, 7, 49}, + {3, 10, -2, 2, 7, 59}, + {5, 5, -1, -3, 7, 69}, + {5, 5, -1, -1, 7, 74}, + {2, 4, -2, 2, 7, 79}, + {5, 1, -1, -3, 7, 83}, + {1, 2, -3, 0, 7, 84}, + {5, 10, -1, 1, 7, 86}, + {5, 8, -1, 0, 7, 96}, + {3, 8, -2, 0, 7, 104}, + {5, 8, -1, 0, 7, 112}, + {5, 8, -1, 0, 7, 120}, + {5, 8, -1, 0, 7, 128}, + {5, 8, -1, 0, 7, 136}, + {5, 8, -1, 0, 7, 144}, + {5, 8, -1, 0, 7, 152}, + {5, 8, -1, 0, 7, 160}, + {5, 8, -1, 0, 7, 168}, + {1, 6, -3, 0, 7, 176}, + {2, 8, -2, 2, 7, 182}, + {5, 9, -1, 1, 7, 190}, + {5, 3, -1, -2, 7, 199}, + {5, 9, -1, 1, 7, 202}, + {5, 8, -1, 0, 7, 211}, + {5, 8, -1, 0, 7, 219}, + {5, 8, -1, 0, 7, 227}, + {5, 8, -1, 0, 7, 235}, + {5, 8, -1, 0, 7, 243}, + {5, 8, -1, 0, 7, 251}, + {5, 8, -1, 0, 7, 259}, + {5, 8, -1, 0, 7, 267}, + {5, 8, -1, 0, 7, 275}, + {5, 8, -1, 0, 7, 283}, + {3, 8, -2, 0, 7, 291}, + {5, 8, -1, 0, 7, 299}, + {5, 8, -1, 0, 7, 307}, + {5, 8, -1, 0, 7, 315}, + {5, 8, -1, 0, 7, 323}, + {5, 8, -1, 0, 7, 331}, + {5, 8, -1, 0, 7, 339}, + {5, 8, -1, 0, 7, 347}, + {5, 10, -1, 2, 7, 355}, + {5, 8, -1, 0, 7, 365}, + {5, 8, -1, 0, 7, 373}, + {5, 8, -1, 0, 7, 381}, + {5, 8, -1, 0, 7, 389}, + {5, 8, -1, 0, 7, 397}, + {5, 8, -1, 0, 7, 405}, + {5, 8, -1, 0, 7, 413}, + {5, 8, -1, 0, 7, 421}, + {5, 8, -1, 0, 7, 429}, + {3, 9, -2, 1, 7, 437}, + {5, 10, -1, 1, 7, 446}, + {3, 9, -2, 1, 7, 456}, + {5, 3, -1, -5, 7, 465}, + {7, 1, 0, 1, 7, 468}, + {3, 4, -2, -5, 7, 469}, + {5, 6, -1, 0, 7, 473}, + {5, 8, -1, 0, 7, 479}, + {5, 6, -1, 0, 7, 487}, + {5, 8, -1, 0, 7, 493}, + {5, 6, -1, 0, 7, 501}, + {5, 8, -1, 0, 7, 507}, + {5, 8, -1, 2, 7, 515}, + {5, 8, -1, 0, 7, 523}, + {3, 8, -2, 0, 7, 531}, + {4, 10, -1, 2, 7, 539}, + {5, 8, -1, 0, 7, 549}, + {3, 8, -2, 0, 7, 557}, + {5, 6, -1, 0, 7, 565}, + {5, 6, -1, 0, 7, 571}, + {5, 6, -1, 0, 7, 577}, + {5, 8, -1, 2, 7, 583}, + {5, 8, -1, 2, 7, 591}, + {5, 6, -1, 0, 7, 599}, + {5, 6, -1, 0, 7, 605}, + {4, 7, -1, 0, 7, 611}, + {5, 6, -1, 0, 7, 618}, + {5, 6, -1, 0, 7, 624}, + {5, 6, -1, 0, 7, 630}, + {5, 6, -1, 0, 7, 636}, + {5, 8, -1, 2, 7, 642}, + {5, 6, -1, 0, 7, 650}, + {5, 10, -1, 2, 7, 656}, + {1, 10, -3, 1, 7, 666}, + {5, 10, -1, 2, 7, 676}, + {6, 3, 0, -2, 7, 686}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {1, 8, -3, 2, 7, 689}, + {5, 9, -1, 0, 7, 697}, + {5, 8, -1, 0, 7, 706}, + {4, 6, -1, -2, 7, 714}, + {5, 8, -1, 0, 7, 720}, + {1, 10, -3, 1, 7, 728}, + {5, 10, -1, 1, 7, 738}, + {3, 1, -2, -7, 7, 748}, + {6, 7, 0, 0, 7, 749}, + {4, 5, -1, -4, 7, 756}, + {6, 7, 0, 0, 7, 761}, + {5, 2, -1, -3, 7, 768}, + {4, 1, -1, -3, 7, 770}, + {6, 7, 0, 0, 7, 771}, + {3, 1, -2, -7, 7, 778}, + {4, 3, -1, -4, 7, 779}, + {5, 7, -1, 0, 7, 782}, + {3, 5, -2, -4, 7, 789}, + {3, 5, -2, -4, 7, 794}, + {2, 2, -2, -7, 7, 799}, + {5, 6, -1, 1, 7, 801}, + {6, 9, 0, 1, 7, 807}, + {1, 2, -3, -3, 7, 816}, + {2, 2, -2, 2, 7, 818}, + {3, 5, -2, -4, 7, 820}, + {4, 5, -1, -4, 7, 825}, + {6, 7, 0, 0, 7, 830}, + {5, 10, -1, 1, 7, 837}, + {5, 10, -1, 1, 7, 847}, + {5, 10, -1, 1, 7, 857}, + {5, 8, -1, 2, 7, 867}, + {5, 10, -1, 0, 7, 875}, + {5, 10, -1, 0, 7, 885}, + {5, 10, -1, 0, 7, 895}, + {5, 10, -1, 0, 7, 905}, + {5, 9, -1, 0, 7, 915}, + {5, 10, -1, 0, 7, 924}, + {6, 8, 0, 0, 7, 934}, + {5, 10, -1, 2, 7, 942}, + {5, 10, -1, 0, 7, 952}, + {5, 10, -1, 0, 7, 962}, + {5, 10, -1, 0, 7, 972}, + {5, 9, -1, 0, 7, 982}, + {3, 10, -2, 0, 7, 991}, + {3, 10, -2, 0, 7, 1001}, + {3, 10, -2, 0, 7, 1011}, + {3, 9, -2, 0, 7, 1021}, + {6, 8, 0, 0, 7, 1030}, + {5, 10, -1, 0, 7, 1038}, + {5, 10, -1, 0, 7, 1048}, + {5, 10, -1, 0, 7, 1058}, + {5, 10, -1, 0, 7, 1068}, + {5, 10, -1, 0, 7, 1078}, + {5, 9, -1, 0, 7, 1088}, + {5, 5, -1, -1, 7, 1097}, + {7, 7, 0, 0, 7, 1102}, + {5, 10, -1, 0, 7, 1109}, + {5, 10, -1, 0, 7, 1119}, + {5, 10, -1, 0, 7, 1129}, + {5, 9, -1, 0, 7, 1139}, + {5, 10, -1, 0, 7, 1148}, + {5, 9, -1, 0, 7, 1158}, + {5, 8, -1, 0, 7, 1167}, + {5, 8, -1, 0, 7, 1175}, + {5, 8, -1, 0, 7, 1183}, + {5, 8, -1, 0, 7, 1191}, + {5, 8, -1, 0, 7, 1199}, + {5, 7, -1, 0, 7, 1207}, + {5, 9, -1, 0, 7, 1214}, + {7, 5, 0, 0, 7, 1223}, + {5, 8, -1, 2, 7, 1228}, + {5, 8, -1, 0, 7, 1236}, + {5, 8, -1, 0, 7, 1244}, + {5, 8, -1, 0, 7, 1252}, + {5, 7, -1, 0, 7, 1260}, + {3, 8, -2, 0, 7, 1267}, + {3, 8, -2, 0, 7, 1275}, + {3, 8, -2, 0, 7, 1283}, + {3, 7, -2, 0, 7, 1291}, + {5, 9, -1, 0, 7, 1298}, + {5, 8, -1, 0, 7, 1307}, + {5, 8, -1, 0, 7, 1315}, + {5, 8, -1, 0, 7, 1323}, + {5, 8, -1, 0, 7, 1331}, + {5, 8, -1, 0, 7, 1339}, + {5, 7, -1, 0, 7, 1347}, + {5, 5, -1, -1, 7, 1354}, + {7, 5, 0, 0, 7, 1359}, + {5, 8, -1, 0, 7, 1364}, + {5, 8, -1, 0, 7, 1372}, + {5, 8, -1, 0, 7, 1380}, + {5, 7, -1, 0, 7, 1388}, + {5, 10, -1, 2, 7, 1395}, + {5, 10, -1, 2, 7, 1405}, + {5, 9, -1, 2, 7, 1415}, + }, + bitmap_data +}; + +#endif + diff --git a/intern/bmfont/intern/BMF_font_scr14.cpp b/intern/bmfont/intern/BMF_font_scr14.cpp new file mode 100644 index 00000000000..6a3ee9dd710 --- /dev/null +++ b/intern/bmfont/intern/BMF_font_scr14.cpp @@ -0,0 +1,513 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BMF_FontData.h" +#include "BMF_Settings.h" + +#if BMF_INCLUDE_SCR14 + +static unsigned char bitmap_data[]= { + 0x80,0x80,0x00,0x80,0x80,0x80,0x80,0x80, + 0x80,0xa0,0xa0,0xa0,0xa0,0x50,0x50,0xfc, + 0x28,0x28,0x28,0x7e,0x14,0x14,0x20,0x70, + 0xa8,0x28,0x30,0x60,0xa0,0xa8,0x70,0x20, + 0x98,0x54,0x54,0x2c,0x10,0x68,0x54,0x54, + 0x32,0x74,0x88,0x8c,0x90,0x60,0x20,0x50, + 0x48,0x30,0x80,0x40,0x20,0x20,0x20,0x40, + 0x40,0x80,0x80,0x80,0x80,0x80,0x40,0x40, + 0x20,0x80,0x40,0x40,0x20,0x20,0x20,0x20, + 0x20,0x40,0x40,0x80,0x20,0xa8,0x70,0x70, + 0xa8,0x20,0x20,0x20,0xf8,0x20,0x20,0x80, + 0x40,0x40,0xc0,0xf8,0x80,0x80,0x80,0x80, + 0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08, + 0x70,0x88,0x88,0xc8,0xa8,0x98,0x88,0x88, + 0x70,0xe0,0x40,0x40,0x40,0x40,0x40,0x40, + 0xc0,0x40,0xf8,0x80,0x40,0x20,0x10,0x08, + 0x88,0x88,0x70,0x70,0x88,0x08,0x08,0x70, + 0x08,0x08,0x88,0x70,0x10,0x10,0x10,0xf8, + 0x90,0x50,0x50,0x30,0x10,0x70,0x88,0x08, + 0x08,0x08,0xf0,0x80,0x80,0xf8,0x70,0x88, + 0x88,0x88,0x88,0xf0,0x80,0x88,0x70,0x40, + 0x40,0x40,0x20,0x20,0x10,0x10,0x08,0xf8, + 0x70,0x88,0x88,0x88,0x70,0x88,0x88,0x88, + 0x70,0x70,0x88,0x08,0x08,0x78,0x88,0x88, + 0x88,0x70,0x80,0x80,0x00,0x00,0x80,0x80, + 0x80,0x40,0x40,0xc0,0x00,0x00,0x40,0x40, + 0x08,0x10,0x20,0x40,0x80,0x40,0x20,0x10, + 0x08,0xf8,0x00,0xf8,0x80,0x40,0x20,0x10, + 0x08,0x10,0x20,0x40,0x80,0x20,0x20,0x00, + 0x20,0x20,0x10,0x88,0x88,0x70,0x38,0x40, + 0x98,0xa8,0xa8,0x98,0x88,0x48,0x30,0x88, + 0x88,0xf8,0x88,0x50,0x50,0x50,0x20,0x20, + 0xf0,0x88,0x88,0x88,0xf0,0x88,0x88,0x88, + 0xf0,0x70,0x88,0x80,0x80,0x80,0x80,0x80, + 0x88,0x70,0xf0,0x88,0x88,0x88,0x88,0x88, + 0x88,0x88,0xf0,0xf8,0x80,0x80,0x80,0xf0, + 0x80,0x80,0x80,0xf8,0x80,0x80,0x80,0x80, + 0xf0,0x80,0x80,0x80,0xf8,0x68,0x98,0x88, + 0x88,0x98,0x80,0x80,0x88,0x70,0x88,0x88, + 0x88,0x88,0xf8,0x88,0x88,0x88,0x88,0xe0, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0xe0, + 0x70,0x88,0x88,0x08,0x08,0x08,0x08,0x08, + 0x08,0x88,0x88,0x90,0xa0,0xc0,0xa0,0x90, + 0x88,0x88,0xf8,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x88,0x88,0x88,0xa8,0xa8, + 0xd8,0xd8,0x88,0x88,0x88,0x98,0x98,0xa8, + 0xa8,0xc8,0xc8,0x88,0x88,0x70,0x88,0x88, + 0x88,0x88,0x88,0x88,0x88,0x70,0x80,0x80, + 0x80,0x80,0xf0,0x88,0x88,0x88,0xf0,0x08, + 0x10,0x70,0xa8,0x88,0x88,0x88,0x88,0x88, + 0x88,0x70,0x88,0x88,0x90,0xa0,0xf0,0x88, + 0x88,0x88,0xf0,0x70,0x88,0x08,0x08,0x70, + 0x80,0x80,0x88,0x70,0x20,0x20,0x20,0x20, + 0x20,0x20,0x20,0x20,0xf8,0x70,0x88,0x88, + 0x88,0x88,0x88,0x88,0x88,0x88,0x20,0x20, + 0x50,0x50,0x50,0x88,0x88,0x88,0x88,0x50, + 0x50,0xf8,0xa8,0xa8,0x88,0x88,0x88,0x88, + 0x88,0x88,0x50,0x50,0x20,0x50,0x50,0x88, + 0x88,0x20,0x20,0x20,0x20,0x20,0x50,0x50, + 0x88,0x88,0xf8,0x80,0x40,0x40,0x20,0x10, + 0x10,0x08,0xf8,0xf0,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0xf0,0x08,0x08, + 0x10,0x10,0x20,0x20,0x40,0x40,0x80,0x80, + 0xf0,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0xf0,0x88,0x50,0x20,0xfe,0x20, + 0x40,0x80,0x80,0x68,0x98,0x88,0x78,0x08, + 0x88,0x70,0xb0,0xc8,0x88,0x88,0x88,0xc8, + 0xb0,0x80,0x80,0x70,0x88,0x80,0x80,0x80, + 0x88,0x70,0x68,0x98,0x88,0x88,0x88,0x98, + 0x68,0x08,0x08,0x70,0x88,0x80,0xf8,0x88, + 0x88,0x70,0x40,0x40,0x40,0x40,0x40,0x40, + 0xf0,0x40,0x38,0x70,0x88,0x08,0x68,0x98, + 0x88,0x88,0x88,0x98,0x68,0x88,0x88,0x88, + 0x88,0x88,0xc8,0xb0,0x80,0x80,0x20,0x20, + 0x20,0x20,0x20,0x20,0xe0,0x00,0x20,0x60, + 0x90,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x70,0x00,0x10,0x88,0x88,0x90,0xe0,0xa0, + 0x90,0x88,0x80,0x80,0x20,0x20,0x20,0x20, + 0x20,0x20,0x20,0x20,0xe0,0xa8,0xa8,0xa8, + 0xa8,0xa8,0xa8,0xd0,0x88,0x88,0x88,0x88, + 0x88,0xc8,0xb0,0x70,0x88,0x88,0x88,0x88, + 0x88,0x70,0x80,0x80,0x80,0xb0,0xc8,0x88, + 0x88,0x88,0xc8,0xb0,0x08,0x08,0x08,0x68, + 0x98,0x88,0x88,0x88,0x98,0x68,0x80,0x80, + 0x80,0x80,0x80,0xc8,0xb0,0x70,0x88,0x08, + 0x70,0x80,0x88,0x70,0x30,0x40,0x40,0x40, + 0x40,0x40,0xf0,0x40,0x40,0x68,0x98,0x88, + 0x88,0x88,0x88,0x88,0x20,0x20,0x50,0x50, + 0x88,0x88,0x88,0x50,0xa8,0xa8,0xa8,0xa8, + 0x88,0x88,0x88,0x88,0x50,0x20,0x50,0x88, + 0x88,0x70,0x88,0x08,0x68,0x98,0x88,0x88, + 0x88,0x88,0x88,0xf8,0x80,0x40,0x20,0x10, + 0x08,0xf8,0x18,0x20,0x20,0x20,0x20,0x20, + 0xc0,0x20,0x20,0x20,0x20,0x18,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0xc0,0x20,0x20,0x20,0x20,0x20, + 0x18,0x20,0x20,0x20,0x20,0xc0,0x98,0xb4, + 0x64,0x80,0x80,0x80,0x80,0x80,0x80,0x00, + 0x80,0x80,0x20,0x20,0x70,0x88,0x80,0x80, + 0x88,0x70,0x20,0x20,0xb0,0x48,0x40,0x40, + 0xf0,0x40,0x40,0x48,0x30,0x88,0x70,0x88, + 0x88,0x70,0x88,0x70,0x20,0xf8,0x20,0xf8, + 0x50,0x50,0x88,0x88,0x80,0x80,0x80,0x80, + 0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x80, + 0x70,0x88,0x10,0x28,0x48,0x88,0x90,0xa0, + 0x40,0x88,0x70,0xd8,0x38,0x44,0x92,0xaa, + 0xa2,0xaa,0x92,0x44,0x38,0xf8,0x00,0x68, + 0x90,0x70,0x10,0x60,0x12,0x24,0x48,0x90, + 0x48,0x24,0x12,0x08,0x08,0xf8,0xf0,0x38, + 0x44,0xaa,0xaa,0xb2,0xaa,0xb2,0x44,0x38, + 0xe0,0x60,0x90,0x90,0x60,0xf8,0x00,0x20, + 0x20,0xf8,0x20,0x20,0xe0,0x40,0x20,0xa0, + 0x40,0xc0,0x20,0x40,0x20,0xc0,0x80,0x40, + 0x80,0x80,0xb4,0xc8,0x88,0x88,0x88,0x88, + 0x28,0x28,0x28,0x28,0x28,0x68,0xa8,0xa8, + 0xa8,0x7c,0x80,0x80,0xc0,0x20,0x40,0xe0, + 0x40,0x40,0xc0,0x40,0xf8,0x00,0x70,0x88, + 0x88,0x88,0x70,0x90,0x48,0x24,0x12,0x24, + 0x48,0x90,0x04,0x9e,0x54,0x2c,0x14,0xe8, + 0x44,0x40,0xc0,0x40,0x1c,0x08,0x84,0x54, + 0x28,0x10,0xe8,0x44,0x40,0xc0,0x40,0x04, + 0x9e,0x54,0x2c,0xd4,0x28,0x44,0x20,0xc0, + 0x70,0x88,0x80,0x40,0x20,0x20,0x00,0x00, + 0x20,0x20,0x88,0x88,0xf8,0x88,0x50,0x50, + 0x20,0x20,0x00,0x20,0x40,0x88,0x88,0xf8, + 0x88,0x50,0x50,0x20,0x20,0x00,0x20,0x10, + 0x88,0x88,0xf8,0x88,0x50,0x50,0x20,0x20, + 0x00,0x50,0x20,0x88,0x88,0xf8,0x88,0x50, + 0x50,0x20,0x20,0x00,0xb0,0x68,0x88,0x88, + 0xf8,0x88,0x50,0x50,0x20,0x20,0x00,0xd8, + 0x88,0x88,0xf8,0x88,0x50,0x50,0x20,0x20, + 0x20,0x50,0x20,0x9c,0x90,0xf0,0x90,0x5c, + 0x50,0x30,0x30,0x1c,0x60,0x10,0x20,0x70, + 0x88,0x80,0x80,0x80,0x80,0x80,0x88,0x70, + 0xf8,0x80,0x80,0x80,0xf0,0x80,0x80,0xf8, + 0x00,0x20,0x40,0xf8,0x80,0x80,0x80,0xf0, + 0x80,0x80,0xf8,0x00,0x20,0x10,0xf8,0x80, + 0x80,0x80,0xf0,0x80,0x80,0xf8,0x00,0x50, + 0x20,0xf8,0x80,0x80,0x80,0xf0,0x80,0x80, + 0xf8,0x00,0xd8,0xe0,0x40,0x40,0x40,0x40, + 0x40,0x40,0xe0,0x00,0x40,0x80,0xe0,0x40, + 0x40,0x40,0x40,0x40,0x40,0xe0,0x00,0x40, + 0x20,0xe0,0x40,0x40,0x40,0x40,0x40,0x40, + 0xe0,0x00,0xa0,0x40,0x70,0x20,0x20,0x20, + 0x20,0x20,0x20,0x70,0x00,0xd8,0x78,0x44, + 0x44,0x44,0xf4,0x44,0x44,0x44,0x78,0x88, + 0x98,0x98,0xa8,0xa8,0xc8,0xc8,0x88,0x00, + 0xb0,0x68,0x70,0x88,0x88,0x88,0x88,0x88, + 0x88,0x70,0x00,0x20,0x40,0x70,0x88,0x88, + 0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x10, + 0x70,0x88,0x88,0x88,0x88,0x88,0x88,0x70, + 0x00,0x50,0x20,0x70,0x88,0x88,0x88,0x88, + 0x88,0x88,0x70,0x00,0xb0,0x68,0x70,0x88, + 0x88,0x88,0x88,0x88,0x88,0x70,0x00,0xd8, + 0x88,0x50,0x20,0x50,0x88,0xb8,0x44,0x64, + 0x64,0x54,0x4c,0x4c,0x44,0x3a,0x70,0x88, + 0x88,0x88,0x88,0x88,0x88,0x88,0x00,0x20, + 0x40,0x70,0x88,0x88,0x88,0x88,0x88,0x88, + 0x88,0x00,0x20,0x10,0x70,0x88,0x88,0x88, + 0x88,0x88,0x88,0x88,0x00,0x50,0x20,0x70, + 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x00, + 0xd8,0x20,0x20,0x20,0x20,0x50,0x50,0x88, + 0x88,0x00,0x20,0x10,0xe0,0x40,0x78,0x44, + 0x44,0x44,0x78,0x40,0xe0,0xb0,0x88,0x88, + 0x88,0x90,0xa0,0x90,0x90,0x60,0x68,0x98, + 0x88,0x78,0x08,0x88,0x70,0x00,0x20,0x40, + 0x68,0x98,0x88,0x78,0x08,0x88,0x70,0x00, + 0x20,0x10,0x68,0x98,0x88,0x78,0x08,0x88, + 0x70,0x00,0x50,0x20,0x68,0x98,0x88,0x78, + 0x08,0x88,0x70,0x00,0xb0,0x68,0x68,0x98, + 0x88,0x78,0x08,0x88,0x70,0x00,0xd8,0x68, + 0x98,0x88,0x78,0x08,0x88,0x70,0x00,0x20, + 0x50,0x20,0x6c,0x92,0x90,0x7e,0x12,0x92, + 0x6c,0x60,0x10,0x20,0x70,0x88,0x80,0x80, + 0x80,0x88,0x70,0x70,0x88,0x80,0xf8,0x88, + 0x88,0x70,0x00,0x20,0x40,0x70,0x88,0x80, + 0xf8,0x88,0x88,0x70,0x00,0x20,0x10,0x70, + 0x88,0x80,0xf8,0x88,0x88,0x70,0x00,0x50, + 0x20,0x70,0x88,0x80,0xf8,0x88,0x88,0x70, + 0x00,0xd8,0x20,0x20,0x20,0x20,0x20,0x20, + 0xe0,0x00,0x20,0x40,0x20,0x20,0x20,0x20, + 0x20,0x20,0xe0,0x00,0x20,0x10,0x20,0x20, + 0x20,0x20,0x20,0x20,0xe0,0x00,0xa0,0x40, + 0x20,0x20,0x20,0x20,0x20,0x20,0xe0,0x00, + 0xd8,0x70,0x88,0x88,0x88,0x88,0x88,0x78, + 0x10,0xd0,0x20,0xd0,0x88,0x88,0x88,0x88, + 0x88,0xc8,0xb0,0x00,0xb0,0x68,0x70,0x88, + 0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x40, + 0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00, + 0x20,0x10,0x70,0x88,0x88,0x88,0x88,0x88, + 0x70,0x00,0x50,0x20,0x70,0x88,0x88,0x88, + 0x88,0x88,0x70,0x00,0xb0,0x68,0x70,0x88, + 0x88,0x88,0x88,0x88,0x70,0x00,0xd8,0x10, + 0x10,0x00,0xfe,0x00,0x10,0x10,0xb8,0x44, + 0x64,0x54,0x4c,0x44,0x3a,0x68,0x98,0x88, + 0x88,0x88,0x88,0x88,0x00,0x20,0x40,0x68, + 0x98,0x88,0x88,0x88,0x88,0x88,0x00,0x20, + 0x10,0x68,0x98,0x88,0x88,0x88,0x88,0x88, + 0x00,0x50,0x20,0x68,0x98,0x88,0x88,0x88, + 0x88,0x88,0x00,0xd8,0x70,0x88,0x08,0x68, + 0x98,0x88,0x88,0x88,0x88,0x88,0x00,0x20, + 0x10,0xe0,0x40,0x58,0x64,0x44,0x44,0x44, + 0x64,0x58,0x40,0xc0,0x70,0x88,0x08,0x68, + 0x98,0x88,0x88,0x88,0x88,0x88,0x00,0xd8, +}; + +BMF_FontData BMF_font_scr14 = { + 0, -3, + 7, 11, + { + {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, -1}, + {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, 16, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 7, -1}, + {1, 9, -3, 0, 7, 0}, + {3, 4, -2, -5, 7, 9}, + {7, 9, 0, 0, 7, 13}, + {5, 10, -1, 1, 7, 22}, + {7, 9, 0, 0, 7, 32}, + {6, 9, 0, 0, 7, 41}, + {3, 4, -2, -5, 7, 50}, + {3, 11, -2, 1, 7, 54}, + {3, 11, -2, 1, 7, 65}, + {5, 6, -1, -2, 7, 76}, + {5, 5, -1, -2, 7, 82}, + {2, 4, -2, 2, 7, 87}, + {5, 1, -1, -4, 7, 91}, + {1, 2, -3, 0, 7, 92}, + {5, 10, -1, 0, 7, 94}, + {5, 9, -1, 0, 7, 104}, + {3, 9, -2, 0, 7, 113}, + {5, 9, -1, 0, 7, 122}, + {5, 9, -1, 0, 7, 131}, + {5, 9, -1, 0, 7, 140}, + {5, 9, -1, 0, 7, 149}, + {5, 9, -1, 0, 7, 158}, + {5, 9, -1, 0, 7, 167}, + {5, 9, -1, 0, 7, 176}, + {5, 9, -1, 0, 7, 185}, + {1, 6, -3, 0, 7, 194}, + {2, 8, -2, 1, 7, 200}, + {5, 9, -1, 0, 7, 208}, + {5, 3, -1, -3, 7, 217}, + {5, 9, -1, 0, 7, 220}, + {5, 9, -1, 0, 7, 229}, + {5, 9, -1, 0, 7, 238}, + {5, 9, -1, 0, 7, 247}, + {5, 9, -1, 0, 7, 256}, + {5, 9, -1, 0, 7, 265}, + {5, 9, -1, 0, 7, 274}, + {5, 9, -1, 0, 7, 283}, + {5, 9, -1, 0, 7, 292}, + {5, 9, -1, 0, 7, 301}, + {5, 9, -1, 0, 7, 310}, + {3, 9, -2, 0, 7, 319}, + {5, 9, -1, 0, 7, 328}, + {5, 9, -1, 0, 7, 337}, + {5, 9, -1, 0, 7, 346}, + {5, 9, -1, 0, 7, 355}, + {5, 9, -1, 0, 7, 364}, + {5, 9, -1, 0, 7, 373}, + {5, 9, -1, 0, 7, 382}, + {5, 11, -1, 2, 7, 391}, + {5, 9, -1, 0, 7, 402}, + {5, 9, -1, 0, 7, 411}, + {5, 9, -1, 0, 7, 420}, + {5, 9, -1, 0, 7, 429}, + {5, 9, -1, 0, 7, 438}, + {5, 9, -1, 0, 7, 447}, + {5, 9, -1, 0, 7, 456}, + {5, 9, -1, 0, 7, 465}, + {5, 9, -1, 0, 7, 474}, + {4, 11, -2, 1, 7, 483}, + {5, 10, -1, 0, 7, 494}, + {4, 11, -1, 1, 7, 504}, + {5, 3, -1, -6, 7, 515}, + {7, 1, 0, 2, 7, 518}, + {3, 4, -2, -5, 7, 519}, + {5, 7, -1, 0, 7, 523}, + {5, 9, -1, 0, 7, 530}, + {5, 7, -1, 0, 7, 539}, + {5, 9, -1, 0, 7, 546}, + {5, 7, -1, 0, 7, 555}, + {5, 9, -1, 0, 7, 562}, + {5, 10, -1, 3, 7, 571}, + {5, 9, -1, 0, 7, 581}, + {3, 9, -2, 0, 7, 590}, + {4, 12, -1, 3, 7, 599}, + {5, 9, -1, 0, 7, 611}, + {3, 9, -2, 0, 7, 620}, + {5, 7, -1, 0, 7, 629}, + {5, 7, -1, 0, 7, 636}, + {5, 7, -1, 0, 7, 643}, + {5, 10, -1, 3, 7, 650}, + {5, 10, -1, 3, 7, 660}, + {5, 7, -1, 0, 7, 670}, + {5, 7, -1, 0, 7, 677}, + {4, 9, -1, 0, 7, 684}, + {5, 7, -1, 0, 7, 693}, + {5, 7, -1, 0, 7, 700}, + {5, 7, -1, 0, 7, 707}, + {5, 7, -1, 0, 7, 714}, + {5, 10, -1, 3, 7, 721}, + {5, 7, -1, 0, 7, 731}, + {5, 12, -1, 2, 7, 738}, + {1, 12, -3, 2, 7, 750}, + {5, 12, -1, 2, 7, 762}, + {6, 3, 0, -3, 7, 774}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {1, 9, -3, 2, 7, 777}, + {5, 10, -1, 0, 7, 786}, + {5, 9, -1, 0, 7, 796}, + {5, 6, -1, -3, 7, 805}, + {5, 9, -1, 0, 7, 811}, + {1, 12, -3, 2, 7, 820}, + {5, 11, -1, 2, 7, 832}, + {5, 1, -1, -8, 7, 843}, + {7, 9, 0, 0, 7, 844}, + {5, 7, -1, -2, 7, 853}, + {7, 7, 0, 0, 7, 860}, + {5, 3, -1, -3, 7, 867}, + {4, 1, -1, -4, 7, 870}, + {7, 9, 0, 0, 7, 871}, + {3, 1, -2, -8, 7, 880}, + {4, 4, -1, -4, 7, 881}, + {5, 7, -1, 0, 7, 885}, + {3, 5, -2, -5, 7, 892}, + {3, 5, -2, -5, 7, 897}, + {2, 2, -3, -8, 7, 902}, + {6, 8, -1, 2, 7, 904}, + {6, 10, 0, 1, 7, 912}, + {1, 2, -3, -3, 7, 922}, + {3, 3, -2, 3, 7, 924}, + {3, 5, -2, -5, 7, 927}, + {5, 7, -1, -2, 7, 932}, + {7, 7, 0, 0, 7, 939}, + {7, 10, 0, 0, 7, 946}, + {6, 11, 0, 1, 7, 956}, + {7, 9, 0, -1, 7, 967}, + {5, 10, -1, 3, 7, 976}, + {5, 11, -1, 0, 7, 986}, + {5, 11, -1, 0, 7, 997}, + {5, 11, -1, 0, 7, 1008}, + {5, 11, -1, 0, 7, 1019}, + {5, 10, -1, 0, 7, 1030}, + {5, 11, -1, 0, 7, 1040}, + {6, 9, 0, 0, 7, 1051}, + {5, 12, -1, 3, 7, 1060}, + {5, 11, -1, 0, 7, 1072}, + {5, 11, -1, 0, 7, 1083}, + {5, 11, -1, 0, 7, 1094}, + {5, 10, -1, 0, 7, 1105}, + {3, 11, -2, 0, 7, 1115}, + {3, 11, -2, 0, 7, 1126}, + {3, 11, -2, 0, 7, 1137}, + {5, 10, -1, 0, 7, 1148}, + {6, 9, 0, 0, 7, 1158}, + {5, 11, -1, 0, 7, 1167}, + {5, 11, -1, 0, 7, 1178}, + {5, 11, -1, 0, 7, 1189}, + {5, 11, -1, 0, 7, 1200}, + {5, 11, -1, 0, 7, 1211}, + {5, 10, -1, 0, 7, 1222}, + {5, 5, -1, -1, 7, 1232}, + {7, 9, 0, 0, 7, 1237}, + {5, 11, -1, 0, 7, 1246}, + {5, 11, -1, 0, 7, 1257}, + {5, 11, -1, 0, 7, 1268}, + {5, 10, -1, 0, 7, 1279}, + {5, 11, -1, 0, 7, 1289}, + {6, 9, 0, 0, 7, 1300}, + {5, 9, -1, 0, 7, 1309}, + {5, 10, -1, 0, 7, 1318}, + {5, 10, -1, 0, 7, 1328}, + {5, 10, -1, 0, 7, 1338}, + {5, 10, -1, 0, 7, 1348}, + {5, 9, -1, 0, 7, 1358}, + {5, 11, -1, 0, 7, 1367}, + {7, 7, 0, 0, 7, 1378}, + {5, 10, -1, 3, 7, 1385}, + {5, 10, -1, 0, 7, 1395}, + {5, 10, -1, 0, 7, 1405}, + {5, 10, -1, 0, 7, 1415}, + {5, 9, -1, 0, 7, 1425}, + {3, 10, -2, 0, 7, 1434}, + {4, 10, -2, 0, 7, 1444}, + {3, 10, -2, 0, 7, 1454}, + {5, 9, -2, 0, 7, 1464}, + {5, 11, -1, 0, 7, 1473}, + {5, 10, -1, 0, 7, 1484}, + {5, 10, -1, 0, 7, 1494}, + {5, 10, -1, 0, 7, 1504}, + {5, 10, -1, 0, 7, 1514}, + {5, 10, -1, 0, 7, 1524}, + {5, 9, -1, 0, 7, 1534}, + {7, 7, 0, 0, 7, 1543}, + {7, 7, 0, 0, 7, 1550}, + {5, 10, -1, 0, 7, 1557}, + {5, 10, -1, 0, 7, 1567}, + {5, 10, -1, 0, 7, 1577}, + {5, 9, -1, 0, 7, 1587}, + {5, 13, -1, 3, 7, 1596}, + {6, 11, 0, 2, 7, 1609}, + {5, 12, -1, 3, 7, 1620}, + }, + bitmap_data +}; + +#endif + diff --git a/intern/bmfont/intern/BMF_font_scr15.cpp b/intern/bmfont/intern/BMF_font_scr15.cpp new file mode 100644 index 00000000000..c130fadbf52 --- /dev/null +++ b/intern/bmfont/intern/BMF_font_scr15.cpp @@ -0,0 +1,528 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BMF_FontData.h" +#include "BMF_Settings.h" + +#if BMF_INCLUDE_SCR15 + +static unsigned char bitmap_data[]= { + 0x80,0x80,0x00,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x90,0x90,0x90,0x90,0x48,0x48, + 0x48,0xfe,0x24,0x24,0x24,0x7f,0x12,0x12, + 0x20,0x70,0xa8,0xa8,0x28,0x30,0x60,0xa0, + 0xa8,0xa8,0x70,0x20,0x8c,0x52,0x52,0x2c, + 0x10,0x10,0x68,0x94,0x94,0x62,0x72,0x8c, + 0x84,0x8a,0x50,0x20,0x30,0x48,0x48,0x30, + 0x80,0x40,0x60,0x60,0x10,0x20,0x40,0x40, + 0x80,0x80,0x80,0x80,0x80,0x40,0x40,0x20, + 0x10,0x80,0x40,0x20,0x20,0x10,0x10,0x10, + 0x10,0x10,0x20,0x20,0x40,0x80,0x20,0xa8, + 0x70,0x70,0xa8,0x20,0x10,0x10,0x10,0xfe, + 0x10,0x10,0x10,0x80,0x40,0x20,0x60,0x60, + 0xfc,0xc0,0xc0,0x80,0x80,0x40,0x40,0x20, + 0x20,0x10,0x10,0x08,0x08,0x04,0x04,0x78, + 0x84,0x84,0xc4,0xa4,0x94,0x8c,0x84,0x84, + 0x78,0xe0,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0xc0,0x40,0xfc,0x80,0x40,0x20,0x10, + 0x08,0x04,0x84,0x84,0x78,0x78,0x84,0x04, + 0x04,0x04,0x38,0x04,0x04,0x84,0x78,0x08, + 0x08,0x08,0xfc,0x88,0x48,0x48,0x28,0x18, + 0x08,0x78,0x84,0x04,0x04,0x04,0xf8,0x80, + 0x80,0x80,0xfc,0x78,0x84,0x84,0x84,0x84, + 0xf8,0x80,0x80,0x84,0x78,0x20,0x20,0x20, + 0x10,0x10,0x08,0x08,0x04,0x04,0xfc,0x78, + 0x84,0x84,0x84,0x84,0x78,0x84,0x84,0x84, + 0x78,0x78,0x84,0x04,0x04,0x7c,0x84,0x84, + 0x84,0x84,0x78,0xc0,0xc0,0x00,0x00,0x00, + 0xc0,0xc0,0x80,0x40,0xc0,0xc0,0x00,0x00, + 0x00,0xc0,0xc0,0x04,0x08,0x10,0x20,0x40, + 0x80,0x40,0x20,0x10,0x08,0x04,0xfc,0x00, + 0x00,0xfc,0x80,0x40,0x20,0x10,0x08,0x04, + 0x08,0x10,0x20,0x40,0x80,0x10,0x10,0x00, + 0x10,0x10,0x08,0x04,0x84,0x84,0x78,0x38, + 0x44,0x80,0x98,0xa4,0xa4,0x9c,0x84,0x48, + 0x30,0x84,0x84,0xfc,0x84,0x48,0x48,0x48, + 0x30,0x30,0x30,0xf8,0x84,0x84,0x84,0x84, + 0xf8,0x84,0x84,0x84,0xf8,0x78,0x84,0x84, + 0x80,0x80,0x80,0x80,0x84,0x84,0x78,0xf0, + 0x88,0x84,0x84,0x84,0x84,0x84,0x84,0x88, + 0xf0,0xfc,0x80,0x80,0x80,0x80,0xf8,0x80, + 0x80,0x80,0xfc,0x80,0x80,0x80,0x80,0x80, + 0xf8,0x80,0x80,0x80,0xfc,0x74,0x8c,0x84, + 0x84,0x84,0x9c,0x80,0x80,0x84,0x78,0x84, + 0x84,0x84,0x84,0x84,0xfc,0x84,0x84,0x84, + 0x84,0xe0,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0xe0,0x70,0x88,0x88,0x08,0x08, + 0x08,0x08,0x08,0x08,0x08,0x84,0x84,0x88, + 0x90,0xa0,0xc0,0xa0,0x90,0x88,0x84,0xfc, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x82,0x82,0x92,0x92,0xaa,0xaa,0xc6, + 0xc6,0x82,0x82,0x84,0x8c,0x8c,0x94,0x94, + 0xa4,0xa4,0xc4,0xc4,0x84,0x78,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x80, + 0x80,0x80,0x80,0xf8,0x84,0x84,0x84,0x84, + 0xf8,0x04,0x08,0x10,0x78,0xa4,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x78,0x84,0x84, + 0x88,0x90,0xf8,0x84,0x84,0x84,0x84,0xf8, + 0x78,0x84,0x84,0x04,0x18,0x60,0x80,0x84, + 0x84,0x78,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0xfe,0x78,0x84,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x30,0x30, + 0x30,0x48,0x48,0x48,0x84,0x84,0x84,0x84, + 0x44,0x44,0x44,0xaa,0xaa,0xaa,0x92,0x92, + 0x92,0x82,0x84,0x84,0x48,0x48,0x30,0x30, + 0x48,0x48,0x84,0x84,0x10,0x10,0x10,0x10, + 0x10,0x28,0x44,0x44,0x82,0x82,0xfc,0x80, + 0x40,0x40,0x20,0x10,0x08,0x08,0x04,0xfc, + 0xf0,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0xf0,0x04,0x04,0x08, + 0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x80, + 0x80,0xf0,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0xf0,0x88,0x50, + 0x20,0xff,0x20,0x40,0xc0,0xc0,0x74,0x88, + 0x88,0x78,0x08,0x88,0x70,0xb8,0xc4,0x84, + 0x84,0x84,0xc4,0xb8,0x80,0x80,0x80,0x78, + 0x84,0x80,0x80,0x80,0x84,0x78,0x74,0x8c, + 0x84,0x84,0x84,0x8c,0x74,0x04,0x04,0x04, + 0x78,0x84,0x80,0xfc,0x84,0x84,0x78,0x20, + 0x20,0x20,0x20,0x20,0x20,0xf8,0x20,0x20, + 0x1c,0x78,0x84,0x04,0x04,0x74,0x8c,0x84, + 0x84,0x84,0x8c,0x74,0x84,0x84,0x84,0x84, + 0x84,0xc4,0xb8,0x80,0x80,0x80,0x20,0x20, + 0x20,0x20,0x20,0x20,0xe0,0x00,0x20,0x20, + 0x70,0x88,0x08,0x08,0x08,0x08,0x08,0x08, + 0x08,0x08,0x38,0x00,0x08,0x08,0x84,0x88, + 0x90,0xe0,0xa0,0x90,0x88,0x80,0x80,0x80, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 0x20,0xe0,0x92,0x92,0x92,0x92,0x92,0x92, + 0xec,0x84,0x84,0x84,0x84,0x84,0xc4,0xb8, + 0x78,0x84,0x84,0x84,0x84,0x84,0x78,0x80, + 0x80,0x80,0x80,0xb8,0xc4,0x84,0x84,0x84, + 0xc4,0xb8,0x04,0x04,0x04,0x04,0x74,0x8c, + 0x84,0x84,0x84,0x8c,0x74,0x80,0x80,0x80, + 0x80,0x80,0xc4,0xb8,0x78,0x84,0x04,0x78, + 0x80,0x84,0x78,0x1c,0x20,0x20,0x20,0x20, + 0x20,0xf8,0x20,0x20,0x74,0x8c,0x84,0x84, + 0x84,0x84,0x84,0x30,0x30,0x48,0x48,0x84, + 0x84,0x84,0x6c,0x92,0x92,0x92,0x92,0x82, + 0x82,0x84,0x84,0x48,0x30,0x48,0x84,0x84, + 0x78,0x84,0x04,0x04,0x74,0x8c,0x84,0x84, + 0x84,0x84,0x84,0xfc,0x80,0x40,0x20,0x10, + 0x08,0xfc,0x1c,0x20,0x20,0x20,0x20,0x20, + 0xc0,0x20,0x20,0x20,0x20,0x20,0x1c,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0xe0,0x10,0x10, + 0x10,0x10,0x10,0x0c,0x10,0x10,0x10,0x10, + 0x10,0xe0,0x98,0xb4,0x64,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x00,0x80,0x80,0x20, + 0x20,0x70,0x88,0x80,0x80,0x88,0x70,0x20, + 0x20,0xb8,0x44,0x40,0x40,0xf0,0x40,0x40, + 0x40,0x48,0x30,0x84,0x78,0x84,0x84,0x84, + 0x78,0x84,0x38,0x10,0x7c,0x10,0x7c,0x28, + 0x44,0x44,0x82,0x82,0x80,0x80,0x80,0x80, + 0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80, + 0x80,0x80,0x78,0x84,0x04,0x18,0x24,0x44, + 0x84,0x88,0x90,0x60,0x80,0x84,0x78,0xd8, + 0x38,0x44,0x92,0xaa,0xa2,0xaa,0x92,0x44, + 0x38,0xf8,0x00,0x68,0x90,0x70,0x10,0x60, + 0x09,0x12,0x24,0x48,0x90,0x48,0x24,0x12, + 0x09,0x04,0x04,0xfc,0xfc,0x38,0x44,0xaa, + 0xaa,0xb2,0xaa,0xb2,0x44,0x38,0xf0,0x60, + 0x90,0x90,0x60,0xfe,0x00,0x10,0x10,0x10, + 0xfe,0x10,0x10,0x10,0xf0,0x40,0x20,0x90, + 0x60,0xe0,0x10,0x60,0x10,0xe0,0x80,0x40, + 0x80,0x80,0x80,0xb4,0xc8,0x88,0x88,0x88, + 0x88,0x88,0x24,0x24,0x24,0x24,0x24,0x24, + 0x64,0xa4,0xa4,0xa4,0xa4,0x7e,0xc0,0xc0, + 0x20,0x40,0xe0,0x40,0x40,0xc0,0x40,0xf8, + 0x00,0x70,0x88,0x88,0x88,0x70,0x90,0x48, + 0x24,0x12,0x09,0x12,0x24,0x48,0x90,0x04, + 0x9e,0x54,0x2c,0x14,0xe8,0x44,0x42,0xc0, + 0x40,0x1e,0x08,0x84,0x52,0x2c,0x10,0xe8, + 0x44,0x42,0xc0,0x40,0x04,0x9e,0x54,0x2c, + 0xd4,0x28,0x44,0x22,0xc0,0x78,0x84,0x84, + 0x80,0x40,0x20,0x20,0x00,0x20,0x20,0x84, + 0x84,0xfc,0x84,0x48,0x48,0x30,0x30,0x00, + 0x20,0x40,0x84,0x84,0xfc,0x84,0x48,0x48, + 0x30,0x30,0x00,0x10,0x08,0x84,0x84,0xfc, + 0x84,0x48,0x48,0x30,0x30,0x00,0x48,0x30, + 0x84,0x84,0xfc,0x84,0x48,0x48,0x30,0x30, + 0x00,0x98,0x64,0x84,0x84,0xfc,0x84,0x48, + 0x48,0x30,0x30,0x00,0x6c,0x84,0x84,0xfc, + 0x84,0x48,0x48,0x30,0x30,0x30,0x48,0x30, + 0x9e,0x90,0x90,0xf0,0x90,0x5c,0x50,0x50, + 0x30,0x1e,0x30,0x08,0x10,0x78,0x84,0x84, + 0x80,0x80,0x80,0x80,0x84,0x84,0x78,0xfc, + 0x80,0x80,0x80,0xf8,0x80,0x80,0xfc,0x00, + 0x20,0x40,0xfc,0x80,0x80,0x80,0xf8,0x80, + 0x80,0xfc,0x00,0x10,0x08,0xfc,0x80,0x80, + 0x80,0xf8,0x80,0x80,0xfc,0x00,0x48,0x30, + 0xfc,0x80,0x80,0x80,0xf8,0x80,0x80,0xfc, + 0x00,0x6c,0xe0,0x40,0x40,0x40,0x40,0x40, + 0x40,0xe0,0x00,0x40,0x80,0xe0,0x40,0x40, + 0x40,0x40,0x40,0x40,0xe0,0x00,0x40,0x20, + 0xe0,0x40,0x40,0x40,0x40,0x40,0x40,0xe0, + 0x00,0x90,0x60,0x70,0x20,0x20,0x20,0x20, + 0x20,0x20,0x70,0x00,0xd8,0x78,0x44,0x42, + 0x42,0x42,0xf2,0x42,0x42,0x44,0x78,0x84, + 0x8c,0x94,0x94,0xa4,0xa4,0xc4,0x84,0x00, + 0x98,0x64,0x78,0x84,0x84,0x84,0x84,0x84, + 0x84,0x78,0x00,0x20,0x40,0x78,0x84,0x84, + 0x84,0x84,0x84,0x84,0x78,0x00,0x10,0x08, + 0x78,0x84,0x84,0x84,0x84,0x84,0x84,0x78, + 0x00,0x48,0x30,0x78,0x84,0x84,0x84,0x84, + 0x84,0x84,0x78,0x00,0x98,0x64,0x78,0x84, + 0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x6c, + 0x84,0x48,0x30,0x30,0x48,0x84,0xbc,0x42, + 0x62,0x52,0x52,0x4a,0x4a,0x46,0x42,0x3d, + 0x78,0x84,0x84,0x84,0x84,0x84,0x84,0x84, + 0x00,0x20,0x40,0x78,0x84,0x84,0x84,0x84, + 0x84,0x84,0x84,0x00,0x10,0x08,0x78,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x00,0x48, + 0x30,0x78,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x00,0x6c,0x10,0x10,0x10,0x10,0x28, + 0x44,0x44,0x82,0x00,0x10,0x08,0xe0,0x40, + 0x7c,0x42,0x42,0x42,0x42,0x7c,0x40,0xe0, + 0x98,0xa4,0x84,0x84,0x84,0x88,0xb0,0x88, + 0x88,0x70,0x74,0x88,0x88,0x78,0x08,0x88, + 0x70,0x00,0x20,0x40,0x74,0x88,0x88,0x78, + 0x08,0x88,0x70,0x00,0x20,0x10,0x74,0x88, + 0x88,0x78,0x08,0x88,0x70,0x00,0x48,0x30, + 0x74,0x88,0x88,0x78,0x08,0x88,0x70,0x00, + 0x98,0x64,0x74,0x88,0x88,0x78,0x08,0x88, + 0x70,0x00,0xd8,0x74,0x88,0x88,0x78,0x08, + 0x88,0x70,0x00,0x30,0x48,0x30,0x6c,0x92, + 0x90,0x7e,0x12,0x92,0x6c,0x30,0x08,0x10, + 0x78,0x84,0x80,0x80,0x80,0x84,0x78,0x78, + 0x84,0x80,0xfc,0x84,0x84,0x78,0x00,0x20, + 0x40,0x78,0x84,0x80,0xfc,0x84,0x84,0x78, + 0x00,0x10,0x08,0x78,0x84,0x80,0xfc,0x84, + 0x84,0x78,0x00,0x48,0x30,0x78,0x84,0x80, + 0xfc,0x84,0x84,0x78,0x00,0x6c,0x20,0x20, + 0x20,0x20,0x20,0x20,0xe0,0x00,0x40,0x80, + 0x20,0x20,0x20,0x20,0x20,0x20,0xe0,0x00, + 0x40,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 0xe0,0x00,0x90,0x60,0x10,0x10,0x10,0x10, + 0x10,0x10,0x70,0x00,0xd8,0x78,0x84,0x84, + 0x84,0x84,0x84,0x7c,0x04,0xc8,0x30,0xc8, + 0x84,0x84,0x84,0x84,0x84,0xc4,0xb8,0x00, + 0x98,0x64,0x78,0x84,0x84,0x84,0x84,0x84, + 0x78,0x00,0x20,0x40,0x78,0x84,0x84,0x84, + 0x84,0x84,0x78,0x00,0x10,0x08,0x78,0x84, + 0x84,0x84,0x84,0x84,0x78,0x00,0x48,0x30, + 0x78,0x84,0x84,0x84,0x84,0x84,0x78,0x00, + 0x98,0x64,0x78,0x84,0x84,0x84,0x84,0x84, + 0x78,0x00,0x00,0x6c,0x30,0x00,0x00,0xfc, + 0x00,0x00,0x30,0xbc,0x62,0x52,0x4a,0x46, + 0x42,0x3d,0x74,0x8c,0x84,0x84,0x84,0x84, + 0x84,0x00,0x20,0x40,0x74,0x8c,0x84,0x84, + 0x84,0x84,0x84,0x00,0x20,0x10,0x74,0x8c, + 0x84,0x84,0x84,0x84,0x84,0x00,0x48,0x30, + 0x74,0x8c,0x84,0x84,0x84,0x84,0x84,0x00, + 0x00,0x6c,0x78,0x84,0x04,0x04,0x74,0x8c, + 0x84,0x84,0x84,0x84,0x84,0x00,0x20,0x10, + 0xe0,0x40,0x40,0x5c,0x62,0x42,0x42,0x42, + 0x62,0x5c,0x40,0x40,0xc0,0x78,0x84,0x04, + 0x04,0x74,0x8c,0x84,0x84,0x84,0x84,0x84, + 0x00,0x00,0x6c, +}; + +BMF_FontData BMF_font_scr15 = { + 0, -4, + 8, 11, + { + {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, -1}, + {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, 20, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 8, -1}, + {1, 10, -3, 0, 8, 0}, + {4, 4, -2, -6, 8, 10}, + {8, 10, 0, 0, 8, 14}, + {5, 12, -1, 1, 8, 24}, + {7, 10, 0, 0, 8, 36}, + {7, 10, 0, 0, 8, 46}, + {3, 4, -2, -6, 8, 56}, + {4, 13, -2, 2, 8, 60}, + {4, 13, -2, 2, 8, 73}, + {5, 6, -1, -2, 8, 86}, + {7, 7, 0, -1, 8, 92}, + {3, 5, -2, 3, 8, 99}, + {6, 1, -1, -4, 8, 104}, + {2, 2, -3, 0, 8, 105}, + {6, 12, -1, 1, 8, 107}, + {6, 10, -1, 0, 8, 119}, + {3, 10, -3, 0, 8, 129}, + {6, 10, -1, 0, 8, 139}, + {6, 10, -1, 0, 8, 149}, + {6, 10, -1, 0, 8, 159}, + {6, 10, -1, 0, 8, 169}, + {6, 10, -1, 0, 8, 179}, + {6, 10, -1, 0, 8, 189}, + {6, 10, -1, 0, 8, 199}, + {6, 10, -1, 0, 8, 209}, + {2, 7, -3, 0, 8, 219}, + {2, 9, -3, 2, 8, 226}, + {6, 11, -1, 1, 8, 235}, + {6, 4, -1, -3, 8, 246}, + {6, 11, -1, 1, 8, 250}, + {6, 10, -1, 0, 8, 261}, + {6, 10, -1, 0, 8, 271}, + {6, 10, -1, 0, 8, 281}, + {6, 10, -1, 0, 8, 291}, + {6, 10, -1, 0, 8, 301}, + {6, 10, -1, 0, 8, 311}, + {6, 10, -1, 0, 8, 321}, + {6, 10, -1, 0, 8, 331}, + {6, 10, -1, 0, 8, 341}, + {6, 10, -1, 0, 8, 351}, + {3, 10, -2, 0, 8, 361}, + {5, 10, -1, 0, 8, 371}, + {6, 10, -1, 0, 8, 381}, + {6, 10, -1, 0, 8, 391}, + {7, 10, 0, 0, 8, 401}, + {6, 10, -1, 0, 8, 411}, + {6, 10, -1, 0, 8, 421}, + {6, 10, -1, 0, 8, 431}, + {6, 13, -1, 3, 8, 441}, + {6, 10, -1, 0, 8, 454}, + {6, 10, -1, 0, 8, 464}, + {7, 10, 0, 0, 8, 474}, + {6, 10, -1, 0, 8, 484}, + {6, 10, -1, 0, 8, 494}, + {7, 10, 0, 0, 8, 504}, + {6, 10, -1, 0, 8, 514}, + {7, 10, 0, 0, 8, 524}, + {6, 10, -1, 0, 8, 534}, + {4, 13, -2, 2, 8, 544}, + {6, 12, -1, 1, 8, 557}, + {4, 13, -2, 2, 8, 569}, + {5, 3, -1, -6, 8, 582}, + {8, 1, 0, 3, 8, 585}, + {3, 4, -2, -6, 8, 586}, + {6, 7, -1, 0, 8, 590}, + {6, 10, -1, 0, 8, 597}, + {6, 7, -1, 0, 8, 607}, + {6, 10, -1, 0, 8, 614}, + {6, 7, -1, 0, 8, 624}, + {6, 10, -1, 0, 8, 631}, + {6, 11, -1, 4, 8, 641}, + {6, 10, -1, 0, 8, 652}, + {3, 10, -2, 0, 8, 662}, + {5, 14, -1, 4, 8, 672}, + {6, 10, -1, 0, 8, 686}, + {3, 10, -2, 0, 8, 696}, + {7, 7, 0, 0, 8, 706}, + {6, 7, -1, 0, 8, 713}, + {6, 7, -1, 0, 8, 720}, + {6, 11, -1, 4, 8, 727}, + {6, 11, -1, 4, 8, 738}, + {6, 7, -1, 0, 8, 749}, + {6, 7, -1, 0, 8, 756}, + {6, 9, -1, 0, 8, 763}, + {6, 7, -1, 0, 8, 772}, + {6, 7, -1, 0, 8, 779}, + {7, 7, 0, 0, 8, 786}, + {6, 7, -1, 0, 8, 793}, + {6, 11, -1, 4, 8, 800}, + {6, 7, -1, 0, 8, 811}, + {6, 13, -1, 2, 8, 818}, + {1, 14, -3, 3, 8, 831}, + {6, 13, -1, 2, 8, 845}, + {6, 3, -1, -3, 8, 858}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {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, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 8, -1}, + {1, 10, -3, 3, 8, 861}, + {5, 10, -1, 0, 8, 871}, + {6, 10, -1, 0, 8, 881}, + {6, 7, -1, -2, 8, 891}, + {7, 10, 0, 0, 8, 898}, + {1, 14, -3, 3, 8, 908}, + {6, 13, -1, 3, 8, 922}, + {5, 1, -1, -9, 8, 935}, + {7, 9, 0, 0, 8, 936}, + {5, 7, -1, -3, 8, 945}, + {8, 9, 0, 0, 8, 952}, + {6, 3, -1, -3, 8, 961}, + {6, 1, -1, -4, 8, 964}, + {7, 9, 0, 0, 8, 965}, + {4, 1, -2, -9, 8, 974}, + {4, 4, -2, -4, 8, 975}, + {7, 9, 0, 0, 8, 979}, + {4, 5, -2, -5, 8, 988}, + {4, 5, -2, -5, 8, 993}, + {2, 2, -3, -9, 8, 998}, + {6, 10, -1, 3, 8, 1000}, + {7, 12, 0, 2, 8, 1010}, + {2, 1, -3, -4, 8, 1022}, + {3, 3, -3, 3, 8, 1023}, + {3, 5, -3, -5, 8, 1026}, + {5, 7, -1, -3, 8, 1031}, + {8, 9, 0, 0, 8, 1038}, + {7, 10, 0, 0, 8, 1047}, + {7, 11, 0, 1, 8, 1057}, + {7, 9, 0, -1, 8, 1068}, + {6, 10, -1, 2, 8, 1077}, + {6, 11, -1, 0, 8, 1087}, + {6, 11, -1, 0, 8, 1098}, + {6, 11, -1, 0, 8, 1109}, + {6, 11, -1, 0, 8, 1120}, + {6, 10, -1, 0, 8, 1131}, + {6, 11, -1, 0, 8, 1141}, + {7, 10, 0, 0, 8, 1152}, + {6, 13, -1, 3, 8, 1162}, + {6, 11, -1, 0, 8, 1175}, + {6, 11, -1, 0, 8, 1186}, + {6, 11, -1, 0, 8, 1197}, + {6, 10, -1, 0, 8, 1208}, + {3, 11, -2, 0, 8, 1218}, + {3, 11, -2, 0, 8, 1229}, + {4, 11, -2, 0, 8, 1240}, + {5, 10, -1, 0, 8, 1251}, + {7, 10, 0, 0, 8, 1261}, + {6, 11, -1, 0, 8, 1271}, + {6, 11, -1, 0, 8, 1282}, + {6, 11, -1, 0, 8, 1293}, + {6, 11, -1, 0, 8, 1304}, + {6, 11, -1, 0, 8, 1315}, + {6, 10, -1, 0, 8, 1326}, + {6, 6, -1, -1, 8, 1336}, + {8, 10, 0, 0, 8, 1342}, + {6, 11, -1, 0, 8, 1352}, + {6, 11, -1, 0, 8, 1363}, + {6, 11, -1, 0, 8, 1374}, + {6, 10, -1, 0, 8, 1385}, + {7, 11, 0, 0, 8, 1395}, + {7, 10, 0, 0, 8, 1406}, + {6, 10, -1, 0, 8, 1416}, + {6, 10, -1, 0, 8, 1426}, + {6, 10, -1, 0, 8, 1436}, + {6, 10, -1, 0, 8, 1446}, + {6, 10, -1, 0, 8, 1456}, + {6, 9, -1, 0, 8, 1466}, + {6, 11, -1, 0, 8, 1475}, + {7, 7, 0, 0, 8, 1486}, + {6, 10, -1, 3, 8, 1493}, + {6, 10, -1, 0, 8, 1503}, + {6, 10, -1, 0, 8, 1513}, + {6, 10, -1, 0, 8, 1523}, + {6, 9, -1, 0, 8, 1533}, + {3, 10, -2, 0, 8, 1542}, + {3, 10, -2, 0, 8, 1552}, + {4, 10, -2, 0, 8, 1562}, + {5, 9, -1, 0, 8, 1572}, + {6, 11, -1, 0, 8, 1581}, + {6, 10, -1, 0, 8, 1592}, + {6, 10, -1, 0, 8, 1602}, + {6, 10, -1, 0, 8, 1612}, + {6, 10, -1, 0, 8, 1622}, + {6, 10, -1, 0, 8, 1632}, + {6, 10, -1, 0, 8, 1642}, + {6, 7, -1, 0, 8, 1652}, + {8, 7, 0, 0, 8, 1659}, + {6, 10, -1, 0, 8, 1666}, + {6, 10, -1, 0, 8, 1676}, + {6, 10, -1, 0, 8, 1686}, + {6, 10, -1, 0, 8, 1696}, + {6, 14, -1, 4, 8, 1706}, + {7, 13, 0, 3, 8, 1720}, + {6, 14, -1, 4, 8, 1733}, + }, + bitmap_data +}; + +#endif + diff --git a/intern/bmfont/intern/Makefile b/intern/bmfont/intern/Makefile new file mode 100644 index 00000000000..cd02eaa31bd --- /dev/null +++ b/intern/bmfont/intern/Makefile @@ -0,0 +1,44 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# bmfont intern Makefile +# + +LIBNAME = bmfont +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I. +CPPFLAGS += -I.. +CPPFLAGS += -I$(OPENGL_HEADERS) + diff --git a/intern/bmfont/make/msvc_6_0/bmfont.dsp b/intern/bmfont/make/msvc_6_0/bmfont.dsp new file mode 100644 index 00000000000..a9d2d9722e1 --- /dev/null +++ b/intern/bmfont/make/msvc_6_0/bmfont.dsp @@ -0,0 +1,176 @@ +# Microsoft Developer Studio Project File - Name="bmfont" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=bmfont - 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 "bmfont.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 "bmfont.mak" CFG="bmfont - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "bmfont - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "bmfont - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "bmfont - 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 "..\..\..\..\obj\windows\intern\bmfont" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\bmfont" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../.." /I "../../intern" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# 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:"..\..\..\..\obj\windows\intern\bmfont\libbmfont.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Desc=Copying BMFONT files library (release target) to lib tree. +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\bmfont\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\bmfont\*.lib ..\..\..\..\..\lib\windows\bmfont\lib\*.a ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "bmfont - 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 "..\..\..\..\obj\windows\intern\bmfont\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\bmfont\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../.." /I "../../intern" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# 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:"..\..\..\..\obj\windows\intern\bmfont\debug\libbmfont.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Desc=Copying BMFONT files library (debug target) to lib tree. +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\bmfont\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\bmfont\debug\*.lib ..\..\..\..\..\lib\windows\bmfont\lib\debug\*.a ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "bmfont - Win32 Release" +# Name "bmfont - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\intern\BMF_Api.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BMF_BitmapFont.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BMF_font_helv10.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BMF_font_helv12.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BMF_font_helvb10.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BMF_font_helvb12.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BMF_font_helvb14.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BMF_font_helvb8.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BMF_font_scr12.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BMF_font_scr14.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BMF_font_scr15.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Group "intern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\intern\BMF_BitmapFont.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BMF_FontData.h +# End Source File +# End Group +# Begin Group "extern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\BMF_Api.h +# End Source File +# Begin Source File + +SOURCE=..\..\BMF_Fonts.h +# End Source File +# Begin Source File + +SOURCE=..\..\BMF_Settings.h +# End Source File +# End Group +# End Group +# End Target +# End Project diff --git a/intern/bmfont/make/msvc_6_0/bmfont.dsw b/intern/bmfont/make/msvc_6_0/bmfont.dsw new file mode 100644 index 00000000000..d2e2f94cd0b --- /dev/null +++ b/intern/bmfont/make/msvc_6_0/bmfont.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "bmfont"=.\bmfont.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/bmfont/make/msvc_7_0/bmfont.sln b/intern/bmfont/make/msvc_7_0/bmfont.sln new file mode 100644 index 00000000000..7f1979a8273 --- /dev/null +++ b/intern/bmfont/make/msvc_7_0/bmfont.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bmfont", "bmfont.vcproj", "{8CDFE9DC-F28C-4E1F-9389-3066BB0AB09F}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {8CDFE9DC-F28C-4E1F-9389-3066BB0AB09F}.Debug.ActiveCfg = Debug|Win32 + {8CDFE9DC-F28C-4E1F-9389-3066BB0AB09F}.Debug.Build.0 = Debug|Win32 + {8CDFE9DC-F28C-4E1F-9389-3066BB0AB09F}.Release.ActiveCfg = Release|Win32 + {8CDFE9DC-F28C-4E1F-9389-3066BB0AB09F}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/intern/bmfont/make/msvc_7_0/bmfont.vcproj b/intern/bmfont/make/msvc_7_0/bmfont.vcproj new file mode 100644 index 00000000000..089130bc5e0 --- /dev/null +++ b/intern/bmfont/make/msvc_7_0/bmfont.vcproj @@ -0,0 +1,314 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/bmfont/test/Makefile b/intern/bmfont/test/Makefile new file mode 100644 index 00000000000..f7e0f927722 --- /dev/null +++ b/intern/bmfont/test/Makefile @@ -0,0 +1,63 @@ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# Test the bmfont module +# + +LIBNAME = bmfont +SOURCEDIR = intern/$(LIBNAME)/test +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = simpletest + +include nan_subdirs.mk +include nan_compile.mk +include nan_link.mk + +TESTLIBS = $(OCGDIR)/intern/$(LIBNAME)/$(DEBUG_DIR)lib$(LIBNAME).a +TESTLIBS += $(NAN_STRING)/lib/$(DEBUG_DIR)libstring.a +TESTLIBS += $(LCGDIR)/ghost/$(DEBUG_DIR)lib/libghost.a + + +ifeq ($(OS),$(findstring $(OS), "beos darwin linux freebsd openbsd")) + TESTLIBS += -L/usr/X11R6/lib -lglut -pthread +endif + +ifeq ($(OS),$(findstring $(OS), "solaris")) + TESTLIBS += -L/usr/openwin/lib -lglut -lX11 -lGL -lGLU -lXmu +endif + + +all debug:: + @echo "****> linking $@ in $(SOURCEDIR)" + $(CCC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)BMF_Test $(DIR)/BMF_Test.o $(TESTLIBS) + +clean:: + $(RM) $(DIR)/BMF_Test $(DIR)/debug/BMF_Test + +test:: $(DIR)/BMF_Test + $(DIR)/BMF_Test $(NAN_TEST_VERBOSITY) + diff --git a/intern/bmfont/test/make/msvc_6_0/BMF_Test.dsp b/intern/bmfont/test/make/msvc_6_0/BMF_Test.dsp new file mode 100644 index 00000000000..13e6e65f706 --- /dev/null +++ b/intern/bmfont/test/make/msvc_6_0/BMF_Test.dsp @@ -0,0 +1,109 @@ +# Microsoft Developer Studio Project File - Name="BMF_Test" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=BMF_Test - 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 "BMF_Test.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 "BMF_Test.mak" CFG="BMF_Test - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BMF_Test - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "BMF_Test - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BMF_Test - 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 "../../../../../../obj/windows/intern/BMF_bmfont/test" +# PROP Intermediate_Dir "../../../../../../obj/windows/intern/BMF_bmfont/test" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "../../../" /I "../../../../../lib/windows/string/include" /I "../../../../../lib/windows/ghost/include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libstring.a libghost.a glu32.lib opengl32.lib user32.lib gdi32.lib /nologo /subsystem:console /machine:I386 /libpath:"../../../../../lib/windows/string/lib" /libpath:"../../../../../lib/windows/ghost/lib" + +!ELSEIF "$(CFG)" == "BMF_Test - 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 "../../../../../../obj/windows/intern/BMF_bmfont/test/debug" +# PROP Intermediate_Dir "../../../../../../obj/windows/intern/BMF_bmfont/test/debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../../" /I "../../../../../lib/windows/string/include" /I "../../../../../lib/windows/ghost/include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 glu32.lib opengl32.lib libstring.a libghost.a user32.lib gdi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"../../../../../lib/windows/string/lib" /libpath:"../../../../../lib/windows/ghost/lib" + +!ENDIF + +# Begin Target + +# Name "BMF_Test - Win32 Release" +# Name "BMF_Test - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\intern\BMF_glut_helb8.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\intern\BMF_glut_helb8.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\BMF_Test.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/intern/bmfont/test/make/msvc_6_0/BMF_Test.dsw b/intern/bmfont/test/make/msvc_6_0/BMF_Test.dsw new file mode 100644 index 00000000000..5baacb9adf7 --- /dev/null +++ b/intern/bmfont/test/make/msvc_6_0/BMF_Test.dsw @@ -0,0 +1,44 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "BMF_Test"=.\BMF_Test.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name BMF_bmfont + End Project Dependency +}}} + +############################################################################### + +Project: "BMF_bmfont"=..\..\..\make\msvc_6_0\BMF_bmfont.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/bmfont/test/simpletest/BMF_Test.cpp b/intern/bmfont/test/simpletest/BMF_Test.cpp new file mode 100644 index 00000000000..00f7bc30f45 --- /dev/null +++ b/intern/bmfont/test/simpletest/BMF_Test.cpp @@ -0,0 +1,229 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * Simple test file for the bitmap font library using GHOST. + * @author Maarten Gribnau + * @date November 15, 2001 + */ + +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define FALSE 0 +#define TRUE 1 + +#if defined(WIN32) || defined(__APPLE__) +#ifdef WIN32 +#include +#include +#else // WIN32 +// __APPLE__ is defined +#include +#endif // WIN32 +#else // defined(WIN32) || defined(__APPLE__) +#include +#endif // defined(WIN32) || defined(__APPLE__) + + +#include "STR_String.h" +#include "GHOST_Rect.h" + +#include "GHOST_ISystem.h" +#include "GHOST_IEvent.h" +#include "GHOST_IEventConsumer.h" + +#include "BMF_Api.h" + +static class Application* fApp; +static GHOST_ISystem* fSystem = 0; + + +static void drawGL() +{ + GLint x = 10, y = 10; + + ::glRasterPos2i(x, y); + BMF_Font *font = BMF_GetFont(BMF_kHelvetica10); + BMF_DrawString(font, "Helvetica 10 point"); + y += 14; + ::glRasterPos2i(x, y); + font = BMF_GetFont(BMF_kHelvetica12); + BMF_DrawString(font, "Helvetica 12 point"); + y += 16; + ::glRasterPos2i(x, y); + font = BMF_GetFont(BMF_kHelveticaBold8); + BMF_DrawString(font, "Helvetica Bold 8 point"); + y += 12; + ::glRasterPos2i(x, y); + font = BMF_GetFont(BMF_kHelveticaBold10); + BMF_DrawString(font, "Helvetica Bold 10 point"); + y += 14; + ::glRasterPos2i(x, y); + font = BMF_GetFont(BMF_kHelveticaBold12); + BMF_DrawString(font, "Helvetica Bold 12 point"); + y += 16; + ::glRasterPos2i(x, y); + font = BMF_GetFont(BMF_kHelveticaBold14); + BMF_DrawString(font, "Helvetica Bold 14 point"); + y += 18; + ::glRasterPos2i(x, y); + font = BMF_GetFont(BMF_kScreen12); + BMF_DrawString(font, "Screen 12 point"); + y += 16; + ::glRasterPos2i(x, y); + font = BMF_GetFont(BMF_kScreen14); + BMF_DrawString(font, "Screen 14 point"); + y += 18; + ::glRasterPos2i(x, y); + font = BMF_GetFont(BMF_kScreen15); + BMF_DrawString(font, "Screen 15 point"); +} + + +static void setViewPortGL(GHOST_IWindow* window) +{ + window->activateDrawingContext(); + GHOST_Rect bnds; + window->getClientBounds(bnds); + + ::glViewport(0, 0, bnds.getWidth(), bnds.getHeight()); + + ::glMatrixMode(GL_PROJECTION); + ::glLoadIdentity(); + ::glOrtho(0, bnds.getWidth(), 0, bnds.getHeight(), -10, 10); + + ::glClearColor(.2f,0.0f,0.0f,0.0f); + ::glClear(GL_COLOR_BUFFER_BIT); +} + + + +class Application : public GHOST_IEventConsumer { +public: + Application(GHOST_ISystem* system); + virtual bool processEvent(GHOST_IEvent* event); + + GHOST_ISystem* m_system; + GHOST_IWindow* m_mainWindow; + bool m_exitRequested; +}; + + +Application::Application(GHOST_ISystem* system) + : m_system(system), m_mainWindow(0), m_exitRequested(false) +{ + fApp = this; + + // Create the main window + STR_String title1 ("gears - main window"); + m_mainWindow = system->createWindow(title1, 10, 64, 320, 200, GHOST_kWindowStateNormal, GHOST_kDrawingContextTypeOpenGL,FALSE); + if (!m_mainWindow) { + std::cout << "could not create main window\n"; + exit(-1); + } +} + + +bool Application::processEvent(GHOST_IEvent* event) +{ + bool handled = true; + + switch (event->getType()) { + case GHOST_kEventWindowClose: + { + GHOST_IWindow* window2 = event->getWindow(); + if (window2 == m_mainWindow) { + exit(0); + } else { + m_system->disposeWindow(window2); + } + } + break; + + case GHOST_kEventWindowActivate: + handled = false; + break; + case GHOST_kEventWindowDeactivate: + handled = false; + break; + case GHOST_kEventWindowUpdate: + { + GHOST_IWindow* window2 = event->getWindow(); + if (!m_system->validWindow(window2)) break; + { + setViewPortGL(window2); + drawGL(); + window2->swapBuffers(); + } + } + break; + + default: + handled = false; + break; + } + return handled; +} + + +int main(int /*argc*/, char** /*argv*/) +{ + // Create the system + GHOST_ISystem::createSystem(); + fSystem = GHOST_ISystem::getSystem(); + + if (fSystem) { + // Create an application object + Application app (fSystem); + + // Add the application as event consumer + fSystem->addEventConsumer(&app); + + // Enter main loop + while (!app.m_exitRequested) { + fSystem->processEvents(TRUE); + fSystem->dispatchEvents(); + } + } + + // Dispose the system + GHOST_ISystem::disposeSystem(); + + return 0; +} + diff --git a/intern/bmfont/test/simpletest/Makefile b/intern/bmfont/test/simpletest/Makefile new file mode 100644 index 00000000000..190a39f0e9b --- /dev/null +++ b/intern/bmfont/test/simpletest/Makefile @@ -0,0 +1,45 @@ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# Test the bmfont module +# + +LIBNAME = bmfont +DIR = $(OCGDIR)/intern/$(LIBNAME)/test + +# we don't want a library here, only object files: +ALLTARGETS = $(OBJS) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS = -I../.. +CPPFLAGS += -I../../intern +CPPFLAGS += -I$(OPENGL_HEADERS) +CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I$(NAN_GHOST)/include diff --git a/intern/boolop/CMakeLists.txt b/intern/boolop/CMakeLists.txt new file mode 100644 index 00000000000..0db6675237b --- /dev/null +++ b/intern/boolop/CMakeLists.txt @@ -0,0 +1,35 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC . intern extern ../moto/include ../container ../memutil ../../source/blender/makesdna ../guardedalloc ../../source/blender/blenlib) + +FILE(GLOB SRC intern/*.cpp) + +BLENDERLIB(blender_bop "${SRC}" "${INC}") +#, libtype='common', priority=5 ) diff --git a/intern/boolop/Makefile b/intern/boolop/Makefile new file mode 100644 index 00000000000..85e6754132e --- /dev/null +++ b/intern/boolop/Makefile @@ -0,0 +1,59 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# bsp main makefile. +# + +include nan_definitions.mk + +LIBNAME = boolop +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +# not yet TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_BOOLOP) ] || mkdir $(NAN_BOOLOP) + @[ -d $(NAN_BOOLOP)/include ] || mkdir $(NAN_BOOLOP)/include + @[ -d $(NAN_BOOLOP)/lib ] || mkdir $(NAN_BOOLOP)/lib + @[ -d $(NAN_BOOLOP)/lib/debug ] || mkdir $(NAN_BOOLOP)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libboolop.a $(NAN_BOOLOP)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libboolop.a $(NAN_BOOLOP)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_BOOLOP)/lib/libboolop.a + ranlib $(NAN_BOOLOP)/lib/debug/libboolop.a +endif + @../tools/cpifdiff.sh extern/*.h $(NAN_BOOLOP)/include/ + + + + diff --git a/intern/boolop/SConscript b/intern/boolop/SConscript new file mode 100644 index 00000000000..a3f3c0b6433 --- /dev/null +++ b/intern/boolop/SConscript @@ -0,0 +1,14 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.cpp') + +incs = '. intern extern ../moto/include ../container ../memutil' +incs += ' ../../source/blender/makesdna ../../intern/guardedalloc' +incs += ' ../../source/blender/blenlib' + +if (env['OURPLATFORM'] == 'win32-mingw'): + env.BlenderLib ('blender_bop', sources, Split(incs) , [], libtype=['common','intern'], priority = [5,50] ) +else: + env.BlenderLib ('blender_bop', sources, Split(incs) , [], libtype='common', priority = 5 ) + diff --git a/intern/boolop/extern/BOP_Interface.h b/intern/boolop/extern/BOP_Interface.h new file mode 100644 index 00000000000..7fe7ae226fd --- /dev/null +++ b/intern/boolop/extern/BOP_Interface.h @@ -0,0 +1,46 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_INTERFACE_H +#define BOP_INTERFACE_H + +#include "../../bsp/intern/BSP_CSGMesh.h" + +typedef enum EnumBoolOpState {BOP_OK, BOP_NO_SOLID, BOP_ERROR} BoolOpState; +typedef enum EnumBoolOpType {BOP_INTERSECTION=e_csg_intersection, BOP_UNION=e_csg_union, BOP_DIFFERENCE=e_csg_difference} BoolOpType; + +BoolOpState BOP_performBooleanOperation(BoolOpType opType, + BSP_CSGMesh** outputMesh, + CSG_FaceIteratorDescriptor obAFaces, + CSG_VertexIteratorDescriptor obAVertices, + CSG_FaceIteratorDescriptor obBFaces, + CSG_VertexIteratorDescriptor obBVertices); + +#endif diff --git a/intern/boolop/intern/BOP_BBox.cpp b/intern/boolop/intern/BOP_BBox.cpp new file mode 100644 index 00000000000..767847e1e09 --- /dev/null +++ b/intern/boolop/intern/BOP_BBox.cpp @@ -0,0 +1,62 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_BBox.h" + +#include "MT_Scalar.h" + +/** + * Constructs a nwe bounding box. + */ +BOP_BBox::BOP_BBox() +{ + m_minX = MT_INFINITY; + m_minY = MT_INFINITY; + m_minZ = MT_INFINITY; + m_maxX = -MT_INFINITY; + m_maxY = -MT_INFINITY; + m_maxZ = -MT_INFINITY; +} + +/** + * Constructs a new bounding box using three points. + * @param p1 first point + * @param p2 second point + * @param p3 third point + */ +BOP_BBox::BOP_BBox(const MT_Point3& p1,const MT_Point3& p2,const MT_Point3& p3) +{ + m_minX = BOP_MIN(BOP_MIN(p1[0],p2[0]),p3[0]); + m_minY = BOP_MIN(BOP_MIN(p1[1],p2[1]),p3[1]); + m_minZ = BOP_MIN(BOP_MIN(p1[2],p2[2]),p3[2]); + m_maxX = BOP_MAX(BOP_MAX(p1[0],p2[0]),p3[0]); + m_maxY = BOP_MAX(BOP_MAX(p1[1],p2[1]),p3[1]); + m_maxZ = BOP_MAX(BOP_MAX(p1[2],p2[2]),p3[2]); +} diff --git a/intern/boolop/intern/BOP_BBox.h b/intern/boolop/intern/BOP_BBox.h new file mode 100644 index 00000000000..473a9828a1a --- /dev/null +++ b/intern/boolop/intern/BOP_BBox.h @@ -0,0 +1,96 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_BBOX_H +#define BOP_BBOX_H + +#include "MT_Point3.h" +#include "BOP_MathUtils.h" + +#define BOP_MAX(a, b) ((a > b) ? a : b) +#define BOP_MIN(a, b) ((a < b) ? a : b) +#define BOP_ABS(a) ((a < 0) ? -(a) : a) + +class BOP_BBox +{ +public: + MT_Scalar m_minX; + MT_Scalar m_minY; + MT_Scalar m_minZ; + MT_Scalar m_maxX; + MT_Scalar m_maxY; + MT_Scalar m_maxZ; + MT_Scalar m_centerX; + MT_Scalar m_centerY; + MT_Scalar m_centerZ; + MT_Scalar m_extentX; + MT_Scalar m_extentY; + MT_Scalar m_extentZ; + +public: + BOP_BBox(); + BOP_BBox(const MT_Point3& p1,const MT_Point3& p2,const MT_Point3& p3); + inline void add(const MT_Point3& p) + { + m_minX = BOP_MIN(m_minX,p[0]); + m_minY = BOP_MIN(m_minY,p[1]); + m_minZ = BOP_MIN(m_minZ,p[2]); + m_maxX = BOP_MAX(m_maxX,p[0]); + m_maxY = BOP_MAX(m_maxY,p[1]); + m_maxZ = BOP_MAX(m_maxZ,p[2]); + }; + + inline const MT_Scalar getCenterX() const {return m_centerX;}; + inline const MT_Scalar getCenterY() const {return m_centerY;}; + inline const MT_Scalar getCenterZ() const {return m_centerZ;}; + + inline const MT_Scalar getExtentX() const {return m_extentX;}; + inline const MT_Scalar getExtentY() const {return m_extentY;}; + inline const MT_Scalar getExtentZ() const {return m_extentZ;}; + + inline void compute() { + m_extentX = (m_maxX-m_minX)/2.0f; + m_extentY = (m_maxY-m_minY)/2.0f; + m_extentZ = (m_maxZ-m_minZ)/2.0f; + m_centerX = m_minX+m_extentX; + m_centerY = m_minY+m_extentY; + m_centerZ = m_minZ+m_extentZ; + }; + + inline const bool intersect(const BOP_BBox& b) const { + return (!((BOP_comp(m_maxX,b.m_minX)<0) || (BOP_comp(b.m_maxX,m_minX)<0) || + (BOP_comp(m_maxY,b.m_minY)<0) || (BOP_comp(b.m_maxY,m_minY)<0) || + (BOP_comp(m_maxZ,b.m_minZ)<0) || (BOP_comp(b.m_maxZ,m_minZ)<0))); + }; + + +}; + +#endif diff --git a/intern/boolop/intern/BOP_BSPNode.cpp b/intern/boolop/intern/BOP_BSPNode.cpp new file mode 100644 index 00000000000..68a20d7a5a4 --- /dev/null +++ b/intern/boolop/intern/BOP_BSPNode.cpp @@ -0,0 +1,717 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_MathUtils.h" +#include "BOP_BSPNode.h" +#include "MT_assert.h" +#include "MT_MinMax.h" +#include +using namespace std; + +/** + * Constructs a new BSP node. + * @param plane split plane. + */ +BOP_BSPNode::BOP_BSPNode(const MT_Plane3& plane) +{ + m_plane = plane; + m_inChild = NULL; + m_outChild = NULL; + m_deep = 1; +} + +/** + * Destroys a BSP tree. + */ +BOP_BSPNode::~BOP_BSPNode() +{ + if (m_inChild!=NULL) delete m_inChild; + if (m_outChild!=NULL) delete m_outChild; +} + +/** + * Adds a new face to this BSP tree. + * @param pts vector containing face points + * @param plane face plane. + */ + +unsigned int BOP_BSPNode::addFace(BOP_BSPPoints pts, + const MT_Plane3& plane ) +{ + unsigned int newDeep = 0; + BOP_TAG tag = ON; + + // find out if any points on the "face" lie in either half-space + BOP_IT_BSPPoints ptsEnd = pts.end(); + for(BOP_IT_BSPPoints itp=pts.begin();itp!=ptsEnd;itp++){ + tag = (BOP_TAG) ((int) tag | (int)testPoint(*itp)); + } + + if (tag == ON) { } // face lies on hyperplane: do nothing + else if ((tag & IN) != 0 && (tag & OUT) == 0) { // face is entirely on inside + if (m_inChild != NULL) + newDeep = m_inChild->addFace(pts, plane) + 1; + else { + m_inChild = new BOP_BSPNode(plane); + newDeep = 2; + } + } else if ((tag & OUT) != 0 && (tag & IN) == 0) { // face is entirely on outside + if (m_outChild != NULL) + newDeep = m_outChild->addFace(pts, plane) + 1; + else { + m_outChild = new BOP_BSPNode(plane); + newDeep = 2; + } + } else { // face lies in both half-spaces: split it + BOP_BSPPoints inside, outside; + MT_Point3 lpoint= pts[pts.size()-1]; + BOP_TAG ltag = testPoint(lpoint); + BOP_TAG tstate = ltag; + + // classify each line segment, looking for endpoints which lie on different + // sides of the hyperplane. + + ptsEnd = pts.end(); + for(BOP_IT_BSPPoints itp=pts.begin();itp!=ptsEnd;itp++){ + MT_Point3 npoint= *itp; + BOP_TAG ntag = testPoint(npoint); + + if(ltag != ON) { // last point not on hyperplane + if(tstate == IN) { + if (m_inChild != NULL) inside.push_back(lpoint); + } else { + if (m_outChild != NULL) outside.push_back(lpoint); + } + if(ntag != ON && ntag != tstate) { // last, self in different half-spaces + MT_Point3 mpoint = BOP_intersectPlane( m_plane, lpoint, npoint ); + if (m_inChild != NULL) inside.push_back(mpoint); + if (m_outChild != NULL) outside.push_back(mpoint); + tstate = ntag; + } + } else { // last point on hyperplane, so we're switching + // half-spaces + // boundary point belong to both faces + if (m_inChild != NULL) inside.push_back(lpoint); + if (m_outChild != NULL) outside.push_back(lpoint); + tstate = ntag; // state changes to new point tag + } + lpoint = npoint; // save point, tag for next iteration + ltag = ntag; + } + + if (m_inChild != NULL) + newDeep = m_inChild->addFace(inside, plane) + 1; + else { + m_inChild = new BOP_BSPNode(plane); + newDeep = 2; + } + if (m_outChild != NULL) + newDeep = MT_max(newDeep, m_outChild->addFace(outside, plane) + 1); + else { + m_outChild = new BOP_BSPNode(plane); + newDeep = MT_max(newDeep,(unsigned int)2); + } + } + + // update the deep attribute + m_deep = MT_max(m_deep,newDeep); + + return m_deep; +} + +/** + * Tests the point situation respect the node plane. + * @param p point to test. + * @return TAG result: IN, OUT or ON. + */ +BOP_TAG BOP_BSPNode::testPoint(const MT_Point3& p) const +{ + return BOP_createTAG(BOP_classify(p,m_plane)); + +} + +/** + * Classifies a face using its coordinates and plane. + * @param p1 first point. + * @param p2 second point. + * @param p3 third point. + * @param plane face plane. + * @return TAG result: IN, OUT or IN&OUT. + */ +BOP_TAG BOP_BSPNode::classifyFace(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const +{ + // local variables + MT_Point3 auxp1, auxp2; + BOP_TAG auxtag1, auxtag2, auxtag3; + + switch(BOP_createTAG(testPoint(p1),testPoint(p2),testPoint(p3))) { + // Classify the face on the IN side + case IN_IN_IN : + return classifyFaceIN(p1, p2, p3, plane); + case IN_IN_ON : + case IN_ON_IN : + case ON_IN_IN : + case IN_ON_ON : + case ON_IN_ON : + case ON_ON_IN : + return BOP_addON(classifyFaceIN(p1, p2, p3, plane)); + + // Classify the face on the OUT side + case OUT_OUT_OUT : + return classifyFaceOUT(p1, p2, p3, plane); + case OUT_OUT_ON : + case OUT_ON_OUT : + case ON_OUT_OUT : + case ON_ON_OUT : + case ON_OUT_ON : + case OUT_ON_ON : + return BOP_addON(classifyFaceOUT(p1, p2, p3, plane)); + + // Classify the ON face depending on it plane normal + case ON_ON_ON : + if (hasSameOrientation(plane)) + return BOP_addON(classifyFaceIN(p1, p2, p3, plane)); + else + return BOP_addON(classifyFaceOUT(p1, p2, p3, plane)); + + // Classify the face IN/OUT and one vertex ON + // becouse only one ON, only one way to subdivide the face + case IN_OUT_ON : + auxp1 = BOP_intersectPlane(m_plane, p1, p2); + auxtag1 = classifyFaceIN( p1, auxp1 , p3, plane); + auxtag2 = classifyFaceOUT(auxp1, p2, p3, plane); + return (BOP_compTAG(auxtag1,auxtag2)?BOP_addON(auxtag1):INOUT); + + case OUT_IN_ON : + auxp1 = BOP_intersectPlane(m_plane, p1, p2); + auxtag1 = classifyFaceOUT(p1, auxp1, p3, plane); + auxtag2 = classifyFaceIN( auxp1, p2, p3, plane); + return (BOP_compTAG(auxtag1,auxtag2)?BOP_addON(auxtag1):INOUT); + + case IN_ON_OUT : + auxp1 = BOP_intersectPlane(m_plane, p1, p3); + auxtag1 = classifyFaceIN( p1, p2, auxp1, plane); + auxtag2 = classifyFaceOUT(p2, p3, auxp1, plane); + return (BOP_compTAG(auxtag1,auxtag2)?BOP_addON(auxtag1):INOUT); + + case OUT_ON_IN : + auxp1 = BOP_intersectPlane(m_plane, p1, p3); + auxtag1 = classifyFaceOUT(p1, p2, auxp1, plane); + auxtag2 = classifyFaceIN( p2, p3, auxp1, plane); + return (BOP_compTAG(auxtag1,auxtag2)?BOP_addON(auxtag1):INOUT); + + case ON_IN_OUT : + auxp1 = BOP_intersectPlane(m_plane, p2, p3); + auxtag1 = classifyFaceIN( p1, p2, auxp1, plane); + auxtag2 = classifyFaceOUT(auxp1, p3, p1, plane); + return (BOP_compTAG(auxtag1,auxtag2)?BOP_addON(auxtag1):INOUT); + + case ON_OUT_IN : + auxp1 = BOP_intersectPlane(m_plane, p2, p3); + auxtag1 = classifyFaceOUT(p1, p2, auxp1, plane); + auxtag2 = classifyFaceIN( auxp1, p3, p1, plane); + return (BOP_compTAG(auxtag1,auxtag2)?BOP_addON(auxtag1):INOUT); + + // Classify IN/OUT face without ON vertices. + // Two ways to divide the triangle, + // will chose the least degenerated sub-triangles. + case IN_OUT_OUT : + auxp1 = BOP_intersectPlane(m_plane, p1, p2); + auxp2 = BOP_intersectPlane(m_plane, p1, p3); + + // f1: p1 auxp1 , auxp1 auxp2 + auxtag1 = classifyFaceIN(p1, auxp1, auxp2, plane); + + // f2: auxp1 p2 , p2 auxp2; f3: p2 p3 , p3 auxp2 || + // f2: auxp1 p3, p3 auxp2; f3: p2 p3 , p3 auxp1 + if (BOP_isInsideCircle(p2, p3, auxp1, auxp2)) { + auxtag2 = classifyFaceOUT(auxp1, p2, auxp2, plane); + auxtag3 = classifyFaceOUT(p2, p3, auxp2, plane); + } + else { + auxtag2 = classifyFaceOUT(auxp1, p3, auxp2, plane); + auxtag3 = classifyFaceOUT(p2, p3, auxp1, plane); + } + return (BOP_compTAG(auxtag1,auxtag2)&&BOP_compTAG(auxtag2,auxtag3)?auxtag1:INOUT); + + case OUT_IN_IN : + auxp1 = BOP_intersectPlane(m_plane, p1, p2); + auxp2 = BOP_intersectPlane(m_plane, p1, p3); + + // f1: p1 auxp1 , auxp1 auxp2 + auxtag1 = classifyFaceOUT(p1, auxp1, auxp2, plane); + + // f2: auxp1 p2 , p2 auxp2; f3: p2 p3 , p3 auxp2 || + // f2: auxp1 p3, p3 auxp2; f3: p2 p3 , p3 auxp1 + if (BOP_isInsideCircle(p2, p3, auxp1, auxp2)) { + auxtag2 = classifyFaceIN(auxp1, p2, auxp2, plane); + auxtag3 = classifyFaceIN(p2, p3, auxp2, plane); + } + else { + auxtag2 = classifyFaceIN(auxp1, p3, auxp2, plane); + auxtag3 = classifyFaceIN(p2, p3, auxp1, plane); + } + return (BOP_compTAG(auxtag1,auxtag2)&&BOP_compTAG(auxtag2,auxtag3)?auxtag1:INOUT); + + case OUT_IN_OUT : + auxp1 = BOP_intersectPlane(m_plane, p2, p1); + auxp2 = BOP_intersectPlane(m_plane, p2, p3); + + // f1: auxp1 p2 , p2 auxp2 + auxtag1 = classifyFaceIN(auxp1, p2, auxp2, plane); + + // f2: p1 auxp1 , auxp1 auxp2; f3: p1 auxp2 , auxp2 p3 || + // f2: p3 auxp1, auxp1 auxp2 f3:p1 auxp1, auxp1 p3 + if (BOP_isInsideCircle(p1, p3, auxp1, auxp2)) { + auxtag2 = classifyFaceOUT(p1, auxp1, auxp2, plane); + auxtag3 = classifyFaceOUT(p1, auxp2, p3, plane); + } + else { + auxtag2 = classifyFaceOUT(p3, auxp1, auxp2, plane); + auxtag3 = classifyFaceOUT(p1, auxp1, p3, plane); + } + return (BOP_compTAG(auxtag1,auxtag2)&&BOP_compTAG(auxtag2,auxtag3)?auxtag1:INOUT); + + case IN_OUT_IN : + auxp1 = BOP_intersectPlane(m_plane, p2, p1); + auxp2 = BOP_intersectPlane(m_plane, p2, p3); + + // f1: auxp1 p2 , p2 auxp2 + auxtag1 = classifyFaceOUT(auxp1, p2, auxp2, plane); + + // f2: p1 auxp1 , auxp1 auxp2; f3: p1 auxp2 , auxp2 p3 || + // f2: p3 auxp1, auxp1 auxp2 f3:p1 auxp1, auxp1 p3 + if (BOP_isInsideCircle(p1, p3, auxp1, auxp2)) { + auxtag2 = classifyFaceIN(p1, auxp1, auxp2, plane); + auxtag3 = classifyFaceIN(p1, auxp2, p3, plane); + } + else { + auxtag2 = classifyFaceIN(p3, auxp1, auxp2, plane); + auxtag3 = classifyFaceIN(p1, auxp1, p3, plane); + } + return (BOP_compTAG(auxtag1,auxtag2)&&BOP_compTAG(auxtag2,auxtag3)?auxtag1:INOUT); + + case OUT_OUT_IN : + auxp1 = BOP_intersectPlane(m_plane, p3, p1); + auxp2 = BOP_intersectPlane(m_plane, p3, p2); + + // f1: auxp1 auxp2 , auxp2 p3 + auxtag1 = classifyFaceIN(auxp1, auxp2, p3, plane); + + // f2: p1 p2 , p2 auxp2; f3:p1 auxp2 , auxp2 auxp1 || + // f2: p1 p2, p2 auxp1; f3:p2 auxp2, auxp2 auxp1 + if (BOP_isInsideCircle(p1, p2, auxp1, auxp2)) { + auxtag2 = classifyFaceOUT(p1, p2, auxp2, plane); + auxtag3 = classifyFaceOUT(p1, auxp2, auxp1, plane); + } + else { + auxtag2 = classifyFaceOUT(p1, p2, auxp1, plane); + auxtag3 = classifyFaceOUT(p2, auxp2, auxp1, plane); + } + return (BOP_compTAG(auxtag1,auxtag2)&&BOP_compTAG(auxtag2,auxtag3)?auxtag1:INOUT); + + case IN_IN_OUT : + auxp1 = BOP_intersectPlane(m_plane, p3, p1); + auxp2 = BOP_intersectPlane(m_plane, p3, p2); + + // f1: auxp1 auxp2 , auxp2 p3 + auxtag1 = classifyFaceOUT(auxp1, auxp2, p3, plane); + + // f2: p1 p2 , p2 auxp2; f3:p1 auxp2 , auxp2 auxp1 || + // f2: p1 p2, p2 auxp1; f3:p2 auxp2, auxp2 auxp1 + if (BOP_isInsideCircle(p1, p2, auxp1, auxp2)) { + auxtag2 = classifyFaceIN(p1, p2, auxp2, plane); + auxtag3 = classifyFaceIN(p1, auxp2, auxp1, plane); + } + else { + auxtag2 = classifyFaceIN(p1, p2, auxp1, plane); + auxtag3 = classifyFaceIN(p2, auxp2, auxp1, plane); + } + return (BOP_compTAG(auxtag1,auxtag2)&&BOP_compTAG(auxtag2,auxtag3)?auxtag1:INOUT); + + default: + return UNCLASSIFIED; + } +} + +/** + * Classifies a face through IN subtree. + * @param p1 firts face vertex. + * @param p2 second face vertex. + * @param p3 third face vertex. + * @param plane face plane. + */ +BOP_TAG BOP_BSPNode::classifyFaceIN(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const +{ + if (m_inChild != NULL) + return m_inChild->classifyFace(p1, p2, p3, plane); + else + return IN; +} + +/** + * Classifies a face through OUT subtree. + * @param p1 firts face vertex. + * @param p2 second face vertex. + * @param p3 third face vertex. + * @param plane face plane. + */ +BOP_TAG BOP_BSPNode::classifyFaceOUT(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const +{ + if (m_outChild != NULL) + return m_outChild->classifyFace(p1, p2, p3, plane); + else + return OUT; +} + +/** + * Simplified classification (optimized but requires that the face is not + * INOUT; only works correctly with faces completely IN or OUT). + * @param p1 firts face vertex. + * @param p2 second face vertex. + * @param p3 third face vertex. + * @param plane face plane. + * @return TAG result: IN or OUT. + */ +BOP_TAG BOP_BSPNode::simplifiedClassifyFace(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const +{ + MT_Point3 ret[3]; + + BOP_TAG tag = BOP_createTAG(testPoint(p1),testPoint(p2),testPoint(p3)); + + if ((tag & IN_IN_IN) != 0) { + if ((tag & OUT_OUT_OUT) != 0) { + if (splitTriangle(ret,m_plane,p1,p2,p3,tag)<0) + return simplifiedClassifyFaceIN(ret[0],ret[1],ret[2],plane); + else + return simplifiedClassifyFaceOUT(ret[0],ret[1],ret[2],plane); + } + else { + return simplifiedClassifyFaceIN(p1,p2,p3,plane); + } + } + else { + if ((tag & OUT_OUT_OUT) != 0) { + return simplifiedClassifyFaceOUT(p1,p2,p3,plane); + } + else { + if (hasSameOrientation(plane)) { + return simplifiedClassifyFaceIN(p1,p2,p3,plane); + } + else { + return simplifiedClassifyFaceOUT(p1,p2,p3,plane); + } + } + } + + return IN; +} + +/** + * Simplified classify through IN subtree. + * @param p1 firts face vertex. + * @param p2 second face vertex. + * @param p3 third face vertex. + * @param plane face plane. + */ +BOP_TAG BOP_BSPNode::simplifiedClassifyFaceIN(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const +{ + if (m_inChild != NULL) + return m_inChild->simplifiedClassifyFace(p1, p2, p3, plane); + else + return IN; +} + +/** + * Simplified classify through OUT subtree. + * @param p1 firts face vertex. + * @param p2 second face vertex. + * @param p3 third face vertex. + * @param plane face plane. + */ +BOP_TAG BOP_BSPNode::simplifiedClassifyFaceOUT(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const +{ + if (m_outChild != NULL) + return m_outChild->simplifiedClassifyFace(p1, p2, p3, plane); + else + return OUT; +} + +/** + * Determine if the input plane have the same orientation of the node plane. + * @param plane plane to test. + * @return TRUE if have the same orientation, FALSE otherwise. + */ +bool BOP_BSPNode::hasSameOrientation(const MT_Plane3& plane) const +{ + return (BOP_orientation(m_plane,plane)>0); +} + +/** + * Comparation between both childrens. + * @return 0 equal deep, 1 inChild more deep than outChild and -1 otherwise. + */ +int BOP_BSPNode::compChildren() const +{ + unsigned int deep1 = (m_inChild == NULL?0:m_inChild->getDeep()); + unsigned int deep2 = (m_outChild == NULL?0:m_outChild->getDeep()); + + if (deep1 == deep2) + return 0; + else if (deep1 < deep2) + return -1; + else + return 1; +} + +/** + * Extract a subtriangle from input triangle, is used for simplified classification. + * The subtriangle is obtained spliting the input triangle by input plane. + * @param res output subtriangle result. + * @param plane spliter plane. + * @param p1 first triangle point. + * @param p2 second triangle point. + * @param p3 third triangle point. + * @param tag triangle orientation respect the plane. + */ +int BOP_BSPNode::splitTriangle(MT_Point3* res, + const MT_Plane3& plane, + const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const BOP_TAG tag) const +{ + switch (tag) { + case IN_OUT_ON : + if (compChildren()<0) { + // f1: p1 new p3 || new = splitedge(p1,p2) + res[0] = p1; + res[1] = BOP_intersectPlane( plane, p1, p2 ); + res[2] = p3; + return -1; + }else{ + // f1: p2 new p3 || new = splitedge(p1,p2) + res[0] = p2; + res[1] = p3; + res[2] = BOP_intersectPlane( plane, p1, p2 ); + return 1; + } + case OUT_IN_ON : + if (compChildren()<0) { + // f1: p2 new p3 || new = splitedge(p1,p2) + res[0] = p2; + res[1] = p3; + res[2] = BOP_intersectPlane( plane, p1, p2 ); + return -1; + }else{ + // f1: p1 new p3 || new = splitedge(p1,p2) + res[0] = p1; + res[1] = BOP_intersectPlane( plane, p1, p2 ); + res[2] = p3; + return 1; + } + case IN_ON_OUT : + if (compChildren()<0) { + // f1: p1 p2 new || new = splitedge(p1,p3) + res[0] = p1; + res[1] = p2; + res[2] = BOP_intersectPlane( plane, p1, p3 ); + return -1; + }else{ + // f1: p2 p3 new || new = splitedge(p1,p3) + res[0] = p2; + res[1] = p3; + res[2] = BOP_intersectPlane( plane, p1, p3 ); + return 1; + } + case OUT_ON_IN : + if (compChildren()<0) { + // f1: p2 p3 new || new = splitedge(p1,p3) + res[0] = p2; + res[1] = p3; + res[2] = BOP_intersectPlane( plane, p1, p3 ); + return -1; + }else{ + // f1: p1 p2 new || new = splitedge(p1,p3) + res[0] = p1; + res[1] = p2; + res[2] = BOP_intersectPlane( plane, p1, p3 ); + return 1; + } + case ON_IN_OUT : + if (compChildren()<0) { + // f1: p1 p2 new || new = splitedge(p2,p3) + res[0] = p1; + res[1] = p2; + res[2] = BOP_intersectPlane( plane, p2, p3 ); + return -1; + }else{ + // f1: p1 p3 new || new = splitedge(p2,p3) + res[0] = p1; + res[1] = BOP_intersectPlane( plane, p2, p3 ); + res[2] = p3; + return 1; + } + case ON_OUT_IN : + if (compChildren()<0) { + // f1: p1 p2 new || new = splitedge(p2,p3) + res[0] = p1; + res[1] = BOP_intersectPlane( plane, p2, p3 ); + res[2] = p3; + return -1; + }else{ + // f1: p1 p2 new || new = splitedge(p2,p3) + res[0] = p1; + res[1] = p2; + res[2] = BOP_intersectPlane( plane, p2, p3 ); + return 1; + } + case IN_OUT_OUT : + if (compChildren()<=0) { + // f1: p1 new1 new2 || new1 = splitedge(p1,p2) new2 = splitedge(p1,p3) + res[0] = p1; + res[1] = BOP_intersectPlane( plane, p1, p2 ); + res[2] = BOP_intersectPlane( plane, p1, p3 ); + return -1; + }else{ + // f1: p1 new1 new2 || new1 = splitedge(p1,p2) new2 = splitedge(p1,p3) + res[0] = BOP_intersectPlane( plane, p1, p2 ); + res[1] = p2; + res[2] = p3; + return 1; + } + case OUT_IN_IN : + if (compChildren()<0) { + // f1: p1 new1 new2 || new1 = splitedge(p1,p2) new2 = splitedge(p1,p3) + res[0] = BOP_intersectPlane( plane, p1, p2 ); + res[1] = p2; + res[2] = p3; + return -1; + }else { + // f1: p1 new1 new2 || new1 = splitedge(p1,p2) new2 = splitedge(p1,p3) + res[0] = p1; + res[1] = BOP_intersectPlane( plane, p1, p2 ); + res[2] = BOP_intersectPlane( plane, p1, p3 ); + return 1; + } + case OUT_IN_OUT : + if (compChildren()<=0) { + // f1: new1 p2 new2 || new1 = splitedge(p2,p1) new2 = splitedge(p2,p3) + res[0] = BOP_intersectPlane( plane, p2, p1 ); + res[1] = p2; + res[2] = BOP_intersectPlane( plane, p2, p3 ); + return -1; + }else { + // f1: new1 p2 new2 || new1 = splitedge(p2,p1) new2 = splitedge(p2,p3) + res[0] = p1; + res[1] = BOP_intersectPlane( plane, p2, p1 ); + res[2] = BOP_intersectPlane( plane, p2, p3 ); + return 1; + } + case IN_OUT_IN : + if (compChildren()<0) { + // f1: new1 p2 new2 || new1 = splitedge(p2,p1) new2 = splitedge(p2,p3) + res[0] = p1; + res[1] = BOP_intersectPlane( plane, p2, p1 ); + res[2] = BOP_intersectPlane( plane, p2, p3 ); + return -1; + }else{ + // f1: new1 p2 new2 || new1 = splitedge(p2,p1) new2 = splitedge(p2,p3) + res[0] = BOP_intersectPlane( plane, p2, p1 ); + res[1] = p2; + res[2] = BOP_intersectPlane( plane, p2, p3 ); + return 1; + } + case OUT_OUT_IN : + if (compChildren()<=0) { + // f1: new1 new2 p2 || new1 = splitedge(p3,p1) new2 = splitedge(p3,p2) + res[0] = BOP_intersectPlane( plane, p3, p1 ); + res[1] = BOP_intersectPlane( plane, p3, p2 ); + res[2] = p3; + return -1; + }else{ + // f1: new1 new2 p2 || new1 = splitedge(p3,p1) new2 = splitedge(p3,p2) + res[0] = BOP_intersectPlane( plane, p3, p1 ); + res[1] = p1; + res[2] = p2; + return 1; + } + case IN_IN_OUT : + if (compChildren()<0) { + // f1: new1 new2 p2 || new1 = splitedge(p3,p1) new2 = splitedge(p3,p2) + res[0] = BOP_intersectPlane( plane, p3, p1 ); + res[1] = p1; + res[2] = p2; + return -1; + }else{ + // f1: new1 new2 p2 || new1 = splitedge(p3,p1) new2 = splitedge(p3,p2) + res[0] = BOP_intersectPlane( plane, p3, p1 ); + res[1] = BOP_intersectPlane( plane, p3, p2 ); + res[2] = p3; + return 1; + } + default: + return 0; + } +} + +/** + * Debug info. + */ +void BOP_BSPNode::print(unsigned int deep) +{ + cout << "(" << deep << "," << m_plane << ")," << endl; + if (m_inChild != NULL) + m_inChild->print(deep + 1); + else + cout << "(" << deep+1 << ",None)," << endl; + if (m_outChild != NULL) + m_outChild->print(deep + 1); + else + cout << "(" << deep+1 << ",None)," << endl; +} diff --git a/intern/boolop/intern/BOP_BSPNode.h b/intern/boolop/intern/BOP_BSPNode.h new file mode 100644 index 00000000000..39a84b94dec --- /dev/null +++ b/intern/boolop/intern/BOP_BSPNode.h @@ -0,0 +1,105 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_BSPNODE_H +#define BOP_BSPNODE_H + +#include "MT_Plane3.h" +#include "BOP_Tag.h" +#include "BOP_Face.h" + +typedef vector BOP_BSPPoints; +typedef vector::iterator BOP_IT_BSPPoints; + +class BOP_BSPNode +{ +protected: + BOP_BSPNode* m_inChild; + BOP_BSPNode* m_outChild; + MT_Plane3 m_plane; + unsigned int m_deep; + +public: + // Construction methods + BOP_BSPNode(const MT_Plane3& plane); + ~BOP_BSPNode(); + unsigned int addFace(BOP_BSPPoints pts, + const MT_Plane3& plane); + BOP_TAG classifyFace(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const; + BOP_TAG simplifiedClassifyFace(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const; + +protected: + BOP_TAG testPoint(const MT_Point3& p) const; + BOP_TAG classifyFaceIN(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const; + BOP_TAG classifyFaceOUT(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const; + BOP_TAG simplifiedClassifyFaceIN(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const; + BOP_TAG simplifiedClassifyFaceOUT(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const; + bool hasSameOrientation(const MT_Plane3& plane) const; + int compChildren() const; + int splitTriangle(MT_Point3* res, + const MT_Plane3& plane, + const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const BOP_TAG tag) const; + +public: + // Inline acces methods + inline void setInChild(BOP_BSPNode* inChild) { m_inChild=inChild; }; + inline void setOutChild(BOP_BSPNode* outChild) { m_outChild=outChild; }; + inline BOP_BSPNode* getInChild() { return m_inChild; }; + inline BOP_BSPNode* getOutChild() { return m_outChild; }; + inline bool isLeaf() const { return !m_inChild && !m_outChild; }; + inline void setPlane(const MT_Plane3& plane) {m_plane=plane;}; + inline MT_Plane3& getPlane() { return m_plane; }; + + inline unsigned int getDeep() const {return m_deep;}; + void print(unsigned int deep); +}; + +#endif diff --git a/intern/boolop/intern/BOP_BSPTree.cpp b/intern/boolop/intern/BOP_BSPTree.cpp new file mode 100644 index 00000000000..3ae375294cd --- /dev/null +++ b/intern/boolop/intern/BOP_BSPTree.cpp @@ -0,0 +1,189 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_BSPTree.h" +#include +#include +using namespace std; + +/** + * Constructs a new BSP tree. + */ +BOP_BSPTree::BOP_BSPTree() +{ + m_root = NULL; + m_bspBB = NULL; +} + +/** + * Destroys a BSP tree. + */ +BOP_BSPTree::~BOP_BSPTree() +{ + if (m_root!=NULL) delete m_root; + if (m_bspBB!=NULL) delete m_bspBB; +} + +/** + * Adds all mesh faces to BSP tree. + * @param mesh mesh to add. + * @param facesList face list to add. + */ +void BOP_BSPTree::addMesh(BOP_Mesh* mesh, BOP_Faces& facesList) +{ + for (BOP_IT_Faces it = facesList.begin(); it != facesList.end(); ++it) { + addFace( mesh, *it ); + } + +} + +/** + * Adds a new face into bsp tree. + * @param mesh Input data for BSP tree. + * @param face index to mesh face. + */ + +void BOP_BSPTree::addFace(BOP_Mesh* mesh, BOP_Face* face) +{ + addFace(mesh->getVertex(face->getVertex(0))->getPoint(), + mesh->getVertex(face->getVertex(1))->getPoint(), + mesh->getVertex(face->getVertex(2))->getPoint(), + face->getPlane()); +} + +/** + * Adds new facee to the bsp-tree. + * @param p1 first face point. + * @param p2 second face point. + * @param p3 third face point. + * @param plane face plane. + */ +void BOP_BSPTree::addFace(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) +{ + if (m_root == NULL) + m_root = new BOP_BSPNode(plane); + else { + BOP_BSPPoints pts; + + pts.push_back(p1); + pts.push_back(p2); + pts.push_back(p3); + + m_root->addFace(pts,plane); + } + + // update bounding box + m_bbox.add(p1); + m_bbox.add(p2); + m_bbox.add(p3); +} + +/** + * Tests face vs bsp-tree (returns where is the face respect bsp planes). + * @param p1 first face triangle point. + * @param p2 secons face triangle point. + * @param p3 third face triangle point. + * @param plane face plane. + * @return BSP_IN, BSP_OUT or BSP_IN_OUT + */ +BOP_TAG BOP_BSPTree::classifyFace(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const +{ + if ( m_root != NULL ) + return m_root->classifyFace(p1, p2, p3, plane); + else + return OUT; +} + +/** + * Filters a face using the BSP bounding infomation. + * @param p1 first face triangle point. + * @param p2 secons face triangle point. + * @param p3 third face triangle point. + * @param face face to test. + * @return UNCLASSIFIED, BSP_IN, BSP_OUT or BSP_IN_OUT + */ +BOP_TAG BOP_BSPTree::filterFace(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + BOP_Face* face) +{ + if ( m_bspBB != NULL ) { + return m_bspBB->classifyFace(p1,p2,p3,face->getPlane()); + } + else + return UNCLASSIFIED; +} + +/** + * Tests face vs bsp-tree (returns where is the face respect bsp planes). + * @param p1 first face triangle point. + * @param p2 secons face triangle point. + * @param p3 third face triangle point. + * @param plane face plane. + * @return BSP_IN, BSP_OUT or BSP_IN_OUT + */ +BOP_TAG BOP_BSPTree::simplifiedClassifyFace(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const +{ + if ( m_root != NULL ) + return m_root->simplifiedClassifyFace(p1, p2, p3, plane); + else + return OUT; +} + +/** + * Returns the deep of this BSP tree. + * @return tree deep + */ +unsigned int BOP_BSPTree::getDeep() const +{ + if ( m_root != NULL ) + return m_root->getDeep(); + else + return 0; +} + +/** + * Prints debug information. + */ +void BOP_BSPTree::print() +{ + if ( m_root != NULL ) + m_root->print( 0 ); +} + diff --git a/intern/boolop/intern/BOP_BSPTree.h b/intern/boolop/intern/BOP_BSPTree.h new file mode 100644 index 00000000000..412d5a40753 --- /dev/null +++ b/intern/boolop/intern/BOP_BSPTree.h @@ -0,0 +1,74 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_BSPTREE_H +#define BOP_BSPTREE_H + +#include "BOP_BSPNode.h" +#include "BOP_Mesh.h" +#include "BOP_Tag.h" +#include "BOP_BBox.h" + +class BOP_BSPTree +{ +protected: + BOP_BSPNode* m_root; + BOP_BSPNode* m_bspBB; + BOP_BBox m_bbox; +public: + // Construction methods + BOP_BSPTree(); + virtual ~BOP_BSPTree(); + void addMesh(BOP_Mesh* mesh, BOP_Faces& facesList); + void addFace(BOP_Mesh* mesh, BOP_Face* face); + virtual void addFace(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane); + BOP_TAG classifyFace(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const; + BOP_TAG filterFace(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + BOP_Face* face); + BOP_TAG simplifiedClassifyFace(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const; + unsigned int getDeep() const; + void print(); + inline void setRoot(BOP_BSPNode* root) {m_root=root;}; + inline BOP_BSPNode* getRoot() const {return m_root;}; +}; + +#endif + diff --git a/intern/boolop/intern/BOP_Chrono.h b/intern/boolop/intern/BOP_Chrono.h new file mode 100644 index 00000000000..5ce64f7a57c --- /dev/null +++ b/intern/boolop/intern/BOP_Chrono.h @@ -0,0 +1,52 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_CHRONO_H +#define BOP_CHRONO_H + +#include + +class BOP_Chrono +{ +private: + clock_t m_begin; +public: + BOP_Chrono(){}; + void start() {m_begin = clock();}; + float stamp() { + clock_t c = clock(); + clock_t stmp = c - m_begin; + m_begin = c; + float t = ((float) stmp / (float) CLOCKS_PER_SEC)*1000.0f; + return t; + }; +}; + +#endif diff --git a/intern/boolop/intern/BOP_Edge.cpp b/intern/boolop/intern/BOP_Edge.cpp new file mode 100644 index 00000000000..31411133878 --- /dev/null +++ b/intern/boolop/intern/BOP_Edge.cpp @@ -0,0 +1,81 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_Edge.h" + +/** + * Constructs a new edge. + * @param v1 vertex index + * @param v2 vertex index + */ +BOP_Edge::BOP_Edge(BOP_Index v1, BOP_Index v2) +{ + m_vertexs[0] = v1; + m_vertexs[1] = v2; +} + +/** + * Adds a new face index to this edge. + * @param i face index + */ +void BOP_Edge::addFace(BOP_Index i) +{ + if (!containsFace(i)) + m_faces.push_back(i); +} + +/** + * Returns if this edge contains the specified face index. + * @param i face index + * @return true if this edge contains the specified face index, false otherwise + */ +bool BOP_Edge::containsFace(BOP_Index i) +{ + int pos=0; + for(BOP_IT_Indexs it = m_faces.begin();it!=m_faces.end();pos++,it++) { + if ((*it) == i) + return true; + } + + return false; +} + +/** + * Replaces an edge vertex index. + * @param oldIndex old vertex index + * @param newIndex new vertex index + */ +void BOP_Edge::replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex) +{ + if (m_vertexs[0] == oldIndex) m_vertexs[0] = newIndex; + else if (m_vertexs[1] == oldIndex) m_vertexs[1] = newIndex; +} + + diff --git a/intern/boolop/intern/BOP_Edge.h b/intern/boolop/intern/BOP_Edge.h new file mode 100644 index 00000000000..abf5dd0a8c8 --- /dev/null +++ b/intern/boolop/intern/BOP_Edge.h @@ -0,0 +1,55 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_EDGE_H +#define BOP_EDGE_H + +#include "BOP_Indexs.h" + +class BOP_Edge +{ +private: + BOP_Index m_vertexs[2]; + BOP_Indexs m_faces; + + bool containsFace(BOP_Index i); + +public: + BOP_Edge(BOP_Index v1, BOP_Index v2); + inline BOP_Index getVertex1() { return m_vertexs[0];}; + inline BOP_Index getVertex2() { return m_vertexs[1];}; + void replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex); + inline BOP_Index getFace(unsigned int i){return m_faces[i];}; + inline unsigned int getNumFaces(){return m_faces.size();}; + inline BOP_Indexs &getFaces(){return m_faces;}; + void addFace(BOP_Index face); +}; + +#endif diff --git a/intern/boolop/intern/BOP_Face.cpp b/intern/boolop/intern/BOP_Face.cpp new file mode 100644 index 00000000000..ebe34237d4f --- /dev/null +++ b/intern/boolop/intern/BOP_Face.cpp @@ -0,0 +1,426 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_Face.h" + +/******************************************************************************/ +/*** BOP_Face ***/ +/******************************************************************************/ + +/** + * Constructs a new face. + * @param plane face plane + * @param originalFace index of the original face + */ +BOP_Face::BOP_Face(MT_Plane3 plane, BOP_Index originalFace) +{ + m_plane = plane; + m_tag = UNCLASSIFIED; + m_originalFace = originalFace; + m_split = 0; + m_bbox = NULL; +} + +/** + * Inverts this face. + */ +void BOP_Face::invert() +{ + getPlane().Invert(); + BOP_Index aux = m_indexs[0]; + m_indexs[0] = m_indexs[2]; + m_indexs[2] = aux; +} + +/******************************************************************************/ +/*** BOP_Face ***/ +/******************************************************************************/ + +/** + * Constructs a new triangle face. + * @param v1 vertex index + * @param v2 vertex index + * @param v3 vertex index + * @param plane face plane + * @param originalFace index of the original face + */ +BOP_Face3::BOP_Face3(BOP_Index v1, BOP_Index v2, BOP_Index v3, MT_Plane3 plane, BOP_Index originalFace): BOP_Face(plane,originalFace) +{ + m_indexs[0] = v1; + m_indexs[1] = v2; + m_indexs[2] = v3; + m_size = 3; +} + +/** + * Returns the relative edge index (1,2,3) for the specified vertex indexs. + * @param v1 vertex index + * @param v2 vertex index + * @param e relative edge index (1,2,3) + * @return true if (v1,v2) is an edge of this face, false otherwise + */ +bool BOP_Face3::getEdgeIndex(BOP_Index v1, BOP_Index v2, unsigned int &e) +{ + if (m_indexs[0] == v1) { + if (m_indexs[1] == v2) { + e = 1; + } + else if (m_indexs[2] == v2) { + e = 3; + } + else + return false; + } + else if (m_indexs[1] == v1) { + if (m_indexs[0] == v2) { + e = 1; + } + else if (m_indexs[2] == v2) { + e = 2; + } + else + return false; + } + else if (m_indexs[2] == v1) { + if (m_indexs[0] == v2) { + e = 3; + } + else if (m_indexs[1] == v2) { + e = 2; + } + else + return false; + }else { + return false; + } + + return true; +} + +/** + * Returns if this face contains the specified vertex index. + * @param v vertex index + * @return true if this face contains the specified vertex index, false otherwise + */ +bool BOP_Face3::containsVertex(BOP_Index v) +{ + return (m_indexs[0] == v || m_indexs[1] == v || m_indexs[2] == v); +} + +/** + * Returns the neighbours of the specified vertex index. + * @param v vertex index + * @param prev previous vertex index + * @param next next vertex index + * @return true if this face contains the vertex index v, false otherwise + */ +bool BOP_Face3::getNeighbours(BOP_Index v, BOP_Index &prev, BOP_Index &next) +{ + if (m_indexs[0] == v) { + prev = m_indexs[2]; + next = m_indexs[1]; + } + else if (m_indexs[1] == v) { + prev = m_indexs[0]; + next = m_indexs[2]; + } + else if (m_indexs[2] == v) { + prev = m_indexs[1]; + next = m_indexs[0]; + } + else return false; + + return true; +} + +/** + * Returns the previous neighbour of the specified vertex index. + * @param v vertex index + * @param w previous vertex index + * @return true if this face contains the specified vertex index, false otherwise + */ +bool BOP_Face3::getPreviousVertex(BOP_Index v, BOP_Index &w) +{ + if (m_indexs[0] == v) w = m_indexs[2]; + else if (m_indexs[1] == v) w = m_indexs[0]; + else if (m_indexs[2] == v) w = m_indexs[1]; + else return false; + + return true; +} + +/** + * Returns the next neighbour of the specified vertex index. + * @param v vertex index + * @param w vertex index + * @return true if this face contains the specified vertex index, false otherwise + */ +bool BOP_Face3::getNextVertex(BOP_Index v, BOP_Index &w) +{ + if (m_indexs[0] == v) w = m_indexs[1]; + else if (m_indexs[1] == v) w = m_indexs[2]; + else if (m_indexs[2] == v) w = m_indexs[0]; + else return false; + + return true; +} + +/** + * Replaces a face vertex index. + * @param oldIndex old vertex index + * @param newIndex new vertex index + */ +void BOP_Face3::replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex) +{ + /* if the old index really exists, and new index also exists already, + * don't create an edge with both vertices == newIndex */ + + if( (m_indexs[0] == oldIndex || m_indexs[1] == oldIndex || m_indexs[2] == oldIndex) && + (m_indexs[0] == newIndex || m_indexs[1] == newIndex || m_indexs[2] == newIndex) ) { + setTAG(BROKEN); + } + + if (m_indexs[0] == oldIndex) m_indexs[0] = newIndex; + else if (m_indexs[1] == oldIndex) m_indexs[1] = newIndex; + else if (m_indexs[2] == oldIndex) m_indexs[2] = newIndex; +} + +/******************************************************************************/ +/*** BOP_Face4 ***/ +/******************************************************************************/ + +/** + * Constructs a new quad face. + * @param v1 vertex index + * @param v2 vertex index + * @param v3 vertex index + * @param v4 vertex index + * @param plane face plane + * @param originalFace index of the original face + */ +BOP_Face4::BOP_Face4(BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4, MT_Plane3 plane, + BOP_Index originalFace): + BOP_Face(plane,originalFace) +{ + m_indexs[0] = v1; + m_indexs[1] = v2; + m_indexs[2] = v3; + m_indexs[3] = v4; + + m_size = 4; +} + +/** + * Returns if this face contains the specified vertex index. + * @param v vertex index + * @return true if this face contains the specified vertex index, false otherwise + */ +bool BOP_Face4::containsVertex(BOP_Index v) +{ + return (m_indexs[0] == v || m_indexs[1] == v || m_indexs[2] == v || m_indexs[3]==v); +} + +/** + * Returns the neighbours of the specified vertex index. + * @param v vertex index + * @param prev previous vertex index + * @param next next vertex index + * @param opp opposite vertex index + * @return true if this face contains the vertex index v, false otherwise + */ +bool BOP_Face4::getNeighbours(BOP_Index v, BOP_Index &prev, BOP_Index &next, BOP_Index &opp) +{ + if (m_indexs[0] == v) { + prev = m_indexs[3]; + next = m_indexs[1]; + opp = m_indexs[2]; + } + else if (m_indexs[1] == v) { + prev = m_indexs[0]; + next = m_indexs[2]; + opp = m_indexs[3]; + } + else if (m_indexs[2] == v) { + prev = m_indexs[1]; + next = m_indexs[3]; + opp = m_indexs[0]; + } + else if (m_indexs[3] == v) { + prev = m_indexs[2]; + next = m_indexs[0]; + opp = m_indexs[1]; + } + else return false; + + return true; +} + +/** + * Returns the previous neighbour of the specified vertex index. + * @param v vertex index + * @param w previous vertex index + * @return true if this face contains the specified vertex index, false otherwise + */ +bool BOP_Face4::getPreviousVertex(BOP_Index v, BOP_Index &w) +{ + if (m_indexs[0] == v) w = m_indexs[3]; + else if (m_indexs[1] == v) w = m_indexs[0]; + else if (m_indexs[2] == v) w = m_indexs[1]; + else if (m_indexs[3] == v) w = m_indexs[2]; + else return false; + + return true; +} + +/** + * Returns the next neighbour of the specified vertex index. + * @param v vertex index + * @param w next vertex index + * @return true if this face contains the specified vertex index, false otherwise + */ +bool BOP_Face4::getNextVertex(BOP_Index v, BOP_Index &w) +{ + if (m_indexs[0] == v) w = m_indexs[1]; + else if (m_indexs[1] == v) w = m_indexs[2]; + else if (m_indexs[2] == v) w = m_indexs[3]; + else if (m_indexs[3] == v) w = m_indexs[0]; + else return false; + + return true; +} + +/** + * Returns the opposite neighbour of the specified vertex index. + * @param v vertex index + * @param w opposite vertex index + * @return true if this face contains the specified vertex index, false otherwise + */ +bool BOP_Face4::getOppositeVertex(BOP_Index v, BOP_Index &w) +{ + if (m_indexs[0] == v) + w = m_indexs[2]; + else if (m_indexs[1] == v) + w = m_indexs[3]; + else if (m_indexs[2] == v) + w = m_indexs[0]; + else if (m_indexs[3] == v) + w = m_indexs[1]; + else + return false; + + return true; +} + +/** + * Replaces a face vertex index. + * @param oldIndex old vertex index + * @param newIndex new vertex index + */ +void BOP_Face4::replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex) +{ + if (m_indexs[0] == oldIndex) m_indexs[0] = newIndex; + else if (m_indexs[1] == oldIndex) m_indexs[1] = newIndex; + else if (m_indexs[2] == oldIndex) m_indexs[2] = newIndex; + else if (m_indexs[3] == oldIndex) m_indexs[3] = newIndex; +} + +/** + * Returns the relative edge index (1,2,3,4) for the specified vertex indexs. + * @param v1 vertex index + * @param v2 vertex index + * @param e relative edge index (1,2,3,4) + * @return true if (v1,v2) is an edge of this face, false otherwise + */ +bool BOP_Face4::getEdgeIndex(BOP_Index v1, BOP_Index v2, unsigned int &e) +{ + if (m_indexs[0] == v1) { + if (m_indexs[1] == v2) { + e = 1; + } + else if (m_indexs[3] == v2) { + e = 4; + } + else + return false; + } + else if (m_indexs[1] == v1) { + if (m_indexs[0] == v2) { + e = 1; + } + else if (m_indexs[2] == v2) { + e = 2; + } + else + return false; + } + else if (m_indexs[2] == v1) { + if (m_indexs[1] == v2) { + e = 2; + } + else if (m_indexs[3] == v2) { + e = 3; + } + else + return false; + } + else if (m_indexs[3] == v1) { + if (m_indexs[2] == v2) { + e = 3; + } + else if (m_indexs[0] == v2) { + e = 4; + } + else + return false; + } + else return false; + + return true; +} + +/** + * Implements operator <<. + */ +ostream &operator<<(ostream &stream, BOP_Face *f) +{ + char aux[20]; + BOP_stringTAG(f->m_tag,aux); + if (f->size()==3) { + stream << "Face[" << f->getVertex(0) << "," << f->getVertex(1) << ","; + stream << f->getVertex(2) << "] (" << aux << ") <-- " << f->m_originalFace; + } + else { + stream << "Face[" << f->getVertex(0) << "," << f->getVertex(1) << ","; + stream << f->getVertex(2) << "," << f->getVertex(3) << "] (" << aux; + stream << ") <-- " << f->m_originalFace; + } + + return stream; +} diff --git a/intern/boolop/intern/BOP_Face.h b/intern/boolop/intern/BOP_Face.h new file mode 100644 index 00000000000..1d854ec00ca --- /dev/null +++ b/intern/boolop/intern/BOP_Face.h @@ -0,0 +1,116 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_FACE_H +#define BOP_FACE_H + +#include "BOP_Tag.h" +#include "MT_Plane3.h" +#include "BOP_Indexs.h" +#include "BOP_BBox.h" +#include +#include +using namespace std; + +class BOP_Face; + +typedef vector BOP_Faces; +typedef vector::iterator BOP_IT_Faces; + +class BOP_Face +{ +private: + BOP_TAG m_tag; + MT_Plane3 m_plane; + BOP_Index m_originalFace; + +protected: + BOP_Index m_indexs[4]; + unsigned int m_size; + unsigned int m_split; + BOP_BBox *m_bbox; + +public: + BOP_Face(MT_Plane3 plane, BOP_Index originalFace); + virtual ~BOP_Face(){if (m_bbox) delete m_bbox;}; + inline MT_Plane3 getPlane() const {return m_plane;}; + inline void setPlane(const MT_Plane3 plane) {m_plane = plane;}; + inline BOP_TAG getTAG() const {return m_tag;}; + inline void setTAG(const BOP_TAG t) {m_tag = t;}; + inline BOP_Index getOriginalFace() const {return m_originalFace;}; + inline void setOriginalFace(const BOP_Index originalFace) {m_originalFace=originalFace;}; + inline BOP_Index getVertex(unsigned int i) const {return m_indexs[i];}; + inline void setVertex(const BOP_Index idx, const BOP_Index i) {m_indexs[idx]=i;}; + inline unsigned int getSplit() const {return m_split;}; + inline void setSplit(const unsigned int i) {m_split=i;}; + + void invert(); + inline void setBBox(const MT_Point3& p1,const MT_Point3& p2,const MT_Point3& p3) { + m_bbox = new BOP_BBox(p1, p2, p3);}; + inline BOP_BBox *getBBox() {return m_bbox;}; + inline void freeBBox(){if (m_bbox!=NULL) {delete m_bbox; m_bbox=NULL;} }; + + inline unsigned int size() const {return m_size;}; + + virtual bool getEdgeIndex(BOP_Index v1, BOP_Index v2, unsigned int &e) = 0; + virtual void replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex) = 0; + virtual bool containsVertex(BOP_Index v) = 0; + + friend ostream &operator<<(ostream &stream, BOP_Face *f); +}; + +class BOP_Face3: public BOP_Face +{ +public: + BOP_Face3(BOP_Index i, BOP_Index j, BOP_Index k, MT_Plane3 p, BOP_Index originalFace); + bool getEdgeIndex(BOP_Index v1, BOP_Index v2, unsigned int &e); + void replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex); + bool containsVertex(BOP_Index v); + + bool getNeighbours(BOP_Index v, BOP_Index &prev, BOP_Index &next); + bool getPreviousVertex(BOP_Index v, BOP_Index &w); + bool getNextVertex(BOP_Index v, BOP_Index &w); +}; + +class BOP_Face4: public BOP_Face +{ +public: + BOP_Face4(BOP_Index i, BOP_Index j, BOP_Index k, BOP_Index l, MT_Plane3 p, BOP_Index originalFace); + bool getEdgeIndex(BOP_Index v1, BOP_Index v2, unsigned int &e); + void replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex); + bool containsVertex(BOP_Index v); + + bool getNeighbours(BOP_Index v, BOP_Index &prev, BOP_Index &next, BOP_Index &opp); + bool getPreviousVertex(BOP_Index v, BOP_Index &w); + bool getNextVertex(BOP_Index v, BOP_Index &w); + bool getOppositeVertex(BOP_Index v, BOP_Index &w); +}; + +#endif diff --git a/intern/boolop/intern/BOP_Face2Face.cpp b/intern/boolop/intern/BOP_Face2Face.cpp new file mode 100644 index 00000000000..ef67e5dd24b --- /dev/null +++ b/intern/boolop/intern/BOP_Face2Face.cpp @@ -0,0 +1,1245 @@ +/** + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Marc Freixas, Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_Face2Face.h" +#include "BOP_BBox.h" + +// TAGS for segment classification in x-segment creation +// sA -> point of sA +// sB -> point of sB +// sX -> point of sA and SB +#define sA_sB 12 +#define sB_sA 21 +#define sX_sA 31 +#define sA_sX 13 +#define sX_sB 32 +#define sB_sX 23 +#define sX_sX 33 + +#define sA_sA_sB 112 +#define sB_sB_sA 221 +#define sB_sA_sA 211 +#define sA_sB_sB 122 +#define sA_sB_sA 121 +#define sB_sA_sB 212 +#define sA_sX_sB 132 +#define sB_sX_sA 231 +#define sX_sA_sB 312 +#define sX_sB_sA 321 +#define sA_sB_sX 123 +#define sB_sA_sX 213 + +#define sA_sA_sB_sB 1122 +#define sB_sB_sA_sA 2211 +#define sA_sB_sA_sB 1212 +#define sB_sA_sB_sA 2121 +#define sA_sB_sB_sA 1221 +#define sB_sA_sA_sB 2112 + +void BOP_intersectCoplanarFaces(BOP_Mesh* mesh, + BOP_Faces* facesB, + BOP_Face* faceA, + BOP_Face* faceB, + bool invert); + +void BOP_intersectCoplanarFaces(BOP_Mesh* mesh, + BOP_Faces* facesB, + BOP_Face* faceB, + BOP_Segment sA, + MT_Plane3 planeA, + bool invert); + +void BOP_intersectNonCoplanarFaces(BOP_Mesh* mesh, + BOP_Faces* facesA, + BOP_Faces* facesB, + BOP_Face* faceA, + BOP_Face* faceB); + +void BOP_getPoints(BOP_Mesh* mesh, + BOP_Face* faceA, + BOP_Segment& sA, + MT_Plane3 planeB, + MT_Point3* points, + unsigned int* faces, + unsigned int& size, + unsigned int faceValue); + +void BOP_mergeSort(MT_Point3 *points, unsigned int *face, unsigned int &size, bool &invertA, bool &invertB); + +void BOP_createXS(BOP_Mesh* mesh, + BOP_Face* faceA, + BOP_Face* faceB, + BOP_Segment sA, + BOP_Segment sB, + bool invert, + BOP_Segment* segments); + +void BOP_createXS(BOP_Mesh* mesh, + BOP_Face* faceA, + BOP_Face* faceB, + MT_Plane3 planeA, + MT_Plane3 planeB, + BOP_Segment sA, + BOP_Segment sB, + bool invert, + BOP_Segment* segments); + +BOP_Index BOP_getVertexIndex(BOP_Mesh* mesh, + MT_Point3 point, + unsigned int cfgA, + unsigned int cfgB, + BOP_Index vA, + BOP_Index vB, + bool invert); + +BOP_Index BOP_getVertexIndex(BOP_Mesh *mesh, MT_Point3 point, unsigned int cfg, BOP_Index v); + +void triangulate(BOP_Mesh *mesh, BOP_Faces *faces, BOP_Face *face, BOP_Segment s); + +BOP_Face *BOP_getOppositeFace(BOP_Mesh* mesh, + BOP_Faces* faces, + BOP_Face* face, + BOP_Edge* edge); + +bool BOP_overlap(MT_Vector3 normal, + MT_Point3 p1, + MT_Point3 p2, + MT_Point3 p3, + MT_Point3 q1, + MT_Point3 q2, + MT_Point3 q3); + +void BOP_mergeVertexs(BOP_Mesh *mesh, unsigned int firstFace); + + +/** + * Computes intersections between faces of both lists. + * @param mesh mesh that contains the faces, edges and vertices + * @param facesA set of faces from object A + * @param facesB set of faces from object B + * + * Two optimizations were added here: + * 1) keep the bounding box for a face once it's created; this is + * especially important for B faces, since they were being created and + * recreated over and over + * 2) associate a "split" index in the faceB vector with each A face; when + * an A face is split, we will not need to recheck any B faces have + * already been checked against that original A face + */ + +void BOP_Face2Face(BOP_Mesh *mesh, BOP_Faces *facesA, BOP_Faces *facesB) +{ + for(unsigned int idxFaceA=0;idxFaceAsize();idxFaceA++) { + BOP_Face *faceA = (*facesA)[idxFaceA]; + MT_Plane3 planeA = faceA->getPlane(); + MT_Point3 p1 = mesh->getVertex(faceA->getVertex(0))->getPoint(); + MT_Point3 p2 = mesh->getVertex(faceA->getVertex(1))->getPoint(); + MT_Point3 p3 = mesh->getVertex(faceA->getVertex(2))->getPoint(); + + /* get (or create) bounding box for face A */ + if( faceA->getBBox() == NULL ) + faceA->setBBox(p1,p2,p3); + BOP_BBox *boxA = faceA->getBBox(); + + /* start checking B faces with the previously stored split index */ + + for(unsigned int idxFaceB=faceA->getSplit(); + idxFaceBsize() && (faceA->getTAG() != BROKEN) && (faceA->getTAG() != PHANTOM);) { + BOP_Face *faceB = (*facesB)[idxFaceB]; + faceA->setSplit(idxFaceB); + if ((faceB->getTAG() != BROKEN) && (faceB->getTAG() != PHANTOM)) { + + /* get (or create) bounding box for face B */ + if( faceB->getBBox() == NULL ) + faceB->setBBox(mesh->getVertex(faceB->getVertex(0))->getPoint(), + mesh->getVertex(faceB->getVertex(1))->getPoint(), + mesh->getVertex(faceB->getVertex(2))->getPoint()); + BOP_BBox *boxB = faceB->getBBox(); + + if (boxA->intersect(*boxB)) { + MT_Plane3 planeB = faceB->getPlane(); + if (BOP_containsPoint(planeB,p1) && + BOP_containsPoint(planeB,p2) && + BOP_containsPoint(planeB,p3)) { + if (BOP_orientation(planeB,planeA)>0) { + BOP_intersectCoplanarFaces(mesh,facesB,faceA,faceB,false); + } + } + else { + BOP_intersectNonCoplanarFaces(mesh,facesA,facesB,faceA,faceB); + } + } + } + idxFaceB++; + } + } + + + // Clean broken faces from facesA + BOP_IT_Faces it; + it = facesA->begin(); + while (it != facesA->end()) { + BOP_Face *face = *it; + if (face->getTAG() == BROKEN) it = facesA->erase(it); + else it++; + } + /* + it = facesB->begin(); + while (it != facesB->end()) { + BOP_Face *face = *it; + if (face->getTAG() == BROKEN) it = facesB->erase(it); + else it++; + } + */ +} + +/** + * Computes intesections of coplanars faces from object A with faces from object B. + * @param mesh mesh that contains the faces, edges and vertices + * @param facesA set of faces from object A + * @param facesB set of faces from object B + */ +void BOP_sew(BOP_Mesh *mesh, BOP_Faces *facesA, BOP_Faces *facesB) +{ + for(unsigned int idxFaceB = 0; idxFaceB < facesB->size(); idxFaceB++) { + BOP_Face *faceB = (*facesB)[idxFaceB]; + MT_Plane3 planeB = faceB->getPlane(); + MT_Point3 p1 = mesh->getVertex(faceB->getVertex(0))->getPoint(); + MT_Point3 p2 = mesh->getVertex(faceB->getVertex(1))->getPoint(); + MT_Point3 p3 = mesh->getVertex(faceB->getVertex(2))->getPoint(); + + for(unsigned int idxFaceA = 0; + idxFaceA < facesA->size() && + faceB->getTAG() != BROKEN && + faceB->getTAG() != PHANTOM; + idxFaceA++) { + BOP_Face *faceA = (*facesA)[idxFaceA]; + if ((faceA->getTAG() != BROKEN)&&(faceA->getTAG() != PHANTOM)) { + MT_Plane3 planeA = faceA->getPlane(); + if (BOP_containsPoint(planeA,p1) && + BOP_containsPoint(planeA,p2) && + BOP_containsPoint(planeA,p3)) { + if (BOP_orientation(planeA,planeB) > 0) { + BOP_intersectCoplanarFaces(mesh,facesA,faceB,faceA,true); + } + } + } + } + } +} + +/** + * Triangulates faceB using edges of faceA that both are complanars. + * @param mesh mesh that contains the faces, edges and vertices + * @param facesB set of faces from object B + * @param faceA face from object A + * @param faceB face from object B + * @param invert indicates if faceA has priority over faceB + */ +void BOP_intersectCoplanarFaces(BOP_Mesh* mesh, + BOP_Faces* facesB, + BOP_Face* faceA, + BOP_Face* faceB, + bool invert) +{ + unsigned int oldSize = facesB->size(); + unsigned int originalFaceB = faceB->getOriginalFace(); + + MT_Point3 p1 = mesh->getVertex(faceA->getVertex(0))->getPoint(); + MT_Point3 p2 = mesh->getVertex(faceA->getVertex(1))->getPoint(); + MT_Point3 p3 = mesh->getVertex(faceA->getVertex(2))->getPoint(); + + MT_Vector3 normal(faceA->getPlane().x(),faceA->getPlane().y(),faceA->getPlane().z()); + + MT_Vector3 p1p2 = p2-p1; + + MT_Plane3 plane1((p1p2.cross(normal).normalized()),p1); + + BOP_Segment sA; + sA.m_cfg1 = BOP_Segment::createVertexCfg(1); + sA.m_v1 = faceA->getVertex(0); + sA.m_cfg2 = BOP_Segment::createVertexCfg(2); + sA.m_v2 = faceA->getVertex(1); + + BOP_intersectCoplanarFaces(mesh,facesB,faceB,sA,plane1,invert); + + MT_Vector3 p2p3 = p3-p2; + MT_Plane3 plane2((p2p3.cross(normal).normalized()),p2); + + sA.m_cfg1 = BOP_Segment::createVertexCfg(2); + sA.m_v1 = faceA->getVertex(1); + sA.m_cfg2 = BOP_Segment::createVertexCfg(3); + sA.m_v2 = faceA->getVertex(2); + + if (faceB->getTAG() == BROKEN) { + for(unsigned int idxFace = oldSize; idxFace < facesB->size(); idxFace++) { + BOP_Face *face = (*facesB)[idxFace]; + if (face->getTAG() != BROKEN && originalFaceB == face->getOriginalFace()) + BOP_intersectCoplanarFaces(mesh,facesB,face,sA,plane2,invert); + } + } + else { + BOP_intersectCoplanarFaces(mesh,facesB,faceB,sA,plane2,invert); + } + + MT_Vector3 p3p1 = p1-p3; + MT_Plane3 plane3((p3p1.cross(normal).normalized()),p3); + + sA.m_cfg1 = BOP_Segment::createVertexCfg(3); + sA.m_v1 = faceA->getVertex(2); + sA.m_cfg2 = BOP_Segment::createVertexCfg(1); + sA.m_v2 = faceA->getVertex(0); + + if (faceB->getTAG() == BROKEN) { + for(unsigned int idxFace = oldSize; idxFace < facesB->size(); idxFace++) { + BOP_Face *face = (*facesB)[idxFace]; + if (face->getTAG() != BROKEN && originalFaceB == face->getOriginalFace()) + BOP_intersectCoplanarFaces(mesh,facesB,face,sA,plane3,invert); + } + } + else { + BOP_intersectCoplanarFaces(mesh,facesB,faceB,sA,plane3,invert); + } +} + +/** + * Triangulates faceB using segment sA and planeA. + * @param mesh mesh that contains the faces, edges and vertices + * @param facesB set of faces from object B + * @param faceB face from object B + * @param sA segment to intersect with faceB + * @param planeA plane to intersect with faceB + * @param invert indicates if sA has priority over faceB + */ +void BOP_intersectCoplanarFaces(BOP_Mesh* mesh, + BOP_Faces* facesB, + BOP_Face* faceB, + BOP_Segment sA, + MT_Plane3 planeA, + bool invert) +{ + BOP_Segment sB = BOP_splitFace(planeA,mesh,faceB); + + if (BOP_Segment::isDefined(sB.m_cfg1)) { + BOP_Segment xSegment[2]; + BOP_createXS(mesh,NULL,faceB,planeA,MT_Plane3(),sA,sB,invert,xSegment); + if (BOP_Segment::isDefined(xSegment[1].m_cfg1)) { + unsigned int sizefaces = mesh->getNumFaces(); + triangulate(mesh,facesB,faceB,xSegment[1]); + BOP_mergeVertexs(mesh,sizefaces); + } + } +} + +/** + * Triangulates faceB using edges of faceA that both are not complanars. + * @param mesh mesh that contains the faces, edges and vertices + * @param facesB set of faces from object B + * @param faceA face from object A + * @param faceB face from object B + */ +void BOP_intersectNonCoplanarFaces(BOP_Mesh *mesh, + BOP_Faces *facesA, + BOP_Faces *facesB, + BOP_Face *faceA, + BOP_Face *faceB) +{ + // Obtain segments of faces A and B from the intersection with their planes + BOP_Segment sA = BOP_splitFace(faceB->getPlane(),mesh,faceA); + BOP_Segment sB = BOP_splitFace(faceA->getPlane(),mesh,faceB); + + if (BOP_Segment::isDefined(sA.m_cfg1) && BOP_Segment::isDefined(sB.m_cfg1)) { + // There is an intesection, build the X-segment + BOP_Segment xSegment[2]; + BOP_createXS(mesh,faceA,faceB,sA,sB,false,xSegment); + + unsigned int sizefaces = mesh->getNumFaces(); + triangulate(mesh,facesA,faceA,xSegment[0]); + BOP_mergeVertexs(mesh,sizefaces); + + sizefaces = mesh->getNumFaces(); + triangulate(mesh,facesB,faceB,xSegment[1]); + BOP_mergeVertexs(mesh,sizefaces); + } +} + +/** + * Tests if faces since firstFace have all vertexs non-coincident of colinear, otherwise repairs the mesh. + * @param mesh mesh that contains the faces, edges and vertices + * @param firstFace first face index to be tested + */ +void BOP_mergeVertexs(BOP_Mesh *mesh, unsigned int firstFace) +{ + unsigned int numFaces = mesh->getNumFaces(); + for(unsigned int idxFace = firstFace; idxFace < numFaces; idxFace++) { + BOP_Face *face = mesh->getFace(idxFace); + if ((face->getTAG() != BROKEN) && (face->getTAG() != PHANTOM)) { + MT_Point3 vertex1 = mesh->getVertex(face->getVertex(0))->getPoint(); + MT_Point3 vertex2 = mesh->getVertex(face->getVertex(1))->getPoint(); + MT_Point3 vertex3 = mesh->getVertex(face->getVertex(2))->getPoint(); + if (BOP_collinear(vertex1,vertex2,vertex3)) // collinear triangle + face->setTAG(PHANTOM); + } + } +} + +/** + * Obtains the points of the segment created from the intersection between faceA and planeB. + * @param mesh mesh that contains the faces, edges and vertices + * @param faceA intersected face + * @param sA segment of the intersection between faceA and planeB + * @param planeB intersected plane + * @param points array of points where the new points are saved + * @param faces array of relative face index to the points + * @param size size of arrays points and faces + * @param faceValue relative face index of new points + */ +void BOP_getPoints(BOP_Mesh* mesh, + BOP_Face* faceA, + BOP_Segment& sA, + MT_Plane3 planeB, + MT_Point3* points, + unsigned int* faces, + unsigned int& size, + unsigned int faceValue) +{ + MT_Point3 p1,p2; + + if (BOP_Segment::isDefined(sA.m_cfg1)) { + if (BOP_Segment::isEdge(sA.m_cfg1)) { + // the new point becomes of split faceA edge + p1 = BOP_splitEdge(planeB,mesh,faceA,BOP_Segment::getEdge(sA.m_cfg1)); + } + else if (BOP_Segment::isVertex(sA.m_cfg1)) { + // the new point becomes of vertex faceA + p1 = mesh->getVertex(BOP_Segment::getVertex(sA.m_v1))->getPoint(); + } + + if (BOP_Segment::isDefined(sA.m_cfg2)) { + if (BOP_Segment::isEdge(sA.m_cfg2)) { + p2 = BOP_splitEdge(planeB,mesh,faceA,BOP_Segment::getEdge(sA.m_cfg2)); + } + else if (BOP_Segment::isVertex(sA.m_cfg2)) { + p2 = mesh->getVertex(BOP_Segment::getVertex(sA.m_v2))->getPoint(); + } + points[size] = p1; + points[size+1] = p2; + faces[size] = faceValue; + faces[size+1] = faceValue; + size += 2; + } + + else { + points[size] = p1; + faces[size] = faceValue; + size++; + } + } +} + +/** + * Sorts the colinear points and relative face indices. + * @param points array of points where the new points are saved + * @param faces array of relative face index to the points + * @param size size of arrays points and faces + * @param invertA indicates if points of same relative face had been exchanged + */ +void BOP_mergeSort(MT_Point3 *points, unsigned int *face, unsigned int &size, bool &invertA, bool &invertB) { + MT_Point3 sortedPoints[4]; + unsigned int sortedFaces[4], position[4]; + unsigned int i; + if (size == 2) { + + // Trivial case, only test the merge ... + if (BOP_fuzzyZero(points[0].distance(points[1]))) { + face[0] = 3; + size--; + } + } + else { + // size is 3 or 4 + // Get segment extreme points + MT_Scalar maxDistance = -1; + for(i=0;i maxDistance){ + maxDistance = distance; + position[0] = i; + position[size-1] = j; + } + } + } + + // Get segment inner points + position[1] = position[2] = size; + for(i=0;i d2) { + unsigned int aux = position[1]; + position[1] = position[2]; + position[2] = aux; + } + } + + // Sort data + for(i=0;i 0 && sB.m_cfg1 > 0 . + * @param mesh mesh that contains the faces, edges and vertices + * @param faceA face of object A + * @param faceB face of object B + * @param sA segment of intersection between faceA and planeB + * @param sB segment of intersection between faceB and planeA + * @param invert indicates if faceA has priority over faceB + * @param segmemts array of the output x-segments + */ + void BOP_createXS(BOP_Mesh* mesh, + BOP_Face* faceA, + BOP_Face* faceB, + BOP_Segment sA, + BOP_Segment sB, + bool invert, + BOP_Segment* segments) { + BOP_createXS(mesh, faceA, faceB, faceA->getPlane(), faceB->getPlane(), + sA, sB, invert, segments); + } + +/** + * Computes the x-segment of two segments (the shared interval). The segments needs to have sA.m_cfg1 > 0 && sB.m_cfg1 > 0 . + * @param mesh mesh that contains the faces, edges and vertices + * @param faceA face of object A + * @param faceB face of object B + * @param planeA plane of faceA + * @param planeB plane of faceB + * @param sA segment of intersection between faceA and planeB + * @param sB segment of intersection between faceB and planeA + * @param invert indicates if faceA has priority over faceB + * @param segmemts array of the output x-segments + */ +void BOP_createXS(BOP_Mesh* mesh, + BOP_Face* faceA, + BOP_Face* faceB, + MT_Plane3 planeA, + MT_Plane3 planeB, + BOP_Segment sA, + BOP_Segment sB, + bool invert, + BOP_Segment* segments) +{ + MT_Point3 points[4]; // points of the segments + unsigned int face[4]; // relative face indexs (1 => faceA, 2 => faceB) + unsigned int size = 0; // size of points and relative face indexs + + BOP_getPoints(mesh, faceA, sA, planeB, points, face, size, 1); + BOP_getPoints(mesh, faceB, sB, planeA, points, face, size, 2); + + bool invertA = false; + bool invertB = false; + BOP_mergeSort(points,face,size,invertA,invertB); + + if (invertA) sA.invert(); + if (invertB) sB.invert(); + + // Compute the configuration label + unsigned int label = 0; + for(unsigned int i =0; i < size; i++) { + label = face[i]+label*10; + } + + if (size == 1) { + // Two coincident points + segments[0].m_cfg1 = sA.m_cfg1; + segments[1].m_cfg1 = sB.m_cfg1; + + segments[0].m_v1 = BOP_getVertexIndex(mesh, points[0], sA.m_cfg1, sB.m_cfg1, + sA.m_v1, sB.m_v1, invert); + segments[1].m_v1 = segments[0].m_v1; + segments[0].m_cfg2 = segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg(); + } + else if (size == 2) { + switch(label) { + // Two non-coincident points + case sA_sB: + case sB_sA: + segments[0].m_cfg1 = + segments[1].m_cfg1 = + segments[0].m_cfg2 = + segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + + // Two coincident points and one non-coincident of sA + case sA_sX: + segments[0].m_cfg1 = sA.m_cfg2; + segments[1].m_cfg1 = sB.m_cfg1; + segments[0].m_v1 = BOP_getVertexIndex(mesh, points[1], sA.m_cfg2, sB.m_cfg1, + sA.m_v2, sB.m_v1, invert); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = BOP_Segment::createUndefinedCfg(); + segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + case sX_sA: + segments[0].m_cfg1 = sA.m_cfg1; + segments[1].m_cfg1 = sB.m_cfg1; + segments[0].m_v1 = BOP_getVertexIndex(mesh, points[0], sA.m_cfg1, sB.m_cfg1, + sA.m_v1, sB.m_v1, invert); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = BOP_Segment::createUndefinedCfg(); + segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + + // Two coincident points and one non-coincident of sB + case sB_sX: + segments[0].m_cfg1 = sA.m_cfg1; + segments[1].m_cfg1 = sB.m_cfg2; + segments[0].m_v1 = BOP_getVertexIndex(mesh, points[1], sA.m_cfg1, sB.m_cfg2, + sA.m_v1, sB.m_v2, invert); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = BOP_Segment::createUndefinedCfg(); + segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + case sX_sB: + segments[0].m_cfg1 = sA.m_cfg1; + segments[1].m_cfg1 = sB.m_cfg1; + segments[0].m_v1 = BOP_getVertexIndex(mesh, points[0], sA.m_cfg1, sB.m_cfg1, + sA.m_v1, sB.m_v1, invert); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = BOP_Segment::createUndefinedCfg(); + segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + + // coincident points 2-2 + case sX_sX: + segments[0].m_cfg1 = sA.m_cfg1; + segments[1].m_cfg1 = sB.m_cfg1; + segments[0].m_v1 = BOP_getVertexIndex(mesh, points[0], sA.m_cfg1, sB.m_cfg1, + sA.m_v1, sB.m_v1, invert); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = sA.m_cfg2; + segments[1].m_cfg2 = sB.m_cfg2; + segments[0].m_v2 = BOP_getVertexIndex(mesh, points[1], sA.m_cfg2, sB.m_cfg2, + sA.m_v2, sB.m_v2, invert); + segments[1].m_v2 = segments[0].m_v2; + break; + + default: + break; + } + } + else if (size == 3) { + switch(label) { + case sA_sA_sB: + case sB_sA_sA: + case sA_sB_sB: + case sB_sB_sA: + segments[0].m_cfg1 = + segments[1].m_cfg1 = + segments[0].m_cfg2 = + segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + + case sA_sB_sA: + segments[1].m_v1 = BOP_getVertexIndex(mesh,points[1],sB.m_cfg1,sB.m_v1); + segments[1].m_cfg1 = sB.m_cfg1; + segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg(); + segments[0].m_cfg1 = sA.getConfig(); + segments[0].m_cfg2 = BOP_Segment::createUndefinedCfg(); + segments[0].m_v1 = segments[1].m_v1; + break; + + case sB_sA_sB: + segments[0].m_v1 = BOP_getVertexIndex(mesh,points[1],sA.m_cfg1,sA.m_v1); + segments[0].m_cfg1 = sA.m_cfg1; + segments[0].m_cfg2 = BOP_Segment::createUndefinedCfg(); + segments[1].m_cfg1 = sB.getConfig(); + segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg(); + segments[1].m_v1 = segments[0].m_v1; + break; + + case sA_sX_sB: + segments[0].m_cfg1 = sA.m_cfg2; + segments[1].m_cfg1 = sB.m_cfg1; + segments[0].m_v1 = BOP_getVertexIndex(mesh, points[1], sA.m_cfg2, sB.m_cfg1, + sA.m_v2, sB.m_v1, invert); + segments[1].m_v1 = segments[0].m_v1; + segments[0].m_cfg2 = BOP_Segment::createUndefinedCfg(); + segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + + case sB_sX_sA: + segments[0].m_cfg1 = sA.m_cfg1; + segments[1].m_cfg1 = sB.m_cfg2; + segments[0].m_v1 = BOP_getVertexIndex(mesh, points[1], sA.m_cfg1, sB.m_cfg2, + sA.m_v1, sB.m_v2, invert); + segments[1].m_v1 = segments[0].m_v1; + segments[0].m_cfg2 = BOP_Segment::createUndefinedCfg(); + segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + + case sX_sA_sB: + segments[0].m_cfg1 = sA.m_cfg1; + segments[1].m_cfg1 = sB.m_cfg1; + segments[0].m_v1 = BOP_getVertexIndex(mesh, points[0], sA.m_cfg1, sB.m_cfg1, + sA.m_v1, sB.m_v1, invert); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = sA.m_cfg2; + segments[1].m_cfg2 = sB.getConfig(); + segments[0].m_v2 = BOP_getVertexIndex(mesh, points[1], sA.m_cfg2, sA.m_v2); + segments[1].m_v2 = segments[0].m_v2; + break; + + case sX_sB_sA: + segments[0].m_cfg1 = sA.m_cfg1; + segments[1].m_cfg1 = sB.m_cfg1; + segments[0].m_v1 = BOP_getVertexIndex(mesh, points[0], sA.m_cfg1, sB.m_cfg1, + sA.m_v1, sB.m_v1, invert); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = sA.getConfig(); + segments[1].m_cfg2 = sB.m_cfg2; + segments[0].m_v2 = BOP_getVertexIndex(mesh,points[1],sB.m_cfg2,sB.m_v2); + segments[1].m_v2 = segments[0].m_v2; + break; + + case sA_sB_sX: + segments[0].m_cfg1 = sA.getConfig(); + segments[1].m_cfg1 = sB.m_cfg1; + segments[0].m_v1 = BOP_getVertexIndex(mesh,points[1],sB.m_cfg1,sB.m_v1); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = sA.m_cfg2; + segments[1].m_cfg2 = sB.m_cfg2; + segments[0].m_v2 = BOP_getVertexIndex(mesh, points[2], sA.m_cfg2, sB.m_cfg2, + sA.m_v2, sB.m_v2, invert); + segments[1].m_v2 = segments[0].m_v2; + break; + + case sB_sA_sX: + segments[0].m_cfg1 = sA.m_cfg1; + segments[1].m_cfg1 = sB.getConfig(); + segments[0].m_v1 = BOP_getVertexIndex(mesh,points[1],sA.m_cfg1,sA.m_v1); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = sA.m_cfg2; + segments[1].m_cfg2 = sB.m_cfg2; + segments[0].m_v2 = BOP_getVertexIndex(mesh, points[2], sA.m_cfg2, sB.m_cfg2, + sA.m_v2, sB.m_v2, invert); + segments[1].m_v2 = segments[0].m_v2; + break; + + default: + break; + } + } + else { + // 4! + switch(label) { + case sA_sA_sB_sB: + case sB_sB_sA_sA: + segments[0].m_cfg1 = + segments[1].m_cfg1 = + segments[0].m_cfg2 = + segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + + case sA_sB_sA_sB: + segments[0].m_cfg1 = sA.getConfig(); + segments[1].m_cfg1 = sB.m_cfg1; + segments[0].m_v1 = BOP_getVertexIndex(mesh,points[1],sB.m_cfg1,sB.m_v1); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = sA.m_cfg2; + segments[1].m_cfg2 = sB.getConfig(); + segments[0].m_v2 = BOP_getVertexIndex(mesh,points[2],sA.m_cfg2,sA.m_v2); + segments[1].m_v2 = segments[0].m_v2; + break; + + case sB_sA_sB_sA: + segments[0].m_cfg1 = sA.m_cfg1; + segments[1].m_cfg1 = sB.getConfig(); + segments[0].m_v1 = BOP_getVertexIndex(mesh,points[1],sA.m_cfg1,sA.m_v1); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = sA.getConfig(); + segments[1].m_cfg2 = sB.m_cfg2; + segments[0].m_v2 = BOP_getVertexIndex(mesh,points[2],sB.m_cfg2,sB.m_v2); + segments[1].m_v2 = segments[0].m_v2; + break; + + case sA_sB_sB_sA: + segments[0].m_cfg1 = sA.getConfig(); + segments[1].m_cfg1 = sB.m_cfg1; + segments[0].m_v1 = BOP_getVertexIndex(mesh,points[1],sB.m_cfg1,sB.m_v1); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = segments[0].m_cfg1; + segments[1].m_cfg2 = sB.m_cfg2; + segments[0].m_v2 = BOP_getVertexIndex(mesh,points[2],sB.m_cfg2,sB.m_v2); + segments[1].m_v2 = segments[0].m_v2; + break; + + case sB_sA_sA_sB: + segments[0].m_cfg1 = sA.m_cfg1; + segments[1].m_cfg1 = sB.getConfig(); + segments[0].m_v1 = BOP_getVertexIndex(mesh,points[1],sA.m_cfg1,sA.m_v1); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = sA.m_cfg2; + segments[1].m_cfg2 = segments[1].m_cfg1; + segments[0].m_v2 = BOP_getVertexIndex(mesh,points[2],sA.m_cfg2,sA.m_v2); + segments[1].m_v2 = segments[0].m_v2; + break; + + default: + break; + } + } + + segments[0].sort(); + segments[1].sort(); +} + +/** + * Computes the vertex index of a point. + * @param mesh mesh that contains the faces, edges and vertices + * @param point input point + * @param cfgA configuration of point on faceA + * @param cfgB configuration of point on faceB + * @param vA vertex index of point on faceA + * @param vB vertex index of point on faceB + * @param invert indicates if vA has priority over vB + * @return final vertex index in the mesh + */ +BOP_Index BOP_getVertexIndex(BOP_Mesh* mesh, + MT_Point3 point, + unsigned int cfgA, + unsigned int cfgB, + BOP_Index vA, + BOP_Index vB, + bool invert) +{ + if (BOP_Segment::isVertex(cfgA)) { // exists vertex index on A + if (BOP_Segment::isVertex(cfgB)) { // exists vertex index on B + // unify vertex indexs + if (invert) + return mesh->replaceVertexIndex(vA,vB); + else + return mesh->replaceVertexIndex(vB,vA); + } + else + return vA; + } + else {// does not exist vertex index on A + if (BOP_Segment::isVertex(cfgB)) // exists vertex index on B + return vB; + else {// does not exist vertex index on B + return mesh->addVertex(point); + } + } +} + +/** + * Computes the vertex index of a point. + * @param mesh mesh that contains the faces, edges and vertices + * @param cfg configuration of point + * @param v vertex index of point + * @return final vertex index in the mesh + */ +BOP_Index BOP_getVertexIndex(BOP_Mesh *mesh, MT_Point3 point, unsigned int cfg, BOP_Index v) +{ + if (BOP_Segment::isVertex(cfg)) // vertex existent + return v; + else { + return mesh->addVertex(point); + } +} + +/******************************************************************************/ +/*** TRIANGULATE ***/ +/******************************************************************************/ + +/** + * Triangulates the input face according to the specified segment. + * @param mesh mesh that contains the faces, edges and vertices + * @param faces set of faces that contains the original face and the new triangulated faces + * @param face face to be triangulated + * @param s segment used to triangulate face + */ +void triangulate(BOP_Mesh *mesh, BOP_Faces *faces, BOP_Face *face, BOP_Segment s) +{ + if (BOP_Segment::isUndefined(s.m_cfg1)) { + // Nothing to do + } + else if (BOP_Segment::isVertex(s.m_cfg1)) { + // VERTEX(v1) + VERTEX(v2) => nothing to do + } + else if (BOP_Segment::isEdge(s.m_cfg1)) { + if (BOP_Segment::isVertex(s.m_cfg2) || BOP_Segment::isUndefined(s.m_cfg2)) { + // EDGE(v1) + VERTEX(v2) + BOP_Edge *edge = mesh->getEdge(face,BOP_Segment::getEdge(s.m_cfg1)); + BOP_triangulateA(mesh,faces,face,s.m_v1,BOP_Segment::getEdge(s.m_cfg1)); + BOP_Face *opposite = BOP_getOppositeFace(mesh,faces,face,edge); + if (opposite != NULL) { + unsigned int e; + opposite->getEdgeIndex(edge->getVertex1(), edge->getVertex2(),e); + BOP_triangulateA(mesh, faces, opposite, s.m_v1, e); + } + } + else { + // EDGE(v1) + EDGE(v2) + if (BOP_Segment::getEdge(s.m_cfg1) == BOP_Segment::getEdge(s.m_cfg2)) { + // EDGE(v1) == EDGE(v2) + BOP_Edge *edge = mesh->getEdge(face,BOP_Segment::getEdge(s.m_cfg1)); + BOP_triangulateD(mesh, faces, face, s.m_v1, s.m_v2, + BOP_Segment::getEdge(s.m_cfg1)); + BOP_Face *opposite = BOP_getOppositeFace(mesh,faces,face,edge); + if (opposite != NULL) { + unsigned int e; + opposite->getEdgeIndex(edge->getVertex1(), edge->getVertex2(),e); + BOP_triangulateD(mesh, faces, opposite, s.m_v1, s.m_v2, e); + } + } + else { // EDGE(v1) != EDGE(v2) + BOP_Edge *edge1 = mesh->getEdge(face,BOP_Segment::getEdge(s.m_cfg1)); + BOP_Edge *edge2 = mesh->getEdge(face,BOP_Segment::getEdge(s.m_cfg2)); + BOP_triangulateE(mesh, faces, face, s.m_v1, s.m_v2, + BOP_Segment::getEdge(s.m_cfg1), + BOP_Segment::getEdge(s.m_cfg2)); + BOP_Face *opposite = BOP_getOppositeFace(mesh,faces,face,edge1); + if (opposite != NULL) { + unsigned int e; + opposite->getEdgeIndex(edge1->getVertex1(), edge1->getVertex2(),e); + BOP_triangulateA(mesh, faces, opposite, s.m_v1, e); + } + opposite = BOP_getOppositeFace(mesh,faces,face,edge2); + if (opposite != NULL) { + unsigned int e; + opposite->getEdgeIndex(edge2->getVertex1(), edge2->getVertex2(),e); + BOP_triangulateA(mesh, faces, opposite, s.m_v2, e); + } + } + } + } + else if (BOP_Segment::isIn(s.m_cfg1)) { + if (BOP_Segment::isVertex(s.m_cfg2) || BOP_Segment::isUndefined(s.m_cfg2)) { + // IN(v1) + VERTEX(v2) + BOP_triangulateB(mesh,faces,face,s.m_v1); + } + else if (BOP_Segment::isEdge(s.m_cfg2)) { + // IN(v1) + EDGE(v2) + BOP_Edge *edge = mesh->getEdge(face,BOP_Segment::getEdge(s.m_cfg2)); + BOP_triangulateF(mesh,faces,face,s.m_v1,s.m_v2,BOP_Segment::getEdge(s.m_cfg2)); + BOP_Face *opposite = BOP_getOppositeFace(mesh,faces,face,edge); + if (opposite != NULL) { + unsigned int e; + opposite->getEdgeIndex(edge->getVertex1(), edge->getVertex2(),e); + BOP_triangulateA(mesh, faces, opposite, s.m_v2, e); + } + } + else // IN(v1) + IN(v2) + BOP_triangulateC(mesh,faces,face,s.m_v1,s.m_v2); + } +} + +/** + * Returns if a face is in the set of faces. + * @param faces set of faces + * @param face face to be searched + * @return if the face is inside faces + */ +bool BOP_containsFace(BOP_Faces *faces, BOP_Face *face) +{ + const BOP_IT_Faces facesEnd = faces->end(); + for(BOP_IT_Faces it=faces->begin();it!=facesEnd;it++) + { + if (*it == face) + return true; + } + + return false; +} + +/** + * Returns the first face of faces that shares the input edge of face. + * @param mesh mesh that contains the faces, edges and vertices + * @param faces set of faces + * @param face input face + * @param edge face's edge + * @return first face that shares the edge of input face + */ +BOP_Face *BOP_getOppositeFace(BOP_Mesh* mesh, + BOP_Faces* faces, + BOP_Face* face, + BOP_Edge* edge) +{ + if (edge == NULL) + return NULL; + + BOP_Indexs auxfaces = edge->getFaces(); + const BOP_IT_Indexs auxfacesEnd = auxfaces.end(); + for(BOP_IT_Indexs it = auxfaces.begin(); it != auxfacesEnd; it++) { + BOP_Face *auxface = mesh->getFace(*it); + if ((auxface != face) && (auxface->getTAG()!=BROKEN) && + BOP_containsFace(faces,auxface)) { + return auxface; + } + } + + return NULL; +} + +/******************************************************************************/ +/*** OVERLAPPING ***/ +/******************************************************************************/ + +/** + * Removes faces from facesB that are overlapped with anyone from facesA. + * @param mesh mesh that contains the faces, edges and vertices + * @param facesA set of faces from object A + * @param facesB set of faces from object B + */ +void BOP_removeOverlappedFaces(BOP_Mesh *mesh, BOP_Faces *facesA, BOP_Faces *facesB) +{ + for(unsigned int i=0;isize();i++) { + BOP_Face *faceI = (*facesA)[i]; + if (faceI->getTAG()==BROKEN) continue; + bool overlapped = false; + MT_Point3 p1 = mesh->getVertex(faceI->getVertex(0))->getPoint(); + MT_Point3 p2 = mesh->getVertex(faceI->getVertex(1))->getPoint(); + MT_Point3 p3 = mesh->getVertex(faceI->getVertex(2))->getPoint(); + for(unsigned int j=0;jsize();) { + BOP_Face *faceJ = (*facesB)[j]; + if (faceJ->getTAG()!=BROKEN) { + MT_Plane3 planeJ = faceJ->getPlane(); + if (BOP_containsPoint(planeJ,p1) && BOP_containsPoint(planeJ,p2) + && BOP_containsPoint(planeJ,p3)) { + MT_Point3 q1 = mesh->getVertex(faceJ->getVertex(0))->getPoint(); + MT_Point3 q2 = mesh->getVertex(faceJ->getVertex(1))->getPoint(); + MT_Point3 q3 = mesh->getVertex(faceJ->getVertex(2))->getPoint(); + if (BOP_overlap(MT_Vector3(planeJ.x(),planeJ.y(),planeJ.z()), + p1,p2,p3,q1,q2,q3)) { + facesB->erase(facesB->begin()+j,facesB->begin()+(j+1)); + faceJ->setTAG(BROKEN); + overlapped = true; + } + else j++; + } + else j++; + }else j++; + } + if (overlapped) faceI->setTAG(OVERLAPPED); + } +} + +/** + * Computes if triangle p1,p2,p3 is overlapped with triangle q1,q2,q3. + * @param normal normal of the triangle p1,p2,p3 + * @param p1 point of first triangle + * @param p2 point of first triangle + * @param p3 point of first triangle + * @param q1 point of second triangle + * @param q2 point of second triangle + * @param q3 point of second triangle + * @return if there is overlapping between both triangles + */ +bool BOP_overlap(MT_Vector3 normal, MT_Point3 p1, MT_Point3 p2, MT_Point3 p3, + MT_Point3 q1, MT_Point3 q2, MT_Point3 q3) +{ + MT_Vector3 p1p2 = p2-p1; + MT_Plane3 plane1(p1p2.cross(normal),p1); + + MT_Vector3 p2p3 = p3-p2; + MT_Plane3 plane2(p2p3.cross(normal),p2); + + MT_Vector3 p3p1 = p1-p3; + MT_Plane3 plane3(p3p1.cross(normal),p3); + + BOP_TAG tag1 = BOP_createTAG(BOP_classify(q1,plane1)); + BOP_TAG tag2 = BOP_createTAG(BOP_classify(q1,plane2)); + BOP_TAG tag3 = BOP_createTAG(BOP_classify(q1,plane3)); + BOP_TAG tagQ1 = BOP_createTAG(tag1,tag2,tag3); + if (tagQ1 == IN_IN_IN) return true; + + tag1 = BOP_createTAG(BOP_classify(q2,plane1)); + tag2 = BOP_createTAG(BOP_classify(q2,plane2)); + tag3 = BOP_createTAG(BOP_classify(q2,plane3)); + BOP_TAG tagQ2 = BOP_createTAG(tag1,tag2,tag3); + if (tagQ2 == IN_IN_IN) return true; + + tag1 = BOP_createTAG(BOP_classify(q3,plane1)); + tag2 = BOP_createTAG(BOP_classify(q3,plane2)); + tag3 = BOP_createTAG(BOP_classify(q3,plane3)); + BOP_TAG tagQ3 = BOP_createTAG(tag1,tag2,tag3); + if (tagQ3 == IN_IN_IN) return true; + + if ((tagQ1 & OUT_OUT_OUT) == 0 && (tagQ2 & OUT_OUT_OUT) == 0 && + (tagQ3 & OUT_OUT_OUT) == 0) return true; + else return false; +} diff --git a/intern/boolop/intern/BOP_Face2Face.h b/intern/boolop/intern/BOP_Face2Face.h new file mode 100644 index 00000000000..09ed4edd076 --- /dev/null +++ b/intern/boolop/intern/BOP_Face2Face.h @@ -0,0 +1,44 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_FACE2FACE_H +#define BOP_FACE2FACE_H + +#include "BOP_Mesh.h" +#include "BOP_Segment.h" +#include "BOP_Triangulator.h" +#include "BOP_Splitter.h" +#include "BOP_BSPTree.h" + +void BOP_Face2Face(BOP_Mesh *mesh, BOP_Faces *facesA, BOP_Faces *facesB); +void BOP_sew(BOP_Mesh *mesh, BOP_Faces *facesA, BOP_Faces *facesB); +void BOP_removeOverlappedFaces(BOP_Mesh *mesh, BOP_Faces *facesA, BOP_Faces *facesB); + +#endif diff --git a/intern/boolop/intern/BOP_Indexs.h b/intern/boolop/intern/BOP_Indexs.h new file mode 100644 index 00000000000..c5546e73252 --- /dev/null +++ b/intern/boolop/intern/BOP_Indexs.h @@ -0,0 +1,41 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_Indexs_H +#define BOP_Indexs_H + +#include +using namespace std; + +typedef unsigned int BOP_Index; +typedef vector BOP_Indexs; +typedef vector::iterator BOP_IT_Indexs; + +#endif diff --git a/intern/boolop/intern/BOP_Interface.cpp b/intern/boolop/intern/BOP_Interface.cpp new file mode 100644 index 00000000000..3c61fd6c7b8 --- /dev/null +++ b/intern/boolop/intern/BOP_Interface.cpp @@ -0,0 +1,505 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include +#include "../extern/BOP_Interface.h" +#include "../../bsp/intern/BSP_CSGMesh_CFIterator.h" +#include "BOP_BSPTree.h" +#include "BOP_Mesh.h" +#include "BOP_Face2Face.h" +#include "BOP_Merge.h" +#include "BOP_Chrono.h" + +//#define DEBUG + +BoolOpState BOP_intersectionBoolOp(BOP_Mesh* meshC, + BOP_Faces* facesA, + BOP_Faces* facesB, + bool invertMeshA, + bool invertMeshB); +BOP_Face3* BOP_createFace(BOP_Mesh* mesh, + BOP_Index vertex1, + BOP_Index vertex2, + BOP_Index vertex3, + BOP_Index origFace); +void BOP_addMesh(BOP_Mesh* mesh, + BOP_Faces* meshFacesId, + CSG_FaceIteratorDescriptor& face_it, + CSG_VertexIteratorDescriptor& vertex_it, + bool invert); +BSP_CSGMesh* BOP_newEmptyMesh(); +BSP_CSGMesh* BOP_exportMesh(BOP_Mesh* inputMesh, + bool invert); +void BOP_meshFilter(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp); +void BOP_simplifiedMeshFilter(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp, bool inverted); +void BOP_meshClassify(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp); + +/** + * Performs a generic booleam operation, the entry point for external modules. + * @param opType Boolean operation type BOP_INTERSECTION, BOP_UNION, BOP_DIFFERENCE + * @param outputMesh Output mesh, the final result (the object C) + * @param obAFaces Object A faces list + * @param obAVertices Object A vertices list + * @param obBFaces Object B faces list + * @param obBVertices Object B vertices list + * @param interpFunc Interpolating function + * @return operation state: BOP_OK, BOP_NO_SOLID, BOP_ERROR + */ +BoolOpState BOP_performBooleanOperation(BoolOpType opType, + BSP_CSGMesh** outputMesh, + CSG_FaceIteratorDescriptor obAFaces, + CSG_VertexIteratorDescriptor obAVertices, + CSG_FaceIteratorDescriptor obBFaces, + CSG_VertexIteratorDescriptor obBVertices) +{ + #ifdef DEBUG + cout << "BEGIN BOP_performBooleanOperation" << endl; + #endif + + // Set invert flags depending on boolean operation type: + // INTERSECTION: A^B = and(A,B) + // UNION: A|B = not(and(not(A),not(B))) + // DIFFERENCE: A-B = and(A,not(B)) + bool invertMeshA = (opType == BOP_UNION); + bool invertMeshB = (opType != BOP_INTERSECTION); + bool invertMeshC = (opType == BOP_UNION); + + // Faces list for both objects, used by boolean op. + BOP_Faces meshAFacesId; + BOP_Faces meshBFacesId; + + // Build C-mesh, the output mesh + BOP_Mesh meshC; + + // Add A-mesh into C-mesh + BOP_addMesh(&meshC, &meshAFacesId, obAFaces, obAVertices, invertMeshA); + + // Add B-mesh into C-mesh + BOP_addMesh(&meshC, &meshBFacesId, obBFaces, obBVertices, invertMeshB); + + // for now, allow operations on non-manifold (non-solid) meshes +#if 0 + if (!meshC.isClosedMesh()) + return BOP_NO_SOLID; +#endif + + // Perform the intersection boolean operation. + BoolOpState result = BOP_intersectionBoolOp(&meshC, &meshAFacesId, &meshBFacesId, + invertMeshA, invertMeshB); + + // Invert the output mesh if is required + *outputMesh = BOP_exportMesh(&meshC, invertMeshC); + + #ifdef DEBUG + cout << "END BOP_performBooleanOperation" << endl; + #endif + + return result; +} + +/** + * Computes the intersection boolean operation. Creates a new mesh resulting from + * an intersection of two meshes. + * @param meshC Input & Output mesh + * @param facesA Mesh A faces list + * @param facesB Mesh B faces list + * @param invertMeshA determines if object A is inverted + * @param invertMeshB determines if object B is inverted + * @return operation state: BOP_OK, BOP_NO_SOLID, BOP_ERROR + */ +BoolOpState BOP_intersectionBoolOp(BOP_Mesh* meshC, + BOP_Faces* facesA, + BOP_Faces* facesB, + bool invertMeshA, + bool invertMeshB) +{ + #ifdef DEBUG + BOP_Chrono chrono; + float t = 0.0f; + float c = 0.0f; + chrono.start(); + cout << "---" << endl; + #endif + + // Create BSPs trees for mesh A & B + BOP_BSPTree bspA; + bspA.addMesh(meshC, *facesA); + + BOP_BSPTree bspB; + bspB.addMesh(meshC, *facesB); + + #ifdef DEBUG + c = chrono.stamp(); t += c; + cout << "Create BSP " << c << endl; + #endif + + unsigned int numVertices = meshC->getNumVertexs(); + + // mesh pre-filter + BOP_simplifiedMeshFilter(meshC, facesA, &bspB, invertMeshB); + if ((0.25*facesA->size()) > bspB.getDeep()) + BOP_meshFilter(meshC, facesA, &bspB); + + BOP_simplifiedMeshFilter(meshC, facesB, &bspA, invertMeshA); + if ((0.25*facesB->size()) > bspA.getDeep()) + BOP_meshFilter(meshC, facesB, &bspA); + + #ifdef DEBUG + c = chrono.stamp(); t += c; + cout << "mesh Filter " << c << endl; + #endif + + // Face 2 Face + BOP_Face2Face(meshC,facesA,facesB); + + #ifdef DEBUG + c = chrono.stamp(); t += c; + cout << "Face2Face " << c << endl; + #endif + + // BSP classification + BOP_meshClassify(meshC,facesA,&bspB); + BOP_meshClassify(meshC,facesB,&bspA); + + #ifdef DEBUG + c = chrono.stamp(); t += c; + cout << "Classification " << c << endl; + #endif + + // Process overlapped faces + BOP_removeOverlappedFaces(meshC,facesA,facesB); + + #ifdef DEBUG + c = chrono.stamp(); t += c; + cout << "Remove overlap " << c << endl; + #endif + + // Sew two meshes + BOP_sew(meshC,facesA,facesB); + + #ifdef DEBUG + c = chrono.stamp(); t += c; + cout << "Sew " << c << endl; + #endif + + // Merge faces + BOP_Merge::getInstance().mergeFaces(meshC,numVertices); + + #ifdef DEBUG + c = chrono.stamp(); t += c; + cout << "Merge faces " << c << endl; + cout << "Total " << t << endl; + // Test integrity + meshC->testMesh(); + #endif + + return BOP_OK; +} + +/** + * Preprocess to filter no collisioned faces. + * @param meshC Input & Output mesh data + * @param faces Faces list to test + * @param bsp BSP tree used to filter + */ +void BOP_meshFilter(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp) +{ + BOP_IT_Faces it; + BOP_TAG tag; + + it = faces->begin(); + while (it!=faces->end()) { + BOP_Face *face = *it; + MT_Point3 p1 = meshC->getVertex(face->getVertex(0))->getPoint(); + MT_Point3 p2 = meshC->getVertex(face->getVertex(1))->getPoint(); + MT_Point3 p3 = meshC->getVertex(face->getVertex(2))->getPoint(); + if ((tag = bsp->classifyFace(p1,p2,p3,face->getPlane()))==OUT||tag==OUTON) { + face->setTAG(BROKEN); + it = faces->erase(it); + } + else if (tag == IN) { + it = faces->erase(it); + }else{ + it++; + } + } +} + +/** + * Pre-process to filter no collisioned faces. + * @param meshC Input & Output mesh data + * @param faces Faces list to test + * @param bsp BSP tree used to filter + * @param inverted determines if the object is inverted + */ +void BOP_simplifiedMeshFilter(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp, bool inverted) +{ + BOP_IT_Faces it; + + it = faces->begin(); + while (it!=faces->end()) { + BOP_Face *face = *it; + MT_Point3 p1 = meshC->getVertex(face->getVertex(0))->getPoint(); + MT_Point3 p2 = meshC->getVertex(face->getVertex(1))->getPoint(); + MT_Point3 p3 = meshC->getVertex(face->getVertex(2))->getPoint(); + if (bsp->filterFace(p1,p2,p3,face)==OUT) { + if (!inverted) face->setTAG(BROKEN); + it = faces->erase(it); + } + else { + it++; + } + } +} + +/** + * Process to classify the mesh faces using a bsp tree. + * @param meshC Input & Output mesh data + * @param faces Faces list to classify + * @param bsp BSP tree used to face classify + */ +void BOP_meshClassify(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp) +{ + for(BOP_IT_Faces face=faces->begin();face!=faces->end();face++) { + if ((*face)->getTAG()!=BROKEN) { + MT_Point3 p1 = meshC->getVertex((*face)->getVertex(0))->getPoint(); + MT_Point3 p2 = meshC->getVertex((*face)->getVertex(1))->getPoint(); + MT_Point3 p3 = meshC->getVertex((*face)->getVertex(2))->getPoint(); + if (bsp->simplifiedClassifyFace(p1,p2,p3,(*face)->getPlane())!=IN) { + (*face)->setTAG(BROKEN); + } + } + } +} + +/** + * Returns a new mesh triangle. + * @param meshC Input & Output mesh data + * @param vertex1 first vertex of the new face + * @param vertex2 second vertex of the new face + * @param vertex3 third vertex of the new face + * @param origFace identifier of the new face + * @return new the new face + */ +BOP_Face3 *BOP_createFace3(BOP_Mesh* mesh, + BOP_Index vertex1, + BOP_Index vertex2, + BOP_Index vertex3, + BOP_Index origFace) +{ + MT_Point3 p1 = mesh->getVertex(vertex1)->getPoint(); + MT_Point3 p2 = mesh->getVertex(vertex2)->getPoint(); + MT_Point3 p3 = mesh->getVertex(vertex3)->getPoint(); + MT_Plane3 plane(p1,p2,p3); + + return new BOP_Face3(vertex1, vertex2, vertex3, plane, origFace); +} + +/** + * Adds mesh information into destination mesh. + * @param mesh input/output mesh, destination for the new mesh data + * @param meshFacesId output mesh faces, contains an added faces list + * @param face_it faces iterator + * @param vertex_it vertices iterator + * @param inverted if TRUE adding inverted faces, non-inverted otherwise + */ +void BOP_addMesh(BOP_Mesh* mesh, + BOP_Faces* meshFacesId, + CSG_FaceIteratorDescriptor& face_it, + CSG_VertexIteratorDescriptor& vertex_it, + bool invert) +{ + unsigned int vtxIndexOffset = mesh->getNumVertexs(); + + // The size of the vertex data array will be at least the number of faces. + CSG_IVertex vertex; + while (!vertex_it.Done(vertex_it.it)) { + vertex_it.Fill(vertex_it.it,&vertex); + MT_Point3 pos(vertex.position); + mesh->addVertex(pos); + vertex_it.Step(vertex_it.it); + } + + CSG_IFace face; + + // now for the polygons. + // we may need to decalare some memory for user defined face properties. + + BOP_Face3 *newface; + + while (!face_it.Done(face_it.it)) { + face_it.Fill(face_it.it,&face); + + // Let's not rely on quads being coplanar - especially if they + // are coming out of that soup of code from blender... + if (face.vertex_number == 4){ + // QUAD + if (invert) { + newface = BOP_createFace3(mesh, + face.vertex_index[2] + vtxIndexOffset, + face.vertex_index[0] + vtxIndexOffset, + face.vertex_index[3] + vtxIndexOffset, + face.orig_face); + meshFacesId->push_back(newface); + mesh->addFace(newface); + newface = BOP_createFace3(mesh, + face.vertex_index[2] + vtxIndexOffset, + face.vertex_index[1] + vtxIndexOffset, + face.vertex_index[0] + vtxIndexOffset, + face.orig_face); + meshFacesId->push_back(newface); + mesh->addFace(newface); + } + else { + newface = BOP_createFace3(mesh, + face.vertex_index[0] + vtxIndexOffset, + face.vertex_index[2] + vtxIndexOffset, + face.vertex_index[3] + vtxIndexOffset, + face.orig_face); + meshFacesId->push_back(newface); + mesh->addFace(newface); + newface = BOP_createFace3(mesh, + face.vertex_index[0] + vtxIndexOffset, + face.vertex_index[1] + vtxIndexOffset, + face.vertex_index[2] + vtxIndexOffset, + face.orig_face); + meshFacesId->push_back(newface); + mesh->addFace(newface); + } + } + else { + // TRIANGLES + if (invert) { + newface = BOP_createFace3(mesh, + face.vertex_index[2] + vtxIndexOffset, + face.vertex_index[1] + vtxIndexOffset, + face.vertex_index[0] + vtxIndexOffset, + face.orig_face); + meshFacesId->push_back(newface); + mesh->addFace(newface); + } + else { + newface = BOP_createFace3(mesh, + face.vertex_index[0] + vtxIndexOffset, + face.vertex_index[1] + vtxIndexOffset, + face.vertex_index[2] + vtxIndexOffset, + face.orig_face); + meshFacesId->push_back(newface); + mesh->addFace(newface); + } + } + + face_it.Step(face_it.it); + } +} + +/** + * Returns an empty mesh with the specified properties. + * @return a new empty mesh + */ +BSP_CSGMesh* BOP_newEmptyMesh() +{ + BSP_CSGMesh* mesh = BSP_CSGMesh::New(); + if (mesh == NULL) return mesh; + + vector* vertices = new vector; + + mesh->SetVertices(vertices); + + return mesh; +} + +/** + * Exports a BOP_Mesh to a BSP_CSGMesh. + * @param mesh Input mesh + * @param invert if TRUE export with inverted faces, no inverted otherwise + * @return the corresponding new BSP_CSGMesh + */ +BSP_CSGMesh* BOP_exportMesh(BOP_Mesh* mesh, + bool invert) +{ + BSP_CSGMesh* outputMesh = BOP_newEmptyMesh(); + + if (outputMesh == NULL) return NULL; + + // vtx index dictionary, to translate indeces from input to output. + map dic; + map::iterator itDic; + + unsigned int count = 0; + + // Add a new face for each face in the input list + BOP_Faces faces = mesh->getFaces(); + BOP_Vertexs vertexs = mesh->getVertexs(); + + for (BOP_IT_Faces face = faces.begin(); face != faces.end(); face++) { + if ((*face)->getTAG()!=BROKEN){ + // Add output face + outputMesh->FaceSet().push_back(BSP_MFace()); + BSP_MFace& outFace = outputMesh->FaceSet().back(); + + // Copy face + outFace.m_verts.clear(); + outFace.m_plane = (*face)->getPlane(); + outFace.m_orig_face = (*face)->getOriginalFace(); + + // invert face if is required + if (invert) (*face)->invert(); + + // Add the face vertex if not added yet + for (unsigned int pos=0;pos<(*face)->size();pos++) { + BSP_VertexInd outVtxId; + BOP_Index idVertex = (*face)->getVertex(pos); + itDic = dic.find(idVertex); + if (itDic == dic.end()) { + // The vertex isn't added yet + outVtxId = BSP_VertexInd(outputMesh->VertexSet().size()); + BSP_MVertex outVtx((mesh->getVertex(idVertex))->getPoint()); + outVtx.m_edges.clear(); + outputMesh->VertexSet().push_back(outVtx); + dic[idVertex] = outVtxId; + count++; + } + else { + // The vertex is added + outVtxId = BSP_VertexInd(itDic->second); + } + + outFace.m_verts.push_back(outVtxId); + } + } + } + + // Build the mesh edges using topological informtion + outputMesh->BuildEdges(); + + return outputMesh; +} diff --git a/intern/boolop/intern/BOP_MathUtils.cpp b/intern/boolop/intern/BOP_MathUtils.cpp new file mode 100644 index 00000000000..e0d96b465ee --- /dev/null +++ b/intern/boolop/intern/BOP_MathUtils.cpp @@ -0,0 +1,471 @@ +/** + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Marc Freixas, Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_MathUtils.h" +#include +using namespace std; + +/** + * Compares two scalars with EPSILON accuracy. + * @param A scalar + * @param B scalar + * @return 1 if A > B, -1 if A < B, 0 otherwise + */ +int BOP_comp(const MT_Scalar A, const MT_Scalar B) +{ +#ifndef VAR_EPSILON + if (A >= B + BOP_EPSILON) return 1; + else if (B >= A + BOP_EPSILON) return -1; + else return 0; +#else + int expA, expB; + float mant; + frexp(A, &expA); /* get exponents of each number */ + frexp(B, &expB); + + if(expA < expB) /* find the larger exponent */ + expA = expB; + mant = frexp((A-B), &expB); /* get exponent of the difference */ + /* mantissa will only be zero is (A-B) is really zero; otherwise, also + * also allow a "reasonably" small exponent or "reasonably large" + * difference in exponents to be considers "close to zero" */ + if( mant == 0 || expB < -30 || expA - expB > 31) return 0; + else if( mant > 0) return 1; + else return -1; +#endif +} + +/** + * Compares a scalar with EPSILON accuracy. + * @param A scalar + * @return 1 if A > 0, -1 if A < 0, 0 otherwise + */ +int BOP_comp0(const MT_Scalar A) +{ + if (A >= BOP_EPSILON) return 1; + else if (0 >= A + BOP_EPSILON) return -1; + else return 0; +} + +/** + * Compares two scalar triplets with EPSILON accuracy. + * @param A scalar triplet + * @param B scalar triplet + * @return 1 if A > B, -1 if A < B, 0 otherwise + */ +int BOP_comp(const MT_Tuple3& A, const MT_Tuple3& B) +{ +#ifndef VAR_EPSILON + if (A.x() >= (B.x() + BOP_EPSILON)) return 1; + else if (B.x() >= (A.x() + BOP_EPSILON)) return -1; + else if (A.y() >= (B.y() + BOP_EPSILON)) return 1; + else if (B.y() >= (A.y() + BOP_EPSILON)) return -1; + else if (A.z() >= (B.z() + BOP_EPSILON)) return 1; + else if (B.z() >= (A.z() + BOP_EPSILON)) return -1; + else return 0; +#else + int result = BOP_comp(A.x(), B.x()); + if (result != 0) return result; + result = BOP_comp(A.y(), B.y()); + if (result != 0) return result; + return BOP_comp(A.z(), B.z()); +#endif +} + +/** + * Compares two scalars strictly. + * @param A scalar + * @param B scalar + * @return 1 if A > B, -1 if A < B, 0 otherwise + */ +int BOP_exactComp(const MT_Scalar A, const MT_Scalar B) +{ + if (A > B) return 1; + else if (B > A) return -1; + else return 0; +} +/** + * Compares two scalar strictly. + * @param A scalar triplet + * @param B scalar triplet + * @return 1 if A > B, -1 if A < B, 0 otherwise + */ +int BOP_exactComp(const MT_Tuple3& A, const MT_Tuple3& B) +{ + if (A.x() > B.x()) return 1; + else if (B.x() > A.x()) return -1; + else if (A.y() > B.y()) return 1; + else if (B.y() > A.y()) return -1; + else if (A.z() > B.z()) return 1; + else if (B.z() > A.z()) return -1; + else return 0; +} + +/** + * Returns if p1 is between p2 and p3 and lay on the same line (are collinears). + * @param p1 point + * @param p2 point + * @param p3 point + * @return true if p1 is between p2 and p3 and lay on the same line, false otherwise + */ +bool BOP_between(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3) +{ + MT_Scalar distance = p2.distance(p3); + return (p1.distance(p2) < distance && p1.distance(p3) < distance) && BOP_collinear(p1,p2,p3); +} + +/** + * Returns if three points lay on the same line (are collinears). + * @param p1 point + * @param p2 point + * @param p3 point + * @return true if the three points lay on the same line, false otherwise + */ +bool BOP_collinear(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3) +{ + if( BOP_comp(p1,p2) == 0 || BOP_comp(p2,p3) == 0 ) return true; + + MT_Vector3 v1 = p2 - p1; + MT_Vector3 v2 = p3 - p2; + + /* normalize vectors before taking their cross product, so its length + * has some actual meaning */ + // if(MT_fuzzyZero(v1.length()) || MT_fuzzyZero(v2.length())) return true; + v1.normalize(); + v2.normalize(); + + MT_Vector3 w = v1.cross(v2); + + return (BOP_fuzzyZero(w.x()) && BOP_fuzzyZero(w.y()) && BOP_fuzzyZero(w.z())); +} + +/** + * Returns if a quad (coplanar) is convex. + * @return true if the quad is convex, false otherwise + */ +bool BOP_convex(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, const MT_Point3& p4) +{ + MT_Vector3 v1 = p3 - p1; + MT_Vector3 v2 = p4 - p2; + MT_Vector3 quadPlane = v1.cross(v2); + // plane1 is the perpendicular plane that contains the quad diagonal (p2,p4) + MT_Plane3 plane1(quadPlane.cross(v2),p2); + // if p1 and p3 are classified in the same region, the quad is not convex + if (BOP_classify(p1,plane1) == BOP_classify(p3,plane1)) return false; + else { + // Test the other quad diagonal (p1,p3) and perpendicular plane + MT_Plane3 plane2(quadPlane.cross(v1),p1); + // if p2 and p4 are classified in the same region, the quad is not convex + return (BOP_classify(p2,plane2) != BOP_classify(p4,plane2)); + } +} + +/** + * Returns if a quad (coplanar) is concave and where is the split edge. + * @return 0 if is convex, 1 if is concave and split edge is p1-p3 and -1 if is + * cancave and split edge is p2-p4. + */ +int BOP_concave(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, const MT_Point3& p4) +{ + MT_Vector3 v1 = p3 - p1; + MT_Vector3 v2 = p4 - p2; + MT_Vector3 quadPlane = v1.cross(v2); + // plane1 is the perpendicular plane that contains the quad diagonal (p2,p4) + MT_Plane3 plane1(quadPlane.cross(v2),p2); + // if p1 and p3 are classified in the same region, the quad is not convex + if (BOP_classify(p1,plane1) == BOP_classify(p3,plane1)) return 1; + else { + // Test the other quad diagonal (p1,p3) and perpendicular plane + MT_Plane3 plane2(quadPlane.cross(v1),p1); + // if p2 and p4 are classified in the same region, the quad is not convex + if (BOP_classify(p2,plane2) == BOP_classify(p4,plane2)) return -1; + else return 0; + } +} + +/** + * Computes the intersection between two lines (on the same plane). + * @param vL1 first line vector + * @param pL1 first line point + * @param vL2 second line vector + * @param pL2 second line point + * @param intersection intersection point (if exists) + * @return false if lines are parallels, true otherwise + */ +bool BOP_intersect(const MT_Vector3& vL1, const MT_Point3& pL1, const MT_Vector3& vL2, + const MT_Point3& pL2, MT_Point3 &intersection) +{ + // NOTE: + // If the lines aren't on the same plane, the intersection point will not be valid. + // So be careful !! + + MT_Scalar t = -1; + MT_Scalar den = (vL1.y()*vL2.x() - vL1.x() * vL2.y()); + + if (!BOP_fuzzyZero(den)) { + t = (pL2.y()*vL1.x() - vL1.y()*pL2.x() + pL1.x()*vL1.y() - pL1.y()*vL1.x()) / den ; + } + else { + den = (vL1.y()*vL2.z() - vL1.z() * vL2.y()); + if (!BOP_fuzzyZero(den)) { + t = (pL2.y()*vL1.z() - vL1.y()*pL2.z() + pL1.z()*vL1.y() - pL1.y()*vL1.z()) / den ; + } + else { + den = (vL1.x()*vL2.z() - vL1.z() * vL2.x()); + if (!BOP_fuzzyZero(den)) { + t = (pL2.x()*vL1.z() - vL1.x()*pL2.z() + pL1.z()*vL1.x() - pL1.x()*vL1.z()) / den ; + } + else { + return false; + } + } + } + + intersection.setValue(vL2.x()*t + pL2.x(), vL2.y()*t + pL2.y(), vL2.z()*t + pL2.z()); + return true; +} + +/** + * Returns the center of the circle defined by three points. + * @param p1 point + * @param p2 point + * @param p3 point + * @param center circle center + * @return false if points are collinears, true otherwise + */ +bool BOP_getCircleCenter(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, + MT_Point3& center) +{ + // Compute quad plane + MT_Vector3 p1p2 = p2-p1; + MT_Vector3 p1p3 = p3-p1; + MT_Plane3 plane1(p1,p2,p3); + MT_Vector3 plane = plane1.Normal(); + + // Compute first line vector, perpendicular to plane vector and edge (p1,p2) + MT_Vector3 vL1 = p1p2.cross(plane); + if( MT_fuzzyZero(vL1.length() ) ) + return false; + vL1.normalize(); + + // Compute first line point, middle point of edge (p1,p2) + MT_Point3 pL1 = p1.lerp(p2, 0.5); + + // Compute second line vector, perpendicular to plane vector and edge (p1,p3) + MT_Vector3 vL2 = p1p3.cross(plane); + if( MT_fuzzyZero(vL2.length() ) ) + return false; + vL2.normalize(); + + // Compute second line point, middle point of edge (p1,p3) + MT_Point3 pL2 = p1.lerp(p3, 0.5); + + // Compute intersection (the lines lay on the same plane, so the intersection exists + // only if they are not parallel!!) + return BOP_intersect(vL1,pL1,vL2,pL2,center); +} + +/** + * Returns if points q is inside the circle defined by p1, p2 and p3. + * @param p1 point + * @param p2 point + * @param p3 point + * @param q point + * @return true if p4 or p5 are inside the circle, false otherwise. If + * the circle does not exist (p1, p2 and p3 are collinears) returns true + */ +bool BOP_isInsideCircle(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, + const MT_Point3& q) +{ + MT_Point3 center; + + // Compute circle center + bool ok = BOP_getCircleCenter(p1,p2,p3,center); + + if (!ok) return true; // p1,p2 and p3 are collinears + + // Check if q is inside the circle + MT_Scalar r = p1.distance(center); + MT_Scalar d = q.distance(center); + return (BOP_comp(d,r) <= 0); +} + +/** + * Returns if points p4 or p5 is inside the circle defined by p1, p2 and p3. + * @param p1 point + * @param p2 point + * @param p3 point + * @param p4 point + * @param p5 point + * @return true if p4 or p5 is inside the circle, false otherwise. If + * the circle does not exist (p1, p2 and p3 are collinears) returns true + */ +bool BOP_isInsideCircle(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, + const MT_Point3& p4, const MT_Point3& p5) +{ + MT_Point3 center; + bool ok = BOP_getCircleCenter(p1,p2,p3,center); + + if (!ok) return true; // Collinear points! + + // Check if p4 or p5 is inside the circle + MT_Scalar r = p1.distance(center); + MT_Scalar d1 = p4.distance(center); + MT_Scalar d2 = p5.distance(center); + return (BOP_comp(d1,r) <= 0 || BOP_comp(d2,r) <= 0); +} + +/** + * Returns if two planes share the same orientation. + * @return >0 if planes share the same orientation + */ +MT_Scalar BOP_orientation(const MT_Plane3& p1, const MT_Plane3& p2) +{ + // Dot product between plane normals + return (p1.x()*p2.x() + p1.y()*p2.y() + p1.z()*p2.z()); +} + +/** + * Classifies a point according to the specified plane with EPSILON accuracy. + * @param p point + * @param plane plane + * @return >0 if the point is above (OUT), + * =0 if the point is on (ON), + * <0 if the point is below (IN) + */ +int BOP_classify(const MT_Point3& p, const MT_Plane3& plane) +{ + // Compare plane - point distance with zero + return BOP_comp0(plane.signedDistance(p)); +} + +/** + * Intersects a plane with the line that contains the specified points. + * @param plane split plane + * @param p1 first line point + * @param p2 second line point + * @return intersection between plane and line that contains p1 and p2 + */ +MT_Point3 BOP_intersectPlane(const MT_Plane3& plane, const MT_Point3& p1, const MT_Point3& p2) +{ + // Compute intersection between plane and line ... + // + // L: (p2-p1)lambda + p1 + // + // supposes resolve equation ... + // + // coefA*((p2.x - p1.y)*lambda + p1.x) + ... + coefD = 0 + + MT_Point3 intersection = MT_Point3(0,0,0); //never ever return anything undefined! + MT_Scalar den = plane.x()*(p2.x()-p1.x()) + + plane.y()*(p2.y()-p1.y()) + + plane.z()*(p2.z()-p1.z()); + if (den != 0) { + MT_Scalar lambda = (-plane.x()*p1.x()-plane.y()*p1.y()-plane.z()*p1.z()-plane.w()) / den; + intersection.setValue(p1.x() + (p2.x()-p1.x())*lambda, + p1.y() + (p2.y()-p1.y())*lambda, + p1.z() + (p2.z()-p1.z())*lambda); + return intersection; + } + return intersection; +} + +/** + * Returns if a plane contains a point with EPSILON accuracy. + * @param plane plane + * @param point point + * @return true if the point is on the plane, false otherwise + */ +bool BOP_containsPoint(const MT_Plane3& plane, const MT_Point3& point) +{ + return BOP_fuzzyZero(plane.signedDistance(point)); +} + +/** + * Pre: p0, p1 and p2 is a triangle and q is an interior point. + * @param p0 point + * @param p1 point + * @param p2 point + * @param q point + * @return intersection point I + * v + * (p0)-----(I)----->(p1) + * \ ^ / + * \ |w / + * \ | / + * \ (q) / + * \ | / + * \ | / + * \ | / + * (p2) + * + * v = P1-P2 + * w = P3-Q + * r0(t) = v*t+P1 + * r1(t) = w*t+P3 + * I = r0^r1 + */ +MT_Point3 BOP_4PointIntersect(const MT_Point3& p0, const MT_Point3& p1, const MT_Point3& p2, + const MT_Point3& q) +{ + MT_Vector3 v(p0.x()-p1.x(), p0.y()-p1.y(), p0.z()-p1.z()); + MT_Vector3 w(p2.x()-q.x(), p2.y()-q.y(), p2.z()-q.z()); + MT_Point3 I; + + BOP_intersect(v,p0,w,p2,I); + return I; +} + +/** + * Pre: p0, p1 and q are collinears. + * @param p0 point + * @param p1 point + * @param q point + * @return 0 if q == p0, 1 if q == p1, or a value between 0 and 1 otherwise + * + * (p0)-----(q)------------(p1) + * |<-d1-->| | + * |<---------d0---------->| + * + */ +MT_Scalar BOP_EpsilonDistance(const MT_Point3& p0, const MT_Point3& p1, const MT_Point3& q) +{ + MT_Scalar d0 = p0.distance(p1); + MT_Scalar d1 = p0.distance(q); + MT_Scalar d; + + if (BOP_fuzzyZero(d0)) d = 1.0; + else if (BOP_fuzzyZero(d1)) d = 0.0; + else d = d1 / d0; + return d; +} diff --git a/intern/boolop/intern/BOP_MathUtils.h b/intern/boolop/intern/BOP_MathUtils.h new file mode 100644 index 00000000000..3cff2d6a23b --- /dev/null +++ b/intern/boolop/intern/BOP_MathUtils.h @@ -0,0 +1,82 @@ +/** + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Marc Freixas, Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_MATHUTILS_H +#define BOP_MATHUTILS_H + +#include +#include +#include "MT_Point3.h" +#include "MT_Plane3.h" + +/* define this to give better precision comparisons */ +#define VAR_EPSILON + +#ifndef VAR_EPSILON +const MT_Scalar BOP_EPSILON(1.0e-5); +#else +const MT_Scalar BOP_EPSILON(9.3132257461547852e-10); /* ~= 2**-30 */ +#endif + +inline int BOP_sign(MT_Scalar x) { + return x < 0.0 ? -1 : x > 0.0 ? 1 : 0; +} +inline MT_Scalar BOP_abs(MT_Scalar x) { return fabs(x); } +int BOP_comp(const MT_Scalar A, const MT_Scalar B); +int BOP_comp(const MT_Tuple3& A, const MT_Tuple3& B); +int BOP_comp0(const MT_Scalar A); +inline bool BOP_fuzzyZero(MT_Scalar x) { return BOP_comp0(x) == 0; } +int BOP_exactComp(const MT_Scalar A, const MT_Scalar B); +int BOP_exactComp(const MT_Tuple3& A, const MT_Tuple3& B); +bool BOP_between(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3); +bool BOP_collinear(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3); +bool BOP_convex(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, + const MT_Point3& p4); +int BOP_concave(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, const MT_Point3& p4); +bool BOP_intersect(const MT_Vector3& vL1, const MT_Point3& pL1, const MT_Vector3& vL2, + const MT_Point3& pL2, MT_Point3& intersection); +bool BOP_getCircleCenter(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, + const MT_Point3& center); +bool BOP_isInsideCircle(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, + const MT_Point3& p4, const MT_Point3& p5); +bool BOP_isInsideCircle(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, + const MT_Point3& q); +MT_Scalar BOP_orientation(const MT_Plane3& p1, const MT_Plane3& p2); +int BOP_classify(const MT_Point3& p, const MT_Plane3& plane); +MT_Point3 BOP_intersectPlane(const MT_Plane3& plane, const MT_Point3& p1, const MT_Point3& p2); +bool BOP_containsPoint(const MT_Plane3& plane, const MT_Point3& point); +MT_Point3 BOP_4PointIntersect(const MT_Point3& p0, const MT_Point3& p1, const MT_Point3& p2, + const MT_Point3& q); +MT_Scalar BOP_EpsilonDistance(const MT_Point3& p0, const MT_Point3& p1, const MT_Point3& q); + +#endif diff --git a/intern/boolop/intern/BOP_Merge.cpp b/intern/boolop/intern/BOP_Merge.cpp new file mode 100644 index 00000000000..c2b1a2db2b7 --- /dev/null +++ b/intern/boolop/intern/BOP_Merge.cpp @@ -0,0 +1,807 @@ +/** + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Marc Freixas, Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_Merge.h" + + +#ifdef _MSC_VER +#if _MSC_VER < 1300 +#include +#endif +#endif + +/** + * SINGLETON (use method BOP_Merge.getInstance). + */ +BOP_Merge BOP_Merge::SINGLETON; + +/** + * Simplifies a mesh, merging its faces. + * @param m mesh + * @param v index of the first mergeable vertex (can be removed by merge) + */ +void BOP_Merge::mergeFaces(BOP_Mesh *m, BOP_Index v) +{ + m_mesh = m; + m_firstVertex = v; + + bool cont = false; + + // Merge faces + mergeFaces(); + + do { + // Add quads ... + cont = createQuads(); + if (cont) { + // ... and merge new faces + cont = mergeFaces(); + } + // ... until the merge is not succesful + } while(cont); +} + +/** + * Simplifies a mesh, merging its faces. + */ +bool BOP_Merge::mergeFaces() +{ + BOP_Indexs mergeVertices; + BOP_Vertexs vertices = m_mesh->getVertexs(); + BOP_IT_Vertexs v = vertices.begin(); + const BOP_IT_Vertexs verticesEnd = vertices.end(); + + // Advance to first mergeable vertex + advance(v,m_firstVertex); + BOP_Index pos = m_firstVertex; + + // Add unbroken vertices to the list + while(v!=verticesEnd) { + if ((*v)->getTAG() != BROKEN) mergeVertices.push_back(pos); + v++;pos++; + } + + // Merge faces with that vertices + return mergeFaces(mergeVertices); +} + + +/** + * Simplifies a mesh, merging the faces with the specified vertices. + * @param mergeVertices vertices to test + * @return true if a face merge was performed + */ +bool BOP_Merge::mergeFaces(BOP_Indexs &mergeVertices) +{ + // Check size > 0! + if (mergeVertices.size() == 0) return false; + + // New faces added by merge + BOP_Faces newFaces; + + // Old faces removed by merge + BOP_Faces oldFaces; + + // Get the first vertex index and add it to + // the current pending vertices to merge + BOP_Index v = mergeVertices[0]; + BOP_Indexs pendingVertices; + pendingVertices.push_back(v); + + // Get faces with index v that come from the same original face + BOP_LFaces facesByOriginalFace; + getFaces(facesByOriginalFace,v); + + bool merged = true; + + // Check it has any unbroken face + if (facesByOriginalFace.size()==0) { + // v has not any unbroken face (so it's a new BROKEN vertex) + (m_mesh->getVertex(v))->setTAG(BROKEN); + merged = false; + } + + // Merge vertex faces + const BOP_IT_LFaces facesEnd = facesByOriginalFace.end(); + + for(BOP_IT_LFaces facesByOriginalFaceX = facesByOriginalFace.begin(); + (facesByOriginalFaceX != facesEnd)&&merged; + facesByOriginalFaceX++) { + merged = mergeFaces((*facesByOriginalFaceX),oldFaces,newFaces,pendingVertices,v); + } + + // Check if the are some pendingVertices to merge + if (pendingVertices.size() > 1 && merged) { + // There are pending vertices that we need to merge in order to merge v ... + for(unsigned int i=1;isetTAG(BROKEN); + + // ... and add merged faces (that are the new merged faces without pending vertices) + const BOP_IT_Faces newFacesEnd = newFaces.end(); + for(BOP_IT_Faces newFace=newFaces.begin();newFace!=newFacesEnd;newFace++) { + m_mesh->addFace(*newFace); + // Also, add new face vertices to the queue of vertices to merge if they weren't + for(BOP_Index i = 0;i<(*newFace)->size();i++) { + BOP_Index vertexIndex = (*newFace)->getVertex(i); + if (vertexIndex >= m_firstVertex && !containsIndex(mergeVertices,vertexIndex)) + mergeVertices.push_back(vertexIndex); + } + } + // Set the merged vertices to BROKEN ... + const BOP_IT_Indexs pendingEnd = pendingVertices.end(); + for(BOP_IT_Indexs pendingVertex = pendingVertices.begin(); pendingVertex != pendingEnd;pendingVertex++) { + BOP_Index pV = *pendingVertex; + m_mesh->getVertex(pV)->setTAG(BROKEN); + // ... and remove them from mergeVertices queue + const BOP_IT_Indexs mergeEnd = mergeVertices.end(); + for(BOP_IT_Indexs mergeVertex = mergeVertices.begin(); mergeVertex != mergeEnd;mergeVertex++) { + BOP_Index mV = *mergeVertex; + if (mV == pV) { + mergeVertices.erase(mergeVertex); + break; + } + } + } + } + else { + // The merge was not succesful, remove the vertex frome merge vertices queue + mergeVertices.erase(mergeVertices.begin()); + + // free the not used newfaces + const BOP_IT_Faces newFacesEnd = newFaces.end(); + for(BOP_IT_Faces newFace=newFaces.begin();newFace!=newFacesEnd;newFace++) { + delete (*newFace); + } + } + + // Invoke mergeFaces and return the merge result + return (mergeFaces(mergeVertices) || merged); +} + + +/** + * Simplifies a mesh, merging the faces with vertex v that come from the same face. + * @param oldFaces sequence of old mesh faces obtained from the merge + * @param newFaces sequence of new mesh faces obtained from the merge + * @param vertices sequence of indexs (v1 ... vi = v ... vn) where : + * v is the current vertex to test, + * vj (j < i) are tested vertices, + * vk (k >= i) are vertices required to test to merge vj + * (so if a vertex vk can't be merged, the merge is not possible). + * @return true if the vertex v was 'merged' (obviously it could require to test + * some new vertices that will be added to the vertices list) + */ +bool BOP_Merge::mergeFaces(BOP_Faces &oldFaces, BOP_Faces &newFaces, BOP_Indexs &vertices, BOP_Index v) { + + bool merged = true; + + // Get faces with v that come from the same original face, (without the already 'merged' from vertices) + BOP_LFaces facesByOriginalFace; + getFaces(facesByOriginalFace,vertices,v); + + if (facesByOriginalFace.size()==0) { + // All the faces with this vertex were already merged!!! + return true; + } + else { + // Merge faces + const BOP_IT_LFaces facesEnd = facesByOriginalFace.end(); + for(BOP_IT_LFaces facesByOriginalFaceX = facesByOriginalFace.begin(); + (facesByOriginalFaceX != facesEnd)&&merged; + facesByOriginalFaceX++) { + merged = mergeFaces((*facesByOriginalFaceX),oldFaces,newFaces,vertices,v); + } + } + return merged; +} + + +/** + * Merge a set of faces removing the vertex index v. + * @param faces set of faces + * @param oldFaces set of old faces obtained from the merge + * @param newFaces set of new faces obtained from the merge + * @param vertices sequence of indexs (v1 ... vi = v ... vn) where : + * v is the current vertex to test, + * vj (j < i) are tested vertices, + * vk (k >= i) are vertices required to test to merge vj + * (so if a vertex vk can't be merged, the merge is not possible). + * @param v vertex index + * @return true if the merge is succesful, false otherwise + */ +bool BOP_Merge::mergeFaces(BOP_Faces &faces, BOP_Faces &oldFaces, BOP_Faces &newFaces, BOP_Indexs &vertices, BOP_Index v) +{ + + bool merged = false; + + if (faces.size() == 2) { + // Merge a pair of faces into a new face without v + BOP_Face *faceI = faces[0]; + BOP_Face *faceJ = faces[1]; + BOP_Face *faceK = mergeFaces(faceI,faceJ,vertices,v); + if (faceK != NULL) { + newFaces.push_back(faceK); + oldFaces.push_back(faceI); + oldFaces.push_back(faceJ); + merged = true; + } + else merged = false; + } + else if (faces.size() == 4) { + // Merge two pair of faces into a new pair without v + // First we try to perform a simplify merge to avoid more pending vertices + // (for example, if we have two triangles and two quads it will be better + // to do 3+4 and 3+4 than 3+3 and 4+4) + BOP_Face *oldFace1 = faces[0]; + BOP_Face *oldFace2, *newFace1; + unsigned int indexJ = 1; + while (indexJ < faces.size() && !merged) { + oldFace2 = faces[indexJ]; + newFace1 = mergeFaces(oldFace1,oldFace2,v); + if (newFace1 != NULL) merged = true; + else indexJ++; + } + if (merged) { + // Merge the other pair of faces + unsigned int indexK, indexL; + if (indexJ == 1) {indexK = 2;indexL = 3;} + else if (indexJ == 2) {indexK = 1;indexL = 3;} + else {indexK = 1;indexL = 2;} + BOP_Face *oldFace3 = faces[indexK]; + BOP_Face *oldFace4 = faces[indexL]; + unsigned int oldSize = vertices.size(); + BOP_Face *newFace2 = mergeFaces(oldFace3,oldFace4,vertices,v); + if (newFace2 != NULL) { + newFaces.push_back(newFace1); + newFaces.push_back(newFace2); + oldFaces.push_back(oldFace1); + oldFaces.push_back(oldFace2); + oldFaces.push_back(oldFace3); + oldFaces.push_back(oldFace4); + merged = true; + } + else { + // Undo all changes + delete newFace1; + merged = false; + unsigned int count = vertices.size() - oldSize; + if (count != 0) + vertices.erase(vertices.end() - count, vertices.end()); + } + } + if (!merged) { + // Try a complete merge + merged = true; + while (faces.size()>0 && merged) { + indexJ = 1; + BOP_Face *faceI = faces[0]; + merged = false; + while (indexJ < faces.size()) { + BOP_Face *faceJ = faces[indexJ]; + BOP_Face *faceK = mergeFaces(faceI,faceJ,vertices,v); + if (faceK != NULL) { + // faceK = faceI + faceJ and it does not include v! + faces.erase(faces.begin()+indexJ,faces.begin()+(indexJ+1)); + faces.erase(faces.begin(),faces.begin()+1); + newFaces.push_back(faceK); + oldFaces.push_back(faceI); + oldFaces.push_back(faceJ); + merged = true; + break; + } + else indexJ++; + } + } + } + } + else merged = false; // there are N=1 or N=3 or N>4 faces! + + // Return merge result + return merged; +} + +/** + * Returns a new quad from the merge of two faces (one quad and one triangle) + * that share the vertex v and come from the same original face. + * @param faceI mesh face (quad or triangle) with index v + * @param faceJ mesh face (quad or triangle) with index v + * @param v vertex index shared by both faces + * @return if the merge is possible, a new quad without v + */ +BOP_Face* BOP_Merge::mergeFaces(BOP_Face *faceI, BOP_Face *faceJ, BOP_Index v) +{ + if (faceI->size() == 3) { + if (faceJ->size() == 4) + return mergeFaces((BOP_Face4*)faceJ,(BOP_Face3*)faceI,v); + } + else if (faceI->size() == 4) { + if (faceJ->size() == 3) + return mergeFaces((BOP_Face4*)faceI,(BOP_Face3*)faceJ,v); + } + return NULL; +} + +/** + * Returns a new face from the merge of two faces (quads or triangles) that + * share te vertex v and come from the same original face. + * @param faceI mesh face (quad or triangle) with index v + * @param faceJ mesh face (quad or triangle) with index v + * @param pending vector with pending vertices (required to merge two quads into + * a new quad or one quad and one triangle into a new triangle; these merges + * suppose to remove two vertexs, v and its neighbour, that will be a pending + * vertex to merge if it wasn't) + * @param v vertex index shared by both faces + * @return if the merge is possible, a new face without v + */ +BOP_Face* BOP_Merge::mergeFaces(BOP_Face *faceI, BOP_Face *faceJ, BOP_Indexs &pending, BOP_Index v) +{ + if (faceI->size() == 3) { + if (faceJ->size() == 3) + return mergeFaces((BOP_Face3*)faceI,(BOP_Face3*)faceJ,v); + else if (faceJ->size() == 4) + return mergeFaces((BOP_Face4*)faceJ,(BOP_Face3*)faceI,pending,v); + } + else if (faceI->size() == 4) { + if (faceJ->size() == 3) + return mergeFaces((BOP_Face4*)faceI,(BOP_Face3*)faceJ,pending,v); + else if (faceJ->size() == 4) + return mergeFaces((BOP_Face4*)faceI,(BOP_Face4*)faceJ,pending,v); + } + return NULL; +} + +/** + * Returns a new triangle from the merge of two triangles that share the vertex + * v and come from the same original face. + * @param faceI mesh triangle + * @param faceJ mesh triangle + * @param v vertex index shared by both triangles + * @return If the merge is possible, a new triangle without v + */ +BOP_Face* BOP_Merge::mergeFaces(BOP_Face3 *faceI, BOP_Face3 *faceJ, BOP_Index v) +{ + BOP_Face *faceK = NULL; + + // Get faces data + BOP_Index prevI, nextI, prevJ, nextJ; + faceI->getNeighbours(v,prevI,nextI); + faceJ->getNeighbours(v,prevJ,nextJ); + MT_Point3 vertex = m_mesh->getVertex(v)->getPoint(); + MT_Point3 vPrevI = m_mesh->getVertex(prevI)->getPoint(); + MT_Point3 vNextI = m_mesh->getVertex(nextI)->getPoint(); + MT_Point3 vPrevJ = m_mesh->getVertex(prevJ)->getPoint(); + MT_Point3 vNextJ = m_mesh->getVertex(nextJ)->getPoint(); + + // Merge test + if (prevI == nextJ) { + // Both faces share the edge (prevI,v) == (v,nextJ) + if (BOP_between(vertex,vNextI,vPrevJ)) { + faceK = new BOP_Face3(prevI,prevJ,nextI,faceI->getPlane(),faceI->getOriginalFace()); + faceK->setTAG(faceI->getTAG()); + } + } + else if (nextI == prevJ) { + // Both faces share the edge (v,nextI) == (prevJ,v) + if (BOP_between(vertex,vPrevI,vNextJ)) { + faceK = new BOP_Face3(prevI,nextJ,nextI,faceI->getPlane(),faceI->getOriginalFace()); + faceK->setTAG(faceI->getTAG()); + } + } + return faceK; +} + +/** + * Returns a new quad from the merge of one quad and one triangle that share + * the vertex v and come from the same original face. + * @param faceI mesh quad + * @param faceJ mesh triangle + * @param v vertex index shared by both faces + * @return If the merge is possible, a new quad without v + */ +BOP_Face* BOP_Merge::mergeFaces(BOP_Face4 *faceI, BOP_Face3 *faceJ, BOP_Index v) +{ + BOP_Face *faceK = NULL; + + // Get faces data + BOP_Index prevI, nextI, opp, prevJ, nextJ; + faceI->getNeighbours(v,prevI,nextI,opp); + faceJ->getNeighbours(v,prevJ,nextJ); + MT_Point3 vertex = m_mesh->getVertex(v)->getPoint(); + MT_Point3 vOpp = m_mesh->getVertex(opp)->getPoint(); + MT_Point3 vPrevI = m_mesh->getVertex(prevI)->getPoint(); + MT_Point3 vNextI = m_mesh->getVertex(nextI)->getPoint(); + MT_Point3 vPrevJ = m_mesh->getVertex(prevJ)->getPoint(); + MT_Point3 vNextJ = m_mesh->getVertex(nextJ)->getPoint(); + + // Merge test + if (prevI == nextJ) { + if (BOP_between(vertex,vNextI,vPrevJ) && !BOP_collinear(vPrevJ,vPrevI,vOpp) + && BOP_convex(vOpp,vPrevI,vPrevJ,vNextI)) { + faceK = new BOP_Face4(opp,prevI,prevJ,nextI,faceI->getPlane(),faceI->getOriginalFace()); + faceK->setTAG(faceI->getTAG()); + } + } + else if (nextI == prevJ) { + if (BOP_between(vertex,vPrevI,vNextJ) && !BOP_collinear(vNextJ,vNextI,vOpp) + && BOP_convex(vOpp,vPrevI,vNextJ,vNextI)) { + faceK = new BOP_Face4(opp,prevI,nextJ,nextI,faceI->getPlane(),faceI->getOriginalFace()); + faceK->setTAG(faceI->getTAG()); + } + } + return faceK; +} + +/** + * Returns a new face (quad or triangle) from the merge of one quad and one + * triangle that share the vertex v and come from the same original face. + * @param faceI mesh quad + * @param faceJ mesh triangle + * @param pending vector with pending vertices (required to merge one quad + * and one triangle into a new triangle; it supposes to remove two vertexs, + * v and its neighbour, that will be a new pending vertex if it wasn't) + * @param v vertex index shared by both faces + * @return If the merge is possible, a new face without v + */ +BOP_Face* BOP_Merge::mergeFaces(BOP_Face4 *faceI, BOP_Face3 *faceJ, BOP_Indexs &pending, BOP_Index v) +{ + BOP_Face *faceK = NULL; + + // Get faces data + BOP_Index prevI, nextI, opp, prevJ, nextJ; + faceI->getNeighbours(v,prevI,nextI,opp); + faceJ->getNeighbours(v,prevJ,nextJ); + MT_Point3 vertex = m_mesh->getVertex(v)->getPoint(); + MT_Point3 vOpp = m_mesh->getVertex(opp)->getPoint(); + MT_Point3 vPrevI = m_mesh->getVertex(prevI)->getPoint(); + MT_Point3 vNextI = m_mesh->getVertex(nextI)->getPoint(); + MT_Point3 vPrevJ = m_mesh->getVertex(prevJ)->getPoint(); + MT_Point3 vNextJ = m_mesh->getVertex(nextJ)->getPoint(); + + // Merge test + if (prevI == nextJ) { + if (BOP_between(vertex,vNextI,vPrevJ)) { + if (!BOP_collinear(vPrevJ,vPrevI,vOpp) && BOP_convex(vOpp,vPrevI,vPrevJ,vNextI)) { + // The result is a new quad + faceK = new BOP_Face4(opp,prevI,prevJ,nextI,faceI->getPlane(),faceI->getOriginalFace()); + faceK->setTAG(faceI->getTAG()); + } + else if (BOP_between(vPrevI,vPrevJ,vOpp)) { + // The result is a triangle (only if prevI can be merged) + if (prevI < m_firstVertex) return NULL; // It can't be merged + faceK = new BOP_Face3(nextI,opp,prevJ,faceI->getPlane(),faceI->getOriginalFace()); + faceK->setTAG(faceI->getTAG()); + if (!containsIndex(pending, prevI)) pending.push_back(prevI); + } + } + } + else if (nextI == prevJ) { + if (BOP_between(vertex,vPrevI,vNextJ)) { + if (!BOP_collinear(vNextJ,vNextI,vOpp) && BOP_convex(vOpp,vPrevI,vNextJ,vNextI)) { + // The result is a new quad + faceK = new BOP_Face4(opp,prevI,nextJ,nextI,faceI->getPlane(),faceI->getOriginalFace()); + faceK->setTAG(faceI->getTAG()); + } + else if (BOP_between(vNextI,vOpp,vNextJ)) { + // The result is a triangle (only if nextI can be merged) + if (nextI < m_firstVertex) return NULL; + faceK = new BOP_Face3(prevI,nextJ,opp,faceI->getPlane(),faceI->getOriginalFace()); + faceK->setTAG(faceI->getTAG()); + if (!containsIndex(pending, nextI)) pending.push_back(nextI); + } + } + } + return faceK; +} + +/** + * Returns a new quad from the merge of two quads that share + * the vertex v and come from the same original face. + * @param faceI mesh quad + * @param faceJ mesh quad + * @param pending vector with pending vertices (required to merge the two + * quads supposes to remove two vertexs, v and its neighbour, + * that will be a new pending vertex if it wasn't) + * @param v vertex index shared by both quads + * @return If the merge is possible, a new quad without v + */ +BOP_Face* BOP_Merge::mergeFaces(BOP_Face4 *faceI, BOP_Face4 *faceJ, BOP_Indexs &pending, BOP_Index v) +{ + BOP_Face *faceK = NULL; + + // Get faces data + BOP_Index prevI, nextI, oppI, prevJ, nextJ, oppJ; + faceI->getNeighbours(v,prevI,nextI,oppI); + faceJ->getNeighbours(v,prevJ,nextJ,oppJ); + MT_Point3 vertex = m_mesh->getVertex(v)->getPoint(); + MT_Point3 vPrevI = m_mesh->getVertex(prevI)->getPoint(); + MT_Point3 vNextI = m_mesh->getVertex(nextI)->getPoint(); + MT_Point3 vOppI = m_mesh->getVertex(oppI)->getPoint(); + MT_Point3 vPrevJ = m_mesh->getVertex(prevJ)->getPoint(); + MT_Point3 vNextJ = m_mesh->getVertex(nextJ)->getPoint(); + MT_Point3 vOppJ = m_mesh->getVertex(oppJ)->getPoint(); + + // Merge test + if (prevI == nextJ) { + // prevI/nextJ will be a new vertex required to merge + if (prevI < m_firstVertex) return NULL; // It can't be merged + if (BOP_between(vertex,vPrevJ,vNextI) && BOP_between(vNextJ,vOppJ,vOppI)) { + faceK = new BOP_Face4(oppJ,prevJ,nextI,oppI,faceI->getPlane(),faceI->getOriginalFace()); + faceK->setTAG(faceI->getTAG()); + // We add prevI to the pending list if it wasn't yet + if (!containsIndex(pending, prevI)) pending.push_back(prevI); + } + } + else if (nextI == prevJ) { + // nextI/prevJ will be a new vertex required to merge + if (nextI < m_firstVertex) return NULL; // It can't be merged + if (BOP_between(vertex,vPrevI,vNextJ) && BOP_between(vNextI,vOppI,vOppJ)) { + faceK = new BOP_Face4(oppI,prevI,nextJ,oppJ,faceI->getPlane(),faceI->getOriginalFace()); + faceK->setTAG(faceI->getTAG()); + // Add nextI to the pending list if it wasn't yet + if (!containsIndex(pending, nextI)) pending.push_back(nextI); + } + } + return faceK; +} + + +/** + * Simplifies the mesh, merging the pairs of triangles that come frome the + * same original face and define a quad. + * @return true if a quad was added, false otherwise + */ +bool BOP_Merge::createQuads() +{ + + BOP_Faces quads; + + // Get mesh faces + BOP_Faces faces = m_mesh->getFaces(); + + + // Merge mesh triangles + const BOP_IT_Faces facesIEnd = (faces.end()-1); + const BOP_IT_Faces facesJEnd = faces.end(); + for(BOP_IT_Faces faceI=faces.begin();faceI!=facesIEnd;faceI++) { + if ((*faceI)->getTAG() == BROKEN || (*faceI)->size() != 3) continue; + for(BOP_IT_Faces faceJ=(faceI+1);faceJ!=facesJEnd;faceJ++) { + if ((*faceJ)->getTAG() == BROKEN || (*faceJ)->size() != 3 || + (*faceJ)->getOriginalFace() != (*faceI)->getOriginalFace()) continue; + + // Test if both triangles share a vertex index + BOP_Index v; + bool found = false; + for(unsigned int i=0;i<3 && !found;i++) { + v = (*faceI)->getVertex(i); + found = (*faceJ)->containsVertex(v); + + } + if (!found) continue; + + BOP_Face *faceK = createQuad((BOP_Face3*)*faceI,(BOP_Face3*)*faceJ,v); + if (faceK != NULL) { + // Set triangles to BROKEN + (*faceI)->setTAG(BROKEN); + (*faceJ)->setTAG(BROKEN); + quads.push_back(faceK); + break; + } + } + } + + // Add quads to mesh + const BOP_IT_Faces quadsEnd = quads.end(); + for(BOP_IT_Faces quad=quads.begin();quad!=quadsEnd;quad++) m_mesh->addFace(*quad); + return (quads.size() > 0); +} + +/** + * Returns a new quad (convex) from the merge of two triangles that share the + * vertex index v. + * @param faceI mesh triangle + * @param faceJ mesh triangle + * @param v vertex index shared by both triangles + * @return a new convex quad if the merge is possible + */ +BOP_Face* BOP_Merge::createQuad(BOP_Face3 *faceI, BOP_Face3 *faceJ, BOP_Index v) +{ + BOP_Face *faceK = NULL; + + // Get faces data + BOP_Index prevI, nextI, prevJ, nextJ; + faceI->getNeighbours(v,prevI,nextI); + faceJ->getNeighbours(v,prevJ,nextJ); + MT_Point3 vertex = m_mesh->getVertex(v)->getPoint(); + MT_Point3 vPrevI = m_mesh->getVertex(prevI)->getPoint(); + MT_Point3 vNextI = m_mesh->getVertex(nextI)->getPoint(); + MT_Point3 vPrevJ = m_mesh->getVertex(prevJ)->getPoint(); + MT_Point3 vNextJ = m_mesh->getVertex(nextJ)->getPoint(); + + // Quad test + if (prevI == nextJ) { + if (!BOP_collinear(vNextI,vertex,vPrevJ) && !BOP_collinear(vNextI,vPrevI,vPrevJ) && + BOP_convex(vertex,vNextI,vPrevI,vPrevJ)) { + faceK = new BOP_Face4(v,nextI,prevI,prevJ,faceI->getPlane(),faceI->getOriginalFace()); + faceK->setTAG(faceI->getTAG()); + } + } + else if (nextI == prevJ) { + if (!BOP_collinear(vPrevI,vertex,vNextJ) && !BOP_collinear(vPrevI,vNextI,vNextJ) && + BOP_convex(vertex,vNextJ,vNextI,vPrevI)) { + faceK = new BOP_Face4(v,nextJ,nextI,prevI,faceI->getPlane(),faceI->getOriginalFace()); + faceK->setTAG(faceI->getTAG()); + } + } + return faceK; +} + +/** + * Returns if a index is inside a set of indexs. + * @param indexs set of indexs + * @param i index + * @return true if the index is inside the set, false otherwise + */ +bool BOP_Merge::containsIndex(BOP_Indexs indexs, BOP_Index i) +{ + const BOP_IT_Indexs indexsEnd = indexs.end(); + for(BOP_IT_Indexs it=indexs.begin();it!=indexsEnd;it++) { + if (*it == i) return true; + } + return false; +} + +/** + * Creates a list of lists L1, L2, ... LN where + * LX = mesh faces with vertex v that come from the same original face + * @param facesByOriginalFace list of faces lists + * @param v vertex index + */ +void BOP_Merge::getFaces(BOP_LFaces &facesByOriginalFace, BOP_Index v) +{ + // Get edges with vertex v + BOP_Indexs edgeIndexs = m_mesh->getVertex(v)->getEdges(); + const BOP_IT_Indexs edgeEnd = edgeIndexs.end(); + for(BOP_IT_Indexs edgeIndex = edgeIndexs.begin();edgeIndex != edgeEnd;edgeIndex++) { + // Foreach edge, add its no broken faces to the output list + BOP_Edge* edge = m_mesh->getEdge(*edgeIndex); + BOP_Indexs faceIndexs = edge->getFaces(); + const BOP_IT_Indexs faceEnd = faceIndexs.end(); + for(BOP_IT_Indexs faceIndex=faceIndexs.begin();faceIndex!=faceEnd;faceIndex++) { + BOP_Face* face = m_mesh->getFace(*faceIndex); + if (face->getTAG() != BROKEN) { + bool found = false; + // Search if we already have created a list for the + // faces that come from the same original face + const BOP_IT_LFaces lfEnd = facesByOriginalFace.end(); + for(BOP_IT_LFaces facesByOriginalFaceX=facesByOriginalFace.begin(); + facesByOriginalFaceX!=lfEnd; facesByOriginalFaceX++) { + if (((*facesByOriginalFaceX)[0])->getOriginalFace() == face->getOriginalFace()) { + // Search that the face has not been added to the list before + for(unsigned int i = 0;i<(*facesByOriginalFaceX).size();i++) { + if ((*facesByOriginalFaceX)[i] == face) { + found = true; + break; + } + } + if (!found) { + // Add the face to the list + if (face->getTAG()==OVERLAPPED) facesByOriginalFaceX->insert(facesByOriginalFaceX->begin(),face); + else facesByOriginalFaceX->push_back(face); + found = true; + } + break; + } + } + if (!found) { + // Create a new list and add the current face + BOP_Faces facesByOriginalFaceX; + facesByOriginalFaceX.push_back(face); + facesByOriginalFace.push_back(facesByOriginalFaceX); + } + } + } + } +} + +/** + * Creates a list of lists L1, L2, ... LN where + * LX = mesh faces with vertex v that come from the same original face + * and without any of the vertices that appear before v in vertices + * @param facesByOriginalFace list of faces lists + * @param vertices vector with vertices indexs that contains v + * @param v vertex index + */ +void BOP_Merge::getFaces(BOP_LFaces &facesByOriginalFace, BOP_Indexs vertices, BOP_Index v) +{ + // Get edges with vertex v + BOP_Indexs edgeIndexs = m_mesh->getVertex(v)->getEdges(); + const BOP_IT_Indexs edgeEnd = edgeIndexs.end(); + for(BOP_IT_Indexs edgeIndex = edgeIndexs.begin();edgeIndex != edgeEnd;edgeIndex++) { + // Foreach edge, add its no broken faces to the output list + BOP_Edge* edge = m_mesh->getEdge(*edgeIndex); + BOP_Indexs faceIndexs = edge->getFaces(); + const BOP_IT_Indexs faceEnd = faceIndexs.end(); + for(BOP_IT_Indexs faceIndex=faceIndexs.begin();faceIndex!=faceEnd;faceIndex++) { + BOP_Face* face = m_mesh->getFace(*faceIndex); + if (face->getTAG() != BROKEN) { + // Search if the face contains any of the forbidden vertices + bool found = false; + for(BOP_IT_Indexs vertex = vertices.begin();*vertex!= v;vertex++) { + if (face->containsVertex(*vertex)) { + // face contains a forbidden vertex! + found = true; + break; + } + } + if (!found) { + // Search if we already have created a list with the + // faces that come from the same original face + const BOP_IT_LFaces lfEnd = facesByOriginalFace.end(); + for(BOP_IT_LFaces facesByOriginalFaceX=facesByOriginalFace.begin(); + facesByOriginalFaceX!=lfEnd; facesByOriginalFaceX++) { + if (((*facesByOriginalFaceX)[0])->getOriginalFace() == face->getOriginalFace()) { + // Search that the face has not been added to the list before + for(unsigned int i = 0;i<(*facesByOriginalFaceX).size();i++) { + if ((*facesByOriginalFaceX)[i] == face) { + found = true; + break; + } + } + if (!found) { + // Add face to the list + if (face->getTAG()==OVERLAPPED) facesByOriginalFaceX->insert(facesByOriginalFaceX->begin(),face); + else facesByOriginalFaceX->push_back(face); + found = true; + } + break; + } + } + if (!found) { + // Create a new list and add the current face + BOP_Faces facesByOriginalFaceX; + facesByOriginalFaceX.push_back(face); + facesByOriginalFace.push_back(facesByOriginalFaceX); + } + } + } + } + } +} diff --git a/intern/boolop/intern/BOP_Merge.h b/intern/boolop/intern/BOP_Merge.h new file mode 100644 index 00000000000..2ccce8e137b --- /dev/null +++ b/intern/boolop/intern/BOP_Merge.h @@ -0,0 +1,74 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_MERGE_H +#define BOP_MERGE_H + +#include "BOP_Mesh.h" +#include "BOP_Tag.h" +#include "BOP_MathUtils.h" +#include "MEM_SmartPtr.h" + +typedef vector< BOP_Faces > BOP_LFaces; +typedef vector< BOP_Faces >::iterator BOP_IT_LFaces; + +class BOP_Merge { + private: + BOP_Mesh* m_mesh; + BOP_Index m_firstVertex; + static BOP_Merge SINGLETON; + + BOP_Merge() {}; + bool mergeFaces(); + bool mergeFaces(BOP_Indexs &mergeVertices); + bool mergeFaces(BOP_Faces &oldFaces, BOP_Faces &newFaces, BOP_Indexs &vertices, BOP_Index v); + bool mergeFaces(BOP_Faces &faces, BOP_Faces &oldFaces, BOP_Faces &newFaces, BOP_Indexs &vertices, BOP_Index v); + BOP_Face *mergeFaces(BOP_Face *faceI, BOP_Face *faceJ, BOP_Index v); + BOP_Face *mergeFaces(BOP_Face *faceI, BOP_Face *faceJ, BOP_Indexs &pending, BOP_Index v); + BOP_Face *mergeFaces(BOP_Face3 *faceI, BOP_Face3 *faceJ, BOP_Index v); + BOP_Face *mergeFaces(BOP_Face4 *faceI, BOP_Face3 *faceJ, BOP_Index v); + BOP_Face *mergeFaces(BOP_Face4 *faceI, BOP_Face3 *faceJ, BOP_Indexs &pending, BOP_Index v); + BOP_Face *mergeFaces(BOP_Face4 *faceI, BOP_Face4 *faceJ, BOP_Indexs &pending, BOP_Index v); + bool createQuads(); + BOP_Face *createQuad(BOP_Face3 *faceI, BOP_Face3 *faceJ, BOP_Index v); + bool containsIndex(BOP_Indexs indexs, BOP_Index index); + void getFaces(BOP_LFaces &facesByOriginalFace, BOP_Index v); + void getFaces(BOP_LFaces &facesByOriginalFace, BOP_Indexs vertices, BOP_Index v); + + public: + + static BOP_Merge &getInstance() { + return SINGLETON; + } + + void mergeFaces(BOP_Mesh *m, BOP_Index v); +}; + +#endif diff --git a/intern/boolop/intern/BOP_Mesh.cpp b/intern/boolop/intern/BOP_Mesh.cpp new file mode 100644 index 00000000000..0b70cc61533 --- /dev/null +++ b/intern/boolop/intern/BOP_Mesh.cpp @@ -0,0 +1,1080 @@ +/** + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_Mesh.h" +#include "BOP_MathUtils.h" +#include +#include + +#include "MEM_guardedalloc.h" +#include "BLI_blenlib.h" + +BOP_Mesh::BOP_Mesh() +{ +#ifdef HASH +#ifdef HASH_PRINTF_DEBUG + printf ("has hashing\n"); +#endif + hash = NULL; + hashsize = 0; +#endif +} + +/** + * Destroys a mesh. + */ +BOP_Mesh::~BOP_Mesh() +{ + const BOP_IT_Vertexs vertexsEnd = m_vertexs.end(); + for(BOP_IT_Vertexs itv=m_vertexs.begin();itv!=vertexsEnd;itv++){ + delete *itv; + } + m_vertexs.clear(); + + const BOP_IT_Edges edgesEnd = m_edges.end(); + for(BOP_IT_Edges ite=m_edges.begin();ite!=edgesEnd;ite++){ + delete *ite; + } + m_edges.clear(); + + const BOP_IT_Faces facesEnd = m_faces.end(); + for(BOP_IT_Faces itf=m_faces.begin();itf!=facesEnd;itf++){ + delete *itf; + } + m_faces.clear(); + +#ifdef HASH + while( hashsize ) { + --hashsize; + BLI_freelistN( &hash[hashsize] ); + } + MEM_freeN( hash ); + hash = NULL; +#endif +} + +/** + * Adds a new vertex. + * @param p vertex point + * @return mesh vertex index + */ +BOP_Index BOP_Mesh::addVertex(MT_Point3 p) +{ + m_vertexs.push_back(new BOP_Vertex(p)); + return m_vertexs.size()-1; +} + +/** + * Adds a new edge. + * @param v1 mesh vertex index + * @param v2 mesh vertex index + * @return mesh edge index + */ +BOP_Index BOP_Mesh::addEdge(BOP_Index v1, BOP_Index v2) +{ +#ifdef HASH + /* prepare a new hash entry for the edge */ + int minv; + EdgeEntry *h = (EdgeEntry *)MEM_callocN( sizeof( EdgeEntry ), "edgehash" ); + + /* store sorted, smallest vert first */ + if( v1 < v2 ) { + minv = HASH(v1); + h->v1 = v1; + h->v2 = v2; + } else { + minv = HASH(v2); + h->v1 = v2; + h->v2 = v1; + } + h->index = m_edges.size(); + + /* if hash index larger than hash list, extend the list */ + if( minv >= hashsize ) { + int newsize = (minv + 8) & ~7; + ListBase *nhash = (ListBase *)MEM_mallocN( + newsize * sizeof( ListBase ), + "edgehashtable" ); + /* copy old entries */ + memcpy( nhash, hash, sizeof( ListBase ) * hashsize ); + /* clear new ones */ + while( hashsize < newsize ) { + nhash[hashsize].first = nhash[hashsize].last = NULL; + ++hashsize; + } + if( hash ) + MEM_freeN( hash ); + hash = nhash; + } + + /* add the entry to tail of the right hash list */ + BLI_addtail( &hash[minv], h ); +#endif + m_edges.push_back(new BOP_Edge(v1,v2)); + return m_edges.size()-1; +} + +#ifdef HASH +/** + * replace one vertex with another in the hash list + * @param o old mesh vertex index + * @param n new mesh vertex index + * @param x edge's other mesh vertex index + */ +void BOP_Mesh::rehashVertex(BOP_Index o, BOP_Index n, BOP_Index x) +{ + EdgeEntry *edge; + int minv = HASH(o); + BOP_Index v1, v2; + + /* figure out where and what to look for */ + if( o < x ) { + minv = HASH(o); + v1 = o; v2 = x; + } else { + minv = HASH(x); + v1 = x; v2 = o; + } + + /* if hash is valid, search for the match */ + if( minv < hashsize ) { + for(edge = (EdgeEntry *)hash[minv].first; + edge; edge = edge->next ) { + if(edge->v1 == v1 && edge->v2 == v2) + break; + } + + /* NULL edge == no match */ + if(!edge) { +#ifdef HASH_PRINTF_DEBUG + printf ("OOPS! didn't find edge (%d %d)\n",v1,v2); +#endif + return; + } +#ifdef HASH_PRINTF_DEBUG + printf ("found edge (%d %d)\n",v1,v2); +#endif + /* remove the edge from the old hash list */ + BLI_remlink( &hash[minv], edge ); + + /* decide where the new edge should go */ + if( n < x ) { + minv = HASH(n); + v1 = n; v2 = x; + } else { + minv = HASH(x); + edge->v1 = x; edge->v2 = n; + } + + /* if necessary, extend the hash list */ + if( minv >= hashsize ) { +#ifdef HASH_PRINTF_DEBUG + printf ("OOPS! new vertex too large! (%d->%d)\n",o,n); +#endif + int newsize = (minv + 8) & ~7; + ListBase *nhash = (ListBase *)MEM_mallocN( + newsize * sizeof( ListBase ), + "edgehashtable" ); + memcpy( nhash, hash, sizeof( ListBase ) * hashsize ); + while( hashsize < newsize ) { + nhash[hashsize].first = nhash[hashsize].last = NULL; + ++hashsize; + } + if( hash ) + MEM_freeN( hash ); + hash = nhash; + } + + /* add the entry to tail of the right hash list */ + BLI_addtail( &hash[minv], edge ); + } else { +#ifdef HASH_PRINTF_DEBUG + printf ("OOPS! hash not large enough for (%d %d)\n",minv,hashsize); +#endif + } +} +#endif + +/** + * Adds a new face. + * @param face mesh face + * @return mesh face index + */ +BOP_Index BOP_Mesh::addFace(BOP_Face *face) +{ + if (face->size()==3) + return addFace((BOP_Face3 *)face); + else + return addFace((BOP_Face4 *)face); +} + +/** + * Adds a new triangle. + * @param face mesh triangle + * @return mesh face index + */ +BOP_Index BOP_Mesh::addFace(BOP_Face3 *face) +{ + BOP_Index indexface = m_faces.size(); + + BOP_Index index1 = face->getVertex(0); + BOP_Index index2 = face->getVertex(1); + BOP_Index index3 = face->getVertex(2); + + m_faces.push_back((BOP_Face *)face); + + BOP_Index edge; + + if (!getIndexEdge(index1,index2,edge)) { + edge = addEdge(index1,index2); + getVertex(index1)->addEdge(edge); + getVertex(index2)->addEdge(edge); + } + + getEdge(edge)->addFace(indexface); + + if (!getIndexEdge(index2,index3,edge)) { + edge = addEdge(index2,index3); + getVertex(index2)->addEdge(edge); + getVertex(index3)->addEdge(edge); + } + + getEdge(edge)->addFace(indexface); + + if (!getIndexEdge(index3,index1,edge)) { + edge = addEdge(index3,index1); + getVertex(index3)->addEdge(edge); + getVertex(index1)->addEdge(edge); + } + + getEdge(edge)->addFace(indexface); + + if ((index1 == index2) || (index1 == index3) || (index2 == index3)) + face->setTAG(BROKEN); + + return indexface; +} + +/** + * Adds a new quad. + * @param face mesh quad + * @return mesh face index + */ +BOP_Index BOP_Mesh::addFace(BOP_Face4 *face) +{ + m_faces.push_back((BOP_Face *)face); + BOP_Index indexface = m_faces.size()-1; + + BOP_Index index1 = face->getVertex(0); + BOP_Index index2 = face->getVertex(1); + BOP_Index index3 = face->getVertex(2); + BOP_Index index4 = face->getVertex(3); + + BOP_Index edge; + + if (!getIndexEdge(index1,index2,edge)) { + edge = addEdge(index1,index2); + getVertex(index1)->addEdge(edge); + getVertex(index2)->addEdge(edge); + } + + getEdge(edge)->addFace(indexface); + + if (!getIndexEdge(index2,index3,edge)) { + edge = addEdge(index2,index3); + getVertex(index2)->addEdge(edge); + getVertex(index3)->addEdge(edge); + } + + getEdge(edge)->addFace(indexface); + + if (!getIndexEdge(index3,index4,edge)) { + edge = addEdge(index3,index4); + getVertex(index3)->addEdge(edge); + getVertex(index4)->addEdge(edge); + } + + getEdge(edge)->addFace(indexface); + + if (!getIndexEdge(index4,index1,edge)) { + edge = addEdge(index4,index1); + getVertex(index4)->addEdge(edge); + getVertex(index1)->addEdge(edge); + } + + getEdge(edge)->addFace(indexface); + + if ((index1 == index2) || (index1 == index3) || (index1 == index4) || + (index2 == index3) || (index2 == index4) || (index3 == index4)) + face->setTAG(BROKEN); + + return m_faces.size()-1; +} + +/** + * Returns if a faces set contains the specified face. + * @param faces faces set + * @param face face + * @return true if the set contains the specified face + */ +bool BOP_Mesh::containsFace(BOP_Faces *faces, BOP_Face *face) +{ + const BOP_IT_Faces facesEnd = faces->end(); + for(BOP_IT_Faces it = faces->begin();it!=facesEnd;it++) { + if (face == *it) + return true; + } + + return false; +} +/** + * Returns the first edge with the specified vertex index from a list of edge indexs. + * @param edges edge indexs + * @param v vertex index + * @return first edge with the specified vertex index, NULL otherwise + */ +BOP_Edge* BOP_Mesh::getEdge(BOP_Indexs edges, BOP_Index v) +{ + const BOP_IT_Indexs edgesEnd = edges.end(); + for(BOP_IT_Indexs it=edges.begin();it!=edgesEnd;it++){ + BOP_Edge *edge = m_edges[*it]; + if ((edge->getVertex1() == v) || (edge->getVertex2() == v)) + return edge; + } + return NULL; +} + +/** + * Returns the mesh edge with the specified vertex indexs. + * @param v1 vertex index + * @param v2 vertex index + * @return mesh edge with the specified vertex indexs, NULL otherwise + */ +BOP_Edge* BOP_Mesh::getEdge(BOP_Index v1, BOP_Index v2) +{ +#ifdef HASH + int minv; + EdgeEntry *edge; + + /* figure out where and what to search for */ + if( v1 < v2 ) { + minv = HASH(v1); + } else { + minv = HASH(v2); + BOP_Index tmp = v1; + v1 = v2; + v2 = tmp; + } + + /* if hash index valid, search the list and return match if found */ + if( minv < hashsize ) { + for(edge = (EdgeEntry *)hash[minv].first; + edge; edge = edge->next ) { + if(edge->v1 == v1 && edge->v2 == v2) + return m_edges[edge->index]; + } + } +#else + const BOP_IT_Edges edgesEnd = m_edges.end(); + for(BOP_IT_Edges edge=m_edges.begin();edge!=edgesEnd;edge++) { + if (((*edge)->getVertex1() == v1 && (*edge)->getVertex2() == v2) || + ((*edge)->getVertex1() == v2 && (*edge)->getVertex2() == v1)) + return *edge; + } +#endif + return NULL; +} + +/** + * Returns the mesh edge index with the specified vertex indexs. + * @param v1 vertex index + * @param v2 vertex index + * @param e edge index with the specified vertex indexs + * @return true if there is a mesh edge with the specified vertex indexs, false otherwise + */ +bool BOP_Mesh::getIndexEdge(BOP_Index v1, BOP_Index v2, BOP_Index &e) +{ +#ifdef HASH + int minv; + EdgeEntry *edge; + + /* figure out what and where to look */ + if( v1 < v2 ) { + minv = HASH(v1); + } else { + minv = HASH(v2); + BOP_Index tmp = v1; + v1 = v2; + v2 = tmp; + } + + /* if hash index is valid, look for a match */ + if( minv < hashsize ) { + for(edge = (EdgeEntry *)hash[minv].first; + edge; edge = edge->next ) { + if(edge->v1 == v1 && edge->v2 == v2) + break; + } + + /* edge != NULL means match */ + if(edge) { +#ifdef HASH_PRINTF_DEBUG + printf ("found edge (%d %d)\n",v1,v2); +#endif + e = edge->index; + return true; + } +#ifdef HASH_PRINTF_DEBUG + else + printf ("didn't find edge (%d %d)\n",v1,v2); +#endif + } +#else + BOP_Index pos=0; + const BOP_IT_Edges edgesEnd = m_edges.end(); + for(BOP_IT_Edges edge=m_edges.begin();edge!=edgesEnd;edge++,pos++) { + if (((*edge)->getVertex1() == v1 && (*edge)->getVertex2() == v2) || + ((*edge)->getVertex1() == v2 && (*edge)->getVertex2() == v1)){ + e = pos; + return true; + } + } +#endif + return false; +} + +/** + * Returns the mesh edge on the specified face and relative edge index. + * @param face mesh face + * @param edge face relative edge index + * @return mesh edge on the specified face and relative index, NULL otherwise + */ +BOP_Edge* BOP_Mesh::getEdge(BOP_Face *face, unsigned int edge) +{ + if (face->size()==3) + return getEdge((BOP_Face3 *)face,edge); + else + return getEdge((BOP_Face4 *)face,edge); +} + +/** + * Returns the mesh edge on the specified triangle and relative edge index. + * @param face mesh triangle + * @param edge face relative edge index + * @return mesh edge on the specified triangle and relative index, NULL otherwise + */ +BOP_Edge* BOP_Mesh::getEdge(BOP_Face3 *face, unsigned int edge) +{ + switch(edge){ + case 1: + return getEdge(m_vertexs[face->getVertex(0)]->getEdges(),face->getVertex(1)); + case 2: + return getEdge(m_vertexs[face->getVertex(1)]->getEdges(),face->getVertex(2)); + case 3: + return getEdge(m_vertexs[face->getVertex(2)]->getEdges(),face->getVertex(0)); + }; + + return NULL; +} + +/** + * Returns the mesh edge on the specified quad and relative edge index. + * @param face mesh quad + * @param edge face relative edge index + * @return mesh edge on the specified quad and relative index, NULL otherwise + */ +BOP_Edge * BOP_Mesh::getEdge(BOP_Face4 *face, unsigned int edge) +{ + switch(edge){ + case 1: + return getEdge(m_vertexs[face->getVertex(0)]->getEdges(),face->getVertex(1)); + case 2: + return getEdge(m_vertexs[face->getVertex(1)]->getEdges(),face->getVertex(2)); + case 3: + return getEdge(m_vertexs[face->getVertex(2)]->getEdges(),face->getVertex(3)); + case 4: + return getEdge(m_vertexs[face->getVertex(3)]->getEdges(),face->getVertex(0)); + }; + + return NULL; +} + +/** + * Returns the mesh face with the specified vertex indexs. + * @param v1 vertex index + * @param v2 vertex index + * @param v3 vertex index + * @return mesh edge with the specified vertex indexs, NULL otherwise + */ +BOP_Face* BOP_Mesh::getFace(BOP_Index v1, BOP_Index v2, BOP_Index v3) +{ + const BOP_IT_Faces facesEnd = m_faces.end(); + for(BOP_IT_Faces face=m_faces.begin();face!=facesEnd;face++) { + if ((*face)->containsVertex(v1) && (*face)->containsVertex(v2) && + (*face)->containsVertex(v3)) + return (*face); + } + return NULL; +} + +/** + * Returns the mesh face index with the specified vertex indexs. + * @param v1 vertex index + * @param v2 vertex index + * @param v3 vertex index + * @param f face index with the specified vertex indexs + * @return true if there is a mesh face with the specified vertex indexs, false otherwise + */ +bool BOP_Mesh::getIndexFace(BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index &f) +{ + BOP_Index pos=0; + const BOP_IT_Faces facesEnd = m_faces.end(); + for(BOP_IT_Faces face=m_faces.begin();face!=facesEnd;face++,pos++) { + if ((*face)->containsVertex(v1) && (*face)->containsVertex(v2) && + (*face)->containsVertex(v3)){ + f = pos; + return true; + } + } + return false; +} + +/** + * Returns the vertices set of this mesh. + * @return vertices set + */ +BOP_Vertexs &BOP_Mesh::getVertexs() +{ + return m_vertexs; +} + +/** + * Returns the edges set of this mesh. + * @return edges set + */ +BOP_Edges &BOP_Mesh::getEdges() +{ + return m_edges; +} + +/** + * Returns the faces set of this mesh. + * @return faces set + */ +BOP_Faces &BOP_Mesh::getFaces() +{ + return m_faces; +} + +/** + * Returns the mesh vertex with the specified index. + * @param i vertex index + * @return vertex with the specified index + */ +BOP_Vertex* BOP_Mesh::getVertex(BOP_Index i) +{ + return m_vertexs[i]; +} + +/** + * Returns the mesh edge with the specified index. + * @param i edge index + * @return edge with the specified index + */ +BOP_Edge* BOP_Mesh::getEdge(BOP_Index i) +{ + return m_edges[i]; +} + +/** + * Returns the mesh face with the specified index. + * @param i face index + * @return face with the specified index + */ +BOP_Face* BOP_Mesh::getFace(BOP_Index i) +{ + return m_faces[i]; +} + +/** + * Returns the number of vertices of this mesh. + * @return number of vertices + */ +unsigned int BOP_Mesh::getNumVertexs() +{ + return m_vertexs.size(); +} + +/** + * Returns the number of edges of this mesh. + * @return number of edges + */ +unsigned int BOP_Mesh::getNumEdges() +{ + return m_edges.size(); +} + +/** + * Returns the number of faces of this mesh. + * @return number of faces + */ +unsigned int BOP_Mesh::getNumFaces() +{ + return m_faces.size(); +} + +/** + * Returns the number of vertices of this mesh with the specified tag. + * @return number of vertices with the specified tag + */ +unsigned int BOP_Mesh::getNumVertexs(BOP_TAG tag) +{ + unsigned int count = 0; + const BOP_IT_Vertexs vertexsEnd = m_vertexs.end(); + for(BOP_IT_Vertexs vertex=m_vertexs.begin();vertex!=vertexsEnd;vertex++) { + if ((*vertex)->getTAG() == tag) count++; + } + return count; +} +/** + * Returns the number of faces of this mesh with the specified tag. + * @return number of faces with the specified tag + */ +unsigned int BOP_Mesh::getNumFaces(BOP_TAG tag) +{ + unsigned int count = 0; + const BOP_IT_Faces facesEnd = m_faces.end(); + for(BOP_IT_Faces face=m_faces.begin();face!=facesEnd;face++) { + if ((*face)->getTAG() == tag) count++; + } + return count; +} + +/** + * Marks faces which bad edges as BROKEN (invalid face, no further processing). + * @param edge edge which is being replaced + * @param mesh mesh containing faces + */ + +static void removeBrokenFaces( BOP_Edge *edge, BOP_Mesh *mesh ) +{ + BOP_Faces m_faces = mesh->getFaces(); + + BOP_Indexs edgeFaces = edge->getFaces(); + const BOP_IT_Indexs edgeFacesEnd = edgeFaces.end(); + for(BOP_IT_Indexs idxFace=edgeFaces.begin();idxFace!=edgeFacesEnd; + idxFace++) + m_faces[*idxFace]->setTAG(BROKEN); +} + +/** + * Replaces a vertex index. + * @param oldIndex old vertex index + * @param newIndex new vertex index + */ +BOP_Index BOP_Mesh::replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex) +{ + BOP_IT_Indexs oldEdgeIndex; + if (oldIndex==newIndex) return newIndex; + + // Update faces, edges and vertices + BOP_Vertex *oldVertex = m_vertexs[oldIndex]; + BOP_Vertex *newVertex = m_vertexs[newIndex]; + BOP_Indexs oldEdges = oldVertex->getEdges(); + + // Update faces to the newIndex + BOP_IT_Indexs oldEdgesEnd = oldEdges.end(); + for(oldEdgeIndex=oldEdges.begin();oldEdgeIndex!=oldEdgesEnd; + oldEdgeIndex++) { + BOP_Edge *edge = m_edges[*oldEdgeIndex]; + if ((edge->getVertex1()==oldIndex && edge->getVertex2()==newIndex) || + (edge->getVertex2()==oldIndex && edge->getVertex1()==newIndex)) { + // Remove old edge ==> set edge faces to BROKEN + removeBrokenFaces( edge, this ); + oldVertex->removeEdge(*oldEdgeIndex); + newVertex->removeEdge(*oldEdgeIndex); + } + else { + BOP_Indexs faces = edge->getFaces(); + const BOP_IT_Indexs facesEnd = faces.end(); + for(BOP_IT_Indexs face=faces.begin();face!=facesEnd;face++) { + if (m_faces[*face]->getTAG()!=BROKEN) + m_faces[*face]->replaceVertexIndex(oldIndex,newIndex); + } + } + } + + oldEdgesEnd = oldEdges.end(); + for(oldEdgeIndex=oldEdges.begin();oldEdgeIndex!=oldEdgesEnd; + oldEdgeIndex++) { + BOP_Edge * edge = m_edges[*oldEdgeIndex]; + BOP_Edge * edge2; + BOP_Index v1 = edge->getVertex1(); + + v1 = (v1==oldIndex?edge->getVertex2():v1); + if ((edge2 = getEdge(newIndex,v1)) == NULL) { + edge->replaceVertexIndex(oldIndex,newIndex); + if ( edge->getVertex1() == edge->getVertex2() ) { + removeBrokenFaces( edge, this ); + oldVertex->removeEdge(*oldEdgeIndex); + } +#ifdef HASH + rehashVertex(oldIndex,newIndex,v1); +#endif + newVertex->addEdge(*oldEdgeIndex); + } + else { + BOP_Indexs faces = edge->getFaces(); + const BOP_IT_Indexs facesEnd = faces.end(); + for(BOP_IT_Indexs f=faces.begin();f!=facesEnd;f++) { + if (m_faces[*f]->getTAG()!=BROKEN) + edge2->addFace(*f); + } + BOP_Vertex *oppositeVertex = m_vertexs[v1]; + oppositeVertex->removeEdge(*oldEdgeIndex); + edge->replaceVertexIndex(oldIndex,newIndex); + if ( edge->getVertex1() == edge->getVertex2() ) { + removeBrokenFaces( edge, this ); + oldVertex->removeEdge(*oldEdgeIndex); + newVertex->removeEdge(*oldEdgeIndex); + } +#ifdef HASH + rehashVertex(oldIndex,newIndex,v1); +#endif + } + } + oldVertex->setTAG(BROKEN); + + return newIndex; +} + +bool BOP_Mesh::isClosedMesh() +{ + for(unsigned int i=0; igetFaces(); + unsigned int count = 0; + const BOP_IT_Indexs facesEnd = faces.end(); + for(BOP_IT_Indexs it = faces.begin();it!=facesEnd;it++) { + if (m_faces[*it]->getTAG()!=BROKEN) + count++; + } + + if ((count%2)!=0) return false; + } + + return true; +} + + +/** *************************************************************************** + * DEBUG METHODS * + * This functions are used to test the mesh state and debug program errors. * + ******************************************************************************/ + +/** + * print + */ +void BOP_Mesh::print() +{ + unsigned int i; + cout << "--Faces--" << endl; + for(i=0;igetPoint() << endl; + } +} + +/** + * printFormat + */ +void BOP_Mesh::printFormat(BOP_Faces *faces) +{ + if (faces->size()) { + for(unsigned int it=1;itsize();it++) { + if ((*faces)[it]->getTAG()!=BROKEN) { + cout << m_vertexs[(*faces)[it]->getVertex(0)]->getPoint() << " "; + cout << m_vertexs[(*faces)[it]->getVertex(1)]->getPoint() << " "; + cout << m_vertexs[(*faces)[it]->getVertex(2)]->getPoint() << endl; + } + } + } +} + +/** + * saveFormat + */ +void BOP_Mesh::saveFormat(BOP_Faces *faces,char *filename) +{ + ofstream fout(filename); + + if (!fout.is_open()) { + cerr << "BOP_Mesh::saveFormat Error: Could not create file." << endl; + return; + } + + unsigned int count = 0; + if (faces->size()) { + for(unsigned int it=0;itsize();it++) { + if ((*faces)[it]->getTAG()!=BROKEN) { + count++; + } + } + } + + fout << count << endl; + if (faces->size()) { + for(unsigned int it=0;itsize();it++) { + if ((*faces)[it]->getTAG()!=BROKEN){ + fout << m_vertexs[(*faces)[it]->getVertex(0)]->getPoint() << " "; + fout << m_vertexs[(*faces)[it]->getVertex(1)]->getPoint() << " "; + fout << m_vertexs[(*faces)[it]->getVertex(2)]->getPoint() << endl; + } + } + } + + fout.close(); +} + +/** + * printFormat + */ +void BOP_Mesh::printFormat() +{ + cout << "--Vertices--" << endl; + if (m_vertexs.size()>0) { + cout << "{" << m_vertexs[0]->getPoint().x() << ","; + cout << m_vertexs[0]->getPoint().y() << ","; + cout << m_vertexs[0]->getPoint().z() << "}"; + for(unsigned int i=1;igetPoint().x() << ","; + cout << m_vertexs[i]->getPoint().y() << ","; + cout << m_vertexs[i]->getPoint().z() << "}"; + } + cout << endl; + } + + cout << "--Faces--" << endl; + if (m_faces.size()>0) { + cout << "{" << m_faces[0]->getVertex(0) << ","; + cout << m_faces[0]->getVertex(1) << "," << m_faces[0]->getVertex(2) << "}"; + for(unsigned int i=1;igetVertex(0) << ","; + cout << m_faces[i]->getVertex(1) << "," << m_faces[i]->getVertex(2) << "}"; + } + cout << endl; + } +} + +/** + * printFace + */ +void BOP_Mesh::printFace(BOP_Face *face, int col) +{ + cout << "--Face" << endl; + cout << m_vertexs[face->getVertex(0)]->getPoint(); + cout << " " << m_vertexs[face->getVertex(1)]->getPoint(); + cout << " " << m_vertexs[face->getVertex(2)]->getPoint(); + if (face->size()==4) + cout << " " << m_vertexs[face->getVertex(3)]->getPoint(); + cout << " " << col << endl; +} + +/** + * testMesh + */ +void BOP_Mesh::testMesh() +{ + + BOP_Face* cares[10]; + unsigned int nedges=0,i; + for(i=0;igetFaces(); + unsigned int count = 0; + const BOP_IT_Indexs facesEnd = faces.end(); + for(BOP_IT_Indexs it = faces.begin();it!=facesEnd;it++) { + if (m_faces[*it]->getTAG()!=BROKEN) { + cares[count] = m_faces[*it]; + count++; + + } + } + + if ((count%2)!=0) nedges++; + } + if (nedges) + cout << nedges << " wrong edges." << endl; + else + cout << "well edges." << endl; + + unsigned int duplFaces = 0; + unsigned int wrongFaces = 0; + for(i=0;igetTAG()==BROKEN) + continue; + + if (testFace(faceI)){ + wrongFaces++; + cout << "Wrong Face: " << faceI << endl; + } + + for(unsigned int j=i+1;jgetTAG()==BROKEN) + continue; + + if (testFaces(faceI,faceJ)){ + duplFaces++; + cout << "Duplicate FaceI: " << faceI << endl; + cout << "Duplicate FaceJ: " << faceJ << endl; + } + } + } + + cout << duplFaces << " duplicate faces." << endl; + cout << wrongFaces << " wrong faces." << endl; +} + +/** + * testFace + */ +bool BOP_Mesh::testFace(BOP_Face *face){ + + for(unsigned int i=0;isize();i++){ + for(unsigned int j=i+1;jsize();j++){ + if (face->getVertex(i)==face->getVertex(j)) + return true; + } + } + + return false; +} + +/** + * testFaces + */ +bool BOP_Mesh::testFaces(BOP_Face *faceI, BOP_Face *faceJ){ + + if (faceI->size()size()){ + for(unsigned int i=0;isize();i++){ + if (!faceJ->containsVertex(faceI->getVertex(i))) + return false; + } + //faceI->setTAG(BROKEN); + } + else{ + for(unsigned int i=0;isize();i++){ + if (!faceI->containsVertex(faceJ->getVertex(i))) + return false; + } + //faceJ->setTAG(BROKEN); + } + + return true; +} + +/** + * testPlane + */ +void BOP_Mesh::testPlane(BOP_Face *face) +{ + MT_Plane3 plane1(m_vertexs[face->getVertex(0)]->getPoint(), + m_vertexs[face->getVertex(1)]->getPoint(), + m_vertexs[face->getVertex(2)]->getPoint()); + + if (BOP_orientation(plane1,face->getPlane()) < 0) { + cout << "Test Plane " << face << " v1: "; + cout << m_vertexs[face->getVertex(0)]->getPoint() << " v2: "; + cout << m_vertexs[face->getVertex(1)]->getPoint() << " v3: "; + cout << m_vertexs[face->getVertex(2)]->getPoint() << " plane: "; + cout << face->getPlane() << endl; + cout << "Incorrect vertices order!!! plane1: " << plane1 << " ("; + cout << BOP_orientation(plane1,face->getPlane()) << ") " << " invert "; + cout << MT_Plane3(m_vertexs[face->getVertex(2)]->getPoint(), + m_vertexs[face->getVertex(1)]->getPoint(), + m_vertexs[face->getVertex(0)]->getPoint()) << endl; + if (BOP_collinear(m_vertexs[face->getVertex(0)]->getPoint(), + m_vertexs[face->getVertex(1)]->getPoint(), + m_vertexs[face->getVertex(2)]->getPoint())) { + cout << " COLLINEAR!!!" << endl; + } + else { + cout << endl; + } + } +} + +/** + * testEdges + */ +bool BOP_Mesh::testEdges(BOP_Faces *facesObj) +{ + for(unsigned int i=0;igetFaces(); + unsigned int count = 0; + const BOP_IT_Indexs facesEnd = faces.end(); + for(BOP_IT_Indexs it = faces.begin();it!=facesEnd;it++) { + if ((m_faces[*it]->getTAG()!=BROKEN) && containsFace(facesObj,m_faces[*it])) + count++; + } + if ((count%2)!=0) { + return false; + } + } + + return true; +} + +/** + * updatePlanes + */ +void BOP_Mesh::updatePlanes() +{ + const BOP_IT_Faces facesEnd = m_faces.end(); + for(BOP_IT_Faces it = m_faces.begin();it!=facesEnd;it++) { + BOP_Face *face = *it; + MT_Plane3 plane(m_vertexs[face->getVertex(0)]->getPoint(), + m_vertexs[face->getVertex(1)]->getPoint(), + m_vertexs[face->getVertex(2)]->getPoint()); + face->setPlane(plane); + } +} + diff --git a/intern/boolop/intern/BOP_Mesh.h b/intern/boolop/intern/BOP_Mesh.h new file mode 100644 index 00000000000..f671b9a96c9 --- /dev/null +++ b/intern/boolop/intern/BOP_Mesh.h @@ -0,0 +1,124 @@ +/* + * TEMPORARY defines to enable hashing support + */ + +#define HASH(x) ((x) >> 5) /* each "hash" covers 32 indices */ +// #define HASH_PRINTF_DEBUG /* uncomment to enable debug output */ + +/** + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_MESH_H +#define BOP_MESH_H + +#include "BOP_Vertex.h" +#include "BOP_Edge.h" +#include "BOP_Face.h" +#include "DNA_listBase.h" + +typedef vector BOP_Vertexs; +typedef vector BOP_Edges; +typedef vector::iterator BOP_IT_Vertexs; +typedef vector::iterator BOP_IT_Edges; + +#ifdef HASH +typedef struct EdgeEntry { + struct EdgeEntry *next, *pref; + BOP_Index v1, v2, index; +} EdgeEntry; +#endif + +class BOP_Mesh +{ +private: + BOP_Vertexs m_vertexs; + BOP_Edges m_edges; + BOP_Faces m_faces; +#ifdef HASH + ListBase *hash; + int hashsize; +#endif + + BOP_Index addEdge(BOP_Index v1, BOP_Index v2); + BOP_Edge *getEdge(BOP_Indexs edges, BOP_Index v2); + bool containsFace(BOP_Faces *faces, BOP_Face *face); + + bool testEdges(BOP_Faces *faces); + bool testFaces(BOP_Face *faceI, BOP_Face *faceJ); + bool testFace(BOP_Face *face); + +public: + BOP_Mesh(); + ~BOP_Mesh(); + + BOP_Index addVertex(MT_Point3 point); + BOP_Index addFace(BOP_Face *face); + BOP_Index addFace(BOP_Face3 *face); + BOP_Index addFace(BOP_Face4 *face); + BOP_Vertex* getVertex(BOP_Index v); + BOP_Face*getFace(BOP_Index v); + BOP_Edge* getEdge(BOP_Index v); + BOP_Edge* getEdge(BOP_Face * face, unsigned int edge); + BOP_Edge* getEdge(BOP_Face3 * face, unsigned int edge); + BOP_Edge* getEdge(BOP_Face4 * face, unsigned int edge); + BOP_Edge* getEdge(BOP_Index v1, BOP_Index v2); + bool getIndexEdge(BOP_Index v1, BOP_Index v2, BOP_Index &e); + BOP_Vertexs &getVertexs(); + BOP_Edges &getEdges(); + BOP_Faces &getFaces(); + BOP_Face* getFace(BOP_Index v1, BOP_Index v2, BOP_Index v3); + bool getIndexFace(BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index &f); + unsigned int getNumVertexs(); + unsigned int getNumEdges(); + unsigned int getNumFaces(); + unsigned int getNumVertexs(BOP_TAG tag); + unsigned int getNumFaces(BOP_TAG tag); + BOP_Index replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex); +#ifdef HASH + void rehashVertex(BOP_Index oldIndex, BOP_Index newIndex, + BOP_Index otherIndex); +#endif + bool isClosedMesh(); + + // Debug functions + void print(); + void printFormat(); + void printFormat(BOP_Faces *faces); + void saveFormat(BOP_Faces *faces, char *filename); + void printFace(BOP_Face *face, int col = 0); + void testPlane(BOP_Face *face); + void testMesh(); + void updatePlanes(); +}; + +#endif diff --git a/intern/boolop/intern/BOP_Segment.cpp b/intern/boolop/intern/BOP_Segment.cpp new file mode 100644 index 00000000000..2a81660c4ff --- /dev/null +++ b/intern/boolop/intern/BOP_Segment.cpp @@ -0,0 +1,247 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_Segment.h" + +#define UNDEFINED 0 + +/** + * Constructs a new segment. + */ +BOP_Segment::BOP_Segment(){ + m_cfg1 = UNDEFINED; + m_cfg2 = UNDEFINED; +} + +/** + * Returns the relative edge index between two relative vertex indices. + * @param v1 relative vertex index + * @param v2 relative vertex index + * @return relative edge index between two relative vertex indices, -1 otherwise + */ +int BOP_Segment::getEdgeBetween(unsigned int v1, unsigned int v2) +{ + if ((v1 == 1 && v2 == 2) || (v1 == 2 && v2 == 1)) return 1; + if ((v1 == 3 && v2 == 2) || (v1 == 2 && v2 == 3)) return 2; + if ((v1 == 1 && v2 == 3) || (v1 == 3 && v2 == 1)) return 3; + return -1; +} + +/** + * Returns if a relative vertex index is on a relative edge index. + * @param v relative vertex index + * @param e relative edge index + * @return true if the relative vertex index is on the relative edge index, + * false otherwise. + */ +bool BOP_Segment::isOnEdge(unsigned int v, unsigned int e) +{ + if (v == 1 && (e == 1 || e == 3)) return true; + if (v == 2 && (e == 1 || e == 2)) return true; + if (v == 3 && (e == 2 || e == 3)) return true; + return false; +} + +/** + * Inverts the segment, swapping ends data. + */ +void BOP_Segment::invert() +{ + BOP_Index aux = m_v1; + m_v1 = m_v2; + m_v2 = aux; + aux = m_cfg1; + m_cfg1 = m_cfg2; + m_cfg2 = aux; +} + +/** + * Sorts the segment according to ends configuration. + * The criterion to sort is ... + * + * UNDEFINED < VERTEX < EDGE < IN + * cfg1 > cfg2 + * + * so ... + * + * VERTEX(cfg1) => UNDEFINED(cfg2) || VERTEX(cfg2) + * EDGE(cfg1) => UNDEFINED(cfg2) || VERTEX(cfg2) || EDGE(cfg2) + * IN(cfg1) => UNDEFINED(cfg2) || VERTEX(cfg2) || EDGE(cfg2) || IN(cfg2) + */ +void BOP_Segment::sort() +{ + if (m_cfg1 < m_cfg2) invert(); +} + +/** + * Returns if the specified end segment configuration is IN. + * @return true if the specified end segment configuration is IN, false otherwise + */ +bool BOP_Segment::isIn(unsigned int cfg) +{ + return (cfg == 20); +} + +/** + * Returns if the specified end segment configuration is EDGE. + * @return true if the specified end segment configuration is EDGE, false otherwise + */ +bool BOP_Segment::isEdge(unsigned int cfg) +{ + return (cfg > 10) && (cfg < 20); +} + +/** + * Returns if the specified end segment configuration is VERTEX. + * @return true if the specified end segment configuration is VERTEX, false otherwise + */ +bool BOP_Segment::isVertex(unsigned int cfg) +{ + return (cfg!=UNDEFINED) && (cfg < 10); +} + +/** + * Returns if the specified end segment configuration is DEFINED (not UNDEFINED). + * @return true if the specified end segment configuration is DEFINED, false otherwise + */ +bool BOP_Segment::isDefined(unsigned int cfg) +{ + return (cfg != UNDEFINED); +} + +/** + * Returns if the specified end segment configuration is UNDEFINED. + * @return true if the specified end segment configuration is UNDEFINED, false otherwise + */ +bool BOP_Segment::isUndefined(unsigned int cfg) +{ + return (cfg == UNDEFINED); +} + +/** + * Returns the relative edge index from the specified end segment configuration. + * @return relative edge index from the specified end segment configuration + */ +unsigned int BOP_Segment::getEdge(unsigned int cfg) +{ + return cfg-10; +} + +/** + * Returns the relative vertex index from the specified end segment configuration. + * @return relative vertex index from the specified end segment configuration + */ +BOP_Index BOP_Segment::getVertex(unsigned int cfg) +{ + return cfg; +} + +/** + * Returns the end segment configuration for the specified relative edge index. + * @return end segment configuration for the specified relative edge index + */ +unsigned int BOP_Segment::createEdgeCfg(unsigned int edge) +{ + return 10+edge; +} + +/** + * Returns the end segment configuration for the specified relative vertex index. + * @return end segment configuration for the specified relative vertex index + */ +unsigned int BOP_Segment::createVertexCfg(BOP_Index vertex) +{ + return vertex; +} + +/** + * Returns the end segment IN configuration. + * @return end segment IN configuration + */ +unsigned int BOP_Segment::createInCfg() +{ + return 20; +} + +/** + * Returns the end segment UNDEFINED configuration. + * @return end segment UNDEFINED configuration + */ +unsigned int BOP_Segment::createUndefinedCfg() +{ + return UNDEFINED; +} + +/** + * Returns the inner segment configuration. + * @return inner segment configuration + */ +unsigned int BOP_Segment::getConfig() +{ + if (isUndefined(m_cfg1)) return m_cfg2; + else if (isUndefined(m_cfg2)) return m_cfg1; + else if (isVertex(m_cfg1)) { + // v1 is vertex + if (isVertex(m_cfg2)) { + // v2 is vertex + return createEdgeCfg(getEdgeBetween(getVertex(m_cfg1),getVertex(m_cfg2))); + } + else if (isEdge(m_cfg2)) { + // v2 is edge + if (isOnEdge(m_cfg1,getEdge(m_cfg2))) return m_cfg2; + else return createInCfg(); //IN + } + else return createInCfg(); //IN + } + else if (isEdge(m_cfg1)) { + // v1 is edge + if (isVertex(m_cfg2)) { + // v2 is vertex + if (isOnEdge(m_cfg2,getEdge(m_cfg1))) return m_cfg1; + else return createInCfg(); //IN + } + else if (isEdge(m_cfg2)) { + // v2 is edge + if (m_cfg1 == m_cfg2) return m_cfg1; + else return createInCfg(); // IN + } + else return createInCfg(); // IN + } + else return createInCfg(); // IN +} + +/** + * Implements operator << + */ +ostream &operator<<(ostream &stream, const BOP_Segment &c) +{ + cout << "m_v1: " << c.m_v1 << "(" << c.m_cfg1 << ") m_v2: " << c.m_v2 << "(" << c.m_cfg2 << ")"; + return stream; +} diff --git a/intern/boolop/intern/BOP_Segment.h b/intern/boolop/intern/BOP_Segment.h new file mode 100644 index 00000000000..caa6157346c --- /dev/null +++ b/intern/boolop/intern/BOP_Segment.h @@ -0,0 +1,73 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_SEGMENT_H +#define BOP_SEGMENT_H + +#include "BOP_Indexs.h" +#include +using namespace std; + +class BOP_Segment +{ +private: + int getEdgeBetween(unsigned int v1, unsigned int v2); + bool isOnEdge(unsigned int v, unsigned int e); + +public: + // Cfg : Configuration of the vertices + // Values: + // 20 IN, + // 1X Intersected edge X{1,2,3} of the face, + // 0X Coincident vertice X{1,2,3} of the face, + // 0 otherwise + unsigned int m_cfg1, m_cfg2; + BOP_Index m_v1, m_v2; // if cfgX >0, vX is the vertice index of the face + BOP_Segment(); + + static bool isIn(unsigned int cfg); + static bool isEdge(unsigned int cfg); + static bool isVertex(unsigned int cfg); + static bool isDefined(unsigned int cfg); + static bool isUndefined(unsigned int cfg); + static unsigned int getEdge(unsigned int cfg); + static BOP_Index getVertex(unsigned int cfg); + static unsigned int createEdgeCfg(unsigned int edge); + static unsigned int createVertexCfg(BOP_Index vertex); + static unsigned int createInCfg(); + static unsigned int createUndefinedCfg(); + void invert(); + void sort(); + unsigned int getConfig(); + + friend ostream &operator<<(ostream &stream, const BOP_Segment &c); +}; + +#endif diff --git a/intern/boolop/intern/BOP_Splitter.cpp b/intern/boolop/intern/BOP_Splitter.cpp new file mode 100644 index 00000000000..07f1f4d6c96 --- /dev/null +++ b/intern/boolop/intern/BOP_Splitter.cpp @@ -0,0 +1,193 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_Splitter.h" +#include "BOP_Tag.h" + +#include +using namespace std; + +/** + * Returns the split point resulting from intersect a plane and a mesh face + * according to its specified relative edge. + * @param plane split plane + * @param m mesh + * @param f face + * @param e relative edge index + * @return intersection point + */ +MT_Point3 BOP_splitEdge(MT_Plane3 plane, BOP_Mesh *m, BOP_Face *f, unsigned int e) +{ + int v1 = -1, v2 = -1; + + switch(e) { + case 1: + v1 = f->getVertex(0); + v2 = f->getVertex(1); + break; + case 2: + v1 = f->getVertex(1); + v2 = f->getVertex(2); + break; + case 3: + v1 = f->getVertex(2); + v2 = f->getVertex(0); + break; + default: + // wrong relative edge index! + break; + } + + MT_Point3 p1 = m->getVertex(v1)->getPoint(); + MT_Point3 p2 = m->getVertex(v2)->getPoint(); + return BOP_intersectPlane(plane,p1,p2); +} + +/** + * Returns the segment resulting from intersect a plane and a mesh face. + * @param plane split plane + * @param m mesh + * @param f face + * @return segment if there is intersection, NULL otherwise + */ +BOP_Segment BOP_splitFace(MT_Plane3 plane, BOP_Mesh *m, BOP_Face *f) +{ + BOP_Vertex *v1 = m->getVertex(f->getVertex(0)); + BOP_Vertex *v2 = m->getVertex(f->getVertex(1)); + BOP_Vertex *v3 = m->getVertex(f->getVertex(2)); + + // Classify face vertices + BOP_TAG tag1 = BOP_createTAG(BOP_classify(v1->getPoint(),plane)); + BOP_TAG tag2 = BOP_createTAG(BOP_classify(v2->getPoint(),plane)); + BOP_TAG tag3 = BOP_createTAG(BOP_classify(v3->getPoint(),plane)); + + // Classify face according to its vertices classification + BOP_TAG tag = BOP_createTAG(tag1,tag2,tag3); + + BOP_Segment s; + + switch(tag) { + case IN_IN_IN : + case OUT_OUT_OUT : + case ON_ON_ON : + s.m_cfg1 = s.m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + + case ON_OUT_OUT : + case ON_IN_IN : + s.m_v1 = f->getVertex(0); + s.m_cfg1 = BOP_Segment::createVertexCfg(1); + s.m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + + case OUT_ON_OUT : + case IN_ON_IN : + s.m_v1 = f->getVertex(1); + s.m_cfg1 = BOP_Segment::createVertexCfg(2); + s.m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + + case OUT_OUT_ON : + case IN_IN_ON : + s.m_v1 = f->getVertex(2); + s.m_cfg1 = BOP_Segment::createVertexCfg(3); + s.m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + + case ON_ON_IN : + case ON_ON_OUT : + s.m_v1 = f->getVertex(0); + s.m_v2 = f->getVertex(1); + s.m_cfg1 = BOP_Segment::createVertexCfg(1); + s.m_cfg2 = BOP_Segment::createVertexCfg(2); + break; + + case ON_OUT_ON : + case ON_IN_ON : + s.m_v1 = f->getVertex(0); + s.m_v2 = f->getVertex(2); + s.m_cfg1 = BOP_Segment::createVertexCfg(1); + s.m_cfg2 = BOP_Segment::createVertexCfg(3); + break; + + case OUT_ON_ON : + case IN_ON_ON : + s.m_v1 = f->getVertex(1); + s.m_v2 = f->getVertex(2); + s.m_cfg1 = BOP_Segment::createVertexCfg(2); + s.m_cfg2 = BOP_Segment::createVertexCfg(3); + break; + + case IN_OUT_ON : + case OUT_IN_ON : + s.m_v2 = f->getVertex(2); + s.m_cfg1 = BOP_Segment::createEdgeCfg(1); + s.m_cfg2 = BOP_Segment::createVertexCfg(3); + break; + + case IN_ON_OUT : + case OUT_ON_IN : + s.m_v1 = f->getVertex(1); + s.m_cfg1 = BOP_Segment::createVertexCfg(2); + s.m_cfg2 = BOP_Segment::createEdgeCfg(3); + break; + + case ON_IN_OUT : + case ON_OUT_IN : + s.m_v1 = f->getVertex(0); + s.m_cfg1 = BOP_Segment::createVertexCfg(1); + s.m_cfg2 = BOP_Segment::createEdgeCfg(2); + break; + + case OUT_IN_IN : + case IN_OUT_OUT : + s.m_cfg1 = BOP_Segment::createEdgeCfg(1); + s.m_cfg2 = BOP_Segment::createEdgeCfg(3); + break; + + case OUT_IN_OUT : + case IN_OUT_IN : + s.m_cfg1 = BOP_Segment::createEdgeCfg(1); + s.m_cfg2 = BOP_Segment::createEdgeCfg(2); + break; + + case OUT_OUT_IN : + case IN_IN_OUT : + s.m_cfg1 = BOP_Segment::createEdgeCfg(2); + s.m_cfg2 = BOP_Segment::createEdgeCfg(3); + break; + + default: + // wrong TAG! + break; + } + + return s; +} diff --git a/intern/boolop/intern/BOP_Splitter.h b/intern/boolop/intern/BOP_Splitter.h new file mode 100644 index 00000000000..02cbdd2aa72 --- /dev/null +++ b/intern/boolop/intern/BOP_Splitter.h @@ -0,0 +1,44 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_SPLITTER_H +#define BOP_SPLITTER_H + +#include "BOP_MathUtils.h" +#include "BOP_Segment.h" +#include "BOP_Mesh.h" + +#include "MT_Plane3.h" +#include "MT_Point3.h" + +MT_Point3 BOP_splitEdge(MT_Plane3 plane, BOP_Mesh *mesh, BOP_Face *face, unsigned int edge); +BOP_Segment BOP_splitFace(MT_Plane3 plane, BOP_Mesh *mesh, BOP_Face *face); + +#endif diff --git a/intern/boolop/intern/BOP_Tag.cpp b/intern/boolop/intern/BOP_Tag.cpp new file mode 100644 index 00000000000..6a8832870fa --- /dev/null +++ b/intern/boolop/intern/BOP_Tag.cpp @@ -0,0 +1,142 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_Tag.h" + +/** + * Gets the tag description. + * @param t tag + * @param dest tag description + */ +void BOP_stringTAG(BOP_TAG t, char *dest) { + + switch(t){ + case IN_IN_IN: + sprintf(dest, "IN_IN_IN"); + break; + case IN_IN_ON: + sprintf(dest, "IN_IN_ON"); + break; + case IN_ON_IN: + sprintf(dest, "IN_ON_IN"); + break; + case IN_ON_ON: + sprintf(dest, "IN_ON_ON"); + break; + case ON_IN_IN: + sprintf(dest, "ON_IN_IN"); + break; + case ON_IN_ON: + sprintf(dest, "ON_IN_ON"); + break; + case ON_ON_IN: + sprintf(dest, "ON_ON_IN"); + break; + case ON_ON_ON: + sprintf(dest, "ON_ON_ON"); + break; + case OUT_OUT_OUT: + sprintf(dest, "OUT_OUT_OUT"); + break; + case OUT_OUT_ON: + sprintf(dest, "OUT_OUT_ON"); + break; + case OUT_ON_OUT: + sprintf(dest, "OUT_ON_OUT"); + break; + case OUT_ON_ON: + sprintf(dest, "OUT_ON_ON"); + break; + case ON_OUT_OUT: + sprintf(dest, "ON_OUT_OUT"); + break; + case ON_OUT_ON: + sprintf(dest, "ON_OUT_ON"); + break; + case ON_ON_OUT: + sprintf(dest, "ON_ON_OUT"); + break; + case OUT_OUT_IN: + sprintf(dest, "OUT_OUT_IN"); + break; + case OUT_IN_OUT: + sprintf(dest, "OUT_IN_OUT"); + break; + case OUT_IN_IN: + sprintf(dest, "OUT_IN_IN"); + break; + case IN_OUT_OUT: + sprintf(dest, "IN_OUT_OUT"); + break; + case IN_OUT_IN: + sprintf(dest, "IN_OUT_IN"); + break; + case IN_IN_OUT: + sprintf(dest, "IN_IN_OUT"); + break; + case OUT_ON_IN: + sprintf(dest, "OUT_ON_IN"); + break; + case OUT_IN_ON: + sprintf(dest, "OUT_IN_ON"); + break; + case IN_ON_OUT: + sprintf(dest, "IN_ON_OUT"); + break; + case IN_OUT_ON: + sprintf(dest, "IN_OUT_ON"); + break; + case ON_IN_OUT: + sprintf(dest, "ON_IN_OUT"); + break; + case ON_OUT_IN: + sprintf(dest, "ON_OUT_IN"); + break; + case UNCLASSIFIED: + sprintf(dest, "UNCLASSIFIED"); + break; + case BROKEN: + sprintf(dest, "BROKEN"); + break; + case PHANTOM: + sprintf(dest, "PHANTOM"); + break; + case OVERLAPPED: + sprintf(dest, "OVERLAPPED"); + break; + case INOUT: + sprintf(dest, "INOUT"); + break; + default: + sprintf(dest, "DESCONEGUT %d",t); + break; + } + +} diff --git a/intern/boolop/intern/BOP_Tag.h b/intern/boolop/intern/BOP_Tag.h new file mode 100644 index 00000000000..2b6ff93b679 --- /dev/null +++ b/intern/boolop/intern/BOP_Tag.h @@ -0,0 +1,145 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include + +#ifndef BOP_TAG_H +#define BOP_TAG_H + +#define IN_TAG 0x02 // Below the plane +#define ON_TAG 0x00 // On the plane +#define OUT_TAG 0x01 // Above the plane +#define INOUT_TAG 0x0E // Above and below the plane +#define INON_TAG 0x12 // Below and on the plane +#define OUTON_TAG 0x11 // Above and on the plane +#define UNCLASSIFIED_TAG 0x0F // Expecting to be classified + +#define PHANTOM_TAG 0x0C // Phantom face +#define OVERLAPPED_TAG 0x0D // Overlapped face +#define BROKEN_TAG 0x0B // Splitted and unused ... + +#define ON_ON_IN_TAG IN_TAG +#define ON_IN_ON_TAG IN_TAG << 2 +#define IN_ON_ON_TAG IN_TAG << 4 + +#define ON_ON_OUT_TAG OUT_TAG +#define ON_OUT_ON_TAG OUT_TAG << 2 +#define OUT_ON_ON_TAG OUT_TAG << 4 + +#define ON_ON_ON_TAG ON_TAG +#define IN_IN_IN_TAG IN_ON_ON_TAG | ON_IN_ON_TAG | ON_ON_IN_TAG +#define OUT_OUT_OUT_TAG OUT_ON_ON_TAG | ON_OUT_ON_TAG | ON_ON_OUT_TAG + +#define IN_IN_ON_TAG IN_ON_ON_TAG | ON_IN_ON_TAG +#define IN_ON_IN_TAG IN_ON_ON_TAG | ON_ON_IN_TAG +#define ON_IN_IN_TAG ON_IN_ON_TAG | ON_ON_IN_TAG + +#define OUT_OUT_ON_TAG OUT_ON_ON_TAG | ON_OUT_ON_TAG +#define OUT_ON_OUT_TAG OUT_ON_ON_TAG | ON_ON_OUT_TAG +#define ON_OUT_OUT_TAG ON_OUT_ON_TAG | ON_ON_OUT_TAG + +#define IN_OUT_OUT_TAG IN_ON_ON_TAG | ON_OUT_OUT_TAG +#define OUT_IN_OUT_TAG ON_IN_ON_TAG | OUT_ON_OUT_TAG +#define OUT_OUT_IN_TAG ON_ON_IN_TAG | OUT_OUT_ON_TAG + +#define OUT_IN_IN_TAG ON_IN_IN_TAG | OUT_ON_ON_TAG +#define IN_OUT_IN_TAG IN_ON_IN_TAG | ON_OUT_ON_TAG +#define IN_IN_OUT_TAG IN_IN_ON_TAG | ON_ON_OUT_TAG + +#define IN_ON_OUT_TAG IN_ON_ON_TAG | ON_ON_OUT_TAG +#define IN_OUT_ON_TAG IN_ON_ON_TAG | ON_OUT_ON_TAG +#define ON_IN_OUT_TAG ON_IN_ON_TAG | ON_ON_OUT_TAG +#define ON_OUT_IN_TAG ON_ON_IN_TAG | ON_OUT_ON_TAG +#define OUT_IN_ON_TAG ON_IN_ON_TAG | OUT_ON_ON_TAG +#define OUT_ON_IN_TAG ON_ON_IN_TAG | OUT_ON_ON_TAG + +typedef enum BOP_TAGEnum { + IN = IN_TAG, + ON = ON_TAG, + OUT = OUT_TAG, + INOUT = INOUT_TAG, + INON = INON_TAG, + OUTON = OUTON_TAG, + UNCLASSIFIED = UNCLASSIFIED_TAG, + PHANTOM = PHANTOM_TAG, + OVERLAPPED = OVERLAPPED_TAG, + BROKEN = BROKEN_TAG, + IN_ON_ON = IN_ON_ON_TAG, + ON_IN_ON = ON_IN_ON_TAG, + ON_ON_IN = ON_ON_IN_TAG, + OUT_ON_ON = OUT_ON_ON_TAG, + ON_OUT_ON = ON_OUT_ON_TAG, + ON_ON_OUT = ON_ON_OUT_TAG, + ON_ON_ON = ON_ON_ON_TAG, + IN_IN_IN = IN_IN_IN_TAG, + OUT_OUT_OUT = OUT_OUT_OUT_TAG, + IN_IN_ON = IN_IN_ON_TAG, + IN_ON_IN = IN_ON_IN_TAG, + ON_IN_IN = ON_IN_IN_TAG, + OUT_OUT_ON = OUT_OUT_ON_TAG, + OUT_ON_OUT = OUT_ON_OUT_TAG, + ON_OUT_OUT = ON_OUT_OUT_TAG, + IN_OUT_OUT = IN_OUT_OUT_TAG, + OUT_IN_OUT = OUT_IN_OUT_TAG, + OUT_OUT_IN = OUT_OUT_IN_TAG, + OUT_IN_IN = OUT_IN_IN_TAG, + IN_OUT_IN = IN_OUT_IN_TAG, + IN_IN_OUT = IN_IN_OUT_TAG, + IN_ON_OUT = IN_ON_OUT_TAG, + IN_OUT_ON = IN_OUT_ON_TAG, + ON_IN_OUT = ON_IN_OUT_TAG, + ON_OUT_IN = ON_OUT_IN_TAG, + OUT_IN_ON = OUT_IN_ON_TAG, + OUT_ON_IN = OUT_ON_IN_TAG } BOP_TAG; + +inline BOP_TAG BOP_createTAG(BOP_TAG tag1, BOP_TAG tag2, BOP_TAG tag3) +{ + return (BOP_TAG) (tag1 << 4 | tag2 << 2 | tag3); +} + +inline BOP_TAG BOP_createTAG(int i) +{ + return i < 0 ? IN : i > 0 ? OUT : ON; +} + +inline BOP_TAG BOP_addON(BOP_TAG tag) +{ + return (tag==IN?INON:(tag==OUT?OUTON:tag)); +} + +void BOP_stringTAG(BOP_TAG tag, char *dest); + +inline bool BOP_compTAG(BOP_TAG tag1, BOP_TAG tag2) +{ + return (tag1==tag2) || (BOP_addON(tag1) == BOP_addON(tag2)); +} + +#endif diff --git a/intern/boolop/intern/BOP_Triangulator.cpp b/intern/boolop/intern/BOP_Triangulator.cpp new file mode 100644 index 00000000000..fd7b3154195 --- /dev/null +++ b/intern/boolop/intern/BOP_Triangulator.cpp @@ -0,0 +1,572 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_Triangulator.h" +#include +using namespace std; + +void BOP_addFace(BOP_Mesh* mesh, BOP_Faces *faces, BOP_Face* face, BOP_TAG tag); +void BOP_splitQuad(BOP_Mesh* mesh, MT_Plane3 plane, BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4, + BOP_Face* triangles[], BOP_Index original); +BOP_Index BOP_getTriangleVertex(BOP_Mesh* mesh, BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4); +BOP_Index BOP_getNearestVertex(BOP_Mesh* mesh, BOP_Index u, BOP_Index v1, BOP_Index v2); +bool BOP_isInsideCircle(BOP_Mesh* mesh, BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4, BOP_Index v5); +bool BOP_isInsideCircle(BOP_Mesh* mesh, BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index w); +void BOP_triangulateC_split(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, + BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4, BOP_Index v5); +void BOP_triangulateD_split(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, + BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4, BOP_Index v5); + +/** + * Triangulates the face in two new faces by splitting one edge. + * + * * + * /|\ + * / | \ + * / | \ + * / | \ + * / | \ + * *-----x-----* + * + * @param mesh mesh that contains the faces, edges and vertices + * @param faces set of faces that contains face and will contains new faces + * @param face input face to be triangulate + * @param v vertex index that intersects the edge + * @param e relative edge index used to triangulate the face + */ + + +void BOP_triangulateA(BOP_Mesh *mesh, BOP_Faces *faces, BOP_Face * face, BOP_Index v, unsigned int e) +{ + BOP_Face *face1, *face2; + if (e == 1) { + face1 = new BOP_Face3(face->getVertex(0), v, face->getVertex(2), face->getPlane(), + face->getOriginalFace()); + face2 = new BOP_Face3(v, face->getVertex(1), face->getVertex(2), face->getPlane(), + face->getOriginalFace()); + } + else if (e == 2) { + face1 = new BOP_Face3(face->getVertex(0), face->getVertex(1), v, face->getPlane(), + face->getOriginalFace()); + face2 = new BOP_Face3(face->getVertex(0), v, face->getVertex(2), face->getPlane(), + face->getOriginalFace()); + } + else if (e == 3) { + face1 = new BOP_Face3(face->getVertex(0), face->getVertex(1), v, face->getPlane(), + face->getOriginalFace()); + face2 = new BOP_Face3(face->getVertex(1), face->getVertex(2), v, face->getPlane(), + face->getOriginalFace()); + } + else { + return; + } + + BOP_addFace(mesh, faces, face1, face->getTAG()); + BOP_addFace(mesh, faces, face2, face->getTAG()); + face1->setSplit(face->getSplit()); + face2->setSplit(face->getSplit()); + + face->setTAG(BROKEN); + face->freeBBox(); +} + +/** + * Triangulates the face in three new faces by one inner point. + * + * * + * / \ + * / \ + * / \ + * / x \ + * / \ + * *-----------* + * + * @param mesh mesh that contains the faces, edges and vertices + * @param faces set of faces that contains face and will contains new faces + * @param face input face to be triangulate + * @param v vertex index that lays inside face + */ +void BOP_triangulateB(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, BOP_Index v) +{ + BOP_Face *face1 = new BOP_Face3(face->getVertex(0), face->getVertex(1), v, face->getPlane(), + face->getOriginalFace()); + BOP_Face *face2 = new BOP_Face3(face->getVertex(1), face->getVertex(2), v, face->getPlane(), + face->getOriginalFace()); + BOP_Face *face3 = new BOP_Face3(face->getVertex(2), face->getVertex(0), v, face->getPlane(), + face->getOriginalFace()); + + BOP_addFace(mesh,faces,face1,face->getTAG()); + BOP_addFace(mesh,faces,face2,face->getTAG()); + BOP_addFace(mesh,faces,face3,face->getTAG()); + face1->setSplit(face->getSplit()); + face2->setSplit(face->getSplit()); + face3->setSplit(face->getSplit()); + face->setTAG(BROKEN); + face->freeBBox(); +} + + +/** + * Triangulates the face in five new faces by two inner points. + * + * * + * / \ + * / \ + * / \ + * / x x \ + * / \ + * *-----------* + * + * @param mesh mesh that contains the faces, edges and vertices + * @param faces set of faces that contains face and will contains new faces + * @param face input face to be triangulate + * @param v1 first vertex index that lays inside face + * @param v2 second vertex index that lays inside face + */ +void BOP_triangulateC(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, BOP_Index v1, BOP_Index v2) +{ + if (!BOP_isInsideCircle(mesh, face->getVertex(0), v1, v2, face->getVertex(1), face->getVertex(2))) { + BOP_triangulateC_split(mesh, faces, face, face->getVertex(0), face->getVertex(1), + face->getVertex(2), v1, v2); + } + else if (!BOP_isInsideCircle(mesh, face->getVertex(1), v1, v2, face->getVertex(0), face->getVertex(2))) { + BOP_triangulateC_split(mesh, faces, face, face->getVertex(1), face->getVertex(2), + face->getVertex(0), v1, v2); + } + else if (!BOP_isInsideCircle(mesh, face->getVertex(2), v1, v2, face->getVertex(0), face->getVertex(1))) { + BOP_triangulateC_split(mesh, faces, face, face->getVertex(2), face->getVertex(0), + face->getVertex(1), v1, v2); + } + else { + BOP_triangulateC_split(mesh, faces, face, face->getVertex(2), face->getVertex(0), + face->getVertex(1), v1, v2); + } +} + +/** + * Triangulates the face (v1,v2,v3) in five new faces by two inner points (v4,v5), where + * v1 v4 v5 defines the nice triangle and v4 v5 v2 v3 defines the quad to be tesselated. + * @param mesh mesh that contains the faces, edges and vertices + * @param faces set of faces that contains face and will contains new faces + * @param face input face to be triangulate + * @param v1 first vertex index that defines the original triangle + * @param v2 second vertex index that defines the original triangle + * @param v3 third vertex index that defines the original triangle + * @param v4 first vertex index that lays inside face + * @param v5 second vertex index that lays inside face + */ +void BOP_triangulateC_split(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, + BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4, BOP_Index v5) +{ + BOP_Index v = BOP_getTriangleVertex(mesh, v1, v2, v4, v5); + BOP_Index w = (v == v4 ? v5 : v4); + BOP_Face *face1 = new BOP_Face3(v1, v, w, face->getPlane(), face->getOriginalFace()); + BOP_Face *face2 = new BOP_Face3(v1, v2, v, face->getPlane(), face->getOriginalFace()); + BOP_Face *face3 = new BOP_Face3(v1, w, v3, face->getPlane(), face->getOriginalFace()); + + // v1 v w defines the nice triangle in the correct order + // v1 v2 v defines one lateral triangle in the correct order + // v1 w v3 defines the other lateral triangle in the correct order + // w v v2 v3 defines the quad in the correct order + + BOP_addFace(mesh, faces, face1, face->getTAG()); + BOP_addFace(mesh, faces, face2, face->getTAG()); + BOP_addFace(mesh, faces, face3, face->getTAG()); + + face1->setSplit(face->getSplit()); + face2->setSplit(face->getSplit()); + face3->setSplit(face->getSplit()); + + BOP_Face *faces45[2]; + + BOP_splitQuad(mesh, face->getPlane(), v2, v3, w, v, faces45, face->getOriginalFace()); + BOP_addFace(mesh, faces, faces45[0], face->getTAG()); + BOP_addFace(mesh, faces, faces45[1], face->getTAG()); + faces45[0]->setSplit(face->getSplit()); + faces45[1]->setSplit(face->getSplit()); + + face->setTAG(BROKEN); + face->freeBBox(); +} + + +/** + * Triangulates the face in three new faces by splitting twice an edge. + * + * * + * / \ + * / \ + * / \ + * / \ + * / \ + * *---x---x---* + * + * @param mesh mesh that contains the faces, edges and vertices + * @param faces set of faces that contains face and will contains new faces + * @param face input face to be triangulate + * @param v1 first vertex index that intersects the edge + * @param v2 second vertex index that intersects the edge + * @param e relative edge index used to triangulate the face + */ +void BOP_triangulateD(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, BOP_Index v1, + BOP_Index v2, unsigned int e) +{ + if (e == 1) { + BOP_triangulateD_split(mesh, faces, face, face->getVertex(0), face->getVertex(1), + face->getVertex(2), v1, v2); + } + else if (e == 2) { + BOP_triangulateD_split(mesh, faces, face, face->getVertex(1), face->getVertex(2), + face->getVertex(0), v1, v2); + } + else if (e == 3) { + BOP_triangulateD_split(mesh, faces, face, face->getVertex(2), face->getVertex(0), + face->getVertex(1), v1, v2); + } +} + +/** + * Triangulates the face (v1,v2,v3) in three new faces by splitting twice an edge. + * @param mesh mesh that contains the faces, edges and vertices + * @param faces set of faces that contains face and will contains new faces + * @param face input face to be triangulate + * @param v1 first vertex index that defines the original triangle + * @param v2 second vertex index that defines the original triangle + * @param v3 third vertex index that defines the original triangle + * @param v4 first vertex index that lays on the edge + * @param v5 second vertex index that lays on the edge + */ +void BOP_triangulateD_split(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, + BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4, BOP_Index v5) +{ + BOP_Index v = BOP_getNearestVertex(mesh, v1, v4, v5); + BOP_Index w = (v == v4 ? v5 : v4); + BOP_Face *face1 = new BOP_Face3(v1, v, v3, face->getPlane(), face->getOriginalFace()); + BOP_Face *face2 = new BOP_Face3(v, w, v3, face->getPlane(), face->getOriginalFace()); + BOP_Face *face3 = new BOP_Face3(w, v2, v3, face->getPlane(), face->getOriginalFace()); + + BOP_addFace(mesh, faces, face1, face->getTAG()); + BOP_addFace(mesh, faces, face2, face->getTAG()); + BOP_addFace(mesh, faces, face3, face->getTAG()); + face1->setSplit(face->getSplit()); + face2->setSplit(face->getSplit()); + face3->setSplit(face->getSplit()); + + face->setTAG(BROKEN); + face->freeBBox(); +} + + +/** + * Triangulates the face in three new faces by splitting two edges. + * + * * + * / \ + * / \ + * x x + * / \ + * / \ + * *-----------* + * + * @param mesh mesh that contains the faces, edges and vertices + * @param faces set of faces that contains face and will contains new faces + * @param face input face to be triangulate + * @param v1 vertex index that intersects the first edge + * @param v1 vertex index that intersects the second edge + * @param e1 first relative edge index used to triangulate the face + * @param e2 second relative edge index used to triangulate the face + */ +void BOP_triangulateE(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, + BOP_Index v1, BOP_Index v2, unsigned int e1, unsigned int e2) +{ + // Sort the edges to reduce the cases + if (e1 > e2) { + unsigned int aux = e1; + e1 = e2; + e2 = aux; + aux = v1; + v1 = v2; + v2 = aux; + } + // e1 < e2! + BOP_Face *face1; + BOP_Face *faces23[2]; + if (e1 == 1 && e2 == 2) { + // the vertex is 2 + face1 = new BOP_Face3(face->getVertex(1), v2, v1, face->getPlane(), + face->getOriginalFace()); + BOP_splitQuad(mesh, face->getPlane(), face->getVertex(2), face->getVertex(0), v1, v2, + faces23, face->getOriginalFace()); + } + else if (e1 == 1 && e2 == 3) { + // the vertex is 1 + face1 = new BOP_Face3(face->getVertex(0), v1, v2, face->getPlane(), + face->getOriginalFace()); + BOP_splitQuad(mesh, face->getPlane(), face->getVertex(1), face->getVertex(2), v2, v1, + faces23, face->getOriginalFace()); + } + else if (e1 == 2 && e2 == 3) { + // the vertex is 3 + face1 = new BOP_Face3(face->getVertex(2), v2, v1, face->getPlane(), + face->getOriginalFace()); + BOP_splitQuad(mesh, face->getPlane(), face->getVertex(0), face->getVertex(1), v1, v2, + faces23, face->getOriginalFace()); + } + else { + return; + } + + BOP_addFace(mesh, faces, face1, face->getTAG()); + BOP_addFace(mesh, faces, faces23[0], face->getTAG()); + BOP_addFace(mesh, faces, faces23[1], face->getTAG()); + face1->setSplit(face->getSplit()); + faces23[0]->setSplit(face->getSplit()); + faces23[1]->setSplit(face->getSplit()); + face->setTAG(BROKEN); + face->freeBBox(); +} + +/** + * Triangulates the face in four new faces by one edge and one inner point. + * + * * + * / \ + * / \ + * x x \ + * / \ + * / \ + * *-----------* + * + * @param mesh mesh that contains the faces, edges and vertices + * @param faces set of faces that contains face and will contains new faces + * @param face input face to be triangulate + * @param v1 vertex index that lays inside face + * @param v2 vertex index that intersects the edge + * @param e relative edge index used to triangulate the face + */ +void BOP_triangulateF(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, + BOP_Index v1, BOP_Index v2, unsigned int e) +{ + BOP_Face *faces12[2]; + BOP_Face *faces34[2]; + if (e == 1) { + BOP_splitQuad(mesh, face->getPlane(), face->getVertex(2), face->getVertex(0), v2, v1, + faces12, face->getOriginalFace()); + BOP_splitQuad(mesh, face->getPlane(), face->getVertex(1), face->getVertex(2), v1, v2, + faces34, face->getOriginalFace()); + } + else if (e == 2) { + BOP_splitQuad(mesh, face->getPlane(), face->getVertex(0), face->getVertex(1), v2, v1, + faces12, face->getOriginalFace()); + BOP_splitQuad(mesh, face->getPlane(), face->getVertex(2), face->getVertex(0), v1, v2, + faces34, face->getOriginalFace()); + } + else if (e==3) { + BOP_splitQuad(mesh, face->getPlane(), face->getVertex(1), face->getVertex(2), v2, v1, + faces12, face->getOriginalFace()); + BOP_splitQuad(mesh, face->getPlane(), face->getVertex(0), face->getVertex(1), v1, v2, + faces34, face->getOriginalFace()); + } + else { + return; + } + + BOP_addFace(mesh, faces, faces12[0], face->getTAG()); + BOP_addFace(mesh, faces, faces12[1], face->getTAG()); + BOP_addFace(mesh, faces, faces34[0], face->getTAG()); + BOP_addFace(mesh, faces, faces34[1], face->getTAG()); + faces12[0]->setSplit(face->getSplit()); + faces12[1]->setSplit(face->getSplit()); + faces34[0]->setSplit(face->getSplit()); + faces34[1]->setSplit(face->getSplit()); + + face->setTAG(BROKEN); + face->freeBBox(); +} + +/** + * Adds the new face into the faces set and the mesh and sets it a new tag. + * @param mesh mesh that contains the faces, edges and vertices + * @param faces set of faces that contains oldFace + * @param face input face to be added + * @param tag tag of the new face + */ +void BOP_addFace(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, BOP_TAG tag) +{ + BOP_Index av1 = face->getVertex(0); + BOP_Index av2 = face->getVertex(1); + BOP_Index av3 = face->getVertex(2); + + /* + * Before adding a new face to the face list, be sure it's not + * already there. Duplicate faces have been found to cause at + * least two instances of infinite loops. Also, some faces are + * created which have the same vertex twice. Don't add these either. + * + * When someone has more time to look into this issue, it's possible + * this code may be removed again. + */ + if( av1==av2 || av2==av3 || av3==av1 ) return; + + for(unsigned int idxFace=0;idxFacesize();idxFace++) { + BOP_Face *faceA = (*faces)[idxFace]; + BOP_Index bv1 = faceA->getVertex(0); + BOP_Index bv2 = faceA->getVertex(1); + BOP_Index bv3 = faceA->getVertex(2); + + if( ( av1==bv1 && av2==bv2 && av3==bv3 ) || + ( av1==bv1 && av2==bv3 && av3==bv2 ) || + ( av1==bv2 && av2==bv1 && av3==bv3 ) || + ( av1==bv2 && av2==bv3 && av3==bv1 ) || + ( av1==bv3 && av2==bv2 && av3==bv1 ) || + ( av1==bv3 && av2==bv1 && av3==bv3 ) ) + return; + } + + face->setTAG(tag); + faces->push_back(face); + mesh->addFace(face); +} + +/** + * Computes the best quad triangulation. + * @param mesh mesh that contains the faces, edges and vertices + * @param plane plane used to create the news faces + * @param v1 first vertex index + * @param v2 second vertex index + * @param v3 third vertex index + * @param v4 fourth vertex index + * @param triangles array of faces where the new two faces will be saved + * @param original face index to the new faces + */ +void BOP_splitQuad(BOP_Mesh* mesh, MT_Plane3 plane, BOP_Index v1, BOP_Index v2, + BOP_Index v3, BOP_Index v4, BOP_Face* triangles[], BOP_Index original) +{ + MT_Point3 p1 = mesh->getVertex(v1)->getPoint(); + MT_Point3 p2 = mesh->getVertex(v2)->getPoint(); + MT_Point3 p3 = mesh->getVertex(v3)->getPoint(); + MT_Point3 p4 = mesh->getVertex(v4)->getPoint(); + + int res = BOP_concave(p1,p2,p3,p4); + + if (res==0) { + MT_Plane3 plane1(p1, p2, p3); + MT_Plane3 plane2(p1, p3, p4); + + if (BOP_isInsideCircle(mesh, v1, v2, v4, v3) && + BOP_orientation(plane1, plane) && + BOP_orientation(plane2, plane)) { + triangles[0] = new BOP_Face3(v1, v2, v3, plane, original); + triangles[1] = new BOP_Face3(v1, v3, v4, plane, original); + } + else { + triangles[0] = new BOP_Face3(v1, v2, v4, plane, original); + triangles[1] = new BOP_Face3(v2, v3, v4, plane, original); + } + } + else if (res==-1) { + triangles[0] = new BOP_Face3(v1, v2, v4, plane, original); + triangles[1] = new BOP_Face3(v2, v3, v4, plane, original); + } + else { + triangles[0] = new BOP_Face3(v1, v2, v3, plane, original); + triangles[1] = new BOP_Face3(v1, v3, v4, plane, original); + } +} + +/** + * Returns the vertex (v3 or v4) that splits the quad (v1,v2,v3,v4) in the best pair of triangles. + * @param mesh mesh that contains the faces, edges and vertices + * @param v1 first vertex index + * @param v2 second vertex index + * @param v3 third vertex index + * @param v4 fourth vertex index + * @return v3 if the best split triangles are (v1,v2,v3) and (v1,v3,v4), v4 otherwise + */ +BOP_Index BOP_getTriangleVertex(BOP_Mesh* mesh, BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4) +{ + if (BOP_isInsideCircle(mesh, v1, v2, v4, v3)) { + return v3; + } + return v4; +} + +/** + * Returns which of vertex v1 or v2 is nearest to u. + * @param mesh mesh that contains the faces, edges and vertices + * @param u reference vertex index + * @param v1 first vertex index + * @param v2 second vertex index + * @return the nearest vertex index + */ +BOP_Index BOP_getNearestVertex(BOP_Mesh* mesh, BOP_Index u, BOP_Index v1, BOP_Index v2) +{ + MT_Point3 q = mesh->getVertex(u)->getPoint(); + MT_Point3 p1 = mesh->getVertex(v1)->getPoint(); + MT_Point3 p2 = mesh->getVertex(v2)->getPoint(); + if (BOP_comp(q.distance(p1), q.distance(p2)) > 0) return v2; + else return v1; +} + +/** + * Computes if vertexs v4 and v5 are not inside the circle defined by v1,v2,v3 (seems to be a nice triangle) + * @param mesh mesh that contains the faces, edges and vertices + * @param v1 first vertex index + * @param v2 second vertex index + * @param v3 third vertex index + * @param v4 fourth vertex index + * @param v5 five vertex index + * @return if v1,v2,v3 defines a nice triangle against v4,v5 + */ +bool BOP_isInsideCircle(BOP_Mesh* mesh, BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4, BOP_Index v5) +{ + return BOP_isInsideCircle(mesh->getVertex(v1)->getPoint(), + mesh->getVertex(v2)->getPoint(), + mesh->getVertex(v3)->getPoint(), + mesh->getVertex(v4)->getPoint(), + mesh->getVertex(v5)->getPoint()); +} + +/** + * Computes if vertex w is not inside the circle defined by v1,v2,v3 (seems to be a nice triangle) + * @param mesh mesh that contains the faces, edges and vertices + * @param v1 first vertex index + * @param v2 second vertex index + * @param v3 third vertex index + * @param w fourth vertex index + * @return if v1,v2,v3 defines a nice triangle against w + */ +bool BOP_isInsideCircle(BOP_Mesh* mesh, BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index w) +{ + return BOP_isInsideCircle(mesh->getVertex(v1)->getPoint(), + mesh->getVertex(v2)->getPoint(), + mesh->getVertex(v3)->getPoint(), + mesh->getVertex(w)->getPoint()); +} diff --git a/intern/boolop/intern/BOP_Triangulator.h b/intern/boolop/intern/BOP_Triangulator.h new file mode 100644 index 00000000000..12223e1ea1f --- /dev/null +++ b/intern/boolop/intern/BOP_Triangulator.h @@ -0,0 +1,44 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_TRIANGULATOR_H +#define BOP_TRIANGULATOR_H + +#include "BOP_MathUtils.h" +#include "BOP_Mesh.h" + +void BOP_triangulateA(BOP_Mesh *mesh, BOP_Faces *faces, BOP_Face * face, BOP_Index v, unsigned int e); +void BOP_triangulateB(BOP_Mesh * mesh, BOP_Faces *faces, BOP_Face * face, BOP_Index v); +void BOP_triangulateC(BOP_Mesh * mesh, BOP_Faces *faces, BOP_Face * face, BOP_Index v1, BOP_Index v2); +void BOP_triangulateD(BOP_Mesh * mesh, BOP_Faces *faces, BOP_Face * face, BOP_Index v1, BOP_Index v2, unsigned int e); +void BOP_triangulateE(BOP_Mesh *mesh, BOP_Faces *faces, BOP_Face * face, BOP_Index v1, BOP_Index v2, unsigned int e1, unsigned int e2); +void BOP_triangulateF(BOP_Mesh *mesh, BOP_Faces *faces, BOP_Face * face, BOP_Index v1, BOP_Index v2, unsigned int e); + +#endif diff --git a/intern/boolop/intern/BOP_Vertex.cpp b/intern/boolop/intern/BOP_Vertex.cpp new file mode 100644 index 00000000000..c039df5775d --- /dev/null +++ b/intern/boolop/intern/BOP_Vertex.cpp @@ -0,0 +1,94 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_Vertex.h" + +/** + * Constructs a new vertex with the specified coordinates. + * @param x X-axis coordinate + * @param y Y-axis coordinate + * @param z Z-axis coordinate + */ +BOP_Vertex::BOP_Vertex(double x, double y, double z) +{ + m_point.setValue(x,y,z); + m_tag = UNCLASSIFIED; +} + +/** + * Constructs a new vertex with the specified point. + * @param p point XYZ + */ +BOP_Vertex::BOP_Vertex(MT_Point3 p) +{ + m_point = p; + m_tag = UNCLASSIFIED; +} + +/** + * Adds a new edge index to this vertex. + * @param i edge index + */ +void BOP_Vertex::addEdge(BOP_Index i) +{ + if (!containsEdge(i)) + m_edges.push_back(i); +} + +/** + * Removes an edge index from this vertex. + * @param i edge index + */ +void BOP_Vertex::removeEdge(BOP_Index i) +{ + for(BOP_IT_Indexs it = m_edges.begin();it!=m_edges.end();it++) { + if ((*it)==i) { + m_edges.erase(it); + return; + } + } +} + +/** + * Returns if this vertex contains the specified edge index. + * @param i edge index + * @return true if this vertex contains the specified edge index, false otherwise + */ +bool BOP_Vertex::containsEdge(BOP_Index i) +{ + int pos=0; + for(BOP_IT_Indexs it = m_edges.begin();it!=m_edges.end();pos++,it++) { + if ((*it)==i){ + return true; + } + } + + return false; +} diff --git a/intern/boolop/intern/BOP_Vertex.h b/intern/boolop/intern/BOP_Vertex.h new file mode 100644 index 00000000000..a781407af34 --- /dev/null +++ b/intern/boolop/intern/BOP_Vertex.h @@ -0,0 +1,60 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_VERTEX_H +#define BOP_VERTEX_H + +#include "BOP_Tag.h" +#include "BOP_Indexs.h" +#include "MT_Point3.h" + +class BOP_Vertex +{ +private: + MT_Point3 m_point; + BOP_Indexs m_edges; + BOP_TAG m_tag; + + bool containsEdge(BOP_Index i); + +public: + BOP_Vertex(double x, double y, double z); + BOP_Vertex(MT_Point3 d); + void addEdge(BOP_Index i); + void removeEdge(BOP_Index i); + inline BOP_Index getEdge(unsigned int i) { return m_edges[i];}; + inline unsigned int getNumEdges() { return m_edges.size();}; + inline BOP_Indexs &getEdges() { return m_edges;}; + inline MT_Point3 getPoint() const { return m_point;}; + inline BOP_TAG getTAG() { return m_tag;}; + inline void setTAG(BOP_TAG t) { m_tag = t;}; +}; + +#endif diff --git a/intern/boolop/intern/Makefile b/intern/boolop/intern/Makefile new file mode 100644 index 00000000000..0838f44ca8a --- /dev/null +++ b/intern/boolop/intern/Makefile @@ -0,0 +1,51 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# string intern Makefile +# + +LIBNAME = boolop +DIR = $(OCGDIR)/intern/$(LIBNAME) +DIRS = common + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I../extern +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I$(NAN_MEMUTIL)/include +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include +CPPFLAGS += -I$(NAN_CONTAINER)/include +CPPFLAGS += -I../../../source/blender/makesdna +CPPFLAGS += -I../../../source/blender/blenlib +CPPFLAGS += -Icommon + + diff --git a/intern/boolop/make/msvc_6_0/boolop.dsp b/intern/boolop/make/msvc_6_0/boolop.dsp new file mode 100644 index 00000000000..f8a072b4531 --- /dev/null +++ b/intern/boolop/make/msvc_6_0/boolop.dsp @@ -0,0 +1,222 @@ +# Microsoft Developer Studio Project File - Name="boolop" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=boolop - 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 "boolop.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 "boolop.mak" CFG="boolop - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "boolop - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "boolop - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "boolop - 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 "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\source\blender\makesdna" /I "..\..\..\..\source\blender\makesdna\\" /I "..\..\..\..\..\lib\windows\moto\include\\" /I "..\..\..\..\..\lib\windows\container\include\\" /I "..\..\..\..\..\lib\windows\memutil\include\\" /I "../../extern" /I "..\..\..\..\..\lib\windows\guardedalloc\include\\" /I "..\..\..\..\source\blender\blenlib\\" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO copy to lib folder XCOPY /Y .\release\*.lib ..\..\..\..\..\lib\windows\boolop\lib\*.lib +# End Special Build Tool + +!ELSEIF "$(CFG)" == "boolop - 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 "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\..\source\blender\makesdna\\" /I "..\..\..\..\..\lib\windows\moto\include\\" /I "..\..\..\..\..\lib\windows\container\include\\" /I "..\..\..\..\..\lib\windows\memutil\include\\" /I "../../extern" /I "..\..\..\..\..\lib\windows\guardedalloc\include\\" /I "..\..\..\..\source\blender\blenlib\\" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "boolop - Win32 Release" +# Name "boolop - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\intern\BOP_BBox.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_BSPNode.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_BSPTree.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Edge.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Face.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Face2Face.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Interface.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_MathUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Merge.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Mesh.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Segment.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Splitter.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Tag.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Triangulator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Vertex.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\intern\BOP_BBox.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_BSPNode.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_BSPTree.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Chrono.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Edge.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Face.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Face2Face.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Indexs.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_MathUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Merge.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Mesh.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Segment.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Splitter.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Tag.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Triangulator.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Vertex.h +# End Source File +# End Group +# End Target +# End Project diff --git a/intern/boolop/make/msvc_7_0/boolop.vcproj b/intern/boolop/make/msvc_7_0/boolop.vcproj new file mode 100644 index 00000000000..7ae417e42d5 --- /dev/null +++ b/intern/boolop/make/msvc_7_0/boolop.vcproj @@ -0,0 +1,363 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/bsp/CMakeLists.txt b/intern/bsp/CMakeLists.txt new file mode 100644 index 00000000000..b6fbb8e4812 --- /dev/null +++ b/intern/bsp/CMakeLists.txt @@ -0,0 +1,35 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC intern ../container ../moto/include ../memutil) + +FILE(GLOB SRC intern/*.cpp) + +BLENDERLIB(blender_BSP "${SRC}" "${INC}") +#, libtype='core', priority=15 ) diff --git a/intern/bsp/Makefile b/intern/bsp/Makefile new file mode 100644 index 00000000000..818e4d69606 --- /dev/null +++ b/intern/bsp/Makefile @@ -0,0 +1,59 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# bsp main makefile. +# + +include nan_definitions.mk + +LIBNAME = bsp +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +# not yet TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_BSP) ] || mkdir $(NAN_BSP) + @[ -d $(NAN_BSP)/include ] || mkdir $(NAN_BSP)/include + @[ -d $(NAN_BSP)/lib ] || mkdir $(NAN_BSP)/lib + @[ -d $(NAN_BSP)/lib/debug ] || mkdir $(NAN_BSP)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libbsp.a $(NAN_BSP)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libbsp.a $(NAN_BSP)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_BSP)/lib/libbsp.a + ranlib $(NAN_BSP)/lib/debug/libbsp.a +endif + @../tools/cpifdiff.sh extern/*.h $(NAN_BSP)/include/ + + + + diff --git a/intern/bsp/SConscript b/intern/bsp/SConscript new file mode 100644 index 00000000000..e363fd1d4c3 --- /dev/null +++ b/intern/bsp/SConscript @@ -0,0 +1,12 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.cpp') + +incs = 'intern ../container ../moto/include ../memutil' + +if (env['OURPLATFORM'] == 'win32-mingw'): + env.BlenderLib ('blender_BSP', sources, Split(incs), [], libtype=['common','intern'], priority=[26,26] ) +else: + env.BlenderLib ('blender_BSP', sources, Split(incs), [], libtype='core', priority=15 ) + diff --git a/intern/bsp/extern/CSG_BooleanOps.h b/intern/bsp/extern/CSG_BooleanOps.h new file mode 100644 index 00000000000..1e862568cda --- /dev/null +++ b/intern/bsp/extern/CSG_BooleanOps.h @@ -0,0 +1,360 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef CSG_BOOLEANOPS_H +#define CSG_BOOLEANOPS_H + + +/** + * @section Interface structures for CSG module. + * This interface falls into 2 categories. + * The first section deals with an abstract mesh description + * between blender and this module. The second deals with + * the module functions. + * The CSG module needs to know about the following entities: + */ + +/** + * CSG_IFace -- an interface polygon structure. + * vertex_index is a fixed size array of 4 elements containing indices into + * an abstract vertex container. 3 or 4 of these elements may be used to + * describe either quads or triangles. + * vertex_number is the number of vertices in this face - either 3 or 4. + * vertex_colors is an array of {r,g,b} triplets one for each vertex index. + * tex_coords is an array of {u,v} triplets one for each vertex index. + * user_data is a pointer to arbitary data of fixed width , + * this data is copied around with the face, and duplicated if a face is + * split. Contains things like material index. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + int vertex_index[4]; + int vertex_number; + int orig_face; +} CSG_IFace; + +/** + * CSG_IVertex -- an interface vertex structure. + * position is the location of the vertex in 3d space. + */ + +typedef struct { + float position[3]; +} CSG_IVertex; + +/** + * The actual useful data contained in a group of faces is + * described by the following struct + */ + +/** + * @section Iterator abstraction. + * + * The CSG module asks blender to fill in an instance of the above + * structure, and requests blender to move up and down (iterate) through + * it's face and vertex containers. + * + * An iterator supports the following functions. + * int IsDone(iterator *it) -- returns true if the iterator has reached + * the end of it's container. + * + * void Fill(iterator *it,DataType *data) -- Return the contents of the + * container at the current iterator position. + * + * void Step(iterator *it) -- increment the iterator to the next position + * in the container. + * + * The iterator is used in the following manner. + * + * MyIterator * iterator = ... + * DataType data; + * + * while (!IsDone(iterator)) { + * Fill(iterator,&data); + * //process information pointed to by data + * ... + * Step(iterator); + * } + * + * The CSG module does not want to know about the implementation of these + * functions so we use the c function ptr mechanism to hide them. Our + * iterator descriptor now looks like this. + */ + +typedef void* CSG_IteratorPtr; + +typedef int (*CSG_FaceItDoneFunc)(CSG_IteratorPtr it); +typedef void (*CSG_FaceItFillFunc)(CSG_IteratorPtr it,CSG_IFace *face); +typedef void (*CSG_FaceItStepFunc)(CSG_IteratorPtr it); +typedef void (*CSG_FaceItResetFunc)(CSG_IteratorPtr it); + +typedef struct CSG_FaceIteratorDescriptor { + CSG_IteratorPtr it; + CSG_FaceItDoneFunc Done; + CSG_FaceItFillFunc Fill; + CSG_FaceItStepFunc Step; + CSG_FaceItResetFunc Reset; + unsigned int num_elements; +} CSG_FaceIteratorDescriptor; + +/** + * Similarly to walk through the vertex arrays we have. + */ +typedef int (*CSG_VertexItDoneFunc)(CSG_IteratorPtr it); +typedef void (*CSG_VertexItFillFunc)(CSG_IteratorPtr it,CSG_IVertex *face); +typedef void (*CSG_VertexItStepFunc)(CSG_IteratorPtr it); +typedef void (*CSG_VertexItResetFunc)(CSG_IteratorPtr it); + +typedef struct CSG_VertexIteratorDescriptor { + CSG_IteratorPtr it; + CSG_VertexItDoneFunc Done; + CSG_VertexItFillFunc Fill; + CSG_VertexItStepFunc Step; + CSG_VertexItResetFunc Reset; + unsigned int num_elements; +} CSG_VertexIteratorDescriptor; + +/** + * The actual iterator structures are not exposed to the CSG module, they + * will contain datatypes specific to blender. + */ + +/** + * @section CSG Module interface functions. + * + * The functions below are to be used in the following way: + * + * // Create a boolean operation handle + * CSG_BooleanOperation *operation = CSG_NewBooleanFunction(); + * if (operation == NULL) { + * // deal with low memory exception + * } + * + * // Report to the user if they will loose any data! + * ... + * + * // Get some mesh iterators for your mesh data structures + * CSG_FaceIteratorDescriptor obA_faces = ... + * CSG_VertexIteratorDescriptor obA_verts = ... + * + * // same for object B + * CSG_FaceIteratorDescriptor obB_faces = ... + * CSG_VertexIteratorDescriptor obB_verts = ... + * + * // perform the operation...! + * + * int success = CSG_PerformBooleanOperation( + * operation, + * e_csg_intersection, + * obA_faces, + * obA_vertices, + * obB_faces, + * obB_vertices + * ); + * + * // if the operation failes report miserable faiulre to user + * // and clear up data structures. + * if (!success) { + * ... + * CSG_FreeBooleanOperation(operation); + * return; + * } + * + * // read the new mesh vertices back from the module + * // and assign to your own mesh structure. + * + * // First we need to create a CSG_IVertex so the module can fill it in. + * CSG_IVertex vertex; + * CSG_VertexIteratorDescriptor * verts_it = CSG_OutputVertexDescriptor(operation); + * + * // initialize your vertex container with the number of verts (verts_it->num_elements) + * + * while (!verts_it->Done(verts_it->it)) { + * verts_it->Fill(verts_it->it,&vertex); + * + * // create a new vertex of your own type and add it + * // to your mesh structure. + * verts_it->Step(verts_it->it); + * } + * // Free the vertex iterator + * CSG_FreeVertexDescriptor(verts_it); + * + * // similarly for faces. + * CSG_IFace face; + * + * // you may need to reserve some memory in face->user_data here. + * + * // initialize your face container with the number of faces (faces_it->num_elements) + * + * CSG_FaceIteratorDescriptor * faces_it = CSG_OutputFaceDescriptor(operation); + * + * while (!faces_it->Done(faces_it->it)) { + * faces_it->Fill(faces_it->it,&face); + * + * // create a new face of your own type and add it + * // to your mesh structure. + * faces_it->Step(&faces_it->it); + * } + * + * // Free the face iterator + * CSG_FreeVertexDescriptor(faces_it); + * + * // that's it free the operation. + * + * CSG_FreeBooleanOperation(operation); + * return; + * + */ + +/** + * Description of boolean operation type. + */ + +typedef enum { + e_csg_union, + e_csg_intersection, + e_csg_difference, + e_csg_classify +} CSG_OperationType; + +/** + * 'Handle' into the CSG module that identifies a particular CSG operation. + * the pointer CSG_info containers module specific data, and should not + * be touched in anyway outside of the module. + */ + +typedef struct { + void *CSG_info; +} CSG_BooleanOperation; + +/** + * Return a ptr to a CSG_BooleanOperation object allocated + * on the heap. The CSG module owns the memory associated with + * the returned ptr, use CSG_FreeBooleanOperation() to free this memory. + */ + CSG_BooleanOperation * +CSG_NewBooleanFunction( + void +); + +/** + * Attempt to perform a boolean operation between the 2 objects of the + * desired type. This may fail due to an internal error or lack of memory. + * In this case 0 is returned, otehrwise 1 is returned indicating success. + * @param operation is a 'handle' into the CSG_Module created by CSG_NewBooleanFunction() + * @param op_type is the operation to perform. + * @param obAFaces is an iterator over the faces of objectA, + * @param obAVertices is an iterator over the vertices of objectA + * @param obAFaces is an iterator over the faces of objectB, + * @param obAVertices is an iterator over the vertices of objectB + * @param interp_func the face_vertex data interpolation function.(see above) + * + * All iterators must be valid and pointing to the first element in their + * respective containers. + */ + int +CSG_PerformBooleanOperation( + CSG_BooleanOperation * operation, + CSG_OperationType op_type, + CSG_FaceIteratorDescriptor obAFaces, + CSG_VertexIteratorDescriptor obAVertices, + CSG_FaceIteratorDescriptor obBFaces, + CSG_VertexIteratorDescriptor obBVertices +); + +/** + * If the a boolean operation was successful, you may access the results + * through the following functions. + * + * CSG_OuputFaceDescriptor() returns a ptr to a CSG_FaceIteratorDesciptor + * allocated on the heap and owned by the CSG module. The iterator is + * positioned at the start of the internal face container. + * CSG_OutputVertexDescriptor() returns a ptr to a CSG_VertexIteratorDescriptor + * allocated on the heap and owned by the CSG module. The iterator is + * positioned at the start of the internal vertex container. + * There is no function to rewind an iterator but you may obtain more + * than one + * iterator at a time. Please use the function CSG_FreeFaceIterator() + * and CSG_FreeVertexIterator to free internal memory allocated for these + * iterators. + * + * If the last operation was not successful, these functions return NULL. + */ + int +CSG_OutputFaceDescriptor( + CSG_BooleanOperation * operation, + CSG_FaceIteratorDescriptor * output +); + + int +CSG_OutputVertexDescriptor( + CSG_BooleanOperation * operation, + CSG_VertexIteratorDescriptor *output +); + +/** + * Clean up functions. + * Free internal memory associated with CSG interface structures. You must + * call these functions on any structures created by the module, even if + * subsequent operations did not succeed. + */ + void +CSG_FreeVertexDescriptor( + CSG_VertexIteratorDescriptor * v_descriptor +); + + void +CSG_FreeFaceDescriptor( + CSG_FaceIteratorDescriptor * f_descriptor +); + +/** + * Free the memory associated with a boolean operation. + * NOTE any iterator descriptor describing the output will become + * invalid after this call and should be freed immediately. + */ + void +CSG_FreeBooleanOperation( + CSG_BooleanOperation *operation +); + +#ifdef __cplusplus +} +#endif + + + +#endif + diff --git a/intern/bsp/intern/BSP_CSGException.h b/intern/bsp/intern/BSP_CSGException.h new file mode 100644 index 00000000000..c2d79630be2 --- /dev/null +++ b/intern/bsp/intern/BSP_CSGException.h @@ -0,0 +1,58 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_CSGException_h +#define NAN_INCLUDED_CSGException_h + +// stick in more error types as you think of them + +enum BSP_ExceptionType{ + e_split_error, + e_mesh_error, + e_mesh_input_error, + e_param_error, + e_tree_build_error +}; + + +class BSP_CSGException { +public : + BSP_ExceptionType m_e_type; + + BSP_CSGException ( + BSP_ExceptionType type + ) : m_e_type (type) + { + } +}; + +#endif + diff --git a/intern/bsp/intern/BSP_CSGMesh.cpp b/intern/bsp/intern/BSP_CSGMesh.cpp new file mode 100644 index 00000000000..5da39c8d551 --- /dev/null +++ b/intern/bsp/intern/BSP_CSGMesh.cpp @@ -0,0 +1,655 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + + +#include "BSP_CSGMesh.h" +#include "MT_assert.h" +#include "CTR_TaggedSetOps.h" +#include "MT_Plane3.h" +#include "BSP_CSGException.h" + +// for vector reverse +#include +#include +using namespace std; + +BSP_CSGMesh:: +BSP_CSGMesh( +) : + MEM_RefCountable() +{ + m_verts = NULL; + m_faces = NULL; + m_edges = NULL; +} + + BSP_CSGMesh * +BSP_CSGMesh:: +New( +){ + return new BSP_CSGMesh(); +} + + BSP_CSGMesh * +BSP_CSGMesh:: +NewCopy( +) const { + + BSP_CSGMesh *mesh = New(); + if (mesh == NULL) return NULL; + + mesh->m_bbox_max = m_bbox_max; + mesh->m_bbox_min = m_bbox_min; + + if (m_edges != NULL) { + mesh->m_edges = new vector(*m_edges); + if (mesh->m_edges == NULL) { + delete mesh; + return NULL; + } + } + if (m_verts != NULL) { + mesh->m_verts = new vector(*m_verts); + if (mesh->m_verts == NULL) { + if (m_edges != NULL) free(mesh->m_edges); + delete mesh; + return NULL; + } + } + if (m_faces != NULL) { + mesh->m_faces = new vector(*m_faces); + if (mesh->m_faces == NULL) { + delete mesh; + return NULL; + } + } + + return mesh; +} + + void +BSP_CSGMesh:: +Invert( +){ + + vector & faces = FaceSet(); + + vector::const_iterator faces_end = faces.end(); + vector::iterator faces_it = faces.begin(); + + for (; faces_it != faces_end; ++faces_it) { + faces_it->Invert(); + } +} + + bool +BSP_CSGMesh:: +SetVertices( + vector *verts +){ + if (verts == NULL) return false; + + // create polygon and edge arrays and reserve some space. + m_faces = new vector; + if (!m_faces) return false; + + m_faces->reserve(verts->size()/2); + + // previous verts get deleted here. + m_verts = verts; + return true; +} + + void +BSP_CSGMesh:: +AddPolygon( + const int * verts, + int num_verts +){ + MT_assert(verts != NULL); + MT_assert(num_verts >=3); + + if (verts == NULL || num_verts <3) return; + + // make a polyscone from these vertex indices. + + const BSP_FaceInd fi = m_faces->size(); + m_faces->push_back(BSP_MFace()); + BSP_MFace & face = m_faces->back(); + + insert_iterator > insert_point(face.m_verts,face.m_verts.end()); + copy (verts,verts + num_verts,insert_point); + + // compute and store the plane equation for this face. + + MT_Plane3 face_plane = FacePlane(fi); + face.m_plane = face_plane; +}; + +// assumes that the face already has a plane equation + void +BSP_CSGMesh:: +AddPolygon( + const BSP_MFace &face +){ + m_faces->push_back(face); +}; + + + bool +BSP_CSGMesh:: +BuildEdges( +){ + + if (m_faces == NULL) return false; + + if (m_edges != NULL) { + DestroyEdges(); + } + + m_edges = new vector; + + if (m_edges == NULL) { + return false; + } + + + //iterate through the face set and add edges for all polygon + //edges + + vector::const_iterator f_it_end = FaceSet().end(); + vector::iterator f_it_begin = FaceSet().begin(); + vector::iterator f_it = FaceSet().begin(); + + vector dummy; + + for (;f_it != f_it_end; ++f_it) { + + BSP_MFace & face = *f_it; + + int vertex_num = face.m_verts.size(); + BSP_VertexInd prev_vi(face.m_verts[vertex_num-1]); + + for (int vert = 0; vert < vertex_num; ++vert) { + + BSP_FaceInd fi(f_it - f_it_begin); + InsertEdge(prev_vi,face.m_verts[vert],fi,dummy); + prev_vi = face.m_verts[vert]; + } + + } + dummy.clear(); + return true; +} + + void +BSP_CSGMesh:: +DestroyEdges( +){ + if ( m_edges != NULL ) { + delete m_edges; + m_edges = NULL; + } + + // Run through the vertices + // and clear their edge arrays. + + if (m_verts){ + + vector::const_iterator vertex_end = VertexSet().end(); + vector::iterator vertex_it = VertexSet().begin(); + + for (; vertex_it != vertex_end; ++vertex_it) { + vertex_it->m_edges.clear(); + } + } +} + + + BSP_EdgeInd +BSP_CSGMesh:: +FindEdge( + const BSP_VertexInd & v1, + const BSP_VertexInd & v2 +) const { + + vector &verts = VertexSet(); + vector &edges = EdgeSet(); + + BSP_MEdge e; + e.m_verts[0] = v1; + e.m_verts[1] = v2; + + vector &v1_edges = verts[v1].m_edges; + vector::const_iterator v1_end = v1_edges.end(); + vector::const_iterator v1_begin = v1_edges.begin(); + + for (; v1_begin != v1_end; ++v1_begin) { + if (edges[*v1_begin] == e) return *v1_begin; + } + + return BSP_EdgeInd::Empty(); +} + + void +BSP_CSGMesh:: +InsertEdge( + const BSP_VertexInd & v1, + const BSP_VertexInd & v2, + const BSP_FaceInd & f, + vector &new_edges +){ + + MT_assert(!v1.IsEmpty()); + MT_assert(!v2.IsEmpty()); + MT_assert(!f.IsEmpty()); + + if (v1.IsEmpty() || v2.IsEmpty() || f.IsEmpty()) { + BSP_CSGException e(e_mesh_error); + throw (e); + } + + vector &verts = VertexSet(); + vector &edges = EdgeSet(); + + BSP_EdgeInd e; + + e = FindEdge(v1,v2); + if (e.IsEmpty()) { + // This edge does not exist -- make a new one + + BSP_MEdge temp_e; + temp_e.m_verts[0] = v1; + temp_e.m_verts[1] = v2; + + e = m_edges->size(); + // set the face index from the edge back to this polygon. + temp_e.m_faces.push_back(f); + + m_edges->push_back(temp_e); + + // add the edge index to it's vertices + verts[v1].AddEdge(e); + verts[v2].AddEdge(e); + + new_edges.push_back(e); + + } else { + + // edge already exists + // insure that there is no polygon already + // attached to the other side of this edge + // swap the empty face pointer in edge with f + + BSP_MEdge &edge = edges[e]; + + // set the face index from the edge back to this polygon. + edge.m_faces.push_back(f); + } +} + + +// geometry access +////////////////// + + vector & +BSP_CSGMesh:: +VertexSet( +) const { + return *m_verts; +} + + vector & +BSP_CSGMesh:: +FaceSet( +) const { + return *m_faces; +} + + vector & +BSP_CSGMesh:: +EdgeSet( +) const { + return *m_edges; +} + +BSP_CSGMesh:: +~BSP_CSGMesh( +){ + if ( m_verts != NULL ) delete m_verts; + if ( m_faces != NULL ) delete m_faces; + if ( m_edges != NULL ) delete m_edges; +} + +// local geometry queries. +///////////////////////// + +// face queries +/////////////// + + void +BSP_CSGMesh:: +FaceVertices( + const BSP_FaceInd & f, + vector &output +){ + vector & face_set = FaceSet(); + output.insert( + output.end(), + face_set[f].m_verts.begin(), + face_set[f].m_verts.end() + ); +} + + + void +BSP_CSGMesh:: +FaceEdges( + const BSP_FaceInd & fi, + vector &output +){ + // take intersection of the edges emminating from all the vertices + // of this polygon; + + vector &faces = FaceSet(); + vector &edges = EdgeSet(); + + const BSP_MFace & f = faces[fi]; + + // collect vertex edges; + + vector::const_iterator face_verts_it = f.m_verts.begin(); + vector::const_iterator face_verts_end = f.m_verts.end(); + + vector< vector > vertex_edges(f.m_verts.size()); + + int vector_slot = 0; + + for (;face_verts_it != face_verts_end; ++face_verts_it, ++vector_slot) { + VertexEdges(*face_verts_it,vertex_edges[vector_slot]); + } + + int prev = vector_slot - 1; + + // intersect pairs of edge sets + + for (int i = 0; i < vector_slot;i++) { + CTR_TaggedSetOps::IntersectPair(vertex_edges[prev],vertex_edges[i],edges,output); + prev = i; + } + + // should always have 3 or more unique edges per face. + MT_assert(output.size() >=3); + + if (output.size() < 3) { + BSP_CSGException e(e_mesh_error); + throw(e); + } +}; + +// edge queries +/////////////// + + void +BSP_CSGMesh:: +EdgeVertices( + const BSP_EdgeInd & e, + vector &output +){ + const vector &edges = EdgeSet(); + output.push_back(edges[e].m_verts[0]); + output.push_back(edges[e].m_verts[1]); +} + + void +BSP_CSGMesh:: +EdgeFaces( + const BSP_EdgeInd & e, + vector &output +){ + + vector & edge_set = EdgeSet(); + output.insert( + output.end(), + edge_set[e].m_faces.begin(), + edge_set[e].m_faces.end() + ); + +} + +// vertex queries +///////////////// + + void +BSP_CSGMesh:: +VertexEdges( + const BSP_VertexInd &v, + vector &output +){ + + vector & vertex_set = VertexSet(); + output.insert( + output.end(), + vertex_set[v].m_edges.begin(), + vertex_set[v].m_edges.end() + ); +} + + void +BSP_CSGMesh:: +VertexFaces( + const BSP_VertexInd &vi, + vector &output +) { + + vector &edges = EdgeSet(); + vector &faces = FaceSet(); + vector &verts = VertexSet(); + + const vector &v_edges = verts[vi].m_edges; + vector::const_iterator e_it = v_edges.begin(); + + for (; e_it != v_edges.end(); ++e_it) { + + BSP_MEdge &e = edges[*e_it]; + + // iterate through the faces of this edge - push unselected + // edges to ouput and then select the edge + + vector::const_iterator e_faces_end = e.m_faces.end(); + vector::iterator e_faces_it = e.m_faces.begin(); + + for (;e_faces_it != e_faces_end; ++e_faces_it) { + + if (!faces[*e_faces_it].SelectTag()) { + output.push_back(*e_faces_it); + faces[*e_faces_it].SetSelectTag(true); + } + } + } + + // deselect selected faces. + vector::iterator f_it = output.begin(); + + for (; f_it != output.end(); ++f_it) { + faces[*f_it].SetSelectTag(false); + } +} + + bool +BSP_CSGMesh:: +SC_Face( + BSP_FaceInd f +){ + + + +#if 0 + { + // check area is greater than zero. + + vector & verts = VertexSet(); + + vector f_verts; + FaceVertices(f,f_verts); + + MT_assert(f_verts.size() >= 3); + + BSP_VertexInd root = f_verts[0]; + + MT_Scalar area = 0; + + for (int i=2; i < f_verts.size(); i++) { + MT_Vector3 a = verts[root].m_pos; + MT_Vector3 b = verts[f_verts[i-1]].m_pos; + MT_Vector3 c = verts[f_verts[i]].m_pos; + + MT_Vector3 l1 = b-a; + MT_Vector3 l2 = c-b; + + area += (l1.cross(l2)).length()/2; + } + + MT_assert(!MT_fuzzyZero(area)); + } +#endif + // Check coplanarity +#if 0 + MT_Plane3 plane = FacePlane(f); + + const BSP_MFace & face = FaceSet()[f]; + vector::const_iterator f_verts_it = face.m_verts.begin(); + vector::const_iterator f_verts_end = face.m_verts.end(); + + for (;f_verts_it != f_verts_end; ++f_verts_it) { + MT_Scalar dist = plane.signedDistance( + VertexSet()[*f_verts_it].m_pos + ); + + MT_assert(fabs(dist) < BSP_SPLIT_EPSILON); + } +#endif + + + // Check connectivity + + vector f_edges; + FaceEdges(f,f_edges); + + MT_assert(f_edges.size() == FaceSet()[f].m_verts.size()); + + unsigned int i; + for (i = 0; i < f_edges.size(); ++i) { + + int matches = 0; + for (unsigned int j = 0; j < EdgeSet()[f_edges[i]].m_faces.size(); j++) { + + if (EdgeSet()[f_edges[i]].m_faces[j] == f) matches++; + } + + MT_assert(matches == 1); + + } + return true; +} + + MT_Plane3 +BSP_CSGMesh:: +FacePlane( + const BSP_FaceInd & fi +) const{ + + const BSP_MFace & f0 = FaceSet()[fi]; + + // Have to be a bit careful here coz the poly may have + // a lot of parallel edges. Should walk round the polygon + // and check length of cross product. + + const MT_Vector3 & p1 = VertexSet()[f0.m_verts[0]].m_pos; + const MT_Vector3 & p2 = VertexSet()[f0.m_verts[1]].m_pos; + + int face_size = f0.m_verts.size(); + MT_Vector3 n; + + for (int i = 2 ; i & face_set = FaceSet(); + + vector::const_iterator face_it = face_set.begin(); + vector::const_iterator face_end = face_set.end(); + + int sum = 0; + + for (;face_it != face_end; face_it++) { + + // Should be careful about degenerate faces here. + sum += face_it->m_verts.size() - 2; + } + + return sum; +} + diff --git a/intern/bsp/intern/BSP_CSGMesh.h b/intern/bsp/intern/BSP_CSGMesh.h new file mode 100644 index 00000000000..47903520157 --- /dev/null +++ b/intern/bsp/intern/BSP_CSGMesh.h @@ -0,0 +1,249 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_BSP_CSGMesh_h +#define NAN_INCLUDED_BSP_CSGMesh_h + +#include "BSP_MeshPrimitives.h" +#include "MEM_SmartPtr.h" +#include "MEM_RefCountPtr.h" +#include "MEM_NonCopyable.h" +#include "../extern/CSG_BooleanOps.h" + + +class MT_Plane3; + +class BSP_CSGMesh : + public MEM_NonCopyable, + public MEM_RefCountable +{ + +public : + + static + BSP_CSGMesh * + New( + ); + + bool + SetVertices( + std::vector *verts + ); + + void + AddPolygon( + const int * verts, + int num_verts + ); + + // assumes that the face already has a plane equation + void + AddPolygon( + const BSP_MFace &face + ); + + + // Allocate and build the mesh edges. + //////////////////////////////////// + + bool + BuildEdges( + ); + + // Clean the mesh of edges. and edge pointers + // This removes the circular connectivity information + ///////////////////////////////////////////// + + void + DestroyEdges( + ); + + // return a new seperate copy of the + // mesh allocated on the heap. + + BSP_CSGMesh * + NewCopy( + ) const; + + + // Reverse the winding order of every polygon + // in the mesh and swap the planes around. + + void + Invert( + ); + + + // geometry access + ////////////////// + + std::vector & + VertexSet( + ) const ; + + std::vector & + FaceSet( + ) const ; + + std::vector & + EdgeSet( + ) const; + + ~BSP_CSGMesh( + ); + + // local geometry queries. + ///////////////////////// + + // face queries + /////////////// + + void + FaceVertices( + const BSP_FaceInd & f, + std::vector &output + ); + + void + FaceEdges( + const BSP_FaceInd & f, + std::vector &output + ); + + // edge queries + /////////////// + + void + EdgeVertices( + const BSP_EdgeInd & e, + std::vector &output + ); + + void + EdgeFaces( + const BSP_EdgeInd & e, + std::vector &output + ); + + // vertex queries + ///////////////// + + void + VertexEdges( + const BSP_VertexInd & v, + std::vector &output + ); + + void + VertexFaces( + const BSP_VertexInd & v, + std::vector &output + ); + + // Returns the edge index of the edge from v1 to v2. + // Does this by searching the edge sets of v1 - but not v2. + // If you are paranoid you should check both and make sure the + // indices are the same. If the edge doe not exist edgeInd is empty. + + BSP_EdgeInd + FindEdge( + const BSP_VertexInd &v1, + const BSP_VertexInd &v2 + ) const; + + + /** + * Sanity checkers + */ + + // make sure the edge faces have a pointer to f + + bool + SC_Face( + BSP_FaceInd f + ); + + /** + * Return the face plane equation + */ + + MT_Plane3 + FacePlane( + const BSP_FaceInd &fi + )const; + + + /** + * Recompute Face plane equations. + * essential if you have been messing with the object. + */ + + void + ComputeFacePlanes( + ); + + /** + * Count the number of trinagles in the mesh. + * This is not the same as the number of polygons. + */ + + int + CountTriangles( + ) const; + +private : + + void + InsertEdge( + const BSP_VertexInd &v1, + const BSP_VertexInd &v2, + const BSP_FaceInd &f, + std::vector &new_edges + ); + + + // Private to insure heap instantiation. + + BSP_CSGMesh( + ); + + std::vector *m_verts; + std::vector *m_faces; + std::vector *m_edges; + + MT_Vector3 m_bbox_min; + MT_Vector3 m_bbox_max; + +}; + + +#endif + diff --git a/intern/bsp/intern/BSP_CSGMesh_CFIterator.h b/intern/bsp/intern/BSP_CSGMesh_CFIterator.h new file mode 100644 index 00000000000..010f62159a5 --- /dev/null +++ b/intern/bsp/intern/BSP_CSGMesh_CFIterator.h @@ -0,0 +1,270 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BSP_CSGMesh_CFIterator_h + +#define BSP_CSGMesh_CFIterator_h + +#include "BSP_CSGMesh.h" +#include "../extern/CSG_BooleanOps.h" +/** + * This class defines 2 C style iterators over a CSG mesh, one for + * vertices and 1 for faces. They conform to the iterator interface + * defined in CSG_BooleanOps.h + */ + +struct BSP_CSGMesh_VertexIt { + BSP_CSGMesh *mesh; + BSP_MVertex * pos; +}; + + +inline + void +BSP_CSGMesh_VertexIt_Destruct( + CSG_VertexIteratorDescriptor * iterator +) { + delete ((BSP_CSGMesh_VertexIt *)(iterator->it)); + iterator->it = NULL; + iterator->Done = NULL; + iterator->Fill = NULL; + iterator->Reset = NULL; + iterator->Step = NULL; + iterator->num_elements = 0; +}; + + +inline + int +BSP_CSGMesh_VertexIt_Done( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + BSP_CSGMesh_VertexIt * vertex_it = (BSP_CSGMesh_VertexIt *)it; + + /* dereferencing iterator::end() is illegal, so we dereference 1 before it */ + /* also check that vector is not empty */ + if (vertex_it->mesh->VertexSet().size() && + vertex_it->pos <= &(*(vertex_it->mesh->VertexSet().end() -1) )) return 0; + return 1; +}; + +inline + void +BSP_CSGMesh_VertexIt_Fill( + CSG_IteratorPtr it, + CSG_IVertex *vert +) { + // assume CSG_IteratorPtr is of the correct type. + BSP_CSGMesh_VertexIt * vertex_it = (BSP_CSGMesh_VertexIt *)it; + + vertex_it->pos->m_pos.getValue(vert->position); +}; + +inline + void +BSP_CSGMesh_VertexIt_Step( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + BSP_CSGMesh_VertexIt * vertex_it = (BSP_CSGMesh_VertexIt *)it; + + ++(vertex_it->pos); +}; + +inline + void +BSP_CSGMesh_VertexIt_Reset( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + BSP_CSGMesh_VertexIt * vertex_it = (BSP_CSGMesh_VertexIt *)it; + vertex_it->pos = &vertex_it->mesh->VertexSet()[0]; +}; + +inline + void +BSP_CSGMeshVertexIt_Construct( + BSP_CSGMesh *mesh, + CSG_VertexIteratorDescriptor *output +){ + // user should have insured mesh is not equal to NULL. + + output->Done = BSP_CSGMesh_VertexIt_Done; + output->Fill = BSP_CSGMesh_VertexIt_Fill; + output->Step = BSP_CSGMesh_VertexIt_Step; + output->Reset = BSP_CSGMesh_VertexIt_Reset; + output->num_elements = mesh->VertexSet().size(); + + BSP_CSGMesh_VertexIt * v_it = new BSP_CSGMesh_VertexIt; + v_it->mesh = mesh; + if( output->num_elements > 0 ) + v_it->pos = &mesh->VertexSet()[0]; + output->it = v_it; +}; + + +/** + * Face iterator. + */ + +struct BSP_CSGMesh_FaceIt { + BSP_CSGMesh *mesh; + BSP_MFace *pos; + int face_triangle; +}; + + +inline + void +BSP_CSGMesh_FaceIt_Destruct( + CSG_FaceIteratorDescriptor *iterator +) { + delete ((BSP_CSGMesh_FaceIt *)(iterator->it)); + iterator->it = NULL; + iterator->Done = NULL; + iterator->Fill = NULL; + iterator->Reset = NULL; + iterator->Step = NULL; + iterator->num_elements = 0; +}; + + +inline + int +BSP_CSGMesh_FaceIt_Done( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + BSP_CSGMesh_FaceIt * face_it = (BSP_CSGMesh_FaceIt *)it; + + /* dereferencing iterator::end() is illegal, so we dereference 1 before it */ + /* also check that vector is not empty */ + if (face_it->mesh->FaceSet().size() && + face_it->pos <= &(*(face_it->mesh->FaceSet().end() -1))) { + if (face_it->face_triangle + 3 <= (int)face_it->pos->m_verts.size()) { + return 0; + } + } + return 1; +}; + +inline + void +BSP_CSGMesh_FaceIt_Fill( + CSG_IteratorPtr it, + CSG_IFace *face +){ + // assume CSG_IteratorPtr is of the correct type. + BSP_CSGMesh_FaceIt * face_it = (BSP_CSGMesh_FaceIt *)it; + // essentially iterating through a triangle fan here. + + if (face_it->pos->m_verts.size()>3) { + // QUAD + face->vertex_index[0] = int(face_it->pos->m_verts[0]); + face->vertex_index[1] = int(face_it->pos->m_verts[1]); + face->vertex_index[2] = int(face_it->pos->m_verts[2]); + face->vertex_index[3] = int(face_it->pos->m_verts[3]); + + face->orig_face = face_it->pos->m_orig_face; + + face->vertex_number = 4; + } + else { + // TRIANGLE + face->vertex_index[0] = int(face_it->pos->m_verts[0]); + face->vertex_index[1] = int(face_it->pos->m_verts[1]); + face->vertex_index[2] = int(face_it->pos->m_verts[2]); + + face->orig_face = face_it->pos->m_orig_face; + + face->vertex_number = 3; + } +}; + +inline + void +BSP_CSGMesh_FaceIt_Step( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + BSP_CSGMesh_FaceIt * face_it = (BSP_CSGMesh_FaceIt *)it; + + /* dereferencing iterator::end() is illegal, so we dereference 1 before it */ + /* also check that vector is not empty */ + if (face_it->mesh->FaceSet().size() && + face_it->pos <= &(*(face_it->mesh->FaceSet().end() -1))) { + + //if (face_it->face_triangle + 3 < face_it->pos->m_verts.size()) { + // (face_it->face_triangle)++; + //} else { + face_it->face_triangle = 0; + (face_it->pos) ++; + //} + } +}; + +inline + void +BSP_CSGMesh_FaceIt_Reset( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + BSP_CSGMesh_FaceIt * f_it = (BSP_CSGMesh_FaceIt *)it; + f_it->pos = &f_it->mesh->FaceSet()[0]; + f_it->face_triangle = 0; +}; + +inline + void +BSP_CSGMesh_FaceIt_Construct( + BSP_CSGMesh * mesh, + CSG_FaceIteratorDescriptor *output +) { + + output->Done = BSP_CSGMesh_FaceIt_Done; + output->Fill = BSP_CSGMesh_FaceIt_Fill; + output->Step = BSP_CSGMesh_FaceIt_Step; + output->Reset = BSP_CSGMesh_FaceIt_Reset; + + output->num_elements = mesh->FaceSet().size(); + + BSP_CSGMesh_FaceIt * f_it = new BSP_CSGMesh_FaceIt; + f_it->mesh = mesh; + if( output->num_elements > 0 ) + f_it->pos = &mesh->FaceSet()[0]; + f_it->face_triangle = 0; + + output->it = f_it; +}; + + +#endif + diff --git a/intern/bsp/intern/BSP_MeshPrimitives.cpp b/intern/bsp/intern/BSP_MeshPrimitives.cpp new file mode 100644 index 00000000000..54db5851be3 --- /dev/null +++ b/intern/bsp/intern/BSP_MeshPrimitives.cpp @@ -0,0 +1,301 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BSP_MeshPrimitives.h" + +#include "MT_assert.h" +#include "BSP_CSGException.h" +#include + +using namespace std; + +BSP_MVertex:: +BSP_MVertex( +) : + m_pos (MT_Point3()), + m_select_tag (false), + m_open_tag (0) +{ +}; + +BSP_MVertex:: +BSP_MVertex( + const MT_Point3 & pos +) : + m_pos(pos), + m_select_tag (false), + m_open_tag (0) +{ +}; + + + bool +BSP_MVertex:: +RemoveEdge( + BSP_EdgeInd e +){ + vector::iterator result = find(m_edges.begin(),m_edges.end(),e); + if (result == m_edges.end()) { + return false; + } + BSP_EdgeInd last = m_edges.back(); + m_edges.pop_back(); + if (m_edges.empty()) return true; + + *result = last; + return true; +} + + void +BSP_MVertex:: +AddEdge( + BSP_EdgeInd e +){ + m_edges.push_back(e); +} + + void +BSP_MVertex:: +SwapEdge( + BSP_EdgeInd e_old, + BSP_EdgeInd e_new +){ + vector::iterator result = + find(m_edges.begin(),m_edges.end(),e_old); + if (result == m_edges.end()) { + BSP_CSGException e(e_mesh_error); + throw(e); + MT_assert(false); + } + + *result = e_new; +} + + bool +BSP_MVertex:: +SelectTag( +) const{ + return m_select_tag; +} + + void +BSP_MVertex:: +SetSelectTag( + bool tag +){ + m_select_tag = tag; +} + + int +BSP_MVertex:: +OpenTag( +) const { + return m_open_tag; +} + + void +BSP_MVertex:: +SetOpenTag( + int tag +){ + m_open_tag = tag; +} + + +/** + * Edge Primitive Methods. + */ + +BSP_MEdge:: +BSP_MEdge( +){ + m_verts[0] = m_verts[1] = BSP_VertexInd::Empty(); +} + + bool +BSP_MEdge:: +operator == ( + BSP_MEdge & rhs +){ + // edges are the same if their vertex indices are the + // same!!! Other properties are not checked + + int matches = 0; + + if (this->m_verts[0] == rhs.m_verts[0]) { + ++matches; + } + if (this->m_verts[1] == rhs.m_verts[0]) { + ++matches; + } + if (this->m_verts[0] == rhs.m_verts[1]) { + ++matches; + } + if (this->m_verts[1] == rhs.m_verts[1]) { + ++matches; + } + + if (matches >= 2) { + return true; + } + return false; +} + + void +BSP_MEdge:: +SwapFace( + BSP_FaceInd old_f, + BSP_FaceInd new_f +){ + vector::iterator result = + find(m_faces.begin(),m_faces.end(),old_f); + if (result == m_faces.end()) { + BSP_CSGException e(e_mesh_error); + throw(e); + MT_assert(false); + } + + *result = new_f; +} + + BSP_VertexInd +BSP_MEdge:: +OpVertex( + BSP_VertexInd vi +) const { + if (vi == m_verts[0]) return m_verts[1]; + if (vi == m_verts[1]) return m_verts[0]; + MT_assert(false); + BSP_CSGException e(e_mesh_error); + throw(e); + + return BSP_VertexInd::Empty(); +} + + bool +BSP_MEdge:: +SelectTag( +) const { + return bool(m_verts[1].Tag() & 0x1); +} + void +BSP_MEdge:: +SetSelectTag( + bool tag +){ + m_verts[1].SetTag(int(tag)); +} + + int +BSP_MEdge:: +OpenTag( +) const { + return m_verts[0].Tag(); +} + + void +BSP_MEdge:: +SetOpenTag( + int tag +) { + // Note conversion from int to unsigned int!!!!! + m_verts[0].SetTag(tag); +} + + +/** + * Face primitive methods + */ + + +BSP_MFace:: +BSP_MFace( +): + m_open_tag(-1), + m_orig_face(0) +{ + // nothing to do +} + + void +BSP_MFace:: +Invert( +){ + + // TODO replace reverse as I think some compilers + // do not support the STL routines employed. + + reverse( + m_verts.begin(), + m_verts.end() + ); + + // invert the normal + m_plane.Invert(); +} + + bool +BSP_MFace:: +SelectTag( +) const { + return bool(m_verts[1].Tag() & 0x1); +} + + void +BSP_MFace:: +SetSelectTag( + bool tag +){ + m_verts[1].SetTag(int(tag)); +}; + + int +BSP_MFace:: +OpenTag( +) const { + return m_open_tag; +} + + void +BSP_MFace:: +SetOpenTag( + int tag +){ + // Note conversion from int to unsigned int!!!!! + m_open_tag = tag; +} + + + diff --git a/intern/bsp/intern/BSP_MeshPrimitives.h b/intern/bsp/intern/BSP_MeshPrimitives.h new file mode 100644 index 00000000000..d245ed02524 --- /dev/null +++ b/intern/bsp/intern/BSP_MeshPrimitives.h @@ -0,0 +1,279 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_BSP_MeshPrimitives +#define NAN_INCLUDED_BSP_MeshPrimitives + +#include "CTR_TaggedIndex.h" +#include "MT_Vector3.h" +#include "MT_Plane3.h" + +#include + +typedef CTR_TaggedIndex<24,0x00ffffff> BSP_VertexInd; +typedef CTR_TaggedIndex<24,0x00ffffff> BSP_EdgeInd; +typedef CTR_TaggedIndex<24,0x00ffffff> BSP_FaceInd; +typedef CTR_TaggedIndex<24,0x00ffffff> BSP_FragInd; + + +typedef std::vector BSP_VertexList; +typedef std::vector BSP_EdgeList; +typedef std::vector BSP_FaceList; + +/** + * Enum representing classification of primitives + * with respect to a hyperplane. + */ + +enum BSP_Classification{ + e_unclassified = 0, + e_classified_in = 1, + e_classified_out = 2, + e_classified_on = 4, + e_classified_spanning = 7 +}; + +/** + * @section Mesh linkage + * The mesh is linked in a similar way to the decimation mesh, + * although the primitives are a little more general and not + * limited to manifold meshes. + * Vertices -> (2+)Edges + * Edges -> (1+)Polygons + * Edges -> (2)Vertices. + * Polygons -> (3+)Vertices. + * + * this structure allows for arbitrary polygons (assumed to be convex). + * Edges can point to more than 2 polygons (non-manifold) + * + * We also define 2 different link types between edges and their + * neighbouring polygons. A weak link and a strong link. + * A weak link means the polygon is in a different mesh fragment + * to the other polygon. A strong link means the polygon is in the + * same fragment. + * This is not entirely consistent as it means edges have to be associated + * with fragments, in reality only polygons will be - edges and vertices + * will live in global pools. I guess we should mark edges as being on plane + * boundaries. This leaves a problem with non-manifold edges because for example + * 3 of 4 possible edges could lie in 1 fragment and the remaining edge lie in + * another, there is no way to work out then from one polygon which neighbouring + * polygons are in the same/different mesh fragment. + * + * By definition an edge will only ever lie on 1 hyperplane. We can then just + * tag neighbouring polygons with one of 3 tags to group them. + */ + +class BSP_MVertex { +public : + MT_Point3 m_pos; + BSP_EdgeList m_edges; + + /** + * TODO + * Is this boolean necessary or can we nick a few bits of m_edges[0] + * for example? + * The only problem with this is that if the vertex is degenerate then + * m_edges[0] may not exist. If the algorithm guarentees that this is + * not the case then it should be changed. + */ + + bool m_select_tag; + int m_open_tag; + + BSP_MVertex( + ); + + BSP_MVertex( + const MT_Point3 & pos + ); + + BSP_MVertex & + operator = ( + const BSP_MVertex & other + ) { + m_pos = other.m_pos; + m_edges = other.m_edges; + m_select_tag = other.m_select_tag; + m_open_tag = other.m_open_tag; + return (*this); + }; + + bool + RemoveEdge( + BSP_EdgeInd e + ); + + void + AddEdge( + BSP_EdgeInd e + ); + + void + SwapEdge( + BSP_EdgeInd e_old, + BSP_EdgeInd e_new + ); + + /** + * These operations are ONLY valid when the + * vertex has some edges associated with it. + * This is left to the user to guarentee. + * Also note that these tag's are not guarenteed + * to survive after a call to RemoveEdge(), + * because we use edges for the open tag. + */ + + int + OpenTag( + ) const; + + void + SetOpenTag( + int tag + ); + + bool + SelectTag( + ) const; + + void + SetSelectTag( + bool tag + ); +}; + +class BSP_MEdge { +public : + BSP_VertexInd m_verts[2]; + BSP_FaceList m_faces; + + BSP_MEdge( + ); + + bool operator == ( + BSP_MEdge & rhs + ); + + void + SwapFace( + BSP_FaceInd old_f, + BSP_FaceInd new_f + ); + + BSP_VertexInd + OpVertex( + BSP_VertexInd vi + ) const; + + bool + SelectTag( + ) const; + + void + SetSelectTag( + bool tag + ); + + /** + * We use one of the vertex indices for tag informtaion. + * This means these tags will not survive if you change + * the vertex indices. + */ + + int + OpenTag( + ) const; + + void + SetOpenTag( + int tag + ) ; +}; + +class BSP_MFace { +public : + + BSP_VertexList m_verts; + + // We also store the plane equation of this + // face. Generating on the fly during tree + // construction can lead to a lot of numerical errors. + // because the polygon size can get very small. + + MT_Plane3 m_plane; + + int m_open_tag; + unsigned int m_orig_face; + + BSP_MFace( + ); + + // Invert the face , done by reversing the vertex order + // and inverting the face normal. + + void + Invert( + ); + + /** + * Tagging + * We use the tag from m_verts[1] for the select tag + * and the the tag from m_verts[0] for the open tag. + * There is always a chance that the polygon contains + * no vertices but this should be checked at construction + * time. + * Also note that changing the vertex indices of this polygon + * will likely remove tagging information. + * + */ + + bool + SelectTag( + ) const; + + void + SetSelectTag( + bool tag + ); + + int + OpenTag( + ) const; + + void + SetOpenTag( + int tag + ) ; + +}; + +#endif + diff --git a/intern/bsp/intern/CSG_BooleanOps.cpp b/intern/bsp/intern/CSG_BooleanOps.cpp new file mode 100644 index 00000000000..c6f4c5d34d0 --- /dev/null +++ b/intern/bsp/intern/CSG_BooleanOps.cpp @@ -0,0 +1,183 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * Implementation of external api for CSG part of BSP lib interface. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "../extern/CSG_BooleanOps.h" +#include "BSP_CSGMesh_CFIterator.h" +#include "MEM_RefCountPtr.h" + +#include "../../boolop/extern/BOP_Interface.h" +#include +using namespace std; + +#include "BSP_MeshPrimitives.h" + +struct BSP_MeshInfo { + BSP_CSGMesh *output_mesh; +}; + +using namespace std; + + CSG_BooleanOperation * +CSG_NewBooleanFunction( + void +){ + BSP_MeshInfo * mesh_info = new BSP_MeshInfo; + CSG_BooleanOperation * output = new CSG_BooleanOperation; + + if (mesh_info==NULL || output==NULL) return NULL; + + mesh_info->output_mesh = NULL; + output->CSG_info = mesh_info; + + return output; +} + +/** + * Compute the boolean operation, UNION, INTERSECION or DIFFERENCE + */ + int +CSG_PerformBooleanOperation( + CSG_BooleanOperation *operation, + CSG_OperationType op_type, + CSG_FaceIteratorDescriptor obAFaces, + CSG_VertexIteratorDescriptor obAVertices, + CSG_FaceIteratorDescriptor obBFaces, + CSG_VertexIteratorDescriptor obBVertices +){ + if (operation == NULL) return 0; + BSP_MeshInfo * mesh_info = static_cast(operation->CSG_info); + if (mesh_info == NULL) return 0; + + obAFaces.Reset(obAFaces.it); + obBFaces.Reset(obBFaces.it); + obAVertices.Reset(obAVertices.it); + obBVertices.Reset(obBVertices.it); + + BoolOpType boolType; + + switch( op_type ) { + case e_csg_union: + boolType = BOP_UNION; + break; + case e_csg_difference: + boolType = BOP_DIFFERENCE; + break; + default: + boolType = BOP_INTERSECTION; + break; + } + + BoolOpState boolOpResult; + try { + boolOpResult = BOP_performBooleanOperation( boolType, + (BSP_CSGMesh**) &(mesh_info->output_mesh), + obAFaces, obAVertices, obBFaces, obBVertices); + } + catch(...) { + return 0; + } + + switch (boolOpResult) { + case BOP_OK: return 1; + case BOP_NO_SOLID: return -2; + case BOP_ERROR: return 0; + default: return 1; + } +} + + int +CSG_OutputFaceDescriptor( + CSG_BooleanOperation * operation, + CSG_FaceIteratorDescriptor * output +){ + if (operation == NULL) return 0; + BSP_MeshInfo * mesh_info = static_cast(operation->CSG_info); + + if (mesh_info == NULL) return 0; + if (mesh_info->output_mesh == NULL) return 0; + + BSP_CSGMesh_FaceIt_Construct(mesh_info->output_mesh,output); + return 1; +} + + + int +CSG_OutputVertexDescriptor( + CSG_BooleanOperation * operation, + CSG_VertexIteratorDescriptor *output +){ + if (operation == NULL) return 0; + BSP_MeshInfo * mesh_info = static_cast(operation->CSG_info); + + if (mesh_info == NULL) return 0; + if (mesh_info->output_mesh == NULL) return 0; + + BSP_CSGMeshVertexIt_Construct(mesh_info->output_mesh,output); + return 1; +} + + void +CSG_FreeVertexDescriptor( + CSG_VertexIteratorDescriptor * v_descriptor +){ + BSP_CSGMesh_VertexIt_Destruct(v_descriptor); +} + + + void +CSG_FreeFaceDescriptor( + CSG_FaceIteratorDescriptor * f_descriptor +){ + BSP_CSGMesh_FaceIt_Destruct(f_descriptor); +} + + + void +CSG_FreeBooleanOperation( + CSG_BooleanOperation *operation +){ + if (operation != NULL) { + BSP_MeshInfo * mesh_info = static_cast(operation->CSG_info); + + delete (mesh_info->output_mesh); + delete(mesh_info); + delete(operation); + } +} + diff --git a/intern/bsp/intern/Makefile b/intern/bsp/intern/Makefile new file mode 100644 index 00000000000..a5e8565a6ff --- /dev/null +++ b/intern/bsp/intern/Makefile @@ -0,0 +1,48 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# string intern Makefile +# + +LIBNAME = bsp +DIR = $(OCGDIR)/intern/$(LIBNAME) +DIRS = common + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I../extern +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I$(NAN_MEMUTIL)/include +CPPFLAGS += -I$(NAN_CONTAINER)/include +CPPFLAGS += -Icommon + + diff --git a/intern/bsp/make/msvc6_0/bsplib.dsp b/intern/bsp/make/msvc6_0/bsplib.dsp new file mode 100644 index 00000000000..00bac967221 --- /dev/null +++ b/intern/bsp/make/msvc6_0/bsplib.dsp @@ -0,0 +1,138 @@ +# Microsoft Developer Studio Project File - Name="bsplib" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=bsplib - 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 "bsplib.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 "bsplib.mak" CFG="bsplib - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "bsplib - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "bsplib - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "bsplib - 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 "..\..\..\..\obj\windows\intern\bsp\" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\bsp\" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /Ob2 /I "../../../../../lib/windows/memutil/include" /I "../.." /I "../../../../../lib/windows/moto/include" /I "../../../../../lib/windows/container/include" /I "..\..\..\container" /I "..\..\..\moto\include" /I "..\..\..\memutil" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\bsp\libbsp.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\extern\*.h ..\..\..\..\..\lib\windows\bsp\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\bsp\*.lib ..\..\..\..\..\lib\windows\bsp\lib\*.a ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "bsplib - 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 "..\..\..\..\obj\windows\intern\bsp\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\bsp\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../../../../lib/windows/memutil" /I "../.." /I "../../../../../lib/windows/moto/include" /I "../../../../../lib/windows/container/include" /I "../../../../../lib/windows/memutil/include" /I "..\..\..\container" /I "..\..\..\moto\include" /I "..\..\..\memutil" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\bsp\debug\libbsp.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\extern\*.h ..\..\..\..\..\lib\windows\bsp\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\bsp\debug\*.lib ..\..\..\..\..\lib\windows\bsp\lib\debug\*.a ECHO Copying Debug info. XCOPY /Y ..\..\..\..\obj\windows\intern\bsp\debug\vc60.* ..\..\..\..\..\lib\windows\bsp\lib\debug\ ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "bsplib - Win32 Release" +# Name "bsplib - Win32 Debug" +# Begin Group "intern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGException.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGISplitter.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGMesh.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGMesh.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGMesh_CFIterator.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_MeshPrimitives.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_MeshPrimitives.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\CSG_BooleanOps.cpp +# End Source File +# End Group +# Begin Group "extern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\extern\CSG_BooleanOps.h +# End Source File +# End Group +# End Target +# End Project diff --git a/intern/bsp/make/msvc6_0/bsplib.dsw b/intern/bsp/make/msvc6_0/bsplib.dsw new file mode 100644 index 00000000000..1827dc3746e --- /dev/null +++ b/intern/bsp/make/msvc6_0/bsplib.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "bsplib"=.\bsplib.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/bsp/make/msvc_7_0/bsplib.sln b/intern/bsp/make/msvc_7_0/bsplib.sln new file mode 100644 index 00000000000..e8c116b639e --- /dev/null +++ b/intern/bsp/make/msvc_7_0/bsplib.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bsplib", "bsplib.vcproj", "{20F0EE62-A21A-46B7-B425-7923F4674B4F}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {20F0EE62-A21A-46B7-B425-7923F4674B4F}.Debug.ActiveCfg = Debug|Win32 + {20F0EE62-A21A-46B7-B425-7923F4674B4F}.Debug.Build.0 = Debug|Win32 + {20F0EE62-A21A-46B7-B425-7923F4674B4F}.Release.ActiveCfg = Release|Win32 + {20F0EE62-A21A-46B7-B425-7923F4674B4F}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/intern/bsp/make/msvc_7_0/bsplib.vcproj b/intern/bsp/make/msvc_7_0/bsplib.vcproj new file mode 100644 index 00000000000..59fb9f3691d --- /dev/null +++ b/intern/bsp/make/msvc_7_0/bsplib.vcproj @@ -0,0 +1,282 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/bsp/test/BSP_GhostTest/BSP_GhostTest.dsp b/intern/bsp/test/BSP_GhostTest/BSP_GhostTest.dsp new file mode 100644 index 00000000000..aaa45273845 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_GhostTest.dsp @@ -0,0 +1,126 @@ +# Microsoft Developer Studio Project File - Name="BSP_GhostTest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=BSP_GhostTest - 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 "BSP_GhostTest.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 "BSP_GhostTest.mak" CFG="BSP_GhostTest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BSP_GhostTest - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "BSP_GhostTest - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BSP_GhostTest - 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 Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /G6 /MT /W3 /GX /O2 /Ob2 /I "../../extern/" /I "../../../../lib/windows/string/include" /I "../../../../lib/windows/ghost/include" /I "../../../../lib/windows/moto/include" /I "../../../../lib/windows/memutil/include" /I "../../../../lib/windows/container/include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 glu32.lib opengl32.lib kernel32.lib user32.lib gdi32.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\..\..\lib\windows\glut-3.7\lib\\" + +!ELSEIF "$(CFG)" == "BSP_GhostTest - 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 Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../extern/" /I "../../../../lib/windows/string/include" /I "../../../../lib/windows/ghost/include" /I "../../../../lib/windows/moto/include" /I "../../../../lib/windows/memutil/include" /I "../../../../lib/windows/container/include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 glu32.lib opengl32.lib user32.lib gdi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\..\lib\windows\glut-3.7\lib\\" + +!ENDIF + +# Begin Target + +# Name "BSP_GhostTest - Win32 Release" +# Name "BSP_GhostTest - Win32 Debug" +# Begin Source File + +SOURCE=.\BSP_GhostTest3D.cpp +# End Source File +# Begin Source File + +SOURCE=.\BSP_GhostTest3D.h +# End Source File +# Begin Source File + +SOURCE=.\BSP_MeshDrawer.cpp +# End Source File +# Begin Source File + +SOURCE=.\BSP_MeshDrawer.h +# End Source File +# Begin Source File + +SOURCE=.\BSP_PlyLoader.cpp +# End Source File +# Begin Source File + +SOURCE=.\BSP_PlyLoader.h +# End Source File +# Begin Source File + +SOURCE=.\BSP_TMesh.h +# End Source File +# Begin Source File + +SOURCE=.\main.cpp +# End Source File +# Begin Source File + +SOURCE=.\ply.h +# End Source File +# Begin Source File + +SOURCE=.\plyfile.c +# End Source File +# End Target +# End Project diff --git a/intern/bsp/test/BSP_GhostTest/BSP_GhostTest.dsw b/intern/bsp/test/BSP_GhostTest/BSP_GhostTest.dsw new file mode 100644 index 00000000000..802fba84bef --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_GhostTest.dsw @@ -0,0 +1,125 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "BSP_GhostTest"=.\BSP_GhostTest.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name bsplib + End Project Dependency + Begin Project Dependency + Project_Dep_Name ghost + End Project Dependency + Begin Project Dependency + Project_Dep_Name string + End Project Dependency + Begin Project Dependency + Project_Dep_Name MoTo + End Project Dependency +}}} + +############################################################################### + +Project: "MoTo"=..\..\..\moto\make\msvc_6_0\MoTo.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "bsplib"=..\..\make\msvc6_0\bsplib.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name container + End Project Dependency + Begin Project Dependency + Project_Dep_Name memutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name MoTo + End Project Dependency +}}} + +############################################################################### + +Project: "container"=..\..\..\container\make\msvc_6_0\container.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name memutil + End Project Dependency +}}} + +############################################################################### + +Project: "ghost"=..\..\..\ghost\make\msvc\ghost.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "memutil"=..\..\..\memutil\make\msvc_60\memutil.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "string"=..\..\..\string\make\msvc_6_0\string.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/bsp/test/BSP_GhostTest/BSP_GhostTest3D.cpp b/intern/bsp/test/BSP_GhostTest/BSP_GhostTest3D.cpp new file mode 100644 index 00000000000..ec34b104e4a --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_GhostTest3D.cpp @@ -0,0 +1,658 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + +* $Id$ +* Copyright (C) 2001 NaN Technologies B.V. +*/ +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(WIN32) || defined(__APPLE__) +# ifdef WIN32 +# include +# include +# include +# else // WIN32 +# include +# endif // WIN32 +#else // defined(WIN32) || defined(__APPLE__) +# include +# include +#endif // defined(WIN32) || defined(__APPLE__) + + +#include "BSP_GhostTest3D.h" +#include "BSP_MeshDrawer.h" + +#include "GHOST_ISystem.h" +#include "GHOST_IWindow.h" + +#include "MT_Quaternion.h" +#include "MT_Transform.h" +#include "CSG_BooleanOps.h" + +#include + + int +EmptyInterpFunc( + void *d1, + void * d2, + void *dnew, + float epsilon +){ + return 0; +} + + + +using namespace std; + + +BSP_GhostTestApp3D:: +BSP_GhostTestApp3D( +) : + m_window(NULL), + m_system(NULL), + m_finish_me_off(false), + m_current_object(0) +{ + //nothing to do; +} + + void +BSP_GhostTestApp3D:: +SetMesh( + MEM_SmartPtr mesh +){ + m_meshes.push_back(mesh); + + BSP_RotationSetting rotation_setting; + BSP_TranslationSetting translation_setting; + + rotation_setting.m_angle_x = MT_Scalar(0); + rotation_setting.m_angle_y = MT_Scalar(0); + rotation_setting.m_moving = false; + rotation_setting.x_old = 0; + rotation_setting.y_old = 0; + + translation_setting.m_t_x = MT_Scalar(0); + translation_setting.m_t_y = MT_Scalar(0); + translation_setting.m_t_z = MT_Scalar(0); + translation_setting.m_moving = false; + translation_setting.x_old = 0; + translation_setting.y_old = 0; + + m_rotation_settings.push_back(rotation_setting); + m_translation_settings.push_back(translation_setting); + m_render_modes.push_back(e_wireframe_shaded); + m_scale_settings.push_back(MT_Scalar(1)); + +} + + void +BSP_GhostTestApp3D:: +Swap( + int i +){ + + if (!m_rotation_settings[i].m_moving && !m_translation_settings[i].m_moving) { + swap(m_meshes[i],m_meshes.back()); + swap(m_rotation_settings[i],m_rotation_settings.back()); + swap(m_translation_settings[i],m_translation_settings.back()); + swap(m_scale_settings[i],m_scale_settings.back()); + swap(m_render_modes[i],m_render_modes.back()); + } +} + + + MT_Transform +BSP_GhostTestApp3D:: +GetTransform( + int i +){ + + MT_Quaternion q_ax(MT_Vector3(0,1,0),m_rotation_settings[i].m_angle_x); + MT_Quaternion q_ay(MT_Vector3(1,0,0),m_rotation_settings[i].m_angle_y); + + MT_Point3 tr( + m_translation_settings[i].m_t_x, + m_translation_settings[i].m_t_y, + m_translation_settings[i].m_t_z + ); + + + MT_Matrix3x3 rotx(q_ax); + MT_Matrix3x3 roty(q_ay); + + MT_Matrix3x3 rot = rotx * roty; + + MT_Transform trans(tr,rot); + + MT_Transform scalet; + scalet.setIdentity(); + scalet.scale(m_scale_settings[i],m_scale_settings[i],m_scale_settings[i]); + + return trans * scalet; +} + + void +BSP_GhostTestApp3D:: +Operate( + int type +){ + + CSG_VertexIteratorDescriptor * vA = VertexIt_Construct(m_meshes[0],GetTransform(0)); + CSG_FaceIteratorDescriptor * fA = FaceIt_Construct(m_meshes[0]); + + CSG_VertexIteratorDescriptor * vB = VertexIt_Construct(m_meshes[1],GetTransform(1)); + CSG_FaceIteratorDescriptor * fB = FaceIt_Construct(m_meshes[1]); + + // describe properties. + + CSG_MeshPropertyDescriptor props; + props.user_face_vertex_data_size = 0; + props.user_data_size = 0; + + CSG_BooleanOperation * op = CSG_NewBooleanFunction(); + props = CSG_DescibeOperands(op,props,props); + + CSG_PerformBooleanOperation( + op,CSG_OperationType(type), + *fA,*vA,*fB,*vB,EmptyInterpFunc + ); + + CSG_FaceIteratorDescriptor out_f; + CSG_OutputFaceDescriptor(op,&out_f); + + CSG_VertexIteratorDescriptor out_v; + CSG_OutputVertexDescriptor(op,&out_v); + + MEM_SmartPtr new_mesh (BuildMesh(props,out_f,out_v)); + + // free stuff + + CSG_FreeVertexDescriptor(&out_v); + CSG_FreeFaceDescriptor(&out_f); + CSG_FreeBooleanOperation(op); + + op = NULL; + SetMesh(new_mesh); +} + + + void +BSP_GhostTestApp3D:: +UpdateFrame( +){ +if (m_window) { + + GHOST_Rect v_rect; + m_window->getClientBounds(v_rect); + + glViewport(0,0,v_rect.getWidth(),v_rect.getHeight()); + +} +} + + +MT_Vector3 +BSP_GhostTestApp3D:: +UnProject( + const MT_Vector3 & vec +) { + + GLint viewport[4]; + GLdouble mvmatrix[16],projmatrix[16]; + + glGetIntegerv(GL_VIEWPORT,viewport); + glGetDoublev(GL_MODELVIEW_MATRIX,mvmatrix); + glGetDoublev(GL_PROJECTION_MATRIX,projmatrix); + + GLdouble realy = viewport[3] - vec.y() - 1; + GLdouble outx,outy,outz; + + gluUnProject(vec.x(),realy,vec.z(),mvmatrix,projmatrix,viewport,&outx,&outy,&outz); + + return MT_Vector3(outx,outy,outz); +} + + + bool +BSP_GhostTestApp3D:: +InitApp( +){ + + // create a system and window with opengl + // rendering context. + + GHOST_TSuccess success = GHOST_ISystem::createSystem(); + if (success == GHOST_kFailure) return false; + + m_system = GHOST_ISystem::getSystem(); + if (m_system == NULL) return false; + + m_system->addEventConsumer(this); + + m_window = m_system->createWindow( + "GHOST crud3D!", + 100,100,512,512,GHOST_kWindowStateNormal, + GHOST_kDrawingContextTypeOpenGL,false + ); + + if ( + m_window == NULL + ) { + m_system = NULL; + GHOST_ISystem::disposeSystem(); + return false; + } + + // make an opengl frustum for this wind + + MT_Vector3 min,max; + + min = m_meshes[0]->m_min; + max = m_meshes[0]->m_max; + InitOpenGl(min,max); + + return true; +} + + void +BSP_GhostTestApp3D:: +Run( +){ + if (m_system == NULL) { + return; + } + + while (!m_finish_me_off) { + m_system->processEvents(true); + m_system->dispatchEvents(); + }; +} + + bool +BSP_GhostTestApp3D:: +processEvent( + GHOST_IEvent* event +){ + + bool handled = false; + + switch(event->getType()) { + case GHOST_kEventWindowSize: + case GHOST_kEventWindowActivate: + UpdateFrame(); + case GHOST_kEventWindowUpdate: + DrawPolies(); + handled = true; + break; + case GHOST_kEventButtonDown: + { + int x,y; + m_system->getCursorPosition(x,y); + + + int wx,wy; + m_window->screenToClient(x,y,wx,wy); + + GHOST_TButtonMask button = + static_cast(event->getData())->button; + + if (button == GHOST_kButtonMaskLeft) { + m_rotation_settings[m_current_object].m_moving = true; + m_rotation_settings[m_current_object].x_old = x; + m_rotation_settings[m_current_object].y_old = y; + } else + if (button == GHOST_kButtonMaskRight) { + m_translation_settings[m_current_object].m_moving = true; + m_translation_settings[m_current_object].x_old = x; + m_translation_settings[m_current_object].y_old = y; + } else + + m_window->invalidate(); + handled = true; + break; + + } + + case GHOST_kEventButtonUp: + { + + GHOST_TButtonMask button = + static_cast(event->getData())->button; + + if (button == GHOST_kButtonMaskLeft) { + m_rotation_settings[m_current_object].m_moving = false; + m_rotation_settings[m_current_object].x_old = 0; + m_rotation_settings[m_current_object].y_old = 0; + + } else + if (button == GHOST_kButtonMaskRight) { + m_translation_settings[m_current_object].m_moving = false; + m_translation_settings[m_current_object].x_old; + m_translation_settings[m_current_object].y_old; + + } + m_window->invalidate(); + handled = true; + break; + + } + + case GHOST_kEventCursorMove: + { + int x,y; + m_system->getCursorPosition(x,y); + int wx,wy; + m_window->screenToClient(x,y,wx,wy); + + if (m_rotation_settings[m_current_object].m_moving) { + m_rotation_settings[m_current_object].m_angle_x = MT_Scalar(wx)/20; + m_rotation_settings[m_current_object].x_old = wx; + m_rotation_settings[m_current_object].m_angle_y = MT_Scalar(wy)/20; + m_rotation_settings[m_current_object].y_old = wy; + + m_window->invalidate(); + } + if (m_translation_settings[m_current_object].m_moving) { + + // project current objects bounding box center into screen space. + // unproject mouse point into object space using z-value from + // projected bounding box center. + + GHOST_Rect bounds; + m_window->getClientBounds(bounds); + + int w_h = bounds.getHeight(); + + y = w_h - wy; + x = wx; + + double mvmatrix[16]; + double projmatrix[16]; + GLint viewport[4]; + + double px, py, pz,sz; + + /* Get the matrices needed for gluUnProject */ + glGetIntegerv(GL_VIEWPORT, viewport); + glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix); + glGetDoublev(GL_PROJECTION_MATRIX, projmatrix); + + // work out the position of the end effector in screen space + + GLdouble ex,ey,ez; + + ex = m_translation_settings[m_current_object].m_t_x; + ey = m_translation_settings[m_current_object].m_t_y; + ez = m_translation_settings[m_current_object].m_t_z; + + gluProject(ex, ey, ez, mvmatrix, projmatrix, viewport, &px, &py, &sz); + gluUnProject((GLdouble) x, (GLdouble) y, sz, mvmatrix, projmatrix, viewport, &px, &py, &pz); + + m_translation_settings[m_current_object].m_t_x = px; + m_translation_settings[m_current_object].m_t_y = py; + m_translation_settings[m_current_object].m_t_z = pz; + m_window->invalidate(); + + } + + handled = true; + break; + } + + case GHOST_kEventKeyDown : + { + GHOST_TEventKeyData *kd = + static_cast(event->getData()); + + + switch(kd->key) { + case GHOST_kKeyI: + { + // now intersect meshes. + Operate(e_csg_intersection); + handled = true; + m_window->invalidate(); + break; + } + case GHOST_kKeyU: + { + Operate(e_csg_union); + handled = true; + m_window->invalidate(); + break; + } + case GHOST_kKeyD: + { + Operate(e_csg_difference); + handled = true; + m_window->invalidate(); + break; + } + + case GHOST_kKeyA: + { + + m_scale_settings[m_current_object] *= 1.1; + handled = true; + m_window->invalidate(); + break; + } + case GHOST_kKeyZ: + { + m_scale_settings[m_current_object] *= 0.8; + + handled = true; + m_window->invalidate(); + break; + } + + case GHOST_kKeyR: + m_render_modes[m_current_object]++; + if (m_render_modes[m_current_object] > e_last_render_mode) { + m_render_modes[m_current_object] = e_first_render_mode; + } + handled = true; + m_window->invalidate(); + break; + + case GHOST_kKeyB: + handled = true; + m_window->invalidate(); + break; + + case GHOST_kKeyQ: + m_finish_me_off = true; + handled = true; + break; + + case GHOST_kKeyS: + Swap(m_current_object); + m_window->invalidate(); + handled = true; + break; + + case GHOST_kKeySpace: + + // increment the current object only if the object is not being + // manipulated. + if (! (m_rotation_settings[m_current_object].m_moving || m_translation_settings[m_current_object].m_moving)) { + m_current_object ++; + if (m_current_object >= m_meshes.size()) { + m_current_object = 0; + + } + } + m_window->invalidate(); + handled = true; + break; + default : + break; + } + } + + default : + break; + } + return handled; +}; + +BSP_GhostTestApp3D:: +~BSP_GhostTestApp3D( +){ + + if (m_window) { + m_system->disposeWindow(m_window); + m_window = NULL; + GHOST_ISystem::disposeSystem(); + m_system = NULL; + } +}; + + + + void +BSP_GhostTestApp3D:: +DrawPolies( +){ + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + for (int i = 0; i < m_meshes.size(); ++i) { + MT_Transform trans = GetTransform(i); + + float opengl_mat[16]; + trans.getValue(opengl_mat); + + glPushMatrix(); + glMultMatrixf(opengl_mat); + MT_Vector3 color(1.0,1.0,1.0); + if (i == m_current_object) { + color = MT_Vector3(1.0,0,0); + } + BSP_MeshDrawer::DrawMesh(m_meshes[i].Ref(),m_render_modes[i]); + + glPopMatrix(); + } + + m_window->swapBuffers(); + +} + + void +BSP_GhostTestApp3D:: +InitOpenGl( + const MT_Vector3 &min, + const MT_Vector3 &max +){ + + GLfloat light_diffuse0[] = {1.0, 0.0, 0.0, 0.5}; /* Red diffuse light. */ + GLfloat light_position0[] = {1.0, 1.0, 1.0, 0.0}; /* Infinite light location. */ + + GLfloat light_diffuse1[] = {1.0, 1.0, 1.0, 0.5}; /* Red diffuse light. */ + GLfloat light_position1[] = {1.0, 0, 0, 0.0}; /* Infinite light location. */ + + /* Enable a single OpenGL light. */ + + glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse0); + glLightfv(GL_LIGHT0, GL_POSITION, light_position0); + + glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse1); + glLightfv(GL_LIGHT1, GL_POSITION, light_position1); + + + glEnable(GL_LIGHT0); + glEnable(GL_LIGHT1); + glEnable(GL_LIGHTING); + + // make sure there is no back face culling. + // glDisable(GL_CULL_FACE); + + // use two sided lighting model + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE); + + /* Use depth buffering for hidden surface elimination. */ + + glEnable(GL_DEPTH_TEST); + + /* Setup the view of the cube. */ + + glMatrixMode(GL_PROJECTION); + + // center of the box + 3* depth of box + + MT_Vector3 center = (min + max) * 0.5; + MT_Vector3 diag = max - min; + + float depth = diag.length(); + float distance = 5; + + gluPerspective( + /* field of view in degree */ 40.0, + /* aspect ratio */ 1.0, + /* Z near */ 1.0, + /* Z far */ distance * depth * 2 + ); + glMatrixMode(GL_MODELVIEW); + + gluLookAt( + center.x(), center.y(), center.z() + distance*depth, //eye + center.x(), center.y(), center.z(), //center + 0.0, 1.0, 0. + ); /* up is in positive Y direction */ + +} + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/bsp/test/BSP_GhostTest/BSP_GhostTest3D.h b/intern/bsp/test/BSP_GhostTest/BSP_GhostTest3D.h new file mode 100644 index 00000000000..042c73174a6 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_GhostTest3D.h @@ -0,0 +1,163 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BSP_GhostTest_h +#define BSP_GhostTest_h + +#include "GHOST_IEventConsumer.h" +#include "MT_Vector3.h" +#include "BSP_TMesh.h" +#include "BSP_MeshDrawer.h" + +#include + +class GHOST_IWindow; +class GHOST_ISystem; + + +class BSP_GhostTestApp3D : +public GHOST_IEventConsumer +{ +public : + // Construct an instance of the application; + + BSP_GhostTestApp3D( + ); + + // initialize the applicaton + + bool + InitApp( + ); + + // Run the application untill internal return. + void + Run( + ); + + ~BSP_GhostTestApp3D( + ); + + void + SetMesh( + MEM_SmartPtr mesh + ); + +private : + + struct BSP_RotationSetting { + MT_Scalar m_angle_x; + MT_Scalar m_angle_y; + int x_old; + int y_old; + bool m_moving; + }; + + struct BSP_TranslationSetting { + MT_Scalar m_t_x; + MT_Scalar m_t_y; + MT_Scalar m_t_z; + int x_old; + int y_old; + bool m_moving; + }; + + // Return the transform of object i + + MT_Transform + GetTransform( + int active_object + ); + + // Perform an operation between the first two objects in the + // list + + void + Operate( + int type + ); + + // Swap mesh i and settings with the last mesh in list. + + void + Swap( + int i + ); + + void + DrawPolies( + ); + + void + UpdateFrame( + ); + + MT_Vector3 + UnProject( + const MT_Vector3 & vec + ); + + // Create a frustum and projection matrix to + // look at the bounding box + + void + InitOpenGl( + const MT_Vector3 &min, + const MT_Vector3 &max + ); + + + // inherited from GHOST_IEventConsumer + bool + processEvent( + GHOST_IEvent* event + ); + + GHOST_IWindow *m_window; + GHOST_ISystem *m_system; + + bool m_finish_me_off; + + // List of current meshes. + std::vector< MEM_SmartPtr > m_meshes; + + std::vector< BSP_RotationSetting> m_rotation_settings; + std::vector< BSP_TranslationSetting> m_translation_settings; + std::vector< MT_Scalar> m_scale_settings; + std::vector< int> m_render_modes; + + int m_current_object; + + +}; + +#endif + diff --git a/intern/bsp/test/BSP_GhostTest/BSP_MeshDrawer.cpp b/intern/bsp/test/BSP_GhostTest/BSP_MeshDrawer.cpp new file mode 100644 index 00000000000..4f5f5d46535 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_MeshDrawer.cpp @@ -0,0 +1,164 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BSP_MeshDrawer.h" + +#include "BSP_TMesh.h" + +#if defined(WIN32) || defined(__APPLE__) +# ifdef WIN32 +# include +# include +# include +# else // WIN32 +# include +# endif // WIN32 +#else // defined(WIN32) || defined(__APPLE__) +# include +# include +#endif // defined(WIN32) || defined(__APPLE__) + +#include + +using namespace std; + + void +BSP_MeshDrawer:: +DrawMesh( + BSP_TMesh &mesh, + int render_mode +){ + + + if (render_mode == e_none) return; + + // decompose polygons into triangles. + + glEnable(GL_LIGHTING); + + + if (render_mode == e_wireframe || render_mode == e_wireframe_shaded) { + + glColor3f(0.0, 0.0, 0.0); + + if (render_mode == e_wireframe) { + glDisable(GL_LIGHTING); + } else { + glEnable(GL_LIGHTING); + } + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(1.0,1.0); + + glBegin(GL_TRIANGLES); + DrawPolies(mesh); + glEnd(); + + glColor3f(1.0, 1.0, 1.0); + glDisable(GL_LIGHTING); + glDisable(GL_POLYGON_OFFSET_FILL); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + glBegin(GL_TRIANGLES); + DrawPolies(mesh); + glEnd(); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } else { + + glEnable(GL_LIGHTING); + + glBegin(GL_TRIANGLES); + DrawPolies(mesh); + glEnd(); + } + + +} + + + void +BSP_MeshDrawer:: +DrawPolies( + BSP_TMesh &mesh +){ + + const vector & verts = mesh.VertexSet(); + const vector &faces = mesh.FaceSet(); + + // just draw the edges for now. + + vector::const_iterator vertex_it = verts.begin(); + + + vector::const_iterator faces_it = faces.begin(); + vector::const_iterator faces_end = faces.end(); + + for (;faces_it != faces_end; ++faces_it ){ + + glNormal3f( + faces_it->m_normal.x(), + faces_it->m_normal.y(), + faces_it->m_normal.z() + ); + + glVertex3f( + verts[faces_it->m_verts[0]].m_pos.x(), + verts[faces_it->m_verts[0]].m_pos.y(), + verts[faces_it->m_verts[0]].m_pos.z() + ); + glVertex3f( + verts[faces_it->m_verts[1]].m_pos.x(), + verts[faces_it->m_verts[1]].m_pos.y(), + verts[faces_it->m_verts[1]].m_pos.z() + ); + glVertex3f( + verts[faces_it->m_verts[2]].m_pos.x(), + verts[faces_it->m_verts[2]].m_pos.y(), + verts[faces_it->m_verts[2]].m_pos.z() + ); + } +} + + + + + + + + + + diff --git a/intern/bsp/test/BSP_GhostTest/BSP_MeshDrawer.h b/intern/bsp/test/BSP_GhostTest/BSP_MeshDrawer.h new file mode 100644 index 00000000000..314b9691137 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_MeshDrawer.h @@ -0,0 +1,75 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BSP_MeshDrawer_h +#define BSP_MeshDrawer_h + +class BSP_TMesh; +class MT_Vector3; + +enum BSP_TRenderMode { + e_shaded, + e_none, + e_wireframe, + e_wireframe_shaded, + e_first_render_mode = e_shaded, + e_last_render_mode = e_wireframe_shaded +}; + +class BSP_MeshDrawer +{ +public : + static + void + DrawMesh( + BSP_TMesh &mesh, + int render_mode + ); + +private : + + static + void + DrawPolies( + BSP_TMesh &mesh + ); + + + BSP_MeshDrawer( + ); + + ~BSP_MeshDrawer( + ); + +}; + +#endif + diff --git a/intern/bsp/test/BSP_GhostTest/BSP_PlyLoader.cpp b/intern/bsp/test/BSP_GhostTest/BSP_PlyLoader.cpp new file mode 100644 index 00000000000..f148250f1aa --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_PlyLoader.cpp @@ -0,0 +1,200 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BSP_PlyLoader.h" + +#include "MT_Vector3.h" +#include "ply.h" + +struct LoadVertex { + float x,y,z; /* the usual 3-space position of a vertex */ +}; + +struct LoadFace { + unsigned char intensity; /* this user attaches intensity to faces */ + unsigned char nverts; /* number of vertex indices in list */ + int *verts; /* vertex index list */ +}; + + + MEM_SmartPtr +BSP_PlyLoader:: +NewMeshFromFile( + char * file_name, + MT_Vector3 &min, + MT_Vector3 &max + +) { + + min = MT_Vector3(MT_INFINITY,MT_INFINITY,MT_INFINITY); + max = MT_Vector3(-MT_INFINITY,-MT_INFINITY,-MT_INFINITY); + + PlyProperty vert_props[] = { /* list of property information for a vertex */ + {"x", PLY_FLOAT, PLY_FLOAT, offsetof(LoadVertex,x), 0, 0, 0, 0}, + {"y", PLY_FLOAT, PLY_FLOAT, offsetof(LoadVertex,y), 0, 0, 0, 0}, + {"z", PLY_FLOAT, PLY_FLOAT, offsetof(LoadVertex,z), 0, 0, 0, 0}, + }; + + PlyProperty face_props[] = { /* list of property information for a vertex */ + {"vertex_indices", PLY_INT, PLY_INT, offsetof(LoadFace,verts), + 1, PLY_UCHAR, PLY_UCHAR, offsetof(LoadFace,nverts)}, + }; + + MEM_SmartPtr mesh = new BSP_TMesh; + + if (mesh == NULL) return NULL; + + int i,j; + PlyFile *ply; + int nelems; + char **elist; + int file_type; + float version; + int nprops; + int num_elems; + PlyProperty **plist; + + char *elem_name; + + LoadVertex load_vertex; + LoadFace load_face; + + /* open a PLY file for reading */ + ply = ply_open_for_reading( + file_name, + &nelems, + &elist, + &file_type, + &version + ); + + if (ply == NULL) return NULL; + + /* go through each kind of element that we learned is in the file */ + /* and read them */ + + for (i = 0; i < nelems; i++) { + + /* get the description of the first element */ + + elem_name = elist[i]; + plist = ply_get_element_description (ply, elem_name, &num_elems, &nprops); + + /* print the name of the element, for debugging */ + + /* if we're on vertex elements, read them in */ + + if (equal_strings ("vertex", elem_name)) { + + /* set up for getting vertex elements */ + + ply_get_property (ply, elem_name, &vert_props[0]); + ply_get_property (ply, elem_name, &vert_props[1]); + ply_get_property (ply, elem_name, &vert_props[2]); + + // make some memory for the vertices + mesh->VertexSet().reserve(num_elems); + + /* grab all the vertex elements */ + for (j = 0; j < num_elems; j++) { + + /* grab and element from the file */ + ply_get_element (ply, (void *)&load_vertex); + // pass the vertex into the mesh builder. + + if (load_vertex.x < min.x()) { + min.x() = load_vertex.x; + } else + if (load_vertex.x > max.x()) { + max.x()= load_vertex.x; + } + + if (load_vertex.y < min.y()) { + min.y() = load_vertex.y; + } else + if (load_vertex.y > max.y()) { + max.y()= load_vertex.y; + } + + if (load_vertex.z < min.z()) { + min.z() = load_vertex.z; + } else + if (load_vertex.z > max.z()) { + max.z()= load_vertex.z; + } + + BSP_TVertex my_vert; + my_vert.m_pos = MT_Vector3(load_vertex.x,load_vertex.y,load_vertex.z); + mesh->VertexSet().push_back(my_vert); + } + + + } + + /* if we're on face elements, read them in */ + if (equal_strings ("face", elem_name)) { + + /* set up for getting face elements */ + + ply_get_property (ply, elem_name, &face_props[0]); + + /* grab all the face elements */ + for (j = 0; j < num_elems; j++) { + + ply_get_element (ply, (void *)&load_face); + + int v; + for (v = 2; v< load_face.nverts; v++) { + + BSP_TFace f; + + f.m_verts[0] = load_face.verts[0]; + f.m_verts[1] = load_face.verts[v-1]; + f.m_verts[2] = load_face.verts[v]; + + mesh->BuildNormal(f); + mesh->FaceSet().push_back(f); + } + // free up the memory this pile of shit used to allocate the polygon's vertices + free (load_face.verts); + } + + } + } + /* close the PLY file */ + ply_close (ply); + + return mesh; +} diff --git a/intern/bsp/test/BSP_GhostTest/BSP_PlyLoader.h b/intern/bsp/test/BSP_GhostTest/BSP_PlyLoader.h new file mode 100644 index 00000000000..d2e9b8cd2cc --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_PlyLoader.h @@ -0,0 +1,64 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BSP_PlyLoader_h +#define BSP_PlyLoader_h + +#include "MEM_SmartPtr.h" +#include "BSP_TMesh.h" + +class BSP_PlyLoader { +public : + + static + MEM_SmartPtr + NewMeshFromFile( + char * file_name, + MT_Vector3 &min, + MT_Vector3 &max + ); + + +private : + + // unimplemented - not for instantiation. + + BSP_PlyLoader( + ); + + ~BSP_PlyLoader( + ); +}; + + + +#endif + diff --git a/intern/bsp/test/BSP_GhostTest/BSP_TMesh.h b/intern/bsp/test/BSP_GhostTest/BSP_TMesh.h new file mode 100644 index 00000000000..eeb4df3d0d9 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_TMesh.h @@ -0,0 +1,401 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BSP_TMesh_h +#define BSP_TMesh_h + +#include "MT_Point3.h" +#include "MT_Vector3.h" +#include "MT_Transform.h" + +#include "MEM_SmartPtr.h" + +#include + +#include "CSG_BooleanOps.h" + +/** + * A very basic test mesh. + */ + +struct BSP_TVertex { + MT_Point3 m_pos; +}; + +struct BSP_TFace { + int m_verts[3]; + MT_Vector3 m_normal; +}; + + +class BSP_TMesh { +public : + + std::vector m_verts; + std::vector m_faces; + + MT_Vector3 m_min,m_max; + + std::vector & + VertexSet( + ){ + return m_verts; + } + + std::vector & + FaceSet( + ) { + return m_faces; + } + + void + AddFace( + int *verts, + int num_verts + ){ + int i; + for (i= 2; i it)); + iterator->it = NULL; + delete(iterator); +}; + + +static + int +VertexIt_Done( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + VertexIt * vertex_it = (VertexIt *)it; + + if (vertex_it->pos < vertex_it->mesh->VertexSet().end()) return 0; + return 1; +}; + +static + void +VertexIt_Fill( + CSG_IteratorPtr it, + CSG_IVertex *vert +) { + // assume CSG_IteratorPtr is of the correct type. + VertexIt * vertex_it = (VertexIt *)it; + + MT_Point3 p = vertex_it->pos->m_pos; + p = vertex_it->trans * p; + + p.getValue(vert->position); +}; + +static + void +VertexIt_Step( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + VertexIt * vertex_it = (VertexIt *)it; + + ++(vertex_it->pos); +}; + +static + void +VertexIt_Reset( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + VertexIt * vertex_it = (VertexIt *)it; + + vertex_it->pos = vertex_it->mesh->VertexSet().begin(); +}; + +static + CSG_VertexIteratorDescriptor * +VertexIt_Construct( + BSP_TMesh *mesh, + MT_Transform trans +){ + // user should have insured mesh is not equal to NULL. + + CSG_VertexIteratorDescriptor * output = new CSG_VertexIteratorDescriptor; + if (output == NULL) return NULL; + output->Done = VertexIt_Done; + output->Fill = VertexIt_Fill; + output->Step = VertexIt_Step; + output->Reset = VertexIt_Reset; + output->num_elements = mesh->VertexSet().size(); + + VertexIt * v_it = new VertexIt; + v_it->mesh = mesh; + v_it->pos = mesh->VertexSet().begin(); + v_it->trans = trans; + output->it = v_it; + return output; +}; + + +/** + * Face iterator. + */ + +struct FaceIt { + BSP_TMesh * mesh; + BSP_TFace *pos; +}; + + +static + void +FaceIt_Destruct( + CSG_FaceIteratorDescriptor * iterator +) { + delete ((FaceIt *)(iterator->it)); + iterator->it = NULL; + delete(iterator); +}; + + +static + int +FaceIt_Done( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + FaceIt * face_it = (FaceIt *)it; + + if (face_it->pos < face_it->mesh->FaceSet().end()) { + return 0; + } + return 1; +}; + +static + void +FaceIt_Fill( + CSG_IteratorPtr it, + CSG_IFace *face +){ + // assume CSG_IteratorPtr is of the correct type. + FaceIt * face_it = (FaceIt *)it; + // essentially iterating through a triangle fan here. + + face->vertex_index[0] = int(face_it->pos->m_verts[0]); + face->vertex_index[1] = int(face_it->pos->m_verts[1]); + face->vertex_index[2] = int(face_it->pos->m_verts[2]); + + face->vertex_number = 3; +}; + +static + void +FaceIt_Step( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + FaceIt * face_it = (FaceIt *)it; + + face_it->pos ++; +}; + +static + void +FaceIt_Reset( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + FaceIt * face_it = (FaceIt *)it; + + face_it->pos = face_it->mesh->FaceSet().begin(); +}; + +static + CSG_FaceIteratorDescriptor * +FaceIt_Construct( + BSP_TMesh * mesh +) { + CSG_FaceIteratorDescriptor * output = new CSG_FaceIteratorDescriptor; + if (output == NULL) return NULL; + + output->Done = FaceIt_Done; + output->Fill = FaceIt_Fill; + output->Step = FaceIt_Step; + output->Reset = FaceIt_Reset; + + output->num_elements = mesh->FaceSet().size(); + + FaceIt * f_it = new FaceIt; + f_it->mesh = mesh; + f_it->pos = mesh->FaceSet().begin(); + + output->it = f_it; + + return output; +}; + +/** + * Some Build functions. + */ + +static + MEM_SmartPtr +BuildMesh( + CSG_MeshPropertyDescriptor &props, + CSG_FaceIteratorDescriptor &face_it, + CSG_VertexIteratorDescriptor &vertex_it +) { + MEM_SmartPtr mesh = new BSP_TMesh(); + + CSG_IVertex vert; + + while (!vertex_it.Done(vertex_it.it)) { + + vertex_it.Fill(vertex_it.it,&vert); + + BSP_TVertex v; + v.m_pos = MT_Point3(vert.position); + mesh->VertexSet().push_back(v); + + vertex_it.Step(vertex_it.it); + } + + + CSG_IFace face; + + while (!face_it.Done(face_it.it)) { + face_it.Fill(face_it.it,&face); + + BSP_TFace f; + + f.m_verts[0] = face.vertex_index[0], + f.m_verts[1] = face.vertex_index[1], + f.m_verts[2] = face.vertex_index[2], + + mesh->BuildNormal(f); + + mesh->FaceSet().push_back(f); + + face_it.Step(face_it.it); + } + + return mesh; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#endif + diff --git a/intern/bsp/test/BSP_GhostTest/Makefile b/intern/bsp/test/BSP_GhostTest/Makefile new file mode 100644 index 00000000000..06dded40a17 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/Makefile @@ -0,0 +1,56 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# BSP_GhostTest Makefile +# + +LIBNAME = BSP_GhostTest +SOURCEDIR = intern/bsp/test/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I$(OPENGL_HEADERS) +CPPFLAGS += -I$(NAN_BSP)/include +CPPFLAGS += -I$(NAN_MEMUTIL)/include +CPPFLAGS += -I$(NAN_CONTAINER)/include +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I$(NAN_GHOST)/include +CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I../../extern/ + +ifeq ($(OS),windows) + CPPFLAGS += -I$(NAN_LIBDIR)/windows/glut-3.7/include +endif + + + diff --git a/intern/bsp/test/BSP_GhostTest/main.cpp b/intern/bsp/test/BSP_GhostTest/main.cpp new file mode 100644 index 00000000000..6b0e0d66234 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/main.cpp @@ -0,0 +1,151 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BSP_GhostTest3D.h" + +#include "BSP_TMesh.h" +#include "MEM_SmartPtr.h" +#include "BSP_PlyLoader.h" + +#include + +using namespace std; +#if 1 + MEM_SmartPtr +NewTestMesh( + int x, + int y, + MT_Scalar fx, + MT_Scalar fy, + MT_Scalar ampx, + MT_Scalar ampy, + MT_Scalar sx, + MT_Scalar sy +) { + + MEM_SmartPtr output = new BSP_TMesh; + + std::vector &verts = output->VertexSet(); + + int i,j; + + MT_Scalar x_scale = fx*MT_PI/x; + MT_Scalar y_scale = fy*MT_PI/y; + + MT_Scalar fsx = sx/x; + MT_Scalar fsy = sy/y; + + for (j = 0; j < y; j++) { + for (i = 0; i < x; i++) { + float z = ampx*sin(x_scale * i) + ampy*sin(y_scale * j); + + MT_Vector3 val(i*fsx - sx/2,j*fsy - sy/2,z); + + BSP_TVertex chuff; + chuff.m_pos = val; + verts.push_back(chuff); + } + } + + int poly[4]; + + for (j = 0; j < (y-1); j++) { + for (i = 0; i < (x-1); i++) { + + poly[0] = j*x + i; + poly[1] = poly[0] + 1; + poly[2] = poly[1] + y; + poly[3] = poly[2] -1; + + output->AddFace(poly,4); + } + } + + output->m_min = MT_Vector3(-sx/2,-sy/2,-ampx -ampy); + output->m_max = MT_Vector3(sx/2,sy/2,ampx + ampy); + + return output; +} +#endif + + +int main() { + + MT_Vector3 min,max; + MT_Vector3 min2,max2; + +#if 1 + MEM_SmartPtr mesh1 = BSP_PlyLoader::NewMeshFromFile("bsp_cube.ply",min,max); + MEM_SmartPtr mesh2 = BSP_PlyLoader::NewMeshFromFile("bsp_cube.ply",min2,max2); + + mesh1->m_min = min; + mesh1->m_max = max; + mesh2->m_min = min2; + mesh1->m_max = max2; + +#else + MEM_SmartPtr mesh1 = NewTestMesh(10,10,2,2,4,4,20,20); + MEM_SmartPtr mesh2 = NewTestMesh(10,10,2,2,4,4,20,20); +#endif + + if (!mesh1) { + cout << "could not load mesh!"; + return 0; + } + + + +// MEM_SmartPtr mesh2 = new BSP_TMesh(mesh1.Ref()); + + BSP_GhostTestApp3D app; + + cout << "Mesh polygons :" << mesh1->FaceSet().size() << "\n"; + cout << "Mesh vertices :" << mesh1->VertexSet().size() << "\n"; + + app.SetMesh(mesh1); + app.SetMesh(mesh2); + + + app.InitApp(); + + app.Run(); + + return 0; + +} + + + + diff --git a/intern/bsp/test/BSP_GhostTest/ply.h b/intern/bsp/test/BSP_GhostTest/ply.h new file mode 100644 index 00000000000..7947d224c5f --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/ply.h @@ -0,0 +1,200 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + +Header for PLY polygon files. + +- Greg Turk, March 1994 + +A PLY file contains a single polygonal _object_. + +An object is composed of lists of _elements_. Typical elements are +vertices, faces, edges and materials. + +Each type of element for a given object has one or more _properties_ +associated with the element type. For instance, a vertex element may +have as properties three floating-point values x,y,z and three unsigned +chars for red, green and blue. + +--------------------------------------------------------------- + +Copyright (c) 1994 The Board of Trustees of The Leland Stanford +Junior University. All rights reserved. + +Permission to use, copy, modify and distribute this software and its +documentation for any purpose is hereby granted without fee, provided +that the above copyright notice and this permission notice appear in +all copies of this software and that you do not sell the software. + +THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, +EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY +WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +*/ + +#ifndef __PLY_H__ +#define __PLY_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define PLY_ASCII 1 /* ascii PLY file */ +#define PLY_BINARY_BE 2 /* binary PLY file, big endian */ +#define PLY_BINARY_LE 3 /* binary PLY file, little endian */ + +#define PLY_OKAY 0 /* ply routine worked okay */ +#define PLY_ERROR -1 /* error in ply routine */ + +/* scalar data types supported by PLY format */ + +#define PLY_START_TYPE 0 +#define PLY_CHAR 1 +#define PLY_SHORT 2 +#define PLY_INT 3 +#define PLY_UCHAR 4 +#define PLY_USHORT 5 +#define PLY_UINT 6 +#define PLY_FLOAT 7 +#define PLY_DOUBLE 8 +#define PLY_END_TYPE 9 + +#define PLY_SCALAR 0 +#define PLY_LIST 1 + + +typedef struct PlyProperty { /* description of a property */ + + char *name; /* property name */ + int external_type; /* file's data type */ + int internal_type; /* program's data type */ + int offset; /* offset bytes of prop in a struct */ + + int is_list; /* 1 = list, 0 = scalar */ + int count_external; /* file's count type */ + int count_internal; /* program's count type */ + int count_offset; /* offset byte for list count */ + +} PlyProperty; + +typedef struct PlyElement { /* description of an element */ + char *name; /* element name */ + int num; /* number of elements in this object */ + int size; /* size of element (bytes) or -1 if variable */ + int nprops; /* number of properties for this element */ + PlyProperty **props; /* list of properties in the file */ + char *store_prop; /* flags: property wanted by user? */ + int other_offset; /* offset to un-asked-for props, or -1 if none*/ + int other_size; /* size of other_props structure */ +} PlyElement; + +typedef struct PlyOtherProp { /* describes other properties in an element */ + char *name; /* element name */ + int size; /* size of other_props */ + int nprops; /* number of properties in other_props */ + PlyProperty **props; /* list of properties in other_props */ +} PlyOtherProp; + +typedef struct OtherData { /* for storing other_props for an other element */ + void *other_props; +} OtherData; + +typedef struct OtherElem { /* data for one "other" element */ + char *elem_name; /* names of other elements */ + int elem_count; /* count of instances of each element */ + OtherData **other_data; /* actual property data for the elements */ + PlyOtherProp *other_props; /* description of the property data */ +} OtherElem; + +typedef struct PlyOtherElems { /* "other" elements, not interpreted by user */ + int num_elems; /* number of other elements */ + OtherElem *other_list; /* list of data for other elements */ +} PlyOtherElems; + +typedef struct PlyFile { /* description of PLY file */ + FILE *fp; /* file pointer */ + int file_type; /* ascii or binary */ + float version; /* version number of file */ + int nelems; /* number of elements of object */ + PlyElement **elems; /* list of elements */ + int num_comments; /* number of comments */ + char **comments; /* list of comments */ + int num_obj_info; /* number of items of object information */ + char **obj_info; /* list of object info items */ + PlyElement *which_elem; /* which element we're currently writing */ + PlyOtherElems *other_elems; /* "other" elements from a PLY file */ +} PlyFile; + +/* memory allocation */ +static char *my_alloc(); +#define myalloc(mem_size) my_alloc((mem_size), __LINE__, __FILE__) + + +/*** delcaration of routines ***/ + +extern PlyFile *ply_write(FILE *, int, char **, int); +extern PlyFile *ply_open_for_writing(char *, int, char **, int, float *); +extern void ply_describe_element(PlyFile *, char *, int, int, PlyProperty *); +extern void ply_describe_property(PlyFile *, char *, PlyProperty *); +extern void ply_element_count(PlyFile *, char *, int); +extern void ply_header_complete(PlyFile *); +extern void ply_put_element_setup(PlyFile *, char *); +extern void ply_put_element(PlyFile *, void *); +extern void ply_put_comment(PlyFile *, char *); +extern void ply_put_obj_info(PlyFile *, char *); +extern PlyFile *ply_read(FILE *, int *, char ***); +extern PlyFile *ply_open_for_reading( char *, int *, char ***, int *, float *); +extern PlyProperty **ply_get_element_description(PlyFile *, char *, int*, int*); +extern void ply_get_element_setup( PlyFile *, char *, int, PlyProperty *); +extern void ply_get_property(PlyFile *, char *, PlyProperty *); +extern PlyOtherProp *ply_get_other_properties(PlyFile *, char *, int); +extern void ply_get_element(PlyFile *, void *); +extern char **ply_get_comments(PlyFile *, int *); +extern char **ply_get_obj_info(PlyFile *, int *); +extern void ply_close(PlyFile *); +extern void ply_get_info(PlyFile *, float *, int *); +extern PlyOtherElems *ply_get_other_element (PlyFile *, char *, int); +extern void ply_describe_other_elements ( PlyFile *, PlyOtherElems *); +extern void ply_put_other_elements (PlyFile *); +extern void ply_free_other_elements (PlyOtherElems *); + +extern int equal_strings(char *, char *); + + +#ifdef __cplusplus +} +#endif +#endif /* !__PLY_H__ */ + diff --git a/intern/bsp/test/BSP_GhostTest/plyfile.c b/intern/bsp/test/BSP_GhostTest/plyfile.c new file mode 100644 index 00000000000..fd808aa0889 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/plyfile.c @@ -0,0 +1,2552 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + +The interface routines for reading and writing PLY polygon files. + +Greg Turk, February 1994 + +--------------------------------------------------------------- + +A PLY file contains a single polygonal _object_. + +An object is composed of lists of _elements_. Typical elements are +vertices, faces, edges and materials. + +Each type of element for a given object has one or more _properties_ +associated with the element type. For instance, a vertex element may +have as properties the floating-point values x,y,z and the three unsigned +chars representing red, green and blue. + +--------------------------------------------------------------- + +Copyright (c) 1994 The Board of Trustees of The Leland Stanford +Junior University. All rights reserved. + +Permission to use, copy, modify and distribute this software and its +documentation for any purpose is hereby granted without fee, provided +that the above copyright notice and this permission notice appear in +all copies of this software and that you do not sell the software. + +THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, +EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY +WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +*/ + +#include +#include +#include +#include +#include "ply.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +char *type_names[] = { +"invalid", +"char", "short", "int", +"uchar", "ushort", "uint", +"float", "double", +}; + +int ply_type_size[] = { + 0, 1, 2, 4, 1, 2, 4, 4, 8 +}; + +#define NO_OTHER_PROPS -1 + +#define DONT_STORE_PROP 0 +#define STORE_PROP 1 + +#define OTHER_PROP 0 +#define NAMED_PROP 1 + + +/* returns 1 if strings are equal, 0 if not */ +int equal_strings(char *, char *); + +/* find an element in a plyfile's list */ +PlyElement *find_element(PlyFile *, char *); + +/* find a property in an element's list */ +PlyProperty *find_property(PlyElement *, char *, int *); + +/* write to a file the word describing a PLY file data type */ +void write_scalar_type (FILE *, int); + +/* read a line from a file and break it up into separate words */ +char **get_words(FILE *, int *, char **); +char **old_get_words(FILE *, int *); + +/* write an item to a file */ +void write_binary_item(FILE *, int, unsigned int, double, int); +void write_ascii_item(FILE *, int, unsigned int, double, int); +double old_write_ascii_item(FILE *, char *, int); + +/* add information to a PLY file descriptor */ +void add_element(PlyFile *, char **); +void add_property(PlyFile *, char **); +void add_comment(PlyFile *, char *); +void add_obj_info(PlyFile *, char *); + +/* copy a property */ +void copy_property(PlyProperty *, PlyProperty *); + +/* store a value into where a pointer and a type specify */ +void store_item(char *, int, int, unsigned int, double); + +/* return the value of a stored item */ +void get_stored_item( void *, int, int *, unsigned int *, double *); + +/* return the value stored in an item, given ptr to it and its type */ +double get_item_value(char *, int); + +/* get binary or ascii item and store it according to ptr and type */ +void get_ascii_item(char *, int, int *, unsigned int *, double *); +void get_binary_item(FILE *, int, int *, unsigned int *, double *); + +/* get a bunch of elements from a file */ +void ascii_get_element(PlyFile *, char *); +void binary_get_element(PlyFile *, char *); + +/* memory allocation */ +char *my_alloc(int, int, char *); + + +/*************/ +/* Writing */ +/*************/ + + +/****************************************************************************** +Given a file pointer, get ready to write PLY data to the file. + +Entry: + fp - the given file pointer + nelems - number of elements in object + elem_names - list of element names + file_type - file type, either ascii or binary + +Exit: + returns a pointer to a PlyFile, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *ply_write( + FILE *fp, + int nelems, + char **elem_names, + int file_type +) +{ + int i; + PlyFile *plyfile; + PlyElement *elem; + + /* check for NULL file pointer */ + if (fp == NULL) + return (NULL); + + /* create a record for this object */ + + plyfile = (PlyFile *) myalloc (sizeof (PlyFile)); + plyfile->file_type = file_type; + plyfile->num_comments = 0; + plyfile->num_obj_info = 0; + plyfile->nelems = nelems; + plyfile->version = 1.0; + plyfile->fp = fp; + plyfile->other_elems = NULL; + + /* tuck aside the names of the elements */ + + plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *) * nelems); + for (i = 0; i < nelems; i++) { + elem = (PlyElement *) myalloc (sizeof (PlyElement)); + plyfile->elems[i] = elem; + elem->name = strdup (elem_names[i]); + elem->num = 0; + elem->nprops = 0; + } + + /* return pointer to the file descriptor */ + return (plyfile); +} + + +/****************************************************************************** +Open a polygon file for writing. + +Entry: + filename - name of file to read from + nelems - number of elements in object + elem_names - list of element names + file_type - file type, either ascii or binary + +Exit: + version - version number of PLY file + returns a file identifier, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *ply_open_for_writing( + char *filename, + int nelems, + char **elem_names, + int file_type, + float *version +) +{ + PlyFile *plyfile; + char *name; + FILE *fp; + + /* tack on the extension .ply, if necessary */ + + name = (char *) myalloc (sizeof (char) * (strlen (filename) + 5)); + strcpy (name, filename); + if (strlen (name) < 4 || + strcmp (name + strlen (name) - 4, ".ply") != 0) + strcat (name, ".ply"); + + /* open the file for writing */ + + fp = fopen (name, "w"); + if (fp == NULL) { + return (NULL); + } + + /* create the actual PlyFile structure */ + + plyfile = ply_write (fp, nelems, elem_names, file_type); + if (plyfile == NULL) + return (NULL); + + /* say what PLY file version number we're writing */ + *version = plyfile->version; + + /* return pointer to the file descriptor */ + return (plyfile); +} + + +/****************************************************************************** +Describe an element, including its properties and how many will be written +to the file. + +Entry: + plyfile - file identifier + elem_name - name of element that information is being specified about + nelems - number of elements of this type to be written + nprops - number of properties contained in the element + prop_list - list of properties +******************************************************************************/ + +void ply_describe_element( + PlyFile *plyfile, + char *elem_name, + int nelems, + int nprops, + PlyProperty *prop_list +) +{ + int i; + PlyElement *elem; + PlyProperty *prop; + + /* look for appropriate element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf(stderr,"ply_describe_element: can't find element '%s'\n",elem_name); + exit (-1); + } + + elem->num = nelems; + + /* copy the list of properties */ + + elem->nprops = nprops; + elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *) * nprops); + elem->store_prop = (char *) myalloc (sizeof (char) * nprops); + + for (i = 0; i < nprops; i++) { + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + elem->props[i] = prop; + elem->store_prop[i] = NAMED_PROP; + copy_property (prop, &prop_list[i]); + } +} + + +/****************************************************************************** +Describe a property of an element. + +Entry: + plyfile - file identifier + elem_name - name of element that information is being specified about + prop - the new property +******************************************************************************/ + +void ply_describe_property( + PlyFile *plyfile, + char *elem_name, + PlyProperty *prop +) +{ + PlyElement *elem; + PlyProperty *elem_prop; + + /* look for appropriate element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf(stderr, "ply_describe_property: can't find element '%s'\n", + elem_name); + return; + } + + /* create room for new property */ + + if (elem->nprops == 0) { + elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *)); + elem->store_prop = (char *) myalloc (sizeof (char)); + elem->nprops = 1; + } + else { + elem->nprops++; + elem->props = (PlyProperty **) + realloc (elem->props, sizeof (PlyProperty *) * elem->nprops); + elem->store_prop = (char *) + realloc (elem->store_prop, sizeof (char) * elem->nprops); + } + + /* copy the new property */ + + elem_prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + elem->props[elem->nprops - 1] = elem_prop; + elem->store_prop[elem->nprops - 1] = NAMED_PROP; + copy_property (elem_prop, prop); +} + + +/****************************************************************************** +Describe what the "other" properties are that are to be stored, and where +they are in an element. +******************************************************************************/ + +void ply_describe_other_properties( + PlyFile *plyfile, + PlyOtherProp *other, + int offset +) +{ + int i; + PlyElement *elem; + PlyProperty *prop; + + /* look for appropriate element */ + elem = find_element (plyfile, other->name); + if (elem == NULL) { + fprintf(stderr, "ply_describe_other_properties: can't find element '%s'\n", + other->name); + return; + } + + /* create room for other properties */ + + if (elem->nprops == 0) { + elem->props = (PlyProperty **) + myalloc (sizeof (PlyProperty *) * other->nprops); + elem->store_prop = (char *) myalloc (sizeof (char) * other->nprops); + elem->nprops = 0; + } + else { + int newsize; + newsize = elem->nprops + other->nprops; + elem->props = (PlyProperty **) + realloc (elem->props, sizeof (PlyProperty *) * newsize); + elem->store_prop = (char *) + realloc (elem->store_prop, sizeof (char) * newsize); + } + + /* copy the other properties */ + + for (i = 0; i < other->nprops; i++) { + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + copy_property (prop, other->props[i]); + elem->props[elem->nprops] = prop; + elem->store_prop[elem->nprops] = OTHER_PROP; + elem->nprops++; + } + + /* save other info about other properties */ + elem->other_size = other->size; + elem->other_offset = offset; +} + + +/****************************************************************************** +State how many of a given element will be written. + +Entry: + plyfile - file identifier + elem_name - name of element that information is being specified about + nelems - number of elements of this type to be written +******************************************************************************/ + +void ply_element_count( + PlyFile *plyfile, + char *elem_name, + int nelems +) +{ + PlyElement *elem; + + /* look for appropriate element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf(stderr,"ply_element_count: can't find element '%s'\n",elem_name); + exit (-1); + } + + elem->num = nelems; +} + + +/****************************************************************************** +Signal that we've described everything a PLY file's header and that the +header should be written to the file. + +Entry: + plyfile - file identifier +******************************************************************************/ + +void ply_header_complete(PlyFile *plyfile) +{ + int i,j; + FILE *fp = plyfile->fp; + PlyElement *elem; + PlyProperty *prop; + + fprintf (fp, "ply\n"); + + switch (plyfile->file_type) { + case PLY_ASCII: + fprintf (fp, "format ascii 1.0\n"); + break; + case PLY_BINARY_BE: + fprintf (fp, "format binary_big_endian 1.0\n"); + break; + case PLY_BINARY_LE: + fprintf (fp, "format binary_little_endian 1.0\n"); + break; + default: + fprintf (stderr, "ply_header_complete: bad file type = %d\n", + plyfile->file_type); + exit (-1); + } + + /* write out the comments */ + + for (i = 0; i < plyfile->num_comments; i++) + fprintf (fp, "comment %s\n", plyfile->comments[i]); + + /* write out object information */ + + for (i = 0; i < plyfile->num_obj_info; i++) + fprintf (fp, "obj_info %s\n", plyfile->obj_info[i]); + + /* write out information about each element */ + + for (i = 0; i < plyfile->nelems; i++) { + + elem = plyfile->elems[i]; + fprintf (fp, "element %s %d\n", elem->name, elem->num); + + /* write out each property */ + for (j = 0; j < elem->nprops; j++) { + prop = elem->props[j]; + if (prop->is_list) { + fprintf (fp, "property list "); + write_scalar_type (fp, prop->count_external); + fprintf (fp, " "); + write_scalar_type (fp, prop->external_type); + fprintf (fp, " %s\n", prop->name); + } + else { + fprintf (fp, "property "); + write_scalar_type (fp, prop->external_type); + fprintf (fp, " %s\n", prop->name); + } + } + } + + fprintf (fp, "end_header\n"); +} + + +/****************************************************************************** +Specify which elements are going to be written. This should be called +before a call to the routine ply_put_element(). + +Entry: + plyfile - file identifier + elem_name - name of element we're talking about +******************************************************************************/ + +void ply_put_element_setup(PlyFile *plyfile, char *elem_name) +{ + PlyElement *elem; + + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf(stderr, "ply_elements_setup: can't find element '%s'\n", elem_name); + exit (-1); + } + + plyfile->which_elem = elem; +} + + +/****************************************************************************** +Write an element to the file. This routine assumes that we're +writing the type of element specified in the last call to the routine +ply_put_element_setup(). + +Entry: + plyfile - file identifier + elem_ptr - pointer to the element +******************************************************************************/ + +void ply_put_element(PlyFile *plyfile, void *elem_ptr) +{ + int j,k; + FILE *fp = plyfile->fp; + PlyElement *elem; + PlyProperty *prop; + char *elem_data,*item; + char **item_ptr; + int list_count; + int item_size; + int int_val; + unsigned int uint_val; + double double_val; + char **other_ptr; + + elem = plyfile->which_elem; + elem_data = elem_ptr; + other_ptr = (char **) (((char *) elem_ptr) + elem->other_offset); + + /* write out either to an ascii or binary file */ + + if (plyfile->file_type == PLY_ASCII) { + + /* write an ascii file */ + + /* write out each property of the element */ + for (j = 0; j < elem->nprops; j++) { + prop = elem->props[j]; + if (elem->store_prop[j] == OTHER_PROP) + elem_data = *other_ptr; + else + elem_data = elem_ptr; + if (prop->is_list) { + item = elem_data + prop->count_offset; + get_stored_item ((void *) item, prop->count_internal, + &int_val, &uint_val, &double_val); + write_ascii_item (fp, int_val, uint_val, double_val, + prop->count_external); + list_count = uint_val; + item_ptr = (char **) (elem_data + prop->offset); + item = item_ptr[0]; + item_size = ply_type_size[prop->internal_type]; + for (k = 0; k < list_count; k++) { + get_stored_item ((void *) item, prop->internal_type, + &int_val, &uint_val, &double_val); + write_ascii_item (fp, int_val, uint_val, double_val, + prop->external_type); + item += item_size; + } + } + else { + item = elem_data + prop->offset; + get_stored_item ((void *) item, prop->internal_type, + &int_val, &uint_val, &double_val); + write_ascii_item (fp, int_val, uint_val, double_val, + prop->external_type); + } + } + + fprintf (fp, "\n"); + } + else { + + /* write a binary file */ + + /* write out each property of the element */ + for (j = 0; j < elem->nprops; j++) { + prop = elem->props[j]; + if (elem->store_prop[j] == OTHER_PROP) + elem_data = *other_ptr; + else + elem_data = elem_ptr; + if (prop->is_list) { + item = elem_data + prop->count_offset; + item_size = ply_type_size[prop->count_internal]; + get_stored_item ((void *) item, prop->count_internal, + &int_val, &uint_val, &double_val); + write_binary_item (fp, int_val, uint_val, double_val, + prop->count_external); + list_count = uint_val; + item_ptr = (char **) (elem_data + prop->offset); + item = item_ptr[0]; + item_size = ply_type_size[prop->internal_type]; + for (k = 0; k < list_count; k++) { + get_stored_item ((void *) item, prop->internal_type, + &int_val, &uint_val, &double_val); + write_binary_item (fp, int_val, uint_val, double_val, + prop->external_type); + item += item_size; + } + } + else { + item = elem_data + prop->offset; + item_size = ply_type_size[prop->internal_type]; + get_stored_item ((void *) item, prop->internal_type, + &int_val, &uint_val, &double_val); + write_binary_item (fp, int_val, uint_val, double_val, + prop->external_type); + } + } + + } +} + + +/****************************************************************************** +Specify a comment that will be written in the header. + +Entry: + plyfile - file identifier + comment - the comment to be written +******************************************************************************/ + +void ply_put_comment(PlyFile *plyfile, char *comment) +{ + /* (re)allocate space for new comment */ + if (plyfile->num_comments == 0) + plyfile->comments = (char **) myalloc (sizeof (char *)); + else + plyfile->comments = (char **) realloc (plyfile->comments, + sizeof (char *) * (plyfile->num_comments + 1)); + + /* add comment to list */ + plyfile->comments[plyfile->num_comments] = strdup (comment); + plyfile->num_comments++; +} + + +/****************************************************************************** +Specify a piece of object information (arbitrary text) that will be written +in the header. + +Entry: + plyfile - file identifier + obj_info - the text information to be written +******************************************************************************/ + +void ply_put_obj_info(PlyFile *plyfile, char *obj_info) +{ + /* (re)allocate space for new info */ + if (plyfile->num_obj_info == 0) + plyfile->obj_info = (char **) myalloc (sizeof (char *)); + else + plyfile->obj_info = (char **) realloc (plyfile->obj_info, + sizeof (char *) * (plyfile->num_obj_info + 1)); + + /* add info to list */ + plyfile->obj_info[plyfile->num_obj_info] = strdup (obj_info); + plyfile->num_obj_info++; +} + + + + + + + +/*************/ +/* Reading */ +/*************/ + + + +/****************************************************************************** +Given a file pointer, get ready to read PLY data from the file. + +Entry: + fp - the given file pointer + +Exit: + nelems - number of elements in object + elem_names - list of element names + returns a pointer to a PlyFile, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *ply_read(FILE *fp, int *nelems, char ***elem_names) +{ + int i,j; + PlyFile *plyfile; + int nwords; + char **words; + int found_format = 0; + char **elist; + PlyElement *elem; + char *orig_line; + + /* check for NULL file pointer */ + if (fp == NULL) + return (NULL); + + /* create record for this object */ + + plyfile = (PlyFile *) myalloc (sizeof (PlyFile)); + plyfile->nelems = 0; + plyfile->comments = NULL; + plyfile->num_comments = 0; + plyfile->obj_info = NULL; + plyfile->num_obj_info = 0; + plyfile->fp = fp; + plyfile->other_elems = NULL; + + /* read and parse the file's header */ + + words = get_words (plyfile->fp, &nwords, &orig_line); + if (!words || !equal_strings (words[0], "ply")) + return (NULL); + + while (words) { + + /* parse words */ + + if (equal_strings (words[0], "format")) { + if (nwords != 3) + return (NULL); + if (equal_strings (words[1], "ascii")) + plyfile->file_type = PLY_ASCII; + else if (equal_strings (words[1], "binary_big_endian")) + plyfile->file_type = PLY_BINARY_BE; + else if (equal_strings (words[1], "binary_little_endian")) + plyfile->file_type = PLY_BINARY_LE; + else + return (NULL); + plyfile->version = (float)atof (words[2]); + found_format = 1; + } + else if (equal_strings (words[0], "element")) + add_element (plyfile, words); + else if (equal_strings (words[0], "property")) + add_property (plyfile, words); + else if (equal_strings (words[0], "comment")) + add_comment (plyfile, orig_line); + else if (equal_strings (words[0], "obj_info")) + add_obj_info (plyfile, orig_line); + else if (equal_strings (words[0], "end_header")) + break; + + /* free up words space */ + free (words); + + words = get_words (plyfile->fp, &nwords, &orig_line); + } + + /* create tags for each property of each element, to be used */ + /* later to say whether or not to store each property for the user */ + + for (i = 0; i < plyfile->nelems; i++) { + elem = plyfile->elems[i]; + elem->store_prop = (char *) myalloc (sizeof (char) * elem->nprops); + for (j = 0; j < elem->nprops; j++) + elem->store_prop[j] = DONT_STORE_PROP; + elem->other_offset = NO_OTHER_PROPS; /* no "other" props by default */ + } + + /* set return values about the elements */ + + elist = (char **) myalloc (sizeof (char *) * plyfile->nelems); + for (i = 0; i < plyfile->nelems; i++) + elist[i] = strdup (plyfile->elems[i]->name); + + *elem_names = elist; + *nelems = plyfile->nelems; + + /* return a pointer to the file's information */ + + return (plyfile); +} + + +/****************************************************************************** +Open a polygon file for reading. + +Entry: + filename - name of file to read from + +Exit: + nelems - number of elements in object + elem_names - list of element names + file_type - file type, either ascii or binary + version - version number of PLY file + returns a file identifier, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *ply_open_for_reading( + char *filename, + int *nelems, + char ***elem_names, + int *file_type, + float *version +) +{ + FILE *fp; + PlyFile *plyfile; + char *name; + + /* tack on the extension .ply, if necessary */ + + name = (char *) myalloc (sizeof (char) * (strlen (filename) + 5)); + strcpy (name, filename); + if (strlen (name) < 4 || + strcmp (name + strlen (name) - 4, ".ply") != 0) + strcat (name, ".ply"); + + /* open the file for reading */ + + fp = fopen (name, "r"); + if (fp == NULL) + return (NULL); + + /* create the PlyFile data structure */ + + plyfile = ply_read (fp, nelems, elem_names); + + /* determine the file type and version */ + + *file_type = plyfile->file_type; + *version = plyfile->version; + + /* return a pointer to the file's information */ + + return (plyfile); +} + + +/****************************************************************************** +Get information about a particular element. + +Entry: + plyfile - file identifier + elem_name - name of element to get information about + +Exit: + nelems - number of elements of this type in the file + nprops - number of properties + returns a list of properties, or NULL if the file doesn't contain that elem +******************************************************************************/ + +PlyProperty **ply_get_element_description( + PlyFile *plyfile, + char *elem_name, + int *nelems, + int *nprops +) +{ + int i; + PlyElement *elem; + PlyProperty *prop; + PlyProperty **prop_list; + + /* find information about the element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) + return (NULL); + + *nelems = elem->num; + *nprops = elem->nprops; + + /* make a copy of the element's property list */ + prop_list = (PlyProperty **) myalloc (sizeof (PlyProperty *) * elem->nprops); + for (i = 0; i < elem->nprops; i++) { + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + copy_property (prop, elem->props[i]); + prop_list[i] = prop; + } + + /* return this duplicate property list */ + return (prop_list); +} + + +/****************************************************************************** +Specify which properties of an element are to be returned. This should be +called before a call to the routine ply_get_element(). + +Entry: + plyfile - file identifier + elem_name - which element we're talking about + nprops - number of properties + prop_list - list of properties +******************************************************************************/ + +void ply_get_element_setup( + PlyFile *plyfile, + char *elem_name, + int nprops, + PlyProperty *prop_list +) +{ + int i; + PlyElement *elem; + PlyProperty *prop; + int index; + + /* find information about the element */ + elem = find_element (plyfile, elem_name); + plyfile->which_elem = elem; + + /* deposit the property information into the element's description */ + for (i = 0; i < nprops; i++) { + + /* look for actual property */ + prop = find_property (elem, prop_list[i].name, &index); + if (prop == NULL) { + fprintf (stderr, "Warning: Can't find property '%s' in element '%s'\n", + prop_list[i].name, elem_name); + continue; + } + + /* store its description */ + prop->internal_type = prop_list[i].internal_type; + prop->offset = prop_list[i].offset; + prop->count_internal = prop_list[i].count_internal; + prop->count_offset = prop_list[i].count_offset; + + /* specify that the user wants this property */ + elem->store_prop[index] = STORE_PROP; + } +} + + +/****************************************************************************** +Specify a property of an element that is to be returned. This should be +called (usually multiple times) before a call to the routine ply_get_element(). +This routine should be used in preference to the less flexible old routine +called ply_get_element_setup(). + +Entry: + plyfile - file identifier + elem_name - which element we're talking about + prop - property to add to those that will be returned +******************************************************************************/ + +void ply_get_property( + PlyFile *plyfile, + char *elem_name, + PlyProperty *prop +) +{ + PlyElement *elem; + PlyProperty *prop_ptr; + int index; + + /* find information about the element */ + elem = find_element (plyfile, elem_name); + plyfile->which_elem = elem; + + /* deposit the property information into the element's description */ + + prop_ptr = find_property (elem, prop->name, &index); + if (prop_ptr == NULL) { + fprintf (stderr, "Warning: Can't find property '%s' in element '%s'\n", + prop->name, elem_name); + return; + } + prop_ptr->internal_type = prop->internal_type; + prop_ptr->offset = prop->offset; + prop_ptr->count_internal = prop->count_internal; + prop_ptr->count_offset = prop->count_offset; + + /* specify that the user wants this property */ + elem->store_prop[index] = STORE_PROP; +} + + +/****************************************************************************** +Read one element from the file. This routine assumes that we're reading +the type of element specified in the last call to the routine +ply_get_element_setup(). + +Entry: + plyfile - file identifier + elem_ptr - pointer to location where the element information should be put +******************************************************************************/ + +void ply_get_element(PlyFile *plyfile, void *elem_ptr) +{ + if (plyfile->file_type == PLY_ASCII) + ascii_get_element (plyfile, (char *) elem_ptr); + else + binary_get_element (plyfile, (char *) elem_ptr); +} + + +/****************************************************************************** +Extract the comments from the header information of a PLY file. + +Entry: + plyfile - file identifier + +Exit: + num_comments - number of comments returned + returns a pointer to a list of comments +******************************************************************************/ + +char **ply_get_comments(PlyFile *plyfile, int *num_comments) +{ + *num_comments = plyfile->num_comments; + return (plyfile->comments); +} + + +/****************************************************************************** +Extract the object information (arbitrary text) from the header information +of a PLY file. + +Entry: + plyfile - file identifier + +Exit: + num_obj_info - number of lines of text information returned + returns a pointer to a list of object info lines +******************************************************************************/ + +char **ply_get_obj_info(PlyFile *plyfile, int *num_obj_info) +{ + *num_obj_info = plyfile->num_obj_info; + return (plyfile->obj_info); +} + + +/****************************************************************************** +Make ready for "other" properties of an element-- those properties that +the user has not explicitly asked for, but that are to be stashed away +in a special structure to be carried along with the element's other +information. + +Entry: + plyfile - file identifier + elem - element for which we want to save away other properties +******************************************************************************/ + +void setup_other_props(PlyElement *elem) +{ + int i; + PlyProperty *prop; + int size = 0; + int type_size; + + /* Examine each property in decreasing order of size. */ + /* We do this so that all data types will be aligned by */ + /* word, half-word, or whatever within the structure. */ + + for (type_size = 8; type_size > 0; type_size /= 2) { + + /* add up the space taken by each property, and save this information */ + /* away in the property descriptor */ + + for (i = 0; i < elem->nprops; i++) { + + /* don't bother with properties we've been asked to store explicitly */ + if (elem->store_prop[i]) + continue; + + prop = elem->props[i]; + + /* internal types will be same as external */ + prop->internal_type = prop->external_type; + prop->count_internal = prop->count_external; + + /* check list case */ + if (prop->is_list) { + + /* pointer to list */ + if (type_size == sizeof (void *)) { + prop->offset = size; + size += sizeof (void *); /* always use size of a pointer here */ + } + + /* count of number of list elements */ + if (type_size == ply_type_size[prop->count_external]) { + prop->count_offset = size; + size += ply_type_size[prop->count_external]; + } + } + /* not list */ + else if (type_size == ply_type_size[prop->external_type]) { + prop->offset = size; + size += ply_type_size[prop->external_type]; + } + } + + } + + /* save the size for the other_props structure */ + elem->other_size = size; +} + + +/****************************************************************************** +Specify that we want the "other" properties of an element to be tucked +away within the user's structure. The user needn't be concerned for how +these properties are stored. + +Entry: + plyfile - file identifier + elem_name - name of element that we want to store other_props in + offset - offset to where other_props will be stored inside user's structure + +Exit: + returns pointer to structure containing description of other_props +******************************************************************************/ + +PlyOtherProp *ply_get_other_properties( + PlyFile *plyfile, + char *elem_name, + int offset +) +{ + int i; + PlyElement *elem; + PlyOtherProp *other; + PlyProperty *prop; + int nprops; + + /* find information about the element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf (stderr, "ply_get_other_properties: Can't find element '%s'\n", + elem_name); + return (NULL); + } + + /* remember that this is the "current" element */ + plyfile->which_elem = elem; + + /* save the offset to where to store the other_props */ + elem->other_offset = offset; + + /* place the appropriate pointers, etc. in the element's property list */ + setup_other_props (elem); + + /* create structure for describing other_props */ + other = (PlyOtherProp *) myalloc (sizeof (PlyOtherProp)); + other->name = strdup (elem_name); +#if 0 + if (elem->other_offset == NO_OTHER_PROPS) { + other->size = 0; + other->props = NULL; + other->nprops = 0; + return (other); + } +#endif + other->size = elem->other_size; + other->props = (PlyProperty **) myalloc (sizeof(PlyProperty) * elem->nprops); + + /* save descriptions of each "other" property */ + nprops = 0; + for (i = 0; i < elem->nprops; i++) { + if (elem->store_prop[i]) + continue; + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + copy_property (prop, elem->props[i]); + other->props[nprops] = prop; + nprops++; + } + other->nprops = nprops; + +#if 1 + /* set other_offset pointer appropriately if there are NO other properties */ + if (other->nprops == 0) { + elem->other_offset = NO_OTHER_PROPS; + } +#endif + + /* return structure */ + return (other); +} + + + + +/*************************/ +/* Other Element Stuff */ +/*************************/ + + + + +/****************************************************************************** +Grab all the data for an element that a user does not want to explicitly +read in. + +Entry: + plyfile - pointer to file + elem_name - name of element whose data is to be read in + elem_count - number of instances of this element stored in the file + +Exit: + returns pointer to ALL the "other" element data for this PLY file +******************************************************************************/ + +PlyOtherElems *ply_get_other_element ( + PlyFile *plyfile, + char *elem_name, + int elem_count +) +{ + int i; + PlyElement *elem; + PlyOtherElems *other_elems; + OtherElem *other; + + /* look for appropriate element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf (stderr, + "ply_get_other_element: can't find element '%s'\n", elem_name); + exit (-1); + } + + /* create room for the new "other" element, initializing the */ + /* other data structure if necessary */ + + if (plyfile->other_elems == NULL) { + plyfile->other_elems = (PlyOtherElems *) myalloc (sizeof (PlyOtherElems)); + other_elems = plyfile->other_elems; + other_elems->other_list = (OtherElem *) myalloc (sizeof (OtherElem)); + other = &(other_elems->other_list[0]); + other_elems->num_elems = 1; + } + else { + other_elems = plyfile->other_elems; + other_elems->other_list = (OtherElem *) realloc (other_elems->other_list, + sizeof (OtherElem) * other_elems->num_elems + 1); + other = &(other_elems->other_list[other_elems->num_elems]); + other_elems->num_elems++; + } + + /* count of element instances in file */ + other->elem_count = elem_count; + + /* save name of element */ + other->elem_name = strdup (elem_name); + + /* create a list to hold all the current elements */ + other->other_data = (OtherData **) + malloc (sizeof (OtherData *) * other->elem_count); + + /* set up for getting elements */ + other->other_props = ply_get_other_properties (plyfile, elem_name, + offsetof(OtherData,other_props)); + + /* grab all these elements */ + for (i = 0; i < other->elem_count; i++) { + /* grab and element from the file */ + other->other_data[i] = (OtherData *) malloc (sizeof (OtherData)); + ply_get_element (plyfile, (void *) other->other_data[i]); + } + + /* return pointer to the other elements data */ + return (other_elems); +} + + +/****************************************************************************** +Pass along a pointer to "other" elements that we want to save in a given +PLY file. These other elements were presumably read from another PLY file. + +Entry: + plyfile - file pointer in which to store this other element info + other_elems - info about other elements that we want to store +******************************************************************************/ + +void ply_describe_other_elements ( + PlyFile *plyfile, + PlyOtherElems *other_elems +) +{ + int i; + OtherElem *other; + + /* ignore this call if there is no other element */ + if (other_elems == NULL) + return; + + /* save pointer to this information */ + plyfile->other_elems = other_elems; + + /* describe the other properties of this element */ + + for (i = 0; i < other_elems->num_elems; i++) { + other = &(other_elems->other_list[i]); + ply_element_count (plyfile, other->elem_name, other->elem_count); + ply_describe_other_properties (plyfile, other->other_props, + offsetof(OtherData,other_props)); + } +} + + +/****************************************************************************** +Write out the "other" elements specified for this PLY file. + +Entry: + plyfile - pointer to PLY file to write out other elements for +******************************************************************************/ + +void ply_put_other_elements (PlyFile *plyfile) +{ + int i,j; + OtherElem *other; + + /* make sure we have other elements to write */ + if (plyfile->other_elems == NULL) + return; + + /* write out the data for each "other" element */ + + for (i = 0; i < plyfile->other_elems->num_elems; i++) { + + other = &(plyfile->other_elems->other_list[i]); + ply_put_element_setup (plyfile, other->elem_name); + + /* write out each instance of the current element */ + for (j = 0; j < other->elem_count; j++) + ply_put_element (plyfile, (void *) other->other_data[j]); + } +} + + +/****************************************************************************** +Free up storage used by an "other" elements data structure. + +Entry: + other_elems - data structure to free up +******************************************************************************/ + + + + +/*******************/ +/* Miscellaneous */ +/*******************/ + + + +/****************************************************************************** +Close a PLY file. + +Entry: + plyfile - identifier of file to close +******************************************************************************/ + +void ply_close(PlyFile *plyfile) +{ + fclose (plyfile->fp); + + /* free up memory associated with the PLY file */ + free (plyfile); +} + + +/****************************************************************************** +Get version number and file type of a PlyFile. + +Entry: + ply - pointer to PLY file + +Exit: + version - version of the file + file_type - PLY_ASCII, PLY_BINARY_BE, or PLY_BINARY_LE +******************************************************************************/ + +void ply_get_info(PlyFile *ply, float *version, int *file_type) +{ + if (ply == NULL) + return; + + *version = ply->version; + *file_type = ply->file_type; +} + + +/****************************************************************************** +Compare two strings. Returns 1 if they are the same, 0 if not. +******************************************************************************/ + +int equal_strings(char *s1, char *s2) +{ + + while (*s1 && *s2) + if (*s1++ != *s2++) + return (0); + + if (*s1 != *s2) + return (0); + else + return (1); +} + + +/****************************************************************************** +Find an element from the element list of a given PLY object. + +Entry: + plyfile - file id for PLY file + element - name of element we're looking for + +Exit: + returns the element, or NULL if not found +******************************************************************************/ + +PlyElement *find_element(PlyFile *plyfile, char *element) +{ + int i; + + for (i = 0; i < plyfile->nelems; i++) + if (equal_strings (element, plyfile->elems[i]->name)) + return (plyfile->elems[i]); + + return (NULL); +} + + +/****************************************************************************** +Find a property in the list of properties of a given element. + +Entry: + elem - pointer to element in which we want to find the property + prop_name - name of property to find + +Exit: + index - index to position in list + returns a pointer to the property, or NULL if not found +******************************************************************************/ + +PlyProperty *find_property(PlyElement *elem, char *prop_name, int *index) +{ + int i; + + for (i = 0; i < elem->nprops; i++) + if (equal_strings (prop_name, elem->props[i]->name)) { + *index = i; + return (elem->props[i]); + } + + *index = -1; + return (NULL); +} + + +/****************************************************************************** +Read an element from an ascii file. + +Entry: + plyfile - file identifier + elem_ptr - pointer to element +******************************************************************************/ + +void ascii_get_element(PlyFile *plyfile, char *elem_ptr) +{ + int j,k; + PlyElement *elem; + PlyProperty *prop; + char **words; + int nwords; + int which_word; + char *elem_data,*item; + char *item_ptr; + int item_size; + int int_val; + unsigned int uint_val; + double double_val; + int list_count; + int store_it; + char **store_array; + char *orig_line; + char *other_data; + int other_flag; + + other_flag = 0; + other_data = NULL; + item = NULL; + item_size = 0; + + /* the kind of element we're reading currently */ + elem = plyfile->which_elem; + + /* do we need to setup for other_props? */ + + if (elem->other_offset != NO_OTHER_PROPS) { + char **ptr; + other_flag = 1; + /* make room for other_props */ + other_data = (char *) myalloc (elem->other_size); + /* store pointer in user's structure to the other_props */ + ptr = (char **) (elem_ptr + elem->other_offset); + *ptr = other_data; + } else { + other_flag = 0; + other_data = NULL; + item = NULL; + item_size = 0; + } + + /* read in the element */ + + words = get_words (plyfile->fp, &nwords, &orig_line); + if (words == NULL) { + fprintf (stderr, "ply_get_element: unexpected end of file\n"); + exit (-1); + } + + which_word = 0; + + for (j = 0; j < elem->nprops; j++) { + + prop = elem->props[j]; + store_it = (elem->store_prop[j] | other_flag); + + /* store either in the user's structure or in other_props */ + if (elem->store_prop[j]) + elem_data = elem_ptr; + else + elem_data = other_data; + + if (prop->is_list) { /* a list */ + + /* get and store the number of items in the list */ + get_ascii_item (words[which_word++], prop->count_external, + &int_val, &uint_val, &double_val); + if (store_it) { + item = elem_data + prop->count_offset; + store_item(item, prop->count_internal, int_val, uint_val, double_val); + } + + /* allocate space for an array of items and store a ptr to the array */ + list_count = int_val; + item_size = ply_type_size[prop->internal_type]; + store_array = (char **) (elem_data + prop->offset); + + if (list_count == 0) { + if (store_it) + *store_array = NULL; + } + else { + if (store_it) { + item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count); + item = item_ptr; + *store_array = item_ptr; + } + + /* read items and store them into the array */ + for (k = 0; k < list_count; k++) { + get_ascii_item (words[which_word++], prop->external_type, + &int_val, &uint_val, &double_val); + if (store_it) { + store_item (item, prop->internal_type, + int_val, uint_val, double_val); + item += item_size; + } + } + } + + } + else { /* not a list */ + get_ascii_item (words[which_word++], prop->external_type, + &int_val, &uint_val, &double_val); + if (store_it) { + item = elem_data + prop->offset; + store_item (item, prop->internal_type, int_val, uint_val, double_val); + } + } + + } + + free (words); +} + + +/****************************************************************************** +Read an element from a binary file. + +Entry: + plyfile - file identifier + elem_ptr - pointer to an element +******************************************************************************/ + +void binary_get_element(PlyFile *plyfile, char *elem_ptr) +{ + int j,k; + PlyElement *elem; + PlyProperty *prop; + FILE *fp = plyfile->fp; + char *elem_data,*item; + char *item_ptr; + int item_size; + int int_val; + unsigned int uint_val; + double double_val; + int list_count; + int store_it; + char **store_array; + char *other_data; + int other_flag; + + + other_flag = 0; + other_data = NULL; + item = NULL; + item_size = 0; + + /* the kind of element we're reading currently */ + elem = plyfile->which_elem; + + /* do we need to setup for other_props? */ + + if (elem->other_offset != NO_OTHER_PROPS) { + char **ptr; + other_flag = 1; + /* make room for other_props */ + other_data = (char *) myalloc (elem->other_size); + /* store pointer in user's structure to the other_props */ + ptr = (char **) (elem_ptr + elem->other_offset); + *ptr = other_data; + } + else { + other_flag = 0; + other_data = NULL; + item = NULL; + item_size = 0; + } + /* read in a number of elements */ + + for (j = 0; j < elem->nprops; j++) { + + prop = elem->props[j]; + store_it = (elem->store_prop[j] | other_flag); + + /* store either in the user's structure or in other_props */ + if (elem->store_prop[j]) + elem_data = elem_ptr; + else + elem_data = other_data; + + if (prop->is_list) { /* a list */ + + /* get and store the number of items in the list */ + get_binary_item (fp, prop->count_external, + &int_val, &uint_val, &double_val); + if (store_it) { + item = elem_data + prop->count_offset; + store_item(item, prop->count_internal, int_val, uint_val, double_val); + } + + /* allocate space for an array of items and store a ptr to the array */ + list_count = int_val; + /* The "if" was added by Afra Zomorodian 8/22/95 + * so that zipper won't crash reading plies that have additional + * properties. + */ + if (store_it) { + item_size = ply_type_size[prop->internal_type]; + } + store_array = (char **) (elem_data + prop->offset); + if (list_count == 0) { + if (store_it) + *store_array = NULL; + } + else { + if (store_it) { + item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count); + item = item_ptr; + *store_array = item_ptr; + } + + /* read items and store them into the array */ + for (k = 0; k < list_count; k++) { + get_binary_item (fp, prop->external_type, + &int_val, &uint_val, &double_val); + if (store_it) { + store_item (item, prop->internal_type, + int_val, uint_val, double_val); + item += item_size; + } + } + } + + } + else { /* not a list */ + get_binary_item (fp, prop->external_type, + &int_val, &uint_val, &double_val); + if (store_it) { + item = elem_data + prop->offset; + store_item (item, prop->internal_type, int_val, uint_val, double_val); + } + } + + } +} + + +/****************************************************************************** +Write to a file the word that represents a PLY data type. + +Entry: + fp - file pointer + code - code for type +******************************************************************************/ + +void write_scalar_type (FILE *fp, int code) +{ + /* make sure this is a valid code */ + + if (code <= PLY_START_TYPE || code >= PLY_END_TYPE) { + fprintf (stderr, "write_scalar_type: bad data code = %d\n", code); + exit (-1); + } + + /* write the code to a file */ + + fprintf (fp, "%s", type_names[code]); +} + + +/****************************************************************************** +Get a text line from a file and break it up into words. + +IMPORTANT: The calling routine call "free" on the returned pointer once +finished with it. + +Entry: + fp - file to read from + +Exit: + nwords - number of words returned + orig_line - the original line of characters + returns a list of words from the line, or NULL if end-of-file +******************************************************************************/ + +char **get_words(FILE *fp, int *nwords, char **orig_line) +{ +#define BIG_STRING 4096 + static char str[BIG_STRING]; + static char str_copy[BIG_STRING]; + char **words; + int max_words = 10; + int num_words = 0; + char *ptr,*ptr2; + char *result; + + words = (char **) myalloc (sizeof (char *) * max_words); + + /* read in a line */ + result = fgets (str, BIG_STRING, fp); + if (result == NULL) { + *nwords = 0; + *orig_line = NULL; + return (NULL); + } + + /* convert line-feed and tabs into spaces */ + /* (this guarentees that there will be a space before the */ + /* null character at the end of the string) */ + + str[BIG_STRING-2] = ' '; + str[BIG_STRING-1] = '\0'; + + for (ptr = str, ptr2 = str_copy; *ptr != '\0'; ptr++, ptr2++) { + *ptr2 = *ptr; + if (*ptr == '\t') { + *ptr = ' '; + *ptr2 = ' '; + } + else if (*ptr == '\n') { + *ptr = ' '; + *ptr2 = '\0'; + break; + } + } + + /* find the words in the line */ + + ptr = str; + while (*ptr != '\0') { + + /* jump over leading spaces */ + while (*ptr == ' ') + ptr++; + + /* break if we reach the end */ + if (*ptr == '\0') + break; + + /* save pointer to beginning of word */ + if (num_words >= max_words) { + max_words += 10; + words = (char **) realloc (words, sizeof (char *) * max_words); + } + words[num_words++] = ptr; + + /* jump over non-spaces */ + while (*ptr != ' ') + ptr++; + + /* place a null character here to mark the end of the word */ + *ptr++ = '\0'; + } + + /* return the list of words */ + *nwords = num_words; + *orig_line = str_copy; + return (words); +} + + +/****************************************************************************** +Return the value of an item, given a pointer to it and its type. + +Entry: + item - pointer to item + type - data type that "item" points to + +Exit: + returns a double-precision float that contains the value of the item +******************************************************************************/ + +double get_item_value(char *item, int type) +{ + unsigned char *puchar; + char *pchar; + short int *pshort; + unsigned short int *pushort; + int *pint; + unsigned int *puint; + float *pfloat; + double *pdouble; + int int_value; + unsigned int uint_value; + double double_value; + + switch (type) { + case PLY_CHAR: + pchar = (char *) item; + int_value = *pchar; + return ((double) int_value); + case PLY_UCHAR: + puchar = (unsigned char *) item; + int_value = *puchar; + return ((double) int_value); + case PLY_SHORT: + pshort = (short int *) item; + int_value = *pshort; + return ((double) int_value); + case PLY_USHORT: + pushort = (unsigned short int *) item; + int_value = *pushort; + return ((double) int_value); + case PLY_INT: + pint = (int *) item; + int_value = *pint; + return ((double) int_value); + case PLY_UINT: + puint = (unsigned int *) item; + uint_value = *puint; + return ((double) uint_value); + case PLY_FLOAT: + pfloat = (float *) item; + double_value = *pfloat; + return (double_value); + case PLY_DOUBLE: + pdouble = (double *) item; + double_value = *pdouble; + return (double_value); + default: + fprintf (stderr, "get_item_value: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Write out an item to a file as raw binary bytes. + +Entry: + fp - file to write to + int_val - integer version of item + uint_val - unsigned integer version of item + double_val - double-precision float version of item + type - data type to write out +******************************************************************************/ + +void write_binary_item( + FILE *fp, + int int_val, + unsigned int uint_val, + double double_val, + int type +) +{ + unsigned char uchar_val; + char char_val; + unsigned short ushort_val; + short short_val; + float float_val; + + switch (type) { + case PLY_CHAR: + char_val = (char)int_val; + fwrite (&char_val, 1, 1, fp); + break; + case PLY_SHORT: + short_val = (short)int_val; + fwrite (&short_val, 2, 1, fp); + break; + case PLY_INT: + fwrite (&int_val, 4, 1, fp); + break; + case PLY_UCHAR: + uchar_val = (unsigned char) uint_val; + fwrite (&uchar_val, 1, 1, fp); + break; + case PLY_USHORT: + ushort_val = (unsigned short)uint_val; + fwrite (&ushort_val, 2, 1, fp); + break; + case PLY_UINT: + fwrite (&uint_val, 4, 1, fp); + break; + case PLY_FLOAT: + float_val = (float) double_val; + fwrite (&float_val, 4, 1, fp); + break; + case PLY_DOUBLE: + fwrite (&double_val, 8, 1, fp); + break; + default: + fprintf (stderr, "write_binary_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Write out an item to a file as ascii characters. + +Entry: + fp - file to write to + int_val - integer version of item + uint_val - unsigned integer version of item + double_val - double-precision float version of item + type - data type to write out +******************************************************************************/ + +void write_ascii_item( + FILE *fp, + int int_val, + unsigned int uint_val, + double double_val, + int type +) +{ + switch (type) { + case PLY_CHAR: + case PLY_SHORT: + case PLY_INT: + fprintf (fp, "%d ", int_val); + break; + case PLY_UCHAR: + case PLY_USHORT: + case PLY_UINT: + fprintf (fp, "%u ", uint_val); + break; + case PLY_FLOAT: + case PLY_DOUBLE: + fprintf (fp, "%g ", double_val); + break; + default: + fprintf (stderr, "write_ascii_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Write out an item to a file as ascii characters. + +Entry: + fp - file to write to + item - pointer to item to write + type - data type that "item" points to + +Exit: + returns a double-precision float that contains the value of the written item +******************************************************************************/ + +double old_write_ascii_item(FILE *fp, char *item, int type) +{ + unsigned char *puchar; + char *pchar; + short int *pshort; + unsigned short int *pushort; + int *pint; + unsigned int *puint; + float *pfloat; + double *pdouble; + int int_value; + unsigned int uint_value; + double double_value; + + switch (type) { + case PLY_CHAR: + pchar = (char *) item; + int_value = *pchar; + fprintf (fp, "%d ", int_value); + return ((double) int_value); + case PLY_UCHAR: + puchar = (unsigned char *) item; + int_value = *puchar; + fprintf (fp, "%d ", int_value); + return ((double) int_value); + case PLY_SHORT: + pshort = (short int *) item; + int_value = *pshort; + fprintf (fp, "%d ", int_value); + return ((double) int_value); + case PLY_USHORT: + pushort = (unsigned short int *) item; + int_value = *pushort; + fprintf (fp, "%d ", int_value); + return ((double) int_value); + case PLY_INT: + pint = (int *) item; + int_value = *pint; + fprintf (fp, "%d ", int_value); + return ((double) int_value); + case PLY_UINT: + puint = (unsigned int *) item; + uint_value = *puint; + fprintf (fp, "%u ", uint_value); + return ((double) uint_value); + case PLY_FLOAT: + pfloat = (float *) item; + double_value = *pfloat; + fprintf (fp, "%g ", double_value); + return (double_value); + case PLY_DOUBLE: + pdouble = (double *) item; + double_value = *pdouble; + fprintf (fp, "%g ", double_value); + return (double_value); + default: + fprintf (stderr, "old_write_ascii_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Get the value of an item that is in memory, and place the result +into an integer, an unsigned integer and a double. + +Entry: + ptr - pointer to the item + type - data type supposedly in the item + +Exit: + int_val - integer value + uint_val - unsigned integer value + double_val - double-precision floating point value +******************************************************************************/ + +void get_stored_item( + void *ptr, + int type, + int *int_val, + unsigned int *uint_val, + double *double_val +) +{ + switch (type) { + case PLY_CHAR: + *int_val = *((char *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case PLY_UCHAR: + *uint_val = *((unsigned char *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case PLY_SHORT: + *int_val = *((short int *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case PLY_USHORT: + *uint_val = *((unsigned short int *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case PLY_INT: + *int_val = *((int *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case PLY_UINT: + *uint_val = *((unsigned int *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case PLY_FLOAT: + *double_val = *((float *) ptr); + *int_val = (int)*double_val; + *uint_val = (unsigned int)*double_val; + break; + case PLY_DOUBLE: + *double_val = *((double *) ptr); + *int_val = (int)*double_val; + *uint_val =(unsigned int) *double_val; + break; + default: + fprintf (stderr, "get_stored_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Get the value of an item from a binary file, and place the result +into an integer, an unsigned integer and a double. + +Entry: + fp - file to get item from + type - data type supposedly in the word + +Exit: + int_val - integer value + uint_val - unsigned integer value + double_val - double-precision floating point value +******************************************************************************/ + +void get_binary_item( + FILE *fp, + int type, + int *int_val, + unsigned int *uint_val, + double *double_val +) +{ + char c[8]; + void *ptr; + + ptr = (void *) c; + + switch (type) { + case PLY_CHAR: + fread (ptr, 1, 1, fp); + *int_val = *((char *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case PLY_UCHAR: + fread (ptr, 1, 1, fp); + *uint_val = *((unsigned char *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case PLY_SHORT: + fread (ptr, 2, 1, fp); + *int_val = *((short int *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case PLY_USHORT: + fread (ptr, 2, 1, fp); + *uint_val = *((unsigned short int *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case PLY_INT: + fread (ptr, 4, 1, fp); + *int_val = *((int *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case PLY_UINT: + fread (ptr, 4, 1, fp); + *uint_val = *((unsigned int *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case PLY_FLOAT: + fread (ptr, 4, 1, fp); + *double_val = *((float *) ptr); + *int_val = (int)*double_val; + *uint_val =(unsigned int) *double_val; + break; + case PLY_DOUBLE: + fread (ptr, 8, 1, fp); + *double_val = *((double *) ptr); + *int_val = (int)*double_val; + *uint_val = (unsigned int)*double_val; + break; + default: + fprintf (stderr, "get_binary_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Extract the value of an item from an ascii word, and place the result +into an integer, an unsigned integer and a double. + +Entry: + word - word to extract value from + type - data type supposedly in the word + +Exit: + int_val - integer value + uint_val - unsigned integer value + double_val - double-precision floating point value +******************************************************************************/ + +void get_ascii_item( + char *word, + int type, + int *int_val, + unsigned int *uint_val, + double *double_val +) +{ + switch (type) { + case PLY_CHAR: + case PLY_UCHAR: + case PLY_SHORT: + case PLY_USHORT: + case PLY_INT: + *int_val = atoi (word); + *uint_val = *int_val; + *double_val = *int_val; + break; + + case PLY_UINT: + *uint_val = strtoul (word, (char **) NULL, 10); + *int_val = *uint_val; + *double_val = *uint_val; + break; + + case PLY_FLOAT: + case PLY_DOUBLE: + *double_val = atof (word); + *int_val = (int) *double_val; + *uint_val = (unsigned int) *double_val; + break; + + default: + fprintf (stderr, "get_ascii_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Store a value into a place being pointed to, guided by a data type. + +Entry: + item - place to store value + type - data type + int_val - integer version of value + uint_val - unsigned integer version of value + double_val - double version of value + +Exit: + item - pointer to stored value +******************************************************************************/ + +void store_item ( + char *item, + int type, + int int_val, + unsigned int uint_val, + double double_val +) +{ + unsigned char *puchar; + short int *pshort; + unsigned short int *pushort; + int *pint; + unsigned int *puint; + float *pfloat; + double *pdouble; + + switch (type) { + case PLY_CHAR: + *item = (char) int_val; + break; + case PLY_UCHAR: + puchar = (unsigned char *) item; + *puchar = (unsigned char)uint_val; + break; + case PLY_SHORT: + pshort = (short *) item; + *pshort = (short)int_val; + break; + case PLY_USHORT: + pushort = (unsigned short *) item; + *pushort = (unsigned short)uint_val; + break; + case PLY_INT: + pint = (int *) item; + *pint = int_val; + break; + case PLY_UINT: + puint = (unsigned int *) item; + *puint = uint_val; + break; + case PLY_FLOAT: + pfloat = (float *) item; + *pfloat = (float)double_val; + break; + case PLY_DOUBLE: + pdouble = (double *) item; + *pdouble = double_val; + break; + default: + fprintf (stderr, "store_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Add an element to a PLY file descriptor. + +Entry: + plyfile - PLY file descriptor + words - list of words describing the element + nwords - number of words in the list +******************************************************************************/ + +void add_element (PlyFile *plyfile, char **words) +{ + PlyElement *elem; + + /* create the new element */ + elem = (PlyElement *) myalloc (sizeof (PlyElement)); + elem->name = strdup (words[1]); + elem->num = atoi (words[2]); + elem->nprops = 0; + + /* make room for new element in the object's list of elements */ + if (plyfile->nelems == 0) + plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *)); + else + plyfile->elems = (PlyElement **) realloc (plyfile->elems, + sizeof (PlyElement *) * (plyfile->nelems + 1)); + + /* add the new element to the object's list */ + plyfile->elems[plyfile->nelems] = elem; + plyfile->nelems++; +} + + +/****************************************************************************** +Return the type of a property, given the name of the property. + +Entry: + name - name of property type + +Exit: + returns integer code for property, or 0 if not found +******************************************************************************/ + +int get_prop_type(char *type_name) +{ + int i; + + for (i = PLY_START_TYPE + 1; i < PLY_END_TYPE; i++) + if (equal_strings (type_name, type_names[i])) + return (i); + + /* if we get here, we didn't find the type */ + return (0); +} + + +/****************************************************************************** +Add a property to a PLY file descriptor. + +Entry: + plyfile - PLY file descriptor + words - list of words describing the property + nwords - number of words in the list +******************************************************************************/ + +void add_property (PlyFile *plyfile, char **words) +{ + PlyProperty *prop; + PlyElement *elem; + + /* create the new property */ + + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + + if (equal_strings (words[1], "list")) { /* is a list */ + prop->count_external = get_prop_type (words[2]); + prop->external_type = get_prop_type (words[3]); + prop->name = strdup (words[4]); + prop->is_list = 1; + } + else { /* not a list */ + prop->external_type = get_prop_type (words[1]); + prop->name = strdup (words[2]); + prop->is_list = 0; + } + + /* add this property to the list of properties of the current element */ + + elem = plyfile->elems[plyfile->nelems - 1]; + + if (elem->nprops == 0) + elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *)); + else + elem->props = (PlyProperty **) realloc (elem->props, + sizeof (PlyProperty *) * (elem->nprops + 1)); + + elem->props[elem->nprops] = prop; + elem->nprops++; +} + + +/****************************************************************************** +Add a comment to a PLY file descriptor. + +Entry: + plyfile - PLY file descriptor + line - line containing comment +******************************************************************************/ + +void add_comment (PlyFile *plyfile, char *line) +{ + int i; + + /* skip over "comment" and leading spaces and tabs */ + i = 7; + while (line[i] == ' ' || line[i] == '\t') + i++; + + ply_put_comment (plyfile, &line[i]); +} + + +/****************************************************************************** +Add a some object information to a PLY file descriptor. + +Entry: + plyfile - PLY file descriptor + line - line containing text info +******************************************************************************/ + +void add_obj_info (PlyFile *plyfile, char *line) +{ + int i; + + /* skip over "obj_info" and leading spaces and tabs */ + i = 8; + while (line[i] == ' ' || line[i] == '\t') + i++; + + ply_put_obj_info (plyfile, &line[i]); +} + + +/****************************************************************************** +Copy a property. +******************************************************************************/ + +void copy_property(PlyProperty *dest, PlyProperty *src) +{ + dest->name = strdup (src->name); + dest->external_type = src->external_type; + dest->internal_type = src->internal_type; + dest->offset = src->offset; + + dest->is_list = src->is_list; + dest->count_external = src->count_external; + dest->count_internal = src->count_internal; + dest->count_offset = src->count_offset; +} + + +/****************************************************************************** +Allocate some memory. + +Entry: + size - amount of memory requested (in bytes) + lnum - line number from which memory was requested + fname - file name from which memory was requested +******************************************************************************/ + +static char *my_alloc(int size, int lnum, char *fname) +{ + char *ptr; + + ptr = (char *) malloc (size); + + if (ptr == 0) { + fprintf(stderr, "Memory allocation bombed on line %d in %s\n", lnum, fname); + } + + return (ptr); +} + diff --git a/intern/bsp/test/Makefile b/intern/bsp/test/Makefile new file mode 100644 index 00000000000..17ed638d745 --- /dev/null +++ b/intern/bsp/test/Makefile @@ -0,0 +1,72 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# bsp test makefile. +# + +LIBNAME = bsp +SOURCEDIR = intern/$(LIBNAME)/test +DIR = $(OCGDIR)/$(SOURCEDIR) + +include nan_compile.mk + +DIRS = BSP_GhostTest + +include nan_subdirs.mk + +include nan_link.mk + +LIBS = $(OCGDIR)/intern/$(LIBNAME)/test/BSP_GhostTest/$(DEBUG_DIR)libBSP_GhostTest.a +LIBS += $(OCGDIR)/intern/$(LIBNAME)/$(DEBUG_DIR)libbsp.a + +SLIBS += $(NAN_MOTO)/lib/$(DEBUG_DIR)libmoto.a +SLIBS += $(NAN_GHOST)/lib/$(DEBUG_DIR)libghost.a +SLIBS += $(NAN_STRING)/lib/$(DEBUG_DIR)libstring.a + +ifeq ($(OS),$(findstring $(OS), "beos darwin linux freebsd openbsd")) + LLIBS = -L/usr/X11R6/lib -lglut -pthread -lXi -lXmu +endif + +all debug:: $(LIBS) $(DIR)/$(DEBUG_DIR)BSPGhostTest + +$(DIR)/$(DEBUG_DIR)BSPGhostTest: + @echo "****> linking $@ in $(DIR)" + $(CCC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)BSPGhostTest $(LIBS) $(SLIBS) $(LLIBS) $(DADD) + +clean:: + $(RM) $(DIR)/BSPGhostTest $(DIR)/debug/BSPGhostTest + +test:: all + $(DIR)/BSPGhostTest + + + + + diff --git a/intern/container/CMakeLists.txt b/intern/container/CMakeLists.txt new file mode 100644 index 00000000000..497a7355edf --- /dev/null +++ b/intern/container/CMakeLists.txt @@ -0,0 +1,35 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC .) + +FILE(GLOB SRC intern/*.cpp) + +BLENDERLIB(blender_CTR "${SRC}" "${INC}") +#, libtype=['intern'], priority = 10 ) diff --git a/intern/container/CTR_List.h b/intern/container/CTR_List.h new file mode 100644 index 00000000000..2ca2d60d0e7 --- /dev/null +++ b/intern/container/CTR_List.h @@ -0,0 +1,142 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + + +#ifndef CTR_LIST_H +#define CTR_LIST_H + +class CTR_Link { +public: + CTR_Link( + ) ; + + CTR_Link( + CTR_Link *next, + CTR_Link *prev + ) ; + + CTR_Link * + getNext( + ) const ; + + CTR_Link * + getPrev( + ) const ; + + bool + isHead( + ) const ; + + bool + isTail( + ) const ; + + void + insertBefore( + CTR_Link *link + ) ; + + void + insertAfter( + CTR_Link *link + ) ; + + void + remove( + ) ; + +private: + CTR_Link *m_next; + CTR_Link *m_prev; +}; + +class CTR_List { +public: + + CTR_List( + ) ; + + CTR_Link * + getHead( + ) const ; + + CTR_Link * + getTail( + ) const ; + + void + addHead( + CTR_Link *link + ) ; + + void + addTail( + CTR_Link *link + ) ; + +private: + CTR_Link m_head; + CTR_Link m_tail; +}; + +#endif + diff --git a/intern/container/CTR_Map.h b/intern/container/CTR_Map.h new file mode 100644 index 00000000000..8329337479b --- /dev/null +++ b/intern/container/CTR_Map.h @@ -0,0 +1,149 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef CTR_MAP_H +#define CTR_MAP_H + +template +class CTR_Map { +private: + struct Entry { + Entry (Entry *next, Key key, Value value) : + m_next(next), + m_key(key), + m_value(value) {} + + Entry *m_next; + Key m_key; + Value m_value; + }; + +public: + CTR_Map(int num_buckets = 100) : m_num_buckets(num_buckets) { + m_buckets = new Entry *[num_buckets]; + for (int i = 0; i < num_buckets; ++i) { + m_buckets[i] = 0; + } + } + + int size() { + int count=0; + for (int i=0;im_next; + count++; + } + } + return count; + } + + Value* at(int index) { + int count=0; + for (int i=0;im_value; + } + bucket = bucket->m_next; + count++; + } + } + return 0; + } + + void clear() { + for (int i = 0; i < m_num_buckets; ++i) { + Entry *entry_ptr = m_buckets[i]; + + while (entry_ptr != 0) { + Entry *tmp_ptr = entry_ptr->m_next; + delete entry_ptr; + entry_ptr = tmp_ptr; + } + m_buckets[i] = 0; + } + } + + ~CTR_Map() { + clear(); + delete [] m_buckets; + } + + void insert(const Key& key, const Value& value) { + Entry *entry_ptr = m_buckets[key.hash() % m_num_buckets]; + while ((entry_ptr != 0) && !(key == entry_ptr->m_key)) { + entry_ptr = entry_ptr->m_next; + } + + if (entry_ptr != 0) { + entry_ptr->m_value = value; + } + else { + Entry **bucket = &m_buckets[key.hash() % m_num_buckets]; + *bucket = new Entry(*bucket, key, value); + } + } + + void remove(const Key& key) { + Entry **entry_ptr = &m_buckets[key.hash() % m_num_buckets]; + while ((*entry_ptr != 0) && !(key == (*entry_ptr)->m_key)) { + entry_ptr = &(*entry_ptr)->m_next; + } + + if (*entry_ptr != 0) { + Entry *tmp_ptr = (*entry_ptr)->m_next; + delete *entry_ptr; + *entry_ptr = tmp_ptr; + } + } + + Value *operator[](Key key) { + Entry *bucket = m_buckets[key.hash() % m_num_buckets]; + while ((bucket != 0) && !(key == bucket->m_key)) { + bucket = bucket->m_next; + } + return bucket != 0 ? &bucket->m_value : 0; + } + +private: + int m_num_buckets; + Entry **m_buckets; +}; + +#endif + diff --git a/intern/container/CTR_TaggedIndex.h b/intern/container/CTR_TaggedIndex.h new file mode 100644 index 00000000000..87bc8a4315e --- /dev/null +++ b/intern/container/CTR_TaggedIndex.h @@ -0,0 +1,201 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * Simple tagged index class. + */ + +#ifndef NAN_INCLUDED_CTR_TaggedIndex_h +#define NAN_INCLUDED_CTR_TaggedIndex_h + +/** + * This class is supposed to be a simple tagged index class. If these + * were indices into a mesh then we would never need 32 bits for such indices. + * It is often handy to have a few extra bits around to mark objects etc. We + * steal a few bits of CTR_TaggedIndex objects for this purpose. From the outside + * it will behave like a standard unsigned int but just carry the extra tag + * information around with it. + */ + +#include + +enum { + + empty_tag = 0x0, + empty_index = 0xffffffff +}; + +template < + int tag_shift, + int index_mask +> class CTR_TaggedIndex { +public: + CTR_TaggedIndex( + ) : + m_val ((empty_tag << tag_shift) | (empty_index & index_mask)) + { + } + + CTR_TaggedIndex( + const int val + ) : + m_val ((val & index_mask) | ((empty_tag << tag_shift) & (~index_mask))) { + } + + CTR_TaggedIndex( + const unsigned int val + ) : + m_val ((val & index_mask) | ((empty_tag << tag_shift) & (~index_mask))) { + } + + CTR_TaggedIndex( + const long int val + ) : + m_val ( ((long int) val & index_mask) + | ( (empty_tag << tag_shift) + & (~index_mask)) ) { + } + + CTR_TaggedIndex( + const long unsigned int val + ) : + m_val ( ((long unsigned int)val & index_mask) + | ( (empty_tag << tag_shift) + & (~index_mask) ) ) { + } + + + CTR_TaggedIndex( + const CTR_TaggedIndex &my_index + ): + m_val(my_index.m_val) + { + } + + bool + operator == ( + const CTR_TaggedIndex& rhs + ) const { + + return ((this->m_val & index_mask) == (rhs.m_val & index_mask)); + } + + operator unsigned int () const { + return m_val & index_mask; + } + + operator unsigned long int () const { + return (unsigned long int)(m_val & index_mask); + } + + operator int () const { + return int(m_val & index_mask); + } + + operator long int () const { + return (long int)(m_val & index_mask); + } + + bool + IsEmpty( + ) const { + return ((m_val & index_mask) == (empty_index & index_mask)); + } + + + static + CTR_TaggedIndex + Empty( + ) { + return CTR_TaggedIndex(); + } + + void + Invalidate( + ) { + m_val = (empty_tag << tag_shift) | (empty_index & index_mask); + } + + + unsigned int + Tag ( + ) const { + return m_val >> tag_shift; + } + + void + SetTag( + unsigned int tag + ) { + m_val = (m_val & index_mask) | ((tag << tag_shift) & (~index_mask)); + } + + void + EmptyTag( + ) { + m_val = (m_val & index_mask) | ((empty_tag << tag_shift) & (~index_mask)); + } + + bool + IsEmptyTag( + ) const { + return (Tag() == Empty().Tag()); + } + + // functionals + + struct greater : std::binary_function + { + bool + operator()( + const CTR_TaggedIndex& a, + const CTR_TaggedIndex& b + ) const { + return (int(a) > int(b)); + } + }; + + +private : + CTR_TaggedIndex( + const CTR_TaggedIndex *index + ) {}; + + unsigned int m_val; + + +}; + +#endif + diff --git a/intern/container/CTR_TaggedSetOps.h b/intern/container/CTR_TaggedSetOps.h new file mode 100644 index 00000000000..0a0367ec673 --- /dev/null +++ b/intern/container/CTR_TaggedSetOps.h @@ -0,0 +1,300 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_LOD_TaggedSetOps_h +#define NAN_INCLUDED_LOD_TaggedSetOps_h + +#include "MEM_NonCopyable.h" +#include + +/** + * This class contains some utility functions for finding the intersection, + * union, and difference of a collection of stl vector of indices into + * a set of primitives. + * + * These are mainly used as helper functions in the decimation and bsp + * libraries. + * + * This template class assumes that each value of type IndexType encountered + * in the list is a valid index into an array of primitives. This is not + * checked at run-time and is left to the user to insure. Prmitives of + * type ObjectType must have the following public methods to be used by + * this template class: + * + * int + * OpenTag(void) --- return a persistent tag value for the primitive + * + * void + * SetOpenTag(int bla) --- set the persistent tag value for this primitive to bla. + * + * bool + * SelectTag() --- return a persistent boolean tag for this primitive + * + * void + * SetSelectTag(bool bla) --- set the persistent boolean tag for this primitive to bla. + * + * Here persistent means that the tag should be associated with the object for the + * entire lifetime of the primitive. Again none of this stuff is enforced you have + * to make sure that your primitives do the right thing. Often these tags can be + * cunningly stowed away inside some of the spare bits in the primitive. See + * CTR_TaggedIndex for such a class. + * + */ + +template + +class CTR_TaggedSetOps : public MEM_NonCopyable { + +public : + + static + void + Intersect( + const std::vector< std::vector > &index_list, + std::vector &primitives, + std::vector &output, + unsigned int mask, + unsigned int shift + ) { + + // iterate through vectors in index_list + // iterate through individual members of each vector + // mark each obejct that the index points to + + typename std::vector< std::vector >::const_iterator + last_vector = index_list.end(); + typename std::vector< std::vector >::const_iterator + start_vector = index_list.begin(); + + // FIXME some temporary space + + std::vector temp_union; + temp_union.reserve(64); + + int tag_num = 0; + + for (; start_vector != last_vector; ++start_vector) { + + typename std::vector::const_iterator + last_index = start_vector->end(); + typename std::vector::const_iterator + start_index = start_vector->begin(); + + for (; start_index != last_index; ++start_index) { + + ObjectType & prim = primitives[*start_index]; + + if (!prim.OpenTag()) { + // compute the union + temp_union.push_back(*start_index); + } + int tag = prim.OpenTag(); + tag = (tag & mask) >> shift; + tag += 1; + prim.SetOpenTag((prim.OpenTag() & ~mask)| ((tag << shift) & mask)); + } + + ++tag_num; + } + + // now iterate through the union and pull out all those with the right tag + + typename std::vector::const_iterator last_index = + temp_union.end(); + typename std::vector::const_iterator start_index = + temp_union.begin(); + + for (; start_index != last_index; ++start_index) { + + ObjectType & prim = primitives[*start_index]; + + if (prim.OpenTag() == tag_num) { + //it's part of the intersection! + + output.push_back(*start_index); + // because we're iterating through the union + // it's safe to remove the tag at this point + + prim.SetOpenTag(prim.OpenTag() & ~mask); + } + } + }; + + // note not a strict set intersection! + // if x appears twice in b and is part of the intersection + // it will appear twice in the intersection + + static + void + IntersectPair( + const std::vector &a, + const std::vector &b, + std::vector &primitives, + std::vector &output + ) { + + typename std::vector::const_iterator last_index = + a.end(); + typename std::vector::const_iterator start_index = + a.begin(); + + for (; start_index != last_index; ++start_index) { + ObjectType & prim = primitives[*start_index]; + prim.SetSelectTag(true); + } + last_index = b.end(); + start_index = b.begin(); + + for (; start_index != last_index; ++start_index) { + ObjectType & prim = primitives[*start_index]; + if (prim.SelectTag()) { + output.push_back(*start_index); + } + } + // deselect + last_index = a.end(); + start_index = a.begin(); + + for (; start_index != last_index; ++start_index) { + ObjectType & prim = primitives[*start_index]; + prim.SetSelectTag(false); + } + }; + + + static + void + Union( + std::vector< std::vector > &index_list, + std::vector &primitives, + std::vector &output + ) { + + // iterate through vectors in index_list + // iterate through individual members of each vector + // mark each obejct that the index points to + + typename std::vector< std::vector >::const_iterator + last_vector = index_list.end(); + typename std::vector< std::vector >::iterator + start_vector = index_list.begin(); + + for (; start_vector != last_vector; ++start_vector) { + + typename std::vector::const_iterator + last_index = start_vector->end(); + typename std::vector::iterator + start_index = start_vector->begin(); + + for (; start_index != last_index; ++start_index) { + + ObjectType & prim = primitives[*start_index]; + + if (!prim.SelectTag()) { + // compute the union + output.push_back(*start_index); + prim.SetSelectTag(true); + } + } + } + + // now iterate through the union and reset the tags + + typename std::vector::const_iterator last_index = + output.end(); + typename std::vector::iterator start_index = + output.begin(); + + for (; start_index != last_index; ++start_index) { + + ObjectType & prim = primitives[*start_index]; + prim.SetSelectTag(false); + } + } + + + static + void + Difference( + std::vector< IndexType> &a, + std::vector< IndexType> &b, + std::vector &primitives, + std::vector< IndexType> &output + ) { + + // iterate through b mark all + // iterate through a and add to output all unmarked + + typename std::vector::const_iterator last_index = + b.end(); + typename std::vector::iterator start_index = + b.begin(); + + for (; start_index != last_index; ++start_index) { + + ObjectType & prim = primitives[*start_index]; + prim.SetSelectTag(true); + } + + last_index = a.end(); + start_index = a.begin(); + + for (; start_index != last_index; ++start_index) { + + ObjectType & prim = primitives[*start_index]; + if (!prim.SelectTag()) { + output.push_back(*start_index); + } + } + + // clean up the tags + + last_index = b.end(); + start_index = b.begin(); + + for (; start_index != last_index; ++start_index) { + + ObjectType & prim = primitives[*start_index]; + prim.SetSelectTag(false); + } + }; + +private : + + // private constructor - this class is not meant for + // instantiation + + CTR_TaggedSetOps(); + +}; + +#endif + diff --git a/intern/container/CTR_UHeap.h b/intern/container/CTR_UHeap.h new file mode 100644 index 00000000000..a7fc33387ee --- /dev/null +++ b/intern/container/CTR_UHeap.h @@ -0,0 +1,305 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * + * @author Laurence + * @mainpage CTR_UHeap an updatable heap template class (also + * known as an updatable priority queue) + * + * Todo: Make CTR_UHeapable a template class with m_key the + * template parameter, so that arbitrary value types with + * operators (=,>) defined can be used. + * + */ + +#ifndef NAN_INCLUDED_CTR_UHeap_h +#define NAN_INCLUDED_CTR_UHeap_h + +#include + +#include "MEM_NonCopyable.h" + +class CTR_UHeapable { + +public : + int & + HeapPos( + ){ + return m_ind; + }; + float & + HeapKey( + ) { + return m_key; + }; + + const + float & + HeapKey( + ) const { + return m_key; + }; + + const + int & + HeapPos( + ) const { + return m_ind; + }; + +private : + + float m_key; + int m_ind; + +protected : + + CTR_UHeapable( + ) : m_key (0), + m_ind (0) + { + }; + + ~CTR_UHeapable( + ){ + }; +}; + +template +class CTR_UHeap : public MEM_NonCopyable +{ + +public: + + static + CTR_UHeap * + New( + ) { + return new CTR_UHeap(); + } + + void + MakeHeap( + HeapType *base + ) { + int i; + int start = Parent(m_vector.size()-1); + for (i = start; i >=0; --i) { + DownHeap(base,i); + } + }; + + void + Insert( + HeapType *base, + int elem + ) { + // add element to vector + m_vector.push_back(elem); + base[elem].HeapPos() = m_vector.size()-1; + + // push the element up the heap + UpHeap(base,m_vector.size()-1); + } + + // access to the vector for initial loading of elements + + std::vector & + HeapVector( + ) { + return m_vector; + }; + + + void + Remove( + HeapType *base, + int i + ) { + + // exchange with last element - pop last + // element and move up or down the heap as appropriate + if (m_vector.empty()) { + assert(false); + } + + if (i != int(m_vector.size())-1) { + + Swap(base,i,m_vector.size() - 1); + m_vector.pop_back(); + + if (!m_vector.empty()) { + UpHeap(base,i); + DownHeap(base,i); + } + } else { + m_vector.pop_back(); + } + } + + int + Top( + ) const { + if (m_vector.empty()) return -1; + return m_vector[0]; + } + + + void + SC_Heap( + HeapType *base + ) { + int i; + for (i = 1; i < int(m_vector.size()) ; i++) { + + CTR_UHeapable * elem = base + m_vector[i]; + CTR_UHeapable * p_elem = base + m_vector[Parent(i)]; + + assert(p_elem->HeapKey() >= elem->HeapKey()); + assert(elem->HeapPos() == i); + } + + }; + + + ~CTR_UHeap( + ) { + }; + + +private: + + CTR_UHeap( + ) { + }; + + + std::vector m_vector; + +private: + void + Swap( + HeapType *base, + int i, + int j + ){ + std::swap(m_vector[i],m_vector[j]); + + CTR_UHeapable *heap_i = base + m_vector[i]; + CTR_UHeapable *heap_j = base + m_vector[j]; + + // Exchange heap positions + heap_i->HeapPos() = i; + heap_j->HeapPos() = j; + } + + int + Parent( + unsigned int i + ) { + return (i-1) >> 1; + } + int + Left( + int i + ) { + return (i<<1)+1; + } + + int + Right( + int i + ) { + return (i<<1)+2; + } + + float + HeapVal( + HeapType *base, + int i + ) { + return base[m_vector[i]].HeapKey(); + } + + void + DownHeap( + HeapType *base, + int i + ) { + int heap_size = m_vector.size(); + + int l = Left(i); + int r = Right(i); + + int largest; + if (l < heap_size && HeapVal(base,l) > HeapVal(base,i)) { + largest = l; + } else { + largest = i; + } + + if (r < heap_size && HeapVal(base,r) > HeapVal(base,largest)) { + largest = r; + } + + if (largest != i) { + // exchange i and largest + Swap(base,i,largest); + DownHeap(base,largest); + } + } + + void + UpHeap( + HeapType *base, + int i + ) { + + // swap parents untill it's found a place in the heap < it's parent or + // top of heap + + while (i > 0) { + int p = Parent(i); + if (HeapVal(base,i) < HeapVal(base,p)) { + break; + } + Swap(base,p,i); + i = p; + } + } +}; + +#endif + diff --git a/intern/container/Makefile b/intern/container/Makefile new file mode 100644 index 00000000000..48343612ef2 --- /dev/null +++ b/intern/container/Makefile @@ -0,0 +1,52 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# container main makefile. +# + +include nan_definitions.mk + +LIBNAME = container +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +#not yet TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_CONTAINER) ] || mkdir $(NAN_CONTAINER) + @[ -d $(NAN_CONTAINER)/include ] || mkdir $(NAN_CONTAINER)/include + @[ -d $(NAN_CONTAINER)/lib ] || mkdir $(NAN_CONTAINER)/lib + @[ -d $(NAN_CONTAINER)/lib/debug ] || mkdir $(NAN_CONTAINER)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libcontainer.a $(NAN_CONTAINER)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libcontainer.a $(NAN_CONTAINER)/lib/debug + @../tools/cpifdiff.sh *.h $(NAN_CONTAINER)/include/ + diff --git a/intern/container/SConscript b/intern/container/SConscript new file mode 100644 index 00000000000..d05104da562 --- /dev/null +++ b/intern/container/SConscript @@ -0,0 +1,7 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.cpp') +incs = '.' + +env.BlenderLib ('blender_CTR', sources, Split(incs) , [], libtype='intern', priority = 10 ) diff --git a/intern/container/intern/CTR_List.cpp b/intern/container/intern/CTR_List.cpp new file mode 100644 index 00000000000..9cbb384c835 --- /dev/null +++ b/intern/container/intern/CTR_List.cpp @@ -0,0 +1,153 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "CTR_List.h" + + +CTR_Link:: +CTR_Link( +) : + m_next(0), + m_prev(0) +{ +} + +CTR_Link:: +CTR_Link( + CTR_Link *next, + CTR_Link *prev +) : + m_next(next), + m_prev(prev) +{ +} + + CTR_Link * +CTR_Link:: +getNext( +) const { + return m_next; +} + + CTR_Link * +CTR_Link:: +getPrev( +) const { + return m_prev; +} + + bool +CTR_Link:: +isHead( +) const { + return m_prev == 0; +} + + bool +CTR_Link:: +isTail( +) const { + return m_next == 0; +} + + void +CTR_Link:: +insertBefore( + CTR_Link *link +) { + m_next = link; + m_prev = link->m_prev; + m_next->m_prev = this; + m_prev->m_next = this; +} + + void +CTR_Link:: +insertAfter( + CTR_Link *link +) { + m_next = link->m_next; + m_prev = link; + m_next->m_prev = this; + m_prev->m_next = this; +} + + void +CTR_Link:: +remove( +) { + m_next->m_prev = m_prev; + m_prev->m_next = m_next; +} + + +CTR_List:: +CTR_List( +) : + m_head(&m_tail, 0), + m_tail(0, &m_head) +{ +} + + CTR_Link * +CTR_List:: +getHead( +) const { + return m_head.getNext(); +} + + CTR_Link * +CTR_List:: +getTail( +) const { + return m_tail.getPrev(); +} + + void +CTR_List:: +addHead( + CTR_Link *link +) { + link->insertAfter(&m_head); +} + + void +CTR_List:: +addTail( + CTR_Link *link +) { + link->insertBefore(&m_tail); +} + diff --git a/intern/container/intern/Makefile b/intern/container/intern/Makefile new file mode 100644 index 00000000000..292df5b7cbc --- /dev/null +++ b/intern/container/intern/Makefile @@ -0,0 +1,42 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# container intern Makefile +# + +LIBNAME = container +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I.. + diff --git a/intern/container/make/msvc_6_0/container.dsp b/intern/container/make/msvc_6_0/container.dsp new file mode 100644 index 00000000000..2ccf1f0a384 --- /dev/null +++ b/intern/container/make/msvc_6_0/container.dsp @@ -0,0 +1,133 @@ +# Microsoft Developer Studio Project File - Name="container" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=container - 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 "container.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 "container.mak" CFG="container - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "container - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "container - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "container - 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 "..\..\..\..\obj\windows\intern\container" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\container" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"../../../../obj/windows/intern/container/libcontainer.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\container\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\container\*.lib ..\..\..\..\..\lib\windows\container\lib\*.a ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "container - 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 "..\..\..\..\obj\windows\intern\container\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\container\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\container\debug\libcontainer.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\container\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\container\debug\*.lib ..\..\..\..\..\lib\windows\container\lib\debug\*.a ECHO Copying Debug info. XCOPY /Y ..\..\..\..\obj\windows\intern\container\debug\vc60.* ..\..\..\..\..\lib\windows\container\lib\debug\ ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "container - Win32 Release" +# Name "container - Win32 Debug" +# Begin Group "intern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\intern\CTR_List.cpp + +!IF "$(CFG)" == "container - Win32 Release" + +# ADD CPP /I "../extern" /I "../../" + +!ELSEIF "$(CFG)" == "container - Win32 Debug" + +# ADD CPP /I "../../" + +!ENDIF + +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\CTR_List.h +# End Source File +# Begin Source File + +SOURCE=..\..\CTR_Map.h +# End Source File +# Begin Source File + +SOURCE=..\..\CTR_TaggedIndex.h +# End Source File +# Begin Source File + +SOURCE=..\..\CTR_TaggedSetOps.h +# End Source File +# Begin Source File + +SOURCE=..\..\CTR_UHeap.h +# End Source File +# End Target +# End Project diff --git a/intern/container/make/msvc_6_0/container.dsw b/intern/container/make/msvc_6_0/container.dsw new file mode 100644 index 00000000000..13092e3c427 --- /dev/null +++ b/intern/container/make/msvc_6_0/container.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "container"=.\container.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/container/make/msvc_7_0/container.sln b/intern/container/make/msvc_7_0/container.sln new file mode 100644 index 00000000000..16ce8e35563 --- /dev/null +++ b/intern/container/make/msvc_7_0/container.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "container", "container.vcproj", "{E9E5B187-2E50-4DD7-9577-327FE6C9E6B0}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {E9E5B187-2E50-4DD7-9577-327FE6C9E6B0}.Debug.ActiveCfg = Debug|Win32 + {E9E5B187-2E50-4DD7-9577-327FE6C9E6B0}.Debug.Build.0 = Debug|Win32 + {E9E5B187-2E50-4DD7-9577-327FE6C9E6B0}.Release.ActiveCfg = Release|Win32 + {E9E5B187-2E50-4DD7-9577-327FE6C9E6B0}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/intern/container/make/msvc_7_0/container.vcproj b/intern/container/make/msvc_7_0/container.vcproj new file mode 100644 index 00000000000..2aefffb6a60 --- /dev/null +++ b/intern/container/make/msvc_7_0/container.vcproj @@ -0,0 +1,292 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/decimation/CMakeLists.txt b/intern/decimation/CMakeLists.txt new file mode 100644 index 00000000000..3b7f428c9b9 --- /dev/null +++ b/intern/decimation/CMakeLists.txt @@ -0,0 +1,35 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC . ../moto/include ../container ../memutil) + +FILE(GLOB SRC intern/*.cpp) + +BLENDERLIB(bf_decimation "${SRC}" "${INC}") +#, libtype=['core','common','player'], priority = [10, 20, 25] ) diff --git a/intern/decimation/Makefile b/intern/decimation/Makefile new file mode 100644 index 00000000000..7bf645a39c9 --- /dev/null +++ b/intern/decimation/Makefile @@ -0,0 +1,56 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# decimation main makefile. +# + +include nan_definitions.mk + +LIBNAME = decimation +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_DECIMATION) ] || mkdir $(NAN_DECIMATION) + @[ -d $(NAN_DECIMATION)/include ] || mkdir $(NAN_DECIMATION)/include + @[ -d $(NAN_DECIMATION)/lib ] || mkdir $(NAN_DECIMATION)/lib + @[ -d $(NAN_DECIMATION)/lib/debug ] || mkdir $(NAN_DECIMATION)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libdecimation.a $(NAN_DECIMATION)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libdecimation.a $(NAN_DECIMATION)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_DECIMATION)/lib/libdecimation.a + ranlib $(NAN_DECIMATION)/lib/debug/libdecimation.a +endif + @../tools/cpifdiff.sh extern/*.h $(NAN_DECIMATION)/include/ + diff --git a/intern/decimation/SConscript b/intern/decimation/SConscript new file mode 100644 index 00000000000..cf199fb3bc5 --- /dev/null +++ b/intern/decimation/SConscript @@ -0,0 +1,8 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.cpp') + +incs = '. ../moto/include ../container ../memutil' + +env.BlenderLib ('bf_decimation', sources, Split(incs) , [], libtype=['core','common','player'], priority = [10, 20, 25] ) diff --git a/intern/decimation/extern/LOD_decimation.h b/intern/decimation/extern/LOD_decimation.h new file mode 100644 index 00000000000..6ebce0206f3 --- /dev/null +++ b/intern/decimation/extern/LOD_decimation.h @@ -0,0 +1,116 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * @author Laurence Bourn + * @date 6/7/2001 + * + * This is the external interface for the decimation module. + */ + +#ifndef NAN_INCLUDED_LOD_decimation_h +#define NAN_INCLUDED_LOD_decimation_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * External decimation structure + */ + +typedef struct LOD_Decimation_Info { + float * vertex_buffer; + float * vertex_normal_buffer; + int * triangle_index_buffer; + int vertex_num; + int face_num; + void * intern; +} LOD_Decimation_Info; + +typedef LOD_Decimation_Info* LOD_Decimation_InfoPtr; + +/** + * Create internal mesh representation from + * LOD_Decimation_Info structure. + * @return 1 on successful loading + * @return 0 on failure + * @warning This should be changed to return an enumeration + * detailing the error encountered + */ + +extern int LOD_LoadMesh(LOD_Decimation_InfoPtr info); + +/** + * Allocate and Compute internal data strucures required for + * decimation. + * @return 1 on successful computation of data + * @return 0 on failure + * @warning This should be changed to return an enumeration + * detailing the error encountered + */ + +extern int LOD_PreprocessMesh(LOD_Decimation_InfoPtr info); + +/** + * Once both the stages above have been completed + * this function collapses a single edge in the mesh. + * The LOD_Decimation_Info structure is updated + * to represent the new mesh. + * @return 1 if an edge was collapsed. + * @return 0 if no suitable edge was found to be collapsable + * You should stop calling this method in this case + * @warning Do not expect that the order of polygons, vertices or + * vertex normals will be preserved by this operation. This function + * returns a packed array of polygons and vertices and so necessarily + * the order will be different. This means you should not expect to + * find the same polygon in the same place in the polygon array after + * this function has been called. + */ + +extern int LOD_CollapseEdge(LOD_Decimation_InfoPtr info); + +/** + * Free any memory the decimation process used + * during the decimation process + * @return 1 if internal data successfully freed + * @return 0 if no data was freed + */ + +extern int LOD_FreeDecimationData(LOD_Decimation_InfoPtr); + +#ifdef __cplusplus +} +#endif + +#endif // NAN_INCLUDED_LOD_decimation_h + diff --git a/intern/decimation/intern/LOD_DecimationClass.h b/intern/decimation/intern/LOD_DecimationClass.h new file mode 100644 index 00000000000..1a3e8dd3620 --- /dev/null +++ b/intern/decimation/intern/LOD_DecimationClass.h @@ -0,0 +1,117 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_LOD_DecimationClass_h +#define NAN_INCLUDED_LOD_DecimationClass_h + +#include "MEM_SmartPtr.h" +#include "MEM_NonCopyable.h" + +#include "LOD_ManMesh2.h" +#include "LOD_QSDecimator.h" +#include "LOD_ExternNormalEditor.h" +#include "../extern/LOD_decimation.h" +#include "LOD_ExternBufferEditor.h" + + +class LOD_DecimationClass : public MEM_NonCopyable +{ +public : + + enum { + e_not_loaded, + e_loaded, + e_preprocessed + } m_e_decimation_state; + + + static + LOD_DecimationClass * + New( + LOD_Decimation_InfoPtr extern_info + ) { + // create everything + + MEM_SmartPtr output(new LOD_DecimationClass()); + MEM_SmartPtr mesh(LOD_ManMesh2::New()); + MEM_SmartPtr extern_editor(LOD_ExternBufferEditor::New(extern_info)); + + if (mesh == NULL || extern_editor == NULL) return NULL; + MEM_SmartPtr normals(LOD_ExternNormalEditor::New(extern_info,mesh.Ref())); + + if (normals == NULL) return NULL; + MEM_SmartPtr decimator(LOD_QSDecimator::New( + mesh.Ref(), + normals.Ref(), + extern_editor.Ref() + )); + if (decimator == NULL || output == NULL) return NULL; + + output->m_mesh = mesh.Release(); + output->m_decimator = decimator.Release(); + output->m_normals = normals.Release(); + output->m_extern_editor = extern_editor.Release(); + + return output.Release(); + } + + LOD_ManMesh2 & + Mesh( + ){ + return m_mesh.Ref(); + } + + LOD_QSDecimator & + Decimator( + ) { + return m_decimator.Ref(); + } + + LOD_ExternNormalEditor & + FaceEditor( + ){ + return m_normals.Ref(); + } + +private : + + LOD_DecimationClass( + ) : m_e_decimation_state(e_not_loaded) { + }; + + MEM_SmartPtr m_mesh; + MEM_SmartPtr m_decimator; + MEM_SmartPtr m_normals; + MEM_SmartPtr m_extern_editor; +}; + +#endif + diff --git a/intern/decimation/intern/LOD_EdgeCollapser.cpp b/intern/decimation/intern/LOD_EdgeCollapser.cpp new file mode 100644 index 00000000000..86b2fbaf423 --- /dev/null +++ b/intern/decimation/intern/LOD_EdgeCollapser.cpp @@ -0,0 +1,413 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "LOD_EdgeCollapser.h" + +#include "LOD_ManMesh2.h" +#include "CTR_TaggedSetOps.h" +#include +#include + + +using namespace std; + + + LOD_EdgeCollapser * +LOD_EdgeCollapser:: +New( +){ + return new LOD_EdgeCollapser(); +} + + + bool +LOD_EdgeCollapser:: +TJunctionTest( + LOD_ManMesh2 &mesh, + vector &e_v0v1, + LOD_EdgeInd collapse_edge +){ + + // we need to copy the egdes in e_v0v1 from the mesh + // into a new buffer -> we are going to modify them + + int original_size = e_v0v1.size(); + if (original_size == 0) return true; + + vector &edge_set = mesh.EdgeSet(); + + LOD_VertexInd c_v0 = edge_set[collapse_edge].m_verts[0]; + LOD_VertexInd c_v1 = edge_set[collapse_edge].m_verts[1]; + + vector temp_edges; + temp_edges.reserve(e_v0v1.size()); + + vector::iterator edge_it = e_v0v1.begin(); + vector::const_iterator edge_end = e_v0v1.end(); + + for (;edge_it != edge_end; ++edge_it) { + temp_edges.push_back(edge_set[*edge_it]); + } + + // in the copied edges replace all instances of c_v0 with c_v1 + + vector::iterator e_it = temp_edges.begin(); + vector::const_iterator e_it_end = temp_edges.end(); + + for (; e_it != e_it_end; ++e_it) { + + if (e_it->m_verts[0] == c_v0) { + e_it->m_verts[0] = c_v1; + } + if (e_it->m_verts[1] == c_v0) { + e_it->m_verts[1] = c_v1; + } + + // normalize the edge + if (int(e_it->m_verts[0]) > int(e_it->m_verts[1])) { + LOD_EdgeInd temp = e_it->m_verts[0]; + e_it->m_verts[0] = e_it->m_verts[1]; + e_it->m_verts[1] = temp; + } + } + + // sort the edges using the edge less functional + + sort(temp_edges.begin(),temp_edges.end(),LOD_EdgeCollapser::less()); + // count the unique edges. + + e_it = temp_edges.begin(); + e_it_end = temp_edges.end(); + + int coincedent_edges = 0; + + vector::const_iterator last_edge = e_it; + ++e_it; + + for (; e_it != e_it_end; ++e_it) { + + if ((e_it->m_verts[0] == last_edge->m_verts[0]) && + (e_it->m_verts[1] == last_edge->m_verts[1]) + ) { + ++coincedent_edges; + } + last_edge = e_it; + } + + // now if the collapse edge is a boundary edges + // then we are alloved at most one coincedent edge + + // otherwise at most 2 coincedent edges + + if (edge_set[collapse_edge].BoundaryEdge()) { + return (coincedent_edges > 1); + } else { + return (coincedent_edges > 2); + } + + +} + + + + bool +LOD_EdgeCollapser:: +CollapseEdge( + LOD_EdgeInd ei, + LOD_ManMesh2 &mesh, + vector & degenerate_edges, + vector & degenerate_faces, + vector & degenerate_vertices, + vector & new_edges, + vector & update_faces, + vector & update_vertices +){ + + vector &verts = mesh.VertexSet(); + vector &edges = mesh.EdgeSet(); + vector &faces = mesh.FaceSet(); + + // shouldn't do this (use mesh interface instead!) + LOD_VertexInd v0_ind = edges[ei].m_verts[0]; + LOD_VertexInd v1_ind = edges[ei].m_verts[1]; +#if 0 + LOD_Vertex &v0 = verts[v0_ind]; + LOD_Vertex &v1 = verts[v1_ind]; +#endif + vector > e_v01(2); + e_v01[0].reserve(32); + e_v01[1].reserve(32); + + mesh.VertexEdges(v0_ind,e_v01[0]); + mesh.VertexEdges(v1_ind,e_v01[1]); + + + // compute the union of e_v0 and e_v1 -> this is the degenerate edges of the collapse + // we remove old edges and replace edges inside the collapse zone with new ones + + CTR_TaggedSetOps::Union(e_v01,edges,degenerate_edges); + + vector< vector > p_v01(2); + p_v01[0].reserve(32); + p_v01[1].reserve(32); + + mesh.VertexFaces(v0_ind,p_v01[0]); + mesh.VertexFaces(v1_ind,p_v01[1]); + + // compute the union of p_v0 anf p_v1 + vector p_v0v1; + p_v0v1.reserve(32); + + CTR_TaggedSetOps::Union(p_v01,faces,p_v0v1); + + // compute the union of all the edges in p_v0v1 this is the collapse zone + + vector > e_input_vectors(p_v0v1.size()); + + vector::iterator p_v0v1_end = p_v0v1.end(); + vector::iterator p_v0v1_start = p_v0v1.begin(); + + vector >::iterator vector_insert_it = e_input_vectors.begin(); + + for (;p_v0v1_start != p_v0v1_end; ++p_v0v1_start , ++vector_insert_it) { + mesh.FaceEdges(*p_v0v1_start,*vector_insert_it); + } + + vector collapse_zone; + collapse_zone.reserve(32); + + CTR_TaggedSetOps::Union(e_input_vectors,edges,collapse_zone); + + // compute the ring edges = collpase_zone - e_v0v1 + + vector edge_ring; + edge_ring.reserve(32); + + CTR_TaggedSetOps::Difference(collapse_zone,degenerate_edges,edges,edge_ring); + + // T Junction test + ////////////////// + // At this point we check to see if any of the polygons + // in p_v0v1 are coninceddent - this leads + // to errors later on if we try and insert a polygon + // into the mesh to an edge which already has 2 polygons. + + // not that t junctions occur naturally from edge collapses + // and are not just the result of coincedent polygons + // for example consider collapsing an edge that forms part + // of a triangular bottle neck. + + // Really we need to make sure that we don't create t-junctions. + + // I think that a sufficient test is to check the number of + // coincedent edge pairs after a collapse. If it is more than 2 + // then collapsing the edge may result in an undeleted edge + // sharing more than 2 polygons. This test probably is too + // restictive though. + + // To perform this test we need to make a copy of the edges + // in e_v0v1. We then apply the contraction to these edge + // copies. Sort them using a function that places coincedent + // edges next to each other. And then count the number + // of coincedent pairs. + + // Of course we have to do this test before we change any of the + // mesh -> so we can back out safely. + + if (TJunctionTest(mesh,degenerate_edges,ei)) return false; + + // Compute the set of possibly degenerate vertices + // this is the union of all the vertices of polygons + // of v0 and v1 + + vector::iterator face_it = p_v0v1.begin(); + vector::const_iterator face_end = p_v0v1.end(); + + + vector > p_v0v1_vertices(p_v0v1.size()); + + for (int i = 0; face_it != face_end; ++face_it, ++i) { + mesh.FaceVertices(*face_it,p_v0v1_vertices[i]); + } + + vector vertex_ring; + vertex_ring.reserve(32); + + CTR_TaggedSetOps::Union(p_v0v1_vertices,verts,vertex_ring); + + // remove all the internal edges e_v0v1 from the mesh. + // for each edge remove the egde from it's vertices edge lists. + + vector::iterator edge_it = degenerate_edges.begin(); + vector::const_iterator edge_end = degenerate_edges.end(); + + for (; !(edge_it == edge_end); ++edge_it) { + + LOD_EdgeInd ed = (*edge_it); + LOD_Edge & edge = edges[ed];//*edge_it]; + + verts[edge.m_verts[0]].RemoveEdge(ed); + verts[edge.m_verts[1]].RemoveEdge(ed); + } + + // we postpone deletion of the internal edges untill the end + // this is because deleting edges invalidates all of the + // EdgeInd vectors above. + + + // now untie all the polygons in p_v0v1 from the edge ring + + // select all polygons in p_v0v1 + + face_it = p_v0v1.begin(); + face_end = p_v0v1.end(); + + for (;face_it != face_end; ++face_it) { + faces[*face_it].SetSelectTag(true); + } + + edge_it = edge_ring.begin(); + edge_end = edge_ring.end(); + + for (;edge_it != edge_end; ++edge_it) { + LOD_Edge & edge = edges[*edge_it]; + + // presumably all edges in edge_ring point to at least + // one polygon from p_v0v1 + + if (!edge.m_faces[0].IsEmpty() && faces[edge.m_faces[0]].SelectTag()) { + edge.m_faces[0].Invalidate(); + } + + if (!edge.m_faces[1].IsEmpty() && faces[edge.m_faces[1]].SelectTag()) { + edge.m_faces[1].Invalidate(); + } + } + + // deselect the faces + + face_it = p_v0v1.begin(); + face_end = p_v0v1.end(); + + for (;face_it != face_end; ++face_it) { + faces[*face_it].SetSelectTag(false); + } + + // perform the edge collapse + //////////////////////////// + + // iterate through the polygons of p_v0 and replace the vertex + // index v0 with v1 + + face_it = p_v01[0].begin(); + face_end = p_v01[0].end(); + + for (;face_it != face_end; ++face_it) { + faces[*face_it].SwapVertex(v0_ind,v1_ind); + } + + face_it = p_v0v1.begin(); + face_end = p_v0v1.end(); + + for (;face_it != face_end; ++face_it) { + if (faces[*face_it].Degenerate()) { + degenerate_faces.push_back(*face_it); + } else { + update_faces.push_back(*face_it); + } + } + + // Add all the non-degenerate faces back into the + // mesh. Get a record of the new edges created in + // this process. + + face_it = update_faces.begin(); + face_end = update_faces.end(); + + for (;face_it != face_end; ++face_it) { + mesh.ConnectTriangle(*face_it,new_edges); + } + + // degenerate ring primitives + ///////////////////////////// + + // we now need to examine each of the edges on the ring + // and work out if they are degenerate - if so we attempt + // to delete them -> add them to the other edges to delete + // in e_v0v1 + + edge_it = edge_ring.begin(); + edge_end = edge_ring.end(); + + for (;edge_it != edge_end; ++edge_it) { + if (edges[*edge_it].Degenerate()) { + degenerate_edges.push_back(*edge_it); + } + } + + // do the same for the ring vertices. + + vector::iterator vertex_it = vertex_ring.begin(); + vector::const_iterator vertex_end = vertex_ring.end(); + + for (;vertex_it != vertex_end; ++vertex_it) { + if (verts[*vertex_it].Degenerate()) { + degenerate_vertices.push_back(*vertex_it); + } else { + update_vertices.push_back(*vertex_it); + } + } + + // we now know all the degenerate primitives + // and the new primitives we have inserted into the mesh + + // We now delete the mesh primitives, mesh.DeleteXXXXXX() methods + // assume that the index vectors are sorted into descending order. + // we do that now. + + sort(degenerate_edges.begin(),degenerate_edges.end(),LOD_EdgeInd::greater()); + sort(degenerate_faces.begin(),degenerate_faces.end(),LOD_FaceInd::greater()); + sort(degenerate_vertices.begin(),degenerate_vertices.end(),LOD_VertexInd::greater()); + + + return true; + +} + +LOD_EdgeCollapser:: +LOD_EdgeCollapser( +){ + // nothing to do +} diff --git a/intern/decimation/intern/LOD_EdgeCollapser.h b/intern/decimation/intern/LOD_EdgeCollapser.h new file mode 100644 index 00000000000..482eccacec2 --- /dev/null +++ b/intern/decimation/intern/LOD_EdgeCollapser.h @@ -0,0 +1,116 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLDUED_EgdeCollapser_h +#define NAN_INCLDUED_EgdeCollapser_h + +// This is a helper class that collapses edges of a 2 - manifold mesh. + +#include "LOD_MeshPrimitives.h" +#include "MEM_NonCopyable.h" +#include +#include + +class LOD_ManMesh2; + +class LOD_EdgeCollapser +: public MEM_NonCopyable +{ + +public : + + static + LOD_EdgeCollapser * + New( + ); + + // returns via arguments the set of modified + // verts,edges and faces. + + bool + CollapseEdge( + LOD_EdgeInd ei, + LOD_ManMesh2 &mesh, + std::vector & degenerate_edges, + std::vector & degenerate_faces, + std::vector & degenerate_vertices, + std::vector & new_edges, + std::vector & update_faces, + std::vector & update_vertices + ); + +private : + + LOD_EdgeCollapser( + ); + + // Test to see if the result of collapsing the + // edge produces 2 junctions in the mesh i.e. where + // an edge is shared by more than 2 polygons + + // We count the number of coincedent edge pairs that + // result from the collapse of collapse_edge. + + // If collapse edge is a boundary edge then the number of + // coincedent pairs should be 1 + // else it should be 2. + + bool + TJunctionTest( + LOD_ManMesh2 &mesh, + std::vector &e_v0v1, + LOD_EdgeInd collapse_edge + ); + + // here's the definition of the sort function + // we use to determine coincedent edges + + // assumes the edges are normalized i.e. m_verts[0] <= m_verts[1] + + struct less : std::binary_function { + bool + operator()( + const LOD_Edge& a, + const LOD_Edge& b + ) const { + + if (int(a.m_verts[0]) == int(b.m_verts[0])) { + return (int(a.m_verts[1]) < int(b.m_verts[1])); + } else { + return (int(a.m_verts[0]) < int(b.m_verts[0])); + } + } + }; + +}; + +#endif + diff --git a/intern/decimation/intern/LOD_ExternBufferEditor.h b/intern/decimation/intern/LOD_ExternBufferEditor.h new file mode 100644 index 00000000000..9f628c4455b --- /dev/null +++ b/intern/decimation/intern/LOD_ExternBufferEditor.h @@ -0,0 +1,164 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + */ + +#ifndef NAN_INCLUDED_LOD_ExternBufferEditor_h +#define NAN_INCLUDED_LOD_ExternBufferEditor_h + +#include "LOD_MeshPrimitives.h" +#include +#include "LOD_ManMesh2.h" +#include "../extern/LOD_decimation.h" + + +// This class syncs external vertex/face buffers +// with the internal mesh representation during +// decimation. + +class LOD_ExternBufferEditor +{ + +public : + + static + LOD_ExternBufferEditor * + New( + LOD_Decimation_InfoPtr extern_info + ){ + if (extern_info == NULL) return NULL; + return new LOD_ExternBufferEditor(extern_info); + } + + // update the external vertex buffer with vertices + // from the mesh + + void + CopyModifiedVerts( + LOD_ManMesh2 & mesh, + const std::vector & mod_vertices + ){ + + std::vector::const_iterator v_start = mod_vertices.begin(); + std::vector::const_iterator v_end = mod_vertices.end(); + + std::vector & mesh_verts = mesh.VertexSet(); + + float * const extern_vertex_ptr = m_extern_info->vertex_buffer; + + for (; v_start != v_end; ++v_start) { + float * mod_vert = extern_vertex_ptr + int(*v_start)*3; + mesh_verts[*v_start].CopyPosition(mod_vert); + } + } + + // update the external face buffer with faces from the mesh + + void + CopyModifiedFaces( + LOD_ManMesh2 & mesh, + const std::vector & mod_faces + ){ + + std::vector::const_iterator f_start = mod_faces.begin(); + std::vector::const_iterator f_end = mod_faces.end(); + + std::vector &mesh_faces = mesh.FaceSet(); + + int * const extern_face_ptr = m_extern_info->triangle_index_buffer; + + for (; f_start != f_end; ++f_start) { + int *mod_face = extern_face_ptr + 3*int(*f_start); + mesh_faces[*f_start].CopyVerts(mod_face); + } + } + + + // Copy the last vertex over the vertex specified by + // vi. Decrement the size of the vertex array + + void + CopyBackVertex( + LOD_VertexInd vi + ){ + + float * const extern_vertex_ptr = m_extern_info->vertex_buffer; + int * extern_vertex_num = &(m_extern_info->vertex_num); + + float * last_external_vert = extern_vertex_ptr + 3*((*extern_vertex_num) - 1); + float * external_vert = extern_vertex_ptr + 3*int(vi); + + external_vert[0] = last_external_vert[0]; + external_vert[1] = last_external_vert[1]; + external_vert[2] = last_external_vert[2]; + + *extern_vertex_num -=1; + } + + // Copy the last face over the face specified by fi + // Decrement the size of the face array + + void + CopyBackFace( + LOD_FaceInd fi + ) { + int * const extern_face_ptr = m_extern_info->triangle_index_buffer; + int * extern_face_num = &(m_extern_info->face_num); + + int * last_external_face = extern_face_ptr + 3*((*extern_face_num) -1); + int * external_face = extern_face_ptr + 3*int(fi); + external_face[0] = last_external_face[0]; + external_face[1] = last_external_face[1]; + external_face[2] = last_external_face[2]; + + *extern_face_num -=1; + } + + +private : + + LOD_ExternBufferEditor( + LOD_Decimation_InfoPtr extern_info + ) : + m_extern_info (extern_info) + { + } + + LOD_Decimation_InfoPtr const m_extern_info; + +}; + +#endif + diff --git a/intern/decimation/intern/LOD_ExternNormalEditor.cpp b/intern/decimation/intern/LOD_ExternNormalEditor.cpp new file mode 100644 index 00000000000..7c9191b60c7 --- /dev/null +++ b/intern/decimation/intern/LOD_ExternNormalEditor.cpp @@ -0,0 +1,267 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "LOD_ExternNormalEditor.h" +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +using namespace std; + + +LOD_ExternNormalEditor:: +LOD_ExternNormalEditor( + LOD_Decimation_InfoPtr extern_info, + LOD_ManMesh2 &mesh +) : + m_extern_info (extern_info), + m_mesh(mesh) +{ +} + + LOD_ExternNormalEditor * +LOD_ExternNormalEditor:: +New( + LOD_Decimation_InfoPtr extern_info, + LOD_ManMesh2 &mesh +){ + if (extern_info == NULL) return NULL; + + MEM_SmartPtr output(new LOD_ExternNormalEditor(extern_info,mesh)); + + int face_num = mesh.FaceSet().size(); + + MEM_SmartPtr > normals(new vector); + + if (output == NULL || + normals == NULL + ) { + return NULL; + } + + normals->reserve(face_num); + output->m_normals = normals.Release(); + + return output.Release(); +}; + + + void +LOD_ExternNormalEditor:: +Remove( + std::vector &sorted_faces +){ + // assumes a collection of faces sorted in descending order . + + vector & normals = m_normals.Ref(); + + vector::const_iterator it_start = sorted_faces.begin(); + vector::const_iterator it_end = sorted_faces.end(); + + for (; it_start != it_end; ++it_start) { + + if (normals.size() > 0) { + MT_Vector3 temp = normals[*it_start]; + + normals[*it_start] = normals.back(); + normals.back() = temp; + + normals.pop_back(); + } + + // FIXME - throw exception + } +} + + + void +LOD_ExternNormalEditor:: +Add( +){ + MT_Vector3 zero(0.0f,0.0f,0.0f); + m_normals->push_back(zero); +}; + + void +LOD_ExternNormalEditor:: +Update( + std::vector &sorted_faces +){ + vector & normals = m_normals.Ref(); + + vector::const_iterator it_start = sorted_faces.begin(); + vector::const_iterator it_end = sorted_faces.end(); + + const vector &faces = m_mesh.FaceSet(); + + for (; it_start != it_end; ++it_start) { + normals[*it_start] = ComputeNormal(faces[*it_start]); + } +}; + + + + +// vertex normals +///////////////// + + void +LOD_ExternNormalEditor:: +RemoveVertexNormals( + std::vector &sorted_verts +){ + + float * vertex_normals = m_extern_info->vertex_normal_buffer; + + // assumption here that the vertexs normal number corresponds with + // the number of vertices ! + + int vertex_normal_num = m_extern_info->vertex_num; + + vector::const_iterator it_start = sorted_verts.begin(); + vector::const_iterator it_end = sorted_verts.end(); + + for (; it_start != it_end; ++it_start) { + + if (vertex_normal_num > 0) { + float * vertex_normal = vertex_normals + int(*it_start)*3; + float * last_vertex = vertex_normals + ((vertex_normal_num-1)*3); + + MT_Vector3 last_v(last_vertex); + last_v.getValue(vertex_normal); + vertex_normal_num--; + } + + // FIXME - through exception + } +}; + + + + void +LOD_ExternNormalEditor:: +UpdateVertexNormals( + std::vector &sorted_verts +){ + float * vertex_normals = m_extern_info->vertex_normal_buffer; + + vector::const_iterator it_start = sorted_verts.begin(); + vector::const_iterator it_end = sorted_verts.end(); + + for (; it_start != it_end; ++it_start) { + MT_Vector3 temp = ComputeVertexNormal(*it_start); + float * vertex_normal = vertex_normals + int(*it_start)*3; + temp.getValue(vertex_normal); + } +} + +// Editor specific methods +////////////////////////// + + void +LOD_ExternNormalEditor:: +BuildNormals( +) { + const vector &faces = m_mesh.FaceSet(); + vector & normals = m_normals.Ref(); + + int face_num = faces.size(); + int cur_face = 0; + + for (; cur_face < face_num; ++cur_face) { + + MT_Vector3 new_normal = ComputeNormal(faces[cur_face]); + normals.push_back(new_normal); + } +} + +const + MT_Vector3 +LOD_ExternNormalEditor:: +ComputeNormal( + const LOD_TriFace &face +) const { + + const vector &verts = m_mesh.VertexSet(); + + MT_Vector3 vec1 = + verts[face.m_verts[1]].pos - + verts[face.m_verts[0]].pos; + + MT_Vector3 vec2 = + verts[face.m_verts[2]].pos - + verts[face.m_verts[1]].pos; + + vec1 = vec1.cross(vec2); + + if (!vec1.fuzzyZero()) { + vec1.normalize(); + return (vec1); + } else { + return (MT_Vector3(1.0,0,0)); + } +} + +const + MT_Vector3 +LOD_ExternNormalEditor:: +ComputeVertexNormal( + const LOD_VertexInd v +) const { + + // average the face normals surrounding this + // vertex and normalize + // vector &verts = m_mesh.VertexSet(); /*unused*/ + const vector & face_normals = m_normals.Ref(); + + vector vertex_faces; + vertex_faces.reserve(32); + + m_mesh.VertexFaces(v,vertex_faces); + + MT_Vector3 normal(0,0,0); + + vector::const_iterator face_it = vertex_faces.begin(); + vector::const_iterator face_end = vertex_faces.end(); + + for (; face_it != face_end; ++face_it) { + normal += face_normals[*face_it]; + } + + if (!normal.fuzzyZero()) { + normal.normalize(); + return (normal); + } else { + return (MT_Vector3(1.0,0,0)); + } +} diff --git a/intern/decimation/intern/LOD_ExternNormalEditor.h b/intern/decimation/intern/LOD_ExternNormalEditor.h new file mode 100644 index 00000000000..190ea5bdd8c --- /dev/null +++ b/intern/decimation/intern/LOD_ExternNormalEditor.h @@ -0,0 +1,134 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_ExternNormalEditor_h +#define NAN_INCLUDED_ExternNormalEditor_h + +#include "MEM_NonCopyable.h" +#include "LOD_ManMesh2.h" +#include "MT_Vector3.h" +#include "../extern/LOD_decimation.h" + +class LOD_ExternNormalEditor : public MEM_NonCopyable +{ + +public : + + // Creation + /////////// + + static + LOD_ExternNormalEditor * + New( + LOD_Decimation_InfoPtr, + LOD_ManMesh2 &mesh + ); + + // Property editor interface + //////////////////////////// + + + // Faces + //////// + void + Remove( + std::vector &sorted_faces + ); + + void + Add( + ); + + void + Update( + std::vector &sorted_faces + ); + + const + std::vector & + Normals( + ) const { + return m_normals.Ref(); + }; + + + // vertex normals + ///////////////// + + void + RemoveVertexNormals( + std::vector &sorted_verts + ); + + + void + UpdateVertexNormals( + std::vector &sorted_verts + ); + + // Editor specific methods + ////////////////////////// + + void + BuildNormals( + ); + + +private : + + MEM_SmartPtr > m_normals; + + LOD_ManMesh2 &m_mesh; + LOD_Decimation_InfoPtr m_extern_info; + +private : + + + LOD_ExternNormalEditor( + LOD_Decimation_InfoPtr extern_info, + LOD_ManMesh2 &mesh + ); + + const + MT_Vector3 + ComputeNormal( + const LOD_TriFace &face + ) const ; + + const + MT_Vector3 + ComputeVertexNormal ( + const LOD_VertexInd vi + ) const; +}; + +#endif + diff --git a/intern/decimation/intern/LOD_FaceNormalEditor.cpp b/intern/decimation/intern/LOD_FaceNormalEditor.cpp new file mode 100644 index 00000000000..bb384dca04c --- /dev/null +++ b/intern/decimation/intern/LOD_FaceNormalEditor.cpp @@ -0,0 +1,294 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +// implementation of LOD_FaceNormalEditor.h + +/////////////////////////////////////// +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "LOD_FaceNormalEditor.h" + +using namespace std; + +LOD_FaceNormalEditor:: +LOD_FaceNormalEditor( + LOD_ManMesh2 & mesh +) : m_mesh(mesh) { +}; + + LOD_FaceNormalEditor * +LOD_FaceNormalEditor:: +New( + LOD_ManMesh2 &mesh +){ + // build a set of normals of the same size + // as the number of polys in the mesh + + MEM_SmartPtr output(new LOD_FaceNormalEditor(mesh)); + + int face_num = mesh.FaceSet().size(); + + MEM_SmartPtr > normals(new vector); + MEM_SmartPtr > vertex_normals(new vector); + + if (output == NULL || + normals == NULL + ) { + return NULL; + } + + normals->reserve(face_num); + vertex_normals->reserve(mesh.VertexSet().size()); + output->m_normals = normals.Release(); + output->m_vertex_normals = vertex_normals.Release(); + + return output.Release(); +}; + + +// Property editor interface +//////////////////////////// + + void +LOD_FaceNormalEditor:: +Remove( + std::vector &sorted_faces +){ + + // assumes a collection of faces sorted in descending order . + + vector & normals = m_normals.Ref(); + + vector::const_iterator it_start = sorted_faces.begin(); + vector::const_iterator it_end = sorted_faces.end(); + + for (; it_start != it_end; ++it_start) { + + if (normals.size() > 0) { + MT_Vector3 temp = normals[*it_start]; + + normals[*it_start] = normals.back(); + normals.back() = temp; + + normals.pop_back(); + } + + // FIXME - through exception + } +} + + + void +LOD_FaceNormalEditor:: +Add( +){ + MT_Vector3 zero(0.0f,0.0f,0.0f); + m_normals->push_back(zero); +} + + void +LOD_FaceNormalEditor:: +Update( + std::vector &sorted_faces +){ + + vector & normals = m_normals.Ref(); + + vector::const_iterator it_start = sorted_faces.begin(); + vector::const_iterator it_end = sorted_faces.end(); + + const vector &faces = m_mesh.FaceSet(); + + for (; it_start != it_end; ++it_start) { + normals[*it_start] = ComputeNormal(faces[*it_start]); + } +}; + +// vertex normals +///////////////// + + + void +LOD_FaceNormalEditor:: +RemoveVertexNormals( + vector &sorted_verts +){ + vector & vertex_normals = m_vertex_normals.Ref(); + + vector::const_iterator it_start = sorted_verts.begin(); + vector::const_iterator it_end = sorted_verts.end(); + + for (; it_start != it_end; ++it_start) { + + if (vertex_normals.size() > 0) { + MT_Vector3 temp = vertex_normals[*it_start]; + + vertex_normals[*it_start] = vertex_normals.back(); + vertex_normals.back() = temp; + + vertex_normals.pop_back(); + } + + // FIXME - through exception + } +}; + + void +LOD_FaceNormalEditor:: +UpdateVertexNormals( + vector &sorted_verts +){ + vector & vertex_normals = m_vertex_normals.Ref(); + + vector::const_iterator it_start = sorted_verts.begin(); + vector::const_iterator it_end = sorted_verts.end(); + + for (; it_start != it_end; ++it_start) { + vertex_normals[*it_start] = ComputeVertexNormal(*it_start); + } +} + + + +// Editor specific methods +////////////////////////// + + void +LOD_FaceNormalEditor:: +BuildNormals( +){ + + const vector &faces = m_mesh.FaceSet(); + vector & normals = m_normals.Ref(); + + int face_num = faces.size(); + int cur_face = 0; + + for (; cur_face < face_num; ++cur_face) { + + MT_Vector3 new_normal = ComputeNormal(faces[cur_face]); + normals.push_back(new_normal); + } + // now build the vertex normals + + vector & vertex_normals = m_vertex_normals.Ref(); + const vector &verts = m_mesh.VertexSet(); + + int vertex_num = verts.size(); + int cur_vertex = 0; + + for (; cur_vertex < vertex_num; ++cur_vertex) { + MT_Vector3 new_normal = ComputeVertexNormal(cur_vertex); + vertex_normals.push_back(new_normal); + } +} + +const + MT_Vector3 +LOD_FaceNormalEditor:: +ComputeNormal( + const LOD_TriFace &face +) const { + + const vector &verts = m_mesh.VertexSet(); + + MT_Vector3 vec1 = + verts[face.m_verts[1]].pos - + verts[face.m_verts[0]].pos; + + MT_Vector3 vec2 = + verts[face.m_verts[2]].pos - + verts[face.m_verts[1]].pos; + + vec1 = vec1.cross(vec2); + + if (!vec1.fuzzyZero()) { + vec1.normalize(); + return (vec1); + } else { + return (MT_Vector3(1.0,0,0)); + } +} + +const + MT_Vector3 +LOD_FaceNormalEditor:: +ComputeVertexNormal( + const LOD_VertexInd v +) const { + + // average the face normals surrounding this + // vertex and normalize + const vector & face_normals = m_normals.Ref(); + + vector vertex_faces; + vertex_faces.reserve(32); + + m_mesh.VertexFaces(v,vertex_faces); + + MT_Vector3 normal(0,0,0); + + vector::const_iterator face_it = vertex_faces.begin(); + vector::const_iterator face_end = vertex_faces.end(); + + for (; face_it != face_end; ++face_it) { + normal += face_normals[*face_it]; + } + + if (!normal.fuzzyZero()) { + normal.normalize(); + return (normal); + } else { + return (MT_Vector3(1.0,0,0)); + } +} + + + + + + + + + + + + + + + + + + + + diff --git a/intern/decimation/intern/LOD_FaceNormalEditor.h b/intern/decimation/intern/LOD_FaceNormalEditor.h new file mode 100644 index 00000000000..892e1f0fbc7 --- /dev/null +++ b/intern/decimation/intern/LOD_FaceNormalEditor.h @@ -0,0 +1,143 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_FaceNormalEditor_h +#define NAN_INCLUDED_FaceNormalEditor_h + +#include "MEM_NonCopyable.h" +#include "LOD_ManMesh2.h" +#include "MT_Vector3.h" + + +class LOD_FaceNormalEditor : public MEM_NonCopyable +{ + +public : + + // Creation + /////////// + + static + LOD_FaceNormalEditor * + New( + LOD_ManMesh2 &mesh + ); + + // Property editor interface + //////////////////////////// + + + // Faces + //////// + void + Remove( + std::vector &sorted_faces + ); + + void + Add( + ); + + void + Update( + std::vector &sorted_faces + ); + + + // vertex normals + ///////////////// + + void + RemoveVertexNormals( + std::vector &sorted_verts + ); + + + void + UpdateVertexNormals( + std::vector &sorted_verts + ); + + + + const + std::vector & + Normals( + ) const { + return m_normals.Ref(); + }; + + + const + std::vector & + VertexNormals( + ) const { + return m_vertex_normals.Ref(); + }; + + // Editor specific methods + ////////////////////////// + + void + BuildNormals( + ); + + +private : + + MEM_SmartPtr > m_normals; + MEM_SmartPtr > m_vertex_normals; + + LOD_ManMesh2 &m_mesh; + +private : + + + LOD_FaceNormalEditor(LOD_ManMesh2 &mesh); + + const + MT_Vector3 + ComputeNormal( + const LOD_TriFace &face + ) const ; + + const + MT_Vector3 + ComputeVertexNormal ( + const LOD_VertexInd vi + ) const; + + + +}; + +#endif + diff --git a/intern/decimation/intern/LOD_ManMesh2.cpp b/intern/decimation/intern/LOD_ManMesh2.cpp new file mode 100644 index 00000000000..322a48e337b --- /dev/null +++ b/intern/decimation/intern/LOD_ManMesh2.cpp @@ -0,0 +1,621 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "LOD_ManMesh2.h" + +#include "MT_assert.h" +#include +#include "LOD_MeshException.h" +#include "CTR_TaggedSetOps.h" +#include "CTR_UHeap.h" +#include "LOD_ExternBufferEditor.h" + + +using namespace std; + +LOD_ManMesh2:: +LOD_ManMesh2( +) : + m_bbox_min(0,0,0), + m_bbox_max(0,0,0) +{ +} + + + LOD_ManMesh2 * +LOD_ManMesh2:: +New( +){ + MEM_SmartPtr output(new LOD_ManMesh2()); + if (output == NULL) return NULL; + + // build the vertex, edge and face sets. + + MEM_SmartPtr > verts(new vector); + MEM_SmartPtr > faces(new vector); + MEM_SmartPtr > edges(new vector); + + if ((faces == NULL) || (edges == NULL) || (verts == NULL)) { + return NULL; + } + + output->m_verts = verts.Release(); + output->m_faces = faces.Release(); + output->m_edges = edges.Release(); + + return output.Release(); +} + +// take ownership of the vertices. + + bool +LOD_ManMesh2:: +SetVertices( + MEM_SmartPtr > verts +){ + + + // take ownership of vertices + m_verts = verts; + + // create a polygon and edge buffer of half the size + // and just use the automatic resizing feature of vector<> + // to worry about the dynamic array resizing + + m_faces->clear(); + m_edges->clear(); + + m_faces->reserve(m_verts->size()/2); + m_edges->reserve(m_verts->size()/2); + + return true; + +} + + +// add a triangle to the mesh + + void +LOD_ManMesh2:: +AddTriangle( + int verts[3] +) { + + MT_assert(verts[0] < int(m_verts->size())); + MT_assert(verts[1] < int(m_verts->size())); + MT_assert(verts[2] < int(m_verts->size())); + + LOD_TriFace face; + face.m_verts[0] = verts[0]; + face.m_verts[1] = verts[1]; + face.m_verts[2] = verts[2]; + + LOD_FaceInd face_index = m_faces->size(); + + m_faces->push_back(face); + + // now work out if any of the directed edges or their + // companion edges exist already. + // We go through the edges associated with each of the given vertices + + // the safest thing to do is iterate through each of the edge sets + // check against each of the 2 other triangle edges to see if they are there + + vector new_edges; + new_edges.reserve(3); + + InsertEdge(verts[0],verts[1],face_index,new_edges); + InsertEdge(verts[1],verts[2],face_index,new_edges); + InsertEdge(verts[2],verts[0],face_index,new_edges); + +} + +// Adds the index of any created edges to new_edges + + bool +LOD_ManMesh2:: +InsertEdge( + const LOD_VertexInd v1, + const LOD_VertexInd v2, + const LOD_FaceInd f, + vector &new_edges +){ + + MT_assert(!v1.IsEmpty()); + MT_assert(!v2.IsEmpty()); + MT_assert(!f.IsEmpty()); + + vector &verts = VertexSet(); + vector &edges = EdgeSet(); + + LOD_EdgeInd e; + + e = FindEdge(v1,v2); + + if (e.IsEmpty()) { + // This edge does not exist -- make a new one + + LOD_Edge temp_e; + temp_e.m_verts[0] = v1; + temp_e.m_verts[1] = v2; + + e = m_edges->size(); + + // set the face ptr for this half-edge + temp_e.m_faces[0] = f; + + m_edges->push_back(temp_e); + + // add the edge index to it's vertices + + verts[v1].AddEdge(e); + verts[v2].AddEdge(e); + + new_edges.push_back(e); + + } else { + + // edge already exists + // insure that there is no polygon already + // attached to the other side of this edge + + // swap the empty face pointer in edge with f + + LOD_Edge &edge = edges[e]; + + edge.SwapFace(LOD_FaceInd::Empty(),f); + } + + + return true; + +} + + void +LOD_ManMesh2:: +ConnectTriangle( + LOD_FaceInd fi, + std::vector & new_edges +){ + + vector &faces = FaceSet(); + + MT_assert(!faces[fi].Degenerate()); + + LOD_TriFace & face = faces[fi]; + + InsertEdge(face.m_verts[0],face.m_verts[1],fi,new_edges); + InsertEdge(face.m_verts[1],face.m_verts[2],fi,new_edges); + InsertEdge(face.m_verts[2],face.m_verts[0],fi,new_edges); +}; + + + + +// geometry access +////////////////// + + vector & +LOD_ManMesh2:: +VertexSet( +) const { + return m_verts.Ref(); +} + + vector & +LOD_ManMesh2:: +FaceSet( +) const { + return m_faces.Ref(); +} + + vector & +LOD_ManMesh2:: +EdgeSet( +) const { + return m_edges.Ref(); +}; + +LOD_ManMesh2:: +~LOD_ManMesh2( +){ + //auto ptr takes care of vertex arrays etc. +} + + LOD_EdgeInd +LOD_ManMesh2:: +FindEdge( + const LOD_VertexInd v1, + const LOD_VertexInd v2 +) { + + vector &verts = VertexSet(); + vector &edges = EdgeSet(); + + LOD_Edge e; + e.m_verts[0] = v1; + e.m_verts[1] = v2; + + vector &v1_edges = verts[v1].m_edges; + vector::const_iterator v1_end = v1_edges.end(); + vector::iterator v1_begin = v1_edges.begin(); + + for (; v1_begin != v1_end; ++v1_begin) { + if (edges[*v1_begin] == e) return *v1_begin; + } + + return LOD_EdgeInd::Empty(); +} + +// face queries +/////////////// + + void +LOD_ManMesh2:: +FaceVertices( + LOD_FaceInd fi, + vector &output +){ + const vector &faces = FaceSet(); + const LOD_TriFace & f = faces[fi]; + + output.push_back(f.m_verts[0]); + output.push_back(f.m_verts[1]); + output.push_back(f.m_verts[2]); +} + + void +LOD_ManMesh2:: +FaceEdges( + LOD_FaceInd fi, + vector &output +){ + const vector &faces = FaceSet(); + vector &edges = EdgeSet(); + vector &verts = VertexSet(); + + const LOD_TriFace & f = faces[fi]; + // intersect vertex edges + + vector & v0_edges = verts[f.m_verts[0]].m_edges; + vector & v1_edges = verts[f.m_verts[1]].m_edges; + vector & v2_edges = verts[f.m_verts[2]].m_edges; + + CTR_TaggedSetOps::IntersectPair(v0_edges,v1_edges,edges,output); + CTR_TaggedSetOps::IntersectPair(v1_edges,v2_edges,edges,output); + CTR_TaggedSetOps::IntersectPair(v2_edges,v0_edges,edges,output); + + MT_assert(output.size() == 3); + if (output.size() != 3) { + LOD_MeshException e(LOD_MeshException::e_non_manifold); + throw(e); + } +} + + +// edge queries +/////////////// + + void +LOD_ManMesh2:: +EdgeVertices( + LOD_EdgeInd ei, + vector &output +){ + const vector &edges = EdgeSet(); + const LOD_Edge & e = edges[ei]; + + output.push_back(e.m_verts[0]); + output.push_back(e.m_verts[1]); +} + + void +LOD_ManMesh2:: +EdgeFaces( + LOD_EdgeInd ei, + vector &output +){ + const vector &edges = EdgeSet(); + const LOD_Edge & e = edges[ei]; + + if (!e.m_faces[0].IsEmpty()) { + output.push_back(e.m_faces[0]); + } + if (!e.m_faces[1].IsEmpty()) { + output.push_back(e.m_faces[1]); + } +} + +// vertex queries +///////////////// + + void +LOD_ManMesh2:: +VertexEdges( + LOD_VertexInd vi, + vector &output +){ + // iterate through the edges of v and push them onto the + // output + + vector &verts = VertexSet(); + + vector & v_edges = verts[vi].m_edges; + vector::iterator v_it = v_edges.begin(); + + for (; v_it != v_edges.end(); ++v_it) { + output.push_back(*v_it); + } +} + + void +LOD_ManMesh2:: +VertexFaces( + LOD_VertexInd vi, + vector &output +){ + const vector &verts = VertexSet(); + vector &edges = EdgeSet(); + vector &faces = FaceSet(); + + const vector &v_edges = verts[vi].m_edges; + vector::const_iterator e_it = v_edges.begin(); + + for (; e_it != v_edges.end(); ++e_it) { + + LOD_Edge &e = edges[*e_it]; + + if ((!e.m_faces[0].IsEmpty()) && (!faces[e.m_faces[0]].SelectTag())) { + output.push_back(e.m_faces[0]); + faces[e.m_faces[0]].SetSelectTag(true); + } + + if ((!e.m_faces[1].IsEmpty()) && (!faces[e.m_faces[1]].SelectTag())) { + output.push_back(e.m_faces[1]); + faces[e.m_faces[1]].SetSelectTag(true); + } + } + + vector::iterator f_it = output.begin(); + + for (; f_it != output.end(); ++f_it) { + faces[*f_it].SetSelectTag(false); + } +}; + + void +LOD_ManMesh2:: +SetBBox( + MT_Vector3 bbox_min, + MT_Vector3 bbox_max +){ + m_bbox_min = bbox_min; + m_bbox_max = bbox_max; +}; + + void +LOD_ManMesh2:: +SC_TriFace( + LOD_FaceInd f +){ + LOD_TriFace face = (*m_faces)[f]; + + // check for unique vertices + + if ( + (face.m_verts[0] == face.m_verts[1]) || + (face.m_verts[1] == face.m_verts[2]) || + (face.m_verts[2] == face.m_verts[0]) + ) { + MT_assert(false); + } + +} + + + void +LOD_ManMesh2:: +SC_EdgeList( + LOD_VertexInd v +){ + vector &edges = EdgeSet(); + vector &verts = VertexSet(); + + vector::iterator e_it = verts[v].m_edges.begin(); + + for (;e_it != verts[v].m_edges.end(); ++e_it) { + MT_assert( (edges[*e_it].m_verts[0] == v) || (edges[*e_it].m_verts[1] == v)); + } + +}; + + void +LOD_ManMesh2:: +DeleteVertex( + LOD_ExternBufferEditor & extern_editor, + LOD_VertexInd v +){ + + vector &edges = EdgeSet(); + vector &verts = VertexSet(); + vector &faces = FaceSet(); + + // need to update all the edge and polygons pointing to + // the last vertex in m_verts + + if (verts.size() == 1) { + verts.clear(); + return; + } + + LOD_VertexInd last = LOD_VertexInd(verts.end() - verts.begin() - 1); + + if (!(last == v)) { + + // we asume that v is already disconnected + + vector v_faces; + vector v_edges; + + v_faces.reserve(64); + v_edges.reserve(64); + + VertexFaces(last,v_faces); + VertexEdges(last,v_edges); + + // map the faces and edges to look at v + + vector::iterator face_it = v_faces.begin(); + + for(; face_it != v_faces.end(); ++face_it) { + faces[*face_it].SwapVertex(last,v); + } + vector::iterator edge_it = v_edges.begin(); + + for (; edge_it != v_edges.end(); ++edge_it) { + edges[*edge_it].SwapVertex(last,v); + } + + // copy the last vertex onto v and pop off the back. + + verts[v] = verts[last]; + + // tidy external buffer + extern_editor.CopyModifiedFaces(*this,v_faces); + } + + verts.pop_back(); + extern_editor.CopyBackVertex(v); + + +}; + + void +LOD_ManMesh2:: +DeleteEdge( + LOD_EdgeInd e, + CTR_UHeap * heap +){ + vector &edges = EdgeSet(); + vector &verts = VertexSet(); + + if (edges.size() == 1) { + edges.clear(); + return; + } + + LOD_EdgeInd last = LOD_EdgeInd(edges.end() - edges.begin() - 1); + + if (!(last == e)) { + vector e_verts; + e_verts.reserve(2); + EdgeVertices(last,e_verts); + // something is wrong if there arent two! + + verts[e_verts[0]].SwapEdge(last,e); + verts[e_verts[1]].SwapEdge(last,e); + + // edges[e] should already have been removed from the heap + + MT_assert(edges[e].HeapPos() == 0xffffffff); + + edges[e] = edges[last]; + // also have to swap there heap positions.!!!!! + + heap->HeapVector()[edges[e].HeapPos()] = e; + + + } + edges.pop_back(); +}; + + void +LOD_ManMesh2:: +DeleteFace( + LOD_ExternBufferEditor & extern_editor, + LOD_FaceInd f +){ + + vector &edges = EdgeSet(); + vector &faces = FaceSet(); + + if (faces.size() == 1) { + faces.clear(); + return; + } + + LOD_FaceInd last = LOD_FaceInd(faces.end() - faces.begin() - 1); + + if (!(last == f)) { + + // we have to update the edges which point to the last + // face + + vector f_edges; + f_edges.reserve(3); + + FaceEdges(last,f_edges); + + vector::iterator edge_it = f_edges.begin(); + vector::const_iterator edge_end = f_edges.end(); + + for (; edge_it != edge_end; ++edge_it) { + edges[*edge_it].SwapFace(last,f); + } + + faces[f] = faces[last]; + + } + faces.pop_back(); + + // tidy external buffers + extern_editor.CopyBackFace(f); +}; + + + + + + + + + + + + + + + + diff --git a/intern/decimation/intern/LOD_ManMesh2.h b/intern/decimation/intern/LOD_ManMesh2.h new file mode 100644 index 00000000000..46ddcff5d80 --- /dev/null +++ b/intern/decimation/intern/LOD_ManMesh2.h @@ -0,0 +1,264 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_ManMesh2_h +#define NAN_INCLUDED_ManMesh2_h + +#include "LOD_MeshPrimitives.h" +#include "MEM_SmartPtr.h" +#include + +template class CTR_UHeap; + +class LOD_ExternBufferEditor; + +class LOD_ManMesh2 // Manifold 2 dimensional mesh +{ + +public: + + static + LOD_ManMesh2 * + New( + ); + + // take ownership of the vertices. + + bool + SetVertices( + MEM_SmartPtr > verts + ); + + // Add a triangle to the mesh + + void + AddTriangle( + int verts[3] + ); + + void + ConnectTriangle( + LOD_FaceInd fi, + std::vector & new_edges + ); + + // geometry access + ////////////////// + + std::vector & + VertexSet( + ) const ; + + std::vector & + FaceSet( + ) const ; + + std::vector & + EdgeSet( + ) const; + + ~LOD_ManMesh2( + ); + + // local geometry queries + ///////////////////////// + + // face queries + /////////////// + + void + FaceVertices( + LOD_FaceInd f, + std::vector &output + ); + + void + FaceEdges( + LOD_FaceInd f, + std::vector &output + ); + + // edge queries + /////////////// + + void + EdgeVertices( + LOD_EdgeInd e, + std::vector &output + ); + + void + EdgeFaces( + LOD_EdgeInd e, + std::vector &output + ); + + // vertex queries + ///////////////// + + void + VertexEdges( + LOD_VertexInd v, + std::vector &output + ); + + void + VertexFaces( + LOD_VertexInd v, + std::vector &output + ); + + void + SetBBox( + MT_Vector3 bbox_min, + MT_Vector3 bbox_max + ); + + MT_Vector3 + BBoxMin( + ) const { + return m_bbox_min; + }; + + MT_Vector3 + BBoxMax( + ) const { + return m_bbox_max; + }; + + // Remove a primitive from the mesh + /////////////////////////////////// + + // These methods assume you have correctly + // tidied up the index pointers in other primitives, + // so that nothing refers to this object any more + + // These methods exchange the primitive with the + // last primitive in the vector. It modifies everything + // pointing to the last primitive correctly. + + // FIXME refactor extern editor out of primitive deletion + // insead return a vector of primitives that need to be + // modified and do this externally + + void + DeleteVertex( + LOD_ExternBufferEditor & extern_editor, + LOD_VertexInd v + ); + + void + DeleteEdge( + LOD_EdgeInd e, + CTR_UHeap *heap + ); + + void + DeleteFace( + LOD_ExternBufferEditor & extern_editor, + LOD_FaceInd f + ); + + // Sanity Check routines + //////////////////////// + + // Make sure the edge sets and the vertex sets are + // consistent + + void + SC_TriFace( + LOD_FaceInd f + ); + + // basic sanity checking of an edge list bails out if there are more than 1024 + // edges + + void + SC_EdgeList( + LOD_EdgeInd e + ); + + + // Check to see that the edges of v1 and v2 are unique. + + bool + SC_UniqueEdge( + LOD_EdgeInd e + ); + + +private : + + + // Returns the edge index of the edge from v1 to v2. + // Does this by searching the edge sets of v1 - but not v2. + // If you are paranoid you should check both and make sure the + // indices are the same. If the edge doe not exist edgeInd is empty. + + LOD_EdgeInd + FindEdge( + const LOD_VertexInd v1, + const LOD_VertexInd v2 + ); + + // Insert an edge into the mesh + // Tie up the ptrs and create space for the edge + // returns manifold errors - need to sort out memory edges + + bool + InsertEdge( + const LOD_VertexInd v1, + const LOD_VertexInd v2, + const LOD_FaceInd f, + std::vector &new_edges + ); + + +private : + + LOD_ManMesh2( + ); + + MEM_SmartPtr< std::vector > m_verts; + MEM_SmartPtr< std::vector > m_faces; + MEM_SmartPtr< std::vector > m_edges; + + // not sure of these descrtiptions of the mesh should + // reside in this class coz may lead to very bloated interface. + + MT_Vector3 m_bbox_min; + MT_Vector3 m_bbox_max; + + +}; + +#endif + diff --git a/intern/decimation/intern/LOD_MeshBounds.h b/intern/decimation/intern/LOD_MeshBounds.h new file mode 100644 index 00000000000..f694ff2dcb3 --- /dev/null +++ b/intern/decimation/intern/LOD_MeshBounds.h @@ -0,0 +1,132 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_MeshBounds_h +#define NAN_INCLUDED_MeshBounds_h + +#include "MEM_SmartPtr.h" +#include "LOD_MeshPrimitives.h" +#include "LOD_ManMesh2.h" +#include "MT_assert.h" + +// simple class to compute the mesh bounds of a manifold mesh, + +class LOD_MeshBounds { + +public : + static + LOD_MeshBounds * + New( + ){ + + MEM_SmartPtr output(new LOD_MeshBounds()); + return output.Release(); + } + + void + ComputeBounds( + const LOD_ManMesh2 * mesh + ){ + MT_assert(mesh!=NULL); + MT_assert(mesh->VertexSet().size() > 0); + + const std::vector &verts = mesh->VertexSet(); + + m_min = verts[0].pos; + m_max = verts[0].pos; + + // iterate through the verts + + int t; + const int size = verts.size(); + + for (t=1; t< size ; ++t) { + + UpdateBounds(verts[t].pos,m_min,m_max); + } + } + + MT_Vector3 + Min( + ) const { + return m_min; + } + + MT_Vector3 + Max( + ) const { + return m_max; + } + +private : + + void + UpdateBounds( + MT_Vector3 vertex, + MT_Vector3& min, + MT_Vector3& max + ) { + if (vertex.x() < min.x()) { + min.x() = vertex.x(); + } else + if (vertex.x() > max.x()) { + max.x()= vertex.x(); + } + + if (vertex.y() < min.y()) { + min.y() = vertex.y(); + } else + if (vertex.y() > max.y()) { + max.y()= vertex.y(); + } + + if (vertex.z() < min.z()) { + min.z() = vertex.z(); + } else + if (vertex.z() > max.z()) { + max.z()= vertex.z(); + } + } + + LOD_MeshBounds( + ) : + m_min(0,0,0), + m_max(0,0,0) + { + }; + + MT_Vector3 m_min; + MT_Vector3 m_max; + +}; + +#endif + diff --git a/intern/decimation/intern/LOD_MeshException.h b/intern/decimation/intern/LOD_MeshException.h new file mode 100644 index 00000000000..4bad167a81b --- /dev/null +++ b/intern/decimation/intern/LOD_MeshException.h @@ -0,0 +1,54 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_MeshExceptions_h +#define NAN_INCLUDED_MeshExceptions_h + +class LOD_MeshException { + +public : + + // stick in more error types as you think of them + + enum ExceptionType{ + e_non_manifold, + e_search_error + } m_e_type; + + LOD_MeshException ( + ExceptionType type + ) : m_e_type (type) + { + } +}; + +#endif + diff --git a/intern/decimation/intern/LOD_MeshPrimitives.cpp b/intern/decimation/intern/LOD_MeshPrimitives.cpp new file mode 100644 index 00000000000..42707252a45 --- /dev/null +++ b/intern/decimation/intern/LOD_MeshPrimitives.cpp @@ -0,0 +1,407 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "LOD_MeshPrimitives.h" + +#include "MT_assert.h" +#include "LOD_MeshException.h" +#include + +using namespace std; + +// Vertex Methods +///////////////// + +LOD_Vertex:: +LOD_Vertex( +) : + pos (MT_Vector3()), + m_select_tag(false) +{ +}; + + bool +LOD_Vertex:: +RemoveEdge( + LOD_EdgeInd e +){ + + vector::iterator result = find(m_edges.begin(),m_edges.end(),e); + if (result == m_edges.end()) { + return false; + } + + std::swap(*result, m_edges.back()); + m_edges.pop_back(); + return true; +}; + + void +LOD_Vertex:: +AddEdge( + LOD_EdgeInd e +){ + m_edges.push_back(e); +}; + + void +LOD_Vertex:: +SwapEdge( + LOD_EdgeInd e_old, + LOD_EdgeInd e_new +){ + + vector::iterator result = + find(m_edges.begin(),m_edges.end(),e_old); + if (result == m_edges.end()) { + MT_assert(false); + LOD_MeshException e(LOD_MeshException::e_search_error); + throw(e); + } + + *result = e_new; +}; + + bool +LOD_Vertex:: +SelectTag( +) const { + return m_select_tag; +}; + + void +LOD_Vertex:: +SetSelectTag( + bool tag +){ + m_select_tag = tag; +}; + + bool +LOD_Vertex:: +Degenerate( +){ + return m_edges.empty(); +} + + void +LOD_Vertex:: +CopyPosition( + float *float_ptr +){ + pos.getValue(float_ptr); +} + + + +// Edge Methods +/////////////// + +LOD_Edge:: +LOD_Edge ( +) { + m_verts[0] = m_verts[1] = LOD_VertexInd::Empty(); + m_faces[0] = m_faces[1] = LOD_FaceInd::Empty(); +} + + bool +LOD_Edge:: +operator == ( + LOD_Edge & rhs +) { + // edges are the same if their vertex indices are the + // same!!! Other properties are not checked + + int matches = 0; + + if (this->m_verts[0] == rhs.m_verts[0]) { + ++matches; + } + if (this->m_verts[1] == rhs.m_verts[0]) { + ++matches; + } + if (this->m_verts[0] == rhs.m_verts[1]) { + ++matches; + } + if (this->m_verts[1] == rhs.m_verts[1]) { + ++matches; + } + + if (matches >= 2) { + return true; + } + return false; +} + +// Elementary helper methods +//////////////////////////// + + LOD_FaceInd +LOD_Edge:: +OpFace( + LOD_FaceInd f +) const { + if (f == m_faces[0]) { + return m_faces[1]; + } else + if (f == m_faces[1]) { + return m_faces[0]; + } else { + MT_assert(false); + LOD_MeshException e(LOD_MeshException::e_search_error); + throw(e); + + return LOD_FaceInd::Empty(); + } +} + + void +LOD_Edge:: +SwapFace( + LOD_FaceInd old_f, + LOD_FaceInd new_f +) { + if (old_f == m_faces[0]) { + m_faces[0] = new_f; + } else + if (old_f == m_faces[1]) { + m_faces[1] = new_f; + } else { + LOD_MeshException e(LOD_MeshException::e_search_error); + throw(e); + } +} + + +// return the half edge face - the half edge is defined +// by the {vertex,edge} tuple. + + LOD_FaceInd +LOD_Edge:: +HalfEdgeFace( + LOD_VertexInd vi +){ + if (vi == m_verts[0]) return m_faces[0]; + if (vi == m_verts[1]) return m_faces[1]; + MT_assert(false); + + LOD_MeshException e(LOD_MeshException::e_search_error); + throw(e); + + return LOD_FaceInd::Empty(); +} + + + LOD_VertexInd +LOD_Edge:: +OpVertex( + LOD_VertexInd vi +) { + if (vi == m_verts[0]) return m_verts[1]; + if (vi == m_verts[1]) return m_verts[0]; + MT_assert(false); + + LOD_MeshException e(LOD_MeshException::e_search_error); + throw(e); + + return LOD_VertexInd::Empty(); +} + +// replace the vertex v_old with vertex v_new +// error if v_old is not one of the original vertices + + void +LOD_Edge:: +SwapVertex( + LOD_VertexInd v_old, + LOD_VertexInd v_new +) { + if (v_old == m_verts[0]) { + m_verts[0] = v_new; + } else + if (v_old == m_verts[1]) { + m_verts[1] = v_new; + } else { + + MT_assert(false); + + LOD_MeshException e(LOD_MeshException::e_search_error); + throw(e); + } + if(m_verts[0] == m_verts[1]) { + MT_assert(false); + + LOD_MeshException e(LOD_MeshException::e_non_manifold); + throw(e); + } + +} + + bool +LOD_Edge:: +SelectTag( +) const { + return bool(m_verts[1].Tag() & 0x1); +}; + + void +LOD_Edge:: +SetSelectTag( + bool tag +) { + m_verts[1].SetTag(int(tag)); +}; + + int +LOD_Edge:: +OpenTag( +) const { + return m_faces[0].Tag(); +} + + void +LOD_Edge:: +SetOpenTag( + int tag +) { + m_faces[0].SetTag(tag); +} + + bool +LOD_Edge:: +Degenerate( +) const { + return ( + (m_faces[0].IsEmpty() && m_faces[1].IsEmpty()) || + (m_verts[0] == m_verts[1]) + ); +}; + +// TriFace Methods +////////////////// + +LOD_TriFace:: +LOD_TriFace( +) { + m_verts[0] = m_verts[1] = m_verts[2] = LOD_VertexInd::Empty(); +} + +// Elementary helper methods +//////////////////////////// + + void +LOD_TriFace:: +SwapVertex( + LOD_VertexInd old_v, + LOD_VertexInd new_v +) { + // could save branching here... + + if (m_verts[0] == old_v) { + m_verts[0] = new_v; + } else + if (m_verts[1] == old_v) { + m_verts[1] = new_v; + } else + if (m_verts[2] == old_v) { + m_verts[2] = new_v; + } else { + MT_assert(false); + + LOD_MeshException excep(LOD_MeshException::e_search_error); + throw(excep); + } +} + + bool +LOD_TriFace:: +SelectTag( +) const { + return bool(m_verts[1].Tag() & 0x1); +}; + + void +LOD_TriFace:: +SetSelectTag( + bool tag +) { + m_verts[1].SetTag(int(tag)); +}; + + int +LOD_TriFace:: +OpenTag( +) { + return m_verts[2].Tag(); +} + + void +LOD_TriFace:: +SetOpenTag( + int tag +) { + m_verts[2].SetTag(tag); +} + + bool +LOD_TriFace:: +Degenerate( +) { + + return ( + (m_verts[0] == m_verts[1]) || + (m_verts[1] == m_verts[2]) || + (m_verts[2] == m_verts[0]) + ); +} + + void +LOD_TriFace:: +CopyVerts( + int * index_ptr +){ + index_ptr[0] = m_verts[0]; + index_ptr[1] = m_verts[1]; + index_ptr[2] = m_verts[2]; +}; + + + + + + + + + diff --git a/intern/decimation/intern/LOD_MeshPrimitives.h b/intern/decimation/intern/LOD_MeshPrimitives.h new file mode 100644 index 00000000000..1168c9cc813 --- /dev/null +++ b/intern/decimation/intern/LOD_MeshPrimitives.h @@ -0,0 +1,220 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_MeshPrimitives_h +#define NAN_INCLUDED_MeshPrimitives_h + +#include "MT_Vector3.h" +#include "CTR_TaggedIndex.h" +#include "CTR_UHeap.h" +#include + +typedef CTR_TaggedIndex<24,0x00ffffff> LOD_VertexInd; +typedef CTR_TaggedIndex<24,0x00ffffff> LOD_EdgeInd; +typedef CTR_TaggedIndex<24,0x00ffffff> LOD_FaceInd; +typedef CTR_TaggedIndex<24,0x00ffffff> LOD_HeapInd; + +class LOD_Vertex { +public : + MT_Vector3 pos; + std::vector m_edges; + bool m_select_tag; + + LOD_Vertex( + ) ; + + bool + RemoveEdge( + LOD_EdgeInd e + ); + + void + AddEdge( + LOD_EdgeInd e + ); + + void + SwapEdge( + LOD_EdgeInd e_old, + LOD_EdgeInd e_new + ); + + bool + SelectTag( + ) const; + + void + SetSelectTag( + bool tag + ); + + bool + Degenerate( + ); + + void + CopyPosition( + float *float_ptr + ); + +private : + + +}; + +class LOD_Edge : public CTR_UHeapable { +public : + LOD_VertexInd m_verts[2]; + LOD_FaceInd m_faces[2]; + + LOD_Edge ( + ); + + bool operator == ( + LOD_Edge & rhs + ); + + // Elementary helper methods + //////////////////////////// + + LOD_FaceInd + OpFace( + LOD_FaceInd f + ) const ; + + void + SwapFace( + LOD_FaceInd old_f, + LOD_FaceInd new_f + ) ; + + + // return the half edge face - the half edge is defined + // by the {vertex,edge} tuple. + + LOD_FaceInd + HalfEdgeFace( + LOD_VertexInd vi + ); + + + LOD_VertexInd + OpVertex( + LOD_VertexInd vi + ); + + // replace the vertex v_old with vertex v_new + // error if v_old is not one of the original vertices + + void + SwapVertex( + LOD_VertexInd v_old, + LOD_VertexInd v_new + ) ; + + bool + SelectTag( + ) const ; + + void + SetSelectTag( + bool tag + ); + + int + OpenTag( + ) const; + + void + SetOpenTag( + int tag + ) ; + + bool + Degenerate( + ) const; + + bool + BoundaryEdge( + ) const { + return (m_faces[0].IsEmpty() || m_faces[1].IsEmpty()); + }; + + +}; + +class LOD_TriFace { +public: + + LOD_VertexInd m_verts[3]; + + LOD_TriFace( + ); + + // Elementary helper methods + //////////////////////////// + + void + SwapVertex( + LOD_VertexInd old_v, + LOD_VertexInd new_v + ); + + bool + SelectTag( + ) const; + + void + SetSelectTag( + bool tag + ); + + int + OpenTag( + ); + void + SetOpenTag( + int tag + ); + + bool + Degenerate( + ); + + void + CopyVerts( + int * index_ptr + ); + +}; + +#endif + diff --git a/intern/decimation/intern/LOD_QSDecimator.cpp b/intern/decimation/intern/LOD_QSDecimator.cpp new file mode 100644 index 00000000000..a9fd5267c54 --- /dev/null +++ b/intern/decimation/intern/LOD_QSDecimator.cpp @@ -0,0 +1,328 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "LOD_QSDecimator.h" + +#include "LOD_ExternBufferEditor.h" + +using namespace std; + + LOD_QSDecimator * +LOD_QSDecimator:: +New( + LOD_ManMesh2 &mesh, + LOD_ExternNormalEditor &face_editor, + LOD_ExternBufferEditor &extern_editor +){ + + MEM_SmartPtr output + = new LOD_QSDecimator(mesh,face_editor,extern_editor); + + MEM_SmartPtr collapser(LOD_EdgeCollapser::New()); + MEM_SmartPtr q_editor(LOD_QuadricEditor::New(mesh)); + + if ( + output == NULL || + collapser == NULL || + q_editor == NULL + ) { + return NULL; + } + output->m_collapser = collapser.Release(); + output->m_quadric_editor = q_editor.Release(); + return output.Release(); +} + + + + bool +LOD_QSDecimator:: +Arm( +){ + MT_assert(!m_is_armed); + bool heap_result = BuildHeap(); + if (!heap_result) { + return false; + } + m_is_armed = true; + return true; +} + + bool +LOD_QSDecimator:: +Step( +){ + return CollapseEdge(); +} + + +LOD_QSDecimator:: +LOD_QSDecimator( + LOD_ManMesh2 &mesh, + LOD_ExternNormalEditor &face_editor, + LOD_ExternBufferEditor &extern_editor +) : + m_mesh(mesh), + m_face_editor(face_editor), + m_extern_editor(extern_editor), + m_is_armed (false) +{ + m_deg_edges.reserve(32); + m_deg_faces.reserve(32); + m_deg_vertices.reserve(32); + m_update_faces.reserve(32); + m_new_edges.reserve(32); + m_update_vertices.reserve(32); +}; + + bool +LOD_QSDecimator:: +CollapseEdge( +){ + + // find an edge to collapse + + // FIXME force an edge collapse + // or return false + + std::vector & edges = m_mesh.EdgeSet(); + std::vector & verts = m_mesh.VertexSet(); + std::vector & quadrics = m_quadric_editor->Quadrics(); + int size = edges.size(); + + if (size == 0) return false; + + const int heap_top = m_heap->Top(); + + if (heap_top == -1 || edges[heap_top].HeapKey() <= -MT_INFINITY) { + return false; + } + + // compute the target position + MT_Vector3 new_vertex = m_quadric_editor->TargetVertex(edges[heap_top]); + LOD_Quadric & q0 = quadrics[edges[heap_top].m_verts[0]]; + LOD_Quadric & q1 = quadrics[edges[heap_top].m_verts[1]]; + + LOD_Vertex &v0 = verts[edges[heap_top].m_verts[0]]; + LOD_Vertex &v1 = verts[edges[heap_top].m_verts[1]]; + + LOD_Quadric sum = q0; + sum += q1; + + + if (m_collapser->CollapseEdge( + heap_top, + m_mesh, + m_deg_edges, + m_deg_faces, + m_deg_vertices, + m_new_edges, + m_update_faces, + m_update_vertices + )) { + + // assign new vertex position + + v0.pos = new_vertex; + v1.pos = new_vertex; + + // sum the quadrics of v0 and v1 + q0 = sum; + q1 = sum; + + // ok update the primitive properties + + m_face_editor.Update(m_update_faces); + m_face_editor.UpdateVertexNormals(m_update_vertices); + + // update the external vertex buffer + m_extern_editor.CopyModifiedVerts(m_mesh,m_update_vertices); + + // update the external face buffer + m_extern_editor.CopyModifiedFaces(m_mesh,m_update_faces); + + // update the edge heap + UpdateHeap(m_deg_edges,m_new_edges); + + m_quadric_editor->Remove(m_deg_vertices); + m_face_editor.Remove(m_deg_faces); + m_face_editor.RemoveVertexNormals(m_deg_vertices); + + // delete the primitives + + DeletePrimitives(m_deg_edges,m_deg_faces,m_deg_vertices); + + } else { + // the edge could not be collapsed at the moment - so + // we adjust it's priority and add it back to the heap. + m_heap->Remove(&edges[0],0); + edges[heap_top].HeapKey() = - MT_INFINITY; + m_heap->Insert(&edges[0],heap_top); + } + + //clear all the temporary buffers + + m_deg_faces.clear(); + m_deg_edges.clear(); + m_deg_vertices.clear(); + + m_update_faces.clear(); + m_update_vertices.clear(); + m_new_edges.clear(); + + return true; + +} + + void +LOD_QSDecimator:: +DeletePrimitives( + const vector & degenerate_edges, + const vector & degenerate_faces, + const vector & degenerate_vertices +) { + + // assumes that the 3 vectors are sorted in descending order. + + // Delete Degnerate primitives + ////////////////////////////// + + + // delete the old edges - we have to be very careful here + // mesh.delete() swaps edges to be deleted with the last edge in + // the edge buffer. However the next edge to be deleted may have + // been the last edge in the buffer! + + // One way to solve this is to sort degenerate_edges in descending order. + // And then delete them in that order. + + // it is also vital that degenerate_edges contains no duplicates + + vector::const_iterator edge_it = degenerate_edges.begin(); + vector::const_iterator edge_end = degenerate_edges.end(); + + for (; edge_it != edge_end; ++edge_it) { + m_mesh.DeleteEdge(*edge_it,m_heap); + } + + + + vector::const_iterator face_it = degenerate_faces.begin(); + vector::const_iterator face_end = degenerate_faces.end(); + + for (;face_it != face_end; ++face_it) { + m_mesh.DeleteFace(m_extern_editor,*face_it); + } + + vector::const_iterator vertex_it = degenerate_vertices.begin(); + vector::const_iterator vertex_end = degenerate_vertices.end(); + + for (;vertex_it != vertex_end; ++vertex_it) { + m_mesh.DeleteVertex(m_extern_editor,*vertex_it); + } +} + + + bool +LOD_QSDecimator:: +BuildHeap( +){ + // build the quadrics + + if (m_quadric_editor->BuildQuadrics(m_face_editor,true) == false) return false; + + + m_heap = CTR_UHeap::New(); + // load in edge pointers to the heap + + std::vector & edge_set= m_mesh.EdgeSet(); + std::vector::const_iterator edge_end = edge_set.end(); + std::vector::iterator edge_start = edge_set.begin(); + + std::vector & heap_vector = m_heap->HeapVector(); + + for (unsigned int i = 0; i < edge_set.size(); ++i) { + edge_set[i].HeapPos() = i; + heap_vector.push_back(i); + } + + m_heap->MakeHeap(&edge_set[0]); + + return true; +} + + void +LOD_QSDecimator:: +UpdateHeap( + std::vector °_edges, + std::vector &new_edges +){ + // first of all compute values for the new edges + // and bung them on the heap. + + std::vector & edge_set= m_mesh.EdgeSet(); + + std::vector::const_iterator edge_it = new_edges.begin(); + std::vector::const_iterator end_it = new_edges.end(); + + + // insert all the new edges + /////////////////////////// + + // compute edge costs ffor the new edges + + m_quadric_editor->ComputeEdgeCosts(new_edges); + + // inser the new elements into the heap + + for (; edge_it != end_it; ++edge_it) { + m_heap->Insert(&edge_set[0],*edge_it); + } + + + // remove all the old values from the heap + + edge_it = deg_edges.begin(); + end_it = deg_edges.end(); + + for (; edge_it != end_it; ++edge_it) { + LOD_Edge &e = edge_set[*edge_it]; + m_heap->Remove(&edge_set[0],e.HeapPos()); + + e.HeapPos() = 0xffffffff; + + } +} + diff --git a/intern/decimation/intern/LOD_QSDecimator.h b/intern/decimation/intern/LOD_QSDecimator.h new file mode 100644 index 00000000000..0492e0bf09e --- /dev/null +++ b/intern/decimation/intern/LOD_QSDecimator.h @@ -0,0 +1,128 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_LOD_QSDecimator_H +#define NAN_INCLUDED_LOD_QSDecimator_H + +#include "MEM_NonCopyable.h" +#include "LOD_ManMesh2.h" +#include "LOD_ExternNormalEditor.h" +#include "LOD_EdgeCollapser.h" +#include "LOD_QuadricEditor.h" + +class LOD_ExternBufferEditor; + +class LOD_QSDecimator : public MEM_NonCopyable { + +public : + + static + LOD_QSDecimator * + New( + LOD_ManMesh2 &mesh, + LOD_ExternNormalEditor &face_editor, + LOD_ExternBufferEditor &extern_editor + ); + + + bool + Arm( + ); + + + bool + Step( + ); + +private : + + LOD_QSDecimator( + LOD_ManMesh2 &mesh, + LOD_ExternNormalEditor &face_editor, + LOD_ExternBufferEditor &extern_editor + ); + + bool + CollapseEdge( + ); + + bool + BuildHeap( + ); + + void + UpdateHeap( + std::vector °_edges, + std::vector &new_edges + ); + + void + DeletePrimitives( + const std::vector & degenerate_edges, + const std::vector & degenerate_faces, + const std::vector & degenerate_vertices + ); + + +private : + + // owned by this class + ////////////////////// + + MEM_SmartPtr m_collapser; + MEM_SmartPtr > m_heap; + MEM_SmartPtr m_quadric_editor; + + bool m_is_armed; + + // arguments to New(...) + //////////////////////// + + LOD_ManMesh2 & m_mesh; + LOD_ExternNormalEditor &m_face_editor; + LOD_ExternBufferEditor & m_extern_editor; + + // temporary buffers + //////////////////// + + std::vector m_deg_faces; + std::vector m_deg_edges; + std::vector m_deg_vertices; + + std::vector m_update_faces; + std::vector m_new_edges; + std::vector m_update_vertices; + + +}; + +#endif + diff --git a/intern/decimation/intern/LOD_Quadric.h b/intern/decimation/intern/LOD_Quadric.h new file mode 100644 index 00000000000..f06b0af65b0 --- /dev/null +++ b/intern/decimation/intern/LOD_Quadric.h @@ -0,0 +1,166 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_LOD_Quadric_h +#define NAN_INCLUDED_LOD_Quadric_h + +#include "MT_Vector3.h" +#include "MT_Matrix3x3.h" + + +class LOD_Quadric { + +private: + MT_Scalar a2, ab, ac, ad; + MT_Scalar b2, bc, bd; + MT_Scalar c2, cd; + MT_Scalar d2; + + void init(MT_Scalar a, MT_Scalar b, MT_Scalar c, MT_Scalar d); + +public: + + LOD_Quadric( + ) { + Clear(); + }; + + LOD_Quadric( + const MT_Vector3 & vec, + const MT_Scalar & offset + ) { + a2 = vec[0] *vec[0]; + b2 = vec[1] *vec[1]; + c2 = vec[2] *vec[2]; + + ab = vec[0]*vec[1]; + ac = vec[0]*vec[2]; + bc = vec[1]*vec[2]; + + MT_Vector3 temp = vec*offset; + ad = temp[0]; + bd = temp[1]; + cd = temp[2]; + + d2 = offset*offset; + }; + + MT_Matrix3x3 + Tensor( + ) const { + // return a symmetric matrix + + return MT_Matrix3x3( + a2,ab,ac, + ab,b2,bc, + ac,bc,c2 + ); + }; + + + MT_Vector3 + Vector( + ) const { + return MT_Vector3(ad, bd, cd); + }; + + void + Clear( + MT_Scalar val=0.0 + ) { + a2=ab=ac=ad=b2=bc=bd=c2=cd=d2=val; + }; + + LOD_Quadric & + operator=( + const LOD_Quadric& Q + ) { + + a2 = Q.a2; ab = Q.ab; ac = Q.ac; ad = Q.ad; + b2 = Q.b2; bc = Q.bc; bd = Q.bd; + c2 = Q.c2; cd = Q.cd; + d2 = Q.d2; + return *this; + }; + + LOD_Quadric& + operator+=( + const LOD_Quadric& Q + ) { + a2 += Q.a2; ab += Q.ab; ac += Q.ac; ad += Q.ad; + b2 += Q.b2; bc += Q.bc; bd += Q.bd; + c2 += Q.c2; cd += Q.cd; + d2 += Q.d2; + return *this; + }; + + LOD_Quadric& + operator*=( + const MT_Scalar & s + ) { + a2 *= s; ab *= s; ac *= s; ad *= s; + b2 *= s; bc *= s; bd *= s; + c2 *= s; cd *= s; + d2 *= s; + return *this; + }; + + + MT_Scalar + Evaluate( + const MT_Vector3 &v + ) const { + // compute the LOD_Quadric error + + return v[0]*v[0]*a2 + 2*v[0]*v[1]*ab + 2*v[0]*v[2]*ac + 2*v[0]*ad + +v[1]*v[1]*b2 + 2*v[1]*v[2]*bc + 2*v[1]*bd + +v[2]*v[2]*c2 + 2*v[2]*cd + + d2; + }; + + bool + Optimize( + MT_Vector3& v + ) const { + + MT_Scalar det = Tensor().determinant(); + if (MT_fuzzyZero(det)) { + return false; + } + + v = -((Tensor().inverse()) * Vector()); + return true; + }; + +}; + +#endif + diff --git a/intern/decimation/intern/LOD_QuadricEditor.cpp b/intern/decimation/intern/LOD_QuadricEditor.cpp new file mode 100644 index 00000000000..c1e5614b01d --- /dev/null +++ b/intern/decimation/intern/LOD_QuadricEditor.cpp @@ -0,0 +1,282 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "LOD_QuadricEditor.h" +#include "LOD_ExternNormalEditor.h" + +// Creation +/////////// + +using namespace std; + + +LOD_QuadricEditor:: +LOD_QuadricEditor( + LOD_ManMesh2 &mesh +) : + m_quadrics(NULL), + m_mesh(mesh) +{ +}; + + LOD_QuadricEditor * +LOD_QuadricEditor:: +New( + LOD_ManMesh2 &mesh +){ + //same number of quadrics as vertices in the mesh + + MEM_SmartPtr output(new LOD_QuadricEditor(mesh)); + + if (output == NULL) { + return NULL; + } + return output.Release(); +} + + +// Property editor interface +//////////////////////////// + + void +LOD_QuadricEditor:: +Remove( + std::vector &sorted_vertices +){ + vector & quadrics = *m_quadrics; + + vector::const_iterator it_start = sorted_vertices.begin(); + vector::const_iterator it_end = sorted_vertices.end(); + + for (; it_start != it_end; ++it_start) { + + if (quadrics.size() > 0) { + LOD_Quadric temp = quadrics[*it_start]; + + quadrics[*it_start] = quadrics.back(); + quadrics.back() = temp; + + quadrics.pop_back(); + } + } +}; + + +// Editor specific methods +////////////////////////// + + bool +LOD_QuadricEditor:: +BuildQuadrics( + LOD_ExternNormalEditor& normal_editor, + bool preserve_boundaries +){ + if (m_quadrics != NULL) delete(m_quadrics); + + m_quadrics =new vector (m_mesh.VertexSet().size()); + if (m_quadrics == NULL) return false; + + // iterate through the face set of the mesh + // compute a quadric based upon that face and + // add it to each of it's vertices quadrics. + + const vector &faces = m_mesh.FaceSet(); + const vector &verts = m_mesh.VertexSet(); + vector &edges = m_mesh.EdgeSet(); + + const vector &normals = normal_editor.Normals(); + vector::const_iterator normal_it = normals.begin(); + + vector::const_iterator face_it = faces.begin(); + vector::const_iterator face_end = faces.end(); + + vector & quadrics = *m_quadrics; + + + for (; face_it != face_end; ++face_it, ++normal_it) { + + MT_Vector3 normal = *normal_it; + MT_Scalar offset = -normal.dot(verts[face_it->m_verts[0]].pos); + + LOD_Quadric q(normal,offset); + + quadrics[face_it->m_verts[0]] += q; + quadrics[face_it->m_verts[1]] += q; + quadrics[face_it->m_verts[2]] += q; + } + + if (preserve_boundaries) { + + // iterate through the edge set and add a boundary quadric to + // each of the boundary edges vertices. + + vector::const_iterator edge_it = edges.begin(); + vector::const_iterator edge_end = edges.end(); + + for (; edge_it != edge_end; ++edge_it) { + if (edge_it->BoundaryEdge()) { + + // compute a plane perpendicular to the edge and the normal + // of the edges single polygon. + const MT_Vector3 & v0 = verts[edge_it->m_verts[0]].pos; + const MT_Vector3 & v1 = verts[edge_it->m_verts[1]].pos; + + MT_Vector3 edge_vector = v1 - v0; + + LOD_FaceInd edge_face = edge_it->OpFace(LOD_EdgeInd::Empty()); + edge_vector = edge_vector.cross(normals[edge_face]); + + if (!edge_vector.fuzzyZero()) { + edge_vector.normalize(); + + LOD_Quadric boundary_q(edge_vector, - edge_vector.dot(v0)); + boundary_q *= 100; + + quadrics[edge_it->m_verts[0]] += boundary_q; + quadrics[edge_it->m_verts[1]] += boundary_q; + } + } + } + } + + + // initiate the heap keys of the edges by computing the edge costs. + + vector::iterator edge_it = edges.begin(); + vector::const_iterator edge_end = edges.end(); + + for (; edge_it != edge_end; ++edge_it) { + + MT_Vector3 target = TargetVertex(*edge_it); + + LOD_Edge &e = *edge_it; + LOD_Quadric q0 = quadrics[e.m_verts[0]]; + const LOD_Quadric &q1 = quadrics[e.m_verts[1]]; + + e.HeapKey() = -float(q0.Evaluate(target) + q1.Evaluate(target)); + } + + return true; + +}; + + MT_Vector3 +LOD_QuadricEditor:: +TargetVertex( + LOD_Edge & e +){ + + // compute an edge contration target for edge ei + // this is computed by summing it's vertices quadrics and + // optimizing the result. + vector &verts = m_mesh.VertexSet(); + + vector &quadrics = *m_quadrics; + + LOD_VertexInd v0 = e.m_verts[0]; + LOD_VertexInd v1 = e.m_verts[1]; + + LOD_Quadric q0 = quadrics[v0]; + q0 += quadrics[v1]; + + MT_Vector3 result; + + if (q0.Optimize(result)) { + return result; + } else { + // the quadric was degenerate -> just take the average of + // v0 and v1 + + return ((verts[v0].pos + verts[v1].pos) * 0.5); + } +}; + + void +LOD_QuadricEditor:: +ComputeEdgeCosts( + vector &edges +){ + + // for each we compute the target vertex and then compute + // the quadric error e = Q1(v') + Q2(v') + vector &edge_set = m_mesh.EdgeSet(); + + vector &quadrics = *m_quadrics; + + vector::const_iterator edge_it = edges.begin(); + vector::const_iterator edge_end = edges.end(); + + for (; edge_it != edge_end; ++edge_it) { + + MT_Vector3 target = TargetVertex(edge_set[*edge_it]); + + LOD_Edge &e = edge_set[*edge_it]; + LOD_Quadric q0 = quadrics[e.m_verts[0]]; + const LOD_Quadric &q1 = quadrics[e.m_verts[1]]; + + e.HeapKey() = -float(q0.Evaluate(target) + q1.Evaluate(target)); + } +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/decimation/intern/LOD_QuadricEditor.h b/intern/decimation/intern/LOD_QuadricEditor.h new file mode 100644 index 00000000000..41e7d227d54 --- /dev/null +++ b/intern/decimation/intern/LOD_QuadricEditor.h @@ -0,0 +1,119 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_LOD_QuadricEditor_h +#define NAN_INCLUDED_LOD_QuadricEditor_h + +#include "MEM_NonCopyable.h" +#include "LOD_ManMesh2.h" +#include "MT_Vector3.h" +#include "LOD_Quadric.h" + +class LOD_ExternNormalEditor; + + +class LOD_QuadricEditor : public MEM_NonCopyable +{ + +public : + + // Creation + /////////// + + static + LOD_QuadricEditor * + New( + LOD_ManMesh2 &mesh + ); + + // Property editor interface + //////////////////////////// + + void + Remove( + std::vector &sorted_vertices + ); + + void + Update( + std::vector &sorted_vertices + ); + + + std::vector & + Quadrics( + ) const { + return *m_quadrics; + }; + + + // Editor specific methods + ////////////////////////// + + bool + BuildQuadrics( + LOD_ExternNormalEditor& normal_editor, + bool preserve_boundaries + ); + + + void + ComputeEdgeCosts( + std::vector &edges + ); + + MT_Vector3 + TargetVertex( + LOD_Edge &e + ); + + ~LOD_QuadricEditor( + ){ + delete(m_quadrics); + }; + + +private : + + std::vector * m_quadrics; + + LOD_ManMesh2 &m_mesh; + +private : + + LOD_QuadricEditor(LOD_ManMesh2 &mesh); + + + +}; + +#endif + diff --git a/intern/decimation/intern/LOD_decimation.cpp b/intern/decimation/intern/LOD_decimation.cpp new file mode 100644 index 00000000000..0f6500b829d --- /dev/null +++ b/intern/decimation/intern/LOD_decimation.cpp @@ -0,0 +1,158 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +// implementation of external c api +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "../extern/LOD_decimation.h" +#include "LOD_DecimationClass.h" + +using namespace std; + + int +LOD_LoadMesh( + LOD_Decimation_InfoPtr info +) { + if (info == NULL) return 0; + if ( + info->vertex_buffer == NULL || + info->vertex_normal_buffer == NULL || + info->triangle_index_buffer == NULL + ) { + return 0; + } + + + // create the intern object to hold all + // the decimation classes + + MEM_SmartPtr intern(LOD_DecimationClass::New(info)); + + if (intern == NULL) return 0; + + MEM_SmartPtr > intern_vertex_buffer(new vector(info->vertex_num)); + if (intern_vertex_buffer == NULL) return 0; + + vector::iterator intern_vertex_it(intern_vertex_buffer->begin()); + + // now load in the vertices to the mesh + + const int vertex_stride = 3; + + float * vertex_ptr = info->vertex_buffer; + const float * vertex_end = vertex_ptr + info->vertex_num*vertex_stride; + + LOD_ManMesh2 &mesh = intern->Mesh(); + + for (;vertex_ptr < vertex_end; vertex_ptr += vertex_stride,++intern_vertex_it) { + intern_vertex_it->pos = MT_Vector3(vertex_ptr); + } + + mesh.SetVertices(intern_vertex_buffer); + + // load in the triangles + + const int triangle_stride = 3; + + int * triangle_ptr = info->triangle_index_buffer; + const int * triangle_end = triangle_ptr + info->face_num*triangle_stride; + + try { + + for (;triangle_ptr < triangle_end; triangle_ptr += triangle_stride) { + mesh.AddTriangle(triangle_ptr); + } + } + + catch (...) { + return 0; + } + + // ok we have built the mesh + + intern->m_e_decimation_state = LOD_DecimationClass::e_loaded; + + info->intern = (void *) (intern.Release()); + + return 1; +} + + int +LOD_PreprocessMesh( + LOD_Decimation_InfoPtr info +) { + if (info == NULL) return 0; + if (info->intern == NULL) return 0; + + LOD_DecimationClass *intern = (LOD_DecimationClass *) info->intern; + if (intern->m_e_decimation_state != LOD_DecimationClass::e_loaded) return 0; + + // arm the various internal classes so that we are ready to step + // through decimation + + intern->FaceEditor().BuildNormals(); + if (intern->Decimator().Arm() == false) return 0; + + // ok preprocessing done + intern->m_e_decimation_state = LOD_DecimationClass::e_preprocessed; + + return 1; +} + + int +LOD_CollapseEdge( + LOD_Decimation_InfoPtr info +){ + if (info == NULL) return 0; + if (info->intern == NULL) return 0; + LOD_DecimationClass *intern = (LOD_DecimationClass *) info->intern; + if (intern->m_e_decimation_state != LOD_DecimationClass::e_preprocessed) return 0; + + bool step_result = intern->Decimator().Step(); + + return step_result == true ? 1 : 0; +} + + + int +LOD_FreeDecimationData( + LOD_Decimation_InfoPtr info +){ + if (info == NULL) return 0; + if (info->intern == NULL) return 0; + LOD_DecimationClass *intern = (LOD_DecimationClass *) info->intern; + delete(intern); + info->intern = NULL; + return 1; +} + diff --git a/intern/decimation/intern/Makefile b/intern/decimation/intern/Makefile new file mode 100644 index 00000000000..d7c9d89d9c7 --- /dev/null +++ b/intern/decimation/intern/Makefile @@ -0,0 +1,45 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# decimation intern Makefile +# + +LIBNAME = decimation +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(NAN_LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I$(NAN_MEMUTIL)/include +CPPFLAGS += -I$(NAN_CONTAINER)/include + + diff --git a/intern/decimation/make/msvc_6_0/decimation.dsp b/intern/decimation/make/msvc_6_0/decimation.dsp new file mode 100644 index 00000000000..013e9e077fb --- /dev/null +++ b/intern/decimation/make/msvc_6_0/decimation.dsp @@ -0,0 +1,186 @@ +# Microsoft Developer Studio Project File - Name="decimation" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=decimation - 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 "decimation.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 "decimation.mak" CFG="decimation - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "decimation - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "decimation - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "decimation - 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 "..\..\..\..\obj\windows\intern\decimation" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\decimation" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /Ob2 /I "..\..\..\..\..\lib\windows\container\include\\" /I "..\..\..\..\..\lib\windows\memutil\include\\" /I "..\..\..\..\..\lib\windows\moto\include\\" /I"..\..\..\moto\include" /I"..\..\..\memutil" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\decimation\libdecimation.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\extern\*.h ..\..\..\..\..\lib\windows\decimation\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\decimation\*.lib ..\..\..\..\..\lib\windows\decimation\lib\*.a ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "decimation - 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 "..\..\..\..\obj\windows\intern\decimation\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\decimation\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W4 /Gm /GX /ZI /Od /I "..\..\..\..\..\lib\windows\container\include\\" /I "..\..\..\..\..\lib\windows\memutil\include\\" /I "..\..\..\..\..\lib\windows\moto\include\\" /I"..\..\..\moto\include" /I"..\..\..\memutil" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\decimation\debug\libdecimation.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\extern\*.h ..\..\..\..\..\lib\windows\decimation\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\decimation\debug\*.lib ..\..\..\..\..\lib\windows\decimation\lib\debug\*.a ECHO Copying Debug info. XCOPY /Y ..\..\..\..\obj\windows\intern\decimation\debug\vc60.* ..\..\..\..\..\lib\windows\decimation\lib\debug\ ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "decimation - Win32 Release" +# Name "decimation - Win32 Debug" +# Begin Group "intern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\intern\LOD_decimation.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_DecimationClass.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_EdgeCollapser.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_EdgeCollapser.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_ExternBufferEditor.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_ExternNormalEditor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_ExternNormalEditor.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_FaceNormalEditor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_FaceNormalEditor.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_ManMesh2.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_ManMesh2.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_MeshBounds.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_MeshException.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_MeshPrimitives.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_MeshPrimitives.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_QSDecimator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_QSDecimator.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_Quadric.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_QuadricEditor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_QuadricEditor.h +# End Source File +# End Group +# Begin Group "extern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\extern\LOD_decimation.h +# End Source File +# End Group +# End Target +# End Project diff --git a/intern/decimation/make/msvc_6_0/decimation.dsw b/intern/decimation/make/msvc_6_0/decimation.dsw new file mode 100644 index 00000000000..f874b324725 --- /dev/null +++ b/intern/decimation/make/msvc_6_0/decimation.dsw @@ -0,0 +1,33 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "decimation"=.\decimation.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + + + + + diff --git a/intern/decimation/make/msvc_7_0/decimation.sln b/intern/decimation/make/msvc_7_0/decimation.sln new file mode 100644 index 00000000000..8760ff74f8a --- /dev/null +++ b/intern/decimation/make/msvc_7_0/decimation.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "decimation", "decimation.vcproj", "{95ED18F3-8A76-4DB9-BDAC-12C7592EFE44}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {95ED18F3-8A76-4DB9-BDAC-12C7592EFE44}.Debug.ActiveCfg = Debug|Win32 + {95ED18F3-8A76-4DB9-BDAC-12C7592EFE44}.Debug.Build.0 = Debug|Win32 + {95ED18F3-8A76-4DB9-BDAC-12C7592EFE44}.Release.ActiveCfg = Release|Win32 + {95ED18F3-8A76-4DB9-BDAC-12C7592EFE44}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/intern/decimation/make/msvc_7_0/decimation.vcproj b/intern/decimation/make/msvc_7_0/decimation.vcproj new file mode 100644 index 00000000000..41bd355db5d --- /dev/null +++ b/intern/decimation/make/msvc_7_0/decimation.vcproj @@ -0,0 +1,321 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/elbeem/CMakeLists.txt b/intern/elbeem/CMakeLists.txt new file mode 100644 index 00000000000..86a60180b05 --- /dev/null +++ b/intern/elbeem/CMakeLists.txt @@ -0,0 +1,40 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC ${PNG_INC} ${ZLIB_INC} ${SDL_INC}) + +FILE(GLOB SRC intern/*.cpp) + +ADD_DEFINITIONS(-DNOGUI -DELBEEM_BLENDER=1) +IF(WINDOWS) + ADD_DEFINITIONS(-DUSE_MSVC6FIXES) +ENDIF(WINDOWS) + +BLENDERLIB_NOLIST(bf_elbeem "${SRC}" "${INC}") +#, libtype='blender', priority=0 ) diff --git a/intern/elbeem/COPYING b/intern/elbeem/COPYING new file mode 100644 index 00000000000..2600c731161 --- /dev/null +++ b/intern/elbeem/COPYING @@ -0,0 +1,358 @@ + All code distributed as part of El'Beem is covered by the following + version of the GNU General Public License. + + 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. + + Copyright (c) 2003-2005 Nils Thuerey. All rights reserved. + + + + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +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 Program or any portion +of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +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 Program, 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 Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) 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; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, 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 executable. However, as a +special exception, the source code 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. + +If distribution of executable or 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 counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program 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. + + 5. 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 Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program 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 to +this License. + + 7. 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 Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program 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 Program. + +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. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program 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. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 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 Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, 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 + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. 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 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. + + 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 +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 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision 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, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This 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 Library General +Public License instead of this License. diff --git a/intern/elbeem/COPYING_trimesh2 b/intern/elbeem/COPYING_trimesh2 new file mode 100644 index 00000000000..a214195fd60 --- /dev/null +++ b/intern/elbeem/COPYING_trimesh2 @@ -0,0 +1,303 @@ +This distribution includes source to "miniball", "freeGLUT", +and "GLUI", which are covered under their own licenses. + +All other code distributed as part of trimesh2 is covered +by the following license: + + +Copyright (c) 2004 Szymon Rusinkiewicz. +All rights reserved. + +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. + + + + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 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. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +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 Program or any portion +of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +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 Program, 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 Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) 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; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, 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 executable. However, as a +special exception, the source code 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. + +If distribution of executable or 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 counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program 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. + + 5. 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 Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program 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 to +this License. + + 7. 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 Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program 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 Program. + +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. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program 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. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 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 Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, 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 + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. 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 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. + + END OF TERMS AND CONDITIONS diff --git a/intern/elbeem/Makefile b/intern/elbeem/Makefile new file mode 100644 index 00000000000..3e0333fb3cd --- /dev/null +++ b/intern/elbeem/Makefile @@ -0,0 +1,58 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# elbeem main makefile. +# + +include nan_definitions.mk + +unexport NAN_QUIET + +LIBNAME = elbeem +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +#not ready yet TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_ELBEEM) ] || mkdir $(NAN_ELBEEM) + @[ -d $(NAN_ELBEEM)/include ] || mkdir $(NAN_ELBEEM)/include + @[ -d $(NAN_ELBEEM)/lib ] || mkdir $(NAN_ELBEEM)/lib + @[ -d $(NAN_ELBEEM)/lib/debug ] || mkdir $(NAN_ELBEEM)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libelbeem.a $(NAN_ELBEEM)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libelbeem.a $(NAN_ELBEEM)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_ELBEEM)/lib/libelbeem.a + ranlib $(NAN_ELBEEM)/lib/debug/libelbeem.a +endif + @../tools/cpifdiff.sh extern/*.h $(NAN_ELBEEM)/include/ + diff --git a/intern/elbeem/SConscript b/intern/elbeem/SConscript new file mode 100644 index 00000000000..bb6637ba32d --- /dev/null +++ b/intern/elbeem/SConscript @@ -0,0 +1,13 @@ +#!/usr/bin/python +import sys +import os +Import('env') + +sources = env.Glob('intern/*.cpp') + +defs = 'NOGUI ELBEEM_BLENDER=1' +if env['OURPLATFORM']=='win32-vc': + defs += ' USE_MSVC6FIXES' +incs = env['BF_PNG_INC'] + ' ' + env['BF_ZLIB_INC'] + ' ' +env['BF_SDL_INC'] + +env.BlenderLib ('bf_elbeem', sources, Split(incs), Split(defs), libtype='blender', priority=0 ) diff --git a/intern/elbeem/extern/LBM_fluidsim.h b/intern/elbeem/extern/LBM_fluidsim.h new file mode 100644 index 00000000000..0f7e0e1ef5d --- /dev/null +++ b/intern/elbeem/extern/LBM_fluidsim.h @@ -0,0 +1,77 @@ +/** + * BKE_fluidsim.h + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef LBM_FLUIDSIM_H +#define LBM_FLUIDSIM_H + +struct Mesh; +struct DerivedMesh; +struct Object; +struct fluidsimDerivedMesh; + +extern double fluidsimViscosityPreset[6]; +extern char* fluidsimViscosityPresetString[6]; + +/* allocates and initializes fluidsim data */ +struct FluidsimSettings* fluidsimSettingsNew(struct Object *srcob); + +/* frees internal data itself */ +void fluidsimSettingsFree(struct FluidsimSettings* sb); + +/* duplicate internal data */ +struct FluidsimSettings* fluidsimSettingsCopy(struct FluidsimSettings* sb); + +/* export blender geometry to fluid solver */ +void fluidsimBake(struct Object* ob); + +/* read & write bobj / bobj.gz files (e.g. for fluid sim surface meshes) */ +void writeBobjgz(char *filename, struct Object *ob, int useGlobalCoords, int append, float time); +struct Mesh* readBobjgz(char *filename, struct Mesh *orgmesh, float* bbstart, float *bbsize); + +/* create derived mesh for fluid sim objects */ +// WARNING - currently implemented in DerivedMesh.c! +void loadFluidsimMesh(struct Object *srcob, int useRenderParams); + +/* run simulation with given config file */ +// WARNING - implemented in intern/elbeem/blendercall.cpp +int performElbeemSimulation(char *cfgfilename); + +/* init axis aligned BB for mesh object */ +// implemented in source/blender/blenkernel/intern/DerivedMesh.c +void fluidsimGetAxisAlignedBB(struct Mesh *mesh, float obmat[][4], + /*RET*/ float start[3], /*RET*/ float size[3], /*RET*/ struct Mesh **bbmesh ); + + +#endif + + diff --git a/intern/elbeem/extern/elbeem.h b/intern/elbeem/extern/elbeem.h new file mode 100644 index 00000000000..b3feda8bbe8 --- /dev/null +++ b/intern/elbeem/extern/elbeem.h @@ -0,0 +1,240 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * All code distributed as part of El'Beem is covered by the version 2 of the + * GNU General Public License. See the file COPYING for details. + * Copyright 2003-2006 Nils Thuerey + * + * API header + */ +#ifndef ELBEEM_API_H +#define ELBEEM_API_H + + +// simulation run callback function type (elbeemSimulationSettings->runsimCallback) +// best use with FLUIDSIM_CBxxx defines below. +// >parameters +// return values: 0=continue, 1=stop, 2=abort +// data pointer: user data pointer from elbeemSimulationSettings->runsimUserData +// status integer: 1=running simulation, 2=new frame saved +// frame integer: if status is 1, contains current frame number +typedef int (*elbeemRunSimulationCallback)(void *data, int status, int frame); +#define FLUIDSIM_CBRET_CONTINUE 0 +#define FLUIDSIM_CBRET_STOP 1 +#define FLUIDSIM_CBRET_ABORT 2 +#define FLUIDSIM_CBSTATUS_STEP 1 +#define FLUIDSIM_CBSTATUS_NEWFRAME 2 + + +// global settings for the simulation +typedef struct elbeemSimulationSettings { + /* version number */ + short version; + /* id number of simulation domain, needed if more than a + * single domain should be simulated */ + short domainId; + + /* geometrical extent */ + float geoStart[3], geoSize[3]; + + /* resolutions */ + short resolutionxyz; + short previewresxyz; + /* size of the domain in real units (meters along largest resolution x,y,z extent) */ + float realsize; + + /* fluid properties */ + double viscosity; + /* gravity strength */ + float gravity[3]; + /* anim start end time */ + float animStart, aniFrameTime; + /* no. of frames to simulate & output */ + short noOfFrames; + /* g star param (LBM compressibility) */ + float gstar; + /* activate refinement? */ + short maxRefine; + /* probability for surface particle generation (0.0=off) */ + float generateParticles; + /* amount of tracer particles to generate (0=off) */ + int numTracerParticles; + + /* store output path, and file prefix for baked fluid surface */ + char outputPath[160+80]; + + /* channel for frame time, visc & gravity animations */ + int channelSizeFrameTime; + float *channelFrameTime; + int channelSizeViscosity; + float *channelViscosity; + int channelSizeGravity; + float *channelGravity; // vector + + /* boundary types and settings for domain walls */ + short domainobsType; + float domainobsPartslip; + /* generate speed vectors for vertices (e.g. for image based motion blur)*/ + short generateVertexVectors; + /* strength of surface smoothing */ + float surfaceSmoothing; + /* no. of surface subdivisions */ + int surfaceSubdivs; + + /* global transformation to apply to fluidsim mesh */ + float surfaceTrafo[4*4]; + + /* development variables, testing for upcoming releases...*/ + float farFieldSize; + + /* callback function to notify calling program of performed simulation steps + * or newly available frame data, if NULL it is ignored */ + elbeemRunSimulationCallback runsimCallback; + /* pointer passed to runsimCallback for user data storage */ + void* runsimUserData; + +} elbeemSimulationSettings; + + +// defines for elbeemMesh->type below +#define OB_FLUIDSIM_FLUID 4 +#define OB_FLUIDSIM_OBSTACLE 8 +#define OB_FLUIDSIM_INFLOW 16 +#define OB_FLUIDSIM_OUTFLOW 32 + +// defines for elbeemMesh->obstacleType below +#define FLUIDSIM_OBSTACLE_NOSLIP 1 +#define FLUIDSIM_OBSTACLE_PARTSLIP 2 +#define FLUIDSIM_OBSTACLE_FREESLIP 3 + +#define OB_VOLUMEINIT_VOLUME 1 +#define OB_VOLUMEINIT_SHELL 2 +#define OB_VOLUMEINIT_BOTH (OB_VOLUMEINIT_SHELL|OB_VOLUMEINIT_VOLUME) + +// a single mesh object +typedef struct elbeemMesh { + /* obstacle,fluid or inflow... */ + short type; + /* id of simulation domain it belongs to */ + short parentDomainId; + + /* vertices */ + int numVertices; + float *vertices; // = float[n][3]; + /* animated vertices */ + int channelSizeVertices; + float *channelVertices; // = float[channelSizeVertices* (n*3+1) ]; + + /* triangles */ + int numTriangles; + int *triangles; // = int[][3]; + + /* animation channels */ + int channelSizeTranslation; + float *channelTranslation; + int channelSizeRotation; + float *channelRotation; + int channelSizeScale; + float *channelScale; + + /* active channel */ + int channelSizeActive; + float *channelActive; + /* initial velocity channel (e.g. for inflow) */ + int channelSizeInitialVel; + float *channelInitialVel; // vector + /* use initial velocity in object coordinates? (e.g. for rotation) */ + short localInivelCoords; + /* boundary types and settings */ + short obstacleType; + float obstaclePartslip; + /* amount of force transfer from fluid to obj, 0=off, 1=normal */ + float obstacleImpactFactor; + /* init volume, shell or both? use OB_VOLUMEINIT_xxx defines above */ + short volumeInitType; + + /* name of the mesh, mostly for debugging */ + char *name; +} elbeemMesh; + +// API functions + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + + +// reset elbeemSimulationSettings struct with defaults +void elbeemResetSettings(struct elbeemSimulationSettings*); + +// start fluidsim init (returns !=0 upon failure) +int elbeemInit(void); + +// start fluidsim init (returns !=0 upon failure) +int elbeemAddDomain(struct elbeemSimulationSettings*); + +// get failure message during simulation or init +// if an error occured (the string is copied into buffer, +// max. length = 256 chars ) +void elbeemGetErrorString(char *buffer); + +// reset elbeemMesh struct with zeroes +void elbeemResetMesh(struct elbeemMesh*); + +// add mesh as fluidsim object +int elbeemAddMesh(struct elbeemMesh*); + +// do the actual simulation +int elbeemSimulate(void); + +// continue a previously stopped simulation +int elbeemContinueSimulation(void); + + +// helper functions + +// simplify animation channels +// returns if the channel and its size changed +int elbeemSimplifyChannelFloat(float *channel, int *size); +int elbeemSimplifyChannelVec3(float *channel, int *size); + +// helper functions implemented in utilities.cpp + +/* set elbeem debug output level (0=off to 10=full on) */ +void elbeemSetDebugLevel(int level); +/* elbeem debug output function, prints if debug level >0 */ +void elbeemDebugOut(char *msg); + +/* estimate how much memory a given setup will require */ +double elbeemEstimateMemreq(int res, + float sx, float sy, float sz, + int refine, char *retstr); + + + +#ifdef __cplusplus +} +#endif // __cplusplus + + + +/******************************************************************************/ +// internal defines, do not use for initializing elbeemMesh +// structs, for these use OB_xxx defines above + +/*! fluid geometry init types */ +#define FGI_FLAGSTART 16 +#define FGI_FLUID (1<<(FGI_FLAGSTART+ 0)) +#define FGI_NO_FLUID (1<<(FGI_FLAGSTART+ 1)) +#define FGI_BNDNO (1<<(FGI_FLAGSTART+ 2)) +#define FGI_BNDFREE (1<<(FGI_FLAGSTART+ 3)) +#define FGI_BNDPART (1<<(FGI_FLAGSTART+ 4)) +#define FGI_NO_BND (1<<(FGI_FLAGSTART+ 5)) +#define FGI_MBNDINFLOW (1<<(FGI_FLAGSTART+ 6)) +#define FGI_MBNDOUTFLOW (1<<(FGI_FLAGSTART+ 7)) + +// all boundary types at once +#define FGI_ALLBOUNDS ( FGI_BNDNO | FGI_BNDFREE | FGI_BNDPART | FGI_MBNDINFLOW | FGI_MBNDOUTFLOW ) + + +#endif // ELBEEM_API_H diff --git a/intern/elbeem/intern/Makefile b/intern/elbeem/intern/Makefile new file mode 100644 index 00000000000..49f0b936e6b --- /dev/null +++ b/intern/elbeem/intern/Makefile @@ -0,0 +1,53 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# elbeem intern Makefile +# + +LIBNAME = elbeem +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +unexport NAN_QUIET + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -DNOGUI -DELBEEM_BLENDER +CPPFLAGS += -I. +CPPFLAGS += -I../extern +CPPFLAGS += $(NAN_SDLCFLAGS) +CPPFLAGS += -I$(NAN_PNG)/include +CPPFLAGS += -I$(NAN_PNG)/include/libpng + +# zlib +ifeq ($(OS),$(findstring $(OS), "solaris windows")) + CPPFLAGS += -I$(NAN_ZLIB)/include +endif diff --git a/intern/elbeem/intern/attributes.cpp b/intern/elbeem/intern/attributes.cpp new file mode 100644 index 00000000000..8e337a92a4e --- /dev/null +++ b/intern/elbeem/intern/attributes.cpp @@ -0,0 +1,359 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * DEPRECATED - replaced by elbeem API, only channels are still used + * + *****************************************************************************/ + +#include "attributes.h" +#include "ntl_matrices.h" +#include "elbeem.h" + + + +/****************************************************************************** + * attribute conversion functions + *****************************************************************************/ + +bool Attribute::initChannel(int elemSize) { + elemSize=0; // remove warning + return false; +} +string Attribute::getAsString(bool debug) { + debug=false; // remove warning + return string(""); +} +int Attribute::getAsInt() { + return 0; +} +bool Attribute::getAsBool() { + return false; +} +double Attribute::getAsFloat() { + return 0.; +} +ntlVec3d Attribute::getAsVec3d() { + return ntlVec3d(0.); +} +void Attribute::getAsMat4Gfx(ntlMat4Gfx *mat) { + mat=NULL; // remove warning +} +string Attribute::getCompleteString() { + return string(""); +} + + +/****************************************************************************** + * channel returns + *****************************************************************************/ + +AnimChannel Attribute::getChannelFloat() { + return AnimChannel(); +} +AnimChannel Attribute::getChannelInt() { + return AnimChannel(); +} +AnimChannel Attribute::getChannelVec3d() { + return AnimChannel(); +} +AnimChannel +Attribute::getChannelSetVec3f() { + return AnimChannel(); +} + +/****************************************************************************** + * check if there were unknown params + *****************************************************************************/ +bool AttributeList::checkUnusedParams() { + return false; +} +void AttributeList::setAllUsed() { +} + +/****************************************************************************** + * Attribute list read functions + *****************************************************************************/ +int AttributeList::readInt(string name, int defaultValue, string source,string target, bool needed) { + name=source=target=string(""); needed=false; // remove warning + return defaultValue; +} +bool AttributeList::readBool(string name, bool defaultValue, string source,string target, bool needed) { + name=source=target=string(""); needed=false; // remove warning + return defaultValue; +} +double AttributeList::readFloat(string name, double defaultValue, string source,string target, bool needed) { + name=source=target=string(""); needed=false; // remove warning + return defaultValue; +} +string AttributeList::readString(string name, string defaultValue, string source,string target, bool needed) { + name=source=target=string(""); needed=false; // remove warning + return defaultValue; +} +ntlVec3d AttributeList::readVec3d(string name, ntlVec3d defaultValue, string source,string target, bool needed) { + name=source=target=string(""); needed=false; // remove warning + return defaultValue; +} + +void AttributeList::readMat4Gfx(string name, ntlMat4Gfx defaultValue, string source,string target, bool needed, ntlMat4Gfx *mat) { + *mat = defaultValue; + name=source=target=string(""); needed=false; mat=NULL; // remove warning +} + +// set that a parameter can be given, and will be ignored... +bool AttributeList::ignoreParameter(string name, string source) { + name=source=(""); // remove warning + return false; +} + +// read channels +AnimChannel AttributeList::readChannelInt(string name, int defaultValue, string source, string target, bool needed) { + name=source=target=string(""); needed=false; // remove warning + return AnimChannel(defaultValue); +} +AnimChannel AttributeList::readChannelFloat(string name, double defaultValue, string source, string target, bool needed ) { + name=source=target=string(""); needed=false; // remove warning + return AnimChannel(defaultValue); +} +AnimChannel AttributeList::readChannelVec3d(string name, ntlVec3d defaultValue, string source, string target, bool needed ) { + name=source=target=string(""); needed=false; // remove warning + return AnimChannel(defaultValue); +} +AnimChannel AttributeList::readChannelSetVec3f(string name, ntlSetVec3f defaultValue, string source, string target, bool needed) { + name=source=target=string(""); needed=false; // remove warning + return AnimChannel(defaultValue); +} +AnimChannel AttributeList::readChannelSinglePrecFloat(string name, float defaultValue, string source, string target, bool needed ) { + name=source=target=string(""); needed=false; // remove warning + return AnimChannel(defaultValue); +} +AnimChannel AttributeList::readChannelVec3f(string name, ntlVec3f defaultValue, string source, string target, bool needed) { + name=source=target=string(""); needed=false; // remove warning + return AnimChannel(defaultValue); +} + +/****************************************************************************** + * destructor + *****************************************************************************/ +AttributeList::~AttributeList() { +}; + + +/****************************************************************************** + * debugging + *****************************************************************************/ + +//! debug function, prints value +void Attribute::print() { +} + +//! debug function, prints all attribs +void AttributeList::print() { +} + + +/****************************************************************************** + * import attributes from other attribute list + *****************************************************************************/ +void AttributeList::import(AttributeList *oal) { + oal=NULL; // remove warning +} + + +/****************************************************************************** + * channel max finding + *****************************************************************************/ +ntlVec3f channelFindMaxVf (AnimChannel channel) { + ntlVec3f ret(0.0); + float maxLen = 0.0; + for(size_t i=0; imaxLen) { ret=channel.accessValues()[i]; maxLen=nlen; } + } + return ret; +} +ntlVec3d channelFindMaxVd (AnimChannel channel) { + ntlVec3d ret(0.0); + float maxLen = 0.0; + for(size_t i=0; imaxLen) { ret=channel.accessValues()[i]; maxLen=nlen; } + } + return ret; +} +int channelFindMaxi (AnimChannel channel) { + int ret = 0; + float maxLen = 0.0; + for(size_t i=0; imaxLen) { ret= (int)channel.accessValues()[i]; maxLen=nlen; } + } + return ret; +} +float channelFindMaxf (AnimChannel channel) { + float ret = 0.0; + float maxLen = 0.0; + for(size_t i=0; imaxLen) { ret=channel.accessValues()[i]; maxLen=nlen; } + } + return ret; +} +double channelFindMaxd (AnimChannel channel) { + double ret = 0.0; + float maxLen = 0.0; + for(size_t i=0; imaxLen) { ret=channel.accessValues()[i]; maxLen=nlen; } + } + return ret; +} + +/****************************************************************************** + // unoptimized channel simplification functions, use elbeem.cpp functions + // warning - currently only with single precision + *****************************************************************************/ + +template +static bool channelSimplifyScalarT(AnimChannel &channel) { + int size = channel.getSize(); + if(size<=1) return false; + float *nchannel = new float[2*size]; + // convert to array + for(size_t i=0; i vals; + vector times; + for(int i=0; i(vals, times); + } + delete [] nchannel; + return ret; +} +bool channelSimplifyi (AnimChannel &channel) { return channelSimplifyScalarT(channel); } +bool channelSimplifyf (AnimChannel &channel) { return channelSimplifyScalarT(channel); } +bool channelSimplifyd (AnimChannel &channel) { return channelSimplifyScalarT(channel); } +template +static bool channelSimplifyVecT(AnimChannel &channel) { + int size = channel.getSize(); + if(size<=1) return false; + float *nchannel = new float[4*size]; + // convert to array + for(size_t i=0; i vals; + vector times; + for(int i=0; i(vals, times); + } + delete [] nchannel; + return ret; +} +bool channelSimplifyVf (AnimChannel &channel) { + return channelSimplifyVecT(channel); +} +bool channelSimplifyVd (AnimChannel &channel) { + return channelSimplifyVecT(channel); +} + +//! debug function, prints channel as string +template +string AnimChannel::printChannel() { + std::ostringstream ostr; + ostr << " CHANNEL #"<< mValue.size() <<" = { "; + for(size_t i=0;i tmp1; + AnimChannel< double > tmp2; + AnimChannel< string > tmp3; + AnimChannel< ntlVector3Dim > tmp4; + AnimChannel< ntlVector3Dim > tmp5; + tmp1.debugPrintChannel(); + tmp2.debugPrintChannel(); + tmp3.debugPrintChannel(); + tmp4.debugPrintChannel(); + tmp5.debugPrintChannel(); +} + + +ntlSetVec3f::ntlSetVec3f(double v ) { + mVerts.clear(); + mVerts.push_back( ntlVec3f(v) ); +} +const ntlSetVec3f& +ntlSetVec3f::operator=(double v ) { + mVerts.clear(); + mVerts.push_back( ntlVec3f(v) ); + return *this; +} + +std::ostream& operator<<( std::ostream& os, const ntlSetVec3f& vs ) { + os<< "{"; + for(int j=0;j<(int)vs.mVerts.size();j++) os< class ntlMatrix4x4; +class ntlSetVec3f; +std::ostream& operator<<( std::ostream& os, const ntlSetVec3f& i ); + + + +//! An animated attribute channel +template +class AnimChannel +{ + public: + // default constructor + AnimChannel() : + mValue(), mTimes() { mInited = false; debugPrintChannel(); } + + // null init constructor + AnimChannel(Scalar null) : + mValue(1), mTimes(1) { mValue[0]=null; mTimes[0]=0.0; mInited = true; debugPrintChannel(); } + + // proper init + AnimChannel(vector &v, vector &t) : + mValue(v), mTimes(t) { mInited = true; debugPrintChannel(); } + + // desctructor, nothing to do + ~AnimChannel() { }; + + // get interpolated value at time t + Scalar get(double t) const { + if(!mInited) { Scalar null; null=(Scalar)(0.0); return null; } + if(t<=mTimes[0]) { return mValue[0]; } + if(t>=mTimes[mTimes.size()-1]) { return mValue[mTimes.size()-1]; } + for(size_t i=0; it)) { + // interpolate + double d = mTimes[i+1]-mTimes[i]; + double f = (t-mTimes[i])/d; + //return (Scalar)(mValue[i] * (1.0-f) + mValue[i+1] * f); + Scalar ret,tmp; + ret = mValue[i]; + ret *= 1.-f; + tmp = mValue[i+1]; + tmp *= f; + ret += tmp; + return ret; + } + } + // whats this...? + return mValue[0]; + }; + + // get uninterpolated value at time t + Scalar getConstant(double t) const { + //errMsg("DEBB","getc"<=mTimes[mTimes.size()-1]) { return mValue[mTimes.size()-1]; } + for(size_t i=0; it)) { return mValue[i]; } + } + // whats this...? + return mValue[0]; + }; + + // reset to null value + void reset(Scalar null) { + mValue.clear(); + mTimes.clear(); + mValue.push_back(null); + mTimes.push_back(0.0); + } + + //! debug function, prints channel as string + string printChannel(); + //! debug function, prints to stdout if DEBUG_CHANNELS flag is enabled, used in constructors + void debugPrintChannel(); + //! valid init? + bool isInited() const { return mInited; } + + //! get number of entries (value and time sizes have to be equal) + int getSize() const { return mValue.size(); }; + //! raw access of value vector + vector &accessValues() { return mValue; } + //! raw access of time vector + vector &accessTimes() { return mTimes; } + + protected: + + /*! inited at least once? */ + bool mInited; + /*! anim channel attribute values */ + vector mValue; + /*! anim channel attr times */ + vector mTimes; +}; + + +// helper class (not templated) for animated meshes +class ntlSetVec3f { + public: + ntlSetVec3f(): mVerts() {}; + ntlSetVec3f(double v); + ntlSetVec3f(vector &v) { mVerts = v; }; + + const ntlSetVec3f& operator=(double v ); + ntlSetVec3f& operator+=( double v ); + ntlSetVec3f& operator+=( const ntlSetVec3f &v ); + ntlSetVec3f& operator*=( double v ); + ntlSetVec3f& operator*=( const ntlSetVec3f &v ); + + vector mVerts; +}; + + +// warning: DEPRECATED - replaced by elbeem API +class Attribute +{ + public: + Attribute(string mn, vector &value, int setline,bool channel) { + mn = string(""); setline=0; channel=false; value.clear(); // remove warnings + }; + Attribute(Attribute &a) { a.getCompleteString(); }; + ~Attribute() { }; + + void setUsed(bool set){ set=false; } + bool getUsed() { return true; } + void setIsChannel(bool set){ set=false; } + bool getIsChannel() { return false; } + + string getAsString(bool debug=false); + int getAsInt(); + bool getAsBool(); + double getAsFloat(); + ntlVec3d getAsVec3d(); + void getAsMat4Gfx(ntlMatrix4x4 *mat); + + AnimChannel getChannelInt(); + AnimChannel getChannelFloat(); + AnimChannel getChannelVec3d(); + AnimChannel getChannelSetVec3f(); + + string getCompleteString(); + void print(); + + protected: + + bool initChannel(int elemSize); +}; + + +// warning: DEPRECATED - replaced by elbeem API +//! The list of configuration attributes +class AttributeList +{ + public: + AttributeList(string name) { name=string(""); }; + ~AttributeList(); + void addAttr(string name, vector &value, int line, bool isChannel) { + name=string(""); value.clear(); line=0; isChannel=false; // remove warnings + }; + bool exists(string name) { name=string(""); return false; } + void setAllUsed(); + bool checkUnusedParams(); + void import(AttributeList *oal); + int readInt(string name, int defaultValue, string source,string target, bool needed); + bool readBool(string name, bool defaultValue, string source,string target, bool needed); + double readFloat(string name, double defaultValue, string source,string target, bool needed); + string readString(string name, string defaultValue, string source,string target, bool needed); + ntlVec3d readVec3d(string name, ntlVec3d defaultValue, string source,string target, bool needed); + void readMat4Gfx(string name, ntlMatrix4x4 defaultValue, string source,string target, bool needed, ntlMatrix4x4 *mat); + AnimChannel readChannelInt( string name, int defaultValue=0, string source=string("src"), string target=string("dst"), bool needed=false ); + AnimChannel readChannelFloat( string name, double defaultValue=0, string source=string("src"), string target=string("dst"), bool needed=false ); + AnimChannel readChannelVec3d( string name, ntlVec3d defaultValue=ntlVec3d(0.), string source=string("src"), string target=string("dst"), bool needed=false ); + AnimChannel readChannelSetVec3f(string name, ntlSetVec3f defaultValue=ntlSetVec3f(0.), string source=string("src"), string target=string("dst"), bool needed=false ); + AnimChannel readChannelVec3f( string name, ntlVec3f defaultValue=ntlVec3f(0.), string source=string("src"), string target=string("dst"), bool needed=false ); + AnimChannel readChannelSinglePrecFloat( string name, float defaultValue=0., string source=string("src"), string target=string("dst"), bool needed=false ); + bool ignoreParameter(string name, string source); + void print(); + protected: +}; + +ntlVec3f channelFindMaxVf (AnimChannel channel); +ntlVec3d channelFindMaxVd (AnimChannel channel); +int channelFindMaxi (AnimChannel channel); +float channelFindMaxf (AnimChannel channel); +double channelFindMaxd (AnimChannel channel); + +// unoptimized channel simplification functions, use elbeem.cpp functions +bool channelSimplifyVf (AnimChannel &channel); +bool channelSimplifyVd (AnimChannel &channel); +bool channelSimplifyi (AnimChannel &channel); +bool channelSimplifyf (AnimChannel &channel); +bool channelSimplifyd (AnimChannel &channel); + +//! output channel values? on=1/off=0 +#define DEBUG_PCHANNELS 0 + +//! debug function, prints to stdout if DEBUG_PCHANNELS flag is enabled, used in constructors +template +void AnimChannel::debugPrintChannel() { } + + +#define NTL_ATTRIBUTES_H +#endif + diff --git a/intern/elbeem/intern/elbeem.cpp b/intern/elbeem/intern/elbeem.cpp new file mode 100644 index 00000000000..b2779f51c3b --- /dev/null +++ b/intern/elbeem/intern/elbeem.cpp @@ -0,0 +1,386 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * All code distributed as part of El'Beem is covered by the version 2 of the + * GNU General Public License. See the file COPYING for details. + * Copyright 2003-2006 Nils Thuerey + * + * Main program functions + */ + +#include "elbeem.h" +#include "ntl_blenderdumper.h" +extern "C" void elbeemCheckDebugEnv(void); + +#include "ntl_world.h" +#include "ntl_geometrymodel.h" + +/*****************************************************************************/ +// region of interest global vars +// currently used by e.g. fsgr solver +double guiRoiSX = 0.0; +double guiRoiSY = 0.0; +double guiRoiSZ = 0.0; +double guiRoiEX = 1.0; +double guiRoiEY = 1.0; +double guiRoiEZ = 1.0; +int guiRoiMaxLev=6, guiRoiMinLev=0; + +//! global raytracer pointer (=world) +ntlWorld *gpWorld = NULL; + + +// API + +// reset elbeemSimulationSettings struct with defaults +extern "C" +void elbeemResetSettings(elbeemSimulationSettings *set) { + if(!set) return; + set->version = 3; + set->domainId = 0; + for(int i=0 ; i<3; i++) set->geoStart[i] = 0.0; + for(int i=0 ; i<3; i++) set->geoSize[i] = 1.0; + set->resolutionxyz = 64; + set->previewresxyz = 24; + set->realsize = 1.0; + set->viscosity = 0.000001; + + for(int i=0 ; i<2; i++) set->gravity[i] = 0.0; + set->gravity[2] = -9.81; + + set->animStart = 0; + set->aniFrameTime = 0.01; + set->noOfFrames = 10; + set->gstar = 0.005; + set->maxRefine = -1; + set->generateParticles = 0.0; + set->numTracerParticles = 0; + strcpy(set->outputPath,"./elbeemdata_"); + + set->channelSizeFrameTime=0; + set->channelFrameTime=NULL; + set->channelSizeViscosity=0; + set->channelViscosity=NULL; + set->channelSizeGravity=0; + set->channelGravity=NULL; + + set->domainobsType= FLUIDSIM_OBSTACLE_NOSLIP; + set->domainobsPartslip= 0.; + set->generateVertexVectors = 0; + set->surfaceSmoothing = 1.; + set->surfaceSubdivs = 1; + + set->farFieldSize = 0.; + set->runsimCallback = NULL; + set->runsimUserData = NULL; + + // init identity + for(int i=0; i<16; i++) set->surfaceTrafo[i] = 0.0; + for(int i=0; i<4; i++) set->surfaceTrafo[i*4+i] = 1.0; +} + +// start fluidsim init +extern "C" +int elbeemInit() { + setElbeemState( SIMWORLD_INITIALIZING ); + setElbeemErrorString("[none]"); + resetGlobalColorSetting(); + + elbeemCheckDebugEnv(); + debMsgStd("performElbeemSimulation",DM_NOTIFY,"El'Beem Simulation Init Start as Plugin, debugLevel:"<addDomain(settings); + return 0; +} + +// error message access +extern "C" +void elbeemGetErrorString(char *buffer) { + if(!buffer) return; + strncpy(buffer,getElbeemErrorString(),256); +} + +// reset elbeemMesh struct with zeroes +extern "C" +void elbeemResetMesh(elbeemMesh *mesh) { + if(!mesh) return; + // init typedef struct elbeemMesh + mesh->type = 0; + + mesh->parentDomainId = 0; + + /* vertices */ + mesh->numVertices = 0; + mesh->vertices = NULL; + + mesh->channelSizeVertices = 0; + mesh->channelVertices = NULL; + + /* triangles */ + mesh->numTriangles = 0; + mesh->triangles = NULL; + + /* animation channels */ + mesh->channelSizeTranslation = 0; + mesh->channelTranslation = NULL; + mesh->channelSizeRotation = 0; + mesh->channelRotation = NULL; + mesh->channelSizeScale = 0; + mesh->channelScale = NULL; + + /* active channel */ + mesh->channelSizeActive = 0; + mesh->channelActive = NULL; + + mesh->channelSizeInitialVel = 0; + mesh->channelInitialVel = NULL; + + mesh->localInivelCoords = 0; + + mesh->obstacleType= FLUIDSIM_OBSTACLE_NOSLIP; + mesh->obstaclePartslip= 0.; + mesh->obstacleImpactFactor= 1.; + + mesh->volumeInitType= OB_VOLUMEINIT_VOLUME; + + /* name of the mesh, mostly for debugging */ + mesh->name = "[unnamed]"; +} + +int globalMeshCounter = 1; +// add mesh as fluidsim object +extern "C" +int elbeemAddMesh(elbeemMesh *mesh) { + int initType = -1; + if(getElbeemState() != SIMWORLD_INITIALIZING) { errFatal("elbeemAddMesh","World and domain not initialized, call elbeemInit and elbeemAddDomain before...", SIMWORLD_INITERROR); } + + switch(mesh->type) { + case OB_FLUIDSIM_OBSTACLE: + if (mesh->obstacleType==FLUIDSIM_OBSTACLE_PARTSLIP) initType = FGI_BNDPART; + else if(mesh->obstacleType==FLUIDSIM_OBSTACLE_FREESLIP) initType = FGI_BNDFREE; + else /*if(mesh->obstacleType==FLUIDSIM_OBSTACLE_NOSLIP)*/ initType = FGI_BNDNO; + break; + case OB_FLUIDSIM_FLUID: initType = FGI_FLUID; break; + case OB_FLUIDSIM_INFLOW: initType = FGI_MBNDINFLOW; break; + case OB_FLUIDSIM_OUTFLOW: initType = FGI_MBNDOUTFLOW; break; + } + // invalid type? + if(initType<0) return 1; + + ntlGeometryObjModel *obj = new ntlGeometryObjModel( ); + gpWorld->getRenderGlobals()->getSimScene()->addGeoClass( obj ); + obj->initModel( + mesh->numVertices, mesh->vertices, mesh->numTriangles, mesh->triangles, + mesh->channelSizeVertices, mesh->channelVertices ); + if(mesh->name) obj->setName(string(mesh->name)); + else { + char meshname[100]; + snprintf(meshname,100,"mesh%04d",globalMeshCounter); + obj->setName(string(meshname)); + } + globalMeshCounter++; + obj->setGeoInitId( mesh->parentDomainId+1 ); + obj->setGeoInitIntersect(true); + obj->setGeoInitType(initType); + obj->setGeoPartSlipValue(mesh->obstaclePartslip); + obj->setGeoImpactFactor(mesh->obstacleImpactFactor); + if((mesh->volumeInitTypevolumeInitType>VOLUMEINIT_BOTH)) mesh->volumeInitType = VOLUMEINIT_VOLUME; + obj->setVolumeInit(mesh->volumeInitType); + // use channel instead, obj->setInitialVelocity( ntlVec3Gfx(mesh->iniVelocity[0], mesh->iniVelocity[1], mesh->iniVelocity[2]) ); + obj->initChannels( + mesh->channelSizeTranslation, mesh->channelTranslation, + mesh->channelSizeRotation, mesh->channelRotation, + mesh->channelSizeScale, mesh->channelScale, + mesh->channelSizeActive, mesh->channelActive, + mesh->channelSizeInitialVel, mesh->channelInitialVel + ); + obj->setLocalCoordInivel( mesh->localInivelCoords ); + + debMsgStd("elbeemAddMesh",DM_MSG,"Added elbeem mesh: "<getName()<<" type="<getIsAnimated(), 9 ); + return 0; +} + +// do the actual simulation +extern "C" +int elbeemSimulate(void) { + if(!gpWorld) return 1; + + gpWorld->finishWorldInit(); + if( isSimworldOk() ) { + myTime_t timestart = getTime(); + gpWorld->renderAnimation(); + myTime_t timeend = getTime(); + + if(getElbeemState() != SIMWORLD_STOP) { + // ok, we're done... + delete gpWorld; + gpWorld = NULL; + debMsgStd("elbeemSimulate",DM_NOTIFY, "El'Beem simulation done, time: "<renderAnimation(); + myTime_t timeend = getTime(); + + if(getElbeemState() != SIMWORLD_STOP) { + // ok, we're done... + delete gpWorld; + gpWorld = NULL; + debMsgStd("elbeemContinueSimulation",DM_NOTIFY, "El'Beem simulation done, time: "< gKeepVal; + +#define SIMPLIFY_FLOAT_EPSILON (1e-6f) +#define SIMPLIFY_DOUBLE_EPSILON (1e-12f) +#define SFLOATEQ(x,y) (ABS((x)-(y)) < SIMPLIFY_FLOAT_EPSILON) +#define SDOUBLEEQ(x,y) (ABS((x)-(y)) < SIMPLIFY_DOUBLE_EPSILON) +#define SVECFLOATEQ(x,y) ( \ + (ABS((x)[0]-(y)[0]) < SIMPLIFY_FLOAT_EPSILON) && \ + (ABS((x)[1]-(y)[1]) < SIMPLIFY_FLOAT_EPSILON) && \ + (ABS((x)[2]-(y)[2]) < SIMPLIFY_FLOAT_EPSILON) ) + +// helper function - simplify animation channels +extern "C" +int elbeemSimplifyChannelFloat(float *channel, int* size) { + bool changed = false; + int nsize = *size; + int orgsize = *size; + if(orgsize<1) return false; + gKeepVal.resize( orgsize ); + for(int i=0; irunsimCallback) +// best use with FLUIDSIM_CBxxx defines below. +// >parameters +// return values: 0=continue, 1=stop, 2=abort +// data pointer: user data pointer from elbeemSimulationSettings->runsimUserData +// status integer: 1=running simulation, 2=new frame saved +// frame integer: if status is 1, contains current frame number +typedef int (*elbeemRunSimulationCallback)(void *data, int status, int frame); +#define FLUIDSIM_CBRET_CONTINUE 0 +#define FLUIDSIM_CBRET_STOP 1 +#define FLUIDSIM_CBRET_ABORT 2 +#define FLUIDSIM_CBSTATUS_STEP 1 +#define FLUIDSIM_CBSTATUS_NEWFRAME 2 + + +// global settings for the simulation +typedef struct elbeemSimulationSettings { + /* version number */ + short version; + /* id number of simulation domain, needed if more than a + * single domain should be simulated */ + short domainId; + + /* geometrical extent */ + float geoStart[3], geoSize[3]; + + /* resolutions */ + short resolutionxyz; + short previewresxyz; + /* size of the domain in real units (meters along largest resolution x,y,z extent) */ + float realsize; + + /* fluid properties */ + double viscosity; + /* gravity strength */ + float gravity[3]; + /* anim start end time */ + float animStart, aniFrameTime; + /* no. of frames to simulate & output */ + short noOfFrames; + /* g star param (LBM compressibility) */ + float gstar; + /* activate refinement? */ + short maxRefine; + /* probability for surface particle generation (0.0=off) */ + float generateParticles; + /* amount of tracer particles to generate (0=off) */ + int numTracerParticles; + + /* store output path, and file prefix for baked fluid surface */ + char outputPath[160+80]; + + /* channel for frame time, visc & gravity animations */ + int channelSizeFrameTime; + float *channelFrameTime; + int channelSizeViscosity; + float *channelViscosity; + int channelSizeGravity; + float *channelGravity; // vector + + /* boundary types and settings for domain walls */ + short domainobsType; + float domainobsPartslip; + /* generate speed vectors for vertices (e.g. for image based motion blur)*/ + short generateVertexVectors; + /* strength of surface smoothing */ + float surfaceSmoothing; + /* no. of surface subdivisions */ + int surfaceSubdivs; + + /* global transformation to apply to fluidsim mesh */ + float surfaceTrafo[4*4]; + + /* development variables, testing for upcoming releases...*/ + float farFieldSize; + + /* callback function to notify calling program of performed simulation steps + * or newly available frame data, if NULL it is ignored */ + elbeemRunSimulationCallback runsimCallback; + /* pointer passed to runsimCallback for user data storage */ + void* runsimUserData; + +} elbeemSimulationSettings; + + +// defines for elbeemMesh->type below +#define OB_FLUIDSIM_FLUID 4 +#define OB_FLUIDSIM_OBSTACLE 8 +#define OB_FLUIDSIM_INFLOW 16 +#define OB_FLUIDSIM_OUTFLOW 32 + +// defines for elbeemMesh->obstacleType below +#define FLUIDSIM_OBSTACLE_NOSLIP 1 +#define FLUIDSIM_OBSTACLE_PARTSLIP 2 +#define FLUIDSIM_OBSTACLE_FREESLIP 3 + +#define OB_VOLUMEINIT_VOLUME 1 +#define OB_VOLUMEINIT_SHELL 2 +#define OB_VOLUMEINIT_BOTH (OB_VOLUMEINIT_SHELL|OB_VOLUMEINIT_VOLUME) + +// a single mesh object +typedef struct elbeemMesh { + /* obstacle,fluid or inflow... */ + short type; + /* id of simulation domain it belongs to */ + short parentDomainId; + + /* vertices */ + int numVertices; + float *vertices; // = float[n][3]; + /* animated vertices */ + int channelSizeVertices; + float *channelVertices; // = float[channelSizeVertices* (n*3+1) ]; + + /* triangles */ + int numTriangles; + int *triangles; // = int[][3]; + + /* animation channels */ + int channelSizeTranslation; + float *channelTranslation; + int channelSizeRotation; + float *channelRotation; + int channelSizeScale; + float *channelScale; + + /* active channel */ + int channelSizeActive; + float *channelActive; + /* initial velocity channel (e.g. for inflow) */ + int channelSizeInitialVel; + float *channelInitialVel; // vector + /* use initial velocity in object coordinates? (e.g. for rotation) */ + short localInivelCoords; + /* boundary types and settings */ + short obstacleType; + float obstaclePartslip; + /* amount of force transfer from fluid to obj, 0=off, 1=normal */ + float obstacleImpactFactor; + /* init volume, shell or both? use OB_VOLUMEINIT_xxx defines above */ + short volumeInitType; + + /* name of the mesh, mostly for debugging */ + const char *name; +} elbeemMesh; + +// API functions + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + + +// reset elbeemSimulationSettings struct with defaults +void elbeemResetSettings(struct elbeemSimulationSettings*); + +// start fluidsim init (returns !=0 upon failure) +int elbeemInit(void); + +// start fluidsim init (returns !=0 upon failure) +int elbeemAddDomain(struct elbeemSimulationSettings*); + +// get failure message during simulation or init +// if an error occured (the string is copied into buffer, +// max. length = 256 chars ) +void elbeemGetErrorString(char *buffer); + +// reset elbeemMesh struct with zeroes +void elbeemResetMesh(struct elbeemMesh*); + +// add mesh as fluidsim object +int elbeemAddMesh(struct elbeemMesh*); + +// do the actual simulation +int elbeemSimulate(void); + +// continue a previously stopped simulation +int elbeemContinueSimulation(void); + + +// helper functions + +// simplify animation channels +// returns if the channel and its size changed +int elbeemSimplifyChannelFloat(float *channel, int *size); +int elbeemSimplifyChannelVec3(float *channel, int *size); + +// helper functions implemented in utilities.cpp + +/* set elbeem debug output level (0=off to 10=full on) */ +void elbeemSetDebugLevel(int level); +/* elbeem debug output function, prints if debug level >0 */ +void elbeemDebugOut(char *msg); + +/* estimate how much memory a given setup will require */ +double elbeemEstimateMemreq(int res, + float sx, float sy, float sz, + int refine, char *retstr); + + + +#ifdef __cplusplus +} +#endif // __cplusplus + + + +/******************************************************************************/ +// internal defines, do not use for initializing elbeemMesh +// structs, for these use OB_xxx defines above + +/*! fluid geometry init types */ +#define FGI_FLAGSTART 16 +#define FGI_FLUID (1<<(FGI_FLAGSTART+ 0)) +#define FGI_NO_FLUID (1<<(FGI_FLAGSTART+ 1)) +#define FGI_BNDNO (1<<(FGI_FLAGSTART+ 2)) +#define FGI_BNDFREE (1<<(FGI_FLAGSTART+ 3)) +#define FGI_BNDPART (1<<(FGI_FLAGSTART+ 4)) +#define FGI_NO_BND (1<<(FGI_FLAGSTART+ 5)) +#define FGI_MBNDINFLOW (1<<(FGI_FLAGSTART+ 6)) +#define FGI_MBNDOUTFLOW (1<<(FGI_FLAGSTART+ 7)) + +// all boundary types at once +#define FGI_ALLBOUNDS ( FGI_BNDNO | FGI_BNDFREE | FGI_BNDPART | FGI_MBNDINFLOW | FGI_MBNDOUTFLOW ) + + +#endif // ELBEEM_API_H diff --git a/intern/elbeem/intern/isosurface.cpp b/intern/elbeem/intern/isosurface.cpp new file mode 100644 index 00000000000..9925565b85d --- /dev/null +++ b/intern/elbeem/intern/isosurface.cpp @@ -0,0 +1,1126 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Marching Cubes surface mesh generation + * + *****************************************************************************/ + +#include "isosurface.h" +#include "mcubes_tables.h" +#include "particletracer.h" +#include +#include + +// just use default rounding for platforms where its not available +#ifndef round +#define round(x) (x) +#endif + +/****************************************************************************** + * Constructor + *****************************************************************************/ +IsoSurface::IsoSurface(double iso) : + ntlGeometryObject(), + mSizex(-1), mSizey(-1), mSizez(-1), + mpData(NULL), + mIsoValue( iso ), + mPoints(), + mUseFullEdgeArrays(false), + mpEdgeVerticesX(NULL), mpEdgeVerticesY(NULL), mpEdgeVerticesZ(NULL), + mEdgeArSize(-1), + mIndices(), + + mStart(0.0), mEnd(0.0), mDomainExtent(0.0), + mInitDone(false), + mSmoothSurface(0.0), mSmoothNormals(0.0), + mAcrossEdge(), mAdjacentFaces(), + mCutoff(-1), mCutArray(NULL), // off by default + mpIsoParts(NULL), mPartSize(0.), mSubdivs(0), + mFlagCnt(1), + mSCrad1(0.), mSCrad2(0.), mSCcenter(0.) +{ +} + + +/****************************************************************************** + * The real init... + *****************************************************************************/ +void IsoSurface::initializeIsosurface(int setx, int sety, int setz, ntlVec3Gfx extent) +{ + // range 1-10 (max due to subd array in triangulate) + if(mSubdivs<1) mSubdivs=1; + if(mSubdivs>10) mSubdivs=10; + + // init solver and size + mSizex = setx; + mSizey = sety; + if(setz == 1) {// 2D, create thin 2D surface + setz = 5; + } + mSizez = setz; + mDomainExtent = extent; + + /* check triangulation size (for raytraing) */ + if( ( mStart[0] >= mEnd[0] ) && ( mStart[1] >= mEnd[1] ) && ( mStart[2] >= mEnd[2] ) ){ + // extent was not set, use normalized one from parametrizer + mStart = ntlVec3Gfx(0.0) - extent*0.5; + mEnd = ntlVec3Gfx(0.0) + extent*0.5; + } + + // init + mIndices.clear(); + mPoints.clear(); + + int nodes = mSizez*mSizey*mSizex; + mpData = new float[nodes]; + for(int i=0;i0) && (kmSizex-2-coAdd-mCutoff) || + (j>mSizey-2-coAdd-mCutoff) ) { + if(mCutArray) { + if(k < mCutArray[j*this->mSizex+i]) continue; + } else { continue; } + } + + // Create the triangles... + for(int e=0; mcTriTable[cubeIndex][e]!=-1; e+=3) { + mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+0] ] ); + mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+1] ] ); + mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+2] ] ); + } + + }//i + }// j + + // copy edge arrays + if(!mUseFullEdgeArrays) { + for(int j=0;j<(mSizey-0);j++) + for(int i=0;i<(mSizex-0);i++) { + //int edgek = 0; + const int dst = ISOLEVEL_INDEX( i+0, j+0, 0); + const int src = ISOLEVEL_INDEX( i+0, j+0, 1); + mpEdgeVerticesX[ dst ] = mpEdgeVerticesX[ src ]; + mpEdgeVerticesY[ dst ] = mpEdgeVerticesY[ src ]; + mpEdgeVerticesZ[ dst ] = mpEdgeVerticesZ[ src ]; + mpEdgeVerticesX[ src ]=-1; + mpEdgeVerticesY[ src ]=-1; + mpEdgeVerticesZ[ src ]=-1; + } + } // */ + + } // k + + // precalculate normals using an approximation of the scalar field gradient + for(int ni=0;ni<(int)mPoints.size();ni++) { normalize( mPoints[ni].n ); } + + } else { // subdivs + +#define EDGEAR_INDEX(Ai,Aj,Ak, Bi,Bj) ((mSizex*mSizey*mSubdivs*mSubdivs*(Ak))+\ + (mSizex*mSubdivs*((Aj)*mSubdivs+(Bj)))+((Ai)*mSubdivs)+(Bi)) + +#define ISOTRILININT(fi,fj,fk) ( \ + (1.-(fi))*(1.-(fj))*(1.-(fk))*orgval[0] + \ + ( (fi))*(1.-(fj))*(1.-(fk))*orgval[1] + \ + ( (fi))*( (fj))*(1.-(fk))*orgval[2] + \ + (1.-(fi))*( (fj))*(1.-(fk))*orgval[3] + \ + (1.-(fi))*(1.-(fj))*( (fk))*orgval[4] + \ + ( (fi))*(1.-(fj))*( (fk))*orgval[5] + \ + ( (fi))*( (fj))*( (fk))*orgval[6] + \ + (1.-(fi))*( (fj))*( (fk))*orgval[7] ) + + // use subdivisions + gfxReal subdfac = 1./(gfxReal)(mSubdivs); + gfxReal orgGsx = gsx; + gfxReal orgGsy = gsy; + gfxReal orgGsz = gsz; + gsx *= subdfac; + gsy *= subdfac; + gsz *= subdfac; + if(mUseFullEdgeArrays) { + errMsg("IsoSurface::triangulate","Disabling mUseFullEdgeArrays!"); + } + + // subdiv local arrays + gfxReal orgval[8]; + gfxReal subdAr[2][11][11]; // max 10 subdivs! + ParticleObject* *arppnt = new ParticleObject*[mSizez*mSizey*mSizex]; + + // construct pointers + // part test + int pInUse = 0; + int pUsedTest = 0; + // reset particles + // reset list array + for(int k=0;k<(mSizez);k++) + for(int j=0;j<(mSizey);j++) + for(int i=0;i<(mSizex);i++) { + arppnt[ISOLEVEL_INDEX(i,j,k)] = NULL; + } + if(mpIsoParts) { + for(vector::iterator pit= mpIsoParts->getParticlesBegin(); + pit!= mpIsoParts->getParticlesEnd(); pit++) { + if( (*pit).getActive()==false ) continue; + if( (*pit).getType()!=PART_DROP) continue; + (*pit).setNext(NULL); + } + // build per node lists + for(vector::iterator pit= mpIsoParts->getParticlesBegin(); + pit!= mpIsoParts->getParticlesEnd(); pit++) { + if( (*pit).getActive()==false ) continue; + if( (*pit).getType()!=PART_DROP) continue; + // check lifetime ignored here + ParticleObject *p = &(*pit); + const ntlVec3Gfx ppos = p->getPos(); + const int pi= (int)round(ppos[0])+0; + const int pj= (int)round(ppos[1])+0; + int pk= (int)round(ppos[2])+0;// no offset necessary + // 2d should be handled by solver. if(LBMDIM==2) { pk = 0; } + + if(pi<0) continue; + if(pj<0) continue; + if(pk<0) continue; + if(pi>mSizex-1) continue; + if(pj>mSizey-1) continue; + if(pk>mSizez-1) continue; + ParticleObject* &pnt = arppnt[ISOLEVEL_INDEX(pi,pj,pk)]; + if(pnt) { + // append + ParticleObject* listpnt = pnt; + while(listpnt) { + if(!listpnt->getNext()) { + listpnt->setNext(p); listpnt = NULL; + } else { + listpnt = listpnt->getNext(); + } + } + } else { + // start new list + pnt = p; + } + pInUse++; + } + } // mpIsoParts + + debMsgStd("IsoSurface::triangulate",DM_MSG,"Starting. Parts in use:"<=mSizez-1) continue; + for(int poj=-poDistOffset; poj<1+poDistOffset; poj++) { + if(j+poj<0) continue; + if(j+poj>=mSizey-1) continue; + for(int poi=-poDistOffset; poi<1+poDistOffset; poi++) { + if(i+poi<0) continue; + if(i+poi>=mSizex-1) continue; + ParticleObject *p; + p = arppnt[ISOLEVEL_INDEX(i+poi,j+poj,k+pok)]; + while(p) { // */ + /* + for(vector::iterator pit= mpIsoParts->getParticlesBegin(); + pit!= mpIsoParts->getParticlesEnd(); pit++) { { { { + // debug test! , full list slow! + if(( (*pit).getActive()==false ) || ( (*pit).getType()!=PART_DROP)) continue; + ParticleObject *p; + p = &(*pit); // */ + + pUsedTest++; + ntlVec3Gfx ppos = p->getPos(); + const int spi= (int)round( (ppos[0]+1.-(gfxReal)i) *(gfxReal)mSubdivs-1.5); + const int spj= (int)round( (ppos[1]+1.-(gfxReal)j) *(gfxReal)mSubdivs-1.5); + const int spk= (int)round( (ppos[2]+1.-(gfxReal)k) *(gfxReal)mSubdivs-1.5)-sdkOffset; // why -2? + // 2d should be handled by solver. if(LBMDIM==2) { spk = 0; } + + gfxReal pfLen = p->getSize()*1.5*mPartSize; // test, was 1.1 + const gfxReal minPfLen = subdfac*0.8; + if(pfLengetSize()<<" ps"< 1) { continue; } // */ + for(int swj=-icellpsize; swj<=icellpsize; swj++) { + if(spj+swj< 0) { continue; } + if(spj+swj>mSubdivs+0) { continue; } // */ + for(int swi=-icellpsize; swi<=icellpsize; swi++) { + if(spi+swi< 0) { continue; } + if(spi+swi>mSubdivs+0) { continue; } // */ + ntlVec3Gfx cellp = ntlVec3Gfx( + (1.5+(gfxReal)(spi+swi)) *subdfac + (gfxReal)(i-1), + (1.5+(gfxReal)(spj+swj)) *subdfac + (gfxReal)(j-1), + (1.5+(gfxReal)(spk+swk)+sdkOffset) *subdfac + (gfxReal)(k-1) + ); + //if(swi==0 && swj==0 && swk==0) subdAr[spk][spj][spi] = 1.; // DEBUG + // clip domain boundaries again + if(cellp[0]<1.) { continue; } + if(cellp[1]<1.) { continue; } + if(cellp[2]<1.) { continue; } + if(cellp[0]>(gfxReal)mSizex-3.) { continue; } + if(cellp[1]>(gfxReal)mSizey-3.) { continue; } + if(cellp[2]>(gfxReal)mSizez-3.) { continue; } + gfxReal len = norm(cellp-ppos); + gfxReal isoadd = 0.; + const gfxReal baseIsoVal = mIsoValue*1.1; + if(len1.) { continue; } + subdAr[spk+swk][spj+swj][spi+swi] = arval + isoadd; + } } } + + p = p->getNext(); + } + } } } // poDist loops */ + + py = mStart[1]+(((double)j-0.5)*orgGsy)-gsy; + for(int sj=0;sj 0) { + + // where to look up if this point already exists + const int edgek = 0; + const int baseIn = EDGEAR_INDEX( i+0, j+0, edgek+0, si,sj); + eVert[ 0] = &mpEdgeVerticesX[ baseIn ]; + eVert[ 1] = &mpEdgeVerticesY[ baseIn + 1 ]; + eVert[ 2] = &mpEdgeVerticesX[ EDGEAR_INDEX( i, j, edgek+0, si+0,sj+1) ]; + eVert[ 3] = &mpEdgeVerticesY[ baseIn ]; + + eVert[ 4] = &mpEdgeVerticesX[ EDGEAR_INDEX( i, j, edgek+1, si+0,sj+0) ]; + eVert[ 5] = &mpEdgeVerticesY[ EDGEAR_INDEX( i, j, edgek+1, si+1,sj+0) ]; // with subdivs + eVert[ 6] = &mpEdgeVerticesX[ EDGEAR_INDEX( i, j, edgek+1, si+0,sj+1) ]; + eVert[ 7] = &mpEdgeVerticesY[ EDGEAR_INDEX( i, j, edgek+1, si+0,sj+0) ]; + + eVert[ 8] = &mpEdgeVerticesZ[ baseIn ]; + eVert[ 9] = &mpEdgeVerticesZ[ EDGEAR_INDEX( i, j, edgek+0, si+1,sj+0) ]; // with subdivs + eVert[10] = &mpEdgeVerticesZ[ EDGEAR_INDEX( i, j, edgek+0, si+1,sj+1) ]; + eVert[11] = &mpEdgeVerticesZ[ EDGEAR_INDEX( i, j, edgek+0, si+0,sj+1) ]; + + // grid positions + pos[0] = ntlVec3Gfx(px ,py ,pz); + pos[1] = ntlVec3Gfx(px+gsx,py ,pz); + pos[2] = ntlVec3Gfx(px+gsx,py+gsy,pz); // with subdivs + pos[3] = ntlVec3Gfx(px ,py+gsy,pz); + pos[4] = ntlVec3Gfx(px ,py ,pz+gsz); + pos[5] = ntlVec3Gfx(px+gsx,py ,pz+gsz); + pos[6] = ntlVec3Gfx(px+gsx,py+gsy,pz+gsz); // with subdivs + pos[7] = ntlVec3Gfx(px ,py+gsy,pz+gsz); + + // check all edges + for(int e=0;e<12;e++) { + if (mcEdgeTable[cubeIndex] & (1<0) { + //smoSubdfac = 1./(float)(mSubdivs); + smoSubdfac = pow(0.55,(double)mSubdivs); // slightly stronger + } + if(mSmoothSurface>0. || mSmoothNormals>0.) debMsgStd("IsoSurface::triangulate",DM_MSG,"Smoothing...",10); + if(mSmoothSurface>0.0) { + smoothSurface(mSmoothSurface*smoSubdfac, (mSmoothNormals<=0.0) ); + } + if(mSmoothNormals>0.0) { + smoothNormals(mSmoothNormals*smoSubdfac); + } + + myTime_t tritimeend = getTime(); + debMsgStd("IsoSurface::triangulate",DM_MSG,"took "<< getTimeString(tritimeend-tritimestart)<<", S("<getNumParticles(), 10); +} + + + + + +/****************************************************************************** + * Get triangles for rendering + *****************************************************************************/ +void IsoSurface::getTriangles(double t, vector *triangles, + vector *vertices, + vector *normals, int objectId ) +{ + if(!mInitDone) { + debugOut("IsoSurface::getTriangles warning: Not initialized! ", 10); + return; + } + t = 0.; + //return; // DEBUG + + /* triangulate field */ + triangulate(); + //errMsg("TRIS"," "<size()<<" ns"<size()<<" ts"<size() ); + //errMsg("NM"," ovs"<push_back( mPoints[i].v ); + } + for(int i=0;i<(int)mPoints.size();i++) { + normals->push_back( mPoints[i].n ); + } + + //errMsg("N2"," ivi"<size()<<" ns"<size()<<" ts"<size() ); + //errMsg("N2"," ovs"< 0) { + flag |= (1<< (geoiId+4)); + flag |= mGeoInitType; + } + + tri.setFlags( flag ); + + /* triangle normal missing */ + tri.setNormal( ntlVec3Gfx(0.0) ); + tri.setSmoothNormals( smooth ); + tri.setObjectId( objectId ); + triangles->push_back( tri ); + } + //errMsg("N3"," ivi"<size()<<" ns"<size()<<" ts"<size() ); + return; +} + + + +inline ntlVec3Gfx IsoSurface::getNormal(int i, int j,int k) { + // WARNING - this requires a security boundary layer... + ntlVec3Gfx ret(0.0); + ret[0] = *getData(i-1,j ,k ) - + *getData(i+1,j ,k ); + ret[1] = *getData(i ,j-1,k ) - + *getData(i ,j+1,k ); + ret[2] = *getData(i ,j ,k-1 ) - + *getData(i ,j ,k+1 ); + return ret; +} + + + + +/****************************************************************************** + * + * Surface improvement, inspired by trimesh2 library + * (http://www.cs.princeton.edu/gfx/proj/trimesh2/) + * + *****************************************************************************/ + +void IsoSurface::setSmoothRad(float radi1, float radi2, ntlVec3Gfx mscc) { + mSCrad1 = radi1*radi1; + mSCrad2 = radi2*radi2; + mSCcenter = mscc; +} + +// compute normals for all generated triangles +void IsoSurface::computeNormals() { + for(int i=0;i<(int)mPoints.size();i++) { + mPoints[i].n = ntlVec3Gfx(0.); + } + + for(int i=0;i<(int)mIndices.size();i+=3) { + const int t1 = mIndices[i]; + const int t2 = mIndices[i+1]; + const int t3 = mIndices[i+2]; + const ntlVec3Gfx p1 = mPoints[t1].v; + const ntlVec3Gfx p2 = mPoints[t2].v; + const ntlVec3Gfx p3 = mPoints[t3].v; + const ntlVec3Gfx n1=p1-p2; + const ntlVec3Gfx n2=p2-p3; + const ntlVec3Gfx n3=p3-p1; + const gfxReal len1 = normNoSqrt(n1); + const gfxReal len2 = normNoSqrt(n2); + const gfxReal len3 = normNoSqrt(n3); + const ntlVec3Gfx norm = cross(n1,n2); + mPoints[t1].n += norm * (1./(len1*len3)); + mPoints[t2].n += norm * (1./(len1*len2)); + mPoints[t3].n += norm * (1./(len2*len3)); + } + + for(int i=0;i<(int)mPoints.size();i++) { + normalize(mPoints[i].n); + } +} + +// Diffuse a vector field at 1 vertex, weighted by +// a gaussian of width 1/sqrt(invsigma2) +bool IsoSurface::diffuseVertexField(ntlVec3Gfx *field, const int pointerScale, int src, float invsigma2, ntlVec3Gfx &target) +{ + if((neighbors[src].size()<1) || (pointareas[src]<=0.0)) return 0; + const ntlVec3Gfx srcp = mPoints[src].v; + const ntlVec3Gfx srcn = mPoints[src].n; + if(mSCrad1>0.0 && mSCrad2>0.0) { + ntlVec3Gfx dp = mSCcenter-srcp; dp[2] = 0.0; // only xy-plane + float rd = normNoSqrt(dp); + if(rd > mSCrad2) { + return 0; + } else if(rd > mSCrad1) { + // optimize? + float org = 1.0/sqrt(invsigma2); + org *= (1.0- (rd-mSCrad1) / (mSCrad2-mSCrad1)); + invsigma2 = 1.0/(org*org); + //errMsg("TRi","p"<= 9.0f) continue; + + // aggressive smoothing factor + float smstr = nvdot * pointareas[bbn]; + // Accumulate weight times field at neighbor + target += *(field+pointerScale*bbn)*smstr; + smstrSum += smstr; + + for(int i = 0; i < (int)neighbors[bbn].size(); i++) { + const int nn = neighbors[bbn][i]; + if (flags[nn] == flag) continue; + mDboundary.push_back(nn); + } + } + target /= smstrSum; + return 1; +} + + +// perform smoothing of the surface (and possible normals) +void IsoSurface::smoothSurface(float sigma, bool normSmooth) +{ + int nv = mPoints.size(); + if ((int)flags.size() != nv) flags.resize(nv); + int nf = mIndices.size()/3; + + { // need neighbors + vector numneighbors(mPoints.size()); + int i; + for (i = 0; i < (int)mIndices.size()/3; i++) { + numneighbors[mIndices[i*3+0]]++; + numneighbors[mIndices[i*3+1]]++; + numneighbors[mIndices[i*3+2]]++; + } + + neighbors.clear(); + neighbors.resize(mPoints.size()); + for (i = 0; i < (int)mPoints.size(); i++) { + neighbors[i].clear(); + neighbors[i].reserve(numneighbors[i]+2); // Slop for boundaries + } + + for (i = 0; i < (int)mIndices.size()/3; i++) { + for (int j = 0; j < 3; j++) { + vector &me = neighbors[ mIndices[i*3+j]]; + int n1 = mIndices[i*3+((j+1)%3)]; + int n2 = mIndices[i*3+((j+2)%3)]; + if (std::find(me.begin(), me.end(), n1) == me.end()) + me.push_back(n1); + if (std::find(me.begin(), me.end(), n2) == me.end()) + me.push_back(n2); + } + } + } // need neighbor + + { // need pointarea + pointareas.clear(); + pointareas.resize(nv); + cornerareas.clear(); + cornerareas.resize(nf); + + for (int i = 0; i < nf; i++) { + // Edges + ntlVec3Gfx e[3] = { + mPoints[mIndices[i*3+2]].v - mPoints[mIndices[i*3+1]].v, + mPoints[mIndices[i*3+0]].v - mPoints[mIndices[i*3+2]].v, + mPoints[mIndices[i*3+1]].v - mPoints[mIndices[i*3+0]].v }; + + // Compute corner weights + float area = 0.5f * norm( cross(e[0], e[1])); + float l2[3] = { normNoSqrt(e[0]), normNoSqrt(e[1]), normNoSqrt(e[2]) }; + float ew[3] = { l2[0] * (l2[1] + l2[2] - l2[0]), + l2[1] * (l2[2] + l2[0] - l2[1]), + l2[2] * (l2[0] + l2[1] - l2[2]) }; + if (ew[0] <= 0.0f) { + cornerareas[i][1] = -0.25f * l2[2] * area / + dot(e[0] , e[2]); + cornerareas[i][2] = -0.25f * l2[1] * area / + dot(e[0] , e[1]); + cornerareas[i][0] = area - cornerareas[i][1] - + cornerareas[i][2]; + } else if (ew[1] <= 0.0f) { + cornerareas[i][2] = -0.25f * l2[0] * area / + dot(e[1] , e[0]); + cornerareas[i][0] = -0.25f * l2[2] * area / + dot(e[1] , e[2]); + cornerareas[i][1] = area - cornerareas[i][2] - + cornerareas[i][0]; + } else if (ew[2] <= 0.0f) { + cornerareas[i][0] = -0.25f * l2[1] * area / + dot(e[2] , e[1]); + cornerareas[i][1] = -0.25f * l2[0] * area / + dot(e[2] , e[0]); + cornerareas[i][2] = area - cornerareas[i][0] - + cornerareas[i][1]; + } else { + float ewscale = 0.5f * area / (ew[0] + ew[1] + ew[2]); + for (int j = 0; j < 3; j++) + cornerareas[i][j] = ewscale * (ew[(j+1)%3] + + ew[(j+2)%3]); + } + + // NT important, check this... +#ifndef WIN32 + if(! finite(cornerareas[i][0]) ) cornerareas[i][0]=1e-6; + if(! finite(cornerareas[i][1]) ) cornerareas[i][1]=1e-6; + if(! finite(cornerareas[i][2]) ) cornerareas[i][2]=1e-6; +#else // WIN32 + // FIXME check as well... + if(! (cornerareas[i][0]>=0.0) ) cornerareas[i][0]=1e-6; + if(! (cornerareas[i][1]>=0.0) ) cornerareas[i][1]=1e-6; + if(! (cornerareas[i][2]>=0.0) ) cornerareas[i][2]=1e-6; +#endif // WIN32 + + pointareas[mIndices[i*3+0]] += cornerareas[i][0]; + pointareas[mIndices[i*3+1]] += cornerareas[i][1]; + pointareas[mIndices[i*3+2]] += cornerareas[i][2]; + } + + } // need pointarea + // */ + + float invsigma2 = 1.0f / (sigma*sigma); + + vector dflt(nv); + for (int i = 0; i < nv; i++) { + if(diffuseVertexField( &mPoints[0].v, 2, + i, invsigma2, dflt[i])) { + // Just keep the displacement + dflt[i] -= mPoints[i].v; + } else { dflt[i] = 0.0; } //?mPoints[i].v; } + } + + // Slightly better small-neighborhood approximation + for (int i = 0; i < nf; i++) { + ntlVec3Gfx c = mPoints[mIndices[i*3+0]].v + + mPoints[mIndices[i*3+1]].v + + mPoints[mIndices[i*3+2]].v; + c /= 3.0f; + for (int j = 0; j < 3; j++) { + int v = mIndices[i*3+j]; + ntlVec3Gfx d =(c - mPoints[v].v) * 0.5f; + dflt[v] += d * (cornerareas[i][j] / + pointareas[mIndices[i*3+j]] * + exp(-0.5f * invsigma2 * normNoSqrt(d)) ); + } + } + + // Filter displacement field + vector dflt2(nv); + for (int i = 0; i < nv; i++) { + if(diffuseVertexField( &dflt[0], 1, + i, invsigma2, dflt2[i])) { } + else { /*mPoints[i].v=0.0;*/ dflt2[i] = 0.0; }//dflt2[i]; } + } + + // Update vertex positions + for (int i = 0; i < nv; i++) { + mPoints[i].v += dflt[i] - dflt2[i]; // second Laplacian + } + + // when normals smoothing off, this cleans up quite well + // costs ca. 50% additional time though + float nsFac = 1.5f; + if(normSmooth) { float ninvsigma2 = 1.0f / (nsFac*nsFac*sigma*sigma); + for (int i = 0; i < nv; i++) { + if( diffuseVertexField( &mPoints[0].n, 2, i, ninvsigma2, dflt[i]) ) { + normalize(dflt[i]); + } else { + dflt[i] = mPoints[i].n; + } + } + for (int i = 0; i < nv; i++) { + mPoints[i].n = dflt[i]; + } + } // smoothNormals copy */ + + //errMsg("SMSURF","done v:"< numneighbors(mPoints.size()); + int i; + for (i = 0; i < (int)mIndices.size()/3; i++) { + numneighbors[mIndices[i*3+0]]++; + numneighbors[mIndices[i*3+1]]++; + numneighbors[mIndices[i*3+2]]++; + } + + neighbors.clear(); + neighbors.resize(mPoints.size()); + for (i = 0; i < (int)mPoints.size(); i++) { + neighbors[i].clear(); + neighbors[i].reserve(numneighbors[i]+2); // Slop for boundaries + } + + for (i = 0; i < (int)mIndices.size()/3; i++) { + for (int j = 0; j < 3; j++) { + vector &me = neighbors[ mIndices[i*3+j]]; + int n1 = mIndices[i*3+((j+1)%3)]; + int n2 = mIndices[i*3+((j+2)%3)]; + if (std::find(me.begin(), me.end(), n1) == me.end()) + me.push_back(n1); + if (std::find(me.begin(), me.end(), n2) == me.end()) + me.push_back(n2); + } + } + } // need neighbor + + { // need pointarea + int nf = mIndices.size()/3, nv = mPoints.size(); + pointareas.clear(); + pointareas.resize(nv); + cornerareas.clear(); + cornerareas.resize(nf); + + for (int i = 0; i < nf; i++) { + // Edges + ntlVec3Gfx e[3] = { + mPoints[mIndices[i*3+2]].v - mPoints[mIndices[i*3+1]].v, + mPoints[mIndices[i*3+0]].v - mPoints[mIndices[i*3+2]].v, + mPoints[mIndices[i*3+1]].v - mPoints[mIndices[i*3+0]].v }; + + // Compute corner weights + float area = 0.5f * norm( cross(e[0], e[1])); + float l2[3] = { normNoSqrt(e[0]), normNoSqrt(e[1]), normNoSqrt(e[2]) }; + float ew[3] = { l2[0] * (l2[1] + l2[2] - l2[0]), + l2[1] * (l2[2] + l2[0] - l2[1]), + l2[2] * (l2[0] + l2[1] - l2[2]) }; + if (ew[0] <= 0.0f) { + cornerareas[i][1] = -0.25f * l2[2] * area / + dot(e[0] , e[2]); + cornerareas[i][2] = -0.25f * l2[1] * area / + dot(e[0] , e[1]); + cornerareas[i][0] = area - cornerareas[i][1] - + cornerareas[i][2]; + } else if (ew[1] <= 0.0f) { + cornerareas[i][2] = -0.25f * l2[0] * area / + dot(e[1] , e[0]); + cornerareas[i][0] = -0.25f * l2[2] * area / + dot(e[1] , e[2]); + cornerareas[i][1] = area - cornerareas[i][2] - + cornerareas[i][0]; + } else if (ew[2] <= 0.0f) { + cornerareas[i][0] = -0.25f * l2[1] * area / + dot(e[2] , e[1]); + cornerareas[i][1] = -0.25f * l2[0] * area / + dot(e[2] , e[0]); + cornerareas[i][2] = area - cornerareas[i][0] - + cornerareas[i][1]; + } else { + float ewscale = 0.5f * area / (ew[0] + ew[1] + ew[2]); + for (int j = 0; j < 3; j++) + cornerareas[i][j] = ewscale * (ew[(j+1)%3] + + ew[(j+2)%3]); + } + + // NT important, check this... +#ifndef WIN32 + if(! finite(cornerareas[i][0]) ) cornerareas[i][0]=1e-6; + if(! finite(cornerareas[i][1]) ) cornerareas[i][1]=1e-6; + if(! finite(cornerareas[i][2]) ) cornerareas[i][2]=1e-6; +#else // WIN32 + // FIXME check as well... + if(! (cornerareas[i][0]>=0.0) ) cornerareas[i][0]=1e-6; + if(! (cornerareas[i][1]>=0.0) ) cornerareas[i][1]=1e-6; + if(! (cornerareas[i][2]>=0.0) ) cornerareas[i][2]=1e-6; +#endif // WIN32 + + pointareas[mIndices[i*3+0]] += cornerareas[i][0]; + pointareas[mIndices[i*3+1]] += cornerareas[i][1]; + pointareas[mIndices[i*3+2]] += cornerareas[i][2]; + } + + } // need pointarea + + int nv = mPoints.size(); + if ((int)flags.size() != nv) flags.resize(nv); + float invsigma2 = 1.0f / (sigma*sigma); + + vector nflt(nv); + for (int i = 0; i < nv; i++) { + if(diffuseVertexField( &mPoints[0].n, 2, i, invsigma2, nflt[i])) { + normalize(nflt[i]); + } else { nflt[i]=mPoints[i].n; } + } + + // copy results + for (int i = 0; i < nv; i++) { mPoints[i].n = nflt[i]; } +} + + diff --git a/intern/elbeem/intern/isosurface.h b/intern/elbeem/intern/isosurface.h new file mode 100644 index 00000000000..9902b40199c --- /dev/null +++ b/intern/elbeem/intern/isosurface.h @@ -0,0 +1,230 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Marching Cubes "displayer" + * + *****************************************************************************/ + +#ifndef ISOSURFACE_H + +#include "ntl_geometryobject.h" +#include "ntl_bsptree.h" + +#define ISO_STRICT_DEBUG 0 +#define ISOSTRICT_EXIT *((int *)0)=0; + +/* access some 3d array */ +#define ISOLEVEL_INDEX(ii,ij,ik) ((mSizex*mSizey*(ik))+(mSizex*(ij))+((ii))) + +class ParticleTracer; + +/* struct for a small cube in the scalar field */ +typedef struct { + ntlVec3Gfx pos[8]; + double value[8]; + int i,j,k; +} IsoLevelCube; + + +typedef struct { + ntlVec3Gfx v; // vertex + ntlVec3Gfx n; // vertex normal +} IsoLevelVertex; + +//! class to triangulate a scalar field, e.g. for +// the fluid surface, templated by scalar field access object +class IsoSurface : + public ntlGeometryObject //, public S +{ + + public: + + /*! Constructor */ + IsoSurface(double iso); + /*! Destructor */ + virtual ~IsoSurface(); + + /*! Init ararys etc. */ + virtual void initializeIsosurface(int setx, int sety, int setz, ntlVec3Gfx extent); + + /*! Reset all values */ + void resetAll(gfxReal val); + + /*! triangulate the scalar field given by pointer*/ + void triangulate( void ); + + /*! set particle pointer */ + void setParticles(ParticleTracer *pnt,float psize){ mpIsoParts = pnt; mPartSize=psize; }; + /*! set # of subdivisions, this has to be done before init! */ + void setSubdivs(int s) { + if(mInitDone) errFatal("IsoSurface::setSubdivs","Changing subdivs after init!", SIMWORLD_INITERROR); + if(s<1) s=1; if(s>10) s=10; + mSubdivs = s; } + int getSubdivs() { return mSubdivs;} + /*! set full edge settings, this has to be done before init! */ + void setUseFulledgeArrays(bool set) { + if(mInitDone) errFatal("IsoSurface::setUseFulledgeArrays","Changing usefulledge after init!", SIMWORLD_INITERROR); + mUseFullEdgeArrays = set;} + + protected: + + /* variables ... */ + + //! size + int mSizex, mSizey, mSizez; + + //! data pointer + float *mpData; + + //! Level of the iso surface + double mIsoValue; + + //! Store all the triangles vertices + vector mPoints; + + //! use full arrays? (not for farfield) + bool mUseFullEdgeArrays; + //! Store indices of calculated points along the cubie edges + int *mpEdgeVerticesX; + int *mpEdgeVerticesY; + int *mpEdgeVerticesZ; + int mEdgeArSize; + + + //! vector for all the triangles (stored as 3 indices) + vector mIndices; + + //! start and end vectors for the triangulation region to create triangles in + ntlVec3Gfx mStart, mEnd; + + //! normalized domain extent from parametrizer/visualizer + ntlVec3Gfx mDomainExtent; + + //! initialized? + bool mInitDone; + + //! amount of surface smoothing + float mSmoothSurface; + //! amount of normal smoothing + float mSmoothNormals; + + //! grid data + vector mAcrossEdge; + vector< vector > mAdjacentFaces; + + //! cutoff border area + int mCutoff; + //! cutoff heigh values + int *mCutArray; + //! particle pointer + ParticleTracer *mpIsoParts; + //! particle size + float mPartSize; + //! no of subdivisions + int mSubdivs; + + //! trimesh vars + vector flags; + int mFlagCnt; + vector cornerareas; + vector pointareas; + vector< vector > neighbors; + + public: + // miscelleanous access functions + + //! set geometry start (for renderer) + void setStart(ntlVec3Gfx set) { mStart = set; }; + ntlVec3Gfx getStart() { return mStart; }; + //! set geometry end (for renderer) + void setEnd(ntlVec3Gfx set) { mEnd = set; }; + ntlVec3Gfx getEnd() { return mEnd; }; + //! set iso level value for surface reconstruction + inline void setIsolevel(double set) { mIsoValue = set; }; + //! set loop subdiv num + inline void setSmoothSurface(float set) { mSmoothSurface = set; }; + inline void setSmoothNormals(float set) { mSmoothNormals = set; }; + inline float getSmoothSurface() { return mSmoothSurface; } + inline float getSmoothNormals() { return mSmoothNormals; } + + // geometry object functions + virtual void getTriangles(double t, vector *triangles, + vector *vertices, + vector *normals, int objectId ); + + //! for easy GUI detection get start of axis aligned bounding box, return NULL of no BB + virtual inline ntlVec3Gfx *getBBStart() { return &mStart; } + virtual inline ntlVec3Gfx *getBBEnd() { return &mEnd; } + + //! access data array + inline float* getData(){ return mpData; } + inline float* getData(int ii, int jj, int kk){ +#if ISO_STRICT_DEBUG==1 + if(ii<0){ errMsg("IsoStrict"," invX- |"<mSizex-1){ errMsg("IsoStrict"," invX+ |"<mSizey-1){ errMsg("IsoStrict"," invY+ |"<mSizez-1){ errMsg("IsoStrict"," invZ+ |"<mSizex-1){ errMsg("IsoStrict"," invX+ |"<mSizey-1){ errMsg("IsoStrict"," invY+ |"<mSizez-1){ errMsg("IsoStrict"," invZ+ |"< mDboundary; + float mSCrad1, mSCrad2; + ntlVec3Gfx mSCcenter; +}; + + +#define ISOSURFACE_H +#endif + + diff --git a/intern/elbeem/intern/loop_tools.h b/intern/elbeem/intern/loop_tools.h new file mode 100644 index 00000000000..3c15a609210 --- /dev/null +++ b/intern/elbeem/intern/loop_tools.h @@ -0,0 +1,109 @@ + +// advance pointer in main loop +#define ADVANCE_POINTERS(p) \ + ccel += (QCELLSTEP*(p)); \ + tcel += (QCELLSTEP*(p)); \ + pFlagSrc+= (p); \ + pFlagDst+= (p); \ + i+= (p); + +#define MAX_CALC_ARR 4 + +// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +// init region vars +#define GRID_REGION_INIT() \ + const int istart = -1+gridLoopBound; \ + const int iend = mLevel[mMaxRefine].lSizex-1-gridLoopBound; \ + LbmFloat calcCurrentMass=0; \ + LbmFloat calcCurrentVolume=0; \ + int calcCellsFilled=0; \ + int calcCellsEmptied=0; \ + int calcNumUsedCells=0; \ + + + + +// ----------------------------------------------------------------------------------- +// serial stuff +#if PARALLEL!=1 + +#define PERFORM_USQRMAXCHECK USQRMAXCHECK(usqr,ux,uy,uz, mMaxVlen, mMxvx,mMxvy,mMxvz); +#define LIST_EMPTY(x) mListEmpty.push_back( x ); +#define LIST_FULL(x) mListFull.push_back( x ); +#define FSGR_ADDPART(x) mpParticles->addFullParticle( x ); + +// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +#define GRID_REGION_START() \ + { /* main_region */ \ + int kstart=getForZMinBnd(), kend=getForZMaxBnd(mMaxRefine); \ + if(gridLoopBound>0){ kstart=getForZMin1(), kend=getForZMax1(mMaxRefine); } \ + int kdir = 1; \ + int jstart = gridLoopBound; \ + int jend = mLevel[mMaxRefine].lSizey-gridLoopBound; \ + const int id=0; \ + LbmFloat *ccel = NULL, *tcel = NULL; \ + CellFlagType *pFlagSrc=NULL, *pFlagDst=NULL; \ + if(mLevel[mMaxRefine].setCurr==1) { \ + kdir = -1; \ + int temp = kend; \ + kend = kstart-1; \ + kstart = temp-1; \ + temp = id; /* dummy remove warning */ \ + } \ + + + + +#define unused_GRID_REGION_END() \ + } /* main_region */ \ + // end unusedGRID_REGION_END + + +// ----------------------------------------------------------------------------------- +#else // PARALLEL==1 + +#include "paraloop.h" + +#endif // PARALLEL==1 + + +// ----------------------------------------------------------------------------------- + +// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +#define GRID_LOOP_START() \ + for(int k=kstart;k!=kend;k+=kdir) { \ + pFlagSrc = &RFLAG(lev, istart, jstart, k, SRCS(lev)); \ + pFlagDst = &RFLAG(lev, istart, jstart, k, TSET(lev)); \ + ccel = RACPNT(lev, istart, jstart, k, SRCS(lev)); \ + tcel = RACPNT(lev, istart, jstart, k, TSET(lev)); \ + for(int j=jstart;j!=jend;++j) { \ + /* for(int i=0;i>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +#define GRID_LOOPREG_END() \ + \ + } /* i */ \ + int i=0; \ + ADVANCE_POINTERS(2*gridLoopBound); \ + } /* j */ \ + /* COMPRESSGRIDS!=1 */ \ + /* int i=0; */ \ + /* ADVANCE_POINTERS(mLevel[lev].lSizex*2); */ \ + } /* all cell loop k,j,i */ \ + if(doReduce) { } /* dummy remove warning */ \ + } /* main_region */ \ + \ + + + +// old loop for COMPRESSGRIDS==0 +#define old__GRID_LOOP_START() \ + for(int k=kstart;k +#include + +#include "utilities.h" +#include "ntl_matrices.h" +#include "ntl_blenderdumper.h" +#include "ntl_world.h" +#include "solver_interface.h" + +#include + + + +/****************************************************************************** + * Constructor + *****************************************************************************/ +ntlBlenderDumper::ntlBlenderDumper() : ntlWorld() +{ + // same as normal constructor here +} +ntlBlenderDumper::ntlBlenderDumper(string filename, bool commandlineMode) : + ntlWorld(filename,commandlineMode) +{ + // init world +} + + + +/****************************************************************************** + * Destructor + *****************************************************************************/ +ntlBlenderDumper::~ntlBlenderDumper() +{ + debMsgStd("ntlBlenderDumper",DM_NOTIFY, "ntlBlenderDumper done", 10); +} + +// required globals +extern bool glob_mpactive; +extern int glob_mpnum, glob_mpindex; + +/****************************************************************************** + * Only dump time dep. objects to file + *****************************************************************************/ +int ntlBlenderDumper::renderScene( void ) +{ + char nrStr[5]; /* nr conversion */ + ntlRenderGlobals *glob = mpGlob; + ntlScene *scene = mpGlob->getSimScene(); + bool debugOut = false; + bool debugRender = false; +#if ELBEEM_PLUGIN==1 + debugOut = false; +#endif // ELBEEM_PLUGIN==1 + + vector gmName; // gm names + vector gmMat; // materials for gm + int numGMs = 0; // no. of .obj models created + + if(debugOut) debMsgStd("ntlBlenderDumper::renderScene",DM_NOTIFY,"Dumping geometry data", 1); + long startTime = getTime(); + snprintf(nrStr, 5, "%04d", glob->getAniCount() ); + + // local scene vars + vector Triangles; + vector Vertices; + vector VertNormals; + + // check geo objects + int idCnt = 0; // give IDs to objects + for (vector::iterator iter = scene->getGeoClasses()->begin(); + iter != scene->getGeoClasses()->end(); iter++) { + if(!(*iter)->getVisible()) continue; + int tid = (*iter)->getTypeId(); + + if(tid & GEOCLASSTID_OBJECT) { + // normal geom. objects -> ignore + } + if(tid & GEOCLASSTID_SHADER) { + ntlGeometryShader *geoshad = (ntlGeometryShader*)(*iter); //dynamic_cast(*iter); + string outname = geoshad->getOutFilename(); + if(outname.length()<1) outname = mpGlob->getOutFilename(); + geoshad->notifyShaderOfDump(DUMP_FULLGEOMETRY, glob->getAniCount(),nrStr,outname); + + for (vector::iterator siter = geoshad->getObjectsBegin(); + siter != geoshad->getObjectsEnd(); + siter++) { + if(debugOut) debMsgStd("ntlBlenderDumper::BuildScene",DM_MSG,"added shader geometry "<<(*siter)->getName(), 8); + + (*siter)->notifyOfDump(DUMP_FULLGEOMETRY, glob->getAniCount(),nrStr,outname, this->mSimulationTime); + bool doDump = false; + bool isPreview = false; + // only dump final&preview surface meshes + if( (*siter)->getName().find( "final" ) != string::npos) { + doDump = true; + } else if( (*siter)->getName().find( "preview" ) != string::npos) { + doDump = true; + isPreview = true; + } + if(!doDump) continue; + + // dont quit, some objects need notifyOfDump call + if((glob_mpactive) && (glob_mpindex>0)) { + continue; //return 0; + } + + // only dump geo shader objects + Triangles.clear(); + Vertices.clear(); + VertNormals.clear(); + (*siter)->initialize( mpGlob ); + (*siter)->getTriangles(this->mSimulationTime, &Triangles, &Vertices, &VertNormals, idCnt); + idCnt ++; + + // WARNING - this is dirty, but simobjs are the only geoshaders right now + SimulationObject *sim = (SimulationObject *)geoshad; + LbmSolverInterface *lbm = sim->getSolver(); + + + // always dump mesh, even empty ones... + + // dump to binary file + std::ostringstream boutfilename(""); + //boutfilename << ecrpath.str() << outname <<"_"<< (*siter)->getName() <<"_" << nrStr << ".obj"; + boutfilename << outname <<"_"<< (*siter)->getName() <<"_" << nrStr; + if(debugOut) debMsgStd("ntlBlenderDumper::renderScene",DM_MSG,"B-Dumping: "<< (*siter)->getName() + <<", triangles:"<getDumpVelocities())) { + std::ostringstream bvelfilename; + bvelfilename << boutfilename.str(); + bvelfilename << ".bvel.gz"; + gzf = gzopen(bvelfilename.str().c_str(), "wb9"); + if(gzf) { + int numVerts; + if(sizeof(numVerts)!=4) { errMsg("ntlBlenderDumper::renderScene","Invalid int size"); return 1; } + numVerts = Vertices.size(); + gzwrite(gzf, &numVerts, sizeof(numVerts)); + for(size_t i=0; igetVelocityAt( Vertices[i][0], Vertices[i][1], Vertices[i][2] ); + // translation not necessary, test rotation & scaling? + for(int j=0; j<3; j++) { + float vertp = v[j]; + //if(i<20) errMsg("ntlBlenderDumper","DUMP_VEL final "< *trafo; + trafo = lbm->getDomainTrafo(); + if(trafo) { + // transform into source space + for(size_t i=0; i rottrafo; + rottrafo.initId(); + if(lbm->getDomainTrafo()) { + // dont modifiy original! + rottrafo = *lbm->getDomainTrafo(); + ntlVec3Gfx rTrans,rScale,rRot,rShear; + rottrafo.decompose(rTrans,rScale,rRot,rShear); + rottrafo.initRotationXYZ(rRot[0],rRot[1],rRot[2]); + // only rotate here... + for(size_t i=0; i0) { + if(debugOut) debMsgStd("ntlBlenderDumper::renderScene",DM_MSG,"Objects dumped: "<0)) { + // ok, nothing to do anyway... + } else { + errFatal("ntlBlenderDumper::renderScene","No objects to dump! Aborting...",SIMWORLD_INITERROR); + return 1; + } + } + + // debug timing + long stopTime = getTime(); + debMsgStd("ntlBlenderDumper::renderScene",DM_MSG,"Scene #"<setAniCount( glob->getAniCount() +1 ); + } + + return 0; +} + + + diff --git a/intern/elbeem/intern/ntl_blenderdumper.h b/intern/elbeem/intern/ntl_blenderdumper.h new file mode 100644 index 00000000000..df66ad7662e --- /dev/null +++ b/intern/elbeem/intern/ntl_blenderdumper.h @@ -0,0 +1,31 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Replaces std. raytracer, and only dumps time dep. objects to disc, header + * + *****************************************************************************/ +#ifndef NTL_BLENDERDUMPER_H +#include "ntl_world.h" + +class ntlBlenderDumper : + public ntlWorld +{ +public: + /*! Constructor */ + ntlBlenderDumper(); + ntlBlenderDumper(string filename, bool commandlineMode); + /*! Destructor */ + virtual ~ntlBlenderDumper( void ); + + /*! render scene (a single pictures) */ + virtual int renderScene( void ); + +protected: + +}; + +#define NTL_BLENDERDUMPER_H +#endif + diff --git a/intern/elbeem/intern/ntl_bsptree.cpp b/intern/elbeem/intern/ntl_bsptree.cpp new file mode 100644 index 00000000000..c444ec70692 --- /dev/null +++ b/intern/elbeem/intern/ntl_bsptree.cpp @@ -0,0 +1,942 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Tree container for fast triangle intersects + * + *****************************************************************************/ + + +#include "ntl_bsptree.h" +#include "utilities.h" + +#include + +/*! Static global variable for sorting direction */ +int globalSortingAxis; +/*! Access to points array for sorting */ +vector *globalSortingPoints; + +#define TREE_DOUBLEI 300 + +/* try axis selection? */ +bool chooseAxis = 0; +/* do median search? */ +int doSort = 0; + + +//! struct for a single node in the bsp tree +class BSPNode { + public: + BSPNode() {}; + + ntlVec3Gfx min,max; /* AABB for node */ + vector *members; /* stored triangles */ + BSPNode *child[2]; /* pointer to children nodes */ + char axis; /* division axis */ + char cloneVec; /* is this vector a clone? */ + + //! check if node is a leaf + inline bool isLeaf() const { + return (child[0] == NULL); + } +}; + + +//! an element node stack +class BSPStackElement { + public: + //! tree node + BSPNode *node; + //! min and maximum distance along axis + gfxReal mindist, maxdist; +}; + +//! bsp tree stack +class BSPStack { + public: + //! current stack element + int stackPtr; + //! stack storage + BSPStackElement elem[ BSP_STACK_SIZE ]; +}; + +//! triangle bounding box for quick tree subdivision +class TriangleBBox { + public: + //! start and end of triangle bounding box + ntlVec3Gfx start, end; +}; + + +/****************************************************************************** + * calculate tree statistics + *****************************************************************************/ +void calcStats(BSPNode *node, int depth, int &noLeafs, gfxReal &avgDepth, gfxReal &triPerLeaf,int &totalTris) +{ + if(node->members != NULL) { + totalTris += node->members->size(); + } + //depth = 15; // DBEUG! + + if( (node->child[0]==NULL) && (node->child[1]==NULL) ) { + // leaf + noLeafs++; + avgDepth += depth; + triPerLeaf += node->members->size(); + } else { + for(int i=0;i<2;i++) + calcStats(node->child[i], depth+1, noLeafs, avgDepth, triPerLeaf, totalTris); + } +} + + + +/****************************************************************************** + * triangle comparison function for median search + *****************************************************************************/ +bool lessTriangleAverage(const ntlTriangle *x, const ntlTriangle *y) +{ + return x->getAverage(globalSortingAxis) < y->getAverage(globalSortingAxis); +} + + +/****************************************************************************** + * triangle AABB intersection + *****************************************************************************/ +bool ntlTree::checkAABBTriangle(ntlVec3Gfx &min, ntlVec3Gfx &max, ntlTriangle *tri) +{ + // test only BB of triangle + TriangleBBox *bbox = &mpTBB[ tri->getBBoxId() ]; + if( bbox->end[0] < min[0] ) return false; + if( bbox->start[0] > max[0] ) return false; + if( bbox->end[1] < min[1] ) return false; + if( bbox->start[1] > max[1] ) return false; + if( bbox->end[2] < min[2] ) return false; + if( bbox->start[2] > max[2] ) return false; + return true; +} + + + + + + + +/****************************************************************************** + * Default constructor + *****************************************************************************/ +ntlTree::ntlTree() : + mStart(0.0), mEnd(0.0), mMaxDepth( 5 ), mMaxListLength( 5 ), mpRoot( NULL) , + mpNodeStack( NULL), mpVertices( NULL ), mpVertNormals( NULL ), mpTriangles( NULL ), + mCurrentDepth(0), mCurrentNodes(0), mTriDoubles(0) +{ + errFatal( "ntlTree","Uninitialized BSP Tree!\n",SIMWORLD_INITERROR ); + return; +} + + +/****************************************************************************** + * Constructor with init + *****************************************************************************/ +//ntlTree::ntlTree(int depth, int objnum, vector *vertices, vector *normals, vector *trilist) : +ntlTree::ntlTree(int depth, int objnum, ntlScene *scene, int triFlagMask) : + mStart(0.0), mEnd(0.0), mMaxDepth( depth ), mMaxListLength( objnum ), mpRoot( NULL) , + mpNodeStack( NULL), mpTBB( NULL ), + mTriangleMask( 0xFFFF ), + mCurrentDepth(0), mCurrentNodes(0), mTriDoubles(0) +{ + // init scene data pointers + mpVertices = scene->getVertexPointer(); + mpVertNormals = scene->getVertexNormalPointer(); + mpTriangles = scene->getTrianglePointer(); + mTriangleMask = triFlagMask; + + if(mpTriangles == NULL) { + errFatal( "ntlTree Cons","no triangle list!\n",SIMWORLD_INITERROR); + return; + } + if(mpTriangles->size() == 0) { + warnMsg( "ntlTree::ntlTree","No triangles ("<< mpTriangles->size() <<")!\n"); + mStart = mEnd = ntlVec3Gfx(0,0,0); + return; + } + if(depth>=BSP_STACK_SIZE) { + errFatal( "ntlTree::ntlTree","Depth to high ("<< mMaxDepth <<")!\n", SIMWORLD_INITERROR ); + return; + } + + /* check triangles (a bit inefficient, but we dont know which vertices belong + to this tree), and generate bounding boxes */ + mppTriangles = new vector; + int noOfTriangles = mpTriangles->size(); + mpTBB = new TriangleBBox[ noOfTriangles ]; + int bbCount = 0; + mStart = mEnd = (*mpVertices)[ mpTriangles->front().getPoints()[0] ]; + //errMsg("TreeDebug","Start"); + for (vector::iterator iter = mpTriangles->begin(); + iter != mpTriangles->end(); + iter++ ) { + //errorOut(" d "<< convertFlags2String((int)(*iter).getFlags()) <<" "<< convertFlags2String( (int)mTriangleMask)<<" add? "<<( ((int)(*iter).getFlags() & (int)mTriangleMask) != 0 ) ); + // discard triangles that dont match mask + if( ((int)(*iter).getFlags() & (int)mTriangleMask) == 0 ) { + continue; + } + + // test? TODO + ntlVec3Gfx tnormal = (*mpVertNormals)[ (*iter).getPoints()[0] ]+ + (*mpVertNormals)[ (*iter).getPoints()[1] ]+ + (*mpVertNormals)[ (*iter).getPoints()[2] ]; + ntlVec3Gfx triangleNormal = (*iter).getNormal(); + if( equal(triangleNormal, ntlVec3Gfx(0.0)) ) continue; + if( equal( tnormal, ntlVec3Gfx(0.0)) ) continue; + // */ + + ntlVec3Gfx bbs, bbe; + //errMsg("TreeDebug","Triangle"); + for(int i=0;i<3;i++) { + int index = (*iter).getPoints()[i]; + ntlVec3Gfx tp = (*mpVertices)[ index ]; + //errMsg("TreeDebug"," Point "< mEnd[0]) mEnd[0]= tp[0]; + if(tp[1] < mStart[1]) mStart[1]= tp[1]; + if(tp[1] > mEnd[1]) mEnd[1]= tp[1]; + if(tp[2] < mStart[2]) mStart[2]= tp[2]; + if(tp[2] > mEnd[2]) mEnd[2]= tp[2]; + if(i==0) { + bbs = bbe = tp; + } else { + if( tp[0] < bbs[0] ) bbs[0] = tp[0]; + if( tp[0] > bbe[0] ) bbe[0] = tp[0]; + if( tp[1] < bbs[1] ) bbs[1] = tp[1]; + if( tp[1] > bbe[1] ) bbe[1] = tp[1]; + if( tp[2] < bbs[2] ) bbs[2] = tp[2]; + if( tp[2] > bbe[2] ) bbe[2] = tp[2]; + } + } + mppTriangles->push_back( &(*iter) ); + //errMsg("TreeDebug","Triangle "<<(*mpVertices)[(*iter).getPoints()[0]]<<" "<<(*mpVertices)[(*iter).getPoints()[1]]<<" "<<(*mpVertices)[(*iter).getPoints()[2]]<<" "); + + // add BB + mpTBB[ bbCount ].start = bbs; + mpTBB[ bbCount ].end = bbe; + (*iter).setBBoxId( bbCount ); + bbCount++; + } + + + + /* slighlty enlarge bounding tolerance for tree + to avoid problems with triangles paralell to slabs */ + mStart -= ntlVec3Gfx( getVecEpsilon() ); + mEnd += ntlVec3Gfx( getVecEpsilon() ); + + /* init root node and stack */ + mpNodeStack = new BSPStack; + mpRoot = new BSPNode; + mpRoot->min = mStart; + mpRoot->max = mEnd; + mpRoot->axis = AXIS_X; + mpRoot->members = mppTriangles; + mpRoot->child[0] = mpRoot->child[1] = NULL; + mpRoot->cloneVec = 0; + globalSortingPoints = mpVertices; + mpTriDist = new char[ mppTriangles->size() ]; + mNumNodes = 1; + mAbortSubdiv = 0; + + /* create tree */ + debugOutInter( "Generating BSP Tree... (Nodes "<< mCurrentNodes << + ", Depth "<members->size() <<" "<min<<" - "<max ); + + if(depth>mCurrentDepth) mCurrentDepth = depth; + node->child[0] = node->child[1] = NULL; + if( ( (int)node->members->size() > mMaxListLength) && + (depth < mMaxDepth ) + && (node->cloneVec<10) + && (!mAbortSubdiv) + ) { + + gfxReal planeDiv = 0.499999; // position of plane division + + // determine next subdivision axis + int newaxis = 0; + gfxReal extX = node->max[0]-node->min[0]; + gfxReal extY = node->max[1]-node->min[1]; + gfxReal extZ = node->max[2]-node->min[2]; + + if( extY>extX ) { + if( extZ>extY ) { + newaxis = 2; + } else { + newaxis = 1; + } + } else { + if( extZ>extX ) { + newaxis = 2; + } else { + newaxis = 0; + } + } + axis = node->axis = newaxis; + + // init child nodes + for( int i=0; i<2; i++) { + /* status output */ + mCurrentNodes++; + if(mCurrentNodes % 13973 ==0) { + debugOutInter( "NTL Generating BSP Tree ("<child[i] = new BSPNode; + node->child[i]->min = node->min; + node->child[i]->max = node->max; + node->child[i]->max = node->max; + node->child[i]->child[0] = NULL; + node->child[i]->child[1] = NULL; + node->child[i]->members = NULL; + nextAxis = (axis+1)%3; + node->child[i]->axis = nextAxis; + mNumNodes++; + // abort when using 256MB only for tree... + if(mNumNodes*sizeof(BSPNode)> 1024*1024*512) mAbortSubdiv = 1; + + /* current division plane */ + if(!i) { + node->child[i]->min[axis] = node->min[axis]; + node->child[i]->max[axis] = node->min[axis] + planeDiv* + (node->max[axis]-node->min[axis]); + } else { + node->child[i]->min[axis] = node->min[axis] + planeDiv* + (node->max[axis]-node->min[axis]); + node->child[i]->max[axis] = node->max[axis]; + } + } + + + /* process the two children */ + int thisTrisFor[2] = {0,0}; + int thisTriDoubles[2] = {0,0}; + for(int t=0;t<(int)node->members->size();t++) mpTriDist[t] = 0; + for( int i=0; i<2; i++) { + /* distribute triangles */ + int t = 0; + for (vector::iterator iter = node->members->begin(); + iter != node->members->end(); iter++ ) { + + /* add triangle, check bounding box axis */ + TriangleBBox *bbox = &mpTBB[ (*iter)->getBBoxId() ]; + bool isintersect = true; + if( bbox->end[axis] < node->child[i]->min[axis] ) isintersect = false; + else if( bbox->start[axis] > node->child[i]->max[axis] ) isintersect = false; + if(isintersect) { + // add flag to vector + mpTriDist[t] |= (1<child[i]->members = new vector( thisTrisFor[i] ); + node->child[i]->cloneVec = 0; + } + + int tind0 = 0; + int tind1 = 0; + if( (!haveCloneVec[0]) || (!haveCloneVec[1]) ){ + int t = 0; // triangle index counter + for (vector::iterator iter = node->members->begin(); + iter != node->members->end(); iter++ ) { + if(!haveCloneVec[0]) { + if( (mpTriDist[t] & 1) == 1) { + (*node->child[0]->members)[tind0] = (*iter); // dont use push_back for preinited size! + tind0++; + } + } + if(!haveCloneVec[1]) { + if( (mpTriDist[t] & 2) == 2) { + (*node->child[1]->members)[tind1] = (*iter); // dont use push_back for preinited size! + tind1++; + } + } + t++; + } /* end of loop over all triangles */ + } + + // subdivide children + for( int i=0; i<2; i++) { + /* recurse */ + subdivide( node->child[i], depth+1, nextAxis ); + } + + /* if we are here, this are childs, so we dont need the members any more... */ + /* delete unecessary members */ + if( (!haveCloneVec[0]) && (!haveCloneVec[1]) && (node->cloneVec == 0) ){ + delete node->members; + } + node->members = NULL; + + } /* subdivision necessary */ +} + +/****************************************************************** + * triangle intersection with triangle pointer, + * returns t,u,v by references + */ +#if GFX_PRECISION==1 +// float values +//! the minimal triangle determinant length +#define RAY_TRIANGLE_EPSILON (1e-07) + +#else +// double values +//! the minimal triangle determinant length +#define RAY_TRIANGLE_EPSILON (1e-15) + +#endif + + +/****************************************************************************** + * intersect ray with BSPtree + *****************************************************************************/ +inline void ntlRay::intersectTriangle(vector *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const +{ + /* (cf. moeller&haines, page 305) */ + t = GFX_REAL_MAX; + ntlVec3Gfx e0 = (*mpV)[ tri->getPoints()[0] ]; + ntlVec3Gfx e1 = (*mpV)[ tri->getPoints()[1] ] - e0; + ntlVec3Gfx e2 = (*mpV)[ tri->getPoints()[2] ] - e0; + ntlVec3Gfx p = cross( mDirection, e2 ); + gfxReal divisor = dot(e1, p); + if((divisor > -RAY_TRIANGLE_EPSILON)&&(divisor < RAY_TRIANGLE_EPSILON)) return; + + gfxReal invDivisor = 1/divisor; + ntlVec3Gfx s = mOrigin - e0; + u = invDivisor * dot(s, p); + if( (u<0.0-RAY_TRIANGLE_EPSILON) || (u>1.0+RAY_TRIANGLE_EPSILON) ) return; + + ntlVec3Gfx q = cross( s,e1 ); + v = invDivisor * dot(mDirection, q); + if( (v<0.0-RAY_TRIANGLE_EPSILON) || ((u+v)>1.0+RAY_TRIANGLE_EPSILON) ) return; + + t = invDivisor * dot(e2, q); +} +void ntlTree::intersect(const ntlRay &ray, gfxReal &distance, + ntlVec3Gfx &normal, + ntlTriangle *&tri, + int flags, bool forceNonsmooth) const +{ + gfxReal mint = GFX_REAL_MAX; /* current minimal t */ + ntlVec3Gfx retnormal; /* intersection (interpolated) normal */ + gfxReal mintu=0.0, mintv=0.0; /* u,v for min t intersection */ + + BSPNode *curr, *nearChild, *farChild; /* current node and children */ + gfxReal planedist, mindist, maxdist; + ntlVec3Gfx pos; + + ntlTriangle *hit = NULL; + tri = NULL; + + ray.intersectCompleteAABB(mStart,mEnd,mindist,maxdist); + + if((maxdist < 0.0) || + (!mpRoot) || + (mindist == GFX_REAL_MAX) || + (maxdist == GFX_REAL_MAX) ) { + distance = -1.0; + return; + } + mindist -= getVecEpsilon(); + maxdist += getVecEpsilon(); + + /* stack init */ + mpNodeStack->elem[0].node = NULL; + mpNodeStack->stackPtr = 1; + + curr = mpRoot; + mint = GFX_REAL_MAX; + while(curr != NULL) { + + while( !curr->isLeaf() ) { + planedist = distanceToPlane(curr, curr->child[0]->max, ray ); + getChildren(curr, ray.getOrigin(), nearChild, farChild ); + + // check ray direction for small plane distances + if( (planedist>-getVecEpsilon() )&&(planedist< getVecEpsilon() ) ) { + // ray origin on intersection plane + planedist = 0.0; + if(ray.getDirection()[curr->axis]>getVecEpsilon() ) { + // larger coords + curr = curr->child[1]; + } else if(ray.getDirection()[curr->axis]<-getVecEpsilon() ) { + // smaller coords + curr = curr->child[0]; + } else { + // paralell, order doesnt really matter are min/max/plane ok? + mpNodeStack->elem[ mpNodeStack->stackPtr ].node = curr->child[0]; + mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist = planedist; + mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist = maxdist; + (mpNodeStack->stackPtr)++; + curr = curr->child[1]; + maxdist = planedist; + } + } else { + // normal ray + if( (planedist>maxdist) || (planedist<0.0-getVecEpsilon() ) ) { + curr = nearChild; + } else if(planedist < mindist) { + curr = farChild; + } else { + mpNodeStack->elem[ mpNodeStack->stackPtr ].node = farChild; + mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist = planedist; + mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist = maxdist; + (mpNodeStack->stackPtr)++; + + curr = nearChild; + maxdist = planedist; + } + } + } + + + /* intersect with current node */ + for (vector::iterator iter = curr->members->begin(); + iter != curr->members->end(); iter++ ) { + + /* check for triangle flags before intersecting */ + if((!flags) || ( ((*iter)->getFlags() & flags) > 0 )) { + + if( ((*iter)->getLastRay() == ray.getID() )&&((*iter)->getLastRay()>0) ) { + // was already intersected... + } else { + // we still need to intersect this triangle + gfxReal u=0.0,v=0.0, t=-1.0; + ray.intersectTriangle( mpVertices, (*iter), t,u,v); + (*iter)->setLastRay( ray.getID() ); + + if( (t > 0.0) && (t0.0) && (mint < GFX_REAL_MAX) ) { + pos = ray.getOrigin() + ray.getDirection()*mint; + + if( (pos[0] >= curr->min[0]) && (pos[0] <= curr->max[0]) && + (pos[1] >= curr->min[1]) && (pos[1] <= curr->max[1]) && + (pos[2] >= curr->min[2]) && (pos[2] <= curr->max[2]) ) + { + + if(forceNonsmooth) { + // calculate triangle normal + ntlVec3Gfx e0,e1,e2; + e0 = (*mpVertices)[ hit->getPoints()[0] ]; + e1 = (*mpVertices)[ hit->getPoints()[1] ]; + e2 = (*mpVertices)[ hit->getPoints()[2] ]; + retnormal = cross( -(e2-e0), (e1-e0) ); + } else { + // calculate interpolated normal + retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+ + (*mpVertNormals)[ hit->getPoints()[1] ]*mintu + + (*mpVertNormals)[ hit->getPoints()[2] ]*mintv; + } + normalize(retnormal); + normal = retnormal; + distance = mint; + tri = hit; + return; + } + } + + (mpNodeStack->stackPtr)--; + curr = mpNodeStack->elem[ mpNodeStack->stackPtr ].node; + mindist = mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist; + maxdist = mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist; + } /* traverse tree */ + + if(mint == GFX_REAL_MAX) { + distance = -1.0; + } else { + // intersection outside the BSP bounding volumes might occur due to roundoff... + //retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+ (*mpVertNormals)[ hit->getPoints()[1] ]*mintu + (*mpVertNormals)[ hit->getPoints()[2] ]*mintv; + if(forceNonsmooth) { + // calculate triangle normal + ntlVec3Gfx e0,e1,e2; + e0 = (*mpVertices)[ hit->getPoints()[0] ]; + e1 = (*mpVertices)[ hit->getPoints()[1] ]; + e2 = (*mpVertices)[ hit->getPoints()[2] ]; + retnormal = cross( -(e2-e0), (e1-e0) ); + } else { + // calculate interpolated normal + retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+ + (*mpVertNormals)[ hit->getPoints()[1] ]*mintu + + (*mpVertNormals)[ hit->getPoints()[2] ]*mintv; + } + + normalize(retnormal); + normal = retnormal; + distance = mint; + tri = hit; + } + return; +} + +inline void ntlRay::intersectTriangleX(vector *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const +{ + /* (cf. moeller&haines, page 305) */ + t = GFX_REAL_MAX; + ntlVec3Gfx e0 = (*mpV)[ tri->getPoints()[0] ]; + ntlVec3Gfx e1 = (*mpV)[ tri->getPoints()[1] ] - e0; + ntlVec3Gfx e2 = (*mpV)[ tri->getPoints()[2] ] - e0; + + //ntlVec3Gfx p = cross( mDirection, e2 ); + //ntlVector3Dim cp( (-), (- (1.0 *v[2])), ((1.0 *v[1]) -) ); + ntlVec3Gfx p(0.0, -e2[2], e2[1]); + + gfxReal divisor = dot(e1, p); + if((divisor > -RAY_TRIANGLE_EPSILON)&&(divisor < RAY_TRIANGLE_EPSILON)) return; + + gfxReal invDivisor = 1/divisor; + ntlVec3Gfx s = mOrigin - e0; + u = invDivisor * dot(s, p); + if( (u<0.0-RAY_TRIANGLE_EPSILON) || (u>1.0+RAY_TRIANGLE_EPSILON) ) return; + + ntlVec3Gfx q = cross( s,e1 ); + //v = invDivisor * dot(mDirection, q); + v = invDivisor * q[0]; + if( (v<0.0-RAY_TRIANGLE_EPSILON) || ((u+v)>1.0+RAY_TRIANGLE_EPSILON) ) return; + + t = invDivisor * dot(e2, q); +} +void ntlTree::intersectX(const ntlRay &ray, gfxReal &distance, + ntlVec3Gfx &normal, + ntlTriangle *&tri, + int flags, bool forceNonsmooth) const +{ + gfxReal mint = GFX_REAL_MAX; /* current minimal t */ + ntlVec3Gfx retnormal; /* intersection (interpolated) normal */ + gfxReal mintu=0.0, mintv=0.0; /* u,v for min t intersection */ + + BSPNode *curr, *nearChild, *farChild; /* current node and children */ + gfxReal planedist, mindist, maxdist; + ntlVec3Gfx pos; + + ntlTriangle *hit = NULL; + tri = NULL; + + ray.intersectCompleteAABB(mStart,mEnd,mindist,maxdist); // +X + + if((maxdist < 0.0) || + (!mpRoot) || + (mindist == GFX_REAL_MAX) || + (maxdist == GFX_REAL_MAX) ) { + distance = -1.0; + return; + } + mindist -= getVecEpsilon(); + maxdist += getVecEpsilon(); + + /* stack init */ + mpNodeStack->elem[0].node = NULL; + mpNodeStack->stackPtr = 1; + + curr = mpRoot; + mint = GFX_REAL_MAX; + while(curr != NULL) { // +X + + while( !curr->isLeaf() ) { + planedist = distanceToPlane(curr, curr->child[0]->max, ray ); + getChildren(curr, ray.getOrigin(), nearChild, farChild ); + + // check ray direction for small plane distances + if( (planedist>-getVecEpsilon() )&&(planedist< getVecEpsilon() ) ) { + // ray origin on intersection plane + planedist = 0.0; + if(ray.getDirection()[curr->axis]>getVecEpsilon() ) { + // larger coords + curr = curr->child[1]; + } else if(ray.getDirection()[curr->axis]<-getVecEpsilon() ) { + // smaller coords + curr = curr->child[0]; + } else { + // paralell, order doesnt really matter are min/max/plane ok? + mpNodeStack->elem[ mpNodeStack->stackPtr ].node = curr->child[0]; + mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist = planedist; + mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist = maxdist; + (mpNodeStack->stackPtr)++; + curr = curr->child[1]; + maxdist = planedist; + } + } else { + // normal ray + if( (planedist>maxdist) || (planedist<0.0-getVecEpsilon() ) ) { + curr = nearChild; + } else if(planedist < mindist) { + curr = farChild; + } else { + mpNodeStack->elem[ mpNodeStack->stackPtr ].node = farChild; + mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist = planedist; + mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist = maxdist; + (mpNodeStack->stackPtr)++; + + curr = nearChild; + maxdist = planedist; + } + } + } // +X + + + /* intersect with current node */ + for (vector::iterator iter = curr->members->begin(); + iter != curr->members->end(); iter++ ) { + + /* check for triangle flags before intersecting */ + if((!flags) || ( ((*iter)->getFlags() & flags) > 0 )) { + + if( ((*iter)->getLastRay() == ray.getID() )&&((*iter)->getLastRay()>0) ) { + // was already intersected... + } else { + // we still need to intersect this triangle + gfxReal u=0.0,v=0.0, t=-1.0; + ray.intersectTriangleX( mpVertices, (*iter), t,u,v); + (*iter)->setLastRay( ray.getID() ); + + if( (t > 0.0) && (t0.0) && (mint < GFX_REAL_MAX) ) { + pos = ray.getOrigin() + ray.getDirection()*mint; + + if( (pos[0] >= curr->min[0]) && (pos[0] <= curr->max[0]) && + (pos[1] >= curr->min[1]) && (pos[1] <= curr->max[1]) && + (pos[2] >= curr->min[2]) && (pos[2] <= curr->max[2]) ) + { + + if(forceNonsmooth) { + // calculate triangle normal + ntlVec3Gfx e0,e1,e2; + e0 = (*mpVertices)[ hit->getPoints()[0] ]; + e1 = (*mpVertices)[ hit->getPoints()[1] ]; + e2 = (*mpVertices)[ hit->getPoints()[2] ]; + retnormal = cross( -(e2-e0), (e1-e0) ); + } else { + // calculate interpolated normal + retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+ + (*mpVertNormals)[ hit->getPoints()[1] ]*mintu + + (*mpVertNormals)[ hit->getPoints()[2] ]*mintv; + } + normalize(retnormal); + normal = retnormal; + distance = mint; + tri = hit; + return; + } + } // +X + + (mpNodeStack->stackPtr)--; + curr = mpNodeStack->elem[ mpNodeStack->stackPtr ].node; + mindist = mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist; + maxdist = mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist; + } /* traverse tree */ + + if(mint == GFX_REAL_MAX) { + distance = -1.0; + } else { + + // intersection outside the BSP bounding volumes might occur due to roundoff... + if(forceNonsmooth) { + // calculate triangle normal + ntlVec3Gfx e0,e1,e2; + e0 = (*mpVertices)[ hit->getPoints()[0] ]; + e1 = (*mpVertices)[ hit->getPoints()[1] ]; + e2 = (*mpVertices)[ hit->getPoints()[2] ]; + retnormal = cross( -(e2-e0), (e1-e0) ); + } else { + // calculate interpolated normal + retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+ + (*mpVertNormals)[ hit->getPoints()[1] ]*mintu + + (*mpVertNormals)[ hit->getPoints()[2] ]*mintv; + } + + normalize(retnormal); + normal = retnormal; + distance = mint; + tri = hit; + } // +X + return; +} + + + +/****************************************************************************** + * distance to plane function for nodes + *****************************************************************************/ +gfxReal ntlTree::distanceToPlane(BSPNode *curr, ntlVec3Gfx plane, ntlRay ray) const +{ + return ( (plane[curr->axis]-ray.getOrigin()[curr->axis]) / ray.getDirection()[curr->axis] ); +} + + +/****************************************************************************** + * return ordering of children nodes relatice to origin point + *****************************************************************************/ +void ntlTree::getChildren(BSPNode *curr, ntlVec3Gfx origin, BSPNode *&node_near, BSPNode *&node_far) const +{ + if(curr->child[0]->max[ curr->axis ] >= origin[ curr->axis ]) { + node_near = curr->child[0]; + node_far = curr->child[1]; + } else { + node_near = curr->child[1]; + node_far = curr->child[0]; + } +} + + +/****************************************************************************** + * delete a node of the tree with all sub nodes + * dont delete root members + *****************************************************************************/ +void ntlTree::deleteNode(BSPNode *curr) +{ + if(!curr) return; + + if(curr->child[0] != NULL) + deleteNode(curr->child[0]); + if(curr->child[1] != NULL) + deleteNode(curr->child[1]); + + if(curr->members != NULL) delete curr->members; + delete curr; +} + + + +/****************************************************************** + * intersect only front or backsides + * currently unused + */ +inline void ntlRay::intersectTriangleFront(vector *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const +{ + t = GFX_REAL_MAX; + ntlVec3Gfx e0 = (*mpV)[ tri->getPoints()[0] ]; + ntlVec3Gfx e1 = (*mpV)[ tri->getPoints()[1] ] - e0; + ntlVec3Gfx e2 = (*mpV)[ tri->getPoints()[2] ] - e0; + ntlVec3Gfx p = cross( mDirection, e2 ); + gfxReal a = dot(e1, p); + //if((a > -RAY_TRIANGLE_EPSILON)&&(a < RAY_TRIANGLE_EPSILON)) return; + if(a < RAY_TRIANGLE_EPSILON) return; // cull backsides + + gfxReal f = 1/a; + ntlVec3Gfx s = mOrigin - e0; + u = f * dot(s, p); + if( (u<0.0-RAY_TRIANGLE_EPSILON) || (u>1.0+RAY_TRIANGLE_EPSILON) ) return; + + ntlVec3Gfx q = cross( s,e1 ); + v = f * dot(mDirection, q); + if( (v<0.0-RAY_TRIANGLE_EPSILON) || ((u+v)>1.0+RAY_TRIANGLE_EPSILON) ) return; + + t = f * dot(e2, q); +} +inline void ntlRay::intersectTriangleBack(vector *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const +{ + t = GFX_REAL_MAX; + ntlVec3Gfx e0 = (*mpV)[ tri->getPoints()[0] ]; + ntlVec3Gfx e1 = (*mpV)[ tri->getPoints()[1] ] - e0; + ntlVec3Gfx e2 = (*mpV)[ tri->getPoints()[2] ] - e0; + ntlVec3Gfx p = cross( mDirection, e2 ); + gfxReal a = dot(e1, p); + //if((a > -RAY_TRIANGLE_EPSILON)&&(a < RAY_TRIANGLE_EPSILON)) return; + if(a > -RAY_TRIANGLE_EPSILON) return; // cull frontsides + + gfxReal f = 1/a; + ntlVec3Gfx s = mOrigin - e0; + u = f * dot(s, p); + if( (u<0.0-RAY_TRIANGLE_EPSILON) || (u>1.0+RAY_TRIANGLE_EPSILON) ) return; + + ntlVec3Gfx q = cross( s,e1 ); + v = f * dot(mDirection, q); + if( (v<0.0-RAY_TRIANGLE_EPSILON) || ((u+v)>1.0+RAY_TRIANGLE_EPSILON) ) return; + + t = f * dot(e2, q); +} + + + diff --git a/intern/elbeem/intern/ntl_bsptree.h b/intern/elbeem/intern/ntl_bsptree.h new file mode 100644 index 00000000000..35bc7c61837 --- /dev/null +++ b/intern/elbeem/intern/ntl_bsptree.h @@ -0,0 +1,125 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Tree container for fast triangle intersects + * + *****************************************************************************/ +#ifndef NTL_TREE_H +#define NTL_TREE_H + +#include "ntl_vector3dim.h" +#include "ntl_ray.h" + + +#define AXIS_X 0 +#define AXIS_Y 1 +#define AXIS_Z 2 + +#define BSP_STACK_SIZE 50 + + +//! bsp tree stack classes, defined in ntl_bsptree.cpp, +// detailed definition unnecesseary here +class BSPNode; +class BSPStackElement; +class BSPStack; +class TriangleBBox; +class ntlScene; +class ntlTriangle; + + +//! Class for a bsp tree for triangles +class ntlTree +{ + public: + + //! Default constructor + ntlTree(); + //! Constructor with init + ntlTree(int depth, int objnum, ntlScene *scene, int triFlagMask); + //! Destructor + ~ntlTree(); + + //! subdivide tree + void subdivide(BSPNode *node, int depth, int axis); + + //! intersect ray with BSPtree + void intersect(const ntlRay &ray, gfxReal &distance, ntlVec3Gfx &normal, ntlTriangle *&tri, int flags, bool forceNonsmooth) const; + //! intersect along +X ray + void intersectX(const ntlRay &ray, gfxReal &distance, ntlVec3Gfx &normal, ntlTriangle *&tri, int flags, bool forceNonsmooth) const; + + //! Returns number of nodes + int getCurrentNodes( void ) { return mCurrentNodes; } + + protected: + + // check if a triangle is in a node + bool checkAABBTriangle(ntlVec3Gfx &min, ntlVec3Gfx &max, ntlTriangle *tri); + + + // VARs + + //! distance to plane function for nodes + gfxReal distanceToPlane(BSPNode *curr, ntlVec3Gfx plane, ntlRay ray) const; + + //! return ordering of children nodes relatice to origin point + void getChildren(BSPNode *curr, ntlVec3Gfx origin, BSPNode *&node_near, BSPNode *&node_far) const; + + //! delete a node of the tree with all sub nodes, dont delete root members + void deleteNode(BSPNode *curr); + + //inline bool isLeaf(BSPNode *node) const { return (node->child[0] == NULL); } + + + //! AABB for tree + ntlVec3Gfx mStart,mEnd; + + //! maximum depth of tree + int mMaxDepth; + + //! maximum number of objects in one node + int mMaxListLength; + + //! root node pointer + BSPNode *mpRoot; + //! count no. of node + int mNumNodes; + int mAbortSubdiv; + + //! stack for the node pointers + BSPStack *mpNodeStack; + //stack nodestack; + + //! pointer to vertex array + vector *mpVertices; + + //! pointer to vertex array + vector *mpVertNormals; + + //! vector for all the triangles + vector *mpTriangles; + vector *mppTriangles; + + //! temporary array for triangle distribution to nodes + char *mpTriDist; + + //! temporary array for triangle bounding boxes + TriangleBBox *mpTBB; + + //! triangle mask - include only triangles that match mask + int mTriangleMask; + + //! Status vars (max depth, # of current nodes) + int mCurrentDepth, mCurrentNodes; + + //! duplicated triangles, inited during subdivide + int mTriDoubles; + +}; + + +#endif + + diff --git a/intern/elbeem/intern/ntl_geometryclass.h b/intern/elbeem/intern/ntl_geometryclass.h new file mode 100644 index 00000000000..9282371d183 --- /dev/null +++ b/intern/elbeem/intern/ntl_geometryclass.h @@ -0,0 +1,115 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Base class for geometry shaders and objects + * + *****************************************************************************/ + + +#ifndef NTL_GEOMETRYCLASS_H +#define NTL_GEOMETRYCLASS_H + +#include "attributes.h" + +//! geometry class type ids +#define GEOCLASSTID_OBJECT 1 +#define GEOCLASSTID_SHADER 2 +#define GEOCLASSTID_BOX (GEOCLASSTID_OBJECT| 4) +#define GEOCLASSTID_OBJMODEL (GEOCLASSTID_OBJECT| 8) +#define GEOCLASSTID_SPHERE (GEOCLASSTID_OBJECT| 16) + +class ntlGeometryClass +{ + + public: + + //! Default constructor + inline ntlGeometryClass() : + mVisible( 1 ), mName( "[ObjNameUndef]" ), + mObjectId(-1), mpAttrs( NULL ), mGeoInitId(-1) + { + mpAttrs = new AttributeList("objAttrs"); + mpSwsAttrs = new AttributeList("swsAttrs"); + }; + + //! Default destructor + virtual ~ntlGeometryClass() { + delete mpAttrs; + }; + + //! Return type id + virtual int getTypeId() = 0; + + /*! Set the object name */ + inline void setName(string set) { mName = set; } + /*! Get the object name */ + inline string getName( void ) { return mName; } + + /*! Sets the visibility attribute + * visibility can be determined at shader _and_ object level , hiding a shader + * means comepletely decativating it */ + inline void setVisible(int set) { mVisible=set; } + /*! Returns the visibility attribute */ + inline int getVisible() const { return mVisible; } + + /*! Sets the attribute list pointer */ + inline void setAttributeList(AttributeList *set) { mpAttrs=set; } + /*! Returns the attribute list pointer */ + inline AttributeList *getAttributeList() { return mpAttrs; } + + /*! Get/Sets the attribute list pointer */ + inline void setSwsAttributeList(AttributeList *set) { mpSwsAttrs=set; } + inline AttributeList *getSwsAttributeList() { return mpSwsAttrs; } + + /*! for easy GUI detection get start of axis aligned bounding box, return NULL of no BB */ + virtual inline ntlVec3Gfx *getBBStart() { return NULL; } + virtual inline ntlVec3Gfx *getBBEnd() { return NULL; } + + /*! Set/get the object id*/ + inline void setObjectId(int set) { mObjectId=set; } + inline int getObjectId() const { return mObjectId; } + + /*! GUI - this function is called for selected objects to display debugging information with OpenGL */ + virtual void drawDebugDisplay() { /* do nothing by default */ } + /*! GUI - this function is called for selected objects to display interactive information with OpenGL */ + virtual void drawInteractiveDisplay() { /* do nothing by default */ } + /*! GUI - handle mouse movement for selection */ + virtual void setMousePos(int ,int , ntlVec3Gfx , ntlVec3Gfx ) { /* do nothing by default */ } + /*! GUI - notify object that mouse was clicked at last pos */ + virtual void setMouseClick() { /* do nothing by default */ } + + /*! Returns the geo init id */ + inline void setGeoInitId(int set) { mGeoInitId=set; } + /*! Returns the geo init id */ + inline int getGeoInitId() const { return mGeoInitId; } + + protected: + + /*! Object visible on/off */ + int mVisible; + + /*! Name of this object */ + string mName; + + /*! global scene object id */ + int mObjectId; + + /*! configuration attributes */ + AttributeList *mpAttrs; + /*! sws configuration attributes */ + AttributeList *mpSwsAttrs; + + /* fluid init data */ + /*! id of fluid init (is used in solver initialization), additional data stored only for objects */ + int mGeoInitId; + + private: + +}; + + + +#endif + diff --git a/intern/elbeem/intern/ntl_geometrymodel.cpp b/intern/elbeem/intern/ntl_geometrymodel.cpp new file mode 100644 index 00000000000..0d769cf6ef8 --- /dev/null +++ b/intern/elbeem/intern/ntl_geometrymodel.cpp @@ -0,0 +1,478 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * A simple box object + * + *****************************************************************************/ + +#include "ntl_geometrymodel.h" +#include "ntl_ray.h" +#include "ntl_world.h" +#include "zlib.h" + +#ifdef WIN32 +#ifndef strncasecmp +#define strncasecmp(a,b,c) strcmp(a,b) +#endif +#endif // WIN32 + + +/****************************************************************************** + * Default Constructor + *****************************************************************************/ +ntlGeometryObjModel::ntlGeometryObjModel( void ) : + ntlGeometryObject(), + mvStart( 0.0 ), mvEnd( 1.0 ), + mLoaded( false ), + mTriangles(), mVertices(), mNormals(), + mcAniVerts(), mcAniNorms(), + mcAniTimes(), mAniTimeScale(1.), mAniTimeOffset(0.) +{ +} + +/****************************************************************************** + * Destructor + *****************************************************************************/ +ntlGeometryObjModel::~ntlGeometryObjModel() +{ + if(!mLoaded) { + errMsg("ntlGeometryObjModel","delete obj..."); + } +} + + +/*! is the mesh animated? */ +bool ntlGeometryObjModel::getMeshAnimated() { + const bool ret = (mcAniVerts.getSize()>1); + //errMsg("getMeshAnimated","ret="< (*sverts)[i][j]) { start[j]= (*sverts)[i][j]; } + if(end[j] < (*sverts)[i][j]) { end[j] = (*sverts)[i][j]; } + } + //errMsg("getExtends","check "<getMaterials() ); + return; + } + + ntlGeometryObject::initialize(glob); + mFilename = mpAttrs->readString("filename", mFilename,"ntlGeometryObjModel", "mFilename", true); + + if(mFilename == "") { + errMsg("ntlGeometryObjModel::initialize","Filename not given!"); + return; + } + + const char *suffix = strrchr(mFilename.c_str(), '.'); + if (suffix) { + if (!strncasecmp(suffix, ".obj", 4)) { + errMsg("ntlGeometryObjModel::initialize",".obj files not supported!"); + return; + } else if (!strncasecmp(suffix, ".gz", 3)) { + //mType = 1; // assume its .bobj.gz + } else if (!strncasecmp(suffix, ".bobj", 5)) { + //mType = 1; + } + } + + if(getAttributeList()->exists("ani_times") || (!mcAniTimes.isInited()) ) { + mcAniTimes = mpAttrs->readChannelFloat("ani_times"); + } + mAniTimeScale = mpAttrs->readFloat("ani_timescale", mAniTimeScale,"ntlGeometryObjModel", "mAniTimeScale", false); + mAniTimeOffset = mpAttrs->readFloat("ani_timeoffset", mAniTimeOffset,"ntlGeometryObjModel", "mAniTimeOffset", false); + + // continue with standard obj + if(loadBobjModel(mFilename)==0) mLoaded=1; + if(!mLoaded) { + debMsgStd("ntlGeometryObjModel",DM_WARNING,"Unable to load object file '"<mIsAnimated = true; + } +} + +/****************************************************************************** + * init model from given vertex and triangle arrays + *****************************************************************************/ + +int ntlGeometryObjModel::initModel(int numVertices, float *vertices, int numTriangles, int *triangles, + int channelSize, float *channelVertices) +{ + mVertices.clear(); + mVertices.resize( numVertices ); + mNormals.resize( numVertices ); + for(int i=0; i=numVertices) { mTriangles[3*i+j]=0; triangleErrs++; } + } + } + if(triangleErrs>0) { + errMsg("ntlGeometryObjModel::initModel","Triangle errors occurred ("<0)) { + vector aniverts; + vector aninorms; + vector anitimes; + aniverts.clear(); + aninorms.clear(); + anitimes.clear(); + for(int frame=0; framemIsAnimated = true; + } + + // inited, no need to parse attribs etc. + mLoaded = 1; + return 0; +} + +/*! init triangle divisions */ +void ntlGeometryObjModel::calcTriangleDivs(vector &verts, vector &tris, gfxReal fsTri) { + // warning - copied from geomobj calc! + errMsg("ntlGeometryObjModel","calcTriangleDivs special!"); + mTriangleDivs1.resize( tris.size() ); + mTriangleDivs2.resize( tris.size() ); + mTriangleDivs3.resize( tris.size() ); + for(size_t i=0; i fsTri*fsTri) { divs1 = (int)(norm(side1)/fsTri); } + if(normNoSqrt(side2) > fsTri*fsTri) { divs2 = (int)(norm(side2)/fsTri); } + //if(normNoSqrt(side3) > fsTri*fsTri) { divs3 = (int)(norm(side3)/fsTri); } + + // special handling + // warning, requires objmodel triangle treatment (no verts dups) + if(getMeshAnimated()) { + vector &sverts = mcAniVerts.accessValues(); + for(int s=0; s<(int)sverts.size(); s++) { + p0 = sverts[s].mVerts[ tris[i].getPoints()[0] ]; + p1 = sverts[s].mVerts[ tris[i].getPoints()[1] ]; + p2 = sverts[s].mVerts[ tris[i].getPoints()[2] ]; + side1 = p1 - p0; side2 = p2 - p0; side3 = p1 - p2; + int tdivs1=0, tdivs2=0, tdivs3=0; + if(normNoSqrt(side1) > fsTri*fsTri) { tdivs1 = (int)(norm(side1)/fsTri); } + if(normNoSqrt(side2) > fsTri*fsTri) { tdivs2 = (int)(norm(side2)/fsTri); } + if(tdivs1>divs1) divs1=tdivs1; + if(tdivs2>divs2) divs2=tdivs2; + if(tdivs3>divs3) divs3=tdivs3; + } + } // */ + mTriangleDivs1[i] = divs1; + mTriangleDivs2[i] = divs2; + mTriangleDivs3[i] = divs3; + } +} + + +/****************************************************************************** + * load model from .obj file + *****************************************************************************/ + +int ntlGeometryObjModel::loadBobjModel(string filename) +{ + bool haveAniSets=false; + vector aniverts; + vector aninorms; + vector anitimes; + + const bool debugPrint=false; + const bool debugPrintFull=false; + gzFile gzf; + gzf = gzopen(filename.c_str(), "rb"); + if (!gzf) { + errFatal("ntlGeometryObjModel::loadBobjModel","Reading GZ_BOBJ, Unable to open '"<< filename <<"'...\n", SIMWORLD_INITERROR ); + return 1; + } + + int numVerts; + if(sizeof(numVerts)!=4) { // paranoia check + errMsg("Reading GZ_BOBJ"," Invalid int size, check compiler settings: int has to be 4 byte long"); + goto gzreaderror; + } + gzread(gzf, &numVerts, sizeof(numVerts) ); + if(numVerts<0 || numVerts>1e9) { + errMsg("Reading GZ_BOBJ"," invalid num vertices "<< numVerts); + goto gzreaderror; + } + mVertices.clear(); + mVertices.resize( numVerts ); + for(int i=0; i1e9) { + errMsg("Reading GZ_BOBJ","invalid num normals "<< numVerts); + goto gzreaderror; + } + mNormals.clear(); + mNormals.resize( numVerts ); + for(int i=0; i1e9) { + errMsg("Reading GZ_BOBJ","invalid num normals "<< numTris); + goto gzreaderror; + } + mTriangles.resize( 3*numTris ); + for(int i=0; i0) { + // finally init channels and stop reading file + mcAniVerts = AnimChannel(aniverts,anitimes); + mcAniNorms = AnimChannel(aninorms,anitimes); + } + goto gzreaddone; + } + bytesRead += gzread(gzf, &numVerts2, sizeof(numVerts2) ); + haveAniSets=true; + // continue to read new set + vector vertset; + vector normset; + vertset.resize(numVerts); + normset.resize(numVerts); + //vertset[0] = check; + if(debugPrintFull) errMsg("FUL1V"," "<<0<<" "<< vertset[0] ); + + for(int i=0; i1) anitime = mcAniTimes.get(anitime); + anitime = anitime*mAniTimeScale+mAniTimeOffset; + + anitimes.push_back( anitime ); + aniverts.push_back( ntlSetVec3f(mVertices) ); + aninorms.push_back( ntlSetVec3f(mNormals) ); + if(debugPrint) errMsg("ANI_NV","new set "<1) anitime = mcAniTimes.get(anitime); + anitime = anitime*mAniTimeScale+mAniTimeOffset; + + anitimes.push_back( anitime ); + aniverts.push_back( ntlSetVec3f(vertset) ); + aninorms.push_back( ntlSetVec3f(normset) ); + if(debugPrint) errMsg("ANI_NV","new set "< *triangles, + vector *vertices, + vector *normals, int objectId ) +{ + if(!mLoaded) { // invalid type... + return; + } + if(mcAniVerts.getSize()>1) { mVertices = mcAniVerts.get(t).mVerts; } + if(mcAniNorms.getSize()>1) { mNormals = mcAniNorms.get(t).mVerts; } + + int startvert = vertices->size(); + vertices->resize( vertices->size() + mVertices.size() ); + normals->resize( normals->size() + mVertices.size() ); + for(int i=0; i<(int)mVertices.size(); i++) { + (*vertices)[startvert+i] = mVertices[i]; + (*normals)[startvert+i] = mNormals[i]; + } + + triangles->reserve(triangles->size() + mTriangles.size()/3 ); + for(int i=0; i<(int)mTriangles.size(); i+=3) { + int trip[3]; + trip[0] = startvert+mTriangles[i+0]; + trip[1] = startvert+mTriangles[i+1]; + trip[2] = startvert+mTriangles[i+2]; + + //sceneAddTriangle( + //mVertices[trip[0]], mVertices[trip[1]], mVertices[trip[2]], + //mNormals[trip[0]], mNormals[trip[1]], mNormals[trip[2]], + //ntlVec3Gfx(0.0), 1 , triangles,vertices,normals ); /* normal unused */ + sceneAddTriangleNoVert( trip, ntlVec3Gfx(0.0), 1 , triangles ); /* normal unused */ + } + objectId = -1; // remove warning + // bobj + return; +} + + + + + diff --git a/intern/elbeem/intern/ntl_geometrymodel.h b/intern/elbeem/intern/ntl_geometrymodel.h new file mode 100644 index 00000000000..572440f28dc --- /dev/null +++ b/intern/elbeem/intern/ntl_geometrymodel.h @@ -0,0 +1,92 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * A model laoded from Wavefront .obj file + * + *****************************************************************************/ +#ifndef NTL_GEOMODEL_H +#define NTL_GEOMODEL_H + +#include "ntl_geometryobject.h" + +/*! A simple box object generatedd by 12 triangles */ +class ntlGeometryObjModel : public ntlGeometryObject +{ + public: + /* Init constructor */ + ntlGeometryObjModel( void ); + /* Init constructor */ + //ntlGeometryObjModel( ntlVec3Gfx start, ntlVec3Gfx end ); + /* Destructor */ + virtual ~ntlGeometryObjModel( void ); + + //! Return type id + virtual int getTypeId() { return GEOCLASSTID_OBJMODEL; } + + /*! Filename setting etc. */ + virtual void initialize(ntlRenderGlobals *glob); + + /*! is the mesh animated? */ + virtual bool getMeshAnimated(); + + /* create triangles from obj */ + virtual void getTriangles(double t, vector *triangles, + vector *vertices, + vector *normals, int objectId ); + + /*! load model from .bobj file, returns !=0 upon error */ + int loadBobjModel(string filename); + /*! init model from given vertex and triangle arrays */ + int initModel(int numVertices, float *vertices, int numTriangles, int *triangles, + int channelSize, float *channelVertices); + /*! init triangle divisions */ + virtual void calcTriangleDivs(vector &verts, vector &tris, gfxReal fsTri); + + /*! calculate max extends of (ani) mesh */ + void getExtends(ntlVec3Gfx &start, ntlVec3Gfx &end); + + private: + + /*! Start and end points of box */ + ntlVec3Gfx mvStart, mvEnd; + + /*! was the model loaded? */ + bool mLoaded; + + /*! filename of the obj file */ + string mFilename; + + /*! for bobj models */ + vector mTriangles; + vector mVertices; + vector mNormals; + + /*! animated channels for vertices, if given will override getris by default */ + AnimChannel mcAniVerts; + AnimChannel mcAniNorms; + /*! map entrie of anim mesh to sim times */ + AnimChannel mcAniTimes; + /*! timing mapping & offset for config files */ + double mAniTimeScale, mAniTimeOffset; + + public: + + /* Access methods */ + /*! Access start vector */ + inline ntlVec3Gfx getStart( void ){ return mvStart; } + inline void setStart( const ntlVec3Gfx &set ){ mvStart = set; } + /*! Access end vector */ + inline ntlVec3Gfx getEnd( void ){ return mvEnd; } + inline void setEnd( const ntlVec3Gfx &set ){ mvEnd = set; } + + inline bool getLoaded( void ){ return mLoaded; } + inline void setLoaded( bool set ){ mLoaded = set; } + + /*! set data file name */ + inline void setFilename(string set) { mFilename = set; } +}; + +#endif + diff --git a/intern/elbeem/intern/ntl_geometryobject.cpp b/intern/elbeem/intern/ntl_geometryobject.cpp new file mode 100644 index 00000000000..f2ebd572682 --- /dev/null +++ b/intern/elbeem/intern/ntl_geometryobject.cpp @@ -0,0 +1,792 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * a geometry object + * all other geometry objects are derived from this one + * + *****************************************************************************/ + + +#include "ntl_geometryobject.h" +#include "ntl_world.h" +#include "ntl_matrices.h" + +// for FGI +#include "elbeem.h" + +#define TRI_UVOFFSET (1./4.) +//#define TRI_UVOFFSET (1./3.) + + +/*****************************************************************************/ +/* Default constructor */ +/*****************************************************************************/ +ntlGeometryObject::ntlGeometryObject() : + mIsInitialized(false), mpMaterial( NULL ), + mMaterialName( "default" ), + mCastShadows( 1 ), mReceiveShadows( 1 ), + mGeoInitType( 0 ), + mInitialVelocity(0.0), mcInitialVelocity(0.0), mLocalCoordInivel(false), + mGeoInitIntersect(false), + mGeoPartSlipValue(0.0), + mcGeoImpactFactor(1.), + mVolumeInit(VOLUMEINIT_VOLUME), + mInitialPos(0.), + mcTrans(0.), mcRot(0.), mcScale(1.), + mIsAnimated(false), + mMovPoints(), mMovNormals(), + mHaveCachedMov(false), + mCachedMovPoints(), mCachedMovNormals(), + mTriangleDivs1(), mTriangleDivs2(), mTriangleDivs3(), + mMovPntsInited(-100.0), mMaxMovPnt(-1), + mcGeoActive(1.) +{ +}; + + +/*****************************************************************************/ +/* Default destructor */ +/*****************************************************************************/ +ntlGeometryObject::~ntlGeometryObject() +{ +} + +/*! is the mesh animated? */ +bool ntlGeometryObject::getMeshAnimated() { + // off by default, on for e.g. ntlGeometryObjModel + return false; +} + +/*! init object anim flag */ +bool ntlGeometryObject::checkIsAnimated() { + if( (mcTrans.accessValues().size()>1) // VALIDATE + || (mcRot.accessValues().size()>1) + || (mcScale.accessValues().size()>1) + || (mcGeoActive.accessValues().size()>1) + // mcGeoImpactFactor only needed when moving + || (mcInitialVelocity.accessValues().size()>1) + ) { + mIsAnimated = true; + } + + // fluid objects always have static init! + if(mGeoInitType==FGI_FLUID) { + mIsAnimated=false; + } + //errMsg("ntlGeometryObject::checkIsAnimated","obj="<getMaterials() ); + + this->mGeoInitId = mpAttrs->readInt("geoinitid", this->mGeoInitId,"ntlGeometryObject", "mGeoInitId", false); + mGeoInitIntersect = mpAttrs->readInt("geoinit_intersect", mGeoInitIntersect,"ntlGeometryObject", "mGeoInitIntersect", false); + string ginitStr = mpAttrs->readString("geoinittype", "", "ntlGeometryObject", "mGeoInitType", false); + if(this->mGeoInitId>=0) { + bool gotit = false; + for(int i=0; ireadInt("geoinitactive", 1,"ntlGeometryObject", "geoActive", false); + if(!geoActive) { + // disable geo init again... + this->mGeoInitId = -1; + } + mInitialVelocity = vec2G( mpAttrs->readVec3d("initial_velocity", vec2D(mInitialVelocity),"ntlGeometryObject", "mInitialVelocity", false)); + if(getAttributeList()->exists("initial_velocity") || (!mcInitialVelocity.isInited()) ) { + mcInitialVelocity = mpAttrs->readChannelVec3f("initial_velocity"); + } + // always use channel + if(!mcInitialVelocity.isInited()) { mcInitialVelocity = AnimChannel(mInitialVelocity); } + mLocalCoordInivel = mpAttrs->readBool("geoinit_localinivel", mLocalCoordInivel,"ntlGeometryObject", "mLocalCoordInivel", false); + + mGeoPartSlipValue = mpAttrs->readFloat("geoinit_partslip", mGeoPartSlipValue,"ntlGeometryObject", "mGeoPartSlipValue", false); + bool mOnlyThinInit = false; // deprecated! + mOnlyThinInit = mpAttrs->readBool("geoinit_onlythin", mOnlyThinInit,"ntlGeometryObject", "mOnlyThinInit", false); + if(mOnlyThinInit) mVolumeInit = VOLUMEINIT_SHELL; + mVolumeInit = mpAttrs->readInt("geoinit_volumeinit", mVolumeInit,"ntlGeometryObject", "mVolumeInit", false); + if((mVolumeInitVOLUMEINIT_BOTH)) mVolumeInit = VOLUMEINIT_VOLUME; + + // moving obs correction factor + float impactfactor=1.; + impactfactor = (float)mpAttrs->readFloat("impactfactor", impactfactor,"ntlGeometryObject", "impactfactor", false); + if(getAttributeList()->exists("impactfactor") || (!mcGeoImpactFactor.isInited()) ) { + mcGeoImpactFactor = mpAttrs->readChannelSinglePrecFloat("impactfactor"); + } + + // override cfg types + mVisible = mpAttrs->readBool("visible", mVisible,"ntlGeometryObject", "mVisible", false); + mReceiveShadows = mpAttrs->readBool("recv_shad", mReceiveShadows,"ntlGeometryObject", "mReceiveShadows", false); + mCastShadows = mpAttrs->readBool("cast_shad", mCastShadows,"ntlGeometryObject", "mCastShadows", false); + + // read mesh animation channels + ntlVec3d translation(0.0); + translation = mpAttrs->readVec3d("translation", translation,"ntlGeometryObject", "translation", false); + if(getAttributeList()->exists("translation") || (!mcTrans.isInited()) ) { + mcTrans = mpAttrs->readChannelVec3f("translation"); + } + ntlVec3d rotation(0.0); + rotation = mpAttrs->readVec3d("rotation", rotation,"ntlGeometryObject", "rotation", false); + if(getAttributeList()->exists("rotation") || (!mcRot.isInited()) ) { + mcRot = mpAttrs->readChannelVec3f("rotation"); + } + ntlVec3d scale(1.0); + scale = mpAttrs->readVec3d("scale", scale,"ntlGeometryObject", "scale", false); + if(getAttributeList()->exists("scale") || (!mcScale.isInited()) ) { + mcScale = mpAttrs->readChannelVec3f("scale"); + } + + float geoactive=1.; + geoactive = (float)mpAttrs->readFloat("geoactive", geoactive,"ntlGeometryObject", "geoactive", false); + if(getAttributeList()->exists("geoactive") || (!mcGeoActive.isInited()) ) { + mcGeoActive = mpAttrs->readChannelSinglePrecFloat("geoactive"); + } + // always use channel + if(!mcGeoActive.isInited()) { mcGeoActive = AnimChannel(geoactive); } + + checkIsAnimated(); + + mIsInitialized = true; + debMsgStd("ntlGeometryObject::initialize",DM_MSG,"GeoObj '"<getName()<<"': visible="<mVisible<<" gid="<mGeoInitId<<" gtype="<getName()<<" frame:"< *mat) +{ + /* search the list... */ + int i=0; + for (vector::iterator iter = mat->begin(); + iter != mat->end(); iter++) { + if( mMaterialName == (*iter)->getName() ) { + //warnMsg("ntlGeometryObject::searchMaterial","for obj '"<getName()<<"' "< *triangles, + vector *vertices, + vector *normals) { + ntlTriangle tri; + int tempVert; + + if(normals->size() != vertices->size()) { + errFatal("ntlGeometryObject::sceneAddTriangle","For '"<mName<<"': Vertices and normals sizes to not match!!!",SIMWORLD_GENERICERROR); + + } else { + + vertices->push_back( p1 ); + normals->push_back( pn1 ); + tempVert = normals->size()-1; + tri.getPoints()[0] = tempVert; + + vertices->push_back( p2 ); + normals->push_back( pn2 ); + tempVert = normals->size()-1; + tri.getPoints()[1] = tempVert; + + vertices->push_back( p3 ); + normals->push_back( pn3 ); + tempVert = normals->size()-1; + tri.getPoints()[2] = tempVert; + + + /* init flags from ntl_ray.h */ + int flag = 0; + if(getVisible()){ flag |= TRI_GEOMETRY; } + if(getCastShadows() ) { + flag |= TRI_CASTSHADOWS; } + + /* init geo init id */ + int geoiId = getGeoInitId(); + //if((geoiId > 0) && (mVolumeInit&VOLUMEINIT_VOLUME) && (!mIsAnimated)) { + if((geoiId > 0) && (mVolumeInit&VOLUMEINIT_VOLUME)) { + flag |= (1<< (geoiId+4)); + flag |= mGeoInitType; + } + /*errMsg("ntlScene::addTriangle","DEBUG flag="<mObjectId ); + triangles->push_back( tri ); + } /* normals check*/ +} + +void ntlGeometryObject::sceneAddTriangleNoVert(int *trips, + ntlVec3Gfx trin, bool smooth, + vector *triangles) { + ntlTriangle tri; + + tri.getPoints()[0] = trips[0]; + tri.getPoints()[1] = trips[1]; + tri.getPoints()[2] = trips[2]; + + // same as normal sceneAddTriangle + + /* init flags from ntl_ray.h */ + int flag = 0; + if(getVisible()){ flag |= TRI_GEOMETRY; } + if(getCastShadows() ) { + flag |= TRI_CASTSHADOWS; } + + /* init geo init id */ + int geoiId = getGeoInitId(); + if((geoiId > 0) && (mVolumeInit&VOLUMEINIT_VOLUME)) { + flag |= (1<< (geoiId+4)); + flag |= mGeoInitType; + } + /*errMsg("ntlScene::addTriangle","DEBUG flag="<mObjectId ); + triangles->push_back( tri ); +} + + +/******************************************************************************/ +/* Init channels from float arrays (for elbeem API) */ +/******************************************************************************/ + +#define ADD_CHANNEL_VEC(dst,nvals,val) \ + vals.clear(); time.clear(); elbeemSimplifyChannelVec3(val,&nvals); \ + for(int i=0; i<(nvals); i++) { \ + vals.push_back(ntlVec3Gfx((val)[i*4+0], (val)[i*4+1],(val)[i*4+2] )); \ + time.push_back( (val)[i*4+3] ); \ + } \ + (dst) = AnimChannel< ntlVec3Gfx >(vals,time); + +#define ADD_CHANNEL_FLOAT(dst,nvals,val) \ + valsfloat.clear(); time.clear(); elbeemSimplifyChannelFloat(val,&nvals); \ + for(int i=0; i<(nvals); i++) { \ + valsfloat.push_back( (val)[i*2+0] ); \ + time.push_back( (val)[i*2+1] ); \ + } \ + (dst) = AnimChannel< float >(valsfloat,time); + +void ntlGeometryObject::initChannels( + int nTrans, float *trans, int nRot, float *rot, int nScale, float *scale, + int nAct, float *act, int nIvel, float *ivel + ) { + const bool debugInitc=true; + if(debugInitc) { debMsgStd("ntlGeometryObject::initChannels",DM_MSG,"nt:"< vals; + vector valsfloat; + vector time; + if((trans)&&(nTrans>0)) { ADD_CHANNEL_VEC(mcTrans, nTrans, trans); } + if((rot)&&(nRot>0)) { ADD_CHANNEL_VEC(mcRot, nRot, rot); } + if((scale)&&(nScale>0)) { ADD_CHANNEL_VEC(mcScale, nScale, scale); } + if((act)&&(nAct>0)) { ADD_CHANNEL_FLOAT(mcGeoActive, nAct, act); } + if((ivel)&&(nIvel>0)) { ADD_CHANNEL_VEC(mcInitialVelocity, nIvel, ivel); } + + checkIsAnimated(); + if(debugInitc) { + debMsgStd("ntlGeometryObject::initChannels",DM_MSG,getName()<< + " nt:"< *verts, vector *norms, int vstart, int vend, int forceTrafo) { + if( (mcTrans.accessValues().size()>1) // VALIDATE + || (mcRot.accessValues().size()>1) + || (mcScale.accessValues().size()>1) + || (forceTrafo) + || (!mHaveCachedMov) + ) { + // transformation is animated, continue + ntlVec3Gfx pos = getTranslation(t); + ntlVec3Gfx scale = mcScale.get(t); + ntlVec3Gfx rot = mcRot.get(t); + ntlMat4Gfx rotMat; + rotMat.initRotationXYZ(rot[0],rot[1],rot[2]); + pos += mInitialPos; + errMsg("ntlGeometryObject::applyTransformation","obj="< &verts, vector &tris, gfxReal fsTri) { + mTriangleDivs1.resize( tris.size() ); + mTriangleDivs2.resize( tris.size() ); + mTriangleDivs3.resize( tris.size() ); + + //fsTri *= 2.; // DEBUG! , wrong init! + + for(size_t i=0; i fsTri*fsTri) { divs1 = (int)(norm(side1)/fsTri); } + if(normNoSqrt(side2) > fsTri*fsTri) { divs2 = (int)(norm(side2)/fsTri); } + + mTriangleDivs1[i] = divs1; + mTriangleDivs2[i] = divs2; + mTriangleDivs3[i] = divs3; + } +} + +/*! Prepare points for moving objects */ +void ntlGeometryObject::initMovingPoints(double time, gfxReal featureSize) { + if((mMovPntsInited==featureSize)&&(!getMeshAnimated())) return; + const bool debugMoinit=false; + + vector triangles; + vector vertices; + vector vnormals; + int objectId = 1; + this->getTriangles(time, &triangles,&vertices,&vnormals,objectId); + + mMovPoints.clear(); + mMovNormals.clear(); + if(debugMoinit) errMsg("ntlGeometryObject::initMovingPoints","Object "<maxpart) maxpart = ABS(maxscale[1]); + if(ABS(maxscale[2])>maxpart) maxpart = ABS(maxscale[2]); + float scaleFac = 1.0/(maxpart); + // TODO - better reinit from time to time? + const gfxReal fsTri = featureSize*0.5 *scaleFac; + if(debugMoinit) errMsg("ntlGeometryObject::initMovingPoints","maxscale:"< fsTri*fsTri) { divs1 = (int)(norm(side1)/fsTri); } + if(normNoSqrt(side2) > fsTri*fsTri) { divs2 = (int)(norm(side2)/fsTri); } + errMsg("ntlGeometryObject::initMovingPoints","tri:"< "< 0) { + for(int u=0; u<=divs1; u++) { + for(int v=0; v<=divs2; v++) { + const gfxReal uf = (gfxReal)(u+TRI_UVOFFSET) / (gfxReal)(divs1+0.0); + const gfxReal vf = (gfxReal)(v+TRI_UVOFFSET) / (gfxReal)(divs2+0.0); + if(uf+vf>1.0) continue; + countp+=2; + } + } + } + } + errMsg("ntlGeometryObject::initMovingPoints","Object "< 0) { + for(int u=0; u<=divs1; u++) { + for(int v=0; v<=divs2; v++) { + const gfxReal uf = (gfxReal)(u+TRI_UVOFFSET) / (gfxReal)(divs1+0.0); + const gfxReal vf = (gfxReal)(v+TRI_UVOFFSET) / (gfxReal)(divs2+0.0); + if(uf+vf>1.0) continue; + ntlVec3Gfx p = + vertices[ trips[0] ] * (1.0-uf-vf)+ + vertices[ trips[1] ] * uf + + vertices[ trips[2] ] * vf; + //ntlVec3Gfx n = vnormals[ + //trips[0] ] * (1.0-uf-vf)+ + //vnormals[ trips[1] ]*uf + + //vnormals[ trips[2] ]*vf; + //normalize(n); + // discard inflow backsides + + mMovPoints.push_back(p + trinorm); // NEW!? + mMovPoints.push_back(p - trinorm); + mMovNormals.push_back(trinormOrg); + mMovNormals.push_back(trinormOrg); + //errMsg("TRINORM","p"<dist) { + mMaxMovPnt = i; + dist = normNoSqrt(mMovPoints[0]); + } + } + + if( (this-getMeshAnimated()) + || (mcTrans.accessValues().size()>1) // VALIDATE + || (mcRot.accessValues().size()>1) + || (mcScale.accessValues().size()>1) + ) { + // also do trafo... + } else { + mCachedMovPoints = mMovPoints; + mCachedMovNormals = mMovNormals; + //applyTransformation(time, &mCachedMovPoints, &mCachedMovNormals, 0, mCachedMovPoints.size(), true); + applyTransformation(time, &mCachedMovPoints, NULL, 0, mCachedMovPoints.size(), true); + mHaveCachedMov = true; + debMsgStd("ntlGeometryObject::initMovingPoints",DM_MSG,"Object "<"< &srcmovPoints, + double dsttime, vector &dstmovPoints, + vector *dstmovNormals, + gfxReal featureSize, + ntlVec3Gfx geostart, ntlVec3Gfx geoend + ) { + const bool debugMoinit=false; + + vector srctriangles; + vector srcvertices; + vector unused_normals; + vector dsttriangles; + vector dstvertices; + vector dstnormals; + int objectId = 1; + // TODO optimize? , get rid of normals? + unused_normals.clear(); + this->getTriangles(srctime, &srctriangles,&srcvertices,&unused_normals,objectId); + unused_normals.clear(); + this->getTriangles(dsttime, &dsttriangles,&dstvertices,&dstnormals,objectId); + + srcmovPoints.clear(); + dstmovPoints.clear(); + if(debugMoinit) errMsg("ntlGeometryObject::initMovingPointsAnim","Object "<maxpart) maxpart = ABS(maxscale[1]); + if(ABS(maxscale[2])>maxpart) maxpart = ABS(maxscale[2]); + float scaleFac = 1.0/(maxpart); + // TODO - better reinit from time to time? + const gfxReal fsTri = featureSize*0.5 *scaleFac; + if(debugMoinit) errMsg("ntlGeometryObject::initMovingPointsAnim","maxscale:"< 0) { + int *srctrips = srctriangles[i].getPoints(); + int *dsttrips = dsttriangles[i].getPoints(); + const ntlVec3Gfx srcp0 = srcvertices[ srctrips[0] ]; + const ntlVec3Gfx srcside1 = srcvertices[ srctrips[1] ] - srcp0; + const ntlVec3Gfx srcside2 = srcvertices[ srctrips[2] ] - srcp0; + const ntlVec3Gfx dstp0 = dstvertices[ dsttrips[0] ]; + const ntlVec3Gfx dstside1 = dstvertices[ dsttrips[1] ] - dstp0; + const ntlVec3Gfx dstside2 = dstvertices[ dsttrips[2] ] - dstp0; + const ntlVec3Gfx src_trinorm = getNormalized(cross(srcside1,srcside2))*0.25*featureSize; + const ntlVec3Gfx dst_trinormOrg = getNormalized(cross(dstside1,dstside2)); + const ntlVec3Gfx dst_trinorm = dst_trinormOrg *0.25*featureSize; + //errMsg("ntlGeometryObject::initMovingPointsAnim","Tri1 "<1.0) continue; + ntlVec3Gfx srcp = + srcvertices[ srctrips[0] ] * (1.0-uf-vf)+ + srcvertices[ srctrips[1] ] * uf + + srcvertices[ srctrips[2] ] * vf; + ntlVec3Gfx dstp = + dstvertices[ dsttrips[0] ] * (1.0-uf-vf)+ + dstvertices[ dsttrips[1] ] * uf + + dstvertices[ dsttrips[2] ] * vf; + + // cutoffDomain + if((srcp[0]geoend[0] ) && (dstp[0]>geoend[0] )) continue; + if((srcp[1]>geoend[1] ) && (dstp[1]>geoend[1] )) continue; + if((srcp[2]>geoend[2] ) && (dstp[2]>geoend[2] )) continue; + + srcmovPoints.push_back(srcp+src_trinorm); // SURFENHTEST + srcmovPoints.push_back(srcp-src_trinorm); + + dstmovPoints.push_back(dstp+dst_trinorm); // SURFENHTEST + dstmovPoints.push_back(dstp-dst_trinorm); + if(dstmovNormals) { + (*dstmovNormals).push_back(dst_trinormOrg); + (*dstmovNormals).push_back(dst_trinormOrg); } + } + } + } + } + + // find max point not necessary + debMsgStd("ntlGeometryObject::initMovingPointsAnim",DM_MSG,"Object "<"< &ret, vector *norms) { + if(mHaveCachedMov) { + ret = mCachedMovPoints; + if(norms) { + *norms = mCachedMovNormals; + //errMsg("ntlGeometryObject","getMovingPoints - Normals currently unused!"); + } + //errMsg ("ntlGeometryObject::getMovingPoints","Object "< verts1,verts2; + verts1.push_back(mMovPoints[mMaxMovPnt]); + verts2 = verts1; + applyTransformation(t1,&verts1,NULL, 0,verts1.size(), true); + applyTransformation(t2,&verts2,NULL, 0,verts2.size(), true); + + vel = (verts2[0]-verts1[0]); // /(t2-t1); + //errMsg("ntlGeometryObject::calculateMaxVel","t1="< off + return act; +} + +void ntlGeometryObject::setInitialVelocity(ntlVec3Gfx set) { + mInitialVelocity=set; + mcInitialVelocity = AnimChannel(set); +} +ntlVec3Gfx ntlGeometryObject::getInitialVelocity(double t) { + ntlVec3Gfx v = mcInitialVelocity.get(t); //return mInitialVelocity; + if(!mLocalCoordInivel) return v; + + ntlVec3Gfx rot = mcRot.get(t); + ntlMat4Gfx rotMat; + rotMat.initRotationXYZ(rot[0],rot[1],rot[2]); + v = rotMat * v; + return v; +} + + diff --git a/intern/elbeem/intern/ntl_geometryobject.h b/intern/elbeem/intern/ntl_geometryobject.h new file mode 100644 index 00000000000..a5afd6b2207 --- /dev/null +++ b/intern/elbeem/intern/ntl_geometryobject.h @@ -0,0 +1,211 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * a geometry object + * all other geometry objects are derived from this one + * + *****************************************************************************/ +#ifndef NTL_GEOMETRYOBJECT_H +#define NTL_GEOMETRYOBJECT_H + +#include "ntl_geometryclass.h" +#include "ntl_lighting.h" +#include "ntl_ray.h" +class ntlRenderGlobals; +class ntlTriangle; + +#define DUMP_FULLGEOMETRY 1 +#define DUMP_PARTIAL 2 + +#define VOLUMEINIT_VOLUME 1 +#define VOLUMEINIT_SHELL 2 +#define VOLUMEINIT_BOTH (VOLUMEINIT_SHELL|VOLUMEINIT_VOLUME) + +class ntlGeometryObject : public ntlGeometryClass +{ + + public: + //! Default constructor + ntlGeometryObject(); + //! Default destructor + virtual ~ntlGeometryObject(); + + //! Return type id + virtual int getTypeId() { return GEOCLASSTID_OBJECT; } + + /*! Init attributes etc. of this object */ + virtual void initialize(ntlRenderGlobals *glob); + + /*! Get the triangles from this object */ + virtual void getTriangles(double t, vector *triangles, + vector *vertices, + vector *normals, int objectId ) = 0; + + /*! notify object that dump is in progress (e.g. for particles) */ + virtual void notifyOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename, double simtime); + + /*! Search the material for this object from the material list */ + void searchMaterial(vector *mat); + + /* Acces methods */ + /*! Set the property of this object */ + inline void setMaterial(ntlMaterial *p) { mpMaterial = p; } + /*! Get the surface property of this object */ + inline ntlMaterial *getMaterial( void ) { return mpMaterial; } + /*! Set the object property name */ + inline void setMaterialName(string set) { mMaterialName = set; } + /*! Get the object property name */ + inline string getMaterialName( void ) { return mMaterialName; } + + /*! Sets the receive shadows attribute */ + inline void setReceiveShadows(int set) { mReceiveShadows=set; } + /*! Returns the receive shadows attribute */ + inline int getReceiveShadows() const { return mReceiveShadows; } + + /*! Sets the cast shadows attribute */ + inline void setCastShadows(int set) { mCastShadows=set; } + /*! Returns the cast shadows attribute */ + inline int getCastShadows() const { return mCastShadows; } + + /*! Returns the geo init typ */ + inline void setGeoInitType(int set) { mGeoInitType=set; } + /*! Returns the geo init typ */ + inline int getGeoInitType() const { return mGeoInitType; } + + /*! Set/get the intersect init flag */ + inline bool getGeoInitIntersect() const { return mGeoInitIntersect; } + inline void setGeoInitIntersect(bool set) { mGeoInitIntersect=set; } + + /*! Set/get the part slip value*/ + inline float getGeoPartSlipValue() const { return mGeoPartSlipValue; } + inline void setGeoPartSlipValue(float set) { mGeoPartSlipValue=set; } + + /*! Set/get the impact corr factor channel */ + inline float getGeoImpactFactor(double t) { return mcGeoImpactFactor.get(t); } + inline void setGeoImpactFactor(float set) { mcGeoImpactFactor = AnimChannel(set); } + + /*! Set/get the part slip value*/ + inline int getVolumeInit() const { return mVolumeInit; } + inline void setVolumeInit(int set) { mVolumeInit=set; } + + /*! Set/get the cast initial veocity attribute */ + void setInitialVelocity(ntlVec3Gfx set); + ntlVec3Gfx getInitialVelocity(double t); + + /*! Set/get the local inivel coords flag */ + inline bool getLocalCoordInivel() const { return mLocalCoordInivel; } + inline void setLocalCoordInivel(bool set) { mLocalCoordInivel=set; } + + /*! Init channels from float arrays (for elbeem API) */ + void initChannels( + int nTrans, float *trans, int nRot, float *rot, int nScale, float *scale, + int nAct, float *act, int nIvel, float *ivel + ); + + /*! is the object animated? */ + inline bool getIsAnimated() const { return mIsAnimated; } + /*! init object anim flag */ + bool checkIsAnimated(); + /*! is the mesh animated? */ + virtual bool getMeshAnimated(); + /*! init triangle divisions */ + virtual void calcTriangleDivs(vector &verts, vector &tris, gfxReal fsTri); + + /*! apply object translation at time t*/ + void applyTransformation(double t, vector *verts, vector *norms, int vstart, int vend, int forceTrafo); + + /*! Prepare points for moving objects */ + void initMovingPoints(double time, gfxReal featureSize); + /*! Prepare points for animated objects */ + void initMovingPointsAnim( + double srctime, vector &srcpoints, + double dsttime, vector &dstpoints, + vector *dstnormals, + gfxReal featureSize, ntlVec3Gfx geostart, ntlVec3Gfx geoend ); + /*! Prepare points for moving objects (copy into ret) */ + void getMovingPoints(vector &ret, vector *norms = NULL); + /*! Calculate max. velocity on object from t1 to t2 */ + ntlVec3Gfx calculateMaxVel(double t1, double t2); + /*! get translation at time t*/ + ntlVec3Gfx getTranslation(double t); + /*! get active flag time t*/ + float getGeoActive(double t); + + /*! add triangle to scene and init flags */ + // helper function for getTriangles + void sceneAddTriangle( + ntlVec3Gfx p1,ntlVec3Gfx p2,ntlVec3Gfx p3, + ntlVec3Gfx pn1,ntlVec3Gfx pn2,ntlVec3Gfx pn3, + ntlVec3Gfx trin, bool smooth, + vector *triangles, + vector *vertices, + vector *vertNormals); + void sceneAddTriangleNoVert(int *trips, + ntlVec3Gfx trin, bool smooth, + vector *triangles); + + protected: + + /* initialized for scene? */ + bool mIsInitialized; + + /*! Point to a property object describing the surface of this object */ + ntlMaterial *mpMaterial; + + /*! Name of the surcace property */ + string mMaterialName; + + /*! Cast shadows on/off */ + int mCastShadows; + /*! REceive shadows on/off */ + int mReceiveShadows; + + /* fluid init data */ + /*! fluid object type (fluid, obstacle, accelerator etc.) */ + int mGeoInitType; + /*! initial velocity for fluid objects */ + ntlVec3Gfx mInitialVelocity; + AnimChannel mcInitialVelocity; + /*! use object local inflow? */ + bool mLocalCoordInivel; + /*! perform more accurate intersecting geo init for this object? */ + bool mGeoInitIntersect; + /*! part slip bc value */ + float mGeoPartSlipValue; + /*! obstacle impact correction factor */ + AnimChannel mcGeoImpactFactor; + /*! only init as thin object, dont fill? */ + int mVolumeInit; + + /*! initial offset for rot/scale */ + ntlVec3Gfx mInitialPos; + /*! animated channels for postition, rotation and scale */ + AnimChannel mcTrans, mcRot, mcScale; + /*! easy check for animation */ + bool mIsAnimated; + + /*! moving point/normal storage */ + vector mMovPoints; + vector mMovNormals; + /*! cached points for non moving objects/timeslots */ + bool mHaveCachedMov; + vector mCachedMovPoints; + vector mCachedMovNormals; + /*! precomputed triangle divisions */ + vector mTriangleDivs1,mTriangleDivs2,mTriangleDivs3; + /*! inited? */ + float mMovPntsInited; + /*! point with max. distance from center */ + int mMaxMovPnt; + + /*! animated channels for in/outflow on/off */ + AnimChannel mcGeoActive; + + public: + +}; + +#endif + diff --git a/intern/elbeem/intern/ntl_geometryshader.h b/intern/elbeem/intern/ntl_geometryshader.h new file mode 100644 index 00000000000..3ecb82e0556 --- /dev/null +++ b/intern/elbeem/intern/ntl_geometryshader.h @@ -0,0 +1,60 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Interface for a geometry shader + * + *****************************************************************************/ +#ifndef NTL_GEOMETRYSHADER_H +#define NTL_GEOMETRYSHADER_H + +#include "ntl_geometryclass.h" +class ntlGeometryObject; +class ntlRenderGlobals; + +class ntlGeometryShader : + public ntlGeometryClass +{ + + public: + + //! Default constructor + inline ntlGeometryShader() : + ntlGeometryClass(), mOutFilename("") + {}; + //! Default destructor + virtual ~ntlGeometryShader() {}; + + //! Return type id + virtual int getTypeId() { return GEOCLASSTID_SHADER; } + + /*! Initialize object, should return !=0 upon error */ + virtual int initializeShader() = 0; + + /*! Do further object initialization after all geometry has been constructed, should return !=0 upon error */ + virtual int postGeoConstrInit(ntlRenderGlobals *glob) { glob=NULL; /*unused*/ return 0; }; + + /*! Get start iterator for all objects */ + virtual vector::iterator getObjectsBegin() { return mObjects.begin(); } + /*! Get end iterator for all objects */ + virtual vector::iterator getObjectsEnd() { return mObjects.end(); } + + /*! notify object that dump is in progress (e.g. for field dump) */ + virtual void notifyShaderOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename) = 0; + + /*! get ouput filename, returns global render outfile if empty */ + string getOutFilename( void ) { return mOutFilename; } + + protected: + + //! vector for the objects + vector mObjects; + + + /*! surface output name for this simulation */ + string mOutFilename; +}; + +#endif + diff --git a/intern/elbeem/intern/ntl_lighting.cpp b/intern/elbeem/intern/ntl_lighting.cpp new file mode 100644 index 00000000000..b11c1fdd4ed --- /dev/null +++ b/intern/elbeem/intern/ntl_lighting.cpp @@ -0,0 +1,181 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * a light object + * + *****************************************************************************/ + + +#include "ntl_lighting.h" +#include "ntl_ray.h" +#include "ntl_world.h" + + +/****************************************************************************** + * Default Constructor + *****************************************************************************/ +ntlLightObject::ntlLightObject(ntlRenderGlobals *glob) : + mpGlob( glob ), + mActive( 1 ), + mCastShadows( 1 ), + mcColor( ntlColor(1.0) ), + mvPosition( ntlVec3Gfx(0.0) ) +{ + // nothing to do... +} + + +/****************************************************************************** + * Constructor with parameters + *****************************************************************************/ +ntlLightObject::ntlLightObject(ntlRenderGlobals *glob, const ntlColor& col) : + mpGlob( glob ), + mActive( 1 ), + mCastShadows( 1 ), + mcColor( col ) +{ + // nothing to do... +} + + + +/****************************************************************************** + * Destructor + *****************************************************************************/ +ntlLightObject::~ntlLightObject() +{ + // nothing to do... +} + + + +/****************************************************************************** + * Determine color contribution of a lightsource (Phong model) + * Specular part is returned in seperate parameter and added later + *****************************************************************************/ +const ntlColor +ntlLightObject::getShadedColor(const ntlRay &reflectedRay, const ntlVec3Gfx lightDir, + ntlMaterial *surf, ntlColor &highlight) const +{ + gfxReal ldot = dot(lightDir, reflectedRay.getNormal()); /* equals cos( angle(L,N) ) */ + ntlColor reflected_color = ntlColor(0.0); /* adds up to total reflected color */ + if(mpGlob->getDebugOut() > 5) errorOut("Lighting dir:"< 0.0) { + //ldot *= -1.0; + reflected_color += surf->getDiffuseRefl() * (getColor() * ldot ); + + /* specular part */ + /* specular reflection only makes sense, when the light is facing the surface, + as the highlight is supposed to be a reflection of the lightsource, it cannot + be reflected on surfaces with ldot<=0, as this means the arc between light + and normal is more than 90 degrees. If this isn't done, ugly moiree patterns appear + in the highlights, and refractions have strange patterns due to highlights on the + inside of the surface */ + gfxReal spec = dot(reflectedRay.getDirection(), lightDir); // equals cos( angle(R,L) ) + if((spec > 0.0) && (surf->getSpecular()>0)) { + spec = pow( spec, surf->getSpecExponent() ); /* phong exponent */ + highlight += getColor() * surf->getSpecular() * spec; + //errorOut( " "<< surf->getName() <<" S "<getSpecular()<<" "<getSpecExponent() ); + } + + } + + return ntlColor(reflected_color); +} + + +// omni light implementation + + +/****************************************************************************** + *! prepare shadow maps if necessary + *****************************************************************************/ +void ntlLightObject::prepare( bool doCaustics ) +{ + doCaustics = false; // unused + if(!mActive) { return; } +} + + +/****************************************************************************** + * Illuminate the given point on an object + *****************************************************************************/ +ntlColor ntlLightObject::illuminatePoint(ntlRay &reflectedRay, ntlGeometryObject *closest, + ntlColor &highlight ) +{ + /* is this light active? */ + if(!mActive) { return ntlColor(0.0); } + + gfxReal visibility = 1.0; // how much of light is visible + ntlVec3Gfx intersectionPos = reflectedRay.getOrigin(); + ntlColor current_color = ntlColor(0.0); + ntlMaterial *clossurf = closest->getMaterial(); + + ntlVec3Gfx lightDir = (mvPosition - intersectionPos); + gfxReal lightDirNorm = normalize(lightDir); + + // where is the lightsource ? + ntlRay rayOfLight(intersectionPos, lightDir, 0, 1.0, mpGlob ); + + if( (1) && (mCastShadows)&&(closest->getReceiveShadows()) ) { + ntlTriangle *tri; + ntlVec3Gfx triNormal; + gfxReal trit; + mpGlob->getRenderScene()->intersectScene(rayOfLight, trit, triNormal, tri, TRI_CASTSHADOWS); + if(( trit>0 )&&( tritgetDebugOut() > 5) errorOut("Omni lighting with "<0.0) { + ntlColor highTemp(0.0); // temporary highlight color to multiply highTemp with offFac + current_color = getShadedColor(reflectedRay, lightDir, clossurf, highTemp) * visibility; + highlight += highTemp * visibility; + if(mpGlob->getDebugOut() > 5) errorOut("Omni lighting color "< +class ntlMatrix4x4 +{ +public: + // Constructor + inline ntlMatrix4x4(void ); + // Copy-Constructor + inline ntlMatrix4x4(const ntlMatrix4x4 &v ); + // construct a vector from one Scalar + inline ntlMatrix4x4(Scalar); + // construct a vector from three Scalars + inline ntlMatrix4x4(Scalar, Scalar, Scalar); + + // Assignment operator + inline const ntlMatrix4x4& operator= (const ntlMatrix4x4& v); + // Assignment operator + inline const ntlMatrix4x4& operator= (Scalar s); + // Assign and add operator + inline const ntlMatrix4x4& operator+= (const ntlMatrix4x4& v); + // Assign and add operator + inline const ntlMatrix4x4& operator+= (Scalar s); + // Assign and sub operator + inline const ntlMatrix4x4& operator-= (const ntlMatrix4x4& v); + // Assign and sub operator + inline const ntlMatrix4x4& operator-= (Scalar s); + // Assign and mult operator + inline const ntlMatrix4x4& operator*= (const ntlMatrix4x4& v); + // Assign and mult operator + inline const ntlMatrix4x4& operator*= (Scalar s); + // Assign and div operator + inline const ntlMatrix4x4& operator/= (const ntlMatrix4x4& v); + // Assign and div operator + inline const ntlMatrix4x4& operator/= (Scalar s); + + + // unary operator + inline ntlMatrix4x4 operator- () const; + + // binary operator add + inline ntlMatrix4x4 operator+ (const ntlMatrix4x4&) const; + // binary operator add + inline ntlMatrix4x4 operator+ (Scalar) const; + // binary operator sub + inline ntlMatrix4x4 operator- (const ntlMatrix4x4&) const; + // binary operator sub + inline ntlMatrix4x4 operator- (Scalar) const; + // binary operator mult + inline ntlMatrix4x4 operator* (const ntlMatrix4x4&) const; + // binary operator mult + inline ntlVector3Dim operator* (const ntlVector3Dim&) const; + // binary operator mult + inline ntlMatrix4x4 operator* (Scalar) const; + // binary operator div + inline ntlMatrix4x4 operator/ (Scalar) const; + + // init function + //! init identity matrix + inline void initId(); + //! init rotation matrix + inline void initTranslation(Scalar x, Scalar y, Scalar z); + //! init rotation matrix + inline void initRotationX(Scalar rot); + inline void initRotationY(Scalar rot); + inline void initRotationZ(Scalar rot); + inline void initRotationXYZ(Scalar rotx,Scalar roty, Scalar rotz); + //! init scaling matrix + inline void initScaling(Scalar scale); + inline void initScaling(Scalar x, Scalar y, Scalar z); + //! from 16 value array (init id if all 0) + inline void initArrayCheck(Scalar *array); + + //! decompose matrix + void decompose(ntlVector3Dim &trans,ntlVector3Dim &scale,ntlVector3Dim &rot,ntlVector3Dim &shear); + + //! public to avoid [][] operators + Scalar value[4][4]; //< Storage of vector values + + +protected: + +}; + + + +//------------------------------------------------------------------------------ +// TYPEDEFS +//------------------------------------------------------------------------------ + +// a 3D vector for graphics output, typically float? +//typedef ntlMatrix4x4 ntlVec3Gfx; + +//typedef ntlMatrix4x4 ntlMat4d; +typedef ntlMatrix4x4 ntlMat4d; + +// a 3D vector with single precision +typedef ntlMatrix4x4 ntlMat4f; + +// a 3D vector with grafix precision +typedef ntlMatrix4x4 ntlMat4Gfx; + +// a 3D integer vector +typedef ntlMatrix4x4 ntlMat4i; + + + + + +//------------------------------------------------------------------------------ +// STREAM FUNCTIONS +//------------------------------------------------------------------------------ + + + +/************************************************************************* + Outputs the object in human readable form using the format + [x,y,z] + */ +template +std::ostream& +operator<<( std::ostream& os, const ntlMatrix4x4& m ) +{ + for(int i=0; i<4; i++) { + os << '|' << m.value[i][0] << ", " << m.value[i][1] << ", " << m.value[i][2] << ", " << m.value[i][3] << '|'; + } + return os; +} + + + +/************************************************************************* + Reads the contents of the object from a stream using the same format + as the output operator. + */ +template +std::istream& +operator>>( std::istream& is, ntlMatrix4x4& m ) +{ + char c; + char dummy[3]; + + for(int i=0; i<4; i++) { + is >> c >> m.value[i][0] >> dummy >> m.value[i][1] >> dummy >> m.value[i][2] >> dummy >> m.value[i][3] >> c; + } + return is; +} + + +//------------------------------------------------------------------------------ +// VECTOR inline FUNCTIONS +//------------------------------------------------------------------------------ + + + +/************************************************************************* + Constructor. + */ +template +inline ntlMatrix4x4::ntlMatrix4x4( void ) +{ +#ifdef MATRIX_INIT_ZERO + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + value[i][j] = 0.0; + } + } +#endif +} + + + +/************************************************************************* + Copy-Constructor. + */ +template +inline ntlMatrix4x4::ntlMatrix4x4( const ntlMatrix4x4 &v ) +{ + value[0][0] = v.value[0][0]; value[0][1] = v.value[0][1]; value[0][2] = v.value[0][2]; value[0][3] = v.value[0][3]; + value[1][0] = v.value[1][0]; value[1][1] = v.value[1][1]; value[1][2] = v.value[1][2]; value[1][3] = v.value[1][3]; + value[2][0] = v.value[2][0]; value[2][1] = v.value[2][1]; value[2][2] = v.value[2][2]; value[2][3] = v.value[2][3]; + value[3][0] = v.value[3][0]; value[3][1] = v.value[3][1]; value[3][2] = v.value[3][2]; value[3][3] = v.value[3][3]; +} + + + +/************************************************************************* + Constructor for a vector from a single Scalar. All components of + the vector get the same value. + \param s The value to set + \return The new vector + */ +template +inline ntlMatrix4x4::ntlMatrix4x4(Scalar s ) +{ + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + value[i][j] = s; + } + } +} + + + +/************************************************************************* + Copy a ntlMatrix4x4 componentwise. + \param v vector with values to be copied + \return Reference to self + */ +template +inline const ntlMatrix4x4& +ntlMatrix4x4::operator=( const ntlMatrix4x4 &v ) +{ + value[0][0] = v.value[0][0]; value[0][1] = v.value[0][1]; value[0][2] = v.value[0][2]; value[0][3] = v.value[0][3]; + value[1][0] = v.value[1][0]; value[1][1] = v.value[1][1]; value[1][2] = v.value[1][2]; value[1][3] = v.value[1][3]; + value[2][0] = v.value[2][0]; value[2][1] = v.value[2][1]; value[2][2] = v.value[2][2]; value[2][3] = v.value[2][3]; + value[3][0] = v.value[3][0]; value[3][1] = v.value[3][1]; value[3][2] = v.value[3][2]; value[3][3] = v.value[3][3]; + return *this; +} + + +/************************************************************************* + Copy a Scalar to each component. + \param s The value to copy + \return Reference to self + */ +template +inline const ntlMatrix4x4& +ntlMatrix4x4::operator=(Scalar s) +{ + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + value[i][j] = s; + } + } + return *this; +} + + +/************************************************************************* + Add another ntlMatrix4x4 componentwise. + \param v vector with values to be added + \return Reference to self + */ +template +inline const ntlMatrix4x4& +ntlMatrix4x4::operator+=( const ntlMatrix4x4 &v ) +{ + value[0][0] += v.value[0][0]; value[0][1] += v.value[0][1]; value[0][2] += v.value[0][2]; value[0][3] += v.value[0][3]; + value[1][0] += v.value[1][0]; value[1][1] += v.value[1][1]; value[1][2] += v.value[1][2]; value[1][3] += v.value[1][3]; + value[2][0] += v.value[2][0]; value[2][1] += v.value[2][1]; value[2][2] += v.value[2][2]; value[2][3] += v.value[2][3]; + value[3][0] += v.value[3][0]; value[3][1] += v.value[3][1]; value[3][2] += v.value[3][2]; value[3][3] += v.value[3][3]; + return *this; +} + + +/************************************************************************* + Add a Scalar value to each component. + \param s Value to add + \return Reference to self + */ +template +inline const ntlMatrix4x4& +ntlMatrix4x4::operator+=(Scalar s) +{ + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + value[i][j] += s; + } + } + return *this; +} + + +/************************************************************************* + Subtract another vector componentwise. + \param v vector of values to subtract + \return Reference to self + */ +template +inline const ntlMatrix4x4& +ntlMatrix4x4::operator-=( const ntlMatrix4x4 &v ) +{ + value[0][0] -= v.value[0][0]; value[0][1] -= v.value[0][1]; value[0][2] -= v.value[0][2]; value[0][3] -= v.value[0][3]; + value[1][0] -= v.value[1][0]; value[1][1] -= v.value[1][1]; value[1][2] -= v.value[1][2]; value[1][3] -= v.value[1][3]; + value[2][0] -= v.value[2][0]; value[2][1] -= v.value[2][1]; value[2][2] -= v.value[2][2]; value[2][3] -= v.value[2][3]; + value[3][0] -= v.value[3][0]; value[3][1] -= v.value[3][1]; value[3][2] -= v.value[3][2]; value[3][3] -= v.value[3][3]; + return *this; +} + + +/************************************************************************* + Subtract a Scalar value from each component. + \param s Value to subtract + \return Reference to self + */ +template +inline const ntlMatrix4x4& +ntlMatrix4x4::operator-=(Scalar s) +{ + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + value[i][j] -= s; + } + } + return *this; +} + + +/************************************************************************* + Multiply with another vector componentwise. + \param v vector of values to multiply with + \return Reference to self + */ +template +inline const ntlMatrix4x4& +ntlMatrix4x4::operator*=( const ntlMatrix4x4 &v ) +{ + ntlMatrix4x4 nv(0.0); + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + + for(int k=0;k<4;k++) + nv.value[i][j] += (value[i][k] * v.value[k][j]); + } + } + *this = nv; + return *this; +} + + +/************************************************************************* + Multiply each component with a Scalar value. + \param s Value to multiply with + \return Reference to self + */ +template +inline const ntlMatrix4x4& +ntlMatrix4x4::operator*=(Scalar s) +{ + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + value[i][j] *= s; + } + } + return *this; +} + + + +/************************************************************************* + Divide each component by a Scalar value. + \param s Value to divide by + \return Reference to self + */ +template +inline const ntlMatrix4x4& +ntlMatrix4x4::operator/=(Scalar s) +{ + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + value[i][j] /= s; + } + } + return *this; +} + + +//------------------------------------------------------------------------------ +// unary operators +//------------------------------------------------------------------------------ + + +/************************************************************************* + Build componentwise the negative this vector. + \return The new (negative) vector + */ +template +inline ntlMatrix4x4 +ntlMatrix4x4::operator-() const +{ + ntlMatrix4x4 nv; + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + nv[i][j] = -value[i][j]; + } + } + return nv; +} + + + +//------------------------------------------------------------------------------ +// binary operators +//------------------------------------------------------------------------------ + + +/************************************************************************* + Build a vector with another vector added componentwise. + \param v The second vector to add + \return The sum vector + */ +template +inline ntlMatrix4x4 +ntlMatrix4x4::operator+( const ntlMatrix4x4 &v ) const +{ + ntlMatrix4x4 nv; + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + nv[i][j] = value[i][j] + v.value[i][j]; + } + } + return nv; +} + + +/************************************************************************* + Build a vector with a Scalar value added to each component. + \param s The Scalar value to add + \return The sum vector + */ +template +inline ntlMatrix4x4 +ntlMatrix4x4::operator+(Scalar s) const +{ + ntlMatrix4x4 nv; + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + nv[i][j] = value[i][j] + s; + } + } + return nv; +} + + +/************************************************************************* + Build a vector with another vector subtracted componentwise. + \param v The second vector to subtract + \return The difference vector + */ +template +inline ntlMatrix4x4 +ntlMatrix4x4::operator-( const ntlMatrix4x4 &v ) const +{ + ntlMatrix4x4 nv; + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + nv[i][j] = value[i][j] - v.value[i][j]; + } + } + return nv; +} + + +/************************************************************************* + Build a vector with a Scalar value subtracted componentwise. + \param s The Scalar value to subtract + \return The difference vector + */ +template +inline ntlMatrix4x4 +ntlMatrix4x4::operator-(Scalar s ) const +{ + ntlMatrix4x4 nv; + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + nv[i][j] = value[i][j] - s; + } + } + return nv; +} + + + +/************************************************************************* + Build a ntlMatrix4x4 with a Scalar value multiplied to each component. + \param s The Scalar value to multiply with + \return The product vector + */ +template +inline ntlMatrix4x4 +ntlMatrix4x4::operator*(Scalar s) const +{ + ntlMatrix4x4 nv; + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + nv[i][j] = value[i][j] * s; + } + } + return nv; +} + + + + +/************************************************************************* + Build a vector divided componentwise by a Scalar value. + \param s The Scalar value to divide by + \return The ratio vector + */ +template +inline ntlMatrix4x4 +ntlMatrix4x4::operator/(Scalar s) const +{ + ntlMatrix4x4 nv; + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + nv[i][j] = value[i][j] / s; + } + } + return nv; +} + + + + + +/************************************************************************* + Build a vector with another vector multiplied by componentwise. + \param v The second vector to muliply with + \return The product vector + */ +template +inline ntlMatrix4x4 +ntlMatrix4x4::operator*( const ntlMatrix4x4& v) const +{ + ntlMatrix4x4 nv(0.0); + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + + for(int k=0;k<4;k++) + nv.value[i][j] += (value[i][k] * v.value[k][j]); + } + } + return nv; +} + + +template +inline ntlVector3Dim +ntlMatrix4x4::operator*( const ntlVector3Dim& v) const +{ + ntlVector3Dim nvec(0.0); + for(int i=0; i<3; i++) { + for(int j=0; j<3; j++) { + nvec[i] += (v[j] * value[i][j]); + } + } + // assume normalized w coord + for(int i=0; i<3; i++) { + nvec[i] += (1.0 * value[i][3]); + } + return nvec; +} + + + +//------------------------------------------------------------------------------ +// Other helper functions +//------------------------------------------------------------------------------ + +//! init identity matrix +template +inline void ntlMatrix4x4::initId() +{ + (*this) = (Scalar)(0.0); + value[0][0] = + value[1][1] = + value[2][2] = + value[3][3] = (Scalar)(1.0); +} + +//! init rotation matrix +template +inline void ntlMatrix4x4::initTranslation(Scalar x, Scalar y, Scalar z) +{ + //(*this) = (Scalar)(0.0); + this->initId(); + value[0][3] = x; + value[1][3] = y; + value[2][3] = z; +} + +//! init rotation matrix +template +inline void +ntlMatrix4x4::initRotationX(Scalar rot) +{ + double drot = (double)(rot/360.0*2.0*M_PI); + //? while(drot < 0.0) drot += (M_PI*2.0); + + this->initId(); + value[1][1] = (Scalar) cos(drot); + value[1][2] = (Scalar) sin(drot); + value[2][1] = (Scalar)(-sin(drot)); + value[2][2] = (Scalar) cos(drot); +} +template +inline void +ntlMatrix4x4::initRotationY(Scalar rot) +{ + double drot = (double)(rot/360.0*2.0*M_PI); + //? while(drot < 0.0) drot += (M_PI*2.0); + + this->initId(); + value[0][0] = (Scalar) cos(drot); + value[0][2] = (Scalar)(-sin(drot)); + value[2][0] = (Scalar) sin(drot); + value[2][2] = (Scalar) cos(drot); +} +template +inline void +ntlMatrix4x4::initRotationZ(Scalar rot) +{ + double drot = (double)(rot/360.0*2.0*M_PI); + //? while(drot < 0.0) drot += (M_PI*2.0); + + this->initId(); + value[0][0] = (Scalar) cos(drot); + value[0][1] = (Scalar) sin(drot); + value[1][0] = (Scalar)(-sin(drot)); + value[1][1] = (Scalar) cos(drot); +} +template +inline void +ntlMatrix4x4::initRotationXYZ( Scalar rotx, Scalar roty, Scalar rotz) +{ + ntlMatrix4x4 val; + ntlMatrix4x4 rot; + this->initId(); + + // org + /*rot.initRotationX(rotx); + (*this) *= rot; + rot.initRotationY(roty); + (*this) *= rot; + rot.initRotationZ(rotz); + (*this) *= rot; + // org */ + + // blender + rot.initRotationZ(rotz); + (*this) *= rot; + rot.initRotationY(roty); + (*this) *= rot; + rot.initRotationX(rotx); + (*this) *= rot; + // blender */ +} + +//! init scaling matrix +template +inline void +ntlMatrix4x4::initScaling(Scalar scale) +{ + this->initId(); + value[0][0] = scale; + value[1][1] = scale; + value[2][2] = scale; +} +//! init scaling matrix +template +inline void +ntlMatrix4x4::initScaling(Scalar x, Scalar y, Scalar z) +{ + this->initId(); + value[0][0] = x; + value[1][1] = y; + value[2][2] = z; +} + + +//! from 16 value array (init id if all 0) +template +inline void +ntlMatrix4x4::initArrayCheck(Scalar *array) +{ + bool allZero = true; + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + value[i][j] = array[i*4+j]; + if(array[i*4+j]!=0.0) allZero=false; + } + } + if(allZero) this->initId(); +} + +//! decompose matrix +template +void +ntlMatrix4x4::decompose(ntlVector3Dim &trans,ntlVector3Dim &scale,ntlVector3Dim &rot,ntlVector3Dim &shear) { + ntlVec3Gfx row[3],temp; + + for(int i = 0; i < 3; i++) { + trans[i] = this->value[3][i]; + } + + for(int i = 0; i < 3; i++) { + row[i][0] = this->value[i][0]; + row[i][1] = this->value[i][1]; + row[i][2] = this->value[i][2]; + } + + scale[0] = norm(row[0]); + normalize (row[0]); + + shear[0] = dot(row[0], row[1]); + row[1][0] = row[1][0] - shear[0]*row[0][0]; + row[1][1] = row[1][1] - shear[0]*row[0][1]; + row[1][2] = row[1][2] - shear[0]*row[0][2]; + + scale[1] = norm(row[1]); + normalize (row[1]); + + if(scale[1] != 0.0) + shear[0] /= scale[1]; + + shear[1] = dot(row[0], row[2]); + row[2][0] = row[2][0] - shear[1]*row[0][0]; + row[2][1] = row[2][1] - shear[1]*row[0][1]; + row[2][2] = row[2][2] - shear[1]*row[0][2]; + + shear[2] = dot(row[1], row[2]); + row[2][0] = row[2][0] - shear[2]*row[1][0]; + row[2][1] = row[2][1] - shear[2]*row[1][1]; + row[2][2] = row[2][2] - shear[2]*row[1][2]; + + scale[2] = norm(row[2]); + normalize (row[2]); + + if(scale[2] != 0.0) { + shear[1] /= scale[2]; + shear[2] /= scale[2]; + } + + temp = cross(row[1], row[2]); + if(dot(row[0], temp) < 0.0) { + for(int i = 0; i < 3; i++) { + scale[i] *= -1.0; + row[i][0] *= -1.0; + row[i][1] *= -1.0; + row[i][2] *= -1.0; + } + } + + if(row[0][2] < -1.0) row[0][2] = -1.0; + if(row[0][2] > +1.0) row[0][2] = +1.0; + + rot[1] = asin(-row[0][2]); + + if(fabs(cos(rot[1])) > VECTOR_EPSILON) { + rot[0] = atan2 (row[1][2], row[2][2]); + rot[2] = atan2 (row[0][1], row[0][0]); + } + else { + rot[0] = atan2 (row[1][0], row[1][1]); + rot[2] = 0.0; + } + + rot[0] = (180.0/M_PI)*rot[0]; + rot[1] = (180.0/M_PI)*rot[1]; + rot[2] = (180.0/M_PI)*rot[2]; +} + +#define NTL_MATRICES_H +#endif + diff --git a/intern/elbeem/intern/ntl_ray.cpp b/intern/elbeem/intern/ntl_ray.cpp new file mode 100644 index 00000000000..d6593b6b335 --- /dev/null +++ b/intern/elbeem/intern/ntl_ray.cpp @@ -0,0 +1,912 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * main renderer class + * + *****************************************************************************/ + + +#include "utilities.h" +#include "ntl_ray.h" +#include "ntl_world.h" +#include "ntl_geometryobject.h" +#include "ntl_geometryshader.h" + + +/* Minimum value for refl/refr to be traced */ +#define RAY_THRESHOLD 0.001 + +#if GFX_PRECISION==1 +// float values +//! Minimal contribution for rays to be traced on +#define RAY_MINCONTRIB (1e-04) + +#else +// double values +//! Minimal contribution for rays to be traced on +#define RAY_MINCONTRIB (1e-05) + +#endif + + + + + +/****************************************************************************** + * Constructor + *****************************************************************************/ +ntlRay::ntlRay( void ) + : mOrigin(0.0) + , mDirection(0.0) + , mvNormal(0.0) + , mDepth(0) + , mpGlob(NULL) + , mIsRefracted(0) +{ + errFatal("ntlRay::ntlRay()","Don't use uninitialized rays !", SIMWORLD_GENERICERROR); + return; +} + + +/****************************************************************************** + * Copy - Constructor + *****************************************************************************/ +ntlRay::ntlRay( const ntlRay &r ) +{ + // copy it! initialization is not enough! + mOrigin = r.mOrigin; + mDirection = r.mDirection; + mvNormal = r.mvNormal; + mDepth = r.mDepth; + mIsRefracted = r.mIsRefracted; + mIsReflected = r.mIsReflected; + mContribution = r.mContribution; + mpGlob = r.mpGlob; + + // get new ID + if(mpGlob) { + mID = mpGlob->getCounterRays()+1; + mpGlob->setCounterRays( mpGlob->getCounterRays()+1 ); + } else { + mID = 0; + } +} + + +/****************************************************************************** + * Constructor with explicit parameters and global render object + *****************************************************************************/ +ntlRay::ntlRay(const ntlVec3Gfx &o, const ntlVec3Gfx &d, unsigned int i, gfxReal contrib, ntlRenderGlobals *glob) + : mOrigin( o ) + , mDirection( d ) + , mvNormal(0.0) + , mDepth( i ) + , mContribution( contrib ) + , mpGlob( glob ) + , mIsRefracted( 0 ) + , mIsReflected( 0 ) +{ + // get new ID + if(mpGlob) { + mID = mpGlob->getCounterRays()+1; + mpGlob->setCounterRays( mpGlob->getCounterRays()+1 ); + } else { + mID = 0; + } +} + + + +/****************************************************************************** + * Destructor + *****************************************************************************/ +ntlRay::~ntlRay() +{ + /* nothing to do... */ +} + + + +/****************************************************************************** + * AABB + *****************************************************************************/ +/* for AABB intersect */ +#define NUMDIM 3 +#define RIGHT 0 +#define LEFT 1 +#define MIDDLE 2 + +//! intersect ray with AABB +#ifndef ELBEEM_PLUGIN +void ntlRay::intersectFrontAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &t, ntlVec3Gfx &retnormal,ntlVec3Gfx &retcoord) const +{ + char inside = true; /* inside box? */ + char hit = false; /* ray hits box? */ + int whichPlane; /* intersection plane */ + gfxReal candPlane[NUMDIM]; /* candidate plane */ + gfxReal quadrant[NUMDIM]; /* quadrants */ + gfxReal maxT[NUMDIM]; /* max intersection T for planes */ + ntlVec3Gfx coord; /* intersection point */ + ntlVec3Gfx dir = mDirection; + ntlVec3Gfx origin = mOrigin; + ntlVec3Gfx normal(0.0, 0.0, 0.0); + + t = GFX_REAL_MAX; + + /* check intersection planes for AABB */ + for(int i=0;i mEnd[i]) { + quadrant[i] = RIGHT; + candPlane[i] = mEnd[i]; + inside = false; + } else { + quadrant[i] = MIDDLE; + } + } + + /* inside AABB? */ + if(!inside) { + /* get t distances to planes */ + /* treat too small direction components as paralell */ + for(int i=0;i getVecEpsilon()) ) { + maxT[i] = (candPlane[i] - origin[i]) / dir[i]; + } else { + maxT[i] = -1; + } + } + + /* largest max t */ + whichPlane = 0; + for(int i=1;i= 0.0) { + + for(int i=0;i mEnd[i] +getVecEpsilon() ) ) { + /* no hit... */ + hit = false; + } + } + else { + coord[i] = candPlane[i]; + } + } + + /* AABB hit... */ + if( hit ) { + t = maxT[whichPlane]; + if(quadrant[whichPlane]==RIGHT) normal[whichPlane] = 1.0; + else normal[whichPlane] = -1.0; + } + } + + + } else { + /* inside AABB... */ + t = 0.0; + coord = origin; + return; + } + + if(t == GFX_REAL_MAX) t = -1.0; + retnormal = normal; + retcoord = coord; +} + +//! intersect ray with AABB +void ntlRay::intersectBackAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &t, ntlVec3Gfx &retnormal,ntlVec3Gfx &retcoord) const +{ + char hit = false; /* ray hits box? */ + int whichPlane; /* intersection plane */ + gfxReal candPlane[NUMDIM]; /* candidate plane */ + gfxReal quadrant[NUMDIM]; /* quadrants */ + gfxReal maxT[NUMDIM]; /* max intersection T for planes */ + ntlVec3Gfx coord; /* intersection point */ + ntlVec3Gfx dir = mDirection; + ntlVec3Gfx origin = mOrigin; + ntlVec3Gfx normal(0.0, 0.0, 0.0); + + t = GFX_REAL_MAX; + for(int i=0;i mEnd[i]) { + quadrant[i] = RIGHT; + candPlane[i] = mStart[i]; + } else { + if(dir[i] > 0) { + quadrant[i] = LEFT; + candPlane [i] = mEnd[i]; + } else + if(dir[i] < 0) { + quadrant[i] = RIGHT; + candPlane[i] = mStart[i]; + } else { + quadrant[i] = MIDDLE; + } + } + } + + + /* get t distances to planes */ + /* treat too small direction components as paralell */ + for(int i=0;i getVecEpsilon()) ) { + maxT[i] = (candPlane[i] - origin[i]) / dir[i]; + } else { + maxT[i] = GFX_REAL_MAX; + } + } + + /* largest max t */ + whichPlane = 0; + for(int i=1;i maxT[i]) whichPlane = i; + } + + /* check final candidate */ + hit = true; + if(maxT[whichPlane] != GFX_REAL_MAX) { + + for(int i=0;i mEnd[i] +getVecEpsilon() ) ) { + /* no hit... */ + hit = false; + } + } + else { + coord[i] = candPlane[i]; + } + } + + /* AABB hit... */ + if( hit ) { + t = maxT[whichPlane]; + + if(quadrant[whichPlane]==RIGHT) normal[whichPlane] = 1.0; + else normal[whichPlane] = -1.0; + } + } + + + if(t == GFX_REAL_MAX) t = -1.0; + retnormal = normal; + retcoord = coord; +} +#endif // ELBEEM_PLUGIN + +//! intersect ray with AABB +void ntlRay::intersectCompleteAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &tmin, gfxReal &tmax) const +{ + char inside = true; /* inside box? */ + char hit = false; /* ray hits box? */ + int whichPlane; /* intersection plane */ + gfxReal candPlane[NUMDIM]; /* candidate plane */ + gfxReal quadrant[NUMDIM]; /* quadrants */ + gfxReal maxT[NUMDIM]; /* max intersection T for planes */ + ntlVec3Gfx coord; /* intersection point */ + ntlVec3Gfx dir = mDirection; + ntlVec3Gfx origin = mOrigin; + gfxReal t = GFX_REAL_MAX; + + /* check intersection planes for AABB */ + for(int i=0;i mEnd[i]) { + quadrant[i] = RIGHT; + candPlane[i] = mEnd[i]; + inside = false; + } else { + /* intersect with backside */ + if(dir[i] > 0) { + quadrant[i] = LEFT; + candPlane [i] = mStart[i]; + } else + if(dir[i] < 0) { + quadrant[i] = RIGHT; + candPlane[i] = mEnd[i]; + } else { + quadrant[i] = MIDDLE; + } + } + } + + /* get t distances to planes */ + for(int i=0;i getVecEpsilon()) ) { + maxT[i] = (candPlane[i] - origin[i]) / dir[i]; + } else { + maxT[i] = GFX_REAL_MAX; + } + } + + /* largest max t */ + whichPlane = 0; + for(int i=1;i mEnd[i] +getVecEpsilon() ) ) { + /* no hit... */ + hit = false; + } + } + else { coord[i] = candPlane[i]; } + } + + /* AABB hit... */ + if( hit ) { + t = maxT[whichPlane]; + } + } + tmin = t; + + /* now the backside */ + t = GFX_REAL_MAX; + for(int i=0;i mEnd[i]) { + quadrant[i] = RIGHT; + candPlane[i] = mStart[i]; + } else { + if(dir[i] > 0) { + quadrant[i] = LEFT; + candPlane [i] = mEnd[i]; + } else + if(dir[i] < 0) { + quadrant[i] = RIGHT; + candPlane[i] = mStart[i]; + } else { + quadrant[i] = MIDDLE; + } + } + } + + + /* get t distances to planes */ + for(int i=0;i getVecEpsilon()) ) { + maxT[i] = (candPlane[i] - origin[i]) / dir[i]; + } else { + maxT[i] = GFX_REAL_MAX; + } + } + + /* smallest max t */ + whichPlane = 0; + for(int i=1;i maxT[i]) whichPlane = i; + } + + /* check final candidate */ + hit = true; + if(maxT[whichPlane] != GFX_REAL_MAX) { + + for(int i=0;i mEnd[i] +getVecEpsilon() ) ) { + /* no hit... */ + hit = false; + } + } + else { + coord[i] = candPlane[i]; + } + } + + /* AABB hit... */ + if( hit ) { + t = maxT[whichPlane]; + } + } + + tmax = t; +} + + + +/****************************************************************************** + * Determine color of this ray by tracing through the scene + *****************************************************************************/ +const ntlColor ntlRay::shade() //const +{ +#ifndef ELBEEM_PLUGIN + ntlGeometryObject *closest = NULL; + gfxReal minT = GFX_REAL_MAX; + vector *lightlist = mpGlob->getLightList(); + mpGlob->setCounterShades( mpGlob->getCounterShades()+1 ); + bool intersectionInside = 0; + if(mpGlob->getDebugOut() > 5) errorOut(std::endl<<"New Ray: depth "<getRenderScene()->intersectScene(*this, minT, normal, tri, 0); + if(minT>0) { + closest = mpGlob->getRenderScene()->getObject( tri->getObjectId() ); + } + + /* object hit... */ + if (closest != NULL) { + + ntlVec3Gfx triangleNormal = tri->getNormal(); + if( equal(triangleNormal, ntlVec3Gfx(0.0)) ) errorOut("ntlRay warning: trinagle normal= 0 "); // DEBUG + /* intersection on inside faces? if yes invert normal afterwards */ + gfxReal valDN; // = mDirection | normal; + valDN = dot(mDirection, triangleNormal); + if( valDN > 0.0) { + intersectionInside = 1; + normal = normal * -1.0; + triangleNormal = triangleNormal * -1.0; + } + + /* ... -> do reflection */ + ntlVec3Gfx intersectionPosition(mOrigin + (mDirection * (minT)) ); + ntlMaterial *clossurf = closest->getMaterial(); + /*if(mpGlob->getDebugOut() > 5) { + errorOut("Ray hit: at "<getRenderScene()->getVertex(tri->getPoints()[0])<<" t2:"<getRenderScene()->getVertex(tri->getPoints()[1])<<" t3:"<getScene()->getVertex(tri->getPoints()[2]) ); + errorOut(" trin:"<getNormal() ); + } // debug */ + + /* current transparence and reflectivity */ + gfxReal currTrans = clossurf->getTransparence(); + gfxReal currRefl = clossurf->getMirror(); + + /* correct intersectopm position */ + intersectionPosition += ( triangleNormal*getVecEpsilon() ); + /* reflection at normal */ + ntlVec3Gfx reflectedDir = getNormalized( reflectVector(mDirection, normal) ); + int badRefl = 0; + if(dot(reflectedDir, triangleNormal)<0.0 ) { + badRefl = 1; + if(mpGlob->getDebugOut() > 5) { errorOut("Ray Bad reflection...!"); } + } + + /* refraction direction, depending on in/outside hit */ + ntlVec3Gfx refractedDir; + int refRefl = 0; + /* refraction at normal is handled by inverting normal before */ + gfxReal myRefIndex = 1.0; + if((currTrans>RAY_THRESHOLD)||(clossurf->getFresnel())) { + if(intersectionInside) { + myRefIndex = 1.0/clossurf->getRefracIndex(); + } else { + myRefIndex = clossurf->getRefracIndex(); + } + + refractedDir = refractVector(mDirection, normal, myRefIndex , (gfxReal)(1.0) /* global ref index */, refRefl); + } + + /* calculate fresnel? */ + if(clossurf->getFresnel()) { + // for total reflection, just set trans to 0 + if(refRefl) { + currRefl = 1.0; currTrans = 0.0; + } else { + // calculate fresnel coefficients + clossurf->calculateFresnel( mDirection, normal, myRefIndex, currRefl,currTrans ); + } + } + + ntlRay reflectedRay(intersectionPosition, reflectedDir, mDepth+1, mContribution*currRefl, mpGlob); + reflectedRay.setNormal( normal ); + ntlColor currentColor(0.0); + ntlColor highlightColor(0.0); + + /* first add reflected ambient color */ + currentColor += (clossurf->getAmbientRefl() * mpGlob->getAmbientLight() ); + + /* calculate lighting, not on the insides of objects... */ + if(!intersectionInside) { + for (vector::iterator iter = lightlist->begin(); + iter != lightlist->end(); + iter++) { + + /* let light illuminate point */ + currentColor += (*iter)->illuminatePoint( reflectedRay, closest, highlightColor ); + + } // for all lights + } + + // recurse ? + if ((mDepth < mpGlob->getRayMaxDepth() )&&(currRefl>RAY_THRESHOLD)) { + + if(badRefl) { + ntlVec3Gfx intersectionPosition2; + ntlGeometryObject *closest2 = NULL; + gfxReal minT2 = GFX_REAL_MAX; + ntlTriangle *tri2 = NULL; + ntlVec3Gfx normal2; + + ntlVec3Gfx refractionPosition2(mOrigin + (mDirection * minT) ); + refractionPosition2 -= (triangleNormal*getVecEpsilon() ); + + ntlRay reflectedRay2 = ntlRay(refractionPosition2, reflectedDir, mDepth+1, mContribution*currRefl, mpGlob); + mpGlob->getRenderScene()->intersectScene(reflectedRay2, minT2, normal2, tri2, 0); + if(minT2>0) { + closest2 = mpGlob->getRenderScene()->getObject( tri2->getObjectId() ); + } + + /* object hit... */ + if (closest2 != NULL) { + ntlVec3Gfx triangleNormal2 = tri2->getNormal(); + gfxReal valDN2; + valDN2 = dot(reflectedDir, triangleNormal2); + if( valDN2 > 0.0) { + triangleNormal2 = triangleNormal2 * -1.0; + intersectionPosition2 = ntlVec3Gfx(intersectionPosition + (reflectedDir * (minT2)) ); + /* correct intersection position and create new reflected ray */ + intersectionPosition2 += ( triangleNormal2*getVecEpsilon() ); + reflectedRay = ntlRay(intersectionPosition2, reflectedDir, mDepth+1, mContribution*currRefl, mpGlob); + } else { + // ray seems to work, continue normally ? + } + + } + + } + + // add mirror color multiplied by mirror factor of surface + if(mpGlob->getDebugOut() > 5) errorOut("Reflected ray from depth "< RAY_THRESHOLD) { + /* position at the other side of the surface, along ray */ + ntlVec3Gfx refraction_position(mOrigin + (mDirection * minT) ); + refraction_position += (mDirection * getVecEpsilon()); + refraction_position -= (triangleNormal*getVecEpsilon() ); + ntlColor refracCol(0.0); /* refracted color */ + + /* trace refracted ray */ + ntlRay transRay(refraction_position, refractedDir, mDepth+1, mContribution*currTrans, mpGlob); + transRay.setRefracted(1); + transRay.setNormal( normal ); + if(mDepth < mpGlob->getRayMaxDepth() ) { + // full reflection should make sure refracindex&fresnel are on... + if((0)||(!refRefl)) { + if(mpGlob->getDebugOut() > 5) errorOut("Refracted ray from depth "<getDebugOut() > 5) errorOut("Fully reflected ray from depth "<getTransAttCol(); + kr = exp( attCol[0] * minT ); + kg = exp( attCol[1] * minT ); + kb = exp( attCol[2] * minT ); + currentColor = currentColor * ntlColor(kr,kg,kb); + } + + /* done... */ + if(mpGlob->getDebugOut() > 5) { errorOut("Ray "< ray goes to infinity */ + return mpGlob->getBackgroundCol(); +} + + + +/****************************************************************************** + ****************************************************************************** + ****************************************************************************** + * scene implementation + ****************************************************************************** + ****************************************************************************** + *****************************************************************************/ + + + +/****************************************************************************** + * Constructor + *****************************************************************************/ +ntlScene::ntlScene( ntlRenderGlobals *glob, bool del ) : + mpGlob( glob ), mSceneDel(del), + mpTree( NULL ), + mDisplayListId( -1 ), + mSceneBuilt( false ), mFirstInitDone( false ) +{ +} + + +/****************************************************************************** + * Destructor + *****************************************************************************/ +ntlScene::~ntlScene() +{ + if(mpTree != NULL) delete mpTree; + + // cleanup lists, only if this is the rendering cleanup scene + if(mSceneDel) { + for (vector::iterator iter = mGeos.begin(); + iter != mGeos.end(); iter++) { + //errMsg("ntlScene::~ntlScene","Deleting obj "<<(*iter)->getName() ); + delete (*iter); + } + for (vector::iterator iter = mpGlob->getLightList()->begin(); + iter != mpGlob->getLightList()->end(); iter++) { + delete (*iter); + } + for (vector::iterator iter = mpGlob->getMaterials()->begin(); + iter != mpGlob->getMaterials()->end(); iter++) { + delete (*iter); + } + } + errMsg("ntlScene::~ntlScene","Deleted, ObjFree:"<::iterator iter = mGeos.begin(); + iter != mGeos.end(); iter++) { + bool geoinit = false; + int tid = (*iter)->getTypeId(); + if(tid & GEOCLASSTID_OBJECT) { + ntlGeometryObject *geoobj = (ntlGeometryObject*)(*iter); + geoinit = true; + mObjects.push_back( geoobj ); + if(buildInfo) debMsgStd("ntlScene::BuildScene",DM_MSG,"added GeoObj "<getName()<<" Id:"<getObjectId(), 5 ); + } + //if(geoshad) { + if(tid & GEOCLASSTID_SHADER) { + ntlGeometryShader *geoshad = (ntlGeometryShader*)(*iter); + geoinit = true; + if(!mFirstInitDone) { + // only on first init + geoshad->initializeShader(); + } + for (vector::iterator siter = geoshad->getObjectsBegin(); + siter != geoshad->getObjectsEnd(); + siter++) { + if(buildInfo) debMsgStd("ntlScene::BuildScene",DM_MSG,"added shader geometry "<<(*siter)->getName()<<" Id:"<<(*siter)->getObjectId(), 5 ); + mObjects.push_back( (*siter) ); + } + } + + if(!geoinit) { + errFatal("ntlScene::BuildScene","Invalid geometry class!", SIMWORLD_INITERROR); + return; + } + } + } + + // collect triangles + mTriangles.clear(); + mVertices.clear(); + mVertNormals.clear(); + + /* for test mode deactivate transparencies etc. */ + if( mpGlob->getTestMode() ) { + debugOut("ntlScene::buildScene : Test Mode activated!", 2); + // assign random colors to dark materials + int matCounter = 0; + ntlColor stdCols[] = { ntlColor(0,0,1.0), ntlColor(0,1.0,0), ntlColor(1.0,0.7,0) , ntlColor(0.7,0,0.6) }; + int stdColNum = 4; + for (vector::iterator iter = mpGlob->getMaterials()->begin(); + iter != mpGlob->getMaterials()->end(); iter++) { + (*iter)->setTransparence(0.0); + (*iter)->setMirror(0.0); + (*iter)->setFresnel(false); + // too dark? + if( norm((*iter)->getDiffuseRefl()) <0.01) { + (*iter)->setDiffuseRefl( stdCols[matCounter] ); + matCounter ++; + matCounter = matCounter%stdColNum; + } + } + + // restrict output file size to 400 + float downscale = 1.0; + if(mpGlob->getResX() > 400){ downscale = 400.0/(float)mpGlob->getResX(); } + if(mpGlob->getResY() > 400){ + float downscale2 = 400.0/(float)mpGlob->getResY(); + if(downscale2setResX( (int)(mpGlob->getResX() * downscale) ); + mpGlob->setResY( (int)(mpGlob->getResY() * downscale) ); + + } + + /* collect triangles from objects */ + int idCnt = 0; // give IDs to objects + bool debugTriCollect = false; + if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"Start...",5); + for (vector::iterator iter = mObjects.begin(); + iter != mObjects.end(); + iter++) { + /* only add visible objects */ + if(firstInit) { + if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"Collect init of "<<(*iter)->getName()<<" idCnt:"<initialize( mpGlob ); } + if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"Collecting tris from "<<(*iter)->getName(), 4 ); + + int vstart = mVertNormals.size(); + (*iter)->setObjectId(idCnt); + (*iter)->getTriangles(time, &mTriangles, &mVertices, &mVertNormals, idCnt); + (*iter)->applyTransformation(time, &mVertices, &mVertNormals, vstart, mVertices.size(), false ); + + if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"Done with "<<(*iter)->getName()<<" totTris:"<::iterator iter = mTriangles.begin(); + iter != mTriangles.end(); + iter++) { + + // calculate normal from triangle points + ntlVec3Gfx normal = + cross( (ntlVec3Gfx)( (mVertices[(*iter).getPoints()[2]] - mVertices[(*iter).getPoints()[0]]) *-1.0), // BLITZ minus sign right?? + (ntlVec3Gfx)(mVertices[(*iter).getPoints()[1]] - mVertices[(*iter).getPoints()[0]]) ); + normalize(normal); + (*iter).setNormal( normal ); + } + + + + // scene geometry built + mSceneBuilt = true; + + // init shaders that require complete geometry + if(!mFirstInitDone) { + // only on first init + for (vector::iterator iter = mGeos.begin(); + iter != mGeos.end(); iter++) { + if( (*iter)->getTypeId() & GEOCLASSTID_SHADER ) { + ntlGeometryShader *geoshad = (ntlGeometryShader*)(*iter); + if(geoshad->postGeoConstrInit( mpGlob )) { + errFatal("ntlScene::buildScene","Init failed for object '"<< (*iter)->getName() <<"' !", SIMWORLD_INITERROR ); + return; + } + } + } + mFirstInitDone = true; + } + + // check unused attributes (for classes and objects!) + for (vector::iterator iter = mObjects.begin(); iter != mObjects.end(); iter++) { + if((*iter)->getAttributeList()->checkUnusedParams()) { + (*iter)->getAttributeList()->print(); // DEBUG + errFatal("ntlScene::buildScene","Unused params for object '"<< (*iter)->getName() <<"' !", SIMWORLD_INITERROR ); + return; + } + } + for (vector::iterator iter = mGeos.begin(); iter != mGeos.end(); iter++) { + if((*iter)->getAttributeList()->checkUnusedParams()) { + (*iter)->getAttributeList()->print(); // DEBUG + errFatal("ntlScene::buildScene","Unused params for object '"<< (*iter)->getName() <<"' !", SIMWORLD_INITERROR ); + return; + } + } + +} + +/****************************************************************************** + * Prepare the scene triangles and maps for raytracing + *****************************************************************************/ +void ntlScene::prepareScene(double time) +{ + /* init triangles... */ + buildScene(time, false); + // what for currently not used ??? + if(mpTree != NULL) delete mpTree; + mpTree = new ntlTree( +# if FSGR_STRICT_DEBUG!=1 + mpGlob->getTreeMaxDepth(), mpGlob->getTreeMaxTriangles(), +# else + mpGlob->getTreeMaxDepth()/3*2, mpGlob->getTreeMaxTriangles()*2, +# endif + this, TRI_GEOMETRY ); + + //debMsgStd("ntlScene::prepareScene",DM_MSG,"Stats - tris:"<< (int)mTriangles.size()<<" verts:"<setCounterSceneInter( mpGlob->getCounterSceneInter()+1 ); + mpTree->intersect(r, distance, normal, tri, flags, false); +} + + + + + diff --git a/intern/elbeem/intern/ntl_ray.h b/intern/elbeem/intern/ntl_ray.h new file mode 100644 index 00000000000..096d5fd61d3 --- /dev/null +++ b/intern/elbeem/intern/ntl_ray.h @@ -0,0 +1,416 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * ray class + * + *****************************************************************************/ +#ifndef NTL_RAY_H +#define NTL_RAY_H + +#include +#include "ntl_vector3dim.h" +#include "ntl_lighting.h" +#include "ntl_geometryobject.h" +#include "ntl_bsptree.h" + +class ntlTriangle; +class ntlRay; +class ntlTree; +class ntlScene; +class ntlRenderGlobals; + +//! store data for an intersection of a ray and a triangle +// NOT YET USED +class ntlIntersection { + public: + + ntlIntersection() : + distance(-1.0), normal(0.0), + ray(NULL), tri(NULL), flags(0) { }; + + gfxReal distance; + ntlVec3Gfx normal; + ntlRay *ray; + ntlTriangle *tri; + char flags; +}; + +//! the main ray class +class ntlRay +{ +public: + // CONSTRUCTORS + //! Initialize ray memebers, prints error message + ntlRay(); + //! Copy constructor, copy all members + ntlRay(const ntlRay &r); + //! Explicitly init member variables with global render object + ntlRay(const ntlVec3Gfx &o, const ntlVec3Gfx &d, unsigned int i, gfxReal contrib, ntlRenderGlobals *glob); + //! Destructor + ~ntlRay(); + + //! Set the refraction flag for refracted rays + inline void setRefracted(unsigned char set) { mIsRefracted = set; } + inline void setReflected(unsigned char set) { mIsReflected = set; } + + //! main ray recursion function + /*! + * First get closest object intersection, return background color if nothing + * was hit, else calculate shading and reflection components + * and return mixed color */ + const ntlColor shade() /*const*/; + + /*! Trace a photon through the scene */ + void tracePhoton(ntlColor) const; + + //! intersect ray with AABB + void intersectFrontAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &t, ntlVec3Gfx &normal, ntlVec3Gfx &retcoord) const; + void intersectBackAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &t, ntlVec3Gfx &normal, ntlVec3Gfx &retcoord) const; + void intersectCompleteAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &tmin, gfxReal &tmax) const; + // intersection routines in bsptree.cpp + //! optimized intersect ray with triangle + inline void intersectTriangle(vector *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const; + //! optimized intersect ray with triangle along +X axis dir + inline void intersectTriangleX(vector *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const; + //! intersect only with front side + inline void intersectTriangleFront(vector *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const; + //! intersect ray only with backsides + inline void intersectTriangleBack(vector *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const; + + // access methods + //! Returns the ray origin + inline ntlVec3Gfx getOrigin() const { return ntlVec3Gfx(mOrigin); } + //! Returns the ray direction + inline ntlVec3Gfx getDirection() const { return ntlVec3Gfx(mDirection); } + /*! Returns the ray relfection normal */ + inline ntlVec3Gfx getNormal() const { return ntlVec3Gfx(mvNormal); } + //! Is this ray refracted? + inline unsigned char getRefracted() const { return mIsRefracted; } + inline unsigned char getReflected() const { return mIsReflected; } + /*! Get position along ray */ + inline ntlVec3Gfx getPositionAt(gfxReal t) const { return (mOrigin+(mDirection*t)); } + /*! Get render globals pointer of this ray */ + inline ntlRenderGlobals *getRenderglobals( void ) const { return mpGlob; } + /*! get this ray's ID */ + inline int getID( void ) const { return mID; } + + /*! Set origin of this ray */ + inline void setOrigin(ntlVec3Gfx set) { mOrigin = set; } + /*! Set direction of this ray */ + inline void setDirection(ntlVec3Gfx set) { mDirection = set; } + /*! Set normal of this ray */ + inline void setNormal(ntlVec3Gfx set) { mvNormal = set; } + +protected: + /* Calulates the Lambertian and Specular color for + * the given reflection and returns it */ + const ntlColor getShadedColor(ntlLightObject *light, const ntlRay &reflectedray, + const ntlVec3Gfx &normal, ntlMaterial *surf) const; + +private: + /*! Origin of ray */ + ntlVec3Gfx mOrigin; + /*! Normalized direction vector of ray */ + ntlVec3Gfx mDirection; + /*! For reflected/refracted rays, the normal is stored here */ + ntlVec3Gfx mvNormal; + /*! recursion depth */ + unsigned int mDepth; + /*! How much does this ray contribute to the surface color? abort if too small */ + gfxReal mContribution; + + /*! Global rendering settings */ + ntlRenderGlobals *mpGlob; + + /*! If this ray is a refracted one, this flag has to be set + * This is necessary to for example also give the background color + * to refracted rays. Otherwise things may look strange... + */ + unsigned char mIsRefracted; + unsigned char mIsReflected; + + /*! ID of this ray (from renderglobals */ + int mID; + +}; + + +/****************************************************************************** + * + * a single triangle + * + *****************************************************************************/ + +// triangle intersection code in bsptree.cpp +// intersectTriangle(vector *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v); + +/*! Triangle flag defines */ +#define TRI_GEOMETRY (1<<0) +#define TRI_CASTSHADOWS (1<<1) + + +class ntlTriangle +{ +public: + /* CONSTRUCTORS */ + /*! Default constructor */ + inline ntlTriangle( void ); + /*! Constructor with parameters */ + inline ntlTriangle(int *p, bool smooth, int obj, ntlVec3Gfx norm, int setflags); + /*! Copy - Constructor */ + inline ntlTriangle(const ntlTriangle &tri); + /*! Destructor */ + inline ~ntlTriangle() {} + + /* Access methods */ + + /*! Acces to points of triangle */ + inline int *getPoints( void ) { return mPoints; } + /*! Acces normal smoothing */ + inline bool getSmoothNormals( void ) const { return mSmoothNormals; } + inline void setSmoothNormals( bool set){ mSmoothNormals = set; } + /*! Access object */ + inline int getObjectId( void ) const { return mObjectId; } + inline void setObjectId( int set) { mObjectId = set; } + /*! Acces normal index */ + inline ntlVec3Gfx getNormal( void ) const { return mNormal; } + inline void setNormal( ntlVec3Gfx set ) { mNormal = set; } + /*! Acces flags */ + inline int getFlags( void ) const { return mFlags; } + inline void setFlags( int set ) { mFlags = set; } + /*! Access last intersection ray ID */ + inline int getLastRay( void ) const { return mLastRay; } + inline void setLastRay( int set ) { mLastRay = set; } + /*! Acces bbox id */ + inline int getBBoxId( void ) const { return mBBoxId; } + inline void setBBoxId( int set ) { mBBoxId = set; } + + /*! Get average of the three points for this axis */ + inline gfxReal getAverage( int axis ) const; + + /*! operator < for sorting, uses global sorting axis */ + inline friend bool operator<(const ntlTriangle &lhs, const ntlTriangle &rhs); + /*! operator > for sorting, uses global sorting axis */ + inline friend bool operator>(const ntlTriangle &lhs, const ntlTriangle &rhs); + +protected: + +private: + + /*! indices to the three points of the triangle */ + int mPoints[3]; + + /*! bounding box id (for tree generation), -1 if invalid */ + int mBBoxId; + + /*! Should the normals of this triangle get smoothed? */ + bool mSmoothNormals; + + /*! Id of parent object */ + int mObjectId; + + /*! Index to normal (for not smooth triangles) */ + //int mNormalIndex; ?? + ntlVec3Gfx mNormal; + + /*! Flags for object attributes cast shadows */ + int mFlags; + + /*! ID of last ray that an intersection was calculated for */ + int mLastRay; + +}; + + + + +/****************************************************************************** + * Default Constructor + *****************************************************************************/ +ntlTriangle::ntlTriangle( void ) : + mBBoxId(-1), + mLastRay( 0 ) +{ + mPoints[0] = mPoints[1] = mPoints[2] = 0; + mSmoothNormals = 0; + mObjectId = 0; + mNormal = ntlVec3Gfx(0.0); + mFlags = 0; +} + + +/****************************************************************************** + * Constructor + *****************************************************************************/ +ntlTriangle::ntlTriangle(int *p, bool smooth, int obj, ntlVec3Gfx norm, int setflags) : + mBBoxId(-1), + mLastRay( 0 ) +{ + mPoints[0] = p[0]; + mPoints[1] = p[1]; + mPoints[2] = p[2]; + mSmoothNormals = smooth; + mObjectId = obj; + mNormal = norm; + mFlags = setflags; +} + + +/****************************************************************************** + * Copy Constructor + *****************************************************************************/ +ntlTriangle::ntlTriangle(const ntlTriangle &tri) : + mBBoxId(-1), + mLastRay( 0 ) +{ + mPoints[0] = tri.mPoints[0]; + mPoints[1] = tri.mPoints[1]; + mPoints[2] = tri.mPoints[2]; + mSmoothNormals = tri.mSmoothNormals; + mObjectId = tri.mObjectId; + mNormal = tri.mNormal; + mFlags = tri.mFlags; +} + + + + +/****************************************************************************** + * Triangle sorting functions + *****************************************************************************/ + +/* variables imported from ntl_bsptree.cc, necessary for using the stl sort funtion */ +/* Static global variable for sorting direction */ +extern int globalSortingAxis; +/* Access to points array for sorting */ +extern vector *globalSortingPoints; + + +gfxReal ntlTriangle::getAverage( int axis ) const +{ + return ( ( (*globalSortingPoints)[ mPoints[0] ][axis] + + (*globalSortingPoints)[ mPoints[1] ][axis] + + (*globalSortingPoints)[ mPoints[2] ][axis] )/3.0); +} + +bool operator<(const ntlTriangle &lhs,const ntlTriangle &rhs) +{ + return ( lhs.getAverage(globalSortingAxis) < + rhs.getAverage(globalSortingAxis) ); +} + +bool operator>(const ntlTriangle &lhs,const ntlTriangle &rhs) +{ + return ( lhs.getAverage(globalSortingAxis) > + rhs.getAverage(globalSortingAxis) ); +} + + + +/****************************************************************************** + * + * Scene object, that contains and manages all geometry objects + * + *****************************************************************************/ + + + +class ntlScene +{ +public: + /* CONSTRUCTORS */ + /*! Default constructor */ + ntlScene( ntlRenderGlobals *glob, bool del=true ); + /*! Default destructor */ + ~ntlScene(); + + /*! Add an object to the scene */ + inline void addGeoClass(ntlGeometryClass *geo) { + mGeos.push_back( geo ); + geo->setObjectId(mGeos.size()); + } + /*! Add a geo object to the scene, warning - only needed for hand init */ + inline void addGeoObject(ntlGeometryObject *geo) { mObjects.push_back( geo ); } + + /*! Acces a certain object */ + inline ntlGeometryObject *getObject(int id) { + if(!mSceneBuilt) { errFatal("ntlScene::getObject","Scene not inited!", SIMWORLD_INITERROR); } + return mObjects[id]; } + + /*! Acces object array */ + inline vector *getObjects() { + if(!mSceneBuilt) { errFatal("ntlScene::getObjects[]","Scene not inited!", SIMWORLD_INITERROR); } + return &mObjects; } + + /*! Acces geo class array */ + inline vector *getGeoClasses() { + if(!mSceneBuilt) { errFatal("ntlScene::getGeoClasses[]","Scene not inited!", SIMWORLD_INITERROR); } + return &mGeos; } + + /*! draw scene with opengl */ + //void draw(); + + /*! Build/first init the scene arrays */ + void buildScene(double time, bool firstInit); + + //! Prepare the scene triangles and maps for raytracing + void prepareScene(double time); + //! Do some memory cleaning, when frame is finished + void cleanupScene( void ); + + /*! Intersect a ray with the scene triangles */ + void intersectScene(const ntlRay &r, gfxReal &distance, ntlVec3Gfx &normal, ntlTriangle *&tri, int flags) const; + + /*! return a vertex */ + ntlVec3Gfx getVertex(int index) { return mVertices[index]; } + + // for tree generation + /*! return pointer to vertices vector */ + vector *getVertexPointer( void ) { return &mVertices; } + /*! return pointer to vertices vector */ + vector *getVertexNormalPointer( void ) { return &mVertNormals; } + /*! return pointer to vertices vector */ + vector *getTrianglePointer( void ) { return &mTriangles; } + +private: + + /*! Global settings */ + ntlRenderGlobals *mpGlob; + + /*! free objects? (only necessary for render scene, which contains all) */ + bool mSceneDel; + + /*! List of geometry classes */ + vector mGeos; + + /*! List of geometry objects */ + vector mObjects; + + /*! List of triangles */ + vector mTriangles; + /*! List of vertices */ + vector mVertices; + /*! List of normals */ + vector mVertNormals; + /*! List of triangle normals */ + vector mTriangleNormals; + + /*! Tree to store quickly intersect triangles */ + ntlTree *mpTree; + + /*! id of dislpay list for raytracer stuff */ + int mDisplayListId; + + /*! was the scene successfully built? only then getObject(i) requests are valid */ + bool mSceneBuilt; + + /*! shader/obj initializations are only done on first init */ + bool mFirstInitDone; + +}; + + +#endif + diff --git a/intern/elbeem/intern/ntl_vector3dim.h b/intern/elbeem/intern/ntl_vector3dim.h new file mode 100644 index 00000000000..912a37350c1 --- /dev/null +++ b/intern/elbeem/intern/ntl_vector3dim.h @@ -0,0 +1,1081 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Basic vector class used everywhere, either blitz or inlined GRAPA class + * + *****************************************************************************/ +#ifndef NTL_VECTOR3DIM_H +#define NTL_VECTOR3DIM_H + +// this serves as the main include file +// for all kinds of stuff that might be required +// under windos there seem to be strange +// errors when including the STL header too +// late... +#include +#include +#include +#include +#include +#include +#include +#include + +// hack for MSVC6.0 compiler +#ifdef _MSC_VER +#if _MSC_VER < 1300 +#define for if(false); else for +#define map std::map +#define vector std::vector +#define string std::string +// use this define for MSVC6 stuff hereafter +#define USE_MSVC6FIXES +#else // _MSC_VER < 1300 , 7.0 or higher +using std::map; +using std::vector; +using std::string; +#endif +#else // not MSVC6 +// for proper compilers... +using std::map; +using std::vector; +using std::string; +#endif // MSVC6 + +#ifdef __APPLE_CC__ +// apple +#else +#ifdef WIN32 + +// windows values missing, see below +#ifndef snprintf +#define snprintf _snprintf +#endif +#ifndef bool +#define bool int +#endif +#ifndef false +#define false 0 +#endif +#ifndef true +#define true 1 +#endif + +#else // WIN32 + +// floating point limits for linux,*bsd etc... +#include + +#endif // WIN32 +#endif // __APPLE_CC__ + +// windos, hardcoded limits for now... +// for e.g. MSVC compiler... +// some of these defines can be needed +// for linux systems as well (e.g. FLT_MAX) +#ifndef __FLT_MAX__ +# ifdef FLT_MAX // try to use it instead +# define __FLT_MAX__ FLT_MAX +# else // FLT_MAX +# define __FLT_MAX__ 3.402823466e+38f +# endif // FLT_MAX +#endif // __FLT_MAX__ +#ifndef __DBL_MAX__ +# ifdef DBL_MAX // try to use it instead +# define __DBL_MAX__ DBL_MAX +# else // DBL_MAX +# define __DBL_MAX__ 1.7976931348623158e+308 +# endif // DBL_MAX +#endif // __DBL_MAX__ + +#ifndef M_PI +#define M_PI 3.1415926536 +#define M_E 2.7182818284 +#endif + +// make sure elbeem plugin def is valid +#if ELBEEM_BLENDER==1 +#ifndef ELBEEM_PLUGIN +#define ELBEEM_PLUGIN 1 +#endif // !ELBEEM_PLUGIN +#endif // ELBEEM_BLENDER==1 + +// make sure GUI support is disabled for plugin use +#if ELBEEM_PLUGIN==1 +#ifndef NOGUI +#define NOGUI 1 +#endif // !NOGUI +#endif // ELBEEM_PLUGIN==1 + + +// basic inlined vector class +template +class ntlVector3Dim +{ +public: + // Constructor + inline ntlVector3Dim(void ); + // Copy-Constructor + inline ntlVector3Dim(const ntlVector3Dim &v ); + inline ntlVector3Dim(const float *); + inline ntlVector3Dim(const double *); + // construct a vector from one Scalar + inline ntlVector3Dim(Scalar); + // construct a vector from three Scalars + inline ntlVector3Dim(Scalar, Scalar, Scalar); + + // get address of array for OpenGL + Scalar *getAddress() { return value; } + + // Assignment operator + inline const ntlVector3Dim& operator= (const ntlVector3Dim& v); + // Assignment operator + inline const ntlVector3Dim& operator= (Scalar s); + // Assign and add operator + inline const ntlVector3Dim& operator+= (const ntlVector3Dim& v); + // Assign and add operator + inline const ntlVector3Dim& operator+= (Scalar s); + // Assign and sub operator + inline const ntlVector3Dim& operator-= (const ntlVector3Dim& v); + // Assign and sub operator + inline const ntlVector3Dim& operator-= (Scalar s); + // Assign and mult operator + inline const ntlVector3Dim& operator*= (const ntlVector3Dim& v); + // Assign and mult operator + inline const ntlVector3Dim& operator*= (Scalar s); + // Assign and div operator + inline const ntlVector3Dim& operator/= (const ntlVector3Dim& v); + // Assign and div operator + inline const ntlVector3Dim& operator/= (Scalar s); + + + // unary operator + inline ntlVector3Dim operator- () const; + + // binary operator add + inline ntlVector3Dim operator+ (const ntlVector3Dim&) const; + // binary operator add + inline ntlVector3Dim operator+ (Scalar) const; + // binary operator sub + inline ntlVector3Dim operator- (const ntlVector3Dim&) const; + // binary operator sub + inline ntlVector3Dim operator- (Scalar) const; + // binary operator mult + inline ntlVector3Dim operator* (const ntlVector3Dim&) const; + // binary operator mult + inline ntlVector3Dim operator* (Scalar) const; + // binary operator div + inline ntlVector3Dim operator/ (const ntlVector3Dim&) const; + // binary operator div + inline ntlVector3Dim operator/ (Scalar) const; + + // Projection normal to a vector + inline ntlVector3Dim getOrthogonalntlVector3Dim() const; + // Project into a plane + inline const ntlVector3Dim& projectNormalTo(const ntlVector3Dim &v); + + // minimize + inline const ntlVector3Dim &minimize(const ntlVector3Dim &); + // maximize + inline const ntlVector3Dim &maximize(const ntlVector3Dim &); + + // access operator + inline Scalar& operator[](unsigned int i); + // access operator + inline const Scalar& operator[](unsigned int i) const; + +protected: + +private: + Scalar value[3]; //< Storage of vector values +}; + + + + +//------------------------------------------------------------------------------ +// STREAM FUNCTIONS +//------------------------------------------------------------------------------ + + + +//! global string for formatting vector output in utilities.cpp +extern const char *globVecFormatStr; + +/************************************************************************* + Outputs the object in human readable form using the format + [x,y,z] + */ +template +std::ostream& +operator<<( std::ostream& os, const ntlVector3Dim& i ) +{ + char buf[256]; + snprintf(buf,256,globVecFormatStr,i[0],i[1],i[2]); + os << string(buf); + //os << '[' << i[0] << ", " << i[1] << ", " << i[2] << ']'; + return os; +} + + + +/************************************************************************* + Reads the contents of the object from a stream using the same format + as the output operator. + */ +template +std::istream& +operator>>( std::istream& is, ntlVector3Dim& i ) +{ + char c; + char dummy[3]; + is >> c >> i[0] >> dummy >> i[1] >> dummy >> i[2] >> c; + return is; +} + + +//------------------------------------------------------------------------------ +// VECTOR inline FUNCTIONS +//------------------------------------------------------------------------------ + + + +/************************************************************************* + Constructor. + */ +template +inline ntlVector3Dim::ntlVector3Dim( void ) +{ + value[0] = value[1] = value[2] = 0; +} + + + +/************************************************************************* + Copy-Constructor. + */ +template +inline ntlVector3Dim::ntlVector3Dim( const ntlVector3Dim &v ) +{ + value[0] = v.value[0]; + value[1] = v.value[1]; + value[2] = v.value[2]; +} +template +inline ntlVector3Dim::ntlVector3Dim( const float *fvalue) +{ + value[0] = (Scalar)fvalue[0]; + value[1] = (Scalar)fvalue[1]; + value[2] = (Scalar)fvalue[2]; +} +template +inline ntlVector3Dim::ntlVector3Dim( const double *fvalue) +{ + value[0] = (Scalar)fvalue[0]; + value[1] = (Scalar)fvalue[1]; + value[2] = (Scalar)fvalue[2]; +} + + + +/************************************************************************* + Constructor for a vector from a single Scalar. All components of + the vector get the same value. + \param s The value to set + \return The new vector + */ +template +inline ntlVector3Dim::ntlVector3Dim(Scalar s ) +{ + value[0]= s; + value[1]= s; + value[2]= s; +} + + +/************************************************************************* + Constructor for a vector from three Scalars. + \param s1 The value for the first vector component + \param s2 The value for the second vector component + \param s3 The value for the third vector component + \return The new vector + */ +template +inline ntlVector3Dim::ntlVector3Dim(Scalar s1, Scalar s2, Scalar s3) +{ + value[0]= s1; + value[1]= s2; + value[2]= s3; +} + + +/************************************************************************* + Compute the vector product of two 3D vectors + \param v Second vector to compute the product with + \return A new vector with the product values + */ +/*template +inline ntlVector3Dim +ntlVector3Dim::operator^( const ntlVector3Dim &v ) const +{ + return ntlVector3Dim(value[1]*v.value[2] - value[2]*v.value[1], + value[2]*v.value[0] - value[0]*v.value[2], + value[0]*v.value[1] - value[1]*v.value[0]); +}*/ + + +/************************************************************************* + Copy a ntlVector3Dim componentwise. + \param v vector with values to be copied + \return Reference to self + */ +template +inline const ntlVector3Dim& +ntlVector3Dim::operator=( const ntlVector3Dim &v ) +{ + value[0] = v.value[0]; + value[1] = v.value[1]; + value[2] = v.value[2]; + return *this; +} + + +/************************************************************************* + Copy a Scalar to each component. + \param s The value to copy + \return Reference to self + */ +template +inline const ntlVector3Dim& +ntlVector3Dim::operator=(Scalar s) +{ + value[0] = s; + value[1] = s; + value[2] = s; + return *this; +} + + +/************************************************************************* + Add another ntlVector3Dim componentwise. + \param v vector with values to be added + \return Reference to self + */ +template +inline const ntlVector3Dim& +ntlVector3Dim::operator+=( const ntlVector3Dim &v ) +{ + value[0] += v.value[0]; + value[1] += v.value[1]; + value[2] += v.value[2]; + return *this; +} + + +/************************************************************************* + Add a Scalar value to each component. + \param s Value to add + \return Reference to self + */ +template +inline const ntlVector3Dim& +ntlVector3Dim::operator+=(Scalar s) +{ + value[0] += s; + value[1] += s; + value[2] += s; + return *this; +} + + +/************************************************************************* + Subtract another vector componentwise. + \param v vector of values to subtract + \return Reference to self + */ +template +inline const ntlVector3Dim& +ntlVector3Dim::operator-=( const ntlVector3Dim &v ) +{ + value[0] -= v.value[0]; + value[1] -= v.value[1]; + value[2] -= v.value[2]; + return *this; +} + + +/************************************************************************* + Subtract a Scalar value from each component. + \param s Value to subtract + \return Reference to self + */ +template +inline const ntlVector3Dim& +ntlVector3Dim::operator-=(Scalar s) +{ + value[0]-= s; + value[1]-= s; + value[2]-= s; + return *this; +} + + +/************************************************************************* + Multiply with another vector componentwise. + \param v vector of values to multiply with + \return Reference to self + */ +template +inline const ntlVector3Dim& +ntlVector3Dim::operator*=( const ntlVector3Dim &v ) +{ + value[0] *= v.value[0]; + value[1] *= v.value[1]; + value[2] *= v.value[2]; + return *this; +} + + +/************************************************************************* + Multiply each component with a Scalar value. + \param s Value to multiply with + \return Reference to self + */ +template +inline const ntlVector3Dim& +ntlVector3Dim::operator*=(Scalar s) +{ + value[0] *= s; + value[1] *= s; + value[2] *= s; + return *this; +} + + +/************************************************************************* + Divide by another ntlVector3Dim componentwise. + \param v vector of values to divide by + \return Reference to self + */ +template +inline const ntlVector3Dim& +ntlVector3Dim::operator/=( const ntlVector3Dim &v ) +{ + value[0] /= v.value[0]; + value[1] /= v.value[1]; + value[2] /= v.value[2]; + return *this; +} + + +/************************************************************************* + Divide each component by a Scalar value. + \param s Value to divide by + \return Reference to self + */ +template +inline const ntlVector3Dim& +ntlVector3Dim::operator/=(Scalar s) +{ + value[0] /= s; + value[1] /= s; + value[2] /= s; + return *this; +} + + +//------------------------------------------------------------------------------ +// unary operators +//------------------------------------------------------------------------------ + + +/************************************************************************* + Build componentwise the negative this vector. + \return The new (negative) vector + */ +template +inline ntlVector3Dim +ntlVector3Dim::operator-() const +{ + return ntlVector3Dim(-value[0], -value[1], -value[2]); +} + + + +//------------------------------------------------------------------------------ +// binary operators +//------------------------------------------------------------------------------ + + +/************************************************************************* + Build a vector with another vector added componentwise. + \param v The second vector to add + \return The sum vector + */ +template +inline ntlVector3Dim +ntlVector3Dim::operator+( const ntlVector3Dim &v ) const +{ + return ntlVector3Dim(value[0]+v.value[0], + value[1]+v.value[1], + value[2]+v.value[2]); +} + + +/************************************************************************* + Build a vector with a Scalar value added to each component. + \param s The Scalar value to add + \return The sum vector + */ +template +inline ntlVector3Dim +ntlVector3Dim::operator+(Scalar s) const +{ + return ntlVector3Dim(value[0]+s, + value[1]+s, + value[2]+s); +} + + +/************************************************************************* + Build a vector with another vector subtracted componentwise. + \param v The second vector to subtract + \return The difference vector + */ +template +inline ntlVector3Dim +ntlVector3Dim::operator-( const ntlVector3Dim &v ) const +{ + return ntlVector3Dim(value[0]-v.value[0], + value[1]-v.value[1], + value[2]-v.value[2]); +} + + +/************************************************************************* + Build a vector with a Scalar value subtracted componentwise. + \param s The Scalar value to subtract + \return The difference vector + */ +template +inline ntlVector3Dim +ntlVector3Dim::operator-(Scalar s ) const +{ + return ntlVector3Dim(value[0]-s, + value[1]-s, + value[2]-s); +} + + + +/************************************************************************* + Build a vector with another vector multiplied by componentwise. + \param v The second vector to muliply with + \return The product vector + */ +template +inline ntlVector3Dim +ntlVector3Dim::operator*( const ntlVector3Dim& v) const +{ + return ntlVector3Dim(value[0]*v.value[0], + value[1]*v.value[1], + value[2]*v.value[2]); +} + + +/************************************************************************* + Build a ntlVector3Dim with a Scalar value multiplied to each component. + \param s The Scalar value to multiply with + \return The product vector + */ +template +inline ntlVector3Dim +ntlVector3Dim::operator*(Scalar s) const +{ + return ntlVector3Dim(value[0]*s, value[1]*s, value[2]*s); +} + + +/************************************************************************* + Build a vector divided componentwise by another vector. + \param v The second vector to divide by + \return The ratio vector + */ +template +inline ntlVector3Dim +ntlVector3Dim::operator/(const ntlVector3Dim& v) const +{ + return ntlVector3Dim(value[0]/v.value[0], + value[1]/v.value[1], + value[2]/v.value[2]); +} + + + +/************************************************************************* + Build a vector divided componentwise by a Scalar value. + \param s The Scalar value to divide by + \return The ratio vector + */ +template +inline ntlVector3Dim +ntlVector3Dim::operator/(Scalar s) const +{ + return ntlVector3Dim(value[0]/s, + value[1]/s, + value[2]/s); +} + + + + + +/************************************************************************* + Get a particular component of the vector. + \param i Number of Scalar to get + \return Reference to the component + */ +template +inline Scalar& +ntlVector3Dim::operator[]( unsigned int i ) +{ + return value[i]; +} + + +/************************************************************************* + Get a particular component of a constant vector. + \param i Number of Scalar to get + \return Reference to the component + */ +template +inline const Scalar& +ntlVector3Dim::operator[]( unsigned int i ) const +{ + return value[i]; +} + + + +//------------------------------------------------------------------------------ +// BLITZ compatibility functions +//------------------------------------------------------------------------------ + + + +/************************************************************************* + Compute the scalar product with another vector. + \param v The second vector to work with + \return The value of the scalar product + */ +template +inline Scalar dot(const ntlVector3Dim &t, const ntlVector3Dim &v ) +{ + //return t.value[0]*v.value[0] + t.value[1]*v.value[1] + t.value[2]*v.value[2]; + return ((t[0]*v[0]) + (t[1]*v[1]) + (t[2]*v[2])); +} + + +/************************************************************************* + Calculate the cross product of this and another vector + */ +template +inline ntlVector3Dim cross(const ntlVector3Dim &t, const ntlVector3Dim &v) +{ + ntlVector3Dim cp( + ((t[1]*v[2]) - (t[2]*v[1])), + ((t[2]*v[0]) - (t[0]*v[2])), + ((t[0]*v[1]) - (t[1]*v[0])) ); + return cp; +} + + + + +/************************************************************************* + Compute a vector that is orthonormal to self. Nothing else can be assumed + for the direction of the new vector. + \return The orthonormal vector + */ +template +ntlVector3Dim +ntlVector3Dim::getOrthogonalntlVector3Dim() const +{ + // Determine the component with max. absolute value + int max= (fabs(value[0]) > fabs(value[1])) ? 0 : 1; + max= (fabs(value[max]) > fabs(value[2])) ? max : 2; + + /************************************************************************* + Choose another axis than the one with max. component and project + orthogonal to self + */ + ntlVector3Dim vec(0.0); + vec[(max+1)%3]= 1; + vec.normalize(); + vec.projectNormalTo(this->getNormalized()); + return vec; +} + + +/************************************************************************* + Projects the vector into a plane normal to the given vector, which must + have unit length. Self is modified. + \param v The plane normal + \return The projected vector + */ +template +inline const ntlVector3Dim& +ntlVector3Dim::projectNormalTo(const ntlVector3Dim &v) +{ + Scalar sprod = dot(*this,v); + value[0]= value[0] - v.value[0] * sprod; + value[1]= value[1] - v.value[1] * sprod; + value[2]= value[2] - v.value[2] * sprod; + return *this; +} + + + +//------------------------------------------------------------------------------ +// Other helper functions +//------------------------------------------------------------------------------ + + + +/************************************************************************* + Minimize the vector, i.e. set each entry of the vector to the minimum + of both values. + \param pnt The second vector to compare with + \return Reference to the modified self + */ +template +inline const ntlVector3Dim & +ntlVector3Dim::minimize(const ntlVector3Dim &pnt) +{ + for (unsigned int i = 0; i < 3; i++) + value[i] = MIN(value[i],pnt[i]); + return *this; +} + + + +/************************************************************************* + Maximize the vector, i.e. set each entry of the vector to the maximum + of both values. + \param pnt The second vector to compare with + \return Reference to the modified self + */ +template +inline const ntlVector3Dim & +ntlVector3Dim::maximize(const ntlVector3Dim &pnt) +{ + for (unsigned int i = 0; i < 3; i++) + value[i] = MAX(value[i],pnt[i]); + return *this; +} + + + + +// ---- + +// a 3D vector with double precision +typedef ntlVector3Dim ntlVec3d; + +// a 3D vector with single precision +typedef ntlVector3Dim ntlVec3f; + +// a 3D integer vector +typedef ntlVector3Dim ntlVec3i; + +// Color uses single precision fp values +typedef ntlVec3f ntlColor; + +/* convert a float to double vector */ +template inline ntlVec3d vec2D(T v) { return ntlVec3d(v[0],v[1],v[2]); } +template inline ntlVec3f vec2F(T v) { return ntlVec3f(v[0],v[1],v[2]); } +template inline ntlColor vec2Col(T v) { return ntlColor(v[0],v[1],v[2]); } + + + +/************************************************************************/ +// graphics vector typing + + +// use which fp-precision for raytracing? 1=float, 2=double + +/* VECTOR_EPSILON is the minimal vector length + In order to be able to discriminate floating point values near zero, and + to be sure not to fail a comparison because of roundoff errors, use this + value as a threshold. */ + +// use which fp-precision for graphics? 1=float, 2=double +#ifdef PRECISION_GFX_SINGLE +#define GFX_PRECISION 1 +#else +#ifdef PRECISION_GFX_DOUBLE +#define GFX_PRECISION 2 +#else +// standard precision for graphics +#ifndef GFX_PRECISION +#define GFX_PRECISION 1 +#endif +#endif +#endif + +#if GFX_PRECISION==1 +typedef float gfxReal; +#define GFX_REAL_MAX __FLT_MAX__ +//#define vecF2Gfx(x) (x) +//#define vecGfx2F(x) (x) +//#define vecD2Gfx(x) vecD2F(x) +//#define vecGfx2D(x) vecF2D(x) +#define VECTOR_EPSILON (1e-5f) +#else +typedef double gfxReal; +#define GFX_REAL_MAX __DBL_MAX__ +//#define vecF2Gfx(x) vecD2F(x) +//#define vecGfx2F(x) vecF2D(x) +//#define vecD2Gfx(x) (x) +//#define vecGfx2D(x) (x) +#define VECTOR_EPSILON (1e-10) +#endif + +/* fixed double prec. type, for epxlicitly double values */ +typedef double gfxDouble; + +// a 3D vector for graphics output, typically float? +typedef ntlVector3Dim ntlVec3Gfx; + +template inline ntlVec3Gfx vec2G(T v) { return ntlVec3Gfx(v[0],v[1],v[2]); } + +/* get minimal vector length value that can be discriminated. */ +//inline double getVecEpsilon() { return (double)VECTOR_EPSILON; } +inline gfxReal getVecEpsilon() { return (gfxReal)VECTOR_EPSILON; } + +#define HAVE_GFXTYPES + + + + +/************************************************************************/ +// HELPER FUNCTIONS, independent of implementation +/************************************************************************/ + +#define VECTOR_TYPE ntlVector3Dim + + +/************************************************************************* + Compute the length (norm) of the vector. + \return The value of the norm + */ +template +inline Scalar norm( const VECTOR_TYPE &v) +{ + Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; + return (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON) ? 1. : sqrt(l); +} + + +/************************************************************************* + Same as getNorm but doesnt sqrt + */ +template +inline Scalar normNoSqrt( const VECTOR_TYPE &v) +{ + return v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; +} + + +/************************************************************************* + Compute a normalized vector based on this vector. + \return The new normalized vector + */ +template +inline VECTOR_TYPE getNormalized( const VECTOR_TYPE &v) +{ + Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; + if (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON) + return v; /* normalized "enough"... */ + else if (l > VECTOR_EPSILON*VECTOR_EPSILON) + { + Scalar fac = 1./sqrt(l); + return VECTOR_TYPE(v[0]*fac, v[1]*fac, v[2]*fac); + } + else + return VECTOR_TYPE((Scalar)0); +} + + +/************************************************************************* + Compute the norm of the vector and normalize it. + \return The value of the norm + */ +template +inline Scalar normalize( VECTOR_TYPE &v) +{ + Scalar norm; + Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; + if (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON) { + norm = 1.; + } else if (l > VECTOR_EPSILON*VECTOR_EPSILON) { + norm = sqrt(l); + Scalar fac = 1./norm; + v[0] *= fac; + v[1] *= fac; + v[2] *= fac; + } else { + v[0]= v[1]= v[2]= 0; + norm = 0.; + } + return (Scalar)norm; +} + + +/************************************************************************* + Compute a vector, that is self (as an incoming + vector) reflected at a surface with a distinct normal vector. Note + that the normal is reversed, if the scalar product with it is positive. + \param n The surface normal + \return The new reflected vector + */ +template +inline VECTOR_TYPE reflectVector(const VECTOR_TYPE &t, const VECTOR_TYPE &n) +{ + VECTOR_TYPE nn= (dot(t, n) > 0.0) ? (n*-1.0) : n; + return ( t - nn * (2.0 * dot(nn, t)) ); +} + + + +/************************************************************************* + * My own refraction calculation + * Taken from Glassner's book, section 5.2 (Heckberts method) + */ +template +inline VECTOR_TYPE refractVector(const VECTOR_TYPE &t, const VECTOR_TYPE &normal, Scalar nt, Scalar nair, int &refRefl) +{ + Scalar eta = nair / nt; + Scalar n = -dot(t, normal); + Scalar tt = 1.0 + eta*eta* (n*n-1.0); + if(tt<0.0) { + // we have total reflection! + refRefl = 1; + } else { + // normal reflection + tt = eta*n - sqrt(tt); + return( t*eta + normal*tt ); + } + return t; +} + /*double eta = nair / nt; + double n = -((*this) | normal); + double t = 1.0 + eta*eta* (n*n-1.0); + if(t<0.0) { + // we have total reflection! + refRefl = 1; + } else { + // normal reflection + t = eta*n - sqrt(t); + return( (*this)*eta + normal*t ); + } + return (*this);*/ + + +/************************************************************************* + Test two ntlVector3Dims for equality based on the equality of their + values within a small threshold. + \param c The second vector to compare + \return TRUE if both are equal + \sa getEpsilon() + */ +template +inline bool equal(const VECTOR_TYPE &v, const VECTOR_TYPE &c) +{ + return (ABS(v[0]-c[0]) + + ABS(v[1]-c[1]) + + ABS(v[2]-c[2]) < VECTOR_EPSILON); +} + + +/************************************************************************* + * Assume this vector is an RGB color, and convert it to HSV + */ +template +inline void rgbToHsv( VECTOR_TYPE &V ) +{ + Scalar h=0,s=0,v=0; + Scalar maxrgb, minrgb, delta; + // convert to hsv... + maxrgb = V[0]; + int maxindex = 1; + if(V[2] > maxrgb){ maxrgb = V[2]; maxindex = 2; } + if(V[1] > maxrgb){ maxrgb = V[1]; maxindex = 3; } + minrgb = V[0]; + if(V[2] < minrgb) minrgb = V[2]; + if(V[1] < minrgb) minrgb = V[1]; + + v = maxrgb; + delta = maxrgb-minrgb; + + if(maxrgb > 0) s = delta/maxrgb; + else s = 0; + + h = 0; + if(s > 0) { + if(maxindex == 1) { + h = ((V[1]-V[2])/delta) + 0.0; } + if(maxindex == 2) { + h = ((V[2]-V[0])/delta) + 2.0; } + if(maxindex == 3) { + h = ((V[0]-V[1])/delta) + 4.0; } + h *= 60.0; + if(h < 0.0) h += 360.0; + } + + V[0] = h; + V[1] = s; + V[2] = v; +} + +/************************************************************************* + * Assume this vector is HSV and convert to RGB + */ +template +inline void hsvToRgb( VECTOR_TYPE &V ) +{ + Scalar h = V[0], s = V[1], v = V[2]; + Scalar r=0,g=0,b=0; + Scalar p,q,t, fracth; + int floorh; + // ...and back to rgb + if(s == 0) { + r = g = b = v; } + else { + h /= 60.0; + floorh = (int)h; + fracth = h - floorh; + p = v * (1.0 - s); + q = v * (1.0 - (s * fracth)); + t = v * (1.0 - (s * (1.0 - fracth))); + switch (floorh) { + case 0: r = v; g = t; b = p; break; + case 1: r = q; g = v; b = p; break; + case 2: r = p; g = v; b = t; break; + case 3: r = p; g = q; b = v; break; + case 4: r = t; g = p; b = v; break; + case 5: r = v; g = p; b = q; break; + } + } + + V[0] = r; + V[1] = g; + V[2] = b; +} + + + + +#endif /* NTL_VECTOR3DIM_HH */ diff --git a/intern/elbeem/intern/ntl_world.cpp b/intern/elbeem/intern/ntl_world.cpp new file mode 100644 index 00000000000..21d9d63aac0 --- /dev/null +++ b/intern/elbeem/intern/ntl_world.cpp @@ -0,0 +1,910 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Main renderer class + * + *****************************************************************************/ + + +#include +#include +#include "utilities.h" +#include "ntl_world.h" +#include "parametrizer.h" + +// for non-threaded renderViz +#ifndef NOGUI +#include "../gui/ntl_openglrenderer.h" +#include "../gui/guifuncs.h" +#include "../gui/frame.h" +#endif + + +/* external parser functions from cfgparser.cxx */ +#ifndef ELBEEM_PLUGIN +/* parse given file as config file */ +void parseFile(string filename); +/* set pointers for parsing */ +void setPointers( ntlRenderGlobals *setglob); +#endif // ELBEEM_PLUGIN + + +/****************************************************************************** + * Constructor + *****************************************************************************/ + +ntlWorld::ntlWorld() { + initDefaults(); +} + +ntlWorld::ntlWorld(string filename, bool commandlineMode) +{ +#ifndef ELBEEM_PLUGIN + + initDefaults(); +# ifdef NOGUI + commandlineMode = true; // remove warning... +# endif // NOGUI + + // load config + setPointers( getRenderGlobals() ); + parseFile( filename.c_str() ); +# ifndef NOGUI + // setup opengl display, save first animation step for start time + // init after parsing file... + if(!commandlineMode) { + mpOpenGLRenderer = new ntlOpenGLRenderer( mpGlob ); + } +# endif // NOGUI + finishWorldInit(); + +#else // ELBEEM_PLUGIN + errFatal("ntlWorld::init","Cfg file parsing not supported for API version! "<setName(string(simname)); + mpGlob->getSims()->push_back( sim ); + + // important - add to both, only render scene objects are free'd + mpGlob->getRenderScene()->addGeoClass( sim ); + mpGlob->getSimScene()->addGeoClass( sim ); + sim->setGeoStart(ntlVec3Gfx(settings->geoStart[0],settings->geoStart[1],settings->geoStart[2])); + sim->setGeoEnd(ntlVec3Gfx( + settings->geoStart[0]+settings->geoSize[0], + settings->geoStart[1]+settings->geoSize[1], + settings->geoStart[2]+settings->geoSize[2] )); + // further init in postGeoConstrInit/initializeLbmSimulation of SimulationObject + sim->copyElbeemSettings(settings); + + Parametrizer *param = sim->getParametrizer(); + param->setSize( settings->resolutionxyz ); + param->setDomainSize( settings->realsize ); + param->setAniStart( settings->animStart ); + param->setNormalizedGStar( settings->gstar ); + + // init domain channels + vector valf; + vector valv; + vector time; + +#define INIT_CHANNEL_FLOAT(channel,size) \ + valf.clear(); time.clear(); elbeemSimplifyChannelFloat(channel,&size); \ + for(int i=0; isetViscosity( settings->viscosity ); + if((settings->channelViscosity)&&(settings->channelSizeViscosity>0)) { + INIT_CHANNEL_FLOAT(settings->channelViscosity, settings->channelSizeViscosity); + param->initViscosityChannel(valf,time); } + + param->setGravity( ParamVec(settings->gravity[0], settings->gravity[1], settings->gravity[2]) ); + if((settings->channelGravity)&&(settings->channelSizeGravity>0)) { + INIT_CHANNEL_VEC(settings->channelGravity, settings->channelSizeGravity); + param->initGravityChannel(valv,time); } + + param->setAniFrameTimeChannel( settings->aniFrameTime ); + if((settings->channelFrameTime)&&(settings->channelSizeFrameTime>0)) { + INIT_CHANNEL_FLOAT(settings->channelFrameTime, settings->channelSizeFrameTime); + param->initAniFrameTimeChannel(valf,time); } + +#undef INIT_CHANNEL_FLOAT +#undef INIT_CHANNEL_VEC + + // might be set by previous domain + if(mpGlob->getAniFrames() < settings->noOfFrames) mpGlob->setAniFrames( settings->noOfFrames ); + // set additionally to SimulationObject->mOutFilename + mpGlob->setOutFilename( settings->outputPath ); + + return 0; +} + +void ntlWorld::initDefaults() +{ + mStopRenderVisualization = false; + mThreadRunning = false; + mSimulationTime = 0.0; + mFirstSim = 1; + mSingleStepDebug = false; + mFrameCnt = 0; + mpOpenGLRenderer = NULL; + + /* create scene storage */ + mpGlob = new ntlRenderGlobals(); + mpLightList = new vector; + mpPropList = new vector; + mpSims = new vector; + + mpGlob->setLightList(mpLightList); + mpGlob->setMaterials(mpPropList); + mpGlob->setSims(mpSims); + + /* init default material */ + ntlMaterial *def = GET_GLOBAL_DEFAULT_MATERIAL; + mpPropList->push_back( def ); + + /* init the scene object */ + ntlScene *renderscene = new ntlScene( mpGlob, true ); + mpGlob->setRenderScene( renderscene ); + // sim scene shouldnt delete objs, may only contain subset + ntlScene *simscene = new ntlScene( mpGlob, false ); + mpGlob->setSimScene( simscene ); +} + +void ntlWorld::finishWorldInit() +{ + if(! isSimworldOk() ) return; + + // init the scene for the first time + long sstartTime = getTime(); + + // first init sim scene for geo setup + mpGlob->getSimScene()->buildScene(0.0, true); + if(! isSimworldOk() ) return; + mpGlob->getRenderScene()->buildScene(0.0, true); + if(! isSimworldOk() ) return; + long sstopTime = getTime(); + debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Scene build time: "<< getTimeString(sstopTime-sstartTime) <<" ", 10); + + // TODO check simulations, run first steps + mFirstSim = -1; + if(mpSims->size() > 0) { + + // use values from first simulation as master time scale + long startTime = getTime(); + + // remember first active sim + for(size_t i=0;isize();i++) { + if(!(*mpSims)[i]->getVisible()) continue; + if((*mpSims)[i]->getPanic()) continue; + + // check largest timestep + if(mFirstSim>=0) { + if( (*mpSims)[i]->getTimestep() > (*mpSims)[mFirstSim]->getTimestep() ) { + mFirstSim = i; + debMsgStd("ntlWorld::ntlWorld",DM_MSG,"First Sim changed: "<=0) { + debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Anistart Time: "<<(*mpSims)[mFirstSim]->getStartTime() ,10); + while(mSimulationTime < (*mpSims)[mFirstSim]->getStartTime() ) { + debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Anistart Time: "<<(*mpSims)[mFirstSim]->getStartTime()<<" simtime:"<getStartTime(); + debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Time for start-sims:"<< getTimeString(stopTime-startTime) , 1); +#ifndef NOGUI + guiResetSimulationTimeRange( mSimulationTime ); +#endif + } else { + if(!mpGlob->getSingleFrameMode()) debMsgStd("ntlWorld::ntlWorld",DM_WARNING,"No active simulations!", 1); + } + } + + if(! isSimworldOk() ) return; + setElbeemState( SIMWORLD_INITED ); +} + + + +/****************************************************************************** + * Destructor + *****************************************************************************/ +ntlWorld::~ntlWorld() +{ + delete mpGlob->getRenderScene(); + delete mpGlob->getSimScene(); + delete mpGlob; + delete mpLightList; + delete mpPropList; + delete mpSims; +#ifndef NOGUI + if(mpOpenGLRenderer) delete mpOpenGLRenderer; +#endif // NOGUI + debMsgStd("ntlWorld",DM_NOTIFY, "ntlWorld done", 10); +} + +/******************************************************************************/ +/*! set single frame rendering to filename */ +void ntlWorld::setSingleFrameOut(string singleframeFilename) { + mpGlob->setSingleFrameMode(true); + mpGlob->setSingleFrameFilename(singleframeFilename); +} + +/****************************************************************************** + * render a whole animation (command line mode) + *****************************************************************************/ + +int ntlWorld::renderAnimation( void ) +{ + // only single pic currently + //debMsgStd("ntlWorld::renderAnimation : Warning only simulating...",1); + if(mpGlob->getAniFrames() < 0) { + debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"No frames to render... ",1); + return 1; + } + + if(mFirstSim<0) { + debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"No reference animation found...",1); + return 1; + } + + mThreadRunning = true; // not threaded, but still use the same flags + if(getElbeemState() == SIMWORLD_INITED) { + renderScene(); + } else if(getElbeemState() == SIMWORLD_STOP) { + // dont render now, just continue + setElbeemState( SIMWORLD_INITED ); + mFrameCnt--; // counted one too many from last abort... + } else { + debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"Not properly inited, stopping...",1); + return 1; + } + + if(mpSims->size() <= 0) { + debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"No simulations found, stopping...",1); + return 1; + } + + bool simok = true; + for( ; ((mFrameCntgetAniFrames()) && (!getStopRenderVisualization() ) && (simok)); mFrameCnt++) { + if(!advanceSims(mFrameCnt)) { + renderScene(); + } // else means sim panicked, so dont render... + else { simok=false; } + } + mThreadRunning = false; + return 0; +} + +/****************************************************************************** + * render a whole animation (visualization mode) + * this function is run in another thread, and communicates + * with the parent thread via a mutex + *****************************************************************************/ +int ntlWorld::renderVisualization( bool multiThreaded ) +{ +#ifndef NOGUI + if(getElbeemState() != SIMWORLD_INITED) { return 0; } + + if(multiThreaded) mThreadRunning = true; + // TODO, check global state? + while(!getStopRenderVisualization()) { + + if(mpSims->size() <= 0) { + debMsgStd("ntlWorld::renderVisualization",DM_NOTIFY,"No simulations found, stopping...",1); + stopSimulationThread(); + break; + } + + // determine stepsize + if(!mSingleStepDebug) { + long startTime = getTime(); + advanceSims(mFrameCnt); + mFrameCnt++; + long stopTime = getTime(); + debMsgStd("ntlWorld::renderVisualization",DM_MSG,"Time for t="<getTimestep(); + singleStepSims(targetTime); + + // check paniced sims (normally done by advanceSims + bool allPanic = true; + for(size_t i=0;isize();i++) { + if(!(*mpSims)[i]->getPanic()) allPanic = false; + } + if(allPanic) { + warnMsg("ntlWorld::advanceSims","All sims panicked... stopping thread" ); + setStopRenderVisualization( true ); + } + if(! isSimworldOk() ) { + warnMsg("ntlWorld::advanceSims","World state error... stopping" ); + setStopRenderVisualization( true ); + } + } + + // save frame + if(mpOpenGLRenderer) mpOpenGLRenderer->saveAnimationFrame( mSimulationTime ); + + // for non-threaded check events + if(!multiThreaded) { + Fl::check(); + gpElbeemFrame->SceneDisplay->doOnlyForcedRedraw(); + } + + } + mThreadRunning = false; + stopSimulationRestoreGui(); +#else + multiThreaded = false; // remove warning +#endif + return 0; +} +/*! render a single step for viz mode */ +int ntlWorld::singleStepVisualization( void ) +{ + mThreadRunning = true; + double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getTimestep(); + singleStepSims(targetTime); + mSimulationTime = (*mpSims)[0]->getCurrentTime(); + +#ifndef NOGUI + if(mpOpenGLRenderer) mpOpenGLRenderer->saveAnimationFrame( mSimulationTime ); + Fl::check(); + gpElbeemFrame->SceneDisplay->doOnlyForcedRedraw(); + mThreadRunning = false; + stopSimulationRestoreGui(); +#else + mThreadRunning = false; +#endif // NOGUI + return 0; +} + +// dont use LBM_EPSILON here, time is always double-precision! +#define LBM_TIME_EPSILON 1e-10 + +/****************************************************************************** + * advance simulations by time t + *****************************************************************************/ +int ntlWorld::advanceSims(int framenum) +{ + bool done = false; + bool allPanic = true; + + // stop/quit, dont display/render + if(getElbeemState()==SIMWORLD_STOP) { + return 1; + } + + for(size_t i=0;isize();i++) { (*mpSims)[i]->setFrameNum(framenum); } + double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getFrameTime(framenum); + + // time stopped? nothing else to do... + if( (*mpSims)[mFirstSim]->getFrameTime(framenum) <= 0.0 ){ + done=true; allPanic=false; + } + + int gstate = 0; + myTime_t advsstart = getTime(); + + // step all the sims, and check for panic + debMsgStd("ntlWorld::advanceSims",DM_MSG, " sims "<size()<<" t"<getCurrentTime() + (*mpSims)[mFirstSim]->getTimestep(); + singleStepSims(nextTargetTime); + + // check target times + done = true; + allPanic = false; + + if((*mpSims)[mFirstSim]->getTimestep() <1e-9 ) { + // safety check, avoid timesteps that are too small + errMsg("ntlWorld::advanceSims","Invalid time step, causing panic! curr:"<<(*mpSims)[mFirstSim]->getCurrentTime()<<" next:"<getTimestep() ); + allPanic = true; + } else { + for(size_t i=0;isize();i++) { + if(!(*mpSims)[i]->getVisible()) continue; + if((*mpSims)[i]->getPanic()) allPanic = true; // do any panic now!? + debMsgStd("ntlWorld::advanceSims",DM_MSG, "Sim "<getCurrentTime()<<", nt:"<getPanic()<<", targett:"<getCurrentTime()) > LBM_TIME_EPSILON) done=false; + if(allPanic) done = true; + } + + if(allPanic) { + warnMsg("ntlWorld::advanceSims","All sims panicked... stopping thread" ); + setStopRenderVisualization( true ); + return 1; + } + + myTime_t advsend = getTime(); + debMsgStd("ntlWorld::advanceSims",DM_MSG,"Overall steps so far took:"<< getTimeString(advsend-advsstart)<<" for sim time "<size();i++) { + SimulationObject *sim = (*mpSims)[i]; + if(!sim->getVisible()) continue; + if(sim->getPanic()) continue; + sim->prepareVisualization(); + } + + return 0; +} + +/* advance simulations by a single step */ +/* dont check target time, if *targetTime==NULL */ +void ntlWorld::singleStepSims(double targetTime) { + const bool debugTime = false; + //double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getTimestep(); + if(debugTime) errMsg("ntlWorld::singleStepSims","Target time: "<size();i++) { + SimulationObject *sim = (*mpSims)[i]; + if(!sim->getVisible()) continue; + if(sim->getPanic()) continue; + bool done = false; + while(!done) { + // try to prevent round off errs + if(debugTime) errMsg("ntlWorld::singleStepSims","Test sim "<getCurrentTime()<<" target:"<getCurrentTime())<<" stept:"<getTimestep()<<" leps:"<getCurrentTime()) > LBM_TIME_EPSILON) { + if(debugTime) errMsg("ntlWorld::singleStepSims","Stepping sim "<getCurrentTime()); // timedebug + sim->step(); + } else { + done = true; + } + } + } + + mSimulationTime = (*mpSims)[mFirstSim]->getCurrentTime(); +#ifndef NOGUI + if(mpOpenGLRenderer) mpOpenGLRenderer->notifyOfNextStep(mSimulationTime); +#endif // NOGUI +} + + + +extern bool glob_mpactive; +extern int glob_mpindex; + +/****************************************************************************** + * Render the current scene + * uses the global variables from the parser + *****************************************************************************/ +int ntlWorld::renderScene( void ) +{ +#ifndef ELBEEM_PLUGIN + char nrStr[5]; // nr conversion + std::ostringstream outfn_conv(""); // converted ppm with other suffix + ntlRenderGlobals *glob; // storage for global rendering parameters + myTime_t timeStart,totalStart,timeEnd; // measure user running time + myTime_t rendStart,rendEnd; // measure user rendering time + glob = mpGlob; + + // deactivate for all with index!=0 + if((glob_mpactive)&&(glob_mpindex>0)) return(0); + + /* check if picture already exists... */ + if(!glob->getSingleFrameMode() ) { + snprintf(nrStr, 5, "%04d", glob->getAniCount() ); + + if(glob_mpactive) { + outfn_conv << glob->getOutFilename() <<"_"<getOutFilename() <<"_" << nrStr << ".png"; + } + + //if((mpGlob->getDisplayMode() == DM_RAY)&&(mpGlob->getFrameSkip())) { + if(mpGlob->getFrameSkip()) { + struct stat statBuf; + if(stat(outfn_conv.str().c_str(),&statBuf) == 0) { + errorOut("ntlWorld::renderscene Warning: file "<setAniCount( glob->getAniCount() +1 ); + return(2); + } + } // RAY mode + } else { + // single frame rendering, overwrite if necessary... + outfn_conv << glob->getSingleFrameFilename(); + } + + /* start program */ + timeStart = getTime(); + + /* build scene geometry, calls buildScene(t,false) */ + glob->getRenderScene()->prepareScene(mSimulationTime); + + /* start program */ + totalStart = getTime(); + + + /* view parameters are currently not animated */ + /* calculate rays through projection plane */ + ntlVec3Gfx direction = glob->getLookat() - glob->getEye(); + /* calculate width of screen using perpendicular triangle diven by + * viewing direction and screen plane */ + gfxReal screenWidth = norm(direction)*tan( (glob->getFovy()*0.5/180.0)*M_PI ); + + /* calculate vector orthogonal to up and viewing direction */ + ntlVec3Gfx upVec = glob->getUpVec(); + ntlVec3Gfx rightVec( cross(upVec,direction) ); + normalize(rightVec); + + /* calculate screen plane up vector, perpendicular to viewdir and right vec */ + upVec = ntlVec3Gfx( cross(rightVec,direction) ); + normalize(upVec); + + /* check if vectors are valid */ + if( (equal(upVec,ntlVec3Gfx(0.0))) || (equal(rightVec,ntlVec3Gfx(0.0))) ) { + errMsg("ntlWorld::renderScene","Invalid viewpoint vectors! up="<getLookat() + upVec*((2.0*scanline-Yres)/Yres) + - rightVec; + + /* loop over all pixels in line */ + for (int sx=0 ; sx < Xres ; ++sx) { + + if((sx==glob->getDebugPixelX())&&(scanline==(Yres-glob->getDebugPixelY()) )) { + // DEBUG!!! + glob->setDebugOut(10); + } else glob->setDebugOut(0); + + /* compute ray from eye through current pixel into scene... */ + ntlColor col; + if(aaDepth<0) { + ntlVec3Gfx dir(screenPos - glob->getEye()); + ntlRay the_ray(glob->getEye(), getNormalized(dir), 0, 1.0, glob ); + + /* ...and trace it */ + col = the_ray.shade(); + } else { + /* anti alias */ + int ai,aj; /* position in grid */ + int aOrg = sx*aaLength; /* grid offset x */ + int currStep = aaLength; /* step size */ + char colDiff = 1; /* do colors still differ too much? */ + ntlColor minCol,maxCol; /* minimum and maximum Color Values */ + minCol = ntlColor(1.0,1.0,1.0); + maxCol = ntlColor(0.0,0.0,0.0); + + while((colDiff) && (currStep>0)) { + colDiff = 0; + + for(aj = 0;aj<=aaLength;aj+= currStep) { + for(ai = 0;ai<=aaLength;ai+= currStep) { + + /* shade pixel if not done */ + if(aaUse[aj*aaArrayX +ai +aOrg] == 0) { + aaUse[aj*aaArrayX +ai +aOrg] = 1; + ntlVec3Gfx aaPos( screenPos + + (rightStep * (ai- aaLength/2)/(gfxReal)aaLength ) + + (upStep * (aj- aaLength/2)/(gfxReal)aaLength ) ); + + ntlVec3Gfx dir(aaPos - glob->getEye()); + ntlRay the_ray(glob->getEye(), getNormalized(dir), 0, 1.0, glob ); + + /* ...and trace it */ + ntlColor newCol= the_ray.shade(); + aaCol[aj*aaArrayX +ai +aOrg]= newCol; + } /* not used? */ + + } + } + + /* check color differences */ + for(aj = 0;aj aaSensRed ) || + (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] - + aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][1])> aaSensGreen ) || + (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] - + aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][2])> aaSensBlue ) ) { + thisColDiff = 1; + } else + if( + (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] - + aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][0])> aaSensRed ) || + (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] - + aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][1])> aaSensGreen ) || + (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] - + aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][2])> aaSensBlue ) ) { + thisColDiff = 1; + } else + if( + (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] - + aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][0])> aaSensRed ) || + (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] - + aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][1])> aaSensGreen ) || + (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] - + aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][2])> aaSensBlue ) ) { + thisColDiff = 1; + } + + //colDiff =1; + if(thisColDiff) { + /* set diff flag */ + colDiff = thisColDiff; + for(int bj=aj;bj<=aj+currStep;bj++) { + for(int bi=ai;bi<=ai+currStep;bi++) { + if(aaUse[bj*aaArrayX +bi +aOrg]==2) { + //if(showAAPic) + aaUse[bj*aaArrayX +bi +aOrg] = 0; + } + } + } + } else { + /* set all values */ + ntlColor avgCol = ( + aaCol[(aj+0 )*aaArrayX +(ai+0 ) +aOrg] + + aaCol[(aj+0 )*aaArrayX +(ai+currStep) +aOrg] + + aaCol[(aj+currStep)*aaArrayX +(ai+0 ) +aOrg] + + aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg] ) *0.25; + for(int bj=aj;bj<=aj+currStep;bj++) { + for(int bi=ai;bi<=ai+currStep;bi++) { + if(aaUse[bj*aaArrayX +bi +aOrg]==0) { + aaCol[bj*aaArrayX +bi +aOrg] = avgCol; + aaUse[bj*aaArrayX +bi +aOrg] = 2; + } + } + } + } /* smaller values set */ + + } + } + + /* half step size */ + currStep /= 2; + + } /* repeat until diff not too big */ + + /* get average color */ + gfxReal colNum = 0.0; + col = ntlColor(0.0, 0.0, 0.0); + for(aj = 0;aj<=aaLength;aj++) { + for(ai = 0;ai<=aaLength;ai++) { + col += aaCol[aj*aaArrayX +ai +aOrg]; + colNum += 1.0; + } + } + col /= colNum; + + } + + /* mark pixels with debugging */ + if( glob->getDebugOut() > 0) col = ntlColor(0,1,0); + + /* store pixel */ + if(!showAAPic) { + finalPic[(scanline-1)*picX+sx] = col; + } + screenPos += rightStep; + + } /* foreach x */ + + /* init aa array */ + if(showAAPic) { + for(int j=0;j<=aaArrayY-1;j++) { + for(int i=0;i<=aaArrayX-1;i++) { + if(aaUse[j*aaArrayX +i]==1) finalPic[((scanline-1)*aaLength +j)*picX+i][0] = 1.0; + } + } + } + + for(int i=0;i= 1.0) col[cc] = 1.0; + } + *filler = (unsigned char)( col[0]*255.0 ); + filler++; + *filler = (unsigned char)( col[1]*255.0 ); + filler++; + *filler = (unsigned char)( col[2]*255.0 ); + filler++; + *filler = (unsigned char)( 255.0 ); + filler++; // alpha channel + } + } + + for(int i = 0; i < h; i++) rows[i] = &screenbuf[ (h - i - 1)*rowbytes ]; + writePng(outfn_conv.str().c_str(), rows, w, h); + } + + + // next frame + glob->setAniCount( glob->getAniCount() +1 ); + + // done + timeEnd = getTime(); + + char resout[1024]; + snprintf(resout,1024, "NTL Done %s, frame %d/%d (took %s scene, %s raytracing, %s total, %d shades, %d i.s.'s)!\n", + outfn_conv.str().c_str(), (glob->getAniCount()), (glob->getAniFrames()+1), + getTimeString(totalStart-timeStart).c_str(), getTimeString(rendEnd-rendStart).c_str(), getTimeString(timeEnd-timeStart).c_str(), + glob->getCounterShades(), + glob->getCounterSceneInter() ); + debMsgStd("ntlWorld::renderScene",DM_MSG, resout, 1 ); + + /* clean stuff up */ + delete [] aaCol; + delete [] aaUse; + delete [] finalPic; + glob->getRenderScene()->cleanupScene(); + + if(mpGlob->getSingleFrameMode() ) { + debMsgStd("ntlWorld::renderScene",DM_NOTIFY, "Single frame mode done...", 1 ); + return 1; + } +#endif // ELBEEM_PLUGIN + return 0; +} + + +/****************************************************************************** + * renderglobals + *****************************************************************************/ + + +/*****************************************************************************/ +/* Constructor with standard value init */ +ntlRenderGlobals::ntlRenderGlobals() : + mpRenderScene(NULL), mpSimScene(NULL), + mpLightList( NULL ), mpMaterials( NULL ), mpSims( NULL ), + mResX(320), mResY(200), mAADepth(-1), mMaxColVal(255), + mRayMaxDepth( 5 ), + mvEye(0.0,0.0,5.0), mvLookat(0.0,0.0,0.0), mvUpvec(0.0,1.0,0.0), + mAspect(320.0/200.0), + mFovy(45), mcBackgr(0.0,0.0,0.0), mcAmbientLight(0.0,0.0,0.0), + mDebugOut( 0 ), + mAniStart(0), mAniFrames( -1 ), mAniCount( 0 ), + mFrameSkip( 0 ), + mCounterRays( 0 ), mCounterShades( 0 ), mCounterSceneInter( 0 ), + mOutFilename( "pic" ), + mTreeMaxDepth( 30 ), mTreeMaxTriangles( 30 ), + mpOpenGlAttr(NULL), + mpBlenderAttr(NULL), + mTestSphereEnabled( false ), + mDebugPixelX( -1 ), mDebugPixelY( -1 ), mTestMode(false), + mSingleFrameMode(false), mSingleFrameFilename("") + //,mpRndDirections( NULL ), mpRndRoulette( NULL ) +{ + // create internal attribute list for opengl renderer + mpOpenGlAttr = new AttributeList("__ntlOpenGLRenderer"); + mpBlenderAttr = new AttributeList("__ntlBlenderAttr"); +}; + + +/*****************************************************************************/ +/* Destructor */ +ntlRenderGlobals::~ntlRenderGlobals() { + if(mpOpenGlAttr) delete mpOpenGlAttr; + if(mpBlenderAttr) delete mpBlenderAttr; +} + + +/*****************************************************************************/ +//! get the next random photon direction +//ntlVec3Gfx ntlRenderGlobals::getRandomDirection( void ) { + //return ntlVec3Gfx( + //(mpRndDirections->getGfxReal()-0.5), + //(mpRndDirections->getGfxReal()-0.5), + //(mpRndDirections->getGfxReal()-0.5) ); +//} + + diff --git a/intern/elbeem/intern/ntl_world.h b/intern/elbeem/intern/ntl_world.h new file mode 100644 index 00000000000..9c5324cfe8f --- /dev/null +++ b/intern/elbeem/intern/ntl_world.h @@ -0,0 +1,389 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Main renderer class + * + *****************************************************************************/ +#ifndef NTL_RAYTRACER_HH +#define NTL_RAYTRACER_HH + +#include "ntl_vector3dim.h" +#include "ntl_ray.h" +#include "ntl_lighting.h" +#include "ntl_geometryobject.h" +#include "simulation_object.h" +#include "elbeem.h" +class ntlOpenGLRenderer; +class ntlScene; +class SimulationObject; +class ntlRandomStream; + +class ntlWorld +{ + public: + /*! Constructor for API init */ + ntlWorld(); + /*! Constructor */ + ntlWorld(string filename, bool commandlineMode); + /*! Destructor */ + virtual ~ntlWorld( void ); + /*! default init for all contructors */ + void initDefaults(); + /*! common world contruction stuff once the scene is set up */ + void finishWorldInit(); + /*! add domain for API init */ + int addDomain(elbeemSimulationSettings *simSettings); + + /*! render a whole animation (command line mode) */ + int renderAnimation( void ); + /*! render a whole animation (visualization mode) */ + int renderVisualization( bool ); + /*! render a single step for viz mode */ + int singleStepVisualization( void ); + /*! advance simulations by time frame time */ + int advanceSims(int framenum); + /*! advance simulations by a single step */ + void singleStepSims(double targetTime); + + /*! set stop rend viz flag */ + void setStopRenderVisualization(bool set) { mStopRenderVisualization = set; } + /*! should the rendering viz thread be stopped? */ + bool getStopRenderVisualization() { return mStopRenderVisualization; } + + /*! render scene (a single pictures) */ + virtual int renderScene( void ); + + /*! set single frame rendering to filename */ + void setSingleFrameOut( string singleframeFilename ); + + /* access functions */ + + /*! set&get render globals */ + inline void setRenderGlobals( ntlRenderGlobals *set) { mpGlob = set; } + inline ntlRenderGlobals *getRenderGlobals( void ) { return mpGlob; } + + /*! set&get render globals */ + inline void setSimulationTime( double set) { mSimulationTime = set; } + inline double getSimulationTime( void ) { return mSimulationTime; } + + /*! set&get single step debug mode */ + inline void setSingleStepDebug( bool set) { mSingleStepDebug = set; } + inline bool getSingleStepDebug( void ) { return mSingleStepDebug; } + + /*! &get simulation object vector (debugging) */ + inline vector *getSimulations( void ) { return mpSims; } + + /*! get opengl renderer */ + inline ntlOpenGLRenderer *getOpenGLRenderer() { return mpOpenGLRenderer; } + + private: + + protected: + + /*! global render settings needed almost everywhere */ + ntlRenderGlobals *mpGlob; + + /*! a list of lights in the scene (geometry is store in ntl_scene) */ + vector *mpLightList; + /*! surface materials */ + vector *mpPropList; + /*! sims list */ + vector *mpSims; + + /*! opengl display */ + ntlOpenGLRenderer *mpOpenGLRenderer; + + /*! stop rend viz? */ + bool mStopRenderVisualization; + + /*! rend viz thread currently running? */ + bool mThreadRunning; + + /*! remember the current simulation time */ + double mSimulationTime; + + /*! first simulation that is valid */ + int mFirstSim; + + /*! single step mode for debugging */ + bool mSingleStepDebug; + + /*! count no. of frame for viz render */ + int mFrameCnt; +}; + + +//! Class that handles global rendering parameters +class ntlRenderGlobals +{ + public: + //! Standard constructor + ntlRenderGlobals(); + //! Destructor + ~ntlRenderGlobals(); + + //! Returns the renderscene manager (scene changes for each frame) + inline ntlScene *getRenderScene(void) { return mpRenderScene; } + //! Set the renderscene manager + inline void setRenderScene(ntlScene *set) { mpRenderScene = set;} + + //! Returns the simulation scene manager (static scene with sim objects) + inline ntlScene *getSimScene(void) { return mpSimScene; } + //! Set the simulation scene manager + inline void setSimScene(ntlScene *set) { mpSimScene = set;} + + //! Returns the light object list + inline vector *getLightList(void) { return mpLightList; } + //! Set the light list + inline void setLightList(vector *set) { mpLightList = set;} + + //! Returns the property object list + inline vector *getMaterials(void) { return mpMaterials; } + //! Set the property list + inline void setMaterials(vector *set) { mpMaterials = set;} + + //! Returns the list of simulations + inline vector *getSims(void) { return mpSims; } + //! Set the pointer to the list of simulations + inline void setSims(vector *set) { mpSims = set;} + + //! Set the x resolution + inline void setResX(unsigned int set) { mResX = set; } + //! Set the y resolution + inline void setResY(unsigned int set) { mResY = set; } + //! Set the anti-aliasing depth + inline void setAADepth(int set) { mAADepth = set; } + //! Set the max color value + inline void setMaxColVal(unsigned int set) { mMaxColVal = set; } + //! Set the maximum ray recursion + inline void setRayMaxDepth(unsigned int set) { mRayMaxDepth = set; } + //! Set the eye point + inline void setEye(ntlVec3Gfx set) { mvEye = set; } + //! Set the look at vector + inline void setLookat(ntlVec3Gfx set) { mvLookat = set; } + //! Set the up vector + inline void setUpVec(ntlVec3Gfx set) { mvUpvec = set; } + //! Set the image aspect + inline void setAspect(float set) { mAspect = set; } + //! Set the field of view + inline void setFovy(float set) { mFovy = set; } + //! Set the background color + inline void setBackgroundCol(ntlColor set) { mcBackgr = set; } + //! Set the ambient lighting color + inline void setAmbientLight(ntlColor set) { mcAmbientLight = set; } + //! Set the debug output var + inline void setDebugOut(int set) { mDebugOut = set; } + + //! Set the animation start time + inline void setAniStart(int set) { mAniStart = set; } + //! Set the animation number of frames + inline void setAniFrames(int set) { mAniFrames = set; } + //! Set the animation + inline void setAniCount(int set) { mAniCount = set; } + //! Set the ray counter + inline void setCounterRays(int set) { mCounterRays = set; } + //! Set the ray shades counter + inline void setCounterShades(int set) { mCounterShades = set; } + //! Set the scenen intersection counter + inline void setCounterSceneInter(int set) { mCounterSceneInter = set; } + //! Set if existing frames should be skipped + inline void setFrameSkip(int set) { mFrameSkip = set; } + + //! Set the outfilename + inline void setOutFilename(string set) { mOutFilename = set; } + + //! get Maximum depth for BSP tree + inline void setTreeMaxDepth( int set ) { mTreeMaxDepth = set; } + //! get Maxmimum nr of triangles per BSP tree node + inline void setTreeMaxTriangles( int set ) { mTreeMaxTriangles = set; } + + //! set the enable flag of the test sphere + inline void setTestSphereEnabled( bool set ) { mTestSphereEnabled = set; } + //! set the center of the test sphere + inline void setTestSphereCenter( ntlVec3Gfx set ) { mTestSphereCenter = set; } + //! set the radius of the test sphere + inline void setTestSphereRadius( gfxReal set ) { mTestSphereRadius = set; } + //! set the material name of the test sphere + inline void setTestSphereMaterialName( char* set ) { mTestSphereMaterialName = set; } + //! set debugging pixel coordinates + inline void setDebugPixel( int setx, int sety ) { mDebugPixelX = setx; mDebugPixelY = sety; } + //! set test mode flag + inline void setTestMode( bool set ) { mTestMode = set; } + //! set single frame mode flag + inline void setSingleFrameMode(bool set) {mSingleFrameMode = set; }; + //! set single frame mode filename + inline void setSingleFrameFilename(string set) {mSingleFrameFilename = set; }; + + + //! Return the x resolution + inline unsigned int getResX(void) { return mResX; } + //! Return the y resolution + inline unsigned int getResY(void) { return mResY; } + //! Return the anti-aliasing depth + inline int getAADepth(void) { return mAADepth; } + //! Return the max color value for ppm + inline unsigned int getMaxColVal(void) { return mMaxColVal; } + //! Return the maximum ray recursion + inline unsigned int getRayMaxDepth(void) { return mRayMaxDepth; } + //! Return the eye point + inline ntlVec3Gfx getEye(void) { return mvEye; } + //! Return the look at vector + inline ntlVec3Gfx getLookat(void) { return mvLookat; } + //! Return the up vector + inline ntlVec3Gfx getUpVec(void) { return mvUpvec; } + //! Return the image aspect + inline float getAspect(void) { return mAspect; } + //! Return the field of view + inline float getFovy(void) { return mFovy; } + //! Return the background color + inline ntlColor getBackgroundCol(void) { return mcBackgr; } + //! Return the ambient color + inline ntlColor getAmbientLight(void) { return mcAmbientLight; } + //! Return the debug mode setting + inline int getDebugOut(void) { return mDebugOut; } + + //! Return the animation start time + inline int getAniStart(void) { return mAniStart; } + //! Return the animation frame number + inline int getAniFrames(void) { return mAniFrames; } + //! Return the animation counter + inline int getAniCount(void) { return mAniCount; } + //! Return the ray counter + inline int getCounterRays(void) { return mCounterRays; } + //! Return the ray shades counter + inline int getCounterShades(void) { return mCounterShades; } + //! Return the scene intersection counter + inline int getCounterSceneInter(void) { return mCounterSceneInter; } + //! Check if existing frames should be skipped + inline int getFrameSkip( void ) { return mFrameSkip; } + + + //! Return the outfilename + inline string getOutFilename(void) { return mOutFilename; } + + //! get Maximum depth for BSP tree + inline int getTreeMaxDepth( void ) { return mTreeMaxDepth; } + //! get Maxmimum nr of triangles per BSP tree node + inline int getTreeMaxTriangles( void ) { return mTreeMaxTriangles; } + + //! get open gl attribute list + inline AttributeList* getOpenGlAttributes( void ) { return mpOpenGlAttr; } + //! get blender output attribute list + inline AttributeList* getBlenderAttributes( void ) { return mpBlenderAttr; } + + //! is the test sphere enabled? + inline bool getTestSphereEnabled( void ) { return mTestSphereEnabled; } + //! get the center of the test sphere + inline ntlVec3Gfx getTestSphereCenter( void ) { return mTestSphereCenter; } + //! get the radius of the test sphere + inline gfxReal getTestSphereRadius( void) { return mTestSphereRadius; } + //! get the materialname of the test sphere + inline char *getTestSphereMaterialName( void) { return mTestSphereMaterialName; } + //! get the debug pixel coordinate + inline int getDebugPixelX( void ) { return mDebugPixelX; } + //! get the debug pixel coordinate + inline int getDebugPixelY( void ) { return mDebugPixelY; } + //! get test mode flag + inline bool getTestMode( void ) { return mTestMode; } + //! set single frame mode flag + inline bool getSingleFrameMode() { return mSingleFrameMode; }; + //! set single frame mode filename + inline string getSingleFrameFilename() { return mSingleFrameFilename; }; + + +private: + + /*! Scene storage (dynamic rendering scene) */ + ntlScene *mpRenderScene; + /*! Scene storage (static sim scene, inited only once) */ + ntlScene *mpSimScene; + + //! List of light objects + vector *mpLightList; + //! List of surface properties + vector *mpMaterials; + /*! storage for simulations */ + vector *mpSims; + + //! resolution of the picture + unsigned int mResX, mResY; + //! Anti-Aliasing depth + int mAADepth; + //! max color value for ppm + unsigned int mMaxColVal; + /* Maximal ray recursion depth */ + int mRayMaxDepth; + //! The eye point + ntlVec3Gfx mvEye; + //! The look at point + ntlVec3Gfx mvLookat; + //! The up vector + ntlVec3Gfx mvUpvec; + //! The image aspect = Xres/Yres + float mAspect; + //! The horizontal field of view + float mFovy; + //! The background color + ntlColor mcBackgr; + //! The ambient color + ntlColor mcAmbientLight; + //! how much debug output is needed? off by default + char mDebugOut; + + + //! animation properties, start time + int mAniStart; + //! animation properties, number of frames to render + int mAniFrames; + //! animation status, current frame number + int mAniCount; + /*! Should existing picture frames be skipped? */ + int mFrameSkip; + + + //! count the total number of rays created (also used for ray ID's) + int mCounterRays; + //! count the total number of rays shaded + int mCounterShades; + //! count the total number of scene intersections + int mCounterSceneInter; + + /*! filename of output pictures (without suffix or numbers) */ + string mOutFilename; + + //! get Maximum depth for BSP tree + int mTreeMaxDepth; + //! get Maxmimum nr of triangles per BSP tree node + int mTreeMaxTriangles; + + //! attribute list for opengl renderer + AttributeList *mpOpenGlAttr; + //! attribute list for blender output + AttributeList *mpBlenderAttr; + + + //! Enable test sphere? + bool mTestSphereEnabled; + //! Center of the test sphere + ntlVec3Gfx mTestSphereCenter; + //! Radius of the test sphere + gfxReal mTestSphereRadius; + //! Materialname of the test sphere + char *mTestSphereMaterialName; + //! coordinates of the debugging pixel + int mDebugPixelX, mDebugPixelY; + + //! test mode for quick rendering activated?, inited in ntl_scene::buildScene + bool mTestMode; + + //! single frame flag + bool mSingleFrameMode; + //! filename for single frame mode + string mSingleFrameFilename; +}; + + + +#endif diff --git a/intern/elbeem/intern/parametrizer.cpp b/intern/elbeem/intern/parametrizer.cpp new file mode 100644 index 00000000000..dca0b48d265 --- /dev/null +++ b/intern/elbeem/intern/parametrizer.cpp @@ -0,0 +1,594 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Parameter calculator for the LBM Solver class + * + *****************************************************************************/ + +#include +#include "parametrizer.h" + +// debug output flag, has to be off for win32 for some reason... +#define DEBUG_PARAMCHANNELS 0 + +/*! param seen debug string array */ +const char *ParamStrings[] = { + "RelaxTime", + "Reynolds", + "Viscosity", + "SoundSpeed", + "DomainSize", + "GravityForce", + "TimeLength", + "Timestep", + "Size", + "TimeFactor", + "AniFrames", + "AniFrameTime", + "AniStart", + "SurfaceTension", + "Density", + "CellSize", + "GStar", + "MaxSpeed", + "SimMaxSpeed", + "FluidVolHeight", + "NormalizedGStar", + "PSERR", "PSERR", "PSERR", "PSERR" +}; + + + +/****************************************************************************** + * Default constructor + *****************************************************************************/ +Parametrizer::Parametrizer( void ) : + mcViscosity( 8.94e-7 ), + mSoundSpeed( 1500 ), + mDomainSize( 0.1 ), mCellSize( 0.01 ), + mcGravity( ParamVec(0.0) ), + mTimestep(0.0001), mDesiredTimestep(-1.0), + mMaxTimestep(-1.0), + mMinTimestep(-1.0), + mSizex(50), mSizey(50), mSizez(50), + mTimeFactor( 1.0 ), + mcAniFrameTime(0.0001), + mTimeStepScale(1.0), + mAniStart(0.0), + //mExtent(1.0, 1.0, 1.0), //mSurfaceTension( 0.0 ), + mDensity(1000.0), mGStar(0.0001), mFluidVolumeHeight(0.0), + mSimulationMaxSpeed(0.0), + mTadapMaxOmega(2.0), mTadapMaxSpeed(0.1), mTadapLevels(1), + mFrameNum(0), + mSeenValues( 0 ), mCalculatedValues( 0 ) +{ +} + + +/****************************************************************************** + * Destructor + *****************************************************************************/ +Parametrizer::~Parametrizer() +{ + /* not much to do... */ +} + +/****************************************************************************** + * Init from attr list + *****************************************************************************/ +void Parametrizer::parseAttrList() +{ + if(!mpAttrs) { + errFatal("Parametrizer::parseAttrList", "mpAttrs pointer not initialized!", SIMWORLD_INITERROR); + return; + } + + // unused + string mSetupType = ""; + mSetupType = mpAttrs->readString("p_setup",mSetupType, "Parametrizer","mSetupType", false); + + // real params + if(getAttributeList()->exists("p_viscosity")) { + mcViscosity = mpAttrs->readChannelFloat("p_viscosity"); seenThis( PARAM_VISCOSITY ); } + + mSoundSpeed = mpAttrs->readFloat("p_soundspeed",mSoundSpeed, "Parametrizer","mSoundSpeed", false); + if(getAttributeList()->exists("p_soundspeed")) seenThis( PARAM_SOUNDSPEED ); + + mDomainSize = mpAttrs->readFloat("p_domainsize",mDomainSize, "Parametrizer","mDomainSize", false); + if(getAttributeList()->exists("p_domainsize")) seenThis( PARAM_DOMAINSIZE ); + if(mDomainSize<=0.0) { + errMsg("Parametrizer::parseAttrList","Invalid real world domain size:"<exists("p_gravity")) { // || (!mcGravity.isInited()) ) { + mcGravity = mpAttrs->readChannelVec3d("p_gravity"); seenThis( PARAM_GRAVITY ); + } + + mTimestep = mpAttrs->readFloat("p_steptime",mTimestep, "Parametrizer","mTimestep", false); + if(getAttributeList()->exists("p_steptime")) seenThis( PARAM_STEPTIME ); + + mTimeFactor = mpAttrs->readFloat("p_timefactor",mTimeFactor, "Parametrizer","mTimeFactor", false); + if(getAttributeList()->exists("p_timefactor")) seenThis( PARAM_TIMEFACTOR ); + + if(getAttributeList()->exists("p_aniframetime")) { //|| (!mcAniFrameTime.isInited()) ) { + mcAniFrameTime = mpAttrs->readChannelFloat("p_aniframetime");seenThis( PARAM_ANIFRAMETIME ); + } + mTimeStepScale = mpAttrs->readFloat("p_timestepscale",mTimeStepScale, "Parametrizer","mTimeStepScale", false); + + mAniStart = mpAttrs->readFloat("p_anistart",mAniStart, "Parametrizer","mAniStart", false); + if(getAttributeList()->exists("p_anistart")) seenThis( PARAM_ANISTART ); + if(mAniStart<0.0) { + errMsg("Parametrizer::parseAttrList","Invalid start time:"<readFloat("p_surfacetension",mSurfaceTension, "Parametrizer","mSurfaceTension", false); + //if(getAttributeList()->exists("p_surfacetension")) seenThis( PARAM_SURFACETENSION ); + + mDensity = mpAttrs->readFloat("p_density",mDensity, "Parametrizer","mDensity", false); + if(getAttributeList()->exists("p_density")) seenThis( PARAM_DENSITY ); + + ParamFloat cellSize = 0.0; // unused, deprecated + cellSize = mpAttrs->readFloat("p_cellsize",cellSize, "Parametrizer","cellSize", false); + + mGStar = mpAttrs->readFloat("p_gstar",mGStar, "Parametrizer","mGStar", false); + if(getAttributeList()->exists("p_gstar")) seenThis( PARAM_GSTAR ); + + mNormalizedGStar = mpAttrs->readFloat("p_normgstar",mNormalizedGStar, "Parametrizer","mNormalizedGStar", false); + if(getAttributeList()->exists("p_normgstar")) seenThis( PARAM_NORMALIZEDGSTAR ); + + mTadapMaxOmega = mpAttrs->readFloat("p_tadapmaxomega",mTadapMaxOmega, "Parametrizer","mTadapMaxOmega", false); + mTadapMaxSpeed = mpAttrs->readFloat("p_tadapmaxspeed",mTadapMaxSpeed, "Parametrizer","mTadapMaxSpeed", false); +} + +/****************************************************************************** + *! advance to next render/output frame + *****************************************************************************/ +void Parametrizer::setFrameNum(int frame) { + mFrameNum = frame; +#if DEBUG_PARAMCHANNELS>0 + errMsg("DEBUG_PARAMCHANNELS","setFrameNum frame-num="<0 +} +/*! get time of an animation frame (renderer) */ +// also used by: mpParam->getCurrentAniFrameTime() , e.g. for velocity dump +ParamFloat Parametrizer::getAniFrameTime( int frame ) { + double frametime = (double)frame; + ParamFloat anift = mcAniFrameTime.get(frametime); + if(anift<0.0) { + ParamFloat resetv = 0.; + errMsg("Parametrizer::setFrameNum","Invalid frame time:"<0 + if((0)|| (DEBUG_PARAMCHANNELS)) errMsg("DEBUG_PARAMCHANNELS","getAniFrameTime frame="<0 + return anift; +} + +/****************************************************************************** + * scale a given speed vector in m/s to lattice values + *****************************************************************************/ +ParamVec Parametrizer::calculateAddForce(ParamVec vec, string usage) +{ + ParamVec ret = vec * (mTimestep*mTimestep) /mCellSize; + debMsgStd("Parametrizer::calculateVector", DM_MSG, "scaled vector = "<0 + errMsg("DEBUG_PARAMCHANNELS","calculateLatticeViscosity viscStar="<0 + return viscStar; +} + +/*! get no of steps for the given length in seconds */ +int Parametrizer::calculateStepsForSecs( ParamFloat s ) { + return (int)(s/mTimestep); +} + +/*! get start time of animation */ +int Parametrizer::calculateAniStart( void ) { + return (int)(mAniStart/mTimestep); +} + +/*! get no of steps for a single animation frame */ +int Parametrizer::calculateAniStepsPerFrame(int frame) { + if(!checkSeenValues(PARAM_ANIFRAMETIME)) { + errFatal("Parametrizer::calculateAniStepsPerFrame", "Missing ani frame time argument!", SIMWORLD_INITERROR); + return 1; + } + int value = (int)(getAniFrameTime(frame)/mTimestep); + if((value<0) || (value>1000000)) { + errFatal("Parametrizer::calculateAniStepsPerFrame", "Invalid step-time (="< ani-frame-time ("<0.0) { gStar = mGStar/mFluidVolumeHeight; } + return gStar; +} + +/****************************************************************************** + * function that tries to calculate all the missing values from the given ones + * prints errors and returns false if thats not possible + *****************************************************************************/ +bool Parametrizer::calculateAllMissingValues( double time, bool silent ) +{ + bool init = false; // did we init correctly? + int valuesChecked = 0; + int reqValues; + + // we always need the sizes + reqValues = PARAM_SIZE; + valuesChecked |= reqValues; + if(!checkSeenValues(reqValues)) { + errMsg("Parametrizer::calculateAllMissingValues"," Missing size argument!"); + return false; + } + + if(!checkSeenValues(PARAM_DOMAINSIZE)) { + errMsg("Parametrizer::calculateAllMissingValues"," Missing domain size argument!"); + return false; + } + int maxsize = mSizex; // get max size + if(mSizey>maxsize) maxsize = mSizey; + if(mSizez>maxsize) maxsize = mSizez; + maxsize = mSizez; // take along gravity dir for now! + mCellSize = ( mDomainSize * calculateCellSize() ); // sets mCellSize + if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," max domain resolution="<<(maxsize)<<" cells , cellsize="<0.0) { + debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," height"<0.0) { + // explicitly set step time according to max velocity in sim + setDeltaT = mDesiredTimestep; + if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," desired step time = "<0)) { + if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," ani start steps = "<(set); + seenThis( PARAM_VISCOSITY ); +#if DEBUG_PARAMCHANNELS>0 + { errMsg("DebugChannels","Parametrizer::mcViscosity set = "<< mcViscosity.printChannel() ); } +#endif // DEBUG_PARAMCHANNELS>0 +} +void Parametrizer::initViscosityChannel(vector val, vector time) { + mcViscosity = AnimChannel(val,time); + seenThis( PARAM_VISCOSITY ); +#if DEBUG_PARAMCHANNELS>0 + { errMsg("DebugChannels","Parametrizer::mcViscosity initc = "<< mcViscosity.printChannel() ); } +#endif // DEBUG_PARAMCHANNELS>0 +} + +/*! set the external force */ +void Parametrizer::setGravity(ParamFloat setx, ParamFloat sety, ParamFloat setz) { + mcGravity = AnimChannel(ParamVec(setx,sety,setz)); + seenThis( PARAM_GRAVITY ); +#if DEBUG_PARAMCHANNELS>0 + { errMsg("DebugChannels","Parametrizer::mcGravity set = "<< mcGravity.printChannel() ); } +#endif // DEBUG_PARAMCHANNELS>0 +} +void Parametrizer::setGravity(ParamVec set) { + mcGravity = AnimChannel(set); + seenThis( PARAM_GRAVITY ); +#if DEBUG_PARAMCHANNELS>0 + { errMsg("DebugChannels","Parametrizer::mcGravity set = "<< mcGravity.printChannel() ); } +#endif // DEBUG_PARAMCHANNELS>0 +} +void Parametrizer::initGravityChannel(vector val, vector time) { + mcGravity = AnimChannel(val,time); + seenThis( PARAM_GRAVITY ); +#if DEBUG_PARAMCHANNELS>0 + { errMsg("DebugChannels","Parametrizer::mcGravity initc = "<< mcGravity.printChannel() ); } +#endif // DEBUG_PARAMCHANNELS>0 +} + +/*! set time of an animation frame (renderer) */ +void Parametrizer::setAniFrameTimeChannel(ParamFloat set) { + mcAniFrameTime = AnimChannel(set); + seenThis( PARAM_ANIFRAMETIME ); +#if DEBUG_PARAMCHANNELS>0 + { errMsg("DebugChannels","Parametrizer::mcAniFrameTime set = "<< mcAniFrameTime.printChannel() ); } +#endif // DEBUG_PARAMCHANNELS>0 +} +void Parametrizer::initAniFrameTimeChannel(vector val, vector time) { + mcAniFrameTime = AnimChannel(val,time); + seenThis( PARAM_ANIFRAMETIME ); +#if DEBUG_PARAMCHANNELS>0 + { errMsg("DebugChannels","Parametrizer::mcAniFrameTime initc = "<< mcAniFrameTime.printChannel() ); } +#endif // DEBUG_PARAMCHANNELS>0 +} + +// OLD interface stuff +// reactivate at some point? + + /*! surface tension, [kg/s^2] */ + //ParamFloat mSurfaceTension; + /*! set starting time of the animation (renderer) */ + //void setSurfaceTension(ParamFloat set) { mSurfaceTension = set; seenThis( PARAM_SURFACETENSION ); } + /*! get starting time of the animation (renderer) */ + //ParamFloat getSurfaceTension( void ) { return mSurfaceTension; } + /*if((checkSeenValues(PARAM_SURFACETENSION))&&(mSurfaceTension>0.0)) { + ParamFloat massDelta = 1.0; + ParamFloat densityStar = 1.0; + massDelta = mDensity / densityStar *mCellSize*mCellSize*mCellSize; + if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," massDelta = "<0.0) { + ParamFloat maxSpeed = 1.0/6.0; // for rough reynolds approx + ParamFloat reynoldsApprox = -1.0; + ParamFloat gridSpeed = (maxSpeed*mCellSize/mTimestep); + reynoldsApprox = (mDomainSize*gridSpeed) / mViscosity; + if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," reynolds number (D="<readFloat("p_relaxtime",mRelaxTime, "Parametrizer","mRelaxTime", false); + //if(getAttributeList()->exists("p_relaxtime")) seenThis( PARAM_RELAXTIME ); + //? mReynolds = mpAttrs->readFloat("p_reynolds",mReynolds, "Parametrizer","mReynolds", false); + //if(getAttributeList()->exists("p_reynolds")) seenThis( PARAM_REYNOLDS ); + + //mViscosity = mpAttrs->readFloat("p_viscosity",mViscosity, "Parametrizer","mViscosity", false); + //if(getAttributeList()->exists("p_viscosity") || (!mcViscosity.isInited()) ) { } + //if(getAttributeList()->exists("p_viscosity")) + + + //ParamFloat viscStar = calculateLatticeViscosity(time); + //RelaxTime = (6.0 * viscStar + 1) * 0.5; + + diff --git a/intern/elbeem/intern/parametrizer.h b/intern/elbeem/intern/parametrizer.h new file mode 100644 index 00000000000..e05db129d77 --- /dev/null +++ b/intern/elbeem/intern/parametrizer.h @@ -0,0 +1,310 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Parameter calculator for the LBM Solver class + * + *****************************************************************************/ +#ifndef MFFSLBM_PARAMETRIZER +#define MFFSLBM_PARAMETRIZER + + +/* LBM Files */ +#include "utilities.h" +#include "attributes.h" + +/* parametrizer accuracy */ +typedef double ParamFloat; +typedef ntlVec3d ParamVec; + +/*! flags to check which values are known */ +#define PARAM_RELAXTIME (1<< 0) +#define PARAM_REYNOLDS (1<< 1) +#define PARAM_VISCOSITY (1<< 2) +#define PARAM_SOUNDSPEED (1<< 3) +#define PARAM_DOMAINSIZE (1<< 4) +#define PARAM_GRAVITY (1<< 5) +#define PARAM_STEPTIME (1<< 7) +#define PARAM_SIZE (1<< 8) +#define PARAM_TIMEFACTOR (1<< 9) +#define PARAM_ANIFRAMETIME (1<<11) +#define PARAM_ANISTART (1<<12) +#define PARAM_SURFACETENSION (1<<13) +#define PARAM_DENSITY (1<<14) +#define PARAM_GSTAR (1<<16) +#define PARAM_SIMMAXSPEED (1<<18) +#define PARAM_FLUIDVOLHEIGHT (1<<19) +#define PARAM_NORMALIZEDGSTAR (1<<20) +#define PARAM_NUMIDS 21 + +//! output parameter debug message? +//#define PARAM_DEBUG 1 + + + +/*! Parameter calculator for the LBM Solver class */ +class Parametrizer { + + public: + /*! default contructor */ + Parametrizer(); + + /*! destructor */ + ~Parametrizer(); + + /*! Initilize variables fom attribute list */ + void parseAttrList( void ); + + /*! function that tries to calculate all the missing values from the given ones + * prints errors and returns false if thats not possible + * currently needs time value as well */ + bool calculateAllMissingValues( double time, bool silent ); + /*! is the parametrizer used at all? */ + bool isUsed() { return true; } + + /*! add this flag to the seen values */ + void seenThis(int seen) { mSeenValues = (mSeenValues | seen); +#ifdef PARAM_DEBUG + errorOut(" seen "< val, vector time); + + /*! set the external force */ + void setGravity(ParamFloat setx, ParamFloat sety, ParamFloat setz); + void setGravity(ParamVec set); + void initGravityChannel(vector val, vector time); + ParamVec getGravity(double time) { return mcGravity.get( time ); } + + /*! set time of an animation frame (renderer) */ + void setAniFrameTimeChannel(ParamFloat set); + void initAniFrameTimeChannel(vector val, vector time); + + /*! set the length of a single time step */ + void setTimestep(ParamFloat set) { mTimestep = set; seenThis( PARAM_STEPTIME ); } + /*! get the length of a single time step */ + ParamFloat getTimestep( void); + /*! set a desired step time for rescaling/adaptive timestepping */ + void setDesiredTimestep(ParamFloat set) { mDesiredTimestep = set; } + /*! get the length of a single time step */ + ParamFloat getMaxTimestep( void ) { return mMaxTimestep; } + /*! get the length of a single time step */ + ParamFloat getMinTimestep( void ) { return mMinTimestep; } + + /*! set the time scaling factor */ + void setTimeFactor(ParamFloat set) { mTimeFactor = set; seenThis( PARAM_TIMEFACTOR ); } + /*! get the time scaling factor */ + ParamFloat getTimeFactor( void ) { return mTimeFactor; } + + /*! init domain resoultion */ + void setSize(int ijk) { mSizex = ijk; mSizey = ijk; mSizez = ijk; seenThis( PARAM_SIZE ); } + void setSize(int i,int j, int k) { mSizex = i; mSizey = j; mSizez = k; seenThis( PARAM_SIZE ); } + + /*! set starting time of the animation (renderer) */ + void setAniStart(ParamFloat set) { mAniStart = set; seenThis( PARAM_ANISTART ); } + /*! get starting time of the animation (renderer) */ + ParamFloat getAniStart( void ) { return mAniStart; } + + /*! set fluid density */ + void setDensity(ParamFloat set) { mDensity = set; seenThis( PARAM_DENSITY ); } + /*! get fluid density */ + ParamFloat getDensity( void ) { return mDensity; } + + /*! set g star value */ + void setGStar(ParamFloat set) { mGStar = set; seenThis( PARAM_GSTAR ); } + /*! get g star value */ + ParamFloat getGStar( void ) { return mGStar; } + /*! get g star value with fhvol calculations */ + ParamFloat getCurrentGStar( void ); + /*! set normalized g star value */ + void setNormalizedGStar(ParamFloat set) { mNormalizedGStar = set; seenThis( PARAM_NORMALIZEDGSTAR ); } + /*! get normalized g star value */ + ParamFloat getNormalizedGStar( void ) { return mNormalizedGStar; } + + /*! set g star value */ + void setFluidVolumeHeight(ParamFloat set) { mFluidVolumeHeight = set; seenThis( PARAM_FLUIDVOLHEIGHT ); } + /*! get g star value */ + ParamFloat getFluidVolumeHeight( void ) { return mFluidVolumeHeight; } + + /*! set the size of a single lbm cell */ + void setDomainSize(ParamFloat set) { mDomainSize = set; seenThis( PARAM_DOMAINSIZE ); } + /*! get the size of a single lbm cell */ + ParamFloat getDomainSize( void ) { return mDomainSize; } + + /*! set the size of a single lbm cell (dont use, normally set by domainsize and resolution) */ + void setCellSize(ParamFloat set) { mCellSize = set; } + /*! get the size of a single lbm cell */ + ParamFloat getCellSize( void ) { return mCellSize; } + + /*! set active flag for parametrizer */ + //void setActive(bool set) { mActive = set; } + + /*! set attr list pointer */ + void setAttrList(AttributeList *set) { mpAttrs = set; } + /*! Returns the attribute list pointer */ + inline AttributeList *getAttributeList() { return mpAttrs; } + + /*! set maximum allowed speed for maxspeed setup */ + void setSimulationMaxSpeed(ParamFloat set) { mSimulationMaxSpeed = set; seenThis( PARAM_SIMMAXSPEED ); } + /*! get maximum allowed speed for maxspeed setup */ + ParamFloat getSimulationMaxSpeed( void ) { return mSimulationMaxSpeed; } + + /*! set maximum allowed omega for time adaptivity */ + void setTadapMaxOmega(ParamFloat set) { mTadapMaxOmega = set; } + /*! get maximum allowed omega for time adaptivity */ + ParamFloat getTadapMaxOmega( void ) { return mTadapMaxOmega; } + + /*! set maximum allowed speed for time adaptivity */ + void setTadapMaxSpeed(ParamFloat set) { mTadapMaxSpeed = set; } + /*! get maximum allowed speed for time adaptivity */ + ParamFloat getTadapMaxSpeed( void ) { return mTadapMaxSpeed; } + + /*! set maximum allowed omega for time adaptivity */ + void setTadapLevels(int set) { mTadapLevels = set; } + /*! get maximum allowed omega for time adaptivity */ + int getTadapLevels( void ) { return mTadapLevels; } + + /*! set */ + // void set(ParamFloat set) { m = set; seenThis( PARAM_ ); } + /*! get */ + // ParamFloat get( void ) { return m; } + + + + private: + + /*! kinematic viscosity of the fluid [m^2/s] */ + AnimChannel mcViscosity; + + /*! speed of sound of the fluid [m/s] */ + ParamFloat mSoundSpeed; + + /*! size of the domain [m] */ + ParamFloat mDomainSize; + + /*! size of a single cell in the grid [m] */ + ParamFloat mCellSize; + + /*! time step length [s] */ + ParamFloat mTimeStep; + + /*! external force as acceleration [m/s^2] */ + AnimChannel mcGravity; + + /*! length of one time step in the simulation */ + ParamFloat mTimestep; + /*! desired step time for rescaling/adaptive timestepping, only regarded if >0.0, reset after usage */ + ParamFloat mDesiredTimestep; + /*! minimal and maximal step times for current setup */ + ParamFloat mMaxTimestep, mMinTimestep; + + /*! domain resoultion, the same values as in lbmsolver */ + int mSizex, mSizey, mSizez; + + /*! time scaling factor (auto calc from accel, or set), equals the delta t in LBM */ + ParamFloat mTimeFactor; + + /*! for renderer - length of an animation step [s] */ + AnimChannel mcAniFrameTime; + /*! time step scaling factor for testing/debugging */ + ParamFloat mTimeStepScale; + + /*! for renderer - start time of the animation [s] */ + ParamFloat mAniStart; + + /*! extent of the domain in meters */ + //ParamVec mExtent; + + /*! fluid density [kg/m^3], default 1.0 g/cm^3 */ + ParamFloat mDensity; + + /*! max difference due to gravity (for caro setup) */ + ParamFloat mGStar; + /*! set gstar normalized! */ + ParamFloat mNormalizedGStar; + /*! fluid volume/height multiplier for GStar */ + ParamFloat mFluidVolumeHeight; + + /*! current max speed of the simulation (for adaptive time steps) */ + ParamFloat mSimulationMaxSpeed; + /*! maximum omega (for adaptive time steps) */ + ParamFloat mTadapMaxOmega; + /*! maximum allowed speed in lattice units e.g. 0.1 (for adaptive time steps, not directly used in parametrizer) */ + ParamFloat mTadapMaxSpeed; + /*! no. of levels for max omega (set by fsgr, not in cfg file) */ + int mTadapLevels; + + /*! remember current frame number */ + int mFrameNum; + + /*! values that are seen for this simulation */ + int mSeenValues; + + /*! values that are calculated from the seen ones for this simulation */ + int mCalculatedValues; + + /*! pointer to the attribute list */ + AttributeList *mpAttrs; +}; + + +#endif + diff --git a/intern/elbeem/intern/particletracer.cpp b/intern/elbeem/intern/particletracer.cpp new file mode 100644 index 00000000000..c9da808543a --- /dev/null +++ b/intern/elbeem/intern/particletracer.cpp @@ -0,0 +1,468 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Particle Viewer/Tracer + * + *****************************************************************************/ + +#include +//#include "../libs/my_gl.h" +//#include "../libs/my_glu.h" + +/* own lib's */ +#include "particletracer.h" +#include "ntl_matrices.h" +#include "ntl_ray.h" +#include "ntl_matrices.h" + +#include + + +// particle object id counter +int ParticleObjectIdCnt = 1; + +/****************************************************************************** + * Standard constructor + *****************************************************************************/ +ParticleTracer::ParticleTracer() : + ntlGeometryObject(), + mParts(), + //mTrailLength(1), mTrailInterval(1),mTrailIntervalCounter(0), + mPartSize(0.01), + mStart(-1.0), mEnd(1.0), + mSimStart(-1.0), mSimEnd(1.0), + mPartScale(0.1) , mPartHeadDist( 0.1 ), mPartTailDist( -0.1 ), mPartSegments( 4 ), + mValueScale(0), + mValueCutoffTop(0.0), mValueCutoffBottom(0.0), + mDumpParts(0), //mDumpText(0), + mDumpTextFile(""), + mDumpTextInterval(0.), mDumpTextLastTime(0.), mDumpTextCount(0), + mShowOnly(0), + mNumInitialParts(0), mpTrafo(NULL), + mInitStart(-1.), mInitEnd(-1.), + mPrevs(), mTrailTimeLast(0.), mTrailInterval(-1.), mTrailLength(0) +{ + debMsgStd("ParticleTracer::ParticleTracer",DM_MSG,"inited",10); +}; + +ParticleTracer::~ParticleTracer() { + debMsgStd("ParticleTracer::~ParticleTracer",DM_MSG,"destroyed",10); +} + +/*****************************************************************************/ +//! parse settings from attributes (dont use own list!) +/*****************************************************************************/ +void ParticleTracer::parseAttrList(AttributeList *att) +{ + AttributeList *tempAtt = mpAttrs; + mpAttrs = att; + + mNumInitialParts = mpAttrs->readInt("particles",mNumInitialParts, "ParticleTracer","mNumInitialParts", false); + //errMsg(" NUMP"," "<readFloat("part_scale",mPartScale, "ParticleTracer","mPartScale", false); + mPartHeadDist = mpAttrs->readFloat("part_headdist",mPartHeadDist, "ParticleTracer","mPartHeadDist", false); + mPartTailDist = mpAttrs->readFloat("part_taildist",mPartTailDist, "ParticleTracer","mPartTailDist", false); + mPartSegments = mpAttrs->readInt ("part_segments",mPartSegments, "ParticleTracer","mPartSegments", false); + mValueScale = mpAttrs->readInt ("part_valscale",mValueScale, "ParticleTracer","mValueScale", false); + mValueCutoffTop = mpAttrs->readFloat("part_valcutofftop",mValueCutoffTop, "ParticleTracer","mValueCutoffTop", false); + mValueCutoffBottom = mpAttrs->readFloat("part_valcutoffbottom",mValueCutoffBottom, "ParticleTracer","mValueCutoffBottom", false); + + mDumpParts = mpAttrs->readInt ("part_dump",mDumpParts, "ParticleTracer","mDumpParts", false); + // mDumpText deprecatd, use mDumpTextInterval>0. instead + mShowOnly = mpAttrs->readInt ("part_showonly",mShowOnly, "ParticleTracer","mShowOnly", false); + mDumpTextFile= mpAttrs->readString("part_textdumpfile",mDumpTextFile, "ParticleTracer","mDumpTextFile", false); + mDumpTextInterval= mpAttrs->readFloat("part_textdumpinterval",mDumpTextInterval, "ParticleTracer","mDumpTextInterval", false); + + string matPart; + matPart = mpAttrs->readString("material_part", "default", "ParticleTracer","material", false); + setMaterialName( matPart ); + + mInitStart = mpAttrs->readFloat("part_initstart",mInitStart, "ParticleTracer","mInitStart", false); + mInitEnd = mpAttrs->readFloat("part_initend", mInitEnd, "ParticleTracer","mInitEnd", false); + + // unused... + //int mTrailLength = 0; // UNUSED + //int mTrailInterval= 0; // UNUSED + mTrailLength = mpAttrs->readInt("traillength",mTrailLength, "ParticleTracer","mTrailLength", false); + mTrailInterval= mpAttrs->readFloat("trailinterval",mTrailInterval, "ParticleTracer","mTrailInterval", false); + + // restore old list + mpAttrs = tempAtt; +} + +/****************************************************************************** + * draw the particle array + *****************************************************************************/ +void ParticleTracer::draw() +{ +} + +/****************************************************************************** + * init trafo matrix + *****************************************************************************/ +void ParticleTracer::initTrafoMatrix() { + ntlVec3Gfx scale = ntlVec3Gfx( + (mEnd[0]-mStart[0])/(mSimEnd[0]-mSimStart[0]), + (mEnd[1]-mStart[1])/(mSimEnd[1]-mSimStart[1]), + (mEnd[2]-mStart[2])/(mSimEnd[2]-mSimStart[2]) + ); + ntlVec3Gfx trans = mStart; + if(!mpTrafo) mpTrafo = new ntlMat4Gfx(0.0); + mpTrafo->initId(); + for(int i=0; i<3; i++) { mpTrafo->value[i][i] = scale[i]; } + for(int i=0; i<3; i++) { mpTrafo->value[i][3] = trans[i]; } +} + +/****************************************************************************** + * adapt time step by rescaling velocities + *****************************************************************************/ +void ParticleTracer::adaptPartTimestep(float factor) { + for(size_t i=0; i0.) { errMsg("ParticleTracer::cleanup","Skipping cleanup due to text dump..."); return; } + + for(int i=0; i<=last; i++) { + if( mParts[i].getActive()==false ) { + ParticleObject *p = &mParts[i]; + ParticleObject *p2 = &mParts[last]; + *p = *p2; last--; mParts.pop_back(); + } + } +} + +extern bool glob_mpactive; +extern int glob_mpindex,glob_mpnum; + +/****************************************************************************** + *! dump particles if desired + *****************************************************************************/ +void ParticleTracer::notifyOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename, double simtime) { + debMsgStd("ParticleTracer::notifyOfDump",DM_MSG,"obj:"<getName()<<" frame:"<0)) { + // dump to binary file + std::ostringstream boutfilename(""); + boutfilename << outfilename <<"_particles_" << frameNrStr; + if(glob_mpactive) { + if(glob_mpindex>0) { boutfilename << "mp"<getName() <<", particles:"<getType(); // export whole type info + int type = p->getFlags(); // debug export whole type & status info + ntlVec3Gfx pos = p->getPos(); + float size = p->getSize(); + + if(type&PART_FLOAT) { // WARNING same handling for dump! + // add one gridcell offset + //pos[2] += 1.0; + } + // display as drop for now externally + //else if(type&PART_TRACER) { type |= PART_DROP; } + + pos = (*mpTrafo) * pos; + + ntlVec3Gfx v = p->getVel(); + v[0] *= mpTrafo->value[0][0]; + v[1] *= mpTrafo->value[1][1]; + v[2] *= mpTrafo->value[2][2]; + // FIXME check: pos = (*mpTrafo) * pos; + gzwrite(gzf, &type, sizeof(type)); + gzwrite(gzf, &size, sizeof(size)); + for(int j=0; j<3; j++) { gzwrite(gzf, &pos[j], sizeof(float)); } + for(int j=0; j<3; j++) { gzwrite(gzf, &v[j], sizeof(float)); } + } + gzclose( gzf ); + } + } // dump? +} + +void ParticleTracer::checkDumpTextPositions(double simtime) { + // dfor partial & full dump + if(mDumpTextInterval>0.) { + debMsgStd("ParticleTracer::checkDumpTextPositions",DM_MSG,"t="<0.) && (simtime>mDumpTextLastTime+mDumpTextInterval)) { + // dump to binary file + std::ostringstream boutfilename(""); + if(mDumpTextFile.length()>1) { + boutfilename << mDumpTextFile << ".cpart2"; + } else { + boutfilename << boutfilename <<"_particles" << ".cpart2"; + } + debMsgStd("ParticleTracer::checkDumpTextPositions",DM_MSG,"T-Dumping: "<< this->getName() <<", particles:"<getPos(); + float size = p->getSize(); + float infl = 1.; + //if(!mParts[i].getActive()) { size=0.; } // switch "off" + if(!mParts[i].getActive()) { infl=0.; } // switch "off" + if(!mParts[i].getInFluid()) { infl=0.; } // switch "off" + if(mParts[i].getLifeTime()<0.) { infl=0.; } // not yet active... + + pos = (*mpTrafo) * pos; + ntlVec3Gfx v = p->getVel(); + v[0] *= mpTrafo->value[0][0]; + v[1] *= mpTrafo->value[1][1]; + v[2] *= mpTrafo->value[2][2]; + + fprintf( stf, "P %f %f %f \n", pos[0],pos[1],pos[2] ); + if(size!=1.0) fprintf( stf, "s %f \n", size ); + if(infl!=1.0) fprintf( stf, "i %f \n", infl ); + fprintf( stf, "\n" ); + } + + fprintf( stf, "# %d end ", mDumpTextCount ); + //gzclose( gzf ); + fclose( stf ); + + mDumpTextCount++; + } + + mDumpTextLastTime += mDumpTextInterval; + } + +} + + +void ParticleTracer::checkTrails(double time) { + if(mTrailLength<1) return; + if(time-mTrailTimeLast > mTrailInterval) { + + if( (int)mPrevs.size() < mTrailLength) mPrevs.resize( mTrailLength ); + for(int i=mPrevs.size()-1; i>0; i--) { + mPrevs[i] = mPrevs[i-1]; + //errMsg("TRAIL"," from "< *triangles, + vector *vertices, + vector *normals, int objectId ) +{ +#ifdef ELBEEM_PLUGIN + // suppress warnings... + vertices = NULL; triangles = NULL; + normals = NULL; objectId = 0; + time = 0.0; +#else // ELBEEM_PLUGIN + int pcnt = 0; + // currently not used in blender + objectId = 0; // remove, deprecated + if(mDumpParts>1) { + return; // only dump, no tri-gen + } + + const bool debugParts = false; + int tris = 0; + int segments = mPartSegments; + ntlVec3Gfx scale = ntlVec3Gfx( (mEnd[0]-mStart[0])/(mSimEnd[0]-mSimStart[0]), (mEnd[1]-mStart[1])/(mSimEnd[1]-mSimStart[1]), (mEnd[2]-mStart[2])/(mSimEnd[2]-mSimStart[2])); + ntlVec3Gfx trans = mStart; + time = 0.; // doesnt matter + + for(size_t t=0; t *dparts; + if(t==0) { + dparts = &mParts; + } else { + dparts = &mPrevs[t-1]; + } + //errMsg("TRAILT","prevs"<size() ); + + gfxReal partscale = mPartScale; + if(t>1) { + partscale *= (gfxReal)(mPrevs.size()+1-t) / (gfxReal)(mPrevs.size()+1); + } + gfxReal partNormSize = 0.01 * partscale; + //for(size_t i=0; isize(); i++) { + ParticleObject *p = &( (*dparts)[i] ); // mParts[i]; + + if(mShowOnly!=10) { + // 10=show only deleted + if( p->getActive()==false ) continue; + } else { + if( p->getActive()==true ) continue; + } + int type = p->getType(); + if(mShowOnly>0) { + switch(mShowOnly) { + case 1: if(!(type&PART_BUBBLE)) continue; break; + case 2: if(!(type&PART_DROP)) continue; break; + case 3: if(!(type&PART_INTER)) continue; break; + case 4: if(!(type&PART_FLOAT)) continue; break; + case 5: if(!(type&PART_TRACER)) continue; break; + } + } else { + // by default dont display inter + if(type&PART_INTER) continue; + } + + pcnt++; + ntlVec3Gfx pnew = p->getPos(); + if(type&PART_FLOAT) { // WARNING same handling for dump! + if(p->getStatus()&PART_IN) { pnew[2] += 0.8; } // offset for display + // add one gridcell offset + //pnew[2] += 1.0; + } +#if LBMDIM==2 + pnew[2] += 0.001; // DEBUG + pnew[2] += 0.009; // DEBUG +#endif + + ntlVec3Gfx pdir = p->getVel(); + gfxReal plen = normalize( pdir ); + if( plen < 1e-05) pdir = ntlVec3Gfx(-1.0 ,0.0 ,0.0); + ntlVec3Gfx pos = (*mpTrafo) * pnew; + gfxReal partsize = 0.0; + if(debugParts) errMsg("DebugParts"," i"< class ntlMatrix4x4; + +// particle types +#define PART_BUBBLE (1<< 1) +#define PART_DROP (1<< 2) +#define PART_INTER (1<< 3) +#define PART_FLOAT (1<< 4) +#define PART_TRACER (1<< 5) + +// particle state +#define PART_IN (1<< 8) +#define PART_OUT (1<< 9) +#define PART_INACTIVE (1<<10) +#define PART_OUTFLUID (1<<11) + +// defines for particle movement +#define MOVE_FLOATS 1 +#define FLOAT_JITTER 0.03 +//#define FLOAT_JITTER 0.0 + +extern int ParticleObjectIdCnt; + +//! A single particle +class ParticleObject +{ + public: + //! Standard constructor + inline ParticleObject(ntlVec3Gfx mp) : + mPos(mp),mVel(0.0), mSize(1.0), mStatus(0),mLifeTime(0),mpNext(NULL) + { mId = ParticleObjectIdCnt++; }; + //! Copy constructor + inline ParticleObject(const ParticleObject &a) : + mPos(a.mPos), mVel(a.mVel), mSize(a.mSize), + mStatus(a.mStatus), + mLifeTime(a.mLifeTime), mpNext(NULL) + { mId = ParticleObjectIdCnt++; }; + //! Destructor + inline ~ParticleObject() { /* empty */ }; + + //! add vector to position + inline void advance(float vx, float vy, float vz) { + mPos[0] += vx; mPos[1] += vy; mPos[2] += vz; } + inline void advanceVec(ntlVec3Gfx v) { + mPos[0] += v[0]; mPos[1] += v[1]; mPos[2] += v[2]; } + //! advance with own velocity + inline void advanceVel() { mPos += mVel; } + //! add acceleration to velocity + inline void addToVel(ntlVec3Gfx acc) { mVel += acc; } + + //! get/set vector to position + inline ntlVec3Gfx getPos() { return mPos; } + inline void setPos(ntlVec3Gfx set) { mPos=set; } + //! set velocity + inline void setVel(ntlVec3Gfx set) { mVel = set; } + //! set velocity + inline void setVel(gfxReal x, gfxReal y, gfxReal z) { mVel = ntlVec3Gfx(x,y,z); } + //! get velocity + inline ntlVec3Gfx getVel() { return mVel; } + + //! get/set size value + inline gfxReal getSize() { return mSize; } + inline void setSize(gfxReal set) { mSize=set; } + + //! get/set next pointer + inline ParticleObject* getNext() { return mpNext; } + inline void setNext(ParticleObject* set) { mpNext=set; } + + //! get whole flags + inline int getFlags() const { return mStatus; } + //! get status (higher byte) + inline int getStatus() const { return (mStatus&0xFF00); } + //! set status (higher byte) + inline void setStatus(int set) { mStatus = set|(mStatus&0x00FF); } + //! get type (lower byte) + inline int getType() const { return (mStatus&0x00FF); } + //! set type (lower byte) + inline void setType(int set) { mStatus = set|(mStatus&0xFF00); } + //! get active flag + inline bool getActive() const { return ((mStatus&PART_INACTIVE)==0); } + //! set active flag + inline void setActive(bool set) { + if(set) mStatus &= (~PART_INACTIVE); + else mStatus |= PART_INACTIVE; + } + //! get influid flag + inline bool getInFluid() const { return ((mStatus&PART_OUTFLUID)==0); } + //! set influid flag + inline void setInFluid(bool set) { + if(set) mStatus &= (~PART_OUTFLUID); + else mStatus |= PART_OUTFLUID; + } + //! get/set lifetime + inline float getLifeTime() const { return mLifeTime; } + //! set type (lower byte) + inline void setLifeTime(float set) { mLifeTime = set; } + + inline int getId() const { return mId; } + + static inline float getMass(float size) { + return 4.0/3.0 * M_PI* (size)*(size)*(size); // mass: 4/3 pi r^3 rho + } + + protected: + + /*! only for debugging */ + int mId; + /*! the particle position */ + ntlVec3Gfx mPos; + /*! the particle velocity */ + ntlVec3Gfx mVel; + /*! size / mass of particle */ + gfxReal mSize; + /*! particle status */ + int mStatus; + /*! count survived time steps */ + float mLifeTime; + + /* for list constructions */ + ParticleObject *mpNext; +}; + + +//! A whole particle array +class ParticleTracer : + public ntlGeometryObject +{ + public: + //! Standard constructor + ParticleTracer(); + //! Destructor + ~ParticleTracer(); + + //! add a particle at this position + void addParticle(float x, float y, float z); + //! add/copy a particle from inited struct + void addFullParticle(ParticleObject &np); + + //! draw the particle array + void draw(); + + //! parse settings from attributes (dont use own list!) + void parseAttrList( AttributeList *att ); + + //! adapt time step by rescaling velocities + void adaptPartTimestep(float factor); + + // access funcs + + //! get the number of particles + inline int getNumParticles() { return mParts.size(); } + //! set/get the number of particles + inline void setNumInitialParticles(int set) { mNumInitialParts=set; } + inline int getNumInitialParticles() { return mNumInitialParts; } + + //! iterate over all newest particles (for advancing positions) + inline vector::iterator getParticlesBegin() { return mParts.begin(); } + //! end iterator for newest particles + inline vector::iterator getParticlesEnd() { return mParts.end(); } + //! end iterator for newest particles + inline ParticleObject* getLast() { return &(mParts[ mParts.size()-1 ]); } + + /*! set geometry start (for renderer) */ + inline void setStart(ntlVec3Gfx set) { mStart = set; initTrafoMatrix(); } + /*! set geometry end (for renderer) */ + inline void setEnd(ntlVec3Gfx set) { mEnd = set; initTrafoMatrix(); } + /*! get values */ + inline ntlVec3Gfx getStart() { return mStart; } + /*! set geometry end (for renderer) */ + inline ntlVec3Gfx getEnd() { return mEnd; } + + /*! set simulation domain start */ + inline void setSimStart(ntlVec3Gfx set) { mSimStart = set; initTrafoMatrix(); } + /*! set simulation domain end */ + inline void setSimEnd(ntlVec3Gfx set) { mSimEnd = set; initTrafoMatrix(); } + + /*! set/get dump flag */ + inline void setDumpParts(bool set) { mDumpParts = set; } + inline bool getDumpParts() { return mDumpParts; } + /*! set/get dump text file */ + inline void setDumpTextFile(string set) { mDumpTextFile = set; } + inline string getDumpTextFile() { return mDumpTextFile; } + /*! set/get dump text interval */ + inline void setDumpTextInterval(float set) { mDumpTextInterval = set; } + inline float getDumpTextInterval() { return mDumpTextInterval; } + /*! set/get init times */ + inline void setInitStart(float set) { mInitStart = set; } + inline float getInitStart() { return mInitStart; } + inline void setInitEnd(float set) { mInitEnd = set; } + inline float getInitEnd() { return mInitEnd; } + + //! set the particle scaling factor + inline void setPartScale(float set) { mPartScale = set; } + + //! called after each frame to check if positions should be dumped + void checkDumpTextPositions(double simtime); + + // NTL geometry implementation + /*! Get the triangles from this object */ + virtual void getTriangles(double t, vector *triangles, + vector *vertices, + vector *normals, int objectId ); + + virtual void notifyOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename,double simtime); + + // notify of next step for trails + void checkTrails(double time); + // free deleted particles + void cleanup(); + + protected: + + /*! the particle array (for multiple timesteps) */ + vector mParts; + + /*! size of the particles to display */ + float mPartSize; + + /*! start and end vectors for the triangulation region to create particles in */ + ntlVec3Gfx mStart, mEnd; + + /*! start and end vectors of the simulation domain */ + ntlVec3Gfx mSimStart, mSimEnd; + + /*! scaling param for particles */ + float mPartScale; + /*! head and tail distance for particle shapes */ + float mPartHeadDist, mPartTailDist; + /*! no of segments for particle cone */ + int mPartSegments; + /*! use length/absval of values to scale particles? */ + int mValueScale; + /*! value length maximal cutoff value, for mValueScale==2 */ + float mValueCutoffTop; + /*! value length minimal cutoff value, for mValueScale==2 */ + float mValueCutoffBottom; + + /*! dump particles (or certain types of) to disk? */ + int mDumpParts; + /*! text dump output file */ + string mDumpTextFile; + /*! text dump interval, start at t=0, dumping active if >0 */ + float mDumpTextInterval; + float mDumpTextLastTime; + int mDumpTextCount; + /*! show only a certain type (debugging) */ + int mShowOnly; + /*! no. of particles to init */ + int mNumInitialParts; + + //! transform matrix + ntlMatrix4x4 *mpTrafo; + /*! init sim/pos transformation */ + void initTrafoMatrix(); + + //! init time distribution start/end + float mInitStart, mInitEnd; + + /*! the particle array (for multiple timesteps) */ + vector< vector > mPrevs; + /* prev pos save interval */ + float mTrailTimeLast, mTrailInterval; + int mTrailLength; +}; + +#define NTL_PARTICLETRACER_H +#endif + diff --git a/intern/elbeem/intern/simulation_object.cpp b/intern/elbeem/intern/simulation_object.cpp new file mode 100644 index 00000000000..2ff600a36d4 --- /dev/null +++ b/intern/elbeem/intern/simulation_object.cpp @@ -0,0 +1,458 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Basic interface for all simulation modules + * + *****************************************************************************/ + +#include "simulation_object.h" +#include "solver_interface.h" +#include "ntl_bsptree.h" +#include "ntl_ray.h" +#include "ntl_world.h" +#include "solver_interface.h" +#include "particletracer.h" +#include "elbeem.h" +#include /* exit(3) - also in linux */ + +#ifdef _WIN32 +#else +#include +#endif + + +//! lbm factory functions +LbmSolverInterface* createSolver(); + + +/****************************************************************************** + * Constructor + *****************************************************************************/ +SimulationObject::SimulationObject() : + ntlGeometryShader(), + mGeoStart(-100.0), mGeoEnd(100.0), + mpGiTree(NULL), mpGiObjects(NULL), + mpGlob(NULL), + mPanic( false ), + mDebugType( 1 /* =FLUIDDISPNothing*/ ), + mpLbm(NULL), mpParam( NULL ), + mShowSurface(true), mShowParticles(false), + mSelectedCid( NULL ), + mpElbeemSettings( NULL ) + +{ + mpParam = new Parametrizer(); + //for(int i=0; igetSimScene(); + mpGiObjects = scene->getObjects(); + + if(mpGiTree != NULL) delete mpGiTree; + char treeFlag = (1<<(mGeoInitId+4)); + mpGiTree = new ntlTree( 20, 4, // warning - fixed values for depth & maxtriangles here... + scene, treeFlag ); + exit(1); // unused!? overriden by solver interface +} + +/*****************************************************************************/ +/*! destroy tree etc. when geometry init done */ +/*****************************************************************************/ +void SimulationObject::freeGeoTree() { + if(mpGiTree != NULL) delete mpGiTree; +} + + + +// copy & remember settings for later use +void SimulationObject::copyElbeemSettings(elbeemSimulationSettings *settings) { + mpElbeemSettings = new elbeemSimulationSettings; + *mpElbeemSettings = *settings; + + mGeoInitId = settings->domainId+1; + debMsgStd("SimulationObject",DM_MSG,"mGeoInitId="<readString("solver", mSolverType, "SimulationObject","mSolverType", false ); + + mpLbm = createSolver(); + /* check lbm pointer */ + if(mpLbm == NULL) { + errFatal("SimulationObject::initializeLbmSimulation","Unable to init LBM solver! ", SIMWORLD_INITERROR); + return 2; + } + debMsgStd("SimulationObject::initialized",DM_MSG,"IdStr:"<getIdString() <<" LBM solver! ", 2); + + mpParts = new ParticleTracer(); + + // for non-param simulations + mpLbm->setParametrizer( mpParam ); + mpParam->setAttrList( getAttributeList() ); + // not needed.. done in solver_init: mpParam->setSize ... in solver_interface + mpParam->parseAttrList(); + + mpLbm->setAttrList( getAttributeList() ); + mpLbm->setSwsAttrList( getSwsAttributeList() ); + mpLbm->parseAttrList(); + mpParts->parseAttrList( getAttributeList() ); + + if(! isSimworldOk() ) return 3; + mpParts->setName( getName() + "_part" ); + mpParts->initialize( glob ); + if(! isSimworldOk() ) return 4; + + // init material settings + string matMc("default"); + matMc = mpAttrs->readString("material_surf", matMc, "SimulationObject","matMc", false ); + mShowSurface = mpAttrs->readInt("showsurface", mShowSurface, "SimulationObject","mShowSurface", false ); + mShowParticles = mpAttrs->readInt("showparticles", mShowParticles, "SimulationObject","mShowParticles", false ); + + checkBoundingBox( mGeoStart, mGeoEnd, "SimulationObject::initializeSimulation" ); + mpLbm->setLbmInitId( mGeoInitId ); + mpLbm->setGeoStart( mGeoStart ); + mpLbm->setGeoEnd( mGeoEnd ); + mpLbm->setRenderGlobals( mpGlob ); + mpLbm->setName( getName() + "_lbm" ); + mpLbm->setParticleTracer( mpParts ); + if(mpElbeemSettings) { + // set further settings from API struct init + if(mpElbeemSettings->outputPath) this->mOutFilename = string(mpElbeemSettings->outputPath); + mpLbm->initDomainTrafo( mpElbeemSettings->surfaceTrafo ); + mpLbm->setSmoothing(1.0 * mpElbeemSettings->surfaceSmoothing, 1.0 * mpElbeemSettings->surfaceSmoothing); + mpLbm->setIsoSubdivs(mpElbeemSettings->surfaceSubdivs); + mpLbm->setSizeX(mpElbeemSettings->resolutionxyz); + mpLbm->setSizeY(mpElbeemSettings->resolutionxyz); + mpLbm->setSizeZ(mpElbeemSettings->resolutionxyz); + mpLbm->setPreviewSize(mpElbeemSettings->previewresxyz); + mpLbm->setRefinementDesired(mpElbeemSettings->maxRefine); + mpLbm->setGenerateParticles(mpElbeemSettings->generateParticles); + // set initial particles + mpParts->setNumInitialParticles(mpElbeemSettings->numTracerParticles); + + string dinitType = string("no"); + if (mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_PARTSLIP) dinitType = string("part"); + else if(mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_FREESLIP) dinitType = string("free"); + else /*if(mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_NOSLIP)*/ dinitType = string("no"); + mpLbm->setDomainBound(dinitType); + mpLbm->setDomainPartSlip(mpElbeemSettings->domainobsPartslip); + mpLbm->setDumpVelocities(mpElbeemSettings->generateVertexVectors); + mpLbm->setFarFieldSize(mpElbeemSettings->farFieldSize); + debMsgStd("SimulationObject::initialize",DM_MSG,"Added domain bound: "<generateVertexVectors<<","<getDumpVelocities(), 9 ); + + debMsgStd("SimulationObject::initialize",DM_MSG,"Set ElbeemSettings values "<getGenerateParticles(),10); + } + + if(! mpLbm->initializeSolverMemory() ) { errMsg("SimulationObject::initialize","initializeSolverMemory failed"); mPanic=true; return 10; } + if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverMemory status"); mPanic=true; return 11; } + if(! mpLbm->initializeSolverGrids() ) { errMsg("SimulationObject::initialize","initializeSolverGrids failed"); mPanic=true; return 12; } + if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverGrids status"); mPanic=true; return 13; } + if(! mpLbm->initializeSolverPostinit() ) { errMsg("SimulationObject::initialize","initializeSolverPostin failed"); mPanic=true; return 14; } + if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverPostin status"); mPanic=true; return 15; } + + // print cell type stats + bool printStats = true; + if(glob_mpnum>0) printStats=false; // skip in this case + if(printStats) { + const int jmax = sizeof(CellFlagType)*8; + int totalCells = 0; + int flagCount[jmax]; + for(int j=0; jgetFirstCell(); + for(; mpLbm->noEndCell( cid ); + mpLbm->advanceCell( cid ) ) { + int flag = mpLbm->getCellFlag(cid,0); + int flag2 = mpLbm->getCellFlag(cid,1); + if(flag != flag2) { + diffInits++; + } + for(int j=0; jdeleteCellIterator( &cid ); + + char charNl = '\n'; + debugOutNnl("SimulationObject::initializeLbmSimulation celltype stats: " <0) { + out<<"\t" << flagCount[j] <<" x "<< convertCellFlagType2String( (CellFlagType)(1< 0) { + debMsgStd("SimulationObject::initializeLbmSimulation",DM_MSG,"celltype Warning: Diffinits="<setStart( mGeoStart );? mpParts->setEnd( mGeoEnd );? + mpParts->setStart( mpLbm->getGeoStart() ); + mpParts->setEnd( mpLbm->getGeoEnd() ); + mpParts->setCastShadows( false ); + mpParts->setReceiveShadows( false ); + mpParts->searchMaterial( glob->getMaterials() ); + + // this has to be inited here - before, the values might be unknown + IsoSurface *surf = mpLbm->getSurfaceGeoObj(); + if(surf) { + surf->setName( "final" ); // final surface mesh + // warning - this might cause overwriting effects for multiple sims and geom dump... + surf->setCastShadows( true ); + surf->setReceiveShadows( false ); + surf->searchMaterial( glob->getMaterials() ); + if(mShowSurface) mObjects.push_back( surf ); + } + +#ifdef ELBEEM_PLUGIN + mShowParticles=1; // for e.g. dumping +#endif // ELBEEM_PLUGIN + if((mpLbm->getGenerateParticles()>0.0)||(mpParts->getNumInitialParticles()>0)) { + mShowParticles=1; + mpParts->setDumpParts(true); + } + //debMsgStd("SimulationObject::init",DM_NOTIFY,"Using envvar ELBEEM_DUMPPARTICLE to set mShowParticles, DEBUG!",1); + //} // DEBUG ENABLE!!!!!!!!!! + if(mShowParticles) { + mObjects.push_back(mpParts); + } + + // add objects to display for debugging (e.g. levelset particles) + vector debugObjs = mpLbm->getDebugObjects(); + for(size_t i=0;isetCastShadows( false ); + debugObjs[i]->setReceiveShadows( false ); + debugObjs[i]->searchMaterial( glob->getMaterials() ); + mObjects.push_back( debugObjs[i] ); + debMsgStd("SimulationObject::init",DM_NOTIFY,"Added debug obj "<getName(), 10 ); + } + return 0; +} + +/*! set current frame */ +void SimulationObject::setFrameNum(int num) { + // advance parametrizer + mpParam->setFrameNum(num); +} + +/****************************************************************************** + * simluation interface: advance simulation another step (whatever delta time that might be) + *****************************************************************************/ +void SimulationObject::step( void ) +{ + if(mpParam->getCurrentAniFrameTime()>0.0) { + // dont advance for stopped time + mpLbm->step(); + mTime += mpParam->getTimestep(); +//if(mTime>0.001) { errMsg("DEBUG!!!!!!!!","quit mlsu..."); exit(1); } // PROFILE DEBUG TEST! + } + if(mpLbm->getPanic()) mPanic = true; + + checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0); + //if((mpElbeemSettings)&&(mpElbeemSettings->runsimCallback)) { + //int ret = (mpElbeemSettings->runsimCallback)(mpElbeemSettings->runsimUserData, FLUIDSIM_CBSTATUS_STEP, 0); + //errMsg("runSimulationCallback cbtest1"," "<getName()<<" ret="<prepareVisualization(); +} + + +/******************************************************************************/ +/* get current start simulation time */ +double SimulationObject::getStartTime( void ) { + //return mpParam->calculateAniStart(); + return mpParam->getAniStart(); +} +/* get time for a single animation frame */ +double SimulationObject::getFrameTime( int frame ) { + return mpParam->getAniFrameTime(frame); +} +/* get time for a single time step */ +double SimulationObject::getTimestep( void ) { + return mpParam->getTimestep(); +} + + +/****************************************************************************** + * return a pointer to the geometry object of this simulation + *****************************************************************************/ +//ntlGeometryObject *SimulationObject::getGeometry() { return mpMC; } +vector::iterator +SimulationObject::getObjectsBegin() +{ + return mObjects.begin(); +} +vector::iterator +SimulationObject::getObjectsEnd() +{ + return mObjects.end(); +} + + + + + +/****************************************************************************** + * GUI - display debug info + *****************************************************************************/ + +void SimulationObject::drawDebugDisplay() { +#ifndef NOGUI + if(!getVisible()) return; + + //if( mDebugType > (MAX_DEBDISPSET-1) ){ errFatal("SimulationObject::drawDebugDisplay","Invalid debug type!", SIMWORLD_GENERICERROR); return; } + //mDebDispSet[ mDebugType ].on = true; + //errorOut( mDebugType <<"//"<< mDebDispSet[mDebugType].type ); + mpLbm->debugDisplay( mDebugType ); + + //::lbmMarkedCellDisplay<>( mpLbm ); + mpLbm->lbmMarkedCellDisplay(); +#endif +} + +/* GUI - display interactive info */ +void SimulationObject::drawInteractiveDisplay() +{ +#ifndef NOGUI + if(!getVisible()) return; + if(mSelectedCid) { + // in debugDisplayNode if dispset is on is ignored... + mpLbm->debugDisplayNode( FLUIDDISPGrid, mSelectedCid ); + } +#endif +} + + +/*******************************************************************************/ +// GUI - handle mouse movement for selection +/*******************************************************************************/ +void SimulationObject::setMousePos(int x,int y, ntlVec3Gfx org, ntlVec3Gfx dir) +{ + normalize( dir ); + // assume 2D sim is in XY plane... + + double zplane = (mGeoEnd[2]-mGeoStart[2])*0.5; + double zt = (zplane-org[2]) / dir[2]; + ntlVec3Gfx pos( + org[0]+ dir[0] * zt, + org[1]+ dir[1] * zt, 0.0); + + mSelectedCid = mpLbm->getCellAt( pos ); + //errMsg("SMP ", mName<< x<<" "<( mpLbm, mSelectedCid, mpLbm->getNodeInfoString() ); + mpLbm->debugPrintNodeInfo( mSelectedCid ); + } +} + +/*! notify object that dump is in progress (e.g. for field dump) */ +void SimulationObject::notifyShaderOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename) { + if(!mpLbm) return; + + mpLbm->notifySolverOfDump(dumptype, frameNr,frameNrStr,outfilename); + checkCallerStatus(FLUIDSIM_CBSTATUS_NEWFRAME, frameNr); +} + +/*! check status (e.g. stop/abort) from calling program, returns !=0 if sth. happened... */ +int SimulationObject::checkCallerStatus(int status, int frame) { + //return 0; // DEBUG + int ret = 0; + if((mpElbeemSettings)&&(mpElbeemSettings->runsimCallback)) { + ret = (mpElbeemSettings->runsimCallback)(mpElbeemSettings->runsimUserData, status,frame); + if(ret!=FLUIDSIM_CBRET_CONTINUE) { + if(ret==FLUIDSIM_CBRET_STOP) { + debMsgStd("SimulationObject::notifySolverOfDump",DM_NOTIFY,"Got stop signal from caller",1); + setElbeemState( SIMWORLD_STOP ); + } + else if(ret==FLUIDSIM_CBRET_ABORT) { + errFatal("SimulationObject::notifySolverOfDump","Got abort signal from caller, aborting...", SIMWORLD_GENERICERROR ); + mPanic = 1; + } + else { + errMsg("SimulationObject::notifySolverOfDump","Invalid callback return value: "<getName()<<" ret="<::iterator getObjectsBegin(); + virtual vector::iterator getObjectsEnd(); + + + /*! simluation interface: advance simulation another step (whatever delta time that might be) */ + virtual void step( void ); + /*! prepare visualization of simulation for e.g. raytracing */ + virtual void prepareVisualization( void ); + + /*! GUI - display debug info */ + virtual void drawDebugDisplay(); + /*! GUI - display interactive info */ + virtual void drawInteractiveDisplay(); + /*! GUI - handle mouse movement for selection */ + virtual void setMousePos(int x,int y, ntlVec3Gfx org, ntlVec3Gfx dir); + virtual void setMouseClick(); + + /*! get current start simulation time */ + double getStartTime( void ); + /*! get time for a single animation frame */ + double getFrameTime( int frame ); + /*! get time for a single time step in the simulation */ + double getTimestep( void ); + + //! access solver + LbmSolverInterface *getSolver(){ return mpLbm; } + + protected: + + /*! current time in the simulation */ + double mTime; + + /*! for display - start and end vectors for geometry */ + ntlVec3Gfx mGeoStart, mGeoEnd; + + /*! geometry init id */ + //? int mGeoInitId; + /*! tree object for geomerty initialization */ + ntlTree *mpGiTree; + /*! object vector for geo init */ + vector *mpGiObjects; + /*! remember globals */ + ntlRenderGlobals *mpGlob; + + /*! simulation panic on/off */ + bool mPanic; + + /*! debug info to display */ + int mDebugType; + + /*! pointer to the lbm solver */ + LbmSolverInterface *mpLbm; + + /*! parametrizer for lbm solver */ + Parametrizer *mpParam; + + /*! particle tracing object */ + ParticleTracer *mpParts; + + /*! show parts of the simulation toggles */ + bool mShowSurface; + bool mShowParticles; + + /*! debug display settings */ + int mDebDispSetting; + + /*! pointer to identifier of selected node */ + CellIdentifierInterface *mSelectedCid; + + /*! storage of API settings */ + elbeemSimulationSettings *mpElbeemSettings; + + public: + + // debug display setting funtions + + /*! set type of info to display */ + inline void setDebugDisplay(int disp) { mDebugType = disp; } + inline int getDebugDisplay() { return mDebugType; } + + /* miscelleanous access functions */ + + /*! init parametrizer for anim step length */ + void initParametrizer(Parametrizer *set) { mpParam = set; } + /*! init parametrizer for anim step length */ + Parametrizer *getParametrizer() { return mpParam; } + + /*! check status (e.g. stop/abort) from calling program, returns !=0 if sth. happened... */ + // parameters same as elbeem runsimCallback + int checkCallerStatus(int status, int frame); + + /*! get bounding box of fluid for GUI */ + virtual inline ntlVec3Gfx *getBBStart() { return &mGeoStart; } + virtual inline ntlVec3Gfx *getBBEnd() { return &mGeoEnd; } + +}; + + +#endif + + + diff --git a/intern/elbeem/intern/solver_adap.cpp b/intern/elbeem/intern/solver_adap.cpp new file mode 100644 index 00000000000..ef516a578bd --- /dev/null +++ b/intern/elbeem/intern/solver_adap.cpp @@ -0,0 +1,1279 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Adaptivity functions + * + *****************************************************************************/ + +#include "solver_class.h" +#include "solver_relax.h" +#include "particletracer.h" + + + +/*****************************************************************************/ +//! coarse step functions +/*****************************************************************************/ + + + +void LbmFsgrSolver::coarseCalculateFluxareas(int lev) +{ + FSGR_FORIJK_BOUNDS(lev) { + if( RFLAG(lev, i,j,k,mLevel[lev].setCurr) & CFFluid) { + if( RFLAG(lev+1, i*2,j*2,k*2,mLevel[lev+1].setCurr) & CFGrFromCoarse) { + LbmFloat totArea = mFsgrCellArea[0]; // for l=0 + for(int l=1; lcDirNum; l++) { + int ni=(2*i)+this->dfVecX[l], nj=(2*j)+this->dfVecY[l], nk=(2*k)+this->dfVecZ[l]; + if(RFLAG(lev+1, ni,nj,nk, mLevel[lev+1].setCurr)& + (CFGrFromCoarse|CFUnused|CFEmpty) //? (CFBnd|CFEmpty|CFGrFromCoarse|CFUnused) + ) { + totArea += mFsgrCellArea[l]; + } + } // l + QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) = totArea; + //continue; + } else + if( RFLAG(lev+1, i*2,j*2,k*2,mLevel[lev+1].setCurr) & (CFEmpty|CFUnused)) { + QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) = 1.0; + //continue; + } else { + QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) = 0.0; + } + //errMsg("DFINI"," at l"<mSilent){ debMsgStd("coarseCalculateFluxareas",DM_MSG,"level "<getName().c_str(),"Debug")){ errMsg("DEBUG","DEBUG!!!!!!!!!!!!!!!!!!!!!!!"); } + + for(int k= getForZMin1(); k< getForZMax1(lev); ++k) { + for(int j=1;j remove + if( ((*pFlagSrc) & (CFGrFromCoarse)) ) { + bool invNb = false; + FORDF1 { if(RFLAG_NB(lev, i, j, k, SRCS(lev), l) & CFUnused) { invNb = true; } } + if(!invNb) { + // WARNING - this modifies source flag array... + *pFlagSrc = CFFluid|CFGrNorm; +#if ELBEEM_PLUGIN!=1 + errMsg("coarseAdvance","FC2NRM_CHECK Converted CFGrFromCoarse to Norm at "<mStepCnt & (1<<(mMaxRefine-lev)) ) ==1) { + FORDF0 { RAC(tcel,l) = RAC(ccel,l); } + } else { + interpolateCellFromCoarse( lev, i,j,k, TSET(lev), 0.0, CFFluid|CFGrFromCoarse, false); + this->mNumUsedCells++; + } + continue; // interpolateFineFromCoarse test! + } // interpolateFineFromCoarse test! old INTCFCOARSETEST==1 + + if( ((*pFlagSrc) & (CFFluid)) ) { + ccel = RACPNT(lev, i,j,k ,SRCS(lev)); + tcel = RACPNT(lev, i,j,k ,TSET(lev)); + + if( ((*pFlagSrc) & (CFGrFromFine)) ) { + FORDF0 { RAC(tcel,l) = RAC(ccel,l); } // always copy...? + continue; // comes from fine grid + } + // also ignore CFGrFromCoarse + else if( ((*pFlagSrc) & (CFGrFromCoarse)) ) { + FORDF0 { RAC(tcel,l) = RAC(ccel,l); } // always copy...? + continue; + } + + OPTIMIZED_STREAMCOLLIDE; + *pFlagDst |= CFNoBndFluid; // test? + calcCurrentVolume += RAC(ccel,dFlux); + calcCurrentMass += RAC(ccel,dFlux)*rho; + //ebugMarkCell(lev+1, 2*i+1,2*j+1,2*k ); +#if FSGR_STRICT_DEBUG==1 + if(rho<-1.0){ debugMarkCell(lev, i,j,k ); + errMsg("INVRHOCELL_CHECK"," l"<mNumUsedCells++; + + } + } + pFlagSrc+=2; // after x + pFlagDst+=2; // after x + ccel += (QCELLSTEP*2); + tcel += (QCELLSTEP*2); + } + pFlagSrc+= mLevel[lev].lSizex*2; // after y + pFlagDst+= mLevel[lev].lSizex*2; // after y + ccel += (QCELLSTEP*mLevel[lev].lSizex*2); + tcel += (QCELLSTEP*mLevel[lev].lSizex*2); + } // all cell loop k,j,i + + + //errMsg("coarseAdvance","level "<mSilent){ errMsg("coarseAdvance","level "<mNumUsedCells++; + } // from fine & fluid + else { + if(RFLAG(lev+1, 2*i,2*j,2*k,srcSet) & CFGrFromCoarse) { + RFLAG(lev, i,j,k,dstSet) |= CFGrToFine; + } else { + RFLAG(lev, i,j,k,dstSet) &= (~CFGrToFine); + } + } + } // & fluid + }}} + if(!this->mSilent){ errMsg("coarseRestrictFromFine"," from l"<<(lev+1)<<",s"<mMaxRefine)) return false; + bool change = false; + { // refinement, PASS 1-3 + + //bool nbsok; + // FIXME remove TIMEINTORDER ? + LbmFloat interTime = 0.0; + // update curr from other, as streaming afterwards works on curr + // thus read only from srcSet, modify other + const int srcSet = mLevel[lev].setOther; + const int dstSet = mLevel[lev].setCurr; + const int srcFineSet = mLevel[lev+1].setCurr; + const bool debugRefinement = false; + + // use //template functions for 2D/3D + /*if(strstr(this->getName().c_str(),"Debug")) + if(lev+1==mMaxRefine) { // mixborder + for(int l=0;((lcDirNum) && (!removeFromFine)); l++) { // FARBORD + int ni=2*i+2*this->dfVecX[l], nj=2*j+2*this->dfVecY[l], nk=2*k+2*this->dfVecZ[l]; + if(RFLAG(lev+1, ni,nj,nk, srcFineSet)&CFBnd) { // NEWREFT + removeFromFine=true; + } + } + } // FARBORD */ + for(int k= getForZMin1(); k< getForZMax1(lev); ++k) { + for(int j=1;jcDirNum; l++) { + int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; + //errMsg("performRefinement","On lev:"< remove + + if(RFLAG(lev, i,j,k, srcSet) & CFGrFromCoarse) { + + // from coarse cells without unused nbs are not necessary...! -> remove + bool invNb = false; + bool fluidNb = false; + for(int l=1; lcDirNum; l++) { + if(RFLAG_NB(lev, i, j, k, srcSet, l) & CFUnused) { invNb = true; } + if(RFLAG_NB(lev, i, j, k, srcSet, l) & (CFGrNorm)) { fluidNb = true; } + } + if(!invNb) { + // no unused cells around -> calculate normally from now on + RFLAG(lev, i,j,k, dstSet) = CFFluid|CFGrNorm; + if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev, i, j, k); + change=true; + mNumFsgrChanges++; + } // from advance + if(!fluidNb) { + // no fluid cells near -> no transfer necessary + RFLAG(lev, i,j,k, dstSet) = CFUnused; + //RFLAG(lev, i,j,k, mLevel[lev].setOther) = CFUnused; // FLAGTEST + if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev, i, j, k); + change=true; + mNumFsgrChanges++; + } // from advance + + + // dont allow double transfer + // this might require fixing the neighborhood + if(RFLAG(lev+1, 2*i,2*j,2*k, srcFineSet)&(CFGrFromCoarse)) { + // dont turn CFGrFromFine above interface cells into CFGrNorm + //errMsg("performRefinement","Removing CFGrFromCoarse on lev"<0) RFLAG(lev-1, i/2,j/2,k/2, mLevel[lev-1].setCurr) &= (~CFGrToFine); // TODO add more of these? + if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev, i, j, k); + change=true; + mNumFsgrChanges++; + for(int l=1; lcDirNum; l++) { + int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; + if(RFLAG(lev, ni,nj,nk, srcSet)&(CFGrNorm)) { //ok + for(int m=1; mcDirNum; m++) { + int mi= ni +this->dfVecX[m], mj= nj +this->dfVecY[m], mk= nk +this->dfVecZ[m]; + if(RFLAG(lev, mi, mj, mk, srcSet)&CFUnused) { + // norm cells in neighborhood with unused nbs have to be new border... + RFLAG(lev, ni,nj,nk, dstSet) = CFFluid|CFGrFromCoarse; + if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev,ni,nj,nk); + } + } + // these alreay have valid values... + } + else if(RFLAG(lev, ni,nj,nk, srcSet)&(CFUnused)) { //ok + // this should work because we have a valid neighborhood here for now + interpolateCellFromCoarse(lev, ni, nj, nk, dstSet, interTime, CFFluid|CFGrFromCoarse, false); + if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev,ni,nj,nk); + mNumFsgrChanges++; + } + } // l + } // double transer + + } // from coarse + + } } } + // PASS 2 */ + + + // fix dstSet from fine cells here + // warning - checks CFGrFromFine on dstset changed before! + for(int k= getForZMin1(); k< getForZMax1(lev); ++k) { // TEST + for(int j=1;jcDirNum; l++) { + int bi=(2*i)+this->dfVecX[l], bj=(2*j)+this->dfVecY[l], bk=(2*k)+this->dfVecZ[l]; + if(RFLAG(lev+1, bi, bj, bk, srcFineSet)&(CFGrFromCoarse)) { + //errMsg("performRefinement","Removing CFGrFromCoarse on lev"<<(lev+1)<<" "<cDirNum; l++) { + int bi=(2*i)+this->dfVecX[l], bj=(2*j)+this->dfVecY[l], bk=(2*k)+this->dfVecZ[l]; + if( (RFLAG(lev+1, bi, bj, bk, srcFineSet)&CFFluid ) && + (!(RFLAG(lev+1, bi, bj, bk, srcFineSet)&CFGrFromCoarse)) ) { + // all unused nbs now of coarse have to be from coarse + for(int m=1; mcDirNum; m++) { + int mi= bi +this->dfVecX[m], mj= bj +this->dfVecY[m], mk= bk +this->dfVecZ[m]; + if(RFLAG(lev+1, mi, mj, mk, srcFineSet)&CFUnused) { + //errMsg("performRefinement","Changing CFUnused on lev"<<(lev+1)<<" "<mSilent){ errMsg("performRefinement"," for l"<mInitDone) { + for(int k= getForZMin1(); k< getForZMax1(lev); ++k) { + for(int j=1;j from fine conversion + bool changeToFromFine = false; + const CellFlagType notAllowed = (CFInter|CFGrFromFine|CFGrToFine); + CellFlagType reqType = CFGrNorm; + if(lev+1==mMaxRefine) reqType = CFNoBndFluid; + if( (RFLAG(lev+1, (2*i),(2*j),(2*k), dstFineSet) & reqType) && + (!(RFLAG(lev+1, (2*i),(2*j),(2*k), dstFineSet) & (notAllowed)) ) ){ + changeToFromFine=true; } + if(changeToFromFine) { + change = true; + mNumFsgrChanges++; + RFLAG(lev, i,j,k, srcSet) = CFFluid|CFGrFromFine; + if((LBMDIM==2)&&(debugCoarsening)) debugMarkCell(lev,i,j,k); + // same as restr from fine func! not necessary ?! + // coarseRestrictFromFine part + coarseRestrictCell(lev, i,j,k,srcSet, dstFineSet); + } + } // only check empty cells + }}} // TEST! + } // PASS 5 */ + + // use //template functions for 2D/3D + /*if(strstr(this->getName().c_str(),"Debug")) + if((nbsok)&&(lev+1==mMaxRefine)) { // mixborder + for(int l=0;((lcDirNum) && (nbsok)); l++) { // FARBORD + int ni=2*i+2*this->dfVecX[l], nj=2*j+2*this->dfVecY[l], nk=2*k+2*this->dfVecZ[l]; + if(RFLAG(lev+1, ni,nj,nk, dstFineSet)&CFBnd) { // NEWREFT + nbsok=false; + } + } + } // FARBORD */ + for(int k= getForZMin1(); k< getForZMax1(lev); ++k) { + for(int j=1;j remove + // perform check from coarseAdvance here? + if(RFLAG(lev, i,j,k, srcSet) & CFGrFromFine) { + // remove from fine cells now that are completely in fluid + // FIXME? check that new from fine in performRefinement never get deleted here afterwards? + // or more general, one cell never changed more than once? + const CellFlagType notAllowed = (CFInter|CFGrFromFine|CFGrToFine); + //const CellFlagType notNbAllowed = (CFInter|CFBnd|CFGrFromFine); unused + CellFlagType reqType = CFGrNorm; + if(lev+1==mMaxRefine) reqType = CFNoBndFluid; + + nbsok = true; + for(int l=0; lcDirNum && nbsok; l++) { + int ni=(2*i)+this->dfVecX[l], nj=(2*j)+this->dfVecY[l], nk=(2*k)+this->dfVecZ[l]; + if( (RFLAG(lev+1, ni,nj,nk, dstFineSet) & reqType) && + (!(RFLAG(lev+1, ni,nj,nk, dstFineSet) & (notAllowed)) ) ){ + // ok + } else { + nbsok=false; + } + // FARBORD + } + // dont turn CFGrFromFine above interface cells into CFGrNorm + // now check nbs on same level + for(int l=1; lcDirNum && nbsok; l++) { + int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; + if(RFLAG(lev, ni,nj,nk, srcSet)&(CFFluid)) { //ok + } else { + nbsok = false; + } + } // l + + if(nbsok) { + // conversion to coarse fluid cell + change = true; + mNumFsgrChanges++; + RFLAG(lev, i,j,k, srcSet) = CFFluid|CFGrNorm; + // dfs are already ok... + //if(this->mInitDone) errMsg("performCoarsening","CFGrFromFine changed to CFGrNorm at lev"<mInitDone) errMsg("performCoarsening","CFGrFromFine subcube init center unused set l"<cDirNum; l++) { + int dstni=dstx+this->dfVecX[l], dstnj=dsty+this->dfVecY[l], dstnk=dstz+this->dfVecZ[l]; + if(RFLAG(dstlev, dstni,dstnj,dstnk, dstFineSet)&(CFFluid)) { + RFLAG(dstlev, dstni,dstnj,dstnk, dstFineSet) = CFFluid|CFGrFromCoarse; + } + if(RFLAG(dstlev, dstni,dstnj,dstnk, dstFineSet)&(CFInter)) { + //if(this->mInitDone) errMsg("performCoarsening","CFGrFromFine subcube init CHECK Warning - deleting interface cell..."); + this->mFixMass += QCELL( dstlev, dstni,dstnj,dstnk, dstFineSet, dMass); + RFLAG(dstlev, dstni,dstnj,dstnk, dstFineSet) = CFFluid|CFGrFromCoarse; + } + } // l + + // again check nb flags of all surrounding cells to see if any from coarse + // can be convted to unused + for(int l=1; lcDirNum; l++) { + int dstni=dstx+this->dfVecX[l], dstnj=dsty+this->dfVecY[l], dstnk=dstz+this->dfVecZ[l]; + // have to be at least from coarse here... + //errMsg("performCoarsening","CFGrFromFine subcube init unused check l"<cDirNum; m++) { + int chkni=dstni+this->dfVecX[m], chknj=dstnj+this->dfVecY[m], chknk=dstnk+this->dfVecZ[m]; + if(RFLAG(dstlev, chkni,chknj,chknk, dstFineSet)&(CFUnused|CFGrFromCoarse)) { + // this nb cell is ok for deletion + } else { + delok=false; // keep it! + } + //errMsg("performCoarsening"," CHECK "<mInitDone) errMsg("performCoarsening","CFGrFromFine subcube init, dir:"<cDirNum; l++) { + int ni=(2*i)+this->dfVecX[l], nj=(2*j)+this->dfVecY[l], nk=(2*k)+this->dfVecZ[l]; + if(RFLAG(lev+1, ni,nj,nk, dstFineSet)& + (CFGrFromCoarse|CFUnused|CFEmpty) //? (CFBnd|CFEmpty|CFGrFromCoarse|CFUnused) + //(CFUnused|CFEmpty) //? (CFBnd|CFEmpty|CFGrFromCoarse|CFUnused) + ) { + //LbmFloat area = 0.25; if(this->dfVecX[l]!=0) area *= 0.5; if(this->dfVecY[l]!=0) area *= 0.5; if(this->dfVecZ[l]!=0) area *= 0.5; + totArea += mFsgrCellArea[l]; + } + } // l + QCELL(lev, i,j,k,mLevel[lev].setOther, dFlux) = + QCELL(lev, i,j,k,srcSet, dFlux) = totArea; + } else { + QCELL(lev, i,j,k,mLevel[lev].setOther, dFlux) = + QCELL(lev, i,j,k,srcSet, dFlux) = 1.0; + } + //errMsg("DFINI"," at l"<getName().c_str(),"Debug")) + if((changeToFromFine)&&(lev+1==mMaxRefine)) { // mixborder + for(int l=0;((lcDirNum) && (changeToFromFine)); l++) { // FARBORD + int ni=2*i+2*this->dfVecX[l], nj=2*j+2*this->dfVecY[l], nk=2*k+2*this->dfVecZ[l]; + if(RFLAG(lev+1, ni,nj,nk, dstFineSet)&CFBnd) { // NEWREFT + changeToFromFine=false; } + } + }// FARBORD */ + //if(!this->mInitDone) { + for(int k= getForZMin1(); k< getForZMax1(lev); ++k) { + for(int j=1;j from fine conversion + bool changeToFromFine = false; + const CellFlagType notAllowed = (CFInter|CFGrFromFine|CFGrToFine); + CellFlagType reqType = CFGrNorm; + if(lev+1==mMaxRefine) reqType = CFNoBndFluid; + + if( (RFLAG(lev+1, (2*i),(2*j),(2*k), dstFineSet) & reqType) && + (!(RFLAG(lev+1, (2*i),(2*j),(2*k), dstFineSet) & (notAllowed)) ) ){ + // DEBUG + changeToFromFine=true; + } + + // FARBORD + + if(changeToFromFine) { + change = true; + mNumFsgrChanges++; + RFLAG(lev, i,j,k, srcSet) = CFFluid|CFGrFromFine; + if((LBMDIM==2)&&(debugCoarsening)) debugMarkCell(lev,i,j,k); + // same as restr from fine func! not necessary ?! + // coarseRestrictFromFine part + } + } // only check empty cells + + }}} // TEST! + //} // init done + // PASS 5 */ + } // coarsening, PASS 4,5 + + if(!this->mSilent){ errMsg("adaptGrid"," for l"<cDirNum); n++) { + int ni=2*i+1*this->dfVecX[n], nj=2*j+1*this->dfVecY[n], nk=2*k+1*this->dfVecZ[n]; + ccel = RACPNT(lev+1, ni,nj,nk,srcSet);// CFINTTEST + const LbmFloat weight = mGaussw[n]; + FORDF0{ + LbmFloat cdf = weight * RAC(ccel,l); +# if FSGR_STRICT_DEBUG==1 + if( cdf<-1.0 ){ errMsg("INVDFCREST_DFCHECK", PRINT_IJK<<" s"<dfDvecX[l]*cdf); + uy += (this->dfDvecY[l]*cdf); + uz += (this->dfDvecZ[l]*cdf); + } + + FORDF0{ feq[l] = this->getCollideEq(l, rho,ux,uy,uz); } + if(mLevel[lev ].lcsmago>0.0) { + const LbmFloat Qo = this->getLesNoneqTensorCoeff(df,feq); + omegaDst = this->getLesOmega(mLevel[lev ].omega,mLevel[lev ].lcsmago,Qo); + omegaSrc = this->getLesOmega(mLevel[lev+1].omega,mLevel[lev+1].lcsmago,Qo); + } else { + omegaDst = mLevel[lev+0].omega; /* NEWSMAGOT*/ + omegaSrc = mLevel[lev+1].omega; + } + dfScale = (mLevel[lev ].timestep/mLevel[lev+1].timestep)* (1.0/omegaDst-1.0)/ (1.0/omegaSrc-1.0); // yu + FORDF0{ + RAC(tcel, l) = feq[l]+ (df[l]-feq[l])*dfScale; + } +# else // OPT3D + // similar to OPTIMIZED_STREAMCOLLIDE_UNUSED + + //rho = ux = uy = uz = 0.0; + MSRC_C = CCELG_C(0) ; + MSRC_N = CCELG_N(0) ; + MSRC_S = CCELG_S(0) ; + MSRC_E = CCELG_E(0) ; + MSRC_W = CCELG_W(0) ; + MSRC_T = CCELG_T(0) ; + MSRC_B = CCELG_B(0) ; + MSRC_NE = CCELG_NE(0); + MSRC_NW = CCELG_NW(0); + MSRC_SE = CCELG_SE(0); + MSRC_SW = CCELG_SW(0); + MSRC_NT = CCELG_NT(0); + MSRC_NB = CCELG_NB(0); + MSRC_ST = CCELG_ST(0); + MSRC_SB = CCELG_SB(0); + MSRC_ET = CCELG_ET(0); + MSRC_EB = CCELG_EB(0); + MSRC_WT = CCELG_WT(0); + MSRC_WB = CCELG_WB(0); + for(int n=1;(ncDirNum); n++) { + ccel = RACPNT(lev+1, 2*i+1*this->dfVecX[n], 2*j+1*this->dfVecY[n], 2*k+1*this->dfVecZ[n] ,srcSet); + MSRC_C += CCELG_C(n) ; + MSRC_N += CCELG_N(n) ; + MSRC_S += CCELG_S(n) ; + MSRC_E += CCELG_E(n) ; + MSRC_W += CCELG_W(n) ; + MSRC_T += CCELG_T(n) ; + MSRC_B += CCELG_B(n) ; + MSRC_NE += CCELG_NE(n); + MSRC_NW += CCELG_NW(n); + MSRC_SE += CCELG_SE(n); + MSRC_SW += CCELG_SW(n); + MSRC_NT += CCELG_NT(n); + MSRC_NB += CCELG_NB(n); + MSRC_ST += CCELG_ST(n); + MSRC_SB += CCELG_SB(n); + MSRC_ET += CCELG_ET(n); + MSRC_EB += CCELG_EB(n); + MSRC_WT += CCELG_WT(n); + MSRC_WB += CCELG_WB(n); + } + rho = MSRC_C + MSRC_N + MSRC_S + MSRC_E + MSRC_W + MSRC_T + + MSRC_B + MSRC_NE + MSRC_NW + MSRC_SE + MSRC_SW + MSRC_NT + + MSRC_NB + MSRC_ST + MSRC_SB + MSRC_ET + MSRC_EB + MSRC_WT + MSRC_WB; + ux = MSRC_E - MSRC_W + MSRC_NE - MSRC_NW + MSRC_SE - MSRC_SW + + MSRC_ET + MSRC_EB - MSRC_WT - MSRC_WB; + uy = MSRC_N - MSRC_S + MSRC_NE + MSRC_NW - MSRC_SE - MSRC_SW + + MSRC_NT + MSRC_NB - MSRC_ST - MSRC_SB; + uz = MSRC_T - MSRC_B + MSRC_NT - MSRC_NB + MSRC_ST - MSRC_SB + + MSRC_ET - MSRC_EB + MSRC_WT - MSRC_WB; + usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \ + \ + lcsmeq[dC] = EQC ; \ + COLL_CALCULATE_DFEQ(lcsmeq); \ + COLL_CALCULATE_NONEQTENSOR(lev+0, MSRC_ )\ + COLL_CALCULATE_CSMOMEGAVAL(lev+0, lcsmDstOmega); \ + COLL_CALCULATE_CSMOMEGAVAL(lev+1, lcsmSrcOmega); \ + \ + lcsmdfscale = (mLevel[lev+0].timestep/mLevel[lev+1].timestep)* (1.0/lcsmDstOmega-1.0)/ (1.0/lcsmSrcOmega-1.0); \ + RAC(tcel, dC ) = (lcsmeq[dC ] + (MSRC_C -lcsmeq[dC ] )*lcsmdfscale); + RAC(tcel, dN ) = (lcsmeq[dN ] + (MSRC_N -lcsmeq[dN ] )*lcsmdfscale); + RAC(tcel, dS ) = (lcsmeq[dS ] + (MSRC_S -lcsmeq[dS ] )*lcsmdfscale); + RAC(tcel, dE ) = (lcsmeq[dE ] + (MSRC_E -lcsmeq[dE ] )*lcsmdfscale); + RAC(tcel, dW ) = (lcsmeq[dW ] + (MSRC_W -lcsmeq[dW ] )*lcsmdfscale); + RAC(tcel, dT ) = (lcsmeq[dT ] + (MSRC_T -lcsmeq[dT ] )*lcsmdfscale); + RAC(tcel, dB ) = (lcsmeq[dB ] + (MSRC_B -lcsmeq[dB ] )*lcsmdfscale); + RAC(tcel, dNE) = (lcsmeq[dNE] + (MSRC_NE-lcsmeq[dNE] )*lcsmdfscale); + RAC(tcel, dNW) = (lcsmeq[dNW] + (MSRC_NW-lcsmeq[dNW] )*lcsmdfscale); + RAC(tcel, dSE) = (lcsmeq[dSE] + (MSRC_SE-lcsmeq[dSE] )*lcsmdfscale); + RAC(tcel, dSW) = (lcsmeq[dSW] + (MSRC_SW-lcsmeq[dSW] )*lcsmdfscale); + RAC(tcel, dNT) = (lcsmeq[dNT] + (MSRC_NT-lcsmeq[dNT] )*lcsmdfscale); + RAC(tcel, dNB) = (lcsmeq[dNB] + (MSRC_NB-lcsmeq[dNB] )*lcsmdfscale); + RAC(tcel, dST) = (lcsmeq[dST] + (MSRC_ST-lcsmeq[dST] )*lcsmdfscale); + RAC(tcel, dSB) = (lcsmeq[dSB] + (MSRC_SB-lcsmeq[dSB] )*lcsmdfscale); + RAC(tcel, dET) = (lcsmeq[dET] + (MSRC_ET-lcsmeq[dET] )*lcsmdfscale); + RAC(tcel, dEB) = (lcsmeq[dEB] + (MSRC_EB-lcsmeq[dEB] )*lcsmdfscale); + RAC(tcel, dWT) = (lcsmeq[dWT] + (MSRC_WT-lcsmeq[dWT] )*lcsmdfscale); + RAC(tcel, dWB) = (lcsmeq[dWB] + (MSRC_WB-lcsmeq[dWB] )*lcsmdfscale); +# endif // OPT3D==0 +} + +void LbmFsgrSolver::interpolateCellFromCoarse(int lev, int i, int j,int k, int dstSet, LbmFloat t, CellFlagType flagSet, bool markNbs) { + LbmFloat rho=0.0, ux=0.0, uy=0.0, uz=0.0; + LbmFloat intDf[19] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + +#if OPT3D==1 + // for macro add + LbmFloat addDfFacT, addVal, usqr; + LbmFloat *addfcel, *dstcell; + LbmFloat lcsmqadd, lcsmqo, lcsmeq[LBM_DFNUM]; + LbmFloat lcsmDstOmega, lcsmSrcOmega, lcsmdfscale; +#endif // OPT3D==true + + // SET required nbs to from coarse (this might overwrite flag several times) + // this is not necessary for interpolateFineFromCoarse + if(markNbs) { + FORDF1{ + int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; + if(RFLAG(lev,ni,nj,nk,dstSet)&CFUnused) { + // parents have to be inited! + interpolateCellFromCoarse(lev, ni, nj, nk, dstSet, t, CFFluid|CFGrFromCoarse, false); + } + } } + + // change flag of cell to be interpolated + RFLAG(lev,i,j,k, dstSet) = flagSet; + mNumInterdCells++; + + // interpolation lines... + int betx = i&1; + int bety = j&1; + int betz = k&1; + + if((!betx) && (!bety) && (!betz)) { + ADD_INT_DFS(lev-1, i/2 ,j/2 ,k/2 , 0.0, 1.0); + } + else if(( betx) && (!bety) && (!betz)) { + ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D1); + ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2) , t, WO1D1); + } + else if((!betx) && ( bety) && (!betz)) { + ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D1); + ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2) , t, WO1D1); + } + else if((!betx) && (!bety) && ( betz)) { + ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D1); + ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2)+1, t, WO1D1); + } + else if(( betx) && ( bety) && (!betz)) { + ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D2); + ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2) , t, WO1D2); + ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2) , t, WO1D2); + ADD_INT_DFS(lev-1, (i/2)+1,(j/2)+1,(k/2) , t, WO1D2); + } + else if((!betx) && ( bety) && ( betz)) { + ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D2); + ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2)+1, t, WO1D2); + ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2) , t, WO1D2); + ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2)+1, t, WO1D2); + } + else if(( betx) && (!bety) && ( betz)) { + ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D2); + ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2) , t, WO1D2); + ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2)+1, t, WO1D2); + ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2)+1, t, WO1D2); + } + else if(( betx) && ( bety) && ( betz)) { + ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D3); + ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2) , t, WO1D3); + ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2)+1, t, WO1D3); + ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2)+1, t, WO1D3); + ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2) , t, WO1D3); + ADD_INT_DFS(lev-1, (i/2)+1,(j/2)+1,(k/2) , t, WO1D3); + ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2)+1, t, WO1D3); + ADD_INT_DFS(lev-1, (i/2)+1,(j/2)+1,(k/2)+1, t, WO1D3); + } + else { + CAUSE_PANIC; + errFatal("interpolateCellFromCoarse","Invalid!?", SIMWORLD_GENERICERROR); + } + + IDF_WRITEBACK; + return; +} + + + +// required globals +extern bool glob_mpactive; +extern int glob_mpnum, glob_mpindex; +#define MPTADAP_INTERV 4 + +/*****************************************************************************/ +/*! change the size of the LBM time step */ +/*****************************************************************************/ +void LbmFsgrSolver::adaptTimestep() { + LbmFloat massTOld=0.0, massTNew=0.0; + LbmFloat volTOld=0.0, volTNew=0.0; + + bool rescale = false; // do any rescale at all? + LbmFloat scaleFac = -1.0; // timestep scaling + if(mPanic) return; + + LbmFloat levOldOmega[FSGR_MAXNOOFLEVELS]; + LbmFloat levOldStepsize[FSGR_MAXNOOFLEVELS]; + for(int lev=mMaxRefine; lev>=0 ; lev--) { + levOldOmega[lev] = mLevel[lev].omega; + levOldStepsize[lev] = mLevel[lev].timestep; + } + + const LbmFloat reduceFac = 0.8; // modify time step by 20%, TODO? do multiple times for large changes? + LbmFloat diffPercent = 0.05; // dont scale if less than 5% + LbmFloat allowMax = mpParam->getTadapMaxSpeed(); // maximum allowed velocity + LbmFloat nextmax = mpParam->getSimulationMaxSpeed() + norm(mLevel[mMaxRefine].gravity); + + // sync nextmax +#if LBM_INCLUDE_TESTSOLVERS==1 + if(glob_mpactive) { + if(mLevel[mMaxRefine].lsteps % MPTADAP_INTERV != MPTADAP_INTERV-1) { + debMsgStd("LbmFsgrSolver::TAdp",DM_MSG, "mpact:"<getTimestep(); // newtr + if(nextmax > allowMax/reduceFac) { + mTimeMaxvelStepCnt++; } + else { mTimeMaxvelStepCnt=0; } + + // emergency, or 10 steps with high vel + if((mTimeMaxvelStepCnt>5) || (nextmax> (1.0/3.0)) || (mForceTimeStepReduce) ) { + newdt = mpParam->getTimestep() * reduceFac; + } else { + if(nextmaxgetTimestep() / reduceFac; + } + } // newtr + //errMsg("LbmFsgrSolver::adaptTimestep","nextmax="<getMaxTimestep()<<" min"<getMinTimestep()<<" diff"<getTimestep() ) // DEBUG + LbmFloat rhoAvg = mCurrentMass/mCurrentVolume; + if( (newdt<=mpParam->getMaxTimestep()) && (newdt>=mpParam->getMinTimestep()) + && (dtdiff>(mpParam->getTimestep()*diffPercent)) ) { + if((newdt>levOldStepsize[mMaxRefine])&&(mTimestepReduceLock)) { + // wait some more... + //debMsgNnl("LbmFsgrSolver::TAdp",DM_NOTIFY," Delayed... "<setDesiredTimestep( newdt ); + rescale = true; + if(!mSilent) { + debMsgStd("LbmFsgrSolver::TAdp",DM_NOTIFY,"\n\n\n\n",10); + debMsgStd("LbmFsgrSolver::TAdp",DM_NOTIFY,"Timestep changing: new="<getSimulationMaxSpeed()<<" next:"<getTimestep(); + mpParam->setDesiredTimestep( newdt ); + } else + if( ((mStepCnt% tadtogInter)== (tadtogInter/4*3)-1) || + ((mStepCnt% tadtogInter)== (tadtogInter/4*4)-1) ){ + rescale = true; minCutoff = false; + newdt = mpParam->getTimestep()/tadtogSwitch ; + mpParam->setDesiredTimestep( newdt ); + } else { + rescale = false; minCutoff = false; + } + // */ + + // test mass rescale + + scaleFac = newdt/mpParam->getTimestep(); + if(rescale) { + // perform acutal rescaling... + mTimeMaxvelStepCnt=0; + mForceTimeStepReduce = false; + + // FIXME - approximate by averaging, take gravity direction here? + //mTimestepReduceLock = 4*(mLevel[mMaxRefine].lSizey+mLevel[mMaxRefine].lSizez+mLevel[mMaxRefine].lSizex)/3; + // use z as gravity direction + mTimestepReduceLock = 4*mLevel[mMaxRefine].lSizez; + + mTimeSwitchCounts++; + mpParam->calculateAllMissingValues( mSimulationTime, mSilent ); + recalculateObjectSpeeds(); + // calc omega, force for all levels + mLastOmega=1e10; mLastGravity=1e10; + initLevelOmegas(); + if(mpParam->getTimestep()getTimestep(); + if(mpParam->getTimestep()>mMaxTimestep) mMaxTimestep = mpParam->getTimestep(); + + // this might be called during init, before we have any particles + if(mpParticles) { mpParticles->adaptPartTimestep(scaleFac); } +#if LBM_INCLUDE_TESTSOLVERS==1 + if((mUseTestdata)&&(mpTest)) { + mpTest->adaptTimestep(scaleFac, mLevel[mMaxRefine].omega, mLevel[mMaxRefine].timestep, vec2L( mpParam->calculateGravity(mSimulationTime)) ); + mpTest->mGrav3d = mLevel[mMaxRefine].gravity; + } +#endif // LBM_INCLUDE_TESTSOLVERS!=1 + + for(int lev=mMaxRefine; lev>=0 ; lev--) { + LbmFloat newSteptime = mLevel[lev].timestep; + LbmFloat dfScaleFac = (newSteptime/1.0)/(levOldStepsize[lev]/levOldOmega[lev]); + + if(!mSilent) { + debMsgStd("LbmFsgrSolver::TAdp",DM_NOTIFY,"Level: "<getCurrentGStar()<<", step:"<=0 ; lev--) { + int rescs=0; + int wss = 0, wse = 1; +#if COMPRESSGRIDS==1 + if(lev== mMaxRefine) wss = wse = mLevel[lev].setCurr; +#endif // COMPRESSGRIDS==1 + for(int workSet = wss; workSet<=wse; workSet++) { // COMPRT + //for(int workSet = 0; workSet<=1; workSet++) { + FSGR_FORIJK1(lev) { + + //if( (RFLAG(lev, i,j,k, workSet) & CFFluid) || (RFLAG(lev, i,j,k, workSet) & CFInter) ) { + if( + (RFLAG(lev,i,j,k, workSet) & CFFluid) || + (RFLAG(lev,i,j,k, workSet) & CFInter) || + (RFLAG(lev,i,j,k, workSet) & CFGrFromCoarse) || + (RFLAG(lev,i,j,k, workSet) & CFGrFromFine) || + (RFLAG(lev,i,j,k, workSet) & CFGrNorm) + ) { + // these cells have to be scaled... + } else { + continue; + } + + // collide on current set + LbmFloat rho, ux,uy,uz; + rho=0.0; ux = uy = uz = 0.0; + for(int l=0; l (allowMax*allowMax) ) { + LbmFloat cfac = allowMax/sqrt(ux*ux+uy*uy+uz*uz); + ux *= cfac; + uy *= cfac; + uz *= cfac; + for(int l=0; l0) { errMsg("adaptTimestep","!!!!! Brute force rescaling was necessary !!!!!!!"); } + debMsgStd("adaptTimestep",DM_MSG,"Brute force rescale done. level:"< + +#if PARALLEL==1 +#include +#endif // PARALLEL=1 +#ifndef PARALLEL +#define PARALLEL 0 +#endif // PARALLEL + + +// general solver setting defines + +//! debug coordinate accesses and the like? (much slower) +// might be enabled by compilation +#ifndef FSGR_STRICT_DEBUG +#define FSGR_STRICT_DEBUG 0 +#endif // FSGR_STRICT_DEBUG + +//! debug coordinate accesses and the like? (much slower) +#define FSGR_OMEGA_DEBUG 0 + +//! OPT3D quick LES on/off, only debug/benchmarking +#define USE_LES 1 + +//! order of interpolation (0=always current/1=interpolate/2=always other) +//#define TIMEINTORDER 0 +// TODO remove interpol t param, also interTime + +// use optimized 3D code? +#if LBMDIM==2 +#define OPT3D 0 +#else +// determine with debugging... +# if FSGR_STRICT_DEBUG==1 +# define OPT3D 0 +# else // FSGR_STRICT_DEBUG==1 +// usually switch optimizations for 3d on, when not debugging +# define OPT3D 1 +// COMPRT +//# define OPT3D 0 +# endif // FSGR_STRICT_DEBUG==1 +#endif + +//! invalid mass value for unused mass data +#define MASS_INVALID -1000.0 + +// empty/fill cells without fluid/empty NB's by inserting them into the full/empty lists? +#define FSGR_LISTTRICK 1 +#define FSGR_LISTTTHRESHEMPTY 0.10 +#define FSGR_LISTTTHRESHFULL 0.90 +#define FSGR_MAGICNR 0.025 +//0.04 + +//! maxmimum no. of grid levels +#define FSGR_MAXNOOFLEVELS 5 + +// enable/disable fine grid compression for finest level +// make sure this is same as useGridComp in calculateMemreqEstimate +#if LBMDIM==3 +#define COMPRESSGRIDS 1 +#else +#define COMPRESSGRIDS 0 +#endif + +// helper for comparing floats with epsilon +#define GFX_FLOATNEQ(x,y) ( ABS((x)-(y)) > (VECTOR_EPSILON) ) +#define LBM_FLOATNEQ(x,y) ( ABS((x)-(y)) > (10.0*LBM_EPSILON) ) + + +// macros for loops over all DFs +#define FORDF0 for(int l= 0; l< LBM_DFNUM; ++l) +#define FORDF1 for(int l= 1; l< LBM_DFNUM; ++l) +// and with different loop var to prevent shadowing +#define FORDF0M for(int m= 0; m< LBM_DFNUM; ++m) +#define FORDF1M for(int m= 1; m< LBM_DFNUM; ++m) + +// iso value defines +// border for marching cubes +#define ISOCORR 3 + +#define LBM_INLINED inline + +// sirdude fix for solaris +#if !defined(linux) && defined(sun) +#ifndef expf +#define expf(a) exp((double)(a)) +#endif +#endif + +#if LBM_INCLUDE_TESTSOLVERS==1 +#include "solver_test.h" +#endif // LBM_INCLUDE_TESTSOLVERS==1 + +/*****************************************************************************/ +/*! cell access classes */ +class UniformFsgrCellIdentifier : + public CellIdentifierInterface , public LbmCellContents +{ + public: + //! which grid level? + int level; + //! location in grid + int x,y,z; + + //! reset constructor + UniformFsgrCellIdentifier() : + x(0), y(0), z(0) { }; + + // implement CellIdentifierInterface + virtual string getAsString() { + std::ostringstream ret; + ret <<"{ i"<2) ret<<",k"<x && y==cid->y && z==cid->z && level==cid->level ) return true; + return false; + } +}; + +//! information needed for each level in the simulation +class FsgrLevelData { +public: + int id; // level number + + //! node size on this level (geometric, in world coordinates, not simulation units!) + LbmFloat nodeSize; + //! node size on this level in simulation units + LbmFloat simCellSize; + //! quadtree node relaxation parameter + LbmFloat omega; + //! size this level was advanced to + LbmFloat time; + //! size of a single lbm step in time units on this level + LbmFloat timestep; + //! step count + int lsteps; + //! gravity force for this level + LbmVec gravity; + //! level array + LbmFloat *mprsCells[2]; + CellFlagType *mprsFlags[2]; + + //! smago params and precalculated values + LbmFloat lcsmago; + LbmFloat lcsmago_sqr; + LbmFloat lcnu; + + // LES statistics per level + double avgOmega; + double avgOmegaCnt; + + //! current set of dist funcs + int setCurr; + //! target/other set of dist funcs + int setOther; + + //! mass&volume for this level + LbmFloat lmass; + LbmFloat lvolume; + LbmFloat lcellfactor; + + //! local storage of mSizes + int lSizex, lSizey, lSizez; + int lOffsx, lOffsy, lOffsz; + +}; + + + +/*****************************************************************************/ +/*! class for solving a LBM problem */ +class LbmFsgrSolver : + public LbmSolverInterface // this means, the solver is a lbmData object and implements the lbmInterface +{ + + public: + //! Constructor + LbmFsgrSolver(); + //! Destructor + virtual ~LbmFsgrSolver(); + + //! initilize variables fom attribute list + virtual void parseAttrList(); + //! Initialize omegas and forces on all levels (for init/timestep change) + void initLevelOmegas(); + + // multi step solver init + /*! finish the init with config file values (allocate arrays...) */ + virtual bool initializeSolverMemory(); + /*! init solver arrays */ + virtual bool initializeSolverGrids(); + /*! prepare actual simulation start, setup viz etc */ + virtual bool initializeSolverPostinit(); + + //! notify object that dump is in progress (e.g. for field dump) + virtual void notifySolverOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename); + +# if LBM_USE_GUI==1 + //! show simulation info (implement LbmSolverInterface pure virtual func) + virtual void debugDisplay(int set); +# endif + + // implement CellIterator interface + typedef UniformFsgrCellIdentifier stdCellId; + virtual CellIdentifierInterface* getFirstCell( ); + virtual void advanceCell( CellIdentifierInterface* ); + virtual bool noEndCell( CellIdentifierInterface* ); + virtual void deleteCellIterator( CellIdentifierInterface** ); + virtual CellIdentifierInterface* getCellAt( ntlVec3Gfx pos ); + virtual int getCellSet ( CellIdentifierInterface* ); + virtual ntlVec3Gfx getCellOrigin ( CellIdentifierInterface* ); + virtual ntlVec3Gfx getCellSize ( CellIdentifierInterface* ); + virtual int getCellLevel ( CellIdentifierInterface* ); + virtual LbmFloat getCellDensity ( CellIdentifierInterface* ,int set); + virtual LbmVec getCellVelocity ( CellIdentifierInterface* ,int set); + virtual LbmFloat getCellDf ( CellIdentifierInterface* ,int set, int dir); + virtual LbmFloat getCellMass ( CellIdentifierInterface* ,int set); + virtual LbmFloat getCellFill ( CellIdentifierInterface* ,int set); + virtual CellFlagType getCellFlag ( CellIdentifierInterface* ,int set); + virtual LbmFloat getEquilDf ( int ); + virtual ntlVec3Gfx getVelocityAt (float x, float y, float z); + // convert pointers + stdCellId* convertBaseCidToStdCid( CellIdentifierInterface* basecid); + + //! perform geometry init (if switched on) + bool initGeometryFlags(); + //! init part for all freesurface testcases + void initFreeSurfaces(); + //! init density gradient if enabled + void initStandingFluidGradient(); + + /*! init a given cell with flag, density, mass and equilibrium dist. funcs */ + LBM_INLINED void initEmptyCell(int level, int i,int j,int k, CellFlagType flag, LbmFloat rho, LbmFloat mass); + LBM_INLINED void initVelocityCell(int level, int i,int j,int k, CellFlagType flag, LbmFloat rho, LbmFloat mass, LbmVec vel); + LBM_INLINED void changeFlag(int level, int xx,int yy,int zz,int set,CellFlagType newflag); + LBM_INLINED void forceChangeFlag(int level, int xx,int yy,int zz,int set,CellFlagType newflag); + LBM_INLINED void initInterfaceVars(int level, int i,int j,int k,int workSet, bool initMass); + //! interpolate velocity and density at a given position + void interpolateCellValues(int level,int ei,int ej,int ek,int workSet, LbmFloat &retrho, LbmFloat &retux, LbmFloat &retuy, LbmFloat &retuz); + + /*! perform a single LBM step */ + void stepMain(); + //! advance fine grid + void fineAdvance(); + //! advance coarse grid + void coarseAdvance(int lev); + //! update flux area values on coarse grids + void coarseCalculateFluxareas(int lev); + // adaptively coarsen grid + bool adaptGrid(int lev); + // restrict fine grid DFs to coarse grid + void coarseRestrictFromFine(int lev); + + /* simulation object interface, just calls stepMain */ + virtual void step(); + /*! init particle positions */ + virtual int initParticles(); + /*! move all particles */ + virtual void advanceParticles(); + /*! move a particle at a boundary */ + void handleObstacleParticle(ParticleObject *p); + /*! check whether to add particle + bool checkAddParticle(); + void performAddParticle();*/ + + + /*! debug object display (used e.g. for preview surface) */ + virtual vector getDebugObjects(); + + // gui/output debugging functions +# if LBM_USE_GUI==1 + virtual void debugDisplayNode(int dispset, CellIdentifierInterface* cell ); + virtual void lbmDebugDisplay(int dispset); + virtual void lbmMarkedCellDisplay(); +# endif // LBM_USE_GUI==1 + virtual void debugPrintNodeInfo(CellIdentifierInterface* cell, int forceSet=-1); + + //! for raytracing, preprocess + void prepareVisualization( void ); + + protected: + + //! internal quick print function (for debugging) + void printLbmCell(int level, int i, int j, int k,int set); + // debugging use CellIterator interface to mark cell + void debugMarkCellCall(int level, int vi,int vj,int vk); + + // loop over grid, stream&collide update + void mainLoop(int lev); + // change time step size + void adaptTimestep(); + //! init mObjectSpeeds for current parametrization + void recalculateObjectSpeeds(); + //! init moving obstacles for next sim step sim + void initMovingObstacles(bool staticInit); + //! flag reinit step - always works on finest grid! + void reinitFlags( int workSet ); + //! mass dist weights + LbmFloat getMassdWeight(bool dirForw, int i,int j,int k,int workSet, int l); + //! compute surface normals: fluid, fluid more accurate, and for obstacles + void computeFluidSurfaceNormal(LbmFloat *cell, CellFlagType *cellflag, LbmFloat *snret); + void computeFluidSurfaceNormalAcc(LbmFloat *cell, CellFlagType *cellflag, LbmFloat *snret); + void computeObstacleSurfaceNormal(LbmFloat *cell, CellFlagType *cellflag, LbmFloat *snret); + void computeObstacleSurfaceNormalAcc(int i,int j,int k, LbmFloat *snret); + //! add point to mListNewInter list + LBM_INLINED void addToNewInterList( int ni, int nj, int nk ); + //! cell is interpolated from coarse level (inited into set, source sets are determined by t) + void interpolateCellFromCoarse(int lev, int i, int j,int k, int dstSet, LbmFloat t, CellFlagType flagSet,bool markNbs); + void coarseRestrictCell(int lev, int i,int j,int k, int srcSet, int dstSet); + + //! minimal and maximal z-coords (for 2D/3D loops) + LBM_INLINED int getForZMinBnd(); + LBM_INLINED int getForZMin1(); + LBM_INLINED int getForZMaxBnd(int lev); + LBM_INLINED int getForZMax1(int lev); + LBM_INLINED bool checkDomainBounds(int lev,int i,int j,int k); + LBM_INLINED bool checkDomainBoundsPos(int lev,LbmVec pos); + + // touch grid and flags once + void preinitGrids(); + // one relaxation step for standing fluid + void standingFluidPreinit(); + + + // member vars + + //! mass calculated during streaming step + LbmFloat mCurrentMass; + LbmFloat mCurrentVolume; + LbmFloat mInitialMass; + + //! count problematic cases, that occured so far... + int mNumProblems; + + // average mlsups, count how many so far... + double mAvgMLSUPS; + double mAvgMLSUPSCnt; + + //! Mcubes object for surface reconstruction + IsoSurface *mpPreviewSurface; + + //! use time adaptivity? + bool mTimeAdap; + //! force smaller timestep for next LBM step? (eg for mov obj) + bool mForceTimeStepReduce; + + //! fluid vol height + LbmFloat mFVHeight; + LbmFloat mFVArea; + bool mUpdateFVHeight; + + //! force quit for gfx + LbmFloat mGfxEndTime; + //! smoother surface initialization? + int mInitSurfaceSmoothing; + //! surface generation settings, default is all off (=0) + // each flag switches side on off, fssgNoObs is for obstacle sides + // -1 equals all on + typedef enum { + fssgNormal = 0, + fssgNoNorth = 1, + fssgNoSouth = 2, + fssgNoEast = 4, + fssgNoWest = 8, + fssgNoTop = 16, + fssgNoBottom = 32, + fssgNoObs = 64 + } fsSurfaceGen; + int mFsSurfGenSetting; + + //! lock time step down switching + int mTimestepReduceLock; + //! count no. of switches + int mTimeSwitchCounts; + // only switch of maxvel is higher for several steps... + int mTimeMaxvelStepCnt; + + //! total simulation time so far + LbmFloat mSimulationTime, mLastSimTime; + //! smallest and largest step size so far + LbmFloat mMinTimestep, mMaxTimestep; + //! track max. velocity + LbmFloat mMxvx, mMxvy, mMxvz, mMaxVlen; + + //! list of the cells to empty at the end of the step + vector mListEmpty; + //! list of the cells to make fluid at the end of the step + vector mListFull; + //! list of new interface cells to init + vector mListNewInter; + //! class for handling redist weights in reinit flag function + class lbmFloatSet { + public: + LbmFloat val[dTotalNum]; + LbmFloat numNbs; + }; + //! normalized vectors for all neighboring cell directions (for e.g. massdweight calc) + LbmVec mDvecNrm[27]; + + + //! debugging + bool checkSymmetry(string idstring); + //! kepp track of max/min no. of filled cells + int mMaxNoCells, mMinNoCells; + LONGINT mAvgNumUsedCells; + + //! precalculated objects speeds for current parametrization + vector mObjectSpeeds; + //! partslip bc. values for obstacle boundary conditions + vector mObjectPartslips; + //! moving object mass boundary condition values + vector mObjectMassMovnd; + + //! permanent movobj vert storage + vector mMOIVertices; + vector mMOIVerticesOld; + vector mMOINormals; + + //! get isofield weights + int mIsoWeightMethod; + float mIsoWeight[27]; + + // grid coarsening vars + + /*! vector for the data for each level */ + FsgrLevelData mLevel[FSGR_MAXNOOFLEVELS]; + + /*! minimal and maximal refinement levels */ + int mMaxRefine; + + /*! df scale factors for level up/down */ + LbmFloat mDfScaleUp, mDfScaleDown; + + /*! precomputed cell area values */ + LbmFloat mFsgrCellArea[27]; + /*! restriction interpolation weights */ + LbmFloat mGaussw[27]; + + /*! LES C_smago paramter for finest grid */ + float mInitialCsmago; + /*! LES stats for non OPT3D */ + LbmFloat mDebugOmegaRet; + /*! remember last init for animated params */ + LbmFloat mLastOmega; + LbmVec mLastGravity; + + //! fluid stats + int mNumInterdCells; + int mNumInvIfCells; + int mNumInvIfTotal; + int mNumFsgrChanges; + + //! debug function to disable standing f init + int mDisableStandingFluidInit; + //! init 2d with skipped Y/Z coords + bool mInit2dYZ; + //! debug function to force tadap syncing + int mForceTadapRefine; + //! border cutoff value + int mCutoff; + + // strict debug interface +# if FSGR_STRICT_DEBUG==1 + int debLBMGI(int level, int ii,int ij,int ik, int is); + CellFlagType& debRFLAG(int level, int xx,int yy,int zz,int set); + CellFlagType& debRFLAG_NB(int level, int xx,int yy,int zz,int set, int dir); + CellFlagType& debRFLAG_NBINV(int level, int xx,int yy,int zz,int set, int dir); + int debLBMQI(int level, int ii,int ij,int ik, int is, int l); + LbmFloat& debQCELL(int level, int xx,int yy,int zz,int set,int l); + LbmFloat& debQCELL_NB(int level, int xx,int yy,int zz,int set, int dir,int l); + LbmFloat& debQCELL_NBINV(int level, int xx,int yy,int zz,int set, int dir,int l); + LbmFloat* debRACPNT(int level, int ii,int ij,int ik, int is ); + LbmFloat& debRAC(LbmFloat* s,int l); +# endif // FSGR_STRICT_DEBUG==1 + + bool mUseTestdata; +# if LBM_INCLUDE_TESTSOLVERS==1 + // test functions + LbmTestdata *mpTest; + void initTestdata(); + void destroyTestdata(); + void handleTestdata(); + void set3dHeight(int ,int ); + + void initCpdata(); + void handleCpdata(); + void cpDebugDisplay(int dispset); + + int mMpNum,mMpIndex; + int mOrgSizeX; + LbmFloat mOrgStartX; + LbmFloat mOrgEndX; + void mrSetup(); + void mrExchange(); + void mrIsoExchange(); + LbmFloat mrInitTadap(LbmFloat max); + void gcFillBuffer( LbmGridConnector *gc, int *retSizeCnt, const int *bdfs); + void gcUnpackBuffer(LbmGridConnector *gc, int *retSizeCnt, const int *bdfs); + public: + // needed for testdata + void find3dHeight(int i,int j, LbmFloat prev, LbmFloat &ret, LbmFloat *retux, LbmFloat *retuy, LbmFloat *retuz); + // mptest + int getMpIndex() { return mMpIndex; }; +# endif // LBM_INCLUDE_TESTSOLVERS==1 + + // former LbmModelLBGK functions + // relaxation funtions - implemented together with relax macros + static inline LbmFloat getVelVecLen(int l, LbmFloat ux,LbmFloat uy,LbmFloat uz); + static inline LbmFloat getCollideEq(int l, LbmFloat rho, LbmFloat ux, LbmFloat uy, LbmFloat uz); + inline LbmFloat getLesNoneqTensorCoeff( LbmFloat df[], LbmFloat feq[] ); + inline LbmFloat getLesOmega(LbmFloat omega, LbmFloat csmago, LbmFloat Qo); + inline void collideArrays( int lev, int i, int j, int k, // position - more for debugging + LbmFloat df[], LbmFloat &outrho, // out only! + // velocity modifiers (returns actual velocity!) + LbmFloat &mux, LbmFloat &muy, LbmFloat &muz, + LbmFloat omega, LbmVec gravity, LbmFloat csmago, + LbmFloat *newOmegaRet, LbmFloat *newQoRet); + + + // former LBM models + //! shorten static const definitions +# define STCON static const + +# if LBMDIM==3 + + //! id string of solver + virtual string getIdString() { return string("FreeSurfaceFsgrSolver[BGK_D3Q19]"); } + + //! how many dimensions? UNUSED? replace by LBMDIM? + STCON int cDimension; + + // Wi factors for collide step + STCON LbmFloat cCollenZero; + STCON LbmFloat cCollenOne; + STCON LbmFloat cCollenSqrtTwo; + + //! threshold value for filled/emptied cells + STCON LbmFloat cMagicNr2; + STCON LbmFloat cMagicNr2Neg; + STCON LbmFloat cMagicNr; + STCON LbmFloat cMagicNrNeg; + + //! size of a single set of distribution functions + STCON int cDfNum; + //! direction vector contain vecs for all spatial dirs, even if not used for LBM model + STCON int cDirNum; + + //! distribution functions directions + typedef enum { + cDirInv= -1, + cDirC = 0, + cDirN = 1, + cDirS = 2, + cDirE = 3, + cDirW = 4, + cDirT = 5, + cDirB = 6, + cDirNE = 7, + cDirNW = 8, + cDirSE = 9, + cDirSW = 10, + cDirNT = 11, + cDirNB = 12, + cDirST = 13, + cDirSB = 14, + cDirET = 15, + cDirEB = 16, + cDirWT = 17, + cDirWB = 18 + } dfDir; + + /* Vector Order 3D: + * 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 + * 0, 0, 0, 1,-1, 0, 0, 1,-1, 1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1,-1, 1,-1, 1,-1, 1,-1 + * 0, 1,-1, 0, 0, 0, 0, 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, 1,-1, 0, 0, 0, 0, 1,-1, 1,-1, 1,-1, 1,-1, 1, 1, 1, 1, -1,-1,-1,-1 + */ + + /*! name of the dist. function + only for nicer output */ + STCON char* dfString[ 19 ]; + + /*! index of normal dist func, not used so far?... */ + STCON int dfNorm[ 19 ]; + + /*! index of inverse dist func, not fast, but useful... */ + STCON int dfInv[ 19 ]; + + /*! index of x reflected dist func for free slip, not valid for all DFs... */ + STCON int dfRefX[ 19 ]; + /*! index of x reflected dist func for free slip, not valid for all DFs... */ + STCON int dfRefY[ 19 ]; + /*! index of x reflected dist func for free slip, not valid for all DFs... */ + STCON int dfRefZ[ 19 ]; + + /*! dist func vectors */ + STCON int dfVecX[ 27 ]; + STCON int dfVecY[ 27 ]; + STCON int dfVecZ[ 27 ]; + + /*! arrays as before with doubles */ + STCON LbmFloat dfDvecX[ 27 ]; + STCON LbmFloat dfDvecY[ 27 ]; + STCON LbmFloat dfDvecZ[ 27 ]; + + /*! principal directions */ + STCON int princDirX[ 2*3 ]; + STCON int princDirY[ 2*3 ]; + STCON int princDirZ[ 2*3 ]; + + /*! vector lengths */ + STCON LbmFloat dfLength[ 19 ]; + + /*! equilibrium distribution functions, precalculated = getCollideEq(i, 0,0,0,0) */ + static LbmFloat dfEquil[ dTotalNum ]; + + /*! arrays for les model coefficients */ + static LbmFloat lesCoeffDiag[ (3-1)*(3-1) ][ 27 ]; + static LbmFloat lesCoeffOffdiag[ 3 ][ 27 ]; + +# else // end LBMDIM==3 , LBMDIM==2 + + //! id string of solver + virtual string getIdString() { return string("FreeSurfaceFsgrSolver[BGK_D2Q9]"); } + + //! how many dimensions? + STCON int cDimension; + + //! Wi factors for collide step + STCON LbmFloat cCollenZero; + STCON LbmFloat cCollenOne; + STCON LbmFloat cCollenSqrtTwo; + + //! threshold value for filled/emptied cells + STCON LbmFloat cMagicNr2; + STCON LbmFloat cMagicNr2Neg; + STCON LbmFloat cMagicNr; + STCON LbmFloat cMagicNrNeg; + + //! size of a single set of distribution functions + STCON int cDfNum; + STCON int cDirNum; + + //! distribution functions directions + typedef enum { + cDirInv= -1, + cDirC = 0, + cDirN = 1, + cDirS = 2, + cDirE = 3, + cDirW = 4, + cDirNE = 5, + cDirNW = 6, + cDirSE = 7, + cDirSW = 8 + } dfDir; + + /* Vector Order 2D: + * 0 1 2 3 4 5 6 7 8 + * 0, 0,0, 1,-1, 1,-1,1,-1 + * 0, 1,-1, 0,0, 1,1,-1,-1 */ + + /* name of the dist. function + only for nicer output */ + STCON char* dfString[ 9 ]; + + /* index of normal dist func, not used so far?... */ + STCON int dfNorm[ 9 ]; + + /* index of inverse dist func, not fast, but useful... */ + STCON int dfInv[ 9 ]; + + /* index of x reflected dist func for free slip, not valid for all DFs... */ + STCON int dfRefX[ 9 ]; + /* index of x reflected dist func for free slip, not valid for all DFs... */ + STCON int dfRefY[ 9 ]; + /* index of x reflected dist func for free slip, not valid for all DFs... */ + STCON int dfRefZ[ 9 ]; + + /* dist func vectors */ + STCON int dfVecX[ 9 ]; + STCON int dfVecY[ 9 ]; + /* Z, 2D values are all 0! */ + STCON int dfVecZ[ 9 ]; + + /* arrays as before with doubles */ + STCON LbmFloat dfDvecX[ 9 ]; + STCON LbmFloat dfDvecY[ 9 ]; + /* Z, 2D values are all 0! */ + STCON LbmFloat dfDvecZ[ 9 ]; + + /*! principal directions */ + STCON int princDirX[ 2*2 ]; + STCON int princDirY[ 2*2 ]; + STCON int princDirZ[ 2*2 ]; + + /* vector lengths */ + STCON LbmFloat dfLength[ 9 ]; + + /* equilibrium distribution functions, precalculated = getCollideEq(i, 0,0,0,0) */ + static LbmFloat dfEquil[ dTotalNum ]; + + /*! arrays for les model coefficients */ + static LbmFloat lesCoeffDiag[ (2-1)*(2-1) ][ 9 ]; + static LbmFloat lesCoeffOffdiag[ 2 ][ 9 ]; + +# endif // LBMDIM==2 +}; + +#undef STCON + + +/*****************************************************************************/ +// relaxation_macros + + + +// cell mark debugging +#if FSGR_STRICT_DEBUG==10 +#define debugMarkCell(lev,x,y,z) \ + errMsg("debugMarkCell",this->mName<<" step: "<mStepCnt<<" lev:"<<(lev)<<" marking "<dfVecX[dir],(yy)+this->dfVecY[dir],(zz)+this->dfVecZ[dir],set) ] +#define _RFLAG_NBINV(level,xx,yy,zz,set, dir) mLevel[level].mprsFlags[set][ LBMGI((level),(xx)+this->dfVecX[this->dfInv[dir]],(yy)+this->dfVecY[this->dfInv[dir]],(zz)+this->dfVecZ[this->dfInv[dir]],set) ] + +// array handling ----------------------------------------------------------------------------------------------- + +#define _LBMQI(level, ii,ij,ik, is, lunused) ( (mLevel[level].lOffsy*(ik)) + (mLevel[level].lOffsx*(ij)) + (ii) ) +#define _QCELL(level,xx,yy,zz,set,l) (mLevel[level].mprsCells[(set)][ LBMQI((level),(xx),(yy),(zz),(set), l)*dTotalNum +(l)]) +#define _QCELL_NB(level,xx,yy,zz,set, dir,l) (mLevel[level].mprsCells[(set)][ LBMQI((level),(xx)+this->dfVecX[dir],(yy)+this->dfVecY[dir],(zz)+this->dfVecZ[dir],set, l)*dTotalNum +(l)]) +#define _QCELL_NBINV(level,xx,yy,zz,set, dir,l) (mLevel[level].mprsCells[(set)][ LBMQI((level),(xx)+this->dfVecX[this->dfInv[dir]],(yy)+this->dfVecY[this->dfInv[dir]],(zz)+this->dfVecZ[this->dfInv[dir]],set, l)*dTotalNum +(l)]) + +#define QCELLSTEP dTotalNum +#define _RACPNT(level, ii,ij,ik, is ) &QCELL(level,ii,ij,ik,is,0) +#define _RAC(s,l) (s)[(l)] + + +#if FSGR_STRICT_DEBUG==1 + +#define LBMGI(level,ii,ij,ik, is) debLBMGI(level,ii,ij,ik, is) +#define RFLAG(level,xx,yy,zz,set) debRFLAG(level,xx,yy,zz,set) +#define RFLAG_NB(level,xx,yy,zz,set, dir) debRFLAG_NB(level,xx,yy,zz,set, dir) +#define RFLAG_NBINV(level,xx,yy,zz,set, dir) debRFLAG_NBINV(level,xx,yy,zz,set, dir) + +#define LBMQI(level,ii,ij,ik, is, l) debLBMQI(level,ii,ij,ik, is, l) +#define QCELL(level,xx,yy,zz,set,l) debQCELL(level,xx,yy,zz,set,l) +#define QCELL_NB(level,xx,yy,zz,set, dir,l) debQCELL_NB(level,xx,yy,zz,set, dir,l) +#define QCELL_NBINV(level,xx,yy,zz,set, dir,l) debQCELL_NBINV(level,xx,yy,zz,set, dir,l) +#define RACPNT(level, ii,ij,ik, is ) debRACPNT(level, ii,ij,ik, is ) +#define RAC(s,l) debRAC(s,l) + +#else // FSGR_STRICT_DEBUG==1 + +#define LBMGI(level,ii,ij,ik, is) _LBMGI(level,ii,ij,ik, is) +#define RFLAG(level,xx,yy,zz,set) _RFLAG(level,xx,yy,zz,set) +#define RFLAG_NB(level,xx,yy,zz,set, dir) _RFLAG_NB(level,xx,yy,zz,set, dir) +#define RFLAG_NBINV(level,xx,yy,zz,set, dir) _RFLAG_NBINV(level,xx,yy,zz,set, dir) + +#define LBMQI(level,ii,ij,ik, is, l) _LBMQI(level,ii,ij,ik, is, l) +#define QCELL(level,xx,yy,zz,set,l) _QCELL(level,xx,yy,zz,set,l) +#define QCELL_NB(level,xx,yy,zz,set, dir,l) _QCELL_NB(level,xx,yy,zz,set, dir, l) +#define QCELL_NBINV(level,xx,yy,zz,set, dir,l) _QCELL_NBINV(level,xx,yy,zz,set, dir,l) +#define RACPNT(level, ii,ij,ik, is ) _RACPNT(level, ii,ij,ik, is ) +#define RAC(s,l) _RAC(s,l) + +#endif // FSGR_STRICT_DEBUG==1 + +// general defines ----------------------------------------------------------------------------------------------- + +// replace TESTFLAG +#define FLAGISEXACT(flag, compflag) ((flag & compflag)==compflag) + +#if LBMDIM==2 +#define dC 0 +#define dN 1 +#define dS 2 +#define dE 3 +#define dW 4 +#define dNE 5 +#define dNW 6 +#define dSE 7 +#define dSW 8 +#else +// direction indices +#define dC 0 +#define dN 1 +#define dS 2 +#define dE 3 +#define dW 4 +#define dT 5 +#define dB 6 +#define dNE 7 +#define dNW 8 +#define dSE 9 +#define dSW 10 +#define dNT 11 +#define dNB 12 +#define dST 13 +#define dSB 14 +#define dET 15 +#define dEB 16 +#define dWT 17 +#define dWB 18 +#endif +//? #define dWB 18 + +// default init for dFlux values +#define FLUX_INIT 0.5f * (float)(this->cDfNum) + +// only for non DF dir handling! +#define dNET 19 +#define dNWT 20 +#define dSET 21 +#define dSWT 22 +#define dNEB 23 +#define dNWB 24 +#define dSEB 25 +#define dSWB 26 + +//! fill value for boundary cells +#define BND_FILL 0.0 + +#define DFL1 (1.0/ 3.0) +#define DFL2 (1.0/18.0) +#define DFL3 (1.0/36.0) + +// loops over _all_ cells (including boundary layer) +#define FSGR_FORIJK_BOUNDS(leveli) \ + for(int k= getForZMinBnd(); k< getForZMaxBnd(leveli); ++k) \ + for(int j=0;jLBM_DFNUM)) { errFatal("LbmFsgrSolver::getCollideEq","Invalid DFEQ call "<dfEquil[l] * rho; } + RAC(ecel, dMass) = mass; + RAC(ecel, dFfrac) = mass/rho; + RAC(ecel, dFlux) = FLUX_INIT; + changeFlag(level, i,j,k, workSet, flag); + + workSet ^= 1; + changeFlag(level, i,j,k, workSet, flag); + return; +} + +void +LbmFsgrSolver::initVelocityCell(int level, int i,int j,int k, CellFlagType flag, LbmFloat rho, LbmFloat mass, LbmVec vel) { + LbmFloat *ecel; + int workSet = mLevel[level].setCurr; + + ecel = RACPNT(level, i,j,k, workSet); + FORDF0 { RAC(ecel, l) = getCollideEq(l, rho,vel[0],vel[1],vel[2]); } + RAC(ecel, dMass) = mass; + RAC(ecel, dFfrac) = mass/rho; + RAC(ecel, dFlux) = FLUX_INIT; + changeFlag(level, i,j,k, workSet, flag); + + workSet ^= 1; + changeFlag(level, i,j,k, workSet, flag); + return; +} + +int LbmFsgrSolver::getForZMinBnd() { + return 0; +} +int LbmFsgrSolver::getForZMin1() { + if(LBMDIM==2) return 0; + return 1; +} + +int LbmFsgrSolver::getForZMaxBnd(int lev) { + if(LBMDIM==2) return 1; + return mLevel[lev].lSizez -0; +} +int LbmFsgrSolver::getForZMax1(int lev) { + if(LBMDIM==2) return 1; + return mLevel[lev].lSizez -1; +} + +bool LbmFsgrSolver::checkDomainBounds(int lev,int i,int j,int k) { + if(i<0) return false; + if(j<0) return false; + if(k<0) return false; + if(i>mLevel[lev].lSizex-1) return false; + if(j>mLevel[lev].lSizey-1) return false; + if(k>mLevel[lev].lSizez-1) return false; + return true; +} +bool LbmFsgrSolver::checkDomainBoundsPos(int lev,LbmVec pos) { + const int i= (int)pos[0]; + if(i<0) return false; + if(i>mLevel[lev].lSizex-1) return false; + const int j= (int)pos[1]; + if(j<0) return false; + if(j>mLevel[lev].lSizey-1) return false; + const int k= (int)pos[2]; + if(k<0) return false; + if(k>mLevel[lev].lSizez-1) return false; + return true; +} + +void LbmFsgrSolver::initInterfaceVars(int level, int i,int j,int k,int workSet, bool initMass) { + LbmFloat *ccel = &QCELL(level ,i,j,k, workSet,0); + LbmFloat nrho = 0.0; + FORDF0 { nrho += RAC(ccel,l); } + if(initMass) { + RAC(ccel,dMass) = nrho; + RAC(ccel, dFfrac) = 1.; + } else { + // preinited, e.g. from reinitFlags + RAC(ccel, dFfrac) = RAC(ccel, dMass)/nrho; + RAC(ccel, dFlux) = FLUX_INIT; + } +} + + +#endif + + diff --git a/intern/elbeem/intern/solver_init.cpp b/intern/elbeem/intern/solver_init.cpp new file mode 100644 index 00000000000..abec4a89c89 --- /dev/null +++ b/intern/elbeem/intern/solver_init.cpp @@ -0,0 +1,2320 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Standard LBM Factory implementation + * + *****************************************************************************/ + + +#include "solver_class.h" +#include "solver_relax.h" +// for geo init FGI_ defines +#include "elbeem.h" + +// helper for 2d init +#define SWAPYZ(vec) { \ + const LbmFloat tmp = (vec)[2]; \ + (vec)[2] = (vec)[1]; (vec)[1] = tmp; } + + +/*****************************************************************************/ +//! common variables + +/*****************************************************************************/ +/*! 3D implementation D3Q19 */ +#if LBMDIM==3 + + //! how many dimensions? + const int LbmFsgrSolver::cDimension = 3; + + // Wi factors for collide step + const LbmFloat LbmFsgrSolver::cCollenZero = (1.0/3.0); + const LbmFloat LbmFsgrSolver::cCollenOne = (1.0/18.0); + const LbmFloat LbmFsgrSolver::cCollenSqrtTwo = (1.0/36.0); + + //! threshold value for filled/emptied cells + const LbmFloat LbmFsgrSolver::cMagicNr2 = 1.0005; + const LbmFloat LbmFsgrSolver::cMagicNr2Neg = -0.0005; + const LbmFloat LbmFsgrSolver::cMagicNr = 1.010001; + const LbmFloat LbmFsgrSolver::cMagicNrNeg = -0.010001; + + //! size of a single set of distribution functions + const int LbmFsgrSolver::cDfNum = 19; + //! direction vector contain vecs for all spatial dirs, even if not used for LBM model + const int LbmFsgrSolver::cDirNum = 27; + + //const string LbmFsgrSolver::dfString[ cDfNum ] = { + const char* LbmFsgrSolver::dfString[ cDfNum ] = { + " C", " N"," S"," E"," W"," T"," B", + "NE","NW","SE","SW", + "NT","NB","ST","SB", + "ET","EB","WT","WB" + }; + + const int LbmFsgrSolver::dfNorm[ cDfNum ] = { + cDirC, cDirN, cDirS, cDirE, cDirW, cDirT, cDirB, + cDirNE, cDirNW, cDirSE, cDirSW, + cDirNT, cDirNB, cDirST, cDirSB, + cDirET, cDirEB, cDirWT, cDirWB + }; + + const int LbmFsgrSolver::dfInv[ cDfNum ] = { + cDirC, cDirS, cDirN, cDirW, cDirE, cDirB, cDirT, + cDirSW, cDirSE, cDirNW, cDirNE, + cDirSB, cDirST, cDirNB, cDirNT, + cDirWB, cDirWT, cDirEB, cDirET + }; + + const int LbmFsgrSolver::dfRefX[ cDfNum ] = { + 0, 0, 0, 0, 0, 0, 0, + cDirSE, cDirSW, cDirNE, cDirNW, + 0, 0, 0, 0, + cDirEB, cDirET, cDirWB, cDirWT + }; + + const int LbmFsgrSolver::dfRefY[ cDfNum ] = { + 0, 0, 0, 0, 0, 0, 0, + cDirNW, cDirNE, cDirSW, cDirSE, + cDirNB, cDirNT, cDirSB, cDirST, + 0, 0, 0, 0 + }; + + const int LbmFsgrSolver::dfRefZ[ cDfNum ] = { + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + cDirST, cDirSB, cDirNT, cDirNB, + cDirWT, cDirWB, cDirET, cDirEB + }; + + // Vector Order 3D: + // 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 + // 0, 0, 0, 1,-1, 0, 0, 1,-1, 1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1,-1, 1,-1, 1,-1, 1,-1 + // 0, 1,-1, 0, 0, 0, 0, 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, 1,-1, 0, 0, 0, 0, 1,-1, 1,-1, 1,-1, 1,-1, 1, 1, 1, 1, -1,-1,-1,-1 + + const int LbmFsgrSolver::dfVecX[ cDirNum ] = { + 0, 0,0, 1,-1, 0,0, + 1,-1,1,-1, + 0,0,0,0, + 1,1,-1,-1, + 1,-1, 1,-1, + 1,-1, 1,-1, + }; + const int LbmFsgrSolver::dfVecY[ cDirNum ] = { + 0, 1,-1, 0,0,0,0, + 1,1,-1,-1, + 1,1,-1,-1, + 0,0,0,0, + 1, 1,-1,-1, + 1, 1,-1,-1 + }; + const int LbmFsgrSolver::dfVecZ[ cDirNum ] = { + 0, 0,0,0,0,1,-1, + 0,0,0,0, + 1,-1,1,-1, + 1,-1,1,-1, + 1, 1, 1, 1, + -1,-1,-1,-1 + }; + + const LbmFloat LbmFsgrSolver::dfDvecX[ cDirNum ] = { + 0, 0,0, 1,-1, 0,0, + 1,-1,1,-1, + 0,0,0,0, + 1,1,-1,-1, + 1,-1, 1,-1, + 1,-1, 1,-1 + }; + const LbmFloat LbmFsgrSolver::dfDvecY[ cDirNum ] = { + 0, 1,-1, 0,0,0,0, + 1,1,-1,-1, + 1,1,-1,-1, + 0,0,0,0, + 1, 1,-1,-1, + 1, 1,-1,-1 + }; + const LbmFloat LbmFsgrSolver::dfDvecZ[ cDirNum ] = { + 0, 0,0,0,0,1,-1, + 0,0,0,0, + 1,-1,1,-1, + 1,-1,1,-1, + 1, 1, 1, 1, + -1,-1,-1,-1 + }; + + /* principal directions */ + const int LbmFsgrSolver::princDirX[ 2*LbmFsgrSolver::cDimension ] = { + 1,-1, 0,0, 0,0 + }; + const int LbmFsgrSolver::princDirY[ 2*LbmFsgrSolver::cDimension ] = { + 0,0, 1,-1, 0,0 + }; + const int LbmFsgrSolver::princDirZ[ 2*LbmFsgrSolver::cDimension ] = { + 0,0, 0,0, 1,-1 + }; + + /*! arrays for les model coefficients, inited in lbmsolver constructor */ + LbmFloat LbmFsgrSolver::lesCoeffDiag[ (cDimension-1)*(cDimension-1) ][ cDirNum ]; + LbmFloat LbmFsgrSolver::lesCoeffOffdiag[ cDimension ][ cDirNum ]; + + + const LbmFloat LbmFsgrSolver::dfLength[ cDfNum ]= { + cCollenZero, + cCollenOne, cCollenOne, cCollenOne, + cCollenOne, cCollenOne, cCollenOne, + cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, + cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, + cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo + }; + + /* precalculated equilibrium dfs, inited in lbmsolver constructor */ + LbmFloat LbmFsgrSolver::dfEquil[ dTotalNum ]; + +#else // end LBMDIM==3 , LBMDIM==2 + +/*****************************************************************************/ +/*! 2D implementation D2Q9 */ + + //! how many dimensions? + const int LbmFsgrSolver::cDimension = 2; + + //! Wi factors for collide step + const LbmFloat LbmFsgrSolver::cCollenZero = (4.0/9.0); + const LbmFloat LbmFsgrSolver::cCollenOne = (1.0/9.0); + const LbmFloat LbmFsgrSolver::cCollenSqrtTwo = (1.0/36.0); + + //! threshold value for filled/emptied cells + const LbmFloat LbmFsgrSolver::cMagicNr2 = 1.0005; + const LbmFloat LbmFsgrSolver::cMagicNr2Neg = -0.0005; + const LbmFloat LbmFsgrSolver::cMagicNr = 1.010001; + const LbmFloat LbmFsgrSolver::cMagicNrNeg = -0.010001; + + //! size of a single set of distribution functions + const int LbmFsgrSolver::cDfNum = 9; + const int LbmFsgrSolver::cDirNum = 9; + + //const string LbmFsgrSolver::dfString[ cDfNum ] = { + const char* LbmFsgrSolver::dfString[ cDfNum ] = { + " C", + " N", " S", " E", " W", + "NE", "NW", "SE","SW" + }; + + const int LbmFsgrSolver::dfNorm[ cDfNum ] = { + cDirC, + cDirN, cDirS, cDirE, cDirW, + cDirNE, cDirNW, cDirSE, cDirSW + }; + + const int LbmFsgrSolver::dfInv[ cDfNum ] = { + cDirC, + cDirS, cDirN, cDirW, cDirE, + cDirSW, cDirSE, cDirNW, cDirNE + }; + + const int LbmFsgrSolver::dfRefX[ cDfNum ] = { + 0, + 0, 0, 0, 0, + cDirSE, cDirSW, cDirNE, cDirNW + }; + + const int LbmFsgrSolver::dfRefY[ cDfNum ] = { + 0, + 0, 0, 0, 0, + cDirNW, cDirNE, cDirSW, cDirSE + }; + + const int LbmFsgrSolver::dfRefZ[ cDfNum ] = { + 0, 0, 0, 0, 0, + 0, 0, 0, 0 + }; + + // Vector Order 2D: + // 0 1 2 3 4 5 6 7 8 + // 0, 0,0, 1,-1, 1,-1,1,-1 + // 0, 1,-1, 0,0, 1,1,-1,-1 + + const int LbmFsgrSolver::dfVecX[ cDirNum ] = { + 0, + 0,0, 1,-1, + 1,-1,1,-1 + }; + const int LbmFsgrSolver::dfVecY[ cDirNum ] = { + 0, + 1,-1, 0,0, + 1,1,-1,-1 + }; + const int LbmFsgrSolver::dfVecZ[ cDirNum ] = { + 0, 0,0,0,0, 0,0,0,0 + }; + + const LbmFloat LbmFsgrSolver::dfDvecX[ cDirNum ] = { + 0, + 0,0, 1,-1, + 1,-1,1,-1 + }; + const LbmFloat LbmFsgrSolver::dfDvecY[ cDirNum ] = { + 0, + 1,-1, 0,0, + 1,1,-1,-1 + }; + const LbmFloat LbmFsgrSolver::dfDvecZ[ cDirNum ] = { + 0, 0,0,0,0, 0,0,0,0 + }; + + const int LbmFsgrSolver::princDirX[ 2*LbmFsgrSolver::cDimension ] = { + 1,-1, 0,0 + }; + const int LbmFsgrSolver::princDirY[ 2*LbmFsgrSolver::cDimension ] = { + 0,0, 1,-1 + }; + const int LbmFsgrSolver::princDirZ[ 2*LbmFsgrSolver::cDimension ] = { + 0,0, 0,0 + }; + + + /*! arrays for les model coefficients, inited in lbmsolver constructor */ + LbmFloat LbmFsgrSolver::lesCoeffDiag[ (cDimension-1)*(cDimension-1) ][ cDirNum ]; + LbmFloat LbmFsgrSolver::lesCoeffOffdiag[ cDimension ][ cDirNum ]; + + + const LbmFloat LbmFsgrSolver::dfLength[ cDfNum ]= { + cCollenZero, + cCollenOne, cCollenOne, cCollenOne, cCollenOne, + cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo + }; + + /* precalculated equilibrium dfs, inited in lbmsolver constructor */ + LbmFloat LbmFsgrSolver::dfEquil[ dTotalNum ]; + +// D2Q9 end +#endif // LBMDIM==2 + + +// required globals +extern bool glob_mpactive; +extern int glob_mpnum, glob_mpindex; + + +/****************************************************************************** + * Lbm Constructor + *****************************************************************************/ +LbmFsgrSolver::LbmFsgrSolver() : + //D(), + mCurrentMass(0.0), mCurrentVolume(0.0), + mNumProblems(0), + mAvgMLSUPS(0.0), mAvgMLSUPSCnt(0.0), + mpPreviewSurface(NULL), + mTimeAdap(true), mForceTimeStepReduce(false), + mFVHeight(0.0), mFVArea(1.0), mUpdateFVHeight(false), + mInitSurfaceSmoothing(0), mFsSurfGenSetting(0), + mTimestepReduceLock(0), + mTimeSwitchCounts(0), mTimeMaxvelStepCnt(0), + mSimulationTime(0.0), mLastSimTime(0.0), + mMinTimestep(0.0), mMaxTimestep(0.0), + mMaxNoCells(0), mMinNoCells(0), mAvgNumUsedCells(0), + mObjectSpeeds(), mObjectPartslips(), mObjectMassMovnd(), + mMOIVertices(), mMOIVerticesOld(), mMOINormals(), + mIsoWeightMethod(1), + mMaxRefine(1), + mDfScaleUp(-1.0), mDfScaleDown(-1.0), + mInitialCsmago(0.02), // set to 0.02 for mMaxRefine==0 below and default for fine level, coarser ones are 0.03 + mDebugOmegaRet(0.0), + mLastOmega(1e10), mLastGravity(1e10), + mNumInvIfTotal(0), mNumFsgrChanges(0), + mDisableStandingFluidInit(0), + mInit2dYZ(false), + mForceTadapRefine(-1), mCutoff(-1) +{ + // not much to do here... +#if LBM_INCLUDE_TESTSOLVERS==1 + mpTest = new LbmTestdata(); + mMpNum = mMpIndex = 0; + mOrgSizeX = 0; + mOrgStartX = 0.; + mOrgEndX = 0.; +#endif // LBM_INCLUDE_TESTSOLVERS!=1 + mpIso = new IsoSurface( mIsoValue ); + + // init equilibrium dist. func + LbmFloat rho=1.0; + FORDF0 { + dfEquil[l] = this->getCollideEq( l,rho, 0.0, 0.0, 0.0); + } + dfEquil[dMass] = 1.; + dfEquil[dFfrac] = 1.; + dfEquil[dFlux] = FLUX_INIT; + + // init LES + int odm = 0; + for(int m=0; mlesCoeffDiag[m][l] = + this->lesCoeffOffdiag[m][l] = 0.0; + } + } + for(int m=0; mreadString("material_surf", matIso, "SimulationLbm","mpIso->material", false ); + mpIso->setMaterialName( matIso ); + mOutputSurfacePreview = mpSifAttrs->readInt("surfacepreview", mOutputSurfacePreview, "SimulationLbm","mOutputSurfacePreview", false ); + mTimeAdap = mpSifAttrs->readBool("timeadap", mTimeAdap, "SimulationLbm","mTimeAdap", false ); + mDomainBound = mpSifAttrs->readString("domainbound", mDomainBound, "SimulationLbm","mDomainBound", false ); + mDomainPartSlipValue = mpSifAttrs->readFloat("domainpartslip", mDomainPartSlipValue, "SimulationLbm","mDomainPartSlipValue", false ); + + mIsoWeightMethod= mpSifAttrs->readInt("isoweightmethod", mIsoWeightMethod, "SimulationLbm","mIsoWeightMethod", false ); + mInitSurfaceSmoothing = mpSifAttrs->readInt("initsurfsmooth", mInitSurfaceSmoothing, "SimulationLbm","mInitSurfaceSmoothing", false ); + mSmoothSurface = mpSifAttrs->readFloat("smoothsurface", mSmoothSurface, "SimulationLbm","mSmoothSurface", false ); + mSmoothNormals = mpSifAttrs->readFloat("smoothnormals", mSmoothNormals, "SimulationLbm","mSmoothNormals", false ); + mFsSurfGenSetting = mpSifAttrs->readInt("fssurfgen", mFsSurfGenSetting, "SimulationLbm","mFsSurfGenSetting", false ); + + // refinement + mMaxRefine = mRefinementDesired; + mMaxRefine = mpSifAttrs->readInt("maxrefine", mMaxRefine ,"LbmFsgrSolver", "mMaxRefine", false); + if(mMaxRefine<0) mMaxRefine=0; + if(mMaxRefine>FSGR_MAXNOOFLEVELS) mMaxRefine=FSGR_MAXNOOFLEVELS-1; + mDisableStandingFluidInit = mpSifAttrs->readInt("disable_stfluidinit", mDisableStandingFluidInit,"LbmFsgrSolver", "mDisableStandingFluidInit", false); + mInit2dYZ = mpSifAttrs->readBool("init2dyz", mInit2dYZ,"LbmFsgrSolver", "mInit2dYZ", false); + mForceTadapRefine = mpSifAttrs->readInt("forcetadaprefine", mForceTadapRefine,"LbmFsgrSolver", "mForceTadapRefine", false); + + // demo mode settings + mFVHeight = mpSifAttrs->readFloat("fvolheight", mFVHeight, "LbmFsgrSolver","mFVHeight", false ); + // FIXME check needed? + mFVArea = mpSifAttrs->readFloat("fvolarea", mFVArea, "LbmFsgrSolver","mFArea", false ); + + // debugging - skip some time... + double starttimeskip = 0.; + starttimeskip = mpSifAttrs->readFloat("forcestarttimeskip", starttimeskip, "LbmFsgrSolver","starttimeskip", false ); + mSimulationTime += starttimeskip; + if(starttimeskip>0.) debMsgStd("LbmFsgrSolver::parseStdAttrList",DM_NOTIFY,"Used starttimeskip="<parseTestdataAttrList(mpSifAttrs); +#ifdef ELBEEM_PLUGIN + mUseTestdata=1; // DEBUG +#endif // ELBEEM_PLUGIN + + mMpNum = mpSifAttrs->readInt("mpnum", mMpNum ,"LbmFsgrSolver", "mMpNum", false); + mMpIndex = mpSifAttrs->readInt("mpindex", mMpIndex ,"LbmFsgrSolver", "mMpIndex", false); + if(glob_mpactive) { + // used instead... + mMpNum = glob_mpnum; + mMpIndex = glob_mpindex; + } else { + glob_mpnum = mMpNum; + glob_mpindex = 0; + } + errMsg("LbmFsgrSolver::parseAttrList"," mpactive:"<0) { + mUseTestdata=1; // needed in this case... + } + + errMsg("LbmFsgrSolver::LBM_INCLUDE_TESTSOLVERS","Active, mUseTestdata:"<=2.) mUseTestdata=1; // equiv. to test solver check +#endif // LBM_INCLUDE_TESTSOLVERS!=1 + + mInitialCsmago = mpSifAttrs->readFloat("csmago", mInitialCsmago, "SimulationLbm","mInitialCsmago", false ); + // deprecated! + float mInitialCsmagoCoarse = 0.0; + mInitialCsmagoCoarse = mpSifAttrs->readFloat("csmago_coarse", mInitialCsmagoCoarse, "SimulationLbm","mInitialCsmagoCoarse", false ); +#if USE_LES==1 +#else // USE_LES==1 + debMsgStd("LbmFsgrSolver", DM_WARNING, "LES model switched off!",2); + mInitialCsmago = 0.0; +#endif // USE_LES==1 +} + + +/****************************************************************************** + * Initialize omegas and forces on all levels (for init/timestep change) + *****************************************************************************/ +void LbmFsgrSolver::initLevelOmegas() +{ + // no explicit settings + mOmega = mpParam->calculateOmega(mSimulationTime); + mGravity = vec2L( mpParam->calculateGravity(mSimulationTime) ); + mSurfaceTension = 0.; //mpParam->calculateSurfaceTension(); // unused + if(mInit2dYZ) { SWAPYZ(mGravity); } + + // check if last init was ok + LbmFloat gravDelta = norm(mGravity-mLastGravity); + //errMsg("ChannelAnimDebug","t:"<1)&&(mInitialCsmagogetTimestep(); + mLevel[i].lcsmago = fineCsmago; //CSMAGO_INITIAL; + mLevel[i].lcsmago_sqr = mLevel[i].lcsmago*mLevel[i].lcsmago; + mLevel[i].lcnu = (2.0* (1.0/mLevel[i].omega)-1.0) * (1.0/6.0); + } + + // init all sub levels + for(int i=mMaxRefine-1; i>=0; i--) { + //mLevel[i].omega = 2.0 * (mLevel[i+1].omega-0.5) + 0.5; + double nomega = 0.5 * ( (1.0/(double)mLevel[i+1].omega) -0.5) + 0.5; + nomega = 1.0/nomega; + mLevel[i].omega = (LbmFloat)nomega; + mLevel[i].timestep = 2.0 * mLevel[i+1].timestep; + mLevel[i].lcsmago = coarseCsmago; + mLevel[i].lcsmago_sqr = mLevel[i].lcsmago*mLevel[i].lcsmago; + mLevel[i].lcnu = (2.0* (1.0/mLevel[i].omega)-1.0) * (1.0/6.0); + } + + // for lbgk + mLevel[ mMaxRefine ].gravity = mGravity / mLevel[ mMaxRefine ].omega; + for(int i=mMaxRefine-1; i>=0; i--) { + // should be the same on all levels... + // for lbgk + mLevel[i].gravity = (mLevel[i+1].gravity * mLevel[i+1].omega) * 2.0 / mLevel[i].omega; + } + + mLastOmega = mOmega; + mLastGravity = mGravity; + // debug? invalidate old values... + mGravity = -100.0; + mOmega = -100.0; + + for(int i=0; i<=mMaxRefine; i++) { + if(!mSilent) { + errMsg("LbmFsgrSolver", "Level init "<0) { + mDfScaleUp = (mLevel[0 ].timestep/mLevel[0+1].timestep)* (1.0/mLevel[0 ].omega-1.0)/ (1.0/mLevel[0+1].omega-1.0); // yu + mDfScaleDown = (mLevel[0+1].timestep/mLevel[0 ].timestep)* (1.0/mLevel[0+1].omega-1.0)/ (1.0/mLevel[0 ].omega-1.0); // yu + } +} + + +/****************************************************************************** + * Init Solver (values should be read from config file) + *****************************************************************************/ + +/*! finish the init with config file values (allocate arrays...) */ +bool LbmFsgrSolver::initializeSolverMemory() +{ + debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Init start... "<0) { + mSizex *= mCppfStage; + mSizey *= mCppfStage; + mSizez *= mCppfStage; + } + if(mFsSurfGenSetting==-1) { + // all on + mFsSurfGenSetting = + fssgNormal | fssgNoNorth | fssgNoSouth | fssgNoEast | + fssgNoWest | fssgNoTop | fssgNoBottom | fssgNoObs ; + } + + // size inits to force cubic cells and mult4 level dimensions + // and make sure we dont allocate too much... + bool memOk = false; + int orgSx = mSizex; + int orgSy = mSizey; + int orgSz = mSizez; + double sizeReduction = 1.0; + double memEstFromFunc = -1.0; + string memreqStr(""); + bool firstMInit = true; + int minitTries=0; + while(!memOk) { + minitTries++; + initGridSizes( mSizex, mSizey, mSizez, + mvGeoStart, mvGeoEnd, mMaxRefine, PARALLEL); + + // MPT +#if LBM_INCLUDE_TESTSOLVERS==1 + if(firstMInit) { + mrSetup(); + } +#endif // LBM_INCLUDE_TESTSOLVERS==1 + firstMInit=false; + + calculateMemreqEstimate( mSizex, mSizey, mSizez, + mMaxRefine, mFarFieldSize, &memEstFromFunc, &memreqStr ); + + double memLimit; + string memLimStr("-"); + if(sizeof(void*)==4) { + // 32bit system, limit to 2GB + memLimit = 2.0* 1024.0*1024.0*1024.0; + memLimStr = string("2GB"); + } else { + // 64bit, just take 16GB as limit for now... + memLimit = 16.0* 1024.0*1024.0*1024.0; + memLimStr = string("16GB"); + } + if(memEstFromFunc>memLimit) { + sizeReduction *= 0.9; + mSizex = (int)(orgSx * sizeReduction); + mSizey = (int)(orgSy * sizeReduction); + mSizez = (int)(orgSz * sizeReduction); + debMsgStd("LbmFsgrSolver::initialize",DM_WARNING,"initGridSizes: memory limit exceeded "<< + //memEstFromFunc<<"/"<setSize(mSizex, mSizey, mSizez); + if((minitTries>1)&&(glob_mpnum)) { errMsg("LbmFsgrSolver::initialize","Warning!!!!!!!!!!!!!!! Original gridsize changed........."); } + + debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Definitions: " + <<"LBM_EPSILON="<setSimulationMaxSpeed(0.0); + if(mFVHeight>0.0) mpParam->setFluidVolumeHeight(mFVHeight); + mpParam->setTadapLevels( mMaxRefine+1 ); + + if(mForceTadapRefine>mMaxRefine) { + mpParam->setTadapLevels( mForceTadapRefine+1 ); + debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Forcing a t-adap refine level of "<calculateAllMissingValues(mSimulationTime, false)) { + errFatal("LbmFsgrSolver::initialize","Fatal: failed to init parameters! Aborting...",SIMWORLD_INITERROR); + return false; + } + + + // init vectors + for(int i=0; i<=mMaxRefine; i++) { + mLevel[i].id = i; + mLevel[i].nodeSize = 0.0; + mLevel[i].simCellSize = 0.0; + mLevel[i].omega = 0.0; + mLevel[i].time = 0.0; + mLevel[i].timestep = 1.0; + mLevel[i].gravity = LbmVec(0.0); + mLevel[i].mprsCells[0] = NULL; + mLevel[i].mprsCells[1] = NULL; + mLevel[i].mprsFlags[0] = NULL; + mLevel[i].mprsFlags[1] = NULL; + + mLevel[i].avgOmega = 0.0; + mLevel[i].avgOmegaCnt = 0.0; + } + + // init sizes + mLevel[mMaxRefine].lSizex = mSizex; + mLevel[mMaxRefine].lSizey = mSizey; + mLevel[mMaxRefine].lSizez = mSizez; + for(int i=mMaxRefine-1; i>=0; i--) { + mLevel[i].lSizex = mLevel[i+1].lSizex/2; + mLevel[i].lSizey = mLevel[i+1].lSizey/2; + mLevel[i].lSizez = mLevel[i+1].lSizez/2; + } + + // safety check + if(sizeof(CellFlagType) != CellFlagTypeSize) { + errFatal("LbmFsgrSolver::initialize","Fatal Error: CellFlagType has wrong size! Is:"<getCellSize(); + mLevel[ mMaxRefine ].lcellfactor = 1.0; + LONGINT rcellSize = ((mLevel[mMaxRefine].lSizex*mLevel[mMaxRefine].lSizey*mLevel[mMaxRefine].lSizez) *dTotalNum); + // +4 for safety ? + mLevel[ mMaxRefine ].mprsFlags[0] = new CellFlagType[ rcellSize/dTotalNum +4 ]; + mLevel[ mMaxRefine ].mprsFlags[1] = new CellFlagType[ rcellSize/dTotalNum +4 ]; + ownMemCheck += 2 * sizeof(CellFlagType) * (rcellSize/dTotalNum +4); + +#if COMPRESSGRIDS==0 + mLevel[ mMaxRefine ].mprsCells[0] = new LbmFloat[ rcellSize +4 ]; + mLevel[ mMaxRefine ].mprsCells[1] = new LbmFloat[ rcellSize +4 ]; + ownMemCheck += 2 * sizeof(LbmFloat) * (rcellSize+4); +#else // COMPRESSGRIDS==0 + LONGINT compressOffset = (mLevel[mMaxRefine].lSizex*mLevel[mMaxRefine].lSizey*dTotalNum*2); + mLevel[ mMaxRefine ].mprsCells[1] = new LbmFloat[ rcellSize +compressOffset +4 ]; + mLevel[ mMaxRefine ].mprsCells[0] = mLevel[ mMaxRefine ].mprsCells[1]+compressOffset; + ownMemCheck += sizeof(LbmFloat) * (rcellSize +compressOffset +4); +#endif // COMPRESSGRIDS==0 + + LbmFloat lcfdimFac = 8.0; + if(LBMDIM==2) lcfdimFac = 4.0; + for(int i=mMaxRefine-1; i>=0; i--) { + mLevel[i].nodeSize = 2.0 * mLevel[i+1].nodeSize; + mLevel[i].simCellSize = 2.0 * mLevel[i+1].simCellSize; + mLevel[i].lcellfactor = mLevel[i+1].lcellfactor * lcfdimFac; + + if(LBMDIM==2){ mLevel[i].lSizez = 1; } // 2D + rcellSize = ((mLevel[i].lSizex*mLevel[i].lSizey*mLevel[i].lSizez) *dTotalNum); + mLevel[i].mprsFlags[0] = new CellFlagType[ rcellSize/dTotalNum +4 ]; + mLevel[i].mprsFlags[1] = new CellFlagType[ rcellSize/dTotalNum +4 ]; + ownMemCheck += 2 * sizeof(CellFlagType) * (rcellSize/dTotalNum +4); + mLevel[i].mprsCells[0] = new LbmFloat[ rcellSize +4 ]; + mLevel[i].mprsCells[1] = new LbmFloat[ rcellSize +4 ]; + ownMemCheck += 2 * sizeof(LbmFloat) * (rcellSize+4); + } + + // isosurface memory, use orig res values + if(mFarFieldSize>0.) { + ownMemCheck += (double)( (3*sizeof(int)+sizeof(float)) * ((mSizex+2)*(mSizey+2)*(mSizez+2)) ); + } else { + // ignore 3 int slices... + ownMemCheck += (double)( ( sizeof(float)) * ((mSizex+2)*(mSizey+2)*(mSizez+2)) ); + } + + // sanity check +#if ELBEEM_PLUGIN!=1 + if(ABS(1.0-ownMemCheck/memEstFromFunc)>0.01) { + errMsg("LbmFsgrSolver::initialize","Sanity Error - memory estimate is off! real:"<=0; i--) { + mLevel[i].lOffsx = mLevel[i].lSizex; + mLevel[i].lOffsy = mLevel[i].lOffsx*mLevel[i].lSizey; + mLevel[i].lOffsz = mLevel[i].lOffsy*mLevel[i].lSizez; + mLevel[i].setCurr = 0; + mLevel[i].setOther = 1; + mLevel[i].lsteps = 0; + mLevel[i].lmass = 0.0; + mLevel[i].lvolume = 0.0; + } + + // calc omega, force for all levels + initLevelOmegas(); + mMinTimestep = mpParam->getTimestep(); + mMaxTimestep = mpParam->getTimestep(); + + // init isosurf + mpIso->setIsolevel( mIsoValue ); +#if LBM_INCLUDE_TESTSOLVERS==1 + if(mUseTestdata) { + mpTest->setMaterialName( mpIso->getMaterialName() ); + delete mpIso; + mpIso = mpTest; + if(mpTest->mFarfMode>0) { // 3d off + mpTest->setIsolevel(-100.0); + } else { + mpTest->setIsolevel( mIsoValue ); + } + } +#endif // LBM_INCLUDE_TESTSOLVERS!=1 + // approximate feature size with mesh resolution + float featureSize = mLevel[ mMaxRefine ].nodeSize*0.5; + // smooth vars defined in solver_interface, set by simulation object + // reset for invalid values... + if((mSmoothSurface<0.)||(mSmoothSurface>50.)) mSmoothSurface = 1.; + if((mSmoothNormals<0.)||(mSmoothNormals>50.)) mSmoothNormals = 1.; + mpIso->setSmoothSurface( mSmoothSurface * featureSize ); + mpIso->setSmoothNormals( mSmoothNormals * featureSize ); + + // init iso weight values mIsoWeightMethod + int wcnt = 0; + float totw = 0.0; + for(int ak=-1;ak<=1;ak++) + for(int aj=-1;aj<=1;aj++) + for(int ai=-1;ai<=1;ai++) { + switch(mIsoWeightMethod) { + case 1: // light smoothing + mIsoWeight[wcnt] = sqrt(3.0) - sqrt( (LbmFloat)(ak*ak + aj*aj + ai*ai) ); + break; + case 2: // very light smoothing + mIsoWeight[wcnt] = sqrt(3.0) - sqrt( (LbmFloat)(ak*ak + aj*aj + ai*ai) ); + mIsoWeight[wcnt] *= mIsoWeight[wcnt]; + break; + case 3: // no smoothing + if(ai==0 && aj==0 && ak==0) mIsoWeight[wcnt] = 1.0; + else mIsoWeight[wcnt] = 0.0; + break; + default: // strong smoothing (=0) + mIsoWeight[wcnt] = 1.0; + break; + } + totw += mIsoWeight[wcnt]; + wcnt++; + } + for(int i=0; i<27; i++) mIsoWeight[i] /= totw; + + LbmVec isostart = vec2L(mvGeoStart); + LbmVec isoend = vec2L(mvGeoEnd); + int twodOff = 0; // 2d slices + if(LBMDIM==2) { + LbmFloat sn,se; + sn = isostart[2]+(isoend[2]-isostart[2])*0.5 - ((isoend[0]-isostart[0]) / (LbmFloat)(mSizex+1.0))*0.5; + se = isostart[2]+(isoend[2]-isostart[2])*0.5 + ((isoend[0]-isostart[0]) / (LbmFloat)(mSizex+1.0))*0.5; + isostart[2] = sn; + isoend[2] = se; + twodOff = 2; + } + int isosx = mSizex+2; + int isosy = mSizey+2; + int isosz = mSizez+2+twodOff; + + // MPT +#if LBM_INCLUDE_TESTSOLVERS==1 + //if( strstr( this->getName().c_str(), "mpfluid1" ) != NULL) { + if( (mMpNum>0) && (mMpIndex==0) ) { + //? mpindex==0 + // restore original value for node0 + isosx = mOrgSizeX + 2; + isostart[0] = mOrgStartX; + isoend[0] = mOrgEndX; + } + errMsg("LbmFsgrSolver::initialize", "MPT: gcon "<mGCMin.mSrcx,mpTest->mGCMin.mSrcy,mpTest->mGCMin.mSrcz)<<" dst" + << PRINT_VEC(mpTest->mGCMin.mDstx,mpTest->mGCMin.mDsty,mpTest->mGCMin.mDstz)<<" consize" + << PRINT_VEC(mpTest->mGCMin.mConSizex,mpTest->mGCMin.mConSizey,mpTest->mGCMin.mConSizez)<<" "); + errMsg("LbmFsgrSolver::initialize", "MPT: gcon "<mGCMax.mSrcx,mpTest->mGCMax.mSrcy,mpTest->mGCMax.mSrcz)<<" dst" + << PRINT_VEC(mpTest->mGCMax.mDstx,mpTest->mGCMax.mDsty,mpTest->mGCMax.mDstz)<<" consize" + << PRINT_VEC(mpTest->mGCMax.mConSizex,mpTest->mGCMax.mConSizey,mpTest->mGCMax.mConSizez)<<" "); +#endif // LBM_INCLUDE_TESTSOLVERS==1 + + errMsg(" SETISO ", "iso "<setStart( vec2G(isostart) ); + mpIso->setEnd( vec2G(isoend) ); + LbmVec isodist = isoend-isostart; + + int isosubs = mIsoSubdivs; + if(mFarFieldSize>1.) { + errMsg("LbmFsgrSolver::initialize","Warning - resetting isosubdivs, using fulledge!"); + isosubs = 1; + mpIso->setUseFulledgeArrays(true); + } + mpIso->setSubdivs(isosubs); + + mpIso->initializeIsosurface( isosx,isosy,isosz, vec2G(isodist) ); + + // reset iso field + for(int ak=0;akgetData(ai,aj,ak) = 0.0; } + + + /* init array (set all invalid first) */ + preinitGrids(); + for(int lev=0; lev<=mMaxRefine; lev++) { + FSGR_FORIJK_BOUNDS(lev) { + RFLAG(lev,i,j,k,0) = RFLAG(lev,i,j,k,0) = 0; // reset for changeFlag usage + if(!mAllfluid) { + initEmptyCell(lev, i,j,k, CFEmpty, -1.0, -1.0); + } else { + initEmptyCell(lev, i,j,k, CFFluid, 1.0, 1.0); + } + } + } + + + if(LBMDIM==2) { + if(mOutputSurfacePreview) { + errMsg("LbmFsgrSolver::init","No preview in 2D allowed!"); + mOutputSurfacePreview = 0; } + } + if((glob_mpactive) && (glob_mpindex>0)) { + mOutputSurfacePreview = 0; + } + +#if LBM_USE_GUI==1 + if(mOutputSurfacePreview) { + errMsg("LbmFsgrSolver::init","No preview in GUI mode... mOutputSurfacePreview=0"); + mOutputSurfacePreview = 0; } +#endif // LBM_USE_GUI==1 + if(mOutputSurfacePreview) { + // same as normal one, but use reduced size + mpPreviewSurface = new IsoSurface( mIsoValue ); + mpPreviewSurface->setMaterialName( mpPreviewSurface->getMaterialName() ); + mpPreviewSurface->setIsolevel( mIsoValue ); + // usually dont display for rendering + mpPreviewSurface->setVisible( false ); + + mpPreviewSurface->setStart( vec2G(isostart) ); + mpPreviewSurface->setEnd( vec2G(isoend) ); + LbmVec pisodist = isoend-isostart; + LbmFloat pfac = mPreviewFactor; + mpPreviewSurface->initializeIsosurface( (int)(pfac*mSizex)+2, (int)(pfac*mSizey)+2, (int)(pfac*mSizez)+2, vec2G(pisodist) ); + //mpPreviewSurface->setName( getName() + "preview" ); + mpPreviewSurface->setName( "preview" ); + + debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Preview with sizes "<<(pfac*mSizex)<<","<<(pfac*mSizey)<<","<<(pfac*mSizez)<<" enabled",10); + } + + // init defaults + mAvgNumUsedCells = 0; + mFixMass= 0.0; + return true; +} + +/*! init solver arrays */ +bool LbmFsgrSolver::initializeSolverGrids() { + /* init boundaries */ + debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Boundary init...",10); + // init obstacles, and reinit time step size + initGeometryFlags(); + mLastSimTime = -1.0; + // TODO check for invalid cells? nitGenericTestCases(); + + // new - init noslip 1 everywhere... + // half fill boundary cells? + + CellFlagType domainBoundType = CFInvalid; + // TODO use normal object types instad... + if(mDomainBound.find(string("free")) != string::npos) { + domainBoundType = CFBnd | CFBndFreeslip; + debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Domain Boundary Type: FreeSlip, value:"<size()); + domainBoundType |= (domainobj<<24); + //for(int i=0; i<(int)(domainobj+0); i++) { + //errMsg("GEOIN","i"<getName()); + //if((*mpGiObjects)[i] == mpIso) { //check... + //} + //} + //errMsg("GEOIN"," dm "<<(domainBoundType>>24)); + + for(int k=0;kgetName().c_str(), "vorttfluid" ) != NULL) && (LBMDIM==2)) { + errMsg("VORTT","init"); + int level=mMaxRefine; + int cx = mLevel[level].lSizex/2; + int cyo = mLevel[level].lSizey/2; + int sx = mLevel[level].lSizex/8; + int sy = mLevel[level].lSizey/8; + LbmFloat rho = 1.; + LbmFloat rhomass = 1.; + LbmFloat uFactor = 0.15; + LbmFloat vdist = 1.0; + + int cy1=cyo-(int)(vdist*sy); + int cy2=cyo+(int)(vdist*sy); + + //for(int j=cy-sy;jcalculateCellSize(); + if(LBMDIM==2) cspv[2] = 1.0; + inmCellCnt = 1; + double nrmMass = (double)mInitialMass / (double)(inmCellCnt) *cspv[0]*cspv[1]*cspv[2] * 1000.0; + debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Initial Mass:"<=0; lev--) { + debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Coarsening level "<setParticles(mpParticles, mPartDropMassSub); + debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Iso Settings, subdivs="<getSubdivs()<<", partsize="<getSmoothSurface()<<","<getSmoothNormals()<<") ",10); + debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Init done ... ",10); + mInitDone = 1; + +#if LBM_INCLUDE_TESTSOLVERS==1 + initCpdata(); + initTestdata(); +#endif // ELBEEM_PLUGIN!=1 + // not inited? dont use... + if(mCutoff<0) mCutoff=0; + + initParticles(); + return true; +} + + + +// macros for mov obj init +#if LBMDIM==2 + +#define POS2GRID_CHECK(vec,n) \ + monTotal++;\ + int k=(int)( ((vec)[n][2]-iniPos[2])/dvec[2] +0.0); \ + if(k!=0) continue; \ + const int i=(int)( ((vec)[n][0]-iniPos[0])/dvec[0] +0.0); \ + if(i<=0) continue; \ + if(i>=mLevel[level].lSizex-1) continue; \ + const int j=(int)( ((vec)[n][1]-iniPos[1])/dvec[1] +0.0); \ + if(j<=0) continue; \ + if(j>=mLevel[level].lSizey-1) continue; \ + +#else // LBMDIM -> 3 +#define POS2GRID_CHECK(vec,n) \ + monTotal++;\ + const int i=(int)( ((vec)[n][0]-iniPos[0])/dvec[0] +0.0); \ + if(i<=0) continue; \ + if(i>=mLevel[level].lSizex-1) continue; \ + const int j=(int)( ((vec)[n][1]-iniPos[1])/dvec[1] +0.0); \ + if(j<=0) continue; \ + if(j>=mLevel[level].lSizey-1) continue; \ + const int k=(int)( ((vec)[n][2]-iniPos[2])/dvec[2] +0.0); \ + if(k<=0) continue; \ + if(k>=mLevel[level].lSizez-1) continue; \ + +#endif // LBMDIM + +// calculate object velocity from vert arrays in objvel vec +#define OBJVEL_CALC \ + LbmVec objvel = vec2L((mMOIVertices[n]-mMOIVerticesOld[n]) /dvec); { \ + const LbmFloat usqr = (objvel[0]*objvel[0]+objvel[1]*objvel[1]+objvel[2]*objvel[2])*1.5; \ + USQRMAXCHECK(usqr, objvel[0],objvel[1],objvel[2], mMaxVlen, mMxvx,mMxvy,mMxvz); \ + if(usqr>maxusqr) { \ + /* cutoff at maxVelVal */ \ + for(int jj=0; jj<3; jj++) { \ + if(objvel[jj]>0.) objvel[jj] = maxVelVal; \ + if(objvel[jj]<0.) objvel[jj] = -maxVelVal; \ + } \ + } } \ + if(ntype&(CFBndFreeslip)) { \ + const LbmFloat dp=dot(objvel, vec2L((*pNormals)[n]) ); \ + const LbmVec oldov=objvel; /*DEBUG*/ \ + objvel = vec2L((*pNormals)[n]) *dp; \ + /* if((j==24)&&(n%5==2)) errMsg("FSBT","n"<size()); + ntlVec3Gfx dvec = ntlVec3Gfx(mLevel[level].nodeSize); //dvec*1.0; + // 2d display as rectangles + ntlVec3Gfx iniPos(0.0); + if(LBMDIM==2) { + dvec[2] = 1.0; + iniPos = (mvGeoStart + ntlVec3Gfx( 0.0, 0.0, (mvGeoEnd[2]-mvGeoStart[2])*0.5 ))-(dvec*0.0); + } else { + iniPos = (mvGeoStart + ntlVec3Gfx( 0.0 ))-(dvec*0.0); + } + + if( (int)mObjectMassMovnd.size() < numobjs) { + for(int i=mObjectMassMovnd.size(); igetGeoInitId() != mLbmInitId) skip=true; + if( (!staticInit) && (!obj->getIsAnimated()) ) skip=true; + if( ( staticInit) && ( obj->getIsAnimated()) ) skip=true; + if(skip) continue; + debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_MSG," obj "<getName()<<" skip:"<getIsAnimated()<<" gid:"<getGeoInitId()<<" simgid:"<getGeoInitType()&FGI_ALLBOUNDS) || + (obj->getGeoInitType()&FGI_FLUID) && staticInit ) { + + otype = ntype = CFInvalid; + switch(obj->getGeoInitType()) { + /* case FGI_BNDPART: // old, use noslip for moving part/free objs + case FGI_BNDFREE: + if(!staticInit) { + errMsg("LbmFsgrSolver::initMovingObstacles","Warning - moving free/part slip objects NYI "<getName() ); + otype = ntype = CFBnd|CFBndNoslip; + } else { + if(obj->getGeoInitType()==FGI_BNDPART) otype = ntype = CFBnd|CFBndPartslip; + if(obj->getGeoInitType()==FGI_BNDFREE) otype = ntype = CFBnd|CFBndFreeslip; + } + break; + // off */ + case FGI_BNDPART: rhomass = BND_FILL; + otype = ntype = CFBnd|CFBndPartslip|(OId<<24); + break; + case FGI_BNDFREE: rhomass = BND_FILL; + otype = ntype = CFBnd|CFBndFreeslip|(OId<<24); + break; + // off */ + case FGI_BNDNO: rhomass = BND_FILL; + otype = ntype = CFBnd|CFBndNoslip|(OId<<24); + break; + case FGI_FLUID: + otype = ntype = CFFluid; + break; + case FGI_MBNDINFLOW: + otype = ntype = CFMbndInflow; + break; + case FGI_MBNDOUTFLOW: + otype = ntype = CFMbndOutflow; + break; + } + int wasActive = ((obj->getGeoActive(sourceTime)>0.)? 1:0); + int active = ((obj->getGeoActive(targetTime)>0.)? 1:0); + //errMsg("GEOACTT"," obj "<getName()<<" a:"<getGeoInitType()); continue; } + if((!active) && (otype&(CFMbndOutflow|CFMbndInflow)) ) continue; + + // copied from recalculateObjectSpeeds + mObjectSpeeds[OId] = vec2L(mpParam->calculateLattVelocityFromRw( vec2P( (*mpGiObjects)[OId]->getInitialVelocity(mSimulationTime) ))); + debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_MSG,"id"<getName()<<" inivel set to "<< mObjectSpeeds[OId]<<", unscaled:"<< (*mpGiObjects)[OId]->getInitialVelocity(mSimulationTime) ,10 ); + + //vector tNormals; + vector *pNormals = NULL; + mMOINormals.clear(); + if(ntype&(CFBndFreeslip|CFBndPartslip)) { pNormals = &mMOINormals; } + + mMOIVertices.clear(); + if(obj->getMeshAnimated()) { + // do two full update + // TODO tNormals handling!? + mMOIVerticesOld.clear(); + obj->initMovingPointsAnim(sourceTime,mMOIVerticesOld, targetTime, mMOIVertices, pNormals, mLevel[mMaxRefine].nodeSize, mvGeoStart, mvGeoEnd); + monTrafo += mMOIVerticesOld.size(); + obj->applyTransformation(sourceTime, &mMOIVerticesOld,pNormals, 0, mMOIVerticesOld.size(), false ); + monTrafo += mMOIVertices.size(); + obj->applyTransformation(targetTime, &mMOIVertices,NULL /* no old normals needed */, 0, mMOIVertices.size(), false ); + } else { + // only do transform update + obj->getMovingPoints(mMOIVertices,pNormals); + mMOIVerticesOld = mMOIVertices; + // WARNING - assumes mSimulationTime is global!? + obj->applyTransformation(targetTime, &mMOIVertices,pNormals, 0, mMOIVertices.size(), false ); + monTrafo += mMOIVertices.size(); + + // correct flags from last position, but extrapolate + // velocity to next timestep + obj->applyTransformation(sourceTime, &mMOIVerticesOld, NULL /* no old normals needed */, 0, mMOIVerticesOld.size(), false ); + monTrafo += mMOIVerticesOld.size(); + } + + // object types + if(ntype&CFBnd){ + + // check if object is moving at all + if(obj->getIsAnimated()) { + ntlVec3Gfx objMaxVel = obj->calculateMaxVel(sourceTime,targetTime); + // FIXME? + if(normNoSqrt(objMaxVel)>0.0) { ntype |= CFBndMoving; } + // get old type - CHECK FIXME , timestep could have changed - cause trouble? + ntlVec3Gfx oldobjMaxVel = obj->calculateMaxVel(sourceTime - mpParam->getTimestep(),sourceTime); + if(normNoSqrt(oldobjMaxVel)>0.0) { otype |= CFBndMoving; } + } + if(obj->getMeshAnimated()) { ntype |= CFBndMoving; otype |= CFBndMoving; } + CellFlagType rflagnb[27]; + LbmFloat massCheck = 0.; + int massReinits=0; + bool fillCells = (mObjectMassMovnd[OId]<=-1.); + LbmFloat impactCorrFactor = obj->getGeoImpactFactor(targetTime); + + + // first pass - set new obs. cells + if(active) { + for(size_t n=0; n "< "< "<getName()<<" dccd massCheck="<getName()<<" verts"<getName()<<" inflow "<getCollideEq(l, iniRho,vel[0],vel[1],vel[2]); } + RAC(tcel, dMass) = RAC(tcel, dFfrac) = iniRho; + RAC(tcel, dFlux) = FLUX_INIT; + CellFlagType setFlag = CFInter; + changeFlag(level, i,j,k, workSet, setFlag); + mInitialMass += iniRho; + } + // second static init pass + if(staticInit) { + CellFlagType set2Flag = CFMbndInflow|(OId<<24); + for(size_t n=0; nsize()); + for(int o=0; ogetName()<<" type "<getGeoInitType()<<" anim"<getIsAnimated()<<" "<getVolumeInit() ,9); + if( + ((obj->getGeoInitType()&FGI_ALLBOUNDS) && (obj->getIsAnimated())) || + (obj->getVolumeInit()&VOLUMEINIT_SHELL) ) { + if(!obj->getMeshAnimated()) { + debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_MSG," obj "<getName()<<" type "<getGeoInitType()<<" anim"<getIsAnimated()<<" "<getVolumeInit() ,9); + obj->initMovingPoints(mSimulationTime, mLevel[mMaxRefine].nodeSize); + } + } + } + + // max speed init + ntlVec3Gfx maxMovobjVelRw = getGeoMaxMovementVelocity( mSimulationTime, mpParam->getTimestep() ); + ntlVec3Gfx maxMovobjVel = vec2G( mpParam->calculateLattVelocityFromRw( vec2P( maxMovobjVelRw )) ); + mpParam->setSimulationMaxSpeed( norm(maxMovobjVel) + norm(mLevel[level].gravity) ); + LbmFloat allowMax = mpParam->getTadapMaxSpeed(); // maximum allowed velocity + debMsgStd("LbmFsgrSolver::initGeometryFlags",DM_MSG,"Maximum Velocity from geo init="<< maxMovobjVel <<" from mov. obj.="<setDesiredTimestep( newdt ); + mpParam->calculateAllMissingValues( mSimulationTime, mSilent ); + maxMovobjVel = vec2G( mpParam->calculateLattVelocityFromRw( vec2P(getGeoMaxMovementVelocity( + mSimulationTime, mpParam->getTimestep() )) )); + debMsgStd("LbmFsgrSolver::initGeometryFlags",DM_MSG,"New maximum Velocity from geo init="<< maxMovobjVel,5); + } + recalculateObjectSpeeds(); + // */ + + // init obstacles for first time step (requires obj speeds) + initMovingObstacles(true); + + /* set interface cells */ + ntlVec3Gfx pos,iniPos; // position of current cell + LbmFloat rhomass = 0.0; + CellFlagType ntype = CFInvalid; + int savedNodes = 0; + int OId = -1; + gfxReal distance; + + // 2d display as rectangles + if(LBMDIM==2) { + dvec[2] = 0.0; + iniPos =(mvGeoStart + ntlVec3Gfx( 0.0, 0.0, (mvGeoEnd[2]-mvGeoStart[2])*0.5 ))+(dvec*0.5); + //if(mInit2dYZ) { SWAPYZ(mGravity); for(int lev=0; lev<=mMaxRefine; lev++){ SWAPYZ( mLevel[lev].gravity ); } } + } else { + iniPos =(mvGeoStart + ntlVec3Gfx( 0.0 ))+(dvec*0.5); + } + + + // first init boundary conditions + // invalid cells are set to empty afterwards + // TODO use floop macros!? + for(int k= getForZMin1(); k< getForZMax1(level); ++k) { + for(int j=1;jgetGeoInitType() ){ + case FGI_MBNDINFLOW: + if(! pObj->getIsAnimated() ) { + rhomass = 1.0; + ntype = CFFluid | CFMbndInflow; + } else { + ntype = CFInvalid; + } + break; + case FGI_MBNDOUTFLOW: + if(! pObj->getIsAnimated() ) { + rhomass = 0.0; + ntype = CFEmpty|CFMbndOutflow; + } else { + ntype = CFInvalid; + } + break; + case FGI_BNDNO: + rhomass = BND_FILL; + ntype = CFBnd|CFBndNoslip; + break; + case FGI_BNDPART: + rhomass = BND_FILL; + ntype = CFBnd|CFBndPartslip; break; + case FGI_BNDFREE: + rhomass = BND_FILL; + ntype = CFBnd|CFBndFreeslip; break; + default: // warn here? + rhomass = BND_FILL; + ntype = CFBnd|CFBndNoslip; break; + } + } + if(ntype != CFInvalid) { + // initDefaultCell + if((ntype & CFMbndInflow) || (ntype & CFMbndOutflow) ) { } + ntype |= (OId<<24); // NEWTEST2 + initVelocityCell(level, i,j,k, ntype, rhomass, rhomass, mObjectSpeeds[OId] ); + } + + // walk along x until hit for following inits + if(distance<=-1.0) { distance = 100.0; } // FIXME dangerous + if(distance>=0.0) { + gfxReal dcnt=dvec[0]; + while(( dcnt< distance-dvec[0] )&&(i+1=0.0) { + gfxReal dcnt=dvec[0]; + while((dcnt< distance )&&(i+10 + + } + } + } // zmax + + // reset invalid to empty again + for(int k= getForZMin1(); k< getForZMax1(level); ++k) { + for(int j=1;j0) { + debMsgStd("Surface Smoothing init", DM_MSG, "Performing "<<(mInitSurfaceSmoothing)<<" smoothing timestep ",10); +#if COMPRESSGRIDS==1 + //errFatal("NYI","COMPRESSGRIDS mInitSurfaceSmoothing",SIMWORLD_INITERROR); return; +#endif // COMPRESSGRIDS==0 + } + for(int s=0; s1) { haveStandingFluid=(iindex); } \ + j = mLevel[mMaxRefine].lSizey; i=mLevel[mMaxRefine].lSizex; k=getForZMaxBnd(); \ + continue; \ + } + int gravIndex[3] = {0,0,0}; + int gravDir[3] = {1,1,1}; + int maxGravComp = 1; // by default y + int gravComp1 = 0; // by default y + int gravComp2 = 2; // by default y + if( ABS(mLevel[mMaxRefine].gravity[0]) > ABS(mLevel[mMaxRefine].gravity[1]) ){ maxGravComp = 0; gravComp1=1; gravComp2=2; } + if( ABS(mLevel[mMaxRefine].gravity[2]) > ABS(mLevel[mMaxRefine].gravity[0]) ){ maxGravComp = 2; gravComp1=0; gravComp2=1; } + + int gravIMin[3] = { 0 , 0 , 0 }; + int gravIMax[3] = { + mLevel[mMaxRefine].lSizex + 0, + mLevel[mMaxRefine].lSizey + 0, + mLevel[mMaxRefine].lSizez + 0 }; + if(LBMDIM==2) gravIMax[2] = 1; + + //int gravDir = 1; + if( mLevel[mMaxRefine].gravity[maxGravComp] > 0.0 ) { + // swap directions + int i=maxGravComp; + int tmp = gravIMin[i]; + gravIMin[i] = gravIMax[i] - 1; + gravIMax[i] = tmp - 1; + gravDir[i] = -1; + } +#define PRINTGDIRS \ + errMsg("Standing fp","X start="<>2); // not much use...? + //preinitSteps = 0; + debMsgStd("Standing fluid preinit", DM_MSG, "Performing "< /* getenv(3) - also in linux */ + + + +/****************************************************************************** + * Interface Constructor + *****************************************************************************/ +LbmSolverInterface::LbmSolverInterface() : + mPanic( false ), + mSizex(10), mSizey(10), mSizez(10), + mAllfluid(false), mStepCnt( 0 ), + mFixMass( 0.0 ), + mOmega( 1.0 ), + mGravity(0.0), + mSurfaceTension( 0.0 ), + mBoundaryEast( (CellFlagType)(CFBnd) ),mBoundaryWest( (CellFlagType)(CFBnd) ),mBoundaryNorth( (CellFlagType)(CFBnd) ), + mBoundarySouth( (CellFlagType)(CFBnd) ),mBoundaryTop( (CellFlagType)(CFBnd) ),mBoundaryBottom( (CellFlagType)(CFBnd) ), + mInitDone( false ), + mInitDensityGradient( false ), + mpSifAttrs( NULL ), mpSifSwsAttrs(NULL), mpParam( NULL ), mpParticles(NULL), + mNumParticlesLost(0), + mNumInvalidDfs(0), mNumFilledCells(0), mNumEmptiedCells(0), mNumUsedCells(0), mMLSUPS(0), + mDebugVelScale( 0.01 ), mNodeInfoString("+"), + mvGeoStart(-1.0), mvGeoEnd(1.0), mpSimTrafo(NULL), + mAccurateGeoinit(0), + mName("lbm_default") , + mpIso( NULL ), mIsoValue(0.499), + mSilent(false) , + mLbmInitId(1) , + mpGiTree( NULL ), + mpGiObjects( NULL ), mGiObjInside(), mpGlob( NULL ), + mRefinementDesired(0), + mOutputSurfacePreview(0), mPreviewFactor(0.25), + mSmoothSurface(1.0), mSmoothNormals(1.0), + mIsoSubdivs(1), mPartGenProb(0.), + mDumpVelocities(false), + mMarkedCells(), mMarkedCellIndex(0), + mDomainBound("noslip"), mDomainPartSlipValue(0.1), + mFarFieldSize(0.), + mPartDropMassSub(0.1), // good default + mPartUsePhysModel(false), + mTForceStrength(0.0), + mCppfStage(0), + mDumpRawText(false), + mDumpRawBinary(false), + mDumpRawBinaryZip(true) +{ +#if ELBEEM_PLUGIN==1 + if(gDebugLevel<=1) setSilent(true); +#endif + mpSimTrafo = new ntlMat4Gfx(0.0); + mpSimTrafo->initId(); + + if(getenv("ELBEEM_RAWDEBUGDUMP")) { + debMsgStd("LbmSolverInterface",DM_MSG,"Using env var ELBEEM_RAWDEBUGDUMP, mDumpRawText on",2); + mDumpRawText = true; + } + + if(getenv("ELBEEM_BINDEBUGDUMP")) { + debMsgStd("LbmSolverInterface",DM_MSG,"Using env var ELBEEM_RAWDEBUGDUMP, mDumpRawText on",2); + mDumpRawBinary = true; + } +} + +LbmSolverInterface::~LbmSolverInterface() +{ + if(mpSimTrafo) delete mpSimTrafo; +} + + +/****************************************************************************** + * initialize correct grid sizes given a geometric bounding box + * and desired grid resolutions, all params except maxrefine + * will be modified + *****************************************************************************/ +void initGridSizes(int &sizex, int &sizey, int &sizez, + ntlVec3Gfx &geoStart, ntlVec3Gfx &geoEnd, + int mMaxRefine, bool parallel) +{ + // fix size inits to force cubic cells and mult4 level dimensions + const int debugGridsizeInit = 1; + if(debugGridsizeInit) debMsgStd("initGridSizes",DM_MSG,"Called - size X:"<maxGridSize) maxGridSize = sizey; + if(sizez>maxGridSize) maxGridSize = sizez; + LbmFloat maxGeoSize = (geoEnd[0]-geoStart[0]); // get max size + if((geoEnd[1]-geoStart[1])>maxGeoSize) maxGeoSize = (geoEnd[1]-geoStart[1]); + if((geoEnd[2]-geoStart[2])>maxGeoSize) maxGeoSize = (geoEnd[2]-geoStart[2]); + // FIXME better divide max geo size by corresponding resolution rather than max? no prob for rx==ry==rz though + LbmFloat cellSize = (maxGeoSize / (LbmFloat)maxGridSize); + if(debugGridsizeInit) debMsgStd("initGridSizes",DM_MSG,"Start:"<=0; i--) { + currResx /= 2.0; + currResy /= 2.0; + currResz /= 2.0; + rcellSize = ((currResz*currResy*currResx) *ddTotalNum); + memCnt += (double)(sizeof(CellFlagType) * (rcellSize/ddTotalNum +4.0) *2.0); + memCnt += (double)(sizeof(LbmFloat) * (rcellSize +4.0) *2.0); + if(debugMemEst) debMsgStd("calculateMemreqEstimate",DM_MSG,"refine "<0.) { + memCnt += (double)( (3*sizeof(int)+sizeof(float)) * ((resx+2)*(resy+2)*(resz+2)) ); + } else { + // ignore 3 int slices... + memCnt += (double)( ( sizeof(float)) * ((resx+2)*(resy+2)*(resz+2)) ); + } + if(debugMemEst) debMsgStd("calculateMemreqEstimate",DM_MSG,"iso, mc:"<sfac){ memd /= sfac; sizeStr="KB"; } + if(memd>sfac){ memd /= sfac; sizeStr="MB"; } + if(memd>sfac){ memd /= sfac; sizeStr="GB"; } + if(memd>sfac){ memd /= sfac; sizeStr="TB"; } + + // return values + std::ostringstream ret; + if(memCnt< 1024.0*1024.0) { + // show full MBs + ret << (ceil(memd)); + } else { + // two digits for anything larger than MB + ret << (ceil(memd*100.0)/100.0); + } + ret << " "<< sizeStr; + *reqret = memCnt; + *reqstr = ret.str(); + //debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Required Grid memory: "<< memd <<" "<< sizeStr<<" ",4); +} + +void LbmSolverInterface::initDomainTrafo(float *mat) { + mpSimTrafo->initArrayCheck(mat); +} + +/*******************************************************************************/ +/*! parse a boundary flag string */ +CellFlagType LbmSolverInterface::readBoundaryFlagInt(string name, int defaultValue, string source,string target, bool needed) { + string val = mpSifAttrs->readString(name, "", source, target, needed); + if(!strcmp(val.c_str(),"")) { + // no value given... + return CFEmpty; + } + if(!strcmp(val.c_str(),"bnd_no")) { + return (CellFlagType)( CFBnd ); + } + if(!strcmp(val.c_str(),"bnd_free")) { + return (CellFlagType)( CFBnd ); + } + if(!strcmp(val.c_str(),"fluid")) { + /* might be used for some in/out flow cases */ + return (CellFlagType)( CFFluid ); + } + errMsg("LbmSolverInterface::readBoundaryFlagInt","Invalid value '"<readMat4Gfx("domain_trafo" , (*mpSimTrafo), "ntlBlenderDumper","mpSimTrafo", false, mpSimTrafo ); + + LbmVec sizeVec(mSizex,mSizey,mSizez); + sizeVec = vec2L( mpSifAttrs->readVec3d("size", vec2P(sizeVec), "LbmSolverInterface", "sizeVec", false) ); + mSizex = (int)sizeVec[0]; + mSizey = (int)sizeVec[1]; + mSizez = (int)sizeVec[2]; + // param needs size in any case + // test solvers might not have mpPara, though + if(mpParam) mpParam->setSize(mSizex, mSizey, mSizez ); + + mInitDensityGradient = mpSifAttrs->readBool("initdensitygradient", mInitDensityGradient,"LbmSolverInterface", "mInitDensityGradient", false); + mIsoValue = mpSifAttrs->readFloat("isovalue", mIsoValue, "LbmOptSolver","mIsoValue", false ); + + mDebugVelScale = mpSifAttrs->readFloat("debugvelscale", mDebugVelScale,"LbmSolverInterface", "mDebugVelScale", false); + mNodeInfoString = mpSifAttrs->readString("nodeinfo", mNodeInfoString, "SimulationLbm","mNodeInfoString", false ); + + mDumpVelocities = mpSifAttrs->readBool("dump_velocities", mDumpVelocities, "SimulationLbm","mDumpVelocities", false ); + if(getenv("ELBEEM_DUMPVELOCITIES")) { + int get = atoi(getenv("ELBEEM_DUMPVELOCITIES")); + if((get==0)||(get==1)) { + mDumpVelocities = get; + debMsgStd("LbmSolverInterface::parseAttrList",DM_NOTIFY,"Using envvar ELBEEM_DUMPVELOCITIES to set mDumpVelocities to "<readFloat("farfieldsize", mFarFieldSize,"LbmSolverInterface", "mFarFieldSize", false); + // old compat + float sizeScale = mpSifAttrs->readFloat("test_scale", 0.,"LbmTestdata", "mSizeScale", false); + if((mFarFieldSize<=0.)&&(sizeScale>0.)) { mFarFieldSize=sizeScale; errMsg("LbmTestdata","Warning - using mSizeScale..."); } + + mPartDropMassSub = mpSifAttrs->readFloat("part_dropmass", mPartDropMassSub,"LbmSolverInterface", "mPartDropMassSub", false); + + mCppfStage = mpSifAttrs->readInt("cppfstage", mCppfStage,"LbmSolverInterface", "mCppfStage", false); + mPartGenProb = mpSifAttrs->readFloat("partgenprob", mPartGenProb,"LbmFsgrSolver", "mPartGenProb", false); + mPartUsePhysModel = mpSifAttrs->readBool("partusephysmodel", mPartUsePhysModel,"LbmFsgrSolver", "mPartUsePhysModel", false); + mIsoSubdivs = mpSifAttrs->readInt("isosubdivs", mIsoSubdivs,"LbmFsgrSolver", "mIsoSubdivs", false); +} + + +/*******************************************************************************/ +/*! geometry initialization */ +/*******************************************************************************/ + +/*****************************************************************************/ +/*! init tree for certain geometry init */ +void LbmSolverInterface::initGeoTree() { + if(mpGlob == NULL) { errFatal("LbmSolverInterface::initGeoTree","Requires globals!",SIMWORLD_INITERROR); return; } + ntlScene *scene = mpGlob->getSimScene(); + mpGiObjects = scene->getObjects(); + mGiObjInside.resize( mpGiObjects->size() ); + mGiObjDistance.resize( mpGiObjects->size() ); + mGiObjSecondDist.resize( mpGiObjects->size() ); + for(size_t i=0; isize(); i++) { + if((*mpGiObjects)[i]->getGeoInitIntersect()) mAccurateGeoinit=true; + //debMsgStd("LbmSolverInterface::initGeoTree",DM_MSG,"id:"<getName() <<" gid:"<<(*mpGiObjects)[i]->getGeoInitId(), 9 ); + } + debMsgStd("LbmSolverInterface::initGeoTree",DM_MSG,"Accurate geo init: "<size() ,10); + + if(mpGiTree != NULL) delete mpGiTree; + char treeFlag = (1<<(this->mLbmInitId+4)); + mpGiTree = new ntlTree( +# if FSGR_STRICT_DEBUG!=1 + 15, 8, // TREEwarning - fixed values for depth & maxtriangles here... +# else // FSGR_STRICT_DEBUG==1 + 10, 20, // reduced/slower debugging values +# endif // FSGR_STRICT_DEBUG==1 + scene, treeFlag ); +} + +/*****************************************************************************/ +/*! destroy tree etc. when geometry init done */ +void LbmSolverInterface::freeGeoTree() { + if(mpGiTree != NULL) { + delete mpGiTree; + mpGiTree = NULL; + } +} + + +int globGeoInitDebug = 0; +int globGICPIProblems = 0; +/*****************************************************************************/ +/*! check for a certain flag type at position org */ +bool LbmSolverInterface::geoInitCheckPointInside(ntlVec3Gfx org, int flags, int &OId, gfxReal &distance, int shootDir) { + // shift ve ctors to avoid rounding errors + org += ntlVec3Gfx(0.0001); + OId = -1; + + // select shooting direction + ntlVec3Gfx dir = ntlVec3Gfx(1., 0., 0.); + if(shootDir==1) dir = ntlVec3Gfx(0., 1., 0.); + else if(shootDir==2) dir = ntlVec3Gfx(0., 0., 1.); + else if(shootDir==-2) dir = ntlVec3Gfx(0., 0., -1.); + else if(shootDir==-1) dir = ntlVec3Gfx(0., -1., 0.); + + ntlRay ray(org, dir, 0, 1.0, mpGlob); + bool done = false; + bool inside = false; + + vector giObjFirstHistSide; + giObjFirstHistSide.resize( mpGiObjects->size() ); + for(size_t i=0; iintersectX(ray,distance,normal, triIns, flags, true); + else mpGiTree->intersect(ray,distance,normal, triIns, flags, true); + if(triIns) { + ntlVec3Gfx norg = ray.getOrigin() + ray.getDirection()*distance; + LbmFloat orientation = dot(normal, dir); + OId = triIns->getObjectId(); + if(orientation<=0.0) { + // outside hit + normal *= -1.0; + mGiObjInside[OId]++; + if(giObjFirstHistSide[OId]==0) giObjFirstHistSide[OId] = 1; + if(globGeoInitDebug) errMsg("IIO"," oid:"<0) { + bool mess = false; + if((mGiObjInside[i]%2)==1) { + if(giObjFirstHistSide[i] != -1) mess=true; + } else { + if(giObjFirstHistSide[i] != 1) mess=true; + } + if(mess) { + //errMsg("IIIproblem","At "<0.0)) { + if( (distance<0.0) || // first intersection -> good + ((distance>0.0)&&(distance>mGiObjDistance[i])) // more than one intersection -> use closest one + ) { + distance = mGiObjDistance[i]; + OId = i; + inside = true; + } + } + } + if(!inside) { + distance = firstHit; + OId = firstOId; + } + if(globGeoInitDebug) errMsg("CHIII","i"<intersectX(ray,distance,normal, triIns, flags, true); + else mpGiTree->intersect(ray,distance,normal, triIns, flags, true); + if(triIns) { + // check outside intersect + LbmFloat orientation = dot(normal, dir); + if(orientation<=0.0) return false; + + OId = triIns->getObjectId(); + return true; + } + return false; + } +} +bool LbmSolverInterface::geoInitCheckPointInside(ntlVec3Gfx org, ntlVec3Gfx dir, int flags, int &OId, gfxReal &distance, const gfxReal halfCellsize, bool &thinHit, bool recurse) { + // shift ve ctors to avoid rounding errors + org += ntlVec3Gfx(0.0001); //? + OId = -1; + ntlRay ray(org, dir, 0, 1.0, mpGlob); + //int insCnt = 0; + bool done = false; + bool inside = false; + for(size_t i=0; iintersect(ray,distance,normal, triIns, flags, true); + if(triIns) { + ntlVec3Gfx norg = ray.getOrigin() + ray.getDirection()*distance; + LbmFloat orientation = dot(normal, dir); + OId = triIns->getObjectId(); + if(orientation<=0.0) { + // outside hit + normal *= -1.0; + //mGiObjDistance[OId] = -1.0; + //errMsg("IIO"," oid:"<0.0)) { + if( (distance<0.0) || // first intersection -> good + ((distance>0.0)&&(distance>mGiObjDistance[i])) // more than one intersection -> use closest one + ) { + distance = mGiObjDistance[i]; + OId = i; + inside = true; + } + } + } + // now check for thin hits + if(!inside) { + distance = -1.0; + for(size_t i=0; i=2)&&(mGiObjDistance[i]>0.0)&&(mGiObjSecondDist[i]>0.0)&& + (mGiObjDistance[i]<1.0*halfCellsize)&&(mGiObjSecondDist[i]<2.0*halfCellsize) ) { + if( (distance<0.0) || // first intersection -> good + ((distance>0.0)&&(distance>mGiObjDistance[i])) // more than one intersection -> use closest one + ) { + distance = mGiObjDistance[i]; + OId = i; + inside = true; + thinHit = true; + } + } + } + } + if(!inside) { + // check for hit in this cell, opposite to current dir (only recurse once) + if(recurse) { + gfxReal r_distance; + int r_OId; + bool ret = geoInitCheckPointInside(org, dir*-1.0, flags, r_OId, r_distance, halfCellsize, thinHit, false); + if((ret)&&(thinHit)) { + OId = r_OId; + distance = 0.0; + return true; + } + } + } + // really no hit... + if(!inside) { + distance = firstHit; + OId = firstOId; + /*if((mGiObjDistance[OId]>0.0)&&(mGiObjSecondDist[OId]>0.0)) { + const gfxReal thisdist = mGiObjSecondDist[OId]-mGiObjDistance[OId]; + // dont walk over this cell... + if(thisdistintersect(ray,distance,normal, triIns, flags, true); + if(triIns) { + // check outside intersect + LbmFloat orientation = dot(normal, dir); + if(orientation<=0.0) return false; + + OId = triIns->getObjectId(); + return true; + } + return false; + } +} + + +/*****************************************************************************/ +ntlVec3Gfx LbmSolverInterface::getGeoMaxMovementVelocity(LbmFloat simtime, LbmFloat stepsize) { + ntlVec3Gfx max(0.0); + if(mpGlob == NULL) return max; + // mpGiObjects has to be inited here... + + for(int i=0; i< (int)mpGiObjects->size(); i++) { + //errMsg("LbmSolverInterface::getGeoMaxMovementVelocity","i="<getName() ); // DEBUG + if( (*mpGiObjects)[i]->getGeoInitType() & (FGI_FLUID|FGI_MBNDINFLOW) ){ + //ntlVec3Gfx objMaxVel = obj->calculateMaxVel(sourceTime,targetTime); + ntlVec3Gfx orgvel = (*mpGiObjects)[i]->calculateMaxVel( simtime, simtime+stepsize ); + if( normNoSqrt(orgvel) > normNoSqrt(max) ) { max = orgvel; } + //errMsg("MVT","i"<getInitialVelocity(simtime)<<" o"<getInitialVelocity(simtime); + if( normNoSqrt(inivel) > normNoSqrt(max) ) { max = inivel; } + } + } + errMsg("LbmSolverInterface::getGeoMaxMovementVelocity", "max="<< max ); // DEBUG + return max; +} + + + + +/*******************************************************************************/ +/*! cell iteration functions */ +/*******************************************************************************/ + + + + +/*****************************************************************************/ +//! add cell to mMarkedCells list +void +LbmSolverInterface::addCellToMarkedList( CellIdentifierInterface *cid ) { + for(size_t i=0; iequal(cid) ) return; + //mMarkedCells[i]->setEnd(false); + } + mMarkedCells.push_back( cid ); + //cid->setEnd(true); +} + +/*****************************************************************************/ +//! marked cell iteration methods +CellIdentifierInterface* +LbmSolverInterface::markedGetFirstCell( ) { + if(mMarkedCells.size() > 0){ return mMarkedCells[0]; } + return NULL; +} + +CellIdentifierInterface* +LbmSolverInterface::markedAdvanceCell() { + mMarkedCellIndex++; + if(mMarkedCellIndex>=(int)mMarkedCells.size()) return NULL; + return mMarkedCells[mMarkedCellIndex]; +} + +void LbmSolverInterface::markedClearList() { + // FIXME free cids? + mMarkedCells.clear(); +} + +/*******************************************************************************/ +/*! string helper functions */ +/*******************************************************************************/ + + + +// 32k +string convertSingleFlag2String(CellFlagType cflag) { + CellFlagType flag = cflag; + if(flag == CFUnused ) return string("cCFUnused"); + if(flag == CFEmpty ) return string("cCFEmpty"); + if(flag == CFBnd ) return string("cCFBnd"); + if(flag == CFBndNoslip ) return string("cCFBndNoSlip"); + if(flag == CFBndFreeslip ) return string("cCFBndFreeSlip"); + if(flag == CFBndPartslip ) return string("cCFBndPartSlip"); + if(flag == CFNoInterpolSrc ) return string("cCFNoInterpolSrc"); + if(flag == CFFluid ) return string("cCFFluid"); + if(flag == CFInter ) return string("cCFInter"); + if(flag == CFNoNbFluid ) return string("cCFNoNbFluid"); + if(flag == CFNoNbEmpty ) return string("cCFNoNbEmpty"); + if(flag == CFNoDelete ) return string("cCFNoDelete"); + if(flag == CFNoBndFluid ) return string("cCFNoBndFluid"); + if(flag == CFGrNorm ) return string("cCFGrNorm"); + if(flag == CFGrFromFine ) return string("cCFGrFromFine"); + if(flag == CFGrFromCoarse ) return string("cCFGrFromCoarse"); + if(flag == CFGrCoarseInited ) return string("cCFGrCoarseInited"); + if(flag == CFMbndInflow ) return string("cCFMbndInflow"); + if(flag == CFMbndOutflow ) return string("cCFMbndOutflow"); + if(flag == CFInvalid ) return string("cfINVALID"); + + std::ostringstream mult; + int val = 0; + if(flag != 0) { + while(! (flag&1) ) { + flag = flag>>1; + val++; + } + } else { + val = -1; + } + if(val>=24) { + mult << "cfOID_" << (flag>>24) <<"_TYPE"; + } else { + mult << "cfUNKNOWN_" << val <<"_TYPE"; + } + return mult.str(); +} + +//! helper function to convert flag to string (for debuggin) +string convertCellFlagType2String( CellFlagType cflag ) { + int flag = cflag; + + const int jmax = sizeof(CellFlagType)*8; + bool somefound = false; + std::ostringstream mult; + mult << "["; + for(int j=0; j +#include "../gui/guifuncs.h" +#endif + +#include +#include "utilities.h" +#include "ntl_bsptree.h" +#include "ntl_geometryobject.h" +#include "parametrizer.h" +#include "attributes.h" +#include "isosurface.h" +class ParticleTracer; +class ParticleObject; + +// use which fp-precision for LBM? 1=float, 2=double +#ifdef PRECISION_LBM_SINGLE +#define LBM_PRECISION 1 +#else +#ifdef PRECISION_LBM_DOUBLE +#define LBM_PRECISION 2 +#else +// default to floats +#define LBM_PRECISION 1 +#endif +#endif + +#if LBM_PRECISION==1 +/* low precision for LBM solver */ +typedef float LbmFloat; +typedef ntlVec3f LbmVec; +#define LBM_EPSILON (1e-5) +#else +/* standard precision for LBM solver */ +typedef double LbmFloat; +typedef ntlVec3d LbmVec; +#define LBM_EPSILON (1e-10) +#endif + +// long integer, needed e.g. for memory calculations +#ifndef USE_MSVC6FIXES +#define LONGINT long long int +#else +#define LONGINT _int64 +#endif + + +// default to 3dim +#ifndef LBMDIM +#define LBMDIM 3 +#endif // LBMDIM + +#if LBMDIM==2 +#define LBM_DFNUM 9 +#else +#define LBM_DFNUM 19 +#endif + +// conversions (lbm and parametrizer) +template inline LbmVec vec2L(T v) { return LbmVec(v[0],v[1],v[2]); } +template inline ParamVec vec2P(T v) { return ParamVec(v[0],v[1],v[2]); } + +template class ntlMatrix4x4; + + +// bubble id type +typedef int BubbleId; + +// basic cell type distinctions +#define CFUnused (1<< 0) +#define CFEmpty (1<< 1) +#define CFBnd (1<< 2) +#define CFMbndInflow (1<< 3) +#define CFMbndOutflow (1<< 4) +#define CFFluid (1<< 5) +#define CFInter (1<< 6) +// additional for fluid (needed separately for adaptive grids) +#define CFNoBndFluid (1<< 7) +#define CFNoDelete (1<< 8) + +// additional bnd add flags +#define CFBndNoslip (1<< 9) +#define CFBndFreeslip (1<<10) +#define CFBndPartslip (1<<11) +#define CFBndMoving (1<<12) + +// additional for fluid/interface +// force symmetry for flag reinit +#define CFNoInterpolSrc (1<<13) +#define CFNoNbFluid (1<<14) +#define CFNoNbEmpty (1<<15) + +// cell treated normally on coarser grids +#define CFGrNorm (1<<16) +#define CFGrCoarseInited (1<<17) + +// (the following values shouldnt overlap to ensure +// proper coarsening) +// border cells to be interpolated from finer grid +#define CFGrFromFine (1<<18) +// 32k aux border marker +#define CFGrToFine (1<<19) +// also needed on finest level +#define CFGrFromCoarse (1<<20) +// additional refinement tags (coarse grids only?) +// */ + +// above 24 is used to encode in/outflow object type +#define CFPersistMask (0xFF000000 | CFMbndInflow | CFMbndOutflow) +#define CFNoPersistMask (~CFPersistMask) + + +// nk +#define CFInvalid (CellFlagType)(1<<31) + +// use 32bit flag types +//#ifdef __x86_64__ + //typedef int cfINT32; +//#else + //typedef long cfINT32; +//#endif // defined (_IA64) +//#define CellFlagType cfINT32 +#define CellFlagType int +#define CellFlagTypeSize 4 + + +// aux. field indices (same for 2d) +#define dFfrac 19 +#define dMass 20 +#define dFlux 21 +// max. no. of cell values for 3d +#define dTotalNum 22 + + +/*****************************************************************************/ +/*! a single lbm cell */ +/* the template is only needed for + * dimension dependend constants e.g. + * number of df's in model */ +class LbmCellContents { + public: + LbmFloat df[ 27 ]; // be on the safe side here... + LbmFloat rho; + LbmVec vel; + LbmFloat mass; + CellFlagType flag; + BubbleId bubble; + LbmFloat ffrac; +}; + +/* struct for the coordinates of a cell in the grid */ +typedef struct { + int x,y,z; + int flag; // special handling? +} LbmPoint; + +/* struct for the coordinates of a cell in the grid */ +typedef struct { + char active; // bubble in use, oder may be overwritten? + LbmFloat volume; // volume of this bubble (0 vor atmosphere) + LbmFloat mass; // "mass" of bubble + int i,j,k; // index of a cell in the bubble +} LbmBubble; + + + + +//! choose which data to display +#define FLUIDDISPINVALID 0 +#define FLUIDDISPNothing 1 +#define FLUIDDISPCelltypes 2 +#define FLUIDDISPVelocities 3 +#define FLUIDDISPCellfills 4 +#define FLUIDDISPDensity 5 +#define FLUIDDISPGrid 6 +#define FLUIDDISPSurface 7 + + + +/*****************************************************************************/ +//! cell identifier interface +class CellIdentifierInterface { + public: + //! reset constructor + CellIdentifierInterface():mEnd(false) { }; + //! virtual destructor + virtual ~CellIdentifierInterface() {}; + + //! return node as string (with some basic info) + virtual string getAsString() = 0; + + //! compare cids + virtual bool equal(CellIdentifierInterface* other) = 0; + + //! set/get end flag for grid traversal (not needed for marked cells) + inline void setEnd(bool set){ mEnd = set; } + inline bool getEnd( ) { return mEnd; } + + //! has the grid been traversed? + bool mEnd; + +}; + + + +/*****************************************************************************/ +/*! class defining abstract function interface */ +/* has to provide iterating functionality */ +class LbmSolverInterface +{ + public: + //! Constructor + LbmSolverInterface(); + //! Destructor + virtual ~LbmSolverInterface(); + //! id string of solver + virtual string getIdString() = 0; + + // multi step solver init + /*! finish the init with config file values (allocate arrays...) */ + virtual bool initializeSolverMemory() =0; + /*! init solver arrays */ + virtual bool initializeSolverGrids() =0; + /*! prepare actual simulation start, setup viz etc */ + virtual bool initializeSolverPostinit() =0; + + /*! notify object that dump is in progress (e.g. for field dump) */ + virtual void notifySolverOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename) = 0; + + /*! parse a boundary flag string */ + CellFlagType readBoundaryFlagInt(string name, int defaultValue, string source,string target, bool needed); + /*! parse standard attributes */ + void parseStdAttrList(); + /*! initilize variables fom attribute list (should at least call std parse) */ + virtual void parseAttrList() = 0; + + virtual void step() = 0; + virtual void prepareVisualization() { /* by default off */ }; + + /*! particle handling */ + virtual int initParticles() = 0; + virtual void advanceParticles() = 0; + /*! get surface object (NULL if no surface) */ + IsoSurface* getSurfaceGeoObj() { return mpIso; } + + /*! debug object display */ + virtual vector getDebugObjects() { vector empty(0); return empty; } + +#if LBM_USE_GUI==1 + /*! show simulation info */ + virtual void debugDisplay(int) = 0; +#endif + + /*! init tree for certain geometry init */ + void initGeoTree(); + /*! destroy tree etc. when geometry init done */ + void freeGeoTree(); + /*! check for a certain flag type at position org (needed for e.g. quadtree refinement) */ + bool geoInitCheckPointInside(ntlVec3Gfx org, int flags, int &OId, gfxReal &distance,int shootDir=0); + bool geoInitCheckPointInside(ntlVec3Gfx org, ntlVec3Gfx dir, int flags, int &OId, gfxReal &distance, + const gfxReal halfCellsize, bool &thinHit, bool recurse); + /*! set render globals, for scene/tree access */ + void setRenderGlobals(ntlRenderGlobals *glob) { mpGlob = glob; }; + /*! get max. velocity of all objects to initialize as fluid regions, and of all moving objects */ + ntlVec3Gfx getGeoMaxMovementVelocity(LbmFloat simtime, LbmFloat stepsize); + + /* rt interface functions */ + unsigned int getIsoVertexCount() { return mpIso->getIsoVertexCount(); } + unsigned int getIsoIndexCount() { return mpIso->getIsoIndexCount(); } + char* getIsoVertexArray() { return mpIso->getIsoVertexArray(); } + unsigned int *getIsoIndexArray() { return mpIso->getIsoIndexArray(); } + void triangulateSurface() { mpIso->triangulate(); } + + /* access functions */ + + /*! return grid sizes */ + int getSizeX( void ) { return mSizex; } + int getSizeY( void ) { return mSizey; } + int getSizeZ( void ) { return mSizez; } + /*! return grid sizes */ + void setSizeX( int ns ) { mSizex = ns; } + void setSizeY( int ns ) { mSizey = ns; } + void setSizeZ( int ns ) { mSizez = ns; } + /*! access fluid only simulation flag */ + void setAllfluid(bool set) { mAllfluid=set; } + bool getAllfluid() { return mAllfluid; } + + /*! set attr list pointer */ + void setAttrList(AttributeList *set) { mpSifAttrs = set; } + /*! Returns the attribute list pointer */ + inline AttributeList *getAttributeList() { return mpSifAttrs; } + /*! set sws attr list pointer */ + void setSwsAttrList(AttributeList *set) { mpSifSwsAttrs = set; } + inline AttributeList *getSwsAttributeList() { return mpSifSwsAttrs; } + + /*! set parametrizer pointer */ + inline void setParametrizer(Parametrizer *set) { mpParam = set; } + /*! get parametrizer pointer */ + inline Parametrizer *getParametrizer() { return mpParam; } + /*! get/set particle pointer */ + inline void setParticleTracer(ParticleTracer *set) { mpParticles = set; } + inline ParticleTracer *getParticleTracer() { return mpParticles; } + + /*! set density gradient init from e.g. init test cases */ + inline void setInitDensityGradient(bool set) { mInitDensityGradient = set; } + + /*! access geometry start vector */ + inline void setGeoStart(ntlVec3Gfx set) { mvGeoStart = set; } + inline ntlVec3Gfx getGeoStart() const { return mvGeoStart; } + + /*! access geometry end vector */ + inline void setGeoEnd(ntlVec3Gfx set) { mvGeoEnd = set; } + inline ntlVec3Gfx getGeoEnd() const { return mvGeoEnd; } + + /*! access geo init vars */ + inline void setLbmInitId(int set) { mLbmInitId = set; } + inline int getLbmInitId() const { return mLbmInitId; } + + /*! init domain transformation matrix from float array */ + void initDomainTrafo(float *mat); + /*! get domain transformation matrix to have object centered fluid vertices */ + inline ntlMatrix4x4 *getDomainTrafo() { return mpSimTrafo; } + + /*! access name string */ + inline void setName(string set) { mName = set; } + inline string getName() const { return mName; } + + /*! access string for node info debugging output */ + inline string getNodeInfoString() const { return mNodeInfoString; } + + /*! get panic flag */ + inline bool getPanic() { return mPanic; } + + //! set silent mode? + inline void setSilent(bool set){ mSilent = set; } + + //! set amount of surface/normal smoothing + inline void setSmoothing(float setss,float setns){ mSmoothSurface=setss; mSmoothNormals=setns; } + //! set amount of iso subdivisions + inline void setIsoSubdivs(int s){ mIsoSubdivs=s; } + //! set desired refinement + inline void setPreviewSize(int set){ mOutputSurfacePreview = set; } + //! set desired refinement + inline void setRefinementDesired(int set){ mRefinementDesired = set; } + + //! set/get dump velocities flag + inline void setDumpVelocities(bool set) { mDumpVelocities = set; } + inline bool getDumpVelocities() const { return mDumpVelocities; } + + //! set/get particle generation prob. + inline void setGenerateParticles(LbmFloat set) { mPartGenProb = set; } + inline LbmFloat getGenerateParticles() const { return mPartGenProb; } + + //! set/get dump velocities flag + inline void setDomainBound(string set) { mDomainBound = set; } + inline string getDomainBound() const { return mDomainBound; } + //! set/get dump velocities flag + inline void setDomainPartSlip(LbmFloat set) { mDomainPartSlipValue = set; } + inline LbmFloat getDomainPartSlip() const { return mDomainPartSlipValue; } + //! set/get far field size + inline void setFarFieldSize(LbmFloat set) { mFarFieldSize = set; } + inline LbmFloat getFarFieldSize() const { return mFarFieldSize; } + //! set/get cp stage + inline void setCpStage(int set) { mCppfStage = set; } + inline int getCpStage() const { return mCppfStage; } + //! set/get dump modes + inline void setDumpRawText(bool set) { mDumpRawText = set; } + inline bool getDumpRawText() const { return mDumpRawText; } + inline void setDumpRawBinary(bool set) { mDumpRawBinary = set; } + inline bool getDumpRawBinary() const { return mDumpRawBinary; } + inline void setDumpRawBinaryZip(bool set) { mDumpRawBinaryZip = set; } + inline bool getDumpRawBinaryZip() const { return mDumpRawBinaryZip; } + //! set/get debug vel scale + inline void setDebugVelScale(LbmFloat set) { mDebugVelScale = set; } + inline LbmFloat getDebugVelScale() const { return mDebugVelScale; } + + // cell iterator interface + + // cell id type + typedef CellIdentifierInterface* CellIdentifier; + + //! cell iteration methods + virtual CellIdentifierInterface* getFirstCell( ) = 0; + virtual void advanceCell( CellIdentifierInterface* ) = 0; + virtual bool noEndCell( CellIdentifierInterface* ) = 0; + //! clean up iteration, this should be called, when the iteration is not completely finished + virtual void deleteCellIterator( CellIdentifierInterface** ) = 0; + + //! find cell at a given position (returns NULL if not in domain) + virtual CellIdentifierInterface* getCellAt( ntlVec3Gfx pos ) = 0; + + //! return node information + virtual int getCellSet ( CellIdentifierInterface* ) = 0; + virtual ntlVec3Gfx getCellOrigin ( CellIdentifierInterface* ) = 0; + virtual ntlVec3Gfx getCellSize ( CellIdentifierInterface* ) = 0; + virtual int getCellLevel ( CellIdentifierInterface* ) = 0; + virtual LbmFloat getCellDensity ( CellIdentifierInterface*,int ) = 0; + virtual LbmVec getCellVelocity ( CellIdentifierInterface*,int ) = 0; + /*! get equilibrium distribution functions */ + virtual LbmFloat getEquilDf ( int ) = 0; + /*! redundant cell functions */ + virtual LbmFloat getCellDf ( CellIdentifierInterface* ,int set, int dir) = 0; + virtual LbmFloat getCellMass ( CellIdentifierInterface* ,int set) = 0; + virtual LbmFloat getCellFill ( CellIdentifierInterface* ,int set) = 0; + virtual CellFlagType getCellFlag ( CellIdentifierInterface* ,int set) = 0; + + /*! get velocity directly from position */ + virtual ntlVec3Gfx getVelocityAt(float x, float y, float z) = 0; + + // gui/output debugging functions +#if LBM_USE_GUI==1 + virtual void debugDisplayNode(int dispset, CellIdentifier cell ) = 0; + virtual void lbmDebugDisplay(int dispset) = 0; + virtual void lbmMarkedCellDisplay() = 0; +#endif // LBM_USE_GUI==1 + virtual void debugPrintNodeInfo(CellIdentifier cell, int forceSet=-1) = 0; + + // debugging cell marker functions + + //! add cell to mMarkedCells list + void addCellToMarkedList( CellIdentifierInterface *cid ); + //! marked cell iteration methods + CellIdentifierInterface* markedGetFirstCell( ); + CellIdentifierInterface* markedAdvanceCell(); + void markedClearList(); + + + protected: + + /*! abort simulation on error... */ + bool mPanic; + + + /*! Size of the array in x,y,z direction */ + int mSizex, mSizey, mSizez; + /*! only fluid in sim? */ + bool mAllfluid; + + + /*! step counter */ + int mStepCnt; + + /*! mass change from one step to the next, for extreme cases fix globally */ + LbmFloat mFixMass; + + // deprecated param vars + /*! omega for lbm */ + LbmFloat mOmega; + /*! gravity strength in neg. z direction */ + LbmVec mGravity; + /*! Surface tension of the fluid */ + LbmFloat mSurfaceTension; + + + /* boundary inits */ + CellFlagType mBoundaryEast, mBoundaryWest, + mBoundaryNorth, mBoundarySouth, + mBoundaryTop, mBoundaryBottom; + + /*! initialization from config file done? */ + int mInitDone; + + /*! init density gradient? */ + bool mInitDensityGradient; + + /*! pointer to the attribute list, only pointer to obj attrs */ + AttributeList *mpSifAttrs; + AttributeList *mpSifSwsAttrs; + + /*! get parameters from this parametrize in finishInit */ + Parametrizer *mpParam; + //! store particle tracer + ParticleTracer *mpParticles; + + /*! number of particles lost so far */ + int mNumParticlesLost; + /*! number of particles lost so far */ + int mNumInvalidDfs; + /*! no of filled/emptied cells per time step */ + int mNumFilledCells, mNumEmptiedCells; + /*! counter number of used cells for performance */ + int mNumUsedCells; + /*! MLSUPS counter */ + LbmFloat mMLSUPS; + /*! debug - velocity output scaling factor */ + LbmFloat mDebugVelScale; + /*! string for node info debugging output */ + string mNodeInfoString; + + // geo init vars + // TODO deprecate SimulationObject vars + + /*! for display - start and end vectors for geometry */ + ntlVec3Gfx mvGeoStart, mvGeoEnd; + //! domain vertex trafos + ntlMatrix4x4 *mpSimTrafo; + + /*! perform accurate geometry init? */ + bool mAccurateGeoinit; + + /*! name of this lbm object (for debug output) */ + string mName; + + //! Mcubes object for surface reconstruction + IsoSurface *mpIso; + /*! isolevel value for marching cubes surface reconstruction */ + LbmFloat mIsoValue; + + //! debug output? + bool mSilent; + + /*! geometry init id, passed from ntl_geomclass */ + int mLbmInitId; + /*! tree object for geomerty initialization */ + ntlTree *mpGiTree; + /*! object vector for geo init */ + vector *mpGiObjects; + /*! inside which objects? */ + vector mGiObjInside; + /*! inside which objects? */ + vector mGiObjDistance; + vector mGiObjSecondDist; + /*! remember globals */ + ntlRenderGlobals *mpGlob; + + //! use refinement/coarsening? + int mRefinementDesired; + + //! output surface preview? if >0 yes, and use as reduzed size + int mOutputSurfacePreview; + LbmFloat mPreviewFactor; + + /*! enable surface and normals smoothing? */ + float mSmoothSurface; + float mSmoothNormals; + /*! isosurface subdivisions */ + int mIsoSubdivs; + + //! particle generation probability + LbmFloat mPartGenProb; + + //! dump velocities? + bool mDumpVelocities; + + // list for marked cells + vector mMarkedCells; + int mMarkedCellIndex; + + //! domain boundary free/no slip type + string mDomainBound; + //! part slip value for domain + LbmFloat mDomainPartSlipValue; + + // size of far field area + LbmFloat mFarFieldSize; + // amount of drop mass to subtract + LbmFloat mPartDropMassSub; + // use physical drop model for particles? + bool mPartUsePhysModel; + + //! test vars + // strength of applied force + LbmFloat mTForceStrength; + int mCppfStage; + + //! dumping modes + bool mDumpRawText; + bool mDumpRawBinary; + bool mDumpRawBinaryZip; +}; + + +// helper function to create consistent grid resolutions +void initGridSizes(int &mSizex, int &mSizey, int &mSizez, + ntlVec3Gfx &mvGeoStart, ntlVec3Gfx &mvGeoEnd, + int mMaxRefine, bool parallel); +void calculateMemreqEstimate(int resx,int resy,int resz, int refine, + float farfieldsize, double *reqret, string *reqstr); + +//! helper function to convert flag to string (for debuggin) +string convertCellFlagType2String( CellFlagType flag ); +string convertSingleFlag2String(CellFlagType cflag); + +#endif // LBMINTERFACE_H diff --git a/intern/elbeem/intern/solver_main.cpp b/intern/elbeem/intern/solver_main.cpp new file mode 100644 index 00000000000..270e8867b3c --- /dev/null +++ b/intern/elbeem/intern/solver_main.cpp @@ -0,0 +1,1698 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Standard LBM Factory implementation + * + *****************************************************************************/ + +#include /* rand(3) - also in linux */ +#include "solver_class.h" +#include "solver_relax.h" +#include "particletracer.h" +#include "loop_tools.h" + +/*****************************************************************************/ +/*! perform a single LBM step */ +/*****************************************************************************/ + +double globdfcnt; +double globdfavg[19]; +double globdfmax[19]; +double globdfmin[19]; +extern int glob_mpindex,glob_mpnum; +extern bool globOutstrForce; + +// simulation object interface +void LbmFsgrSolver::step() { + stepMain(); +} + +// lbm main step +void messageOutputForce(string from); +void LbmFsgrSolver::stepMain() { + myTime_t timestart = getTime(); + + initLevelOmegas(); + markedClearList(); // DMC clearMarkedCellsList + + // safety check, counter reset + mNumUsedCells = 0; + mNumInterdCells = 0; + mNumInvIfCells = 0; + + //debugOutNnl("LbmFsgrSolver::step : "<mMaxNoCells) mMaxNoCells = mNumUsedCells; + if(mNumUsedCells0)&&(mInitialMass>0.0)) { + LbmFloat mscale = mInitialMass/mCurrentMass; + + mscale = 1.0; + const LbmFloat dchh = 0.001; + if(mCurrentMassmInitialMass) mscale = 1.0-dchh; + + // use mass rescaling? + // with float precision this seems to be nonsense... + const bool MREnable = false; + + const int MSInter = 2; + static int mscount = 0; + if( (MREnable) && ((mLevel[0].lsteps%MSInter)== (MSInter-1)) && ( ABS( (mInitialMass/mCurrentMass)-1.0 ) > 0.01) && ( dsbits & (1<<(mMaxRefine-0)) ) ){ + // example: FORCE RESCALE MASS! ini:1843.5, cur:1817.6, f=1.01425 step:22153 levstep:5539 msc:37 + // mass rescale MASS RESCALE check + errMsg("MDTDD","\n\n"); + errMsg("MDTDD","FORCE RESCALE MASS! " + <<"ini:"<=0 ; lev--) { + //for(int workSet = 0; workSet<=1; workSet++) { + int wss = 0; + int wse = 1; +#if COMPRESSGRIDS==1 + if(lev== mMaxRefine) wss = wse = mLevel[lev].setCurr; +#endif // COMPRESSGRIDS==1 + for(int workSet = wss; workSet<=wse; workSet++) { // COMPRT + + FSGR_FORIJK1(lev) { + if( (RFLAG(lev,i,j,k, workSet) & (CFFluid| CFInter| CFGrFromCoarse| CFGrFromFine| CFGrNorm)) + ) { + + FORDF0 { QCELL(lev, i,j,k,workSet, l) *= mscale; } + QCELL(lev, i,j,k,workSet, dMass) *= mscale; + QCELL(lev, i,j,k,workSet, dFfrac) *= mscale; + + } else { + continue; + } + } + } + mLevel[lev].lmass *= mscale; + } + } + + mCurrentMass *= mscale; + }// if mass scale test */ + else { + // use current mass after full step for initial setting + if((mMaxRefine>0)&&(mInitialMass<=0.0) && (levsteps == (mMaxRefine+1))) { + mInitialMass = mCurrentMass; + debMsgStd("MDTDD",DM_NOTIFY,"Second Initial Mass Init: "<checkDumpTextPositions(mSimulationTime); + mpParticles->checkTrails(mSimulationTime); + } + + // one of the last things to do - adapt timestep + // was in fineAdvance before... + if(mTimeAdap) { + adaptTimestep(); + } // time adaptivity + + +#ifndef WIN32 + // good indicator for instabilities + if( (!finite(mMxvx)) || (!finite(mMxvy)) || (!finite(mMxvz)) ) { CAUSE_PANIC; } + if( (!finite(mCurrentMass)) || (!finite(mCurrentVolume)) ) { CAUSE_PANIC; } +#endif // WIN32 + + // output total step time + myTime_t timeend2 = getTime(); + double mdelta = (lastMass-mCurrentMass); + if(ABS(mdelta)<1e-12) mdelta=0.; + double effMLSUPS = ((double)mNumUsedCells / ((timeend2-timestart)/(double)1000.0) ) / (1000000.0); + if(mInitDone) { + if(effMLSUPS>10000){ effMLSUPS = -1; } + else { mAvgMLSUPS += effMLSUPS; mAvgMLSUPSCnt += 1.0; } // track average mlsups + } + + debMsgStd("LbmFsgrSolver::stepMain", DM_MSG, "mmpid:"<mPanic){ FSGR_FORIJK_BOUNDS(mMaxRefine) { \ + if(RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr)&(CFFluid|CFInter)) { \ + for(int l=0;lsetFluidVolumeHeight(mFVHeight); + } + + // advance time before timestep change + mSimulationTime += mpParam->getTimestep(); + // time adaptivity + mpParam->setSimulationMaxSpeed( sqrt(mMaxVlen / 1.5) ); + //if(mStartSymm) { checkSymmetry("step2"); } // DEBUG + if(!mSilent){ debMsgStd("fineAdvance",DM_NOTIFY," stepped from "<cDfNum; l++) { + LbmFloat df = QCELL(lev, i,j,k,workSet, l); + compRho += df; + compUx += (this->dfDvecX[l]*df); + compUy += (this->dfDvecY[l]*df); + compUz += (this->dfDvecZ[l]*df); + } + LbmVec u(compUx,compUy,compUz); + LbmFloat nu = norm(u); + if(nu>maxUlen) { + maxU = u; + maxUlen = nu; + mi=i; mj=j; mk=k; + } + if(compRho>maxRho) { + maxRho=compRho; + ri=i; rj=j; rk=k; + } + } else { + continue; + } + } + + errMsg("MAXVELCHECK"," at "<mFarfMode>0)) { return; } +# endif // ELBEEM_PLUGIN!=1 + + // main loop region + const bool doReduce = true; + const int gridLoopBound=1; + GRID_REGION_INIT(); +#if PARALLEL==1 +#include "paraloopstart.h" + GRID_REGION_START(); +#else // PARALLEL==1 + GRID_REGION_START(); +#endif // PARALLEL==1 + + // local to main + CellFlagType nbflag[LBM_DFNUM]; + int oldFlag, newFlag, nbored; + LbmFloat m[LBM_DFNUM]; + LbmFloat rho, ux, uy, uz, tmp, usqr; + + // smago vars + LbmFloat lcsmqadd, lcsmeq[LBM_DFNUM], lcsmomega; + + // ifempty cell conversion flags + bool iffilled, ifemptied; + LbmFloat nbfracs[LBM_DFNUM]; // ffracs of neighbors + int recons[LBM_DFNUM]; // reconstruct this DF? + int numRecons; // how many are reconstructed? + + LbmFloat mass=0., change=0., lcsmqo=0.; + rho= ux= uy= uz= usqr= tmp= 0.; + lcsmqadd = lcsmomega = 0.; + FORDF0{ lcsmeq[l] = 0.; } + + // --- + // now stream etc. + // use //template functions for 2D/3D + + GRID_LOOP_START(); + // loop start + // stream from current set to other, then collide and store + //errMsg("l2"," at "<>24; + if(!isValid) { + // make new if cell + const LbmVec vel(mObjectSpeeds[OId]); + // TODO add OPT3D treatment + FORDF0 { RAC(tcel, l) = this->getCollideEq(l, iniRho,vel[0],vel[1],vel[2]); } + RAC(tcel, dMass) = RAC(tcel, dFfrac) = iniRho; + RAC(tcel, dFlux) = FLUX_INIT; + changeFlag(lev, i,j,k, TSET(lev), CFInter); + calcCurrentMass += iniRho; + calcCurrentVolume += 1.0; + calcNumUsedCells++; + mInitialMass += iniRho; + // dont treat cell until next step + continue; + } + } + else // these are exclusive + if(oldFlag & (CFMbndOutflow)) { + int isnotValid = oldFlag & (CFFluid); + if(isnotValid) { + // remove fluid cells, shouldnt be here anyway + LbmFloat fluidRho = m[0]; FORDF1 { fluidRho += m[l]; } + mInitialMass -= fluidRho; + const LbmFloat iniRho = 0.0; + RAC(tcel, dMass) = RAC(tcel, dFfrac) = iniRho; + RAC(tcel, dFlux) = FLUX_INIT; + changeFlag(lev, i,j,k, TSET(lev), CFInter); + + // same as ifemptied for if below + LbmPoint oemptyp; oemptyp.flag = 0; + oemptyp.x = i; oemptyp.y = j; oemptyp.z = k; + LIST_EMPTY(oemptyp); + calcCellsEmptied++; + continue; + } + } + + if(oldFlag & (CFBnd|CFEmpty|CFGrFromCoarse|CFUnused)) { + *pFlagDst = oldFlag; + continue; + } + /*if( oldFlag & CFNoBndFluid ) { // TEST ME FASTER? + OPTIMIZED_STREAMCOLLIDE; PERFORM_USQRMAXCHECK; + RAC(tcel,dFfrac) = 1.0; + *pFlagDst = (CellFlagType)oldFlag; // newFlag; + calcCurrentMass += rho; calcCurrentVolume += 1.0; + calcNumUsedCells++; + continue; + }// TEST ME FASTER? */ + + // only neighbor flags! not own flag + nbored = 0; + +#if OPT3D==0 + FORDF1 { + nbflag[l] = RFLAG_NB(lev, i,j,k,SRCS(lev),l); + nbored |= nbflag[l]; + } +#else + nbflag[dSB] = *(pFlagSrc + (-mLevel[lev].lOffsy+-mLevel[lev].lOffsx)); nbored |= nbflag[dSB]; + nbflag[dWB] = *(pFlagSrc + (-mLevel[lev].lOffsy+-1)); nbored |= nbflag[dWB]; + nbflag[ dB] = *(pFlagSrc + (-mLevel[lev].lOffsy)); nbored |= nbflag[dB]; + nbflag[dEB] = *(pFlagSrc + (-mLevel[lev].lOffsy+ 1)); nbored |= nbflag[dEB]; + nbflag[dNB] = *(pFlagSrc + (-mLevel[lev].lOffsy+ mLevel[lev].lOffsx)); nbored |= nbflag[dNB]; + + nbflag[dSW] = *(pFlagSrc + (-mLevel[lev].lOffsx+-1)); nbored |= nbflag[dSW]; + nbflag[ dS] = *(pFlagSrc + (-mLevel[lev].lOffsx)); nbored |= nbflag[dS]; + nbflag[dSE] = *(pFlagSrc + (-mLevel[lev].lOffsx+ 1)); nbored |= nbflag[dSE]; + + nbflag[ dW] = *(pFlagSrc + (-1)); nbored |= nbflag[dW]; + nbflag[ dE] = *(pFlagSrc + ( 1)); nbored |= nbflag[dE]; + + nbflag[dNW] = *(pFlagSrc + ( mLevel[lev].lOffsx+-1)); nbored |= nbflag[dNW]; + nbflag[ dN] = *(pFlagSrc + ( mLevel[lev].lOffsx)); nbored |= nbflag[dN]; + nbflag[dNE] = *(pFlagSrc + ( mLevel[lev].lOffsx+ 1)); nbored |= nbflag[dNE]; + + nbflag[dST] = *(pFlagSrc + ( mLevel[lev].lOffsy+-mLevel[lev].lOffsx)); nbored |= nbflag[dST]; + nbflag[dWT] = *(pFlagSrc + ( mLevel[lev].lOffsy+-1)); nbored |= nbflag[dWT]; + nbflag[ dT] = *(pFlagSrc + ( mLevel[lev].lOffsy)); nbored |= nbflag[dT]; + nbflag[dET] = *(pFlagSrc + ( mLevel[lev].lOffsy+ 1)); nbored |= nbflag[dET]; + nbflag[dNT] = *(pFlagSrc + ( mLevel[lev].lOffsy+ mLevel[lev].lOffsx)); nbored |= nbflag[dNT]; + // */ +#endif + + // pointer to destination cell + calcNumUsedCells++; + + // FLUID cells + if( oldFlag & CFFluid ) { + // only standard fluid cells (with nothing except fluid as nbs + + if(oldFlag&CFMbndInflow) { + // force velocity for inflow, necessary to have constant direction of flow + // FIXME , test also set interface cells? + const int OId = oldFlag>>24; + //? DEFAULT_STREAM; + //const LbmFloat fluidRho = 1.0; + // for submerged inflows, streaming would have to be performed... + LbmFloat fluidRho = m[0]; FORDF1 { fluidRho += m[l]; } + const LbmVec vel(mObjectSpeeds[OId]); + ux=vel[0], uy=vel[1], uz=vel[2]; + usqr = 1.5 * (ux*ux + uy*uy + uz*uz); + FORDF0 { RAC(tcel, l) = this->getCollideEq(l, fluidRho,ux,uy,uz); } + rho = fluidRho; + //errMsg("INFLOW_DEBUG","std at "<dfInv[(l)] ] + + // update mass + // only do boundaries for fluid cells, and interface cells without + // any fluid neighbors (assume that interface cells _with_ fluid + // neighbors are affected enough by these) + // which Df's have to be reconstructed? + // for fluid cells - just the f_i difference from streaming to empty cells ---- + numRecons = 0; + bool onlyBndnb = ((!(oldFlag&CFNoBndFluid))&&(oldFlag&CFNoNbFluid)&&(nbored&CFBndNoslip)); + //onlyBndnb = false; // DEBUG test off + + FORDF1 { // dfl loop + recons[l] = 0; + nbfracs[l] = 0.0; + // finally, "normal" interface cells ---- + if( nbflag[l]&(CFFluid|CFBnd) ) { // NEWTEST! FIXME check!!!!!!!!!!!!!!!!!! + change = nbdf(l) - MYDF(l); + } + // interface cells - distuingish cells that shouldn't fill/empty + else if( nbflag[l] & CFInter ) { + + LbmFloat mynbfac,nbnbfac; + // NEW TEST t1 + // t2 -> off + if((oldFlag&CFNoBndFluid)&&(nbflag[l]&CFNoBndFluid)) { + mynbfac = QCELL_NB(lev, i,j,k,SRCS(lev),l, dFlux) / QCELL(lev, i,j,k,SRCS(lev), dFlux); + nbnbfac = 1.0/mynbfac; + onlyBndnb = false; + } else { + mynbfac = nbnbfac = 1.0; // switch calc flux off + goto changeDefault; // NEWSURFT + //change = 0.; goto changeDone; // NEWSURFT + } + //mynbfac = nbnbfac = 1.0; // switch calc flux off t3 + + // perform interface case handling + if ((oldFlag|nbflag[l])&(CFNoNbFluid|CFNoNbEmpty)) { + switch (oldFlag&(CFNoNbFluid|CFNoNbEmpty)) { + case 0: + // we are a normal cell so... + switch (nbflag[l]&(CFNoNbFluid|CFNoNbEmpty)) { + case CFNoNbFluid: + // just fill current cell = empty neighbor + change = nbnbfac*nbdf(l) ; goto changeDone; + case CFNoNbEmpty: + // just empty current cell = fill neighbor + change = - mynbfac*MYDF(l) ; goto changeDone; + } + break; + + case CFNoNbFluid: + // we dont have fluid nb's so... + switch (nbflag[l]&(CFNoNbFluid|CFNoNbEmpty)) { + case 0: + case CFNoNbEmpty: + // we have no fluid nb's -> just empty + change = - mynbfac*MYDF(l) ; goto changeDone; + } + break; + + case CFNoNbEmpty: + // we dont have empty nb's so... + switch (nbflag[l]&(CFNoNbFluid|CFNoNbEmpty)) { + case 0: + case CFNoNbFluid: + // we have no empty nb's -> just fill + change = nbnbfac*nbdf(l); goto changeDone; + } + break; + }} // inter-inter exchange + + changeDefault: ; + // just do normal mass exchange... + change = ( nbnbfac*nbdf(l) - mynbfac*MYDF(l) ) ; + changeDone: ; + nbfracs[l] = QCELL_NB(lev, i,j,k, SRCS(lev),l, dFfrac); + if(nbfracs[l]<0.) nbfracs[l] = 0.; // NEWSURFT + change *= (myfrac + nbfracs[l]) * 0.5; + } // the other cell is interface + + // last alternative - reconstruction in this direction + else { + // empty + bnd case + recons[l] = 1; + numRecons++; + change = 0.0; + } + + // modify mass at SRCS + mass += change; + } // l + // normal interface, no if empty/fluid + + // computenormal + LbmFloat surfaceNormal[3]; + computeFluidSurfaceNormal(ccel,pFlagSrc, surfaceNormal); + + if( (ABS(surfaceNormal[0])+ABS(surfaceNormal[1])+ABS(surfaceNormal[2])) > LBM_EPSILON) { + // normal ok and usable... + FORDF1 { + if( (this->dfDvecX[l]*surfaceNormal[0] + this->dfDvecY[l]*surfaceNormal[1] + this->dfDvecZ[l]*surfaceNormal[2]) // dot Dvec,norml + > LBM_EPSILON) { + recons[l] = 2; + numRecons++; + } + } + } + + // calculate macroscopic cell values + LbmFloat oldUx, oldUy, oldUz; + LbmFloat oldRho; // OLD rho = ccel->rho; +# define REFERENCE_PRESSURE 1.0 // always atmosphere... +# if OPT3D==0 + oldRho=RAC(ccel,0); + oldUx = oldUy = oldUz = 0.0; + for(int l=1; lcDfNum; l++) { + oldRho += RAC(ccel,l); + oldUx += (this->dfDvecX[l]*RAC(ccel,l)); + oldUy += (this->dfDvecY[l]*RAC(ccel,l)); + oldUz += (this->dfDvecZ[l]*RAC(ccel,l)); + } + // reconstruct dist funcs from empty cells + FORDF1 { + if(recons[ l ]) { + m[ this->dfInv[l] ] = + this->getCollideEq(l, REFERENCE_PRESSURE, oldUx,oldUy,oldUz) + + this->getCollideEq(this->dfInv[l], REFERENCE_PRESSURE, oldUx,oldUy,oldUz) + - MYDF( l ); + } + } + ux=oldUx, uy=oldUy, uz=oldUz; // no local vars, only for usqr + usqr = 1.5 * (ux*ux + uy*uy + uz*uz); // needed later on +# else // OPT3D==0 + oldRho = + RAC(ccel,dC) + RAC(ccel,dN ) + + RAC(ccel,dS ) + RAC(ccel,dE ) + + RAC(ccel,dW ) + RAC(ccel,dT ) + + RAC(ccel,dB ) + RAC(ccel,dNE) + + RAC(ccel,dNW) + RAC(ccel,dSE) + + RAC(ccel,dSW) + RAC(ccel,dNT) + + RAC(ccel,dNB) + RAC(ccel,dST) + + RAC(ccel,dSB) + RAC(ccel,dET) + + RAC(ccel,dEB) + RAC(ccel,dWT) + + RAC(ccel,dWB); + + oldUx = + RAC(ccel,dE) - RAC(ccel,dW) + + RAC(ccel,dNE) - RAC(ccel,dNW) + + RAC(ccel,dSE) - RAC(ccel,dSW) + + RAC(ccel,dET) + RAC(ccel,dEB) + - RAC(ccel,dWT) - RAC(ccel,dWB); + + oldUy = + RAC(ccel,dN) - RAC(ccel,dS) + + RAC(ccel,dNE) + RAC(ccel,dNW) + - RAC(ccel,dSE) - RAC(ccel,dSW) + + RAC(ccel,dNT) + RAC(ccel,dNB) + - RAC(ccel,dST) - RAC(ccel,dSB); + + oldUz = + RAC(ccel,dT) - RAC(ccel,dB) + + RAC(ccel,dNT) - RAC(ccel,dNB) + + RAC(ccel,dST) - RAC(ccel,dSB) + + RAC(ccel,dET) - RAC(ccel,dEB) + + RAC(ccel,dWT) - RAC(ccel,dWB); + + // now reconstruction + ux=oldUx, uy=oldUy, uz=oldUz; // no local vars, only for usqr + rho = REFERENCE_PRESSURE; + usqr = 1.5 * (ux*ux + uy*uy + uz*uz); // needed later on + if(recons[dN ]) { m[dS ] = EQN + EQS - MYDF(dN ); } + if(recons[dS ]) { m[dN ] = EQS + EQN - MYDF(dS ); } + if(recons[dE ]) { m[dW ] = EQE + EQW - MYDF(dE ); } + if(recons[dW ]) { m[dE ] = EQW + EQE - MYDF(dW ); } + if(recons[dT ]) { m[dB ] = EQT + EQB - MYDF(dT ); } + if(recons[dB ]) { m[dT ] = EQB + EQT - MYDF(dB ); } + if(recons[dNE]) { m[dSW] = EQNE + EQSW - MYDF(dNE); } + if(recons[dNW]) { m[dSE] = EQNW + EQSE - MYDF(dNW); } + if(recons[dSE]) { m[dNW] = EQSE + EQNW - MYDF(dSE); } + if(recons[dSW]) { m[dNE] = EQSW + EQNE - MYDF(dSW); } + if(recons[dNT]) { m[dSB] = EQNT + EQSB - MYDF(dNT); } + if(recons[dNB]) { m[dST] = EQNB + EQST - MYDF(dNB); } + if(recons[dST]) { m[dNB] = EQST + EQNB - MYDF(dST); } + if(recons[dSB]) { m[dNT] = EQSB + EQNT - MYDF(dSB); } + if(recons[dET]) { m[dWB] = EQET + EQWB - MYDF(dET); } + if(recons[dEB]) { m[dWT] = EQEB + EQWT - MYDF(dEB); } + if(recons[dWT]) { m[dEB] = EQWT + EQEB - MYDF(dWT); } + if(recons[dWB]) { m[dET] = EQWB + EQET - MYDF(dWB); } +# endif + + + // inflow bc handling + if(oldFlag & (CFMbndInflow)) { + // fill if cells in inflow region + if(myfrac<0.5) { + mass += 0.25; + mInitialMass += 0.25; + } + const int OId = oldFlag>>24; + const LbmVec vel(mObjectSpeeds[OId]); + ux=vel[0], uy=vel[1], uz=vel[2]; + //? usqr = 1.5 * (ux*ux + uy*uy + uz*uz); + //FORDF0 { RAC(tcel, l) = this->getCollideEq(l, fluidRho,ux,uy,uz); } rho = fluidRho; + rho = REFERENCE_PRESSURE; + FORDF0 { RAC(tcel, l) = this->getCollideEq(l, rho,ux,uy,uz); } + //errMsg("INFLOW_DEBUG","if at "<RWVEL_WINDTHRESH) && (lcsmqomSizez-SLOWDOWNREGION) ) { + LbmFloat nuz = uz; + if(k>mSizez-SLOWDOWNREGION) { + // special case + LbmFloat zfac = (LbmFloat)( k-(mSizez-SLOWDOWNREGION) ); + zfac /= (LbmFloat)(SLOWDOWNREGION); + nuz += (1.0) * zfac; // check max speed? OFF? + //errMsg("TOPT"," at "<0.025) { + const LbmFloat add = this->dfLength[l]*(-ux*this->dfDvecX[l]-uy*this->dfDvecY[l]-nuz*this->dfDvecZ[l])*jdf; + RAC(tcel,l) += add; } + } + //errMsg("TOPDOWNCORR"," jdf:"<0.0095)) { // add + if((prob0.012)) { // add + } else { doAdd = false; }// dont... + } + + + // remove noise + if(usqr<0.0001) doAdd=false; // TODO check!? + + // dont try to subtract from empty cells + // ensure cell has enough mass for new drop + LbmFloat newPartsize = 1.0; + if(mPartUsePhysModel) { + // 1-10 + newPartsize += 9.0* (rand()/(RAND_MAX+1.0)); + } else { + // 1-5, overall size has to be less than + // .62 (ca. 0.5) to make drops significantly smaller + // than a full cell! + newPartsize += 4.0* (rand()/(RAND_MAX+1.0)); + } + LbmFloat dropmass = ParticleObject::getMass(mPartDropMassSub*newPartsize); //PARTMASS(mPartDropMassSub*newPartsize); // mass: 4/3 pi r^3 rho + while(dropmass>mass) { + newPartsize -= 0.2; + dropmass = ParticleObject::getMass(mPartDropMassSub*newPartsize); + } + if(newPartsize<=1.) doAdd=false; + + if( (doAdd) ) { // init new particle + for(int s=0; s<1; s++) { // one part! + const LbmFloat posjitter = 0.05; + const LbmFloat posjitteroffs = posjitter*-0.5; + LbmFloat jpx = posjitteroffs+ posjitter* (rand()/(RAND_MAX+1.0)); + LbmFloat jpy = posjitteroffs+ posjitter* (rand()/(RAND_MAX+1.0)); + LbmFloat jpz = posjitteroffs+ posjitter* (rand()/(RAND_MAX+1.0)); + + const LbmFloat jitterstr = 1.0; + const LbmFloat jitteroffs = jitterstr*-0.5; + LbmFloat jx = jitteroffs+ jitterstr* (rand()/(RAND_MAX+1.0)); + LbmFloat jy = jitteroffs+ jitterstr* (rand()/(RAND_MAX+1.0)); + LbmFloat jz = jitteroffs+ jitterstr* (rand()/(RAND_MAX+1.0)); + + // average normal & velocity + // -> mostly along velocity dir, many into surface + // fluid velocity (not normalized!) + LbmVec flvelVel = LbmVec(ux,uy,uz); + LbmFloat flvelLen = norm(flvelVel); + // surface normal + LbmVec normVel = LbmVec(surfaceNormal[0],surfaceNormal[1],surfaceNormal[2]); + normalize(normVel); + LbmFloat normScale = (0.01+flvelLen); + // jitter vector, 0.2 * flvel + LbmVec jittVel = LbmVec(jx,jy,jz)*(0.05+flvelLen)*0.1; + // weighten velocities + const LbmFloat flvelWeight = 0.9; + LbmVec newpartVel = normVel*normScale*(1.-flvelWeight) + flvelVel*(flvelWeight) + jittVel; + + // offset towards surface (hide popping) + jpx += -normVel[0]*0.4; + jpy += -normVel[1]*0.4; + jpz += -normVel[2]*0.4; + + LbmFloat srci=i+0.5+jpx, srcj=j+0.5+jpy, srck=k+0.5+jpz; + int type=0; + type = PART_DROP; + +# if LBMDIM==2 + newpartVel[2]=0.; srck=0.5; +# endif // LBMDIM==2 + // subtract drop mass + mass -= dropmass; + // init new particle + { + ParticleObject np( ntlVec3Gfx(srci,srcj,srck) ); + np.setVel(newpartVel[0],newpartVel[1],newpartVel[2]); + np.setStatus(PART_IN); + np.setType(type); + //if((s%3)==2) np.setType(PART_FLOAT); + np.setSize(newPartsize); + //errMsg("NEWPART"," at "<= (rho * (1.0+FSGR_MAGICNR)) ) { iffilled = 1; } + // interface cell if empty? + if( (mass) <= (rho * ( -FSGR_MAGICNR)) ) { ifemptied = 1; } + + if(oldFlag & (CFMbndOutflow)) { + mInitialMass -= mass; + mass = myfrac = 0.0; + iffilled = 0; ifemptied = 1; + } + + // looks much nicer... LISTTRICK +# if FSGR_LISTTRICK==1 + //if((oldFlag&CFNoNbEmpty)&&(newFlag&CFNoNbEmpty)) { TEST_IF_CHECK; } + if(newFlag&CFNoBndFluid) { // test NEW TEST + if(!iffilled) { + // remove cells independent from amount of change... + if( (oldFlag & CFNoNbEmpty)&&(newFlag & CFNoNbEmpty)&& + ( (mass>(rho*FSGR_LISTTTHRESHFULL)) || ((nbored&CFInter)==0) )) { + //if((nbored&CFInter)==0){ errMsg("NBORED!CFINTER","filled "< better cell conversions + RAC(tcel,dFfrac) = (mass/rho); + + // init new flux value + float flux = FLUX_INIT; // dxqn on + if(newFlag&CFNoBndFluid) { + //flux = 50.0; // extreme on + for(int nn=1; nncDfNum; nn++) { + if(nbflag[nn] & (CFFluid|CFInter|CFBnd)) { flux += this->dfLength[nn]; } + } + // optical hack - smooth slow moving + // surface regions + if(usqr< sssUsqrLimit) { + for(int nn=1; nncDfNum; nn++) { + if(nbfracs[nn]!=0.0) { + LbmFloat curSmooth = (sssUsqrLimit-usqr)*sssUsqrLimitInv; + if(curSmooth>1.0) curSmooth=1.0; + flux *= (1.0+ smoothStrength*curSmooth * (nbfracs[nn]-myfrac)) ; + } + } } + // NEW TEST */ + } + // flux = FLUX_INIT; // calc flux off + QCELL(lev, i,j,k,TSET(lev), dFlux) = flux; // */ + + // perform mass exchange with streamed values + QCELL(lev, i,j,k,TSET(lev), dMass) = mass; // MASST + // set new flag + *pFlagDst = (CellFlagType)newFlag; + calcCurrentMass += mass; + calcCurrentVolume += RAC(tcel,dFfrac); + + // interface cell handling done... + +#if PARALLEL!=1 + GRID_LOOPREG_END(); +#else // PARALLEL==1 +#include "paraloopend.h" // = GRID_LOOPREG_END(); +#endif // PARALLEL==1 + + // write vars from computations to class + mLevel[lev].lmass = calcCurrentMass; + mLevel[lev].lvolume = calcCurrentVolume; + mNumFilledCells = calcCellsFilled; + mNumEmptiedCells = calcCellsEmptied; + mNumUsedCells = calcNumUsedCells; +} + + + +void +LbmFsgrSolver::preinitGrids() +{ + const int lev = mMaxRefine; + const bool doReduce = false; + const int gridLoopBound=0; + + // preinit both grids + for(int s=0; s<2; s++) { + + GRID_REGION_INIT(); +#if PARALLEL==1 +#include "paraloopstart.h" +#endif // PARALLEL==1 + GRID_REGION_START(); + GRID_LOOP_START(); + for(int l=0; l-LBM_EPSILON) ret = 0.0; + else ret = scal * -1.0; + } + //errMsg("massd", PRINT_IJK<<" nv"<dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; + //if((LBMDIM>2)&&( (ni<=0) || (nj<=0) || (nk<=0) || (ni>=mLevel[workLev].lSizex-1) || (nj>=mLevel[workLev].lSizey-1) || (nk>=mLevel[workLev].lSizez-1) )) { + if( (ni<=0) || (nj<=0) || + (ni>=mLevel[workLev].lSizex-1) || + (nj>=mLevel[workLev].lSizey-1) +# if LBMDIM==3 + || (nk<=0) || (nk>=mLevel[workLev].lSizez-1) +# endif // LBMDIM==1 + ) { + continue; } // new bc, dont treat cells on boundary NEWBC + if( RFLAG(workLev, ni,nj,nk, workSet) & CFEmpty ){ + + // preinit speed, get from average surrounding cells + // interpolate from non-workset to workset, sets are handled in function + + // new and empty interface cell, dont change old flag here! + addToNewInterList(ni,nj,nk); + + LbmFloat avgrho = 0.0; + LbmFloat avgux = 0.0, avguy = 0.0, avguz = 0.0; + interpolateCellValues(workLev,ni,nj,nk,workSet, avgrho,avgux,avguy,avguz); + + // careful with l's... + FORDF0M { + QCELL(workLev,ni,nj,nk, workSet, m) = this->getCollideEq( m,avgrho, avgux, avguy, avguz ); + //QCELL(workLev,ni,nj,nk, workSet, l) = avgnbdf[l]; // CHECK FIXME test? + } + //errMsg("FNEW", PRINT_VEC(ni,nj,nk)<<" mss"< + let fill cells+surrounding interface cells have the higher importance */ + for( vector::iterator iter=mListEmpty.begin(); + iter != mListEmpty.end(); iter++ ) { + int i=iter->x, j=iter->y, k=iter->z; + if((RFLAG(workLev,i,j,k, workSet)&(CFInter|CFNoDelete)) == (CFInter|CFNoDelete)){ errMsg("A"," ARGHARGRAG "); } // DEBUG + if(debugFlagreinit) errMsg("EMPT", PRINT_IJK<<" mss"<dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; + if( RFLAG(workLev,ni,nj,nk, workSet) & CFFluid){ + // init fluid->interface + //RFLAG(workLev,ni,nj,nk, workSet) = (CellFlagType)(CFInter); + changeFlag(workLev,ni,nj,nk, workSet, CFInter); + /* new mass = current density */ + LbmFloat nbrho = QCELL(workLev,ni,nj,nk, workSet, dC); + for(int rl=1; rl< this->cDfNum ; ++rl) { nbrho += QCELL(workLev,ni,nj,nk, workSet, rl); } + QCELL(workLev,ni,nj,nk, workSet, dMass) = nbrho; + QCELL(workLev,ni,nj,nk, workSet, dFfrac) = 1.0; + + // store point + addToNewInterList(ni,nj,nk); + } + if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter){ + // test, also add to list... + addToNewInterList(ni,nj,nk); + } // NEW? + } + + /* for symmetry, set our flag right now */ + changeFlag(workLev,i,j,k, workSet, CFEmpty); + // mark cell not be changed mass... - not necessary, not in list anymore anyway! + } // emptylist + + + + // precompute weights to get rid of order dependancies + vector vWeights; + vWeights.resize( mListFull.size() + mListEmpty.size() ); + int weightIndex = 0; + int nbCount = 0; + LbmFloat nbWeights[LBM_DFNUM]; + LbmFloat nbTotWeights = 0.0; + for( vector::iterator iter=mListFull.begin(); + iter != mListFull.end(); iter++ ) { + int i=iter->x, j=iter->y, k=iter->z; + nbCount = 0; nbTotWeights = 0.0; + FORDF1 { + int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; + if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) { + nbCount++; + if(iter->flag&1) nbWeights[l] = 1.; // NEWSURFT + else nbWeights[l] = getMassdWeight(1,i,j,k,workSet,l); // NEWSURFT + nbTotWeights += nbWeights[l]; + } else { + nbWeights[l] = -100.0; // DEBUG; + } + } + if(nbCount>0) { + //errMsg("FF I", PRINT_IJK<<" "<::iterator iter=mListEmpty.begin(); + iter != mListEmpty.end(); iter++ ) { + int i=iter->x, j=iter->y, k=iter->z; + nbCount = 0; nbTotWeights = 0.0; + FORDF1 { + int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; + if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) { + nbCount++; + if(iter->flag&1) nbWeights[l] = 1.; // NEWSURFT + else nbWeights[l] = getMassdWeight(0,i,j,k,workSet,l); // NEWSURFT + nbTotWeights += nbWeights[l]; + } else { + nbWeights[l] = -100.0; // DEBUG; + } + } + if(nbCount>0) { + //errMsg("EE I", PRINT_IJK<<" "<::iterator iter=mListFull.begin(); + iter != mListFull.end(); iter++ ) { + int i=iter->x, j=iter->y, k=iter->z; + + LbmFloat myrho = QCELL(workLev,i,j,k, workSet, dC); + FORDF1 { myrho += QCELL(workLev,i,j,k, workSet, l); } // QCELL.rho + + LbmFloat massChange = QCELL(workLev,i,j,k, workSet, dMass) - myrho; + if(vWeights[weightIndex].numNbs>0.0) { + const LbmFloat nbTotWeightsp = vWeights[weightIndex].val[0]; + //errMsg("FF I", PRINT_IJK<<" "<dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; + if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) { + LbmFloat change = -1.0; + if(nbTotWeightsp>0.0) { + //change = massChange * ( nbWeights[l]/nbTotWeightsp ); + change = massChange * ( vWeights[weightIndex].val[l]/nbTotWeightsp ); + } else { + change = (LbmFloat)(massChange/vWeights[weightIndex].numNbs); + } + QCELL(workLev,ni,nj,nk, workSet, dMass) += change; + } + } + massChange = 0.0; + } else { + // Problem! no interface neighbors + mFixMass += massChange; + //TTT mNumProblems++; + //errMsg(" FULL PROBLEM ", PRINT_IJK<<" "<::iterator iter=mListEmpty.begin(); + iter != mListEmpty.end(); iter++ ) { + int i=iter->x, j=iter->y, k=iter->z; + + LbmFloat massChange = QCELL(workLev, i,j,k, workSet, dMass); + if(vWeights[weightIndex].numNbs>0.0) { + const LbmFloat nbTotWeightsp = vWeights[weightIndex].val[0]; + //errMsg("EE I", PRINT_IJK<<" "<dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; + if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) { + LbmFloat change = -1.0; + if(nbTotWeightsp>0.0) { + change = massChange * ( vWeights[weightIndex].val[l]/nbTotWeightsp ); + } else { + change = (LbmFloat)(massChange/vWeights[weightIndex].numNbs); + } + QCELL(workLev, ni,nj,nk, workSet, dMass) += change; + } + } + massChange = 0.0; + } else { + // Problem! no interface neighbors + mFixMass += massChange; + //TTT mNumProblems++; + //errMsg(" EMPT PROBLEM ", PRINT_IJK<<" "<::iterator iter=mListEmpty.begin(); + iter != mListEmpty.end(); iter++ ) { + int i=iter->x, j=iter->y, k=iter->z; + changeFlag(workLev,i,j,k, otherSet, CFEmpty); + } + + + // check if some of the new interface cells can be removed again + // never happens !!! not necessary + // calculate ffrac for new IF cells NEW + + // how many are really new interface cells? + int numNewIf = 0; + for( vector::iterator iter=mListNewInter.begin(); + iter != mListNewInter.end(); iter++ ) { + int i=iter->x, j=iter->y, k=iter->z; + if(!(RFLAG(workLev,i,j,k, workSet)&CFInter)) { + continue; + // FIXME remove from list? + } + numNewIf++; + } + + // redistribute mass, reinit flags + if(debugFlagreinit) errMsg("NEWIF", "total:"<::iterator iter=mListNewInter.begin(); + iter != mListNewInter.end(); iter++ ) { + int i=iter->x, j=iter->y, k=iter->z; + if((i<=0) || (j<=0) || + (i>=mLevel[workLev].lSizex-1) || + (j>=mLevel[workLev].lSizey-1) || + ((LBMDIM==3) && ((k<=0) || (k>=mLevel[workLev].lSizez-1) ) ) + ) { + continue; } // new bc, dont treat cells on boundary NEWBC + if(!(RFLAG(workLev,i,j,k, workSet)&CFInter)) { + //errMsg("???"," "<::iterator iter=mListNewInter.begin(); + iter != mListNewInter.end(); iter++ ) { + int i=iter->x, j=iter->y, k=iter->z; + if(!(RFLAG(workLev,i,j,k, workSet)&CFInter)) { continue; } + + initInterfaceVars(workLev, i,j,k, workSet, false); //int level, int i,int j,int k,int workSet, bool initMass) { + //LbmFloat nrho = 0.0; + //FORDF0 { nrho += QCELL(workLev, i,j,k, workSet, l); } + //QCELL(workLev,i,j,k, workSet, dFfrac) = QCELL(workLev,i,j,k, workSet, dMass)/nrho; + //QCELL(workLev,i,j,k, workSet, dFlux) = FLUX_INIT; + } + + if(mListNewInter.size()>0){ + //errMsg("FixMassDisted"," fm:"<mPanic=1; /* *((int*)(0x0)) = 1; crash*/ } +#else // FSGR_STRICT_DEBUG==1 +#define CAUSE_PANIC { this->mPanic=1; } /*set flag*/ +#endif // FSGR_STRICT_DEBUG==1 + +#if LBM_INCLUDE_TESTSOLVERS!=1 + +#define PRECOLLIDE_MODS(rho,ux,uy,uz, grav) \ + ux += (grav)[0]; \ + uy += (grav)[1]; \ + uz += (grav)[2]; + +#define TEST_IF_CHECK + +#else // LBM_INCLUDE_TESTSOLVERS!=1 +// defined in test.h + +#define NEWDIRVELMOTEST 0 +#if NEWDIRVELMOTEST==1 +// off for non testing +#undef PRECOLLIDE_MODS +#define PRECOLLIDE_MODS(rho,ux,uy,uz, grav) \ + ux += (grav)[0]; \ + uy += (grav)[1]; \ + uz += (grav)[2]; \ + { \ + int lev = mMaxRefine, nomb=0; \ + LbmFloat bcnt = 0.,nux=0.,nuy=0.,nuz=0.; \ + for(int l=1; lcDfNum; l++) { \ + if(RFLAG_NB(lev, i,j,k,SRCS(lev),l)&CFBnd) { \ + if(RFLAG_NB(lev, i,j,k,SRCS(lev),l)&CFBndMoving) { \ + nux += QCELL_NB(lev, i,j,k,SRCS(lev),l, dMass); \ + nuy += QCELL_NB(lev, i,j,k,SRCS(lev),l, dFfrac); \ + bcnt += 1.; \ + } else { \ + nomb++; \ + } \ + } \ + } \ + if((bcnt>0.)&&(nomb==0)) { \ + ux = nux/bcnt; \ + uy = nuy/bcnt; \ + uz = nuz/bcnt; \ + } \ + } +#else // NEWDIRVELMOTEST==1 +// off for non testing +#endif // NEWDIRVELMOTEST==1 + +#endif // LBM_INCLUDE_TESTSOLVERS!=1 + + +/****************************************************************************** + * normal relaxation + *****************************************************************************/ + +// standard arrays +#define CSRC_C RAC(ccel , dC ) +#define CSRC_E RAC(ccel + (-1) *(dTotalNum), dE ) +#define CSRC_W RAC(ccel + (+1) *(dTotalNum), dW ) +#define CSRC_N RAC(ccel + (-mLevel[lev].lOffsx) *(dTotalNum), dN ) +#define CSRC_S RAC(ccel + (+mLevel[lev].lOffsx) *(dTotalNum), dS ) +#define CSRC_NE RAC(ccel + (-mLevel[lev].lOffsx-1) *(dTotalNum), dNE) +#define CSRC_NW RAC(ccel + (-mLevel[lev].lOffsx+1) *(dTotalNum), dNW) +#define CSRC_SE RAC(ccel + (+mLevel[lev].lOffsx-1) *(dTotalNum), dSE) +#define CSRC_SW RAC(ccel + (+mLevel[lev].lOffsx+1) *(dTotalNum), dSW) +#define CSRC_T RAC(ccel + (-mLevel[lev].lOffsy) *(dTotalNum), dT ) +#define CSRC_B RAC(ccel + (+mLevel[lev].lOffsy) *(dTotalNum), dB ) +#define CSRC_ET RAC(ccel + (-mLevel[lev].lOffsy-1) *(dTotalNum), dET) +#define CSRC_EB RAC(ccel + (+mLevel[lev].lOffsy-1) *(dTotalNum), dEB) +#define CSRC_WT RAC(ccel + (-mLevel[lev].lOffsy+1) *(dTotalNum), dWT) +#define CSRC_WB RAC(ccel + (+mLevel[lev].lOffsy+1) *(dTotalNum), dWB) +#define CSRC_NT RAC(ccel + (-mLevel[lev].lOffsy-mLevel[lev].lOffsx) *(dTotalNum), dNT) +#define CSRC_NB RAC(ccel + (+mLevel[lev].lOffsy-mLevel[lev].lOffsx) *(dTotalNum), dNB) +#define CSRC_ST RAC(ccel + (-mLevel[lev].lOffsy+mLevel[lev].lOffsx) *(dTotalNum), dST) +#define CSRC_SB RAC(ccel + (+mLevel[lev].lOffsy+mLevel[lev].lOffsx) *(dTotalNum), dSB) + +#define XSRC_C(x) RAC(ccel + (x) *dTotalNum, dC ) +#define XSRC_E(x) RAC(ccel + ((x)-1) *dTotalNum, dE ) +#define XSRC_W(x) RAC(ccel + ((x)+1) *dTotalNum, dW ) +#define XSRC_N(x) RAC(ccel + ((x)-mLevel[lev].lOffsx) *dTotalNum, dN ) +#define XSRC_S(x) RAC(ccel + ((x)+mLevel[lev].lOffsx) *dTotalNum, dS ) +#define XSRC_NE(x) RAC(ccel + ((x)-mLevel[lev].lOffsx-1) *dTotalNum, dNE) +#define XSRC_NW(x) RAC(ccel + ((x)-mLevel[lev].lOffsx+1) *dTotalNum, dNW) +#define XSRC_SE(x) RAC(ccel + ((x)+mLevel[lev].lOffsx-1) *dTotalNum, dSE) +#define XSRC_SW(x) RAC(ccel + ((x)+mLevel[lev].lOffsx+1) *dTotalNum, dSW) +#define XSRC_T(x) RAC(ccel + ((x)-mLevel[lev].lOffsy) *dTotalNum, dT ) +#define XSRC_B(x) RAC(ccel + ((x)+mLevel[lev].lOffsy) *dTotalNum, dB ) +#define XSRC_ET(x) RAC(ccel + ((x)-mLevel[lev].lOffsy-1) *dTotalNum, dET) +#define XSRC_EB(x) RAC(ccel + ((x)+mLevel[lev].lOffsy-1) *dTotalNum, dEB) +#define XSRC_WT(x) RAC(ccel + ((x)-mLevel[lev].lOffsy+1) *dTotalNum, dWT) +#define XSRC_WB(x) RAC(ccel + ((x)+mLevel[lev].lOffsy+1) *dTotalNum, dWB) +#define XSRC_NT(x) RAC(ccel + ((x)-mLevel[lev].lOffsy-mLevel[lev].lOffsx) *dTotalNum, dNT) +#define XSRC_NB(x) RAC(ccel + ((x)+mLevel[lev].lOffsy-mLevel[lev].lOffsx) *dTotalNum, dNB) +#define XSRC_ST(x) RAC(ccel + ((x)-mLevel[lev].lOffsy+mLevel[lev].lOffsx) *dTotalNum, dST) +#define XSRC_SB(x) RAC(ccel + ((x)+mLevel[lev].lOffsy+mLevel[lev].lOffsx) *dTotalNum, dSB) + + + +#define OMEGA(l) mLevel[(l)].omega + +#define EQC ( DFL1*(rho - usqr)) +#define EQN ( DFL2*(rho + uy*(4.5*uy + 3.0) - usqr)) +#define EQS ( DFL2*(rho + uy*(4.5*uy - 3.0) - usqr)) +#define EQE ( DFL2*(rho + ux*(4.5*ux + 3.0) - usqr)) +#define EQW ( DFL2*(rho + ux*(4.5*ux - 3.0) - usqr)) +#define EQT ( DFL2*(rho + uz*(4.5*uz + 3.0) - usqr)) +#define EQB ( DFL2*(rho + uz*(4.5*uz - 3.0) - usqr)) + +#define EQNE ( DFL3*(rho + (+ux+uy)*(4.5*(+ux+uy) + 3.0) - usqr)) +#define EQNW ( DFL3*(rho + (-ux+uy)*(4.5*(-ux+uy) + 3.0) - usqr)) +#define EQSE ( DFL3*(rho + (+ux-uy)*(4.5*(+ux-uy) + 3.0) - usqr)) +#define EQSW ( DFL3*(rho + (-ux-uy)*(4.5*(-ux-uy) + 3.0) - usqr)) +#define EQNT ( DFL3*(rho + (+uy+uz)*(4.5*(+uy+uz) + 3.0) - usqr)) +#define EQNB ( DFL3*(rho + (+uy-uz)*(4.5*(+uy-uz) + 3.0) - usqr)) +#define EQST ( DFL3*(rho + (-uy+uz)*(4.5*(-uy+uz) + 3.0) - usqr)) +#define EQSB ( DFL3*(rho + (-uy-uz)*(4.5*(-uy-uz) + 3.0) - usqr)) +#define EQET ( DFL3*(rho + (+ux+uz)*(4.5*(+ux+uz) + 3.0) - usqr)) +#define EQEB ( DFL3*(rho + (+ux-uz)*(4.5*(+ux-uz) + 3.0) - usqr)) +#define EQWT ( DFL3*(rho + (-ux+uz)*(4.5*(-ux+uz) + 3.0) - usqr)) +#define EQWB ( DFL3*(rho + (-ux-uz)*(4.5*(-ux-uz) + 3.0) - usqr)) + + +// this is a bit ugly, but necessary for the CSRC_ access... +#define MSRC_C m[dC ] +#define MSRC_N m[dN ] +#define MSRC_S m[dS ] +#define MSRC_E m[dE ] +#define MSRC_W m[dW ] +#define MSRC_T m[dT ] +#define MSRC_B m[dB ] +#define MSRC_NE m[dNE] +#define MSRC_NW m[dNW] +#define MSRC_SE m[dSE] +#define MSRC_SW m[dSW] +#define MSRC_NT m[dNT] +#define MSRC_NB m[dNB] +#define MSRC_ST m[dST] +#define MSRC_SB m[dSB] +#define MSRC_ET m[dET] +#define MSRC_EB m[dEB] +#define MSRC_WT m[dWT] +#define MSRC_WB m[dWB] + +// this is a bit ugly, but necessary for the ccel local access... +#define CCEL_C RAC(ccel, dC ) +#define CCEL_N RAC(ccel, dN ) +#define CCEL_S RAC(ccel, dS ) +#define CCEL_E RAC(ccel, dE ) +#define CCEL_W RAC(ccel, dW ) +#define CCEL_T RAC(ccel, dT ) +#define CCEL_B RAC(ccel, dB ) +#define CCEL_NE RAC(ccel, dNE) +#define CCEL_NW RAC(ccel, dNW) +#define CCEL_SE RAC(ccel, dSE) +#define CCEL_SW RAC(ccel, dSW) +#define CCEL_NT RAC(ccel, dNT) +#define CCEL_NB RAC(ccel, dNB) +#define CCEL_ST RAC(ccel, dST) +#define CCEL_SB RAC(ccel, dSB) +#define CCEL_ET RAC(ccel, dET) +#define CCEL_EB RAC(ccel, dEB) +#define CCEL_WT RAC(ccel, dWT) +#define CCEL_WB RAC(ccel, dWB) +// for coarse to fine interpol access +#define CCELG_C(f) (RAC(ccel, dC )*mGaussw[(f)]) +#define CCELG_N(f) (RAC(ccel, dN )*mGaussw[(f)]) +#define CCELG_S(f) (RAC(ccel, dS )*mGaussw[(f)]) +#define CCELG_E(f) (RAC(ccel, dE )*mGaussw[(f)]) +#define CCELG_W(f) (RAC(ccel, dW )*mGaussw[(f)]) +#define CCELG_T(f) (RAC(ccel, dT )*mGaussw[(f)]) +#define CCELG_B(f) (RAC(ccel, dB )*mGaussw[(f)]) +#define CCELG_NE(f) (RAC(ccel, dNE)*mGaussw[(f)]) +#define CCELG_NW(f) (RAC(ccel, dNW)*mGaussw[(f)]) +#define CCELG_SE(f) (RAC(ccel, dSE)*mGaussw[(f)]) +#define CCELG_SW(f) (RAC(ccel, dSW)*mGaussw[(f)]) +#define CCELG_NT(f) (RAC(ccel, dNT)*mGaussw[(f)]) +#define CCELG_NB(f) (RAC(ccel, dNB)*mGaussw[(f)]) +#define CCELG_ST(f) (RAC(ccel, dST)*mGaussw[(f)]) +#define CCELG_SB(f) (RAC(ccel, dSB)*mGaussw[(f)]) +#define CCELG_ET(f) (RAC(ccel, dET)*mGaussw[(f)]) +#define CCELG_EB(f) (RAC(ccel, dEB)*mGaussw[(f)]) +#define CCELG_WT(f) (RAC(ccel, dWT)*mGaussw[(f)]) +#define CCELG_WB(f) (RAC(ccel, dWB)*mGaussw[(f)]) + + +#if PARALLEL==1 +#define CSMOMEGA_STATS(dlev, domega) +#else // PARALLEL==1 +#if FSGR_OMEGA_DEBUG==1 +#define CSMOMEGA_STATS(dlev, domega) \ + mLevel[dlev].avgOmega += domega; mLevel[dlev].avgOmegaCnt+=1.0; +#else // FSGR_OMEGA_DEBUG==1 +#define CSMOMEGA_STATS(dlev, domega) +#endif // FSGR_OMEGA_DEBUG==1 +#endif // PARALLEL==1 + + +// used for main loops and grav init +// source set +#define SRCS(l) mLevel[(l)].setCurr +// target set +#define TSET(l) mLevel[(l)].setOther + +// handle mov. obj +#if FSGR_STRICT_DEBUG==1 + +#define LBMDS_ADDMOV(linv,l) \ + \ + if((nbflag[linv]&CFBndMoving)&&(!(nbflag[l]&CFBnd))){ \ + \ + LbmFloat dte=QCELL_NBINV(lev, i, j, k, SRCS(lev), l,dFlux)-(mSimulationTime+this->mpParam->getTimestep()); \ + if( ABS(dte)< 1e-15 ) { \ + m[l]+=QCELL_NBINV(lev, i, j, k, SRCS(lev), l,l); \ + } else { \ + const int sdx = i+this->dfVecX[linv], sdy = j+this->dfVecY[linv], sdz = k+this->dfVecZ[linv]; \ + \ + errMsg("INVALID_MOV_OBJ_TIME"," at "<dfInv[l] ); \ + } \ + } else { \ + m[l] = QCELL_NBINV(lev, i, j, k, SRCS(lev), l,l); \ + if(RFLAG(lev, i,j,k, mLevel[lev].setCurr)&CFFluid) { \ + if(!(nbf&(CFFluid|CFInter)) ) { \ + int ni=i+this->dfVecX[this->dfInv[l]], nj=j+this->dfVecY[this->dfInv[l]], nk=k+this->dfVecZ[this->dfInv[l]]; \ + errMsg("STREAMCHECK"," Invalid nbflag, streamed DF l"<dfVecX[this->dfInv[l]], j+this->dfVecY[this->dfInv[l]],k+this->dfVecZ[this->dfInv[l]], l); \ + } \ + } \ + + + + +// careful ux,uy,uz need to be inited before! +#define DEFAULT_COLLIDEG(grav) \ + this->collideArrays(lev, i,j,k, m, rho,ux,uy,uz, OMEGA(lev), grav, mLevel[lev].lcsmago, &mDebugOmegaRet, &lcsmqo ); \ + CSMOMEGA_STATS(lev,mDebugOmegaRet); \ + FORDF0 { RAC(tcel,l) = m[l]; } \ + usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \ + COLLCHECK; \ + + + +#define OPTIMIZED_STREAMCOLLIDE \ + m[0] = RAC(ccel,0); \ + FORDF1 { \ + \ + if(RFLAG_NBINV(lev, i,j,k,SRCS(lev),l)&CFBnd) { errMsg("???", "bnd-err-nobndfl"); CAUSE_PANIC; \ + } else { m[l] = QCELL_NBINV(lev, i, j, k, SRCS(lev), l, l); } \ + STREAMCHECK(8, i+this->dfVecX[this->dfInv[l]], j+this->dfVecY[this->dfInv[l]],k+this->dfVecZ[this->dfInv[l]], l); \ + } \ + rho=m[0]; \ + DEFAULT_COLLIDEG(mLevel[lev].gravity) \ + + + +#define OPTIMIZED_STREAMCOLLIDE___UNUSED \ + \ + this->collideArrays(lev, i,j,k, m, rho,ux,uy,uz, OMEGA(lev), mLevel[lev].gravity, mLevel[lev].lcsmago , &mDebugOmegaRet, &lcsmqo ); \ + CSMOMEGA_STATS(lev,mDebugOmegaRet); \ + FORDF0 { RAC(tcel,l) = m[l]; } \ + usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \ + COLLCHECK; \ + + + +#else // 3D, opt OPT3D==true + + +// default stream opt3d add moving bc val +#define DEFAULT_STREAM \ + m[dC] = RAC(ccel,dC); \ + \ + if((!nbored & CFBnd)) { \ + \ + m[dN ] = CSRC_N ; m[dS ] = CSRC_S ; \ + m[dE ] = CSRC_E ; m[dW ] = CSRC_W ; \ + m[dT ] = CSRC_T ; m[dB ] = CSRC_B ; \ + m[dNE] = CSRC_NE; m[dNW] = CSRC_NW; m[dSE] = CSRC_SE; m[dSW] = CSRC_SW; \ + m[dNT] = CSRC_NT; m[dNB] = CSRC_NB; m[dST] = CSRC_ST; m[dSB] = CSRC_SB; \ + m[dET] = CSRC_ET; m[dEB] = CSRC_EB; m[dWT] = CSRC_WT; m[dWB] = CSRC_WB; \ + } else { \ + \ + if(nbflag[dS ]&CFBnd) { m[dN ] = RAC(ccel,dS ); LBMDS_ADDMOV(dS ,dN ); } else { m[dN ] = CSRC_N ; } \ + if(nbflag[dN ]&CFBnd) { m[dS ] = RAC(ccel,dN ); LBMDS_ADDMOV(dN ,dS ); } else { m[dS ] = CSRC_S ; } \ + if(nbflag[dW ]&CFBnd) { m[dE ] = RAC(ccel,dW ); LBMDS_ADDMOV(dW ,dE ); } else { m[dE ] = CSRC_E ; } \ + if(nbflag[dE ]&CFBnd) { m[dW ] = RAC(ccel,dE ); LBMDS_ADDMOV(dE ,dW ); } else { m[dW ] = CSRC_W ; } \ + if(nbflag[dB ]&CFBnd) { m[dT ] = RAC(ccel,dB ); LBMDS_ADDMOV(dB ,dT ); } else { m[dT ] = CSRC_T ; } \ + if(nbflag[dT ]&CFBnd) { m[dB ] = RAC(ccel,dT ); LBMDS_ADDMOV(dT ,dB ); } else { m[dB ] = CSRC_B ; } \ + \ + \ + if(nbflag[dSW]&CFBnd) { if(nbflag[dSW]&CFBndNoslip){ m[dNE] = RAC(ccel,dSW); LBMDS_ADDMOV(dSW,dNE); }else{ DEFAULT_STREAM_FREESLIP(dNE,dSW,nbflag[dSW]);} } else { m[dNE] = CSRC_NE; } \ + if(nbflag[dSE]&CFBnd) { if(nbflag[dSE]&CFBndNoslip){ m[dNW] = RAC(ccel,dSE); LBMDS_ADDMOV(dSE,dNW); }else{ DEFAULT_STREAM_FREESLIP(dNW,dSE,nbflag[dSE]);} } else { m[dNW] = CSRC_NW; } \ + if(nbflag[dNW]&CFBnd) { if(nbflag[dNW]&CFBndNoslip){ m[dSE] = RAC(ccel,dNW); LBMDS_ADDMOV(dNW,dSE); }else{ DEFAULT_STREAM_FREESLIP(dSE,dNW,nbflag[dNW]);} } else { m[dSE] = CSRC_SE; } \ + if(nbflag[dNE]&CFBnd) { if(nbflag[dNE]&CFBndNoslip){ m[dSW] = RAC(ccel,dNE); LBMDS_ADDMOV(dNE,dSW); }else{ DEFAULT_STREAM_FREESLIP(dSW,dNE,nbflag[dNE]);} } else { m[dSW] = CSRC_SW; } \ + if(nbflag[dSB]&CFBnd) { if(nbflag[dSB]&CFBndNoslip){ m[dNT] = RAC(ccel,dSB); LBMDS_ADDMOV(dSB,dNT); }else{ DEFAULT_STREAM_FREESLIP(dNT,dSB,nbflag[dSB]);} } else { m[dNT] = CSRC_NT; } \ + if(nbflag[dST]&CFBnd) { if(nbflag[dST]&CFBndNoslip){ m[dNB] = RAC(ccel,dST); LBMDS_ADDMOV(dST,dNB); }else{ DEFAULT_STREAM_FREESLIP(dNB,dST,nbflag[dST]);} } else { m[dNB] = CSRC_NB; } \ + if(nbflag[dNB]&CFBnd) { if(nbflag[dNB]&CFBndNoslip){ m[dST] = RAC(ccel,dNB); LBMDS_ADDMOV(dNB,dST); }else{ DEFAULT_STREAM_FREESLIP(dST,dNB,nbflag[dNB]);} } else { m[dST] = CSRC_ST; } \ + if(nbflag[dNT]&CFBnd) { if(nbflag[dNT]&CFBndNoslip){ m[dSB] = RAC(ccel,dNT); LBMDS_ADDMOV(dNT,dSB); }else{ DEFAULT_STREAM_FREESLIP(dSB,dNT,nbflag[dNT]);} } else { m[dSB] = CSRC_SB; } \ + if(nbflag[dWB]&CFBnd) { if(nbflag[dWB]&CFBndNoslip){ m[dET] = RAC(ccel,dWB); LBMDS_ADDMOV(dWB,dET); }else{ DEFAULT_STREAM_FREESLIP(dET,dWB,nbflag[dWB]);} } else { m[dET] = CSRC_ET; } \ + if(nbflag[dWT]&CFBnd) { if(nbflag[dWT]&CFBndNoslip){ m[dEB] = RAC(ccel,dWT); LBMDS_ADDMOV(dWT,dEB); }else{ DEFAULT_STREAM_FREESLIP(dEB,dWT,nbflag[dWT]);} } else { m[dEB] = CSRC_EB; } \ + if(nbflag[dEB]&CFBnd) { if(nbflag[dEB]&CFBndNoslip){ m[dWT] = RAC(ccel,dEB); LBMDS_ADDMOV(dEB,dWT); }else{ DEFAULT_STREAM_FREESLIP(dWT,dEB,nbflag[dEB]);} } else { m[dWT] = CSRC_WT; } \ + if(nbflag[dET]&CFBnd) { if(nbflag[dET]&CFBndNoslip){ m[dWB] = RAC(ccel,dET); LBMDS_ADDMOV(dET,dWB); }else{ DEFAULT_STREAM_FREESLIP(dWB,dET,nbflag[dET]);} } else { m[dWB] = CSRC_WB; } \ + } \ + + + + + +#define COLL_CALCULATE_DFEQ(dstarray) \ + dstarray[dN ] = EQN ; dstarray[dS ] = EQS ; \ + dstarray[dE ] = EQE ; dstarray[dW ] = EQW ; \ + dstarray[dT ] = EQT ; dstarray[dB ] = EQB ; \ + dstarray[dNE] = EQNE; dstarray[dNW] = EQNW; dstarray[dSE] = EQSE; dstarray[dSW] = EQSW; \ + dstarray[dNT] = EQNT; dstarray[dNB] = EQNB; dstarray[dST] = EQST; dstarray[dSB] = EQSB; \ + dstarray[dET] = EQET; dstarray[dEB] = EQEB; dstarray[dWT] = EQWT; dstarray[dWB] = EQWB; \ + + + +#define COLL_CALCULATE_NONEQTENSOR(csolev, srcArray ) \ + lcsmqadd = (srcArray##NE - lcsmeq[ dNE ]); \ + lcsmqadd -= (srcArray##NW - lcsmeq[ dNW ]); \ + lcsmqadd -= (srcArray##SE - lcsmeq[ dSE ]); \ + lcsmqadd += (srcArray##SW - lcsmeq[ dSW ]); \ + lcsmqo = (lcsmqadd* lcsmqadd); \ + lcsmqadd = (srcArray##ET - lcsmeq[ dET ]); \ + lcsmqadd -= (srcArray##EB - lcsmeq[ dEB ]); \ + lcsmqadd -= (srcArray##WT - lcsmeq[ dWT ]); \ + lcsmqadd += (srcArray##WB - lcsmeq[ dWB ]); \ + lcsmqo += (lcsmqadd* lcsmqadd); \ + lcsmqadd = (srcArray##NT - lcsmeq[ dNT ]); \ + lcsmqadd -= (srcArray##NB - lcsmeq[ dNB ]); \ + lcsmqadd -= (srcArray##ST - lcsmeq[ dST ]); \ + lcsmqadd += (srcArray##SB - lcsmeq[ dSB ]); \ + lcsmqo += (lcsmqadd* lcsmqadd); \ + lcsmqo *= 2.0; \ + lcsmqadd = (srcArray##E - lcsmeq[ dE ]); \ + lcsmqadd += (srcArray##W - lcsmeq[ dW ]); \ + lcsmqadd += (srcArray##NE - lcsmeq[ dNE ]); \ + lcsmqadd += (srcArray##NW - lcsmeq[ dNW ]); \ + lcsmqadd += (srcArray##SE - lcsmeq[ dSE ]); \ + lcsmqadd += (srcArray##SW - lcsmeq[ dSW ]); \ + lcsmqadd += (srcArray##ET - lcsmeq[ dET ]); \ + lcsmqadd += (srcArray##EB - lcsmeq[ dEB ]); \ + lcsmqadd += (srcArray##WT - lcsmeq[ dWT ]); \ + lcsmqadd += (srcArray##WB - lcsmeq[ dWB ]); \ + lcsmqo += (lcsmqadd* lcsmqadd); \ + lcsmqadd = (srcArray##N - lcsmeq[ dN ]); \ + lcsmqadd += (srcArray##S - lcsmeq[ dS ]); \ + lcsmqadd += (srcArray##NE - lcsmeq[ dNE ]); \ + lcsmqadd += (srcArray##NW - lcsmeq[ dNW ]); \ + lcsmqadd += (srcArray##SE - lcsmeq[ dSE ]); \ + lcsmqadd += (srcArray##SW - lcsmeq[ dSW ]); \ + lcsmqadd += (srcArray##NT - lcsmeq[ dNT ]); \ + lcsmqadd += (srcArray##NB - lcsmeq[ dNB ]); \ + lcsmqadd += (srcArray##ST - lcsmeq[ dST ]); \ + lcsmqadd += (srcArray##SB - lcsmeq[ dSB ]); \ + lcsmqo += (lcsmqadd* lcsmqadd); \ + lcsmqadd = (srcArray##T - lcsmeq[ dT ]); \ + lcsmqadd += (srcArray##B - lcsmeq[ dB ]); \ + lcsmqadd += (srcArray##NT - lcsmeq[ dNT ]); \ + lcsmqadd += (srcArray##NB - lcsmeq[ dNB ]); \ + lcsmqadd += (srcArray##ST - lcsmeq[ dST ]); \ + lcsmqadd += (srcArray##SB - lcsmeq[ dSB ]); \ + lcsmqadd += (srcArray##ET - lcsmeq[ dET ]); \ + lcsmqadd += (srcArray##EB - lcsmeq[ dEB ]); \ + lcsmqadd += (srcArray##WT - lcsmeq[ dWT ]); \ + lcsmqadd += (srcArray##WB - lcsmeq[ dWB ]); \ + lcsmqo += (lcsmqadd* lcsmqadd); \ + lcsmqo = sqrt(lcsmqo); \ + + + +// COLL_CALCULATE_CSMOMEGAVAL(csolev, lcsmomega); + +// careful - need lcsmqo +#define COLL_CALCULATE_CSMOMEGAVAL(csolev, dstomega ) \ + dstomega = 1.0/ \ + ( 3.0*( mLevel[(csolev)].lcnu+mLevel[(csolev)].lcsmago_sqr*( \ + -mLevel[(csolev)].lcnu + sqrt( mLevel[(csolev)].lcnu*mLevel[(csolev)].lcnu + 18.0*mLevel[(csolev)].lcsmago_sqr* lcsmqo ) \ + / (6.0*mLevel[(csolev)].lcsmago_sqr)) \ + ) +0.5 ); \ + + + +#define DEFAULT_COLLIDE_LES(grav) \ + rho = + MSRC_C + MSRC_N \ + + MSRC_S + MSRC_E \ + + MSRC_W + MSRC_T \ + + MSRC_B + MSRC_NE \ + + MSRC_NW + MSRC_SE \ + + MSRC_SW + MSRC_NT \ + + MSRC_NB + MSRC_ST \ + + MSRC_SB + MSRC_ET \ + + MSRC_EB + MSRC_WT \ + + MSRC_WB; \ + \ + ux = MSRC_E - MSRC_W \ + + MSRC_NE - MSRC_NW \ + + MSRC_SE - MSRC_SW \ + + MSRC_ET + MSRC_EB \ + - MSRC_WT - MSRC_WB ; \ + \ + uy = MSRC_N - MSRC_S \ + + MSRC_NE + MSRC_NW \ + - MSRC_SE - MSRC_SW \ + + MSRC_NT + MSRC_NB \ + - MSRC_ST - MSRC_SB ; \ + \ + uz = MSRC_T - MSRC_B \ + + MSRC_NT - MSRC_NB \ + + MSRC_ST - MSRC_SB \ + + MSRC_ET - MSRC_EB \ + + MSRC_WT - MSRC_WB ; \ + PRECOLLIDE_MODS(rho,ux,uy,uz, grav); \ + usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \ + COLL_CALCULATE_DFEQ(lcsmeq); \ + COLL_CALCULATE_NONEQTENSOR(lev, MSRC_); \ + COLL_CALCULATE_CSMOMEGAVAL(lev, lcsmomega); \ + CSMOMEGA_STATS(lev,lcsmomega); \ + \ + RAC(tcel,dC ) = (1.0-lcsmomega)*MSRC_C + lcsmomega*EQC ; \ + \ + RAC(tcel,dN ) = (1.0-lcsmomega)*MSRC_N + lcsmomega*lcsmeq[ dN ]; \ + RAC(tcel,dS ) = (1.0-lcsmomega)*MSRC_S + lcsmomega*lcsmeq[ dS ]; \ + RAC(tcel,dE ) = (1.0-lcsmomega)*MSRC_E + lcsmomega*lcsmeq[ dE ]; \ + RAC(tcel,dW ) = (1.0-lcsmomega)*MSRC_W + lcsmomega*lcsmeq[ dW ]; \ + RAC(tcel,dT ) = (1.0-lcsmomega)*MSRC_T + lcsmomega*lcsmeq[ dT ]; \ + RAC(tcel,dB ) = (1.0-lcsmomega)*MSRC_B + lcsmomega*lcsmeq[ dB ]; \ + \ + RAC(tcel,dNE) = (1.0-lcsmomega)*MSRC_NE + lcsmomega*lcsmeq[ dNE]; \ + RAC(tcel,dNW) = (1.0-lcsmomega)*MSRC_NW + lcsmomega*lcsmeq[ dNW]; \ + RAC(tcel,dSE) = (1.0-lcsmomega)*MSRC_SE + lcsmomega*lcsmeq[ dSE]; \ + RAC(tcel,dSW) = (1.0-lcsmomega)*MSRC_SW + lcsmomega*lcsmeq[ dSW]; \ + RAC(tcel,dNT) = (1.0-lcsmomega)*MSRC_NT + lcsmomega*lcsmeq[ dNT]; \ + RAC(tcel,dNB) = (1.0-lcsmomega)*MSRC_NB + lcsmomega*lcsmeq[ dNB]; \ + RAC(tcel,dST) = (1.0-lcsmomega)*MSRC_ST + lcsmomega*lcsmeq[ dST]; \ + RAC(tcel,dSB) = (1.0-lcsmomega)*MSRC_SB + lcsmomega*lcsmeq[ dSB]; \ + RAC(tcel,dET) = (1.0-lcsmomega)*MSRC_ET + lcsmomega*lcsmeq[ dET]; \ + RAC(tcel,dEB) = (1.0-lcsmomega)*MSRC_EB + lcsmomega*lcsmeq[ dEB]; \ + RAC(tcel,dWT) = (1.0-lcsmomega)*MSRC_WT + lcsmomega*lcsmeq[ dWT]; \ + RAC(tcel,dWB) = (1.0-lcsmomega)*MSRC_WB + lcsmomega*lcsmeq[ dWB]; \ + + + +#define DEFAULT_COLLIDE_NOLES(grav) \ + rho = + MSRC_C + MSRC_N \ + + MSRC_S + MSRC_E \ + + MSRC_W + MSRC_T \ + + MSRC_B + MSRC_NE \ + + MSRC_NW + MSRC_SE \ + + MSRC_SW + MSRC_NT \ + + MSRC_NB + MSRC_ST \ + + MSRC_SB + MSRC_ET \ + + MSRC_EB + MSRC_WT \ + + MSRC_WB; \ + \ + ux = MSRC_E - MSRC_W \ + + MSRC_NE - MSRC_NW \ + + MSRC_SE - MSRC_SW \ + + MSRC_ET + MSRC_EB \ + - MSRC_WT - MSRC_WB ; \ + \ + uy = MSRC_N - MSRC_S \ + + MSRC_NE + MSRC_NW \ + - MSRC_SE - MSRC_SW \ + + MSRC_NT + MSRC_NB \ + - MSRC_ST - MSRC_SB ; \ + \ + uz = MSRC_T - MSRC_B \ + + MSRC_NT - MSRC_NB \ + + MSRC_ST - MSRC_SB \ + + MSRC_ET - MSRC_EB \ + + MSRC_WT - MSRC_WB ; \ + PRECOLLIDE_MODS(rho, ux,uy,uz, grav); \ + usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \ + \ + RAC(tcel,dC ) = (1.0-OMEGA(lev))*MSRC_C + OMEGA(lev)*EQC ; \ + \ + RAC(tcel,dN ) = (1.0-OMEGA(lev))*MSRC_N + OMEGA(lev)*EQN ; \ + RAC(tcel,dS ) = (1.0-OMEGA(lev))*MSRC_S + OMEGA(lev)*EQS ; \ + RAC(tcel,dE ) = (1.0-OMEGA(lev))*MSRC_E + OMEGA(lev)*EQE ; \ + RAC(tcel,dW ) = (1.0-OMEGA(lev))*MSRC_W + OMEGA(lev)*EQW ; \ + RAC(tcel,dT ) = (1.0-OMEGA(lev))*MSRC_T + OMEGA(lev)*EQT ; \ + RAC(tcel,dB ) = (1.0-OMEGA(lev))*MSRC_B + OMEGA(lev)*EQB ; \ + \ + RAC(tcel,dNE) = (1.0-OMEGA(lev))*MSRC_NE + OMEGA(lev)*EQNE; \ + RAC(tcel,dNW) = (1.0-OMEGA(lev))*MSRC_NW + OMEGA(lev)*EQNW; \ + RAC(tcel,dSE) = (1.0-OMEGA(lev))*MSRC_SE + OMEGA(lev)*EQSE; \ + RAC(tcel,dSW) = (1.0-OMEGA(lev))*MSRC_SW + OMEGA(lev)*EQSW; \ + RAC(tcel,dNT) = (1.0-OMEGA(lev))*MSRC_NT + OMEGA(lev)*EQNT; \ + RAC(tcel,dNB) = (1.0-OMEGA(lev))*MSRC_NB + OMEGA(lev)*EQNB; \ + RAC(tcel,dST) = (1.0-OMEGA(lev))*MSRC_ST + OMEGA(lev)*EQST; \ + RAC(tcel,dSB) = (1.0-OMEGA(lev))*MSRC_SB + OMEGA(lev)*EQSB; \ + RAC(tcel,dET) = (1.0-OMEGA(lev))*MSRC_ET + OMEGA(lev)*EQET; \ + RAC(tcel,dEB) = (1.0-OMEGA(lev))*MSRC_EB + OMEGA(lev)*EQEB; \ + RAC(tcel,dWT) = (1.0-OMEGA(lev))*MSRC_WT + OMEGA(lev)*EQWT; \ + RAC(tcel,dWB) = (1.0-OMEGA(lev))*MSRC_WB + OMEGA(lev)*EQWB; \ + + + + + +#define OPTIMIZED_STREAMCOLLIDE_LES \ + \ + m[dC ] = CSRC_C ; \ + m[dN ] = CSRC_N ; m[dS ] = CSRC_S ; \ + m[dE ] = CSRC_E ; m[dW ] = CSRC_W ; \ + m[dT ] = CSRC_T ; m[dB ] = CSRC_B ; \ + m[dNE] = CSRC_NE; m[dNW] = CSRC_NW; m[dSE] = CSRC_SE; m[dSW] = CSRC_SW; \ + m[dNT] = CSRC_NT; m[dNB] = CSRC_NB; m[dST] = CSRC_ST; m[dSB] = CSRC_SB; \ + m[dET] = CSRC_ET; m[dEB] = CSRC_EB; m[dWT] = CSRC_WT; m[dWB] = CSRC_WB; \ + \ + rho = MSRC_C + MSRC_N + MSRC_S + MSRC_E + MSRC_W + MSRC_T \ + + MSRC_B + MSRC_NE + MSRC_NW + MSRC_SE + MSRC_SW + MSRC_NT \ + + MSRC_NB + MSRC_ST + MSRC_SB + MSRC_ET + MSRC_EB + MSRC_WT + MSRC_WB; \ + ux = MSRC_E - MSRC_W + MSRC_NE - MSRC_NW + MSRC_SE - MSRC_SW \ + + MSRC_ET + MSRC_EB - MSRC_WT - MSRC_WB; \ + uy = MSRC_N - MSRC_S + MSRC_NE + MSRC_NW - MSRC_SE - MSRC_SW \ + + MSRC_NT + MSRC_NB - MSRC_ST - MSRC_SB; \ + uz = MSRC_T - MSRC_B + MSRC_NT - MSRC_NB + MSRC_ST - MSRC_SB \ + + MSRC_ET - MSRC_EB + MSRC_WT - MSRC_WB; \ + PRECOLLIDE_MODS(rho, ux,uy,uz, mLevel[lev].gravity); \ + usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \ + COLL_CALCULATE_DFEQ(lcsmeq); \ + COLL_CALCULATE_NONEQTENSOR(lev, MSRC_) \ + COLL_CALCULATE_CSMOMEGAVAL(lev, lcsmomega); \ + CSMOMEGA_STATS(lev,lcsmomega); \ + \ + RAC(tcel,dC ) = (1.0-lcsmomega)*MSRC_C + lcsmomega*EQC ; \ + RAC(tcel,dN ) = (1.0-lcsmomega)*MSRC_N + lcsmomega*lcsmeq[ dN ]; \ + RAC(tcel,dS ) = (1.0-lcsmomega)*MSRC_S + lcsmomega*lcsmeq[ dS ]; \ + RAC(tcel,dE ) = (1.0-lcsmomega)*MSRC_E + lcsmomega*lcsmeq[ dE ]; \ + RAC(tcel,dW ) = (1.0-lcsmomega)*MSRC_W + lcsmomega*lcsmeq[ dW ]; \ + RAC(tcel,dT ) = (1.0-lcsmomega)*MSRC_T + lcsmomega*lcsmeq[ dT ]; \ + RAC(tcel,dB ) = (1.0-lcsmomega)*MSRC_B + lcsmomega*lcsmeq[ dB ]; \ + \ + RAC(tcel,dNE) = (1.0-lcsmomega)*MSRC_NE + lcsmomega*lcsmeq[ dNE]; \ + RAC(tcel,dNW) = (1.0-lcsmomega)*MSRC_NW + lcsmomega*lcsmeq[ dNW]; \ + RAC(tcel,dSE) = (1.0-lcsmomega)*MSRC_SE + lcsmomega*lcsmeq[ dSE]; \ + RAC(tcel,dSW) = (1.0-lcsmomega)*MSRC_SW + lcsmomega*lcsmeq[ dSW]; \ + \ + RAC(tcel,dNT) = (1.0-lcsmomega)*MSRC_NT + lcsmomega*lcsmeq[ dNT]; \ + RAC(tcel,dNB) = (1.0-lcsmomega)*MSRC_NB + lcsmomega*lcsmeq[ dNB]; \ + RAC(tcel,dST) = (1.0-lcsmomega)*MSRC_ST + lcsmomega*lcsmeq[ dST]; \ + RAC(tcel,dSB) = (1.0-lcsmomega)*MSRC_SB + lcsmomega*lcsmeq[ dSB]; \ + \ + RAC(tcel,dET) = (1.0-lcsmomega)*MSRC_ET + lcsmomega*lcsmeq[ dET]; \ + RAC(tcel,dEB) = (1.0-lcsmomega)*MSRC_EB + lcsmomega*lcsmeq[ dEB]; \ + RAC(tcel,dWT) = (1.0-lcsmomega)*MSRC_WT + lcsmomega*lcsmeq[ dWT]; \ + RAC(tcel,dWB) = (1.0-lcsmomega)*MSRC_WB + lcsmomega*lcsmeq[ dWB]; \ + + + +#define OPTIMIZED_STREAMCOLLIDE_UNUSED \ + \ + rho = CSRC_C + CSRC_N + CSRC_S + CSRC_E + CSRC_W + CSRC_T \ + + CSRC_B + CSRC_NE + CSRC_NW + CSRC_SE + CSRC_SW + CSRC_NT \ + + CSRC_NB + CSRC_ST + CSRC_SB + CSRC_ET + CSRC_EB + CSRC_WT + CSRC_WB; \ + ux = CSRC_E - CSRC_W + CSRC_NE - CSRC_NW + CSRC_SE - CSRC_SW \ + + CSRC_ET + CSRC_EB - CSRC_WT - CSRC_WB; \ + uy = CSRC_N - CSRC_S + CSRC_NE + CSRC_NW - CSRC_SE - CSRC_SW \ + + CSRC_NT + CSRC_NB - CSRC_ST - CSRC_SB; \ + uz = CSRC_T - CSRC_B + CSRC_NT - CSRC_NB + CSRC_ST - CSRC_SB \ + + CSRC_ET - CSRC_EB + CSRC_WT - CSRC_WB; \ + PRECOLLIDE_MODS(rho, ux,uy,uz, mLevel[lev].gravity); \ + usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \ + COLL_CALCULATE_DFEQ(lcsmeq); \ + COLL_CALCULATE_NONEQTENSOR(lev, CSRC_) \ + COLL_CALCULATE_CSMOMEGAVAL(lev, lcsmomega); \ + \ + RAC(tcel,dC ) = (1.0-lcsmomega)*CSRC_C + lcsmomega*EQC ; \ + RAC(tcel,dN ) = (1.0-lcsmomega)*CSRC_N + lcsmomega*lcsmeq[ dN ]; \ + RAC(tcel,dS ) = (1.0-lcsmomega)*CSRC_S + lcsmomega*lcsmeq[ dS ]; \ + RAC(tcel,dE ) = (1.0-lcsmomega)*CSRC_E + lcsmomega*lcsmeq[ dE ]; \ + RAC(tcel,dW ) = (1.0-lcsmomega)*CSRC_W + lcsmomega*lcsmeq[ dW ]; \ + RAC(tcel,dT ) = (1.0-lcsmomega)*CSRC_T + lcsmomega*lcsmeq[ dT ]; \ + RAC(tcel,dB ) = (1.0-lcsmomega)*CSRC_B + lcsmomega*lcsmeq[ dB ]; \ + \ + RAC(tcel,dNE) = (1.0-lcsmomega)*CSRC_NE + lcsmomega*lcsmeq[ dNE]; \ + RAC(tcel,dNW) = (1.0-lcsmomega)*CSRC_NW + lcsmomega*lcsmeq[ dNW]; \ + RAC(tcel,dSE) = (1.0-lcsmomega)*CSRC_SE + lcsmomega*lcsmeq[ dSE]; \ + RAC(tcel,dSW) = (1.0-lcsmomega)*CSRC_SW + lcsmomega*lcsmeq[ dSW]; \ + \ + RAC(tcel,dNT) = (1.0-lcsmomega)*CSRC_NT + lcsmomega*lcsmeq[ dNT]; \ + RAC(tcel,dNB) = (1.0-lcsmomega)*CSRC_NB + lcsmomega*lcsmeq[ dNB]; \ + RAC(tcel,dST) = (1.0-lcsmomega)*CSRC_ST + lcsmomega*lcsmeq[ dST]; \ + RAC(tcel,dSB) = (1.0-lcsmomega)*CSRC_SB + lcsmomega*lcsmeq[ dSB]; \ + \ + RAC(tcel,dET) = (1.0-lcsmomega)*CSRC_ET + lcsmomega*lcsmeq[ dET]; \ + RAC(tcel,dEB) = (1.0-lcsmomega)*CSRC_EB + lcsmomega*lcsmeq[ dEB]; \ + RAC(tcel,dWT) = (1.0-lcsmomega)*CSRC_WT + lcsmomega*lcsmeq[ dWT]; \ + RAC(tcel,dWB) = (1.0-lcsmomega)*CSRC_WB + lcsmomega*lcsmeq[ dWB]; \ + + + +#define OPTIMIZED_STREAMCOLLIDE_NOLES \ + \ + rho = CSRC_C + CSRC_N + CSRC_S + CSRC_E + CSRC_W + CSRC_T \ + + CSRC_B + CSRC_NE + CSRC_NW + CSRC_SE + CSRC_SW + CSRC_NT \ + + CSRC_NB + CSRC_ST + CSRC_SB + CSRC_ET + CSRC_EB + CSRC_WT + CSRC_WB; \ + ux = CSRC_E - CSRC_W + CSRC_NE - CSRC_NW + CSRC_SE - CSRC_SW \ + + CSRC_ET + CSRC_EB - CSRC_WT - CSRC_WB; \ + uy = CSRC_N - CSRC_S + CSRC_NE + CSRC_NW - CSRC_SE - CSRC_SW \ + + CSRC_NT + CSRC_NB - CSRC_ST - CSRC_SB; \ + uz = CSRC_T - CSRC_B + CSRC_NT - CSRC_NB + CSRC_ST - CSRC_SB \ + + CSRC_ET - CSRC_EB + CSRC_WT - CSRC_WB; \ + PRECOLLIDE_MODS(rho, ux,uy,uz, mLevel[lev].gravity); \ + usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \ + RAC(tcel,dC ) = (1.0-OMEGA(lev))*CSRC_C + OMEGA(lev)*EQC ; \ + RAC(tcel,dN ) = (1.0-OMEGA(lev))*CSRC_N + OMEGA(lev)*EQN ; \ + RAC(tcel,dS ) = (1.0-OMEGA(lev))*CSRC_S + OMEGA(lev)*EQS ; \ + RAC(tcel,dE ) = (1.0-OMEGA(lev))*CSRC_E + OMEGA(lev)*EQE ; \ + RAC(tcel,dW ) = (1.0-OMEGA(lev))*CSRC_W + OMEGA(lev)*EQW ; \ + RAC(tcel,dT ) = (1.0-OMEGA(lev))*CSRC_T + OMEGA(lev)*EQT ; \ + RAC(tcel,dB ) = (1.0-OMEGA(lev))*CSRC_B + OMEGA(lev)*EQB ; \ + \ + RAC(tcel,dNE) = (1.0-OMEGA(lev))*CSRC_NE + OMEGA(lev)*EQNE; \ + RAC(tcel,dNW) = (1.0-OMEGA(lev))*CSRC_NW + OMEGA(lev)*EQNW; \ + RAC(tcel,dSE) = (1.0-OMEGA(lev))*CSRC_SE + OMEGA(lev)*EQSE; \ + RAC(tcel,dSW) = (1.0-OMEGA(lev))*CSRC_SW + OMEGA(lev)*EQSW; \ + \ + RAC(tcel,dNT) = (1.0-OMEGA(lev))*CSRC_NT + OMEGA(lev)*EQNT; \ + RAC(tcel,dNB) = (1.0-OMEGA(lev))*CSRC_NB + OMEGA(lev)*EQNB; \ + RAC(tcel,dST) = (1.0-OMEGA(lev))*CSRC_ST + OMEGA(lev)*EQST; \ + RAC(tcel,dSB) = (1.0-OMEGA(lev))*CSRC_SB + OMEGA(lev)*EQSB; \ + \ + RAC(tcel,dET) = (1.0-OMEGA(lev))*CSRC_ET + OMEGA(lev)*EQET; \ + RAC(tcel,dEB) = (1.0-OMEGA(lev))*CSRC_EB + OMEGA(lev)*EQEB; \ + RAC(tcel,dWT) = (1.0-OMEGA(lev))*CSRC_WT + OMEGA(lev)*EQWT; \ + RAC(tcel,dWB) = (1.0-OMEGA(lev))*CSRC_WB + OMEGA(lev)*EQWB; \ + + + + + +// LES switching for OPT3D +#if USE_LES==1 +#define DEFAULT_COLLIDEG(grav) DEFAULT_COLLIDE_LES(grav) +#define OPTIMIZED_STREAMCOLLIDE OPTIMIZED_STREAMCOLLIDE_LES +#else +#define DEFAULT_COLLIDEG(grav) DEFAULT_COLLIDE_NOLES(grav) +#define OPTIMIZED_STREAMCOLLIDE OPTIMIZED_STREAMCOLLIDE_NOLES +#endif + +#endif // 3D, opt OPT3D==true + +#define USQRMAXCHECK(Cusqr,Cux,Cuy,Cuz, CmMaxVlen,CmMxvx,CmMxvy,CmMxvz) \ + if(Cusqr>CmMaxVlen) { \ + CmMxvx = Cux; CmMxvy = Cuy; CmMxvz = Cuz; CmMaxVlen = Cusqr; \ + } /* stats */ + + + +/****************************************************************************** + * interpolateCellFromCoarse macros + *****************************************************************************/ + + +// WOXDY_N = Weight Order X Dimension Y _ number N +#define WO1D1 ( 1.0/ 2.0) +#define WO1D2 ( 1.0/ 4.0) +#define WO1D3 ( 1.0/ 8.0) + +#define WO2D1_1 (-1.0/16.0) +#define WO2D1_9 ( 9.0/16.0) + +#define WO2D2_11 (WO2D1_1 * WO2D1_1) +#define WO2D2_19 (WO2D1_9 * WO2D1_1) +#define WO2D2_91 (WO2D1_9 * WO2D1_1) +#define WO2D2_99 (WO2D1_9 * WO2D1_9) + +#define WO2D3_111 (WO2D1_1 * WO2D1_1 * WO2D1_1) +#define WO2D3_191 (WO2D1_9 * WO2D1_1 * WO2D1_1) +#define WO2D3_911 (WO2D1_9 * WO2D1_1 * WO2D1_1) +#define WO2D3_991 (WO2D1_9 * WO2D1_9 * WO2D1_1) +#define WO2D3_119 (WO2D1_1 * WO2D1_1 * WO2D1_9) +#define WO2D3_199 (WO2D1_9 * WO2D1_1 * WO2D1_9) +#define WO2D3_919 (WO2D1_9 * WO2D1_1 * WO2D1_9) +#define WO2D3_999 (WO2D1_9 * WO2D1_9 * WO2D1_9) + +#if FSGR_STRICT_DEBUG==1 +#define ADD_INT_DFSCHECK(alev, ai,aj,ak, at, afac, l) \ + if( (((1.0-(at))>0.0) && (!(QCELL((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr , l) > -1.0 ))) || \ + ((( (at))>0.0) && (!(QCELL((alev), (ai),(aj),(ak),mLevel[(alev)].setOther, l) > -1.0 ))) ){ \ + errMsg("INVDFSCHECK", " l"<<(alev)<<" "<0.0) && (!(RFLAG((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr )&(CFInter|CFFluid|CFGrCoarseInited) ))) || \ + ((( (at))>0.0) && (!(RFLAG((alev), (ai),(aj),(ak),mLevel[(alev)].setOther)&(CFInter|CFFluid|CFGrCoarseInited) ))) ){ \ + errMsg("INVFLAGCINTCHECK", " l"<<(alev)<<" at:"<<(at)<<" "<mPanic) { errMsg("interpolateCellFromCoarse", "ICFC_DFOUT cell "< only current +// t=0.5 -> mix +// t=1.0 -> only other +#if OPT3D==0 +#define ADD_INT_DFS(alev, ai,aj,ak, at, afac) \ + ADD_INT_FLAGCHECK(alev, ai,aj,ak, at, afac); \ + FORDF0{ \ + LbmFloat df = ( \ + QCELL((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr , l)*(1.0-(at)) + \ + QCELL((alev), (ai),(aj),(ak),mLevel[(alev)].setOther, l)*( (at)) \ + ) ; \ + ADD_INT_DFSCHECK(alev, ai,aj,ak, at, afac, l); \ + df *= (afac); \ + rho += df; \ + ux += (this->dfDvecX[l]*df); \ + uy += (this->dfDvecY[l]*df); \ + uz += (this->dfDvecZ[l]*df); \ + intDf[l] += df; \ + } +// write interpolated dfs back to cell (correct non-eq. parts) +#define IDF_WRITEBACK_ \ + FORDF0{ \ + LbmFloat eq = getCollideEq(l, rho,ux,uy,uz);\ + QCELL(lev,i,j,k, dstSet, l) = (eq+ (intDf[l]-eq)*mDfScaleDown);\ + } \ + /* check that all values are ok */ \ + INTDEBOUT +#define IDF_WRITEBACK \ + LbmFloat omegaDst, omegaSrc;\ + /* smago new */ \ + LbmFloat feq[LBM_DFNUM]; \ + LbmFloat dfScale = mDfScaleDown; \ + FORDF0{ \ + feq[l] = getCollideEq(l, rho,ux,uy,uz); \ + } \ + if(mLevel[lev ].lcsmago>0.0) {\ + LbmFloat Qo = this->getLesNoneqTensorCoeff(intDf,feq); \ + omegaDst = this->getLesOmega(mLevel[lev+0].omega,mLevel[lev+0].lcsmago,Qo); \ + omegaSrc = this->getLesOmega(mLevel[lev-1].omega,mLevel[lev-1].lcsmago,Qo); \ + } else {\ + omegaDst = mLevel[lev+0].omega; \ + omegaSrc = mLevel[lev-1].omega;\ + } \ + \ + dfScale = (mLevel[lev+0].timestep/mLevel[lev-1].timestep)* (1.0/omegaDst-1.0)/ (1.0/omegaSrc-1.0); \ + FORDF0{ \ + /*errMsg("SMAGO"," org"<cDfNum; l++) { + if(this->lesCoeffOffdiag[m][l]==0.0) continue; + qadd += this->lesCoeffOffdiag[m][l]*(df[l]-feq[l]); + } + Qo += (qadd*qadd); + } + Qo *= 2.0; // off diag twice + for(int m=0; mcDfNum; l++) { + if(this->lesCoeffDiag[m][l]==0.0) continue; + qadd += this->lesCoeffDiag[m][l]*(df[l]-feq[l]); + } + Qo += (qadd*qadd); + } + Qo = sqrt(Qo); + return Qo; +}; + +inline LbmFloat LbmFsgrSolver::getLesOmega(LbmFloat omega, LbmFloat csmago, LbmFloat Qo) { + const LbmFloat tau = 1.0/omega; + const LbmFloat nu = (2.0*tau-1.0) * (1.0/6.0); + const LbmFloat C = csmago; + const LbmFloat Csqr = C*C; + LbmFloat S = -nu + sqrt( nu*nu + 18.0*Csqr*Qo ) / (6.0*Csqr); + return( 1.0/( 3.0*( nu+Csqr*S ) +0.5 ) ); +} + +#define DEBUG_CALCPRINTCELL(str,df) {\ + LbmFloat prho=df[0], pux=0., puy=0., puz=0.; \ + for(int dfl=1; dflcDfNum; dfl++) { \ + prho += df[dfl]; \ + pux += (this->dfDvecX[dfl]*df[dfl]); \ + puy += (this->dfDvecY[dfl]*df[dfl]); \ + puz += (this->dfDvecZ[dfl]*df[dfl]); \ + } \ + errMsg("DEBUG_CALCPRINTCELL",">"<cDfNum; l++) { + rho += df[l]; + ux += (this->dfDvecX[l]*df[l]); + uy += (this->dfDvecY[l]*df[l]); + uz += (this->dfDvecZ[l]*df[l]); + } + + + PRECOLLIDE_MODS(rho,ux,uy,uz, gravity); + for(l=0; lcDfNum; l++) { + feq[l] = getCollideEq(l,rho,ux,uy,uz); + } + + if(csmago>0.0) { + Qo = getLesNoneqTensorCoeff(df,feq); + omegaNew = getLesOmega(omega,csmago,Qo); + } else { + omegaNew = omega; // smago off... + } + if(newOmegaRet) *newOmegaRet = omegaNew; // return value for stats + if(newQoRet) *newQoRet = Qo; // return value of non-eq. stress tensor + + for(l=0; lcDfNum; l++) { + df[l] = (1.0-omegaNew ) * df[l] + omegaNew * feq[l]; + } + //if((i==16)&&(j==10)) DEBUG_CALCPRINTCELL( "2dcoll "< /* rand(3) */ + +#include +#ifndef sqrtf +#define sqrtf sqrt +#endif + +/****************************************************************************** + * helper functions + *****************************************************************************/ + +// try to enhance surface? +#define SURFACE_ENH 2 + +extern bool glob_mpactive; +extern bool glob_mpnum; +extern bool glob_mpindex; + +//! for raytracing +void LbmFsgrSolver::prepareVisualization( void ) { + int lev = mMaxRefine; + int workSet = mLevel[lev].setCurr; + + int mainGravDir=0; + LbmFloat mainGravLen = 0.; + FORDF1{ + LbmFloat thisGravLen = dot(LbmVec(dfVecX[l],dfVecY[l],dfVecZ[l]), getNormalized(mLevel[mMaxRefine].gravity) ); + if(thisGravLen>mainGravLen) { + mainGravLen = thisGravLen; + mainGravDir = l; + } + } + +#if LBMDIM==2 + // 2d, place in the middle of isofield slice (k=2) +# define ZKD1 0 + // 2d z offset = 2, lbmGetData adds 1, so use one here +# define ZKOFF 1 + // reset all values... + for(int k= 0; k< 5; ++k) + for(int j=0;jlbmGetData(i,j,ZKOFF)=0.0; + } +#else // LBMDIM==2 + // 3d, use normal bounds +# define ZKD1 1 +# define ZKOFF k + // reset all values... + for(int k= getForZMinBnd(); k< getForZMaxBnd(lev); ++k) + for(int j=0;jlbmGetData(i,j,ZKOFF)=0.0; + } +#endif // LBMDIM==2 + + // MPT, ignore + if((glob_mpactive) && (glob_mpnum>1) && (glob_mpindex==0)) { + mpIso->resetAll(0.); + } + + + LbmFloat minval = mIsoValue*1.05; // / mIsoWeight[13]; + // add up... + float val = 0.0; + for(int k= getForZMin1(); k< getForZMax1(lev); ++k) + for(int j=1;j6)) { + *mpIso->lbmGetData(i,j,ZKOFF) += minval; + } else if((noslipbnd)&&(intercnt>0)) { + // necessary? + *mpIso->lbmGetData(i,j,ZKOFF) += mIsoValue*0.9; + } else { + // nothing to do... + } + + continue; + } else if(cflag&(CFNoNbEmpty|CFFluid)) { + // no empty nb interface cells are treated as full + val=1.0; + } else { + val = (QCELL(lev, i,j,k,workSet, dFfrac)); + } + + if(noslipbnd) { + if(vallbmGetData(i,j,ZKOFF) += minval-( val * mIsoWeight[13] ); + } +#endif // SURFACE_ENH>0 + + } else { // all others, unused? + continue; + } + + *mpIso->lbmGetData( i-1 , j-1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[0] ); + *mpIso->lbmGetData( i , j-1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[1] ); + *mpIso->lbmGetData( i+1 , j-1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[2] ); + + *mpIso->lbmGetData( i-1 , j ,ZKOFF-ZKD1) += ( val * mIsoWeight[3] ); + *mpIso->lbmGetData( i , j ,ZKOFF-ZKD1) += ( val * mIsoWeight[4] ); + *mpIso->lbmGetData( i+1 , j ,ZKOFF-ZKD1) += ( val * mIsoWeight[5] ); + + *mpIso->lbmGetData( i-1 , j+1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[6] ); + *mpIso->lbmGetData( i , j+1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[7] ); + *mpIso->lbmGetData( i+1 , j+1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[8] ); + + + *mpIso->lbmGetData( i-1 , j-1 ,ZKOFF ) += ( val * mIsoWeight[9] ); + *mpIso->lbmGetData( i , j-1 ,ZKOFF ) += ( val * mIsoWeight[10] ); + *mpIso->lbmGetData( i+1 , j-1 ,ZKOFF ) += ( val * mIsoWeight[11] ); + + *mpIso->lbmGetData( i-1 , j ,ZKOFF ) += ( val * mIsoWeight[12] ); + *mpIso->lbmGetData( i , j ,ZKOFF ) += ( val * mIsoWeight[13] ); + *mpIso->lbmGetData( i+1 , j ,ZKOFF ) += ( val * mIsoWeight[14] ); + + *mpIso->lbmGetData( i-1 , j+1 ,ZKOFF ) += ( val * mIsoWeight[15] ); + *mpIso->lbmGetData( i , j+1 ,ZKOFF ) += ( val * mIsoWeight[16] ); + *mpIso->lbmGetData( i+1 , j+1 ,ZKOFF ) += ( val * mIsoWeight[17] ); + + + *mpIso->lbmGetData( i-1 , j-1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[18] ); + *mpIso->lbmGetData( i , j-1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[19] ); + *mpIso->lbmGetData( i+1 , j-1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[20] ); + + *mpIso->lbmGetData( i-1 , j ,ZKOFF+ZKD1) += ( val * mIsoWeight[21] ); + *mpIso->lbmGetData( i , j ,ZKOFF+ZKD1)+= ( val * mIsoWeight[22] ); + *mpIso->lbmGetData( i+1 , j ,ZKOFF+ZKD1) += ( val * mIsoWeight[23] ); + + *mpIso->lbmGetData( i-1 , j+1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[24] ); + *mpIso->lbmGetData( i , j+1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[25] ); + *mpIso->lbmGetData( i+1 , j+1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[26] ); + } + + // TEST!? +#if SURFACE_ENH>=2 + + if(mFsSurfGenSetting&fssgNoObs) { + for(int k= getForZMin1(); k< getForZMax1(lev); ++k) + for(int j=1;j=mLevel[mMaxRefine].lSizex) + //|| (nj>=mLevel[mMaxRefine].lSizey) + //|| (nk>=mLevel[mMaxRefine].lSizez) ) continue; + } + + if(nbored&CFInter) { + if(avgfcnt>0.) avgfill/=avgfcnt; + *mpIso->lbmGetData(i,j,ZKOFF) = avgfill; continue; + } + else if(nbored&CFFluid) { + *mpIso->lbmGetData(i,j,ZKOFF) = 1.; continue; + } + + } + } + + // move surface towards inner "row" of obstacle + // cells if necessary (all obs cells without fluid/inter + // nbs (=iso==0) next to obstacles...) + for(int k= getForZMin1(); k< getForZMax1(lev); ++k) + for(int j=1;jlbmGetData(i,j,ZKOFF)==0.)) { + int bndnbcnt=0; + FORDF1 { + const int ni = i+dfVecX[l]; + const int nj = j+dfVecY[l]; + const int nk = ZKOFF+dfVecZ[l]; + const CellFlagType nbflag = RFLAG(lev, ni,nj,nk, workSet); + if(nbflag&CFBnd) bndnbcnt++; + } + if(bndnbcnt>0) *mpIso->lbmGetData(i,j,ZKOFF)=mIsoValue*0.95; + } + } + } + // */ + + if(mFsSurfGenSetting&fssgNoNorth) + for(int k= getForZMinBnd(); k< getForZMaxBnd(lev); ++k) + for(int j=0;jlbmGetData(0, j,ZKOFF) = *mpIso->lbmGetData(1, j,ZKOFF); + } + if(mFsSurfGenSetting&fssgNoEast) + for(int k= getForZMinBnd(); k< getForZMaxBnd(lev); ++k) + for(int i=0;ilbmGetData(i,0, ZKOFF) = *mpIso->lbmGetData(i,1, ZKOFF); + } + if(mFsSurfGenSetting&fssgNoSouth) + for(int k= getForZMinBnd(); k< getForZMaxBnd(lev); ++k) + for(int j=0;jlbmGetData(mLevel[lev].lSizex-1,j,ZKOFF) = *mpIso->lbmGetData(mLevel[lev].lSizex-2,j,ZKOFF); + } + if(mFsSurfGenSetting&fssgNoWest) + for(int k= getForZMinBnd(); k< getForZMaxBnd(lev); ++k) + for(int i=0;ilbmGetData(i,mLevel[lev].lSizey-1,ZKOFF) = *mpIso->lbmGetData(i,mLevel[lev].lSizey-2,ZKOFF); + } + if(LBMDIM>2) { + if(mFsSurfGenSetting&fssgNoBottom) + for(int j=0;jlbmGetData(i,j,0 ) = *mpIso->lbmGetData(i,j,1 ); + } + if(mFsSurfGenSetting&fssgNoTop) + for(int j=0;jlbmGetData(i,j,mLevel[lev].lSizez-1) = *mpIso->lbmGetData(i,j,mLevel[lev].lSizez-2); + } + } +#endif // SURFACE_ENH>=2 + + + // update preview, remove 2d? + if((mOutputSurfacePreview)&&(LBMDIM==3)) { + int pvsx = (int)(mPreviewFactor*mSizex); + int pvsy = (int)(mPreviewFactor*mSizey); + int pvsz = (int)(mPreviewFactor*mSizez); + //float scale = (float)mSizex / previewSize; + LbmFloat scalex = (LbmFloat)mSizex/(LbmFloat)pvsx; + LbmFloat scaley = (LbmFloat)mSizey/(LbmFloat)pvsy; + LbmFloat scalez = (LbmFloat)mSizez/(LbmFloat)pvsz; + for(int k= 0; k< (pvsz-1); ++k) + for(int j=0;j< pvsy;j++) + for(int i=0;i< pvsx;i++) { + *mpPreviewSurface->lbmGetData(i,j,k) = *mpIso->lbmGetData( (int)(i*scalex), (int)(j*scaley), (int)(k*scalez) ); + } + // set borders again... + for(int k= 0; k< (pvsz-1); ++k) { + for(int j=0;j< pvsy;j++) { + *mpPreviewSurface->lbmGetData(0,j,k) = *mpIso->lbmGetData( 0, (int)(j*scaley), (int)(k*scalez) ); + *mpPreviewSurface->lbmGetData(pvsx-1,j,k) = *mpIso->lbmGetData( mSizex-1, (int)(j*scaley), (int)(k*scalez) ); + } + for(int i=0;i< pvsx;i++) { + *mpPreviewSurface->lbmGetData(i,0,k) = *mpIso->lbmGetData( (int)(i*scalex), 0, (int)(k*scalez) ); + *mpPreviewSurface->lbmGetData(i,pvsy-1,k) = *mpIso->lbmGetData( (int)(i*scalex), mSizey-1, (int)(k*scalez) ); + } + } + for(int j=0;jlbmGetData(i,j,0) = *mpIso->lbmGetData( (int)(i*scalex), (int)(j*scaley) , 0); + *mpPreviewSurface->lbmGetData(i,j,pvsz-1) = *mpIso->lbmGetData( (int)(i*scalex), (int)(j*scaley) , mSizez-1); + } + + if(mFarFieldSize>=1.2) { + // also remove preview border + for(int k= 0; k< (pvsz-1); ++k) { + for(int j=0;j< pvsy;j++) { + *mpPreviewSurface->lbmGetData(0,j,k) = + *mpPreviewSurface->lbmGetData(1,j,k) = + *mpPreviewSurface->lbmGetData(2,j,k); + *mpPreviewSurface->lbmGetData(pvsx-1,j,k) = + *mpPreviewSurface->lbmGetData(pvsx-2,j,k) = + *mpPreviewSurface->lbmGetData(pvsx-3,j,k); + //0.0; + } + for(int i=0;i< pvsx;i++) { + *mpPreviewSurface->lbmGetData(i,0,k) = + *mpPreviewSurface->lbmGetData(i,1,k) = + *mpPreviewSurface->lbmGetData(i,2,k); + *mpPreviewSurface->lbmGetData(i,pvsy-1,k) = + *mpPreviewSurface->lbmGetData(i,pvsy-2,k) = + *mpPreviewSurface->lbmGetData(i,pvsy-3,k); + //0.0; + } + } + for(int j=0;jlbmGetData(i,j,0) = + *mpPreviewSurface->lbmGetData(i,j,1) = + *mpPreviewSurface->lbmGetData(i,j,2); + *mpPreviewSurface->lbmGetData(i,j,pvsz-1) = + *mpPreviewSurface->lbmGetData(i,j,pvsz-2) = + *mpPreviewSurface->lbmGetData(i,j,pvsz-3); + //0.0; + } + } + } + + // MPT + #if LBM_INCLUDE_TESTSOLVERS==1 + mrIsoExchange(); + #endif // LBM_INCLUDE_TESTSOLVERS==1 + + return; +} + +/*! calculate speeds of fluid objects (or inflow) */ +void LbmFsgrSolver::recalculateObjectSpeeds() { + const bool debugRecalc = false; + int numobjs = (int)(this->mpGiObjects->size()); + // note - (numobjs + 1) is entry for domain settings + + if(debugRecalc) errMsg("recalculateObjectSpeeds","start, #obj:"<255-1) { + errFatal("LbmFsgrSolver::recalculateObjectSpeeds","More than 256 objects currently not supported...",SIMWORLD_INITERROR); + return; + } + mObjectSpeeds.resize(numobjs+1); + for(int i=0; i<(int)(numobjs+0); i++) { + mObjectSpeeds[i] = vec2L(this->mpParam->calculateLattVelocityFromRw( vec2P( (*this->mpGiObjects)[i]->getInitialVelocity(mSimulationTime) ))); + if(debugRecalc) errMsg("recalculateObjectSpeeds","id"<mpGiObjects)[i]->getInitialVelocity(mSimulationTime) ); + } + + // also reinit part slip values here + mObjectPartslips.resize(numobjs+1); + for(int i=0; i<=(int)(numobjs+0); i++) { + if(impGiObjects)[i]->getGeoPartSlipValue(); + } else { + // domain setting + mObjectPartslips[i] = this->mDomainPartSlipValue; + } + LbmFloat set = mObjectPartslips[i]; + + // as in setInfluenceVelocity + const LbmFloat dt = mLevel[mMaxRefine].timestep; + const LbmFloat dtInter = 0.01; + //LbmFloat facFv = 1.-set; + // mLevel[mMaxRefine].timestep + LbmFloat facNv = (LbmFloat)( 1.-pow( (double)(set), (double)(dt/dtInter)) ); + errMsg("mObjectPartslips","id:"< LbmFsgrSolver::getDebugObjects() { + vector debo; + if(this->mOutputSurfacePreview) { + debo.push_back( mpPreviewSurface ); + } +#if LBM_INCLUDE_TESTSOLVERS==1 + if(mUseTestdata) { + vector tdebo; + tdebo = mpTest->getDebugObjects(); + for(size_t i=0; isetStart( this->mvGeoStart + ntlVec3Gfx(mLevel[mMaxRefine].nodeSize*0.5) ); + partt->setEnd ( this->mvGeoEnd + ntlVec3Gfx(mLevel[mMaxRefine].nodeSize*0.5) ); + + partt->setSimStart( ntlVec3Gfx(0.0) ); + partt->setSimEnd ( ntlVec3Gfx(mSizex, mSizey, getForZMaxBnd(mMaxRefine)) ); + + while( (numgetNumInitialParticles()) && (tries<100*partt->getNumInitialParticles()) ) { + LbmFloat x,y,z,t; + x = 1.0+(( (LbmFloat)(mSizex-3.) ) * (rand()/(RAND_MAX+1.0)) ); + y = 1.0+(( (LbmFloat)(mSizey-3.) ) * (rand()/(RAND_MAX+1.0)) ); + z = 1.0+(( (LbmFloat) getForZMax1(mMaxRefine)-2. )* (rand()/(RAND_MAX+1.0)) ); + int i = (int)(x+0.5); + int j = (int)(y+0.5); + int k = (int)(z+0.5); + if(LBMDIM==2) { + k = 0; z = 0.5; // place in the middle of domain + } + + //if( RFLAG(mMaxRefine, i,j,k, workSet)& (CFFluid) ) + //&& ( RFLAG(mMaxRefine, i,j,k, workSet)& CFNoNbFluid ) + //if( RFLAG(mMaxRefine, i,j,k, workSet) & (CFFluid|CFInter|CFMbndInflow) ) { + if( RFLAG(mMaxRefine, i,j,k, workSet) & (CFNoBndFluid|CFUnused) ) { + bool cellOk = true; + //? FORDF1 { if(!(RFLAG_NB(mMaxRefine,i,j,k,workSet, l) & CFFluid)) cellOk = false; } + if(!cellOk) continue; + // in fluid... + partt->addParticle(x,y,z); + partt->getLast()->setStatus(PART_IN); + partt->getLast()->setType(PART_TRACER); + + partt->getLast()->setSize(1.); + // randomize size + partt->getLast()->setSize(0.5 + (rand()/(RAND_MAX+1.0))); + + if( ( partt->getInitStart()>0.) + && ( partt->getInitEnd()>0.) + && ( partt->getInitEnd()>partt->getInitStart() )) { + t = partt->getInitStart()+ (partt->getInitEnd()-partt->getInitStart())*(rand()/(RAND_MAX+1.0)); + partt->getLast()->setLifeTime( -t ); + } + num++; + } + tries++; + } // */ + + /*FSGR_FORIJK1(mMaxRefine) { + if( (RFLAG(mMaxRefine,i,j,k, workSet) & (CFNoBndFluid)) ) { + LbmFloat rndn = (rand()/(RAND_MAX+1.0)); + if(rndn>0.0) { + ntlVec3Gfx pos( (LbmFloat)(i)-0.5, (LbmFloat)(j)-0.5, (LbmFloat)(k)-0.5 ); + if(LBMDIM==2) { pos[2]=0.5; } + partt->addParticle( pos[0],pos[1],pos[2] ); + partt->getLast()->setStatus(PART_IN); + partt->getLast()->setType(PART_TRACER); + partt->getLast()->setSize(1.0); + } + } + } // */ + + + // DEBUG TEST +#if LBM_INCLUDE_TESTSOLVERS==1 + if(mUseTestdata) { + const bool partDebug=false; + if(mpTest->mPartTestcase==0){ errMsg("LbmTestdata"," part init "<mPartTestcase); } + if(mpTest->mPartTestcase==-12){ + const int lev = mMaxRefine; + for(int i=5;i<15;i++) { + LbmFloat x,y,z; + y = 0.5+(LbmFloat)(i); + x = mLevel[lev].lSizex/20.0*10.0; + z = mLevel[lev].lSizez/20.0*2.0; + partt->addParticle(x,y,z); + partt->getLast()->setStatus(PART_IN); + partt->getLast()->setType(PART_BUBBLE); + partt->getLast()->setSize( (-4.0+(LbmFloat)i)/1.0 ); + if(partDebug) errMsg("PARTTT","SET "<getLast()->getPos() <<" s"<getLast()->getSize() ); + } + } + if(mpTest->mPartTestcase==-11){ + const int lev = mMaxRefine; + for(int i=5;i<15;i++) { + LbmFloat x,y,z; + y = 10.5+(LbmFloat)(i); + x = mLevel[lev].lSizex/20.0*10.0; + z = mLevel[lev].lSizez/20.0*40.0; + partt->addParticle(x,y,z); + partt->getLast()->setStatus(PART_IN); + partt->getLast()->setType(PART_DROP); + partt->getLast()->setSize( (-4.0+(LbmFloat)i)/1.0 ); + if(partDebug) errMsg("PARTTT","SET "<getLast()->getPos() <<" s"<getLast()->getSize() ); + } + } + // place floats on rectangular region FLOAT_JITTER_BND + if(mpTest->mPartTestcase==-10){ + const int lev = mMaxRefine; + const int sx = mLevel[lev].lSizex; + const int sy = mLevel[lev].lSizey; + //for(int j=-(int)(sy*0.25);j<-(int)(sy*0.25)+2;++j) { for(int i=-(int)(sx*0.25);i<-(int)(sy*0.25)+2;++i) { + //for(int j=-(int)(sy*1.25);j<(int)(2.25*sy);++j) { for(int i=-(int)(sx*1.25);i<(int)(2.25*sx);++i) { + for(int j=-(int)(sy*0.3);j<(int)(1.3*sy);++j) { for(int i=-(int)(sx*0.3);i<(int)(1.3*sx);++i) { + //for(int j=-(int)(sy*0.2);j<(int)(0.2*sy);++j) { for(int i= (int)(sx*0.5);i<= (int)(0.51*sx);++i) { + LbmFloat x,y,z; + x = 0.0+(LbmFloat)(i); + y = 0.0+(LbmFloat)(j); + //z = mLevel[lev].lSizez/10.0*2.5 - 1.0; + z = mLevel[lev].lSizez/20.0*9.5 - 1.0; + //z = mLevel[lev].lSizez/20.0*4.5 - 1.0; + partt->addParticle(x,y,z); + //if( (i>0)&&(i0)&&(jgetLast()->setStatus(PART_IN); } else { partt->getLast()->setStatus(PART_OUT); } + partt->getLast()->setStatus(PART_IN); + partt->getLast()->setType(PART_FLOAT); + partt->getLast()->setSize( 15.0 ); + if(partDebug) errMsg("PARTTT","SET "<getLast()->getPos() <<" s"<getLast()->getSize() ); + } + } } + } + // DEBUG TEST +#endif // LBM_INCLUDE_TESTSOLVERS + + + debMsgStd("LbmFsgrSolver::initParticles",DM_MSG,"Added "<mPartGenProb<<", tries:"<getNumParticles()) return 1; + + return 0; +} + +// helper function for particle debugging +/*static string getParticleStatusString(int state) { + std::ostringstream out; + if(state&PART_DROP) out << "dropp "; + if(state&PART_TRACER) out << "tracr "; + if(state&PART_BUBBLE) out << "bubbl "; + if(state&PART_FLOAT) out << "float "; + if(state&PART_INTER) out << "inter "; + + if(state&PART_IN) out << "inn "; + if(state&PART_OUT) out << "out "; + if(state&PART_INACTIVE) out << "INACT "; + if(state&PART_OUTFLUID) out << "outfluid "; + return out.str(); +} // */ + +#define P_CHANGETYPE(p, newtype) \ + p->setLifeTime(0.); \ + /* errMsg("PIT","U pit"<<(p)->getId()<<" pos:"<< (p)->getPos()<<" status:"<getFlags())<<" to "<< (newtype) ); */ \ + p->setType(newtype); + +// tracer defines +#define TRACE_JITTER 0.025 +#define TRACE_RAND (rand()/(RAND_MAX+1.0))*TRACE_JITTER-(TRACE_JITTER*0.5) +#define FFGET_NORM(var,dl) \ + if(RFLAG_NB(lev,i,j,k,workSet, dl) &(CFInter)){ (var) = QCELL_NB(lev,i,j,k,workSet,dl,dFfrac); } \ + else if(RFLAG_NB(lev,i,j,k,workSet, dl) &(CFFluid|CFUnused)){ (var) = 1.; } else (var) = 0.0; + +// float jitter +#define FLOAT_JITTER_BND (FLOAT_JITTER*2.0) +#define FLOAT_JITTBNDRAND(x) ((rand()/(RAND_MAX+1.0))*FLOAT_JITTER_BND*(1.-(x/(LbmFloat)maxdw))-(FLOAT_JITTER_BND*(1.-(x)/(LbmFloat)maxdw)*0.5)) + +#define DEL_PART { \ + /*errMsg("PIT","DEL AT "<< __LINE__<<" type:"<getType()<<" "); */ \ + p->setActive( false ); \ + continue; } + +void LbmFsgrSolver::advanceParticles() { + const int level = mMaxRefine; + const int workSet = mLevel[level].setCurr; + LbmFloat vx=0.0,vy=0.0,vz=0.0; + //int debugOutCounter=0; // debug output counter + + myTime_t parttstart = getTime(); + const LbmFloat cellsize = this->mpParam->getCellSize(); + const LbmFloat timestep = this->mpParam->getTimestep(); + //const LbmFloat viscAir = 1.79 * 1e-5; // RW2L kin. viscosity, mu + //const LbmFloat viscWater = 1.0 * 1e-6; // RW2L kin. viscosity, mu + const LbmFloat rhoAir = 1.2; // [kg m^-3] RW2L + const LbmFloat rhoWater = 1000.0; // RW2L + const LbmFloat minDropSize = 0.0005; // [m], = 2mm RW2L + const LbmVec velAir(0.); // [m / s] + + const LbmFloat r1 = 0.005; // r max + const LbmFloat r2 = 0.0005; // r min + const LbmFloat v1 = 9.0; // v max + const LbmFloat v2 = 2.0; // v min + const LbmVec rwgrav = vec2L( this->mpParam->getGravity(mSimulationTime) ); + const bool useff = (mFarFieldSize>1.2); // if(mpTest->mFarfMode>0){ + + // TODO scale bubble/part damping dep. on timestep, also drop bnd rev damping + const int cutval = mCutoff; // use full border!? + if(this->mStepCnt%50==49) { mpParticles->cleanup(); } + for(vector::iterator pit= mpParticles->getParticlesBegin(); + pit!= mpParticles->getParticlesEnd(); pit++) { + //if((*pit).getPos()[2]>10.) errMsg("PIT"," pit"<<(*pit).getId()<<" pos:"<< (*pit).getPos()<<" status:["<getLifeTime()<0.){ + if(p->getLifeTime() < -mSimulationTime) continue; + else p->setLifeTime(-mLevel[level].timestep); // zero for following update + } + int i,j,k; + p->setLifeTime(p->getLifeTime()+mLevel[level].timestep); + + // nearest neighbor, particle positions don't include empty bounds + ntlVec3Gfx pos = p->getPos(); + i= (int)pos[0]; j= (int)pos[1]; k= (int)pos[2];// no offset necessary + if(LBMDIM==2) { k = 0; } + + // only testdata handling, all for sws +#if LBM_INCLUDE_TESTSOLVERS==1 + if(useff && (mpTest->mFarfMode>0)) { + p->setStatus(PART_OUT); + mpTest->handleParticle(p, i,j,k); continue; + } +#endif // LBM_INCLUDE_TESTSOLVERS==1 + + // in out tests + if(p->getStatus()&PART_IN) { // IN + if( (imSizex-1-cutval)|| + (jmSizey-1-cutval) + //||(kmSizez-1-cutval) + ) { + if(!useff) { DEL_PART; + } else { + p->setStatus(PART_OUT); + } + } + } else { // OUT rough check + // check in again? + if( (i>=cutval)&&(i<=mSizex-1-cutval)&& + (j>=cutval)&&(j<=mSizey-1-cutval) + ) { + p->setStatus(PART_IN); + } + } + + if( (p->getType()==PART_BUBBLE) || + (p->getType()==PART_TRACER) ) { + + // no interpol + vx = vy = vz = 0.0; + if(p->getStatus()&PART_IN) { // IN + if(k>=cutval) { + if(k>mSizez-1-cutval) DEL_PART; + + if( RFLAG(level, i,j,k, workSet)&(CFFluid|CFUnused) ) { + // still ok + int partLev = level; + int si=i, sj=j, sk=k; + while(partLev>0 && RFLAG(partLev, si,sj,sk, workSet)&(CFUnused)) { + partLev--; + si/=2; + sj/=2; + sk/=2; + } + // get velocity from fluid cell + if( RFLAG(partLev, si,sj,sk, workSet)&(CFFluid) ) { + LbmFloat *ccel = RACPNT(partLev, si,sj,sk, workSet); + FORDF1{ + LbmFloat cdf = RAC(ccel, l); + // TODO update below + vx += (this->dfDvecX[l]*cdf); + vy += (this->dfDvecY[l]*cdf); + vz += (this->dfDvecZ[l]*cdf); + } + // remove gravity influence + const LbmFloat lesomega = mLevel[level].omega; // no les + vx -= mLevel[level].gravity[0] * lesomega*0.5; + vy -= mLevel[level].gravity[1] * lesomega*0.5; + vz -= mLevel[level].gravity[2] * lesomega*0.5; + } // fluid vel + + } else { // OUT + // out of bounds, deactivate... + // FIXME make fsgr treatment + if(p->getType()==PART_BUBBLE) { P_CHANGETYPE(p, PART_FLOAT ); continue; } + } + } else { + // below 3d region, just rise + } + } else { // OUT +# if LBM_INCLUDE_TESTSOLVERS==1 + if(useff) { mpTest->handleParticle(p, i,j,k); } + else DEL_PART; +# else // LBM_INCLUDE_TESTSOLVERS==1 + DEL_PART; +# endif // LBM_INCLUDE_TESTSOLVERS==1 + // TODO use x,y vel...? + } + + ntlVec3Gfx v = p->getVel(); // dampen... + if( (useff)&& (p->getType()==PART_BUBBLE) ) { + // test rise + + if(mPartUsePhysModel) { + LbmFloat radius = p->getSize() * minDropSize; + LbmVec velPart = vec2L(p->getVel()) *cellsize/timestep; // L2RW, lattice velocity + LbmVec velWater = LbmVec(vx,vy,vz) *cellsize/timestep;// L2RW, fluid velocity + LbmVec velRel = velWater - velPart; + //LbmFloat velRelNorm = norm(velRel); + LbmFloat pvolume = rhoAir * 4.0/3.0 * M_PI* radius*radius*radius; // volume: 4/3 pi r^3 + + LbmVec fb = -rwgrav* pvolume *rhoWater; + LbmVec fd = velRel*6.0*M_PI*radius* (1e-3); //viscWater; + LbmVec change = (fb+fd) *10.0*timestep *(timestep/cellsize); + /*if(debugOutCounter<0) { + errMsg("PIT","BTEST1 vol="<getVel())) * 6.0*M_PI*radius* (1e-3); //viscWater; + LbmFloat w = 0.99; + vz = (1.0-w)*vz + w*(p->getVel()[2]-0.5*(p->getSize()/5.0)*mLevel[level].gravity[2]); + v = ntlVec3Gfx(vx,vy,vz)+vec2G(fd2); + p->setVel( v ); + } else { + // non phys, half old, half fluid, use slightly slower acc + v = v*0.5 + ntlVec3Gfx(vx,vy,vz)* 0.5-vec2G(mLevel[level].gravity)*0.5; + p->setVel( v * 0.99 ); + } + p->advanceVel(); + + } else if(p->getType()==PART_TRACER) { + v = ntlVec3Gfx(vx,vy,vz); + CellFlagType fflag = RFLAG(level, i,j,k, workSet); + + if(fflag&(CFFluid|CFInter) ) { p->setInFluid(true); + } else { p->setInFluid(false); } + + if( (( fflag&CFFluid ) && ( fflag&CFNoBndFluid )) || + (( fflag&CFInter ) && (!(fflag&CFNoNbFluid)) ) ) { + // only real fluid +# if LBMDIM==3 + p->advance( TRACE_RAND,TRACE_RAND,TRACE_RAND); +# else + p->advance( TRACE_RAND,TRACE_RAND, 0.); +# endif + + } else { + // move inwards along normal, make sure normal is valid first + // todo use class funcs! + const int lev = level; + LbmFloat nx=0.,ny=0.,nz=0., nv1,nv2; + bool nonorm = false; + if(i<=0) { nx = -1.; nonorm = true; } + if(i>=mSizex-1) { nx = 1.; nonorm = true; } + if(j<=0) { ny = -1.; nonorm = true; } + if(j>=mSizey-1) { ny = 1.; nonorm = true; } +# if LBMDIM==3 + if(k<=0) { nz = -1.; nonorm = true; } + if(k>=mSizez-1) { nz = 1.; nonorm = true; } +# endif // LBMDIM==3 + if(!nonorm) { + FFGET_NORM(nv1,dE); FFGET_NORM(nv2,dW); + nx = 0.5* (nv2-nv1); + FFGET_NORM(nv1,dN); FFGET_NORM(nv2,dS); + ny = 0.5* (nv2-nv1); +# if LBMDIM==3 + FFGET_NORM(nv1,dT); FFGET_NORM(nv2,dB); + nz = 0.5* (nv2-nv1); +# else // LBMDIM==3 + nz = 0.; +# endif // LBMDIM==3 + } else { + v = p->getVel() + vec2G(mLevel[level].gravity); + } + p->advanceVec( (ntlVec3Gfx(nx,ny,nz)) * -0.1 ); // + vec2G(mLevel[level].gravity); + } + } + + p->setVel( v ); + p->advanceVel(); + } + + // drop handling + else if(p->getType()==PART_DROP) { + ntlVec3Gfx v = p->getVel(); // dampen... + + if(mPartUsePhysModel) { + LbmFloat radius = p->getSize() * minDropSize; + LbmVec velPart = vec2L(p->getVel()) *cellsize /timestep; // * cellsize / timestep; // L2RW, lattice velocity + LbmVec velRel = velAir - velPart; + //LbmVec velRelLat = velRel /cellsize*timestep; // L2RW + LbmFloat velRelNorm = norm(velRel); + // TODO calculate values in lattice units, compute CD?!??! + LbmFloat mb = rhoWater * 4.0/3.0 * M_PI* radius*radius*radius; // mass: 4/3 pi r^3 rho + const LbmFloat rw = (r1-radius)/(r1-r2); + const LbmFloat rmax = (0.5 + 0.5*rw); + const LbmFloat vmax = (v2 + (v1-v2)* (1.0-rw) ); + const LbmFloat cd = (rmax) * (velRelNorm)/(vmax); + + LbmVec fg = rwgrav * mb;// * (1.0-rhoAir/rhoWater); + LbmVec fd = velRel* velRelNorm* cd*M_PI *rhoAir *0.5 *radius*radius; + LbmVec change = (fg+ fd ) *timestep / mb *(timestep/cellsize); + //if(k>0) { errMsg("\nPIT","NTEST1 mb="<setVel( v*0.9 ); // restdamping + } else { + p->addToVel( vec2G(mLevel[level].gravity) ); + } + } // OLD + p->advanceVel(); + + if(p->getStatus()&PART_IN) { // IN + if(kgetSize(); + const LbmFloat dropmass = ParticleObject::getMass(mPartDropMassSub*size); + bool orgcellok = false; + if( (oi<0)||(oi>mSizex-1)|| + (oj<0)||(oj>mSizey-1)|| + (ok<0)||(ok>mSizez-1) ) { + // org cell not ok! + } else if( RFLAG(level, oi,oj,ok, workSet) & (CFInter) ){ + orgcellok = true; + } else { + // search upward for interface + oi=i; oj=j; ok=k; + for(int kk=0; kk<5 && ok<=mSizez-2; kk++) { + ok++; // check sizez-2 due to this increment! + if( RFLAG(level, oi,oj,ok, workSet) & (CFInter) ){ + kk = 5; orgcellok = true; + } + } + } + + //errMsg("PTIMPULSE"," new v"< 0.166*0.166) { + v *= 1./sqrtf((float)vlensqr)*0.166; + } + // compute cell velocity + LbmFloat *tcel = RACPNT(level, oi,oj,ok, workSet); + LbmFloat velUx=0., velUy=0., velUz=0.; + FORDF0 { + velUx += (this->dfDvecX[l]*RAC(tcel,l)); + velUy += (this->dfDvecY[l]*RAC(tcel,l)); + velUz += (this->dfDvecZ[l]*RAC(tcel,l)); + } + // add impulse + /* + LbmFloat cellVelSqr = velUx*velUx+ velUy*velUy+ velUz*velUz; + //errMsg("PTIMPULSE"," new v"<getStatus() ); + } + } + myTime_t parttend = getTime(); + debMsgStd("LbmFsgrSolver::advanceParticles",DM_MSG,"Time for particle update:"<< getTimeString(parttend-parttstart)<<", #particles:"<getNumParticles() , 10 ); +} + +void LbmFsgrSolver::notifySolverOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename) { + int workSet = mLevel[mMaxRefine].setCurr; + std::ostringstream name; + + // debug - raw dump of ffrac values, as text! + if(mDumpRawText) { + name << outfilename<< frameNrStr <<".dump"; + FILE *file = fopen(name.str().c_str(),"w"); + if(file) { + + for(int k= getForZMinBnd(); k< getForZMaxBnd(mMaxRefine); ++k) { + for(int j=0;j1.) val=1.; + } + if(RFLAG(mMaxRefine, i,j,k, workSet) & CFFluid) val = 1.; + fprintf(file, "%f ",val); // text + //errMsg("W", PRINT_IJK<<" val:"<1.) val=1.; + } + if(RFLAG(mMaxRefine, i,j,k, workSet) & CFFluid) val = 1.; + fwrite( &val, sizeof(val), 1, file); // binary + } + } + } + fclose(file); + } // file + } // unzipped + else { + // zipped, use iso values + prepareVisualization(); + name << outfilename<< frameNrStr <<".bdump.gz"; + gzFile gzf = gzopen(name.str().c_str(),"wb9"); + if(gzf) { + // write size + int s; + s=mSizex; gzwrite(gzf, &s, sizeof(s)); + s=mSizey; gzwrite(gzf, &s, sizeof(s)); + s=mSizez; gzwrite(gzf, &s, sizeof(s)); + + // write isovalues + for(int k= getForZMinBnd(); k< getForZMaxBnd(mMaxRefine); ++k) { + for(int j=0;jlbmGetData( i,j,k ); + gzwrite(gzf, &val, sizeof(val)); + } + } + } + gzclose(gzf); + } // gzf + } // zip + } // bin dump + + dumptype = 0; frameNr = 0; // get rid of warning +} + +/*! move a particle at a boundary */ +void LbmFsgrSolver::handleObstacleParticle(ParticleObject *p) { + //if(normNoSqrt(v)<=0.) continue; // skip stuck + /* + p->setVel( v * -1. ); // revert + p->advanceVel(); // move back twice... + if( RFLAG(mMaxRefine, i,j,k, workSet)& (CFBndNoslip)) { + p->setVel( v * -0.5 ); // revert & dampen + } + p->advanceVel(); + // */ + // TODO mark/remove stuck parts!? + + const int level = mMaxRefine; + const int workSet = mLevel[level].setCurr; + LbmVec v = vec2L( p->getVel() ); + if(normNoSqrt(v)<=0.) { + p->setVel(vec2G(mLevel[level].gravity)); + } + + CellFlagType pflag = CFBnd; + ntlVec3Gfx posOrg(p->getPos()); + ntlVec3Gfx npos(0.); + int ni=1,nj=1,nk=1; + int tries = 0; + + // try to undo movement + p->advanceVec( (p->getVel()-vec2G(mLevel[level].gravity)) * -2.); + + npos = p->getPos(); ni= (int)npos[0]; + nj= (int)npos[1]; nk= (int)npos[2]; + if(LBMDIM==2) { nk = 0; } + //errMsg("BOUNDCPAR"," t"<setActive( false ); + return; + } + pflag = RFLAG(level, ni,nj,nk, workSet); + + // try to force particle out of boundary + bool haveNorm = false; + LbmVec bnormal; + if(pflag&CFBnd) { + npos = posOrg; ni= (int)npos[0]; + nj= (int)npos[1]; nk= (int)npos[2]; + if(LBMDIM==2) { nk = 0; } + + computeObstacleSurfaceNormalAcc(ni,nj,nk, &bnormal[0]); + haveNorm = true; + normalize(bnormal); + bnormal *= 0.25; + + tries = 1; + while(pflag&CFBnd && tries<=5) { + // use increasing step sizes + p->advanceVec( vec2G( bnormal *0.5 *(gfxReal)tries ) ); + npos = p->getPos(); + ni= (int)npos[0]; + nj= (int)npos[1]; + nk= (int)npos[2]; + + // delete out of domain + if(!checkDomainBounds(level,ni,nj,nk)) { + //errMsg("BOUNDCPAR"," DEL! "); + p->setActive( false ); + return; + } + pflag = RFLAG(level, ni,nj,nk, workSet); + tries++; + } + + // really stuck, delete... + if(pflag&CFBnd) { + p->setActive( false ); + return; + } + } + + // not in bound anymore! + if(!haveNorm) { + CellFlagType *bflag = &RFLAG(level, ni,nj,nk, workSet); + LbmFloat *bcell = RACPNT(level, ni,nj,nk, workSet); + computeObstacleSurfaceNormal(bcell,bflag, &bnormal[0]); + } + normalize(bnormal); + LbmVec normComp = bnormal * dot(vec2L(v),bnormal); + //errMsg("BOUNDCPAR","bnormal"<setVel(vec2G(v)); + p->advanceVel(); +} + +/*****************************************************************************/ +/*! internal quick print function (for debugging) */ +/*****************************************************************************/ +void +LbmFsgrSolver::printLbmCell(int level, int i, int j, int k, int set) { + stdCellId *newcid = new stdCellId; + newcid->level = level; + newcid->x = i; + newcid->y = j; + newcid->z = k; + + // this function is not called upon clicking, then its from setMouseClick + debugPrintNodeInfo( newcid, set ); + delete newcid; +} +void +LbmFsgrSolver::debugMarkCellCall(int level, int vi,int vj,int vk) { + stdCellId *newcid = new stdCellId; + newcid->level = level; + newcid->x = vi; + newcid->y = vj; + newcid->z = vk; + this->addCellToMarkedList( newcid ); +} + + +/*****************************************************************************/ +// implement CellIterator interface +/*****************************************************************************/ + + + +// values from guiflkt.cpp +extern double guiRoiSX, guiRoiSY, guiRoiSZ, guiRoiEX, guiRoiEY, guiRoiEZ; +extern int guiRoiMaxLev, guiRoiMinLev; +#define CID_SX (int)( (mLevel[cid->level].lSizex-1) * guiRoiSX ) +#define CID_SY (int)( (mLevel[cid->level].lSizey-1) * guiRoiSY ) +#define CID_SZ (int)( (mLevel[cid->level].lSizez-1) * guiRoiSZ ) + +#define CID_EX (int)( (mLevel[cid->level].lSizex-1) * guiRoiEX ) +#define CID_EY (int)( (mLevel[cid->level].lSizey-1) * guiRoiEY ) +#define CID_EZ (int)( (mLevel[cid->level].lSizez-1) * guiRoiEZ ) + +CellIdentifierInterface* +LbmFsgrSolver::getFirstCell( ) { + int level = mMaxRefine; + +#if LBMDIM==3 + if(mMaxRefine>0) { level = mMaxRefine-1; } // NO1HIGHESTLEV DEBUG +#endif + level = guiRoiMaxLev; + if(level>mMaxRefine) level = mMaxRefine; + + //errMsg("LbmFsgrSolver::getFirstCell","Celliteration started..."); + stdCellId *cid = new stdCellId; + cid->level = level; + cid->x = CID_SX; + cid->y = CID_SY; + cid->z = CID_SZ; + return cid; +} + +LbmFsgrSolver::stdCellId* +LbmFsgrSolver::convertBaseCidToStdCid( CellIdentifierInterface* basecid) { + //stdCellId *cid = dynamic_cast( basecid ); + stdCellId *cid = (stdCellId*)( basecid ); + return cid; +} + +void LbmFsgrSolver::advanceCell( CellIdentifierInterface* basecid) { + stdCellId *cid = convertBaseCidToStdCid(basecid); + if(cid->getEnd()) return; + + //debugOut(" ADb "<x<<","<y<<","<z<<" e"<getEnd(), 10); + cid->x++; + if(cid->x > CID_EX){ cid->x = CID_SX; cid->y++; + if(cid->y > CID_EY){ cid->y = CID_SY; cid->z++; + if(cid->z > CID_EZ){ + cid->level--; + cid->x = CID_SX; + cid->y = CID_SY; + cid->z = CID_SZ; + if(cid->level < guiRoiMinLev) { + cid->level = guiRoiMaxLev; + cid->setEnd( true ); + } + } + } + } + //debugOut(" ADa "<x<<","<y<<","<z<<" e"<getEnd(), 10); +} + +bool LbmFsgrSolver::noEndCell( CellIdentifierInterface* basecid) { + stdCellId *cid = convertBaseCidToStdCid(basecid); + return (!cid->getEnd()); +} + +void LbmFsgrSolver::deleteCellIterator( CellIdentifierInterface** cid ) { + delete *cid; + *cid = NULL; +} + +CellIdentifierInterface* LbmFsgrSolver::getCellAt( ntlVec3Gfx pos ) { + //int cellok = false; + pos -= (this->mvGeoStart); + + LbmFloat mmaxsize = mLevel[mMaxRefine].nodeSize; + for(int level=mMaxRefine; level>=0; level--) { // finest first + //for(int level=0; level<=mMaxRefine; level++) { // coarsest first + LbmFloat nsize = mLevel[level].nodeSize; + int x,y,z; + // CHECK +- maxsize? + x = (int)((pos[0]+0.5*mmaxsize) / nsize ); + y = (int)((pos[1]+0.5*mmaxsize) / nsize ); + z = (int)((pos[2]+0.5*mmaxsize) / nsize ); + if(LBMDIM==2) z = 0; + + // double check... + if(x<0) continue; + if(y<0) continue; + if(z<0) continue; + if(x>=mLevel[level].lSizex) continue; + if(y>=mLevel[level].lSizey) continue; + if(z>=mLevel[level].lSizez) continue; + + // return fluid/if/border cells + if( ( (RFLAG(level, x,y,z, mLevel[level].setCurr)&(CFUnused)) ) || + ( (levellevel = level; + newcid->x = x; + newcid->y = y; + newcid->z = z; + //errMsg("cellAt",this->mName<<" "<level].setCurr; + //return mLevel[cid->level].setOther; +} + +int LbmFsgrSolver::getCellLevel ( CellIdentifierInterface* basecid) { + stdCellId *cid = convertBaseCidToStdCid(basecid); + return cid->level; +} + +ntlVec3Gfx LbmFsgrSolver::getCellOrigin ( CellIdentifierInterface* basecid) { + ntlVec3Gfx ret; + + stdCellId *cid = convertBaseCidToStdCid(basecid); + ntlVec3Gfx cs( mLevel[cid->level].nodeSize ); + if(LBMDIM==2) { cs[2] = 0.0; } + + if(LBMDIM==2) { + ret =(this->mvGeoStart + ntlVec3Gfx( cid->x *cs[0], cid->y *cs[1], (this->mvGeoEnd[2]-this->mvGeoStart[2])*0.5 ) + + ntlVec3Gfx(0.0,0.0,cs[1]*-0.25)*cid->level ) + +getCellSize(basecid); + } else { + ret =(this->mvGeoStart + ntlVec3Gfx( cid->x *cs[0], cid->y *cs[1], cid->z *cs[2] )) + +getCellSize(basecid); + } + return (ret); +} + +ntlVec3Gfx LbmFsgrSolver::getCellSize ( CellIdentifierInterface* basecid) { + // return half size + stdCellId *cid = convertBaseCidToStdCid(basecid); + ntlVec3Gfx retvec( mLevel[cid->level].nodeSize * 0.5 ); + // 2d display as rectangles + if(LBMDIM==2) { retvec[2] = 0.0; } + return (retvec); +} + +LbmFloat LbmFsgrSolver::getCellDensity ( CellIdentifierInterface* basecid,int set) { + stdCellId *cid = convertBaseCidToStdCid(basecid); + + // skip non-fluid cells + if(RFLAG(cid->level, cid->x,cid->y,cid->z, set)&(CFFluid|CFInter)) { + // ok go on... + } else { + return 0.; + } + + LbmFloat rho = 0.0; + FORDF0 { rho += QCELL(cid->level, cid->x,cid->y,cid->z, set, l); } // ORG + return ((rho-1.0) * mLevel[cid->level].simCellSize / mLevel[cid->level].timestep) +1.0; // ORG + /*if(RFLAG(cid->level, cid->x,cid->y,cid->z, set)&CFInter) { // test + LbmFloat ux,uy,uz; + ux=uy=uz= 0.0; + int lev = cid->level; + LbmFloat df[27], feqOld[27]; + FORDF0 { + rho += QCELL(lev, cid->x,cid->y,cid->z, set, l); + ux += this->dfDvecX[l]* QCELL(lev, cid->x,cid->y,cid->z, set, l); + uy += this->dfDvecY[l]* QCELL(lev, cid->x,cid->y,cid->z, set, l); + uz += this->dfDvecZ[l]* QCELL(lev, cid->x,cid->y,cid->z, set, l); + df[l] = QCELL(lev, cid->x,cid->y,cid->z, set, l); + } + FORDF0 { + feqOld[l] = getCollideEq(l, rho,ux,uy,uz); + } + // debugging mods + //const LbmFloat Qo = this->getLesNoneqTensorCoeff(df,feqOld); + //const LbmFloat modOmega = this->getLesOmega(mLevel[lev].omega, mLevel[lev].lcsmago,Qo); + //rho = (2.0-modOmega) *25.0; + //rho = Qo*100.0; + //if(cid->x==24){ errMsg("MODOMT"," at "<x,cid->y,cid->z)<<" = "<level, cid->x,cid->y,cid->z, set)&(CFFluid|CFInter)) { + // ok go on... + } else { + return LbmVec(0.0); + } + + LbmFloat ux,uy,uz; + ux=uy=uz= 0.0; + FORDF0 { + ux += this->dfDvecX[l]* QCELL(cid->level, cid->x,cid->y,cid->z, set, l); + uy += this->dfDvecY[l]* QCELL(cid->level, cid->x,cid->y,cid->z, set, l); + uz += this->dfDvecZ[l]* QCELL(cid->level, cid->x,cid->y,cid->z, set, l); + } + LbmVec vel(ux,uy,uz); + // TODO fix... + return (vel * mLevel[cid->level].simCellSize / mLevel[cid->level].timestep * this->mDebugVelScale); // normal +} + +LbmFloat LbmFsgrSolver::getCellDf( CellIdentifierInterface* basecid,int set, int dir) { + stdCellId *cid = convertBaseCidToStdCid(basecid); + return QCELL(cid->level, cid->x,cid->y,cid->z, set, dir); +} +LbmFloat LbmFsgrSolver::getCellMass( CellIdentifierInterface* basecid,int set) { + stdCellId *cid = convertBaseCidToStdCid(basecid); + return QCELL(cid->level, cid->x,cid->y,cid->z, set, dMass); +} +LbmFloat LbmFsgrSolver::getCellFill( CellIdentifierInterface* basecid,int set) { + stdCellId *cid = convertBaseCidToStdCid(basecid); + if(RFLAG(cid->level, cid->x,cid->y,cid->z, set)&CFInter) return QCELL(cid->level, cid->x,cid->y,cid->z, set, dFfrac); + if(RFLAG(cid->level, cid->x,cid->y,cid->z, set)&CFFluid) return 1.0; + return 0.0; + //return QCELL(cid->level, cid->x,cid->y,cid->z, set, dFfrac); +} +CellFlagType LbmFsgrSolver::getCellFlag( CellIdentifierInterface* basecid,int set) { + stdCellId *cid = convertBaseCidToStdCid(basecid); + return RFLAG(cid->level, cid->x,cid->y,cid->z, set); +} + +LbmFloat LbmFsgrSolver::getEquilDf( int l ) { + return this->dfEquil[l]; +} + + +ntlVec3Gfx LbmFsgrSolver::getVelocityAt (float xp, float yp, float zp) { + ntlVec3Gfx avgvel(0.0); + LbmFloat avgnum = 0.; + + // taken from getCellAt! + const int level = mMaxRefine; + const int workSet = mLevel[level].setCurr; + const LbmFloat nsize = mLevel[level].nodeSize; + const int x = (int)((-this->mvGeoStart[0]+xp-0.5*nsize) / nsize ); + const int y = (int)((-this->mvGeoStart[1]+yp-0.5*nsize) / nsize ); + int z = (int)((-this->mvGeoStart[2]+zp-0.5*nsize) / nsize ); + if(LBMDIM==2) z=0; + //errMsg("DUMPVEL","p"<dfVecX[l]; + const int j = y+this->dfVecY[l]; + const int k = z+this->dfVecZ[l]; + + if( (i<0) || (j<0) || (k<0) + || (i>=mLevel[level].lSizex) + || (j>=mLevel[level].lSizey) + || (k>=mLevel[level].lSizez) ) continue; + + if( (RFLAG(level, i,j,k, mLevel[level].setCurr)&(CFFluid|CFInter)) ) { + ntlVec3Gfx vel(0.0); + LbmFloat *ccel = RACPNT(level, i,j,k ,workSet); // omp + for(int n=1; ncDfNum; n++) { + vel[0] += (this->dfDvecX[n]*RAC(ccel,n)); + vel[1] += (this->dfDvecY[n]*RAC(ccel,n)); + vel[2] += (this->dfDvecZ[n]*RAC(ccel,n)); + } + + avgvel += vel; + avgnum += 1.0; + if(l==0) { // center slightly more weight + avgvel += vel; avgnum += 1.0; + } + } // */ + } + + if(avgnum>0.) { + ntlVec3Gfx retv = avgvel / avgnum; + retv *= nsize/mLevel[level].timestep; + // scale for current animation settings (frame time) + retv *= mpParam->getCurrentAniFrameTime(); + //errMsg("DUMPVEL","t"<getCurrentAniFrameTime() ); + return retv; + } + // no cells here...? + //errMsg("DUMPVEL"," at "<( set, this ); + lbmDebugDisplay( set ); +} +#endif + +/*****************************************************************************/ +// strict debugging functions +/*****************************************************************************/ +#if FSGR_STRICT_DEBUG==1 +#define STRICT_EXIT *((int *)0)=0; + +int LbmFsgrSolver::debLBMGI(int level, int ii,int ij,int ik, int is) { + if(level < 0){ errMsg("LbmStrict::debLBMGI"," invLev- l"< mMaxRefine){ errMsg("LbmStrict::debLBMGI"," invLev+ l"<mLevel[level].lSizex-1){ errMsg("LbmStrict"," invX+ l"<mLevel[level].lSizey-1){ errMsg("LbmStrict"," invY+ l"<mLevel[level].lSizez-1){ errMsg("LbmStrict"," invZ+ l"<1){ errMsg("LbmStrict"," invS+ l"<this->cDirNum){ errMsg("LbmStrict"," invD+ l"<this->cDirNum){ errMsg("LbmStrict"," invD+ l"< mMaxRefine){ errMsg("LbmStrict::debLBMQI"," invLev+ l"<mLevel[level].lSizex-1){ errMsg("LbmStrict"," invX+ l"<mLevel[level].lSizey-1){ errMsg("LbmStrict"," invY+ l"<mLevel[level].lSizez-1){ errMsg("LbmStrict"," invZ+ l"<1){ errMsg("LbmStrict"," invS+ l"<this->cDfNum){ // dFfrac is an exception + if((l != dMass) && (l != dFfrac) && (l != dFlux)){ errMsg("LbmStrict"," invD+ "<<" l"<mInitDone) && (is!=mLevel[level].setCurr)){ STRICT_EXIT; } // COMPRT debug +#endif // COMPRESSGRIDS==1 + return _LBMQI(level, ii,ij,ik, is, l); +}; + +LbmFloat& LbmFsgrSolver::debQCELL(int level, int xx,int yy,int zz,int set,int l) { + //errMsg("LbmStrict","debQCELL debug: l"<this->cDfNum){ errMsg("LbmStrict"," invD+ l"<this->cDfNum){ errMsg("LbmStrict"," invD+ l"<dTotalNum){ errMsg("LbmStrict"," invD+ "<<" l"<this->cDfNum){ // dFfrac is an exception + //if((l != dMass) && (l != dFfrac) && (l != dFlux)){ errMsg("LbmStrict"," invD+ "<<" l"<getAsString() , 10); + ntlVec3Gfx org = this->getCellOrigin( cell ); + ntlVec3Gfx halfsize = this->getCellSize( cell ); + int set = this->getCellSet( cell ); + //debugOut(" DD: "<getAsString()<<" "<< (dispset->type) , 10); + + bool showcell = true; + int linewidth = 1; + ntlColor col(0.5); + LbmFloat cscale = 1.0; //dispset->scale; + +#define DRAWDISPCUBE(col,scale) \ + { glLineWidth( linewidth ); \ + glColor3f( (col)[0], (col)[1], (col)[2]); \ + ntlVec3Gfx s = org-(halfsize * (scale)); \ + ntlVec3Gfx e = org+(halfsize * (scale)); \ + drawCubeWire( s,e ); } + + CellFlagType flag = this->getCellFlag(cell, set ); + // always check types + if(flag& CFInvalid ) { if(!guiShowInvalid ) return; } + if(flag& CFUnused ) { if(!guiShowInvalid ) return; } + if(flag& CFEmpty ) { if(!guiShowEmpty ) return; } + if(flag& CFInter ) { if(!guiShowInterface) return; } + if(flag& CFNoDelete ) { if(!guiShowNoDelete ) return; } + if(flag& CFBnd ) { if(!guiShowBnd ) return; } + + // only dismiss one of these types + if(flag& CFGrFromCoarse) { if(!guiShowCoarseInner ) return; } // inner not really interesting + else + if(flag& CFGrFromFine) { if(!guiShowCoarseBorder ) return; } + else + if(flag& CFFluid ) { if(!guiShowFluid ) return; } + + switch(dispset) { + case FLUIDDISPNothing: { + showcell = false; + } break; + case FLUIDDISPCelltypes: { + cscale = 0.5; + + if(flag& CFNoDelete) { // debug, mark nodel cells + ntlColor ccol(0.7,0.0,0.0); + DRAWDISPCUBE(ccol, 0.1); + } + if(flag& CFPersistMask) { // mark persistent flags + ntlColor ccol(0.5); + DRAWDISPCUBE(ccol, 0.125); + } + if(flag& CFNoBndFluid) { // mark persistent flags + ntlColor ccol(0,0,1); + DRAWDISPCUBE(ccol, 0.075); + } + + if(flag& CFInvalid) { + cscale = 0.50; + col = ntlColor(0.0,0,0.0); + } + else if(flag& CFBnd) { + cscale = 0.59; + col = ntlColor(0.4); + } + + else if(flag& CFInter) { + cscale = 0.55; + col = ntlColor(0,1,1); + + } else if(flag& CFGrFromCoarse) { + // draw as - with marker + ntlColor col2(0.0,1.0,0.3); + DRAWDISPCUBE(col2, 0.1); + cscale = 0.5; + showcell=false; // DEBUG + } + else if(flag& CFFluid) { + cscale = 0.5; + if(flag& CFGrToFine) { + ntlColor col2(0.5,0.0,0.5); + DRAWDISPCUBE(col2, 0.1); + col = ntlColor(0,0,1); + } + if(flag& CFGrFromFine) { + ntlColor col2(1.0,1.0,0.0); + DRAWDISPCUBE(col2, 0.1); + col = ntlColor(0,0,1); + } else if(flag& CFGrFromCoarse) { + // draw as fluid with marker + ntlColor col2(0.0,1.0,0.3); + DRAWDISPCUBE(col2, 0.1); + col = ntlColor(0,0,1); + } else { + col = ntlColor(0,0,1); + } + } + else if(flag& CFEmpty) { + showcell=false; + } + + } break; + case FLUIDDISPVelocities: { + // dont use cube display + LbmVec vel = this->getCellVelocity( cell, set ); + glBegin(GL_LINES); + glColor3f( 0.0,0.0,0.0 ); + glVertex3f( org[0], org[1], org[2] ); + org += vec2G(vel * 10.0 * cscale); + glColor3f( 1.0,1.0,1.0 ); + glVertex3f( org[0], org[1], org[2] ); + glEnd(); + showcell = false; + } break; + case FLUIDDISPCellfills: { + cscale = 0.5; + if(flag& CFFluid) { + cscale = 0.75; + col = ntlColor(0,0,0.5); + } + else if(flag& CFInter) { + cscale = 0.75 * this->getCellMass(cell,set); + col = ntlColor(0,1,1); + } + else { + showcell=false; + } + + if( ABS(this->getCellMass(cell,set)) < 10.0 ) { + cscale = 0.75 * this->getCellMass(cell,set); + } else { + showcell = false; + } + if(cscale>0.0) { + col = ntlColor(0,1,1); + } else { + col = ntlColor(1,1,0); + } + // TODO + } break; + case FLUIDDISPDensity: { + LbmFloat rho = this->getCellDensity(cell,set); + cscale = rho*rho * 0.25; + col = ntlColor( MIN(0.5+cscale,1.0) , MIN(0.0+cscale,1.0), MIN(0.0+cscale,1.0) ); + cscale *= 2.0; + } break; + case FLUIDDISPGrid: { + cscale = 0.59; + col = ntlColor(1.0); + } break; + default: { + cscale = 0.5; + col = ntlColor(1.0,0.0,0.0); + } break; + } + + if(!showcell) return; + if(cscale==0.0) return; // dont draw zero values + DRAWDISPCUBE(col, cscale); +} + +//! debug display function +// D has to implement the CellIterator interface +void LbmFsgrSolver::lbmDebugDisplay(int dispset) { + // DEBUG always display testdata +#if LBM_INCLUDE_TESTSOLVERS==1 + if(mUseTestdata){ + cpDebugDisplay(dispset); + mpTest->testDebugDisplay(dispset); + } +#endif // LBM_INCLUDE_TESTSOLVERS==1 + if(dispset<=FLUIDDISPNothing) return; + //if(!dispset->on) return; + glDisable( GL_LIGHTING ); // dont light lines + +#if LBM_INCLUDE_TESTSOLVERS==1 + if((!mUseTestdata)|| (mUseTestdata)&&(mpTest->mFarfMode<=0)) { +#endif // LBM_INCLUDE_TESTSOLVERS==1 + + LbmFsgrSolver::CellIdentifier cid = this->getFirstCell(); + for(; this->noEndCell( cid ); + this->advanceCell( cid ) ) { + this->debugDisplayNode(dispset, cid ); + } + delete cid; + +#if LBM_INCLUDE_TESTSOLVERS==1 + } // 3d check +#endif // LBM_INCLUDE_TESTSOLVERS==1 + + glEnable( GL_LIGHTING ); // dont light lines +} + +//! debug display function +// D has to implement the CellIterator interface +void LbmFsgrSolver::lbmMarkedCellDisplay() { + //fluidDispSettings dispset; + // trick - display marked cells as grid displa -> white, big + int dispset = FLUIDDISPGrid; + glDisable( GL_LIGHTING ); // dont light lines + + LbmFsgrSolver::CellIdentifier cid = this->markedGetFirstCell(); + while(cid) { + this->debugDisplayNode(dispset, cid ); + cid = this->markedAdvanceCell(); + } + delete cid; + + glEnable( GL_LIGHTING ); // dont light lines +} + +#endif // LBM_USE_GUI==1 + +//! display a single node +void LbmFsgrSolver::debugPrintNodeInfo(CellIdentifierInterface* cell, int forceSet) { + //string printInfo, + // force printing of one set? default = -1 = off + bool printDF = false; + bool printRho = false; + bool printVel = false; + bool printFlag = false; + bool printGeom = false; + bool printMass=false; + bool printBothSets = false; + string printInfo = this->getNodeInfoString(); + + for(size_t i=0; igetCellOrigin( cell ); + ntlVec3Gfx halfsize = this->getCellSize( cell ); + int set = this->getCellSet( cell ); + debMsgStd("debugPrintNodeInfo",DM_NOTIFY, "Printing cell info '"<getAsString()<<" from "<getName()<<" currSet:"<=0) setmax = 1; + + for(int s=0; s=0) workset = forceSet; + debMsgStd(" ",DM_MSG, "Printing set:"<getCellDf(cell,workset,l), 1); + } + } + if(printRho) { + debMsgStd(" ",DM_MSG, " Rho: "<getCellDensity(cell,workset), 1); + } + if(printVel) { + debMsgStd(" ",DM_MSG, " Vel: "<getCellVelocity(cell,workset), 1); + } + if(printFlag) { + CellFlagType flag = this->getCellFlag(cell,workset); + debMsgStd(" ",DM_MSG, " Flg: "<< flag<<" "<getCellMass(cell,workset), 1); + } + // dirty... TODO fixme + debMsgStd(" ",DM_MSG, " Flx: "<getCellDf(cell,workset,dFlux), 1); + } +} + + diff --git a/intern/elbeem/intern/utilities.cpp b/intern/elbeem/intern/utilities.cpp new file mode 100644 index 00000000000..332052e91b6 --- /dev/null +++ b/intern/elbeem/intern/utilities.cpp @@ -0,0 +1,496 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Global C style utility funcions + * + *****************************************************************************/ + + +#include +#include +#include /* getenv(3), strtol(3) */ +#ifdef WIN32 +// for timing +#include +#else +#include +#include +#include +#endif + +#include "utilities.h" + +#ifndef NOPNG +#ifdef WIN32 +#include "png.h" +#else +#include +#endif +#endif // NOPNG +#include + +// global debug level +#ifdef DEBUG +int gDebugLevel = DEBUG; +#else // DEBUG +int gDebugLevel = 0; +#endif // DEBUG + +// global world state, acces with get/setElbeemState +int gElbeemState = SIMWORLD_INVALID; + +// access global state of elbeem simulator +void setElbeemState(int set) { + gElbeemState = set; +} +int getElbeemState(void) { + return gElbeemState; +} +int isSimworldOk(void) { + return (getElbeemState>=0); +} + +// last error as string, acces with get/setElbeemErrorString +char gElbeemErrorString[256] = {'-','\0' }; + +// access elbeem simulator error string +void setElbeemErrorString(const char* set) { + strncpy(gElbeemErrorString, set, 256); +} +char* getElbeemErrorString(void) { return gElbeemErrorString; } + + +//! for interval debugging output +myTime_t globalIntervalTime = 0; +//! color output setting for messages (0==off, else on) +#ifdef WIN32 +// switch off first call +#define DEF_globalColorSetting -1 +#else // WIN32 +// linux etc., on by default +#define DEF_globalColorSetting 1 +#endif // WIN32 +int globalColorSetting = DEF_globalColorSetting; // linux etc., on by default +int globalFirstEnvCheck = 0; +void resetGlobalColorSetting() { globalColorSetting = DEF_globalColorSetting; } + +// global string for formatting vector output, TODO test!? +const char *globVecFormatStr = "V[%f,%f,%f]"; + + +// global mp on/off switch +bool glob_mpactive = false; +// global access to mpi index, for debugging (e.g. in utilities.cpp) +int glob_mpnum = -1; +int glob_mpindex = -1; +int glob_mppn = -1; + + +//----------------------------------------------------------------------------- +// helper function that converts a string to integer, +// and returns an alternative value if the conversion fails +int convertString2Int(const char *str, int alt) +{ + int val; + char *endptr; + bool success=true; + + val = strtol(str, &endptr, 10); + if( (str==endptr) || + ((str!=endptr) && (*endptr != '\0')) ) success = false; + + if(!success) { + return alt; + } + return val; +} + +//----------------------------------------------------------------------------- +//! helper function that converts a flag field to a readable integer +string convertFlags2String(int flags) { + std::ostringstream ret; + ret <<"("; + int max = sizeof(int)*8; + for(int i=0; i4) && (filentemp[filentemp.length()-4]=='.')) { + filentemp[filentemp.length()-4] = '\0'; + } + std::ostringstream filennew; + filennew << filentemp.c_str(); + filennew << ".ppm.gz"; + + gzf = gzopen(filennew.str().c_str(), "wb9"); + if(!gzf) goto fail; + + gzprintf(gzf,"P6\n%d %d\n255\n",w,h); + // output binary pixels + for(int j=0;j0) { + ret << ms<<"m"<< ss<<"s" ; + } else { + if(ps>0) { + ret << ss<<"."; + if(ps<10) { ret <<"0"; } + ret <e[0]) || + (s[1]>e[1]) || + (s[2]>e[2]) ) { + errFatal("checkBoundingBox","Check by '"<0) { + myTime_t currTime = getTime(); + if((currTime - globalIntervalTime)>interval) { + globalIntervalTime = getTime(); + } else { + return; + } + } + + // colors off? + if( (globalColorSetting == -1) || // off for e.g. win32 + ((globalColorSetting==1) && ((id==DM_FATAL)||( getenv("ELBEEM_NOCOLOROUT") )) ) + ) { + // only reset once + col_std = col_black = col_dark_gray = col_bright_gray = + col_red = col_bright_red = col_green = + col_bright_green = col_bright_yellow = + col_yellow = col_cyan = col_bright_cyan = + col_purple = col_bright_purple = col_neutral = ""; + globalColorSetting = 0; + } + + std::ostringstream sout; + if(id==DM_DIRECT) { + sout << msg; + } else { + sout << col_cyan<< from; + switch(id) { + case DM_MSG: + sout << col_std << " message:"; + break; + case DM_NOTIFY: + sout << col_bright_cyan << " note:" << col_std; + break; + case DM_IMPORTANT: + sout << col_yellow << " important:" << col_std; + break; + case DM_WARNING: + sout << col_bright_red << " warning:" << col_std; + break; + case DM_ERROR: + sout << col_red << " error:" << col_red; + break; + case DM_FATAL: + sout << col_red << " fatal("<=0) { + mpin << "elbeem_log_"<< glob_mpindex <<".txt"; + } else { + mpin << "elbeem_log_ini.txt"; + } + fileout = 1; + strncpy(filen, mpin.str().c_str(),255); filen[255]='\0'; +#else + strncpy(filen, "elbeem_debug_log.txt",255); +#endif + +#ifdef WIN32 + // windows causes trouble with direct output + fileout = 1; +#endif // WIN32 + +#if PARALLEL==1 + fileout = 2;// buffer out, switch off again... + if(globOutstrForce) fileout=1; +#endif + if(getenv("ELBEEM_FORCESTDOUT")) { + fileout = 0;// always direct out + } + //fprintf(stdout,"out deb %d, %d, '%s',l%d \n",globOutstrForce,fileout, filen, globOutstr.str().size() ); + +#if PARALLEL==1 +#pragma omp critical +#endif // PARALLEL==1 + { + if(fileout==1) { + // debug level is >0 anyway, so write to file... + FILE *logf = fopen(filen,"a+"); + // dont complain anymore here... + if(logf) { + if(globOutstrForce) { + fprintf(logf, "%s",globOutstr.str().c_str() ); + globOutstr.str(""); // reset + } + fprintf(logf, "%s",sout.str().c_str() ); + fclose(logf); + } + } else if(fileout==2) { + globOutstr << sout.str(); + } else { + // normal stdout output + fprintf(stdout, "%s",sout.str().c_str() ); + if(id!=DM_DIRECT) fflush(stdout); + } + } // omp crit +} + +// helper functions from external program using elbeem lib (e.g. Blender) +/* set gDebugLevel according to env. var */ +extern "C" +void elbeemCheckDebugEnv(void) { + const char *strEnvName = "BLENDER_ELBEEMDEBUG"; + const char *strEnvName2 = "ELBEEM_DEBUGLEVEL"; + if(globalFirstEnvCheck) return; + + if(getenv(strEnvName)) { + gDebugLevel = atoi(getenv(strEnvName)); + if(gDebugLevel>0) debMsgStd("performElbeemSimulation",DM_NOTIFY,"Using envvar '"<0) debMsgStd("performElbeemSimulation",DM_NOTIFY,"Using envvar '"<10) gDebugLevel = 0; // only use valid values + globalFirstEnvCheck = 1; +} + +/* elbeem debug output function */ +extern "C" +void elbeemDebugOut(char *msg) { + elbeemCheckDebugEnv(); + // external messages default to debug level 5... + if(gDebugLevel<5) return; + // delegate to messageOutputFunc + messageOutputFunc("[External]",DM_MSG,msg,0); +} + +/* set elbeem debug output level (0=off to 10=full on) */ +extern "C" +void elbeemSetDebugLevel(int level) { + if(level<0) level=0; + if(level>10) level=10; + gDebugLevel=level; +} + + +/* estimate how much memory a given setup will require */ +#include "solver_interface.h" + +extern "C" +double elbeemEstimateMemreq(int res, + float sx, float sy, float sz, + int refine, char *retstr) { + int resx = res, resy = res, resz = res; + // dont use real coords, just place from 0.0 to sizeXYZ + ntlVec3Gfx vgs(0.0), vge(sx,sy,sz); + initGridSizes( resx,resy,resz, vgs,vge, refine, 0); + + double memreq = -1.0; + string memreqStr(""); + // ignore farfield for now... + calculateMemreqEstimate(resx,resy,resz, refine, 0., &memreq, &memreqStr ); + + if(retstr) { + // copy at max. 32 characters + strncpy(retstr, memreqStr.c_str(), 32 ); + retstr[31] = '\0'; + } + return memreq; +} + + + diff --git a/intern/elbeem/intern/utilities.h b/intern/elbeem/intern/utilities.h new file mode 100644 index 00000000000..0f65408d23c --- /dev/null +++ b/intern/elbeem/intern/utilities.h @@ -0,0 +1,204 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Global C style utility funcions + * + *****************************************************************************/ +#ifndef UTILITIES_H +#include "ntl_vector3dim.h" + +// Solaris requires ieeefp.h for finite(3C) +#if !defined(linux) && defined(sun) +#include +#endif + + +/* debugging outputs , debug level 0 (off) to 10 (max) */ +#ifdef ELBEEM_PLUGIN +#define DEBUG 0 +#else // ELBEEM_PLUGIN +#define DEBUG 10 +#endif // ELBEEM_PLUGIN +extern "C" int gDebugLevel; + + +// time measurements +typedef unsigned long myTime_t; + + +// state of the simulation world +// default +#define SIMWORLD_INVALID 0 +// performing init +#define SIMWORLD_INITIALIZING 1 +// after init, before starting simulation +#define SIMWORLD_INITED 2 +// stop of the simulation run, can be continued later +#define SIMWORLD_STOP 3 +// error during init +#define SIMWORLD_INITERROR -1 +// error during simulation +#define SIMWORLD_PANIC -2 +// general error +#define SIMWORLD_GENERICERROR -3 + +// access global state of elbeem simulator +void setElbeemState(int set); +int getElbeemState(void); +int isSimworldOk(void); + +// access elbeem simulator error string +void setElbeemErrorString(const char* set); +char* getElbeemErrorString(void); + + +/* debug output function */ +#define DM_MSG 1 +#define DM_NOTIFY 2 +#define DM_IMPORTANT 3 +#define DM_WARNING 4 +#define DM_ERROR 5 +#define DM_DIRECT 6 +#define DM_FATAL 7 +void messageOutputFunc(string from, int id, string msg, myTime_t interval); + +/* debugging messages defines */ +#ifdef DEBUG +#if LBM_PRECISION==2 +#define MSGSTREAM std::ostringstream msg; msg.precision(15); msg.width(17); +#else +#define MSGSTREAM std::ostringstream msg; msg.precision(7); msg.width(9); +#endif + +# define debMsgDirect(mStr) if(gDebugLevel>0) { std::ostringstream msg; msg << mStr; messageOutputFunc(string(""), DM_DIRECT, msg.str(), 0); } +# define debMsgStd(from,id,mStr,level) if(gDebugLevel>=level) { MSGSTREAM; msg << mStr <<"\n"; messageOutputFunc(from, id, msg.str(), 0); } +# define debMsgNnl(from,id,mStr,level) if(gDebugLevel>=level) { MSGSTREAM; msg << mStr ; messageOutputFunc(from, id, msg.str(), 0); } +# define debMsgInter(from,id,mStr,level, interval) if(gDebugLevel>=level) { MSGSTREAM; msg << mStr <<"\n"; messageOutputFunc(from, id, msg.str(), interval); } +# define debugOut(mStr,level) if(gDebugLevel>=level) { debMsgStd("D",DM_MSG,mStr,level); } +# define debugOutNnl(mStr,level) if(gDebugLevel>=level) { debMsgNnl("D",DM_MSG,mStr,level); } +# define debugOutInter(mStr,level, interval) debMsgInter("D",DM_MSG ,mStr,level, interval); +/* Error output function */ +#define errMsg(from,mStr) if(gDebugLevel>0){ MSGSTREAM; msg << mStr <<"\n"; messageOutputFunc(from, DM_ERROR, msg.str(), 0); } +#define warnMsg(from,mStr) if(gDebugLevel>0){ MSGSTREAM; msg << mStr <<"\n"; messageOutputFunc(from, DM_WARNING, msg.str(), 0); } + +#else +// no messages at all... +# define debMsgDirect(mStr) +# define debMsgStd(from,id,mStr,level) +# define debMsgNnl(from,id,mStr,level) +# define debMsgInter(from,id,mStr,level, interval) +# define debugOut(mStr,level) +# define debugOutNnl(mStr,level) +# define debugOutInter(mStr,level, interval) +# define errMsg(from,mStr) +# define warnMsg(from,mStr) +#endif + +#define errorOut(mStr) { errMsg("D",mStr); } + +// fatal errors - have to be handled +#define errFatal(from,mStr,errCode) { \ + setElbeemState(errCode); \ + MSGSTREAM; msg << mStr; \ + messageOutputFunc(from, DM_FATAL, msg.str(), 0); \ +} + + +//! helper function that converts a string to integer +int convertString2Int(const char *str, int alt); + +//! helper function that converts a flag field to a readable integer +string convertFlags2String(int flags); + +//! get the current system time +myTime_t getTime(); +//! convert time to readable string +string getTimeString(myTime_t usecs); + +//! helper to check if a bounding box was specified in the right way +bool checkBoundingBox(ntlVec3Gfx s, ntlVec3Gfx e, string checker); + +//! reset color output for elbeem init +void resetGlobalColorSetting(); + + +/*! print some vector from 3 values e.g. for ux,uy,uz */ +#define PRINT_VEC(x,y,z) " ["<<(x)<<","<<(y)<<","<<(z)<<"] " + +/*! print some vector from 3 values e.g. for ux,uy,uz */ +#define PRINT_VEC2D(x,y) " ["<<(x)<<","<<(y)<<"] " + +/*! print l'th neighbor of i,j,k as a vector, as we need ijk all the time */ +#define PRINT_IJK_NBL PRINT_VEC(i+D::dfVecX[l],j+D::dfVecY[l],k+D::dfVecZ[l]) + +/*! print i,j,k as a vector, as we need ijk all the time */ +#define PRINT_IJK PRINT_VEC(i,j,k) + +/*! print i,j,k as a vector, as we need ijk all the time */ +#define PRINT_IJ PRINT_VEC2D(i,j) + +/*! print some vector from 3 values e.g. for ux,uy,uz */ +#define PRINT_NTLVEC(v) " ["<<(v)[0]<<","<<(v)[1]<<","<<(v)[2]<<"] " + +/*! print some vector from 3 values e.g. for ux,uy,uz */ +#define PRINT_NTLVEC2D(v) " ["<<(v)[0]<<","<<(v)[1]<<"] " + +/*! print a triangle */ +#define PRINT_TRIANGLE(t,mpV) " { "< +inline T +MIN( T a, T b ) +{ return (a < b) ? a : b ; } + +/* maximum */ +template < class T > +inline T +MAX( T a, T b ) +{ return (a < b) ? b : a ; } + +/* absolute value */ +template < class T > +inline T +ABS( T a ) +{ return (0 < a) ? a : -a ; } + +/* sign of the value */ +template < class T > +inline T +SIGNUM( T a ) +{ return (0 < a) ? 1 : -1 ; } + +/* sign, returns -1,0,1 depending on sign/value=0 */ +template < class T > +inline T +SIGNUM0( T a ) +{ return (0 < a) ? 1 : ( a < 0 ? -1 : 0 ) ; } + +/* round to nearest integer */ +inline int +ROUND(double d) +{ return int(d + 0.5); } + +/* square function */ +template < class T > +inline T +SQUARE( T a ) +{ return a*a; } + + +#define UTILITIES_H +#endif diff --git a/intern/elbeem/make/msvc_6_0/elbeem.dsp b/intern/elbeem/make/msvc_6_0/elbeem.dsp new file mode 100644 index 00000000000..ef5daa29fa4 --- /dev/null +++ b/intern/elbeem/make/msvc_6_0/elbeem.dsp @@ -0,0 +1,290 @@ +# Microsoft Developer Studio Project File - Name="elbeem" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=elbeem - 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 "elbeem.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 "elbeem.mak" CFG="elbeem - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "elbeem - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "elbeem - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "elbeem - 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 "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /I "../../../../../lib/windows/sdl/include" /I "../../../../../lib/windows/zlib/include" /I "../../../../../lib/windows/png/include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "NOGUI" /D "ELBEEM_BLENDER" /YX /FD /c +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"Release\blender_elbeem.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO copy to lib ... xcopy /Y .\release\blender_elbeem.lib ..\..\..\..\..\lib\windows\elbeem\lib\*.* +# End Special Build Tool + +!ELSEIF "$(CFG)" == "elbeem - 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 "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../../../../lib/windows/sdl/include" /I "../../../../../lib/windows/zlib/include" /I "../../../../../lib/windows/png/include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "NOGUI" /D "ELBEEM_BLENDER" /YX /FD /GZ /c +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"Debug\blender_elbeem.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO copy to lib ... xcopy /Y .\debug\blender_elbeem.lib ..\..\..\..\..\lib\windows\elbeem\lib\debug\*.* +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "elbeem - Win32 Release" +# Name "elbeem - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\intern\attributes.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\elbeem.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\isosurface.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_blenderdumper.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_bsptree.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_geometrymodel.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_geometryobject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_lighting.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_ray.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_world.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\parametrizer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\particletracer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\simulation_object.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\solver_adap.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\solver_init.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\solver_interface.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\solver_main.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\solver_util.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\utilities.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\intern\attributes.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\isosurface.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\mcubes_tables.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_blenderdumper.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_bsptree.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_geometryclass.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_geometrymodel.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_geometryobject.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_geometryshader.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_lighting.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_lightobject.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_material.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_matrices.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_ray.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_renderglobals.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_rndstream.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_scene.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_triangle.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_vector3dim.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_world.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\parametrizer.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\particletracer.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\simulation_object.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\solver_class.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\solver_dimenions.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\solver_interface.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\solver_relax.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\utilities.h +# End Source File +# End Group +# End Target +# End Project diff --git a/intern/elbeem/make/msvc_7_0/elbeem.vcproj b/intern/elbeem/make/msvc_7_0/elbeem.vcproj new file mode 100644 index 00000000000..9de4482e2fd --- /dev/null +++ b/intern/elbeem/make/msvc_7_0/elbeem.vcproj @@ -0,0 +1,367 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt new file mode 100644 index 00000000000..1e1380df9a3 --- /dev/null +++ b/intern/ghost/CMakeLists.txt @@ -0,0 +1,60 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC . ../string ${WINTAB_INC}) + +FILE(GLOB SRC intern/*.cpp) + +IF(APPLE) + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_DisplayManagerWin32.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_SystemWin32.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_WindowWin32.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_DisplayManagerX11.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_SystemX11.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_WindowX11.cpp") +ELSE(APPLE) + IF(WIN32) + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_DisplayManagerCarbon.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_SystemCarbon.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_WindowCarbon.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_DisplayManagerX11.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_SystemX11.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_WindowX11.cpp") + ELSE(WIN32) + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_DisplayManagerWin32.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_SystemWin32.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_WindowWin32.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_DisplayManagerCarbon.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_SystemCarbon.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_WindowCarbon.cpp") + ENDIF(WIN32) +ENDIF(APPLE) + +BLENDERLIB(bf_ghost "${SRC}" "${INC}") +#, libtype=['core','player'], priority = [25,15] ) diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h new file mode 100644 index 00000000000..4c4094409dd --- /dev/null +++ b/intern/ghost/GHOST_C-api.h @@ -0,0 +1,765 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_C-api.h + * GHOST C-API function and type declarations. + * The C-API wraps the C++ objects with the + */ + +#ifndef GHOST_C_API_H +#define GHOST_C_API_H + +#include "GHOST_Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Creates a "handle" for a C++ GHOST object. + * A handle is just an opaque pointer to an empty struct. + * In the API the pointer is casted to the actual C++ class. + * @param name Name of the handle to create. + */ +#define GHOST_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name + +GHOST_DECLARE_HANDLE(GHOST_SystemHandle); +GHOST_DECLARE_HANDLE(GHOST_TimerTaskHandle); +GHOST_DECLARE_HANDLE(GHOST_WindowHandle); +GHOST_DECLARE_HANDLE(GHOST_EventHandle); +GHOST_DECLARE_HANDLE(GHOST_RectangleHandle); +GHOST_DECLARE_HANDLE(GHOST_EventConsumerHandle); + + +/** + * Definition of a callback routine that receives events. + * @param event The event received. + * @param userdata The callback's user data, supplied to GHOST_CreateSystem. + */ +typedef int (*GHOST_EventCallbackProcPtr)(GHOST_EventHandle event, GHOST_TUserDataPtr userdata); + + +/** + * Creates the one and only system. + * @return a handle to the system. + */ +extern GHOST_SystemHandle GHOST_CreateSystem(void); + +/** + * Disposes the one and only system. + * @param systemhandle The handle to the system + * @return An indication of success. + */ +extern GHOST_TSuccess GHOST_DisposeSystem(GHOST_SystemHandle systemhandle); + + +/** + * Creates an event consumer object + * @param eventCallback The event callback routine. + * @param userdata Pointer to user data returned to the callback routine. + */ +extern GHOST_EventConsumerHandle GHOST_CreateEventConsumer(GHOST_EventCallbackProcPtr eventCallback, GHOST_TUserDataPtr userdata); + +/** + * Disposes an event consumer object + * @param consumerhandle Handle to the event consumer. + * @return An indication of success. + */ +extern GHOST_TSuccess GHOST_DisposeEventConsumer(GHOST_EventConsumerHandle consumerhandle); + + +/** + * Returns the system time. + * Returns the number of milliseconds since the start of the system process. + * Based on ANSI clock() routine. + * @param systemhandle The handle to the system + * @return The number of milliseconds. + */ +extern GHOST_TUns64 GHOST_GetMilliSeconds(GHOST_SystemHandle systemhandle); + +/** + * Installs a timer. + * Note that, on most operating systems, messages need to be processed in order + * for the timer callbacks to be invoked. + * @param systemhandle The handle to the system + * @param delay The time to wait for the first call to the timerProc (in milliseconds) + * @param interval The interval between calls to the timerProc (in milliseconds) + * @param timerProc The callback invoked when the interval expires, + * @param userData Placeholder for user data. + * @return A timer task (0 if timer task installation failed). + */ +extern GHOST_TimerTaskHandle GHOST_InstallTimer(GHOST_SystemHandle systemhandle, + GHOST_TUns64 delay, + GHOST_TUns64 interval, + GHOST_TimerProcPtr timerProc, + GHOST_TUserDataPtr userData); + +/** + * Removes a timer. + * @param systemhandle The handle to the system + * @param timerTask Timer task to be removed. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_RemoveTimer(GHOST_SystemHandle systemhandle, + GHOST_TimerTaskHandle timertaskhandle); + +/*************************************************************************************** + ** Display/window management functionality + ***************************************************************************************/ + +/** + * Returns the number of displays on this system. + * @param systemhandle The handle to the system + * @return The number of displays. + */ +extern GHOST_TUns8 GHOST_GetNumDisplays(GHOST_SystemHandle systemhandle); + +/** + * Returns the dimensions of the main display on this system. + * @param systemhandle The handle to the system + * @param width A pointer the width gets put in + * @param height A pointer the height gets put in + * @return void. + */ +extern void GHOST_GetMainDisplayDimensions(GHOST_SystemHandle systemhandle, + GHOST_TUns32* width, + GHOST_TUns32* height); + +/** + * Create a new window. + * The new window is added to the list of windows managed. + * Never explicitly delete the window, use disposeWindow() instead. + * @param systemhandle The handle to the system + * @param title The name of the window (displayed in the title bar of the window if the OS supports it). + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state of the window when opened. + * @param type The type of drawing context installed in this window. + * @return A handle to the new window ( == NULL if creation failed). + */ +extern GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle, + char* title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const int stereoVisual); + +/** + * Returns the window user data. + * @param windowhandle The handle to the window + * @return The window user data. + */ +extern GHOST_TUserDataPtr GHOST_GetWindowUserData(GHOST_WindowHandle windowhandle); + +/** + * Changes the window user data. + * @param windowhandle The handle to the window + * @param data The window user data. + */ +extern void GHOST_SetWindowUserData(GHOST_WindowHandle windowhandle, + GHOST_TUserDataPtr userdata); + +/** + * Dispose a window. + * @param systemhandle The handle to the system + * @param window Handle to the window to be disposed. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_DisposeWindow(GHOST_SystemHandle systemhandle, + GHOST_WindowHandle windowhandle); + +/** + * Returns whether a window is valid. + * @param systemhandle The handle to the system + * @param window Handle to the window to be checked. + * @return Indication of validity. + */ +extern int GHOST_ValidWindow(GHOST_SystemHandle systemhandle, + GHOST_WindowHandle windowhandle); + +/** + * Begins full screen mode. + * @param systemhandle The handle to the system + * @param setting The new setting of the display. + * @return A handle to the window displayed in full screen. + * This window is invalid after full screen has been ended. + */ +extern GHOST_WindowHandle GHOST_BeginFullScreen(GHOST_SystemHandle systemhandle, + GHOST_DisplaySetting* setting, + const int stereoVisual); + +/** + * Ends full screen mode. + * @param systemhandle The handle to the system + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_EndFullScreen(GHOST_SystemHandle systemhandle); + +/** + * Returns current full screen mode status. + * @param systemhandle The handle to the system + * @return The current status. + */ +extern int GHOST_GetFullScreen(GHOST_SystemHandle systemhandle); + +/*************************************************************************************** + ** Event management functionality + ***************************************************************************************/ + +/** + * Retrieves events from the system and stores them in the queue. + * @param systemhandle The handle to the system + * @param waitForEvent Boolean to indicate that ProcessEvents should + * wait (block) until the next event before returning. + * @return Indication of the presence of events. + */ +extern int GHOST_ProcessEvents(GHOST_SystemHandle systemhandle, int waitForEvent); + +/** + * Retrieves events from the queue and send them to the event consumers. + * @param systemhandle The handle to the system + * @return Indication of the presence of events. + */ +extern int GHOST_DispatchEvents(GHOST_SystemHandle systemhandle); + +/** + * Adds the given event consumer to our list. + * @param systemhandle The handle to the system + * @param consumerhandle The event consumer to add. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_AddEventConsumer(GHOST_SystemHandle systemhandle, + GHOST_EventConsumerHandle consumerhandle); + + + +/*************************************************************************************** + ** Cursor management functionality + ***************************************************************************************/ + +/** + * Returns the current cursor shape. + * @param windowhandle The handle to the window + * @return The current cursor shape. + */ +extern GHOST_TStandardCursor GHOST_GetCursorShape(GHOST_WindowHandle windowhandle); + +/** + * Set the shape of the cursor. + * @param windowhandle The handle to the window + * @param cursor The new cursor shape type id. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetCursorShape(GHOST_WindowHandle windowhandle, + GHOST_TStandardCursor cursorshape); + +/** + * Set the shape of the cursor to a custom cursor. + * @param windowhandle The handle to the window + * @param bitmap The bitmap data for the cursor. + * @param mask The mask data for the cursor. + * @param hotX The X coordinate of the cursor hotspot. + * @param hotY The Y coordinate of the cursor hotspot. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetCustomCursorShape(GHOST_WindowHandle windowhandle, + GHOST_TUns8 bitmap[16][2], + GHOST_TUns8 mask[16][2], + int hotX, + int hotY); +/** + * Set the shape of the cursor to a custom cursor of specified size. + * @param windowhandle The handle to the window + * @param bitmap The bitmap data for the cursor. + * @param mask The mask data for the cursor. + * @parm sizex, sizey The size of the cursor + * @param hotX The X coordinate of the cursor hotspot. + * @param hotY The Y coordinate of the cursor hotspot. + * @param fg_color, bg_color Colors of the cursor + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetCustomCursorShapeEx(GHOST_WindowHandle windowhandle, + GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, int sizey, + int hotX, int hotY, + int fg_color, int bg_color ); + +/** + * Returns the visibility state of the cursor. + * @param windowhandle The handle to the window + * @return The visibility state of the cursor. + */ +extern int GHOST_GetCursorVisibility(GHOST_WindowHandle windowhandle); + +/** + * Shows or hides the cursor. + * @param windowhandle The handle to the window + * @param visible The new visibility state of the cursor. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetCursorVisibility(GHOST_WindowHandle windowhandle, + int visible); + +/** + * Returns the current location of the cursor (location in screen coordinates) + * @param systemhandle The handle to the system + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_GetCursorPosition(GHOST_SystemHandle systemhandle, + GHOST_TInt32* x, + GHOST_TInt32* y); + +/** + * Updates the location of the cursor (location in screen coordinates). + * Not all operating systems allow the cursor to be moved (without the input device being moved). + * @param systemhandle The handle to the system + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle, + GHOST_TInt32 x, + GHOST_TInt32 y); + +/*************************************************************************************** + ** Access to mouse button and keyboard states. + ***************************************************************************************/ + +/** + * Returns the state of a modifier key (ouside the message queue). + * @param systemhandle The handle to the system + * @param mask The modifier key state to retrieve. + * @param isDown Pointer to return modifier state in. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_GetModifierKeyState(GHOST_SystemHandle systemhandle, + GHOST_TModifierKeyMask mask, + int* isDown); + +/** + * Returns the state of a mouse button (ouside the message queue). + * @param systemhandle The handle to the system + * @param mask The button state to retrieve. + * @param isDown Pointer to return button state in. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_GetButtonState(GHOST_SystemHandle systemhandle, + GHOST_TButtonMask mask, + int* isDown); + +/** + * Returns the event type. + * @param eventhandle The handle to the event + * @return The event type. + */ +extern GHOST_TEventType GHOST_GetEventType(GHOST_EventHandle eventhandle); + +/** + * Returns the time this event was generated. + * @param eventhandle The handle to the event + * @return The event generation time. + */ +extern GHOST_TUns64 GHOST_GetEventTime(GHOST_EventHandle eventhandle); + +/** + * Returns the window this event was generated on, + * or NULL if it is a 'system' event. + * @param eventhandle The handle to the event + * @return The generating window. + */ +extern GHOST_WindowHandle GHOST_GetEventWindow(GHOST_EventHandle eventhandle); + +/** + * Returns the event data. + * @param eventhandle The handle to the event + * @return The event data. + */ +extern GHOST_TEventDataPtr GHOST_GetEventData(GHOST_EventHandle eventhandle); + +/** + * Returns the timer callback. + * @param timertaskhandle The handle to the timertask + * @return The timer callback. + */ +extern GHOST_TimerProcPtr GHOST_GetTimerProc(GHOST_TimerTaskHandle timertaskhandle); + +/** + * Changes the timer callback. + * @param timertaskhandle The handle to the timertask + * @param timerProc The timer callback. + */ +extern void GHOST_SetTimerProc(GHOST_TimerTaskHandle timertaskhandle, + GHOST_TimerProcPtr timerProc); + +/** + * Returns the timer user data. + * @param timertaskhandle The handle to the timertask + * @return The timer user data. + */ +extern GHOST_TUserDataPtr GHOST_GetTimerTaskUserData(GHOST_TimerTaskHandle timertaskhandle); + +/** + * Changes the time user data. + * @param timertaskhandle The handle to the timertask + * @param data The timer user data. + */ +extern void GHOST_SetTimerTaskUserData(GHOST_TimerTaskHandle timertaskhandle, + GHOST_TUserDataPtr userData); + +/** + * Returns indication as to whether the window is valid. + * @param windowhandle The handle to the window + * @return The validity of the window. + */ +extern int GHOST_GetValid(GHOST_WindowHandle windowhandle) ; + +/** + * Returns the type of drawing context used in this window. + * @param windowhandle The handle to the window + * @return The current type of drawing context. + */ +extern GHOST_TDrawingContextType GHOST_GetDrawingContextType(GHOST_WindowHandle windowhandle); + +/** + * Tries to install a rendering context in this window. + * @param windowhandle The handle to the window + * @param type The type of rendering context installed. + * @return Indication as to whether installation has succeeded. + */ +extern GHOST_TSuccess GHOST_SetDrawingContextType(GHOST_WindowHandle windowhandle, + GHOST_TDrawingContextType type); + +/** + * Sets the title displayed in the title bar. + * @param windowhandle The handle to the window + * @param title The title to display in the title bar. + */ +extern void GHOST_SetTitle(GHOST_WindowHandle windowhandle, + char* title); + +/** + * Returns the title displayed in the title bar. The title + * should be free'd with free(). + * + * @param windowhandle The handle to the window + * @return The title, free with free(). + */ +extern char* GHOST_GetTitle(GHOST_WindowHandle windowhandle); + +/** + * Returns the window rectangle dimensions. + * These are screen coordinates. + * @param windowhandle The handle to the window + * @return A handle to the bounding rectangle of the window. + */ +extern GHOST_RectangleHandle GHOST_GetWindowBounds(GHOST_WindowHandle windowhandle); + +/** + * Returns the client rectangle dimensions. + * The left and top members of the rectangle are always zero. + * @param windowhandle The handle to the window + * @return A handle to the bounding rectangle of the window. + */ +extern GHOST_RectangleHandle GHOST_GetClientBounds(GHOST_WindowHandle windowhandle); + +/** + * Disposes a rectangle object + * @param rectanglehandle Handle to the rectangle. + */ +void GHOST_DisposeRectangle(GHOST_RectangleHandle rectanglehandle); + +/** + * Resizes client rectangle width. + * @param windowhandle The handle to the window + * @param width The new width of the client area of the window. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetClientWidth(GHOST_WindowHandle windowhandle, + GHOST_TUns32 width); + +/** + * Resizes client rectangle height. + * @param windowhandle The handle to the window + * @param height The new height of the client area of the window. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetClientHeight(GHOST_WindowHandle windowhandle, + GHOST_TUns32 height); + +/** + * Resizes client rectangle. + * @param windowhandle The handle to the window + * @param width The new width of the client area of the window. + * @param height The new height of the client area of the window. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetClientSize(GHOST_WindowHandle windowhandle, + GHOST_TUns32 width, + GHOST_TUns32 height); + +/** + * Converts a point in screen coordinates to client rectangle coordinates + * @param windowhandle The handle to the window + * @param inX The x-coordinate on the screen. + * @param inY The y-coordinate on the screen. + * @param outX The x-coordinate in the client rectangle. + * @param outY The y-coordinate in the client rectangle. + */ +extern void GHOST_ScreenToClient(GHOST_WindowHandle windowhandle, + GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32* outX, + GHOST_TInt32* outY) ; + +/** + * Converts a point in screen coordinates to client rectangle coordinates + * @param windowhandle The handle to the window + * @param inX The x-coordinate in the client rectangle. + * @param inY The y-coordinate in the client rectangle. + * @param outX The x-coordinate on the screen. + * @param outY The y-coordinate on the screen. + */ +extern void GHOST_ClientToScreen(GHOST_WindowHandle windowhandle, + GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32* outX, + GHOST_TInt32* outY); + +/** + * Returns the state of the window (normal, minimized, maximized). + * @param windowhandle The handle to the window + * @return The state of the window. + */ +extern GHOST_TWindowState GHOST_GetWindowState(GHOST_WindowHandle windowhandle); + +/** + * Sets the state of the window (normal, minimized, maximized). + * @param windowhandle The handle to the window + * @param state The state of the window. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetWindowState(GHOST_WindowHandle windowhandle, + GHOST_TWindowState state); + +/** + * Sets the order of the window (bottom, top). + * @param windowhandle The handle to the window + * @param order The order of the window. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetWindowOrder(GHOST_WindowHandle windowhandle, + GHOST_TWindowOrder order); + +/** + * Swaps front and back buffers of a window. + * @param windowhandle The handle to the window + * @return An intean success indicator. + */ +extern GHOST_TSuccess GHOST_SwapWindowBuffers(GHOST_WindowHandle windowhandle); + +/** + * Activates the drawing context of this window. + * @param windowhandle The handle to the window + * @return An intean success indicator. + */ +extern GHOST_TSuccess GHOST_ActivateWindowDrawingContext(GHOST_WindowHandle windowhandle); + +/** + * Invalidates the contents of this window. + * @param windowhandle The handle to the window + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_InvalidateWindow(GHOST_WindowHandle windowhandle); + +/** + * Returns the status of the tablet + * @param windowhandle The handle to the window + * @return Status of tablet + */ +extern const GHOST_TabletData *GHOST_GetTabletData(GHOST_WindowHandle windowhandle); + +/** + * Access to rectangle width. + * @param rectanglehandle The handle to the rectangle + * @return width of the rectangle + */ +extern GHOST_TInt32 GHOST_GetWidthRectangle(GHOST_RectangleHandle rectanglehandle); + +/** + * Access to rectangle height. + * @param rectanglehandle The handle to the rectangle + * @return height of the rectangle + */ +extern GHOST_TInt32 GHOST_GetHeightRectangle(GHOST_RectangleHandle rectanglehandle); + +/** + * Gets all members of the rectangle. + * @param rectanglehandle The handle to the rectangle + * @param l Pointer to return left coordinate in. + * @param t Pointer to return top coordinate in. + * @param r Pointer to return right coordinate in. + * @param b Pointer to return bottom coordinate in. + */ +extern void GHOST_GetRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32* l, + GHOST_TInt32* t, + GHOST_TInt32* r, + GHOST_TInt32* b); + +/** + * Sets all members of the rectangle. + * @param rectanglehandle The handle to the rectangle + * @param l requested left coordinate of the rectangle + * @param t requested top coordinate of the rectangle + * @param r requested right coordinate of the rectangle + * @param b requested bottom coordinate of the rectangle + */ +extern void GHOST_SetRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 l, + GHOST_TInt32 t, + GHOST_TInt32 r, + GHOST_TInt32 b); + +/** + * Returns whether this rectangle is empty. + * Empty rectangles are rectangles that have width==0 and/or height==0. + * @param rectanglehandle The handle to the rectangle + * @return intean value (true == empty rectangle) + */ +extern GHOST_TSuccess GHOST_IsEmptyRectangle(GHOST_RectangleHandle rectanglehandle); + +/** + * Returns whether this rectangle is valid. + * Valid rectangles are rectangles that have m_l <= m_r and m_t <= m_b. Thus, emapty rectangles are valid. + * @param rectanglehandle The handle to the rectangle + * @return intean value (true==valid rectangle) + */ +extern GHOST_TSuccess GHOST_IsValidRectangle(GHOST_RectangleHandle rectanglehandle); + +/** + * Grows (or shrinks the rectangle). + * The method avoids negative insets making the rectangle invalid + * @param rectanglehandle The handle to the rectangle + * @param i The amount of offset given to each extreme (negative values shrink the rectangle). + */ +extern void GHOST_InsetRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 i); + +/** + * Does a union of the rectangle given and this rectangle. + * The result is stored in this rectangle. + * @param rectanglehandle The handle to the rectangle + * @param r The rectangle that is input for the union operation. + */ +extern void GHOST_UnionRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_RectangleHandle anotherrectanglehandle); + +/** + * Grows the rectangle to included a point. + * @param rectanglehandle The handle to the rectangle + * @param x The x-coordinate of the point. + * @param y The y-coordinate of the point. + */ +extern void GHOST_UnionPointRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 x, + GHOST_TInt32 y); + +/** + * Returns whether the point is inside this rectangle. + * Point on the boundary is considered inside. + * @param rectanglehandle The handle to the rectangle + * @param x x-coordinate of point to test. + * @param y y-coordinate of point to test. + * @return intean value (true if point is inside). + */ +extern GHOST_TSuccess GHOST_IsInsideRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 x, + GHOST_TInt32 y); + +/** + * Returns whether the rectangle is inside this rectangle. + * @param rectanglehandle The handle to the rectangle + * @param r rectangle to test. + * @return visibility (not, partially or fully visible). + */ +extern GHOST_TVisibility GHOST_GetRectangleVisibility(GHOST_RectangleHandle rectanglehandle, + GHOST_RectangleHandle anotherrectanglehandle); + +/** + * Sets rectangle members. + * Sets rectangle members such that it is centered at the given location. + * @param rectanglehandle The handle to the rectangle + * @param cx requested center x-coordinate of the rectangle + * @param cy requested center y-coordinate of the rectangle + */ +extern void GHOST_SetCenterRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 cx, + GHOST_TInt32 cy); + +/** + * Sets rectangle members. + * Sets rectangle members such that it is centered at the given location, + * with the width requested. + * @param rectanglehandle The handle to the rectangle + * @param cx requested center x-coordinate of the rectangle + * @param cy requested center y-coordinate of the rectangle + * @param w requested width of the rectangle + * @param h requested height of the rectangle + */ +extern void GHOST_SetRectangleCenter(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 cx, + GHOST_TInt32 cy, + GHOST_TInt32 w, + GHOST_TInt32 h); + +/** + * Clips a rectangle. + * Updates the rectangle given such that it will fit within this one. + * This can result in an empty rectangle. + * @param rectanglehandle The handle to the rectangle + * @param r the rectangle to clip + * @return whether clipping has occurred + */ +extern GHOST_TSuccess GHOST_ClipRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_RectangleHandle anotherrectanglehandle); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/intern/ghost/GHOST_IEvent.h b/intern/ghost/GHOST_IEvent.h new file mode 100644 index 00000000000..4ec47c6d732 --- /dev/null +++ b/intern/ghost/GHOST_IEvent.h @@ -0,0 +1,92 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_IEvent.h + * Declaration of GHOST_IEvent interface class. + */ + +#ifndef _GHOST_IEVENT_H_ +#define _GHOST_IEVENT_H_ + +#include "GHOST_Types.h" + +class GHOST_IWindow; + +/** + * Interface class for events received from GHOST. + * You should not need to inherit this class. The system will pass these events + * to the GHOST_IEventConsumer::processEvent() method of event consumers.
+ * Use the getType() method to retrieve the type of event and the getData() + * method to get the event data out. Using the event type you can cast the + * event data to the correct event dat structure. + * @see GHOST_IEventConsumer#processEvent + * @see GHOST_TEventType + * @author Maarten Gribnau + * @date May 31, 2001 + */ +class GHOST_IEvent +{ +public: + /** + * Destructor. + */ + virtual ~GHOST_IEvent() + { + } + + /** + * Returns the event type. + * @return The event type. + */ + virtual GHOST_TEventType getType() = 0; + + /** + * Returns the time this event was generated. + * @return The event generation time. + */ + virtual GHOST_TUns64 getTime() = 0; + + /** + * Returns the window this event was generated on, + * or NULL if it is a 'system' event. + * @return The generating window. + */ + virtual GHOST_IWindow* getWindow() = 0; + + /** + * Returns the event data. + * @return The event data. + */ + virtual GHOST_TEventDataPtr getData() = 0; +}; + +#endif // _GHOST_IEVENT_H_ + diff --git a/intern/ghost/GHOST_IEventConsumer.h b/intern/ghost/GHOST_IEventConsumer.h new file mode 100644 index 00000000000..4186d4c1cab --- /dev/null +++ b/intern/ghost/GHOST_IEventConsumer.h @@ -0,0 +1,71 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_IEventConsumer.h + * Declaration of GHOST_IEventConsumer interface class. + */ + +#ifndef _GHOST_IEVENT_CONSUMER_H_ +#define _GHOST_IEVENT_CONSUMER_H_ + +#include "GHOST_IEvent.h" + +/** + * Interface class for objects interested in receiving events. + * Objects interested in events should inherit this class and implement the + * processEvent() method. They should then be registered with the system that + * they want to receive events. The system will call the processEvent() method + * for every installed event consumer to pass events. + * @see GHOST_ISystem#addEventConsumer + * @author Maarten Gribnau + * @date May 14, 2001 + */ +class GHOST_IEventConsumer +{ +public: + /** + * Destructor. + */ + virtual ~GHOST_IEventConsumer() + { + } + + /** + * This method is called by the system when it has events to dispatch. + * @see GHOST_ISystem#dispatchEvents + * @param event The event that can be handled or ignored. + * @return Indication as to whether the event was handled. + */ + virtual bool processEvent(GHOST_IEvent* event) = 0; +}; + +#endif // _GHOST_EVENT_CONSUMER_H_ + diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h new file mode 100644 index 00000000000..dffd81bdb13 --- /dev/null +++ b/intern/ghost/GHOST_ISystem.h @@ -0,0 +1,357 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_ISystem.h + * Main interface file for C++ Api with declaration of GHOST_ISystem interface + * class. + * Contains the doxygen documentation main page. + */ + +#ifndef _GHOST_ISYSTEM_H_ +#define _GHOST_ISYSTEM_H_ + +#include "GHOST_Types.h" +#include "GHOST_ITimerTask.h" +#include "GHOST_IWindow.h" + +class GHOST_IEventConsumer; + +/** + *! \mainpage GHOST Main Page + * + * \section intro Introduction + * + * GHOST is yet another acronym. It stands for "Generic Handy Operating System + * Toolkit". It has been created to replace the OpenGL utility tool kit + * GLUT. + * GLUT was used in Blender until the + * point that Blender needed to be ported to Apple's Mac OSX. Blender needed a + * number of modifications in GLUT to work but the GLUT sources for OSX were + * unavailable at the time. The decision was made to build our own replacement + * for GLUT. In those days, NaN Technologies BV was the company that developed + * Blender. + *

+ * Enough history. What does GHOST have to offer?
+ * In short: everything that Blender needed from GLUT to run on all it's supported + * operating systems and some extra's. + * This includes : + *
    + *
  • Time(r) management.
  • + *
  • Display/window management (windows are only created on the main display). + *
  • Event management.
  • + *
  • Cursor shape management (no custom cursors for now).
  • + *
  • Access to the state of the mouse buttons and the keyboard.
  • + *
  • Menus for windows with events generated when they are accessed (this is + * work in progress).
  • + *
+ * Font management has been moved to a separate library. + * + * \section platforms Platforms + * + * \section Building GHOST + * + * \section interface Interface + * GHOST has two programming interfaces: + *
    + *
  • The C-API. For programs written in C.
  • + *
  • The C++-API. For programs written in C++.
  • + *
+ * GHOST itself is writtem in C++ and the C-API is a wrapper around the C++ + * API. + * + * \subsection cplusplus_api The C++ API consists of the following files: + *
    + *
  • GHOST_IEvent.h
  • + *
  • GHOST_IEventConsumer.h
  • + *
  • GHOST_IMenu.h (in progress)
  • + *
  • GHOST_IMenuBar.h (in progress)
  • + *
  • GHOST_ISystem.h
  • + *
  • GHOST_ITimerTask.h
  • + *
  • GHOST_IWindow.h
  • + *
  • GHOST_Rect.h
  • + *
  • GHOST_Types.h
  • + *
+ * For an example of using the C++-API, have a look at the GHOST_C-Test.cpp + * program in the ?/ghost/test/gears/ directory. + * + * \subsection c_api The C-API + * To use GHOST in programs written in C, include the file GHOST_C-API.h in + * your program. This file includes the GHOST_Types.h file for all GHOST types + * and defines functions that give you access to the same functionality present + * in the C++ API.
+ * For an example of using the C-API, have a look at the GHOST_C-Test.c program + * in the ?/ghost/test/gears/ directory. + * + * \section work Work in progress + * + * \subsection menus Menu functionality + * Menu bars with pull-down menu's for windows are in development in the + * current version of GHOST. The file GHOST_MenuDependKludge.h contains a + * setting to turn menu functionality on or off. + */ + +/** + * Interface for classes that provide access to the operating system. + * There should be only one system class in an application. + * Therefore, the routines to create and dispose the system are static. + * Provides: + * -# Time(r) management. + * -# Display/window management (windows are only created on the main display). + * -# Event management. + * -# Cursor shape management (no custom cursors for now). + * -# Access to the state of the mouse buttons and the keyboard. + * -# Menus for windows with events generated when they are accessed (this is + * work in progress). + * @author Maarten Gribnau + * @date May 30, 2001 + */ +class GHOST_ISystem +{ +public: + /** + * Creates the one and only system. + * @return An indication of success. + */ + static GHOST_TSuccess createSystem(); + + /** + * Disposes the one and only system. + * @return An indication of success. + */ + static GHOST_TSuccess disposeSystem(); + + /** + * Returns a pointer to the one and only system (nil if it hasn't been created). + * @return A pointer to the system. + */ + static GHOST_ISystem* getSystem(); + +protected: + /** + * Constructor. + * Protected default constructor to force use of static createSystem member. + */ + GHOST_ISystem() {} + + /** + * Destructor. + * Protected default constructor to force use of static dispose member. + */ + virtual ~GHOST_ISystem() {} + +public: + /*************************************************************************************** + ** Time(r) functionality + ***************************************************************************************/ + + /** + * Returns the system time. + * Returns the number of milliseconds since the start of the system process. + * Based on ANSI clock() routine. + * @return The number of milliseconds. + */ + virtual GHOST_TUns64 getMilliSeconds() const = 0; + + /** + * Installs a timer. + * Note that, on most operating systems, messages need to be processed in order + * for the timer callbacks to be invoked. + * @param delay The time to wait for the first call to the timerProc (in milliseconds) + * @param interval The interval between calls to the timerProc (in milliseconds) + * @param timerProc The callback invoked when the interval expires, + * @param userData Placeholder for user data. + * @return A timer task (0 if timer task installation failed). + */ + virtual GHOST_ITimerTask* installTimer(GHOST_TUns64 delay, GHOST_TUns64 interval, GHOST_TimerProcPtr timerProc, GHOST_TUserDataPtr userData = 0) = 0; + + /** + * Removes a timer. + * @param timerTask Timer task to be removed. + * @return Indication of success. + */ + virtual GHOST_TSuccess removeTimer(GHOST_ITimerTask* timerTask) = 0; + + /*************************************************************************************** + ** Display/window management functionality + ***************************************************************************************/ + + /** + * Returns the number of displays on this system. + * @return The number of displays. + */ + virtual GHOST_TUns8 getNumDisplays() const = 0; + + /** + * Returns the dimensions of the main display on this system. + * @return The dimension of the main display. + */ + virtual void getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const = 0; + + /** + * Create a new window. + * The new window is added to the list of windows managed. + * Never explicitly delete the window, use disposeWindow() instead. + * @param title The name of the window (displayed in the title bar of the window if the OS supports it). + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state of the window when opened. + * @param type The type of drawing context installed in this window. + * @param stereoVisual Create a stereo visual for quad buffered stereo. + * @return The new window (or 0 if creation failed). + */ + virtual GHOST_IWindow* createWindow( + const STR_String& title, + GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height, + GHOST_TWindowState state, GHOST_TDrawingContextType type, + const bool stereoVisual) = 0; + + /** + * Dispose a window. + * @param window Pointer to the window to be disposed. + * @return Indication of success. + */ + virtual GHOST_TSuccess disposeWindow(GHOST_IWindow* window) = 0; + + /** + * Returns whether a window is valid. + * @param window Pointer to the window to be checked. + * @return Indication of validity. + */ + virtual bool validWindow(GHOST_IWindow* window) = 0; + + /** + * Begins full screen mode. + * @param setting The new setting of the display. + * @param window Window displayed in full screen. + * This window is invalid after full screen has been ended. + * @return Indication of success. + */ + virtual GHOST_TSuccess beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow** window, + const bool stereoVisual) = 0; + + /** + * Ends full screen mode. + * @return Indication of success. + */ + virtual GHOST_TSuccess endFullScreen(void) = 0; + + /** + * Returns current full screen mode status. + * @return The current status. + */ + virtual bool getFullScreen(void) = 0; + + /*************************************************************************************** + ** Event management functionality + ***************************************************************************************/ + + /** + * Retrieves events from the system and stores them in the queue. + * @param waitForEvent Flag to wait for an event (or return immediately). + * @return Indication of the presence of events. + */ + virtual bool processEvents(bool waitForEvent) = 0; + + /** + * Retrieves events from the queue and send them to the event consumers. + * @return Indication of the presence of events. + */ + virtual bool dispatchEvents() = 0; + + /** + * Adds the given event consumer to our list. + * @param consumer The event consumer to add. + * @return Indication of success. + */ + virtual GHOST_TSuccess addEventConsumer(GHOST_IEventConsumer* consumer) = 0; + + /*************************************************************************************** + ** Cursor management functionality + ***************************************************************************************/ + + /** + * Returns the current location of the cursor (location in screen coordinates) + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const = 0; + + /** + * Updates the location of the cursor (location in screen coordinates). + * Not all operating systems allow the cursor to be moved (without the input device being moved). + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) const = 0; + + /*************************************************************************************** + ** Access to mouse button and keyboard states. + ***************************************************************************************/ + + /** + * Returns the state of a modifier key (ouside the message queue). + * @param mask The modifier key state to retrieve. + * @param isDown The state of a modifier key (true == pressed). + * @return Indication of success. + */ + virtual GHOST_TSuccess getModifierKeyState(GHOST_TModifierKeyMask mask, bool& isDown) const = 0; + + /** + * Returns the state of a mouse button (ouside the message queue). + * @param mask The button state to retrieve. + * @param isDown Button state. + * @return Indication of success. + */ + virtual GHOST_TSuccess getButtonState(GHOST_TButtonMask mask, bool& isDown) const = 0; + +protected: + /** + * Initialize the system. + * @return Indication of success. + */ + virtual GHOST_TSuccess init() = 0; + + /** + * Shut the system down. + * @return Indication of success. + */ + virtual GHOST_TSuccess exit() = 0; + + /** The one and only system */ + static GHOST_ISystem* m_system; +}; + +#endif // _GHOST_ISYSTEM_H_ + diff --git a/intern/ghost/GHOST_ITimerTask.h b/intern/ghost/GHOST_ITimerTask.h new file mode 100644 index 00000000000..fa2f788823f --- /dev/null +++ b/intern/ghost/GHOST_ITimerTask.h @@ -0,0 +1,92 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_ITimerTask.h + * Declaration of GHOST_ITimerTask interface class. + */ + +#ifndef _GHOST_ITIMER_TASK_H_ +#define _GHOST_ITIMER_TASK_H_ + +#include "GHOST_Types.h" + + +/** + * Interface for a timer task. + * Timer tasks are created by the system and can be installed by the system. + * After installation, the timer callback-procedure or "timerProc" will be called + * periodically. You should not need to inherit this class. It is passed to the + * application in the timer-callback.
+ *
+ * Note that GHOST processes timers in the UI thread. You should ask GHOST + * process messages in order for the timer-callbacks to be called. + * @see GHOST_ISystem#installTimer + * @see GHOST_TimerProcPtr + * @author Maarten Gribnau + * @date May 31, 2001 + */ +class GHOST_ITimerTask +{ +public: + /** + * Destructor. + */ + virtual ~GHOST_ITimerTask() + { + } + + /** + * Returns the timer callback. + * @return The timer callback. + */ + virtual GHOST_TimerProcPtr getTimerProc() const = 0; + + /** + * Changes the timer callback. + * @param timerProc The timer callback. + */ + virtual void setTimerProc(const GHOST_TimerProcPtr timerProc) = 0; + + /** + * Returns the timer user data. + * @return The timer user data. + */ + virtual GHOST_TUserDataPtr getUserData() const = 0; + + /** + * Changes the time user data. + * @param data The timer user data. + */ + virtual void setUserData(const GHOST_TUserDataPtr userData) = 0; +}; + +#endif // _GHOST_ITIMER_TASK_H_ + diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h new file mode 100644 index 00000000000..5f6bbe553c6 --- /dev/null +++ b/intern/ghost/GHOST_IWindow.h @@ -0,0 +1,261 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_IWindow.h + * Declaration of GHOST_IWindow interface class. + */ + +#ifndef _GHOST_IWINDOW_H_ +#define _GHOST_IWINDOW_H_ + +#include "STR_String.h" +#include "GHOST_Rect.h" +#include "GHOST_Types.h" + + +/** + * Interface for GHOST windows. + * + * You can create a window with the system's GHOST_ISystem::createWindow + * method. + * @see GHOST_ISystem#createWindow + * + * There are two coordinate systems: + *
    + *
  • The screen coordinate system. The origin of the screen is located in the + * upper left corner of the screen.
  • + *
  • The client rectangle coordinate system. The client rectangle of a window + * is the area that is drawable by the application (excluding title bars etc.). + *
  • + *
+ * @author Maarten Gribnau + * @date May 31, 2001 + */ +class GHOST_IWindow +{ +public: + /** + * Destructor. + */ + virtual ~GHOST_IWindow() + { + } + + /** + * Returns indication as to whether the window is valid. + * @return The validity of the window. + */ + virtual bool getValid() const = 0; + + /** + * Returns the type of drawing context used in this window. + * @return The current type of drawing context. + */ + virtual GHOST_TDrawingContextType getDrawingContextType() = 0; + + /** + * Tries to install a rendering context in this window. + * @param type The type of rendering context installed. + * @return Indication as to whether installation has succeeded. + */ + virtual GHOST_TSuccess setDrawingContextType(GHOST_TDrawingContextType type) = 0; + + /** + * Sets the title displayed in the title bar. + * @param title The title to display in the title bar. + */ + virtual void setTitle(const STR_String& title) = 0; + + /** + * Returns the title displayed in the title bar. + * @param title The title displayed in the title bar. + */ + virtual void getTitle(STR_String& title) const = 0; + + /** + * Returns the window rectangle dimensions. + * These are screen coordinates. + * @param bounds The bounding rectangle of the window. + */ + virtual void getWindowBounds(GHOST_Rect& bounds) const = 0; + + /** + * Returns the client rectangle dimensions. + * The left and top members of the rectangle are always zero. + * @param bounds The bounding rectangle of the client area of the window. + */ + virtual void getClientBounds(GHOST_Rect& bounds) const = 0; + + /** + * Resizes client rectangle width. + * @param width The new width of the client area of the window. + */ + virtual GHOST_TSuccess setClientWidth(GHOST_TUns32 width) = 0; + + /** + * Resizes client rectangle height. + * @param height The new height of the client area of the window. + */ + virtual GHOST_TSuccess setClientHeight(GHOST_TUns32 height) = 0; + + /** + * Resizes client rectangle. + * @param width The new width of the client area of the window. + * @param height The new height of the client area of the window. + */ + virtual GHOST_TSuccess setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) = 0; + + /** + * Converts a point in screen coordinates to client rectangle coordinates + * @param inX The x-coordinate on the screen. + * @param inY The y-coordinate on the screen. + * @param outX The x-coordinate in the client rectangle. + * @param outY The y-coordinate in the client rectangle. + */ + virtual void screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const = 0; + + /** + * Converts a point in screen coordinates to client rectangle coordinates + * @param inX The x-coordinate in the client rectangle. + * @param inY The y-coordinate in the client rectangle. + * @param outX The x-coordinate on the screen. + * @param outY The y-coordinate on the screen. + */ + virtual void clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const = 0; + + /** + * Returns the state of the window (normal, minimized, maximized). + * @return The state of the window. + */ + virtual GHOST_TWindowState getState() const = 0; + + /** + * Sets the state of the window (normal, minimized, maximized). + * @param state The state of the window. + * @return Indication of success. + */ + virtual GHOST_TSuccess setState(GHOST_TWindowState state) = 0; + + /** + * Sets the order of the window (bottom, top). + * @param order The order of the window. + * @return Indication of success. + */ + virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order) = 0; + + /** + * Swaps front and back buffers of a window. + * @return A boolean success indicator. + */ + virtual GHOST_TSuccess swapBuffers() = 0; + + /** + * Activates the drawing context of this window. + * @return A boolean success indicator. + */ + virtual GHOST_TSuccess activateDrawingContext() = 0; + + /** + * Invalidates the contents of this window. + * @return Indication of success. + */ + virtual GHOST_TSuccess invalidate() = 0; + + /** + * Returns the window user data. + * @return The window user data. + */ + virtual GHOST_TUserDataPtr getUserData() const = 0; + + /** + * Changes the window user data. + * @param data The window user data. + */ + virtual void setUserData(const GHOST_TUserDataPtr userData) = 0; + + /** + * Returns the tablet data (pressure etc). + * @return The tablet data (pressure etc). + */ + virtual const GHOST_TabletData* GetTabletData() = 0; + + /*************************************************************************************** + ** Cursor management functionality + ***************************************************************************************/ + + /** + * Returns the current cursor shape. + * @return The current cursor shape. + */ + virtual GHOST_TStandardCursor getCursorShape() const = 0; + + /** + * Set the shape of the cursor. + * @param cursor The new cursor shape type id. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCursorShape(GHOST_TStandardCursor cursorShape) = 0; + + /** + * Set the shape of the cursor to a custom cursor. + * @param bitmap The bitmap data for the cursor. + * @param mask The mask data for the cursor. + * @param hotX The X coordinate of the cursor hotspot. + * @param hotY The Y coordinate of the cursor hotspot. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCustomCursorShape(GHOST_TUns8 bitmap[16][2], + GHOST_TUns8 mask[16][2], + int hotX, + int hotY) = 0; + + virtual GHOST_TSuccess setCustomCursorShape(GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, int sizey, + int hotX, int hotY, + int fg_color, int bg_color) = 0; + + /** + * Returns the visibility state of the cursor. + * @return The visibility state of the cursor. + */ + virtual bool getCursorVisibility() const = 0; + + /** + * Shows or hides the cursor. + * @param visible The new visibility state of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCursorVisibility(bool visible) = 0; +}; + +#endif // _GHOST_IWINDOW_H_ + diff --git a/intern/ghost/GHOST_Rect.h b/intern/ghost/GHOST_Rect.h new file mode 100644 index 00000000000..6b303504572 --- /dev/null +++ b/intern/ghost/GHOST_Rect.h @@ -0,0 +1,234 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_Rect.h + * Declaration of GHOST_Rect rectangle class. + */ + +#ifndef _H_GHOST_Rect +#define _H_GHOST_Rect + +#include "GHOST_Types.h" + + +/** + * Implements rectangle functionality. + * The four extreme coordinates are stored as left, top, right and bottom. + * To be valid, a rectangle should have a left coordinate smaller than or equal to right. + * To be valid, a rectangle should have a top coordinate smaller than or equal to bottom. + * @author Maarten Gribnau + * @date May 10, 2001 + */ + +class GHOST_Rect { +public: + + /** + * Constructs a rectangle with the given values. + * @param l requested left coordinate of the rectangle + * @param t requested top coordinate of the rectangle + * @param r requested right coordinate of the rectangle + * @param b requested bottom coordinate of the rectangle + */ + GHOST_Rect(GHOST_TInt32 l=0, GHOST_TInt32 t=0, GHOST_TInt32 r=0, GHOST_TInt32 b=0) + : m_l(l), m_t(t), m_r(r), m_b(b) {} + + /** + * Copy constructor. + * @param r rectangle to copy + */ + GHOST_Rect(const GHOST_Rect& r) + : m_l(r.m_l), m_t(r.m_t), m_r(r.m_r), m_b(r.m_b) {} + + /** + * Destructor. + */ + virtual ~GHOST_Rect() {}; + + /** + * Access to rectangle width. + * @return width of the rectangle + */ + virtual inline GHOST_TInt32 getWidth() const; + + /** + * Access to rectangle height. + * @return height of the rectangle + */ + virtual inline GHOST_TInt32 getHeight() const; + + /** + * Sets all members of the rectangle. + * @param l requested left coordinate of the rectangle + * @param t requested top coordinate of the rectangle + * @param r requested right coordinate of the rectangle + * @param b requested bottom coordinate of the rectangle + */ + virtual inline void set(GHOST_TInt32 l, GHOST_TInt32 t, GHOST_TInt32 r, GHOST_TInt32 b); + + /** + * Returns whether this rectangle is empty. + * Empty rectangles are rectangles that have width==0 and/or height==0. + * @return boolean value (true==empty rectangle) + */ + virtual inline bool isEmpty() const; + + /** + * Returns whether this rectangle is valid. + * Valid rectangles are rectangles that have m_l <= m_r and m_t <= m_b. Thus, emapty rectangles are valid. + * @return boolean value (true==valid rectangle) + */ + virtual inline bool isValid() const; + + /** + * Grows (or shrinks the rectangle). + * The method avoids negative insets making the rectangle invalid + * @param i The amount of offset given to each extreme (negative values shrink the rectangle). + */ + virtual void inset(GHOST_TInt32 i); + + /** + * Does a union of the rectangle given and this rectangle. + * The result is stored in this rectangle. + * @param r The rectangle that is input for the union operation. + */ + virtual inline void unionRect(const GHOST_Rect& r); + + /** + * Grows the rectangle to included a point. + * @param x The x-coordinate of the point. + * @param y The y-coordinate of the point. + */ + virtual inline void unionPoint(GHOST_TInt32 x, GHOST_TInt32 y); + + /** + * Returns whether the point is inside this rectangle. + * Point on the boundary is considered inside. + * @param x x-coordinate of point to test. + * @param y y-coordinate of point to test. + * @return boolean value (true if point is inside). + */ + virtual inline bool isInside(GHOST_TInt32 x, GHOST_TInt32 y) const; + + /** + * Returns whether the rectangle is inside this rectangle. + * @param r rectangle to test. + * @return visibility (not, partially or fully visible). + */ + virtual GHOST_TVisibility getVisibility(GHOST_Rect& r) const; + + /** + * Sets rectangle members. + * Sets rectangle members such that it is centered at the given location. + * @param cx requested center x-coordinate of the rectangle + * @param cy requested center y-coordinate of the rectangle + */ + virtual void setCenter(GHOST_TInt32 cx, GHOST_TInt32 cy); + + /** + * Sets rectangle members. + * Sets rectangle members such that it is centered at the given location, + * with the width requested. + * @param cx requested center x-coordinate of the rectangle + * @param cy requested center y-coordinate of the rectangle + * @param w requested width of the rectangle + * @param h requested height of the rectangle + */ + virtual void setCenter(GHOST_TInt32 cx, GHOST_TInt32 cy, GHOST_TInt32 w, GHOST_TInt32 h); + + /** + * Clips a rectangle. + * Updates the rectangle given such that it will fit within this one. + * This can result in an empty rectangle. + * @param r the rectangle to clip + * @return whether clipping has occurred + */ + virtual bool clip(GHOST_Rect& r) const; + + /** Left coordinate of the rectangle */ + GHOST_TInt32 m_l; + /** Top coordinate of the rectangle */ + GHOST_TInt32 m_t; + /** Right coordinate of the rectangle */ + GHOST_TInt32 m_r; + /** Bottom coordinate of the rectangle */ + GHOST_TInt32 m_b; +}; + + +inline GHOST_TInt32 GHOST_Rect::getWidth() const +{ + return m_r - m_l; +} + +inline GHOST_TInt32 GHOST_Rect::getHeight() const +{ + return m_b - m_t; +} + +inline void GHOST_Rect::set(GHOST_TInt32 l, GHOST_TInt32 t, GHOST_TInt32 r, GHOST_TInt32 b) +{ + m_l = l; m_t = t; m_r = r; m_b = b; +} + +inline bool GHOST_Rect::isEmpty() const +{ + return (getWidth() == 0) || (getHeight() == 0); +} + +inline bool GHOST_Rect::isValid() const +{ + return (m_l <= m_r) && (m_t <= m_b); +} + +inline void GHOST_Rect::unionRect(const GHOST_Rect& r) +{ + if (r.m_l < m_l) m_l = r.m_l; + if (r.m_r > m_r) m_r = r.m_r; + if (r.m_t < m_t) m_t = r.m_t; + if (r.m_b > m_b) m_b = r.m_b; +} + +inline void GHOST_Rect::unionPoint(GHOST_TInt32 x, GHOST_TInt32 y) +{ + if (x < m_l) m_l = x; + if (x > m_r) m_r = x; + if (y < m_t) m_t = y; + if (y > m_b) m_b = y; +} + +inline bool GHOST_Rect::isInside(GHOST_TInt32 x, GHOST_TInt32 y) const +{ + return (x >= m_l) && (x <= m_r) && (y >= m_t) && (y <= m_b); +} + +#endif // _H_GHOST_Rect + diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h new file mode 100644 index 00000000000..d5575354370 --- /dev/null +++ b/intern/ghost/GHOST_Types.h @@ -0,0 +1,372 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef _GHOST_TYPES_H_ +#define _GHOST_TYPES_H_ + +typedef char GHOST_TInt8; +typedef unsigned char GHOST_TUns8; +typedef short GHOST_TInt16; +typedef unsigned short GHOST_TUns16; +typedef int GHOST_TInt32; +typedef unsigned int GHOST_TUns32; + +#if defined(WIN32) && !defined(FREE_WINDOWS) +typedef __int64 GHOST_TInt64; +typedef unsigned __int64 GHOST_TUns64; +#else +typedef long long GHOST_TInt64; +typedef unsigned long long GHOST_TUns64; +#endif + +typedef void* GHOST_TUserDataPtr; + +typedef enum +{ + GHOST_kFailure = 0, + GHOST_kSuccess +} GHOST_TSuccess; + +/* Xtilt and Ytilt represent how much the pen is tilted away from + * vertically upright in either the X or Y direction, with X and Y the + * axes of the tablet surface. + * In other words, Xtilt and Ytilt are components of a vector created by projecting + * the pen's angle in 3D space vertically downwards on to the XY plane + * --Matt + */ +typedef struct GHOST_TabletData { + char Active; /* 0=None, 1=Stylus, 2=Eraser */ + float Pressure; /* range 0.0 (not touching) to 1.0 (full pressure) */ + float Xtilt; /* range 0.0 (upright) to 1.0 (tilted fully against the tablet surface) */ + float Ytilt; /* as above */ +} GHOST_TabletData; + + +typedef enum { + GHOST_kNotVisible = 0, + GHOST_kPartiallyVisible, + GHOST_kFullyVisible +} GHOST_TVisibility; + + +typedef enum { + GHOST_kFireTimeNever = 0xFFFFFFFF +} GHOST_TFireTimeConstant; + +typedef enum { + GHOST_kModifierKeyLeftShift = 0, + GHOST_kModifierKeyRightShift, + GHOST_kModifierKeyLeftAlt, + GHOST_kModifierKeyRightAlt, + GHOST_kModifierKeyLeftControl, + GHOST_kModifierKeyRightControl, + GHOST_kModifierKeyCommand, // APPLE only + GHOST_kModifierKeyNumMasks +} GHOST_TModifierKeyMask; + + +typedef enum { + GHOST_kWindowStateNormal = 0, + GHOST_kWindowStateMaximized, + GHOST_kWindowStateMinimized, + GHOST_kWindowStateFullScreen, + GHOST_kWindowState8Normal = 8, + GHOST_kWindowState8Maximized, + GHOST_kWindowState8Minimized, + GHOST_kWindowState8FullScreen +} GHOST_TWindowState; + + +typedef enum { + GHOST_kWindowOrderTop = 0, + GHOST_kWindowOrderBottom +} GHOST_TWindowOrder; + + +typedef enum { + GHOST_kDrawingContextTypeNone = 0, + GHOST_kDrawingContextTypeOpenGL +} GHOST_TDrawingContextType; + + +typedef enum { + GHOST_kButtonMaskLeft = 0, + GHOST_kButtonMaskMiddle, + GHOST_kButtonMaskRight, + GHOST_kButtonNumMasks +} GHOST_TButtonMask; + + +typedef enum { + GHOST_kEventUnknown = 0, + + GHOST_kEventCursorMove, /// Mouse move event + GHOST_kEventButtonDown, /// Mouse button event + GHOST_kEventButtonUp, /// Mouse button event + GHOST_kEventWheel, /// Mouse wheel event + + GHOST_kEventKeyDown, + GHOST_kEventKeyUp, +// GHOST_kEventKeyAuto, + + GHOST_kEventQuit, + + GHOST_kEventWindowClose, + GHOST_kEventWindowActivate, + GHOST_kEventWindowDeactivate, + GHOST_kEventWindowUpdate, + GHOST_kEventWindowSize, + + GHOST_kNumEventTypes +} GHOST_TEventType; + + +typedef enum { + GHOST_kStandardCursorFirstCursor = 0, + GHOST_kStandardCursorDefault = 0, + GHOST_kStandardCursorRightArrow, + GHOST_kStandardCursorLeftArrow, + GHOST_kStandardCursorInfo, + GHOST_kStandardCursorDestroy, + GHOST_kStandardCursorHelp, + GHOST_kStandardCursorCycle, + GHOST_kStandardCursorSpray, + GHOST_kStandardCursorWait, + GHOST_kStandardCursorText, + GHOST_kStandardCursorCrosshair, + GHOST_kStandardCursorUpDown, + GHOST_kStandardCursorLeftRight, + GHOST_kStandardCursorTopSide, + GHOST_kStandardCursorBottomSide, + GHOST_kStandardCursorLeftSide, + GHOST_kStandardCursorRightSide, + GHOST_kStandardCursorTopLeftCorner, + GHOST_kStandardCursorTopRightCorner, + GHOST_kStandardCursorBottomRightCorner, + GHOST_kStandardCursorBottomLeftCorner, + GHOST_kStandardCursorCustom, + GHOST_kStandardCursorNumCursors, + GHOST_kStandardCursorPencil +} GHOST_TStandardCursor; + + +typedef enum { + GHOST_kKeyUnknown = -1, + GHOST_kKeyBackSpace, + GHOST_kKeyTab, + GHOST_kKeyLinefeed, + GHOST_kKeyClear, + GHOST_kKeyEnter = 0x0D, + + GHOST_kKeyEsc = 0x1B, + GHOST_kKeySpace = ' ', + GHOST_kKeyQuote = 0x27, + GHOST_kKeyComma = ',', + GHOST_kKeyMinus = '-', + GHOST_kKeyPeriod = '.', + GHOST_kKeySlash = '/', + + // Number keys + GHOST_kKey0 = '0', + GHOST_kKey1, + GHOST_kKey2, + GHOST_kKey3, + GHOST_kKey4, + GHOST_kKey5, + GHOST_kKey6, + GHOST_kKey7, + GHOST_kKey8, + GHOST_kKey9, + + GHOST_kKeySemicolon = ';', + GHOST_kKeyEqual = '=', + + // Character keys + GHOST_kKeyA = 'A', + GHOST_kKeyB, + GHOST_kKeyC, + GHOST_kKeyD, + GHOST_kKeyE, + GHOST_kKeyF, + GHOST_kKeyG, + GHOST_kKeyH, + GHOST_kKeyI, + GHOST_kKeyJ, + GHOST_kKeyK, + GHOST_kKeyL, + GHOST_kKeyM, + GHOST_kKeyN, + GHOST_kKeyO, + GHOST_kKeyP, + GHOST_kKeyQ, + GHOST_kKeyR, + GHOST_kKeyS, + GHOST_kKeyT, + GHOST_kKeyU, + GHOST_kKeyV, + GHOST_kKeyW, + GHOST_kKeyX, + GHOST_kKeyY, + GHOST_kKeyZ, + + GHOST_kKeyLeftBracket = '[', + GHOST_kKeyRightBracket = ']', + GHOST_kKeyBackslash = 0x5C, + GHOST_kKeyAccentGrave = '`', + + + GHOST_kKeyLeftShift = 0x100, + GHOST_kKeyRightShift, + GHOST_kKeyLeftControl, + GHOST_kKeyRightControl, + GHOST_kKeyLeftAlt, + GHOST_kKeyRightAlt, + GHOST_kKeyCommand, // APPLE only! + GHOST_kKeyGrLess , // German PC only! + + GHOST_kKeyCapsLock, + GHOST_kKeyNumLock, + GHOST_kKeyScrollLock, + + GHOST_kKeyLeftArrow, + GHOST_kKeyRightArrow, + GHOST_kKeyUpArrow, + GHOST_kKeyDownArrow, + + GHOST_kKeyPrintScreen, + GHOST_kKeyPause, + + GHOST_kKeyInsert, + GHOST_kKeyDelete, + GHOST_kKeyHome, + GHOST_kKeyEnd, + GHOST_kKeyUpPage, + GHOST_kKeyDownPage, + + // Numpad keys + GHOST_kKeyNumpad0, + GHOST_kKeyNumpad1, + GHOST_kKeyNumpad2, + GHOST_kKeyNumpad3, + GHOST_kKeyNumpad4, + GHOST_kKeyNumpad5, + GHOST_kKeyNumpad6, + GHOST_kKeyNumpad7, + GHOST_kKeyNumpad8, + GHOST_kKeyNumpad9, + GHOST_kKeyNumpadPeriod, + GHOST_kKeyNumpadEnter, + GHOST_kKeyNumpadPlus, + GHOST_kKeyNumpadMinus, + GHOST_kKeyNumpadAsterisk, + GHOST_kKeyNumpadSlash, + + // Function keys + GHOST_kKeyF1, + GHOST_kKeyF2, + GHOST_kKeyF3, + GHOST_kKeyF4, + GHOST_kKeyF5, + GHOST_kKeyF6, + GHOST_kKeyF7, + GHOST_kKeyF8, + GHOST_kKeyF9, + GHOST_kKeyF10, + GHOST_kKeyF11, + GHOST_kKeyF12, + GHOST_kKeyF13, + GHOST_kKeyF14, + GHOST_kKeyF15, + GHOST_kKeyF16, + GHOST_kKeyF17, + GHOST_kKeyF18, + GHOST_kKeyF19, + GHOST_kKeyF20, + GHOST_kKeyF21, + GHOST_kKeyF22, + GHOST_kKeyF23, + GHOST_kKeyF24 +} GHOST_TKey; + + +typedef void* GHOST_TEventDataPtr; + +typedef struct { + /** The x-coordinate of the cursor position. */ + GHOST_TInt32 x; + /** The y-coordinate of the cursor position. */ + GHOST_TInt32 y; +} GHOST_TEventCursorData; + +typedef struct { + /** The mask of the mouse button. */ + GHOST_TButtonMask button; +} GHOST_TEventButtonData; + +typedef struct { + /** Displacement of a mouse wheel. */ + GHOST_TInt32 z; +} GHOST_TEventWheelData; + +typedef struct { + /** The key code. */ + GHOST_TKey key; + /** The ascii code for the key event ('\0' if none). */ + char ascii; +} GHOST_TEventKeyData; + +typedef struct { + /** Number of pixels on a line. */ + GHOST_TUns32 xPixels; + /** Number of lines. */ + GHOST_TUns32 yPixels; + /** Numberof bits per pixel. */ + GHOST_TUns32 bpp; + /** Refresh rate (in Hertz). */ + GHOST_TUns32 frequency; +} GHOST_DisplaySetting; + + +/** + * A timer task callback routine. + * @param task The timer task object. + * @param time The current time. + */ +#ifdef __cplusplus +class GHOST_ITimerTask; +typedef void (*GHOST_TimerProcPtr)(GHOST_ITimerTask* task, GHOST_TUns64 time); +#else +struct GHOST_TimerTaskHandle__; +typedef void (*GHOST_TimerProcPtr)(struct GHOST_TimerTaskHandle__* task, GHOST_TUns64 time); +#endif + +#endif // _GHOST_TYPES_H_ + diff --git a/intern/ghost/Makefile b/intern/ghost/Makefile new file mode 100644 index 00000000000..fe65afbfb93 --- /dev/null +++ b/intern/ghost/Makefile @@ -0,0 +1,56 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# ghost main makefile. +# + +include nan_definitions.mk + +LIBNAME = ghost +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_GHOST) ] || mkdir $(NAN_GHOST) + @[ -d $(NAN_GHOST)/include ] || mkdir $(NAN_GHOST)/include + @[ -d $(NAN_GHOST)/lib ] || mkdir $(NAN_GHOST)/lib + @[ -d $(NAN_GHOST)/lib/debug ] || mkdir $(NAN_GHOST)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libghost.a $(NAN_GHOST)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libghost.a $(NAN_GHOST)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_GHOST)/lib/libghost.a + ranlib $(NAN_GHOST)/lib/debug/libghost.a +endif + @../tools/cpifdiff.sh *.h $(NAN_GHOST)/include/ + diff --git a/intern/ghost/SConscript b/intern/ghost/SConscript new file mode 100644 index 00000000000..40968e816a9 --- /dev/null +++ b/intern/ghost/SConscript @@ -0,0 +1,32 @@ +#!/usr/bin/python +import sys +import os + +Import ('env') + +window_system = env['OURPLATFORM'] + +sources = env.Glob('intern/*.cpp') + +pf = ['GHOST_DisplayManager', 'GHOST_System', 'GHOST_Window'] + +if window_system in ('linux2', 'openbsd3', 'sunos5', 'freebsd6'): + for f in pf: + sources.remove('intern' + os.sep + f + 'Win32.cpp') + sources.remove('intern' + os.sep + f + 'Carbon.cpp') +elif window_system in ('win32-vc', 'win32-mingw', 'cygwin', 'linuxcross'): + for f in pf: + sources.remove('intern' + os.sep + f + 'X11.cpp') + sources.remove('intern' + os.sep + f + 'Carbon.cpp') +elif window_system == 'darwin': + for f in pf: + sources.remove('intern' + os.sep + f + 'Win32.cpp') + sources.remove('intern' + os.sep + f + 'X11.cpp') +else: + print "Unknown window system specified." + Exit() + +incs = '. ../string ' + env['BF_OPENGL_INC'] +if window_system in ('win32-vc', 'win32-mingw', 'cygwin', 'linuxcross'): + incs = env['BF_WINTAB_INC'] + ' ' + incs +env.BlenderLib ('bf_ghost', sources, Split(incs), defines=['_USE_MATH_DEFINES'], libtype=['core','player'], priority = [25,15] ) diff --git a/intern/ghost/doc/ghost_interface.cfg b/intern/ghost/doc/ghost_interface.cfg new file mode 100644 index 00000000000..ebe4153ea3b --- /dev/null +++ b/intern/ghost/doc/ghost_interface.cfg @@ -0,0 +1,626 @@ +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. +PROJECT_NAME = "GHOST (Generic Handy Operating System Toolkit)" + +# 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 = 1.0 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# 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 = ./interface + +# 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. +# The default language is English, other supported languages are: +# Dutch, French, Italian, Czech, Swedish, German, Finnish, Japanese, +# Korean, Hungarian, Norwegian, Spanish, Romanian, Russian, Croatian, +# Polish, Portuguese and Slovene. +OUTPUT_LANGUAGE = English + +# 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 and EXTRACT_STATIC tags are set to YES +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. +EXTRACT_STATIC = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) 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. +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 (the default) these class will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. +HIDE_UNDOC_CLASSES = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) 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. +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) 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. +REPEAT_BRIEF = YES + +# 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. +ALWAYS_DETAILED_SEC = YES + +# If the FULL_PATH_NAMES tag is set to YES then 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. +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then 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. It is allowed to use relative paths in the argument list. +STRIP_FROM_PATH = + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. +INTERNAL_DOCS = NO + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a class diagram (in Html and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. +CLASS_DIAGRAMS = YES + +# 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. +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. +STRIP_CODE_COMMENTS = YES + +# 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 +# users are adviced to set this option to NO. +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. +HIDE_SCOPE_NAMES = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) 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. +VERBATIM_HEADERS = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put list of the files that are included by a file in the documentation +# of that file. +SHOW_INCLUDE_FILES = YES + +# 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 +# comments will behave just like the Qt-style comments (thus requiring an +# explict @brief command for a brief description. +JAVADOC_AUTOBRIEF = YES + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# reimplements. +INHERIT_DOCS = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) 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. +SORT_MEMBER_DOCS = 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. +DISTRIBUTE_GROUP_DOC = 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. +TAB_SIZE = 4 + +# The ENABLE_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. +ENABLED_SECTION = + +# 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 +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. +GENERATE_TESTLIST = YES + +# This tag can be used to specify a number of aliases that acts +# 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 = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED 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. +WARN_IF_UNDOCUMENTED = YES + +# 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. +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 stderr. +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be 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. +INPUT = .. + +# If the value of the INPUT tag contains directories, you can use the +# FILE_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. +FILE_PATTERNS = *.h *.cpp *.c + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# 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. +EXCLUDE = + +# 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. +EXCLUDE_PATTERNS = + +# 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 = ../test + +# 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 = *.h *.cpp *.c + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are 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. +INPUT_FILTER = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse. +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# 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. +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) +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 one or more prefixes that +# should be ignored while generating the index headers. +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. +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. If left blank `html' will be used as the default path. +HTML_OUTPUT = html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. +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 the tag is left blank doxygen +# will generate a default style sheet +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. +GENERATE_HTMLHELP = YES + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side pannel 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 and frames is required (for instance Netscape 4.0+ +# or Internet explorer 4.0+). +GENERATE_TREEVIEW = YES + +# 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. +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. +LATEX_OUTPUT = latex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. +LATEX_BATCHMODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimised for Word 97 and may not look very pretty with +# other RTF readers or editors. +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using a WORD or other. +# programs which support those fields. +# Note: wordpad (write) and others do not support links. +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assigments. You only have to provide +# replacements, missing definitions are set to their default value. +RTF_STYLESHEET_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) +MAN_EXTENSION = .3 + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. Warning: This feature +# is still experimental and very incomplete. +GENERATE_XML = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. +EXPAND_AS_DEFINED = + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tagfiles. +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. +ALLEXTERNALS = + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) +HAVE_DOT = YES + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. +COLLABORATION_GRAPH = YES + +# If the ENABLE_PREPROCESSING, INCLUDE_GRAPH, and HAVE_DOT tags are set to +# YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other +# documented files. +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to +# YES then doxygen will generate a graph for each documented header file showing +# the documented files that directly or indirectly include this file +INCLUDED_BY_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. +GRAPHICAL_HIERARCHY = YES + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found on the path. +DOT_PATH = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. +MAX_DOT_GRAPH_HEIGHT = 1024 + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. +GENERATE_LEGEND = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. +SEARCHENGINE = NO + +# The CGI_NAME tag should be the name of the CGI script that +# starts the search engine (doxysearch) with the correct parameters. +# A script with this name will be generated by doxygen. +CGI_NAME= search.cgi + +# The CGI_URL tag should be the absolute URL to the directory where the +# cgi binaries are located. See the documentation of your http daemon for +# details. +CGI_URL= + +# The DOC_URL tag should be the absolute URL to the directory where the +# documentation is located. If left blank the absolute path to the +# documentation, with file:// prepended to it, will be used. +DOC_URL= + +# The DOC_ABSPATH tag should be the absolute path to the directory where the +# documentation is located. If left blank the directory on the local machine +# will be used. +DOC_ABSPATH= + +# The BIN_ABSPATH tag must point to the directory where the doxysearch binary +# is installed. +BIN_ABSPATH= /bin + +# The EXT_DOC_PATHS tag can be used to specify one or more paths to +# documentation generated for other projects. This allows doxysearch to search +# the documentation for these projects as well. +EXT_DOC_PATHS= diff --git a/intern/ghost/intern/GHOST_Buttons.cpp b/intern/ghost/intern/GHOST_Buttons.cpp new file mode 100644 index 00000000000..def01b0786f --- /dev/null +++ b/intern/ghost/intern/GHOST_Buttons.cpp @@ -0,0 +1,81 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "GHOST_Buttons.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + + + +GHOST_Buttons::GHOST_Buttons() +{ + clear(); +} + + +bool GHOST_Buttons::get(GHOST_TButtonMask mask) const +{ + switch (mask) { + case GHOST_kButtonMaskLeft: + return m_ButtonLeft; + case GHOST_kButtonMaskMiddle: + return m_ButtonMiddle; + case GHOST_kButtonMaskRight: + return m_ButtonRight; + default: + return false; + } +} + +void GHOST_Buttons::set(GHOST_TButtonMask mask, bool down) +{ + switch (mask) { + case GHOST_kButtonMaskLeft: + m_ButtonLeft = down; break; + case GHOST_kButtonMaskMiddle: + m_ButtonMiddle = down; break; + case GHOST_kButtonMaskRight: + m_ButtonRight = down; break; + default: + break; + } +} + +void GHOST_Buttons::clear() +{ + m_ButtonLeft = false; + m_ButtonMiddle = false; + m_ButtonRight = false; +} + +GHOST_Buttons::~GHOST_Buttons() {} diff --git a/intern/ghost/intern/GHOST_Buttons.h b/intern/ghost/intern/GHOST_Buttons.h new file mode 100644 index 00000000000..e244d54b2c6 --- /dev/null +++ b/intern/ghost/intern/GHOST_Buttons.h @@ -0,0 +1,81 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_Buttons.h + * Declaration of GHOST_Buttons struct. + */ + +#ifndef _GHOST_BUTTONS_H_ +#define _GHOST_BUTTONS_H_ + +#include "GHOST_Types.h" + + +/** + * This struct stores the state of the mouse buttons. + * Buttons can be set using button masks. + * @author Maarten Gribnau + * @date May 15, 2001 + */ +struct GHOST_Buttons { + /** + * Constructor. + */ + GHOST_Buttons(); + + virtual ~GHOST_Buttons(); + + /** + * Returns the state of a single button. + * @param mask. Key button to return. + * @return The state of the button (pressed == true). + */ + virtual bool get(GHOST_TButtonMask mask) const; + + /** + * Updates the state of a single button. + * @param mask. Button state to update. + * @param down. The new state of the button. + */ + virtual void set(GHOST_TButtonMask mask, bool down); + + /** + * Sets the state of all buttons to up. + */ + virtual void clear(); + + GHOST_TUns8 m_ButtonLeft : 1; + GHOST_TUns8 m_ButtonMiddle : 1; + GHOST_TUns8 m_ButtonRight : 1; +}; + +#endif // _GHOST_BUTTONS_H_ + diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp new file mode 100644 index 00000000000..c2b8eca9573 --- /dev/null +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -0,0 +1,804 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * GHOST_C-Api.cpp + * + * C Api for GHOST + * + * Version: $Id$ + */ + +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "intern/GHOST_Debug.h" +#include "GHOST_C-api.h" +#include "GHOST_ISystem.h" +#include "GHOST_IEvent.h" +#include "GHOST_IEventConsumer.h" +#include "intern/GHOST_CallbackEventConsumer.h" + +#ifdef WIN32 +#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning +#endif //WIN32 + + +GHOST_SystemHandle GHOST_CreateSystem(void) +{ + GHOST_ISystem::createSystem(); + GHOST_ISystem* system = GHOST_ISystem::getSystem(); + + return (GHOST_SystemHandle)system; +} + + + +GHOST_TSuccess GHOST_DisposeSystem(GHOST_SystemHandle systemhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return system->disposeSystem(); +} + + +GHOST_EventConsumerHandle GHOST_CreateEventConsumer(GHOST_EventCallbackProcPtr eventCallback, GHOST_TUserDataPtr userdata) +{ + return (GHOST_EventConsumerHandle) new GHOST_CallbackEventConsumer (eventCallback, userdata); +} + + +GHOST_TSuccess GHOST_DisposeEventConsumer(GHOST_EventConsumerHandle consumerhandle) +{ + delete ((GHOST_CallbackEventConsumer*)consumerhandle); + return GHOST_kSuccess; +} + + +GHOST_TUns64 GHOST_GetMilliSeconds(GHOST_SystemHandle systemhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return system->getMilliSeconds(); +} + + + +GHOST_TimerTaskHandle GHOST_InstallTimer(GHOST_SystemHandle systemhandle, + GHOST_TUns64 delay, + GHOST_TUns64 interval, + GHOST_TimerProcPtr timerproc, + GHOST_TUserDataPtr userdata) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return (GHOST_TimerTaskHandle) system->installTimer(delay, interval, timerproc, userdata); +} + + + +GHOST_TSuccess GHOST_RemoveTimer(GHOST_SystemHandle systemhandle, + GHOST_TimerTaskHandle timertaskhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + GHOST_ITimerTask* timertask = (GHOST_ITimerTask*) timertaskhandle; + + return system->removeTimer(timertask); +} + + + +GHOST_TUns8 GHOST_GetNumDisplays(GHOST_SystemHandle systemhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return system->getNumDisplays(); +} + + + +void GHOST_GetMainDisplayDimensions(GHOST_SystemHandle systemhandle, + GHOST_TUns32* width, + GHOST_TUns32* height) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + system->getMainDisplayDimensions(*width, *height); +} + + + +GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle, + char* title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const int stereoVisual) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + bool bstereoVisual; + + if(stereoVisual) + bstereoVisual = true; + else + bstereoVisual = false; + + return (GHOST_WindowHandle) system->createWindow(title, left, top, width, height, + state, type, bstereoVisual); +} + +GHOST_TUserDataPtr GHOST_GetWindowUserData(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->getUserData(); +} +void GHOST_SetWindowUserData(GHOST_WindowHandle windowhandle, GHOST_TUserDataPtr userdata) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + window->setUserData(userdata); +} + +GHOST_TSuccess GHOST_DisposeWindow(GHOST_SystemHandle systemhandle, + GHOST_WindowHandle windowhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return system->disposeWindow(window); +} + + + +int GHOST_ValidWindow(GHOST_SystemHandle systemhandle, + GHOST_WindowHandle windowhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return (int) system->validWindow(window); +} + + + +GHOST_WindowHandle GHOST_BeginFullScreen(GHOST_SystemHandle systemhandle, + GHOST_DisplaySetting* setting, + const int stereoVisual) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + GHOST_IWindow* window = NULL; + bool bstereoVisual; + + if(stereoVisual) + bstereoVisual = true; + else + bstereoVisual = false; + + system->beginFullScreen(*setting, &window, bstereoVisual); + + return (GHOST_WindowHandle)window; +} + + + +GHOST_TSuccess GHOST_EndFullScreen(GHOST_SystemHandle systemhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return system->endFullScreen(); +} + + + +int GHOST_GetFullScreen(GHOST_SystemHandle systemhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return (int) system->getFullScreen(); +} + + + +int GHOST_ProcessEvents(GHOST_SystemHandle systemhandle, int waitForEvent) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return (int) system->processEvents(waitForEvent?true:false); +} + + + +int GHOST_DispatchEvents(GHOST_SystemHandle systemhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return (int) system->dispatchEvents(); +} + + +GHOST_TSuccess GHOST_AddEventConsumer(GHOST_SystemHandle systemhandle, GHOST_EventConsumerHandle consumerhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return system->addEventConsumer((GHOST_CallbackEventConsumer*)consumerhandle); +} + + + +GHOST_TStandardCursor GHOST_GetCursorShape(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->getCursorShape(); +} + + + +GHOST_TSuccess GHOST_SetCursorShape(GHOST_WindowHandle windowhandle, + GHOST_TStandardCursor cursorshape) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setCursorShape(cursorshape); +} + +GHOST_TSuccess GHOST_SetCustomCursorShape(GHOST_WindowHandle windowhandle, + GHOST_TUns8 bitmap[16][2], + GHOST_TUns8 mask[16][2], + int hotX, + int hotY) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setCustomCursorShape(bitmap, mask, hotX, hotY); +} + +GHOST_TSuccess GHOST_SetCustomCursorShapeEx(GHOST_WindowHandle windowhandle, + GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, + int sizey, + int hotX, + int hotY, + int fg_color, + int bg_color) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setCustomCursorShape(bitmap, mask, sizex, sizey, + hotX, hotY, fg_color, bg_color); +} + + + +int GHOST_GetCursorVisibility(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return (int) window->getCursorVisibility(); +} + + + +GHOST_TSuccess GHOST_SetCursorVisibility(GHOST_WindowHandle windowhandle, + int visible) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setCursorVisibility(visible?true:false); +} + + + +GHOST_TSuccess GHOST_GetCursorPosition(GHOST_SystemHandle systemhandle, + GHOST_TInt32* x, + GHOST_TInt32* y) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return system->getCursorPosition(*x, *y); +} + + + +GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle, + GHOST_TInt32 x, + GHOST_TInt32 y) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return system->setCursorPosition(x, y); +} + + + +GHOST_TSuccess GHOST_GetModifierKeyState(GHOST_SystemHandle systemhandle, + GHOST_TModifierKeyMask mask, + int* isDown) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + GHOST_TSuccess result; + bool isdown; + + result = system->getModifierKeyState(mask, isdown); + *isDown = (int) isdown; + + return result; +} + + + +GHOST_TSuccess GHOST_GetButtonState(GHOST_SystemHandle systemhandle, + GHOST_TButtonMask mask, + int* isDown) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + GHOST_TSuccess result; + bool isdown; + + result = system->getButtonState(mask, isdown); + *isDown = (int) isdown; + + return result; +} + + + +GHOST_TEventType GHOST_GetEventType(GHOST_EventHandle eventhandle) +{ + GHOST_IEvent* event = (GHOST_IEvent*) eventhandle; + + return event->getType(); +} + + + +GHOST_TUns64 GHOST_GetEventTime(GHOST_EventHandle eventhandle) +{ + GHOST_IEvent* event = (GHOST_IEvent*) eventhandle; + + return event->getTime(); +} + + +GHOST_WindowHandle GHOST_GetEventWindow(GHOST_EventHandle eventhandle) +{ + GHOST_IEvent* event = (GHOST_IEvent*) eventhandle; + + return (GHOST_WindowHandle) event->getWindow(); +} + + +GHOST_TEventDataPtr GHOST_GetEventData(GHOST_EventHandle eventhandle) +{ + GHOST_IEvent* event = (GHOST_IEvent*) eventhandle; + + return event->getData(); +} + + + +GHOST_TimerProcPtr GHOST_GetTimerProc(GHOST_TimerTaskHandle timertaskhandle) +{ + GHOST_ITimerTask* timertask = (GHOST_ITimerTask*) timertaskhandle; + + return timertask->getTimerProc(); +} + + + +void GHOST_SetTimerProc(GHOST_TimerTaskHandle timertaskhandle, + GHOST_TimerProcPtr timerproc) +{ + GHOST_ITimerTask* timertask = (GHOST_ITimerTask*) timertaskhandle; + + timertask->setTimerProc(timerproc); +} + + + +GHOST_TUserDataPtr GHOST_GetTimerTaskUserData(GHOST_TimerTaskHandle timertaskhandle) +{ + GHOST_ITimerTask* timertask = (GHOST_ITimerTask*) timertaskhandle; + + return timertask->getUserData(); +} + + + +void GHOST_SetTimerTaskUserData(GHOST_TimerTaskHandle timertaskhandle, + GHOST_TUserDataPtr userdata) +{ + GHOST_ITimerTask* timertask = (GHOST_ITimerTask*) timertaskhandle; + + timertask->setUserData(userdata); +} + + + +int GHOST_GetValid(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return (int) window->getValid(); +} + + + +GHOST_TDrawingContextType GHOST_GetDrawingContextType(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->getDrawingContextType(); +} + + + +GHOST_TSuccess GHOST_SetDrawingContextType(GHOST_WindowHandle windowhandle, + GHOST_TDrawingContextType type) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setDrawingContextType(type); +} + + + +void GHOST_SetTitle(GHOST_WindowHandle windowhandle, + char* title) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + window->setTitle(title); +} + + +char* GHOST_GetTitle(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + STR_String title; + + window->getTitle(title); + + char *ctitle = (char*) malloc(title.Length() + 1); + + if (ctitle == NULL) return NULL; + strcpy(ctitle, title.Ptr()); + + return ctitle; +} + + + +GHOST_RectangleHandle GHOST_GetWindowBounds(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + GHOST_Rect* rectangle = NULL; + + rectangle = new GHOST_Rect(); + window->getWindowBounds(*rectangle); + + return (GHOST_RectangleHandle)rectangle; +} + + + +GHOST_RectangleHandle GHOST_GetClientBounds(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + GHOST_Rect* rectangle = NULL; + + rectangle = new GHOST_Rect(); + window->getClientBounds(*rectangle); + + return (GHOST_RectangleHandle)rectangle; +} + + + +void GHOST_DisposeRectangle(GHOST_RectangleHandle rectanglehandle) +{ + delete (GHOST_Rect*) rectanglehandle; +} + + + +GHOST_TSuccess GHOST_SetClientWidth(GHOST_WindowHandle windowhandle, + GHOST_TUns32 width) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setClientWidth(width); +} + + + +GHOST_TSuccess GHOST_SetClientHeight(GHOST_WindowHandle windowhandle, + GHOST_TUns32 height) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setClientHeight(height); +} + + + +GHOST_TSuccess GHOST_SetClientSize(GHOST_WindowHandle windowhandle, + GHOST_TUns32 width, + GHOST_TUns32 height) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setClientSize(width, height); +} + + + +void GHOST_ScreenToClient(GHOST_WindowHandle windowhandle, + GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32* outX, + GHOST_TInt32* outY) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + window->screenToClient(inX, inY, *outX, *outY); +} + + + +void GHOST_ClientToScreen(GHOST_WindowHandle windowhandle, + GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32* outX, + GHOST_TInt32* outY) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + window->clientToScreen(inX, inY, *outX, *outY); +} + + + +GHOST_TWindowState GHOST_GetWindowState(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->getState(); +} + + + +GHOST_TSuccess GHOST_SetWindowState(GHOST_WindowHandle windowhandle, + GHOST_TWindowState state) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setState(state); +} + + + +GHOST_TSuccess GHOST_SetWindowOrder(GHOST_WindowHandle windowhandle, + GHOST_TWindowOrder order) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setOrder(order); +} + + + +GHOST_TSuccess GHOST_SwapWindowBuffers(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->swapBuffers(); +} + + + +GHOST_TSuccess GHOST_ActivateWindowDrawingContext(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->activateDrawingContext(); +} + + + +GHOST_TSuccess GHOST_InvalidateWindow(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->invalidate(); +} + + +extern const GHOST_TabletData* GHOST_GetTabletData(GHOST_WindowHandle windowhandle) +{ + return ((GHOST_IWindow*)windowhandle)->GetTabletData(); +} + + +GHOST_TInt32 GHOST_GetWidthRectangle(GHOST_RectangleHandle rectanglehandle) +{ + return ((GHOST_Rect*)rectanglehandle)->getWidth(); +} + + + +GHOST_TInt32 GHOST_GetHeightRectangle(GHOST_RectangleHandle rectanglehandle) +{ + return ((GHOST_Rect*)rectanglehandle)->getHeight(); +} + + + +void GHOST_GetRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32* l, + GHOST_TInt32* t, + GHOST_TInt32* r, + GHOST_TInt32* b) +{ + GHOST_Rect *rect= (GHOST_Rect*) rectanglehandle; + + *l= rect->m_l; + *t= rect->m_t; + *r= rect->m_r; + *b= rect->m_b; +} + + +void GHOST_SetRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 l, + GHOST_TInt32 t, + GHOST_TInt32 r, + GHOST_TInt32 b) +{ + ((GHOST_Rect*)rectanglehandle)->set(l, t, r, b); +} + + + +GHOST_TSuccess GHOST_IsEmptyRectangle(GHOST_RectangleHandle rectanglehandle) +{ + GHOST_TSuccess result = GHOST_kFailure; + + if (((GHOST_Rect*)rectanglehandle)->isEmpty()) + result = GHOST_kSuccess; + + return result; +} + + + +GHOST_TSuccess GHOST_IsValidRectangle(GHOST_RectangleHandle rectanglehandle) +{ + GHOST_TSuccess result = GHOST_kFailure; + + if(((GHOST_Rect*)rectanglehandle)->isValid()) + result = GHOST_kSuccess; + + return result; +} + + + +void GHOST_InsetRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 i) +{ + ((GHOST_Rect*)rectanglehandle)->inset(i); +} + + + +void GHOST_UnionRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_RectangleHandle anotherrectanglehandle) +{ + ((GHOST_Rect*)rectanglehandle)->unionRect(*(GHOST_Rect*)anotherrectanglehandle); +} + + + +void GHOST_UnionPointRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 x, + GHOST_TInt32 y) +{ + ((GHOST_Rect*)rectanglehandle)->unionPoint(x, y); +} + + + +GHOST_TSuccess GHOST_IsInsideRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 x, + GHOST_TInt32 y) +{ + GHOST_TSuccess result = GHOST_kFailure; + + if (((GHOST_Rect*)rectanglehandle)->isInside(x, y)) + result = GHOST_kSuccess; + + return result; +} + + + +GHOST_TVisibility GHOST_GetRectangleVisibility(GHOST_RectangleHandle rectanglehandle, + GHOST_RectangleHandle anotherrectanglehandle) +{ + GHOST_TVisibility visible = GHOST_kNotVisible; + + visible = ((GHOST_Rect*)rectanglehandle)->getVisibility(*(GHOST_Rect*)anotherrectanglehandle); + + return visible; +} + + + +void GHOST_SetCenterRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 cx, + GHOST_TInt32 cy) +{ + ((GHOST_Rect*)rectanglehandle)->setCenter(cx, cy); +} + + + +void GHOST_SetRectangleCenter(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 cx, + GHOST_TInt32 cy, + GHOST_TInt32 w, + GHOST_TInt32 h) +{ + ((GHOST_Rect*)rectanglehandle)->setCenter(cx, cy, w, h); +} + + + +GHOST_TSuccess GHOST_ClipRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_RectangleHandle anotherrectanglehandle) +{ + GHOST_TSuccess result = GHOST_kFailure; + + if (((GHOST_Rect*)rectanglehandle)->clip(*(GHOST_Rect*)anotherrectanglehandle)) + result = GHOST_kSuccess; + + return result; +} diff --git a/intern/ghost/intern/GHOST_CallbackEventConsumer.cpp b/intern/ghost/intern/GHOST_CallbackEventConsumer.cpp new file mode 100644 index 00000000000..2a5e7fb9b71 --- /dev/null +++ b/intern/ghost/intern/GHOST_CallbackEventConsumer.cpp @@ -0,0 +1,59 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date October 25, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_Debug.h" +#include "GHOST_C-api.h" +#include "GHOST_CallbackEventConsumer.h" + +GHOST_CallbackEventConsumer::GHOST_CallbackEventConsumer(GHOST_EventCallbackProcPtr eventCallback, + GHOST_TUserDataPtr userData) +{ + m_eventCallback = eventCallback; + m_userData = userData; +} + + +bool GHOST_CallbackEventConsumer::processEvent(GHOST_IEvent* event) +{ + return m_eventCallback((GHOST_EventHandle)event, m_userData) != 0; +} diff --git a/intern/ghost/intern/GHOST_CallbackEventConsumer.h b/intern/ghost/intern/GHOST_CallbackEventConsumer.h new file mode 100644 index 00000000000..eb54d1c0e14 --- /dev/null +++ b/intern/ghost/intern/GHOST_CallbackEventConsumer.h @@ -0,0 +1,82 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_CallbackEventConsumer.h + * Declaration of GHOST_CallbackEventConsumer class. + */ + +#ifndef _GHOST_CALLBACK_EVENT_CONSUMER_H_ +#define _GHOST_CALLBACK_EVENT_CONSUMER_H_ + +#include "GHOST_IEventConsumer.h" +#include "GHOST_C-api.h" + +/** + * Event consumer that will forward events to a call-back routine. + * Especially useful for the C-API. + * @author Maarten Gribnau + * @date October 25, 2001 + */ +class GHOST_CallbackEventConsumer : public GHOST_IEventConsumer +{ +public: + /** + * Constructor. + * @param eventCallback The call-back routine invoked. + * @param userData The data passed back though the call-back routine. + */ + GHOST_CallbackEventConsumer( + GHOST_EventCallbackProcPtr eventCallback, + GHOST_TUserDataPtr userData); + + /** + * Destructor. + */ + virtual ~GHOST_CallbackEventConsumer(void) + { + } + + /** + * This method is called by an event producer when an event is available. + * @param event The event that can be handled or ignored. + * @return Indication as to whether the event was handled. + */ + virtual bool processEvent(GHOST_IEvent* event); + +protected: + /** The call-back routine invoked. */ + GHOST_EventCallbackProcPtr m_eventCallback; + /** The data passed back though the call-back routine. */ + GHOST_TUserDataPtr m_userData; +}; + +#endif // _GHOST_CALLBACK_EVENT_CONSUMER_H_ + diff --git a/intern/ghost/intern/GHOST_Debug.h b/intern/ghost/intern/GHOST_Debug.h new file mode 100644 index 00000000000..5a56c8ef6ea --- /dev/null +++ b/intern/ghost/intern/GHOST_Debug.h @@ -0,0 +1,68 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + * @file GHOST_Debug.h + * Macro's used in GHOST debug target. + */ + +#ifndef _GHOST_DEBUG_H_ +#define _GHOST_DEBUG_H_ + +#ifdef WIN32 + #ifdef _DEBUG + #pragma warning (disable:4786) // suppress stl-MSVC debug info warning + #define GHOST_DEBUG + #endif // _DEBUG +#endif // WIN32 + +#ifdef GHOST_DEBUG + #include +#endif // GHOST_DEBUG + + +#ifdef GHOST_DEBUG + #define GHOST_PRINT(x) { std::cout << x; } + //#define GHOST_PRINTF(x) { printf(x); } +#else // GHOST_DEBUG + #define GHOST_PRINT(x) + //#define GHOST_PRINTF(x) +#endif // GHOST_DEBUG + + +#ifdef GHOST_DEBUG + #define GHOST_ASSERT(x, info) { if (!(x)) {GHOST_PRINT("assertion failed: "); GHOST_PRINT(info); GHOST_PRINT("\n"); } } +#else // GHOST_DEBUG + #define GHOST_ASSERT(x, info) +#endif // GHOST_DEBUG + +#endif // _GHOST_DEBUG_H_ + diff --git a/intern/ghost/intern/GHOST_DisplayManager.cpp b/intern/ghost/intern/GHOST_DisplayManager.cpp new file mode 100644 index 00000000000..f806daee86b --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManager.cpp @@ -0,0 +1,222 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date September 21, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_DisplayManager.h" +#include "GHOST_Debug.h" + + +GHOST_DisplayManager::GHOST_DisplayManager( + void) +: m_settingsInitialized(false) +{ +} + + +GHOST_DisplayManager::~GHOST_DisplayManager(void) +{ +} + + +GHOST_TSuccess +GHOST_DisplayManager::initialize( + void) +{ + GHOST_TSuccess success; + if (!m_settingsInitialized) { + success = initializeSettings(); + m_settingsInitialized = true; + } + else { + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TSuccess +GHOST_DisplayManager::getNumDisplays( + GHOST_TUns8& /*numDisplays*/) const +{ + // Don't know if we have a display... + return GHOST_kFailure; +} + + +GHOST_TSuccess +GHOST_DisplayManager::getNumDisplaySettings( + GHOST_TUns8 display, + GHOST_TInt32& numSettings) const +{ + GHOST_TSuccess success; + + GHOST_ASSERT(m_settingsInitialized, "GHOST_DisplayManager::getNumDisplaySettings(): m_settingsInitialized=false"); + GHOST_TUns8 numDisplays; + success = getNumDisplays(numDisplays); + if (success == GHOST_kSuccess) { + if (display < numDisplays) { + numSettings = m_settings[display].size(); + } + else { + success = GHOST_kFailure; + } + } + return success; +} + + +GHOST_TSuccess +GHOST_DisplayManager::getDisplaySetting( + GHOST_TUns8 display, + GHOST_TInt32 index, + GHOST_DisplaySetting& setting) const +{ + GHOST_TSuccess success; + + GHOST_ASSERT(m_settingsInitialized, "GHOST_DisplayManager::getNumDisplaySettings(): m_settingsInitialized=false"); + GHOST_TUns8 numDisplays; + success = getNumDisplays(numDisplays); + if (success == GHOST_kSuccess) { + if (display < numDisplays && ((GHOST_TUns8)index < m_settings[display].size())) { + setting = m_settings[display][index]; + } + else { + success = GHOST_kFailure; + } + } + return success; +} + + +GHOST_TSuccess +GHOST_DisplayManager::getCurrentDisplaySetting( + GHOST_TUns8 /*display*/, + GHOST_DisplaySetting& /*setting*/) const +{ + return GHOST_kFailure; +} + + +GHOST_TSuccess +GHOST_DisplayManager::setCurrentDisplaySetting( + GHOST_TUns8 /*display*/, + const GHOST_DisplaySetting& /*setting*/) +{ + return GHOST_kFailure; +} + + +GHOST_TSuccess +GHOST_DisplayManager::findMatch( + GHOST_TUns8 display, + const GHOST_DisplaySetting& setting, + GHOST_DisplaySetting& match) const +{ + GHOST_TSuccess success = GHOST_kSuccess; + GHOST_ASSERT(m_settingsInitialized, "GHOST_DisplayManager::findMatch(): m_settingsInitialized=false"); + + int criteria[4] = { setting.xPixels, setting.yPixels, setting.bpp, setting.frequency }; + int capabilities[4]; + double field, score; + double best = 1e12; // A big number + int found = 0; + + // Look at all the display modes + for (int i = 0; (i < (int)m_settings[display].size()); i++) { + // Store the capabilities of the display device + capabilities[0] = m_settings[display][i].xPixels; + capabilities[1] = m_settings[display][i].yPixels; + capabilities[2] = m_settings[display][i].bpp; + capabilities[3] = m_settings[display][i].frequency; + + // Match against all the fields of the display settings + score = 0; + for (int j = 0; j < 4; j++) { + field = capabilities[j] - criteria[j]; + score += field * field; + } + + if (score < best) { + found = i; + best = score; + } + } + + match = m_settings[display][found]; + + GHOST_PRINT("GHOST_DisplayManager::findMatch(): settings of match:\n"); + GHOST_PRINT(" setting.xPixels=" << match.xPixels << "\n"); + GHOST_PRINT(" setting.yPixels=" << match.yPixels << "\n"); + GHOST_PRINT(" setting.bpp=" << match.bpp << "\n"); + GHOST_PRINT(" setting.frequency=" << match.frequency << "\n"); + + return success; +} + + +GHOST_TSuccess +GHOST_DisplayManager::initializeSettings( + void) +{ + GHOST_TUns8 numDisplays; + GHOST_TSuccess success = getNumDisplays(numDisplays); + if (success == GHOST_kSuccess) { + for (GHOST_TUns8 display = 0; (display < numDisplays) && (success == GHOST_kSuccess); display++) { + GHOST_DisplaySettings displaySettings; + m_settings.push_back(displaySettings); + GHOST_TInt32 numSettings; + success = getNumDisplaySettings(display, numSettings); + if (success == GHOST_kSuccess) { + GHOST_TInt32 index; + GHOST_DisplaySetting setting; + for (index = 0; (index < numSettings) && (success == GHOST_kSuccess); index++) { + success = getDisplaySetting(display, index, setting); + m_settings[display].push_back(setting); + } + } + else { + break; + } + } + } + return success; +} diff --git a/intern/ghost/intern/GHOST_DisplayManager.h b/intern/ghost/intern/GHOST_DisplayManager.h new file mode 100644 index 00000000000..d7133f4401f --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManager.h @@ -0,0 +1,140 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_DisplayManager.h + * Declaration of GHOST_DisplayManager class. + */ + +#ifndef _GHOST_DISPLAY_MANAGER_H_ +#define _GHOST_DISPLAY_MANAGER_H_ + +#include "GHOST_Types.h" + +#ifdef WIN32 +#pragma warning (disable:4786) // suppress stl-MSVC debug info warning +#endif // WIN32 + +#include + +/** + * Manages system displays (platform independent implementation). + * @author Maarten Gribnau + * @date September 21, 2001 + */ +class GHOST_DisplayManager +{ +public: + enum { kMainDisplay = 0 }; + /** + * Constructor. + */ + GHOST_DisplayManager(void); + + /** + * Destructor. + */ + virtual ~GHOST_DisplayManager(void); + + /** + * Initializes the list with devices and settings. + * @return Indication of success. + */ + virtual GHOST_TSuccess initialize(void); + + /** + * Returns the number of display devices on this system. + * @param numDisplays The number of displays on this system. + * @return Indication of success. + */ + virtual GHOST_TSuccess getNumDisplays(GHOST_TUns8& numDisplays) const; + + /** + * Returns the number of display settings for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The number of settings of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param index The setting index to be returned. + * @param setting The setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The current setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const; + + /** + * Changes the current setting for this display device. + * The setting given to this method is matched againts the available diplay settings. + * The best match is activated (@see findMatch()). + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The setting of the display device to be matched and activated. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting); + +protected: + typedef std::vector GHOST_DisplaySettings; + + /** + * Finds the best display settings match. + * @param display The index of the display device. + * @param setting The setting to match. + * @param match The optimal display setting. + * @return Indication of success. + */ + GHOST_TSuccess findMatch(GHOST_TUns8 display, const GHOST_DisplaySetting& setting, GHOST_DisplaySetting& match) const; + + /** + * Retrieves settings for each display device and stores them. + * @return Indication of success. + */ + GHOST_TSuccess initializeSettings(void); + + /** Tells whether the list of display modes has been stored already. */ + bool m_settingsInitialized; + /** The list with display settings for the main display. */ + std::vector m_settings; +}; + + +#endif // _GHOST_DISPLAY_MANAGER_H_ + diff --git a/intern/ghost/intern/GHOST_DisplayManagerCarbon.cpp b/intern/ghost/intern/GHOST_DisplayManagerCarbon.cpp new file mode 100644 index 00000000000..9877d55d8a5 --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManagerCarbon.cpp @@ -0,0 +1,181 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date September 21, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_DisplayManagerCarbon.h" +#include "GHOST_Debug.h" + +// We do not support multiple monitors at the moment + + +GHOST_DisplayManagerCarbon::GHOST_DisplayManagerCarbon(void) +{ + if (::CGGetActiveDisplayList(0, NULL, &m_numDisplays) != CGDisplayNoErr) + { + m_numDisplays = 0; + m_displayIDs = NULL; + } + if (m_numDisplays > 0) + { + m_displayIDs = new CGDirectDisplayID [m_numDisplays]; + GHOST_ASSERT((m_displayIDs!=NULL), "GHOST_DisplayManagerCarbon::GHOST_DisplayManagerCarbon(): memory allocation failed"); + ::CGGetActiveDisplayList(m_numDisplays, m_displayIDs, &m_numDisplays); + } +} + + +GHOST_TSuccess GHOST_DisplayManagerCarbon::getNumDisplays(GHOST_TUns8& numDisplays) const +{ + numDisplays = (GHOST_TUns8) m_numDisplays; + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_DisplayManagerCarbon::getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCarbon::getNumDisplaySettings(): only main display is supported"); + + CFArrayRef displayModes; + displayModes = ::CGDisplayAvailableModes(m_displayIDs[display]); + CFIndex numModes = ::CFArrayGetCount(displayModes); + numSettings = (GHOST_TInt32)numModes; + + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_DisplayManagerCarbon::getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCarbon::getDisplaySetting(): only main display is supported"); + + CFArrayRef displayModes; + CGDirectDisplayID d = m_displayIDs[display]; + displayModes = ::CGDisplayAvailableModes(d); + //CFIndex numModes = ::CFArrayGetCount(displayModes);/*unused*/ + //GHOST_TInt32 numSettings = (GHOST_TInt32)numModes; /*unused*/ + CFDictionaryRef displayModeValues = (CFDictionaryRef)::CFArrayGetValueAtIndex(displayModes, index); + + setting.xPixels = getValue(displayModeValues, kCGDisplayWidth); + setting.yPixels = getValue(displayModeValues, kCGDisplayHeight); + setting.bpp = getValue(displayModeValues, kCGDisplayBitsPerPixel); + setting.frequency = getValue(displayModeValues, kCGDisplayRefreshRate); + +#ifdef GHOST_DEBUG + printf("display mode: width=%d, height=%d, bpp=%d, frequency=%d\n", setting.xPixels, setting.yPixels, setting.bpp, setting.frequency); +#endif // GHOST_DEBUG + + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_DisplayManagerCarbon::getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCarbon::getCurrentDisplaySetting(): only main display is supported"); + + CFDictionaryRef displayModeValues = ::CGDisplayCurrentMode(m_displayIDs[display]); + + setting.xPixels = getValue(displayModeValues, kCGDisplayWidth); + setting.yPixels = getValue(displayModeValues, kCGDisplayHeight); + setting.bpp = getValue(displayModeValues, kCGDisplayBitsPerPixel); + setting.frequency = getValue(displayModeValues, kCGDisplayRefreshRate); + +#ifdef GHOST_DEBUG + printf("current display mode: width=%d, height=%d, bpp=%d, frequency=%d\n", setting.xPixels, setting.yPixels, setting.bpp, setting.frequency); +#endif // GHOST_DEBUG + + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_DisplayManagerCarbon::setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting) +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCarbon::setCurrentDisplaySetting(): only main display is supported"); + +#ifdef GHOST_DEBUG + printf("GHOST_DisplayManagerCarbon::setCurrentDisplaySetting(): requested settings:\n"); + printf(" setting.xPixels=%d\n", setting.xPixels); + printf(" setting.yPixels=%d\n", setting.yPixels); + printf(" setting.bpp=%d\n", setting.bpp); + printf(" setting.frequency=%d\n", setting.frequency); +#endif // GHOST_DEBUG + + CFDictionaryRef displayModeValues = ::CGDisplayBestModeForParametersAndRefreshRate( + m_displayIDs[display], + (size_t)setting.bpp, + (size_t)setting.xPixels, + (size_t)setting.yPixels, + (CGRefreshRate)setting.frequency, + NULL); + +#ifdef GHOST_DEBUG + printf("GHOST_DisplayManagerCarbon::setCurrentDisplaySetting(): switching to:\n"); + printf(" setting.xPixels=%d\n", getValue(displayModeValues, kCGDisplayWidth)); + printf(" setting.yPixels=%d\n", getValue(displayModeValues, kCGDisplayHeight)); + printf(" setting.bpp=%d\n", getValue(displayModeValues, kCGDisplayBitsPerPixel)); + printf(" setting.frequency=%d\n", getValue(displayModeValues, kCGDisplayRefreshRate)); +#endif // GHOST_DEBUG + + CGDisplayErr err = ::CGDisplaySwitchToMode(m_displayIDs[display], displayModeValues); + + return err == CGDisplayNoErr ? GHOST_kSuccess : GHOST_kFailure; +} + + +long GHOST_DisplayManagerCarbon::getValue(CFDictionaryRef values, CFStringRef key) const +{ + CFNumberRef numberValue = (CFNumberRef) CFDictionaryGetValue(values, key); + + if (!numberValue) + { + return -1; + } + + long intValue; + + if (!CFNumberGetValue(numberValue, kCFNumberLongType, &intValue)) + { + return -1; + } + + return intValue; +} + diff --git a/intern/ghost/intern/GHOST_DisplayManagerCarbon.h b/intern/ghost/intern/GHOST_DisplayManagerCarbon.h new file mode 100644 index 00000000000..42a1aa37a5a --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManagerCarbon.h @@ -0,0 +1,119 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_DisplayManagerCarbon.h + * Declaration of GHOST_DisplayManagerCarbon class. + */ + +#ifndef _GHOST_DISPLAY_MANAGER_CARBON_H_ +#define _GHOST_DISPLAY_MANAGER_CARBON_H_ + +#ifndef __APPLE__ +#error Apple only! +#endif // __APPLE__ + +#include "GHOST_DisplayManager.h" + +#define __CARBONSOUND__ +#include + +/** + * Manages system displays (Mac OSX/Carbon implementation). + * @see GHOST_DisplayManager + * @author Maarten Gribnau + * @date September 21, 2001 + */ +class GHOST_DisplayManagerCarbon : public GHOST_DisplayManager +{ +public: + /** + * Constructor. + */ + GHOST_DisplayManagerCarbon(void); + + /** + * Returns the number of display devices on this system. + * @param numDisplays The number of displays on this system. + * @return Indication of success. + */ + virtual GHOST_TSuccess getNumDisplays(GHOST_TUns8& numDisplays) const; + + /** + * Returns the number of display settings for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The number of settings of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param index The setting index to be returned. + * @param setting The setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The current setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const; + + /** + * Changes the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The current setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting); + +protected: + /** + * Returns a value from a dictionary. + * @param values Dictionary to return value from. + * @param key Key to return value for. + * @return The value for this key. + */ + long getValue(CFDictionaryRef values, CFStringRef key) const; + + /** Cached number of displays. */ + CGDisplayCount m_numDisplays; + /** Cached display id's for each display. */ + CGDirectDisplayID* m_displayIDs; +}; + + +#endif // _GHOST_DISPLAY_MANAGER_CARBON_H_ + diff --git a/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp new file mode 100644 index 00000000000..3fbacfb1db8 --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp @@ -0,0 +1,191 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date September 21, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_DisplayManagerWin32.h" +#include "GHOST_Debug.h" + +// We do not support multiple monitors at the moment +#include +#define COMPILE_MULTIMON_STUBS +#ifndef FREE_WINDOWS +#include +#endif + + +GHOST_DisplayManagerWin32::GHOST_DisplayManagerWin32(void) +{ +} + + +GHOST_TSuccess GHOST_DisplayManagerWin32::getNumDisplays(GHOST_TUns8& numDisplays) const +{ + // We do not support multiple monitors at the moment + numDisplays = ::GetSystemMetrics(SM_CMONITORS); + return numDisplays > 0 ? GHOST_kSuccess : GHOST_kFailure; +} + + +/* + * When you call EnumDisplaySettings with iModeNum set to zero, the operating system + * initializes and caches information about the display device. When you call + * EnumDisplaySettings with iModeNum set to a non-zero value, the function returns + * the information that was cached the last time the function was called with iModeNum + * set to zero. + */ +GHOST_TSuccess GHOST_DisplayManagerWin32::getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerWin32::getNumDisplaySettings(): only main displlay is supported"); + numSettings = 0; + DEVMODE dm; + while (::EnumDisplaySettings(NULL, numSettings, &dm)) { + numSettings++; + } + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_DisplayManagerWin32::getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerWin32::getDisplaySetting(): only main display is supported"); + GHOST_TSuccess success; + DEVMODE dm; + if (::EnumDisplaySettings(NULL, index, &dm)) { +#ifdef GHOST_DEBUG + printf("display mode: width=%d, height=%d, bpp=%d, frequency=%d\n", dm.dmPelsWidth, dm.dmPelsHeight, dm.dmBitsPerPel, dm.dmDisplayFrequency); +#endif // GHOST_DEBUG + setting.xPixels = dm.dmPelsWidth; + setting.yPixels = dm.dmPelsHeight; + setting.bpp = dm.dmBitsPerPel; + /* When you call the EnumDisplaySettings function, the dmDisplayFrequency member + * may return with the value 0 or 1. These values represent the display hardware's + * default refresh rate. This default rate is typically set by switches on a display + * card or computer motherboard, or by a configuration program that does not use + * Win32 display functions such as ChangeDisplaySettings. + */ + /* First, we tried to explicitly set the frequency to 60 if EnumDisplaySettings + * returned 0 or 1 but this doesn't work since later on an exact match will + * be searched. And this will never happen if we change it to 60. Now we rely + * on the default h/w setting. + */ + setting.frequency = dm.dmDisplayFrequency; + success = GHOST_kSuccess; + } + else { + success = GHOST_kFailure; + } + return success; +} + + +GHOST_TSuccess GHOST_DisplayManagerWin32::getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerWin32::getCurrentDisplaySetting(): only main display is supported"); + return getDisplaySetting(kMainDisplay, ENUM_CURRENT_SETTINGS, setting); +} + + +GHOST_TSuccess GHOST_DisplayManagerWin32::setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting) +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerWin32::setCurrentDisplaySetting(): only main display is supported"); + + GHOST_DisplaySetting match; + GHOST_TSuccess success = findMatch(display, setting, match); + DEVMODE dm; + int i = 0; + while (::EnumDisplaySettings(NULL, i++, &dm)) { + if ((dm.dmBitsPerPel == match.bpp) && + (dm.dmPelsWidth == match.xPixels) && + (dm.dmPelsHeight == match.yPixels) && + (dm.dmDisplayFrequency == match.frequency)) { + break; + } + } + /* + dm.dmBitsPerPel = match.bpp; + dm.dmPelsWidth = match.xPixels; + dm.dmPelsHeight = match.yPixels; + dm.dmDisplayFrequency = match.frequency; + dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; + dm.dmSize = sizeof(DEVMODE); + dm.dmDriverExtra = 0; + */ +#ifdef GHOST_DEBUG + printf("display change: Requested settings:\n"); + printf(" dmBitsPerPel=%d\n", dm.dmBitsPerPel); + printf(" dmPelsWidth=%d\n", dm.dmPelsWidth); + printf(" dmPelsHeight=%d\n", dm.dmPelsHeight); + printf(" dmDisplayFrequency=%d\n", dm.dmDisplayFrequency); +#endif // GHOST_DEBUG + + LONG status = ::ChangeDisplaySettings(&dm, CDS_FULLSCREEN); +#ifdef GHOST_DEBUG + switch (status) + { + case DISP_CHANGE_SUCCESSFUL: + printf("display change: The settings change was successful.\n"); + break; + case DISP_CHANGE_RESTART: + printf("display change: The computer must be restarted in order for the graphics mode to work.\n"); + break; + case DISP_CHANGE_BADFLAGS: + printf("display change: An invalid set of flags was passed in.\n"); + break; + case DISP_CHANGE_BADPARAM: + printf("display change: An invalid parameter was passed in. This can include an invalid flag or combination of flags.\n"); + break; + case DISP_CHANGE_FAILED: + printf("display change: The display driver failed the specified graphics mode.\n"); + break; + case DISP_CHANGE_BADMODE: + printf("display change: The graphics mode is not supported.\n"); + break; + case DISP_CHANGE_NOTUPDATED: + printf("display change: Windows NT: Unable to write settings to the registry.\n"); + break; + default: + printf("display change: Return value invalid\n"); + break; + } +#endif // GHOST_DEBUG + return status == DISP_CHANGE_SUCCESSFUL? GHOST_kSuccess : GHOST_kFailure; +} diff --git a/intern/ghost/intern/GHOST_DisplayManagerWin32.h b/intern/ghost/intern/GHOST_DisplayManagerWin32.h new file mode 100644 index 00000000000..71fc56257f8 --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManagerWin32.h @@ -0,0 +1,104 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_DisplayManagerWin32.h + * Declaration of GHOST_DisplayManagerWin32 class. + */ + +#ifndef _GHOST_DISPLAY_MANAGER_WIN32_H_ +#define _GHOST_DISPLAY_MANAGER_WIN32_H_ + +#ifndef WIN32 +#error WIN32 only! +#endif // WIN32 + +#include "GHOST_DisplayManager.h" + + +/** + * Manages system displays (WIN32 implementation). + * @author Maarten Gribnau + * @date September 21, 2001 + */ +class GHOST_DisplayManagerWin32 : public GHOST_DisplayManager +{ +public: + /** + * Constructor. + */ + GHOST_DisplayManagerWin32(void); + + /** + * Returns the number of display devices on this system. + * @param numDisplays The number of displays on this system. + * @return Indication of success. + */ + virtual GHOST_TSuccess getNumDisplays(GHOST_TUns8& numDisplays) const; + + /** + * Returns the number of display settings for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The number of settings of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param index The setting index to be returned. + * @param setting The setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The current setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const; + + /** + * Changes the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The current setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting); + +protected: +}; + + +#endif // _GHOST_DISPLAY_MANAGER_WIN32_H_ + diff --git a/intern/ghost/intern/GHOST_DisplayManagerX11.cpp b/intern/ghost/intern/GHOST_DisplayManagerX11.cpp new file mode 100644 index 00000000000..9695e24e737 --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManagerX11.cpp @@ -0,0 +1,128 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_DisplayManagerX11.h" +#include "GHOST_SystemX11.h" + + + +GHOST_DisplayManagerX11:: +GHOST_DisplayManagerX11( + GHOST_SystemX11 *system +) : + GHOST_DisplayManager(), + m_system(system) +{ + //nothing to do. +} + + GHOST_TSuccess +GHOST_DisplayManagerX11:: +getNumDisplays( + GHOST_TUns8& numDisplays +) const{ + numDisplays = m_system->getNumDisplays(); + return GHOST_kSuccess; +} + + + GHOST_TSuccess +GHOST_DisplayManagerX11:: +getNumDisplaySettings( + GHOST_TUns8 display, + GHOST_TInt32& numSettings +) const{ + + // We only have one X11 setting at the moment. + GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n"); + numSettings = GHOST_TInt32(1); + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_DisplayManagerX11:: +getDisplaySetting( + GHOST_TUns8 display, + GHOST_TInt32 index, + GHOST_DisplaySetting& setting +) const { + + GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n"); + GHOST_ASSERT(index < 1, "Requested setting outside of valid range.\n"); + + Display * x_display = m_system->getXDisplay(); + + if (x_display == NULL) { + return GHOST_kFailure; + } + + setting.xPixels = DisplayWidth(x_display, DefaultScreen(x_display)); + setting.yPixels = DisplayHeight(x_display, DefaultScreen(x_display)); + setting.bpp = DefaultDepth(x_display,DefaultScreen(x_display)); + + // Don't think it's possible to get this value from X! + // So let's guess!! + setting.frequency = 60; + + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_DisplayManagerX11:: +getCurrentDisplaySetting( + GHOST_TUns8 display, + GHOST_DisplaySetting& setting +) const { + return getDisplaySetting(display,GHOST_TInt32(0),setting); +} + + + GHOST_TSuccess +GHOST_DisplayManagerX11:: +setCurrentDisplaySetting( + GHOST_TUns8 display, + const GHOST_DisplaySetting& setting +){ + // This is never going to work robustly in X + // but it's currently part of the full screen interface + + // we fudge it for now. + + return GHOST_kSuccess; +} + + + + diff --git a/intern/ghost/intern/GHOST_DisplayManagerX11.h b/intern/ghost/intern/GHOST_DisplayManagerX11.h new file mode 100644 index 00000000000..18226a25e74 --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManagerX11.h @@ -0,0 +1,126 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_DisplayManagerX11.h + * Declaration of GHOST_DisplayManagerX11 class. + */ + +#ifndef _GHOST_DISPLAY_MANAGER_X11_H_ +#define _GHOST_DISPLAY_MANAGER_X11_H_ + +#include "GHOST_DisplayManager.h" + + +class GHOST_SystemX11; + +/** + * Manages system displays (X11 implementation). + * @author Laurence Bourn + * @date October 26, 2001 + */ +class GHOST_DisplayManagerX11 : public GHOST_DisplayManager +{ +public: + /** + * Constructor. + */ + GHOST_DisplayManagerX11( + GHOST_SystemX11 *system + ); + + /** + * Returns the number of display devices on this system. + * @param numDisplays The number of displays on this system. + * @return Indication of success. + */ + GHOST_TSuccess + getNumDisplays( + GHOST_TUns8& numDisplays + ) const; + + /** + * Returns the number of display settings for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The number of settings of the display device with this index. + * @return Indication of success. + */ + GHOST_TSuccess + getNumDisplaySettings( + GHOST_TUns8 display, + GHOST_TInt32& numSettings + ) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param index The setting index to be returned. + * @param setting The setting of the display device with this index. + * @return Indication of success. + */ + GHOST_TSuccess + getDisplaySetting( + GHOST_TUns8 display, + GHOST_TInt32 index, + GHOST_DisplaySetting& setting + ) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The current setting of the display device with this index. + * @return Indication of success. + */ + GHOST_TSuccess + getCurrentDisplaySetting( + GHOST_TUns8 display, + GHOST_DisplaySetting& setting + ) const; + + /** + * Changes the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The current setting of the display device with this index. + * @return Indication of success. + */ + GHOST_TSuccess + setCurrentDisplaySetting( + GHOST_TUns8 display, + const GHOST_DisplaySetting& setting + ); + +private : + + GHOST_SystemX11 * m_system; +}; + + +#endif // + diff --git a/intern/ghost/intern/GHOST_Event.h b/intern/ghost/intern/GHOST_Event.h new file mode 100644 index 00000000000..e4844f9bab5 --- /dev/null +++ b/intern/ghost/intern/GHOST_Event.h @@ -0,0 +1,110 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_Event.h + * Declaration of GHOST_Event class. + */ + +#ifndef _GHOST_EVENT_H_ +#define _GHOST_EVENT_H_ + +#include "GHOST_IEvent.h" + + +/** + * Base class for events received the operating system. + * @author Maarten Gribnau + * @date May 11, 2001 + */ +class GHOST_Event : public GHOST_IEvent +{ +public: + /** + * Constructor. + * @param msec The time this event was generated. + * @param type The type of this event. + * @param window The generating window (or NULL if system event). + */ + GHOST_Event(GHOST_TUns64 msec, GHOST_TEventType type, GHOST_IWindow* window) + : m_type(type), m_time(msec), m_window(window), m_data(0) + { + } + + /** + * Returns the event type. + * @return The event type. + */ + virtual GHOST_TEventType getType() + { + return m_type; + } + + /** + * Returns the time this event was generated. + * @return The event generation time. + */ + virtual GHOST_TUns64 getTime() + { + return m_time; + } + + /** + * Returns the window this event was generated on, + * or NULL if it is a 'system' event. + * @return The generating window. + */ + virtual GHOST_IWindow* getWindow() + { + return m_window; + } + + /** + * Returns the event data. + * @return The event data. + */ + virtual GHOST_TEventDataPtr getData() + { + return m_data; + } + +protected: + /** Type of this event. */ + GHOST_TEventType m_type; + /** The time this event was generated. */ + GHOST_TUns64 m_time; + /** Pointer to the generating window. */ + GHOST_IWindow* m_window; + /** Pointer to the event data. */ + GHOST_TEventDataPtr m_data; +}; + +#endif // _GHOST_EVENT_H_ + diff --git a/intern/ghost/intern/GHOST_EventButton.h b/intern/ghost/intern/GHOST_EventButton.h new file mode 100644 index 00000000000..c808fd44430 --- /dev/null +++ b/intern/ghost/intern/GHOST_EventButton.h @@ -0,0 +1,70 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_EventButton.h + * Declaration of GHOST_EventButton class. + */ + +#ifndef _GHOST_EVENT_BUTTON_H_ +#define _GHOST_EVENT_BUTTON_H_ + +#include "GHOST_Event.h" + +/** + * Mouse button event. + * @author Maarten Gribnau + * @date May 11, 2001 + */ +class GHOST_EventButton : public GHOST_Event +{ +public: + /** + * Constructor. + * @param time The time this event was generated. + * @param type The type of this event. + * @param x The x-coordinate of the location the cursor was at at the time of the event. + * @param y The y-coordinate of the location the cursor was at at the time of the event. + * @param buttons The state of the buttons was at at the time of the event. + */ + GHOST_EventButton(GHOST_TUns64 time, GHOST_TEventType type, GHOST_IWindow* window, GHOST_TButtonMask button) + : GHOST_Event(time, type, window) + { + m_buttonEventData.button = button; + m_data = &m_buttonEventData; + } + +protected: + /** The button event data. */ + GHOST_TEventButtonData m_buttonEventData; +}; + +#endif // _GHOST_EVENT_BUTTON_H_ + diff --git a/intern/ghost/intern/GHOST_EventCursor.h b/intern/ghost/intern/GHOST_EventCursor.h new file mode 100644 index 00000000000..a174242653e --- /dev/null +++ b/intern/ghost/intern/GHOST_EventCursor.h @@ -0,0 +1,71 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_EventCursor.h + * Declaration of GHOST_EventCursor class. + */ + +#ifndef _GHOST_EVENT_CURSOR_H_ +#define _GHOST_EVENT_CURSOR_H_ + +#include "GHOST_Event.h" + +/** + * Cursor event. + * @author Maarten Gribnau + * @date May 11, 2001 + */ +class GHOST_EventCursor : public GHOST_Event +{ +public: + /** + * Constructor. + * @param msec The time this event was generated. + * @param type The type of this event. + * @param x The x-coordinate of the location the cursor was at at the time of the event. + * @param y The y-coordinate of the location the cursor was at at the time of the event. + */ + GHOST_EventCursor(GHOST_TUns64 msec, GHOST_TEventType type, GHOST_IWindow* window, GHOST_TInt32 x, GHOST_TInt32 y) + : GHOST_Event(msec, type, window) + { + m_cursorEventData.x = x; + m_cursorEventData.y = y; + m_data = &m_cursorEventData; + } + +protected: + /** The x,y-coordinates of the cursor position. */ + GHOST_TEventCursorData m_cursorEventData; +}; + + +#endif // _GHOST_EVENT_CURSOR_H_ + diff --git a/intern/ghost/intern/GHOST_EventKey.h b/intern/ghost/intern/GHOST_EventKey.h new file mode 100644 index 00000000000..b170d5a9a48 --- /dev/null +++ b/intern/ghost/intern/GHOST_EventKey.h @@ -0,0 +1,84 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_EventKey.h + * Declaration of GHOST_EventKey class. + */ + +#ifndef _GHOST_EVENT_KEY_H_ +#define _GHOST_EVENT_KEY_H_ + +#include "GHOST_Event.h" + +/** + * Key event. + * @author Maarten Gribnau + * @date May 11, 2001 + */ +class GHOST_EventKey : public GHOST_Event +{ +public: + /** + * Constructor. + * @param msec The time this event was generated. + * @param type The type of key event. + * @param key The key code of the key. + */ + GHOST_EventKey(GHOST_TUns64 msec, GHOST_TEventType type, GHOST_IWindow* window, GHOST_TKey key) + : GHOST_Event(msec, type, window) + { + m_keyEventData.key = key; + m_keyEventData.ascii = '\0'; + m_data = &m_keyEventData; + } + + /** + * Constructor. + * @param msec The time this event was generated. + * @param type The type of key event. + * @param key The key code of the key. + * @param ascii The ascii code for the key event. + */ + GHOST_EventKey(GHOST_TUns64 msec, GHOST_TEventType type, GHOST_IWindow* window, GHOST_TKey key, char ascii) + : GHOST_Event(msec, type, window) + { + m_keyEventData.key = key; + m_keyEventData.ascii = ascii; + m_data = &m_keyEventData; + } + +protected: + /** The key event data. */ + GHOST_TEventKeyData m_keyEventData; +}; + +#endif // _GHOST_EVENT_KEY_H_ + diff --git a/intern/ghost/intern/GHOST_EventManager.cpp b/intern/ghost/intern/GHOST_EventManager.cpp new file mode 100644 index 00000000000..ba20cce12fd --- /dev/null +++ b/intern/ghost/intern/GHOST_EventManager.cpp @@ -0,0 +1,261 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 14, 2001 + */ + +#include "GHOST_EventManager.h" +#include +#include "GHOST_Debug.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + + +GHOST_EventManager::GHOST_EventManager() +{ +} + + +GHOST_EventManager::~GHOST_EventManager() +{ + disposeEvents(); +} + + +GHOST_TUns32 GHOST_EventManager::getNumEvents() +{ + return (GHOST_TUns32) m_events.size(); +} + + +GHOST_TUns32 GHOST_EventManager::getNumEvents(GHOST_TEventType type) +{ + GHOST_TUns32 numEvents = 0; + TEventStack::iterator p; + for (p = m_events.begin(); p != m_events.end(); p++) { + if ((*p)->getType() == type) { + numEvents++; + } + } + return numEvents; +} + + +GHOST_IEvent* GHOST_EventManager::peekEvent() +{ + GHOST_IEvent* event = 0; + if (m_events.size() > 0) { + event = m_events.back(); + } + return event; +} + + +GHOST_TSuccess GHOST_EventManager::pushEvent(GHOST_IEvent* event) +{ + GHOST_TSuccess success; + GHOST_ASSERT(event, "invalid event"); + if (m_events.size() < m_events.max_size()) { + m_events.push_front(event); + success = GHOST_kSuccess; + } + else { + success = GHOST_kFailure; + } + return success; +} + + +bool GHOST_EventManager::dispatchEvent(GHOST_IEvent* event) +{ + bool handled; + if (event) { + handled = true; + TConsumerVector::iterator iter; + for (iter = m_consumers.begin(); iter != m_consumers.end(); iter++) { + if ((*iter)->processEvent(event)) { + handled = false; + } + } + } + else { + handled = false; + } + return handled; +} + + +bool GHOST_EventManager::dispatchEvent() +{ + GHOST_IEvent* event = popEvent(); + bool handled = false; + if (event) { + handled = dispatchEvent(event); + delete event; + } + return handled; +} + + +bool GHOST_EventManager::dispatchEvents() +{ + bool handled; + if (getNumEvents()) { + handled = true; + while (getNumEvents()) { + if (!dispatchEvent()) { + handled = false; + } + } + } + else { + handled = false; + } + return handled; +} + + +GHOST_TSuccess GHOST_EventManager::addConsumer(GHOST_IEventConsumer* consumer) +{ + GHOST_TSuccess success; + GHOST_ASSERT(consumer, "invalid consumer"); + + // Check to see whether the consumer is already in our list + TConsumerVector::const_iterator iter = std::find(m_consumers.begin(), m_consumers.end(), consumer); + + if (iter == m_consumers.end()) { + // Add the consumer + m_consumers.push_back(consumer); + success = GHOST_kSuccess; + } + else { + success = GHOST_kFailure; + } + return success; +} + + +GHOST_TSuccess GHOST_EventManager::removeConsumer(GHOST_IEventConsumer* consumer) +{ + GHOST_TSuccess success; + GHOST_ASSERT(consumer, "invalid consumer"); + + // Check to see whether the consumer is in our list + TConsumerVector::iterator iter = std::find(m_consumers.begin(), m_consumers.end(), consumer); + + if (iter != m_consumers.end()) { + // Remove the consumer + m_consumers.erase(iter); + success = GHOST_kSuccess; + } + else { + success = GHOST_kFailure; + } + return success; +} + + +void GHOST_EventManager::removeWindowEvents(GHOST_IWindow* window) +{ + TEventStack::iterator iter; + iter = m_events.begin(); + while (iter != m_events.end()) + { + GHOST_IEvent* event = *iter; + if (event->getWindow() == window) + { + GHOST_PRINT("GHOST_EventManager::removeWindowEvents(): removing event\n"); + /* + * Found an event for this window, remove it. + * The iterator will become invalid. + */ + delete event; + m_events.erase(iter); + iter = m_events.begin(); + } + else + { + iter++; + } + } +} + +void GHOST_EventManager::removeTypeEvents(GHOST_TEventType type, GHOST_IWindow* window) +{ + TEventStack::iterator iter; + iter = m_events.begin(); + while (iter != m_events.end()) + { + GHOST_IEvent* event = *iter; + if ((event->getType() == type) && (!window || (event->getWindow() == window))) + { + GHOST_PRINT("GHOST_EventManager::removeTypeEvents(): removing event\n"); + /* + * Found an event of this type for the window, remove it. + * The iterator will become invalid. + */ + delete event; + m_events.erase(iter); + iter = m_events.begin(); + } + else + { + iter++; + } + } +} + + +GHOST_IEvent* GHOST_EventManager::popEvent() +{ + GHOST_IEvent* event = peekEvent(); + if (event) { + m_events.pop_back(); + } + return event; +} + + +void GHOST_EventManager::disposeEvents() +{ + while (m_events.size() > 0) { + GHOST_ASSERT(m_events[0], "invalid event"); + delete m_events[0]; + m_events.pop_front(); + } +} diff --git a/intern/ghost/intern/GHOST_EventManager.h b/intern/ghost/intern/GHOST_EventManager.h new file mode 100644 index 00000000000..068ded8ddee --- /dev/null +++ b/intern/ghost/intern/GHOST_EventManager.h @@ -0,0 +1,181 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_EventManager.h + * Declaration of GHOST_EventManager class. + */ + +#ifndef _GHOST_EVENT_MANAGER_H_ +#define _GHOST_EVENT_MANAGER_H_ + +#ifdef WIN32 +#pragma warning (disable:4786) // suppress stl-MSVC debug info warning +#endif // WIN32 + +#include +#include + +#include "GHOST_IEventConsumer.h" + + +/** + * Manages an event stack and a list of event consumers. + * The stack works on a FIFO (First In First Out) basis. + * Events are pushed on the front of the stack and retrieved from the back. + * Ownership of the event is transferred to the event manager as soon as an event is pushed. + * Ownership of the event is transferred from the event manager as soon as an event is popped. + * Events can be dispatched to the event consumers. + */ +class GHOST_EventManager +{ +public: + /** + * Constructor. + */ + GHOST_EventManager(); + + /** + * Destructor. + */ + virtual ~GHOST_EventManager(); + + /** + * Returns the number of events currently on the stack. + * @return The number of events on the stack. + */ + virtual GHOST_TUns32 getNumEvents(); + + /** + * Returns the number of events of a certain type currently on the stack. + * @param type The type of events to be counted. + * @return The number of events on the stack of this type. + */ + virtual GHOST_TUns32 getNumEvents(GHOST_TEventType type); + + /** + * Return the event at the top of the stack without removal. + * Do not delete the event! + * @return The event at the top of the stack. + */ + virtual GHOST_IEvent* peekEvent(); + + /** + * Pushes an event on the stack. + * To dispatch it, call dispatchEvent() or dispatchEvents(). + * Do not delete the event! + * @param event The event to push on the stack. + */ + virtual GHOST_TSuccess pushEvent(GHOST_IEvent* event); + + /** + * Dispatches the given event directly, bypassing the event stack. + * @return Indication as to whether any of the consumers handled the event. + */ + virtual bool dispatchEvent(GHOST_IEvent* event); + + /** + * Dispatches the event at the back of the stack. + * The event will be removed from the stack. + * @return Indication as to whether any of the consumers handled the event. + */ + virtual bool dispatchEvent(); + + /** + * Dispatches all the events on the stack. + * The event stack will be empty afterwards. + * @return Indication as to whether any of the consumers handled the events. + */ + virtual bool dispatchEvents(); + + /** + * Adds a consumer to the list of event consumers. + * @param consumer The consumer added to the list. + * @return Indication as to whether addition has succeeded. + */ + virtual GHOST_TSuccess addConsumer(GHOST_IEventConsumer* consumer); + + /** + * Removes a consumer from the list of event consumers. + * @param consumer The consumer removed from the list. + * @return Indication as to whether removal has succeeded. + */ + virtual GHOST_TSuccess removeConsumer(GHOST_IEventConsumer* consumer); + + /** + * Removes all events for a window from the stack. + * @param window The window to remove events for. + */ + virtual void + removeWindowEvents( + GHOST_IWindow* window + ); + + /** + * Removes all events of a certain type from the stack. + * The window parameter is optional. If non-null, the routine will remove + * events only associated with that window. + * @param type The type of events to be removed. + * @param window The window to remove the events for. + */ + virtual void + removeTypeEvents( + GHOST_TEventType type, + GHOST_IWindow* window = 0 + ); + +protected: + /** + * Returns the event at the top of the stack and removes it. + * Delete the event after use! + * @return The event at the top of the stack. + */ + virtual GHOST_IEvent* popEvent(); + + /** + * Removes all events from the stack. + */ + virtual void disposeEvents(); + + /** A stack with events. */ + typedef std::deque TEventStack; + + /** The event stack. */ + std::deque m_events; + + /** A vector with event consumers. */ + typedef std::vector TConsumerVector; + + /** The list with event consumers. */ + TConsumerVector m_consumers; +}; + +#endif // _GHOST_EVENT_MANAGER_H_ + diff --git a/intern/ghost/intern/GHOST_EventPrinter.cpp b/intern/ghost/intern/GHOST_EventPrinter.cpp new file mode 100644 index 00000000000..ad65d1fbb18 --- /dev/null +++ b/intern/ghost/intern/GHOST_EventPrinter.cpp @@ -0,0 +1,282 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_EventPrinter.h + * Declaration of GHOST_EventPrinter class. + */ + +#include "GHOST_EventPrinter.h" +#include +#include "GHOST_EventKey.h" +#include "GHOST_Debug.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + + +bool GHOST_EventPrinter::processEvent(GHOST_IEvent* event) +{ + bool handled = true; + + GHOST_ASSERT(event, "event==0"); + + if (event->getType() == GHOST_kEventWindowUpdate) return false; + + //std::cout << "GHOST_EventPrinter::processEvent, time: " << (GHOST_TInt32)event->getTime() << ", type: "; + switch (event->getType()) { + case GHOST_kEventUnknown: + //std::cout << "GHOST_kEventUnknown"; handled = false; + break; + + case GHOST_kEventButtonUp: + { + GHOST_TEventButtonData* buttonData = (GHOST_TEventButtonData*)((GHOST_IEvent*)event)->getData(); + //std::cout << "GHOST_kEventCursorButtonUp, button: " << buttonData->button; + } + break; + case GHOST_kEventButtonDown: + { + GHOST_TEventButtonData* buttonData = (GHOST_TEventButtonData*)((GHOST_IEvent*)event)->getData(); + //std::cout << "GHOST_kEventButtonDown, button: " << buttonData->button; + } + break; + + case GHOST_kEventWheel: + { + GHOST_TEventWheelData* wheelData = (GHOST_TEventWheelData*)((GHOST_IEvent*)event)->getData(); + //std::cout << "GHOST_kEventWheel, z: " << wheelData->z; + } + break; + + case GHOST_kEventCursorMove: + { + GHOST_TEventCursorData* cursorData = (GHOST_TEventCursorData*)((GHOST_IEvent*)event)->getData(); + //std::cout << "GHOST_kEventCursorMove, (x,y): (" << cursorData->x << "," << cursorData->y << ")"; + } + break; + + case GHOST_kEventKeyUp: + { + GHOST_TEventKeyData* keyData = (GHOST_TEventKeyData*)((GHOST_IEvent*)event)->getData(); + STR_String str; + getKeyString(keyData->key, str); + //std::cout << "GHOST_kEventKeyUp, key: " << str.Ptr(); + } + break; + case GHOST_kEventKeyDown: + { + GHOST_TEventKeyData* keyData = (GHOST_TEventKeyData*)((GHOST_IEvent*)event)->getData(); + STR_String str; + getKeyString(keyData->key, str); + //std::cout << "GHOST_kEventKeyDown, key: " << str.Ptr(); + } + break; + + case GHOST_kEventQuit: + //std::cout << "GHOST_kEventQuit"; + break; + case GHOST_kEventWindowClose: + //std::cout << "GHOST_kEventWindowClose"; + break; + case GHOST_kEventWindowActivate: + //std::cout << "GHOST_kEventWindowActivate"; + break; + case GHOST_kEventWindowDeactivate: + //std::cout << "GHOST_kEventWindowDeactivate"; + break; + case GHOST_kEventWindowUpdate: + //std::cout << "GHOST_kEventWindowUpdate"; + break; + case GHOST_kEventWindowSize: + //std::cout << "GHOST_kEventWindowSize"; + break; + + default: + //std::cout << "not found"; handled = false; + break; + } + //std::cout << "\n"; + return handled; +} + + +void GHOST_EventPrinter::getKeyString(GHOST_TKey key, STR_String& str) const +{ + if ((key >= GHOST_kKeyComma) && (key <= GHOST_kKeyRightBracket)) { + str = ((char)key); + } else if ((key >= GHOST_kKeyNumpad0) && (key <= GHOST_kKeyNumpad9)) { + int number = key - GHOST_kKeyNumpad0; + STR_String numberStr (number); + str = "Numpad"; + str += numberStr; +#if defined(__sun__) || defined(__sun) + } else if (key == 268828432) { /* solaris keyboards are messed up */ + /* This should really test XK_F11 but that doesn't work */ + str = "F11"; + } else if (key == 268828433) { /* solaris keyboards are messed up */ + /* This should really test XK_F12 but that doesn't work */ + str = "F12"; +#endif + } else if ((key >= GHOST_kKeyF1) && (key <= GHOST_kKeyF24)) { + int number = key - GHOST_kKeyF1 + 1; + STR_String numberStr (number); + str = "F"; + str += numberStr; + } else { + switch (key) + { + case GHOST_kKeyBackSpace: + str = "BackSpace"; + break; + case GHOST_kKeyTab: + str = "Tab"; + break; + case GHOST_kKeyLinefeed: + str = "Linefeed"; + break; + case GHOST_kKeyClear: + str = "Clear"; + break; + case GHOST_kKeyEnter: + str = "Enter"; + break; + case GHOST_kKeyEsc: + str = "Esc"; + break; + case GHOST_kKeySpace: + str = "Space"; + break; + case GHOST_kKeyQuote: + str = "Quote"; + break; + case GHOST_kKeyBackslash: + str = "\\"; + break; + case GHOST_kKeyAccentGrave: + str = "`"; + break; + case GHOST_kKeyLeftShift: + str = "LeftShift"; + break; + case GHOST_kKeyRightShift: + str = "RightShift"; + break; + case GHOST_kKeyLeftControl: + str = "LeftControl"; + break; + case GHOST_kKeyRightControl: + str = "RightControl"; + break; + case GHOST_kKeyLeftAlt: + str = "LeftAlt"; + break; + case GHOST_kKeyRightAlt: + str = "RightAlt"; + break; + case GHOST_kKeyCommand: + // APPLE only! + str = "Command"; + break; + case GHOST_kKeyGrLess: + // PC german! + str = "GrLess"; + break; + case GHOST_kKeyCapsLock: + str = "CapsLock"; + break; + case GHOST_kKeyNumLock: + str = "NumLock"; + break; + case GHOST_kKeyScrollLock: + str = "ScrollLock"; + break; + case GHOST_kKeyLeftArrow: + str = "LeftArrow"; + break; + case GHOST_kKeyRightArrow: + str = "RightArrow"; + break; + case GHOST_kKeyUpArrow: + str = "UpArrow"; + break; + case GHOST_kKeyDownArrow: + str = "DownArrow"; + break; + case GHOST_kKeyPrintScreen: + str = "PrintScreen"; + break; + case GHOST_kKeyPause: + str = "Pause"; + break; + case GHOST_kKeyInsert: + str = "Insert"; + break; + case GHOST_kKeyDelete: + str = "Delete"; + break; + case GHOST_kKeyHome: + str = "Home"; + break; + case GHOST_kKeyEnd: + str = "End"; + break; + case GHOST_kKeyUpPage: + str = "UpPage"; + break; + case GHOST_kKeyDownPage: + str = "DownPage"; + break; + case GHOST_kKeyNumpadPeriod: + str = "NumpadPeriod"; + break; + case GHOST_kKeyNumpadEnter: + str = "NumpadEnter"; + break; + case GHOST_kKeyNumpadPlus: + str = "NumpadPlus"; + break; + case GHOST_kKeyNumpadMinus: + str = "NumpadMinus"; + break; + case GHOST_kKeyNumpadAsterisk: + str = "NumpadAsterisk"; + break; + case GHOST_kKeyNumpadSlash: + str = "NumpadSlash"; + break; + default: + str = "unknown"; + break; + } + } +} + diff --git a/intern/ghost/intern/GHOST_EventPrinter.h b/intern/ghost/intern/GHOST_EventPrinter.h new file mode 100644 index 00000000000..9838d2fb6d5 --- /dev/null +++ b/intern/ghost/intern/GHOST_EventPrinter.h @@ -0,0 +1,67 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_EventPrinter.h + * Declaration of GHOST_EventPrinter class. + */ + +#ifndef _GHOST_EVENT_PRINTER_H_ +#define _GHOST_EVENT_PRINTER_H_ + +#include "GHOST_IEventConsumer.h" + +#include "STR_String.h" + +/** + * An Event consumer that prints all the events to standard out. + * Really useful when debugging. + */ +class GHOST_EventPrinter : public GHOST_IEventConsumer +{ +public: + /** + * Prints all the events received to std out. + * @param event The event that can be handled or not. + * @return Indication as to whether the event was handled. + */ + virtual bool processEvent(GHOST_IEvent* event); + +protected: + /** + * Converts GHOST key code to a readable string. + * @param key The GHOST key code to convert. + * @param str The GHOST key code converted to a readable string. + */ + void getKeyString(GHOST_TKey key, STR_String& str) const; +}; + +#endif // _GHOST_EVENT_PRINTER_H_ + diff --git a/intern/ghost/intern/GHOST_EventWheel.h b/intern/ghost/intern/GHOST_EventWheel.h new file mode 100644 index 00000000000..7776a1778db --- /dev/null +++ b/intern/ghost/intern/GHOST_EventWheel.h @@ -0,0 +1,71 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_EventWheel.h + * Declaration of GHOST_EventWheel class. + */ + +#ifndef _GHOST_EVENT_WHEEL_H_ +#define _GHOST_EVENT_WHEEL_H_ + +#include "GHOST_Event.h" + +/** + * Mouse wheel event. + * The displacement of the mouse wheel is counted in ticks. + * A positive value means the wheel is turned away from the user. + * @author Maarten Gribnau + * @date May 11, 2001 + */ +class GHOST_EventWheel : public GHOST_Event +{ +public: + /** + * Constructor. + * @param msec The time this event was generated. + * @param type The type of this event. + * @param z The displacement of the mouse wheel. + */ + GHOST_EventWheel(GHOST_TUns64 msec, GHOST_IWindow* window, GHOST_TInt32 z) + : GHOST_Event(msec, GHOST_kEventWheel, window) + { + m_wheelEventData.z = z; + m_data = &m_wheelEventData; + } + +protected: + /** The z-displacement of the mouse wheel. */ + GHOST_TEventWheelData m_wheelEventData; +}; + + +#endif // _GHOST_EVENT_WHEEL_H_ + diff --git a/intern/ghost/intern/GHOST_ISystem.cpp b/intern/ghost/intern/GHOST_ISystem.cpp new file mode 100644 index 00000000000..677978973aa --- /dev/null +++ b/intern/ghost/intern/GHOST_ISystem.cpp @@ -0,0 +1,102 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 7, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_ISystem.h" + +#ifdef WIN32 +# include "GHOST_SystemWin32.h" +#else +# ifdef __APPLE__ +# include "GHOST_SystemCarbon.h" +# else +# include "GHOST_SystemX11.h" +# endif +#endif + + +GHOST_ISystem* GHOST_ISystem::m_system = 0; + + +GHOST_TSuccess GHOST_ISystem::createSystem() +{ + GHOST_TSuccess success; + if (!m_system) { +#ifdef WIN32 + m_system = new GHOST_SystemWin32 (); +#else +# ifdef __APPLE__ + m_system = new GHOST_SystemCarbon (); +# else + m_system = new GHOST_SystemX11 (); +# endif +#endif + success = m_system != 0 ? GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kFailure; + } + if (success) { + success = m_system->init(); + } + return success; +} + +GHOST_TSuccess GHOST_ISystem::disposeSystem() +{ + GHOST_TSuccess success = GHOST_kSuccess; + if (m_system) { + delete m_system; + m_system = 0; + } + else { + success = GHOST_kFailure; + } + return success; +} + + +GHOST_ISystem* GHOST_ISystem::getSystem() +{ + return m_system; +} + diff --git a/intern/ghost/intern/GHOST_ModifierKeys.cpp b/intern/ghost/intern/GHOST_ModifierKeys.cpp new file mode 100644 index 00000000000..36293d87c26 --- /dev/null +++ b/intern/ghost/intern/GHOST_ModifierKeys.cpp @@ -0,0 +1,142 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 31, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_ModifierKeys.h" + + +GHOST_ModifierKeys::GHOST_ModifierKeys() +{ + clear(); +} + +GHOST_ModifierKeys::~GHOST_ModifierKeys() {} + + +GHOST_TKey GHOST_ModifierKeys::getModifierKeyCode(GHOST_TModifierKeyMask mask) +{ + GHOST_TKey key; + switch (mask) { + case GHOST_kModifierKeyLeftShift: key = GHOST_kKeyLeftShift; break; + case GHOST_kModifierKeyRightShift: key = GHOST_kKeyRightShift; break; + case GHOST_kModifierKeyLeftAlt: key = GHOST_kKeyLeftAlt; break; + case GHOST_kModifierKeyRightAlt: key = GHOST_kKeyRightAlt; break; + case GHOST_kModifierKeyLeftControl: key = GHOST_kKeyLeftControl; break; + case GHOST_kModifierKeyRightControl: key = GHOST_kKeyRightControl; break; + case GHOST_kModifierKeyCommand: key = GHOST_kKeyCommand; break; + default: + // Should not happen + key = GHOST_kKeyUnknown; + break; + } + return key; +} + + +bool GHOST_ModifierKeys::get(GHOST_TModifierKeyMask mask) const +{ + switch (mask) { + case GHOST_kModifierKeyLeftShift: + return m_LeftShift; + case GHOST_kModifierKeyRightShift: + return m_RightShift; + case GHOST_kModifierKeyLeftAlt: + return m_LeftAlt; + case GHOST_kModifierKeyRightAlt: + return m_RightAlt; + case GHOST_kModifierKeyLeftControl: + return m_LeftControl; + case GHOST_kModifierKeyRightControl: + return m_RightControl; + case GHOST_kModifierKeyCommand: + return m_Command; + default: + return false; + } +} + + +void GHOST_ModifierKeys::set(GHOST_TModifierKeyMask mask, bool down) +{ + switch (mask) { + case GHOST_kModifierKeyLeftShift: + m_LeftShift = down; break; + case GHOST_kModifierKeyRightShift: + m_RightShift = down; break; + case GHOST_kModifierKeyLeftAlt: + m_LeftAlt = down; break; + case GHOST_kModifierKeyRightAlt: + m_RightAlt = down; break; + case GHOST_kModifierKeyLeftControl: + m_LeftControl = down; break; + case GHOST_kModifierKeyRightControl: + m_RightControl = down; break; + case GHOST_kModifierKeyCommand: + m_Command = down; break; + default: + break; + } +} + + +void GHOST_ModifierKeys::clear() +{ + m_LeftShift = false; + m_RightShift = false; + m_LeftAlt = false; + m_RightAlt = false; + m_LeftControl = false; + m_RightControl = false; + m_Command = false; +} + + +bool GHOST_ModifierKeys::equals(const GHOST_ModifierKeys& keys) const +{ + return (m_LeftShift == keys.m_LeftShift) && + (m_RightShift == keys.m_RightShift) && + (m_LeftAlt == keys.m_LeftAlt) && + (m_RightAlt == keys.m_RightAlt) && + (m_LeftControl == keys.m_LeftControl) && + (m_RightControl == keys.m_RightControl) && + (m_Command == keys.m_Command); +} diff --git a/intern/ghost/intern/GHOST_ModifierKeys.h b/intern/ghost/intern/GHOST_ModifierKeys.h new file mode 100644 index 00000000000..6b26dd5829e --- /dev/null +++ b/intern/ghost/intern/GHOST_ModifierKeys.h @@ -0,0 +1,107 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_ModifierKeys.h + * Declaration of GHOST_ModifierKeys struct. + */ + +#ifndef _GHOST_MODIFIER_KEYS_H_ +#define _GHOST_MODIFIER_KEYS_H_ + +#include "GHOST_Types.h" + +/** + * Stores the state of modifier keys. + * Discriminates between left and right modifier keys. + * @author Maarten Gribnau + * @date May 17, 2001 + */ +struct GHOST_ModifierKeys +{ + /** + * Constructor. + */ + GHOST_ModifierKeys(); + + virtual ~GHOST_ModifierKeys(); + + /** + * Returns the modifier key's key code from a modifier key mask. + * @param mask The mask of the modifier key. + * @return The modifier key's key code. + */ + static GHOST_TKey getModifierKeyCode(GHOST_TModifierKeyMask mask); + + + /** + * Returns the state of a single modifier key. + * @param mask. Key state to return. + * @return The state of the key (pressed == true). + */ + virtual bool get(GHOST_TModifierKeyMask mask) const; + + /** + * Updates the state of a single modifier key. + * @param mask. Key state to update. + * @param down. The new state of the key. + */ + virtual void set(GHOST_TModifierKeyMask mask, bool down); + + /** + * Sets the state of all modifier keys to up. + */ + virtual void clear(); + + /** + * Determines whether to modifier key states are equal. + * @param keys. The modifier key state to compare to. + * @return Indication of equality. + */ + virtual bool equals(const GHOST_ModifierKeys& keys) const; + + /** Bitfield that stores the appropriate key state. */ + GHOST_TUns8 m_LeftShift : 1; + /** Bitfield that stores the appropriate key state. */ + GHOST_TUns8 m_RightShift : 1; + /** Bitfield that stores the appropriate key state. */ + GHOST_TUns8 m_LeftAlt : 1; + /** Bitfield that stores the appropriate key state. */ + GHOST_TUns8 m_RightAlt : 1; + /** Bitfield that stores the appropriate key state. */ + GHOST_TUns8 m_LeftControl : 1; + /** Bitfield that stores the appropriate key state. */ + GHOST_TUns8 m_RightControl : 1; + /** Bitfield that stores the appropriate key state. APPLE only! */ + GHOST_TUns8 m_Command : 1; +}; + +#endif // _GHOST_MODIFIER_KEYS_H_ + diff --git a/intern/ghost/intern/GHOST_Rect.cpp b/intern/ghost/intern/GHOST_Rect.cpp new file mode 100644 index 00000000000..70773fe1497 --- /dev/null +++ b/intern/ghost/intern/GHOST_Rect.cpp @@ -0,0 +1,144 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_Rect.h" + + + +void GHOST_Rect::inset(GHOST_TInt32 i) +{ + if (i > 0) { + // Grow the rectangle + m_l -= i; + m_r += i; + m_t -= i; + m_b += i; + } + else if (i < 0) { + // Shrink the rectangle, check for insets larger than half the size + GHOST_TInt32 i2 = i * 2; + if (getWidth() > i2) { + m_l += i; + m_r -= i; + } + else { + m_l = m_l + ((m_r - m_l) / 2); + m_r = m_l; + } + if (getHeight() > i2) { + m_t += i; + m_b -= i; + } + else { + m_t = m_t + ((m_b - m_t) / 2); + m_b = m_t; + } + } +} + + +GHOST_TVisibility GHOST_Rect::getVisibility(GHOST_Rect& r) const +{ + bool lt = isInside(r.m_l, r.m_t); + bool rt = isInside(r.m_r, r.m_t); + bool lb = isInside(r.m_l, r.m_b); + bool rb = isInside(r.m_r, r.m_b); + GHOST_TVisibility v; + if (lt && rt && lb && rb) { + // All points inside, rectangle is inside this + v = GHOST_kFullyVisible; + } + else if (!(lt || rt || lb || rb)) { + // None of the points inside + // Check to see whether the rectangle is larger than this one + if ((r.m_l < m_l) && (r.m_t < m_t) && (r.m_r > m_r) && (r.m_b > m_b)) { + v = GHOST_kPartiallyVisible; + } + else { + v = GHOST_kNotVisible; + } + } + else { + // Some of the points inside, rectangle is partially inside + v = GHOST_kPartiallyVisible; + } + return v; +} + + +void GHOST_Rect::setCenter(GHOST_TInt32 cx, GHOST_TInt32 cy) +{ + GHOST_TInt32 offset = cx - (m_l + (m_r - m_l)/2); + m_l += offset; + m_r += offset; + offset = cy - (m_t + (m_b - m_t)/2); + m_t += offset; + m_b += offset; +} + +void GHOST_Rect::setCenter(GHOST_TInt32 cx, GHOST_TInt32 cy, GHOST_TInt32 w, GHOST_TInt32 h) +{ + long w_2, h_2; + + w_2 = w >> 1; + h_2 = h >> 1; + m_l = cx - w_2; + m_t = cy - h_2; + m_r = m_l + w; + m_b = m_t + h; +} + +bool GHOST_Rect::clip(GHOST_Rect& r) const +{ + bool clipped = false; + if (r.m_l < m_l) { + r.m_l = m_l; + clipped = true; + } + if (r.m_t < m_t) { + r.m_t = m_t; + clipped = true; + } + if (r.m_r > m_r) { + r.m_r = m_r; + clipped = true; + } + if (r.m_b > m_b) { + r.m_b = m_b; + clipped = true; + } + return clipped; +} + diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp new file mode 100644 index 00000000000..d91658787b9 --- /dev/null +++ b/intern/ghost/intern/GHOST_System.cpp @@ -0,0 +1,331 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 7, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_System.h" + +#include + +#include "GHOST_DisplayManager.h" +#include "GHOST_EventManager.h" +#include "GHOST_TimerTask.h" +#include "GHOST_TimerManager.h" +#include "GHOST_WindowManager.h" + + +GHOST_System::GHOST_System() +: m_displayManager(0), m_timerManager(0), m_windowManager(0), m_eventManager(0) +{ +} + + +GHOST_System::~GHOST_System() +{ + exit(); +} + + +GHOST_TUns64 GHOST_System::getMilliSeconds() const +{ + GHOST_TUns64 millis = ::clock(); + if (CLOCKS_PER_SEC != 1000) { + millis *= 1000; + millis /= CLOCKS_PER_SEC; + } + return millis; +} + + +GHOST_ITimerTask* GHOST_System::installTimer(GHOST_TUns64 delay, GHOST_TUns64 interval, GHOST_TimerProcPtr timerProc, GHOST_TUserDataPtr userData) +{ + GHOST_TUns64 millis = getMilliSeconds(); + GHOST_TimerTask* timer = new GHOST_TimerTask(millis+delay, interval, timerProc, userData); + if (timer) { + if (m_timerManager->addTimer(timer) == GHOST_kSuccess) { + // Check to see whether we need to fire the timer right away + m_timerManager->fireTimers(millis); + } + else { + delete timer; + timer = 0; + } + } + return timer; +} + + +GHOST_TSuccess GHOST_System::removeTimer(GHOST_ITimerTask* timerTask) +{ + GHOST_TSuccess success = GHOST_kFailure; + if (timerTask) { + success = m_timerManager->removeTimer((GHOST_TimerTask*)timerTask); + } + return success; +} + + +GHOST_TSuccess GHOST_System::disposeWindow(GHOST_IWindow* window) +{ + GHOST_TSuccess success; + + /* + * Remove all pending events for the window. + */ + if (m_windowManager->getWindowFound(window)) { + m_eventManager->removeWindowEvents(window); + } + if (window == m_windowManager->getFullScreenWindow()) { + success = endFullScreen(); + } + else { + if (m_windowManager->getWindowFound(window)) { + success = m_windowManager->removeWindow(window); + if (success) { + delete window; + } + } + else { + success = GHOST_kFailure; + } + } + return success; +} + + +bool GHOST_System::validWindow(GHOST_IWindow* window) +{ + return m_windowManager->getWindowFound(window); +} + + +GHOST_TSuccess GHOST_System::beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow** window, + const bool stereoVisual) +{ + GHOST_TSuccess success = GHOST_kFailure; + GHOST_ASSERT(m_windowManager, "GHOST_System::beginFullScreen(): invalid window manager") + if (m_displayManager) { + if (!m_windowManager->getFullScreen()) { + m_displayManager->getCurrentDisplaySetting(GHOST_DisplayManager::kMainDisplay, m_preFullScreenSetting); + + //GHOST_PRINT("GHOST_System::beginFullScreen(): activating new display settings\n"); + success = m_displayManager->setCurrentDisplaySetting(GHOST_DisplayManager::kMainDisplay, setting); + if (success == GHOST_kSuccess) { + //GHOST_PRINT("GHOST_System::beginFullScreen(): creating full-screen window\n"); + success = createFullScreenWindow((GHOST_Window**)window, stereoVisual); + if (success == GHOST_kSuccess) { + m_windowManager->beginFullScreen(*window, stereoVisual); + } + else { + m_displayManager->setCurrentDisplaySetting(GHOST_DisplayManager::kMainDisplay, m_preFullScreenSetting); + } + } + } + } + if (success == GHOST_kFailure) { + GHOST_PRINT("GHOST_System::beginFullScreen(): could not enter full-screen mode\n"); + } + return success; +} + + +GHOST_TSuccess GHOST_System::endFullScreen(void) +{ + GHOST_TSuccess success = GHOST_kFailure; + GHOST_ASSERT(m_windowManager, "GHOST_System::endFullScreen(): invalid window manager") + if (m_windowManager->getFullScreen()) { + //GHOST_IWindow* window = m_windowManager->getFullScreenWindow(); + //GHOST_PRINT("GHOST_System::endFullScreen(): leaving window manager full-screen mode\n"); + success = m_windowManager->endFullScreen(); + GHOST_ASSERT(m_displayManager, "GHOST_System::endFullScreen(): invalid display manager") + //GHOST_PRINT("GHOST_System::endFullScreen(): leaving full-screen mode\n"); + success = m_displayManager->setCurrentDisplaySetting(GHOST_DisplayManager::kMainDisplay, m_preFullScreenSetting); + } + else { + success = GHOST_kFailure; + } + return success; +} + + +bool GHOST_System::getFullScreen(void) +{ + bool fullScreen; + if (m_windowManager) { + fullScreen = m_windowManager->getFullScreen(); + } + else { + fullScreen = false; + } + return fullScreen; +} + + +bool GHOST_System::dispatchEvents() +{ + bool handled; + if (m_eventManager) { + handled = m_eventManager->dispatchEvents(); + } + else { + handled = false; + } + + m_timerManager->fireTimers(getMilliSeconds()); + return handled; +} + + +GHOST_TSuccess GHOST_System::addEventConsumer(GHOST_IEventConsumer* consumer) +{ + GHOST_TSuccess success; + if (m_eventManager) { + success = m_eventManager->addConsumer(consumer); + } + else { + success = GHOST_kFailure; + } + return success; +} + + +GHOST_TSuccess GHOST_System::pushEvent(GHOST_IEvent* event) +{ + GHOST_TSuccess success; + if (m_eventManager) { + success = m_eventManager->pushEvent(event); + } + else { + success = GHOST_kFailure; + } + return success; +} + + +GHOST_TSuccess GHOST_System::getModifierKeyState(GHOST_TModifierKeyMask mask, bool& isDown) const +{ + GHOST_ModifierKeys keys; + // Get the state of all modifier keys + GHOST_TSuccess success = getModifierKeys(keys); + if (success) { + // Isolate the state of the key requested + isDown = keys.get(mask); + } + return success; +} + + +GHOST_TSuccess GHOST_System::getButtonState(GHOST_TButtonMask mask, bool& isDown) const +{ + GHOST_Buttons buttons; + // Get the state of all mouse buttons + GHOST_TSuccess success = getButtons(buttons); + if (success) { + // Isolate the state of the mouse button requested + isDown = buttons.get(mask); + } + return success; +} + + +GHOST_TSuccess GHOST_System::init() +{ + m_timerManager = new GHOST_TimerManager (); + m_windowManager = new GHOST_WindowManager (); + m_eventManager = new GHOST_EventManager (); +#ifdef GHOST_DEBUG + if (m_eventManager) { + m_eventManager->addConsumer(&m_eventPrinter); + } +#endif // GHOST_DEBUG + + if (m_timerManager && m_windowManager && m_eventManager) { + return GHOST_kSuccess; + } else { + return GHOST_kFailure; + } +} + + +GHOST_TSuccess GHOST_System::exit() +{ + if (getFullScreen()) { + endFullScreen(); + } + if (m_displayManager) { + delete m_displayManager; + m_displayManager = 0; + } + if (m_windowManager) { + delete m_windowManager; + m_windowManager = 0; + } + if (m_timerManager) { + delete m_timerManager; + m_timerManager = 0; + } + if (m_eventManager) { + delete m_eventManager; + m_eventManager = 0; + } + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window** window, const bool stereoVisual) +{ + GHOST_TSuccess success; + GHOST_ASSERT(m_displayManager, "GHOST_System::createFullScreenWindow(): invalid display manager") + GHOST_DisplaySetting settings; + + success = m_displayManager->getCurrentDisplaySetting(GHOST_DisplayManager::kMainDisplay, settings); + if (success) { + //GHOST_PRINT("GHOST_System::createFullScreenWindow(): creating full-screen window\n"); + *window = (GHOST_Window*)createWindow( + STR_String (""), + 0, 0, settings.xPixels, settings.yPixels, + GHOST_kWindowStateFullScreen, + GHOST_kDrawingContextTypeOpenGL, + stereoVisual); + success = *window == 0 ? GHOST_kFailure : GHOST_kSuccess; + } + return success; +} diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h new file mode 100644 index 00000000000..85e7b2d6b44 --- /dev/null +++ b/intern/ghost/intern/GHOST_System.h @@ -0,0 +1,318 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_System.h + * Declaration of GHOST_System class. + */ + +#ifndef _GHOST_SYSTEM_H_ +#define _GHOST_SYSTEM_H_ + +#include "GHOST_ISystem.h" + +#include "GHOST_Debug.h" +#include "GHOST_Buttons.h" +#include "GHOST_ModifierKeys.h" +#include "GHOST_EventManager.h" +#ifdef GHOST_DEBUG +#include "GHOST_EventPrinter.h" +#endif // GHOST_DEBUG + +class GHOST_DisplayManager; +class GHOST_Event; +class GHOST_TimerManager; +class GHOST_Window; +class GHOST_WindowManager; + +/** + * Implementation of platform independent functionality of the GHOST_ISystem + * interface. + * GHOST_System is an abstract class because not all methods of GHOST_ISystem + * are implemented. + * @see GHOST_ISystem. + * @author Maarten Gribnau + * @date May 7, 2001 + */ +class GHOST_System : public GHOST_ISystem +{ +protected: + /** + * Constructor. + * Protected default constructor to force use of static createSystem member. + */ + GHOST_System(); + + /** + * Destructor. + * Protected default constructor to force use of static dispose member. + */ + virtual ~GHOST_System(); + +public: + /*************************************************************************************** + ** Time(r) functionality + ***************************************************************************************/ + + /** + * Returns the system time. + * Returns the number of milliseconds since the start of the system process. + * Based on ANSI clock() routine. + * @return The number of milliseconds. + */ + virtual GHOST_TUns64 getMilliSeconds() const; + + /** + * Installs a timer. + * Note that, on most operating systems, messages need to be processed in order + * for the timer callbacks to be invoked. + * @param delay The time to wait for the first call to the timerProc (in milliseconds) + * @param interval The interval between calls to the timerProc + * @param timerProc The callback invoked when the interval expires, + * @param userData Placeholder for user data. + * @return A timer task (0 if timer task installation failed). + */ + virtual GHOST_ITimerTask* installTimer(GHOST_TUns64 delay, GHOST_TUns64 interval, GHOST_TimerProcPtr timerProc, GHOST_TUserDataPtr userData = 0); + + /** + * Removes a timer. + * @param timerTask Timer task to be removed. + * @return Indication of success. + */ + virtual GHOST_TSuccess removeTimer(GHOST_ITimerTask* timerTask); + + /*************************************************************************************** + ** Display/window management functionality + ***************************************************************************************/ + + /** + * Inherited from GHOST_ISystem but left pure virtual + * + * virtual GHOST_TUns8 getNumDisplays() const = 0; + * virtual void getMainDisplayDimensions(...) const = 0; + * virtual GHOST_IWindow* createWindow(..) + */ + + /** + * Dispose a window. + * @param window Pointer to the window to be disposed. + * @return Indication of success. + */ + virtual GHOST_TSuccess disposeWindow(GHOST_IWindow* window); + + /** + * Returns whether a window is valid. + * @param window Pointer to the window to be checked. + * @return Indication of validity. + */ + virtual bool validWindow(GHOST_IWindow* window); + + /** + * Begins full screen mode. + * @param setting The new setting of the display. + * @param window Window displayed in full screen. + * @param stereoVisual Stereo visual for quad buffered stereo. + * This window is invalid after full screen has been ended. + * @return Indication of success. + */ + virtual GHOST_TSuccess beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow** window, + const bool stereoVisual); + + /** + * Ends full screen mode. + * @return Indication of success. + */ + virtual GHOST_TSuccess endFullScreen(void); + + /** + * Returns current full screen mode status. + * @return The current status. + */ + virtual bool getFullScreen(void); + + + /*************************************************************************************** + ** Event management functionality + ***************************************************************************************/ + + /** + * Inherited from GHOST_ISystem but left pure virtual + * + * virtual bool processEvents(bool waitForEvent) = 0; + */ + + + + /** + * Dispatches all the events on the stack. + * The event stack will be empty afterwards. + * @return Indication as to whether any of the consumers handled the events. + */ + virtual bool dispatchEvents(); + + /** + * Adds the given event consumer to our list. + * @param consumer The event consumer to add. + * @return Indication of success. + */ + virtual GHOST_TSuccess addEventConsumer(GHOST_IEventConsumer* consumer); + + /*************************************************************************************** + ** Cursor management functionality + ***************************************************************************************/ + + /** Inherited from GHOST_ISystem but left pure virtual + * GHOST_TSuccess getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const = 0; + * GHOST_TSuccess setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) + */ + + /*************************************************************************************** + ** Access to mouse button and keyboard states. + ***************************************************************************************/ + + /** + * Returns the state of a modifier key (ouside the message queue). + * @param mask The modifier key state to retrieve. + * @param isDown The state of a modifier key (true == pressed). + * @return Indication of success. + */ + virtual GHOST_TSuccess getModifierKeyState(GHOST_TModifierKeyMask mask, bool& isDown) const; + + /** + * Returns the state of a mouse button (ouside the message queue). + * @param mask The button state to retrieve. + * @param isDown Button state. + * @return Indication of success. + */ + virtual GHOST_TSuccess getButtonState(GHOST_TButtonMask mask, bool& isDown) const; + + /*************************************************************************************** + ** Other (internal) functionality. + ***************************************************************************************/ + + /** + * Pushes an event on the stack. + * To dispatch it, call dispatchEvent() or dispatchEvents(). + * Do not delete the event! + * @param event The event to push on the stack. + */ + virtual GHOST_TSuccess pushEvent(GHOST_IEvent* event); + + /** + * Returns the timer manager. + * @return The timer manager. + */ + inline virtual GHOST_TimerManager* getTimerManager() const; + + /** + * Returns a pointer to our event manager. + * @return A pointer to our event manager. + */ + virtual inline GHOST_EventManager* getEventManager() const; + + /** + * Returns a pointer to our window manager. + * @return A pointer to our window manager. + */ + virtual inline GHOST_WindowManager* getWindowManager() const; + + /** + * Returns the state of all modifier keys. + * @param keys The state of all modifier keys (true == pressed). + * @return Indication of success. + */ + virtual GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys& keys) const = 0; + + /** + * Returns the state of the mouse buttons (ouside the message queue). + * @param buttons The state of the buttons. + * @return Indication of success. + */ + virtual GHOST_TSuccess getButtons(GHOST_Buttons& buttons) const = 0; + +protected: + /** + * Initialize the system. + * @return Indication of success. + */ + virtual GHOST_TSuccess init(); + + /** + * Shut the system down. + * @return Indication of success. + */ + virtual GHOST_TSuccess exit(); + + /** + * Creates a fullscreen window. + * @param window The window created. + * @return Indication of success. + */ + virtual GHOST_TSuccess createFullScreenWindow(GHOST_Window** window, + const bool stereoVisual); + + /** The display manager (platform dependant). */ + GHOST_DisplayManager* m_displayManager; + + /** The timer manager. */ + GHOST_TimerManager* m_timerManager; + + /** The window manager. */ + GHOST_WindowManager* m_windowManager; + + /** The event manager. */ + GHOST_EventManager* m_eventManager; + + /** Prints all the events. */ +#ifdef GHOST_DEBUG + GHOST_EventPrinter m_eventPrinter; +#endif // GHOST_DEBUG + + /** Settings of the display before the display went fullscreen. */ + GHOST_DisplaySetting m_preFullScreenSetting; +}; + +inline GHOST_TimerManager* GHOST_System::getTimerManager() const +{ + return m_timerManager; +} + +inline GHOST_EventManager* GHOST_System::getEventManager() const +{ + return m_eventManager; +} + +inline GHOST_WindowManager* GHOST_System::getWindowManager() const +{ + return m_windowManager; +} + +#endif // _GHOST_SYSTEM_H_ + diff --git a/intern/ghost/intern/GHOST_SystemCarbon.cpp b/intern/ghost/intern/GHOST_SystemCarbon.cpp new file mode 100644 index 00000000000..e1e3853e8a8 --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemCarbon.cpp @@ -0,0 +1,1067 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 7, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_SystemCarbon.h" + +#include "GHOST_DisplayManagerCarbon.h" +#include "GHOST_EventKey.h" +#include "GHOST_EventButton.h" +#include "GHOST_EventCursor.h" +#include "GHOST_EventWheel.h" +#include "GHOST_TimerManager.h" +#include "GHOST_TimerTask.h" +#include "GHOST_WindowManager.h" +#include "GHOST_WindowCarbon.h" + +#define GHOST_KEY_SWITCH(mac, ghost) { case (mac): ghostKey = (ghost); break; } + +const EventTypeSpec kEvents[] = +{ + { kEventClassAppleEvent, kEventAppleEvent }, + +/* + { kEventClassApplication, kEventAppActivated }, + { kEventClassApplication, kEventAppDeactivated }, +*/ + + { kEventClassKeyboard, kEventRawKeyDown }, + { kEventClassKeyboard, kEventRawKeyRepeat }, + { kEventClassKeyboard, kEventRawKeyUp }, + { kEventClassKeyboard, kEventRawKeyModifiersChanged }, + + { kEventClassMouse, kEventMouseDown }, + { kEventClassMouse, kEventMouseUp }, + { kEventClassMouse, kEventMouseMoved }, + { kEventClassMouse, kEventMouseDragged }, + { kEventClassMouse, kEventMouseWheelMoved }, + + { kEventClassWindow, kEventWindowClickZoomRgn } , /* for new zoom behaviour */ + { kEventClassWindow, kEventWindowZoom }, /* for new zoom behaviour */ + { kEventClassWindow, kEventWindowExpand } , /* for new zoom behaviour */ + { kEventClassWindow, kEventWindowExpandAll }, /* for new zoom behaviour */ + + { kEventClassWindow, kEventWindowClose }, + { kEventClassWindow, kEventWindowActivated }, + { kEventClassWindow, kEventWindowDeactivated }, + { kEventClassWindow, kEventWindowUpdate }, + { kEventClassWindow, kEventWindowBoundsChanged } + +}; + + + +static GHOST_TButtonMask convertButton(EventMouseButton button) +{ + switch (button) { + case kEventMouseButtonPrimary: + return GHOST_kButtonMaskLeft; + case kEventMouseButtonSecondary: + return GHOST_kButtonMaskRight; + case kEventMouseButtonTertiary: + default: + return GHOST_kButtonMaskMiddle; + } +} + +static GHOST_TKey convertKey(int rawCode) +{ + /* This bit of magic converts the rawCode into a virtual + * Mac key based on the current keyboard mapping, but + * without regard to the modifiers (so we don't get 'a' + * and 'A' for example. + */ + static UInt32 dummy= 0; + Handle transData = (Handle) GetScriptManagerVariable(smKCHRCache); + unsigned char vk = KeyTranslate(transData, rawCode, &dummy); + /* Map numpad based on rawcodes first, otherwise they + * look like non-numpad events. + * Added too: mapping the number keys, for french keyboards etc (ton) + */ + // printf("GHOST: vk: %d %c raw: %d\n", vk, vk, rawCode); + + switch (rawCode) { + case 18: return GHOST_kKey1; + case 19: return GHOST_kKey2; + case 20: return GHOST_kKey3; + case 21: return GHOST_kKey4; + case 23: return GHOST_kKey5; + case 22: return GHOST_kKey6; + case 26: return GHOST_kKey7; + case 28: return GHOST_kKey8; + case 25: return GHOST_kKey9; + case 29: return GHOST_kKey0; + + case 82: return GHOST_kKeyNumpad0; + case 83: return GHOST_kKeyNumpad1; + case 84: return GHOST_kKeyNumpad2; + case 85: return GHOST_kKeyNumpad3; + case 86: return GHOST_kKeyNumpad4; + case 87: return GHOST_kKeyNumpad5; + case 88: return GHOST_kKeyNumpad6; + case 89: return GHOST_kKeyNumpad7; + case 91: return GHOST_kKeyNumpad8; + case 92: return GHOST_kKeyNumpad9; + case 65: return GHOST_kKeyNumpadPeriod; + case 76: return GHOST_kKeyNumpadEnter; + case 69: return GHOST_kKeyNumpadPlus; + case 78: return GHOST_kKeyNumpadMinus; + case 67: return GHOST_kKeyNumpadAsterisk; + case 75: return GHOST_kKeyNumpadSlash; + } + + if ((vk >= 'a') && (vk <= 'z')) { + return (GHOST_TKey) (vk - 'a' + GHOST_kKeyA); + } else if ((vk >= '0') && (vk <= '9')) { + return (GHOST_TKey) (vk - '0' + GHOST_kKey0); + } else if (vk==16) { + switch (rawCode) { + case 122: return GHOST_kKeyF1; + case 120: return GHOST_kKeyF2; + case 99: return GHOST_kKeyF3; + case 118: return GHOST_kKeyF4; + case 96: return GHOST_kKeyF5; + case 97: return GHOST_kKeyF6; + case 98: return GHOST_kKeyF7; + case 100: return GHOST_kKeyF8; + case 101: return GHOST_kKeyF9; + case 109: return GHOST_kKeyF10; + case 103: return GHOST_kKeyF11; + case 111: return GHOST_kKeyF12; // Never get, is used for ejecting the CD! + } + } else { + switch (vk) { + case kUpArrowCharCode: return GHOST_kKeyUpArrow; + case kDownArrowCharCode: return GHOST_kKeyDownArrow; + case kLeftArrowCharCode: return GHOST_kKeyLeftArrow; + case kRightArrowCharCode: return GHOST_kKeyRightArrow; + + case kReturnCharCode: return GHOST_kKeyEnter; + case kBackspaceCharCode: return GHOST_kKeyBackSpace; + case kDeleteCharCode: return GHOST_kKeyDelete; + case kEscapeCharCode: return GHOST_kKeyEsc; + case kTabCharCode: return GHOST_kKeyTab; + case kSpaceCharCode: return GHOST_kKeySpace; + + case kHomeCharCode: return GHOST_kKeyHome; + case kEndCharCode: return GHOST_kKeyEnd; + case kPageUpCharCode: return GHOST_kKeyUpPage; + case kPageDownCharCode: return GHOST_kKeyDownPage; + + case '-': return GHOST_kKeyMinus; + case '=': return GHOST_kKeyEqual; + case ',': return GHOST_kKeyComma; + case '.': return GHOST_kKeyPeriod; + case '/': return GHOST_kKeySlash; + case ';': return GHOST_kKeySemicolon; + case '\'': return GHOST_kKeyQuote; + case '\\': return GHOST_kKeyBackslash; + case '[': return GHOST_kKeyLeftBracket; + case ']': return GHOST_kKeyRightBracket; + case '`': return GHOST_kKeyAccentGrave; + } + } + + // printf("GHOST: unknown key: %d %d\n", vk, rawCode); + + return GHOST_kKeyUnknown; +} + +/* MacOSX returns a Roman charset with kEventParamKeyMacCharCodes + * as defined here: http://developer.apple.com/documentation/mac/Text/Text-516.html + * I am not sure how international this works... + * For cross-platform convention, we'll use the Latin ascii set instead. + * As defined at: http://www.ramsch.org/martin/uni/fmi-hp/iso8859-1.html + * + */ +static unsigned char convertRomanToLatin(unsigned char ascii) +{ + + if(ascii<128) return ascii; + + switch(ascii) { + case 128: return 142; + case 129: return 143; + case 130: return 128; + case 131: return 201; + case 132: return 209; + case 133: return 214; + case 134: return 220; + case 135: return 225; + case 136: return 224; + case 137: return 226; + case 138: return 228; + case 139: return 227; + case 140: return 229; + case 141: return 231; + case 142: return 233; + case 143: return 232; + case 144: return 234; + case 145: return 235; + case 146: return 237; + case 147: return 236; + case 148: return 238; + case 149: return 239; + case 150: return 241; + case 151: return 243; + case 152: return 242; + case 153: return 244; + case 154: return 246; + case 155: return 245; + case 156: return 250; + case 157: return 249; + case 158: return 251; + case 159: return 252; + case 160: return 0; + case 161: return 176; + case 162: return 162; + case 163: return 163; + case 164: return 167; + case 165: return 183; + case 166: return 182; + case 167: return 223; + case 168: return 174; + case 169: return 169; + case 170: return 174; + case 171: return 180; + case 172: return 168; + case 173: return 0; + case 174: return 198; + case 175: return 216; + case 176: return 0; + case 177: return 177; + case 178: return 0; + case 179: return 0; + case 180: return 165; + case 181: return 181; + case 182: return 0; + case 183: return 0; + case 184: return 215; + case 185: return 0; + case 186: return 0; + case 187: return 170; + case 188: return 186; + case 189: return 0; + case 190: return 230; + case 191: return 248; + case 192: return 191; + case 193: return 161; + case 194: return 172; + case 195: return 0; + case 196: return 0; + case 197: return 0; + case 198: return 0; + case 199: return 171; + case 200: return 187; + case 201: return 201; + case 202: return 0; + case 203: return 192; + case 204: return 195; + case 205: return 213; + case 206: return 0; + case 207: return 0; + case 208: return 0; + case 209: return 0; + case 210: return 0; + + case 214: return 247; + + case 229: return 194; + case 230: return 202; + case 231: return 193; + case 232: return 203; + case 233: return 200; + case 234: return 205; + case 235: return 206; + case 236: return 207; + case 237: return 204; + case 238: return 211; + case 239: return 212; + case 240: return 0; + case 241: return 210; + case 242: return 218; + case 243: return 219; + case 244: return 217; + case 245: return 0; + case 246: return 0; + case 247: return 0; + case 248: return 0; + case 249: return 0; + case 250: return 0; + + + default: return 0; + } + +} + + +/***/ + +GHOST_SystemCarbon::GHOST_SystemCarbon() : + m_modifierMask(0) +{ + m_displayManager = new GHOST_DisplayManagerCarbon (); + GHOST_ASSERT(m_displayManager, "GHOST_SystemCarbon::GHOST_SystemCarbon(): m_displayManager==0\n"); + m_displayManager->initialize(); + + UnsignedWide micros; + ::Microseconds(µs); + m_start_time = UnsignedWideToUInt64(micros)/1000; + m_ignoreWindowSizedMessages = false; +} + +GHOST_SystemCarbon::~GHOST_SystemCarbon() +{ +} + + +GHOST_TUns64 GHOST_SystemCarbon::getMilliSeconds() const +{ + UnsignedWide micros; + ::Microseconds(µs); + UInt64 millis; + millis = UnsignedWideToUInt64(micros); + return (millis / 1000) - m_start_time; +} + + +GHOST_TUns8 GHOST_SystemCarbon::getNumDisplays() const +{ + // We do not support multiple monitors at the moment + return 1; +} + + +void GHOST_SystemCarbon::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const +{ + BitMap screenBits; + Rect bnds = GetQDGlobalsScreenBits(&screenBits)->bounds; + width = bnds.right - bnds.left; + height = bnds.bottom - bnds.top; +} + + +GHOST_IWindow* GHOST_SystemCarbon::createWindow( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + bool stereoVisual +) +{ + GHOST_IWindow* window = 0; + + window = new GHOST_WindowCarbon (title, left, top, width, height, state, type); + + if (window) { + if (window->getValid()) { + // Store the pointer to the window + GHOST_ASSERT(m_windowManager, "m_windowManager not initialized"); + m_windowManager->addWindow(window); + m_windowManager->setActiveWindow(window); + pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window)); + } + else { + GHOST_PRINT("GHOST_SystemCarbon::createWindow(): window invalid\n"); + delete window; + window = 0; + } + } + else { + GHOST_PRINT("GHOST_SystemCarbon::createWindow(): could not create window\n"); + } + return window; +} + + +bool GHOST_SystemCarbon::processEvents(bool waitForEvent) +{ + bool anyProcessed = false; + EventRef event; + + do { + GHOST_TimerManager* timerMgr = getTimerManager(); + + if (waitForEvent) { + GHOST_TUns64 curtime = getMilliSeconds(); + GHOST_TUns64 next = timerMgr->nextFireTime(); + double timeOut; + + if (next == GHOST_kFireTimeNever) { + timeOut = kEventDurationForever; + } else { + if (next<=curtime) + timeOut = 0.0; + else + timeOut = (double) (next - getMilliSeconds())/1000.0; + } + + ::ReceiveNextEvent(0, NULL, timeOut, false, &event); + } + + if (timerMgr->fireTimers(getMilliSeconds())) { + anyProcessed = true; + } + + if (getFullScreen()) { + // Check if the full-screen window is dirty + GHOST_IWindow* window = m_windowManager->getFullScreenWindow(); + if (((GHOST_WindowCarbon*)window)->getFullScreenDirty()) { + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window) ); + anyProcessed = true; + } + } + + while (::ReceiveNextEvent(0, NULL, 0, true, &event)==noErr) { + OSStatus status= ::SendEventToEventTarget(event, ::GetEventDispatcherTarget()); + if (status==noErr) { + anyProcessed = true; + } else { + UInt32 i= ::GetEventClass(event); + + /* Ignore 'cgs ' class, no documentation on what they + * are, but we get a lot of them + */ + if (i!='cgs ') { + //printf("Missed - Class: '%.4s', Kind: %d\n", &i, ::GetEventKind(event)); + } + } + ::ReleaseEvent(event); + } + } while (waitForEvent && !anyProcessed); + + return anyProcessed; +} + + +GHOST_TSuccess GHOST_SystemCarbon::getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const +{ + Point mouseLoc; + // Get the position of the mouse in the active port + ::GetGlobalMouse(&mouseLoc); + // Convert the coordinates to screen coordinates + x = (GHOST_TInt32)mouseLoc.h; + y = (GHOST_TInt32)mouseLoc.v; + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_SystemCarbon::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) const +{ + float xf=(float)x, yf=(float)y; + + CGAssociateMouseAndMouseCursorPosition(false); + CGSetLocalEventsSuppressionInterval(0); + CGWarpMouseCursorPosition(CGPointMake(xf, yf)); + CGAssociateMouseAndMouseCursorPosition(true); + +//this doesn't work properly, see game engine mouse-look scripts +// CGWarpMouseCursorPosition(CGPointMake(xf, yf)); + // this call below sends event, but empties other events (like shift) + // CGPostMouseEvent(CGPointMake(xf, yf), TRUE, 1, FALSE, 0); + + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_SystemCarbon::getModifierKeys(GHOST_ModifierKeys& keys) const +{ + UInt32 modifiers = ::GetCurrentKeyModifiers(); + + keys.set(GHOST_kModifierKeyCommand, (modifiers & cmdKey) ? true : false); + keys.set(GHOST_kModifierKeyLeftAlt, (modifiers & optionKey) ? true : false); + keys.set(GHOST_kModifierKeyLeftShift, (modifiers & shiftKey) ? true : false); + keys.set(GHOST_kModifierKeyLeftControl, (modifiers & controlKey) ? true : false); + + return GHOST_kSuccess; +} + + /* XXX, incorrect for multibutton mice */ +GHOST_TSuccess GHOST_SystemCarbon::getButtons(GHOST_Buttons& buttons) const +{ + Boolean theOnlyButtonIsDown = ::Button(); + buttons.clear(); + buttons.set(GHOST_kButtonMaskLeft, theOnlyButtonIsDown); + return GHOST_kSuccess; +} + +#define FIRSTFILEBUFLG 512 +static bool g_hasFirstFile = false; +static char g_firstFileBuf[512]; + +extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG]) { + if (g_hasFirstFile) { + strncpy(buf, g_firstFileBuf, FIRSTFILEBUFLG - 1); + buf[FIRSTFILEBUFLG - 1] = '\0'; + return 1; + } else { + return 0; + } +} + +OSErr GHOST_SystemCarbon::sAEHandlerLaunch(const AppleEvent *event, AppleEvent *reply, SInt32 refCon) +{ + //GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon; + + return noErr; +} + +OSErr GHOST_SystemCarbon::sAEHandlerOpenDocs(const AppleEvent *event, AppleEvent *reply, SInt32 refCon) +{ + //GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon; + AEDescList docs; + SInt32 ndocs; + OSErr err; + + err = AEGetParamDesc(event, keyDirectObject, typeAEList, &docs); + if (err != noErr) return err; + + err = AECountItems(&docs, &ndocs); + if (err==noErr) { + int i; + + for (i=0; ipushEvent( new GHOST_Event(sys->getMilliSeconds(), GHOST_kEventQuit, NULL) ); + + return noErr; +} + + +GHOST_TSuccess GHOST_SystemCarbon::init() +{ + GHOST_TSuccess success = GHOST_System::init(); + if (success) { + /* + * Initialize the cursor to the standard arrow shape (so that we can change it later on). + * This initializes the cursor's visibility counter to 0. + */ + ::InitCursor(); + + MenuRef windMenu; + ::CreateStandardWindowMenu(0, &windMenu); + ::InsertMenu(windMenu, 0); + ::DrawMenuBar(); + + ::InstallApplicationEventHandler(sEventHandlerProc, GetEventTypeCount(kEvents), kEvents, this, &m_handler); + + ::AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, sAEHandlerLaunch, (SInt32) this, false); + ::AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, sAEHandlerOpenDocs, (SInt32) this, false); + ::AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, sAEHandlerPrintDocs, (SInt32) this, false); + ::AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, sAEHandlerQuit, (SInt32) this, false); + } + return success; +} + + +GHOST_TSuccess GHOST_SystemCarbon::exit() +{ + return GHOST_System::exit(); +} + + +OSStatus GHOST_SystemCarbon::handleWindowEvent(EventRef event) +{ + WindowRef windowRef; + GHOST_WindowCarbon *window; + OSStatus err = eventNotHandledErr; + + // Check if the event was send to a GHOST window + ::GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &windowRef); + window = (GHOST_WindowCarbon*) ::GetWRefCon(windowRef); + if (!validWindow(window)) { + return err; + } + + //if (!getFullScreen()) { + err = noErr; + switch(::GetEventKind(event)) + { + case kEventWindowClose: + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowClose, window) ); + break; + case kEventWindowActivated: + m_windowManager->setActiveWindow(window); + window->loadCursor(window->getCursorVisibility(), window->getCursorShape()); + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowActivate, window) ); + break; + case kEventWindowDeactivated: + m_windowManager->setWindowInactive(window); + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowDeactivate, window) ); + break; + case kEventWindowUpdate: + //if (getFullScreen()) GHOST_PRINT("GHOST_SystemCarbon::handleWindowEvent(): full-screen update event\n"); + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window) ); + break; + case kEventWindowBoundsChanged: + if (!m_ignoreWindowSizedMessages) + { + window->updateDrawingContext(); + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window) ); + } + break; + default: + err = eventNotHandledErr; + break; + } +// } + //else { + //window = (GHOST_WindowCarbon*) m_windowManager->getFullScreenWindow(); + //GHOST_PRINT("GHOST_SystemCarbon::handleWindowEvent(): full-screen window event, " << window << "\n"); + //::RemoveEventFromQueue(::GetMainEventQueue(), event); + //} + + return err; +} + +OSStatus GHOST_SystemCarbon::handleTabletEvent(EventRef event) +{ + GHOST_IWindow* window = m_windowManager->getActiveWindow(); + TabletPointRec tabletPointRecord; + TabletProximityRec tabletProximityRecord; + UInt32 anInt32; + GHOST_TabletData& ct=((GHOST_WindowCarbon*)window)->GetCarbonTabletData(); + OSStatus err = eventNotHandledErr; + + ct.Pressure = 0; + ct.Xtilt = 0; + ct.Ytilt = 0; + + // is there an embedded tablet event inside this mouse event? + if(noErr == GetEventParameter(event, kEventParamTabletEventType, typeUInt32, NULL, sizeof(UInt32), NULL, (void *)&anInt32)) + { + // yes there is one! + // Embedded tablet events can either be a proximity or pointer event. + if(anInt32 == kEventTabletPoint) + { + //GHOST_PRINT("Embedded pointer event!\n"); + + // Extract the tablet Pointer Event. If there is no Tablet Pointer data + // in this event, then this call will return an error. Just ignore the + // error and go on. This can occur when a proximity event is embedded in + // a mouse event and you did not check the mouse event to see which type + // of tablet event was embedded. + if(noErr == GetEventParameter(event, kEventParamTabletPointRec, + typeTabletPointRec, NULL, + sizeof(TabletPointRec), + NULL, (void *)&tabletPointRecord)) + { + ct.Pressure = tabletPointRecord.pressure / 65535.0f; + ct.Xtilt = tabletPointRecord.tiltX / 32767.0f; /* can be positive or negative */ + ct.Ytilt = tabletPointRecord.tiltY / 32767.0f; /* can be positive or negative */ + } + } else { + //GHOST_PRINT("Embedded proximity event\n"); + + // Extract the Tablet Proximity record from the event. + if(noErr == GetEventParameter(event, kEventParamTabletProximityRec, + typeTabletProximityRec, NULL, + sizeof(TabletProximityRec), + NULL, (void *)&tabletProximityRecord)) + { + if (tabletProximityRecord.enterProximity) { + //pointer is entering tablet area proximity + + switch(tabletProximityRecord.pointerType) + { + case 1: /* stylus */ + ct.Active = 1; + break; + case 2: /* puck, not supported so far */ + ct.Active = 0; + break; + case 3: /* eraser */ + ct.Active = 2; + break; + default: + ct.Active = 0; + break; + } + } else { + // pointer is leaving - return to mouse + ct.Active = 0; + } + } + } + err = noErr; + } +} + +OSStatus GHOST_SystemCarbon::handleMouseEvent(EventRef event) +{ + OSStatus err = eventNotHandledErr; + GHOST_IWindow* window = m_windowManager->getActiveWindow(); + UInt32 kind = ::GetEventKind(event); + + switch (kind) + { + case kEventMouseDown: + case kEventMouseUp: + // Handle Mac application responsibilities + if ((kind == kEventMouseDown) && handleMouseDown(event)) { + err = noErr; + } + else { + GHOST_TEventType type = (kind == kEventMouseDown) ? GHOST_kEventButtonDown : GHOST_kEventButtonUp; + EventMouseButton button; + + /* Window still gets mouse up after command-H */ + if (m_windowManager->getActiveWindow()) { + // handle any tablet events that may have come with the mouse event (optional) + handleTabletEvent(event); + + ::GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button); + pushEvent(new GHOST_EventButton(getMilliSeconds(), type, window, convertButton(button))); + err = noErr; + } + } + break; + + case kEventMouseMoved: + case kEventMouseDragged: { + Point mousePos; + + if (window) { + //handle any tablet events that may have come with the mouse event (optional) + handleTabletEvent(event); + + ::GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &mousePos); + pushEvent(new GHOST_EventCursor(getMilliSeconds(), GHOST_kEventCursorMove, window, mousePos.h, mousePos.v)); + err = noErr; + } + break; + } + case kEventMouseWheelMoved: + { + OSStatus status; + //UInt32 modifiers; + EventMouseWheelAxis axis; + SInt32 delta; + //status = ::GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(modifiers), NULL, &modifiers); + //GHOST_ASSERT(status == noErr, "GHOST_SystemCarbon::handleMouseEvent(): GetEventParameter() failed"); + status = ::GetEventParameter(event, kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis); + GHOST_ASSERT(status == noErr, "GHOST_SystemCarbon::handleMouseEvent(): GetEventParameter() failed"); + if (axis == kEventMouseWheelAxisY) + { + status = ::GetEventParameter(event, kEventParamMouseWheelDelta, typeLongInteger, NULL, sizeof(delta), NULL, &delta); + GHOST_ASSERT(status == noErr, "GHOST_SystemCarbon::handleMouseEvent(): GetEventParameter() failed"); + /* + * Limit mouse wheel delta to plus and minus one. + */ + delta = delta > 0 ? 1 : -1; + pushEvent(new GHOST_EventWheel(getMilliSeconds(), window, delta)); + err = noErr; + } + } + break; + } + + return err; +} + + +OSStatus GHOST_SystemCarbon::handleKeyEvent(EventRef event) +{ + OSStatus err = eventNotHandledErr; + GHOST_IWindow* window = m_windowManager->getActiveWindow(); + UInt32 kind = ::GetEventKind(event); + UInt32 modifiers; + UInt32 rawCode; + GHOST_TKey key; + unsigned char ascii; + + /* Can happen, very rarely - seems to only be when command-H makes + * the window go away and we still get an HKey up. + */ + if (!window) { + //::GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &rawCode); + //key = convertKey(rawCode); + return err; + } + + err = noErr; + switch (kind) { + case kEventRawKeyDown: + case kEventRawKeyRepeat: + case kEventRawKeyUp: + ::GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &rawCode); + ::GetEventParameter(event, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &ascii); + + key = convertKey(rawCode); + ascii= convertRomanToLatin(ascii); + + // if (key!=GHOST_kKeyUnknown) { + GHOST_TEventType type; + if (kind == kEventRawKeyDown) { + type = GHOST_kEventKeyDown; + } else if (kind == kEventRawKeyRepeat) { + type = GHOST_kEventKeyDown; /* XXX, fixme */ + } else { + type = GHOST_kEventKeyUp; + } + pushEvent( new GHOST_EventKey( getMilliSeconds(), type, window, key, ascii) ); +// } + break; + + case kEventRawKeyModifiersChanged: + /* ugh */ + ::GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); + if ((modifiers & shiftKey) != (m_modifierMask & shiftKey)) { + pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & shiftKey)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftShift) ); + } + if ((modifiers & controlKey) != (m_modifierMask & controlKey)) { + pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & controlKey)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftControl) ); + } + if ((modifiers & optionKey) != (m_modifierMask & optionKey)) { + pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & optionKey)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftAlt) ); + } + if ((modifiers & cmdKey) != (m_modifierMask & cmdKey)) { + pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & cmdKey)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyCommand) ); + } + + m_modifierMask = modifiers; + break; + + default: + err = eventNotHandledErr; + break; + } + + return err; +} + + +bool GHOST_SystemCarbon::handleMouseDown(EventRef event) +{ + WindowPtr window; + short part; + BitMap screenBits; + bool handled = true; + GHOST_WindowCarbon* ghostWindow; + Point mousePos = {0 , 0}; + + ::GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &mousePos); + + part = ::FindWindow(mousePos, &window); + ghostWindow = (GHOST_WindowCarbon*) ::GetWRefCon(window); + + switch (part) { + case inMenuBar: + handleMenuCommand(::MenuSelect(mousePos)); + break; + + case inDrag: + /* + * The DragWindow() routine creates a lot of kEventWindowBoundsChanged + * events. By setting m_ignoreWindowSizedMessages these are suppressed. + * @see GHOST_SystemCarbon::handleWindowEvent(EventRef event) + */ + GHOST_ASSERT(validWindow(ghostWindow), "GHOST_SystemCarbon::handleMouseDown: invalid window"); + m_ignoreWindowSizedMessages = true; + ::DragWindow(window, mousePos, &GetQDGlobalsScreenBits(&screenBits)->bounds); + m_ignoreWindowSizedMessages = false; + break; + + case inContent: + if (window != ::FrontWindow()) { + ::SelectWindow(window); + /* + * We add a mouse down event on the newly actived window + */ + //GHOST_PRINT("GHOST_SystemCarbon::handleMouseDown(): adding mouse down event, " << ghostWindow << "\n"); + EventMouseButton button; + ::GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button); + pushEvent(new GHOST_EventButton(getMilliSeconds(), GHOST_kEventButtonDown, ghostWindow, convertButton(button))); + } else { + handled = false; + } + break; + + case inGoAway: + GHOST_ASSERT(ghostWindow, "GHOST_SystemCarbon::handleMouseEvent: ghostWindow==0"); + if (::TrackGoAway(window, mousePos)) + { + // todo: add option-close, because itØs in the HIG + // if (event.modifiers & optionKey) { + // Close the clean documents, others will be confirmed one by one. + //} + // else { + pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowClose, ghostWindow)); + //} + } + break; + + case inGrow: + GHOST_ASSERT(ghostWindow, "GHOST_SystemCarbon::handleMouseEvent: ghostWindow==0"); + ::ResizeWindow(window, mousePos, NULL, NULL); + break; + + case inZoomIn: + case inZoomOut: + GHOST_ASSERT(ghostWindow, "GHOST_SystemCarbon::handleMouseEvent: ghostWindow==0"); + if (::TrackBox(window, mousePos, part)) { + int macState; + + macState = ghostWindow->getMac_windowState(); + if ( macState== 0) + ::ZoomWindow(window, part, true); + else + if (macState == 2) { // always ok + ::ZoomWindow(window, part, true); + ghostWindow->setMac_windowState(1); + } else { // need to force size again + // GHOST_TUns32 scr_x,scr_y; /*unused*/ + Rect outAvailableRect; + + ghostWindow->setMac_windowState(2); + ::GetAvailableWindowPositioningBounds ( GetMainDevice(), &outAvailableRect); + + //this->getMainDisplayDimensions(scr_x,scr_y); + ::SizeWindow (window, outAvailableRect.right-outAvailableRect.left,outAvailableRect.bottom-outAvailableRect.top-1,false); + ::MoveWindow (window, outAvailableRect.left, outAvailableRect.top,true); + } + + } + break; + + default: + handled = false; + break; + } + + return handled; +} + + +bool GHOST_SystemCarbon::handleMenuCommand(GHOST_TInt32 menuResult) +{ + short menuID; + short menuItem; + UInt32 command; + bool handled; + OSErr err; + + menuID = HiWord(menuResult); + menuItem = LoWord(menuResult); + + err = ::GetMenuItemCommandID(::GetMenuHandle(menuID), menuItem, &command); + + handled = false; + + if (err || command == 0) { + } + else { + switch(command) { + } + } + + ::HiliteMenu(0); + return handled; +} + +OSStatus GHOST_SystemCarbon::sEventHandlerProc(EventHandlerCallRef handler, EventRef event, void* userData) +{ + GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) userData; + OSStatus err = eventNotHandledErr; + + switch (::GetEventClass(event)) + { + case kEventClassAppleEvent: + EventRecord eventrec; + if (ConvertEventRefToEventRecord(event, &eventrec)) { + err = AEProcessAppleEvent(&eventrec); + } + break; + case kEventClassMouse: + err = sys->handleMouseEvent(event); + break; + case kEventClassWindow: + err = sys->handleWindowEvent(event); + break; + case kEventClassKeyboard: + err = sys->handleKeyEvent(event); + break; + } + + return err; +} diff --git a/intern/ghost/intern/GHOST_SystemCarbon.h b/intern/ghost/intern/GHOST_SystemCarbon.h new file mode 100644 index 00000000000..93022aa78ff --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemCarbon.h @@ -0,0 +1,258 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_SystemCarbon.h + * Declaration of GHOST_SystemCarbon class. + */ + +#ifndef _GHOST_SYSTEM_CARBON_H_ +#define _GHOST_SYSTEM_CARBON_H_ + +#ifndef __APPLE__ +#error Apple OSX only! +#endif // __APPLE__ + +#define __CARBONSOUND__ +#include + +#include "GHOST_System.h" + +class GHOST_EventCursor; +class GHOST_EventKey; +class GHOST_EventWindow; + +/** + * OSX/Carbon Implementation of GHOST_System class. + * @see GHOST_System. + * @author Maarten Gribnau + * @date May 21, 2001 + */ +class GHOST_SystemCarbon : public GHOST_System { +public: + /** + * Constructor. + */ + GHOST_SystemCarbon::GHOST_SystemCarbon(); + + /** + * Destructor. + */ + GHOST_SystemCarbon::~GHOST_SystemCarbon(); + + /*************************************************************************************** + ** Time(r) functionality + ***************************************************************************************/ + + /** + * Returns the system time. + * Returns the number of milliseconds since the start of the system process. + * Based on ANSI clock() routine. + * @return The number of milliseconds. + */ + virtual GHOST_TUns64 getMilliSeconds() const; + + /*************************************************************************************** + ** Display/window management functionality + ***************************************************************************************/ + + /** + * Returns the number of displays on this system. + * @return The number of displays. + */ + virtual GHOST_TUns8 getNumDisplays() const; + + /** + * Returns the dimensions of the main display on this system. + * @return The dimension of the main display. + */ + virtual void getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const; + + /** + * Create a new window. + * The new window is added to the list of windows managed. + * Never explicitly delete the window, use disposeWindow() instead. + * @param title The name of the window (displayed in the title bar of the window if the OS supports it). + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state of the window when opened. + * @param type The type of drawing context installed in this window. + * @return The new window (or 0 if creation failed). + */ + virtual GHOST_IWindow* createWindow( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const bool stereoVisual + ); + + /*************************************************************************************** + ** Event management functionality + ***************************************************************************************/ + + /** + * Gets events from the system and stores them in the queue. + * @param waitForEvent Flag to wait for an event (or return immediately). + * @return Indication of the presence of events. + */ + virtual bool processEvents(bool waitForEvent); + + /*************************************************************************************** + ** Cursor management functionality + ***************************************************************************************/ + + /** + * Returns the current location of the cursor (location in screen coordinates) + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const; + + /** + * Updates the location of the cursor (location in screen coordinates). + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) const; + + /*************************************************************************************** + ** Access to mouse button and keyboard states. + ***************************************************************************************/ + + /** + * Returns the state of all modifier keys. + * @param keys The state of all modifier keys (true == pressed). + * @return Indication of success. + */ + virtual GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys& keys) const; + + /** + * Returns the state of the mouse buttons (ouside the message queue). + * @param buttons The state of the buttons. + * @return Indication of success. + */ + virtual GHOST_TSuccess getButtons(GHOST_Buttons& buttons) const; + +protected: + /** + * Initializes the system. + * For now, it justs registers the window class (WNDCLASS). + * @return A success value. + */ + virtual GHOST_TSuccess init(); + + /** + * Closes the system down. + * @return A success value. + */ + virtual GHOST_TSuccess exit(); + + + /** + * Handles a tablet event. + * @param event A Mac event. + * @return Indication whether the event was handled. + */ + OSStatus handleTabletEvent(EventRef event); + /** + * Handles a mouse event. + * @param event A Mac event. + * @return Indication whether the event was handled. + */ + OSStatus handleMouseEvent(EventRef event); + + /** + * Handles a key event. + * @param event A Mac event. + * @return Indication whether the event was handled. + */ + OSStatus handleKeyEvent(EventRef event); + + /** + * Handles a window event. + * @param event A Mac event. + * @return Indication whether the event was handled. + */ + OSStatus handleWindowEvent(EventRef event); + + /** + * Handles all basic Mac application stuff for a mouse down event. + * @param event A Mac event. + * @return Indication whether the event was handled. + */ + bool handleMouseDown(EventRef event); + + /** + * Handles a Mac menu command. + * @param menuResult A Mac menu/item identifier. + * @return Indication whether the event was handled. + */ + bool handleMenuCommand(GHOST_TInt32 menuResult); + + /** + * Callback for Carbon when it has events. + */ + static OSStatus sEventHandlerProc(EventHandlerCallRef handler, EventRef event, void* userData); + + /** Apple Event Handlers */ + static OSErr sAEHandlerLaunch(const AppleEvent *event, AppleEvent *reply, SInt32 refCon); + static OSErr sAEHandlerOpenDocs(const AppleEvent *event, AppleEvent *reply, SInt32 refCon); + static OSErr sAEHandlerPrintDocs(const AppleEvent *event, AppleEvent *reply, SInt32 refCon); + static OSErr sAEHandlerQuit(const AppleEvent *event, AppleEvent *reply, SInt32 refCon); + + /** + * Callback for Mac Timer tasks that expire. + * @param tmTask Pointer to the timer task that expired. + */ + //static void s_timerCallback(TMTaskPtr tmTask); + + /** Event handler reference. */ + EventHandlerRef m_handler; + + /** Start time at initialization. */ + GHOST_TUns64 m_start_time; + + /** State of the modifiers. */ + UInt32 m_modifierMask; + + /** Ignores window size messages (when window is dragged). */ + bool m_ignoreWindowSizedMessages; +}; + +#endif // _GHOST_SYSTEM_CARBON_H_ + diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp new file mode 100644 index 00000000000..ec6d0d355b5 --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -0,0 +1,871 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 7, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning + +#include "GHOST_SystemWin32.h" + +/* + * According to the docs the mouse wheel message is supported from windows 98 + * upwards. Leaving WINVER at default value, the WM_MOUSEWHEEL message and the + * wheel detent value are undefined. + */ +#ifndef WM_MOUSEWHEEL +#define WM_MOUSEWHEEL 0x020A +#endif // WM_MOUSEWHEEL +#ifndef WHEEL_DELTA +#define WHEEL_DELTA 120 /* Value for rolling one detent */ +#endif // WHEEL_DELTA + + +#include "GHOST_Debug.h" +#include "GHOST_DisplayManagerWin32.h" +#include "GHOST_EventButton.h" +#include "GHOST_EventCursor.h" +#include "GHOST_EventKey.h" +#include "GHOST_EventWheel.h" +#include "GHOST_TimerTask.h" +#include "GHOST_TimerManager.h" +#include "GHOST_WindowManager.h" +#include "GHOST_WindowWin32.h" + +// Key code values not found in winuser.h +#ifndef VK_MINUS +#define VK_MINUS 0xBD +#endif // VK_MINUS +#ifndef VK_SEMICOLON +#define VK_SEMICOLON 0xBA +#endif // VK_SEMICOLON +#ifndef VK_PERIOD +#define VK_PERIOD 0xBE +#endif // VK_PERIOD +#ifndef VK_COMMA +#define VK_COMMA 0xBC +#endif // VK_COMMA +#ifndef VK_QUOTE +#define VK_QUOTE 0xDE +#endif // VK_QUOTE +#ifndef VK_BACK_QUOTE +#define VK_BACK_QUOTE 0xC0 +#endif // VK_BACK_QUOTE +#ifndef VK_SLASH +#define VK_SLASH 0xBF +#endif // VK_SLASH +#ifndef VK_BACK_SLASH +#define VK_BACK_SLASH 0xDC +#endif // VK_BACK_SLASH +#ifndef VK_EQUALS +#define VK_EQUALS 0xBB +#endif // VK_EQUALS +#ifndef VK_OPEN_BRACKET +#define VK_OPEN_BRACKET 0xDB +#endif // VK_OPEN_BRACKET +#ifndef VK_CLOSE_BRACKET +#define VK_CLOSE_BRACKET 0xDD +#endif // VK_CLOSE_BRACKET +#ifndef VK_GR_LESS +#define VK_GR_LESS 0xE2 +#endif // VK_GR_LESS + + +GHOST_SystemWin32::GHOST_SystemWin32() +: m_hasPerformanceCounter(false), m_freq(0), m_start(0), + m_seperateLeftRight(false), + m_seperateLeftRightInitialized(false) +{ + m_displayManager = new GHOST_DisplayManagerWin32 (); + GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::GHOST_SystemWin32(): m_displayManager==0\n"); + m_displayManager->initialize(); +} + +GHOST_SystemWin32::~GHOST_SystemWin32() +{ +} + + +GHOST_TUns64 GHOST_SystemWin32::getMilliSeconds() const +{ + // Hardware does not support high resolution timers. We will use GetTickCount instead then. + if (!m_hasPerformanceCounter) { + return ::GetTickCount(); + } + + // Retrieve current count + __int64 count = 0; + ::QueryPerformanceCounter((LARGE_INTEGER*)&count); + + // Calculate the time passed since system initialization. + __int64 delta = 1000*(count-m_start); + + GHOST_TUns64 t = (GHOST_TUns64)(delta/m_freq); + return t; +} + + +GHOST_TUns8 GHOST_SystemWin32::getNumDisplays() const +{ + GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::getNumDisplays(): m_displayManager==0\n"); + GHOST_TUns8 numDisplays; + m_displayManager->getNumDisplays(numDisplays); + return numDisplays; +} + + +void GHOST_SystemWin32::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const +{ + width = ::GetSystemMetrics(SM_CXSCREEN); + height= ::GetSystemMetrics(SM_CYSCREEN); +} + + +GHOST_IWindow* GHOST_SystemWin32::createWindow( + const STR_String& title, + GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height, + GHOST_TWindowState state, GHOST_TDrawingContextType type, + bool stereoVisual) +{ + GHOST_Window* window = 0; + window = new GHOST_WindowWin32 (title, left, top, width, height, state, type, stereoVisual); + if (window) { + if (window->getValid()) { + // Store the pointer to the window +// if (state != GHOST_kWindowStateFullScreen) { + m_windowManager->addWindow(window); +// } + } + else { + delete window; + window = 0; + } + } + return window; +} + + +bool GHOST_SystemWin32::processEvents(bool waitForEvent) +{ + MSG msg; + bool anyProcessed = false; + + do { + GHOST_TimerManager* timerMgr = getTimerManager(); + + if (waitForEvent && !::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE)) { +#if 1 + ::Sleep(1); +#else + GHOST_TUns64 next = timerMgr->nextFireTime(); + + if (next == GHOST_kFireTimeNever) { + ::WaitMessage(); + } else { + ::SetTimer(NULL, 0, next - getMilliSeconds(), NULL); + ::WaitMessage(); + ::KillTimer(NULL, 0); + } +#endif + } + + if (timerMgr->fireTimers(getMilliSeconds())) { + anyProcessed = true; + } + + // Process all the events waiting for us + while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE) != 0) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + anyProcessed = true; + } + } while (waitForEvent && !anyProcessed); + + return anyProcessed; +} + + +GHOST_TSuccess GHOST_SystemWin32::getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const +{ + POINT point; + bool success = ::GetCursorPos(&point) == TRUE; + x = point.x; + y = point.y; + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_SystemWin32::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) const +{ + return ::SetCursorPos(x, y) == TRUE ? GHOST_kSuccess : GHOST_kFailure; +} + + +GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys& keys) const +{ + /* + GetKeyState and GetAsyncKeyState only work with Win95, Win98, NT4, + Terminal Server and Windows 2000. + But on WinME it always returns zero. These two functions are simply + skipped by Millenium Edition! + + Official explanation from Microsoft: + Intentionally disabled. + It didn't work all that well on some newer hardware, and worked less + well with the passage of time, so it was fully disabled in ME. + */ + if (m_seperateLeftRight && m_seperateLeftRightInitialized) { + bool down = HIBYTE(::GetKeyState(VK_LSHIFT)) != 0; + keys.set(GHOST_kModifierKeyLeftShift, down); + down = HIBYTE(::GetKeyState(VK_RSHIFT)) != 0; + keys.set(GHOST_kModifierKeyRightShift, down); + down = HIBYTE(::GetKeyState(VK_LMENU)) != 0; + keys.set(GHOST_kModifierKeyLeftAlt, down); + down = HIBYTE(::GetKeyState(VK_RMENU)) != 0; + keys.set(GHOST_kModifierKeyRightAlt, down); + down = HIBYTE(::GetKeyState(VK_LCONTROL)) != 0; + keys.set(GHOST_kModifierKeyLeftControl, down); + down = HIBYTE(::GetKeyState(VK_RCONTROL)) != 0; + keys.set(GHOST_kModifierKeyRightControl, down); + } + else { + bool down = HIBYTE(::GetKeyState(VK_SHIFT)) != 0; + keys.set(GHOST_kModifierKeyLeftShift, down); + keys.set(GHOST_kModifierKeyRightShift, down); + down = HIBYTE(::GetKeyState(VK_MENU)) != 0; + keys.set(GHOST_kModifierKeyLeftAlt, down); + keys.set(GHOST_kModifierKeyRightAlt, down); + down = HIBYTE(::GetKeyState(VK_CONTROL)) != 0; + keys.set(GHOST_kModifierKeyLeftControl, down); + keys.set(GHOST_kModifierKeyRightControl, down); + } + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_SystemWin32::getButtons(GHOST_Buttons& buttons) const +{ + /* Check for swapped buttons (left-handed mouse buttons) + * GetAsyncKeyState() will give back the state of the physical mouse buttons. + */ + bool swapped = ::GetSystemMetrics(SM_SWAPBUTTON) == TRUE; + + bool down = HIBYTE(::GetKeyState(VK_LBUTTON)) != 0; + buttons.set(swapped ? GHOST_kButtonMaskRight : GHOST_kButtonMaskLeft, down); + + down = HIBYTE(::GetKeyState(VK_MBUTTON)) != 0; + buttons.set(GHOST_kButtonMaskMiddle, down); + + down = HIBYTE(::GetKeyState(VK_RBUTTON)) != 0; + buttons.set(swapped ? GHOST_kButtonMaskLeft : GHOST_kButtonMaskRight, down); + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_SystemWin32::init() +{ + GHOST_TSuccess success = GHOST_System::init(); + + // Determine whether this system has a high frequency performance counter. */ + m_hasPerformanceCounter = ::QueryPerformanceFrequency((LARGE_INTEGER*)&m_freq) == TRUE; + if (m_hasPerformanceCounter) { + GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer available\n") + ::QueryPerformanceCounter((LARGE_INTEGER*)&m_start); + } + else { + GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer not available\n") + } + + if (success) { + WNDCLASS wc; + wc.style= CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc= s_wndProc; + wc.cbClsExtra= 0; + wc.cbWndExtra= 0; + wc.hInstance= ::GetModuleHandle(0); + wc.hIcon = ::LoadIcon(wc.hInstance, "APPICON"); + + if (!wc.hIcon) { + ::LoadIcon(NULL, IDI_APPLICATION); + } + wc.hCursor = ::LoadCursor(0, IDC_ARROW); + wc.hbrBackground= (HBRUSH)::GetStockObject(BLACK_BRUSH); + wc.lpszMenuName = 0; + wc.lpszClassName= GHOST_WindowWin32::getWindowClassName(); + + // Use RegisterClassEx for setting small icon + if (::RegisterClass(&wc) == 0) { + success = GHOST_kFailure; + } + } + return success; +} + + +GHOST_TSuccess GHOST_SystemWin32::exit() +{ + return GHOST_System::exit(); +} + + +GHOST_TKey GHOST_SystemWin32::convertKey(WPARAM wParam, LPARAM lParam) const +{ + GHOST_TKey key; + bool isExtended = (lParam&(1<<24))?true:false; + + if ((wParam >= '0') && (wParam <= '9')) { + // VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) + key = (GHOST_TKey)(wParam - '0' + GHOST_kKey0); + } + else if ((wParam >= 'A') && (wParam <= 'Z')) { + // VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) + key = (GHOST_TKey)(wParam - 'A' + GHOST_kKeyA); + } + else if ((wParam >= VK_F1) && (wParam <= VK_F24)) { + key = (GHOST_TKey)(wParam - VK_F1 + GHOST_kKeyF1); + } + else { + switch (wParam) { + case VK_RETURN: + key = isExtended?GHOST_kKeyNumpadEnter:GHOST_kKeyEnter; + break; + + case VK_BACK: key = GHOST_kKeyBackSpace; break; + case VK_TAB: key = GHOST_kKeyTab; break; + case VK_ESCAPE: key = GHOST_kKeyEsc; break; + case VK_SPACE: key = GHOST_kKeySpace; break; + case VK_PRIOR: key = GHOST_kKeyUpPage; break; + case VK_NEXT: key = GHOST_kKeyDownPage; break; + case VK_END: key = GHOST_kKeyEnd; break; + case VK_HOME: key = GHOST_kKeyHome; break; + case VK_INSERT: key = GHOST_kKeyInsert; break; + case VK_DELETE: key = GHOST_kKeyDelete; break; + case VK_LEFT: key = GHOST_kKeyLeftArrow; break; + case VK_RIGHT: key = GHOST_kKeyRightArrow; break; + case VK_UP: key = GHOST_kKeyUpArrow; break; + case VK_DOWN: key = GHOST_kKeyDownArrow; break; + case VK_NUMPAD0: key = GHOST_kKeyNumpad0; break; + case VK_NUMPAD1: key = GHOST_kKeyNumpad1; break; + case VK_NUMPAD2: key = GHOST_kKeyNumpad2; break; + case VK_NUMPAD3: key = GHOST_kKeyNumpad3; break; + case VK_NUMPAD4: key = GHOST_kKeyNumpad4; break; + case VK_NUMPAD5: key = GHOST_kKeyNumpad5; break; + case VK_NUMPAD6: key = GHOST_kKeyNumpad6; break; + case VK_NUMPAD7: key = GHOST_kKeyNumpad7; break; + case VK_NUMPAD8: key = GHOST_kKeyNumpad8; break; + case VK_NUMPAD9: key = GHOST_kKeyNumpad9; break; + case VK_SNAPSHOT: key = GHOST_kKeyPrintScreen; break; + case VK_PAUSE: key = GHOST_kKeyPause; break; + case VK_MULTIPLY: key = GHOST_kKeyNumpadAsterisk; break; + case VK_SUBTRACT: key = GHOST_kKeyNumpadMinus; break; + case VK_DECIMAL: key = GHOST_kKeyNumpadPeriod; break; + case VK_DIVIDE: key = GHOST_kKeyNumpadSlash; break; + case VK_ADD: key = GHOST_kKeyNumpadPlus; break; + + case VK_SEMICOLON: key = GHOST_kKeySemicolon; break; + case VK_EQUALS: key = GHOST_kKeyEqual; break; + case VK_COMMA: key = GHOST_kKeyComma; break; + case VK_MINUS: key = GHOST_kKeyMinus; break; + case VK_PERIOD: key = GHOST_kKeyPeriod; break; + case VK_SLASH: key = GHOST_kKeySlash; break; + case VK_BACK_QUOTE: key = GHOST_kKeyAccentGrave; break; + case VK_OPEN_BRACKET: key = GHOST_kKeyLeftBracket; break; + case VK_BACK_SLASH: key = GHOST_kKeyBackslash; break; + case VK_CLOSE_BRACKET: key = GHOST_kKeyRightBracket; break; + case VK_QUOTE: key = GHOST_kKeyQuote; break; + case VK_GR_LESS: key = GHOST_kKeyGrLess; break; + + // Process these keys separately because we need to distinguish right from left modifier keys + case VK_SHIFT: + case VK_CONTROL: + case VK_MENU: + + // Ignore these keys + case VK_NUMLOCK: + case VK_SCROLL: + case VK_CAPITAL: + default: + key = GHOST_kKeyUnknown; + break; + } + } + return key; +} + + +void GHOST_SystemWin32::processModifierKeys(GHOST_IWindow *window) +{ + GHOST_ModifierKeys oldModifiers, newModifiers; + // Retrieve old state of the modifier keys + ((GHOST_SystemWin32*)getSystem())->retrieveModifierKeys(oldModifiers); + // Retrieve current state of the modifier keys + ((GHOST_SystemWin32*)getSystem())->getModifierKeys(newModifiers); + + // Compare the old and the new + if (!newModifiers.equals(oldModifiers)) { + // Create events for the masks that changed + for (int i = 0; i < GHOST_kModifierKeyNumMasks; i++) { + if (newModifiers.get((GHOST_TModifierKeyMask)i) != oldModifiers.get((GHOST_TModifierKeyMask)i)) { + // Convert the mask to a key code + GHOST_TKey key = GHOST_ModifierKeys::getModifierKeyCode((GHOST_TModifierKeyMask)i); + bool keyDown = newModifiers.get((GHOST_TModifierKeyMask)i); + GHOST_EventKey* event; + if (key != GHOST_kKeyUnknown) { + // Create an event + event = new GHOST_EventKey(getSystem()->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown: GHOST_kEventKeyUp, window, key); + pushEvent(event); + } + } + } + } + + // Store new modifier keys state + ((GHOST_SystemWin32*)getSystem())->storeModifierKeys(newModifiers); +} + + +GHOST_EventButton* GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, GHOST_IWindow *window, GHOST_TButtonMask mask) +{ + return new GHOST_EventButton (getSystem()->getMilliSeconds(), type, window, mask); +} + + +GHOST_EventCursor* GHOST_SystemWin32::processCursorEvent(GHOST_TEventType type, GHOST_IWindow *window) +{ + GHOST_TInt32 x, y; + getSystem()->getCursorPosition(x, y); + return new GHOST_EventCursor (getSystem()->getMilliSeconds(), type, window, x, y); +} + + +GHOST_EventWheel* GHOST_SystemWin32::processWheelEvent(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam) +{ + // short fwKeys = LOWORD(wParam); // key flags + int zDelta = (short) HIWORD(wParam); // wheel rotation + zDelta /= WHEEL_DELTA; + // short xPos = (short) LOWORD(lParam); // horizontal position of pointer + // short yPos = (short) HIWORD(lParam); // vertical position of pointer + return new GHOST_EventWheel (getSystem()->getMilliSeconds(), window, zDelta); +} + + +GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, bool keyDown, WPARAM wParam, LPARAM lParam) +{ + GHOST_TKey key = ((GHOST_SystemWin32*)getSystem())->convertKey(wParam, lParam); + GHOST_EventKey* event; + if (key != GHOST_kKeyUnknown) { + MSG keyMsg; + char ascii = '\0'; + + /* Eat any character related messages */ + if (::PeekMessage(&keyMsg, NULL, WM_CHAR, WM_SYSDEADCHAR, PM_REMOVE)) { + ascii = (char) keyMsg.wParam; + } + + event = new GHOST_EventKey(getSystem()->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown: GHOST_kEventKeyUp, window, key, ascii); + } + else { + event = 0; + } + return event; +} + + +GHOST_Event* GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type, GHOST_IWindow* window) +{ + return new GHOST_Event(getSystem()->getMilliSeconds(), type, window); +} + + +LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + GHOST_Event* event = 0; + LRESULT lResult; + GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem()); + GHOST_ASSERT(system, "GHOST_SystemWin32::s_wndProc(): system not initialized") + + if (hwnd) { + GHOST_WindowWin32* window = (GHOST_WindowWin32*)::GetWindowLong(hwnd, GWL_USERDATA); + if (window) { + switch (msg) { + //////////////////////////////////////////////////////////////////////// + // Keyboard events, processed + //////////////////////////////////////////////////////////////////////// + case WM_KEYDOWN: + /* The WM_KEYDOWN message is posted to the window with the keyboard focus when a + * nonsystem key is pressed. A nonsystem key is a key that is pressed when the alt + * key is not pressed. + */ + case WM_SYSKEYDOWN: + /* The WM_SYSKEYDOWN message is posted to the window with the keyboard focus when + * the user presses the F10 key (which activates the menu bar) or holds down the + * alt key and then presses another key. It also occurs when no window currently + * has the keyboard focus; in this case, the WM_SYSKEYDOWN message is sent to the + * active window. The window that receives the message can distinguish between these + * two contexts by checking the context code in the lKeyData parameter. + */ + switch (wParam) { + case VK_SHIFT: + case VK_CONTROL: + case VK_MENU: + if (!system->m_seperateLeftRightInitialized) { + // Check whether this system supports seperate left and right keys + switch (wParam) { + case VK_SHIFT: + system->m_seperateLeftRight = + (HIBYTE(::GetKeyState(VK_LSHIFT)) != 0) || + (HIBYTE(::GetKeyState(VK_RSHIFT)) != 0) ? + true : false; + break; + case VK_CONTROL: + system->m_seperateLeftRight = + (HIBYTE(::GetKeyState(VK_LCONTROL)) != 0) || + (HIBYTE(::GetKeyState(VK_RCONTROL)) != 0) ? + true : false; + break; + case VK_MENU: + system->m_seperateLeftRight = + (HIBYTE(::GetKeyState(VK_LMENU)) != 0) || + (HIBYTE(::GetKeyState(VK_RMENU)) != 0) ? + true : false; + break; + } + system->m_seperateLeftRightInitialized = true; + } + system->processModifierKeys(window); + // Bypass call to DefWindowProc + return 0; + default: + event = processKeyEvent(window, true, wParam, lParam); + if (!event) { + GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ") + GHOST_PRINT(msg) + GHOST_PRINT(" key ignored\n") + } + break; + } + break; + + case WM_KEYUP: + case WM_SYSKEYUP: + switch (wParam) { + case VK_SHIFT: + case VK_CONTROL: + case VK_MENU: + system->processModifierKeys(window); + // Bypass call to DefWindowProc + return 0; + default: + event = processKeyEvent(window, false, wParam, lParam); + if (!event) { + GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ") + GHOST_PRINT(msg) + GHOST_PRINT(" key ignored\n") + } + break; + } + break; + + //////////////////////////////////////////////////////////////////////// + // Keyboard events, ignored + //////////////////////////////////////////////////////////////////////// + case WM_CHAR: + /* The WM_CHAR message is posted to the window with the keyboard focus when + * a WM_KEYDOWN message is translated by the TranslateMessage function. WM_CHAR + * contains the character code of the key that was pressed. + */ + case WM_DEADCHAR: + /* The WM_DEADCHAR message is posted to the window with the keyboard focus when a + * WM_KEYUP message is translated by the TranslateMessage function. WM_DEADCHAR + * specifies a character code generated by a dead key. A dead key is a key that + * generates a character, such as the umlaut (double-dot), that is combined with + * another character to form a composite character. For example, the umlaut-O + * character (Ù) is generated by typing the dead key for the umlaut character, and + * then typing the O key. + */ + case WM_SYSDEADCHAR: + /* The WM_SYSDEADCHAR message is sent to the window with the keyboard focus when + * a WM_SYSKEYDOWN message is translated by the TranslateMessage function. + * WM_SYSDEADCHAR specifies the character code of a system dead key - that is, + * a dead key that is pressed while holding down the alt key. + */ + break; + //////////////////////////////////////////////////////////////////////// + // Tablet events, processed + //////////////////////////////////////////////////////////////////////// + case WT_PACKET: + ((GHOST_WindowWin32*)window)->processWin32TabletEvent(wParam, lParam); + break; + case WT_CSRCHANGE: + case WT_PROXIMITY: + ((GHOST_WindowWin32*)window)->processWin32TabletInitEvent(); + break; + //////////////////////////////////////////////////////////////////////// + // Mouse events, processed + //////////////////////////////////////////////////////////////////////// + case WM_LBUTTONDOWN: + window->registerMouseClickEvent(true); + event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft); + break; + case WM_MBUTTONDOWN: + window->registerMouseClickEvent(true); + event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskMiddle); + break; + case WM_RBUTTONDOWN: + window->registerMouseClickEvent(true); + event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight); + break; + case WM_LBUTTONUP: + window->registerMouseClickEvent(false); + event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft); + break; + case WM_MBUTTONUP: + window->registerMouseClickEvent(false); + event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskMiddle); + break; + case WM_RBUTTONUP: + window->registerMouseClickEvent(false); + event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight); + break; + case WM_MOUSEMOVE: + event = processCursorEvent(GHOST_kEventCursorMove, window); + break; + case WM_MOUSEWHEEL: + /* The WM_MOUSEWHEEL message is sent to the focus window + * when the mouse wheel is rotated. The DefWindowProc + * function propagates the message to the window's parent. + * There should be no internal forwarding of the message, + * since DefWindowProc propagates it up the parent chain + * until it finds a window that processes it. + */ + event = processWheelEvent(window, wParam, lParam); + break; + case WM_SETCURSOR: + /* The WM_SETCURSOR message is sent to a window if the mouse causes the cursor + * to move within a window and mouse input is not captured. + * This means we have to set the cursor shape every time the mouse moves! + * The DefWindowProc function uses this message to set the cursor to an + * arrow if it is not in the client area. + */ + if (LOWORD(lParam) == HTCLIENT) { + // Load the current cursor + window->loadCursor(window->getCursorVisibility(), window->getCursorShape()); + // Bypass call to DefWindowProc + return 0; + } + else { + // Outside of client area show standard cursor + window->loadCursor(true, GHOST_kStandardCursorDefault); + } + break; + + //////////////////////////////////////////////////////////////////////// + // Mouse events, ignored + //////////////////////////////////////////////////////////////////////// + case WM_NCMOUSEMOVE: + /* The WM_NCMOUSEMOVE message is posted to a window when the cursor is moved + * within the nonclient area of the window. This message is posted to the window + * that contains the cursor. If a window has captured the mouse, this message is not posted. + */ + case WM_NCHITTEST: + /* The WM_NCHITTEST message is sent to a window when the cursor moves, or + * when a mouse button is pressed or released. If the mouse is not captured, + * the message is sent to the window beneath the cursor. Otherwise, the message + * is sent to the window that has captured the mouse. + */ + break; + + //////////////////////////////////////////////////////////////////////// + // Window events, processed + //////////////////////////////////////////////////////////////////////// + case WM_CLOSE: + /* The WM_CLOSE message is sent as a signal that a window or an application should terminate. */ + event = processWindowEvent(GHOST_kEventWindowClose, window); + break; + case WM_ACTIVATE: + /* The WM_ACTIVATE message is sent to both the window being activated and the window being + * deactivated. If the windows use the same input queue, the message is sent synchronously, + * first to the window procedure of the top-level window being deactivated, then to the window + * procedure of the top-level window being activated. If the windows use different input queues, + * the message is sent asynchronously, so the window is activated immediately. + */ + event = processWindowEvent(LOWORD(wParam) ? GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate, window); + break; + case WM_PAINT: + /* An application sends the WM_PAINT message when the system or another application + * makes a request to paint a portion of an application's window. The message is sent + * when the UpdateWindow or RedrawWindow function is called, or by the DispatchMessage + * function when the application obtains a WM_PAINT message by using the GetMessage or + * PeekMessage function. + */ + event = processWindowEvent(GHOST_kEventWindowUpdate, window); + ::ValidateRect(hwnd, NULL); + break; + case WM_SIZE: + /* The WM_SIZE message is sent to a window after its size has changed. + * The WM_SIZE and WM_MOVE messages are not sent if an application handles the + * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient + * to perform any move or size change processing during the WM_WINDOWPOSCHANGED + * message without calling DefWindowProc. + */ + event = processWindowEvent(GHOST_kEventWindowSize, window); + case WM_CAPTURECHANGED: + window->lostMouseCapture(); + break; + + //////////////////////////////////////////////////////////////////////// + // Window events, ignored + //////////////////////////////////////////////////////////////////////// + case WM_WINDOWPOSCHANGED: + /* The WM_WINDOWPOSCHANGED message is sent to a window whose size, position, or place + * in the Z order has changed as a result of a call to the SetWindowPos function or + * another window-management function. + * The WM_SIZE and WM_MOVE messages are not sent if an application handles the + * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient + * to perform any move or size change processing during the WM_WINDOWPOSCHANGED + * message without calling DefWindowProc. + */ + case WM_MOVE: + /* The WM_SIZE and WM_MOVE messages are not sent if an application handles the + * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient + * to perform any move or size change processing during the WM_WINDOWPOSCHANGED + * message without calling DefWindowProc. + */ + case WM_ERASEBKGND: + /* An application sends the WM_ERASEBKGND message when the window background must be + * erased (for example, when a window is resized). The message is sent to prepare an + * invalidated portion of a window for painting. + */ + case WM_NCPAINT: + /* An application sends the WM_NCPAINT message to a window when its frame must be painted. */ + case WM_NCACTIVATE: + /* The WM_NCACTIVATE message is sent to a window when its nonclient area needs to be changed + * to indicate an active or inactive state. + */ + case WM_DESTROY: + /* The WM_DESTROY message is sent when a window is being destroyed. It is sent to the window + * procedure of the window being destroyed after the window is removed from the screen. + * This message is sent first to the window being destroyed and then to the child windows + * (if any) as they are destroyed. During the processing of the message, it can be assumed + * that all child windows still exist. + */ + case WM_NCDESTROY: + /* The WM_NCDESTROY message informs a window that its nonclient area is being destroyed. The + * DestroyWindow function sends the WM_NCDESTROY message to the window following the WM_DESTROY + * message. WM_DESTROY is used to free the allocated memory object associated with the window. + */ + case WM_KILLFOCUS: + /* The WM_KILLFOCUS message is sent to a window immediately before it loses the keyboard focus. */ + case WM_SHOWWINDOW: + /* The WM_SHOWWINDOW message is sent to a window when the window is about to be hidden or shown. */ + case WM_WINDOWPOSCHANGING: + /* The WM_WINDOWPOSCHANGING message is sent to a window whose size, position, or place in + * the Z order is about to change as a result of a call to the SetWindowPos function or + * another window-management function. + */ + case WM_SETFOCUS: + /* The WM_SETFOCUS message is sent to a window after it has gained the keyboard focus. */ + case WM_MOVING: + /* The WM_MOVING message is sent to a window that the user is moving. By processing + * this message, an application can monitor the size and position of the drag rectangle + * and, if needed, change its size or position. + */ + case WM_ENTERSIZEMOVE: + /* The WM_ENTERSIZEMOVE message is sent one time to a window after it enters the moving + * or sizing modal loop. The window enters the moving or sizing modal loop when the user + * clicks the window's title bar or sizing border, or when the window passes the + * WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the + * message specifies the SC_MOVE or SC_SIZE value. The operation is complete when + * DefWindowProc returns. + */ + break; + + //////////////////////////////////////////////////////////////////////// + // Other events + //////////////////////////////////////////////////////////////////////// + case WM_GETTEXT: + /* An application sends a WM_GETTEXT message to copy the text that + * corresponds to a window into a buffer provided by the caller. + */ + case WM_ACTIVATEAPP: + /* The WM_ACTIVATEAPP message is sent when a window belonging to a + * different application than the active window is about to be activated. + * The message is sent to the application whose window is being activated + * and to the application whose window is being deactivated. + */ + case WM_TIMER: + /* The WIN32 docs say: + * The WM_TIMER message is posted to the installing thread's message queue + * when a timer expires. You can process the message by providing a WM_TIMER + * case in the window procedure. Otherwise, the default window procedure will + * call the TimerProc callback function specified in the call to the SetTimer + * function used to install the timer. + * + * In GHOST, we let DefWindowProc call the timer callback. + */ + break; + } + } + else { + // Event found for a window before the pointer to the class has been set. + GHOST_PRINT("GHOST_SystemWin32::wndProc: GHOST window event before creation\n") + /* These are events we typically miss at this point: + WM_GETMINMAXINFO 0x24 + WM_NCCREATE 0x81 + WM_NCCALCSIZE 0x83 + WM_CREATE 0x01 + We let DefWindowProc do the work. + */ + } + } + else { + // Events without valid hwnd + GHOST_PRINT("GHOST_SystemWin32::wndProc: event without window\n") + } + + if (event) { + system->pushEvent(event); + lResult = 0; + } + else { + lResult = ::DefWindowProc(hwnd, msg, wParam, lParam); + } + return lResult; +} diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h new file mode 100644 index 00000000000..218fc5794eb --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemWin32.h @@ -0,0 +1,291 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_SystemWin32.h + * Declaration of GHOST_SystemWin32 class. + */ + +#ifndef _GHOST_SYSTEM_WIN32_H_ +#define _GHOST_SYSTEM_WIN32_H_ + +#ifndef WIN32 +#error WIN32 only! +#endif // WIN32 + +#include + +#include "GHOST_System.h" + +#if defined(__CYGWIN32__) +# define __int64 long long +#endif + + +class GHOST_EventButton; +class GHOST_EventCursor; +class GHOST_EventKey; +class GHOST_EventWheel; +class GHOST_EventWindow; + +/** + * WIN32 Implementation of GHOST_System class. + * @see GHOST_System. + * @author Maarten Gribnau + * @date May 10, 2001 + */ +class GHOST_SystemWin32 : public GHOST_System { +public: + /** + * Constructor. + */ + GHOST_SystemWin32(); + + /** + * Destructor. + */ + virtual ~GHOST_SystemWin32(); + + /*************************************************************************************** + ** Time(r) functionality + ***************************************************************************************/ + + /** + * Returns the system time. + * Returns the number of milliseconds since the start of the system process. + * This overloaded method uses the high frequency timer if available. + * @return The number of milliseconds. + */ + virtual GHOST_TUns64 getMilliSeconds() const; + + /*************************************************************************************** + ** Display/window management functionality + ***************************************************************************************/ + + /** + * Returns the number of displays on this system. + * @return The number of displays. + */ + virtual GHOST_TUns8 getNumDisplays() const; + + /** + * Returns the dimensions of the main display on this system. + * @return The dimension of the main display. + */ + virtual void getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const; + + /** + * Create a new window. + * The new window is added to the list of windows managed. + * Never explicitly delete the window, use disposeWindow() instead. + * @param title The name of the window (displayed in the title bar of the window if the OS supports it). + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state of the window when opened. + * @param type The type of drawing context installed in this window. + * @return The new window (or 0 if creation failed). + */ + virtual GHOST_IWindow* createWindow( + const STR_String& title, + GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height, + GHOST_TWindowState state, GHOST_TDrawingContextType type, + const bool stereoVisual); + + /*************************************************************************************** + ** Event management functionality + ***************************************************************************************/ + + /** + * Gets events from the system and stores them in the queue. + * @param waitForEvent Flag to wait for an event (or return immediately). + * @return Indication of the presence of events. + */ + virtual bool processEvents(bool waitForEvent); + + + /*************************************************************************************** + ** Cursor management functionality + ***************************************************************************************/ + + /** + * Returns the current location of the cursor (location in screen coordinates) + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const; + + /** + * Updates the location of the cursor (location in screen coordinates). + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) const; + + /*************************************************************************************** + ** Access to mouse button and keyboard states. + ***************************************************************************************/ + + /** + * Returns the state of all modifier keys. + * @param keys The state of all modifier keys (true == pressed). + * @return Indication of success. + */ + virtual GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys& keys) const; + + /** + * Returns the state of the mouse buttons (ouside the message queue). + * @param buttons The state of the buttons. + * @return Indication of success. + */ + virtual GHOST_TSuccess getButtons(GHOST_Buttons& buttons) const; + +protected: + /** + * Initializes the system. + * For now, it justs registers the window class (WNDCLASS). + * @return A success value. + */ + virtual GHOST_TSuccess init(); + + /** + * Closes the system down. + * @return A success value. + */ + virtual GHOST_TSuccess exit(); + + /** + * Converts raw WIN32 key codes from the wndproc to GHOST keys. + * @param wParam The wParam from the wndproc + * @param lParam The lParam from the wndproc + * @return The GHOST key (GHOST_kKeyUnknown if no match). + */ + virtual GHOST_TKey convertKey(WPARAM wParam, LPARAM lParam) const; + + /** + * Creates modifier key event(s) and updates the key data stored locally (m_modifierKeys). + * With the modifier keys, we want to distinguish left and right keys. + * Sometimes this is not possible (Windows ME for instance). Then, we want + * events generated for both keys. + * @param window The window receiving the event (the active window). + */ + void processModifierKeys(GHOST_IWindow *window); + + /** + * Creates mouse button event. + * @param type The type of event to create. + * @param window The window receiving the event (the active window). + * @param mask The button mask of this event. + * @return The event created. + */ + static GHOST_EventButton* processButtonEvent(GHOST_TEventType type, GHOST_IWindow *window, GHOST_TButtonMask mask); + + /** + * Creates cursor event. + * @param type The type of event to create. + * @param window The window receiving the event (the active window). + * @return The event created. + */ + static GHOST_EventCursor* processCursorEvent(GHOST_TEventType type, GHOST_IWindow *window); + + /** + * Creates a mouse wheel event. + * @param window The window receiving the event (the active window). + * @param wParam The wParam from the wndproc + * @param lParam The lParam from the wndproc + */ + static GHOST_EventWheel* processWheelEvent(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam); + + /** + * Creates a key event and updates the key data stored locally (m_modifierKeys). + * In most cases this is a straightforward conversion of key codes. + * For the modifier keys however, we want to distinguish left and right keys. + * @param window The window receiving the event (the active window). + * @param wParam The wParam from the wndproc + * @param lParam The lParam from the wndproc + */ + static GHOST_EventKey* processKeyEvent(GHOST_IWindow *window, bool keyDown, WPARAM wParam, LPARAM lParam); + + /** + * Creates a window event. + * @param type The type of event to create. + * @param window The window receiving the event (the active window). + * @return The event created. + */ + static GHOST_Event* processWindowEvent(GHOST_TEventType type, GHOST_IWindow* window); + + /** + * Returns the local state of the modifier keys (from the message queue). + * @param keys The state of the keys. + */ + inline virtual void retrieveModifierKeys(GHOST_ModifierKeys& keys) const; + + /** + * Stores the state of the modifier keys locally. + * For internal use only! + * @param keys The new state of the modifier keys. + */ + inline virtual void storeModifierKeys(const GHOST_ModifierKeys& keys); + + /** + * Windows call back routine for our window class. + */ + static LRESULT WINAPI s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + + /** The current state of the modifier keys. */ + GHOST_ModifierKeys m_modifierKeys; + /** State variable set at initialization. */ + bool m_hasPerformanceCounter; + /** High frequency timer variable. */ + __int64 m_freq; + /** High frequency timer variable. */ + __int64 m_start; + /** Stores the capability of this system to distinguish left and right modifier keys. */ + bool m_seperateLeftRight; + /** Stores the initialization state of the member m_leftRightDistinguishable. */ + bool m_seperateLeftRightInitialized; + +}; + +inline void GHOST_SystemWin32::retrieveModifierKeys(GHOST_ModifierKeys& keys) const +{ + keys = m_modifierKeys; +} + +inline void GHOST_SystemWin32::storeModifierKeys(const GHOST_ModifierKeys& keys) +{ + m_modifierKeys = keys; +} + +#endif // _GHOST_SYSTEM_WIN32_H_ + diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp new file mode 100644 index 00000000000..14383ad3624 --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -0,0 +1,878 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_SystemX11.h" +#include "GHOST_WindowX11.h" +#include "GHOST_WindowManager.h" +#include "GHOST_TimerManager.h" +#include "GHOST_EventCursor.h" +#include "GHOST_EventKey.h" +#include "GHOST_EventButton.h" +#include "GHOST_EventWheel.h" +#include "GHOST_DisplayManagerX11.h" + +#include "GHOST_Debug.h" + +#include +#include + +#ifdef __sgi + +#if defined(_SGI_EXTRA_PREDEFINES) && !defined(NO_FAST_ATOMS) +#include +#else +#define XSGIFastInternAtom(dpy,string,fast_name,how) XInternAtom(dpy,string,how) +#endif + +#endif + +// For timing + +#include +#include + +#include + +using namespace std; + +GHOST_SystemX11:: +GHOST_SystemX11( +) : + GHOST_System(), + m_start_time(0) +{ + m_display = XOpenDisplay(NULL); + + if (!m_display) return; + +#ifdef __sgi + m_delete_window_atom + = XSGIFastInternAtom(m_display, + "WM_DELETE_WINDOW", + SGI_XA_WM_DELETE_WINDOW, False); +#else + m_delete_window_atom + = XInternAtom(m_display, "WM_DELETE_WINDOW", True); +#endif + + // compute the initial time + timeval tv; + if (gettimeofday(&tv,NULL) == -1) { + GHOST_ASSERT(false,"Could not instantiate timer!"); + } + + m_start_time = GHOST_TUns64(tv.tv_sec*1000 + tv.tv_usec/1000); +} + + GHOST_TSuccess +GHOST_SystemX11:: +init( +){ + GHOST_TSuccess success = GHOST_System::init(); + + if (success) { + m_keyboard_vector = new char[32]; + + m_displayManager = new GHOST_DisplayManagerX11(this); + + if (m_keyboard_vector && m_displayManager) { + return GHOST_kSuccess; + } + } + + return GHOST_kFailure; +} + + + + GHOST_TUns64 +GHOST_SystemX11:: +getMilliSeconds( +) const { + timeval tv; + if (gettimeofday(&tv,NULL) == -1) { + GHOST_ASSERT(false,"Could not compute time!"); + } + + return GHOST_TUns64(tv.tv_sec*1000 + tv.tv_usec/1000) - m_start_time; +} + + GHOST_TUns8 +GHOST_SystemX11:: +getNumDisplays( +) const { + return GHOST_TUns8(1); +} + + /** + * Returns the dimensions of the main display on this system. + * @return The dimension of the main display. + */ + void +GHOST_SystemX11:: +getMainDisplayDimensions( + GHOST_TUns32& width, + GHOST_TUns32& height +) const { + if (m_display) { + width = DisplayWidth(m_display, DefaultScreen(m_display)); + height = DisplayHeight(m_display, DefaultScreen(m_display)); + } +} + + /** + * Create a new window. + * The new window is added to the list of windows managed. + * Never explicitly delete the window, use disposeWindow() instead. + * @param title The name of the window (displayed in the title bar of the window if the OS supports it). + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state of the window when opened. + * @param type The type of drawing context installed in this window. + * @return The new window (or 0 if creation failed). + */ + GHOST_IWindow* +GHOST_SystemX11:: +createWindow( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + bool stereoVisual +){ + GHOST_WindowX11 * window = 0; + + if (!m_display) return 0; + + window = new GHOST_WindowX11 ( + this,m_display,title, left, top, width, height, state, type, stereoVisual + ); + + if (window) { + + // Install a new protocol for this window - so we can overide + // the default window closure mechanism. + + XSetWMProtocols(m_display, window->getXWindow(), &m_delete_window_atom, 1); + + if (window->getValid()) { + // Store the pointer to the window + m_windowManager->addWindow(window); + + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window) ); + } + else { + delete window; + window = 0; + } + } + return window; + +} + + GHOST_WindowX11 * +GHOST_SystemX11:: +findGhostWindow( + Window xwind +) const { + + if (xwind == 0) return NULL; + + // It is not entirely safe to do this as the backptr may point + // to a window that has recently been removed. + // We should always check the window manager's list of windows + // and only process events on these windows. + + vector & win_vec = m_windowManager->getWindows(); + + vector::iterator win_it = win_vec.begin(); + vector::const_iterator win_end = win_vec.end(); + + for (; win_it != win_end; ++win_it) { + GHOST_WindowX11 * window = static_cast(*win_it); + if (window->getXWindow() == xwind) { + return window; + } + } + return NULL; + +} + +static void SleepTillEvent(Display *display, GHOST_TInt64 maxSleep) { + int fd = ConnectionNumber(display); + fd_set fds; + + FD_ZERO(&fds); + FD_SET(fd, &fds); + + if (maxSleep == -1) { + select(fd + 1, &fds, NULL, NULL, NULL); + } else { + timeval tv; + + tv.tv_sec = maxSleep/1000; + tv.tv_usec = (maxSleep - tv.tv_sec*1000)*1000; + + select(fd + 1, &fds, NULL, NULL, &tv); + } +} + + bool +GHOST_SystemX11:: +processEvents( + bool waitForEvent +){ + // Get all the current events -- translate them into + // ghost events and call base class pushEvent() method. + + bool anyProcessed = false; + + do { + GHOST_TimerManager* timerMgr = getTimerManager(); + + if (waitForEvent && m_dirty_windows.empty() && !XPending(m_display)) { + GHOST_TUns64 next = timerMgr->nextFireTime(); + + if (next==GHOST_kFireTimeNever) { + SleepTillEvent(m_display, -1); + } else { + SleepTillEvent(m_display, next - getMilliSeconds()); + } + } + + if (timerMgr->fireTimers(getMilliSeconds())) { + anyProcessed = true; + } + + while (XPending(m_display)) { + XEvent xevent; + XNextEvent(m_display, &xevent); + processEvent(&xevent); + anyProcessed = true; + } + + if (generateWindowExposeEvents()) { + anyProcessed = true; + } + } while (waitForEvent && !anyProcessed); + + return anyProcessed; +} + + void +GHOST_SystemX11::processEvent(XEvent *xe) +{ + GHOST_WindowX11 * window = findGhostWindow(xe->xany.window); + GHOST_Event * g_event = NULL; + + if (!window) { + return; + } + + switch (xe->type) { + case Expose: + { + XExposeEvent & xee = xe->xexpose; + + if (xee.count == 0) { + // Only generate a single expose event + // per read of the event queue. + + g_event = new + GHOST_Event( + getMilliSeconds(), + GHOST_kEventWindowUpdate, + window + ); + } + break; + } + + case MotionNotify: + { + XMotionEvent &xme = xe->xmotion; + + g_event = new + GHOST_EventCursor( + getMilliSeconds(), + GHOST_kEventCursorMove, + window, + xme.x_root, + xme.y_root + ); + break; + } + + case KeyPress: + case KeyRelease: + { + XKeyEvent *xke = &(xe->xkey); + + KeySym key_sym = XLookupKeysym(xke,0); + char ascii; + + GHOST_TKey gkey = convertXKey(key_sym); + GHOST_TEventType type = (xke->type == KeyPress) ? + GHOST_kEventKeyDown : GHOST_kEventKeyUp; + + if (!XLookupString(xke, &ascii, 1, NULL, NULL)) { + ascii = '\0'; + } + + g_event = new + GHOST_EventKey( + getMilliSeconds(), + type, + window, + gkey, + ascii + ); + + break; + } + + case ButtonPress: + { + /* process wheel mouse events and break */ + if (xe->xbutton.button == 4) { + g_event = new GHOST_EventWheel(getMilliSeconds(), window, 1); + break; + } + if (xe->xbutton.button == 5) { + g_event = new GHOST_EventWheel(getMilliSeconds(), window, -1); + break; + } + } + case ButtonRelease: + { + + XButtonEvent & xbe = xe->xbutton; + GHOST_TButtonMask gbmask = GHOST_kButtonMaskLeft; + + switch (xbe.button) { + case Button1 : gbmask = GHOST_kButtonMaskLeft; break; + case Button3 : gbmask = GHOST_kButtonMaskRight; break; + default: + case Button2 : gbmask = GHOST_kButtonMaskMiddle; break; + } + + GHOST_TEventType type = (xbe.type == ButtonPress) ? + GHOST_kEventButtonDown : GHOST_kEventButtonUp; + + g_event = new + GHOST_EventButton( + getMilliSeconds(), + type, + window, + gbmask + ); + break; + } + + // change of size, border, layer etc. + case ConfigureNotify: + { + /* XConfigureEvent & xce = xe->xconfigure; */ + + g_event = new + GHOST_Event( + getMilliSeconds(), + GHOST_kEventWindowSize, + window + ); + break; + } + + case FocusIn: + case FocusOut: + { + XFocusChangeEvent &xfe = xe->xfocus; + + // May have to look at the type of event and filter some + // out. + + GHOST_TEventType gtype = (xfe.type == FocusIn) ? + GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate; + + g_event = new + GHOST_Event( + getMilliSeconds(), + gtype, + window + ); + break; + + } + case ClientMessage: + { + XClientMessageEvent & xcme = xe->xclient; + +#ifndef __sgi + if (xcme.data.l[0] == m_delete_window_atom) { + g_event = new + GHOST_Event( + getMilliSeconds(), + GHOST_kEventWindowClose, + window + ); + } else { + /* Unknown client message, ignore */ + } +#endif + break; + } + + // We're not interested in the following things.(yet...) + case NoExpose : + case GraphicsExpose : + + case EnterNotify: + case LeaveNotify: + // XCrossingEvents pointer leave enter window. + break; + case MapNotify: + case UnmapNotify: + break; + case MappingNotify: + case ReparentNotify: + break; + + default: { + if(xe->type == window->GetXTablet().MotionEvent) + { + XDeviceMotionEvent* data = (XDeviceMotionEvent*)xe; + window->GetXTablet().CommonData.Pressure= + data->axis_data[2]/((float)window->GetXTablet().PressureLevels); + + /* the (short) cast and the &0xffff is bizarre and unexplained anywhere, + * but I got garbage data without it. Found it in the xidump.c source --matt */ + window->GetXTablet().CommonData.Xtilt= + (short)(data->axis_data[3]&0xffff)/((float)window->GetXTablet().XtiltLevels); + window->GetXTablet().CommonData.Ytilt= + (short)(data->axis_data[4]&0xffff)/((float)window->GetXTablet().YtiltLevels); + } + else if(xe->type == window->GetXTablet().ProxInEvent) + { + XProximityNotifyEvent* data = (XProximityNotifyEvent*)xe; + if(data->deviceid == window->GetXTablet().StylusID) + window->GetXTablet().CommonData.Active= 1; + else if(data->deviceid == window->GetXTablet().EraserID) + window->GetXTablet().CommonData.Active= 2; + } + else if(xe->type == window->GetXTablet().ProxOutEvent) + window->GetXTablet().CommonData.Active= 0; + + break; + } + } + + if (g_event) { + pushEvent(g_event); + } +} + + + GHOST_TSuccess +GHOST_SystemX11:: +getModifierKeys( + GHOST_ModifierKeys& keys +) const { + + // analyse the masks retuned from XQueryPointer. + + memset(m_keyboard_vector,0,sizeof(m_keyboard_vector)); + + XQueryKeymap(m_display,m_keyboard_vector); + + // now translate key symobols into keycodes and + // test with vector. + + const KeyCode shift_l = XKeysymToKeycode(m_display,XK_Shift_L); + const KeyCode shift_r = XKeysymToKeycode(m_display,XK_Shift_R); + const KeyCode control_l = XKeysymToKeycode(m_display,XK_Control_L); + const KeyCode control_r = XKeysymToKeycode(m_display,XK_Control_R); + const KeyCode alt_l = XKeysymToKeycode(m_display,XK_Alt_L); + const KeyCode alt_r = XKeysymToKeycode(m_display,XK_Alt_R); + + // Shift + if ((m_keyboard_vector[shift_l >> 3] >> (shift_l & 7)) & 1) { + keys.set(GHOST_kModifierKeyLeftShift,true); + } else { + keys.set(GHOST_kModifierKeyLeftShift,false); + } + if ((m_keyboard_vector[shift_r >> 3] >> (shift_r & 7)) & 1) { + + keys.set(GHOST_kModifierKeyRightShift,true); + } else { + keys.set(GHOST_kModifierKeyRightShift,false); + } + + // control (weep) + if ((m_keyboard_vector[control_l >> 3] >> (control_l & 7)) & 1) { + keys.set(GHOST_kModifierKeyLeftControl,true); + } else { + keys.set(GHOST_kModifierKeyLeftControl,false); + } + if ((m_keyboard_vector[control_r >> 3] >> (control_r & 7)) & 1) { + keys.set(GHOST_kModifierKeyRightControl,true); + } else { + keys.set(GHOST_kModifierKeyRightControl,false); + } + + // Alt (yawn) + if ((m_keyboard_vector[alt_l >> 3] >> (alt_l & 7)) & 1) { + keys.set(GHOST_kModifierKeyLeftAlt,true); + } else { + keys.set(GHOST_kModifierKeyLeftAlt,false); + } + if ((m_keyboard_vector[alt_r >> 3] >> (alt_r & 7)) & 1) { + keys.set(GHOST_kModifierKeyRightAlt,true); + } else { + keys.set(GHOST_kModifierKeyRightAlt,false); + } + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_SystemX11:: +getButtons( + GHOST_Buttons& buttons +) const { + + Window root_return, child_return; + int rx,ry,wx,wy; + unsigned int mask_return; + + if (XQueryPointer( + m_display, + RootWindow(m_display,DefaultScreen(m_display)), + &root_return, + &child_return, + &rx,&ry, + &wx,&wy, + &mask_return + ) == False) { + return GHOST_kFailure; + } else { + + if (mask_return & Button1Mask) { + buttons.set(GHOST_kButtonMaskLeft,true); + } else { + buttons.set(GHOST_kButtonMaskLeft,false); + } + + if (mask_return & Button2Mask) { + buttons.set(GHOST_kButtonMaskMiddle,true); + } else { + buttons.set(GHOST_kButtonMaskMiddle,false); + } + + if (mask_return & Button3Mask) { + buttons.set(GHOST_kButtonMaskRight,true); + } else { + buttons.set(GHOST_kButtonMaskRight,false); + } + } + + return GHOST_kSuccess; +} + + + GHOST_TSuccess +GHOST_SystemX11:: +getCursorPosition( + GHOST_TInt32& x, + GHOST_TInt32& y +) const { + + Window root_return, child_return; + int rx,ry,wx,wy; + unsigned int mask_return; + + if (XQueryPointer( + m_display, + RootWindow(m_display,DefaultScreen(m_display)), + &root_return, + &child_return, + &rx,&ry, + &wx,&wy, + &mask_return + ) == False) { + return GHOST_kFailure; + } else { + x = rx; + y = ry; + } + return GHOST_kSuccess; +} + + + GHOST_TSuccess +GHOST_SystemX11:: +setCursorPosition( + GHOST_TInt32 x, + GHOST_TInt32 y +) const { + + // This is a brute force move in screen coordinates + // XWarpPointer does relative moves so first determine the + // current pointer position. + + int cx,cy; + if (getCursorPosition(cx,cy) == GHOST_kFailure) { + return GHOST_kFailure; + } + + int relx = x-cx; + int rely = y-cy; + + XWarpPointer(m_display,None,None,0,0,0,0,relx,rely); + XFlush(m_display); + + return GHOST_kSuccess; +} + + + void +GHOST_SystemX11:: +addDirtyWindow( + GHOST_WindowX11 * bad_wind +){ + + GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)"); + + m_dirty_windows.push_back(bad_wind); +} + + + bool +GHOST_SystemX11:: +generateWindowExposeEvents( +){ + + vector::iterator w_start = m_dirty_windows.begin(); + vector::const_iterator w_end = m_dirty_windows.end(); + bool anyProcessed = false; + + for (;w_start != w_end; ++w_start) { + GHOST_Event * g_event = new + GHOST_Event( + getMilliSeconds(), + GHOST_kEventWindowUpdate, + *w_start + ); + + (*w_start)->validate(); + + if (g_event) { + pushEvent(g_event); + anyProcessed = true; + } + } + + m_dirty_windows.clear(); + return anyProcessed; +} + +#define GXMAP(k,x,y) case x: k = y; break; + + GHOST_TKey +GHOST_SystemX11:: +convertXKey( + KeySym key +){ + GHOST_TKey type; + + if ((key >= XK_A) && (key <= XK_Z)) { + type = GHOST_TKey( key - XK_A + int(GHOST_kKeyA)); + } else if ((key >= XK_a) && (key <= XK_z)) { + type = GHOST_TKey(key - XK_a + int(GHOST_kKeyA)); + } else if ((key >= XK_0) && (key <= XK_9)) { + type = GHOST_TKey(key - XK_0 + int(GHOST_kKey0)); + } else if ((key >= XK_F1) && (key <= XK_F24)) { + type = GHOST_TKey(key - XK_F1 + int(GHOST_kKeyF1)); +#if defined(__sun) || defined(__sun__) + /* This is a bit of a hack, but it looks like sun + Used F11 and friends for its special keys Stop,again etc.. + So this little patch enables F11 and F12 to work as expected + following link has documentation on it: + http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4734408 + also from /usr/include/X11/Sunkeysym.h +#define SunXK_F36 0x1005FF10 // Labeled F11 +#define SunXK_F37 0x1005FF11 // Labeled F12 + + mein@cs.umn.edu + */ + + } else if (key == 268828432) { + type = GHOST_kKeyF11; + } else if (key == 268828433) { + type = GHOST_kKeyF12; +#endif + } else { + switch(key) { + GXMAP(type,XK_BackSpace, GHOST_kKeyBackSpace); + GXMAP(type,XK_Tab, GHOST_kKeyTab); + GXMAP(type,XK_Return, GHOST_kKeyEnter); + GXMAP(type,XK_Escape, GHOST_kKeyEsc); + GXMAP(type,XK_space, GHOST_kKeySpace); + + GXMAP(type,XK_Linefeed, GHOST_kKeyLinefeed); + GXMAP(type,XK_semicolon, GHOST_kKeySemicolon); + GXMAP(type,XK_period, GHOST_kKeyPeriod); + GXMAP(type,XK_comma, GHOST_kKeyComma); + GXMAP(type,XK_quoteright, GHOST_kKeyQuote); + GXMAP(type,XK_quoteleft, GHOST_kKeyAccentGrave); + GXMAP(type,XK_minus, GHOST_kKeyMinus); + GXMAP(type,XK_slash, GHOST_kKeySlash); + GXMAP(type,XK_backslash, GHOST_kKeyBackslash); + GXMAP(type,XK_equal, GHOST_kKeyEqual); + GXMAP(type,XK_bracketleft, GHOST_kKeyLeftBracket); + GXMAP(type,XK_bracketright, GHOST_kKeyRightBracket); + GXMAP(type,XK_Pause, GHOST_kKeyPause); + + GXMAP(type,XK_Shift_L, GHOST_kKeyLeftShift); + GXMAP(type,XK_Shift_R, GHOST_kKeyRightShift); + GXMAP(type,XK_Control_L, GHOST_kKeyLeftControl); + GXMAP(type,XK_Control_R, GHOST_kKeyRightControl); + GXMAP(type,XK_Alt_L, GHOST_kKeyLeftAlt); + GXMAP(type,XK_Alt_R, GHOST_kKeyRightAlt); + + GXMAP(type,XK_Insert, GHOST_kKeyInsert); + GXMAP(type,XK_Delete, GHOST_kKeyDelete); + GXMAP(type,XK_Home, GHOST_kKeyHome); + GXMAP(type,XK_End, GHOST_kKeyEnd); + GXMAP(type,XK_Page_Up, GHOST_kKeyUpPage); + GXMAP(type,XK_Page_Down, GHOST_kKeyDownPage); + + GXMAP(type,XK_Left, GHOST_kKeyLeftArrow); + GXMAP(type,XK_Right, GHOST_kKeyRightArrow); + GXMAP(type,XK_Up, GHOST_kKeyUpArrow); + GXMAP(type,XK_Down, GHOST_kKeyDownArrow); + + GXMAP(type,XK_Caps_Lock, GHOST_kKeyCapsLock); + GXMAP(type,XK_Scroll_Lock, GHOST_kKeyScrollLock); + GXMAP(type,XK_Num_Lock, GHOST_kKeyNumLock); + + /* keypad events */ + + GXMAP(type,XK_KP_0, GHOST_kKeyNumpad0); + GXMAP(type,XK_KP_1, GHOST_kKeyNumpad1); + GXMAP(type,XK_KP_2, GHOST_kKeyNumpad2); + GXMAP(type,XK_KP_3, GHOST_kKeyNumpad3); + GXMAP(type,XK_KP_4, GHOST_kKeyNumpad4); + GXMAP(type,XK_KP_5, GHOST_kKeyNumpad5); + GXMAP(type,XK_KP_6, GHOST_kKeyNumpad6); + GXMAP(type,XK_KP_7, GHOST_kKeyNumpad7); + GXMAP(type,XK_KP_8, GHOST_kKeyNumpad8); + GXMAP(type,XK_KP_9, GHOST_kKeyNumpad9); + GXMAP(type,XK_KP_Decimal, GHOST_kKeyNumpadPeriod); + + GXMAP(type,XK_KP_Insert, GHOST_kKeyNumpad0); + GXMAP(type,XK_KP_End, GHOST_kKeyNumpad1); + GXMAP(type,XK_KP_Down, GHOST_kKeyNumpad2); + GXMAP(type,XK_KP_Page_Down, GHOST_kKeyNumpad3); + GXMAP(type,XK_KP_Left, GHOST_kKeyNumpad4); + GXMAP(type,XK_KP_Begin, GHOST_kKeyNumpad5); + GXMAP(type,XK_KP_Right, GHOST_kKeyNumpad6); + GXMAP(type,XK_KP_Home, GHOST_kKeyNumpad7); + GXMAP(type,XK_KP_Up, GHOST_kKeyNumpad8); + GXMAP(type,XK_KP_Page_Up, GHOST_kKeyNumpad9); + GXMAP(type,XK_KP_Delete, GHOST_kKeyNumpadPeriod); + + GXMAP(type,XK_KP_Enter, GHOST_kKeyNumpadEnter); + GXMAP(type,XK_KP_Add, GHOST_kKeyNumpadPlus); + GXMAP(type,XK_KP_Subtract, GHOST_kKeyNumpadMinus); + GXMAP(type,XK_KP_Multiply, GHOST_kKeyNumpadAsterisk); + GXMAP(type,XK_KP_Divide, GHOST_kKeyNumpadSlash); + + /* some extra sun cruft (NICE KEYBOARD!) */ +#ifdef __sun__ + GXMAP(type,0xffde, GHOST_kKeyNumpad1); + GXMAP(type,0xffe0, GHOST_kKeyNumpad3); + GXMAP(type,0xffdc, GHOST_kKeyNumpad5); + GXMAP(type,0xffd8, GHOST_kKeyNumpad7); + GXMAP(type,0xffda, GHOST_kKeyNumpad9); + + GXMAP(type,0xffd6, GHOST_kKeyNumpadSlash); + GXMAP(type,0xffd7, GHOST_kKeyNumpadAsterisk); +#endif + + default : + type = GHOST_kKeyUnknown; + break; + } + } + + return type; +} + +#undef GXMAP diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h new file mode 100644 index 00000000000..c8d8d73404a --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemX11.h @@ -0,0 +1,245 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_SystemX11.h + * Declaration of GHOST_SystemX11 class. + */ + +#ifndef _GHOST_SYSTEM_X11_H_ +#define _GHOST_SYSTEM_X11_H_ + +#include +#include + +#include "GHOST_System.h" +#include "../GHOST_Types.h" + +class GHOST_WindowX11; + +/** + * X11 Implementation of GHOST_System class. + * @see GHOST_System. + * @author Laurence Bourn + * @date October 26, 2001 + */ + +class GHOST_SystemX11 : public GHOST_System { +public: + + /** + * Constructor + * this class should only be instanciated by GHOST_ISystem. + */ + + GHOST_SystemX11( + ); + + GHOST_TSuccess + init( + ); + + + /** + * @section Interface Inherited from GHOST_ISystem + */ + + /** + * Returns the system time. + * Returns the number of milliseconds since the start of the system process. + * @return The number of milliseconds. + */ + GHOST_TUns64 + getMilliSeconds( + ) const; + + + /** + * Returns the number of displays on this system. + * @return The number of displays. + */ + GHOST_TUns8 + getNumDisplays( + ) const; + + /** + * Returns the dimensions of the main display on this system. + * @return The dimension of the main display. + */ + void + getMainDisplayDimensions( + GHOST_TUns32& width, + GHOST_TUns32& height + ) const; + + /** + * Create a new window. + * The new window is added to the list of windows managed. + * Never explicitly delete the window, use disposeWindow() instead. + * @param title The name of the window (displayed in the title bar of the window if the OS supports it). + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state of the window when opened. + * @param type The type of drawing context installed in this window. + * @param stereoVisual Create a stereo visual for quad buffered stereo. + * @return The new window (or 0 if creation failed). + */ + GHOST_IWindow* + createWindow( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const bool stereoVisual + ); + + /** + * @section Interface Inherited from GHOST_ISystem + */ + + /** + * Retrieves events from the system and stores them in the queue. + * @param waitForEvent Flag to wait for an event (or return immediately). + * @return Indication of the presence of events. + */ + bool + processEvents( + bool waitForEvent + ); + + /** + * @section Interface Inherited from GHOST_System + */ + GHOST_TSuccess + getCursorPosition( + GHOST_TInt32& x, + GHOST_TInt32& y + ) const; + + GHOST_TSuccess + setCursorPosition( + GHOST_TInt32 x, + GHOST_TInt32 y + ) const; + + /** + * Returns the state of all modifier keys. + * @param keys The state of all modifier keys (true == pressed). + * @return Indication of success. + */ + GHOST_TSuccess + getModifierKeys( + GHOST_ModifierKeys& keys + ) const ; + + /** + * Returns the state of the mouse buttons (ouside the message queue). + * @param buttons The state of the buttons. + * @return Indication of success. + */ + GHOST_TSuccess + getButtons( + GHOST_Buttons& buttons + ) const; + + /** + * @section + * Flag a window as dirty. This will + * generate a GHOST window update event on a call to processEvents() + */ + + void + addDirtyWindow( + GHOST_WindowX11 * bad_wind + ); + + + /** + * return a pointer to the X11 display structure + */ + + Display * + getXDisplay( + ) { + return m_display; + } + + +private : + + Display * m_display; + + /** + * Atom used to detect window close events + */ + Atom m_delete_window_atom; + + /// The vector of windows that need to be updated. + std::vector m_dirty_windows; + + /// Start time at initialization. + GHOST_TUns64 m_start_time; + + /// A vector of keyboard key masks + char *m_keyboard_vector; + + /** + * Return the ghost window associated with the + * X11 window xwind + */ + + GHOST_WindowX11 * + findGhostWindow( + Window xwind + ) const ; + + void + processEvent( + XEvent *xe + ); + + bool + generateWindowExposeEvents( + ); + + GHOST_TKey + convertXKey( + KeySym key + ); + +}; + +#endif + diff --git a/intern/ghost/intern/GHOST_TimerManager.cpp b/intern/ghost/intern/GHOST_TimerManager.cpp new file mode 100644 index 00000000000..9f50b350baa --- /dev/null +++ b/intern/ghost/intern/GHOST_TimerManager.cpp @@ -0,0 +1,167 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 31, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_TimerManager.h" + +#include + +#include "GHOST_TimerTask.h" + + +GHOST_TimerManager::GHOST_TimerManager() +{ +} + + +GHOST_TimerManager::~GHOST_TimerManager() +{ + disposeTimers(); +} + + +GHOST_TUns32 GHOST_TimerManager::getNumTimers() +{ + return (GHOST_TUns32)m_timers.size(); +} + + +bool GHOST_TimerManager::getTimerFound(GHOST_TimerTask* timer) +{ + TTimerVector::const_iterator iter = std::find(m_timers.begin(), m_timers.end(), timer); + return iter != m_timers.end(); +} + + +GHOST_TSuccess GHOST_TimerManager::addTimer(GHOST_TimerTask* timer) +{ + GHOST_TSuccess success; + if (!getTimerFound(timer)) { + // Add the timer task + m_timers.push_back(timer); + success = GHOST_kSuccess; + } + else { + success = GHOST_kFailure; + } + return success; +} + + +GHOST_TSuccess GHOST_TimerManager::removeTimer(GHOST_TimerTask* timer) +{ + GHOST_TSuccess success; + TTimerVector::iterator iter = std::find(m_timers.begin(), m_timers.end(), timer); + if (iter != m_timers.end()) { + // Remove the timer task + m_timers.erase(iter); + delete timer; + timer = 0; + success = GHOST_kSuccess; + } + else { + success = GHOST_kFailure; + } + return success; +} + +GHOST_TUns64 GHOST_TimerManager::nextFireTime() +{ + GHOST_TUns64 smallest = GHOST_kFireTimeNever; + TTimerVector::iterator iter; + + for (iter = m_timers.begin(); iter != m_timers.end(); iter++) { + GHOST_TUns64 next = (*iter)->getNext(); + + if (nextgetNext(); + + // Check if the timer should be fired + if (time > next) { + // Fire the timer + GHOST_TimerProcPtr timerProc = task->getTimerProc(); + GHOST_TUns64 start = task->getStart(); + timerProc(task, time - start); + + // Update the time at which we will fire it again + GHOST_TUns64 interval = task->getInterval(); + GHOST_TUns64 numCalls = (next - start) / interval; + numCalls++; + next = start + numCalls * interval; + task->setNext(next); + + return true; + } else { + return false; + } +} + + +void GHOST_TimerManager::disposeTimers() +{ + while (m_timers.size() > 0) { + delete m_timers[0]; + m_timers.erase(m_timers.begin()); + } +} diff --git a/intern/ghost/intern/GHOST_TimerManager.h b/intern/ghost/intern/GHOST_TimerManager.h new file mode 100644 index 00000000000..ff42f95fc0f --- /dev/null +++ b/intern/ghost/intern/GHOST_TimerManager.h @@ -0,0 +1,132 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_TimerManager.h + * Declaration of GHOST_TimerManager class. + */ + +#ifndef _GHOST_TIMER_MANAGER_H_ +#define _GHOST_TIMER_MANAGER_H_ + +#ifdef WIN32 +#pragma warning (disable:4786) // suppress stl-MSVC debug info warning +#endif // WIN32 + +#include + +#include "GHOST_Types.h" + +class GHOST_TimerTask; + + +/** + * Manages a list of timer tasks. + * Timer tasks added are owned by the manager. + * Don't delete timer task objects. + * @author Maarten Gribnau + * @date May 31, 2001 + */ +class GHOST_TimerManager +{ +public: + /** + * Constructor. + */ + GHOST_TimerManager(); + + /** + * Destructor. + */ + virtual ~GHOST_TimerManager(); + + /** + * Returns the number of timer tasks. + * @return The number of events on the stack. + */ + virtual GHOST_TUns32 getNumTimers(); + + /** + * Returns whther this timer task ins in our list. + * @return Indication of presence. + */ + virtual bool getTimerFound(GHOST_TimerTask* timer); + + /** + * Adds a timer task to the list. + * It is only added when it not already present in the list. + * @param timer The timer task added to the list. + * @return Indication as to whether addition has succeeded. + */ + virtual GHOST_TSuccess addTimer(GHOST_TimerTask* timer); + + /** + * Removes a timer task from the list. + * It is only removed when it is found in the list. + * @param timer The timer task to be removed from the list. + * @return Indication as to whether removal has succeeded. + */ + virtual GHOST_TSuccess removeTimer(GHOST_TimerTask* timer); + + /** + * Finds the soonest time the next timer would fire. + * @return The soonest time the next timer would fire, + * or GHOST_kFireTimeNever if no timers exist. + */ + virtual GHOST_TUns64 nextFireTime(); + + /** + * Checks all timer tasks to see if they are expired and fires them if needed. + * @param time The current time. + * @return True if any timers were fired. + */ + virtual bool fireTimers(GHOST_TUns64 time); + + /** + * Checks this timer task to see if they are expired and fires them if needed. + * @param time The current time. + * @param task The timer task to check and optionally fire. + * @return True if the timer fired. + */ + virtual bool fireTimer(GHOST_TUns64 time, GHOST_TimerTask* task); + +protected: + /** + * Deletes all timers. + */ + void disposeTimers(); + + typedef std::vector TTimerVector; + /** The list with event consumers. */ + TTimerVector m_timers; +}; + +#endif // _GHOST_TIMER_MANAGER_H_ + diff --git a/intern/ghost/intern/GHOST_TimerTask.h b/intern/ghost/intern/GHOST_TimerTask.h new file mode 100644 index 00000000000..49bbe5e09ab --- /dev/null +++ b/intern/ghost/intern/GHOST_TimerTask.h @@ -0,0 +1,191 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_TimerTask.h + * Declaration of GHOST_TimerTask class. + */ + +#ifndef _GHOST_TIMER_TASK_H_ +#define _GHOST_TIMER_TASK_H_ + +#include "GHOST_ITimerTask.h" + + +/** + * Implementation of a timer task. + * @author Maarten Gribnau + * @date May 28, 2001 + */ +class GHOST_TimerTask : public GHOST_ITimerTask +{ +public: + /** + * Constructor. + * @param start The timer start time. + * @param interval The interval between calls to the timerProc + * @param timerProc The callbak invoked when the interval expires. + * @param data The timer user data. + */ + GHOST_TimerTask(GHOST_TUns64 start, GHOST_TUns64 interval, GHOST_TimerProcPtr timerProc, GHOST_TUserDataPtr userData = 0) + : m_start(start), m_interval(interval), m_next(start), m_timerProc(timerProc), m_userData(userData), m_auxData(0) + { + } + + /** + * Returns the timer start time. + * @return The timer start time. + */ + inline virtual GHOST_TUns64 getStart() const + { + return m_start; + } + + /** + * Changes the timer start time. + * @param start The timer start time. + */ + virtual void setStart(GHOST_TUns64 start) + { + m_start = start; + } + + /** + * Returns the timer interval. + * @return The timer interval. + */ + inline virtual GHOST_TUns64 getInterval() const + { + return m_interval; + } + + /** + * Changes the timer interval. + * @param interval The timer interval. + */ + virtual void setInterval(GHOST_TUns64 interval) + { + m_interval = interval; + } + + /** + * Returns the time the timerProc will be called. + * @return The time the timerProc will be called. + */ + inline virtual GHOST_TUns64 getNext() const + { + return m_next; + } + + /** + * Changes the time the timerProc will be called. + * @param next The time the timerProc will be called. + */ + virtual void setNext(GHOST_TUns64 next) + { + m_next = next; + } + + /** + * Returns the timer callback. + * @return the timer callback. + */ + inline virtual GHOST_TimerProcPtr getTimerProc() const + { + return m_timerProc; + } + + /** + * Changes the timer callback. + * @param The timer callback. + */ + inline virtual void setTimerProc(const GHOST_TimerProcPtr timerProc) + { + m_timerProc = timerProc; + } + + /** + * Returns the timer user data. + * @return The timer user data. + */ + inline virtual GHOST_TUserDataPtr getUserData() const + { + return m_userData; + } + + /** + * Changes the time user data. + * @param data The timer user data. + */ + virtual void setUserData(const GHOST_TUserDataPtr userData) + { + m_userData = userData; + } + + /** + * Returns the auxiliary storage room. + * @return The auxiliary storage room. + */ + inline virtual GHOST_TUns32 getAuxData() const + { + return m_auxData; + } + + /** + * Changes the auxiliary storage room. + * @param auxData The auxiliary storage room. + */ + virtual void setAuxData(GHOST_TUns32 auxData) + { + m_auxData = auxData; + } + +protected: + /** The time the timer task was started. */ + GHOST_TUns64 m_start; + + /** The interval between calls. */ + GHOST_TUns64 m_interval; + + /** The time the timerProc will be called. */ + GHOST_TUns64 m_next; + + /** The callback invoked when the timer expires. */ + GHOST_TimerProcPtr m_timerProc; + + /** The timer task user data. */ + GHOST_TUserDataPtr m_userData; + + /** Auxiliary storage room. */ + GHOST_TUns32 m_auxData; +}; + +#endif // _GHOST_TIMER_TASK_H_ + diff --git a/intern/ghost/intern/GHOST_Window.cpp b/intern/ghost/intern/GHOST_Window.cpp new file mode 100644 index 00000000000..f4f7c581814 --- /dev/null +++ b/intern/ghost/intern/GHOST_Window.cpp @@ -0,0 +1,129 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 10, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_Window.h" + + +GHOST_Window::GHOST_Window( + const STR_String& /*title*/, + GHOST_TInt32 /*left*/, GHOST_TInt32 /*top*/, GHOST_TUns32 width, GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const bool stereoVisual) +: + m_drawingContextType(type), + m_cursorVisible(true), + m_cursorShape(GHOST_kStandardCursorDefault), + m_stereoVisual(stereoVisual) +{ + m_fullScreen = state == GHOST_kWindowStateFullScreen; + if (m_fullScreen) { + m_fullScreenWidth = width; + m_fullScreenHeight = height; + } +} + + +GHOST_Window::~GHOST_Window() +{ +} + + +GHOST_TSuccess GHOST_Window::setDrawingContextType(GHOST_TDrawingContextType type) +{ + GHOST_TSuccess success = GHOST_kSuccess; + if (type != m_drawingContextType) { + success = removeDrawingContext(); + if (success) { + success = installDrawingContext(type); + m_drawingContextType = type; + } + else { + m_drawingContextType = GHOST_kDrawingContextTypeNone; + } + } + return success; +} + +GHOST_TSuccess GHOST_Window::setCursorVisibility(bool visible) +{ + if (setWindowCursorVisibility(visible)) { + m_cursorVisible = visible; + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } +} + +GHOST_TSuccess GHOST_Window::setCursorShape(GHOST_TStandardCursor cursorShape) +{ + if (setWindowCursorShape(cursorShape)) { + m_cursorShape = cursorShape; + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } +} + +GHOST_TSuccess GHOST_Window::setCustomCursorShape(GHOST_TUns8 bitmap[16][2], GHOST_TUns8 mask[16][2], + int hotX, int hotY) +{ + return setCustomCursorShape( (GHOST_TUns8 *)bitmap, (GHOST_TUns8 *)mask, + 16, 16, hotX, hotY, 0, 1 ); +} + +GHOST_TSuccess GHOST_Window::setCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, + int sizex, int sizey, int hotX, int hotY, + int fg_color, int bg_color ) +{ + if (setWindowCustomCursorShape(bitmap, mask, sizex, sizey,hotX, hotY, fg_color, bg_color)) { + m_cursorShape = GHOST_kStandardCursorCustom; + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } +} + diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h new file mode 100644 index 00000000000..acf28177b37 --- /dev/null +++ b/intern/ghost/intern/GHOST_Window.h @@ -0,0 +1,284 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_Window.h + * Declaration of GHOST_Window class. + */ + +#ifndef _GHOST_WINDOW_H_ +#define _GHOST_WINDOW_H_ + +#include "GHOST_IWindow.h" + +class STR_String; + +/** + * Platform independent implementation of GHOST_IWindow. + * Dimensions are given in screen coordinates that are relative to the + * upper-left corner of the screen. + * Implements part of the GHOST_IWindow interface and adds some methods to + * be implemented by childs of this class. + * @author Maarten Gribnau + * @date May 7, 2001 + */ +class GHOST_Window : public GHOST_IWindow +{ +public: + /** + * @section Interface inherited from GHOST_IWindow left for derived class + * implementation. + * virtual bool getValid() const = 0; + * virtual void setTitle(const STR_String& title) = 0; + * virtual void getTitle(STR_String& title) const = 0; + * virtual void getWindowBounds(GHOST_Rect& bounds) const = 0; + * virtual void getClientBounds(GHOST_Rect& bounds) const = 0; + * virtual GHOST_TSuccess setClientWidth(GHOST_TUns32 width) = 0; + * virtual GHOST_TSuccess setClientHeight(GHOST_TUns32 height) = 0; + * virtual GHOST_TSuccess setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) = 0; + * virtual void screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const = 0; + * virtual void clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const = 0; + * virtual GHOST_TWindowState getState() const = 0; + * virtual GHOST_TSuccess setState(GHOST_TWindowState state) = 0; + * virtual GHOST_TWindowOrder getOrder(void) = 0; + * virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order) = 0; + * virtual GHOST_TSuccess swapBuffers() = 0; + * virtual GHOST_TSuccess activateDrawingContext() = 0; + * virtual GHOST_TSuccess invalidate() = 0; + */ + + /** + * Constructor. + * Creates a new window and opens it. + * To check if the window was created properly, use the getValid() method. + * @param title The text shown in the title bar of the window. + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param heigh The height the window. + * @param state The state the window is initially opened with. + * @param type The type of drawing context installed in this window. + * @param stereoVisual Stereo visual for quad buffered stereo. + */ + GHOST_Window( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone, + const bool stereoVisual = false); + + /** + * @section Interface inherited from GHOST_IWindow left for derived class + * implementation. + * virtual bool getValid() const = 0; + * virtual void setTitle(const STR_String& title) = 0; + * virtual void getTitle(STR_String& title) const = 0; + * virtual void getWindowBounds(GHOST_Rect& bounds) const = 0; + * virtual void getClientBounds(GHOST_Rect& bounds) const = 0; + * virtual GHOST_TSuccess setClientWidth(GHOST_TUns32 width) = 0; + * virtual GHOST_TSuccess setClientHeight(GHOST_TUns32 height) = 0; + * virtual GHOST_TSuccess setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) = 0; + * virtual void screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const = 0; + * virtual void clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const = 0; + * virtual GHOST_TWindowState getState() const = 0; + * virtual GHOST_TSuccess setState(GHOST_TWindowState state) = 0; + * virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order) = 0; + * virtual GHOST_TSuccess swapBuffers() = 0; + * virtual GHOST_TSuccess activateDrawingContext() = 0; + * virtual GHOST_TSuccess invalidate() = 0; + */ + + /** + * Destructor. + * Closes the window and disposes resources allocated. + */ + virtual ~GHOST_Window(); + + /** + * Returns the current cursor shape. + * @return The current cursor shape. + */ + inline virtual GHOST_TStandardCursor getCursorShape() const; + + /** + * Set the shape of the cursor. + * @param cursor The new cursor shape type id. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCursorShape(GHOST_TStandardCursor cursorShape); + + /** + * Set the shape of the cursor to a custom cursor. + * @param bitmap The bitmap data for the cursor. + * @param mask The mask data for the cursor. + * @param hotX The X coordinate of the cursor hotspot. + * @param hotY The Y coordinate of the cursor hotspot. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCustomCursorShape(GHOST_TUns8 bitmap[16][2], + GHOST_TUns8 mask[16][2], + int hotX, + int hotY); + + virtual GHOST_TSuccess setCustomCursorShape(GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, int sizey, + int hotX, int hotY, + int fg_color, int bg_color); + + /** + * Returns the visibility state of the cursor. + * @return The visibility state of the cursor. + */ + inline virtual bool getCursorVisibility() const; + + /** + * Shows or hides the cursor. + * @param visible The new visibility state of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCursorVisibility(bool visible); + + /** + * Returns the type of drawing context used in this window. + * @return The current type of drawing context. + */ + inline virtual GHOST_TDrawingContextType getDrawingContextType(); + + /** + * Tries to install a rendering context in this window. + * Child classes do not need to overload this method. + * They should overload the installDrawingContext and removeDrawingContext instead. + * @param type The type of rendering context installed. + * @return Indication as to whether installation has succeeded. + */ + virtual GHOST_TSuccess setDrawingContextType(GHOST_TDrawingContextType type); + + /** + * Returns the window user data. + * @return The window user data. + */ + inline virtual GHOST_TUserDataPtr getUserData() const + { + return m_userData; + } + + /** + * Changes the window user data. + * @param data The window user data. + */ + virtual void setUserData(const GHOST_TUserDataPtr userData) + { + m_userData = userData; + } + +protected: + /** + * Tries to install a rendering context in this window. + * @param type The type of rendering context installed. + * @return Indication as to whether installation has succeeded. + */ + virtual GHOST_TSuccess installDrawingContext(GHOST_TDrawingContextType type) = 0; + + /** + * Removes the current drawing context. + * @return Indication as to whether removal has succeeded. + */ + virtual GHOST_TSuccess removeDrawingContext() = 0; + + /** + * Sets the cursor visibility on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCursorVisibility(bool visible) = 0; + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape) = 0; + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], GHOST_TUns8 mask[16][2], + int hotX, int hotY) = 0; + + virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, + int szx, int szy, int hotX, int hotY, int fg, int bg) = 0; + /** The the of drawing context installed in this window. */ + GHOST_TDrawingContextType m_drawingContextType; + + /** The window user data */ + GHOST_TUserDataPtr m_userData; + + /** The current visibility of the cursor */ + bool m_cursorVisible; + + /** The current shape of the cursor */ + GHOST_TStandardCursor m_cursorShape; + + /** Stores wether this is a full screen window. */ + bool m_fullScreen; + + /** Stereo visual created. Only necessary for 'real' stereo support, + * ie quad buffered stereo. This is not always possible, depends on + * the graphics h/w + */ + bool m_stereoVisual; + + /** Full-screen width */ + GHOST_TUns32 m_fullScreenWidth; + /** Full-screen height */ + GHOST_TUns32 m_fullScreenHeight; +}; + + +inline GHOST_TDrawingContextType GHOST_Window::getDrawingContextType() +{ + return m_drawingContextType; +} + +inline bool GHOST_Window::getCursorVisibility() const +{ + return m_cursorVisible; +} + +inline GHOST_TStandardCursor GHOST_Window::getCursorShape() const +{ + return m_cursorShape; +} + +#endif // _GHOST_WINDOW_H + diff --git a/intern/ghost/intern/GHOST_WindowCarbon.cpp b/intern/ghost/intern/GHOST_WindowCarbon.cpp new file mode 100644 index 00000000000..04debe36191 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowCarbon.cpp @@ -0,0 +1,742 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 10, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_WindowCarbon.h" +#include "GHOST_Debug.h" + +AGLContext GHOST_WindowCarbon::s_firstaglCtx = NULL; +#ifdef GHOST_DRAW_CARBON_GUTTER +const GHOST_TInt32 GHOST_WindowCarbon::s_sizeRectSize = 16; +#endif //GHOST_DRAW_CARBON_GUTTER + +static const GLint sPreferredFormatWindow[8] = { +AGL_RGBA, +AGL_DOUBLEBUFFER, +AGL_ACCELERATED, +AGL_DEPTH_SIZE, 32, +AGL_AUX_BUFFERS, 1, +AGL_NONE, +}; + +static const GLint sPreferredFormatFullScreen[9] = { +AGL_RGBA, +AGL_DOUBLEBUFFER, +AGL_ACCELERATED, +AGL_FULLSCREEN, +AGL_DEPTH_SIZE, 32, +AGL_AUX_BUFFERS, 1, +AGL_NONE, +}; + + + +WindowRef ugly_hack=NULL; + +const EventTypeSpec kWEvents[] = { + { kEventClassWindow, kEventWindowZoom }, /* for new zoom behaviour */ +}; + +static OSStatus myWEventHandlerProc(EventHandlerCallRef handler, EventRef event, void* userData) { + WindowRef mywindow; + GHOST_WindowCarbon *ghost_window; + OSStatus err; + int theState; + + if (::GetEventKind(event) == kEventWindowZoom) { + err = ::GetEventParameter (event,kEventParamDirectObject,typeWindowRef,NULL,sizeof(mywindow),NULL, &mywindow); + ghost_window = (GHOST_WindowCarbon *) GetWRefCon(mywindow); + theState = ghost_window->getMac_windowState(); + if (theState == 1) + ghost_window->setMac_windowState(2); + else if (theState == 2) + ghost_window->setMac_windowState(1); + + } + return eventNotHandledErr; +} + +GHOST_WindowCarbon::GHOST_WindowCarbon( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const bool stereoVisual +) : + GHOST_Window(title, left, top, width, height, state, GHOST_kDrawingContextTypeNone), + m_windowRef(0), + m_grafPtr(0), + m_aglCtx(0), + m_customCursor(0), + m_fullScreenDirty(false) +{ + Str255 title255; + OSStatus err; + + //fprintf(stderr," main screen top %i left %i height %i width %i\n", top, left, height, width); + + if (state >= GHOST_kWindowState8Normal ) { + if(state == GHOST_kWindowState8Normal) state= GHOST_kWindowStateNormal; + else if(state == GHOST_kWindowState8Maximized) state= GHOST_kWindowStateMaximized; + else if(state == GHOST_kWindowState8Minimized) state= GHOST_kWindowStateMinimized; + else if(state == GHOST_kWindowState8FullScreen) state= GHOST_kWindowStateFullScreen; + + // state = state - 8; this was the simple version of above code, doesnt work in gcc 4.0 + + setMac_windowState(1); + } else + setMac_windowState(0); + + if (state != GHOST_kWindowStateFullScreen) { + Rect bnds = { top, left, top+height, left+width }; + // Boolean visible = (state == GHOST_kWindowStateNormal) || (state == GHOST_kWindowStateMaximized); /*unused*/ + gen2mac(title, title255); + + err = ::CreateNewWindow( kDocumentWindowClass, + kWindowStandardDocumentAttributes+kWindowLiveResizeAttribute, + &bnds, + &m_windowRef); + + if ( err != noErr) { + fprintf(stderr," error creating window %i \n",err); + } else { + + ::SetWRefCon(m_windowRef,(SInt32)this); + setTitle(title); + err = InstallWindowEventHandler (m_windowRef, myWEventHandlerProc, GetEventTypeCount(kWEvents), kWEvents,NULL,NULL); + if ( err != noErr) { + fprintf(stderr," error creating handler %i \n",err); + } else { + // ::TransitionWindow (m_windowRef,kWindowZoomTransitionEffect,kWindowShowTransitionAction,NULL); + ::ShowWindow(m_windowRef); + ::MoveWindow (m_windowRef, left, top,true); + + } + } + if (m_windowRef) { + m_grafPtr = ::GetWindowPort(m_windowRef); + setDrawingContextType(type); + updateDrawingContext(); + activateDrawingContext(); + } + if(ugly_hack==NULL) { + ugly_hack= m_windowRef; + // when started from commandline, window remains in the back... also for play anim + ProcessSerialNumber psn; + GetCurrentProcess(&psn); + SetFrontProcess(&psn); + } + } + else { + /* + Rect bnds = { top, left, top+height, left+width }; + gen2mac("", title255); + m_windowRef = ::NewCWindow( + nil, // Storage + &bnds, // Bounding rectangle of the window + title255, // Title of the window + 0, // Window initially visible + plainDBox, // procID + (WindowRef)-1L, // Put window before all other windows + 0, // Window has minimize box + (SInt32)this); // Store a pointer to the class in the refCon + */ + //GHOST_PRINT("GHOST_WindowCarbon::GHOST_WindowCarbon(): creating full-screen OpenGL context\n"); + setDrawingContextType(GHOST_kDrawingContextTypeOpenGL);;installDrawingContext(GHOST_kDrawingContextTypeOpenGL); + updateDrawingContext(); + activateDrawingContext(); + + m_tablet.Active = 0; + } +} + + +GHOST_WindowCarbon::~GHOST_WindowCarbon() +{ + if (m_customCursor) delete m_customCursor; + + if(ugly_hack==m_windowRef) ugly_hack= NULL; + + // printf("GHOST_WindowCarbon::~GHOST_WindowCarbon(): removing drawing context\n"); + if(ugly_hack==NULL) setDrawingContextType(GHOST_kDrawingContextTypeNone); + if (m_windowRef) { + ::DisposeWindow(m_windowRef); + m_windowRef = 0; + } +} + +bool GHOST_WindowCarbon::getValid() const +{ + bool valid; + if (!m_fullScreen) { + valid = (m_windowRef != 0) && (m_grafPtr != 0) && ::IsValidWindowPtr(m_windowRef); + } + else { + valid = true; + } + return valid; +} + + +void GHOST_WindowCarbon::setTitle(const STR_String& title) +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::setTitle(): window invalid") + Str255 title255; + gen2mac(title, title255); + ::SetWTitle(m_windowRef, title255); +} + + +void GHOST_WindowCarbon::getTitle(STR_String& title) const +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::getTitle(): window invalid") + Str255 title255; + ::GetWTitle(m_windowRef, title255); + mac2gen(title255, title); +} + + +void GHOST_WindowCarbon::getWindowBounds(GHOST_Rect& bounds) const +{ + OSStatus success; + Rect rect; + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::getWindowBounds(): window invalid") + success = ::GetWindowBounds(m_windowRef, kWindowStructureRgn, &rect); + bounds.m_b = rect.bottom; + bounds.m_l = rect.left; + bounds.m_r = rect.right; + bounds.m_t = rect.top; +} + + +void GHOST_WindowCarbon::getClientBounds(GHOST_Rect& bounds) const +{ + Rect rect; + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::getClientBounds(): window invalid") + ::GetPortBounds(m_grafPtr, &rect); + bounds.m_b = rect.bottom; + bounds.m_l = rect.left; + bounds.m_r = rect.right; + bounds.m_t = rect.top; + + // Subtract gutter height from bottom +#ifdef GHOST_DRAW_CARBON_GUTTER + if ((bounds.m_b - bounds.m_t) > s_sizeRectSize) + { + bounds.m_b -= s_sizeRectSize; + } + else + { + bounds.m_t = bounds.m_b; + } +#endif //GHOST_DRAW_CARBON_GUTTER +} + + +GHOST_TSuccess GHOST_WindowCarbon::setClientWidth(GHOST_TUns32 width) +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::setClientWidth(): window invalid") + GHOST_Rect cBnds, wBnds; + getClientBounds(cBnds); + if (((GHOST_TUns32)cBnds.getWidth()) != width) { + ::SizeWindow(m_windowRef, width, cBnds.getHeight(), true); + } + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_WindowCarbon::setClientHeight(GHOST_TUns32 height) +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::setClientHeight(): window invalid") + GHOST_Rect cBnds, wBnds; + getClientBounds(cBnds); +#ifdef GHOST_DRAW_CARBON_GUTTER + if (((GHOST_TUns32)cBnds.getHeight()) != height+s_sizeRectSize) { + ::SizeWindow(m_windowRef, cBnds.getWidth(), height+s_sizeRectSize, true); + } +#else //GHOST_DRAW_CARBON_GUTTER + if (((GHOST_TUns32)cBnds.getHeight()) != height) { + ::SizeWindow(m_windowRef, cBnds.getWidth(), height, true); + } +#endif //GHOST_DRAW_CARBON_GUTTER + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_WindowCarbon::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::setClientSize(): window invalid") + GHOST_Rect cBnds, wBnds; + getClientBounds(cBnds); +#ifdef GHOST_DRAW_CARBON_GUTTER + if ((((GHOST_TUns32)cBnds.getWidth()) != width) || + (((GHOST_TUns32)cBnds.getHeight()) != height+s_sizeRectSize)) { + ::SizeWindow(m_windowRef, width, height+s_sizeRectSize, true); + } +#else //GHOST_DRAW_CARBON_GUTTER + if ((((GHOST_TUns32)cBnds.getWidth()) != width) || + (((GHOST_TUns32)cBnds.getHeight()) != height)) { + ::SizeWindow(m_windowRef, width, height, true); + } +#endif //GHOST_DRAW_CARBON_GUTTER + return GHOST_kSuccess; +} + + +GHOST_TWindowState GHOST_WindowCarbon::getState() const +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::getState(): window invalid") + GHOST_TWindowState state; + if (::IsWindowVisible(m_windowRef)) { + state = GHOST_kWindowStateMinimized; + } + else if (::IsWindowInStandardState(m_windowRef, nil, nil)) { + state = GHOST_kWindowStateMaximized; + } + else { + state = GHOST_kWindowStateNormal; + } + return state; +} + + +void GHOST_WindowCarbon::screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::screenToClient(): window invalid") + Point point; + point.h = inX; + point.v = inY; + GrafPtr oldPort; + ::GetPort(&oldPort); + ::SetPort(m_grafPtr); + ::GlobalToLocal(&point); + ::SetPort(oldPort); + outX = point.h; + outY = point.v; +} + + +void GHOST_WindowCarbon::clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::clientToScreen(): window invalid") + Point point; + point.h = inX; + point.v = inY; + GrafPtr oldPort; + ::GetPort(&oldPort); + ::SetPort(m_grafPtr); + ::LocalToGlobal(&point); + ::SetPort(oldPort); + outX = point.h; + outY = point.v; +} + + +GHOST_TSuccess GHOST_WindowCarbon::setState(GHOST_TWindowState state) +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::setState(): window invalid") + switch (state) { + case GHOST_kWindowStateMinimized: + ::HideWindow(m_windowRef); + break; + case GHOST_kWindowStateMaximized: + case GHOST_kWindowStateNormal: + default: + ::ShowWindow(m_windowRef); + break; + } + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_WindowCarbon::setOrder(GHOST_TWindowOrder order) +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::setOrder(): window invalid") + if (order == GHOST_kWindowOrderTop) { + //::BringToFront(m_windowRef); is wrong, front window should be active for input too + ::SelectWindow(m_windowRef); + } + else { + /* doesnt work if you do this with a mouseclick */ + ::SendBehind(m_windowRef, nil); + } + return GHOST_kSuccess; +} + +/*#define WAIT_FOR_VSYNC 1*/ +#ifdef WAIT_FOR_VSYNC +#include +#endif + +GHOST_TSuccess GHOST_WindowCarbon::swapBuffers() +{ +#ifdef WAIT_FOR_VSYNC +/* wait for vsync, to avoid tearing artifacts */ +long VBL = 1; +CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &VBL); +#endif + + GHOST_TSuccess succeeded = GHOST_kSuccess; + if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { + if (m_aglCtx) { + ::aglSwapBuffers(m_aglCtx); + } + else { + succeeded = GHOST_kFailure; + } + } + return succeeded; +} + +GHOST_TSuccess GHOST_WindowCarbon::updateDrawingContext() +{ + GHOST_TSuccess succeeded = GHOST_kSuccess; + if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { + if (m_aglCtx) { + ::aglUpdateContext(m_aglCtx); + } + else { + succeeded = GHOST_kFailure; + } + } + return succeeded; +} + +GHOST_TSuccess GHOST_WindowCarbon::activateDrawingContext() +{ + GHOST_TSuccess succeeded = GHOST_kSuccess; + if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { + if (m_aglCtx) { + ::aglSetCurrentContext(m_aglCtx); +#ifdef GHOST_DRAW_CARBON_GUTTER + // Restrict drawing to non-gutter area + ::aglEnable(m_aglCtx, AGL_BUFFER_RECT); + GHOST_Rect bnds; + getClientBounds(bnds); + GLint b[4] = + { + bnds.m_l, + bnds.m_t+s_sizeRectSize, + bnds.m_r-bnds.m_l, + bnds.m_b-bnds.m_t + }; + GLboolean result = ::aglSetInteger(m_aglCtx, AGL_BUFFER_RECT, b); +#endif //GHOST_DRAW_CARBON_GUTTER + } + else { + succeeded = GHOST_kFailure; + } + } + return succeeded; +} + + +GHOST_TSuccess GHOST_WindowCarbon::installDrawingContext(GHOST_TDrawingContextType type) +{ + GHOST_TSuccess success = GHOST_kFailure; + switch (type) { + case GHOST_kDrawingContextTypeOpenGL: + { + if (!getValid()) break; + + AGLPixelFormat pixelFormat; + if (!m_fullScreen) { + pixelFormat = ::aglChoosePixelFormat(0, 0, sPreferredFormatWindow); + m_aglCtx = ::aglCreateContext(pixelFormat, s_firstaglCtx); + if (!m_aglCtx) break; + if (!s_firstaglCtx) s_firstaglCtx = m_aglCtx; + success = ::aglSetDrawable(m_aglCtx, m_grafPtr) == GL_TRUE ? GHOST_kSuccess : GHOST_kFailure; + } + else { + //GHOST_PRINT("GHOST_WindowCarbon::installDrawingContext(): init full-screen OpenGL\n"); +GDHandle device=::GetMainDevice();pixelFormat=::aglChoosePixelFormat(&device,1,sPreferredFormatFullScreen); + m_aglCtx = ::aglCreateContext(pixelFormat, 0); + if (!m_aglCtx) break; + if (!s_firstaglCtx) s_firstaglCtx = m_aglCtx; + //GHOST_PRINT("GHOST_WindowCarbon::installDrawingContext(): created OpenGL context\n"); + //::CGGetActiveDisplayList(0, NULL, &m_numDisplays) + success = ::aglSetFullScreen(m_aglCtx, m_fullScreenWidth, m_fullScreenHeight, 75, 0) == GL_TRUE ? GHOST_kSuccess : GHOST_kFailure; + /* + if (success == GHOST_kSuccess) { + GHOST_PRINT("GHOST_WindowCarbon::installDrawingContext(): init full-screen OpenGL succeeded\n"); + } + else { + GHOST_PRINT("GHOST_WindowCarbon::installDrawingContext(): init full-screen OpenGL failed\n"); + } + */ + } + ::aglDestroyPixelFormat(pixelFormat); + } + break; + + case GHOST_kDrawingContextTypeNone: + success = GHOST_kSuccess; + break; + + default: + break; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowCarbon::removeDrawingContext() +{ + GHOST_TSuccess success = GHOST_kFailure; + switch (m_drawingContextType) { + case GHOST_kDrawingContextTypeOpenGL: + if (m_aglCtx) { + aglSetCurrentContext(NULL); + aglSetDrawable(m_aglCtx, NULL); + //aglDestroyContext(m_aglCtx); + if (s_firstaglCtx == m_aglCtx) s_firstaglCtx = NULL; + success = ::aglDestroyContext(m_aglCtx) == GL_TRUE ? GHOST_kSuccess : GHOST_kFailure; + m_aglCtx = 0; + } + break; + case GHOST_kDrawingContextTypeNone: + success = GHOST_kSuccess; + break; + default: + break; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowCarbon::invalidate() +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::invalidate(): window invalid") + if (!m_fullScreen) { + Rect rect; + ::GetPortBounds(m_grafPtr, &rect); + ::InvalWindowRect(m_windowRef, &rect); + } + else { + //EventRef event; + //OSStatus status = ::CreateEvent(NULL, kEventClassWindow, kEventWindowUpdate, 0, 0, &event); + //GHOST_PRINT("GHOST_WindowCarbon::invalidate(): created event " << status << " \n"); + //status = ::SetEventParameter(event, kEventParamDirectObject, typeWindowRef, sizeof(WindowRef), this); + //GHOST_PRINT("GHOST_WindowCarbon::invalidate(): set event parameter " << status << " \n"); + //status = ::PostEventToQueue(::GetMainEventQueue(), event, kEventPriorityStandard); + //status = ::SendEventToEventTarget(event, ::GetApplicationEventTarget()); + //GHOST_PRINT("GHOST_WindowCarbon::invalidate(): added event to queue " << status << " \n"); + m_fullScreenDirty = true; + } + return GHOST_kSuccess; +} + + +void GHOST_WindowCarbon::gen2mac(const STR_String& in, Str255 out) const +{ + STR_String tempStr = in; + int num = tempStr.Length(); + if (num > 255) num = 255; + ::memcpy(out+1, tempStr.Ptr(), num); + out[0] = num; +} + + +void GHOST_WindowCarbon::mac2gen(const Str255 in, STR_String& out) const +{ + char tmp[256]; + ::memcpy(tmp, in+1, in[0]); + tmp[in[0]] = '\0'; + out = tmp; +} + +void GHOST_WindowCarbon::loadCursor(bool visible, GHOST_TStandardCursor cursor) const +{ + static bool systemCursorVisible = true; + + if (visible != systemCursorVisible) { + if (visible) { + ::ShowCursor(); + systemCursorVisible = true; + } + else { + ::HideCursor(); + systemCursorVisible = false; + } + } + + if (cursor == GHOST_kStandardCursorCustom && m_customCursor) { + ::SetCursor( m_customCursor ); + } else { + int carbon_cursor; + +#define GCMAP(ghostCursor, carbonCursor) case ghostCursor: carbon_cursor = carbonCursor; break + switch (cursor) { + default: + GCMAP( GHOST_kStandardCursorDefault, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorRightArrow, kThemeAliasArrowCursor); + GCMAP( GHOST_kStandardCursorLeftArrow, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorInfo, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorDestroy, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorHelp, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorCycle, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorSpray, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorWait, kThemeWatchCursor); + GCMAP( GHOST_kStandardCursorText, kThemeIBeamCursor); + GCMAP( GHOST_kStandardCursorCrosshair, kThemeCrossCursor); + GCMAP( GHOST_kStandardCursorUpDown, kThemeClosedHandCursor); + GCMAP( GHOST_kStandardCursorLeftRight, kThemeClosedHandCursor); + GCMAP( GHOST_kStandardCursorTopSide, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorBottomSide, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorLeftSide, kThemeResizeLeftCursor); + GCMAP( GHOST_kStandardCursorRightSide, kThemeResizeRightCursor); + GCMAP( GHOST_kStandardCursorTopLeftCorner, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorTopRightCorner, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorBottomRightCorner, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorBottomLeftCorner, kThemeArrowCursor); + }; +#undef GCMAP + + ::SetThemeCursor(carbon_cursor); + } +} + + +bool GHOST_WindowCarbon::getFullScreenDirty() +{ + return m_fullScreen && m_fullScreenDirty; +} + + +GHOST_TSuccess GHOST_WindowCarbon::setWindowCursorVisibility(bool visible) +{ + if (::FrontWindow() == m_windowRef) { + loadCursor(visible, getCursorShape()); + } + + return GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_WindowCarbon::setWindowCursorShape(GHOST_TStandardCursor shape) +{ + if (m_customCursor) { + delete m_customCursor; + m_customCursor = 0; + } + + if (::FrontWindow() == m_windowRef) { + loadCursor(getCursorVisibility(), shape); + } + + return GHOST_kSuccess; +} + +#if 0 +/** Reverse the bits in a GHOST_TUns8 */ +static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch) +{ + ch= ((ch>>1)&0x55) | ((ch<<1)&0xAA); + ch= ((ch>>2)&0x33) | ((ch<<2)&0xCC); + ch= ((ch>>4)&0x0F) | ((ch<<4)&0xF0); + return ch; +} +#endif + + +/** Reverse the bits in a GHOST_TUns16 */ +static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt) +{ + shrt= ((shrt>>1)&0x5555) | ((shrt<<1)&0xAAAA); + shrt= ((shrt>>2)&0x3333) | ((shrt<<2)&0xCCCC); + shrt= ((shrt>>4)&0x0F0F) | ((shrt<<4)&0xF0F0); + shrt= ((shrt>>8)&0x00FF) | ((shrt<<8)&0xFF00); + return shrt; +} + +GHOST_TSuccess GHOST_WindowCarbon::setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, + int sizex, int sizey, int hotX, int hotY, int fg_color, int bg_color) +{ + int y; + + if (m_customCursor) { + delete m_customCursor; + m_customCursor = 0; + } + + m_customCursor = new Cursor; + if (!m_customCursor) return GHOST_kFailure; + + for (y=0; y<16; y++) { +#if !defined(__LITTLE_ENDIAN__) + m_customCursor->data[y] = uns16ReverseBits((bitmap[2*y]<<0) | (bitmap[2*y+1]<<8)); + m_customCursor->mask[y] = uns16ReverseBits((mask[2*y]<<0) | (mask[2*y+1]<<8)); +#else + m_customCursor->data[y] = uns16ReverseBits((bitmap[2*y+1]<<0) | (bitmap[2*y]<<8)); + m_customCursor->mask[y] = uns16ReverseBits((mask[2*y+1]<<0) | (mask[2*y]<<8)); +#endif + + } + + m_customCursor->hotSpot.h = hotX; + m_customCursor->hotSpot.v = hotY; + + if (::FrontWindow() == m_windowRef) { + loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom); + } + + return GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_WindowCarbon::setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], + GHOST_TUns8 mask[16][2], int hotX, int hotY) +{ + return setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*) mask, 16, 16, hotX, hotY, 0, 1); +} + + +void GHOST_WindowCarbon::setMac_windowState(short value) +{ + mac_windowState = value; +} + +short GHOST_WindowCarbon::getMac_windowState() +{ + return mac_windowState; +} diff --git a/intern/ghost/intern/GHOST_WindowCarbon.h b/intern/ghost/intern/GHOST_WindowCarbon.h new file mode 100644 index 00000000000..5b81470a030 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowCarbon.h @@ -0,0 +1,314 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_WindowCarbon.h + * Declaration of GHOST_WindowCarbon class. + */ + +#ifndef _GHOST_WINDOW_CARBON_H_ +#define _GHOST_WINDOW_CARBON_H_ + +#ifndef __APPLE__ +#error Apple OSX only! +#endif // __APPLE__ + +#include "GHOST_Window.h" +#include "STR_String.h" + +#define __CARBONSOUND__ +#include + +#include + + +/** + * Window on Mac OSX/Carbon. + * Carbon windows have a size widget in the lower right corner of the window. + * To force it to be visible, the height of the client rectangle is reduced so + * that applications do not draw in that area. GHOST will manage that area + * which is called the gutter. + * When OpenGL contexts are active, GHOST will use AGL_BUFFER_RECT to prevent + * OpenGL drawing outside the reduced client rectangle. + * @author Maarten Gribnau + * @date May 23, 2001 + */ +class GHOST_WindowCarbon : public GHOST_Window { +public: + /** + * Constructor. + * Creates a new window and opens it. + * To check if the window was created properly, use the getValid() method. + * @param title The text shown in the title bar of the window. + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state the window is initially opened with. + * @param type The type of drawing context installed in this window. + * @param stereoVisual Stereo visual for quad buffered stereo. + */ + GHOST_WindowCarbon( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone, + const bool stereoVisual = false + ); + + /** + * Destructor. + * Closes the window and disposes resources allocated. + */ + virtual ~GHOST_WindowCarbon(); + + /** + * Returns indication as to whether the window is valid. + * @return The validity of the window. + */ + virtual bool getValid() const; + + /** + * Sets the title displayed in the title bar. + * @param title The title to display in the title bar. + */ + virtual void setTitle(const STR_String& title); + + /** + * Returns the title displayed in the title bar. + * @param title The title displayed in the title bar. + */ + virtual void getTitle(STR_String& title) const; + + /** + * Returns the window rectangle dimensions. + * The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen. + * @param bounds The bounding rectangle of the window. + */ + virtual void getWindowBounds(GHOST_Rect& bounds) const; + + /** + * Returns the client rectangle dimensions. + * The left and top members of the rectangle are always zero. + * @param bounds The bounding rectangle of the cleient area of the window. + */ + virtual void getClientBounds(GHOST_Rect& bounds) const; + + /** + * Resizes client rectangle width. + * @param width The new width of the client area of the window. + */ + virtual GHOST_TSuccess setClientWidth(GHOST_TUns32 width); + + /** + * Resizes client rectangle height. + * @param height The new height of the client area of the window. + */ + virtual GHOST_TSuccess setClientHeight(GHOST_TUns32 height); + + /** + * Resizes client rectangle. + * @param width The new width of the client area of the window. + * @param height The new height of the client area of the window. + */ + virtual GHOST_TSuccess setClientSize(GHOST_TUns32 width, GHOST_TUns32 height); + + /** + * Returns the state of the window (normal, minimized, maximized). + * @return The state of the window. + */ + virtual GHOST_TWindowState getState() const; + + /** + * Converts a point in screen coordinates to client rectangle coordinates + * @param inX The x-coordinate on the screen. + * @param inY The y-coordinate on the screen. + * @param outX The x-coordinate in the client rectangle. + * @param outY The y-coordinate in the client rectangle. + */ + virtual void screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const; + + /** + * Converts a point in screen coordinates to client rectangle coordinates + * @param inX The x-coordinate in the client rectangle. + * @param inY The y-coordinate in the client rectangle. + * @param outX The x-coordinate on the screen. + * @param outY The y-coordinate on the screen. + */ + virtual void clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const; + + /** + * Sets the state of the window (normal, minimized, maximized). + * @param state The state of the window. + * @return Indication of success. + */ + virtual GHOST_TSuccess setState(GHOST_TWindowState state); + + /** + * Sets the order of the window (bottom, top). + * @param order The order of the window. + * @return Indication of success. + */ + virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order); + + /** + * Swaps front and back buffers of a window. + * @return A boolean success indicator. + */ + virtual GHOST_TSuccess swapBuffers(); + + /** + * Updates the drawing context of this window. Needed + * whenever the window is changed. + * @return Indication of success. + */ + GHOST_TSuccess updateDrawingContext(); + + /** + * Activates the drawing context of this window. + * @return A boolean success indicator. + */ + virtual GHOST_TSuccess activateDrawingContext(); + + virtual void loadCursor(bool visible, GHOST_TStandardCursor cursor) const; + + /** + * Returns the dirty state of the window when in full-screen mode. + * @return Whether it is dirty. + */ + virtual bool getFullScreenDirty(); + + /* accessor for fullscreen window */ + virtual void setMac_windowState(short value); + virtual short getMac_windowState(); + + + const GHOST_TabletData* GetTabletData() + { return &m_tablet; } + + GHOST_TabletData& GetCarbonTabletData() + { return m_tablet; } +protected: + /** + * Tries to install a rendering context in this window. + * @param type The type of rendering context installed. + * @return Indication as to whether installation has succeeded. + */ + virtual GHOST_TSuccess installDrawingContext(GHOST_TDrawingContextType type); + + /** + * Removes the current drawing context. + * @return Indication as to whether removal has succeeded. + */ + virtual GHOST_TSuccess removeDrawingContext(); + + /** + * Invalidates the contents of this window. + * @return Indication of success. + */ + virtual GHOST_TSuccess invalidate(); + + /** + * Sets the cursor visibility on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCursorVisibility(bool visible); + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape); + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, + int sizex, int sizey, int hotX, int hotY, int fg_color, int bg_color); + + virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], GHOST_TUns8 mask[16][2], int hotX, int hotY); + + /** + * Converts a string object to a Mac Pascal string. + * @param in The string object to be converted. + * @param out The converted string. + */ + virtual void gen2mac(const STR_String& in, Str255 out) const; + + /** + * Converts a Mac Pascal string to a string object. + * @param in The string to be converted. + * @param out The converted string object. + */ + virtual void mac2gen(const Str255 in, STR_String& out) const; + + WindowRef m_windowRef; + CGrafPtr m_grafPtr; + AGLContext m_aglCtx; + + /** The first created OpenGL context (for sharing display lists) */ + static AGLContext s_firstaglCtx; + + Cursor* m_customCursor; + + GHOST_TabletData m_tablet; + + /** When running in full-screen this tells whether to refresh the window. */ + bool m_fullScreenDirty; + + /** specific MacOs X full screen window setting as we use partially system mechanism + values : 0 not maximizable default + 1 normal state + 2 maximized state + + this will be reworked when rebuilding GHOST carbon to use new OS X apis + in order to be unified with GHOST fullscreen/maximised settings + + (lukep) + **/ + + short mac_windowState; + + + /** + * The width/height of the size rectangle in the lower right corner of a + * Mac/Carbon window. This is also the height of the gutter area. + */ +#ifdef GHOST_DRAW_CARBON_GUTTER + static const GHOST_TInt32 s_sizeRectSize; +#endif // GHOST_DRAW_CARBON_GUTTER +}; + +#endif // _GHOST_WINDOW_CARBON_H_ + diff --git a/intern/ghost/intern/GHOST_WindowManager.cpp b/intern/ghost/intern/GHOST_WindowManager.cpp new file mode 100644 index 00000000000..775260a9503 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowManager.cpp @@ -0,0 +1,198 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 11, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_WindowManager.h" +#include +#include "GHOST_Debug.h" +#include "GHOST_Window.h" + + +GHOST_WindowManager::GHOST_WindowManager() : + m_fullScreenWindow(0), + m_activeWindow(0), + m_activeWindowBeforeFullScreen(0) +{ +} + + +GHOST_WindowManager::~GHOST_WindowManager() +{ +} + + +GHOST_TSuccess GHOST_WindowManager::addWindow(GHOST_IWindow* window) +{ + GHOST_TSuccess success = GHOST_kFailure; + if (window) { + if (!getWindowFound(window)) { + // Store the pointer to the window + m_windows.push_back(window); + success = GHOST_kSuccess; + } + } + return success; +} + + +GHOST_TSuccess GHOST_WindowManager::removeWindow(const GHOST_IWindow* window) +{ + GHOST_TSuccess success = GHOST_kFailure; + if (window) { + if (window == m_fullScreenWindow) { + endFullScreen(); + } + else { + vector::iterator result = find(m_windows.begin(), m_windows.end(), window); + if (result != m_windows.end()) { + setWindowInactive(window); + m_windows.erase(result); + success = GHOST_kSuccess; + } + } + } + return success; +} + + +bool GHOST_WindowManager::getWindowFound(const GHOST_IWindow* window) const +{ + bool found = false; + if (window) { + if (getFullScreen() && (window == m_fullScreenWindow)) { + found = true; + } + else { + vector::const_iterator result = find(m_windows.begin(), m_windows.end(), window); + if (result != m_windows.end()) { + found = true; + } + } + } + return found; +} + + +bool GHOST_WindowManager::getFullScreen(void) const +{ + return m_fullScreenWindow != 0; +} + + +GHOST_IWindow* GHOST_WindowManager::getFullScreenWindow(void) const +{ + return m_fullScreenWindow; +} + + +GHOST_TSuccess GHOST_WindowManager::beginFullScreen(GHOST_IWindow* window, + bool stereoVisual) +{ + GHOST_TSuccess success = GHOST_kFailure; + GHOST_ASSERT(window, "GHOST_WindowManager::beginFullScreen(): invalid window"); + GHOST_ASSERT(window->getValid(), "GHOST_WindowManager::beginFullScreen(): invalid window"); + if (!getFullScreen()) { + m_fullScreenWindow = window; + m_activeWindowBeforeFullScreen = getActiveWindow(); + setActiveWindow(m_fullScreenWindow); + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowManager::endFullScreen(void) +{ + GHOST_TSuccess success = GHOST_kFailure; + if (getFullScreen()) { + if (m_fullScreenWindow != 0) { + //GHOST_PRINT("GHOST_WindowManager::endFullScreen(): deleting full-screen window\n"); + setWindowInactive(m_fullScreenWindow); + delete m_fullScreenWindow; + //GHOST_PRINT("GHOST_WindowManager::endFullScreen(): done\n"); + m_fullScreenWindow = 0; + if (m_activeWindowBeforeFullScreen) { + setActiveWindow(m_activeWindowBeforeFullScreen); + } + } + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowManager::setActiveWindow(GHOST_IWindow* window) +{ + GHOST_TSuccess success = GHOST_kSuccess; + if (window != m_activeWindow) { + if (getWindowFound(window)) { + m_activeWindow = window; + } + else { + success = GHOST_kFailure; + } + } + return success; +} + + +GHOST_IWindow* GHOST_WindowManager::getActiveWindow(void) const +{ + return m_activeWindow; +} + + +void GHOST_WindowManager::setWindowInactive(const GHOST_IWindow* window) +{ + if (window == m_activeWindow) { + m_activeWindow = 0; + } +} + + + std::vector & +GHOST_WindowManager:: +getWindows( +){ + return m_windows; +} + diff --git a/intern/ghost/intern/GHOST_WindowManager.h b/intern/ghost/intern/GHOST_WindowManager.h new file mode 100644 index 00000000000..f2ad003d801 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowManager.h @@ -0,0 +1,164 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_WindowManager.h + * Declaration of GHOST_WindowManager class. + */ + +#ifndef _GHOST_WINDOW_MANAGER_H_ +#define _GHOST_WINDOW_MANAGER_H_ + +#ifdef WIN32 +#pragma warning (disable:4786) // suppress stl-MSVC debug info warning +#endif // WIN32 + +#include + +#include "GHOST_Rect.h" +#include "GHOST_IWindow.h" + + +/** + * Manages system windows (platform independent implementation). + * @author Maarten Gribnau + * @date May 11, 2001 + */ +class GHOST_WindowManager +{ +public: + /** + * Constructor. + */ + GHOST_WindowManager(); + + /** + * Destructor. + */ + virtual ~GHOST_WindowManager(); + + /** + * Add a window to our list. + * It is only added if it is not already in the list. + * @param window Pointer to the window to be added. + * @return Indication of success. + */ + virtual GHOST_TSuccess addWindow(GHOST_IWindow* window); + + /** + * Remove a window from our list. + * @param window Pointer to the window to be removed. + * @return Indication of success. + */ + virtual GHOST_TSuccess removeWindow(const GHOST_IWindow* window); + + /** + * Returns whether the window is in our list. + * @param window Pointer to the window to query. + * @return A boolean indicator. + */ + virtual bool getWindowFound(const GHOST_IWindow* window) const; + + /** + * Returns whether one of the windows is fullscreen. + * @return A boolean indicator. + */ + virtual bool getFullScreen(void) const; + + /** + * Returns pointer to the full-screen window. + * @return The fll-screen window (0 if not in full-screen). + */ + virtual GHOST_IWindow* getFullScreenWindow(void) const; + + /** + * Activates fullscreen mode for a window. + * @param window The window displayed fullscreen. + * @return Indication of success. + */ + virtual GHOST_TSuccess beginFullScreen(GHOST_IWindow* window, const bool stereoVisual); + + /** + * Closes fullscreen mode down. + * @return Indication of success. + */ + virtual GHOST_TSuccess endFullScreen(void); + + /** + * Sets new window as active window (the window receiving events). + * There can be only one window active which should be in the current window list. + * @param window The new active window. + */ + virtual GHOST_TSuccess setActiveWindow(GHOST_IWindow* window); + + /** + * Returns the active window (the window receiving events). + * There can be only one window active which should be in the current window list. + * @return window The active window (or NULL if there is none). + */ + virtual GHOST_IWindow* getActiveWindow(void) const; + + + /** + * Set this window to be inactive (not receiving events). + * @param window The window to decativate. + */ + virtual void setWindowInactive(const GHOST_IWindow* window); + + + /** + * Return a vector of the windows currently managed by this + * class. + * @warning It is very dangerous to mess with the contents of + * this vector. Please do not destroy or add windows use the + * interface above for this, + */ + + std::vector & + getWindows( + ); + + +protected: + /** The list of windows managed */ + std::vector m_windows; + + /** Window in fullscreen state. There can be only one of this which is not in or window list. */ + GHOST_IWindow* m_fullScreenWindow; + + /** The active window. */ + GHOST_IWindow* m_activeWindow; + + /** Window that was active before entering fullscreen state. */ + GHOST_IWindow* m_activeWindowBeforeFullScreen; +}; + +#endif // _GHOST_WINDOW_MANAGER_H_ + diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp new file mode 100644 index 00000000000..ef7294c2354 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -0,0 +1,886 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 10, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include "GHOST_WindowWin32.h" +#include +#include + +// MSVC6 still doesn't define M_PI +#ifndef M_PI +#define M_PI 3.1415926536 +#endif + +LPCSTR GHOST_WindowWin32::s_windowClassName = "GHOST_WindowClass"; +const int GHOST_WindowWin32::s_maxTitleLength = 128; +HGLRC GHOST_WindowWin32::s_firsthGLRc = NULL; + +static int WeightPixelFormat(PIXELFORMATDESCRIPTOR& pfd); +static int EnumPixelFormats(HDC hdc); + +/* + * Color and depth bit values are not to be trusted. + * For instance, on TNT2: + * When the screen color depth is set to 16 bit, we get 5 color bits + * and 16 depth bits. + * When the screen color depth is set to 32 bit, we get 8 color bits + * and 24 depth bits. + * Just to be safe, we request high waulity settings. + */ +static PIXELFORMATDESCRIPTOR sPreferredFormat = { + sizeof(PIXELFORMATDESCRIPTOR), /* size */ + 1, /* version */ + PFD_SUPPORT_OPENGL | + PFD_DRAW_TO_WINDOW | + PFD_SWAP_COPY | /* support swap copy */ + PFD_DOUBLEBUFFER, /* support double-buffering */ + PFD_TYPE_RGBA, /* color type */ + 32, /* prefered color depth */ + 0, 0, 0, 0, 0, 0, /* color bits (ignored) */ + 0, /* no alpha buffer */ + 0, /* alpha bits (ignored) */ + 0, /* no accumulation buffer */ + 0, 0, 0, 0, /* accum bits (ignored) */ + 32, /* depth buffer */ + 0, /* no stencil buffer */ + 0, /* no auxiliary buffers */ + PFD_MAIN_PLANE, /* main layer */ + 0, /* reserved */ + 0, 0, 0 /* no layer, visible, damage masks */ +}; + +GHOST_WindowWin32::GHOST_WindowWin32( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const bool stereoVisual) +: + GHOST_Window(title, left, top, width, height, state, GHOST_kDrawingContextTypeNone, + stereoVisual), + m_hDC(0), + m_hGlRc(0), + m_hasMouseCaptured(false), + m_nPressedButtons(0), + m_customCursor(0), + m_tabletData(NULL), + m_tablet(0), + m_wintab(NULL), + m_maxPressure(0) +{ + if (state != GHOST_kWindowStateFullScreen) { + /* Convert client size into window size */ + width += GetSystemMetrics(SM_CXSIZEFRAME)*2; + height += GetSystemMetrics(SM_CYSIZEFRAME)*2 + GetSystemMetrics(SM_CYCAPTION); + + m_hWnd = ::CreateWindow( + s_windowClassName, // pointer to registered class name + title, // pointer to window name + WS_OVERLAPPEDWINDOW, // window style + left, // horizontal position of window + top, // vertical position of window + width, // window width + height, // window height + 0, // handle to parent or owner window + 0, // handle to menu or child-window identifier + ::GetModuleHandle(0), // handle to application instance + 0); // pointer to window-creation data + } + else { + m_hWnd = ::CreateWindow( + s_windowClassName, // pointer to registered class name + title, // pointer to window name + WS_POPUP | WS_MAXIMIZE, // window style + left, // horizontal position of window + top, // vertical position of window + width, // window width + height, // window height + 0, // handle to parent or owner window + 0, // handle to menu or child-window identifier + ::GetModuleHandle(0), // handle to application instance + 0); // pointer to window-creation data + } + if (m_hWnd) { + // Store a pointer to this class in the window structure + LONG result = ::SetWindowLong(m_hWnd, GWL_USERDATA, (LONG)this); + + // Store the device context + m_hDC = ::GetDC(m_hWnd); + + // Show the window + int nCmdShow; + switch (state) { + case GHOST_kWindowStateMaximized: + nCmdShow = SW_SHOWMAXIMIZED; + break; + case GHOST_kWindowStateMinimized: + nCmdShow = SW_SHOWMINIMIZED; + break; + case GHOST_kWindowStateNormal: + default: + nCmdShow = SW_SHOWNORMAL; + break; + } + setDrawingContextType(type); + ::ShowWindow(m_hWnd, nCmdShow); + // Force an initial paint of the window + ::UpdateWindow(m_hWnd); + } + + m_wintab = ::LoadLibrary("Wintab32.dll"); + if (m_wintab) { + GHOST_WIN32_WTInfo fpWTInfo = ( GHOST_WIN32_WTInfo ) ::GetProcAddress( m_wintab, "WTInfoA" ); + GHOST_WIN32_WTOpen fpWTOpen = ( GHOST_WIN32_WTOpen ) ::GetProcAddress( m_wintab, "WTOpenA" ); + + // let's see if we can initialize tablet here + /* check if WinTab available. */ + if (fpWTInfo && fpWTInfo(0, 0, NULL)) { + // Now init the tablet + LOGCONTEXT lc; + AXIS TabletX, TabletY, Pressure, Orientation[3]; /* The maximum tablet size, pressure and orientation (tilt) */ + + // Open a Wintab context + + // Get default context information + fpWTInfo( WTI_DEFCONTEXT, 0, &lc ); + + // Open the context + lc.lcPktData = PACKETDATA; + lc.lcPktMode = PACKETMODE; + lc.lcOptions |= CXO_MESSAGES | CXO_SYSTEM; + + /* Set the entire tablet as active */ + fpWTInfo(WTI_DEVICES,DVC_X,&TabletX); + fpWTInfo(WTI_DEVICES,DVC_Y,&TabletY); + + /* get the max pressure, to divide into a float */ + BOOL pressureSupport = fpWTInfo (WTI_DEVICES, DVC_NPRESSURE, &Pressure); + if (pressureSupport) + m_maxPressure = Pressure.axMax; + else + m_maxPressure = 0; + + /* get the max tilt axes, to divide into floats */ + BOOL tiltSupport = fpWTInfo (WTI_DEVICES, DVC_ORIENTATION, &Orientation); + if (tiltSupport) { + /* does the tablet support azimuth ([0]) and altitude ([1]) */ + if (Orientation[0].axResolution && Orientation[1].axResolution) { + /* all this assumes the minimum is 0 */ + m_maxAzimuth = Orientation[0].axMax; + m_maxAltitude = Orientation[1].axMax; + } + else { /* no so dont do tilt stuff */ + m_maxAzimuth = m_maxAltitude = 0; + } + } + + if (fpWTOpen) { + m_tablet = fpWTOpen( m_hWnd, &lc, TRUE ); + if (m_tablet) { + m_tabletData = new GHOST_TabletData(); + m_tabletData->Active = 0; + } + } + } + } +} + + +GHOST_WindowWin32::~GHOST_WindowWin32() +{ + if (m_wintab) { + GHOST_WIN32_WTClose fpWTClose = ( GHOST_WIN32_WTClose ) ::GetProcAddress( m_wintab, "WTClose" ); + if (fpWTClose) { + if (m_tablet) + fpWTClose(m_tablet); + if (m_tabletData) + delete m_tabletData; + m_tabletData = NULL; + } + } + if (m_customCursor) { + DestroyCursor(m_customCursor); + m_customCursor = NULL; + } + + setDrawingContextType(GHOST_kDrawingContextTypeNone); + if (m_hDC) { + ::ReleaseDC(m_hWnd, m_hDC); + m_hDC = 0; + } + if (m_hWnd) { + ::DestroyWindow(m_hWnd); + m_hWnd = 0; + } +} + +bool GHOST_WindowWin32::getValid() const +{ + return m_hWnd != 0; +} + + +void GHOST_WindowWin32::setTitle(const STR_String& title) +{ + ::SetWindowText(m_hWnd, title); +} + + +void GHOST_WindowWin32::getTitle(STR_String& title) const +{ + char buf[s_maxTitleLength]; + ::GetWindowText(m_hWnd, buf, s_maxTitleLength); + STR_String temp (buf); + title = buf; +} + + +void GHOST_WindowWin32::getWindowBounds(GHOST_Rect& bounds) const +{ + RECT rect; + ::GetWindowRect(m_hWnd, &rect); + bounds.m_b = rect.bottom; + bounds.m_l = rect.left; + bounds.m_r = rect.right; + bounds.m_t = rect.top; +} + + +void GHOST_WindowWin32::getClientBounds(GHOST_Rect& bounds) const +{ + RECT rect; + ::GetClientRect(m_hWnd, &rect); + bounds.m_b = rect.bottom; + bounds.m_l = rect.left; + bounds.m_r = rect.right; + bounds.m_t = rect.top; +} + + +GHOST_TSuccess GHOST_WindowWin32::setClientWidth(GHOST_TUns32 width) +{ + GHOST_TSuccess success; + GHOST_Rect cBnds, wBnds; + getClientBounds(cBnds); + if (cBnds.getWidth() != width) { + getWindowBounds(wBnds); + int cx = wBnds.getWidth() + width - cBnds.getWidth(); + int cy = wBnds.getHeight(); + success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ? + GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowWin32::setClientHeight(GHOST_TUns32 height) +{ + GHOST_TSuccess success; + GHOST_Rect cBnds, wBnds; + getClientBounds(cBnds); + if (cBnds.getHeight() != height) { + getWindowBounds(wBnds); + int cx = wBnds.getWidth(); + int cy = wBnds.getHeight() + height - cBnds.getHeight(); + success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ? + GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowWin32::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) +{ + GHOST_TSuccess success; + GHOST_Rect cBnds, wBnds; + getClientBounds(cBnds); + if ((cBnds.getWidth() != width) || (cBnds.getHeight() != height)) { + getWindowBounds(wBnds); + int cx = wBnds.getWidth() + width - cBnds.getWidth(); + int cy = wBnds.getHeight() + height - cBnds.getHeight(); + success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ? + GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TWindowState GHOST_WindowWin32::getState() const +{ + GHOST_TWindowState state; + if (::IsIconic(m_hWnd)) { + state = GHOST_kWindowStateMinimized; + } + else if (::IsZoomed(m_hWnd)) { + state = GHOST_kWindowStateMaximized; + } + else { + state = GHOST_kWindowStateNormal; + } + return state; +} + + +void GHOST_WindowWin32::screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const +{ + POINT point = { inX, inY }; + ::ScreenToClient(m_hWnd, &point); + outX = point.x; + outY = point.y; +} + + +void GHOST_WindowWin32::clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const +{ + POINT point = { inX, inY }; + ::ClientToScreen(m_hWnd, &point); + outX = point.x; + outY = point.y; +} + + +GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state) +{ + WINDOWPLACEMENT wp; + wp.length = sizeof(WINDOWPLACEMENT); + ::GetWindowPlacement(m_hWnd, &wp); + switch (state) { + case GHOST_kWindowStateMinimized: + wp.showCmd = SW_SHOWMINIMIZED; + break; + case GHOST_kWindowStateMaximized: + ShowWindow(m_hWnd, SW_HIDE); //fe. HACK! + //Solves redraw problems when switching from fullscreen to normal. + + wp.showCmd = SW_SHOWMAXIMIZED; + SetWindowLong(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW); + break; + case GHOST_kWindowStateFullScreen: + wp.showCmd = SW_SHOWMAXIMIZED; + SetWindowLong(m_hWnd, GWL_STYLE, WS_POPUP | WS_MAXIMIZE); + break; + case GHOST_kWindowStateNormal: + default: + wp.showCmd = SW_SHOWNORMAL; + break; + } + return ::SetWindowPlacement(m_hWnd, &wp) == TRUE ? GHOST_kSuccess : GHOST_kFailure; +} + + +GHOST_TSuccess GHOST_WindowWin32::setOrder(GHOST_TWindowOrder order) +{ + HWND hWndInsertAfter = order == GHOST_kWindowOrderTop ? HWND_TOP : HWND_BOTTOM; + return ::SetWindowPos(m_hWnd, hWndInsertAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE) == TRUE ? GHOST_kSuccess : GHOST_kFailure; +} + + +GHOST_TSuccess GHOST_WindowWin32::swapBuffers() +{ + // adding a glFinish() here is to prevent Geforce in 'full scene antialias' mode + // from antialising the Blender window. Officially a swapbuffers does a glFinish + // itself, so this feels really like a hack... but it won't harm. (ton) + glFinish(); + return ::SwapBuffers(m_hDC) == TRUE ? GHOST_kSuccess : GHOST_kFailure; +} + + +GHOST_TSuccess GHOST_WindowWin32::activateDrawingContext() +{ + GHOST_TSuccess success; + if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { + if (m_hDC && m_hGlRc) { + success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kFailure; + } + } + else { + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowWin32::invalidate() +{ + GHOST_TSuccess success; + if (m_hWnd) { + success = ::InvalidateRect(m_hWnd, 0, FALSE) != 0 ? GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kFailure; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowWin32::installDrawingContext(GHOST_TDrawingContextType type) +{ + GHOST_TSuccess success; + switch (type) { + case GHOST_kDrawingContextTypeOpenGL: + { + if(m_stereoVisual) + sPreferredFormat.dwFlags |= PFD_STEREO; + + // Attempt to match device context pixel format to the preferred format + int iPixelFormat = EnumPixelFormats(m_hDC); + if (iPixelFormat == 0) { + success = GHOST_kFailure; + break; + } + if (::SetPixelFormat(m_hDC, iPixelFormat, &sPreferredFormat) == FALSE) { + success = GHOST_kFailure; + break; + } + // For debugging only: retrieve the pixel format chosen + PIXELFORMATDESCRIPTOR preferredFormat; + ::DescribePixelFormat(m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &preferredFormat); + // Create the context + m_hGlRc = ::wglCreateContext(m_hDC); + if (m_hGlRc) { + if (s_firsthGLRc) { + wglShareLists(s_firsthGLRc, m_hGlRc); + } else { + s_firsthGLRc = m_hGlRc; + } + + success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kFailure; + } + } + break; + + case GHOST_kDrawingContextTypeNone: + success = GHOST_kSuccess; + break; + + default: + success = GHOST_kFailure; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowWin32::removeDrawingContext() +{ + GHOST_TSuccess success; + switch (m_drawingContextType) { + case GHOST_kDrawingContextTypeOpenGL: + if (m_hGlRc) { + success = ::wglDeleteContext(m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure; + if (m_hGlRc == s_firsthGLRc) { + s_firsthGLRc = NULL; + } + m_hGlRc = 0; + } + else { + success = GHOST_kFailure; + } + break; + case GHOST_kDrawingContextTypeNone: + success = GHOST_kSuccess; + break; + default: + success = GHOST_kFailure; + } + return success; +} + +void GHOST_WindowWin32::lostMouseCapture() +{ + if (m_hasMouseCaptured) { + m_hasMouseCaptured = false; + m_nPressedButtons = 0; + } +} + +void GHOST_WindowWin32::registerMouseClickEvent(bool press) +{ + if (press) { + if (!m_hasMouseCaptured) { + ::SetCapture(m_hWnd); + m_hasMouseCaptured = true; + } + m_nPressedButtons++; + } else { + if (m_nPressedButtons) { + m_nPressedButtons--; + if (!m_nPressedButtons) { + ::ReleaseCapture(); + m_hasMouseCaptured = false; + } + } + } +} + + +void GHOST_WindowWin32::loadCursor(bool visible, GHOST_TStandardCursor cursor) const +{ + if (!visible) { + while (::ShowCursor(FALSE) >= 0); + } + else { + while (::ShowCursor(TRUE) < 0); + } + + if (cursor == GHOST_kStandardCursorCustom && m_customCursor) { + ::SetCursor( m_customCursor ); + } else { + // Convert GHOST cursor to Windows OEM cursor + bool success = true; + LPCSTR id; + switch (cursor) { + case GHOST_kStandardCursorDefault: id = IDC_ARROW; break; + case GHOST_kStandardCursorRightArrow: id = IDC_ARROW; break; + case GHOST_kStandardCursorLeftArrow: id = IDC_ARROW; break; + case GHOST_kStandardCursorInfo: id = IDC_SIZEALL; break; // Four-pointed arrow pointing north, south, east, and west + case GHOST_kStandardCursorDestroy: id = IDC_NO; break; // Slashed circle + case GHOST_kStandardCursorHelp: id = IDC_HELP; break; // Arrow and question mark + case GHOST_kStandardCursorCycle: id = IDC_NO; break; // Slashed circle + case GHOST_kStandardCursorSpray: id = IDC_SIZEALL; break; // Four-pointed arrow pointing north, south, east, and west + case GHOST_kStandardCursorWait: id = IDC_WAIT; break; // Hourglass + case GHOST_kStandardCursorText: id = IDC_IBEAM; break; // I-beam + case GHOST_kStandardCursorCrosshair: id = IDC_CROSS; break; // Crosshair + case GHOST_kStandardCursorUpDown: id = IDC_SIZENS; break; // Double-pointed arrow pointing north and south + case GHOST_kStandardCursorLeftRight: id = IDC_SIZEWE; break; // Double-pointed arrow pointing west and east + case GHOST_kStandardCursorTopSide: id = IDC_UPARROW; break; // Vertical arrow + case GHOST_kStandardCursorBottomSide: id = IDC_SIZENS; break; + case GHOST_kStandardCursorLeftSide: id = IDC_SIZEWE; break; + case GHOST_kStandardCursorTopLeftCorner: id = IDC_SIZENWSE; break; + case GHOST_kStandardCursorTopRightCorner: id = IDC_SIZENESW; break; + case GHOST_kStandardCursorBottomRightCorner: id = IDC_SIZENWSE; break; + case GHOST_kStandardCursorBottomLeftCorner: id = IDC_SIZENESW; break; + case GHOST_kStandardCursorPencil: id = IDC_ARROW; break; + default: + success = false; + } + + if (success) { + HCURSOR hCursor = ::SetCursor(::LoadCursor(0, id)); + } + } +} + +GHOST_TSuccess GHOST_WindowWin32::setWindowCursorVisibility(bool visible) +{ + if (::GetForegroundWindow() == m_hWnd) { + loadCursor(visible, getCursorShape()); + } + + return GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cursorShape) +{ + if (m_customCursor) { + DestroyCursor(m_customCursor); + m_customCursor = NULL; + } + + if (::GetForegroundWindow() == m_hWnd) { + loadCursor(getCursorVisibility(), cursorShape); + } + + return GHOST_kSuccess; +} +void GHOST_WindowWin32::processWin32TabletInitEvent() +{ + if (m_wintab) { + GHOST_WIN32_WTInfo fpWTInfo = ( GHOST_WIN32_WTInfo ) ::GetProcAddress( m_wintab, "WTInfoA" ); + + // let's see if we can initialize tablet here + /* check if WinTab available. */ + if (fpWTInfo) { + AXIS Pressure, Orientation[3]; /* The maximum tablet size */ + + BOOL pressureSupport = fpWTInfo (WTI_DEVICES, DVC_NPRESSURE, &Pressure); + if (pressureSupport) + m_maxPressure = Pressure.axMax; + else + m_maxPressure = 0; + + BOOL tiltSupport = fpWTInfo (WTI_DEVICES, DVC_ORIENTATION, &Orientation); + if (tiltSupport) { + /* does the tablet support azimuth ([0]) and altitude ([1]) */ + if (Orientation[0].axResolution && Orientation[1].axResolution) { + m_maxAzimuth = Orientation[0].axMax; + m_maxAltitude = Orientation[1].axMax; + } + else { /* no so dont do tilt stuff */ + m_maxAzimuth = m_maxAltitude = 0; + } + } + + m_tabletData->Active = 0; + } + } +} + +void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam) +{ + PACKET pkt; + if (m_wintab) { + GHOST_WIN32_WTPacket fpWTPacket = ( GHOST_WIN32_WTPacket ) ::GetProcAddress( m_wintab, "WTPacket" ); + if (fpWTPacket) { + if (fpWTPacket((HCTX)lParam, wParam, &pkt)) { + if (m_tabletData) { + switch (pkt.pkCursor) { + case 0: /* first device */ + case 3: /* second device */ + m_tabletData->Active = 0; /* puck - not yet supported */ + break; + case 1: + case 4: + m_tabletData->Active = 1; /* stylus */ + break; + case 2: + case 5: + m_tabletData->Active = 2; /* eraser */ + break; + } + if (m_maxPressure > 0) { + m_tabletData->Pressure = (float)pkt.pkNormalPressure / (float)m_maxPressure; + } else { + m_tabletData->Pressure = 1.0f; + } + + if ((m_maxAzimuth > 0) && (m_maxAltitude > 0)) { + ORIENTATION ort = pkt.pkOrientation; + float vecLen; + float altRad, azmRad; /* in radians */ + + /* + from the wintab spec: + orAzimuth Specifies the clockwise rotation of the + cursor about the z axis through a full circular range. + + orAltitude Specifies the angle with the x-y plane + through a signed, semicircular range. Positive values + specify an angle upward toward the positive z axis; + negative values specify an angle downward toward the negative z axis. + + wintab.h defines .orAltitude as a UINT but documents .orAltitude + as positive for upward angles and negative for downward angles. + WACOM uses negative altitude values to show that the pen is inverted; + therefore we cast .orAltitude as an (int) and then use the absolute value. + */ + + /* convert raw fixed point data to radians */ + altRad = (fabs((float)ort.orAltitude)/(float)m_maxAltitude) * M_PI/2.0; + azmRad = ((float)ort.orAzimuth/(float)m_maxAzimuth) * M_PI*2.0; + + /* find length of the stylus' projected vector on the XY plane */ + vecLen = cos(altRad); + + /* from there calculate X and Y components based on azimuth */ + m_tabletData->Xtilt = sin(azmRad) * vecLen; + m_tabletData->Ytilt = sin(M_PI/2.0 - azmRad) * vecLen; + + } else { + m_tabletData->Xtilt = 0.0f; + m_tabletData->Ytilt = 0.0f; + } + } + } + } + } +} + +/** Reverse the bits in a GHOST_TUns8 */ +static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch) +{ + ch= ((ch>>1)&0x55) | ((ch<<1)&0xAA); + ch= ((ch>>2)&0x33) | ((ch<<2)&0xCC); + ch= ((ch>>4)&0x0F) | ((ch<<4)&0xF0); + return ch; +} + +/** Reverse the bits in a GHOST_TUns16 */ +static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt) +{ + shrt= ((shrt>>1)&0x5555) | ((shrt<<1)&0xAAAA); + shrt= ((shrt>>2)&0x3333) | ((shrt<<2)&0xCCCC); + shrt= ((shrt>>4)&0x0F0F) | ((shrt<<4)&0xF0F0); + shrt= ((shrt>>8)&0x00FF) | ((shrt<<8)&0xFF00); + return shrt; +} +GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], + GHOST_TUns8 mask[16][2], int hotX, int hotY) +{ + return setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*)mask, + 16, 16, hotX, hotY, 0, 1); +} + +GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, int sizeX, int sizeY, int hotX, int hotY, + int fg_color, int bg_color) +{ + GHOST_TUns32 andData[32]; + GHOST_TUns32 xorData[32]; + GHOST_TUns32 fullBitRow, fullMaskRow; + int x, y, cols; + + cols=sizeX/8; /* Num of whole bytes per row (width of bm/mask) */ + if (sizeX%8) cols++; + + if (m_customCursor) { + DestroyCursor(m_customCursor); + m_customCursor = NULL; + } + + memset(&andData, 0xFF, sizeof(andData)); + memset(&xorData, 0, sizeof(xorData)); + + for (y=0; y=0; x--){ + fullBitRow<<=8; + fullMaskRow<<=8; + fullBitRow |= uns8ReverseBits(bitmap[cols*y + x]); + fullMaskRow |= uns8ReverseBits( mask[cols*y + x]); + } + xorData[y]= fullBitRow & fullMaskRow; + andData[y]= ~fullMaskRow; + } + + m_customCursor = ::CreateCursor(::GetModuleHandle(0), hotX, hotY, 32, 32, andData, xorData); + if (!m_customCursor) { + return GHOST_kFailure; + } + + if (::GetForegroundWindow() == m_hWnd) { + loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom); + } + + return GHOST_kSuccess; +} + + +/* Ron Fosner's code for weighting pixel formats and forcing software. + See http://www.opengl.org/resources/faq/technical/weight.cpp */ + +static int WeightPixelFormat(PIXELFORMATDESCRIPTOR& pfd) { + int weight = 0; + + /* assume desktop color depth is 32 bits per pixel */ + + /* cull unusable pixel formats */ + /* if no formats can be found, can we determine why it was rejected? */ + if( !(pfd.dwFlags & PFD_SUPPORT_OPENGL) || + !(pfd.dwFlags & PFD_DRAW_TO_WINDOW) || + !(pfd.dwFlags & PFD_DOUBLEBUFFER) || /* Blender _needs_ this */ + ( pfd.cDepthBits <= 8 ) || + !(pfd.iPixelType == PFD_TYPE_RGBA) ) + return 0; + + weight = 1; /* it's usable */ + + /* the bigger the depth buffer the better */ + /* give no weight to a 16-bit depth buffer, because those are crap */ + weight += pfd.cDepthBits - 16; + + weight += pfd.cColorBits - 8; + + /* want swap copy capability -- it matters a lot */ + if(pfd.dwFlags & PFD_SWAP_COPY) weight += 16; + + /* but if it's a generic (not accelerated) view, it's really bad */ + if(pfd.dwFlags & PFD_GENERIC_FORMAT) weight /= 10; + + return weight; +} + +/* A modification of Ron Fosner's replacement for ChoosePixelFormat */ +/* returns 0 on error, else returns the pixel format number to be used */ +static int EnumPixelFormats(HDC hdc) { + int iPixelFormat; + int i, n, w, weight = 0; + PIXELFORMATDESCRIPTOR pfd, pfd_fallback; + + /* we need a device context to do anything */ + if(!hdc) return 0; + + iPixelFormat = 1; /* careful! PFD numbers are 1 based, not zero based */ + + /* obtain detailed information about + the device context's first pixel format */ + n = 1+::DescribePixelFormat(hdc, iPixelFormat, + sizeof(PIXELFORMATDESCRIPTOR), &pfd); + + /* choose a pixel format using the useless Windows function in case + we come up empty handed */ + iPixelFormat = ::ChoosePixelFormat( hdc, &sPreferredFormat ); + + if(!iPixelFormat) return 0; /* couldn't find one to use */ + + for(i=1; i<=n; i++) { /* not the idiom, but it's right */ + ::DescribePixelFormat( hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd ); + w = WeightPixelFormat(pfd); + if(w > weight) { + weight = w; + iPixelFormat = i; + } + } + + return iPixelFormat; +} + + diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h new file mode 100644 index 00000000000..08209c0ec29 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -0,0 +1,311 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_WindowWin32.h + * Declaration of GHOST_WindowWin32 class. + */ + +#ifndef _GHOST_WINDOW_WIN32_H_ +#define _GHOST_WINDOW_WIN32_H_ + +#ifndef WIN32 +#error WIN32 only! +#endif // WIN32 + +#include "GHOST_Window.h" + +#include + + +#include +#define PACKETDATA (PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_CURSOR) +#define PACKETMODE PK_BUTTONS +#include + +// typedefs for WinTab functions to allow dynamic loading +typedef UINT (API * GHOST_WIN32_WTInfo) ( UINT, UINT, LPVOID ); +typedef HCTX (API * GHOST_WIN32_WTOpen) (HWND, LPLOGCONTEXTA, BOOL); +typedef BOOL (API * GHOST_WIN32_WTClose) (HCTX); +typedef BOOL (API * GHOST_WIN32_WTPacket) (HCTX, UINT, LPVOID); + +/** + * GHOST window on M$ Windows OSs. + * @author Maarten Gribnau + * @date May 10, 2001 + */ +class GHOST_WindowWin32 : public GHOST_Window { +public: + /** + * Constructor. + * Creates a new window and opens it. + * To check if the window was created properly, use the getValid() method. + * @param title The text shown in the title bar of the window. + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state the window is initially opened with. + * @param type The type of drawing context installed in this window. + * @param stereoVisual Stereo visual for quad buffered stereo. + */ + GHOST_WindowWin32( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone, + const bool stereoVisual = false + ); + + /** + * Destructor. + * Closes the window and disposes resources allocated. + */ + virtual ~GHOST_WindowWin32(); + + /** + * Returns indication as to whether the window is valid. + * @return The validity of the window. + */ + virtual bool getValid() const; + + /** + * Sets the title displayed in the title bar. + * @param title The title to display in the title bar. + */ + virtual void setTitle(const STR_String& title); + + /** + * Returns the title displayed in the title bar. + * @param title The title displayed in the title bar. + */ + virtual void getTitle(STR_String& title) const; + + /** + * Returns the window rectangle dimensions. + * The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen. + * @param bounds The bounding rectangle of the window. + */ + virtual void getWindowBounds(GHOST_Rect& bounds) const; + + /** + * Returns the client rectangle dimensions. + * The left and top members of the rectangle are always zero. + * @param bounds The bounding rectangle of the cleient area of the window. + */ + virtual void getClientBounds(GHOST_Rect& bounds) const; + + /** + * Resizes client rectangle width. + * @param width The new width of the client area of the window. + */ + virtual GHOST_TSuccess setClientWidth(GHOST_TUns32 width); + + /** + * Resizes client rectangle height. + * @param height The new height of the client area of the window. + */ + virtual GHOST_TSuccess setClientHeight(GHOST_TUns32 height); + + /** + * Resizes client rectangle. + * @param width The new width of the client area of the window. + * @param height The new height of the client area of the window. + */ + virtual GHOST_TSuccess setClientSize(GHOST_TUns32 width, GHOST_TUns32 height); + + /** + * Returns the state of the window (normal, minimized, maximized). + * @return The state of the window. + */ + virtual GHOST_TWindowState getState() const; + + /** + * Converts a point in screen coordinates to client rectangle coordinates + * @param inX The x-coordinate on the screen. + * @param inY The y-coordinate on the screen. + * @param outX The x-coordinate in the client rectangle. + * @param outY The y-coordinate in the client rectangle. + */ + virtual void screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const; + + /** + * Converts a point in screen coordinates to client rectangle coordinates + * @param inX The x-coordinate in the client rectangle. + * @param inY The y-coordinate in the client rectangle. + * @param outX The x-coordinate on the screen. + * @param outY The y-coordinate on the screen. + */ + virtual void clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const; + + /** + * Sets the state of the window (normal, minimized, maximized). + * @param state The state of the window. + * @return Indication of success. + */ + virtual GHOST_TSuccess setState(GHOST_TWindowState state); + + /** + * Sets the order of the window (bottom, top). + * @param order The order of the window. + * @return Indication of success. + */ + virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order); + + /** + * Swaps front and back buffers of a window. + * @return Indication of success. + */ + virtual GHOST_TSuccess swapBuffers(); + + /** + * Activates the drawing context of this window. + * @return Indication of success. + */ + virtual GHOST_TSuccess activateDrawingContext(); + + /** + * Invalidates the contents of this window. + */ + virtual GHOST_TSuccess invalidate(); + + /** + * Returns the name of the window class. + * @return The name of the window class. + */ + static LPCSTR getWindowClassName() { return s_windowClassName; } + + /** + * Register a mouse click event (should be called + * for any real button press, controls mouse + * capturing). + * + * @param press True the event was a button press. + */ + void registerMouseClickEvent(bool press); + + /** + * Inform the window that it has lost mouse capture, + * called in response to native window system messages. + */ + void lostMouseCapture(); + + /** + * Loads the windows equivalent of a standard GHOST cursor. + * @param visible Flag for cursor visibility. + * @param cursorShape The cursor shape. + */ + void loadCursor(bool visible, GHOST_TStandardCursor cursorShape) const; + + const GHOST_TabletData* GetTabletData() + { return m_tabletData; } + + void processWin32TabletInitEvent(); + void processWin32TabletEvent(WPARAM wParam, LPARAM lParam); + +protected: + /** + * Tries to install a rendering context in this window. + * @param type The type of rendering context installed. + * @return Indication of success. + */ + virtual GHOST_TSuccess installDrawingContext(GHOST_TDrawingContextType type); + + /** + * Removes the current drawing context. + * @return Indication of success. + */ + virtual GHOST_TSuccess removeDrawingContext(); + + /** + * Sets the cursor visibility on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCursorVisibility(bool visible); + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape); + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], GHOST_TUns8 mask[16][2], int hotX, int hotY); + + virtual GHOST_TSuccess setWindowCustomCursorShape( + GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, + int sizey, + int hotX, + int hotY, + int fg_color, + int bg_color + ); + + /** Window handle. */ + HWND m_hWnd; + /** Device context handle. */ + HDC m_hDC; + /** OpenGL rendering context. */ + HGLRC m_hGlRc; + /** The first created OpenGL context (for sharing display lists) */ + static HGLRC s_firsthGLRc; + /** Flag for if window has captured the mouse */ + bool m_hasMouseCaptured; + /** Count of number of pressed buttons */ + int m_nPressedButtons; + /** HCURSOR structure of the custom cursor */ + HCURSOR m_customCursor; + + static LPCSTR s_windowClassName; + static const int s_maxTitleLength; + + /** WinTab dll handle */ + HMODULE m_wintab; + + /** Tablet data for GHOST */ + GHOST_TabletData* m_tabletData; + + /** Stores the Tablet context if detected Tablet features using WinTab.dll */ + HCTX m_tablet; + LONG m_maxPressure; + LONG m_maxAzimuth, m_maxAltitude; + +}; + +#endif // _GHOST_WINDOW_WIN32_H_ + diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp new file mode 100644 index 00000000000..30fa30e59e6 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -0,0 +1,1032 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "GHOST_WindowX11.h" +#include "GHOST_SystemX11.h" +#include "STR_String.h" +#include "GHOST_Debug.h" + +// For standard X11 cursors +#include +#include + +#if defined(__sun__) || defined( __sun ) || defined (__sparc) || defined (__sparc__) +#include +#endif + + +// For obscure full screen mode stuuf +// lifted verbatim from blut. + +typedef struct { + long flags; + long functions; + long decorations; + long input_mode; +} MotifWmHints; + +#define MWM_HINTS_DECORATIONS (1L << 1) + +/* +import bpy +I = bpy.data.images['blender.png'] # the 48x48 icon + +# Write to a file that can be +# used within static unsigned char BLENDER_ICON_48x48x24[] = {...} +f = open('/myicon.txt', 'w') +for j in xrange(48): + for k in xrange(48): + v = I.getPixelI(j,47-k) + v.pop() + for p in v: + f.write(str(hex(p))+',') + + f.write('\n') +*/ + +// See the python script above to regenerate the 48x48 icon within blender +#define BLENDER_ICON_WIDTH 48 +#define BLENDER_ICON_HEIGHT 48 +static unsigned char BLENDER_ICON_48x48x24[] = { +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x4f,0x2a,0xd,0xa7,0x5b,0x1f,0xb8,0x66,0x22,0x6c,0x3b,0x14,0x5,0x3,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x6f,0x3a,0x13,0xea,0x7f,0x2c,0xee,0x7e,0x2b,0xee,0x7e,0x2b,0xef,0x85,0x2e,0x5f,0x35,0x12,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x43,0x22,0xb,0xed,0x7f,0x2c,0xed,0x7c,0x2b,0xee,0x7f,0x2c,0xee,0x80,0x2c,0xee,0x80,0x2c,0xa8,0x5f,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x2e,0x16,0x6,0xd0,0x6f,0x26,0xed,0x7b,0x2a,0xed,0x7d,0x2b,0xee,0x7f,0x2c,0xee,0x80,0x2c,0xee,0x82,0x2d,0x9a,0x57,0x1d,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x17,0xb,0x4,0xb9,0x60,0x21,0xed,0x7a,0x2a,0xed,0x7b,0x2a,0xed,0x7e,0x2b,0xee,0x7f,0x2c,0xee,0x7f,0x2c,0xee,0x86,0x2e,0x4e,0x2b,0xe,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x1,0x0,0x0,0x96,0x4d,0x19,0xee,0x7a,0x2a,0xed,0x79,0x2a,0xed,0x7c,0x2b,0xed,0x7e,0x2b,0xed,0x7e,0x2b,0xef,0x83,0x2d,0x98,0x55,0x1c,0x3,0x1,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x20,0xf,0x5,0x4b,0x27,0xe,0x21,0x11,0x5,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x67,0x34,0x11,0xed,0x7b,0x2a,0xec,0x79,0x29,0xed,0x7b,0x2a,0xed,0x7c,0x2b,0xed,0x7d,0x2b,0xee,0x7f,0x2c,0xbb,0x69,0x24,0x11,0x9,0x3,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x38,0x1c,0x9,0xc9,0x6d,0x2c,0xf1,0x86,0x36,0xd7,0x79,0x2a,0x22,0x12,0x5,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x3b,0x1d,0x9,0xe0,0x74,0x27,0xed,0x7a,0x2a,0xed,0x7c,0x2a,0xed,0x7d,0x2b,0xed,0x7d,0x2b,0xed,0x7d,0x2b,0xdc,0x7a,0x2a,0x1e,0xf,0x5,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xa6,0x56,0x23,0xee,0x83,0x3b,0xed,0x7d,0x2c,0xf0,0x85,0x2e,0x75,0x43,0x17,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x25,0x12,0x5,0xc9,0x68,0x24,0xed,0x7b,0x2a,0xed,0x7d,0x2b,0xed,0x7e,0x2b,0xee,0x7e,0x2c,0xed,0x7d,0x2b,0xe3,0x7d,0x2b,0x3b,0x1f,0xa,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x1c,0xd,0x4,0xd9,0x74,0x35,0xee,0x83,0x3a,0xee,0x7f,0x2b,0xf0,0x86,0x2e,0x83,0x4d,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xa,0x5,0x1,0xa1,0x54,0x1c,0xee,0x7e,0x2c,0xed,0x7e,0x2c,0xed,0x7f,0x2c,0xed,0x80,0x2c,0xed,0x7f,0x2b,0xec,0x81,0x2d,0x60,0x33,0x11,0x1,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x24,0x11,0x5,0xe0,0x7a,0x38,0xee,0x84,0x3a,0xee,0x82,0x2c,0xf0,0x88,0x2f,0x82,0x4d,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x6f,0x39,0x13,0xef,0x82,0x30,0xed,0x82,0x2f,0xee,0x82,0x2e,0xee,0x82,0x2d,0xee,0x81,0x2c,0xf0,0x83,0x2d,0x88,0x49,0x18,0x3,0x2,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x24,0x11,0x5,0xe0,0x7c,0x3a,0xee,0x86,0x3b,0xee,0x84,0x2d,0xf1,0x8b,0x30,0x82,0x4d,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0x54,0x2b,0xf,0xe9,0x80,0x30,0xee,0x87,0x33,0xef,0x88,0x32,0xef,0x88,0x30,0xee,0x85,0x2f,0xef,0x83,0x2e,0xae,0x5f,0x20,0x4,0x2,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x24,0x11,0x5,0xe0,0x7e,0x3d,0xef,0x8a,0x3d,0xef,0x88,0x2e,0xf1,0x8d,0x31,0x81,0x4d,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0x29,0x15,0x7,0xd2,0x74,0x2d,0xf0,0x8b,0x36,0xf0,0x8d,0x35,0xef,0x8d,0x35,0xef,0x8b,0x33,0xef,0x88,0x30,0xc4,0x6d,0x26,0x18,0xc,0x4,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x24,0x11,0x5,0xe1,0x80,0x3f,0xf0,0x8d,0x3f,0xef,0x8a,0x2f,0xf1,0x8f,0x32,0x81,0x4e,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0x9,0x3,0x0,0xb1,0x61,0x26,0xf1,0x8e,0x3a,0xf1,0x90,0x3a,0xf0,0x90,0x38,0xf0,0x90,0x36,0xef,0x8e,0x35,0xd3,0x7a,0x2c,0x22,0x11,0x6,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x24,0x12,0x5,0xe1,0x83,0x42,0xf0,0x90,0x42,0xf0,0x8d,0x30,0xf2,0x92,0x33,0x80,0x4e,0x1b,0x0,0x0,0x0,0x3,0x2,0x0,0x81,0x45,0x1b,0xf1,0x90,0x3e,0xf1,0x94,0x3d,0xf1,0x95,0x3c,0xf0,0x94,0x3b,0xf0,0x92,0x39,0xf0,0x90,0x35,0xd0,0x7b,0x2b,0xc2,0x6e,0x26,0xbe,0x6c,0x25,0x94,0x54,0x1c,0x5b,0x33,0x11,0x1a,0xe,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x25,0x14,0x6,0xe2,0x86,0x44,0xf1,0x94,0x45,0xf0,0x90,0x31,0xf2,0x94,0x33,0x80,0x4e,0x1b,0x0,0x0,0x0,0x60,0x34,0x14,0xed,0x8c,0x3e,0xf0,0x96,0x42,0xf1,0x97,0x40,0xf1,0x95,0x3f,0xf0,0x91,0x39,0xef,0x8e,0x33,0xef,0x8d,0x31,0xf0,0x8d,0x31,0xef,0x8c,0x30,0xef,0x8c,0x30,0xf0,0x8d,0x31,0xf1,0x8e,0x31,0xe1,0x85,0x2e,0x92,0x55,0x1d,0x25,0x14,0x7,0x1,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x26,0x14,0x6,0xe2,0x89,0x46,0xf2,0x97,0x47,0xf1,0x92,0x32,0xf2,0x96,0x34,0x80,0x4e,0x1a,0x32,0x1a,0xa,0xe3,0x87,0x3d,0xf1,0x97,0x45,0xf1,0x98,0x44,0xf1,0x95,0x41,0xf0,0x90,0x39,0xef,0x8d,0x30,0xef,0x8f,0x31,0xf0,0x90,0x32,0xf0,0x92,0x33,0xf1,0x93,0x33,0xf1,0x94,0x34,0xf1,0x94,0x34,0xf0,0x93,0x34,0xf0,0x91,0x32,0xf1,0x91,0x33,0xe2,0x8a,0x30,0x6b,0x3f,0x15,0x1,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x26,0x14,0x6,0xe3,0x8b,0x49,0xf2,0x9a,0x49,0xf1,0x93,0x32,0xf2,0x98,0x35,0x8f,0x57,0x1d,0xcf,0x7c,0x38,0xf2,0x99,0x48,0xf1,0x98,0x47,0xf1,0x96,0x44,0xf0,0x90,0x39,0xef,0x8d,0x31,0xf0,0x90,0x31,0xf0,0x92,0x33,0xf1,0x94,0x33,0xf1,0x96,0x35,0xf1,0x98,0x35,0xf1,0x9a,0x36,0xf1,0x9c,0x37,0xf2,0x9d,0x37,0xf2,0x9c,0x37,0xf2,0x99,0x36,0xf0,0x94,0x34,0xf3,0x97,0x35,0x9f,0x60,0x21,0x13,0xb,0x3,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x26,0x14,0x6,0xe3,0x8d,0x4b,0xf2,0x9b,0x4c,0xf1,0x93,0x32,0xf1,0x97,0x35,0xea,0x98,0x43,0xf2,0x9d,0x4d,0xf1,0x9a,0x4b,0xf1,0x99,0x49,0xf0,0x93,0x3d,0xf0,0x8d,0x30,0xf0,0x90,0x32,0xf0,0x92,0x32,0xf0,0x94,0x34,0xf1,0x96,0x34,0xf1,0x98,0x36,0xf1,0x9a,0x36,0xf2,0x9c,0x38,0xf2,0x9f,0x38,0xf2,0xa2,0x39,0xf3,0xa2,0x39,0xf3,0xa2,0x39,0xf2,0x9f,0x38,0xf1,0x99,0x35,0xf2,0x97,0x35,0xba,0x74,0x29,0x13,0xb,0x4,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x26,0x14,0x6,0xe4,0x8e,0x4d,0xf2,0x9d,0x4e,0xf1,0x93,0x32,0xf2,0x9d,0x3f,0xf3,0xa4,0x54,0xf2,0x9d,0x50,0xf1,0x9b,0x4d,0xf2,0x98,0x46,0xef,0x8d,0x31,0xf0,0x8f,0x31,0xf0,0x91,0x32,0xf0,0x93,0x32,0xf1,0x94,0x32,0xf1,0x95,0x32,0xf1,0x98,0x34,0xf1,0x9b,0x36,0xf2,0x9e,0x38,0xf2,0xa1,0x39,0xf2,0xa4,0x3a,0xf3,0xa6,0x3b,0xf4,0xa8,0x3c,0xf3,0xa7,0x3c,0xf3,0xa4,0x3a,0xf2,0x9c,0x37,0xf2,0x99,0x36,0xa9,0x69,0x25,0x2,0x1,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x26,0x14,0x6,0xe4,0x90,0x50,0xf2,0x9e,0x51,0xf1,0x95,0x35,0xf4,0xa6,0x54,0xf3,0xa2,0x55,0xf2,0x9e,0x51,0xf2,0x9c,0x4e,0xf0,0x8f,0x35,0xf0,0x8e,0x31,0xf0,0x90,0x32,0xf3,0xa5,0x56,0xf7,0xc4,0x8e,0xfa,0xd8,0xb6,0xfb,0xdf,0xc2,0xfa,0xd8,0xb2,0xf7,0xc4,0x89,0xf4,0xae,0x59,0xf2,0xa1,0x38,0xf3,0xa5,0x3b,0xf4,0xa8,0x3c,0xf4,0xab,0x3d,0xf4,0xac,0x3e,0xf4,0xab,0x3d,0xf3,0xa7,0x3b,0xf2,0x9e,0x38,0xf4,0x9e,0x38,0x6f,0x45,0x17,0x1,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x19,0xc,0x5,0x63,0x36,0x18,0x3f,0x20,0x9,0x2,0x1,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x26,0x14,0x6,0xe4,0x91,0x52,0xf3,0xa2,0x55,0xf2,0x9d,0x43,0xf4,0xa7,0x5b,0xf3,0xa2,0x57,0xf3,0xa0,0x55,0xf1,0x97,0x43,0xf0,0x8d,0x30,0xf2,0x9d,0x4c,0xfa,0xda,0xbc,0xfe,0xfb,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfb,0xf6,0xfa,0xdc,0xb5,0xf4,0xae,0x4e,0xf4,0xa9,0x3c,0xf4,0xac,0x3d,0xf4,0xae,0x3f,0xf4,0xaf,0x3f,0xf4,0xad,0x3f,0xf3,0xa8,0x3d,0xf2,0x9d,0x38,0xe2,0x94,0x34,0x23,0x14,0x6,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x11,0x8,0x3,0x9e,0x62,0x39,0xf2,0x91,0x4e,0xe7,0x79,0x29,0x48,0x25,0xc,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0x27,0x13,0x6,0xe5,0x93,0x54,0xf3,0xa7,0x59,0xf4,0xa6,0x56,0xf4,0xa7,0x5d,0xf3,0xa4,0x59,0xf3,0xa2,0x57,0xf1,0x90,0x36,0xf4,0xa7,0x5d,0xfe,0xf4,0xeb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xf2,0xe3,0xf6,0xb8,0x5f,0xf4,0xac,0x3e,0xf4,0xaf,0x3f,0xf4,0xb1,0x40,0xf4,0xb2,0x40,0xf5,0xaf,0x3f,0xf3,0xa6,0x3c,0xf3,0x9f,0x38,0x90,0x5d,0x21,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x3d,0x1f,0xf,0xed,0x9c,0x6a,0xef,0x8b,0x4a,0xec,0x78,0x29,0xe4,0x79,0x2a,0x29,0x15,0x7,0x0,0x0,0x0,0xff,0x0,0xff,0x28,0x14,0x6,0xe6,0x97,0x57,0xf5,0xad,0x63,0xf5,0xac,0x62,0xf4,0xa8,0x5f,0xf4,0xa6,0x5c,0xf3,0xa0,0x53,0xf4,0xa9,0x64,0xfe,0xf8,0xf4,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xff,0xf2,0xf7,0xfa,0xed,0xf4,0xf8,0xfd,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xf7,0xed,0xf5,0xb5,0x53,0xf5,0xb0,0x3f,0xf5,0xb3,0x41,0xf5,0xb4,0x42,0xf5,0xb3,0x41,0xf4,0xad,0x3f,0xf3,0xa1,0x39,0xe4,0x98,0x37,0x1d,0x11,0x5,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x43,0x23,0x10,0xf2,0xa1,0x70,0xf1,0x99,0x61,0xec,0x78,0x2a,0xed,0x7b,0x2a,0xc4,0x69,0x23,0x15,0xa,0x3,0x0,0x0,0x0,0x1d,0xf,0x5,0xe7,0x9b,0x5b,0xf5,0xb1,0x68,0xf5,0xad,0x65,0xf4,0xaa,0x62,0xf4,0xa8,0x5f,0xf3,0xa4,0x59,0xfd,0xec,0xde,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xfd,0xfe,0xc3,0xda,0xe9,0x5c,0x9a,0xc5,0x2a,0x7b,0xb4,0x17,0x6f,0xae,0x36,0x81,0xb8,0x91,0xbb,0xd9,0xf0,0xf6,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xe7,0xc7,0xf5,0xb2,0x43,0xf6,0xb3,0x41,0xf5,0xb5,0x43,0xf5,0xb6,0x43,0xf5,0xb3,0x42,0xf4,0xa8,0x3c,0xf4,0xa2,0x3a,0x66,0x41,0x17,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x22,0x10,0x7,0xd6,0x88,0x5b,0xf2,0xa5,0x76,0xee,0x84,0x3f,0xed,0x7a,0x2a,0xee,0x80,0x2c,0xa5,0x59,0x1e,0x7,0x3,0x1,0x19,0xd,0x4,0xe7,0x9e,0x5e,0xf6,0xb2,0x6b,0xf5,0xae,0x67,0xf5,0xac,0x65,0xf4,0xa9,0x61,0xf8,0xcc,0xa1,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0xfe,0xfe,0x97,0xbf,0xdb,0x33,0x83,0xbb,0x24,0x7e,0xb9,0x3,0x6a,0xae,0x0,0x66,0xab,0x0,0x64,0xa9,0x1,0x63,0xa9,0x3c,0x87,0xbd,0xee,0xf5,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xf8,0xc7,0x76,0xf6,0xb4,0x41,0xf5,0xb7,0x43,0xf6,0xb8,0x44,0xf6,0xb6,0x43,0xf5,0xae,0x3f,0xf3,0xa2,0x3a,0xac,0x71,0x29,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x52,0x2c,0x16,0xf0,0xa1,0x71,0xf2,0xa2,0x6f,0xed,0x7e,0x32,0xed,0x7e,0x2b,0xef,0x82,0x2d,0x8a,0x49,0x18,0x1b,0xe,0x4,0xe7,0xa2,0x61,0xf6,0xb3,0x6e,0xf6,0xb0,0x6a,0xf5,0xae,0x67,0xf5,0xab,0x64,0xfe,0xf4,0xeb,0xff,0xff,0xff,0xff,0xff,0xff,0xb4,0xd1,0xe5,0x3e,0x8d,0xc3,0x37,0x8e,0xc5,0x16,0x7a,0xb9,0x0,0x6b,0xaf,0x0,0x68,0xac,0x0,0x65,0xaa,0x0,0x65,0xab,0x0,0x66,0xac,0x4d,0x93,0xc4,0xf8,0xfb,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xe7,0xc5,0xf6,0xb3,0x40,0xf6,0xb7,0x43,0xf6,0xb9,0x44,0xf6,0xb8,0x45,0xf5,0xb2,0x41,0xf3,0xa5,0x3b,0xe2,0x98,0x37,0x3,0x1,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x86,0x4e,0x2e,0xf3,0xa6,0x77,0xf1,0x9e,0x66,0xed,0x7e,0x2d,0xee,0x82,0x2c,0xf0,0x85,0x2d,0x7e,0x47,0x17,0xe8,0xa6,0x64,0xf6,0xb5,0x70,0xf6,0xb2,0x6d,0xf5,0xb0,0x6a,0xf7,0xbb,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xfb,0xfd,0x5b,0x9c,0xca,0x42,0x96,0xcb,0x3c,0x93,0xc9,0x9,0x73,0xb6,0x0,0x6b,0xb0,0x0,0x69,0xad,0x0,0x66,0xab,0x0,0x66,0xab,0x0,0x67,0xad,0x4,0x6a,0xaf,0xbb,0xd7,0xe9,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xf8,0xee,0xf6,0xb9,0x4f,0xf6,0xb7,0x44,0xf6,0xba,0x45,0xf6,0xba,0x45,0xf5,0xb5,0x43,0xf4,0xa8,0x3d,0xf5,0xa7,0x3d,0x1b,0xf,0x4,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x11,0x8,0x3,0xb0,0x6d,0x45,0xf4,0xaa,0x7b,0xf1,0x9a,0x5b,0xee,0x82,0x2d,0xef,0x86,0x2e,0xee,0x91,0x36,0xf5,0xb5,0x70,0xf6,0xb7,0x73,0xf6,0xb4,0x70,0xf5,0xb1,0x6c,0xf9,0xcc,0xa1,0xff,0xff,0xff,0xff,0xff,0xff,0xd1,0xe2,0xef,0x4b,0x97,0xca,0x47,0x9a,0xce,0x3f,0x95,0xcb,0x3,0x71,0xb5,0x0,0x6c,0xb0,0x0,0x69,0xae,0x0,0x67,0xac,0x0,0x66,0xac,0x0,0x67,0xad,0x0,0x69,0xaf,0x66,0xa5,0xcf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xfa,0xf8,0xc3,0x67,0xf6,0xb8,0x44,0xf6,0xba,0x45,0xf6,0xbb,0x46,0xf6,0xb7,0x44,0xf4,0xab,0x3e,0xf8,0xab,0x3f,0x2a,0x19,0x8,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x2b,0x15,0x9,0xd4,0x8a,0x5c,0xf4,0xac,0x7c,0xf1,0x98,0x54,0xee,0x85,0x2e,0xf1,0x93,0x38,0xf6,0xba,0x75,0xf6,0xb9,0x75,0xf6,0xb6,0x72,0xf6,0xb3,0x6f,0xfa,0xd5,0xb1,0xff,0xff,0xff,0xff,0xff,0xff,0xb0,0xcf,0xe5,0x51,0x9e,0xcf,0x4b,0x9d,0xd0,0x43,0x97,0xcc,0x3,0x71,0xb5,0x0,0x6d,0xb1,0x0,0x6a,0xae,0x0,0x67,0xac,0x0,0x67,0xad,0x0,0x68,0xae,0x0,0x6a,0xb0,0x3b,0x8c,0xc2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xf9,0xc9,0x77,0xf6,0xb8,0x44,0xf6,0xba,0x45,0xf6,0xbc,0x46,0xf6,0xb8,0x44,0xf4,0xad,0x3f,0xf8,0xac,0x3f,0x2a,0x1a,0x8,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x47,0x26,0x12,0xee,0xa3,0x72,0xf4,0xae,0x7b,0xf1,0x97,0x4e,0xf1,0x92,0x38,0xf6,0xbb,0x78,0xf6,0xbb,0x78,0xf6,0xb7,0x75,0xf6,0xb5,0x71,0xfa,0xd6,0xb2,0xff,0xff,0xff,0xff,0xff,0xff,0xad,0xcd,0xe4,0x54,0xa0,0xd1,0x4e,0xa0,0xd1,0x48,0x9b,0xce,0xb,0x76,0xb8,0x0,0x6d,0xb2,0x0,0x6a,0xaf,0x0,0x68,0xad,0x0,0x68,0xad,0x0,0x69,0xae,0x0,0x6b,0xb1,0x36,0x89,0xc1,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xf9,0xc9,0x76,0xf6,0xb9,0x44,0xf6,0xbb,0x46,0xf6,0xbc,0x47,0xf6,0xb9,0x44,0xf4,0xad,0x3f,0xf8,0xad,0x40,0x2a,0x1a,0x8,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x70,0x42,0x26,0xf4,0xad,0x7b,0xf5,0xb1,0x7d,0xf3,0x9f,0x50,0xf7,0xbc,0x7b,0xf7,0xbc,0x7b,0xf6,0xb9,0x78,0xf6,0xb7,0x74,0xf9,0xd0,0xa6,0xff,0xff,0xff,0xff,0xff,0xff,0xc3,0xda,0xeb,0x56,0xa0,0xd0,0x51,0xa1,0xd2,0x4a,0x9c,0xcf,0x20,0x82,0xbf,0x0,0x6e,0xb2,0x0,0x6b,0xb0,0x0,0x68,0xae,0x0,0x68,0xae,0x0,0x69,0xaf,0x0,0x6b,0xb1,0x50,0x98,0xc9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xf9,0xf8,0xc3,0x66,0xf6,0xb9,0x45,0xf7,0xbb,0x46,0xf6,0xbc,0x47,0xf6,0xb8,0x45,0xf4,0xad,0x3f,0xf8,0xac,0x3f,0x2a,0x19,0x7,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xc,0x5,0x0,0xa5,0x67,0x40,0xf5,0xb1,0x7f,0xf5,0xb7,0x7e,0xf7,0xbf,0x80,0xf7,0xbe,0x7d,0xf7,0xbb,0x7b,0xf6,0xb9,0x78,0xf8,0xc2,0x8b,0xff,0xff,0xff,0xff,0xff,0xff,0xee,0xf5,0xf9,0x5b,0xa0,0xce,0x53,0xa2,0xd2,0x4c,0x9e,0xd0,0x3c,0x93,0xc8,0x6,0x71,0xb4,0x0,0x6c,0xb0,0x0,0x69,0xae,0x0,0x69,0xae,0x0,0x6a,0xaf,0x0,0x6b,0xb1,0x9b,0xc5,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xf7,0xec,0xf6,0xba,0x4e,0xf6,0xb9,0x45,0xf7,0xbb,0x46,0xf6,0xbc,0x47,0xf5,0xb7,0x44,0xf4,0xab,0x3e,0xf5,0xa8,0x3e,0x18,0xd,0x4,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x1f,0x10,0x7,0xc9,0x84,0x56,0xf5,0xb5,0x81,0xf7,0xbf,0x82,0xf8,0xc0,0x80,0xf7,0xbd,0x7d,0xf7,0xba,0x7a,0xf6,0xb8,0x77,0xfe,0xf5,0xec,0xff,0xff,0xff,0xff,0xff,0xff,0x9a,0xc2,0xdf,0x55,0x9f,0xd0,0x4e,0x9f,0xd0,0x47,0x99,0xcc,0x2a,0x87,0xc1,0x3,0x6d,0xb1,0x0,0x69,0xaf,0x0,0x6a,0xaf,0x0,0x6a,0xb0,0x27,0x80,0xbc,0xec,0xf4,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xe5,0xbf,0xf6,0xb6,0x42,0xf6,0xba,0x46,0xf7,0xbb,0x46,0xf7,0xbb,0x47,0xf5,0xb5,0x43,0xf3,0xa8,0x3d,0xdd,0x97,0x37,0x2,0x1,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x32,0x1a,0xb,0xe4,0x9d,0x6a,0xf7,0xbd,0x84,0xf8,0xc1,0x83,0xf8,0xbe,0x80,0xf7,0xbd,0x7d,0xf7,0xba,0x79,0xfa,0xd9,0xb6,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xf6,0xfa,0x74,0xac,0xd4,0x4f,0x9b,0xcd,0x48,0x99,0xcc,0x41,0x94,0xc8,0x2c,0x85,0xbe,0xb,0x70,0xb3,0x1,0x6a,0xb0,0xb,0x6e,0xb2,0xbf,0xd9,0xeb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xf8,0xc8,0x74,0xf6,0xb7,0x44,0xf6,0xba,0x46,0xf7,0xbb,0x46,0xf7,0xb9,0x46,0xf6,0xb2,0x42,0xf4,0xa7,0x3d,0xa6,0x70,0x29,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x4f,0x2e,0x18,0xef,0xaf,0x78,0xf8,0xc1,0x85,0xf8,0xc0,0x82,0xf7,0xbe,0x7f,0xf7,0xbc,0x7d,0xf7,0xbe,0x81,0xfe,0xf3,0xe8,0xff,0xff,0xff,0xff,0xff,0xff,0xf2,0xf7,0xfa,0x91,0xbd,0xdb,0x4f,0x97,0xc8,0x40,0x8e,0xc3,0x37,0x8a,0xc0,0x34,0x88,0xbf,0x57,0x9c,0xca,0xcc,0xe1,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xe4,0xbf,0xf5,0xb6,0x45,0xf6,0xb8,0x45,0xf6,0xba,0x46,0xf7,0xba,0x46,0xf6,0xb7,0x45,0xf5,0xad,0x3f,0xf4,0xa9,0x40,0x5c,0x3d,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x85,0x55,0x31,0xf7,0xbd,0x84,0xf8,0xc2,0x85,0xf8,0xc0,0x82,0xf7,0xbe,0x80,0xf7,0xbc,0x7d,0xf9,0xcb,0x99,0xfe,0xf9,0xf4,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xfe,0xfe,0xe5,0xef,0xf6,0xc1,0xda,0xeb,0xba,0xd5,0xe9,0xd8,0xe8,0xf2,0xf9,0xfb,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xf3,0xe4,0xf6,0xb9,0x51,0xf5,0xb5,0x43,0xf6,0xb8,0x45,0xf6,0xb9,0x46,0xf6,0xb8,0x46,0xf6,0xb3,0x43,0xf4,0xa7,0x3e,0xdf,0x9d,0x43,0x17,0xd,0x4,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x14,0xa,0x4,0xb2,0x7b,0x4b,0xf8,0xc2,0x88,0xf8,0xc1,0x85,0xf7,0xbf,0x82,0xf7,0xbe,0x80,0xf7,0xbd,0x7d,0xf9,0xca,0x97,0xfe,0xf9,0xf4,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xf2,0xe1,0xf7,0xbc,0x5d,0xf5,0xb3,0x42,0xf5,0xb6,0x44,0xf5,0xb7,0x45,0xf6,0xb8,0x45,0xf6,0xb5,0x44,0xf5,0xad,0x40,0xf6,0xae,0x4c,0x88,0x5d,0x27,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x1d,0x10,0x6,0xdb,0xa0,0x68,0xf8,0xc3,0x88,0xf7,0xc1,0x85,0xf7,0xc0,0x82,0xf7,0xbf,0x80,0xf7,0xbe,0x7e,0xf8,0xc4,0x88,0xfc,0xe6,0xcc,0xfe,0xfb,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfa,0xf3,0xfa,0xda,0xa9,0xf5,0xb3,0x4a,0xf5,0xb2,0x42,0xf5,0xb3,0x43,0xf5,0xb6,0x44,0xf5,0xb7,0x45,0xf5,0xb5,0x44,0xf5,0xb0,0x42,0xf5,0xad,0x4d,0xdd,0x9e,0x4a,0x19,0xf,0x5,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x50,0x33,0x19,0xec,0xb4,0x7a,0xf8,0xc2,0x87,0xf7,0xc1,0x85,0xf7,0xc1,0x83,0xf7,0xc0,0x80,0xf7,0xc0,0x7f,0xf7,0xc0,0x7c,0xf7,0xc2,0x7e,0xf8,0xcc,0x92,0xfa,0xda,0xb0,0xfb,0xdf,0xb9,0xfa,0xd9,0xad,0xf7,0xc8,0x84,0xf5,0xb4,0x54,0xf4,0xad,0x3f,0xf4,0xaf,0x41,0xf5,0xb2,0x42,0xf5,0xb4,0x43,0xf5,0xb5,0x44,0xf5,0xb4,0x44,0xf5,0xb2,0x46,0xf5,0xb2,0x54,0xf5,0xb4,0x5a,0x5e,0x3e,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x71,0x4b,0x29,0xf8,0xc0,0x86,0xf7,0xc3,0x87,0xf7,0xc2,0x85,0xf7,0xc1,0x83,0xf7,0xc2,0x82,0xf7,0xc2,0x7f,0xf7,0xc2,0x7e,0xf6,0xc0,0x76,0xf4,0xb4,0x59,0xf3,0xa8,0x3e,0xf3,0xa7,0x39,0xf3,0xa9,0x3d,0xf4,0xab,0x3e,0xf4,0xad,0x40,0xf4,0xb0,0x41,0xf4,0xb2,0x42,0xf5,0xb2,0x42,0xf5,0xb3,0x45,0xf6,0xb7,0x54,0xf6,0xb7,0x60,0xf6,0xb5,0x5f,0x9d,0x6b,0x31,0x2,0x1,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x8b,0x5f,0x36,0xf9,0xc1,0x87,0xf7,0xc3,0x88,0xf8,0xc3,0x86,0xf7,0xc3,0x84,0xf8,0xc3,0x81,0xf7,0xc4,0x80,0xf7,0xc4,0x7e,0xf7,0xc4,0x7d,0xf7,0xc3,0x7a,0xf6,0xbd,0x6c,0xf5,0xb7,0x5c,0xf5,0xb5,0x54,0xf5,0xb4,0x50,0xf5,0xb6,0x52,0xf6,0xb9,0x58,0xf6,0xbd,0x62,0xf7,0xbf,0x6a,0xf6,0xba,0x66,0xf6,0xb6,0x63,0xab,0x78,0x39,0xa,0x6,0x2,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x83,0x58,0x32,0xf0,0xb9,0x7f,0xf7,0xc3,0x88,0xf7,0xc3,0x86,0xf8,0xc4,0x84,0xf7,0xc5,0x82,0xf7,0xc5,0x80,0xf7,0xc5,0x7f,0xf8,0xc5,0x7d,0xf7,0xc4,0x7b,0xf7,0xc4,0x79,0xf7,0xc4,0x78,0xf7,0xc3,0x76,0xf7,0xc3,0x74,0xf7,0xc2,0x71,0xf6,0xbe,0x6d,0xf6,0xba,0x6a,0xf4,0xb6,0x65,0x8a,0x5e,0x2c,0xc,0x7,0x3,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x4f,0x33,0x1a,0xd2,0x99,0x60,0xf8,0xc4,0x89,0xf8,0xc3,0x86,0xf8,0xc4,0x84,0xf7,0xc5,0x82,0xf7,0xc5,0x80,0xf7,0xc5,0x7f,0xf7,0xc4,0x7e,0xf7,0xc4,0x7b,0xf7,0xc3,0x79,0xf7,0xc2,0x77,0xf6,0xc0,0x74,0xf6,0xbd,0x71,0xf6,0xbb,0x6e,0xe1,0xa4,0x59,0x5c,0x3d,0x1b,0x1,0x1,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xe,0x6,0x0,0x72,0x4b,0x28,0xd0,0x9a,0x62,0xf7,0xbf,0x80,0xf8,0xc4,0x85,0xf7,0xc3,0x82,0xf7,0xc3,0x80,0xf7,0xc3,0x7e,0xf7,0xc1,0x7c,0xf6,0xc0,0x7a,0xf7,0xbf,0x78,0xf8,0xbc,0x72,0xde,0xa2,0x5d,0x80,0x57,0x2b,0x13,0xb,0x4,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x19,0xe,0x5,0x44,0x2c,0x15,0x81,0x59,0x32,0xb2,0x80,0x4c,0xcb,0x95,0x5b,0xd2,0x9c,0x5f,0xcd,0x97,0x5a,0xb9,0x86,0x4d,0x8b,0x61,0x34,0x4a,0x30,0x17,0x15,0xc,0x5,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x0,0x0,0x0,0x1,0x0,0x0,0x3,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +}; + + +GLXContext GHOST_WindowX11::s_firstContext = NULL; + +GHOST_WindowX11:: +GHOST_WindowX11( + GHOST_SystemX11 *system, + Display * display, + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const bool stereoVisual +) : + GHOST_Window(title,left,top,width,height,state,type,stereoVisual), + m_context(NULL), + m_display(display), + m_system (system), + m_valid_setup (false), + m_invalid_window(false), + m_empty_cursor(None), + m_custom_cursor(None) +{ + + // Set up the minimum atrributes that we require and see if + // X can find us a visual matching those requirements. + + int attributes[40], i = 0; + + + if(m_stereoVisual) + attributes[i++] = GLX_STEREO; + + attributes[i++] = GLX_RGBA; + attributes[i++] = GLX_DOUBLEBUFFER; + attributes[i++] = GLX_RED_SIZE; attributes[i++] = 1; + attributes[i++] = GLX_BLUE_SIZE; attributes[i++] = 1; + attributes[i++] = GLX_GREEN_SIZE; attributes[i++] = 1; + attributes[i++] = GLX_DEPTH_SIZE; attributes[i++] = 1; + attributes[i] = None; + + m_visual = glXChooseVisual(m_display, DefaultScreen(m_display), attributes); + + if (m_visual == NULL) { + // barf : no visual meeting these requirements could be found. + printf("%s:%d: X11 glxChooseVisual() failed for OpenGL, verify working openGL system!\n", __FILE__, __LINE__); + return; + } + + // Create a bunch of attributes needed to create an X window. + + + // First create a colormap for the window and visual. + // This seems pretty much a legacy feature as we are in rgba mode anyway. + + XSetWindowAttributes xattributes; + memset(&xattributes, 0, sizeof(xattributes)); + + xattributes.colormap= XCreateColormap( + m_display, + RootWindow(m_display, m_visual->screen), + m_visual->visual, + AllocNone + ); + + xattributes.border_pixel= 0; + + // Specify which events we are interested in hearing. + + xattributes.event_mask= + ExposureMask | StructureNotifyMask | + KeyPressMask | KeyReleaseMask | + EnterWindowMask | LeaveWindowMask | + ButtonPressMask | ButtonReleaseMask | + PointerMotionMask | FocusChangeMask; + + // create the window! + + m_window = + XCreateWindow( + m_display, + RootWindow(m_display, m_visual->screen), + left, + top, + width, + height, + 0, // no border. + m_visual->depth, + InputOutput, + m_visual->visual, + CWBorderPixel|CWColormap|CWEventMask, + &xattributes + ); + + + // Are we in fullscreen mode - then include + // some obscure blut code to remove decorations. + + if (state == GHOST_kWindowStateFullScreen) { + + MotifWmHints hints; + Atom atom; + + atom = XInternAtom(m_display, "_MOTIF_WM_HINTS", False); + + if (atom == None) { + GHOST_PRINT("Could not intern X atom for _MOTIF_WM_HINTS.\n"); + } else { + hints.flags = MWM_HINTS_DECORATIONS; + hints.decorations = 0; /* Absolutely no decorations. */ + // other hints.decorations make no sense + // you can't select individual decorations + + XChangeProperty(m_display, m_window, + atom, atom, 32, + PropModeReplace, (unsigned char *) &hints, 4); + } + } else if (state == GHOST_kWindowStateMaximized) { + // With this, xprop should report the following just after launch + // _NET_WM_STATE(ATOM) = _NET_WM_STATE_MAXIMIZED_VERT, _NET_WM_STATE_MAXIMIZED_HORZ + // After demaximization the right side is empty, though (maybe not the most correct then?) + Atom state, atomh, atomv; + + state = XInternAtom(m_display, "_NET_WM_STATE", False); + atomh = XInternAtom(m_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False); + atomv = XInternAtom(m_display, "_NET_WM_STATE_MAXIMIZED_VERT", False); + if (state == None ) { + GHOST_PRINT("Atom _NET_WM_STATE requested but not avaliable nor created.\n"); + } else { + XChangeProperty(m_display, m_window, + state, XA_ATOM, 32, + PropModeAppend, (unsigned char *) &atomh, 1); + XChangeProperty(m_display, m_window, + state, XA_ATOM, 32, + PropModeAppend, (unsigned char *) &atomv, 1); + } + } + + // Create some hints for the window manager on how + // we want this window treated. + + XSizeHints * xsizehints = XAllocSizeHints(); + xsizehints->flags = USPosition | USSize; + xsizehints->x = left; + xsizehints->y = top; + xsizehints->width = width; + xsizehints->height = height; + XSetWMNormalHints(m_display, m_window, xsizehints); + XFree(xsizehints); + + XClassHint * xclasshint = XAllocClassHint(); + int len = title.Length() +1 ; + char *wmclass = (char *)malloc(sizeof(char) * len); + strncpy(wmclass, (const char*)title, sizeof(char) * len); + xclasshint->res_name = wmclass; + xclasshint->res_class = wmclass; + XSetClassHint(m_display, m_window, xclasshint); + free(wmclass); + XFree(xclasshint); + + + // Set the window icon + XWMHints *xwmhints = XAllocWMHints(); + XImage *x_image, *mask_image; + Pixmap icon_pixmap, mask_pixmap; + icon_pixmap = XCreatePixmap(display, m_window, BLENDER_ICON_WIDTH, BLENDER_ICON_HEIGHT, 24); + mask_pixmap = XCreatePixmap(display, m_window, BLENDER_ICON_WIDTH, BLENDER_ICON_HEIGHT, 1); + GC gc_icon = XCreateGC(display, icon_pixmap, 0, NULL); + GC gc_mask = XCreateGC(display, mask_pixmap, 0, NULL); + + x_image = XCreateImage( display, m_visual->visual, 24, ZPixmap, 0, NULL, BLENDER_ICON_WIDTH, BLENDER_ICON_HEIGHT, 32, 0 ); + mask_image = XCreateImage( display, m_visual->visual, 1, ZPixmap, 0, NULL, BLENDER_ICON_WIDTH, BLENDER_ICON_HEIGHT, 8, 0); + + x_image->data = (char *)malloc(x_image->bytes_per_line * BLENDER_ICON_HEIGHT); + mask_image->data = (char *)malloc( mask_image->bytes_per_line * BLENDER_ICON_HEIGHT); + + /* copy the BLENDER_ICON_48x48x24 into the XImage */ + unsigned char *col = BLENDER_ICON_48x48x24; + int px, py; + for (px=0; pxicon_pixmap = icon_pixmap; + xwmhints->icon_mask = mask_pixmap; + XFreeGC (display, gc_icon); + XFreeGC (display, gc_mask); + XDestroyImage( x_image ); /* frees x_image->data too */ + XDestroyImage( mask_image ); + + xwmhints->initial_state = NormalState; + xwmhints->flags = IconPixmapHint|IconMaskHint|StateHint; + XSetWMHints(display, m_window, xwmhints ); + XFree(xwmhints); + // done setting the icon + + + setTitle(title); + + initXInputDevices(); + + // now set up the rendering context. + if (installDrawingContext(type) == GHOST_kSuccess) { + m_valid_setup = true; + GHOST_PRINT("Created window\n"); + } + + XMapWindow(m_display, m_window); + GHOST_PRINT("Mapped window\n"); + + XFlush(m_display); +} + +/* + Dummy function to get around IO Handler exiting if device invalid + Basically it will not crash blender now if you have a X device that + is configured but not plugged in. + +*/ +static int ApplicationErrorHandler(Display *display, XErrorEvent *theEvent) { + fprintf(stderr, "Ignoring Xlib error: error code %d request code %d\n", + theEvent->error_code, theEvent->request_code) ; + + /* No exit! - but keep lint happy */ + return 0 ; +} + +void GHOST_WindowX11::initXInputDevices() +{ + static XErrorHandler old_handler = (XErrorHandler) 0 ; + XExtensionVersion *version = XGetExtensionVersion(m_display, INAME); + + if(version && (version != (XExtensionVersion*)NoSuchExtension)) { + if(version->present) { + int device_count; + XDeviceInfo* device_info = XListInputDevices(m_display, &device_count); + m_xtablet.StylusDevice = 0; + m_xtablet.EraserDevice = 0; + m_xtablet.CommonData.Active= 0; + + /* Install our error handler to override Xlib's termination behavior */ + old_handler = XSetErrorHandler(ApplicationErrorHandler) ; + + for(int i=0; inum_classes; ++j) { + if(ici->c_class==ValuatorClass) { + XValuatorInfo* xvi = (XValuatorInfo*)ici; + m_xtablet.PressureLevels = xvi->axes[2].max_value; + + /* this is assuming that the tablet has the same tilt resolution in both + * positive and negative directions. It would be rather weird if it didn't.. */ + m_xtablet.XtiltLevels = xvi->axes[3].max_value; + m_xtablet.YtiltLevels = xvi->axes[4].max_value; + break; + } + + ici = (XAnyClassPtr)(((char *)ici) + ici->length); + } + } else { + m_xtablet.StylusID= 0; + } + } + if(!strcasecmp(device_info[i].name, "eraser")) { + m_xtablet.EraserID= device_info[i].id; + m_xtablet.EraserDevice = XOpenDevice(m_display, m_xtablet.EraserID); + if (m_xtablet.EraserDevice == NULL) m_xtablet.EraserID= 0; + } + } + + /* Restore handler */ + (void) XSetErrorHandler(old_handler) ; + + XFreeDeviceList(device_info); + + + XEventClass xevents[10], ev; + int dcount = 0; + + if(m_xtablet.StylusDevice) { + DeviceMotionNotify(m_xtablet.StylusDevice, m_xtablet.MotionEvent, ev); + if(ev) xevents[dcount++] = ev; + ProximityIn(m_xtablet.StylusDevice, m_xtablet.ProxInEvent, ev); + if(ev) xevents[dcount++] = ev; + ProximityOut(m_xtablet.StylusDevice, m_xtablet.ProxOutEvent, ev); + if(ev) xevents[dcount++] = ev; + } + if(m_xtablet.EraserDevice) { + DeviceMotionNotify(m_xtablet.EraserDevice, m_xtablet.MotionEvent, ev); + if(ev) xevents[dcount++] = ev; + ProximityIn(m_xtablet.EraserDevice, m_xtablet.ProxInEvent, ev); + if(ev) xevents[dcount++] = ev; + ProximityOut(m_xtablet.EraserDevice, m_xtablet.ProxOutEvent, ev); + if(ev) xevents[dcount++] = ev; + } + + XSelectExtensionEvent(m_display, m_window, xevents, dcount); + } + XFree(version); + } +} + + + Window +GHOST_WindowX11:: +getXWindow( +){ + return m_window; +} + + bool +GHOST_WindowX11:: +getValid( +) const { + return m_valid_setup; +} + + void +GHOST_WindowX11:: +setTitle( + const STR_String& title +){ + XStoreName(m_display,m_window,title); + XFlush(m_display); +} + + void +GHOST_WindowX11:: +getTitle( + STR_String& title +) const { + char *name = NULL; + + XFetchName(m_display,m_window,&name); + title= name?name:"untitled"; + XFree(name); +} + + void +GHOST_WindowX11:: +getWindowBounds( + GHOST_Rect& bounds +) const { + // Getting the window bounds under X11 is not + // really supported (nor should it be desired). + getClientBounds(bounds); +} + + void +GHOST_WindowX11:: +getClientBounds( + GHOST_Rect& bounds +) const { + Window root_return; + int x_return,y_return; + unsigned int w_return,h_return,border_w_return,depth_return; + GHOST_TInt32 screen_x, screen_y; + + XGetGeometry(m_display,m_window,&root_return,&x_return,&y_return, + &w_return,&h_return,&border_w_return,&depth_return); + + clientToScreen(0, 0, screen_x, screen_y); + + bounds.m_l = screen_x; + bounds.m_r = bounds.m_l + w_return; + bounds.m_t = screen_y; + bounds.m_b = bounds.m_t + h_return; + +} + + GHOST_TSuccess +GHOST_WindowX11:: +setClientWidth( + GHOST_TUns32 width +){ + XWindowChanges values; + unsigned int value_mask= CWWidth; + values.width = width; + XConfigureWindow(m_display,m_window,value_mask,&values); + + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_WindowX11:: +setClientHeight( + GHOST_TUns32 height +){ + XWindowChanges values; + unsigned int value_mask= CWHeight; + values.height = height; + XConfigureWindow(m_display,m_window,value_mask,&values); + return GHOST_kSuccess; + +} + + GHOST_TSuccess +GHOST_WindowX11:: +setClientSize( + GHOST_TUns32 width, + GHOST_TUns32 height +){ + XWindowChanges values; + unsigned int value_mask= CWWidth | CWHeight; + values.width = width; + values.height = height; + XConfigureWindow(m_display,m_window,value_mask,&values); + return GHOST_kSuccess; + +} + + void +GHOST_WindowX11:: +screenToClient( + GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32& outX, + GHOST_TInt32& outY +) const { + // not sure about this one! + + int ax,ay; + Window temp; + + XTranslateCoordinates( + m_display, + RootWindow(m_display, m_visual->screen), + m_window, + inX, + inY, + &ax, + &ay, + &temp + ); + outX = ax; + outY = ay; +} + + void +GHOST_WindowX11:: +clientToScreen( + GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32& outX, + GHOST_TInt32& outY +) const { + int ax,ay; + Window temp; + + XTranslateCoordinates( + m_display, + m_window, + RootWindow(m_display, m_visual->screen), + inX, + inY, + &ax, + &ay, + &temp + ); + outX = ax; + outY = ay; +} + + + GHOST_TWindowState +GHOST_WindowX11:: +getState( +) const { + //FIXME + return GHOST_kWindowStateNormal; +} + + GHOST_TSuccess +GHOST_WindowX11:: +setState( + GHOST_TWindowState state +){ + //TODO + + if (state == (int)getState()) { + return GHOST_kSuccess; + } else { + return GHOST_kFailure; + } + +} + +#include +using namespace std; + + GHOST_TSuccess +GHOST_WindowX11:: +setOrder( + GHOST_TWindowOrder order +){ + if (order == GHOST_kWindowOrderTop) { + XWindowAttributes attr; + Atom atom; + + /* We use both XRaiseWindow and _NET_ACTIVE_WINDOW, since some + window managers ignore the former (e.g. kwin from kde) and others + don't implement the latter (e.g. fluxbox pre 0.9.9) */ + + XRaiseWindow(m_display, m_window); + + atom = XInternAtom(m_display, "_NET_ACTIVE_WINDOW", True); + + if (atom != None) { + Window root; + XEvent xev; + long eventmask; + + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.window = m_window; + xev.xclient.message_type = atom; + + xev.xclient.format = 32; + xev.xclient.data.l[0] = 0; + xev.xclient.data.l[1] = 0; + xev.xclient.data.l[2] = 0; + xev.xclient.data.l[3] = 0; + xev.xclient.data.l[4] = 0; + + root = RootWindow(m_display, m_visual->screen), + eventmask = SubstructureRedirectMask | SubstructureNotifyMask; + + XSendEvent(m_display, root, False, eventmask, &xev); + } + + XGetWindowAttributes(m_display, m_window, &attr); + + /* iconized windows give bad match error */ + if (attr.map_state == IsViewable) + XSetInputFocus(m_display, m_window, RevertToPointerRoot, + CurrentTime); + XFlush(m_display); + } else if (order == GHOST_kWindowOrderBottom) { + XLowerWindow(m_display,m_window); + XFlush(m_display); + } else { + return GHOST_kFailure; + } + + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_WindowX11:: +swapBuffers( +){ + if (getDrawingContextType() == GHOST_kDrawingContextTypeOpenGL) { + glXSwapBuffers(m_display,m_window); + return GHOST_kSuccess; + } else { + return GHOST_kFailure; + } +} + + GHOST_TSuccess +GHOST_WindowX11:: +activateDrawingContext( +){ + if (m_context !=NULL) { + glXMakeCurrent(m_display, m_window,m_context); + return GHOST_kSuccess; + } + return GHOST_kFailure; +} + + GHOST_TSuccess +GHOST_WindowX11:: +invalidate( +){ + + // So the idea of this function is to generate an expose event + // for the window. + // Unfortunately X does not handle expose events for you and + // it is the client's job to refresh the dirty part of the window. + // We need to queue up invalidate calls and generate GHOST events + // for them in the system. + + // We implement this by setting a boolean in this class to concatenate + // all such calls into a single event for this window. + + // At the same time we queue the dirty windows in the system class + // and generate events for them at the next processEvents call. + + if (m_invalid_window == false) { + m_system->addDirtyWindow(this); + m_invalid_window = true; + } + + return GHOST_kSuccess; +} + +/** + * called by the X11 system implementation when expose events + * for the window have been pushed onto the GHOST queue + */ + + void +GHOST_WindowX11:: +validate( +){ + m_invalid_window = false; +} + + +/** + * Destructor. + * Closes the window and disposes resources allocated. + */ + +GHOST_WindowX11:: +~GHOST_WindowX11( +){ + std::map::iterator it = m_standard_cursors.begin(); + for (; it != m_standard_cursors.end(); it++) { + XFreeCursor(m_display, it->second); + } + + if (m_empty_cursor) { + XFreeCursor(m_display, m_empty_cursor); + } + if (m_custom_cursor) { + XFreeCursor(m_display, m_custom_cursor); + } + + if (m_context) { + if (m_context == s_firstContext) { + s_firstContext = NULL; + } + glXDestroyContext(m_display, m_context); + } + XDestroyWindow(m_display, m_window); + XFree(m_visual); +} + + + + +/** + * Tries to install a rendering context in this window. + * @param type The type of rendering context installed. + * @return Indication as to whether installation has succeeded. + */ + GHOST_TSuccess +GHOST_WindowX11:: +installDrawingContext( + GHOST_TDrawingContextType type +){ + // only support openGL for now. + GHOST_TSuccess success; + switch (type) { + case GHOST_kDrawingContextTypeOpenGL: + m_context = glXCreateContext(m_display, m_visual, s_firstContext, True); + if (m_context !=NULL) { + if (!s_firstContext) { + s_firstContext = m_context; + } + glXMakeCurrent(m_display, m_window,m_context); + success = GHOST_kSuccess; + } else { + success = GHOST_kFailure; + } + + break; + + case GHOST_kDrawingContextTypeNone: + success = GHOST_kSuccess; + break; + + default: + success = GHOST_kFailure; + } + return success; +} + + + +/** + * Removes the current drawing context. + * @return Indication as to whether removal has succeeded. + */ + GHOST_TSuccess +GHOST_WindowX11:: +removeDrawingContext( +){ + GHOST_TSuccess success; + + if (m_context != NULL) { + glXDestroyContext(m_display, m_context); + success = GHOST_kSuccess; + } else { + success = GHOST_kFailure; + } + return success; +} + + + Cursor +GHOST_WindowX11:: +getStandardCursor( + GHOST_TStandardCursor g_cursor +){ + unsigned int xcursor_id; + +#define GtoX(gcurs, xcurs) case gcurs: xcursor_id = xcurs + switch (g_cursor) { + GtoX(GHOST_kStandardCursorRightArrow, XC_arrow); break; + GtoX(GHOST_kStandardCursorLeftArrow, XC_top_left_arrow); break; + GtoX(GHOST_kStandardCursorInfo, XC_hand1); break; + GtoX(GHOST_kStandardCursorDestroy, XC_pirate); break; + GtoX(GHOST_kStandardCursorHelp, XC_question_arrow); break; + GtoX(GHOST_kStandardCursorCycle, XC_exchange); break; + GtoX(GHOST_kStandardCursorSpray, XC_spraycan); break; + GtoX(GHOST_kStandardCursorWait, XC_watch); break; + GtoX(GHOST_kStandardCursorText, XC_xterm); break; + GtoX(GHOST_kStandardCursorCrosshair, XC_crosshair); break; + GtoX(GHOST_kStandardCursorUpDown, XC_sb_v_double_arrow); break; + GtoX(GHOST_kStandardCursorLeftRight, XC_sb_h_double_arrow); break; + GtoX(GHOST_kStandardCursorTopSide, XC_top_side); break; + GtoX(GHOST_kStandardCursorBottomSide, XC_bottom_side); break; + GtoX(GHOST_kStandardCursorLeftSide, XC_left_side); break; + GtoX(GHOST_kStandardCursorRightSide, XC_right_side); break; + GtoX(GHOST_kStandardCursorTopLeftCorner, XC_top_left_corner); break; + GtoX(GHOST_kStandardCursorTopRightCorner, XC_top_right_corner); break; + GtoX(GHOST_kStandardCursorBottomRightCorner, XC_bottom_right_corner); break; + GtoX(GHOST_kStandardCursorBottomLeftCorner, XC_bottom_left_corner); break; + GtoX(GHOST_kStandardCursorPencil, XC_pencil); break; + default: + xcursor_id = 0; + } +#undef GtoX + + if (xcursor_id) { + Cursor xcursor = m_standard_cursors[xcursor_id]; + + if (!xcursor) { + xcursor = XCreateFontCursor(m_display, xcursor_id); + + m_standard_cursors[xcursor_id] = xcursor; + } + + return xcursor; + } else { + return None; + } +} + + Cursor +GHOST_WindowX11:: +getEmptyCursor( +) { + if (!m_empty_cursor) { + Pixmap blank; + XColor dummy; + char data[1] = {0}; + + /* make a blank cursor */ + blank = XCreateBitmapFromData ( + m_display, + RootWindow(m_display,DefaultScreen(m_display)), + data, 1, 1 + ); + + m_empty_cursor = XCreatePixmapCursor(m_display, blank, blank, &dummy, &dummy, 0, 0); + XFreePixmap(m_display, blank); + } + + return m_empty_cursor; +} + + GHOST_TSuccess +GHOST_WindowX11:: +setWindowCursorVisibility( + bool visible +){ + Cursor xcursor; + + if (visible) { + xcursor = getStandardCursor( getCursorShape() ); + } else { + xcursor = getEmptyCursor(); + } + + XDefineCursor(m_display, m_window, xcursor); + XFlush(m_display); + + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_WindowX11:: +setWindowCursorShape( + GHOST_TStandardCursor shape +){ + Cursor xcursor = getStandardCursor( shape ); + + XDefineCursor(m_display, m_window, xcursor); + XFlush(m_display); + + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_WindowX11:: +setWindowCustomCursorShape( + GHOST_TUns8 bitmap[16][2], + GHOST_TUns8 mask[16][2], + int hotX, + int hotY +){ + +setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*)mask, + 16, 16, hotX, hotY, 0, 1); + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_WindowX11:: +setWindowCustomCursorShape( + GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, + int sizey, + int hotX, + int hotY, + int fg_color, + int bg_color +){ + Pixmap bitmap_pix, mask_pix; + XColor fg, bg; + + if(XAllocNamedColor(m_display, DefaultColormap(m_display, DefaultScreen(m_display)), + "White", &fg, &fg) == 0) return GHOST_kFailure; + if(XAllocNamedColor(m_display, DefaultColormap(m_display, DefaultScreen(m_display)), + "Black", &bg, &bg) == 0) return GHOST_kFailure; + + if (m_custom_cursor) { + XFreeCursor(m_display, m_custom_cursor); + } + + bitmap_pix = XCreateBitmapFromData(m_display, m_window, (char*) bitmap, sizex, sizey); + mask_pix = XCreateBitmapFromData(m_display, m_window, (char*) mask, sizex, sizey); + + m_custom_cursor = XCreatePixmapCursor(m_display, bitmap_pix, mask_pix, &fg, &bg, hotX, hotY); + XDefineCursor(m_display, m_window, m_custom_cursor); + XFlush(m_display); + + XFreePixmap(m_display, bitmap_pix); + XFreePixmap(m_display, mask_pix); + + return GHOST_kSuccess; +} + +/* + +void glutCustomCursor(char *data1, char *data2, int size) +{ + Pixmap source, mask; + Cursor cursor; + XColor fg, bg; + + if(XAllocNamedColor(__glutDisplay, DefaultColormap(__glutDisplay, __glutScreen), + "White", &fg, &fg) == 0) return; + if(XAllocNamedColor(__glutDisplay, DefaultColormap(__glutDisplay, __glutScreen), + "Red", &bg, &bg) == 0) return; + + + source= XCreateBitmapFromData(__glutDisplay, xdraw, data2, size, size); + mask= XCreateBitmapFromData(__glutDisplay, xdraw, data1, size, size); + + cursor= XCreatePixmapCursor(__glutDisplay, source, mask, &fg, &bg, 7, 7); + + XFreePixmap(__glutDisplay, source); + XFreePixmap(__glutDisplay, mask); + + XDefineCursor(__glutDisplay, xdraw, cursor); +} + +*/ diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h new file mode 100644 index 00000000000..0de4f65acd1 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowX11.h @@ -0,0 +1,334 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_WindowX11.h + * Declaration of GHOST_WindowX11 class. + */ + +#ifndef _GHOST_WINDOWX11_H_ +#define _GHOST_WINDOWX11_H_ + +#include "GHOST_Window.h" +#include +#include +// For tablets +#include + +#include + +class STR_String; +class GHOST_SystemX11; + +/** + * X11 implementation of GHOST_IWindow. + * Dimensions are given in screen coordinates that are relative to the upper-left corner of the screen. + * @author Laurence Bourn + * @date October 26, 2001 + */ + +class GHOST_WindowX11 : public GHOST_Window +{ +public: + /** + * Constructor. + * Creates a new window and opens it. + * To check if the window was created properly, use the getValid() method. + * @param title The text shown in the title bar of the window. + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state the window is initially opened with. + * @param type The type of drawing context installed in this window. + * @param stereoVisual Stereo visual for quad buffered stereo. + */ + GHOST_WindowX11( + GHOST_SystemX11 *system, + Display * display, + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone, + const bool stereoVisual = false + ); + + bool + getValid( + ) const; + + void + setTitle(const STR_String& title); + + void + getTitle( + STR_String& title + ) const; + + void + getWindowBounds( + GHOST_Rect& bounds + ) const; + + void + getClientBounds( + GHOST_Rect& bounds + ) const; + + GHOST_TSuccess + setClientWidth( + GHOST_TUns32 width + ); + + GHOST_TSuccess + setClientHeight( + GHOST_TUns32 height + ); + + GHOST_TSuccess + setClientSize( + GHOST_TUns32 width, + GHOST_TUns32 height + ); + + void + screenToClient( + GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32& outX, + GHOST_TInt32& outY + ) const; + + void + clientToScreen( + GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32& outX, + GHOST_TInt32& outY + ) const; + + GHOST_TWindowState + getState( + ) const ; + + GHOST_TSuccess + setState( + GHOST_TWindowState state + ); + + GHOST_TSuccess + setOrder( + GHOST_TWindowOrder order + ); + + GHOST_TSuccess + swapBuffers( + ); + + GHOST_TSuccess + activateDrawingContext( + ); + GHOST_TSuccess + invalidate( + ); + + /** + * Destructor. + * Closes the window and disposes resources allocated. + */ + ~GHOST_WindowX11(); + + /** + * @section + * X11 system specific calls. + */ + + /** + * The reverse of invalidate! Tells this window + * that all events for it have been pushed into + * the GHOST event queue. + */ + + void + validate( + ); + + /** + * Return a handle to the x11 window type. + */ + Window + getXWindow( + ); + + class XTablet + { + public: + GHOST_TabletData CommonData; + + XDevice* StylusDevice; + XDevice* EraserDevice; + + XID StylusID, EraserID; + + int MotionEvent; + int ProxInEvent; + int ProxOutEvent; + + int PressureLevels; + int XtiltLevels, YtiltLevels; + }; + + XTablet& GetXTablet() + { return m_xtablet; } + + const GHOST_TabletData* GetTabletData() + { return &m_xtablet.CommonData; } +protected: + /** + * Tries to install a rendering context in this window. + * @param type The type of rendering context installed. + * @return Indication as to whether installation has succeeded. + */ + GHOST_TSuccess + installDrawingContext( + GHOST_TDrawingContextType type + ); + + /** + * Removes the current drawing context. + * @return Indication as to whether removal has succeeded. + */ + GHOST_TSuccess + removeDrawingContext( + ); + + /** + * Sets the cursor visibility on the window using + * native window system calls. + */ + GHOST_TSuccess + setWindowCursorVisibility( + bool visible + ); + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + GHOST_TSuccess + setWindowCursorShape( + GHOST_TStandardCursor shape + ); + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + GHOST_TSuccess + setWindowCustomCursorShape( + GHOST_TUns8 bitmap[16][2], + GHOST_TUns8 mask[16][2], + int hotX, + int hotY + ); + + /** + * Sets the cursor shape on the window using + * native window system calls (Arbitrary size/color). + */ + GHOST_TSuccess + setWindowCustomCursorShape( + GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, + int sizey, + int hotX, + int hotY, + int fg_color, + int bg_color + ); + +private : + + /// Force use of public constructor. + + GHOST_WindowX11( + ); + + GHOST_WindowX11( + const GHOST_WindowX11 & + ); + + Cursor + getStandardCursor( + GHOST_TStandardCursor g_cursor + ); + + Cursor + getEmptyCursor( + ); + + void initXInputDevices(); + + GLXContext m_context; + Window m_window; + Display *m_display; + XVisualInfo *m_visual; + + /** The first created OpenGL context (for sharing display lists) */ + static GLXContext s_firstContext; + + /// A pointer to the typed system class. + + GHOST_SystemX11 * m_system; + + bool m_valid_setup; + + /** Used to concatenate calls to invalidate() on this window. */ + bool m_invalid_window; + + /** XCursor structure of an empty (blank) cursor */ + Cursor m_empty_cursor; + + /** XCursor structure of the custom cursor */ + Cursor m_custom_cursor; + + /** Cache of XC_* ID's to XCursor structures */ + std::map m_standard_cursors; + + /* Tablet devices */ + XTablet m_xtablet; +}; + + +#endif // _GHOST_WINDOWX11_H_ diff --git a/intern/ghost/intern/Makefile b/intern/ghost/intern/Makefile new file mode 100644 index 00000000000..32498222ac6 --- /dev/null +++ b/intern/ghost/intern/Makefile @@ -0,0 +1,66 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# ghost intern Makefile +# + +LIBNAME = ghost +DIR = $(OCGDIR)/intern/$(LIBNAME) + +CCSRCS = GHOST_Buttons.cpp GHOST_System.cpp GHOST_Window.cpp +CCSRCS += GHOST_EventManager.cpp GHOST_EventPrinter.cpp GHOST_WindowManager.cpp +CCSRCS += GHOST_ISystem.cpp GHOST_ModifierKeys.cpp GHOST_TimerManager.cpp +CCSRCS += GHOST_Rect.cpp GHOST_DisplayManager.cpp GHOST_C-api.cpp +CCSRCS += GHOST_CallbackEventConsumer.cpp + +include nan_definitions.mk + +ifeq ($(OS),$(findstring $(OS), "darwin")) + CCSRCS += $(wildcard *Carbon.cpp) +endif + +ifeq ($(OS),$(findstring $(OS), "windows")) + CPPFLAGS += -I$(NAN_WINTAB)/include + CCSRCS += $(wildcard *Win32.cpp) +endif + +ifeq ($(OS),$(findstring $(OS), "freebsd irix linux openbsd solaris")) + CCSRCS += $(wildcard *X11.cpp) +endif + +include nan_compile.mk + +#CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I$(NAN_MEMUTIL)/include +CPPFLAGS += -I.. +CPPFLAGS += -I$(OPENGL_HEADERS) + diff --git a/intern/ghost/make/msvc/ghost.dsp b/intern/ghost/make/msvc/ghost.dsp new file mode 100644 index 00000000000..fd287488b56 --- /dev/null +++ b/intern/ghost/make/msvc/ghost.dsp @@ -0,0 +1,292 @@ +# Microsoft Developer Studio Project File - Name="ghost" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=ghost - 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 "ghost.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 "ghost.mak" CFG="ghost - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ghost - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "ghost - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ghost - 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 "..\..\..\..\obj\windows\intern\ghost" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\ghost" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../.." /I "../../../../../lib/windows/string/include" /I "..\..\..\..\intern\string" /I "../../../../../lib/windows/wintab/include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# 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:"..\..\..\..\obj\windows\intern\ghost\libghost.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Desc=Copying GHOST files library (release target) to lib tree. +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\ghost\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\ghost\*.lib ..\..\..\..\..\lib\windows\ghost\lib\*.a ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "ghost - 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 "..\..\..\..\obj\windows\intern\ghost\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\ghost\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "../.." /I "../../../../../lib/windows/string/include" /I "..\..\..\..\intern\string" /I "../../../../../lib/windows/wintab/include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c +# 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:"..\..\..\..\obj\windows\intern\ghost\debug\libghost.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Desc=Copying GHOST files library (debug target) to lib tree. +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\ghost\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\ghost\debug\*.lib ..\..\..\..\..\lib\windows\ghost\lib\debug\*.a ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "ghost - Win32 Release" +# Name "ghost - Win32 Debug" +# Begin Group "Header Files" + +# PROP Default_Filter "" +# Begin Group "intern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\intern\GHOST_Buttons.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_CallbackEventConsumer.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_Debug.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_DisplayManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_DisplayManagerWin32.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_Event.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_EventButton.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_EventCursor.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_EventKey.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_EventManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_EventPrinter.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_EventWheel.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_EventWindow.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_ModifierKeys.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_System.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_SystemWin32.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_TimerManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_TimerTask.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_Window.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_WindowManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_WindowWin32.h +# End Source File +# End Group +# Begin Group "extern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE="..\..\GHOST_C-api.h" +# End Source File +# Begin Source File + +SOURCE=..\..\GHOST_IEvent.h +# End Source File +# Begin Source File + +SOURCE=..\..\GHOST_IEventConsumer.h +# End Source File +# Begin Source File + +SOURCE=..\..\GHOST_ISystem.h +# End Source File +# Begin Source File + +SOURCE=..\..\GHOST_ITimerTask.h +# End Source File +# Begin Source File + +SOURCE=..\..\GHOST_IWindow.h +# End Source File +# Begin Source File + +SOURCE=..\..\GHOST_Rect.h +# End Source File +# Begin Source File + +SOURCE=..\..\GHOST_Types.h +# End Source File +# End Group +# End Group +# Begin Group "Source Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\intern\GHOST_Buttons.cpp +# End Source File +# Begin Source File + +SOURCE="..\..\intern\GHOST_C-api.cpp" +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_CallbackEventConsumer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_DisplayManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_DisplayManagerWin32.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_EventManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_EventPrinter.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_ISystem.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_ModifierKeys.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_Rect.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_System.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_SystemWin32.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_TimerManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_Window.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_WindowManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_WindowWin32.cpp +# End Source File +# End Group +# End Target +# End Project diff --git a/intern/ghost/make/msvc/ghost.dsw b/intern/ghost/make/msvc/ghost.dsw new file mode 100644 index 00000000000..807a6ec3157 --- /dev/null +++ b/intern/ghost/make/msvc/ghost.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "ghost"=".\ghost.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/ghost/make/msvc_7_0/ghost.sln b/intern/ghost/make/msvc_7_0/ghost.sln new file mode 100644 index 00000000000..a2073664ca5 --- /dev/null +++ b/intern/ghost/make/msvc_7_0/ghost.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ghost", "ghost.vcproj", "{37364341-0C53-433A-B4CC-CDDD176CABC5}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {37364341-0C53-433A-B4CC-CDDD176CABC5}.Debug.ActiveCfg = Debug|Win32 + {37364341-0C53-433A-B4CC-CDDD176CABC5}.Debug.Build.0 = Debug|Win32 + {37364341-0C53-433A-B4CC-CDDD176CABC5}.Release.ActiveCfg = Release|Win32 + {37364341-0C53-433A-B4CC-CDDD176CABC5}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/intern/ghost/make/msvc_7_0/ghost.vcproj b/intern/ghost/make/msvc_7_0/ghost.vcproj new file mode 100644 index 00000000000..9d0aef451e7 --- /dev/null +++ b/intern/ghost/make/msvc_7_0/ghost.vcproj @@ -0,0 +1,401 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/ghost/test/Makefile b/intern/ghost/test/Makefile new file mode 100644 index 00000000000..ded21c32cc6 --- /dev/null +++ b/intern/ghost/test/Makefile @@ -0,0 +1,86 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# GHOST test applications makefile. +# This bounces to test application directories. +# + +LIBNAME = ghost +SOURCEDIR = intern/$(LIBNAME)/test +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = gears multitest + +include nan_subdirs.mk + +include nan_compile.mk +include nan_link.mk + +OCGGHOST = $(OCGDIR)/intern/$(LIBNAME) +GEARDIR = $(OCGGHOST)/test/$(DEBUG_DIR)gears.app + +LIBS = $(OCGGHOST)/$(DEBUG_DIR)libghost.a +SLIBS += $(LCGDIR)/string/lib/libstring.a + +all debug:: $(LIBS) + @echo "****> linking $@ in $(SOURCEDIR)" +ifeq ($(OS),darwin) + $(CCC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)gears $(DIR)/$(DEBUG_DIR)GHOST_Test.o $(LIBS) $(SLIBS) $(LLIBS) $(DADD) $(LOPTS) + @# set up directory structure for the OSX application bundle + @[ -d $(OCGGHOST)/test/ ] || mkdir $(OCGGHOST)/test/ + @[ -d $(OCGGHOST)/test/debug ] || mkdir $(OCGGHOST)/test/debug + @[ -d $(GEARDIR) ] || mkdir $(GEARDIR) + @[ -d $(GEARDIR)/Contents ] || mkdir $(GEARDIR)/Contents + @[ -d $(GEARDIR)/Contents/MacOS ] || mkdir $(GEARDIR)/Contents/MacOS + @[ -d $(GEARDIR)/Contents/Resources ] || mkdir $(GEARDIR)/Contents/Resources + @[ -d $(GEARDIR)/Contents/Resources/English.lproj ] || mkdir $(GEARDIR)/Contents/Resources/English.lproj + @[ -d $(GEARDIR)/Contents/Resources/English.lproj/MainMenu.nib ] || mkdir $(GEARDIR)/Contents/Resources/English.lproj/MainMenu.nib + @# copy the files into the bundle directory tree + cp -f $(DIR)/$(DEBUG_DIR)gears $(GEARDIR)/Contents/MacOS + cp -f gears/resources/osx/PkgInfo $(GEARDIR)/Contents/ + cp -f gears/resources/osx/Info.plist $(GEARDIR)/Contents/ + cp -f gears/resources/osx/English.lproj/InfoPlist.strings $(GEARDIR)/Contents/Resources/English.lproj + cp -f gears/resources/osx/English.lproj/MainMenu.nib/classes.nib $(GEARDIR)/Contents/Resources/English.lproj + cp -f gears/resources/osx/English.lproj/MainMenu.nib/info.nib $(GEARDIR)/Contents/Resources/English.lproj + cp -f gears/resources/osx/English.lproj/MainMenu.nib/objects.nib $(GEARDIR)/Contents/Resources/English.lproj +else + $(CCC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)gears_cpp $(DIR)/$(DEBUG_DIR)GHOST_Test.o $(LIBS) $(SLIBS) $(LLIBS) $(DADD) $(LOPTS) + $(CCC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)gears_c $(DIR)/$(DEBUG_DIR)GHOST_C-Test.o $(LIBS) $(SLIBS) $(LLIBS) $(DADD) $(LOPTS) +endif + +clean:: + @# mac stuff. well ok, only the binary + @rm -f $(DIR)/gears $(DIR)/debug/gears + @# others + @rm -f $(DIR)/gears_c $(DIR)/debug/gears_c + @rm -f $(DIR)/gears_cpp $(DIR)/debug/gears_cpp + +test:: all + $(DIR)/gears_cpp + $(DIR)/gears_c diff --git a/intern/ghost/test/gears/GHOST_C-Test.c b/intern/ghost/test/gears/GHOST_C-Test.c new file mode 100644 index 00000000000..9fd4e155b3b --- /dev/null +++ b/intern/ghost/test/gears/GHOST_C-Test.c @@ -0,0 +1,564 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * + * Simple test file for the GHOST library. + * The OpenGL gear code is taken from the Qt sample code which, + * in turn, is probably taken from somewhere as well. + * @author Maarten Gribnau + * @date May 31, 2001 + */ + +#include +#include +#include +#include + +#define FALSE 0 + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_C-api.h" + +#if defined(WIN32) || defined(__APPLE__) + #ifdef WIN32 + #include + #include + #else /* WIN32 */ + /* __APPLE__ is defined */ + #include + #endif /* WIN32 */ +#else /* defined(WIN32) || defined(__APPLE__) */ + #include +#endif /* defined(WIN32) || defined(__APPLE__) */ + + +static void gearsTimerProc(GHOST_TimerTaskHandle task, GHOST_TUns64 time); +int processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData); + +static GLfloat view_rotx=20.0, view_roty=30.0, view_rotz=0.0; +static GLfloat fAngle = 0.0; +static int sExitRequested = 0; +static GHOST_SystemHandle shSystem = NULL; +static GHOST_WindowHandle sMainWindow = NULL; +static GHOST_WindowHandle sSecondaryWindow = NULL; +static GHOST_TStandardCursor sCursor = GHOST_kStandardCursorFirstCursor; +static GHOST_WindowHandle sFullScreenWindow = NULL; +static GHOST_TimerTaskHandle sTestTimer; +static GHOST_TimerTaskHandle sGearsTimer; + +static void testTimerProc(GHOST_TimerTaskHandle task, GHOST_TUns64 time) +{ + printf("timer1, time=%d\n", (int)time); +} + + +static void gearGL(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GLint teeth, GLfloat tooth_depth) +{ + GLint i; + GLfloat r0, r1, r2; + GLfloat angle, da; + GLfloat u, v, len; + const double pi = 3.14159264; + + r0 = inner_radius; + r1 = (float)(outer_radius - tooth_depth/2.0); + r2 = (float)(outer_radius + tooth_depth/2.0); + + da = (float)(2.0*pi / teeth / 4.0); + + glShadeModel(GL_FLAT); + glNormal3f(0.0, 0.0, 1.0); + + /* draw front face */ + glBegin(GL_QUAD_STRIP); + for (i=0;i<=teeth;i++) { + angle = (float)(i * 2.0*pi / teeth); + glVertex3f((float)(r0*cos(angle)), (float)(r0*sin(angle)), (float)(width*0.5)); + glVertex3f((float)(r1*cos(angle)), (float)(r1*sin(angle)), (float)(width*0.5)); + glVertex3f((float)(r0*cos(angle)), (float)(r0*sin(angle)), (float)(width*0.5)); + glVertex3f((float)(r1*cos(angle+3*da)), (float)(r1*sin(angle+3*da)), (float)(width*0.5)); + } + glEnd(); + + /* draw front sides of teeth */ + glBegin(GL_QUADS); + da = (float)(2.0*pi / teeth / 4.0); + for (i=0;iz > 0) + { + view_rotz += 5.f; + } + else + { + view_rotz -= 5.f; + } + } + break; + + case GHOST_kEventKeyUp: + break; + + case GHOST_kEventKeyDown: + { + keyData = (GHOST_TEventKeyData*)GHOST_GetEventData(hEvent); + switch (keyData->key) + { + case GHOST_kKeyC: + { + cursor = sCursor; + cursor++; + if (cursor >= GHOST_kStandardCursorNumCursors) + { + cursor = GHOST_kStandardCursorFirstCursor; + } + sCursor = (GHOST_TStandardCursor)cursor; + GHOST_SetCursorShape(window, sCursor); + } + break; + case GHOST_kKeyF: + if (!GHOST_GetFullScreen(shSystem)) + { + /* Begin fullscreen mode */ + setting.bpp = 24; + setting.frequency = 85; + setting.xPixels = 640; + setting.yPixels = 480; + + /* + setting.bpp = 16; + setting.frequency = 75; + setting.xPixels = 640; + setting.yPixels = 480; + */ + + sFullScreenWindow = GHOST_BeginFullScreen(shSystem, &setting, + + FALSE /* stereo flag */); + } + else + { + GHOST_EndFullScreen(shSystem); + sFullScreenWindow = 0; + } + break; + case GHOST_kKeyH: + { + visibility = GHOST_GetCursorVisibility(window); + GHOST_SetCursorVisibility(window, !visibility); + } + break; + case GHOST_kKeyQ: + if (GHOST_GetFullScreen(shSystem)) + { + GHOST_EndFullScreen(shSystem); + sFullScreenWindow = 0; + } + sExitRequested = 1; + case GHOST_kKeyT: + if (!sTestTimer) + { + sTestTimer = GHOST_InstallTimer(shSystem, 0, 1000, testTimerProc, NULL); + } + else + { + GHOST_RemoveTimer(shSystem, sTestTimer); + sTestTimer = 0; + } + break; + case GHOST_kKeyW: + { + if (sMainWindow) + { + char *title = GHOST_GetTitle(sMainWindow); + char *ntitle = malloc(strlen(title)+2); + + sprintf(ntitle, "%s-", title); + GHOST_SetTitle(sMainWindow, ntitle); + + free(ntitle); + free(title); + } + } + break; + default: + break; + } + } + break; + + case GHOST_kEventWindowClose: + { + GHOST_WindowHandle window2 = GHOST_GetEventWindow(hEvent); + if (window2 == sMainWindow) + { + sExitRequested = 1; + } + else + { + if (sGearsTimer) + { + GHOST_RemoveTimer(shSystem, sGearsTimer); + sGearsTimer = 0; + } + GHOST_DisposeWindow(shSystem, window2); + } + } + break; + + case GHOST_kEventWindowActivate: + handled = 0; + break; + case GHOST_kEventWindowDeactivate: + handled = 0; + break; + case GHOST_kEventWindowUpdate: + { + GHOST_WindowHandle window2 = GHOST_GetEventWindow(hEvent); + if (!GHOST_ValidWindow(shSystem, window2)) + break; + setViewPortGL(window2); + drawGL(); + GHOST_SwapWindowBuffers(window2); + } + break; + + default: + handled = 0; + break; + } + return handled; +} + + +int main(int argc, char** argv) +{ + char* title1 = "gears - main window"; + char* title2 = "gears - secondary window"; + GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(processEvent, NULL); + + /* Create the system */ + shSystem = GHOST_CreateSystem(); + GHOST_AddEventConsumer(shSystem, consumer); + + if (shSystem) + { + /* Create the main window */ + sMainWindow = GHOST_CreateWindow(shSystem, + title1, + 10, + 64, + 320, + 200, + GHOST_kWindowStateNormal, + GHOST_kDrawingContextTypeOpenGL, + FALSE); + if (!sMainWindow) + { + printf("could not create main window\n"); + exit(-1); + } + + /* Create a secondary window */ + sSecondaryWindow = GHOST_CreateWindow(shSystem, + title2, + 340, + 64, + 320, + 200, + GHOST_kWindowStateNormal, + GHOST_kDrawingContextTypeOpenGL, + FALSE); + if (!sSecondaryWindow) + { + printf("could not create secondary window\n"); + exit(-1); + } + + /* Install a timer to have the gears running */ + sGearsTimer = GHOST_InstallTimer(shSystem, + 0, + 10, + gearsTimerProc, + sMainWindow); + + /* Enter main loop */ + while (!sExitRequested) + { + if (!GHOST_ProcessEvents(shSystem, 0)) + { +#ifdef WIN32 + /* If there were no events, be nice to other applications */ + Sleep(10); +#endif + } + GHOST_DispatchEvents(shSystem); + } + } + + /* Dispose windows */ + if (GHOST_ValidWindow(shSystem, sMainWindow)) + { + GHOST_DisposeWindow(shSystem, sMainWindow); + } + if (GHOST_ValidWindow(shSystem, sSecondaryWindow)) + { + GHOST_DisposeWindow(shSystem, sSecondaryWindow); + } + + /* Dispose the system */ + GHOST_DisposeSystem(shSystem); + GHOST_DisposeEventConsumer(consumer); + + return 0; +} + + +static void gearsTimerProc(GHOST_TimerTaskHandle hTask, GHOST_TUns64 time) +{ + GHOST_WindowHandle hWindow = NULL; + fAngle += 2.0; + view_roty += 1.0; + hWindow = (GHOST_WindowHandle)GHOST_GetTimerTaskUserData(hTask); + if (GHOST_GetFullScreen(shSystem)) + { + /* Running full screen */ + GHOST_InvalidateWindow(sFullScreenWindow); + } + else + { + if (GHOST_ValidWindow(shSystem, hWindow)) + { + GHOST_InvalidateWindow(hWindow); + } + } +} diff --git a/intern/ghost/test/gears/GHOST_Test.cpp b/intern/ghost/test/gears/GHOST_Test.cpp new file mode 100644 index 00000000000..3abdd3977eb --- /dev/null +++ b/intern/ghost/test/gears/GHOST_Test.cpp @@ -0,0 +1,761 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * Simple test file for the GHOST library. + * The OpenGL gear code is taken from the Qt sample code which, + * in turn, is probably taken from somewhere as well. + * @author Maarten Gribnau + * @date May 31, 2001 + * Stereo code by Raymond de Vries, januari 2002 + */ + +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(WIN32) || defined(__APPLE__) + #ifdef WIN32 + #include + #include + + #include + #else // WIN32 + // __APPLE__ is defined + #include + #endif // WIN32 +#else // defined(WIN32) || defined(__APPLE__) + #include +#endif // defined(WIN32) || defined(__APPLE__) + +#include "STR_String.h" +#include "GHOST_Rect.h" + +#include "GHOST_ISystem.h" +#include "GHOST_IEvent.h" +#include "GHOST_IEventConsumer.h" + + +#define LEFT_EYE 0 +#define RIGHT_EYE 1 + +static bool nVidiaWindows; // very dirty but hey, it's for testing only + +static void gearsTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 time); + +static class Application* fApp; +static GLfloat view_rotx=20.0, view_roty=30.0, view_rotz=0.0; +static GLfloat fAngle = 0.0; +static GHOST_ISystem* fSystem = 0; + + +void StereoProjection(float left, float right, float bottom, float top, float nearplane, float farplane, + float zero_plane, float dist, + float eye); + + +static void testTimerProc(GHOST_ITimerTask* /*task*/, GHOST_TUns64 time) +{ + std::cout << "timer1, time=" << (int)time << "\n"; +} + + +static void gearGL(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GLint teeth, GLfloat tooth_depth) +{ + GLint i; + GLfloat r0, r1, r2; + GLfloat angle, da; + GLfloat u, v, len; + + r0 = inner_radius; + r1 = outer_radius - tooth_depth/2.0; + r2 = outer_radius + tooth_depth/2.0; + + const double pi = 3.14159264; + da = 2.0*pi / teeth / 4.0; + + glShadeModel(GL_FLAT); + glNormal3f(0.0, 0.0, 1.0); + + /* draw front face */ + glBegin(GL_QUAD_STRIP); + for (i=0;i<=teeth;i++) { + angle = i * 2.0*pi / teeth; + glVertex3f(r0*cos(angle), r0*sin(angle), width*0.5); + glVertex3f(r1*cos(angle), r1*sin(angle), width*0.5); + glVertex3f(r0*cos(angle), r0*sin(angle), width*0.5); + glVertex3f(r1*cos(angle+3*da), r1*sin(angle+3*da), width*0.5); + } + glEnd(); + + /* draw front sides of teeth */ + glBegin(GL_QUADS); + da = 2.0*pi / teeth / 4.0; + for (i=0;iactivateDrawingContext(); + GHOST_Rect bnds; + int noOfScanlines = 0, lowerScanline = 0; + int verticalBlankingInterval = 32; // hard coded for testing purposes, display device dependant + float left, right, bottom, top; + float nearplane, farplane, zeroPlane, distance; + float eyeSeparation = 0.62f; + window->getClientBounds(bnds); + + // viewport + if(stereo) + { + if(nVidiaWindows) + { + // handled by nVidia driver so act as normal (explicitly put here since + // it -is- stereo) + glViewport(0, 0, bnds.getWidth(), bnds.getHeight()); + } + else + { // generic cross platform above-below stereo + noOfScanlines = (bnds.getHeight() - verticalBlankingInterval) / 2; + switch(eye) + { + case LEFT_EYE: + // upper half of window + lowerScanline = bnds.getHeight() - noOfScanlines; + break; + case RIGHT_EYE: + // lower half of window + lowerScanline = 0; + break; + } + } + } + else + { + noOfScanlines = bnds.getHeight(); + lowerScanline = 0; + } + + glViewport(0, lowerScanline, bnds.getWidth(), noOfScanlines); + + // projection + left = -6.0; + right = 6.0; + bottom = -4.8f; + top = 4.8f; + nearplane = 5.0; + farplane = 60.0; + + if(stereo) + { + zeroPlane = 0.0; + distance = 14.5; + switch(eye) + { + case LEFT_EYE: + StereoProjection(left, right, bottom, top, nearplane, farplane, zeroPlane, distance, -eyeSeparation / 2.0); + break; + case RIGHT_EYE: + StereoProjection(left, right, bottom, top, nearplane, farplane, zeroPlane, distance, eyeSeparation / 2.0); + break; + } + } + else + { +// left = -w; +// right = w; +// bottom = -h; +// top = h; + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(left, right, bottom, top, 5.0, 60.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0.0, 0.0, -40.0); + + } + + glClearColor(.2f,0.0f,0.0f,0.0f); +} + + +void StereoProjection(float left, float right, float bottom, float top, float nearplane, float farplane, + float zero_plane, float dist, + float eye) +/* Perform the perspective projection for one eye's subfield. +The projection is in the direction of the negative z axis. + +-6.0, 6.0, -4.8, 4.8, +left, right, bottom, top = the coordinate range, in the plane of zero +parallax setting, which will be displayed on the screen. The +ratio between (right-left) and (top-bottom) should equal the aspect +ratio of the display. + +6.0, -6.0, +near, far = the z-coordinate values of the clipping planes. + +0.0, +zero_plane = the z-coordinate of the plane of zero parallax setting. + +14.5, +dist = the distance from the center of projection to the plane +of zero parallax. + +-0.31 +eye = half the eye separation; positive for the right eye subfield, +negative for the left eye subfield. +*/ +{ + float xmid, ymid, clip_near, clip_far, topw, bottomw, leftw, rightw, + dx, dy, n_over_d; + + dx = right - left; + dy = top - bottom; + + xmid = (right + left) / 2.0; + ymid = (top + bottom) / 2.0; + + clip_near = dist + zero_plane - nearplane; + clip_far = dist + zero_plane - farplane; + + n_over_d = clip_near / dist; + + topw = n_over_d * dy / 2.0; + bottomw = -topw; + rightw = n_over_d * (dx / 2.0 - eye); + leftw = n_over_d *(-dx / 2.0 - eye); + + /* Need to be in projection mode for this. */ + glLoadIdentity(); + glFrustum(leftw, rightw, bottomw, topw, clip_near, clip_far); + + glTranslatef(-xmid - eye, -ymid, -zero_plane - dist); + return; +} /* stereoproj */ + + +class Application : public GHOST_IEventConsumer { +public: + Application(GHOST_ISystem* system); + ~Application(void); + virtual bool processEvent(GHOST_IEvent* event); + + GHOST_ISystem* m_system; + GHOST_IWindow* m_mainWindow; + GHOST_IWindow* m_secondaryWindow; + GHOST_IWindow* m_fullScreenWindow; + GHOST_ITimerTask* m_gearsTimer, *m_testTimer; + GHOST_TStandardCursor m_cursor; + bool m_exitRequested; + + bool stereo; +}; + + +Application::Application(GHOST_ISystem* system) + : m_system(system), m_mainWindow(0), m_secondaryWindow(0), m_fullScreenWindow(0), + m_gearsTimer(0), m_testTimer(0), m_cursor(GHOST_kStandardCursorFirstCursor), + m_exitRequested(false), stereo(false) +{ + fApp = this; + + // Create the main window + STR_String title1 ("gears - main window"); + m_mainWindow = system->createWindow(title1, 10, 64, 320, 200, GHOST_kWindowStateNormal, + GHOST_kDrawingContextTypeOpenGL, true /* stereo flag */); + + if (!m_mainWindow) { + std::cout << "could not create main window\n"; + exit(-1); + } + + // Create a secondary window + STR_String title2 ("gears - secondary window"); + m_secondaryWindow = system->createWindow(title2, 340, 64, 320, 200, GHOST_kWindowStateNormal, + GHOST_kDrawingContextTypeOpenGL, false /* stereo flag */); + if (!m_secondaryWindow) { + cout << "could not create secondary window\n"; + exit(-1); + } + + // Install a timer to have the gears running + m_gearsTimer = system->installTimer(0 /*delay*/, 20/*interval*/, gearsTimerProc, m_mainWindow); +} + + +Application::~Application(void) +{ + // Dispose windows + if (m_system->validWindow(m_mainWindow)) { + m_system->disposeWindow(m_mainWindow); + } + if (m_system->validWindow(m_secondaryWindow)) { + m_system->disposeWindow(m_secondaryWindow); + } +} + + +bool Application::processEvent(GHOST_IEvent* event) +{ + GHOST_IWindow* window = event->getWindow(); + bool handled = true; + + switch (event->getType()) { +/* case GHOST_kEventUnknown: + break; + case GHOST_kEventCursorButton: + std::cout << "GHOST_kEventCursorButton"; break; + case GHOST_kEventCursorMove: + std::cout << "GHOST_kEventCursorMove"; break; +*/ + case GHOST_kEventWheel: + { + GHOST_TEventWheelData* wheelData = (GHOST_TEventWheelData*) event->getData(); + if (wheelData->z > 0) + { + view_rotz += 5.f; + } + else + { + view_rotz -= 5.f; + } + } + break; + + case GHOST_kEventKeyUp: + break; + + case GHOST_kEventKeyDown: + { + GHOST_TEventKeyData* keyData = (GHOST_TEventKeyData*) event->getData(); + switch (keyData->key) { + case GHOST_kKeyC: + { + int cursor = m_cursor; + cursor++; + if (cursor >= GHOST_kStandardCursorNumCursors) { + cursor = GHOST_kStandardCursorFirstCursor; + } + m_cursor = (GHOST_TStandardCursor)cursor; + window->setCursorShape(m_cursor); + } + break; + + case GHOST_kKeyE: + { + int x = 200, y= 200; + m_system->setCursorPosition(x,y); + break; + } + + case GHOST_kKeyF: + if (!m_system->getFullScreen()) { + // Begin fullscreen mode + GHOST_DisplaySetting setting; + + setting.bpp = 16; + setting.frequency = 50; + setting.xPixels = 640; + setting.yPixels = 480; + m_system->beginFullScreen(setting, &m_fullScreenWindow, false /* stereo flag */); + } + else { + m_system->endFullScreen(); + m_fullScreenWindow = 0; + } + break; + + case GHOST_kKeyH: + window->setCursorVisibility(!window->getCursorVisibility()); + break; + + case GHOST_kKeyM: + { + bool down = false; + m_system->getModifierKeyState(GHOST_kModifierKeyLeftShift,down); + if (down) { + std::cout << "left shift down\n"; + } + m_system->getModifierKeyState(GHOST_kModifierKeyRightShift,down); + if (down) { + std::cout << "right shift down\n"; } + m_system->getModifierKeyState(GHOST_kModifierKeyLeftAlt,down); + if (down) { + std::cout << "left Alt down\n"; + } + m_system->getModifierKeyState(GHOST_kModifierKeyRightAlt,down); + if (down) { + std::cout << "right Alt down\n"; + } + m_system->getModifierKeyState(GHOST_kModifierKeyLeftControl,down); + if (down) { + std::cout << "left control down\n"; + } + m_system->getModifierKeyState(GHOST_kModifierKeyRightControl,down); + if (down) { + std::cout << "right control down\n"; + } + } + break; + + case GHOST_kKeyQ: + if (m_system->getFullScreen()) + { + m_system->endFullScreen(); + m_fullScreenWindow = 0; + } + m_exitRequested = true; + break; + + case GHOST_kKeyS: // toggle mono and stereo + if(stereo) + stereo = false; + else + stereo = true; + break; + + case GHOST_kKeyT: + if (!m_testTimer) { + m_testTimer = m_system->installTimer(0, 1000, testTimerProc); + } + + else { + m_system->removeTimer(m_testTimer); + m_testTimer = 0; + } + + break; + + case GHOST_kKeyW: + if (m_mainWindow) + { + STR_String title; + m_mainWindow->getTitle(title); + title += "-"; + m_mainWindow->setTitle(title); + + } + break; + + default: + break; + } + } + break; + + case GHOST_kEventWindowClose: + { + GHOST_IWindow* window2 = event->getWindow(); + if (window2 == m_mainWindow) { + m_exitRequested = true; + } + else { + m_system->disposeWindow(window2); + } + } + break; + + case GHOST_kEventWindowActivate: + handled = false; + break; + + case GHOST_kEventWindowDeactivate: + handled = false; + break; + + case GHOST_kEventWindowUpdate: + { + GHOST_IWindow* window2 = event->getWindow(); + if(!m_system->validWindow(window2)) + break; + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + if(stereo) + { + View(window2, stereo, LEFT_EYE); + glPushMatrix(); + RenderCamera(); + RenderScene(); + glPopMatrix(); + + View(window2, stereo, RIGHT_EYE); + glPushMatrix(); + RenderCamera(); + RenderScene(); + glPopMatrix(); + } + else + { + View(window2, stereo); + glPushMatrix(); + RenderCamera(); + RenderScene(); + glPopMatrix(); + } + window2->swapBuffers(); + } + break; + + default: + handled = false; + break; + } + return handled; +} + + +int main(int /*argc*/, char** /*argv*/) +{ + nVidiaWindows = false; +// nVidiaWindows = true; + +#ifdef WIN32 + /* Set a couple of settings in the registry for the nVidia detonator driver. + * So this is very specific... + */ + if(nVidiaWindows) + { + LONG lresult; + HKEY hkey = 0; + DWORD dwd = 0; + //unsigned char buffer[128]; + + CRegKey regkey; + //DWORD keyValue; +// lresult = regkey.Open(HKEY_LOCAL_MACHINE, "SOFTWARE\\NVIDIA Corporation\\Global\\Stereo3D\\StereoEnable"); + lresult = regkey.Open(HKEY_LOCAL_MACHINE, "SOFTWARE\\NVIDIA Corporation\\Global\\Stereo3D\\StereoEnable", + KEY_ALL_ACCESS ); + + if(lresult == ERROR_SUCCESS) + printf("Succesfully opened key\n"); +#if 0 + lresult = regkey.QueryValue(&keyValue, "StereoEnable"); + if(lresult == ERROR_SUCCESS) + printf("Succesfully queried key\n"); +#endif + lresult = regkey.SetValue(HKEY_LOCAL_MACHINE, "SOFTWARE\\NVIDIA Corporation\\Global\\Stereo3D\\StereoEnable", + "1"); + if(lresult == ERROR_SUCCESS) + printf("Succesfully set value for key\n"); + regkey.Close(); + if(lresult == ERROR_SUCCESS) + printf("Succesfully closed key\n"); +// regkey.Write("2"); + } +#endif // WIN32 + + // Create the system + GHOST_ISystem::createSystem(); + fSystem = GHOST_ISystem::getSystem(); + + if (fSystem) { + // Create an application object + Application app (fSystem); + + // Add the application as event consumer + fSystem->addEventConsumer(&app); + + // Enter main loop + while (!app.m_exitRequested) { + //printf("main: loop\n"); + fSystem->processEvents(true); + fSystem->dispatchEvents(); + } + } + + // Dispose the system + GHOST_ISystem::disposeSystem(); + + return 0; +} + + +static void gearsTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 /*time*/) +{ + fAngle += 2.0; + view_roty += 1.0; + GHOST_IWindow* window = (GHOST_IWindow*)task->getUserData(); + if (fApp->m_fullScreenWindow) { + // Running full screen + fApp->m_fullScreenWindow->invalidate(); + } + else { + if (fSystem->validWindow(window)) { + window->invalidate(); + } + } +} diff --git a/intern/ghost/test/gears/Makefile b/intern/ghost/test/gears/Makefile new file mode 100644 index 00000000000..b7966b4d157 --- /dev/null +++ b/intern/ghost/test/gears/Makefile @@ -0,0 +1,48 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# GHOST gears test application Makefile +# + +LIBNAME = gearstest +DIR = $(OCGDIR)/intern/ghost/test + +# we don't want a library here, only object files: +ALLTARGETS = $(OBJS) + +include nan_compile.mk + +CFLAGS += $(LEVEL_2_C_WARNINGS) +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I$(OPENGL_HEADERS) +CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I../.. + diff --git a/intern/ghost/test/make/msvc_6_0/gears.dsp b/intern/ghost/test/make/msvc_6_0/gears.dsp new file mode 100644 index 00000000000..3e809a6b604 --- /dev/null +++ b/intern/ghost/test/make/msvc_6_0/gears.dsp @@ -0,0 +1,102 @@ +# Microsoft Developer Studio Project File - Name="gears" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=gears - Win32 Release +!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 "gears.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 "gears.mak" CFG="gears - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gears - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "gears - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gears - 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 "../../../../../../obj/windows/intern/ghost/test/" +# PROP Intermediate_Dir "../../../../../../obj/windows/intern/ghost/test/" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../.." /I "../../../../string" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 glu32.lib opengl32.lib user32.lib gdi32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "gears - 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 "../../../../../../obj/windows/intern/ghost/test/debug" +# PROP Intermediate_Dir "../../../../../../obj/windows/intern/ghost/test/debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "../../.." /I "../../../../string" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 glu32.lib opengl32.lib user32.lib gdi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "gears - Win32 Release" +# Name "gears - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\gears\GHOST_Test.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/intern/ghost/test/make/msvc_6_0/gears_C.dsp b/intern/ghost/test/make/msvc_6_0/gears_C.dsp new file mode 100644 index 00000000000..5972d123268 --- /dev/null +++ b/intern/ghost/test/make/msvc_6_0/gears_C.dsp @@ -0,0 +1,102 @@ +# Microsoft Developer Studio Project File - Name="gears_C" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=gears_C - Win32 Release +!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 "gears_C.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 "gears_C.mak" CFG="gears_C - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gears_C - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "gears_C - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gears_C - 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 "../../../../../../obj/windows/intern/ghost/test/" +# PROP Intermediate_Dir "../../../../../../obj/windows/intern/ghost/test/" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../.." /I "../../../../string" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 glu32.lib opengl32.lib user32.lib gdi32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "gears_C - 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 "../../../../../../obj/windows/intern/ghost/test/debug" +# PROP Intermediate_Dir "../../../../../../obj/windows/intern/ghost/test/debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "../../.." /I "../../../../string" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 glu32.lib opengl32.lib user32.lib gdi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "gears_C - Win32 Release" +# Name "gears_C - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE="..\..\gears\GHOST_C-Test.c" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/intern/ghost/test/make/msvc_6_0/ghost_test.dsw b/intern/ghost/test/make/msvc_6_0/ghost_test.dsw new file mode 100644 index 00000000000..03bf5eb5c9a --- /dev/null +++ b/intern/ghost/test/make/msvc_6_0/ghost_test.dsw @@ -0,0 +1,77 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "gears"=.\gears.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name ghost + End Project Dependency + Begin Project Dependency + Project_Dep_Name string + End Project Dependency +}}} + +############################################################################### + +Project: "gears_C"=.\gears_C.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name ghost + End Project Dependency + Begin Project Dependency + Project_Dep_Name string + End Project Dependency +}}} + +############################################################################### + +Project: "ghost"=..\..\..\make\msvc\ghost.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "string"=..\..\..\..\string\make\msvc_6_0\string.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/ghost/test/multitest/Basic.c b/intern/ghost/test/multitest/Basic.c new file mode 100644 index 00000000000..db2ad9428b2 --- /dev/null +++ b/intern/ghost/test/multitest/Basic.c @@ -0,0 +1,71 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "Basic.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +int min_i(int a, int b) { + return (a + +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_guardedalloc.h" + +#include "GHOST_C-api.h" +#include "EventToBuf.h" + +char *eventtype_to_string(GHOST_TEventType type) { + switch(type) { + case GHOST_kEventCursorMove: return "CursorMove"; + case GHOST_kEventButtonDown: return "ButtonDown"; + case GHOST_kEventButtonUp: return "ButtonUp"; + + case GHOST_kEventKeyDown: return "KeyDown"; + case GHOST_kEventKeyUp: return "KeyUp"; + + case GHOST_kEventQuit: return "Quit"; + + case GHOST_kEventWindowClose: return "WindowClose"; + case GHOST_kEventWindowActivate: return "WindowActivate"; + case GHOST_kEventWindowDeactivate: return "WindowDeactivate"; + case GHOST_kEventWindowUpdate: return "WindowUpdate"; + case GHOST_kEventWindowSize: return "WindowSize"; + default: + return ""; + } +} + +static char *keytype_to_string(GHOST_TKey key) { +#define K(key) case GHOST_k##key: return #key; + switch (key) { + K(KeyBackSpace); + K(KeyTab); + K(KeyLinefeed); + K(KeyClear); + K(KeyEnter); + + K(KeyEsc); + K(KeySpace); + K(KeyQuote); + K(KeyComma); + K(KeyMinus); + K(KeyPeriod); + K(KeySlash); + + K(Key0); + K(Key1); + K(Key2); + K(Key3); + K(Key4); + K(Key5); + K(Key6); + K(Key7); + K(Key8); + K(Key9); + + K(KeySemicolon); + K(KeyEqual); + + K(KeyA); + K(KeyB); + K(KeyC); + K(KeyD); + K(KeyE); + K(KeyF); + K(KeyG); + K(KeyH); + K(KeyI); + K(KeyJ); + K(KeyK); + K(KeyL); + K(KeyM); + K(KeyN); + K(KeyO); + K(KeyP); + K(KeyQ); + K(KeyR); + K(KeyS); + K(KeyT); + K(KeyU); + K(KeyV); + K(KeyW); + K(KeyX); + K(KeyY); + K(KeyZ); + + K(KeyLeftBracket); + K(KeyRightBracket); + K(KeyBackslash); + K(KeyAccentGrave); + + K(KeyLeftShift); + K(KeyRightShift); + K(KeyLeftControl); + K(KeyRightControl); + K(KeyLeftAlt); + K(KeyRightAlt); + K(KeyCommand); + + K(KeyCapsLock); + K(KeyNumLock); + K(KeyScrollLock); + + K(KeyLeftArrow); + K(KeyRightArrow); + K(KeyUpArrow); + K(KeyDownArrow); + + K(KeyPrintScreen); + K(KeyPause); + + K(KeyInsert); + K(KeyDelete); + K(KeyHome); + K(KeyEnd); + K(KeyUpPage); + K(KeyDownPage); + + K(KeyNumpad0); + K(KeyNumpad1); + K(KeyNumpad2); + K(KeyNumpad3); + K(KeyNumpad4); + K(KeyNumpad5); + K(KeyNumpad6); + K(KeyNumpad7); + K(KeyNumpad8); + K(KeyNumpad9); + K(KeyNumpadPeriod); + K(KeyNumpadEnter); + K(KeyNumpadPlus); + K(KeyNumpadMinus); + K(KeyNumpadAsterisk); + K(KeyNumpadSlash); + + K(KeyF1); + K(KeyF2); + K(KeyF3); + K(KeyF4); + K(KeyF5); + K(KeyF6); + K(KeyF7); + K(KeyF8); + K(KeyF9); + K(KeyF10); + K(KeyF11); + K(KeyF12); + K(KeyF13); + K(KeyF14); + K(KeyF15); + K(KeyF16); + K(KeyF17); + K(KeyF18); + K(KeyF19); + K(KeyF20); + K(KeyF21); + K(KeyF22); + K(KeyF23); + K(KeyF24); + + default: + return "KeyUnknown"; + } +#undef K +} + +void event_to_buf(GHOST_EventHandle evt, char buf[128]) { + GHOST_TEventType type= GHOST_GetEventType(evt); + double time= (double) ((GHOST_TInt64) GHOST_GetEventTime(evt))/1000; + GHOST_WindowHandle win= GHOST_GetEventWindow(evt); + void *data= GHOST_GetEventData(evt); + char *pos= buf; + + pos+= sprintf(pos, "event: %6.2f, %16s", time, eventtype_to_string(type)); + if (win) { + char *s= GHOST_GetTitle(win); + pos+= sprintf(pos, " - win: %s", s); + free(s); + } else { + pos+= sprintf(pos, " - sys evt"); + } + switch (type) { + case GHOST_kEventCursorMove: { + GHOST_TEventCursorData *cd= data; + pos+= sprintf(pos, " - pos: (%d, %d)", cd->x, cd->y); + break; + } + case GHOST_kEventButtonDown: + case GHOST_kEventButtonUp: { + GHOST_TEventButtonData *bd= data; + pos+= sprintf(pos, " - but: %d", bd->button); + break; + } + + case GHOST_kEventKeyDown: + case GHOST_kEventKeyUp: { + GHOST_TEventKeyData *kd= data; + pos+= sprintf(pos, " - key: %s (%d)", keytype_to_string(kd->key), kd->key); + if (kd->ascii) pos+= sprintf(pos, " ascii: '%c' (%d)", kd->ascii, kd->ascii); + break; + } + } +} diff --git a/intern/ghost/test/multitest/EventToBuf.h b/intern/ghost/test/multitest/EventToBuf.h new file mode 100644 index 00000000000..0324af1f73f --- /dev/null +++ b/intern/ghost/test/multitest/EventToBuf.h @@ -0,0 +1,34 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +char *eventtype_to_string(GHOST_TEventType type); +void event_to_buf(GHOST_EventHandle evt, char buf[128]); + diff --git a/intern/ghost/test/multitest/GL.h b/intern/ghost/test/multitest/GL.h new file mode 100644 index 00000000000..7a96ae9e9f8 --- /dev/null +++ b/intern/ghost/test/multitest/GL.h @@ -0,0 +1,44 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#if defined(WIN32) || defined(__APPLE__) + + #ifdef WIN32 + #include + #include + #else // WIN32 + // __APPLE__ is defined + #include + #endif // WIN32 +#else // defined(WIN32) || defined(__APPLE__) + #include +#endif // defined(WIN32) || defined(__APPLE__) + diff --git a/intern/ghost/test/multitest/Makefile b/intern/ghost/test/multitest/Makefile new file mode 100644 index 00000000000..a424a397502 --- /dev/null +++ b/intern/ghost/test/multitest/Makefile @@ -0,0 +1,60 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# GHOST gears test application Makefile +# + +DIR = $(OCGDIR)/intern/ghost/test + +# we don't want a library here, only object files: +ALLTARGETS = $(OBJS) + +include nan_compile.mk +include nan_link.mk + +CFLAGS += $(LEVEL_1_C_WARNINGS) +CCFLAGS += $(LEVEL_1_CPP_WARNINGS) + +CPPFLAGS += -I$(OPENGL_HEADERS) +CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I$(NAN_BMFONT)/include +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include +CPPFLAGS += -I../.. + +OCGGHOST = $(OCGDIR)/intern/ghost + +LIBS = $(OCGGHOST)/$(DEBUG_DIR)libghost.a +SLIBS += $(LCGDIR)/string/lib/libstring.a +SLIBS += $(LCGDIR)/bmfont/lib/libbmfont.a +SLIBS += $(LCGDIR)/guardedalloc/lib/libguardedalloc.a + +all:: + @echo "- link $(DIR)/$(DEBUG_DIR)multitest -" + @$(CCC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)multitest $(OBJS) $(LIBS) $(SLIBS) $(LLIBS) $(DADD) $(LOPTS) diff --git a/intern/ghost/test/multitest/MultiTest.c b/intern/ghost/test/multitest/MultiTest.c new file mode 100644 index 00000000000..e81fb3c034e --- /dev/null +++ b/intern/ghost/test/multitest/MultiTest.c @@ -0,0 +1,866 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#define FALSE 0 + +#ifdef WIN32 + +#pragma warning(disable: 4244 4305) +#endif + +#include +#include +#include +#include + +#include "GL.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_guardedalloc.h" + +#include "GHOST_C-api.h" +#include "BMF_Api.h" + +#include "Util.h" +#include "Basic.h" +#include "ScrollBar.h" +#include "EventToBuf.h" + +#include "WindowData.h" + +/***/ + +typedef struct _MultiTestApp MultiTestApp; +typedef struct _LoggerWindow LoggerWindow; + +void loggerwindow_log(LoggerWindow *lw, char *line); + +void multitestapp_toggle_extra_window(MultiTestApp *app); +void multitestapp_free_extrawindow(MultiTestApp *app); +LoggerWindow *multitestapp_get_logger(MultiTestApp *app); +GHOST_SystemHandle multitestapp_get_system(MultiTestApp *app); +void multitestapp_exit(MultiTestApp *app); + +/**/ + +void rect_bevel_side(int rect[2][2], int side, float *lt, float *dk, float *col, int width) { + int ltidx= (side/2)%4; + int dkidx= (ltidx + 1 + (side&1))%4; + int i, corner; + + glBegin(GL_LINES); + for (i=0; iltidx)?dkf:ltf; + int lx= rect[1][0]-i-1; + int ly= rect[0][1]+i; + + glColor3f(col[0]*stf, col[1]*stf, col[2]*stf); + for (corner=0; corner<4; corner++) { + int x= (corner==0 || corner==1)?(rect[0][0]+i):(rect[1][0]-i-1); + int y= (corner==0 || corner==3)?(rect[0][1]+i):(rect[1][1]-i-1); + + if (ltidx==corner) + glColor3f(col[0]*ltf, col[1]*ltf, col[2]*ltf); + if (dkidx==corner) + glColor3f(col[0]*dkf, col[1]*dkf, col[2]*dkf); + + glVertex2i(lx, ly); + glVertex2i(lx= x, ly= y); + } + } + glEnd(); + + glColor3fv(col); + glRecti(rect[0][0]+width, rect[0][1]+width, rect[1][0]-width, rect[1][1]-width); +} + +void rect_bevel_smooth(int rect[2][2], int width) { + float *lt= malloc(sizeof(*lt)*width); + float *dk= malloc(sizeof(*dk)*width); + float col[4]; + int i; + + for (i=0; iapp), str); +} + +static void mainwindow_do_draw(MainWindow *mw) { + GHOST_ActivateWindowDrawingContext(mw->win); + + if (mw->lmbut[0]) { + glClearColor(0.5, 0.5, 0.5, 1); + } else { + glClearColor(1, 1, 1, 1); + } + glClear(GL_COLOR_BUFFER_BIT); + + glColor3f(0.5, 0.6, 0.8); + glRecti(mw->tmouse[0]-5, mw->tmouse[1]-5, mw->tmouse[0]+5, mw->tmouse[1]+5); + + GHOST_SwapWindowBuffers(mw->win); +} + +static void mainwindow_do_reshape(MainWindow *mw) { + GHOST_RectangleHandle bounds= GHOST_GetClientBounds(mw->win); + + GHOST_ActivateWindowDrawingContext(mw->win); + + mw->size[0]= GHOST_GetWidthRectangle(bounds); + mw->size[1]= GHOST_GetHeightRectangle(bounds); + + glViewport(0, 0, mw->size[0], mw->size[1]); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, mw->size[0], 0, mw->size[1], -1, 1); + glTranslatef(0.375, 0.375, 0.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +static void mainwindow_do_key(MainWindow *mw, GHOST_TKey key, int press) { + switch(key) { + case GHOST_kKeyC: + if (press) + GHOST_SetCursorShape(mw->win, (GHOST_TStandardCursor) (rand()%(GHOST_kStandardCursorNumCursors))); + break; + case GHOST_kKeyLeftBracket: + if (press) + GHOST_SetCursorVisibility(mw->win, 0); + break; + case GHOST_kKeyRightBracket: + if (press) + GHOST_SetCursorVisibility(mw->win, 1); + break; + case GHOST_kKeyE: + if (press) + multitestapp_toggle_extra_window(mw->app); + break; + case GHOST_kKeyQ: + if (press) + multitestapp_exit(mw->app); + break; + case GHOST_kKeyT: + if (press) + mainwindow_log(mw, "TextTest~|`hello`\"world\",<>/"); + break; + case GHOST_kKeyR: + if (press) { + int i; + + mainwindow_log(mw, "Invalidating window 10 times"); + for (i=0; i<10; i++) + GHOST_InvalidateWindow(mw->win); + } + break; + case GHOST_kKeyF11: + if (press) { + GHOST_SetWindowOrder(mw->win, GHOST_kWindowOrderBottom); + } + break; + } +} + +static void mainwindow_do_move(MainWindow *mw, int x, int y) { + mw->lmouse[0]= x, mw->lmouse[1]= y; + + if (mw->lmbut[0]) { + mw->tmouse[0]= x, mw->tmouse[1]= y; + GHOST_InvalidateWindow(mw->win); + } +} + +static void mainwindow_do_button(MainWindow *mw, int which, int press) { + if (which==GHOST_kButtonMaskLeft) { + mw->lmbut[0]= press; + mw->tmouse[0]= mw->lmouse[0], mw->tmouse[1]= mw->lmouse[1]; + GHOST_InvalidateWindow(mw->win); + } else if (which==GHOST_kButtonMaskLeft) { + mw->lmbut[1]= press; + } else if (which==GHOST_kButtonMaskLeft) { + mw->lmbut[2]= press; + } +} + +static void mainwindow_handle(void *priv, GHOST_EventHandle evt) { + MainWindow *mw= priv; + GHOST_TEventType type= GHOST_GetEventType(evt); + char buf[256]; + + event_to_buf(evt, buf); + mainwindow_log(mw, buf); + + switch (type) { + case GHOST_kEventCursorMove: { + GHOST_TEventCursorData *cd= GHOST_GetEventData(evt); + int x, y; + GHOST_ScreenToClient(mw->win, cd->x, cd->y, &x, &y); + mainwindow_do_move(mw, x, mw->size[1]-y-1); + break; + } + case GHOST_kEventButtonDown: + case GHOST_kEventButtonUp: { + GHOST_TEventButtonData *bd= GHOST_GetEventData(evt); + mainwindow_do_button(mw, bd->button, (type == GHOST_kEventButtonDown)); + break; + } + case GHOST_kEventKeyDown: + case GHOST_kEventKeyUp: { + GHOST_TEventKeyData *kd= GHOST_GetEventData(evt); + mainwindow_do_key(mw, kd->key, (type == GHOST_kEventKeyDown)); + break; + } + + case GHOST_kEventWindowUpdate: + mainwindow_do_draw(mw); + break; + case GHOST_kEventWindowSize: + mainwindow_do_reshape(mw); + break; + } +} + +/**/ + +static void mainwindow_timer_proc(GHOST_TimerTaskHandle task, GHOST_TUns64 time) { + MainWindow *mw= GHOST_GetTimerTaskUserData(task); + char buf[64]; + + sprintf(buf, "timer: %6.2f", (double) ((GHOST_TInt64) time)/1000); + mainwindow_log(mw, buf); +} + +MainWindow *mainwindow_new(MultiTestApp *app) { + GHOST_SystemHandle sys= multitestapp_get_system(app); + GHOST_WindowHandle win; + + win= GHOST_CreateWindow(sys, "MultiTest:Main", 40, 40, 400, 400, + GHOST_kWindowStateNormal, GHOST_kDrawingContextTypeOpenGL, + FALSE); + + if (win) { + MainWindow *mw= MEM_callocN(sizeof(*mw), "mainwindow_new"); + mw->app= app; + mw->win= win; + + GHOST_SetWindowUserData(mw->win, windowdata_new(mw, mainwindow_handle)); + + GHOST_InstallTimer(sys, 1000, 10000, mainwindow_timer_proc, mw); + + return mw; + } else { + return NULL; + } +} + +void mainwindow_free(MainWindow *mw) { + GHOST_SystemHandle sys= multitestapp_get_system(mw->app); + + windowdata_free(GHOST_GetWindowUserData(mw->win)); + GHOST_DisposeWindow(sys, mw->win); + MEM_freeN(mw); +} + + /* + * LoggerWindow + */ + +struct _LoggerWindow { + MultiTestApp *app; + + GHOST_WindowHandle win; + + BMF_Font *font; + int fonttexid; + int fontheight; + + int size[2]; + + int ndisplines; + int textarea[2][2]; + ScrollBar *scroll; + + char **loglines; + int nloglines, logsize; + + int lmbut[3]; + int lmouse[2]; +}; + +#define SCROLLBAR_PAD 2 +#define SCROLLBAR_WIDTH 14 +#define TEXTAREA_PAD 2 +static void loggerwindow_recalc_regions(LoggerWindow *lw) { + int nscroll[2][2]; + + nscroll[0][0]= SCROLLBAR_PAD; + nscroll[0][1]= SCROLLBAR_PAD; + nscroll[1][0]= nscroll[0][0] + SCROLLBAR_WIDTH; + nscroll[1][1]= lw->size[1] - SCROLLBAR_PAD - 1; + + lw->textarea[0][0]= nscroll[1][0] + TEXTAREA_PAD; + lw->textarea[0][1]= TEXTAREA_PAD; + lw->textarea[1][0]= lw->size[0] - TEXTAREA_PAD - 1; + lw->textarea[1][1]= lw->size[1] - TEXTAREA_PAD - 1; + + lw->ndisplines= (lw->textarea[1][1]-lw->textarea[0][1])/lw->fontheight; + + scrollbar_set_thumbpct(lw->scroll, (float) lw->ndisplines/lw->nloglines); + scrollbar_set_rect(lw->scroll, nscroll); +} + +static void loggerwindow_setup_window_gl(LoggerWindow *lw) { + glViewport(0, 0, lw->size[0], lw->size[1]); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, lw->size[0], 0, lw->size[1], -1, 1); + glTranslatef(0.375, 0.375, 0.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +static void loggerwindow_do_reshape(LoggerWindow *lw) { + GHOST_RectangleHandle bounds= GHOST_GetClientBounds(lw->win); + + GHOST_ActivateWindowDrawingContext(lw->win); + + lw->size[0]= GHOST_GetWidthRectangle(bounds); + lw->size[1]= GHOST_GetHeightRectangle(bounds); + + loggerwindow_recalc_regions(lw); + loggerwindow_setup_window_gl(lw); +} + +static void loggerwindow_do_draw(LoggerWindow *lw) { + int i, ndisplines, startline; + int sb_rect[2][2], sb_thumb[2][2]; + + GHOST_ActivateWindowDrawingContext(lw->win); + + glClearColor(1, 1, 1, 1); + glClear(GL_COLOR_BUFFER_BIT); + + glColor3f(0.8, 0.8, 0.8); + rect_bevel_smooth(lw->textarea, 4); + + scrollbar_get_rect(lw->scroll, sb_rect); + scrollbar_get_thumb(lw->scroll, sb_thumb); + + glColor3f(0.6, 0.6, 0.6); + rect_bevel_smooth(sb_rect, 1); + + if (scrollbar_is_scrolling(lw->scroll)) { + glColor3f(0.6, 0.7, 0.5); + } else { + glColor3f(0.9, 0.9, 0.92); + } + rect_bevel_smooth(sb_thumb, 1); + + startline= scrollbar_get_thumbpos(lw->scroll)*(lw->nloglines-1); + ndisplines= min_i(lw->ndisplines, lw->nloglines-startline); + + if (lw->fonttexid!=-1) { + glBindTexture(GL_TEXTURE_2D, lw->fonttexid); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + glEnable(GL_TEXTURE_2D); + } + glColor3f(0, 0, 0); + for (i=0; iloglines[(lw->nloglines-1)-(i+startline)]; + int x_pos= lw->textarea[0][0] + 4; + int y_pos= lw->textarea[0][1] + 4 + i*lw->fontheight; + + if (lw->fonttexid==-1) { + glRasterPos2i(x_pos, y_pos); + BMF_DrawString(lw->font, line); + } else { + BMF_DrawStringTexture(lw->font, line, x_pos, y_pos, 0.0); + } + } + if (lw->fonttexid!=-1) { + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + } + + GHOST_SwapWindowBuffers(lw->win); +} + +static void loggerwindow_do_move(LoggerWindow *lw, int x, int y) { + lw->lmouse[0]= x, lw->lmouse[1]= y; + + if (scrollbar_is_scrolling(lw->scroll)) { + scrollbar_keep_scrolling(lw->scroll, y); + GHOST_InvalidateWindow(lw->win); + } +} + +static void loggerwindow_do_button(LoggerWindow *lw, int which, int press) { + if (which==GHOST_kButtonMaskLeft) { + lw->lmbut[0]= press; + + if (press) { + if (scrollbar_contains_pt(lw->scroll, lw->lmouse)) { + scrollbar_start_scrolling(lw->scroll, lw->lmouse[1]); + GHOST_SetCursorShape(lw->win, GHOST_kStandardCursorUpDown); + GHOST_InvalidateWindow(lw->win); + } + } else { + if (scrollbar_is_scrolling(lw->scroll)) { + scrollbar_stop_scrolling(lw->scroll); + GHOST_SetCursorShape(lw->win, GHOST_kStandardCursorDefault); + GHOST_InvalidateWindow(lw->win); + } + } + } else if (which==GHOST_kButtonMaskMiddle) { + lw->lmbut[1]= press; + } else if (which==GHOST_kButtonMaskRight) { + lw->lmbut[2]= press; + } +} + +static void loggerwindow_do_key(LoggerWindow *lw, GHOST_TKey key, int press) { + switch (key) { + case GHOST_kKeyQ: + if (press) + multitestapp_exit(lw->app); + break; + } +} + +static void loggerwindow_handle(void *priv, GHOST_EventHandle evt) { + LoggerWindow *lw= priv; + GHOST_TEventType type= GHOST_GetEventType(evt); + + switch(type) { + case GHOST_kEventCursorMove: { + GHOST_TEventCursorData *cd= GHOST_GetEventData(evt); + int x, y; + GHOST_ScreenToClient(lw->win, cd->x, cd->y, &x, &y); + loggerwindow_do_move(lw, x, lw->size[1]-y-1); + break; + } + case GHOST_kEventButtonDown: + case GHOST_kEventButtonUp: { + GHOST_TEventButtonData *bd= GHOST_GetEventData(evt); + loggerwindow_do_button(lw, bd->button, (type == GHOST_kEventButtonDown)); + break; + } + case GHOST_kEventKeyDown: + case GHOST_kEventKeyUp: { + GHOST_TEventKeyData *kd= GHOST_GetEventData(evt); + loggerwindow_do_key(lw, kd->key, (type == GHOST_kEventKeyDown)); + break; + } + + case GHOST_kEventWindowUpdate: + loggerwindow_do_draw(lw); + break; + case GHOST_kEventWindowSize: + loggerwindow_do_reshape(lw); + break; + } +} + +/**/ + +LoggerWindow *loggerwindow_new(MultiTestApp *app) { + GHOST_SystemHandle sys= multitestapp_get_system(app); + GHOST_TUns32 screensize[2]; + GHOST_WindowHandle win; + + GHOST_GetMainDisplayDimensions(sys, &screensize[0], &screensize[1]); + win= GHOST_CreateWindow(sys, "MultiTest:Logger", 40, screensize[1]-432, + 800, 300, GHOST_kWindowStateNormal, + GHOST_kDrawingContextTypeOpenGL, FALSE); + + if (win) { + LoggerWindow *lw= MEM_callocN(sizeof(*lw), "loggerwindow_new"); + int bbox[2][2]; + lw->app= app; + lw->win= win; + + lw->font= BMF_GetFont(BMF_kScreen12); + lw->fonttexid= BMF_GetFontTexture(lw->font); + + BMF_GetBoundingBox(lw->font, &bbox[0][0], &bbox[0][1], &bbox[1][0], &bbox[1][1]); + lw->fontheight= rect_height(bbox); + + lw->nloglines= lw->logsize= 0; + lw->loglines= MEM_mallocN(sizeof(*lw->loglines)*lw->nloglines, "loglines"); + + lw->scroll= scrollbar_new(2, 40); + + GHOST_SetWindowUserData(lw->win, windowdata_new(lw, loggerwindow_handle)); + + loggerwindow_do_reshape(lw); + + return lw; + } else { + return NULL; + } +} + +void loggerwindow_log(LoggerWindow *lw, char *line) { + if (lw->nloglines==lw->logsize) { + lw->loglines= memdbl(lw->loglines, &lw->logsize, sizeof(*lw->loglines)); + } + + lw->loglines[lw->nloglines++]= string_dup(line); + scrollbar_set_thumbpct(lw->scroll, (float) lw->ndisplines/lw->nloglines); + + GHOST_InvalidateWindow(lw->win); +} + +void loggerwindow_free(LoggerWindow *lw) { + GHOST_SystemHandle sys= multitestapp_get_system(lw->app); + int i; + + for (i=0; inloglines; i++) { + MEM_freeN(lw->loglines[i]); + } + MEM_freeN(lw->loglines); + + windowdata_free(GHOST_GetWindowUserData(lw->win)); + GHOST_DisposeWindow(sys, lw->win); + MEM_freeN(lw); +} + + /* + * ExtraWindow + */ + + +typedef struct { + MultiTestApp *app; + + GHOST_WindowHandle win; + + int size[2]; +} ExtraWindow; + +static void extrawindow_do_draw(ExtraWindow *ew) { + GHOST_ActivateWindowDrawingContext(ew->win); + + glClearColor(1, 1, 1, 1); + glClear(GL_COLOR_BUFFER_BIT); + + glColor3f(0.8, 0.8, 0.8); + glRecti(10, 10, ew->size[0]-10, ew->size[1]-10); + + GHOST_SwapWindowBuffers(ew->win); +} + +static void extrawindow_do_reshape(ExtraWindow *ew) { + GHOST_RectangleHandle bounds= GHOST_GetClientBounds(ew->win); + + GHOST_ActivateWindowDrawingContext(ew->win); + + ew->size[0]= GHOST_GetWidthRectangle(bounds); + ew->size[1]= GHOST_GetHeightRectangle(bounds); + + glViewport(0, 0, ew->size[0], ew->size[1]); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, ew->size[0], 0, ew->size[1], -1, 1); + glTranslatef(0.375, 0.375, 0.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +static void extrawindow_do_key(ExtraWindow *ew, GHOST_TKey key, int press) { + switch (key) { + case GHOST_kKeyE: + if (press) + multitestapp_toggle_extra_window(ew->app); + break; + } +} + +static void extrawindow_spin_cursor(ExtraWindow *ew, GHOST_TUns64 time) { + GHOST_TUns8 bitmap[16][2]; + GHOST_TUns8 mask[16][2]; + double ftime= (double) ((GHOST_TInt64) time)/1000; + float angle= fmod(ftime, 1.0) * 3.1415*2; + int i; + + memset(&bitmap, 0, sizeof(bitmap)); + memset(&mask, 0, sizeof(mask)); + + bitmap[0][0] |= mask[0][0] |= 0xF; + bitmap[1][0] |= mask[1][0] |= 0xF; + bitmap[2][0] |= mask[2][0] |= 0xF; + bitmap[3][0] |= mask[3][0] |= 0xF; + + for (i=0; i<7; i++) { + int x = 7 + cos(angle)*i; + int y = 7 + sin(angle)*i; + + mask[y][x/8] |= (1 << (x%8)); + } + for (i=0; i<64; i++) { + float v= (i/63.0) * 3.1415*2; + int x = 7 + cos(v)*7; + int y = 7 + sin(v)*7; + + mask[y][x/8] |= (1 << (x%8)); + } + + GHOST_SetCustomCursorShape(ew->win, bitmap, mask, 0, 0); +} + +static void extrawindow_handle(void *priv, GHOST_EventHandle evt) { + ExtraWindow *ew= priv; + GHOST_TEventType type= GHOST_GetEventType(evt); + char buf[256]; + + event_to_buf(evt, buf); + loggerwindow_log(multitestapp_get_logger(ew->app), buf); + + switch (type) { + case GHOST_kEventKeyDown: + case GHOST_kEventKeyUp: { + GHOST_TEventKeyData *kd= GHOST_GetEventData(evt); + extrawindow_do_key(ew, kd->key, (type == GHOST_kEventKeyDown)); + break; + } + + case GHOST_kEventCursorMove: { + extrawindow_spin_cursor(ew, GHOST_GetEventTime(evt)); + break; + } + + case GHOST_kEventWindowClose: + multitestapp_free_extrawindow(ew->app); + break; + case GHOST_kEventWindowUpdate: + extrawindow_do_draw(ew); + break; + case GHOST_kEventWindowSize: + extrawindow_do_reshape(ew); + break; + } +} + +/**/ + +ExtraWindow *extrawindow_new(MultiTestApp *app) { + GHOST_SystemHandle sys= multitestapp_get_system(app); + GHOST_WindowHandle win; + + win= GHOST_CreateWindow(sys, "MultiTest:Extra", 500, 40, 400, 400, + GHOST_kWindowStateNormal, GHOST_kDrawingContextTypeOpenGL, + FALSE); + + if (win) { + ExtraWindow *ew= MEM_callocN(sizeof(*ew), "mainwindow_new"); + ew->app= app; + ew->win= win; + + GHOST_SetWindowUserData(ew->win, windowdata_new(ew, extrawindow_handle)); + + return ew; + } else { + return NULL; + } +} + +void extrawindow_free(ExtraWindow *ew) { + GHOST_SystemHandle sys= multitestapp_get_system(ew->app); + + windowdata_free(GHOST_GetWindowUserData(ew->win)); + GHOST_DisposeWindow(sys, ew->win); + MEM_freeN(ew); +} + + /* + * MultiTestApp + */ + +struct _MultiTestApp { + GHOST_SystemHandle sys; + MainWindow *main; + LoggerWindow *logger; + ExtraWindow *extra; + + int exit; +}; + +static int multitest_event_handler(GHOST_EventHandle evt, GHOST_TUserDataPtr data) { + MultiTestApp *app= data; + GHOST_WindowHandle win; + + win= GHOST_GetEventWindow(evt); + if (win && !GHOST_ValidWindow(app->sys, win)) { + loggerwindow_log(app->logger, "WARNING: bad event, non-valid window\n"); + return 1; + } + + if (win) { + WindowData *wb= GHOST_GetWindowUserData(win); + + windowdata_handle(wb, evt); + } else { + GHOST_TEventType type= GHOST_GetEventType(evt); + + /* GHOST_kEventQuit are the only 'system' events, + * that is, events without a window. + */ + switch(type) { + case GHOST_kEventQuit: + app->exit= 1; + break; + + default: + fatal("Unhandled system event: %d (%s)\n", type, eventtype_to_string(type)); + break; + } + } + + return 1; +} + +/**/ + +MultiTestApp *multitestapp_new(void) { + MultiTestApp *app= MEM_mallocN(sizeof(*app), "multitestapp_new"); + GHOST_EventConsumerHandle consumer= GHOST_CreateEventConsumer(multitest_event_handler, app); + + app->sys= GHOST_CreateSystem(); + if (!app->sys) + fatal("Unable to create ghost system"); + + if (!GHOST_AddEventConsumer(app->sys, consumer)) + fatal("Unable to add multitest event consumer "); + + app->main= mainwindow_new(app); + if (!app->main) + fatal("Unable to create main window"); + + app->logger= loggerwindow_new(app); + if (!app->logger) + fatal("Unable to create logger window"); + + app->extra= NULL; + app->exit= 0; + + return app; +} + +LoggerWindow *multitestapp_get_logger(MultiTestApp *app) { + return app->logger; +} + +GHOST_SystemHandle multitestapp_get_system(MultiTestApp *app) { + return app->sys; +} + +void multitestapp_free_extrawindow(MultiTestApp *app) { + extrawindow_free(app->extra); + app->extra= NULL; +} + +void multitestapp_toggle_extra_window(MultiTestApp *app) { + if (app->extra) { + multitestapp_free_extrawindow(app); + } else { + app->extra= extrawindow_new(app); + } +} + +void multitestapp_exit(MultiTestApp *app) { + app->exit= 1; +} + +void multitestapp_run(MultiTestApp *app) { + while (!app->exit) { + GHOST_ProcessEvents(app->sys, 1); + GHOST_DispatchEvents(app->sys); + } +} + +void multitestapp_free(MultiTestApp *app) { + mainwindow_free(app->main); + loggerwindow_free(app->logger); + GHOST_DisposeSystem(app->sys); + MEM_freeN(app); +} + + /***/ + +int main(int argc, char **argv) { + MultiTestApp *app= multitestapp_new(); + + multitestapp_run(app); + multitestapp_free(app); + + return 0; +} diff --git a/intern/ghost/test/multitest/ScrollBar.c b/intern/ghost/test/multitest/ScrollBar.c new file mode 100644 index 00000000000..6ede0619b5f --- /dev/null +++ b/intern/ghost/test/multitest/ScrollBar.c @@ -0,0 +1,149 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include + +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_guardedalloc.h" + +#include "Basic.h" +#include "ScrollBar.h" + +struct _ScrollBar { + int rect[2][2]; + float thumbpos, thumbpct; + + int inset; + int minthumb; + + int scrolling; + float scrolloffs; +}; + +static int scrollbar_get_thumbH(ScrollBar *sb) { + int scrollable_h= rect_height(sb->rect) - 2*sb->inset; + + return clamp_i(sb->thumbpct*scrollable_h, sb->minthumb, scrollable_h); +} +static int scrollbar_get_thumbableH(ScrollBar *sb) { + int scrollable_h= rect_height(sb->rect) - 2*sb->inset; + int thumb_h= scrollbar_get_thumbH(sb); + + return scrollable_h - thumb_h; +} + +static float scrollbar_co_to_pos(ScrollBar *sb, int yco) { + int thumb_h= scrollbar_get_thumbH(sb); + int thumbable_h= scrollbar_get_thumbableH(sb); + int thumbable_y= (sb->rect[0][1]+sb->inset) + thumb_h/2; + + return (float) (yco-thumbable_y)/thumbable_h; +} + +/**/ + +ScrollBar *scrollbar_new(int inset, int minthumb) { + ScrollBar *sb= MEM_callocN(sizeof(*sb), "scrollbar_new"); + sb->inset= inset; + sb->minthumb= minthumb; + + return sb; +} + +void scrollbar_get_thumb(ScrollBar *sb, int thumb_r[2][2]) { + int thumb_h= scrollbar_get_thumbH(sb); + int thumbable_h= scrollbar_get_thumbableH(sb); + + thumb_r[0][0]= sb->rect[0][0]+sb->inset; + thumb_r[1][0]= sb->rect[1][0]-sb->inset; + + thumb_r[0][1]= sb->rect[0][1]+sb->inset + sb->thumbpos*thumbable_h; + thumb_r[1][1]= thumb_r[0][1] + thumb_h; +} + +int scrollbar_is_scrolling(ScrollBar *sb) { + return sb->scrolling; +} +int scrollbar_contains_pt(ScrollBar *sb, int pt[2]) { + return rect_contains_pt(sb->rect, pt); +} + +void scrollbar_start_scrolling(ScrollBar *sb, int yco) { + int thumb_h_2= scrollbar_get_thumbH(sb)/2; + int thumbable_h= scrollbar_get_thumbableH(sb); + float npos= scrollbar_co_to_pos(sb, yco); + + sb->scrolloffs= sb->thumbpos - npos; + if (fabs(sb->scrolloffs) >= (float) thumb_h_2/thumbable_h) { + sb->scrolloffs= 0.0; + } + + sb->scrolling= 1; + sb->thumbpos= clamp_f(npos + sb->scrolloffs, 0.0, 1.0); +} +void scrollbar_keep_scrolling(ScrollBar *sb, int yco) { + float npos= scrollbar_co_to_pos(sb, yco); + + sb->thumbpos= clamp_f(npos + sb->scrolloffs, 0.0, 1.0); +} +void scrollbar_stop_scrolling(ScrollBar *sb) { + sb->scrolling= 0; + sb->scrolloffs= 0.0; +} + +void scrollbar_set_thumbpct(ScrollBar *sb, float pct) { + sb->thumbpct= pct; +} +void scrollbar_set_thumbpos(ScrollBar *sb, float pos) { + sb->thumbpos= clamp_f(pos, 0.0, 1.0); +} +void scrollbar_set_rect(ScrollBar *sb, int rect[2][2]) { + rect_copy(sb->rect, rect); +} + +float scrollbar_get_thumbpct(ScrollBar *sb) { + return sb->thumbpct; +} +float scrollbar_get_thumbpos(ScrollBar *sb) { + return sb->thumbpos; +} +void scrollbar_get_rect(ScrollBar *sb, int rect_r[2][2]) { + rect_copy(rect_r, sb->rect); +} + +void scrollbar_free(ScrollBar *sb) { + MEM_freeN(sb); +} diff --git a/intern/ghost/test/multitest/ScrollBar.h b/intern/ghost/test/multitest/ScrollBar.h new file mode 100644 index 00000000000..b49ad041415 --- /dev/null +++ b/intern/ghost/test/multitest/ScrollBar.h @@ -0,0 +1,57 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +typedef struct _ScrollBar ScrollBar; + + + /***/ + +ScrollBar* scrollbar_new (int inset, int minthumb); + +int scrollbar_is_scrolling (ScrollBar *sb); +int scrollbar_contains_pt (ScrollBar *sb, int pt[2]); + +void scrollbar_start_scrolling (ScrollBar *sb, int yco); +void scrollbar_keep_scrolling (ScrollBar *sb, int yco); +void scrollbar_stop_scrolling (ScrollBar *sb); + +void scrollbar_set_thumbpct (ScrollBar *sb, float pct); +void scrollbar_set_thumbpos (ScrollBar *sb, float pos); +void scrollbar_set_rect (ScrollBar *sb, int rect[2][2]); + +float scrollbar_get_thumbpct (ScrollBar *sb); +float scrollbar_get_thumbpos (ScrollBar *sb); +void scrollbar_get_rect (ScrollBar *sb, int rect_r[2][2]); + +void scrollbar_get_thumb (ScrollBar *sb, int thumb_r[2][2]); + +void scrollbar_free (ScrollBar *sb); + diff --git a/intern/ghost/test/multitest/Util.c b/intern/ghost/test/multitest/Util.c new file mode 100644 index 00000000000..4cf23ff06a9 --- /dev/null +++ b/intern/ghost/test/multitest/Util.c @@ -0,0 +1,77 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_guardedalloc.h" + +#include "Util.h" + +void* memdbl(void *mem, int *size_pr, int item_size) { + int cur_size= *size_pr; + int new_size= cur_size?(cur_size*2):1; + void *nmem= MEM_mallocN(new_size*item_size, "memdbl"); + + memcpy(nmem, mem, cur_size*item_size); + MEM_freeN(mem); + + *size_pr= new_size; + return nmem; +} + +char* string_dup(char *str) { + int len= strlen(str); + char *nstr= MEM_mallocN(len + 1, "string_dup"); + + memcpy(nstr, str, len+1); + + return nstr; +} + +void fatal(char *fmt, ...) { + va_list ap; + + fprintf(stderr, "FATAL: "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); + + exit(1); +} diff --git a/intern/ghost/test/multitest/Util.h b/intern/ghost/test/multitest/Util.h new file mode 100644 index 00000000000..e3e51824515 --- /dev/null +++ b/intern/ghost/test/multitest/Util.h @@ -0,0 +1,36 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +void* memdbl (void *mem, int *size_pr, int item_size); + +char* string_dup (char *str); +void fatal (char *fmt, ...); + diff --git a/intern/ghost/test/multitest/WindowData.c b/intern/ghost/test/multitest/WindowData.c new file mode 100644 index 00000000000..3c5739fd593 --- /dev/null +++ b/intern/ghost/test/multitest/WindowData.c @@ -0,0 +1,63 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_guardedalloc.h" + +#include "GHOST_C-api.h" + +#include "WindowData.h" + +struct _WindowData { + void *data; + WindowDataHandler handler; +}; + +WindowData *windowdata_new(void *data, WindowDataHandler handler) { + WindowData *wb= MEM_mallocN(sizeof(*wb), "windowdata_new"); + wb->data= data; + wb->handler= handler; + + return wb; +} + +void windowdata_handle(WindowData *wb, GHOST_EventHandle evt) { + wb->handler(wb->data, evt); +} + +void windowdata_free(WindowData *wb) { + MEM_freeN(wb); +} diff --git a/intern/ghost/test/multitest/WindowData.h b/intern/ghost/test/multitest/WindowData.h new file mode 100644 index 00000000000..10a1ca710f2 --- /dev/null +++ b/intern/ghost/test/multitest/WindowData.h @@ -0,0 +1,40 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +typedef void (*WindowDataHandler)(void *priv, GHOST_EventHandle evt); +typedef struct _WindowData WindowData; + + /***/ + +WindowData* windowdata_new (void *data, WindowDataHandler handler); +void windowdata_handle (WindowData *wb, GHOST_EventHandle evt); +void windowdata_free (WindowData *wb); + diff --git a/intern/guardedalloc/CMakeLists.txt b/intern/guardedalloc/CMakeLists.txt new file mode 100644 index 00000000000..71e3a40fefc --- /dev/null +++ b/intern/guardedalloc/CMakeLists.txt @@ -0,0 +1,35 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC .) + +FILE(GLOB SRC intern/*.c) + +BLENDERLIB(bf_guardedalloc "${SRC}" "${INC}") +#, libtype=['intern', 'player'], priority = [10, 175] ) diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h new file mode 100644 index 00000000000..26a9258d03b --- /dev/null +++ b/intern/guardedalloc/MEM_guardedalloc.h @@ -0,0 +1,128 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * Guarded memory (de)allocation + * + * + * @mainpage MEM - c-style guarded memory allocation + * + * @section about About the MEM module + * + * MEM provides guarded malloc/calloc calls. All memory is enclosed by + * pads, to detect out-of-bound writes. All blocks are placed in a + * linked list, so they remain reachable at all times. There is no + * back-up in case the linked-list related data is lost. + * + * @section issues Known issues with MEM + * + * There are currently no known issues with MEM. Note that there is a + * second intern/ module with MEM_ prefix, for use in c++. + * + * @section dependencies Dependencies + * + * - stdlib + * + * - stdio + * + * */ + +#ifndef MEM_MALLOCN_H +#define MEM_MALLOCN_H + +/* Needed for FILE* */ +#include "stdio.h" + +#ifdef __cplusplus +extern "C" { +#endif + + /** Returns the lenght of the allocated memory segment pointed at + * by vmemh. If the pointer was not previously allocated by this + * module, the result is undefined.*/ + int MEM_allocN_len(void *vmemh); + + /** + * Release memory previously allocatred by this module. + */ + short MEM_freeN(void *vmemh); + + /** + * Duplicates a block of memory, and returns a pointer to the + * newly allocated block. */ + void *MEM_dupallocN(void *vmemh); + + /** + * Allocate a block of memory of size len, with tag name str. The + * memory is cleared. The name must be static, because only a + * pointer to it is stored ! */ + void *MEM_callocN(unsigned int len, const char * str); + + /** Allocate a block of memory of size len, with tag name str. The + * name must be a static, because only a pointer to it is stored ! + * */ + void *MEM_mallocN(unsigned int len, const char * str); + + /** Same as callocN, clears memory and uses mmap (disk cached) if supported. + Can be free'd with MEM_freeN as usual. + * */ + void *MEM_mapallocN(unsigned int len, const char * str); + + /** Print a list of the names and sizes of all allocated memory + * blocks. */ + void MEM_printmemlist(void); + + /** Set the callback function for error output. */ + void MEM_set_error_callback(void (*func)(char *)); + + /** + * Are the start/end block markers still correct ? + * + * @retval 0 for correct memory, 1 for corrupted memory. */ + int MEM_check_memory_integrity(void); + + /** Set thread locking functions for safe memory allocation from multiple + threads, pass NULL pointers to disable thread locking again. */ + void MEM_set_lock_callback(void (*lock)(void), void (*unlock)(void)); + + /** Attempt to enforce OSX (or other OS's) to have malloc and stack nonzero */ + void MEM_set_memory_debug(void); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/intern/guardedalloc/Makefile b/intern/guardedalloc/Makefile new file mode 100644 index 00000000000..702e7d5264f --- /dev/null +++ b/intern/guardedalloc/Makefile @@ -0,0 +1,56 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# decimation main makefile. +# + +include nan_definitions.mk + +LIBNAME = guardedalloc +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_GUARDEDALLOC) ] || mkdir $(NAN_GUARDEDALLOC) + @[ -d $(NAN_GUARDEDALLOC)/include ] || mkdir $(NAN_GUARDEDALLOC)/include + @[ -d $(NAN_GUARDEDALLOC)/lib ] || mkdir $(NAN_GUARDEDALLOC)/lib + @[ -d $(NAN_GUARDEDALLOC)/lib/debug ] || mkdir $(NAN_GUARDEDALLOC)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libguardedalloc.a $(NAN_GUARDEDALLOC)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libguardedalloc.a $(NAN_GUARDEDALLOC)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_GUARDEDALLOC)/lib/libguardedalloc.a + ranlib $(NAN_GUARDEDALLOC)/lib/debug/libguardedalloc.a +endif + @../tools/cpifdiff.sh *.h $(NAN_GUARDEDALLOC)/include/ + diff --git a/intern/guardedalloc/SConscript b/intern/guardedalloc/SConscript new file mode 100644 index 00000000000..ef6c6b49266 --- /dev/null +++ b/intern/guardedalloc/SConscript @@ -0,0 +1,8 @@ +#!/usr/bin/python + +Import('env') + +sources = env.Glob('intern/*.c') +incs = '.' + +env.BlenderLib ('bf_guardedalloc', sources, Split(incs), defines=[], libtype=['intern', 'player'], priority = [10, 175] ) diff --git a/intern/guardedalloc/intern/Makefile b/intern/guardedalloc/intern/Makefile new file mode 100644 index 00000000000..bc96ba5f27f --- /dev/null +++ b/intern/guardedalloc/intern/Makefile @@ -0,0 +1,42 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# guardedalloc intern Makefile +# + +LIBNAME = guardedalloc +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CFLAGS += $(NAN_LEVEL_2_C_WARNINGS) + +CPPFLAGS += -I.. + diff --git a/intern/guardedalloc/intern/mallocn.c b/intern/guardedalloc/intern/mallocn.c new file mode 100644 index 00000000000..51c2a2427b5 --- /dev/null +++ b/intern/guardedalloc/intern/mallocn.c @@ -0,0 +1,576 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * Guarded memory allocation, and boundary-write detection. + */ + +#include +#include /* memcpy */ +#include + +/* mmap exception */ +#if defined(AMIGA) || defined(__BeOS) || defined(WIN32) +#else +#include +#include +#endif + +#include "MEM_guardedalloc.h" + +/* --------------------------------------------------------------------- */ +/* Data definition */ +/* --------------------------------------------------------------------- */ +/* all memory chunks are put in linked lists */ +typedef struct localLink +{ + struct localLink *next,*prev; +} localLink; + +typedef struct localListBase +{ + void *first, *last; +} localListBase; + + /* note: keep this struct aligned (e.g., irix/gcc) - Hos */ +typedef struct MemHead { + int tag1; + int len; + struct MemHead *next,*prev; + const char * name; + const char * nextname; + int tag2; + int mmap; /* if true, memory was mmapped */ +} MemHead; + +typedef struct MemTail { + int tag3, pad; +} MemTail; + + +/* --------------------------------------------------------------------- */ +/* local functions */ +/* --------------------------------------------------------------------- */ + +static void addtail(volatile localListBase *listbase, void *vlink); +static void remlink(volatile localListBase *listbase, void *vlink); +static void rem_memblock(MemHead *memh); +static void MemorY_ErroR(const char *block, const char *error); +static const char *check_memlist(MemHead *memh); + +/* --------------------------------------------------------------------- */ +/* locally used defines */ +/* --------------------------------------------------------------------- */ + +#if defined( __sgi) || defined (__sun) || defined (__sun__) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || (defined (__APPLE__) && !defined(__LITTLE_ENDIAN__)) +#define MAKE_ID(a,b,c,d) ( (int)(a)<<24 | (int)(b)<<16 | (c)<<8 | (d) ) +#else +#define MAKE_ID(a,b,c,d) ( (int)(d)<<24 | (int)(c)<<16 | (b)<<8 | (a) ) +#endif + +#define MEMTAG1 MAKE_ID('M', 'E', 'M', 'O') +#define MEMTAG2 MAKE_ID('R', 'Y', 'B', 'L') +#define MEMTAG3 MAKE_ID('O', 'C', 'K', '!') +#define MEMFREE MAKE_ID('F', 'R', 'E', 'E') + +#define MEMNEXT(x) ((MemHead *)(((char *) x) - ((char *) & (((MemHead *)0)->next)))) + +/* --------------------------------------------------------------------- */ +/* vars */ +/* --------------------------------------------------------------------- */ + + +volatile int totblock= 0; +volatile unsigned long mem_in_use= 0, mmap_in_use= 0; + +volatile static struct localListBase _membase; +volatile static struct localListBase *membase = &_membase; +static void (*error_callback)(char *) = NULL; +static void (*thread_lock_callback)(void) = NULL; +static void (*thread_unlock_callback)(void) = NULL; + +static int malloc_debug_memset= 0; + +#ifdef malloc +#undef malloc +#endif + +#ifdef calloc +#undef calloc +#endif + +#ifdef free +#undef free +#endif + + +/* --------------------------------------------------------------------- */ +/* implementation */ +/* --------------------------------------------------------------------- */ + +static void print_error(const char *str, ...) +{ + char buf[1024]; + va_list ap; + + va_start(ap, str); + vsprintf(buf, str, ap); + va_end(ap); + + if (error_callback) error_callback(buf); +} + +static void mem_lock_thread() +{ + if (thread_lock_callback) + thread_lock_callback(); +} + +static void mem_unlock_thread() +{ + if (thread_unlock_callback) + thread_unlock_callback(); +} + +int MEM_check_memory_integrity() +{ + const char* err_val = NULL; + MemHead* listend; + /* check_memlist starts from the front, and runs until it finds + * the requested chunk. For this test, that's the last one. */ + listend = membase->last; + + err_val = check_memlist(listend); + + if (err_val == 0) return 0; + return 1; +} + + +void MEM_set_error_callback(void (*func)(char *)) +{ + error_callback = func; +} + +void MEM_set_lock_callback(void (*lock)(void), void (*unlock)(void)) +{ + thread_lock_callback = lock; + thread_unlock_callback = unlock; +} + +void MEM_set_memory_debug(void) +{ + malloc_debug_memset= 1; +} + +int MEM_allocN_len(void *vmemh) +{ + if (vmemh) { + MemHead *memh= vmemh; + + memh--; + return memh->len; + } else + return 0; +} + +void *MEM_dupallocN(void *vmemh) +{ + void *newp= NULL; + + if (vmemh) { + MemHead *memh= vmemh; + memh--; + + if(memh->mmap) + newp= MEM_mapallocN(memh->len, "dupli_mapalloc"); + else + newp= MEM_mallocN(memh->len, "dupli_alloc"); + + if (newp == NULL) return NULL; + + memcpy(newp, vmemh, memh->len); + } + + return newp; +} + +static void make_memhead_header(MemHead *memh, unsigned int len, const char *str) +{ + MemTail *memt; + + memh->tag1 = MEMTAG1; + memh->name = str; + memh->nextname = 0; + memh->len = len; + memh->mmap = 0; + memh->tag2 = MEMTAG2; + + memt = (MemTail *)(((char *) memh) + sizeof(MemHead) + len); + memt->tag3 = MEMTAG3; + + addtail(membase,&memh->next); + if (memh->next) memh->nextname = MEMNEXT(memh->next)->name; + + totblock++; + mem_in_use += len; +} + +void *MEM_mallocN(unsigned int len, const char *str) +{ + MemHead *memh; + + mem_lock_thread(); + + len = (len + 3 ) & ~3; /* allocate in units of 4 */ + + memh= (MemHead *)malloc(len+sizeof(MemHead)+sizeof(MemTail)); + + if(memh) { + make_memhead_header(memh, len, str); + mem_unlock_thread(); + if(malloc_debug_memset && len) + memset(memh+1, 255, len); + return (++memh); + } + mem_unlock_thread(); + print_error("Malloc returns nill: len=%d in %s, total %u\n",len, str, mem_in_use); + return NULL; +} + +void *MEM_callocN(unsigned int len, const char *str) +{ + MemHead *memh; + + mem_lock_thread(); + + len = (len + 3 ) & ~3; /* allocate in units of 4 */ + + memh= (MemHead *)calloc(len+sizeof(MemHead)+sizeof(MemTail),1); + + if(memh) { + make_memhead_header(memh, len, str); + mem_unlock_thread(); + return (++memh); + } + mem_unlock_thread(); + print_error("Calloc returns nill: len=%d in %s, total %u\n",len, str, mem_in_use); + return 0; +} + +/* note; mmap returns zero'd memory */ +void *MEM_mapallocN(unsigned int len, const char *str) +{ +#if defined(AMIGA) || defined(__BeOS) || defined(WIN32) + return MEM_callocN(len, str); +#else + MemHead *memh; + + mem_lock_thread(); + + len = (len + 3 ) & ~3; /* allocate in units of 4 */ + +#ifdef __sgi + { +#include + + int fd; + fd = open("/dev/zero", O_RDWR); + + memh= mmap(0, len+sizeof(MemHead)+sizeof(MemTail), + PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + close(fd); + } +#else + memh= mmap(0, len+sizeof(MemHead)+sizeof(MemTail), + PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0); +#endif + + if(memh!=(MemHead *)-1) { + make_memhead_header(memh, len, str); + memh->mmap= 1; + mmap_in_use += len; + mem_unlock_thread(); + return (++memh); + } + else { + mem_unlock_thread(); + print_error("Mapalloc returns nill, fallback to regular malloc: len=%d in %s, total %u\n",len, str, mmap_in_use); + return MEM_callocN(len, str); + } +#endif +} + + +void MEM_printmemlist() +{ + MemHead *membl; + + mem_lock_thread(); + + membl = membase->first; + if (membl) membl = MEMNEXT(membl); + while(membl) { + print_error("%s len: %d %p\n",membl->name,membl->len, membl+1); + if(membl->next) + membl= MEMNEXT(membl->next); + else break; + } + + mem_unlock_thread(); +} + +short MEM_freeN(void *vmemh) /* anders compileertie niet meer */ +{ + short error = 0; + MemTail *memt; + MemHead *memh= vmemh; + const char *name; + + if (memh == NULL){ + MemorY_ErroR("free","attempt to free NULL pointer"); + /* print_error(err_stream, "%d\n", (memh+4000)->tag1); */ + return(-1); + } + + if(sizeof(long)==8) { + if (((long) memh) & 0x7) { + MemorY_ErroR("free","attempt to free illegal pointer"); + return(-1); + } + } + else { + if (((long) memh) & 0x3) { + MemorY_ErroR("free","attempt to free illegal pointer"); + return(-1); + } + } + + memh--; + if(memh->tag1 == MEMFREE && memh->tag2 == MEMFREE) { + MemorY_ErroR(memh->name,"double free"); + return(-1); + } + + mem_lock_thread(); + + if ((memh->tag1 == MEMTAG1) && (memh->tag2 == MEMTAG2) && ((memh->len & 0x3) == 0)) { + memt = (MemTail *)(((char *) memh) + sizeof(MemHead) + memh->len); + if (memt->tag3 == MEMTAG3){ + + memh->tag1 = MEMFREE; + memh->tag2 = MEMFREE; + memt->tag3 = MEMFREE; + /* after tags !!! */ + rem_memblock(memh); + + mem_unlock_thread(); + + return(0); + } + error = 2; + MemorY_ErroR(memh->name,"end corrupt"); + name = check_memlist(memh); + if (name != 0){ + if (name != memh->name) MemorY_ErroR(name,"is also corrupt"); + } + } else{ + error = -1; + name = check_memlist(memh); + if (name == 0) MemorY_ErroR("free","pointer not in memlist"); + else MemorY_ErroR(name,"error in header"); + } + + totblock--; + /* here a DUMP should happen */ + + mem_unlock_thread(); + + return(error); +} + +/* --------------------------------------------------------------------- */ +/* local functions */ +/* --------------------------------------------------------------------- */ + +static void addtail(volatile localListBase *listbase, void *vlink) +{ + struct localLink *link= vlink; + + if (link == 0) return; + if (listbase == 0) return; + + link->next = 0; + link->prev = listbase->last; + + if (listbase->last) ((struct localLink *)listbase->last)->next = link; + if (listbase->first == 0) listbase->first = link; + listbase->last = link; +} + +static void remlink(volatile localListBase *listbase, void *vlink) +{ + struct localLink *link= vlink; + + if (link == 0) return; + if (listbase == 0) return; + + if (link->next) link->next->prev = link->prev; + if (link->prev) link->prev->next = link->next; + + if (listbase->last == link) listbase->last = link->prev; + if (listbase->first == link) listbase->first = link->next; +} + +static void rem_memblock(MemHead *memh) +{ + remlink(membase,&memh->next); + if (memh->prev) { + if (memh->next) + MEMNEXT(memh->prev)->nextname = MEMNEXT(memh->next)->name; + else + MEMNEXT(memh->prev)->nextname = NULL; + } + + totblock--; + mem_in_use -= memh->len; + +#if defined(AMIGA) || defined(__BeOS) || defined(WIN32) + free(memh); +#else + + if(memh->mmap) { + mmap_in_use -= memh->len; + if (munmap(memh, memh->len + sizeof(MemHead) + sizeof(MemTail))) + printf("Couldn't unmap memory %s\n", memh->name); + } + else { + if(malloc_debug_memset && memh->len) + memset(memh+1, 255, memh->len); + free(memh); + } +#endif +} + +static void MemorY_ErroR(const char *block, const char *error) +{ + print_error("Memoryblock %s: %s\n",block, error); +} + +static const char *check_memlist(MemHead *memh) +{ + MemHead *forw,*back,*forwok,*backok; + const char *name; + + forw = membase->first; + if (forw) forw = MEMNEXT(forw); + forwok = 0; + while(forw){ + if (forw->tag1 != MEMTAG1 || forw->tag2 != MEMTAG2) break; + forwok = forw; + if (forw->next) forw = MEMNEXT(forw->next); + else forw = 0; + } + + back = (MemHead *) membase->last; + if (back) back = MEMNEXT(back); + backok = 0; + while(back){ + if (back->tag1 != MEMTAG1 || back->tag2 != MEMTAG2) break; + backok = back; + if (back->prev) back = MEMNEXT(back->prev); + else back = 0; + } + + if (forw != back) return ("MORE THAN 1 MEMORYBLOCK CORRUPT"); + + if (forw == 0 && back == 0){ + /* geen foute headers gevonden dan maar op zoek naar memblock*/ + + forw = membase->first; + if (forw) forw = MEMNEXT(forw); + forwok = 0; + while(forw){ + if (forw == memh) break; + if (forw->tag1 != MEMTAG1 || forw->tag2 != MEMTAG2) break; + forwok = forw; + if (forw->next) forw = MEMNEXT(forw->next); + else forw = 0; + } + if (forw == 0) return (0); + + back = (MemHead *) membase->last; + if (back) back = MEMNEXT(back); + backok = 0; + while(back){ + if (back == memh) break; + if (back->tag1 != MEMTAG1 || back->tag2 != MEMTAG2) break; + backok = back; + if (back->prev) back = MEMNEXT(back->prev); + else back = 0; + } + } + + if (forwok) name = forwok->nextname; + else name = "No name found"; + + if (forw == memh){ + /* voor alle zekerheid wordt dit block maar uit de lijst gehaald */ + if (forwok){ + if (backok){ + forwok->next = (MemHead *)&backok->next; + backok->prev = (MemHead *)&forwok->next; + forwok->nextname = backok->name; + } else{ + forwok->next = 0; + membase->last = (struct localLink *) &forwok->next; +/* membase->last = (struct Link *) &forwok->next; */ + } + } else{ + if (backok){ + backok->prev = 0; + membase->first = &backok->next; + } else{ + membase->first = membase->last = 0; + } + } + } else{ + MemorY_ErroR(name,"Additional error in header"); + return("Additional error in header"); + } + + return(name); +} + +/* eof */ diff --git a/intern/guardedalloc/make/msvc_6_0/guardedalloc.dsp b/intern/guardedalloc/make/msvc_6_0/guardedalloc.dsp new file mode 100644 index 00000000000..21cc20e14f1 --- /dev/null +++ b/intern/guardedalloc/make/msvc_6_0/guardedalloc.dsp @@ -0,0 +1,114 @@ +# Microsoft Developer Studio Project File - Name="guardedalloc" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=guardedalloc - 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 "guardedalloc.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 "guardedalloc.mak" CFG="guardedalloc - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "guardedalloc - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "guardedalloc - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "guardedalloc - 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 "..\..\..\..\obj\windows\intern\guardedalloc\" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\guardedalloc\" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\.." /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# 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:"..\..\..\..\obj\windows\intern\guardedalloc\libguardedalloc.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\guardedalloc\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\guardedalloc\*.lib ..\..\..\..\..\lib\windows\guardedalloc\lib\*.a ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "guardedalloc - 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 "..\..\..\..\obj\windows\intern\guardedalloc\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\guardedalloc\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\.." /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# 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:"..\..\..\..\obj\windows\intern\guardedalloc\debug\libguardedalloc.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\guardedalloc\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\guardedalloc\debug\*.lib ..\..\..\..\..\lib\windows\guardedalloc\lib\debug\*.a ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "guardedalloc - Win32 Release" +# Name "guardedalloc - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\intern\mallocn.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Group "extern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\MEM_guardedalloc.h +# End Source File +# End Group +# End Group +# End Target +# End Project diff --git a/intern/guardedalloc/make/msvc_7_0/guardedalloc.sln b/intern/guardedalloc/make/msvc_7_0/guardedalloc.sln new file mode 100644 index 00000000000..b2557eee949 --- /dev/null +++ b/intern/guardedalloc/make/msvc_7_0/guardedalloc.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "guardedalloc", "guardedalloc.vcproj", "{1CC733F1-6AB5-4904-8F63-C08C46B79DD9}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {1CC733F1-6AB5-4904-8F63-C08C46B79DD9}.Debug.ActiveCfg = Debug|Win32 + {1CC733F1-6AB5-4904-8F63-C08C46B79DD9}.Debug.Build.0 = Debug|Win32 + {1CC733F1-6AB5-4904-8F63-C08C46B79DD9}.Release.ActiveCfg = Release|Win32 + {1CC733F1-6AB5-4904-8F63-C08C46B79DD9}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/intern/guardedalloc/make/msvc_7_0/guardedalloc.vcproj b/intern/guardedalloc/make/msvc_7_0/guardedalloc.vcproj new file mode 100644 index 00000000000..cb3490716fa --- /dev/null +++ b/intern/guardedalloc/make/msvc_7_0/guardedalloc.vcproj @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/guardedalloc/test/Makefile b/intern/guardedalloc/test/Makefile new file mode 100644 index 00000000000..760695bd19e --- /dev/null +++ b/intern/guardedalloc/test/Makefile @@ -0,0 +1,55 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# Test the guarded memory module +# + +LIBNAME = guardedalloc +SOURCEDIR = intern/$(LIBNAME)/test +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = simpletest + +include nan_subdirs.mk + +include nan_compile.mk +include nan_link.mk + +TESTLIBS = $(OCGDIR)/intern/$(LIBNAME)/$(DEBUG_DIR)lib$(LIBNAME).a + +all debug:: + @echo "****> linking $@ in $(SOURCEDIR)" + $(CC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)memtest $(DIR)/memtest.o $(TESTLIBS) + +clean:: + $(RM) $(DIR)/memtest $(DIR)/debug/memtest + +test:: $(DIR)/memtest + $(DIR)/memtest $(NAN_TEST_VERBOSITY) + diff --git a/intern/guardedalloc/test/simpletest/Makefile b/intern/guardedalloc/test/simpletest/Makefile new file mode 100644 index 00000000000..8f1db9c4cac --- /dev/null +++ b/intern/guardedalloc/test/simpletest/Makefile @@ -0,0 +1,44 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# Test the guarded memory module +# + +LIBNAME = guardedalloc +DIR = $(OCGDIR)/intern/$(LIBNAME)/test + +# we don't want a library here, only object files: +ALLTARGETS = $(OBJS) + +include nan_compile.mk + +# this module's header +CPPFLAGS = -I../.. + diff --git a/intern/guardedalloc/test/simpletest/memtest.c b/intern/guardedalloc/test/simpletest/memtest.c new file mode 100644 index 00000000000..c35af2d9ce2 --- /dev/null +++ b/intern/guardedalloc/test/simpletest/memtest.c @@ -0,0 +1,162 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * Simple test of memory. + */ + + + +/* Number of chunks to test with */ +#define NUM_BLOCKS 10 + +#include +#include +#include +#include "MEM_guardedalloc.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +int main (int argc, char *argv[]) +{ + int verbose = 0; + int error_status = 0; + int retval = 0; + int *ip; + + void *p[NUM_BLOCKS]; + int i = 0; + + /* ----------------------------------------------------------------- */ + switch (argc) { + case 2: + verbose = atoi(argv[1]); + if (verbose < 0) verbose = 0; + break; + case 1: + default: + verbose = 0; + } + if (verbose) { + fprintf(stderr,"\n*** Simple memory test\n|\n"); + } + + /* ----------------------------------------------------------------- */ + /* Round one, do a normal allocation, and free the blocks again. */ + /* ----------------------------------------------------------------- */ + /* flush mem lib output to stderr */ + MEM_set_error_callback(stderr); + + for (i = 0; i < NUM_BLOCKS; i++) { + int blocksize = 10000; + char tagstring[1000]; + if (verbose >1) printf("|--* Allocating block %d\n", i); + sprintf(tagstring,"Memblock no. %d : ", i); + p[i]= MEM_callocN(blocksize, strdup(tagstring)); + } + + /* report on that */ + if (verbose > 1) MEM_printmemlist(); + + /* memory is there: test it */ + error_status = MEM_check_memory_integrity(); + + if (verbose) { + if (error_status) { + fprintf(stderr, "|--* Memory test FAILED\n|\n"); + } else { + fprintf(stderr, "|--* Memory tested as good (as it should be)\n|\n"); + } + } + + for (i = 0; i < NUM_BLOCKS; i++) { + MEM_freeN(p[i]); + } + + /* ----------------------------------------------------------------- */ + /* Round two, do a normal allocation, and corrupt some blocks. */ + /* ----------------------------------------------------------------- */ + /* switch off, because it will complain about some things. */ + MEM_set_error_callback(NULL); + + for (i = 0; i < NUM_BLOCKS; i++) { + int blocksize = 10000; + char tagstring[1000]; + if (verbose >1) printf("|--* Allocating block %d\n", i); + sprintf(tagstring,"Memblock no. %d : ", i); + p[i]= MEM_callocN(blocksize, strdup(tagstring)); + } + + /* now corrupt a few blocks...*/ + ip = (int*) p[5] - 50 ; + for (i = 0; i< 1000; i++,ip++) *ip = i+1; + ip = (int*) p[6]; + *(ip+10005) = 0; + + retval = MEM_check_memory_integrity(); + + /* the test should have failed */ + error_status |= !retval; + if (verbose) { + if (retval) { + fprintf(stderr, "|--* Memory test failed (as it should be)\n"); + } else { + fprintf(stderr, "|--* Memory test FAILED to find corrupted blocks \n"); + } + } + + for (i = 0; i < NUM_BLOCKS; i++) { + MEM_freeN(p[i]); + } + + + if (verbose && error_status) { + fprintf(stderr,"|--* Memory was corrupted\n"); + } + /* ----------------------------------------------------------------- */ + if (verbose) { + if (error_status) { + fprintf(stderr,"|\n|--* Errors were detected\n"); + } else { + fprintf(stderr,"|\n|--* Test exited succesfully\n"); + } + + fprintf(stderr,"|\n*** Finished test\n\n"); + } + return error_status; +} + + diff --git a/intern/iksolver/CMakeLists.txt b/intern/iksolver/CMakeLists.txt new file mode 100644 index 00000000000..c0990c2a405 --- /dev/null +++ b/intern/iksolver/CMakeLists.txt @@ -0,0 +1,35 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC intern ../moto/include ../memutil) + +FILE(GLOB SRC intern/*.cpp) + +BLENDERLIB_NOLIST(blender_IK "${SRC}" "${INC}") +#, libtype=['blender'], priority = [10] ) diff --git a/intern/iksolver/Makefile b/intern/iksolver/Makefile new file mode 100644 index 00000000000..b439dcf8fa3 --- /dev/null +++ b/intern/iksolver/Makefile @@ -0,0 +1,56 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# iksolver main makefile. +# + +include nan_definitions.mk + +LIBNAME = iksolver +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_IKSOLVER) ] || mkdir $(NAN_IKSOLVER) + @[ -d $(NAN_IKSOLVER)/include ] || mkdir $(NAN_IKSOLVER)/include + @[ -d $(NAN_IKSOLVER)/lib ] || mkdir $(NAN_IKSOLVER)/lib + @[ -d $(NAN_IKSOLVER)/lib/debug ] || mkdir $(NAN_IKSOLVER)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libiksolver.a $(NAN_IKSOLVER)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libiksolver.a $(NAN_IKSOLVER)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_IKSOLVER)/lib/libiksolver.a + ranlib $(NAN_IKSOLVER)/lib/debug/libiksolver.a +endif + @../tools/cpifdiff.sh extern/*.h $(NAN_IKSOLVER)/include/ + diff --git a/intern/iksolver/SConscript b/intern/iksolver/SConscript new file mode 100644 index 00000000000..81bf61dfcd8 --- /dev/null +++ b/intern/iksolver/SConscript @@ -0,0 +1,8 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.cpp') + +incs = 'intern ../moto/include ../memutil' + +env.BlenderLib ('blender_IK', sources, Split(incs), [], libtype='blender', priority=10 ) diff --git a/intern/iksolver/extern/IK_solver.h b/intern/iksolver/extern/IK_solver.h new file mode 100644 index 00000000000..bf53a9e3724 --- /dev/null +++ b/intern/iksolver/extern/IK_solver.h @@ -0,0 +1,172 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * + * @author Laurence, Brecht + * @mainpage IK - Blender inverse kinematics module. + * + * @section about About the IK module + * + * This module allows you to create segments and form them into + * tree. You can then define a goal points that the end of a given + * segment should attempt to reach - an inverse kinematic problem. + * This module will then modify the segments in the tree in order + * to get the as near as possible to the goal. This solver uses an + * inverse jacobian method to find a solution. + * + * @section issues Known issues with this IK solver. + * + * - There is currently no support for joint constraints in the + * solver. This is within the realms of possibility - please ask + * if this functionality is required. + * - The solver is slow, inverse jacobian methods in general give + * 'smooth' solutions and the method is also very flexible, it + * does not rely on specific angle parameterization and can be + * extended to deal with different joint types and joint + * constraints. However it is not suitable for real time use. + * Other algorithms exist which are more suitable for real-time + * applications, please ask if this functionality is required. + * + * @section dependencies Dependencies + * + * This module only depends on Moto. + */ + +#ifndef NAN_INCLUDED_IK_solver_h +#define NAN_INCLUDED_IK_solver_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Typical order of calls for solving an IK problem: + * + * - create number of IK_Segment's and set their parents and transforms + * - create an IK_Solver + * - set a number of goals for the IK_Solver to solve + * - call IK_Solve + * - free the IK_Solver + * - get basis and translation changes from segments + * - free all segments + */ + +/** + * IK_Segment defines a single segment of an IK tree. + * - Individual segments are always defined in local coordinates. + * - The segment is assumed to be oriented in the local + * y-direction. + * - start is the start of the segment relative to the end + * of the parent segment. + * - rest_basis is a column major matrix defineding the rest + * position (w.r.t. which the limits are defined), must + * be a pure rotation + * - basis is a column major matrix defining the current change + * from the rest basis, must be a pure rotation + * - length is the length of the bone. + * + * - basis_change and translation_change respectively define + * the change in rotation or translation. basis_change is a + * column major 3x3 matrix. + * + * The local transformation is then defined as: + * start * rest_basis * basis * basis_change * translation_change * translate(0,length,0) + * + */ + +typedef void IK_Segment; + +enum IK_SegmentFlag { + IK_XDOF = 1, + IK_YDOF = 2, + IK_ZDOF = 4, + IK_TRANS_XDOF = 8, + IK_TRANS_YDOF = 16, + IK_TRANS_ZDOF = 32 +}; + +typedef enum IK_SegmentAxis { + IK_X = 0, + IK_Y = 1, + IK_Z = 2, + IK_TRANS_X = 3, + IK_TRANS_Y = 4, + IK_TRANS_Z = 5 +} IK_SegmentAxis; + +extern IK_Segment *IK_CreateSegment(int flag); +extern void IK_FreeSegment(IK_Segment *seg); + +extern void IK_SetParent(IK_Segment *seg, IK_Segment *parent); +extern void IK_SetTransform(IK_Segment *seg, float start[3], float rest_basis[][3], float basis[][3], float length); +extern void IK_SetLimit(IK_Segment *seg, IK_SegmentAxis axis, float lmin, float lmax); +extern void IK_SetStiffness(IK_Segment *seg, IK_SegmentAxis axis, float stiffness); + +extern void IK_GetBasisChange(IK_Segment *seg, float basis_change[][3]); +extern void IK_GetTranslationChange(IK_Segment *seg, float *translation_change); + +/** + * An IK_Solver must be created to be able to execute the solver. + * + * An arbitray number of goals can be created, stating that a given + * end effector must have a given position or rotation. If multiple + * goals are specified, they can be weighted (range 0..1) to get + * some control over their importance. + * + * IK_Solve will execute the solver, that will run until either the + * system converges, or a maximum number of iterations is reached. + * It returns 1 if the system converged, 0 otherwise. + */ + +typedef void IK_Solver; + +IK_Solver *IK_CreateSolver(IK_Segment *root); +void IK_FreeSolver(IK_Solver *solver); + +void IK_SolverAddGoal(IK_Solver *solver, IK_Segment *tip, float goal[3], float weight); +void IK_SolverAddGoalOrientation(IK_Solver *solver, IK_Segment *tip, float goal[][3], float weight); +void IK_SolverSetPoleVectorConstraint(IK_Solver *solver, IK_Segment *tip, float goal[3], float polegoal[3], float poleangle, int getangle); +float IK_SolverGetPoleAngle(IK_Solver *solver); + +int IK_Solve(IK_Solver *solver, float tolerance, int max_iterations); + + +#ifdef __cplusplus +} +#endif + +#endif // NAN_INCLUDED_IK_solver_h + diff --git a/intern/iksolver/intern/IK_QJacobian.cpp b/intern/iksolver/intern/IK_QJacobian.cpp new file mode 100644 index 00000000000..1dd4d086aa8 --- /dev/null +++ b/intern/iksolver/intern/IK_QJacobian.cpp @@ -0,0 +1,443 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original Author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "IK_QJacobian.h" +#include "TNT/svd.h" + +IK_QJacobian::IK_QJacobian() +: m_sdls(true), m_min_damp(1.0) +{ +} + +IK_QJacobian::~IK_QJacobian() +{ +} + +void IK_QJacobian::ArmMatrices(int dof, int task_size) +{ + m_dof = dof; + m_task_size = task_size; + + m_jacobian.newsize(task_size, dof); + m_jacobian = 0; + + m_alpha.newsize(dof); + m_alpha = 0; + + m_null.newsize(dof, dof); + + m_d_theta.newsize(dof); + m_d_theta_tmp.newsize(dof); + + m_norm.newsize(dof); + m_norm = 0.0; + + m_beta.newsize(task_size); + + m_weight.newsize(dof); + m_weight_sqrt.newsize(dof); + m_weight = 1.0; + m_weight_sqrt = 1.0; + + if (task_size >= dof) { + m_transpose = false; + + m_jacobian_tmp.newsize(task_size, dof); + + m_svd_u.newsize(task_size, dof); + m_svd_v.newsize(dof, dof); + m_svd_w.newsize(dof); + + m_work1.newsize(task_size); + m_work2.newsize(dof); + + m_svd_u_t.newsize(dof, task_size); + m_svd_u_beta.newsize(dof); + } + else { + // use the SVD of the transpose jacobian, it works just as well + // as the original, and often allows using smaller matrices. + m_transpose = true; + + m_jacobian_tmp.newsize(dof, task_size); + + m_svd_u.newsize(task_size, task_size); + m_svd_v.newsize(dof, task_size); + m_svd_w.newsize(task_size); + + m_work1.newsize(dof); + m_work2.newsize(task_size); + + m_svd_u_t.newsize(task_size, task_size); + m_svd_u_beta.newsize(task_size); + } +} + +void IK_QJacobian::SetBetas(int id, int, const MT_Vector3& v) +{ + m_beta[id] = v.x(); + m_beta[id+1] = v.y(); + m_beta[id+2] = v.z(); +} + +void IK_QJacobian::SetDerivatives(int id, int dof_id, const MT_Vector3& v) +{ + m_jacobian[id][dof_id] = v.x()*m_weight_sqrt[dof_id]; + m_jacobian[id+1][dof_id] = v.y()*m_weight_sqrt[dof_id]; + m_jacobian[id+2][dof_id] = v.z()*m_weight_sqrt[dof_id]; +} + +void IK_QJacobian::Invert() +{ + if (m_transpose) { + // SVD will decompose Jt into V*W*Ut with U,V orthogonal and W diagonal, + // so J = U*W*Vt and Jinv = V*Winv*Ut + TNT::transpose(m_jacobian, m_jacobian_tmp); + TNT::SVD(m_jacobian_tmp, m_svd_v, m_svd_w, m_svd_u, m_work1, m_work2); + } + else { + // SVD will decompose J into U*W*Vt with U,V orthogonal and W diagonal, + // so Jinv = V*Winv*Ut + m_jacobian_tmp = m_jacobian; + TNT::SVD(m_jacobian_tmp, m_svd_u, m_svd_w, m_svd_v, m_work1, m_work2); + } + + if (m_sdls) + InvertSDLS(); + else + InvertDLS(); +} + +bool IK_QJacobian::ComputeNullProjection() +{ + MT_Scalar epsilon = 1e-10; + + // compute null space projection based on V + int i, j, rank = 0; + for (i = 0; i < m_svd_w.size(); i++) + if (m_svd_w[i] > epsilon) + rank++; + + if (rank < m_task_size) + return false; + + TMatrix basis(m_svd_v.num_rows(), rank); + TMatrix basis_t(rank, m_svd_v.num_rows()); + int b = 0; + + for (i = 0; i < m_svd_w.size(); i++) + if (m_svd_w[i] > epsilon) { + for (j = 0; j < m_svd_v.num_rows(); j++) + basis[j][b] = m_svd_v[j][i]; + b++; + } + + TNT::transpose(basis, basis_t); + TNT::matmult(m_null, basis, basis_t); + + for (i = 0; i < m_null.num_rows(); i++) + for (j = 0; j < m_null.num_cols(); j++) + if (i == j) + m_null[i][j] = 1.0 - m_null[i][j]; + else + m_null[i][j] = -m_null[i][j]; + + return true; +} + +void IK_QJacobian::SubTask(IK_QJacobian& jacobian) +{ + if (!ComputeNullProjection()) + return; + + // restrict lower priority jacobian + jacobian.Restrict(m_d_theta, m_null); + + // add angle update from lower priority + jacobian.Invert(); + + // note: now damps secondary angles with minimum damping value from + // SDLS, to avoid shaking when the primary task is near singularities, + // doesn't work well at all + int i; + for (i = 0; i < m_d_theta.size(); i++) + m_d_theta[i] = m_d_theta[i] + /*m_min_damp**/jacobian.AngleUpdate(i); +} + +void IK_QJacobian::Restrict(TVector& d_theta, TMatrix& null) +{ + // subtract part already moved by higher task from beta + TVector beta_sub(m_beta.size()); + + TNT::matmult(beta_sub, m_jacobian, d_theta); + m_beta = m_beta - beta_sub; + + // note: should we be using the norm of the unrestricted jacobian for SDLS? + + // project jacobian on to null space of higher priority task + TMatrix jacobian_copy(m_jacobian); + TNT::matmult(m_jacobian, jacobian_copy, null); +} + +void IK_QJacobian::InvertSDLS() +{ + // Compute the dampeds least squeares pseudo inverse of J. + // + // Since J is usually not invertible (most of the times it's not even + // square), the psuedo inverse is used. This gives us a least squares + // solution. + // + // This is fine when the J*Jt is of full rank. When J*Jt is near to + // singular the least squares inverse tries to minimize |J(dtheta) - dX)| + // and doesn't try to minimize dTheta. This results in eratic changes in + // angle. The damped least squares minimizes |dtheta| to try and reduce this + // erratic behaviour. + // + // The selectively damped least squares (SDLS) is used here instead of the + // DLS. The SDLS damps individual singular values, instead of using a single + // damping term. + + MT_Scalar max_angle_change = MT_PI/4.0; + MT_Scalar epsilon = 1e-10; + int i, j; + + m_d_theta = 0; + m_min_damp = 1.0; + + for (i = 0; i < m_dof; i++) { + m_norm[i] = 0.0; + for (j = 0; j < m_task_size; j+=3) { + MT_Scalar n = 0.0; + n += m_jacobian[j][i]*m_jacobian[j][i]; + n += m_jacobian[j+1][i]*m_jacobian[j+1][i]; + n += m_jacobian[j+2][i]*m_jacobian[j+2][i]; + m_norm[i] += sqrt(n); + } + } + + for (i = 0; i max_dtheta) + max_dtheta = abs_dtheta; + } + + M *= wInv; + + // compute damping term and damp the dTheta's + MT_Scalar gamma = max_angle_change; + if (N < M) + gamma *= N/M; + + MT_Scalar damp = (gamma < max_dtheta)? gamma/max_dtheta: 1.0; + + for (j = 0; j < m_d_theta.size(); j++) { + // slight hack: we do 0.80*, so that if there is some oscillation, + // the system can still converge (for joint limits). also, it's + // better to go a little to slow than to far + + MT_Scalar dofdamp = damp/m_weight[j]; + if (dofdamp > 1.0) dofdamp = 1.0; + + m_d_theta[j] += 0.80*dofdamp*m_d_theta_tmp[j]; + } + + if (damp < m_min_damp) + m_min_damp = damp; + } + + // weight + prevent from doing angle updates with angles > max_angle_change + MT_Scalar max_angle = 0.0, abs_angle; + + for (j = 0; j max_angle) + max_angle = abs_angle; + } + + if (max_angle > max_angle_change) { + MT_Scalar damp = (max_angle_change)/(max_angle_change + max_angle); + + for (j = 0; j epsilon && m_svd_w[i] < w_min) + w_min = m_svd_w[i]; + } + + // compute lambda damping term + + MT_Scalar d = x_length/max_angle_change; + MT_Scalar lambda; + + if (w_min <= d/2) + lambda = d/2; + else if (w_min < d) + lambda = sqrt(w_min*(d - w_min)); + else + lambda = 0.0; + + lambda *= lambda; + + if (lambda > 10) + lambda = 10; + + // immediately multiply with Beta, so we can do matrix*vector products + // rather than matrix*matrix products + + // compute Ut*Beta + TNT::transpose(m_svd_u, m_svd_u_t); + TNT::matmult(m_svd_u_beta, m_svd_u_t, m_beta); + + m_d_theta = 0.0; + + for (i = 0; i < m_svd_w.size(); i++) { + if (m_svd_w[i] > epsilon) { + MT_Scalar wInv = m_svd_w[i]/(m_svd_w[i]*m_svd_w[i] + lambda); + + // compute V*Winv*Ut*Beta + m_svd_u_beta[i] *= wInv; + + for (j = 0; j mx) + mx = dtheta_abs; + } + + return mx; +} + +void IK_QJacobian::SetDoFWeight(int dof, MT_Scalar weight) +{ + m_weight[dof] = weight; + m_weight_sqrt[dof] = sqrt(weight); +} + diff --git a/intern/iksolver/intern/IK_QJacobian.h b/intern/iksolver/intern/IK_QJacobian.h new file mode 100644 index 00000000000..3e20e4a9fd0 --- /dev/null +++ b/intern/iksolver/intern/IK_QJacobian.h @@ -0,0 +1,118 @@ + +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original Author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_IK_QJacobian_h + +#define NAN_INCLUDED_IK_QJacobian_h + +#include "TNT/cmat.h" +#include +#include "MT_Vector3.h" + +class IK_QJacobian +{ +public: + typedef TNT::Matrix TMatrix; + typedef TNT::Vector TVector; + + IK_QJacobian(); + ~IK_QJacobian(); + + // Call once to initialize + void ArmMatrices(int dof, int task_size); + void SetDoFWeight(int dof, MT_Scalar weight); + + // Iteratively called + void SetBetas(int id, int size, const MT_Vector3& v); + void SetDerivatives(int id, int dof_id, const MT_Vector3& v); + + void Invert(); + + MT_Scalar AngleUpdate(int dof_id) const; + MT_Scalar AngleUpdateNorm() const; + + // DoF locking for inner clamping loop + void Lock(int dof_id, MT_Scalar delta); + + // Secondary task + bool ComputeNullProjection(); + + void Restrict(TVector& d_theta, TMatrix& null); + void SubTask(IK_QJacobian& jacobian); + +private: + + void InvertSDLS(); + void InvertDLS(); + + int m_dof, m_task_size; + bool m_transpose; + + // the jacobian matrix and it's null space projector + TMatrix m_jacobian, m_jacobian_tmp; + TMatrix m_null; + + /// the vector of intermediate betas + TVector m_beta; + + /// the vector of computed angle changes + TVector m_d_theta; + + /// space required for SVD computation + + TVector m_svd_w; + TMatrix m_svd_v; + TMatrix m_svd_u; + TVector m_work1; + TVector m_work2; + + TMatrix m_svd_u_t; + TVector m_svd_u_beta; + + // space required for SDLS + + bool m_sdls; + TVector m_norm; + TVector m_d_theta_tmp; + MT_Scalar m_min_damp; + + // null space task vector + TVector m_alpha; + + // dof weighting + TVector m_weight; + TVector m_weight_sqrt; +}; + +#endif + diff --git a/intern/iksolver/intern/IK_QJacobianSolver.cpp b/intern/iksolver/intern/IK_QJacobianSolver.cpp new file mode 100644 index 00000000000..17750a7195f --- /dev/null +++ b/intern/iksolver/intern/IK_QJacobianSolver.cpp @@ -0,0 +1,394 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original Author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include "IK_QJacobianSolver.h" +#include "MT_Quaternion.h" + +//#include "analyze.h" +IK_QJacobianSolver::IK_QJacobianSolver() +{ + m_poleconstraint = false; + m_getpoleangle = false; + m_rootmatrix.setIdentity(); +} + +MT_Scalar IK_QJacobianSolver::ComputeScale() +{ + std::vector::iterator seg; + float length = 0.0f; + + for (seg = m_segments.begin(); seg != m_segments.end(); seg++) + length += (*seg)->MaxExtension(); + + if(length == 0.0f) + return 1.0f; + else + return 1.0f/length; +} + +void IK_QJacobianSolver::Scale(float scale, std::list& tasks) +{ + std::list::iterator task; + std::vector::iterator seg; + + for (task = tasks.begin(); task != tasks.end(); task++) + (*task)->Scale(scale); + + for (seg = m_segments.begin(); seg != m_segments.end(); seg++) + (*seg)->Scale(scale); + + m_rootmatrix.getOrigin() *= scale; + m_goal *= scale; + m_polegoal *= scale; +} + +void IK_QJacobianSolver::AddSegmentList(IK_QSegment *seg) +{ + m_segments.push_back(seg); + + IK_QSegment *child; + for (child = seg->Child(); child; child = child->Sibling()) + AddSegmentList(child); +} + +bool IK_QJacobianSolver::Setup(IK_QSegment *root, std::list& tasks) +{ + m_segments.clear(); + AddSegmentList(root); + + // assign each segment a unique id for the jacobian + std::vector::iterator seg; + int num_dof = 0; + + for (seg = m_segments.begin(); seg != m_segments.end(); seg++) { + (*seg)->SetDoFId(num_dof); + num_dof += (*seg)->NumberOfDoF(); + } + + if (num_dof == 0) + return false; + + // compute task id's and assing weights to task + int primary_size = 0, primary = 0; + int secondary_size = 0, secondary = 0; + MT_Scalar primary_weight = 0.0, secondary_weight = 0.0; + std::list::iterator task; + + for (task = tasks.begin(); task != tasks.end(); task++) { + IK_QTask *qtask = *task; + + if (qtask->Primary()) { + qtask->SetId(primary_size); + primary_size += qtask->Size(); + primary_weight += qtask->Weight(); + primary++; + } + else { + qtask->SetId(secondary_size); + secondary_size += qtask->Size(); + secondary_weight += qtask->Weight(); + secondary++; + } + } + + if (primary_size == 0 || MT_fuzzyZero(primary_weight)) + return false; + + m_secondary_enabled = (secondary > 0); + + // rescale weights of tasks to sum up to 1 + MT_Scalar primary_rescale = 1.0/primary_weight; + MT_Scalar secondary_rescale; + if (MT_fuzzyZero(secondary_weight)) + secondary_rescale = 0.0; + else + secondary_rescale = 1.0/secondary_weight; + + for (task = tasks.begin(); task != tasks.end(); task++) { + IK_QTask *qtask = *task; + + if (qtask->Primary()) + qtask->SetWeight(qtask->Weight()*primary_rescale); + else + qtask->SetWeight(qtask->Weight()*secondary_rescale); + } + + // set matrix sizes + m_jacobian.ArmMatrices(num_dof, primary_size); + if (secondary > 0) + m_jacobian_sub.ArmMatrices(num_dof, secondary_size); + + // set dof weights + int i; + + for (seg = m_segments.begin(); seg != m_segments.end(); seg++) + for (i = 0; i < (*seg)->NumberOfDoF(); i++) + m_jacobian.SetDoFWeight((*seg)->DoFId()+i, (*seg)->Weight(i)); + + return true; +} + +void IK_QJacobianSolver::SetPoleVectorConstraint(IK_QSegment *tip, MT_Vector3& goal, MT_Vector3& polegoal, float poleangle, bool getangle) +{ + m_poleconstraint = true; + m_poletip = tip; + m_goal = goal; + m_polegoal = polegoal; + m_poleangle = (getangle)? 0.0f: poleangle; + m_getpoleangle = getangle; +} + +static MT_Scalar safe_acos(MT_Scalar f) +{ + // acos that does not return NaN with rounding errors + if (f <= -1.0f) return MT_PI; + else if (f >= 1.0f) return 0.0; + else return acos(f); +} + +static MT_Vector3 normalize(const MT_Vector3& v) +{ + // a sane normalize function that doesn't give (1, 0, 0) in case + // of a zero length vector, like MT_Vector3.normalize + MT_Scalar len = v.length(); + return MT_fuzzyZero(len)? MT_Vector3(0, 0, 0): v/len; +} + +static float angle(const MT_Vector3& v1, const MT_Vector3& v2) +{ + return safe_acos(v1.dot(v2)); +} + +void IK_QJacobianSolver::ConstrainPoleVector(IK_QSegment *root, std::list& tasks) +{ + // this function will be called before and after solving. calling it before + // solving gives predictable solutions by rotating towards the solution, + // and calling it afterwards ensures the solution is exact. + + if(!m_poleconstraint) + return; + + // disable pole vector constraint in case of multiple position tasks + std::list::iterator task; + int positiontasks = 0; + + for (task = tasks.begin(); task != tasks.end(); task++) + if((*task)->PositionTask()) + positiontasks++; + + if (positiontasks >= 2) { + m_poleconstraint = false; + return; + } + + // get positions and rotations + root->UpdateTransform(m_rootmatrix); + + const MT_Vector3 rootpos = root->GlobalStart(); + const MT_Vector3 endpos = m_poletip->GlobalEnd(); + const MT_Matrix3x3& rootbasis = root->GlobalTransform().getBasis(); + + // construct "lookat" matrices (like gluLookAt), based on a direction and + // an up vector, with the direction going from the root to the end effector + // and the up vector going from the root to the pole constraint position. + MT_Vector3 dir = normalize(endpos - rootpos); + MT_Vector3 rootx= rootbasis.getColumn(0); + MT_Vector3 rootz= rootbasis.getColumn(2); + MT_Vector3 up = rootx*cos(m_poleangle) + rootz*sin(m_poleangle); + + // in post, don't rotate towards the goal but only correct the pole up + MT_Vector3 poledir = (m_getpoleangle)? dir: normalize(m_goal - rootpos); + MT_Vector3 poleup = normalize(m_polegoal - rootpos); + + MT_Matrix3x3 mat, polemat; + + mat[0] = normalize(MT_cross(dir, up)); + mat[1] = MT_cross(mat[0], dir); + mat[2] = -dir; + + polemat[0] = normalize(MT_cross(poledir, poleup)); + polemat[1] = MT_cross(polemat[0], poledir); + polemat[2] = -poledir; + + if(m_getpoleangle) { + // we compute the pole angle that to rotate towards the target + m_poleangle = angle(mat[1], polemat[1]); + + if(rootz.dot(mat[1]*cos(m_poleangle) + mat[0]*sin(m_poleangle)) > 0.0f) + m_poleangle = -m_poleangle; + + // solve again, with the pole angle we just computed + m_getpoleangle = false; + ConstrainPoleVector(root, tasks); + } + else { + // now we set as root matrix the difference between the current and + // desired rotation based on the pole vector constraint. we use + // transpose instead of inverse because we have orthogonal matrices + // anyway, and in case of a singular matrix we don't get NaN's. + MT_Transform trans(MT_Point3(0, 0, 0), polemat.transposed()*mat); + m_rootmatrix = trans*m_rootmatrix; + } +} + +bool IK_QJacobianSolver::UpdateAngles(MT_Scalar& norm) +{ + // assing each segment a unique id for the jacobian + std::vector::iterator seg; + IK_QSegment *qseg, *minseg = NULL; + MT_Scalar minabsdelta = 1e10, absdelta; + MT_Vector3 delta, mindelta; + bool locked = false, clamp[3]; + int i, mindof = 0; + + // here we check if any angle limits were violated. angles whose clamped + // position is the same as it was before, are locked immediate. of the + // other violation angles the most violating angle is rememberd + for (seg = m_segments.begin(); seg != m_segments.end(); seg++) { + qseg = *seg; + if (qseg->UpdateAngle(m_jacobian, delta, clamp)) { + for (i = 0; i < qseg->NumberOfDoF(); i++) { + if (clamp[i] && !qseg->Locked(i)) { + absdelta = MT_abs(delta[i]); + + if (absdelta < MT_EPSILON) { + qseg->Lock(i, m_jacobian, delta); + locked = true; + } + else if (absdelta < minabsdelta) { + minabsdelta = absdelta; + mindelta = delta; + minseg = qseg; + mindof = i; + } + } + } + } + } + + // lock most violating angle + if (minseg) { + minseg->Lock(mindof, m_jacobian, mindelta); + locked = true; + + if (minabsdelta > norm) + norm = minabsdelta; + } + + if (locked == false) + // no locking done, last inner iteration, apply the angles + for (seg = m_segments.begin(); seg != m_segments.end(); seg++) { + (*seg)->UnLock(); + (*seg)->UpdateAngleApply(); + } + + // signal if another inner iteration is needed + return locked; +} + +bool IK_QJacobianSolver::Solve( + IK_QSegment *root, + std::list tasks, + const MT_Scalar, + const int max_iterations +) +{ + float scale = ComputeScale(); + bool solved = false; + //double dt = analyze_time(); + + Scale(scale, tasks); + + ConstrainPoleVector(root, tasks); + + root->UpdateTransform(m_rootmatrix); + + // iterate + for (int iterations = 0; iterations < max_iterations; iterations++) { + // update transform + root->UpdateTransform(m_rootmatrix); + + std::list::iterator task; + + // compute jacobian + for (task = tasks.begin(); task != tasks.end(); task++) { + if ((*task)->Primary()) + (*task)->ComputeJacobian(m_jacobian); + else + (*task)->ComputeJacobian(m_jacobian_sub); + } + + MT_Scalar norm = 0.0; + + do { + // invert jacobian + try { + m_jacobian.Invert(); + if (m_secondary_enabled) + m_jacobian.SubTask(m_jacobian_sub); + } + catch (...) { + fprintf(stderr, "IK Exception\n"); + return false; + } + + // update angles and check limits + } while (UpdateAngles(norm)); + + // unlock segments again after locking in clamping loop + std::vector::iterator seg; + for (seg = m_segments.begin(); seg != m_segments.end(); seg++) + (*seg)->UnLock(); + + // compute angle update norm + MT_Scalar maxnorm = m_jacobian.AngleUpdateNorm(); + if (maxnorm > norm) + norm = maxnorm; + + // check for convergence + if (norm < 1e-3) { + solved = true; + break; + } + } + + if(m_poleconstraint) + root->PrependBasis(m_rootmatrix.getBasis()); + + Scale(1.0f/scale, tasks); + + //analyze_add_run(max_iterations, analyze_time()-dt); + + return solved; +} + diff --git a/intern/iksolver/intern/IK_QJacobianSolver.h b/intern/iksolver/intern/IK_QJacobianSolver.h new file mode 100644 index 00000000000..9ad46cd0aa6 --- /dev/null +++ b/intern/iksolver/intern/IK_QJacobianSolver.h @@ -0,0 +1,101 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original Author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_IK_QJacobianSolver_h + +#define NAN_INCLUDED_IK_QJacobianSolver_h + +/** + * @author Laurence Bourn + * @date 28/6/2001 + */ + +#include +#include + +#include "MT_Vector3.h" +#include "MT_Transform.h" +#include "IK_QJacobian.h" +#include "IK_QSegment.h" +#include "IK_QTask.h" + +class IK_QJacobianSolver +{ +public: + IK_QJacobianSolver(); + ~IK_QJacobianSolver() {}; + + // setup pole vector constraint + void SetPoleVectorConstraint(IK_QSegment *tip, MT_Vector3& goal, + MT_Vector3& polegoal, float poleangle, bool getangle); + float GetPoleAngle() { return m_poleangle; }; + + // call setup once before solving, if it fails don't solve + bool Setup(IK_QSegment *root, std::list& tasks); + + // returns true if converged, false if max number of iterations was used + bool Solve( + IK_QSegment *root, + std::list tasks, + const MT_Scalar tolerance, + const int max_iterations + ); + +private: + void AddSegmentList(IK_QSegment *seg); + bool UpdateAngles(MT_Scalar& norm); + void ConstrainPoleVector(IK_QSegment *root, std::list& tasks); + + MT_Scalar ComputeScale(); + void Scale(float scale, std::list& tasks); + +private: + + IK_QJacobian m_jacobian; + IK_QJacobian m_jacobian_sub; + + bool m_secondary_enabled; + + std::vector m_segments; + + MT_Transform m_rootmatrix; + + bool m_poleconstraint; + bool m_getpoleangle; + MT_Vector3 m_goal; + MT_Vector3 m_polegoal; + float m_poleangle; + IK_QSegment *m_poletip; +}; + +#endif + diff --git a/intern/iksolver/intern/IK_QSegment.cpp b/intern/iksolver/intern/IK_QSegment.cpp new file mode 100644 index 00000000000..a5217ed91d6 --- /dev/null +++ b/intern/iksolver/intern/IK_QSegment.cpp @@ -0,0 +1,1052 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original Author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "IK_QSegment.h" + +// Utility functions + +static MT_Matrix3x3 RotationMatrix(MT_Scalar sine, MT_Scalar cosine, int axis) +{ + if (axis == 0) + return MT_Matrix3x3(1.0, 0.0, 0.0, + 0.0, cosine, -sine, + 0.0, sine, cosine); + else if (axis == 1) + return MT_Matrix3x3(cosine, 0.0, sine, + 0.0, 1.0, 0.0, + -sine, 0.0, cosine); + else + return MT_Matrix3x3(cosine, -sine, 0.0, + sine, cosine, 0.0, + 0.0, 0.0, 1.0); +} + +static MT_Matrix3x3 RotationMatrix(MT_Scalar angle, int axis) +{ + return RotationMatrix(sin(angle), cos(angle), axis); +} + + +static MT_Scalar EulerAngleFromMatrix(const MT_Matrix3x3& R, int axis) +{ + MT_Scalar t = sqrt(R[0][0]*R[0][0] + R[0][1]*R[0][1]); + + if (t > 16.0*MT_EPSILON) { + if (axis == 0) return atan2(R[1][2], R[2][2]); + else if(axis == 1) return atan2(-R[0][2], t); + else return atan2(R[0][1], R[0][0]); + } else { + if (axis == 0) return atan2(-R[2][1], R[1][1]); + else if(axis == 1) return atan2(-R[0][2], t); + else return 0.0f; + } +} + +static MT_Scalar safe_acos(MT_Scalar f) +{ + if (f <= -1.0f) + return MT_PI; + else if (f >= 1.0f) + return 0.0; + else + return acos(f); +} + +static MT_Scalar ComputeTwist(const MT_Matrix3x3& R) +{ + // qy and qw are the y and w components of the quaternion from R + MT_Scalar qy = R[0][2] - R[2][0]; + MT_Scalar qw = R[0][0] + R[1][1] + R[2][2] + 1; + + MT_Scalar tau = 2*atan2(qy, qw); + + return tau; +} + +static MT_Matrix3x3 ComputeTwistMatrix(MT_Scalar tau) +{ + return RotationMatrix(tau, 1); +} + +static void RemoveTwist(MT_Matrix3x3& R) +{ + // compute twist parameter + MT_Scalar tau = ComputeTwist(R); + + // compute twist matrix + MT_Matrix3x3 T = ComputeTwistMatrix(tau); + + // remove twist + R = R*T.transposed(); +} + +static MT_Vector3 SphericalRangeParameters(const MT_Matrix3x3& R) +{ + // compute twist parameter + MT_Scalar tau = ComputeTwist(R); + + // compute swing parameters + MT_Scalar num = 2.0*(1.0 + R[1][1]); + + // singularity at pi + if (MT_abs(num) < MT_EPSILON) + // TODO: this does now rotation of size pi over z axis, but could + // be any axis, how to deal with this i'm not sure, maybe don't + // enforce limits at all then + return MT_Vector3(0.0, tau, 1.0); + + num = 1.0/sqrt(num); + MT_Scalar ax = -R[2][1]*num; + MT_Scalar az = R[0][1]*num; + + return MT_Vector3(ax, tau, az); +} + +static MT_Matrix3x3 ComputeSwingMatrix(MT_Scalar ax, MT_Scalar az) +{ + // length of (ax, 0, az) = sin(theta/2) + MT_Scalar sine2 = ax*ax + az*az; + MT_Scalar cosine2 = sqrt((sine2 >= 1.0)? 0.0: 1.0-sine2); + + // compute swing matrix + MT_Matrix3x3 S(MT_Quaternion(ax, 0.0, az, -cosine2)); + + return S; +} + +static MT_Vector3 MatrixToAxisAngle(const MT_Matrix3x3& R) +{ + MT_Vector3 delta = MT_Vector3(R[2][1] - R[1][2], + R[0][2] - R[2][0], + R[1][0] - R[0][1]); + + MT_Scalar c = safe_acos((R[0][0] + R[1][1] + R[2][2] - 1)/2); + MT_Scalar l = delta.length(); + + if (!MT_fuzzyZero(l)) + delta *= c/l; + + return delta; +} + +static bool EllipseClamp(MT_Scalar& ax, MT_Scalar& az, MT_Scalar *amin, MT_Scalar *amax) +{ + MT_Scalar xlim, zlim, x, z; + + if (ax < 0.0) { + x = -ax; + xlim = -amin[0]; + } + else { + x = ax; + xlim = amax[0]; + } + + if (az < 0.0) { + z = -az; + zlim = -amin[1]; + } + else { + z = az; + zlim = amax[1]; + } + + if (MT_fuzzyZero(xlim) || MT_fuzzyZero(zlim)) { + if (x <= xlim && z <= zlim) + return false; + + if (x > xlim) + x = xlim; + if (z > zlim) + z = zlim; + } + else { + MT_Scalar invx = 1.0/(xlim*xlim); + MT_Scalar invz = 1.0/(zlim*zlim); + + if ((x*x*invx + z*z*invz) <= 1.0) + return false; + + if (MT_fuzzyZero(x)) { + x = 0.0; + z = zlim; + } + else { + MT_Scalar rico = z/x; + MT_Scalar old_x = x; + x = sqrt(1.0/(invx + invz*rico*rico)); + if (old_x < 0.0) + x = -x; + z = rico*x; + } + } + + ax = (ax < 0.0)? -x: x; + az = (az < 0.0)? -z: z; + + return true; +} + +// IK_QSegment + +IK_QSegment::IK_QSegment(int num_DoF, bool translational) +: m_parent(NULL), m_child(NULL), m_sibling(NULL), m_composite(NULL), + m_num_DoF(num_DoF), m_translational(translational) +{ + m_locked[0] = m_locked[1] = m_locked[2] = false; + m_weight[0] = m_weight[1] = m_weight[2] = 1.0; + + m_max_extension = 0.0; + + m_start = MT_Vector3(0, 0, 0); + m_rest_basis.setIdentity(); + m_basis.setIdentity(); + m_translation = MT_Vector3(0, 0, 0); + + m_orig_basis = m_basis; + m_orig_translation = m_translation; +} + +void IK_QSegment::Reset() +{ + m_locked[0] = m_locked[1] = m_locked[2] = false; + + m_basis = m_orig_basis; + m_translation = m_orig_translation; + SetBasis(m_basis); + + for (IK_QSegment *seg = m_child; seg; seg = seg->m_sibling) + seg->Reset(); +} + +void IK_QSegment::SetTransform( + const MT_Vector3& start, + const MT_Matrix3x3& rest_basis, + const MT_Matrix3x3& basis, + const MT_Scalar length +) +{ + m_max_extension = start.length() + length; + + m_start = start; + m_rest_basis = rest_basis; + + m_orig_basis = basis; + SetBasis(basis); + + m_translation = MT_Vector3(0, length, 0); + m_orig_translation = m_translation; +} + +MT_Matrix3x3 IK_QSegment::BasisChange() const +{ + return m_orig_basis.transposed()*m_basis; +} + +MT_Vector3 IK_QSegment::TranslationChange() const +{ + return m_translation - m_orig_translation; +} + +IK_QSegment::~IK_QSegment() +{ + if (m_parent) + m_parent->RemoveChild(this); + + for (IK_QSegment *seg = m_child; seg; seg = seg->m_sibling) + seg->m_parent = NULL; +} + +void IK_QSegment::SetParent(IK_QSegment *parent) +{ + if (m_parent == parent) + return; + + if (m_parent) + m_parent->RemoveChild(this); + + if (parent) { + m_sibling = parent->m_child; + parent->m_child = this; + } + + m_parent = parent; +} + +void IK_QSegment::SetComposite(IK_QSegment *seg) +{ + m_composite = seg; +} + +void IK_QSegment::RemoveChild(IK_QSegment *child) +{ + if (m_child == NULL) + return; + else if (m_child == child) + m_child = m_child->m_sibling; + else { + IK_QSegment *seg = m_child; + + while (seg->m_sibling != child); + seg = seg->m_sibling; + + if (child == seg->m_sibling) + seg->m_sibling = child->m_sibling; + } +} + +void IK_QSegment::UpdateTransform(const MT_Transform& global) +{ + // compute the global transform at the end of the segment + m_global_start = global.getOrigin() + global.getBasis()*m_start; + + m_global_transform.setOrigin(m_global_start); + m_global_transform.setBasis(global.getBasis() * m_rest_basis * m_basis); + m_global_transform.translate(m_translation); + + // update child transforms + for (IK_QSegment *seg = m_child; seg; seg = seg->m_sibling) + seg->UpdateTransform(m_global_transform); +} + +void IK_QSegment::PrependBasis(const MT_Matrix3x3& mat) +{ + m_basis = m_rest_basis.inverse() * mat * m_rest_basis * m_basis; +} + +void IK_QSegment::Scale(float scale) +{ + m_start *= scale; + m_translation *= scale; + m_orig_translation *= scale; + m_global_start *= scale; + m_global_transform.getOrigin() *= scale; + m_max_extension *= scale; +} + +// IK_QSphericalSegment + +IK_QSphericalSegment::IK_QSphericalSegment() +: IK_QSegment(3, false), m_limit_x(false), m_limit_y(false), m_limit_z(false) +{ +} + +MT_Vector3 IK_QSphericalSegment::Axis(int dof) const +{ + return m_global_transform.getBasis().getColumn(dof); +} + +void IK_QSphericalSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax) +{ + if (lmin >= lmax) + return; + + if (axis == 1) { + lmin = MT_clamp(lmin, -180, 180); + lmax = MT_clamp(lmax, -180, 180); + + m_min_y = MT_radians(lmin); + m_max_y = MT_radians(lmax); + + m_limit_y = true; + } + else { + // clamp and convert to axis angle parameters + lmin = MT_clamp(lmin, -180, 180); + lmax = MT_clamp(lmax, -180, 180); + + lmin = sin(MT_radians(lmin)*0.5); + lmax = sin(MT_radians(lmax)*0.5); + + if (axis == 0) { + m_min[0] = -lmax; + m_max[0] = -lmin; + m_limit_x = true; + } + else if (axis == 2) { + m_min[1] = -lmax; + m_max[1] = -lmin; + m_limit_z = true; + } + } +} + +void IK_QSphericalSegment::SetWeight(int axis, MT_Scalar weight) +{ + m_weight[axis] = weight; +} + +bool IK_QSphericalSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp) +{ + if (m_locked[0] && m_locked[1] && m_locked[2]) + return false; + + MT_Vector3 dq; + dq.x() = jacobian.AngleUpdate(m_DoF_id); + dq.y() = jacobian.AngleUpdate(m_DoF_id+1); + dq.z() = jacobian.AngleUpdate(m_DoF_id+2); + + // Directly update the rotation matrix, with Rodrigues' rotation formula, + // to avoid singularities and allow smooth integration. + + MT_Scalar theta = dq.length(); + + if (!MT_fuzzyZero(theta)) { + MT_Vector3 w = dq*(1.0/theta); + + MT_Scalar sine = sin(theta); + MT_Scalar cosine = cos(theta); + MT_Scalar cosineInv = 1-cosine; + + MT_Scalar xsine = w.x()*sine; + MT_Scalar ysine = w.y()*sine; + MT_Scalar zsine = w.z()*sine; + + MT_Scalar xxcosine = w.x()*w.x()*cosineInv; + MT_Scalar xycosine = w.x()*w.y()*cosineInv; + MT_Scalar xzcosine = w.x()*w.z()*cosineInv; + MT_Scalar yycosine = w.y()*w.y()*cosineInv; + MT_Scalar yzcosine = w.y()*w.z()*cosineInv; + MT_Scalar zzcosine = w.z()*w.z()*cosineInv; + + MT_Matrix3x3 M( + cosine + xxcosine, -zsine + xycosine, ysine + xzcosine, + zsine + xycosine, cosine + yycosine, -xsine + yzcosine, + -ysine + xzcosine, xsine + yzcosine, cosine + zzcosine); + + m_new_basis = m_basis*M; + } + else + m_new_basis = m_basis; + + + if (m_limit_y == false && m_limit_x == false && m_limit_z == false) + return false; + + MT_Vector3 a = SphericalRangeParameters(m_new_basis); + + if (m_locked[0]) + a.x() = m_locked_ax; + if (m_locked[1]) + a.y() = m_locked_ay; + if (m_locked[2]) + a.z() = m_locked_az; + + MT_Scalar ax = a.x(), ay = a.y(), az = a.z(); + + clamp[0] = clamp[1] = clamp[2] = false; + + if (m_limit_y) { + if (a.y() > m_max_y) { + ay = m_max_y; + clamp[1] = true; + } + else if (a.y() < m_min_y) { + ay = m_min_y; + clamp[1] = true; + } + } + + if (m_limit_x && m_limit_z) { + if (EllipseClamp(ax, az, m_min, m_max)) + clamp[0] = clamp[2] = true; + } + else if (m_limit_x) { + if (ax < m_min[0]) { + ax = m_min[0]; + clamp[0] = true; + } + else if (ax > m_max[0]) { + ax = m_max[0]; + clamp[0] = true; + } + } + else if (m_limit_z) { + if (az < m_min[1]) { + az = m_min[1]; + clamp[2] = true; + } + else if (az > m_max[1]) { + az = m_max[1]; + clamp[2] = true; + } + } + + if (clamp[0] == false && clamp[1] == false && clamp[2] == false) { + if (m_locked[0] || m_locked[1] || m_locked[2]) + m_new_basis = ComputeSwingMatrix(ax, az)*ComputeTwistMatrix(ay); + return false; + } + + m_new_basis = ComputeSwingMatrix(ax, az)*ComputeTwistMatrix(ay); + + delta = MatrixToAxisAngle(m_basis.transposed()*m_new_basis); + + if (!(m_locked[0] || m_locked[2]) && (clamp[0] || clamp[2])) { + m_locked_ax = ax; + m_locked_az = az; + } + + if (!m_locked[1] && clamp[1]) + m_locked_ay = ay; + + return true; +} + +void IK_QSphericalSegment::Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta) +{ + if (dof == 1) { + m_locked[1] = true; + jacobian.Lock(m_DoF_id+1, delta[1]); + } + else { + m_locked[0] = m_locked[2] = true; + jacobian.Lock(m_DoF_id, delta[0]); + jacobian.Lock(m_DoF_id+2, delta[2]); + } +} + +void IK_QSphericalSegment::UpdateAngleApply() +{ + m_basis = m_new_basis; +} + +// IK_QNullSegment + +IK_QNullSegment::IK_QNullSegment() +: IK_QSegment(0, false) +{ +} + +// IK_QRevoluteSegment + +IK_QRevoluteSegment::IK_QRevoluteSegment(int axis) +: IK_QSegment(1, false), m_axis(axis), m_angle(0.0), m_limit(false) +{ +} + +void IK_QRevoluteSegment::SetBasis(const MT_Matrix3x3& basis) +{ + if (m_axis == 1) { + m_angle = ComputeTwist(basis); + m_basis = ComputeTwistMatrix(m_angle); + } + else { + m_angle = EulerAngleFromMatrix(basis, m_axis); + m_basis = RotationMatrix(m_angle, m_axis); + } +} + +MT_Vector3 IK_QRevoluteSegment::Axis(int) const +{ + return m_global_transform.getBasis().getColumn(m_axis); +} + +bool IK_QRevoluteSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp) +{ + if (m_locked[0]) + return false; + + m_new_angle = m_angle + jacobian.AngleUpdate(m_DoF_id); + + clamp[0] = false; + + if (m_limit == false) + return false; + + if (m_new_angle > m_max) + delta[0] = m_max - m_angle; + else if (m_new_angle < m_min) + delta[0] = m_min - m_angle; + else + return false; + + clamp[0] = true; + m_new_angle = m_angle + delta[0]; + + return true; +} + +void IK_QRevoluteSegment::Lock(int, IK_QJacobian& jacobian, MT_Vector3& delta) +{ + m_locked[0] = true; + jacobian.Lock(m_DoF_id, delta[0]); +} + +void IK_QRevoluteSegment::UpdateAngleApply() +{ + m_angle = m_new_angle; + m_basis = RotationMatrix(m_angle, m_axis); +} + +void IK_QRevoluteSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax) +{ + if (lmin >= lmax || m_axis != axis) + return; + + // clamp and convert to axis angle parameters + lmin = MT_clamp(lmin, -180, 180); + lmax = MT_clamp(lmax, -180, 180); + + m_min = MT_radians(lmin); + m_max = MT_radians(lmax); + + m_limit = true; +} + +void IK_QRevoluteSegment::SetWeight(int axis, MT_Scalar weight) +{ + if (axis == m_axis) + m_weight[0] = weight; +} + +// IK_QSwingSegment + +IK_QSwingSegment::IK_QSwingSegment() +: IK_QSegment(2, false), m_limit_x(false), m_limit_z(false) +{ +} + +void IK_QSwingSegment::SetBasis(const MT_Matrix3x3& basis) +{ + m_basis = basis; + RemoveTwist(m_basis); +} + +MT_Vector3 IK_QSwingSegment::Axis(int dof) const +{ + return m_global_transform.getBasis().getColumn((dof==0)? 0: 2); +} + +bool IK_QSwingSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp) +{ + if (m_locked[0] && m_locked[1]) + return false; + + MT_Vector3 dq; + dq.x() = jacobian.AngleUpdate(m_DoF_id); + dq.y() = 0.0; + dq.z() = jacobian.AngleUpdate(m_DoF_id+1); + + // Directly update the rotation matrix, with Rodrigues' rotation formula, + // to avoid singularities and allow smooth integration. + + MT_Scalar theta = dq.length(); + + if (!MT_fuzzyZero(theta)) { + MT_Vector3 w = dq*(1.0/theta); + + MT_Scalar sine = sin(theta); + MT_Scalar cosine = cos(theta); + MT_Scalar cosineInv = 1-cosine; + + MT_Scalar xsine = w.x()*sine; + MT_Scalar zsine = w.z()*sine; + + MT_Scalar xxcosine = w.x()*w.x()*cosineInv; + MT_Scalar xzcosine = w.x()*w.z()*cosineInv; + MT_Scalar zzcosine = w.z()*w.z()*cosineInv; + + MT_Matrix3x3 M( + cosine + xxcosine, -zsine, xzcosine, + zsine, cosine, -xsine, + xzcosine, xsine, cosine + zzcosine); + + m_new_basis = m_basis*M; + + RemoveTwist(m_new_basis); + } + else + m_new_basis = m_basis; + + if (m_limit_x == false && m_limit_z == false) + return false; + + MT_Vector3 a = SphericalRangeParameters(m_new_basis); + MT_Scalar ax = 0, az = 0; + + clamp[0] = clamp[1] = false; + + if (m_limit_x && m_limit_z) { + ax = a.x(); + az = a.z(); + + if (EllipseClamp(ax, az, m_min, m_max)) + clamp[0] = clamp[1] = true; + } + else if (m_limit_x) { + if (ax < m_min[0]) { + ax = m_min[0]; + clamp[0] = true; + } + else if (ax > m_max[0]) { + ax = m_max[0]; + clamp[0] = true; + } + } + else if (m_limit_z) { + if (az < m_min[1]) { + az = m_min[1]; + clamp[1] = true; + } + else if (az > m_max[1]) { + az = m_max[1]; + clamp[1] = true; + } + } + + if (clamp[0] == false && clamp[1] == false) + return false; + + m_new_basis = ComputeSwingMatrix(ax, az); + + delta = MatrixToAxisAngle(m_basis.transposed()*m_new_basis); + delta[1] = delta[2]; delta[2] = 0.0; + + return true; +} + +void IK_QSwingSegment::Lock(int, IK_QJacobian& jacobian, MT_Vector3& delta) +{ + m_locked[0] = m_locked[1] = true; + jacobian.Lock(m_DoF_id, delta[0]); + jacobian.Lock(m_DoF_id+1, delta[1]); +} + +void IK_QSwingSegment::UpdateAngleApply() +{ + m_basis = m_new_basis; +} + +void IK_QSwingSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax) +{ + if (lmin >= lmax) + return; + + // clamp and convert to axis angle parameters + lmin = MT_clamp(lmin, -180, 180); + lmax = MT_clamp(lmax, -180, 180); + + lmin = sin(MT_radians(lmin)*0.5); + lmax = sin(MT_radians(lmax)*0.5); + + // put center of ellispe in the middle between min and max + MT_Scalar offset = 0.5*(lmin + lmax); + //lmax = lmax - offset; + + if (axis == 0) { + m_min[0] = -lmax; + m_max[0] = -lmin; + + m_limit_x = true; + m_offset_x = offset; + m_max_x = lmax; + } + else if (axis == 2) { + m_min[1] = -lmax; + m_max[1] = -lmin; + + m_limit_z = true; + m_offset_z = offset; + m_max_z = lmax; + } +} + +void IK_QSwingSegment::SetWeight(int axis, MT_Scalar weight) +{ + if (axis == 0) + m_weight[0] = weight; + else if (axis == 2) + m_weight[1] = weight; +} + +// IK_QElbowSegment + +IK_QElbowSegment::IK_QElbowSegment(int axis) +: IK_QSegment(2, false), m_axis(axis), m_twist(0.0), m_angle(0.0), + m_cos_twist(1.0), m_sin_twist(0.0), m_limit(false), m_limit_twist(false) +{ +} + +void IK_QElbowSegment::SetBasis(const MT_Matrix3x3& basis) +{ + m_basis = basis; + + m_twist = ComputeTwist(m_basis); + RemoveTwist(m_basis); + m_angle = EulerAngleFromMatrix(basis, m_axis); + + m_basis = RotationMatrix(m_angle, m_axis)*ComputeTwistMatrix(m_twist); +} + +MT_Vector3 IK_QElbowSegment::Axis(int dof) const +{ + if (dof == 0) { + MT_Vector3 v; + if (m_axis == 0) + v = MT_Vector3(m_cos_twist, 0, m_sin_twist); + else + v = MT_Vector3(-m_sin_twist, 0, m_cos_twist); + + return m_global_transform.getBasis() * v; + } + else + return m_global_transform.getBasis().getColumn(1); +} + +bool IK_QElbowSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp) +{ + if (m_locked[0] && m_locked[1]) + return false; + + clamp[0] = clamp[1] = false; + + if (!m_locked[0]) { + m_new_angle = m_angle + jacobian.AngleUpdate(m_DoF_id); + + if (m_limit) { + if (m_new_angle > m_max) { + delta[0] = m_max - m_angle; + m_new_angle = m_max; + clamp[0] = true; + } + else if (m_new_angle < m_min) { + delta[0] = m_min - m_angle; + m_new_angle = m_min; + clamp[0] = true; + } + } + } + + if (!m_locked[1]) { + m_new_twist = m_twist + jacobian.AngleUpdate(m_DoF_id+1); + + if (m_limit_twist) { + if (m_new_twist > m_max_twist) { + delta[1] = m_max_twist - m_twist; + m_new_twist = m_max_twist; + clamp[1] = true; + } + else if (m_new_twist < m_min_twist) { + delta[1] = m_min_twist - m_twist; + m_new_twist = m_min_twist; + clamp[1] = true; + } + } + } + + return (clamp[0] || clamp[1]); +} + +void IK_QElbowSegment::Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta) +{ + if (dof == 0) { + m_locked[0] = true; + jacobian.Lock(m_DoF_id, delta[0]); + } + else { + m_locked[1] = true; + jacobian.Lock(m_DoF_id+1, delta[1]); + } +} + +void IK_QElbowSegment::UpdateAngleApply() +{ + m_angle = m_new_angle; + m_twist = m_new_twist; + + m_sin_twist = sin(m_twist); + m_cos_twist = cos(m_twist); + + MT_Matrix3x3 A = RotationMatrix(m_angle, m_axis); + MT_Matrix3x3 T = RotationMatrix(m_sin_twist, m_cos_twist, 1); + + m_basis = A*T; +} + +void IK_QElbowSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax) +{ + if (lmin >= lmax) + return; + + // clamp and convert to axis angle parameters + lmin = MT_clamp(lmin, -180, 180); + lmax = MT_clamp(lmax, -180, 180); + + lmin = MT_radians(lmin); + lmax = MT_radians(lmax); + + if (axis == 1) { + m_min_twist = lmin; + m_max_twist = lmax; + m_limit_twist = true; + } + else if (axis == m_axis) { + m_min = lmin; + m_max = lmax; + m_limit = true; + } +} + +void IK_QElbowSegment::SetWeight(int axis, MT_Scalar weight) +{ + if (axis == m_axis) + m_weight[0] = weight; + else if (axis == 1) + m_weight[1] = weight; +} + +// IK_QTranslateSegment + +IK_QTranslateSegment::IK_QTranslateSegment(int axis1) +: IK_QSegment(1, true) +{ + m_axis_enabled[0] = m_axis_enabled[1] = m_axis_enabled[2] = false; + m_axis_enabled[axis1] = true; + + m_axis[0] = axis1; + + m_limit[0] = m_limit[1] = m_limit[2] = false; +} + +IK_QTranslateSegment::IK_QTranslateSegment(int axis1, int axis2) +: IK_QSegment(2, true) +{ + m_axis_enabled[0] = m_axis_enabled[1] = m_axis_enabled[2] = false; + m_axis_enabled[axis1] = true; + m_axis_enabled[axis2] = true; + + m_axis[0] = axis1; + m_axis[1] = axis2; + + m_limit[0] = m_limit[1] = m_limit[2] = false; +} + +IK_QTranslateSegment::IK_QTranslateSegment() +: IK_QSegment(3, true) +{ + m_axis_enabled[0] = m_axis_enabled[1] = m_axis_enabled[2] = true; + + m_axis[0] = 0; + m_axis[1] = 1; + m_axis[2] = 2; + + m_limit[0] = m_limit[1] = m_limit[2] = false; +} + +MT_Vector3 IK_QTranslateSegment::Axis(int dof) const +{ + return m_global_transform.getBasis().getColumn(m_axis[dof]); +} + +bool IK_QTranslateSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp) +{ + int dof_id = m_DoF_id, dof = 0, i, clamped = false; + + MT_Vector3 dx(0.0, 0.0, 0.0); + + for (i = 0; i < 3; i++) { + if (!m_axis_enabled[i]) { + m_new_translation[i] = m_translation[i]; + continue; + } + + clamp[dof] = false; + + if (!m_locked[dof]) { + m_new_translation[i] = m_translation[i] + jacobian.AngleUpdate(dof_id); + + if (m_limit[i]) { + if (m_new_translation[i] > m_max[i]) { + delta[dof] = m_max[i] - m_translation[i]; + m_new_translation[i] = m_max[i]; + clamped = clamp[dof] = true; + } + else if (m_new_translation[i] < m_min[i]) { + delta[dof] = m_min[i] - m_translation[i]; + m_new_translation[i] = m_min[i]; + clamped = clamp[dof] = true; + } + } + } + + dof_id++; + dof++; + } + + return clamped; +} + +void IK_QTranslateSegment::UpdateAngleApply() +{ + m_translation = m_new_translation; +} + +void IK_QTranslateSegment::Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta) +{ + m_locked[dof] = true; + jacobian.Lock(m_DoF_id+dof, delta[dof]); +} + +void IK_QTranslateSegment::SetWeight(int axis, MT_Scalar weight) +{ + int i; + + for (i = 0; i < m_num_DoF; i++) + if (m_axis[i] == axis) + m_weight[i] = weight; +} + +void IK_QTranslateSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax) +{ + if (lmax < lmin) + return; + + m_min[axis]= lmin; + m_max[axis]= lmax; + m_limit[axis]= true; +} + +void IK_QTranslateSegment::Scale(float scale) +{ + int i; + + IK_QSegment::Scale(scale); + + for (i = 0; i < 3; i++) { + m_min[0] *= scale; + m_max[1] *= scale; + } + + m_new_translation *= scale; +} + diff --git a/intern/iksolver/intern/IK_QSegment.h b/intern/iksolver/intern/IK_QSegment.h new file mode 100644 index 00000000000..3c5df463468 --- /dev/null +++ b/intern/iksolver/intern/IK_QSegment.h @@ -0,0 +1,351 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_IK_QSegment_h +#define NAN_INCLUDED_IK_QSegment_h + +#include "MT_Vector3.h" +#include "MT_Transform.h" +#include "MT_Matrix4x4.h" +#include "IK_QJacobian.h" +#include "MEM_SmartPtr.h" + +#include + +/** + * An IK_Qsegment encodes information about a segments + * local coordinate system. + * + * These segments always point along the y-axis. + * + * Here we define the local coordinates of a joint as + * local_transform = + * translate(tr1) * rotation(A) * rotation(q) * translate(0,length,0) + * We use the standard moto column ordered matrices. You can read + * this as: + * - first translate by (0,length,0) + * - multiply by the rotation matrix derived from the current + * angle parameterization q. + * - multiply by the user defined matrix representing the rest + * position of the bone. + * - translate by the used defined translation (tr1) + * The ordering of these transformations is vital, you must + * use exactly the same transformations when displaying the segments + */ + +class IK_QSegment +{ +public: + virtual ~IK_QSegment(); + + // start: a user defined translation + // rest_basis: a user defined rotation + // basis: a user defined rotation + // length: length of this segment + + void SetTransform( + const MT_Vector3& start, + const MT_Matrix3x3& rest_basis, + const MT_Matrix3x3& basis, + const MT_Scalar length + ); + + // tree structure access + void SetParent(IK_QSegment *parent); + + IK_QSegment *Child() const + { return m_child; } + + IK_QSegment *Sibling() const + { return m_sibling; } + + IK_QSegment *Parent() const + { return m_parent; } + + // for combining two joints into one from the interface + void SetComposite(IK_QSegment *seg); + + IK_QSegment *Composite() const + { return m_composite; } + + // number of degrees of freedom + int NumberOfDoF() const + { return m_num_DoF; } + + // unique id for this segment, for identification in the jacobian + int DoFId() const + { return m_DoF_id; } + + void SetDoFId(int dof_id) + { m_DoF_id = dof_id; } + + // the max distance of the end of this bone from the local origin. + const MT_Scalar MaxExtension() const + { return m_max_extension; } + + // the change in rotation and translation w.r.t. the rest pose + MT_Matrix3x3 BasisChange() const; + MT_Vector3 TranslationChange() const; + + // the start and end of the segment + const MT_Point3 &GlobalStart() const + { return m_global_start; } + + const MT_Point3 &GlobalEnd() const + { return m_global_transform.getOrigin(); } + + // the global transformation at the end of the segment + const MT_Transform &GlobalTransform() const + { return m_global_transform; } + + // is a translational segment? + bool Translational() const + { return m_translational; } + + // locking (during inner clamping loop) + bool Locked(int dof) const + { return m_locked[dof]; } + + void UnLock() + { m_locked[0] = m_locked[1] = m_locked[2] = false; } + + // per dof joint weighting + MT_Scalar Weight(int dof) const + { return m_weight[dof]; } + + void ScaleWeight(int dof, MT_Scalar scale) + { m_weight[dof] *= scale; } + + // recursively update the global coordinates of this segment, 'global' + // is the global transformation from the parent segment + void UpdateTransform(const MT_Transform &global); + + // get axis from rotation matrix for derivative computation + virtual MT_Vector3 Axis(int dof) const=0; + + // update the angles using the dTheta's computed using the jacobian matrix + virtual bool UpdateAngle(const IK_QJacobian&, MT_Vector3&, bool*)=0; + virtual void Lock(int, IK_QJacobian&, MT_Vector3&) {} + virtual void UpdateAngleApply()=0; + + // set joint limits + virtual void SetLimit(int, MT_Scalar, MT_Scalar) {}; + + // set joint weights (per axis) + virtual void SetWeight(int, MT_Scalar) {}; + + virtual void SetBasis(const MT_Matrix3x3& basis) { m_basis = basis; } + + // functions needed for pole vector constraint + void PrependBasis(const MT_Matrix3x3& mat); + void Reset(); + + // scale + virtual void Scale(float scale); + +protected: + + // num_DoF: number of degrees of freedom + IK_QSegment(int num_DoF, bool translational); + + // remove child as a child of this segment + void RemoveChild(IK_QSegment *child); + + // tree structure variables + IK_QSegment *m_parent; + IK_QSegment *m_child; + IK_QSegment *m_sibling; + IK_QSegment *m_composite; + + // full transform = + // start * rest_basis * basis * translation + MT_Vector3 m_start; + MT_Matrix3x3 m_rest_basis; + MT_Matrix3x3 m_basis; + MT_Vector3 m_translation; + + // original basis + MT_Matrix3x3 m_orig_basis; + MT_Vector3 m_orig_translation; + + // maximum extension of this segment + MT_Scalar m_max_extension; + + // accumulated transformations starting from root + MT_Point3 m_global_start; + MT_Transform m_global_transform; + + // number degrees of freedom, (first) id of this segments DOF's + int m_num_DoF, m_DoF_id; + + bool m_locked[3]; + bool m_translational; + MT_Scalar m_weight[3]; +}; + +class IK_QSphericalSegment : public IK_QSegment +{ +public: + IK_QSphericalSegment(); + + MT_Vector3 Axis(int dof) const; + + bool UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp); + void Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta); + void UpdateAngleApply(); + + bool ComputeClampRotation(MT_Vector3& clamp); + + void SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax); + void SetWeight(int axis, MT_Scalar weight); + +private: + MT_Matrix3x3 m_new_basis; + bool m_limit_x, m_limit_y, m_limit_z; + MT_Scalar m_min[2], m_max[2]; + MT_Scalar m_min_y, m_max_y, m_max_x, m_max_z, m_offset_x, m_offset_z; + MT_Scalar m_locked_ax, m_locked_ay, m_locked_az; +}; + +class IK_QNullSegment : public IK_QSegment +{ +public: + IK_QNullSegment(); + + bool UpdateAngle(const IK_QJacobian&, MT_Vector3&, bool*) { return false; } + void UpdateAngleApply() {} + + MT_Vector3 Axis(int) const { return MT_Vector3(0, 0, 0); } + void SetBasis(const MT_Matrix3x3&) { m_basis.setIdentity(); } +}; + +class IK_QRevoluteSegment : public IK_QSegment +{ +public: + // axis: the axis of the DoF, in range 0..2 + IK_QRevoluteSegment(int axis); + + MT_Vector3 Axis(int dof) const; + + bool UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp); + void Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta); + void UpdateAngleApply(); + + void SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax); + void SetWeight(int axis, MT_Scalar weight); + void SetBasis(const MT_Matrix3x3& basis); + +private: + int m_axis; + MT_Scalar m_angle, m_new_angle; + bool m_limit; + MT_Scalar m_min, m_max; +}; + +class IK_QSwingSegment : public IK_QSegment +{ +public: + // XZ DOF, uses one direct rotation + IK_QSwingSegment(); + + MT_Vector3 Axis(int dof) const; + + bool UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp); + void Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta); + void UpdateAngleApply(); + + void SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax); + void SetWeight(int axis, MT_Scalar weight); + void SetBasis(const MT_Matrix3x3& basis); + +private: + MT_Matrix3x3 m_new_basis; + bool m_limit_x, m_limit_z; + MT_Scalar m_min[2], m_max[2]; + MT_Scalar m_max_x, m_max_z, m_offset_x, m_offset_z; +}; + +class IK_QElbowSegment : public IK_QSegment +{ +public: + // XY or ZY DOF, uses two sequential rotations: first rotate around + // X or Z, then rotate around Y (twist) + IK_QElbowSegment(int axis); + + MT_Vector3 Axis(int dof) const; + + bool UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp); + void Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta); + void UpdateAngleApply(); + + void SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax); + void SetWeight(int axis, MT_Scalar weight); + void SetBasis(const MT_Matrix3x3& basis); + +private: + int m_axis; + + MT_Scalar m_twist, m_angle, m_new_twist, m_new_angle; + MT_Scalar m_cos_twist, m_sin_twist; + + bool m_limit, m_limit_twist; + MT_Scalar m_min, m_max, m_min_twist, m_max_twist; +}; + +class IK_QTranslateSegment : public IK_QSegment +{ +public: + // 1DOF, 2DOF or 3DOF translational segments + IK_QTranslateSegment(int axis1); + IK_QTranslateSegment(int axis1, int axis2); + IK_QTranslateSegment(); + + MT_Vector3 Axis(int dof) const; + + bool UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp); + void Lock(int, IK_QJacobian&, MT_Vector3&); + void UpdateAngleApply(); + + void SetWeight(int axis, MT_Scalar weight); + void SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax); + + void Scale(float scale); + +private: + int m_axis[3]; + bool m_axis_enabled[3], m_limit[3]; + MT_Vector3 m_new_translation; + MT_Scalar m_min[3], m_max[3]; +}; + +#endif + diff --git a/intern/iksolver/intern/IK_QTask.cpp b/intern/iksolver/intern/IK_QTask.cpp new file mode 100644 index 00000000000..c72f146b36e --- /dev/null +++ b/intern/iksolver/intern/IK_QTask.cpp @@ -0,0 +1,239 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original Author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "IK_QTask.h" + +// IK_QTask + +IK_QTask::IK_QTask( + int size, + bool primary, + bool active, + const IK_QSegment *segment +) : + m_size(size), m_primary(primary), m_active(active), m_segment(segment), + m_weight(1.0) +{ +} + +// IK_QPositionTask + +IK_QPositionTask::IK_QPositionTask( + bool primary, + const IK_QSegment *segment, + const MT_Vector3& goal +) : + IK_QTask(3, primary, true, segment), m_goal(goal) +{ + // computing clamping length + int num; + const IK_QSegment *seg; + + m_clamp_length = 0.0; + num = 0; + + for (seg = m_segment; seg; seg = seg->Parent()) { + m_clamp_length += seg->MaxExtension(); + num++; + } + + m_clamp_length /= 2*num; +} + +void IK_QPositionTask::ComputeJacobian(IK_QJacobian& jacobian) +{ + // compute beta + const MT_Vector3& pos = m_segment->GlobalEnd(); + + MT_Vector3 d_pos = m_goal - pos; + MT_Scalar length = d_pos.length(); + + if (length > m_clamp_length) + d_pos = (m_clamp_length/length)*d_pos; + + jacobian.SetBetas(m_id, m_size, m_weight*d_pos); + + // compute derivatives + int i; + const IK_QSegment *seg; + + for (seg = m_segment; seg; seg = seg->Parent()) { + MT_Vector3 p = seg->GlobalStart() - pos; + + for (i = 0; i < seg->NumberOfDoF(); i++) { + MT_Vector3 axis = seg->Axis(i)*m_weight; + + if (seg->Translational()) + jacobian.SetDerivatives(m_id, seg->DoFId()+i, axis); + else { + MT_Vector3 pa = p.cross(axis); + jacobian.SetDerivatives(m_id, seg->DoFId()+i, pa); + } + } + } +} + +MT_Scalar IK_QPositionTask::Distance() const +{ + const MT_Vector3& pos = m_segment->GlobalEnd(); + MT_Vector3 d_pos = m_goal - pos; + return d_pos.length(); +} + +// IK_QOrientationTask + +IK_QOrientationTask::IK_QOrientationTask( + bool primary, + const IK_QSegment *segment, + const MT_Matrix3x3& goal +) : + IK_QTask(3, primary, true, segment), m_goal(goal), m_distance(0.0) +{ +} + +void IK_QOrientationTask::ComputeJacobian(IK_QJacobian& jacobian) +{ + // compute betas + const MT_Matrix3x3& rot = m_segment->GlobalTransform().getBasis(); + + MT_Matrix3x3 d_rotm = m_goal*rot.transposed(); + d_rotm.transpose(); + + MT_Vector3 d_rot; + d_rot = -0.5*MT_Vector3(d_rotm[2][1] - d_rotm[1][2], + d_rotm[0][2] - d_rotm[2][0], + d_rotm[1][0] - d_rotm[0][1]); + + m_distance = d_rot.length(); + + jacobian.SetBetas(m_id, m_size, m_weight*d_rot); + + // compute derivatives + int i; + const IK_QSegment *seg; + + for (seg = m_segment; seg; seg = seg->Parent()) + for (i = 0; i < seg->NumberOfDoF(); i++) { + + if (seg->Translational()) + jacobian.SetDerivatives(m_id, seg->DoFId()+i, MT_Vector3(0, 0, 0)); + else { + MT_Vector3 axis = seg->Axis(i)*m_weight; + jacobian.SetDerivatives(m_id, seg->DoFId()+i, axis); + } + } +} + +// IK_QCenterOfMassTask +// Note: implementation not finished! + +IK_QCenterOfMassTask::IK_QCenterOfMassTask( + bool primary, + const IK_QSegment *segment, + const MT_Vector3& goal_center +) : + IK_QTask(3, primary, true, segment), m_goal_center(goal_center) +{ + m_total_mass_inv = ComputeTotalMass(m_segment); + if (!MT_fuzzyZero(m_total_mass_inv)) + m_total_mass_inv = 1.0/m_total_mass_inv; +} + +MT_Scalar IK_QCenterOfMassTask::ComputeTotalMass(const IK_QSegment *segment) +{ + MT_Scalar mass = /*seg->Mass()*/ 1.0; + + const IK_QSegment *seg; + for (seg = segment->Child(); seg; seg = seg->Sibling()) + mass += ComputeTotalMass(seg); + + return mass; +} + +MT_Vector3 IK_QCenterOfMassTask::ComputeCenter(const IK_QSegment *segment) +{ + MT_Vector3 center = /*seg->Mass()**/segment->GlobalStart(); + + const IK_QSegment *seg; + for (seg = segment->Child(); seg; seg = seg->Sibling()) + center += ComputeCenter(seg); + + return center; +} + +void IK_QCenterOfMassTask::JacobianSegment(IK_QJacobian& jacobian, MT_Vector3& center, const IK_QSegment *segment) +{ + int i; + MT_Vector3 p = center - segment->GlobalStart(); + + for (i = 0; i < segment->NumberOfDoF(); i++) { + MT_Vector3 axis = segment->Axis(i)*m_weight; + axis *= /*segment->Mass()**/m_total_mass_inv; + + if (segment->Translational()) + jacobian.SetDerivatives(m_id, segment->DoFId()+i, axis); + else { + MT_Vector3 pa = axis.cross(p); + jacobian.SetDerivatives(m_id, segment->DoFId()+i, pa); + } + } + + const IK_QSegment *seg; + for (seg = segment->Child(); seg; seg = seg->Sibling()) + JacobianSegment(jacobian, center, seg); +} + +void IK_QCenterOfMassTask::ComputeJacobian(IK_QJacobian& jacobian) +{ + MT_Vector3 center = ComputeCenter(m_segment)*m_total_mass_inv; + + // compute beta + MT_Vector3 d_pos = m_goal_center - center; + + m_distance = d_pos.length(); + +#if 0 + if (m_distance > m_clamp_length) + d_pos = (m_clamp_length/m_distance)*d_pos; +#endif + + jacobian.SetBetas(m_id, m_size, m_weight*d_pos); + + // compute derivatives + JacobianSegment(jacobian, center, m_segment); +} + +MT_Scalar IK_QCenterOfMassTask::Distance() const +{ + return m_distance; +} + diff --git a/intern/iksolver/intern/IK_QTask.h b/intern/iksolver/intern/IK_QTask.h new file mode 100644 index 00000000000..f2fd34119a1 --- /dev/null +++ b/intern/iksolver/intern/IK_QTask.h @@ -0,0 +1,156 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_IK_QTask_h +#define NAN_INCLUDED_IK_QTask_h + +#include "MT_Vector3.h" +#include "MT_Transform.h" +#include "MT_Matrix4x4.h" +#include "IK_QJacobian.h" +#include "IK_QSegment.h" + +class IK_QTask +{ +public: + IK_QTask( + int size, + bool primary, + bool active, + const IK_QSegment *segment + ); + virtual ~IK_QTask() {}; + + int Id() const + { return m_size; } + + void SetId(int id) + { m_id = id; } + + int Size() const + { return m_size; } + + bool Primary() const + { return m_primary; } + + bool Active() const + { return m_active; } + + MT_Scalar Weight() const + { return m_weight*m_weight; } + + void SetWeight(MT_Scalar weight) + { m_weight = sqrt(weight); } + + virtual void ComputeJacobian(IK_QJacobian& jacobian)=0; + + virtual MT_Scalar Distance() const=0; + + virtual bool PositionTask() const { return false; } + + virtual void Scale(float scale) {} + +protected: + int m_id; + int m_size; + bool m_primary; + bool m_active; + const IK_QSegment *m_segment; + MT_Scalar m_weight; +}; + +class IK_QPositionTask : public IK_QTask +{ +public: + IK_QPositionTask( + bool primary, + const IK_QSegment *segment, + const MT_Vector3& goal + ); + + void ComputeJacobian(IK_QJacobian& jacobian); + + MT_Scalar Distance() const; + + bool PositionTask() const { return true; } + void Scale(float scale) { m_goal *= scale; m_clamp_length *= scale; } + +private: + MT_Vector3 m_goal; + MT_Scalar m_clamp_length; +}; + +class IK_QOrientationTask : public IK_QTask +{ +public: + IK_QOrientationTask( + bool primary, + const IK_QSegment *segment, + const MT_Matrix3x3& goal + ); + + MT_Scalar Distance() const { return m_distance; }; + void ComputeJacobian(IK_QJacobian& jacobian); + +private: + MT_Matrix3x3 m_goal; + MT_Scalar m_distance; +}; + + +class IK_QCenterOfMassTask : public IK_QTask +{ +public: + IK_QCenterOfMassTask( + bool primary, + const IK_QSegment *segment, + const MT_Vector3& center + ); + + void ComputeJacobian(IK_QJacobian& jacobian); + + MT_Scalar Distance() const; + + void Scale(float scale) { m_goal_center *= scale; m_distance *= scale; } + +private: + MT_Scalar ComputeTotalMass(const IK_QSegment *segment); + MT_Vector3 ComputeCenter(const IK_QSegment *segment); + void JacobianSegment(IK_QJacobian& jacobian, MT_Vector3& center, const IK_QSegment *segment); + + MT_Vector3 m_goal_center; + MT_Scalar m_total_mass_inv; + MT_Scalar m_distance; +}; + +#endif + diff --git a/intern/iksolver/intern/IK_Solver.cpp b/intern/iksolver/intern/IK_Solver.cpp new file mode 100644 index 00000000000..140c35c8c46 --- /dev/null +++ b/intern/iksolver/intern/IK_Solver.cpp @@ -0,0 +1,380 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original Author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "../extern/IK_solver.h" + +#include "IK_QJacobianSolver.h" +#include "IK_QSegment.h" +#include "IK_QTask.h" + +#include +using namespace std; + +class IK_QSolver { +public: + IK_QSolver() : root(NULL) {}; + + IK_QJacobianSolver solver; + IK_QSegment *root; + std::list tasks; +}; + +IK_QSegment *CreateSegment(int flag, bool translate) +{ + int ndof = 0; + ndof += (flag & IK_XDOF)? 1: 0; + ndof += (flag & IK_YDOF)? 1: 0; + ndof += (flag & IK_ZDOF)? 1: 0; + + IK_QSegment *seg; + + if (ndof == 0) + return NULL; + else if (ndof == 1) { + int axis; + + if (flag & IK_XDOF) axis = 0; + else if (flag & IK_YDOF) axis = 1; + else axis = 2; + + if (translate) + seg = new IK_QTranslateSegment(axis); + else + seg = new IK_QRevoluteSegment(axis); + } + else if (ndof == 2) { + int axis1, axis2; + + if (flag & IK_XDOF) { + axis1 = 0; + axis2 = (flag & IK_YDOF)? 1: 2; + } + else { + axis1 = 1; + axis2 = 2; + } + + if (translate) + seg = new IK_QTranslateSegment(axis1, axis2); + else { + if (axis1 + axis2 == 2) + seg = new IK_QSwingSegment(); + else + seg = new IK_QElbowSegment((axis1 == 0)? 0: 2); + } + } + else { + if (translate) + seg = new IK_QTranslateSegment(); + else + seg = new IK_QSphericalSegment(); + } + + return seg; +} + +IK_Segment *IK_CreateSegment(int flag) +{ + IK_QSegment *rot = CreateSegment(flag, false); + IK_QSegment *trans = CreateSegment(flag >> 3, true); + + IK_QSegment *seg; + + if (rot == NULL && trans == NULL) + seg = new IK_QNullSegment(); + else if (rot == NULL) + seg = trans; + else { + seg = rot; + + // make it seem from the interface as if the rotation and translation + // segment are one + if (trans) { + seg->SetComposite(trans); + trans->SetParent(seg); + } + } + + return seg; +} + +void IK_FreeSegment(IK_Segment *seg) +{ + IK_QSegment *qseg = (IK_QSegment*)seg; + + if (qseg->Composite()) + delete qseg->Composite(); + delete qseg; +} + +void IK_SetParent(IK_Segment *seg, IK_Segment *parent) +{ + IK_QSegment *qseg = (IK_QSegment*)seg; + IK_QSegment *qparent = (IK_QSegment*)parent; + + if (qparent && qparent->Composite()) + qseg->SetParent(qparent->Composite()); + else + qseg->SetParent(qparent); +} + +void IK_SetTransform(IK_Segment *seg, float start[3], float rest[][3], float basis[][3], float length) +{ + IK_QSegment *qseg = (IK_QSegment*)seg; + + MT_Vector3 mstart(start); + // convert from blender column major to moto row major + MT_Matrix3x3 mbasis(basis[0][0], basis[1][0], basis[2][0], + basis[0][1], basis[1][1], basis[2][1], + basis[0][2], basis[1][2], basis[2][2]); + MT_Matrix3x3 mrest(rest[0][0], rest[1][0], rest[2][0], + rest[0][1], rest[1][1], rest[2][1], + rest[0][2], rest[1][2], rest[2][2]); + MT_Scalar mlength(length); + + if (qseg->Composite()) { + MT_Vector3 cstart(0, 0, 0); + MT_Matrix3x3 cbasis; + cbasis.setIdentity(); + + qseg->SetTransform(mstart, mrest, mbasis, 0.0); + qseg->Composite()->SetTransform(cstart, cbasis, cbasis, mlength); + } + else + qseg->SetTransform(mstart, mrest, mbasis, mlength); +} + +void IK_SetLimit(IK_Segment *seg, IK_SegmentAxis axis, float lmin, float lmax) +{ + IK_QSegment *qseg = (IK_QSegment*)seg; + + if (axis >= IK_TRANS_X) { + if(!qseg->Translational()) + if(qseg->Composite() && qseg->Composite()->Translational()) + qseg = qseg->Composite(); + else + return; + + if(axis == IK_TRANS_X) axis = IK_X; + else if(axis == IK_TRANS_Y) axis = IK_Y; + else axis = IK_Z; + } + + qseg->SetLimit(axis, lmin, lmax); +} + +void IK_SetStiffness(IK_Segment *seg, IK_SegmentAxis axis, float stiffness) +{ + if (stiffness < 0.0) + return; + + if (stiffness > 0.999) + stiffness = 0.999; + + IK_QSegment *qseg = (IK_QSegment*)seg; + MT_Scalar weight = 1.0-stiffness; + + if (axis >= IK_TRANS_X) { + if(!qseg->Translational()) + if(qseg->Composite() && qseg->Composite()->Translational()) + qseg = qseg->Composite(); + else + return; + + if(axis == IK_TRANS_X) axis = IK_X; + else if(axis == IK_TRANS_Y) axis = IK_Y; + else axis = IK_Z; + } + + qseg->SetWeight(axis, weight); +} + +void IK_GetBasisChange(IK_Segment *seg, float basis_change[][3]) +{ + IK_QSegment *qseg = (IK_QSegment*)seg; + const MT_Matrix3x3& change = qseg->BasisChange(); + + if (qseg->Translational() && qseg->Composite()) + qseg = qseg->Composite(); + + // convert from moto row major to blender column major + basis_change[0][0] = (float)change[0][0]; + basis_change[1][0] = (float)change[0][1]; + basis_change[2][0] = (float)change[0][2]; + basis_change[0][1] = (float)change[1][0]; + basis_change[1][1] = (float)change[1][1]; + basis_change[2][1] = (float)change[1][2]; + basis_change[0][2] = (float)change[2][0]; + basis_change[1][2] = (float)change[2][1]; + basis_change[2][2] = (float)change[2][2]; +} + +void IK_GetTranslationChange(IK_Segment *seg, float *translation_change) +{ + IK_QSegment *qseg = (IK_QSegment*)seg; + + if (!qseg->Translational() && qseg->Composite()) + qseg = qseg->Composite(); + + const MT_Vector3& change = qseg->TranslationChange(); + + translation_change[0] = (float)change[0]; + translation_change[1] = (float)change[1]; + translation_change[2] = (float)change[2]; +} + +IK_Solver *IK_CreateSolver(IK_Segment *root) +{ + if (root == NULL) + return NULL; + + IK_QSolver *solver = new IK_QSolver(); + solver->root = (IK_QSegment*)root; + + return (IK_Solver*)solver; +} + +void IK_FreeSolver(IK_Solver *solver) +{ + if (solver == NULL) + return; + + IK_QSolver *qsolver = (IK_QSolver*)solver; + std::list& tasks = qsolver->tasks; + std::list::iterator task; + + for (task = tasks.begin(); task != tasks.end(); task++) + delete (*task); + + delete qsolver; +} + +void IK_SolverAddGoal(IK_Solver *solver, IK_Segment *tip, float goal[3], float weight) +{ + if (solver == NULL || tip == NULL) + return; + + IK_QSolver *qsolver = (IK_QSolver*)solver; + IK_QSegment *qtip = (IK_QSegment*)tip; + + if (qtip->Composite()) + qtip = qtip->Composite(); + + MT_Vector3 pos(goal); + + IK_QTask *ee = new IK_QPositionTask(true, qtip, pos); + ee->SetWeight(weight); + qsolver->tasks.push_back(ee); +} + +void IK_SolverAddGoalOrientation(IK_Solver *solver, IK_Segment *tip, float goal[][3], float weight) +{ + if (solver == NULL || tip == NULL) + return; + + IK_QSolver *qsolver = (IK_QSolver*)solver; + IK_QSegment *qtip = (IK_QSegment*)tip; + + if (qtip->Composite()) + qtip = qtip->Composite(); + + // convert from blender column major to moto row major + MT_Matrix3x3 rot(goal[0][0], goal[1][0], goal[2][0], + goal[0][1], goal[1][1], goal[2][1], + goal[0][2], goal[1][2], goal[2][2]); + + IK_QTask *orient = new IK_QOrientationTask(true, qtip, rot); + orient->SetWeight(weight); + qsolver->tasks.push_back(orient); +} + +void IK_SolverSetPoleVectorConstraint(IK_Solver *solver, IK_Segment *tip, float goal[3], float polegoal[3], float poleangle, int getangle) +{ + if (solver == NULL || tip == NULL) + return; + + IK_QSolver *qsolver = (IK_QSolver*)solver; + IK_QSegment *qtip = (IK_QSegment*)tip; + + MT_Vector3 qgoal(goal); + MT_Vector3 qpolegoal(polegoal); + + qsolver->solver.SetPoleVectorConstraint( + qtip, qgoal, qpolegoal, poleangle, getangle); +} + +float IK_SolverGetPoleAngle(IK_Solver *solver) +{ + if (solver == NULL) + return 0.0f; + + IK_QSolver *qsolver = (IK_QSolver*)solver; + + return qsolver->solver.GetPoleAngle(); +} + +void IK_SolverAddCenterOfMass(IK_Solver *solver, IK_Segment *root, float goal[3], float weight) +{ + if (solver == NULL || root == NULL) + return; + + IK_QSolver *qsolver = (IK_QSolver*)solver; + IK_QSegment *qroot = (IK_QSegment*)root; + + // convert from blender column major to moto row major + MT_Vector3 center(goal); + + IK_QTask *com = new IK_QCenterOfMassTask(true, qroot, center); + com->SetWeight(weight); + qsolver->tasks.push_back(com); +} + +int IK_Solve(IK_Solver *solver, float tolerance, int max_iterations) +{ + if (solver == NULL) + return 0; + + IK_QSolver *qsolver = (IK_QSolver*)solver; + + IK_QSegment *root = qsolver->root; + IK_QJacobianSolver& jacobian = qsolver->solver; + std::list& tasks = qsolver->tasks; + MT_Scalar tol = tolerance; + + if(!jacobian.Setup(root, tasks)) + return 0; + + bool result = jacobian.Solve(root, tasks, tol, max_iterations); + + return ((result)? 1: 0); +} + diff --git a/intern/iksolver/intern/MT_ExpMap.cpp b/intern/iksolver/intern/MT_ExpMap.cpp new file mode 100644 index 00000000000..9b758103de8 --- /dev/null +++ b/intern/iksolver/intern/MT_ExpMap.cpp @@ -0,0 +1,251 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original Author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "MT_ExpMap.h" + +/** + * Set the exponential map from a quaternion. The quaternion must be non-zero. + */ + + void +MT_ExpMap:: +setRotation( + const MT_Quaternion &q +) { + // ok first normalize the quaternion + // then compute theta the axis-angle and the normalized axis v + // scale v by theta and that's it hopefully! + + m_q = q.normalized(); + m_v = MT_Vector3(m_q.x(), m_q.y(), m_q.z()); + + MT_Scalar cosp = m_q.w(); + m_sinp = m_v.length(); + m_v /= m_sinp; + + m_theta = atan2(double(m_sinp),double(cosp)); + m_v *= m_theta; +} + +/** + * Convert from an exponential map to a quaternion + * representation + */ + + const MT_Quaternion& +MT_ExpMap:: +getRotation( +) const { + return m_q; +} + +/** + * Convert the exponential map to a 3x3 matrix + */ + + MT_Matrix3x3 +MT_ExpMap:: +getMatrix( +) const { + return MT_Matrix3x3(m_q); +} + +/** + * Update & reparameterizate the exponential map + */ + + void +MT_ExpMap:: +update( + const MT_Vector3& dv +){ + m_v += dv; + + angleUpdated(); +} + +/** + * Compute the partial derivatives of the exponential + * map (dR/de - where R is a 3x3 rotation matrix formed + * from the map) and return them as a 3x3 matrix + */ + + void +MT_ExpMap:: +partialDerivatives( + MT_Matrix3x3& dRdx, + MT_Matrix3x3& dRdy, + MT_Matrix3x3& dRdz +) const { + + MT_Quaternion dQdx[3]; + + compute_dQdVi(dQdx); + + compute_dRdVi(dQdx[0], dRdx); + compute_dRdVi(dQdx[1], dRdy); + compute_dRdVi(dQdx[2], dRdz); +} + + void +MT_ExpMap:: +compute_dRdVi( + const MT_Quaternion &dQdvi, + MT_Matrix3x3 & dRdvi +) const { + + MT_Scalar prod[9]; + + /* This efficient formulation is arrived at by writing out the + * entire chain rule product dRdq * dqdv in terms of 'q' and + * noticing that all the entries are formed from sums of just + * nine products of 'q' and 'dqdv' */ + + prod[0] = -MT_Scalar(4)*m_q.x()*dQdvi.x(); + prod[1] = -MT_Scalar(4)*m_q.y()*dQdvi.y(); + prod[2] = -MT_Scalar(4)*m_q.z()*dQdvi.z(); + prod[3] = MT_Scalar(2)*(m_q.y()*dQdvi.x() + m_q.x()*dQdvi.y()); + prod[4] = MT_Scalar(2)*(m_q.w()*dQdvi.z() + m_q.z()*dQdvi.w()); + prod[5] = MT_Scalar(2)*(m_q.z()*dQdvi.x() + m_q.x()*dQdvi.z()); + prod[6] = MT_Scalar(2)*(m_q.w()*dQdvi.y() + m_q.y()*dQdvi.w()); + prod[7] = MT_Scalar(2)*(m_q.z()*dQdvi.y() + m_q.y()*dQdvi.z()); + prod[8] = MT_Scalar(2)*(m_q.w()*dQdvi.x() + m_q.x()*dQdvi.w()); + + /* first row, followed by second and third */ + dRdvi[0][0] = prod[1] + prod[2]; + dRdvi[0][1] = prod[3] - prod[4]; + dRdvi[0][2] = prod[5] + prod[6]; + + dRdvi[1][0] = prod[3] + prod[4]; + dRdvi[1][1] = prod[0] + prod[2]; + dRdvi[1][2] = prod[7] - prod[8]; + + dRdvi[2][0] = prod[5] - prod[6]; + dRdvi[2][1] = prod[7] + prod[8]; + dRdvi[2][2] = prod[0] + prod[1]; +} + +// compute partial derivatives dQ/dVi + + void +MT_ExpMap:: +compute_dQdVi( + MT_Quaternion *dQdX +) const { + + /* This is an efficient implementation of the derivatives given + * in Appendix A of the paper with common subexpressions factored out */ + + MT_Scalar sinc, termCoeff; + + if (m_theta < MT_EXPMAP_MINANGLE) { + sinc = 0.5 - m_theta*m_theta/48.0; + termCoeff = (m_theta*m_theta/40.0 - 1.0)/24.0; + } + else { + MT_Scalar cosp = m_q.w(); + MT_Scalar ang = 1.0/m_theta; + + sinc = m_sinp*ang; + termCoeff = ang*ang*(0.5*cosp - sinc); + } + + for (int i = 0; i < 3; i++) { + MT_Quaternion& dQdx = dQdX[i]; + int i2 = (i+1)%3; + int i3 = (i+2)%3; + + MT_Scalar term = m_v[i]*termCoeff; + + dQdx[i] = term*m_v[i] + sinc; + dQdx[i2] = term*m_v[i2]; + dQdx[i3] = term*m_v[i3]; + dQdx.w() = -0.5*m_v[i]*sinc; + } +} + +// reParametize away from singularity, updating +// m_v and m_theta + + void +MT_ExpMap:: +reParametrize( +){ + if (m_theta > MT_PI) { + MT_Scalar scl = m_theta; + if (m_theta > MT_2_PI){ /* first get theta into range 0..2PI */ + m_theta = MT_Scalar(fmod(m_theta, MT_2_PI)); + scl = m_theta/scl; + m_v *= scl; + } + if (m_theta > MT_PI){ + scl = m_theta; + m_theta = MT_2_PI - m_theta; + scl = MT_Scalar(1.0) - MT_2_PI/scl; + m_v *= scl; + } + } +} + +// compute cached variables + + void +MT_ExpMap:: +angleUpdated( +){ + m_theta = m_v.length(); + + reParametrize(); + + // compute quaternion, sinp and cosp + + if (m_theta < MT_EXPMAP_MINANGLE) { + m_sinp = MT_Scalar(0.0); + + /* Taylor Series for sinc */ + MT_Vector3 temp = m_v * MT_Scalar(MT_Scalar(.5) - m_theta*m_theta/MT_Scalar(48.0)); + m_q.x() = temp.x(); + m_q.y() = temp.y(); + m_q.z() = temp.z(); + m_q.w() = MT_Scalar(1.0); + } else { + m_sinp = MT_Scalar(sin(.5*m_theta)); + + /* Taylor Series for sinc */ + MT_Vector3 temp = m_v * (m_sinp/m_theta); + m_q.x() = temp.x(); + m_q.y() = temp.y(); + m_q.z() = temp.z(); + m_q.w() = MT_Scalar(cos(.5*m_theta)); + } +} + diff --git a/intern/iksolver/intern/MT_ExpMap.h b/intern/iksolver/intern/MT_ExpMap.h new file mode 100644 index 00000000000..401993764aa --- /dev/null +++ b/intern/iksolver/intern/MT_ExpMap.h @@ -0,0 +1,212 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef MT_ExpMap_H +#define MT_ExpMap_H + +#include + +#include "MT_Vector3.h" +#include "MT_Quaternion.h" +#include "MT_Matrix4x4.h" + +const MT_Scalar MT_EXPMAP_MINANGLE (1e-7); + +/** + * MT_ExpMap an exponential map parameterization of rotations + * in 3D. This implementation is derived from the paper + * "F. Sebastian Grassia. Practical parameterization of + * rotations using the exponential map. Journal of Graphics Tools, + * 3(3):29-48, 1998" Please go to http://www.acm.org/jgt/papers/Grassia98/ + * for a thorough description of the theory and sample code used + * to derive this class. + * + * Basic overview of why this class is used. + * In an IK system we need to paramterize the joint angles in some + * way. Typically 2 parameterizations are used. + * - Euler Angles + * These suffer from singularities in the parameterization known + * as gimbal lock. They also do not interpolate well. For every + * set of euler angles there is exactly 1 corresponding 3d rotation. + * - Quaternions. + * Great for interpolating. Only unit quaternions are valid rotations + * means that in a differential ik solver we often stray outside of + * this manifold into invalid rotations. Means we have to do a lot + * of nasty normalizations all the time. Does not suffer from + * gimbal lock problems. More expensive to compute partial derivatives + * as there are 4 of them. + * + * So exponential map is similar to a quaternion axis/angle + * representation but we store the angle as the length of the + * axis. So require only 3 parameters. Means that all exponential + * maps are valid rotations. Suffers from gimbal lock. But it's + * possible to detect when gimbal lock is near and reparameterize + * away from it. Also nice for interpolating. + * Exponential maps are share some of the useful properties of + * euler and quaternion parameterizations. And are very useful + * for differential IK solvers. + */ + +class MT_ExpMap { +public: + + /** + * Default constructor + * @warning there is no initialization in the + * default constructor + */ + + MT_ExpMap() {} + MT_ExpMap(const MT_Vector3& v) : m_v(v) { angleUpdated(); } + + MT_ExpMap(const float v[3]) : m_v(v) { angleUpdated(); } + MT_ExpMap(const double v[3]) : m_v(v) { angleUpdated(); } + + MT_ExpMap(MT_Scalar x, MT_Scalar y, MT_Scalar z) : + m_v(x, y, z) { angleUpdated(); } + + /** + * Construct an exponential map from a quaternion + */ + + MT_ExpMap( + const MT_Quaternion &q + ) { + setRotation(q); + }; + + /** + * Accessors + * Decided not to inherit from MT_Vector3 but rather + * this class contains an MT_Vector3. This is because + * it is very dangerous to use MT_Vector3 functions + * on this class and some of them have no direct meaning. + */ + + const + MT_Vector3 & + vector( + ) const { + return m_v; + }; + + /** + * Set the exponential map from a quaternion + */ + + void + setRotation( + const MT_Quaternion &q + ); + + /** + * Convert from an exponential map to a quaternion + * representation + */ + + const MT_Quaternion& + getRotation( + ) const; + + /** + * Convert the exponential map to a 3x3 matrix + */ + + MT_Matrix3x3 + getMatrix( + ) const; + + /** + * Update (and reparameterize) the expontial map + * @param dv delta update values. + */ + + void + update( + const MT_Vector3& dv + ); + + /** + * Compute the partial derivatives of the exponential + * map (dR/de - where R is a 4x4 matrix formed + * from the map) and return them as a 4x4 matrix + */ + + void + partialDerivatives( + MT_Matrix3x3& dRdx, + MT_Matrix3x3& dRdy, + MT_Matrix3x3& dRdz + ) const ; + +private : + + // m_v contains the exponential map, the other variables are + // cached for efficiency + + MT_Vector3 m_v; + MT_Scalar m_theta, m_sinp; + MT_Quaternion m_q; + + // private methods + + // Compute partial derivatives dR (3x3 rotation matrix) / dVi (EM vector) + // given the partial derivative dQ (Quaternion) / dVi (ith element of EM vector) + + void + compute_dRdVi( + const MT_Quaternion &dQdV, + MT_Matrix3x3 & dRdVi + ) const; + + // compute partial derivatives dQ/dVi + + void + compute_dQdVi( + MT_Quaternion *dQdX + ) const ; + + // reparametrize away from singularity + + void + reParametrize( + ); + + // (re-)compute cached variables + + void + angleUpdated( + ); +}; + +#endif + diff --git a/intern/iksolver/intern/Makefile b/intern/iksolver/intern/Makefile new file mode 100644 index 00000000000..fff4aec252d --- /dev/null +++ b/intern/iksolver/intern/Makefile @@ -0,0 +1,45 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# iksolver intern Makefile +# + +LIBNAME = iksolver +DIR = $(OCGDIR)/intern/$(LIBNAME) +CCSRCS = IK_QJacobianSolver.cpp IK_QSegment.cpp IK_Solver.cpp IK_QJacobian.cpp +CCSRCS += IK_QTask.cpp + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I$(NAN_MEMUTIL)/include + diff --git a/intern/iksolver/intern/TNT/cholesky.h b/intern/iksolver/intern/TNT/cholesky.h new file mode 100644 index 00000000000..3a8011c374c --- /dev/null +++ b/intern/iksolver/intern/TNT/cholesky.h @@ -0,0 +1,99 @@ +/* + * $Id$ + */ + +/* +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + +#ifndef CHOLESKY_H +#define CHOLESKY_H + +#include + +// index method + +namespace TNT +{ + + +// +// Only upper part of A is used. Cholesky factor is returned in +// lower part of L. Returns 0 if successful, 1 otherwise. +// +template +int Cholesky_upper_factorization(SPDMatrix &A, SymmMatrix &L) +{ + Subscript M = A.dim(1); + Subscript N = A.dim(2); + + assert(M == N); // make sure A is square + + // readjust size of L, if necessary + + if (M != L.dim(1) || N != L.dim(2)) + L = SymmMatrix(N,N); + + Subscript i,j,k; + + + typename SPDMatrix::element_type dot=0; + + + for (j=1; j<=N; j++) // form column j of L + { + dot= 0; + + for (i=1; i +#include +#include +#ifdef TNT_USE_REGIONS +#include "region2d.h" +#endif + +namespace TNT +{ + +template +class Matrix +{ + + + public: + + typedef Subscript size_type; + typedef T value_type; + typedef T element_type; + typedef T* pointer; + typedef T* iterator; + typedef T& reference; + typedef const T* const_iterator; + typedef const T& const_reference; + + Subscript lbound() const { return 1;} + + protected: + Subscript m_; + Subscript n_; + Subscript mn_; // total size + T* v_; + T** row_; + T* vm1_ ; // these point to the same data, but are 1-based + T** rowm1_; + + // internal helper function to create the array + // of row pointers + + void initialize(Subscript M, Subscript N) + { + mn_ = M*N; + m_ = M; + n_ = N; + + v_ = new T[mn_]; + row_ = new T*[M]; + rowm1_ = new T*[M]; + + assert(v_ != NULL); + assert(row_ != NULL); + assert(rowm1_ != NULL); + + T* p = v_; + vm1_ = v_ - 1; + for (Subscript i=0; i &A) + { + initialize(A.m_, A.n_); + copy(A.v_); + } + + Matrix(Subscript M, Subscript N, const T& value = T()) + { + initialize(M,N); + set(value); + } + + Matrix(Subscript M, Subscript N, const T* v) + { + initialize(M,N); + copy(v); + } + + + // destructor + // + ~Matrix() + { + destroy(); + } + + + // reallocating + // + Matrix& newsize(Subscript M, Subscript N) + { + if (num_rows() == M && num_cols() == N) + return *this; + + destroy(); + initialize(M,N); + + return *this; + } + + void + diagonal(Vector &diag) + { + int sz = diag.dim(); + newsize(sz,sz); + set(0); + + Subscript i; + for (i = 0; i < sz; i++) { + row_[i][i] = diag[i]; + } + } + + + + // assignments + // + Matrix& operator=(const Matrix &A) + { + if (v_ == A.v_) + return *this; + + if (m_ == A.m_ && n_ == A.n_) // no need to re-alloc + copy(A.v_); + + else + { + destroy(); + initialize(A.m_, A.n_); + copy(A.v_); + } + + return *this; + } + + Matrix& operator=(const T& scalar) + { + set(scalar); + return *this; + } + + + Subscript dim(Subscript d) const + { +#ifdef TNT_BOUNDS_CHECK + assert( d >= 1); + assert( d <= 2); +#endif + return (d==1) ? m_ : ((d==2) ? n_ : 0); + } + + Subscript num_rows() const { return m_; } + Subscript num_cols() const { return n_; } + + + + + inline T* operator[](Subscript i) + { +#ifdef TNT_BOUNDS_CHECK + assert(0<=i); + assert(i < m_) ; +#endif + return row_[i]; + } + + inline const T* operator[](Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert(0<=i); + assert(i < m_) ; +#endif + return row_[i]; + } + + inline reference operator()(Subscript i) + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i <= mn_) ; +#endif + return vm1_[i]; + } + + inline const_reference operator()(Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i <= mn_) ; +#endif + return vm1_[i]; + } + + + + inline reference operator()(Subscript i, Subscript j) + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i <= m_) ; + assert(1<=j); + assert(j <= n_); +#endif + return rowm1_[i][j]; + } + + + + inline const_reference operator() (Subscript i, Subscript j) const + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i <= m_) ; + assert(1<=j); + assert(j <= n_); +#endif + return rowm1_[i][j]; + } + + + +#ifdef TNT_USE_REGIONS + + typedef Region2D > Region; + + + Region operator()(const Index1D &I, const Index1D &J) + { + return Region(*this, I,J); + } + + + typedef const_Region2D< Matrix > const_Region; + const_Region operator()(const Index1D &I, const Index1D &J) const + { + return const_Region(*this, I,J); + } + +#endif + + +}; + + +/* *************************** I/O ********************************/ + +template +std::ostream& operator<<(std::ostream &s, const Matrix &A) +{ + Subscript M=A.num_rows(); + Subscript N=A.num_cols(); + + s << M << " " << N << "\n"; + + for (Subscript i=0; i +std::istream& operator>>(std::istream &s, Matrix &A) +{ + + Subscript M, N; + + s >> M >> N; + + if ( !(M == A.num_rows() && N == A.num_cols() )) + { + A.newsize(M,N); + } + + + for (Subscript i=0; i> A[i][j]; + } + + + return s; +} + +// *******************[ basic matrix algorithms ]*************************** + +template +Matrix operator+(const Matrix &A, + const Matrix &B) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(M==B.num_rows()); + assert(N==B.num_cols()); + + Matrix tmp(M,N); + Subscript i,j; + + for (i=0; i +Matrix operator-(const Matrix &A, + const Matrix &B) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(M==B.num_rows()); + assert(N==B.num_cols()); + + Matrix tmp(M,N); + Subscript i,j; + + for (i=0; i +Matrix mult_element(const Matrix &A, + const Matrix &B) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(M==B.num_rows()); + assert(N==B.num_cols()); + + Matrix tmp(M,N); + Subscript i,j; + + for (i=0; i +void transpose(const Matrix &A, Matrix &S) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(M==S.num_cols()); + assert(N==S.num_rows()); + + Subscript i, j; + + for (i=0; i +inline void matmult(Matrix& C, const Matrix &A, + const Matrix &B) +{ + + assert(A.num_cols() == B.num_rows()); + + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + Subscript K = B.num_cols(); + + C.newsize(M,K); + + T sum; + + const T* row_i; + const T* col_k; + + for (Subscript i=0; i +void matmult(Vector &y, const Matrix &A, const Vector &x) +{ + +#ifdef TNT_BOUNDS_CHECK + assert(A.num_cols() == x.dim()); + assert(A.num_rows() == y.dim()); +#endif + + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + T sum; + + for (Subscript i=0; i +inline void matmultdiag( + Matrix& C, + const Matrix &A, + const Vector &diag +){ +#ifdef TNT_BOUNDS_CHECK + assert(A.num_cols() ==A.num_rows()== diag.dim()); +#endif + + Subscript M = A.num_rows(); + Subscript K = diag.dim(); + + C.newsize(M,K); + + const T* row_i; + const T* col_k; + + for (Subscript i=0; i +inline void matmultdiag( + Matrix& C, + const Vector &diag, + const Matrix &A +){ +#ifdef TNT_BOUNDS_CHECK + assert(A.num_cols() ==A.num_rows()== diag.dim()); +#endif + + Subscript M = A.num_rows(); + Subscript K = diag.dim(); + + C.newsize(M,K); + + for (Subscript i=0; i +#include +#include "tnt.h" +#include "vec.h" + +using namespace std; + +namespace TNT +{ + +template +class Fortran_Sparse_Col_Matrix +{ + + protected: + + Vector val_; // data values (nz_ elements) + Vector rowind_; // row_ind (nz_ elements) + Vector colptr_; // col_ptr (n_+1 elements) + + int nz_; // number of nonzeros + Subscript m_; // global dimensions + Subscript n_; + + public: + + + Fortran_Sparse_Col_Matrix(void); + Fortran_Sparse_Col_Matrix(const Fortran_Sparse_Col_Matrix &S) + : val_(S.val_), rowind_(S.rowind_), colptr_(S.colptr_), nz_(S.nz_), + m_(S.m_), n_(S.n_) {}; + Fortran_Sparse_Col_Matrix(Subscript M, Subscript N, + Subscript nz, const T *val, const Subscript *r, + const Subscript *c) : val_(nz, val), rowind_(nz, r), + colptr_(N+1, c), nz_(nz), m_(M), n_(N) {}; + + Fortran_Sparse_Col_Matrix(Subscript M, Subscript N, + Subscript nz, char *val, char *r, + char *c) : val_(nz, val), rowind_(nz, r), + colptr_(N+1, c), nz_(nz), m_(M), n_(N) {}; + + Fortran_Sparse_Col_Matrix(Subscript M, Subscript N, + Subscript nz, const T *val, Subscript *r, Subscript *c) + : val_(nz, val), rowind_(nz, r), colptr_(N+1, c), nz_(nz), + m_(M), n_(N) {}; + + ~Fortran_Sparse_Col_Matrix() {}; + + + T & val(Subscript i) { return val_(i); } + const T & val(Subscript i) const { return val_(i); } + + Subscript & row_ind(Subscript i) { return rowind_(i); } + const Subscript & row_ind(Subscript i) const { return rowind_(i); } + + Subscript col_ptr(Subscript i) { return colptr_(i);} + const Subscript col_ptr(Subscript i) const { return colptr_(i);} + + + Subscript num_cols() const { return m_;} + Subscript num_rows() const { return n_; } + + Subscript dim(Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert( 1 <= i ); + assert( i <= 2 ); +#endif + if (i==1) return m_; + else if (i==2) return m_; + else return 0; + } + + Subscript num_nonzeros() const {return nz_;}; + Subscript lbound() const {return 1;} + + + + Fortran_Sparse_Col_Matrix& operator=(const + Fortran_Sparse_Col_Matrix &C) + { + val_ = C.val_; + rowind_ = C.rowind_; + colptr_ = C.colptr_; + nz_ = C.nz_; + m_ = C.m_; + n_ = C.n_; + + return *this; + } + + Fortran_Sparse_Col_Matrix& newsize(Subscript M, Subscript N, + Subscript nz) + { + val_.newsize(nz); + rowind_.newsize(nz); + colptr_.newsize(N+1); + return *this; + } +}; + +template +ostream& operator<<(ostream &s, const Fortran_Sparse_Col_Matrix &A) +{ + Subscript M=A.num_rows(); + Subscript N=A.num_cols(); + + s << M << " " << N << " " << A.num_nonzeros() << endl; + + + for (Subscript k=1; k<=N; k++) + { + Subscript start = A.col_ptr(k); + Subscript end = A.col_ptr(k+1); + + for (Subscript i= start; i +#include +#include +#ifdef TNT_USE_REGIONS +#include "region2d.h" +#endif + +// simple 1-based, column oriented Matrix class + +namespace TNT +{ + +template +class Fortran_Matrix +{ + + + public: + + typedef T value_type; + typedef T element_type; + typedef T* pointer; + typedef T* iterator; + typedef T& reference; + typedef const T* const_iterator; + typedef const T& const_reference; + + Subscript lbound() const { return 1;} + + protected: + T* v_; // these are adjusted to simulate 1-offset + Subscript m_; + Subscript n_; + T** col_; // these are adjusted to simulate 1-offset + + // internal helper function to create the array + // of row pointers + + void initialize(Subscript M, Subscript N) + { + // adjust col_[] pointers so that they are 1-offset: + // col_[j][i] is really col_[j-1][i-1]; + // + // v_[] is the internal contiguous array, it is still 0-offset + // + v_ = new T[M*N]; + col_ = new T*[N]; + + assert(v_ != NULL); + assert(col_ != NULL); + + + m_ = M; + n_ = N; + T* p = v_ - 1; + for (Subscript i=0; i &A) + { + initialize(A.m_, A.n_); + copy(A.v_); + } + + Fortran_Matrix(Subscript M, Subscript N, const T& value = T()) + { + initialize(M,N); + set(value); + } + + Fortran_Matrix(Subscript M, Subscript N, const T* v) + { + initialize(M,N); + copy(v); + } + + + // destructor + ~Fortran_Matrix() + { + destroy(); + } + + + // assignments + // + Fortran_Matrix& operator=(const Fortran_Matrix &A) + { + if (v_ == A.v_) + return *this; + + if (m_ == A.m_ && n_ == A.n_) // no need to re-alloc + copy(A.v_); + + else + { + destroy(); + initialize(A.m_, A.n_); + copy(A.v_); + } + + return *this; + } + + Fortran_Matrix& operator=(const T& scalar) + { + set(scalar); + return *this; + } + + + Subscript dim(Subscript d) const + { +#ifdef TNT_BOUNDS_CHECK + assert( d >= 1); + assert( d <= 2); +#endif + return (d==1) ? m_ : ((d==2) ? n_ : 0); + } + + Subscript num_rows() const { return m_; } + Subscript num_cols() const { return n_; } + + Fortran_Matrix& newsize(Subscript M, Subscript N) + { + if (num_rows() == M && num_cols() == N) + return *this; + + destroy(); + initialize(M,N); + + return *this; + } + + + + // 1-based element access + // + inline reference operator()(Subscript i, Subscript j) + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i <= m_) ; + assert(1<=j); + assert(j <= n_); +#endif + return col_[j][i]; + } + + inline const_reference operator() (Subscript i, Subscript j) const + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i <= m_) ; + assert(1<=j); + assert(j <= n_); +#endif + return col_[j][i]; + } + + +#ifdef TNT_USE_REGIONS + + typedef Region2D > Region; + typedef const_Region2D< Fortran_Matrix > const_Region; + + Region operator()(const Index1D &I, const Index1D &J) + { + return Region(*this, I,J); + } + + const_Region operator()(const Index1D &I, const Index1D &J) const + { + return const_Region(*this, I,J); + } + +#endif + + +}; + + +/* *************************** I/O ********************************/ + +template +std::ostream& operator<<(std::ostream &s, const Fortran_Matrix &A) +{ + Subscript M=A.num_rows(); + Subscript N=A.num_cols(); + + s << M << " " << N << "\n"; + + for (Subscript i=1; i<=M; i++) + { + for (Subscript j=1; j<=N; j++) + { + s << A(i,j) << " "; + } + s << "\n"; + } + + + return s; +} + +template +std::istream& operator>>(std::istream &s, Fortran_Matrix &A) +{ + + Subscript M, N; + + s >> M >> N; + + if ( !(M == A.num_rows() && N == A.num_cols())) + { + A.newsize(M,N); + } + + + for (Subscript i=1; i<=M; i++) + for (Subscript j=1; j<=N; j++) + { + s >> A(i,j); + } + + + return s; +} + +// *******************[ basic matrix algorithms ]*************************** + + +template +Fortran_Matrix operator+(const Fortran_Matrix &A, + const Fortran_Matrix &B) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(M==B.num_rows()); + assert(N==B.num_cols()); + + Fortran_Matrix tmp(M,N); + Subscript i,j; + + for (i=1; i<=M; i++) + for (j=1; j<=N; j++) + tmp(i,j) = A(i,j) + B(i,j); + + return tmp; +} + +template +Fortran_Matrix operator-(const Fortran_Matrix &A, + const Fortran_Matrix &B) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(M==B.num_rows()); + assert(N==B.num_cols()); + + Fortran_Matrix tmp(M,N); + Subscript i,j; + + for (i=1; i<=M; i++) + for (j=1; j<=N; j++) + tmp(i,j) = A(i,j) - B(i,j); + + return tmp; +} + +// element-wise multiplication (use matmult() below for matrix +// multiplication in the linear algebra sense.) +// +// +template +Fortran_Matrix mult_element(const Fortran_Matrix &A, + const Fortran_Matrix &B) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(M==B.num_rows()); + assert(N==B.num_cols()); + + Fortran_Matrix tmp(M,N); + Subscript i,j; + + for (i=1; i<=M; i++) + for (j=1; j<=N; j++) + tmp(i,j) = A(i,j) * B(i,j); + + return tmp; +} + + +template +Fortran_Matrix transpose(const Fortran_Matrix &A) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + Fortran_Matrix S(N,M); + Subscript i, j; + + for (i=1; i<=M; i++) + for (j=1; j<=N; j++) + S(j,i) = A(i,j); + + return S; +} + + + +template +inline Fortran_Matrix matmult(const Fortran_Matrix &A, + const Fortran_Matrix &B) +{ + +#ifdef TNT_BOUNDS_CHECK + assert(A.num_cols() == B.num_rows()); +#endif + + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + Subscript K = B.num_cols(); + + Fortran_Matrix tmp(M,K); + T sum; + + for (Subscript i=1; i<=M; i++) + for (Subscript k=1; k<=K; k++) + { + sum = 0; + for (Subscript j=1; j<=N; j++) + sum = sum + A(i,j) * B(j,k); + + tmp(i,k) = sum; + } + + return tmp; +} + +template +inline Fortran_Matrix operator*(const Fortran_Matrix &A, + const Fortran_Matrix &B) +{ + return matmult(A,B); +} + +template +inline int matmult(Fortran_Matrix& C, const Fortran_Matrix &A, + const Fortran_Matrix &B) +{ + + assert(A.num_cols() == B.num_rows()); + + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + Subscript K = B.num_cols(); + + C.newsize(M,K); // adjust shape of C, if necessary + + + T sum; + + const T* row_i; + const T* col_k; + + for (Subscript i=1; i<=M; i++) + { + for (Subscript k=1; k<=K; k++) + { + row_i = &A(i,1); + col_k = &B(1,k); + sum = 0; + for (Subscript j=1; j<=N; j++) + { + sum += *row_i * *col_k; + row_i += M; + col_k ++; + } + + C(i,k) = sum; + } + + } + + return 0; +} + + +template +Vector matmult(const Fortran_Matrix &A, const Vector &x) +{ + +#ifdef TNT_BOUNDS_CHECK + assert(A.num_cols() == x.dim()); +#endif + + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + Vector tmp(M); + T sum; + + for (Subscript i=1; i<=M; i++) + { + sum = 0; + for (Subscript j=1; j<=N; j++) + sum = sum + A(i,j) * x(j); + + tmp(i) = sum; + } + + return tmp; +} + +template +inline Vector operator*(const Fortran_Matrix &A, const Vector &x) +{ + return matmult(A,x); +} + +template +inline Fortran_Matrix operator*(const Fortran_Matrix &A, const T &x) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + Subscript MN = M*N; + + Fortran_Matrix res(M,N); + const T* a = A.begin(); + T* t = res.begin(); + T* tend = res.end(); + + for (t=res.begin(); t < tend; t++, a++) + *t = *a * x; + + return res; +} + +} // namespace TNT + +#endif // FMAT_H + diff --git a/intern/iksolver/intern/TNT/fortran.h b/intern/iksolver/intern/TNT/fortran.h new file mode 100644 index 00000000000..0837a918a0a --- /dev/null +++ b/intern/iksolver/intern/TNT/fortran.h @@ -0,0 +1,70 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + + +// Header file to define C/Fortran conventions (Platform specific) + +#ifndef FORTRAN_H +#define FORTRAN_H + +// help map between C/C++ data types and Fortran types + +typedef int Fortran_integer; +typedef float Fortran_float; +typedef double Fortran_double; + + +typedef Fortran_double *fda_; // (in/out) double precision array +typedef const Fortran_double *cfda_; // (in) double precsion array + +typedef Fortran_double *fd_; // (in/out) single double precision +typedef const Fortran_double *cfd_; // (in) single double precision + +typedef Fortran_float *ffa_; // (in/out) float precision array +typedef const Fortran_float *cffa_; // (in) float precsion array + +typedef Fortran_float *ff_; // (in/out) single float precision +typedef const Fortran_float *cff_; // (in) single float precision + +typedef Fortran_integer *fia_; // (in/out) single integer array +typedef const Fortran_integer *cfia_; // (in) single integer array + +typedef Fortran_integer *fi_; // (in/out) single integer +typedef const Fortran_integer *cfi_; // (in) single integer + +typedef char *fch_; // (in/out) single character +typedef char *cfch_; // (in) single character + + +#ifndef TNT_SUBSCRIPT_TYPE +#define TNT_SUBSCRIPT_TYPE TNT::Fortran_integer +#endif + +#endif // FORTRAN_H + diff --git a/intern/iksolver/intern/TNT/fspvec.h b/intern/iksolver/intern/TNT/fspvec.h new file mode 100644 index 00000000000..1fafccdfe93 --- /dev/null +++ b/intern/iksolver/intern/TNT/fspvec.h @@ -0,0 +1,172 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + +// Templated sparse vector (Fortran conventions). +// Used primarily to interface with Fortran sparse matrix libaries. +// (CANNOT BE USED AS AN STL CONTAINER.) + +#ifndef FSPVEC_H +#define FSPVEC_H + +#include "tnt.h" +#include "vec.h" +#include +#include +#include + +using namespace std; + +namespace TNT +{ + +template +class Fortran_Sparse_Vector +{ + + + public: + + typedef Subscript size_type; + typedef T value_type; + typedef T element_type; + typedef T* pointer; + typedef T* iterator; + typedef T& reference; + typedef const T* const_iterator; + typedef const T& const_reference; + + Subscript lbound() const { return 1;} + + protected: + Vector val_; + Vector index_; + Subscript dim_; // prescribed dimension + + + public: + + // size and shape information + + Subscript dim() const { return dim_; } + Subscript num_nonzeros() const { return val_.dim(); } + + // access + + T& val(Subscript i) { return val_(i); } + const T& val(Subscript i) const { return val_(i); } + + Subscript &index(Subscript i) { return index_(i); } + const Subscript &index(Subscript i) const { return index_(i); } + + // constructors + + Fortran_Sparse_Vector() : val_(), index_(), dim_(0) {}; + Fortran_Sparse_Vector(Subscript N, Subscript nz) : val_(nz), + index_(nz), dim_(N) {}; + Fortran_Sparse_Vector(Subscript N, Subscript nz, const T *values, + const Subscript *indices): val_(nz, values), index_(nz, indices), + dim_(N) {} + + Fortran_Sparse_Vector(const Fortran_Sparse_Vector &S): + val_(S.val_), index_(S.index_), dim_(S.dim_) {} + + // initialize from string, e.g. + // + // Fortran_Sparse_Vector A(N, 2, "1.0 2.1", "1 3"); + // + Fortran_Sparse_Vector(Subscript N, Subscript nz, char *v, + char *ind) : val_(nz, v), index_(nz, ind), dim_(N) {} + + // assignments + + Fortran_Sparse_Vector & newsize(Subscript N, Subscript nz) + { + val_.newsize(nz); + index_.newsize(nz); + dim_ = N; + return *this; + } + + Fortran_Sparse_Vector & operator=( const Fortran_Sparse_Vector &A) + { + val_ = A.val_; + index_ = A.index_; + dim_ = A.dim_; + + return *this; + } + + // methods + + + +}; + + +/* *************************** I/O ********************************/ + +template +ostream& operator<<(ostream &s, const Fortran_Sparse_Vector &A) +{ + // output format is : N nz val1 ind1 val2 ind2 ... + Subscript nz=A.num_nonzeros(); + + s << A.dim() << " " << nz << endl; + + for (Subscript i=1; i<=nz; i++) + s << A.val(i) << " " << A.index(i) << endl; + s << endl; + + return s; +} + + +template +istream& operator>>(istream &s, Fortran_Sparse_Vector &A) +{ + // output format is : N nz val1 ind1 val2 ind2 ... + + Subscript N; + Subscript nz; + + s >> N >> nz; + + A.newsize(N, nz); + + for (Subscript i=1; i<=nz; i++) + s >> A.val(i) >> A.index(i); + + + return s; +} + +} // namespace TNT + +#endif // FSPVEC_H + diff --git a/intern/iksolver/intern/TNT/index.h b/intern/iksolver/intern/TNT/index.h new file mode 100644 index 00000000000..71f254e47b9 --- /dev/null +++ b/intern/iksolver/intern/TNT/index.h @@ -0,0 +1,88 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + + +// Vector/Matrix/Array Index Module + +#ifndef INDEX_H +#define INDEX_H + +#include "subscript.h" + +namespace TNT +{ + +class Index1D +{ + Subscript lbound_; + Subscript ubound_; + + public: + + Subscript lbound() const { return lbound_; } + Subscript ubound() const { return ubound_; } + + Index1D(const Index1D &D) : lbound_(D.lbound_), ubound_(D.ubound_) {} + Index1D(Subscript i1, Subscript i2) : lbound_(i1), ubound_(i2) {} + + Index1D & operator=(const Index1D &D) + { + lbound_ = D.lbound_; + ubound_ = D.ubound_; + return *this; + } + +}; + +inline Index1D operator+(const Index1D &D, Subscript i) +{ + return Index1D(i+D.lbound(), i+D.ubound()); +} + +inline Index1D operator+(Subscript i, const Index1D &D) +{ + return Index1D(i+D.lbound(), i+D.ubound()); +} + + + +inline Index1D operator-(Index1D &D, Subscript i) +{ + return Index1D(D.lbound()-i, D.ubound()-i); +} + +inline Index1D operator-(Subscript i, Index1D &D) +{ + return Index1D(i-D.lbound(), i-D.ubound()); +} + +} // namespace TNT + +#endif + diff --git a/intern/iksolver/intern/TNT/lapack.h b/intern/iksolver/intern/TNT/lapack.h new file mode 100644 index 00000000000..043400cd211 --- /dev/null +++ b/intern/iksolver/intern/TNT/lapack.h @@ -0,0 +1,190 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + + +// Header file for Fortran Lapack + +#ifndef LAPACK_H +#define LAPACK_H + +// This file incomplete and included here to only demonstrate the +// basic framework for linking with the Fortran Lapack routines. + +#include "fortran.h" +#include "vec.h" +#include "fmat.h" + + +#define F77_DGESV dgesv_ +#define F77_DGELS dgels_ +#define F77_DSYEV dsyev_ +#define F77_DGEEV dgeev_ + +extern "C" +{ + + // linear equations (general) using LU factorizaiton + // + void F77_DGESV(cfi_ N, cfi_ nrhs, fda_ A, cfi_ lda, + fia_ ipiv, fda_ b, cfi_ ldb, fi_ info); + + // solve linear least squares using QR or LU factorization + // + void F77_DGELS(cfch_ trans, cfi_ M, + cfi_ N, cfi_ nrhs, fda_ A, cfi_ lda, fda_ B, cfi_ ldb, fda_ work, + cfi_ lwork, fi_ info); + + // solve symmetric eigenvalues + // + void F77_DSYEV( cfch_ jobz, cfch_ uplo, cfi_ N, fda_ A, cfi_ lda, + fda_ W, fda_ work, cfi_ lwork, fi_ info); + + // solve unsymmetric eigenvalues + // + void F77_DGEEV(cfch_ jobvl, cfch_ jobvr, cfi_ N, fda_ A, cfi_ lda, + fda_ wr, fda_ wi, fda_ vl, cfi_ ldvl, fda_ vr, + cfi_ ldvr, fda_ work, cfi_ lwork, fi_ info); + +} + +// solve linear equations using LU factorization + +using namespace TNT; + +Vector Lapack_LU_linear_solve(const Fortran_Matrix &A, + const Vector &b) +{ + const Fortran_integer one=1; + Subscript M=A.num_rows(); + Subscript N=A.num_cols(); + + Fortran_Matrix Tmp(A); + Vector x(b); + Vector index(M); + Fortran_integer info = 0; + + F77_DGESV(&N, &one, &Tmp(1,1), &M, &index(1), &x(1), &M, &info); + + if (info != 0) return Vector(0); + else + return x; +} + +// solve linear least squares problem using QR factorization +// +Vector Lapack_LLS_QR_linear_solve(const Fortran_Matrix &A, + const Vector &b) +{ + const Fortran_integer one=1; + Subscript M=A.num_rows(); + Subscript N=A.num_cols(); + + Fortran_Matrix Tmp(A); + Vector x(b); + Fortran_integer info = 0; + + char transp = 'N'; + Fortran_integer lwork = 5 * (M+N); // temporary work space + Vector work(lwork); + + F77_DGELS(&transp, &M, &N, &one, &Tmp(1,1), &M, &x(1), &M, &work(1), + &lwork, &info); + + if (info != 0) return Vector(0); + else + return x; +} + +// *********************** Eigenvalue problems ******************* + +// solve symmetric eigenvalue problem (eigenvalues only) +// +Vector Upper_symmetric_eigenvalue_solve(const Fortran_Matrix &A) +{ + char jobz = 'N'; + char uplo = 'U'; + Subscript N = A.num_rows(); + + assert(N == A.num_cols()); + + Vector eigvals(N); + Fortran_integer worksize = 3*N; + Fortran_integer info = 0; + Vector work(worksize); + Fortran_Matrix Tmp = A; + + F77_DSYEV(&jobz, &uplo, &N, &Tmp(1,1), &N, eigvals.begin(), work.begin(), + &worksize, &info); + + if (info != 0) return Vector(); + else + return eigvals; +} + + +// solve unsymmetric eigenvalue problems +// +int eigenvalue_solve(const Fortran_Matrix &A, + Vector &wr, Vector &wi) +{ + char jobvl = 'N'; + char jobvr = 'N'; + + Fortran_integer N = A.num_rows(); + + + assert(N == A.num_cols()); + + if (N<1) return 1; + + Fortran_Matrix vl(1,N); /* should be NxN ? **** */ + Fortran_Matrix vr(1,N); + Fortran_integer one = 1; + + Fortran_integer worksize = 5*N; + Fortran_integer info = 0; + Vector work(worksize, 0.0); + Fortran_Matrix Tmp = A; + + wr.newsize(N); + wi.newsize(N); + +// void F77_DGEEV(cfch_ jobvl, cfch_ jobvr, cfi_ N, fda_ A, cfi_ lda, +// fda_ wr, fda_ wi, fda_ vl, cfi_ ldvl, fda_ vr, +// cfi_ ldvr, fda_ work, cfi_ lwork, fi_ info); + + F77_DGEEV(&jobvl, &jobvr, &N, &Tmp(1,1), &N, &(wr(1)), + &(wi(1)), &(vl(1,1)), &one, &(vr(1,1)), &one, + &(work(1)), &worksize, &info); + + return (info==0 ? 0: 1); +} + +#endif // LAPACK_H + diff --git a/intern/iksolver/intern/TNT/lu.h b/intern/iksolver/intern/TNT/lu.h new file mode 100644 index 00000000000..40b474bb532 --- /dev/null +++ b/intern/iksolver/intern/TNT/lu.h @@ -0,0 +1,209 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + + +#ifndef LU_H +#define LU_H + +// Solve system of linear equations Ax = b. +// +// Typical usage: +// +// Matrix(double) A; +// Vector(Subscript) ipiv; +// Vector(double) b; +// +// 1) LU_Factor(A,ipiv); +// 2) LU_Solve(A,ipiv,b); +// +// Now b has the solution x. Note that both A and b +// are overwritten. If these values need to be preserved, +// one can make temporary copies, as in +// +// O) Matrix(double) T = A; +// 1) LU_Factor(T,ipiv); +// 1a) Vector(double) x=b; +// 2) LU_Solve(T,ipiv,x); +// +// See details below. +// + + +// for fabs() +// +#include + +// right-looking LU factorization algorithm (unblocked) +// +// Factors matrix A into lower and upper triangular matrices +// (L and U respectively) in solving the linear equation Ax=b. +// +// +// Args: +// +// A (input/output) Matrix(1:n, 1:n) In input, matrix to be +// factored. On output, overwritten with lower and +// upper triangular factors. +// +// indx (output) Vector(1:n) Pivot vector. Describes how +// the rows of A were reordered to increase +// numerical stability. +// +// Return value: +// +// int (0 if successful, 1 otherwise) +// +// + + +namespace TNT +{ + +template +int LU_factor( MaTRiX &A, VecToRSubscript &indx) +{ + assert(A.lbound() == 1); // currently for 1-offset + assert(indx.lbound() == 1); // vectors and matrices + + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + if (M == 0 || N==0) return 0; + if (indx.dim() != M) + indx.newsize(M); + + Subscript i=0,j=0,k=0; + Subscript jp=0; + + typename MaTRiX::element_type t; + + Subscript minMN = (M < N ? M : N) ; // min(M,N); + + for (j=1; j<= minMN; j++) + { + + // find pivot in column j and test for singularity. + + jp = j; + t = fabs(A(j,j)); + for (i=j+1; i<=M; i++) + if ( fabs(A(i,j)) > t) + { + jp = i; + t = fabs(A(i,j)); + } + + indx(j) = jp; + + // jp now has the index of maximum element + // of column j, below the diagonal + + if ( A(jp,j) == 0 ) + return 1; // factorization failed because of zero pivot + + + if (jp != j) // swap rows j and jp + for (k=1; k<=N; k++) + { + t = A(j,k); + A(j,k) = A(jp,k); + A(jp,k) =t; + } + + if (j +int LU_solve(const MaTRiX &A, const VecToRSubscripts &indx, VecToR &b) +{ + assert(A.lbound() == 1); // currently for 1-offset + assert(indx.lbound() == 1); // vectors and matrices + assert(b.lbound() == 1); + + Subscript i,ii=0,ip,j; + Subscript n = b.dim(); + typename MaTRiX::element_type sum = 0.0; + + for (i=1;i<=n;i++) + { + ip=indx(i); + sum=b(ip); + b(ip)=b(i); + if (ii) + for (j=ii;j<=i-1;j++) + sum -= A(i,j)*b(j); + else if (sum) ii=i; + b(i)=sum; + } + for (i=n;i>=1;i--) + { + sum=b(i); + for (j=i+1;j<=n;j++) + sum -= A(i,j)*b(j); + b(i)=sum/A(i,i); + } + + return 0; +} + +} // namespace TNT + +#endif // LU_H + diff --git a/intern/iksolver/intern/TNT/qr.h b/intern/iksolver/intern/TNT/qr.h new file mode 100644 index 00000000000..954dad468af --- /dev/null +++ b/intern/iksolver/intern/TNT/qr.h @@ -0,0 +1,234 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + +#ifndef QR_H +#define QR_H + +// Classical QR factorization example, based on Stewart[1973]. +// +// +// This algorithm computes the factorization of a matrix A +// into a product of an orthognal matrix (Q) and an upper triangular +// matrix (R), such that QR = A. +// +// Parameters: +// +// A (in): Matrix(1:N, 1:N) +// +// Q (output): Matrix(1:N, 1:N), collection of Householder +// column vectors Q1, Q2, ... QN +// +// R (output): upper triangular Matrix(1:N, 1:N) +// +// Returns: +// +// 0 if successful, 1 if A is detected to be singular +// + + +#include //for sqrt() & fabs() +#include "tntmath.h" // for sign() + +// Classical QR factorization, based on Stewart[1973]. +// +// +// This algorithm computes the factorization of a matrix A +// into a product of an orthognal matrix (Q) and an upper triangular +// matrix (R), such that QR = A. +// +// Parameters: +// +// A (in/out): On input, A is square, Matrix(1:N, 1:N), that represents +// the matrix to be factored. +// +// On output, Q and R is encoded in the same Matrix(1:N,1:N) +// in the following manner: +// +// R is contained in the upper triangular section of A, +// except that R's main diagonal is in D. The lower +// triangular section of A represents Q, where each +// column j is the vector Qj = I - uj*uj'/pi_j. +// +// C (output): vector of Pi[j] +// D (output): main diagonal of R, i.e. D(i) is R(i,i) +// +// Returns: +// +// 0 if successful, 1 if A is detected to be singular +// + +namespace TNT +{ + +template +int QR_factor(MaTRiX &A, Vector& C, Vector &D) +{ + assert(A.lbound() == 1); // ensure these are all + assert(C.lbound() == 1); // 1-based arrays and vectors + assert(D.lbound() == 1); + + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(M == N); // make sure A is square + + Subscript i,j,k; + typename MaTRiX::element_type eta, sigma, sum; + + // adjust the shape of C and D, if needed... + + if (N != C.size()) C.newsize(N); + if (N != D.size()) D.newsize(N); + + for (k=1; k eta ? absA : eta ); + } + + if (eta == 0) // matrix is singular + { + cerr << "QR: k=" << k << "\n"; + return 1; + } + + // form Qk and premiltiply M by it + // + for(i=k; i<=N; i++) + A(i,k) = A(i,k) / eta; + + sum = 0; + for (i=k; i<=N; i++) + sum = sum + A(i,k)*A(i,k); + sigma = sign(A(k,k)) * sqrt(sum); + + + A(k,k) = A(k,k) + sigma; + C(k) = sigma * A(k,k); + D(k) = -eta * sigma; + + for (j=k+1; j<=N; j++) + { + sum = 0; + for (i=k; i<=N; i++) + sum = sum + A(i,k)*A(i,j); + sum = sum / C(k); + + for (i=k; i<=N; i++) + A(i,j) = A(i,j) - sum * A(i,k); + } + + D(N) = A(N,N); + } + + return 0; +} + +// modified form of upper triangular solve, except that the main diagonal +// of R (upper portion of A) is in D. +// +template +int R_solve(const MaTRiX &A, /*const*/ Vector &D, Vector &b) +{ + assert(A.lbound() == 1); // ensure these are all + assert(D.lbound() == 1); // 1-based arrays and vectors + assert(b.lbound() == 1); + + Subscript i,j; + Subscript N = A.num_rows(); + + assert(N == A.num_cols()); + assert(N == D.dim()); + assert(N == b.dim()); + + typename MaTRiX::element_type sum; + + if (D(N) == 0) + return 1; + + b(N) = b(N) / + D(N); + + for (i=N-1; i>=1; i--) + { + if (D(i) == 0) + return 1; + sum = 0; + for (j=i+1; j<=N; j++) + sum = sum + A(i,j)*b(j); + b(i) = ( b(i) - sum ) / + D(i); + } + + return 0; +} + + +template +int QR_solve(const MaTRiX &A, const Vector &c, /*const*/ Vector &d, + Vector &b) +{ + assert(A.lbound() == 1); // ensure these are all + assert(c.lbound() == 1); // 1-based arrays and vectors + assert(d.lbound() == 1); + + Subscript N=A.num_rows(); + + assert(N == A.num_cols()); + assert(N == c.dim()); + assert(N == d.dim()); + assert(N == b.dim()); + + Subscript i,j; + typename MaTRiX::element_type sum, tau; + + for (j=1; j +#include + +namespace TNT +{ + +template +class const_Region1D; + +template +class Region1D +{ + protected: + + Array1D & A_; + Subscript offset_; // 0-based + Subscript dim_; + + typedef typename Array1D::element_type T; + + public: + const Array1D & array() const { return A_; } + + Subscript offset() const { return offset_;} + Subscript dim() const { return dim_; } + + Subscript offset(Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert(i==TNT_BASE_OFFSET); +#endif + return offset_; + } + + Subscript dim(Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert(i== TNT_BASE_OFFSET); +#endif + return offset_; + } + + + Region1D(Array1D &A, Subscript i1, Subscript i2) : A_(A) + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET <= i1 ); + assert(i2 <= A.dim() + (TNT_BASE_OFFSET-1)); + assert(i1 <= i2); +#endif + offset_ = i1 - TNT_BASE_OFFSET; + dim_ = i2-i1 + 1; + } + + Region1D(Array1D &A, const Index1D &I) : A_(A) + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET <=I.lbound()); + assert(I.ubound() <= A.dim() + (TNT_BASE_OFFSET-1)); + assert(I.lbound() <= I.ubound()); +#endif + offset_ = I.lbound() - TNT_BASE_OFFSET; + dim_ = I.ubound() - I.lbound() + 1; + } + + Region1D(Region1D &A, Subscript i1, Subscript i2) : + A_(A.A_) + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET <= i1 ); + assert(i2 <= A.dim() + (TNT_BASE_OFFSET - 1)); + assert(i1 <= i2); +#endif + // (old-offset) (new-offset) + // + offset_ = (i1 - TNT_BASE_OFFSET) + A.offset_; + dim_ = i2-i1 + 1; + } + + Region1D operator()(Subscript i1, Subscript i2) + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET <= i1); + assert(i2 <= dim() + (TNT_BASE_OFFSET -1)); + assert(i1 <= i2); +#endif + // offset_ is 0-based, so no need for + // ( - TNT_BASE_OFFSET) + // + return Region1D(A_, i1+offset_, + offset_ + i2); + } + + + Region1D operator()(const Index1D &I) + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET<=I.lbound()); + assert(I.ubound() <= dim() + (TNT_BASE_OFFSET-1)); + assert(I.lbound() <= I.ubound()); +#endif + return Region1D(A_, I.lbound()+offset_, + offset_ + I.ubound()); + } + + + + + T & operator()(Subscript i) + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET <= i); + assert(i <= dim() + (TNT_BASE_OFFSET-1)); +#endif + return A_(i+offset_); + } + + const T & operator() (Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET <= i); + assert(i <= dim() + (TNT_BASE_OFFSET-1)); +#endif + return A_(i+offset_); + } + + + Region1D & operator=(const Region1D &R) + { + // make sure both sides conform + assert(dim() == R.dim()); + + Subscript N = dim(); + Subscript i; + Subscript istart = TNT_BASE_OFFSET; + Subscript iend = istart + N-1; + + for (i=istart; i<=iend; i++) + (*this)(i) = R(i); + + return *this; + } + + + + Region1D & operator=(const const_Region1D &R) + { + // make sure both sides conform + assert(dim() == R.dim()); + + Subscript N = dim(); + Subscript i; + Subscript istart = TNT_BASE_OFFSET; + Subscript iend = istart + N-1; + + for (i=istart; i<=iend; i++) + (*this)(i) = R(i); + + return *this; + + } + + + Region1D & operator=(const T& t) + { + Subscript N=dim(); + Subscript i; + Subscript istart = TNT_BASE_OFFSET; + Subscript iend = istart + N-1; + + for (i=istart; i<= iend; i++) + (*this)(i) = t; + + return *this; + + } + + + Region1D & operator=(const Array1D &R) + { + // make sure both sides conform + Subscript N = dim(); + assert(dim() == R.dim()); + + Subscript i; + Subscript istart = TNT_BASE_OFFSET; + Subscript iend = istart + N-1; + + for (i=istart; i<=iend; i++) + (*this)(i) = R(i); + + return *this; + + } + +}; + +template +std::ostream& operator<<(std::ostream &s, Region1D &A) +{ + Subscript N=A.dim(); + Subscript istart = TNT_BASE_OFFSET; + Subscript iend = N - 1 + TNT_BASE_OFFSET; + + for (Subscript i=istart; i<=iend; i++) + s << A(i) << endl; + + return s; +} + + +/* --------- class const_Region1D ------------ */ + +template +class const_Region1D +{ + protected: + + const Array1D & A_; + Subscript offset_; // 0-based + Subscript dim_; + typedef typename Array1D::element_type T; + + public: + const Array1D & array() const { return A_; } + + Subscript offset() const { return offset_;} + Subscript dim() const { return dim_; } + + Subscript offset(Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert(i==TNT_BASE_OFFSET); +#endif + return offset_; + } + + Subscript dim(Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert(i== TNT_BASE_OFFSET); +#endif + return offset_; + } + + + const_Region1D(const Array1D &A, Subscript i1, Subscript i2) : A_(A) + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET <= i1 ); + assert(i2 <= A.dim() + (TNT_BASE_OFFSET-1)); + assert(i1 <= i2); +#endif + offset_ = i1 - TNT_BASE_OFFSET; + dim_ = i2-i1 + 1; + } + + const_Region1D(const Array1D &A, const Index1D &I) : A_(A) + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET <=I.lbound()); + assert(I.ubound() <= A.dim() + (TNT_BASE_OFFSET-1)); + assert(I.lbound() <= I.ubound()); +#endif + offset_ = I.lbound() - TNT_BASE_OFFSET; + dim_ = I.ubound() - I.lbound() + 1; + } + + const_Region1D(const_Region1D &A, Subscript i1, Subscript i2) : + A_(A.A_) + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET <= i1 ); + assert(i2 <= A.dim() + (TNT_BASE_OFFSET - 1)); + assert(i1 <= i2); +#endif + // (old-offset) (new-offset) + // + offset_ = (i1 - TNT_BASE_OFFSET) + A.offset_; + dim_ = i2-i1 + 1; + } + + const_Region1D operator()(Subscript i1, Subscript i2) + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET <= i1); + assert(i2 <= dim() + (TNT_BASE_OFFSET -1)); + assert(i1 <= i2); +#endif + // offset_ is 0-based, so no need for + // ( - TNT_BASE_OFFSET) + // + return const_Region1D(A_, i1+offset_, + offset_ + i2); + } + + + const_Region1D operator()(const Index1D &I) + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET<=I.lbound()); + assert(I.ubound() <= dim() + (TNT_BASE_OFFSET-1)); + assert(I.lbound() <= I.ubound()); +#endif + return const_Region1D(A_, I.lbound()+offset_, + offset_ + I.ubound()); + } + + + const T & operator() (Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET <= i); + assert(i <= dim() + (TNT_BASE_OFFSET-1)); +#endif + return A_(i+offset_); + } + + + + +}; + +template +std::ostream& operator<<(std::ostream &s, const_Region1D &A) +{ + Subscript N=A.dim(); + + for (Subscript i=1; i<=N; i++) + s << A(i) << endl; + + return s; +} + + +} // namespace TNT + +#endif // const_Region1D_H + diff --git a/intern/iksolver/intern/TNT/region2d.h b/intern/iksolver/intern/TNT/region2d.h new file mode 100644 index 00000000000..364edd76689 --- /dev/null +++ b/intern/iksolver/intern/TNT/region2d.h @@ -0,0 +1,472 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + +// 2D Regions for arrays and matrices + +#ifndef REGION2D_H +#define REGION2D_H + +#include "index.h" +#include +#include + +namespace TNT +{ + +template +class const_Region2D; + + +template +class Region2D +{ + protected: + + Array2D & A_; + Subscript offset_[2]; // 0-offset internally + Subscript dim_[2]; + + public: + typedef typename Array2D::value_type T; + typedef Subscript size_type; + typedef T value_type; + typedef T element_type; + typedef T* pointer; + typedef T* iterator; + typedef T& reference; + typedef const T* const_iterator; + typedef const T& const_reference; + + Array2D & array() { return A_; } + const Array2D & array() const { return A_; } + Subscript lbound() const { return A_.lbound(); } + Subscript num_rows() const { return dim_[0]; } + Subscript num_cols() const { return dim_[1]; } + Subscript offset(Subscript i) const // 1-offset + { +#ifdef TNT_BOUNDS_CHECK + assert( A_.lbound() <= i); + assert( i<= dim_[0] + A_.lbound()-1); +#endif + return offset_[i-A_.lbound()]; + } + + Subscript dim(Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert( A_.lbound() <= i); + assert( i<= dim_[0] + A_.lbound()-1); +#endif + return dim_[i-A_.lbound()]; + } + + + + Region2D(Array2D &A, Subscript i1, Subscript i2, Subscript j1, + Subscript j2) : A_(A) + { +#ifdef TNT_BOUNDS_CHECK + assert( i1 <= i2 ); + assert( j1 <= j2); + assert( A.lbound() <= i1); + assert( i2<= A.dim(A.lbound()) + A.lbound()-1); + assert( A.lbound() <= j1); + assert( j2<= A.dim(A.lbound()+1) + A.lbound()-1 ); +#endif + + + offset_[0] = i1-A.lbound(); + offset_[1] = j1-A.lbound(); + dim_[0] = i2-i1+1; + dim_[1] = j2-j1+1; + } + + Region2D(Array2D &A, const Index1D &I, const Index1D &J) : A_(A) + { +#ifdef TNT_BOUNDS_CHECK + assert( I.lbound() <= I.ubound() ); + assert( J.lbound() <= J.ubound() ); + assert( A.lbound() <= I.lbound()); + assert( I.ubound()<= A.dim(A.lbound()) + A.lbound()-1); + assert( A.lbound() <= J.lbound()); + assert( J.ubound() <= A.dim(A.lbound()+1) + A.lbound()-1 ); +#endif + + offset_[0] = I.lbound()-A.lbound(); + offset_[1] = J.lbound()-A.lbound(); + dim_[0] = I.ubound() - I.lbound() + 1; + dim_[1] = J.ubound() - J.lbound() + 1; + } + + Region2D(Region2D &A, Subscript i1, Subscript i2, + Subscript j1, Subscript j2) : A_(A.A_) + { +#ifdef TNT_BOUNDS_CHECK + assert( i1 <= i2 ); + assert( j1 <= j2); + assert( A.lbound() <= i1); + assert( i2<= A.dim(A.lbound()) + A.lbound()-1); + assert( A.lbound() <= j1); + assert( j2<= A.dim(A.lbound()+1) + A.lbound()-1 ); +#endif + offset_[0] = (i1 - A.lbound()) + A.offset_[0]; + offset_[1] = (j1 - A.lbound()) + A.offset_[1]; + dim_[0] = i2-i1 + 1; + dim_[1] = j2-j1+1; + } + + Region2D operator()(Subscript i1, Subscript i2, + Subscript j1, Subscript j2) + { +#ifdef TNT_BOUNDS_CHECK + assert( i1 <= i2 ); + assert( j1 <= j2); + assert( A_.lbound() <= i1); + assert( i2<= dim_[0] + A_.lbound()-1); + assert( A_.lbound() <= j1); + assert( j2<= dim_[1] + A_.lbound()-1 ); +#endif + return Region2D(A_, + i1+offset_[0], offset_[0] + i2, + j1+offset_[1], offset_[1] + j2); + } + + + Region2D operator()(const Index1D &I, + const Index1D &J) + { +#ifdef TNT_BOUNDS_CHECK + assert( I.lbound() <= I.ubound() ); + assert( J.lbound() <= J.ubound() ); + assert( A_.lbound() <= I.lbound()); + assert( I.ubound()<= dim_[0] + A_.lbound()-1); + assert( A_.lbound() <= J.lbound()); + assert( J.ubound() <= dim_[1] + A_.lbound()-1 ); +#endif + + return Region2D(A_, I.lbound()+offset_[0], + offset_[0] + I.ubound(), offset_[1]+J.lbound(), + offset_[1] + J.ubound()); + } + + inline T & operator()(Subscript i, Subscript j) + { +#ifdef TNT_BOUNDS_CHECK + assert( A_.lbound() <= i); + assert( i<= dim_[0] + A_.lbound()-1); + assert( A_.lbound() <= j); + assert( j<= dim_[1] + A_.lbound()-1 ); +#endif + return A_(i+offset_[0], j+offset_[1]); + } + + inline const T & operator() (Subscript i, Subscript j) const + { +#ifdef TNT_BOUNDS_CHECK + assert( A_.lbound() <= i); + assert( i<= dim_[0] + A_.lbound()-1); + assert( A_.lbound() <= j); + assert( j<= dim_[1] + A_.lbound()-1 ); +#endif + return A_(i+offset_[0], j+offset_[1]); + } + + + Region2D & operator=(const Region2D &R) + { + Subscript M = num_rows(); + Subscript N = num_cols(); + + // make sure both sides conform + assert(M == R.num_rows()); + assert(N == R.num_cols()); + + + Subscript start = R.lbound(); + Subscript Mend = start + M - 1; + Subscript Nend = start + N - 1; + for (Subscript i=start; i<=Mend; i++) + for (Subscript j=start; j<=Nend; j++) + (*this)(i,j) = R(i,j); + + return *this; + } + + Region2D & operator=(const const_Region2D &R) + { + Subscript M = num_rows(); + Subscript N = num_cols(); + + // make sure both sides conform + assert(M == R.num_rows()); + assert(N == R.num_cols()); + + + Subscript start = R.lbound(); + Subscript Mend = start + M - 1; + Subscript Nend = start + N - 1; + for (Subscript i=start; i<=Mend; i++) + for (Subscript j=start; j<=Nend; j++) + (*this)(i,j) = R(i,j); + + return *this; + } + + Region2D & operator=(const Array2D &R) + { + Subscript M = num_rows(); + Subscript N = num_cols(); + + // make sure both sides conform + assert(M == R.num_rows()); + assert(N == R.num_cols()); + + + Subscript start = R.lbound(); + Subscript Mend = start + M - 1; + Subscript Nend = start + N - 1; + for (Subscript i=start; i<=Mend; i++) + for (Subscript j=start; j<=Nend; j++) + (*this)(i,j) = R(i,j); + + return *this; + } + + Region2D & operator=(const T &scalar) + { + Subscript start = lbound(); + Subscript Mend = lbound() + num_rows() - 1; + Subscript Nend = lbound() + num_cols() - 1; + + + for (Subscript i=start; i<=Mend; i++) + for (Subscript j=start; j<=Nend; j++) + (*this)(i,j) = scalar; + + return *this; + } + +}; + +//************************ + +template +class const_Region2D +{ + protected: + + const Array2D & A_; + Subscript offset_[2]; // 0-offset internally + Subscript dim_[2]; + + public: + typedef typename Array2D::value_type T; + typedef T value_type; + typedef T element_type; + typedef const T* const_iterator; + typedef const T& const_reference; + + const Array2D & array() const { return A_; } + Subscript lbound() const { return A_.lbound(); } + Subscript num_rows() const { return dim_[0]; } + Subscript num_cols() const { return dim_[1]; } + Subscript offset(Subscript i) const // 1-offset + { +#ifdef TNT_BOUNDS_CHECK + assert( TNT_BASE_OFFSET <= i); + assert( i<= dim_[0] + TNT_BASE_OFFSET-1); +#endif + return offset_[i-TNT_BASE_OFFSET]; + } + + Subscript dim(Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert( TNT_BASE_OFFSET <= i); + assert( i<= dim_[0] + TNT_BASE_OFFSET-1); +#endif + return dim_[i-TNT_BASE_OFFSET]; + } + + + const_Region2D(const Array2D &A, Subscript i1, Subscript i2, + Subscript j1, Subscript j2) : A_(A) + { +#ifdef TNT_BOUNDS_CHECK + assert( i1 <= i2 ); + assert( j1 <= j2); + assert( TNT_BASE_OFFSET <= i1); + assert( i2<= A.dim(TNT_BASE_OFFSET) + TNT_BASE_OFFSET-1); + assert( TNT_BASE_OFFSET <= j1); + assert( j2<= A.dim(TNT_BASE_OFFSET+1) + TNT_BASE_OFFSET-1 ); +#endif + + offset_[0] = i1-TNT_BASE_OFFSET; + offset_[1] = j1-TNT_BASE_OFFSET; + dim_[0] = i2-i1+1; + dim_[1] = j2-j1+1; + } + + const_Region2D(const Array2D &A, const Index1D &I, const Index1D &J) + : A_(A) + { +#ifdef TNT_BOUNDS_CHECK + assert( I.lbound() <= I.ubound() ); + assert( J.lbound() <= J.ubound() ); + assert( TNT_BASE_OFFSET <= I.lbound()); + assert( I.ubound()<= A.dim(TNT_BASE_OFFSET) + TNT_BASE_OFFSET-1); + assert( TNT_BASE_OFFSET <= J.lbound()); + assert( J.ubound() <= A.dim(TNT_BASE_OFFSET+1) + TNT_BASE_OFFSET-1 ); +#endif + + offset_[0] = I.lbound()-TNT_BASE_OFFSET; + offset_[1] = J.lbound()-TNT_BASE_OFFSET; + dim_[0] = I.ubound() - I.lbound() + 1; + dim_[1] = J.ubound() - J.lbound() + 1; + } + + + const_Region2D(const_Region2D &A, Subscript i1, + Subscript i2, + Subscript j1, Subscript j2) : A_(A.A_) + { +#ifdef TNT_BOUNDS_CHECK + assert( i1 <= i2 ); + assert( j1 <= j2); + assert( TNT_BASE_OFFSET <= i1); + assert( i2<= A.dim(TNT_BASE_OFFSET) + TNT_BASE_OFFSET-1); + assert( TNT_BASE_OFFSET <= j1); + assert( j2<= A.dim(TNT_BASE_OFFSET+1) + TNT_BASE_OFFSET-1 ); +#endif + offset_[0] = (i1 - TNT_BASE_OFFSET) + A.offset_[0]; + offset_[1] = (j1 - TNT_BASE_OFFSET) + A.offset_[1]; + dim_[0] = i2-i1 + 1; + dim_[1] = j2-j1+1; + } + + const_Region2D operator()(Subscript i1, Subscript i2, + Subscript j1, Subscript j2) + { +#ifdef TNT_BOUNDS_CHECK + assert( i1 <= i2 ); + assert( j1 <= j2); + assert( TNT_BASE_OFFSET <= i1); + assert( i2<= dim_[0] + TNT_BASE_OFFSET-1); + assert( TNT_BASE_OFFSET <= j1); + assert( j2<= dim_[0] + TNT_BASE_OFFSET-1 ); +#endif + return const_Region2D(A_, + i1+offset_[0], offset_[0] + i2, + j1+offset_[1], offset_[1] + j2); + } + + + const_Region2D operator()(const Index1D &I, + const Index1D &J) + { +#ifdef TNT_BOUNDS_CHECK + assert( I.lbound() <= I.ubound() ); + assert( J.lbound() <= J.ubound() ); + assert( TNT_BASE_OFFSET <= I.lbound()); + assert( I.ubound()<= dim_[0] + TNT_BASE_OFFSET-1); + assert( TNT_BASE_OFFSET <= J.lbound()); + assert( J.ubound() <= dim_[1] + TNT_BASE_OFFSET-1 ); +#endif + + return const_Region2D(A_, I.lbound()+offset_[0], + offset_[0] + I.ubound(), offset_[1]+J.lbound(), + offset_[1] + J.ubound()); + } + + + inline const T & operator() (Subscript i, Subscript j) const + { +#ifdef TNT_BOUNDS_CHECK + assert( TNT_BASE_OFFSET <= i); + assert( i<= dim_[0] + TNT_BASE_OFFSET-1); + assert( TNT_BASE_OFFSET <= j); + assert( j<= dim_[1] + TNT_BASE_OFFSET-1 ); +#endif + return A_(i+offset_[0], j+offset_[1]); + } + +}; + + +// ************** std::ostream algorithms ******************************* + +template +std::ostream& operator<<(std::ostream &s, const const_Region2D &A) +{ + Subscript start = A.lbound(); + Subscript Mend=A.lbound()+ A.num_rows() - 1; + Subscript Nend=A.lbound() + A.num_cols() - 1; + + + s << A.num_rows() << " " << A.num_cols() << "\n"; + for (Subscript i=start; i<=Mend; i++) + { + for (Subscript j=start; j<=Nend; j++) + { + s << A(i,j) << " "; + } + s << "\n"; + } + + + return s; +} + +template +std::ostream& operator<<(std::ostream &s, const Region2D &A) +{ + Subscript start = A.lbound(); + Subscript Mend=A.lbound()+ A.num_rows() - 1; + Subscript Nend=A.lbound() + A.num_cols() - 1; + + + s << A.num_rows() << " " << A.num_cols() << "\n"; + for (Subscript i=start; i<=Mend; i++) + { + for (Subscript j=start; j<=Nend; j++) + { + s << A(i,j) << " "; + } + s << "\n"; + } + + + return s; + +} + +} // namespace TNT + +#endif // REGION2D_H + diff --git a/intern/iksolver/intern/TNT/stopwatch.h b/intern/iksolver/intern/TNT/stopwatch.h new file mode 100644 index 00000000000..30cc0fd1641 --- /dev/null +++ b/intern/iksolver/intern/TNT/stopwatch.h @@ -0,0 +1,84 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + +#ifndef STPWATCH_H +#define STPWATCH_H + +// for clock() and CLOCKS_PER_SEC +#include + +namespace TNT +{ + +/* Simple stopwatch object: + + void start() : start timing + double stop() : stop timing + void reset() : set elapsed time to 0.0 + double read() : read elapsed time (in seconds) + +*/ + +inline double seconds(void) +{ + static const double secs_per_tick = 1.0 / CLOCKS_PER_SEC; + return ( (double) clock() ) * secs_per_tick; +} + + +class stopwatch { + private: + int running; + double last_time; + double total; + + public: + stopwatch() : running(0), last_time(0.0), total(0.0) {} + void reset() { running = 0; last_time = 0.0; total=0.0; } + void start() { if (!running) { last_time = seconds(); running = 1;}} + double stop() { if (running) + { + total += seconds() - last_time; + running = 0; + } + return total; + } + double read() { if (running) + { + total+= seconds() - last_time; + last_time = seconds(); + } + return total; + } + +}; + +} // namespace TNT + +#endif + diff --git a/intern/iksolver/intern/TNT/subscript.h b/intern/iksolver/intern/TNT/subscript.h new file mode 100644 index 00000000000..d9e037c43fd --- /dev/null +++ b/intern/iksolver/intern/TNT/subscript.h @@ -0,0 +1,64 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + +#ifndef SUBSCRPT_H +#define SUBSCRPT_H + + +//--------------------------------------------------------------------- +// This definition describes the default TNT data type used for +// indexing into TNT matrices and vectors. The data type should +// be wide enough to index into large arrays. It defaults to an +// "int", but can be overriden at compile time redefining TNT_SUBSCRIPT_TYPE, +// e.g. +// +// g++ -DTNT_SUBSCRIPT_TYPE='unsigned int' ... +// +//--------------------------------------------------------------------- +// + +#ifndef TNT_SUBSCRIPT_TYPE +#define TNT_SUBSCRIPT_TYPE int +#endif + +namespace TNT +{ + typedef TNT_SUBSCRIPT_TYPE Subscript; +} + + +// () indexing in TNT means 1-offset, i.e. x(1) and A(1,1) are the +// first elements. This offset is left as a macro for future +// purposes, but should not be changed in the current release. +// +// +#define TNT_BASE_OFFSET (1) + +#endif + diff --git a/intern/iksolver/intern/TNT/svd.h b/intern/iksolver/intern/TNT/svd.h new file mode 100644 index 00000000000..af281d0fce0 --- /dev/null +++ b/intern/iksolver/intern/TNT/svd.h @@ -0,0 +1,429 @@ +/** + * $Id$ + */ + +#ifndef SVD_H + +#define SVD_H + +// Compute the Single Value Decomposition of an arbitrary matrix A +// That is compute the 3 matrices U,W,V with U column orthogonal (m,n) +// ,W a diagonal matrix and V an orthogonal square matrix s.t. +// A = U.W.Vt. From this decomposition it is trivial to compute the +// inverse of A as Ainv = V.Winv.tranpose(U). +// +// s = diagonal elements of W +// work1 = workspace, length must be A.num_rows +// work2 = workspace, length must be A.num_cols + +#include "tntmath.h" + +namespace TNT +{ + +template +void SVD(MaTRiX &A, MaTRiX &U, VecToR &s, MaTRiX &V, VecToR &work1, VecToR &work2) { + + int m = A.num_rows(); + int n = A.num_cols(); + int nu = min(m,n); + + VecToR& work = work1; + VecToR& e = work2; + + U = 0; + s = 0; + + int i=0, j=0, k=0; + + // Reduce A to bidiagonal form, storing the diagonal elements + // in s and the super-diagonal elements in e. + + int nct = min(m-1,n); + int nrt = max(0,min(n-2,m)); + for (k = 0; k < max(nct,nrt); k++) { + if (k < nct) { + + // Compute the transformation for the k-th column and + // place the k-th diagonal in s[k]. + // Compute 2-norm of k-th column without under/overflow. + s[k] = 0; + for (i = k; i < m; i++) { + s[k] = hypot(s[k],A[i][k]); + } + if (s[k] != 0.0) { + if (A[k][k] < 0.0) { + s[k] = -s[k]; + } + for (i = k; i < m; i++) { + A[i][k] /= s[k]; + } + A[k][k] += 1.0; + } + s[k] = -s[k]; + } + for (j = k+1; j < n; j++) { + if ((k < nct) && (s[k] != 0.0)) { + + // Apply the transformation. + + typename MaTRiX::value_type t = 0; + for (i = k; i < m; i++) { + t += A[i][k]*A[i][j]; + } + t = -t/A[k][k]; + for (i = k; i < m; i++) { + A[i][j] += t*A[i][k]; + } + } + + // Place the k-th row of A into e for the + // subsequent calculation of the row transformation. + + e[j] = A[k][j]; + } + if (k < nct) { + + // Place the transformation in U for subsequent back + // multiplication. + + for (i = k; i < m; i++) + U[i][k] = A[i][k]; + } + if (k < nrt) { + + // Compute the k-th row transformation and place the + // k-th super-diagonal in e[k]. + // Compute 2-norm without under/overflow. + e[k] = 0; + for (i = k+1; i < n; i++) { + e[k] = hypot(e[k],e[i]); + } + if (e[k] != 0.0) { + if (e[k+1] < 0.0) { + e[k] = -e[k]; + } + for (i = k+1; i < n; i++) { + e[i] /= e[k]; + } + e[k+1] += 1.0; + } + e[k] = -e[k]; + if ((k+1 < m) & (e[k] != 0.0)) { + + // Apply the transformation. + + for (i = k+1; i < m; i++) { + work[i] = 0.0; + } + for (j = k+1; j < n; j++) { + for (i = k+1; i < m; i++) { + work[i] += e[j]*A[i][j]; + } + } + for (j = k+1; j < n; j++) { + typename MaTRiX::value_type t = -e[j]/e[k+1]; + for (i = k+1; i < m; i++) { + A[i][j] += t*work[i]; + } + } + } + + // Place the transformation in V for subsequent + // back multiplication. + + for (i = k+1; i < n; i++) + V[i][k] = e[i]; + } + } + + // Set up the final bidiagonal matrix or order p. + + int p = min(n,m+1); + if (nct < n) { + s[nct] = A[nct][nct]; + } + if (m < p) { + s[p-1] = 0.0; + } + if (nrt+1 < p) { + e[nrt] = A[nrt][p-1]; + } + e[p-1] = 0.0; + + // If required, generate U. + + for (j = nct; j < nu; j++) { + for (i = 0; i < m; i++) { + U[i][j] = 0.0; + } + U[j][j] = 1.0; + } + for (k = nct-1; k >= 0; k--) { + if (s[k] != 0.0) { + for (j = k+1; j < nu; j++) { + typename MaTRiX::value_type t = 0; + for (i = k; i < m; i++) { + t += U[i][k]*U[i][j]; + } + t = -t/U[k][k]; + for (i = k; i < m; i++) { + U[i][j] += t*U[i][k]; + } + } + for (i = k; i < m; i++ ) { + U[i][k] = -U[i][k]; + } + U[k][k] = 1.0 + U[k][k]; + for (i = 0; i < k-1; i++) { + U[i][k] = 0.0; + } + } else { + for (i = 0; i < m; i++) { + U[i][k] = 0.0; + } + U[k][k] = 1.0; + } + } + + // If required, generate V. + + for (k = n-1; k >= 0; k--) { + if ((k < nrt) & (e[k] != 0.0)) { + for (j = k+1; j < nu; j++) { + typename MaTRiX::value_type t = 0; + for (i = k+1; i < n; i++) { + t += V[i][k]*V[i][j]; + } + t = -t/V[k+1][k]; + for (i = k+1; i < n; i++) { + V[i][j] += t*V[i][k]; + } + } + } + for (i = 0; i < n; i++) { + V[i][k] = 0.0; + } + V[k][k] = 1.0; + } + + // Main iteration loop for the singular values. + + int pp = p-1; + int iter = 0; + typename MaTRiX::value_type eps = pow(2.0,-52.0); + while (p > 0) { + int kase=0; + k=0; + + // Here is where a test for too many iterations would go. + + // This section of the program inspects for + // negligible elements in the s and e arrays. On + // completion the variables kase and k are set as follows. + + // kase = 1 if s(p) and e[k-1] are negligible and k

= -1; k--) { + if (k == -1) { + break; + } + if (TNT::abs(e[k]) <= eps*(TNT::abs(s[k]) + TNT::abs(s[k+1]))) { + e[k] = 0.0; + break; + } + } + if (k == p-2) { + kase = 4; + } else { + int ks; + for (ks = p-1; ks >= k; ks--) { + if (ks == k) { + break; + } + typename MaTRiX::value_type t = (ks != p ? TNT::abs(e[ks]) : 0.) + + (ks != k+1 ? TNT::abs(e[ks-1]) : 0.); + if (TNT::abs(s[ks]) <= eps*t) { + s[ks] = 0.0; + break; + } + } + if (ks == k) { + kase = 3; + } else if (ks == p-1) { + kase = 1; + } else { + kase = 2; + k = ks; + } + } + k++; + + // Perform the task indicated by kase. + + switch (kase) { + + // Deflate negligible s(p). + + case 1: { + typename MaTRiX::value_type f = e[p-2]; + e[p-2] = 0.0; + for (j = p-2; j >= k; j--) { + typename MaTRiX::value_type t = hypot(s[j],f); + typename MaTRiX::value_type cs = s[j]/t; + typename MaTRiX::value_type sn = f/t; + s[j] = t; + if (j != k) { + f = -sn*e[j-1]; + e[j-1] = cs*e[j-1]; + } + + for (i = 0; i < n; i++) { + t = cs*V[i][j] + sn*V[i][p-1]; + V[i][p-1] = -sn*V[i][j] + cs*V[i][p-1]; + V[i][j] = t; + } + } + } + break; + + // Split at negligible s(k). + + case 2: { + typename MaTRiX::value_type f = e[k-1]; + e[k-1] = 0.0; + for (j = k; j < p; j++) { + typename MaTRiX::value_type t = hypot(s[j],f); + typename MaTRiX::value_type cs = s[j]/t; + typename MaTRiX::value_type sn = f/t; + s[j] = t; + f = -sn*e[j]; + e[j] = cs*e[j]; + + for (i = 0; i < m; i++) { + t = cs*U[i][j] + sn*U[i][k-1]; + U[i][k-1] = -sn*U[i][j] + cs*U[i][k-1]; + U[i][j] = t; + } + } + } + break; + + // Perform one qr step. + + case 3: { + + // Calculate the shift. + + typename MaTRiX::value_type scale = max(max(max(max( + TNT::abs(s[p-1]),TNT::abs(s[p-2])),TNT::abs(e[p-2])), + TNT::abs(s[k])),TNT::abs(e[k])); + typename MaTRiX::value_type sp = s[p-1]/scale; + typename MaTRiX::value_type spm1 = s[p-2]/scale; + typename MaTRiX::value_type epm1 = e[p-2]/scale; + typename MaTRiX::value_type sk = s[k]/scale; + typename MaTRiX::value_type ek = e[k]/scale; + typename MaTRiX::value_type b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/2.0; + typename MaTRiX::value_type c = (sp*epm1)*(sp*epm1); + typename MaTRiX::value_type shift = 0.0; + if ((b != 0.0) || (c != 0.0)) { + shift = sqrt(b*b + c); + if (b < 0.0) { + shift = -shift; + } + shift = c/(b + shift); + } + typename MaTRiX::value_type f = (sk + sp)*(sk - sp) + shift; + typename MaTRiX::value_type g = sk*ek; + + // Chase zeros. + + for (j = k; j < p-1; j++) { + typename MaTRiX::value_type t = hypot(f,g); + typename MaTRiX::value_type cs = f/t; + typename MaTRiX::value_type sn = g/t; + if (j != k) { + e[j-1] = t; + } + f = cs*s[j] + sn*e[j]; + e[j] = cs*e[j] - sn*s[j]; + g = sn*s[j+1]; + s[j+1] = cs*s[j+1]; + + for (i = 0; i < n; i++) { + t = cs*V[i][j] + sn*V[i][j+1]; + V[i][j+1] = -sn*V[i][j] + cs*V[i][j+1]; + V[i][j] = t; + } + + t = hypot(f,g); + cs = f/t; + sn = g/t; + s[j] = t; + f = cs*e[j] + sn*s[j+1]; + s[j+1] = -sn*e[j] + cs*s[j+1]; + g = sn*e[j+1]; + e[j+1] = cs*e[j+1]; + if (j < m-1) { + for (i = 0; i < m; i++) { + t = cs*U[i][j] + sn*U[i][j+1]; + U[i][j+1] = -sn*U[i][j] + cs*U[i][j+1]; + U[i][j] = t; + } + } + } + e[p-2] = f; + iter = iter + 1; + } + break; + + // Convergence. + + case 4: { + + // Make the singular values positive. + + if (s[k] <= 0.0) { + s[k] = (s[k] < 0.0 ? -s[k] : 0.0); + + for (i = 0; i <= pp; i++) + V[i][k] = -V[i][k]; + } + + // Order the singular values. + + while (k < pp) { + if (s[k] >= s[k+1]) { + break; + } + typename MaTRiX::value_type t = s[k]; + s[k] = s[k+1]; + s[k+1] = t; + if (k < n-1) { + for (i = 0; i < n; i++) { + t = V[i][k+1]; V[i][k+1] = V[i][k]; V[i][k] = t; + } + } + if (k < m-1) { + for (i = 0; i < m; i++) { + t = U[i][k+1]; U[i][k+1] = U[i][k]; U[i][k] = t; + } + } + k++; + } + iter = 0; + p--; + } + break; + } + } +} + +} + +#endif + diff --git a/intern/iksolver/intern/TNT/tnt.h b/intern/iksolver/intern/TNT/tnt.h new file mode 100644 index 00000000000..6c65a0bedcd --- /dev/null +++ b/intern/iksolver/intern/TNT/tnt.h @@ -0,0 +1,94 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + +#ifndef TNT_H +#define TNT_H + +//--------------------------------------------------------------------- +// tnt.h TNT general header file. Defines default types +// and conventions. +//--------------------------------------------------------------------- + +//--------------------------------------------------------------------- +// Include current version +//--------------------------------------------------------------------- +#include "version.h" + +//--------------------------------------------------------------------- +// Define the data type used for matrix and vector Subscripts. +// This will default to "int", but it can be overriden at compile time, +// e.g. +// +// g++ -DTNT_SUBSCRIPT_TYPE='unsinged long' ... +// +// See subscript.h for details. +//--------------------------------------------------------------------- + +#include "subscript.h" + + + +//--------------------------------------------------------------------- +// Define this macro if you want TNT to ensure all refernces +// are within the bounds of the array. This encurs a run-time +// overhead, of course, but is recommended while developing +// code. It can be turned off for production runs. +// +// #define TNT_BOUNDS_CHECK +//--------------------------------------------------------------------- +// +#define TNT_BOUNDS_CHECK +#ifdef TNT_NO_BOUNDS_CHECK +#undef TNT_BOUNDS_CHECK +#endif + +//--------------------------------------------------------------------- +// Define this macro if you want to utilize matrix and vector +// regions. This is typically on, but you can save some +// compilation time by turning it off. If you do this and +// attempt to use regions you will get an error message. +// +// #define TNT_USE_REGIONS +//--------------------------------------------------------------------- +// +#define TNT_USE_REGIONS + +//--------------------------------------------------------------------- +// +//--------------------------------------------------------------------- +// if your system doesn't have abs() min(), and max() uncoment the following +//--------------------------------------------------------------------- +// +// +//#define __NEED_ABS_MIN_MAX_ + +#include "tntmath.h" + +#endif // TNT_H + diff --git a/intern/iksolver/intern/TNT/tntmath.h b/intern/iksolver/intern/TNT/tntmath.h new file mode 100644 index 00000000000..5773900caf9 --- /dev/null +++ b/intern/iksolver/intern/TNT/tntmath.h @@ -0,0 +1,153 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + + +// Header file for scalar math functions + +#ifndef TNTMATH_H +#define TNTMATH_H + +// conventional functions required by several matrix algorithms + + + +namespace TNT +{ + +struct TNTException { + int i; +}; + + +inline double abs(double t) +{ + return ( t > 0 ? t : -t); +} + +inline double min(double a, double b) +{ + return (a < b ? a : b); +} + +inline double max(double a, double b) +{ + return (a > b ? a : b); +} + +inline float abs(float t) +{ + return ( t > 0 ? t : -t); +} + +inline float min(float a, float b) +{ + return (a < b ? a : b); +} + +inline int min(int a, int b) +{ + return (a < b ? a : b); +} + +inline int max(int a, int b) +{ + return (a > b ? a : b); +} + +inline float max(float a, float b) +{ + return (a > b ? a : b); +} + +inline double sign(double a) +{ + return (a > 0 ? 1.0 : -1.0); +} + +inline double sign(double a,double b) { + return (b >= 0.0 ? TNT::abs(a) : -TNT::abs(a)); +} + +inline float sign(float a,float b) { + return (b >= 0.0f ? TNT::abs(a) : -TNT::abs(a)); +} + +inline float sign(float a) +{ + return (a > 0.0 ? 1.0f : -1.0f); +} + +inline float pythag(float a, float b) +{ + float absa,absb; + absa = abs(a); + absb = abs(b); + + if (absa > absb) { + float sqr = absb/absa; + sqr *= sqr; + return absa * float(sqrt(1 + sqr)); + } else { + if (absb > float(0)) { + float sqr = absa/absb; + sqr *= sqr; + return absb * float(sqrt(1 + sqr)); + } else { + return float(0); + } + } +} + +inline double pythag(double a, double b) +{ + double absa,absb; + absa = abs(a); + absb = abs(b); + + if (absa > absb) { + double sqr = absb/absa; + sqr *= sqr; + return absa * double(sqrt(1 + sqr)); + } else { + + if (absb > double(0)) { + double sqr = absa/absb; + sqr *= sqr; + return absb * double(sqrt(1 + sqr)); + } else { + return double(0); + } + } +} + + +} /* namespace TNT */ + +#endif /* TNTMATH_H */ + diff --git a/intern/iksolver/intern/TNT/tntreqs.h b/intern/iksolver/intern/TNT/tntreqs.h new file mode 100644 index 00000000000..75b79fd86a9 --- /dev/null +++ b/intern/iksolver/intern/TNT/tntreqs.h @@ -0,0 +1,74 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + +// The requirements for a bare-bones vector class: +// +// +// o) must have 0-based [] indexing for const and +// non-const objects (i.e. operator[] defined) +// +// o) must have size() method to denote the number of +// elements +// o) must clean up after itself when destructed +// (i.e. no memory leaks) +// +// -) must have begin() and end() methods (The begin() +// method is necessary, because relying on +// &v_[0] may not work on a empty vector (i.e. v_ is NULL.) +// +// o) must be templated +// o) must have X::value_type defined to be the types of elements +// o) must have X::X(const &x) copy constructor (by *value*) +// o) must have X::X(int N) constructor to N-length vector +// (NOTE: this constructor need *NOT* initalize elements) +// +// -) must have X::X(int N, T scalar) constructor to initalize +// elements to value of "scalar". +// +// ( removed, because valarray<> class uses (scalar, N) rather +// than (N, scalar) ) +// -) must have X::X(int N, const T* scalars) constructor to copy from +// any C linear array +// +// ( removed, because of same reverse order of valarray<> ) +// +// o) must have assignment A=B, by value +// +// NOTE: this class is *NOT* meant to be derived from, +// so its methods (particularly indexing) need not be +// declared virtual. +// +// +// Some things it *DOES NOT* need to do are +// +// o) bounds checking +// o) array referencing (e.g. reference counting) +// o) support () indexing +// o) I/O +// + diff --git a/intern/iksolver/intern/TNT/transv.h b/intern/iksolver/intern/TNT/transv.h new file mode 100644 index 00000000000..dca3d09b4ac --- /dev/null +++ b/intern/iksolver/intern/TNT/transv.h @@ -0,0 +1,165 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + + +// Matrix Transpose Views + +#ifndef TRANSV_H +#define TRANSV_H + +#include +#include +#include "vec.h" + +namespace TNT +{ + +template +class Transpose_View +{ + protected: + + const Array2D & A_; + + public: + + typedef typename Array2D::element_type T; + typedef T value_type; + typedef T element_type; + typedef T* pointer; + typedef T* iterator; + typedef T& reference; + typedef const T* const_iterator; + typedef const T& const_reference; + + + const Array2D & array() const { return A_; } + Subscript num_rows() const { return A_.num_cols();} + Subscript num_cols() const { return A_.num_rows();} + Subscript lbound() const { return A_.lbound(); } + Subscript dim(Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert( A_.lbound() <= i); + assert( i<= A_.lbound()+1); +#endif + if (i== A_.lbound()) + return num_rows(); + else + return num_cols(); + } + + + Transpose_View(const Transpose_View &A) : A_(A.A_) {}; + Transpose_View(const Array2D &A) : A_(A) {}; + + + inline const typename Array2D::element_type & operator()( + Subscript i, Subscript j) const + { +#ifdef TNT_BOUNDS_CHECK + assert(lbound()<=i); + assert(i<=A_.num_cols() + lbound() - 1); + assert(lbound()<=j); + assert(j<=A_.num_rows() + lbound() - 1); +#endif + + return A_(j,i); + } + + +}; + +template +Transpose_View Transpose_view(const Matrix &A) +{ + return Transpose_View(A); +} + +template +Vector matmult( + const Transpose_View & A, + const Vector &B) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(B.dim() == N); + + Vector x(N); + + Subscript i, j; + T tmp = 0; + + for (i=1; i<=M; i++) + { + tmp = 0; + for (j=1; j<=N; j++) + tmp += A(i,j) * B(j); + x(i) = tmp; + } + + return x; +} + +template +inline Vector operator*(const Transpose_View & A, const Vector &B) +{ + return matmult(A,B); +} + + +template +std::ostream& operator<<(std::ostream &s, const Transpose_View &A) +{ + Subscript M=A.num_rows(); + Subscript N=A.num_cols(); + + Subscript start = A.lbound(); + Subscript Mend = M + A.lbound() - 1; + Subscript Nend = N + A.lbound() - 1; + + s << M << " " << N << endl; + for (Subscript i=start; i<=Mend; i++) + { + for (Subscript j=start; j<=Nend; j++) + { + s << A(i,j) << " "; + } + s << endl; + } + + + return s; +} + +} // namespace TNT + +#endif // TRANSV_H + diff --git a/intern/iksolver/intern/TNT/triang.h b/intern/iksolver/intern/TNT/triang.h new file mode 100644 index 00000000000..73b98afbb40 --- /dev/null +++ b/intern/iksolver/intern/TNT/triang.h @@ -0,0 +1,638 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + + +// Triangular Matrices (Views and Adpators) + +#ifndef TRIANG_H +#define TRIANG_H + +// default to use lower-triangular portions of arrays +// for symmetric matrices. + +namespace TNT +{ + +template +class LowerTriangularView +{ + protected: + + + const MaTRiX &A_; + const typename MaTRiX::element_type zero_; + + public: + + + typedef typename MaTRiX::const_reference const_reference; + typedef const typename MaTRiX::element_type element_type; + typedef const typename MaTRiX::element_type value_type; + typedef element_type T; + + Subscript dim(Subscript d) const { return A_.dim(d); } + Subscript lbound() const { return A_.lbound(); } + Subscript num_rows() const { return A_.num_rows(); } + Subscript num_cols() const { return A_.num_cols(); } + + + // constructors + + LowerTriangularView(/*const*/ MaTRiX &A) : A_(A), zero_(0) {} + + + inline const_reference get(Subscript i, Subscript j) const + { +#ifdef TNT_BOUNDS_CHECK + assert(lbound()<=i); + assert(i<=A_.num_rows() + lbound() - 1); + assert(lbound()<=j); + assert(j<=A_.num_cols() + lbound() - 1); +#endif + if (i > + const_Region; + + const_Region operator()(/*const*/ Index1D &I, + /*const*/ Index1D &J) const + { + return const_Region(*this, I, J); + } + + const_Region operator()(Subscript i1, Subscript i2, + Subscript j1, Subscript j2) const + { + return const_Region(*this, i1, i2, j1, j2); + } + + + +#endif +// TNT_USE_REGIONS + +}; + + +/* *********** Lower_triangular_view() algorithms ****************** */ + +template +VecToR matmult(/*const*/ LowerTriangularView &A, VecToR &x) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(N == x.dim()); + + Subscript i, j; + typename MaTRiX::element_type sum=0.0; + VecToR result(M); + + Subscript start = A.lbound(); + Subscript Mend = M + A.lbound() -1 ; + + for (i=start; i<=Mend; i++) + { + sum = 0.0; + for (j=start; j<=i; j++) + sum = sum + A(i,j)*x(j); + result(i) = sum; + } + + return result; +} + +template +inline VecToR operator*(/*const*/ LowerTriangularView &A, VecToR &x) +{ + return matmult(A,x); +} + +template +class UnitLowerTriangularView +{ + protected: + + const MaTRiX &A_; + const typename MaTRiX::element_type zero; + const typename MaTRiX::element_type one; + + public: + + typedef typename MaTRiX::const_reference const_reference; + typedef typename MaTRiX::element_type element_type; + typedef typename MaTRiX::element_type value_type; + typedef element_type T; + + Subscript lbound() const { return 1; } + Subscript dim(Subscript d) const { return A_.dim(d); } + Subscript num_rows() const { return A_.num_rows(); } + Subscript num_cols() const { return A_.num_cols(); } + + + // constructors + + UnitLowerTriangularView(/*const*/ MaTRiX &A) : A_(A), zero(0), one(1) {} + + + inline const_reference get(Subscript i, Subscript j) const + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i<=A_.dim(1)); + assert(1<=j); + assert(j<=A_.dim(2)); + assert(0<=i && ij) + return A_(i,j); + else if (i==j) + return one; + else + return zero; + } + + + inline const_reference operator() (Subscript i, Subscript j) const + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i<=A_.dim(1)); + assert(1<=j); + assert(j<=A_.dim(2)); +#endif + if (i>j) + return A_(i,j); + else if (i==j) + return one; + else + return zero; + } + + +#ifdef TNT_USE_REGIONS + // These are the "index-aware" features + + typedef const_Region2D< UnitLowerTriangularView > + const_Region; + + const_Region operator()(/*const*/ Index1D &I, + /*const*/ Index1D &J) const + { + return const_Region(*this, I, J); + } + + const_Region operator()(Subscript i1, Subscript i2, + Subscript j1, Subscript j2) const + { + return const_Region(*this, i1, i2, j1, j2); + } +#endif +// TNT_USE_REGIONS +}; + +template +LowerTriangularView Lower_triangular_view( + /*const*/ MaTRiX &A) +{ + return LowerTriangularView(A); +} + + +template +UnitLowerTriangularView Unit_lower_triangular_view( + /*const*/ MaTRiX &A) +{ + return UnitLowerTriangularView(A); +} + +template +VecToR matmult(/*const*/ UnitLowerTriangularView &A, VecToR &x) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(N == x.dim()); + + Subscript i, j; + typename MaTRiX::element_type sum=0.0; + VecToR result(M); + + Subscript start = A.lbound(); + Subscript Mend = M + A.lbound() -1 ; + + for (i=start; i<=Mend; i++) + { + sum = 0.0; + for (j=start; j +inline VecToR operator*(/*const*/ UnitLowerTriangularView &A, VecToR &x) +{ + return matmult(A,x); +} + + +//********************** Algorithms ************************************* + + + +template +std::ostream& operator<<(std::ostream &s, const LowerTriangularView&A) +{ + Subscript M=A.num_rows(); + Subscript N=A.num_cols(); + + s << M << " " << N << endl; + + for (Subscript i=1; i<=M; i++) + { + for (Subscript j=1; j<=N; j++) + { + s << A(i,j) << " "; + } + s << endl; + } + + + return s; +} + +template +std::ostream& operator<<(std::ostream &s, + const UnitLowerTriangularView&A) +{ + Subscript M=A.num_rows(); + Subscript N=A.num_cols(); + + s << M << " " << N << endl; + + for (Subscript i=1; i<=M; i++) + { + for (Subscript j=1; j<=N; j++) + { + s << A(i,j) << " "; + } + s << endl; + } + + + return s; +} + + + +// ******************* Upper Triangular Section ************************** + +template +class UpperTriangularView +{ + protected: + + + /*const*/ MaTRiX &A_; + /*const*/ typename MaTRiX::element_type zero_; + + public: + + + typedef typename MaTRiX::const_reference const_reference; + typedef /*const*/ typename MaTRiX::element_type element_type; + typedef /*const*/ typename MaTRiX::element_type value_type; + typedef element_type T; + + Subscript dim(Subscript d) const { return A_.dim(d); } + Subscript lbound() const { return A_.lbound(); } + Subscript num_rows() const { return A_.num_rows(); } + Subscript num_cols() const { return A_.num_cols(); } + + + // constructors + + UpperTriangularView(/*const*/ MaTRiX &A) : A_(A), zero_(0) {} + + + inline const_reference get(Subscript i, Subscript j) const + { +#ifdef TNT_BOUNDS_CHECK + assert(lbound()<=i); + assert(i<=A_.num_rows() + lbound() - 1); + assert(lbound()<=j); + assert(j<=A_.num_cols() + lbound() - 1); +#endif + if (i>j) + return zero_; + else + return A_(i,j); + } + + + inline const_reference operator() (Subscript i, Subscript j) const + { +#ifdef TNT_BOUNDS_CHECK + assert(lbound()<=i); + assert(i<=A_.num_rows() + lbound() - 1); + assert(lbound()<=j); + assert(j<=A_.num_cols() + lbound() - 1); +#endif + if (i>j) + return zero_; + else + return A_(i,j); + } + +#ifdef TNT_USE_REGIONS + + typedef const_Region2D< UpperTriangularView > + const_Region; + + const_Region operator()(const Index1D &I, + const Index1D &J) const + { + return const_Region(*this, I, J); + } + + const_Region operator()(Subscript i1, Subscript i2, + Subscript j1, Subscript j2) const + { + return const_Region(*this, i1, i2, j1, j2); + } + + + +#endif +// TNT_USE_REGIONS + +}; + + +/* *********** Upper_triangular_view() algorithms ****************** */ + +template +VecToR matmult(/*const*/ UpperTriangularView &A, VecToR &x) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(N == x.dim()); + + Subscript i, j; + typename VecToR::element_type sum=0.0; + VecToR result(M); + + Subscript start = A.lbound(); + Subscript Mend = M + A.lbound() -1 ; + + for (i=start; i<=Mend; i++) + { + sum = 0.0; + for (j=i; j<=N; j++) + sum = sum + A(i,j)*x(j); + result(i) = sum; + } + + return result; +} + +template +inline VecToR operator*(/*const*/ UpperTriangularView &A, VecToR &x) +{ + return matmult(A,x); +} + +template +class UnitUpperTriangularView +{ + protected: + + const MaTRiX &A_; + const typename MaTRiX::element_type zero; + const typename MaTRiX::element_type one; + + public: + + typedef typename MaTRiX::const_reference const_reference; + typedef typename MaTRiX::element_type element_type; + typedef typename MaTRiX::element_type value_type; + typedef element_type T; + + Subscript lbound() const { return 1; } + Subscript dim(Subscript d) const { return A_.dim(d); } + Subscript num_rows() const { return A_.num_rows(); } + Subscript num_cols() const { return A_.num_cols(); } + + + // constructors + + UnitUpperTriangularView(/*const*/ MaTRiX &A) : A_(A), zero(0), one(1) {} + + + inline const_reference get(Subscript i, Subscript j) const + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i<=A_.dim(1)); + assert(1<=j); + assert(j<=A_.dim(2)); + assert(0<=i && i > + const_Region; + + const_Region operator()(const Index1D &I, + const Index1D &J) const + { + return const_Region(*this, I, J); + } + + const_Region operator()(Subscript i1, Subscript i2, + Subscript j1, Subscript j2) const + { + return const_Region(*this, i1, i2, j1, j2); + } +#endif +// TNT_USE_REGIONS +}; + +template +UpperTriangularView Upper_triangular_view( + /*const*/ MaTRiX &A) +{ + return UpperTriangularView(A); +} + + +template +UnitUpperTriangularView Unit_upper_triangular_view( + /*const*/ MaTRiX &A) +{ + return UnitUpperTriangularView(A); +} + +template +VecToR matmult(/*const*/ UnitUpperTriangularView &A, VecToR &x) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(N == x.dim()); + + Subscript i, j; + typename VecToR::element_type sum=0.0; + VecToR result(M); + + Subscript start = A.lbound(); + Subscript Mend = M + A.lbound() -1 ; + + for (i=start; i<=Mend; i++) + { + sum = x(i); + for (j=i+1; j<=N; j++) + sum = sum + A(i,j)*x(j); + result(i) = sum + x(i); + } + + return result; +} + +template +inline VecToR operator*(/*const*/ UnitUpperTriangularView &A, VecToR &x) +{ + return matmult(A,x); +} + + +//********************** Algorithms ************************************* + + + +template +std::ostream& operator<<(std::ostream &s, + /*const*/ UpperTriangularView&A) +{ + Subscript M=A.num_rows(); + Subscript N=A.num_cols(); + + s << M << " " << N << endl; + + for (Subscript i=1; i<=M; i++) + { + for (Subscript j=1; j<=N; j++) + { + s << A(i,j) << " "; + } + s << endl; + } + + + return s; +} + +template +std::ostream& operator<<(std::ostream &s, + /*const*/ UnitUpperTriangularView&A) +{ + Subscript M=A.num_rows(); + Subscript N=A.num_cols(); + + s << M << " " << N << endl; + + for (Subscript i=1; i<=M; i++) + { + for (Subscript j=1; j<=N; j++) + { + s << A(i,j) << " "; + } + s << endl; + } + + + return s; +} + +} // namespace TNT + +#endif //TRIANG_H + diff --git a/intern/iksolver/intern/TNT/trisolve.h b/intern/iksolver/intern/TNT/trisolve.h new file mode 100644 index 00000000000..255eb0ca0c6 --- /dev/null +++ b/intern/iksolver/intern/TNT/trisolve.h @@ -0,0 +1,189 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + + +// Triangular Solves + +#ifndef TRISLV_H +#define TRISLV_H + + +#include "triang.h" + +namespace TNT +{ + +template +VecToR Lower_triangular_solve(/*const*/ MaTriX &A, /*const*/ VecToR &b) +{ + Subscript N = A.num_rows(); + + // make sure matrix sizes agree; A must be square + + assert(A.num_cols() == N); + assert(b.dim() == N); + + VecToR x(N); + + Subscript i; + for (i=1; i<=N; i++) + { + typename MaTriX::element_type tmp=0; + + for (Subscript j=1; j +VecToR Unit_lower_triangular_solve(/*const*/ MaTriX &A, /*const*/ VecToR &b) +{ + Subscript N = A.num_rows(); + + // make sure matrix sizes agree; A must be square + + assert(A.num_cols() == N); + assert(b.dim() == N); + + VecToR x(N); + + Subscript i; + for (i=1; i<=N; i++) + { + + typename MaTriX::element_type tmp=0; + + for (Subscript j=1; j +VecToR linear_solve(/*const*/ LowerTriangularView &A, + /*const*/ VecToR &b) +{ + return Lower_triangular_solve(A, b); +} + +template +VecToR linear_solve(/*const*/ UnitLowerTriangularView &A, + /*const*/ VecToR &b) +{ + return Unit_lower_triangular_solve(A, b); +} + + + +//********************** Upper triangular section **************** + +template +VecToR Upper_triangular_solve(/*const*/ MaTriX &A, /*const*/ VecToR &b) +{ + Subscript N = A.num_rows(); + + // make sure matrix sizes agree; A must be square + + assert(A.num_cols() == N); + assert(b.dim() == N); + + VecToR x(N); + + Subscript i; + for (i=N; i>=1; i--) + { + + typename MaTriX::element_type tmp=0; + + for (Subscript j=i+1; j<=N; j++) + tmp = tmp + A(i,j)*x(j); + + x(i) = (b(i) - tmp)/ A(i,i); + } + + return x; +} + + +template +VecToR Unit_upper_triangular_solve(/*const*/ MaTriX &A, /*const*/ VecToR &b) +{ + Subscript N = A.num_rows(); + + // make sure matrix sizes agree; A must be square + + assert(A.num_cols() == N); + assert(b.dim() == N); + + VecToR x(N); + + Subscript i; + for (i=N; i>=1; i--) + { + + typename MaTriX::element_type tmp=0; + + for (Subscript j=i+1; j +VecToR linear_solve(/*const*/ UpperTriangularView &A, + /*const*/ VecToR &b) +{ + return Upper_triangular_solve(A, b); +} + +template +VecToR linear_solve(/*const*/ UnitUpperTriangularView &A, + /*const*/ VecToR &b) +{ + return Unit_upper_triangular_solve(A, b); +} + + +} // namespace TNT + +#endif // TRISLV_H + diff --git a/intern/iksolver/intern/TNT/vec.h b/intern/iksolver/intern/TNT/vec.h new file mode 100644 index 00000000000..1729d83ca10 --- /dev/null +++ b/intern/iksolver/intern/TNT/vec.h @@ -0,0 +1,492 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + +// Basic TNT numerical vector (0-based [i] AND 1-based (i) indexing ) +// + +#ifndef VEC_H +#define VEC_H + +#include "subscript.h" +#include +#include +#include + +namespace TNT +{ + +template +class Vector +{ + + + public: + + typedef Subscript size_type; + typedef T value_type; + typedef T element_type; + typedef T* pointer; + typedef T* iterator; + typedef T& reference; + typedef const T* const_iterator; + typedef const T& const_reference; + + Subscript lbound() const { return 1;} + + protected: + T* v_; + T* vm1_; // pointer adjustment for optimzied 1-offset indexing + Subscript n_; + + // internal helper function to create the array + // of row pointers + + void initialize(Subscript N) + { + // adjust pointers so that they are 1-offset: + // v_[] is the internal contiguous array, it is still 0-offset + // + assert(v_ == NULL); + v_ = new T[N]; + assert(v_ != NULL); + vm1_ = v_-1; + n_ = N; + } + + void copy(const T* v) + { + Subscript N = n_; + Subscript i; + +#ifdef TNT_UNROLL_LOOPS + Subscript Nmod4 = N & 3; + Subscript N4 = N - Nmod4; + + for (i=0; i &A) : v_(0), vm1_(0), n_(0) + { + initialize(A.n_); + copy(A.v_); + } + + Vector(Subscript N, const T& value = T()) : v_(0), vm1_(0), n_(0) + { + initialize(N); + set(value); + } + + Vector(Subscript N, const T* v) : v_(0), vm1_(0), n_(0) + { + initialize(N); + copy(v); + } + + + // methods + // + Vector& newsize(Subscript N) + { + if (n_ == N) return *this; + + destroy(); + initialize(N); + + return *this; + } + + + // assignments + // + Vector& operator=(const Vector &A) + { + if (v_ == A.v_) + return *this; + + if (n_ == A.n_) // no need to re-alloc + copy(A.v_); + + else + { + destroy(); + initialize(A.n_); + copy(A.v_); + } + + return *this; + } + + Vector& operator=(const T& scalar) + { + set(scalar); + return *this; + } + + inline Subscript dim() const + { + return n_; + } + + inline Subscript size() const + { + return n_; + } + + + inline reference operator()(Subscript i) + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i <= n_) ; +#endif + return vm1_[i]; + } + + inline const_reference operator() (Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i <= n_) ; +#endif + return vm1_[i]; + } + + inline reference operator[](Subscript i) + { +#ifdef TNT_BOUNDS_CHECK + assert(0<=i); + assert(i < n_) ; +#endif + return v_[i]; + } + + inline const_reference operator[](Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert(0<=i) ; + assert(i < n_) ; +#endif + return v_[i]; + } + + + +}; + + +/* *************************** I/O ********************************/ + +template +std::ostream& operator<<(std::ostream &s, const Vector &A) +{ + Subscript N=A.dim(); + + s << N << std::endl; + + for (Subscript i=0; i +std::istream & operator>>(std::istream &s, Vector &A) +{ + + Subscript N; + + s >> N; + + if ( !(N == A.size() )) + { + A.newsize(N); + } + + + for (Subscript i=0; i> A[i]; + + + return s; +} + +// *******************[ basic matrix algorithms ]*************************** + + +template +Vector operator+(const Vector &A, + const Vector &B) +{ + Subscript N = A.dim(); + + assert(N==B.dim()); + + Vector tmp(N); + Subscript i; + + for (i=0; i +Vector operator-(const Vector &A, + const Vector &B) +{ + Subscript N = A.dim(); + + assert(N==B.dim()); + + Vector tmp(N); + Subscript i; + + for (i=0; i +Vector operator*(const Vector &A, + const Vector &B) +{ + Subscript N = A.dim(); + + assert(N==B.dim()); + + Vector tmp(N); + Subscript i; + + for (i=0; i +Vector operator*(const Vector &A, + const T &B) +{ + Subscript N = A.dim(); + + Vector tmp(N); + Subscript i; + + for (i=0; i +T dot_prod(const Vector &A, const Vector &B) +{ + Subscript N = A.dim(); + assert(N == B.dim()); + + Subscript i; + T sum = 0; + + for (i=0; i +void vectoradd( + Vector &A, + const Vector &B) +{ + const Subscript N = A.dim(); + assert(N==B.dim()); + Subscript i; + + for (i=0; i +void vectoradd( + Vector &C, + const Vector &A, + const Vector &B) +{ + const Subscript N = A.dim(); + assert(N==B.dim()); + Subscript i; + + for (i=0; i +void vectorsub( + Vector &A, + const Vector &B) +{ + const Subscript N = A.dim(); + assert(N==B.dim()); + Subscript i; + + for (i=0; i +void vectorsub( + Vector &C, + const Vector &A, + const Vector &B) +{ + const Subscript N = A.dim(); + assert(N==B.dim()); + Subscript i; + + for (i=0; i +void vectorscale( + Vector &C, + const Vector &A, + const T &B) +{ + const Subscript N = A.dim(); + Subscript i; + + for (i=0; i +void vectorscale( + Vector &A, + const T &B) +{ + const Subscript N = A.dim(); + Subscript i; + + for (i=0; i +#include +#include + +#include "subscript.h" + +#ifdef TNT_USE_REGIONS +#include "region1d.h" +#endif + +namespace TNT +{ + +// see "tntreq.h" for TNT requirements for underlying vector +// class. This need NOT be the STL vector<> class, but a subset +// that provides minimal services. +// +// This is a container adaptor that provides the following services. +// +// o) adds 1-offset operator() access ([] is always 0 offset) +// o) adds TNT_BOUNDS_CHECK to () and [] +// o) adds initialization from strings, e.g. "1.0 2.0 3.0"; +// o) adds newsize(N) function (does not preserve previous values) +// o) adds dim() and dim(1) +// o) adds free() function to release memory used by vector +// o) adds regions, e.g. A(Index(1,10)) = ... +// o) add getVector() method to return adapted container +// o) adds simple I/O for ostreams + +template +class Vector_Adaptor +{ + + public: + typedef typename BBVec::value_type T; + typedef T value_type; + typedef T element_type; + typedef T* pointer; + typedef T* iterator; + typedef T& reference; + typedef const T* const_iterator; + typedef const T& const_reference; + + Subscript lbound() const { return 1; } + + protected: + BBVec v_; + T* vm1_; + + public: + + Subscript size() const { return v_.size(); } + + // These were removed so that the ANSI C++ valarray class + // would work as a possible storage container. + // + // + //iterator begin() { return v_.begin();} + //iterator begin() { return &v_[0];} + // + //iterator end() { return v_.end(); } + //iterator end() { return &v_[0] + v_.size(); } + // + //const_iterator begin() const { return v_.begin();} + //const_iterator begin() const { return &v_[0];} + // + //const_iterator end() const { return v_.end(); } + //const_iterator end() const { return &v_[0] + v_.size(); } + + BBVec& getVector() { return v_; } + Subscript dim() const { return v_.size(); } + Subscript dim(Subscript i) + { +#ifdef TNT_BOUNDS_CHECK + assert(i==TNT_BASE_OFFSET); +#endif + return (i==TNT_BASE_OFFSET ? v_.size() : 0 ); + } + Vector_Adaptor() : v_() {}; + Vector_Adaptor(const Vector_Adaptor &A) : v_(A.v_) + { + vm1_ = ( v_.size() > 0 ? &(v_[0]) -1 : NULL); + + } + + Vector_Adaptor(Subscript N, const T& value = T()) : v_(N) + { + for (Subscript i=0; i 0 ? &(v_[0]) -1 : NULL); + } + + Vector_Adaptor(Subscript N, const T* values) : v_(N) + { + for (Subscript i=0; i 0 ? &(v_[0]) -1 : NULL); + } + Vector_Adaptor(const BBVec & A) : v_(A) + { + vm1_ = ( v_.size() > 0 ? &(v_[0]) -1 : NULL); + } + + // NOTE: this assumes that BBVec(0) constructor creates an + // null vector that does not take up space... It would be + // great to require that BBVec have a corresponding free() + // function, but in particular STL vectors do not. + // + Vector_Adaptor& free() + { + return *this = Vector_Adaptor(0); + } + + Vector_Adaptor& operator=(const Vector_Adaptor &A) + { + v_ = A.v_ ; + vm1_ = ( v_.size() > 0 ? &(v_[0]) -1 : NULL); + return *this; + } + + Vector_Adaptor& newsize(Subscript N) + { + // NOTE: this is not as efficient as it could be + // but to retain compatiblity with STL interface + // we cannot assume underlying implementation + // has a newsize() function. + + return *this = Vector_Adaptor(N); + + } + + Vector_Adaptor& operator=(const T &a) + { + Subscript i; + Subscript N = v_.size(); + for (i=0; i& resize(Subscript N) + { + if (N == size()) return *this; + + Vector_Adaptor tmp(N); + Subscript n = (N < size() ? N : size()); // min(N, size()); + Subscript i; + + for (i=0; i > Region; + + typedef const_Region1D< Vector_Adaptor > const_Region; + + Region operator()(const Index1D &I) + { return Region(*this, I); } + + Region operator()(const Subscript i1, Subscript i2) + { return Region(*this, i1, i2); } + + const_Region operator()(const Index1D &I) const + { return const_Region(*this, I); } + + const_Region operator()(const Subscript i1, Subscript i2) const + { return const_Region(*this, i1, i2); } +#endif +// TNT_USE_REGIONS + + +}; + +#include + +template +std::ostream& operator<<(std::ostream &s, const Vector_Adaptor &A) +{ + Subscript M=A.size(); + + s << M << endl; + for (Subscript i=1; i<=M; i++) + s << A(i) << endl; + return s; +} + +template +std::istream& operator>>(std::istream &s, Vector_Adaptor &A) +{ + Subscript N; + + s >> N; + + A.resize(N); + + for (Subscript i=1; i<=N; i++) + s >> A(i); + + return s; +} + +} // namespace TNT + +#endif + diff --git a/intern/iksolver/intern/TNT/version.h b/intern/iksolver/intern/TNT/version.h new file mode 100644 index 00000000000..55aefbdf31d --- /dev/null +++ b/intern/iksolver/intern/TNT/version.h @@ -0,0 +1,26 @@ +/** + * $Id$ + */ + +// Template Numerical Toolkit (TNT) for Linear Algebra + +// +// BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +// Please see http://math.nist.gov/tnt for updates +// +// R. Pozo +// Mathematical and Computational Sciences Division +// National Institute of Standards and Technology + + +#ifndef TNT_VERSION_H +#define TNT_VERSION_H + + +#define TNT_MAJOR_VERSION '0' +#define TNT_MINOR_VERSION '9' +#define TNT_SUBMINOR_VERSION '4' +#define TNT_VERSION_STRING "0.9.4" + +#endif + diff --git a/intern/iksolver/make/msvc_6_0/iksolver.dsp b/intern/iksolver/make/msvc_6_0/iksolver.dsp new file mode 100644 index 00000000000..c5e842bdd04 --- /dev/null +++ b/intern/iksolver/make/msvc_6_0/iksolver.dsp @@ -0,0 +1,260 @@ +# Microsoft Developer Studio Project File - Name="iksolver" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=iksolver - 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 "iksolver.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 "iksolver.mak" CFG="iksolver - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "iksolver - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "iksolver - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "iksolver - 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 "..\..\..\..\obj\windows\intern\iksolver" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\iksolver" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /Ob2 /I "..\..\..\..\intern\moto\include" /I "..\..\..\..\intern\memutil" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\iksolver\libiksolver.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\extern\*.h ..\..\..\..\..\lib\windows\iksolver\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\iksolver\*.lib ..\..\..\..\..\lib\windows\iksolver\lib\*.a ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "iksolver - 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 "..\..\..\..\obj\windows\intern\iksolver\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\iksolver\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\..\intern\moto\include" /I "..\..\..\..\intern\memutil" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\iksolver\debug\libiksolver.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\extern\*.h ..\..\..\..\..\lib\windows\iksolver\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\iksolver\debug\*.lib ..\..\..\..\..\lib\windows\iksolver\lib\debug\*.a ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "iksolver - Win32 Release" +# Name "iksolver - Win32 Debug" +# Begin Group "intern" + +# PROP Default_Filter "" +# Begin Group "common" + +# PROP Default_Filter "" +# End Group +# Begin Group "TNT" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\intern\TNT\cholesky.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\cmat.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\fcscmat.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\fmat.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\fortran.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\fspvec.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\index.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\lapack.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\lu.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\qr.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\region1d.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\region2d.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\stopwatch.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\subscript.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\svd.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\tnt.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\tntmath.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\tntreqs.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\transv.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\triang.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\trisolve.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\vec.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\vecadaptor.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\version.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\intern\IK_QJacobian.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\IK_QJacobian.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\IK_QJacobianSolver.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\IK_QJacobianSolver.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\IK_QSegment.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\IK_QSegment.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\IK_QSolver_Class.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\IK_QTask.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\IK_QTask.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\IK_Solver.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MT_ExpMap.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MT_ExpMap.h +# End Source File +# End Group +# Begin Group "extern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\extern\IK_solver.h +# End Source File +# End Group +# End Target +# End Project diff --git a/intern/iksolver/make/msvc_6_0/iksolver.dsw b/intern/iksolver/make/msvc_6_0/iksolver.dsw new file mode 100644 index 00000000000..90a123d9ce8 --- /dev/null +++ b/intern/iksolver/make/msvc_6_0/iksolver.dsw @@ -0,0 +1,35 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "iksolver"=.\iksolver.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + + + + + + + diff --git a/intern/iksolver/make/msvc_7_0/iksolver.sln b/intern/iksolver/make/msvc_7_0/iksolver.sln new file mode 100644 index 00000000000..e06e5163993 --- /dev/null +++ b/intern/iksolver/make/msvc_7_0/iksolver.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iksolver", "iksolver.vcproj", "{EB6E6428-C3FA-4A95-91AE-F060EFD1D57C}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {EB6E6428-C3FA-4A95-91AE-F060EFD1D57C}.Debug.ActiveCfg = Debug|Win32 + {EB6E6428-C3FA-4A95-91AE-F060EFD1D57C}.Debug.Build.0 = Debug|Win32 + {EB6E6428-C3FA-4A95-91AE-F060EFD1D57C}.Release.ActiveCfg = Release|Win32 + {EB6E6428-C3FA-4A95-91AE-F060EFD1D57C}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/intern/iksolver/make/msvc_7_0/iksolver.vcproj b/intern/iksolver/make/msvc_7_0/iksolver.vcproj new file mode 100644 index 00000000000..008a29774dc --- /dev/null +++ b/intern/iksolver/make/msvc_7_0/iksolver.vcproj @@ -0,0 +1,370 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/iksolver/test/Makefile b/intern/iksolver/test/Makefile new file mode 100644 index 00000000000..c472c514bad --- /dev/null +++ b/intern/iksolver/test/Makefile @@ -0,0 +1,71 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# iksolver test makefile. +# + +LIBNAME = iksolver +SOURCEDIR = intern/$(LIBNAME)/test +DIR = $(OCGDIR)/$(SOURCEDIR) + +include nan_compile.mk + +DIRS = ik_glut_test + +include nan_subdirs.mk + +include nan_link.mk + +LIBS = $(OCGDIR)/intern/$(LIBNAME)/test/ik_glut_test/intern/$(DEBUG_DIR)libintern.a +LIBS += $(OCGDIR)/intern/$(LIBNAME)/test/ik_glut_test/common/$(DEBUG_DIR)libcommon.a +LIBS += $(OCGDIR)/intern/$(LIBNAME)/$(DEBUG_DIR)libiksolver.a + +SLIBS += $(NAN_MOTO)/lib/$(DEBUG_DIR)libmoto.a + +ifeq ($(OS),$(findstring $(OS), "beos darwin linux freebsd openbsd")) + LLIBS = -L/usr/X11R6/lib -lglut -pthread +endif + +ifeq ($(OS),$(findstring $(OS), "solaris")) + LLIBS = -L/usr/openwin/lib -lglut -lX11 -lGL -lGLU -lXmu +endif + +all debug:: $(LIBS) $(DIR)/$(DEBUG_DIR)iksolvertest + +$(DIR)/$(DEBUG_DIR)iksolvertest: + @echo "****> linking $@ in $(DIR)" + $(CCC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)iksolvertest $(LIBS) $(SLIBS) $(LLIBS) $(DADD) + +clean:: + $(RM) $(DIR)/iksolvertest $(DIR)/debug/iksolvertest + +test:: all + $(DIR)/iksolvertest + diff --git a/intern/iksolver/test/ik_glut_test/Makefile b/intern/iksolver/test/ik_glut_test/Makefile new file mode 100644 index 00000000000..4b47af16599 --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/Makefile @@ -0,0 +1,42 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# iksolver subdir bouncer. Pure waste. +# + +include nan_definitions.mk + +LIBNAME = ik_glut_test +SOURCEDIR = intern/iksolver/test/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = common intern + +include nan_subdirs.mk + diff --git a/intern/iksolver/test/ik_glut_test/common/GlutDrawer.cpp b/intern/iksolver/test/ik_glut_test/common/GlutDrawer.cpp new file mode 100644 index 00000000000..6161addc170 --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/common/GlutDrawer.cpp @@ -0,0 +1,99 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GlutDrawer.h" + +#include "MT_assert.h" + +MEM_SmartPtr GlutDrawManager::m_s_instance = MEM_SmartPtr(); + + GlutDrawManager * +GlutDrawManager:: +Instance( +){ + if (m_s_instance == NULL) { + m_s_instance = new GlutDrawManager(); + } + + return m_s_instance; +} + + +// this is the function you should pass to glut + + void +GlutDrawManager:: +Draw( +){ + GlutDrawManager *manager = GlutDrawManager::Instance(); + + if (manager->m_drawer != NULL) { + manager->m_drawer->Draw(); + } +} + + void +GlutDrawManager:: +InstallDrawer( + GlutDrawer * drawer +){ + + MT_assert(m_drawer == NULL); + m_drawer = drawer; +} + + void +GlutDrawManager:: +ReleaseDrawer( +){ + m_drawer = NULL; +} + + +GlutDrawManager:: +~GlutDrawManager( +){ + + delete(m_drawer); +} + + + + + + + + + diff --git a/intern/iksolver/test/ik_glut_test/common/GlutDrawer.h b/intern/iksolver/test/ik_glut_test/common/GlutDrawer.h new file mode 100644 index 00000000000..706ccb92dec --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/common/GlutDrawer.h @@ -0,0 +1,99 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_GlutDrawer +#define NAN_INCLUDED_GlutDrawer + +#include "MEM_NonCopyable.h" +#include "MEM_SmartPtr.h" + +// So pissed off with Glut callback stuff +// that is impossible to call objects unless they are global + +// inherit from GlutDrawer and installl the drawer in the singleton +// class GlutDrawManager. + +class GlutDrawer { +public : + + virtual + void + Draw( + )= 0; + + virtual + ~GlutDrawer( + ){}; +}; + +class GlutDrawManager : public MEM_NonCopyable{ + +public : + + static + GlutDrawManager * + Instance( + ); + + // this is the function you should pass to glut + + static + void + Draw( + ); + + void + InstallDrawer( + GlutDrawer * + ); + + void + ReleaseDrawer( + ); + + ~GlutDrawManager( + ); + +private : + + GlutDrawManager ( + ) : + m_drawer (0) + { + }; + + GlutDrawer * m_drawer; + + static MEM_SmartPtr m_s_instance; +}; + +#endif + diff --git a/intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.cpp b/intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.cpp new file mode 100644 index 00000000000..454e76f11bb --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.cpp @@ -0,0 +1,92 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GlutKeyboardManager.h" +#include "MT_assert.h" + +MEM_SmartPtr GlutKeyboardManager::m_s_instance = MEM_SmartPtr(); + + GlutKeyboardManager * +GlutKeyboardManager:: +Instance( +){ + if (m_s_instance == NULL) { + m_s_instance = new GlutKeyboardManager(); + } + + return m_s_instance; +} + + +// this is the function you should pass to glut + + void +GlutKeyboardManager:: +HandleKeyboard( + unsigned char key, + int x, + int y +){ + GlutKeyboardManager *manager = GlutKeyboardManager::Instance(); + + if (manager->m_handler != NULL) { + manager->m_handler->HandleKeyboard(key,x,y); + } +} + + void +GlutKeyboardManager:: +InstallHandler( + GlutKeyboardHandler * handler +){ + + MT_assert(m_handler == NULL); + m_handler = handler; +} + + void +GlutKeyboardManager:: +ReleaseHandler( +){ + m_handler = NULL; +} + + +GlutKeyboardManager:: +~GlutKeyboardManager( +){ + + delete(m_handler); +} diff --git a/intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.h b/intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.h new file mode 100644 index 00000000000..595e5e19d0e --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.h @@ -0,0 +1,105 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_GlutKeyboardManager +#define NAN_INCLUDED_GlutKeyboardManager + +#include "MEM_NonCopyable.h" +#include "MEM_SmartPtr.h" + +// So pissed off with Glut callback stuff +// that is impossible to call objects unless they are global + +// inherit from GlutKeyboardHandler and installl the drawer in the singleton +// class GlutKeyboardManager. + +class GlutKeyboardHandler : public MEM_NonCopyable { +public : + + virtual + void + HandleKeyboard( + unsigned char key, + int x, + int y + )= 0; + + virtual + ~GlutKeyboardHandler( + ){}; +}; + +class GlutKeyboardManager : public MEM_NonCopyable{ + +public : + + static + GlutKeyboardManager * + Instance( + ); + + // this is the function you should pass to glut + + static + void + HandleKeyboard( + unsigned char key, + int x, + int y + ); + + void + InstallHandler( + GlutKeyboardHandler * + ); + + void + ReleaseHandler( + ); + + ~GlutKeyboardManager( + ); + +private : + + GlutKeyboardManager ( + ) : + m_handler (0) + { + }; + + GlutKeyboardHandler * m_handler; + + static MEM_SmartPtr m_s_instance; +}; + +#endif + diff --git a/intern/iksolver/test/ik_glut_test/common/GlutMouseManager.cpp b/intern/iksolver/test/ik_glut_test/common/GlutMouseManager.cpp new file mode 100644 index 00000000000..8221cb55a00 --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/common/GlutMouseManager.cpp @@ -0,0 +1,107 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GlutMouseManager.h" +#include "MT_assert.h" + +MEM_SmartPtr GlutMouseManager::m_s_instance = MEM_SmartPtr(); + + + GlutMouseManager * +GlutMouseManager:: +Instance( +){ + if (m_s_instance == NULL) { + m_s_instance = new GlutMouseManager(); + } + + return m_s_instance; +} + +// these are the functions you should pass to GLUT + + void +GlutMouseManager:: +Mouse( + int button, + int state, + int x, + int y +){ + GlutMouseManager *manager = GlutMouseManager::Instance(); + + if (manager->m_handler != NULL) { + manager->m_handler->Mouse(button,state,x,y); + } +} + + void +GlutMouseManager:: +Motion( + int x, + int y +){ + GlutMouseManager *manager = GlutMouseManager::Instance(); + + if (manager->m_handler != NULL) { + manager->m_handler->Motion(x,y); + } +} + + void +GlutMouseManager:: +InstallHandler( + GlutMouseHandler *handler +){ + + MT_assert(m_handler == NULL); + m_handler = handler; +} + + void +GlutMouseManager:: +ReleaseHandler( +){ + m_handler = NULL; +} + +GlutMouseManager:: +~GlutMouseManager( +){ + + delete(m_handler); +} + + diff --git a/intern/iksolver/test/ik_glut_test/common/GlutMouseManager.h b/intern/iksolver/test/ik_glut_test/common/GlutMouseManager.h new file mode 100644 index 00000000000..9675bd3ca1c --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/common/GlutMouseManager.h @@ -0,0 +1,115 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_GlutMouseManager_h +#define NAN_INCLUDED_GlutMouseManager_h + +#include "MEM_NonCopyable.h" +#include "MEM_SmartPtr.h" + +class GlutMouseHandler { +public : + + virtual + void + Mouse( + int button, + int state, + int x, + int y + ) = 0; + + virtual + void + Motion( + int x, + int y + ) = 0; + + virtual + ~GlutMouseHandler( + ){}; +}; + +class GlutMouseManager : public MEM_NonCopyable{ + +public : + + static + GlutMouseManager * + Instance( + ); + + // these are the functions you should pass to GLUT + + static + void + Mouse( + int button, + int state, + int x, + int y + ); + + static + void + Motion( + int x, + int y + ); + + void + InstallHandler( + GlutMouseHandler * + ); + + void + ReleaseHandler( + ); + + ~GlutMouseManager( + ); + +private : + + GlutMouseManager ( + ) : + m_handler (0) + { + }; + + GlutMouseHandler * m_handler; + + static MEM_SmartPtr m_s_instance; +}; + +#endif + diff --git a/intern/iksolver/test/ik_glut_test/common/Makefile b/intern/iksolver/test/ik_glut_test/common/Makefile new file mode 100644 index 00000000000..07ad1837a7d --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/common/Makefile @@ -0,0 +1,44 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# iksolver test intern Makefile +# + +LIBNAME = common +SOURCEDIR = intern/iksolver/test/ik_glut_test/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I$(NAN_MEMUTIL)/include + diff --git a/intern/iksolver/test/ik_glut_test/intern/ChainDrawer.h b/intern/iksolver/test/ik_glut_test/intern/ChainDrawer.h new file mode 100644 index 00000000000..6312d9c23f9 --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/intern/ChainDrawer.h @@ -0,0 +1,379 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_ChainDrawer_h +#define NAN_INCLUDED_ChainDrawer_h + +#include "../common/GlutDrawer.h" +#include "MyGlutMouseHandler.h" +#include "MyGlutKeyHandler.h" +#include "MT_Transform.h" +# include "IK_Qsolver.h" +# include "../intern/IK_QChain.h" +# include "../intern/IK_QSolver_Class.h" +#include + +class ChainDrawer : public GlutDrawer +{ +public : + static + ChainDrawer * + New( + ) { + return new ChainDrawer(); + } + + void + SetMouseHandler( + MyGlutMouseHandler *mouse_handler + ) { + m_mouse_handler = mouse_handler; + } + + void + SetKeyHandler ( + MyGlutKeyHandler *key_handler + ) { + m_key_handler = key_handler; + } + + void + SetChain( + IK_Chain_ExternPtr *chains,int chain_num + ) { + m_chain_num = chain_num; + m_chains = chains; + } + + + // inherited from GlutDrawer + void + Draw( + ) { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glPopMatrix(); + glPushMatrix(); + glRotatef(m_mouse_handler->AngleX(), 0.0, 1.0, 0.0); + glRotatef(m_mouse_handler->AngleY(), 1.0, 0.0, 0.0); + + DrawScene(); + glutSwapBuffers(); + + } + + ~ChainDrawer( + ){ + // nothing to do + }; + +private : + + void + DrawScene( + ){ + + // draw a little cross at the position of the key handler + // coordinates + + MT_Vector3 line_x(4,0,0); + MT_Vector3 line_y(0.0,4,0); + MT_Vector3 line_z(0.0,0.0,4); + + MT_Vector3 cross_origin = m_mouse_handler->Position(); + MT_Vector3 temp; + + glDisable(GL_LIGHTING); + + + glBegin(GL_LINES); + + glColor3f (1.0f,1.0f,1.0f); + + temp = cross_origin - line_x; + glVertex3f(temp[0],temp[1],temp[2]); + temp = cross_origin + line_x; + glVertex3f(temp[0],temp[1],temp[2]); + + temp = cross_origin - line_y; + glVertex3f(temp[0],temp[1],temp[2]); + temp = cross_origin + line_y; + glVertex3f(temp[0],temp[1],temp[2]); + + temp = cross_origin - line_z; + glVertex3f(temp[0],temp[1],temp[2]); + temp = cross_origin + line_z; + glVertex3f(temp[0],temp[1],temp[2]); + + glEnd(); + glEnable(GL_LIGHTING); + + + IK_Chain_ExternPtr chain; + + int chain_num; + for (chain_num = 0; chain_num < m_chain_num; chain_num++) { + chain = m_chains[chain_num]; + + + IK_Segment_ExternPtr segs = chain->segments; + IK_Segment_ExternPtr seg_start = segs; + const IK_Segment_ExternPtr seg_end = segs + chain->num_segments; + float ogl_matrix[16]; + + glColor3f (0.0f,1.0f,0.0f); + + MT_Vector3 previous_origin(0,0,0); + + MT_Transform global_transform; + global_transform.setIdentity(); + + for (; seg_start != seg_end; ++seg_start) { + + glPushMatrix(); + + // fill ogl_matrix with zeros + + std::fill(ogl_matrix,ogl_matrix + 16,float(0)); + + // we have to do a bit of work here to compute the chain's + // bone values + + // first compute all the matrices we need + + MT_Transform translation; + translation.setIdentity(); + translation.translate(MT_Vector3(0,seg_start->length,0)); + + MT_Matrix3x3 seg_rot( + seg_start->basis_change[0],seg_start->basis_change[1],seg_start->basis_change[2], + seg_start->basis_change[3],seg_start->basis_change[4],seg_start->basis_change[5], + seg_start->basis_change[6],seg_start->basis_change[7],seg_start->basis_change[8] + ); + + seg_rot.transpose(); + + MT_Matrix3x3 seg_pre_rot( + seg_start->basis[0],seg_start->basis[1],seg_start->basis[2], + seg_start->basis[3],seg_start->basis[4],seg_start->basis[5], + seg_start->basis[6],seg_start->basis[7],seg_start->basis[8] + ); + + + MT_Transform seg_t_pre_rot( + MT_Point3( + seg_start->seg_start[0], + seg_start->seg_start[1], + seg_start->seg_start[2] + ), + seg_pre_rot + ); + // start of the bone is just the current global transform + // multiplied by the seg_start vector + + + + MT_Transform seg_t_rot(MT_Point3(0,0,0),seg_rot); + MT_Transform seg_local = seg_t_pre_rot * seg_t_rot * translation; + + MT_Vector3 bone_start = global_transform * + MT_Point3( + seg_start->seg_start[0], + seg_start->seg_start[1], + seg_start->seg_start[2] + ); + + + global_transform = global_transform * seg_local; + + global_transform.getValue(ogl_matrix); + MT_Vector3 bone_end = global_transform.getOrigin(); + + glMultMatrixf(ogl_matrix); +// glutSolidSphere(0.5,5,5); + + glPopMatrix(); + + glDisable(GL_LIGHTING); + + glBegin(GL_LINES); + + // draw lines of the principle axis of the local transform + + MT_Vector3 x_axis(1,0,0); + MT_Vector3 y_axis(0,1,0); + MT_Vector3 z_axis(0,0,1); + + x_axis = global_transform.getBasis() * x_axis * 5; + y_axis = global_transform.getBasis() * y_axis * 5; + z_axis = global_transform.getBasis() * z_axis * 5; + + + x_axis = x_axis + bone_start; + y_axis = y_axis + bone_start; + z_axis = z_axis + bone_start; + + glColor3f(1,0,0); + + glVertex3f(x_axis.x(),x_axis.y(),x_axis.z()); + glVertex3f( + bone_start.x(), + bone_start.y(), + bone_start.z() + ); + + glColor3f(0,1,0); + + glVertex3f(y_axis.x(),y_axis.y(),y_axis.z()); + glVertex3f( + bone_start.x(), + bone_start.y(), + bone_start.z() + ); + + glColor3f(0,1,1); + + glVertex3f(z_axis.x(),z_axis.y(),z_axis.z()); + glVertex3f( + bone_start.x(), + bone_start.y(), + bone_start.z() + ); + + glColor3f(0,0,1); + + glVertex3f( + bone_start.x(), + bone_start.y(), + bone_start.z() + ); + glVertex3f(bone_end[0],bone_end[1],bone_end[2]); + + glEnd(); + glEnable(GL_LIGHTING); + } +#if 0 + // draw jacobian column vectors + + // hack access to internals + + IK_Solver_Class * internals = static_cast(chain->intern); + + glDisable(GL_LIGHTING); + + glBegin(GL_LINES); + + const TNT::Matrix & jac = internals->Chain().TransposedJacobian(); + + int i = 0; + for (i=0; i < jac.num_rows(); i++) { + glColor3f(1,1,1); + + previous_origin = internals->Chain().Segments()[i/3].GlobalSegmentStart(); + + glVertex3f(previous_origin[0],previous_origin[1],previous_origin[2]); + glVertex3f(jac[i][0] + previous_origin[0],jac[i][1] + previous_origin[1],jac[i][2] + previous_origin[2]); + + + } + glEnd(); + glEnable(GL_LIGHTING); +#endif + + } + + glColor3f(1.0,1.0,1.0); + + glDisable(GL_LIGHTING); + glBegin(GL_LINES); + + MT_Scalar cube_size = 50; + glVertex3f(cube_size,cube_size,cube_size); + glVertex3f(-cube_size,cube_size,cube_size); + + glVertex3f(cube_size,-cube_size,cube_size); + glVertex3f(-cube_size,-cube_size,cube_size); + + glVertex3f(cube_size,cube_size,-cube_size); + glVertex3f(-cube_size,cube_size,-cube_size); + + glVertex3f(cube_size,-cube_size,-cube_size); + glVertex3f(-cube_size,-cube_size,-cube_size); + + + glVertex3f(-cube_size,cube_size,cube_size); + glVertex3f(-cube_size,-cube_size,cube_size); + + glVertex3f(cube_size,cube_size,-cube_size); + glVertex3f(cube_size,-cube_size,-cube_size); + + glVertex3f(cube_size,cube_size,cube_size); + glVertex3f(cube_size,-cube_size,cube_size); + + glVertex3f(-cube_size,cube_size,-cube_size); + glVertex3f(-cube_size,-cube_size,-cube_size); + + + glVertex3f(cube_size,cube_size,cube_size); + glVertex3f(cube_size,cube_size,-cube_size); + + glVertex3f(cube_size,-cube_size,cube_size); + glVertex3f(cube_size,-cube_size,-cube_size); + + glVertex3f(-cube_size,cube_size,cube_size); + glVertex3f(-cube_size,cube_size,-cube_size); + + glVertex3f(-cube_size,-cube_size,cube_size); + glVertex3f(-cube_size,-cube_size,-cube_size); + glEnd(); + glEnable(GL_LIGHTING); + + }; + + + +private : + + MyGlutMouseHandler * m_mouse_handler; + MyGlutKeyHandler *m_key_handler; + IK_Chain_ExternPtr *m_chains; + + int m_chain_num; + ChainDrawer ( + ) : m_chains (NULL), + m_mouse_handler (NULL), + m_chain_num (0) + { + }; + +}; + +#endif + diff --git a/intern/iksolver/test/ik_glut_test/intern/Makefile b/intern/iksolver/test/ik_glut_test/intern/Makefile new file mode 100644 index 00000000000..fe1f4b54182 --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/intern/Makefile @@ -0,0 +1,51 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# iksolver test intern Makefile +# + +LIBNAME = intern +SOURCEDIR = intern/iksolver/test/ik_glut_test/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I$(OPENGL_HEADERS) +CPPFLAGS += -I../../../extern +CPPFLAGS += -I../common +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I$(NAN_MEMUTIL)/include + +ifeq ($(OS),windows) + CPPFLAGS += -I$(NAN_LIBDIR)/windows/glut-3.7/include +endif + diff --git a/intern/iksolver/test/ik_glut_test/intern/MyGlutKeyHandler.h b/intern/iksolver/test/ik_glut_test/intern/MyGlutKeyHandler.h new file mode 100644 index 00000000000..e9a85fad320 --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/intern/MyGlutKeyHandler.h @@ -0,0 +1,84 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_MyGlutKeyHandler_h +#define NAN_INCLUDED_MyGlutKeyHandler_h + +#include "../common/GlutKeyboardManager.h" + +class MyGlutKeyHandler : public GlutKeyboardHandler +{ +public : + static + MyGlutKeyHandler * + New( + ) { + MEM_SmartPtr output = new MyGlutKeyHandler(); + + if (output == NULL + ) { + return NULL; + } + return output.Release(); + + } + + void + HandleKeyboard( + unsigned char key, + int x, + int y + ){ + + switch (key) { + + case 27 : + + exit(0); + } + } + + ~MyGlutKeyHandler( + ) + { + }; + +private : + + MyGlutKeyHandler( + ) + { + } + +}; + +#endif + diff --git a/intern/iksolver/test/ik_glut_test/intern/MyGlutMouseHandler.h b/intern/iksolver/test/ik_glut_test/intern/MyGlutMouseHandler.h new file mode 100644 index 00000000000..978d9693692 --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/intern/MyGlutMouseHandler.h @@ -0,0 +1,210 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_MyGlutMouseHandler_h +#define NAN_INCLUDED_MyGlutMouseHandler_h + +#include "../common/GlutMouseManager.h" +#include +#include "IK_solver.h" + +class MyGlutMouseHandler : public GlutMouseHandler +{ + +public : + + static + MyGlutMouseHandler * + New( + ) { + MEM_SmartPtr output = new MyGlutMouseHandler(); + if (output == NULL + ) { + return NULL; + } + return output.Release(); + + } + + void + SetChain( + IK_Chain_ExternPtr *chains, int num_chains + ){ + m_chains = chains; + m_num_chains = num_chains; + } + + void + Mouse( + int button, + int state, + int x, + int y + ){ + if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { + m_moving = true; + m_begin_x = x; + m_begin_y = y; + } + if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) { + m_moving = false; + } + + if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) { + m_tracking = true; + } + if (button == GLUT_RIGHT_BUTTON && state == GLUT_UP) { + m_tracking = false; + } + + if (button == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) { + m_cg_on = true; + } + if (button == GLUT_MIDDLE_BUTTON && state == GLUT_UP) { + m_cg_on = false; + } + + } + + + void + Motion( + int x, + int y + ){ + if (m_moving) { + m_angle_x = m_angle_x + (x - m_begin_x); + m_begin_x = x; + + m_angle_y = m_angle_y + (y - m_begin_y); + m_begin_y = y; + + glutPostRedisplay(); + } + if (m_tracking) { + + int w_h = glutGet((GLenum)GLUT_WINDOW_HEIGHT); + + y = w_h - y; + + double mvmatrix[16]; + double projmatrix[16]; + GLint viewport[4]; + + double px, py, pz,sz; + + /* Get the matrices needed for gluUnProject */ + glGetIntegerv(GL_VIEWPORT, viewport); + glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix); + glGetDoublev(GL_PROJECTION_MATRIX, projmatrix); + + // work out the position of the end effector in screen space + + GLdouble ex,ey,ez; + ex = m_pos.x(); + ey = m_pos.y(); + ez = m_pos.z(); + + gluProject(ex, ey, ez, mvmatrix, projmatrix, viewport, &px, &py, &sz); + gluUnProject((GLdouble) x, (GLdouble) y, sz, mvmatrix, projmatrix, viewport, &px, &py, &pz); + + m_pos = MT_Vector3(px,py,pz); + + } + if (m_tracking || m_cg_on) { + float temp[3]; + m_pos.getValue(temp); + + IK_SolveChain(m_chains[0],temp,0.01,200,0.1,m_chains[1]->segments); + IK_LoadChain(m_chains[0],m_chains[0]->segments,m_chains[0]->num_segments); + + glutPostRedisplay(); + } + + + } + + const + float + AngleX( + ) const { + return m_angle_x; + } + + const + float + AngleY( + ) const { + return m_angle_y; + } + + const + MT_Vector3 + Position( + ) const { + return m_pos; + } + + +private : + + MyGlutMouseHandler ( + ) : + m_angle_x(0), + m_angle_y(0), + m_begin_x(0), + m_begin_y(0), + m_moving (false), + m_tracking (false), + m_pos(0,0,0), + m_cg_on (false), + m_chains(NULL), + m_num_chains(0) + { + }; + + float m_angle_x; + float m_angle_y; + float m_begin_x; + float m_begin_y; + + bool m_moving; + bool m_tracking; + bool m_cg_on; + MT_Vector3 m_pos; + + IK_Chain_ExternPtr *m_chains; + int m_num_chains; + +}; + +#endif + diff --git a/intern/iksolver/test/ik_glut_test/intern/main.cpp b/intern/iksolver/test/ik_glut_test/intern/main.cpp new file mode 100644 index 00000000000..7f1cce80a7e --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/intern/main.cpp @@ -0,0 +1,364 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_SmartPtr.h" + +#ifdef USE_QUATERNIONS +#include "IK_Qsolver.h" +#else +#include "IK_solver.h" +#endif + +#include +#include "MT_Vector3.h" +#include "MT_Quaternion.h" +#include "MT_Matrix3x3.h" +#include "MyGlutMouseHandler.h" +#include "MyGlutKeyHandler.h" +#include "ChainDrawer.h" + +void +init(MT_Vector3 min,MT_Vector3 max) +{ + + GLfloat light_diffuse0[] = {1.0, 0.0, 0.0, 1.0}; /* Red diffuse light. */ + GLfloat light_position0[] = {1.0, 1.0, 1.0, 0.0}; /* Infinite light location. */ + + GLfloat light_diffuse1[] = {1.0, 1.0, 1.0, 1.0}; /* Red diffuse light. */ + GLfloat light_position1[] = {1.0, 0, 0, 0.0}; /* Infinite light location. */ + + /* Enable a single OpenGL light. */ + glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse0); + glLightfv(GL_LIGHT0, GL_POSITION, light_position0); + + glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse1); + glLightfv(GL_LIGHT1, GL_POSITION, light_position1); + + glEnable(GL_LIGHT0); + glEnable(GL_LIGHT1); + glEnable(GL_LIGHTING); + + /* Use depth buffering for hidden surface elimination. */ + glEnable(GL_DEPTH_TEST); + + /* Setup the view of the cube. */ + glMatrixMode(GL_PROJECTION); + + // center of the box + 3* depth of box + + MT_Vector3 center = (min + max) * 0.5; + MT_Vector3 diag = max - min; + + float depth = diag.length(); + float distance = 2; + + gluPerspective( + /* field of view in degree */ 40.0, + /* aspect ratio */ 1.0, + /* Z near */ 1.0, + /* Z far */ distance * depth * 2 + ); + glMatrixMode(GL_MODELVIEW); + + + gluLookAt( + center.x(), center.y(), center.z() + distance*depth, /* eye is at (0,0,5) */ + center.x(), center.y(), center.z(), /* center is at (0,0,0) */ + 0.0, 1.0, 0.); /* up is in positive Y direction */ + + glPushMatrix(); + + +} +int +main(int argc, char **argv) +{ + + + const int seg_num = 5; + const MT_Scalar seg_length = 15; + + const float seg_startA[3] = {0,0,0}; + const float seg_startB[3] = {0,-20,0}; + + // create some segments to solve with + + // First chain + ////////////// + + + IK_Segment_ExternPtr const segmentsA = new IK_Segment_Extern[seg_num]; + IK_Segment_ExternPtr const segmentsB = new IK_Segment_Extern[seg_num]; + + IK_Segment_ExternPtr seg_it = segmentsA; + IK_Segment_ExternPtr seg_itB = segmentsB; + + + { + +// MT_Quaternion qmat(MT_Vector3(0,0,1),-3.141/2); + MT_Quaternion qmat(MT_Vector3(0,0,1),0); + MT_Matrix3x3 mat(qmat); + + seg_it->seg_start[0] = seg_startA[0]; + seg_it->seg_start[1] = seg_startA[1]; + seg_it->seg_start[2] = seg_startA[2]; + + float temp[12]; + mat.getValue(temp); + + seg_it->basis[0] = temp[0]; + seg_it->basis[1] = temp[1]; + seg_it->basis[2] = temp[2]; + + seg_it->basis[3] = temp[4]; + seg_it->basis[4] = temp[5]; + seg_it->basis[5] = temp[6]; + + seg_it->basis[6] = temp[8]; + seg_it->basis[7] = temp[9]; + seg_it->basis[8] = temp[10]; + + seg_it->length = seg_length; + + MT_Quaternion q; + q.setEuler(0,0,0); + + + MT_Matrix3x3 qrot(q); + + seg_it->basis_change[0] = 1; + seg_it->basis_change[1] = 0; + seg_it->basis_change[2] = 0; + seg_it->basis_change[3] = 0; + seg_it->basis_change[4] = 1; + seg_it->basis_change[5] = 0; + seg_it->basis_change[6] = 0; + seg_it->basis_change[7] = 0; + seg_it->basis_change[8] = 1; + + + seg_it ++; + + seg_itB->seg_start[0] = seg_startA[0]; + seg_itB->seg_start[1] = seg_startA[1]; + seg_itB->seg_start[2] = seg_startA[2]; + + seg_itB->basis[0] = temp[0]; + seg_itB->basis[1] = temp[1]; + seg_itB->basis[2] = temp[2]; + + seg_itB->basis[3] = temp[4]; + seg_itB->basis[4] = temp[5]; + seg_itB->basis[5] = temp[6]; + + seg_itB->basis[6] = temp[8]; + seg_itB->basis[7] = temp[9]; + seg_itB->basis[8] = temp[10]; + + seg_itB->length = seg_length; + + seg_itB->basis_change[0] = 1; + seg_itB->basis_change[1] = 0; + seg_itB->basis_change[2] = 0; + seg_itB->basis_change[3] = 0; + seg_itB->basis_change[4] = 1; + seg_itB->basis_change[5] = 0; + seg_itB->basis_change[6] = 0; + seg_itB->basis_change[7] = 0; + seg_itB->basis_change[8] = 1; + + + seg_itB ++; + + + } + + + int i; + for (i=1; i < seg_num; ++i, ++seg_it,++seg_itB) { + + MT_Quaternion qmat(MT_Vector3(0,0,1),0.3); + MT_Matrix3x3 mat(qmat); + + seg_it->seg_start[0] = 0; + seg_it->seg_start[1] = 0; + seg_it->seg_start[2] = 0; + + float temp[12]; + mat.getValue(temp); + + seg_it->basis[0] = temp[0]; + seg_it->basis[1] = temp[1]; + seg_it->basis[2] = temp[2]; + + seg_it->basis[3] = temp[4]; + seg_it->basis[4] = temp[5]; + seg_it->basis[5] = temp[6]; + + seg_it->basis[6] = temp[8]; + seg_it->basis[7] = temp[9]; + seg_it->basis[8] = temp[10]; + + seg_it->length = seg_length; + + MT_Quaternion q; + q.setEuler(0,0,0); + + + MT_Matrix3x3 qrot(q); + + seg_it->basis_change[0] = 1; + seg_it->basis_change[1] = 0; + seg_it->basis_change[2] = 0; + seg_it->basis_change[3] = 0; + seg_it->basis_change[4] = 1; + seg_it->basis_change[5] = 0; + seg_it->basis_change[6] = 0; + seg_it->basis_change[7] = 0; + seg_it->basis_change[8] = 1; + + + /////////////////////////////// + + seg_itB->seg_start[0] = 0; + seg_itB->seg_start[1] = 0; + seg_itB->seg_start[2] = 0; + + seg_itB->basis[0] = temp[0]; + seg_itB->basis[1] = temp[1]; + seg_itB->basis[2] = temp[2]; + + seg_itB->basis[3] = temp[4]; + seg_itB->basis[4] = temp[5]; + seg_itB->basis[5] = temp[6]; + + seg_itB->basis[6] = temp[8]; + seg_itB->basis[7] = temp[9]; + seg_itB->basis[8] = temp[10]; + + seg_itB->length = seg_length; + + seg_itB->basis_change[0] = 1; + seg_itB->basis_change[1] = 0; + seg_itB->basis_change[2] = 0; + seg_itB->basis_change[3] = 0; + seg_itB->basis_change[4] = 1; + seg_itB->basis_change[5] = 0; + seg_itB->basis_change[6] = 0; + seg_itB->basis_change[7] = 0; + seg_itB->basis_change[8] = 1; + + + + } + + // create the chains + + const int num_chains = 2; + + IK_Chain_ExternPtr chains[num_chains]; + + chains[0] = IK_CreateChain(); + chains[1] = IK_CreateChain(); + + // load segments into chain + + IK_LoadChain(chains[0],segmentsA,seg_num); + IK_LoadChain(chains[1],segmentsB,seg_num); + + // make and install a mouse handler + + MEM_SmartPtr mouse_handler (MyGlutMouseHandler::New()); + GlutMouseManager::Instance()->InstallHandler(mouse_handler); + + mouse_handler->SetChain(chains,num_chains); + + // make and install a keyhandler + MEM_SmartPtr key_handler (MyGlutKeyHandler::New()); + GlutKeyboardManager::Instance()->InstallHandler(key_handler); + + // instantiate the drawing class + + MEM_SmartPtr drawer (ChainDrawer::New()); + GlutDrawManager::Instance()->InstallDrawer(drawer); + + drawer->SetMouseHandler(mouse_handler); + drawer->SetChain(chains,num_chains); + drawer->SetKeyHandler(key_handler); + + glutInit(&argc, argv); + glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); + glutCreateWindow("ik"); + glutDisplayFunc(GlutDrawManager::Draw); + glutMouseFunc(GlutMouseManager::Mouse); + glutMotionFunc(GlutMouseManager::Motion); + glutKeyboardFunc(GlutKeyboardManager::HandleKeyboard); + + init(MT_Vector3(-50,-50,-50),MT_Vector3(50,50,50)); + glutMainLoop(); + return 0; /* ANSI C requires main to return int. */ +} diff --git a/intern/iksolver/test/ik_glut_test/make/msvc_6_0/ik_glut_test.dsp b/intern/iksolver/test/ik_glut_test/make/msvc_6_0/ik_glut_test.dsp new file mode 100644 index 00000000000..8688b2fcc2c --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/make/msvc_6_0/ik_glut_test.dsp @@ -0,0 +1,130 @@ +# Microsoft Developer Studio Project File - Name="ik_glut_test" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=ik_glut_test - 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 "ik_glut_test.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 "ik_glut_test.mak" CFG="ik_glut_test - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ik_glut_test - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "ik_glut_test - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ik_glut_test - 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 Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\extern" /I "..\..\..\..\..\..\lib\windows\glut-3.7\include" /I "..\..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\..\..\lib\windows\memutil\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 iksolver_rmtd.lib libmoto.a /nologo /subsystem:console /machine:I386 /libpath:"..\..\..\..\lib\windows\release" /libpath:"..\..\..\..\..\..\lib\windows\glut-3.7\lib" /libpath:"..\..\..\..\..\..\lib\windows\moto\lib" + +!ELSEIF "$(CFG)" == "ik_glut_test - 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 Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\..\extern" /I "..\..\..\..\..\..\lib\windows\glut-3.7\include" /I "..\..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\..\..\lib\windows\memutil\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 iksolver_dmtd.lib libmoto.a /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"LIBCMTD.lib" /pdbtype:sept /libpath:"..\..\..\..\lib\windows\debug" /libpath:"..\..\..\..\..\..\lib\windows\glut-3.7\lib" /libpath:"..\..\..\..\..\..\lib\windows\moto\lib\debug" + +!ENDIF + +# Begin Target + +# Name "ik_glut_test - Win32 Release" +# Name "ik_glut_test - Win32 Debug" +# Begin Group "common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\common\GlutDrawer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\common\GlutDrawer.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\GlutKeyboardManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\common\GlutKeyboardManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\GlutMouseManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\common\GlutMouseManager.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\intern\ChainDrawer.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\main.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MyGlutKeyHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MyGlutMouseHandler.h +# End Source File +# End Target +# End Project diff --git a/intern/iksolver/test/ik_glut_test/make/msvc_6_0/ik_glut_test.dsw b/intern/iksolver/test/ik_glut_test/make/msvc_6_0/ik_glut_test.dsw new file mode 100644 index 00000000000..09b7094137b --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/make/msvc_6_0/ik_glut_test.dsw @@ -0,0 +1,49 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "ik_glut_test"=.\ik_glut_test.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name iksolver + End Project Dependency +}}} + +############################################################################### + +Project: "iksolver"=..\..\..\..\make\msvc_6_0\iksolver.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + + + + + + diff --git a/intern/make/msvc_6_0/build_install_all.dsp b/intern/make/msvc_6_0/build_install_all.dsp new file mode 100644 index 00000000000..110c28ddeac --- /dev/null +++ b/intern/make/msvc_6_0/build_install_all.dsp @@ -0,0 +1,68 @@ +# Microsoft Developer Studio Project File - Name="Build_install_all" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Generic Project" 0x010a + +CFG=Build_install_all - 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 "Build_install_all.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 "Build_install_all.mak" CFG="Build_install_all - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Build_install_all - Win32 Release" (based on "Win32 (x86) Generic Project") +!MESSAGE "Build_install_all - Win32 Debug" (based on "Win32 (x86) Generic Project") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +MTL=midl.exe + +!IF "$(CFG)" == "Build_install_all - 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 "" + +!ELSEIF "$(CFG)" == "Build_install_all - 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 "" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Desc=Python freeze +PostBuild_Cmds=ECHO Freezing Blender Python code ..\..\python\freeze\freeze.bat +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "Build_install_all - Win32 Release" +# Name "Build_install_all - Win32 Debug" +# End Target +# End Project diff --git a/intern/make/msvc_6_0/intern.dsw b/intern/make/msvc_6_0/intern.dsw new file mode 100644 index 00000000000..2818636c1c6 --- /dev/null +++ b/intern/make/msvc_6_0/intern.dsw @@ -0,0 +1,302 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "Build_install_all"=.\build_install_all.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name OpenNL + End Project Dependency + Begin Project Dependency + Project_Dep_Name bmfont + End Project Dependency + Begin Project Dependency + Project_Dep_Name bsplib + End Project Dependency + Begin Project Dependency + Project_Dep_Name container + End Project Dependency + Begin Project Dependency + Project_Dep_Name decimation + End Project Dependency + Begin Project Dependency + Project_Dep_Name DummySoundSystem + End Project Dependency + Begin Project Dependency + Project_Dep_Name ghost + End Project Dependency + Begin Project Dependency + Project_Dep_Name guardedalloc + End Project Dependency + Begin Project Dependency + Project_Dep_Name iksolver + End Project Dependency + Begin Project Dependency + Project_Dep_Name memutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name MoTo + End Project Dependency + Begin Project Dependency + Project_Dep_Name SoundSystem + End Project Dependency + Begin Project Dependency + Project_Dep_Name string + End Project Dependency + Begin Project Dependency + Project_Dep_Name elbeem + End Project Dependency + Begin Project Dependency + Project_Dep_Name boolop + End Project Dependency + Begin Project Dependency + Project_Dep_Name OpenALSoundSystem + End Project Dependency +}}} + +############################################################################### + +Project: "DummySoundSystem"=..\..\SoundSystem\make\msvc_6_0\dummy\DummySoundSystem.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "MoTo"=..\..\moto\make\msvc_6_0\MoTo.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "OpenALSoundSystem"=..\..\SoundSystem\make\msvc_6_0\openal\OpenALSoundSystem.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "OpenNL"=..\..\opennl\make\msvc_6_0\OpenNL.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "SoundSystem"=..\..\SoundSystem\make\msvc_6_0\SoundSystem.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "bmfont"=..\..\bmfont\make\msvc_6_0\bmfont.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "boolop"=..\..\boolop\make\msvc_6_0\boolop.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "bsplib"=..\..\bsp\make\msvc6_0\bsplib.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name container + End Project Dependency + Begin Project Dependency + Project_Dep_Name memutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name MoTo + End Project Dependency +}}} + +############################################################################### + +Project: "container"=..\..\container\make\msvc_6_0\container.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "csg"=..\..\csg\make\msvc60\csg.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "decimation"=..\..\decimation\make\msvc_6_0\decimation.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name memutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name MoTo + End Project Dependency + Begin Project Dependency + Project_Dep_Name container + End Project Dependency +}}} + +############################################################################### + +Project: "elbeem"=..\..\elbeem\make\msvc_6_0\elbeem.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "ghost"=..\..\ghost\make\msvc\ghost.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name string + End Project Dependency +}}} + +############################################################################### + +Project: "guardedalloc"=..\..\guardedalloc\make\msvc_6_0\guardedalloc.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "iksolver"=..\..\iksolver\make\msvc_6_0\iksolver.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "memutil"=..\..\memutil\make\msvc_60\memutil.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "string"=..\..\string\make\msvc_6_0\string.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/make/msvc_7_0/build_install_all.vcproj b/intern/make/msvc_7_0/build_install_all.vcproj new file mode 100644 index 00000000000..3d80bd48b8b --- /dev/null +++ b/intern/make/msvc_7_0/build_install_all.vcproj @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/make/msvc_7_0/intern.sln b/intern/make/msvc_7_0/intern.sln new file mode 100644 index 00000000000..5fdb4ca95d0 --- /dev/null +++ b/intern/make/msvc_7_0/intern.sln @@ -0,0 +1,252 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "build_install_all", "build_install_all.vcproj", "{02110D03-59DB-4571-8787-72B3C03B2F2D}" + ProjectSection(ProjectDependencies) = postProject + {A90C4918-4B21-4277-93BD-AF65F30951D9} = {A90C4918-4B21-4277-93BD-AF65F30951D9} + {98330220-47A6-42E0-9DE4-AD0FF5D204D6} = {98330220-47A6-42E0-9DE4-AD0FF5D204D6} + {C66F722C-46BE-40C9-ABAE-2EAC7A697EB8} = {C66F722C-46BE-40C9-ABAE-2EAC7A697EB8} + {FAF46346-65CC-4DB2-85C4-B99826F79D0C} = {FAF46346-65CC-4DB2-85C4-B99826F79D0C} + {B093415D-C0F6-4E76-8F5A-6BC1917BCE9E} = {B093415D-C0F6-4E76-8F5A-6BC1917BCE9E} + {E784098D-3ED8-433A-9353-9679415DDDC5} = {E784098D-3ED8-433A-9353-9679415DDDC5} + {76D90B92-ECC7-409C-9F98-A8814B90F3C0} = {76D90B92-ECC7-409C-9F98-A8814B90F3C0} + {542A9FA1-B7FF-441C-AE15-054DB31D3488} = {542A9FA1-B7FF-441C-AE15-054DB31D3488} + {213356A9-3A1F-41DA-9819-1297BCD17DEE} = {213356A9-3A1F-41DA-9819-1297BCD17DEE} + {51A348C1-8684-4D67-B980-97B1FC74159B} = {51A348C1-8684-4D67-B980-97B1FC74159B} + {8B8D4FC3-3234-4E54-8376-5AB83D00D164} = {8B8D4FC3-3234-4E54-8376-5AB83D00D164} + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74} = {4B6AFCC5-968C-424A-8F20-76E41B3BEF74} + {EB75F4D6-2970-4A3A-8D99-2BAD7201C0E9} = {EB75F4D6-2970-4A3A-8D99-2BAD7201C0E9} + {E86B7BDE-C33C-4E55-9433-E74C141D7538} = {E86B7BDE-C33C-4E55-9433-E74C141D7538} + {B789C2F3-279E-4A85-8F0A-7F7AC068E598} = {B789C2F3-279E-4A85-8F0A-7F7AC068E598} + {6B3229F4-2A37-47EE-8B89-9AA046B35193} = {6B3229F4-2A37-47EE-8B89-9AA046B35193} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MoTo", "..\..\moto\make\msvc_7_0\MoTo.vcproj", "{4B6AFCC5-968C-424A-8F20-76E41B3BEF74}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bmfont", "..\..\bmfont\make\msvc_7_0\bmfont.vcproj", "{E784098D-3ED8-433A-9353-9679415DDDC5}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bsplib", "..\..\bsp\make\msvc_7_0\bsplib.vcproj", "{B093415D-C0F6-4E76-8F5A-6BC1917BCE9E}" + ProjectSection(ProjectDependencies) = postProject + {51A348C1-8684-4D67-B980-97B1FC74159B} = {51A348C1-8684-4D67-B980-97B1FC74159B} + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74} = {4B6AFCC5-968C-424A-8F20-76E41B3BEF74} + {E86B7BDE-C33C-4E55-9433-E74C141D7538} = {E86B7BDE-C33C-4E55-9433-E74C141D7538} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "container", "..\..\container\make\msvc_7_0\container.vcproj", "{51A348C1-8684-4D67-B980-97B1FC74159B}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "decimation", "..\..\decimation\make\msvc_7_0\decimation.vcproj", "{C66F722C-46BE-40C9-ABAE-2EAC7A697EB8}" + ProjectSection(ProjectDependencies) = postProject + {51A348C1-8684-4D67-B980-97B1FC74159B} = {51A348C1-8684-4D67-B980-97B1FC74159B} + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74} = {4B6AFCC5-968C-424A-8F20-76E41B3BEF74} + {E86B7BDE-C33C-4E55-9433-E74C141D7538} = {E86B7BDE-C33C-4E55-9433-E74C141D7538} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ghost", "..\..\ghost\make\msvc_7_0\ghost.vcproj", "{76D90B92-ECC7-409C-9F98-A8814B90F3C0}" + ProjectSection(ProjectDependencies) = postProject + {B789C2F3-279E-4A85-8F0A-7F7AC068E598} = {B789C2F3-279E-4A85-8F0A-7F7AC068E598} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "guardedalloc", "..\..\guardedalloc\make\msvc_7_0\guardedalloc.vcproj", "{6B3229F4-2A37-47EE-8B89-9AA046B35193}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iksolver", "..\..\iksolver\make\msvc_7_0\iksolver.vcproj", "{542A9FA1-B7FF-441C-AE15-054DB31D3488}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "memutil", "..\..\memutil\make\msvc_7_0\memutil.vcproj", "{E86B7BDE-C33C-4E55-9433-E74C141D7538}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "string", "..\..\string\make\msvc_7_0\string.vcproj", "{B789C2F3-279E-4A85-8F0A-7F7AC068E598}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SoundSystem", "..\..\SoundSystem\make\msvc_7_0\SoundSystem.vcproj", "{98330220-47A6-42E0-9DE4-AD0FF5D204D6}" + ProjectSection(ProjectDependencies) = postProject + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74} = {4B6AFCC5-968C-424A-8F20-76E41B3BEF74} + {B789C2F3-279E-4A85-8F0A-7F7AC068E598} = {B789C2F3-279E-4A85-8F0A-7F7AC068E598} + {6B3229F4-2A37-47EE-8B89-9AA046B35193} = {6B3229F4-2A37-47EE-8B89-9AA046B35193} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenALSoundSystem", "..\..\SoundSystem\make\msvc_7_0\openal\OpenALSoundSystem.vcproj", "{213356A9-3A1F-41DA-9819-1297BCD17DEE}" + ProjectSection(ProjectDependencies) = postProject + {98330220-47A6-42E0-9DE4-AD0FF5D204D6} = {98330220-47A6-42E0-9DE4-AD0FF5D204D6} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DummySoundSystem", "..\..\SoundSystem\make\msvc_7_0\dummy\DummySoundSystem.vcproj", "{FAF46346-65CC-4DB2-85C4-B99826F79D0C}" + ProjectSection(ProjectDependencies) = postProject + {98330220-47A6-42E0-9DE4-AD0FF5D204D6} = {98330220-47A6-42E0-9DE4-AD0FF5D204D6} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opennl", "..\..\opennl\make\msvc_7_0\opennl.vcproj", "{8B8D4FC3-3234-4E54-8376-5AB83D00D164}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "elbeem", "..\..\elbeem\make\msvc_7_0\elbeem.vcproj", "{A90C4918-4B21-4277-93BD-AF65F30951D9}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "boolop", "..\..\boolop\make\msvc_7_0\boolop.vcproj", "{EB75F4D6-2970-4A3A-8D99-2BAD7201C0E9}" + ProjectSection(ProjectDependencies) = postProject + {51A348C1-8684-4D67-B980-97B1FC74159B} = {51A348C1-8684-4D67-B980-97B1FC74159B} + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74} = {4B6AFCC5-968C-424A-8F20-76E41B3BEF74} + {E86B7BDE-C33C-4E55-9433-E74C141D7538} = {E86B7BDE-C33C-4E55-9433-E74C141D7538} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + 3DPlugin Debug = 3DPlugin Debug + 3DPlugin Release = 3DPlugin Release + Blender Debug = Blender Debug + Blender Release = Blender Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {02110D03-59DB-4571-8787-72B3C03B2F2D}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {02110D03-59DB-4571-8787-72B3C03B2F2D}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {02110D03-59DB-4571-8787-72B3C03B2F2D}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {02110D03-59DB-4571-8787-72B3C03B2F2D}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {02110D03-59DB-4571-8787-72B3C03B2F2D}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {02110D03-59DB-4571-8787-72B3C03B2F2D}.Blender Debug.Build.0 = Blender Debug|Win32 + {02110D03-59DB-4571-8787-72B3C03B2F2D}.Blender Release.ActiveCfg = Blender Release|Win32 + {02110D03-59DB-4571-8787-72B3C03B2F2D}.Blender Release.Build.0 = Blender Release|Win32 + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74}.Blender Debug.Build.0 = Blender Debug|Win32 + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74}.Blender Release.ActiveCfg = Blender Release|Win32 + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74}.Blender Release.Build.0 = Blender Release|Win32 + {E784098D-3ED8-433A-9353-9679415DDDC5}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {E784098D-3ED8-433A-9353-9679415DDDC5}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {E784098D-3ED8-433A-9353-9679415DDDC5}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {E784098D-3ED8-433A-9353-9679415DDDC5}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {E784098D-3ED8-433A-9353-9679415DDDC5}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {E784098D-3ED8-433A-9353-9679415DDDC5}.Blender Debug.Build.0 = Blender Debug|Win32 + {E784098D-3ED8-433A-9353-9679415DDDC5}.Blender Release.ActiveCfg = Blender Release|Win32 + {E784098D-3ED8-433A-9353-9679415DDDC5}.Blender Release.Build.0 = Blender Release|Win32 + {B093415D-C0F6-4E76-8F5A-6BC1917BCE9E}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {B093415D-C0F6-4E76-8F5A-6BC1917BCE9E}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {B093415D-C0F6-4E76-8F5A-6BC1917BCE9E}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {B093415D-C0F6-4E76-8F5A-6BC1917BCE9E}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {B093415D-C0F6-4E76-8F5A-6BC1917BCE9E}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {B093415D-C0F6-4E76-8F5A-6BC1917BCE9E}.Blender Debug.Build.0 = Blender Debug|Win32 + {B093415D-C0F6-4E76-8F5A-6BC1917BCE9E}.Blender Release.ActiveCfg = Blender Release|Win32 + {B093415D-C0F6-4E76-8F5A-6BC1917BCE9E}.Blender Release.Build.0 = Blender Release|Win32 + {51A348C1-8684-4D67-B980-97B1FC74159B}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {51A348C1-8684-4D67-B980-97B1FC74159B}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {51A348C1-8684-4D67-B980-97B1FC74159B}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {51A348C1-8684-4D67-B980-97B1FC74159B}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {51A348C1-8684-4D67-B980-97B1FC74159B}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {51A348C1-8684-4D67-B980-97B1FC74159B}.Blender Debug.Build.0 = Blender Debug|Win32 + {51A348C1-8684-4D67-B980-97B1FC74159B}.Blender Release.ActiveCfg = Blender Release|Win32 + {51A348C1-8684-4D67-B980-97B1FC74159B}.Blender Release.Build.0 = Blender Release|Win32 + {C66F722C-46BE-40C9-ABAE-2EAC7A697EB8}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {C66F722C-46BE-40C9-ABAE-2EAC7A697EB8}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {C66F722C-46BE-40C9-ABAE-2EAC7A697EB8}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {C66F722C-46BE-40C9-ABAE-2EAC7A697EB8}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {C66F722C-46BE-40C9-ABAE-2EAC7A697EB8}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {C66F722C-46BE-40C9-ABAE-2EAC7A697EB8}.Blender Debug.Build.0 = Blender Debug|Win32 + {C66F722C-46BE-40C9-ABAE-2EAC7A697EB8}.Blender Release.ActiveCfg = Blender Release|Win32 + {C66F722C-46BE-40C9-ABAE-2EAC7A697EB8}.Blender Release.Build.0 = Blender Release|Win32 + {76D90B92-ECC7-409C-9F98-A8814B90F3C0}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {76D90B92-ECC7-409C-9F98-A8814B90F3C0}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {76D90B92-ECC7-409C-9F98-A8814B90F3C0}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {76D90B92-ECC7-409C-9F98-A8814B90F3C0}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {76D90B92-ECC7-409C-9F98-A8814B90F3C0}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {76D90B92-ECC7-409C-9F98-A8814B90F3C0}.Blender Debug.Build.0 = Blender Debug|Win32 + {76D90B92-ECC7-409C-9F98-A8814B90F3C0}.Blender Release.ActiveCfg = Blender Release|Win32 + {76D90B92-ECC7-409C-9F98-A8814B90F3C0}.Blender Release.Build.0 = Blender Release|Win32 + {6B3229F4-2A37-47EE-8B89-9AA046B35193}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {6B3229F4-2A37-47EE-8B89-9AA046B35193}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {6B3229F4-2A37-47EE-8B89-9AA046B35193}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {6B3229F4-2A37-47EE-8B89-9AA046B35193}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {6B3229F4-2A37-47EE-8B89-9AA046B35193}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {6B3229F4-2A37-47EE-8B89-9AA046B35193}.Blender Debug.Build.0 = Blender Debug|Win32 + {6B3229F4-2A37-47EE-8B89-9AA046B35193}.Blender Release.ActiveCfg = Blender Release|Win32 + {6B3229F4-2A37-47EE-8B89-9AA046B35193}.Blender Release.Build.0 = Blender Release|Win32 + {542A9FA1-B7FF-441C-AE15-054DB31D3488}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {542A9FA1-B7FF-441C-AE15-054DB31D3488}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {542A9FA1-B7FF-441C-AE15-054DB31D3488}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {542A9FA1-B7FF-441C-AE15-054DB31D3488}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {542A9FA1-B7FF-441C-AE15-054DB31D3488}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {542A9FA1-B7FF-441C-AE15-054DB31D3488}.Blender Debug.Build.0 = Blender Debug|Win32 + {542A9FA1-B7FF-441C-AE15-054DB31D3488}.Blender Release.ActiveCfg = Blender Release|Win32 + {542A9FA1-B7FF-441C-AE15-054DB31D3488}.Blender Release.Build.0 = Blender Release|Win32 + {E86B7BDE-C33C-4E55-9433-E74C141D7538}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {E86B7BDE-C33C-4E55-9433-E74C141D7538}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {E86B7BDE-C33C-4E55-9433-E74C141D7538}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {E86B7BDE-C33C-4E55-9433-E74C141D7538}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {E86B7BDE-C33C-4E55-9433-E74C141D7538}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {E86B7BDE-C33C-4E55-9433-E74C141D7538}.Blender Debug.Build.0 = Blender Debug|Win32 + {E86B7BDE-C33C-4E55-9433-E74C141D7538}.Blender Release.ActiveCfg = Blender Release|Win32 + {E86B7BDE-C33C-4E55-9433-E74C141D7538}.Blender Release.Build.0 = Blender Release|Win32 + {B789C2F3-279E-4A85-8F0A-7F7AC068E598}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {B789C2F3-279E-4A85-8F0A-7F7AC068E598}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {B789C2F3-279E-4A85-8F0A-7F7AC068E598}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {B789C2F3-279E-4A85-8F0A-7F7AC068E598}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {B789C2F3-279E-4A85-8F0A-7F7AC068E598}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {B789C2F3-279E-4A85-8F0A-7F7AC068E598}.Blender Debug.Build.0 = Blender Debug|Win32 + {B789C2F3-279E-4A85-8F0A-7F7AC068E598}.Blender Release.ActiveCfg = Blender Release|Win32 + {B789C2F3-279E-4A85-8F0A-7F7AC068E598}.Blender Release.Build.0 = Blender Release|Win32 + {98330220-47A6-42E0-9DE4-AD0FF5D204D6}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {98330220-47A6-42E0-9DE4-AD0FF5D204D6}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {98330220-47A6-42E0-9DE4-AD0FF5D204D6}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {98330220-47A6-42E0-9DE4-AD0FF5D204D6}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {98330220-47A6-42E0-9DE4-AD0FF5D204D6}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {98330220-47A6-42E0-9DE4-AD0FF5D204D6}.Blender Debug.Build.0 = Blender Debug|Win32 + {98330220-47A6-42E0-9DE4-AD0FF5D204D6}.Blender Release.ActiveCfg = Blender Release|Win32 + {98330220-47A6-42E0-9DE4-AD0FF5D204D6}.Blender Release.Build.0 = Blender Release|Win32 + {213356A9-3A1F-41DA-9819-1297BCD17DEE}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {213356A9-3A1F-41DA-9819-1297BCD17DEE}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {213356A9-3A1F-41DA-9819-1297BCD17DEE}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {213356A9-3A1F-41DA-9819-1297BCD17DEE}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {213356A9-3A1F-41DA-9819-1297BCD17DEE}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {213356A9-3A1F-41DA-9819-1297BCD17DEE}.Blender Debug.Build.0 = Blender Debug|Win32 + {213356A9-3A1F-41DA-9819-1297BCD17DEE}.Blender Release.ActiveCfg = Blender Release|Win32 + {213356A9-3A1F-41DA-9819-1297BCD17DEE}.Blender Release.Build.0 = Blender Release|Win32 + {FAF46346-65CC-4DB2-85C4-B99826F79D0C}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {FAF46346-65CC-4DB2-85C4-B99826F79D0C}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {FAF46346-65CC-4DB2-85C4-B99826F79D0C}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {FAF46346-65CC-4DB2-85C4-B99826F79D0C}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {FAF46346-65CC-4DB2-85C4-B99826F79D0C}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {FAF46346-65CC-4DB2-85C4-B99826F79D0C}.Blender Debug.Build.0 = Blender Debug|Win32 + {FAF46346-65CC-4DB2-85C4-B99826F79D0C}.Blender Release.ActiveCfg = Blender Release|Win32 + {FAF46346-65CC-4DB2-85C4-B99826F79D0C}.Blender Release.Build.0 = Blender Release|Win32 + {8B8D4FC3-3234-4E54-8376-5AB83D00D164}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {8B8D4FC3-3234-4E54-8376-5AB83D00D164}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {8B8D4FC3-3234-4E54-8376-5AB83D00D164}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {8B8D4FC3-3234-4E54-8376-5AB83D00D164}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {8B8D4FC3-3234-4E54-8376-5AB83D00D164}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {8B8D4FC3-3234-4E54-8376-5AB83D00D164}.Blender Debug.Build.0 = Blender Debug|Win32 + {8B8D4FC3-3234-4E54-8376-5AB83D00D164}.Blender Release.ActiveCfg = Blender Release|Win32 + {8B8D4FC3-3234-4E54-8376-5AB83D00D164}.Blender Release.Build.0 = Blender Release|Win32 + {A90C4918-4B21-4277-93BD-AF65F30951D9}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {A90C4918-4B21-4277-93BD-AF65F30951D9}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {A90C4918-4B21-4277-93BD-AF65F30951D9}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {A90C4918-4B21-4277-93BD-AF65F30951D9}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {A90C4918-4B21-4277-93BD-AF65F30951D9}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {A90C4918-4B21-4277-93BD-AF65F30951D9}.Blender Debug.Build.0 = Blender Debug|Win32 + {A90C4918-4B21-4277-93BD-AF65F30951D9}.Blender Release.ActiveCfg = Blender Release|Win32 + {A90C4918-4B21-4277-93BD-AF65F30951D9}.Blender Release.Build.0 = Blender Release|Win32 + {EB75F4D6-2970-4A3A-8D99-2BAD7201C0E9}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {EB75F4D6-2970-4A3A-8D99-2BAD7201C0E9}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {EB75F4D6-2970-4A3A-8D99-2BAD7201C0E9}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {EB75F4D6-2970-4A3A-8D99-2BAD7201C0E9}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {EB75F4D6-2970-4A3A-8D99-2BAD7201C0E9}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {EB75F4D6-2970-4A3A-8D99-2BAD7201C0E9}.Blender Debug.Build.0 = Blender Debug|Win32 + {EB75F4D6-2970-4A3A-8D99-2BAD7201C0E9}.Blender Release.ActiveCfg = Blender Release|Win32 + {EB75F4D6-2970-4A3A-8D99-2BAD7201C0E9}.Blender Release.Build.0 = Blender Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/intern/memutil/CMakeLists.txt b/intern/memutil/CMakeLists.txt new file mode 100644 index 00000000000..a116ca8b721 --- /dev/null +++ b/intern/memutil/CMakeLists.txt @@ -0,0 +1,35 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC . ..) + +FILE(GLOB SRC intern/*.cpp) + +BLENDERLIB(bf_memutil "${SRC}" "${INC}") +#, libtype=['intern', 'player'], priority = [0, 180] ) diff --git a/intern/memutil/MEM_Allocator.h b/intern/memutil/MEM_Allocator.h new file mode 100644 index 00000000000..68712e45558 --- /dev/null +++ b/intern/memutil/MEM_Allocator.h @@ -0,0 +1,111 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributor(s): Peter Schlaile 2005 + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __MEM_Allocator_h_included__ +#define __MEM_Allocator_h_included__ 1 + +#include "guardedalloc/MEM_guardedalloc.h" + +#ifdef _MSC_VER +#if _MSC_VER < 1300 // 1200 == VC++ 6.0 according to boost +#define MS_VISUALC_6_0_WORKAROUND 1 +#endif +#endif + +template +struct MEM_Allocator +{ + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef _Tp* pointer; + typedef const _Tp* const_pointer; + typedef _Tp& reference; + typedef const _Tp& const_reference; + typedef _Tp value_type; + +#ifndef MS_VISUALC_6_0_WORKAROUND + template + struct rebind { + typedef MEM_Allocator<_Tp1> other; + }; +#endif + + MEM_Allocator() throw() {} + MEM_Allocator(const MEM_Allocator&) throw() {} + +#ifndef MS_VISUALC_6_0_WORKAROUND + template + MEM_Allocator(const MEM_Allocator<_Tp1>) throw() { } +#endif + + ~MEM_Allocator() throw() {} + + pointer address(reference __x) const { return &__x; } + + const_pointer address(const_reference __x) const { return &__x; } + +#ifdef MS_VISUALC_6_0_WORKAROUND + char *_Charalloc(size_type n) { + return (char *) MEM_mallocN(n, "STL MEM_Allocator VC6.0"); + } +#endif + // NB: __n is permitted to be 0. The C++ standard says nothing + // about what the return value is when __n == 0. + _Tp* allocate(size_type __n, const void* = 0) { + _Tp* __ret = 0; + if (__n) + __ret = static_cast<_Tp*>( + MEM_mallocN(__n * sizeof(_Tp), + "STL MEM_Allocator")); + return __ret; + } + +#ifndef MS_VISUALC_6_0_WORKAROUND + // __p is not permitted to be a null pointer. + void deallocate(pointer __p, size_type){ + MEM_freeN(__p); + } +#else + // __p is not permitted to be a null pointer. + void deallocate(void* __p, size_type){ + MEM_freeN(__p); + } +#endif + + size_type max_size() const throw() { + return size_t(-1) / sizeof(_Tp); + } + + void construct(pointer __p, const _Tp& __val) { + new(__p) _Tp(__val); + } + + void destroy(pointer __p) { + __p->~_Tp(); + } +}; + +#endif diff --git a/intern/memutil/MEM_CacheLimiter.h b/intern/memutil/MEM_CacheLimiter.h new file mode 100644 index 00000000000..13fb6b23446 --- /dev/null +++ b/intern/memutil/MEM_CacheLimiter.h @@ -0,0 +1,170 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributor(s): Peter Schlaile 2005 + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __MEM_cache_limiter_h_included__ +#define __MEM_cache_limiter_h_included__ 1 + +/** + * @section MEM_CacheLimiter + * This class defines a generic memory cache management system + * to limit memory usage to a fixed global maximum. + * + * Please use the C-API in MEM_CacheLimiterC-Api.h for code written in C. + * + * Usage example: + * + * class BigFatImage { + * public: + * ~BigFatImage() { tell_everyone_we_are_gone(this); } + * }; + * + * void doit() { + * MEM_Cache BigFatImages; + * + * MEM_Cache_Handle* h = BigFatImages.insert(new BigFatImage); + * + * BigFatImages.enforce_limits(); + * h->ref(); + * + * work with image... + * + * h->unref(); + * + * leave image in cache. + */ + +#include +#include "MEM_Allocator.h" + +template +class MEM_CacheLimiter; + +#ifndef __MEM_cache_limiter_c_api_h_included__ +extern "C" { + extern void MEM_CacheLimiter_set_maximum(int m); + extern int MEM_CacheLimiter_get_maximum(); + // this is rather _ugly_! + extern int mem_in_use; + extern int mmap_in_use; +}; +#endif + +template +class MEM_CacheLimiterHandle { +public: + explicit MEM_CacheLimiterHandle(T * data_, + MEM_CacheLimiter * parent_) + : data(data_), refcount(0), parent(parent_) { } + + void ref() { + refcount++; + } + void unref() { + refcount--; + } + T * get() { + return data; + } + const T * get() const { + return data; + } + int get_refcount() const { + return refcount; + } + bool can_destroy() const { + return !data || !refcount; + } + bool destroy_if_possible() { + if (can_destroy()) { + delete data; + data = 0; + unmanage(); + return true; + } + return false; + } + void unmanage() { + parent->unmanage(this); + } + void touch() { + parent->touch(this); + } +private: + friend class MEM_CacheLimiter; + + T * data; + int refcount; + typename std::list *, + MEM_Allocator *> >::iterator me; + MEM_CacheLimiter * parent; +}; + +template +class MEM_CacheLimiter { +public: + typedef typename std::list *, + MEM_Allocator *> >::iterator iterator; + ~MEM_CacheLimiter() { + for (iterator it = queue.begin(); it != queue.end(); it++) { + delete *it; + } + } + MEM_CacheLimiterHandle * insert(T * elem) { + queue.push_back(new MEM_CacheLimiterHandle(elem, this)); + iterator it = queue.end(); + --it; + queue.back()->me = it; + return queue.back(); + } + void unmanage(MEM_CacheLimiterHandle * handle) { + queue.erase(handle->me); + delete handle; + } + void enforce_limits() { + int max = MEM_CacheLimiter_get_maximum(); + if (max == 0) { + return; + } + for (iterator it = queue.begin(); + it != queue.end() && mem_in_use + mmap_in_use > max;) { + iterator jt = it; + ++it; + (*jt)->destroy_if_possible(); + } + } + void touch(MEM_CacheLimiterHandle * handle) { + queue.push_back(handle); + queue.erase(handle->me); + iterator it = queue.end(); + --it; + handle->me = it; + } +private: + std::list*, + MEM_Allocator *> > queue; +}; + +#endif diff --git a/intern/memutil/MEM_CacheLimiterC-Api.h b/intern/memutil/MEM_CacheLimiterC-Api.h new file mode 100644 index 00000000000..f06acb5adea --- /dev/null +++ b/intern/memutil/MEM_CacheLimiterC-Api.h @@ -0,0 +1,144 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributor(s): Peter Schlaile 2005 + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __MEM_cache_limiter_c_api_h_included__ +#define __MEM_cache_limiter_c_api_h_included__ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +struct MEM_CacheLimiter_s; +struct MEM_CacheLimiterHandle_s; + +typedef struct MEM_CacheLimiter_s MEM_CacheLimiterC; +typedef struct MEM_CacheLimiterHandle_s MEM_CacheLimiterHandleC; + +/* function used to remove data from memory */ +typedef void(*MEM_CacheLimiter_Destruct_Func)(void*); + +#ifndef __MEM_cache_limiter_h_included__ +extern void MEM_CacheLimiter_set_maximum(int m); +extern int MEM_CacheLimiter_get_maximum(); +#endif +/** + * Create new MEM_CacheLimiter object + * managed objects are destructed with the data_destructor + * + * @param data_destructor + * @return A new MEM_CacheLimter object + */ + +extern MEM_CacheLimiterC * new_MEM_CacheLimiter( + MEM_CacheLimiter_Destruct_Func data_destructor); + +/** + * Delete MEM_CacheLimiter + * + * Frees the memory of the CacheLimiter but does not touch managed objects! + * + * @param This "This" pointer + */ + +extern void delete_MEM_CacheLimiter(MEM_CacheLimiterC * This); + +/** + * Manage object + * + * @param This "This" pointer, data data object to manage + * @return CacheLimiterHandle to ref, unref, touch the managed object + */ + +extern MEM_CacheLimiterHandleC * MEM_CacheLimiter_insert( + MEM_CacheLimiterC * This, void * data); + +/** + * Free objects until memory constraints are satisfied + * + * @param This "This" pointer + */ + +extern void MEM_CacheLimiter_enforce_limits(MEM_CacheLimiterC * This); + +/** + * Unmanage object previously inserted object. + * Does _not_ delete managed object! + * + * @param This "This" pointer, handle of object + */ + +extern void MEM_CacheLimiter_unmanage(MEM_CacheLimiterHandleC * handle); + + +/** + * Raise priority of object (put it at the tail of the deletion chain) + * + * @param handle of object + */ + +extern void MEM_CacheLimiter_touch(MEM_CacheLimiterHandleC * handle); + +/** + * Increment reference counter. Objects with reference counter != 0 are _not_ + * deleted. + * + * @param handle of object + */ + +extern void MEM_CacheLimiter_ref(MEM_CacheLimiterHandleC * handle); + +/** + * Decrement reference counter. Objects with reference counter != 0 are _not_ + * deleted. + * + * @param handle of object + */ + +extern void MEM_CacheLimiter_unref(MEM_CacheLimiterHandleC * handle); + +/** + * Get reference counter. + * + * @param This "This" pointer, handle of object + */ + +extern int MEM_CacheLimiter_get_refcount(MEM_CacheLimiterHandleC * handle); + +/** + * Get pointer to managed object + * + * @param handle of object + */ + +extern void * MEM_CacheLimiter_get(MEM_CacheLimiterHandleC * handle); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/intern/memutil/MEM_NonCopyable.h b/intern/memutil/MEM_NonCopyable.h new file mode 100644 index 00000000000..e413c2ce28c --- /dev/null +++ b/intern/memutil/MEM_NonCopyable.h @@ -0,0 +1,61 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file MEM_NonCopyable.h + * Declaration of MEM_NonCopyable class. + */ + +#ifndef NAN_INCLUDED_NonCopyable_h +#define NAN_INCLUDED_NonCopyable_h + +/** + * Simple class that makes sure sub classes cannot + * generate standard copy constructors. + * If you want to make sure that your class does + * not have any of these cheesy hidden constructors + * inherit from this class. + */ + +class MEM_NonCopyable { +protected : + + MEM_NonCopyable( + ) { + }; + +private : + + MEM_NonCopyable (const MEM_NonCopyable *); + MEM_NonCopyable (const MEM_NonCopyable &); +}; + +#endif + diff --git a/intern/memutil/MEM_RefCountPtr.h b/intern/memutil/MEM_RefCountPtr.h new file mode 100644 index 00000000000..042c90fa0cb --- /dev/null +++ b/intern/memutil/MEM_RefCountPtr.h @@ -0,0 +1,293 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file MEM_RefCountPtr.h + * Declaration of MEM_RefCounted and MEM_RefCountable classes. + * @author Laurence + */ + +#ifndef NAN_INCLUDED_MEM_RefCountPtr_h +#define NAN_INCLUDED_MEM_RefCountPtr_h + +#include // for NULL ! + +/** + * @section MEM_RefCountable + * This is a base class for reference countable objects. + * If you want an object to be shared using a reference + * counted system derrivce from this class. All subclasses + * should insist that they are created on the heap, this + * can be done by makeing all constructors private and + * defining a static New() method that returns a ref counted + * ptr to a new()ly allocated instance. + * + * @section Example subclass + * + * + * class MySharedObject : public MEM_RefCountable { + * + * private : + * MySharedObject() : MEM_RefCountable() { //class specific initialization}; + * MySharedObject(const MySharedObject &other) // not implemented + * public : + * static + * MEM_RefCountPtr + * New( + * ) { + * return MEM_RefCountPtr( new MySharedObject()); + * } + * + * // other member functions + * }; + * + * Alternitively you may first wish to define a fully functional + * class and then define a reference counting wrapper for this class. + * This is useful when the base type can be used without reference + * counting. + * + * E.g. + * class UsefullClass { + * private : + * ... + * public : + * + * UsefullClass() + * UsefullMethod(...) + * AnotherUsefullMethod(...) + * }; + * + * class RcUsefullClass : public UsefullClass, public MEM_RefCountable + * { + * private : + * // Override base class public constructor --- forces + * // use of New(...) + * RcUsefullClass(...) + * public : + * + * // Override each public constructor of UsefullClass with + * // an equivalent static New method returning a MEM_RefCountPtr + * + * static + * MEM_RefCountPtr + * New(...){ + * return MEM_RefCountPtr output( + * new UsefullClass(...) + * ); + * } + * + * // warning never call destructor directly allow ref counting + * // mechanism to handle object lifetime. + * ~RcUsefullClass(); + * }; + * + * + */ + +class MEM_RefCountable { +private : + + /** + * The reference count! + * We use mutable here because we would like to + * share references of const objects! + * Maybe should think about having decRef() + * another value because we should not be deleting + * non-const objects + */ + + mutable int m_count; + +protected : + + /** + * Protected constructors + * This class is not for direct instanciation. Sub classes + * should only be allocated on the heap. + */ + + MEM_RefCountable ( + ) : + m_count (0) + { + }; + + MEM_RefCountable ( + const MEM_RefCountable & + ) : + m_count (0) + { + } + +public : + + void + IncRef( + ) const { + m_count++; + } + + int + DecRef( + ) { + return (--m_count); + } + + ~MEM_RefCountable( + ) { + //nothing to do + } +}; + +/** + * @section MEM_RefCountPtr + */ + +template + < class T > +class MEM_RefCountPtr { + +public : + + /** + * Construction from reference - share ownership with + * the right hand side. + */ + + MEM_RefCountPtr( + const MEM_RefCountPtr &rhs + ) : m_val (NULL) { + ShareOwnership(rhs.m_val); + } + + /** + * Construction from ptr - this class shares + * ownership of object val. + */ + + MEM_RefCountPtr( + const T* val + ) : + m_val (NULL) + { + ShareOwnership(val); + } + + /** + * Default constructor + */ + + MEM_RefCountPtr( + ) : + m_val (NULL) + { + } + + /** + * Type conversion from this class to the type + * of a pointer to the template parameter. + * This means you can pass an instance of this class + * to a function expecting a ptr of type T. + */ + + operator T * () const { + return m_val; + } + + + MEM_RefCountPtr & operator=( + const MEM_RefCountPtr &rhs + ) { + if (this->m_val != rhs.m_val) { + ReleaseOwnership(); + ShareOwnership(rhs.m_val); + } + return *this; + } + + /** + * Overload the operator -> so that it's possible to access + * all the normal methods of the internal ptr. + */ + + T * operator->() const { + return m_val; + } + + /** + * Returrn a reference to the shared object. + */ + + T& + Ref( + ) { + return *m_val; + } + + + /** + * Destructor - deletes object if it's ref count is zero. + */ + + ~MEM_RefCountPtr( + ) { + ReleaseOwnership(); + } + +private : + + /// The ptr owned by this class. + T * m_val; + + void + ShareOwnership( + const T * val + ) { + if (val != NULL) { + val->IncRef(); + } + m_val = const_cast(val); + } + + void + ReleaseOwnership( + ) { + if (m_val) { + if (m_val->DecRef() == 0) { + delete(m_val); + m_val = NULL; + } + } + } + +}; + +#endif + diff --git a/intern/memutil/MEM_RefCounted.h b/intern/memutil/MEM_RefCounted.h new file mode 100644 index 00000000000..239465cdf34 --- /dev/null +++ b/intern/memutil/MEM_RefCounted.h @@ -0,0 +1,115 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file MEM_RefCounted.h + * Declaration of MEM_RefCounted class. + */ + +#ifndef _H_MEM_REF_COUNTED +#define _H_MEM_REF_COUNTED + +/** + * An object with reference counting. + * Base class for objects with reference counting. + * When a shared object is ceated, it has reference count == 1. + * If the the reference count of a shared object reaches zero, the object self-destructs. + * The default destructor of this object has been made protected on purpose. + * This disables the creation of shared objects on the stack. + * + * @author Maarten Gribnau + * @date March 31, 2001 + */ + +class MEM_RefCounted { +public: + /** + * Constructs a a shared object. + */ + MEM_RefCounted() : m_refCount(1) + { + } + + /** + * Returns the reference count of this object. + * @return the reference count. + */ + inline virtual int getRef() const; + + /** + * Increases the reference count of this object. + * @return the new reference count. + */ + inline virtual int incRef(); + + /** + * Decreases the reference count of this object. + * If the the reference count reaches zero, the object self-destructs. + * @return the new reference count. + */ + inline virtual int decRef(); + +protected: + /** + * Destructs a shared object. + * The destructor is protected to force the use of incRef and decRef. + */ + virtual ~MEM_RefCounted() + { + } + +protected: + /// The reference count. + int m_refCount; +}; + + +inline int MEM_RefCounted::getRef() const +{ + return m_refCount; +} + +inline int MEM_RefCounted::incRef() +{ + return ++m_refCount; +} + +inline int MEM_RefCounted::decRef() +{ + m_refCount--; + if (m_refCount == 0) { + delete this; + return 0; + } + return m_refCount; +} + +#endif // _H_MEM_REF_COUNTED + diff --git a/intern/memutil/MEM_RefCountedC-Api.h b/intern/memutil/MEM_RefCountedC-Api.h new file mode 100644 index 00000000000..f78194fe2f6 --- /dev/null +++ b/intern/memutil/MEM_RefCountedC-Api.h @@ -0,0 +1,78 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file MEM_RefCountedC-Api.h + * Interface for C access to functionality relating to shared objects in the foundation library. + */ + +#ifndef _H_MEM_REF_COUNTED_C_API +#define _H_MEM_REF_COUNTED_C_API + +/** A pointer to a private object. */ +typedef struct MEM_TOpaqueObject* MEM_TObjectPtr; +/** A pointer to a shared object. */ +typedef MEM_TObjectPtr MEM_TRefCountedObjectPtr; + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Returns the reference count of this object. + * @param shared The object to query. + * @return The current reference count. + */ +extern int MEM_RefCountedGetRef(MEM_TRefCountedObjectPtr shared); + +/** + * Increases the reference count of this object. + * @param shared The object to query. + * @return The new reference count. + */ +extern int MEM_RefCountedIncRef(MEM_TRefCountedObjectPtr shared); + +/** + * Decreases the reference count of this object. + * If the the reference count reaches zero, the object self-destructs. + * @param shared The object to query. + * @return The new reference count. + */ +extern int MEM_RefCountedDecRef(MEM_TRefCountedObjectPtr shared); + + +#ifdef __cplusplus +} +#endif + +#endif // _H_MEM_REF_COUNTED_C_API + diff --git a/intern/memutil/MEM_SmartPtr.h b/intern/memutil/MEM_SmartPtr.h new file mode 100644 index 00000000000..55bae151027 --- /dev/null +++ b/intern/memutil/MEM_SmartPtr.h @@ -0,0 +1,240 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file MEM_SmartPtr.h + * Declaration of MEM_RefCounted and MEM_RefCountable classes. + * @author Laurence + */ + +#ifndef NAN_INCLUDED_MEM_SmartPtr_h +#define NAN_INCLUDED_MEM_SmartPtr_h + + +#include // for NULL ! + + +/** + * @section MEM_SmartPtr + * This class defines a smart pointer similar to that defined in + * the Standard Template Library but without the painful get() + * semantics to access the internal c style pointer. + * + * It is often useful to explicitely decalre ownership of memory + * allocated on the heap within class or function scope. This + * class helps you to encapsulate this ownership within a value + * type. When an instance of this class goes out of scope it + * makes sure that any memory associated with it's internal pointer + * is deleted. It can help to inform users of an aggregate class + * that it owns instances of it's members and these instances + * should not be shared. This is not reliably enforcable in C++ + * but this class attempts to make the 1-1 relationship clear. + * + * @section Example usage + * + * class foo { + * ...constructors accessors etc. + * int x[1000]; + * } + * + * class bar { + * public : + * static + * bar * + * New( + * ) { + * MEM_SmartPtr afoo = new foo(); + * MEM_SmartPtr that = new bar(); + * + * if (foo == NULL || that == NULL) return NULL; + * + * that->m_foo = afoo.Release(); + * return that.Release(); + * } + * + * ~bar() { + * // smart ptr takes care of deletion + * } + * private : + * MEM_SmartPtr m_foo; + * } + * + * You may also safely construct vectors of MEM_SmartPtrs and + * have the vector own stuff you put into it. + * + * e.g. + * { + * std::vector > foo_vector; + * foo_vector.push_back( new foo()); + * foo_vector.push_back( new foo()); + * + * foo_vector[0]->bla(); + * } // foo_vector out of scope => heap memory freed for both foos + * + * @warning this class should only be used for objects created + * on the heap via the new function. It will not behave correctly + * if you pass ptrs to objects created with new[] nor with + * objects declared on the stack. Doing this is likely to crash + * the program or lead to memory leaks. + */ + +template + < class T > +class MEM_SmartPtr { + +public : + + /** + * Construction from reference - this class + * always assumes ownership from the rhs. + */ + + MEM_SmartPtr( + const MEM_SmartPtr &rhs + ){ + m_val = rhs.Release(); + } + + /** + * Construction from ptr - this class always + * assumes that it now owns the memory associated with the + * ptr. + */ + + MEM_SmartPtr( + T* val + ) : + m_val (val) + { + } + + /** + * Defalut constructor + */ + + MEM_SmartPtr( + ) : + m_val (NULL) + { + } + + /** + * Type conversion from this class to the type + * of a pointer to the template parameter. + * This means you can pass an instance of this class + * to a function expecting a ptr of type T. + */ + + operator T * () const { + return m_val; + } + + /** + * Return a reference to the internal ptr class. + * Use with care when you now that the internal ptr + * is not NULL! + */ + + T & + Ref( + ) const { + return *m_val; + } + + /** + * Assignment operator - ownership is transfered from rhs to lhs. + * There is an intenional side-effect of function of transferring + * ownership from the const parameter rhs. This is to insure + * the 1-1 relationship. + * The object associated with this instance is deleted if it + * is not the same as that contained in the rhs. + */ + + MEM_SmartPtr & operator=( + const MEM_SmartPtr &rhs + ) { + if (this->m_val != rhs.m_val) { + delete this->m_val; + } + + this->m_val = rhs.Release(); + return *this; + } + + /** + * Overload the operator -> so that it's possible to access + * all the normal methods of the internal ptr. + */ + + T * operator->() const { + return m_val; + } + + /** + * Caller takes ownership of the object - the object will not + * be deleted when the ptr goes out of scope. + */ + + T * + Release( + ) const { + T* temp = m_val; + (const_cast(this))->m_val = NULL; + return temp; + } + + /** + * Force destruction of the internal object. + */ + + void + Delete( + ) { + delete (m_val); + m_val = NULL; + } + + /** + * Destructor - deletes object if it exists + */ + + ~MEM_SmartPtr( + ) { + delete (m_val); + } + +private : + + /// The ptr owned by this class. + T * m_val; +}; + +#endif + diff --git a/intern/memutil/Makefile b/intern/memutil/Makefile new file mode 100644 index 00000000000..57a8adc8e10 --- /dev/null +++ b/intern/memutil/Makefile @@ -0,0 +1,56 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# memutil main makefile. +# + +include nan_definitions.mk + +LIBNAME = memutil +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +#not yet TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_MEMUTIL) ] || mkdir $(NAN_MEMUTIL) + @[ -d $(NAN_MEMUTIL)/include ] || mkdir $(NAN_MEMUTIL)/include + @[ -d $(NAN_MEMUTIL)/lib ] || mkdir $(NAN_MEMUTIL)/lib + @[ -d $(NAN_MEMUTIL)/lib/debug ] || mkdir $(NAN_MEMUTIL)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libmemutil.a $(NAN_MEMUTIL)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libmemutil.a $(NAN_MEMUTIL)/lib/debug +ifeq ($(OS),darwin) + ranlib $(NAN_MEMUTIL)/lib/libmemutil.a + ranlib $(NAN_MEMUTIL)/lib/debug/libmemutil.a +endif + @../tools/cpifdiff.sh *.h $(NAN_MEMUTIL)/include/ + diff --git a/intern/memutil/SConscript b/intern/memutil/SConscript new file mode 100644 index 00000000000..4528de814f3 --- /dev/null +++ b/intern/memutil/SConscript @@ -0,0 +1,8 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.cpp') + +incs = '. ..' + +env.BlenderLib ('bf_memutil', sources, Split(incs), [], libtype=['intern', 'player'], priority = [0, 180] ) diff --git a/intern/memutil/intern/MEM_CacheLimiterC-Api.cpp b/intern/memutil/intern/MEM_CacheLimiterC-Api.cpp new file mode 100644 index 00000000000..4cf0ef305d4 --- /dev/null +++ b/intern/memutil/intern/MEM_CacheLimiterC-Api.cpp @@ -0,0 +1,195 @@ +/** + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributor(s): Peter Schlaile 2005 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_CacheLimiter.h" +#include "MEM_CacheLimiterC-Api.h" + +static int & get_max() +{ + static int m = 32*1024*1024; + return m; +} + +void MEM_CacheLimiter_set_maximum(int m) +{ + get_max() = m; +} + +int MEM_CacheLimiter_get_maximum() +{ + return get_max(); +} + +class MEM_CacheLimiterHandleCClass; +class MEM_CacheLimiterCClass; + +typedef MEM_CacheLimiterHandle handle_t; +typedef MEM_CacheLimiter cache_t; +typedef std::list > list_t; + +class MEM_CacheLimiterCClass { +public: + MEM_CacheLimiterCClass(MEM_CacheLimiter_Destruct_Func data_destructor_) + : data_destructor(data_destructor_) { + } + ~MEM_CacheLimiterCClass(); + + handle_t * insert(void * data); + + void destruct(void * data, + list_t::iterator it); + + cache_t * get_cache() { + return &cache; + } +private: + MEM_CacheLimiter_Destruct_Func data_destructor; + + MEM_CacheLimiter cache; + + list_t cclass_list; +}; + +class MEM_CacheLimiterHandleCClass { +public: + MEM_CacheLimiterHandleCClass(void * data_, + MEM_CacheLimiterCClass * parent_) + : data(data_), parent(parent_) { } + ~MEM_CacheLimiterHandleCClass(); + void set_iter(list_t::iterator it_) { + it = it_; + } + void set_data(void * data_) { + data = data_; + } + void * get_data() const { + return data; + } +private: + void * data; + MEM_CacheLimiterCClass * parent; + list_t::iterator it; +}; + +handle_t * MEM_CacheLimiterCClass::insert(void * data) +{ + cclass_list.push_back(new MEM_CacheLimiterHandleCClass(data, this)); + list_t::iterator it = cclass_list.end(); + --it; + cclass_list.back()->set_iter(it); + + return cache.insert(cclass_list.back()); +} + +void MEM_CacheLimiterCClass::destruct(void * data, list_t::iterator it) +{ + data_destructor(data); + cclass_list.erase(it); +} + +MEM_CacheLimiterHandleCClass::~MEM_CacheLimiterHandleCClass() +{ + if (data) { + parent->destruct(data, it); + } +} + +MEM_CacheLimiterCClass::~MEM_CacheLimiterCClass() +{ + // should not happen, but don't leak memory in this case... + for (list_t::iterator it = cclass_list.begin(); + it != cclass_list.end(); it++) { + (*it)->set_data(0); + delete *it; + } +} + +// ---------------------------------------------------------------------- + +static inline MEM_CacheLimiterCClass* cast(MEM_CacheLimiterC * l) +{ + return (MEM_CacheLimiterCClass*) l; +} + +static inline handle_t* cast(MEM_CacheLimiterHandleC * l) +{ + return (handle_t*) l; +} + +MEM_CacheLimiterC * new_MEM_CacheLimiter( + MEM_CacheLimiter_Destruct_Func data_destructor) +{ + return (MEM_CacheLimiterC*) new MEM_CacheLimiterCClass( + data_destructor); +} + +void delete_MEM_CacheLimiter(MEM_CacheLimiterC * This) +{ + delete cast(This); +} + +MEM_CacheLimiterHandleC * MEM_CacheLimiter_insert( + MEM_CacheLimiterC * This, void * data) +{ + return (MEM_CacheLimiterHandleC *) cast(This)->insert(data); +} + +void MEM_CacheLimiter_enforce_limits(MEM_CacheLimiterC * This) +{ + cast(This)->get_cache()->enforce_limits(); +} + +void MEM_CacheLimiter_unmanage(MEM_CacheLimiterHandleC * handle) +{ + cast(handle)->unmanage(); +} + +void MEM_CacheLimiter_touch(MEM_CacheLimiterHandleC * handle) +{ + cast(handle)->touch(); +} + +void MEM_CacheLimiter_ref(MEM_CacheLimiterHandleC * handle) +{ + cast(handle)->ref(); +} + +void MEM_CacheLimiter_unref(MEM_CacheLimiterHandleC * handle) +{ + cast(handle)->unref(); +} + +int MEM_CacheLimiter_get_refcount(MEM_CacheLimiterHandleC * handle) +{ + return cast(handle)->get_refcount(); +} + + +void * MEM_CacheLimiter_get(MEM_CacheLimiterHandleC * handle) +{ + return cast(handle)->get()->get_data(); +} diff --git a/intern/memutil/intern/MEM_RefCountedC-Api.cpp b/intern/memutil/intern/MEM_RefCountedC-Api.cpp new file mode 100644 index 00000000000..873b2c99a59 --- /dev/null +++ b/intern/memutil/intern/MEM_RefCountedC-Api.cpp @@ -0,0 +1,56 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_RefCountedC-Api.h" +#include "MEM_RefCounted.h" + + + +int MEM_RefCountedGetRef(MEM_TRefCountedObjectPtr shared) +{ + return shared ? ((MEM_RefCounted*)shared)->getRef() : 0; +} + + +int MEM_RefCountedIncRef(MEM_TRefCountedObjectPtr shared) +{ + return shared ? ((MEM_RefCounted*)shared)->incRef() : 0; +} + + +int MEM_RefCountedDecRef(MEM_TRefCountedObjectPtr shared) +{ + return shared ? ((MEM_RefCounted*)shared)->decRef() : 0; +} diff --git a/intern/memutil/intern/Makefile b/intern/memutil/intern/Makefile new file mode 100644 index 00000000000..71ffa6fa7e4 --- /dev/null +++ b/intern/memutil/intern/Makefile @@ -0,0 +1,42 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# memutil intern Makefile +# + +LIBNAME = memutil +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I.. -I../.. + diff --git a/intern/memutil/make/msvc_60/memutil.dsp b/intern/memutil/make/msvc_60/memutil.dsp new file mode 100644 index 00000000000..62b7efba9d8 --- /dev/null +++ b/intern/memutil/make/msvc_60/memutil.dsp @@ -0,0 +1,150 @@ +# Microsoft Developer Studio Project File - Name="memutil" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=memutil - 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 "memutil.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 "memutil.mak" CFG="memutil - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "memutil - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "memutil - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "memutil - 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 "..\..\..\..\obj\windows\intern\memutil\" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\memutil\" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /Ob2 /I "../../" /I "../../../" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# 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 +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\memutil\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\memutil\*.lib ..\..\..\..\..\lib\windows\memutil\lib\*.a ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "memutil - 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 "..\..\..\..\obj\windows\intern\memutil\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\memutil\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../" /I "../../../" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# 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 +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\memutil\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\memutil\debug\*.lib ..\..\..\..\..\lib\windows\memutil\lib\debug\*.a ECHO Copying Debug info. XCOPY /Y ..\..\..\..\obj\windows\intern\memutil\debug\vc60.* ..\..\..\..\..\lib\windows\memutil\lib\debug\ ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "memutil - Win32 Release" +# Name "memutil - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\MEM_Allocator.h +# End Source File +# Begin Source File + +SOURCE=..\..\MEM_CacheLimiter.h +# End Source File +# Begin Source File + +SOURCE="..\..\intern\MEM_CacheLimiterC-Api.cpp" +# End Source File +# Begin Source File + +SOURCE=..\..\..\guardedalloc\MEM_guardedalloc.h +# End Source File +# Begin Source File + +SOURCE="..\..\intern\MEM_RefCountedC-Api.cpp" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Group "intern" + +# PROP Default_Filter "" +# End Group +# Begin Group "extern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\MEM_NonCopyable.h +# End Source File +# Begin Source File + +SOURCE=..\..\MEM_RefCounted.h +# End Source File +# Begin Source File + +SOURCE="..\..\MEM_RefCountedC-Api.h" +# End Source File +# Begin Source File + +SOURCE=..\..\MEM_RefCountPtr.h +# End Source File +# Begin Source File + +SOURCE=..\..\MEM_SmartPtr.h +# End Source File +# End Group +# End Group +# End Target +# End Project diff --git a/intern/memutil/make/msvc_60/memutil.dsw b/intern/memutil/make/msvc_60/memutil.dsw new file mode 100644 index 00000000000..bba4cbcdafd --- /dev/null +++ b/intern/memutil/make/msvc_60/memutil.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "memutil"=".\memutil.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/memutil/make/msvc_7_0/memutil.sln b/intern/memutil/make/msvc_7_0/memutil.sln new file mode 100644 index 00000000000..462cd1a3871 --- /dev/null +++ b/intern/memutil/make/msvc_7_0/memutil.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "memutil", "memutil.vcproj", "{8B8B95BA-3084-408F-8EE6-3FE6EF52E112}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {8B8B95BA-3084-408F-8EE6-3FE6EF52E112}.Debug.ActiveCfg = Debug|Win32 + {8B8B95BA-3084-408F-8EE6-3FE6EF52E112}.Debug.Build.0 = Debug|Win32 + {8B8B95BA-3084-408F-8EE6-3FE6EF52E112}.Release.ActiveCfg = Release|Win32 + {8B8B95BA-3084-408F-8EE6-3FE6EF52E112}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/intern/memutil/make/msvc_7_0/memutil.vcproj b/intern/memutil/make/msvc_7_0/memutil.vcproj new file mode 100644 index 00000000000..2d570ea3d49 --- /dev/null +++ b/intern/memutil/make/msvc_7_0/memutil.vcproj @@ -0,0 +1,292 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/moto/CMakeLists.txt b/intern/moto/CMakeLists.txt new file mode 100644 index 00000000000..9004e4c435d --- /dev/null +++ b/intern/moto/CMakeLists.txt @@ -0,0 +1,35 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC include) + +FILE(GLOB SRC intern/*.cpp) + +BLENDERLIB(bf_moto "${SRC}" "${INC}") +#, libtype=['intern','game','game2','player'], priority = [15, 55, 100, 135] ) diff --git a/intern/moto/Makefile b/intern/moto/Makefile new file mode 100644 index 00000000000..0649719e92e --- /dev/null +++ b/intern/moto/Makefile @@ -0,0 +1,56 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# moto main makefile. +# + +include nan_definitions.mk + +LIBNAME = moto +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +#not ready yet TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_MOTO) ] || mkdir $(NAN_MOTO) + @[ -d $(NAN_MOTO)/include ] || mkdir $(NAN_MOTO)/include + @[ -d $(NAN_MOTO)/lib ] || mkdir $(NAN_MOTO)/lib + @[ -d $(NAN_MOTO)/lib/debug ] || mkdir $(NAN_MOTO)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libmoto.a $(NAN_MOTO)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libmoto.a $(NAN_MOTO)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_MOTO)/lib/libmoto.a + ranlib $(NAN_MOTO)/lib/debug/libmoto.a +endif + @../tools/cpifdiff.sh include/*.h $(NAN_MOTO)/include/ + diff --git a/intern/moto/SConscript b/intern/moto/SConscript new file mode 100644 index 00000000000..636515aa5c5 --- /dev/null +++ b/intern/moto/SConscript @@ -0,0 +1,8 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.cpp') + +incs = 'include' + +env.BlenderLib ('bf_moto', sources, Split(incs), [], libtype=['intern','game','game2','player'], priority = [15, 55, 100, 135] ) diff --git a/intern/moto/include/GEN_List.h b/intern/moto/include/GEN_List.h new file mode 100644 index 00000000000..00fdbb85ad1 --- /dev/null +++ b/intern/moto/include/GEN_List.h @@ -0,0 +1,117 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef GEN_LIST_H +#define GEN_LIST_H + +class GEN_Link { +public: + GEN_Link() : m_next(0), m_prev(0) {} + GEN_Link(GEN_Link *next, GEN_Link *prev) : m_next(next), m_prev(prev) {} + + GEN_Link *getNext() const { return m_next; } + GEN_Link *getPrev() const { return m_prev; } + + bool isHead() const { return m_prev == 0; } + bool isTail() const { return m_next == 0; } + + void insertBefore(GEN_Link *link) { + m_next = link; + m_prev = link->m_prev; + m_next->m_prev = this; + m_prev->m_next = this; + } + + void insertAfter(GEN_Link *link) { + m_next = link->m_next; + m_prev = link; + m_next->m_prev = this; + m_prev->m_next = this; + } + + void remove() { + m_next->m_prev = m_prev; + m_prev->m_next = m_next; + } + +private: + GEN_Link *m_next; + GEN_Link *m_prev; +}; + +class GEN_List { +public: + GEN_List() : m_head(&m_tail, 0), m_tail(0, &m_head) {} + + GEN_Link *getHead() const { return m_head.getNext(); } + GEN_Link *getTail() const { return m_tail.getPrev(); } + + void addHead(GEN_Link *link) { link->insertAfter(&m_head); } + void addTail(GEN_Link *link) { link->insertBefore(&m_tail); } + +private: + GEN_Link m_head; + GEN_Link m_tail; +}; + +#endif + diff --git a/intern/moto/include/GEN_Map.h b/intern/moto/include/GEN_Map.h new file mode 100644 index 00000000000..64a2c3cfc6e --- /dev/null +++ b/intern/moto/include/GEN_Map.h @@ -0,0 +1,149 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef GEN_MAP_H +#define GEN_MAP_H + +template +class GEN_Map { +private: + struct Entry { + Entry (Entry *next, Key key, Value value) : + m_next(next), + m_key(key), + m_value(value) {} + + Entry *m_next; + Key m_key; + Value m_value; + }; + +public: + GEN_Map(int num_buckets = 100) : m_num_buckets(num_buckets) { + m_buckets = new Entry *[num_buckets]; + for (int i = 0; i < num_buckets; ++i) { + m_buckets[i] = 0; + } + } + + int size() { + int count=0; + for (int i=0;im_next; + count++; + } + } + return count; + } + + Value* at(int index) { + int count=0; + for (int i=0;im_value; + } + bucket = bucket->m_next; + count++; + } + } + return 0; + } + + void clear() { + for (int i = 0; i < m_num_buckets; ++i) { + Entry *entry_ptr = m_buckets[i]; + + while (entry_ptr != 0) { + Entry *tmp_ptr = entry_ptr->m_next; + delete entry_ptr; + entry_ptr = tmp_ptr; + } + m_buckets[i] = 0; + } + } + + ~GEN_Map() { + clear(); + delete [] m_buckets; + } + + void insert(const Key& key, const Value& value) { + Entry *entry_ptr = m_buckets[key.hash() % m_num_buckets]; + while ((entry_ptr != 0) && !(key == entry_ptr->m_key)) { + entry_ptr = entry_ptr->m_next; + } + + if (entry_ptr != 0) { + entry_ptr->m_value = value; + } + else { + Entry **bucket = &m_buckets[key.hash() % m_num_buckets]; + *bucket = new Entry(*bucket, key, value); + } + } + + void remove(const Key& key) { + Entry **entry_ptr = &m_buckets[key.hash() % m_num_buckets]; + while ((*entry_ptr != 0) && !(key == (*entry_ptr)->m_key)) { + entry_ptr = &(*entry_ptr)->m_next; + } + + if (*entry_ptr != 0) { + Entry *tmp_ptr = (*entry_ptr)->m_next; + delete *entry_ptr; + *entry_ptr = tmp_ptr; + } + } + + Value *operator[](Key key) { + Entry *bucket = m_buckets[key.hash() % m_num_buckets]; + while ((bucket != 0) && !(key == bucket->m_key)) { + bucket = bucket->m_next; + } + return bucket != 0 ? &bucket->m_value : 0; + } + +private: + int m_num_buckets; + Entry **m_buckets; +}; + +#endif + diff --git a/intern/moto/include/MT_CmMatrix4x4.h b/intern/moto/include/MT_CmMatrix4x4.h new file mode 100644 index 00000000000..86858576abf --- /dev/null +++ b/intern/moto/include/MT_CmMatrix4x4.h @@ -0,0 +1,147 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef INCLUDED_MT_CmMatrix4x4 +#define INCLUDED_MT_CmMatrix4x4 + +/** + * A 4x4 matrix. This is an OpenGl style matrix (column major) meaning + * that the vector {m[0][0],m[0][1],m[0][2],m[0][3]} is the first column of + * the matrix , the same as what you get if you transform {1,0,0,0}. + * This makes it easy to transform stuff to OpenGl. Please note that the + * the other MoTo matrices are row major. + * + * This class should be deprecated in favour of the more consistent + * MT_Matrix4x4. Please do not start using this class. + */ + +#include "MT_Scalar.h" + +class MT_Point3; +class MT_Vector3; + +class MT_CmMatrix4x4 +{ + +public : + + MT_CmMatrix4x4( + const float value[4][4] + ); + + MT_CmMatrix4x4( + ); + + + MT_CmMatrix4x4( + const double value[16] + ); + + MT_CmMatrix4x4( + const MT_CmMatrix4x4 & other + ); + + MT_CmMatrix4x4( + const MT_Point3& orig, + const MT_Vector3& dir, + const MT_Vector3 up + ); + + void + Identity( + ); + + void + SetMatrix( + const MT_CmMatrix4x4 & other + ); + + double* + getPointer( + ); + + const + double* + getPointer( + ) const; + + void + setElem( + int pos, + double newvalue + ); + + MT_Vector3 + GetRight( + ) const; + + MT_Vector3 + GetUp( + ) const; + + MT_Vector3 + GetDir( + ) const; + + MT_Point3 + GetPos( + ) const; + + void + SetPos( + const MT_Vector3 & v + ); + + double& + operator ( + ) (int row,int col) { return m_V[col][row]; } + + static + MT_CmMatrix4x4 + Perspective( + MT_Scalar inLeft, + MT_Scalar inRight, + MT_Scalar inBottom, + MT_Scalar inTop, + MT_Scalar inNear, + MT_Scalar inFar + ); + +protected: + union + { + double m_V[4][4]; + double m_Vflat[16]; + }; +}; + +#endif //MT_CmMatrix4x4 + diff --git a/intern/moto/include/MT_Matrix3x3.h b/intern/moto/include/MT_Matrix3x3.h new file mode 100644 index 00000000000..fb899a7da96 --- /dev/null +++ b/intern/moto/include/MT_Matrix3x3.h @@ -0,0 +1,224 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * Copyright (c) 2000 Gino van den Bergen + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Gino van den Bergen makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef MT_MATRIX3X3_H +#define MT_MATRIX3X3_H + +#include + +#include "MT_Vector3.h" +#include "MT_Quaternion.h" + +class MT_Matrix3x3 { +public: + MT_Matrix3x3() {} + MT_Matrix3x3(const float *m) { setValue(m); } + MT_Matrix3x3(const double *m) { setValue(m); } + MT_Matrix3x3(const MT_Quaternion& q) { setRotation(q); } + + MT_Matrix3x3(const MT_Quaternion& q, const MT_Vector3& s) { + setRotation(q); + scale(s[0], s[1], s[2]); + } + + MT_Matrix3x3(const MT_Vector3& euler) { setEuler(euler); } + MT_Matrix3x3(const MT_Vector3& euler, const MT_Vector3& s) { + setEuler(euler); + scale(s[0], s[1], s[2]); + } + + MT_Matrix3x3(MT_Scalar xx, MT_Scalar xy, MT_Scalar xz, + MT_Scalar yx, MT_Scalar yy, MT_Scalar yz, + MT_Scalar zx, MT_Scalar zy, MT_Scalar zz) { + setValue(xx, xy, xz, + yx, yy, yz, + zx, zy, zz); + } + + MT_Vector3& operator[](int i) { return m_el[i]; } + const MT_Vector3& operator[](int i) const { return m_el[i]; } + + MT_Vector3 getColumn(int i) const { + return MT_Vector3(m_el[0][i], m_el[1][i], m_el[2][i]); + } + void setColumn(int i, const MT_Vector3& v) { + m_el[0][i] = v[0]; + m_el[1][i] = v[1]; + m_el[2][i] = v[2]; + } + + void setValue(const float *m) { + m_el[0][0] = *m++; m_el[1][0] = *m++; m_el[2][0] = *m++; m++; + m_el[0][1] = *m++; m_el[1][1] = *m++; m_el[2][1] = *m++; m++; + m_el[0][2] = *m++; m_el[1][2] = *m++; m_el[2][2] = *m; + } + + void setValue(const double *m) { + m_el[0][0] = *m++; m_el[1][0] = *m++; m_el[2][0] = *m++; m++; + m_el[0][1] = *m++; m_el[1][1] = *m++; m_el[2][1] = *m++; m++; + m_el[0][2] = *m++; m_el[1][2] = *m++; m_el[2][2] = *m; + } + + void setValue(MT_Scalar xx, MT_Scalar xy, MT_Scalar xz, + MT_Scalar yx, MT_Scalar yy, MT_Scalar yz, + MT_Scalar zx, MT_Scalar zy, MT_Scalar zz) { + m_el[0][0] = xx; m_el[0][1] = xy; m_el[0][2] = xz; + m_el[1][0] = yx; m_el[1][1] = yy; m_el[1][2] = yz; + m_el[2][0] = zx; m_el[2][1] = zy; m_el[2][2] = zz; + } + + void setRotation(const MT_Quaternion& q) { + MT_Scalar d = q.length2(); + MT_assert(!MT_fuzzyZero2(d)); + MT_Scalar s = MT_Scalar(2.0) / d; + MT_Scalar xs = q[0] * s, ys = q[1] * s, zs = q[2] * s; + MT_Scalar wx = q[3] * xs, wy = q[3] * ys, wz = q[3] * zs; + MT_Scalar xx = q[0] * xs, xy = q[0] * ys, xz = q[0] * zs; + MT_Scalar yy = q[1] * ys, yz = q[1] * zs, zz = q[2] * zs; + setValue(MT_Scalar(1.0) - (yy + zz), xy - wz , xz + wy, + xy + wz , MT_Scalar(1.0) - (xx + zz), yz - wx, + xz - wy , yz + wx, MT_Scalar(1.0) - (xx + yy)); + } + + /** + * setEuler + * @param euler a const reference to a MT_Vector3 of euler angles + * These angles are used to produce a rotation matrix. The euler + * angles are applied in ZYX order. I.e a vector is first rotated + * about X then Y and then Z + **/ + + void setEuler(const MT_Vector3& euler) { + MT_Scalar ci = cos(euler[0]); + MT_Scalar cj = cos(euler[1]); + MT_Scalar ch = cos(euler[2]); + MT_Scalar si = sin(euler[0]); + MT_Scalar sj = sin(euler[1]); + MT_Scalar sh = sin(euler[2]); + MT_Scalar cc = ci * ch; + MT_Scalar cs = ci * sh; + MT_Scalar sc = si * ch; + MT_Scalar ss = si * sh; + + setValue(cj * ch, sj * sc - cs, sj * cc + ss, + cj * sh, sj * ss + cc, sj * cs - sc, + -sj, cj * si, cj * ci); + } + + void scale(MT_Scalar x, MT_Scalar y, MT_Scalar z) { + m_el[0][0] *= x; m_el[0][1] *= y; m_el[0][2] *= z; + m_el[1][0] *= x; m_el[1][1] *= y; m_el[1][2] *= z; + m_el[2][0] *= x; m_el[2][1] *= y; m_el[2][2] *= z; + } + + MT_Matrix3x3 scaled(MT_Scalar x, MT_Scalar y, MT_Scalar z) const { + return MT_Matrix3x3(m_el[0][0] * x, m_el[0][1] * y, m_el[0][2] * z, + m_el[1][0] * x, m_el[1][1] * y, m_el[1][2] * z, + m_el[2][0] * x, m_el[2][1] * y, m_el[2][2] * z); + } + + void setIdentity() { + setValue(MT_Scalar(1.0), MT_Scalar(0.0), MT_Scalar(0.0), + MT_Scalar(0.0), MT_Scalar(1.0), MT_Scalar(0.0), + MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(1.0)); + } + + void getValue(float *m) const { + *m++ = (float) m_el[0][0]; *m++ = (float) m_el[1][0]; *m++ = (float) m_el[2][0]; *m++ = (float) 0.0; + *m++ = (float) m_el[0][1]; *m++ = (float) m_el[1][1]; *m++ = (float) m_el[2][1]; *m++ = (float) 0.0; + *m++ = (float) m_el[0][2]; *m++ = (float) m_el[1][2]; *m++ = (float) m_el[2][2]; *m = (float) 0.0; + } + + void getValue(double *m) const { + *m++ = m_el[0][0]; *m++ = m_el[1][0]; *m++ = m_el[2][0]; *m++ = 0.0; + *m++ = m_el[0][1]; *m++ = m_el[1][1]; *m++ = m_el[2][1]; *m++ = 0.0; + *m++ = m_el[0][2]; *m++ = m_el[1][2]; *m++ = m_el[2][2]; *m = 0.0; + } + + MT_Quaternion getRotation() const; + + MT_Matrix3x3& operator*=(const MT_Matrix3x3& m); + + MT_Scalar tdot(int c, const MT_Vector3& v) const { + return m_el[0][c] * v[0] + m_el[1][c] * v[1] + m_el[2][c] * v[2]; + } + + MT_Scalar cofac(int r1, int c1, int r2, int c2) const { + return m_el[r1][c1] * m_el[r2][c2] - m_el[r1][c2] * m_el[r2][c1]; + } + + MT_Scalar determinant() const; + MT_Matrix3x3 adjoint() const; + + MT_Matrix3x3 absolute() const; + + MT_Matrix3x3 transposed() const; + void transpose(); + + MT_Matrix3x3 inverse() const; + void invert(); + +protected: + + MT_Vector3 m_el[3]; +}; + +MT_Vector3 operator*(const MT_Matrix3x3& m, const MT_Vector3& v); +MT_Vector3 operator*(const MT_Vector3& v, const MT_Matrix3x3& m); +MT_Matrix3x3 operator*(const MT_Matrix3x3& m1, const MT_Matrix3x3& m2); + +MT_Matrix3x3 MT_multTransposeLeft(const MT_Matrix3x3& m1, const MT_Matrix3x3& m2); +MT_Matrix3x3 MT_multTransposeRight(const MT_Matrix3x3& m1, const MT_Matrix3x3& m2); + +inline MT_OStream& operator<<(MT_OStream& os, const MT_Matrix3x3& m) { + return os << m[0] << GEN_endl << m[1] << GEN_endl << m[2] << GEN_endl; +} + +#ifdef GEN_INLINED +#include "MT_Matrix3x3.inl" +#endif + +#endif + diff --git a/intern/moto/include/MT_Matrix3x3.inl b/intern/moto/include/MT_Matrix3x3.inl new file mode 100644 index 00000000000..c581640ebfe --- /dev/null +++ b/intern/moto/include/MT_Matrix3x3.inl @@ -0,0 +1,128 @@ +#include "MT_Optimize.h" + +GEN_INLINE MT_Quaternion MT_Matrix3x3::getRotation() const { + static int next[3] = { 1, 2, 0 }; + + MT_Quaternion result; + + MT_Scalar trace = m_el[0][0] + m_el[1][1] + m_el[2][2]; + + if (trace > 0.0) + { + MT_Scalar s = sqrt(trace + MT_Scalar(1.0)); + result[3] = s * MT_Scalar(0.5); + s = MT_Scalar(0.5) / s; + + result[0] = (m_el[2][1] - m_el[1][2]) * s; + result[1] = (m_el[0][2] - m_el[2][0]) * s; + result[2] = (m_el[1][0] - m_el[0][1]) * s; + } + else + { + int i = 0; + if (m_el[1][1] > m_el[0][0]) + i = 1; + if (m_el[2][2] > m_el[i][i]) + i = 2; + + int j = next[i]; + int k = next[j]; + + MT_Scalar s = sqrt(m_el[i][i] - m_el[j][j] - m_el[k][k] + MT_Scalar(1.0)); + + result[i] = s * MT_Scalar(0.5); + + s = MT_Scalar(0.5) / s; + + result[3] = (m_el[k][j] - m_el[j][k]) * s; + result[j] = (m_el[j][i] + m_el[i][j]) * s; + result[k] = (m_el[k][i] + m_el[i][k]) * s; + } + return result; +} + +GEN_INLINE MT_Matrix3x3& MT_Matrix3x3::operator*=(const MT_Matrix3x3& m) { + setValue(m.tdot(0, m_el[0]), m.tdot(1, m_el[0]), m.tdot(2, m_el[0]), + m.tdot(0, m_el[1]), m.tdot(1, m_el[1]), m.tdot(2, m_el[1]), + m.tdot(0, m_el[2]), m.tdot(1, m_el[2]), m.tdot(2, m_el[2])); + return *this; +} + +GEN_INLINE MT_Scalar MT_Matrix3x3::determinant() const { + return MT_triple((*this)[0], (*this)[1], (*this)[2]); +} + +GEN_INLINE MT_Matrix3x3 MT_Matrix3x3::absolute() const { + return + MT_Matrix3x3(MT_abs(m_el[0][0]), MT_abs(m_el[0][1]), MT_abs(m_el[0][2]), + MT_abs(m_el[1][0]), MT_abs(m_el[1][1]), MT_abs(m_el[1][2]), + MT_abs(m_el[2][0]), MT_abs(m_el[2][1]), MT_abs(m_el[2][2])); +} + +GEN_INLINE MT_Matrix3x3 MT_Matrix3x3::transposed() const { + return MT_Matrix3x3(m_el[0][0], m_el[1][0], m_el[2][0], + m_el[0][1], m_el[1][1], m_el[2][1], + m_el[0][2], m_el[1][2], m_el[2][2]); +} + +GEN_INLINE void MT_Matrix3x3::transpose() { + *this = transposed(); +} + +GEN_INLINE MT_Matrix3x3 MT_Matrix3x3::adjoint() const { + return + MT_Matrix3x3(cofac(1, 1, 2, 2), cofac(0, 2, 2, 1), cofac(0, 1, 1, 2), + cofac(1, 2, 2, 0), cofac(0, 0, 2, 2), cofac(0, 2, 1, 0), + cofac(1, 0, 2, 1), cofac(0, 1, 2, 0), cofac(0, 0, 1, 1)); +} + +GEN_INLINE MT_Matrix3x3 MT_Matrix3x3::inverse() const { + MT_Vector3 co(cofac(1, 1, 2, 2), cofac(1, 2, 2, 0), cofac(1, 0, 2, 1)); + MT_Scalar det = MT_dot((*this)[0], co); + MT_assert(!MT_fuzzyZero2(det)); + MT_Scalar s = MT_Scalar(1.0) / det; + return + MT_Matrix3x3(co[0] * s, cofac(0, 2, 2, 1) * s, cofac(0, 1, 1, 2) * s, + co[1] * s, cofac(0, 0, 2, 2) * s, cofac(0, 2, 1, 0) * s, + co[2] * s, cofac(0, 1, 2, 0) * s, cofac(0, 0, 1, 1) * s); +} + +GEN_INLINE void MT_Matrix3x3::invert() { + *this = inverse(); +} + +GEN_INLINE MT_Vector3 operator*(const MT_Matrix3x3& m, const MT_Vector3& v) { + return MT_Vector3(MT_dot(m[0], v), MT_dot(m[1], v), MT_dot(m[2], v)); +} + +GEN_INLINE MT_Vector3 operator*(const MT_Vector3& v, const MT_Matrix3x3& m) { + return MT_Vector3(m.tdot(0, v), m.tdot(1, v), m.tdot(2, v)); +} + +GEN_INLINE MT_Matrix3x3 operator*(const MT_Matrix3x3& m1, const MT_Matrix3x3& m2) { + return + MT_Matrix3x3(m2.tdot(0, m1[0]), m2.tdot(1, m1[0]), m2.tdot(2, m1[0]), + m2.tdot(0, m1[1]), m2.tdot(1, m1[1]), m2.tdot(2, m1[1]), + m2.tdot(0, m1[2]), m2.tdot(1, m1[2]), m2.tdot(2, m1[2])); +} + +GEN_INLINE MT_Matrix3x3 MT_multTransposeLeft(const MT_Matrix3x3& m1, const MT_Matrix3x3& m2) { + return MT_Matrix3x3( + m1[0][0] * m2[0][0] + m1[1][0] * m2[1][0] + m1[2][0] * m2[2][0], + m1[0][0] * m2[0][1] + m1[1][0] * m2[1][1] + m1[2][0] * m2[2][1], + m1[0][0] * m2[0][2] + m1[1][0] * m2[1][2] + m1[2][0] * m2[2][2], + m1[0][1] * m2[0][0] + m1[1][1] * m2[1][0] + m1[2][1] * m2[2][0], + m1[0][1] * m2[0][1] + m1[1][1] * m2[1][1] + m1[2][1] * m2[2][1], + m1[0][1] * m2[0][2] + m1[1][1] * m2[1][2] + m1[2][1] * m2[2][2], + m1[0][2] * m2[0][0] + m1[1][2] * m2[1][0] + m1[2][2] * m2[2][0], + m1[0][2] * m2[0][1] + m1[1][2] * m2[1][1] + m1[2][2] * m2[2][1], + m1[0][2] * m2[0][2] + m1[1][2] * m2[1][2] + m1[2][2] * m2[2][2]); +} + +GEN_INLINE MT_Matrix3x3 MT_multTransposeRight(const MT_Matrix3x3& m1, const MT_Matrix3x3& m2) { + return + MT_Matrix3x3(m1[0].dot(m2[0]), m1[0].dot(m2[1]), m1[0].dot(m2[2]), + m1[1].dot(m2[0]), m1[1].dot(m2[1]), m1[1].dot(m2[2]), + m1[2].dot(m2[0]), m1[2].dot(m2[1]), m1[2].dot(m2[2])); + +} diff --git a/intern/moto/include/MT_Matrix4x4.h b/intern/moto/include/MT_Matrix4x4.h new file mode 100644 index 00000000000..fc930055524 --- /dev/null +++ b/intern/moto/include/MT_Matrix4x4.h @@ -0,0 +1,251 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * A 4x4 matrix compatible with other stuff. + */ + +#ifndef MT_MATRIX4X4_H +#define MT_MATRIX4X4_H + +#include + +#include "MT_Vector4.h" +#include "MT_Transform.h" + +// Row-major 4x4 matrix + +class MT_Matrix4x4 { +public: + /** + * Empty contructor. + */ + MT_Matrix4x4() {} + /** + * Initialize all fields with the values pointed at by m. A + * contigous block of 16 values is read. */ + MT_Matrix4x4(const float *m) { setValue(m); } + /** + * Initialize all fields with the values pointed at by m. A + * contigous block of 16 values is read. */ + MT_Matrix4x4(const double *m) { setValue(m); } + + /** + * Initialise with these 16 explicit values. + */ + MT_Matrix4x4(MT_Scalar xx, MT_Scalar xy, MT_Scalar xz, MT_Scalar xw, + MT_Scalar yx, MT_Scalar yy, MT_Scalar yz, MT_Scalar yw, + MT_Scalar zx, MT_Scalar zy, MT_Scalar zz, MT_Scalar zw, + MT_Scalar wx, MT_Scalar wy, MT_Scalar wz, MT_Scalar ww) { + setValue(xx, xy, xz, xw, + yx, yy, yz, yw, + zx, zy, zz, zw, + wx, wy, wz, ww); + } + + /** + * Initialize from an MT_Transform. + */ + MT_Matrix4x4(const MT_Transform &t) { + + const MT_Matrix3x3 &basis = t.getBasis(); + const MT_Vector3 &origin = t.getOrigin(); + + setValue( + basis[0][0],basis[0][1],basis[0][2],origin[0], + basis[1][0],basis[1][1],basis[1][2],origin[1], + basis[2][0],basis[2][1],basis[2][2],origin[2], + MT_Scalar(0),MT_Scalar(0),MT_Scalar(0),MT_Scalar(1) + ); + } + + /** + * Get the i-th row. + */ + MT_Vector4& operator[](int i) { return m_el[i]; } + /** + * Get the i-th row. + */ + const MT_Vector4& operator[](int i) const { return m_el[i]; } + + /** + * Set the matrix to the values pointer at by m. A contiguous + * block of 16 values is copied. */ + void setValue(const float *m) { + m_el[0][0] = *m++; m_el[1][0] = *m++; m_el[2][0] = *m++; m_el[3][0] = *m++; + m_el[0][1] = *m++; m_el[1][1] = *m++; m_el[2][1] = *m++; m_el[3][1] = *m++; + m_el[0][2] = *m++; m_el[1][2] = *m++; m_el[2][2] = *m++; m_el[3][2] = *m++; + m_el[0][3] = *m++; m_el[1][3] = *m++; m_el[2][3] = *m++; m_el[3][3] = *m; + } + + /** + * Set the matrix to the values pointer at by m. A contiguous + * block of 16 values is copied. + */ + void setValue(const double *m) { + m_el[0][0] = *m++; m_el[1][0] = *m++; m_el[2][0] = *m++; m_el[3][0] = *m++; + m_el[0][1] = *m++; m_el[1][1] = *m++; m_el[2][1] = *m++; m_el[3][1] = *m++; + m_el[0][2] = *m++; m_el[1][2] = *m++; m_el[2][2] = *m++; m_el[3][2] = *m++; + m_el[0][3] = *m++; m_el[1][3] = *m++; m_el[2][3] = *m++; m_el[3][3] = *m; + } + + /** + * Set the matrix to these 16 explicit values. + */ + void setValue(MT_Scalar xx, MT_Scalar xy, MT_Scalar xz, MT_Scalar xw, + MT_Scalar yx, MT_Scalar yy, MT_Scalar yz, MT_Scalar yw, + MT_Scalar zx, MT_Scalar zy, MT_Scalar zz, MT_Scalar zw, + MT_Scalar wx, MT_Scalar wy, MT_Scalar wz, MT_Scalar ww) { + m_el[0][0] = xx; m_el[0][1] = xy; m_el[0][2] = xz; m_el[0][3] = xw; + m_el[1][0] = yx; m_el[1][1] = yy; m_el[1][2] = yz; m_el[1][3] = yw; + m_el[2][0] = zx; m_el[2][1] = zy; m_el[2][2] = zz; m_el[2][3] = zw; + m_el[3][0] = wx; m_el[3][1] = wy; m_el[3][2] = wz; m_el[3][3] = ww; + } + + /** + * Scale the columns of this matrix with x, y, z, w respectively. + */ + void scale(MT_Scalar x, MT_Scalar y, MT_Scalar z, MT_Scalar w) { + m_el[0][0] *= x; m_el[0][1] *= y; m_el[0][2] *= z; m_el[0][3] *= w; + m_el[1][0] *= x; m_el[1][1] *= y; m_el[1][2] *= z; m_el[1][3] *= w; + m_el[2][0] *= x; m_el[2][1] *= y; m_el[2][2] *= z; m_el[2][3] *= w; + m_el[3][0] *= x; m_el[3][1] *= y; m_el[3][2] *= z; m_el[3][3] *= w; + } + + /** + * Return a column-scaled version of this matrix. + */ + MT_Matrix4x4 scaled(MT_Scalar x, MT_Scalar y, MT_Scalar z, MT_Scalar w) const { + return MT_Matrix4x4(m_el[0][0] * x, m_el[0][1] * y, m_el[0][2] * z, m_el[0][3] * w, + m_el[1][0] * x, m_el[1][1] * y, m_el[1][2] * z, m_el[1][3] * w, + m_el[2][0] * x, m_el[2][1] * y, m_el[2][2] * z, m_el[2][3] * w, + m_el[3][0] * x, m_el[3][1] * y, m_el[3][2] * z, m_el[3][3] * w); + } + + /** + * Set this matrix to I. + */ + void setIdentity() { + setValue(MT_Scalar(1.0), MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0), + MT_Scalar(0.0), MT_Scalar(1.0), MT_Scalar(0.0), MT_Scalar(0.0), + MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(1.0), MT_Scalar(0.0), + MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(1.0)); + } + + /** + * Read the element from row i, column j. + */ + float getElement(int i, int j) { + return (float) m_el[i][j]; + } + + /** + * Copy the contents to a contiguous block of 16 floats. + */ + void getValue(float *m) const { + *m++ = (float) m_el[0][0]; *m++ = (float) m_el[1][0]; *m++ = (float) m_el[2][0]; *m++ = (float) m_el[3][0]; + *m++ = (float) m_el[0][1]; *m++ = (float) m_el[1][1]; *m++ = (float) m_el[2][1]; *m++ = (float) m_el[3][1]; + *m++ = (float) m_el[0][2]; *m++ = (float) m_el[1][2]; *m++ = (float) m_el[2][2]; *m++ = (float) m_el[3][2]; + *m++ = (float) m_el[0][3]; *m++ = (float) m_el[1][3]; *m++ = (float) m_el[2][3]; *m = (float) m_el[3][3]; + } + + /** + * Copy the contents to a contiguous block of 16 doubles. + */ + void getValue(double *m) const { + *m++ = m_el[0][0]; *m++ = m_el[1][0]; *m++ = m_el[2][0]; *m++ = m_el[3][0]; + *m++ = m_el[0][1]; *m++ = m_el[1][1]; *m++ = m_el[2][1]; *m++ = m_el[3][1]; + *m++ = m_el[0][2]; *m++ = m_el[1][2]; *m++ = m_el[2][2]; *m++ = m_el[3][2]; + *m++ = m_el[0][3]; *m++ = m_el[1][3]; *m++ = m_el[2][3]; *m = m_el[3][3]; + } + + /** + * Left-multiply this matrix with the argument. + */ + MT_Matrix4x4& operator*=(const MT_Matrix4x4& m); + + /** + * Left-multiply column c with row vector c. + */ + MT_Scalar tdot(int c, const MT_Vector4& v) const { + return m_el[0][c] * v[0] + + m_el[1][c] * v[1] + + m_el[2][c] * v[2] + + m_el[3][c] * v[3]; + } + + /* I'll postpone this for now... - nzc*/ +/* MT_Scalar determinant() const; */ +/* MT_Matrix4x4 adjoint() const; */ +/* MT_Matrix4x4 inverse() const; */ + + MT_Matrix4x4 absolute() const; + + MT_Matrix4x4 transposed() const; + void transpose(); + + void invert(); + +protected: + /** + * Access with [row index][column index] + */ + MT_Vector4 m_el[4]; +}; + +/* These multiplicators do exactly what you ask from them: they + * multiply in the indicated order. */ +MT_Vector4 operator*(const MT_Matrix4x4& m, const MT_Vector4& v); +MT_Vector4 operator*(const MT_Vector4& v, const MT_Matrix4x4& m); +MT_Matrix4x4 operator*(const MT_Matrix4x4& m1, const MT_Matrix4x4& m2); + +/* MT_Matrix4x4 MT_multTransposeLeft(const MT_Matrix4x4& m1, const MT_Matrix4x4& m2); */ +/* MT_Matrix4x4 MT_multTransposeRight(const MT_Matrix4x4& m1, const MT_Matrix4x4& m2); */ + +inline MT_OStream& operator<<(MT_OStream& os, const MT_Matrix4x4& m) { + return os << m[0] << GEN_endl + << m[1] << GEN_endl + << m[2] << GEN_endl + << m[3] << GEN_endl; + + + +} + +#ifdef GEN_INLINED +#include "MT_Matrix4x4.inl" +#endif + +#endif + diff --git a/intern/moto/include/MT_Matrix4x4.inl b/intern/moto/include/MT_Matrix4x4.inl new file mode 100644 index 00000000000..a2aa893a6b3 --- /dev/null +++ b/intern/moto/include/MT_Matrix4x4.inl @@ -0,0 +1,108 @@ +#include "MT_Optimize.h" + +/* + * This is a supposedly faster inverter than the cofactor + * computation. It uses an LU decomposition sort of thing. */ +GEN_INLINE void MT_Matrix4x4::invert() { + /* normalize row 0 */ + + int i,j,k; + + for (i=1; i < 4; i++) m_el[0][i] /= m_el[0][0]; + for (i=1; i < 4; i++) { + for (j=i; j < 4; j++) { // do a column of L + MT_Scalar sum = 0.0; + for (k = 0; k < i; k++) + sum += m_el[j][k] * m_el[k][i]; + m_el[j][i] -= sum; + } + if (i == 3) continue; + for (j=i+1; j < 4; j++) { // do a row of U + MT_Scalar sum = 0.0; + for (k = 0; k < i; k++) + sum += m_el[i][k]*m_el[k][j]; + m_el[i][j] = + (m_el[i][j]-sum) / m_el[i][i]; + } + } + for (i = 0; i < 4; i++ ) // invert L + for (j = i; j < 4; j++ ) { + MT_Scalar x = 1.0; + if ( i != j ) { + x = 0.0; + for (k = i; k < j; k++ ) + x -= m_el[j][k]*m_el[k][i]; + } + m_el[j][i] = x / m_el[j][j]; + } + for (i = 0; i < 4; i++ ) // invert U + for (j = i; j < 4; j++ ) { + if ( i == j ) continue; + MT_Scalar sum = 0.0; + for (k = i; k < j; k++ ) + sum += m_el[k][j]*( (i==k) ? 1.0 : m_el[i][k] ); + m_el[i][j] = -sum; + } + for (i = 0; i < 4; i++ ) // final inversion + for (j = 0; j < 4; j++ ) { + MT_Scalar sum = 0.0; + for (k = ((i>j)?i:j); k < 4; k++ ) + sum += ((j==k)?1.0:m_el[j][k])*m_el[k][i]; + m_el[j][i] = sum; + } +} + +/* We do things slightly different here, because the invert() modifies + * the buffer itself. This makes it impossible to make this op right + * away. Like other, still missing facilities, I will repair this + * later. */ +/* GEN_INLINE T_Matrix4x4 MT_Matrix4x4::inverse() const */ +/* { */ +/* } */ + + +GEN_INLINE MT_Matrix4x4& MT_Matrix4x4::operator*=(const MT_Matrix4x4& m) +{ + setValue(m.tdot(0, m_el[0]), m.tdot(1, m_el[0]), m.tdot(2, m_el[0]), m.tdot(3, m_el[0]), + m.tdot(0, m_el[1]), m.tdot(1, m_el[1]), m.tdot(2, m_el[1]), m.tdot(3, m_el[1]), + m.tdot(0, m_el[2]), m.tdot(1, m_el[2]), m.tdot(2, m_el[2]), m.tdot(3, m_el[2]), + m.tdot(0, m_el[3]), m.tdot(1, m_el[3]), m.tdot(2, m_el[3]), m.tdot(3, m_el[3])); + return *this; + +} + +GEN_INLINE MT_Vector4 operator*(const MT_Matrix4x4& m, const MT_Vector4& v) { + return MT_Vector4(MT_dot(m[0], v), MT_dot(m[1], v), MT_dot(m[2], v), MT_dot(m[3], v)); +} + +GEN_INLINE MT_Vector4 operator*(const MT_Vector4& v, const MT_Matrix4x4& m) { + return MT_Vector4(m.tdot(0, v), m.tdot(1, v), m.tdot(2, v), m.tdot(3, v)); +} + +GEN_INLINE MT_Matrix4x4 operator*(const MT_Matrix4x4& m1, const MT_Matrix4x4& m2) { + return + MT_Matrix4x4(m2.tdot(0, m1[0]), m2.tdot(1, m1[0]), m2.tdot(2, m1[0]), m2.tdot(3, m1[0]), + m2.tdot(0, m1[1]), m2.tdot(1, m1[1]), m2.tdot(2, m1[1]), m2.tdot(3, m1[1]), + m2.tdot(0, m1[2]), m2.tdot(1, m1[2]), m2.tdot(2, m1[2]), m2.tdot(3, m1[2]), + m2.tdot(0, m1[3]), m2.tdot(1, m1[3]), m2.tdot(2, m1[3]), m2.tdot(3, m1[3])); +} + + +GEN_INLINE MT_Matrix4x4 MT_Matrix4x4::transposed() const { + return MT_Matrix4x4(m_el[0][0], m_el[1][0], m_el[2][0], m_el[3][0], + m_el[0][1], m_el[1][1], m_el[2][1], m_el[3][1], + m_el[0][2], m_el[1][2], m_el[2][2], m_el[3][2], + m_el[0][3], m_el[1][3], m_el[2][3], m_el[3][3]); +} + +GEN_INLINE void MT_Matrix4x4::transpose() { + *this = transposed(); +} + +GEN_INLINE MT_Matrix4x4 MT_Matrix4x4::absolute() const { + return + MT_Matrix4x4(MT_abs(m_el[0][0]), MT_abs(m_el[0][1]), MT_abs(m_el[0][2]), MT_abs(m_el[0][3]), + MT_abs(m_el[1][0]), MT_abs(m_el[1][1]), MT_abs(m_el[1][2]), MT_abs(m_el[1][3]), + MT_abs(m_el[2][0]), MT_abs(m_el[2][1]), MT_abs(m_el[2][2]), MT_abs(m_el[2][3]), + MT_abs(m_el[3][0]), MT_abs(m_el[3][1]), MT_abs(m_el[3][2]), MT_abs(m_el[3][3])); +} diff --git a/intern/moto/include/MT_MinMax.h b/intern/moto/include/MT_MinMax.h new file mode 100644 index 00000000000..06f8a8d18c8 --- /dev/null +++ b/intern/moto/include/MT_MinMax.h @@ -0,0 +1,70 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * Copyright (c) 2000 Gino van den Bergen + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Gino van den Bergen makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef MT_MINMAX_H +#define MT_MINMAX_H + +template +inline const T& MT_min(const T& a, const T& b) { + return b < a ? b : a; +} + +template +inline const T& MT_max(const T& a, const T& b) { + return a < b ? b : a; +} + +template +inline void MT_set_min(T& a, const T& b) { + if (a > b) a = b; +} + +template +inline void MT_set_max(T& a, const T& b) { + if (a < b) a = b; +} + +#endif + diff --git a/intern/moto/include/MT_Optimize.h b/intern/moto/include/MT_Optimize.h new file mode 100644 index 00000000000..c09a9431a34 --- /dev/null +++ b/intern/moto/include/MT_Optimize.h @@ -0,0 +1,42 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef GEN_OPTIMIZE_H +#define GEN_OPTIMIZE_H + +#ifdef GEN_INLINED +#define GEN_INLINE inline +#else +#define GEN_INLINE +#endif + +#endif + diff --git a/intern/moto/include/MT_Plane3.h b/intern/moto/include/MT_Plane3.h new file mode 100644 index 00000000000..5caf1c4c36e --- /dev/null +++ b/intern/moto/include/MT_Plane3.h @@ -0,0 +1,136 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef MT_PLANE3 +#define MT_PLANE3 + +#include "MT_Tuple4.h" +#include "MT_Point3.h" + +/** + * A simple 3d plane class. + * + * This class represents a plane in 3d. The internal parameterization used + * is n.x + d =0 where n is a unit vector and d is a scalar. + * + * It inherits data from MT_Tuple4 please see this class for low level + * access to the internal representation. + * + */ + +class MT_Plane3 : public MT_Tuple4 +{ +public : + /** + * Constructor from 3 points + */ + + MT_Plane3( + const MT_Vector3 &a, + const MT_Vector3 &b, + const MT_Vector3 &c + ); + /** + * Construction from vector and a point. + */ + + MT_Plane3( + const MT_Vector3 &n, + const MT_Vector3 &p + ); + + /** + * Default constructor + */ + MT_Plane3( + ); + + /** + * Default constructor + */ + + MT_Plane3( + const MT_Plane3 & p + ): + MT_Tuple4(p) + { + } + + /** + * Return plane normal + */ + + MT_Vector3 + Normal( + ) const; + + /** + * Return plane scalar i.e the d from n.x + d = 0 + */ + + MT_Scalar + Scalar( + ) const ; + + /** + * Invert the plane - just swaps direction of normal. + */ + void + Invert( + ); + + /** + * Assignment operator + */ + + MT_Plane3 & + operator = ( + const MT_Plane3 & rhs + ); + + /** + * Return the signed perpendicular distance from a point to the plane + */ + + MT_Scalar + signedDistance( + const MT_Vector3 & + ) const; + + +}; + +#ifdef GEN_INLINED +#include "MT_Plane3.inl" +#endif + +#endif + diff --git a/intern/moto/include/MT_Plane3.inl b/intern/moto/include/MT_Plane3.inl new file mode 100644 index 00000000000..77db9b35e1d --- /dev/null +++ b/intern/moto/include/MT_Plane3.inl @@ -0,0 +1,128 @@ +#include "MT_Optimize.h" + + +GEN_INLINE +MT_Plane3:: +MT_Plane3( + const MT_Vector3 &a, + const MT_Vector3 &b, + const MT_Vector3 &c +){ + MT_Vector3 l1 = b-a; + MT_Vector3 l2 = c-b; + + MT_Vector3 n = l1.cross(l2); + n = n.safe_normalized(); + MT_Scalar d = n.dot(a); + + m_co[0] = n.x(); + m_co[1] = n.y(); + m_co[2] = n.z(); + m_co[3] = -d; +} + +/** + * Construction from vector and a point. + */ +GEN_INLINE +MT_Plane3:: +MT_Plane3( + const MT_Vector3 &n, + const MT_Vector3 &p +){ + + MT_Vector3 mn = n.safe_normalized(); + MT_Scalar md = mn.dot(p); + + m_co[0] = mn.x(); + m_co[1] = mn.y(); + m_co[2] = mn.z(); + m_co[3] = -md; +} + + +/** + * Default constructor + */ +GEN_INLINE +MT_Plane3:: +MT_Plane3( +): + MT_Tuple4() +{ + m_co[0] = MT_Scalar(1); + m_co[1] = MT_Scalar(0); + m_co[2] = MT_Scalar(0); + m_co[3] = MT_Scalar(0); +} + +/** + * Return plane normal + */ + +GEN_INLINE + MT_Vector3 +MT_Plane3:: +Normal( +) const { + return MT_Vector3(m_co[0],m_co[1],m_co[2]); +} + +/** + * Return plane scalar i.e the d from n.x + d = 0 + */ + +GEN_INLINE + MT_Scalar +MT_Plane3:: +Scalar( +) const { + return m_co[3]; +} + +GEN_INLINE + void +MT_Plane3:: +Invert( +) { + m_co[0] = -m_co[0]; + m_co[1] = -m_co[1]; + m_co[2] = -m_co[2]; + m_co[3] = -m_co[3]; +} + + +/** + * Assignment operator + */ + +GEN_INLINE + MT_Plane3 & +MT_Plane3:: +operator = ( + const MT_Plane3 & rhs +) { + m_co[0] = rhs.m_co[0]; + m_co[1] = rhs.m_co[1]; + m_co[2] = rhs.m_co[2]; + m_co[3] = rhs.m_co[3]; + return *this; +} + +/** + * Return the distance from a point to the plane + */ + +GEN_INLINE + MT_Scalar +MT_Plane3:: +signedDistance( + const MT_Vector3 &v +) const { + return Normal().dot(v) + m_co[3]; +} + + + + + diff --git a/intern/moto/include/MT_Point2.h b/intern/moto/include/MT_Point2.h new file mode 100644 index 00000000000..cc6819039fc --- /dev/null +++ b/intern/moto/include/MT_Point2.h @@ -0,0 +1,82 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * Copyright (c) 2000 Gino van den Bergen + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Gino van den Bergen makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef MT_POINT2_H +#define MT_POINT2_H + +#include "MT_Vector2.h" + +class MT_Point2 : public MT_Vector2 { +public: + MT_Point2() {} + MT_Point2(const float *v2) : MT_Vector2(v2) {} + MT_Point2(const double *v2) : MT_Vector2(v2) {} + MT_Point2(MT_Scalar x2, MT_Scalar y2) : MT_Vector2(x2, y2) {} + + MT_Point2& operator+=(const MT_Vector2& v); + MT_Point2& operator-=(const MT_Vector2& v); + MT_Point2& operator=(const MT_Vector2& v); + + MT_Scalar distance(const MT_Point2& p) const; + MT_Scalar distance2(const MT_Point2& p) const; + + MT_Point2 lerp(const MT_Point2& p, MT_Scalar t) const; +}; + +MT_Point2 operator+(const MT_Point2& p, const MT_Vector2& v); +MT_Point2 operator-(const MT_Point2& p, const MT_Vector2& v); +MT_Vector2 operator-(const MT_Point2& p1, const MT_Point2& p2); + +MT_Scalar MT_distance(const MT_Point2& p1, const MT_Point2& p2); +MT_Scalar MT_distance2(const MT_Point2& p1, const MT_Point2& p2); + +MT_Point2 MT_lerp(const MT_Point2& p1, const MT_Point2& p2, MT_Scalar t); + +#ifdef GEN_INLINED +#include "MT_Point2.inl" +#endif + +#endif + diff --git a/intern/moto/include/MT_Point2.inl b/intern/moto/include/MT_Point2.inl new file mode 100644 index 00000000000..ec09a3260e2 --- /dev/null +++ b/intern/moto/include/MT_Point2.inl @@ -0,0 +1,54 @@ +#include "MT_Optimize.h" + +GEN_INLINE MT_Point2& MT_Point2::operator+=(const MT_Vector2& v) { + m_co[0] += v[0]; m_co[1] += v[1]; + return *this; +} + +GEN_INLINE MT_Point2& MT_Point2::operator-=(const MT_Vector2& v) { + m_co[0] -= v[0]; m_co[1] -= v[1]; + return *this; +} + +GEN_INLINE MT_Point2& MT_Point2::operator=(const MT_Vector2& v) { + m_co[0] = v[0]; m_co[1] = v[1]; + return *this; +} + +GEN_INLINE MT_Scalar MT_Point2::distance(const MT_Point2& p) const { + return (p - *this).length(); +} + +GEN_INLINE MT_Scalar MT_Point2::distance2(const MT_Point2& p) const { + return (p - *this).length2(); +} + +GEN_INLINE MT_Point2 MT_Point2::lerp(const MT_Point2& p, MT_Scalar t) const { + return MT_Point2(m_co[0] + (p[0] - m_co[0]) * t, + m_co[1] + (p[1] - m_co[1]) * t); +} + +GEN_INLINE MT_Point2 operator+(const MT_Point2& p, const MT_Vector2& v) { + return MT_Point2(p[0] + v[0], p[1] + v[1]); +} + +GEN_INLINE MT_Point2 operator-(const MT_Point2& p, const MT_Vector2& v) { + return MT_Point2(p[0] - v[0], p[1] - v[1]); +} + +GEN_INLINE MT_Vector2 operator-(const MT_Point2& p1, const MT_Point2& p2) { + return MT_Vector2(p1[0] - p2[0], p1[1] - p2[1]); +} + +GEN_INLINE MT_Scalar MT_distance(const MT_Point2& p1, const MT_Point2& p2) { + return p1.distance(p2); +} + +GEN_INLINE MT_Scalar MT_distance2(const MT_Point2& p1, const MT_Point2& p2) { + return p1.distance2(p2); +} + +GEN_INLINE MT_Point2 MT_lerp(const MT_Point2& p1, const MT_Point2& p2, MT_Scalar t) { + return p1.lerp(p2, t); +} + diff --git a/intern/moto/include/MT_Point3.h b/intern/moto/include/MT_Point3.h new file mode 100644 index 00000000000..372718af312 --- /dev/null +++ b/intern/moto/include/MT_Point3.h @@ -0,0 +1,83 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * Copyright (c) 2000 Gino van den Bergen + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Gino van den Bergen makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef MT_POINT_H +#define MT_POINT_H + +#include "MT_Vector3.h" + +class MT_Point3 : public MT_Vector3 { +public: + MT_Point3() {} + MT_Point3(const float *v) : MT_Vector3(v) {} + MT_Point3(const double *v) : MT_Vector3(v) {} + MT_Point3(MT_Scalar xx, MT_Scalar yy, MT_Scalar zz) : MT_Vector3(xx, yy, zz) {} + + MT_Point3& operator+=(const MT_Vector3& v); + MT_Point3& operator-=(const MT_Vector3& v); + MT_Point3& operator=(const MT_Vector3& v); + MT_Point3& operator=(const MT_Point3& v); + + MT_Scalar distance(const MT_Point3& p) const; + MT_Scalar distance2(const MT_Point3& p) const; + + MT_Point3 lerp(const MT_Point3& p, MT_Scalar t) const; +}; + +MT_Point3 operator+(const MT_Point3& p, const MT_Vector3& v); +MT_Point3 operator-(const MT_Point3& p, const MT_Vector3& v); +MT_Vector3 operator-(const MT_Point3& p1, const MT_Point3& p2); + +MT_Scalar MT_distance(const MT_Point3& p1, const MT_Point3& p2); +MT_Scalar MT_distance2(const MT_Point3& p1, const MT_Point3& p2); + +MT_Point3 MT_lerp(const MT_Point3& p1, const MT_Point3& p2, MT_Scalar t); + +#ifdef GEN_INLINED +#include "MT_Point3.inl" +#endif + +#endif + diff --git a/intern/moto/include/MT_Point3.inl b/intern/moto/include/MT_Point3.inl new file mode 100644 index 00000000000..081a8195694 --- /dev/null +++ b/intern/moto/include/MT_Point3.inl @@ -0,0 +1,59 @@ +#include "MT_Optimize.h" + +GEN_INLINE MT_Point3& MT_Point3::operator+=(const MT_Vector3& v) { + m_co[0] += v[0]; m_co[1] += v[1]; m_co[2] += v[2]; + return *this; +} + +GEN_INLINE MT_Point3& MT_Point3::operator-=(const MT_Vector3& v) { + m_co[0] -= v[0]; m_co[1] -= v[1]; m_co[2] -= v[2]; + return *this; +} + +GEN_INLINE MT_Point3& MT_Point3::operator=(const MT_Vector3& v) { + m_co[0] = v[0]; m_co[1] = v[1]; m_co[2] = v[2]; + return *this; +} + +GEN_INLINE MT_Point3& MT_Point3::operator=(const MT_Point3& v) { + m_co[0] = v[0]; m_co[1] = v[1]; m_co[2] = v[2]; + return *this; +} + +GEN_INLINE MT_Scalar MT_Point3::distance(const MT_Point3& p) const { + return (p - *this).length(); +} + +GEN_INLINE MT_Scalar MT_Point3::distance2(const MT_Point3& p) const { + return (p - *this).length2(); +} + +GEN_INLINE MT_Point3 MT_Point3::lerp(const MT_Point3& p, MT_Scalar t) const { + return MT_Point3(m_co[0] + (p[0] - m_co[0]) * t, + m_co[1] + (p[1] - m_co[1]) * t, + m_co[2] + (p[2] - m_co[2]) * t); +} + +GEN_INLINE MT_Point3 operator+(const MT_Point3& p, const MT_Vector3& v) { + return MT_Point3(p[0] + v[0], p[1] + v[1], p[2] + v[2]); +} + +GEN_INLINE MT_Point3 operator-(const MT_Point3& p, const MT_Vector3& v) { + return MT_Point3(p[0] - v[0], p[1] - v[1], p[2] - v[2]); +} + +GEN_INLINE MT_Vector3 operator-(const MT_Point3& p1, const MT_Point3& p2) { + return MT_Vector3(p1[0] - p2[0], p1[1] - p2[1], p1[2] - p2[2]); +} + +GEN_INLINE MT_Scalar MT_distance(const MT_Point3& p1, const MT_Point3& p2) { + return p1.distance(p2); +} + +GEN_INLINE MT_Scalar MT_distance2(const MT_Point3& p1, const MT_Point3& p2) { + return p1.distance2(p2); +} + +GEN_INLINE MT_Point3 MT_lerp(const MT_Point3& p1, const MT_Point3& p2, MT_Scalar t) { + return p1.lerp(p2, t); +} diff --git a/intern/moto/include/MT_Quaternion.h b/intern/moto/include/MT_Quaternion.h new file mode 100644 index 00000000000..98046292982 --- /dev/null +++ b/intern/moto/include/MT_Quaternion.h @@ -0,0 +1,113 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * Copyright (c) 2000 Gino van den Bergen + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Gino van den Bergen makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef MT_QUATERNION_H +#define MT_QUATERNION_H + +#include + +#include "MT_Vector3.h" +#include "MT_Vector4.h" + +class MT_Quaternion : public MT_Vector4 { +public: + MT_Quaternion() {} + MT_Quaternion(const MT_Vector4& v) : MT_Vector4(v) {} + MT_Quaternion(const float v[4]) : MT_Vector4(v) {} + MT_Quaternion(const double v[4]) : MT_Vector4(v) {} + MT_Quaternion(MT_Scalar xx, MT_Scalar yy, MT_Scalar zz, MT_Scalar ww) : + MT_Vector4(xx, yy, zz, ww) {} + MT_Quaternion(const MT_Vector3& axis, MT_Scalar mt_angle) { + setRotation(axis, mt_angle); + } + MT_Quaternion(MT_Scalar yaw, MT_Scalar pitch, MT_Scalar roll) { + setEuler(yaw, pitch, roll); + } + + void setRotation(const MT_Vector3& axis, MT_Scalar mt_angle) { + MT_Scalar d = axis.length(); + MT_assert(!MT_fuzzyZero(d)); + MT_Scalar s = sin(mt_angle * MT_Scalar(0.5)) / d; + setValue(axis[0] * s, axis[1] * s, axis[2] * s, + cos(mt_angle * MT_Scalar(0.5))); + } + + void setEuler(MT_Scalar yaw, MT_Scalar pitch, MT_Scalar roll) { + MT_Scalar cosYaw = cos(yaw * MT_Scalar(0.5)); + MT_Scalar sinYaw = sin(yaw * MT_Scalar(0.5)); + MT_Scalar cosPitch = cos(pitch * MT_Scalar(0.5)); + MT_Scalar sinPitch = sin(pitch * MT_Scalar(0.5)); + MT_Scalar cosRoll = cos(roll * MT_Scalar(0.5)); + MT_Scalar sinRoll = sin(roll * MT_Scalar(0.5)); + setValue(cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw, + cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw, + sinRoll * cosPitch * cosYaw - cosRoll * sinPitch * sinYaw, + cosRoll * cosPitch * cosYaw + sinRoll * sinPitch * sinYaw); + } + + MT_Quaternion& operator*=(const MT_Quaternion& q); + + void conjugate(); + MT_Quaternion conjugate() const; + + void invert(); + MT_Quaternion inverse() const; + + MT_Scalar angle(const MT_Quaternion& q) const; + MT_Quaternion slerp(const MT_Quaternion& q, const MT_Scalar& t) const; + + static MT_Quaternion random(); +}; + +MT_Quaternion operator*(const MT_Quaternion& q1, const MT_Quaternion& q2); +MT_Quaternion operator*(const MT_Quaternion& q, const MT_Vector3& w); +MT_Quaternion operator*(const MT_Vector3& w, const MT_Quaternion& q); + +#ifdef GEN_INLINED +#include "MT_Quaternion.inl" +#endif + +#endif + diff --git a/intern/moto/include/MT_Quaternion.inl b/intern/moto/include/MT_Quaternion.inl new file mode 100644 index 00000000000..ecfd6699f67 --- /dev/null +++ b/intern/moto/include/MT_Quaternion.inl @@ -0,0 +1,92 @@ +#include "MT_Optimize.h" + +GEN_INLINE MT_Quaternion& MT_Quaternion::operator*=(const MT_Quaternion& q) { + setValue(m_co[3] * q[0] + m_co[0] * q[3] + m_co[1] * q[2] - m_co[2] * q[1], + m_co[3] * q[1] + m_co[1] * q[3] + m_co[2] * q[0] - m_co[0] * q[2], + m_co[3] * q[2] + m_co[2] * q[3] + m_co[0] * q[1] - m_co[1] * q[0], + m_co[3] * q[3] - m_co[0] * q[0] - m_co[1] * q[1] - m_co[2] * q[2]); + return *this; +} + +GEN_INLINE void MT_Quaternion::conjugate() { + m_co[0] = -m_co[0]; m_co[1] = -m_co[1]; m_co[2] = -m_co[2]; +} + +GEN_INLINE MT_Quaternion MT_Quaternion::conjugate() const { + return MT_Quaternion(-m_co[0], -m_co[1], -m_co[2], m_co[3]); +} + +GEN_INLINE void MT_Quaternion::invert() { + conjugate(); + *this /= length2(); +} + +GEN_INLINE MT_Quaternion MT_Quaternion::inverse() const { + return conjugate() / length2(); +} + +// From: "Uniform Random Rotations", Ken Shoemake, Graphics Gems III, +// pg. 124-132 +GEN_INLINE MT_Quaternion MT_Quaternion::random() { + MT_Scalar x0 = MT_random(); + MT_Scalar r1 = sqrt(MT_Scalar(1.0) - x0), r2 = sqrt(x0); + MT_Scalar t1 = MT_2_PI * MT_random(), t2 = MT_2_PI * MT_random(); + MT_Scalar c1 = cos(t1), s1 = sin(t1); + MT_Scalar c2 = cos(t2), s2 = sin(t2); + return MT_Quaternion(s1 * r1, c1 * r1, s2 * r2, c2 * r2); +} + +GEN_INLINE MT_Quaternion operator*(const MT_Quaternion& q1, + const MT_Quaternion& q2) { + return MT_Quaternion(q1[3] * q2[0] + q1[0] * q2[3] + q1[1] * q2[2] - q1[2] * q2[1], + q1[3] * q2[1] + q1[1] * q2[3] + q1[2] * q2[0] - q1[0] * q2[2], + q1[3] * q2[2] + q1[2] * q2[3] + q1[0] * q2[1] - q1[1] * q2[0], + q1[3] * q2[3] - q1[0] * q2[0] - q1[1] * q2[1] - q1[2] * q2[2]); +} + +GEN_INLINE MT_Quaternion operator*(const MT_Quaternion& q, const MT_Vector3& w) +{ + return MT_Quaternion( q[3] * w[0] + q[1] * w[2] - q[2] * w[1], + q[3] * w[1] + q[2] * w[0] - q[0] * w[2], + q[3] * w[2] + q[0] * w[1] - q[1] * w[0], + -q[0] * w[0] - q[1] * w[1] - q[2] * w[2]); +} + +GEN_INLINE MT_Quaternion operator*(const MT_Vector3& w, const MT_Quaternion& q) +{ + return MT_Quaternion( w[0] * q[3] + w[1] * q[2] - w[2] * q[1], + w[1] * q[3] + w[2] * q[0] - w[0] * q[2], + w[2] * q[3] + w[0] * q[1] - w[1] * q[0], + -w[0] * q[0] - w[1] * q[1] - w[2] * q[2]); +} + +GEN_INLINE MT_Scalar MT_Quaternion::angle(const MT_Quaternion& q) const +{ + MT_Scalar s = sqrt(length2() * q.length2()); + assert(s != MT_Scalar(0.0)); + + s = dot(q) / s; + + s = MT_clamp(s, -1.0, 1.0); + + return acos(s); +} + +GEN_INLINE MT_Quaternion MT_Quaternion::slerp(const MT_Quaternion& q, const MT_Scalar& t) const +{ + MT_Scalar theta = angle(q); + + if (!MT_fuzzyZero(theta)) + { + MT_Scalar d = MT_Scalar(1.0) / sin(theta); + MT_Scalar s0 = sin((MT_Scalar(1.0) - t) * theta); + MT_Scalar s1 = sin(t * theta); + + return d*(*this * s0 + q * s1); + } + else + { + return *this; + } +} + diff --git a/intern/moto/include/MT_Scalar.h b/intern/moto/include/MT_Scalar.h new file mode 100644 index 00000000000..5cf9f76e592 --- /dev/null +++ b/intern/moto/include/MT_Scalar.h @@ -0,0 +1,96 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * Copyright (c) 2000 Gino van den Bergen + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Gino van den Bergen makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef MT_SCALAR_H +#define MT_SCALAR_H + +#include +#include + +#include "MT_random.h" +#include "NM_Scalar.h" + +typedef double MT_Scalar; //this should be float ! + + +const MT_Scalar MT_DEGS_PER_RAD(57.29577951308232286465); +const MT_Scalar MT_RADS_PER_DEG(0.01745329251994329547); +const MT_Scalar MT_PI(3.14159265358979323846); +const MT_Scalar MT_2_PI(6.28318530717958623200); +const MT_Scalar MT_EPSILON(1.0e-10); +const MT_Scalar MT_EPSILON2(1.0e-20); +const MT_Scalar MT_INFINITY(1.0e50); + +inline int MT_sign(MT_Scalar x) { + return x < 0.0 ? -1 : x > 0.0 ? 1 : 0; +} + +inline MT_Scalar MT_abs(MT_Scalar x) { return fabs(x); } + +inline bool MT_fuzzyZero(MT_Scalar x) { return MT_abs(x) < MT_EPSILON; } +inline bool MT_fuzzyZero2(MT_Scalar x) { return MT_abs(x) < MT_EPSILON2; } + +inline MT_Scalar MT_radians(MT_Scalar x) { + return x * MT_RADS_PER_DEG; +} + +inline MT_Scalar MT_degrees(MT_Scalar x) { + return x * MT_DEGS_PER_RAD; +} + +inline MT_Scalar MT_random() { + return MT_Scalar(MT_rand()) / MT_Scalar(MT_RAND_MAX); +} + +inline MT_Scalar MT_clamp(const MT_Scalar x, const MT_Scalar min, const MT_Scalar max) +{ + if (x < min) + return min; + else if (x > max) + return max; + return x; +} +#endif + diff --git a/intern/moto/include/MT_Stream.h b/intern/moto/include/MT_Stream.h new file mode 100644 index 00000000000..49378eceb18 --- /dev/null +++ b/intern/moto/include/MT_Stream.h @@ -0,0 +1,58 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef GEN_STREAM_H +#define GEN_STREAM_H + +#ifdef __CUSTOM_STREAM + +class MT_OStream +{ +public: + inline MT_OStream& operator<<(double); + inline MT_OStream& operator<<(int); + inline MT_OStream& operator<<(char*); +}; + +const char GEN_endl = '\n'; + +#else + +#include + +typedef std::ostream MT_OStream; + +inline MT_OStream& GEN_endl(MT_OStream& os) { return std::endl(os); } + +#endif + +#endif + diff --git a/intern/moto/include/MT_Transform.h b/intern/moto/include/MT_Transform.h new file mode 100644 index 00000000000..ee5ae29dc41 --- /dev/null +++ b/intern/moto/include/MT_Transform.h @@ -0,0 +1,189 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + MoTo - 3D Motion Toolkit + Copyright (C) 2000 Gino van den Bergen + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef MT_TRANSFORM_H +#define MT_TRANSFORM_H + +#include "MT_Point3.h" +#include "MT_Matrix3x3.h" + +class MT_Transform { +public: + MT_Transform() {} + MT_Transform(const float *m) { setValue(m); } + MT_Transform(const double *m) { setValue(m); } + MT_Transform(const MT_Point3& p, const MT_Quaternion& q) + : m_type(IDENTITY) + { + setOrigin(p); + setRotation(q); + } + + MT_Transform(const MT_Point3& p, const MT_Matrix3x3& m) + : m_type(IDENTITY) + { + setOrigin(p); + setBasis(m); + } + + static MT_Transform Identity() + { + MT_Transform t; + t.setIdentity(); + return t; + } + + + MT_Point3 operator()(const MT_Point3& p) const { + return MT_Point3(MT_dot(m_basis[0], p) + m_origin[0], + MT_dot(m_basis[1], p) + m_origin[1], + MT_dot(m_basis[2], p) + m_origin[2]); + } + + MT_Vector3 operator()(const MT_Vector3& p) const { + return MT_Vector3(MT_dot(m_basis[0], p) + m_origin[0], + MT_dot(m_basis[1], p) + m_origin[1], + MT_dot(m_basis[2], p) + m_origin[2]); + } + + MT_Point3 operator*(const MT_Point3& p) const { + return (*this)(p); + } + + MT_Vector3 operator*(const MT_Vector3& p) const { + return (*this)(p); + } + + + MT_Matrix3x3& getBasis() { return m_basis; } + const MT_Matrix3x3& getBasis() const { return m_basis; } + MT_Point3& getOrigin() { return m_origin; } + const MT_Point3& getOrigin() const { return m_origin; } + MT_Quaternion getRotation() const { return m_basis.getRotation(); } + + void setValue(const float *m); + void setValue(const double *m); + + void setOrigin(const MT_Point3& origin) { + m_origin = origin; + m_type |= TRANSLATION; + } + + void setBasis(const MT_Matrix3x3& basis) { + m_basis = basis; + m_type |= LINEAR; + } + + void setRotation(const MT_Quaternion& q) { + m_basis.setRotation(q); + m_type &= ~SCALING; + m_type |= ROTATION; + } + + void getValue(float *m) const; + void getValue(double *m) const; + + void setIdentity(); + + MT_Transform& operator*=(const MT_Transform& t); + + /** + * Translate the origin of the transform according to the vector. + * @param v The vector to translate over. The vector is specified + * in the coordinate system of the transform itself. + */ + void translate(const MT_Vector3& v); + void rotate(const MT_Quaternion& q); + void scale(MT_Scalar x, MT_Scalar y, MT_Scalar z); + + void invert(const MT_Transform& t); + void mult(const MT_Transform& t1, const MT_Transform& t2); + void multInverseLeft(const MT_Transform& t1, const MT_Transform& t2); + +private: + enum { + IDENTITY = 0x00, + TRANSLATION = 0x01, + ROTATION = 0x02, + RIGID = TRANSLATION | ROTATION, + SCALING = 0x04, + LINEAR = ROTATION | SCALING, + AFFINE = TRANSLATION | LINEAR + }; + + MT_Transform(const MT_Matrix3x3& basis, const MT_Point3& origin, + unsigned int type) { + setValue(basis, origin, type); + } + + void setValue(const MT_Matrix3x3& basis, const MT_Point3& origin, + unsigned int type) { + m_basis = basis; + m_origin = origin; + m_type = type; + } + + friend MT_Transform operator*(const MT_Transform& t1, const MT_Transform& t2); + + MT_Matrix3x3 m_basis; + MT_Point3 m_origin; + unsigned int m_type; +}; + +inline MT_Transform operator*(const MT_Transform& t1, const MT_Transform& t2) { + return MT_Transform(t1.m_basis * t2.m_basis, + t1(t2.m_origin), + t1.m_type | t2.m_type); +} + +#endif + diff --git a/intern/moto/include/MT_Tuple2.h b/intern/moto/include/MT_Tuple2.h new file mode 100644 index 00000000000..84280bec50a --- /dev/null +++ b/intern/moto/include/MT_Tuple2.h @@ -0,0 +1,110 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * Copyright (c) 2000 Gino van den Bergen + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Gino van den Bergen makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef MT_Tuple2_H +#define MT_Tuple2_H + +#include "MT_Stream.h" +#include "MT_Scalar.h" + +class MT_Tuple2 { +public: + MT_Tuple2() {} + MT_Tuple2(const float *vv) { setValue(vv); } + MT_Tuple2(const double *vv) { setValue(vv); } + MT_Tuple2(MT_Scalar xx, MT_Scalar yy) { setValue(xx, yy); } + + MT_Scalar& operator[](int i) { return m_co[i]; } + const MT_Scalar& operator[](int i) const { return m_co[i]; } + + MT_Scalar& x() { return m_co[0]; } + const MT_Scalar& x() const { return m_co[0]; } + + MT_Scalar& y() { return m_co[1]; } + const MT_Scalar& y() const { return m_co[1]; } + + MT_Scalar& u() { return m_co[0]; } + const MT_Scalar& u() const { return m_co[0]; } + + MT_Scalar& v() { return m_co[1]; } + const MT_Scalar& v() const { return m_co[1]; } + + MT_Scalar *getValue() { return m_co; } + const MT_Scalar *getValue() const { return m_co; } + + void getValue(float *vv) const { + vv[0] = (float) m_co[0]; vv[1] = (float) m_co[1]; + } + + void getValue(double *vv) const { + vv[0] = m_co[0]; vv[1] = m_co[1]; + } + + void setValue(const float *vv) { + m_co[0] = vv[0]; m_co[1] = vv[1]; + } + + void setValue(const double *vv) { + m_co[0] = vv[0]; m_co[1] = vv[1]; + } + + void setValue(MT_Scalar xx, MT_Scalar yy) { + m_co[0] = xx; m_co[1] = yy; + } + +protected: + MT_Scalar m_co[2]; +}; + +inline bool operator==(const MT_Tuple2& t1, const MT_Tuple2& t2) { + return t1[0] == t2[0] && t1[1] == t2[1]; +} + +inline MT_OStream& operator<<(MT_OStream& os, const MT_Tuple2& t) { + return os << t[0] << ' ' << t[1]; +} + +#endif + diff --git a/intern/moto/include/MT_Tuple3.h b/intern/moto/include/MT_Tuple3.h new file mode 100644 index 00000000000..271e323aab5 --- /dev/null +++ b/intern/moto/include/MT_Tuple3.h @@ -0,0 +1,115 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * Copyright (c) 2000 Gino van den Bergen + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Gino van den Bergen makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef MT_TUPLE3_H +#define MT_TUPLE3_H + +#include "MT_Stream.h" +#include "MT_Scalar.h" + +class MT_Tuple3 { +public: + MT_Tuple3() {} + MT_Tuple3(const float *v) { setValue(v); } + MT_Tuple3(const double *v) { setValue(v); } + MT_Tuple3(MT_Scalar xx, MT_Scalar yy, MT_Scalar zz) { setValue(xx, yy, zz); } + + MT_Scalar& operator[](int i) { return m_co[i]; } + const MT_Scalar& operator[](int i) const { return m_co[i]; } + + MT_Scalar& x() { return m_co[0]; } + const MT_Scalar& x() const { return m_co[0]; } + + MT_Scalar& y() { return m_co[1]; } + const MT_Scalar& y() const { return m_co[1]; } + + MT_Scalar& z() { return m_co[2]; } + const MT_Scalar& z() const { return m_co[2]; } + + MT_Scalar *getValue() { return m_co; } + const MT_Scalar *getValue() const { return m_co; } + + void getValue(float *v) const { + v[0] = float(m_co[0]); + v[1] = float(m_co[1]); + v[2] = float(m_co[2]); + } + + void getValue(double *v) const { + v[0] = double(m_co[0]); + v[1] = double(m_co[1]); + v[2] = double(m_co[2]); + } + + void setValue(const float *v) { + m_co[0] = MT_Scalar(v[0]); + m_co[1] = MT_Scalar(v[1]); + m_co[2] = MT_Scalar(v[2]); + } + + void setValue(const double *v) { + m_co[0] = MT_Scalar(v[0]); + m_co[1] = MT_Scalar(v[1]); + m_co[2] = MT_Scalar(v[2]); + } + + void setValue(MT_Scalar xx, MT_Scalar yy, MT_Scalar zz) { + m_co[0] = xx; m_co[1] = yy; m_co[2] = zz; + } + +protected: + MT_Scalar m_co[3]; +}; + +inline bool operator==(const MT_Tuple3& t1, const MT_Tuple3& t2) { + return t1[0] == t2[0] && t1[1] == t2[1] && t1[2] == t2[2]; +} + +inline MT_OStream& operator<<(MT_OStream& os, const MT_Tuple3& t) { + return os << t[0] << ' ' << t[1] << ' ' << t[2]; +} + +#endif + diff --git a/intern/moto/include/MT_Tuple4.h b/intern/moto/include/MT_Tuple4.h new file mode 100644 index 00000000000..9a484dbedde --- /dev/null +++ b/intern/moto/include/MT_Tuple4.h @@ -0,0 +1,125 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * Copyright (c) 2000 Gino van den Bergen + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Gino van den Bergen makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef MT_TUPLE4_H +#define MT_TUPLE4_H + +#include "MT_Stream.h" +#include "MT_Scalar.h" + +class MT_Tuple4 { +public: + MT_Tuple4() {} + MT_Tuple4(const float *v) { setValue(v); } + MT_Tuple4(const double *v) { setValue(v); } + MT_Tuple4(MT_Scalar xx, MT_Scalar yy, MT_Scalar zz, MT_Scalar ww) { + setValue(xx, yy, zz, ww); + } + + MT_Scalar& operator[](int i) { return m_co[i]; } + const MT_Scalar& operator[](int i) const { return m_co[i]; } + + MT_Scalar& x() { return m_co[0]; } + const MT_Scalar& x() const { return m_co[0]; } + + MT_Scalar& y() { return m_co[1]; } + const MT_Scalar& y() const { return m_co[1]; } + + MT_Scalar& z() { return m_co[2]; } + const MT_Scalar& z() const { return m_co[2]; } + + MT_Scalar& w() { return m_co[3]; } + const MT_Scalar& w() const { return m_co[3]; } + + MT_Scalar *getValue() { return m_co; } + const MT_Scalar *getValue() const { return m_co; } + + + void getValue(float *v) const { + v[0] = float(m_co[0]); + v[1] = float(m_co[1]); + v[2] = float(m_co[2]); + v[3] = float(m_co[3]); + } + + void getValue(double *v) const { + v[0] = double(m_co[0]); + v[1] = double(m_co[1]); + v[2] = double(m_co[2]); + v[3] = double(m_co[3]); + } + + void setValue(const float *v) { + m_co[0] = MT_Scalar(v[0]); + m_co[1] = MT_Scalar(v[1]); + m_co[2] = MT_Scalar(v[2]); + m_co[3] = MT_Scalar(v[3]); + } + + void setValue(const double *v) { + m_co[0] = MT_Scalar(v[0]); + m_co[1] = MT_Scalar(v[1]); + m_co[2] = MT_Scalar(v[2]); + m_co[3] = MT_Scalar(v[3]); + } + + void setValue(MT_Scalar xx, MT_Scalar yy, MT_Scalar zz, MT_Scalar ww) { + m_co[0] = xx; m_co[1] = yy; m_co[2] = zz; m_co[3] = ww; + } + +protected: + MT_Scalar m_co[4]; +}; + +inline bool operator==(const MT_Tuple4& t1, const MT_Tuple4& t2) { + return t1[0] == t2[0] && t1[1] == t2[1] && t1[2] == t2[2] && t1[3] == t2[3]; +} + +inline MT_OStream& operator<<(MT_OStream& os, const MT_Tuple4& t) { + return os << t[0] << ' ' << t[1] << ' ' << t[2] << ' ' << t[3]; +} + +#endif + diff --git a/intern/moto/include/MT_Vector2.h b/intern/moto/include/MT_Vector2.h new file mode 100644 index 00000000000..629d962a781 --- /dev/null +++ b/intern/moto/include/MT_Vector2.h @@ -0,0 +1,113 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * Copyright (c) 2000 Gino van den Bergen + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Gino van den Bergen makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef MT_VECTOR2_H +#define MT_VECTOR2_H + +#include +#include "MT_Tuple2.h" + +class MT_Vector2 : public MT_Tuple2 { +public: + MT_Vector2() {} + MT_Vector2(const float *v2) : MT_Tuple2(v2) {} + MT_Vector2(const double *v2) : MT_Tuple2(v2) {} + MT_Vector2(MT_Scalar xx, MT_Scalar yy) : MT_Tuple2(xx, yy) {} + + MT_Vector2& operator+=(const MT_Vector2& v); + MT_Vector2& operator-=(const MT_Vector2& v); + MT_Vector2& operator*=(MT_Scalar s); + MT_Vector2& operator/=(MT_Scalar s); + + MT_Scalar dot(const MT_Vector2& v) const; + + MT_Scalar length2() const; + MT_Scalar length() const; + + MT_Vector2 absolute() const; + + void normalize(); + MT_Vector2 normalized() const; + + void scale(MT_Scalar x, MT_Scalar y); + MT_Vector2 scaled(MT_Scalar x, MT_Scalar y) const; + + bool fuzzyZero() const; + + MT_Scalar angle(const MT_Vector2& v) const; + MT_Vector2 cross(const MT_Vector2& v) const; + MT_Scalar triple(const MT_Vector2& v1, const MT_Vector2& v2) const; + + int closestAxis() const; + + static MT_Vector2 random(); +}; + +MT_Vector2 operator+(const MT_Vector2& v1, const MT_Vector2& v2); +MT_Vector2 operator-(const MT_Vector2& v1, const MT_Vector2& v2); +MT_Vector2 operator-(const MT_Vector2& v); +MT_Vector2 operator*(const MT_Vector2& v, MT_Scalar s); +MT_Vector2 operator*(MT_Scalar s, const MT_Vector2& v); +MT_Vector2 operator/(const MT_Vector2& v, MT_Scalar s); + +MT_Scalar MT_dot(const MT_Vector2& v1, const MT_Vector2& v2); + +MT_Scalar MT_length2(const MT_Vector2& v); +MT_Scalar MT_length(const MT_Vector2& v); + +bool MT_fuzzyZero(const MT_Vector2& v); +bool MT_fuzzyEqual(const MT_Vector2& v1, const MT_Vector2& v2); + +MT_Scalar MT_angle(const MT_Vector2& v1, const MT_Vector2& v2); +MT_Vector2 MT_cross(const MT_Vector2& v1, const MT_Vector2& v2); +MT_Scalar MT_triple(const MT_Vector2& v1, const MT_Vector2& v2, + const MT_Vector2& v3); + +#ifdef GEN_INLINED +#include "MT_Vector2.inl" +#endif + +#endif + diff --git a/intern/moto/include/MT_Vector2.inl b/intern/moto/include/MT_Vector2.inl new file mode 100644 index 00000000000..860f9bad830 --- /dev/null +++ b/intern/moto/include/MT_Vector2.inl @@ -0,0 +1,89 @@ +#include "MT_Optimize.h" + +GEN_INLINE MT_Vector2& MT_Vector2::operator+=(const MT_Vector2& vv) { + m_co[0] += vv[0]; m_co[1] += vv[1]; + return *this; +} + +GEN_INLINE MT_Vector2& MT_Vector2::operator-=(const MT_Vector2& vv) { + m_co[0] -= vv[0]; m_co[1] -= vv[1]; + return *this; +} + +GEN_INLINE MT_Vector2& MT_Vector2::operator*=(MT_Scalar s) { + m_co[0] *= s; m_co[1] *= s; + return *this; +} + +GEN_INLINE MT_Vector2& MT_Vector2::operator/=(MT_Scalar s) { + MT_assert(!MT_fuzzyZero(s)); + return *this *= 1.0 / s; +} + +GEN_INLINE MT_Vector2 operator+(const MT_Vector2& v1, const MT_Vector2& v2) { + return MT_Vector2(v1[0] + v2[0], v1[1] + v2[1]); +} + +GEN_INLINE MT_Vector2 operator-(const MT_Vector2& v1, const MT_Vector2& v2) { + return MT_Vector2(v1[0] - v2[0], v1[1] - v2[1]); +} + +GEN_INLINE MT_Vector2 operator-(const MT_Vector2& v) { + return MT_Vector2(-v[0], -v[1]); +} + +GEN_INLINE MT_Vector2 operator*(const MT_Vector2& v, MT_Scalar s) { + return MT_Vector2(v[0] * s, v[1] * s); +} + +GEN_INLINE MT_Vector2 operator*(MT_Scalar s, const MT_Vector2& v) { return v * s; } + +GEN_INLINE MT_Vector2 operator/(const MT_Vector2& v, MT_Scalar s) { + MT_assert(!MT_fuzzyZero(s)); + return v * (1.0 / s); +} + +GEN_INLINE MT_Scalar MT_Vector2::dot(const MT_Vector2& vv) const { + return m_co[0] * vv[0] + m_co[1] * vv[1]; +} + +GEN_INLINE MT_Scalar MT_Vector2::length2() const { return dot(*this); } +GEN_INLINE MT_Scalar MT_Vector2::length() const { return sqrt(length2()); } + +GEN_INLINE MT_Vector2 MT_Vector2::absolute() const { + return MT_Vector2(MT_abs(m_co[0]), MT_abs(m_co[1])); +} + +GEN_INLINE bool MT_Vector2::fuzzyZero() const { return MT_fuzzyZero2(length2()); } + +GEN_INLINE void MT_Vector2::normalize() { *this /= length(); } +GEN_INLINE MT_Vector2 MT_Vector2::normalized() const { return *this / length(); } + +GEN_INLINE void MT_Vector2::scale(MT_Scalar xx, MT_Scalar yy) { + m_co[0] *= xx; m_co[1] *= yy; +} + +GEN_INLINE MT_Vector2 MT_Vector2::scaled(MT_Scalar xx, MT_Scalar yy) const { + return MT_Vector2(m_co[0] * xx, m_co[1] * yy); +} + +GEN_INLINE MT_Scalar MT_Vector2::angle(const MT_Vector2& vv) const { + MT_Scalar s = sqrt(length2() * vv.length2()); + MT_assert(!MT_fuzzyZero(s)); + return acos(dot(vv) / s); +} + + +GEN_INLINE MT_Scalar MT_dot(const MT_Vector2& v1, const MT_Vector2& v2) { + return v1.dot(v2); +} + +GEN_INLINE MT_Scalar MT_length2(const MT_Vector2& v) { return v.length2(); } +GEN_INLINE MT_Scalar MT_length(const MT_Vector2& v) { return v.length(); } + +GEN_INLINE bool MT_fuzzyZero(const MT_Vector2& v) { return v.fuzzyZero(); } +GEN_INLINE bool MT_fuzzyEqual(const MT_Vector2& v1, const MT_Vector2& v2) { + return MT_fuzzyZero(v1 - v2); +} + +GEN_INLINE MT_Scalar MT_angle(const MT_Vector2& v1, const MT_Vector2& v2) { return v1.angle(v2); } diff --git a/intern/moto/include/MT_Vector3.h b/intern/moto/include/MT_Vector3.h new file mode 100644 index 00000000000..c35a9d47234 --- /dev/null +++ b/intern/moto/include/MT_Vector3.h @@ -0,0 +1,120 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * Copyright (c) 2000 Gino van den Bergen + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Gino van den Bergen makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef MT_VECTOR3_H +#define MT_VECTOR3_H + +#include +#include "MT_Tuple3.h" + +class MT_Vector3 : public MT_Tuple3 { +public: + virtual ~MT_Vector3() {} + MT_Vector3() {} + MT_Vector3(const float *v) : MT_Tuple3(v) {} + MT_Vector3(const double *v) : MT_Tuple3(v) {} + MT_Vector3(MT_Scalar xx, MT_Scalar yy, MT_Scalar zz) : MT_Tuple3(xx, yy, zz) {} + + MT_Vector3& operator+=(const MT_Vector3& v); + MT_Vector3& operator-=(const MT_Vector3& v); + MT_Vector3& operator*=(MT_Scalar s); + MT_Vector3& operator/=(MT_Scalar s); + + MT_Scalar dot(const MT_Vector3& v) const; + + MT_Scalar length2() const; + MT_Scalar length() const; + + MT_Vector3 absolute() const; + + void noiseGate(MT_Scalar threshold); + + void normalize(); + MT_Vector3 normalized() const; + MT_Vector3 safe_normalized() const; + + + void scale(MT_Scalar x, MT_Scalar y, MT_Scalar z); + MT_Vector3 scaled(MT_Scalar x, MT_Scalar y, MT_Scalar z) const; + + bool fuzzyZero() const; + + MT_Scalar angle(const MT_Vector3& v) const; + MT_Vector3 cross(const MT_Vector3& v) const; + MT_Scalar triple(const MT_Vector3& v1, const MT_Vector3& v2) const; + + int closestAxis() const; + + static MT_Vector3 random(); +}; + +MT_Vector3 operator+(const MT_Vector3& v1, const MT_Vector3& v2); +MT_Vector3 operator-(const MT_Vector3& v1, const MT_Vector3& v2); +MT_Vector3 operator-(const MT_Vector3& v); +MT_Vector3 operator*(const MT_Vector3& v, MT_Scalar s); +MT_Vector3 operator*(MT_Scalar s, const MT_Vector3& v); +MT_Vector3 operator/(const MT_Vector3& v, MT_Scalar s); + +MT_Vector3 operator*(const MT_Vector3& v1, const MT_Vector3& v2); + +MT_Scalar MT_dot(const MT_Vector3& v1, const MT_Vector3& v2); + +MT_Scalar MT_length2(const MT_Vector3& v); +MT_Scalar MT_length(const MT_Vector3& v); + +bool MT_fuzzyZero(const MT_Vector3& v); +bool MT_fuzzyEqual(const MT_Vector3& v1, const MT_Vector3& v2); + +MT_Scalar MT_angle(const MT_Vector3& v1, const MT_Vector3& v2); +MT_Vector3 MT_cross(const MT_Vector3& v1, const MT_Vector3& v2); +MT_Scalar MT_triple(const MT_Vector3& v1, const MT_Vector3& v2, + const MT_Vector3& v3); + +#ifdef GEN_INLINED +#include "MT_Vector3.inl" +#endif + +#endif + diff --git a/intern/moto/include/MT_Vector3.inl b/intern/moto/include/MT_Vector3.inl new file mode 100644 index 00000000000..b17ef47c709 --- /dev/null +++ b/intern/moto/include/MT_Vector3.inl @@ -0,0 +1,134 @@ +#include "MT_Optimize.h" + +GEN_INLINE MT_Vector3& MT_Vector3::operator+=(const MT_Vector3& v) { + m_co[0] += v[0]; m_co[1] += v[1]; m_co[2] += v[2]; + return *this; +} + +GEN_INLINE MT_Vector3& MT_Vector3::operator-=(const MT_Vector3& v) { + m_co[0] -= v[0]; m_co[1] -= v[1]; m_co[2] -= v[2]; + return *this; +} + +GEN_INLINE MT_Vector3& MT_Vector3::operator*=(MT_Scalar s) { + m_co[0] *= s; m_co[1] *= s; m_co[2] *= s; + return *this; +} + +GEN_INLINE MT_Vector3& MT_Vector3::operator/=(MT_Scalar s) { + MT_assert(!MT_fuzzyZero(s)); + return *this *= MT_Scalar(1.0) / s; +} + +GEN_INLINE MT_Vector3 operator+(const MT_Vector3& v1, const MT_Vector3& v2) { + return MT_Vector3(v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2]); +} + +GEN_INLINE MT_Vector3 operator-(const MT_Vector3& v1, const MT_Vector3& v2) { + return MT_Vector3(v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2]); +} + +GEN_INLINE MT_Vector3 operator-(const MT_Vector3& v) { + return MT_Vector3(-v[0], -v[1], -v[2]); +} + +GEN_INLINE MT_Vector3 operator*(const MT_Vector3& v, MT_Scalar s) { + return MT_Vector3(v[0] * s, v[1] * s, v[2] * s); +} + +GEN_INLINE MT_Vector3 operator*(MT_Scalar s, const MT_Vector3& v) { return v * s; } + +GEN_INLINE MT_Vector3 operator/(const MT_Vector3& v, MT_Scalar s) { + MT_assert(!MT_fuzzyZero(s)); + return v * (MT_Scalar(1.0) / s); +} + +GEN_INLINE MT_Vector3 operator*(const MT_Vector3& v1, const MT_Vector3& v2) { + return MT_Vector3(v1[0] * v2[0], v1[1] * v2[1], v1[2] * v2[2]); +} + +GEN_INLINE MT_Scalar MT_Vector3::dot(const MT_Vector3& v) const { + return m_co[0] * v[0] + m_co[1] * v[1] + m_co[2] * v[2]; +} + +GEN_INLINE MT_Scalar MT_Vector3::length2() const { return dot(*this); } +GEN_INLINE MT_Scalar MT_Vector3::length() const { return sqrt(length2()); } + +GEN_INLINE MT_Vector3 MT_Vector3::absolute() const { + return MT_Vector3(MT_abs(m_co[0]), MT_abs(m_co[1]), MT_abs(m_co[2])); +} + +GEN_INLINE bool MT_Vector3::fuzzyZero() const { + return MT_fuzzyZero(length2()); +} + +GEN_INLINE void MT_Vector3::noiseGate(MT_Scalar threshold) { + if (length2() < threshold) { + setValue(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0)); + } +} + +GEN_INLINE void MT_Vector3::normalize() { *this /= length(); } +GEN_INLINE MT_Vector3 MT_Vector3::normalized() const { return *this / length(); } +GEN_INLINE MT_Vector3 MT_Vector3::safe_normalized() const { + MT_Scalar len = length(); + return MT_fuzzyZero(len) ? + MT_Vector3(MT_Scalar(1.0), MT_Scalar(0.0), MT_Scalar(0.0)) : + *this / len; +} + +GEN_INLINE void MT_Vector3::scale(MT_Scalar xx, MT_Scalar yy, MT_Scalar zz) { + m_co[0] *= xx; m_co[1] *= yy; m_co[2] *= zz; +} + +GEN_INLINE MT_Vector3 MT_Vector3::scaled(MT_Scalar xx, MT_Scalar yy, MT_Scalar zz) const { + return MT_Vector3(m_co[0] * xx, m_co[1] * yy, m_co[2] * zz); +} + +GEN_INLINE MT_Scalar MT_Vector3::angle(const MT_Vector3& v) const { + MT_Scalar s = sqrt(length2() * v.length2()); + MT_assert(!MT_fuzzyZero(s)); + return acos(dot(v) / s); +} + +GEN_INLINE MT_Vector3 MT_Vector3::cross(const MT_Vector3& v) const { + return MT_Vector3(m_co[1] * v[2] - m_co[2] * v[1], + m_co[2] * v[0] - m_co[0] * v[2], + m_co[0] * v[1] - m_co[1] * v[0]); +} + +GEN_INLINE MT_Scalar MT_Vector3::triple(const MT_Vector3& v1, const MT_Vector3& v2) const { + return m_co[0] * (v1[1] * v2[2] - v1[2] * v2[1]) + + m_co[1] * (v1[2] * v2[0] - v1[0] * v2[2]) + + m_co[2] * (v1[0] * v2[1] - v1[1] * v2[0]); +} + +GEN_INLINE int MT_Vector3::closestAxis() const { + MT_Vector3 a = absolute(); + return a[0] < a[1] ? (a[1] < a[2] ? 2 : 1) : (a[0] < a[2] ? 2 : 0); +} + +GEN_INLINE MT_Vector3 MT_Vector3::random() { + MT_Scalar z = MT_Scalar(2.0) * MT_random() - MT_Scalar(1.0); + MT_Scalar r = sqrt(MT_Scalar(1.0) - z * z); + MT_Scalar t = MT_2_PI * MT_random(); + return MT_Vector3(r * cos(t), r * sin(t), z); +} + +GEN_INLINE MT_Scalar MT_dot(const MT_Vector3& v1, const MT_Vector3& v2) { + return v1.dot(v2); +} + +GEN_INLINE MT_Scalar MT_length2(const MT_Vector3& v) { return v.length2(); } +GEN_INLINE MT_Scalar MT_length(const MT_Vector3& v) { return v.length(); } + +GEN_INLINE bool MT_fuzzyZero(const MT_Vector3& v) { return v.fuzzyZero(); } +GEN_INLINE bool MT_fuzzyEqual(const MT_Vector3& v1, const MT_Vector3& v2) { + return MT_fuzzyZero(v1 - v2); +} + +GEN_INLINE MT_Scalar MT_angle(const MT_Vector3& v1, const MT_Vector3& v2) { return v1.angle(v2); } +GEN_INLINE MT_Vector3 MT_cross(const MT_Vector3& v1, const MT_Vector3& v2) { return v1.cross(v2); } +GEN_INLINE MT_Scalar MT_triple(const MT_Vector3& v1, const MT_Vector3& v2, const MT_Vector3& v3) { + return v1.triple(v2, v3); +} diff --git a/intern/moto/include/MT_Vector4.h b/intern/moto/include/MT_Vector4.h new file mode 100644 index 00000000000..5f1ee99d584 --- /dev/null +++ b/intern/moto/include/MT_Vector4.h @@ -0,0 +1,103 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * Copyright (c) 2000 Gino van den Bergen + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Gino van den Bergen makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef MT_VECTOR4_H +#define MT_VECTOR4_H + +#include + +#include "MT_Tuple4.h" + +class MT_Vector4 : public MT_Tuple4 { +public: + virtual ~MT_Vector4() {} + MT_Vector4() {} + MT_Vector4(const float *v) : MT_Tuple4(v) {} + MT_Vector4(const double *v) : MT_Tuple4(v) {} + MT_Vector4(MT_Scalar xx, MT_Scalar yy, MT_Scalar zz, MT_Scalar ww) : + MT_Tuple4(xx, yy, zz, ww) {} + + MT_Vector4& operator+=(const MT_Vector4& v); + MT_Vector4& operator-=(const MT_Vector4& v); + MT_Vector4& operator*=(MT_Scalar s); + MT_Vector4& operator/=(MT_Scalar s); + + MT_Scalar dot(const MT_Vector4& v) const; + + MT_Scalar length2() const; + MT_Scalar length() const; + + MT_Vector4 absolute() const; + + void normalize(); + MT_Vector4 normalized() const; + + void scale(MT_Scalar x, MT_Scalar y, MT_Scalar z, MT_Scalar w); + MT_Vector4 scaled(MT_Scalar x, MT_Scalar y, MT_Scalar z, MT_Scalar w) const; + + bool fuzzyZero() const; +}; + +MT_Vector4 operator+(const MT_Vector4& v1, const MT_Vector4& v2); +MT_Vector4 operator-(const MT_Vector4& v1, const MT_Vector4& v2); +MT_Vector4 operator-(const MT_Vector4& v); +MT_Vector4 operator*(const MT_Vector4& v, MT_Scalar s); +MT_Vector4 operator*(MT_Scalar s, const MT_Vector4& v); +MT_Vector4 operator/(const MT_Vector4& v, MT_Scalar s); + +MT_Scalar MT_dot(const MT_Vector4& v1, const MT_Vector4& v2); + +MT_Scalar MT_length2(const MT_Vector4& v); +MT_Scalar MT_length(const MT_Vector4& v); + +bool MT_fuzzyZero(const MT_Vector4& v); +bool MT_fuzzyEqual(const MT_Vector4& v1, const MT_Vector4& v2); + +#ifdef GEN_INLINED +#include "MT_Vector4.inl" +#endif + +#endif + diff --git a/intern/moto/include/MT_Vector4.inl b/intern/moto/include/MT_Vector4.inl new file mode 100644 index 00000000000..9b4126093c1 --- /dev/null +++ b/intern/moto/include/MT_Vector4.inl @@ -0,0 +1,80 @@ +#include "MT_Optimize.h" + +GEN_INLINE MT_Vector4& MT_Vector4::operator+=(const MT_Vector4& v) { + m_co[0] += v[0]; m_co[1] += v[1]; m_co[2] += v[2]; m_co[3] += v[3]; + return *this; +} + +GEN_INLINE MT_Vector4& MT_Vector4::operator-=(const MT_Vector4& v) { + m_co[0] -= v[0]; m_co[1] -= v[1]; m_co[2] -= v[2]; m_co[3] -= v[3]; + return *this; +} + +GEN_INLINE MT_Vector4& MT_Vector4::operator*=(MT_Scalar s) { + m_co[0] *= s; m_co[1] *= s; m_co[2] *= s; m_co[3] *= s; + return *this; +} + +GEN_INLINE MT_Vector4& MT_Vector4::operator/=(MT_Scalar s) { + MT_assert(!MT_fuzzyZero(s)); + return *this *= MT_Scalar(1.0) / s; +} + +GEN_INLINE MT_Vector4 operator+(const MT_Vector4& v1, const MT_Vector4& v2) { + return MT_Vector4(v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2], v1[3] + v2[3]); +} + +GEN_INLINE MT_Vector4 operator-(const MT_Vector4& v1, const MT_Vector4& v2) { + return MT_Vector4(v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2], v1[3] - v2[3]); +} + +GEN_INLINE MT_Vector4 operator-(const MT_Vector4& v) { + return MT_Vector4(-v[0], -v[1], -v[2], -v[3]); +} + +GEN_INLINE MT_Vector4 operator*(const MT_Vector4& v, MT_Scalar s) { + return MT_Vector4(v[0] * s, v[1] * s, v[2] * s, v[3] * s); +} + +GEN_INLINE MT_Vector4 operator*(MT_Scalar s, const MT_Vector4& v) { return v * s; } + +GEN_INLINE MT_Vector4 operator/(const MT_Vector4& v, MT_Scalar s) { + MT_assert(!MT_fuzzyZero(s)); + return v * (MT_Scalar(1.0) / s); +} + +GEN_INLINE MT_Scalar MT_Vector4::dot(const MT_Vector4& v) const { + return m_co[0] * v[0] + m_co[1] * v[1] + m_co[2] * v[2] + m_co[3] * v[3]; +} + +GEN_INLINE MT_Scalar MT_Vector4::length2() const { return MT_dot(*this, *this); } +GEN_INLINE MT_Scalar MT_Vector4::length() const { return sqrt(length2()); } + +GEN_INLINE MT_Vector4 MT_Vector4::absolute() const { + return MT_Vector4(MT_abs(m_co[0]), MT_abs(m_co[1]), MT_abs(m_co[2]), MT_abs(m_co[3])); +} + +GEN_INLINE void MT_Vector4::scale(MT_Scalar xx, MT_Scalar yy, MT_Scalar zz, MT_Scalar ww) { + m_co[0] *= xx; m_co[1] *= yy; m_co[2] *= zz; m_co[3] *= ww; +} + +GEN_INLINE MT_Vector4 MT_Vector4::scaled(MT_Scalar xx, MT_Scalar yy, MT_Scalar zz, MT_Scalar ww) const { + return MT_Vector4(m_co[0] * xx, m_co[1] * yy, m_co[2] * zz, m_co[3] * ww); +} + +GEN_INLINE bool MT_Vector4::fuzzyZero() const { return MT_fuzzyZero2(length2()); } + +GEN_INLINE void MT_Vector4::normalize() { *this /= length(); } +GEN_INLINE MT_Vector4 MT_Vector4::normalized() const { return *this / length(); } + +GEN_INLINE MT_Scalar MT_dot(const MT_Vector4& v1, const MT_Vector4& v2) { + return v1.dot(v2); +} + +GEN_INLINE MT_Scalar MT_length2(const MT_Vector4& v) { return v.length2(); } +GEN_INLINE MT_Scalar MT_length(const MT_Vector4& v) { return v.length(); } + +GEN_INLINE bool MT_fuzzyZero(const MT_Vector4& v) { return v.fuzzyZero(); } +GEN_INLINE bool MT_fuzzyEqual(const MT_Vector4& v1, const MT_Vector4& v2) { + return MT_fuzzyZero(v1 - v2); +} diff --git a/intern/moto/include/MT_assert.h b/intern/moto/include/MT_assert.h new file mode 100644 index 00000000000..54aea403cda --- /dev/null +++ b/intern/moto/include/MT_assert.h @@ -0,0 +1,102 @@ +/** +* $Id$ +* ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +* +* 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. The Blender +* Foundation also sells licenses for use in proprietary software under +* the Blender License. See http://www.blender.org/BL/ for information +* about this. +* +* 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. +* +* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): none yet. +* +* ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef MT_ASSERT_H +#define MT_ASSERT_H + +#include +#include +#include + + +// So it can be used from C +#ifdef __cplusplus +#define MT_CDECL extern "C" +#else +#define MT_CDECL +#endif + +// Ask the user if they wish to abort/break, ignore, or ignore for good. +// file, line, predicate form the message to ask, *do_assert should be set +// to 0 to ignore. +// returns 1 to break, false to ignore +MT_CDECL int MT_QueryAssert(const char *file, int line, const char *predicate, int *do_assert); + + +#ifdef NDEBUG +#define MT_assert(predicate) ((void)0) +#define BREAKPOINT() ((void)0) +#else + +// BREAKPOINT() will cause a break into the debugger +#if defined(__i386) && defined(__GNUC__) +// gcc on intel... +#define BREAKPOINT() \ +asm("int $3") +#elif defined(_MSC_VER) +// Visual C++ (on Intel) +#define BREAKPOINT() \ +{ _asm int 3 } +#elif defined(SIGTRAP) +// POSIX compatible... +#define BREAKPOINT() \ +raise(SIGTRAP); +#else +// FIXME: Don't know how to do a decent break! +// Add some code for your cpu type, or get a posix +// system. +// abort instead +#define BREAKPOINT() \ +abort(); +#endif /* breakpoint */ + + +#if defined(WIN32) && !defined(__GNUC__) +#define MT_assert(predicate) assert(predicate) +#else + + + +// Abort the program if predicate is not true +#define MT_assert(predicate) \ +{ \ + static int do_assert = 1; \ + if (!(predicate) && MT_QueryAssert(__FILE__, __LINE__, #predicate, &do_assert)) \ + { \ + BREAKPOINT(); \ + } \ +} +#endif /* windows */ + +#endif /* NDEBUG */ + +#endif + diff --git a/intern/moto/include/MT_random.h b/intern/moto/include/MT_random.h new file mode 100644 index 00000000000..8a578fa7d09 --- /dev/null +++ b/intern/moto/include/MT_random.h @@ -0,0 +1,43 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef MT_RANDOM_H +#define MT_RANDOM_H + +#include + +#define MT_RAND_MAX ULONG_MAX + +extern void MT_srand(unsigned long); +extern unsigned long MT_rand(); + +#endif + diff --git a/intern/moto/include/NM_Scalar.h b/intern/moto/include/NM_Scalar.h new file mode 100644 index 00000000000..a15b187cab9 --- /dev/null +++ b/intern/moto/include/NM_Scalar.h @@ -0,0 +1,158 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include + +template +class NM_Scalar { +public: + NM_Scalar() {} + explicit NM_Scalar(T value, T error = 0.0) : + m_value(value), m_error(error) {} + + T getValue() const { return m_value; } + T getError() const { return m_error; } + + operator T() const { return m_value; } + + NM_Scalar operator-() const { + return NM_Scalar(-m_value, m_error); + } + + NM_Scalar& operator=(T value) { + m_value = value; + m_error = 0.0; + return *this; + } + + NM_Scalar& operator+=(const NM_Scalar& x) { + m_value += x.m_value; + m_error = (fabs(m_value) * (m_error + 1.0) + + fabs(x.m_value) * (x.m_error + 1.0)) / + fabs(m_value + x.m_value); + return *this; + } + + NM_Scalar& operator-=(const NM_Scalar& x) { + m_value -= x.m_value; + m_error = (fabs(m_value) * (m_error + 1.0) + + fabs(x.m_value) * (x.m_error + 1.0)) / + fabs(m_value - x.m_value); + return *this; + } + + NM_Scalar& operator*=(const NM_Scalar& x) { + m_value *= x.m_value; + m_error += x.m_error + 1.0; + return *this; + } + + NM_Scalar& operator/=(const NM_Scalar& x) { + m_value /= x.m_value; + m_error += x.m_error + 1.0; + return *this; + } + +private: + T m_value; + T m_error; +}; + +template +inline NM_Scalar operator+(const NM_Scalar& x, const NM_Scalar& y) { + return x.getValue() == 0.0 && y.getValue() == 0.0 ? + NM_Scalar(0.0, 0.0) : + NM_Scalar(x.getValue() + y.getValue(), + (fabs(x.getValue()) * (x.getError() + 1.0) + + fabs(y.getValue()) * (y.getError() + 1.0)) / + fabs(x.getValue() + y.getValue())); +} + +template +inline NM_Scalar operator-(const NM_Scalar& x, const NM_Scalar& y) { + return x.getValue() == 0.0 && y.getValue() == 0.0 ? + NM_Scalar(0.0, 0.0) : + NM_Scalar(x.getValue() - y.getValue(), + (fabs(x.getValue()) * (x.getError() + 1.0) + + fabs(y.getValue()) * (y.getError() + 1.0)) / + fabs(x.getValue() - y.getValue())); +} + +template +inline NM_Scalar operator*(const NM_Scalar& x, const NM_Scalar& y) { + return NM_Scalar(x.getValue() * y.getValue(), + x.getError() + y.getError() + 1.0); +} + +template +inline NM_Scalar operator/(const NM_Scalar& x, const NM_Scalar& y) { + return NM_Scalar(x.getValue() / y.getValue(), + x.getError() + y.getError() + 1.0); +} + +template +inline std::ostream& operator<<(std::ostream& os, const NM_Scalar& x) { + return os << x.getValue() << '[' << x.getError() << ']'; +} + +template +inline NM_Scalar sqrt(const NM_Scalar& x) { + return NM_Scalar(sqrt(x.getValue()), + 0.5 * x.getError() + 1.0); +} + +template +inline NM_Scalar acos(const NM_Scalar& x) { + return NM_Scalar(acos(x.getValue()), x.getError() + 1.0); +} + +template +inline NM_Scalar cos(const NM_Scalar& x) { + return NM_Scalar(cos(x.getValue()), x.getError() + 1.0); +} + +template +inline NM_Scalar sin(const NM_Scalar& x) { + return NM_Scalar(sin(x.getValue()), x.getError() + 1.0); +} + +template +inline NM_Scalar fabs(const NM_Scalar& x) { + return NM_Scalar(fabs(x.getValue()), x.getError()); +} + +template +inline NM_Scalar pow(const NM_Scalar& x, const NM_Scalar& y) { + return NM_Scalar(pow(x.getValue(), y.getValue()), + fabs(y.getValue()) * x.getError() + 1.0); +} + diff --git a/intern/moto/intern/MT_Assert.cpp b/intern/moto/intern/MT_Assert.cpp new file mode 100644 index 00000000000..c16c43f2045 --- /dev/null +++ b/intern/moto/intern/MT_Assert.cpp @@ -0,0 +1,67 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include + +#ifdef _WIN32 +#include +#endif + +#include "MT_assert.h" + +#ifdef _MSC_VER +#ifndef snprintf + #define snprintf _snprintf +#endif +#endif + +// Query the user if they want to break/abort the program, ignore the assert, or ignore all future +// occurance of the assert. +int MT_QueryAssert(const char *file, int line, const char *predicate, int *do_assert) +{ +#ifdef _WIN32 + if (*do_assert) + { + char buffer[1024]; + snprintf(buffer, 1024, "ASSERT %s:%d: %s failed.\nWould you like to debug? (Cancel = ignore)", file, line, predicate); + int result = MessageBox(NULL, buffer, "ASSERT failed.", MB_YESNOCANCEL|MB_ICONERROR); + if (result == IDCANCEL) + { + *do_assert = 0; + return 0; + } + + return result == IDYES; + } +#endif + printf("ASSERT %s:%d: %s failed.\n", file, line, predicate); + return *do_assert; +} diff --git a/intern/moto/intern/MT_CmMatrix4x4.cpp b/intern/moto/intern/MT_CmMatrix4x4.cpp new file mode 100644 index 00000000000..64ff3512c7a --- /dev/null +++ b/intern/moto/intern/MT_CmMatrix4x4.cpp @@ -0,0 +1,240 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MT_CmMatrix4x4.h" +#include "MT_Vector3.h" +#include "MT_Point3.h" + + +MT_CmMatrix4x4::MT_CmMatrix4x4() +{ + Identity(); +} + + + +MT_CmMatrix4x4::MT_CmMatrix4x4(const float value[4][4]) +{ + for (int i=0;i<4;i++) + { + for (int j=0;j<4;j++) + m_V[i][j] = value[i][j]; + } +} + + + +MT_CmMatrix4x4::MT_CmMatrix4x4(const double value[16]) +{ + for (int i=0;i<16;i++) + m_Vflat[i] = value[i]; +} + + + +MT_CmMatrix4x4::MT_CmMatrix4x4(const MT_CmMatrix4x4& other) +{ + SetMatrix(other); +} + + + +MT_CmMatrix4x4::MT_CmMatrix4x4(const MT_Point3& orig, + const MT_Vector3& dir, + const MT_Vector3 up) +{ + MT_Vector3 z = -(dir.normalized()); + MT_Vector3 x = (up.cross(z)).normalized(); + MT_Vector3 y = (z.cross(x)); + + m_V[0][0] = x.x(); + m_V[0][1] = y.x(); + m_V[0][2] = z.x(); + m_V[0][3] = 0.0f; + + m_V[1][0] = x.y(); + m_V[1][1] = y.y(); + m_V[1][2] = z.y(); + m_V[1][3] = 0.0f; + + m_V[2][0] = x.z(); + m_V[2][1] = y.z(); + m_V[2][2] = z.z(); + m_V[2][3] = 0.0f; + + m_V[3][0] = orig.x();//0.0f; + m_V[3][1] = orig.y();//0.0f; + m_V[3][2] = orig.z();//0.0f; + m_V[3][3] = 1.0f; + + //Translate(-orig); +} + + + +MT_Vector3 MT_CmMatrix4x4::GetRight() const +{ + return MT_Vector3(m_V[0][0], m_V[0][1], m_V[0][2]); +} + + + +MT_Vector3 MT_CmMatrix4x4::GetUp() const +{ + return MT_Vector3(m_V[1][0], m_V[1][1], m_V[1][2]); +} + + + +MT_Vector3 MT_CmMatrix4x4::GetDir() const +{ + return MT_Vector3(m_V[2][0], m_V[2][1], m_V[2][2]); +} + + + +MT_Point3 MT_CmMatrix4x4::GetPos() const +{ + return MT_Point3(m_V[3][0], m_V[3][1], m_V[3][2]); +} + + + +void MT_CmMatrix4x4::Identity() +{ + for (int i=0; i<4; i++) + { + for (int j=0; j<4; j++) + m_V[i][j] = (i==j?1.0f:0.0f); + } +} + + + +void MT_CmMatrix4x4::SetMatrix(const MT_CmMatrix4x4& other) +{ + for (int i=0; i<16; i++) + m_Vflat[i] = other.m_Vflat[i]; +} + + + +double* MT_CmMatrix4x4::getPointer() +{ + return &m_V[0][0]; +} + + + +const double* MT_CmMatrix4x4::getPointer() const +{ + return &m_V[0][0]; +} + + + +void MT_CmMatrix4x4::setElem(int pos,double newvalue) +{ + m_Vflat[pos] = newvalue; +} + +MT_CmMatrix4x4 MT_CmMatrix4x4::Perspective( + MT_Scalar inLeft, + MT_Scalar inRight, + MT_Scalar inBottom, + MT_Scalar inTop, + MT_Scalar inNear, + MT_Scalar inFar +){ + + MT_CmMatrix4x4 mat; + + // Column 0 + mat(0, 0) = -(2.0*inNear) / (inRight-inLeft); + mat(1, 0) = 0; + mat(2, 0) = 0; + mat(3, 0) = 0; + + // Column 1 + mat(0, 1) = 0; + mat(1, 1) = (2.0*inNear) / (inTop-inBottom); + mat(2, 1) = 0; + mat(3, 1) = 0; + + // Column 2 + mat(0, 2) = (inRight+inLeft) / (inRight-inLeft); + mat(1, 2) = (inTop+inBottom) / (inTop-inBottom); + mat(2, 2) = -(inFar+inNear) / (inFar-inNear); + mat(3, 2) = -1; + + // Column 3 + mat(0, 3) = 0; + mat(1, 3) = 0; + mat(2, 3) = -(2.0*inFar*inNear) / (inFar-inNear); + mat(3, 3) = 0; + + return mat; +} diff --git a/intern/moto/intern/MT_Matrix3x3.cpp b/intern/moto/intern/MT_Matrix3x3.cpp new file mode 100644 index 00000000000..61dcc3b2d02 --- /dev/null +++ b/intern/moto/intern/MT_Matrix3x3.cpp @@ -0,0 +1,41 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MT_Matrix3x3.h" + + +#ifndef GEN_INLINED +#include "MT_Matrix3x3.inl" +#endif diff --git a/intern/moto/intern/MT_Matrix4x4.cpp b/intern/moto/intern/MT_Matrix4x4.cpp new file mode 100644 index 00000000000..ff0ad3caba7 --- /dev/null +++ b/intern/moto/intern/MT_Matrix4x4.cpp @@ -0,0 +1,41 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MT_Matrix4x4.h" + + +#ifndef GEN_INLINED +#include "MT_Matrix4x4.inl" +#endif diff --git a/intern/moto/intern/MT_Plane3.cpp b/intern/moto/intern/MT_Plane3.cpp new file mode 100644 index 00000000000..054b09a48cc --- /dev/null +++ b/intern/moto/intern/MT_Plane3.cpp @@ -0,0 +1,71 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifndef GEN_INLINED +#include "MT_Plane3.h" +#include "MT_Plane3.inl" +#endif + diff --git a/intern/moto/intern/MT_Point3.cpp b/intern/moto/intern/MT_Point3.cpp new file mode 100644 index 00000000000..1c585ad5eb4 --- /dev/null +++ b/intern/moto/intern/MT_Point3.cpp @@ -0,0 +1,41 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MT_Point3.h" + + +#ifndef GEN_INLINED +#include "MT_Point3.inl" +#endif diff --git a/intern/moto/intern/MT_Quaternion.cpp b/intern/moto/intern/MT_Quaternion.cpp new file mode 100644 index 00000000000..6dd08ad484f --- /dev/null +++ b/intern/moto/intern/MT_Quaternion.cpp @@ -0,0 +1,41 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MT_Quaternion.h" + + +#ifndef GEN_INLINED +#include "MT_Quaternion.inl" +#endif diff --git a/intern/moto/intern/MT_Transform.cpp b/intern/moto/intern/MT_Transform.cpp new file mode 100644 index 00000000000..1af52abca3b --- /dev/null +++ b/intern/moto/intern/MT_Transform.cpp @@ -0,0 +1,142 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + MOTTO - 3D Motion Toolkit + Copyright (C) 2000 Gino van den Bergen + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MT_Transform.h" + +void MT_Transform::setValue(const float *m) { + m_basis.setValue(m); + m_origin.setValue(&m[12]); + m_type = AFFINE; +} + +void MT_Transform::setValue(const double *m) { + m_basis.setValue(m); + m_origin.setValue(&m[12]); + m_type = AFFINE; +} + +void MT_Transform::getValue(float *m) const { + m_basis.getValue(m); + m_origin.getValue(&m[12]); + m[15] = 1.0; +} + +void MT_Transform::getValue(double *m) const { + m_basis.getValue(m); + m_origin.getValue(&m[12]); + m[15] = 1.0; +} + +MT_Transform& MT_Transform::operator*=(const MT_Transform& t) { + m_origin += m_basis * t.m_origin; + m_basis *= t.m_basis; + m_type |= t.m_type; + return *this; +} + +void MT_Transform::translate(const MT_Vector3& v) { + m_origin += m_basis * v; + m_type |= TRANSLATION; +} + +void MT_Transform::rotate(const MT_Quaternion& q) { + m_basis *= MT_Matrix3x3(q); + m_type |= ROTATION; +} + +void MT_Transform::scale(MT_Scalar x, MT_Scalar y, MT_Scalar z) { + m_basis.scale(x, y, z); + m_type |= SCALING; +} + +void MT_Transform::setIdentity() { + m_basis.setIdentity(); + m_origin.setValue(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0)); + m_type = IDENTITY; +} + +void MT_Transform::invert(const MT_Transform& t) { + m_basis = t.m_type & SCALING ? + t.m_basis.inverse() : + t.m_basis.transposed(); + m_origin.setValue(-MT_dot(m_basis[0], t.m_origin), + -MT_dot(m_basis[1], t.m_origin), + -MT_dot(m_basis[2], t.m_origin)); + m_type = t.m_type; +} + +void MT_Transform::mult(const MT_Transform& t1, const MT_Transform& t2) { + m_basis = t1.m_basis * t2.m_basis; + m_origin = t1(t2.m_origin); + m_type = t1.m_type | t2.m_type; +} + +void MT_Transform::multInverseLeft(const MT_Transform& t1, const MT_Transform& t2) { + MT_Vector3 v = t2.m_origin - t1.m_origin; + if (t1.m_type & SCALING) { + MT_Matrix3x3 inv = t1.m_basis.inverse(); + m_basis = inv * t2.m_basis; + m_origin = inv * v; + } + else { + m_basis = MT_multTransposeLeft(t1.m_basis, t2.m_basis); + m_origin = v * t1.m_basis; + } + m_type = t1.m_type | t2.m_type; +} + + + diff --git a/intern/moto/intern/MT_Vector2.cpp b/intern/moto/intern/MT_Vector2.cpp new file mode 100644 index 00000000000..c8ac08210e5 --- /dev/null +++ b/intern/moto/intern/MT_Vector2.cpp @@ -0,0 +1,41 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MT_Vector2.h" + + +#ifndef GEN_INLINED +#include "MT_Vector2.inl" +#endif diff --git a/intern/moto/intern/MT_Vector3.cpp b/intern/moto/intern/MT_Vector3.cpp new file mode 100644 index 00000000000..9285f2fcb19 --- /dev/null +++ b/intern/moto/intern/MT_Vector3.cpp @@ -0,0 +1,41 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MT_Vector3.h" + + +#ifndef GEN_INLINED +#include "MT_Vector3.inl" +#endif diff --git a/intern/moto/intern/MT_Vector4.cpp b/intern/moto/intern/MT_Vector4.cpp new file mode 100644 index 00000000000..efe7d3e7b04 --- /dev/null +++ b/intern/moto/intern/MT_Vector4.cpp @@ -0,0 +1,41 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MT_Vector4.h" + + +#ifndef GEN_INLINED +#include "MT_Vector4.inl" +#endif diff --git a/intern/moto/intern/MT_random.cpp b/intern/moto/intern/MT_random.cpp new file mode 100644 index 00000000000..0c46211c3e8 --- /dev/null +++ b/intern/moto/intern/MT_random.cpp @@ -0,0 +1,146 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* A C-program for MT19937: Real number version */ + +/* genrand() generates one pseudorandom real number (double) */ +/* which is uniformly distributed on [0,1]-interval, for each */ +/* call. sgenrand(seed) set initial values to the working area */ +/* of 624 words. Before genrand(), sgenrand(seed) must be */ +/* called once. (seed is any 32-bit integer except for 0). */ +/* Integer generator is obtained by modifying two lines. */ +/* Coded by Takuji Nishimura, considering the suggestions by */ +/* Topher Cooper and Marc Rieffel in July-Aug. 1997. */ + +/* This library is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public */ +/* License as published by the Free Software Foundation; either */ +/* version 2 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 Library General Public License for more details. */ +/* You should have received a copy of the GNU Library General */ +/* Public License along with this library; if not, write to the */ +/* Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA */ +/* 02111-1307 USA */ + +/* Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. */ +/* When you use this, send an email to: matumoto@math.keio.ac.jp */ +/* with an appropriate reference to your work. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MT_random.h" + +/* Period parameters */ +#define N 624 +#define M 397 +#define MATRIX_A 0x9908b0df /* constant vector a */ +#define UPPER_MASK 0x80000000 /* most significant w-r bits */ +#define LOWER_MASK 0x7fffffff /* least significant r bits */ + +/* Tempering parameters */ +#define TEMPERING_MASK_B 0x9d2c5680 +#define TEMPERING_MASK_C 0xefc60000 +#define TEMPERING_SHIFT_U(y) (y >> 11) +#define TEMPERING_SHIFT_S(y) (y << 7) +#define TEMPERING_SHIFT_T(y) (y << 15) +#define TEMPERING_SHIFT_L(y) (y >> 18) + +static unsigned long mt[N]; /* the array for the state vector */ +static int mti = N+1; /* mti==N+1 means mt[N] is not initialized */ + +/* initializing the array with a NONZERO seed */ +void MT_srand(unsigned long seed) +{ + /* setting initial seeds to mt[N] using */ + /* the generator Line 25 of Table 1 in */ + /* [KNUTH 1981, The Art of Computer Programming */ + /* Vol. 2 (2nd Ed.), pp102] */ + mt[0] = seed & 0xffffffff; + for (mti = 1; mti < N; mti++) + mt[mti] = (69069 * mt[mti-1]) & 0xffffffff; +} + +unsigned long MT_rand() +{ + static unsigned long mag01[2] = { 0x0, MATRIX_A }; + /* mag01[x] = x * MATRIX_A for x=0,1 */ + + unsigned long y; + + if (mti >= N) { /* generate N words at one time */ + int kk; + + if (mti == N+1) /* if sgenrand() has not been called, */ + MT_srand(4357); /* a default initial seed is used */ + + for (kk = 0; kk < N - M; kk++) { + y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK); + mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1]; + } + for (; kk < N-1; kk++) { + y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK); + mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1]; + } + y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK); + mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1]; + + mti = 0; + } + + y = mt[mti++]; + y ^= TEMPERING_SHIFT_U(y); + y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B; + y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C; + y ^= TEMPERING_SHIFT_L(y); + + return y; +} + +#undef N +#undef M +#undef MATRIX_A +#undef UPPER_MASK +#undef LOWER_MASK + +/* Tempering parameters */ +#undef TEMPERING_MASK_B +#undef TEMPERING_MASK_C +#undef TEMPERING_SHIFT_U +#undef TEMPERING_SHIFT_S +#undef TEMPERING_SHIFT_T +#undef TEMPERING_SHIFT_L + diff --git a/intern/moto/intern/Makefile b/intern/moto/intern/Makefile new file mode 100644 index 00000000000..eeba381ab2a --- /dev/null +++ b/intern/moto/intern/Makefile @@ -0,0 +1,42 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# moto intern Makefile +# + +LIBNAME = moto +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I../include + diff --git a/intern/moto/make/msvc_6_0/MoTo.dsp b/intern/moto/make/msvc_6_0/MoTo.dsp new file mode 100644 index 00000000000..23224fc7fa8 --- /dev/null +++ b/intern/moto/make/msvc_6_0/MoTo.dsp @@ -0,0 +1,379 @@ +# Microsoft Developer Studio Project File - Name="MoTo" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=MoTo - 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 "MoTo.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 "MoTo.mak" CFG="MoTo - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "MoTo - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "MoTo - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "MoTo - 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 "..\..\..\..\obj\windows\intern\moto\" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\moto\" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W4 /GX /O2 /Ob2 /I "..\..\include\\" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\moto\libmoto.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\include\*.h ..\..\..\..\..\lib\windows\moto\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\moto\*.lib ..\..\..\..\..\lib\windows\moto\lib\*.a ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "MoTo - 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 "..\..\..\..\obj\windows\intern\moto\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\moto\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\..\include\\" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\moto\debug\libmoto.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\include\*.h ..\..\..\..\..\lib\windows\moto\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\moto\debug\*.lib ..\..\..\..\..\lib\windows\moto\lib\debug\*.a ECHO Copying Debug info. XCOPY /Y ..\..\..\..\obj\windows\intern\moto\debug\vc60.* ..\..\..\..\..\lib\windows\moto\lib\debug\ ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "MoTo - Win32 Release" +# Name "MoTo - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\intern\MT_CmMatrix4x4.cpp + +!IF "$(CFG)" == "MoTo - Win32 Release" + +# ADD CPP /W3 /I "../../include" + +!ELSEIF "$(CFG)" == "MoTo - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MT_Matrix3x3.cpp + +!IF "$(CFG)" == "MoTo - Win32 Release" + +# ADD CPP /W3 /I "../../include" + +!ELSEIF "$(CFG)" == "MoTo - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MT_Matrix4x4.cpp + +!IF "$(CFG)" == "MoTo - Win32 Release" + +# ADD CPP /W3 /I "../../include" + +!ELSEIF "$(CFG)" == "MoTo - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MT_Plane3.cpp + +!IF "$(CFG)" == "MoTo - Win32 Release" + +# ADD CPP /W3 + +!ELSEIF "$(CFG)" == "MoTo - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MT_Point3.cpp + +!IF "$(CFG)" == "MoTo - Win32 Release" + +# ADD CPP /W3 /I "../../include" + +!ELSEIF "$(CFG)" == "MoTo - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MT_Quaternion.cpp + +!IF "$(CFG)" == "MoTo - Win32 Release" + +# ADD CPP /W3 /I "../../include" + +!ELSEIF "$(CFG)" == "MoTo - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MT_random.cpp + +!IF "$(CFG)" == "MoTo - Win32 Release" + +# ADD CPP /W3 /I "../../include" + +!ELSEIF "$(CFG)" == "MoTo - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MT_Transform.cpp + +!IF "$(CFG)" == "MoTo - Win32 Release" + +# ADD CPP /W3 /I "../../include" + +!ELSEIF "$(CFG)" == "MoTo - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MT_Vector2.cpp + +!IF "$(CFG)" == "MoTo - Win32 Release" + +# ADD CPP /W3 /I "../../include" + +!ELSEIF "$(CFG)" == "MoTo - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MT_Vector3.cpp + +!IF "$(CFG)" == "MoTo - Win32 Release" + +# ADD CPP /W3 /I "../../include" + +!ELSEIF "$(CFG)" == "MoTo - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MT_Vector4.cpp + +!IF "$(CFG)" == "MoTo - Win32 Release" + +# ADD CPP /W3 /I "../../include" + +!ELSEIF "$(CFG)" == "MoTo - Win32 Debug" + +!ENDIF + +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Group "inlines" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\include\MT_Matrix3x3.inl +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Matrix4x4.inl +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Plane3.inl +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Point2.inl +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Point3.inl +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Quaternion.inl +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Vector2.inl +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Vector3.inl +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Vector4.inl +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\include\GEN_List.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\GEN_Map.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_assert.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_CmMatrix4x4.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Matrix3x3.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Matrix4x4.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_MinMax.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Optimize.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Plane3.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Point2.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Point3.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Quaternion.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_random.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Scalar.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Stream.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Transform.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Tuple2.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Tuple3.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Tuple4.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Vector2.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Vector3.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Vector4.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\NM_Scalar.h +# End Source File +# End Group +# End Target +# End Project diff --git a/intern/moto/make/msvc_6_0/MoTo.dsw b/intern/moto/make/msvc_6_0/MoTo.dsw new file mode 100644 index 00000000000..bc76539dd6c --- /dev/null +++ b/intern/moto/make/msvc_6_0/MoTo.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "MoTo"=.\MoTo.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/moto/make/msvc_7_0/moto.sln b/intern/moto/make/msvc_7_0/moto.sln new file mode 100644 index 00000000000..c1c34ff4af1 --- /dev/null +++ b/intern/moto/make/msvc_7_0/moto.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MoTo", "MoTo.vcproj", "{11ABF09B-4414-4188-8071-27CE3FE49256}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {11ABF09B-4414-4188-8071-27CE3FE49256}.Debug.ActiveCfg = Debug|Win32 + {11ABF09B-4414-4188-8071-27CE3FE49256}.Debug.Build.0 = Debug|Win32 + {11ABF09B-4414-4188-8071-27CE3FE49256}.Release.ActiveCfg = Release|Win32 + {11ABF09B-4414-4188-8071-27CE3FE49256}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/intern/moto/make/msvc_7_0/moto.vcproj b/intern/moto/make/msvc_7_0/moto.vcproj new file mode 100644 index 00000000000..6ecff4b78d0 --- /dev/null +++ b/intern/moto/make/msvc_7_0/moto.vcproj @@ -0,0 +1,543 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/opennl/CMakeLists.txt b/intern/opennl/CMakeLists.txt new file mode 100644 index 00000000000..78e2359eec5 --- /dev/null +++ b/intern/opennl/CMakeLists.txt @@ -0,0 +1,36 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC extern superlu) + +FILE(GLOB SRC intern/*.c superlu/*.c) + +BLENDERLIB(blender_ONL "${SRC}" "${INC}") +#, libtype='core', priority=55 ) + diff --git a/intern/opennl/Makefile b/intern/opennl/Makefile new file mode 100644 index 00000000000..8aa0d4f590b --- /dev/null +++ b/intern/opennl/Makefile @@ -0,0 +1,67 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# opennl main makefile. +# + +include nan_definitions.mk + +LIBNAME = opennl +LIBNAME_SLU = superlu +SOURCEDIR = intern/$(LIBNAME) +SOURCEDIR_SLU = intern/$(LIBNAME_SLU) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIR_SLU = $(OCGDIR)/$(SOURCEDIR_SLU) +DIRS = intern superlu + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_OPENNL) ] || mkdir $(NAN_OPENNL) + @[ -d $(NAN_OPENNL)/include ] || mkdir $(NAN_OPENNL)/include + @[ -d $(NAN_OPENNL)/lib ] || mkdir $(NAN_OPENNL)/lib + @[ -d $(NAN_OPENNL)/lib/debug ] || mkdir $(NAN_OPENNL)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libopennl.a $(NAN_OPENNL)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libopennl.a $(NAN_OPENNL)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_OPENNL)/lib/libopennl.a + ranlib $(NAN_OPENNL)/lib/debug/libopennl.a +endif + @../tools/cpifdiff.sh extern/*.h $(NAN_OPENNL)/include/ + @[ -d $(NAN_SUPERLU) ] || mkdir $(NAN_SUPERLU) + @[ -d $(NAN_SUPERLU)/lib ] || mkdir $(NAN_SUPERLU)/lib + @[ -d $(NAN_SUPERLU)/lib/debug ] || mkdir $(NAN_SUPERLU)/lib/debug + @../tools/cpifdiff.sh $(DIR_SLU)/libsuperlu.a $(NAN_SUPERLU)/lib/ + @../tools/cpifdiff.sh $(DIR_SLU)/debug/libsuperlu.a $(NAN_SUPERLU)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_SUPERLU)/lib/libsuperlu.a + ranlib $(NAN_SUPERLU)/lib/debug/libsuperlu.a +endif + diff --git a/intern/opennl/SConscript b/intern/opennl/SConscript new file mode 100644 index 00000000000..bcfb030f7e6 --- /dev/null +++ b/intern/opennl/SConscript @@ -0,0 +1,12 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.c') + env.Glob('superlu/*.c') + +incs = 'extern superlu' + +if (env['OURPLATFORM'] == 'win32-mingw'): + env.BlenderLib ('blender_ONL', sources, Split(incs), [], libtype=['core','intern'], priority=[1,80] ) +else: + env.BlenderLib ('blender_ONL', sources, Split(incs), [], libtype='core', priority=55 ) + diff --git a/intern/opennl/doc/OpenNL_License.txt b/intern/opennl/doc/OpenNL_License.txt new file mode 100644 index 00000000000..4e8d97fd526 --- /dev/null +++ b/intern/opennl/doc/OpenNL_License.txt @@ -0,0 +1,341 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +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 Program or any portion +of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +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 Program, 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 Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) 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; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, 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 executable. However, as a +special exception, the source code 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. + +If distribution of executable or 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 counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program 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. + + 5. 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 Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program 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 to +this License. + + 7. 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 Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program 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 Program. + +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. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program 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. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 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 Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, 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 + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. 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 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. + + + END OF TERMS AND CONDITIONS + + Appendix: 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 +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) 19yy + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision 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, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This 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 Library General +Public License instead of this License. + diff --git a/intern/opennl/doc/OpenNL_Readme.txt b/intern/opennl/doc/OpenNL_Readme.txt new file mode 100644 index 00000000000..e6aea3c0286 --- /dev/null +++ b/intern/opennl/doc/OpenNL_Readme.txt @@ -0,0 +1,13 @@ + +This is OpenNL, a library to easily construct and solve sparse linear systems. +* OpenNL is supplied with a set of iterative solvers (Conjugate gradient, + BICGSTAB, GMRes) and preconditioners (Jacobi, SSOR). +* OpenNL can also use other solvers (SuperLU 3.0 supported as an OpenNL + extension) + +Note that to be compatible with OpenNL, SuperLU 3.0 needs to be compiled with +the following flag (see make.inc in SuperLU3.0): +CDEFS = -DAdd_ (the default is -DAdd__, just remove the second underscore) + +OpenNL was modified for Blender to be used only as a wrapper for SuperLU. + diff --git a/intern/opennl/doc/SuperLU_License.txt b/intern/opennl/doc/SuperLU_License.txt new file mode 100644 index 00000000000..f31a01782e2 --- /dev/null +++ b/intern/opennl/doc/SuperLU_License.txt @@ -0,0 +1,31 @@ +Copyright (c) 2003, The Regents of the University of California, through +Lawrence Berkeley National Laboratory (subject to receipt of any required +approvals from U.S. Dept. of Energy) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, +are permitted provided that the following conditions are met: + +(1) Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +(2) 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. +(3) Neither the name of Lawrence Berkeley National Laboratory, U.S. Dept. of +Energy 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. + diff --git a/intern/opennl/doc/SuperLU_Readme.txt b/intern/opennl/doc/SuperLU_Readme.txt new file mode 100644 index 00000000000..c1cedd09893 --- /dev/null +++ b/intern/opennl/doc/SuperLU_Readme.txt @@ -0,0 +1,52 @@ + SuperLU (Version 3.0) + ===================== + +Copyright (c) 2003, The Regents of the University of California, through +Lawrence Berkeley National Laboratory (subject to receipt of any required +approvals from U.S. Dept. of Energy) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +(1) Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +(2) 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. +(3) Neither the name of Lawrence Berkeley National Laboratory, U.S. Dept. of +Energy 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. + + +SuperLU contains a set of subroutines to solve a sparse linear system +A*X=B. It uses Gaussian elimination with partial pivoting (GEPP). +The columns of A may be preordered before factorization; the +preordering for sparsity is completely separate from the factorization. + +SuperLU is implemented in ANSI C, and must be compiled with standard +ANSI C compilers. It provides functionality for both real and complex +matrices, in both single and double precision. The file names for the +single-precision real version start with letter "s" (such as sgstrf.c); +the file names for the double-precision real version start with letter "d" +(such as dgstrf.c); the file names for the single-precision complex +version start with letter "c" (such as cgstrf.c); the file names +for the double-precision complex version start with letter "z" +(such as zgstrf.c). + +SuperLU was modified for Blender to only include single-precision +functionality. + diff --git a/intern/opennl/extern/ONL_opennl.h b/intern/opennl/extern/ONL_opennl.h new file mode 100644 index 00000000000..be76aa95eac --- /dev/null +++ b/intern/opennl/extern/ONL_opennl.h @@ -0,0 +1,147 @@ +/* + * $Id$ + * + * OpenNL: Numerical Library + * Copyright (C) 2004 Bruno Levy + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * If you modify this software, you should include a notice giving the + * name of the person performing the modification, the date of modification, + * and the reason for such modification. + * + * Contact: Bruno Levy + * + * levy@loria.fr + * + * ISA Project + * LORIA, INRIA Lorraine, + * Campus Scientifique, BP 239 + * 54506 VANDOEUVRE LES NANCY CEDEX + * FRANCE + * + * Note that the GNU General Public License does not permit incorporating + * the Software into proprietary programs. + */ + +/* +#define NL_DEBUG +#define NL_PARANOID +*/ + +#define NL_USE_SUPERLU + +#ifndef nlOPENNL_H +#define nlOPENNL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define NL_VERSION_0_0 1 + +/* Datatypes */ + +typedef unsigned int NLenum; +typedef unsigned char NLboolean; +typedef unsigned int NLbitfield; +typedef void NLvoid; +typedef signed char NLbyte; /* 1-byte signed */ +typedef short NLshort; /* 2-byte signed */ +typedef int NLint; /* 4-byte signed */ +typedef unsigned char NLubyte; /* 1-byte unsigned */ +typedef unsigned short NLushort; /* 2-byte unsigned */ +typedef unsigned int NLuint; /* 4-byte unsigned */ +typedef int NLsizei; /* 4-byte signed */ +typedef float NLfloat; /* single precision float */ +typedef double NLdouble; /* double precision float */ + +typedef void* NLContext; + +/* Constants */ + +#define NL_FALSE 0x0 +#define NL_TRUE 0x1 + +/* Primitives */ + +#define NL_SYSTEM 0x0 +#define NL_MATRIX 0x1 + +/* Solver Parameters */ + +#define NL_SOLVER 0x100 +#define NL_NB_VARIABLES 0x101 +#define NL_LEAST_SQUARES 0x102 +#define NL_SYMMETRIC 0x106 +#define NL_ERROR 0x108 +#define NL_NB_ROWS 0x110 +#define NL_NB_RIGHT_HAND_SIDES 0x112 /* 4 max */ + +/* Contexts */ + +NLContext nlNewContext(void); +void nlDeleteContext(NLContext context); +void nlMakeCurrent(NLContext context); +NLContext nlGetCurrent(void); + +/* State get/set */ + +void nlSolverParameterf(NLenum pname, NLfloat param); +void nlSolverParameteri(NLenum pname, NLint param); + +void nlGetBooleanv(NLenum pname, NLboolean* params); +void nlGetFloatv(NLenum pname, NLfloat* params); +void nlGetIntergerv(NLenum pname, NLint* params); + +void nlEnable(NLenum pname); +void nlDisable(NLenum pname); +NLboolean nlIsEnabled(NLenum pname); + +/* Variables */ + +void nlSetVariable(NLuint rhsindex, NLuint index, NLfloat value); +NLfloat nlGetVariable(NLuint rhsindex, NLuint index); +void nlLockVariable(NLuint index); +void nlUnlockVariable(NLuint index); +NLboolean nlVariableIsLocked(NLuint index); + +/* Begin/End */ + +void nlBegin(NLenum primitive); +void nlEnd(NLenum primitive); + +/* Setting elements in matrix/vector */ + +void nlMatrixAdd(NLuint row, NLuint col, NLfloat value); +void nlRightHandSideAdd(NLuint rhsindex, NLuint index, NLfloat value); +void nlRightHandSideSet(NLuint rhsindex, NLuint index, NLfloat value); + +/* Multiply */ + +void nlMatrixMultiply(NLfloat *x, NLfloat *y); + +/* Solve */ + +void nlPrintMatrix(void); +NLboolean nlSolve(); +NLboolean nlSolveAdvanced(NLint *permutation, NLboolean solveAgain); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/intern/opennl/intern/Makefile b/intern/opennl/intern/Makefile new file mode 100644 index 00000000000..2e57905d931 --- /dev/null +++ b/intern/opennl/intern/Makefile @@ -0,0 +1,43 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# opennl intern Makefile +# + +LIBNAME = opennl +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(NAN_LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I../superlu -I../extern + + diff --git a/intern/opennl/intern/opennl.c b/intern/opennl/intern/opennl.c new file mode 100644 index 00000000000..2d30da075d3 --- /dev/null +++ b/intern/opennl/intern/opennl.c @@ -0,0 +1,1263 @@ +/* + * $Id$ + * + * OpenNL: Numerical Library + * Copyright (C) 2004 Bruno Levy + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * If you modify this software, you should include a notice giving the + * name of the person performing the modification, the date of modification, + * and the reason for such modification. + * + * Contact: Bruno Levy + * + * levy@loria.fr + * + * ISA Project + * LORIA, INRIA Lorraine, + * Campus Scientifique, BP 239 + * 54506 VANDOEUVRE LES NANCY CEDEX + * FRANCE + * + * Note that the GNU General Public License does not permit incorporating + * the Software into proprietary programs. + */ + +#include "ONL_opennl.h" + +#include +#include +#include +#include + +#ifdef NL_PARANOID +#ifndef NL_DEBUG +#define NL_DEBUG +#endif +#endif + +/* SuperLU includes */ +#include +#include + +/************************************************************************************/ +/* Assertions */ + + +static void __nl_assertion_failed(char* cond, char* file, int line) { + fprintf( + stderr, + "OpenNL assertion failed: %s, file:%s, line:%d\n", + cond,file,line + ); + abort(); +} + +static void __nl_range_assertion_failed( + float x, float min_val, float max_val, char* file, int line +) { + fprintf( + stderr, + "OpenNL range assertion failed: %f in [ %f ... %f ], file:%s, line:%d\n", + x, min_val, max_val, file,line + ); + abort(); +} + +static void __nl_should_not_have_reached(char* file, int line) { + fprintf( + stderr, + "OpenNL should not have reached this point: file:%s, line:%d\n", + file,line + ); + abort(); +} + + +#define __nl_assert(x) { \ + if(!(x)) { \ + __nl_assertion_failed(#x,__FILE__, __LINE__); \ + } \ +} + +#define __nl_range_assert(x,min_val,max_val) { \ + if(((x) < (min_val)) || ((x) > (max_val))) { \ + __nl_range_assertion_failed(x, min_val, max_val, \ + __FILE__, __LINE__ \ + ); \ + } \ +} + +#define __nl_assert_not_reached { \ + __nl_should_not_have_reached(__FILE__, __LINE__); \ +} + +#ifdef NL_DEBUG +#define __nl_debug_assert(x) __nl_assert(x) +#define __nl_debug_range_assert(x,min_val,max_val) __nl_range_assert(x,min_val,max_val) +#else +#define __nl_debug_assert(x) +#define __nl_debug_range_assert(x,min_val,max_val) +#endif + +#ifdef NL_PARANOID +#define __nl_parano_assert(x) __nl_assert(x) +#define __nl_parano_range_assert(x,min_val,max_val) __nl_range_assert(x,min_val,max_val) +#else +#define __nl_parano_assert(x) +#define __nl_parano_range_assert(x,min_val,max_val) +#endif + +/************************************************************************************/ +/* classic macros */ + +#ifndef MIN +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#endif + +#ifndef MAX +#define MAX(x,y) (((x) > (y)) ? (x) : (y)) +#endif + +/************************************************************************************/ +/* memory management */ + +#define __NL_NEW(T) (T*)(calloc(1, sizeof(T))) +#define __NL_NEW_ARRAY(T,NB) (T*)(calloc((NB),sizeof(T))) +#define __NL_RENEW_ARRAY(T,x,NB) (T*)(realloc(x,(NB)*sizeof(T))) +#define __NL_DELETE(x) free(x); x = NULL +#define __NL_DELETE_ARRAY(x) free(x); x = NULL + +#define __NL_CLEAR(T, x) memset(x, 0, sizeof(T)) +#define __NL_CLEAR_ARRAY(T,x,NB) memset(x, 0, (NB)*sizeof(T)) + +/************************************************************************************/ +/* Dynamic arrays for sparse row/columns */ + +typedef struct { + NLuint index; + NLfloat value; +} __NLCoeff; + +typedef struct { + NLuint size; + NLuint capacity; + __NLCoeff* coeff; +} __NLRowColumn; + +static void __nlRowColumnConstruct(__NLRowColumn* c) { + c->size = 0; + c->capacity = 0; + c->coeff = NULL; +} + +static void __nlRowColumnDestroy(__NLRowColumn* c) { + __NL_DELETE_ARRAY(c->coeff); +#ifdef NL_PARANOID + __NL_CLEAR(__NLRowColumn, c); +#endif +} + +static void __nlRowColumnGrow(__NLRowColumn* c) { + if(c->capacity != 0) { + c->capacity = 2 * c->capacity; + c->coeff = __NL_RENEW_ARRAY(__NLCoeff, c->coeff, c->capacity); + } else { + c->capacity = 4; + c->coeff = __NL_NEW_ARRAY(__NLCoeff, c->capacity); + } +} + +static void __nlRowColumnAdd(__NLRowColumn* c, NLint index, NLfloat value) { + NLuint i; + for(i=0; isize; i++) { + if(c->coeff[i].index == (NLuint)index) { + c->coeff[i].value += value; + return; + } + } + if(c->size == c->capacity) { + __nlRowColumnGrow(c); + } + c->coeff[c->size].index = index; + c->coeff[c->size].value = value; + c->size++; +} + +/* Does not check whether the index already exists */ +static void __nlRowColumnAppend(__NLRowColumn* c, NLint index, NLfloat value) { + if(c->size == c->capacity) { + __nlRowColumnGrow(c); + } + c->coeff[c->size].index = index; + c->coeff[c->size].value = value; + c->size++; +} + +static void __nlRowColumnClear(__NLRowColumn* c) { + c->size = 0; + c->capacity = 0; + __NL_DELETE_ARRAY(c->coeff); +} + +/************************************************************************************/ +/* SparseMatrix data structure */ + +#define __NL_ROWS 1 +#define __NL_COLUMNS 2 +#define __NL_SYMMETRIC 4 + +typedef struct { + NLuint m; + NLuint n; + NLuint diag_size; + NLenum storage; + __NLRowColumn* row; + __NLRowColumn* column; + NLfloat* diag; +} __NLSparseMatrix; + + +static void __nlSparseMatrixConstruct( + __NLSparseMatrix* M, NLuint m, NLuint n, NLenum storage +) { + NLuint i; + M->m = m; + M->n = n; + M->storage = storage; + if(storage & __NL_ROWS) { + M->row = __NL_NEW_ARRAY(__NLRowColumn, m); + for(i=0; irow[i])); + } + } else { + M->row = NULL; + } + + if(storage & __NL_COLUMNS) { + M->column = __NL_NEW_ARRAY(__NLRowColumn, n); + for(i=0; icolumn[i])); + } + } else { + M->column = NULL; + } + + M->diag_size = MIN(m,n); + M->diag = __NL_NEW_ARRAY(NLfloat, M->diag_size); +} + +static void __nlSparseMatrixDestroy(__NLSparseMatrix* M) { + NLuint i; + __NL_DELETE_ARRAY(M->diag); + if(M->storage & __NL_ROWS) { + for(i=0; im; i++) { + __nlRowColumnDestroy(&(M->row[i])); + } + __NL_DELETE_ARRAY(M->row); + } + if(M->storage & __NL_COLUMNS) { + for(i=0; in; i++) { + __nlRowColumnDestroy(&(M->column[i])); + } + __NL_DELETE_ARRAY(M->column); + } +#ifdef NL_PARANOID + __NL_CLEAR(__NLSparseMatrix,M); +#endif +} + +static void __nlSparseMatrixAdd( + __NLSparseMatrix* M, NLuint i, NLuint j, NLfloat value +) { + __nl_parano_range_assert(i, 0, M->m - 1); + __nl_parano_range_assert(j, 0, M->n - 1); + if((M->storage & __NL_SYMMETRIC) && (j > i)) { + return; + } + if(i == j) { + M->diag[i] += value; + } + if(M->storage & __NL_ROWS) { + __nlRowColumnAdd(&(M->row[i]), j, value); + } + if(M->storage & __NL_COLUMNS) { + __nlRowColumnAdd(&(M->column[j]), i, value); + } +} + +static void __nlSparseMatrixClear( __NLSparseMatrix* M) { + NLuint i; + if(M->storage & __NL_ROWS) { + for(i=0; im; i++) { + __nlRowColumnClear(&(M->row[i])); + } + } + if(M->storage & __NL_COLUMNS) { + for(i=0; in; i++) { + __nlRowColumnClear(&(M->column[i])); + } + } + __NL_CLEAR_ARRAY(NLfloat, M->diag, M->diag_size); +} + +/* Returns the number of non-zero coefficients */ +static NLuint __nlSparseMatrixNNZ( __NLSparseMatrix* M) { + NLuint nnz = 0; + NLuint i; + if(M->storage & __NL_ROWS) { + for(i = 0; im; i++) { + nnz += M->row[i].size; + } + } else if (M->storage & __NL_COLUMNS) { + for(i = 0; in; i++) { + nnz += M->column[i].size; + } + } else { + __nl_assert_not_reached; + } + return nnz; +} + +/************************************************************************************/ +/* SparseMatrix x Vector routines, internal helper routines */ + +static void __nlSparseMatrix_mult_rows_symmetric( + __NLSparseMatrix* A, NLfloat* x, NLfloat* y +) { + NLuint m = A->m; + NLuint i,ij; + __NLRowColumn* Ri = NULL; + __NLCoeff* c = NULL; + for(i=0; irow[i]); + for(ij=0; ijsize; ij++) { + c = &(Ri->coeff[ij]); + y[i] += c->value * x[c->index]; + if(i != c->index) { + y[c->index] += c->value * x[i]; + } + } + } +} + +static void __nlSparseMatrix_mult_rows( + __NLSparseMatrix* A, NLfloat* x, NLfloat* y +) { + NLuint m = A->m; + NLuint i,ij; + __NLRowColumn* Ri = NULL; + __NLCoeff* c = NULL; + for(i=0; irow[i]); + for(ij=0; ijsize; ij++) { + c = &(Ri->coeff[ij]); + y[i] += c->value * x[c->index]; + } + } +} + +static void __nlSparseMatrix_mult_cols_symmetric( + __NLSparseMatrix* A, NLfloat* x, NLfloat* y +) { + NLuint n = A->n; + NLuint j,ii; + __NLRowColumn* Cj = NULL; + __NLCoeff* c = NULL; + for(j=0; jcolumn[j]); + for(ii=0; iisize; ii++) { + c = &(Cj->coeff[ii]); + y[c->index] += c->value * x[j]; + if(j != c->index) { + y[j] += c->value * x[c->index]; + } + } + } +} + +static void __nlSparseMatrix_mult_cols( + __NLSparseMatrix* A, NLfloat* x, NLfloat* y +) { + NLuint n = A->n; + NLuint j,ii; + __NLRowColumn* Cj = NULL; + __NLCoeff* c = NULL; + __NL_CLEAR_ARRAY(NLfloat, y, A->m); + for(j=0; jcolumn[j]); + for(ii=0; iisize; ii++) { + c = &(Cj->coeff[ii]); + y[c->index] += c->value * x[j]; + } + } +} + +/************************************************************************************/ +/* SparseMatrix x Vector routines, main driver routine */ + +static void __nlSparseMatrixMult(__NLSparseMatrix* A, NLfloat* x, NLfloat* y) { + if(A->storage & __NL_ROWS) { + if(A->storage & __NL_SYMMETRIC) { + __nlSparseMatrix_mult_rows_symmetric(A, x, y); + } else { + __nlSparseMatrix_mult_rows(A, x, y); + } + } else { + if(A->storage & __NL_SYMMETRIC) { + __nlSparseMatrix_mult_cols_symmetric(A, x, y); + } else { + __nlSparseMatrix_mult_cols(A, x, y); + } + } +} + +/* ****************** Routines for least squares ******************* */ + +static void __nlSparseMatrix_square( + __NLSparseMatrix* AtA, __NLSparseMatrix *A +) { + NLuint m = A->m; + NLuint n = A->n; + NLuint i, j0, j1; + __NLRowColumn *Ri = NULL; + __NLCoeff *c0 = NULL, *c1 = NULL; + float value; + + __nlSparseMatrixConstruct(AtA, n, n, A->storage); + + for(i=0; irow[i]); + + for(j0=0; j0size; j0++) { + c0 = &(Ri->coeff[j0]); + for(j1=0; j1size; j1++) { + c1 = &(Ri->coeff[j1]); + + value = c0->value*c1->value; + __nlSparseMatrixAdd(AtA, c0->index, c1->index, value); + } + } + } +} + +static void __nlSparseMatrix_transpose_mult_rows( + __NLSparseMatrix* A, NLfloat* x, NLfloat* y +) { + NLuint m = A->m; + NLuint n = A->n; + NLuint i,ij; + __NLRowColumn* Ri = NULL; + __NLCoeff* c = NULL; + + __NL_CLEAR_ARRAY(NLfloat, y, n); + + for(i=0; irow[i]); + for(ij=0; ijsize; ij++) { + c = &(Ri->coeff[ij]); + y[c->index] += c->value * x[i]; + } + } +} + +/************************************************************************************/ +/* NLContext data structure */ + +typedef void(*__NLMatrixFunc)(float* x, float* y); + +typedef struct { + NLfloat value[4]; + NLboolean locked; + NLuint index; + __NLRowColumn *a; +} __NLVariable; + +#define __NL_STATE_INITIAL 0 +#define __NL_STATE_SYSTEM 1 +#define __NL_STATE_MATRIX 2 +#define __NL_STATE_MATRIX_CONSTRUCTED 3 +#define __NL_STATE_SYSTEM_CONSTRUCTED 4 +#define __NL_STATE_SYSTEM_SOLVED 5 + +typedef struct { + NLenum state; + NLuint n; + NLuint m; + __NLVariable* variable; + NLfloat* b; + NLfloat* Mtb; + __NLSparseMatrix M; + __NLSparseMatrix MtM; + NLfloat* x; + NLuint nb_variables; + NLuint nb_rows; + NLboolean least_squares; + NLboolean symmetric; + NLuint nb_rhs; + NLboolean solve_again; + NLboolean alloc_M; + NLboolean alloc_MtM; + NLboolean alloc_variable; + NLboolean alloc_x; + NLboolean alloc_b; + NLboolean alloc_Mtb; + NLfloat error; + __NLMatrixFunc matrix_vector_prod; + + struct __NLSuperLUContext { + NLboolean alloc_slu; + SuperMatrix L, U; + NLint *perm_c, *perm_r; + SuperLUStat_t stat; + } slu; +} __NLContext; + +static __NLContext* __nlCurrentContext = NULL; + +static void __nlMatrixVectorProd_default(NLfloat* x, NLfloat* y) { + __nlSparseMatrixMult(&(__nlCurrentContext->M), x, y); +} + + +NLContext nlNewContext(void) { + __NLContext* result = __NL_NEW(__NLContext); + result->state = __NL_STATE_INITIAL; + result->matrix_vector_prod = __nlMatrixVectorProd_default; + result->nb_rhs = 1; + nlMakeCurrent(result); + return result; +} + +static void __nlFree_SUPERLU(__NLContext *context); + +void nlDeleteContext(NLContext context_in) { + __NLContext* context = (__NLContext*)(context_in); + int i; + + if(__nlCurrentContext == context) { + __nlCurrentContext = NULL; + } + if(context->alloc_M) { + __nlSparseMatrixDestroy(&context->M); + } + if(context->alloc_MtM) { + __nlSparseMatrixDestroy(&context->MtM); + } + if(context->alloc_variable) { + for(i=0; inb_variables; i++) { + if(context->variable[i].a) { + __nlRowColumnDestroy(context->variable[i].a); + __NL_DELETE(context->variable[i].a); + } + } + } + if(context->alloc_b) { + __NL_DELETE_ARRAY(context->b); + } + if(context->alloc_Mtb) { + __NL_DELETE_ARRAY(context->Mtb); + } + if(context->alloc_x) { + __NL_DELETE_ARRAY(context->x); + } + if (context->slu.alloc_slu) { + __nlFree_SUPERLU(context); + } + +#ifdef NL_PARANOID + __NL_CLEAR(__NLContext, context); +#endif + __NL_DELETE(context); +} + +void nlMakeCurrent(NLContext context) { + __nlCurrentContext = (__NLContext*)(context); +} + +NLContext nlGetCurrent(void) { + return __nlCurrentContext; +} + +static void __nlCheckState(NLenum state) { + __nl_assert(__nlCurrentContext->state == state); +} + +static void __nlTransition(NLenum from_state, NLenum to_state) { + __nlCheckState(from_state); + __nlCurrentContext->state = to_state; +} + +/************************************************************************************/ +/* Get/Set parameters */ + +void nlSolverParameterf(NLenum pname, NLfloat param) { + __nlCheckState(__NL_STATE_INITIAL); + switch(pname) { + case NL_NB_VARIABLES: { + __nl_assert(param > 0); + __nlCurrentContext->nb_variables = (NLuint)param; + } break; + case NL_NB_ROWS: { + __nl_assert(param > 0); + __nlCurrentContext->nb_rows = (NLuint)param; + } break; + case NL_LEAST_SQUARES: { + __nlCurrentContext->least_squares = (NLboolean)param; + } break; + case NL_SYMMETRIC: { + __nlCurrentContext->symmetric = (NLboolean)param; + } break; + case NL_NB_RIGHT_HAND_SIDES: { + __nlCurrentContext->nb_rhs = (NLuint)param; + } break; + default: { + __nl_assert_not_reached; + } break; + } +} + +void nlSolverParameteri(NLenum pname, NLint param) { + __nlCheckState(__NL_STATE_INITIAL); + switch(pname) { + case NL_NB_VARIABLES: { + __nl_assert(param > 0); + __nlCurrentContext->nb_variables = (NLuint)param; + } break; + case NL_NB_ROWS: { + __nl_assert(param > 0); + __nlCurrentContext->nb_rows = (NLuint)param; + } break; + case NL_LEAST_SQUARES: { + __nlCurrentContext->least_squares = (NLboolean)param; + } break; + case NL_SYMMETRIC: { + __nlCurrentContext->symmetric = (NLboolean)param; + } break; + case NL_NB_RIGHT_HAND_SIDES: { + __nlCurrentContext->nb_rhs = (NLuint)param; + } break; + default: { + __nl_assert_not_reached; + } break; + } +} + +void nlGetBooleanv(NLenum pname, NLboolean* params) { + switch(pname) { + case NL_LEAST_SQUARES: { + *params = __nlCurrentContext->least_squares; + } break; + case NL_SYMMETRIC: { + *params = __nlCurrentContext->symmetric; + } break; + default: { + __nl_assert_not_reached; + } break; + } +} + +void nlGetFloatv(NLenum pname, NLfloat* params) { + switch(pname) { + case NL_NB_VARIABLES: { + *params = (NLfloat)(__nlCurrentContext->nb_variables); + } break; + case NL_NB_ROWS: { + *params = (NLfloat)(__nlCurrentContext->nb_rows); + } break; + case NL_LEAST_SQUARES: { + *params = (NLfloat)(__nlCurrentContext->least_squares); + } break; + case NL_SYMMETRIC: { + *params = (NLfloat)(__nlCurrentContext->symmetric); + } break; + case NL_ERROR: { + *params = (NLfloat)(__nlCurrentContext->error); + } break; + default: { + __nl_assert_not_reached; + } break; + } +} + +void nlGetIntergerv(NLenum pname, NLint* params) { + switch(pname) { + case NL_NB_VARIABLES: { + *params = (NLint)(__nlCurrentContext->nb_variables); + } break; + case NL_NB_ROWS: { + *params = (NLint)(__nlCurrentContext->nb_rows); + } break; + case NL_LEAST_SQUARES: { + *params = (NLint)(__nlCurrentContext->least_squares); + } break; + case NL_SYMMETRIC: { + *params = (NLint)(__nlCurrentContext->symmetric); + } break; + default: { + __nl_assert_not_reached; + } break; + } +} + +/************************************************************************************/ +/* Enable / Disable */ + +void nlEnable(NLenum pname) { + switch(pname) { + default: { + __nl_assert_not_reached; + } + } +} + +void nlDisable(NLenum pname) { + switch(pname) { + default: { + __nl_assert_not_reached; + } + } +} + +NLboolean nlIsEnabled(NLenum pname) { + switch(pname) { + default: { + __nl_assert_not_reached; + } + } + return NL_FALSE; +} + +/************************************************************************************/ +/* Get/Set Lock/Unlock variables */ + +void nlSetVariable(NLuint rhsindex, NLuint index, NLfloat value) { + __nlCheckState(__NL_STATE_SYSTEM); + __nl_parano_range_assert(index, 0, __nlCurrentContext->nb_variables - 1); + __nlCurrentContext->variable[index].value[rhsindex] = value; +} + +NLfloat nlGetVariable(NLuint rhsindex, NLuint index) { + __nl_assert(__nlCurrentContext->state != __NL_STATE_INITIAL); + __nl_parano_range_assert(index, 0, __nlCurrentContext->nb_variables - 1); + return __nlCurrentContext->variable[index].value[rhsindex]; +} + +void nlLockVariable(NLuint index) { + __nlCheckState(__NL_STATE_SYSTEM); + __nl_parano_range_assert(index, 0, __nlCurrentContext->nb_variables - 1); + __nlCurrentContext->variable[index].locked = NL_TRUE; +} + +void nlUnlockVariable(NLuint index) { + __nlCheckState(__NL_STATE_SYSTEM); + __nl_parano_range_assert(index, 0, __nlCurrentContext->nb_variables - 1); + __nlCurrentContext->variable[index].locked = NL_FALSE; +} + +NLboolean nlVariableIsLocked(NLuint index) { + __nl_assert(__nlCurrentContext->state != __NL_STATE_INITIAL); + __nl_parano_range_assert(index, 0, __nlCurrentContext->nb_variables - 1); + return __nlCurrentContext->variable[index].locked; +} + +/************************************************************************************/ +/* System construction */ + +static void __nlVariablesToVector() { + __NLContext *context = __nlCurrentContext; + NLuint i, j, nb_rhs; + + __nl_assert(context->alloc_x); + __nl_assert(context->alloc_variable); + + nb_rhs= context->nb_rhs; + + for(i=0; inb_variables; i++) { + __NLVariable* v = &(context->variable[i]); + if(!v->locked) { + __nl_assert(v->index < context->n); + + for(j=0; jx[context->n*j + v->index] = v->value[j]; + } + } +} + +static void __nlVectorToVariables() { + __NLContext *context = __nlCurrentContext; + NLuint i, j, nb_rhs; + + __nl_assert(context->alloc_x); + __nl_assert(context->alloc_variable); + + nb_rhs= context->nb_rhs; + + for(i=0; inb_variables; i++) { + __NLVariable* v = &(context->variable[i]); + if(!v->locked) { + __nl_assert(v->index < context->n); + + for(j=0; jvalue[j] = context->x[context->n*j + v->index]; + } + } +} + +static void __nlBeginSystem() { + __nl_assert(__nlCurrentContext->nb_variables > 0); + + if (__nlCurrentContext->solve_again) + __nlTransition(__NL_STATE_SYSTEM_SOLVED, __NL_STATE_SYSTEM); + else { + __nlTransition(__NL_STATE_INITIAL, __NL_STATE_SYSTEM); + + __nlCurrentContext->variable = __NL_NEW_ARRAY( + __NLVariable, __nlCurrentContext->nb_variables); + + __nlCurrentContext->alloc_variable = NL_TRUE; + } +} + +static void __nlEndSystem() { + __nlTransition(__NL_STATE_MATRIX_CONSTRUCTED, __NL_STATE_SYSTEM_CONSTRUCTED); +} + +static void __nlBeginMatrix() { + NLuint i; + NLuint m = 0, n = 0; + NLenum storage = __NL_ROWS; + __NLContext *context = __nlCurrentContext; + + __nlTransition(__NL_STATE_SYSTEM, __NL_STATE_MATRIX); + + if (!context->solve_again) { + for(i=0; inb_variables; i++) { + if(context->variable[i].locked) { + context->variable[i].index = ~0; + context->variable[i].a = __NL_NEW(__NLRowColumn); + __nlRowColumnConstruct(context->variable[i].a); + } + else + context->variable[i].index = n++; + } + + m = (context->nb_rows == 0)? n: context->nb_rows; + + context->m = m; + context->n = n; + + __nlSparseMatrixConstruct(&context->M, m, n, storage); + context->alloc_M = NL_TRUE; + + context->b = __NL_NEW_ARRAY(NLfloat, m*context->nb_rhs); + context->alloc_b = NL_TRUE; + + context->x = __NL_NEW_ARRAY(NLfloat, n*context->nb_rhs); + context->alloc_x = NL_TRUE; + } + else { + /* need to recompute b only, A is not constructed anymore */ + __NL_CLEAR_ARRAY(NLfloat, context->b, context->m*context->nb_rhs); + } + + __nlVariablesToVector(); +} + +static void __nlEndMatrixRHS(NLuint rhs) { + __NLContext *context = __nlCurrentContext; + __NLVariable *variable; + __NLRowColumn *a; + NLfloat *b, *Mtb; + NLuint i, j; + + b = context->b + context->m*rhs; + Mtb = context->Mtb + context->n*rhs; + + for(i=0; i<__nlCurrentContext->nb_variables; i++) { + variable = &(context->variable[i]); + + if(variable->locked) { + a = variable->a; + + for(j=0; jsize; j++) { + b[a->coeff[j].index] -= a->coeff[j].value*variable->value[rhs]; + } + } + } + + if(context->least_squares) + __nlSparseMatrix_transpose_mult_rows(&context->M, b, Mtb); +} + +static void __nlEndMatrix() { + __NLContext *context = __nlCurrentContext; + NLuint i; + + __nlTransition(__NL_STATE_MATRIX, __NL_STATE_MATRIX_CONSTRUCTED); + + if(context->least_squares) { + if(!__nlCurrentContext->solve_again) { + __nlSparseMatrix_square(&context->MtM, &context->M); + context->alloc_MtM = NL_TRUE; + + context->Mtb = + __NL_NEW_ARRAY(NLfloat, context->n*context->nb_rhs); + context->alloc_Mtb = NL_TRUE; + } + } + + for(i=0; inb_rhs; i++) + __nlEndMatrixRHS(i); +} + +void nlMatrixAdd(NLuint row, NLuint col, NLfloat value) +{ + __NLContext *context = __nlCurrentContext; + + __nlCheckState(__NL_STATE_MATRIX); + + if(context->solve_again) + return; + + if (!context->least_squares && context->variable[row].locked); + else if (context->variable[col].locked) { + if(!context->least_squares) + row = context->variable[row].index; + __nlRowColumnAppend(context->variable[col].a, row, value); + } + else { + __NLSparseMatrix* M = &context->M; + + if(!context->least_squares) + row = context->variable[row].index; + col = context->variable[col].index; + + __nl_range_assert(row, 0, context->m - 1); + __nl_range_assert(col, 0, context->n - 1); + + __nlSparseMatrixAdd(M, row, col, value); + } +} + +void nlRightHandSideAdd(NLuint rhsindex, NLuint index, NLfloat value) +{ + __NLContext *context = __nlCurrentContext; + NLfloat* b = context->b; + + __nlCheckState(__NL_STATE_MATRIX); + + if(context->least_squares) { + __nl_range_assert(index, 0, context->m - 1); + b[rhsindex*context->m + index] += value; + } + else { + if(!context->variable[index].locked) { + index = context->variable[index].index; + __nl_range_assert(index, 0, context->m - 1); + + b[rhsindex*context->m + index] += value; + } + } +} + +void nlRightHandSideSet(NLuint rhsindex, NLuint index, NLfloat value) +{ + __NLContext *context = __nlCurrentContext; + NLfloat* b = context->b; + + __nlCheckState(__NL_STATE_MATRIX); + + if(context->least_squares) { + __nl_range_assert(index, 0, context->m - 1); + b[rhsindex*context->m + index] = value; + } + else { + if(!context->variable[index].locked) { + index = context->variable[index].index; + __nl_range_assert(index, 0, context->m - 1); + + b[rhsindex*context->m + index] = value; + } + } +} + +void nlBegin(NLenum prim) { + switch(prim) { + case NL_SYSTEM: { + __nlBeginSystem(); + } break; + case NL_MATRIX: { + __nlBeginMatrix(); + } break; + default: { + __nl_assert_not_reached; + } + } +} + +void nlEnd(NLenum prim) { + switch(prim) { + case NL_SYSTEM: { + __nlEndSystem(); + } break; + case NL_MATRIX: { + __nlEndMatrix(); + } break; + default: { + __nl_assert_not_reached; + } + } +} + +/************************************************************************/ +/* SuperLU wrapper */ + +/* Note: SuperLU is difficult to call, but it is worth it. */ +/* Here is a driver inspired by A. Sheffer's "cow flattener". */ +static NLboolean __nlFactorize_SUPERLU(__NLContext *context, NLint *permutation) { + + /* OpenNL Context */ + __NLSparseMatrix* M = (context->least_squares)? &context->MtM: &context->M; + NLuint n = context->n; + NLuint nnz = __nlSparseMatrixNNZ(M); /* number of non-zero coeffs */ + + /* Compressed Row Storage matrix representation */ + NLint *xa = __NL_NEW_ARRAY(NLint, n+1); + NLfloat *rhs = __NL_NEW_ARRAY(NLfloat, n); + NLfloat *a = __NL_NEW_ARRAY(NLfloat, nnz); + NLint *asub = __NL_NEW_ARRAY(NLint, nnz); + NLint *etree = __NL_NEW_ARRAY(NLint, n); + + /* SuperLU variables */ + SuperMatrix At, AtP; + NLint info, panel_size, relax; + superlu_options_t options; + + /* Temporary variables */ + NLuint i, jj, count; + + __nl_assert(!(M->storage & __NL_SYMMETRIC)); + __nl_assert(M->storage & __NL_ROWS); + __nl_assert(M->m == M->n); + + /* Convert M to compressed column format */ + for(i=0, count=0; irow + i; + xa[i] = count; + + for(jj=0; jjsize; jj++, count++) { + a[count] = Ri->coeff[jj].value; + asub[count] = Ri->coeff[jj].index; + } + } + xa[n] = nnz; + + /* Free M, don't need it anymore at this point */ + __nlSparseMatrixClear(M); + + /* Create superlu A matrix transposed */ + sCreate_CompCol_Matrix( + &At, n, n, nnz, a, asub, xa, + SLU_NC, /* Colum wise, no supernode */ + SLU_S, /* floats */ + SLU_GE /* general storage */ + ); + + /* Set superlu options */ + set_default_options(&options); + options.ColPerm = MY_PERMC; + options.Fact = DOFACT; + + StatInit(&(context->slu.stat)); + + panel_size = sp_ienv(1); /* sp_ienv give us the defaults */ + relax = sp_ienv(2); + + /* Compute permutation and permuted matrix */ + context->slu.perm_r = __NL_NEW_ARRAY(NLint, n); + context->slu.perm_c = __NL_NEW_ARRAY(NLint, n); + + if ((permutation == NULL) || (*permutation == -1)) { + get_perm_c(3, &At, context->slu.perm_c); + + if (permutation) + memcpy(permutation, context->slu.perm_c, sizeof(NLint)*n); + } + else + memcpy(context->slu.perm_c, permutation, sizeof(NLint)*n); + + sp_preorder(&options, &At, context->slu.perm_c, etree, &AtP); + + /* Decompose into L and U */ + sgstrf(&options, &AtP, relax, panel_size, + etree, NULL, 0, context->slu.perm_c, context->slu.perm_r, + &(context->slu.L), &(context->slu.U), &(context->slu.stat), &info); + + /* Cleanup */ + + Destroy_SuperMatrix_Store(&At); + Destroy_CompCol_Permuted(&AtP); + + __NL_DELETE_ARRAY(etree); + __NL_DELETE_ARRAY(xa); + __NL_DELETE_ARRAY(rhs); + __NL_DELETE_ARRAY(a); + __NL_DELETE_ARRAY(asub); + + context->slu.alloc_slu = NL_TRUE; + + return (info == 0); +} + +static NLboolean __nlInvert_SUPERLU(__NLContext *context) { + + /* OpenNL Context */ + NLfloat* b = (context->least_squares)? context->Mtb: context->b; + NLfloat* x = context->x; + NLuint n = context->n, j; + + /* SuperLU variables */ + SuperMatrix B; + NLint info; + + for(j=0; jnb_rhs; j++, b+=n, x+=n) { + /* Create superlu array for B */ + sCreate_Dense_Matrix( + &B, n, 1, b, n, + SLU_DN, /* Fortran-type column-wise storage */ + SLU_S, /* floats */ + SLU_GE /* general */ + ); + + /* Forward/Back substitution to compute x */ + sgstrs(TRANS, &(context->slu.L), &(context->slu.U), + context->slu.perm_c, context->slu.perm_r, &B, + &(context->slu.stat), &info); + + if(info == 0) + memcpy(x, ((DNformat*)B.Store)->nzval, sizeof(*x)*n); + + Destroy_SuperMatrix_Store(&B); + } + + return (info == 0); +} + +static void __nlFree_SUPERLU(__NLContext *context) { + + Destroy_SuperNode_Matrix(&(context->slu.L)); + Destroy_CompCol_Matrix(&(context->slu.U)); + + StatFree(&(context->slu.stat)); + + __NL_DELETE_ARRAY(context->slu.perm_r); + __NL_DELETE_ARRAY(context->slu.perm_c); + + context->slu.alloc_slu = NL_FALSE; +} + +void nlPrintMatrix(void) { + __NLContext *context = __nlCurrentContext; + __NLSparseMatrix* M = &(context->M); + __NLSparseMatrix* MtM = &(context->MtM); + float *b = context->b; + NLuint i, jj, k; + NLuint m = context->m; + NLuint n = context->n; + __NLRowColumn* Ri = NULL; + float *value = malloc(sizeof(*value)*(n+m)); + + printf("A:\n"); + for(i=0; irow[i]); + + memset(value, 0.0, sizeof(*value)*n); + for(jj=0; jjsize; jj++) + value[Ri->coeff[jj].index] = Ri->coeff[jj].value; + + for (k = 0; knb_rhs; k++) { + printf("b (%d):\n", k); + for(i=0; in*k + i]); + printf("\n"); + } + + if(context->alloc_MtM) { + printf("AtA:\n"); + for(i=0; irow[i]); + + memset(value, 0.0, sizeof(*value)*m); + for(jj=0; jjsize; jj++) + value[Ri->coeff[jj].index] = Ri->coeff[jj].value; + + for (k = 0; knb_rhs; k++) { + printf("Mtb (%d):\n", k); + for(i=0; iMtb[context->n*k + i]); + printf("\n"); + } + printf("\n"); + } + + free(value); +} + +/************************************************************************/ +/* nlSolve() driver routine */ + +NLboolean nlSolveAdvanced(NLint *permutation, NLboolean solveAgain) { + NLboolean result = NL_TRUE; + + __nlCheckState(__NL_STATE_SYSTEM_CONSTRUCTED); + + if (!__nlCurrentContext->solve_again) + result = __nlFactorize_SUPERLU(__nlCurrentContext, permutation); + + if (result) { + result = __nlInvert_SUPERLU(__nlCurrentContext); + + if (result) { + __nlVectorToVariables(); + + if (solveAgain) + __nlCurrentContext->solve_again = NL_TRUE; + + __nlTransition(__NL_STATE_SYSTEM_CONSTRUCTED, __NL_STATE_SYSTEM_SOLVED); + } + } + + return result; +} + +NLboolean nlSolve() { + return nlSolveAdvanced(NULL, NL_FALSE); +} + diff --git a/intern/opennl/make/msvc_6_0/OpenNL.dsp b/intern/opennl/make/msvc_6_0/OpenNL.dsp new file mode 100644 index 00000000000..bce93059e50 --- /dev/null +++ b/intern/opennl/make/msvc_6_0/OpenNL.dsp @@ -0,0 +1,252 @@ +# Microsoft Developer Studio Project File - Name="OpenNL" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=OpenNL - 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 "OpenNL.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 "OpenNL.mak" CFG="OpenNL - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "OpenNL - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "OpenNL - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "OpenNL - 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 "../../../../obj/windows/intern/opennl" +# PROP Intermediate_Dir "../../../../obj/windows/intern/opennl/imf" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "../../extern" /I "../../superlu" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"../../../../obj/windows/intern/opennl\blender_ONL.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO copy header files XCOPY /Y ..\..\extern\*.h ..\..\..\..\..\lib\windows\opennl\include\*.h ECHO copy library XCOPY /Y ..\..\..\..\obj\windows\intern\openNL\*.lib ..\..\..\..\..\lib\windows\openNL\*.lib +# End Special Build Tool + +!ELSEIF "$(CFG)" == "OpenNL - 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 "../../../../obj/windows/intern/opennl/Debug/" +# PROP Intermediate_Dir "../../../../obj/windows/intern/opennl/imf/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 /W3 /Gm /GX /ZI /Od /I "../../extern" /I "../../superlu" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"../../../../obj/windows/intern/opennl/Debug/blender_ONL.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO copy header files XCOPY /Y ..\..\extern\*.h ..\..\..\..\..\lib\windows\opennl\include\*.h ECHO copy library XCOPY /Y ..\..\..\..\obj\windows\intern\openNL\debug\*.lib ..\..\..\..\..\lib\windows\openNL\debug\*.lib +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "OpenNL - Win32 Release" +# Name "OpenNL - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\superlu\colamd.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\get_perm_c.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\heap_relax_snode.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\lsame.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\memory.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\mmd.c +# End Source File +# Begin Source File + +SOURCE=..\..\intern\opennl.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\relax_snode.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\scolumn_bmod.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\scolumn_dfs.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\scopy_to_ucol.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\sgssv.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\sgstrf.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\sgstrs.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\smemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\smyblas2.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\sp_coletree.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\sp_ienv.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\sp_preorder.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\spanel_bmod.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\spanel_dfs.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\spivotL.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\spruneL.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\ssnode_bmod.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\ssnode_dfs.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\ssp_blas2.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\ssp_blas3.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\strsv.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\superlu_timer.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\sutil.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\util.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\xerbla.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\superlu\Cnames.h +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\colamd.h +# End Source File +# Begin Source File + +SOURCE=..\..\extern\ONL_opennl.h +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\ssp_defs.h +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\supermatrix.h +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\util.h +# End Source File +# End Group +# End Target +# End Project diff --git a/intern/opennl/make/msvc_6_0/OpenNL.dsw b/intern/opennl/make/msvc_6_0/OpenNL.dsw new file mode 100644 index 00000000000..407aeb006fd --- /dev/null +++ b/intern/opennl/make/msvc_6_0/OpenNL.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "OpenNL"=.\OpenNL.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/opennl/make/msvc_7_0/opennl.vcproj b/intern/opennl/make/msvc_7_0/opennl.vcproj new file mode 100644 index 00000000000..ec999b0c252 --- /dev/null +++ b/intern/opennl/make/msvc_7_0/opennl.vcproj @@ -0,0 +1,742 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/opennl/superlu/Cnames.h b/intern/opennl/superlu/Cnames.h new file mode 100644 index 00000000000..35ff7b0b665 --- /dev/null +++ b/intern/opennl/superlu/Cnames.h @@ -0,0 +1,281 @@ +/* + * -- SuperLU routine (version 2.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * November 1, 1997 + * + */ +#ifndef __SUPERLU_CNAMES /* allow multiple inclusions */ +#define __SUPERLU_CNAMES + +/* We want this flag, safer than putting in build system */ +#define Add_ + +/* + * These macros define how C routines will be called. ADD_ assumes that + * they will be called by fortran, which expects C routines to have an + * underscore postfixed to the name (Suns, and the Intel expect this). + * NOCHANGE indicates that fortran will be calling, and that it expects + * the name called by fortran to be identical to that compiled by the C + * (RS6K's do this). UPCASE says it expects C routines called by fortran + * to be in all upcase (CRAY wants this). + */ + +#define ADD_ 0 +#define ADD__ 1 +#define NOCHANGE 2 +#define UPCASE 3 +#define C_CALL 4 + +#ifdef UpCase +#define F77_CALL_C UPCASE +#endif + +#ifdef NoChange +#define F77_CALL_C NOCHANGE +#endif + +#ifdef Add_ +#define F77_CALL_C ADD_ +#endif + +#ifdef Add__ +#define F77_CALL_C ADD__ +#endif + +/* Default */ +#ifndef F77_CALL_C +#define F77_CALL_C ADD_ +#endif + + +#if (F77_CALL_C == ADD_) +/* + * These defines set up the naming scheme required to have a fortran 77 + * routine call a C routine + * No redefinition necessary to have following Fortran to C interface: + * FORTRAN CALL C DECLARATION + * call dgemm(...) void dgemm_(...) + * + * This is the default. + */ + +#endif + +#if (F77_CALL_C == ADD__) +/* + * These defines set up the naming scheme required to have a fortran 77 + * routine call a C routine + * for following Fortran to C interface: + * FORTRAN CALL C DECLARATION + * call dgemm(...) void dgemm__(...) + */ +#define sasum_ sasum__ +#define isamax_ isamax__ +#define scopy_ scopy__ +#define sscal_ sscal__ +#define sger_ sger__ +#define snrm2_ snrm2__ +#define ssymv_ ssymv__ +#define sdot_ sdot__ +#define saxpy_ saxpy__ +#define ssyr2_ ssyr2__ +#define srot_ srot__ +#define sgemv_ sgemv__ +#define strsv_ strsv__ +#define sgemm_ sgemm__ +#define strsm_ strsm__ + +#define dasum_ dasum__ +#define idamax_ idamax__ +#define dcopy_ dcopy__ +#define dscal_ dscal__ +#define dger_ dger__ +#define dnrm2_ dnrm2__ +#define dsymv_ dsymv__ +#define ddot_ ddot__ +#define daxpy_ daxpy__ +#define dsyr2_ dsyr2__ +#define drot_ drot__ +#define dgemv_ dgemv__ +#define dtrsv_ dtrsv__ +#define dgemm_ dgemm__ +#define dtrsm_ dtrsm__ + +#define scasum_ scasum__ +#define icamax_ icamax__ +#define ccopy_ ccopy__ +#define cscal_ cscal__ +#define scnrm2_ scnrm2__ +#define caxpy_ caxpy__ +#define cgemv_ cgemv__ +#define ctrsv_ ctrsv__ +#define cgemm_ cgemm__ +#define ctrsm_ ctrsm__ +#define cgerc_ cgerc__ +#define chemv_ chemv__ +#define cher2_ cher2__ + +#define dzasum_ dzasum__ +#define izamax_ izamax__ +#define zcopy_ zcopy__ +#define zscal_ zscal__ +#define dznrm2_ dznrm2__ +#define zaxpy_ zaxpy__ +#define zgemv_ zgemv__ +#define ztrsv_ ztrsv__ +#define zgemm_ zgemm__ +#define ztrsm_ ztrsm__ +#define zgerc_ zgerc__ +#define zhemv_ zhemv__ +#define zher2_ zher2__ + +#define c_bridge_dgssv_ c_bridge_dgssv__ +#define c_fortran_dgssv_ c_fortran_dgssv__ +#endif + +#if (F77_CALL_C == UPCASE) +/* + * These defines set up the naming scheme required to have a fortran 77 + * routine call a C routine + * following Fortran to C interface: + * FORTRAN CALL C DECLARATION + * call dgemm(...) void DGEMM(...) + */ +#define sasum_ SASUM +#define isamax_ ISAMAX +#define scopy_ SCOPY +#define sscal_ SSCAL +#define sger_ SGER +#define snrm2_ SNRM2 +#define ssymv_ SSYMV +#define sdot_ SDOT +#define saxpy_ SAXPY +#define ssyr2_ SSYR2 +#define srot_ SROT +#define sgemv_ SGEMV +#define strsv_ STRSV +#define sgemm_ SGEMM +#define strsm_ STRSM + +#define dasum_ SASUM +#define idamax_ ISAMAX +#define dcopy_ SCOPY +#define dscal_ SSCAL +#define dger_ SGER +#define dnrm2_ SNRM2 +#define dsymv_ SSYMV +#define ddot_ SDOT +#define daxpy_ SAXPY +#define dsyr2_ SSYR2 +#define drot_ SROT +#define dgemv_ SGEMV +#define dtrsv_ STRSV +#define dgemm_ SGEMM +#define dtrsm_ STRSM + +#define scasum_ SCASUM +#define icamax_ ICAMAX +#define ccopy_ CCOPY +#define cscal_ CSCAL +#define scnrm2_ SCNRM2 +#define caxpy_ CAXPY +#define cgemv_ CGEMV +#define ctrsv_ CTRSV +#define cgemm_ CGEMM +#define ctrsm_ CTRSM +#define cgerc_ CGERC +#define chemv_ CHEMV +#define cher2_ CHER2 + +#define dzasum_ SCASUM +#define izamax_ ICAMAX +#define zcopy_ CCOPY +#define zscal_ CSCAL +#define dznrm2_ SCNRM2 +#define zaxpy_ CAXPY +#define zgemv_ CGEMV +#define ztrsv_ CTRSV +#define zgemm_ CGEMM +#define ztrsm_ CTRSM +#define zgerc_ CGERC +#define zhemv_ CHEMV +#define zher2_ CHER2 + +#define c_bridge_dgssv_ C_BRIDGE_DGSSV +#define c_fortran_dgssv_ C_FORTRAN_DGSSV +#endif + +#if (F77_CALL_C == NOCHANGE) +/* + * These defines set up the naming scheme required to have a fortran 77 + * routine call a C routine + * for following Fortran to C interface: + * FORTRAN CALL C DECLARATION + * call dgemm(...) void dgemm(...) + */ +#define sasum_ sasum +#define isamax_ isamax +#define scopy_ scopy +#define sscal_ sscal +#define sger_ sger +#define snrm2_ snrm2 +#define ssymv_ ssymv +#define sdot_ sdot +#define saxpy_ saxpy +#define ssyr2_ ssyr2 +#define srot_ srot +#define sgemv_ sgemv +#define strsv_ strsv +#define sgemm_ sgemm +#define strsm_ strsm + +#define dasum_ dasum +#define idamax_ idamax +#define dcopy_ dcopy +#define dscal_ dscal +#define dger_ dger +#define dnrm2_ dnrm2 +#define dsymv_ dsymv +#define ddot_ ddot +#define daxpy_ daxpy +#define dsyr2_ dsyr2 +#define drot_ drot +#define dgemv_ dgemv +#define dtrsv_ dtrsv +#define dgemm_ dgemm +#define dtrsm_ dtrsm + +#define scasum_ scasum +#define icamax_ icamax +#define ccopy_ ccopy +#define cscal_ cscal +#define scnrm2_ scnrm2 +#define caxpy_ caxpy +#define cgemv_ cgemv +#define ctrsv_ ctrsv +#define cgemm_ cgemm +#define ctrsm_ ctrsm +#define cgerc_ cgerc +#define chemv_ chemv +#define cher2_ cher2 + +#define dzasum_ dzasum +#define izamax_ izamax +#define zcopy_ zcopy +#define zscal_ zscal +#define dznrm2_ dznrm2 +#define zaxpy_ zaxpy +#define zgemv_ zgemv +#define ztrsv_ ztrsv +#define zgemm_ zgemm +#define ztrsm_ ztrsm +#define zgerc_ zgerc +#define zhemv_ zhemv +#define zher2_ zher2 + +#define c_bridge_dgssv_ c_bridge_dgssv +#define c_fortran_dgssv_ c_fortran_dgssv +#endif + +#endif /* __SUPERLU_CNAMES */ diff --git a/intern/opennl/superlu/Makefile b/intern/opennl/superlu/Makefile new file mode 100644 index 00000000000..942ceebc79c --- /dev/null +++ b/intern/opennl/superlu/Makefile @@ -0,0 +1,40 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# opennl intern Makefile +# + +LIBNAME = superlu +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(NAN_LEVEL_2_CPP_WARNINGS) + diff --git a/intern/opennl/superlu/colamd.c b/intern/opennl/superlu/colamd.c new file mode 100644 index 00000000000..b60718f9938 --- /dev/null +++ b/intern/opennl/superlu/colamd.c @@ -0,0 +1,2583 @@ +/* ========================================================================== */ +/* === colamd - a sparse matrix column ordering algorithm =================== */ +/* ========================================================================== */ + +/* + colamd: An approximate minimum degree column ordering algorithm. + + Purpose: + + Colamd computes a permutation Q such that the Cholesky factorization of + (AQ)'(AQ) has less fill-in and requires fewer floating point operations + than A'A. This also provides a good ordering for sparse partial + pivoting methods, P(AQ) = LU, where Q is computed prior to numerical + factorization, and P is computed during numerical factorization via + conventional partial pivoting with row interchanges. Colamd is the + column ordering method used in SuperLU, part of the ScaLAPACK library. + It is also available as user-contributed software for Matlab 5.2, + available from MathWorks, Inc. (http://www.mathworks.com). This + routine can be used in place of COLMMD in Matlab. By default, the \ + and / operators in Matlab perform a column ordering (using COLMMD) + prior to LU factorization using sparse partial pivoting, in the + built-in Matlab LU(A) routine. + + Authors: + + The authors of the code itself are Stefan I. Larimore and Timothy A. + Davis (davis@cise.ufl.edu), University of Florida. The algorithm was + developed in collaboration with John Gilbert, Xerox PARC, and Esmond + Ng, Oak Ridge National Laboratory. + + Date: + + August 3, 1998. Version 1.0. + + Acknowledgements: + + This work was supported by the National Science Foundation, under + grants DMS-9504974 and DMS-9803599. + + Notice: + + Copyright (c) 1998 by the University of Florida. All Rights Reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + User documentation of any code that uses this code must cite the + Authors, the Copyright, and "Used by permission." If this code is + accessible from within Matlab, then typing "help colamd" or "colamd" + (with no arguments) must cite the Authors. Permission to modify the + code and to distribute modified code is granted, provided the above + notices are retained, and a notice that the code was modified is + included with the above copyright notice. You must also retain the + Availability information below, of the original version. + + This software is provided free of charge. + + Availability: + + This file is located at + + http://www.cise.ufl.edu/~davis/colamd/colamd.c + + The colamd.h file is required, located in the same directory. + The colamdmex.c file provides a Matlab interface for colamd. + The symamdmex.c file provides a Matlab interface for symamd, which is + a symmetric ordering based on this code, colamd.c. All codes are + purely ANSI C compliant (they use no Unix-specific routines, include + files, etc.). +*/ + +/* ========================================================================== */ +/* === Description of user-callable routines ================================ */ +/* ========================================================================== */ + +/* + Each user-callable routine (declared as PUBLIC) is briefly described below. + Refer to the comments preceding each routine for more details. + + ---------------------------------------------------------------------------- + colamd_recommended: + ---------------------------------------------------------------------------- + + Usage: + + Alen = colamd_recommended (nnz, n_row, n_col) ; + + Purpose: + + Returns recommended value of Alen for use by colamd. Returns -1 + if any input argument is negative. + + Arguments: + + int nnz ; Number of nonzeros in the matrix A. This must + be the same value as p [n_col] in the call to + colamd - otherwise you will get a wrong value + of the recommended memory to use. + int n_row ; Number of rows in the matrix A. + int n_col ; Number of columns in the matrix A. + + ---------------------------------------------------------------------------- + colamd_set_defaults: + ---------------------------------------------------------------------------- + + Usage: + + colamd_set_defaults (knobs) ; + + Purpose: + + Sets the default parameters. + + Arguments: + + double knobs [COLAMD_KNOBS] ; Output only. + + Rows with more than (knobs [COLAMD_DENSE_ROW] * n_col) entries + are removed prior to ordering. Columns with more than + (knobs [COLAMD_DENSE_COL] * n_row) entries are removed + prior to ordering, and placed last in the output column + ordering. Default values of these two knobs are both 0.5. + Currently, only knobs [0] and knobs [1] are used, but future + versions may use more knobs. If so, they will be properly set + to their defaults by the future version of colamd_set_defaults, + so that the code that calls colamd will not need to change, + assuming that you either use colamd_set_defaults, or pass a + (double *) NULL pointer as the knobs array to colamd. + + ---------------------------------------------------------------------------- + colamd: + ---------------------------------------------------------------------------- + + Usage: + + colamd (n_row, n_col, Alen, A, p, knobs) ; + + Purpose: + + Computes a column ordering (Q) of A such that P(AQ)=LU or + (AQ)'AQ=LL' have less fill-in and require fewer floating point + operations than factorizing the unpermuted matrix A or A'A, + respectively. + + Arguments: + + int n_row ; + + Number of rows in the matrix A. + Restriction: n_row >= 0. + Colamd returns FALSE if n_row is negative. + + int n_col ; + + Number of columns in the matrix A. + Restriction: n_col >= 0. + Colamd returns FALSE if n_col is negative. + + int Alen ; + + Restriction (see note): + Alen >= 2*nnz + 6*(n_col+1) + 4*(n_row+1) + n_col + COLAMD_STATS + Colamd returns FALSE if these conditions are not met. + + Note: this restriction makes an modest assumption regarding + the size of the two typedef'd structures, below. We do, + however, guarantee that + Alen >= colamd_recommended (nnz, n_row, n_col) + will be sufficient. + + int A [Alen] ; Input argument, stats on output. + + A is an integer array of size Alen. Alen must be at least as + large as the bare minimum value given above, but this is very + low, and can result in excessive run time. For best + performance, we recommend that Alen be greater than or equal to + colamd_recommended (nnz, n_row, n_col), which adds + nnz/5 to the bare minimum value given above. + + On input, the row indices of the entries in column c of the + matrix are held in A [(p [c]) ... (p [c+1]-1)]. The row indices + in a given column c need not be in ascending order, and + duplicate row indices may be be present. However, colamd will + work a little faster if both of these conditions are met + (Colamd puts the matrix into this format, if it finds that the + the conditions are not met). + + The matrix is 0-based. That is, rows are in the range 0 to + n_row-1, and columns are in the range 0 to n_col-1. Colamd + returns FALSE if any row index is out of range. + + The contents of A are modified during ordering, and are thus + undefined on output with the exception of a few statistics + about the ordering (A [0..COLAMD_STATS-1]): + A [0]: number of dense or empty rows ignored. + A [1]: number of dense or empty columns ignored (and ordered + last in the output permutation p) + A [2]: number of garbage collections performed. + A [3]: 0, if all row indices in each column were in sorted + order, and no duplicates were present. + 1, otherwise (in which case colamd had to do more work) + Note that a row can become "empty" if it contains only + "dense" and/or "empty" columns, and similarly a column can + become "empty" if it only contains "dense" and/or "empty" rows. + Future versions may return more statistics in A, but the usage + of these 4 entries in A will remain unchanged. + + int p [n_col+1] ; Both input and output argument. + + p is an integer array of size n_col+1. On input, it holds the + "pointers" for the column form of the matrix A. Column c of + the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first + entry, p [0], must be zero, and p [c] <= p [c+1] must hold + for all c in the range 0 to n_col-1. The value p [n_col] is + thus the total number of entries in the pattern of the matrix A. + Colamd returns FALSE if these conditions are not met. + + On output, if colamd returns TRUE, the array p holds the column + permutation (Q, for P(AQ)=LU or (AQ)'(AQ)=LL'), where p [0] is + the first column index in the new ordering, and p [n_col-1] is + the last. That is, p [k] = j means that column j of A is the + kth pivot column, in AQ, where k is in the range 0 to n_col-1 + (p [0] = j means that column j of A is the first column in AQ). + + If colamd returns FALSE, then no permutation is returned, and + p is undefined on output. + + double knobs [COLAMD_KNOBS] ; Input only. + + See colamd_set_defaults for a description. If the knobs array + is not present (that is, if a (double *) NULL pointer is passed + in its place), then the default values of the parameters are + used instead. + +*/ + + +/* ========================================================================== */ +/* === Include files ======================================================== */ +/* ========================================================================== */ + +/* limits.h: the largest positive integer (INT_MAX) */ +#include + +/* colamd.h: knob array size, stats output size, and global prototypes */ +#include "colamd.h" + +/* ========================================================================== */ +/* === Scaffolding code definitions ======================================== */ +/* ========================================================================== */ + +/* Ensure that debugging is turned off: */ +#ifndef NDEBUG +#define NDEBUG +#endif + +/* assert.h: the assert macro (no debugging if NDEBUG is defined) */ +#include + +/* + Our "scaffolding code" philosophy: In our opinion, well-written library + code should keep its "debugging" code, and just normally have it turned off + by the compiler so as not to interfere with performance. This serves + several purposes: + + (1) assertions act as comments to the reader, telling you what the code + expects at that point. All assertions will always be true (unless + there really is a bug, of course). + + (2) leaving in the scaffolding code assists anyone who would like to modify + the code, or understand the algorithm (by reading the debugging output, + one can get a glimpse into what the code is doing). + + (3) (gasp!) for actually finding bugs. This code has been heavily tested + and "should" be fully functional and bug-free ... but you never know... + + To enable debugging, comment out the "#define NDEBUG" above. The code will + become outrageously slow when debugging is enabled. To control the level of + debugging output, set an environment variable D to 0 (little), 1 (some), + 2, 3, or 4 (lots). +*/ + +/* ========================================================================== */ +/* === Row and Column structures ============================================ */ +/* ========================================================================== */ + +typedef struct ColInfo_struct +{ + int start ; /* index for A of first row in this column, or DEAD */ + /* if column is dead */ + int length ; /* number of rows in this column */ + union + { + int thickness ; /* number of original columns represented by this */ + /* col, if the column is alive */ + int parent ; /* parent in parent tree super-column structure, if */ + /* the column is dead */ + } shared1 ; + union + { + int score ; /* the score used to maintain heap, if col is alive */ + int order ; /* pivot ordering of this column, if col is dead */ + } shared2 ; + union + { + int headhash ; /* head of a hash bucket, if col is at the head of */ + /* a degree list */ + int hash ; /* hash value, if col is not in a degree list */ + int prev ; /* previous column in degree list, if col is in a */ + /* degree list (but not at the head of a degree list) */ + } shared3 ; + union + { + int degree_next ; /* next column, if col is in a degree list */ + int hash_next ; /* next column, if col is in a hash list */ + } shared4 ; + +} ColInfo ; + +typedef struct RowInfo_struct +{ + int start ; /* index for A of first col in this row */ + int length ; /* number of principal columns in this row */ + union + { + int degree ; /* number of principal & non-principal columns in row */ + int p ; /* used as a row pointer in init_rows_cols () */ + } shared1 ; + union + { + int mark ; /* for computing set differences and marking dead rows*/ + int first_column ;/* first column in row (used in garbage collection) */ + } shared2 ; + +} RowInfo ; + +/* ========================================================================== */ +/* === Definitions ========================================================== */ +/* ========================================================================== */ + +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +#define ONES_COMPLEMENT(r) (-(r)-1) + +#define TRUE (1) +#define FALSE (0) +#define EMPTY (-1) + +/* Row and column status */ +#define ALIVE (0) +#define DEAD (-1) + +/* Column status */ +#define DEAD_PRINCIPAL (-1) +#define DEAD_NON_PRINCIPAL (-2) + +/* Macros for row and column status update and checking. */ +#define ROW_IS_DEAD(r) ROW_IS_MARKED_DEAD (Row[r].shared2.mark) +#define ROW_IS_MARKED_DEAD(row_mark) (row_mark < ALIVE) +#define ROW_IS_ALIVE(r) (Row [r].shared2.mark >= ALIVE) +#define COL_IS_DEAD(c) (Col [c].start < ALIVE) +#define COL_IS_ALIVE(c) (Col [c].start >= ALIVE) +#define COL_IS_DEAD_PRINCIPAL(c) (Col [c].start == DEAD_PRINCIPAL) +#define KILL_ROW(r) { Row [r].shared2.mark = DEAD ; } +#define KILL_PRINCIPAL_COL(c) { Col [c].start = DEAD_PRINCIPAL ; } +#define KILL_NON_PRINCIPAL_COL(c) { Col [c].start = DEAD_NON_PRINCIPAL ; } + +/* Routines are either PUBLIC (user-callable) or PRIVATE (not user-callable) */ +#define PUBLIC +#define PRIVATE static + +/* ========================================================================== */ +/* === Prototypes of PRIVATE routines ======================================= */ +/* ========================================================================== */ + +PRIVATE int init_rows_cols +( + int n_row, + int n_col, + RowInfo Row [], + ColInfo Col [], + int A [], + int p [] +) ; + +PRIVATE void init_scoring +( + int n_row, + int n_col, + RowInfo Row [], + ColInfo Col [], + int A [], + int head [], + double knobs [COLAMD_KNOBS], + int *p_n_row2, + int *p_n_col2, + int *p_max_deg +) ; + +PRIVATE int find_ordering +( + int n_row, + int n_col, + int Alen, + RowInfo Row [], + ColInfo Col [], + int A [], + int head [], + int n_col2, + int max_deg, + int pfree +) ; + +PRIVATE void order_children +( + int n_col, + ColInfo Col [], + int p [] +) ; + +PRIVATE void detect_super_cols +( +#ifndef NDEBUG + int n_col, + RowInfo Row [], +#endif + ColInfo Col [], + int A [], + int head [], + int row_start, + int row_length +) ; + +PRIVATE int garbage_collection +( + int n_row, + int n_col, + RowInfo Row [], + ColInfo Col [], + int A [], + int *pfree +) ; + +PRIVATE int clear_mark +( + int n_row, + RowInfo Row [] +) ; + +/* ========================================================================== */ +/* === Debugging definitions ================================================ */ +/* ========================================================================== */ + +#ifndef NDEBUG + +/* === With debugging ======================================================= */ + +/* stdlib.h: for getenv and atoi, to get debugging level from environment */ +#include + +/* stdio.h: for printf (no printing if debugging is turned off) */ +#include + +PRIVATE void debug_deg_lists +( + int n_row, + int n_col, + RowInfo Row [], + ColInfo Col [], + int head [], + int min_score, + int should, + int max_deg +) ; + +PRIVATE void debug_mark +( + int n_row, + RowInfo Row [], + int tag_mark, + int max_mark +) ; + +PRIVATE void debug_matrix +( + int n_row, + int n_col, + RowInfo Row [], + ColInfo Col [], + int A [] +) ; + +PRIVATE void debug_structures +( + int n_row, + int n_col, + RowInfo Row [], + ColInfo Col [], + int A [], + int n_col2 +) ; + +/* the following is the *ONLY* global variable in this file, and is only */ +/* present when debugging */ + +PRIVATE int debug_colamd ; /* debug print level */ + +#define DEBUG0(params) { (void) printf params ; } +#define DEBUG1(params) { if (debug_colamd >= 1) (void) printf params ; } +#define DEBUG2(params) { if (debug_colamd >= 2) (void) printf params ; } +#define DEBUG3(params) { if (debug_colamd >= 3) (void) printf params ; } +#define DEBUG4(params) { if (debug_colamd >= 4) (void) printf params ; } + +#else + +/* === No debugging ========================================================= */ + +#define DEBUG0(params) ; +#define DEBUG1(params) ; +#define DEBUG2(params) ; +#define DEBUG3(params) ; +#define DEBUG4(params) ; + +#endif + +/* ========================================================================== */ + + +/* ========================================================================== */ +/* === USER-CALLABLE ROUTINES: ============================================== */ +/* ========================================================================== */ + + +/* ========================================================================== */ +/* === colamd_recommended =================================================== */ +/* ========================================================================== */ + +/* + The colamd_recommended routine returns the suggested size for Alen. This + value has been determined to provide good balance between the number of + garbage collections and the memory requirements for colamd. +*/ + +PUBLIC int colamd_recommended /* returns recommended value of Alen. */ +( + /* === Parameters ======================================================= */ + + int nnz, /* number of nonzeros in A */ + int n_row, /* number of rows in A */ + int n_col /* number of columns in A */ +) +{ + /* === Local variables ================================================== */ + + int minimum ; /* bare minimum requirements */ + int recommended ; /* recommended value of Alen */ + + if (nnz < 0 || n_row < 0 || n_col < 0) + { + /* return -1 if any input argument is corrupted */ + DEBUG0 (("colamd_recommended error!")) ; + DEBUG0 ((" nnz: %d, n_row: %d, n_col: %d\n", nnz, n_row, n_col)) ; + return (-1) ; + } + + minimum = + 2 * (nnz) /* for A */ + + (((n_col) + 1) * sizeof (ColInfo) / sizeof (int)) /* for Col */ + + (((n_row) + 1) * sizeof (RowInfo) / sizeof (int)) /* for Row */ + + n_col /* minimum elbow room to guarrantee success */ + + COLAMD_STATS ; /* for output statistics */ + + /* recommended is equal to the minumum plus enough memory to keep the */ + /* number garbage collections low */ + recommended = minimum + nnz/5 ; + + return (recommended) ; +} + + +/* ========================================================================== */ +/* === colamd_set_defaults ================================================== */ +/* ========================================================================== */ + +/* + The colamd_set_defaults routine sets the default values of the user- + controllable parameters for colamd: + + knobs [0] rows with knobs[0]*n_col entries or more are removed + prior to ordering. + + knobs [1] columns with knobs[1]*n_row entries or more are removed + prior to ordering, and placed last in the column + permutation. + + knobs [2..19] unused, but future versions might use this +*/ + +PUBLIC void colamd_set_defaults +( + /* === Parameters ======================================================= */ + + double knobs [COLAMD_KNOBS] /* knob array */ +) +{ + /* === Local variables ================================================== */ + + int i ; + + if (!knobs) + { + return ; /* no knobs to initialize */ + } + for (i = 0 ; i < COLAMD_KNOBS ; i++) + { + knobs [i] = 0 ; + } + knobs [COLAMD_DENSE_ROW] = 0.5 ; /* ignore rows over 50% dense */ + knobs [COLAMD_DENSE_COL] = 0.5 ; /* ignore columns over 50% dense */ +} + + +/* ========================================================================== */ +/* === colamd =============================================================== */ +/* ========================================================================== */ + +/* + The colamd routine computes a column ordering Q of a sparse matrix + A such that the LU factorization P(AQ) = LU remains sparse, where P is + selected via partial pivoting. The routine can also be viewed as + providing a permutation Q such that the Cholesky factorization + (AQ)'(AQ) = LL' remains sparse. + + On input, the nonzero patterns of the columns of A are stored in the + array A, in order 0 to n_col-1. A is held in 0-based form (rows in the + range 0 to n_row-1 and columns in the range 0 to n_col-1). Row indices + for column c are located in A [(p [c]) ... (p [c+1]-1)], where p [0] = 0, + and thus p [n_col] is the number of entries in A. The matrix is + destroyed on output. The row indices within each column do not have to + be sorted (from small to large row indices), and duplicate row indices + may be present. However, colamd will work a little faster if columns are + sorted and no duplicates are present. Matlab 5.2 always passes the matrix + with sorted columns, and no duplicates. + + The integer array A is of size Alen. Alen must be at least of size + (where nnz is the number of entries in A): + + nnz for the input column form of A + + nnz for a row form of A that colamd generates + + 6*(n_col+1) for a ColInfo Col [0..n_col] array + (this assumes sizeof (ColInfo) is 6 int's). + + 4*(n_row+1) for a RowInfo Row [0..n_row] array + (this assumes sizeof (RowInfo) is 4 int's). + + elbow_room must be at least n_col. We recommend at least + nnz/5 in addition to that. If sufficient, + changes in the elbow room affect the ordering + time only, not the ordering itself. + + COLAMD_STATS for the output statistics + + Colamd returns FALSE is memory is insufficient, or TRUE otherwise. + + On input, the caller must specify: + + n_row the number of rows of A + n_col the number of columns of A + Alen the size of the array A + A [0 ... nnz-1] the row indices, where nnz = p [n_col] + A [nnz ... Alen-1] (need not be initialized by the user) + p [0 ... n_col] the column pointers, p [0] = 0, and p [n_col] + is the number of entries in A. Column c of A + is stored in A [p [c] ... p [c+1]-1]. + knobs [0 ... 19] a set of parameters that control the behavior + of colamd. If knobs is a NULL pointer the + defaults are used. The user-callable + colamd_set_defaults routine sets the default + parameters. See that routine for a description + of the user-controllable parameters. + + If the return value of Colamd is TRUE, then on output: + + p [0 ... n_col-1] the column permutation. p [0] is the first + column index, and p [n_col-1] is the last. + That is, p [k] = j means that column j of A + is the kth column of AQ. + + A is undefined on output (the matrix pattern is + destroyed), except for the following statistics: + + A [0] the number of dense (or empty) rows ignored + A [1] the number of dense (or empty) columms. These + are ordered last, in their natural order. + A [2] the number of garbage collections performed. + If this is excessive, then you would have + gotten your results faster if Alen was larger. + A [3] 0, if all row indices in each column were in + sorted order and no duplicates were present. + 1, if there were unsorted or duplicate row + indices in the input. You would have gotten + your results faster if A [3] was returned as 0. + + If the return value of Colamd is FALSE, then A and p are undefined on + output. +*/ + +PUBLIC int colamd /* returns TRUE if successful */ +( + /* === Parameters ======================================================= */ + + int n_row, /* number of rows in A */ + int n_col, /* number of columns in A */ + int Alen, /* length of A */ + int A [], /* row indices of A */ + int p [], /* pointers to columns in A */ + double knobs [COLAMD_KNOBS] /* parameters (uses defaults if NULL) */ +) +{ + /* === Local variables ================================================== */ + + int i ; /* loop index */ + int nnz ; /* nonzeros in A */ + int Row_size ; /* size of Row [], in integers */ + int Col_size ; /* size of Col [], in integers */ + int elbow_room ; /* remaining free space */ + RowInfo *Row ; /* pointer into A of Row [0..n_row] array */ + ColInfo *Col ; /* pointer into A of Col [0..n_col] array */ + int n_col2 ; /* number of non-dense, non-empty columns */ + int n_row2 ; /* number of non-dense, non-empty rows */ + int ngarbage ; /* number of garbage collections performed */ + int max_deg ; /* maximum row degree */ + double default_knobs [COLAMD_KNOBS] ; /* default knobs knobs array */ + int init_result ; /* return code from initialization */ + +#ifndef NDEBUG + debug_colamd = 0 ; /* no debug printing */ + /* get "D" environment variable, which gives the debug printing level */ + if (getenv ("D")) debug_colamd = atoi (getenv ("D")) ; + DEBUG0 (("debug version, D = %d (THIS WILL BE SLOOOOW!)\n", debug_colamd)) ; +#endif + + /* === Check the input arguments ======================================== */ + + if (n_row < 0 || n_col < 0 || !A || !p) + { + /* n_row and n_col must be non-negative, A and p must be present */ + DEBUG0 (("colamd error! %d %d %d\n", n_row, n_col, Alen)) ; + return (FALSE) ; + } + nnz = p [n_col] ; + if (nnz < 0 || p [0] != 0) + { + /* nnz must be non-negative, and p [0] must be zero */ + DEBUG0 (("colamd error! %d %d\n", nnz, p [0])) ; + return (FALSE) ; + } + + /* === If no knobs, set default parameters ============================== */ + + if (!knobs) + { + knobs = default_knobs ; + colamd_set_defaults (knobs) ; + } + + /* === Allocate the Row and Col arrays from array A ===================== */ + + Col_size = (n_col + 1) * sizeof (ColInfo) / sizeof (int) ; + Row_size = (n_row + 1) * sizeof (RowInfo) / sizeof (int) ; + elbow_room = Alen - (2*nnz + Col_size + Row_size) ; + if (elbow_room < n_col + COLAMD_STATS) + { + /* not enough space in array A to perform the ordering */ + DEBUG0 (("colamd error! elbow_room %d, %d\n", elbow_room,n_col)) ; + return (FALSE) ; + } + Alen = 2*nnz + elbow_room ; + Col = (ColInfo *) &A [Alen] ; + Row = (RowInfo *) &A [Alen + Col_size] ; + + /* === Construct the row and column data structures ===================== */ + + init_result = init_rows_cols (n_row, n_col, Row, Col, A, p) ; + if (init_result == -1) + { + /* input matrix is invalid */ + DEBUG0 (("colamd error! matrix invalid\n")) ; + return (FALSE) ; + } + + /* === Initialize scores, kill dense rows/columns ======================= */ + + init_scoring (n_row, n_col, Row, Col, A, p, knobs, + &n_row2, &n_col2, &max_deg) ; + + /* === Order the supercolumns =========================================== */ + + ngarbage = find_ordering (n_row, n_col, Alen, Row, Col, A, p, + n_col2, max_deg, 2*nnz) ; + + /* === Order the non-principal columns ================================== */ + + order_children (n_col, Col, p) ; + + /* === Return statistics in A =========================================== */ + + for (i = 0 ; i < COLAMD_STATS ; i++) + { + A [i] = 0 ; + } + A [COLAMD_DENSE_ROW] = n_row - n_row2 ; + A [COLAMD_DENSE_COL] = n_col - n_col2 ; + A [COLAMD_DEFRAG_COUNT] = ngarbage ; + A [COLAMD_JUMBLED_COLS] = init_result ; + + return (TRUE) ; +} + + +/* ========================================================================== */ +/* === NON-USER-CALLABLE ROUTINES: ========================================== */ +/* ========================================================================== */ + +/* There are no user-callable routines beyond this point in the file */ + + +/* ========================================================================== */ +/* === init_rows_cols ======================================================= */ +/* ========================================================================== */ + +/* + Takes the column form of the matrix in A and creates the row form of the + matrix. Also, row and column attributes are stored in the Col and Row + structs. If the columns are un-sorted or contain duplicate row indices, + this routine will also sort and remove duplicate row indices from the + column form of the matrix. Returns -1 on error, 1 if columns jumbled, + or 0 if columns not jumbled. Not user-callable. +*/ + +PRIVATE int init_rows_cols /* returns status code */ +( + /* === Parameters ======================================================= */ + + int n_row, /* number of rows of A */ + int n_col, /* number of columns of A */ + RowInfo Row [], /* of size n_row+1 */ + ColInfo Col [], /* of size n_col+1 */ + int A [], /* row indices of A, of size Alen */ + int p [] /* pointers to columns in A, of size n_col+1 */ +) +{ + /* === Local variables ================================================== */ + + int col ; /* a column index */ + int row ; /* a row index */ + int *cp ; /* a column pointer */ + int *cp_end ; /* a pointer to the end of a column */ + int *rp ; /* a row pointer */ + int *rp_end ; /* a pointer to the end of a row */ + int last_start ; /* start index of previous column in A */ + int start ; /* start index of column in A */ + int last_row ; /* previous row */ + int jumbled_columns ; /* indicates if columns are jumbled */ + + /* === Initialize columns, and check column pointers ==================== */ + + last_start = 0 ; + for (col = 0 ; col < n_col ; col++) + { + start = p [col] ; + if (start < last_start) + { + /* column pointers must be non-decreasing */ + DEBUG0 (("colamd error! last p %d p [col] %d\n",last_start,start)); + return (-1) ; + } + Col [col].start = start ; + Col [col].length = p [col+1] - start ; + Col [col].shared1.thickness = 1 ; + Col [col].shared2.score = 0 ; + Col [col].shared3.prev = EMPTY ; + Col [col].shared4.degree_next = EMPTY ; + last_start = start ; + } + /* must check the end pointer for last column */ + if (p [n_col] < last_start) + { + /* column pointers must be non-decreasing */ + DEBUG0 (("colamd error! last p %d p [n_col] %d\n",p[col],last_start)) ; + return (-1) ; + } + + /* p [0..n_col] no longer needed, used as "head" in subsequent routines */ + + /* === Scan columns, compute row degrees, and check row indices ========= */ + + jumbled_columns = FALSE ; + + for (row = 0 ; row < n_row ; row++) + { + Row [row].length = 0 ; + Row [row].shared2.mark = -1 ; + } + + for (col = 0 ; col < n_col ; col++) + { + last_row = -1 ; + + cp = &A [p [col]] ; + cp_end = &A [p [col+1]] ; + + while (cp < cp_end) + { + row = *cp++ ; + + /* make sure row indices within range */ + if (row < 0 || row >= n_row) + { + DEBUG0 (("colamd error! col %d row %d last_row %d\n", + col, row, last_row)) ; + return (-1) ; + } + else if (row <= last_row) + { + /* row indices are not sorted or repeated, thus cols */ + /* are jumbled */ + jumbled_columns = TRUE ; + } + /* prevent repeated row from being counted */ + if (Row [row].shared2.mark != col) + { + Row [row].length++ ; + Row [row].shared2.mark = col ; + last_row = row ; + } + else + { + /* this is a repeated entry in the column, */ + /* it will be removed */ + Col [col].length-- ; + } + } + } + + /* === Compute row pointers ============================================= */ + + /* row form of the matrix starts directly after the column */ + /* form of matrix in A */ + Row [0].start = p [n_col] ; + Row [0].shared1.p = Row [0].start ; + Row [0].shared2.mark = -1 ; + for (row = 1 ; row < n_row ; row++) + { + Row [row].start = Row [row-1].start + Row [row-1].length ; + Row [row].shared1.p = Row [row].start ; + Row [row].shared2.mark = -1 ; + } + + /* === Create row form ================================================== */ + + if (jumbled_columns) + { + /* if cols jumbled, watch for repeated row indices */ + for (col = 0 ; col < n_col ; col++) + { + cp = &A [p [col]] ; + cp_end = &A [p [col+1]] ; + while (cp < cp_end) + { + row = *cp++ ; + if (Row [row].shared2.mark != col) + { + A [(Row [row].shared1.p)++] = col ; + Row [row].shared2.mark = col ; + } + } + } + } + else + { + /* if cols not jumbled, we don't need the mark (this is faster) */ + for (col = 0 ; col < n_col ; col++) + { + cp = &A [p [col]] ; + cp_end = &A [p [col+1]] ; + while (cp < cp_end) + { + A [(Row [*cp++].shared1.p)++] = col ; + } + } + } + + /* === Clear the row marks and set row degrees ========================== */ + + for (row = 0 ; row < n_row ; row++) + { + Row [row].shared2.mark = 0 ; + Row [row].shared1.degree = Row [row].length ; + } + + /* === See if we need to re-create columns ============================== */ + + if (jumbled_columns) + { + +#ifndef NDEBUG + /* make sure column lengths are correct */ + for (col = 0 ; col < n_col ; col++) + { + p [col] = Col [col].length ; + } + for (row = 0 ; row < n_row ; row++) + { + rp = &A [Row [row].start] ; + rp_end = rp + Row [row].length ; + while (rp < rp_end) + { + p [*rp++]-- ; + } + } + for (col = 0 ; col < n_col ; col++) + { + assert (p [col] == 0) ; + } + /* now p is all zero (different than when debugging is turned off) */ +#endif + + /* === Compute col pointers ========================================= */ + + /* col form of the matrix starts at A [0]. */ + /* Note, we may have a gap between the col form and the row */ + /* form if there were duplicate entries, if so, it will be */ + /* removed upon the first garbage collection */ + Col [0].start = 0 ; + p [0] = Col [0].start ; + for (col = 1 ; col < n_col ; col++) + { + /* note that the lengths here are for pruned columns, i.e. */ + /* no duplicate row indices will exist for these columns */ + Col [col].start = Col [col-1].start + Col [col-1].length ; + p [col] = Col [col].start ; + } + + /* === Re-create col form =========================================== */ + + for (row = 0 ; row < n_row ; row++) + { + rp = &A [Row [row].start] ; + rp_end = rp + Row [row].length ; + while (rp < rp_end) + { + A [(p [*rp++])++] = row ; + } + } + return (1) ; + } + else + { + /* no columns jumbled (this is faster) */ + return (0) ; + } +} + + +/* ========================================================================== */ +/* === init_scoring ========================================================= */ +/* ========================================================================== */ + +/* + Kills dense or empty columns and rows, calculates an initial score for + each column, and places all columns in the degree lists. Not user-callable. +*/ + +PRIVATE void init_scoring +( + /* === Parameters ======================================================= */ + + int n_row, /* number of rows of A */ + int n_col, /* number of columns of A */ + RowInfo Row [], /* of size n_row+1 */ + ColInfo Col [], /* of size n_col+1 */ + int A [], /* column form and row form of A */ + int head [], /* of size n_col+1 */ + double knobs [COLAMD_KNOBS],/* parameters */ + int *p_n_row2, /* number of non-dense, non-empty rows */ + int *p_n_col2, /* number of non-dense, non-empty columns */ + int *p_max_deg /* maximum row degree */ +) +{ + /* === Local variables ================================================== */ + + int c ; /* a column index */ + int r, row ; /* a row index */ + int *cp ; /* a column pointer */ + int deg ; /* degree (# entries) of a row or column */ + int *cp_end ; /* a pointer to the end of a column */ + int *new_cp ; /* new column pointer */ + int col_length ; /* length of pruned column */ + int score ; /* current column score */ + int n_col2 ; /* number of non-dense, non-empty columns */ + int n_row2 ; /* number of non-dense, non-empty rows */ + int dense_row_count ; /* remove rows with more entries than this */ + int dense_col_count ; /* remove cols with more entries than this */ + int min_score ; /* smallest column score */ + int max_deg ; /* maximum row degree */ + int next_col ; /* Used to add to degree list.*/ +#ifndef NDEBUG + int debug_count ; /* debug only. */ +#endif + + /* === Extract knobs ==================================================== */ + + dense_row_count = MAX (0, MIN (knobs [COLAMD_DENSE_ROW] * n_col, n_col)) ; + dense_col_count = MAX (0, MIN (knobs [COLAMD_DENSE_COL] * n_row, n_row)) ; + DEBUG0 (("densecount: %d %d\n", dense_row_count, dense_col_count)) ; + max_deg = 0 ; + n_col2 = n_col ; + n_row2 = n_row ; + + /* === Kill empty columns =============================================== */ + + /* Put the empty columns at the end in their natural, so that LU */ + /* factorization can proceed as far as possible. */ + for (c = n_col-1 ; c >= 0 ; c--) + { + deg = Col [c].length ; + if (deg == 0) + { + /* this is a empty column, kill and order it last */ + Col [c].shared2.order = --n_col2 ; + KILL_PRINCIPAL_COL (c) ; + } + } + DEBUG0 (("null columns killed: %d\n", n_col - n_col2)) ; + + /* === Kill dense columns =============================================== */ + + /* Put the dense columns at the end, in their natural order */ + for (c = n_col-1 ; c >= 0 ; c--) + { + /* skip any dead columns */ + if (COL_IS_DEAD (c)) + { + continue ; + } + deg = Col [c].length ; + if (deg > dense_col_count) + { + /* this is a dense column, kill and order it last */ + Col [c].shared2.order = --n_col2 ; + /* decrement the row degrees */ + cp = &A [Col [c].start] ; + cp_end = cp + Col [c].length ; + while (cp < cp_end) + { + Row [*cp++].shared1.degree-- ; + } + KILL_PRINCIPAL_COL (c) ; + } + } + DEBUG0 (("Dense and null columns killed: %d\n", n_col - n_col2)) ; + + /* === Kill dense and empty rows ======================================== */ + + for (r = 0 ; r < n_row ; r++) + { + deg = Row [r].shared1.degree ; + assert (deg >= 0 && deg <= n_col) ; + if (deg > dense_row_count || deg == 0) + { + /* kill a dense or empty row */ + KILL_ROW (r) ; + --n_row2 ; + } + else + { + /* keep track of max degree of remaining rows */ + max_deg = MAX (max_deg, deg) ; + } + } + DEBUG0 (("Dense and null rows killed: %d\n", n_row - n_row2)) ; + + /* === Compute initial column scores ==================================== */ + + /* At this point the row degrees are accurate. They reflect the number */ + /* of "live" (non-dense) columns in each row. No empty rows exist. */ + /* Some "live" columns may contain only dead rows, however. These are */ + /* pruned in the code below. */ + + /* now find the initial matlab score for each column */ + for (c = n_col-1 ; c >= 0 ; c--) + { + /* skip dead column */ + if (COL_IS_DEAD (c)) + { + continue ; + } + score = 0 ; + cp = &A [Col [c].start] ; + new_cp = cp ; + cp_end = cp + Col [c].length ; + while (cp < cp_end) + { + /* get a row */ + row = *cp++ ; + /* skip if dead */ + if (ROW_IS_DEAD (row)) + { + continue ; + } + /* compact the column */ + *new_cp++ = row ; + /* add row's external degree */ + score += Row [row].shared1.degree - 1 ; + /* guard against integer overflow */ + score = MIN (score, n_col) ; + } + /* determine pruned column length */ + col_length = (int) (new_cp - &A [Col [c].start]) ; + if (col_length == 0) + { + /* a newly-made null column (all rows in this col are "dense" */ + /* and have already been killed) */ + DEBUG0 (("Newly null killed: %d\n", c)) ; + Col [c].shared2.order = --n_col2 ; + KILL_PRINCIPAL_COL (c) ; + } + else + { + /* set column length and set score */ + assert (score >= 0) ; + assert (score <= n_col) ; + Col [c].length = col_length ; + Col [c].shared2.score = score ; + } + } + DEBUG0 (("Dense, null, and newly-null columns killed: %d\n",n_col-n_col2)) ; + + /* At this point, all empty rows and columns are dead. All live columns */ + /* are "clean" (containing no dead rows) and simplicial (no supercolumns */ + /* yet). Rows may contain dead columns, but all live rows contain at */ + /* least one live column. */ + +#ifndef NDEBUG + debug_structures (n_row, n_col, Row, Col, A, n_col2) ; +#endif + + /* === Initialize degree lists ========================================== */ + +#ifndef NDEBUG + debug_count = 0 ; +#endif + + /* clear the hash buckets */ + for (c = 0 ; c <= n_col ; c++) + { + head [c] = EMPTY ; + } + min_score = n_col ; + /* place in reverse order, so low column indices are at the front */ + /* of the lists. This is to encourage natural tie-breaking */ + for (c = n_col-1 ; c >= 0 ; c--) + { + /* only add principal columns to degree lists */ + if (COL_IS_ALIVE (c)) + { + DEBUG4 (("place %d score %d minscore %d ncol %d\n", + c, Col [c].shared2.score, min_score, n_col)) ; + + /* === Add columns score to DList =============================== */ + + score = Col [c].shared2.score ; + + assert (min_score >= 0) ; + assert (min_score <= n_col) ; + assert (score >= 0) ; + assert (score <= n_col) ; + assert (head [score] >= EMPTY) ; + + /* now add this column to dList at proper score location */ + next_col = head [score] ; + Col [c].shared3.prev = EMPTY ; + Col [c].shared4.degree_next = next_col ; + + /* if there already was a column with the same score, set its */ + /* previous pointer to this new column */ + if (next_col != EMPTY) + { + Col [next_col].shared3.prev = c ; + } + head [score] = c ; + + /* see if this score is less than current min */ + min_score = MIN (min_score, score) ; + +#ifndef NDEBUG + debug_count++ ; +#endif + } + } + +#ifndef NDEBUG + DEBUG0 (("Live cols %d out of %d, non-princ: %d\n", + debug_count, n_col, n_col-debug_count)) ; + assert (debug_count == n_col2) ; + debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2, max_deg) ; +#endif + + /* === Return number of remaining columns, and max row degree =========== */ + + *p_n_col2 = n_col2 ; + *p_n_row2 = n_row2 ; + *p_max_deg = max_deg ; +} + + +/* ========================================================================== */ +/* === find_ordering ======================================================== */ +/* ========================================================================== */ + +/* + Order the principal columns of the supercolumn form of the matrix + (no supercolumns on input). Uses a minimum approximate column minimum + degree ordering method. Not user-callable. +*/ + +PRIVATE int find_ordering /* return the number of garbage collections */ +( + /* === Parameters ======================================================= */ + + int n_row, /* number of rows of A */ + int n_col, /* number of columns of A */ + int Alen, /* size of A, 2*nnz + elbow_room or larger */ + RowInfo Row [], /* of size n_row+1 */ + ColInfo Col [], /* of size n_col+1 */ + int A [], /* column form and row form of A */ + int head [], /* of size n_col+1 */ + int n_col2, /* Remaining columns to order */ + int max_deg, /* Maximum row degree */ + int pfree /* index of first free slot (2*nnz on entry) */ +) +{ + /* === Local variables ================================================== */ + + int k ; /* current pivot ordering step */ + int pivot_col ; /* current pivot column */ + int *cp ; /* a column pointer */ + int *rp ; /* a row pointer */ + int pivot_row ; /* current pivot row */ + int *new_cp ; /* modified column pointer */ + int *new_rp ; /* modified row pointer */ + int pivot_row_start ; /* pointer to start of pivot row */ + int pivot_row_degree ; /* # of columns in pivot row */ + int pivot_row_length ; /* # of supercolumns in pivot row */ + int pivot_col_score ; /* score of pivot column */ + int needed_memory ; /* free space needed for pivot row */ + int *cp_end ; /* pointer to the end of a column */ + int *rp_end ; /* pointer to the end of a row */ + int row ; /* a row index */ + int col ; /* a column index */ + int max_score ; /* maximum possible score */ + int cur_score ; /* score of current column */ + unsigned int hash ; /* hash value for supernode detection */ + int head_column ; /* head of hash bucket */ + int first_col ; /* first column in hash bucket */ + int tag_mark ; /* marker value for mark array */ + int row_mark ; /* Row [row].shared2.mark */ + int set_difference ; /* set difference size of row with pivot row */ + int min_score ; /* smallest column score */ + int col_thickness ; /* "thickness" (# of columns in a supercol) */ + int max_mark ; /* maximum value of tag_mark */ + int pivot_col_thickness ; /* number of columns represented by pivot col */ + int prev_col ; /* Used by Dlist operations. */ + int next_col ; /* Used by Dlist operations. */ + int ngarbage ; /* number of garbage collections performed */ +#ifndef NDEBUG + int debug_d ; /* debug loop counter */ + int debug_step = 0 ; /* debug loop counter */ +#endif + + /* === Initialization and clear mark ==================================== */ + + max_mark = INT_MAX - n_col ; /* INT_MAX defined in */ + tag_mark = clear_mark (n_row, Row) ; + min_score = 0 ; + ngarbage = 0 ; + DEBUG0 (("Ordering.. n_col2=%d\n", n_col2)) ; + + /* === Order the columns ================================================ */ + + for (k = 0 ; k < n_col2 ; /* 'k' is incremented below */) + { + +#ifndef NDEBUG + if (debug_step % 100 == 0) + { + DEBUG0 (("\n... Step k: %d out of n_col2: %d\n", k, n_col2)) ; + } + else + { + DEBUG1 (("\n----------Step k: %d out of n_col2: %d\n", k, n_col2)) ; + } + debug_step++ ; + debug_deg_lists (n_row, n_col, Row, Col, head, + min_score, n_col2-k, max_deg) ; + debug_matrix (n_row, n_col, Row, Col, A) ; +#endif + + /* === Select pivot column, and order it ============================ */ + + /* make sure degree list isn't empty */ + assert (min_score >= 0) ; + assert (min_score <= n_col) ; + assert (head [min_score] >= EMPTY) ; + +#ifndef NDEBUG + for (debug_d = 0 ; debug_d < min_score ; debug_d++) + { + assert (head [debug_d] == EMPTY) ; + } +#endif + + /* get pivot column from head of minimum degree list */ + while (head [min_score] == EMPTY && min_score < n_col) + { + min_score++ ; + } + pivot_col = head [min_score] ; + assert (pivot_col >= 0 && pivot_col <= n_col) ; + next_col = Col [pivot_col].shared4.degree_next ; + head [min_score] = next_col ; + if (next_col != EMPTY) + { + Col [next_col].shared3.prev = EMPTY ; + } + + assert (COL_IS_ALIVE (pivot_col)) ; + DEBUG3 (("Pivot col: %d\n", pivot_col)) ; + + /* remember score for defrag check */ + pivot_col_score = Col [pivot_col].shared2.score ; + + /* the pivot column is the kth column in the pivot order */ + Col [pivot_col].shared2.order = k ; + + /* increment order count by column thickness */ + pivot_col_thickness = Col [pivot_col].shared1.thickness ; + k += pivot_col_thickness ; + assert (pivot_col_thickness > 0) ; + + /* === Garbage_collection, if necessary ============================= */ + + needed_memory = MIN (pivot_col_score, n_col - k) ; + if (pfree + needed_memory >= Alen) + { + pfree = garbage_collection (n_row, n_col, Row, Col, A, &A [pfree]) ; + ngarbage++ ; + /* after garbage collection we will have enough */ + assert (pfree + needed_memory < Alen) ; + /* garbage collection has wiped out the Row[].shared2.mark array */ + tag_mark = clear_mark (n_row, Row) ; +#ifndef NDEBUG + debug_matrix (n_row, n_col, Row, Col, A) ; +#endif + } + + /* === Compute pivot row pattern ==================================== */ + + /* get starting location for this new merged row */ + pivot_row_start = pfree ; + + /* initialize new row counts to zero */ + pivot_row_degree = 0 ; + + /* tag pivot column as having been visited so it isn't included */ + /* in merged pivot row */ + Col [pivot_col].shared1.thickness = -pivot_col_thickness ; + + /* pivot row is the union of all rows in the pivot column pattern */ + cp = &A [Col [pivot_col].start] ; + cp_end = cp + Col [pivot_col].length ; + while (cp < cp_end) + { + /* get a row */ + row = *cp++ ; + DEBUG4 (("Pivot col pattern %d %d\n", ROW_IS_ALIVE (row), row)) ; + /* skip if row is dead */ + if (ROW_IS_DEAD (row)) + { + continue ; + } + rp = &A [Row [row].start] ; + rp_end = rp + Row [row].length ; + while (rp < rp_end) + { + /* get a column */ + col = *rp++ ; + /* add the column, if alive and untagged */ + col_thickness = Col [col].shared1.thickness ; + if (col_thickness > 0 && COL_IS_ALIVE (col)) + { + /* tag column in pivot row */ + Col [col].shared1.thickness = -col_thickness ; + assert (pfree < Alen) ; + /* place column in pivot row */ + A [pfree++] = col ; + pivot_row_degree += col_thickness ; + } + } + } + + /* clear tag on pivot column */ + Col [pivot_col].shared1.thickness = pivot_col_thickness ; + max_deg = MAX (max_deg, pivot_row_degree) ; + +#ifndef NDEBUG + DEBUG3 (("check2\n")) ; + debug_mark (n_row, Row, tag_mark, max_mark) ; +#endif + + /* === Kill all rows used to construct pivot row ==================== */ + + /* also kill pivot row, temporarily */ + cp = &A [Col [pivot_col].start] ; + cp_end = cp + Col [pivot_col].length ; + while (cp < cp_end) + { + /* may be killing an already dead row */ + row = *cp++ ; + DEBUG2 (("Kill row in pivot col: %d\n", row)) ; + KILL_ROW (row) ; + } + + /* === Select a row index to use as the new pivot row =============== */ + + pivot_row_length = pfree - pivot_row_start ; + if (pivot_row_length > 0) + { + /* pick the "pivot" row arbitrarily (first row in col) */ + pivot_row = A [Col [pivot_col].start] ; + DEBUG2 (("Pivotal row is %d\n", pivot_row)) ; + } + else + { + /* there is no pivot row, since it is of zero length */ + pivot_row = EMPTY ; + assert (pivot_row_length == 0) ; + } + assert (Col [pivot_col].length > 0 || pivot_row_length == 0) ; + + /* === Approximate degree computation =============================== */ + + /* Here begins the computation of the approximate degree. The column */ + /* score is the sum of the pivot row "length", plus the size of the */ + /* set differences of each row in the column minus the pattern of the */ + /* pivot row itself. The column ("thickness") itself is also */ + /* excluded from the column score (we thus use an approximate */ + /* external degree). */ + + /* The time taken by the following code (compute set differences, and */ + /* add them up) is proportional to the size of the data structure */ + /* being scanned - that is, the sum of the sizes of each column in */ + /* the pivot row. Thus, the amortized time to compute a column score */ + /* is proportional to the size of that column (where size, in this */ + /* context, is the column "length", or the number of row indices */ + /* in that column). The number of row indices in a column is */ + /* monotonically non-decreasing, from the length of the original */ + /* column on input to colamd. */ + + /* === Compute set differences ====================================== */ + + DEBUG1 (("** Computing set differences phase. **\n")) ; + + /* pivot row is currently dead - it will be revived later. */ + + DEBUG2 (("Pivot row: ")) ; + /* for each column in pivot row */ + rp = &A [pivot_row_start] ; + rp_end = rp + pivot_row_length ; + while (rp < rp_end) + { + col = *rp++ ; + assert (COL_IS_ALIVE (col) && col != pivot_col) ; + DEBUG2 (("Col: %d\n", col)) ; + + /* clear tags used to construct pivot row pattern */ + col_thickness = -Col [col].shared1.thickness ; + assert (col_thickness > 0) ; + Col [col].shared1.thickness = col_thickness ; + + /* === Remove column from degree list =========================== */ + + cur_score = Col [col].shared2.score ; + prev_col = Col [col].shared3.prev ; + next_col = Col [col].shared4.degree_next ; + assert (cur_score >= 0) ; + assert (cur_score <= n_col) ; + assert (cur_score >= EMPTY) ; + if (prev_col == EMPTY) + { + head [cur_score] = next_col ; + } + else + { + Col [prev_col].shared4.degree_next = next_col ; + } + if (next_col != EMPTY) + { + Col [next_col].shared3.prev = prev_col ; + } + + /* === Scan the column ========================================== */ + + cp = &A [Col [col].start] ; + cp_end = cp + Col [col].length ; + while (cp < cp_end) + { + /* get a row */ + row = *cp++ ; + row_mark = Row [row].shared2.mark ; + /* skip if dead */ + if (ROW_IS_MARKED_DEAD (row_mark)) + { + continue ; + } + assert (row != pivot_row) ; + set_difference = row_mark - tag_mark ; + /* check if the row has been seen yet */ + if (set_difference < 0) + { + assert (Row [row].shared1.degree <= max_deg) ; + set_difference = Row [row].shared1.degree ; + } + /* subtract column thickness from this row's set difference */ + set_difference -= col_thickness ; + assert (set_difference >= 0) ; + /* absorb this row if the set difference becomes zero */ + if (set_difference == 0) + { + DEBUG1 (("aggressive absorption. Row: %d\n", row)) ; + KILL_ROW (row) ; + } + else + { + /* save the new mark */ + Row [row].shared2.mark = set_difference + tag_mark ; + } + } + } + +#ifndef NDEBUG + debug_deg_lists (n_row, n_col, Row, Col, head, + min_score, n_col2-k-pivot_row_degree, max_deg) ; +#endif + + /* === Add up set differences for each column ======================= */ + + DEBUG1 (("** Adding set differences phase. **\n")) ; + + /* for each column in pivot row */ + rp = &A [pivot_row_start] ; + rp_end = rp + pivot_row_length ; + while (rp < rp_end) + { + /* get a column */ + col = *rp++ ; + assert (COL_IS_ALIVE (col) && col != pivot_col) ; + hash = 0 ; + cur_score = 0 ; + cp = &A [Col [col].start] ; + /* compact the column */ + new_cp = cp ; + cp_end = cp + Col [col].length ; + + DEBUG2 (("Adding set diffs for Col: %d.\n", col)) ; + + while (cp < cp_end) + { + /* get a row */ + row = *cp++ ; + assert(row >= 0 && row < n_row) ; + row_mark = Row [row].shared2.mark ; + /* skip if dead */ + if (ROW_IS_MARKED_DEAD (row_mark)) + { + continue ; + } + assert (row_mark > tag_mark) ; + /* compact the column */ + *new_cp++ = row ; + /* compute hash function */ + hash += row ; + /* add set difference */ + cur_score += row_mark - tag_mark ; + /* integer overflow... */ + cur_score = MIN (cur_score, n_col) ; + } + + /* recompute the column's length */ + Col [col].length = (int) (new_cp - &A [Col [col].start]) ; + + /* === Further mass elimination ================================= */ + + if (Col [col].length == 0) + { + DEBUG1 (("further mass elimination. Col: %d\n", col)) ; + /* nothing left but the pivot row in this column */ + KILL_PRINCIPAL_COL (col) ; + pivot_row_degree -= Col [col].shared1.thickness ; + assert (pivot_row_degree >= 0) ; + /* order it */ + Col [col].shared2.order = k ; + /* increment order count by column thickness */ + k += Col [col].shared1.thickness ; + } + else + { + /* === Prepare for supercolumn detection ==================== */ + + DEBUG2 (("Preparing supercol detection for Col: %d.\n", col)) ; + + /* save score so far */ + Col [col].shared2.score = cur_score ; + + /* add column to hash table, for supercolumn detection */ + hash %= n_col + 1 ; + + DEBUG2 ((" Hash = %d, n_col = %d.\n", hash, n_col)) ; + assert (hash <= n_col) ; + + head_column = head [hash] ; + if (head_column > EMPTY) + { + /* degree list "hash" is non-empty, use prev (shared3) of */ + /* first column in degree list as head of hash bucket */ + first_col = Col [head_column].shared3.headhash ; + Col [head_column].shared3.headhash = col ; + } + else + { + /* degree list "hash" is empty, use head as hash bucket */ + first_col = - (head_column + 2) ; + head [hash] = - (col + 2) ; + } + Col [col].shared4.hash_next = first_col ; + + /* save hash function in Col [col].shared3.hash */ + Col [col].shared3.hash = (int) hash ; + assert (COL_IS_ALIVE (col)) ; + } + } + + /* The approximate external column degree is now computed. */ + + /* === Supercolumn detection ======================================== */ + + DEBUG1 (("** Supercolumn detection phase. **\n")) ; + + detect_super_cols ( +#ifndef NDEBUG + n_col, Row, +#endif + Col, A, head, pivot_row_start, pivot_row_length) ; + + /* === Kill the pivotal column ====================================== */ + + KILL_PRINCIPAL_COL (pivot_col) ; + + /* === Clear mark =================================================== */ + + tag_mark += (max_deg + 1) ; + if (tag_mark >= max_mark) + { + DEBUG1 (("clearing tag_mark\n")) ; + tag_mark = clear_mark (n_row, Row) ; + } +#ifndef NDEBUG + DEBUG3 (("check3\n")) ; + debug_mark (n_row, Row, tag_mark, max_mark) ; +#endif + + /* === Finalize the new pivot row, and column scores ================ */ + + DEBUG1 (("** Finalize scores phase. **\n")) ; + + /* for each column in pivot row */ + rp = &A [pivot_row_start] ; + /* compact the pivot row */ + new_rp = rp ; + rp_end = rp + pivot_row_length ; + while (rp < rp_end) + { + col = *rp++ ; + /* skip dead columns */ + if (COL_IS_DEAD (col)) + { + continue ; + } + *new_rp++ = col ; + /* add new pivot row to column */ + A [Col [col].start + (Col [col].length++)] = pivot_row ; + + /* retrieve score so far and add on pivot row's degree. */ + /* (we wait until here for this in case the pivot */ + /* row's degree was reduced due to mass elimination). */ + cur_score = Col [col].shared2.score + pivot_row_degree ; + + /* calculate the max possible score as the number of */ + /* external columns minus the 'k' value minus the */ + /* columns thickness */ + max_score = n_col - k - Col [col].shared1.thickness ; + + /* make the score the external degree of the union-of-rows */ + cur_score -= Col [col].shared1.thickness ; + + /* make sure score is less or equal than the max score */ + cur_score = MIN (cur_score, max_score) ; + assert (cur_score >= 0) ; + + /* store updated score */ + Col [col].shared2.score = cur_score ; + + /* === Place column back in degree list ========================= */ + + assert (min_score >= 0) ; + assert (min_score <= n_col) ; + assert (cur_score >= 0) ; + assert (cur_score <= n_col) ; + assert (head [cur_score] >= EMPTY) ; + next_col = head [cur_score] ; + Col [col].shared4.degree_next = next_col ; + Col [col].shared3.prev = EMPTY ; + if (next_col != EMPTY) + { + Col [next_col].shared3.prev = col ; + } + head [cur_score] = col ; + + /* see if this score is less than current min */ + min_score = MIN (min_score, cur_score) ; + + } + +#ifndef NDEBUG + debug_deg_lists (n_row, n_col, Row, Col, head, + min_score, n_col2-k, max_deg) ; +#endif + + /* === Resurrect the new pivot row ================================== */ + + if (pivot_row_degree > 0) + { + /* update pivot row length to reflect any cols that were killed */ + /* during super-col detection and mass elimination */ + Row [pivot_row].start = pivot_row_start ; + Row [pivot_row].length = (int) (new_rp - &A[pivot_row_start]) ; + Row [pivot_row].shared1.degree = pivot_row_degree ; + Row [pivot_row].shared2.mark = 0 ; + /* pivot row is no longer dead */ + } + } + + /* === All principal columns have now been ordered ====================== */ + + return (ngarbage) ; +} + + +/* ========================================================================== */ +/* === order_children ======================================================= */ +/* ========================================================================== */ + +/* + The find_ordering routine has ordered all of the principal columns (the + representatives of the supercolumns). The non-principal columns have not + yet been ordered. This routine orders those columns by walking up the + parent tree (a column is a child of the column which absorbed it). The + final permutation vector is then placed in p [0 ... n_col-1], with p [0] + being the first column, and p [n_col-1] being the last. It doesn't look + like it at first glance, but be assured that this routine takes time linear + in the number of columns. Although not immediately obvious, the time + taken by this routine is O (n_col), that is, linear in the number of + columns. Not user-callable. +*/ + +PRIVATE void order_children +( + /* === Parameters ======================================================= */ + + int n_col, /* number of columns of A */ + ColInfo Col [], /* of size n_col+1 */ + int p [] /* p [0 ... n_col-1] is the column permutation*/ +) +{ + /* === Local variables ================================================== */ + + int i ; /* loop counter for all columns */ + int c ; /* column index */ + int parent ; /* index of column's parent */ + int order ; /* column's order */ + + /* === Order each non-principal column ================================== */ + + for (i = 0 ; i < n_col ; i++) + { + /* find an un-ordered non-principal column */ + assert (COL_IS_DEAD (i)) ; + if (!COL_IS_DEAD_PRINCIPAL (i) && Col [i].shared2.order == EMPTY) + { + parent = i ; + /* once found, find its principal parent */ + do + { + parent = Col [parent].shared1.parent ; + } while (!COL_IS_DEAD_PRINCIPAL (parent)) ; + + /* now, order all un-ordered non-principal columns along path */ + /* to this parent. collapse tree at the same time */ + c = i ; + /* get order of parent */ + order = Col [parent].shared2.order ; + + do + { + assert (Col [c].shared2.order == EMPTY) ; + + /* order this column */ + Col [c].shared2.order = order++ ; + /* collaps tree */ + Col [c].shared1.parent = parent ; + + /* get immediate parent of this column */ + c = Col [c].shared1.parent ; + + /* continue until we hit an ordered column. There are */ + /* guarranteed not to be anymore unordered columns */ + /* above an ordered column */ + } while (Col [c].shared2.order == EMPTY) ; + + /* re-order the super_col parent to largest order for this group */ + Col [parent].shared2.order = order ; + } + } + + /* === Generate the permutation ========================================= */ + + for (c = 0 ; c < n_col ; c++) + { + p [Col [c].shared2.order] = c ; + } +} + + +/* ========================================================================== */ +/* === detect_super_cols ==================================================== */ +/* ========================================================================== */ + +/* + Detects supercolumns by finding matches between columns in the hash buckets. + Check amongst columns in the set A [row_start ... row_start + row_length-1]. + The columns under consideration are currently *not* in the degree lists, + and have already been placed in the hash buckets. + + The hash bucket for columns whose hash function is equal to h is stored + as follows: + + if head [h] is >= 0, then head [h] contains a degree list, so: + + head [h] is the first column in degree bucket h. + Col [head [h]].headhash gives the first column in hash bucket h. + + otherwise, the degree list is empty, and: + + -(head [h] + 2) is the first column in hash bucket h. + + For a column c in a hash bucket, Col [c].shared3.prev is NOT a "previous + column" pointer. Col [c].shared3.hash is used instead as the hash number + for that column. The value of Col [c].shared4.hash_next is the next column + in the same hash bucket. + + Assuming no, or "few" hash collisions, the time taken by this routine is + linear in the sum of the sizes (lengths) of each column whose score has + just been computed in the approximate degree computation. + Not user-callable. +*/ + +PRIVATE void detect_super_cols +( + /* === Parameters ======================================================= */ + +#ifndef NDEBUG + /* these two parameters are only needed when debugging is enabled: */ + int n_col, /* number of columns of A */ + RowInfo Row [], /* of size n_row+1 */ +#endif + ColInfo Col [], /* of size n_col+1 */ + int A [], /* row indices of A */ + int head [], /* head of degree lists and hash buckets */ + int row_start, /* pointer to set of columns to check */ + int row_length /* number of columns to check */ +) +{ + /* === Local variables ================================================== */ + + int hash ; /* hash # for a column */ + int *rp ; /* pointer to a row */ + int c ; /* a column index */ + int super_c ; /* column index of the column to absorb into */ + int *cp1 ; /* column pointer for column super_c */ + int *cp2 ; /* column pointer for column c */ + int length ; /* length of column super_c */ + int prev_c ; /* column preceding c in hash bucket */ + int i ; /* loop counter */ + int *rp_end ; /* pointer to the end of the row */ + int col ; /* a column index in the row to check */ + int head_column ; /* first column in hash bucket or degree list */ + int first_col ; /* first column in hash bucket */ + + /* === Consider each column in the row ================================== */ + + rp = &A [row_start] ; + rp_end = rp + row_length ; + while (rp < rp_end) + { + col = *rp++ ; + if (COL_IS_DEAD (col)) + { + continue ; + } + + /* get hash number for this column */ + hash = Col [col].shared3.hash ; + assert (hash <= n_col) ; + + /* === Get the first column in this hash bucket ===================== */ + + head_column = head [hash] ; + if (head_column > EMPTY) + { + first_col = Col [head_column].shared3.headhash ; + } + else + { + first_col = - (head_column + 2) ; + } + + /* === Consider each column in the hash bucket ====================== */ + + for (super_c = first_col ; super_c != EMPTY ; + super_c = Col [super_c].shared4.hash_next) + { + assert (COL_IS_ALIVE (super_c)) ; + assert (Col [super_c].shared3.hash == hash) ; + length = Col [super_c].length ; + + /* prev_c is the column preceding column c in the hash bucket */ + prev_c = super_c ; + + /* === Compare super_c with all columns after it ================ */ + + for (c = Col [super_c].shared4.hash_next ; + c != EMPTY ; c = Col [c].shared4.hash_next) + { + assert (c != super_c) ; + assert (COL_IS_ALIVE (c)) ; + assert (Col [c].shared3.hash == hash) ; + + /* not identical if lengths or scores are different */ + if (Col [c].length != length || + Col [c].shared2.score != Col [super_c].shared2.score) + { + prev_c = c ; + continue ; + } + + /* compare the two columns */ + cp1 = &A [Col [super_c].start] ; + cp2 = &A [Col [c].start] ; + + for (i = 0 ; i < length ; i++) + { + /* the columns are "clean" (no dead rows) */ + assert (ROW_IS_ALIVE (*cp1)) ; + assert (ROW_IS_ALIVE (*cp2)) ; + /* row indices will same order for both supercols, */ + /* no gather scatter nessasary */ + if (*cp1++ != *cp2++) + { + break ; + } + } + + /* the two columns are different if the for-loop "broke" */ + if (i != length) + { + prev_c = c ; + continue ; + } + + /* === Got it! two columns are identical =================== */ + + assert (Col [c].shared2.score == Col [super_c].shared2.score) ; + + Col [super_c].shared1.thickness += Col [c].shared1.thickness ; + Col [c].shared1.parent = super_c ; + KILL_NON_PRINCIPAL_COL (c) ; + /* order c later, in order_children() */ + Col [c].shared2.order = EMPTY ; + /* remove c from hash bucket */ + Col [prev_c].shared4.hash_next = Col [c].shared4.hash_next ; + } + } + + /* === Empty this hash bucket ======================================= */ + + if (head_column > EMPTY) + { + /* corresponding degree list "hash" is not empty */ + Col [head_column].shared3.headhash = EMPTY ; + } + else + { + /* corresponding degree list "hash" is empty */ + head [hash] = EMPTY ; + } + } +} + + +/* ========================================================================== */ +/* === garbage_collection =================================================== */ +/* ========================================================================== */ + +/* + Defragments and compacts columns and rows in the workspace A. Used when + all avaliable memory has been used while performing row merging. Returns + the index of the first free position in A, after garbage collection. The + time taken by this routine is linear is the size of the array A, which is + itself linear in the number of nonzeros in the input matrix. + Not user-callable. +*/ + +PRIVATE int garbage_collection /* returns the new value of pfree */ +( + /* === Parameters ======================================================= */ + + int n_row, /* number of rows */ + int n_col, /* number of columns */ + RowInfo Row [], /* row info */ + ColInfo Col [], /* column info */ + int A [], /* A [0 ... Alen-1] holds the matrix */ + int *pfree /* &A [0] ... pfree is in use */ +) +{ + /* === Local variables ================================================== */ + + int *psrc ; /* source pointer */ + int *pdest ; /* destination pointer */ + int j ; /* counter */ + int r ; /* a row index */ + int c ; /* a column index */ + int length ; /* length of a row or column */ + +#ifndef NDEBUG + int debug_rows ; + DEBUG0 (("Defrag..\n")) ; + for (psrc = &A[0] ; psrc < pfree ; psrc++) assert (*psrc >= 0) ; + debug_rows = 0 ; +#endif + + /* === Defragment the columns =========================================== */ + + pdest = &A[0] ; + for (c = 0 ; c < n_col ; c++) + { + if (COL_IS_ALIVE (c)) + { + psrc = &A [Col [c].start] ; + + /* move and compact the column */ + assert (pdest <= psrc) ; + Col [c].start = (int) (pdest - &A [0]) ; + length = Col [c].length ; + for (j = 0 ; j < length ; j++) + { + r = *psrc++ ; + if (ROW_IS_ALIVE (r)) + { + *pdest++ = r ; + } + } + Col [c].length = (int) (pdest - &A [Col [c].start]) ; + } + } + + /* === Prepare to defragment the rows =================================== */ + + for (r = 0 ; r < n_row ; r++) + { + if (ROW_IS_ALIVE (r)) + { + if (Row [r].length == 0) + { + /* this row is of zero length. cannot compact it, so kill it */ + DEBUG0 (("Defrag row kill\n")) ; + KILL_ROW (r) ; + } + else + { + /* save first column index in Row [r].shared2.first_column */ + psrc = &A [Row [r].start] ; + Row [r].shared2.first_column = *psrc ; + assert (ROW_IS_ALIVE (r)) ; + /* flag the start of the row with the one's complement of row */ + *psrc = ONES_COMPLEMENT (r) ; +#ifndef NDEBUG + debug_rows++ ; +#endif + } + } + } + + /* === Defragment the rows ============================================== */ + + psrc = pdest ; + while (psrc < pfree) + { + /* find a negative number ... the start of a row */ + if (*psrc++ < 0) + { + psrc-- ; + /* get the row index */ + r = ONES_COMPLEMENT (*psrc) ; + assert (r >= 0 && r < n_row) ; + /* restore first column index */ + *psrc = Row [r].shared2.first_column ; + assert (ROW_IS_ALIVE (r)) ; + + /* move and compact the row */ + assert (pdest <= psrc) ; + Row [r].start = (int) (pdest - &A [0]) ; + length = Row [r].length ; + for (j = 0 ; j < length ; j++) + { + c = *psrc++ ; + if (COL_IS_ALIVE (c)) + { + *pdest++ = c ; + } + } + Row [r].length = (int) (pdest - &A [Row [r].start]) ; +#ifndef NDEBUG + debug_rows-- ; +#endif + } + } + /* ensure we found all the rows */ + assert (debug_rows == 0) ; + + /* === Return the new value of pfree ==================================== */ + + return ((int) (pdest - &A [0])) ; +} + + +/* ========================================================================== */ +/* === clear_mark =========================================================== */ +/* ========================================================================== */ + +/* + Clears the Row [].shared2.mark array, and returns the new tag_mark. + Return value is the new tag_mark. Not user-callable. +*/ + +PRIVATE int clear_mark /* return the new value for tag_mark */ +( + /* === Parameters ======================================================= */ + + int n_row, /* number of rows in A */ + RowInfo Row [] /* Row [0 ... n_row-1].shared2.mark is set to zero */ +) +{ + /* === Local variables ================================================== */ + + int r ; + + DEBUG0 (("Clear mark\n")) ; + for (r = 0 ; r < n_row ; r++) + { + if (ROW_IS_ALIVE (r)) + { + Row [r].shared2.mark = 0 ; + } + } + return (1) ; +} + + +/* ========================================================================== */ +/* === debugging routines =================================================== */ +/* ========================================================================== */ + +/* When debugging is disabled, the remainder of this file is ignored. */ + +#ifndef NDEBUG + + +/* ========================================================================== */ +/* === debug_structures ===================================================== */ +/* ========================================================================== */ + +/* + At this point, all empty rows and columns are dead. All live columns + are "clean" (containing no dead rows) and simplicial (no supercolumns + yet). Rows may contain dead columns, but all live rows contain at + least one live column. +*/ + +PRIVATE void debug_structures +( + /* === Parameters ======================================================= */ + + int n_row, + int n_col, + RowInfo Row [], + ColInfo Col [], + int A [], + int n_col2 +) +{ + /* === Local variables ================================================== */ + + int i ; + int c ; + int *cp ; + int *cp_end ; + int len ; + int score ; + int r ; + int *rp ; + int *rp_end ; + int deg ; + + /* === Check A, Row, and Col ============================================ */ + + for (c = 0 ; c < n_col ; c++) + { + if (COL_IS_ALIVE (c)) + { + len = Col [c].length ; + score = Col [c].shared2.score ; + DEBUG4 (("initial live col %5d %5d %5d\n", c, len, score)) ; + assert (len > 0) ; + assert (score >= 0) ; + assert (Col [c].shared1.thickness == 1) ; + cp = &A [Col [c].start] ; + cp_end = cp + len ; + while (cp < cp_end) + { + r = *cp++ ; + assert (ROW_IS_ALIVE (r)) ; + } + } + else + { + i = Col [c].shared2.order ; + assert (i >= n_col2 && i < n_col) ; + } + } + + for (r = 0 ; r < n_row ; r++) + { + if (ROW_IS_ALIVE (r)) + { + i = 0 ; + len = Row [r].length ; + deg = Row [r].shared1.degree ; + assert (len > 0) ; + assert (deg > 0) ; + rp = &A [Row [r].start] ; + rp_end = rp + len ; + while (rp < rp_end) + { + c = *rp++ ; + if (COL_IS_ALIVE (c)) + { + i++ ; + } + } + assert (i > 0) ; + } + } +} + + +/* ========================================================================== */ +/* === debug_deg_lists ====================================================== */ +/* ========================================================================== */ + +/* + Prints the contents of the degree lists. Counts the number of columns + in the degree list and compares it to the total it should have. Also + checks the row degrees. +*/ + +PRIVATE void debug_deg_lists +( + /* === Parameters ======================================================= */ + + int n_row, + int n_col, + RowInfo Row [], + ColInfo Col [], + int head [], + int min_score, + int should, + int max_deg +) +{ + /* === Local variables ================================================== */ + + int deg ; + int col ; + int have ; + int row ; + + /* === Check the degree lists =========================================== */ + + if (n_col > 10000 && debug_colamd <= 0) + { + return ; + } + have = 0 ; + DEBUG4 (("Degree lists: %d\n", min_score)) ; + for (deg = 0 ; deg <= n_col ; deg++) + { + col = head [deg] ; + if (col == EMPTY) + { + continue ; + } + DEBUG4 (("%d:", deg)) ; + while (col != EMPTY) + { + DEBUG4 ((" %d", col)) ; + have += Col [col].shared1.thickness ; + assert (COL_IS_ALIVE (col)) ; + col = Col [col].shared4.degree_next ; + } + DEBUG4 (("\n")) ; + } + DEBUG4 (("should %d have %d\n", should, have)) ; + assert (should == have) ; + + /* === Check the row degrees ============================================ */ + + if (n_row > 10000 && debug_colamd <= 0) + { + return ; + } + for (row = 0 ; row < n_row ; row++) + { + if (ROW_IS_ALIVE (row)) + { + assert (Row [row].shared1.degree <= max_deg) ; + } + } +} + + +/* ========================================================================== */ +/* === debug_mark =========================================================== */ +/* ========================================================================== */ + +/* + Ensures that the tag_mark is less that the maximum and also ensures that + each entry in the mark array is less than the tag mark. +*/ + +PRIVATE void debug_mark +( + /* === Parameters ======================================================= */ + + int n_row, + RowInfo Row [], + int tag_mark, + int max_mark +) +{ + /* === Local variables ================================================== */ + + int r ; + + /* === Check the Row marks ============================================== */ + + assert (tag_mark > 0 && tag_mark <= max_mark) ; + if (n_row > 10000 && debug_colamd <= 0) + { + return ; + } + for (r = 0 ; r < n_row ; r++) + { + assert (Row [r].shared2.mark < tag_mark) ; + } +} + + +/* ========================================================================== */ +/* === debug_matrix ========================================================= */ +/* ========================================================================== */ + +/* + Prints out the contents of the columns and the rows. +*/ + +PRIVATE void debug_matrix +( + /* === Parameters ======================================================= */ + + int n_row, + int n_col, + RowInfo Row [], + ColInfo Col [], + int A [] +) +{ + /* === Local variables ================================================== */ + + int r ; + int c ; + int *rp ; + int *rp_end ; + int *cp ; + int *cp_end ; + + /* === Dump the rows and columns of the matrix ========================== */ + + if (debug_colamd < 3) + { + return ; + } + DEBUG3 (("DUMP MATRIX:\n")) ; + for (r = 0 ; r < n_row ; r++) + { + DEBUG3 (("Row %d alive? %d\n", r, ROW_IS_ALIVE (r))) ; + if (ROW_IS_DEAD (r)) + { + continue ; + } + DEBUG3 (("start %d length %d degree %d\n", + Row [r].start, Row [r].length, Row [r].shared1.degree)) ; + rp = &A [Row [r].start] ; + rp_end = rp + Row [r].length ; + while (rp < rp_end) + { + c = *rp++ ; + DEBUG3 ((" %d col %d\n", COL_IS_ALIVE (c), c)) ; + } + } + + for (c = 0 ; c < n_col ; c++) + { + DEBUG3 (("Col %d alive? %d\n", c, COL_IS_ALIVE (c))) ; + if (COL_IS_DEAD (c)) + { + continue ; + } + DEBUG3 (("start %d length %d shared1 %d shared2 %d\n", + Col [c].start, Col [c].length, + Col [c].shared1.thickness, Col [c].shared2.score)) ; + cp = &A [Col [c].start] ; + cp_end = cp + Col [c].length ; + while (cp < cp_end) + { + r = *cp++ ; + DEBUG3 ((" %d row %d\n", ROW_IS_ALIVE (r), r)) ; + } + } +} + +#endif + diff --git a/intern/opennl/superlu/colamd.h b/intern/opennl/superlu/colamd.h new file mode 100644 index 00000000000..00783983b27 --- /dev/null +++ b/intern/opennl/superlu/colamd.h @@ -0,0 +1,67 @@ +/* ========================================================================== */ +/* === colamd prototypes and definitions ==================================== */ +/* ========================================================================== */ + +/* + This is the colamd include file, + + http://www.cise.ufl.edu/~davis/colamd/colamd.h + + for use in the colamd.c, colamdmex.c, and symamdmex.c files located at + + http://www.cise.ufl.edu/~davis/colamd/ + + See those files for a description of colamd and symamd, and for the + copyright notice, which also applies to this file. + + August 3, 1998. Version 1.0. +*/ + +/* ========================================================================== */ +/* === Definitions ========================================================== */ +/* ========================================================================== */ + +/* size of the knobs [ ] array. Only knobs [0..1] are currently used. */ +#define COLAMD_KNOBS 20 + +/* number of output statistics. Only A [0..2] are currently used. */ +#define COLAMD_STATS 20 + +/* knobs [0] and A [0]: dense row knob and output statistic. */ +#define COLAMD_DENSE_ROW 0 + +/* knobs [1] and A [1]: dense column knob and output statistic. */ +#define COLAMD_DENSE_COL 1 + +/* A [2]: memory defragmentation count output statistic */ +#define COLAMD_DEFRAG_COUNT 2 + +/* A [3]: whether or not the input columns were jumbled or had duplicates */ +#define COLAMD_JUMBLED_COLS 3 + +/* ========================================================================== */ +/* === Prototypes of user-callable routines ================================= */ +/* ========================================================================== */ + +int colamd_recommended /* returns recommended value of Alen */ +( + int nnz, /* nonzeros in A */ + int n_row, /* number of rows in A */ + int n_col /* number of columns in A */ +) ; + +void colamd_set_defaults /* sets default parameters */ +( /* knobs argument is modified on output */ + double knobs [COLAMD_KNOBS] /* parameter settings for colamd */ +) ; + +int colamd /* returns TRUE if successful, FALSE otherwise*/ +( /* A and p arguments are modified on output */ + int n_row, /* number of rows in A */ + int n_col, /* number of columns in A */ + int Alen, /* size of the array A */ + int A [], /* row indices of A, of size Alen */ + int p [], /* column pointers of A, of size n_col+1 */ + double knobs [COLAMD_KNOBS] /* parameter settings for colamd */ +) ; + diff --git a/intern/opennl/superlu/get_perm_c.c b/intern/opennl/superlu/get_perm_c.c new file mode 100644 index 00000000000..e255b4a76bd --- /dev/null +++ b/intern/opennl/superlu/get_perm_c.c @@ -0,0 +1,453 @@ +/* + * -- SuperLU routine (version 2.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * November 15, 1997 + * + */ + +#include "ssp_defs.h" +#include "colamd.h" + +extern int genmmd_(int *, int *, int *, int *, int *, int *, int *, + int *, int *, int *, int *, int *); + +static void +get_colamd( + const int m, /* number of rows in matrix A. */ + const int n, /* number of columns in matrix A. */ + const int nnz,/* number of nonzeros in matrix A. */ + int *colptr, /* column pointer of size n+1 for matrix A. */ + int *rowind, /* row indices of size nz for matrix A. */ + int *perm_c /* out - the column permutation vector. */ + ) +{ + int Alen, *A, i, info, *p; + double *knobs; + + Alen = colamd_recommended(nnz, m, n); + + if ( !(knobs = (double *) SUPERLU_MALLOC(COLAMD_KNOBS * sizeof(double))) ) + ABORT("Malloc fails for knobs"); + colamd_set_defaults(knobs); + + if (!(A = (int *) SUPERLU_MALLOC(Alen * sizeof(int))) ) + ABORT("Malloc fails for A[]"); + if (!(p = (int *) SUPERLU_MALLOC((n+1) * sizeof(int))) ) + ABORT("Malloc fails for p[]"); + for (i = 0; i <= n; ++i) p[i] = colptr[i]; + for (i = 0; i < nnz; ++i) A[i] = rowind[i]; + info = colamd(m, n, Alen, A, p, knobs); + if ( info == FALSE ) ABORT("COLAMD failed"); + + for (i = 0; i < n; ++i) perm_c[p[i]] = i; + + SUPERLU_FREE(knobs); + SUPERLU_FREE(A); + SUPERLU_FREE(p); +} + +static void +getata( + const int m, /* number of rows in matrix A. */ + const int n, /* number of columns in matrix A. */ + const int nz, /* number of nonzeros in matrix A */ + int *colptr, /* column pointer of size n+1 for matrix A. */ + int *rowind, /* row indices of size nz for matrix A. */ + int *atanz, /* out - on exit, returns the actual number of + nonzeros in matrix A'*A. */ + int **ata_colptr, /* out - size n+1 */ + int **ata_rowind /* out - size *atanz */ + ) +/* + * Purpose + * ======= + * + * Form the structure of A'*A. A is an m-by-n matrix in column oriented + * format represented by (colptr, rowind). The output A'*A is in column + * oriented format (symmetrically, also row oriented), represented by + * (ata_colptr, ata_rowind). + * + * This routine is modified from GETATA routine by Tim Davis. + * The complexity of this algorithm is: SUM_{i=1,m} r(i)^2, + * i.e., the sum of the square of the row counts. + * + * Questions + * ========= + * o Do I need to withhold the *dense* rows? + * o How do I know the number of nonzeros in A'*A? + * + */ +{ + register int i, j, k, col, num_nz, ti, trow; + int *marker, *b_colptr, *b_rowind; + int *t_colptr, *t_rowind; /* a column oriented form of T = A' */ + + if ( !(marker = (int*) SUPERLU_MALLOC((SUPERLU_MAX(m,n)+1)*sizeof(int))) ) + ABORT("SUPERLU_MALLOC fails for marker[]"); + if ( !(t_colptr = (int*) SUPERLU_MALLOC((m+1) * sizeof(int))) ) + ABORT("SUPERLU_MALLOC t_colptr[]"); + if ( !(t_rowind = (int*) SUPERLU_MALLOC(nz * sizeof(int))) ) + ABORT("SUPERLU_MALLOC fails for t_rowind[]"); + + + /* Get counts of each column of T, and set up column pointers */ + for (i = 0; i < m; ++i) marker[i] = 0; + for (j = 0; j < n; ++j) { + for (i = colptr[j]; i < colptr[j+1]; ++i) + ++marker[rowind[i]]; + } + t_colptr[0] = 0; + for (i = 0; i < m; ++i) { + t_colptr[i+1] = t_colptr[i] + marker[i]; + marker[i] = t_colptr[i]; + } + + /* Transpose the matrix from A to T */ + for (j = 0; j < n; ++j) + for (i = colptr[j]; i < colptr[j+1]; ++i) { + col = rowind[i]; + t_rowind[marker[col]] = j; + ++marker[col]; + } + + + /* ---------------------------------------------------------------- + compute B = T * A, where column j of B is: + + Struct (B_*j) = UNION ( Struct (T_*k) ) + A_kj != 0 + + do not include the diagonal entry + + ( Partition A as: A = (A_*1, ..., A_*n) + Then B = T * A = (T * A_*1, ..., T * A_*n), where + T * A_*j = (T_*1, ..., T_*m) * A_*j. ) + ---------------------------------------------------------------- */ + + /* Zero the diagonal flag */ + for (i = 0; i < n; ++i) marker[i] = -1; + + /* First pass determines number of nonzeros in B */ + num_nz = 0; + for (j = 0; j < n; ++j) { + /* Flag the diagonal so it's not included in the B matrix */ + marker[j] = j; + + for (i = colptr[j]; i < colptr[j+1]; ++i) { + /* A_kj is nonzero, add pattern of column T_*k to B_*j */ + k = rowind[i]; + for (ti = t_colptr[k]; ti < t_colptr[k+1]; ++ti) { + trow = t_rowind[ti]; + if ( marker[trow] != j ) { + marker[trow] = j; + num_nz++; + } + } + } + } + *atanz = num_nz; + + /* Allocate storage for A'*A */ + if ( !(*ata_colptr = (int*) SUPERLU_MALLOC( (n+1) * sizeof(int)) ) ) + ABORT("SUPERLU_MALLOC fails for ata_colptr[]"); + if ( *atanz ) { + if ( !(*ata_rowind = (int*) SUPERLU_MALLOC( *atanz * sizeof(int)) ) ) + ABORT("SUPERLU_MALLOC fails for ata_rowind[]"); + } + b_colptr = *ata_colptr; /* aliasing */ + b_rowind = *ata_rowind; + + /* Zero the diagonal flag */ + for (i = 0; i < n; ++i) marker[i] = -1; + + /* Compute each column of B, one at a time */ + num_nz = 0; + for (j = 0; j < n; ++j) { + b_colptr[j] = num_nz; + + /* Flag the diagonal so it's not included in the B matrix */ + marker[j] = j; + + for (i = colptr[j]; i < colptr[j+1]; ++i) { + /* A_kj is nonzero, add pattern of column T_*k to B_*j */ + k = rowind[i]; + for (ti = t_colptr[k]; ti < t_colptr[k+1]; ++ti) { + trow = t_rowind[ti]; + if ( marker[trow] != j ) { + marker[trow] = j; + b_rowind[num_nz++] = trow; + } + } + } + } + b_colptr[n] = num_nz; + + SUPERLU_FREE(marker); + SUPERLU_FREE(t_colptr); + SUPERLU_FREE(t_rowind); +} + + +static void +at_plus_a( + const int n, /* number of columns in matrix A. */ + const int nz, /* number of nonzeros in matrix A */ + int *colptr, /* column pointer of size n+1 for matrix A. */ + int *rowind, /* row indices of size nz for matrix A. */ + int *bnz, /* out - on exit, returns the actual number of + nonzeros in matrix A'*A. */ + int **b_colptr, /* out - size n+1 */ + int **b_rowind /* out - size *bnz */ + ) +{ +/* + * Purpose + * ======= + * + * Form the structure of A'+A. A is an n-by-n matrix in column oriented + * format represented by (colptr, rowind). The output A'+A is in column + * oriented format (symmetrically, also row oriented), represented by + * (b_colptr, b_rowind). + * + */ + register int i, j, k, col, num_nz; + int *t_colptr, *t_rowind; /* a column oriented form of T = A' */ + int *marker; + + if ( !(marker = (int*) SUPERLU_MALLOC( n * sizeof(int)) ) ) + ABORT("SUPERLU_MALLOC fails for marker[]"); + if ( !(t_colptr = (int*) SUPERLU_MALLOC( (n+1) * sizeof(int)) ) ) + ABORT("SUPERLU_MALLOC fails for t_colptr[]"); + if ( !(t_rowind = (int*) SUPERLU_MALLOC( nz * sizeof(int)) ) ) + ABORT("SUPERLU_MALLOC fails t_rowind[]"); + + + /* Get counts of each column of T, and set up column pointers */ + for (i = 0; i < n; ++i) marker[i] = 0; + for (j = 0; j < n; ++j) { + for (i = colptr[j]; i < colptr[j+1]; ++i) + ++marker[rowind[i]]; + } + t_colptr[0] = 0; + for (i = 0; i < n; ++i) { + t_colptr[i+1] = t_colptr[i] + marker[i]; + marker[i] = t_colptr[i]; + } + + /* Transpose the matrix from A to T */ + for (j = 0; j < n; ++j) + for (i = colptr[j]; i < colptr[j+1]; ++i) { + col = rowind[i]; + t_rowind[marker[col]] = j; + ++marker[col]; + } + + + /* ---------------------------------------------------------------- + compute B = A + T, where column j of B is: + + Struct (B_*j) = Struct (A_*k) UNION Struct (T_*k) + + do not include the diagonal entry + ---------------------------------------------------------------- */ + + /* Zero the diagonal flag */ + for (i = 0; i < n; ++i) marker[i] = -1; + + /* First pass determines number of nonzeros in B */ + num_nz = 0; + for (j = 0; j < n; ++j) { + /* Flag the diagonal so it's not included in the B matrix */ + marker[j] = j; + + /* Add pattern of column A_*k to B_*j */ + for (i = colptr[j]; i < colptr[j+1]; ++i) { + k = rowind[i]; + if ( marker[k] != j ) { + marker[k] = j; + ++num_nz; + } + } + + /* Add pattern of column T_*k to B_*j */ + for (i = t_colptr[j]; i < t_colptr[j+1]; ++i) { + k = t_rowind[i]; + if ( marker[k] != j ) { + marker[k] = j; + ++num_nz; + } + } + } + *bnz = num_nz; + + /* Allocate storage for A+A' */ + if ( !(*b_colptr = (int*) SUPERLU_MALLOC( (n+1) * sizeof(int)) ) ) + ABORT("SUPERLU_MALLOC fails for b_colptr[]"); + if ( *bnz) { + if ( !(*b_rowind = (int*) SUPERLU_MALLOC( *bnz * sizeof(int)) ) ) + ABORT("SUPERLU_MALLOC fails for b_rowind[]"); + } + + /* Zero the diagonal flag */ + for (i = 0; i < n; ++i) marker[i] = -1; + + /* Compute each column of B, one at a time */ + num_nz = 0; + for (j = 0; j < n; ++j) { + (*b_colptr)[j] = num_nz; + + /* Flag the diagonal so it's not included in the B matrix */ + marker[j] = j; + + /* Add pattern of column A_*k to B_*j */ + for (i = colptr[j]; i < colptr[j+1]; ++i) { + k = rowind[i]; + if ( marker[k] != j ) { + marker[k] = j; + (*b_rowind)[num_nz++] = k; + } + } + + /* Add pattern of column T_*k to B_*j */ + for (i = t_colptr[j]; i < t_colptr[j+1]; ++i) { + k = t_rowind[i]; + if ( marker[k] != j ) { + marker[k] = j; + (*b_rowind)[num_nz++] = k; + } + } + } + (*b_colptr)[n] = num_nz; + + SUPERLU_FREE(marker); + SUPERLU_FREE(t_colptr); + SUPERLU_FREE(t_rowind); +} + +void +get_perm_c(int ispec, SuperMatrix *A, int *perm_c) +/* + * Purpose + * ======= + * + * GET_PERM_C obtains a permutation matrix Pc, by applying the multiple + * minimum degree ordering code by Joseph Liu to matrix A'*A or A+A'. + * or using approximate minimum degree column ordering by Davis et. al. + * The LU factorization of A*Pc tends to have less fill than the LU + * factorization of A. + * + * Arguments + * ========= + * + * ispec (input) int + * Specifies the type of column ordering to reduce fill: + * = 1: minimum degree on the structure of A^T * A + * = 2: minimum degree on the structure of A^T + A + * = 3: approximate minimum degree for unsymmetric matrices + * If ispec == 0, the natural ordering (i.e., Pc = I) is returned. + * + * A (input) SuperMatrix* + * Matrix A in A*X=B, of dimension (A->nrow, A->ncol). The number + * of the linear equations is A->nrow. Currently, the type of A + * can be: Stype = NC; Dtype = _D; Mtype = GE. In the future, + * more general A can be handled. + * + * perm_c (output) int* + * Column permutation vector of size A->ncol, which defines the + * permutation matrix Pc; perm_c[i] = j means column i of A is + * in position j in A*Pc. + * + */ +{ + NCformat *Astore = A->Store; + int m, n, bnz, *b_colptr, i; + int delta, maxint, nofsub, *invp; + int *b_rowind, *dhead, *qsize, *llist, *marker; + double t, SuperLU_timer_(); + + m = A->nrow; + n = A->ncol; + + t = SuperLU_timer_(); + switch ( ispec ) { + case 0: /* Natural ordering */ + for (i = 0; i < n; ++i) perm_c[i] = i; +#if ( PRNTlevel>=1 ) + printf("Use natural column ordering.\n"); +#endif + return; + case 1: /* Minimum degree ordering on A'*A */ + getata(m, n, Astore->nnz, Astore->colptr, Astore->rowind, + &bnz, &b_colptr, &b_rowind); +#if ( PRNTlevel>=1 ) + printf("Use minimum degree ordering on A'*A.\n"); +#endif + t = SuperLU_timer_() - t; + /*printf("Form A'*A time = %8.3f\n", t);*/ + break; + case 2: /* Minimum degree ordering on A'+A */ + if ( m != n ) ABORT("Matrix is not square"); + at_plus_a(n, Astore->nnz, Astore->colptr, Astore->rowind, + &bnz, &b_colptr, &b_rowind); +#if ( PRNTlevel>=1 ) + printf("Use minimum degree ordering on A'+A.\n"); +#endif + t = SuperLU_timer_() - t; + /*printf("Form A'+A time = %8.3f\n", t);*/ + break; + case 3: /* Approximate minimum degree column ordering. */ + get_colamd(m, n, Astore->nnz, Astore->colptr, Astore->rowind, + perm_c); +#if ( PRNTlevel>=1 ) + printf(".. Use approximate minimum degree column ordering.\n"); +#endif + return; + default: + ABORT("Invalid ISPEC"); + } + + if ( bnz != 0 ) { + t = SuperLU_timer_(); + + /* Initialize and allocate storage for GENMMD. */ + delta = 1; /* DELTA is a parameter to allow the choice of nodes + whose degree <= min-degree + DELTA. */ + maxint = 2147483647; /* 2**31 - 1 */ + invp = (int *) SUPERLU_MALLOC((n+delta)*sizeof(int)); + if ( !invp ) ABORT("SUPERLU_MALLOC fails for invp."); + dhead = (int *) SUPERLU_MALLOC((n+delta)*sizeof(int)); + if ( !dhead ) ABORT("SUPERLU_MALLOC fails for dhead."); + qsize = (int *) SUPERLU_MALLOC((n+delta)*sizeof(int)); + if ( !qsize ) ABORT("SUPERLU_MALLOC fails for qsize."); + llist = (int *) SUPERLU_MALLOC(n*sizeof(int)); + if ( !llist ) ABORT("SUPERLU_MALLOC fails for llist."); + marker = (int *) SUPERLU_MALLOC(n*sizeof(int)); + if ( !marker ) ABORT("SUPERLU_MALLOC fails for marker."); + + /* Transform adjacency list into 1-based indexing required by GENMMD.*/ + for (i = 0; i <= n; ++i) ++b_colptr[i]; + for (i = 0; i < bnz; ++i) ++b_rowind[i]; + + genmmd_(&n, b_colptr, b_rowind, perm_c, invp, &delta, dhead, + qsize, llist, marker, &maxint, &nofsub); + + /* Transform perm_c into 0-based indexing. */ + for (i = 0; i < n; ++i) --perm_c[i]; + + SUPERLU_FREE(b_colptr); + SUPERLU_FREE(b_rowind); + SUPERLU_FREE(invp); + SUPERLU_FREE(dhead); + SUPERLU_FREE(qsize); + SUPERLU_FREE(llist); + SUPERLU_FREE(marker); + + t = SuperLU_timer_() - t; + /* printf("call GENMMD time = %8.3f\n", t);*/ + + } else { /* Empty adjacency structure */ + for (i = 0; i < n; ++i) perm_c[i] = i; + } + +} diff --git a/intern/opennl/superlu/heap_relax_snode.c b/intern/opennl/superlu/heap_relax_snode.c new file mode 100644 index 00000000000..86971f59571 --- /dev/null +++ b/intern/opennl/superlu/heap_relax_snode.c @@ -0,0 +1,116 @@ +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include "ssp_defs.h" + +void +heap_relax_snode ( + const int n, + int *et, /* column elimination tree */ + const int relax_columns, /* max no of columns allowed in a + relaxed snode */ + int *descendants, /* no of descendants of each node + in the etree */ + int *relax_end /* last column in a supernode */ + ) +{ +/* + * Purpose + * ======= + * relax_snode() - Identify the initial relaxed supernodes, assuming that + * the matrix has been reordered according to the postorder of the etree. + * + */ + register int i, j, k, l, parent; + register int snode_start; /* beginning of a snode */ + int *et_save, *post, *inv_post, *iwork; + int nsuper_et = 0, nsuper_et_post = 0; + + /* The etree may not be postordered, but is heap ordered. */ + + iwork = (int*) intMalloc(3*n+2); + if ( !iwork ) ABORT("SUPERLU_MALLOC fails for iwork[]"); + inv_post = iwork + n+1; + et_save = inv_post + n+1; + + /* Post order etree */ + post = (int *) TreePostorder(n, et); + for (i = 0; i < n+1; ++i) inv_post[post[i]] = i; + + /* Renumber etree in postorder */ + for (i = 0; i < n; ++i) { + iwork[post[i]] = post[et[i]]; + et_save[i] = et[i]; /* Save the original etree */ + } + for (i = 0; i < n; ++i) et[i] = iwork[i]; + + /* Compute the number of descendants of each node in the etree */ + ifill (relax_end, n, EMPTY); + for (j = 0; j < n; j++) descendants[j] = 0; + for (j = 0; j < n; j++) { + parent = et[j]; + if ( parent != n ) /* not the dummy root */ + descendants[parent] += descendants[j] + 1; + } + + /* Identify the relaxed supernodes by postorder traversal of the etree. */ + for (j = 0; j < n; ) { + parent = et[j]; + snode_start = j; + while ( parent != n && descendants[parent] < relax_columns ) { + j = parent; + parent = et[j]; + } + /* Found a supernode in postordered etree; j is the last column. */ + ++nsuper_et_post; + k = n; + for (i = snode_start; i <= j; ++i) + k = SUPERLU_MIN(k, inv_post[i]); + l = inv_post[j]; + if ( (l - k) == (j - snode_start) ) { + /* It's also a supernode in the original etree */ + relax_end[k] = l; /* Last column is recorded */ + ++nsuper_et; + } else { + for (i = snode_start; i <= j; ++i) { + l = inv_post[i]; + if ( descendants[i] == 0 ) relax_end[l] = l; + } + } + j++; + /* Search for a new leaf */ + while ( descendants[j] != 0 && j < n ) j++; + } + +#if ( PRNTlevel>=1 ) + printf(".. heap_snode_relax:\n" + "\tNo of relaxed snodes in postordered etree:\t%d\n" + "\tNo of relaxed snodes in original etree:\t%d\n", + nsuper_et_post, nsuper_et); +#endif + + /* Recover the original etree */ + for (i = 0; i < n; ++i) et[i] = et_save[i]; + + SUPERLU_FREE(post); + SUPERLU_FREE(iwork); +} + + diff --git a/intern/opennl/superlu/lsame.c b/intern/opennl/superlu/lsame.c new file mode 100644 index 00000000000..79fb4d428a5 --- /dev/null +++ b/intern/opennl/superlu/lsame.c @@ -0,0 +1,73 @@ +int lsame_(char *, char *); + + +int lsame_(char *ca, char *cb) +{ +/* -- LAPACK auxiliary routine (version 2.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994 + + Purpose + ======= + + LSAME returns .TRUE. if CA is the same letter as CB regardless of case. + + Arguments + ========= + + CA (input) CHARACTER*1 + CB (input) CHARACTER*1 + CA and CB specify the single characters to be compared. + + ===================================================================== +*/ + + /* System generated locals */ + int ret_val; + + /* Local variables */ + int inta, intb, zcode; + + ret_val = *(unsigned char *)ca == *(unsigned char *)cb; + if (ret_val) { + return ret_val; + } + + /* Now test for equivalence if both characters are alphabetic. */ + + zcode = 'Z'; + + /* Use 'Z' rather than 'A' so that ASCII can be detected on Prime + machines, on which ICHAR returns a value with bit 8 set. + ICHAR('A') on Prime machines returns 193 which is the same as + ICHAR('A') on an EBCDIC machine. */ + + inta = *(unsigned char *)ca; + intb = *(unsigned char *)cb; + + if (zcode == 90 || zcode == 122) { + /* ASCII is assumed - ZCODE is the ASCII code of either lower or + upper case 'Z'. */ + if (inta >= 97 && inta <= 122) inta += -32; + if (intb >= 97 && intb <= 122) intb += -32; + + } else if (zcode == 233 || zcode == 169) { + /* EBCDIC is assumed - ZCODE is the EBCDIC code of either lower or + upper case 'Z'. */ + if ((inta >= 129 && inta <= 137) || (inta >= 145 && inta <= 153) || (inta + >= 162 && inta <= 169)) + inta += 64; + if ((intb >= 129 && intb <= 137) || (intb >= 145 && intb <= 153) || (intb + >= 162 && intb <= 169)) + intb += 64; + } else if (zcode == 218 || zcode == 250) { + /* ASCII is assumed, on Prime machines - ZCODE is the ASCII code + plus 128 of either lower or upper case 'Z'. */ + if (inta >= 225 && inta <= 250) inta += -32; + if (intb >= 225 && intb <= 250) intb += -32; + } + ret_val = inta == intb; + return ret_val; + +} /* lsame_ */ diff --git a/intern/opennl/superlu/memory.c b/intern/opennl/superlu/memory.c new file mode 100644 index 00000000000..279b60b5239 --- /dev/null +++ b/intern/opennl/superlu/memory.c @@ -0,0 +1,211 @@ +/* + * -- SuperLU routine (version 2.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * November 15, 1997 + * + */ +/** Precision-independent memory-related routines. + (Shared by [sdcz]memory.c) **/ + +#include "ssp_defs.h" + +/* prototypes --------------------------------- */ +void copy_mem_int(int, void *, void *); +void user_bcopy(char *, char *, int); + + +#if ( DEBUGlevel>=1 ) /* Debug malloc/free. */ +int superlu_malloc_total = 0; + +#define PAD_FACTOR 2 +#define DWORD (sizeof(double)) /* Be sure it's no smaller than double. */ + +void *superlu_malloc(size_t size) +{ + char *buf; + + buf = (char *) malloc(size + DWORD); + if ( !buf ) { + printf("superlu_malloc fails: malloc_total %.0f MB, size %d\n", + superlu_malloc_total*1e-6, size); + ABORT("superlu_malloc: out of memory"); + } + + ((int_t *) buf)[0] = size; +#if 0 + superlu_malloc_total += size + DWORD; +#else + superlu_malloc_total += size; +#endif + return (void *) (buf + DWORD); +} + +void superlu_free(void *addr) +{ + char *p = ((char *) addr) - DWORD; + + if ( !addr ) + ABORT("superlu_free: tried to free NULL pointer"); + + if ( !p ) + ABORT("superlu_free: tried to free NULL+DWORD pointer"); + + { + int_t n = ((int_t *) p)[0]; + + if ( !n ) + ABORT("superlu_free: tried to free a freed pointer"); + *((int_t *) p) = 0; /* Set to zero to detect duplicate free's. */ +#if 0 + superlu_malloc_total -= (n + DWORD); +#else + superlu_malloc_total -= n; +#endif + + if ( superlu_malloc_total < 0 ) + ABORT("superlu_malloc_total went negative!"); + + /*free (addr);*/ + free (p); + } + +} + +#else /* production mode */ + +void *superlu_malloc(size_t size) +{ + void *buf; + buf = (void *) malloc(size); + return (buf); +} + +void superlu_free(void *addr) +{ + free (addr); +} + +#endif + + +/* + * Set up pointers for integer working arrays. + */ +void +SetIWork(int m, int n, int panel_size, int *iworkptr, int **segrep, + int **parent, int **xplore, int **repfnz, int **panel_lsub, + int **xprune, int **marker) +{ + *segrep = iworkptr; + *parent = iworkptr + m; + *xplore = *parent + m; + *repfnz = *xplore + m; + *panel_lsub = *repfnz + panel_size * m; + *xprune = *panel_lsub + panel_size * m; + *marker = *xprune + n; + ifill (*repfnz, m * panel_size, EMPTY); + ifill (*panel_lsub, m * panel_size, EMPTY); +} + + +void +copy_mem_int(int howmany, void *old, void *new) +{ + register int i; + int *iold = old; + int *inew = new; + for (i = 0; i < howmany; i++) inew[i] = iold[i]; +} + + +void +user_bcopy(char *src, char *dest, int bytes) +{ + char *s_ptr, *d_ptr; + + s_ptr = src + bytes - 1; + d_ptr = dest + bytes - 1; + for (; d_ptr >= dest; --s_ptr, --d_ptr ) *d_ptr = *s_ptr; +} + + + +int *intMalloc(int n) +{ + int *buf; + buf = (int *) SUPERLU_MALLOC(n * sizeof(int)); + if ( !buf ) { + ABORT("SUPERLU_MALLOC fails for buf in intMalloc()"); + } + return (buf); +} + +int *intCalloc(int n) +{ + int *buf; + register int i; + buf = (int *) SUPERLU_MALLOC(n * sizeof(int)); + if ( !buf ) { + ABORT("SUPERLU_MALLOC fails for buf in intCalloc()"); + } + for (i = 0; i < n; ++i) buf[i] = 0; + return (buf); +} + + + +#if 0 +check_expanders() +{ + int p; + printf("Check expanders:\n"); + for (p = 0; p < NO_MEMTYPE; p++) { + printf("type %d, size %d, mem %d\n", + p, expanders[p].size, (int)expanders[p].mem); + } + + return 0; +} + + +StackInfo() +{ + printf("Stack: size %d, used %d, top1 %d, top2 %d\n", + stack.size, stack.used, stack.top1, stack.top2); + return 0; +} + + + +PrintStack(char *msg, GlobalLU_t *Glu) +{ + int i; + int *xlsub, *lsub, *xusub, *usub; + + xlsub = Glu->xlsub; + lsub = Glu->lsub; + xusub = Glu->xusub; + usub = Glu->usub; + + printf("%s\n", msg); + +/* printf("\nUCOL: "); + for (i = 0; i < xusub[ndim]; ++i) + printf("%f ", ucol[i]); + + printf("\nLSUB: "); + for (i = 0; i < xlsub[ndim]; ++i) + printf("%d ", lsub[i]); + + printf("\nUSUB: "); + for (i = 0; i < xusub[ndim]; ++i) + printf("%d ", usub[i]); + + printf("\n");*/ + return 0; +} +#endif + + + diff --git a/intern/opennl/superlu/mmd.c b/intern/opennl/superlu/mmd.c new file mode 100644 index 00000000000..e103c7de175 --- /dev/null +++ b/intern/opennl/superlu/mmd.c @@ -0,0 +1,1025 @@ + +typedef int shortint; + + +/* prototypes -------------------- */ +int genmmd_(int *, int *, int *, int *, int *, int *, int *, + int *, int *, int *, int *, int *); +int mmdint_(int *, int *, shortint *, shortint *, shortint *, shortint *, shortint *, + shortint *, shortint *); +int mmdelm_(int *, int *, shortint *, shortint *, shortint *, shortint *, shortint *, + shortint *, shortint *, int *, int *); +int mmdupd_(int *, int *, int *, shortint *, int *, int *, shortint *, + shortint *, shortint *, shortint *, shortint *, shortint *, int *, int *); +int mmdnum_(int *, shortint *, shortint *, shortint *); + + +/* *************************************************************** */ +/* *************************************************************** */ +/* **** GENMMD ..... MULTIPLE MINIMUM EXTERNAL DEGREE **** */ +/* *************************************************************** */ +/* *************************************************************** */ + +/* AUTHOR - JOSEPH W.H. LIU */ +/* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */ + +/* PURPOSE - THIS ROUTINE IMPLEMENTS THE MINIMUM DEGREE */ +/* ALGORITHM. IT MAKES USE OF THE IMPLICIT REPRESENTATION */ +/* OF ELIMINATION GRAPHS BY QUOTIENT GRAPHS, AND THE */ +/* NOTION OF INDISTINGUISHABLE NODES. IT ALSO IMPLEMENTS */ +/* THE MODIFICATIONS BY MULTIPLE ELIMINATION AND MINIMUM */ +/* EXTERNAL DEGREE. */ +/* --------------------------------------------- */ +/* CAUTION - THE ADJACENCY VECTOR ADJNCY WILL BE */ +/* DESTROYED. */ +/* --------------------------------------------- */ + +/* INPUT PARAMETERS - */ +/* NEQNS - NUMBER OF EQUATIONS. */ +/* (XADJ,ADJNCY) - THE ADJACENCY STRUCTURE. */ +/* DELTA - TOLERANCE VALUE FOR MULTIPLE ELIMINATION. */ +/* MAXINT - MAXIMUM MACHINE REPRESENTABLE (SHORT) INTEGER */ +/* (ANY SMALLER ESTIMATE WILL DO) FOR MARKING */ +/* NODES. */ + +/* OUTPUT PARAMETERS - */ +/* PERM - THE MINIMUM DEGREE ORDERING. */ +/* INVP - THE INVERSE OF PERM. */ +/* NOFSUB - AN UPPER BOUND ON THE NUMBER OF NONZERO */ +/* SUBSCRIPTS FOR THE COMPRESSED STORAGE SCHEME. */ + +/* WORKING PARAMETERS - */ +/* DHEAD - VECTOR FOR HEAD OF DEGREE LISTS. */ +/* INVP - USED TEMPORARILY FOR DEGREE FORWARD LINK. */ +/* PERM - USED TEMPORARILY FOR DEGREE BACKWARD LINK. */ +/* QSIZE - VECTOR FOR SIZE OF SUPERNODES. */ +/* LLIST - VECTOR FOR TEMPORARY LINKED LISTS. */ +/* MARKER - A TEMPORARY MARKER VECTOR. */ + +/* PROGRAM SUBROUTINES - */ +/* MMDELM, MMDINT, MMDNUM, MMDUPD. */ + +/* *************************************************************** */ + +/* Subroutine */ int genmmd_(int *neqns, int *xadj, shortint *adjncy, + shortint *invp, shortint *perm, int *delta, shortint *dhead, + shortint *qsize, shortint *llist, shortint *marker, int *maxint, + int *nofsub) +{ + /* System generated locals */ + int i__1; + + /* Local variables */ + static int mdeg, ehead, i, mdlmt, mdnode; + extern /* Subroutine */ int mmdelm_(int *, int *, shortint *, + shortint *, shortint *, shortint *, shortint *, shortint *, + shortint *, int *, int *), mmdupd_(int *, int *, + int *, shortint *, int *, int *, shortint *, shortint + *, shortint *, shortint *, shortint *, shortint *, int *, + int *), mmdint_(int *, int *, shortint *, shortint *, + shortint *, shortint *, shortint *, shortint *, shortint *), + mmdnum_(int *, shortint *, shortint *, shortint *); + static int nextmd, tag, num; + + +/* *************************************************************** */ + + +/* *************************************************************** */ + + /* Parameter adjustments */ + --marker; + --llist; + --qsize; + --dhead; + --perm; + --invp; + --adjncy; + --xadj; + + /* Function Body */ + if (*neqns <= 0) { + return 0; + } + +/* ------------------------------------------------ */ +/* INITIALIZATION FOR THE MINIMUM DEGREE ALGORITHM. */ +/* ------------------------------------------------ */ + *nofsub = 0; + mmdint_(neqns, &xadj[1], &adjncy[1], &dhead[1], &invp[1], &perm[1], & + qsize[1], &llist[1], &marker[1]); + +/* ---------------------------------------------- */ +/* NUM COUNTS THE NUMBER OF ORDERED NODES PLUS 1. */ +/* ---------------------------------------------- */ + num = 1; + +/* ----------------------------- */ +/* ELIMINATE ALL ISOLATED NODES. */ +/* ----------------------------- */ + nextmd = dhead[1]; +L100: + if (nextmd <= 0) { + goto L200; + } + mdnode = nextmd; + nextmd = invp[mdnode]; + marker[mdnode] = *maxint; + invp[mdnode] = -num; + ++num; + goto L100; + +L200: +/* ---------------------------------------- */ +/* SEARCH FOR NODE OF THE MINIMUM DEGREE. */ +/* MDEG IS THE CURRENT MINIMUM DEGREE; */ +/* TAG IS USED TO FACILITATE MARKING NODES. */ +/* ---------------------------------------- */ + if (num > *neqns) { + goto L1000; + } + tag = 1; + dhead[1] = 0; + mdeg = 2; +L300: + if (dhead[mdeg] > 0) { + goto L400; + } + ++mdeg; + goto L300; +L400: +/* ------------------------------------------------- */ +/* USE VALUE OF DELTA TO SET UP MDLMT, WHICH GOVERNS */ +/* WHEN A DEGREE UPDATE IS TO BE PERFORMED. */ +/* ------------------------------------------------- */ + mdlmt = mdeg + *delta; + ehead = 0; + +L500: + mdnode = dhead[mdeg]; + if (mdnode > 0) { + goto L600; + } + ++mdeg; + if (mdeg > mdlmt) { + goto L900; + } + goto L500; +L600: +/* ---------------------------------------- */ +/* REMOVE MDNODE FROM THE DEGREE STRUCTURE. */ +/* ---------------------------------------- */ + nextmd = invp[mdnode]; + dhead[mdeg] = nextmd; + if (nextmd > 0) { + perm[nextmd] = -mdeg; + } + invp[mdnode] = -num; + *nofsub = *nofsub + mdeg + qsize[mdnode] - 2; + if (num + qsize[mdnode] > *neqns) { + goto L1000; + } +/* ---------------------------------------------- */ +/* ELIMINATE MDNODE AND PERFORM QUOTIENT GRAPH */ +/* TRANSFORMATION. RESET TAG VALUE IF NECESSARY. */ +/* ---------------------------------------------- */ + ++tag; + if (tag < *maxint) { + goto L800; + } + tag = 1; + i__1 = *neqns; + for (i = 1; i <= i__1; ++i) { + if (marker[i] < *maxint) { + marker[i] = 0; + } +/* L700: */ + } +L800: + mmdelm_(&mdnode, &xadj[1], &adjncy[1], &dhead[1], &invp[1], &perm[1], & + qsize[1], &llist[1], &marker[1], maxint, &tag); + num += qsize[mdnode]; + llist[mdnode] = ehead; + ehead = mdnode; + if (*delta >= 0) { + goto L500; + } +L900: +/* ------------------------------------------- */ +/* UPDATE DEGREES OF THE NODES INVOLVED IN THE */ +/* MINIMUM DEGREE NODES ELIMINATION. */ +/* ------------------------------------------- */ + if (num > *neqns) { + goto L1000; + } + mmdupd_(&ehead, neqns, &xadj[1], &adjncy[1], delta, &mdeg, &dhead[1], & + invp[1], &perm[1], &qsize[1], &llist[1], &marker[1], maxint, &tag) + ; + goto L300; + +L1000: + mmdnum_(neqns, &perm[1], &invp[1], &qsize[1]); + return 0; + +} /* genmmd_ */ + +/* *************************************************************** */ +/* *************************************************************** */ +/* *** MMDINT ..... MULT MINIMUM DEGREE INITIALIZATION *** */ +/* *************************************************************** */ +/* *************************************************************** */ + +/* AUTHOR - JOSEPH W.H. LIU */ +/* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */ + +/* PURPOSE - THIS ROUTINE PERFORMS INITIALIZATION FOR THE */ +/* MULTIPLE ELIMINATION VERSION OF THE MINIMUM DEGREE */ +/* ALGORITHM. */ + +/* INPUT PARAMETERS - */ +/* NEQNS - NUMBER OF EQUATIONS. */ +/* (XADJ,ADJNCY) - ADJACENCY STRUCTURE. */ + +/* OUTPUT PARAMETERS - */ +/* (DHEAD,DFORW,DBAKW) - DEGREE DOUBLY LINKED STRUCTURE. */ +/* QSIZE - SIZE OF SUPERNODE (INITIALIZED TO ONE). */ +/* LLIST - LINKED LIST. */ +/* MARKER - MARKER VECTOR. */ + +/* *************************************************************** */ + +/* Subroutine */ int mmdint_(int *neqns, int *xadj, shortint *adjncy, + shortint *dhead, shortint *dforw, shortint *dbakw, shortint *qsize, + shortint *llist, shortint *marker) +{ + /* System generated locals */ + int i__1; + + /* Local variables */ + static int ndeg, node, fnode; + + +/* *************************************************************** */ + + +/* *************************************************************** */ + + /* Parameter adjustments */ + --marker; + --llist; + --qsize; + --dbakw; + --dforw; + --dhead; + --adjncy; + --xadj; + + /* Function Body */ + i__1 = *neqns; + for (node = 1; node <= i__1; ++node) { + dhead[node] = 0; + qsize[node] = 1; + marker[node] = 0; + llist[node] = 0; +/* L100: */ + } +/* ------------------------------------------ */ +/* INITIALIZE THE DEGREE DOUBLY LINKED LISTS. */ +/* ------------------------------------------ */ + i__1 = *neqns; + for (node = 1; node <= i__1; ++node) { + ndeg = xadj[node + 1] - xadj[node] + 1; + fnode = dhead[ndeg]; + dforw[node] = fnode; + dhead[ndeg] = node; + if (fnode > 0) { + dbakw[fnode] = node; + } + dbakw[node] = -ndeg; +/* L200: */ + } + return 0; + +} /* mmdint_ */ + +/* *************************************************************** */ +/* *************************************************************** */ +/* ** MMDELM ..... MULTIPLE MINIMUM DEGREE ELIMINATION *** */ +/* *************************************************************** */ +/* *************************************************************** */ + +/* AUTHOR - JOSEPH W.H. LIU */ +/* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */ + +/* PURPOSE - THIS ROUTINE ELIMINATES THE NODE MDNODE OF */ +/* MINIMUM DEGREE FROM THE ADJACENCY STRUCTURE, WHICH */ +/* IS STORED IN THE QUOTIENT GRAPH FORMAT. IT ALSO */ +/* TRANSFORMS THE QUOTIENT GRAPH REPRESENTATION OF THE */ +/* ELIMINATION GRAPH. */ + +/* INPUT PARAMETERS - */ +/* MDNODE - NODE OF MINIMUM DEGREE. */ +/* MAXINT - ESTIMATE OF MAXIMUM REPRESENTABLE (SHORT) */ +/* INT. */ +/* TAG - TAG VALUE. */ + +/* UPDATED PARAMETERS - */ +/* (XADJ,ADJNCY) - UPDATED ADJACENCY STRUCTURE. */ +/* (DHEAD,DFORW,DBAKW) - DEGREE DOUBLY LINKED STRUCTURE. */ +/* QSIZE - SIZE OF SUPERNODE. */ +/* MARKER - MARKER VECTOR. */ +/* LLIST - TEMPORARY LINKED LIST OF ELIMINATED NABORS. */ + +/* *************************************************************** */ + +/* Subroutine */ int mmdelm_(int *mdnode, int *xadj, shortint *adjncy, + shortint *dhead, shortint *dforw, shortint *dbakw, shortint *qsize, + shortint *llist, shortint *marker, int *maxint, int *tag) +{ + /* System generated locals */ + int i__1, i__2; + + /* Local variables */ + static int node, link, rloc, rlmt, i, j, nabor, rnode, elmnt, xqnbr, + istop, jstop, istrt, jstrt, nxnode, pvnode, nqnbrs, npv; + + +/* *************************************************************** */ + + +/* *************************************************************** */ + +/* ----------------------------------------------- */ +/* FIND REACHABLE SET AND PLACE IN DATA STRUCTURE. */ +/* ----------------------------------------------- */ + /* Parameter adjustments */ + --marker; + --llist; + --qsize; + --dbakw; + --dforw; + --dhead; + --adjncy; + --xadj; + + /* Function Body */ + marker[*mdnode] = *tag; + istrt = xadj[*mdnode]; + istop = xadj[*mdnode + 1] - 1; +/* ------------------------------------------------------- */ +/* ELMNT POINTS TO THE BEGINNING OF THE LIST OF ELIMINATED */ +/* NABORS OF MDNODE, AND RLOC GIVES THE STORAGE LOCATION */ +/* FOR THE NEXT REACHABLE NODE. */ +/* ------------------------------------------------------- */ + elmnt = 0; + rloc = istrt; + rlmt = istop; + i__1 = istop; + for (i = istrt; i <= i__1; ++i) { + nabor = adjncy[i]; + if (nabor == 0) { + goto L300; + } + if (marker[nabor] >= *tag) { + goto L200; + } + marker[nabor] = *tag; + if (dforw[nabor] < 0) { + goto L100; + } + adjncy[rloc] = nabor; + ++rloc; + goto L200; +L100: + llist[nabor] = elmnt; + elmnt = nabor; +L200: + ; + } +L300: +/* ----------------------------------------------------- */ +/* MERGE WITH REACHABLE NODES FROM GENERALIZED ELEMENTS. */ +/* ----------------------------------------------------- */ + if (elmnt <= 0) { + goto L1000; + } + adjncy[rlmt] = -elmnt; + link = elmnt; +L400: + jstrt = xadj[link]; + jstop = xadj[link + 1] - 1; + i__1 = jstop; + for (j = jstrt; j <= i__1; ++j) { + node = adjncy[j]; + link = -node; + if (node < 0) { + goto L400; + } else if (node == 0) { + goto L900; + } else { + goto L500; + } +L500: + if (marker[node] >= *tag || dforw[node] < 0) { + goto L800; + } + marker[node] = *tag; +/* --------------------------------- */ +/* USE STORAGE FROM ELIMINATED NODES */ +/* IF NECESSARY. */ +/* --------------------------------- */ +L600: + if (rloc < rlmt) { + goto L700; + } + link = -adjncy[rlmt]; + rloc = xadj[link]; + rlmt = xadj[link + 1] - 1; + goto L600; +L700: + adjncy[rloc] = node; + ++rloc; +L800: + ; + } +L900: + elmnt = llist[elmnt]; + goto L300; +L1000: + if (rloc <= rlmt) { + adjncy[rloc] = 0; + } +/* -------------------------------------------------------- */ +/* FOR EACH NODE IN THE REACHABLE SET, DO THE FOLLOWING ... */ +/* -------------------------------------------------------- */ + link = *mdnode; +L1100: + istrt = xadj[link]; + istop = xadj[link + 1] - 1; + i__1 = istop; + for (i = istrt; i <= i__1; ++i) { + rnode = adjncy[i]; + link = -rnode; + if (rnode < 0) { + goto L1100; + } else if (rnode == 0) { + goto L1800; + } else { + goto L1200; + } +L1200: +/* -------------------------------------------- */ +/* IF RNODE IS IN THE DEGREE LIST STRUCTURE ... */ +/* -------------------------------------------- */ + pvnode = dbakw[rnode]; + if (pvnode == 0 || pvnode == -(*maxint)) { + goto L1300; + } +/* ------------------------------------- */ +/* THEN REMOVE RNODE FROM THE STRUCTURE. */ +/* ------------------------------------- */ + nxnode = dforw[rnode]; + if (nxnode > 0) { + dbakw[nxnode] = pvnode; + } + if (pvnode > 0) { + dforw[pvnode] = nxnode; + } + npv = -pvnode; + if (pvnode < 0) { + dhead[npv] = nxnode; + } +L1300: +/* ---------------------------------------- */ +/* PURGE INACTIVE QUOTIENT NABORS OF RNODE. */ +/* ---------------------------------------- */ + jstrt = xadj[rnode]; + jstop = xadj[rnode + 1] - 1; + xqnbr = jstrt; + i__2 = jstop; + for (j = jstrt; j <= i__2; ++j) { + nabor = adjncy[j]; + if (nabor == 0) { + goto L1500; + } + if (marker[nabor] >= *tag) { + goto L1400; + } + adjncy[xqnbr] = nabor; + ++xqnbr; +L1400: + ; + } +L1500: +/* ---------------------------------------- */ +/* IF NO ACTIVE NABOR AFTER THE PURGING ... */ +/* ---------------------------------------- */ + nqnbrs = xqnbr - jstrt; + if (nqnbrs > 0) { + goto L1600; + } +/* ----------------------------- */ +/* THEN MERGE RNODE WITH MDNODE. */ +/* ----------------------------- */ + qsize[*mdnode] += qsize[rnode]; + qsize[rnode] = 0; + marker[rnode] = *maxint; + dforw[rnode] = -(*mdnode); + dbakw[rnode] = -(*maxint); + goto L1700; +L1600: +/* -------------------------------------- */ +/* ELSE FLAG RNODE FOR DEGREE UPDATE, AND */ +/* ADD MDNODE AS A NABOR OF RNODE. */ +/* -------------------------------------- */ + dforw[rnode] = nqnbrs + 1; + dbakw[rnode] = 0; + adjncy[xqnbr] = *mdnode; + ++xqnbr; + if (xqnbr <= jstop) { + adjncy[xqnbr] = 0; + } + +L1700: + ; + } +L1800: + return 0; + +} /* mmdelm_ */ + +/* *************************************************************** */ +/* *************************************************************** */ +/* ***** MMDUPD ..... MULTIPLE MINIMUM DEGREE UPDATE ***** */ +/* *************************************************************** */ +/* *************************************************************** */ + +/* AUTHOR - JOSEPH W.H. LIU */ +/* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */ + +/* PURPOSE - THIS ROUTINE UPDATES THE DEGREES OF NODES */ +/* AFTER A MULTIPLE ELIMINATION STEP. */ + +/* INPUT PARAMETERS - */ +/* EHEAD - THE BEGINNING OF THE LIST OF ELIMINATED */ +/* NODES (I.E., NEWLY FORMED ELEMENTS). */ +/* NEQNS - NUMBER OF EQUATIONS. */ +/* (XADJ,ADJNCY) - ADJACENCY STRUCTURE. */ +/* DELTA - TOLERANCE VALUE FOR MULTIPLE ELIMINATION. */ +/* MAXINT - MAXIMUM MACHINE REPRESENTABLE (SHORT) */ +/* INTEGER. */ + +/* UPDATED PARAMETERS - */ +/* MDEG - NEW MINIMUM DEGREE AFTER DEGREE UPDATE. */ +/* (DHEAD,DFORW,DBAKW) - DEGREE DOUBLY LINKED STRUCTURE. */ +/* QSIZE - SIZE OF SUPERNODE. */ +/* LLIST - WORKING LINKED LIST. */ +/* MARKER - MARKER VECTOR FOR DEGREE UPDATE. */ +/* TAG - TAG VALUE. */ + +/* *************************************************************** */ + +/* Subroutine */ int mmdupd_(int *ehead, int *neqns, int *xadj, + shortint *adjncy, int *delta, int *mdeg, shortint *dhead, + shortint *dforw, shortint *dbakw, shortint *qsize, shortint *llist, + shortint *marker, int *maxint, int *tag) +{ + /* System generated locals */ + int i__1, i__2; + + /* Local variables */ + static int node, mtag, link, mdeg0, i, j, enode, fnode, nabor, elmnt, + istop, jstop, q2head, istrt, jstrt, qxhead, iq2, deg, deg0; + + +/* *************************************************************** */ + + +/* *************************************************************** */ + + /* Parameter adjustments */ + --marker; + --llist; + --qsize; + --dbakw; + --dforw; + --dhead; + --adjncy; + --xadj; + + /* Function Body */ + mdeg0 = *mdeg + *delta; + elmnt = *ehead; +L100: +/* ------------------------------------------------------- */ +/* FOR EACH OF THE NEWLY FORMED ELEMENT, DO THE FOLLOWING. */ +/* (RESET TAG VALUE IF NECESSARY.) */ +/* ------------------------------------------------------- */ + if (elmnt <= 0) { + return 0; + } + mtag = *tag + mdeg0; + if (mtag < *maxint) { + goto L300; + } + *tag = 1; + i__1 = *neqns; + for (i = 1; i <= i__1; ++i) { + if (marker[i] < *maxint) { + marker[i] = 0; + } +/* L200: */ + } + mtag = *tag + mdeg0; +L300: +/* --------------------------------------------- */ +/* CREATE TWO LINKED LISTS FROM NODES ASSOCIATED */ +/* WITH ELMNT: ONE WITH TWO NABORS (Q2HEAD) IN */ +/* ADJACENCY STRUCTURE, AND THE OTHER WITH MORE */ +/* THAN TWO NABORS (QXHEAD). ALSO COMPUTE DEG0, */ +/* NUMBER OF NODES IN THIS ELEMENT. */ +/* --------------------------------------------- */ + q2head = 0; + qxhead = 0; + deg0 = 0; + link = elmnt; +L400: + istrt = xadj[link]; + istop = xadj[link + 1] - 1; + i__1 = istop; + for (i = istrt; i <= i__1; ++i) { + enode = adjncy[i]; + link = -enode; + if (enode < 0) { + goto L400; + } else if (enode == 0) { + goto L800; + } else { + goto L500; + } + +L500: + if (qsize[enode] == 0) { + goto L700; + } + deg0 += qsize[enode]; + marker[enode] = mtag; +/* ---------------------------------- */ +/* IF ENODE REQUIRES A DEGREE UPDATE, */ +/* THEN DO THE FOLLOWING. */ +/* ---------------------------------- */ + if (dbakw[enode] != 0) { + goto L700; + } +/* --------------------------------------- +*/ +/* PLACE EITHER IN QXHEAD OR Q2HEAD LISTS. +*/ +/* --------------------------------------- +*/ + if (dforw[enode] == 2) { + goto L600; + } + llist[enode] = qxhead; + qxhead = enode; + goto L700; +L600: + llist[enode] = q2head; + q2head = enode; +L700: + ; + } +L800: +/* -------------------------------------------- */ +/* FOR EACH ENODE IN Q2 LIST, DO THE FOLLOWING. */ +/* -------------------------------------------- */ + enode = q2head; + iq2 = 1; +L900: + if (enode <= 0) { + goto L1500; + } + if (dbakw[enode] != 0) { + goto L2200; + } + ++(*tag); + deg = deg0; +/* ------------------------------------------ */ +/* IDENTIFY THE OTHER ADJACENT ELEMENT NABOR. */ +/* ------------------------------------------ */ + istrt = xadj[enode]; + nabor = adjncy[istrt]; + if (nabor == elmnt) { + nabor = adjncy[istrt + 1]; + } +/* ------------------------------------------------ */ +/* IF NABOR IS UNELIMINATED, INCREASE DEGREE COUNT. */ +/* ------------------------------------------------ */ + link = nabor; + if (dforw[nabor] < 0) { + goto L1000; + } + deg += qsize[nabor]; + goto L2100; +L1000: +/* -------------------------------------------- */ +/* OTHERWISE, FOR EACH NODE IN THE 2ND ELEMENT, */ +/* DO THE FOLLOWING. */ +/* -------------------------------------------- */ + istrt = xadj[link]; + istop = xadj[link + 1] - 1; + i__1 = istop; + for (i = istrt; i <= i__1; ++i) { + node = adjncy[i]; + link = -node; + if (node == enode) { + goto L1400; + } + if (node < 0) { + goto L1000; + } else if (node == 0) { + goto L2100; + } else { + goto L1100; + } + +L1100: + if (qsize[node] == 0) { + goto L1400; + } + if (marker[node] >= *tag) { + goto L1200; + } +/* ----------------------------------- +-- */ +/* CASE WHEN NODE IS NOT YET CONSIDERED +. */ +/* ----------------------------------- +-- */ + marker[node] = *tag; + deg += qsize[node]; + goto L1400; +L1200: +/* ---------------------------------------- + */ +/* CASE WHEN NODE IS INDISTINGUISHABLE FROM + */ +/* ENODE. MERGE THEM INTO A NEW SUPERNODE. + */ +/* ---------------------------------------- + */ + if (dbakw[node] != 0) { + goto L1400; + } + if (dforw[node] != 2) { + goto L1300; + } + qsize[enode] += qsize[node]; + qsize[node] = 0; + marker[node] = *maxint; + dforw[node] = -enode; + dbakw[node] = -(*maxint); + goto L1400; +L1300: +/* -------------------------------------- +*/ +/* CASE WHEN NODE IS OUTMATCHED BY ENODE. +*/ +/* -------------------------------------- +*/ + if (dbakw[node] == 0) { + dbakw[node] = -(*maxint); + } +L1400: + ; + } + goto L2100; +L1500: +/* ------------------------------------------------ */ +/* FOR EACH ENODE IN THE QX LIST, DO THE FOLLOWING. */ +/* ------------------------------------------------ */ + enode = qxhead; + iq2 = 0; +L1600: + if (enode <= 0) { + goto L2300; + } + if (dbakw[enode] != 0) { + goto L2200; + } + ++(*tag); + deg = deg0; +/* --------------------------------- */ +/* FOR EACH UNMARKED NABOR OF ENODE, */ +/* DO THE FOLLOWING. */ +/* --------------------------------- */ + istrt = xadj[enode]; + istop = xadj[enode + 1] - 1; + i__1 = istop; + for (i = istrt; i <= i__1; ++i) { + nabor = adjncy[i]; + if (nabor == 0) { + goto L2100; + } + if (marker[nabor] >= *tag) { + goto L2000; + } + marker[nabor] = *tag; + link = nabor; +/* ------------------------------ */ +/* IF UNELIMINATED, INCLUDE IT IN */ +/* DEG COUNT. */ +/* ------------------------------ */ + if (dforw[nabor] < 0) { + goto L1700; + } + deg += qsize[nabor]; + goto L2000; +L1700: +/* ------------------------------- +*/ +/* IF ELIMINATED, INCLUDE UNMARKED +*/ +/* NODES IN THIS ELEMENT INTO THE +*/ +/* DEGREE COUNT. */ +/* ------------------------------- +*/ + jstrt = xadj[link]; + jstop = xadj[link + 1] - 1; + i__2 = jstop; + for (j = jstrt; j <= i__2; ++j) { + node = adjncy[j]; + link = -node; + if (node < 0) { + goto L1700; + } else if (node == 0) { + goto L2000; + } else { + goto L1800; + } + +L1800: + if (marker[node] >= *tag) { + goto L1900; + } + marker[node] = *tag; + deg += qsize[node]; +L1900: + ; + } +L2000: + ; + } +L2100: +/* ------------------------------------------- */ +/* UPDATE EXTERNAL DEGREE OF ENODE IN DEGREE */ +/* STRUCTURE, AND MDEG (MIN DEG) IF NECESSARY. */ +/* ------------------------------------------- */ + deg = deg - qsize[enode] + 1; + fnode = dhead[deg]; + dforw[enode] = fnode; + dbakw[enode] = -deg; + if (fnode > 0) { + dbakw[fnode] = enode; + } + dhead[deg] = enode; + if (deg < *mdeg) { + *mdeg = deg; + } +L2200: +/* ---------------------------------- */ +/* GET NEXT ENODE IN CURRENT ELEMENT. */ +/* ---------------------------------- */ + enode = llist[enode]; + if (iq2 == 1) { + goto L900; + } + goto L1600; +L2300: +/* ----------------------------- */ +/* GET NEXT ELEMENT IN THE LIST. */ +/* ----------------------------- */ + *tag = mtag; + elmnt = llist[elmnt]; + goto L100; + +} /* mmdupd_ */ + +/* *************************************************************** */ +/* *************************************************************** */ +/* ***** MMDNUM ..... MULTI MINIMUM DEGREE NUMBERING ***** */ +/* *************************************************************** */ +/* *************************************************************** */ + +/* AUTHOR - JOSEPH W.H. LIU */ +/* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */ + +/* PURPOSE - THIS ROUTINE PERFORMS THE FINAL STEP IN */ +/* PRODUCING THE PERMUTATION AND INVERSE PERMUTATION */ +/* VECTORS IN THE MULTIPLE ELIMINATION VERSION OF THE */ +/* MINIMUM DEGREE ORDERING ALGORITHM. */ + +/* INPUT PARAMETERS - */ +/* NEQNS - NUMBER OF EQUATIONS. */ +/* QSIZE - SIZE OF SUPERNODES AT ELIMINATION. */ + +/* UPDATED PARAMETERS - */ +/* INVP - INVERSE PERMUTATION VECTOR. ON INPUT, */ +/* IF QSIZE(NODE)=0, THEN NODE HAS BEEN MERGED */ +/* INTO THE NODE -INVP(NODE); OTHERWISE, */ +/* -INVP(NODE) IS ITS INVERSE LABELLING. */ + +/* OUTPUT PARAMETERS - */ +/* PERM - THE PERMUTATION VECTOR. */ + +/* *************************************************************** */ + +/* Subroutine */ int mmdnum_(int *neqns, shortint *perm, shortint *invp, + shortint *qsize) +{ + /* System generated locals */ + int i__1; + + /* Local variables */ + static int node, root, nextf, father, nqsize, num; + + +/* *************************************************************** */ + + +/* *************************************************************** */ + + /* Parameter adjustments */ + --qsize; + --invp; + --perm; + + /* Function Body */ + i__1 = *neqns; + for (node = 1; node <= i__1; ++node) { + nqsize = qsize[node]; + if (nqsize <= 0) { + perm[node] = invp[node]; + } + if (nqsize > 0) { + perm[node] = -invp[node]; + } +/* L100: */ + } +/* ------------------------------------------------------ */ +/* FOR EACH NODE WHICH HAS BEEN MERGED, DO THE FOLLOWING. */ +/* ------------------------------------------------------ */ + i__1 = *neqns; + for (node = 1; node <= i__1; ++node) { + if (perm[node] > 0) { + goto L500; + } +/* ----------------------------------------- */ +/* TRACE THE MERGED TREE UNTIL ONE WHICH HAS */ +/* NOT BEEN MERGED, CALL IT ROOT. */ +/* ----------------------------------------- */ + father = node; +L200: + if (perm[father] > 0) { + goto L300; + } + father = -perm[father]; + goto L200; +L300: +/* ----------------------- */ +/* NUMBER NODE AFTER ROOT. */ +/* ----------------------- */ + root = father; + num = perm[root] + 1; + invp[node] = -num; + perm[root] = num; +/* ------------------------ */ +/* SHORTEN THE MERGED TREE. */ +/* ------------------------ */ + father = node; +L400: + nextf = -perm[father]; + if (nextf <= 0) { + goto L500; + } + perm[father] = -root; + father = nextf; + goto L400; +L500: + ; + } +/* ---------------------- */ +/* READY TO COMPUTE PERM. */ +/* ---------------------- */ + i__1 = *neqns; + for (node = 1; node <= i__1; ++node) { + num = -invp[node]; + invp[node] = num; + perm[num] = node; +/* L600: */ + } + return 0; + +} /* mmdnum_ */ + diff --git a/intern/opennl/superlu/relax_snode.c b/intern/opennl/superlu/relax_snode.c new file mode 100644 index 00000000000..549f3fcf873 --- /dev/null +++ b/intern/opennl/superlu/relax_snode.c @@ -0,0 +1,71 @@ +/* + * -- SuperLU routine (version 2.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * November 15, 1997 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include "ssp_defs.h" + +void +relax_snode ( + const int n, + int *et, /* column elimination tree */ + const int relax_columns, /* max no of columns allowed in a + relaxed snode */ + int *descendants, /* no of descendants of each node + in the etree */ + int *relax_end /* last column in a supernode */ + ) +{ +/* + * Purpose + * ======= + * relax_snode() - Identify the initial relaxed supernodes, assuming that + * the matrix has been reordered according to the postorder of the etree. + * + */ + register int j, parent; + register int snode_start; /* beginning of a snode */ + + ifill (relax_end, n, EMPTY); + for (j = 0; j < n; j++) descendants[j] = 0; + + /* Compute the number of descendants of each node in the etree */ + for (j = 0; j < n; j++) { + parent = et[j]; + if ( parent != n ) /* not the dummy root */ + descendants[parent] += descendants[j] + 1; + } + + /* Identify the relaxed supernodes by postorder traversal of the etree. */ + for (j = 0; j < n; ) { + parent = et[j]; + snode_start = j; + while ( parent != n && descendants[parent] < relax_columns ) { + j = parent; + parent = et[j]; + } + /* Found a supernode with j being the last column. */ + relax_end[snode_start] = j; /* Last column is recorded */ + j++; + /* Search for a new leaf */ + while ( descendants[j] != 0 && j < n ) j++; + } + + /*printf("No of relaxed snodes: %d; relaxed columns: %d\n", + nsuper, no_relaxed_col); */ +} diff --git a/intern/opennl/superlu/scolumn_bmod.c b/intern/opennl/superlu/scolumn_bmod.c new file mode 100644 index 00000000000..c877a27dd53 --- /dev/null +++ b/intern/opennl/superlu/scolumn_bmod.c @@ -0,0 +1,353 @@ + +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include +#include +#include "ssp_defs.h" + +/* + * Function prototypes + */ +void susolve(int, int, float*, float*); +void slsolve(int, int, float*, float*); +void smatvec(int, int, int, float*, float*, float*); + + + +/* Return value: 0 - successful return + * > 0 - number of bytes allocated when run out of space + */ +int +scolumn_bmod ( + const int jcol, /* in */ + const int nseg, /* in */ + float *dense, /* in */ + float *tempv, /* working array */ + int *segrep, /* in */ + int *repfnz, /* in */ + int fpanelc, /* in -- first column in the current panel */ + GlobalLU_t *Glu, /* modified */ + SuperLUStat_t *stat /* output */ + ) +{ +/* + * Purpose: + * ======== + * Performs numeric block updates (sup-col) in topological order. + * It features: col-col, 2cols-col, 3cols-col, and sup-col updates. + * Special processing on the supernodal portion of L\U[*,j] + * + */ +#ifdef _CRAY + _fcd ftcs1 = _cptofcd("L", strlen("L")), + ftcs2 = _cptofcd("N", strlen("N")), + ftcs3 = _cptofcd("U", strlen("U")); +#endif + +#ifdef USE_VENDOR_BLAS + int incx = 1, incy = 1; + float alpha, beta; +#endif + + /* krep = representative of current k-th supernode + * fsupc = first supernodal column + * nsupc = no of columns in supernode + * nsupr = no of rows in supernode (used as leading dimension) + * luptr = location of supernodal LU-block in storage + * kfnz = first nonz in the k-th supernodal segment + * no_zeros = no of leading zeros in a supernodal U-segment + */ + float ukj, ukj1, ukj2; + int luptr, luptr1, luptr2; + int fsupc, nsupc, nsupr, segsze; + int nrow; /* No of rows in the matrix of matrix-vector */ + int jcolp1, jsupno, k, ksub, krep, krep_ind, ksupno; + register int lptr, kfnz, isub, irow, i; + register int no_zeros, new_next; + int ufirst, nextlu; + int fst_col; /* First column within small LU update */ + int d_fsupc; /* Distance between the first column of the current + panel and the first column of the current snode. */ + int *xsup, *supno; + int *lsub, *xlsub; + float *lusup; + int *xlusup; + int nzlumax; + float *tempv1; + float zero = 0.0; +#ifdef USE_VENDOR_BLAS + float one = 1.0; + float none = -1.0; +#endif + int mem_error; + flops_t *ops = stat->ops; + + xsup = Glu->xsup; + supno = Glu->supno; + lsub = Glu->lsub; + xlsub = Glu->xlsub; + lusup = Glu->lusup; + xlusup = Glu->xlusup; + nzlumax = Glu->nzlumax; + jcolp1 = jcol + 1; + jsupno = supno[jcol]; + + /* + * For each nonz supernode segment of U[*,j] in topological order + */ + k = nseg - 1; + for (ksub = 0; ksub < nseg; ksub++) { + + krep = segrep[k]; + k--; + ksupno = supno[krep]; + if ( jsupno != ksupno ) { /* Outside the rectangular supernode */ + + fsupc = xsup[ksupno]; + fst_col = SUPERLU_MAX ( fsupc, fpanelc ); + + /* Distance from the current supernode to the current panel; + d_fsupc=0 if fsupc > fpanelc. */ + d_fsupc = fst_col - fsupc; + + luptr = xlusup[fst_col] + d_fsupc; + lptr = xlsub[fsupc] + d_fsupc; + + kfnz = repfnz[krep]; + kfnz = SUPERLU_MAX ( kfnz, fpanelc ); + + segsze = krep - kfnz + 1; + nsupc = krep - fst_col + 1; + nsupr = xlsub[fsupc+1] - xlsub[fsupc]; /* Leading dimension */ + nrow = nsupr - d_fsupc - nsupc; + krep_ind = lptr + nsupc - 1; + + ops[TRSV] += segsze * (segsze - 1); + ops[GEMV] += 2 * nrow * segsze; + + + /* + * Case 1: Update U-segment of size 1 -- col-col update + */ + if ( segsze == 1 ) { + ukj = dense[lsub[krep_ind]]; + luptr += nsupr*(nsupc-1) + nsupc; + + for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) { + irow = lsub[i]; + dense[irow] -= ukj*lusup[luptr]; + luptr++; + } + + } else if ( segsze <= 3 ) { + ukj = dense[lsub[krep_ind]]; + luptr += nsupr*(nsupc-1) + nsupc-1; + ukj1 = dense[lsub[krep_ind - 1]]; + luptr1 = luptr - nsupr; + + if ( segsze == 2 ) { /* Case 2: 2cols-col update */ + ukj -= ukj1 * lusup[luptr1]; + dense[lsub[krep_ind]] = ukj; + for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) { + irow = lsub[i]; + luptr++; + luptr1++; + dense[irow] -= ( ukj*lusup[luptr] + + ukj1*lusup[luptr1] ); + } + } else { /* Case 3: 3cols-col update */ + ukj2 = dense[lsub[krep_ind - 2]]; + luptr2 = luptr1 - nsupr; + ukj1 -= ukj2 * lusup[luptr2-1]; + ukj = ukj - ukj1*lusup[luptr1] - ukj2*lusup[luptr2]; + dense[lsub[krep_ind]] = ukj; + dense[lsub[krep_ind-1]] = ukj1; + for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) { + irow = lsub[i]; + luptr++; + luptr1++; + luptr2++; + dense[irow] -= ( ukj*lusup[luptr] + + ukj1*lusup[luptr1] + ukj2*lusup[luptr2] ); + } + } + + + + } else { + /* + * Case: sup-col update + * Perform a triangular solve and block update, + * then scatter the result of sup-col update to dense + */ + + no_zeros = kfnz - fst_col; + + /* Copy U[*,j] segment from dense[*] to tempv[*] */ + isub = lptr + no_zeros; + for (i = 0; i < segsze; i++) { + irow = lsub[isub]; + tempv[i] = dense[irow]; + ++isub; + } + + /* Dense triangular solve -- start effective triangle */ + luptr += nsupr * no_zeros + no_zeros; + +#ifdef USE_VENDOR_BLAS +#ifdef _CRAY + STRSV( ftcs1, ftcs2, ftcs3, &segsze, &lusup[luptr], + &nsupr, tempv, &incx ); +#else + strsv_( "L", "N", "U", &segsze, &lusup[luptr], + &nsupr, tempv, &incx ); +#endif + luptr += segsze; /* Dense matrix-vector */ + tempv1 = &tempv[segsze]; + alpha = one; + beta = zero; +#ifdef _CRAY + SGEMV( ftcs2, &nrow, &segsze, &alpha, &lusup[luptr], + &nsupr, tempv, &incx, &beta, tempv1, &incy ); +#else + sgemv_( "N", &nrow, &segsze, &alpha, &lusup[luptr], + &nsupr, tempv, &incx, &beta, tempv1, &incy ); +#endif +#else + slsolve ( nsupr, segsze, &lusup[luptr], tempv ); + + luptr += segsze; /* Dense matrix-vector */ + tempv1 = &tempv[segsze]; + smatvec (nsupr, nrow , segsze, &lusup[luptr], tempv, tempv1); +#endif + + + /* Scatter tempv[] into SPA dense[] as a temporary storage */ + isub = lptr + no_zeros; + for (i = 0; i < segsze; i++) { + irow = lsub[isub]; + dense[irow] = tempv[i]; + tempv[i] = zero; + ++isub; + } + + /* Scatter tempv1[] into SPA dense[] */ + for (i = 0; i < nrow; i++) { + irow = lsub[isub]; + dense[irow] -= tempv1[i]; + tempv1[i] = zero; + ++isub; + } + } + + } /* if jsupno ... */ + + } /* for each segment... */ + + /* + * Process the supernodal portion of L\U[*,j] + */ + nextlu = xlusup[jcol]; + fsupc = xsup[jsupno]; + + /* Copy the SPA dense into L\U[*,j] */ + new_next = nextlu + xlsub[fsupc+1] - xlsub[fsupc]; + while ( new_next > nzlumax ) { + if ((mem_error = sLUMemXpand(jcol, nextlu, LUSUP, &nzlumax, Glu))) + return (mem_error); + lusup = Glu->lusup; + lsub = Glu->lsub; + } + + for (isub = xlsub[fsupc]; isub < xlsub[fsupc+1]; isub++) { + irow = lsub[isub]; + lusup[nextlu] = dense[irow]; + dense[irow] = zero; + ++nextlu; + } + + xlusup[jcolp1] = nextlu; /* Close L\U[*,jcol] */ + + /* For more updates within the panel (also within the current supernode), + * should start from the first column of the panel, or the first column + * of the supernode, whichever is bigger. There are 2 cases: + * 1) fsupc < fpanelc, then fst_col := fpanelc + * 2) fsupc >= fpanelc, then fst_col := fsupc + */ + fst_col = SUPERLU_MAX ( fsupc, fpanelc ); + + if ( fst_col < jcol ) { + + /* Distance between the current supernode and the current panel. + d_fsupc=0 if fsupc >= fpanelc. */ + d_fsupc = fst_col - fsupc; + + lptr = xlsub[fsupc] + d_fsupc; + luptr = xlusup[fst_col] + d_fsupc; + nsupr = xlsub[fsupc+1] - xlsub[fsupc]; /* Leading dimension */ + nsupc = jcol - fst_col; /* Excluding jcol */ + nrow = nsupr - d_fsupc - nsupc; + + /* Points to the beginning of jcol in snode L\U(jsupno) */ + ufirst = xlusup[jcol] + d_fsupc; + + ops[TRSV] += nsupc * (nsupc - 1); + ops[GEMV] += 2 * nrow * nsupc; + +#ifdef USE_VENDOR_BLAS +#ifdef _CRAY + STRSV( ftcs1, ftcs2, ftcs3, &nsupc, &lusup[luptr], + &nsupr, &lusup[ufirst], &incx ); +#else + strsv_( "L", "N", "U", &nsupc, &lusup[luptr], + &nsupr, &lusup[ufirst], &incx ); +#endif + + alpha = none; beta = one; /* y := beta*y + alpha*A*x */ + +#ifdef _CRAY + SGEMV( ftcs2, &nrow, &nsupc, &alpha, &lusup[luptr+nsupc], &nsupr, + &lusup[ufirst], &incx, &beta, &lusup[ufirst+nsupc], &incy ); +#else + sgemv_( "N", &nrow, &nsupc, &alpha, &lusup[luptr+nsupc], &nsupr, + &lusup[ufirst], &incx, &beta, &lusup[ufirst+nsupc], &incy ); +#endif +#else + slsolve ( nsupr, nsupc, &lusup[luptr], &lusup[ufirst] ); + + smatvec ( nsupr, nrow, nsupc, &lusup[luptr+nsupc], + &lusup[ufirst], tempv ); + + /* Copy updates from tempv[*] into lusup[*] */ + isub = ufirst + nsupc; + for (i = 0; i < nrow; i++) { + lusup[isub] -= tempv[i]; + tempv[i] = 0.0; + ++isub; + } + +#endif + + + } /* if fst_col < jcol ... */ + + return 0; +} diff --git a/intern/opennl/superlu/scolumn_dfs.c b/intern/opennl/superlu/scolumn_dfs.c new file mode 100644 index 00000000000..ecfb5c3b839 --- /dev/null +++ b/intern/opennl/superlu/scolumn_dfs.c @@ -0,0 +1,270 @@ + + +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include "ssp_defs.h" + +/* What type of supernodes we want */ +#define T2_SUPER + +int +scolumn_dfs( + const int m, /* in - number of rows in the matrix */ + const int jcol, /* in */ + int *perm_r, /* in */ + int *nseg, /* modified - with new segments appended */ + int *lsub_col, /* in - defines the RHS vector to start the dfs */ + int *segrep, /* modified - with new segments appended */ + int *repfnz, /* modified */ + int *xprune, /* modified */ + int *marker, /* modified */ + int *parent, /* working array */ + int *xplore, /* working array */ + GlobalLU_t *Glu /* modified */ + ) +{ +/* + * Purpose + * ======= + * "column_dfs" performs a symbolic factorization on column jcol, and + * decide the supernode boundary. + * + * This routine does not use numeric values, but only use the RHS + * row indices to start the dfs. + * + * A supernode representative is the last column of a supernode. + * The nonzeros in U[*,j] are segments that end at supernodal + * representatives. The routine returns a list of such supernodal + * representatives in topological order of the dfs that generates them. + * The location of the first nonzero in each such supernodal segment + * (supernodal entry location) is also returned. + * + * Local parameters + * ================ + * nseg: no of segments in current U[*,j] + * jsuper: jsuper=EMPTY if column j does not belong to the same + * supernode as j-1. Otherwise, jsuper=nsuper. + * + * marker2: A-row --> A-row/col (0/1) + * repfnz: SuperA-col --> PA-row + * parent: SuperA-col --> SuperA-col + * xplore: SuperA-col --> index to L-structure + * + * Return value + * ============ + * 0 success; + * > 0 number of bytes allocated when run out of space. + * + */ + int jcolp1, jcolm1, jsuper, nsuper, nextl; + int k, krep, krow, kmark, kperm; + int *marker2; /* Used for small panel LU */ + int fsupc; /* First column of a snode */ + int myfnz; /* First nonz column of a U-segment */ + int chperm, chmark, chrep, kchild; + int xdfs, maxdfs, kpar, oldrep; + int jptr, jm1ptr; + int ito, ifrom, istop; /* Used to compress row subscripts */ + int mem_error; + int *xsup, *supno, *lsub, *xlsub; + int nzlmax; + static int first = 1, maxsuper; + + xsup = Glu->xsup; + supno = Glu->supno; + lsub = Glu->lsub; + xlsub = Glu->xlsub; + nzlmax = Glu->nzlmax; + + if ( first ) { + maxsuper = sp_ienv(3); + first = 0; + } + jcolp1 = jcol + 1; + jcolm1 = jcol - 1; + nsuper = supno[jcol]; + jsuper = nsuper; + nextl = xlsub[jcol]; + marker2 = &marker[2*m]; + + + /* For each nonzero in A[*,jcol] do dfs */ + for (k = 0; lsub_col[k] != EMPTY; k++) { + + krow = lsub_col[k]; + lsub_col[k] = EMPTY; + kmark = marker2[krow]; + + /* krow was visited before, go to the next nonz */ + if ( kmark == jcol ) continue; + + /* For each unmarked nbr krow of jcol + * krow is in L: place it in structure of L[*,jcol] + */ + marker2[krow] = jcol; + kperm = perm_r[krow]; + + if ( kperm == EMPTY ) { + lsub[nextl++] = krow; /* krow is indexed into A */ + if ( nextl >= nzlmax ) { + if ((mem_error = sLUMemXpand(jcol, nextl, LSUB, &nzlmax, Glu))) + return (mem_error); + lsub = Glu->lsub; + } + if ( kmark != jcolm1 ) jsuper = EMPTY;/* Row index subset testing */ + } else { + /* krow is in U: if its supernode-rep krep + * has been explored, update repfnz[*] + */ + krep = xsup[supno[kperm]+1] - 1; + myfnz = repfnz[krep]; + + if ( myfnz != EMPTY ) { /* Visited before */ + if ( myfnz > kperm ) repfnz[krep] = kperm; + /* continue; */ + } + else { + /* Otherwise, perform dfs starting at krep */ + oldrep = EMPTY; + parent[krep] = oldrep; + repfnz[krep] = kperm; + xdfs = xlsub[krep]; + maxdfs = xprune[krep]; + + do { + /* + * For each unmarked kchild of krep + */ + while ( xdfs < maxdfs ) { + + kchild = lsub[xdfs]; + xdfs++; + chmark = marker2[kchild]; + + if ( chmark != jcol ) { /* Not reached yet */ + marker2[kchild] = jcol; + chperm = perm_r[kchild]; + + /* Case kchild is in L: place it in L[*,k] */ + if ( chperm == EMPTY ) { + lsub[nextl++] = kchild; + if ( nextl >= nzlmax ) { + if ((mem_error = + sLUMemXpand(jcol,nextl,LSUB,&nzlmax,Glu))) + return (mem_error); + lsub = Glu->lsub; + } + if ( chmark != jcolm1 ) jsuper = EMPTY; + } else { + /* Case kchild is in U: + * chrep = its supernode-rep. If its rep has + * been explored, update its repfnz[*] + */ + chrep = xsup[supno[chperm]+1] - 1; + myfnz = repfnz[chrep]; + if ( myfnz != EMPTY ) { /* Visited before */ + if ( myfnz > chperm ) + repfnz[chrep] = chperm; + } else { + /* Continue dfs at super-rep of kchild */ + xplore[krep] = xdfs; + oldrep = krep; + krep = chrep; /* Go deeper down G(L^t) */ + parent[krep] = oldrep; + repfnz[krep] = chperm; + xdfs = xlsub[krep]; + maxdfs = xprune[krep]; + } /* else */ + + } /* else */ + + } /* if */ + + } /* while */ + + /* krow has no more unexplored nbrs; + * place supernode-rep krep in postorder DFS. + * backtrack dfs to its parent + */ + segrep[*nseg] = krep; + ++(*nseg); + kpar = parent[krep]; /* Pop from stack, mimic recursion */ + if ( kpar == EMPTY ) break; /* dfs done */ + krep = kpar; + xdfs = xplore[krep]; + maxdfs = xprune[krep]; + + } while ( kpar != EMPTY ); /* Until empty stack */ + + } /* else */ + + } /* else */ + + } /* for each nonzero ... */ + + /* Check to see if j belongs in the same supernode as j-1 */ + if ( jcol == 0 ) { /* Do nothing for column 0 */ + nsuper = supno[0] = 0; + } else { + fsupc = xsup[nsuper]; + jptr = xlsub[jcol]; /* Not compressed yet */ + jm1ptr = xlsub[jcolm1]; + +#ifdef T2_SUPER + if ( (nextl-jptr != jptr-jm1ptr-1) ) jsuper = EMPTY; +#endif + /* Make sure the number of columns in a supernode doesn't + exceed threshold. */ + if ( jcol - fsupc >= maxsuper ) jsuper = EMPTY; + + /* If jcol starts a new supernode, reclaim storage space in + * lsub from the previous supernode. Note we only store + * the subscript set of the first and last columns of + * a supernode. (first for num values, last for pruning) + */ + if ( jsuper == EMPTY ) { /* starts a new supernode */ + if ( (fsupc < jcolm1-1) ) { /* >= 3 columns in nsuper */ +#ifdef CHK_COMPRESS + printf(" Compress lsub[] at super %d-%d\n", fsupc, jcolm1); +#endif + ito = xlsub[fsupc+1]; + xlsub[jcolm1] = ito; + istop = ito + jptr - jm1ptr; + xprune[jcolm1] = istop; /* Initialize xprune[jcol-1] */ + xlsub[jcol] = istop; + for (ifrom = jm1ptr; ifrom < nextl; ++ifrom, ++ito) + lsub[ito] = lsub[ifrom]; + nextl = ito; /* = istop + length(jcol) */ + } + nsuper++; + supno[jcol] = nsuper; + } /* if a new supernode */ + + } /* else: jcol > 0 */ + + /* Tidy up the pointers before exit */ + xsup[nsuper+1] = jcolp1; + supno[jcolp1] = nsuper; + xprune[jcol] = nextl; /* Initialize upper bound for pruning */ + xlsub[jcolp1] = nextl; + + return 0; +} diff --git a/intern/opennl/superlu/scopy_to_ucol.c b/intern/opennl/superlu/scopy_to_ucol.c new file mode 100644 index 00000000000..fd97352923f --- /dev/null +++ b/intern/opennl/superlu/scopy_to_ucol.c @@ -0,0 +1,105 @@ + + +/* + * -- SuperLU routine (version 2.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * November 15, 1997 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include "ssp_defs.h" +#include "util.h" + +int +scopy_to_ucol( + int jcol, /* in */ + int nseg, /* in */ + int *segrep, /* in */ + int *repfnz, /* in */ + int *perm_r, /* in */ + float *dense, /* modified - reset to zero on return */ + GlobalLU_t *Glu /* modified */ + ) +{ +/* + * Gather from SPA dense[*] to global ucol[*]. + */ + int ksub, krep, ksupno; + int i, k, kfnz, segsze; + int fsupc, isub, irow; + int jsupno, nextu; + int new_next, mem_error; + int *xsup, *supno; + int *lsub, *xlsub; + float *ucol; + int *usub, *xusub; + int nzumax; + + float zero = 0.0; + + xsup = Glu->xsup; + supno = Glu->supno; + lsub = Glu->lsub; + xlsub = Glu->xlsub; + ucol = Glu->ucol; + usub = Glu->usub; + xusub = Glu->xusub; + nzumax = Glu->nzumax; + + jsupno = supno[jcol]; + nextu = xusub[jcol]; + k = nseg - 1; + for (ksub = 0; ksub < nseg; ksub++) { + krep = segrep[k--]; + ksupno = supno[krep]; + + if ( ksupno != jsupno ) { /* Should go into ucol[] */ + kfnz = repfnz[krep]; + if ( kfnz != EMPTY ) { /* Nonzero U-segment */ + + fsupc = xsup[ksupno]; + isub = xlsub[fsupc] + kfnz - fsupc; + segsze = krep - kfnz + 1; + + new_next = nextu + segsze; + while ( new_next > nzumax ) { + if ((mem_error = sLUMemXpand(jcol, nextu, UCOL, &nzumax, Glu))) + return (mem_error); + ucol = Glu->ucol; + if ((mem_error = sLUMemXpand(jcol, nextu, USUB, &nzumax, Glu))) + return (mem_error); + usub = Glu->usub; + lsub = Glu->lsub; + } + + for (i = 0; i < segsze; i++) { + irow = lsub[isub]; + usub[nextu] = perm_r[irow]; + ucol[nextu] = dense[irow]; + dense[irow] = zero; + nextu++; + isub++; + } + + } + + } + + } /* for each segment... */ + + xusub[jcol + 1] = nextu; /* Close U[*,jcol] */ + return 0; +} diff --git a/intern/opennl/superlu/sgssv.c b/intern/opennl/superlu/sgssv.c new file mode 100644 index 00000000000..ede3dc83907 --- /dev/null +++ b/intern/opennl/superlu/sgssv.c @@ -0,0 +1,221 @@ + + +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +#include "ssp_defs.h" + +void +sgssv(superlu_options_t *options, SuperMatrix *A, int *perm_c, int *perm_r, + SuperMatrix *L, SuperMatrix *U, SuperMatrix *B, + SuperLUStat_t *stat, int *info ) +{ +/* + * Purpose + * ======= + * + * SGSSV solves the system of linear equations A*X=B, using the + * LU factorization from SGSTRF. It performs the following steps: + * + * 1. If A is stored column-wise (A->Stype = SLU_NC): + * + * 1.1. Permute the columns of A, forming A*Pc, where Pc + * is a permutation matrix. For more details of this step, + * see sp_preorder.c. + * + * 1.2. Factor A as Pr*A*Pc=L*U with the permutation Pr determined + * by Gaussian elimination with partial pivoting. + * L is unit lower triangular with offdiagonal entries + * bounded by 1 in magnitude, and U is upper triangular. + * + * 1.3. Solve the system of equations A*X=B using the factored + * form of A. + * + * 2. If A is stored row-wise (A->Stype = SLU_NR), apply the + * above algorithm to the transpose of A: + * + * 2.1. Permute columns of transpose(A) (rows of A), + * forming transpose(A)*Pc, where Pc is a permutation matrix. + * For more details of this step, see sp_preorder.c. + * + * 2.2. Factor A as Pr*transpose(A)*Pc=L*U with the permutation Pr + * determined by Gaussian elimination with partial pivoting. + * L is unit lower triangular with offdiagonal entries + * bounded by 1 in magnitude, and U is upper triangular. + * + * 2.3. Solve the system of equations A*X=B using the factored + * form of A. + * + * See supermatrix.h for the definition of 'SuperMatrix' structure. + * + * Arguments + * ========= + * + * options (input) superlu_options_t* + * The structure defines the input parameters to control + * how the LU decomposition will be performed and how the + * system will be solved. + * + * A (input) SuperMatrix* + * Matrix A in A*X=B, of dimension (A->nrow, A->ncol). The number + * of linear equations is A->nrow. Currently, the type of A can be: + * Stype = SLU_NC or SLU_NR; Dtype = SLU_S; Mtype = SLU_GE. + * In the future, more general A may be handled. + * + * perm_c (input/output) int* + * If A->Stype = SLU_NC, column permutation vector of size A->ncol + * which defines the permutation matrix Pc; perm_c[i] = j means + * column i of A is in position j in A*Pc. + * If A->Stype = SLU_NR, column permutation vector of size A->nrow + * which describes permutation of columns of transpose(A) + * (rows of A) as described above. + * + * If options->ColPerm = MY_PERMC or options->Fact = SamePattern or + * options->Fact = SamePattern_SameRowPerm, it is an input argument. + * On exit, perm_c may be overwritten by the product of the input + * perm_c and a permutation that postorders the elimination tree + * of Pc'*A'*A*Pc; perm_c is not changed if the elimination tree + * is already in postorder. + * Otherwise, it is an output argument. + * + * perm_r (input/output) int* + * If A->Stype = SLU_NC, row permutation vector of size A->nrow, + * which defines the permutation matrix Pr, and is determined + * by partial pivoting. perm_r[i] = j means row i of A is in + * position j in Pr*A. + * If A->Stype = SLU_NR, permutation vector of size A->ncol, which + * determines permutation of rows of transpose(A) + * (columns of A) as described above. + * + * If options->RowPerm = MY_PERMR or + * options->Fact = SamePattern_SameRowPerm, perm_r is an + * input argument. + * otherwise it is an output argument. + * + * L (output) SuperMatrix* + * The factor L from the factorization + * Pr*A*Pc=L*U (if A->Stype = SLU_NC) or + * Pr*transpose(A)*Pc=L*U (if A->Stype = SLU_NR). + * Uses compressed row subscripts storage for supernodes, i.e., + * L has types: Stype = SLU_SC, Dtype = SLU_S, Mtype = SLU_TRLU. + * + * U (output) SuperMatrix* + * The factor U from the factorization + * Pr*A*Pc=L*U (if A->Stype = SLU_NC) or + * Pr*transpose(A)*Pc=L*U (if A->Stype = SLU_NR). + * Uses column-wise storage scheme, i.e., U has types: + * Stype = SLU_NC, Dtype = SLU_S, Mtype = SLU_TRU. + * + * B (input/output) SuperMatrix* + * B has types: Stype = SLU_DN, Dtype = SLU_S, Mtype = SLU_GE. + * On entry, the right hand side matrix. + * On exit, the solution matrix if info = 0; + * + * stat (output) SuperLUStat_t* + * Record the statistics on runtime and floating-point operation count. + * See util.h for the definition of 'SuperLUStat_t'. + * + * info (output) int* + * = 0: successful exit + * > 0: if info = i, and i is + * <= A->ncol: U(i,i) is exactly zero. The factorization has + * been completed, but the factor U is exactly singular, + * so the solution could not be computed. + * > A->ncol: number of bytes allocated when memory allocation + * failure occurred, plus A->ncol. + * + */ + DNformat *Bstore; + SuperMatrix *AA = NULL;/* A in SLU_NC format used by the factorization routine.*/ + SuperMatrix AC; /* Matrix postmultiplied by Pc */ + int lwork = 0, *etree, i; + + /* Set default values for some parameters */ + int panel_size; /* panel size */ + int relax; /* no of columns in a relaxed snodes */ + int permc_spec; + trans_t trans = NOTRANS; + double *utime; + double t; /* Temporary time */ + + /* Test the input parameters ... */ + *info = 0; + Bstore = B->Store; + if ( options->Fact != DOFACT ) *info = -1; + else if ( A->nrow != A->ncol || A->nrow < 0 || + (A->Stype != SLU_NC && A->Stype != SLU_NR) || + A->Dtype != SLU_S || A->Mtype != SLU_GE ) + *info = -2; + else if ( B->ncol < 0 || Bstore->lda < SUPERLU_MAX(0, A->nrow) || + B->Stype != SLU_DN || B->Dtype != SLU_S || B->Mtype != SLU_GE ) + *info = -7; + if ( *info != 0 ) { + i = -(*info); + xerbla_("sgssv", &i); + return; + } + + utime = stat->utime; + + /* Convert A to SLU_NC format when necessary. */ + if ( A->Stype == SLU_NR ) { + NRformat *Astore = A->Store; + AA = (SuperMatrix *) SUPERLU_MALLOC( sizeof(SuperMatrix) ); + sCreate_CompCol_Matrix(AA, A->ncol, A->nrow, Astore->nnz, + Astore->nzval, Astore->colind, Astore->rowptr, + SLU_NC, A->Dtype, A->Mtype); + trans = TRANS; + } else { + if ( A->Stype == SLU_NC ) AA = A; + } + + t = SuperLU_timer_(); + /* + * Get column permutation vector perm_c[], according to permc_spec: + * permc_spec = NATURAL: natural ordering + * permc_spec = MMD_AT_PLUS_A: minimum degree on structure of A'+A + * permc_spec = MMD_ATA: minimum degree on structure of A'*A + * permc_spec = COLAMD: approximate minimum degree column ordering + * permc_spec = MY_PERMC: the ordering already supplied in perm_c[] + */ + permc_spec = options->ColPerm; + if ( permc_spec != MY_PERMC && options->Fact == DOFACT ) + get_perm_c(permc_spec, AA, perm_c); + utime[COLPERM] = SuperLU_timer_() - t; + + etree = intMalloc(A->ncol); + + t = SuperLU_timer_(); + sp_preorder(options, AA, perm_c, etree, &AC); + utime[ETREE] = SuperLU_timer_() - t; + + panel_size = sp_ienv(1); + relax = sp_ienv(2); + + /*printf("Factor PA = LU ... relax %d\tw %d\tmaxsuper %d\trowblk %d\n", + relax, panel_size, sp_ienv(3), sp_ienv(4));*/ + t = SuperLU_timer_(); + /* Compute the LU factorization of A. */ + sgstrf(options, &AC, relax, panel_size, + etree, NULL, lwork, perm_c, perm_r, L, U, stat, info); + utime[FACT] = SuperLU_timer_() - t; + + t = SuperLU_timer_(); + if ( *info == 0 ) { + /* Solve the system A*X=B, overwriting B with X. */ + sgstrs (trans, L, U, perm_c, perm_r, B, stat, info); + } + utime[SOLVE] = SuperLU_timer_() - t; + + SUPERLU_FREE (etree); + Destroy_CompCol_Permuted(&AC); + if ( A->Stype == SLU_NR ) { + Destroy_SuperMatrix_Store(AA); + SUPERLU_FREE(AA); + } + +} diff --git a/intern/opennl/superlu/sgstrf.c b/intern/opennl/superlu/sgstrf.c new file mode 100644 index 00000000000..42f8dc9d0ee --- /dev/null +++ b/intern/opennl/superlu/sgstrf.c @@ -0,0 +1,433 @@ + +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include "ssp_defs.h" + +void +sgstrf (superlu_options_t *options, SuperMatrix *A, + int relax, int panel_size, int *etree, void *work, int lwork, + int *perm_c, int *perm_r, SuperMatrix *L, SuperMatrix *U, + SuperLUStat_t *stat, int *info) +{ +/* + * Purpose + * ======= + * + * SGSTRF computes an LU factorization of a general sparse m-by-n + * matrix A using partial pivoting with row interchanges. + * The factorization has the form + * Pr * A = L * U + * where Pr is a row permutation matrix, L is lower triangular with unit + * diagonal elements (lower trapezoidal if A->nrow > A->ncol), and U is upper + * triangular (upper trapezoidal if A->nrow < A->ncol). + * + * See supermatrix.h for the definition of 'SuperMatrix' structure. + * + * Arguments + * ========= + * + * options (input) superlu_options_t* + * The structure defines the input parameters to control + * how the LU decomposition will be performed. + * + * A (input) SuperMatrix* + * Original matrix A, permuted by columns, of dimension + * (A->nrow, A->ncol). The type of A can be: + * Stype = SLU_NCP; Dtype = SLU_S; Mtype = SLU_GE. + * + * drop_tol (input) float (NOT IMPLEMENTED) + * Drop tolerance parameter. At step j of the Gaussian elimination, + * if abs(A_ij)/(max_i abs(A_ij)) < drop_tol, drop entry A_ij. + * 0 <= drop_tol <= 1. The default value of drop_tol is 0. + * + * relax (input) int + * To control degree of relaxing supernodes. If the number + * of nodes (columns) in a subtree of the elimination tree is less + * than relax, this subtree is considered as one supernode, + * regardless of the row structures of those columns. + * + * panel_size (input) int + * A panel consists of at most panel_size consecutive columns. + * + * etree (input) int*, dimension (A->ncol) + * Elimination tree of A'*A. + * Note: etree is a vector of parent pointers for a forest whose + * vertices are the integers 0 to A->ncol-1; etree[root]==A->ncol. + * On input, the columns of A should be permuted so that the + * etree is in a certain postorder. + * + * work (input/output) void*, size (lwork) (in bytes) + * User-supplied work space and space for the output data structures. + * Not referenced if lwork = 0; + * + * lwork (input) int + * Specifies the size of work array in bytes. + * = 0: allocate space internally by system malloc; + * > 0: use user-supplied work array of length lwork in bytes, + * returns error if space runs out. + * = -1: the routine guesses the amount of space needed without + * performing the factorization, and returns it in + * *info; no other side effects. + * + * perm_c (input) int*, dimension (A->ncol) + * Column permutation vector, which defines the + * permutation matrix Pc; perm_c[i] = j means column i of A is + * in position j in A*Pc. + * When searching for diagonal, perm_c[*] is applied to the + * row subscripts of A, so that diagonal threshold pivoting + * can find the diagonal of A, rather than that of A*Pc. + * + * perm_r (input/output) int*, dimension (A->nrow) + * Row permutation vector which defines the permutation matrix Pr, + * perm_r[i] = j means row i of A is in position j in Pr*A. + * If options->Fact = SamePattern_SameRowPerm, the pivoting routine + * will try to use the input perm_r, unless a certain threshold + * criterion is violated. In that case, perm_r is overwritten by + * a new permutation determined by partial pivoting or diagonal + * threshold pivoting. + * Otherwise, perm_r is output argument; + * + * L (output) SuperMatrix* + * The factor L from the factorization Pr*A=L*U; use compressed row + * subscripts storage for supernodes, i.e., L has type: + * Stype = SLU_SC, Dtype = SLU_S, Mtype = SLU_TRLU. + * + * U (output) SuperMatrix* + * The factor U from the factorization Pr*A*Pc=L*U. Use column-wise + * storage scheme, i.e., U has types: Stype = SLU_NC, + * Dtype = SLU_S, Mtype = SLU_TRU. + * + * stat (output) SuperLUStat_t* + * Record the statistics on runtime and floating-point operation count. + * See util.h for the definition of 'SuperLUStat_t'. + * + * info (output) int* + * = 0: successful exit + * < 0: if info = -i, the i-th argument had an illegal value + * > 0: if info = i, and i is + * <= A->ncol: U(i,i) is exactly zero. The factorization has + * been completed, but the factor U is exactly singular, + * and division by zero will occur if it is used to solve a + * system of equations. + * > A->ncol: number of bytes allocated when memory allocation + * failure occurred, plus A->ncol. If lwork = -1, it is + * the estimated amount of space needed, plus A->ncol. + * + * ====================================================================== + * + * Local Working Arrays: + * ====================== + * m = number of rows in the matrix + * n = number of columns in the matrix + * + * xprune[0:n-1]: xprune[*] points to locations in subscript + * vector lsub[*]. For column i, xprune[i] denotes the point where + * structural pruning begins. I.e. only xlsub[i],..,xprune[i]-1 need + * to be traversed for symbolic factorization. + * + * marker[0:3*m-1]: marker[i] = j means that node i has been + * reached when working on column j. + * Storage: relative to original row subscripts + * NOTE: There are 3 of them: marker/marker1 are used for panel dfs, + * see spanel_dfs.c; marker2 is used for inner-factorization, + * see scolumn_dfs.c. + * + * parent[0:m-1]: parent vector used during dfs + * Storage: relative to new row subscripts + * + * xplore[0:m-1]: xplore[i] gives the location of the next (dfs) + * unexplored neighbor of i in lsub[*] + * + * segrep[0:nseg-1]: contains the list of supernodal representatives + * in topological order of the dfs. A supernode representative is the + * last column of a supernode. + * The maximum size of segrep[] is n. + * + * repfnz[0:W*m-1]: for a nonzero segment U[*,j] that ends at a + * supernodal representative r, repfnz[r] is the location of the first + * nonzero in this segment. It is also used during the dfs: repfnz[r]>0 + * indicates the supernode r has been explored. + * NOTE: There are W of them, each used for one column of a panel. + * + * panel_lsub[0:W*m-1]: temporary for the nonzeros row indices below + * the panel diagonal. These are filled in during spanel_dfs(), and are + * used later in the inner LU factorization within the panel. + * panel_lsub[]/dense[] pair forms the SPA data structure. + * NOTE: There are W of them. + * + * dense[0:W*m-1]: sparse accumulating (SPA) vector for intermediate values; + * NOTE: there are W of them. + * + * tempv[0:*]: real temporary used for dense numeric kernels; + * The size of this array is defined by NUM_TEMPV() in ssp_defs.h. + * + */ + /* Local working arrays */ + NCPformat *Astore; + int *iperm_r = NULL; /* inverse of perm_r; + used when options->Fact == SamePattern_SameRowPerm */ + int *iperm_c; /* inverse of perm_c */ + int *iwork; + float *swork; + int *segrep, *repfnz, *parent, *xplore; + int *panel_lsub; /* dense[]/panel_lsub[] pair forms a w-wide SPA */ + int *xprune; + int *marker; + float *dense, *tempv; + int *relax_end; + float *a; + int *asub; + int *xa_begin, *xa_end; + int *xsup, *supno; + int *xlsub, *xlusup, *xusub; + int nzlumax; + static GlobalLU_t Glu; /* persistent to facilitate multiple factors. */ + + /* Local scalars */ + fact_t fact = options->Fact; + double diag_pivot_thresh = options->DiagPivotThresh; + int pivrow; /* pivotal row number in the original matrix A */ + int nseg1; /* no of segments in U-column above panel row jcol */ + int nseg; /* no of segments in each U-column */ + register int jcol; + register int kcol; /* end column of a relaxed snode */ + register int icol; + register int i, k, jj, new_next, iinfo; + int m, n, min_mn, jsupno, fsupc, nextlu, nextu; + int w_def; /* upper bound on panel width */ + int usepr, iperm_r_allocated = 0; + int nnzL, nnzU; + int *panel_histo = stat->panel_histo; + flops_t *ops = stat->ops; + + iinfo = 0; + m = A->nrow; + n = A->ncol; + min_mn = SUPERLU_MIN(m, n); + Astore = A->Store; + a = Astore->nzval; + asub = Astore->rowind; + xa_begin = Astore->colbeg; + xa_end = Astore->colend; + + /* Allocate storage common to the factor routines */ + *info = sLUMemInit(fact, work, lwork, m, n, Astore->nnz, + panel_size, L, U, &Glu, &iwork, &swork); + if ( *info ) return; + + xsup = Glu.xsup; + supno = Glu.supno; + xlsub = Glu.xlsub; + xlusup = Glu.xlusup; + xusub = Glu.xusub; + + SetIWork(m, n, panel_size, iwork, &segrep, &parent, &xplore, + &repfnz, &panel_lsub, &xprune, &marker); + sSetRWork(m, panel_size, swork, &dense, &tempv); + + usepr = (fact == SamePattern_SameRowPerm); + if ( usepr ) { + /* Compute the inverse of perm_r */ + iperm_r = (int *) intMalloc(m); + for (k = 0; k < m; ++k) iperm_r[perm_r[k]] = k; + iperm_r_allocated = 1; + } + iperm_c = (int *) intMalloc(n); + for (k = 0; k < n; ++k) iperm_c[perm_c[k]] = k; + + /* Identify relaxed snodes */ + relax_end = (int *) intMalloc(n); + if ( options->SymmetricMode == YES ) { + heap_relax_snode(n, etree, relax, marker, relax_end); + } else { + relax_snode(n, etree, relax, marker, relax_end); + } + + ifill (perm_r, m, EMPTY); + ifill (marker, m * NO_MARKER, EMPTY); + supno[0] = -1; + xsup[0] = xlsub[0] = xusub[0] = xlusup[0] = 0; + w_def = panel_size; + + /* + * Work on one "panel" at a time. A panel is one of the following: + * (a) a relaxed supernode at the bottom of the etree, or + * (b) panel_size contiguous columns, defined by the user + */ + for (jcol = 0; jcol < min_mn; ) { + + if ( relax_end[jcol] != EMPTY ) { /* start of a relaxed snode */ + kcol = relax_end[jcol]; /* end of the relaxed snode */ + panel_histo[kcol-jcol+1]++; + + /* -------------------------------------- + * Factorize the relaxed supernode(jcol:kcol) + * -------------------------------------- */ + /* Determine the union of the row structure of the snode */ + if ( (*info = ssnode_dfs(jcol, kcol, asub, xa_begin, xa_end, + xprune, marker, &Glu)) != 0 ) + return; + + nextu = xusub[jcol]; + nextlu = xlusup[jcol]; + jsupno = supno[jcol]; + fsupc = xsup[jsupno]; + new_next = nextlu + (xlsub[fsupc+1]-xlsub[fsupc])*(kcol-jcol+1); + nzlumax = Glu.nzlumax; + while ( new_next > nzlumax ) { + if ( (*info = sLUMemXpand(jcol, nextlu, LUSUP, &nzlumax, &Glu)) ) + return; + } + + for (icol = jcol; icol<= kcol; icol++) { + xusub[icol+1] = nextu; + + /* Scatter into SPA dense[*] */ + for (k = xa_begin[icol]; k < xa_end[icol]; k++) + dense[asub[k]] = a[k]; + + /* Numeric update within the snode */ + ssnode_bmod(icol, fsupc, dense, tempv, &Glu, stat); + + if ( (*info = spivotL(icol, diag_pivot_thresh, &usepr, perm_r, + iperm_r, iperm_c, &pivrow, &Glu, stat)) ) + if ( iinfo == 0 ) iinfo = *info; + +#ifdef DEBUG + sprint_lu_col("[1]: ", icol, pivrow, xprune, &Glu); +#endif + + } + + jcol = icol; + + } else { /* Work on one panel of panel_size columns */ + + /* Adjust panel_size so that a panel won't overlap with the next + * relaxed snode. + */ + panel_size = w_def; + for (k = jcol + 1; k < SUPERLU_MIN(jcol+panel_size, min_mn); k++) + if ( relax_end[k] != EMPTY ) { + panel_size = k - jcol; + break; + } + if ( k == min_mn ) panel_size = min_mn - jcol; + panel_histo[panel_size]++; + + /* symbolic factor on a panel of columns */ + spanel_dfs(m, panel_size, jcol, A, perm_r, &nseg1, + dense, panel_lsub, segrep, repfnz, xprune, + marker, parent, xplore, &Glu); + + /* numeric sup-panel updates in topological order */ + spanel_bmod(m, panel_size, jcol, nseg1, dense, + tempv, segrep, repfnz, &Glu, stat); + + /* Sparse LU within the panel, and below panel diagonal */ + for ( jj = jcol; jj < jcol + panel_size; jj++) { + k = (jj - jcol) * m; /* column index for w-wide arrays */ + + nseg = nseg1; /* Begin after all the panel segments */ + + if ((*info = scolumn_dfs(m, jj, perm_r, &nseg, &panel_lsub[k], + segrep, &repfnz[k], xprune, marker, + parent, xplore, &Glu)) != 0) return; + + /* Numeric updates */ + if ((*info = scolumn_bmod(jj, (nseg - nseg1), &dense[k], + tempv, &segrep[nseg1], &repfnz[k], + jcol, &Glu, stat)) != 0) return; + + /* Copy the U-segments to ucol[*] */ + if ((*info = scopy_to_ucol(jj, nseg, segrep, &repfnz[k], + perm_r, &dense[k], &Glu)) != 0) + return; + + if ( (*info = spivotL(jj, diag_pivot_thresh, &usepr, perm_r, + iperm_r, iperm_c, &pivrow, &Glu, stat)) ) + if ( iinfo == 0 ) iinfo = *info; + + /* Prune columns (0:jj-1) using column jj */ + spruneL(jj, perm_r, pivrow, nseg, segrep, + &repfnz[k], xprune, &Glu); + + /* Reset repfnz[] for this column */ + resetrep_col (nseg, segrep, &repfnz[k]); + +#ifdef DEBUG + sprint_lu_col("[2]: ", jj, pivrow, xprune, &Glu); +#endif + + } + + jcol += panel_size; /* Move to the next panel */ + + } /* else */ + + } /* for */ + + *info = iinfo; + + if ( m > n ) { + k = 0; + for (i = 0; i < m; ++i) + if ( perm_r[i] == EMPTY ) { + perm_r[i] = n + k; + ++k; + } + } + + countnz(min_mn, xprune, &nnzL, &nnzU, &Glu); + fixupL(min_mn, perm_r, &Glu); + + sLUWorkFree(iwork, swork, &Glu); /* Free work space and compress storage */ + + if ( fact == SamePattern_SameRowPerm ) { + /* L and U structures may have changed due to possibly different + pivoting, even though the storage is available. + There could also be memory expansions, so the array locations + may have changed, */ + ((SCformat *)L->Store)->nnz = nnzL; + ((SCformat *)L->Store)->nsuper = Glu.supno[n]; + ((SCformat *)L->Store)->nzval = Glu.lusup; + ((SCformat *)L->Store)->nzval_colptr = Glu.xlusup; + ((SCformat *)L->Store)->rowind = Glu.lsub; + ((SCformat *)L->Store)->rowind_colptr = Glu.xlsub; + ((NCformat *)U->Store)->nnz = nnzU; + ((NCformat *)U->Store)->nzval = Glu.ucol; + ((NCformat *)U->Store)->rowind = Glu.usub; + ((NCformat *)U->Store)->colptr = Glu.xusub; + } else { + sCreate_SuperNode_Matrix(L, A->nrow, A->ncol, nnzL, Glu.lusup, + Glu.xlusup, Glu.lsub, Glu.xlsub, Glu.supno, + Glu.xsup, SLU_SC, SLU_S, SLU_TRLU); + sCreate_CompCol_Matrix(U, min_mn, min_mn, nnzU, Glu.ucol, + Glu.usub, Glu.xusub, SLU_NC, SLU_S, SLU_TRU); + } + + ops[FACT] += ops[TRSV] + ops[GEMV]; + + if ( iperm_r_allocated ) SUPERLU_FREE (iperm_r); + SUPERLU_FREE (iperm_c); + SUPERLU_FREE (relax_end); + +} diff --git a/intern/opennl/superlu/sgstrs.c b/intern/opennl/superlu/sgstrs.c new file mode 100644 index 00000000000..b83545f8ce6 --- /dev/null +++ b/intern/opennl/superlu/sgstrs.c @@ -0,0 +1,331 @@ + +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include "ssp_defs.h" + + +/* + * Function prototypes + */ +void susolve(int, int, float*, float*); +void slsolve(int, int, float*, float*); +void smatvec(int, int, int, float*, float*, float*); +void sprint_soln(int , float *); + +void +sgstrs (trans_t trans, SuperMatrix *L, SuperMatrix *U, + int *perm_c, int *perm_r, SuperMatrix *B, + SuperLUStat_t *stat, int *info) +{ +/* + * Purpose + * ======= + * + * SGSTRS solves a system of linear equations A*X=B or A'*X=B + * with A sparse and B dense, using the LU factorization computed by + * SGSTRF. + * + * See supermatrix.h for the definition of 'SuperMatrix' structure. + * + * Arguments + * ========= + * + * trans (input) trans_t + * Specifies the form of the system of equations: + * = NOTRANS: A * X = B (No transpose) + * = TRANS: A'* X = B (Transpose) + * = CONJ: A**H * X = B (Conjugate transpose) + * + * L (input) SuperMatrix* + * The factor L from the factorization Pr*A*Pc=L*U as computed by + * sgstrf(). Use compressed row subscripts storage for supernodes, + * i.e., L has types: Stype = SLU_SC, Dtype = SLU_S, Mtype = SLU_TRLU. + * + * U (input) SuperMatrix* + * The factor U from the factorization Pr*A*Pc=L*U as computed by + * sgstrf(). Use column-wise storage scheme, i.e., U has types: + * Stype = SLU_NC, Dtype = SLU_S, Mtype = SLU_TRU. + * + * perm_c (input) int*, dimension (L->ncol) + * Column permutation vector, which defines the + * permutation matrix Pc; perm_c[i] = j means column i of A is + * in position j in A*Pc. + * + * perm_r (input) int*, dimension (L->nrow) + * Row permutation vector, which defines the permutation matrix Pr; + * perm_r[i] = j means row i of A is in position j in Pr*A. + * + * B (input/output) SuperMatrix* + * B has types: Stype = SLU_DN, Dtype = SLU_S, Mtype = SLU_GE. + * On entry, the right hand side matrix. + * On exit, the solution matrix if info = 0; + * + * stat (output) SuperLUStat_t* + * Record the statistics on runtime and floating-point operation count. + * See util.h for the definition of 'SuperLUStat_t'. + * + * info (output) int* + * = 0: successful exit + * < 0: if info = -i, the i-th argument had an illegal value + * + */ +#ifdef _CRAY + _fcd ftcs1, ftcs2, ftcs3, ftcs4; +#endif +#ifdef USE_VENDOR_BLAS + float alpha = 1.0, beta = 1.0; + float *work_col; +#endif + DNformat *Bstore; + float *Bmat; + SCformat *Lstore; + NCformat *Ustore; + float *Lval, *Uval; + int fsupc, nrow, nsupr, nsupc, luptr, istart, irow; + int i, j, k, iptr, jcol, n, ldb, nrhs; + float *work, *rhs_work, *soln; + flops_t solve_ops; + void sprint_soln(); + + /* Test input parameters ... */ + *info = 0; + Bstore = B->Store; + ldb = Bstore->lda; + nrhs = B->ncol; + if ( trans != NOTRANS && trans != TRANS && trans != CONJ ) *info = -1; + else if ( L->nrow != L->ncol || L->nrow < 0 || + L->Stype != SLU_SC || L->Dtype != SLU_S || L->Mtype != SLU_TRLU ) + *info = -2; + else if ( U->nrow != U->ncol || U->nrow < 0 || + U->Stype != SLU_NC || U->Dtype != SLU_S || U->Mtype != SLU_TRU ) + *info = -3; + else if ( ldb < SUPERLU_MAX(0, L->nrow) || + B->Stype != SLU_DN || B->Dtype != SLU_S || B->Mtype != SLU_GE ) + *info = -6; + if ( *info ) { + i = -(*info); + xerbla_("sgstrs", &i); + return; + } + + n = L->nrow; + work = floatCalloc(n * nrhs); + if ( !work ) ABORT("Malloc fails for local work[]."); + soln = floatMalloc(n); + if ( !soln ) ABORT("Malloc fails for local soln[]."); + + Bmat = Bstore->nzval; + Lstore = L->Store; + Lval = Lstore->nzval; + Ustore = U->Store; + Uval = Ustore->nzval; + solve_ops = 0; + + if ( trans == NOTRANS ) { + /* Permute right hand sides to form Pr*B */ + for (i = 0; i < nrhs; i++) { + rhs_work = &Bmat[i*ldb]; + for (k = 0; k < n; k++) soln[perm_r[k]] = rhs_work[k]; + for (k = 0; k < n; k++) rhs_work[k] = soln[k]; + } + + /* Forward solve PLy=Pb. */ + for (k = 0; k <= Lstore->nsuper; k++) { + fsupc = L_FST_SUPC(k); + istart = L_SUB_START(fsupc); + nsupr = L_SUB_START(fsupc+1) - istart; + nsupc = L_FST_SUPC(k+1) - fsupc; + nrow = nsupr - nsupc; + + solve_ops += nsupc * (nsupc - 1) * nrhs; + solve_ops += 2 * nrow * nsupc * nrhs; + + if ( nsupc == 1 ) { + for (j = 0; j < nrhs; j++) { + rhs_work = &Bmat[j*ldb]; + luptr = L_NZ_START(fsupc); + for (iptr=istart+1; iptr < L_SUB_START(fsupc+1); iptr++){ + irow = L_SUB(iptr); + ++luptr; + rhs_work[irow] -= rhs_work[fsupc] * Lval[luptr]; + } + } + } else { + luptr = L_NZ_START(fsupc); +#ifdef USE_VENDOR_BLAS +#ifdef _CRAY + ftcs1 = _cptofcd("L", strlen("L")); + ftcs2 = _cptofcd("N", strlen("N")); + ftcs3 = _cptofcd("U", strlen("U")); + STRSM( ftcs1, ftcs1, ftcs2, ftcs3, &nsupc, &nrhs, &alpha, + &Lval[luptr], &nsupr, &Bmat[fsupc], &ldb); + + SGEMM( ftcs2, ftcs2, &nrow, &nrhs, &nsupc, &alpha, + &Lval[luptr+nsupc], &nsupr, &Bmat[fsupc], &ldb, + &beta, &work[0], &n ); +#else + strsm_("L", "L", "N", "U", &nsupc, &nrhs, &alpha, + &Lval[luptr], &nsupr, &Bmat[fsupc], &ldb); + + sgemm_( "N", "N", &nrow, &nrhs, &nsupc, &alpha, + &Lval[luptr+nsupc], &nsupr, &Bmat[fsupc], &ldb, + &beta, &work[0], &n ); +#endif + for (j = 0; j < nrhs; j++) { + rhs_work = &Bmat[j*ldb]; + work_col = &work[j*n]; + iptr = istart + nsupc; + for (i = 0; i < nrow; i++) { + irow = L_SUB(iptr); + rhs_work[irow] -= work_col[i]; /* Scatter */ + work_col[i] = 0.0; + iptr++; + } + } +#else + for (j = 0; j < nrhs; j++) { + rhs_work = &Bmat[j*ldb]; + slsolve (nsupr, nsupc, &Lval[luptr], &rhs_work[fsupc]); + smatvec (nsupr, nrow, nsupc, &Lval[luptr+nsupc], + &rhs_work[fsupc], &work[0] ); + + iptr = istart + nsupc; + for (i = 0; i < nrow; i++) { + irow = L_SUB(iptr); + rhs_work[irow] -= work[i]; + work[i] = 0.0; + iptr++; + } + } +#endif + } /* else ... */ + } /* for L-solve */ + +#ifdef DEBUG + printf("After L-solve: y=\n"); + sprint_soln(n, Bmat); +#endif + + /* + * Back solve Ux=y. + */ + for (k = Lstore->nsuper; k >= 0; k--) { + fsupc = L_FST_SUPC(k); + istart = L_SUB_START(fsupc); + nsupr = L_SUB_START(fsupc+1) - istart; + nsupc = L_FST_SUPC(k+1) - fsupc; + luptr = L_NZ_START(fsupc); + + solve_ops += nsupc * (nsupc + 1) * nrhs; + + if ( nsupc == 1 ) { + rhs_work = &Bmat[0]; + for (j = 0; j < nrhs; j++) { + rhs_work[fsupc] /= Lval[luptr]; + rhs_work += ldb; + } + } else { +#ifdef USE_VENDOR_BLAS +#ifdef _CRAY + ftcs1 = _cptofcd("L", strlen("L")); + ftcs2 = _cptofcd("U", strlen("U")); + ftcs3 = _cptofcd("N", strlen("N")); + STRSM( ftcs1, ftcs2, ftcs3, ftcs3, &nsupc, &nrhs, &alpha, + &Lval[luptr], &nsupr, &Bmat[fsupc], &ldb); +#else + strsm_("L", "U", "N", "N", &nsupc, &nrhs, &alpha, + &Lval[luptr], &nsupr, &Bmat[fsupc], &ldb); +#endif +#else + for (j = 0; j < nrhs; j++) + susolve ( nsupr, nsupc, &Lval[luptr], &Bmat[fsupc+j*ldb] ); +#endif + } + + for (j = 0; j < nrhs; ++j) { + rhs_work = &Bmat[j*ldb]; + for (jcol = fsupc; jcol < fsupc + nsupc; jcol++) { + solve_ops += 2*(U_NZ_START(jcol+1) - U_NZ_START(jcol)); + for (i = U_NZ_START(jcol); i < U_NZ_START(jcol+1); i++ ){ + irow = U_SUB(i); + rhs_work[irow] -= rhs_work[jcol] * Uval[i]; + } + } + } + + } /* for U-solve */ + +#ifdef DEBUG + printf("After U-solve: x=\n"); + sprint_soln(n, Bmat); +#endif + + /* Compute the final solution X := Pc*X. */ + for (i = 0; i < nrhs; i++) { + rhs_work = &Bmat[i*ldb]; + for (k = 0; k < n; k++) soln[k] = rhs_work[perm_c[k]]; + for (k = 0; k < n; k++) rhs_work[k] = soln[k]; + } + + stat->ops[SOLVE] = solve_ops; + + } else { /* Solve A'*X=B or CONJ(A)*X=B */ + /* Permute right hand sides to form Pc'*B. */ + for (i = 0; i < nrhs; i++) { + rhs_work = &Bmat[i*ldb]; + for (k = 0; k < n; k++) soln[perm_c[k]] = rhs_work[k]; + for (k = 0; k < n; k++) rhs_work[k] = soln[k]; + } + + stat->ops[SOLVE] = 0; + for (k = 0; k < nrhs; ++k) { + + /* Multiply by inv(U'). */ + sp_strsv("U", "T", "N", L, U, &Bmat[k*ldb], stat, info); + + /* Multiply by inv(L'). */ + sp_strsv("L", "T", "U", L, U, &Bmat[k*ldb], stat, info); + + } + /* Compute the final solution X := Pr'*X (=inv(Pr)*X) */ + for (i = 0; i < nrhs; i++) { + rhs_work = &Bmat[i*ldb]; + for (k = 0; k < n; k++) soln[k] = rhs_work[perm_r[k]]; + for (k = 0; k < n; k++) rhs_work[k] = soln[k]; + } + + } + + SUPERLU_FREE(work); + SUPERLU_FREE(soln); +} + +/* + * Diagnostic print of the solution vector + */ +void +sprint_soln(int n, float *soln) +{ + int i; + + for (i = 0; i < n; i++) + printf("\t%d: %.4f\n", i, soln[i]); +} diff --git a/intern/opennl/superlu/smemory.c b/intern/opennl/superlu/smemory.c new file mode 100644 index 00000000000..79da748671a --- /dev/null +++ b/intern/opennl/superlu/smemory.c @@ -0,0 +1,676 @@ + +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +#include "ssp_defs.h" + +/* Constants */ +#define NO_MEMTYPE 4 /* 0: lusup; + 1: ucol; + 2: lsub; + 3: usub */ +#define GluIntArray(n) (5 * (n) + 5) + +/* Internal prototypes */ +void *sexpand (int *, MemType,int, int, GlobalLU_t *); +int sLUWorkInit (int, int, int, int **, float **, LU_space_t); +void copy_mem_float (int, void *, void *); +void sStackCompress (GlobalLU_t *); +void sSetupSpace (void *, int, LU_space_t *); +void *suser_malloc (int, int); +void suser_free (int, int); + +/* External prototypes (in memory.c - prec-indep) */ +extern void copy_mem_int (int, void *, void *); +extern void user_bcopy (char *, char *, int); + +/* Headers for 4 types of dynamatically managed memory */ +typedef struct e_node { + int size; /* length of the memory that has been used */ + void *mem; /* pointer to the new malloc'd store */ +} ExpHeader; + +typedef struct { + int size; + int used; + int top1; /* grow upward, relative to &array[0] */ + int top2; /* grow downward */ + void *array; +} LU_stack_t; + +/* Variables local to this file */ +static ExpHeader *expanders = 0; /* Array of pointers to 4 types of memory */ +static LU_stack_t stack; +static int no_expand; + +/* Macros to manipulate stack */ +#define StackFull(x) ( x + stack.used >= stack.size ) +#define NotDoubleAlign(addr) ( (long int)addr & 7 ) +#define DoubleAlign(addr) ( ((long int)addr + 7) & ~7L ) +#define TempSpace(m, w) ( (2*w + 4 + NO_MARKER) * m * sizeof(int) + \ + (w + 1) * m * sizeof(float) ) +#define Reduce(alpha) ((alpha + 1) / 2) /* i.e. (alpha-1)/2 + 1 */ + + + + +/* + * Setup the memory model to be used for factorization. + * lwork = 0: use system malloc; + * lwork > 0: use user-supplied work[] space. + */ +void sSetupSpace(void *work, int lwork, LU_space_t *MemModel) +{ + if ( lwork == 0 ) { + *MemModel = SYSTEM; /* malloc/free */ + } else if ( lwork > 0 ) { + *MemModel = USER; /* user provided space */ + stack.used = 0; + stack.top1 = 0; + stack.top2 = (lwork/4)*4; /* must be word addressable */ + stack.size = stack.top2; + stack.array = (void *) work; + } +} + + + +void *suser_malloc(int bytes, int which_end) +{ + void *buf; + + if ( StackFull(bytes) ) return (NULL); + + if ( which_end == HEAD ) { + buf = (char*) stack.array + stack.top1; + stack.top1 += bytes; + } else { + stack.top2 -= bytes; + buf = (char*) stack.array + stack.top2; + } + + stack.used += bytes; + return buf; +} + + +void suser_free(int bytes, int which_end) +{ + if ( which_end == HEAD ) { + stack.top1 -= bytes; + } else { + stack.top2 += bytes; + } + stack.used -= bytes; +} + + + +/* + * mem_usage consists of the following fields: + * - for_lu (float) + * The amount of space used in bytes for the L\U data structures. + * - total_needed (float) + * The amount of space needed in bytes to perform factorization. + * - expansions (int) + * Number of memory expansions during the LU factorization. + */ +int sQuerySpace(SuperMatrix *L, SuperMatrix *U, mem_usage_t *mem_usage) +{ + SCformat *Lstore; + NCformat *Ustore; + register int n, iword, dword, panel_size = sp_ienv(1); + + Lstore = L->Store; + Ustore = U->Store; + n = L->ncol; + iword = sizeof(int); + dword = sizeof(float); + + /* For LU factors */ + mem_usage->for_lu = (float)( (4*n + 3) * iword + Lstore->nzval_colptr[n] * + dword + Lstore->rowind_colptr[n] * iword ); + mem_usage->for_lu += (float)( (n + 1) * iword + + Ustore->colptr[n] * (dword + iword) ); + + /* Working storage to support factorization */ + mem_usage->total_needed = mem_usage->for_lu + + (float)( (2 * panel_size + 4 + NO_MARKER) * n * iword + + (panel_size + 1) * n * dword ); + + mem_usage->expansions = --no_expand; + + return 0; +} /* sQuerySpace */ + +/* + * Allocate storage for the data structures common to all factor routines. + * For those unpredictable size, make a guess as FILL * nnz(A). + * Return value: + * If lwork = -1, return the estimated amount of space required, plus n; + * otherwise, return the amount of space actually allocated when + * memory allocation failure occurred. + */ +int +sLUMemInit(fact_t fact, void *work, int lwork, int m, int n, int annz, + int panel_size, SuperMatrix *L, SuperMatrix *U, GlobalLU_t *Glu, + int **iwork, float **dwork) +{ + int info, iword, dword; + SCformat *Lstore; + NCformat *Ustore; + int *xsup, *supno; + int *lsub, *xlsub; + float *lusup; + int *xlusup; + float *ucol; + int *usub, *xusub; + int nzlmax, nzumax, nzlumax; + int FILL = sp_ienv(6); + + Glu->n = n; + no_expand = 0; + iword = sizeof(int); + dword = sizeof(float); + + if ( !expanders ) + expanders = (ExpHeader*)SUPERLU_MALLOC(NO_MEMTYPE * sizeof(ExpHeader)); + if ( !expanders ) ABORT("SUPERLU_MALLOC fails for expanders"); + + if ( fact != SamePattern_SameRowPerm ) { + /* Guess for L\U factors */ + nzumax = nzlumax = FILL * annz; + nzlmax = SUPERLU_MAX(1, FILL/4.) * annz; + + if ( lwork == -1 ) { + return ( GluIntArray(n) * iword + TempSpace(m, panel_size) + + (nzlmax+nzumax)*iword + (nzlumax+nzumax)*dword + n ); + } else { + sSetupSpace(work, lwork, &Glu->MemModel); + } + +#ifdef DEBUG + printf("sLUMemInit() called: annz %d, MemModel %d\n", + annz, Glu->MemModel); +#endif + + /* Integer pointers for L\U factors */ + if ( Glu->MemModel == SYSTEM ) { + xsup = intMalloc(n+1); + supno = intMalloc(n+1); + xlsub = intMalloc(n+1); + xlusup = intMalloc(n+1); + xusub = intMalloc(n+1); + } else { + xsup = (int *)suser_malloc((n+1) * iword, HEAD); + supno = (int *)suser_malloc((n+1) * iword, HEAD); + xlsub = (int *)suser_malloc((n+1) * iword, HEAD); + xlusup = (int *)suser_malloc((n+1) * iword, HEAD); + xusub = (int *)suser_malloc((n+1) * iword, HEAD); + } + + lusup = (float *) sexpand( &nzlumax, LUSUP, 0, 0, Glu ); + ucol = (float *) sexpand( &nzumax, UCOL, 0, 0, Glu ); + lsub = (int *) sexpand( &nzlmax, LSUB, 0, 0, Glu ); + usub = (int *) sexpand( &nzumax, USUB, 0, 1, Glu ); + + while ( !lusup || !ucol || !lsub || !usub ) { + if ( Glu->MemModel == SYSTEM ) { + SUPERLU_FREE(lusup); + SUPERLU_FREE(ucol); + SUPERLU_FREE(lsub); + SUPERLU_FREE(usub); + } else { + suser_free((nzlumax+nzumax)*dword+(nzlmax+nzumax)*iword, HEAD); + } + nzlumax /= 2; + nzumax /= 2; + nzlmax /= 2; + if ( nzlumax < annz ) { + printf("Not enough memory to perform factorization.\n"); + return (smemory_usage(nzlmax, nzumax, nzlumax, n) + n); + } + lusup = (float *) sexpand( &nzlumax, LUSUP, 0, 0, Glu ); + ucol = (float *) sexpand( &nzumax, UCOL, 0, 0, Glu ); + lsub = (int *) sexpand( &nzlmax, LSUB, 0, 0, Glu ); + usub = (int *) sexpand( &nzumax, USUB, 0, 1, Glu ); + } + + } else { + /* fact == SamePattern_SameRowPerm */ + Lstore = L->Store; + Ustore = U->Store; + xsup = Lstore->sup_to_col; + supno = Lstore->col_to_sup; + xlsub = Lstore->rowind_colptr; + xlusup = Lstore->nzval_colptr; + xusub = Ustore->colptr; + nzlmax = Glu->nzlmax; /* max from previous factorization */ + nzumax = Glu->nzumax; + nzlumax = Glu->nzlumax; + + if ( lwork == -1 ) { + return ( GluIntArray(n) * iword + TempSpace(m, panel_size) + + (nzlmax+nzumax)*iword + (nzlumax+nzumax)*dword + n ); + } else if ( lwork == 0 ) { + Glu->MemModel = SYSTEM; + } else { + Glu->MemModel = USER; + stack.top2 = (lwork/4)*4; /* must be word-addressable */ + stack.size = stack.top2; + } + + lsub = expanders[LSUB].mem = Lstore->rowind; + lusup = expanders[LUSUP].mem = Lstore->nzval; + usub = expanders[USUB].mem = Ustore->rowind; + ucol = expanders[UCOL].mem = Ustore->nzval;; + expanders[LSUB].size = nzlmax; + expanders[LUSUP].size = nzlumax; + expanders[USUB].size = nzumax; + expanders[UCOL].size = nzumax; + } + + Glu->xsup = xsup; + Glu->supno = supno; + Glu->lsub = lsub; + Glu->xlsub = xlsub; + Glu->lusup = lusup; + Glu->xlusup = xlusup; + Glu->ucol = ucol; + Glu->usub = usub; + Glu->xusub = xusub; + Glu->nzlmax = nzlmax; + Glu->nzumax = nzumax; + Glu->nzlumax = nzlumax; + + info = sLUWorkInit(m, n, panel_size, iwork, dwork, Glu->MemModel); + if ( info ) + return ( info + smemory_usage(nzlmax, nzumax, nzlumax, n) + n); + + ++no_expand; + return 0; + +} /* sLUMemInit */ + +/* Allocate known working storage. Returns 0 if success, otherwise + returns the number of bytes allocated so far when failure occurred. */ +int +sLUWorkInit(int m, int n, int panel_size, int **iworkptr, + float **dworkptr, LU_space_t MemModel) +{ + int isize, dsize, extra; + float *old_ptr; + int maxsuper = sp_ienv(3), + rowblk = sp_ienv(4); + + isize = ( (2 * panel_size + 3 + NO_MARKER ) * m + n ) * sizeof(int); + dsize = (m * panel_size + + NUM_TEMPV(m,panel_size,maxsuper,rowblk)) * sizeof(float); + + if ( MemModel == SYSTEM ) + *iworkptr = (int *) intCalloc(isize/sizeof(int)); + else + *iworkptr = (int *) suser_malloc(isize, TAIL); + if ( ! *iworkptr ) { + fprintf(stderr, "sLUWorkInit: malloc fails for local iworkptr[]\n"); + return (isize + n); + } + + if ( MemModel == SYSTEM ) + *dworkptr = (float *) SUPERLU_MALLOC(dsize); + else { + *dworkptr = (float *) suser_malloc(dsize, TAIL); + if ( NotDoubleAlign(*dworkptr) ) { + old_ptr = *dworkptr; + *dworkptr = (float*) DoubleAlign(*dworkptr); + *dworkptr = (float*) ((double*)*dworkptr - 1); + extra = (char*)old_ptr - (char*)*dworkptr; +#ifdef DEBUG + printf("sLUWorkInit: not aligned, extra %d\n", extra); +#endif + stack.top2 -= extra; + stack.used += extra; + } + } + if ( ! *dworkptr ) { + fprintf(stderr, "malloc fails for local dworkptr[]."); + return (isize + dsize + n); + } + + return 0; +} + + +/* + * Set up pointers for real working arrays. + */ +void +sSetRWork(int m, int panel_size, float *dworkptr, + float **dense, float **tempv) +{ + float zero = 0.0; + + int maxsuper = sp_ienv(3), + rowblk = sp_ienv(4); + *dense = dworkptr; + *tempv = *dense + panel_size*m; + sfill (*dense, m * panel_size, zero); + sfill (*tempv, NUM_TEMPV(m,panel_size,maxsuper,rowblk), zero); +} + +/* + * Free the working storage used by factor routines. + */ +void sLUWorkFree(int *iwork, float *dwork, GlobalLU_t *Glu) +{ + if ( Glu->MemModel == SYSTEM ) { + SUPERLU_FREE (iwork); + SUPERLU_FREE (dwork); + } else { + stack.used -= (stack.size - stack.top2); + stack.top2 = stack.size; +/* sStackCompress(Glu); */ + } + + SUPERLU_FREE (expanders); + expanders = 0; +} + +/* Expand the data structures for L and U during the factorization. + * Return value: 0 - successful return + * > 0 - number of bytes allocated when run out of space + */ +int +sLUMemXpand(int jcol, + int next, /* number of elements currently in the factors */ + MemType mem_type, /* which type of memory to expand */ + int *maxlen, /* modified - maximum length of a data structure */ + GlobalLU_t *Glu /* modified - global LU data structures */ + ) +{ + void *new_mem; + +#ifdef DEBUG + printf("sLUMemXpand(): jcol %d, next %d, maxlen %d, MemType %d\n", + jcol, next, *maxlen, mem_type); +#endif + + if (mem_type == USUB) + new_mem = sexpand(maxlen, mem_type, next, 1, Glu); + else + new_mem = sexpand(maxlen, mem_type, next, 0, Glu); + + if ( !new_mem ) { + int nzlmax = Glu->nzlmax; + int nzumax = Glu->nzumax; + int nzlumax = Glu->nzlumax; + fprintf(stderr, "Can't expand MemType %d: jcol %d\n", mem_type, jcol); + return (smemory_usage(nzlmax, nzumax, nzlumax, Glu->n) + Glu->n); + } + + switch ( mem_type ) { + case LUSUP: + Glu->lusup = (float *) new_mem; + Glu->nzlumax = *maxlen; + break; + case UCOL: + Glu->ucol = (float *) new_mem; + Glu->nzumax = *maxlen; + break; + case LSUB: + Glu->lsub = (int *) new_mem; + Glu->nzlmax = *maxlen; + break; + case USUB: + Glu->usub = (int *) new_mem; + Glu->nzumax = *maxlen; + break; + } + + return 0; + +} + + + +void +copy_mem_float(int howmany, void *old, void *new) +{ + register int i; + float *dold = old; + float *dnew = new; + for (i = 0; i < howmany; i++) dnew[i] = dold[i]; +} + +/* + * Expand the existing storage to accommodate more fill-ins. + */ +void +*sexpand ( + int *prev_len, /* length used from previous call */ + MemType type, /* which part of the memory to expand */ + int len_to_copy, /* size of the memory to be copied to new store */ + int keep_prev, /* = 1: use prev_len; + = 0: compute new_len to expand */ + GlobalLU_t *Glu /* modified - global LU data structures */ + ) +{ + float EXPAND = 1.5; + float alpha; + void *new_mem, *old_mem; + int new_len, tries, lword, extra, bytes_to_copy; + + alpha = EXPAND; + + if ( no_expand == 0 || keep_prev ) /* First time allocate requested */ + new_len = *prev_len; + else { + new_len = alpha * *prev_len; + } + + if ( type == LSUB || type == USUB ) lword = sizeof(int); + else lword = sizeof(float); + + if ( Glu->MemModel == SYSTEM ) { + new_mem = (void *) SUPERLU_MALLOC(new_len * lword); +/* new_mem = (void *) calloc(new_len, lword); */ + if ( no_expand != 0 ) { + tries = 0; + if ( keep_prev ) { + if ( !new_mem ) return (NULL); + } else { + while ( !new_mem ) { + if ( ++tries > 10 ) return (NULL); + alpha = Reduce(alpha); + new_len = alpha * *prev_len; + new_mem = (void *) SUPERLU_MALLOC(new_len * lword); +/* new_mem = (void *) calloc(new_len, lword); */ + } + } + if ( type == LSUB || type == USUB ) { + copy_mem_int(len_to_copy, expanders[type].mem, new_mem); + } else { + copy_mem_float(len_to_copy, expanders[type].mem, new_mem); + } + SUPERLU_FREE (expanders[type].mem); + } + expanders[type].mem = (void *) new_mem; + + } else { /* MemModel == USER */ + if ( no_expand == 0 ) { + new_mem = suser_malloc(new_len * lword, HEAD); + if ( NotDoubleAlign(new_mem) && + (type == LUSUP || type == UCOL) ) { + old_mem = new_mem; + new_mem = (void *)DoubleAlign(new_mem); + extra = (char*)new_mem - (char*)old_mem; +#ifdef DEBUG + printf("expand(): not aligned, extra %d\n", extra); +#endif + stack.top1 += extra; + stack.used += extra; + } + expanders[type].mem = (void *) new_mem; + } + else { + tries = 0; + extra = (new_len - *prev_len) * lword; + if ( keep_prev ) { + if ( StackFull(extra) ) return (NULL); + } else { + while ( StackFull(extra) ) { + if ( ++tries > 10 ) return (NULL); + alpha = Reduce(alpha); + new_len = alpha * *prev_len; + extra = (new_len - *prev_len) * lword; + } + } + + if ( type != USUB ) { + new_mem = (void*)((char*)expanders[type + 1].mem + extra); + bytes_to_copy = (char*)stack.array + stack.top1 + - (char*)expanders[type + 1].mem; + user_bcopy(expanders[type+1].mem, new_mem, bytes_to_copy); + + if ( type < USUB ) { + Glu->usub = expanders[USUB].mem = + (void*)((char*)expanders[USUB].mem + extra); + } + if ( type < LSUB ) { + Glu->lsub = expanders[LSUB].mem = + (void*)((char*)expanders[LSUB].mem + extra); + } + if ( type < UCOL ) { + Glu->ucol = expanders[UCOL].mem = + (void*)((char*)expanders[UCOL].mem + extra); + } + stack.top1 += extra; + stack.used += extra; + if ( type == UCOL ) { + stack.top1 += extra; /* Add same amount for USUB */ + stack.used += extra; + } + + } /* if ... */ + + } /* else ... */ + } + + expanders[type].size = new_len; + *prev_len = new_len; + if ( no_expand ) ++no_expand; + + return (void *) expanders[type].mem; + +} /* sexpand */ + + +/* + * Compress the work[] array to remove fragmentation. + */ +void +sStackCompress(GlobalLU_t *Glu) +{ + register int iword, dword, ndim; + char *last, *fragment; + int *ifrom, *ito; + float *dfrom, *dto; + int *xlsub, *lsub, *xusub, *usub, *xlusup; + float *ucol, *lusup; + + iword = sizeof(int); + dword = sizeof(float); + ndim = Glu->n; + + xlsub = Glu->xlsub; + lsub = Glu->lsub; + xusub = Glu->xusub; + usub = Glu->usub; + xlusup = Glu->xlusup; + ucol = Glu->ucol; + lusup = Glu->lusup; + + dfrom = ucol; + dto = (float *)((char*)lusup + xlusup[ndim] * dword); + copy_mem_float(xusub[ndim], dfrom, dto); + ucol = dto; + + ifrom = lsub; + ito = (int *) ((char*)ucol + xusub[ndim] * iword); + copy_mem_int(xlsub[ndim], ifrom, ito); + lsub = ito; + + ifrom = usub; + ito = (int *) ((char*)lsub + xlsub[ndim] * iword); + copy_mem_int(xusub[ndim], ifrom, ito); + usub = ito; + + last = (char*)usub + xusub[ndim] * iword; + fragment = (char*) (((char*)stack.array + stack.top1) - last); + stack.used -= (long int) fragment; + stack.top1 -= (long int) fragment; + + Glu->ucol = ucol; + Glu->lsub = lsub; + Glu->usub = usub; + +#ifdef DEBUG + printf("sStackCompress: fragment %d\n", fragment); + /* for (last = 0; last < ndim; ++last) + print_lu_col("After compress:", last, 0);*/ +#endif + +} + +/* + * Allocate storage for original matrix A + */ +void +sallocateA(int n, int nnz, float **a, int **asub, int **xa) +{ + *a = (float *) floatMalloc(nnz); + *asub = (int *) intMalloc(nnz); + *xa = (int *) intMalloc(n+1); +} + + +float *floatMalloc(int n) +{ + float *buf; + buf = (float *) SUPERLU_MALLOC(n * sizeof(float)); + if ( !buf ) { + ABORT("SUPERLU_MALLOC failed for buf in floatMalloc()\n"); + } + return (buf); +} + +float *floatCalloc(int n) +{ + float *buf; + register int i; + float zero = 0.0; + buf = (float *) SUPERLU_MALLOC(n * sizeof(float)); + if ( !buf ) { + ABORT("SUPERLU_MALLOC failed for buf in floatCalloc()\n"); + } + for (i = 0; i < n; ++i) buf[i] = zero; + return (buf); +} + + +int smemory_usage(const int nzlmax, const int nzumax, + const int nzlumax, const int n) +{ + register int iword, dword; + + iword = sizeof(int); + dword = sizeof(float); + + return (10 * n * iword + + nzlmax * iword + nzumax * (iword + dword) + nzlumax * dword); + +} diff --git a/intern/opennl/superlu/smyblas2.c b/intern/opennl/superlu/smyblas2.c new file mode 100644 index 00000000000..cb2d5cb65af --- /dev/null +++ b/intern/opennl/superlu/smyblas2.c @@ -0,0 +1,232 @@ + + +/* + * -- SuperLU routine (version 2.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * November 15, 1997 + * + */ +/* + * File name: smyblas2.c + * Purpose: + * Level 2 BLAS operations: solves and matvec, written in C. + * Note: + * This is only used when the system lacks an efficient BLAS library. + */ + +/* + * Solves a dense UNIT lower triangular system. The unit lower + * triangular matrix is stored in a 2D array M(1:nrow,1:ncol). + * The solution will be returned in the rhs vector. + */ + +/* local prototypes*/ +void slsolve ( int, int, float *, float *); +void susolve ( int, int, float *, float *); +void smatvec ( int, int, int, float *, float *, float *); + + +void slsolve ( int ldm, int ncol, float *M, float *rhs ) +{ + int k; + float x0, x1, x2, x3, x4, x5, x6, x7; + float *M0; + register float *Mki0, *Mki1, *Mki2, *Mki3, *Mki4, *Mki5, *Mki6, *Mki7; + register int firstcol = 0; + + M0 = &M[0]; + + while ( firstcol < ncol - 7 ) { /* Do 8 columns */ + Mki0 = M0 + 1; + Mki1 = Mki0 + ldm + 1; + Mki2 = Mki1 + ldm + 1; + Mki3 = Mki2 + ldm + 1; + Mki4 = Mki3 + ldm + 1; + Mki5 = Mki4 + ldm + 1; + Mki6 = Mki5 + ldm + 1; + Mki7 = Mki6 + ldm + 1; + + x0 = rhs[firstcol]; + x1 = rhs[firstcol+1] - x0 * *Mki0++; + x2 = rhs[firstcol+2] - x0 * *Mki0++ - x1 * *Mki1++; + x3 = rhs[firstcol+3] - x0 * *Mki0++ - x1 * *Mki1++ - x2 * *Mki2++; + x4 = rhs[firstcol+4] - x0 * *Mki0++ - x1 * *Mki1++ - x2 * *Mki2++ + - x3 * *Mki3++; + x5 = rhs[firstcol+5] - x0 * *Mki0++ - x1 * *Mki1++ - x2 * *Mki2++ + - x3 * *Mki3++ - x4 * *Mki4++; + x6 = rhs[firstcol+6] - x0 * *Mki0++ - x1 * *Mki1++ - x2 * *Mki2++ + - x3 * *Mki3++ - x4 * *Mki4++ - x5 * *Mki5++; + x7 = rhs[firstcol+7] - x0 * *Mki0++ - x1 * *Mki1++ - x2 * *Mki2++ + - x3 * *Mki3++ - x4 * *Mki4++ - x5 * *Mki5++ + - x6 * *Mki6++; + + rhs[++firstcol] = x1; + rhs[++firstcol] = x2; + rhs[++firstcol] = x3; + rhs[++firstcol] = x4; + rhs[++firstcol] = x5; + rhs[++firstcol] = x6; + rhs[++firstcol] = x7; + ++firstcol; + + for (k = firstcol; k < ncol; k++) + rhs[k] = rhs[k] - x0 * *Mki0++ - x1 * *Mki1++ + - x2 * *Mki2++ - x3 * *Mki3++ + - x4 * *Mki4++ - x5 * *Mki5++ + - x6 * *Mki6++ - x7 * *Mki7++; + + M0 += 8 * ldm + 8; + } + + while ( firstcol < ncol - 3 ) { /* Do 4 columns */ + Mki0 = M0 + 1; + Mki1 = Mki0 + ldm + 1; + Mki2 = Mki1 + ldm + 1; + Mki3 = Mki2 + ldm + 1; + + x0 = rhs[firstcol]; + x1 = rhs[firstcol+1] - x0 * *Mki0++; + x2 = rhs[firstcol+2] - x0 * *Mki0++ - x1 * *Mki1++; + x3 = rhs[firstcol+3] - x0 * *Mki0++ - x1 * *Mki1++ - x2 * *Mki2++; + + rhs[++firstcol] = x1; + rhs[++firstcol] = x2; + rhs[++firstcol] = x3; + ++firstcol; + + for (k = firstcol; k < ncol; k++) + rhs[k] = rhs[k] - x0 * *Mki0++ - x1 * *Mki1++ + - x2 * *Mki2++ - x3 * *Mki3++; + + M0 += 4 * ldm + 4; + } + + if ( firstcol < ncol - 1 ) { /* Do 2 columns */ + Mki0 = M0 + 1; + Mki1 = Mki0 + ldm + 1; + + x0 = rhs[firstcol]; + x1 = rhs[firstcol+1] - x0 * *Mki0++; + + rhs[++firstcol] = x1; + ++firstcol; + + for (k = firstcol; k < ncol; k++) + rhs[k] = rhs[k] - x0 * *Mki0++ - x1 * *Mki1++; + + } + +} + +/* + * Solves a dense upper triangular system. The upper triangular matrix is + * stored in a 2-dim array M(1:ldm,1:ncol). The solution will be returned + * in the rhs vector. + */ +void +susolve ( ldm, ncol, M, rhs ) +int ldm; /* in */ +int ncol; /* in */ +float *M; /* in */ +float *rhs; /* modified */ +{ + float xj; + int jcol, j, irow; + + jcol = ncol - 1; + + for (j = 0; j < ncol; j++) { + + xj = rhs[jcol] / M[jcol + jcol*ldm]; /* M(jcol, jcol) */ + rhs[jcol] = xj; + + for (irow = 0; irow < jcol; irow++) + rhs[irow] -= xj * M[irow + jcol*ldm]; /* M(irow, jcol) */ + + jcol--; + + } +} + + +/* + * Performs a dense matrix-vector multiply: Mxvec = Mxvec + M * vec. + * The input matrix is M(1:nrow,1:ncol); The product is returned in Mxvec[]. + */ +void smatvec ( ldm, nrow, ncol, M, vec, Mxvec ) + +int ldm; /* in -- leading dimension of M */ +int nrow; /* in */ +int ncol; /* in */ +float *M; /* in */ +float *vec; /* in */ +float *Mxvec; /* in/out */ + +{ + float vi0, vi1, vi2, vi3, vi4, vi5, vi6, vi7; + float *M0; + register float *Mki0, *Mki1, *Mki2, *Mki3, *Mki4, *Mki5, *Mki6, *Mki7; + register int firstcol = 0; + int k; + + M0 = &M[0]; + while ( firstcol < ncol - 7 ) { /* Do 8 columns */ + + Mki0 = M0; + Mki1 = Mki0 + ldm; + Mki2 = Mki1 + ldm; + Mki3 = Mki2 + ldm; + Mki4 = Mki3 + ldm; + Mki5 = Mki4 + ldm; + Mki6 = Mki5 + ldm; + Mki7 = Mki6 + ldm; + + vi0 = vec[firstcol++]; + vi1 = vec[firstcol++]; + vi2 = vec[firstcol++]; + vi3 = vec[firstcol++]; + vi4 = vec[firstcol++]; + vi5 = vec[firstcol++]; + vi6 = vec[firstcol++]; + vi7 = vec[firstcol++]; + + for (k = 0; k < nrow; k++) + Mxvec[k] += vi0 * *Mki0++ + vi1 * *Mki1++ + + vi2 * *Mki2++ + vi3 * *Mki3++ + + vi4 * *Mki4++ + vi5 * *Mki5++ + + vi6 * *Mki6++ + vi7 * *Mki7++; + + M0 += 8 * ldm; + } + + while ( firstcol < ncol - 3 ) { /* Do 4 columns */ + + Mki0 = M0; + Mki1 = Mki0 + ldm; + Mki2 = Mki1 + ldm; + Mki3 = Mki2 + ldm; + + vi0 = vec[firstcol++]; + vi1 = vec[firstcol++]; + vi2 = vec[firstcol++]; + vi3 = vec[firstcol++]; + for (k = 0; k < nrow; k++) + Mxvec[k] += vi0 * *Mki0++ + vi1 * *Mki1++ + + vi2 * *Mki2++ + vi3 * *Mki3++ ; + + M0 += 4 * ldm; + } + + while ( firstcol < ncol ) { /* Do 1 column */ + + Mki0 = M0; + vi0 = vec[firstcol++]; + for (k = 0; k < nrow; k++) + Mxvec[k] += vi0 * *Mki0++; + + M0 += ldm; + } + +} + diff --git a/intern/opennl/superlu/sp_coletree.c b/intern/opennl/superlu/sp_coletree.c new file mode 100644 index 00000000000..d49919167f5 --- /dev/null +++ b/intern/opennl/superlu/sp_coletree.c @@ -0,0 +1,332 @@ + +/* Elimination tree computation and layout routines */ + +#include +#include +#include "ssp_defs.h" + +/* + * Implementation of disjoint set union routines. + * Elements are integers in 0..n-1, and the + * names of the sets themselves are of type int. + * + * Calls are: + * initialize_disjoint_sets (n) initial call. + * s = make_set (i) returns a set containing only i. + * s = link (t, u) returns s = t union u, destroying t and u. + * s = find (i) return name of set containing i. + * finalize_disjoint_sets final call. + * + * This implementation uses path compression but not weighted union. + * See Tarjan's book for details. + * John Gilbert, CMI, 1987. + * + * Implemented path-halving by XSL 07/05/95. + */ + +static int *pp; /* parent array for sets */ + +static +int *mxCallocInt(int n) +{ + register int i; + int *buf; + + buf = (int *) SUPERLU_MALLOC( n * sizeof(int) ); + if ( !buf ) { + ABORT("SUPERLU_MALLOC fails for buf in mxCallocInt()"); + } + for (i = 0; i < n; i++) buf[i] = 0; + return (buf); +} + +static +void initialize_disjoint_sets ( + int n + ) +{ + pp = mxCallocInt(n); +} + + +static +int make_set ( + int i + ) +{ + pp[i] = i; + return i; +} + + +static +int link ( + int s, + int t + ) +{ + pp[s] = t; + return t; +} + + +/* PATH HALVING */ +static +int find (int i) +{ + register int p, gp; + + p = pp[i]; + gp = pp[p]; + while (gp != p) { + pp[i] = gp; + i = gp; + p = pp[i]; + gp = pp[p]; + } + return (p); +} + +#if 0 +/* PATH COMPRESSION */ +static +int find ( + int i + ) +{ + if (pp[i] != i) + pp[i] = find (pp[i]); + return pp[i]; +} +#endif + +static +void finalize_disjoint_sets ( + void + ) +{ + SUPERLU_FREE(pp); +} + + +/* + * Find the elimination tree for A'*A. + * This uses something similar to Liu's algorithm. + * It runs in time O(nz(A)*log n) and does not form A'*A. + * + * Input: + * Sparse matrix A. Numeric values are ignored, so any + * explicit zeros are treated as nonzero. + * Output: + * Integer array of parents representing the elimination + * tree of the symbolic product A'*A. Each vertex is a + * column of A, and nc means a root of the elimination forest. + * + * John R. Gilbert, Xerox, 10 Dec 1990 + * Based on code by JRG dated 1987, 1988, and 1990. + */ + +/* + * Nonsymmetric elimination tree + */ +int +sp_coletree( + int *acolst, int *acolend, /* column start and end past 1 */ + int *arow, /* row indices of A */ + int nr, int nc, /* dimension of A */ + int *parent /* parent in elim tree */ + ) +{ + int *root; /* root of subtee of etree */ + int *firstcol; /* first nonzero col in each row*/ + int rset, cset; + int row, col; + int rroot; + int p; + + root = mxCallocInt (nc); + initialize_disjoint_sets (nc); + + /* Compute firstcol[row] = first nonzero column in row */ + + firstcol = mxCallocInt (nr); + for (row = 0; row < nr; firstcol[row++] = nc); + for (col = 0; col < nc; col++) + for (p = acolst[col]; p < acolend[col]; p++) { + row = arow[p]; + firstcol[row] = SUPERLU_MIN(firstcol[row], col); + } + + /* Compute etree by Liu's algorithm for symmetric matrices, + except use (firstcol[r],c) in place of an edge (r,c) of A. + Thus each row clique in A'*A is replaced by a star + centered at its first vertex, which has the same fill. */ + + for (col = 0; col < nc; col++) { + cset = make_set (col); + root[cset] = col; + parent[col] = nc; /* Matlab */ + for (p = acolst[col]; p < acolend[col]; p++) { + row = firstcol[arow[p]]; + if (row >= col) continue; + rset = find (row); + rroot = root[rset]; + if (rroot != col) { + parent[rroot] = col; + cset = link (cset, rset); + root[cset] = col; + } + } + } + + SUPERLU_FREE (root); + SUPERLU_FREE (firstcol); + finalize_disjoint_sets (); + return 0; +} + +/* + * q = TreePostorder (n, p); + * + * Postorder a tree. + * Input: + * p is a vector of parent pointers for a forest whose + * vertices are the integers 0 to n-1; p[root]==n. + * Output: + * q is a vector indexed by 0..n-1 such that q[i] is the + * i-th vertex in a postorder numbering of the tree. + * + * ( 2/7/95 modified by X.Li: + * q is a vector indexed by 0:n-1 such that vertex i is the + * q[i]-th vertex in a postorder numbering of the tree. + * That is, this is the inverse of the previous q. ) + * + * In the child structure, lower-numbered children are represented + * first, so that a tree which is already numbered in postorder + * will not have its order changed. + * + * Written by John Gilbert, Xerox, 10 Dec 1990. + * Based on code written by John Gilbert at CMI in 1987. + */ + +static int *first_kid, *next_kid; /* Linked list of children. */ +static int *post, postnum; + +static +/* + * Depth-first search from vertex v. + */ +void etdfs ( + int v + ) +{ + int w; + + for (w = first_kid[v]; w != -1; w = next_kid[w]) { + etdfs (w); + } + /* post[postnum++] = v; in Matlab */ + post[v] = postnum++; /* Modified by X.Li on 2/14/95 */ +} + + +/* + * Post order a tree + */ +int *TreePostorder( + int n, + int *parent +) +{ + int v, dad; + + /* Allocate storage for working arrays and results */ + first_kid = mxCallocInt (n+1); + next_kid = mxCallocInt (n+1); + post = mxCallocInt (n+1); + + /* Set up structure describing children */ + for (v = 0; v <= n; first_kid[v++] = -1); + for (v = n-1; v >= 0; v--) { + dad = parent[v]; + next_kid[v] = first_kid[dad]; + first_kid[dad] = v; + } + + /* Depth-first search from dummy root vertex #n */ + postnum = 0; + etdfs (n); + + SUPERLU_FREE (first_kid); + SUPERLU_FREE (next_kid); + return post; +} + + +/* + * p = spsymetree (A); + * + * Find the elimination tree for symmetric matrix A. + * This uses Liu's algorithm, and runs in time O(nz*log n). + * + * Input: + * Square sparse matrix A. No check is made for symmetry; + * elements below and on the diagonal are ignored. + * Numeric values are ignored, so any explicit zeros are + * treated as nonzero. + * Output: + * Integer array of parents representing the etree, with n + * meaning a root of the elimination forest. + * Note: + * This routine uses only the upper triangle, while sparse + * Cholesky (as in spchol.c) uses only the lower. Matlab's + * dense Cholesky uses only the upper. This routine could + * be modified to use the lower triangle either by transposing + * the matrix or by traversing it by rows with auxiliary + * pointer and link arrays. + * + * John R. Gilbert, Xerox, 10 Dec 1990 + * Based on code by JRG dated 1987, 1988, and 1990. + * Modified by X.S. Li, November 1999. + */ + +/* + * Symmetric elimination tree + */ +int +sp_symetree( + int *acolst, int *acolend, /* column starts and ends past 1 */ + int *arow, /* row indices of A */ + int n, /* dimension of A */ + int *parent /* parent in elim tree */ + ) +{ + int *root; /* root of subtree of etree */ + int rset, cset; + int row, col; + int rroot; + int p; + + root = mxCallocInt (n); + initialize_disjoint_sets (n); + + for (col = 0; col < n; col++) { + cset = make_set (col); + root[cset] = col; + parent[col] = n; /* Matlab */ + for (p = acolst[col]; p < acolend[col]; p++) { + row = arow[p]; + if (row >= col) continue; + rset = find (row); + rroot = root[rset]; + if (rroot != col) { + parent[rroot] = col; + cset = link (cset, rset); + root[cset] = col; + } + } + } + SUPERLU_FREE (root); + finalize_disjoint_sets (); + return 0; +} /* SP_SYMETREE */ diff --git a/intern/opennl/superlu/sp_ienv.c b/intern/opennl/superlu/sp_ienv.c new file mode 100644 index 00000000000..5b0ba7b2151 --- /dev/null +++ b/intern/opennl/superlu/sp_ienv.c @@ -0,0 +1,65 @@ +/* + * File name: sp_ienv.c + * History: Modified from lapack routine ILAENV + */ + +#include "ssp_defs.h" +#include "util.h" + +int +sp_ienv(int ispec) +{ +/* + Purpose + ======= + + sp_ienv() is inquired to choose machine-dependent parameters for the + local environment. See ISPEC for a description of the parameters. + + This version provides a set of parameters which should give good, + but not optimal, performance on many of the currently available + computers. Users are encouraged to modify this subroutine to set + the tuning parameters for their particular machine using the option + and problem size information in the arguments. + + Arguments + ========= + + ISPEC (input) int + Specifies the parameter to be returned as the value of SP_IENV. + = 1: the panel size w; a panel consists of w consecutive + columns of matrix A in the process of Gaussian elimination. + The best value depends on machine's cache characters. + = 2: the relaxation parameter relax; if the number of + nodes (columns) in a subtree of the elimination tree is less + than relax, this subtree is considered as one supernode, + regardless of their row structures. + = 3: the maximum size for a supernode; + = 4: the minimum row dimension for 2-D blocking to be used; + = 5: the minimum column dimension for 2-D blocking to be used; + = 6: the estimated fills factor for L and U, compared with A; + + (SP_IENV) (output) int + >= 0: the value of the parameter specified by ISPEC + < 0: if SP_IENV = -k, the k-th argument had an illegal value. + + ===================================================================== +*/ + int i; + + switch (ispec) { + case 1: return (10); + case 2: return (5); + case 3: return (100); + case 4: return (200); + case 5: return (40); + case 6: return (20); + } + + /* Invalid value for ISPEC */ + i = 1; + xerbla_("sp_ienv", &i); + return 0; + +} /* sp_ienv_ */ + diff --git a/intern/opennl/superlu/sp_preorder.c b/intern/opennl/superlu/sp_preorder.c new file mode 100644 index 00000000000..c40ebc9a4f7 --- /dev/null +++ b/intern/opennl/superlu/sp_preorder.c @@ -0,0 +1,206 @@ +#include "ssp_defs.h" + +int check_perm(char *, int , int *); + + +void +sp_preorder(superlu_options_t *options, SuperMatrix *A, int *perm_c, + int *etree, SuperMatrix *AC) +{ +/* + * Purpose + * ======= + * + * sp_preorder() permutes the columns of the original matrix. It performs + * the following steps: + * + * 1. Apply column permutation perm_c[] to A's column pointers to form AC; + * + * 2. If options->Fact = DOFACT, then + * (1) Compute column elimination tree etree[] of AC'AC; + * (2) Post order etree[] to get a postordered elimination tree etree[], + * and a postorder permutation post[]; + * (3) Apply post[] permutation to columns of AC; + * (4) Overwrite perm_c[] with the product perm_c * post. + * + * Arguments + * ========= + * + * options (input) superlu_options_t* + * Specifies whether or not the elimination tree will be re-used. + * If options->Fact == DOFACT, this means first time factor A, + * etree is computed, postered, and output. + * Otherwise, re-factor A, etree is input, unchanged on exit. + * + * A (input) SuperMatrix* + * Matrix A in A*X=B, of dimension (A->nrow, A->ncol). The number + * of the linear equations is A->nrow. Currently, the type of A can be: + * Stype = NC or SLU_NCP; Mtype = SLU_GE. + * In the future, more general A may be handled. + * + * perm_c (input/output) int* + * Column permutation vector of size A->ncol, which defines the + * permutation matrix Pc; perm_c[i] = j means column i of A is + * in position j in A*Pc. + * If options->Fact == DOFACT, perm_c is both input and output. + * On output, it is changed according to a postorder of etree. + * Otherwise, perm_c is input. + * + * etree (input/output) int* + * Elimination tree of Pc'*A'*A*Pc, dimension A->ncol. + * If options->Fact == DOFACT, etree is an output argument, + * otherwise it is an input argument. + * Note: etree is a vector of parent pointers for a forest whose + * vertices are the integers 0 to A->ncol-1; etree[root]==A->ncol. + * + * AC (output) SuperMatrix* + * The resulting matrix after applied the column permutation + * perm_c[] to matrix A. The type of AC can be: + * Stype = SLU_NCP; Dtype = A->Dtype; Mtype = SLU_GE. + * + */ + + NCformat *Astore; + NCPformat *ACstore; + int *iwork, *post; + register int n, i; + + n = A->ncol; + + /* Apply column permutation perm_c to A's column pointers so to + obtain NCP format in AC = A*Pc. */ + AC->Stype = SLU_NCP; + AC->Dtype = A->Dtype; + AC->Mtype = A->Mtype; + AC->nrow = A->nrow; + AC->ncol = A->ncol; + Astore = A->Store; + ACstore = AC->Store = (void *) SUPERLU_MALLOC( sizeof(NCPformat) ); + if ( !ACstore ) ABORT("SUPERLU_MALLOC fails for ACstore"); + ACstore->nnz = Astore->nnz; + ACstore->nzval = Astore->nzval; + ACstore->rowind = Astore->rowind; + ACstore->colbeg = (int*) SUPERLU_MALLOC(n*sizeof(int)); + if ( !(ACstore->colbeg) ) ABORT("SUPERLU_MALLOC fails for ACstore->colbeg"); + ACstore->colend = (int*) SUPERLU_MALLOC(n*sizeof(int)); + if ( !(ACstore->colend) ) ABORT("SUPERLU_MALLOC fails for ACstore->colend"); + +#ifdef DEBUG + print_int_vec("pre_order:", n, perm_c); + check_perm("Initial perm_c", n, perm_c); +#endif + + for (i = 0; i < n; i++) { + ACstore->colbeg[perm_c[i]] = Astore->colptr[i]; + ACstore->colend[perm_c[i]] = Astore->colptr[i+1]; + } + + if ( options->Fact == DOFACT ) { +#undef ETREE_ATplusA +#ifdef ETREE_ATplusA + /*-------------------------------------------- + COMPUTE THE ETREE OF Pc*(A'+A)*Pc'. + --------------------------------------------*/ + int *b_colptr, *b_rowind, bnz, j; + int *c_colbeg, *c_colend; + + /*printf("Use etree(A'+A)\n");*/ + + /* Form B = A + A'. */ + at_plus_a(n, Astore->nnz, Astore->colptr, Astore->rowind, + &bnz, &b_colptr, &b_rowind); + + /* Form C = Pc*B*Pc'. */ + c_colbeg = (int*) SUPERLU_MALLOC(2*n*sizeof(int)); + c_colend = c_colbeg + n; + if (!c_colbeg ) ABORT("SUPERLU_MALLOC fails for c_colbeg/c_colend"); + for (i = 0; i < n; i++) { + c_colbeg[perm_c[i]] = b_colptr[i]; + c_colend[perm_c[i]] = b_colptr[i+1]; + } + for (j = 0; j < n; ++j) { + for (i = c_colbeg[j]; i < c_colend[j]; ++i) { + b_rowind[i] = perm_c[b_rowind[i]]; + } + } + + /* Compute etree of C. */ + sp_symetree(c_colbeg, c_colend, b_rowind, n, etree); + + SUPERLU_FREE(b_colptr); + if ( bnz ) SUPERLU_FREE(b_rowind); + SUPERLU_FREE(c_colbeg); + +#else + /*-------------------------------------------- + COMPUTE THE COLUMN ELIMINATION TREE. + --------------------------------------------*/ + sp_coletree(ACstore->colbeg, ACstore->colend, ACstore->rowind, + A->nrow, A->ncol, etree); +#endif +#ifdef DEBUG + print_int_vec("etree:", n, etree); +#endif + + /* In symmetric mode, do not do postorder here. */ + if ( options->SymmetricMode == NO ) { + /* Post order etree */ + post = (int *) TreePostorder(n, etree); + /* for (i = 0; i < n+1; ++i) inv_post[post[i]] = i; + iwork = post; */ + +#ifdef DEBUG + print_int_vec("post:", n+1, post); + check_perm("post", n, post); +#endif + iwork = (int*) SUPERLU_MALLOC((n+1)*sizeof(int)); + if ( !iwork ) ABORT("SUPERLU_MALLOC fails for iwork[]"); + + /* Renumber etree in postorder */ + for (i = 0; i < n; ++i) iwork[post[i]] = post[etree[i]]; + for (i = 0; i < n; ++i) etree[i] = iwork[i]; + +#ifdef DEBUG + print_int_vec("postorder etree:", n, etree); +#endif + + /* Postmultiply A*Pc by post[] */ + for (i = 0; i < n; ++i) iwork[post[i]] = ACstore->colbeg[i]; + for (i = 0; i < n; ++i) ACstore->colbeg[i] = iwork[i]; + for (i = 0; i < n; ++i) iwork[post[i]] = ACstore->colend[i]; + for (i = 0; i < n; ++i) ACstore->colend[i] = iwork[i]; + + for (i = 0; i < n; ++i) + iwork[i] = post[perm_c[i]]; /* product of perm_c and post */ + for (i = 0; i < n; ++i) perm_c[i] = iwork[i]; + +#ifdef DEBUG + print_int_vec("Pc*post:", n, perm_c); + check_perm("final perm_c", n, perm_c); +#endif + SUPERLU_FREE (post); + SUPERLU_FREE (iwork); + } /* end postordering */ + + } /* if options->Fact == DOFACT ... */ + +} + +int check_perm(char *what, int n, int *perm) +{ + register int i; + int *marker; + marker = (int *) calloc(n, sizeof(int)); + + for (i = 0; i < n; ++i) { + if ( marker[perm[i]] == 1 || perm[i] >= n ) { + printf("%s: Not a valid PERM[%d] = %d\n", what, i, perm[i]); + ABORT("check_perm"); + } else { + marker[perm[i]] = 1; + } + } + + SUPERLU_FREE(marker); + return 0; +} diff --git a/intern/opennl/superlu/spanel_bmod.c b/intern/opennl/superlu/spanel_bmod.c new file mode 100644 index 00000000000..a59a9086df1 --- /dev/null +++ b/intern/opennl/superlu/spanel_bmod.c @@ -0,0 +1,449 @@ + +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include +#include +#include "ssp_defs.h" + +/* + * Function prototypes + */ +void slsolve(int, int, float *, float *); +void smatvec(int, int, int, float *, float *, float *); +extern void scheck_tempv(); + +void +spanel_bmod ( + const int m, /* in - number of rows in the matrix */ + const int w, /* in */ + const int jcol, /* in */ + const int nseg, /* in */ + float *dense, /* out, of size n by w */ + float *tempv, /* working array */ + int *segrep, /* in */ + int *repfnz, /* in, of size n by w */ + GlobalLU_t *Glu, /* modified */ + SuperLUStat_t *stat /* output */ + ) +{ +/* + * Purpose + * ======= + * + * Performs numeric block updates (sup-panel) in topological order. + * It features: col-col, 2cols-col, 3cols-col, and sup-col updates. + * Special processing on the supernodal portion of L\U[*,j] + * + * Before entering this routine, the original nonzeros in the panel + * were already copied into the spa[m,w]. + * + * Updated/Output parameters- + * dense[0:m-1,w]: L[*,j:j+w-1] and U[*,j:j+w-1] are returned + * collectively in the m-by-w vector dense[*]. + * + */ + +#ifdef USE_VENDOR_BLAS +#ifdef _CRAY + _fcd ftcs1 = _cptofcd("L", strlen("L")), + ftcs2 = _cptofcd("N", strlen("N")), + ftcs3 = _cptofcd("U", strlen("U")); +#endif + int incx = 1, incy = 1; + float alpha, beta; +#endif + + register int k, ksub; + int fsupc, nsupc, nsupr, nrow; + int krep, krep_ind; + float ukj, ukj1, ukj2; + int luptr, luptr1, luptr2; + int segsze; + int block_nrow; /* no of rows in a block row */ + register int lptr; /* Points to the row subscripts of a supernode */ + int kfnz, irow, no_zeros; + register int isub, isub1, i; + register int jj; /* Index through each column in the panel */ + int *xsup, *supno; + int *lsub, *xlsub; + float *lusup; + int *xlusup; + int *repfnz_col; /* repfnz[] for a column in the panel */ + float *dense_col; /* dense[] for a column in the panel */ + float *tempv1; /* Used in 1-D update */ + float *TriTmp, *MatvecTmp; /* used in 2-D update */ + float zero = 0.0; + register int ldaTmp; + register int r_ind, r_hi; + static int first = 1, maxsuper, rowblk, colblk; + flops_t *ops = stat->ops; + + xsup = Glu->xsup; + supno = Glu->supno; + lsub = Glu->lsub; + xlsub = Glu->xlsub; + lusup = Glu->lusup; + xlusup = Glu->xlusup; + + if ( first ) { + maxsuper = sp_ienv(3); + rowblk = sp_ienv(4); + colblk = sp_ienv(5); + first = 0; + } + ldaTmp = maxsuper + rowblk; + + /* + * For each nonz supernode segment of U[*,j] in topological order + */ + k = nseg - 1; + for (ksub = 0; ksub < nseg; ksub++) { /* for each updating supernode */ + + /* krep = representative of current k-th supernode + * fsupc = first supernodal column + * nsupc = no of columns in a supernode + * nsupr = no of rows in a supernode + */ + krep = segrep[k--]; + fsupc = xsup[supno[krep]]; + nsupc = krep - fsupc + 1; + nsupr = xlsub[fsupc+1] - xlsub[fsupc]; + nrow = nsupr - nsupc; + lptr = xlsub[fsupc]; + krep_ind = lptr + nsupc - 1; + + repfnz_col = repfnz; + dense_col = dense; + + if ( nsupc >= colblk && nrow > rowblk ) { /* 2-D block update */ + + TriTmp = tempv; + + /* Sequence through each column in panel -- triangular solves */ + for (jj = jcol; jj < jcol + w; jj++, + repfnz_col += m, dense_col += m, TriTmp += ldaTmp ) { + + kfnz = repfnz_col[krep]; + if ( kfnz == EMPTY ) continue; /* Skip any zero segment */ + + segsze = krep - kfnz + 1; + luptr = xlusup[fsupc]; + + ops[TRSV] += segsze * (segsze - 1); + ops[GEMV] += 2 * nrow * segsze; + + /* Case 1: Update U-segment of size 1 -- col-col update */ + if ( segsze == 1 ) { + ukj = dense_col[lsub[krep_ind]]; + luptr += nsupr*(nsupc-1) + nsupc; + + for (i = lptr + nsupc; i < xlsub[fsupc+1]; i++) { + irow = lsub[i]; + dense_col[irow] -= ukj * lusup[luptr]; + ++luptr; + } + + } else if ( segsze <= 3 ) { + ukj = dense_col[lsub[krep_ind]]; + ukj1 = dense_col[lsub[krep_ind - 1]]; + luptr += nsupr*(nsupc-1) + nsupc-1; + luptr1 = luptr - nsupr; + + if ( segsze == 2 ) { + ukj -= ukj1 * lusup[luptr1]; + dense_col[lsub[krep_ind]] = ukj; + for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) { + irow = lsub[i]; + luptr++; luptr1++; + dense_col[irow] -= (ukj*lusup[luptr] + + ukj1*lusup[luptr1]); + } + } else { + ukj2 = dense_col[lsub[krep_ind - 2]]; + luptr2 = luptr1 - nsupr; + ukj1 -= ukj2 * lusup[luptr2-1]; + ukj = ukj - ukj1*lusup[luptr1] - ukj2*lusup[luptr2]; + dense_col[lsub[krep_ind]] = ukj; + dense_col[lsub[krep_ind-1]] = ukj1; + for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) { + irow = lsub[i]; + luptr++; luptr1++; luptr2++; + dense_col[irow] -= ( ukj*lusup[luptr] + + ukj1*lusup[luptr1] + ukj2*lusup[luptr2] ); + } + } + + } else { /* segsze >= 4 */ + + /* Copy U[*,j] segment from dense[*] to TriTmp[*], which + holds the result of triangular solves. */ + no_zeros = kfnz - fsupc; + isub = lptr + no_zeros; + for (i = 0; i < segsze; ++i) { + irow = lsub[isub]; + TriTmp[i] = dense_col[irow]; /* Gather */ + ++isub; + } + + /* start effective triangle */ + luptr += nsupr * no_zeros + no_zeros; + +#ifdef USE_VENDOR_BLAS +#ifdef _CRAY + STRSV( ftcs1, ftcs2, ftcs3, &segsze, &lusup[luptr], + &nsupr, TriTmp, &incx ); +#else + strsv_( "L", "N", "U", &segsze, &lusup[luptr], + &nsupr, TriTmp, &incx ); +#endif +#else + slsolve ( nsupr, segsze, &lusup[luptr], TriTmp ); +#endif + + + } /* else ... */ + + } /* for jj ... end tri-solves */ + + /* Block row updates; push all the way into dense[*] block */ + for ( r_ind = 0; r_ind < nrow; r_ind += rowblk ) { + + r_hi = SUPERLU_MIN(nrow, r_ind + rowblk); + block_nrow = SUPERLU_MIN(rowblk, r_hi - r_ind); + luptr = xlusup[fsupc] + nsupc + r_ind; + isub1 = lptr + nsupc + r_ind; + + repfnz_col = repfnz; + TriTmp = tempv; + dense_col = dense; + + /* Sequence through each column in panel -- matrix-vector */ + for (jj = jcol; jj < jcol + w; jj++, + repfnz_col += m, dense_col += m, TriTmp += ldaTmp) { + + kfnz = repfnz_col[krep]; + if ( kfnz == EMPTY ) continue; /* Skip any zero segment */ + + segsze = krep - kfnz + 1; + if ( segsze <= 3 ) continue; /* skip unrolled cases */ + + /* Perform a block update, and scatter the result of + matrix-vector to dense[]. */ + no_zeros = kfnz - fsupc; + luptr1 = luptr + nsupr * no_zeros; + MatvecTmp = &TriTmp[maxsuper]; + +#ifdef USE_VENDOR_BLAS + alpha = one; + beta = zero; +#ifdef _CRAY + SGEMV(ftcs2, &block_nrow, &segsze, &alpha, &lusup[luptr1], + &nsupr, TriTmp, &incx, &beta, MatvecTmp, &incy); +#else + sgemv_("N", &block_nrow, &segsze, &alpha, &lusup[luptr1], + &nsupr, TriTmp, &incx, &beta, MatvecTmp, &incy); +#endif +#else + smatvec(nsupr, block_nrow, segsze, &lusup[luptr1], + TriTmp, MatvecTmp); +#endif + + /* Scatter MatvecTmp[*] into SPA dense[*] temporarily + * such that MatvecTmp[*] can be re-used for the + * the next blok row update. dense[] will be copied into + * global store after the whole panel has been finished. + */ + isub = isub1; + for (i = 0; i < block_nrow; i++) { + irow = lsub[isub]; + dense_col[irow] -= MatvecTmp[i]; + MatvecTmp[i] = zero; + ++isub; + } + + } /* for jj ... */ + + } /* for each block row ... */ + + /* Scatter the triangular solves into SPA dense[*] */ + repfnz_col = repfnz; + TriTmp = tempv; + dense_col = dense; + + for (jj = jcol; jj < jcol + w; jj++, + repfnz_col += m, dense_col += m, TriTmp += ldaTmp) { + kfnz = repfnz_col[krep]; + if ( kfnz == EMPTY ) continue; /* Skip any zero segment */ + + segsze = krep - kfnz + 1; + if ( segsze <= 3 ) continue; /* skip unrolled cases */ + + no_zeros = kfnz - fsupc; + isub = lptr + no_zeros; + for (i = 0; i < segsze; i++) { + irow = lsub[isub]; + dense_col[irow] = TriTmp[i]; + TriTmp[i] = zero; + ++isub; + } + + } /* for jj ... */ + + } else { /* 1-D block modification */ + + + /* Sequence through each column in the panel */ + for (jj = jcol; jj < jcol + w; jj++, + repfnz_col += m, dense_col += m) { + + kfnz = repfnz_col[krep]; + if ( kfnz == EMPTY ) continue; /* Skip any zero segment */ + + segsze = krep - kfnz + 1; + luptr = xlusup[fsupc]; + + ops[TRSV] += segsze * (segsze - 1); + ops[GEMV] += 2 * nrow * segsze; + + /* Case 1: Update U-segment of size 1 -- col-col update */ + if ( segsze == 1 ) { + ukj = dense_col[lsub[krep_ind]]; + luptr += nsupr*(nsupc-1) + nsupc; + + for (i = lptr + nsupc; i < xlsub[fsupc+1]; i++) { + irow = lsub[i]; + dense_col[irow] -= ukj * lusup[luptr]; + ++luptr; + } + + } else if ( segsze <= 3 ) { + ukj = dense_col[lsub[krep_ind]]; + luptr += nsupr*(nsupc-1) + nsupc-1; + ukj1 = dense_col[lsub[krep_ind - 1]]; + luptr1 = luptr - nsupr; + + if ( segsze == 2 ) { + ukj -= ukj1 * lusup[luptr1]; + dense_col[lsub[krep_ind]] = ukj; + for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) { + irow = lsub[i]; + ++luptr; ++luptr1; + dense_col[irow] -= (ukj*lusup[luptr] + + ukj1*lusup[luptr1]); + } + } else { + ukj2 = dense_col[lsub[krep_ind - 2]]; + luptr2 = luptr1 - nsupr; + ukj1 -= ukj2 * lusup[luptr2-1]; + ukj = ukj - ukj1*lusup[luptr1] - ukj2*lusup[luptr2]; + dense_col[lsub[krep_ind]] = ukj; + dense_col[lsub[krep_ind-1]] = ukj1; + for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) { + irow = lsub[i]; + ++luptr; ++luptr1; ++luptr2; + dense_col[irow] -= ( ukj*lusup[luptr] + + ukj1*lusup[luptr1] + ukj2*lusup[luptr2] ); + } + } + + } else { /* segsze >= 4 */ + /* + * Perform a triangular solve and block update, + * then scatter the result of sup-col update to dense[]. + */ + no_zeros = kfnz - fsupc; + + /* Copy U[*,j] segment from dense[*] to tempv[*]: + * The result of triangular solve is in tempv[*]; + * The result of matrix vector update is in dense_col[*] + */ + isub = lptr + no_zeros; + for (i = 0; i < segsze; ++i) { + irow = lsub[isub]; + tempv[i] = dense_col[irow]; /* Gather */ + ++isub; + } + + /* start effective triangle */ + luptr += nsupr * no_zeros + no_zeros; + +#ifdef USE_VENDOR_BLAS +#ifdef _CRAY + STRSV( ftcs1, ftcs2, ftcs3, &segsze, &lusup[luptr], + &nsupr, tempv, &incx ); +#else + strsv_( "L", "N", "U", &segsze, &lusup[luptr], + &nsupr, tempv, &incx ); +#endif + + luptr += segsze; /* Dense matrix-vector */ + tempv1 = &tempv[segsze]; + alpha = one; + beta = zero; +#ifdef _CRAY + SGEMV( ftcs2, &nrow, &segsze, &alpha, &lusup[luptr], + &nsupr, tempv, &incx, &beta, tempv1, &incy ); +#else + sgemv_( "N", &nrow, &segsze, &alpha, &lusup[luptr], + &nsupr, tempv, &incx, &beta, tempv1, &incy ); +#endif +#else + slsolve ( nsupr, segsze, &lusup[luptr], tempv ); + + luptr += segsze; /* Dense matrix-vector */ + tempv1 = &tempv[segsze]; + smatvec (nsupr, nrow, segsze, &lusup[luptr], tempv, tempv1); +#endif + + /* Scatter tempv[*] into SPA dense[*] temporarily, such + * that tempv[*] can be used for the triangular solve of + * the next column of the panel. They will be copied into + * ucol[*] after the whole panel has been finished. + */ + isub = lptr + no_zeros; + for (i = 0; i < segsze; i++) { + irow = lsub[isub]; + dense_col[irow] = tempv[i]; + tempv[i] = zero; + isub++; + } + + /* Scatter the update from tempv1[*] into SPA dense[*] */ + /* Start dense rectangular L */ + for (i = 0; i < nrow; i++) { + irow = lsub[isub]; + dense_col[irow] -= tempv1[i]; + tempv1[i] = zero; + ++isub; + } + + } /* else segsze>=4 ... */ + + } /* for each column in the panel... */ + + } /* else 1-D update ... */ + + } /* for each updating supernode ... */ + +} + + + diff --git a/intern/opennl/superlu/spanel_dfs.c b/intern/opennl/superlu/spanel_dfs.c new file mode 100644 index 00000000000..7f5f3c7532a --- /dev/null +++ b/intern/opennl/superlu/spanel_dfs.c @@ -0,0 +1,249 @@ + + +/* + * -- SuperLU routine (version 2.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * November 15, 1997 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include "ssp_defs.h" +#include "util.h" + +void +spanel_dfs ( + const int m, /* in - number of rows in the matrix */ + const int w, /* in */ + const int jcol, /* in */ + SuperMatrix *A, /* in - original matrix */ + int *perm_r, /* in */ + int *nseg, /* out */ + float *dense, /* out */ + int *panel_lsub, /* out */ + int *segrep, /* out */ + int *repfnz, /* out */ + int *xprune, /* out */ + int *marker, /* out */ + int *parent, /* working array */ + int *xplore, /* working array */ + GlobalLU_t *Glu /* modified */ + ) +{ +/* + * Purpose + * ======= + * + * Performs a symbolic factorization on a panel of columns [jcol, jcol+w). + * + * A supernode representative is the last column of a supernode. + * The nonzeros in U[*,j] are segments that end at supernodal + * representatives. + * + * The routine returns one list of the supernodal representatives + * in topological order of the dfs that generates them. This list is + * a superset of the topological order of each individual column within + * the panel. + * The location of the first nonzero in each supernodal segment + * (supernodal entry location) is also returned. Each column has a + * separate list for this purpose. + * + * Two marker arrays are used for dfs: + * marker[i] == jj, if i was visited during dfs of current column jj; + * marker1[i] >= jcol, if i was visited by earlier columns in this panel; + * + * marker: A-row --> A-row/col (0/1) + * repfnz: SuperA-col --> PA-row + * parent: SuperA-col --> SuperA-col + * xplore: SuperA-col --> index to L-structure + * + */ + NCPformat *Astore; + float *a; + int *asub; + int *xa_begin, *xa_end; + int krep, chperm, chmark, chrep, oldrep, kchild, myfnz; + int k, krow, kmark, kperm; + int xdfs, maxdfs, kpar; + int jj; /* index through each column in the panel */ + int *marker1; /* marker1[jj] >= jcol if vertex jj was visited + by a previous column within this panel. */ + int *repfnz_col; /* start of each column in the panel */ + float *dense_col; /* start of each column in the panel */ + int nextl_col; /* next available position in panel_lsub[*,jj] */ + int *xsup, *supno; + int *lsub, *xlsub; + + /* Initialize pointers */ + Astore = A->Store; + a = Astore->nzval; + asub = Astore->rowind; + xa_begin = Astore->colbeg; + xa_end = Astore->colend; + marker1 = marker + m; + repfnz_col = repfnz; + dense_col = dense; + *nseg = 0; + xsup = Glu->xsup; + supno = Glu->supno; + lsub = Glu->lsub; + xlsub = Glu->xlsub; + + /* For each column in the panel */ + for (jj = jcol; jj < jcol + w; jj++) { + nextl_col = (jj - jcol) * m; + +#ifdef CHK_DFS + printf("\npanel col %d: ", jj); +#endif + + /* For each nonz in A[*,jj] do dfs */ + for (k = xa_begin[jj]; k < xa_end[jj]; k++) { + krow = asub[k]; + dense_col[krow] = a[k]; + kmark = marker[krow]; + if ( kmark == jj ) + continue; /* krow visited before, go to the next nonzero */ + + /* For each unmarked nbr krow of jj + * krow is in L: place it in structure of L[*,jj] + */ + marker[krow] = jj; + kperm = perm_r[krow]; + + if ( kperm == EMPTY ) { + panel_lsub[nextl_col++] = krow; /* krow is indexed into A */ + } + /* + * krow is in U: if its supernode-rep krep + * has been explored, update repfnz[*] + */ + else { + + krep = xsup[supno[kperm]+1] - 1; + myfnz = repfnz_col[krep]; + +#ifdef CHK_DFS + printf("krep %d, myfnz %d, perm_r[%d] %d\n", krep, myfnz, krow, kperm); +#endif + if ( myfnz != EMPTY ) { /* Representative visited before */ + if ( myfnz > kperm ) repfnz_col[krep] = kperm; + /* continue; */ + } + else { + /* Otherwise, perform dfs starting at krep */ + oldrep = EMPTY; + parent[krep] = oldrep; + repfnz_col[krep] = kperm; + xdfs = xlsub[krep]; + maxdfs = xprune[krep]; + +#ifdef CHK_DFS + printf(" xdfs %d, maxdfs %d: ", xdfs, maxdfs); + for (i = xdfs; i < maxdfs; i++) printf(" %d", lsub[i]); + printf("\n"); +#endif + do { + /* + * For each unmarked kchild of krep + */ + while ( xdfs < maxdfs ) { + + kchild = lsub[xdfs]; + xdfs++; + chmark = marker[kchild]; + + if ( chmark != jj ) { /* Not reached yet */ + marker[kchild] = jj; + chperm = perm_r[kchild]; + + /* Case kchild is in L: place it in L[*,j] */ + if ( chperm == EMPTY ) { + panel_lsub[nextl_col++] = kchild; + } + /* Case kchild is in U: + * chrep = its supernode-rep. If its rep has + * been explored, update its repfnz[*] + */ + else { + + chrep = xsup[supno[chperm]+1] - 1; + myfnz = repfnz_col[chrep]; +#ifdef CHK_DFS + printf("chrep %d,myfnz %d,perm_r[%d] %d\n",chrep,myfnz,kchild,chperm); +#endif + if ( myfnz != EMPTY ) { /* Visited before */ + if ( myfnz > chperm ) + repfnz_col[chrep] = chperm; + } + else { + /* Cont. dfs at snode-rep of kchild */ + xplore[krep] = xdfs; + oldrep = krep; + krep = chrep; /* Go deeper down G(L) */ + parent[krep] = oldrep; + repfnz_col[krep] = chperm; + xdfs = xlsub[krep]; + maxdfs = xprune[krep]; +#ifdef CHK_DFS + printf(" xdfs %d, maxdfs %d: ", xdfs, maxdfs); + for (i = xdfs; i < maxdfs; i++) printf(" %d", lsub[i]); + printf("\n"); +#endif + } /* else */ + + } /* else */ + + } /* if... */ + + } /* while xdfs < maxdfs */ + + /* krow has no more unexplored nbrs: + * Place snode-rep krep in postorder DFS, if this + * segment is seen for the first time. (Note that + * "repfnz[krep]" may change later.) + * Backtrack dfs to its parent. + */ + if ( marker1[krep] < jcol ) { + segrep[*nseg] = krep; + ++(*nseg); + marker1[krep] = jj; + } + + kpar = parent[krep]; /* Pop stack, mimic recursion */ + if ( kpar == EMPTY ) break; /* dfs done */ + krep = kpar; + xdfs = xplore[krep]; + maxdfs = xprune[krep]; + +#ifdef CHK_DFS + printf(" pop stack: krep %d,xdfs %d,maxdfs %d: ", krep,xdfs,maxdfs); + for (i = xdfs; i < maxdfs; i++) printf(" %d", lsub[i]); + printf("\n"); +#endif + } while ( kpar != EMPTY ); /* do-while - until empty stack */ + + } /* else */ + + } /* else */ + + } /* for each nonz in A[*,jj] */ + + repfnz_col += m; /* Move to next column */ + dense_col += m; + + } /* for jj ... */ + +} diff --git a/intern/opennl/superlu/spivotL.c b/intern/opennl/superlu/spivotL.c new file mode 100644 index 00000000000..6243065bb5b --- /dev/null +++ b/intern/opennl/superlu/spivotL.c @@ -0,0 +1,173 @@ + +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include +#include +#include "ssp_defs.h" + +#undef DEBUG + +int +spivotL( + const int jcol, /* in */ + const float u, /* in - diagonal pivoting threshold */ + int *usepr, /* re-use the pivot sequence given by perm_r/iperm_r */ + int *perm_r, /* may be modified */ + int *iperm_r, /* in - inverse of perm_r */ + int *iperm_c, /* in - used to find diagonal of Pc*A*Pc' */ + int *pivrow, /* out */ + GlobalLU_t *Glu, /* modified - global LU data structures */ + SuperLUStat_t *stat /* output */ + ) +{ +/* + * Purpose + * ======= + * Performs the numerical pivoting on the current column of L, + * and the CDIV operation. + * + * Pivot policy: + * (1) Compute thresh = u * max_(i>=j) abs(A_ij); + * (2) IF user specifies pivot row k and abs(A_kj) >= thresh THEN + * pivot row = k; + * ELSE IF abs(A_jj) >= thresh THEN + * pivot row = j; + * ELSE + * pivot row = m; + * + * Note: If you absolutely want to use a given pivot order, then set u=0.0. + * + * Return value: 0 success; + * i > 0 U(i,i) is exactly zero. + * + */ + int fsupc; /* first column in the supernode */ + int nsupc; /* no of columns in the supernode */ + int nsupr; /* no of rows in the supernode */ + int lptr; /* points to the starting subscript of the supernode */ + int pivptr, old_pivptr, diag, diagind; + float pivmax, rtemp, thresh; + float temp; + float *lu_sup_ptr; + float *lu_col_ptr; + int *lsub_ptr; + int isub, icol, k, itemp; + int *lsub, *xlsub; + float *lusup; + int *xlusup; + flops_t *ops = stat->ops; + + /* Initialize pointers */ + lsub = Glu->lsub; + xlsub = Glu->xlsub; + lusup = Glu->lusup; + xlusup = Glu->xlusup; + fsupc = (Glu->xsup)[(Glu->supno)[jcol]]; + nsupc = jcol - fsupc; /* excluding jcol; nsupc >= 0 */ + lptr = xlsub[fsupc]; + nsupr = xlsub[fsupc+1] - lptr; + lu_sup_ptr = &lusup[xlusup[fsupc]]; /* start of the current supernode */ + lu_col_ptr = &lusup[xlusup[jcol]]; /* start of jcol in the supernode */ + lsub_ptr = &lsub[lptr]; /* start of row indices of the supernode */ + +#ifdef DEBUG +if ( jcol == MIN_COL ) { + printf("Before cdiv: col %d\n", jcol); + for (k = nsupc; k < nsupr; k++) + printf(" lu[%d] %f\n", lsub_ptr[k], lu_col_ptr[k]); +} +#endif + + /* Determine the largest abs numerical value for partial pivoting; + Also search for user-specified pivot, and diagonal element. */ + if ( *usepr ) *pivrow = iperm_r[jcol]; + diagind = iperm_c[jcol]; + pivmax = 0.0; + pivptr = nsupc; + diag = EMPTY; + old_pivptr = nsupc; + for (isub = nsupc; isub < nsupr; ++isub) { + rtemp = fabs (lu_col_ptr[isub]); + if ( rtemp > pivmax ) { + pivmax = rtemp; + pivptr = isub; + } + if ( *usepr && lsub_ptr[isub] == *pivrow ) old_pivptr = isub; + if ( lsub_ptr[isub] == diagind ) diag = isub; + } + + /* Test for singularity */ + if ( pivmax == 0.0 ) { + *pivrow = lsub_ptr[pivptr]; + perm_r[*pivrow] = jcol; + *usepr = 0; + return (jcol+1); + } + + thresh = u * pivmax; + + /* Choose appropriate pivotal element by our policy. */ + if ( *usepr ) { + rtemp = fabs (lu_col_ptr[old_pivptr]); + if ( rtemp != 0.0 && rtemp >= thresh ) + pivptr = old_pivptr; + else + *usepr = 0; + } + if ( *usepr == 0 ) { + /* Use diagonal pivot? */ + if ( diag >= 0 ) { /* diagonal exists */ + rtemp = fabs (lu_col_ptr[diag]); + if ( rtemp != 0.0 && rtemp >= thresh ) pivptr = diag; + } + *pivrow = lsub_ptr[pivptr]; + } + + /* Record pivot row */ + perm_r[*pivrow] = jcol; + + /* Interchange row subscripts */ + if ( pivptr != nsupc ) { + itemp = lsub_ptr[pivptr]; + lsub_ptr[pivptr] = lsub_ptr[nsupc]; + lsub_ptr[nsupc] = itemp; + + /* Interchange numerical values as well, for the whole snode, such + * that L is indexed the same way as A. + */ + for (icol = 0; icol <= nsupc; icol++) { + itemp = pivptr + icol * nsupr; + temp = lu_sup_ptr[itemp]; + lu_sup_ptr[itemp] = lu_sup_ptr[nsupc + icol*nsupr]; + lu_sup_ptr[nsupc + icol*nsupr] = temp; + } + } /* if */ + + /* cdiv operation */ + ops[FACT] += nsupr - nsupc; + + temp = 1.0 / lu_col_ptr[nsupc]; + for (k = nsupc+1; k < nsupr; k++) + lu_col_ptr[k] *= temp; + + return 0; +} + diff --git a/intern/opennl/superlu/spruneL.c b/intern/opennl/superlu/spruneL.c new file mode 100644 index 00000000000..59702706375 --- /dev/null +++ b/intern/opennl/superlu/spruneL.c @@ -0,0 +1,149 @@ + + +/* + * -- SuperLU routine (version 2.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * November 15, 1997 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include "ssp_defs.h" +#include "util.h" + +void +spruneL( + const int jcol, /* in */ + const int *perm_r, /* in */ + const int pivrow, /* in */ + const int nseg, /* in */ + const int *segrep, /* in */ + const int *repfnz, /* in */ + int *xprune, /* out */ + GlobalLU_t *Glu /* modified - global LU data structures */ + ) +{ +/* + * Purpose + * ======= + * Prunes the L-structure of supernodes whose L-structure + * contains the current pivot row "pivrow" + * + */ + float utemp; + int jsupno, irep, irep1, kmin, kmax, krow, movnum; + int i, ktemp, minloc, maxloc; + int do_prune; /* logical variable */ + int *xsup, *supno; + int *lsub, *xlsub; + float *lusup; + int *xlusup; + + xsup = Glu->xsup; + supno = Glu->supno; + lsub = Glu->lsub; + xlsub = Glu->xlsub; + lusup = Glu->lusup; + xlusup = Glu->xlusup; + + /* + * For each supernode-rep irep in U[*,j] + */ + jsupno = supno[jcol]; + for (i = 0; i < nseg; i++) { + + irep = segrep[i]; + irep1 = irep + 1; + do_prune = FALSE; + + /* Don't prune with a zero U-segment */ + if ( repfnz[irep] == EMPTY ) + continue; + + /* If a snode overlaps with the next panel, then the U-segment + * is fragmented into two parts -- irep and irep1. We should let + * pruning occur at the rep-column in irep1's snode. + */ + if ( supno[irep] == supno[irep1] ) /* Don't prune */ + continue; + + /* + * If it has not been pruned & it has a nonz in row L[pivrow,i] + */ + if ( supno[irep] != jsupno ) { + if ( xprune[irep] >= xlsub[irep1] ) { + kmin = xlsub[irep]; + kmax = xlsub[irep1] - 1; + for (krow = kmin; krow <= kmax; krow++) + if ( lsub[krow] == pivrow ) { + do_prune = TRUE; + break; + } + } + + if ( do_prune ) { + + /* Do a quicksort-type partition + * movnum=TRUE means that the num values have to be exchanged. + */ + movnum = FALSE; + if ( irep == xsup[supno[irep]] ) /* Snode of size 1 */ + movnum = TRUE; + + while ( kmin <= kmax ) { + + if ( perm_r[lsub[kmax]] == EMPTY ) + kmax--; + else if ( perm_r[lsub[kmin]] != EMPTY ) + kmin++; + else { /* kmin below pivrow, and kmax above pivrow: + * interchange the two subscripts + */ + ktemp = lsub[kmin]; + lsub[kmin] = lsub[kmax]; + lsub[kmax] = ktemp; + + /* If the supernode has only one column, then we + * only keep one set of subscripts. For any subscript + * interchange performed, similar interchange must be + * done on the numerical values. + */ + if ( movnum ) { + minloc = xlusup[irep] + (kmin - xlsub[irep]); + maxloc = xlusup[irep] + (kmax - xlsub[irep]); + utemp = lusup[minloc]; + lusup[minloc] = lusup[maxloc]; + lusup[maxloc] = utemp; + } + + kmin++; + kmax--; + + } + + } /* while */ + + xprune[irep] = kmin; /* Pruning */ + +#ifdef CHK_PRUNE + printf(" After spruneL(),using col %d: xprune[%d] = %d\n", + jcol, irep, kmin); +#endif + } /* if do_prune */ + + } /* if */ + + } /* for each U-segment... */ +} diff --git a/intern/opennl/superlu/ssnode_bmod.c b/intern/opennl/superlu/ssnode_bmod.c new file mode 100644 index 00000000000..fe97abd9ff6 --- /dev/null +++ b/intern/opennl/superlu/ssnode_bmod.c @@ -0,0 +1,117 @@ + +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include "ssp_defs.h" + +void slsolve(int, int, float*, float*); +void smatvec(int, int, int, float*, float*, float*); + +/* + * Performs numeric block updates within the relaxed snode. + */ +int +ssnode_bmod ( + const int jcol, /* in */ + const int fsupc, /* in */ + float *dense, /* in */ + float *tempv, /* working array */ + GlobalLU_t *Glu, /* modified */ + SuperLUStat_t *stat /* output */ + ) +{ +#ifdef USE_VENDOR_BLAS +#ifdef _CRAY + _fcd ftcs1 = _cptofcd("L", strlen("L")), + ftcs2 = _cptofcd("N", strlen("N")), + ftcs3 = _cptofcd("U", strlen("U")); +#endif + int incx = 1, incy = 1; + float alpha = -1.0, beta = 1.0; +#endif + + int luptr, nsupc, nsupr, nrow; + int isub, irow, i, iptr; + register int ufirst, nextlu; + int *lsub, *xlsub; + float *lusup; + int *xlusup; + flops_t *ops = stat->ops; + + lsub = Glu->lsub; + xlsub = Glu->xlsub; + lusup = Glu->lusup; + xlusup = Glu->xlusup; + + nextlu = xlusup[jcol]; + + /* + * Process the supernodal portion of L\U[*,j] + */ + for (isub = xlsub[fsupc]; isub < xlsub[fsupc+1]; isub++) { + irow = lsub[isub]; + lusup[nextlu] = dense[irow]; + dense[irow] = 0; + ++nextlu; + } + + xlusup[jcol + 1] = nextlu; /* Initialize xlusup for next column */ + + if ( fsupc < jcol ) { + + luptr = xlusup[fsupc]; + nsupr = xlsub[fsupc+1] - xlsub[fsupc]; + nsupc = jcol - fsupc; /* Excluding jcol */ + ufirst = xlusup[jcol]; /* Points to the beginning of column + jcol in supernode L\U(jsupno). */ + nrow = nsupr - nsupc; + + ops[TRSV] += nsupc * (nsupc - 1); + ops[GEMV] += 2 * nrow * nsupc; + +#ifdef USE_VENDOR_BLAS +#ifdef _CRAY + STRSV( ftcs1, ftcs2, ftcs3, &nsupc, &lusup[luptr], &nsupr, + &lusup[ufirst], &incx ); + SGEMV( ftcs2, &nrow, &nsupc, &alpha, &lusup[luptr+nsupc], &nsupr, + &lusup[ufirst], &incx, &beta, &lusup[ufirst+nsupc], &incy ); +#else + strsv_( "L", "N", "U", &nsupc, &lusup[luptr], &nsupr, + &lusup[ufirst], &incx ); + sgemv_( "N", &nrow, &nsupc, &alpha, &lusup[luptr+nsupc], &nsupr, + &lusup[ufirst], &incx, &beta, &lusup[ufirst+nsupc], &incy ); +#endif +#else + slsolve ( nsupr, nsupc, &lusup[luptr], &lusup[ufirst] ); + smatvec ( nsupr, nrow, nsupc, &lusup[luptr+nsupc], + &lusup[ufirst], &tempv[0] ); + + /* Scatter tempv[*] into lusup[*] */ + iptr = ufirst + nsupc; + for (i = 0; i < nrow; i++) { + lusup[iptr++] -= tempv[i]; + tempv[i] = 0.0; + } +#endif + + } + + return 0; +} diff --git a/intern/opennl/superlu/ssnode_dfs.c b/intern/opennl/superlu/ssnode_dfs.c new file mode 100644 index 00000000000..c8974237a9a --- /dev/null +++ b/intern/opennl/superlu/ssnode_dfs.c @@ -0,0 +1,106 @@ + + +/* + * -- SuperLU routine (version 2.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * November 15, 1997 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include "ssp_defs.h" +#include "util.h" + +int +ssnode_dfs ( + const int jcol, /* in - start of the supernode */ + const int kcol, /* in - end of the supernode */ + const int *asub, /* in */ + const int *xa_begin, /* in */ + const int *xa_end, /* in */ + int *xprune, /* out */ + int *marker, /* modified */ + GlobalLU_t *Glu /* modified */ + ) +{ +/* Purpose + * ======= + * ssnode_dfs() - Determine the union of the row structures of those + * columns within the relaxed snode. + * Note: The relaxed snodes are leaves of the supernodal etree, therefore, + * the portion outside the rectangular supernode must be zero. + * + * Return value + * ============ + * 0 success; + * >0 number of bytes allocated when run out of memory. + * + */ + register int i, k, ifrom, ito, nextl, new_next; + int nsuper, krow, kmark, mem_error; + int *xsup, *supno; + int *lsub, *xlsub; + int nzlmax; + + xsup = Glu->xsup; + supno = Glu->supno; + lsub = Glu->lsub; + xlsub = Glu->xlsub; + nzlmax = Glu->nzlmax; + + nsuper = ++supno[jcol]; /* Next available supernode number */ + nextl = xlsub[jcol]; + + for (i = jcol; i <= kcol; i++) { + /* For each nonzero in A[*,i] */ + for (k = xa_begin[i]; k < xa_end[i]; k++) { + krow = asub[k]; + kmark = marker[krow]; + if ( kmark != kcol ) { /* First time visit krow */ + marker[krow] = kcol; + lsub[nextl++] = krow; + if ( nextl >= nzlmax ) { + if ( (mem_error = sLUMemXpand(jcol, nextl, LSUB, &nzlmax, Glu)) ) + return (mem_error); + lsub = Glu->lsub; + } + } + } + supno[i] = nsuper; + } + + /* Supernode > 1, then make a copy of the subscripts for pruning */ + if ( jcol < kcol ) { + new_next = nextl + (nextl - xlsub[jcol]); + while ( new_next > nzlmax ) { + if ( (mem_error = sLUMemXpand(jcol, nextl, LSUB, &nzlmax, Glu)) ) + return (mem_error); + lsub = Glu->lsub; + } + ito = nextl; + for (ifrom = xlsub[jcol]; ifrom < nextl; ) + lsub[ito++] = lsub[ifrom++]; + for (i = jcol+1; i <= kcol; i++) xlsub[i] = nextl; + nextl = ito; + } + + xsup[nsuper+1] = kcol + 1; + supno[kcol+1] = nsuper; + xprune[kcol] = nextl; + xlsub[kcol+1] = nextl; + + return 0; +} + diff --git a/intern/opennl/superlu/ssp_blas2.c b/intern/opennl/superlu/ssp_blas2.c new file mode 100644 index 00000000000..e9f8f53128a --- /dev/null +++ b/intern/opennl/superlu/ssp_blas2.c @@ -0,0 +1,472 @@ + +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +/* + * File name: ssp_blas2.c + * Purpose: Sparse BLAS 2, using some dense BLAS 2 operations. + */ + +#include "ssp_defs.h" + +/* + * Function prototypes + */ +void susolve(int, int, float*, float*); +void slsolve(int, int, float*, float*); +void smatvec(int, int, int, float*, float*, float*); +int strsv_(char*, char*, char*, int*, float*, int*, float*, int*); + +int +sp_strsv(char *uplo, char *trans, char *diag, SuperMatrix *L, + SuperMatrix *U, float *x, SuperLUStat_t *stat, int *info) +{ +/* + * Purpose + * ======= + * + * sp_strsv() solves one of the systems of equations + * A*x = b, or A'*x = b, + * where b and x are n element vectors and A is a sparse unit , or + * non-unit, upper or lower triangular matrix. + * No test for singularity or near-singularity is included in this + * routine. Such tests must be performed before calling this routine. + * + * Parameters + * ========== + * + * uplo - (input) char* + * On entry, uplo specifies whether the matrix is an upper or + * lower triangular matrix as follows: + * uplo = 'U' or 'u' A is an upper triangular matrix. + * uplo = 'L' or 'l' A is a lower triangular matrix. + * + * trans - (input) char* + * On entry, trans specifies the equations to be solved as + * follows: + * trans = 'N' or 'n' A*x = b. + * trans = 'T' or 't' A'*x = b. + * trans = 'C' or 'c' A'*x = b. + * + * diag - (input) char* + * On entry, diag specifies whether or not A is unit + * triangular as follows: + * diag = 'U' or 'u' A is assumed to be unit triangular. + * diag = 'N' or 'n' A is not assumed to be unit + * triangular. + * + * L - (input) SuperMatrix* + * The factor L from the factorization Pr*A*Pc=L*U. Use + * compressed row subscripts storage for supernodes, + * i.e., L has types: Stype = SC, Dtype = SLU_S, Mtype = TRLU. + * + * U - (input) SuperMatrix* + * The factor U from the factorization Pr*A*Pc=L*U. + * U has types: Stype = NC, Dtype = SLU_S, Mtype = TRU. + * + * x - (input/output) float* + * Before entry, the incremented array X must contain the n + * element right-hand side vector b. On exit, X is overwritten + * with the solution vector x. + * + * info - (output) int* + * If *info = -i, the i-th argument had an illegal value. + * + */ +#ifdef _CRAY + _fcd ftcs1 = _cptofcd("L", strlen("L")), + ftcs2 = _cptofcd("N", strlen("N")), + ftcs3 = _cptofcd("U", strlen("U")); +#endif + SCformat *Lstore; + NCformat *Ustore; + float *Lval, *Uval; + int incx = 1; + int nrow; + int fsupc, nsupr, nsupc, luptr, istart, irow; + int i, k, iptr, jcol; + float *work; + flops_t solve_ops; + + /* Test the input parameters */ + *info = 0; + if ( !lsame_(uplo,"L") && !lsame_(uplo, "U") ) *info = -1; + else if ( !lsame_(trans, "N") && !lsame_(trans, "T") && + !lsame_(trans, "C")) *info = -2; + else if ( !lsame_(diag, "U") && !lsame_(diag, "N") ) *info = -3; + else if ( L->nrow != L->ncol || L->nrow < 0 ) *info = -4; + else if ( U->nrow != U->ncol || U->nrow < 0 ) *info = -5; + if ( *info ) { + i = -(*info); + xerbla_("sp_strsv", &i); + return 0; + } + + Lstore = L->Store; + Lval = Lstore->nzval; + Ustore = U->Store; + Uval = Ustore->nzval; + solve_ops = 0; + + if ( !(work = floatCalloc(L->nrow)) ) + ABORT("Malloc fails for work in sp_strsv()."); + + if ( lsame_(trans, "N") ) { /* Form x := inv(A)*x. */ + + if ( lsame_(uplo, "L") ) { + /* Form x := inv(L)*x */ + if ( L->nrow == 0 ) { + SUPERLU_FREE(work); + return 0; /* Quick return */ + } + + for (k = 0; k <= Lstore->nsuper; k++) { + fsupc = L_FST_SUPC(k); + istart = L_SUB_START(fsupc); + nsupr = L_SUB_START(fsupc+1) - istart; + nsupc = L_FST_SUPC(k+1) - fsupc; + luptr = L_NZ_START(fsupc); + nrow = nsupr - nsupc; + + solve_ops += nsupc * (nsupc - 1); + solve_ops += 2 * nrow * nsupc; + + if ( nsupc == 1 ) { + for (iptr=istart+1; iptr < L_SUB_START(fsupc+1); ++iptr) { + irow = L_SUB(iptr); + ++luptr; + x[irow] -= x[fsupc] * Lval[luptr]; + } + } else { +#ifdef USE_VENDOR_BLAS +#ifdef _CRAY + STRSV(ftcs1, ftcs2, ftcs3, &nsupc, &Lval[luptr], &nsupr, + &x[fsupc], &incx); + + SGEMV(ftcs2, &nrow, &nsupc, &alpha, &Lval[luptr+nsupc], + &nsupr, &x[fsupc], &incx, &beta, &work[0], &incy); +#else + strsv_("L", "N", "U", &nsupc, &Lval[luptr], &nsupr, + &x[fsupc], &incx); + + sgemv_("N", &nrow, &nsupc, &alpha, &Lval[luptr+nsupc], + &nsupr, &x[fsupc], &incx, &beta, &work[0], &incy); +#endif +#else + slsolve ( nsupr, nsupc, &Lval[luptr], &x[fsupc]); + + smatvec ( nsupr, nsupr-nsupc, nsupc, &Lval[luptr+nsupc], + &x[fsupc], &work[0] ); +#endif + + iptr = istart + nsupc; + for (i = 0; i < nrow; ++i, ++iptr) { + irow = L_SUB(iptr); + x[irow] -= work[i]; /* Scatter */ + work[i] = 0.0; + + } + } + } /* for k ... */ + + } else { + /* Form x := inv(U)*x */ + + if ( U->nrow == 0 ) return 0; /* Quick return */ + + for (k = Lstore->nsuper; k >= 0; k--) { + fsupc = L_FST_SUPC(k); + nsupr = L_SUB_START(fsupc+1) - L_SUB_START(fsupc); + nsupc = L_FST_SUPC(k+1) - fsupc; + luptr = L_NZ_START(fsupc); + + solve_ops += nsupc * (nsupc + 1); + + if ( nsupc == 1 ) { + x[fsupc] /= Lval[luptr]; + for (i = U_NZ_START(fsupc); i < U_NZ_START(fsupc+1); ++i) { + irow = U_SUB(i); + x[irow] -= x[fsupc] * Uval[i]; + } + } else { +#ifdef USE_VENDOR_BLAS +#ifdef _CRAY + STRSV(ftcs3, ftcs2, ftcs2, &nsupc, &Lval[luptr], &nsupr, + &x[fsupc], &incx); +#else + strsv_("U", "N", "N", &nsupc, &Lval[luptr], &nsupr, + &x[fsupc], &incx); +#endif +#else + susolve ( nsupr, nsupc, &Lval[luptr], &x[fsupc] ); +#endif + + for (jcol = fsupc; jcol < L_FST_SUPC(k+1); jcol++) { + solve_ops += 2*(U_NZ_START(jcol+1) - U_NZ_START(jcol)); + for (i = U_NZ_START(jcol); i < U_NZ_START(jcol+1); + i++) { + irow = U_SUB(i); + x[irow] -= x[jcol] * Uval[i]; + } + } + } + } /* for k ... */ + + } + } else { /* Form x := inv(A')*x */ + + if ( lsame_(uplo, "L") ) { + /* Form x := inv(L')*x */ + if ( L->nrow == 0 ) return 0; /* Quick return */ + + for (k = Lstore->nsuper; k >= 0; --k) { + fsupc = L_FST_SUPC(k); + istart = L_SUB_START(fsupc); + nsupr = L_SUB_START(fsupc+1) - istart; + nsupc = L_FST_SUPC(k+1) - fsupc; + luptr = L_NZ_START(fsupc); + + solve_ops += 2 * (nsupr - nsupc) * nsupc; + + for (jcol = fsupc; jcol < L_FST_SUPC(k+1); jcol++) { + iptr = istart + nsupc; + for (i = L_NZ_START(jcol) + nsupc; + i < L_NZ_START(jcol+1); i++) { + irow = L_SUB(iptr); + x[jcol] -= x[irow] * Lval[i]; + iptr++; + } + } + + if ( nsupc > 1 ) { + solve_ops += nsupc * (nsupc - 1); +#ifdef _CRAY + ftcs1 = _cptofcd("L", strlen("L")); + ftcs2 = _cptofcd("T", strlen("T")); + ftcs3 = _cptofcd("U", strlen("U")); + STRSV(ftcs1, ftcs2, ftcs3, &nsupc, &Lval[luptr], &nsupr, + &x[fsupc], &incx); +#else + strsv_("L", "T", "U", &nsupc, &Lval[luptr], &nsupr, + &x[fsupc], &incx); +#endif + } + } + } else { + /* Form x := inv(U')*x */ + if ( U->nrow == 0 ) return 0; /* Quick return */ + + for (k = 0; k <= Lstore->nsuper; k++) { + fsupc = L_FST_SUPC(k); + nsupr = L_SUB_START(fsupc+1) - L_SUB_START(fsupc); + nsupc = L_FST_SUPC(k+1) - fsupc; + luptr = L_NZ_START(fsupc); + + for (jcol = fsupc; jcol < L_FST_SUPC(k+1); jcol++) { + solve_ops += 2*(U_NZ_START(jcol+1) - U_NZ_START(jcol)); + for (i = U_NZ_START(jcol); i < U_NZ_START(jcol+1); i++) { + irow = U_SUB(i); + x[jcol] -= x[irow] * Uval[i]; + } + } + + solve_ops += nsupc * (nsupc + 1); + + if ( nsupc == 1 ) { + x[fsupc] /= Lval[luptr]; + } else { +#ifdef _CRAY + ftcs1 = _cptofcd("U", strlen("U")); + ftcs2 = _cptofcd("T", strlen("T")); + ftcs3 = _cptofcd("N", strlen("N")); + STRSV( ftcs1, ftcs2, ftcs3, &nsupc, &Lval[luptr], &nsupr, + &x[fsupc], &incx); +#else + strsv_("U", "T", "N", &nsupc, &Lval[luptr], &nsupr, + &x[fsupc], &incx); +#endif + } + } /* for k ... */ + } + } + + stat->ops[SOLVE] += solve_ops; + SUPERLU_FREE(work); + return 0; +} + + + + +int +sp_sgemv(char *trans, float alpha, SuperMatrix *A, float *x, + int incx, float beta, float *y, int incy) +{ +/* Purpose + ======= + + sp_sgemv() performs one of the matrix-vector operations + y := alpha*A*x + beta*y, or y := alpha*A'*x + beta*y, + where alpha and beta are scalars, x and y are vectors and A is a + sparse A->nrow by A->ncol matrix. + + Parameters + ========== + + TRANS - (input) char* + On entry, TRANS specifies the operation to be performed as + follows: + TRANS = 'N' or 'n' y := alpha*A*x + beta*y. + TRANS = 'T' or 't' y := alpha*A'*x + beta*y. + TRANS = 'C' or 'c' y := alpha*A'*x + beta*y. + + ALPHA - (input) float + On entry, ALPHA specifies the scalar alpha. + + A - (input) SuperMatrix* + Matrix A with a sparse format, of dimension (A->nrow, A->ncol). + Currently, the type of A can be: + Stype = NC or NCP; Dtype = SLU_S; Mtype = GE. + In the future, more general A can be handled. + + X - (input) float*, array of DIMENSION at least + ( 1 + ( n - 1 )*abs( INCX ) ) when TRANS = 'N' or 'n' + and at least + ( 1 + ( m - 1 )*abs( INCX ) ) otherwise. + Before entry, the incremented array X must contain the + vector x. + + INCX - (input) int + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + + BETA - (input) float + On entry, BETA specifies the scalar beta. When BETA is + supplied as zero then Y need not be set on input. + + Y - (output) float*, array of DIMENSION at least + ( 1 + ( m - 1 )*abs( INCY ) ) when TRANS = 'N' or 'n' + and at least + ( 1 + ( n - 1 )*abs( INCY ) ) otherwise. + Before entry with BETA non-zero, the incremented array Y + must contain the vector y. On exit, Y is overwritten by the + updated vector y. + + INCY - (input) int + On entry, INCY specifies the increment for the elements of + Y. INCY must not be zero. + + ==== Sparse Level 2 Blas routine. +*/ + + /* Local variables */ + NCformat *Astore; + float *Aval; + int info; + float temp; + int lenx, leny, i, j, irow; + int iy, jx, jy, kx, ky; + int notran; + + notran = lsame_(trans, "N"); + Astore = A->Store; + Aval = Astore->nzval; + + /* Test the input parameters */ + info = 0; + if ( !notran && !lsame_(trans, "T") && !lsame_(trans, "C")) info = 1; + else if ( A->nrow < 0 || A->ncol < 0 ) info = 3; + else if (incx == 0) info = 5; + else if (incy == 0) info = 8; + if (info != 0) { + xerbla_("sp_sgemv ", &info); + return 0; + } + + /* Quick return if possible. */ + if (A->nrow == 0 || A->ncol == 0 || (alpha == 0. && beta == 1.)) + return 0; + + /* Set LENX and LENY, the lengths of the vectors x and y, and set + up the start points in X and Y. */ + if (lsame_(trans, "N")) { + lenx = A->ncol; + leny = A->nrow; + } else { + lenx = A->nrow; + leny = A->ncol; + } + if (incx > 0) kx = 0; + else kx = - (lenx - 1) * incx; + if (incy > 0) ky = 0; + else ky = - (leny - 1) * incy; + + /* Start the operations. In this version the elements of A are + accessed sequentially with one pass through A. */ + /* First form y := beta*y. */ + if (beta != 1.) { + if (incy == 1) { + if (beta == 0.) + for (i = 0; i < leny; ++i) y[i] = 0.; + else + for (i = 0; i < leny; ++i) y[i] = beta * y[i]; + } else { + iy = ky; + if (beta == 0.) + for (i = 0; i < leny; ++i) { + y[iy] = 0.; + iy += incy; + } + else + for (i = 0; i < leny; ++i) { + y[iy] = beta * y[iy]; + iy += incy; + } + } + } + + if (alpha == 0.) return 0; + + if ( notran ) { + /* Form y := alpha*A*x + y. */ + jx = kx; + if (incy == 1) { + for (j = 0; j < A->ncol; ++j) { + if (x[jx] != 0.) { + temp = alpha * x[jx]; + for (i = Astore->colptr[j]; i < Astore->colptr[j+1]; ++i) { + irow = Astore->rowind[i]; + y[irow] += temp * Aval[i]; + } + } + jx += incx; + } + } else { + ABORT("Not implemented."); + } + } else { + /* Form y := alpha*A'*x + y. */ + jy = ky; + if (incx == 1) { + for (j = 0; j < A->ncol; ++j) { + temp = 0.; + for (i = Astore->colptr[j]; i < Astore->colptr[j+1]; ++i) { + irow = Astore->rowind[i]; + temp += Aval[i] * x[irow]; + } + y[jy] += alpha * temp; + jy += incy; + } + } else { + ABORT("Not implemented."); + } + } + return 0; +} /* sp_sgemv */ + + + diff --git a/intern/opennl/superlu/ssp_blas3.c b/intern/opennl/superlu/ssp_blas3.c new file mode 100644 index 00000000000..19086077c4c --- /dev/null +++ b/intern/opennl/superlu/ssp_blas3.c @@ -0,0 +1,121 @@ + + +/* + * -- SuperLU routine (version 2.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * November 15, 1997 + * + */ +/* + * File name: sp_blas3.c + * Purpose: Sparse BLAS3, using some dense BLAS3 operations. + */ + +#include "ssp_defs.h" +#include "util.h" + +int +sp_sgemm(char *transa, int n, + float alpha, SuperMatrix *A, float *b, int ldb, + float beta, float *c, int ldc) +{ +/* Purpose + ======= + + sp_s performs one of the matrix-matrix operations + + C := alpha*op( A )*op( B ) + beta*C, + + where op( X ) is one of + + op( X ) = X or op( X ) = X' or op( X ) = conjg( X' ), + + alpha and beta are scalars, and A, B and C are matrices, with op( A ) + an m by k matrix, op( B ) a k by n matrix and C an m by n matrix. + + + Parameters + ========== + + TRANSA - (input) char* + On entry, TRANSA specifies the form of op( A ) to be used in + the matrix multiplication as follows: + TRANSA = 'N' or 'n', op( A ) = A. + TRANSA = 'T' or 't', op( A ) = A'. + TRANSA = 'C' or 'c', op( A ) = conjg( A' ). + Unchanged on exit. + + TRANSB - (input) char* + On entry, TRANSB specifies the form of op( B ) to be used in + the matrix multiplication as follows: + TRANSB = 'N' or 'n', op( B ) = B. + TRANSB = 'T' or 't', op( B ) = B'. + TRANSB = 'C' or 'c', op( B ) = conjg( B' ). + Unchanged on exit. + + M - (input) int + On entry, M specifies the number of rows of the matrix + op( A ) and of the matrix C. M must be at least zero. + Unchanged on exit. + + N - (input) int + On entry, N specifies the number of columns of the matrix + op( B ) and the number of columns of the matrix C. N must be + at least zero. + Unchanged on exit. + + K - (input) int + On entry, K specifies the number of columns of the matrix + op( A ) and the number of rows of the matrix op( B ). K must + be at least zero. + Unchanged on exit. + + ALPHA - (input) float + On entry, ALPHA specifies the scalar alpha. + + A - (input) SuperMatrix* + Matrix A with a sparse format, of dimension (A->nrow, A->ncol). + Currently, the type of A can be: + Stype = NC or NCP; Dtype = SLU_S; Mtype = GE. + In the future, more general A can be handled. + + B - FLOAT PRECISION array of DIMENSION ( LDB, kb ), where kb is + n when TRANSB = 'N' or 'n', and is k otherwise. + Before entry with TRANSB = 'N' or 'n', the leading k by n + part of the array B must contain the matrix B, otherwise + the leading n by k part of the array B must contain the + matrix B. + Unchanged on exit. + + LDB - (input) int + On entry, LDB specifies the first dimension of B as declared + in the calling (sub) program. LDB must be at least max( 1, n ). + Unchanged on exit. + + BETA - (input) float + On entry, BETA specifies the scalar beta. When BETA is + supplied as zero then C need not be set on input. + + C - FLOAT PRECISION array of DIMENSION ( LDC, n ). + Before entry, the leading m by n part of the array C must + contain the matrix C, except when beta is zero, in which + case C need not be set on entry. + On exit, the array C is overwritten by the m by n matrix + ( alpha*op( A )*B + beta*C ). + + LDC - (input) int + On entry, LDC specifies the first dimension of C as declared + in the calling (sub)program. LDC must be at least max(1,m). + Unchanged on exit. + + ==== Sparse Level 3 Blas routine. +*/ + int incx = 1, incy = 1; + int j; + + for (j = 0; j < n; ++j) { + sp_sgemv(transa, alpha, A, &b[ldb*j], incx, beta, &c[ldc*j], incy); + } + return 0; +} diff --git a/intern/opennl/superlu/ssp_defs.h b/intern/opennl/superlu/ssp_defs.h new file mode 100644 index 00000000000..61b324e74d8 --- /dev/null +++ b/intern/opennl/superlu/ssp_defs.h @@ -0,0 +1,237 @@ + +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +#ifndef __SUPERLU_sSP_DEFS /* allow multiple inclusions */ +#define __SUPERLU_sSP_DEFS + +/* + * File name: ssp_defs.h + * Purpose: Sparse matrix types and function prototypes + * History: + */ + +#ifdef _CRAY +#include +#include +#endif + +/* Define my integer type int_t */ +typedef int int_t; /* default */ + +#include "Cnames.h" +#include "supermatrix.h" +#include "util.h" + + +/* + * Global data structures used in LU factorization - + * + * nsuper: #supernodes = nsuper + 1, numbered [0, nsuper]. + * (xsup,supno): supno[i] is the supernode no to which i belongs; + * xsup(s) points to the beginning of the s-th supernode. + * e.g. supno 0 1 2 2 3 3 3 4 4 4 4 4 (n=12) + * xsup 0 1 2 4 7 12 + * Note: dfs will be performed on supernode rep. relative to the new + * row pivoting ordering + * + * (xlsub,lsub): lsub[*] contains the compressed subscript of + * rectangular supernodes; xlsub[j] points to the starting + * location of the j-th column in lsub[*]. Note that xlsub + * is indexed by column. + * Storage: original row subscripts + * + * During the course of sparse LU factorization, we also use + * (xlsub,lsub) for the purpose of symmetric pruning. For each + * supernode {s,s+1,...,t=s+r} with first column s and last + * column t, the subscript set + * lsub[j], j=xlsub[s], .., xlsub[s+1]-1 + * is the structure of column s (i.e. structure of this supernode). + * It is used for the storage of numerical values. + * Furthermore, + * lsub[j], j=xlsub[t], .., xlsub[t+1]-1 + * is the structure of the last column t of this supernode. + * It is for the purpose of symmetric pruning. Therefore, the + * structural subscripts can be rearranged without making physical + * interchanges among the numerical values. + * + * However, if the supernode has only one column, then we + * only keep one set of subscripts. For any subscript interchange + * performed, similar interchange must be done on the numerical + * values. + * + * The last column structures (for pruning) will be removed + * after the numercial LU factorization phase. + * + * (xlusup,lusup): lusup[*] contains the numerical values of the + * rectangular supernodes; xlusup[j] points to the starting + * location of the j-th column in storage vector lusup[*] + * Note: xlusup is indexed by column. + * Each rectangular supernode is stored by column-major + * scheme, consistent with Fortran 2-dim array storage. + * + * (xusub,ucol,usub): ucol[*] stores the numerical values of + * U-columns outside the rectangular supernodes. The row + * subscript of nonzero ucol[k] is stored in usub[k]. + * xusub[i] points to the starting location of column i in ucol. + * Storage: new row subscripts; that is subscripts of PA. + */ +typedef struct { + int *xsup; /* supernode and column mapping */ + int *supno; + int *lsub; /* compressed L subscripts */ + int *xlsub; + float *lusup; /* L supernodes */ + int *xlusup; + float *ucol; /* U columns */ + int *usub; + int *xusub; + int nzlmax; /* current max size of lsub */ + int nzumax; /* " " " ucol */ + int nzlumax; /* " " " lusup */ + int n; /* number of columns in the matrix */ + LU_space_t MemModel; /* 0 - system malloc'd; 1 - user provided */ +} GlobalLU_t; + +typedef struct { + float for_lu; + float total_needed; + int expansions; +} mem_usage_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/* Driver routines */ +extern void +sgssv(superlu_options_t *, SuperMatrix *, int *, int *, SuperMatrix *, + SuperMatrix *, SuperMatrix *, SuperLUStat_t *, int *); +extern void +sgssvx(superlu_options_t *, SuperMatrix *, int *, int *, int *, + char *, float *, float *, SuperMatrix *, SuperMatrix *, + void *, int, SuperMatrix *, SuperMatrix *, + float *, float *, float *, float *, + mem_usage_t *, SuperLUStat_t *, int *); + +/* Supernodal LU factor related */ +extern void +sCreate_CompCol_Matrix(SuperMatrix *, int, int, int, float *, + int *, int *, Stype_t, Dtype_t, Mtype_t); +extern void +sCreate_CompRow_Matrix(SuperMatrix *, int, int, int, float *, + int *, int *, Stype_t, Dtype_t, Mtype_t); +extern void +sCopy_CompCol_Matrix(SuperMatrix *, SuperMatrix *); +extern void +sCreate_Dense_Matrix(SuperMatrix *, int, int, float *, int, + Stype_t, Dtype_t, Mtype_t); +extern void +sCreate_SuperNode_Matrix(SuperMatrix *, int, int, int, float *, + int *, int *, int *, int *, int *, + Stype_t, Dtype_t, Mtype_t); +extern void +sCopy_Dense_Matrix(int, int, float *, int, float *, int); + +extern void countnz (const int, int *, int *, int *, GlobalLU_t *); +extern void fixupL (const int, const int *, GlobalLU_t *); + +extern void sallocateA (int, int, float **, int **, int **); +extern void sgstrf (superlu_options_t*, SuperMatrix*, + int, int, int*, void *, int, int *, int *, + SuperMatrix *, SuperMatrix *, SuperLUStat_t*, int *); +extern int ssnode_dfs (const int, const int, const int *, const int *, + const int *, int *, int *, GlobalLU_t *); +extern int ssnode_bmod (const int, const int, float *, + float *, GlobalLU_t *, SuperLUStat_t*); +extern void spanel_dfs (const int, const int, const int, SuperMatrix *, + int *, int *, float *, int *, int *, int *, + int *, int *, int *, int *, GlobalLU_t *); +extern void spanel_bmod (const int, const int, const int, const int, + float *, float *, int *, int *, + GlobalLU_t *, SuperLUStat_t*); +extern int scolumn_dfs (const int, const int, int *, int *, int *, int *, + int *, int *, int *, int *, int *, GlobalLU_t *); +extern int scolumn_bmod (const int, const int, float *, + float *, int *, int *, int, + GlobalLU_t *, SuperLUStat_t*); +extern int scopy_to_ucol (int, int, int *, int *, int *, + float *, GlobalLU_t *); +extern int spivotL (const int, const float, int *, int *, + int *, int *, int *, GlobalLU_t *, SuperLUStat_t*); +extern void spruneL (const int, const int *, const int, const int, + const int *, const int *, int *, GlobalLU_t *); +extern void sreadmt (int *, int *, int *, float **, int **, int **); +extern void sGenXtrue (int, int, float *, int); +extern void sFillRHS (trans_t, int, float *, int, SuperMatrix *, + SuperMatrix *); +extern void sgstrs (trans_t, SuperMatrix *, SuperMatrix *, int *, int *, + SuperMatrix *, SuperLUStat_t*, int *); + + +/* Driver related */ + +extern void sgsequ (SuperMatrix *, float *, float *, float *, + float *, float *, int *); +extern void slaqgs (SuperMatrix *, float *, float *, float, + float, float, char *); +extern void sgscon (char *, SuperMatrix *, SuperMatrix *, + float, float *, SuperLUStat_t*, int *); +extern float sPivotGrowth(int, SuperMatrix *, int *, + SuperMatrix *, SuperMatrix *); +extern void sgsrfs (trans_t, SuperMatrix *, SuperMatrix *, + SuperMatrix *, int *, int *, char *, float *, + float *, SuperMatrix *, SuperMatrix *, + float *, float *, SuperLUStat_t*, int *); + +extern int sp_strsv (char *, char *, char *, SuperMatrix *, + SuperMatrix *, float *, SuperLUStat_t*, int *); +extern int sp_sgemv (char *, float, SuperMatrix *, float *, + int, float, float *, int); + +extern int sp_sgemm (char *, int, float, + SuperMatrix *, float *, int, float, + float *, int); + +/* Memory-related */ +extern int sLUMemInit (fact_t, void *, int, int, int, int, int, + SuperMatrix *, SuperMatrix *, + GlobalLU_t *, int **, float **); +extern void sSetRWork (int, int, float *, float **, float **); +extern void sLUWorkFree (int *, float *, GlobalLU_t *); +extern int sLUMemXpand (int, int, MemType, int *, GlobalLU_t *); + +extern float *floatMalloc(int); +extern float *floatCalloc(int); +extern int smemory_usage(const int, const int, const int, const int); +extern int sQuerySpace (SuperMatrix *, SuperMatrix *, mem_usage_t *); + +/* Auxiliary routines */ +extern void sreadhb(int *, int *, int *, float **, int **, int **); +extern void sCompRow_to_CompCol(int, int, int, float*, int*, int*, + float **, int **, int **); +extern void sfill (float *, int, float); +extern void sinf_norm_error (int, SuperMatrix *, float *); +extern void PrintPerf (SuperMatrix *, SuperMatrix *, mem_usage_t *, + float, float, float *, float *, char *); + +/* Routines for debugging */ +extern void sPrint_CompCol_Matrix(char *, SuperMatrix *); +extern void sPrint_SuperNode_Matrix(char *, SuperMatrix *); +extern void sPrint_Dense_Matrix(char *, SuperMatrix *); +extern void print_lu_col(char *, int, int, int *, GlobalLU_t *); +extern void check_tempv(int, float *); +extern int print_int_vec(char *what, int n, int *vec); + +extern int sp_symetree(int *acolst, int *acolend, int *arow, int n, int *parent); + +#ifdef __cplusplus + } +#endif + +#endif /* __SUPERLU_sSP_DEFS */ + diff --git a/intern/opennl/superlu/strsv.c b/intern/opennl/superlu/strsv.c new file mode 100644 index 00000000000..415f96f5f74 --- /dev/null +++ b/intern/opennl/superlu/strsv.c @@ -0,0 +1,333 @@ +int strsv_(char *, char *, char *, int *, float *, int *, float *, int *); + + +/* Subroutine */ int strsv_(char *uplo, char *trans, char *diag, int *n, + float *a, int *lda, float *x, int *incx) +{ + + + /* System generated locals */ + int i__1, i__2; + + /* Local variables */ + static int info; + static float temp; + static int i, j; + extern int lsame_(char *, char *); + static int ix, jx, kx; + extern /* Subroutine */ int xerbla_(char *, int *); + static int nounit; + + +/* Purpose + ======= + + STRSV solves one of the systems of equations + + A*x = b, or A'*x = b, + + where b and x are n element vectors and A is an n by n unit, or + non-unit, upper or lower triangular matrix. + + No test for singularity or near-singularity is included in this + routine. Such tests must be performed before calling this routine. + + Parameters + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the matrix is an upper or + lower triangular matrix as follows: + + UPLO = 'U' or 'u' A is an upper triangular matrix. + + UPLO = 'L' or 'l' A is a lower triangular matrix. + + Unchanged on exit. + + TRANS - CHARACTER*1. + On entry, TRANS specifies the equations to be solved as + follows: + + TRANS = 'N' or 'n' A*x = b. + + TRANS = 'T' or 't' A'*x = b. + + TRANS = 'C' or 'c' A'*x = b. + + Unchanged on exit. + + DIAG - CHARACTER*1. + On entry, DIAG specifies whether or not A is unit + triangular as follows: + + DIAG = 'U' or 'u' A is assumed to be unit triangular. + + DIAG = 'N' or 'n' A is not assumed to be unit + triangular. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix A. + N must be at least zero. + Unchanged on exit. + + A - REAL array of DIMENSION ( LDA, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array A must contain the upper + + triangular matrix and the strictly lower triangular part of + + A is not referenced. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array A must contain the lower + + triangular matrix and the strictly upper triangular part of + + A is not referenced. + Note that when DIAG = 'U' or 'u', the diagonal elements of + + A are not referenced either, but are assumed to be unity. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + + in the calling (sub) program. LDA must be at least + max( 1, n ). + Unchanged on exit. + + X - REAL array of dimension at least + ( 1 + ( n - 1 )*abs( INCX ) ). + Before entry, the incremented array X must contain the n + element right-hand side vector b. On exit, X is overwritten + + with the solution vector x. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + + + Test the input parameters. + + + Parameter adjustments + Function Body */ +#define X(I) x[(I)-1] + +#define A(I,J) a[(I)-1 + ((J)-1)* ( *lda)] + + info = 0; + if (! lsame_(uplo, "U") && ! lsame_(uplo, "L")) { + info = 1; + } else if (! lsame_(trans, "N") && ! lsame_(trans, "T") && + ! lsame_(trans, "C")) { + info = 2; + } else if (! lsame_(diag, "U") && ! lsame_(diag, "N")) { + info = 3; + } else if (*n < 0) { + info = 4; + } else if (*lda < ((1 > *n)? 1: *n)) { + info = 6; + } else if (*incx == 0) { + info = 8; + } + if (info != 0) { + xerbla_("STRSV ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0) { + return 0; + } + + nounit = lsame_(diag, "N"); + +/* Set up the start point in X if the increment is not unity. This + will be ( N - 1 )*INCX too small for descending loops. */ + + if (*incx <= 0) { + kx = 1 - (*n - 1) * *incx; + } else if (*incx != 1) { + kx = 1; + } + +/* Start the operations. In this version the elements of A are + accessed sequentially with one pass through A. */ + + if (lsame_(trans, "N")) { + +/* Form x := inv( A )*x. */ + + if (lsame_(uplo, "U")) { + if (*incx == 1) { + for (j = *n; j >= 1; --j) { + if (X(j) != 0.f) { + if (nounit) { + X(j) /= A(j,j); + } + temp = X(j); + for (i = j - 1; i >= 1; --i) { + X(i) -= temp * A(i,j); +/* L10: */ + } + } +/* L20: */ + } + } else { + jx = kx + (*n - 1) * *incx; + for (j = *n; j >= 1; --j) { + if (X(jx) != 0.f) { + if (nounit) { + X(jx) /= A(j,j); + } + temp = X(jx); + ix = jx; + for (i = j - 1; i >= 1; --i) { + ix -= *incx; + X(ix) -= temp * A(i,j); +/* L30: */ + } + } + jx -= *incx; +/* L40: */ + } + } + } else { + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= *n; ++j) { + if (X(j) != 0.f) { + if (nounit) { + X(j) /= A(j,j); + } + temp = X(j); + i__2 = *n; + for (i = j + 1; i <= *n; ++i) { + X(i) -= temp * A(i,j); +/* L50: */ + } + } +/* L60: */ + } + } else { + jx = kx; + i__1 = *n; + for (j = 1; j <= *n; ++j) { + if (X(jx) != 0.f) { + if (nounit) { + X(jx) /= A(j,j); + } + temp = X(jx); + ix = jx; + i__2 = *n; + for (i = j + 1; i <= *n; ++i) { + ix += *incx; + X(ix) -= temp * A(i,j); +/* L70: */ + } + } + jx += *incx; +/* L80: */ + } + } + } + } else { + +/* Form x := inv( A' )*x. */ + + if (lsame_(uplo, "U")) { + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= *n; ++j) { + temp = X(j); + i__2 = j - 1; + for (i = 1; i <= j-1; ++i) { + temp -= A(i,j) * X(i); +/* L90: */ + } + if (nounit) { + temp /= A(j,j); + } + X(j) = temp; +/* L100: */ + } + } else { + jx = kx; + i__1 = *n; + for (j = 1; j <= *n; ++j) { + temp = X(jx); + ix = kx; + i__2 = j - 1; + for (i = 1; i <= j-1; ++i) { + temp -= A(i,j) * X(ix); + ix += *incx; +/* L110: */ + } + if (nounit) { + temp /= A(j,j); + } + X(jx) = temp; + jx += *incx; +/* L120: */ + } + } + } else { + if (*incx == 1) { + for (j = *n; j >= 1; --j) { + temp = X(j); + i__1 = j + 1; + for (i = *n; i >= j+1; --i) { + temp -= A(i,j) * X(i); +/* L130: */ + } + if (nounit) { + temp /= A(j,j); + } + X(j) = temp; +/* L140: */ + } + } else { + kx += (*n - 1) * *incx; + jx = kx; + for (j = *n; j >= 1; --j) { + temp = X(jx); + ix = kx; + i__1 = j + 1; + for (i = *n; i >= j+1; --i) { + temp -= A(i,j) * X(ix); + ix -= *incx; +/* L150: */ + } + if (nounit) { + temp /= A(j,j); + } + X(jx) = temp; + jx -= *incx; +/* L160: */ + } + } + } + } + + return 0; + +/* End of STRSV . */ + +} /* strsv_ */ + diff --git a/intern/opennl/superlu/superlu_timer.c b/intern/opennl/superlu/superlu_timer.c new file mode 100644 index 00000000000..f9e130c8c5a --- /dev/null +++ b/intern/opennl/superlu/superlu_timer.c @@ -0,0 +1,58 @@ +/* + * Purpose + * ======= + * Returns the time in seconds used by the process. + * + * Note: the timer function call is machine dependent. Use conditional + * compilation to choose the appropriate function. + * + */ + +/* We want this flag, safer than putting in build system */ +#define NO_TIMER + +double SuperLU_timer_ (); + +#ifdef SUN +/* + * It uses the system call gethrtime(3C), which is accurate to + * nanoseconds. +*/ +#include + +double SuperLU_timer_() { + return ( (double)gethrtime() / 1e9 ); +} + +#else + +#ifndef NO_TIMER +#include +#include +#include +#include +#endif + +#ifndef CLK_TCK +#define CLK_TCK 60 +#endif +double SuperLU_timer_(void); + +double SuperLU_timer_(void) +{ +#ifdef NO_TIMER + /* no sys/times.h on WIN32 */ + double tmp; + tmp = 0.0; +#else + struct tms use; + double tmp; + times(&use); + tmp = use.tms_utime; + tmp += use.tms_stime; +#endif + return (double)(tmp) / CLK_TCK; +} + +#endif + diff --git a/intern/opennl/superlu/supermatrix.h b/intern/opennl/superlu/supermatrix.h new file mode 100644 index 00000000000..665e22dc91f --- /dev/null +++ b/intern/opennl/superlu/supermatrix.h @@ -0,0 +1,140 @@ +#ifndef __SUPERLU_SUPERMATRIX /* allow multiple inclusions */ +#define __SUPERLU_SUPERMATRIX + +/******************************************** + * The matrix types are defined as follows. * + ********************************************/ +typedef enum { + SLU_NC, /* column-wise, no supernode */ + SLU_NR, /* row-wize, no supernode */ + SLU_SC, /* column-wise, supernode */ + SLU_SR, /* row-wise, supernode */ + SLU_NCP, /* column-wise, column-permuted, no supernode + (The consecutive columns of nonzeros, after permutation, + may not be stored contiguously.) */ + SLU_DN /* Fortran style column-wise storage for dense matrix */ +} Stype_t; + +typedef enum { + SLU_S, /* single */ + SLU_D, /* double */ + SLU_C, /* single complex */ + SLU_Z /* double complex */ +} Dtype_t; + +typedef enum { + SLU_GE, /* general */ + SLU_TRLU, /* lower triangular, unit diagonal */ + SLU_TRUU, /* upper triangular, unit diagonal */ + SLU_TRL, /* lower triangular */ + SLU_TRU, /* upper triangular */ + SLU_SYL, /* symmetric, store lower half */ + SLU_SYU, /* symmetric, store upper half */ + SLU_HEL, /* Hermitian, store lower half */ + SLU_HEU /* Hermitian, store upper half */ +} Mtype_t; + +typedef struct { + Stype_t Stype; /* Storage type: interprets the storage structure + pointed to by *Store. */ + Dtype_t Dtype; /* Data type. */ + Mtype_t Mtype; /* Matrix type: describes the mathematical property of + the matrix. */ + int_t nrow; /* number of rows */ + int_t ncol; /* number of columns */ + void *Store; /* pointer to the actual storage of the matrix */ +} SuperMatrix; + +/*********************************************** + * The storage schemes are defined as follows. * + ***********************************************/ + +/* Stype == NC (Also known as Harwell-Boeing sparse matrix format) */ +typedef struct { + int_t nnz; /* number of nonzeros in the matrix */ + void *nzval; /* pointer to array of nonzero values, packed by column */ + int_t *rowind; /* pointer to array of row indices of the nonzeros */ + int_t *colptr; /* pointer to array of beginning of columns in nzval[] + and rowind[] */ + /* Note: + Zero-based indexing is used; + colptr[] has ncol+1 entries, the last one pointing + beyond the last column, so that colptr[ncol] = nnz. */ +} NCformat; + +/* Stype == NR (Also known as row compressed storage (RCS). */ +typedef struct { + int_t nnz; /* number of nonzeros in the matrix */ + void *nzval; /* pointer to array of nonzero values, packed by row */ + int_t *colind; /* pointer to array of column indices of the nonzeros */ + int_t *rowptr; /* pointer to array of beginning of rows in nzval[] + and colind[] */ + /* Note: + Zero-based indexing is used; + nzval[] and colind[] are of the same length, nnz; + rowptr[] has nrow+1 entries, the last one pointing + beyond the last column, so that rowptr[nrow] = nnz. */ +} NRformat; + +/* Stype == SC */ +typedef struct { + int_t nnz; /* number of nonzeros in the matrix */ + int_t nsuper; /* number of supernodes, minus 1 */ + void *nzval; /* pointer to array of nonzero values, packed by column */ + int_t *nzval_colptr;/* pointer to array of beginning of columns in nzval[] */ + int_t *rowind; /* pointer to array of compressed row indices of + rectangular supernodes */ + int_t *rowind_colptr;/* pointer to array of beginning of columns in rowind[] */ + int_t *col_to_sup; /* col_to_sup[j] is the supernode number to which column + j belongs; mapping from column to supernode number. */ + int_t *sup_to_col; /* sup_to_col[s] points to the start of the s-th + supernode; mapping from supernode number to column. + e.g.: col_to_sup: 0 1 2 2 3 3 3 4 4 4 4 4 4 (ncol=12) + sup_to_col: 0 1 2 4 7 12 (nsuper=4) */ + /* Note: + Zero-based indexing is used; + nzval_colptr[], rowind_colptr[], col_to_sup and + sup_to_col[] have ncol+1 entries, the last one + pointing beyond the last column. + For col_to_sup[], only the first ncol entries are + defined. For sup_to_col[], only the first nsuper+2 + entries are defined. */ +} SCformat; + +/* Stype == NCP */ +typedef struct { + int_t nnz; /* number of nonzeros in the matrix */ + void *nzval; /* pointer to array of nonzero values, packed by column */ + int_t *rowind;/* pointer to array of row indices of the nonzeros */ + /* Note: nzval[]/rowind[] always have the same length */ + int_t *colbeg;/* colbeg[j] points to the beginning of column j in nzval[] + and rowind[] */ + int_t *colend;/* colend[j] points to one past the last element of column + j in nzval[] and rowind[] */ + /* Note: + Zero-based indexing is used; + The consecutive columns of the nonzeros may not be + contiguous in storage, because the matrix has been + postmultiplied by a column permutation matrix. */ +} NCPformat; + +/* Stype == DN */ +typedef struct { + int_t lda; /* leading dimension */ + void *nzval; /* array of size lda*ncol to represent a dense matrix */ +} DNformat; + + + +/********************************************************* + * Macros used for easy access of sparse matrix entries. * + *********************************************************/ +#define L_SUB_START(col) ( Lstore->rowind_colptr[col] ) +#define L_SUB(ptr) ( Lstore->rowind[ptr] ) +#define L_NZ_START(col) ( Lstore->nzval_colptr[col] ) +#define L_FST_SUPC(superno) ( Lstore->sup_to_col[superno] ) +#define U_NZ_START(col) ( Ustore->colptr[col] ) +#define U_SUB(ptr) ( Ustore->rowind[ptr] ) + + +#endif /* __SUPERLU_SUPERMATRIX */ diff --git a/intern/opennl/superlu/sutil.c b/intern/opennl/superlu/sutil.c new file mode 100644 index 00000000000..78f0b8bc5cc --- /dev/null +++ b/intern/opennl/superlu/sutil.c @@ -0,0 +1,486 @@ + +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include +#include "ssp_defs.h" + +/* prototypes */ +void sprint_lu_col(char *msg, int jcol, int pivrow, int *xprune, GlobalLU_t *Glu); +void scheck_tempv(int n, float *tempv); +void sPrintPerf(SuperMatrix *, SuperMatrix *, mem_usage_t *,float , float , + float *, float *, char *, SuperLUStat_t *); +int print_float_vec(char *what, int n, float *vec); +/* ********** */ + +void +sCreate_CompCol_Matrix(SuperMatrix *A, int m, int n, int nnz, + float *nzval, int *rowind, int *colptr, + Stype_t stype, Dtype_t dtype, Mtype_t mtype) +{ + NCformat *Astore; + + A->Stype = stype; + A->Dtype = dtype; + A->Mtype = mtype; + A->nrow = m; + A->ncol = n; + A->Store = (void *) SUPERLU_MALLOC( sizeof(NCformat) ); + if ( !(A->Store) ) ABORT("SUPERLU_MALLOC fails for A->Store"); + Astore = A->Store; + Astore->nnz = nnz; + Astore->nzval = nzval; + Astore->rowind = rowind; + Astore->colptr = colptr; +} + +void +sCreate_CompRow_Matrix(SuperMatrix *A, int m, int n, int nnz, + float *nzval, int *colind, int *rowptr, + Stype_t stype, Dtype_t dtype, Mtype_t mtype) +{ + NRformat *Astore; + + A->Stype = stype; + A->Dtype = dtype; + A->Mtype = mtype; + A->nrow = m; + A->ncol = n; + A->Store = (void *) SUPERLU_MALLOC( sizeof(NRformat) ); + if ( !(A->Store) ) ABORT("SUPERLU_MALLOC fails for A->Store"); + Astore = A->Store; + Astore->nnz = nnz; + Astore->nzval = nzval; + Astore->colind = colind; + Astore->rowptr = rowptr; +} + +/* Copy matrix A into matrix B. */ +void +sCopy_CompCol_Matrix(SuperMatrix *A, SuperMatrix *B) +{ + NCformat *Astore, *Bstore; + int ncol, nnz, i; + + B->Stype = A->Stype; + B->Dtype = A->Dtype; + B->Mtype = A->Mtype; + B->nrow = A->nrow;; + B->ncol = ncol = A->ncol; + Astore = (NCformat *) A->Store; + Bstore = (NCformat *) B->Store; + Bstore->nnz = nnz = Astore->nnz; + for (i = 0; i < nnz; ++i) + ((float *)Bstore->nzval)[i] = ((float *)Astore->nzval)[i]; + for (i = 0; i < nnz; ++i) Bstore->rowind[i] = Astore->rowind[i]; + for (i = 0; i <= ncol; ++i) Bstore->colptr[i] = Astore->colptr[i]; +} + + +void +sCreate_Dense_Matrix(SuperMatrix *X, int m, int n, float *x, int ldx, + Stype_t stype, Dtype_t dtype, Mtype_t mtype) +{ + DNformat *Xstore; + + X->Stype = stype; + X->Dtype = dtype; + X->Mtype = mtype; + X->nrow = m; + X->ncol = n; + X->Store = (void *) SUPERLU_MALLOC( sizeof(DNformat) ); + if ( !(X->Store) ) ABORT("SUPERLU_MALLOC fails for X->Store"); + Xstore = (DNformat *) X->Store; + Xstore->lda = ldx; + Xstore->nzval = (float *) x; +} + +void +sCopy_Dense_Matrix(int M, int N, float *X, int ldx, + float *Y, int ldy) +{ +/* + * + * Purpose + * ======= + * + * Copies a two-dimensional matrix X to another matrix Y. + */ + int i, j; + + for (j = 0; j < N; ++j) + for (i = 0; i < M; ++i) + Y[i + j*ldy] = X[i + j*ldx]; +} + +void +sCreate_SuperNode_Matrix(SuperMatrix *L, int m, int n, int nnz, + float *nzval, int *nzval_colptr, int *rowind, + int *rowind_colptr, int *col_to_sup, int *sup_to_col, + Stype_t stype, Dtype_t dtype, Mtype_t mtype) +{ + SCformat *Lstore; + + L->Stype = stype; + L->Dtype = dtype; + L->Mtype = mtype; + L->nrow = m; + L->ncol = n; + L->Store = (void *) SUPERLU_MALLOC( sizeof(SCformat) ); + if ( !(L->Store) ) ABORT("SUPERLU_MALLOC fails for L->Store"); + Lstore = L->Store; + Lstore->nnz = nnz; + Lstore->nsuper = col_to_sup[n]; + Lstore->nzval = nzval; + Lstore->nzval_colptr = nzval_colptr; + Lstore->rowind = rowind; + Lstore->rowind_colptr = rowind_colptr; + Lstore->col_to_sup = col_to_sup; + Lstore->sup_to_col = sup_to_col; + +} + + +/* + * Convert a row compressed storage into a column compressed storage. + */ +void +sCompRow_to_CompCol(int m, int n, int nnz, + float *a, int *colind, int *rowptr, + float **at, int **rowind, int **colptr) +{ + register int i, j, col, relpos; + int *marker; + + /* Allocate storage for another copy of the matrix. */ + *at = (float *) floatMalloc(nnz); + *rowind = (int *) intMalloc(nnz); + *colptr = (int *) intMalloc(n+1); + marker = (int *) intCalloc(n); + + /* Get counts of each column of A, and set up column pointers */ + for (i = 0; i < m; ++i) + for (j = rowptr[i]; j < rowptr[i+1]; ++j) ++marker[colind[j]]; + (*colptr)[0] = 0; + for (j = 0; j < n; ++j) { + (*colptr)[j+1] = (*colptr)[j] + marker[j]; + marker[j] = (*colptr)[j]; + } + + /* Transfer the matrix into the compressed column storage. */ + for (i = 0; i < m; ++i) { + for (j = rowptr[i]; j < rowptr[i+1]; ++j) { + col = colind[j]; + relpos = marker[col]; + (*rowind)[relpos] = i; + (*at)[relpos] = a[j]; + ++marker[col]; + } + } + + SUPERLU_FREE(marker); +} + + +void +sPrint_CompCol_Matrix(char *what, SuperMatrix *A) +{ + NCformat *Astore; + register int i,n; + float *dp; + + printf("\nCompCol matrix %s:\n", what); + printf("Stype %d, Dtype %d, Mtype %d\n", A->Stype,A->Dtype,A->Mtype); + n = A->ncol; + Astore = (NCformat *) A->Store; + dp = (float *) Astore->nzval; + printf("nrow %d, ncol %d, nnz %d\n", A->nrow,A->ncol,Astore->nnz); + printf("nzval: "); + for (i = 0; i < Astore->colptr[n]; ++i) printf("%f ", dp[i]); + printf("\nrowind: "); + for (i = 0; i < Astore->colptr[n]; ++i) printf("%d ", Astore->rowind[i]); + printf("\ncolptr: "); + for (i = 0; i <= n; ++i) printf("%d ", Astore->colptr[i]); + printf("\n"); + fflush(stdout); +} + +void +sPrint_SuperNode_Matrix(char *what, SuperMatrix *A) +{ + SCformat *Astore; + register int i, j, k, c, d, n, nsup; + float *dp; + int *col_to_sup, *sup_to_col, *rowind, *rowind_colptr; + + printf("\nSuperNode matrix %s:\n", what); + printf("Stype %d, Dtype %d, Mtype %d\n", A->Stype,A->Dtype,A->Mtype); + n = A->ncol; + Astore = (SCformat *) A->Store; + dp = (float *) Astore->nzval; + col_to_sup = Astore->col_to_sup; + sup_to_col = Astore->sup_to_col; + rowind_colptr = Astore->rowind_colptr; + rowind = Astore->rowind; + printf("nrow %d, ncol %d, nnz %d, nsuper %d\n", + A->nrow,A->ncol,Astore->nnz,Astore->nsuper); + printf("nzval:\n"); + for (k = 0; k <= Astore->nsuper; ++k) { + c = sup_to_col[k]; + nsup = sup_to_col[k+1] - c; + for (j = c; j < c + nsup; ++j) { + d = Astore->nzval_colptr[j]; + for (i = rowind_colptr[c]; i < rowind_colptr[c+1]; ++i) { + printf("%d\t%d\t%e\n", rowind[i], j, dp[d++]); + } + } + } +#if 0 + for (i = 0; i < Astore->nzval_colptr[n]; ++i) printf("%f ", dp[i]); +#endif + printf("\nnzval_colptr: "); + for (i = 0; i <= n; ++i) printf("%d ", Astore->nzval_colptr[i]); + printf("\nrowind: "); + for (i = 0; i < Astore->rowind_colptr[n]; ++i) + printf("%d ", Astore->rowind[i]); + printf("\nrowind_colptr: "); + for (i = 0; i <= n; ++i) printf("%d ", Astore->rowind_colptr[i]); + printf("\ncol_to_sup: "); + for (i = 0; i < n; ++i) printf("%d ", col_to_sup[i]); + printf("\nsup_to_col: "); + for (i = 0; i <= Astore->nsuper+1; ++i) + printf("%d ", sup_to_col[i]); + printf("\n"); + fflush(stdout); +} + +void +sPrint_Dense_Matrix(char *what, SuperMatrix *A) +{ + DNformat *Astore; + register int i; + float *dp; + + printf("\nDense matrix %s:\n", what); + printf("Stype %d, Dtype %d, Mtype %d\n", A->Stype,A->Dtype,A->Mtype); + Astore = (DNformat *) A->Store; + dp = (float *) Astore->nzval; + printf("nrow %d, ncol %d, lda %d\n", A->nrow,A->ncol,Astore->lda); + printf("\nnzval: "); + for (i = 0; i < A->nrow; ++i) printf("%f ", dp[i]); + printf("\n"); + fflush(stdout); +} + +/* + * Diagnostic print of column "jcol" in the U/L factor. + */ +void +sprint_lu_col(char *msg, int jcol, int pivrow, int *xprune, GlobalLU_t *Glu) +{ + int i, k, fsupc; + int *xsup, *supno; + int *xlsub, *lsub; + float *lusup; + int *xlusup; + float *ucol; + int *usub, *xusub; + + xsup = Glu->xsup; + supno = Glu->supno; + lsub = Glu->lsub; + xlsub = Glu->xlsub; + lusup = Glu->lusup; + xlusup = Glu->xlusup; + ucol = Glu->ucol; + usub = Glu->usub; + xusub = Glu->xusub; + + printf("%s", msg); + printf("col %d: pivrow %d, supno %d, xprune %d\n", + jcol, pivrow, supno[jcol], xprune[jcol]); + + printf("\tU-col:\n"); + for (i = xusub[jcol]; i < xusub[jcol+1]; i++) + printf("\t%d%10.4f\n", usub[i], ucol[i]); + printf("\tL-col in rectangular snode:\n"); + fsupc = xsup[supno[jcol]]; /* first col of the snode */ + i = xlsub[fsupc]; + k = xlusup[jcol]; + while ( i < xlsub[fsupc+1] && k < xlusup[jcol+1] ) { + printf("\t%d\t%10.4f\n", lsub[i], lusup[k]); + i++; k++; + } + fflush(stdout); +} + + +/* + * Check whether tempv[] == 0. This should be true before and after + * calling any numeric routines, i.e., "panel_bmod" and "column_bmod". + */ +void scheck_tempv(int n, float *tempv) +{ + int i; + + for (i = 0; i < n; i++) { + if (tempv[i] != 0.0) + { + fprintf(stderr,"tempv[%d] = %f\n", i,tempv[i]); + ABORT("scheck_tempv"); + } + } +} + + +void +sGenXtrue(int n, int nrhs, float *x, int ldx) +{ + int i, j; + for (j = 0; j < nrhs; ++j) + for (i = 0; i < n; ++i) { + x[i + j*ldx] = 1.0;/* + (float)(i+1.)/n;*/ + } +} + +/* + * Let rhs[i] = sum of i-th row of A, so the solution vector is all 1's + */ +void +sFillRHS(trans_t trans, int nrhs, float *x, int ldx, + SuperMatrix *A, SuperMatrix *B) +{ + NCformat *Astore; + float *Aval; + DNformat *Bstore; + float *rhs; + float one = 1.0; + float zero = 0.0; + int ldc; + char transc[1]; + + Astore = A->Store; + Aval = (float *) Astore->nzval; + Bstore = B->Store; + rhs = Bstore->nzval; + ldc = Bstore->lda; + + if ( trans == NOTRANS ) *(unsigned char *)transc = 'N'; + else *(unsigned char *)transc = 'T'; + + sp_sgemm(transc, nrhs, one, A, + x, ldx, zero, rhs, ldc); + +} + +/* + * Fills a float precision array with a given value. + */ +void +sfill(float *a, int alen, float dval) +{ + register int i; + for (i = 0; i < alen; i++) a[i] = dval; +} + + + +/* + * Check the inf-norm of the error vector + */ +void sinf_norm_error(int nrhs, SuperMatrix *X, float *xtrue) +{ + DNformat *Xstore; + float err, xnorm; + float *Xmat, *soln_work; + int i, j; + + Xstore = X->Store; + Xmat = Xstore->nzval; + + for (j = 0; j < nrhs; j++) { + soln_work = &Xmat[j*Xstore->lda]; + err = xnorm = 0.0; + for (i = 0; i < X->nrow; i++) { + err = SUPERLU_MAX(err, fabs(soln_work[i] - xtrue[i])); + xnorm = SUPERLU_MAX(xnorm, fabs(soln_work[i])); + } + err = err / xnorm; + printf("||X - Xtrue||/||X|| = %e\n", err); + } +} + + + +/* Print performance of the code. */ +void +sPrintPerf(SuperMatrix *L, SuperMatrix *U, mem_usage_t *mem_usage, + float rpg, float rcond, float *ferr, + float *berr, char *equed, SuperLUStat_t *stat) +{ + SCformat *Lstore; + NCformat *Ustore; + double *utime; + flops_t *ops; + + utime = stat->utime; + ops = stat->ops; + + if ( utime[FACT] != 0. ) + printf("Factor flops = %e\tMflops = %8.2f\n", ops[FACT], + ops[FACT]*1e-6/utime[FACT]); + printf("Identify relaxed snodes = %8.2f\n", utime[RELAX]); + if ( utime[SOLVE] != 0. ) + printf("Solve flops = %.0f, Mflops = %8.2f\n", ops[SOLVE], + ops[SOLVE]*1e-6/utime[SOLVE]); + + Lstore = (SCformat *) L->Store; + Ustore = (NCformat *) U->Store; + printf("\tNo of nonzeros in factor L = %d\n", Lstore->nnz); + printf("\tNo of nonzeros in factor U = %d\n", Ustore->nnz); + printf("\tNo of nonzeros in L+U = %d\n", Lstore->nnz + Ustore->nnz); + + printf("L\\U MB %.3f\ttotal MB needed %.3f\texpansions %d\n", + mem_usage->for_lu/1e6, mem_usage->total_needed/1e6, + mem_usage->expansions); + + printf("\tFactor\tMflops\tSolve\tMflops\tEtree\tEquil\tRcond\tRefine\n"); + printf("PERF:%8.2f%8.2f%8.2f%8.2f%8.2f%8.2f%8.2f%8.2f\n", + utime[FACT], ops[FACT]*1e-6/utime[FACT], + utime[SOLVE], ops[SOLVE]*1e-6/utime[SOLVE], + utime[ETREE], utime[EQUIL], utime[RCOND], utime[REFINE]); + + printf("\tRpg\t\tRcond\t\tFerr\t\tBerr\t\tEquil?\n"); + printf("NUM:\t%e\t%e\t%e\t%e\t%s\n", + rpg, rcond, ferr[0], berr[0], equed); + +} + + + + +int print_float_vec(char *what, int n, float *vec) +{ + int i; + printf("%s: n %d\n", what, n); + for (i = 0; i < n; ++i) printf("%d\t%f\n", i, vec[i]); + return 0; +} + diff --git a/intern/opennl/superlu/util.c b/intern/opennl/superlu/util.c new file mode 100644 index 00000000000..824cabacee5 --- /dev/null +++ b/intern/opennl/superlu/util.c @@ -0,0 +1,397 @@ +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include +#include "ssp_defs.h" +#include "util.h" + +/* prototypes */ +flops_t LUFactFlops(SuperLUStat_t *stat); +flops_t LUSolveFlops(SuperLUStat_t *stat); +float SpaSize(int n, int np, float sum_npw); +float DenseSize(int n, float sum_nw); + +/* + * Global statistics variale + */ + +void superlu_abort_and_exit(char* msg) +{ + fprintf(stderr, msg); + exit (-1); +} + +/* + * Set the default values for the options argument. + */ +void set_default_options(superlu_options_t *options) +{ + options->Fact = DOFACT; + options->Equil = YES; + options->ColPerm = COLAMD; + options->DiagPivotThresh = 1.0; + options->Trans = NOTRANS; + options->IterRefine = NOREFINE; + options->SymmetricMode = NO; + options->PivotGrowth = NO; + options->ConditionNumber = NO; + options->PrintStat = YES; +} + +/* Deallocate the structure pointing to the actual storage of the matrix. */ +void +Destroy_SuperMatrix_Store(SuperMatrix *A) +{ + SUPERLU_FREE ( A->Store ); +} + +void +Destroy_CompCol_Matrix(SuperMatrix *A) +{ + SUPERLU_FREE( ((NCformat *)A->Store)->rowind ); + SUPERLU_FREE( ((NCformat *)A->Store)->colptr ); + SUPERLU_FREE( ((NCformat *)A->Store)->nzval ); + SUPERLU_FREE( A->Store ); +} + +void +Destroy_CompRow_Matrix(SuperMatrix *A) +{ + SUPERLU_FREE( ((NRformat *)A->Store)->colind ); + SUPERLU_FREE( ((NRformat *)A->Store)->rowptr ); + SUPERLU_FREE( ((NRformat *)A->Store)->nzval ); + SUPERLU_FREE( A->Store ); +} + +void +Destroy_SuperNode_Matrix(SuperMatrix *A) +{ + SUPERLU_FREE ( ((SCformat *)A->Store)->rowind ); + SUPERLU_FREE ( ((SCformat *)A->Store)->rowind_colptr ); + SUPERLU_FREE ( ((SCformat *)A->Store)->nzval ); + SUPERLU_FREE ( ((SCformat *)A->Store)->nzval_colptr ); + SUPERLU_FREE ( ((SCformat *)A->Store)->col_to_sup ); + SUPERLU_FREE ( ((SCformat *)A->Store)->sup_to_col ); + SUPERLU_FREE ( A->Store ); +} + +/* A is of type Stype==NCP */ +void +Destroy_CompCol_Permuted(SuperMatrix *A) +{ + SUPERLU_FREE ( ((NCPformat *)A->Store)->colbeg ); + SUPERLU_FREE ( ((NCPformat *)A->Store)->colend ); + SUPERLU_FREE ( A->Store ); +} + +/* A is of type Stype==DN */ +void +Destroy_Dense_Matrix(SuperMatrix *A) +{ + DNformat* Astore = A->Store; + SUPERLU_FREE (Astore->nzval); + SUPERLU_FREE ( A->Store ); +} + +/* + * Reset repfnz[] for the current column + */ +void +resetrep_col (const int nseg, const int *segrep, int *repfnz) +{ + int i, irep; + + for (i = 0; i < nseg; i++) { + irep = segrep[i]; + repfnz[irep] = EMPTY; + } +} + + +/* + * Count the total number of nonzeros in factors L and U, and in the + * symmetrically reduced L. + */ +void +countnz(const int n, int *xprune, int *nnzL, int *nnzU, GlobalLU_t *Glu) +{ + int nsuper, fsupc, i, j; + int nnzL0, jlen, irep; + int *xsup, *xlsub; + + xsup = Glu->xsup; + xlsub = Glu->xlsub; + *nnzL = 0; + *nnzU = (Glu->xusub)[n]; + nnzL0 = 0; + nsuper = (Glu->supno)[n]; + + if ( n <= 0 ) return; + + /* + * For each supernode + */ + for (i = 0; i <= nsuper; i++) { + fsupc = xsup[i]; + jlen = xlsub[fsupc+1] - xlsub[fsupc]; + + for (j = fsupc; j < xsup[i+1]; j++) { + *nnzL += jlen; + *nnzU += j - fsupc + 1; + jlen--; + } + irep = xsup[i+1] - 1; + nnzL0 += xprune[irep] - xlsub[irep]; + } + + /* printf("\tNo of nonzeros in symm-reduced L = %d\n", nnzL0);*/ +} + + + +/* + * Fix up the data storage lsub for L-subscripts. It removes the subscript + * sets for structural pruning, and applies permuation to the remaining + * subscripts. + */ +void +fixupL(const int n, const int *perm_r, GlobalLU_t *Glu) +{ + register int nsuper, fsupc, nextl, i, j, k, jstrt; + int *xsup, *lsub, *xlsub; + + if ( n <= 1 ) return; + + xsup = Glu->xsup; + lsub = Glu->lsub; + xlsub = Glu->xlsub; + nextl = 0; + nsuper = (Glu->supno)[n]; + + /* + * For each supernode ... + */ + for (i = 0; i <= nsuper; i++) { + fsupc = xsup[i]; + jstrt = xlsub[fsupc]; + xlsub[fsupc] = nextl; + for (j = jstrt; j < xlsub[fsupc+1]; j++) { + lsub[nextl] = perm_r[lsub[j]]; /* Now indexed into P*A */ + nextl++; + } + for (k = fsupc+1; k < xsup[i+1]; k++) + xlsub[k] = nextl; /* Other columns in supernode i */ + + } + + xlsub[n] = nextl; +} + + +/* + * Diagnostic print of segment info after panel_dfs(). + */ +void print_panel_seg(int n, int w, int jcol, int nseg, + int *segrep, int *repfnz) +{ + int j, k; + + for (j = jcol; j < jcol+w; j++) { + printf("\tcol %d:\n", j); + for (k = 0; k < nseg; k++) + printf("\t\tseg %d, segrep %d, repfnz %d\n", k, + segrep[k], repfnz[(j-jcol)*n + segrep[k]]); + } + +} + + +void +StatInit(SuperLUStat_t *stat) +{ + register int i, w, panel_size, relax; + + panel_size = sp_ienv(1); + relax = sp_ienv(2); + w = SUPERLU_MAX(panel_size, relax); + stat->panel_histo = intCalloc(w+1); + stat->utime = (double *) SUPERLU_MALLOC(NPHASES * sizeof(double)); + if (!stat->utime) ABORT("SUPERLU_MALLOC fails for stat->utime"); + stat->ops = (flops_t *) SUPERLU_MALLOC(NPHASES * sizeof(flops_t)); + if (!stat->ops) ABORT("SUPERLU_MALLOC fails for stat->ops"); + for (i = 0; i < NPHASES; ++i) { + stat->utime[i] = 0.; + stat->ops[i] = 0.; + } +} + + +void +StatPrint(SuperLUStat_t *stat) +{ + double *utime; + flops_t *ops; + + utime = stat->utime; + ops = stat->ops; + printf("Factor time = %8.2f\n", utime[FACT]); + if ( utime[FACT] != 0.0 ) + printf("Factor flops = %e\tMflops = %8.2f\n", ops[FACT], + ops[FACT]*1e-6/utime[FACT]); + + printf("Solve time = %8.2f\n", utime[SOLVE]); + if ( utime[SOLVE] != 0.0 ) + printf("Solve flops = %e\tMflops = %8.2f\n", ops[SOLVE], + ops[SOLVE]*1e-6/utime[SOLVE]); + +} + + +void +StatFree(SuperLUStat_t *stat) +{ + SUPERLU_FREE(stat->panel_histo); + SUPERLU_FREE(stat->utime); + SUPERLU_FREE(stat->ops); +} + + +flops_t +LUFactFlops(SuperLUStat_t *stat) +{ + return (stat->ops[FACT]); +} + +flops_t +LUSolveFlops(SuperLUStat_t *stat) +{ + return (stat->ops[SOLVE]); +} + + + + + +/* + * Fills an integer array with a given value. + */ +void ifill(int *a, int alen, int ival) +{ + register int i; + for (i = 0; i < alen; i++) a[i] = ival; +} + + + +/* + * Get the statistics of the supernodes + */ +#define NBUCKS 10 +static int max_sup_size; + +void super_stats(int nsuper, int *xsup) +{ + register int nsup1 = 0; + int i, isize, whichb, bl, bh; + int bucket[NBUCKS]; + + max_sup_size = 0; + + for (i = 0; i <= nsuper; i++) { + isize = xsup[i+1] - xsup[i]; + if ( isize == 1 ) nsup1++; + if ( max_sup_size < isize ) max_sup_size = isize; + } + + printf(" Supernode statistics:\n\tno of super = %d\n", nsuper+1); + printf("\tmax supernode size = %d\n", max_sup_size); + printf("\tno of size 1 supernodes = %d\n", nsup1); + + /* Histogram of the supernode sizes */ + ifill (bucket, NBUCKS, 0); + + for (i = 0; i <= nsuper; i++) { + isize = xsup[i+1] - xsup[i]; + whichb = (float) isize / max_sup_size * NBUCKS; + if (whichb >= NBUCKS) whichb = NBUCKS - 1; + bucket[whichb]++; + } + + printf("\tHistogram of supernode sizes:\n"); + for (i = 0; i < NBUCKS; i++) { + bl = (float) i * max_sup_size / NBUCKS; + bh = (float) (i+1) * max_sup_size / NBUCKS; + printf("\tsnode: %d-%d\t\t%d\n", bl+1, bh, bucket[i]); + } + +} + + +float SpaSize(int n, int np, float sum_npw) +{ + return (sum_npw*8 + np*8 + n*4)/1024.; +} + +float DenseSize(int n, float sum_nw) +{ + return (sum_nw*8 + n*8)/1024.;; +} + + + +/* + * Check whether repfnz[] == EMPTY after reset. + */ +void check_repfnz(int n, int w, int jcol, int *repfnz) +{ + int jj, k; + + for (jj = jcol; jj < jcol+w; jj++) + for (k = 0; k < n; k++) + if ( repfnz[(jj-jcol)*n + k] != EMPTY ) { + fprintf(stderr, "col %d, repfnz_col[%d] = %d\n", jj, + k, repfnz[(jj-jcol)*n + k]); + ABORT("check_repfnz"); + } +} + + +/* Print a summary of the testing results. */ +void +PrintSumm(char *type, int nfail, int nrun, int nerrs) +{ + if ( nfail > 0 ) + printf("%3s driver: %d out of %d tests failed to pass the threshold\n", + type, nfail, nrun); + else + printf("All tests for %3s driver passed the threshold (%6d tests run)\n", type, nrun); + + if ( nerrs > 0 ) + printf("%6d error messages recorded\n", nerrs); +} + + +int print_int_vec(char *what, int n, int *vec) +{ + int i; + printf("%s\n", what); + for (i = 0; i < n; ++i) printf("%d\t%d\n", i, vec[i]); + return 0; +} diff --git a/intern/opennl/superlu/util.h b/intern/opennl/superlu/util.h new file mode 100644 index 00000000000..1a3526d4e7e --- /dev/null +++ b/intern/opennl/superlu/util.h @@ -0,0 +1,267 @@ +#ifndef __SUPERLU_UTIL /* allow multiple inclusions */ +#define __SUPERLU_UTIL + +#include +#include +#include +/* +#ifndef __STDC__ +#include +#endif +*/ +#include + +/*********************************************************************** + * Macros + ***********************************************************************/ +#define FIRSTCOL_OF_SNODE(i) (xsup[i]) +/* No of marker arrays used in the symbolic factorization, + each of size n */ +#define NO_MARKER 3 +#define NUM_TEMPV(m,w,t,b) ( SUPERLU_MAX(m, (t + b)*w) ) + +#ifndef USER_ABORT +#define USER_ABORT(msg) superlu_abort_and_exit(msg) +#endif + +#define ABORT(err_msg) \ + { char msg[256];\ + sprintf(msg,"%s at line %d in file %s\n",err_msg,__LINE__, __FILE__);\ + USER_ABORT(msg); } + + +#ifndef USER_MALLOC +#if 1 +#define USER_MALLOC(size) superlu_malloc(size) +#else +/* The following may check out some uninitialized data */ +#define USER_MALLOC(size) memset (superlu_malloc(size), '\x0F', size) +#endif +#endif + +#define SUPERLU_MALLOC(size) USER_MALLOC(size) + +#ifndef USER_FREE +#define USER_FREE(addr) superlu_free(addr) +#endif + +#define SUPERLU_FREE(addr) USER_FREE(addr) + +#define CHECK_MALLOC(where) { \ + extern int superlu_malloc_total; \ + printf("%s: malloc_total %d Bytes\n", \ + where, superlu_malloc_total); \ +} + +#define SUPERLU_MAX(x, y) ( (x) > (y) ? (x) : (y) ) +#define SUPERLU_MIN(x, y) ( (x) < (y) ? (x) : (y) ) + +/*********************************************************************** + * Constants + ***********************************************************************/ +#define EMPTY (-1) +/*#define NO (-1)*/ +#define FALSE 0 +#define TRUE 1 + +/*********************************************************************** + * Enumerate types + ***********************************************************************/ +typedef enum {NO, YES} yes_no_t; +typedef enum {DOFACT, SamePattern, SamePattern_SameRowPerm, FACTORED} fact_t; +typedef enum {NOROWPERM, LargeDiag, MY_PERMR} rowperm_t; +typedef enum {NATURAL, MMD_ATA, MMD_AT_PLUS_A, COLAMD, MY_PERMC}colperm_t; +typedef enum {NOTRANS, TRANS, CONJ} trans_t; +typedef enum {NOEQUIL, ROW, COL, BOTH} DiagScale_t; +typedef enum {NOREFINE, SINGLE=1, SLU_DOUBLE, EXTRA} IterRefine_t; +typedef enum {LUSUP, UCOL, LSUB, USUB} MemType; +typedef enum {HEAD, TAIL} stack_end_t; +typedef enum {SYSTEM, USER} LU_space_t; + +/* + * The following enumerate type is used by the statistics variable + * to keep track of flop count and time spent at various stages. + * + * Note that not all of the fields are disjoint. + */ +typedef enum { + COLPERM, /* find a column ordering that minimizes fills */ + RELAX, /* find artificial supernodes */ + ETREE, /* compute column etree */ + EQUIL, /* equilibrate the original matrix */ + FACT, /* perform LU factorization */ + RCOND, /* estimate reciprocal condition number */ + SOLVE, /* forward and back solves */ + REFINE, /* perform iterative refinement */ + SLU_FLOAT, /* time spent in floating-point operations */ + TRSV, /* fraction of FACT spent in xTRSV */ + GEMV, /* fraction of FACT spent in xGEMV */ + FERR, /* estimate error bounds after iterative refinement */ + NPHASES /* total number of phases */ +} PhaseType; + + +/*********************************************************************** + * Type definitions + ***********************************************************************/ +typedef float flops_t; +typedef unsigned char Logical; + +/* + *-- This contains the options used to control the solve process. + * + * Fact (fact_t) + * Specifies whether or not the factored form of the matrix + * A is supplied on entry, and if not, how the matrix A should + * be factorizaed. + * = DOFACT: The matrix A will be factorized from scratch, and the + * factors will be stored in L and U. + * = SamePattern: The matrix A will be factorized assuming + * that a factorization of a matrix with the same sparsity + * pattern was performed prior to this one. Therefore, this + * factorization will reuse column permutation vector + * ScalePermstruct->perm_c and the column elimination tree + * LUstruct->etree. + * = SamePattern_SameRowPerm: The matrix A will be factorized + * assuming that a factorization of a matrix with the same + * sparsity pattern and similar numerical values was performed + * prior to this one. Therefore, this factorization will reuse + * both row and column scaling factors R and C, and the + * both row and column permutation vectors perm_r and perm_c, + * distributed data structure set up from the previous symbolic + * factorization. + * = FACTORED: On entry, L, U, perm_r and perm_c contain the + * factored form of A. If DiagScale is not NOEQUIL, the matrix + * A has been equilibrated with scaling factors R and C. + * + * Equil (yes_no_t) + * Specifies whether to equilibrate the system (scale A's row and + * columns to have unit norm). + * + * ColPerm (colperm_t) + * Specifies what type of column permutation to use to reduce fill. + * = NATURAL: use the natural ordering + * = MMD_ATA: use minimum degree ordering on structure of A'*A + * = MMD_AT_PLUS_A: use minimum degree ordering on structure of A'+A + * = COLAMD: use approximate minimum degree column ordering + * = MY_PERMC: use the ordering specified in ScalePermstruct->perm_c[] + * + * Trans (trans_t) + * Specifies the form of the system of equations: + * = NOTRANS: A * X = B (No transpose) + * = TRANS: A**T * X = B (Transpose) + * = CONJ: A**H * X = B (Transpose) + * + * IterRefine (IterRefine_t) + * Specifies whether to perform iterative refinement. + * = NO: no iterative refinement + * = WorkingPrec: perform iterative refinement in working precision + * = ExtraPrec: perform iterative refinement in extra precision + * + * PrintStat (yes_no_t) + * Specifies whether to print the solver's statistics. + * + * DiagPivotThresh (double, in [0.0, 1.0]) (only for sequential SuperLU) + * Specifies the threshold used for a diagonal entry to be an + * acceptable pivot. + * + * PivotGrowth (yes_no_t) + * Specifies whether to compute the reciprocal pivot growth. + * + * ConditionNumber (ues_no_t) + * Specifies whether to compute the reciprocal condition number. + * + * RowPerm (rowperm_t) (only for SuperLU_DIST) + * Specifies whether to permute rows of the original matrix. + * = NO: not to permute the rows + * = LargeDiag: make the diagonal large relative to the off-diagonal + * = MY_PERMR: use the permutation given in ScalePermstruct->perm_r[] + * + * ReplaceTinyPivot (yes_no_t) (only for SuperLU_DIST) + * Specifies whether to replace the tiny diagonals by + * sqrt(epsilon)*||A|| during LU factorization. + * + * SolveInitialized (yes_no_t) (only for SuperLU_DIST) + * Specifies whether the initialization has been performed to the + * triangular solve. + * + * RefineInitialized (yes_no_t) (only for SuperLU_DIST) + * Specifies whether the initialization has been performed to the + * sparse matrix-vector multiplication routine needed in iterative + * refinement. + */ +typedef struct { + fact_t Fact; + yes_no_t Equil; + colperm_t ColPerm; + trans_t Trans; + IterRefine_t IterRefine; + yes_no_t PrintStat; + yes_no_t SymmetricMode; + double DiagPivotThresh; + yes_no_t PivotGrowth; + yes_no_t ConditionNumber; + rowperm_t RowPerm; + yes_no_t ReplaceTinyPivot; + yes_no_t SolveInitialized; + yes_no_t RefineInitialized; +} superlu_options_t; + +typedef struct { + int *panel_histo; /* histogram of panel size distribution */ + double *utime; /* running time at various phases */ + flops_t *ops; /* operation count at various phases */ + int TinyPivots; /* number of tiny pivots */ + int RefineSteps; /* number of iterative refinement steps */ +} SuperLUStat_t; + + +/*********************************************************************** + * Prototypes + ***********************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +extern void Destroy_SuperMatrix_Store(SuperMatrix *); +extern void Destroy_CompCol_Matrix(SuperMatrix *); +extern void Destroy_CompRow_Matrix(SuperMatrix *); +extern void Destroy_SuperNode_Matrix(SuperMatrix *); +extern void Destroy_CompCol_Permuted(SuperMatrix *); +extern void Destroy_Dense_Matrix(SuperMatrix *); +extern void get_perm_c(int, SuperMatrix *, int *); +extern void set_default_options(superlu_options_t *options); +extern void sp_preorder (superlu_options_t *, SuperMatrix*, int*, int*, + SuperMatrix*); +extern void superlu_abort_and_exit(char*); +extern void *superlu_malloc (size_t); +extern int *intMalloc (int); +extern int *intCalloc (int); +extern void superlu_free (void*); +extern void SetIWork (int, int, int, int *, int **, int **, int **, + int **, int **, int **, int **); +extern int sp_coletree (int *, int *, int *, int, int, int *); +extern void relax_snode (const int, int *, const int, int *, int *); +extern void heap_relax_snode (const int, int *, const int, int *, int *); +extern void resetrep_col (const int, const int *, int *); +extern int spcoletree (int *, int *, int *, int, int, int *); +extern int *TreePostorder (int, int *); +extern double SuperLU_timer_ (); +extern int sp_ienv (int); +extern int lsame_ (char *, char *); +extern int xerbla_ (char *, int *); +extern void ifill (int *, int, int); +extern void snode_profile (int, int *); +extern void super_stats (int, int *); +extern void PrintSumm (char *, int, int, int); +extern void StatInit(SuperLUStat_t *); +extern void StatPrint (SuperLUStat_t *); +extern void StatFree(SuperLUStat_t *); +extern void print_panel_seg(int, int, int, int, int *, int *); +extern void check_repfnz(int, int, int, int *); + +#ifdef __cplusplus + } +#endif + +#endif /* __SUPERLU_UTIL */ diff --git a/intern/opennl/superlu/xerbla.c b/intern/opennl/superlu/xerbla.c new file mode 100644 index 00000000000..68cef9d84e4 --- /dev/null +++ b/intern/opennl/superlu/xerbla.c @@ -0,0 +1,44 @@ + +#include +int xerbla_(char *, int *); + +/* Subroutine */ int xerbla_(char *srname, int *info) +{ +/* -- LAPACK auxiliary routine (version 2.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994 + + + Purpose + ======= + + XERBLA is an error handler for the LAPACK routines. + It is called by an LAPACK routine if an input parameter has an + invalid value. A message is printed and execution stops. + + Installers may consider modifying the STOP statement in order to + call system-specific exception-handling facilities. + + Arguments + ========= + + SRNAME (input) CHARACTER*6 + The name of the routine which called XERBLA. + + INFO (input) INT + The position of the invalid parameter in the parameter list + + of the calling routine. + + ===================================================================== +*/ + + printf("** On entry to %6s, parameter number %2d had an illegal value\n", + srname, *info); + +/* End of XERBLA */ + + return 0; +} /* xerbla_ */ + diff --git a/intern/string/CMakeLists.txt b/intern/string/CMakeLists.txt new file mode 100644 index 00000000000..bee946d3c15 --- /dev/null +++ b/intern/string/CMakeLists.txt @@ -0,0 +1,35 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC .) + +FILE(GLOB SRC intern/*.cpp) + +BLENDERLIB(bf_string "${SRC}" "${INC}") +#, libtype=['core', 'player'], priority = [30,10] ) diff --git a/intern/string/Makefile b/intern/string/Makefile new file mode 100644 index 00000000000..e3dffbe9e44 --- /dev/null +++ b/intern/string/Makefile @@ -0,0 +1,56 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# string main makefile. +# + +include nan_definitions.mk + +LIBNAME = string +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +# not yet TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_STRING) ] || mkdir $(NAN_STRING) + @[ -d $(NAN_STRING)/include ] || mkdir $(NAN_STRING)/include + @[ -d $(NAN_STRING)/lib ] || mkdir $(NAN_STRING)/lib + @[ -d $(NAN_STRING)/lib/debug ] || mkdir $(NAN_STRING)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libstring.a $(NAN_STRING)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libstring.a $(NAN_STRING)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_STRING)/lib/libstring.a + ranlib $(NAN_STRING)/lib/debug/libstring.a +endif + @../tools/cpifdiff.sh *.h $(NAN_STRING)/include/ + diff --git a/intern/string/SConscript b/intern/string/SConscript new file mode 100644 index 00000000000..7f817f82759 --- /dev/null +++ b/intern/string/SConscript @@ -0,0 +1,7 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.cpp') +incs = '.' + +env.BlenderLib ('bf_string', sources, Split(incs), [], libtype=['core', 'player'], priority = [30,10] ) diff --git a/intern/string/STR_HashedString.h b/intern/string/STR_HashedString.h new file mode 100644 index 00000000000..bf18a4e4da6 --- /dev/null +++ b/intern/string/STR_HashedString.h @@ -0,0 +1,154 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * This file was formerly known as: GEN_StdString.cpp. + * @date November, 14, 2001 + */ + +#ifndef __STR_HASHSTRING +#define __STR_HASHSTRING + +#include "STR_String.h" + + +// Hash Mix utility function, by Bob Jenkins - Mix 3 32-bit values reversibly +// +// - If gHashMix() is run forward or backward, at least 32 bits in a,b,c have at +// least 1/4 probability of changing. +// +// - If gHashMix() is run forward, every bit of c will change between 1/3 and +// 2/3 of the time. +// +static inline void STR_gHashMix(dword& a, dword& b, dword& c) +{ + a -= b; a -= c; a ^= (c>>13); + b -= c; b -= a; b ^= (a<<8); + c -= a; c -= b; c ^= (b>>13); + a -= b; a -= c; a ^= (c>>12); + b -= c; b -= a; b ^= (a<<16); + c -= a; c -= b; c ^= (b>>5); + a -= b; a -= c; a ^= (c>>3); + b -= c; b -= a; b ^= (a<<10); + c -= a; c -= b; c ^= (b>>15); +} + +// +// Fast Hashable functionality +// http://www.concentric.net/~Ttwang/tech/inthash.htm +// +static inline dword STR_gHash(dword inDWord) +{ + dword key = inDWord; + key += ~(key << 16); + key ^= (key >> 5); + key += (key << 3); + key ^= (key >> 13); + key += ~(key << 9); + key ^= (key >> 17); + return key; +} + +enum { GOLDEN_RATIO = 0x9e3779b9 }; // arbitrary value to initialize hash funtion, well not so arbitrary + // as this value is taken from the pigs library (Orange Games/Lost Boys) + + + +static dword STR_gHash(const void* in, int len, dword init_val) +{ + unsigned int length = len; + dword a = (dword)GOLDEN_RATIO; + dword b = (dword)GOLDEN_RATIO; + dword c = init_val; // the previous hash value + byte *p_in = (byte *)in; + + // Do the largest part of the key + while (length >= 12) + { + a += (p_in[0] + ((dword)p_in[1]<<8) + ((dword)p_in[2] <<16) + ((dword)p_in[3] <<24)); + b += (p_in[4] + ((dword)p_in[5]<<8) + ((dword)p_in[6] <<16) + ((dword)p_in[7] <<24)); + c += (p_in[8] + ((dword)p_in[9]<<8) + ((dword)p_in[10]<<16) + ((dword)p_in[11]<<24)); + STR_gHashMix(a, b, c); + p_in += 12; length -= 12; + } + + // Handle the last 11 bytes + c += len; + switch(length) { + case 11: c+=((dword)p_in[10]<<24); + case 10: c+=((dword)p_in[9]<<16); + case 9 : c+=((dword)p_in[8]<<8); // the first byte of c is reserved for the length + case 8 : b+=((dword)p_in[7]<<24); + case 7 : b+=((dword)p_in[6]<<16); + case 6 : b+=((dword)p_in[5]<<8); + case 5 : b+=p_in[4]; + case 4 : a+=((dword)p_in[3]<<24); + case 3 : a+=((dword)p_in[2]<<16); + case 2 : a+=((dword)p_in[1]<<8); + case 1 : a+=p_in[0]; + } + STR_gHashMix(a, b, c); + + return c; +} + + + + +class STR_HashedString : public STR_String +{ +public: + STR_HashedString() : STR_String(),m_Hashed(false) {} + STR_HashedString(const char* str) : STR_String(str),m_Hashed(false) {} + STR_HashedString(const STR_String& str) : STR_String(str),m_Hashed(false) {} + + inline dword hash(dword init=0) const + { + if (!m_Hashed) + { + const char* str = *this; + int length = this->Length(); + m_CachedHash = STR_gHash(str,length,init); + m_Hashed=true; + } + return m_CachedHash; + } + +private: + mutable bool m_Hashed; + mutable dword m_CachedHash; +}; + +#endif //__STR_HASHSTRING + diff --git a/intern/string/STR_String.h b/intern/string/STR_String.h new file mode 100644 index 00000000000..2da2b57c6f2 --- /dev/null +++ b/intern/string/STR_String.h @@ -0,0 +1,203 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * This file was formerly known as: GEN_StdString.h. + * @date April, 25, 2001 + */ + +#ifndef _STR_String_H_ +#define _STR_String_H_ + +#ifndef STR_NO_ASSERTD +#undef assertd +#define assertd(exp) ((void)NULL) +#endif + +#include +#include +using namespace std; + + +class STR_String; + +typedef unsigned long dword; +typedef const STR_String& rcSTR_String; +typedef unsigned char byte; + +/** + * Smart String Value class. Is used by parser when an expression tree is build containing string. +*/ + +class STR_String +{ +public: + // Initialization + STR_String(); + STR_String(char c); + STR_String(char c, int len); + STR_String(const char *str); + STR_String(const char *str, int len); + STR_String(const STR_String &str); + STR_String(const STR_String & str, int len); + STR_String(const char *src1, int src1_len, const char *src2, int src2_len); + explicit STR_String(int val); + explicit STR_String(dword val); + explicit STR_String(float val); + explicit STR_String(double val); + inline ~STR_String() { delete[] pData; } + + // Operations + STR_String& Format(const char *fmt, ...); // Set formatted text to string + STR_String& FormatAdd(const char *fmt, ...); // Add formatted text to string + inline void Clear() { Len = pData[0] = 0; } + inline const STR_String & Reverse() + { + for (int i1=0, i2=Len-1; i1 Explode(char c) const; + + // Formatting + STR_String& Upper(); + STR_String& Lower(); + STR_String& Capitalize(); + STR_String& TrimLeft(); + STR_String& TrimLeft(char *set); + STR_String& TrimRight(); + STR_String& TrimRight(char *set); + STR_String& Trim(); + STR_String& Trim(char *set); + STR_String& TrimQuotes(); + + // Conversions +// inline operator char*() { return pData; } + inline operator const char *() const { return pData; } + inline char *Ptr() { return pData; } + inline const char *ReadPtr() const { return pData; } + inline float ToFloat() const { float x=atof(pData); return x; } + inline int ToInt() const { return atoi(pData); } + + // Operators + inline rcSTR_String operator=(const byte *rhs) { return Copy((const char *)rhs, strlen((const char *)rhs)); } + inline rcSTR_String operator=(rcSTR_String rhs) { return Copy(rhs.ReadPtr(), rhs.Length()); } + inline rcSTR_String operator=(char rhs) { return Copy(&rhs, 1); } + inline rcSTR_String operator=(const char *rhs) { return Copy(rhs, strlen(rhs)); } + + inline rcSTR_String operator+=(const char *rhs) { return Concat(rhs, strlen(rhs)); } + inline rcSTR_String operator+=(rcSTR_String rhs) { return Concat(rhs.ReadPtr(), rhs.Length()); } + inline rcSTR_String operator+=(char rhs) { return Concat(&rhs, 1); } + + + inline friend bool operator<(rcSTR_String lhs, rcSTR_String rhs) { return (strcmp(lhs, rhs)<0); } + inline friend bool operator<(rcSTR_String lhs, const char *rhs) { return (strcmp(lhs, rhs)<0); }; + inline friend bool operator<(const char *lhs, rcSTR_String rhs) { return (strcmp(lhs, rhs)<0); } + inline friend bool operator>(rcSTR_String lhs, rcSTR_String rhs) { return (strcmp(lhs, rhs)>0); } + inline friend bool operator>(rcSTR_String lhs, const char *rhs) { return (strcmp(lhs, rhs)>0); } + inline friend bool operator>(const char *lhs, rcSTR_String rhs) { return (strcmp(lhs, rhs)>0); } + inline friend bool operator<=(rcSTR_String lhs, rcSTR_String rhs) { return (strcmp(lhs, rhs)<=0); } + inline friend bool operator<=(rcSTR_String lhs, const char *rhs) { return (strcmp(lhs, rhs)<=0); } + inline friend bool operator<=(const char *lhs, rcSTR_String rhs) { return (strcmp(lhs, rhs)<=0); } + inline friend bool operator>=(rcSTR_String lhs, rcSTR_String rhs) { return (strcmp(lhs, rhs)>=0); } + inline friend bool operator>=(rcSTR_String lhs, const char *rhs) { return (strcmp(lhs, rhs)>=0); } + inline friend bool operator>=(const char *lhs, rcSTR_String rhs) { return (strcmp(lhs, rhs)>=0); } + inline friend bool operator==(rcSTR_String lhs, rcSTR_String rhs) { return ((lhs.Length() == rhs.Length()) && (memcmp(lhs, rhs, lhs.Length())==0)); } + inline friend bool operator==(rcSTR_String lhs, const char *rhs) { return (memcmp(lhs, rhs, lhs.Length()+1)==0); } + inline friend bool operator==(const char *lhs, rcSTR_String rhs) { return (memcmp(lhs, rhs, rhs.Length()+1)==0); } + inline friend bool operator!=(rcSTR_String lhs, rcSTR_String rhs) { return ((lhs.Length() != rhs.Length()) || (memcmp(lhs, rhs, lhs.Length())!=0)); } + inline friend bool operator!=(rcSTR_String lhs, const char *rhs) { return (memcmp(lhs, rhs, lhs.Length()+1)!=0); } + inline friend bool operator!=(const char *lhs, rcSTR_String rhs) { return (memcmp(lhs, rhs, rhs.Length()+1)!=0); } + + // serializing + //int Serialize(pCStream stream); + +protected: + // Implementation + void AllocBuffer(int len, bool keep_contents); + rcSTR_String Copy(const char *src, int len); + rcSTR_String Concat(const char *data, int len); + + static bool isLower(char c) { return !isUpper(c); } + static bool isUpper(char c) { return (c>='A') && (c <= 'Z'); } + static bool isSpace(char c) { return (c==' ') || (c=='\t'); } + + char *pData; // -> STR_String data + int Len; // Data length + int Max; // Space in data buffer +}; + +inline STR_String operator+(rcSTR_String lhs, rcSTR_String rhs) { return STR_String(lhs.ReadPtr(), lhs.Length(), rhs.ReadPtr(), rhs.Length()); } +inline STR_String operator+(rcSTR_String lhs, char rhs) { return STR_String(lhs.ReadPtr(), lhs.Length(), &rhs, 1); } +inline STR_String operator+(char lhs, rcSTR_String rhs) { return STR_String(&lhs, 1, rhs.ReadPtr(), rhs.Length()); } +inline STR_String operator+(rcSTR_String lhs, const char *rhs) { return STR_String(lhs.ReadPtr(), lhs.Length(), rhs, strlen(rhs)); } +inline STR_String operator+(const char *lhs, rcSTR_String rhs) { return STR_String(lhs, strlen(lhs), rhs.ReadPtr(), rhs.Length()); } + + +#endif //_STR_String_H_ + diff --git a/intern/string/intern/Makefile b/intern/string/intern/Makefile new file mode 100644 index 00000000000..925cdfed54a --- /dev/null +++ b/intern/string/intern/Makefile @@ -0,0 +1,42 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# string intern Makefile +# + +LIBNAME = string +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I.. + diff --git a/intern/string/intern/STR_String.cpp b/intern/string/intern/STR_String.cpp new file mode 100644 index 00000000000..af8f0d11445 --- /dev/null +++ b/intern/string/intern/STR_String.cpp @@ -0,0 +1,746 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * This file was formerly known as: GEN_StdString.cpp. + * @date April, 25, 2001 + */ + +#include +#include +#include +#include +#include +#include "STR_String.h" + +/*------------------------------------------------------------------------------------------------- + Construction / destruction +-------------------------------------------------------------------------------------------------*/ + + + +// +// Construct an empty string +// +STR_String::STR_String() : + pData(new char [32]), + Len(0), + Max(32) +{ + pData[0] = 0; +} + + + +// +// Construct a string of one character +// +STR_String::STR_String(char c) : + pData(new char [9]), + Len(1), + Max(9) +{ + pData[0] = c; + pData[1] = 0; +} + + + +// +// Construct a string of multiple repeating characters +// +STR_String::STR_String(char c, int len) : + pData(new char [len+8]), + Len(len), + Max(len+8) +{ + assertd(pData != NULL); + memset(pData, c, len); + pData[len] = 0; +} + + + +// +// Construct a string from a pointer-to-ASCIIZ-string +// +// MAART: Changed to test for null strings +STR_String::STR_String(const char *str) +{ + if (str) { + Len = ::strlen(str); + Max = Len + 8; + pData = new char [Max]; + assertd(pData != NULL); + ::memcpy(pData, str, Len); + pData[Len] = 0; + } + else { + pData = 0; + Len = 0; + Max = 8; + } +} + + + +// +// Construct a string from a pointer-to-ASCII-string and a length +// +STR_String::STR_String(const char *str, int len) : + pData(new char [len+8]), + Len(len), + Max(len+8) +{ + assertd(pData != NULL); + memcpy(pData, str, len); + pData[len] = 0; +} + + + +// +// Construct a string from another string +// +STR_String::STR_String(rcSTR_String str) : + pData(new char [str.Length()+8]), + Len(str.Length()), + Max(str.Length()+8) +{ + assertd(pData != NULL); + assertd(str.pData != NULL); + memcpy(pData, str.pData, str.Length()); + pData[str.Length()] = 0; +} + + + +// +// Construct a string from the first number of characters in another string +// +STR_String::STR_String(rcSTR_String str, int len) : + pData(new char [len+8]), + Len(len), + Max(len+8) +{ + assertd(pData != NULL); + assertd(str.pData != NULL); + memcpy(pData, str.pData, str.Length()); + pData[str.Length()] = 0; +} + + + +// +// Create a string by concatenating two sources +// +STR_String::STR_String(const char *src1, int len1, const char *src2, int len2) : + pData(new char [len1+len2+8]), + Len(len1+len2), + Max(len1+len2+8) +{ + assertd(pData != NULL); + memcpy(pData, src1, len1); + memcpy(pData+len1, src2, len2); + pData[len1+len2] = 0; +} + + + +// +// Create a string with an integer value +// +STR_String::STR_String(int val) : + pData(new char [32]), + Max(32) +{ + assertd(pData != NULL); + Len=sprintf(pData, "%d", val); +} + + + + +// +// Create a string with a dword value +// +STR_String::STR_String(dword val) : + pData(new char [32]), + Max(32) +{ + assertd(pData != NULL); + Len=sprintf(pData, "%lu", val); +} + + + +// +// Create a string with a floating point value +// +STR_String::STR_String(float val) : + pData(new char [32]), + Max(32) +{ + assertd(pData != NULL); + Len=sprintf(pData, "%g", val); +} + + + +// +// Create a string with a double value +// +STR_String::STR_String(double val) : + pData(new char [32]), + Max(32) +{ + assertd(pData != NULL); + Len=sprintf(pData, "%g", val); +} + + + +/*------------------------------------------------------------------------------------------------- + Buffer management +-------------------------------------------------------------------------------------------------*/ + + + +// +// Make sure that the allocated buffer is at least in size +// +void STR_String::AllocBuffer(int len, bool keep_contents) +{ + // Check if we have enough space + if (len+1 <= Max) return; + + // Reallocate string + char *new_data = new char [len+8]; + if (keep_contents) memcpy(new_data, pData, Len); + delete[] pData; + + // Accept new data + Max = len+8; + pData = new_data; + assertd(pData != NULL); +} + + + +/*------------------------------------------------------------------------------------------------- + Basic string operations +-------------------------------------------------------------------------------------------------*/ + + + +// +// Format string (as does sprintf) +// +STR_String& STR_String::Format(const char *fmt, ...) +{ + AllocBuffer(2048, false); + + assertd(pData != NULL); + // Expand arguments and format to string + va_list args; + va_start(args, fmt); + Len = vsprintf(pData, fmt, args); + assertd(Len <= 2048); + va_end(args); + + return *this; +} + + + +// +// Format string (as does sprintf) +// +STR_String& STR_String::FormatAdd(const char *fmt, ...) +{ + AllocBuffer(2048, false); + + assertd(pData != NULL); + // Expand arguments and format to string + va_list args; + va_start(args, fmt); + Len += vsprintf(pData+Len, fmt, args); + assertd(Len <= 2048); + va_end(args); + + return *this; +} + + + +/*------------------------------------------------------------------------------------------------- + Properties +-------------------------------------------------------------------------------------------------*/ + + + +// +// Check if string is entirely in UPPERCase +// +bool STR_String::IsUpper() const +{ + for (int i=0; i in the string +// +int STR_String::Find(char c, int pos) const +{ + assertd(pos >= 0); + assertd(Len==0 || pos in the string +// +int STR_String::Find(const char *str, int pos) const +{ + assertd(pos >= 0); + assertd(Len==0 || pos in the string +// +int STR_String::Find(rcSTR_String str, int pos) const +{ + assertd(pos >= 0); + assertd(Len==0 || pos in the string +// +int STR_String::RFind(char c) const +{ + assertd(pData != NULL); + char *pos = strrchr(pData, c); + return (pos) ? (pos-pData) : -1; +} + + + +// +// Find the first occurence of any character in character set in the string +// +int STR_String::FindOneOf(const char *set, int pos) const +{ + assertd(pos >= 0); + assertd(Len==0 || pos= 1); + + if (str.Length() < num) + { + // Remove some data from the string by replacement + memcpy(pData+pos+str.Length(), pData+pos+num, Len-pos-num+1); + memcpy(pData+pos, str.ReadPtr(), str.Length()); + } + else + { + // Insert zero or more characters into the string + AllocBuffer(Len + str.Length() - num, true); + if (str.Length() != num) memcpy(pData+pos+str.Length(), pData+pos+num, Length()-pos-num+1); + memcpy(pData+pos, str.ReadPtr(), str.Length()); + } + + Len += str.Length()-num; +} + + + +/*------------------------------------------------------------------------------------------------- + Comparison +-------------------------------------------------------------------------------------------------*/ + + + +// +// Compare two strings and return the result, <0 if *this0 if *this>rhs or 0 if *this==rhs +// +int STR_String::Compare(rcSTR_String rhs) const +{ + return strcmp(pData, rhs.pData); +} + + + +// +// Compare two strings without respecting case and return the result, <0 if *this0 if *this>rhs or 0 if *this==rhs +// +int STR_String::CompareNoCase(rcSTR_String rhs) const +{ +#ifdef WIN32 + return stricmp(pData, rhs.pData); +#else + return strcasecmp(pData, rhs.pData); +#endif +} + + + +/*------------------------------------------------------------------------------------------------- + Formatting +-------------------------------------------------------------------------------------------------*/ + + + +// +// Capitalize string, "heLLo" -> "HELLO" +// +STR_String& STR_String::Upper() +{ + assertd(pData != NULL); +#ifdef WIN32 + _strupr(pData); +#else + for (int i=0;i= 'a' && pData[i] <= 'z')?pData[i]+'A'-'a':pData[i]; +#endif + return *this; +} + + + +// +// Lower string, "heLLo" -> "hello" +// +STR_String& STR_String::Lower() +{ + assertd(pData != NULL); +#ifdef WIN32 + _strlwr(pData); +#else + for (int i=0;i= 'A' && pData[i] <= 'Z')?pData[i]+'a'-'A':pData[i]; +#endif + return *this; +} + + + +// +// Capitalize string, "heLLo" -> "Hello" +// +STR_String& STR_String::Capitalize() +{ + assertd(pData != NULL); +#ifdef WIN32 + if (Len>0) pData[0] = toupper(pData[0]); + if (Len>1) _strlwr(pData+1); +#else + if (Len > 0) + pData[0] = (pData[0] >= 'A' && pData[0] <= 'A')?pData[0]+'a'-'A':pData[0]; + for (int i=1;i= 'a' && pData[i] <= 'z')?pData[i]+'A'-'a':pData[i]; +#endif + return *this; +} + + + +// +// Trim whitespace from the left side of the string +// +STR_String& STR_String::TrimLeft() +{ + int skip; + assertd(pData != NULL); + for (skip=0; isSpace(pData[skip]); skip++, Len--); + memmove(pData, pData+skip, Len+1); + return *this; +} + + + +// +// Trim whitespaces from the right side of the string +// +STR_String& STR_String::TrimRight() +{ + assertd(pData != NULL); + while (Len && isSpace(pData[Len-1])) Len--; + pData[Len]=0; + return *this; +} + + + +// +// Trim spaces from both sides of the character set +// +STR_String& STR_String::Trim() +{ + TrimRight(); + TrimLeft(); + return *this; +} + + + +// +// Trim characters from the character set from the left side of the string +// +STR_String& STR_String::TrimLeft(char *set) +{ + int skip; + assertd(pData != NULL); + for (skip=0; Len && strchr(set, pData[skip]); skip++, Len--); + memmove(pData, pData+skip, Len+1); + return *this; +} + + + +// +// Trim characters from the character set from the right side of the string +// +STR_String& STR_String::TrimRight(char *set) +{ + assertd(pData != NULL); + while (Len && strchr(set, pData[Len-1])) Len--; + pData[Len]=0; + return *this; +} + + + +// +// Trim characters from the character set from both sides of the character set +// +STR_String& STR_String::Trim(char *set) +{ + TrimRight(set); + TrimLeft(set); + return *this; +} + + + +// +// Trim quotes from both sides of the string +// +STR_String& STR_String::TrimQuotes() +{ + // Trim quotes if they are on both sides of the string + assertd(pData != NULL); + if ((Len >= 2) && (pData[0] == '\"') && (pData[Len-1] == '\"')) + { + memmove(pData, pData+1, Len-2+1); + Len-=2; + } + return *this; +} + + + +/*------------------------------------------------------------------------------------------------- + Assignment/Concatenation +-------------------------------------------------------------------------------------------------*/ + + + +// +// Set the string's conents to a copy of with length +// +rcSTR_String STR_String::Copy(const char *src, int len) +{ + assertd(len>=0); + assertd(src); + assertd(pData != NULL); + + AllocBuffer(len, false); + Len = len; + memcpy(pData, src, len); + pData[Len] = 0; + + return *this; +} + + + +// +// Concate a number of bytes to the current string +// +rcSTR_String STR_String::Concat(const char *data, int len) +{ + assertd(Len>=0); + assertd(len>=0); + assertd(data); + assertd(pData != NULL); + + AllocBuffer(Len+len, true); + memcpy(pData+Len, data, len); + Len+=len; + pData[Len] = 0; + + return *this; +} + + + + + +vector STR_String::Explode(char c) const +{ + STR_String lcv = *this; + vector uc; + + while (lcv.Length()) + { + int pos = lcv.Find(c); + if (pos < 0) + { + uc.push_back(lcv); + lcv.Clear(); + } else + { + uc.push_back(lcv.Left(pos)); + lcv = lcv.Mid(pos+1); + } + } + + //uc. -= STR_String(""); + + return uc; +} + + +/* + +int STR_String::Serialize(pCStream stream) +{ + if (stream->GetAccess() == CStream::Access_Read) + { + int ln; + stream->Read(&ln, sizeof(ln)); + AllocBuffer(ln, false); + stream->Read(pData, ln); + pData[ln] = '\0'; + Len = ln; + } else + { + stream->Write(&Len, sizeof(Len)); + stream->Write(pData, Len); + } + + return Len + sizeof(Len); +} +*/ + diff --git a/intern/string/make/msvc_6_0/string.dsp b/intern/string/make/msvc_6_0/string.dsp new file mode 100644 index 00000000000..c6ac70e193a --- /dev/null +++ b/intern/string/make/msvc_6_0/string.dsp @@ -0,0 +1,122 @@ +# Microsoft Developer Studio Project File - Name="string" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=string - 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 "string.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 "string.mak" CFG="string - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "string - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "string - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "string - 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 "..\..\..\..\obj\windows\intern\string" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\string" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../.." /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# 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:"..\..\..\..\obj\windows\intern\string\libstring.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\string\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\string\*.lib ..\..\..\..\..\lib\windows\string\lib\*.a ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "string - 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 "../../../../obj/windows/intern/string/debug" +# PROP Intermediate_Dir "../../../../obj/windows/intern/string/debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "../.." /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# 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:"../../../../obj/windows/intern/string/debug\libstring.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\string\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\string\debug\*.lib ..\..\..\..\..\lib\windows\string\lib\debug\*.a ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "string - Win32 Release" +# Name "string - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\intern\STR_String.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Group "intern" + +# PROP Default_Filter "" +# End Group +# Begin Group "extern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\STR_HashedString.h +# End Source File +# Begin Source File + +SOURCE=..\..\STR_String.h +# End Source File +# End Group +# End Group +# End Target +# End Project diff --git a/intern/string/make/msvc_6_0/string.dsw b/intern/string/make/msvc_6_0/string.dsw new file mode 100644 index 00000000000..b599b6407c5 --- /dev/null +++ b/intern/string/make/msvc_6_0/string.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "string"=".\string.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/string/make/msvc_7_0/string.sln b/intern/string/make/msvc_7_0/string.sln new file mode 100644 index 00000000000..53981b212ea --- /dev/null +++ b/intern/string/make/msvc_7_0/string.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "string", "string.vcproj", "{0607A77B-49DD-42D8-A767-D0D60769DC90}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {0607A77B-49DD-42D8-A767-D0D60769DC90}.Debug.ActiveCfg = Debug|Win32 + {0607A77B-49DD-42D8-A767-D0D60769DC90}.Debug.Build.0 = Debug|Win32 + {0607A77B-49DD-42D8-A767-D0D60769DC90}.Release.ActiveCfg = Release|Win32 + {0607A77B-49DD-42D8-A767-D0D60769DC90}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/intern/string/make/msvc_7_0/string.vcproj b/intern/string/make/msvc_7_0/string.vcproj new file mode 100644 index 00000000000..deb342c26e8 --- /dev/null +++ b/intern/string/make/msvc_7_0/string.vcproj @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/po/Makefile b/po/Makefile new file mode 100644 index 00000000000..b7288c0e64c --- /dev/null +++ b/po/Makefile @@ -0,0 +1,62 @@ +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2002 by Stichting Blender Foundation, +# Amsterdam, the Netherlands. +# All rights reserved. +# +# The Original Code is: revision 1.1 +# +# Contributor(s): Wouter van Heyst +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# po Makefile for blender. Compiles the translations and places them +# where release can pick them up. + +SOURCEDIR = blender/po + +include nan_definitions.mk + +ifeq ($(INTERNTIONAL),true) + LINGUAS = ar bg ca cs de es fr hr it ja nl pl pt_BR ro ru sr sr@Latn sv uk zh_CN +else + LINGUAS = +endif + +ifeq ($(OS), darwin) +DIR = $(OCGDIR)/bin/blender.app/Contents/Resources/locale/$@/LC_MESSAGES/ +else +DIR = $(OCGDIR)/bin/.blender/locale/$@/LC_MESSAGES/ +endif + +all debug:: $(LINGUAS) + +clean:: +ifeq ($(OS), darwin) + rm -rf $(OCGDIR)/bin/blender.app/Contents/Resources/locale/ +else + rm -rf $(OCGDIR)/bin/.blender/locale/ +endif + +$(LINGUAS): + mkdir -p $(DIR) + msgfmt -o $(DIR)/blender.mo $@.po diff --git a/projectfiles/blender/BLO_readblenfile/BLO_readblenfile.dsp b/projectfiles/blender/BLO_readblenfile/BLO_readblenfile.dsp new file mode 100644 index 00000000000..8e478f425d9 --- /dev/null +++ b/projectfiles/blender/BLO_readblenfile/BLO_readblenfile.dsp @@ -0,0 +1,155 @@ +# Microsoft Developer Studio Project File - Name="BLO_readblenfile" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BLO_readblenfile - Win32 Release +!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 "BLO_readblenfile.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 "BLO_readblenfile.mak" CFG="BLO_readblenfile - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BLO_readblenfile - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BLO_readblenfile - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "BLO_readblenfile - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BLO_readblenfile - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BLO_readblenfile - 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 "..\..\..\obj\windows\blender\readblenfile" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\readblenfile" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\source\blender\streamglue\\" /I "..\..\..\source\blender\blenloader\\" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\kernel\gen_messaging" /I "..\..\..\source\blender\readblenfile\\" /I "..\..\..\source\blender\deflate\\" /I "..\..\..\source\blender\inflate\\" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\source\blender\readstreamglue" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BLO_readblenfile - 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 "..\..\..\obj\windows\blender\readblenfile\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\readblenfile\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\source\blender\readstreamglue\\" /I "..\..\..\source\blender\blenloader\\" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\kernel\gen_messaging" /I "..\..\..\source\blender\readblenfile\\" /I "..\..\..\source\blender\deflate\\" /I "..\..\..\source\blender\inflate\\" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\source\blender\readstreamglue" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BLO_readblenfile - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "BLO_readblenfile___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "BLO_readblenfile___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\readblenfile\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\readblenfile\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /I "..\..\..\source\blender\streamglue\\" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\kernel\gen_messaging" /I "..\..\..\source\blender\readblenfile\\" /I "..\..\..\source\blender\deflate\\" /I "..\..\..\source\blender\inflate\\" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\source\blender\readstreamglue" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\source\blender\streamglue\\" /I "..\..\..\source\blender\blenloader\\" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\kernel\gen_messaging" /I "..\..\..\source\blender\readblenfile\\" /I "..\..\..\source\blender\deflate\\" /I "..\..\..\source\blender\inflate\\" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\source\blender\readstreamglue" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BLO_readblenfile - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "BLO_readblenfile___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "BLO_readblenfile___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\readblenfile\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\readblenfile\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\readstreamglue\\" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\kernel\gen_messaging" /I "..\..\..\source\blender\readblenfile\\" /I "..\..\..\source\blender\deflate\\" /I "..\..\..\source\blender\inflate\\" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\source\blender\readstreamglue" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\source\blender\readstreamglue\\" /I "..\..\..\source\blender\blenloader\\" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\kernel\gen_messaging" /I "..\..\..\source\blender\readblenfile\\" /I "..\..\..\source\blender\deflate\\" /I "..\..\..\source\blender\inflate\\" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\source\blender\readstreamglue" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "BLO_readblenfile - Win32 Release" +# Name "BLO_readblenfile - Win32 Debug" +# Name "BLO_readblenfile - Win32 MT DLL Release" +# Name "BLO_readblenfile - Win32 MT DLL Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\readblenfile\intern\BLO_readblenfile.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\readblenfile\BLO_readblenfile.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/BPY_python/BPY_python.dsp b/projectfiles/blender/BPY_python/BPY_python.dsp new file mode 100644 index 00000000000..e122f0ffe90 --- /dev/null +++ b/projectfiles/blender/BPY_python/BPY_python.dsp @@ -0,0 +1,588 @@ +# Microsoft Developer Studio Project File - Name="BPY_python" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BPY_python - Win32 Release +!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 "BPY_python.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 "BPY_python.mak" CFG="BPY_python - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BPY_python - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BPY_python - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BPY_python - 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 "..\..\..\obj\windows\blender\bpython" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\bpython" +# PROP Target_Dir "" +MTL=midl.exe +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\img" /I "..\..\..\source\blender\radiosity\extern\include" /I "..\..\..\..\lib\windows\bmfont\include" /I "..\..\source\blender\misc" /I "..\..\..\lib\windows\guardedalloc\include" /I "..\..\source\blender\blenlib" /I "..\..\source\kernel\gen_messaging" /I "..\..\source\blender\include" /I "..\..\source\blender" /I "..\..\source\blender\makesdna" /I "..\..\source\blender\blenkernel" /I "..\..\source\blender\blenloader" /I "..\..\source\blender\bpython\include" /I "..\..\source\blender\imbuf" /I "..\..\source\blender\render\extern\include" /I "..\..\source\blender\radiosity\extern\include" /I "..\..\source\kernel\gen_system" /I "..\..\source\blender\renderconverter\\" /I "..\..\source\blender\renderui\\" /I "..\..\source\blender\python" /I "../../../../lib/windows/bsp/include" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\avi" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender" /I "..\..\..\source\blender\bpython\include" /I "../../../source/gameengine\SoundSystem\\" /I "../../../../lib/windows/iksolver/include" /I "..\..\..\source\blender\python" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 + +!ELSEIF "$(CFG)" == "BPY_python - 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 "..\..\..\obj\windows\blender\bpython\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\bpython\debug" +# PROP Target_Dir "" +MTL=midl.exe +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /w /W0 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\img" /I "..\..\..\..\lib\windows\bmfont\include" /I "..\..\source\blender\misc" /I "..\..\..\lib\windows\guardedalloc\include" /I "..\..\source\blender\blenlib" /I "..\..\source\kernel\gen_messaging" /I "..\..\source\blender\include" /I "..\..\source\blender" /I "..\..\source\blender\makesdna" /I "..\..\source\blender\blenkernel" /I "..\..\source\blender\blenloader" /I "..\..\..\source\blender\radiosity\extern\include" /I "..\..\source\blender\bpython\include" /I "..\..\source\blender\imbuf" /I "..\..\source\blender\render\extern\include" /I "..\..\source\kernel\gen_system" /I "..\..\source\blender\renderconverter\\" /I "..\..\source\blender\renderui\\" /I "..\..\source\blender\python" /I "../../../../lib/windows/bsp/include" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\avi" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender" /I "..\..\..\source\blender\bpython\include" /I "../../../source/gameengine\SoundSystem\\" /I "../../../../lib/windows/iksolver/include" /I "..\..\..\source\blender\python" /D "WIN32" /D "_MBCS" /D "_LIB" /U "_DEBUG" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "BPY_python - Win32 Release" +# Name "BPY_python - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Armature.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\BezTriple.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\BGL.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Blender.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Bone.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\BPY_interface.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\BPY_menus.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Camera.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\charRGBA.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\constant.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Constraint.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\CurNurb.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Curve.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Draw.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Effect.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\euler.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\EXPP_interface.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Font.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\gen_utils.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Geometry.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Group.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\IDProp.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Image.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Ipo.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Ipocurve.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Key.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Lamp.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Lattice.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Library.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\logic.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Material.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Mathutils.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\matrix.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Mesh.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\meshPrimitive.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Metaball.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Modifier.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\MTex.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\NLA.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\NMesh.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Noise.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Object.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Particle.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\point.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Pose.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\quat.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Registry.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\rgbTuple.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Scene.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\sceneRadio.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\sceneRender.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\sceneTimeLine.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Sound.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\SurfNurb.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Sys.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Text.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Text3d.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Texture.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Types.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\vector.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Window.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\windowTheme.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\World.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Armature.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\BezTriple.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\BGL.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Blender.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Bone.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\BPY_extern.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\BPY_menus.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\bpy_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Camera.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\charRGBA.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\constant.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Constraint.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\CurNurb.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Curve.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Draw.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Effect.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\euler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\EXPP_interface.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Font.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\gen_utils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Geometry.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Group.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Image.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Ipo.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Ipocurve.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Key.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Lamp.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Lattice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Material.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Mathutils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\matrix.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Mesh.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\meshPrimitive.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Metaball.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Modifier.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\modules.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\MTex.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\NLA.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\NMesh.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Object.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Particle.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\point.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\quat.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Registry.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\rgbTuple.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Scene.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\sceneRadio.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\sceneRender.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\sceneTimeLine.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Sound.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\SurfNurb.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Sys.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Text.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Text3d.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Texture.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\vector.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Window.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\windowTheme.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\World.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/avi/BL_avi.dsp b/projectfiles/blender/avi/BL_avi.dsp new file mode 100644 index 00000000000..1237ddcec47 --- /dev/null +++ b/projectfiles/blender/avi/BL_avi.dsp @@ -0,0 +1,199 @@ +# Microsoft Developer Studio Project File - Name="BL_avi" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BL_avi - Win32 Release +!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 "BL_avi.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 "BL_avi.mak" CFG="BL_avi - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BL_avi - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BL_avi - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "BL_avi - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "BL_avi - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BL_avi - 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 "..\..\..\obj\windows\blender\avi" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\avi" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\include" /I "..\..\..\..\lib\windows\jpeg\include" /I "..\..\..\source\blender\makesdna" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "DWORDS_LITTLEENDIAN" /YX /J /FD /c +# 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 + +!ELSEIF "$(CFG)" == "BL_avi - 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 "..\..\..\obj\windows\blender\avi\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\avi\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\include" /I "..\..\..\..\lib\windows\jpeg\include" /I "..\..\..\source\blender\makesdna" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "DWORDS_LITTLEENDIAN" /YX /J /FD /GZ /c +# SUBTRACT CPP /Fr +# 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 + +!ELSEIF "$(CFG)" == "BL_avi - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "BL_avi___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "BL_avi___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\avi\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\avi\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\include" /I "..\..\..\..\lib\windows\jpeg\include" /I "..\..\..\source\blender\makesdna" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "DWORDS_LITTLEENDIAN" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\include" /I "..\..\..\..\lib\windows\jpeg\include" /I "..\..\..\source\blender\makesdna" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "DWORDS_LITTLEENDIAN" /YX /J /FD /GZ /c +# 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 /out:"..\..\..\..\..\obj\windows\blender\avi\debug\BL_avi.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BL_avi - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "BL_avi___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "BL_avi___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\avi\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\avi\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\include" /I "..\..\..\..\lib\windows\jpeg\include" /I "..\..\..\source\blender\makesdna" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "DWORDS_LITTLEENDIAN" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\include" /I "..\..\..\..\lib\windows\jpeg\include" /I "..\..\..\source\blender\makesdna" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "DWORDS_LITTLEENDIAN" /YX /J /FD /c +# 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 /out:"..\..\..\..\..\obj\windows\blender\avi\BL_avi.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "BL_avi - Win32 Release" +# Name "BL_avi - Win32 Debug" +# Name "BL_avi - Win32 MT DLL Debug" +# Name "BL_avi - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\intern\avi.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\intern\avirgb.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\intern\codecs.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\intern\endian.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\intern\mjpeg.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\intern\options.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\intern\rgb32.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\AVI_avi.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\intern\avi_intern.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\intern\avirgb.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\intern\endian.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\intern\mjpeg.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\intern\rgb32.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/blender.dsp b/projectfiles/blender/blender.dsp new file mode 100644 index 00000000000..17cd7022d82 --- /dev/null +++ b/projectfiles/blender/blender.dsp @@ -0,0 +1,124 @@ +# Microsoft Developer Studio Project File - Name="blender" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=blender - Win32 Release +!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 "blender.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 "blender.mak" CFG="blender - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "blender - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "blender - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "blender - 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 "..\..\obj\windows\blender" +# PROP Intermediate_Dir "..\..\obj\windows\blender" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\source\blender\misc" /I "..\..\..\lib\windows\guardedalloc\include" /I "..\..\source\blender\blenlib" /I "..\..\source\kernel\gen_messaging" /I "..\..\source\blender\include" /I "..\..\source\blender" /I "..\..\source\blender\makesdna" /I "..\..\source\blender\blenkernel" /I "..\..\source\blender\blenloader" /I "..\..\source\blender\python" /I "..\..\source\blender\imbuf" /I "..\..\source\blender\render\extern\include" /I "..\..\source\blender\radiosity\extern\include" /I "..\..\source\kernel\gen_system" /I "..\..\source\blender\renderconverter\\" /I "..\..\source\blender\renderui\\" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WITH_QUICKTIME" /YX /FD /c +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 solid.lib SDL.lib freetype2ST.lib ftgl_static_ST.lib gnu_gettext.lib qtmlClient.lib openal_static.lib libsoundsystem.a libopenalsoundsystem.lib libdummysoundsystem.lib libguardedalloc.a libbsp.a libbmfont.a libghost.a libstring.a ws2_32.lib dxguid.lib opengl32.lib libjpeg.a glu32.lib user32.lib shell32.lib gdi32.lib vfw32.lib advapi32.lib winmm.lib ole32.lib libdecimation.a libiksolver.a libpng.a zlib.lib libmoto.a blender_ONL.lib blender_elbeem.lib boolop.lib BLI_bullet.lib pthreadVC2.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"msvcprt.lib" /nodefaultlib:"msvcrt.lib" /nodefaultlib:"glut32.lib" /nodefaultlib:"libcd.lib" /nodefaultlib:"libc.lib" /nodefaultlib:"libcpd.lib" /nodefaultlib:"libcp.lib" /nodefaultlib:"libcmtd.lib" /out:"..\..\bin\blender.exe" /libpath:"..\..\..\lib\windows\sdl\lib" /libpath:"..\..\..\lib\windows\freetype\lib" /libpath:"..\..\..\lib\windows\ftgl\lib" /libpath:"..\..\..\lib\windows\gettext\lib" /libpath:"..\..\..\lib\windows\ode\lib" /libpath:"..\..\..\lib\windows\bsp\lib" /libpath:"..\..\..\lib\windows\moto\lib" /libpath:"..\..\..\lib\windows\bmfont\lib" /libpath:"..\..\..\lib\windows\ghost\lib" /libpath:"..\..\..\lib\windows\python\frozen" /libpath:"..\..\..\lib\windows\guardedalloc\lib" /libpath:"..\..\..\lib\windows\string\lib" /libpath:"..\..\..\lib\windows\solid\lib" /libpath:"..\..\..\lib\windows\python\lib" /libpath:"..\..\..\lib\windows\iksolver\lib" /libpath:"..\..\..\lib\windows\decimation\lib" /libpath:"..\..\..\lib\windows\openal\lib" /libpath:"..\..\..\lib\windows\jpeg\lib" /libpath:"..\..\..\lib\windows\blenkey\lib" /libpath:"..\..\..\lib\windows\openssl\lib" /libpath:"..\..\obj\windows\intern\soundsystem\dummy" /libpath:"..\..\obj\windows\intern\soundsystem\openal" /libpath:"..\..\..\lib\windows\soundsystem\lib\\" /libpath:"..\..\..\lib\windows\zlib\lib\\" /libpath:"..\..\..\lib\windows\png\lib\\" /libpath:"..\..\..\lib\windows\opennl" /libpath:"..\..\..\lib\windows\elbeem\lib" /libpath:"..\..\..\lib\windows\boolop\lib" /libpath:"..\..\..\lib\windows\bullet\lib" /libpath:"..\..\..\lib\windows\pthreads\lib" +# SUBTRACT LINK32 /pdb:none +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying required 3rd party dlls... XCOPY /Y ..\..\..\lib\windows\gettext\lib\*.dll ..\..\bin\ XCOPY /Y ..\..\..\lib\windows\sdl\lib\*dll ..\..\bin\ ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "blender - 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 "..\..\obj\windows\blender\debug" +# PROP Intermediate_Dir "..\..\obj\windows\blender\debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\source\blender\misc" /I "..\..\..\lib\windows\guardedalloc\include" /I "..\..\source\blender\blenlib" /I "..\..\source\kernel\gen_messaging" /I "..\..\source\blender\include" /I "..\..\source\blender" /I "..\..\source\blender\makesdna" /I "..\..\source\blender\blenkernel" /I "..\..\source\blender\blenloader" /I "..\..\source\blender\python" /I "..\..\source\blender\imbuf" /I "..\..\source\blender\render\extern\include" /I "..\..\source\blender\radiosity\extern\include" /I "..\..\source\kernel\gen_system" /I "..\..\source\blender\renderconverter\\" /I "..\..\source\blender\renderui" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WITH_QUICKTIME" /YX /FD /GZ /c +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 solid.lib SDL.lib freetype2ST.lib ftgl_static_ST.lib gnu_gettext.lib qtmlClient.lib openal_static.lib libsoundsystem.a libopenalsoundsystem.lib libdummysoundsystem.lib libguardedalloc.a libbsp.a libbmfont.a libghost.a libstring.a ws2_32.lib dxguid.lib opengl32.lib libjpeg.a glu32.lib user32.lib gdi32.lib shell32.lib vfw32.lib advapi32.lib winmm.lib ole32.lib libdecimation.a libiksolver.a libpng.a zlib.lib libmoto.a blender_ONL.lib blender_elbeem.lib boolop.lib BLI_bullet_d.lib pthreadVC2.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"glut32.lib" /nodefaultlib:"libcd.lib" /nodefaultlib:"libc.lib" /nodefaultlib:"libcpd.lib" /nodefaultlib:"libcp.lib" /nodefaultlib:"libcmt.lib" /nodefaultlib:"libcpmtd.lib" /nodefaultlib:"msvcprtd.lib" /out:"..\..\bin\debug\blender.exe" /pdbtype:sept /libpath:"..\..\..\lib\windows\sdl\lib" /libpath:"..\..\..\lib\windows\freetype\lib" /libpath:"..\..\..\lib\windows\ftgl\lib" /libpath:"..\..\..\lib\windows\gettext\lib" /libpath:"..\..\..\lib\windows\ode\lib" /libpath:"..\..\..\lib\windows\bsp\lib\debug" /libpath:"..\..\..\lib\windows\moto\lib\debug" /libpath:"..\..\..\lib\windows\bmfont\lib\debug" /libpath:"..\..\..\lib\windows\ghost\lib\debug" /libpath:"..\..\..\lib\windows\python\frozen" /libpath:"..\..\..\lib\windows\guardedalloc\lib\debug" /libpath:"..\..\..\lib\windows\string\lib\debug" /libpath:"..\..\..\lib\windows\solid\lib\\" /libpath:"..\..\..\lib\windows\python\lib" /libpath:"..\..\..\lib\windows\iksolver\lib\debug" /libpath:"..\..\..\lib\windows\decimation\lib\debug" /libpath:"..\..\..\lib\windows\openal\lib" /libpath:"..\..\obj\windows\intern\soundsystem\dummy\debug" /libpath:"..\..\obj\windows\intern\soundsystem\openal\debug" /libpath:"..\..\..\lib\windows\soundsystem\lib\debug\\" /libpath:"..\..\..\lib\windows\jpeg\lib" /libpath:"..\..\..\lib\windows\blenkey\lib\debug" /libpath:"..\..\..\lib\windows\openssl\lib" /libpath:"..\..\..\lib\windows\zlib\lib\\" /libpath:"..\..\..\lib\windows\png\lib\\" /libpath:"..\..\..\lib\windows\opennl\debug" /libpath:"..\..\..\lib\windows\elbeem\lib\debug" /libpath:"..\..\..\lib\windows\boolop\lib" /libpath:"..\..\..\lib\windows\bullet\lib" /libpath:"..\..\..\lib\windows\elbeem\lib" /libpath:"..\..\..\lib\windows\pthreads\lib" +# SUBTRACT LINK32 /pdb:none +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying required 3rd party dlls... XCOPY /Y ..\..\..\lib\windows\gettext\lib\*.dll ..\..\bin\ ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "blender - Win32 Release" +# Name "blender - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\source\creator\creator.c +# End Source File +# Begin Source File + +SOURCE=..\..\source\icons\winblender.rc +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=..\..\source\icons\winblender.ico +# End Source File +# Begin Source File + +SOURCE=..\..\source\icons\winblenderfile.ico +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/blender.dsw b/projectfiles/blender/blender.dsw new file mode 100644 index 00000000000..3a69055807e --- /dev/null +++ b/projectfiles/blender/blender.dsw @@ -0,0 +1,743 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "BKE_blenkernel"=.\blenkernel\BKE_blenkernel.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "BLI_blenlib"=.\blenlib\BLI_blenlib.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "BLO_loader"=.\loader\BLO_loader.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "BLO_readblenfile"=.\BLO_readblenfile\BLO_readblenfile.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "BL_avi"=.\avi\BL_avi.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "BL_imbuf"=.\imbuf\BL_imbuf.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "BL_src"=.\src\BL_src.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "BL_src_cre"=.\src\BL_src_cre.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "BPY_python"=.\BPY_python\BPY_python.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "BRA_radiosity"=.\radiosity\BRA_radiosity.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "BRE_render"=.\render\BRE_render.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name BRE_yafray + End Project Dependency +}}} + +############################################################################### + +Project: "BRE_renderconverter"=.\renderconverter\BRE_renderconverter.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "BRE_yafray"=.\yafray\BRE_yafray.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "Bullet"=..\..\extern\bullet\Bullet\BLI_Bullet.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "BulletDynamics"=..\..\extern\bullet\BulletDynamics\BLI_BulletDynamics.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "DNA_makesdna"=.\makesdna\DNA_makesdna.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "EXP_expressions"=..\gameengine\expression\EXP_expressions.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "FTF_ftfont"=.\ftfont\FTF_ftfont.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "GP_axctl"=..\gameengine\gameplayer\axctl\GP_axctl.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name KX_converter + End Project Dependency + Begin Project Dependency + Project_Dep_Name EXP_expressions + End Project Dependency + Begin Project Dependency + Project_Dep_Name SCA_GameLogic + End Project Dependency + Begin Project Dependency + Project_Dep_Name KX_ketsji + End Project Dependency + Begin Project Dependency + Project_Dep_Name SG_SceneGraph + End Project Dependency + Begin Project Dependency + Project_Dep_Name RAS_openglrasterizer + End Project Dependency + Begin Project Dependency + Project_Dep_Name RAS_rasterizer + End Project Dependency + Begin Project Dependency + Project_Dep_Name SYS_system + End Project Dependency + Begin Project Dependency + Project_Dep_Name GP_common + End Project Dependency + Begin Project Dependency + Project_Dep_Name KX_network + End Project Dependency + Begin Project Dependency + Project_Dep_Name NG_loopbacknetwork + End Project Dependency + Begin Project Dependency + Project_Dep_Name NG_network + End Project Dependency + Begin Project Dependency + Project_Dep_Name DNA_makesdna + End Project Dependency + Begin Project Dependency + Project_Dep_Name gen_messaging + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_verify + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_decrypt + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_loader + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_readblenfile + End Project Dependency + Begin Project Dependency + Project_Dep_Name BKE_blenkernel + End Project Dependency + Begin Project Dependency + Project_Dep_Name BL_avi + End Project Dependency + Begin Project Dependency + Project_Dep_Name BL_imbuf + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLI_blenlib + End Project Dependency + Begin Project Dependency + Project_Dep_Name SND_OpenAL + End Project Dependency + Begin Project Dependency + Project_Dep_Name PHY_Physics + End Project Dependency + Begin Project Dependency + Project_Dep_Name PHY_Ode + End Project Dependency + Begin Project Dependency + Project_Dep_Name PHY_Dummy + End Project Dependency +}}} + +############################################################################### + +Project: "GP_common"=..\gameengine\gameplayer\common\GP_common.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "GP_ghost"=..\gameengine\gameplayer\ghost\GP_ghost.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name BKE_blenkernel + End Project Dependency + Begin Project Dependency + Project_Dep_Name BL_avi + End Project Dependency + Begin Project Dependency + Project_Dep_Name BL_imbuf + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLI_blenlib + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_loader + End Project Dependency + Begin Project Dependency + Project_Dep_Name DNA_makesdna + End Project Dependency + Begin Project Dependency + Project_Dep_Name EXP_expressions + End Project Dependency + Begin Project Dependency + Project_Dep_Name KX_converter + End Project Dependency + Begin Project Dependency + Project_Dep_Name KX_ketsji + End Project Dependency + Begin Project Dependency + Project_Dep_Name KX_network + End Project Dependency + Begin Project Dependency + Project_Dep_Name NG_loopbacknetwork + End Project Dependency + Begin Project Dependency + Project_Dep_Name NG_network + End Project Dependency + Begin Project Dependency + Project_Dep_Name RAS_openglrasterizer + End Project Dependency + Begin Project Dependency + Project_Dep_Name RAS_rasterizer + End Project Dependency + Begin Project Dependency + Project_Dep_Name SCA_GameLogic + End Project Dependency + Begin Project Dependency + Project_Dep_Name SG_SceneGraph + End Project Dependency + Begin Project Dependency + Project_Dep_Name SYS_system + End Project Dependency + Begin Project Dependency + Project_Dep_Name gen_messaging + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_readblenfile + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_decrypt + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_verify + End Project Dependency + Begin Project Dependency + Project_Dep_Name SND_OpenAL + End Project Dependency + Begin Project Dependency + Project_Dep_Name GP_common + End Project Dependency + Begin Project Dependency + Project_Dep_Name PHY_Physics + End Project Dependency + Begin Project Dependency + Project_Dep_Name PHY_Dummy + End Project Dependency + Begin Project Dependency + Project_Dep_Name PHY_Sumo + End Project Dependency +}}} + +############################################################################### + +Project: "KX_blenderhook"=..\gameengine\blenderhook\KX_blenderhook.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "KX_converter"=..\gameengine\converter\KX_converter.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "KX_ketsji"=..\gameengine\ketsji\KX_ketsji.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "KX_network"=..\gameengine\ketsji\network\KX_network.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "NG_loopbacknetwork"=..\gameengine\network\loopbacknetwork\NG_loopbacknetwork.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "NG_network"=..\gameengine\network\network\NG_network.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "PHY_Dummy"=..\GAMEENGINE\PHYSICS\PHY_PHYSICS\PHY_Dummy\PHY_Dummy.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "PHY_Ode"=..\gameengine\physics\PHY_Physics\PHY_Ode\PHY_Ode.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "PHY_Physics"=..\gameengine\physics\PHY_Physics\PHY_Physics.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "PHY_Sumo"=..\gameengine\physics\PHY_Physics\PHY_Sumo\PHY_Sumo.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "RAS_openglrasterizer"=..\gameengine\rasterizer\openglrasterizer\RAS_openglrasterizer.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "RAS_rasterizer"=..\gameengine\rasterizer\RAS_rasterizer.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "SCA_GameLogic"=..\gameengine\gamelogic\SCA_GameLogic.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "SG_SceneGraph"=..\gameengine\scenegraph\SG_SceneGraph.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "SYS_system"=..\kernel\system\SYS_system.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "blender"=.\blender.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name BKE_blenkernel + End Project Dependency + Begin Project Dependency + Project_Dep_Name BL_avi + End Project Dependency + Begin Project Dependency + Project_Dep_Name BL_imbuf + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLI_blenlib + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_decrypt + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_encrypt + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_loader + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_sign + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_verify + End Project Dependency + Begin Project Dependency + Project_Dep_Name BRA_radiosity + End Project Dependency + Begin Project Dependency + Project_Dep_Name BRE_render + End Project Dependency + Begin Project Dependency + Project_Dep_Name DNA_makesdna + End Project Dependency + Begin Project Dependency + Project_Dep_Name EXP_expressions + End Project Dependency + Begin Project Dependency + Project_Dep_Name gen_messaging + End Project Dependency + Begin Project Dependency + Project_Dep_Name NG_loopbacknetwork + End Project Dependency + Begin Project Dependency + Project_Dep_Name NG_network + End Project Dependency + Begin Project Dependency + Project_Dep_Name RAS_openglrasterizer + End Project Dependency + Begin Project Dependency + Project_Dep_Name RAS_rasterizer + End Project Dependency + Begin Project Dependency + Project_Dep_Name SCA_GameLogic + End Project Dependency + Begin Project Dependency + Project_Dep_Name SG_SceneGraph + End Project Dependency + Begin Project Dependency + Project_Dep_Name SYS_system + End Project Dependency + Begin Project Dependency + Project_Dep_Name BL_src_pub + End Project Dependency + Begin Project Dependency + Project_Dep_Name blenpluginapi + End Project Dependency + Begin Project Dependency + Project_Dep_Name BL_src + End Project Dependency + Begin Project Dependency + Project_Dep_Name SND_OpenAL + End Project Dependency + Begin Project Dependency + Project_Dep_Name PHY_Dummy + End Project Dependency + Begin Project Dependency + Project_Dep_Name PHY_Physics + End Project Dependency + Begin Project Dependency + Project_Dep_Name FTF_ftfont + End Project Dependency + Begin Project Dependency + Project_Dep_Name BPY_python + End Project Dependency + Begin Project Dependency + Project_Dep_Name PHY_Sumo + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_readblenfile + End Project Dependency + Begin Project Dependency + Project_Dep_Name Bullet + End Project Dependency + Begin Project Dependency + Project_Dep_Name BulletDynamics + End Project Dependency +}}} + +############################################################################### + +Project: "blenpluginapi"=.\blenpluginapi\blenpluginapi\blenpluginapi.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "gen_messaging"=..\KERNEL\gen_messaging\gen_messaging.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/projectfiles/blender/blenkernel/BKE_blenkernel.dsp b/projectfiles/blender/blenkernel/BKE_blenkernel.dsp new file mode 100644 index 00000000000..171bfab7dad --- /dev/null +++ b/projectfiles/blender/blenkernel/BKE_blenkernel.dsp @@ -0,0 +1,564 @@ +# Microsoft Developer Studio Project File - Name="BKE_blenkernel" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BKE_blenkernel - Win32 Release +!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 "BKE_blenkernel.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 "BKE_blenkernel.mak" CFG="BKE_blenkernel - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BKE_blenkernel - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BKE_blenkernel - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "BKE_blenkernel - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "BKE_blenkernel - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BKE_blenkernel - 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 "..\..\..\obj\windows\blender\blenkernel" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\blenkernel" +# PROP Target_Dir "" +MTL=midl.exe +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\decimation\include" /I "../../../../lib/windows/zlib/include" /I "..\..\..\intern\elbeem\extern" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\blenlib" /I "../../../source/gameengine\SoundSystem\\" /I "../../../../lib/windows/iksolver/include" /I "../../../../lib/windows/bsp/include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "WITH_FREETYPE2" /D "USE_CCGSUBSURFLIB" /YX /J /FD /c +# 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 + +!ELSEIF "$(CFG)" == "BKE_blenkernel - 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 "..\..\..\obj\windows\blender\blenkernel\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\blenkernel\debug" +# PROP Target_Dir "" +MTL=midl.exe +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\decimation\include" /I "../../../../lib/windows/zlib/include" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\blenlib" /I "../../../source/gameengine\SoundSystem\\" /I "../../../../lib/windows/iksolver/include" /I "../../../../lib/windows/bsp/include" /I "..\..\..\intern\elbeem\extern" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "WITH_FREETYPE2" /YX /J /FD /GZ /c +# 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 + +!ELSEIF "$(CFG)" == "BKE_blenkernel - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "BKE_blenkernel___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "BKE_blenkernel___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\blenkernel\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\blenkernel\mtdll_debug" +# PROP Target_Dir "" +MTL=midl.exe +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\soundsystem" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\gameengine\soundsystem\snd_blenderwavecache" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# SUBTRACT BASE CPP /WX +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\source\blenloader" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\blenlib" /I "../../../source/gameengine\SoundSystem\\" /I "../../../../lib/windows/iksolver/include" /I "../../../../lib/windows/bsp/include" /I "..\..\..\intern\elbeem\extern" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# SUBTRACT CPP /WX +# 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 /out:"..\..\..\..\..\obj\windows\blender\blenkernel\debug\BKE_blenkernel.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BKE_blenkernel - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "BKE_blenkernel___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "BKE_blenkernel___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\blenkernel\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\blenkernel\mtdll" +# PROP Target_Dir "" +MTL=midl.exe +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\soundsystem" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\gameengine\soundsystem\snd_blenderwavecache" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\source\gameengine\soundsystem" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\gameengine\soundsystem\snd_blenderwavecache" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\blenlib" /I "../../../source/gameengine\SoundSystem\\" /I "../../../../lib/windows/iksolver/include" /I "../../../../lib/windows/bsp/include" /I "..\..\..\intern\elbeem\extern" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 /out:"..\..\..\..\..\obj\windows\blender\blenkernel\BKE_blenkernel.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "BKE_blenkernel - Win32 Release" +# Name "BKE_blenkernel - Win32 Debug" +# Name "BKE_blenkernel - Win32 MT DLL Debug" +# Name "BKE_blenkernel - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\action.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\idprop.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\anim.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\armature.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\blender.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\bmfont.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\brush.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\CCGSubSurf.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\cdderivedmesh.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\colortools.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\constraint.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\curve.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\customdata.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\deform.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\depsgraph.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\DerivedMesh.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\displist.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\effect.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\exotic.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\font.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\group.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\icons.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\image.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\ipo.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\key.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\lattice.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\library.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\material.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\mball.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\mesh.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\modifier.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\nla.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\node.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\node_composite.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\node_shaders.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\object.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\packedFile.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\property.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\sca.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\scene.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\screen.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\script.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\softbody.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\sound.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\subsurf_ccg.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\text.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\texture.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\world.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\writeavi.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\writeframeserver.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_action.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_anim.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_armature.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_bad_level_calls.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_blender.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_bmfont.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_bmfont_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_booleanops.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_booleanops_mesh.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_brush.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_cdderivedmesh.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_constraint.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_curve.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_customdata.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_deform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_depsgraph.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_DerivedMesh.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_displist.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_effect.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_endian.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_exotic.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_font.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_global.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_group.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_image.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_ipo.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_key.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_lattice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_library.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_main.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_material.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_mball.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_mesh.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_modifier.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_nla.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_object.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_packedFile.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_plugin_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_property.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_sca.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_scene.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_screen.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_script.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_softbody.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_sound.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_subsurf.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_text.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_texture.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_utildefines.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_world.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_writeavi.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\CCGSubSurf.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\depsgraph_private.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/blenlib/BLI_blenlib.dsp b/projectfiles/blender/blenlib/BLI_blenlib.dsp new file mode 100644 index 00000000000..137725d3f7f --- /dev/null +++ b/projectfiles/blender/blenlib/BLI_blenlib.dsp @@ -0,0 +1,318 @@ +# Microsoft Developer Studio Project File - Name="BLI_blenlib" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BLI_blenlib - Win32 Release +!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 "BLI_blenlib.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 "BLI_blenlib.mak" CFG="BLI_blenlib - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BLI_blenlib - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BLI_blenlib - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "BLI_blenlib - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "BLI_blenlib - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BLI_blenlib - 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 "..\..\..\obj\windows\blender\blenlib" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\blenlib" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\..\lib\windows\freetype\include" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\makesdna" /I "../../../../lib/windows/zlib/include" /I "..\..\..\..\lib\windows\sdl\include" /I "..\..\..\..\lib\windows\pthreads\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "WITH_FREETYPE2" /J /FD /c +# 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 + +!ELSEIF "$(CFG)" == "BLI_blenlib - 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 "..\..\..\obj\windows\blender\blenlib\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\blenlib\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\..\lib\windows\freetype\include" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\makesdna" /I "../../../../lib/windows/zlib/include" /I "..\..\..\..\lib\windows\sdl\include" /I "..\..\..\..\lib\windows\pthreads\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "WITH_FREETYPE2" /J /FD /GZ /c +# 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 + +!ELSEIF "$(CFG)" == "BLI_blenlib - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "BLI_blenlib___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "BLI_blenlib___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\blenlib\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\blenlib\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\makesdna" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\makesdna" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# 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 /out:"..\..\..\..\..\obj\windows\blender\blenlib\debug\BLI_blenlib.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BLI_blenlib - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "BLI_blenlib___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "BLI_blenlib___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\blenlib\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\blenlib\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\makesdna" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\makesdna" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 /out:"..\..\..\..\..\obj\windows\blender\blenlib\BLI_blenlib.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "BLI_blenlib - Win32 Release" +# Name "BLI_blenlib - Win32 Debug" +# Name "BLI_blenlib - Win32 MT DLL Debug" +# Name "BLI_blenlib - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\arithb.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\BLI_dynstr.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\BLI_ghash.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\BLI_heap.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\BLI_linklist.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\BLI_memarena.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\dynlib.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\edgehash.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\fileops.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\freetypefont.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\gsqueue.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\jitter.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\matrixops.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\noise.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\psfont.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\rand.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\rct.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\scanfill.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\storage.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\threads.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\time.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\util.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\vectorops.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\winstuff.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\BLI_arithb.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\BLI_blenlib.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\BLI_callbacks.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\BLI_edgehash.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\BLI_editVert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\BLI_fileops.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\BLI_ghash.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\BLI_linklist.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\BLI_memarena.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\BLI_scanfill.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\BLI_storage.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\BLI_storage_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\BLI_util.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\BLI_winstuff.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\MTC_matrixops.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\MTC_vectorops.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\PIL_dynlib.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\PIL_time.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/blenpluginapi/blenpluginapi/blenpluginapi.dsp b/projectfiles/blender/blenpluginapi/blenpluginapi/blenpluginapi.dsp new file mode 100644 index 00000000000..6b219ffad19 --- /dev/null +++ b/projectfiles/blender/blenpluginapi/blenpluginapi/blenpluginapi.dsp @@ -0,0 +1,119 @@ +# Microsoft Developer Studio Project File - Name="blenpluginapi" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=blenpluginapi - Win32 Release +!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 "blenpluginapi.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 "blenpluginapi.mak" CFG="blenpluginapi - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "blenpluginapi - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "blenpluginapi - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "blenpluginapi - 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 "..\..\..\..\obj\windows\blender\blenpluginapi" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\blender\blenpluginapi" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\..\source\blender" /I "..\..\..\..\source\blender\blenpluginapi" /I "..\..\..\..\source\blender\blenlib" /I "..\..\..\..\source\blender\imbuf" /I "..\..\..\..\source\blender\makesdna" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# 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:"..\..\..\..\obj\windows\blender\blenpluginapi.lib" + +!ELSEIF "$(CFG)" == "blenpluginapi - 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 "..\..\..\..\obj\windows\blender\blenpluginapi\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\blender\blenpluginapi\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\..\source\blender" /I "..\..\..\..\source\blender\blenpluginapi" /I "..\..\..\..\source\blender\blenlib" /I "..\..\..\..\source\blender\imbuf" /I "..\..\..\..\source\blender\makesdna" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# SUBTRACT CPP /X +# 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:"..\..\..\..\obj\windows\blender\debug\blenpluginapi.lib" + +!ENDIF + +# Begin Target + +# Name "blenpluginapi - Win32 Release" +# Name "blenpluginapi - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\blender\blenpluginapi\intern\pluginapi.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\blender\blenpluginapi\documentation.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\blender\blenpluginapi\floatpatch.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\blender\blenpluginapi\iff.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\blender\blenpluginapi\plugin.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\blender\blenpluginapi\util.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/ftfont/FTF_ftfont.dsp b/projectfiles/blender/ftfont/FTF_ftfont.dsp new file mode 100644 index 00000000000..7ecd50aa75f --- /dev/null +++ b/projectfiles/blender/ftfont/FTF_ftfont.dsp @@ -0,0 +1,118 @@ +# Microsoft Developer Studio Project File - Name="FTF_ftfont" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=FTF_ftfont - 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 "FTF_ftfont.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 "FTF_ftfont.mak" CFG="FTF_ftfont - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "FTF_ftfont - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "FTF_ftfont - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "FTF_ftfont - 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 "..\..\..\obj\windows\blender\ftfont" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\ftfont" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "../../../source\blender\makesdna" /I "../../../source\blender\blenloader" /I "../../../source\blender\blenlib" /I "../../../../lib/windows/ftgl/include" /I "../../../../lib/windows/freetype/include" /I "../../../lib/windows/iconv/include" /I "../../../../lib/windows/gettext/include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "WCHAR_T16" /D "HAVE_LC_MESSAGES" /YX /FD /c +# ADD BASE RSC /l 0x411 /d "NDEBUG" +# ADD RSC /l 0x411 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "FTF_ftfont - 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 "..\..\..\obj\windows\blender\ftfont" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\ftfont" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../../source\blender\blenlib" /I "../../../source\blender\makesdna" /I "../../../../lib/windows/ftgl/include" /I "../../../../lib/windows/freetype/include" /I "../../../lib/windows/iconv/include" /I "../../../../lib/windows/gettext/include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "WCHAR_T16" /D "HAVE_LC_MESSAGES" /D "FTGL_LIBRARY_STATIC" /YX /FD /GZ /c +# ADD BASE RSC /l 0x411 /d "_DEBUG" +# ADD RSC /l 0x411 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "FTF_ftfont - Win32 Release" +# Name "FTF_ftfont - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\ftfont\intern\FTF_Api.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\ftfont\intern\FTF_TTFont.cpp +# End Source File +# End Group +# Begin Group "extern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\source\blender\ftfont\FTF_Api.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\ftfont\FTF_Settings.h +# End Source File +# End Group +# Begin Group "intern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\source\blender\ftfont\intern\FTF_TTFont.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/glut/BL_glut.dsp b/projectfiles/blender/glut/BL_glut.dsp new file mode 100644 index 00000000000..2e351603e67 --- /dev/null +++ b/projectfiles/blender/glut/BL_glut.dsp @@ -0,0 +1,324 @@ +# Microsoft Developer Studio Project File - Name="BL_glut" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BL_glut - Win32 Profile +!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 "BL_glut.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 "BL_glut.mak" CFG="BL_glut - Win32 Profile" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BL_glut - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BL_glut - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "BL_glut - Win32 Profile" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BL_glut - 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 "..\..\..\..\obj\windows\blender\glut" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\source\blender\\" /I "..\..\..\..\lib\windows\glut-3.7\include" /I "..\..\..\source\blender\glut-win" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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:"..\..\..\..\obj\windows\blender\glut\BL_glut.lib" + +!ELSEIF "$(CFG)" == "BL_glut - 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 "..\..\..\..\obj\windows\blender\glut\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\glut-3.7\include" /I "..\..\..\source\blender\glut-win" /I "..\..\..\source\blender\\" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /FR /YX /J /FD /GZ /c +# 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:"..\..\..\..\obj\windows\blender\glut\debug\BL_glut.lib" + +!ELSEIF "$(CFG)" == "BL_glut - Win32 Profile" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "BL_glut___Win32_Profile" +# PROP BASE Intermediate_Dir "BL_glut___Win32_Profile" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "BL_glut___Win32_Profile" +# PROP Intermediate_Dir "BL_glut___Win32_Profile" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\..\lib\windows\glut-3.7\include" /I "..\..\..\source\blender\glut-win" /I "..\..\..\source\blender\\" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /O2 /I "..\..\..\..\lib\windows\glut-3.7\include" /I "..\..\..\source\blender\glut-win" /I "..\..\..\source\blender\\" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 /out:"..\..\..\..\obj\windows\blender\glut\debug\BL_glut.lib" +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\blender\glut\profile\BL_glut.lib" + +!ENDIF + +# Begin Target + +# Name "BL_glut - Win32 Release" +# Name "BL_glut - Win32 Debug" +# Name "BL_glut - Win32 Profile" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_8x13.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_9x15.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_bitmap.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_blender.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_bwidth.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_cindex.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_cmap.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_cursor.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_dials.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_draw.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_dstr.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_event.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_ext.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_fullscrn.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_get.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_hel10.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_hel12.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_hel18.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_helb10.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_helb12.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_helb14.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_helb8.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_init.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_input.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_mesa.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_modifier.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_mroman.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_overlay.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_roman.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_scr12.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_scr14.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_scr15.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_shapes.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_space.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_stroke.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_swap.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_swidth.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_tablet.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_teapot.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_tr10.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_tr24.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_util.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_vidresize.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_warp.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_win.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_winmisc.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\win32_glx.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\win32_menu.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\win32_util.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\win32_x11.c" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\glut\blenderglut.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/imbuf/BL_imbuf.dsp b/projectfiles/blender/imbuf/BL_imbuf.dsp new file mode 100644 index 00000000000..002426124b6 --- /dev/null +++ b/projectfiles/blender/imbuf/BL_imbuf.dsp @@ -0,0 +1,438 @@ +# Microsoft Developer Studio Project File - Name="BL_imbuf" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BL_imbuf - Win32 Release +!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 "BL_imbuf.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 "BL_imbuf.mak" CFG="BL_imbuf - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BL_imbuf - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BL_imbuf - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "BL_imbuf - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "BL_imbuf - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BL_imbuf - 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 "..\..\..\obj\windows\blender\imbuf" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\imbuf" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\source\blender\imbuf\intern" /I "..\..\..\source\blender\quicktime" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\makesdna" /I "..\..\..\..\lib\windows\memutil\include" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\include" /I "..\..\..\..\lib\windows\jpeg\include" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\..\lib\windows\png\include" /I "..\..\..\..\lib\windows\tiff\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "WITH_QUICKTIME" /YX /J /FD /c +# 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 + +!ELSEIF "$(CFG)" == "BL_imbuf - 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 "..\..\..\obj\windows\blender\imbuf\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\imbuf\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\source\blender\imbuf\intern" /I "..\..\..\source\blender\quicktime" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\makesdna" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\include" /I "..\..\..\..\lib\windows\jpeg\include" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\..\lib\windows\png\include" /I "..\..\..\..\lib\windows\memutil\include" /I "..\..\..\..\lib\windows\tiff\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "WITH_QUICKTIME" /YX /FD /I /GZ /c +# 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 + +!ELSEIF "$(CFG)" == "BL_imbuf - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "BL_imbuf___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "BL_imbuf___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\imbuf\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\imbuf\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\include" /I "..\..\..\..\lib\windows\jpeg\include" /I "..\..\..\source\blender\makesdna" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\source\blender\makesdna..\..\..\lib\windows\\" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\include" /I "..\..\..\..\lib\windows\jpeg\include" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\..\lib\windows\png\include" /I "..\..\..\..\lib\windows\memutil\include" /I "..\..\..\..\lib\windows\tiff\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# 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 /out:"..\..\..\..\..\obj\windows\blender\imbuf\debug\BL_imbuf.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BL_imbuf - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "BL_imbuf___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "BL_imbuf___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\imbuf\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\imbuf\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\include" /I "..\..\..\..\lib\windows\jpeg\include" /I "..\..\..\source\blender\makesdna" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\source\blender\makesdna..\..\..\lib\windows\\" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\include" /I "..\..\..\..\lib\windows\jpeg\include" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\..\lib\windows\png\include" /I "..\..\..\..\lib\windows\memutil\include" /I "..\..\..\..\lib\windows\tiff\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 /out:"..\..\..\..\..\obj\windows\blender\imbuf\BL_imbuf.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "BL_imbuf - Win32 Release" +# Name "BL_imbuf - Win32 Debug" +# Name "BL_imbuf - Win32 MT DLL Debug" +# Name "BL_imbuf - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\allocimbuf.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\amiga.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\anim.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\anim5.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\antialias.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\bitplanes.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\bmp.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\cineon_dpx.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\cineonlib.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cmap.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cspace.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\data.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\dither.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\divers.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\dpxlib.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\dynlibtiff.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\filter.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\ham.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\hamx.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\iff.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\imageprocess.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\iris.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\jpeg.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\logImageCore.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\logImageLib.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\logmemfile.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\png.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\quicktime\apple\quicktime_export.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\quicktime\apple\quicktime_import.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\radiance_hdr.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\readimage.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\rectop.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\rotate.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\scaling.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\targa.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\tiff.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\util.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\writeimage.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\cin_debug_stuff.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\cineonfile.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\cineonlib.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\dpxfile.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\dpxlib.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\dynlibtiff.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_allocimbuf.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_amiga.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_anim.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_anim5.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_bitplanes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_bmp.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_cmap.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_divers.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_filter.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_ham.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_hamx.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_iff.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\IMB_imbuf.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\IMB_imbuf_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_iris.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_jpeg.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_png.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_radiance_hdr.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_targa.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_tiff.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\imbuf.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\imbuf_patch.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\logImageCore.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\logImageLib.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\logmemfile.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\matrix.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\quicktime\quicktime_export.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\quicktime\quicktime_import.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/img/BL_img.dsp b/projectfiles/blender/img/BL_img.dsp new file mode 100644 index 00000000000..16f0827fbe9 --- /dev/null +++ b/projectfiles/blender/img/BL_img.dsp @@ -0,0 +1,171 @@ +# Microsoft Developer Studio Project File - Name="BL_img" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BL_IMG - 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 "BL_img.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 "BL_img.mak" CFG="BL_IMG - WIN32 DEBUG" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BL_img - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BL_img - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BL_img - 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 "..\..\..\obj\windows\blender\img" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\img" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 + +!ELSEIF "$(CFG)" == "BL_img - 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 "..\..\..\obj\windows\blender\img\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\img\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# SUBTRACT CPP /Fr +# 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 + +!ENDIF + +# Begin Target + +# Name "BL_img - Win32 Release" +# Name "BL_img - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_Api.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_BrushRGBA32.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_CanvasRGBA32.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_Line.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_Pixmap.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_PixmapRGBA32.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_Rect.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Group "intern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_BrushRGBA32.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_CanvasRGBA32.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_Color.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_Line.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_MemPtr.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_Pixmap.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_PixmapRGBA32.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_Rect.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_Types.h +# End Source File +# End Group +# Begin Group "extern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\source\blender\img\IMG_Api.h +# End Source File +# End Group +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/loader/BLO_loader.dsp b/projectfiles/blender/loader/BLO_loader.dsp new file mode 100644 index 00000000000..13b32246652 --- /dev/null +++ b/projectfiles/blender/loader/BLO_loader.dsp @@ -0,0 +1,186 @@ +# Microsoft Developer Studio Project File - Name="BLO_loader" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BLO_loader - Win32 Release +!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 "BLO_loader.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 "BLO_loader.mak" CFG="BLO_loader - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BLO_loader - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BLO_loader - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "BLO_loader - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "BLO_loader - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BLO_loader - 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 "..\..\..\obj\windows\blender\loader" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\loader" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\source\blender\blenloader" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\streamglue\\" /I "..\..\..\source\blender\readblenfile\\" /I "..\..\..\source\blender\writeblenfile\\" /I "..\..\..\source\blender\deflate\\" /I "..\..\..\source\blender\inflate\\" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\source\blender\readblenfile" /I "..\..\..\source\kernel\gen_messaging" /I "..\..\..\source\blender\readstreamglue" /I "..\..\..\source\blender\writestreamglue" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\python" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 + +!ELSEIF "$(CFG)" == "BLO_loader - 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 "..\..\..\obj\windows\blender\loader\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\loader\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender\streamglue\\" /I "..\..\..\source\blender\readblenfile\\" /I "..\..\..\source\blender\writeblenfile\\" /I "..\..\..\source\blender\deflate\\" /I "..\..\..\source\blender\inflate\\" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\source\blender\readblenfile" /I "..\..\..\source\kernel\gen_messaging" /I "..\..\..\source\blender\readstreamglue" /I "..\..\..\source\blender\writestreamglue" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\python" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# SUBTRACT CPP /Fr +# 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 + +!ELSEIF "$(CFG)" == "BLO_loader - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "BLO_loader___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "BLO_loader___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\loader\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\loader\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\python" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender\streamglue\\" /I "..\..\..\source\blender\readblenfile\\" /I "..\..\..\source\blender\writeblenfile\\" /I "..\..\..\source\blender\deflate\\" /I "..\..\..\source\blender\inflate\\" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\source\blender\readblenfile" /I "..\..\..\source\kernel\gen_messaging" /I "..\..\..\source\blender\readstreamglue" /I "..\..\..\source\blender\writestreamglue" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\python" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# 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 /out:"..\..\..\..\..\obj\windows\blender\loader\debug\BLO_loader.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BLO_loader - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "BLO_loader___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "BLO_loader___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\loader\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\loader\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\python" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender\streamglue\\" /I "..\..\..\source\blender\readblenfile\\" /I "..\..\..\source\blender\writeblenfile\\" /I "..\..\..\source\blender\deflate\\" /I "..\..\..\source\blender\inflate\\" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\source\blender\readblenfile" /I "..\..\..\source\kernel\gen_messaging" /I "..\..\..\source\blender\readstreamglue" /I "..\..\..\source\blender\writestreamglue" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\python" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 /out:"..\..\..\..\..\obj\windows\blender\loader\BLO_loader.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "BLO_loader - Win32 Release" +# Name "BLO_loader - Win32 Debug" +# Name "BLO_loader - Win32 MT DLL Debug" +# Name "BLO_loader - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\blenloader\intern\genfile.c +# ADD CPP /I "..\..\..\source\blender" +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenloader\intern\readblenentry.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenloader\intern\readfile.c +# ADD CPP /I "..\..\..\source\blender" +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenloader\intern\undofile.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenloader\intern\writefile.c +# ADD CPP /I "..\..\..\source\blender" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\blenloader\BLO_genfile.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenloader\BLO_readfile.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenloader\BLO_soundfile.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenloader\BLO_undofile.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/makesdna/DNA_makesdna.dsp b/projectfiles/blender/makesdna/DNA_makesdna.dsp new file mode 100644 index 00000000000..993968c2f6d --- /dev/null +++ b/projectfiles/blender/makesdna/DNA_makesdna.dsp @@ -0,0 +1,373 @@ +# Microsoft Developer Studio Project File - Name="DNA_makesdna" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=DNA_makesdna - Win32 Release +!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 "DNA_makesdna.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 "DNA_makesdna.mak" CFG="DNA_makesdna - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "DNA_makesdna - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "DNA_makesdna - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "DNA_makesdna - Win32 MT DLL Release" (based on "Win32 (x86) Console Application") +!MESSAGE "DNA_makesdna - Win32 MT DLL Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "DNA_makesdna - 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 "..\..\..\source\blender\makesdna\intern" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\makesdna" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo /o"DNA_makesdna.bsc" +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 libguardedalloc.a BLI_blenlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:"DNA_makesdna.pdb" /machine:I386 /nodefaultlib:"libc.lib" /libpath:"..\..\..\..\lib\windows\guardedalloc\lib" /libpath:"..\..\..\obj\windows\blender\blenlib" +# SUBTRACT LINK32 /pdb:none +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Desc=Building DNA +PostBuild_Cmds=CD ..\..\..\source\blender\makesdna\intern\ DNA_makesdna.exe dna.c +# End Special Build Tool + +!ELSEIF "$(CFG)" == "DNA_makesdna - 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 "..\..\..\source\blender\makesdna\intern" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\makesdna\debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /J /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo /o"DNA_makesdna.bsc" +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 libguardedalloc.a BLI_blenlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:"DNA_makesdna.pdb" /debug /machine:I386 /nodefaultlib:"libc.lib" /pdbtype:sept /libpath:"..\..\..\..\lib\windows\guardedalloc\lib\debug" /libpath:"..\..\..\obj\windows\blender\blenlib\debug" +# SUBTRACT LINK32 /pdb:none +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Desc=Building DNA +PostBuild_Cmds=CD ..\..\..\source\blender\makesdna\intern\ DNA_makesdna.exe dna.c +# End Special Build Tool + +!ELSEIF "$(CFG)" == "DNA_makesdna - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "DNA_makesdna___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "DNA_makesdna___Win32_MT_DLL_Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\source\blender\makesdna\intern" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\makesdna\mtdll" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /J /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo /o"DNA_makesdna.bsc" +# ADD BSC32 /nologo /o"DNA_makesdna.bsc" +LINK32=link.exe +# ADD BASE LINK32 BLI_blenlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:"DNA_makesdna.pdb" /machine:I386 /out:"..\..\..\source\blender\makesdna\intern\DNA_makesdna.exe" /libpath:"..\..\..\..\obj\windows\blender\blenlib" +# SUBTRACT BASE LINK32 /pdb:none +# ADD LINK32 libguardedalloc.a /nologo /subsystem:console /pdb:"DNA_makesdna.pdb" /machine:I386 /libpath:"..\..\..\..\lib\windows\guardedalloc\lib" /libpath:"..\..\..\..\obj\windows\blender\blenlib" +# SUBTRACT LINK32 /pdb:none +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=CD ..\..\..\source\blender\makesdna\intern\ DNA_makesdna.exe dna.c +# End Special Build Tool + +!ELSEIF "$(CFG)" == "DNA_makesdna - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "DNA_makesdna___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "DNA_makesdna___Win32_MT_DLL_Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\source\blender\makesdna\intern" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\makesdna\mtdll_debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo /o"DNA_makesdna.bsc" +# ADD BSC32 /nologo /o"DNA_makesdna.bsc" +LINK32=link.exe +# ADD BASE LINK32 BLI_blenlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:"DNA_makesdna.pdb" /debug /machine:I386 /out:"..\..\..\source\blender\makesdna\debug\DNA_makesdna.exe" /pdbtype:sept /libpath:"..\..\..\..\obj\windows\blender\blenlib\debug" +# SUBTRACT BASE LINK32 /pdb:none +# ADD LINK32 libguardedalloc.a /nologo /subsystem:console /pdb:"DNA_makesdna.pdb" /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\..\lib\windows\guardedalloc\lib" +# SUBTRACT LINK32 /pdb:none +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=CD ..\..\..\source\blender\makesdna\intern\ DNA_makesdna.exe dna.c +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "DNA_makesdna - Win32 Release" +# Name "DNA_makesdna - Win32 Debug" +# Name "DNA_makesdna - Win32 MT DLL Release" +# Name "DNA_makesdna - Win32 MT DLL Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\intern\makesdna.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_action_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_actuator_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_armature_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_camera_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_constraint_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_controller_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_curve_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_customdata_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_documentation.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_effect_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_fileglobal_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_group_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_ID.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_image_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_ipo_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_key_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_lamp_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_lattice_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_listBase.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_material_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_mesh_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_meshdata_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_meta_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_modifier_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_nla_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_object_force.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_object_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_oops_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_packedFile_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_property_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_radio_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_scene_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_screen_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_scriptlink_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_sdna_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_sensor_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_sequence_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_sound_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_space_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_text_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_texture_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_userdef_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_vec_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_vfont_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_view2d_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_view3d_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_wave_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_world_types.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/radiosity/BRA_radiosity.dsp b/projectfiles/blender/radiosity/BRA_radiosity.dsp new file mode 100644 index 00000000000..be9e33e311f --- /dev/null +++ b/projectfiles/blender/radiosity/BRA_radiosity.dsp @@ -0,0 +1,133 @@ +# Microsoft Developer Studio Project File - Name="BRA_radiosity" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BRA_radiosity - Win32 Release +!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 "BRA_radiosity.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 "BRA_radiosity.mak" CFG="BRA_radiosity - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BRA_radiosity - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BRA_radiosity - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BRA_radiosity - 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 "..\..\..\obj\windows\blender\radiosity" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\radiosity" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\radiosity\extern\include" /I "..\..\..\source\blender" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\misc" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\render\intern\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 + +!ELSEIF "$(CFG)" == "BRA_radiosity - 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 "..\..\..\obj\windows\blender\radiosity\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\radiosity\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\radiosity\extern\include" /I "..\..\..\source\blender" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\misc" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\render\intern\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# SUBTRACT CPP /Fr +# 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 + +!ENDIF + +# Begin Target + +# Name "BRA_radiosity - Win32 Release" +# Name "BRA_radiosity - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\radiosity\intern\source\raddisplay.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\radiosity\intern\source\radfactors.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\radiosity\intern\source\radio.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\radiosity\intern\source\radnode.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\radiosity\intern\source\radpostprocess.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\radiosity\intern\source\radpreprocess.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\radiosity\intern\source\radrender.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\radiosity\extern\include\radio.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\radiosity\extern\include\radio_types.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/render/BRE_render.dsp b/projectfiles/blender/render/BRE_render.dsp new file mode 100644 index 00000000000..7d29bce934c --- /dev/null +++ b/projectfiles/blender/render/BRE_render.dsp @@ -0,0 +1,192 @@ +# Microsoft Developer Studio Project File - Name="BRE_render" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BRE_render - Win32 Release +!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 "BRE_render.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 "BRE_render.mak" CFG="BRE_render - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BRE_render - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BRE_render - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BRE_render - 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 "..\..\..\obj\windows\blender\render" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\render" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\..\lib\windows\sdl\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\kernel\gen_messaging" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\quicktime" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\misc" /I "..\..\..\source\kernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\radiosity\extern\include" /I "..\..\..\source\blender\render\intern\include" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender" /I "..\..\..\source\blender\yafray" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "WITH_QUICKTIME" /YX /J /FD /c +# 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 + +!ELSEIF "$(CFG)" == "BRE_render - 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 "..\..\..\obj\windows\blender\render\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\render\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\..\lib\windows\sdl\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\kernel\gen_messaging" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\quicktime" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\misc" /I "..\..\..\source\kernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\radiosity\extern\include" /I "..\..\..\source\blender\render\intern\include" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender" /I "..\..\..\source\blender\yafray" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "WITH_QUICKTIME" /YX /J /FD /GZ /c +# 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 + +!ENDIF + +# Begin Target + +# Name "BRE_render - Win32 Release" +# Name "BRE_render - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\convertblender.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\envmap.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\gammaCorrectionTables.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\imagetexture.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\initrender.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\pipeline.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\pixelblending.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\pixelshading.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\ray.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\rendercore.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\renderdatabase.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\shadbuf.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\texture.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\zbuf.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\include\edgeRender.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\include\envmap.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\include\gammaCorrectionTables.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\include\initrender.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\include\pixelblending.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\include\pixelshading.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\include\rendercore.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\include\shadbuf.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\include\texture.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\include\zbuf.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/renderconverter/BRE_renderconverter.dsp b/projectfiles/blender/renderconverter/BRE_renderconverter.dsp new file mode 100644 index 00000000000..4b3729061a8 --- /dev/null +++ b/projectfiles/blender/renderconverter/BRE_renderconverter.dsp @@ -0,0 +1,102 @@ +# Microsoft Developer Studio Project File - Name="BRE_renderconverter" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BRE_renderconverter - Win32 Release +!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 "BRE_renderconverter.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 "BRE_renderconverter.mak" CFG="BRE_renderconverter - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BRE_renderconverter - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BRE_renderconverter - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BRE_renderconverter - 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 "..\..\..\obj\windows\blender\renderconverter" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\renderconverter" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\yafray" /I "..\..\..\source\blender\radiosity\extern\include" /I "..\..\..\source\blender\misc" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\render\extern\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BRE_renderconverter - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "BRE_renderconverter___Win32_Debug" +# PROP BASE Intermediate_Dir "BRE_renderconverter___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\render\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\render\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\yafray" /I "..\..\..\source\blender\radiosity\extern\include" /I "..\..\..\source\blender\misc" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\render\extern\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\obj\windows\blender\renderconverter\debug\BRE_renderconverter.lib" + +!ENDIF + +# Begin Target + +# Name "BRE_renderconverter - Win32 Release" +# Name "BRE_renderconverter - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\renderconverter\intern\convertBlenderScene.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\renderconverter\RE_renderconverter.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/src/BL_src.dsp b/projectfiles/blender/src/BL_src.dsp new file mode 100644 index 00000000000..d6a1c3945e9 --- /dev/null +++ b/projectfiles/blender/src/BL_src.dsp @@ -0,0 +1,1040 @@ +# Microsoft Developer Studio Project File - Name="BL_src" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BL_SRC - 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 "BL_src.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 "BL_src.mak" CFG="BL_SRC - WIN32 DEBUG" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BL_src - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BL_src - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BL_src - 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 "..\..\..\obj\windows\blender\src" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\src" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\sdl\include\\" /I "..\..\..\source\blender\img" /I "..\..\..\source\blender\renderui" /I "..\..\..\..\lib\windows\soundsystem\include\\" /I "..\..\..\..\lib\windows\python\include\python2.0\\" /I "..\..\..\..\lib\windows\bmfont\include" /I "..\..\..\source\blender\ftfont" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\verify" /I "..\..\..\source\blender\readstreamglue" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender\quicktime" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\misc" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\radiosity\extern\include" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\gameengine\network" /I "..\..\..\..\lib\windows\decimation\include" /I "..\..\..\source\blender\blenpluginapi\\" /I "..\..\..\..\lib\windows\blenkey\include" /I "..\..\..\..\lib\windows\ghost\include" /I "..\..\..\..\lib\windows\bsp\include" /I "..\..\..\..\lib\windows\opennl\include" /I "..\..\..\intern\elbeem\extern" /I "..\..\..\..\lib\windows\memutil\include" /I "..\..\..\..\lib\windows\pthreads\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "_CONSOLE" /D "xGAMEBLENDER" /D "WITH_QUICKTIME" /D "INTERNATIONAL" /FR /J /FD /c +# 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 + +!ELSEIF "$(CFG)" == "BL_src - 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 "..\..\..\obj\windows\blender\src\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\src\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\sdl\include\\" /I "..\..\..\source\blender\img" /I "..\..\..\source\blender\renderui" /I "..\..\..\..\lib\windows\soundsystem\include\\" /I "..\..\..\..\lib\windows\python\include\python2.0\\" /I "..\..\..\..\lib\windows\bmfont\include" /I "..\..\..\source\blender\ftfont" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\verify" /I "..\..\..\source\blender\readstreamglue" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender\quicktime" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\misc" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\radiosity\extern\include" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\gameengine\network" /I "..\..\..\..\lib\windows\decimation\include" /I "..\..\..\source\blender\blenpluginapi\\" /I "..\..\..\..\lib\windows\blenkey\include" /I "..\..\..\..\lib\windows\ghost\include" /I "..\..\..\..\lib\windows\bsp\include" /I "..\..\..\..\lib\windows\opennl\include" /I "..\..\..\intern\elbeem\extern" /I "..\..\..\..\lib\windows\memutil\include" /I "..\..\..\..\lib\windows\pthreads\include" /D "WIN32" /D "_MBCS" /D "_LIB" /D "_CONSOLE" /D "xGAMEBLENDER" /D "WITH_QUICKTIME" /D "INTERNATIONAL" /U "_DEBUG" /J /FD /GZ /c +# 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 + +!ENDIF + +# Begin Target + +# Name "BL_src - Win32 Release" +# Name "BL_src - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\src\B.blend.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\Bfont.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\bfont.ttf.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\blenderbuttons.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\booleanops.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\booleanops_mesh.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\butspace.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\buttons_editing.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\buttons_logic.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\buttons_object.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\buttons_scene.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\buttons_script.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\buttons_shading.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\cmap.tga.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\cmovie.tga.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\cursors.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\intern\dna.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawaction.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawarmature.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawdeps.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawimage.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawimasel.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawipo.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawmesh.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawnla.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawnode.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawobject.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawoops.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawscene.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawscript.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawseq.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawsound.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawtext.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawtime.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawview.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\edit.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editaction.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editarmature.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editconstraint.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editcurve.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editdeform.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editface.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editfont.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editgroup.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editimasel.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editipo.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editipo_lib.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editipo_mods.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editkey.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editlattice.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editmball.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editmesh.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editmesh_add.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editmesh_lib.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editmesh_loop.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editmesh_mods.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editmesh_tools.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editmode_undo.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editnla.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editnode.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editobject.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editoops.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editscreen.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editseq.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editsima.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editsound.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\edittime.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editview.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\eventdebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\filesel.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\fluidsim.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\ghostwinlay.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\glutil.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\hddaudio.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_action.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_buttonswin.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_filesel.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_image.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_imasel.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_info.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_ipo.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_nla.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_node.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_oops.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_script.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_seq.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_sound.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_text.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_time.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_view3d.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\headerbuttons.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\imagepaint.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\imasel.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\interface.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\interface_draw.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\interface_icons.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\interface_panel.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\keyval.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\language.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\lorem.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\mainqueue.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\meshtools.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\multires.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\mywindow.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\oops.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\outliner.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\parametrizer.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\playanim.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenpluginapi\intern\pluginapi.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\poseobject.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\preview.blend.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\previewrender.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\renderwin.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\resources.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\retopo.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\scrarea.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\screendump.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\sculptmode.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\seqaudio.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\seqeffects.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\seqscopes.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\sequence.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\space.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\spacetypes.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\splash.jpg.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\swapbuffers.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\toets.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\toolbox.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\transform.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\transform_constraints.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\transform_conversions.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\transform_generics.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\transform_manipulator.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\transform_numinput.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\transform_snap.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\unwrapper.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\usiblender.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\view.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\vpaint.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\writeavicodec.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\writeimage.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\writemovie.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BDR_drawaction.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BDR_drawmesh.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BDR_drawobject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BDR_editcurve.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BDR_editface.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BDR_editmball.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BDR_editobject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BDR_sculptmode.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BDR_unwrapper.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BDR_vpaint.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_butspace.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_cursors.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_drawimage.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_drawoops.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_drawscene.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_drawscript.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_drawseq.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_drawtext.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editaction.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editarmature.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editconstraint.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editdeform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editfont.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editgroup.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editkey.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editlattice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editmesh.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editmode_undo.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editnla.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editoops.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editsca.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editseq.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editsima.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editsound.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editview.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_fsmenu.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_gl.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_glutil.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_graphics.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_imasel.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_interface.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_keyval.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_language.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_mainqueue.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_meshtools.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_mywindow.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_oops.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_outliner.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_poseobject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_previewrender.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_renderwin.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_resources.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_retopo.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_scrarea.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_screen.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_space.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_spacetypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_tbcallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_toets.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_toolbox.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_transform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_usiblender.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_writeavicodec.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_writeimage.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_writemovie.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\blendef.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BPI_script.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_buttons.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_drawimasel.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_drawipo.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_drawnla.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_drawoops.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_drawview.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_edit.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_editaction.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_editaction_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_editipo.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_editipo_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_editnla_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_filesel.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_headerbuttons.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_seqaudio.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_sequence.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_time.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_trans_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_view.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\butspace.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\editmesh.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\multires.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\parametrizer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\parametrizer_intern.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\transform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\winlay.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/src/BL_src_cre.dsp b/projectfiles/blender/src/BL_src_cre.dsp new file mode 100644 index 00000000000..1705b45a96f --- /dev/null +++ b/projectfiles/blender/src/BL_src_cre.dsp @@ -0,0 +1,102 @@ +# Microsoft Developer Studio Project File - Name="BL_src_cre" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BL_src_cre - Win32 Release +!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 "BL_src_cre.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 "BL_src_cre.mak" CFG="BL_src_cre - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BL_src_cre - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BL_src_cre - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BL_src_cre - 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 "..\..\..\obj\windows\blender\src_cre" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\src_cre" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\renderui" /I "..\..\..\source\gameengine\soundsystem\\" /I "..\..\..\..\lib\windows\python\include\python2.2\\" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\verify" /I "..\..\..\source\blender\readstreamglue" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\misc" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\radiosity\extern\include" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\gameengine\network" /I "..\..\..\..\lib\windows\decimation\include" /I "..\..\..\source\blender\blenpluginapi\\" /I "..\..\..\..\lib\windows\blenkey\include" /I "..\..\..\..\lib\windows\pthreads\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "_CONSOLE" /D "NAN_GAME" /D "GAME" /J /FD /c +# 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:"..\..\..\obj\windows\blender\src\BL_src_cre.lib" + +!ELSEIF "$(CFG)" == "BL_src_cre - 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 "..\..\..\obj\windows\blender\src_cre\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\src_cre\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\renderui" /I "..\..\..\source\gameengine\soundsystem\\" /I "..\..\..\..\lib\windows\python\include\python2.2\\" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\verify" /I "..\..\..\source\blender\readstreamglue" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\misc" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\radiosity\extern\include" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\gameengine\network" /I "..\..\..\..\lib\windows\decimation\include" /I "..\..\..\source\blender\blenpluginapi\\" /I "..\..\..\..\lib\windows\blenkey\include" /I "..\..\..\..\lib\windows\pthreads\include" /D "WIN32" /D "_MBCS" /D "_LIB" /D "_CONSOLE" /D "NAN_GAME" /D "GAME" /U "_DEBUG" /J /FD /GZ /c +# 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:"..\..\..\obj\windows\blender\src\debug\BL_src_cre.lib" + +!ENDIF + +# Begin Target + +# Name "BL_src_cre - Win32 Release" +# Name "BL_src_cre - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\src\cre\license.jpeg.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\cre\license_key.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/yafray/BRE_yafray.dsp b/projectfiles/blender/yafray/BRE_yafray.dsp new file mode 100644 index 00000000000..cf6d6ddc308 --- /dev/null +++ b/projectfiles/blender/yafray/BRE_yafray.dsp @@ -0,0 +1,134 @@ +# Microsoft Developer Studio Project File - Name="BRE_yafray" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BRE_yafray - 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 "BRE_yafray.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 "BRE_yafray.mak" CFG="BRE_yafray - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BRE_yafray - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BRE_yafray - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BRE_yafray - 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 "..\..\..\obj\windows\blender\yafray" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\yafray" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\misc" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\render\intern\include" /I "..\..\..\source\blender\imbuf" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BRE_yafray - 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 "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\misc" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\render\intern\include" /I "..\..\..\source\blender\imbuf" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /Fp"..\..\..\obj\windows\blender\render\debug/BRE_yafray.pch" /YX /Fo"..\..\..\obj\windows\blender\render\debug/" /Fd"..\..\..\obj\windows\blender\render\debug/" /J /FD /GZ /c +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "BRE_yafray - Win32 Release" +# Name "BRE_yafray - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\yafray\intern\api.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\yafray\intern\export_File.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\yafray\intern\export_Plugin.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\yafray\intern\yafexternal.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\yafray\intern\yafexternal.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\yafray\intern\yafray_Render.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\yafray\intern\export_File.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\yafray\intern\export_Plugin.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\yafray\YafRay_Api.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\yafray\intern\yafray_Render.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/datatoc/datatoc.dsp b/projectfiles/datatoc/datatoc.dsp new file mode 100644 index 00000000000..4e55182bb2c --- /dev/null +++ b/projectfiles/datatoc/datatoc.dsp @@ -0,0 +1,100 @@ +# Microsoft Developer Studio Project File - Name="datatoc" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=datatoc - 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 "datatoc.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 "datatoc.mak" CFG="datatoc - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "datatoc - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "datatoc - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "datatoc - 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 "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "datatoc - 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 "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "datatoc - Win32 Release" +# Name "datatoc - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\release\datafiles\datatoc.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/blenderhook/KX_blenderhook.dsp b/projectfiles/gameengine/blenderhook/KX_blenderhook.dsp new file mode 100644 index 00000000000..c3657ed30c5 --- /dev/null +++ b/projectfiles/gameengine/blenderhook/KX_blenderhook.dsp @@ -0,0 +1,161 @@ +# Microsoft Developer Studio Project File - Name="KX_blenderhook" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=KX_blenderhook - Win32 Release +!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 "KX_blenderhook.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 "KX_blenderhook.mak" CFG="KX_blenderhook - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "KX_blenderhook - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "KX_blenderhook - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "KX_blenderhook - 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 "..\..\..\obj\windows\gameengine\blenderhook" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\blenderhook" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\extern\solid" /I "..\..\..\source\gameengine\physics\sumo" /I "..\..\..\source\gameengine\physics\common" /I "..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\bmfont\include" /I "..\..\..\source\gameengine\Converter\\" /I "..\..\..\source\blender\imbuf" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\source\gameengine\ketsji" /I "..\..\..\source\gameengine\physics\sumo\fuzzics\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\gameengine\network" /I "..\..\..\source\gameengine\scenegraph" /I "..\..\..\source\sumo\include" /I "..\..\..\source\sumo\fuzzics\include" /I "..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\lib\windows\soundsystem\include" /I "..\..\..\source\blender\misc" /I "..\..\..\source\blender\blenloader" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 + +!ELSEIF "$(CFG)" == "KX_blenderhook - 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 "..\..\..\obj\windows\gameengine\blenderhook\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\blenderhook\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\extern\solid" /I "..\..\..\source\gameengine\physics\sumo" /I "..\..\..\source\gameengine\physics\common" /I "..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\bmfont\include" /I "..\..\..\source\gameengine\Converter\\" /I "..\..\..\source\blender\imbuf" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\source\gameengine\ketsji" /I "..\..\..\source\gameengine\physics\sumo\fuzzics\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\gameengine\network" /I "..\..\..\source\gameengine\scenegraph" /I "..\..\..\source\sumo\include" /I "..\..\..\source\sumo\fuzzics\include" /I "..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\lib\windows\soundsystem\include" /I "..\..\..\source\blender\misc" /I "..\..\..\source\blender\blenloader" /D "WIN32" /D "_MBCS" /D "_LIB" /U "_DEBUG" /YX /J /FD /GZ /c +# 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 + +!ENDIF + +# Begin Target + +# Name "KX_blenderhook - Win32 Release" +# Name "KX_blenderhook - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\BL_KetsjiEmbedStart.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderCanvas.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderGL.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderInputDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderKeyboardDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderMouseDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderPolyMaterial.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderRenderTools.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderSystem.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderCanvas.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderGL.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderInputDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderKeyboardDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderMouseDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderPolyMaterial.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderRenderTools.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderSystem.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/converter/KX_converter.dsp b/projectfiles/gameengine/converter/KX_converter.dsp new file mode 100644 index 00000000000..96826d3004b --- /dev/null +++ b/projectfiles/gameengine/converter/KX_converter.dsp @@ -0,0 +1,278 @@ +# Microsoft Developer Studio Project File - Name="KX_converter" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=KX_converter - Win32 Release +!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 "KX_converter.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 "KX_converter.mak" CFG="KX_converter - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "KX_converter - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "KX_converter - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "KX_converter - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "KX_converter - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "KX_converter - 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 "..\..\..\obj\windows\gameengine\converter" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\converter" +# PROP Target_Dir "" +MTL=midl.exe +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\source\gameengine\physics\common" /I "..\..\..\source\gameengine\physics\BlOde" /I "..\..\..\source\gameengine\physics\Dummy" /I "..\..\..\extern\solid" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\gameengine\BlenderRoutines" /I "..\..\..\source\sumo\include" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\source\\gameengine\physics\sumo\Fuzzics\include" /I "..\..\..\source\gameengine\Ketsji" /I "..\..\..\source\gameengine\SceneGraph" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\lib\windows\soundsystem\include" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\gameengine\soundsystem\snd_blenderwavecache" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\gameengine\network" /I "..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\source\gameengine\physics" /I "..\..\..\source\gameengine\physics\ode" /I "..\..\..\source\gameengine\physics\dummy" /I "..\..\..\source\gameengine\physics\sumo" /I "..\..\..\source\gameengine\physics\bullet" /I "..\..\..\extern\bullet\linearmath" /I "..\..\..\extern\bullet\Bulletdynamics" /I "..\..\..\extern\bullet\Bullet" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "USE_SUMO_SOLID" /YX /J /FD /c +# 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 + +!ELSEIF "$(CFG)" == "KX_converter - 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 "..\..\..\obj\windows\gameengine\converter\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\converter\debug" +# PROP Target_Dir "" +MTL=midl.exe +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\source\gameengine\physics\common" /I "..\..\..\source\gameengine\physics\BlOde" /I "..\..\..\source\gameengine\physics\Dummy" /I "..\..\..\extern\solid" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\gameengine\BlenderRoutines" /I "..\..\..\source\sumo\include" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\source\\gameengine\physics\sumo\Fuzzics\include" /I "..\..\..\source\gameengine\Ketsji" /I "..\..\..\source\gameengine\SceneGraph" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\lib\windows\soundsystem\include" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\gameengine\soundsystem\snd_blenderwavecache" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\gameengine\network" /I "..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\source\gameengine\physics" /I "..\..\..\source\gameengine\physics\ode" /I "..\..\..\source\gameengine\physics\dummy" /I "..\..\..\source\gameengine\physics\sumo" /I "..\..\..\source\gameengine\physics\bullet" /I "..\..\..\extern\bullet\linearmath" /I "..\..\..\extern\bullet\Bulletdynamics" /I "..\..\..\extern\bullet\Bullet" /D "WIN32" /D "_MBCS" /D "_LIB" /D "USE_SUMO_SOLID" /U "_DEBUG" /YX /J /FD /GZ /c +# 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 + +!ELSEIF "$(CFG)" == "KX_converter - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "KX_converter___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "KX_converter___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\converter\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\converter\mtdll_debug" +# PROP Target_Dir "" +MTL=midl.exe +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\gameengine\BlenderRoutines" /I "..\..\..\source\sumo\include" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\source\gameengine\Ketsji" /I "..\..\..\source\gameengine\SceneGraph" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\source\gameengine\soundsystem" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\gameengine\soundsystem\snd_blenderwavecache" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender" /I "..\..\..\source\blender\makesdna" /I "..\..\..\..\lib\windows\python\include\python1.5" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\..\source\gameengine\physics" /I "..\..\..\source\gameengine\physics\ode" /I "..\..\..\source\gameengine\physics\dummy" /I "..\..\..\source\gameengine\physics\sumo\include" /I "..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\gameengine\BlenderRoutines" /I "..\..\..\source\sumo\include" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\source\gameengine\Ketsji" /I "..\..\..\source\gameengine\SceneGraph" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\source\gameengine\soundsystem" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\gameengine\soundsystem\snd_blenderwavecache" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\gameengine\network" /I "..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\source\gameengine\physics\sumo" /I "..\..\..\source\gameengine\physics\sumo\fuzzics\include" /I "..\..\..\source\gameengine\physics\common" /I "..\..\..\source\gameengine\physics\BlOde" /D "WIN32" /D "_MBCS" /D "_LIB" /U "_DEBUG" /YX /J /FD /GZ /c +# 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 /out:"..\..\..\..\..\obj\windows\gameengine\converter\debug\KX_converter.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "KX_converter - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "KX_converter___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "KX_converter___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\converter\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\converter\mtdll" +# PROP Target_Dir "" +MTL=midl.exe +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\gameengine\BlenderRoutines" /I "..\..\..\source\sumo\include" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\source\gameengine\Ketsji" /I "..\..\..\source\gameengine\SceneGraph" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\source\gameengine\soundsystem" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\gameengine\soundsystem\snd_blenderwavecache" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender" /I "..\..\..\source\blender\makesdna" /I "..\..\..\..\lib\windows\python\include\python2.0" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\..\source\gameengine\physics" /I "..\..\..\source\gameengine\physics\ode" /I "..\..\..\source\gameengine\physics\dummy" /I "..\..\..\source\gameengine\physics\sumo\include" /I "..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\gameengine\BlenderRoutines" /I "..\..\..\source\sumo\include" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\source\gameengine\Ketsji" /I "..\..\..\source\gameengine\SceneGraph" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\source\gameengine\soundsystem" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\gameengine\soundsystem\snd_blenderwavecache" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\gameengine\network" /I "..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\source\gameengine\physics\sumo" /I "..\..\..\source\gameengine\physics\sumo\fuzzics\include" /I "..\..\..\source\gameengine\physics\common" /I "..\..\..\source\gameengine\physics\BlOde" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 /out:"..\..\..\..\..\obj\windows\gameengine\converter\KX_converter.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "KX_converter - Win32 Release" +# Name "KX_converter - Win32 Debug" +# Name "KX_converter - Win32 MT DLL Debug" +# Name "KX_converter - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_ActionActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_ArmatureObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_BlenderDataConversion.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_DeformableGameObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_MeshDeformer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_SkinDeformer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_SkinMeshObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BlenderWorldInfo.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Bullet\CcdPhysicsController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Bullet\CcdPhysicsEnvironment.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_BlenderScalarInterpolator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_BlenderSceneConverter.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_ConvertActuators.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_ConvertControllers.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_ConvertProperties.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_ConvertSensors.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_IpoConvert.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_ActionActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_ArmatureObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_BlenderDataConversion.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_DeformableGameObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_MeshDeformer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_SkinDeformer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_SkinMeshObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BlenderWorldInfo.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_BlenderScalarInterpolator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_BlenderSceneConverter.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_ConvertActuators.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_ConvertControllers.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_ConvertProperties.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_ConvertSensors.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_IpoConvert.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/expression/EXP_expressions.dsp b/projectfiles/gameengine/expression/EXP_expressions.dsp new file mode 100644 index 00000000000..94ded903d41 --- /dev/null +++ b/projectfiles/gameengine/expression/EXP_expressions.dsp @@ -0,0 +1,302 @@ +# Microsoft Developer Studio Project File - Name="EXP_expressions" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=EXP_expressions - Win32 Release +!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 "EXP_expressions.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 "EXP_expressions.mak" CFG="EXP_expressions - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "EXP_expressions - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "EXP_expressions - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "EXP_expressions - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "EXP_expressions - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "EXP_expressions - 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 "..\..\..\obj\windows\gameengine\expressions" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\expressions" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "..\..\..\intern\moto\include" /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\source\kernel\gen_system" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /YX /J /FD /c +# 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 + +!ELSEIF "$(CFG)" == "EXP_expressions - 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 "..\..\..\obj\windows\gameengine\expressions\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\expressions\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\intern\moto\include" /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\source\kernel\gen_system" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /U "_DEBUG" /YX /J /FD /GZ /c +# 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 + +!ELSEIF "$(CFG)" == "EXP_expressions - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "EXP_expressions___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "EXP_expressions___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\expressions\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\expressions\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\source\kernel\gen_system" /I "..\..\..\..\lib\windows\python\include\python1.5" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\source\kernel\gen_system" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /U "_DEBUG" /YX /J /FD /GZ /c +# 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 /out:"..\..\..\..\..\obj\windows\gameengine\expressions\debug\EXP_expressions.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "EXP_expressions - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "EXP_expressions___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "EXP_expressions___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\expressions\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\expressions\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\kernel\gen_system" /I "..\..\..\..\lib\windows\python\include\python2.0" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\source\kernel\gen_system" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /YX /J /FD /c +# 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 /out:"..\..\..\..\..\obj\windows\gameengine\expressions\EXP_expressions.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "EXP_expressions - Win32 Release" +# Name "EXP_expressions - Win32 Debug" +# Name "EXP_expressions - Win32 MT DLL Debug" +# Name "EXP_expressions - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\BoolValue.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\ConstExpr.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\EmptyValue.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\ErrorValue.cpp +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Expressions\EXP_C-Api.cpp" +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\Expression.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\FloatValue.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\IdentifierExpr.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\IfExpr.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\InputParser.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\IntValue.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\KX_HashedPtr.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\ListValue.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\Operator1Expr.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\Operator2Expr.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\PyObjectPlus.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\StringValue.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\Value.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\VectorValue.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\BoolValue.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\ConstExpr.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\EmptyValue.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\ErrorValue.h +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Expressions\EXP_C-Api.h" +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\Expression.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\FloatValue.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\IdentifierExpr.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\IfExpr.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\InputParser.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\IntValue.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\KX_HashedPtr.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\ListValue.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\Operator1Expr.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\Operator2Expr.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\PyObjectPlus.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\StringValue.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\Value.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\VectorValue.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\VoidValue.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/gamelogic/SCA_gamelogic.dsp b/projectfiles/gameengine/gamelogic/SCA_gamelogic.dsp new file mode 100644 index 00000000000..45be1cf2772 --- /dev/null +++ b/projectfiles/gameengine/gamelogic/SCA_gamelogic.dsp @@ -0,0 +1,406 @@ +# Microsoft Developer Studio Project File - Name="SCA_GameLogic" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=SCA_GameLogic - Win32 Release +!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 "SCA_GameLogic.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 "SCA_GameLogic.mak" CFG="SCA_GameLogic - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SCA_GameLogic - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "SCA_GameLogic - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SCA_GameLogic - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SCA_GameLogic - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SCA_GameLogic - 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 "..\..\..\obj\windows\gameengine\gamelogic" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\gamelogic" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\sdl\include" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\..\lib\windows\moto\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /YX /J /FD /c +# 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 + +!ELSEIF "$(CFG)" == "SCA_GameLogic - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SCA_GameLogic___Win32_Debug" +# PROP BASE Intermediate_Dir "SCA_GameLogic___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\gamelogic\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\gamelogic\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\sdl\include" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\..\lib\windows\moto\include" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /U "_DEBUG" /YX /J /FD /GZ /c +# 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 + +!ELSEIF "$(CFG)" == "SCA_GameLogic - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SCA_GameLogic___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "SCA_GameLogic___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\gamelogic\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\gamelogic\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\lib\windows\python\include\python1.5" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\sdl\include" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\..\lib\windows\moto\include" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /U "_DEBUG" /YX /J /FD /GZ /c +# 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 /out:"..\..\..\..\..\obj\windows\gameengine\gamelogic\debug\SCA_GameLogic.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SCA_GameLogic - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "SCA_GameLogic___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "SCA_GameLogic___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\gamelogic\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\gamelogic\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\lib\windows\python\include\python2.0" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\sdl\include" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\..\lib\windows\moto\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /YX /J /FD /c +# 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 /out:"..\..\..\..\..\obj\windows\gameengine\gamelogic\SCA_GameLogic.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "SCA_GameLogic - Win32 Release" +# Name "SCA_GameLogic - Win32 Debug" +# Name "SCA_GameLogic - Win32 MT DLL Debug" +# Name "SCA_GameLogic - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Group "JoystickImp" + +# PROP Default_Filter "cpp" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\Joystick\SCA_Joystick.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\Joystick\SCA_JoystickEvents.cpp +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_AlwaysEventManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_AlwaysSensor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_ANDController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_EventManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_ExpressionController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_IActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_IController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_IInputDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_ILogicBrick.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_IObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_IScene.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_ISensor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_JoystickManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_JoystickSensor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_KeyboardManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_KeyboardSensor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_LogicManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_MouseManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_MouseSensor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_ORController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_PropertyActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_PropertyEventManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_PropertySensor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_PythonController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_RandomActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_RandomEventManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_RandomNumberGenerator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_RandomSensor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_TimeEventManager.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Group "Joystick" + +# PROP Default_Filter "h" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\Joystick\SCA_Joystick.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\Joystick\SCA_JoystickDefines.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\Joystick\SCA_JoystickPrivate.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_AlwaysEventManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_AlwaysSensor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_ANDController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_EventManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_ExpressionController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_IActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_IController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_IInputDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_ILogicBrick.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_IObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_IScene.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_ISensor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_JoystickManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_JoystickSensor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_KeyboardManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_KeyboardSensor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_LogicManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_MouseManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_MouseSensor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_ORController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_PropertyActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_PropertyEventManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_PropertySensor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_PythonController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_RandomActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_RandomEventManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_RandomNumberGenerator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_RandomSensor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_TimeEventManager.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/gameplayer/axctl/GP_axctl.dsp b/projectfiles/gameengine/gameplayer/axctl/GP_axctl.dsp new file mode 100644 index 00000000000..99b6798bf59 --- /dev/null +++ b/projectfiles/gameengine/gameplayer/axctl/GP_axctl.dsp @@ -0,0 +1,253 @@ +# Microsoft Developer Studio Project File - Name="GP_axctl" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=GP_axctl - Win32 MT DLL 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 "GP_axctl.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 "GP_axctl.mak" CFG="GP_axctl - Win32 MT DLL Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GP_axctl - Win32 MT DLL Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "GP_axctl - Win32 MT DLL Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GP_axctl - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 2 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "GP_axctl___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "GP_axctl___Win32_MT_DLL_Debug" +# PROP BASE Target_Ext "ocx" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\axctl\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\axctl\mtdll_debug" +# PROP Target_Ext "ocx" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /FR /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\source\kernel\gen_messaging" /I "..\..\..\..\..\lib\windows\bmfont\include" /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /I "..\..\..\..\source\gameengine\converter" /I "..\..\..\..\source\gameengine\GamePlayer\common" /I "..\..\..\..\source\gameengine\GamePlayer\common\windows" /I "..\..\..\..\..\lib\windows\iksolver\include" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /U "_DEBUG" /YX /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 opengl32.lib glu32.lib glaux.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"Debug/ActiveXgp.ocx" /pdbtype:sept /libpath:"..\..\..\..\..\lib\windows\python\lib" /libpath:"..\..\..\..\..\lib\windows\openal\lib\lib_release" +# SUBTRACT BASE LINK32 /nodefaultlib +# ADD LINK32 openal_static.lib libmoto.a libguardedalloc.a libbmfont.a libstring.a ws2_32.lib opengl32.lib glu32.lib glaux.lib dxguid.lib ole32.lib vfw32.lib libblenkey.a libeay32.lib libz.a libpng.a libjpeg.a odelib.lib /nologo /subsystem:windows /dll /debug /machine:I386 /nodefaultlib:"libc.lib" /nodefaultlib:"libcmt.lib" /nodefaultlib:"msvcrt.lib" /out:"..\..\..\..\obj\windows\debug\Blender3DPlugin.ocx" /pdbtype:sept /libpath:"..\..\..\..\..\lib\windows\ode\lib\mt_dll" /libpath:"..\..\..\..\..\lib\windows\openal\lib" /libpath:"..\..\..\..\..\lib\windows\guardedalloc\lib" /libpath:"..\..\..\..\..\lib\windows\moto\lib" /libpath:"../../../../../lib/windows/bmfont/lib" /libpath:"../../../../../lib/windows/string/lib" /libpath:"../../../../../lib/windows/python/lib" /libpath:"..\..\..\..\..\lib\windows\openssl\lib\mt_dll" /libpath:"..\..\..\..\..\lib\windows\jpeg\lib" /libpath:"..\..\..\..\..\lib\windows\bmfont/lib" /libpath:"..\..\..\..\..\lib\windows\string\lib" /libpath:"..\..\..\..\..\lib\windows\python\lib" /libpath:"..\..\..\..\..\lib\windows\openssl\lib\\" /libpath:"..\..\..\..\..\lib\windows\zlib\lib\\" /libpath:"..\..\..\..\..\lib\windows\blenkey\lib\\" /libpath:"..\..\..\..\..\lib\windows\png\lib" +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "GP_axctl - Win32 MT DLL Release" + +# PROP BASE Use_MFC 2 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "GP_axctl___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "GP_axctl___Win32_MT_DLL_Release" +# PROP BASE Target_Ext "ocx" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\axctl\mtdll" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\axctl\mtdll" +# PROP Target_Ext "ocx" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\source\kernel\gen_messaging" /I "..\..\..\..\..\lib\windows\bmfont\include" /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /I "..\..\..\..\source\gameengine\converter" /I "..\..\..\..\source\gameengine\GamePlayer\common" /I "..\..\..\..\source\gameengine\GamePlayer\common\windows" /I "..\..\..\..\..\lib\windows\iksolver\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 opengl32.lib glu32.lib glaux.lib /nologo /subsystem:windows /dll /machine:I386 /out:"Release/ActiveXgp.ocx" +# ADD LINK32 openal_static.lib libmoto.a libguardedalloc.a libbmfont.a libstring.a ws2_32.lib opengl32.lib glu32.lib glaux.lib dxguid.lib ole32.lib vfw32.lib libblenkey.a libeay32.lib libz.a libpng.a libjpeg.a odelib.lib /nologo /subsystem:windows /dll /machine:I386 /nodefaultlib:"libc.lib" /nodefaultlib:"libcmt.lib" /nodefaultlib:"msvcrtd.lib" /out:"..\..\..\..\obj\windows\Blender3DPlugin.ocx" /libpath:"..\..\..\..\..\lib\windows\ode\lib\mt_dll" /libpath:"..\..\..\..\..\lib\windows\openal\lib" /libpath:"..\..\..\..\..\lib\windows\guardedalloc\lib" /libpath:"..\..\..\..\..\lib\windows\moto\lib" /libpath:"..\..\..\..\..\lib\windows\bmfont/lib" /libpath:"..\..\..\..\..\lib\windows\string\lib" /libpath:"..\..\..\..\..\lib\windows\python\lib" /libpath:"..\..\..\..\..\lib\windows\openssl\lib\mt_dll" /libpath:"..\..\..\..\..\lib\windows\jpeg\lib" /libpath:"..\..\..\..\..\lib\windows\zlib\lib\\" /libpath:"..\..\..\..\..\lib\windows\blenkey\lib\\" /libpath:"..\..\..\..\..\lib\windows\png\lib" +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "GP_axctl - Win32 MT DLL Debug" +# Name "GP_axctl - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderDataPathProperty.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayer.def +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayer.odl +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayer.rc +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayerCtl.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayerPpg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\CControlRefresher.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\blender\makesdna\intern\dna.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\MemoryResource.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\RawImageRsrc.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\SafeControl.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\StdAfx.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\blender\blenkernel\bad_level_call_stubs\stubs.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderDataPathProperty.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayerCtl.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayerPpg.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\CControlRefresher.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\MemoryResource.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\RawImageRsrc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\Resource.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\SafeControl.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayer.ico +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayerCtl.bmp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\splash.bmp +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\ActiveXandNetscapeTest.html +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayer.html +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayerDuo.html +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\load.blend +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\logo_blender.raw +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\logo_blender3d.raw +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\logo_nan.raw +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\ReadMe.txt +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\ReadMeBuilding.txt +# End Source File +# End Target +# End Project diff --git a/projectfiles/gameengine/gameplayer/common/GP_common.dsp b/projectfiles/gameengine/gameplayer/common/GP_common.dsp new file mode 100644 index 00000000000..c1509608731 --- /dev/null +++ b/projectfiles/gameengine/gameplayer/common/GP_common.dsp @@ -0,0 +1,255 @@ +# Microsoft Developer Studio Project File - Name="GP_common" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=GP_common - Win32 Release +!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 "GP_common.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 "GP_common.mak" CFG="GP_common - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GP_common - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "GP_common - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "GP_common - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "GP_common - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GP_common - 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 "..\..\..\..\obj\windows\gameengine\gameplayer\common" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\common" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\..\source\gameengine\Converter" /I "..\..\..\..\source\gameengine\soundsystem\snd_dummy" /I "..\..\..\..\..\lib\windows\bmfont\include" /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\GamePlayer\common\\" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 + +!ELSEIF "$(CFG)" == "GP_common - 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 "..\..\..\..\obj\windows\gameengine\gameplayer\common\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\common\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\..\source\gameengine\Converter" /I "..\..\..\..\source\gameengine\soundsystem\snd_dummy" /I "..\..\..\..\..\lib\windows\bmfont\include" /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\GamePlayer\common\\" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /D "WIN32" /D "_MBCS" /D "_LIB" /U "_DEBUG" /YX /FD /GZ /GZ /c +# 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 + +!ELSEIF "$(CFG)" == "GP_common - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "GP_common___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "GP_common___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\common\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\common\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\..\source\gameengine\Converter" /I "..\..\..\..\source\gameengine\soundsystem\snd_dummy" /I "..\..\..\..\..\lib\windows\bmfont\include" /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\GamePlayer\common\\" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /D "WIN32" /D "_MBCS" /D "_LIB" /U "_DEBUG" /YX /FD /GZ /c +# SUBTRACT CPP /Fr +# 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 /out:"..\..\..\..\..\obj\windows\gameengine\gameplayer\common\debug\GP_common.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "GP_common - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "GP_common___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "GP_common___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\common\mtdll" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\common\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\..\lib\windows\python\include\python2.0" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\..\lib\windows\python\include\python1.5" /I "..\..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\..\source\gameengine\Converter" /I "..\..\..\..\source\gameengine\soundsystem\snd_dummy" /I "..\..\..\..\..\lib\windows\bmfont\include" /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\GamePlayer\common\\" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 /out:"..\..\..\..\..\obj\windows\gameengine\gameplayer\common\GP_common.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "GP_common - Win32 Release" +# Name "GP_common - Win32 Debug" +# Name "GP_common - Win32 MT DLL Debug" +# Name "GP_common - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\bmfont.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_Canvas.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_Engine.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_KeyboardDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_MouseDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_PolygonMaterial.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_RawImage.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_RawLoadDotBlendArray.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_RawLogoArrays.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_RenderTools.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_System.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\windows\GPW_Canvas.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\windows\GPW_Engine.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\windows\GPW_KeyboardDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\windows\GPW_System.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_Canvas.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_Engine.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_KeyboardDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_MouseDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_PolygonMaterial.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_RenderTools.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_System.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\windows\GPW_Canvas.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\windows\GPW_Engine.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\windows\GPW_KeyboardDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\windows\GPW_System.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\Makefile +# End Source File +# End Target +# End Project diff --git a/projectfiles/gameengine/gameplayer/ghost/GP_ghost.dsp b/projectfiles/gameengine/gameplayer/ghost/GP_ghost.dsp new file mode 100644 index 00000000000..d569d6fceac --- /dev/null +++ b/projectfiles/gameengine/gameplayer/ghost/GP_ghost.dsp @@ -0,0 +1,156 @@ +# Microsoft Developer Studio Project File - Name="GP_ghost" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=GP_ghost - Win32 Release +!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 "GP_ghost.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 "GP_ghost.mak" CFG="GP_ghost - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GP_ghost - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "GP_ghost - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GP_ghost - 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 "..\..\..\..\obj\windows\" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\ghost\" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\..\lib\windows\ode\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\gameengine\Physics\Ode" /I "..\..\..\..\source\gameengine\Physics" /I "..\..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\..\lib\windows\bmfont\include" /I "..\..\..\..\source\kernel\gen_messaging" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/readblenfile" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /I "..\..\..\..\source\gameengine\converter" /I "..\..\..\..\source\gameengine\gameplayer\common\windows" /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\..\lib\windows\ghost\include" /I "..\..\..\..\..\lib\windows\iksolver\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 libguardedalloc.a libstring.a libghost.a odelib.lib fmodvc.lib libbmfont.a ws2_32.lib kernel32.lib user32.lib gdi32.lib vfw32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libjpeg.a opengl32.lib glu32.lib openal_static.lib dxguid.lib libblenkey.a libeay32.lib libpng.a libz.a libmoto.a /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcd.lib" /nodefaultlib:"libc.lib" /nodefaultlib:"msvcrt.lib" /nodefaultlib:"msvcrtd.lib" /nodefaultlib:"msvcprt.lib" /out:"..\..\..\..\obj\windows\blenderplayer.exe" /libpath:"..\..\..\..\..\lib\windows\ode\lib" /libpath:"..\..\..\..\..\lib\windows\bmfont\lib" /libpath:"..\..\..\..\..\lib\windows\guardedalloc\lib" /libpath:"..\..\..\..\..\lib\windows\string\lib" /libpath:"..\..\..\..\..\lib\windows\ghost\lib" /libpath:"..\..\..\..\..\lib\windows\jpeg/lib" /libpath:"..\..\..\..\..\lib\windows\moto\lib\\" /libpath:"..\..\..\..\..\lib\windows\png\lib" /libpath:"..\..\..\..\..\lib\windows\zlib\lib" /libpath:"..\..\..\..\..\lib\windows\ode-0.03\lib" /libpath:"../../../../../lib/windows/fmod/lib" /libpath:"..\..\..\..\..\lib\windows\python\lib" /libpath:"../../../../../lib/windows/openal/lib" /libpath:"..\..\..\..\..\lib\windows\openssl\lib" /libpath:"..\..\..\..\..\lib\windows\blenkey\lib\\" +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "GP_ghost - 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 "..\..\..\..\obj\windows\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\ghost\debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "../../../../../lib/windows/moto/include" /I "..\..\..\..\source\gameengine\Physics\Ode" /I "..\..\..\..\source\gameengine\Physics" /I "..\..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\..\lib\windows\bmfont\include" /I "..\..\..\..\source\kernel\gen_messaging" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/readblenfile" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /I "..\..\..\..\source\gameengine\converter" /I "..\..\..\..\source\gameengine\gameplayer\common\windows" /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\..\lib\windows\ghost\include" /I "../../../../../lib/windows/iksolver/include" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "dSINGLE" /U "_DEBUG" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 libguardedalloc.a libstring.a libghost.a odelib.lib fmodvc.lib libbmfont.a ws2_32.lib kernel32.lib user32.lib gdi32.lib vfw32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib opengl32.lib glu32.lib openal_static.lib libjpeg.a dxguid.lib libblenkey.a libeay32.lib libpng.a libz.a libmoto.a /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"libcd.lib" /nodefaultlib:"libc.lib" /nodefaultlib:"libcmt.lib" /nodefaultlib:"msvcrt.lib" /nodefaultlib:"msvcrtd.lib" /nodefaultlib:"msvcprtd.lib" /out:"..\..\..\..\obj\windows\debug\blenderplayer.exe" /pdbtype:sept /libpath:"..\..\..\..\..\lib\windows\ode\lib" /libpath:"..\..\..\..\..\lib\windows\bmfont\lib\\" /libpath:"..\..\..\..\..\lib\windows\guardedalloc\lib" /libpath:"..\..\..\..\..\lib\windows\string\lib\\" /libpath:"..\..\..\..\..\lib\windows\ghost\lib\\" /libpath:"..\..\..\..\..\lib\windows\jpeg\lib" /libpath:"..\..\..\..\..\lib\windows\moto\lib\\" /libpath:"..\..\..\..\..\lib\windows\zlib\lib\\" /libpath:"..\..\..\..\..\lib\windows\png\lib\\" /libpath:"..\..\..\..\..\lib\windows\ode-0.03\lib" /libpath:"../../../../../lib/windows/fmod/lib" /libpath:"..\..\..\..\..\lib\windows\python\lib" /libpath:"../../../../../lib/windows/openal/lib" /libpath:"..\..\..\..\..\lib\windows\openssl\lib" /libpath:"..\..\..\..\..\lib\windows\blenkey\lib\\" +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "GP_ghost - Win32 Release" +# Name "GP_ghost - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\blender\makesdna\intern\dna.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ghost\GPG_Application.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ghost\GPG_Canvas.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ghost\GPG_ghost.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ghost\GPG_KeyboardDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ghost\GPG_System.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\blender\blenkernel\bad_level_call_stubs\stubs.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\icons\winplayer.rc +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ghost\GPG_Application.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ghost\GPG_Canvas.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ghost\GPG_KeyboardDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ghost\GPG_System.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=..\..\..\..\source\icons\winplayer.ico +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ghost\Makefile +# End Source File +# End Target +# End Project diff --git a/projectfiles/gameengine/gameplayer/glut/GP_glut.dsp b/projectfiles/gameengine/gameplayer/glut/GP_glut.dsp new file mode 100644 index 00000000000..64315293ac6 --- /dev/null +++ b/projectfiles/gameengine/gameplayer/glut/GP_glut.dsp @@ -0,0 +1,205 @@ +# Microsoft Developer Studio Project File - Name="GP_glut" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=GP_glut - Win32 Profile +!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 "GP_glut.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 "GP_glut.mak" CFG="GP_glut - Win32 Profile" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GP_glut - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "GP_glut - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "GP_glut - Win32 Profile" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GP_glut - 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 "..\..\..\..\..\obj\windows\gameengine\gameplayer\glut" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\lib\windows\glut-3.7\include" /I "..\..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\source\gameengine\SoundSystem" /I "../../../../../lib/windows/moto/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 glu32.lib user32.lib gdi32.lib advapi32.lib dxguid.lib ole32.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\..\..\..\lib\windows\glut-3.7\lib" /libpath:"..\..\..\..\..\lib\windows\python\lib" /libpath:"..\..\..\..\..\lib\windows\openal\lib\lib_release" + +!ELSEIF "$(CFG)" == "GP_glut - 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 "..\..\..\..\..\obj\windows\gameengine\gameplayer\glut\debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\lib\windows\glut-3.7\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /I "..\..\source\gameengine\SoundSystem" /I "../../../../../lib/windows/moto/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 glu32.lib user32.lib gdi32.lib advapi32.lib dxguid.lib ole32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\..\..\lib\windows\glut-3.7\lib" /libpath:"..\..\..\..\..\lib\windows\python\lib" /libpath:"..\..\..\..\..\lib\windows\openal\lib\lib_release" + +!ELSEIF "$(CFG)" == "GP_glut - Win32 Profile" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "GP_glut___Win32_Profile" +# PROP BASE Intermediate_Dir "GP_glut___Win32_Profile" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "GP_glut___Win32_Profile" +# PROP Intermediate_Dir "GP_glut___Win32_Profile" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\lib\windows\glut-3.7\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /I "..\..\source\gameengine\SoundSystem" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /O2 /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\lib\windows\glut-3.7\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /I "..\..\source\gameengine\SoundSystem" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 glu32.lib user32.lib gdi32.lib advapi32.lib dxguid.lib ole32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\..\..\lib\windows\glut-3.7\lib" /libpath:"..\..\..\..\..\lib\windows\python\lib" /libpath:"..\..\..\..\..\lib\windows\openal\lib\lib_release" +# ADD LINK32 glu32.lib user32.lib gdi32.lib advapi32.lib dxguid.lib ole32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\..\..\lib\windows\glut-3.7\lib" /libpath:"..\..\..\..\..\lib\windows\python\lib" /libpath:"..\..\..\..\..\lib\windows\openal\lib\lib_release" + +!ENDIF + +# Begin Target + +# Name "GP_glut - Win32 Release" +# Name "GP_glut - Win32 Debug" +# Name "GP_glut - Win32 Profile" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Glut\GlutGamePlayer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Glut\GlutKeyboardDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Glut\GlutSystem.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Glut\GlutCanvas.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Glut\GlutInputDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Glut\GlutKeyboardDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Glut\GlutPolygonMaterial.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Glut\GlutRenderTools.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Glut\GlutSystem.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\alc\ALc.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\alu\ALu.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\alut\ALut.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alBuffer.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alEax.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alError.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alExtension.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alListener.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alSource.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alState.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\OpenAL32.obj +# End Source File +# End Target +# End Project diff --git a/projectfiles/gameengine/gameplayer/loader/BlenderLoader/BlenderLoader.dsp b/projectfiles/gameengine/gameplayer/loader/BlenderLoader/BlenderLoader.dsp new file mode 100644 index 00000000000..1af82b0644f --- /dev/null +++ b/projectfiles/gameengine/gameplayer/loader/BlenderLoader/BlenderLoader.dsp @@ -0,0 +1,206 @@ +# Microsoft Developer Studio Project File - Name="BlenderLoader" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=BlenderLoader - Win32 Profile +!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 "BlenderLoader.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 "BlenderLoader.mak" CFG="BlenderLoader - Win32 Profile" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BlenderLoader - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "BlenderLoader - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "BlenderLoader - Win32 Profile" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BlenderLoader - 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 "..\..\..\..\..\..\obj\windows\gameengine\gameplayer\BlenderLoader" +# PROP Intermediate_Dir "..\..\..\..\..\..\obj\windows\gameengine\gameplayer\BlenderLoader" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "../../../../../../lib/windows/python/include/python2.0" /I "../../../../../source/blender/encrypt" /I "../../../../../source/blender/blenkernel" /I "../../../../../source/blender/makesdna" /I "../../../../../source/blender/blenlib" /I "../../../../../source/blender/blenloader" /I "../../../../../source/blender/render/extern/include" /I "../../../../../source/gameengine/Rasterizer" /I "../../../../../../lib\windows\sdl\SDL-1.1.7\include" /I "../../../../../source/gameengine/GameLogic" /I "..\..\..\..\..\source\sumo\include" /I "..\..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\source\kernel\gen_system" /I "../../../../../source/blender/imbuf" /I "../../../../../source/gameengine/SoundSystem" /I "../../../../../source/gameengine/SoundSystem/SND_OpenAL" /I "../../../../../source/gameengine/Ketsji" /I "../../../../../source/gameengine/Expressions" /I "../../../../../source/gameengine/SceneGraph" /I "../../../../../source/gameengine/ketsji/kxnetwork" /I "../../../../../source/gameengine/network" /I "../../../../../source/gameengine/network/loopbacknetwork" /I "../../../../../source/gameengine/GamePlayer/common" /I "../../../../../../lib/windows/iksolver/include" /I "../../../../../source/gameengine/SoundSystem/SND_Dummy" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 libguardedalloc.a libmoto.a sdlmain.lib sdl.lib dxguid.lib ole32.lib libjpeg.lib glu32.lib opengl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\..\..\..\..\..\obj\windows\BlenderLoader.exe" /libpath:"../../../../../../lib/windows/moto/lib" /libpath:"..\..\..\..\..\..\lib\windows\guardedalloc\lib" /libpath:"../../../../../../lib/windows/python/lib" /libpath:"../../../../../../lib/windows/jpeg/lib" /libpath:"../../../../../../lib/windows/sdl/SDL-1.1.7\Lib" + +!ELSEIF "$(CFG)" == "BlenderLoader - 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 "..\..\..\..\..\..\obj\windows\gameengine\gameplayer\BlenderLoader\debug" +# PROP Intermediate_Dir "..\..\..\..\..\..\obj\windows\gameengine\gameplayer\BlenderLoader\debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "../../../../../../lib/windows/python/include/python1.5" /I "../../../../../source/blender/encrypt" /I "../../../../../source/blender/blenkernel" /I "../../../../../source/blender/makesdna" /I "../../../../../source/blender/blenlib" /I "../../../../../source/blender/blenloader" /I "../../../../../source/blender/render/extern/include" /I "../../../../../source/gameengine/Rasterizer" /I "../../../../../../lib\windows\sdl\SDL-1.1.7\include" /I "../../../../../source/gameengine/GameLogic" /I "..\..\..\..\..\source\sumo\include" /I "..\..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\source\kernel\gen_system" /I "../../../../../source/blender/imbuf" /I "../../../../../source/gameengine/SoundSystem" /I "../../../../../source/gameengine/SoundSystem/SND_OpenAL" /I "../../../../../source/gameengine/Ketsji" /I "../../../../../source/gameengine/Expressions" /I "../../../../../source/gameengine/SceneGraph" /I "../../../../../source/gameengine/ketsji/kxnetwork" /I "../../../../../source/gameengine/network" /I "../../../../../source/gameengine/network/loopbacknetwork" /I "../../../../../source/gameengine/GamePlayer/common" /I "../../../../../../lib/windows/iksolver/include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Fr /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 sdldebug.lib libguardedalloc.a libmoto.a sdlmain.lib sdl.lib dxguid.lib ole32.lib libjpeg.lib glu32.lib opengl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\..\..\..\..\..\obj\windows\debug\BlenderLoader.exe" /pdbtype:sept /libpath:"..\..\..\..\..\..\lib\windows\guardedalloc\lib" /libpath:"../../../../../../lib/windows/python/lib" /libpath:"../../../../../../lib/windows/jpeg/lib" /libpath:"../../../../../../lib/windows/sdl/SDL-1.1.7\Lib" + +!ELSEIF "$(CFG)" == "BlenderLoader - Win32 Profile" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "BlenderLoader___Win32_Profile" +# PROP BASE Intermediate_Dir "BlenderLoader___Win32_Profile" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "BlenderLoader___Win32_Profile" +# PROP Intermediate_Dir "BlenderLoader___Win32_Profile" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../../../../../lib/windows/python/include/python1.5" /I "../../../../../source/blender/blenkernel" /I "../../../../../source/blender/makesdna" /I "../../../../../source/blender/blenlib" /I "../../../../../source/blender/blenloader" /I "../../../../../source/blender/render/extern/include" /I "../../../../../source/gameengine/Rasterizer" /I "../../../../../../lib\windows\sdl\SDL-1.1.7\include" /I "../../../../../source/gameengine/GameLogic" /I "..\..\..\..\..\source\sumo\include" /I "..\..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\source\kernel\gen_system" /I "../../../../../source/blender/imbuf" /I "../../../../../source/gameengine/SoundSystem" /I "../../../../../source/gameengine/SoundSystem/SND_OpenAL" /I "../../../../../source/gameengine/Ketsji" /I "../../../../../source/gameengine/Expressions" /I "../../../../../source/gameengine/SceneGraph" /I "../../../../../source/gameengine/ketsji/kxnetwork" /I "../../../../../source/gameengine/network" /I "../../../../../source/gameengine/network/loopbacknetwork" /I "../../../../../source/gameengine/GamePlayer/common" /I "../../../../../../lib/windows/iksolver/include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# SUBTRACT BASE CPP /Fr +# ADD CPP /nologo /W3 /Gm /GX /Zi /O2 /I "../../../../../../lib/windows/python/include/python1.5" /I "../../../../../source/blender/encrypt" /I "../../../../../source/blender/blenkernel" /I "../../../../../source/blender/makesdna" /I "../../../../../source/blender/blenlib" /I "../../../../../source/blender/blenloader" /I "../../../../../source/blender/render/extern/include" /I "../../../../../source/gameengine/Rasterizer" /I "../../../../../../lib\windows\sdl\SDL-1.1.7\include" /I "../../../../../source/gameengine/GameLogic" /I "..\..\..\..\..\source\sumo\include" /I "..\..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\source\kernel\gen_system" /I "../../../../../source/blender/imbuf" /I "../../../../../source/gameengine/SoundSystem" /I "../../../../../source/gameengine/SoundSystem/SND_OpenAL" /I "../../../../../source/gameengine/Ketsji" /I "../../../../../source/gameengine/Expressions" /I "../../../../../source/gameengine/SceneGraph" /I "../../../../../source/gameengine/ketsji/kxnetwork" /I "../../../../../source/gameengine/network" /I "../../../../../source/gameengine/network/loopbacknetwork" /I "../../../../../source/gameengine/GamePlayer/common" /I "../../../../../../lib/windows/iksolver/include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 sdldebug.lib sdlmain.lib sdl.lib dxguid.lib ole32.lib libjpeg.lib glu32.lib opengl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\..\..\..\..\..\obj\windows\debug\BlenderLoader.exe" /pdbtype:sept /libpath:"../../../../../../lib/windows/python/lib" /libpath:"../../../../../../lib/windows/jpeg/lib" /libpath:"../../../../../../lib/windows/sdl/SDL-1.1.7\Lib" +# ADD LINK32 sdldebug.lib libguardedalloc.a libmoto.a sdlmain.lib sdl.lib dxguid.lib ole32.lib libjpeg.lib glu32.lib opengl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\..\..\..\..\..\obj\windows\profile\BlenderLoader.exe" /pdbtype:sept /libpath:"..\..\..\..\..\..\lib\windows\guardedalloc\lib" /libpath:"../../../../../../lib/windows/python/lib" /libpath:"../../../../../../lib/windows/jpeg/lib" /libpath:"../../../../../../lib/windows/sdl/SDL-1.1.7\Lib" + +!ENDIF + +# Begin Target + +# Name "BlenderLoader - Win32 Release" +# Name "BlenderLoader - Win32 Debug" +# Name "BlenderLoader - Win32 Profile" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\..\source\blender\makesdna\intern\dna.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\GamePlayer\Loaders\Blender\loader.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\GamePlayer\Loaders\Blender\SDLKeyboardDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\GamePlayer\Loaders\Blender\SDLSystem.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\blender\blenkernel\bad_level_call_stubs\stubs.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\GamePlayer\Loaders\Blender\SDLCanvas.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\GamePlayer\Loaders\Blender\SDLInputDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\GamePlayer\Loaders\Blender\SDLKeyboardDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\GamePlayer\Loaders\Blender\SDLSystem.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Source File + +SOURCE=..\..\..\..\..\..\lib\windows\openal\lib\alc\ALc.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\..\lib\windows\openal\lib\alu\ALu.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\..\lib\windows\openal\lib\alut\ALut.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alBuffer.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alEax.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alError.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alExtension.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alListener.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alSource.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alState.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\..\lib\windows\openal\lib\OpenAL32\OpenAL32.obj +# End Source File +# End Target +# End Project diff --git a/projectfiles/gameengine/gameplayer/netscape/GP_netscape.dsp b/projectfiles/gameengine/gameplayer/netscape/GP_netscape.dsp new file mode 100644 index 00000000000..60dc29e4918 --- /dev/null +++ b/projectfiles/gameengine/gameplayer/netscape/GP_netscape.dsp @@ -0,0 +1,173 @@ +# Microsoft Developer Studio Project File - Name="GP_netscape" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=GP_netscape - Win32 Profile +!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 "GP_netscape.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 "GP_netscape.mak" CFG="GP_netscape - Win32 Profile" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GP_netscape - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "GP_netscape - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "GP_netscape - Win32 Profile" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GP_netscape - 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 "C:\Program Files\Netscape\Communicator\Program\Plugins" +# PROP Intermediate_Dir ".\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /I "..\..\..\..\source\gameengine\converter" /I "..\..\..\..\source\gameengine\gameplayer\common\windows" /I "..\..\..\..\source\gameengine\GamePlayer\Netscape\windows_sdk" /I "..\..\..\..\..\lib\windows\iksolver\include" /I "../../../../../lib/windows/moto/include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libjpeg.lib opengl32.lib glu32.lib libblenkey.a libz.a /nologo /subsystem:windows /dll /machine:I386 /out:"C:\Program Files\Netscape\Communicator\Program\Plugins\NPBlender.dll" /libpath:"../../../../../lib/windows/python/lib" /libpath:"../../../../../lib/windows/jpeg/lib" /libpath:"../../../../../lib/windows/zlib/lib/" /libpath:"..\..\..\..\..\lib\windows\blenkey\lib" /libpath:"..\..\..\..\..\lib\windows\openssl\lib" /libpath:"..\..\..\..\..\lib\windows\iksolver\lib\\" + +!ELSEIF "$(CFG)" == "GP_netscape - 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 "C:\Program Files\Netscape\Communicator\Program\Plugins" +# PROP Intermediate_Dir ".\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\GamePlayer\Netscape\windows_sdk" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /I "..\..\..\..\source\gameengine\converter" /I "..\..\..\..\source\gameengine\gameplayer\common\windows" /I "..\..\..\..\..\lib\windows\iksolver\include" /I "../../../../../lib/windows/moto/include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libjpeg.lib opengl32.lib glu32.lib openal_static.lib dxguid.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libjpeg.lib opengl32.lib glu32.lib openal_static.lib dxguid.lib libblenkey.a libz.a kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libjpeg.lib opengl32.lib glu32.lib openal_static.lib dxguid.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libjpeg.lib opengl32.lib glu32.lib openal_static.lib dxguid.lib python15.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"C:\Program Files\Netscape\Communicator\Program\Plugins\NPBlender.dll" /libpath:"../../../../../lib/windows/python/lib" /libpath:"../../../../../lib/windows/jpeg/lib" /libpath:"../../../../../lib/windows/openal/lib" /libpath:"../../../../../lib/windows/zlib/lib/" /libpath:"..\..\..\..\..\lib\windows\blenkey\lib" /libpath:"..\..\..\..\..\lib\windows\openssl\lib" /libpath:"..\..\..\..\..\lib\windows\iksolver\lib\\" + +!ELSEIF "$(CFG)" == "GP_netscape - Win32 Profile" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "GP_netscape___Win32_Profile" +# PROP BASE Intermediate_Dir "GP_netscape___Win32_Profile" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "GP_netscape___Win32_Profile" +# PROP Intermediate_Dir "GP_netscape___Win32_Profile" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\GamePlayer\Netscape\windows_sdk" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /I "..\..\..\..\source\gameengine\converter" /I "..\..\..\..\source\gameengine\gameplayer\common\windows" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /O2 /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\GamePlayer\Netscape\windows_sdk" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /I "..\..\..\..\source\gameengine\converter" /I "..\..\..\..\source\gameengine\gameplayer\common\windows" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libjpeg.lib opengl32.lib glu32.lib openal_static.lib dxguid.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"C:\Program Files\Netscape\Communicator\Program\Plugins\NPBlender.dll" /libpath:"../../../../../lib/windows/python/lib" /libpath:"../../../../../lib/windows/jpeg/lib" /libpath:"../../../../../lib/windows/openal/lib" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libjpeg.lib opengl32.lib glu32.lib openal_static.lib dxguid.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"C:\Program Files\Netscape\Communicator\Program\Plugins\NPBlender.dll" /libpath:"../../../../../lib/windows/python/lib" /libpath:"../../../../../lib/windows/jpeg/lib" /libpath:"../../../../../lib/windows/openal/lib" + +!ENDIF + +# Begin Target + +# Name "GP_netscape - Win32 Release" +# Name "GP_netscape - Win32 Debug" +# Name "GP_netscape - Win32 Profile" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape\windows\BlenderPlayer.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\blender\makesdna\intern\dna.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape\windows\netscape_plugin_Plugin.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape\npblender.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape\windows\npblender.def +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape\windows\npblender.rc +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape\windows\npwin.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\blender\blenkernel\bad_level_call_stubs\stubs.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# End Group +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\NSPlugin\autodownload.html +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape\Testing\NetscapeExample.html +# End Source File +# End Target +# End Project diff --git a/projectfiles/gameengine/gameplayer/netscape2/GP_netscape.dsp b/projectfiles/gameengine/gameplayer/netscape2/GP_netscape.dsp new file mode 100644 index 00000000000..e065ac280b7 --- /dev/null +++ b/projectfiles/gameengine/gameplayer/netscape2/GP_netscape.dsp @@ -0,0 +1,181 @@ +# Microsoft Developer Studio Project File - Name="GP_netscape2" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=GP_netscape2 - Win32 Profile +!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 "GP_netscape.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 "GP_netscape.mak" CFG="GP_netscape2 - Win32 Profile" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GP_netscape2 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "GP_netscape2 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "GP_netscape2 - Win32 Profile" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GP_netscape2 - 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 "C:\Program Files\Netscape\Communicator\Program\Plugins" +# PROP Intermediate_Dir ".\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\..\source\kernel\gen_messaging" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\GamePlayer\Netscape2\windows_sdk" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /I "..\..\..\..\source\gameengine\converter" /I "..\..\..\..\source\gameengine\gameplayer\common\windows" /I "..\..\..\..\source\gameengine\gameplayer\Netscape2\windows" /I "..\..\..\..\..\lib\windows\iksolver\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 libblenkey.a libeay32.lib libz.a ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libjpeg.lib opengl32.lib glu32.lib openal_static.lib dxguid.lib /nologo /subsystem:windows /dll /machine:I386 /out:"C:\Program Files\Netscape\Communicator\Program\Plugins\npBlender3DPlugin.dll" /libpath:"../../../../../lib/windows/python/lib" /libpath:"../../../../../lib/windows/jpeg/lib" /libpath:"../../../../../lib/windows/zlib/lib/" /libpath:"..\..\..\..\..\lib\windows\blenkey\lib" /libpath:"..\..\..\..\..\lib\windows\openssl\lib" /libpath:"..\..\..\..\..\lib\windows\iksolver\lib\\" /libpath:"../../../../../lib/windows/openal/lib" + +!ELSEIF "$(CFG)" == "GP_netscape2 - 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 "C:\Program Files\Netscape\Communicator\Program\Plugins" +# PROP Intermediate_Dir ".\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\..\..\source\kernel\gen_messaging" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\GamePlayer\Netscape2\windows_sdk" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /I "..\..\..\..\source\gameengine\converter" /I "..\..\..\..\source\gameengine\gameplayer\common\windows" /I "..\..\..\..\source\gameengine\gameplayer\Netscape2\windows" /I "..\..\..\..\..\lib\windows\iksolver\include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /FR /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 +# ADD LINK32 libblenkey.a libeay32.lib libz.a ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libjpeg.lib opengl32.lib glu32.lib openal_static.lib dxguid.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"C:\Program Files\Netscape\Communicator\Program\Plugins\npBlender3DPlugin.dll" /libpath:"../../../../../lib/windows/python/lib" /libpath:"../../../../../lib/windows/jpeg/lib" /libpath:"../../../../../lib/windows/openal/lib" /libpath:"../../../../../lib/windows/zlib/lib/" /libpath:"..\..\..\..\..\lib\windows\blenkey\lib" /libpath:"..\..\..\lib\windows\openssl\lib" /libpath:"..\..\..\lib\windows\iksolver\lib\\" + +!ELSEIF "$(CFG)" == "GP_netscape2 - Win32 Profile" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "GP_netscape2___Win32_Profile" +# PROP BASE Intermediate_Dir "GP_netscape2___Win32_Profile" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "GP_netscape2___Win32_Profile" +# PROP Intermediate_Dir "GP_netscape2___Win32_Profile" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\GamePlayer\Netscape\windows_sdk" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /I "..\..\..\..\source\gameengine\converter" /I "..\..\..\..\source\gameengine\gameplayer\common\windows" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /O2 /I "..\..\..\..\source\kernel\gen_messaging" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\GamePlayer\Netscape2\windows_sdk" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /I "..\..\..\..\source\gameengine\converter" /I "..\..\..\..\source\gameengine\gameplayer\common\windows" /I "..\..\..\..\source\gameengine\gameplayer\Netscape2\windows" /I "..\..\..\..\..\lib\windows\iksolver\include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libjpeg.lib opengl32.lib glu32.lib openal_static.lib dxguid.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"C:\Program Files\Netscape\Communicator\Program\Plugins\NPBlender.dll" /libpath:"../../../../../lib/windows/python/lib" /libpath:"../../../../../lib/windows/jpeg/lib" /libpath:"../../../../../lib/windows/openal/lib" +# ADD LINK32 libblenkey.a libeay32.lib libz.a ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libjpeg.lib opengl32.lib glu32.lib openal_static.lib dxguid.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"C:\Program Files\Netscape\Communicator\Program\Plugins\npBlender3DPlugin.dll" /libpath:"../../../../../lib/windows/python/lib" /libpath:"../../../../../lib/windows/jpeg/lib" /libpath:"../../../../../lib/windows/openal/lib" + +!ENDIF + +# Begin Target + +# Name "GP_netscape2 - Win32 Release" +# Name "GP_netscape2 - Win32 Debug" +# Name "GP_netscape2 - Win32 Profile" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape2\windows\Blender3DPlugin.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\blender\makesdna\intern\dna.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape2\windows\netscape_plugin_Plugin.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape2\windows\npblender.def +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape2\windows\npblender.rc +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape2\npshell.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape2\windows\npwin.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape2\windows\plgwnd.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\blender\blenkernel\bad_level_call_stubs\stubs.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape\plgwnd.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# End Group +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\NSPlugin\autodownload.html +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape\Testing\NetscapeExample.html +# End Source File +# End Target +# End Project diff --git a/projectfiles/gameengine/gameplayer/ps2/GP_ps2.dsp b/projectfiles/gameengine/gameplayer/ps2/GP_ps2.dsp new file mode 100644 index 00000000000..84aa94ef1a5 --- /dev/null +++ b/projectfiles/gameengine/gameplayer/ps2/GP_ps2.dsp @@ -0,0 +1,182 @@ +# Microsoft Developer Studio Project File - Name="GP_ps2" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=GP_ps2 - Win32 Profile +!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 "GP_ps2.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 "GP_ps2.mak" CFG="GP_ps2 - Win32 Profile" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GP_ps2 - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "GP_ps2 - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "GP_ps2 - Win32 Profile" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GP_ps2 - 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 "..\..\..\..\obj\windows\gameengine\gameplayer\ps2" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /GX /O2 /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\sumo\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "GP_ps2 - 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 "..\..\..\..\obj\windows\gameengine\gameplayer\ps2\debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\sumo\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "GP_ps2 - Win32 Profile" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "GP_ps2___Win32_Profile" +# PROP BASE Intermediate_Dir "GP_ps2___Win32_Profile" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "GP_ps2___Win32_Profile" +# PROP Intermediate_Dir "GP_ps2___Win32_Profile" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\sumo\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /O2 /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\sumo\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "GP_ps2 - Win32 Release" +# Name "GP_ps2 - Win32 Debug" +# Name "GP_ps2 - Win32 Profile" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\DebugActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\GPC_Init.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\PS2DualShockDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\PS2GamePlayer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\PS2System.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\DebugActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\ExampleEngine.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\GPC_Init.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\PS2Canvas.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\PS2DualShockDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\PS2InputDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\PS2Rasterizer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\PS2RenderTools.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\PS2System.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\SamplePolygonMaterial.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/gameplayer/qt/gp.dsp b/projectfiles/gameengine/gameplayer/qt/gp.dsp new file mode 100644 index 00000000000..512c5b69de6 --- /dev/null +++ b/projectfiles/gameengine/gameplayer/qt/gp.dsp @@ -0,0 +1,164 @@ +# Microsoft Developer Studio Project File - Name="gp" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=gp - 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 "gp.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 "gp.mak" CFG="gp - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gp - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "gp - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gp - 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 "..\..\..\..\..\obj\windows\gameengine\gameplayer\qt\gp" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\gameplayer\qt\gp" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "h:\qtwin\include" /I "..\..\..\..\source\gameengine\Expressions" /I "..\..\..\..\source\gameengine\GameLogic" /I "..\..\..\..\source\gameengine\Ketsji" /I "..\..\..\..\source\gameengine\Ketsji\KXNetwork" /I "..\..\..\..\source\gameengine\Network" /I "..\..\..\..\source\gameengine\Network\LoopBackNetwork" /I "..\..\..\..\source\gameengine\Rasterizer" /I "..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer" /I "..\..\..\..\source\gameengine\SceneGraph" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\..\lib\windows\python\include\python2.0" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 opengl32.lib glu32.lib kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib imm32.lib winmm.lib wsock32.lib h:\qtwin\lib\qt.lib h:\qtwin\lib\qnp.lib python20.lib /nologo /subsystem:windows /machine:I386 /out:"..\..\..\..\..\obj\windows\gp.exe" /libpath:"..\..\..\..\..\lib\windows\python\lib\\" + +!ELSEIF "$(CFG)" == "gp - 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 "..\..\..\..\..\obj\windows\gameengine\gameplayer\qt\gp\debug" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\gameplayer\qt\gp\debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /GX /Od /I "h:\qtwin\include" /I "..\..\..\..\source\gameengine\Expressions" /I "..\..\..\..\source\gameengine\GameLogic" /I "..\..\..\..\source\gameengine\Ketsji" /I "..\..\..\..\source\gameengine\Ketsji\KXNetwork" /I "..\..\..\..\source\gameengine\Network" /I "..\..\..\..\source\gameengine\Network\LoopBackNetwork" /I "..\..\..\..\source\gameengine\Rasterizer" /I "..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer" /I "..\..\..\..\source\gameengine\SceneGraph" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /D "_DEBUG" /D "WIN32" +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 opengl32.lib glu32.lib kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib imm32.lib winmm.lib wsock32.lib h:\qtwin\lib\qt.lib python15_d.lib /nologo /subsystem:windows /debug /machine:I386 /out:"..\..\..\..\..\obj\windows\debug\gp.exe" /libpath:"..\..\..\..\..\lib\windows\python\lib\\" +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "gp - Win32 Release" +# Name "gp - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\GP.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\GP_Init.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtExampleEngine.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtKeyboardDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtOpenGLWidget.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtSystem.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\DebugActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\GP_Init.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtExampleEngine.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtInputDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtKeyboardDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtOpenGLWidget.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtRenderTools.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtSystem.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\SamplePolygonMaterial.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/gameplayer/qt/gpplugin.dsp b/projectfiles/gameengine/gameplayer/qt/gpplugin.dsp new file mode 100644 index 00000000000..180f147c79a --- /dev/null +++ b/projectfiles/gameengine/gameplayer/qt/gpplugin.dsp @@ -0,0 +1,824 @@ +# Microsoft Developer Studio Project File - Name="gpplugin" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=gpplugin - 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 "gpplugin.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 "gpplugin.mak" CFG="gpplugin - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gpplugin - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "gpplugin - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gpplugin - 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 "..\..\..\..\..\obj\windows\gameengine\gameplayer\qt\gpplugin" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\gameplayer\qt\gpplugin" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GPPLUGIN_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "h:\qtwin\include" /I "..\..\..\..\source\gameengine\Expressions" /I "..\..\..\..\source\gameengine\GameLogic" /I "..\..\..\..\source\gameengine\Ketsji" /I "..\..\..\..\source\gameengine\Ketsji\KXNetwork" /I "..\..\..\..\source\gameengine\Network" /I "..\..\..\..\source\gameengine\Network\LoopBackNetwork" /I "..\..\..\..\source\gameengine\Rasterizer" /I "..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer" /I "..\..\..\..\source\gameengine\SceneGraph" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\..\lib\windows\python\include\python2.0" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GPPLUGIN_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib imm32.lib winmm.lib wsock32.lib h:\qtwin\lib\qnp.lib h:\qtwin\lib\qt.lib opengl32.lib glu32.lib python20.lib /nologo /dll /machine:I386 /out:"..\..\..\..\..\obj\windows\npWebGP.dll" /libpath:"..\..\..\..\..\lib\windows\python\lib\\" + +!ELSEIF "$(CFG)" == "gpplugin - 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 "..\..\..\..\..\obj\windows\gameengine\gameplayer\qt\gpplugin\debug" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\gameplayer\qt\gpplugin\debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GPPLUGIN_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /GX /Zi /Od /I "h:\qtwin\include" /I "..\..\..\..\source\gameengine\Expressions" /I "..\..\..\..\source\gameengine\GameLogic" /I "..\..\..\..\source\gameengine\Ketsji" /I "..\..\..\..\source\gameengine\Ketsji\KXNetwork" /I "..\..\..\..\source\gameengine\Network" /I "..\..\..\..\source\gameengine\Network\LoopBackNetwork" /I "..\..\..\..\source\gameengine\Rasterizer" /I "..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer" /I "..\..\..\..\source\gameengine\SceneGraph" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /D "WIN32" /D "PLUGIN" /D "_DEBUG" +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x409 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib imm32.lib winmm.lib wsock32.lib h:\qtwin\lib\qnp.lib h:\qtwin\lib\qt.lib opengl32.lib glu32.lib python15_d.lib /nologo /subsystem:windows /dll /debug /machine:I386 /def:"..\..\..\..\source\gameengine\GamePlayer\Qt\GP.def" /out:"..\..\..\..\..\obj\windows\debug\npWebGP.dll" /libpath:"..\..\..\..\..\lib\windows\python\lib" +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "gpplugin - Win32 Release" +# Name "gpplugin - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\GP.cpp +DEP_CPP_GP_CP=\ + "..\..\..\..\..\qtwin\include\qapplication.h"\ + "..\..\..\..\..\qtwin\include\qarray.h"\ + "..\..\..\..\..\qtwin\include\qasciidict.h"\ + "..\..\..\..\..\qtwin\include\qbrush.h"\ + "..\..\..\..\..\qtwin\include\qcollection.h"\ + "..\..\..\..\..\qtwin\include\qcolor.h"\ + "..\..\..\..\..\qtwin\include\qconfig-large.h"\ + "..\..\..\..\..\qtwin\include\qconfig-medium.h"\ + "..\..\..\..\..\qtwin\include\qconfig-minimal.h"\ + "..\..\..\..\..\qtwin\include\qconfig-small.h"\ + "..\..\..\..\..\qtwin\include\qconfig.h"\ + "..\..\..\..\..\qtwin\include\qcstring.h"\ + "..\..\..\..\..\qtwin\include\qcursor.h"\ + "..\..\..\..\..\qtwin\include\qdatastream.h"\ + "..\..\..\..\..\qtwin\include\qdialog.h"\ + "..\..\..\..\..\qtwin\include\qevent.h"\ + "..\..\..\..\..\qtwin\include\qfeatures.h"\ + "..\..\..\..\..\qtwin\include\qfont.h"\ + "..\..\..\..\..\qtwin\include\qfontinfo.h"\ + "..\..\..\..\..\qtwin\include\qfontmetrics.h"\ + "..\..\..\..\..\qtwin\include\qframe.h"\ + "..\..\..\..\..\qtwin\include\qgarray.h"\ + "..\..\..\..\..\qtwin\include\qgdict.h"\ + "..\..\..\..\..\qtwin\include\qgl.h"\ + "..\..\..\..\..\qtwin\include\qglist.h"\ + "..\..\..\..\..\qtwin\include\qglobal.h"\ + "..\..\..\..\..\qtwin\include\qiconset.h"\ + "..\..\..\..\..\qtwin\include\qimage.h"\ + "..\..\..\..\..\qtwin\include\qintdict.h"\ + "..\..\..\..\..\qtwin\include\qiodevice.h"\ + "..\..\..\..\..\qtwin\include\qlist.h"\ + "..\..\..\..\..\qtwin\include\qmenudata.h"\ + "..\..\..\..\..\qtwin\include\qmessagebox.h"\ + "..\..\..\..\..\qtwin\include\qmime.h"\ + "..\..\..\..\..\qtwin\include\qnamespace.h"\ + "..\..\..\..\..\qtwin\include\qnp.h"\ + "..\..\..\..\..\qtwin\include\qobject.h"\ + "..\..\..\..\..\qtwin\include\qobjectdefs.h"\ + "..\..\..\..\..\qtwin\include\qpaintdevice.h"\ + "..\..\..\..\..\qtwin\include\qpainter.h"\ + "..\..\..\..\..\qtwin\include\qpalette.h"\ + "..\..\..\..\..\qtwin\include\qpen.h"\ + "..\..\..\..\..\qtwin\include\qpixmap.h"\ + "..\..\..\..\..\qtwin\include\qpngio.h"\ + "..\..\..\..\..\qtwin\include\qpoint.h"\ + "..\..\..\..\..\qtwin\include\qpointarray.h"\ + "..\..\..\..\..\qtwin\include\qpopupmenu.h"\ + "..\..\..\..\..\qtwin\include\qrect.h"\ + "..\..\..\..\..\qtwin\include\qregexp.h"\ + "..\..\..\..\..\qtwin\include\qregion.h"\ + "..\..\..\..\..\qtwin\include\qshared.h"\ + "..\..\..\..\..\qtwin\include\qsignal.h"\ + "..\..\..\..\..\qtwin\include\qsize.h"\ + "..\..\..\..\..\qtwin\include\qsizepolicy.h"\ + "..\..\..\..\..\qtwin\include\qstring.h"\ + "..\..\..\..\..\qtwin\include\qstringlist.h"\ + "..\..\..\..\..\qtwin\include\qstrlist.h"\ + "..\..\..\..\..\qtwin\include\qstyle.h"\ + "..\..\..\..\..\qtwin\include\qt_windows.h"\ + "..\..\..\..\..\qtwin\include\qtranslator.h"\ + "..\..\..\..\..\qtwin\include\qvaluelist.h"\ + "..\..\..\..\..\qtwin\include\qwidget.h"\ + "..\..\..\..\..\qtwin\include\qwindowdefs.h"\ + "..\..\..\..\..\qtwin\include\qwindowdefs_win.h"\ + "..\..\..\..\..\qtwin\include\qwmatrix.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\abstract.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\bufferobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\ceval.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\classobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\cobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\complexobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\config.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\dictobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\fileobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\floatobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\funcobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\import.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\intobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\intrcheck.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\listobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\longobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\methodobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\modsupport.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\moduleobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\mymalloc.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\myproto.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\object.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\objimpl.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\patchlevel.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pydebug.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pyerrors.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pyfpe.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pystate.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\Python.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pythonrun.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\rangeobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\sliceobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\stringobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\sysmodule.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\traceback.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\tupleobject.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_IInputDevice.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_ISystem.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\GP_Init.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtInputDevice.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtKeyboardDevice.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtOpenGLWidget.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtRenderTools.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtSystem.h"\ + "..\..\..\..\source\gameengine\Network\LoopBackNetwork\NG_LoopBackNetworkDeviceInterface.h"\ + "..\..\..\..\source\gameengine\Network\NG_NetworkDeviceInterface.h"\ + "..\..\..\..\source\gameengine\Network\NG_NetworkScene.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_ICanvas.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IPolygonMaterial.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IRasterizer.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IRenderTools.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_MaterialBucket.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_TexVert.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_HashedString.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_Matrix4x4.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_StdString.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Map.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_MinMax.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Optimize.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_random.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Stream.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_assert.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Matrix3x3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Matrix3x3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point2.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Quaternion.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Quaternion.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Scalar.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Transform.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple4.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector2.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector4.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector4.inl"\ + "..\..\..\..\..\lib\windows\moto\include\NM_Scalar.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\GP_Init.cpp +DEP_CPP_GP_IN=\ + "..\..\..\..\..\lib\windows\python\include\python1.5\abstract.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\bufferobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\ceval.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\classobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\cobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\complexobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\config.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\dictobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\fileobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\floatobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\funcobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\import.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\intobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\intrcheck.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\listobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\longobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\methodobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\modsupport.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\moduleobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\mymalloc.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\myproto.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\object.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\objimpl.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\patchlevel.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pydebug.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pyerrors.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pyfpe.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pystate.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\Python.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pythonrun.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\rangeobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\sliceobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\stringobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\sysmodule.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\traceback.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\tupleobject.h"\ + "..\..\..\..\source\gameengine\Expressions\BoolValue.h"\ + "..\..\..\..\source\gameengine\Expressions\ListValue.h"\ + "..\..\..\..\source\gameengine\Expressions\PyObjectPlus.h"\ + "..\..\..\..\source\gameengine\Expressions\Value.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_AlwaysEventManager.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_AlwaysSensor.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_ANDController.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_EventManager.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_IActuator.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_IController.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_IInputDevice.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_ILogicBrick.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_IObject.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_ISensor.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_ISystem.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_KeyboardManager.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_KeyboardSensor.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_LogicManager.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_PythonController.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\DebugActuator.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtExampleEngine.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\SamplePolygonMaterial.h"\ + "..\..\..\..\source\gameengine\Ketsji\KX_GameObject.h"\ + "..\..\..\..\source\gameengine\Ketsji\KX_ObjectActuator.h"\ + "..\..\..\..\source\gameengine\Ketsji\KX_PythonInit.h"\ + "..\..\..\..\source\gameengine\Ketsji\KX_SoundActuator.h"\ + "..\..\..\..\source\gameengine\Ketsji\KXNetwork\KX_NetworkEventManager.h"\ + "..\..\..\..\source\gameengine\Network\LoopBackNetwork\NG_LoopBackNetworkDeviceInterface.h"\ + "..\..\..\..\source\gameengine\Network\NG_NetworkDeviceInterface.h"\ + "..\..\..\..\source\gameengine\Network\NG_NetworkScene.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_BucketManager.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_ICanvas.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IPolygonMaterial.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IRasterizer.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_MaterialBucket.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_MeshObject.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer\RAS_OpenGLRasterizer.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_Polygon.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_TexVert.h"\ + "..\..\..\..\source\gameengine\SceneGraph\SG_IObject.h"\ + "..\..\..\..\source\gameengine\SceneGraph\SG_Node.h"\ + "..\..\..\..\source\gameengine\SceneGraph\SG_Spatial.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_HashedPtr.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_HashedString.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_Matrix4x4.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_StdString.h"\ + "..\..\..\..\source\sumo\include\solid.h"\ + "..\..\..\..\source\sumo\include\solid_types.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Map.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_MinMax.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Optimize.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_random.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Stream.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_assert.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Matrix3x3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Matrix3x3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point2.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Quaternion.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Quaternion.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Scalar.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Transform.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple4.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector2.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector4.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector4.inl"\ + "..\..\..\..\..\lib\windows\moto\include\NM_Scalar.h"\ + +NODEP_CPP_GP_IN=\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\GPC_OpenALWaveCache.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\OpenALScene.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\SND_SoundObject.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtExampleEngine.cpp +DEP_CPP_QTEXA=\ + "..\..\..\..\..\lib\windows\python\include\python1.5\abstract.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\bufferobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\ceval.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\classobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\cobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\complexobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\config.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\dictobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\fileobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\floatobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\funcobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\import.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\intobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\intrcheck.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\listobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\longobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\methodobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\modsupport.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\moduleobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\mymalloc.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\myproto.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\object.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\objimpl.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\patchlevel.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pydebug.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pyerrors.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pyfpe.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pystate.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\Python.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pythonrun.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\rangeobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\sliceobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\stringobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\sysmodule.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\traceback.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\tupleobject.h"\ + "..\..\..\..\source\gameengine\Expressions\BoolValue.h"\ + "..\..\..\..\source\gameengine\Expressions\IntValue.h"\ + "..\..\..\..\source\gameengine\Expressions\ListValue.h"\ + "..\..\..\..\source\gameengine\Expressions\PyObjectPlus.h"\ + "..\..\..\..\source\gameengine\Expressions\Value.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_IActuator.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_IInputDevice.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_ILogicBrick.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_IObject.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_ISystem.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_LogicManager.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtExampleEngine.h"\ + "..\..\..\..\source\gameengine\Ketsji\KX_Camera.h"\ + "..\..\..\..\source\gameengine\Ketsji\KX_GameObject.h"\ + "..\..\..\..\source\gameengine\Ketsji\KX_ObjectActuator.h"\ + "..\..\..\..\source\gameengine\Network\NG_NetworkScene.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_BucketManager.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_CameraData.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IPolygonMaterial.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IRasterizer.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IRenderTools.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_MaterialBucket.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_MeshObject.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_Polygon.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_TexVert.h"\ + "..\..\..\..\source\gameengine\SceneGraph\SG_IObject.h"\ + "..\..\..\..\source\gameengine\SceneGraph\SG_Node.h"\ + "..\..\..\..\source\gameengine\SceneGraph\SG_Spatial.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_HashedPtr.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_HashedString.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_Matrix4x4.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_StdString.h"\ + "..\..\..\..\source\sumo\Fuzzics\include\SM_Scene.h"\ + "..\..\..\..\source\sumo\include\solid.h"\ + "..\..\..\..\source\sumo\include\solid_types.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Map.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_MinMax.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Optimize.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_random.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Stream.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_assert.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Matrix3x3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Matrix3x3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point2.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Quaternion.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Quaternion.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Scalar.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Transform.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple4.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector2.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector4.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector4.inl"\ + "..\..\..\..\..\lib\windows\moto\include\NM_Scalar.h"\ + +NODEP_CPP_QTEXA=\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\OpenALScene.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtKeyboardDevice.cpp +DEP_CPP_QTKEY=\ + "..\..\..\..\source\gameengine\GameLogic\SCA_IInputDevice.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtInputDevice.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtKeyboardDevice.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtOpenGLWidget.cpp +DEP_CPP_QTOPE=\ + "..\..\..\..\..\qtwin\include\qapplication.h"\ + "..\..\..\..\..\qtwin\include\qarray.h"\ + "..\..\..\..\..\qtwin\include\qasciidict.h"\ + "..\..\..\..\..\qtwin\include\qbrush.h"\ + "..\..\..\..\..\qtwin\include\qcollection.h"\ + "..\..\..\..\..\qtwin\include\qcolor.h"\ + "..\..\..\..\..\qtwin\include\qconfig-large.h"\ + "..\..\..\..\..\qtwin\include\qconfig-medium.h"\ + "..\..\..\..\..\qtwin\include\qconfig-minimal.h"\ + "..\..\..\..\..\qtwin\include\qconfig-small.h"\ + "..\..\..\..\..\qtwin\include\qconfig.h"\ + "..\..\..\..\..\qtwin\include\qcstring.h"\ + "..\..\..\..\..\qtwin\include\qcursor.h"\ + "..\..\..\..\..\qtwin\include\qdatastream.h"\ + "..\..\..\..\..\qtwin\include\qevent.h"\ + "..\..\..\..\..\qtwin\include\qfeatures.h"\ + "..\..\..\..\..\qtwin\include\qfont.h"\ + "..\..\..\..\..\qtwin\include\qfontinfo.h"\ + "..\..\..\..\..\qtwin\include\qfontmetrics.h"\ + "..\..\..\..\..\qtwin\include\qframe.h"\ + "..\..\..\..\..\qtwin\include\qgarray.h"\ + "..\..\..\..\..\qtwin\include\qgdict.h"\ + "..\..\..\..\..\qtwin\include\qgl.h"\ + "..\..\..\..\..\qtwin\include\qglist.h"\ + "..\..\..\..\..\qtwin\include\qglobal.h"\ + "..\..\..\..\..\qtwin\include\qiconset.h"\ + "..\..\..\..\..\qtwin\include\qintdict.h"\ + "..\..\..\..\..\qtwin\include\qiodevice.h"\ + "..\..\..\..\..\qtwin\include\qlist.h"\ + "..\..\..\..\..\qtwin\include\qmenudata.h"\ + "..\..\..\..\..\qtwin\include\qmime.h"\ + "..\..\..\..\..\qtwin\include\qnamespace.h"\ + "..\..\..\..\..\qtwin\include\qobject.h"\ + "..\..\..\..\..\qtwin\include\qobjectdefs.h"\ + "..\..\..\..\..\qtwin\include\qpaintdevice.h"\ + "..\..\..\..\..\qtwin\include\qpalette.h"\ + "..\..\..\..\..\qtwin\include\qpixmap.h"\ + "..\..\..\..\..\qtwin\include\qpoint.h"\ + "..\..\..\..\..\qtwin\include\qpopupmenu.h"\ + "..\..\..\..\..\qtwin\include\qrect.h"\ + "..\..\..\..\..\qtwin\include\qregexp.h"\ + "..\..\..\..\..\qtwin\include\qregion.h"\ + "..\..\..\..\..\qtwin\include\qshared.h"\ + "..\..\..\..\..\qtwin\include\qsignal.h"\ + "..\..\..\..\..\qtwin\include\qsize.h"\ + "..\..\..\..\..\qtwin\include\qsizepolicy.h"\ + "..\..\..\..\..\qtwin\include\qstring.h"\ + "..\..\..\..\..\qtwin\include\qstringlist.h"\ + "..\..\..\..\..\qtwin\include\qstyle.h"\ + "..\..\..\..\..\qtwin\include\qt_windows.h"\ + "..\..\..\..\..\qtwin\include\qtranslator.h"\ + "..\..\..\..\..\qtwin\include\qvaluelist.h"\ + "..\..\..\..\..\qtwin\include\qwidget.h"\ + "..\..\..\..\..\qtwin\include\qwindowdefs.h"\ + "..\..\..\..\..\qtwin\include\qwindowdefs_win.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\abstract.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\bufferobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\ceval.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\classobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\cobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\complexobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\config.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\dictobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\fileobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\floatobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\funcobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\import.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\intobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\intrcheck.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\listobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\longobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\methodobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\modsupport.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\moduleobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\mymalloc.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\myproto.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\object.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\objimpl.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\patchlevel.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pydebug.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pyerrors.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pyfpe.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pystate.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\Python.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pythonrun.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\rangeobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\sliceobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\stringobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\sysmodule.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\traceback.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\tupleobject.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_IInputDevice.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_ISystem.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\GP_Init.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtInputDevice.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtKeyboardDevice.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtOpenGLWidget.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtRenderTools.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtSystem.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_ICanvas.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IPolygonMaterial.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IRasterizer.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IRenderTools.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_MaterialBucket.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_TexVert.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_HashedString.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_Matrix4x4.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_StdString.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Map.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_MinMax.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Optimize.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_random.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Stream.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_assert.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Matrix3x3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Matrix3x3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point2.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Quaternion.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Quaternion.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Scalar.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Transform.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple4.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector2.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector4.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector4.inl"\ + "..\..\..\..\..\lib\windows\moto\include\NM_Scalar.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtSystem.cpp +DEP_CPP_QTSYS=\ + "..\..\..\..\..\qtwin\include\qapplication.h"\ + "..\..\..\..\..\qtwin\include\qarray.h"\ + "..\..\..\..\..\qtwin\include\qasciidict.h"\ + "..\..\..\..\..\qtwin\include\qbrush.h"\ + "..\..\..\..\..\qtwin\include\qcollection.h"\ + "..\..\..\..\..\qtwin\include\qcolor.h"\ + "..\..\..\..\..\qtwin\include\qconfig-large.h"\ + "..\..\..\..\..\qtwin\include\qconfig-medium.h"\ + "..\..\..\..\..\qtwin\include\qconfig-minimal.h"\ + "..\..\..\..\..\qtwin\include\qconfig-small.h"\ + "..\..\..\..\..\qtwin\include\qconfig.h"\ + "..\..\..\..\..\qtwin\include\qcstring.h"\ + "..\..\..\..\..\qtwin\include\qcursor.h"\ + "..\..\..\..\..\qtwin\include\qdatastream.h"\ + "..\..\..\..\..\qtwin\include\qevent.h"\ + "..\..\..\..\..\qtwin\include\qfeatures.h"\ + "..\..\..\..\..\qtwin\include\qfont.h"\ + "..\..\..\..\..\qtwin\include\qfontinfo.h"\ + "..\..\..\..\..\qtwin\include\qfontmetrics.h"\ + "..\..\..\..\..\qtwin\include\qframe.h"\ + "..\..\..\..\..\qtwin\include\qgarray.h"\ + "..\..\..\..\..\qtwin\include\qgdict.h"\ + "..\..\..\..\..\qtwin\include\qgl.h"\ + "..\..\..\..\..\qtwin\include\qglist.h"\ + "..\..\..\..\..\qtwin\include\qglobal.h"\ + "..\..\..\..\..\qtwin\include\qiconset.h"\ + "..\..\..\..\..\qtwin\include\qintdict.h"\ + "..\..\..\..\..\qtwin\include\qiodevice.h"\ + "..\..\..\..\..\qtwin\include\qlist.h"\ + "..\..\..\..\..\qtwin\include\qmenudata.h"\ + "..\..\..\..\..\qtwin\include\qmime.h"\ + "..\..\..\..\..\qtwin\include\qnamespace.h"\ + "..\..\..\..\..\qtwin\include\qobject.h"\ + "..\..\..\..\..\qtwin\include\qobjectdefs.h"\ + "..\..\..\..\..\qtwin\include\qpaintdevice.h"\ + "..\..\..\..\..\qtwin\include\qpalette.h"\ + "..\..\..\..\..\qtwin\include\qpixmap.h"\ + "..\..\..\..\..\qtwin\include\qpoint.h"\ + "..\..\..\..\..\qtwin\include\qpopupmenu.h"\ + "..\..\..\..\..\qtwin\include\qrect.h"\ + "..\..\..\..\..\qtwin\include\qregexp.h"\ + "..\..\..\..\..\qtwin\include\qregion.h"\ + "..\..\..\..\..\qtwin\include\qshared.h"\ + "..\..\..\..\..\qtwin\include\qsignal.h"\ + "..\..\..\..\..\qtwin\include\qsize.h"\ + "..\..\..\..\..\qtwin\include\qsizepolicy.h"\ + "..\..\..\..\..\qtwin\include\qstring.h"\ + "..\..\..\..\..\qtwin\include\qstringlist.h"\ + "..\..\..\..\..\qtwin\include\qstyle.h"\ + "..\..\..\..\..\qtwin\include\qt_windows.h"\ + "..\..\..\..\..\qtwin\include\qtranslator.h"\ + "..\..\..\..\..\qtwin\include\qvaluelist.h"\ + "..\..\..\..\..\qtwin\include\qwidget.h"\ + "..\..\..\..\..\qtwin\include\qwindowdefs.h"\ + "..\..\..\..\..\qtwin\include\qwindowdefs_win.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\abstract.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\bufferobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\ceval.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\classobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\cobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\complexobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\config.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\dictobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\fileobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\floatobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\funcobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\import.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\intobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\intrcheck.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\listobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\longobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\methodobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\modsupport.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\moduleobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\mymalloc.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\myproto.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\object.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\objimpl.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\patchlevel.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pydebug.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pyerrors.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pyfpe.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pystate.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\Python.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pythonrun.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\rangeobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\sliceobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\stringobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\sysmodule.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\traceback.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\tupleobject.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_IInputDevice.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_ISystem.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\GP_Init.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtInputDevice.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtKeyboardDevice.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtOpenGLWidget.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtRenderTools.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtSystem.h"\ + "..\..\..\..\source\gameengine\Network\LoopBackNetwork\NG_LoopBackNetworkDeviceInterface.h"\ + "..\..\..\..\source\gameengine\Network\NG_NetworkDeviceInterface.h"\ + "..\..\..\..\source\gameengine\Network\NG_NetworkScene.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_ICanvas.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IPolygonMaterial.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IRasterizer.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IRenderTools.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_MaterialBucket.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_TexVert.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_HashedString.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_Matrix4x4.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_StdString.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Map.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_MinMax.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Optimize.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_random.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Stream.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_assert.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Matrix3x3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Matrix3x3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point2.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Quaternion.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Quaternion.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Scalar.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Transform.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple4.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector2.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector4.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector4.inl"\ + "..\..\..\..\..\lib\windows\moto\include\NM_Scalar.h"\ + +NODEP_CPP_QTSYS=\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\BKE_bad_level_calls.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\BLO_readfile.h"\ + +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\DebugActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\GP_Init.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtExampleEngine.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtInputDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtKeyboardDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtOpenGLWidget.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtRenderTools.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtSystem.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\resource.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\SamplePolygonMaterial.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\GP.rc +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/gameplayer/qt/qtgp.dsw b/projectfiles/gameengine/gameplayer/qt/qtgp.dsw new file mode 100644 index 00000000000..22d9c5db23c --- /dev/null +++ b/projectfiles/gameengine/gameplayer/qt/qtgp.dsw @@ -0,0 +1,323 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "BLO_loader"=..\..\..\blender\loader\BLO_loader.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "EXP_expressions"=..\..\expression\EXP_expressions.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "SCA_GameLogic"=..\..\gamelogic\SCA_GameLogic.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "KX_ketsji"=..\..\ketsji\KX_ketsji.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "KX_network"=..\..\ketsji\network\KX_network.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "SG_SceneGraph"=..\..\scenegraph\SG_SceneGraph.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "NG_loopbacknetwork"=..\..\network\loopbacknetwork\NG_loopbacknetwork.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "NG_network"=..\..\network\network\NG_network.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "RAS_openglrasterizer"=..\..\rasterizer\openglrasterizer\RAS_openglrasterizer.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "RAS_rasterizer"=..\..\rasterizer\RAS_rasterizer.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "SM_fuzzics"=..\..\..\sumo\fuzzics\SM_fuzzics.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "SM_moto"=..\..\..\sumo\moto\SM_moto.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "SM_solid"=..\..\..\sumo\solid\SM_solid.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "SND_openal"=..\..\sound\openal\SND_openal.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "SND_sound"=..\..\sound\SND_sound.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "SYS_system"=..\..\..\kernel\system\SYS_system.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "gp"=.\gp.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name EXP_expressions + End Project Dependency + Begin Project Dependency + Project_Dep_Name SCA_GameLogic + End Project Dependency + Begin Project Dependency + Project_Dep_Name KX_ketsji + End Project Dependency + Begin Project Dependency + Project_Dep_Name KX_network + End Project Dependency + Begin Project Dependency + Project_Dep_Name SG_SceneGraph + End Project Dependency + Begin Project Dependency + Project_Dep_Name NG_loopbacknetwork + End Project Dependency + Begin Project Dependency + Project_Dep_Name NG_network + End Project Dependency + Begin Project Dependency + Project_Dep_Name RAS_openglrasterizer + End Project Dependency + Begin Project Dependency + Project_Dep_Name RAS_rasterizer + End Project Dependency + Begin Project Dependency + Project_Dep_Name SM_fuzzics + End Project Dependency + Begin Project Dependency + Project_Dep_Name SM_moto + End Project Dependency + Begin Project Dependency + Project_Dep_Name SM_solid + End Project Dependency + Begin Project Dependency + Project_Dep_Name SND_openal + End Project Dependency + Begin Project Dependency + Project_Dep_Name SND_sound + End Project Dependency + Begin Project Dependency + Project_Dep_Name SYS_system + End Project Dependency +}}} + +############################################################################### + +Project: "gpplugin"=.\gpplugin.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name EXP_expressions + End Project Dependency + Begin Project Dependency + Project_Dep_Name SCA_GameLogic + End Project Dependency + Begin Project Dependency + Project_Dep_Name KX_ketsji + End Project Dependency + Begin Project Dependency + Project_Dep_Name KX_network + End Project Dependency + Begin Project Dependency + Project_Dep_Name SG_SceneGraph + End Project Dependency + Begin Project Dependency + Project_Dep_Name NG_loopbacknetwork + End Project Dependency + Begin Project Dependency + Project_Dep_Name NG_network + End Project Dependency + Begin Project Dependency + Project_Dep_Name RAS_openglrasterizer + End Project Dependency + Begin Project Dependency + Project_Dep_Name RAS_rasterizer + End Project Dependency + Begin Project Dependency + Project_Dep_Name SM_fuzzics + End Project Dependency + Begin Project Dependency + Project_Dep_Name SM_moto + End Project Dependency + Begin Project Dependency + Project_Dep_Name SM_solid + End Project Dependency + Begin Project Dependency + Project_Dep_Name SND_openal + End Project Dependency + Begin Project Dependency + Project_Dep_Name SND_sound + End Project Dependency + Begin Project Dependency + Project_Dep_Name SYS_system + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/projectfiles/gameengine/gameplayer/sdl/GP_sdl.dsp b/projectfiles/gameengine/gameplayer/sdl/GP_sdl.dsp new file mode 100644 index 00000000000..56c758de7e9 --- /dev/null +++ b/projectfiles/gameengine/gameplayer/sdl/GP_sdl.dsp @@ -0,0 +1,205 @@ +# Microsoft Developer Studio Project File - Name="GP_sdl" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=GP_sdl - Win32 Profile +!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 "GP_sdl.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 "GP_sdl.mak" CFG="GP_sdl - Win32 Profile" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GP_sdl - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "GP_sdl - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "GP_sdl - Win32 Profile" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GP_sdl - 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 "..\..\..\..\obj\windows\gameengine\gameplayer\sdl" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\Rasterizer" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\lib\windows\sdl\SDL-1.1.7\include" /I "..\..\..\..\..\lib\windows\python\include\python2.0" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 sdl.lib sdlmain.lib kernel32.lib winspool.lib comdlg32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib opengl32.lib user32.lib gdi32.lib advapi32.lib dxguid.lib ole32.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\..\..\..\lib\windows\sdl\sdl-1.1.7\lib" /libpath:"..\..\..\..\..\lib\windows\python\lib" + +!ELSEIF "$(CFG)" == "GP_sdl - 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 "..\..\..\..\obj\windows\gameengine\gameplayer\sdl\debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\Rasterizer" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\lib\windows\sdl\SDL-1.1.7\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 glu32.lib sdlmaindebug.lib sdldebug.lib opengl32.lib user32.lib gdi32.lib advapi32.lib dxguid.lib ole32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\..\..\lib\windows\sdl\sdl-1.1.7\lib" /libpath:"..\..\..\..\..\lib\windows\python\lib" /libpath:"..\..\..\..\..\lib\windows\openal\lib\lib_release" + +!ELSEIF "$(CFG)" == "GP_sdl - Win32 Profile" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "GP_sdl___Win32_Profile" +# PROP BASE Intermediate_Dir "GP_sdl___Win32_Profile" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "GP_sdl___Win32_Profile" +# PROP Intermediate_Dir "GP_sdl___Win32_Profile" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\Rasterizer" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\lib\windows\sdl\SDL-1.1.7\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /O2 /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\Rasterizer" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\lib\windows\sdl\SDL-1.1.7\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 glu32.lib sdlmaindebug.lib sdldebug.lib opengl32.lib user32.lib gdi32.lib advapi32.lib dxguid.lib ole32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\..\..\lib\windows\sdl\sdl-1.1.7\lib" /libpath:"..\..\..\..\..\lib\windows\python\lib" /libpath:"..\..\..\..\..\lib\windows\openal\lib\lib_release" +# ADD LINK32 glu32.lib sdlmaindebug.lib sdldebug.lib opengl32.lib user32.lib gdi32.lib advapi32.lib dxguid.lib ole32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\..\..\lib\windows\sdl\sdl-1.1.7\lib" /libpath:"..\..\..\..\..\lib\windows\python\lib" /libpath:"..\..\..\..\..\lib\windows\openal\lib\lib_release" + +!ENDIF + +# Begin Target + +# Name "GP_sdl - Win32 Release" +# Name "GP_sdl - Win32 Debug" +# Name "GP_sdl - Win32 Profile" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\SDL\main.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\SDL\SDLKeyboardDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\SDL\SDLRenderTools.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\SDL\SDLSystem.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\SDL\SDLCanvas.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\SDL\SDLInputDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\SDL\SDLKeyboardDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\SDL\SDLRenderTools.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\SDL\SDLSystem.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\alc\ALc.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\alu\ALu.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\alut\ALut.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alBuffer.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alEax.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alError.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alExtension.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alListener.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alSource.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alState.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\OpenAL32.obj +# End Source File +# End Target +# End Project diff --git a/projectfiles/gameengine/ketsji/KX_ketsji.dsp b/projectfiles/gameengine/ketsji/KX_ketsji.dsp new file mode 100644 index 00000000000..b7139d01bc3 --- /dev/null +++ b/projectfiles/gameengine/ketsji/KX_ketsji.dsp @@ -0,0 +1,690 @@ +# Microsoft Developer Studio Project File - Name="KX_ketsji" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=KX_ketsji - Win32 Release +!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 "KX_ketsji.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 "KX_ketsji.mak" CFG="KX_ketsji - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "KX_ketsji - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "KX_ketsji - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "KX_ketsji - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "KX_ketsji - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "KX_ketsji - 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 "..\..\..\obj\windows\gameengine\ketsji" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\ketsji" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "..\..\..\source\gameengine\physics\common\dummy" /I "..\..\..\extern\solid" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\..\lib\windows\soundsystem\include" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\scenegraph" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\sumo\include" /I "..\..\..\source\sumo\fuzzics\include" /I "..\..\..\source\gameengine\network" /I "..\..\..\source\gameengine\Converter" /I "..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\source\gameengine\physics" /I "..\..\..\source\gameengine\physics\common" /I "..\..\..\source\gameengine\physics\dummy" /I "..\..\..\source\gameengine\physics\sumo" /I "..\..\..\source\gameengine\physics\sumo\fuzzics\include" /I "..\..\..\source\gameengine\physics\sumo\include" /I "..\..\..\source\gameengine\physics\BlOde" /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\imbuf" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\gameengine\physics\bullet" /I "..\..\..\extern\bullet\linearmath" /I "..\..\..\extern\bullet\Bulletdynamics" /I "..\..\..\extern\bullet\Bullet" /I "..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer" /I "..\..\..\source\blender\blenlib" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /D "USE_SUMO_SOLID" /YX /J /FD /c +# 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 + +!ELSEIF "$(CFG)" == "KX_ketsji - 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 "..\..\..\obj\windows\gameengine\ketsji\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\ketsji\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\source\gameengine\physics\common\dummy" /I "..\..\..\extern\solid" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\..\lib\windows\soundsystem\include" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\scenegraph" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\sumo\include" /I "..\..\..\source\sumo\fuzzics\include" /I "..\..\..\source\gameengine\network" /I "..\..\..\source\gameengine\Converter" /I "..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\source\gameengine\physics" /I "..\..\..\source\gameengine\physics\common" /I "..\..\..\source\gameengine\physics\dummy" /I "..\..\..\source\gameengine\physics\sumo" /I "..\..\..\source\gameengine\physics\sumo\fuzzics\include" /I "..\..\..\source\gameengine\physics\sumo\include" /I "..\..\..\source\gameengine\physics\BlOde" /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\imbuf" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\gameengine\physics\bullet" /I "..\..\..\extern\bullet\linearmath" /I "..\..\..\extern\bullet\Bulletdynamics" /I "..\..\..\extern\bullet\Bullet" /I "..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer" /I "..\..\..\source\blender\blenlib" /D "JANCODEPANCO" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /D "USE_SUMO_SOLID" /U "_DEBUG" /YX /J /FD /GZ /c +# 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 + +!ELSEIF "$(CFG)" == "KX_ketsji - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "KX_ketsji___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "KX_ketsji___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\ketsji\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\ketsji\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\soundsystem" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\scenegraph" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\sumo\include" /I "..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\lib\windows\python\include\python1.5" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\source\gameengine\physics\common\dummy" /I "..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\soundsystem" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\scenegraph" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\sumo\include" /I "..\..\..\source\sumo\fuzzics\include" /I "..\..\..\source\gameengine\network" /I "..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\source\gameengine\physics" /I "..\..\..\source\gameengine\physics\common" /I "..\..\..\source\gameengine\physics\dummy" /I "..\..\..\source\gameengine\physics\sumo" /I "..\..\..\source\gameengine\physics\sumo\fuzzics\include" /I "..\..\..\source\gameengine\physics\sumo\include" /I "..\..\..\source\gameengine\physics\BlOde" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /U "_DEBUG" /YX /J /FD /GZ /c +# 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 /out:"..\..\..\..\..\obj\windows\gameengine\ketsji\debug\KX_ketsji.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "KX_ketsji - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "KX_ketsji___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "KX_ketsji___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\ketsji\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\ketsji\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\soundsystem" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\scenegraph" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\sumo\include" /I "..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\lib\windows\python\include\python2.0" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\source\gameengine\physics\common\dummy" /I "..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\soundsystem" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\scenegraph" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\sumo\include" /I "..\..\..\source\sumo\fuzzics\include" /I "..\..\..\source\gameengine\network" /I "..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\source\gameengine\physics" /I "..\..\..\source\gameengine\physics\common" /I "..\..\..\source\gameengine\physics\dummy" /I "..\..\..\source\gameengine\physics\sumo" /I "..\..\..\source\gameengine\physics\sumo\fuzzics\include" /I "..\..\..\source\gameengine\physics\sumo\include" /I "..\..\..\source\gameengine\physics\BlOde" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /YX /J /FD /c +# 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 /out:"..\..\..\..\..\obj\windows\gameengine\ketsji\KX_ketsji.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "KX_ketsji - Win32 Release" +# Name "KX_ketsji - Win32 Debug" +# Name "KX_ketsji - Win32 MT DLL Debug" +# Name "KX_ketsji - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Group "ActuatorsImp" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_CameraActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_CDActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ConstraintActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_GameActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_IpoActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ObjectActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SCA_AddObjectActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SCA_EndObjectActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SCA_ReplaceMeshActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SceneActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SoundActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_TrackToActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_VisibilityActuator.cpp +# End Source File +# End Group +# Begin Group "SG_ControllersImp" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_CameraIpoSGController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_IPO_SGController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_LightIpoSGController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ObColorIpoSGController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_WorldIpoController.cpp +# End Source File +# End Group +# Begin Group "SensorsImp" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_MouseFocusSensor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_NearSensor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_RadarSensor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_RaySensor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_TouchSensor.cpp +# End Source File +# End Group +# Begin Group "IposImp" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_OrientationInterpolator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_PositionInterpolator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ScalarInterpolator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ScalingInterpolator.cpp +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\BL_Material.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\BL_Shader.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\BL_Texture.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_BlenderMaterial.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_BulletPhysicsController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_Camera.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ConstraintWrapper.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ConvertPhysicsObjects.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_EmptyObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_GameObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_IPhysicsController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_KetsjiEngine.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_Light.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_MaterialIpoController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_MeshProxy.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_MotionState.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_OdePhysicsController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_PhysicsObjectWrapper.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_PolygonMaterial.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_PyConstraintBinding.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_PyMath.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_PythonInit.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_RayCast.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_RayEventManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_Scene.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SG_BoneParentNodeRelationship.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SG_NodeRelationships.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SumoPhysicsController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_TimeCategoryLogger.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_TimeLogger.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_TouchEventManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_VehicleWrapper.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_VertexProxy.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_WorldInfo.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Group "Actuators" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_CameraActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_CDActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ConstraintActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_GameActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_IpoActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ObjectActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SCA_AddObjectActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SCA_EndObjectActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SCA_ReplaceMeshActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SceneActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SoundActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_TrackToActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_VisibilityActuator.h +# End Source File +# End Group +# Begin Group "SG_Controllers" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_CameraIpoSGController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_IPO_SGController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_LightIpoSGController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ObColorIpoSGController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_WorldIpoController.h +# End Source File +# End Group +# Begin Group "Sensors" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_MouseFocusSensor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_NearSensor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_RadarSensor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_RaySensor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_TouchSensor.h +# End Source File +# End Group +# Begin Group "Ipos" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_IInterpolator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_IScalarInterpolator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_OrientationInterpolator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_PositionInterpolator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ScalarInterpolator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ScalingInterpolator.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\BL_Material.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\BL_Shader.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\BL_Texture.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_BlenderMaterial.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_BulletPhysicsController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_Camera.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ConstraintWrapper.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ConvertPhysicsObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_EmptyObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_GameObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_IPhysicsController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_IPOTransform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ISceneConverter.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ISystem.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_KetsjiEngine.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_Light.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_MaterialIpoController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_MeshProxy.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_MotionState.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_OdePhysicsController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_PhysicsObjectWrapper.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_PolygonMaterial.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_PyConstraintBinding.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_PyMath.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_PythonInit.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_RayCast.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_RayEventManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_Scene.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SG_BoneParentNodeRelationship.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SG_NodeRelationships.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SumoPhysicsController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_TimeCategoryLogger.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_TimeLogger.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_TouchEventManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_VehicleWrapper.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_VertexProxy.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_WorldInfo.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/ketsji/network/KX_network.dsp b/projectfiles/gameengine/ketsji/network/KX_network.dsp new file mode 100644 index 00000000000..0c265e9dd56 --- /dev/null +++ b/projectfiles/gameengine/ketsji/network/KX_network.dsp @@ -0,0 +1,186 @@ +# Microsoft Developer Studio Project File - Name="KX_network" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=KX_network - Win32 Release +!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 "KX_network.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 "KX_network.mak" CFG="KX_network - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "KX_network - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "KX_network - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "KX_network - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "KX_network - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "KX_network - 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 "..\..\..\..\obj\windows\gameengine\ketsji\network" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\ketsji\network" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "..\..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\GameLogic" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\Network" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 + +!ELSEIF "$(CFG)" == "KX_network - 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 "..\..\..\..\obj\windows\gameengine\ketsji\network\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\ketsji\network\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\GameLogic" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\Network" /D "WIN32" /D "_MBCS" /D "_LIB" /U "_DEBUG" /YX /J /FD /GZ /c +# 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 + +!ELSEIF "$(CFG)" == "KX_network - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "KX_network___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "KX_network___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\ketsji\network\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\ketsji\network\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\GameLogic" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\Network" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\GameLogic" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\Network" /D "WIN32" /D "_MBCS" /D "_LIB" /U "_DEBUG" /YX /J /FD /GZ /c +# 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 /out:"..\..\..\..\..\..\obj\windows\gameengine\ketsji\network\debug\KX_network.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "KX_network - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "KX_network___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "KX_network___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\ketsji\network\mtdll" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\ketsji\network\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\GameLogic" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\Network" /I "..\..\..\..\..\lib\windows\python\include\python2.0" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\GameLogic" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\Network" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 /out:"..\..\..\..\..\..\obj\windows\gameengine\ketsji\network\KX_network.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "KX_network - Win32 Release" +# Name "KX_network - Win32 Debug" +# Name "KX_network - Win32 MT DLL Debug" +# Name "KX_network - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Ketsji\KXNetwork\KX_NetworkEventManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Ketsji\KXNetwork\KX_NetworkMessageActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Ketsji\KXNetwork\KX_NetworkMessageSensor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Ketsji\KXNetwork\KX_NetworkObjectActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Ketsji\KXNetwork\KX_NetworkObjectSensor.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Ketsji\KXNetwork\KX_NetworkEventManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Ketsji\KXNetwork\KX_NetworkMessageActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Ketsji\KXNetwork\KX_NetworkMessageSensor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Ketsji\KXNetwork\KX_NetworkObjectActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Ketsji\KXNetwork\KX_NetworkObjectSensor.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/network/loopbacknetwork/NG_loopbacknetwork.dsp b/projectfiles/gameengine/network/loopbacknetwork/NG_loopbacknetwork.dsp new file mode 100644 index 00000000000..08bd4a1326d --- /dev/null +++ b/projectfiles/gameengine/network/loopbacknetwork/NG_loopbacknetwork.dsp @@ -0,0 +1,155 @@ +# Microsoft Developer Studio Project File - Name="NG_loopbacknetwork" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=NG_loopbacknetwork - Win32 Release +!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 "NG_loopbacknetwork.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 "NG_loopbacknetwork.mak" CFG="NG_loopbacknetwork - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "NG_loopbacknetwork - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "NG_loopbacknetwork - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "NG_loopbacknetwork - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "NG_loopbacknetwork - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "NG_loopbacknetwork - 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 "..\..\..\..\obj\windows\gameengine\network\loopbacknetwork" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\network\loopbacknetwork" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\Network" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 + +!ELSEIF "$(CFG)" == "NG_loopbacknetwork - 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 "..\..\..\..\obj\windows\gameengine\network\loopbacknetwork\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\network\loopbacknetwork\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\Network" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# SUBTRACT CPP /Fr +# 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 + +!ELSEIF "$(CFG)" == "NG_loopbacknetwork - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "NG_loopbacknetwork___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "NG_loopbacknetwork___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\network\loopbacknetwork\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\network\loopbacknetwork\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\Network" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\Network" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# 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 /out:"..\..\..\..\..\..\obj\windows\gameengine\network\loopbacknetwork\debug\NG_loopbacknetwork.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "NG_loopbacknetwork - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "NG_loopbacknetwork___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "NG_loopbacknetwork___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\network\loopbacknetwork\mtdll" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\network\loopbacknetwork\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\Network" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\Network" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 /out:"..\..\..\..\..\..\obj\windows\gameengine\network\loopbacknetwork\NG_loopbacknetwork.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "NG_loopbacknetwork - Win32 Release" +# Name "NG_loopbacknetwork - Win32 Debug" +# Name "NG_loopbacknetwork - Win32 MT DLL Debug" +# Name "NG_loopbacknetwork - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Network\LoopBackNetwork\NG_LoopBackNetworkDeviceInterface.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Network\LoopBackNetwork\NG_LoopBackNetworkDeviceInterface.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/network/network/NG_network.dsp b/projectfiles/gameengine/network/network/NG_network.dsp new file mode 100644 index 00000000000..8c13c01f7e7 --- /dev/null +++ b/projectfiles/gameengine/network/network/NG_network.dsp @@ -0,0 +1,174 @@ +# Microsoft Developer Studio Project File - Name="NG_network" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=NG_network - Win32 Release +!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 "NG_network.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 "NG_network.mak" CFG="NG_network - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "NG_network - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "NG_network - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "NG_network - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "NG_network - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "NG_network - 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 "..\..\..\..\obj\windows\gameengine\network\network" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\network\network" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\kernel\gen_system" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 + +!ELSEIF "$(CFG)" == "NG_network - 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 "..\..\..\..\obj\windows\gameengine\network\network\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\network\network\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\kernel\gen_system" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# 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 + +!ELSEIF "$(CFG)" == "NG_network - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "NG_network___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "NG_network___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\network\network\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\network\network\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\..\source\kernel\gen_system" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\kernel\gen_system" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# 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 /out:"..\..\..\..\..\..\obj\windows\gameengine\network\network\debug\NG_network.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "NG_network - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "NG_network___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "NG_network___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\network\network\mtdll" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\network\network\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\..\source\kernel\gen_system" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\kernel\gen_system" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 /out:"..\..\..\..\..\..\obj\windows\gameengine\network\network\NG_network.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "NG_network - Win32 Release" +# Name "NG_network - Win32 Debug" +# Name "NG_network - Win32 MT DLL Debug" +# Name "NG_network - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Network\NG_NetworkMessage.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Network\NG_NetworkObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Network\NG_NetworkScene.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Network\NG_NetworkDeviceInterface.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Network\NG_NetworkMessage.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Network\NG_NetworkObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Network\NG_NetworkScene.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/network/terraplaynetwork/NG_terraplaynetwork.dsp b/projectfiles/gameengine/network/terraplaynetwork/NG_terraplaynetwork.dsp new file mode 100644 index 00000000000..ce407eda0f7 --- /dev/null +++ b/projectfiles/gameengine/network/terraplaynetwork/NG_terraplaynetwork.dsp @@ -0,0 +1,180 @@ +# Microsoft Developer Studio Project File - Name="NG_terraplaynetwork" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=NG_terraplaynetwork - Win32 Profile +!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 "NG_terraplaynetwork.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 "NG_terraplaynetwork.mak" CFG="NG_terraplaynetwork - Win32 Profile" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "NG_terraplaynetwork - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "NG_terraplaynetwork - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "NG_terraplaynetwork - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "NG_terraplaynetwork - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE "NG_terraplaynetwork - Win32 Profile" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "NG_terraplaynetwork - 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 "..\..\..\..\..\obj\windows\gameengine\network\terraplaynetwork" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\..\lib\windows\terraplay\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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:"..\..\..\..\..\obj\windows\gameengine\network\terraplaynetwork\NG_terraplaynetwork.lib" + +!ELSEIF "$(CFG)" == "NG_terraplaynetwork - 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 "..\..\..\..\..\obj\windows\gameengine\network\terraplaynetwork\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\..\lib\windows\terraplay\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /FR /YX /J /FD /GZ /c +# 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:"..\..\..\..\..\obj\windows\gameengine\network\terraplaynetwork\debug\NG_terraplaynetwork.lib" + +!ELSEIF "$(CFG)" == "NG_terraplaynetwork - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "NG_terraplaynetwork___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "NG_terraplaynetwork___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\..\obj\windows\gameengine\network\terraplaynetwork\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\network\terraplaynetwork\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\..\lib\windows\terraplay\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\..\lib\windows\terraplay\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# 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 /out:"..\..\..\..\..\..\obj\windows\gameengine\network\terraplaynetwork\debug\NG_terraplaynetwork.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "NG_terraplaynetwork - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "NG_terraplaynetwork___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "NG_terraplaynetwork___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\..\obj\windows\gameengine\network\terraplaynetwork\mtdll" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\network\terraplaynetwork\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\..\lib\windows\terraplay\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\..\lib\windows\terraplay\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 /out:"..\..\..\..\..\..\obj\windows\gameengine\network\terraplaynetwork\NG_terraplaynetwork.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "NG_terraplaynetwork - Win32 Profile" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "NG_terraplaynetwork___Win32_Profile" +# PROP BASE Intermediate_Dir "NG_terraplaynetwork___Win32_Profile" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "NG_terraplaynetwork___Win32_Profile" +# PROP Intermediate_Dir "NG_terraplaynetwork___Win32_Profile" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\..\lib\windows\terraplay\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /O2 /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\..\lib\windows\terraplay\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 /out:"..\..\..\..\..\obj\windows\gameengine\network\terraplaynetwork\debug\NG_terraplaynetwork.lib" +# ADD LIB32 /nologo /out:"..\..\..\..\..\obj\windows\gameengine\network\terraplaynetwork\profile\NG_terraplaynetwork.lib" + +!ENDIF + +# Begin Target + +# Name "NG_terraplaynetwork - Win32 Release" +# Name "NG_terraplaynetwork - Win32 Debug" +# Name "NG_terraplaynetwork - Win32 MT DLL Debug" +# Name "NG_terraplaynetwork - Win32 MT DLL Release" +# Name "NG_terraplaynetwork - Win32 Profile" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Network\TerraplayNetwork\NG_TerraplayNetworkDeviceInterface.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Network\TerraplayNetwork\NG_TerraplayNetworkDeviceInterface.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/physics/PHY_Physics/PHY_Dummy/PHY_Dummy.dsp b/projectfiles/gameengine/physics/PHY_Physics/PHY_Dummy/PHY_Dummy.dsp new file mode 100644 index 00000000000..0cc26260fd0 --- /dev/null +++ b/projectfiles/gameengine/physics/PHY_Physics/PHY_Dummy/PHY_Dummy.dsp @@ -0,0 +1,154 @@ +# Microsoft Developer Studio Project File - Name="PHY_Dummy" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=PHY_Dummy - Win32 MT DLL 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 "PHY_Dummy.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 "PHY_Dummy.mak" CFG="PHY_Dummy - Win32 MT DLL Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "PHY_Dummy - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "PHY_Dummy - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "PHY_Dummy - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "PHY_Dummy - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "PHY_Dummy - 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 "..\..\..\..\..\obj\windows\gameengine\physics\dummy\" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\physics\dummy\" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GR /GX /O2 /I "../../../../../source/gameengine/physics/common" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# 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 + +!ELSEIF "$(CFG)" == "PHY_Dummy - 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 "..\..\..\..\..\obj\windows\gameengine\physics\dummy\debug" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\physics\dummy\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GR /GX /ZI /Od /I "../../../../../source/gameengine/physics/common" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# 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 + +!ELSEIF "$(CFG)" == "PHY_Dummy - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "PHY_Dummy___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "PHY_Dummy___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\..\obj\windows\gameengine\physics\dummy\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\physics\dummy\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../../../../source/gameengine/physics/common" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../../../../source/gameengine/physics/common" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# 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 + +!ELSEIF "$(CFG)" == "PHY_Dummy - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "PHY_Dummy___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "PHY_Dummy___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\..\obj\windows\gameengine\physics\dummy\mtdll" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\physics\dummy\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /I "../../../../../source/gameengine/physics/common" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../../../../source/gameengine/physics/common" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# 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 + +!ENDIF + +# Begin Target + +# Name "PHY_Dummy - Win32 Release" +# Name "PHY_Dummy - Win32 Debug" +# Name "PHY_Dummy - Win32 MT DLL Debug" +# Name "PHY_Dummy - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Dummy\DummyPhysicsEnvironment.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Dummy\DummyPhysicsEnvironment.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/physics/PHY_Physics/PHY_Ode/PHY_Ode.dsp b/projectfiles/gameengine/physics/PHY_Physics/PHY_Ode/PHY_Ode.dsp new file mode 100644 index 00000000000..fef5dbf63f5 --- /dev/null +++ b/projectfiles/gameengine/physics/PHY_Physics/PHY_Ode/PHY_Ode.dsp @@ -0,0 +1,162 @@ +# Microsoft Developer Studio Project File - Name="PHY_Ode" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=PHY_Ode - Win32 MT DLL 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 "PHY_Ode.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 "PHY_Ode.mak" CFG="PHY_Ode - Win32 MT DLL Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "PHY_Ode - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "PHY_Ode - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "PHY_Ode - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE "PHY_Ode - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "PHY_Ode - 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 "..\..\..\..\..\obj\windows\gameengine\physics\ode\" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\physics\ode\" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GR /GX /O2 /I "..\..\..\..\..\..\lib\windows\ode\include" /I "..\..\..\..\..\source\gameengine\physics\common" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /c +# 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 + +!ELSEIF "$(CFG)" == "PHY_Ode - 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 "..\..\..\..\..\obj\windows\gameengine\physics\ode\debug" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\physics\ode\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /ZI /Od /I "..\..\..\..\..\..\lib\windows\ode\include" /I "..\..\..\..\..\source\gameengine\physics\common" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# 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 + +!ELSEIF "$(CFG)" == "PHY_Ode - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "PHY_Ode___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "PHY_Ode___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\..\obj\windows\gameengine\physics\ode\mtdll" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\physics\ode\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /I "../../../../../source/ode/include" /I "..\..\..\..\..\..\lib\windows\ode\include" /I "../../../../../source/gameengine/physics/common" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "dSINGLE" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\..\..\..\lib\windows\ode\include" /I "..\..\..\..\..\source\gameengine\physics\common" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /c +# 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 + +!ELSEIF "$(CFG)" == "PHY_Ode - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "PHY_Ode___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "PHY_Ode___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\..\obj\windows\gameengine\physics\ode\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\physics\ode\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../../../../../lib/windows/ode/include" /I "../../../../../source/gameengine/physics/common" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "dSINGLE" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\..\..\..\lib\windows\ode\include" /I "..\..\..\..\..\source\gameengine\physics\common" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# 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 + +!ENDIF + +# Begin Target + +# Name "PHY_Ode - Win32 Release" +# Name "PHY_Ode - Win32 Debug" +# Name "PHY_Ode - Win32 MT DLL Release" +# Name "PHY_Ode - Win32 MT DLL Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\BlOde\OdePhysicsController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\BlOde\OdePhysicsEnvironment.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\BlOde\OdePhysicsController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\BlOde\OdePhysicsEnvironment.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/physics/PHY_Physics/PHY_Physics.dsp b/projectfiles/gameengine/physics/PHY_Physics/PHY_Physics.dsp new file mode 100644 index 00000000000..f54875c2c18 --- /dev/null +++ b/projectfiles/gameengine/physics/PHY_Physics/PHY_Physics.dsp @@ -0,0 +1,178 @@ +# Microsoft Developer Studio Project File - Name="PHY_Physics" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=PHY_Physics - Win32 MT DLL 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 "PHY_Physics.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 "PHY_Physics.mak" CFG="PHY_Physics - Win32 MT DLL Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "PHY_Physics - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "PHY_Physics - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "PHY_Physics - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "PHY_Physics - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "PHY_Physics - 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 "..\..\..\..\obj\windows\gameengine\physics" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\physics" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GR /GX /O2 /I "common" /I "dummy" /I "../../../../extern/solid/include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# 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 + +!ELSEIF "$(CFG)" == "PHY_Physics - 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 "..\..\..\..\obj\windows\gameengine\physics\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\physics\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GR /GX /ZI /Od /I "common" /I "dummy" /I "../../../../extern/solid/include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# 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 + +!ELSEIF "$(CFG)" == "PHY_Physics - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "PHY_Physics___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "PHY_Physics___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\physics\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\physics\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "common" /I "dummy" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "common" /I "dummy" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# 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 + +!ELSEIF "$(CFG)" == "PHY_Physics - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "PHY_Physics___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "PHY_Physics___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\physics\mtdll" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\physics\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /I "common" /I "dummy" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "common" /I "dummy" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# 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 + +!ENDIF + +# Begin Target + +# Name "PHY_Physics - Win32 Release" +# Name "PHY_Physics - Win32 Debug" +# Name "PHY_Physics - Win32 MT DLL Debug" +# Name "PHY_Physics - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Physics\common\PHY_IMotionState.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Physics\common\PHY_IPhysicsController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Physics\common\PHY_IPhysicsEnvironment.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Physics\common\PHY_DynamicTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Physics\common\PHY_IMotionState.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Physics\common\PHY_IPhysicsController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Physics\common\PHY_IPhysicsEnvironment.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Physics\common\PHY_Pro.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/physics/PHY_Physics/PHY_Sumo/PHY_Sumo.dsp b/projectfiles/gameengine/physics/PHY_Physics/PHY_Sumo/PHY_Sumo.dsp new file mode 100644 index 00000000000..8f148363add --- /dev/null +++ b/projectfiles/gameengine/physics/PHY_Physics/PHY_Sumo/PHY_Sumo.dsp @@ -0,0 +1,162 @@ +# Microsoft Developer Studio Project File - Name="PHY_Sumo" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=PHY_Sumo - 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 "PHY_Sumo.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 "PHY_Sumo.mak" CFG="PHY_Sumo - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "PHY_Sumo - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "PHY_Sumo - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "PHY_Sumo - 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 "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "../../../../../extern/solid" /I "../../../../../source/gameengine/physics" /I "../../../../../source/gameengine/physics/common" /I "../../../../../source/gameengine/physics/sumo" /I "../../../../../source/gameengine/physics/sumo/include" /I "../../../../../source/gameengine/physics/sumo/fuzzics/include" /I "../../../../../../lib/windows/Moto/include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# 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:"..\..\..\..\obj\windows\gameengine\physics\sumo\PHY_Sumo.lib" + +!ELSEIF "$(CFG)" == "PHY_Sumo - 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 "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GR /GX /ZI /Od /I "../../../../../extern/solid" /I "../../../../../source/gameengine/physics" /I "../../../../../source/gameengine/physics/common" /I "../../../../../source/gameengine/physics/sumo" /I "../../../../../source/gameengine/physics/sumo/include" /I "../../../../../source/gameengine/physics/sumo/fuzzics/include" /I "../../../../../../lib/windows/Moto/include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# 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:"..\..\..\..\obj\windows\gameengine\physics\sumo\debug\PHY_Sumo.lib" + +!ENDIF + +# Begin Target + +# Name "PHY_Sumo - Win32 Release" +# Name "PHY_Sumo - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\Fuzzics\src\SM_FhObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\Fuzzics\src\SM_MotionState.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\Fuzzics\src\SM_Object.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\Fuzzics\src\SM_Scene.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\SumoPHYCallbackBridge.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\SumoPhysicsController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\SumoPhysicsEnvironment.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_Callback.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_ClientObjectInfo.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_FhObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_MotionState.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_Object.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_Props.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_Scene.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\SumoPHYCallbackBridge.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\SumoPhysicsController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\SumoPhysicsEnvironment.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/rasterizer/RAS_rasterizer.dsp b/projectfiles/gameengine/rasterizer/RAS_rasterizer.dsp new file mode 100644 index 00000000000..c764823632e --- /dev/null +++ b/projectfiles/gameengine/rasterizer/RAS_rasterizer.dsp @@ -0,0 +1,243 @@ +# Microsoft Developer Studio Project File - Name="RAS_rasterizer" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=RAS_rasterizer - Win32 Release +!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 "RAS_rasterizer.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 "RAS_rasterizer.mak" CFG="RAS_rasterizer - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "RAS_rasterizer - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "RAS_rasterizer - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "RAS_rasterizer - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "RAS_rasterizer - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "RAS_rasterizer - 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 "..\..\..\obj\windows\gameengine\rasterizer" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\rasterizer" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "..\..\..\..\lib\windows\moto\include\\" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\source\kernel\gen_system" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 + +!ELSEIF "$(CFG)" == "RAS_rasterizer - 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 "..\..\..\obj\windows\gameengine\rasterizer\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\rasterizer\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\..\lib\windows\moto\include\\" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\source\kernel\gen_system" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# SUBTRACT CPP /Fr +# 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 + +!ELSEIF "$(CFG)" == "RAS_rasterizer - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "RAS_rasterizer___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "RAS_rasterizer___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\rasterizer\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\rasterizer\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "../../../../../lib/windows/moto/include" /I "..\..\..\source\kernel\gen_system" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "../../../../lib/windows/moto/include" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\source\kernel\gen_system" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# 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 /out:"..\..\..\..\..\obj\windows\gameengine\rasterizer\debug\RAS_rasterizer.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "RAS_rasterizer - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "RAS_rasterizer___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "RAS_rasterizer___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\rasterizer\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\rasterizer\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "../../../../../lib/windows/moto/include" /I "..\..\..\source\kernel\gen_system" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "../../../../lib/windows/moto/include" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\source\kernel\gen_system" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 /out:"..\..\..\..\..\obj\windows\gameengine\rasterizer\RAS_rasterizer.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "RAS_rasterizer - Win32 Release" +# Name "RAS_rasterizer - Win32 Debug" +# Name "RAS_rasterizer - Win32 MT DLL Debug" +# Name "RAS_rasterizer - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_BucketManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_FramingManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_IPolygonMaterial.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_IRenderTools.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_MaterialBucket.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_MeshObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_Polygon.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_texmatrix.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_TexVert.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_BucketManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_CameraData.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_Deformer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_FramingManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_ICanvas.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_IPolygonMaterial.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_IRasterizer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_IRenderTools.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_LightObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_MaterialBucket.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_MeshObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_ObjectColor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_Polygon.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_TexMatrix.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_TexVert.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/rasterizer/openglrasterizer/RAS_openglrasterizer.dsp b/projectfiles/gameengine/rasterizer/openglrasterizer/RAS_openglrasterizer.dsp new file mode 100644 index 00000000000..1f1b95291ed --- /dev/null +++ b/projectfiles/gameengine/rasterizer/openglrasterizer/RAS_openglrasterizer.dsp @@ -0,0 +1,183 @@ +# Microsoft Developer Studio Project File - Name="RAS_openglrasterizer" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=RAS_openglrasterizer - Win32 Release +!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 "RAS_openglrasterizer.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 "RAS_openglrasterizer.mak" CFG="RAS_openglrasterizer - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "RAS_openglrasterizer - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "RAS_openglrasterizer - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "RAS_openglrasterizer - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "RAS_openglrasterizer - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "RAS_openglrasterizer - 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 "..\..\..\..\obj\windows\gameengine\rasterizer\openglrasterizer" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\rasterizer\openglrasterizer" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\kernel\gen_system" /I "../../../../../lib/windows/moto/include" /I "..\..\..\..\source\gameengine\Rasterizer" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 + +!ELSEIF "$(CFG)" == "RAS_openglrasterizer - 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 "..\..\..\..\obj\windows\gameengine\rasterizer\openglrasterizer\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\rasterizer\openglrasterizer\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\kernel\gen_system" /I "../../../../../lib/windows/moto/include" /I "..\..\..\..\source\gameengine\Rasterizer" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# SUBTRACT CPP /Fr +# 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 + +!ELSEIF "$(CFG)" == "RAS_openglrasterizer - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "RAS_openglrasterizer___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "RAS_openglrasterizer___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\rasterizer\openglrasterizer\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\rasterizer\openglrasterizer\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\..\source\kernel\gen_system" /I "../../../../../lib/windows/moto/include" /I "..\..\..\..\source\gameengine\Rasterizer" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\kernel\gen_system" /I "../../../../../lib/windows/moto/include" /I "..\..\..\..\source\gameengine\Rasterizer" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# 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 /out:"..\..\..\..\..\..\obj\windows\gameengine\rasterizer\openglrasterizer\debug\RAS_openglrasterizer.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "RAS_openglrasterizer - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "RAS_openglrasterizer___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "RAS_openglrasterizer___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\rasterizer\openglrasterizer\mtdll" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\rasterizer\openglrasterizer\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\..\source\kernel\gen_system" /I ".../../../../../lib/windows/moto/include" /I "..\..\..\..\source\gameengine\Rasterizer" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\kernel\gen_system" /I "../../../../../lib/windows/moto/include" /I "..\..\..\..\source\gameengine\Rasterizer" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 /out:"..\..\..\..\..\..\obj\windows\gameengine\rasterizer\openglrasterizer\RAS_openglrasterizer.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "RAS_openglrasterizer - Win32 Release" +# Name "RAS_openglrasterizer - Win32 Debug" +# Name "RAS_openglrasterizer - Win32 MT DLL Debug" +# Name "RAS_openglrasterizer - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer\RAS_GLExtensionManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer\RAS_ListRasterizer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer\RAS_OpenGLRasterizer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer\RAS_VAOpenGLRasterizer.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer\RAS_GLExtensionManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer\RAS_ListRasterizer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer\RAS_OpenGLRasterizer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer\RAS_VAOpenGLRasterizer.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/scenegraph/SG_scenegraph.dsp b/projectfiles/gameengine/scenegraph/SG_scenegraph.dsp new file mode 100644 index 00000000000..5a2b4c8cba3 --- /dev/null +++ b/projectfiles/gameengine/scenegraph/SG_scenegraph.dsp @@ -0,0 +1,199 @@ +# Microsoft Developer Studio Project File - Name="SG_SceneGraph" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=SG_SceneGraph - Win32 Release +!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 "SG_SceneGraph.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 "SG_SceneGraph.mak" CFG="SG_SceneGraph - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SG_SceneGraph - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "SG_SceneGraph - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SG_SceneGraph - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SG_SceneGraph - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SG_SceneGraph - 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 "..\..\..\obj\windows\gameengine\scenegraph" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\scenegraph" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "../../../../lib/windows/moto/include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 + +!ELSEIF "$(CFG)" == "SG_SceneGraph - 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 "..\..\..\obj\windows\gameengine\scenegraph\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\scenegraph\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Zi /Od /I "../../../../lib/windows/moto/include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# SUBTRACT CPP /Fr +# 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 + +!ELSEIF "$(CFG)" == "SG_SceneGraph - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SG_SceneGraph___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "SG_SceneGraph___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\scenegraph\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\scenegraph\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "../../../../../lib/windows/moto/include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "../../../../lib/windows/moto/include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# 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 /out:"..\..\..\..\..\obj\windows\gameengine\scenegraph\debug\SG_SceneGraph.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SG_SceneGraph - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "SG_SceneGraph___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "SG_SceneGraph___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\scenegraph\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\scenegraph\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "../../../../../lib/windows/moto/include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "../../../../lib/windows/moto/include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 /out:"..\..\..\..\..\obj\windows\gameengine\scenegraph\SG_SceneGraph.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "SG_SceneGraph - Win32 Release" +# Name "SG_SceneGraph - Win32 Debug" +# Name "SG_SceneGraph - Win32 MT DLL Debug" +# Name "SG_SceneGraph - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_BBox.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_Controller.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_IObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_Node.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_Spatial.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_Tree.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_BBox.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_Controller.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_IObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_Node.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_ParentRelation.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_Spatial.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_Tree.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/kernel/gen_messaging/gen_messaging.dsp b/projectfiles/kernel/gen_messaging/gen_messaging.dsp new file mode 100644 index 00000000000..578f8971122 --- /dev/null +++ b/projectfiles/kernel/gen_messaging/gen_messaging.dsp @@ -0,0 +1,155 @@ +# Microsoft Developer Studio Project File - Name="gen_messaging" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=gen_messaging - Win32 Release +!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 "gen_messaging.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 "gen_messaging.mak" CFG="gen_messaging - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gen_messaging - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "gen_messaging - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "gen_messaging - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE "gen_messaging - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gen_messaging - 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 "..\..\..\obj\windows\kernel\gen_messaging" +# PROP Intermediate_Dir "..\..\..\obj\windows\kernel\gen_messaging" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\source\kernel\gen_messaging" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# 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 + +!ELSEIF "$(CFG)" == "gen_messaging - 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 "..\..\..\obj\windows\kernel\gen_messaging\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\kernel\gen_messaging\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\source\kernel\gen_messaging" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# SUBTRACT CPP /Fr +# 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 + +!ELSEIF "$(CFG)" == "gen_messaging - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "gen_messaging___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "gen_messaging___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\kernel\gen_messaging\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\kernel\gen_messaging\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /I "..\..\..\source\kernel\gen_messaging" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\source\kernel\gen_messaging" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# 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 + +!ELSEIF "$(CFG)" == "gen_messaging - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "gen_messaging___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "gen_messaging___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\kernel\gen_messaging\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\kernel\gen_messaging\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\source\kernel\gen_messaging" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\source\kernel\gen_messaging" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# 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 + +!ENDIF + +# Begin Target + +# Name "gen_messaging - Win32 Release" +# Name "gen_messaging - Win32 Debug" +# Name "gen_messaging - Win32 MT DLL Release" +# Name "gen_messaging - Win32 MT DLL Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\kernel\gen_messaging\intern\messaging.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\kernel\gen_messaging\GEN_messaging.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/kernel/system/SYS_system.dsp b/projectfiles/kernel/system/SYS_system.dsp new file mode 100644 index 00000000000..b424839e4ba --- /dev/null +++ b/projectfiles/kernel/system/SYS_system.dsp @@ -0,0 +1,183 @@ +# Microsoft Developer Studio Project File - Name="SYS_system" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=SYS_system - Win32 Release +!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 "SYS_system.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 "SYS_system.mak" CFG="SYS_system - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SYS_system - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "SYS_system - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SYS_system - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SYS_system - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SYS_system - 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 "..\..\..\obj\windows\gameengine\kernel\gen_system" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\kernel\gen_system" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\string\include" /I "../../../../../lib/windows/moto/include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 + +!ELSEIF "$(CFG)" == "SYS_system - 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 "..\..\..\obj\windows\gameengine\kernel\gen_system\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\kernel\gen_system\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\string\include" /I "../../../../../lib/windows/moto/include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# SUBTRACT CPP /Fr +# 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 + +!ELSEIF "$(CFG)" == "SYS_system - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SYS_system___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "SYS_system___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\kernel\gen_system\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\kernel\gen_system\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /MDd /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\lib\windows\string\include" /I "../../../../../lib/windows/moto/include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# 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 /out:"..\..\..\..\..\obj\windows\gameengine\kernel\gen_system\debug\SYS_system.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SYS_system - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "SYS_system___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "SYS_system___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\kernel\gen_system\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\kernel\gen_system\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\lib\windows\string\include" /I "../../../../../lib/windows/moto/include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 /out:"..\..\..\..\..\obj\windows\gameengine\kernel\gen_system\SYS_system.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "SYS_system - Win32 Release" +# Name "SYS_system - Win32 Debug" +# Name "SYS_system - Win32 MT DLL Debug" +# Name "SYS_system - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\kernel\gen_system\GEN_HashedPtr.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\kernel\gen_system\SYS_SingletonSystem.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\kernel\gen_system\SYS_System.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\kernel\gen_system\GEN_DataCache.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\kernel\gen_system\GEN_HashedPtr.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\kernel\gen_system\GEN_Map.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\kernel\gen_system\GEN_SmartPtr.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\kernel\gen_system\SYS_SingletonSystem.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\kernel\gen_system\SYS_System.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/sumo/fuzzics/SM_fuzzics.dsp b/projectfiles/sumo/fuzzics/SM_fuzzics.dsp new file mode 100644 index 00000000000..c415810d2c9 --- /dev/null +++ b/projectfiles/sumo/fuzzics/SM_fuzzics.dsp @@ -0,0 +1,216 @@ +# Microsoft Developer Studio Project File - Name="SM_fuzzics" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=SM_fuzzics - Win32 Profile +!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 "SM_fuzzics.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 "SM_fuzzics.mak" CFG="SM_fuzzics - Win32 Profile" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SM_fuzzics - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_fuzzics - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_fuzzics - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_fuzzics - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_fuzzics - Win32 Profile" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SM_fuzzics - 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 "..\..\..\obj\windows\sumo\fuzzics" +# PROP Intermediate_Dir "..\..\..\obj\windows\sumo\fuzzics" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "..\..\..\source\gameengine\physics\sumo\Fuzzics\include" /I "../../../../lib/windows/moto/include" /I "../../../extern/solid" /I "..\..\..\source\sumo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 + +!ELSEIF "$(CFG)" == "SM_fuzzics - 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 "..\..\..\obj\windows\sumo\fuzzics\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\sumo\fuzzics\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\source\gameengine\physics\sumo\Fuzzics\include" /I "../../../../lib/windows/moto/include" /I "../../../extern/solid" /I "..\..\..\source\sumo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# 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 + +!ELSEIF "$(CFG)" == "SM_fuzzics - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SM_fuzzics___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "SM_fuzzics___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\sumo\fuzzics\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\sumo\fuzzics\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\sumo\Fuzzics\include" /I "../../../../../lib/windows/moto/include" /I "..\..\..\source\sumo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\source\sumo\Fuzzics\include" /I "../../../../lib/windows/moto/include" /I "..\..\..\source\sumo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# 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 /out:"..\..\..\..\..\obj\windows\sumo\fuzzics\debug\SM_fuzzics.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SM_fuzzics - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "SM_fuzzics___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "SM_fuzzics___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\sumo\fuzzics\mtdll" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\sumo\fuzzics\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\sumo\Fuzzics\include" /I "../../../../../lib/windows/moto/include" /I "..\..\..\source\sumo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\source\sumo\Fuzzics\include" /I "../../../../lib/windows/moto/include" /I "..\..\..\source\sumo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 /out:"..\..\..\..\..\obj\windows\sumo\fuzzics\SM_fuzzics.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SM_fuzzics - Win32 Profile" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SM_fuzzics___Win32_Profile" +# PROP BASE Intermediate_Dir "SM_fuzzics___Win32_Profile" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "SM_fuzzics___Win32_Profile" +# PROP Intermediate_Dir "SM_fuzzics___Win32_Profile" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\source\sumo\Fuzzics\include" /I "../../../../../lib/windows/moto/include" /I "..\..\..\source\sumo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /O2 /I "..\..\..\source\sumo\Fuzzics\include" /I "../../../../lib/windows/moto/include" /I "..\..\..\source\sumo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 /out:"..\..\..\..\obj\windows\sumo\fuzzics\debug\SM_fuzzics.lib" +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\sumo\fuzzics\profile\SM_fuzzics.lib" + +!ENDIF + +# Begin Target + +# Name "SM_fuzzics - Win32 Release" +# Name "SM_fuzzics - Win32 Debug" +# Name "SM_fuzzics - Win32 MT DLL Debug" +# Name "SM_fuzzics - Win32 MT DLL Release" +# Name "SM_fuzzics - Win32 Profile" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Sumo\Fuzzics\src\SM_FhObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Sumo\Fuzzics\src\SM_Object.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Sumo\Fuzzics\src\SM_Scene.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_Callback.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_ClientObjectInfo.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_Debug.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_FhObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_MotionState.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_Object.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_Props.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_Scene.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/sumo/moto/SM_moto.dsp b/projectfiles/sumo/moto/SM_moto.dsp new file mode 100644 index 00000000000..3fd627ce60d --- /dev/null +++ b/projectfiles/sumo/moto/SM_moto.dsp @@ -0,0 +1,332 @@ +# Microsoft Developer Studio Project File - Name="SM_moto" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=SM_moto - Win32 Profile +!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 "SM_moto.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 "SM_moto.mak" CFG="SM_moto - Win32 Profile" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SM_moto - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_moto - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_moto - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_moto - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_moto - Win32 Profile" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SM_moto - 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 "..\..\..\..\obj\windows\sumo\moto" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\..\lib\windows\moto\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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:"..\..\..\..\obj\windows\sumo\moto\SM_moto.lib" + +!ELSEIF "$(CFG)" == "SM_moto - 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 "..\..\..\..\obj\windows\sumo\moto\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\..\source\sumo\MoTo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /FR /YX /J /FD /c +# 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:"..\..\..\..\obj\windows\sumo\moto\debug\SM_moto.lib" + +!ELSEIF "$(CFG)" == "SM_moto - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SM_moto___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "SM_moto___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\sumo\moto\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\sumo\moto\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\sumo\MoTo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\source\sumo\MoTo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /FR /YX /J /FD /GZ /c +# 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 /out:"..\..\..\..\..\obj\windows\sumo\moto\debug\SM_moto.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SM_moto - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "SM_moto___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "SM_moto___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\sumo\moto\mtdll" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\sumo\moto\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\sumo\MoTo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\source\sumo\MoTo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 /out:"..\..\..\..\..\obj\windows\sumo\moto\SM_moto.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SM_moto - Win32 Profile" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SM_moto___Win32_Profile" +# PROP BASE Intermediate_Dir "SM_moto___Win32_Profile" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "SM_moto___Win32_Profile" +# PROP Intermediate_Dir "SM_moto___Win32_Profile" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /O2 /I "..\..\..\source\sumo\MoTo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /O2 /I "..\..\..\source\sumo\MoTo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 /out:"..\..\..\..\obj\windows\sumo\moto\debug\SM_moto.lib" +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\sumo\moto\profile\SM_moto.lib" + +!ENDIF + +# Begin Target + +# Name "SM_moto - Win32 Release" +# Name "SM_moto - Win32 Debug" +# Name "SM_moto - Win32 MT DLL Debug" +# Name "SM_moto - Win32 MT DLL Release" +# Name "SM_moto - Win32 Profile" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_CmMatrix4x4.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Matrix3x3.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Matrix4x4.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Point3.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Quaternion.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_random.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Transform.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Vector2.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Vector3.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Vector4.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\GEN_List.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\GEN_Map.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_assert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_CmMatrix4x4.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Matrix3x3.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Matrix3x3.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Matrix4x4.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Matrix4x4.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_MinMax.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Optimize.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Point2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Point2.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Point3.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Point3.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Quaternion.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Quaternion.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_random.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Scalar.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Stream.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Transform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Tuple2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Tuple3.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Tuple4.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Vector2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Vector2.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Vector3.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Vector3.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Vector4.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Vector4.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\NM_Scalar.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/sumo/solid/SM_solid.dsp b/projectfiles/sumo/solid/SM_solid.dsp new file mode 100644 index 00000000000..dfaa85c35d8 --- /dev/null +++ b/projectfiles/sumo/solid/SM_solid.dsp @@ -0,0 +1,340 @@ +# Microsoft Developer Studio Project File - Name="SM_solid" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=SM_solid - Win32 Release +!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 "SM_solid.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 "SM_solid.mak" CFG="SM_solid - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SM_solid - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_solid - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_solid - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_solid - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SM_solid - 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 "..\..\..\obj\windows\sumo\solid" +# PROP Intermediate_Dir "..\..\..\obj\windows\sumo\solid" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\source\gameengine\physics\sumo\SOLID-3.0\include" /I "../../../../lib/windows/moto/include" /I "..\..\..\source\gameengine\physics\sumo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /J /FD /c +# SUBTRACT CPP /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 + +!ELSEIF "$(CFG)" == "SM_solid - 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 "..\..\..\obj\windows\sumo\solid\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\sumo\solid\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\source\gameengine\physics\sumo\SOLID-3.0\include" /I "../../../../lib/windows/moto/include" /I "..\..\..\source\gameengine\physics\sumo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# SUBTRACT CPP /Fr +# 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 + +!ELSEIF "$(CFG)" == "SM_solid - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SM_solid___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "SM_solid___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\sumo\solid\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\sumo\solid\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\sumo\SOLID-3.0\include" /I "../../../../../lib/windows/moto/include" /I "..\..\..\source\sumo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\source\gameengine\physics\sumo\SOLID-3.0\include" /I "../../../../lib/windows/moto/include" /I "..\..\..\source\gameengine\physics\sumo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# 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 /out:"..\..\..\..\..\obj\windows\sumo\solid\debug\SM_solid.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SM_solid - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "SM_solid___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "SM_solid___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\sumo\solid\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\sumo\solid\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\sumo\SOLID-3.0\include" /I "../../../../../lib/windows/moto/include" /I "..\..\..\source\sumo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\source\gameengine\physics\sumo\SOLID-3.0\include" /I "../../../../lib/windows/moto/include" /I "..\..\..\source\gameengine\physics\sumo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 /out:"..\..\..\..\..\obj\windows\sumo\solid\SM_solid.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "SM_solid - Win32 Release" +# Name "SM_solid - Win32 Debug" +# Name "SM_solid - Win32 MT DLL Debug" +# Name "SM_solid - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\BBoxTree.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Box.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Complex.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Cone.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Convex.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Cylinder.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_BP_C-api.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_BP_Endpoint.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_BP_Proxy.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_BP_Scene.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_C-api.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_DoubleBase.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_Encounter.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_FloatBase.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_LineSegment.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_Object.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_RespTable.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_Scene.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Polyhedron.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Polytope.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Sphere.cpp" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\AlgoTable.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\BBoxTree.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Box.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Complex.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Cone.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Convex.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Cylinder.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_AABBox.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_BBox.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_BP_Endpoint.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_BP_Proxy.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_BP_Scene.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_DoubleBase.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_Encounter.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_FloatBase.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_LineSegment.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_Object.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_Response.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_RespTable.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_Scene.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_VertexBase.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_VertexBased.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\IndexArray.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Polyhedron.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Polytope.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Shape.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Sphere.h" +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles_vc7/blender/BLO_readblenfile/BLO_readblenfile.vcproj b/projectfiles_vc7/blender/BLO_readblenfile/BLO_readblenfile.vcproj new file mode 100644 index 00000000000..3618ac56296 --- /dev/null +++ b/projectfiles_vc7/blender/BLO_readblenfile/BLO_readblenfile.vcproj @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/BPY_python/BPY_python.vcproj b/projectfiles_vc7/blender/BPY_python/BPY_python.vcproj new file mode 100644 index 00000000000..ac933502efb --- /dev/null +++ b/projectfiles_vc7/blender/BPY_python/BPY_python.vcproj @@ -0,0 +1,561 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/avi/BL_avi.vcproj b/projectfiles_vc7/blender/avi/BL_avi.vcproj new file mode 100644 index 00000000000..302586b1dc3 --- /dev/null +++ b/projectfiles_vc7/blender/avi/BL_avi.vcproj @@ -0,0 +1,379 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/blender.sln b/projectfiles_vc7/blender/blender.sln new file mode 100644 index 00000000000..0888cf7971a --- /dev/null +++ b/projectfiles_vc7/blender/blender.sln @@ -0,0 +1,815 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blender", "blender.vcproj", "{F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}" + ProjectSection(ProjectDependencies) = postProject + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F} = {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F} + {6E24BF09-9653-4166-A871-F65CC9E98A9B} = {6E24BF09-9653-4166-A871-F65CC9E98A9B} + {FB88301F-F725-401B-ACD7-D2ABBF333B71} = {FB88301F-F725-401B-ACD7-D2ABBF333B71} + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE} = {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE} + {9625642D-6F20-4FB6-A089-BE7441B223E3} = {9625642D-6F20-4FB6-A089-BE7441B223E3} + {E645CC32-4823-463E-82F0-46ADDE664018} = {E645CC32-4823-463E-82F0-46ADDE664018} + {51FB3D48-2467-4BFA-A321-D848252B437E} = {51FB3D48-2467-4BFA-A321-D848252B437E} + {31628053-825D-4C06-8A21-D13883489718} = {31628053-825D-4C06-8A21-D13883489718} + {EADC3C5A-6C51-4F03-8038-1553E7D7F740} = {EADC3C5A-6C51-4F03-8038-1553E7D7F740} + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D} = {DB6BE55D-B6D9-494D-856A-8764FF7BA91D} + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E} = {0A73055E-4DED-40CD-9F72-9093ED3EEC7E} + {09222F5E-1625-4FF3-A89A-384D16875EE5} = {09222F5E-1625-4FF3-A89A-384D16875EE5} + {E013786A-9575-4F34-81B2-33290357EE87} = {E013786A-9575-4F34-81B2-33290357EE87} + {415BFD6E-64CF-422B-AF88-C07F040A7292} = {415BFD6E-64CF-422B-AF88-C07F040A7292} + {106AE171-0083-41D6-A949-20DB0E8DC251} = {106AE171-0083-41D6-A949-20DB0E8DC251} + {4C3AB78A-52CA-4276-A041-39776E52D8C8} = {4C3AB78A-52CA-4276-A041-39776E52D8C8} + {6B801390-5F95-4F07-81A7-97FBA046AACC} = {6B801390-5F95-4F07-81A7-97FBA046AACC} + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94} = {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94} + {F90BD995-FFA4-4B18-81E8-FA4322C939E8} = {F90BD995-FFA4-4B18-81E8-FA4322C939E8} + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23} = {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23} + {8154A59A-CAED-403D-AB94-BC4E7C032666} = {8154A59A-CAED-403D-AB94-BC4E7C032666} + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7} = {3648FB9A-C36F-43AB-AED0-1F1361E67FC7} + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B} = {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B} + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA} = {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA} + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90} = {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90} + {E90C7BC2-CF30-4A60-A8F2-0050D592E358} = {E90C7BC2-CF30-4A60-A8F2-0050D592E358} + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879} = {9991A3C3-83FE-4AFE-9E18-9D01CB57E879} + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49} = {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49} + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA} = {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA} + {32CC75E2-EE85-45E6-8E3D-513F58464F43} = {32CC75E2-EE85-45E6-8E3D-513F58464F43} + {9A307EE5-CD77-47BC-BD87-62508C7E19D8} = {9A307EE5-CD77-47BC-BD87-62508C7E19D8} + {AB590CED-F71F-4A17-A89B-18583ECD633D} = {AB590CED-F71F-4A17-A89B-18583ECD633D} + {64019BFA-8C14-4FA6-B275-D7598D821FF6} = {64019BFA-8C14-4FA6-B275-D7598D821FF6} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BKE_blenkernel", "blenkernel\BKE_blenkernel.vcproj", "{CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BLI_blenlib", "blenlib\BLI_blenlib.vcproj", "{31628053-825D-4C06-8A21-D13883489718}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BLO_loader", "loader\BLO_loader.vcproj", "{E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BLO_readblenfile", "BLO_readblenfile\BLO_readblenfile.vcproj", "{DB6BE55D-B6D9-494D-856A-8764FF7BA91D}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BL_avi", "avi\BL_avi.vcproj", "{9A307EE5-CD77-47BC-BD87-62508C7E19D8}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BL_imbuf", "imbuf\BL_imbuf.vcproj", "{415BFD6E-64CF-422B-AF88-C07F040A7292}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BL_src", "src\BL_src.vcproj", "{FB88301F-F725-401B-ACD7-D2ABBF333B71}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BL_src_cre", "src\BL_src_cre.vcproj", "{64019BFA-8C14-4FA6-B275-D7598D821FF6}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BPY_python", "BPY_python\BPY_python.vcproj", "{5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BRA_radiosity", "radiosity\BRA_radiosity.vcproj", "{2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BRE_render", "render\BRE_render.vcproj", "{106AE171-0083-41D6-A949-20DB0E8DC251}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DNA_makesdna", "makesdna\DNA_makesdna.vcproj", "{E013786A-9575-4F34-81B2-33290357EE87}" + ProjectSection(ProjectDependencies) = postProject + {31628053-825D-4C06-8A21-D13883489718} = {31628053-825D-4C06-8A21-D13883489718} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EXP_expressions", "..\gameengine\expression\EXP_expressions.vcproj", "{EADC3C5A-6C51-4F03-8038-1553E7D7F740}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FTF_ftfont", "ftfont\FTF_ftfont.vcproj", "{A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GP_axctl", "..\gameengine\gameplayer\axctl\GP_axctl.vcproj", "{DF25E6F2-780C-438B-8AAD-D10CF8B3820A}" + ProjectSection(ProjectDependencies) = postProject + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F} = {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F} + {6E24BF09-9653-4166-A871-F65CC9E98A9B} = {6E24BF09-9653-4166-A871-F65CC9E98A9B} + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE} = {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE} + {9625642D-6F20-4FB6-A089-BE7441B223E3} = {9625642D-6F20-4FB6-A089-BE7441B223E3} + {E645CC32-4823-463E-82F0-46ADDE664018} = {E645CC32-4823-463E-82F0-46ADDE664018} + {51FB3D48-2467-4BFA-A321-D848252B437E} = {51FB3D48-2467-4BFA-A321-D848252B437E} + {31628053-825D-4C06-8A21-D13883489718} = {31628053-825D-4C06-8A21-D13883489718} + {EADC3C5A-6C51-4F03-8038-1553E7D7F740} = {EADC3C5A-6C51-4F03-8038-1553E7D7F740} + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D} = {DB6BE55D-B6D9-494D-856A-8764FF7BA91D} + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E} = {0A73055E-4DED-40CD-9F72-9093ED3EEC7E} + {09222F5E-1625-4FF3-A89A-384D16875EE5} = {09222F5E-1625-4FF3-A89A-384D16875EE5} + {E013786A-9575-4F34-81B2-33290357EE87} = {E013786A-9575-4F34-81B2-33290357EE87} + {415BFD6E-64CF-422B-AF88-C07F040A7292} = {415BFD6E-64CF-422B-AF88-C07F040A7292} + {4C3AB78A-52CA-4276-A041-39776E52D8C8} = {4C3AB78A-52CA-4276-A041-39776E52D8C8} + {6B801390-5F95-4F07-81A7-97FBA046AACC} = {6B801390-5F95-4F07-81A7-97FBA046AACC} + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94} = {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94} + {F90BD995-FFA4-4B18-81E8-FA4322C939E8} = {F90BD995-FFA4-4B18-81E8-FA4322C939E8} + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23} = {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23} + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7} = {3648FB9A-C36F-43AB-AED0-1F1361E67FC7} + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0} = {D8ABD6A5-1B36-4D62-934E-B5C6801130B0} + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B} = {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B} + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA} = {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA} + {E90C7BC2-CF30-4A60-A8F2-0050D592E358} = {E90C7BC2-CF30-4A60-A8F2-0050D592E358} + {32CC75E2-EE85-45E6-8E3D-513F58464F43} = {32CC75E2-EE85-45E6-8E3D-513F58464F43} + {9A307EE5-CD77-47BC-BD87-62508C7E19D8} = {9A307EE5-CD77-47BC-BD87-62508C7E19D8} + {AB590CED-F71F-4A17-A89B-18583ECD633D} = {AB590CED-F71F-4A17-A89B-18583ECD633D} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GP_common", "..\gameengine\gameplayer\common\GP_common.vcproj", "{D8ABD6A5-1B36-4D62-934E-B5C6801130B0}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GP_ghost", "..\gameengine\gameplayer\ghost\GP_ghost.vcproj", "{3D310C60-6771-48E4-BCCA-D2718CDED898}" + ProjectSection(ProjectDependencies) = postProject + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F} = {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F} + {6E24BF09-9653-4166-A871-F65CC9E98A9B} = {6E24BF09-9653-4166-A871-F65CC9E98A9B} + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE} = {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE} + {9625642D-6F20-4FB6-A089-BE7441B223E3} = {9625642D-6F20-4FB6-A089-BE7441B223E3} + {E645CC32-4823-463E-82F0-46ADDE664018} = {E645CC32-4823-463E-82F0-46ADDE664018} + {51FB3D48-2467-4BFA-A321-D848252B437E} = {51FB3D48-2467-4BFA-A321-D848252B437E} + {31628053-825D-4C06-8A21-D13883489718} = {31628053-825D-4C06-8A21-D13883489718} + {EADC3C5A-6C51-4F03-8038-1553E7D7F740} = {EADC3C5A-6C51-4F03-8038-1553E7D7F740} + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D} = {DB6BE55D-B6D9-494D-856A-8764FF7BA91D} + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E} = {0A73055E-4DED-40CD-9F72-9093ED3EEC7E} + {09222F5E-1625-4FF3-A89A-384D16875EE5} = {09222F5E-1625-4FF3-A89A-384D16875EE5} + {E013786A-9575-4F34-81B2-33290357EE87} = {E013786A-9575-4F34-81B2-33290357EE87} + {415BFD6E-64CF-422B-AF88-C07F040A7292} = {415BFD6E-64CF-422B-AF88-C07F040A7292} + {4C3AB78A-52CA-4276-A041-39776E52D8C8} = {4C3AB78A-52CA-4276-A041-39776E52D8C8} + {6B801390-5F95-4F07-81A7-97FBA046AACC} = {6B801390-5F95-4F07-81A7-97FBA046AACC} + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94} = {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94} + {F90BD995-FFA4-4B18-81E8-FA4322C939E8} = {F90BD995-FFA4-4B18-81E8-FA4322C939E8} + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23} = {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23} + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7} = {3648FB9A-C36F-43AB-AED0-1F1361E67FC7} + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0} = {D8ABD6A5-1B36-4D62-934E-B5C6801130B0} + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B} = {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B} + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA} = {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA} + {E90C7BC2-CF30-4A60-A8F2-0050D592E358} = {E90C7BC2-CF30-4A60-A8F2-0050D592E358} + {32CC75E2-EE85-45E6-8E3D-513F58464F43} = {32CC75E2-EE85-45E6-8E3D-513F58464F43} + {9A307EE5-CD77-47BC-BD87-62508C7E19D8} = {9A307EE5-CD77-47BC-BD87-62508C7E19D8} + {AB590CED-F71F-4A17-A89B-18583ECD633D} = {AB590CED-F71F-4A17-A89B-18583ECD633D} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KX_blenderhook", "..\gameengine\blenderhook\KX_blenderhook.vcproj", "{8154A59A-CAED-403D-AB94-BC4E7C032666}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KX_converter", "..\gameengine\converter\KX_converter.vcproj", "{F90BD995-FFA4-4B18-81E8-FA4322C939E8}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KX_ketsji", "..\gameengine\ketsji\KX_ketsji.vcproj", "{E645CC32-4823-463E-82F0-46ADDE664018}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KX_network", "..\gameengine\ketsji\network\KX_network.vcproj", "{6E24BF09-9653-4166-A871-F65CC9E98A9B}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NG_loopbacknetwork", "..\gameengine\network\loopbacknetwork\NG_loopbacknetwork.vcproj", "{6B801390-5F95-4F07-81A7-97FBA046AACC}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NG_network", "..\gameengine\network\network\NG_network.vcproj", "{0A73055E-4DED-40CD-9F72-9093ED3EEC7E}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PHY_Dummy", "..\GAMEENGINE\PHYSICS\PHY_PHYSICS\PHY_Dummy\PHY_Dummy.vcproj", "{3648FB9A-C36F-43AB-AED0-1F1361E67FC7}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PHY_Ode", "..\gameengine\physics\PHY_Physics\PHY_Ode\PHY_Ode.vcproj", "{EC405272-28E3-4840-AAC2-53D6DE4E163D}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PHY_Physics", "..\gameengine\physics\PHY_Physics\PHY_Physics.vcproj", "{E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RAS_openglrasterizer", "..\gameengine\rasterizer\openglrasterizer\RAS_openglrasterizer.vcproj", "{AB590CED-F71F-4A17-A89B-18583ECD633D}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RAS_rasterizer", "..\gameengine\rasterizer\RAS_rasterizer.vcproj", "{51FB3D48-2467-4BFA-A321-D848252B437E}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SCA_GameLogic", "..\gameengine\gamelogic\SCA_GameLogic.vcproj", "{32CC75E2-EE85-45E6-8E3D-513F58464F43}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SG_SceneGraph", "..\gameengine\scenegraph\SG_SceneGraph.vcproj", "{09222F5E-1625-4FF3-A89A-384D16875EE5}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SYS_system", "..\kernel\system\SYS_system.vcproj", "{BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blenpluginapi", "blenpluginapi\blenpluginapi\blenpluginapi.vcproj", "{BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gen_messaging", "..\KERNEL\gen_messaging\gen_messaging.vcproj", "{727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PHY_Sumo", "..\gameengine\physics\PHY_Physics\PHY_Sumo\PHY_Sumo.vcproj", "{9625642D-6F20-4FB6-A089-BE7441B223E3}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BRE_yafray", "yafray\BRE_yafray.vcproj", "{9991A3C3-83FE-4AFE-9E18-9D01CB57E879}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PHY_Bullet", "..\gameengine\physics\PHY_Physics\PHY_Bullet\PHY_Bullet.vcproj", "{E90C7BC2-CF30-4A60-A8F2-0050D592E358}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BL_nodes", "nodes\nodes.vcproj", "{4C3AB78A-52CA-4276-A041-39776E52D8C8}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + 3D Plugin Debug = 3D Plugin Debug + 3D Plugin Release = 3D Plugin Release + Blender Debug = Blender Debug + Blender Release = Blender Release + BlenderPlayer Debug = BlenderPlayer Debug + BlenderPlayer Release = BlenderPlayer Release + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}.3D Plugin Debug.ActiveCfg = Blender Debug|Win32 + {F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}.3D Plugin Release.ActiveCfg = Blender Release|Win32 + {F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}.Blender Debug.Build.0 = Blender Debug|Win32 + {F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}.Blender Release.ActiveCfg = Blender Release|Win32 + {F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}.Blender Release.Build.0 = Blender Release|Win32 + {F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}.BlenderPlayer Debug.ActiveCfg = Blender Debug|Win32 + {F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}.Debug.ActiveCfg = Blender Debug|Win32 + {F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}.Debug.Build.0 = Blender Debug|Win32 + {F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}.Release.ActiveCfg = Blender Release|Win32 + {F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}.Release.Build.0 = Blender Release|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.Blender Debug.Build.0 = Blender Debug|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.Blender Release.ActiveCfg = Blender Release|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.Blender Release.Build.0 = Blender Release|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.Release.Build.0 = BlenderPlayer Release|Win32 + {31628053-825D-4C06-8A21-D13883489718}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {31628053-825D-4C06-8A21-D13883489718}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {31628053-825D-4C06-8A21-D13883489718}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {31628053-825D-4C06-8A21-D13883489718}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {31628053-825D-4C06-8A21-D13883489718}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {31628053-825D-4C06-8A21-D13883489718}.Blender Debug.Build.0 = Blender Debug|Win32 + {31628053-825D-4C06-8A21-D13883489718}.Blender Release.ActiveCfg = Blender Release|Win32 + {31628053-825D-4C06-8A21-D13883489718}.Blender Release.Build.0 = Blender Release|Win32 + {31628053-825D-4C06-8A21-D13883489718}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {31628053-825D-4C06-8A21-D13883489718}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {31628053-825D-4C06-8A21-D13883489718}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {31628053-825D-4C06-8A21-D13883489718}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {31628053-825D-4C06-8A21-D13883489718}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {31628053-825D-4C06-8A21-D13883489718}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {31628053-825D-4C06-8A21-D13883489718}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {31628053-825D-4C06-8A21-D13883489718}.Release.Build.0 = BlenderPlayer Release|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.Blender Debug.Build.0 = Blender Debug|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.Blender Release.ActiveCfg = Blender Release|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.Blender Release.Build.0 = Blender Release|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.Release.Build.0 = BlenderPlayer Release|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.Blender Debug.Build.0 = Blender Debug|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.Blender Release.ActiveCfg = Blender Release|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.Blender Release.Build.0 = Blender Release|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.Release.Build.0 = BlenderPlayer Release|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.Blender Debug.Build.0 = Blender Debug|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.Blender Release.ActiveCfg = Blender Release|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.Blender Release.Build.0 = Blender Release|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.Release.Build.0 = BlenderPlayer Release|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.Blender Debug.Build.0 = Blender Debug|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.Blender Release.ActiveCfg = Blender Release|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.Blender Release.Build.0 = Blender Release|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.Release.Build.0 = BlenderPlayer Release|Win32 + {FB88301F-F725-401B-ACD7-D2ABBF333B71}.3D Plugin Debug.ActiveCfg = Blender Debug|Win32 + {FB88301F-F725-401B-ACD7-D2ABBF333B71}.3D Plugin Release.ActiveCfg = Blender Release|Win32 + {FB88301F-F725-401B-ACD7-D2ABBF333B71}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {FB88301F-F725-401B-ACD7-D2ABBF333B71}.Blender Debug.Build.0 = Blender Debug|Win32 + {FB88301F-F725-401B-ACD7-D2ABBF333B71}.Blender Release.ActiveCfg = Blender Release|Win32 + {FB88301F-F725-401B-ACD7-D2ABBF333B71}.Blender Release.Build.0 = Blender Release|Win32 + {FB88301F-F725-401B-ACD7-D2ABBF333B71}.BlenderPlayer Debug.ActiveCfg = Blender Debug|Win32 + {FB88301F-F725-401B-ACD7-D2ABBF333B71}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {FB88301F-F725-401B-ACD7-D2ABBF333B71}.Debug.ActiveCfg = Blender Debug|Win32 + {FB88301F-F725-401B-ACD7-D2ABBF333B71}.Debug.Build.0 = Blender Debug|Win32 + {FB88301F-F725-401B-ACD7-D2ABBF333B71}.Release.ActiveCfg = Blender Release|Win32 + {FB88301F-F725-401B-ACD7-D2ABBF333B71}.Release.Build.0 = Blender Release|Win32 + {64019BFA-8C14-4FA6-B275-D7598D821FF6}.3D Plugin Debug.ActiveCfg = Blender Debug|Win32 + {64019BFA-8C14-4FA6-B275-D7598D821FF6}.3D Plugin Release.ActiveCfg = Blender Release|Win32 + {64019BFA-8C14-4FA6-B275-D7598D821FF6}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {64019BFA-8C14-4FA6-B275-D7598D821FF6}.Blender Debug.Build.0 = Blender Debug|Win32 + {64019BFA-8C14-4FA6-B275-D7598D821FF6}.Blender Release.ActiveCfg = Blender Release|Win32 + {64019BFA-8C14-4FA6-B275-D7598D821FF6}.Blender Release.Build.0 = Blender Release|Win32 + {64019BFA-8C14-4FA6-B275-D7598D821FF6}.BlenderPlayer Debug.ActiveCfg = Blender Debug|Win32 + {64019BFA-8C14-4FA6-B275-D7598D821FF6}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {64019BFA-8C14-4FA6-B275-D7598D821FF6}.Debug.ActiveCfg = Blender Debug|Win32 + {64019BFA-8C14-4FA6-B275-D7598D821FF6}.Debug.Build.0 = Blender Debug|Win32 + {64019BFA-8C14-4FA6-B275-D7598D821FF6}.Release.ActiveCfg = Blender Release|Win32 + {64019BFA-8C14-4FA6-B275-D7598D821FF6}.Release.Build.0 = Blender Release|Win32 + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}.3D Plugin Debug.ActiveCfg = Blender Debug|Win32 + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}.3D Plugin Release.ActiveCfg = Blender Release|Win32 + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}.Blender Debug.Build.0 = Blender Debug|Win32 + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}.Blender Release.ActiveCfg = Blender Release|Win32 + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}.Blender Release.Build.0 = Blender Release|Win32 + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}.BlenderPlayer Debug.ActiveCfg = Blender Debug|Win32 + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}.Debug.ActiveCfg = Blender Debug|Win32 + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}.Debug.Build.0 = Blender Debug|Win32 + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}.Release.ActiveCfg = Blender Release|Win32 + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}.Release.Build.0 = Blender Release|Win32 + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}.3D Plugin Debug.ActiveCfg = Blender Debug|Win32 + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}.3D Plugin Release.ActiveCfg = Blender Release|Win32 + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}.Blender Debug.Build.0 = Blender Debug|Win32 + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}.Blender Release.ActiveCfg = Blender Release|Win32 + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}.Blender Release.Build.0 = Blender Release|Win32 + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}.BlenderPlayer Debug.ActiveCfg = Blender Debug|Win32 + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}.Debug.ActiveCfg = Blender Debug|Win32 + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}.Debug.Build.0 = Blender Debug|Win32 + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}.Release.ActiveCfg = Blender Release|Win32 + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}.Release.Build.0 = Blender Release|Win32 + {106AE171-0083-41D6-A949-20DB0E8DC251}.3D Plugin Debug.ActiveCfg = Blender Debug|Win32 + {106AE171-0083-41D6-A949-20DB0E8DC251}.3D Plugin Release.ActiveCfg = Blender Release|Win32 + {106AE171-0083-41D6-A949-20DB0E8DC251}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {106AE171-0083-41D6-A949-20DB0E8DC251}.Blender Debug.Build.0 = Blender Debug|Win32 + {106AE171-0083-41D6-A949-20DB0E8DC251}.Blender Release.ActiveCfg = Blender Release|Win32 + {106AE171-0083-41D6-A949-20DB0E8DC251}.Blender Release.Build.0 = Blender Release|Win32 + {106AE171-0083-41D6-A949-20DB0E8DC251}.BlenderPlayer Debug.ActiveCfg = Blender Debug|Win32 + {106AE171-0083-41D6-A949-20DB0E8DC251}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {106AE171-0083-41D6-A949-20DB0E8DC251}.Debug.ActiveCfg = Blender Debug|Win32 + {106AE171-0083-41D6-A949-20DB0E8DC251}.Debug.Build.0 = Blender Debug|Win32 + {106AE171-0083-41D6-A949-20DB0E8DC251}.Release.ActiveCfg = Blender Release|Win32 + {106AE171-0083-41D6-A949-20DB0E8DC251}.Release.Build.0 = Blender Release|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.Blender Debug.Build.0 = Blender Debug|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.Blender Release.ActiveCfg = Blender Release|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.Blender Release.Build.0 = Blender Release|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.Release.Build.0 = BlenderPlayer Release|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.Blender Debug.Build.0 = Blender Debug|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.Blender Release.ActiveCfg = Blender Release|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.Blender Release.Build.0 = Blender Release|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.Release.Build.0 = BlenderPlayer Release|Win32 + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}.3D Plugin Debug.ActiveCfg = Blender Debug|Win32 + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}.3D Plugin Release.ActiveCfg = Blender Release|Win32 + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}.Blender Debug.Build.0 = Blender Debug|Win32 + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}.Blender Release.ActiveCfg = Blender Release|Win32 + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}.Blender Release.Build.0 = Blender Release|Win32 + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}.BlenderPlayer Debug.ActiveCfg = Blender Debug|Win32 + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}.Debug.ActiveCfg = Blender Debug|Win32 + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}.Debug.Build.0 = Blender Debug|Win32 + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}.Release.ActiveCfg = Blender Release|Win32 + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}.Release.Build.0 = Blender Release|Win32 + {DF25E6F2-780C-438B-8AAD-D10CF8B3820A}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {DF25E6F2-780C-438B-8AAD-D10CF8B3820A}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {DF25E6F2-780C-438B-8AAD-D10CF8B3820A}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {DF25E6F2-780C-438B-8AAD-D10CF8B3820A}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {DF25E6F2-780C-438B-8AAD-D10CF8B3820A}.Blender Debug.ActiveCfg = 3D Plugin Debug|Win32 + {DF25E6F2-780C-438B-8AAD-D10CF8B3820A}.Blender Release.ActiveCfg = 3D Plugin Release|Win32 + {DF25E6F2-780C-438B-8AAD-D10CF8B3820A}.BlenderPlayer Debug.ActiveCfg = 3D Plugin Debug|Win32 + {DF25E6F2-780C-438B-8AAD-D10CF8B3820A}.BlenderPlayer Release.ActiveCfg = 3D Plugin Release|Win32 + {DF25E6F2-780C-438B-8AAD-D10CF8B3820A}.Debug.ActiveCfg = 3D Plugin Debug|Win32 + {DF25E6F2-780C-438B-8AAD-D10CF8B3820A}.Debug.Build.0 = 3D Plugin Debug|Win32 + {DF25E6F2-780C-438B-8AAD-D10CF8B3820A}.Release.ActiveCfg = 3D Plugin Release|Win32 + {DF25E6F2-780C-438B-8AAD-D10CF8B3820A}.Release.Build.0 = 3D Plugin Release|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.Blender Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.Blender Release.ActiveCfg = BlenderPlayer Release|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.Release.Build.0 = BlenderPlayer Release|Win32 + {3D310C60-6771-48E4-BCCA-D2718CDED898}.3D Plugin Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {3D310C60-6771-48E4-BCCA-D2718CDED898}.3D Plugin Release.ActiveCfg = BlenderPlayer Release|Win32 + {3D310C60-6771-48E4-BCCA-D2718CDED898}.Blender Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {3D310C60-6771-48E4-BCCA-D2718CDED898}.Blender Release.ActiveCfg = BlenderPlayer Release|Win32 + {3D310C60-6771-48E4-BCCA-D2718CDED898}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {3D310C60-6771-48E4-BCCA-D2718CDED898}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {3D310C60-6771-48E4-BCCA-D2718CDED898}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {3D310C60-6771-48E4-BCCA-D2718CDED898}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {3D310C60-6771-48E4-BCCA-D2718CDED898}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {3D310C60-6771-48E4-BCCA-D2718CDED898}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {3D310C60-6771-48E4-BCCA-D2718CDED898}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {3D310C60-6771-48E4-BCCA-D2718CDED898}.Release.Build.0 = BlenderPlayer Release|Win32 + {8154A59A-CAED-403D-AB94-BC4E7C032666}.3D Plugin Debug.ActiveCfg = Blender Debug|Win32 + {8154A59A-CAED-403D-AB94-BC4E7C032666}.3D Plugin Release.ActiveCfg = Blender Release|Win32 + {8154A59A-CAED-403D-AB94-BC4E7C032666}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {8154A59A-CAED-403D-AB94-BC4E7C032666}.Blender Debug.Build.0 = Blender Debug|Win32 + {8154A59A-CAED-403D-AB94-BC4E7C032666}.Blender Release.ActiveCfg = Blender Release|Win32 + {8154A59A-CAED-403D-AB94-BC4E7C032666}.Blender Release.Build.0 = Blender Release|Win32 + {8154A59A-CAED-403D-AB94-BC4E7C032666}.BlenderPlayer Debug.ActiveCfg = Blender Debug|Win32 + {8154A59A-CAED-403D-AB94-BC4E7C032666}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {8154A59A-CAED-403D-AB94-BC4E7C032666}.Debug.ActiveCfg = Blender Debug|Win32 + {8154A59A-CAED-403D-AB94-BC4E7C032666}.Debug.Build.0 = Blender Debug|Win32 + {8154A59A-CAED-403D-AB94-BC4E7C032666}.Release.ActiveCfg = Blender Release|Win32 + {8154A59A-CAED-403D-AB94-BC4E7C032666}.Release.Build.0 = Blender Release|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.Blender Debug.Build.0 = Blender Debug|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.Blender Release.ActiveCfg = Blender Release|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.Blender Release.Build.0 = Blender Release|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.Release.Build.0 = BlenderPlayer Release|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.Blender Debug.Build.0 = Blender Debug|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.Blender Release.ActiveCfg = Blender Release|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.Blender Release.Build.0 = Blender Release|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.Release.Build.0 = BlenderPlayer Release|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.Blender Debug.Build.0 = Blender Debug|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.Blender Release.ActiveCfg = Blender Release|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.Blender Release.Build.0 = Blender Release|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.Release.Build.0 = BlenderPlayer Release|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.Blender Debug.Build.0 = Blender Debug|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.Blender Release.ActiveCfg = Blender Release|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.Blender Release.Build.0 = Blender Release|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.Release.Build.0 = BlenderPlayer Release|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.Blender Debug.Build.0 = Blender Debug|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.Blender Release.ActiveCfg = Blender Release|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.Blender Release.Build.0 = Blender Release|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.Release.Build.0 = BlenderPlayer Release|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.Blender Debug.Build.0 = Blender Debug|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.Blender Release.ActiveCfg = Blender Release|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.Blender Release.Build.0 = Blender Release|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.Release.Build.0 = BlenderPlayer Release|Win32 + {EC405272-28E3-4840-AAC2-53D6DE4E163D}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {EC405272-28E3-4840-AAC2-53D6DE4E163D}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {EC405272-28E3-4840-AAC2-53D6DE4E163D}.Blender Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {EC405272-28E3-4840-AAC2-53D6DE4E163D}.Blender Release.ActiveCfg = BlenderPlayer Release|Win32 + {EC405272-28E3-4840-AAC2-53D6DE4E163D}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {EC405272-28E3-4840-AAC2-53D6DE4E163D}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {EC405272-28E3-4840-AAC2-53D6DE4E163D}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {EC405272-28E3-4840-AAC2-53D6DE4E163D}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {EC405272-28E3-4840-AAC2-53D6DE4E163D}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {EC405272-28E3-4840-AAC2-53D6DE4E163D}.Release.Build.0 = BlenderPlayer Release|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.Blender Debug.Build.0 = Blender Debug|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.Blender Release.ActiveCfg = Blender Release|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.Blender Release.Build.0 = Blender Release|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.Release.Build.0 = BlenderPlayer Release|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.Blender Debug.Build.0 = Blender Debug|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.Blender Release.ActiveCfg = Blender Release|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.Blender Release.Build.0 = Blender Release|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.Release.Build.0 = BlenderPlayer Release|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.Blender Debug.Build.0 = Blender Debug|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.Blender Release.ActiveCfg = Blender Release|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.Blender Release.Build.0 = Blender Release|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.Release.Build.0 = BlenderPlayer Release|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.Blender Debug.Build.0 = Blender Debug|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.Blender Release.ActiveCfg = Blender Release|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.Blender Release.Build.0 = Blender Release|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.Release.Build.0 = BlenderPlayer Release|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.Blender Debug.Build.0 = Blender Debug|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.Blender Release.ActiveCfg = Blender Release|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.Blender Release.Build.0 = Blender Release|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.Release.Build.0 = BlenderPlayer Release|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.Blender Debug.Build.0 = Blender Debug|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.Blender Release.ActiveCfg = Blender Release|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.Blender Release.Build.0 = Blender Release|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.Release.Build.0 = BlenderPlayer Release|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.Blender Debug.Build.0 = Blender Debug|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.Blender Release.ActiveCfg = Blender Release|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.Blender Release.Build.0 = Blender Release|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.Debug.ActiveCfg = 3D Plugin Debug|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.Debug.Build.0 = 3D Plugin Debug|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.Release.Build.0 = BlenderPlayer Release|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.Blender Debug.Build.0 = Blender Debug|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.Blender Release.ActiveCfg = Blender Release|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.Blender Release.Build.0 = Blender Release|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.Release.Build.0 = BlenderPlayer Release|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.Blender Debug.Build.0 = Blender Debug|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.Blender Release.ActiveCfg = Blender Release|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.Blender Release.Build.0 = Blender Release|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.Debug.ActiveCfg = 3D Plugin Debug|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.Debug.Build.0 = 3D Plugin Debug|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.Release.Build.0 = BlenderPlayer Release|Win32 + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879}.3D Plugin Debug.ActiveCfg = Blender Debug|Win32 + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879}.3D Plugin Release.ActiveCfg = Blender Release|Win32 + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879}.Blender Debug.Build.0 = Blender Debug|Win32 + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879}.Blender Release.ActiveCfg = Blender Release|Win32 + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879}.Blender Release.Build.0 = Blender Release|Win32 + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879}.BlenderPlayer Debug.ActiveCfg = Blender Debug|Win32 + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879}.Debug.ActiveCfg = Blender Debug|Win32 + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879}.Debug.Build.0 = Blender Debug|Win32 + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879}.Release.ActiveCfg = Blender Release|Win32 + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879}.Release.Build.0 = Blender Release|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.Blender Debug.Build.0 = Blender Debug|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.Blender Release.ActiveCfg = Blender Release|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.Blender Release.Build.0 = Blender Release|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.BlenderPlayer Debug.ActiveCfg = Blender Debug|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.BlenderPlayer Debug.Build.0 = Blender Debug|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.Debug.ActiveCfg = 3D Plugin Debug|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.Debug.Build.0 = 3D Plugin Debug|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.Release.ActiveCfg = 3D Plugin Release|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.Release.Build.0 = 3D Plugin Release|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.3D Plugin Debug.ActiveCfg = Blender Release|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.3D Plugin Debug.Build.0 = Blender Release|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.3D Plugin Release.ActiveCfg = Blender Release|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.3D Plugin Release.Build.0 = Blender Release|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.Blender Debug.Build.0 = Blender Debug|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.Blender Release.ActiveCfg = Blender Release|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.Blender Release.Build.0 = Blender Release|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.BlenderPlayer Release.Build.0 = Blender Release|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.Debug.ActiveCfg = Blender Debug|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.Debug.Build.0 = Blender Debug|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.Release.ActiveCfg = Blender Release|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.Release.Build.0 = Blender Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/projectfiles_vc7/blender/blender.vcproj b/projectfiles_vc7/blender/blender.vcproj new file mode 100644 index 00000000000..9761d94d746 --- /dev/null +++ b/projectfiles_vc7/blender/blender.vcproj @@ -0,0 +1,227 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/blendercompact.sln b/projectfiles_vc7/blender/blendercompact.sln new file mode 100644 index 00000000000..f933457804c --- /dev/null +++ b/projectfiles_vc7/blender/blendercompact.sln @@ -0,0 +1,28 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "makesdnacompact", "makesdnacompact.vcproj", "{14705769-A148-4DCC-B2C5-AFE8C20824E4}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blendercompactNG", "blendercompactNG.vcproj", "{CB70E20D-75A2-497B-AD6E-60F3989F0622}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + {CB70E20D-75A2-497B-AD6E-60F3989F0622}.0 = {14705769-A148-4DCC-B2C5-AFE8C20824E4} + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {14705769-A148-4DCC-B2C5-AFE8C20824E4}.Debug.ActiveCfg = Debug|Win32 + {14705769-A148-4DCC-B2C5-AFE8C20824E4}.Debug.Build.0 = Debug|Win32 + {14705769-A148-4DCC-B2C5-AFE8C20824E4}.Release.ActiveCfg = Release|Win32 + {14705769-A148-4DCC-B2C5-AFE8C20824E4}.Release.Build.0 = Release|Win32 + {CB70E20D-75A2-497B-AD6E-60F3989F0622}.Debug.ActiveCfg = Debug|Win32 + {CB70E20D-75A2-497B-AD6E-60F3989F0622}.Debug.Build.0 = Debug|Win32 + {CB70E20D-75A2-497B-AD6E-60F3989F0622}.Release.ActiveCfg = Release|Win32 + {CB70E20D-75A2-497B-AD6E-60F3989F0622}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/projectfiles_vc7/blender/blendercompactNG.vcproj b/projectfiles_vc7/blender/blendercompactNG.vcproj new file mode 100644 index 00000000000..4eff6662659 --- /dev/null +++ b/projectfiles_vc7/blender/blendercompactNG.vcproj @@ -0,0 +1,3561 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/blenkernel/BKE_blenkernel.vcproj b/projectfiles_vc7/blender/blenkernel/BKE_blenkernel.vcproj new file mode 100644 index 00000000000..4e58c6617aa --- /dev/null +++ b/projectfiles_vc7/blender/blenkernel/BKE_blenkernel.vcproj @@ -0,0 +1,685 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/blenlib/BLI_blenlib.vcproj b/projectfiles_vc7/blender/blenlib/BLI_blenlib.vcproj new file mode 100644 index 00000000000..f7038e610f1 --- /dev/null +++ b/projectfiles_vc7/blender/blenlib/BLI_blenlib.vcproj @@ -0,0 +1,486 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/blenpluginapi/blenpluginapi/blenpluginapi.vcproj b/projectfiles_vc7/blender/blenpluginapi/blenpluginapi/blenpluginapi.vcproj new file mode 100644 index 00000000000..8a88ed9db50 --- /dev/null +++ b/projectfiles_vc7/blender/blenpluginapi/blenpluginapi/blenpluginapi.vcproj @@ -0,0 +1,361 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/ftfont/FTF_ftfont.vcproj b/projectfiles_vc7/blender/ftfont/FTF_ftfont.vcproj new file mode 100644 index 00000000000..ef756c7b67f --- /dev/null +++ b/projectfiles_vc7/blender/ftfont/FTF_ftfont.vcproj @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/imbuf/BL_imbuf.vcproj b/projectfiles_vc7/blender/imbuf/BL_imbuf.vcproj new file mode 100644 index 00000000000..b7518c0bc82 --- /dev/null +++ b/projectfiles_vc7/blender/imbuf/BL_imbuf.vcproj @@ -0,0 +1,648 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/img/BL_img.vcproj b/projectfiles_vc7/blender/img/BL_img.vcproj new file mode 100644 index 00000000000..cf94dbeed4f --- /dev/null +++ b/projectfiles_vc7/blender/img/BL_img.vcproj @@ -0,0 +1,287 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/loader/BLO_loader.vcproj b/projectfiles_vc7/blender/loader/BLO_loader.vcproj new file mode 100644 index 00000000000..49b0af17c01 --- /dev/null +++ b/projectfiles_vc7/blender/loader/BLO_loader.vcproj @@ -0,0 +1,475 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/makesdna/DNA_makesdna.vcproj b/projectfiles_vc7/blender/makesdna/DNA_makesdna.vcproj new file mode 100644 index 00000000000..f8d88f8640e --- /dev/null +++ b/projectfiles_vc7/blender/makesdna/DNA_makesdna.vcproj @@ -0,0 +1,596 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/makesdnacompact.vcproj b/projectfiles_vc7/blender/makesdnacompact.vcproj new file mode 100644 index 00000000000..5ea0280e008 --- /dev/null +++ b/projectfiles_vc7/blender/makesdnacompact.vcproj @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/nodes/nodes.vcproj b/projectfiles_vc7/blender/nodes/nodes.vcproj new file mode 100644 index 00000000000..04403630664 --- /dev/null +++ b/projectfiles_vc7/blender/nodes/nodes.vcproj @@ -0,0 +1,449 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/radiosity/BRA_radiosity.vcproj b/projectfiles_vc7/blender/radiosity/BRA_radiosity.vcproj new file mode 100644 index 00000000000..8ef408c5a5d --- /dev/null +++ b/projectfiles_vc7/blender/radiosity/BRA_radiosity.vcproj @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/render/BRE_render.vcproj b/projectfiles_vc7/blender/render/BRE_render.vcproj new file mode 100644 index 00000000000..2383f41b69b --- /dev/null +++ b/projectfiles_vc7/blender/render/BRE_render.vcproj @@ -0,0 +1,252 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/renderconverter/BRE_renderconverter.vcproj b/projectfiles_vc7/blender/renderconverter/BRE_renderconverter.vcproj new file mode 100644 index 00000000000..ef830fe5905 --- /dev/null +++ b/projectfiles_vc7/blender/renderconverter/BRE_renderconverter.vcproj @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/src/BL_src.vcproj b/projectfiles_vc7/blender/src/BL_src.vcproj new file mode 100644 index 00000000000..685615e4b6d --- /dev/null +++ b/projectfiles_vc7/blender/src/BL_src.vcproj @@ -0,0 +1,894 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/src/BL_src_cre.vcproj b/projectfiles_vc7/blender/src/BL_src_cre.vcproj new file mode 100644 index 00000000000..70de861c91c --- /dev/null +++ b/projectfiles_vc7/blender/src/BL_src_cre.vcproj @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/yafray/BRE_yafray.vcproj b/projectfiles_vc7/blender/yafray/BRE_yafray.vcproj new file mode 100644 index 00000000000..b51aaaab947 --- /dev/null +++ b/projectfiles_vc7/blender/yafray/BRE_yafray.vcproj @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/blenderhook/KX_blenderhook.vcproj b/projectfiles_vc7/gameengine/blenderhook/KX_blenderhook.vcproj new file mode 100644 index 00000000000..1721062b75c --- /dev/null +++ b/projectfiles_vc7/gameengine/blenderhook/KX_blenderhook.vcproj @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/converter/KX_converter.vcproj b/projectfiles_vc7/gameengine/converter/KX_converter.vcproj new file mode 100644 index 00000000000..36a49364dfc --- /dev/null +++ b/projectfiles_vc7/gameengine/converter/KX_converter.vcproj @@ -0,0 +1,433 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/expression/EXP_expressions.vcproj b/projectfiles_vc7/gameengine/expression/EXP_expressions.vcproj new file mode 100644 index 00000000000..e8516326a62 --- /dev/null +++ b/projectfiles_vc7/gameengine/expression/EXP_expressions.vcproj @@ -0,0 +1,457 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/gamelogic/SCA_GameLogic.vcproj b/projectfiles_vc7/gameengine/gamelogic/SCA_GameLogic.vcproj new file mode 100644 index 00000000000..4336f0dd7cd --- /dev/null +++ b/projectfiles_vc7/gameengine/gamelogic/SCA_GameLogic.vcproj @@ -0,0 +1,529 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/gameplayer/axctl/GP_axctl.vcproj b/projectfiles_vc7/gameengine/gameplayer/axctl/GP_axctl.vcproj new file mode 100644 index 00000000000..07189cf1f7f --- /dev/null +++ b/projectfiles_vc7/gameengine/gameplayer/axctl/GP_axctl.vcproj @@ -0,0 +1,324 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/gameplayer/common/GP_common.vcproj b/projectfiles_vc7/gameengine/gameplayer/common/GP_common.vcproj new file mode 100644 index 00000000000..cba8b1558c9 --- /dev/null +++ b/projectfiles_vc7/gameengine/gameplayer/common/GP_common.vcproj @@ -0,0 +1,315 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/gameplayer/ghost/GP_ghost.vcproj b/projectfiles_vc7/gameengine/gameplayer/ghost/GP_ghost.vcproj new file mode 100644 index 00000000000..ffa4c00f098 --- /dev/null +++ b/projectfiles_vc7/gameengine/gameplayer/ghost/GP_ghost.vcproj @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/ketsji/KX_ketsji.vcproj b/projectfiles_vc7/gameengine/ketsji/KX_ketsji.vcproj new file mode 100644 index 00000000000..a18b944a189 --- /dev/null +++ b/projectfiles_vc7/gameengine/ketsji/KX_ketsji.vcproj @@ -0,0 +1,760 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/ketsji/network/KX_network.vcproj b/projectfiles_vc7/gameengine/ketsji/network/KX_network.vcproj new file mode 100644 index 00000000000..a59c7fa145a --- /dev/null +++ b/projectfiles_vc7/gameengine/ketsji/network/KX_network.vcproj @@ -0,0 +1,370 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/network/loopbacknetwork/NG_loopbacknetwork.vcproj b/projectfiles_vc7/gameengine/network/loopbacknetwork/NG_loopbacknetwork.vcproj new file mode 100644 index 00000000000..400154a8533 --- /dev/null +++ b/projectfiles_vc7/gameengine/network/loopbacknetwork/NG_loopbacknetwork.vcproj @@ -0,0 +1,346 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/network/network/NG_network.vcproj b/projectfiles_vc7/gameengine/network/network/NG_network.vcproj new file mode 100644 index 00000000000..60dc5655fb6 --- /dev/null +++ b/projectfiles_vc7/gameengine/network/network/NG_network.vcproj @@ -0,0 +1,361 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Bullet/PHY_Bullet.vcproj b/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Bullet/PHY_Bullet.vcproj new file mode 100644 index 00000000000..9a807f2d39a --- /dev/null +++ b/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Bullet/PHY_Bullet.vcproj @@ -0,0 +1,317 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Dummy/PHY_Dummy.vcproj b/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Dummy/PHY_Dummy.vcproj new file mode 100644 index 00000000000..b1200e635d2 --- /dev/null +++ b/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Dummy/PHY_Dummy.vcproj @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Ode/PHY_Ode.vcproj b/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Ode/PHY_Ode.vcproj new file mode 100644 index 00000000000..a940d3a7f9b --- /dev/null +++ b/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Ode/PHY_Ode.vcproj @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Physics.vcproj b/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Physics.vcproj new file mode 100644 index 00000000000..c46ba8f36de --- /dev/null +++ b/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Physics.vcproj @@ -0,0 +1,367 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Sumo/PHY_Sumo.vcproj b/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Sumo/PHY_Sumo.vcproj new file mode 100644 index 00000000000..a8d6e77cd58 --- /dev/null +++ b/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Sumo/PHY_Sumo.vcproj @@ -0,0 +1,380 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/rasterizer/RAS_rasterizer.vcproj b/projectfiles_vc7/gameengine/rasterizer/RAS_rasterizer.vcproj new file mode 100644 index 00000000000..129084f7b1b --- /dev/null +++ b/projectfiles_vc7/gameengine/rasterizer/RAS_rasterizer.vcproj @@ -0,0 +1,412 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/rasterizer/openglrasterizer/RAS_openglrasterizer.vcproj b/projectfiles_vc7/gameengine/rasterizer/openglrasterizer/RAS_openglrasterizer.vcproj new file mode 100644 index 00000000000..40bd1369aae --- /dev/null +++ b/projectfiles_vc7/gameengine/rasterizer/openglrasterizer/RAS_openglrasterizer.vcproj @@ -0,0 +1,373 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/scenegraph/SG_SceneGraph.vcproj b/projectfiles_vc7/gameengine/scenegraph/SG_SceneGraph.vcproj new file mode 100644 index 00000000000..02bb647eb92 --- /dev/null +++ b/projectfiles_vc7/gameengine/scenegraph/SG_SceneGraph.vcproj @@ -0,0 +1,379 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/kernel/gen_messaging/gen_messaging.vcproj b/projectfiles_vc7/kernel/gen_messaging/gen_messaging.vcproj new file mode 100644 index 00000000000..e947f52bd6b --- /dev/null +++ b/projectfiles_vc7/kernel/gen_messaging/gen_messaging.vcproj @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/kernel/system/SYS_system.vcproj b/projectfiles_vc7/kernel/system/SYS_system.vcproj new file mode 100644 index 00000000000..50ffc1fbb99 --- /dev/null +++ b/projectfiles_vc7/kernel/system/SYS_system.vcproj @@ -0,0 +1,367 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/sumo/fuzzics/SM_fuzzics.vcproj b/projectfiles_vc7/sumo/fuzzics/SM_fuzzics.vcproj new file mode 100644 index 00000000000..1b454bd0316 --- /dev/null +++ b/projectfiles_vc7/sumo/fuzzics/SM_fuzzics.vcproj @@ -0,0 +1,376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/sumo/fuzzics/fuzzics.vcproj b/projectfiles_vc7/sumo/fuzzics/fuzzics.vcproj new file mode 100644 index 00000000000..6976e66a0bc --- /dev/null +++ b/projectfiles_vc7/sumo/fuzzics/fuzzics.vcproj @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/sumo/moto/SM_moto.dsp b/projectfiles_vc7/sumo/moto/SM_moto.dsp new file mode 100644 index 00000000000..3fd627ce60d --- /dev/null +++ b/projectfiles_vc7/sumo/moto/SM_moto.dsp @@ -0,0 +1,332 @@ +# Microsoft Developer Studio Project File - Name="SM_moto" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=SM_moto - Win32 Profile +!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 "SM_moto.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 "SM_moto.mak" CFG="SM_moto - Win32 Profile" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SM_moto - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_moto - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_moto - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_moto - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_moto - Win32 Profile" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SM_moto - 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 "..\..\..\..\obj\windows\sumo\moto" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\..\lib\windows\moto\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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:"..\..\..\..\obj\windows\sumo\moto\SM_moto.lib" + +!ELSEIF "$(CFG)" == "SM_moto - 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 "..\..\..\..\obj\windows\sumo\moto\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\..\source\sumo\MoTo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /FR /YX /J /FD /c +# 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:"..\..\..\..\obj\windows\sumo\moto\debug\SM_moto.lib" + +!ELSEIF "$(CFG)" == "SM_moto - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SM_moto___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "SM_moto___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\sumo\moto\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\sumo\moto\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\sumo\MoTo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\source\sumo\MoTo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /FR /YX /J /FD /GZ /c +# 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 /out:"..\..\..\..\..\obj\windows\sumo\moto\debug\SM_moto.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SM_moto - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "SM_moto___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "SM_moto___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\sumo\moto\mtdll" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\sumo\moto\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\sumo\MoTo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\source\sumo\MoTo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 /out:"..\..\..\..\..\obj\windows\sumo\moto\SM_moto.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SM_moto - Win32 Profile" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SM_moto___Win32_Profile" +# PROP BASE Intermediate_Dir "SM_moto___Win32_Profile" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "SM_moto___Win32_Profile" +# PROP Intermediate_Dir "SM_moto___Win32_Profile" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /O2 /I "..\..\..\source\sumo\MoTo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /O2 /I "..\..\..\source\sumo\MoTo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 /out:"..\..\..\..\obj\windows\sumo\moto\debug\SM_moto.lib" +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\sumo\moto\profile\SM_moto.lib" + +!ENDIF + +# Begin Target + +# Name "SM_moto - Win32 Release" +# Name "SM_moto - Win32 Debug" +# Name "SM_moto - Win32 MT DLL Debug" +# Name "SM_moto - Win32 MT DLL Release" +# Name "SM_moto - Win32 Profile" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_CmMatrix4x4.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Matrix3x3.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Matrix4x4.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Point3.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Quaternion.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_random.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Transform.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Vector2.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Vector3.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Vector4.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\GEN_List.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\GEN_Map.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_assert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_CmMatrix4x4.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Matrix3x3.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Matrix3x3.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Matrix4x4.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Matrix4x4.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_MinMax.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Optimize.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Point2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Point2.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Point3.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Point3.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Quaternion.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Quaternion.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_random.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Scalar.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Stream.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Transform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Tuple2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Tuple3.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Tuple4.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Vector2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Vector2.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Vector3.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Vector3.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Vector4.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Vector4.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\NM_Scalar.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles_vc7/sumo/solid/SM_solid.dsp b/projectfiles_vc7/sumo/solid/SM_solid.dsp new file mode 100644 index 00000000000..dfaa85c35d8 --- /dev/null +++ b/projectfiles_vc7/sumo/solid/SM_solid.dsp @@ -0,0 +1,340 @@ +# Microsoft Developer Studio Project File - Name="SM_solid" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=SM_solid - Win32 Release +!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 "SM_solid.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 "SM_solid.mak" CFG="SM_solid - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SM_solid - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_solid - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_solid - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_solid - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SM_solid - 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 "..\..\..\obj\windows\sumo\solid" +# PROP Intermediate_Dir "..\..\..\obj\windows\sumo\solid" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\source\gameengine\physics\sumo\SOLID-3.0\include" /I "../../../../lib/windows/moto/include" /I "..\..\..\source\gameengine\physics\sumo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /J /FD /c +# SUBTRACT CPP /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 + +!ELSEIF "$(CFG)" == "SM_solid - 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 "..\..\..\obj\windows\sumo\solid\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\sumo\solid\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\source\gameengine\physics\sumo\SOLID-3.0\include" /I "../../../../lib/windows/moto/include" /I "..\..\..\source\gameengine\physics\sumo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# SUBTRACT CPP /Fr +# 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 + +!ELSEIF "$(CFG)" == "SM_solid - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SM_solid___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "SM_solid___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\sumo\solid\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\sumo\solid\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\sumo\SOLID-3.0\include" /I "../../../../../lib/windows/moto/include" /I "..\..\..\source\sumo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\source\gameengine\physics\sumo\SOLID-3.0\include" /I "../../../../lib/windows/moto/include" /I "..\..\..\source\gameengine\physics\sumo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# 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 /out:"..\..\..\..\..\obj\windows\sumo\solid\debug\SM_solid.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SM_solid - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "SM_solid___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "SM_solid___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\sumo\solid\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\sumo\solid\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\sumo\SOLID-3.0\include" /I "../../../../../lib/windows/moto/include" /I "..\..\..\source\sumo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\source\gameengine\physics\sumo\SOLID-3.0\include" /I "../../../../lib/windows/moto/include" /I "..\..\..\source\gameengine\physics\sumo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# 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 /out:"..\..\..\..\..\obj\windows\sumo\solid\SM_solid.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "SM_solid - Win32 Release" +# Name "SM_solid - Win32 Debug" +# Name "SM_solid - Win32 MT DLL Debug" +# Name "SM_solid - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\BBoxTree.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Box.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Complex.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Cone.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Convex.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Cylinder.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_BP_C-api.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_BP_Endpoint.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_BP_Proxy.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_BP_Scene.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_C-api.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_DoubleBase.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_Encounter.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_FloatBase.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_LineSegment.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_Object.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_RespTable.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_Scene.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Polyhedron.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Polytope.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Sphere.cpp" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\AlgoTable.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\BBoxTree.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Box.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Complex.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Cone.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Convex.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Cylinder.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_AABBox.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_BBox.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_BP_Endpoint.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_BP_Proxy.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_BP_Scene.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_DoubleBase.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_Encounter.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_FloatBase.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_LineSegment.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_Object.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_Response.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_RespTable.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_Scene.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_VertexBase.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_VertexBased.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\IndexArray.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Polyhedron.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Polytope.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Shape.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Sphere.h" +# End Source File +# End Group +# End Target +# End Project diff --git a/release/Makefile b/release/Makefile new file mode 100644 index 00000000000..c55e62be003 --- /dev/null +++ b/release/Makefile @@ -0,0 +1,206 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +include nan_definitions.mk + +export VERSION := $(shell cat VERSION) + +BLENDNAME=blender-$(VERSION)-$(CONFIG_GUESS)-py$(NAN_PYTHON_VERSION)$(TYPE) +export DISTDIR=$(NAN_OBJDIR)/$(BLENDNAME) +export CONFDIR=$(DISTDIR)/.blender + +ifeq ($(OS),beos) + TAR="zip" + TARFLAGS="-ry9" + EXT0="" + EXT1=".zip" + COMPRESS="" + EXT2="" + NOPLUGINS="true" +endif + +ifeq ($(OS),$(findstring $(OS), "freebsd irix linux openbsd solaris")) + TAR="tar" + TARFLAGS="cf" + EXT0="" + EXT1=".tar" + COMPRESS="bzip2" + COMPRESSFLAGS="-f" + EXT2=".bz2" +endif + +ifeq ($(OS),windows) + TAR="zip" + TARFLAGS="-r9" + EXT0=".exe" + EXT1=".zip" + NOPLUGINS="true" + NOSTRIP="true" +endif + +ifeq ($(OS),darwin) + TAR="tar" + TARFLAGS="cf" + EXT0=".app" + EXT1=".tar" + COMPRESS="bzip2" + COMPRESSFLAGS="-f" + EXT2=".bz2" +endif + +release: all + +all: + @$(MAKE) pkg TYPE="" +ifeq ($(WITH_BF_STATICOPENGL), true) + @$(MAKE) pkg TYPE="-static" +endif + +# OS independent targets below: + +dist: all + +package: version makedirs + +install: package + @#echo "****> Install text" + @cp text/blender.html $(DISTDIR) + @cp text/*.txt $(DISTDIR) + @cp text/*.pdf $(DISTDIR) + ifeq ($(FREEDESKTOP), true) + @#echo "****> Install freedesktop icons" + @mkdir $(DISTDIR)/icons + @mkdir $(DISTDIR)/icons/16x16 + @cp freedesktop/icons/16x16/blender.png $(DISTDIR)/icons/16x16 + @mkdir $(DISTDIR)/icons/22x22 + @cp freedesktop/icons/22x22/blender.png $(DISTDIR)/icons/22x22 + @mkdir $(DISTDIR)/icons/32x32 + @cp freedesktop/icons/32x32/blender.png $(DISTDIR)/icons/32x32 + @mkdir $(DISTDIR)/icons/scalable + @cp freedesktop/icons/scalable/blender.svg $(DISTDIR)/icons/scalable + endif + @echo "----> Make Config dir .blender" + @mkdir -p $(CONFDIR) + @# possible overruling .txt text documents + @[ ! -d $(CONFIG_GUESS)/text ] || \ + cp -f $(CONFIG_GUESS)/text/*.txt $(DISTDIR) +#on OS X the contents of the .blender dir is already inside the bundle + ifneq ($(OS), darwin) + @[ ! -d $(OCGDIR)/bin/.blender ] || \ + cp -r $(OCGDIR)/bin/.blender $(DISTDIR) + @rm -rf $(DISTDIR)/.svn $(DISTDIR)/*/.svn $(DISTDIR)/*/*/.svn + @cp $(NANBLENDERHOME)/bin/.blender/.Blanguages $(CONFDIR) + @cp $(NANBLENDERHOME)/bin/.blender/.bfont.ttf $(CONFDIR) + endif + @echo "----> Copy blender$(EXT0) executable" + ifeq ($(TYPE),-static) + @cp $(OCGDIR)/bin/blenderstatic$(EXT0) $(DISTDIR)/blender$(EXT0) + else + ifeq ($(OS),darwin) + @cp -r $(OCGDIR)/bin/blender$(EXT0) $(DISTDIR)/Blender$(EXT0) + else + @cp $(OCGDIR)/bin/blender$(EXT0) $(DISTDIR)/blender$(EXT0) + endif + @if [ -f $(OCGDIR)/bin/blenderplayer$(EXTO) ]; then \ + cp $(OCGDIR)/bin/blenderplayer$(EXTO) \ + $(DISTDIR)/blenderplayer$(EXTO) ; \ + fi + endif + +ifneq ($(NOPLUGINS),true) + @echo "----> Copy and compile plugins" + @cp -r plugins $(DISTDIR)/plugins + @mkdir -p $(DISTDIR)/plugins/include + @cp ../source/blender/blenpluginapi/*.h $(DISTDIR)/plugins/include/ + @chmod 755 $(DISTDIR)/plugins/bmake + @$(MAKE) -C $(DISTDIR)/plugins all > /dev/null || exit 1; + @rm -fr $(DISTDIR)/plugins/.svn $(DISTDIR)/plugins/*/.svn \ + $(DISTDIR)/plugins/*/*.o + +#on OS X the plugins move to the installation directory + ifneq ($(OS),darwin) + @mkdir -p $(CONFDIR)/plugins/sequence + @mkdir -p $(CONFDIR)/plugins/texture + @mv $(DISTDIR)/plugins/sequence/*.so $(CONFDIR)/plugins/sequence + @mv $(DISTDIR)/plugins/texture/*.so $(CONFDIR)/plugins/texture + endif +endif + + @echo "----> Copy python infrastructure" + @[ ! -d scripts ] || cp -r scripts $(CONFDIR)/scripts + @[ ! -d $(CONFDIR)/scripts ] || rm -fr $(CONFDIR)/scripts/.svn $(CONFDIR)/scripts/*/.svn $(CONFDIR)/scripts/*/*/.svn + + ifeq ($(OS),darwin) + @echo "----> Move .blender to .app/Contents/MacOS/" + @rm -fr $(DISTDIR)/blender$(EXT0)/Contents/MacOS/.blender + @mv $(DISTDIR)/.blender $(DISTDIR)/blender$(EXT0)/Contents/MacOS/ + endif + + ifneq ($(NOSTRIP),true) + @echo "----> Strip blender executable" + ifeq ($(OS),darwin) + @strip -x $(DISTDIR)/blender$(EXT0)/Contents/MacOS/blender + else + @strip -x $(DISTDIR)/blender$(EXT0) + @if [ -f $(DISTDIR)/blenderplayer$(EXTO) ]; then \ + strip -x $(DISTDIR)/blender$(EXT0) ; \ + fi + endif + endif + @[ ! -x $(CONFIG_GUESS)/specific.sh ] || (\ + echo "**--> Execute specific.sh in $(CONFIG_GUESS)/" && \ + cd $(CONFIG_GUESS) && ./specific.sh ) + +pkg: install + @echo "----> Create distribution file $(BLENDNAME)$(EXT1)" + @#enable the next sleep if you get 'tar file changed while reading' + @#sleep 10 + rm -f $(NAN_OBJDIR)/$(VERSION)/$(BLENDNAME)$(EXT1)* + @cd $(NAN_OBJDIR) && $(TAR) $(TARFLAGS) $(VERSION)/$(BLENDNAME)$(EXT1) $(BLENDNAME) + ifdef COMPRESS + @echo "----> Compressing distribution to $(BLENDNAME)$(EXT1)$(EXT2)" + @$(COMPRESS) $(COMPRESSFLAGS) $(NAN_OBJDIR)/$(VERSION)/$(BLENDNAME)$(EXT1) + endif + @#echo "****> Clean up temporary distribution directory" + @rm -fr $(DISTDIR) + @echo "****> $(NAN_OBJDIR)/$(VERSION)/$(BLENDNAME)$(EXT1)$(EXT2) is ready" + +version: FORCE + @echo "*---> Create $(BLENDNAME) package" + +makedirs: FORCE + @#echo "****> Create package directory $(VERSION) if necessary" + @[ -d $(NAN_OBJDIR)/$(VERSION) ] || mkdir $(NAN_OBJDIR)/$(VERSION) + @#echo "****> Prepare temporary distribution directory" + @rm -fr $(DISTDIR) + @mkdir $(DISTDIR) + +FORCE: diff --git a/release/VERSION b/release/VERSION new file mode 100644 index 00000000000..f454b8169e3 --- /dev/null +++ b/release/VERSION @@ -0,0 +1 @@ +2.44 diff --git a/release/beos-4.5-i386/specific.sh b/release/beos-4.5-i386/specific.sh new file mode 100644 index 00000000000..66ce08c4613 --- /dev/null +++ b/release/beos-4.5-i386/specific.sh @@ -0,0 +1,39 @@ +#!/bin/sh +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# OS specific stuff for the package, only to be executed by ../Makefile + +# Add Python .so to package +cp -f $NAN_PYTHON/lib/libpython$NAN_PYTHON_VERSION.so $DISTDIR/ + +# And create a drag'n'drop symlink for it +cd $DISTDIR && ln -s /boot/home/config/lib Drag_libpython$NAN_PYTHON_VERSION.so_here diff --git a/release/beos-5.0-i386/specific.sh b/release/beos-5.0-i386/specific.sh new file mode 100644 index 00000000000..66ce08c4613 --- /dev/null +++ b/release/beos-5.0-i386/specific.sh @@ -0,0 +1,39 @@ +#!/bin/sh +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# OS specific stuff for the package, only to be executed by ../Makefile + +# Add Python .so to package +cp -f $NAN_PYTHON/lib/libpython$NAN_PYTHON_VERSION.so $DISTDIR/ + +# And create a drag'n'drop symlink for it +cd $DISTDIR && ln -s /boot/home/config/lib Drag_libpython$NAN_PYTHON_VERSION.so_here diff --git a/release/datafiles/.Bfont b/release/datafiles/.Bfont new file mode 100644 index 0000000000000000000000000000000000000000..364194d9ff11683177366930e51cbad6b9914311 GIT binary patch literal 25316 zcmaI7V{m3cv;`Xbi*4IZCbn(cw(WdzCbm79Xky#8t%=Pym#^yGs#oVvpS`+I@7`Uf zYh!f~=piTw2nC6fDub|@qlvkMqk|g*3nMcxv53XLCNVSfzZYf}02~Vov6;208?lMG zrL_Y9j_E%-N;_CM60

7hvY@^uM5oxr?i{qXRMZe-Ec2b}=_Lb9AutCN?v-_>a-< zc6JKJ_U6RY|2fV7#f|N)?Y#g0dT5$kTUxmhQ>&O;y4xAM{GTsKyBXVAn+iKv+L;so z)9^oMwRV-T_A)n9vUW4IBDOHLb2a~OK;6O2+{Mn?!CcAF)!OYpG-qI8{-06*3#wUJ zo7y^}dKU%qAl{)2$vWe|S<%x4)MKd^p^x zyiu*BD5%b{Cotn#C#-#%0o=w`xm8MGXw(odF>NjFdSxhBx`y$&m7t^pHpR@Zd7I% zaZ;J5TK&q6EL>ipcc@02oGEKmb?6UV&=HbQ=E>On1Cn*g$2}Uqeg96Q zSxGz<6?;?z;d{Ro*!_t=5k~^ve&3j~fS||G`ZLWFq3TpkC2VARhtgRBVyZmmQQMo1 zC2$hc5I7uKSI_Q;^>e=hf%GxHbZ2>{-*ypEd;~|(am8(f;D=#=EqmqzzJo~j%^=Z% z6k-p_?ojy0QGLRFVi#Ph(-;!_Q&9M`MTIS`yhy`*L`otAn{T!h+SspoPbj0Uec+#^ zZOADA@N?PU@_?Psg6OR{<*=N0CP%C+t-R7rwLi@&g9tj8QjP!s_bkZMZ*%;|E3#v3 zLFK%nrCf)b!oDC8z&zQFSZNs;Wr3~CPkeTmhkDV453((a;*cP@(@cUQqC5|c)&6)i zoFL##qI9X5Dol_>78WFXe{&5Oz`OAK%g-~2l7^+mjv9dX0I#UT{gf60$$qyfPF zb(|tPmKtOkWhHRUj2qrt&(+`-eKlppNk<$dYk!+e@0eo?E)??!A;O9HmaV$kb54Y8 z2xm~g69K>h;DlrJQ>5nK=6q8l5poOwZ$t~ZDnVfh@YzfY>8J6ZDpuzw-IWT&I$$(o zKJinD=aa(++&oZ%Fn_g22=^{VMT%Y47P$-IA4 z=mp(9hpqnvy0sPqUSh=jjuy1%&1-&cwK$WvFha%!rf_7)-Rr#*+eLbZ}O+KNuLpDzlD5 zkqFkDKcC$!Cc*f3To ztxo4wd&sL~Vsn-T72plH-^S^upItvl`-aoT_=@H4%~jt?EJ9VFxgCNaruKvZ;J#G- z(NQD=;<=T$nEhL8a*7M3Uaco*8rNKZgQ;xBBR0i+sm78^Oz0}B9HDhea{9#VJLMf(xQkDrV8P^h6Mot+;yh##`e8+;P9Z?;BkS;+GyP! zr`dbWCVQ1Q?(2DKjnP^n;$z@A|7N|O-OTT$%Bz~ZFUq?(DA%>Vh_VCnSx*gm(g8_N zgY#P-#mZXpEiW-FaC(1A1*u~k0o18!5ul>~(GG|nj>l)=2HWA$A|M-=mD8G&Qaytu z?M$o35yU6OaD|nmeoj7W7)sLEECVFpKzAHE)&Gl^(w4;>vA-BW@iQ}xlaK<~bsNXT z6PqNXh1Ad}c&i&ssEB4I#l1q|cPFoGpAB;6({8Jqq*tT^;asJ*5Ed_lr=Rg+YoK3X z|9bmw5h7y5<^+697iQ?nb??+QW{I)2iJY9E^d$MI>614M6Tc45{i>w#sq!>&!c)M? z-hpiw^4W*YHpU7rTHoPUS`+_~lfC)D_Sf2gnf|P!)7NZ$hunp8V}~loX_^rY0Jjt? zjt~<;A7T&%;V6&cx>tlmnZF)mQ4JQ)oX2DEqXi|fduLGO%9b??EWSJg6=xsx^Bu(k z-4Wk73W-nnn2H6bj0lwz0$Y1w|4nAUO*Do8RXxWqNe$&!IU9ge#aL*1%yDFS{vwsD z`8G=9Yr{v#vQg2wI6&4`(c%FkWqAIbEJ_-Qm?16V(^=KA&|&e81OWj#p?`$p@ZAA= zX_!licn(O)WbwLI=0RiwhHAr@oazrUt3CJ3mGB$wPoSg+dKCDXy=SxQjzerqwY`;; zKt=*$u1eNt{K^kdcoSP7!c8JKCF17ath)5Z8LRVcwSZh5c8>rftcl178sx!wdVjH` z(@XYki%=!=zv~YxQ--`os3J?c&%E?JX??MgGM=4#-VID_37piT;$B|tV&~$5+F$q2ksq}U+a*{sY}_6+g8#%J~1s}G1{)W3|Oqp zOiBldQl0!q7%e{(%}SlDR9-ixNQa4rdzz&dTLd%#9Mx*uIiX`kwM_IK)}CQZhppu5 z>+tV)ep3}6*pDn~g|-VAf*aaMZoR0p8iulx*U#2|>UD{m*qsK{b7ALu9O5^$OnRs{ zUh}|;b!)z-=c~?V09+Av)V{85ZUtLAlA>7F9y`rpAQ{cB@gBW8@}B81bBoEvcLVl3 zFXE^gYFIQ`wcxc7J*n5Kjp2yz!BVio9~=o&AlmtPM2?J{HQ{k$-`Rm;ESz6yj7- z@+pq>dG`zLG`kQl&#*v8(LQ{FR-)PK`9Zy>{G0sUm9s}-q2&V-!Hk%B6!+X0r|>hP zf)A-f0Q>s4iJtv{lfqr$+wQ!9BdOV-q@|4S>RM9)iIBDLAAdD@B~$z7+KOu*tuyz( zsdR}0-`jr6;W_RP(9!_260u)B`ggQmrq%L z1~9f2;+h_tTnCT!O-pycA2xk1&!%YoT*ml(Ys5V>nR2%`*hWfk_1wtEWk2T9^-g>oCE;3qrb5_!0#_|T-b;>Fu{j)D>PFErEF2l?|D!EY$m6Zh9JK$G`p z#FB&CYA*oJiSm?{%!`Mi=9EHyKhq)fbH1WUm79&bYumUlDuy$g2Egm8_~ zdjThJ>9~+AC9iD#s!6iH#|xs(;lA?idmtW`UM>*fhsK8wAPBLQE1Uk4fXTO~Evwk& zZIyW)n4Fo5op+&`abda(7e>c*H+^7tiL|I|dp%oW%=`|P zdnM!g*&7^ri<^P$J~@cqWhKmf^Q;MsKy#uk5t+i7?_n9(gWXHPnV4mwYpmUs-P!>w}XprQI%cJLaBu;qX4o zdOVj`d+dNVnW%z**`s{BJ=mIWnn_@UH|os05f5RjxOlB2rYQ9*i7V{n{t01;Eh0sz zXSlOG4HDDZYyJs7k4~8lH64XnrI%Cc7XKzSana}Y05QkaP5?vFw%XeN$6mgV|L1#P`_)!m^^0Y zp=uAuyyiIuX-6x*VB@kXq7!jte)tSpWoL?Gy9=F1299Lw^R)n#KTN$YV<1K4b9>c^ zji0{CL?r8Pbs5(UIip(oJIdl}L=ZzcQ&~i+CAStSu=9FhlQeP(jp+3C$2b)1GnzKu z25wHD)RT0YWh01tM#0guphCl#hd*&ih&Z}K65t0N6Fbaa&d?wseFdU+ZIXYh&GU^+ zNFm}~vI|oBs+e6rYaV|j)pJce@?k$;C?dGapr#|vLLVH*wAhl=ESx^*YAF5X%KAmT zg_5plb%nDpmn}u5GpFy#i2}PVfEtB^^rL@*Ck=$%$4YI)swu1KcU)~{mNS{`aBi9s z{o+gA={rznxr@fjIY$^7X$+MCdEV-ol7#w|-!rpOO3TN7R=54+X)Ftu+%;g0z8`3L zg!Fa*w3+m%%vDPx3hMt#+)`6qNG0L3U8u@`u@-az!8+GFzVU#1Yi>OdYNs|3-3!-7 zLas|J{Q)HnK>ZhjGXBM4Bf;xi6zqpo6#1<@s`j-{JkxhzPD5}irGA+%qn}n*ovj?IY+v0<(d}a6oOmvmpl8zUls=r^ zYzp1N+MOGRGLm|Xcw=}KTWF*nouw#RVg4C_Rhqy=l4}MP^4TeZF?H`Ia9j9$R`(Y2sk zu}_}C7MV_~c>8AdlyDExoPbx3eAXgw>Fk&AWa_B5La?GY6)AY7hZj4UXFLH?VvbIP zxi!2Ku?)yYewZ1wjaEEuettOoFFmb91g0i60cYv9FZg<75|9__8|X`!xv%vU-#si_1NT#DSLYScnPb~i zBSoIcG}_iKiFp0xNGKNB%IHEk7i)r9cY6Sm7D_iJThi3L69s^XB_Qe=XfZTkg<(G#b$T{Ehutgx!iRQF|x+ji`QMY8l$BrX-lt zI@!aY^YMei{>UQMprN7Uge9Addl0EI@qI-*_*iNqc1XeA0*9I2cVX40?XO=r6-5#H zLPT~2{B}mdf>U@DMx}O#9)Ds$e5tMw0}XeH9m{RBDSeL_{9f6^A4KuE*1k=t1<@U3 zx&u;8UE(9PBIkGibq}I1WRj|}ITk`^tG-1QA*E&FpKA|)`*y74gARdQACpHNs*If-AQbGKDh-7LM|JK#~yVaGrh8>}rcUF1|FCa2y)*m`~AT zl!p~i>1CTyuZ;MgkG{aTDv6t-eitr<1=;E6k1by9oVDLWyg-sH_bnT;#qmiA#;{PHS6O?XRI6L}1ZeTlem1JV_Z2%y;zwJJcmsTRPYUW;N0o$4aYTc4 zjT=G-98)7Cd6JyxezRo};5W$t#8Zss?dr8(u7rTofhMkVJ;{d-Xli>{WpVpyon zd|uJLc}Czt?&Wx}791Ae)(x|g8fzKOvY$lBCiEe}biLj5g~W+k8fAVA)1X#=UetzQy)1$54-qWv8eLd?|t3T9I3}8?^7)mU|qJsNZhHqT`=I zh9;V09A3VF|(g!0(R@C?0$V6%h_Pr}=$r!~( zG-M{@`z!e;Lob3zrH&)J%4kbJT8AhIJrqeJOTW9pZ#jfcDB=}_c}4GX9Gi*nwA&9{ zGU?CC4XD}0MB9|lHqA&Ngba_K(t*A55HTeghruIk+~dxUA?>f+xfLBDke7!i96spE zn5R~wY%zmuOr+aNbe5Gl$LrBVNRrI>>r@AK`xj9Y``nJ2f=YExkj&td z^FIntlZO$nT4sa870#=)WPRtP0~!8`ir9s<$aRdORiQbj8rrplRCB*sqt)yua2l;? z)8n|AlI?%(-Oo=e5B|*`E9Gj=6wh?`SPK!374!HpHm(v}gk`~>Z9nZ#;~1-27k)<% zcG1rJY#LQ-^Y%iT5e`0E6^z9vy~xqP&1xMX?)(rA<%N?S z_O(Al$6X;_X{cI8D!$ZVa_^bo{puN9YMBfKL|qkBeO51;T-OY|ip}t0hXj=uH-v0L z#SV`-;Ob^4CM>Gkunx=2S0ta-5N1q^(=%z6Hf=F{yfERC#COTdqqjZ3YKgkPrhD+9 zMhA68q^d(R@x?n>e=wAGM6iB0afd|9b**PGrqY96GfDMIAj;@OJ(5vZ6QCH&w-QrQ zejtGC!*7TE@t#u!FS#dnv`?Dgx$T9tEeQf&7jGEdW)QY^aBY>n-(uOX>SB2cCP|~5 z0AF^TPOFG6Is`YeZpE`vCQdo#+Zd^rF+)`XN(8xjI;zybKvi^d4>{#mu8!)wTREXM zO8#h$+0FY%WfkTk@rsYOLyx~q)E?^YM6)=!p{xq_75D7}P=wQ$&&Snd&C=$O1=NF@ z^hH`+9AT1npgIbv+M?v%y8nP#;2YI!)ed{*LskB}$FUXqy)Ja!58X@+&Sj=K6t7S}wW0RZ^%I`fzdow>4P4v>>+n{9N2Q zNPh)Zjb@3g1lwz}sUef;kq7hFG{UcmU@HAUR0J+M@()lew;z#xNq=Yr6iT~JgLdKL zzrl74l{PeAy@{GxZ;1lyOt0$Qgf|Pia3(F$PiO~7o22{ zQ^(yUjFg{BKV4JTV(2Hx>9>CPh*iB@Xx+`xN)ow4{@hy4a-%tk@l_9!w0A_2D&Dh) zrVf{p%eE!$bGhLs!e(31O-)V7O% z7!Rt;ll0QSS{T^;LX6-U0D`!$0PXF_M94DT;s1OAbwpZNCzVBE0Hfv4*=BGcSsnA?=V z%vq%hP>Y{2+sH1X`z-uUNYzJywy$?W)J$pjCC>j)b!>UVzn;+(Lcv`Hp}~%SLaQN; zJ{M1UKc6v#a-Opl_ZdzFpyFTkRQxNSG(Y#I*Bj>Y?c#c2Ba2wDwK-BjO?4oH#xa~T zC*ta5FRg2(gE-pb)7N0HOtsT``Z3dts4G8US4rl?y`J~g$+t4uI$ijEK^Nyp{_xoy zT#-~xnrSfhV92uXP7qX$bSSH18Xy5VU)+Izna@Lsy++~*Z_AM62K$!+x4eIDQ3k+K zvOtFd;Ko}Of2u9{gwJBfg&{n=7tnBT_j@lYMy|N08DRZIQlr=QWwa%XP2K^3 zv$`{HtDjyeQ|Wq~6`-6k?qy&!5g8LVoL-pRi=H%d;8i1VN@POR{<++b^mCh7Pf!HQPA*>Sgj>orplTQk0s3#j^Gip=O zG0qGSQc08G8porvW$S;|Fto9#Z41SYjV^Uy052vszjrvFT~tyEY3TrPy$A-Q zFQe)w&rf4pO>52w+gcnLP`JyR8J~LGc_?S=hUdD*lBw|E`y+2-VR{d!^Dm3qEk@Gb zZ`(h-J<#yC0+>C!*QEM&A(l|0NuQvh5+03vKe&=q0C4h-L`pI_h+>W^aupM>o1ACA z+AFQ@!4mA3o{I;YDUey$@q;~zI!wm*AE@wjzAyYurn4Itcq5gJH;JQA_xax0s!Ew4 z1Pf@a)v2YQ>5p{DslEopwjhVcetX*MYqffUjT4(19-_08wcGJ5r+V{0@AHF zhY6B)zNoefDF*BMLh{PCx{72ho}l5P{vm-ci_t8g3H5A{VY)nZx0Y-U)66Eke?GQ$ zJRevN4*dkxcA1ak$-^w1BUKQb&?w7wfg>2+Me==;Te-T!j!?TM0o8V@{fNFv`Q~ zu^EIhD-bHy$6ick#IT3E!P-xc*{q78LiVq|e!Grfb@SED$-JZ~{0Hw8>#4G_giAzX z19~}#_rZ((d#OtK0+|u@s6Eyr5J9Harn(T^4%~SGOiSlrd~iTqtAbkdc^(qiJ)ag_ zI`#R|0r|4B5p$SWF~&#&st`{y`__rClPw|(WM+cSLaQnES_+r3PEHsxa(uyW4B~*= zlhFc8GNHUgzBdvXFE!A&XRd%nKgOW2c}hu%M0$dOyuVfh`g}A7T>#xd4f$%u_tzP9 zB%6Aa(B$w;dQtcc?^DN^ZkrtATy3Ug-mSezusxatVY}R`|Iq!;2C{y{>5ooYi0t6Y zq_T%?OYpL!G@f9z&)ho^<5FAArpIR{G}6co138bJ=T!Rm67*K1#u!ej#S5bqDh9R{ zDke`a%%QS8TvrTa2duKNxl_xR(eSHX0ILJZLKft8^uA_j#@>%vmdU@$KS|3Oo4p-~ z?Dhe0N>EH{P4yZQ)m!QbH3wctvcT|x`dU4eMq^jE%UucjvS}<+kR_&x%&mr}K|+~X zvq$x)FsLQzkr)2yI2nGk=3KT=L$|f{BH}0joa>e_@(x;YjWp0$Ty(@O`n}UeOaW(a zoZ7w61pqfoz`Uk%E*p^p`+1v)*&b`|NFilN@*DkWJ`D6*EwdW9&7(oud`JbzBja&K z<~MevV(!(l7*myYK5#>qu8g#WF?z$oxnnCMD5#{n*7+Kq<9sDr!}8$iMHiQ6#U|}8 z!*6B@*bc7-QD59QAcJrJq%Aseq~X8-8C*b-Zd&;FH^W!bu9!NWL!M&3)=fk<+ zY)Czd@CArq5FxBFaQ>uQiTTvX3hT1f>@NHA)&Rgm`MhIXqpYPFA&{Xa6PusqZ3=&g zah@UF^U-tM`h%Uu0*xWU&0FfCibuqZ2vs1$Af(v}P2l@-A_p3-;=?&imky=wx&HKqI*f|nRcn6m2`PQXrH1a86}QiV5tl~m(2ol* zj<+~27vfU^N>6Rk$J&U>p7xH741>oU0t**;xY!IRwfFQWuDQurCw!BD0u%};JC_UK z8O)>7sN)l6ZPjdF2~=_Z_?L|g=K<)#b;h@M41)idNzv!g?R#P5oCCEOZN(n`45 zes_=<$84q8lDTd*e^TmGqqNijaH^QKqK7CHQ7`B6XGxBqMDmM{+bfLn{}Nig-YB&a z9~@E0zl-pl{hE_6UX+yX3^00&E-{K9){x582Iy8de~X)v@veOgSO5mCq1Kq^MiOG# z4w{rwr~hOUJ@U0ojbuKYzRy+C7K^Sm=$ba$5(7c2; zk{2~l-7%0lC-%~DZ1i*g?|8Bp49#3>&9v=(7tg?MUmO73FLV(yn9m6m#cM?tJx2i{ zgET|dCo~1^X9%3+_%ZWn@pi9k-N|=Y#K0o1w}ShRpd?;w$zy9lbCJ`#qB!*6iQ{X_7=-=a=N@3O0U} z@2=C-pXw0LT+M7QZC39D1P``Qdq=ANY0orm*bxn_8RFYG8+f!^pbXlrTl?;6tSVW1 zmyb||w_uC;X@(I*QBQ_6!VMRj)B0*KAr;G97&Z_SWp&+a>xH@!TVZ&^RAcY#``QCQ z-<^~(V{TC~x!7pWY0jLjTLpmA3}rDa9T6z%xNe8u3u+jn+F9x!7hdh0Eab2pwd3}j z$~drw;W9PbKbW?vc@3ay1HF&fw<52 z<{q?yZjk-?lQrP`!>{Z;{Y7;ouXq|Flvq4kpM6PfV^2L97sDsUu1lYQ94)Zzy*&an zHY620#W@o-$9Xf#bOw3X1JeI_r{lYxVb4tX*x=dbGM2e2veQB8UuDwMd&^y^5MI^M z3L1H3R8E5M!v5Qi4U@{FtPKD+h7%d<%XDJ!mwsy3Jb!~-cEdf;fWo8LDSYi=2oOJ8W?Hxul8Zr`Xus z(p@uTX4d57t`+OI4QOk;0p7M9?648 zjnXZ7e>s6v&30L_PHj$FZ2tPViub*7aMi zONb)lhHp!BFZB?NRBCALN_QMBIpB0Kids2=@Xw7Sv+opZm@_>=90kbvLuku41bvIr zJr8(YN2c#zth7BNNI&D0`EVk=PN>xaf20L6WJUVff3#1Uq!xt(;LcAov{pIqrWFbh z{w1&u!LC?gkKHDx3t&eO5Ox8X%50y&p;V?`#E$P(hqz&~#RpM&W=%#$=c!F)YkSz2 zely9A0@$sFde1@fCT1iM6b@hl`sWk(gVRn>f-ZSgh!*@HdFKoYXm^G2D1n%vXCGrVI`HCu3k1Mcpc^*1@owSzvcpEftzwAvu)=dd+^ggMW+q)KI zs)SN*9PzqL#l%Jb)i!uk`&|Y?iCoM5BFg3Rq5Yn$k8S1LOi@CSXB6GDjKQ|T>+4wP zmg}_8InQprp}W)*Ud?1t$5!=^kU-dsLMI2fi=tu3#%54VUWc+}iYJaUC`I_GR^>A; z8WKPi{Lq1RfN6JbV8WmMez-_S@uj>?BMQ0a$1&lEy(omD-v7nE>CUt>CbCirA7Y z3oAIJ456MU{7(2b!P$$xW`C?2`!anp+O5iDan@%@zE-N+41tS#S{Amlf+6Uv+E7g# zxGie0*Pt$;iq2^<050BWSRi0A(`+W$=S;6N1rOF@(sS-ka@)@3we|<1D6Z8_)QChV zRRk(%hT?9B)j;ElPW!_Zf=+Xi?3G%cqhN=3Mp$`TjKBo7L`>E^1?#@}X96zBeJEtC zA~UnA55FW0=;<|tk<8p@(C&7gaT+pV*v-h02SAd$pqp&Pq4Wz^oNl0)@G*v23HYe3 zS}IJ1uKF+kr890`quW4+;>F;h%h%NuPKp+tk$~L348eGZ)p#_?wT{^dxeXK_pd%v9 z59PpDoy~J9M&|zoF76yrhv8qO+w$&(Vqo?$;z9NzG~Gz)U9UC-3&!C1Q1~_yGF$!z zlFb8RNHzTz5{oxJTD~M>!+_^6@`fi5uX&f%)FJ*~&jiz3$O2d0m8aoMzILIP08#Gj zMlK6*Cb1-%Ifhglc*&mXM-r&;RZ#mNZm(yQ%CuU3M-X8!!y~~TZK+E?f!#dm#nP}R zZ*l<(2)__1lL;*_{dl9Vn@#J%TA2sKUVu9NhEO_p)n8o~Fk%m`+G_wf{+bWjcK5|q zflrg1Gox58-S>(u(GyhQ8|7(&@aB22O{-wFrx7tML%NKla*;i6zkg5V18g@1r3v{} zJ!Kl<0Z0#D7YIbd;8n{ROaS7gv>9?53$9hhP#DLN+2Ay^jBWzfwATl_bYUt@K{Ub4 zHXtamr-%=GzvE3>?&*f;%RbTKWoCuGgYg(XBz4?G_-u@?l2k}pU~2F1 z>i9F{^+mb}_~nf45W0-HK28zMJsXuIRlG5pZrSZhQIJ7QZBB5X;n z3it=@18}BG9&q{+`_G#u?9$a67ko8djHSwc{{+Cj0$i^qoKo7`7_Zq9Qs0Ybzr1hm zF^iZ6>0d#91SYD$i~Grio?KQM*Hq+Uqww1uwPb<}VtG(Yls70cIm_xZMy7i6pr_%B z%*Vy+hB{q$l0h~Hf&K7;I-Cv(vm)F`Q9)paHDMzijJ$Mh0KnnEOyQpZM|O9Me6{+= z*WFmoqMf8Ja{Z%a!dS#lU!QN8V4NVOVt#sqrB3Rf&<6v5PFqpTHfxCbl)IFTMl?0X zdLi3X>+?4LYJ5l~SFO%%Np{2pNp!Gg(z*Q2L{Iki*D+2TsvUEXxC|=+#VC+BHk#nA zggp)v;I5*7`{fl|3hH7F9ofY5F@7fgNeQpDgEAphR2BH6SOukHkq z#$WV15yY11Ku%Bc7MkFoK4r8PFLkW>&EMmb775DtXGo%da*cevLKL$+$Q3fMeRVV{ zN6`s*=EITMvB%MC&5!w+tPLKR)@C#{^(SK-VA4ikf@350NJ-P4CHfP~F-!`fDHXuU zX(I}ACp1Z`@kfN(Lv}2^wL)0y0C22|0KFnpQ1uEQ{xBtVrz@z&nIaD4;kWha@w*oy z8I7UvK62CWf*mgMO!Lyt*2XUK;V-rkfZIQ=Mx^;{8K*61nK9)UgT^|2F<))4ILaiK zdYqD(R-oOKuyp?9>e~&9_u!y6qY%!Dmc`Zs*^7~jh<^mMsxgRC+3qUl5-ROoK#TG& z0FI)Mu1+RDg;#hj#bMddr_SG7MkGH1nrZw@Sok#>X@^qLc0~D= zyBfJb!)}Uaf$+m)ZfEN@Ek~ys8zkoPk=`qc0+eEs-WUfjgQgBz|0k-LCNJ}}`fV*W z2&L@&!B?7lg%(W{k^FTOh0QjJ;Pu)g0sOZ?bC|AD2GZ_lhgFYZ6PF#fFfm@rn1zMV zBjR9IWq6M}i=Aw^lp%8fXjw<_j)4)?-uB>pFd24x5>%~{ zmix0Lx{e4ZTV+Bc`kK5Yc31(GtDa(3*lanHznb-1{i;c&Tn$sD%5EEW$N_K&8>}_4 z8MvoyuZFKM59kU}aY>aGV6(7<6s$j)SW$$QD~PcUPl*&Z-@+uq5%pt_eMXb8+KcTwchjtv(I%0Jxv1giz)jI@#BsDm?K1YS6#j1m;hjLO!iC zCy2b>Zy9I;jgsLznp`miTb2fYeHRg(2@g5YMsa$a*MonkLfD3*?UNRt5>Zt*+>wh5 zk(9?Ow-(HJQbbdivXs>JJpfy^P7Wkfi)U49mN=@@h=kL~h_s9+(C3~3A_bJqR! zZhwel#m(?iV3%~IHpsy&y4}!Oyu`??ibo%PXEEumMJyjFufK5Qzb9NFa}M-*Q!Jtm zQ6^&heFIC>JD*;yFveDXs;6mA%va;Vga)eqyt{6R}` z`8)~8?!iRwO@|1Ti;GCk|BLdA604JfF`vfCHjD&RzHq~kQR}W1KBPG(^&lX6P z!N&dMlUZkz1WZAyL^>ZG2Q5~JqT{i8%pBn&HoMJhD1 z6r%*>9ba+X(Q96J`ZnvcSC!VEfn`)g^Kh!9 zF1H_WGq|iw{b%prrL{7iljGB$C2meWAT1mtA6%@C_oG5R1UDKT0pZ@SuN1s>b5t3Y z>7ju$S%{t2__ibfI3ATeH^DsuOQi_4M+yL_gkh6P4~Xc!=z1#QOF_7vYWL84nmc}j zHwy9`L}xaaN<M*hQ2O@04t%3l!V z1w_9kwjb4>#O)d6(|?U)p~Q;Fmu0`JLsEs9y4KG9bn2I`DfDSF_tS2&jL z>N2R)7R7Ucpq0mK$Xw7JgBR(OT+=mwX4~L1r_r5TbUb%Z)8&yc-z^)q1c2kLGZh2Z zpteSMq}N75){g3M$dQ7XldN88aANB4e?@YuJ@E;32!&G`dAWWKjx^5WX_D zz?U|c9@uiF-=~-8oSz@N*!SP;7a=Obu%iopZA|76e|p2rjT&j`i`=WprN$p=5ZM6W zu%br8GSb-m#{uJl4wU`~&L~BCYuI)dbIQWwjePa+x&jOVMzA885%AO}QzDSBdZwP! z)^;@(B(X{Ae}T&a^RF`ryf!TWIN4_xw7~f_i|)~%FtE(ePu*=&l+K|g1WCFAU}RW|WUSFRQdH74@678k=f zQ`2%VDzT2_K*i8&gdhyO_n7(wx@EsiY1FU`g_-*iW9=z?V71`=qaR0Znmh^QMp%G4 zKL}HS+f-o2BMSkMluXGm8%xX7&CYa=P!;qhzt?xY*MBCP>-?RItC8%}`PEfgsfC9$ zv=>I~v!bmR@~fbI44q%7C>)&b4)pV*IqGx0IK+`0F&uhhGKrM9s_!3JPbNh!#@5@% zJrDnh^*b`A1ckC>UbfC{HaV%7voPN3?o-aVT`yF;YwdO~SAjyoXtN*uY1z9$AD6K- z8e+#7(SVixoK-_SuGD)xgF+oMa`BANW;O!=H;9!8HiAmWbg4?n`3jxnc1_;nT5T>* zWl{c`ao!h)o$wWQ%d)l8Wr^^JezWAAp(5Vc+YTkdjft6f7MFf7gB+{f}@B5A@Z;R>0AJwy$729O6<9L^^CzqztP%aZ{?NlGkfhH9=0h_Z|hl>o_ zf_}H>?L-2H7sPXNTLxCDqn}iBD$L;i* zybT>#D4a}^9LViLtfqwRbacFApqu(&56E?78>_7qiAsZVbj*TBaRcDZ-Tg4dsN5El z+AiT=8{?QFL5llVI|9J1sQA;Ba<<~8OHNF)^70h2S76>X`a9C;YJx)t{N^l9)&J)5 zql=R&BTXre1Yr%xCwv=$Ll6Uj8%Z|3Tdn5CO)}64MA~5o3;~7eOWN#na6b z@+iH9Rrg09KbQ7oZ93MKvNPBZ!9m+Dj4l2l^6_0Phja-V88O{n#Re+)0x(Ye0+wT_NuWoJ*|7(%^q<_Jz1&{rZQoix07xSy} zZ?LvZ#4+zu+i;JUO|faC=q&G*wJsUC$!)Uj166kUCLiC{*Toym(Ww4uN3WvK_Uxsf zRK_1+h7z|-oM;K1KU1#?`@K>09mDU&7XQR#G*BD^ZKHjPWg#Q?+KE|1t%i^_i<{o7 z@S1Pc8w1=nrWNlX&1p)Nc0`E9B(*r)SLbS+7K1Zb?D;Phw{zgHiN^VTr+9;)4e??l zbv=7K0H&puU%-KLGsTmv`ZJZ~9=<+~gr&DoUFxL0MH~4sn>Mewy#Yvvu!}B3S{<%_ zx9t?&nqQlzScYQ|X%=r-gBo7=w4Kb1i6ZKLv>nllgU64KDU*eQWM-I&r?Xn->Hk=I z^E#jq$E z$D!%^B(E#I*PQ9-a?VyPN@#w`SpgIn9unW=25NW7{6r_I8+n9zpR88b_G8@y$Ved% zCd7t3HhG-H$_A01^*?{bqVi$oxKisTw;M8~{Z!7K;kemVl&l7+l+eG4=Ml&Fp{k|H z7W-rXXw15~**BQTLaZY&ZLdxix%v97U^!!wbGY<{dGg$o@kRktGa1!PC<|M+|EuQe zuPxp&fU>uLNPU4QMDi?thN-#6AsaISeI? zFsHfWeeLHJl+*uq9sYbEXDdy4cuRuDA0t7*zU?HEnTO!=YBY zO@M4XCmPq_#y%79UI<5<(<07Omr#FsW!_`b00cn+$%%q^SL&66{cCpTW}a$i`Y?_8 zYX8W8W}`NcJGZY&a4^-^J7`5Hua_J%+~O&j8AIQCNR5_uWOo}-6HaAHTE!u4B4z#_ z&A#?Bk3z}()+%n>8d)_FH~jIdD_A8$W*?T1}mUDa#<*6I`Zs-ia$9Ny>wr@(EN$i2{O zs7j>iC?My2ZYW&e)d`UO{!$f93S8fkCJ7hPY&iYuiuCZ^7KVeDZ(ad z4W15g01A`z8R@yridPcvqiYH#pT8xHyNA^>GQQ_;g{(2F-nfb{*=bfDmz7N!*7Gp^ zV8kfnrz~b7lI5k)veuYre9kHmVv&XRb_6W#VolLKxHi7#Sx*IYyr*ts6Wh#f2mpe6 z-D8i%CXJ!hJy9S2f=-y)xCGFbqF~k|=@|Z=FTE%Ye3*q&hn_`awty2sYQ1Ryd9d?$ z@K*)L5I>#e6iksPgKZO^;L1si%UD#*C;% zfb0WQyih$+b0Q3ugFlJ!XWXE^-o@bG zRKq!aXw=9DXt0~SLe*Y!oLmNoJ>`dTOw!%k5m;Up8TB$wC_^A@*JNVx@Y^~Ne zH5jrj0IABywphdng*G-u7&0phA;;RW(|h5}(rGBxS4Z1Rl= z9N+D^B3X);c-$-%8Lq2vB|61L*uNx^16*WrUrrXm3S8OW8=uAc%DGFaSWBotvbq2v zHlJpIjaeb!2IGe=Bj;(N|G4thWZJDnD`B*( z9LKUGsTnq2nt*O=&jjZu$J@B)Vs2gG-I9WgzFU7kGPh$0e|%_jsH+J(`ce@4u+(4U zOB6q!Gv~9Zu4n}`9J)sFJV2o({%+&~vSLU4W>>hYO*@6xjV=T2Zlq*-PKZcDm~^p| zOooaI9YglAG?a;IAMel34K@nWs_O!GAxDmCHdu^xIa4lX?`>)cwEo&fbXKoD;aR#| zOv1Q>vA21qEIlx^q%dV0-=?_@Y@=~i=~8!=Fwf- zA3H;oIMMJJR^+;afqT!LGjK-Sju8S?n%Q0~Y>`MSUK(Q>UQZgdw`G+I zv&!PK9G*J#JWrBQ6yrr}x!>AWxe&pM@>J1&mLX}$?LZ)@{N~~;IG`E?;azJ7-&`n^ zpH#T#go5m|&UkRxafY|;H&BRqdy>mZnSv>Xq4Nty98x6p^pB7SQFV&A-nI6j{^%H-EWh%5`#@j?}9*BV~l z4G0kP@5nUx8rpdsUHu)LK<@*aU``E8wGD`DA7{3#924^6n&ANqiQR;TKDO)^Nss4u&g&-}C;gri8B{AJ_a(2WW&NeoeGvVP!3o(kgCZYCpORi_GT~t!Hy*xo{Rk3;cCjtRPRovuZw&=t zpi$3gd@zAN3#eq=(K{bXutLOyU~gNsP)o>jWUbB?WRM!mSSM*%I-uQTt9df32FmF0 z{Q;eDP72&7DYfMPc)R6~*?qzjTq{>cmZf(z~hg+C3paCf$FU(i4ko=^S-D*FU6 zL5RnyhiW91=Y4l+W3glT8d119GVO(l1Z`^RMzceY_u232P=D}AUXUee<; ze%_kT@Q>7K+|pA0A6BnWWUnRQ_F1#ORC-pYLqcu!OwH*gq-IJ_zgpS}LtRJj*5Bov(4gHcb*0j{qH?JlelGMU zm#V}HNEpQ~$aQ!DF8{{(DIEr30;kp)w<`;h?RvWuG&Iw&5+k!R04zalxn8?07UZ7Z z^_l(v1Vg6`#T%bM`%7%F;h&j5oOMsfCW9tJHU+1Qc6gp5QhDHP1d>{BN5bbX!|nbU z=EmIUts6B=6!2}{9p>`7kYf3pBq=YhYHs#W@wZ=gY$i#KcjD}TpMu+4dju=>)%??> zNK@kZ+xUS)6ILV*fpP7L?xj_*E^LczJt*iAHz|CmgxZ*K9eaf#bt0Zf;KwF<+>) zcfJhFV4}d`Ps$>;4Yqad!5%4+FcawkqNDzi<|yUtPB;W5RT~HhGOaS602DsW!Uc_> z{(iwPCf-@-p%$sDB9i5C&Z{=o~AH)@3GDN3s+fDrp;V9EQqwZTc>|te=)MS;y}U-l&&;cGp1gy z%Ta!@{(vxH<|=bW za)Rfbvt?FPXQ*AmWa!;jp#vd7v22)frbv4qWFmMJo5rx1@#BjwizJ&7#2KvWmhSjA zKM_|l2e+pF>SHEnm5$T&D+-p($&uRouzpEqko~iOJmgIBvzRxZ z8oGA*N)7>}y`J7vT2&LnF>nMk;|l~(d(sB#EPPW^Nj+TwiW=FXnv*F=R#{q{Fu~*y zIoma3EwHe!c9}4-ZrepUZaWaf@-%oM++c3?hE7z1x&n+^{_y6NL$x<9o4b(xWrJc$ z%`l@hmd6&3^EZrQvAW8@ac;n1v&zlA%lO^f=DV@|*!GZJSV}Uq#_vvwF{xo(7=e(^ zuxVd2hEvpW#?UQpUUnx+Eh2DP*~?h?ZbI2Zh5}ZwcA&4#TGn^Vr=0tEbXB6C(VX2I zR_0tv89ox;zUPffN9(2T)6UksB_)vIv|Pl{^h@ytj7g_X-yut$XI*277h{o z7GsjCPZtE_dV<)O*3o)o-s2CwvYcO}D(5gy?sa$=Wq!Ie8#l{{kmm|b z)tR$gP}(H%@C$*1e#)F#;_N4$FyM5%4U$rU^Noqh2?1!qQhrErf6N=|`5y@))LUPQ zOKH5qey}c(l7|181&Z_il#rfrpHDZf#%M5bgt54v9F6A5Ld38uUz%=3{Pw)K27zfy z@sw>|`W_QmFL1}3D0YmI_|1omWh|Di)^_?SO$ijbffb}^i4F5b zO=cR=1K0?T)9PeyZ|wd4#2MyRO1-cZ(&ij%?Fp}?rtk4H9M@M&Tmas8Hn&IB6aHGl zA$PUv*OPNsObalkiOPK`Ww?Loe%C@P87{@fr13*2EsMk~OTg7Wu*S8Q;2#R*rf7qN zzg~4=I+O|EcUaNeKDJOL?KhlXfcfj8;oI{N6Ty}LWGgb_H?4r$INnT>N>5_6H@o#7 z=L?Fv6HhPg7m*k`vWeCByD0qpf9XfE5wfqTu<$~CQinZ*=_=6rHkRPR6UphbvdVm5 z80msl?$%qZ3-@t2IKImOJsO72kcWk%aHx z^ixmmz@8gN+tk1_{N*^}Ib}0AIIDg4DM+L1lq_jiGEfe*$VBeKvoBY++3nnyUGvY% z1IsuBb1J2G+)vm~?ZYH=uR_uAbf>y1tMOE+jdU;b$L)PY63^$cU_$Fjw$*eKJ54dK zoW%56dD$bsQ)MEi*{ZG{kA>oOnqqikQ|-iq{SnlU9R2OCDla2lJzvIyE4CeTN*w+{ z&pmy-q+ovICs^f@NnAOsY`dsEIfZyQ*gj0q4**AmX{mI9k_) z>u)copm=o=H?BeG-DmE6A)}u}rg4W-ZVx!;&J9Y!Rz~SFdvngc>ctwhKuj^(h1Tl0Y632MtZeoY3xK(d^ z3}|F!SJ24oeg+HHQ@31x0Caq868QT2Ul)NVEnA+>+B;i$Dk5RxJn4v*VL+-=|EQ<6 zI!TZDwqUow1>W|Ck$sLMqmFH(i|Hi*CIUht24%5)@!sr+QKL@%*_Pz zouTo8wy{PAl$7_by4gCEZf+sA-YQF1`|b1&<0XGa6kA>$950xYbcr}_XAl_8q!rNQ zz4(08f+5+w&-nxz%mmk_@_NQ9R0z8+*#$u!QZkW?u_5N_6pD8dhR zcz^!sm^ruBU&mik1BKceiDQJu}{Pyp_9`zJI2zV)6&DaW>G4Tan&$QN@8v!g5Wq zW~;**j6I0o%#XmXu>4fuR|PEFq~@2Y#gBA5sy;<>^|HvSyde&~&u=m`!x|H7v{;~X z%KiQ<9Vx5iirh?D#G*f6#S+bdsBqxmZtd+m$+}-ror;*T9dlWnxw`-A_*|H{%#+VJ zBS`U^{8AE9DGbb*2Nc5-*4NYCz}il1%iuibkt7iZwseE7;m_QL)adB4l3&wCCYrUd zE`w-F*n*uwFxOakSaN@IkE0->tVOg|IyM*Qjn3b`z8%;_2iJHRN} z4||eUfmR~c7Hl`}CxU{_^k)2XTD4}zT2*i7t?eJQQE}^d_FC0P#-k<< zkg=4=H(7)snS7}lA!&Jhv3q5)c0vhBL0iM%6MUV_rnf!`&WH~kljCiuTd_MwLmP!I zK2t)XNvG~o*VVp~V-FK{&=0Vb;8ehTA#Fg?!H$1{8Zwl0iy=}8N8)xSACLPAV)3rS z(j(K3mn!@%k_D%HhdIeB$Gi#t2rGkp`U`MOkahKV;++iJtXMG{zUJlaJf*;G&hMPQuWdf)k{oveKv8>1~x5Y<86kXeH-V~KgN(Tndr zL%n`a99(gVN5mqb!j?27IV5i@GNGc6 zAu#q^<5$tfkK!N+Fp(1aw3h`9hQx<|o&}*0nKq(Xp*75Hx+PJJvuvt9YLVl#DAp=u zP`YdR1ao2VcX%sqcOa`Wpn+pQz7X&BF}uBiGgjr-@;P!n51YEmM`TbRxp`o1!Cl3( z(kdsY_|qoHRHC;1SE5IN$dVPXJAr?Rrq-1pKI78NV7MEvH8O5*qxZv=q&fxTDFjQ9;A(RoNOI8vQ5!dw?s-&xuW z8ey~j0L2&O)T*bo8IL#3tM?~1dxZbGW2;(`j1ZN_B9QRxHuCQn>@n81ZRk?P1}XP$0^6%+YwrKHv^ONXuSJCloy7Y zM;FNqFI5var(ayMhp?QZ%tZg|irgit!zjLV< zkySyI!(`&*i;*&=M8Wx2hb;kJKBue+gq`D;67T*!E@ddovI&F56IRkpKxVuxE5Jyivb5ruk#6&0P8S_o2em@^Eu^&<`B zHhVykBlWLkVx1(FJLc$G{Co;td;_er48O{dei^4`s}jrFl*DT?740A8M>2aMZVJ4; z<@U`mZ?ql+Az6xVXkZ=e%J7BwVjzA~SG{yZlbeFfvAQu52o%PsApg586oxxrF}rl6c+);1R9@UaIM8NJapH~@^AMFcFG%MQ8E%l z>`V}ZTHh=Nod0%>*ST*$A(OwMr~K1cjQ$>2`QtFBK!pVjOU2Jq^cgkY*rEI7;_g`} z;Rgy`1_@t5e%3)<6*JBCnVNP%YDEhkMhkUFN1sfKtl$}*b}(*)N{Za{Ny((P&wTK~ z7ZQSy(3)m*`@j~TK?*`Nf1gE%+|kSmCv2Xc|4gP53P$mPc3x-oy7k;#xVo4jk~Ag{ zYyx z#}L57Cp1qi;`E*m)xj)V#rHVp+f?*>CQS*uWE)nm5E|B8HKcknK&lH9dkl!E$4%>y zC($g=6ip8Ad@glWhja;%?}li(MCd9#jw61%!%!-oJ7YFkL2KoZ zFb`r5-Om!OpsXIfy8jfOH_dmmUtQC{;s!jLzhzGuBNz?0L~mta{q0OfP46V7bQAGE9i}7o{<+#8`?Dxb)<6vHv!iTT6FMMG(Ig1u)1IHqyTkb2CYoe>w1PEQs9iq-UTCP~jzg5x*(9c3Nx}%1=u!OF?WL zdf7z#f}abrmggZA&(r{Pq~8*T6)tP3%wo!tH7+5e4Q){or_C1^v%IX?K29NiVRYCB;%?0Nk*GkVzIIs(C2yg2t5 z(;%o0$}+7QA4=MkZQFR3fIZsIIme@8=V=nIOW68=1_4*|79NnC9@8T^54B=_f-OMa zItK%b!mn%aOr?^5z+b@opL=-jl*My3H`&WleL^j4gO3_q--pHlR+c#}WvgNNp-j+Y1Pz5@5^0*Bk%K=%d=~(ofbxhH*3;7!^d%?WxvcPu%I95&C znw7IV36?q7GcG|td*b_!l?u5uVc1bZMit-4ikP+5EDm#!J~71PwA>+IYi#MSn+ZO; z8o!kGrPVGCn`Kqml1d#cl$rUaQ~rtVDnEY_SP+;@_8IeiMz+nAcmic7%xdt_WZ7vj z>Vw*Q;cXcgz$E7ULKJYrGJr#ykwQx{*PEjVa4WjGU504&suHT+Cgwi@fX-wzR!yY=)yd-*PdHCEFfDV?ii z6m>*iZ@|sP7z4Dh+<{rDW;CNVNtNOmkP6iOAt5YczV@hRglOv9P%+&SK*_B!7a20k zD%H|1e>`^NM@LnLkd>Hd^)BhDz1ThdAv65<9IjT*-wba{cIUsds*-Z)68%}25B>gy z=leu$l54weC0uw>xpnHnQ!_gqDiUq*jMVfx5S<%y$>NR3<1-070twYvh@fJ5ZUR*% z#BYA5cti?L9L6{8m2D$QZFRCsL-tr7uWzcTKN#C4{;9P;a;o~@W$-> z5lBh|ZG5@_7`RBF_R+F{EpTKp=5d@YWw z#E~m`=_@H4$V0&SMGhA9G%`R~k5o6r6Qf6)>Wklc)abZ}TWtKdWwklQ=g9nMnu^=A zj~4!;n&6eb(ptlbk|$kKwT~PkX2~-#51!)g-%3-OLr>;Pm}_mbPsl3I!WGqv`?}*| z?Bs9w^wFH9cWN@!WBL`wp4<`TAJ#edn;*e;sk9vv#r%a+uqy~}-rAp^nj2oS)op5R zB>TJhk}IS`QQhBRW9lcE^>h#r2*^yscra_2C1zJgd{}?E(oaPz^(M_p_lTu%@;is91CSmy}Y;_#gu4WBfo>g-l#!!<03z z(j%^ux{QCmNSTN~vvJPvg?yx+ZoKQwY45$NWrFUX&mZ$6eyT&Tc^(^@0x#Euh6><} z;@ENR literal 0 HcmV?d00001 diff --git a/release/datafiles/.Bfs b/release/datafiles/.Bfs new file mode 100644 index 00000000000..80854424071 --- /dev/null +++ b/release/datafiles/.Bfs @@ -0,0 +1,2 @@ +/ +/tmp/ diff --git a/release/datafiles/DejaVuSans-Lite.sfd.bz2 b/release/datafiles/DejaVuSans-Lite.sfd.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..0447c7c907def33fd766718cdfd1b0ae32effcec GIT binary patch literal 182524 zcma&LbyytD5;wZI1a}WCzPLNVWzhu|f(CbYO>lR2*F}OmBm{SN3+`?q%31-~doR{rP|C+U$VpCI5rR z6vHHG{W=&*mxkF|Th=O*U5gBhV=5z{uOi>9PSr|fwlw2v9mPQc&}*?}VbWQY?3}u% z8Qm5*2Z#$u`1v{m03?`VbXs;y27ulGFmXMf#F0AgLm&VE49mp^1~RE5cumLO24c(4 zzy}@+7|#GU)-d5_07!@zMcKAk?p2MID8$i38f;s0RT}6b#+3p0v<%J4gjDE z1TX;rNY(&sgJ=L5z*ZJcWreaHKyC~G05DhJQbR@n0Be?3C_o()rjGDx0RT`3V1kk- zQ+em2;e#uMDKAQ9m>?;^t|<1HXaH+$xj6a4OW0Q2DjTJnWr;Tc_tYI>27vW=OgY%? z7Eb^#U1+V2UJEFaibhzLN?$lDv!0!ybOiuT&*3CqZ2}Mq$p8poCagn>R082ysW?7r zVYGTAKzSf06P&~h!HhLTDh`P)46YD>ghU6he)Smu00oDwoCc!g>9ivhA}p0s0Xw3?RC7l)n~Q&d;A|QwD<39hJ2g zF&5SmDoTRWB()$&c!{gUz~aJnyrtm4;4Lc%8e+$^6iVN#lW?ei9sLi%pZ~XlvJIjJ z6aokUP$mKZ0UF&asCWQ%X98~txG{qBxeOb;VjLI^PADA^4+xZ!35Eg{fvJg63R-0l ztyBn35IRn@BqB(>A3Kl)K#g#fhDW^4vN$PJA%&A=%J~lP z77TooQ2soF;YoGl!HKrW!;-bfH7@hl^Usy7Rc4;rZ!?X z-vKZA*oE`xsapV~2#tn*FljsbrBPtkSLyiRn(uyM`_=CEp;zz`TVg0iUnv(b1Ga7y z$-jkF4OBZ{nQYvnUAN*sNOgO@6p8`i1JMYW3IT8u>TptNP^jiKDcsYxFCM9lVq1P; zhF4LU-wd%c(nfUF99m~8&u7#1{N%2XC4*~r58p){QNm&J^*774gA{u+U3q~|F5pbT z55nZVf!My{==a(o5}-24^Fej^tDddbYy`juz9xGAXD9DMajyl$m*J5bJ(%d_6JYNv zqpPMfVt<?-B%t;WWTY1?;<_1Mz|RMKqK<+ z@Wq5+0Gz!142srk!ePr-NYd*qf-C&5QHK2kBxVrQd^jlHbXL1uL{yy$eO2}dIGTAY z?jNvoFZ^;@x*@u>buXZPZx-4xv!2Na$lviN@(=9h2-I5fIY((-pjL-5J2@iJv9B_z zBY|S!1#BP6z?8SZc6X+&(MrrC3n&ESszr6m*cV57@ zhTKDSttLoOCp(3$=;$qgz&`i^IRNld@d1IVUjhn|k(P)gS|A{JJuQ|1dNv#s2zyt( zfx5Uw-!@R%^7R+sH!-}Ts;f3=sG0QMTa7mk~PU#6x-|po}UV|s`7_rz4CJmkn`gGz9K(W-Q@>Z zKaE=|iy>2O^7pmZBVa~QyQ~*ddHZZ7NL*232O(F2nBWi-Wwm1eccyd#)M0S=D&nSh=>kgQUG{SwIhsZXTt}=NhGQRBVSJ`SvU#!QuHWl zcxz4oIy!I(wlagh@-u=2^IR02T#pZN@MaCFJpXet0jkfsH1wk89PH5nNhTqGG_ zX2u$Tmu)TuhDsnvmM5t5A_tXc^Ul0Z!=Rf30u|yU@tJ&Ws(Mry;;MG!L-|NWHB|s) z)&Qv_8bF{5FM_577fBo$zODJ!8Cra;8-;H&I6zc|Q1e+eYv%gweEgZJi>kni=A<2E z=0ee}jr@hw7eq>|NUXO5IH-@F-hbM%U$*@|msLgm@_>F>`9^#Db^EMAzV`Rvn_aGK zRNHr^rAbA41FIZVo_L|cW~~d|fwg_D%f!?__V{UHq!rn12R;bO8W5Sa(!>ti4`Up? z_cY-C8u^))yH5mVe8IH)i%4{|aPiirXv5>Afn1SMPw#r|#o|_d_62&1?LJYw@`UkK z`ySVT5IEwPfwKI`RfoiP$zR2V+FyaJA0I!0-7ex)Z zZ5$+;qqh6p)&Q%$*yB_qQrB)(hCi$dvn=0FncCM41aswmZy$CH{;_HlW`isux=q)o zkWO?)4?>;mkDy7)OyNS9BY2kmRQO*-_cvM{r^LKqAi zD{CL6mKP1z+0bH_;qhg9Y8t8Cudj6TbfAb((Ut|T0R&9PNLt~Xw;zCn9;>*A6-7es zF511`8^XVYyyOjYRqzaL#mv$Lv9qyQhNf?&(-N zF(FyZGWxPv%QNE~X%bKdgXoG>G5SiirIGB31UE!R6(HS_Vf_@exl zduOn6aGxZrmgg=c26SkMsk;gx&?9M{DBCU<6480Z1w>+Uo+alw=4G7NgybBQ+glj_ zlWkeGyM=1~yxY@N@&Jg(Ta}$c5+vPpmK!O}dzRye1YRN6kTVo$MFusq8;N&Dw!9Z% zKFDluuiVL)1@m|V4}JNQnL?os=Sd{C*5}ci(J|awT`Byd<6D%* zUQDQpX$jprm$~eC%bxJq{9uw5%I+ha-4|7vFsO>-5SF}DfHyM_B)(&vc}V**Fn%r8 zmsKM|j)sQlVs&zEpeI_5k;wkVZFJDRcZy65u9>1_sMS$dOKG-zb~A%akGl__k( z8Ggf8wOsjayU!VC1kGXB+x#aZDkobs`;1=KYC>jHoV7-yIfJmM3t^L!EBg8M#VM1F zJdMq;iu^e@_7ZFleYJt{@r;jJSu-o~k>RC-dxu?Oo*#^#VvWpsUDtZ`)(14@8SQH9 zBRm&6Pk|-;W4ZOf!Um)5^t&3Lx}M!_+T!+ymfj(JIim&4I#4Wu<6y%)rY9q5eCas0 zWr$W%kNxE;jw)Ve?Ab==lxL=nkbeWvovN7Hqg z)uM>cuuzq42NT|k_B)ZTzD=NTC!Xq3{ZMnz6~8ZkapP`b9*HT+z18PraD)^eG^IwNyxS2>ms&8=WbAN$u#Un97wiLik(- zMdA)R`8uI}9fXroC;0M}$>MENxm9!E#h9*)bwz&J!Bg`pz9Mt@|aWyS&Q85J4R|eQ4Pf~$8km}f_ACt=j)Ty zcRC%k`wwOI9WM`vXnmfAq0rdpP>x!(<1@s(HkAphY3t9;Et%gH7{*6PXQV7#R(Y-L zZO_{64PFkjX-VqQ`_xFxw#JWGmfPs^bNu*=5G=&e3L0;-Ie-vFC-*I_%1kY>FDwA< z_wqK3d8wY6?A}Q(#A(JJW=l-4eFV;vsMsp|3T}Sn@mLr)5P4v1gQ6>t2R{%@qX}`I zddVZ6GUNQ3$j`2<@E|sL%7xo~CwLmoXmi0ssFr&jJWrTMIGw^dx*4;ambXeRvoGZ! zBk}#Kt)($ArIjW=XS3R3luczK+IOlmeBKpV=H_g&;V}V=1ku{likp}g3?7&Y)-)v} zDu(?8OB_G169|tGqU`v7&G((84}MG=oG}ac*{X^RAgK>yXsZtt($!egkWVkWs&>xtAr+-zO<3Z?jg0z_ zQjf$J$4a(}pLKG%n?@C*n#^bkZnVD8H4k~!Vwq&5NV0W;8PffO9}^WLi3Rk zr2INLf8FP;eFu3GQ?NM&|8Z-ZX@Oblcx}=|Nllilv>r=boLzJ0li9q-6CnIKEwKx_ zD4W-oF4_X>%=O}C4`UUf9v}+AaRhY`P01)|9Lx&ku)7Lw29XJ9-teG~4`YTn^o z`UmfL7jul=LclB`SQU*dUb6MB&FH~^_xN~o8OzXUtJ{J3<7LG%nGSYaSD6r7q?G?= zZa;tR&Inq*R?!F9y2V7{0S{3iE|QR^*E@Bd(rD=lFNq9~-bqN<_&J+P@Ayr`oLq(N8o6m`!>&zuMrXu4b$e_4gyjgPz~tduphMfCVPF(Xp@HJHpO*w~q* z30eDqmStYL3o`9$Lbi7w%!`OFJ^5W-S8cP4B5HOxwAKZy{g%k~MtfJsAHR51Oj_us z<8Bs};H7I*=XQS9b0(q33P)LrU*3owvh>^Enj4%kxd~!-H%Ztn#2a0; znvq+bo{Rg?3kMGsx!Ye62^AfmlN(P`!QZ56i7cD1fZ~pu!q{z;Daxi)bQObgp1#it zKm7UtvqUW>0+LkqdW)qhzdgzHsRDDbof%oAx1VC9``MSqMmVZyilq|8NaoeaFz_43 z!D0ke8C?l=%gX|C_p04GzFm?w@V&`c|9C$xF(+xWXHnRU!ZSWIRC^U4ASk$n>PiEa z@hzni9Q0zw8$oU?L?_Hsi+}e1<*u5Lz!vDg-*|J!#71XCTwI%A*?3l|Ym$4Fzw}fz z0K%7Vou$zg7p1A(*3i0P+J)V&sNUiEcvcm|E@BsMe{dh4?sXCNB;TQizjt%LU5{z) zs_q#h2uW0G0vuaijt*LpW3F5X3L)YWq7_(`Ki@#mc&U|6$(RmUC5Me|kL(A?E*@Sq z+r;GGAG+=Bc8y8FfGd<%0(ez`(&3o#RiG;w&aTw? z$^xP`vFP2r!uhtB(3$9+xo1X~&E?3ZC)6;=WB__PH}!FJWSBIfm-&#n^G%JNZ<^XP zXryX*vc%ZV92~ z{UOk0y~(2ZZOW9V_Jpg=`>bW@-E~jL*-8KW%iOLEgOib{g`751-<9L18sRuE6B>M|4@H4QNshE1@IZxq5}Lg_XW2t)?>x=x_-J{F{H z-bS|<{C8QNhejHYzEq|zW~qevcJS#zm`o=f? z_^A(!Q6KmR1H}6A2PH=R-W6ZI$p{!mynJ-RDM@{Wz&KOcGwV={ zrSKg({Em&yi(Cs?VxK(|FaP$Tb6e1^ZLHiuGmS+$^qrBNZyX^9<}(4Bj1Qr0<@d<; zmZuGi0}aO;>1vnWhi-XX=uydpxcIY)5YAa0Pn5XD62-RbIzbxpR{iiio1e|KvCmQF zm0v|)XzMTJWmMU2rjH|rgHsGP(1a{a&cz|fFu#<7-LSoXW>o1iyY`hR^FD^vI|ju# zeqRavc>V?<1n}%edFHpu>Xjn{T>mCb{^Nzspkm=}>>NSEG}DsG@^cN;r*+q$Q?ltO ztPX3RZ_}b*$PGiI4316u4%W7|VYO~C!Q9p-k#2;AZ-rcua<_57i^V+_cO`c5_Tw!> zvJlmuU>jJimtH8f|6Squ+&139iRXH ziysVPLqfHcbhkI#8k~|pZq-s^V~W4?`J7|BXugs9BOa?dIx}A1-PRGiJx6LiAT6~8 z;y?D8VvDH*eD_v0dlhBDt#xLJ&1me*rZ_@_xs5tDYj`l3-M3~cGsN_nBwkiYgiRGH z!n;gZW!dEvA)<|U-BMM%$>K!@ zA$!ils-VnfTg#_zQ8mD896nYZ_N-eQ5brMAL?rnKiy+fp!qlEbxi6~jt+ERYmnJ|W=SD%KSLqL>9)uX#_pOG-D$>VT+bfA~( zUQx}F)XHi4lp7w-Mu)RX>l}uA4pJFY#Dn#56v*EKZ(v9b(C{U zuHEoeQ;<0qo^zf{bNiy_$%ir=8+j*tSkqdwgCarq8 zTs-DlmRL8#>B^@n;nNiZ(g||z`u*n)e8yqot_>qB2aFvu)47_#<3}S4yfX8f_#SGk z#FXnUfG$1>k^3G78@bX(gNn?sswBL;Bkqe7?TZCVO9OY(EI%F$cT+yus2r;#?kB4L zqVLOU`9={$=RNARIHp1tbI_R9O{aQu3sNXcm`#MTSq6rztQv!v7S_)^F4vv-+0rO3 zu`!hPQ4B*B^}KHn>*-ntvN++*>p6OLVEH2cRH^fF$=piMJ92Xv6h7+TA6?1xfb(n zU7^>{Cui*aMQZ_mf9*%2vv7Ay9lwTk&1UAW&;Az&Hp_>agXSq6-$rxY&9QSlQdH_& zb2cys-jv}dUR3gNtB#imS6Il(+_kpvo2^v_9ARXTGI%$V8P1<}9`QlAbZ1BAbX#1> zCS38$9SPAVJW=r#R}qAnQD_diz1To4MsvR3uqe(;=np+_(R92wtvb)z0xGNpYw&n_ z+|t<+FL{Fsb?6TzC36xNnj&U-_YO=Wq`9p5Fl^yO*1=BwlhYg@9FU&fumpoY_b$y& zb_{mRd_ReoSRd#yhtjKJs)5Slt0+#o`H_ze$wVs`h_kp^f?>h4tIlFq4wPkPha2N! zvf4{E!oOCS;TMgEnh!^hY#Rai*gq-XKHGs??!9gjXV(JWJvk=*`cvRfBhG$~ ze|;5JB%@K1r1ev=N+cG=bmQdrcAc-Xdxo&tJEGFicZ5+G zQ*kA8xT`6~1WpAHF&W)EcM?mJUtfp?-gB>LvDit1$0CRAlUwzfBTY#|LMTX!nX)1? ziJv6Q<9N#uwLX6Oy#7zFGczlXaxsW2`W^FG5P@t|DtcHe(dwr!hv8q+-&cYLpR_tWsWOUYi5l3T=!ZNRNZ zaQh)3m*pqz2mjMIzLcF}MtO1TlZ$!M`{s{#OXb;qv~7PZR+YMYq5}^8l=-Vk{|FFc z%uP@Q-8R>(T_@H~izmrEtxkR47RYdpXCb>HZ3g#-{>m^bvAoP%CLRZ}H_T~nPOF7d z#xD}wvyF^pjq`xYx$ARsiMGwonX|ZfipzE%yt5;V9lu0e9BYk{tYZzM+GE(MSAqf$ zKz#P-eZ(EEMe=*PkzgPft`?N|pSQ>Tlf|-xGV)QTO%E;u76Ryda6=_TtnZ7`KOew~ z!}YX^(OL_K^bWH0f2{Jc&oDI*5NKI&Q6eCOz;o-cejT)?bkNpl8=yJ1g;KDfh6fwV zaRS-c@!od zz#IXW24{u?s7_p2{HM}{8Te_lJLMbGNG z{`?)97Cx){=JP5&OyNpfDYzHU|2$0j>V(ZQmB$*#e;GqH*Ws_Wc}E1+=&{PW9>)P0)hDn2 zk^98qySv|Ce*9_q?eaV94|^^Ci=*wxuTL!rk6jBN58JHv-L`i&iJfIUKn6dmKqcCl z+fGqkN`5I6E<7BznlFg+_tro~Bs_>LB4x7rILFgFwaep@e;Or=`j3OrXrKI(73JIi zEG9#cM;^JueYGVf33|{0r;@~n>a=89m9u3W49Z!WN7DsFeoy%y|AnpY6_&Hwh$*Rm z!$#pUg4O<3_$*#N#xoy}M!k z$BnbkuWkw6y&{11ABP3!<9S2=qCxk+WZ|^>7m>k#%VEM-=>7wN?%#^0%P`h|1@p2! zmJMW=4a0Fbb4e}2NlZM6MX(FR{hx0g|7PrnMY`_aUTu=U5X)2W{0H)Q&eySBRl&W; z|E0C6;2hR#UFgsL|FB-d_!mpTl6Y~<)^%Hc^4C0fa*G%HyY-j7y6>h$Z(i3|P@b#^ zeBEWU#Q7cz?`0D`PLpdOsWeNnfKc?P;%C55p$x;asWS(r60EGl9Vwre#Dc!!SH-7} zGR~KOjXw`lSPWA*5K{=yw(qG3|7XX|O(N(0O__v z_2Rmc$i{skaP6#hol_`uMMxb?4TKdBx=@tq(xz*xdAvaL&G2!~56zuna7P9XLs{07 zyz_~LQm+vF)i`MIw|wPMA51K`e81lgcSl+dt@l!%cya9$LNj@yTW^N0s6=p*|A@z8 zFlHiT#w&dh^f%^?Rmcvml24%G!5m7RKbjI$5#=Tc`YKn|C$B4$Eb^49!W#vsLK%&y z5tk4?YoP1luJOz$bQ^T}a{0;a`Oop69?|Dhi-}4Qe|n6J<0mJOP5X|+xI7PTYiiXn zW~(D9XRU2kW{g3Bd%3;?fA--eyDaBKTJ5*pwI~})OM#c>Lkg{NC=sh{n51@EV+*2b zaB($y7?j1-&5b)psvgb0rR|Q}0?f?fV-ibXgckWpgUoZRAR#K>g6&&_?S}mMyni)K zjs>e;l;qoxYeo0*iTMeGf~Y@o^WU1w4k9`{FZ#LX@&5F9sSv8&{~4V=nfdiC_{TJ| znecckq32y!We#0y7S+Z6>E4aQouOZB{ZvZgsd|((6WoU*ID|XUXo{st3R5n=-gIwsvvS|-!oGgPv(7{VqM3isWv;Z1$c@71v9RRK5Qzd) zkF?X_0%R8GW!TVcfrW)&pfrIZ0}G+EY@il_URn%MIU*7rO$lsfsGnf8=-YyDW;PIY zhDaMe+yViENielT5rZ?t8VwnT6&I%u7Zhp?@QLDitokn zsJ6O4p|lO{-RNpQcFj-LT>>!hx(c5L65OU329?SK$|j^Da1PC*()WLTxVn4zluk~Q zWy~L~d9EmVE#J{CmisN9PB0_)Ho>i2}FThX9F#20X^sj zp$6&4k8f)dHwe4+; z14_+BMh(3xO<5VVfK)E;E!JB+p|&_b#hbE>Kd}YBOT8<)liQR3l(FDSlgn9&vAZ{~ zw~3{O5)c1bq3bpW=3y~s4`-u&<9(MLC@;`Mk;<;JV$`_JlO)_ARdqWEc>~JavBFT( z5&ZZx9z9^Os2bax2N4{e@|H7~#6JK+fnqjtCDzSND@D5Ij}y6-(PQs^&+Uf0uz6Cq ziHWD-NdTWCYnOU%&2mX7Km5squJHUhqN(^@m(8l)SP03iDbEd~eG+wH0TNG8^F&uq zSF%4Rnn{v5D5VLv*i>N8`)u55xixQPPfNK zlSBhLk~2?re(&6cWB>F!f%XqL?iAlG=`h5BmfqY%rv>5CQmp)0^ixXPT1&NfuV~6g zt~IA@ZPhKys(hgy@dXc;EN9r3jg*!IRu0s6nI#0J{GFETwU4(EPDXw5&*yI5mc$X* z&$_#fQQl38GWgEHHMgBbQ;S)66&%gMu7%6)cf4Ql8_q8~PCg!COLR|oG~DP5K-rJY ztxRG2=PvXYsW{ZkMYu@GmzqY8-;ITWSsVCbFQsva39v3E8}TBGfo6l_h|Qn;}u%%CQ*MX-n@ z0Ya};BD1*Ym%`P~G;h1p7%#0m_J7ulPAe9@+SG(HW2@&2+Pr9nrQ>ZwC>GtMd^$=_ zMx5F=#m?FJH*)k{2IX!JpIq*;uKe%2;%)#BzyVoZA{sZp>R$35Z)-x;iQCKgsmXxF zwm7H7i4Qn;#Gj$IM>03b`ll6RD;^F|gHs}~=}Wl>L)_TH@qV3!ZR35Jou6>cDovS< znzx0j+g6rOnh+sGgbN$LU3w4))Y8(@{oE0uqY0yZb7AYR&2%=lUOxVjT_FEBFFo90 z1>D@`m34A?(T|~VNVB+Mkw6MT%X8wAoXEJG^8Vsd?vyS1)Aw=JNleE=(F?cAQF?!u z%1m{G9*dU4$W*mzw-F0kK8NDw)??M2g7}oTpn_x7)B`MUE#?={TFka!>qq&9E4?qn zD}A$eTs6EJ8O?dPvAiI~0(GTPogLHO`_{VbVkqji6Fg^R(&=eSaaJ>R9JVI?z`r%9 z*y$>qVZ+mWk)v@l-FfKwM&bCa{R)^+&2d(!V{dk+lOjx#?<^!%N0v*Lm0x#W8Gh1hBOS=C%xQV~xQSH&RsTYaT+ zb~!o_EYfR$|8#!y_$T*=5H?_0+!xc3^ABF%rvilGPc3RcHaH}}ZnSk_f$xS8fo@I+t<#i_Kt(c|G>aVegKMV3v3 zo7jThuQP?Aw}9HyI6-`cGp%D#G^sW2)MDLlC9ctEa%`dc+_BOWkps1C!*KXajcFi_ zP`O}pM{NskA#3d-TP10x!O}FPtmL?sLSEUHGz@kr+Qe3K>u3`&!9)kC8@uoXF~ea~ zmX5QYi%`F7iSdWrDPrHU zd=jQ~F4VAW(!NwqGjwQP03gSz$G{d=RB}E6x;kQuD+Efz<|kA zW7*Ylwfwtr`=`ox7YB>SGBO5d!B}|#Oa0ZHeTBcb6PBktG#ez0;U(zQO=QvlqApW# zH(wve$^eY!;ib~K;RaGjHJLSv+t#F{NP&foDtDPZt8%u0J^mVp%$^ z5o_vrX7cohO+Uyz)xV-#W*S0m05wkq_dDUkX*U6(yMbBT2 zuPN(I*d+SEJ9BxFe&qwHXumA~wmrKhdO7li4i(!=Jqrt0@OA2zc^2=beo9h<0lWTr z&gDzw*%!x`+&lrXixUd(7ypEg%PD>$FBXJoUG~QYmbyf`v+|~=QdBwt-)Cz zLc_79F1pIN^Yx?4&avS*@9MVWX1xqX09w%3b03pef2=Vkf zW^-GE-C(ztVh&PLHjC+e;-D{`qg_YW6mHG$b)3=62q=zMaNs=Y;o z*SmB6Er{!~&Pe<59J+g4b((v|tr{$hw5e3QZbx+OwtUVg6HnOR>d$9F^z440O#n2t5ZMuA_+2ADVByLdc*OSS8Rue;bzSrKy zQ>!fHGm(|i)8iGYBP!K9K7M&J0U_*JPZK=@F6b~v>FdlE{LvcpYwLMv%jbSW)3X_x zyZHp$uJE}1XP2*<;88eMm)v7@^Z!s+OZHQqz`Wr)Pm6BP|LGp~@{*DH`-;MSQETq# z^5Sx8EB;_})^Is^0(QA|`TvW~tAtNuCpPDcA$jDv)oiSTX|TEn?TYyL%3klx1*6k0 zudFU8ZX1-ZsliRR$MrTM_v3o*Y4l~~gc$E^j;&=*sk7;#t)hcd zSM`Iz$u`_Uv9V3rJ?qYF@}E-%r&^$nOP>U&w?6gWU4Pz~3~Bx1MLlN8|46!TQ;=gT z^5A(-gd7YYlH!UAv2PE&fct5Va!W1xDHS^<^PRPpbZKELG1Pa4^4C!>!Oi1WECq*I z5<`3d=9w?thTHO(vm3fcnfS>X?#&;L(ii=o2^TpLM1;agNdG8(S!)@7-6VgVm^56KEj^RC5yth z+i=~oNwYNxcsiDJWi(WjBE-8jahMN}EG_S)c=nY?A~20zs`aO^5tq^9*ywG4 zrwT9Jckyp_JR)YFh!)cLmB)k}|7 zY_pK|ds3{A7>-W^!gP1grG&AN^4^8=qFTKcaLt6L9oTMIB@su4fT+8>J1(kOL~_Wg zZ<$1bc-Utps=a1-lE38m|5SYZ*g_ZeC7DwiXGghr*I_Kom1Ot>H1QZXs! zF@qtlwvOU?0Xb^rb~)Jbx5q9+4<}SAoNl?sF#*&!7Qp=!8aABDc}%x053CuSsjO0) zwkM&!iGqzVCxmvohqIu)TIT&m(AT{;I-}|g)9;Iku!)aFRa_0H67PzouXyR!PTWdO ztCE&Wx|OGxwr#89iVFurvEfB6T2vvAw*0!=zHOF~k`%A@M+s5a-iKv@gY*YfH; ztgq|sOqGQ==aO-VoM$*GdrC8B*5JB!UDa=kLmtFPl&(H{K6cWfqFNs;oxoIJ(I4Lm z9fY@%Y8$V!n%&>3)jZZv#8<^|c+L|0^a#+1B+F?BzBtF&QGU*fNbYdrpCBaG;3^hL z$Dk46jL>j3hE;XM_EfavLHw44@d$eCSNP>llqvPSv_=P4!YL{O7;7~Hcs37|&yMJq z%~LP&cA?65H!y7Kr`&;2*2Vb3%X0794U*2rGhUjLJI_uI2G1*5jNnsBOFq}*av1fJ z1G!*jQq4rr0Jv{d@lo+KLP$hhXfY{Z8a}Vo3Z5_~%iX1SsLUeVn# zzgms=W;-pBtQNdwkEKbUT^jwLxDL+!-ws@`UW7F;%XAEqc#JEWle1^ulxG}yQtx;l zy)mNMYdqGt6)P)?Hym27zhUIfRouhhy$K>0tuZ`}vKQn$F`)T=%v})BRhA37T;qWb z+YP0pOAaOv6DQ=MWV23*dVd=i^`7r*NqYS%q?yzi0Y={ zR;bv0#DV1;Ji@`V>Ua8*wzXsYJ)JBk!)E6_os`WtA)i3y@0+n&sQYwIOs11?tq=wJ z=+ed!g{AixUP^RiW4KCk>|fVbzdOgKQ%ESR;Y?`uAqxS(%TLMg)9MJa5!Y zWc8yJ5=)7TbKZDKpHz-H7M3Sd_L*|DNeS1uFcTWFB^fh4Cul4BGN+-(R6btJN*TrIM;VKu?fXWJxkcfuz$ zOyp0W#K#hJh~{PtCmNKSkt*UHkVYDUSKb zKk`kPv&lS{(Q_W*`AI(`KA0AXCE*^soYBZ!clg5`MF9(nHmGDBaaSSL<^vJUp6ABH z_o{R~V)f6k;{4p}y|nlY4e2h)j*lo`_u$!he%w$MciSkkQ+G7wE7By^xDCAE-Pf_5 zLgk3`5B1HvMD)v0Z^RC%m)mVEq<8wuyq>bKy_KxDI&u#aTbac_Sk;d-$987C{btRv z0a3+mwVBBS1w?}!^gFz=RbY`I){o4yJxU!r&K7*hjbZE#+TT8c*zOpuxWUV@%N1-V z=BcXYYOFB-fGkKGIn-&K_i(bi?P9q5^rK3$f+gMQ+#NQ&%0}bb$!) zG9jx9Ou+;y)@;@rWHuGs!l?HULm*pz2E)PGZeH4QMp`XFLZXk))l>d6cTb((GY9<3 zRCNEY^wvW1NZZeneIIVerj*RKi69Y`{+2+_wF?Ejrwln&A6}zjbFEPx$&qQ zp{qV}kJ;2ulTKhTIo7y*R}K-E|Ni21EL)LWV|)}4k`*t&tv5}I+Y7rla`3(!?WpNa zqgXT5((dYtb~XP(Lp+Hlv2m%%tQ=}vSYaAFV`FJPy$I{;kTjC<2wA=SZ5Et%U1vY)xt+ znkSiD0~(L_RSt>7d-A>0Sf-kMy+ehy9uV&Y#r7sD;o-;En1iwWZY&^?cm+$c@HNk@ z4{FnD9q(w&v||rZ-Oj-XWZ!X&1+`8i7(c{~_}y6$pWBD4FqWoZu==z5GPqPnOnMOQ z(1}jvbY0@q{yLHs7a7&DrJ&Mm=$*o<1AqMfwrrF-8@@8Kw6Zd?5||W4UHpYINEV_( zpkPC1E+xTL%p|K)0`?loQ9HtplS7@@%fEJ1~RA>5(Ze!a>Y%k;6B;icw}_ z7AER%@W@hSGsiN=YToG@$^wJd03L5bF%~73p{w&IUuXEc*BtoiBoe7l%DQnvIy+A% zOxfP$={J7fI}=_jHWtE!ry*Q!AgYUtson9}yW3Bs_D!VGj6Kw)(-oEG4%(xEas^G+ z@8a)KE3MN#i2K(I2Dj$Wqz_hri-6UxXmIu7BKk>UFHHwV<@@Zqn!e)ns`sfdspRAiiCs8)!anB2P$^|B zT62h&Hj9Hoaa3!AX>{N}%IRpfl^a2!-^OKR3Fzr0NHZIh3Fc%79?inkwPXl+2nbb_ zX9=`;=(*@=7Cda@<#;L%b&w$q6gLLqWC7>?GxDf?_R z8_}A%{D9_(vxi2_%J?>fOE?g24hPEs44a8`BUiWqGO~OY=#-LsfTuQQNrop2Pac_U zKuU9U4f2zMoF$#bk8CyQ&;bs?;ok*`^#s53^*e)h>m&xMtCZq-l@J+I>j6Xf&W8#p zAz~6-p~ym}CFv_xSDz7|t={1};V?nOwfJ-)SV>}(%fvcm3l(QmhCSIhs@4ts9T^J- z*wd*{Q?Hyhn(InZ9M8>37HN@|EQ&VE^0`s2)x;1Z0`bYgqj$!3%jQZBy*2bh%Gt<$ zb>v~m^{isdwli179L;UMR|37B?osl^J25wljeMEm)Js;bgkQ&D`UN>JNqp8Jl>9A z43#aHf9GV%F{D~}GAlksM?BHh%e}3>j>nU`g~X=8*2lp^Zd*-blsR2&=0OL=bUAkr z8e?fi5v_ImkUmyh0((maU$~I8H09Vb-ucEij2Jqd-I$(TUDS zQ)@WbmbgQ!BE!j4NGy*AMNDQv!4Mt=MSPioRGAh9f>gMq#5qZ2Tv|nf6lpLQni7~d zaKAZI>cBL0h6}!rKqF2AiFckmjv24HR;D>powu19Nqrzm#*NywFs))t>#|67A>Ix)Gzs2HjdT-Bcnyo>SxW|R zDx6kQCNHwY+>Ck_DfJAEqNGxCYB^3SjeK%H={tQ%aN$Kw$tat?!BtXHlO@WL$P$v1B9Wjd6s#zzSW6VFvf3h`sDu(y zsbGnk2$Lfvi7K4T11A_MDqtMUh$1MeXr@S6Y=vqph|;Z^kf;L4RF$M6DGC=W zF{VnB2&E~^%5sPzq@v7llL8i#B&H&YtcM_?fT{^(axs@M#h}T^q0GpG8f6LsVaTg7 z2AUA0N)jYW0)Q%lrc5UZMuQp1XK|#M6F>6DFq4;DG**1QJ}(CAfZYalqdi)MuBossvOK|f?Ui>gKQyKRCgb@uUPEJDP3qwUUSrEkGjuGE}{6wB7 z&)ey*w_trweiKX+XNZRx4N?UKWvWFh^! zY>I^f>L4kD?0KfC=l@ZDcRyzQAs8J(__y;`WLlY*V!DqfduOft&|b_#?VnNet=Zm1+Au zPV4TJo1A?x-Y@abrpKR`smoS*{QkM|-qoYt&SFXzEPq4$;tCfEc=soUC+Y0;R=c{C zq1GK7n?DcVKihpIACC%DT>kvt@7}wThoU7vy87YV+6GP^4@Zyr_Vox6i5tJtP<>7F+k8oi6%XnKm>zDO? z9)@(jblK6#|HH|Qr39;G>%O21P1Hb0dT&5R=QBMa<|*tkxiQm?UKL`mOS5l(GC z%OU#Gcziu0uXn~2iXYnNUPZUgJN*~pTg6m%Zol3h5%he~3G-jwF}A*TBwu;{GUMrU zk?)81(g#wio$=_hy%w&1)UV{p^+Yo>JVJZ%P6%nY2xpn`{SlM8$VF!QnnF#x`piAip^jRoxI zZ@vVAFM1Ou?r6l|>HcF+4Na=9B!waGzO1dQA0GVufV4gB*?Cd-86J({nAtsd;BgCV ze}^(ycXl7E+yN`=0nWSg@`Xr8pAvjO+l2e!9fSzNa)?x`g@?D?~_u8eUh3f zOT>94T$=ojD5&`Ey`5jC1n=+Mym0u}qK(+@%hVqu<13kvy01@pSD-brdJ3ES%);Pj z@NL{LX!g9IKFFuH9=0LV{O@E5(2tM4pOP2ei0W{~YGA}i&&|1JJ+h7#OVNI_`%Uv6p@g{li<47x>aEGx?j#3h0Gh`Ym*kFjtezWfI@lW?ik<4aqlKH%sed<$m zWM#oYUEaWl@^py%+2s#p-^;Jp+@bc}=bqQ7d0Hc__fe8+~rKZ=i>b@QmdwR~LM`hCupB`@r;*K~dI`r>Qrhp&0)dp&WN4Z3j@z93Z`+X;U>~Bcp7%@>9T({R=@1a?q z3-D--r*8=iherv^h+V3!VAr;Und! zwbVRv51IycN7PKdUwd}9UVcXw(YNJm+~%xCtz5pp7b1t0CwGTzTCx7&_l;Obo?-9d z{HmT)aFCnsW#u=$-RL<@^Y2ex`Qcy^?*7)#ganp1nI=rdqvGQq=u~UmH{WkuV5;qg z7Jc-KTcIu#De4JnS(z`Z-ojWBl1WMRm-og&YKZis;3L}r-S3d>S>ZfaZT%x<^F1E= ze(07J-4zreF7F|t(ZWVKIi2=Ox@UN&&T#8K@iEz_dICok&z@GVCdYQ=^;+q0L9qNV zfcMJc7Ng4{uF0a)Y*V?)JJ?s9I$tON6MU>5qJfzy`m7u z3@Q%^&2!}^8R>!w^qbT?AL)D0lkxQfrU~a}=r0vT~ddpF}(TSM4a*)92jdqKETDJ?2k%lmY3bkHBi!2ItF&ZK1>`~8%`8jT& zbLMe)&xa_5Xobg%tu~x_d-9z2wijn{n*#MbpKQ-jDbEmT@pp{hBY;4BfaLO+{eKy( zHjH_;rKt(io5ArUgX zIyFhB#?daYLq9(zJR$u8N-=pWn3(ZK${i>9{RHOgdJ01|e8Y~Za@2gSd*E>cpDguT zFrip|Urn z@KuAJLN}*lPHmWsO)xsA=?Oz|q!$Dd{GEAHOUtpw5W>|e5C{YY0IHvv0q)d#31J^> z3>+*M$<2lIk58#Pyj+Z5RV8$!aO}-<`!#laju3qC!1T+FJRd^fe@q;CCQzvMEn10@ocA@`adFzE@Wi z$FuGo!Rch*d+`sX937sSE|XTg+q<&~tCsa67$yO<@Y`O_wl5NloT83*hs4rD5QL7$ zrt)K%{A7W_eu2EBcF365(_0a@wya@BE3FY4I!sWQuuUF=x%wT8(dZHx?d5Hi6Aiu3 z!$b8~Zw27}Za5CpfZOPW+`BuKo-Nx9*f8`;%igI{Nw*?da~rQ68{3YduyXDpU0qYg z+j5F_h#p+sdv4C0Hi=yJ1+7-@Tx6rPquSiu=4TEgkk-9?-kS;OASd0RkSxD~omC!}AcQXMmOQ>iB&&V5?3A0&ejk1rrG&G`uN}_k5^#*< zN#Powp|3i9?tqc(w7Q-x$TS+vFeM1k!mZsCBg$u%B;C0T{E}s?mN7nbsHt<3B z)844g^!)h=@jbl0AqFeMjrf?zI8-vuN5*?{lA#Z0L;YP-&T3wsf#*BPj|5-B_%Pd# zD%{_pyqVKbsSAqzIOmZ)ai;yed9Cp!F668I(`)JwT_EFhMkS8N^u9um)MWFja?<$J?F`e6r|$xjyf;K5uWqu zRPdAP_T{T~yWZ)V#BI%}XCKRs$oS|H;;Y3uWB?2?=ZJ~{eKJ{j8zX^~ToZ&L>F<65O+e?BNsk|TI> zL{qk2=O%_I$20Gt8acjm1Uq}rEMLQX-z3i1hPof#`|MM%Jrq~i!gqgPpXVdkt1LWw z#(js&Vp`9p2Nj+(nWfJ|5hh2ywO_l(M26`doio+6!zOvIt8KitJVTxrQkIzP}a)XIP#- zu#pH>&4TKn6oQv?)$)2J*-Oe|ioVrQjkkRgOgxaul5BHNK65wK=cJFmbLvCRyRNOM z``%5nB zHQT*jO?L3i7v^t)z4h7J@fiMv^ce$~IqddgOy%~>NJ;Ooi3-a@7%?KsJx+#8=Xci! zNo~Il?BsXd_D8PN?B}1;@S7J;#TK*WMH%xHZc2Ar&il}Fuc|!{op)}O#9Y65yv7uH z5c~-*n$9VZYyV~$DmCQ%i%y*-jY1g3b|FaHY1Z` zdA?Rb_jxGy1k!WS* z*X$7Q_aAv@%N42l;+kmnX4-+rK0J8a&p60mSP1SUh>ar z(c#pKkzZlxm+@a$tn#F0o%OSN#x!Cy`Fi^=n%g@j8ZOv#=i(;cGGX86m@yDLdnOTP zIaz-wseA3A;V%*J?_mefO7_ptN#$>y_s5p>`>LZ~Z?NdLNuZ01Ii^QGGTKLWgMy>S z+wc_|vjW_>Gg?JI4nEh#lOv~pbpgIg&Brpkt06t5jCavKt0(8|`)Kv%Ui(P-tyt&Y z!iv1{$*}lB9A6HHZ4qsndO@e}u6CLo>>CNY2C8R@lpN%jzIw;U*1cVY>3Jqw#skpqF^8?!h&D%4x04GM zbnP{IZZR+rzH!vL_@QG?Ocezh{vf}+hw-EQo^E}SY`|yM;Xgc}iiwEpa6#?A zuJS@0pi}Mn{)wT@SDI-GQRMs1<2H{<1aHqz4G`mwB2{<3OMR*Xeln|RoO+dyYIk00 zM?(5N@uK<>#n~ss+n+aA-RI6W_t6FMk%sFQUxhNAPTm-48LmKewCSR}_)z}H;3oYe zHT^k!^Wza@MV~J|GB^0|A*2o=+hx+MSKB_kI$=4hnAzt$#e8OJcXhICL#Oht1FeY? z5t)-VItxZ6GJ~8?XEQhvP&c}>ki6P%+AA3Ij_~}p&USTW_Cr>`7KL_V)MeZf)x3JH zyOk15gt3xQn(p}Qw?2Q2Oh3BgFTRLAMt7He@mZH*RCH{;2;Yr~&o^C>pKp2jLifq> zJ0g&@aMRBlS0{eD`CDRAuIeiM;}Ck zG+Vj=^mC$Yp<~9m9Wd(WUEru55((mzRSbXxq(>o9Ood8BP&xPZ^v>?veTCnvw(i}a z+*Z|&YKsdczlw!*=wwVq!=YymX%m{v$+r)GhkY;aoIN|vdg`w=;gKRb9^R8LO{0X# zl|qIg{&-XDk=?nykHJeI=n)C(8`#+ChL1bq`bC`Q!OfGgq4gPa z6>+5Yty4W8UY(_!jeEJ|6%n6j*UaiZ%f?_Y&h~uCEAYe&e3X~YA`e$NkqsP*d33M6 z6~7v9Cv&f*D1S=mdoZ}Ed%`3)R0$4z39K#C-KH&@#qee-EPX3nRr5){1buJQ4Nu{vY#g*cEek_W_ioIt1Xg>_*!LHQx+*Ebz#(c z>nkjy#y-3fraC6N&%NJse0$@LgTyKBxRI5PG)q5WXA?S`1~UtmfqYwa+e_7bmpSp{ z+I;m&(Txh0d>F`4MLUWYmJ=`D1~3j7uQ%s2S$T5h|~;e zW{YH2h*FC_XXVcem~tZ^vm;aRK>OKeo>Kb6vFoBBezvJ7sPSj65T}biRwcW;(3D5L zgIN)!Wvnu?WuTU)$wBOU}lciEH{wq ziXr}qB^mIY(r47Y?sw0z==%}sc(UclmmyTtTJ|+>2*fWZ8*9$^f!DmUDl#%1l~O72 zrYTY$#>V@i4~|O(Eet0dp2vtwJ9IA^iBZoOgDoeu?>|ipOG;Q$3E@K_boSDLCzG-e zjL{YHmC0$VWw^e8v*@QT*xSvT2Z=TO`Z#)_YBM%H^u@iyxm^yvr-z%mRiAs=@m4`L z%xvonG&DPH+VSu)lDcibweIfj)xV$1<>dS0@4nZjHBR8f6}j&FyH$41rssPW zSqti_g1#l`n6?Pz7g;ua_4Iz&nrX!7q}Yu39x(A3-h$}%&`edrTWTWJ1!+H z(WTrw;2txw_zQ_2UXG8vbEc+rYVwDn`yVa!vK^yaH8X^SoQ92$2uGXKo8ahu zYtZ2041ps)j(6vVP48@C^L&+i#q$^AF_(`h@TJ}gl&!Pov&7mdO*8C0IgWP)%5f=o z&HRbYV~~B~ys0myeEnr^obJK^I>PR--H9L1Rm zF*Dh^$BWb3t@s+z8n!zbOgg`p%<)?HO>!F`IXqukvgfiII8Nqr)0|&N$i6i4`5HPU zZ~IiovGCu+`WyFW;y_3V6Mm{8`Hq*oB)TIc-d6dA7x!IEE6w@u>G_*sLPx{1 zxb1MCAhzbfA30ms(O-CfzTGsTT7tDgZO1KUj)-jcltCT0;v8Qvq$ zzkP?Y_6M?$xOwx=xijK=>*9Iz-;p9X`(Mw<+)3t+;^uvgwEujo=!ueG8{{(wvwZdP zDDn|9SCO#F&490_wanr)VT*&KzRGJKR*o@#EUDPLXKfnNjXp+D5uSxNa-p3lX~HDq zcNIL|#mdDhJ{a;V>EKZ($HQiu_0$oA!h^|R_cYAV`xU*d&Hnl26~01; z!wwYBfrM8(tMm(g`p59S_tA10^zNr#jaf6ot=MbXc$EJ0#$>#=*O5vQ<>7?PA6Y+H zUtD2ERz^3OR+}^B%(#_MObPIyzmkW)ftC5gLtH}moT@zcQ>44@@Jie5`#ad}_f#*D zV{H_DiL5r05@41M)|zgv)k?RseY zA3IaJt#tUL-wud2HQ#5!LeFCGgs+c^pQbg5Rp^fKUp?m$c2J2+>vIe~9Q3X0@t3FG zXGfc^>CGZrM7ci0w|#aX@+kB1=OnUfzEcK;nkONTy3}anR5~@%DNy9q4U` zl&Tz+_j2&=LnLSOTg9A%K0ENDtbw3s`tiQaG$gd5pMQGYM)bs<>sxns%9E^3c@E{Z zA03%gAqR!v)O)e>g@tsJ_E9#9S1|TORT3#PJbmgBadshWW^3Pz-n?Yx$)k76ES~cG z4mNn^`{Qmk5mOd;f-CKd$9UYwWH^a)^;*YHVO*+Wy$j^$+g;*FLetRc-TpCo zR0~xKX|TEbH_{(gKiNM`9}@!ywZi(Om>)bT67lxWluNo!cD_CRuvqEQY~)(|uHSnE znI>-BVwsYqTi-P6YQtUq+?}~-q?5!x3;-0;HYawwv z(w7y-u|p)xqWnV+_DJP!57O#nihQ(`=4^FxJdH-%y4xSoZw~bP_ke{j_r8|UUH3jn z`q18JiZe#k0Y!_#no5Z0J@P%b^x8;@($0JO>V2Ae@P2+WHp{)`p9zuh(dF|*H+*Kk zwfz`sr-)B58|oz(If({);s^Q2#U8RIo|Qw3>2`N^?)#-H%J)d=$(_T-x$TkNoT7(d zSy0N3!*C+^V>g)e_192DTAbI^_~9Ue9pyVU8&^8c6)eHGbWcmRLr+7O-Ip@@@tmsQ zw3*|cI%aCR+Kt=;t>AbbdGhM*N6?zK-d15PK4~)`o^{T>!xX#T!>&QC47V7Hts%Ee zvEvJVmz9=oL&*W%=DA8MFoA5#Y}Y)(Pj{VMw9fqhyGu|&BdKG>12D+IZ zL9EfHY~K5-?mDeYYdBl>AHSG^#m7EApjjk8bE-xnQJz z-=`p1MMtYWFRxPPz8g#?$8%erdb47^VOI2a#SENpyX#bO)n^bByqhZs&V z;SllX+A-N&!l)SXT#ZL&95M7=C2@nfo4?|=Zjc)fn13I`L{dc^)ZY8;p;OFY>nmp) zBDTWc=Y^YtJ6yX9g*Snm^HrBw+%I1x?&f67qm`cLv5Hfo3gKvDtC-Il zeHS7VDpf3L@57<}4B}_UCtF?=#k;j$ z-ijUCjWT|#rtBgvGdS$ER;0KHr@ogH^UB`Il&=mnT^`>}yt;*^y0|CiVC=@RTigfR z#5Z~Fo&01sZ<+#`{w@TMq!b)gQ`9+Oy0pWmDrFxPpht~gfPi%ednmkmVa~W2AYz*{sxoqT4 znEJ_sb?)}7*v2xM^1*p+cI0JEMwg0As8;SS-hyUc8lF$OIP#34^zWhCR9eQLd>(^t zAtDKh_QYq0%WE_YskTa}2l}oTeSaMi;(Z#!=z31OUsv$h`nS{QQ#yjhukiJNB z-pP|U*v3`SUnLW~j8XH9-NXG{V4m)a&9joC5dTa8BpS|<)7Pt-Mq!^_C-FT}2^tJv zB>>t|HMSV2dnfMqUwHaUKI{sx4?x%=9Q*Hn z{uwhd;&r^~K+=|*h&(zUj}Y4L#BF9X;yS*ZFzCs}WQkzMz{U(X#6qZribgxMh0lg*JKp0=a=wwuE#m7t-S0xk*r(~% z>+9y%SK~OX41MeZZ0NRFldpU4nG2OH=%ff0hf6?x=Wmd5YY55qZC}-u12uef(S@T* zS?D~22Gq^5;oQ@nndL9L)M{hxCN>*{_&D=M3&I?X=rqr`&$4~zZiVfL)XvV`yRKwQ zlgvIkbY@@ckMfi_uY65DzKf=i&Zjn8Ne3z3?KED5{Bws-lr;3K|Njf}6tv zl*kxKa!iz@Xj;NDD5j948WyT0DFZVGl%WbrDWHjHC@4y5fQg7HqrZ;Hr5=4VT`tRK zb~oRhE7ozxh>!5-*Z&SGt2PItFGy7-e7AMooP|SstP>=@=_cBgpRPBO4PM>92(K0{cV9gp8F=D7Eh+f<_WtRDK0B=jBTfWuFq`Kn?l6G_g@71W-t`W? zT@KfU+$db3?OUmSd=I|MpRnbtAc<3F&%=H8yn-WHLGlY&k}DhTQ1dzU$wIMGbIkO* zU*CE>FDnag=8?}|O272O%1RAXPB7G5tusKEzaSqMiH z0|H!qG#Ehe#HE*ptjkWI;9g#)!s^=XCH0Rh73+-Ho{(Elj+lnIqP^|A%^-Ec^t-;~ z`LN2TuaMe~PoM=N-6$t4lFy3yn-ZCf0LvuyN8Wo-gAPZ`N7Ll8P8@kx;Fs(6FAcXw z%jy<-jBgaq{GLP*;ik|-V;d0-#1Jq|Fgn*j1Y=VY9l54B>BoTqJ-_k%d&1j&k3>a_ z6p7dPOOM-9eQDscZb!%F50f{#=w5$fpaK`3srHYfvv~z4CDLa`GL)K}c0IGc`NzGx znmxteQFRi-5}AeNVu2$5-?QoO2Yi^u5f0&ih|dr_c~si+k>AVde)@j*DsNR~blLL~ z{_fkCJ?v<2hE2KPYPa>*o!{x5RqH(~T}~s+!Jl^y-z$7?r_b-C&eGwOWiKP-{!HyB z#{B(ElU}m}n5lfd z75uS=s%G(R+#jI*j^(iP{D+ypL7!|e6Wv)p4ho~u6EPd z#9H~@7!``vy$=G)E}mX;pNFYP0aBnF@UX!(olmZpo7Lk^`>;oWHOu2FN5T@>W9mzd zxG8}@ldUwTJc*gEo$d6}R_DUBXd+0tpM_2#@mcYoH=Nyk#MYy)=VLm`h})IkUnmxC z;`iK~P}8}Q5ivDGMn?ilfN}}6MAQ1C>j9~5l4aI6(m%(~zRy210=2@yYSd{$7}zLx zPMxz{v0V4d>)LDfquwKs<1&bTS}CuTzP7SS0x9DZl|chi{!pwucjw%g$;DM868Skx zso20}DUyCR7~+V7XQPuxd4%Kt|w~XRz$jQV8Y`t-U#WJl0CsKj{ymz$D(D&awRNghIV)&NOy>8q`X))$*9z0Gp zi#fwG+g(U`<%D}av8+|LorQA0E1|>7r+9}&pp%Y_xU!a6#yfSl+}?8*-!8wT2DzN? zM>Gt^uQ!JA2T^Q@8fB4z4-zMpXGRrH&k91bmcPD0!v84;j{vXI@=3&&4&{PCdB7S149;~0w5$A zIEWU^-Dyc?Cdv=Y1sN@ti?CJ{Qi9_bu{9L|Wsyc~%bfY=kP>9_m`s_Mmq@cZXH1n& z-W8C+FldD>>;_@WuKUNAVjhoVl=+X@;X7QU+eRvaDs{W0I_9VYg^>ah&MD&ewXZrwxSVd%(x6!-Oc# z4V`-RiLy=|*k3u5r)1>x@?B*iD}!m?x6Nb#pw#*!O#H2DBJ-j)EF3dPEdVut_k)6&Wp1i*)sKD|v*25oO8Q=`|92I(H!okRNZRa$lX*b?usq2((OQ`OvB~ zfm5xrkRuq0UMk%pTGIvRG68r{g6JXwaLW;PUPRU4niFPq1`Mrgf?80aN`g$d7kx7H zL$l_|JkJaWp9HaD_V7ao7|$_CcXoPP$Q+R@x0_&Y88ZVFbgb~}d30+AftAWzNH|m# zLY)cI1gBa~k~m*uCx#TBGJD+Rnt5jWhbTEpfmwz(SVIAoDI}z)3aw;pbr~|5CCNx& z4Xny!3WgU)G_vR!invZ2%LPGfJoI$20eD$Ym@{I-FyzJzVd=*D&mk45Be|Vb`t;Cx zXok!YW?<7OWQ;*E5Mdcq63ooO43S}$V}NBrM1zvCgrSWAK@pja6w<*k<`}^dP*jw( z&=MqMnNXEXp(9}{gi%9DLo~#ZG8qO7D+4hUN zAp-zIAyB|cNd*uzLj(*E)s|2a1WFQ6Ng*y~FcwAxgpo861Vj=+1q%e3I50#_OFBN1QjgIP_(fHER+O9pky|ZfdgoL_Fv(8VqQB~WU^ll zy!d$pX0jq%^Q_}idZQ;dMMdmwzY zyx#kpmtR8p`sDbBv&e?g7Tdw=^%Z0@9|;02I&?$R#E3p#6*t^%7vsBO;}YJL^qY^K z%vh9LeAeR$d9bp<&7p@G8sWn+lQQXv!H{^qm;2}yOO^F}qHoV)jfrEe#@V zZhxuwQHYerA}fA1q|(a>HRsO!?ZPz>j9&2YyplYc#!XQ!zR#oKkE4E7j(cGEzrOT+ z^1rkwps%s7q4<^2c3``rnF-K%}8TxZvgq4DAn{6q6B@TI={q$sH8 zf0Fy5Kg4Vk=Sfq<7FWwaWQLK6Nf3axOnY6^6`ACyuA$_S_kmO13}C3APC7ijiT&RR zm&EyWjvgZ~?uWNuFDBo3I$DSjh|KFeTiKsVS(hCCLgx_i_KZ=HW(iwU)2}Gl3V<~6~JK&9k6#YK2i>{tnpbb zwTS@8f%V&d&k}`UYe;7DNY#Yy9Z}BPo1I7AIPhBY*nQr%zhOq6J~j~)XrBEw=F&X= ze20iUWc>9V=x>Cvmee!F#yhgd=lkf`(o(2@y}qo8UGW8GNDg1iduFNyN>*KCHZ$|H zusDWG#XKioUKc6!L#+3R5^udmWCQ*5ZgSX;7{Q1J9APi0dtW9zy!3ro1+2;o}~cM1AE_trVp$PATd-ju&E_TvOi=N+A=(dT|~SG>RWH71owa zMtUPi%QR(^)(3{^ z(FjeE>WW)b9EQ#D-R13noxH2;s17u-Ek5JK3loy5H_LKx`-@ZG8sd6BE&fGW-kn`` zzO6>4?lk7Z=H7OBrJqm_7UB)?VH_g&#*lqa?fUqNAT)AO2e6MK*S>i|yG!Ez;+tbx zj*WCY-Naurl5G*OD@Q2t>=-7gi2@>O6TUJi3kxY4YKlUVsb-m&q9LT99E8FMj39Cv zMv|0iR+pD=XE}Ked3>uoJZE{0X1u$C_v~1u3EbqBVzZD zn?oo?oNvz_CB$iW)VZf-pyMv6*jbQr<;>-G3*HMw0L-N^AkkD(wAD0;5FtoJ5h)Oe zlLbC5x8shuW4ezAfvC5Kj&8Ae#LQ@j#LYY>jbc=99T(QIrNs6^Bon-f|#hk8sW7_{B>Jas?1e(=S~>)Gxw$M3ul84BNw zfsa^FY|A|4sc%t-NnnB0a-`8*#d0^D1L734ki}~p>+ANtpJ}d0$I082EmEiDBvR$~ zg1w%PR@RSk9J=v?{FKB`)NojQ?+jxa>+qDK{!2%zVED^r^8F0$!U$h4a6B6AOy@K` zK*y$$X6?={9>pJ?SG$aSzc`=pzMJ8j(RZ&S`l4qyZCbPCSW4l|H{{gcY;r<(eiI)E z&xU*msh_Ry!~E`ue#J>#KvEjK?mRu;MXp-<8TS4nG8vD(JBh0IoDuuzZv|^d*QUVSh^J<>$)7e$T&SqX>dWX^!3HnF%YJ#BNv9bZqr({* zlglQzM4b-*pm=f5h<}uKdVJKKq@R2t@bi9!2>h6zzkO$f#VxC2d8l3^hcGCh1E&S=NazE%WMV-#^rS@-Bz;wa%V6$^^sPzgT{lgt@i|w=6G~b zZpRE~eNH(YCbQ1_D41|i=RDE!Nv)svr{$_t9_GcWM8qIfX4o?W7@57}E89#*i1)p0 zd1ek&w?pJUDJFJ!=BTop;f3rzk=UQ4zRGWhd4cv^!Ut@3C+|1qI-?uWNg*$E$_X8Z z5*3lk7gs49NO)%m*C)6GMr$_Cu!0a}GY)ut!>KJ%NOw;(<^yS0LqRAh4G>Cq2Q#%vf) zsPQLHZ5e%Pn|ikvK1IWx+|*I<WlNd=8U*UPh-oC@7LNtUNvd# zdpvUQ&p&*7Ij0j;!oCDvatBL&{h))In=8gJ& zC+oAl2;=67aeT%ch^}r1A3{CdN(Y{Pq0&0GC%y`{4$rK=dcCRVh^3liqv@$?c$?U} zeAoD*#&O7v^n0Htm)|SDeYGZY{9*Mc=uWB;_Phw!_+jJTXE^afUrjj?>v1hvSyt`O zF4C9YoY=SeH>M2t%P7qDqT+`5W%3IIlS3;ob5?jWB7G(z0$Fl2Un(UF<$tXCbrB7u zs-2d*Gurh(#kKVM9$trgMiMw*+mf5P5DTx^d5-& z*WtgE-`gjZF$Dd5`o?0g_z-VlYtt%rzOTGw#mCyKC1ct(dCD$Anj^ZL`ah4~N%4lI z85S>(pAt=i{BEd)^$x{Xq4ZDtW8op$b^Sd>?Cab4{WH_o?z}4WwE)eV5DO7QMEzzhNxDCWc1DxnTn;Q`4U)Ay*$dr(AZsa`DemM0d^=>h0jaaPYei zf&tbq3WZ-fN`jz}-1%R~RIXv}UcUBBi1fW;`+n$d!_MX$?{t~9hnDD_KDHj`KFZ^M zWUJ#yFoyoy)rhmbV|?4OS$Cd%?~X*;uGfP3%_CQ4_|Ki4D+huJST6gQnog%MQoG&E z6ztU=hhyHCTW$9{Zq$5)WBiUe{I1{J{#+!!5);4D5)tbf0QKL#pOxCWcXvKetsi^C zA|>2&)FZ^CV7I}Lj}~=Ihmd{p*yAF;9h@EQ7AxI|(mryEMFw**T5U5D%uJs_EW^pb z#G-+T^nFKye&R>^?i-iB=%~2FN!E2CNIy_9@sP;``hHw<=_&S+=tDQ0c24Z+z2}|c zr#|`xhD94e?_KbhMi~YTVFHP0I?lPtINO$pq8ip=O8Fka^zM(l+fv8T#56Nds3vdk zUp;ilbdU6#M39o5awl)Ms3HE@!1>4;gdsLw!O1H}lV8OfIhk!S1T;6%mh#$+KGJ99 z^*?w=*`UgsEqwsD+mg5`#x`T;sT`h47s zV)c(ALr0X%R(CT(V@~=WAL4$C>2d_QBw)#%lQzuI`8ZVPDG6X`V+NQ72zjW>>rj!> zN8HaJ1{5ch`NP4G&aig931K?)PO!*kR^h3bYA5Ko&fmK?;pKe3!OyGAf${R?dOx1$ zT&c=5rD0*ieqpd@rD>tZNuwzBG#7bN%5cWuzWeSlc~(ls8W?Vb{&;0<0k$+x63$!YEko8*VzaJ(?)pt@^M&kFKh!{t6{sMCJLgaHBR*K~ zx$)^S9~a?3;%W5GzssG~#71b1i}9#i^83OdpJf+L=e#nM_T+zb1CwGxC zL_n-kf@So2J`8<&GwOkfpdo$J?{V4hw9B6JI$vhtrPZ`FF@`yF_r7|R+S)$JG55}V zDX5Po+4N06qTS~nj*Mou!NYPZ*}KkK$#i^g9wTRlbXW7)KHzG0-*`fuim!^TH^*rO z`NMvr;}vs{tG?mll`$iZ!ij0zCK4`_Ca4OyipYW7>D{F;TQBM=qeh)dIy~OJMkCE^X&Np_4UaqN{QGU`T8H; z2Lp_EtV4+T5wFXiNV9%%&$2=1%?;lG zqd;8027>2lZX&jR@^t@6cZ12^ckDGhtWec{YfQfO%L!7t_=&ECZZxo%rKs;Wx>7I` z2oTv(o-g9)&kNc)F!rzKF!|{nPx8b!bER!j?xw`0jflg&GOS??dY$#lBjzjKdN&%; z<;ZUve)_Xt1z})@gUFf8e>w5)etRL374g7Am0sB();;F={f*L4@E(?j%1mZgb8>2L zPfWOh)DAKnPkgiDUR-2;?R&S&OS0|rOd9;G=rV)XBeITLyr z679RNbi3H*A84(PbChR3{H`Hl9$y{1o~tKlEQDkCz}%bb@0MO?$33B;k-l91XZhQY zigcCyi6WaLW|I3yK#8tUy8*D_+KI_swUB*#`9}``7C&2$_U2K_z*(N&4!9V4(2a zjs552zjwOXkC2n6OR>JQ`^G!b`{?xomP1zd6m&pf&ita6+zfrHx0dHdp1e?-L<>Lo_;lMw=b4p zeYsGa#F_KMlni~@3h9i5{!D1VeMwqv=xy)u3CKqzu~*rntKfRDXr$d<%U-%v<&`V8Q_$+L)gDX`U0!<+n37DQMz5rd@Xh82 z?Saa0Z<&ecSp2}4JQ!p^xo9F$NzS;`d0rMl%6re!^AbGD_)qTI%LS65q);pKrOT-A zyiru*x5~JG5Jah3a;&SHa$a@IUpe!`n4Did9G^78JhfdpGtIPzM_|vD{;(+rODOQ#`*cDpFI@5l?*ko-xpk# z-`nHQw+|5rxpOkPbdQ%&zaG^1ozE;c2!u+$f0JC8JQK|9mn-^Mh8;_s9`$>&5_8g% zwz$KZ9~n`cZ%x;0_POw)g;73!ca6t)N7#H4qOvGg_mvbok@k3fy_#g%&R3q_=yZB} z<7TzTDST&V9}B^sea5g=A#;$&976T7nRxPe`#H?^Ymme43XpmG42R&@Ye{j*xXe+m=35y&OT@1Nq%j zchNj5R+$N{5SNxie6Dgc9tBE~(NU;7$i(rMv?B4(-ec^`!n+uv1$Z72tfDh4Gu;Yo;6=Zngp$3+3+2<#xj%6{-bAlK3S8rjoQSV|JX z3AbSHt~X{4hi~235LUiqWvgCVxiJ%idq-=d5l@nugM~_ds$VNyzF#kw%gN{BM0}^= z$dj^cBP+)b-Oj#NwRHCO`1s#jg#cPQ2t+hO8+ycbL79}0)#s@dy0!APi{;DZ^7qR` zjD1z{@)9>Vv*Bf|Qmty`^5x~&d=B0p;?2nqOSm{%7RA=4H(_G=YSr@P^7(6@7O}I2 zkg(nKZ`E@%cBNwZd1~_V`DfDLIZFe^MrYQd*UOj6*URP0=*5e;!5E36_H%?=FER4!W&{T-m&zF@wdink5Mrpj5=0g0W!R6h0H>Ef0G9*hQ z^d3XY{mitA(ZsVK@TI-YH;X+%Fw8bU$G-Gimln_^gXYJkrXLsHeb@8UefLB!L*x1; zpHaU!lq2sxbKzWccE21V&GXdY?vK5nhn^<|@jm)e&s-P!W6UqiqvNwzJ!R!Defwv_ z4K>HM9#0*~elxvGsz4M$&+@?^b$u1N4u>p`^pQwZF1q2&9Dq;@WDL~zN;+nP2SJ!q z4(+96c+bfu7PAbbiHFtYNngjOO23w#dAl@F3ph-D?#1!wDEbUK6myo`WdWdnP^U`Fq-cJIq`S)M2>>h69#8;Ka zi|oG{=x0%PX$jP|G(VB<_>4>D`9c>iQLpii_IIb{a7K9Kt-X}Zw%i)ZRm76mxlo{l zp(tbLF%hSSBQeNLd%qNXk9weZb7wD4)ydgXZ_5@d`QdvU;ca@piR!5IEO~jCWAoVr z{P`=0OXUT@LEdeuH0J4tZN=vz`>}y4E&nQEB3>Sx6hhxi)Q(7^V)T{pPieS*v==bs`r;~jgtMC>|IojwuJ8P?9+}orOv2k zCha=5pFPDfS?1n%oZXUoDj267GDJJq*V*a$gCJ%;52}(Ir2DDVyQONr-K{9fg}uRJ134x(R=9$T0if z`Z*iaawuq?C@`T!DhMxu!f%i%dl^qo4C)Zy7I}<}ZpYBe8PhswI3|vrJ&7m~I{8mO zYuSgJH{Sc``0hQGu{*1#6V5_^oWe(4Ai?z-^=T*&=vjm#9#ec`32J3*HA5dBb1566 zg6TUI3#HMODnPb^j}A64I|2emQp1h9xq%gzv`e2+<%rk$LimItiRV7|&F`2n^9$jN z!a`6+s37I!!YS&X-hJo$Q_r8`ZVzzj+39&4)MOqMua(E3-;>Jv#enC^d((1p9{Bbj zZ1M813HH%7yUSy{CSIZE@cBJH>M`E}NEauoea;-k!38(ljkT89*6KLVe2+r8-@d+( zagm8(gVDg_wpe{}3; z5%&H(F$hjiLHlYK zeHP&6A^{W$CENJjxEFKs+-pb4FMRpuxp!M`@_lmX z#j_BTb+^Q&9OliYsdSjEjFX9lruefta?TGTd~Ji^eIcMmL(k!|SZbW@Nnz0U$tF<(feK_O99}o`V9gpI zA3I}@#TXUG$H%J6D1|N(Yfxnj4wD$ey+R~sLuYLDPRuG&ew=So{L_!{`+*L6#vEhF zLVR<$TgRU7$b>6*eR#K-hMtOxSe=m2+T)89er6gY$T#zoLG3gqG2(@N*jXZZeA!0( zWHLkJpOlsudP#?nV0>!aFO^24==`tSP@O5AWXT%%LzIt`^eJA`a^3!7O(T~OOCx2( zUb}Jc9}|%CU5mOB>R@#@%gYYQT+S^^VGsskl@AQ``VnPhw4C^q-G1nyP%oK*mumM+ zOGfEnYaGXFDCj%xZQ+-g=qyYsF56ddI9N>V;uf+y%<@k4xj8h@P!oiXQtW4xuJNr5 zV==*WYxBK^FrGFGBz-Fg{31T6NyJpUvYRvSdWR-nP;W&aw1D8ASNTpbRItP7F?#8~ zTrqE6=}G>EdX*EZ;?R+asbHq5>gY+V^Vdrb(7R70MJ=>(QP$xQxxJt8`CUjFN!l&kxpImaJTdx!OHTBw<*`1ymUm|q?mrPUv- z#ZhQC>Es>hk1dRX0|fKpuimN@8qZ5B!i`(Q;ebx(zc8b`{JwI3d~thK`13XC5++{slL?Fy%IjgoBCN@4K2hr&z=8x z!D^TJ(mr33r(pd~;F5hCM|K?do|wCCgriD7RG%rWGA-bGbog?2SQ{D$(hrAiUxe#d z$&at^yyhp5(xGzsYQ_0#)vHx1RH;(ct5+|VmzS59mF!)R-*YCSx;}#18Q#xbzs}m; zrIOvK^nJ?JtXjTWzF#jcT)A@Ps~46mR=lx!YSrb-my-I&eOf3={`oJ9BPxh7^X9~uBI0EG%;jZ#OisJ)71?)xc}tE!^q@$JevOV%23^cb+Gv~V__vC~A4+a@8@*@e z8JVhh`FET?B#Sb#1n5&DWQUsCvKxzWH=X`YG&QE_jAvmo_$)BfHp6NlZ#h|gk7r}n zJPzl|IMvUjHzyRS;@%MC#Uzi-oFsYcH-1<$84RO2FU?yL#DZHyJdxKVCbiQJ#$~Sh z#{10Fx$L-`Pxkli>1Ol+5bS~nWATs@=+&Y=WNyx3Q16S*_L|TtQ^UzsQsYRFxGVwTL!^vBHdl)cXa%P zi1KGe{5QJkOUUhP9BHqAnAA4t25yheMj_#oH_*}UPIj(upWgPE|GyNn6Z`9rcebe3 zfDxx2I-w(p4eOmhOhR_F8@4$44*sapE#HQI_1R84OPYgWn}0jU;78_Pv(8(d`URnk z(A_^qtcoG6D|K>y5tz(To+1#^sN2uJLY?8;3ftEv>d%H173pRl4}I-q|3&l5(Fce$ zirLw$c7tB}jdCwL>bnZkN@y94+D6($#thG58%V_fer6t0oKw!0MG$iQtrrdwD$iQX zkBe!nB8Ov>!`r_TT{#Z#_aA)nBF{tV)OTk)F^a}ph?5oyL0zOYYP%xe5@6k*cN@Q< z?}bInUca+GB6Z&F+)7Bd_tAc{aSei(H_Dn@;O>4h@7Va9cYZP3lSZ#*2dN~m3zEf^xoWmvvBuZD&KMXghUrRC9sML9vzPwrHus)#&}7Ew{s{&z~#p|g)% z?!GKxpU9#n7px*Rb#1SM?-NCy%|f-`9J)uf>Uq=W^8#ilN9Fq{fsAH2$lCHF$4_6y zW;G_7P75+=EOq23t%vS+bqivw>~F_IJ)bXpm8)^z$7RpY^Q&>u+4sC)GyK32mJ;s? z&kYfY<<9evE@PlC*9@WnR)J(JQl<<7V+BiBeP9?kYEN|F& z+s4OeP)am~yPank(7z@x^QGTJ4h!Dtr>~vi8P2R}Vt#fz&yqD3RQD*NW8R0`{IQYi za=rLJQ^DD*ew&*c2ElxXW!Go%2Uq3wBNmZhJ8O1%e#ql5*1118zD=jwz{)KrQ&WJ`oJUw(e^?P9obK|ln&A1M)c$b=VtU>Y}{bOQc zvOaIU?!rCujO~~>O%B%*Y?02ldEO?;>2xm>_FuB6)jw?zo>zxa)eSr(9t~=(n9@T1 zeMUZ$hH6iCSMwPAET7z?)6gh%%pX8}|9+3l@m?KsrN1aP3n2E@$to7Fk+aJ24CIcA zmQDm1SBdfs@2Ad=bYNlIJHY|GLg|_>zTU1?*JPnd^8AgDi>L|BbK3JTxPPn0OfQIi zD*k>m*P6Vi=R7a0h=Kmu%8#GaJ;4HpcO0YD?N(L$f@q4_!)A(~JWhHMy28xUN$jDgc8^BnB>bC-F~$*B=*P793u4DFs8 z)mSFKCOc`LvH6B=1ZYQm8op>ieMQ(cyjP&|W?;II?QcUd<>nYNJ@0s}i0teG((4ad zU$?^fIgXFtejbKxg822!j<*VkefmdfuneawKPDL*Z@~e*m@lb0m1NIbw&_mmbh6X6 zf#0$r;Wq9b7SzAO^2?Z#o@f_RC(xCT?+rxrr1c(_TKt(NB2cq>yt3v$WyPaBo!y_% zeu}qwdJn1zKR@i4sx$GG15eU`P%{!z$odz|N~vp%BfffpVG$Puqdez6O0?p+&3Ooj8_0k~qs{WP8D?znhfvyX93ch&2V!YAxXJ`;WN`X_kt^H#X+kbUa& zq(i;Mr{xai@k0>IIrBC~XG1r^4v}Wz^m;t$onxsg@mlpx6M0#7ov1_hUgCCS z5&1f5BCtGtJ7Zr&oyAO| z5Jfj$V2BZEys>;g>uemFt~>O}@ROlOA095Ah-)vbwHCdJe%{TqqCUa(WmJ!fUPyFK zzY4E5o@?0c!h~}mu}Jh$F0Gx|FjMqEZ^fP|6tV>aL%&njI5UGMF!AIlC-gq2xLMdL z)j9Z`c!d7Vnoul^+uIw~^>w~2LY3S??VU1{?0r7KnCUm<|B>Zu=`N>4ct#&NA`1r) zJ`8~tIY$oC(D28fkr?p5Yv|kFD%iVFL+vAGjrVCT){sXI$?fcdcyBy{ZbtjGc8g|= zIV>*zt_wxUaXgzQ^e%x=H!mPJ#Eck2$PIHu;N+o<7|>)fcEL;%!*p=A`>P1te5w6r zVK*=2L)1|~{Jbey4__)Dm@bsW&gj41k})XsgY=*c{3Oj>7f+wzs= z<*OF1Uo6bSkCLp>$8wEEWb6F?k2i&v)V@}=TJq)P@&`=BDH{KL$oxzzZIkw=JWKxH zHJbO1_185SmvIKAPW9HUeq6b7<@tQ8uLbl|_WAzwL)Y9n&iT@{YV!GNRlT{EKM031Q_y=bw*ls8+doa^>anUvRU|=|j@s?X}hRa^>>!<>kxEZ@@3}w0WpP_ zF2hA`dwPU@3P;jSJ{+{~1*Tc$G=66|7jiyuMyvD4&8HqCP>;;;w^_GiCel zfVmPGZq9ZtSLb!By7`mRZW$8EH(vwLc=)?MjQLMf=fW4sH1x?%d%je>wQ~7+d3h}R z?SF|z&Uu=$EqtX?wer>S`FfYcpmE2Geo7p*dOMNw`C|EEeSTjrmsiox%N8qJb2Bh- zKqU&@@#Au(V*8c(e5HK8US3}>mi?b6aa~kVXmT#TP`+O*PxJh~Uo4-V{c_6u-j%;r zD_p)NF8F`i@C{@3OZ!c~aGjm&@hyuf8n$3f~tL zzEZwiv2yu*rT+3WpG4`Y_#Fk$yXYglB5KtxTCHO8kDui)_bl=5IypV?w*(z&?% zq=J6*X`DyjeFUMza)kY_(;@ZeeMG67d469vcshN(7rP+l)UPh$vQxVd9y-#XA7MC1 zPDt)7;T_;E>zd=npo@hSF^A=(OYDwn@lR-SU-IPtJowF^KC~kI<_>qzWqaj0)MhY{ zFjRSbO~l>*iT%%@fso;#oALm7gMgH8w`-#OorbC0>@EmUY`qw<6foNgDaPI=Fid&! z$S-a@i^2&-tLKH=O8)eAc#Xn7%g%^)L{|}-=M^O%W}e;#cd>o;N0-#kj?T`xQCjgOZz9$@u?VD(zn_dQGVufCCUoi93`ufJZ{xU`T?=GR8N6mgTz z%24qhd>=A>cj(mzopH-*X4_B2QsFtL*P3oiDoGJyLM)3{T1R+yUoH9JN{x~}f3EXi zIY_8M?U`b48QVM2_JVy@tCK16oKGfteo!xvI%9x`hp(Y^YeJ*uQlFxg(>hSu+Puq8=-i^9Q=i?`ztY0o(OXp@{ zr+_2qUokc1JfdeTa`GmZ%NNU1*IMi6`Al`_vA%lsPA`ILIr#dnr9#z9moF|~D1V5v zMl1$#^uvM%F=xaaz9L+HCzf1JV3Iq?|k6s%UhQ)jJDJ0JoP0fl6CL0mWzv~a4|dscXuR!zl`$`D)%J)-z>G99%gsIyhaTaz{w?*2f2sPP)c&XSKdJBIlV{b0 z_udb)xH8%Mm8n*-d3kw!qwbCaNR^Mp0kIMEZyxE$4T^5P-;^&eD^I4QMuu)gQko6X zJpJRIC{U=}0|G|2P{Vxryl(xRPcN3LUo2inw!R1jwr+hNY+P;1h0En@mabdx51eJq z%1-HLs*}#V5K2gs=fPz>^XO~8JBBwixOT4kefbG*doSp=lv;+Ccy5LcR>0v$;q&c= zj|~Zl^}BnHsvWGITSt?eqWPer(K^2-@276N4T+wV8v|1PnX|5CV0^zBjUDZ z%Lu;*BJ_{4Vo#Bx_A69Teo6krC=)RI~YK``J z6ZTuLmn&XezFfSU-yRQ-kA~or(m?HRx7c@*Z@h8DC$9Nw#pSEz%gg28Y3HRuBlC)& zFP$MIkB4*Q|7A~{c|)Gn%a@lgE?+N}&)Lo_4-xVv9r@D8vserlaxD> ztwqFlzTV5f6A&n$duJmv%0t>gEXkX^&eBWJZg~3I;_1`kOWki0X;7qF2W3#5CspcP z%-lOPSITmvZyz*+XbX!tInVb*X z%@Jx87V_;}+aojKckbpNbQUNgK^O`Mu?~9n$hCbgpul)H#iEl1U`KSr`<)l8Lh4Gy zA$Cwyxc5@xX-e6|5Q=!y@Mpjr7c9;1>h0WBn zVdBej2y>?PCsN*z;UZo9<}85mZahgM`_e~^9MHGh$NY)n%J`AL9OVyAK=9$$L=Vn5 zgnQ=WhpzE)+(Zjq&#O$Q`QFJ8T>^ZUyZOoF?WT{gQDqgPFhOF23+{IPLO2aTV!iy`5({5z*d3?arMVhlzbY2D*q(vOKCf1lRx&_t^i z)95|!B9NpR#kuPf(HM0|}s4)IhD6i#5C zs!e_%xHuzG|T`}N&dE?+q8&V(Z!$6j3T zjg*MOA6YW_@dhjyr*V&gjLE67xqY{r`J>NaUjV?*)|m~9bLf1%J+1nwp*od!QMfz4 zU)LEFE1~Ybf)h!IR!|L}%A4V~VAyP0wDXnD(ye%m5 zr5zAj65vD@(m?5W>-b+=?6AE4ap6h#U}8vkcTTB<#jqv|82RJ~7?Nj|h&{*Iy3@*^ zB0T}DYGj%NIaF%+`s+R^A6KFZkBApIQmU+|*}{&}o0EJDTZuC!X2;bEspLeb5%H+K z@(_kOG>a&#;Yyz;u{4sMFDDni>z|3pq(b(K=t8E)eRy|!uL0+;X6-+%xNl>Uns>h9 z`1Ia#*>_)Y3*b^>JI>-!4xQs2Df5pt=kD!qTY&4{`dD!;TnHIl#&9n0Yk1gNm=W!9 zE+4lvS8Z1Lp_2`|>bD4J@)4!?(mL{yeFoM$9qcQJs-K*XWGPU-9C?(s8i_)AUJ(L5 z-t!gfe~tNVU!Gw3)y(<>GQP%~zpoM+Zs^ewe#qDF$+%;({oL%xzRQT>^{p1M`XQE9|_$xSnP0!_Qi>$MpAp>*`ICTfj2*^$H=qcX4#X2Nanvlj}8;|LCab(W ze|-wu!SkOe3Cd6w9==~z{O!kbxqqkKQ@QmSyzrrBHDvB6A)FCEdGK;NzNg3YLZSZp z{-1Mtx!n7iEZ?#vIv!ni=H4am5aLb`&GR63TAhK>mJ*4%T4#b1=~-IGC$)w>KwSA3Yx; z4-fGVsc*xOaWD6XAGEDRLGP`4+svum-JerSeB!tHabxSDawpIBuT~_IUG-He^%(q; zefg~tdtQExhkQEzYWZZkq+2INe4XS@Q10fA#tY+O2s!#opr|%?>_XEx5F=V3O2()x zfia7jL@qcr0DSa{G4Ai{gXvEw_}OH!n(6bse{h}YzHjwo7?$=KIJL&62PV7SxR)SI zyzgS$3~P3$zVtkT4bF{>len#N-!7gAPXd}xKX~rsFJq}bqvsliuz-^X^+BnpUE8?F zJ0wTG9CYmce&z2)t@(7bo=lJyNt~udBEa>k+3$u?C zMZYhwc@qw{dUCM)%2BqA9D+`v)DYD^uI$4S>7`NBkUPz(Au?gXLpyihL%X^5D9^0p zof>v19lY*|gRbmjeB=&Rt3O?wqURFhvy@bu>L!_+=exSI*)o}jva8(iD+cb#ON?T3 z?8Zd4J3b}zf%17>_u8o0VwmIS)lONV$R*q#A^|(8;s(I_jr-uv4~uIjTNOCxdkXf= zKgcwSX?LJA?y}+I49pGIb0gUs3Xh$`&qjKdb@g=mo+VmBN2(&qn<0BgwARhL7mtJH zOChr;o4*if1!MAo$HKN!r-Lwr7N7*6*%4}vZ9H3ZAqci!> zAt~fzeYu(1h+%0coe7+n&u{1FDJu61_^nU#{3Gu#hzdnybG(weHyyd*26@77IGJ=r zBry-TNQmGwgLzVg-+X(kM^7&!kDq*!ol?$o&R0ft2vGLiz9HTrDTr4(fhQNp4HvgD zG^8f6ZWbbhQX?Ew2@5HU1ISW&8c`VKAm<|prAPyn0x~5gnh24H5;h`kX$RZwq9Bne zMzd~I{|o9sHd4kTh~RJHd1v8ob-SC`ZaoQ}lK*$zJ&xnnaql$8p6hRw{64dr5Vo|L4SK^=b1Mb~k_J zd`2GGzbg}Vw~g^1b6hu<-+i4QAI_gVpEt;DFXSuu|Bv@?Fw5;{a8*<+ zqii>CjtZLMHG1rc$a2oRlKrart&=X$A+B7s+L@-*tWT30iMBHm&AiOs?CYxPOOxV@ zx!l;y$KKiP={Qj7(#Na2BJo_-5{x6B*7fEb?u3=)WTcboNlT?O3}#XohGN7xA}WZz zuGrhHoyV-Weu=8Zb(Pv?M5o9(;`^&Oi>rJV=2pph$sF^yw|6-g3MQRn%k||}VJ}^I zrEc{ zu4o8doEkwQXUeaRm6N9HC0^c0vfU)$lF}8Br_qD5EO;JPcJk;IR#@`PH(#&|B zZi=cMj)u->UD?JO(mrms-L+NqORl`@q^;v?D(3an)9-F7wL6lP97ZWiy6(u}dm*Ze zs6+FxsB2oC1El?0nC5&6MiDlW*Noenmvp$}QqsG(*E{Xvi7eYMip6kQZXrI*N!f_r zx8;22UhI6nv>;QZjC(6zJ1aJJYE}b}0zw)?3MGs7(c+98H(UC+mdD*o0t)GKU!^y@(S$Wjz!-nS0V(AmI!` zJ6`SEY2_8$H4@}uWu;o{424=Glkuc>qM~0f5^1axm^rjomd=$4DpRILIfM$T?;w4R zFJkT_qpB4%s(Gs`97dfvYj*CclW3mSM$bm-F=QfL!*S(J?Hfjl7iMA8%vlCZ-)Pax&sV^E zCZaIW*m{RYS7Umc8fl5XR!?b#>TNfPycqHNPbRipiO=_A%6@(N z2myJ86;(w=RY%L26jc=wRZ~*sNVW`MV;J@<*t(tDmlai26S|sdESkzL7784gF%uxd zI52*HXW~gdh(7c9O2rvp&^#YnM3BWMNE=l6Pk4xTMR?C4hO}ZqOc2WyQ4jQ`WmZ_E zG*(eZS}UklCZkHTTeh%68x>Pq7_kuyW+p^LMjIJ7HtTVUB`WEd=Cqh``)8(?PubAU z0L_~_EAv;L{{OH=8lNlGEB`wGJ;J7FdMYh!BcUvbAiPyPpPtp10h`ae-Afkka;4X% zDY#n((TGC|CQe%~6O~~p^z3^Ru2mgUhr4N#^Dc%au?S7OH#Ar_B-Wgbl+TJ zZprLKzUH+l9C}^6k@&aaz9}z7$~8MR9r0~n*vr)uC?Eus%|LmQaIvxtiUxHZ;tsG z`1H}Sdr@l`tGSJ?6GXFV*=IK0`L8zfBz@xT=?V5*CkUMCIOfhQlXc1*Q_`LzQkZJl zx6a1J*mRo+bmi^V#CF$QWLYKKt%i*3>Udn^^<-9&Qa)BEThwE=tU8RpDwwHxnxxo@)UM?u`=vW( zTsyfNZ(Ui9Q+t)Yw5H-VaamST-3U=PyyZEDqFG|acW^D-ma+4rE+n9HA+W5yS+qYz z?A=RiK~8RhfYUkoW^^5ll~(O8sF5Lz=egp@BH}pRl2ED#Gc>J%=IeR~o_C#ywH--% zpA2U#TXy@8yNz~L@$|}SmzF8^;dH0#g|&^jPiVSDs?qW)iOh`Bls^h#QhBN4BKVlc z?1fuOTYDw(+XZr&0P_9bW^k~TUQs^Sg9y^GjrECD>=UN&n=xSf)U?5blGm~ zS88sjRcz;VBGmKKxkbLcxhmD~^uU&k@AjRSNcI73iNS$_cHWx2}q%!>BS}vNmu_ctwS? zy6zKwo6|M3);{=V-*ZffKz`PIMIARn$2SLjc$az2sj)JtbFY!FOBUtE(?w@qs55(W zdEE#x_KDqEZN298Y)0(iInzfxk&uke=*XaQ1orKD$Ty9%Ym@fyt5R6>WAv(pF?$z} z8262$dF01)t@3+)0`&8`7DChZoq5e`cJ=Be9TydIZu;seuclud*poK*pxTVp#!1h> zs$B)tVKc-FpCe;?Ho39isk*UFqA6>3se6IvwN;AUx=6cmHWkk@Bcb~5Cy`s#d6uKL z)IL3BlNVg|syZ%uo#rjVu*G$)&Pb|>NR>E;qN+D`vlmwx6KMkLEy>#3k>zwYT7>(g zEwQrWu@k+S7de8(DFdp#7WQ+zQ1ESCnW1HgvUVES7dY8_B(qai^YGx`(rFYp;sVL%_F5xQ3XxX@{-S zwX;+Wk4uMbtYwtXM%=`txSE;AwRq$uvDmbne9om)Gtnq|Y?hkWtG&udrzPKA%6@$1 zo6ku~xN{t{R_qF+E$&QN5jnd~_D#B6@oBVuD+!BNHEW`-Q}r6GemNBBc4=KToc#|g zre1d(RFym%xVx~;ho`rw*NMn}w-V0Q-Nw0vMmox=a(a4dT5clmM)NEbTfHdln;ya^a@4D=uE(gY%H=UL zf}1l;6sg@t_f@dn!d$-k@Ox*cRo=Mz(R;Vqb5|{AmomvS5c}7f{XCxEvTGk|@}pVY zT;B7MZ?Y-xJhYlZ6NL9nOC8Jg8I4)mqatauHM%k=t(qX0fjg2!4vP|x(x&lg}vR5wYGKH#Mb1_4z=09W0LStVY`E(RKYgxfK z_3&zThn)G&w!HP8q>+fk98nPnwPmRrE2!RYVX;o03~C%7UlDrjM!UU5&E2YDxoRVq zE0AO6FpAMf6>Z;;dhFfqL8`R;ogpNO<6{$6L`=J!p2W+t4N!tma-+4ER-3#*x^Jad zR~1DkvMS3StK+a}T&A6&HKx8;LrO6=@Z%j_Q7p0`#nC4phm;XE-x;X*&za(Cb$qeO zxM^ma9dHVEA4De?_?fhe)U(?>SgqPAUm zRiGv|4R@UM@LOjVDk0!{%FII55Kdo(PP-ZgJvkYT6#%2-kMyfe$IxWg!==}MGRl-#WZszw`|Bd5!OChC0?0cg<{iZ^;)Fq1-rRc{qyOvHg^JgRa#4@)?K z`o*2aX8JSL+dZ^C8E35LDLrPgZc>lNKJd8@AYB`}xz{-^hN$YUs3E)D$8y3fO%^3Q z&2877ItO>v>vC1D*>zC{Am=#{!axpkaNJJQ1I;}kdohe1+MCu%a31#j}#`UTEBPtLIkw`YX$O zcH%RW?TOxX@Sa8WUDgF&Qlz2ir_g~7kRH5VrBd^&r!ys(#$CTH97GIrx?H}6(TP6~ za|=22t+|5p9q*1V)oa<6!`eBLGqLXbi_DihYq@faj@vUeTvm?`Yb9mf-cYYzY z94bw$;;w^hLUAbNC6yH^`r@~ohIw9jTifmK0(Ncnt4&VRc!bhk8R5|}FA7}5YAr;U zF7aQZ?O}DO!5F-ny47m&af3AMzr5`S{7=Fks7Sw5{72aP&%hsx{w10GBR-No;{T625^j({6%?_;x+sF-8p(G+93d949VsS;e2JYRZMdQmW z-}0NdSH(F3!Ajf3RL+U9+SESdKN|~PUN&^x%qYdHY9oc*=4|CH=$xr{TAe_hCTTYs zN3kufyHu23kCU3L^S$-8sxDk@aS7gKJP_nS>!W)1Tzh^;O4t=ga(q=%6Ojn&*U78JDrGrYEtHMS zE=pyCx!eqSeZFTh4>`;p>)s*D63=^{ZQ*vB>{k1Hoy6fCql~gX1C}D)wz+8ncVu(8 zYuXsJZ534YJ7l>DE~rY=VvHOO4z?h%-oywKE}5;~(?yTI{NcXmYVqCDypxeEwMd{i z7MI_Hfa#b@s}s?)R`lC-52&T4tBD+WO|4Wz;4E7Eh}UX>N@CkOii^mWNQBNRabYN@ zMm}MZwu53}jY4U_gvYG;mWO4WyEp{=LJ{P8p+kVsGFXmIU&(yD!SgZ zh{u}P3UuwMir3`x&o*2+A1SYz`Lb#n(ISM-4$N{wV(@nBs962mJX5Ykb8v_4a-sWf zrF$-&o8nfbPsfF4Fq%$GQ`fBWwwg?lk8*8dCf%uP=}TuUo_ouzep```aCJnnX(u_J zw)LQ4zR8+MAGe$aR*gQ?Qn8!)oOVk*+w^!^Ww77eQ6=0hit)^(4P z*|p1Th6^hzXmjWaJcv996^PkS*Gxz{_}=eJrtdIpF+ zb|mK8Hq4JF6PhQ;q*8u(%ZGlt*^7BH=95-&43Ja0#IT3SSJl0$DRf+7>Wb%{vYtAw z>eW6znKP-HaNB1v-p#%MM?kp0b7k7wx26G?w#R{vTCLY2ARV2NEK8c=T^MCzQFGj~ z-;aA9*)YX;Asc*Y)%zw<<&<<8auyCIjO(eqtS7RcTdswOu6>-2$tlNUVHB*bnZd-F zmTsNW&t}|^wi(c5m(v`v^5%}^(KT*XM%O^*>)bQqS_+&sRA}(ERTHl9S+vc2S}g>v z5iaPuhl}MzUY)x|qj{Bk=BCa-0f^G zho=(Dc9HPZ`fOJ0*JK>)2e_ppm_TJ#QZm26?uMBxs zxyL6Qdw4^z&CJcb^f!Xb^y0VXWlX)6MID5@I}sq_mv_V|euv21lM|<0?rIc?YvagX zkg@YM>m*vSEp@5be%QpF+)FXXR|14(TC}oa(bpuzwxe;)H!^D{o^X{T^dakAdppr_ zp*f`FYN9m>dz~jeZ2H?@T9pOIjU3&BVLB%$SFEx3on9&~`jT zI6B29I<;u(tWuA0=@L8Mvhg6+S?=87j|bdFjO*#b z+@JN3&z|FPg_M6*W7@XtN~Oy&|BTsnRw!F&6F@ z+Zyj{miKU#lTE3+D;CizH?li6)@m0=LgV?TgHG`C-QWDJPw8*Ep+_ za30)`c=HnFEyp%vzF0APopYSz9&_6J?zPj|n*idd>giQ_&NGa*rI#hvI$}*HVSTci z!PGY|Lac?$X9FktU z^Tv8qa?I?Lc~L~D$Hf~nId;==2-nzw+|8lmBc2}LXDQzB#Nub}-hH;QFz?V^vy?m9 zosO#x!WkEpr5hGuTQY3Sy;Y>TBE8Ey+oKg5c+Xr)Mqt}Ph^}0xXPK^X;sJ{keB-;x z+q1pn-re3)q>UxZJcrfZ7rajT=63hfHw>|v>}Fk6wnL=~Q*6G_@S|Xaqd3W96y}+i z4yb&ZM=myLUn{P2B!ZzQK&POHe0nFXOtm4ZoU|LxT|O%>x!@+79h!OCv0TZ;(O{B7 zr?~s?IqZDW-eY}Ub<_#AOLFAaE4>oc$_`@F)3SP54^?oasU3G~t1kRJtqpk(b%}-g zm5%Ik=uXZhcU-aDo0e`gD|fNhVa6*x;~{&=&RvA>5Jsn+wdF>3uDa~Ieut$Os}Zu< zUJx`ONuwnYmSk?u#e;}3!Pr_LiHn9Fw&eosm$MO;lHVMO71C#6u<@9pW;oi>X6zcb zvI3&P^G-S>$few;VdeSX0_?3*fhxN2Q&#b4eMxmWD)q=*v`odc>)F}4c;Sxu1&TvP z(<3{QVep)&jI7sUVd5O3qPUEX5{|}s$WfP?=%GvJW}F!N68imDu!S_H6)oI8ZF-sC zFFDN^j)fbz+d?jLIvO z3Ngn?B!?Z|uBn5BXBnGAQ_Z~JF-lUL$|l-*OfGDtGkH3iv!SgRpOwy(=){|qZ5?@e zPGaS4Rg1v6c;2gvosDJk;jrR@>aA+~3~8f-EyR<&1+7@=*4=ZDEA<3tFY8@1_ zovGo1D4J`H(=r{&qjsXTKJE6^w$AAzoVvG>WfMWH>Dk?#&U0Ehk&2ckrL^0d56+ca zoo~0!ieK=addtT|h?GZNZOzGf>nN?V9t_;N+L>F53E!`FTHC^j&Ex9HmhSEEb{Z#^ z{PA}p*HpfR6wVq@L%W40B~j11qUqkSm#)nY-N)(aS={jR#3qi1n^iGRf?b{E>EkgI zow}+<6mv|F?As47*&A+}iOsWOmK{>{uUVvaC7U+fIy^)A-ZRaYR`kys=ZvaT?xk%@ zq{yst^3&|yyj0EhrtZl*8rZcJyIjn)cY4f}I>AaNX;D=C#fHhSNd=~Ex20%x2<>wB zVq?2*U1lyf!98N+A2*Dawfo+D%;s~wlbvl^cdheX0dd7i9~h|Qlyy@bcBc$!1niNQ4s5CPTId4o?%||xOLwn zZW^n+swK-Q>hM-GhZarWq)T_M?fiL?=KqWUTT`>?vGuz=VE*^5<1M|r^Q4U zEf~GR>WAyG?nSe>xO?5xsqIGjbhbRYX!1+XJv8r4g^nKgcggdpadlJaBehm{btNlZ z^=^$YmJx1Xah=@7Q#?z$YB~F}Xo@Izz__W$c-+gZx_H7~(qk(jC?wgtQMfvbWSTE? z6sDofP-Qt&PpRjxl-0bIF0R=-&hAwa8#7z4Np&LP>vt{PToF%kzQvc#U2$z|yf;%^ zzborkFR{NHe&9D32aDbA+nbk7VoQy+ZtJt0iQl0-s@6Klv~$L7rL&NqU!x*Z+Ly{V zE)uG;vE>Q!UYxTtBby~>V`YyqwHB42)XBu{uNxb7`I)bUOzC4|!GE`8KJ_!pFIp$2v3}AvL=^q4~XhfW$TAbsnYe zD|0QP^CDbb+qnm0yGyGlPY0b@?%h^#vMk4Q7q+7x7Z*n(PRvkCmXefjTy`UJI*6B) zQB5(gnS4acZ=23>-@i%CEU*?VkEgBAnK_x1O-*-Y6%89RbMYXpFB!HJQd%W)^&GA{!mGaopW!b_U{W?RcR z&)jMpK_rGUA?$vJheeq1eG7!nu1gG2f(uT~8!Y)5@=*tp(v)Y?XAFu6JV<;%I50FAbIk}yVezy8s%-!wgZ!_Z0GkIIg!X33Dc;2@J4rLTVs_QUvDR3h?@C`xZ zfIwp_027zDdzanx`gO-45IK@Q;iG1cXop9-Z92jv2OEt7?J#Db;MQo z|7iZ6HHnTFTjvM_0n+NBHao+0NxX9NT{QS&g+k`JLdgdVLc#jR-GK&Oh(N{@E(r!T zxH70Ocw885fBu15f!#ou`2xlwy<{=YBj!*IP>r);}homL+20RCWQRsp!!7r(ysBO`QMrP5x1e+>iR_!-(eVr$vC4KnFN@^t#jT*>tzP0XFB{Z~hKY4hf%9DI)&?wR4g_#6+wmdcF=!3;b8GZA#!{a)R>q zA{zCn#|Su?x<9)H!4%4)f7_d!fl*_A$s_rOpz%v0ftJ1|a#dIxPDydK#3 z#&eiRgboOtTdswqA-$JY7!7T0xN#+z!ZP<2q>!kZy1oMZE&G^Z{k_> zJKx?KvQz`)bNt_JA@Nd$J?7h141`BCG@va??H9S4n4fw7Qn(6Ok5cl{8-E7$FU+?U zh(HTbp;ND0UbK7f+BNU@qnrDw%fuB2)Oz8d&?&TzG{xTVFN}fl5r>;k$7&91*_7gSY?Yl;7(VJ|MIS5&&~-D)^BijG2>qmDF>=6>b-xQ7_V)c zl2ti$|7gp!%S0)=7r!c)&o_iH^o^# zgsP?@0bFZM2#{YX^+=V2@tmk7K=_bIUCe)kG$o(au-uDt0m3jC!BgWEIJQ_lxg?rZ zuQ`~|DB^}Ez-66@TNcfFp5X&W1(dB7O4Qn?Rcds1JB=uKR2|;t5TFQj=@IdW6j;hb zun0XFJ(K?z7xL0NXm5vRp3#EkEX8H9L>YYD8%IOoqPEDEm-yv4(w()@hASK>XU}su z{N#^UU-0q}o{lcmm(|Ei93ag_Y(7RUa+b3%SBl|&F$`|ewktN{e51n|dD3YaqlNlZ z`*vR3Pt6Wi*sq6eQERu|UE6Lx{nf&cPd+uNm%QD7d@9_o<7s@UADzSDa}kQ94i&Lr z!D;LWbWJXxhi!2mM1F8W#1pASmV(<__#iwA2d`={Xo>`gmAopP>1$Z#s<(>?Eyupo zU5^XlOi~Q@lw4M{O4jTyuoWdR0d9bCdg;K!Wi&k_2?%f2Xik%1qL{UcLZ1h8rgz|l z%Ql<(Y+a0H^|ezqDYdXEN=s1&hu2bC=MA)n=oX&}ApL}agB{rUtZM6uzrYYPc#Ql; zKHjFi_PqHM{56xE4d1nYa^6)qJ*$lo(ZIu6ASIgoD&^Y$d{C@WKpT~aw0Jc- zzJ8XYRL3@nv{&9R zf|?2`WRanXVI*jl0ECf(XeufxprnWlV;C5~7{m-|VuMY*{;VL5TZdU@?YR@XB^GjsOHT3c59szd)Yt3g0I85~_ZU%k z(yI3N)-NZ?&LRHELt{JMi}%m4ND!&~HlixvV-93=<%TdehJLK0nlc+)+alIUe`^bh z_g?X~CnD4v$#A5_p8mog5J{lwl|1D89~KrL&^O#=V`~dIkDs4YG(nU2mm4Rxka9)S z;rp>2aTIk?NJ*Lw8E$#>m+oG)eN3Z8#p{)r z)*7GgzL%J9>+&@0{f6PG$#c;4){@0aCi;|c1NiuvKEFqFsA#$#5(La6r^ZoX1a9fS z591ejsPGm#Mj0u$L^j#lER0RkvdBz_L@`>Xx(o22%aKT#*@oQPOo zhrq6p0r(7XW=W(ix293M~)MV zm5eZsJ4^Fq9 zbsR4um)INaf~WBwpbzan&S6%Rp$kl?9wc^+C;>Amy&G;CSRZmUL-I9Fk)DNy-4970 zZ>SaHIPwD&SI`{#d??k((IpvtyqROzg-cIHFZ9o_g{sc^lGK~l;J(vi^NLVLI4C3Y z1C-;ND2>WPwBbe5IeQO?0s;5MfGHmQ`vW59_~JEwE<1r{JNPQjfiv5c&G~wDA5c&f zmfZYHjis9{XxWLpwbHgZWV$@h`_J0UOuxei(JvYouFI+tRZ#>8|9GvTo~{GE@isqi z#UY6*O|@BVyj9H_Z@@W+G4pc`4e#6i;4ijVP7Orp7|2gR->4vg(Lm-Lkw63tbdE^` z(J_v5_nr@A+rBtUNcF25IWkO){JSsQ9;FhOcca*9%Av4vm zHPZNw$m2D9$j9T#B$_LMLsJ~skK`UO>LI{HfT)!8c*YjQ3s7U)ifCr*TIyW~anlgF z+cFuW+x}Gv(B4Lmj}EVBXAogcxY9F2hd8(=D_c+^zE(HDt3Oes|v|N%k$SH*8y`+QkmQ(C0`>jfalTOM1PTNX`$ufH;+Ybr; zK?|HJ%7X(sFTUyYx#Cxky!;L4H=%S~9VaktEa77eMsj=@O}>#$%Vlt=2@Fzd>>gsn z^^bppepyDAo1MPob>s61$hX@$pkvEt>oXMfOzx+}%K%Z=cc(vTDH9T#u%TA{izfW} zpA_6S@qw%HC{d_UN-9yULi*i{+`C`7UFQ$xZ2+Iufu}8F##Rlp&{o(Iz~=zt>K>#j z`PvyWCJfv_M?@aw$-<32h)#09X1ldoj5yz3@Lfs_*4WFGIBULOm8uh>d*3gI7O(Z^ z>s>IXJP+gZoyPuW^@s-*QXkv0^itJE*`oH=h2Hv<@$*T(cB?0c|APHxC!ZzgQ!j|l zg!_75H!;;)6+?;o@c$-Cj#2E5LG^{Ge!gWl&Y)w*+~Mw>>l!xEv#D#kKCArHvq)cq zW))e{9y22awt_N_v0D(fdz8M`9eO2hhA5#i&OWtQj3Dy zLUt?-YWWAl+=uLF2~x_0O7E?%bF4zO8Mz4GZH8Oa3X-gvVIO^M6-0 zGZ%Ce^*Z5o(@wj$X{m13uCwp|bNG>ixR|Hwnm(*T;nf8+NUZ;5_HfA=bt?G&_ep9l>OW)4^W#r>7>2y-O>RyAGO2=57aG;`5Q+WU z&&rZw3Z5|c*zgZ+$kj5m@gkrSI(&Q%Q3gt_`}*VFO>RbdWhV_DEoQR5-D&?E*Cqv;?X?e? zI`5!B0|=D=3j2SE3<<% zI94K8Oh#L;i}ErsWoEzZf|}Y2T9dRAlVgd-T!S}Gcagr8$2F#4)|gVzqpqbDsjj-q9FPQojFJZk z7z2b2b9sYb0wSuYW1mXLF{LC=Ad(E4^eo$4!{1cDxlf73Of7>42Kj z1jweS1}bLSVA+s}@0)llPs4x4>ocsMr)k4JrFx!Pb# zzBx<#bhK8JB5j#z{95JD@y}Z-Vxt?sGgP&v;ESBan7QyaTPK^624OrcT78@3ShF&e zxYoS#QDS4|K`PY9|!K3Rb;l}k%P!Q!5a z{+Q+S>)Y7m2(aFDmEK~_VTLE#b)1A__`5G_a$2Wm5+8o8QXJ(3?OAU&PV)3d=fZC_ zhhvG_Us9!#g80vyn?&s)wFWXla$i=vIOUoGg@~%nRbD2o3N+5)rDKiVy@`# zpY@pHCbcf){Ftgo;)J1t+P>RSmk-aM)q0IWNu^qdqCYBpEtZOUVM9*Ze5r4%yI$3s zzu5VL-?jd=SfFcZhM05csRlSbO>J9cxBBfbRV&_z-Iif1fNgzHBCKW2$aNCnZ)M8Y zCss#PRrpg=#5~8T29*=r2m>T=9paDeys9T>?ke{USq#wJU007rM!A;R0x7!5a7BuC ze>g%lu0XrcJ|#s!$%gdLE8D#s2!NnvXC!_JBrn>9;xZ+V+8#~w8X@vha zuX+DnTvoN7hFURervP@zo(M&xdVc2LLq)0{ywHaVC25tnqmm9z{u48}cg>*-;@Xtj zv0suC-%FBuXn->_N4>HyXC2UV#dDGPRgjf9lGJx%eeqZqd9t%(1NMwj>!&5U9hkqdFWtFvl>%V!t*P%Mkg(qglfVET&D@o6n-*h7bPsGdZRSoQeG(@ncNo5o@Q=S0#3(Y?fu#34$8|4B&#`f`EshL+lWM2t@^e#h?(l2xcTm#BO@#%ckvhmfjV?5-t9+ zX)}?3v{nueR@tl~+TD=+{BMKS*&&E&7Y6Q;WB}w}>WK;;X1c=TF31pv%&+6}uG{Ot zO))|5wDqE1TX*IvniYC@=xiP_Q0QdsH0;_>`)p%+Xvwn+Zh z(U!(rd8#$u-3?bA?8RH!_Q3uv?(4JuX6PZW1CyvOk1G>+$5JF7)`dS8cE2D1Wmz-j zx|jgIsgno*0NMI1kOP^j8ik0;gh2}0I;z%^1~3+cCo~9UHiyCR7`VIv6^qBA6>@Lg z>vy|}oIGb_qOZt&>r6#&CiNuwQ-%aM@76ARDJAECIS@IBh0lqPdSM~7kjIbZ>V_*F z^WRT>D1}Z{;J&^6F1vc`5bJY|TkydwgeGR7qnX^*GDg{wyD1&WcHRDO=k=^uuwZXp z8y#mu(wx8UccjGc7aceeM)iJUTfJt6wc>wz01V-)^}RFKpF-e+Zj19CbC9#*^efptcxJtk2o zb3X>Aa#g$*oxJt6p(%oIjSAlKw8p7r`>oIVw0V!wfc|N^%b7b@2XCq|BsvJ-(p61E zM3)`qB&5c$=#Z9Um(?%JtU#jv2dW8Auh2^u1MWxxqu}nz?!S3J$HQbI!X-`X5B9)K zmvLUk@qWHkfFWYYs%ZCT<55_rH&f0a?XKq=58Wna4i*Q~+GUmT{^8c$1;+SLj399<)F+4Ecpr#`P1-RbfEyX;(Gw+0u3PPKf zm&e;tKDd1GSbbjQ$)~61%TKSN>+e^^JdvsVVjk3=QM&&3{~e*efTiEiA>fN=T39}2 zh$zY9V#P17uLLM>p@;s=JC-;7@$^7~hSdW$e_phetwaUkTMf`^AFrg?K#42n&$hB$ zaOM5uBm^Jw9^;3>om3+6q4 zjr$}D5pX`EyWi_B_HxgTR(mC}$K1P*a{+TP3>#-)*ir$K1F95Iv~T7{gLi$ zzb+Rlwc`#MulY!@n)hL3UTq!n|0#TO&G&yC>2V`kf^l(jA{pdd&+$K68=3m)awnxZ z7yEPjT<~|b7UF-}?o6wxDnEH}@Q=AME0=jO2n_wH0_vU~Hf;F#VRw0Rw4-J>-2ajWoCq-S63-6B)M-_3k+8uG8t?OPo`K@X<0^rEavEP$o6fnKa` z<7YMkb%I*e`H_39BI77;`O^*6BFW?GC=hHlHv z%h7Bq0ltouk+xziX!2-z#hGU&M=(>TxK|_^l7M%-{2qns6h!rf^ymEP6=6e>A8$0k z0lC8Ypqpi7B0x*-q)M<aO>J(`}BATsCk5||H|Fo4d(Iik{y3G;)rYfZx+Fm(dm4&|3a>5O4!KsZGxyJ zmP_uYurO@$=bOn4=$tbVR1JczPoyZx&De)de>5WVq-8VcrQQb=>ix~djF9jd`rOH? zh>20nQol6$6mi#a$Vu5_PkJl!3pWUR2yP@P{LYnGb<$BoL-mz|o|4yhs*;_M|Kt=p z$5Atc(?wGpzv$op5BLzm3=wPh|MeH{h6FIF6!2wLi*&2{H(UnG6aGuzWU-HxxY*nN zZX{TUJS=}`XHR{|N0kRuf%%m1c(evKa1KH*T;ZF#-}IkDVd{R!!)`p?`@K`UNv+>9 z+npXsZybE1JxZA1{Za}wl+dcg`i;|x#C6PTUz@v9(+O&osZOYm%x%{iE2Pht2(HQ%br)IKdT_ z-(AQXVW+t*r6%r9_fqaLHnXbNGqYY@-RfDG&Sn>z6U{d& zrUpaa%d+0ARui0RwA;GvT^CR-&oip2K=^Ihc?)y3V6R^9iJFY5w}Y=~RYn`u^LMO* zpNeZyk-Mrajp)tk(z|;$cCk#E5u7c7W*C%`gDbn&TEiEE3M~Mch`j) zV?}RwEXStc#CJbE z$#EiiqC2p~Ta|KhwGN@kRj?9?7hIW>*6&w&IjTj+F3IUx8IwJm*)`j!I@z5EIZU8T z?9Uk_KN7dIp6Z@2BK8)hNrh8URdWv;myg+#IF;V*ZuIX}zRm?s*iEdg%TJe3Ws*{B zhRw;YEp<$o(FWHb;tiWkn8jH#ZNkdzetxRXcbB_K?^~K57DL`SWA|I{Ny6RI=4Uyx zBJ6!1t5tJ-JIs^a>{}Y$olzRXdt5X<-aKg67WsY4x+WuyBu}vdjeVlcs4|h;IaK}C za~6(mN*s=ZE|%mLaxkLrjGbLQjor1Dpv{pE`_+0?$&0hMpJDd8XR$tY&H}1)Fd_l= z)Xk7W$HjCh>o=cK7gyc8%HgIm=dQbQA$44AteeaprLrepsEvxDKUTflsn@c4_6@7% zXXa|Wn25L5sojxJbk=oM4-WO1JjQQaDBh)NTyu8uZCmXtmhS6OH?I+fspqi{L?&_X zcBo1(COdB-_h~DevT)+zTsk_{7VNNqcil+2f;)1SinC(z_>3@~=ycmp9a*$OevWKT zTJ49^3hC|Fbz2Fk5SHDBmRPfH?sJsKWSLJ-)f`Q3^z8}bqBx9+yMBC&jfYC9pt z-04KZSlumMLh8ram9Lk(xJ`D8Zlt_0R6bf+w-i3^^z4%GM5%o3%Ux5|WT|e8+)sSy z=6X76tk{8b-kOzawT`9;h>e--#oD1?Z$iGBn`~a|GlJ>wIC-l}BwWj97?t|kL%p*> z$hc9Nu{(4*bxHWuLf6*5d?GQ&*X0XqYF}QfVV^SY6TRWPb2~6a%jOx3?-w>FcOBiG zovJ#XWUEE)J@zHL-Fvl{$@1W=lJ+f3^Xp?iEx0ojy!2^f(u~)&SD0=-tQLo_LTRFk#b9&9hB|vm1saB{!V-DY)XrIQm*TmObeUde?H4 z@p01ey>HVLNrrO?Y#>@rUgH7&jF-*x(Om(w9( z2$okbD{p3abnDyY+q*ctr!r@|6smKx2oU$3*B3Dj8e2n?5u1J7S&KSiGM6Wkk#rME zUtOIndV{&+VFxMrfNU-ZJwtt?KGIWDgM+kprY=QZs%at!PSS)((R~eCV@71plXJ*%A<|~bSxH=81h{xyL ztEHVYJ(b$=6|nb@ds;@1R;}h;Y-Qy_m62DL_t0Y1vgs{_QglyVWZG9Rxj3~#)u|jV zt-Eze$B9>)cvF-m#=%k(K^pyg70op-S$))RCtFr5#ZoOC*9i{f@UK!MGitJ3nGtJc zp4l@PDXJ$Vd8$_ZQbEGatd4j)Q)(cdIR4>- zv%~B|({$pfl@8gUnVmefy@#YSdQCl#GO0;&?w4k3qT(Lv1r4oD8_cRlqB9~VXD?Mz zV~=|FmgSnpv$s(Z9bmY5u6Mc*6)*iLcX!ZNg!1TCwD6$=uk=Ns&jL1Yc$*D3m3F~ zP`uR4ua(A5NmqccD@q671ID<~RGc|8^-lxd7 zCutqMn|2&M;80YNcQ^|k7^)MQ4_5n2DZ{IxGSg72BQrX(vhz)oCnK}5(6fiUDAfi_ z&0Z`nl5$&OTM2x`Yl!BJx8BFtdfi=h+Wjf=@jJlkqavps`E?nrvNNnYXL(p+yorl? z%qKZz+U>l4caDwAhMd^Vj?SK^N_o?5g}dBjTu$-XM)3QkampxraW)uf6USACyX;i- z>@HDV8POHg>X$`r;?C1iq`TwnJ*K?8iHvzcv8HcFHSG^uc!%eE-Q}IokgiEDYi>G; zj^$g^Cv$6Tx_gB3;(B{JCb`Un7j-+4WG>~oBlRjR^PTQ(J+*S4}=y?whFXQPSni4_R5;&s;3E3~`t_EB}pxo>v8E|K8vBJ;UR^!HyD+i+Ie~Gn$DdzS+sL zr1dASCGz;DdtUbsS+VmdTJEzlZAPk%%8XmNZvCGdA(L+ui4+?C8KdJDN0%j4xrCh{_=-ghG-w0h?iy=I~JuB!H{i@v&f zb5T6Os>JiAa`u;+pXE|%8}N_&c;?G`&?ZmMJdT2Fok=YMMQI*kxKU* z#iD+4I<_o$H?GdUiNaIhj_Nqc*|;mU#S{>wWTi>WGJCe;x)C=O+ZUG*!`wzsF>Kg9 zcWqNPXI9vwUS96{9pz^=sEgT$r|pZy3OgPvXEb;YnbhyCgVvyR2Wl5j+%yZ2Rg)#W zP)mKT6%~&)0;!B1;ayI?6+4FQTx@PjS%CS@YbmBryA)0~Mc-|enojjBS2bA`nQJDV z7DZOP;V))ezF?GG3XCD{vwACTY8;hwdl|EFl;&b0*^uh08gcq2 z+B34vgt-nbD{pz!(YKSn_Kj^|&`{#BC#8?U%o;V`U zTufwGKR$V?RP_#fK&O^pElG^?&n{0Btfu>w4;T-Zeiy9pNi~vG13Q=_A@gW>GpsJh zl-WpjxpO6}q`@Rs8>G57Nsd@rqRyegI)Uf56(v4*bT_oAJ8Z^z>tW(`1q|i$nS|C| zI%J2c!_lvg&uM(+OgQFtgO$4IRuB}DNyrpAz!@SVsYPj2K+M4bT$&;kN)!x*PN)$> z@q5S1_4?1v_WqCBe@|EE`F=yrK5$}ZebXg@z#SCL0$}3q6LlXa8GdZ_SVZ=Ja zsV%r9DlV%QHmJ7H3}g;w;4I=v7D|vfyUdgOSB3#pr6IUkf<>H3SXKpOxmHcuO^l+k(ZaU+;*ePIfosHyc=xb>(1G`IdJNE=MF;|WusFfa{)X=MiEXhVjZQKZ)sY> z`L%GmMdDWR80J(JY~DMwgNTwMupD|$iyqePMur7TZ8{PMOCg~XmkhZ~w-XAq@oH1f z7-CVnDmWyj%t*aai!L=+4(_RfY#-ACk z@|ju^z3G~abX^wi6<3*t?aG?fm~qTEDZ$S+Iu~xEFZAS-<292|S$UXkF4|G^ zGY%HcT5&jn;@T_mD5e#s9~r9z1Qi7lkQGo>M46DNnJAcqqLN7|qL8AQiKwO`f*_)q zAlZQPI%(3Bl1rk=={XoqOCbqPp>m{ZhJc7eBOuWZ7A)2WHp`ik8pSth15r(QlSDLP zH&2B0!bggMlL;|U$4 zjj|#bHP#q28H@^mq!2?@qaiw5NOhj1)=jh(t%Vtguvt(mF_}x_TuW%$W^BOs*oi6% zssgB*Nu;WVpopesmWG6?NMMSZB1)=ap@@oz)UOjslYtpHSt*iX4><=33Ts7@%urZ3 z7O=sn2=-MNMVPHCell^xm&C3?)UMm4uq_+zOd*z0Nix8&#z9C{u(ps(xp1OcDvy^1 znP#DiTgF42GzAEt6qE%hP^Ae$Nd!bNK~V!h6%j!a6ckdFl%)*`64Hk(T?D+KO-7(K zWG+BNflEWE3J}Spcmp|DGa6Je7pYicu}YO~#ub`{Ee#QBj4oVan9yKRfZV2LbuBbf z6A>i=F+|iXP(;K{HBD4O5ituDR8qiDF+_z_5g}9*(-KiYPbZ!(0)VEes$_^HVhToz5;w*Yjv?x#-dO^qnAQe~1WJ-A!m;I^UCm8qu*;jU z6xLK(xn#>m*^W5EwF{M0tXN>FMPXH_)saRV(y3`6Wul@fD42#wNnj$0rbsG6nuw*O zDGC{)YGG=amJNuj4^d@gcD8_|L5fS45n=1QZqj;&4p}@rrCxBwIMKeQTXG_D)0V_G z!c^rbtAcYcIk^Al{{JKZeQ<%&1ffolPevrw!PE+L5`k}Q-^_R&MHQ^e;B)P-U!MIw;aup7H{HyTAIW-chm zLKZ0cs2;eY0yE20ibWI=Cj>=0At{ugn`mQ>CNk~D7==U}OE4;1#nr88G9fCaiYSVf znuwsHA|k3ODoLtnnrTpD0aR2-A}JOsDcef*4M9rOkwDVb6>81P!H|YCCA3cxZ?yDC zb&_?gH*1zkuj>?vDPkxHnu(?%riyBUikhg3hJqxLrYMR*SvZf&}W9fc&yw zDN%l8oXaZGhNr|hWty#cA&F4ALlY8^LXEao<%SsYs}*3$5X@0Rlm#TfRKU?gR6#^9 zrvr%R2xJ{og^(E~N%EBT8Hc%9ucnmL*0rA;W~EKaV^fKil5q}mnS+RCRg*2Mv3-JS zLMfU`X_=v-24aYyq6&nFnQ9;@Vgf^CYF0}4`=u^s2N7omVtt5Xc9rLm{DZLvbc5p(`X7Nr{4XV}4SCaRQvR1Lm#x)mCZ(D-P{a zC_5o*4Z`A~a>EiXEJ81c869n{PS_=)Zf>d)XqJ+xAet&A3So+7nPUk$YX?)1*HWq` zQlU~;7FKa91)jO3RLHEHlXWSoslE&Y8iFAx7?!9gX$qvElb=iumnx8u6cpkZ%oIZ$ zb0Wf0+NmnX!KqoqD=|>0XqCexfjW{E?aZREMk(E^4l2W2+FZ5_F*$A^qV2L;Qp$=8 z5+JZ*G{q1>6+%%HMN&hVjuBM@th})6IEz@)P3_f)OpGzfBQeQ%vNzh&M1>_GK}k?e zEe$M9Rg!8hSmflH1IExXhPmCitXOX#&> z4kmhLB*tTvTEn>tDx&zxfs86MprWi*6slGxswzqunhK_bs40yC@HE+X=sGh(464S*qA0kk_|3zdm*NZ3Mio>D58o0P(ZK05}7*d z0QIR3iv=NA6)Ib0wDiPEN)n2h2!f^D8zicu21~Nr3b0}2CkUpb6_|i(0pSclDfzO^wcClc*3#wez_g}Y1?VkpFQ zl>~^gD5|7c84ATJ%V>nZn6wt&0!UhnLKw<9lRK(@h#8QL{&u{a#lB>qN3a-bsv)wEJ={d z&}gZqDgvpcqJ*M?CK-}QAfkqXB&whaT8JVjpsE6rlgEzZlno=0bCm0{4Z_t3!6^kz z0#M|PFKLW`j0h|aAO%8k0A3_S(BBK{u*J%Zl?_QIxPr`NU15VL!!m_!p$nA960i(M zEUFC>VVR~nr~UeHQA|~)D&>5#Vk(XnN)zI_g+=xJ(^OPNMi{@UB23D{jGu8*M>5aS zET$y!bVZ4DOL_wy(59_^?~nO;{i`{3wGzaVK}$nQv{KVVKrXmyn1rZ998D8M zn9X4{W~EQr5pZR+wyX~v%OVYGR){~fH8r2R4rN-Y2W&Ah7=r3%_ATmPZJw8dM^UOGNh7CGD*I&oT4p2}PO*17^H6%1qRLsOdR8W-AN=zhCGgS&#cA3@6OfYAiXzi&7hvV2f*Lh@}M%;|VDOh^d(>mLOvm z1!0UnZ4G4-4&CKCfyCb25YAjfM8;z6NU&(rjY^r3vxvAWmYZ^6Ewx5;NnLdZEENs0 z)G>r6ADX!3(a{k5D4sfdU%4G(=f-`Vnkfn*prooQqH2XInWTzHhN+aAsF0$nf|U3% zUBSvIdWba+Mxaee-wqIjK+qF4Git;jB9ze`A{8<))T{$-kQQoI8kAtn%#f@M`oW(E8j1o-X$Q*!3 zCUA*?AQDLwk}=5UFi7UH-sRhg($#WD8MVS{5dV%5CXGUkk4Q+Q!Gshew2KFrZvPd~ zwqgv%7{GzI{u6WVZ^e1BEbP_@QHNPAbn*RXrjN{&X~Ahp7rpLy>*;bTbYAB9l>?u0 z2gBMw_oWjodTafoTdPZ5r6SBmO#{@FCYPkGpF`9^6@X$OPGdO{1WaIHLGghuZRWaR z$LajBI`>fyVe9RmTXv(2Xy>yR0`8i$Iq`Wv4q{*6M=;j>3j`5gh#F_Y4Z`JAI`F_4 z2?XNH8$wkuhDQMVxN7Ik7W%;S>^z`{fzMVQUzqe>fzVz#;4GIH*qMu}p+R1etJVXi z2hVl^OkPihuN=KSLe+ukUFtVnAzv22hS?Ey%$RhmR4XUaEphY(=C;(6hPzgmKfvIu; zC_pk)LS+Rl08FwJrJ+ErdOr4nK5vx4A3TRSLX}jZq$ygUDFFWR zfaHpPKPCt4fOjY_?0_;tjC~*L^M23i|6WhI<~{X(pK%#936Z(YMjD0;phpRqu7M-v z0fpo0Tl0c8sT`Xzei(|*L@3%hVH*DlQ3N^5+R#&6ZsOYCRUgnW`!e4wJSkxGh==j} z@w9WY?~e%&cjL4b_+<7z9^m=?6{s+QfQn)vE5~`bkpLt{fpans`JsXQRM7t9J8q|U zk4y1&UZ}K&T)O;&Xb}-s@Eg-&?m0uyFc@>`(uhcYtGX6s{TQs*Zh|59+?H1KHG>Xe zRpXtR=pycy(Z*jktk{3^ZT$YvL7h(D4wU~i)*m1c1OKkf{kSU1))IxNE^5X^20>ik zOd{PX z;LNNt`Y0f#>1B4uU3~1(YIwt2VlI@qI)5Yk!hk=t2;NwZz zREUZ?3@C^$Fy9Dbb=562usU%IhKRO7mXfK?rDHrY#t8Ayz+^LUhX`;dOEi5r#Y`}T zu^4e!VT81gVkBwlx+o)9;*2!GBZ)5m-*N~Mz8YC;wBktb6xcY08d*cwLNLfyIR$$l zRyaB|92}9w!NJ55LMYofqGp64!-zOU96o`?S*J_qA;BK8ofyjvFsl(to(+hy&+7dD z@Art=!I^7B_0R0`cr=D&k~QHdc^{Dj$}_?!Z7e~g15ld_A_560!$V9yJHooK*}& z2?lUJWiE_ihfW+iS)&hljM1}3by_nP=T;HO95B?KM1Aj<;`Tm{t@}Q|^Z%#M$o&HI zv3w`!_I#Mhp^UMHh$LZhJv018e2E|+cOY^D3~U-PD&%104spYCBq^v8=W`HYKuCm5 zHi)Sn%^6eNC1D3=O*GO&hlDs;((q&q-qofh?qLKvu?&YxH$~9H3k?HLB4r%btBAe|$5U|s5ggO<0)KW!Z1Xw!LfX*6iqUg&wdTS`NcXuqZ z(a4#J%a zF_>a{D(Nh-XT=}25?MtMM{p;B7;xN4iDAJ*j$uQ~aYls(6H-B$f_5n5jMGd)CkBcs z@RB&e6j2Q35;L5QDTxrM%Pi8+rb=PtU1i!=x=kGzZyHz*bt6kKcEJ!?gN0bmn;VHY zhZK25BBQ?mXYJz(xMCV?Vn3jFt(bY?t)m7<#jAtY22A6mAw{s7gV00 zq30~d=fM=Ga`eh9eA*&XPp@fDOW$+E?BQ1G6z=xfO!ctmRKIcB=R2c1?M756V7?sg zN|^})Y(~52jKR|AE;M0PI}%k+zi96Hf-F0jGs`Nr^W-<&4AE&vsq!h|!{#?R$1jLk zr%3CyE=pW1;>oNgb<*dlIdevh0^V+CcAa6T9djYW$DFe+?s;Mop`xo{zIPW4I6CEv zr?wMaQ00_bLlo^P6zd$D>2Vf}$QW^s#(|cN05xq}l$2)U4?x7^m`E!wROiC}!`Gd>1 z*Td7^t41fbsEOez*JC4y&4$Znw9q?}F~bg9MRv>P@{=9fTw*9um~AU-+Fe|-Dxw&A zWSv7gzIn9^Ei4usqRtK&QDqtEA;(-W>m-v%ViHM^km{oy(y)z$t@-b|h?cxu%8unW z<#IP8w9c9)Y1Ju;-6{DV@i>VKvCc(?w>03CW$`X6_aNv|W|v~7X*axG)N~)9+6%1P z7A&0WebVQ&zPFu|2^@%y0`dwZ6?&8ybwRA+XLJ`!+O)ohD`ZRdg!pQB3%ATm(K`TbpxfF-T_F?9rcK z=tKxOh&C1V^z}_`RAcTw>*=m)-X3o>$#r{hvhh(>PkB*lZ0UX_K=$@`Hby;kzE#VX z@pV0xtan0pe0PNA&5JnLR7OMQW6smszHfKWcz4pf;StWfAouAUQbY}F;16>}6D zdwpf8eYz`Z7I%{DLehy_8;KVpX*;PlGoxDKLdw({AqhwED!0 z_VJTbP{UfA*S52dn5AkY^m*ByyPWnEU3pTmZq8>Obq^3rok}}mvwAk>C3ca$7fPke z&KQtcL?bnF=^;?X!ZtG;H*(YAFS06}xURJuaOG2|qUPT9_=MYu8E;T@bE(r+X?Gnl zXDhxp3FKJ4ehb%kJKMy7LnPcG3YE)GVC`z^HPi27Mrqq=2;CH8551S%+LpO}7Z|I` zrYsuG*=rN6=PlR!48o2mi#doil7Ue{BO$$GX|50w+PWR-gB2*6Ge=|R(&2^{bT*P? z;zt`^(CN{C~Zw85I~I}vP?J>qlzpr(uQ*bN*u!ILgTHIv<8z1RZR#uLytNT z9C61Q5?Op%9Dl9<&-o<44ZRK&5eg2*Gh7on)+g(-%|=b01Hw3bTqDpYC{GUUb{rtG z%QVoELdXgksG?_!I6^G2G)9g%+CYd5fX#G<8@iC%5;;)dj~d7!qFS<}3o!7i9jdJ% z3p)%BAr2(tmKw5-95A4=$S|=h(|g= zI^h~7Fue&nnJsLBVB`hSB3wOG%dQ+PL!gW_?~Ns9gcmJ_7$XMcGKXy3C~?f8F-|*C zC8S8wV;iO@8vW`H1`9T5$+7Ne2^Qhv4kVCA4oQR6$%YXHwKp0+1{^tJHEJpC6m?MUPG?XKRR1Rr)7+6~)NHxwdfpn+iLVMCUDVInZ14s8}Opn$-l z%!D1~OQb@)9;-p@CsibSdLtN_uIFZ$<_xmy3>jV(1(-s-aD~|HU6V;1lBXJk&qgvV zMwtU(Ar*Y)C65-49K8_wBs*N1beM7uAA$=cTGWxS5=oE&=BpQ;@7Lwx42$D)HlL{RM z=MK_m2sm-1f)x%~WQel`qNX^LODsl+fZ**j1_*}Ouv{;4w1n)+ zBuwDA(n~mk&Xlm>*rNnKi&@<#b6UtK5g|t!ag-<3!XeUW*Uv;2sV2m!D$v9_XcV&h zwnK#E;5lUGb6L1c(N?Hs7w!plRuJLrwY=RFV6EYpG-RUxf9Lz3Ad*6_V8+s$kGhN?sHs|Jy&-&6$R=`n(-XN_2n%(SaPq2jPGO za3FXMdDtn%B8oB?-oM{N|7HKm7ys=i@r!(|l#N;h0T)mBc|xcb7}Z~maAO4lzaVDH zwB0k6KB+lU<1C#nc zOjJ|p&WO-zUmcKh1!z9jBn@Vz%wnqkaz2+X^sBkomHBA(q$>!(RT3^0Uf0w9q^$nr?15DnDo~ zWm2ST6s!&!z*|5A^xrjCv&a44jm@!LzrQC%wn(7TVdLpiaWnhSkv^9&fId)BFA!;Ns zve=!`=WjPEt>Rqe%o72p61?Gy3==L@GI6rp$WvQNZqo|F@ysZ+v30|SmrR!p z)G|ue8*c6MnWa-s2xB#+p_=P*xlA%X)&5gXdh#bo};#V0Lmd)jC%>klr@dCKRMn2_PL?pcYbrHn11TP--t+GCqYV1_utwA`mP zN;EEG%-sWa=G5C3UQ4W2H%Wh|Du=dJL%jaCt6+mK_T)|2@(|Ntc<>+q!$6WhM-BDk zoq6Alc-}F8=l_q%@%#R|@vd{1GvU5-oYz-(d-3bnnwg#Nd(O43dG+hgeE9L>$DbZN zoAc+ydhv~V#lhd79>EJj1ke=391&PmVNxE4XOlb3tjr9Q$p@As63|6Dlzv8t&!^Zp z@~Vyz3e*=fLnlvg{${b5^oiL;qR~Sb+iV(4JPOdRuY`Aap)a!E366u-YoI@Z5<(L& znVX`t>7Pb-8E*o6TM2X~x7C$GDRN625j7>POVSamT{<^Yx`pE0h=>&4tsw)TUo9Rcj~h%!;(`^Do`ckFj#|Rj%ngZ+CP=PfX0+_in*4x?bGjQ@6`q z>FPKAH$ykTFnLyTUZ|g-7m#zbMLKev!{|$%^xXm?A&f~gIFmzG)Dp!oOrEny)OgTE z;hNl?MD|er)#&xr_$<6OJbRYXI}Z*flg|Ygfuqp9|GU;*2e(mXS6FtHAlo>846##e z{av{T>}M3c?(tLPwF1RRhNOThsn{zcP-gFy2{*T;iZ?kUZoxNEs_d9+BUU`r z_X9#lGospuc2r^8&iPzTUyC+<<}pN<6Y9I9io*-@vo;&RXR5QE$MScD9^$50qzN?@ zl{V)1hDI|}-(evF_}{5g6@w`qGa`khh-rxmDuktVDk^A|N2*Z-IF#$>#)@7#Vjv;8 z6iP$@0<{kky%|uXCbArUu;U2mSOO~+PP)n8l<^YODb*tkbhj&dAqfH^F^(dZVr1lo z-7Kok~ zBYC}+7D~H~vKA^xK-1NR7I?Io-EvG9W z1Cw6xM7McJ_CC1`?!Y#eo;KM6Jv&ooaIPXR5!Buo%dYh(*PR~m#&gsvL!hlx=)Uns zibiwyhoENk`#caFGqegJs})?$+i$aMzD<%-4+mHp#y&QKq$QwHH|cyO+Yq0{8Q1Q^ zs!VB-_|v>uSTb7PrwuehFfj_5(kt3ehOBin?!qH6CoTiMg58kkWOLzicp0-Eu!_Nl^R%bX>X8t5!QGh0 zc46Qo7>Umv!<43Tr*{sV6zYLdIK9Vvv&6Zt=_U-V$aWcwXiIio-82~aJRTjHn^OXc zqhfi3-sv#lW_dCJAZw}1yx_c^A)A4lM9s+qTIHG>R~cMk%c`(Tg8+jjO5>%t%K}BF zH!Cx=(P)K_$ELVD3$tkRrE?GNzf4r)40V^}kqMk@B;Y~^K``#Z*I`+r?O>;6x+m~K zux7ER4=qWZ_G<1Mq)*fcn{ui1*++@?SisNfUF{hpamNbmfWmdMF&U|839O_@q|Z=0 zzHYdX;_Ic#a4Tj!gU1nRnD$(trh&A9oG8PShA=5iK|AJ0Wr>YK?e<{+lRdOa>5v;^ zcZ;834JDgqxlmeUyx6*XE7?-ydVwphvP5HGN3MHoZd@6MC~z7)Z=J`e)C@VqNQh!K zJGM8c)>BAlD(pE*vV(8hFJQ1hn%ec%ISMVIJH8u*=s4zqEb4_#qDW?vh&7#iT!?gH zDut!kJ?lE*_MPm@VVg=6RQR7DhH{ca`#6J$0*OG7J2)~#vC7rhmp8*D*p~L-N$EB) z<>H~4Z$Qm_dTquX_)0%l#=EQ+TIzeo=wct-lv(Fq53Hx+^x2* zkl?IZQ4<4NVVWH@!{4mgpal~9@K2_I4=G-t2BgQJU^$ffF3He#VC-Np+jw9&u@335 z2iqhJ&pq;|y$KS~>O;&v%p}jAhJ8sNFwPldg7VOuw1r6ttPZ&f5qU}vNd%z*+$P`- zQB4#M+PTV`g?Cd=6Oabr0U!z_KI?ouJA^)i_AmiLeY6vmtfItxgOJ~fs8GQaHvyD; z?Z`2hp~h$#n?x}dss0Kq1KHUcu6j>vn#o*s<6#>JhcV-3{$vV6$VQjz^wHo~ujPIrgAj%l< zm@2vkYEGCTGcYV6Zr*pV-j;d7^6W%=GB1g&Ek7G^K?>4^9iEHF24mc)i{ENTgpSB7 zM>U$uma%49H66^>$q-wiIQy&NN1UkOX*|b0vtj{ zF-|rWUU)9gAcXGv#+hFBsj`zu`w7HG&slr#3sT+|u%Q~6$2Z+vd&Iovo)&v;h=#72 zY1e3X+)afz;UG736|rza=~xvQm6x-o9EGgQNCA(Cd1n7-dkG;ebAxwy=8ScZmlX3+Tr#j$TiLW0?t5kSha zLgGre4o@j4vzp0w#c*VloL=4p-k%*1%sy3DTM79oa?PI;c#zNIih*4a#CcCWy36LGdZ#J z!J0C`sgbYb&?#wUgYbA=tyk=HFuac^b?v5!aH=@*jLqYlSqO(ZipgY>plE`-l@Tnm zu#BaK+SX=jBX=C-P6grES6x(x8Hi&5xmvqc1}`njVUgyvVIidIZnMT{;e(GPOHW1e z=0)4CXoEAFDT$|Gqk>?2JU^lR<7)`g$LJJTuYA=R?+tH4Ea{MAoGzZ}x}UsGYMj4S z19Y+8?1wY79%Idr)qc!1VbXi5S+p*lVi#_`QjNb1_Pye>O_@F5sSzsjBf|l=mZKnr ztv)sr1yuBqLy%!a81?T1VH{_?=rFwrlA`gw29imKsFr3tF$U_vdnp>qXlvo>`5I*F$0WFA! zbgAD%Y(dORz;BKK%v_yENh7dd5e!@qnangHP~)v&qP69nZwbAC&7DjGmOu(C+~sYB zM5}KTEThjBZBfHFc+7NGq^nC7K|(6x<@v=8(d#-u!b;NbN+#}lUjwJQt6pYwjXL6i zoFNVmUJ*fqw<(@Xk+toOa`)V`J4bZjrR|4~8izL6$~_h=wjuN#G+mcGE)h%0Sm4c* z#E@^L`dnban8m^r8JM_NC|T21t!5~!xr;bL*4dKT?Zav=&a2J{b>|^z zBT|ayG{t#qHtrW3%v`DBPd4*~cR6*T#8E(0OA?f{fz{9hC8m(L$!S|chLlJfx-f3! zaBgMt;w~DNs9BFtr*(P^G}hzM#M67%bp^b6J<$4sQ`o$6pDZKL=ei3|uiWNi-8n0< z@m;4JE+aP{2Sg!x&7s+ImWGF6&5f@1yv9tlm%GIg+r;5E(v~laSdVTu7(R*Bd&eFE{RzaSPeg6X|Z>slC01cMRq5+8npm zs~Pv64i3uv$%^EtH*)-@ueSW$Fjr-@5okvqJ68)T)p4cgZ8p&7foH|i6|j(pa|HVD zAn0WmjSOu&$EPyjR6f|&LE##Ta zrZW)DxWeU~me(JT9?=gw^N{g6TTovb#CFqJJV(3lHv^J_Pr7LdTZMs}X7ld2me)js7<($b)x7uFVq*?bno-!Dd$Ek^lnDF%Y{oUV$Vv$!-XiZy1Sdh9{ zMEN-Vg}QFt_3`(zf`6y>Z&Z)jo1QE|63 zFv+?)>IU&v^&LgFCo>ka5w1Cjfm^|mGoI8HfyK2pEiDO4ecp7{pi^{u*ce zEZh~gWw7I~HsVYEJTT5$7~|2_DuTL-329I*OH!{WVq&$j_YKpzR(CQzHe`xhOv{OH z`EnFZEr_EP6Kz>UtXT5HM5$8>)fZBj(JjQ{NvJFV4K0GntprPDi7s)|MbxlBXtq*0 zWT`PIiIgcZq2r`B*$@qv7Cemv- zhVjLYa6#rMx;#ll28bP?anBZU<4zxoAZ8HOam`_b5MibTf-IA4g327S%xaHpkoZtD&1=UOi><%8apIvmMZdN!-lF zRb~d^=Zw0Q3?zsHM-fH@-hziTv(tcxI7Jj?AMKtrO=cW8Yhi(4=sN1n z5)`C+HbJ`}QDhY->U{r!k?(evxKLm^`aU1At~pH$$BRtX8_op z=W7e6?5QV2ULFn67eU^bu$zgUI8OMZ)?mul24V+MINM`}Nrclad@_qIuyaER>@9^f zL0NZrLn6zoAXQ}>T4cUsj61##@`X=^)~mEG-P+>A36e zGR%$FQWldl79(>JZp$;5;i^}~Y7Yxb*P>3 zSqzFX6DdfD+DuT>5HyF@5N&5e#u!0KF%-*j7_1SHe+W2(WyBZ^!8lZ5D@V{uQ2{K0 zRg@`37%>>Mwu}QJK}-ZeLDqv9OrS&&g*Flfp>l|#7-B*oFvk_6BNB!*65}YtVxJ`| zCJ<3UD=3tuD1|9x3R5J3hJkSG=l`D{*!6#ZtiLbNeg7wLcKQ4LK2Imo62R6P53v6D z)#HDDV^KG{&UcgVQ)&tXK<1Bx3_JPW2&*4>9^kf2$n}#T*KRT*Ftiy4$LoxzeC6tM&%4%Hx-cr}#aIv|4NFjhh_D8!LN z4I~nTKvPINu!g7{fTL5Q7?j8`fQj^|Ycxbd7-JBcN}#MW1pDxSt%#GZtJd`;+g`eh zuNdCET}|&B-Kj5BSjP^%7{SUnAk>N)3?f`f=Mfr1^bRA9ijm75-wH$v_-Sh|gw-1c z8H6UXPeuvR>Pjk$Hpd8Y2eR5@bp-@#SpXr?v?)ETzGViAiUQh4^NIlA?_V)gb~ow)6M-FSdJ{w%{ZfCLkA8} z;K6$cCwsy|@Pb-SBp7!D3`lGPY#>lIkj>B#Ls8NO;7Jb{1wy3Z5Qd|;1`-<|QeN1y zPMxrZ4y2{B6K3}S;mZJ00ZpZX7?fZYg-A@BaABySEegO(_n@7TaX*vR@zU~T>88;P zkw8O%jw%Qoju6737MQl(wkI*y)2#NP(gaM#1`gbvrXy;7o>oGD1fwd+;qDYqp;eCH4QR3qqLit>|tz^7|adEbECoS z;VyyVA7Vjnxun!}${JVKK%BARMO{4z(J}AR0(-G8|48!g5K@ zOao99EN02MlUc?!q@0}QXo7OoDoMcSFb#Mi)?!J-IN}@-l`w69G2$Cy2EZEt{~!7O z@xvL6{Cs!bW6BRKL_En1VAxi-Q+V~SahtvGbha=V?RIv)FQO^xTnbzq$a7=0WKE05 zX@My-A?>pSDn|6PT&mcY~VZjViXtN+F+d~?y=+Jyb>Kz@mGViZLgC>2E zI?F8h;mtlC7gbeqG-{@SQarVEUJg+>Rw4DzI*CmVTu}ByZE4$TL_V3_djy0O&;HA^ z%)wGduPSO@BHTiOO#5rJ;G($mVN4pI(ju_Th*WN2ejFmlFQmz5p^h@yE2keXqpjs7 zMwIc4Um?;{RBIb>MH0=Z&iXz}a@HtK;d_;RvQB1UA1u9^WgLaH65bG|>P+8gvT}K9 zt!N-0gyX6xd2tgW&wblv#wQM9qn$LvQx8tOoQ8!wX7{8w9gM6-P7y;wZ+OjSnJDFi zHz}GnLv)~Klqvzc0Hk8G{HomncnCx^3jj#PcR*W8a7Yy71`vb6&J&j)5q75pQ4Y8; zh8blU1(SqW9Ly%MK;ob{7jOjtQnalAP@h-Y56mK6I*0rPJ zwX4SP$yuR~Y^sj|v7Cg)qf$2xju|v-h%W@GN=JPbGWJe0Qj0uCQ(D-(Ho5h**Bqt^ z9Lahkrb{YDG^H-uUP;{GW)flt&=BUk22Q}zwnqx=hMzkQ!eqy&koORK{l^cN2{ff~ zQD@ECTewg|n(oCO$G9MpODN&uzA_JuAu%D*_r#f>2fAHfh&<4&Z?InwNe0|)nMmU^ zoQ%>*)6P9|J(N9pr%|+B;9l>b$obf#UqQ3Yi8CaGnUFFpu4qAtQ;5nhrWKl!$Y)IA zV%&y#$tst7Z$hsJGtK<}t^XvJY|+s@2)_jMG7kk`hHg`hu}K=dn3^_W8z9D{ZDoNC zB@6_8096tmtcfn^m_(X@(#WLUvTFqm5*(3Tl7(ysY7$lfcPU+vm@*kH2(ft9hjNq- z_=Gs)X~fbyRNnNa%OxcljXg_^-0Y} zIa%ke+}7c*W|Gcu%qzSikL-Edha{p{M4Dq!o-m~#h&j+`YVuf5wi%BYKN3l`gX}0M zp$}X`IOx%vcXv{xPP^k+mNt%StwdIYq_xAP${xpdqErxsb)FwOS>AB!kjF$|)<(~> z<4qq}x^7aD@TsFr*><>XF9)WAT{!w%l%z=UN#>o2VYR9>j98gVGAi7V4l2z7yZV5J> zyAg|mH+3In6z@l+Ri7ynX(1N`!+-FAJZa;91v!d`ML!P@4+O*P=T;b%tb`o0AAp#J z7*gc3lE@^}g^>hVYz3QUtmraz9(%5~Ai`p&H zjw~>9sH5QQDSXd}f=MO`_{V9gG`%&>I75wPlXStz5(h&xJAnxb0MsT!LiOx1+=k)p zGB5^=+ZJKA6cDKiyJQSVq?wimA#F7Q-7^MJ+$mWhyI?tl(@BjH876H54Wh_SX+QGj z=kN2}xAlloj8JpNPZ-`jMyq!Boy4HjP)S}kI^fxn6GCb?Ny7!c)F$-OW=OiZAg@Gc z53%Fflh(}eGY(k(#&!_$N!tt%&0$2enL_h8&jSS(hVfs7pjOCX(*DkB%w{b7b2oaIl^qmtS*bJTaPq8cv9P27O+M8Y@pt0lPy*`+e49P zqjLzVF8pSO;deKgc3G|%Mr(-7vo2YmLQJ-ih)5E;MdppB-S#^jBXg)V8!V#40u_DJ zta9^n#qoMzh@LiG)VrB$zMpfu%jcX7ERvZDcwnhz_}TZ7n^u+!EXD%xSi+3NrIser z6wCp)BJC(vLw13oqb#4|=P)=h%(Dax%1$oPNN&p}A)tX$1r6K-RRLs^P16h$QkKF^ z+c40i$RZ#0Pj~Oe{deE8JF?#QT)KUtLn<)dBb$nIh@M!Eu zh$==arI)GnZLH(o!Ms~GavzP}1olHn72yOB zX(xnXIierXv$A)Z*Pz#hDY{Ntp>I@}a!IdVYXjf6y8X;Xn(gf6pA{QmmF&ZZ@!2@?F4kd7a zsLTZSzenozdH#>#_dnnLy8l=Ae_sQTAktN`c#Rp8DyRxLBiRw%4JK+SKYsoA9{NQ{NUb1{ z1Qs&OFk(+yNyQe-i{`)1iDZ>OXH9^X+i3ozqZ0XS*DkC{Bk4&vYSBUY<1iu8o3k8m znUP=4o?@)cn{0gI^G_PTo_5I@t%pH^+s-Z+TU_90?@9)g!_+4Oa=#3bZU{J;+mJDh z-B@^%#x5b7J5Rp;IQ>DH_3`

`q)WbEd@bKPAB!MIR3%!ejZuM#<%~s9gxP+ zDi*}CZ-8Vtz_*-a2l)ID_TyPDuuiw=+S=-)*WoGwy&Z+2=1}{bFzx1s6?pcSHr|x~ z8KVK(wItPVmP7}Gzzb91zqy1VHZ}8Xh#FYax7{>gtFz|OCWH}(9_F@N?7)qFoEN6+ zJ_8%@|J5l>rXK?cmRu6B#F`d})bT}Ttu+k;@z`z{6~JpaT-tcuKD_)ogoJ@6@bn0W z@Dd0dz=(!(5dd=$5I)=u0Aw1K`!eJk-Xdf)WDAffK+*<4h-xwoSqb|kG)RRnwY+8! zwThW3Mo2*}L6nB&7C=%f%OZ88sZi=e=FmEG!<-tCImxIOiAN)OE1gHRF&@MLUzinMidAZ)%bkhAQerAtW^dWQI!8 zr{IO+4cZ?v!@>+IK|tdq#Nr0LU>hDv0Cs4$Z@Vvi6Bs0VPETb0O7!MPlesW&MkP%#L5%L5n!okLj+ za?%B44MU^En9eFj9`{4Tm6EqOWCaLSXv}00ful78yUaXcD-@j*a=~UW7Nu5dO5!LA zLoJYqkSY+wCL)2;Hvoj&gq;kboTLp&i2-4WQbmC}Bm((Kj4?3-z3jL{iiZbwkONr*9c1DX4>u<* zl5v5F1vrE#hgrmc>42mS$P@r`mwaLz)?N+?l=TSXKd9B-91xEIemW zCOVLd4d!4RNkIsAoaPz=!!vS84ff73#Kbtj9H2u}7z$z&w#hZ|hO=00raTkn+=?kJ zssfxsc+RpMLs+F@1hkgYR!A(7_QMdH-eIgD)WYGcl@EDmn{g`+G8dPuN**P0N(XY% zW@1bsmmH0nLV?*X6%J+(8Hz5U;#G3xn2Z>jB)lzg7NnJiWs**?A>-m2SHmIVWu~w^ zdB%jsLs&wxP71j$;nuMY$Of585ZnXAYF40}u=v8bal8@*@9&ZtutgY+G(tqQG!<}Q zWCrIVhLz(1!N@XNLZYIAilV8AO@nQ*v5ksJSYPeVD>&n2MhA>n{pY^E7thUNA_)Fk z#Zh3gejz~wNtuRZi|5QK)EQAWKF4Q1?!G&FJG;5!HK~67XKiL#ZI)SSrBq2ElT9?! zOQe!XB)jJvXy-c1EV8Pqs;)TWZK~5vG}}!!6+3OT;tZ;jiKcO|Po#BQMj0%b(=m)h zL*`FBg&o&*;TwRVm?;`5Hz4EzMNky9)g=x<84I{EoXlyWhK7hJk|==b1~E}0($EwY zOA-_`l|>~2QjGyo2~UNA0YxzaQ$b3R1qnq`tsoxXyoYteXUa=%H!|2W;BB3EP}E|S zjkMfVVuI5x{s_d-(vO+dO+&a?siW!D=52&DqGX*p7lEL@iS(!YL11@vbQTXR?HOhR<0v0JUMr{({~kjb=_3? z84Gx;tbK>u%DtC}>r-*Bx=&ukIZs!Tvg@a!t=`=e*_E5!GdD9cH+|a`ccqUSylYsU z^P8|P^SXcA{Fy+4{*pi_2d&7dq%D!9J888;4uHJ)F;I-WhN^a1SeG_GSrm}4$dkN!>uuJqr%a# zLEuM13AF=CX*YPrg4Q*)-bx=yIh%_%-7=SQd|?cHt#XW=tXQTRY5US!$7XxIRLzklU$0 z!@F@xer*unSG>uV_KBUr#~A^wbaCdg3j#}~0N9WufXi(-c+diUXcZ(8jK-W9@;1U4 zTTIRvQ(56T_;fG6X7HqmiJ2K&TJ9A3gY%c8PcSiEO9^s8E0?-hX>S=0d#|grcQLJ~ z)1^j5nHVw}@}|8sc+XWvaJ?!K#$Q>-y#n@~g)}MkSUHwF6?n6pPH8U|u%6RATo?9d zzP~aZHpxdSg8pj=!H5AHm+?mN4}TE){=-eF(MWM*Ld`L+pWZQ1sg2`DmSh!R`eu&t;f(#nxg>k>T?sGXtQ=HLEO}E&7QgS0;wqhVsW1XPxWbl%|@cPM!^o zRL6Uf4P*#?abEgZ$dUztM?41bBU+sGQ(AHdlcTvzoovn>4Nf+> zB?T5%{Z&Y8-fbaAW0gGTi{6dFbxY&}62=uSVM{tMEPfnA(~O>AjXv}aow&zm&222t zTt%UA@2gO>nGeh~{LV^`bQ@wZ%5r;dwn^A!T ziE~d`>wL796OV}$U3=6y>?%CN+t)iJ=eWFl;>-75w93)i3`EBmKH*-I)Z+IYy$6V{ zXk^-SFFP%Xu-3aq@=Q0di!Euc8L`fvGCe6PZi(fLk36y6koGeR)vMZ2SOI0R`O3?>a55g3S{DMk>%{NrYQdQrl8)|n*n_Y#dltsK>>)8{)lyd_K)jHm02 zK8}Fu@^(oHvQqW5%em4g9Dfv9MD!g$YYLtmd=DBIu43OsxVEsY@^fw((2nKC7UbmN zSbFTbxYH-1QNz5kwoo=yJ6M8u)gT;|-`VBf~}S ziqccIcydcOsdPEptkhSxGsYFMMq+&r9OzG-S3@?4Q>`SL9Zj{FO>=&R$v;z=aJN5x z^yQcLGWfsW0~AqfcX8v)x76N(s6y)7Cpr&o6Spa&(DZ9`bFkF8wUN2l@}!d9{AEz% zq&r3OAXso@`*29>cU7%3!S9`N#SU)q#jl>9WrZs@a@?TrS)Qy$;c&$ha$&Y3hdgdo zzQvd}7UG?)DNC}!5M|yQ19-kBobu*mq1lHP9B*($k$RdZ#gAC$FmEyBp546S;(fl^ zMof8WA#vgv@@I)KInN;1s5JB@cld|lnHpH36k>sB4(5CVV4C==w^R@h3(ePd$A4iWge4CVn7)ZK% z&8nkZ=eK-;bz}M!ft2;3y={CcFv@f#Vo)fB$+;*OBMD#j%;Af%&Q%;N`x;y9{34t4`4 zkwq9#r*>8cfM~2xCP0!ZY<3*oD8h*A_hjitb(danP48s1b}7ps!y3-^*_r3+CPIAu zRqknI9*;)t7I%KnO2Q$)CD9Dz6H(CjEK$Ouk-_Mg$&z_goQ=z@Ovd~xlc)(8hX9Xz zppGE|BM?Ku$FQ$48hN0~J#{BAmhw7$H)USoenhWxpl5tzpP^ZPzhOs-@p`Ldo`ZG= zSlOQPA{%-W>|8w*#-2L97mYB3KsHWl4jbl=)v>wi_rGclHr}JrFE2AI?C|Kaq@UXU zI}b_Igmb&xc(|R?N@)k?w4ZJqViM=JqPD2*b1|V22)nY(n!y~^RhI0bA<0FwQcVm| zl4H%VeuEg~)<7>0spJsH%oX$AMG=o~NdIVrTeH&v;lSrMSS%Gohtg)a{_)L*!38dG zg>g1_BONMOSuc((!g;bgINUXjGDODmb2nFsDo0OUx<+$$v+h|!J9s9dU(*slKe#lY za^S~VhoP!7TXdhy2{K(X2{6K68bpZs@u-?gCDe)qpG0W2e9NVQ*}(|;I|;bl%AJ0>M3KoE#C5H9%2gi zx`)W4eU%qCQs+Dno%fpNwG;AUy|>ui>Xv~bP*xef(Y9sc8i6wcTAx?VM1yGo6Qe zBE_4x8BsAiG0&EaB|xFpM2a=eeNPz@WM*1FOXe+v_tJJMu9r#$`K# z7$lS<{7d5fLl)b*`{ib+nrVA$9o&{rPp;=NK5}b|sP_A)lB*cz3Zk*h$Ra3YpVUo07{y0gH8jV^r{ihME{|7F!l%R}@3lXMeg{m!4#FDcg`Y_iWxsb+UC?Yi~ zXLBGsXpYibRi&T$UAd^b>Q^%6GK>{7GD91D%0Y7-!(f-YyZ!vY#u0A}z_v_Aml6rg z&CssWW~gpJLmH{OW(W(paAPeo#v|R#KuDmqs*a^H+m^7HnN(WaMzk3+lm$gdw<=`@ zC1Xn>ftHzUQR7o=CazV1i89%aAX`e?Yhoy6u{UlkbttXO!nu&CD+=5Uz*5>O#9|~y z6$@(A);Bntit!6`47LhhUEMHUN{EQWLpL&^b1R4U59ZPd^8~xw;KR?_46T}~>P!MH81wfDj1Q(b&G_esa5fwre2~tE9 zg%s5^Q9(q_G|;Xo?C7NGAYMa2147P$WT)#GolC z2#Ts9Bq<6hVuGZGCI%rYiUNkJfWQ#J0F(knArOUN0Du`0kr_ZC2|*+R0SQomL|_6C zUBB`nxD6A21RzV<1L6Bh<5r9cj5G7?o0E7t`HiIPNQ5eW&K zyCRy531OIGmWrgM5S0KTDDN?d$d(8qDpeQ|S`Q412oaP}C*kydj}ITg_ci@~h6bcy zbkhsh@AcWn1W<5@f+TzhX*|*`_iK@VAID;Tz^n<;IYbBAK(|(&YyeHT1eXQKGejB*+ zHOaQRxlz_ZPc@lD)ozzE`=h+;$35)5Y~;c_gCSNTL?ert8v;uZK!($dEa4T5#D)#V zkVzpZp~nPi1{z^z2&3_*szFn(8a~uMA;FToAcu@q=MHHgg3mLd&ki>p4J`GJNJz{h z)>-4Fp=qUsoe+VYYP5Y+%?%c7Mhy~1nFkD(7%YOIc|VWB|6lhv?Jv#$FT4^$@94yX z_5B}St$h{}ijRtWs+;)vKDx$rJ^Ja5mtcbhV~$ZGJUF$LyDPF$O=dcL(R7>o#NjYk=d@cCgA@CfmOE$g0&fQj;;+OmA(p1X^P#>|^qQs^Yu+{%w- zrqa7>1v61oMVQ^vU@KR8R(r^wYbkBT+H*ncGLUwhdmr3$ddwy1e#)+M)k6j%i$Tek zCx@gi&VfzS4=hi8eQuM`kS%tT?T1XGyZm_|egT%s0ADnPvW(II!z|jUWqYVY)MkvHYEvV1<#2IW< zZI(2VT~y(Tm|&3vI)NxfJ_b`{#HOI3(2%f_87UG0f2PnuT$a3P~^@IZ@hK5m0AYQZHag+-Qk~tPoKY z6&lEbO|(Xe0T_lELn4Tnsc8f$5g>tB5QjZ45sd37@u8Hd0R<4Ka)F6MaHbN2kRY-} zffgtNgq`iJ-z{M>h$|Z#sw6YR|04I}3QXo*2 ziv%l5DUdHc-VYO#Mj&+xP89GN5fIxr&IyW^NR}8t9H2@7bVz}apb9A=Jnt~%1SqiU z3dW^a^<0QaMaTi#NfHQTh!{x-RzU8;tbr935#{1T0~solXvH!}B}I6VQ;lP@nP#ek zwC(|nF;s&%*O7%mqDT|gNOh7P!gJhI>1TEJ&ebroRXZR z??_vOnz0Mb08xXGMhsLmTWE{D+a#bi(>hyjuLkt#6IMGpu&%3*>)D-_Ou5y1RE(Un zmP)FULY|5livT68zm7w*HR0`RsUkh^2gI4$HoR$H2&?x6j`vMB^ED5W_vJ^Rg4jTh zp2~N*iST>hUX$@YV^2-AczP@4a_3$2Y#fEb4e=N)_U95$B6`?Fg*6yaa)~mKphIiq z>NU=@ZmT&RL_D2$7hHMF?*~ePGZ&l`GcQ6*4AhP=ra~=}(rfpB%lUnzl0x|4FK20; zo=7?@A#_35#pt4I%n)i}F`9vlD^7BJ8aeXM)HeQ&JQn4Js8%i9teA0fiJHQYKoGBw&`3j8M@F0RSDdX0lMoC=oRP zg&+kYEdUru3KR;dsVFE4Y9bDAj?oirkP42R74OU#E2rfR!C!kp0b!xqSmyM zN>xE26-`niUY)@ z3euny0_qBwq}^kHMG#U1gn|yB8w8KI^{>0(0z&F^dW=<+k4#9j%qS4Z%H%^ogt=vw zolJ^|sqZ_^X8#|}{l9~m*7(Gf2u-bRXq9KO0k)lPGomP%KdD&M%}H8o=bWQP@uu#Q zVJU0K#E}X`bbnkhND}%=Ye?O%9FO@#i#5<3Ida1wfT0njpi;9ip&F_Nlqmp5F0RE2M@%EE0}DnGQmy1q}7<3PK=kv^g~H0mzPliIh!3ZNm~IfJ1VC8X;*CNv4wg`7H7z zB&c)ye{QCdUT4pbuXmoK-^R`4c3%GiAcNN{&dgejg=oyq(M-EZJJp60T1FB*qdZIi z=+0=eSy1L)h=fD7kZE}BMpger4;O=!L*av55^a|y70YFGTHLrGY6&Z&P24c%7;?Td zi4E)^=M08%VzLYhTP6f>VgrK`P=@B0W#QUM!U`qZ22vwE=UJ@x79BEpm!ZZ;7#%Ub z@ne?HuGqA85l?1^7ct~{1o^?yVkKf3jIqr_0f>JNT$aSkU(PmtjII>|Qf9tOh% zFwi&;o_N|cs`fkimWBVs~>0k#w<017}%re&f`hP9&+h#Fe~C{n;kg-D@e zI+W)+noEl+W(^TBg0A2MqKZmEa-wKinTZerc%uv?h9C|VOfYg>GQoxd4UxGuM$7=h z0CxZ(+tuxWbbtfti>|+8u zAV(wCW-w?tXzY&-Ao#gH9U&kN%)=i?}qTlM?z^5EJ2|sjFJO5#~^@C z*EJgFM&%TA1G1!goMI~J+8dkZW%c2>A!4fW55XJ2;y3T`#S?t$3ZB>Ou;%`qR z2X4E7#!eQj_c)tiXwKlixmWBQ#6>wyakk>53gd4jsFM1w_$w-03OmtM?e;+otoLlw zFU}nv^BnX$a%TGEg>I_778G}!oc&5HIlPbzTSXH8PC!dHIwlp zJv1MS3L@V8WDDvXsTb{P^zi1x3>`mXz3oLHiznK$RYoFdfRqG0@_^uk$AM%KQ6N(y zQ3XUxQ7jP5B-BN`LV(H%p+GQ{8l(eo8Y!TOY{AHy(HOD{bRq^YAu(E81rj1!P!$kh zj8M!$6$I4EtFl6sbrJVvIOHKkUqFBrv?}lvWysU+$nJ|fRNOy zN}zFS8e#`z7;rg-F(n$zSRlg6MMEMXcWObEIYPUUG)NH$Q9#g4l!6qDN`XoVN^n4w zphRVN|7@glY-E;jbW(U3(FD>`ze2PGv0M^B-)S1L`iIR`36BS_>!V%KnDFmbF* z1*cW;da%H=pnT^45(_hK%>7@Da%1ok$yxZ3=#m2G@&g>w$4KPug}Z3je0%F0zaJ3~ z_3wIfYkFAbj19HX6f{}Vo#8zWo$fD!b(2ydPskVtxj<3|2x(5)Z07ui=o{{QC*t-# zu5o*#jupCc!lKVnFhgX{*>8K}ca2@(h&)hyQ-&df6PDj7VSQ2ay^C09i0?R#Dj0S5 zos89$&im{PJmYjuP>Z$)kC)wLS4=VRn@@hnBqM9~IS3J!|BpsEbd`6Xx1HyX8`luz zCfkXFAt9_@>1OwIQ#>Sr2gR6BU`!fEoJDjMNGg+bXyJ5Z9S+Azb2|g9?dKxI64FEw zKoJZ~MG;a=pru63PmbqlHDy+248ascHnR|kL3Jxjs8>|Pl@kyYK$Hzoq|_*)YFAOH zJLEDbaKi}eBQS$0g`h#2h2m6Sw>p@DASmE~GANgp7)TV9ig5~*3DVS+R7qG^!GwW| zAT_9EDYg|@492K}HNncXDG^dyrHG*<#DT6dKwc$nl@9Hckbr2Dj}T#n zm4YQ7{)&>STsq^wzR=iX+bb-rDn3$Iz(xJQv zci63&fhzye?h-ReTU>b%X$tE5r3JEwQ6xnKHWMdM+ zOGpwyNG8%J8x+BaRX1f+nllV4C@3nKCLj!uik5|HlAIzi!ND-aUfDx}P90GoF*#v1 z$1J58QwvuHRurLPPOu1Z$5BF-z!;FJ#O1I-Or!%qK}8{qtP}+$M@;HLHY5UZZdHhY zxGXr#asn}MkjxxKGEZ}X{C`8^07rwF-P_OW>+2dsYvlL8o@y}|>qLC->zu8kjTLSO zA|&}3$M7%5OepZRdkK8!idij^iil}AggoWYt)>(*x@O&f+~;#;X* zq=&CFsKOVcMkIGIaI*5bB;V7V{a)^3q{Fh$g>+s)D49j^jRVWeUyp)>b+LXvnJeo# z$2^A?mJ#t6Bh|R}U(OX_tdg|MatK8Lk;#a=iuu77h&(>LTW?=DWZ}Kv$Edxa&&7$V3!UP!S>oKyXAsj21x07BFCyDYVg<1>(r8%qXX3 zVMH?^(ID} zPB_2_qA3U=ik5BRl~!Pjxmp+UdITh6$De&=;9dBiEOQ>QspoIr@4inr&5*-98w$8D zM71QQTRAOyPn{W%)Ix5K(sAjpSkj_EGc_lM@~Qq`-tH`cu$m;pz?|Q{>_pNaQG*y? zN&7HDC53g7q*_~#3EtGq!0w;EG=`DCCm|k993D67YGgmzKOqcu4iMPVIdLreI*A3Z zZMhXla$V5#OCDiRT{D}*4s!&Xh)$)BG(2t11Qs~}gNN^~lwlHhu;}a1v zBuWQuW*L?gV*+YWblh>ANQ9C^%0N4eB{0FsDRuwNP!0Rm&i0DWs_gh!Dxi z5-nzNMul8-i$W%A449aV;{%Q`1VC8F<3v#s+7QbUxI?4D57pv9M`tbhJ5B=ebr*lX zdiU0}U&e91>E~Ar9+>#0N@5NUDhOiIzMs={!|l(ZrBDgCnAJWMJ3k zFBp2cpb_0Kk;ItZbr&}ot1Xw7cQlEcSc=ke8!8|6m{~0a)PC^R$aB(W%{AWRa`sv1 zHL^0iT5-Maxc6QrLM53MAa}(xXK(M{4(vIWttoMRdgfe5?o$wkY!iNHFqZpTjWM}Y z5>>L=)Xh5ZfCb%@U}s~raYwk!hLkWYaNf1tum8@A{vGJ(~f+ku_q%{dfSrnEK@NofP z2Sk!GH3~4ILWgYTmI%p+Rs#`W9T*2k7$Azel^Dr1;dL?Cj8IskITDE^r)t%jGbi?_){6!j0!@ON#5OL zB8aOFM6{=Hp;=&pprarx6ktyoJJRYSBv4Q{mZ$41H6iQmk)ceMNj)cvH5rWv;`F3; z#dteIQ=^m?CfQg}hZ@SzrR@uk%1&O9wQL~#vN@Jtj4OnHY z$nwTHo91A9od~2Og%+&ZL;?~w_xA}H?mX*cE?mZB()@M!ol6;*fkS+ zNRD4^lbLU~xOh3{=0-YMz010JX~wgW3c_QtA;i*hG}Q@-G%$m*OBxl~F6)xsWl1Vt z<{=qKCFFq>+zT+Pb8gE_*2P_-(8#tlrsWKE%vOcm!v!`YZWmpeZe!O)cX;MpO5wDZ zDT{o(-enFMm{%{GbuF~ph6_z@R+`@4b9r^WH$3F#QBkoGENx3<8g}l*aogE>caGKF z>m1u}9;$;=8Dq?_aWfGhsJ849mf}ZI1gZ$i?L~S7y%^6kVTWGY)Pi7N~)^M zob~3`!@JJ9>(8GaJb2b_%JJjJj~91$d-dznde*g^yyw4Oy!!Lwo;-N(zaBh#j;7zA zID>ykLKL);10FZ^*~Rqt$6T8b)H9T{wTQ$(@jkWATQ_z$?JRZXak$c0nhY(!M@w+szVXJ2X%SlpC z0xe+#vJGrvAY`C;5b8+n(!~g1#iQw*)p~o^cw@;?d=VB(d2AnLjl7{El)aYbVTP6z zXj@vI6H4cEHxib^mQTZfuz(oUn@zOX5W3Gbql)J81Y!`7ZGu7@Lk!FW458xF+V{JJ zUR{s8%)?mskjt(AiS}`bF%>wIpV5qmD3_N`eylajD62$<*@T4 zWe=I@%e1VCBWiIi$z8ae$Js@Cj3Mc_%bibv zShZ0sLL&<8(b*4Jhs^xl9pF69tjjb5k(R3Nj5OJj3>ChMZBeF@Y$X&`l2tqw+qRl1 z_iFt|aT~lreYr~K4IHI4)ZJ0e*M0lgV`7M@-w&ugzRDP>c6+SW?G4&2ob`1ZlgVLY zVkG5))Xwu#RE@#o=nkipt<2)cci|LC4&i47>tYhA4&%NXu~?5mLgKxpIAP~WPnL=1 zY107GWahMH(p-ulioUnJHWJ&XosO!*2nr}?V9mv>IyiS0bYXI25J`wv68!nZ=)_?% ztMaTdlT`bnT45o_fpCgF5QIruFG}hoF%-=DRSCk_9WX4`Ag!kO{cmZB(wM%m&Gs-0_C*6n)4;0Gp1 zV#Ziz6n438(RZLw=lKb^mSt*l}?Joih<~2U{X1|oiDOtp;nc$Yh8>_VGdYu@48TNFx3?$Xo*yH zlSFJ)s=PRH%d@T;_(i}cT^>y$-)Dtzy*-f1JazY)rfHF@Mci{_Z1ang)Xv%3JrKm= zC^@N9^Fpj0(sh~w&%j~&lL*S_AADAMVK>8@Q#bj;1o zC5oXAyuW+Yp?U@;X*V}lH>K^Ib(v-c-KrIX9g!he+l-2BTf@DHZBkAHlLTQU2yTVd z*LyPWkjCDa8><#+2?pj&L7inj1Hikc$SR!F7l3br<+(Qj1Y&2DgsWeEN zDn*Mn?A(iED`3l+E=J73xXhN!!!ArRWhruDnPp=am29PRI9e!H#|*$OQLGCdu5o7bolkiDbmSfB0X)IncD&bTS?y_8 zU4!A5W`>HDS6b{Lr*jT0=;Tjt0T2%HusC(yl8!Ji<=S6V4>U;T(7Fz8;xDtWXzR1N z$F-}AGe+(pd9s6!6;atKv5?4T(Mpl&>_!sthD)`NGXwS-)x6FZ3k35)xRgL+gBaDg zL7PSO#lX&OWWjA?9AubH7UP=E_XAmdfVd>0AUl;L^H?%mQYmqnY=yw>`K~L*7ro9< zP8aSw8>xW_fnGn^M2IhakY12ThiMay84uoF4zA)8_RB3>G05sVxyRgtEsh3|!a{4J zf=WZCccu%md)RYGQJrs-rP)VF?JE^zaf+El$Pn6Pw=tQ@(MoZ$a!$6}?3mGYlTd72 zJf?2p%n;a5X$?utq;O50`zzHLxtUdxd7v0l(Tz_g0lHEiy>d0ZEJ zJET>fzQWFJQNARVUC(2EPq@ftkwbiKhajEAq^!(lAbu^lkrmS2dtl?26}lEVsvdSa z%z-3R=v8RsZmg7w#(53CM%|DSQNn!UovgFCt$ZPyY2x9d9vFTl*E*1+mv1W^aoj?H zWMm9b;X)1HXqc{v3A?6S=ME5}?+nu`e_LM+mlY-}tqbtE}r zM&M8}s2i&+?hVnW8eXYWIP$s`JXEQvM%Cb&-b-@Jcyh24%Zak-`rk7+jgcxI$2I#j+$%@T?oY|aj3lw6(VE@wMZCjq z*53`h5b>VLV=S=QIZoojASG~BK`j`ltK7P(m$!Xq9lqJYTHU=K#Z#1e=r5Vu9JIB` zr0|ooh~{E8r>J6gD7SUjHeX?EE^0VFcFXrD+Lq8MnVjCR6`jq)X;66EyJ8_pRb`bn z;I|oe*IXlTFEWTaYfRClB*Zz!^D)x#fjDFPHE-yP{S}{l=uZTzYN!1bH1!nou&O@n ze%s!gm?}@xeVX^mr(-QChaac5BP5xCWVQC>m*pp&Cpv2y{KKk7EOTlkA!@pOr@W6m z7@lhmA7175%ZbRJpJt{qHUD|*x98M_<0i;zx0`ZDxt6bbtfqs;f#Q zyiZR=CzCB*O#8a0HoBr$5?G#0vL?ziCi*K7o$(vnYKygy{S&1=*sCjhySl$8x3u}= zE#lMak`RYrj_|}&boZOn4^`vdcr!aTvJyNT>iJve5Ymd0Rj*u2omX1-a|fRLL`?g2 z2<8Nt$dpk~l8OLKn3-UlCJ7j#*x>^TW|`|vd3aHl&mZNWNl^>}rEk1eR6{&wpHjs# zLslx}*(P2aSZViu`q|^@%Px#uG2-IG=XA6YW$kbgX_B$e$%@5^TLg-n+^?2-S|Txs zz`%iwa}f~BmMaiv{ule%Ig;_HB1bH_Z7s`L78L^?f2)|I#5>(HX;F!7tgOQ-%V~GcF=XwwZI?sU5@UmH)`Btmry|X^DM-(SmG^Jp-mE8C^nuP%slTvEsl`or<5S4{Aw8l)yWmU3*%9T_W+Y}WX8xa)|5tOvKL}1*&Vm@YX za|~h3re#o=$|}PeW0B0YB8stDmTFYuYYjl%?n9b&# zgh)liWe1`V1OT#NKoGQMVbyCL>#&i&&}2Lu1`U#60}vGgZv&sv0Y!*JnWcz7xGNxo zU=VQwoLPetW|j!!h=D|d;badZ!0a~zKls6d(@hZAS;KH0?KpOpJUPdi=mdCj3ovlr z3vMx+dWxIk_0Fgub|jf>lS~bYtK6DqHmqWet0lDVE2~|WX0!CGme6M`cXlN-7Uk&= zt)shC_C$9hrN10Ip*iQ?7_XCwq$H*T8{MecbvL^QOR7<>w4#&7j3pAYUqSSz6U)2K zBL}H`mI^FMHEXq_0$gU3fx`$6C8#rO(BlpuM`^6g;Egcm!)T*H5;*}Tw6yDEaqJcG z$A_Z_l9A&=4)r1q9LFc1-7L}APpZa(i~*1;GHk&~gHT!h2Mm^FV2#j@$;+3~I_1vLiB2qwk%4pC#52&WNVv2WoF z3Z4((n4CdWKC&mzm~X=LLSx%u;65-k!we~_8f_zD8d@e6qBC7`@2+B13=fcWddj$2 z`BkbN$4AKdB{|tEQSkc8t{i=+brc^ev|3{OOEp%PtcmLnrsv@cJvXKYw$z^@6T#N7 zuo)x{l&4wo1J3gxq~0{2Q&?j>VMnQZ@P=;7B9I#1$oA3tmFGU;4!=vgu=FB6QJTh6 z)&O9H^`ZcKA&@RWJf#Xi)bR#LWc5H$7>fs#AyN?3CNPqsh9s$3n;>-ol5P`n>sUI0 zcLAb6iC3Q_#!6$d>8uW^4M7zsbz9REAQ-@=ij^{9ViKThvF~msd*v-< zsl?1tZ{(9x##;DujAm%KD07C>oTI;WkdVS0aI|6fGa*DvC^Z(hmnTxFU=y}flf`7`4q<=j5Wa~NeZv%kJhluuPTVnq5MpNB8A?N`0cTxc zAR_dokpu=EO2ZJxFri3@A=WJjbpt61L_1AjO|ckQ!RiNFa!gqjXJUHPeln6mMo)Q* z08`3TMG#I0hTv|63VJ~b3FQ@0RtJ|5NX0}B@S%(?9}G8TWE3ML<%M*lEd)d;j^Snk zBb2cO;8VDusH|2_nK2P#%PCTpl;aA>oRWy7<-rfts&(j%%i(Y5E+wK!Y$L8v>C}ZW z1AWJJWsIFoSbo)M?V-mVX@;(#1hX|{MJ-FJYNjX zK&-e~>d?{0C_#ohuXGW9@tm=~A1SDV7BbhfHY2cT(mCkz^Q#NrSNTQsL9~u;N4a5E}j^F$&R@ zD3;7h4izOqNe}8pQV4S5Lqr(V59>Q*hV3RL%Ty4Ql$7ed$t0*OL|E~pEhwTyIc0|m zBAoqZu@H|aVf<$7v6#ajSAB9rNSrr!RklK`V-aAX>H?AX(>5|9#tL-;tYPaV%2ptP z{+~R$`YFak$h5La_A$j-^3nn8N%7qE8fy1KW!R3nzmPu$hA>#YR&z7{p{x z6QG!q3PZ+MQma)e-iCK*!I~|$)L=2GF_vbI2(SbmS_*?r1{+WB+BVx?`Gesg5as>f zcbhfu-F*Cf`pxzA<65on8{MnsbD5IBqBKD#$4`iwGaY7^%L7ksiyIlqwrwoNiab4E zgDGaDI-wAHk9H3THCaa{_PEi4;zI;5lhJa@pY8Rwg>#_w z$zFFXpw-r1lIx#Wo&NCp?jXc#u?d#*kq=D5W9M^~CK4gvFi#{Vf4U`D{G7-WWkAd~ zIKfeFXTnJc;RJ_f`XM8rzK)KBG33!W;)FkkMJ{G+G~iDUXT%HpaR`I) zDn{A;C}MmMIFYF#03!wZOkbIEa1q@r!E--OqK>C zFxDA2QnDb)#`N4WBb1`3h#;M&8zD`7%w6RUMHf)(ig2eKXAd(r*bxRKK_0h+9x%fa zoV3ePDP=UJ4MQA_ro;n}_!{y?2x~&{Z&OTRSSyyQ!4Ywyk1bexVYyCTjx#A$P*YGS za707z$`9!IK!jI^UH!h(_Dip*N6dXq+-sN5bM}jk>O|TmatINnmuxX?sPnlGM-I*= z=?Fp7D04i2S-~G4c<|Z>w0ourk%}Bdly8a>EC$8|EvbUbGc1A45e!j?(=eb$j1FwV z)&4#W5O;BInz^cu@QhjFOtGh22Z|0bb#sz2WI{hY!=7{3eje1*1dsbJxg4E9Ry5(a z=%~juDdbGV^x8w2_}tmK{HG@3$2R5)^PbBiCOm=U)3W0d7`I<})G5u{SJ9e0zk=y- z`S0b>QX0v`fl!dd=WN6T#s#?D$VA1oe&4V{L>f3{Z0A@8N$0v=Ar{p5YK%)BLQUDT zAz0yAza3gbPnYuMD<(2ni7-k*652!!Y5<6S=PWS?nC6bF6e7>-Iv8gn4J%6}r37m& zEw=D(Qc$A5rLq=xxif^J(*lbGU|`q*LNMI8!HlDJnU)rer3Q$IVo?WC8_*hLO<^KR zzF{B`IsRrh*zKWzhx~1cpIGY|JHlY>!%l1(R4#Wm#G{ zjDsL^0|%D1a37BsdH(by;<-bXU zSwXq%%i$RG{+$mU2ro$tlhXhUCJ(?SfU*I_S z?<0uu-0$^dyS|)2eA2M-f*=oAamB_@!?>m({)cIR9h|tS9103{QX)=W&7fRtR4CZ7 z83?R|g-_RW5m9+)r&@n1qzrKKw5TdZAiT5N8u&3!(6Pg={P1Q2Y<%)r%k6eCA4VlJnS zNweM5d4@y=AJe}CvMBH)&1`zoa~=?->%>K3j8uF%Xsx5EMinI=44}z@$H5r^q!k-R z@wb4=5UO(Yx>1yJ`Rm&7n)Sq+I$e@e3-o@g?2LEtF!9)2bDvSg;fz$ery+|j&8)-( z)LThd%dWen)sSaS0ZU!%hA1`IY&jEB#VuMEAbp&1sS)krhD13zRJ_t4k3<1vI4% zym=E?DYcf5EGS75EM!Om_%;Bk2b8=@xVB;gE@VN9b%mWQD8Y=!neIbJ4&ArGJIKaU zT3ZPq6l6gd26HB>pk@@^xRix#RgniNt}d4_+zS;E4+g3rlQ7ku90Cqlz(6R z0Bt~$zme%7AiQ^MVjEV5z&GZBWB13{Z35d;2TvFH+A zf@vfSHU|bC4v!vA!cM#-M}rXt@y(ELg(WXf14;XY?0|TniUN_3^b8i_0+I*BL z(Xo(Y09g=DAQlK=N@Xq#gacs45Ahz*07Az8-*0uO%K17yDxaKZ`ndacarZyRG5?50 zh;AWqGIr`{We`&Yvju6G8I?A}_$-S#&>&63jOcMnjxUPnE#uVsH}gbAQ8)bL)ljiv ziby1X#>>Yfiy0zic>4PcE(i+PvQAsF90F4w1XXC^hS;ZsxmZ8BAbc*1I`;oZoG-;qh6 zl)-a`%N3$dZuVvndJHUmZ5|~!ogv-nB zVcbG(Q$YhPeUTj2a4Rh~boxV*U+ZxCYGs0-&fg$HBqsDHnvdVEIb3q}%n+Zg$tc(u zuf>&3P-+KG?BF^QKP8a?;YPoaVr@)R3-mo)Hh0Yw$B73EvWX4$aCpH383s0sEJh`&RVU@ajLB6x#q2rHL00wo8i8mhF6mN5 zvUx+#T+X>VvnPF5J7+sno=6Id8qnN1@jpMxC6V|OmfoWXGMtA7`2#{d&G!%u?E3*5 zKDs@>gXRep#C|g1{W}gFmPRiW7HYb70?*MkKc8bfFCUorKKpz>uUAZc1nhjoNzCwK zEA#gb277o=by-l4N#8e&O8IV&rKhz?^2~Qs z_Vq5XRW+;pAGP{^K?uSU5&&S5Iz0!I$S`AD2q5g}EYWfyswzDX#`6S}hXh(A)EXFi zDv7Ot&4Uf`uwykCK?K^1S*WH`eKsjo6uQSFATlA2W;sa_H6bG|r-DfOJ7!^py5J~5 z7{z7@N-(vcix%b+46+q53@{Rf7)4yLnI$C(JY|mT7^QYa49d~U7Xrk9Af){yqALY> zCEk8!!-+(+F~eFYsSXHmaRf-=Xq(K%{6pQ@#L!N%%S#$iT7q$jxsq|L6C>D!+&hLU zq6%6$N+eMjGgwhAEQq`+OB+-X5^#mCSXGMgfw?T>F-bH{til+HhAqTF^88*T716_< zJbnKD|5#so@XcyICaSsd%h})8Grd%b7^{St4HiJQU`HJSwPB)U00z;ol@Vq!vI8vhm2|dvrCmwR7&uZ(Vb7e%MXISh;Iwg zC2@-}K~qX%O?J$7wJ~rAO>M5*@a^m=VCY#uSq?ytYmEX2^Nwikoa^0^2_8`f*3)?rB)*hkmm*~SMwCe!; zWH6Pj&?p+y1Fb=~(8L=l1SCLZvkPs3q7BjHP8a5peeTew05paIjv`b|VWsXCK6jd?eh;2Req)8+kLOGFw z9A*m!uzSq3$c+^TP@sUYheQe@X-Wtjc^pyDZty6EfR^nTkqov$6Im3bRe}N_$O5~} z!A2u?6H!r-qecM?!Aea~F)9?Mp~j5ap)`O{HgBc;qH7z2YC0tN&O z0hcdNORZ-&#o@CQx7mIqeTZU2@AJLiF*UU>bbQ?pF3^lp3+Bz0&cG~pQ9D{EeGYZn)W+oN{%I(}WMHDj88B1Ku z%9gg(wM%N3b9K78xht<83!|#R{VfOWe#j365ZvT%~)>7_x&CL41pw6MaQx;x4k!;Y4+-sb75s&LC3rkiCm69mc(%&lmuin!duRVmuMyO$j{ zHIr3SCNZ$IjAJ4bbB9xZ)8F0ypV++YfoYuXWBXmN7bHtXSEuVcz04R+vP-J6%9!TE zBlAB-m0^ZlX{MSosG_lvNv4`LRC00C znD(LJK*T>rVX-W{kqqAq2-K4T~6#ET(@&~Ds6aF2b^xkn39_e z+LPSlf`Po;_DgjPO7$1pn+83T~+CG^pTj2zSsbvK68<*2M;zWsU}jl0;8Ire0B4w^f|P zkp~2YJ$`SEK%_XiZ)JXkYZjnxmu18AN-OC_zwhHKt2-u`u`uGO%Wga|U zoZv={Ns%qP+oqmQ^jZ@3m(6%%M~djG78FrrSoBcDLyt+veYP{WXJ({@1R1)Q7EvXe zj^;RU5)88@W)6_5>?L$T2&__fSF_kl*Ni+tP&bB+ zN$~TJM5aLWIlTle%@pEZwk@l;MY{5Bnx?x@%yQTZF{LO#N@fv-<`yB*cjAaLpsqDx zu1m~vO)E#v85GVo>1AMrMTVCojgqnhtir@$k=zcktN}E^I$Fnqcy8Nyu$QSXaT;V2 zZjEG#%IQj@bKXX`iIbw;=4;O~mcas>DSOGYYmQp+?)%2KwnFQpLxJX4hV6y-(dhz( zb$85=Ed{Qe&~+zoLK(~RxPj-L+9OD2jgU08XRFtJUF$5imn&D2tF%Kii599O3EJ?S zH-rc!r_VZbt??vxx7WuYLLC_f>d3mX38*u0f1$UY?iI2ond1*kkJYIOH3bNEj2_Q3 zA4(S_JkFfhdk5FRUP?d_x3IRN_O5zjr>D9=?V#?lV?&%aIl9%#P5tfas~;cEi;J&e zrk)xGif#?lLZYpp^eMsIoSIy@%E&JhTkNIzOfaz+CzeGeBCG_$9YFyR zEiSo^oY4f)g;bJOsKu#SP$-Hj$eL3V5w^045EzhZ0<2Y1wG~3cX{ObXSRxw%MtFFp z{01KU)hdU(#-Ywxkg?@a9fOl3O(Tmn6cG2En}wNHV{){VmO|tOs*4R#1a#4C%~Gs$k5|;oNpvw9MvKET0}SXD`o{rsFWR;{ld5Ib70ZVhO~Uh|AWnN2i4c?sKn( zv9!%iCV3z+x_@9cCfz}K?Jcmg&F+%DH?{9U9;BdhaJSZrxB1sv!Geh+q<^| zqr4A0@s@VGk)_Vl=qUq-NHQm;aYhD&UFTWAsGw9M9l0826C|wT-%dKP*kR8ySGtc1 z3xXOhn~61~m%P3K;R~IN-Y#@Amt>DoP9Uzb07jXGGjit9Oy&b|$S>RV2$V+o=8x*9Jt zraQ(Em1G*Snv5Fv1@ba5(hPEsobQ*4o;Z?A#Rg-V&qZVmIv8|DDSdS~aH0t&Q}Z#( zh-IQV0B|5BAUa=&K6`Av>Yz+_uwqJjJMB>O&Cfb%h(+bh)RCxjijBvF-KW;=tk|v> zn+GL%GzYUW--qxbFb`md?=<+vuFAMsZP=7Pz%5nVI}cuwR)?=_M3QS7xycDEf&;9) z4$8~J8;(&6H*A_S&!vmnAv=@e~-WRNKj+i!WcmYeU|1Mm*#`acv)~3Qtev)VVZiKJ^`_cgou1wmTnyi-Rdk%Y8+%iK9_T{1RTx&5X&z!S&4*S0Tw7nQD1S1fUiW3JT$Z>Kd z6q$`&WWgpLv4=a8dNag<)TZ9JoE|diIKw(UE+AHd^ID}-gQ_qr<=0sQ<2_X55g&y;!9$Oz zJt=uSnd`Whg|PAOm)Fg!p!wUWrLS*|Z%w@UOb%WiT!xQnV$r+KO!YnN5OY+R7|<3e zmsMge`z3pqoxF!0BChX>VYkRRWlvqSb&WM#MYh8SliO{1PUJkp~mV@9I2RXb_(3|&OSmQk5RQ@>=F zm3*HBHwX+w2y`$)9Srwy*ob6ueQq@gZCdKs4N2|a1|5vZ^{J;AivZPc`5Mi;uA%^;HcVC$i1 z)tE`3@&eV5#3aexO^@Tfo@ZIxQ(^4wS!qrLgH(TU*Bnt`-VXg z5#G}dHlt?bs|-wF;ZcGNLc4Ir0hbq7a2O)9F6CjjTqtg2SU6c}xvs$5qS_7?4X~~y z-7t$X?Z8tq?$K5#pop+xb6-|ETQ2{6<4#Afv%Tf=>X#PKiHdma8-xJQysD6pyS~k_we${?d%} zbS#i$Wc()LPIF|plO(U57-8B_?L57wD7eqn0K-6Vd z7Sv;rO4NX-c-$Pm90;LIYr-&DtE|if%~l$i)dI1IC6m@#Q=C`UDFd{^$5^#o-If>5J48xvxI99si%yzmq1$ zFeTeyOB(g!k_M`{IJ74%&kS-nBCZ_@DSO1_c#JJK8+sTQRGmsEiG(+Lj|CIM zvqOM8`F!t(5pN5-<%H4<uZXi7wA{LYc`@F1HKUfrnsEh^<)5Y%lgR58jxw2HR$*8rKu=ERn+jG_ zEToSP%$XEs7+esHTpncTg+hAh#tO%UoTcp3_oc-R8Y>R8Gt4ka0cP6)NDDI3Ll6oh zA<06DM59<768qn~qVSgYl?sf; zs%>OyDv1<|EQz*LZz31yKjrzpQbH}XcdYzR+wJc4wP50KKn<>11@8l8#5@6gCba?4e5Ewa@pIy#OjWZh_!?2Uf z+h7b}+Du>$HgO6H6*Cz^iL?IfKAI4y8*2dtk}4dbvP>#s7L>yzHYOj|l{5L4T534QBOf9W=gS@s(MnwbG~2(h*q%Od^1sGV2+)(is*_poa`$JR*;8u@m*#| zM_m`s-r@qR*PXg3g0NFE*A#TAT2hvGyD`#{1hGh-UcP&H0>zP$6}DZbrS7RF0w9A> z_uVjH`cRUmeDY125KvG>H*!sNFXLa;x_=BfzCi-YF1=sd?e&ddMo`A4J+x{4ht8t+ z>Fa*-`Imc70~G5T0Xx%D` zD~^pCS@4{u&w}LpOf1H`Hf^2cuu{c@Hz0cY+3)A!TU|HMLbZA7IU_pU=3~b-aquZp z%^Xy|w!hDUu=Zn2d_a121Ko?{ef30b^pIv^9>i+v8OJn{H;~|s`;~{+J{6THMHe^o z9g-0vW>|O6$7MkhYa|Y6?DYyRu6*9UNmxqXwhdp0A+|6#@NF3*DNizG2_PvoTL{gZD7U`1d$Rm zl;?DG1Wh7k+z{x9;}aSZ9v}{AM*>jY ztr%?%_Ep?mq{$+*-*j7?PMH-lGDWmDc*$-!#EKIcNa`e;cP6^IMErJD4pbSfB}~0b zTop8TeX^S0BRU}d8euBkz;AeJP?g84FRgQ9z8yCYDs zAshUEm(U3<28;w?($VCqEx~SIpDkNZK_Ma*d<$jKWe^9Fh$DP#Y#4Jswg#C>MAVxW z0%U?j-exg_w*Me=D-ONkxYXwCz;l>l#mZ99pw8PO!HGAX7%Dmp%XZO3MHGUDma2*( z1}`=khfc1W-3Hd979H`Kf)13sW!e<@SXhT?U@SUXbGhBN(FC}dLr~Om)UlJeQ96a* z;fzyKww4-g0~rNQHDdCXiNgvapopTTQj9=HTB0Du!hui~V2FpMr4T_`4sOW_Xr$SW zEWAmCp@pciVx(3mq;i!hN@2N%@LXgmTokfs*^UHF69f!Z`o@_F9z7sP|AtJf^XKjM z_jviue0TF%#9+pH^}N*ghm9dPW|+49lfpqkyclZigu#n88%0^%uL*5)c_wP8+Zb$jVdRoS_ozQE!_-;PNerJg?$pZR`c$t_YKTohoS_>?~ z@IkWf&Bnw`$1BE5JF<-&8S|}Wwgkj6wnPj?DN;im5J-eY{+8vHW44IP1Hsbh$1)R4 z7Eu*oXe5ac-m6j2ZnBdaE;hgnN#6r~WQC<%=gEHD6O5Cjl%ySUBN&}$4DLL-kivB^9< zNJu}kC^TQ6e{Z*oRK8l5)jZy@@yYr6yyCfRqy=aYMk_>O3O<4|d}$HGeo8w&u^H5o z)8vqeX)Nr)jjKvZtD?YW)4XHQua9|UKsm)eL?B> z4Js2p6zKR-Gg#}KFDlTEiL(_UX_A;}5f*I1s zQXPz1I-lB0ctQAICc)hC!;*khIf}(M25T2KT6~fiF=9Rj5E&!lXAp7*%W>(=^S9w@ zF;ioN0}u|x%aTVy0#Wq(kG#(*kq-(GGUqIeO{kKqplrzN5o<97GUe2mayV_M&0`si z-1!nh?BHv9l^QA>MFgG?7zk9dc8?7VY-vZI49c>aNM#A2mWGt^5@dgw`miwt z*d(GN@`R#;jU%mC3>F#sr%fvXVCEFTU@>4PEUN{brF+~YP%vW!K>-mArC5Sovjm8! zG7%6`vJ_NUMUZ3^7gFiBA%}tnYp5|4h?5vm9$dot5IKQHNUI?-ut>sC2IO^^Xi}tw zCPJW$3lazk<+0&PpopmP3ouKG$$|bp-4-G~31JjiL&<48X5d&tT2e%UkYL+n7&&N0 zG75N5ECoPBdAXt*hI>E=7{&rJp*dOaN`3$Ul?p;)BuGg@Rni1_O9aEh6DEYZ@8K_4 z5+k+$%6r;D52Xqu=fGrRY*`nN(%jDZ4((A+iEH;Kd@Igew4+3zo=ooS^2-vt+nXEh z-&kOTjH}Q0I z52F2~7q29>edprwTjU;)eQ~OcJtW^SKvCr`B&rVs0S_LQEC<;#nolW9Z-Bt$~o#AN|^HIzz$mb+|4F>=X?g(>SQDU1v)!I*8- z9SQ3Xauzb`OmVedcH;s-EXaYUx$-(o=<6_qxn31H{0=s3Jf8i%}%~yj|kl(l!_wvs=V*S`gGB&reb2vcAq6O^B-pd_I=pSx(SEMyAsQ zY51bF3WY{wuP%BY5*RVxA&ASs2Rj40bkR3OjZE)o8TOq`iB%FpqfO<%J zD;o+%B8O~by%7H_;oAN}P?`}JvnyK8vk1D94}-b3ik6^#XNY+E8}m_Uw;J7P4<8dh zAF5esgF8xXFxLX!Z)l0{jO!?$h8o2@V|Gah4fOc9DR4^qiU)bO*R#5ENKf#3d|4YN z;AkQ~__8>G0r22AfgTs zetvv-_hcvWzV&YAaR8}};j*yY+9kbV0O*IGC zE)NWUL^-YbC}uJz-Ql5i6_aVMeyA4;+Qr;v*g?+%gW2hJ4qF9^#;CM3EE}5S>nCIN->TgrsSN(CmjU_$t-Ja37rQICeCH;<6q*D=LQ=+UPY9?3dF_ z*nHDwo^0W6#V2=Iao%S*`F*4Q>9W5{dfF@Z%_Yh!iqf;?sO9<{k3>J+)=T<>$sc`; z1Yz3GdPLKq-60LO2EFoCaIaR-KSB^y1%lGyL(uwD8gWm23m~xR!;^>MKS@w*lu(IF zC-9U=u@I~)`=kuXK*Yk~fGXx;g=(y{L>t2hB`78wEF~&ngorkUB^fB-)l|_g7R8GZ zjEX@O+C?Ku4C_bjmw`$m1rnT2Ix+Cqs@6A^8emZiN(P*7Pi*;uLzL{ShL zTC}jE5i3Lr7p?*%6=dLs<$}lx6dE8b7KnrG=0Ot`6fqQ26&$e)crnZzz^)0wrvfqk zo^Lz%?}h$(?4PsHd|!hQ@h{WWUo5bokb@+_E2^6A`~PicB>EU9`v5Aug!~Lt-$G&u z0VK%q$psI{()n1aZr!g6fl$D&Mw}n=T75I8B9!*g!~IH@)u!zEmlL#e0SX{FpuL*6 zcg{CoBQ*Z@+B?T@V{Xg8eH6q_@1YYlBG1sWe#`*;XADGpwHw!{U&l+pHo1c00fxpq zvZp`^lp_>q(W6H7d|bdk2jlAM>DSa8@tLM-uMEnns?*Dt=bY#K{$i@Cs*0+rs+;GR zd;W{nOk)_vF@W4)SC|tY>>cXa0q}M>Pa`RjbjkSAAWxy?_LnxChta+RYmE7$a^OEh zBi6I=O{Fbr(>g0?(3|f)`t3vm;rdGo0|m|k%$Qt4Rns1lk2FJN;U#XUeaM}XHI;|a zq<(v`mXpIh2vF)k7X2Ys57aROs5}2qg~K_7>=-KySN6s7G(J1oNBE+B?lBq_sFXkA zxBObJP%)-A1@h$nt{v|VrMo+VU9p|rW@X(jYU*z0Syz{xwdV^%|9i)FiH;a~{CS4) zr8yVOxmfRvz=E!2G0*U>cNxW6jJvzxkY(#m+cRQnZR)tZu<4d9QOFwd6tFJ-*Tdee1sIhQb_%(z&%;z+~_m7x~#MDFA=@R&SN z4s)3KcTD9}=;mJ=v?;K(%3@`vIgt<>nu;ixf?S*j5Q5^+PziU z`0K3h@t&us*0H{=nC-=lollc;T=#BuL-uv2xyvV>PK>L_o_!xwZ!U|svFmzQWmL~Y z%x@PPTPF1H%f@)8c--qx7O&fz?&!IxQxkpA^OG%?E_Ls0JUo*lqVX`>#Fcu;O|C<` z8M6X5Y8lNE9GZ^I#x2e;yA)}>^@EenSzxv-bN^gIlflwonCxx}t#eH%%(aK3N)Y)K zCON{aNKS(HcpIx5*?X zLM(1>2EmN6qz)4*dMUcwK@t$@k0S~u*ss^aUdMb(JK4$GB11;-eVU1=orPhRi5*>M zTU&FS^6nSU9IJ;L9jnV7Tzwhmp62f6(xxn=jH{rwbs#R+7sYD3jx>?s1imjFP#&_X zO{=EPIA?mTM@z8w)RoBz_h+hmGO_le9LP;_r55hdEQND%y-^6fcIup~Oj%fq9X(p<|VDWurB5`=?X!o{fYw0~;UrjiTo zTPIyhIXBEFb~;iimgzAQeEBt$Zmcrk)()G-qTJGX@$%GO@IxYM#5rdeK)SM#q6Gj%b73HCQFruZ9wy-8el+D zV8Lcl#966dH$`7bB<&76F%CO3_S)1amM~caXH!loA-N`^iz;Q#l7*(U=v!{fI!6*w z*U^pCs5pE>nVNQxOr9W*XkP@OFsSa922ZH~7&P<}GKJJhZEZZcjB zA+%Bq6A| zM5oq#Mv!T*D$7qcDWbPQ9XrIvn&%UGSuduZ<)Oavow9F^kj7CsKWgoT+mx_qUA8On ztB8&0xW!UYW=&02aYO0in)VATNQ1{Lb7;{s7e;mC)Vz}O8ks$jovvbJxfQq-P-Que zX{B@Sm-HHigrRZg&XM8a9uj4^!^2WR3a4@N4{_KRXM&#&ZQXBa54Vp&cMLXRa>k{b zjN_sLsFXzMq`0~9h}a(nWt{`xQ3d#-eLE=rug{=twOM5$%El{1N@{hy0_~J zAeSaSLowtNW)NYvj?vtHp<90NMH}oNXtl?lW=LcjOfoeUtd1YXsT~?WmKIRPyEzTh zgj_L6=%DBHEHGym9^O2J2~tkTcDW1Zwykq;@#CVQ!kZ6!AznCJgL~G}JW6cGNJ)n` zw$&J340KTv`DS+93CD9w+QP4Gb;C=YGjRno?*z^9hGQEDal~mu5TTW221z;ER|%Ba z7Cw^u&T?#wSY(l$Ml&Gl#Gn^Db1YrKL)1Z6*nJ3Bs%?5hpV@QKbpdgd#(Ib($p#)Y z!{gc9vsC!^nas!rq}qn_Rf~c&r=-Q-C{2v}pw2Z38_*RlJ%hobE+P3<7Z#4Vrmo|3 z{bfj4=1TM75myfSarNNQ;pWK`g*cTj1w@@j&Q;~ zA;U~G>0R}l(hhm;N}Xcx?GIDR>DsrSS%UCF5ayFrhKep^mdLHM1X1i~fxH=uZQ`6> z^6{|c)L3o9#iXgCU8KG*lL)!vWWB>43Spa$*4`;MG<9z+u3T?(aGQ`ZZn-74UK1c? zm${Y`B}Z3vbh>fW(N4MBOc1Qy&Bh_{$KtbFqR_gr?L3=R9eKL< zS3sZfZ(T82 zNK3*6e|I|l8HZYeyvovpc3F)wwsUClbHxRprTbon>iMVGPB5ut}ZwWpfcYv`V< zHa40jMWhSCm&q>7&@i~!(-3vF>PmU0hX&gZRn|po zIShH#P=b`(dbxWxGrefad1#^M8O%9ezn^Sa{dB#_-WsPkZZ|{8Zu!fm7UL}mTJGf) z0)5wNfy_)~VFT0gY3B9KNUHOlEVy$WZee=Ob8dUK_m;vVhkR_sHL7PT2)U9esCjdz zYhl9h#il!RC)^)rX{8<9ZRwMBJX)@DPA@Cj%;x2bI#adJBIW9OnQBHA&p5Sf-c!BW znYay=8Nr+*%o^&-vg$JJoigd{yboDs*#)&%R6G~=ds{3b-;$3^!H;a_L&gOHnVjb2 zy@99D$(7kYe9r8auSc8G`*3^Cn0H~&hiJ_d6pRH}?a)c7!fnOvt~!z_XQ6E#KwGYJ z*XH-EwSzd-#+c_R{7P`t_61}W6ugp=e}(8xQYtjVfPw-G0x5U zBiEkB?+|W4^FI7Ap7*sy_<<>^Ki^rn$b=t^c(9q)y=Ko?5VVqv-Tez~E1NJ}WIYV=EKl5Eq zZJGWmb;yIl@h(}7O3H|fb72r9G#povp~e=6F~=TU9TC$LcdDWZR<2z)eU=Ryk;EHi z<=k42X;@{Us)o89cxAH6THbEUyO72PFlC`wF_`0mK{Cn2#u-aBmeU+bMq?{-fUy*6 zEaO>R+S-a1$_$!?M7KQLiVLk_sb#rv$2o8m+_f=`Hq$I^D`lgZnM&qiidsUs+%U## zSYwY^Y8r|IHi3*3ln5CBl0t}R5tEPsu>>$V33C9BgrDXAisJuI$^QVO_D>xRKzKV1 zl7Bd4JrrP~$uIm04l#sH1CTY4SV6|4&T{TH4J7+0^f!JqgGWp>hXW6eTtBjOV~2(~ zj2zLNZIh2DHU}hjal?n?N3$5yX;6gkc04Fz+U#O>x>q1v}qdb9Mz`#Ixd( zBx5b`ySb#IBWjxv?Tp3@Z1eR&b+$gciI+CUIU_r*^SMPM+C8*RA{}|*3|r4lnb_Up z^v|;wC(1B~T133&JNfLNI<&9vdykN`t}+Lr`Ou5A0z_eDrm{{C1&w4$a7%dE4;Uvf zZZpC{G_znuqk|~3gkgsW(u*dD5ZXCM`^OY`Rup)EP)~^w#fO6o9MeJoK;)1XGQ)-i zfWc&wVUWSIVuL61N%DXW(cE{v|LgXz7J1fWU5?uEFxcGrj|6J&-Y3TKzC+cNBh*2R z#rH0)Z7mo+yme@p>>ac_t?4u3?JmEVGu$7l!|(gqJ)rn7hWAIZFT$g2L)p*-1de>D z)7(HxBykwal+uzr%;%0O=G=0j2GGboXQZ?OdhAuyWZj=xXGLo1^Reb>eKN^BJS~+h z^WeDmY#Y^kd3t+a-j+$2mXO$?U=gh(xjCGk#Rj{an+u2cwiUG*#ZtTOuck$^U z2{_|VynIRG2=g)VsNrD}LIJHt*jET9Wegz6D3JJ)aPl4o8hT$0DZj6(C-DRrGbyPlfQRq^Vu_5!5fMz$0xU=(hgupkh|V;Civ)oW1So1~q_i0_jwWIukw6p$ zRs#|dMyDc>H7%I5P=NqY3|3&7Fw(?Dvw967Ohro(Ko+XPX__ghAclykD2TeJ1}Y4J z#DrL|Lv0**lSe@|&M?pRT4Puh1E?5;=#VP}NfZ%95g4>X1hFhbLX$K{;6CHm{k^}- z{eO3%Qd=46YwA8f7vjIWE7}9_>v#A58}IPrna=m%jM5FP$dB~I3A-HGF!EpL7QVsm zUfs`rAB|b$ulO9~D+p{gAF~g{#FQu13k}B2!}z5mH|$n8Uij*o*@-7&i#AC|f%O)r zW*H+X1j-VJAgSL@1oMDx8{*lU!^yTd7))+VhN|O8ri1s1lF@!4+%;G0aZrST)u47? zhttItbQg{CVRMo42<@G2I7nhhWlN*7-I%yrX%alT?1xcipL|u4k1ZgTPG&+qT3lJ^ zY(H6KqW30;)p9hLtu+3$*0||ku6~w-PJiEx&`HyH38SmE+o)xd>$rv!ncY*aWmkci zZ5)x!58}mA4O(g~;}IccmWUCbqou>cz~S5{>#yiVWvnd$LRAacttJ|B#Kvhd7^19N zp(hkXM21=ej4GtIm6TXD7FJs&f)xOYaP zk+g`2kxI%Uv~N1PX6b3si5b5`=2=b%SS83`(%zEs-K9yvG8ZD*0DY`*71hp zL`Ra(6~nB=>n=QV_EkI*EUcL6wI9jXeeyoR;I9YsL-?29zaD!OJ(+yt+aR_fthU<8 z-;cERkmQkGIZ*yEqew%UpGaJD**thYvkp587)|n&Su9%EniLs%BlhXf&1CeMn!W33 ztaNesd@qa~mc@gkPY0%dSErK9A`i?kY2S9oij(wmKV^JnFV}yI`H#AWrM*MQkH$LJ zhQ>^pCdYarPiM543_iTIq*C8AojZAq+x3veAY`=kZhlH3T7IWX+xc|njBUJkL&2L9 z{f|i@c{`xcyC6FTQ6d_x;JUF7pRhc6aPbW=6VpaF(J$>b3lK_)Dyc$|nTYP3qVi+m zYO7e~QBaHoK}1wk!!*$mKw@cWnL=VlT8xE)x;Nztg{4u#*KMphgruLy2JL{sEvQ>6 zGTMS7NP`rM1rY#brrrswL@1_8k07*gJ95*M(OD!?6lx-qrG+wxH8h2lW}rx81miV3 z2nPhvPBcUrK?ekANm3I;;R7i|qzoFcN8kC3`vfaTe*W*Y`NIRYx_=CfRQvh)%g%R? zdE9Tr&4A;6RIWk5qF{`UV>m}#H&^r@AxyuEX{5_p&+8fb!OCq1dGRn!jai*gv(6lr z$TjoVEof`0D$0wNHyoqISw)%Uc<|d%6y==q_*UUg^k){ zEz?kWNd`&0>0eQAqb_QuIQu$MmWD9lC7CG*;!UOHsAC|DCW@iTCoYvVRYed} zMNo*~T1zO2(1j|B3M56Sh&#x_SO_CR#w8Anz%XDSfo%%g4H54EGm;{`v$!<2J;H#n zK{zQ2RU(cQ(UBT1BsKtWK##u@M5GNoty-vLjgi2^6qs5ewu3e_QLUw|V$#hpxYDddJJvW9#c*QsRD&Vr?97e2gn)TSv)3f@0wvWQby0<_m6kT+x+2BuqIZnYd(A zk-B0}U!bm{Is6^LeUKwV5H*5yy3u68rO`5IMcK9{tDe#ZpO_KUSnGw;3{eP!D3r>) zob%q=tfA#o>_5vmrt}hK9`Si`bhX5NZWB^F_y-FWce0>f8m!36HQVFT87azdfng33 zB4;t`@kD-Se;bX0&8&aC`@t;N()4yDCBVM0nH0kbsWp>EV?r#d#3f5%R+Ov}iV6u6X+y0b ziV9nHY0(Z67|M3pLP%1?kU(k}gvy41rlM%vIT;DcW-5q?Gvx{+!yE~W5rTPaXhDe4 zBtmq7!V!*mdOmOY@ravw9zH%kXVS7#|HA_%CR?^f(h=FKU zJCra{SST_mGfP-(N|-YzY|(=0!ovhL2y22ULYj)CA*7Ospr%=&s#ehgTKxMz6a0Sy z1376_bK~#&zj|K_=S~yV{NLBU-n>;_I@a@nA11moxf%|#P^2e8^Q;Lo?%%_d8o@!& z9X^*oxqVygY7YauH9nrQ>3Hx-*idJkNyt0S196e|b}sf*9IN4FuVyZxJ^fdNw;e!a~ zr6)oenTF$?&KBI{MxA;xe>^RE^c5NTdENxfIGz+?adr|$Lp~}n$C{gnxvh$rh+-o+ zQ19!~7KVXnbKwS2n34h*?=yRIb43)STL{T@ zncm@^801KunS}{J>~S(UR+LG`prm6Ruqr`9v`|D4N6onbUk2I*5$vU(s|z(QWuEM! zFhdYpB6;O8@-kAk9@6@GXu+6NHwl=8)6X|zFjPcCQc)e-ff%o?jF9mtf`uk#GX*Cc zW}u-WDJckvAwqPe08@74OjOlyR0Sh2UJxQkp8h^7$9#`J9zFMc_svdsu4i~f8H(Yt z!H+m^g6PYER zT!Y1z2v#W6Y&Em@rOvJM(T936M=ci1SaiZP_c&7!xiLbNdfmR$#*>o9#PIbO(`=Zo zatEQtl1{zgaL9QX3q7#wgV2#E{b}tn`|qW=UeNg;a_pg>Xv?`dXW~~9%R&OYfTS_- zxJHS=tpZO?cT?-t^o}APkpcR)W@nRSqKc2Wxl zGxs)?3{=F0WI+WZh00MN{~4!At&(xZV$!f<6jKmULcB>thX%Sa5Wdp0h*U(11uZEC z%)yL|iHM>ik|V(@2Z>N`aG;|QNmC$z!);LTu=6;~4+Jp`Ktu%VV6cPInvlVR!NkB5 zmar5;3Wm1O1T==kNWV{^3Q<)3eEips8fs6D;62nYY=#LTU&Q0B>%S4otY??5VH-nu zDE7C5<45~}xEqVqoc>Jlj9^#I5IF1B*U;uGE??w+ZKiV^gjj_(U+PS()D}UpBw~z~ zvP?e@C03Xm*W6r_YRVEOj3LX$4t#1+dpr}g^@G0tgFBt)@HR9fm;w$DrVJsr^M;~l zoXjXpkkdSuWNMj-F61hWgLc)%d*UGN`aDApTIfqW;l%w9)1=3aJL9Ua=3k+okHa`e zw9;(-Bp(pO{u!GK7rO65gh+nzWtT2HAq~*+dOZkOft>zxegy`QcS_VPyd3>}$$}() zFsM8{8-6d5zGUtgF&DCB0o-lWLwLpsETXF2xqJU##pn=8gGP;qlZBQ$Jxp0|p^Sct z+*ZbCVD$=5;Ii4e$H*B0hYEARfyBt?bjS4E$w(m1HD?$f%(iiw#-#}Hs3aq{w{XFX zWoU{50ExRy1nRO_k-`d9A-P_bNkKt1V=RdcY%wJyP;Cl=mb9Z%qy|Jmf*3TxrRrgb zWeO}5iinY5+E|ZmQ0pj|?ob3sutXMi*q|&G0fz?049j#AkVY0va?GM?K!k}lKi9^7 zk7!EKh7TQmzSHyXF~%_6|#k zW_KeIH~dxXNq-NI`t0Ap9*<_^D190voOk30P)VW%nkATsFcuJPty!UzQvW}{@lU|n zBxjV&yR>5JO-5A|e>lPaHWgA)zdwx7Y~C0{=KB0P_rwbl(Lm-75m5mIL{)S%LopFj z9|yI|T!kcnq6vJHjAV{MH6F&8$lFCD(hGnH6?U%${sUESbCN7 zIe=|J5c9!9C?}M-64fC{~{wp*%uw>z;08QRl+B zs$>!UWQ`L*8G1_=<_%Q{}yP+HJE%`KD&E@jFBqe`x3g) zdv0>|;#Pc3)-Ljt?;7tj92Gd$UI}8Ebm7a{Q7gMzrSY{K%yBbryAD~gz}z@&*0nHv zOi1OBtH0VVHR|PR74n`SU}|q$ySYwn%39cF7!D9=w}>NM0B z9HlUGM9iAunJ&995XQwcDY#o;RtrXqT)Bn2LS-|p*~SWFLbV%QU=B_lcK>6EH>EQI{>u)`h#1N@9?!rtXiPb9CtSZO1NoxFXE~U8N~^E(=a2 zGJ(R|moZCR%XelF*|f=>rYXSLnQa!TG`905CV#r%eh90Fm#jA0nEm!T>Y!X!Pw>~_ zcP7^P2#?LYAfeW6h1o>t8n0c}Z?>~6w#!X4(UWB~(+MWhZ8XwJB$7!q}=!?BkZM;m}gkI(2E#r>4#PU35#3w{&MRyKo5Y(;PWp7Hh+Q!70 z|KpOI%XVgOH$CGy?R57?T?>1wW2Pi?9tGKX(JrFqDr*NSIrQ?q^>pB;)hfJ%rqpU^Dd*Wx_9j}sdN)toDX1rd;>b>_HTtLQD zmF7)nmUv208J!6d!Z%=1*B0h4OqIT$a(`Sq*u0K^CiGSZuxa;u81p`sW}naN@%ugu zL$BXE;&hvD?D+h-+;3>@CVcM_?m1(Q;o<&6j)a=EwsYMD!oVHqZ#@}I2o@ab0oi56_WH51jKrtZJnaLst1n1%Ekv& zl$R|Hj&Qby_g`|l(6>h7-6H+bG+u%W>ojRTgfaVQi!4UnRyFJ zXnIZ=79<_Bh-(2hUypRKrXigiC&xr43a)`LQ3%9^+3_4vM?h zp~b>5k82suHk08uQ9yG!z&XIy>A{_!4(T@n`Y;4Qm?;*B5FrkDly)6Q2qWi%%Xx6( zCLMbN)FFQ#5csK(KtY!G&Y#B_dw6Ca8(k>V7fGWyT-iI?hDv1|ZvyHU?XaJyBiKR$*y(V=e>K%30a~n^z^)qVFIzs{DBg>L3!-)MqA3 z#YA+JOo*w5wbbSoaX3=to~`m~Th{hrZYn%e@eNamOyyqCnV@4+P^NfVC&<}vJej$| zk7f6xY*$SzuBE%EZO)>V9d+Jw#j_DbcjD^F$4A6PkW1ig;HF-GP!{8rO*2svF{3D?eS%l1KC&;xj z@8;z`%k!YjbDoZ;?Y5b{^xw8HL1bodtrIG}a1MoNBqKehcVm--=vzYd$l*D}vtZ+> z$J2D}6Un`xc~UcBjNos_jtj!9d?hJc=ltzBsNl*VO)x87H64d&SXSDl5`s zkarLVk0yK0PqP^9y;|>85d);*ld6ep@fM@L zHH>UrnoSp_Np_=SWtnKO7`&sTw9;lX5TJ;&I?me?GEs0rg15uZWn-TANauF&B6X#A zOrzXcGWp~_lFEJQ$i8OA>;>p}mt0JGf*otz@OP%1e{YuOjAO}A<=w}jS4evdhbfq| z)91%7TF-gO)5WnG4$hTCo2HalY9=MlGz#%46&b%S5rNn#L`<08X)SzZGq-wp>7%O0 zq;7>nrC%ckG({#Zjmu=g?^6_bBa9y&)9k1$lXt4P$48AQw&yT{bIE#7WB5uk2Ng3G z?4KXdNZjh?la@{sMjNBEVDIT6+oprA+DF0CJ6tX6r{3KbUGgZ*J;j}>_4Z)(^B8c5 z#xIsmk|RBHhY?<#4tde$CfW3G#Mv%1ZXJ|u85WGY!w+MTMoAB*#Iqcq$ho0l9pzj| z=Hu2QGFy!ucuyn51fUU4-4;U~bZzrE?S2zJB$*{x_(i$TXNw8a2*GhL;q%)=lRn5H zbdkp%Fs};frI~~4;Ge1sG1^g1MOTlnJY3Hz)N@`|G5qAs3s6KdRs)eD`kKorRtp#KfV<5uoQ37F}U|)Q4@MkLxtTt7?vY zoga&TVCk{B)dwo(B{B;eLgVMMyB*|xe-f~F=G$v@yvE(n6|xpF<3(N zr4uAe*zS)KwY}?Lg^F4>j7dCHItvcGYH5XVc6u43t18vNPC_Vh=Nz!VaHmf9Ev492 zED9K7)2*w3jhusbo?sEdB}--LIi2GDm>Cae3m!F66Mf)b6RgB z+Ab};OT-|RuXxnjG2W=YYdCQ`IYAV+$-WCrQ465QqN9ypmyDsw!$uCG(Zv2|W7 zj*@JMhce1XqnMy2Zdslq#hax;k&eFw)J*{pT|DNwhJEk^@(P~bs6esumv;+FRNc}e z0@!ugA!p+62UB-E)?Xr$U#&rLnJokH*3-%2d~3J zB62rPEk4ZKuXwt*)nz^NrD!U~Mr~VY2ImONmd&V=x(*jcR6?>R9!?vt zmr)N2RGJwTwC>xoxIpfmH7@`r)RY?V{N~2SQja;8wU$DAPfF1i-FH*6`BGG`IeC<7 zWpRpQ8J}hD(@H|WSR|;EVT?uye z45G4axmwa*-Q!&JryW(P;!Ink?vZ!3OkC@QJjOkp4TTYf!-<4T+d|rrrr67=DazjU zc80|x%he>pjBA%?sNQ_#aI4W;ULx7x?J=LdTb=FQ-*eoVWs1!}``aPl)HuR++3I2e zh<#;FGmM@gtbypjoo*KfNK`v)3FAKo9er^PLVaPuC#m%hSZWfk*(LUYDj0xqo-l?o zAA4Z)lnzpl5VSji2&z zM;btBfoxFmJW6hRB~G|e)Sz}$y_YCME|C_GB5>EQS9JyFIYxX>q?^Z=*Cwmtdxf_k zYu+fCuBQP*sfctt9(QSQc2rZnzEqZ|OD2*Br>gZARwJJ|&s~k0qasv8R5=%EwRLJPB2Al+$|Z=4lb6 zEm<92ebto{66zK!Hybr?9w6$=b>;4VW1{=LGf89YJoZ(S2|r!j;>`6`Zk64Uqd#|O z?NWl#JnWpvy_9&=`Ij?*Z9HF^!=f(9FSFi{Mpv%u*<$YB6X+8pc%0EjnOmTWI zT^UgshHrNURqCfp2Y08*x_;wF(;5o0YiPe76J^R$jP)6C|9Fu^mk_r{l3B6^1)m?8 zd8gXLAxQ8>KJ55D~QKKr=g|t?*6fur& zVrYu0)_`s}?b9hnIk|*4DTo&4N-Crg3W6XP9KdejfUGr!+h#2@2EwWs%8^TI!M3U~ zL>4(^iNw1~C2ge^l&HJR!C>XBb;h;E)WZ}T3vt5$OHA8{XzZ#p0H} zphx(GHj4*XywpI>q64XU1}9V**`D)5%u-J9}z#VE=m>y^x`M0T^;D=sW(d9ympzw9yFpxUy4G zhsKD&ah;7UfcdhYI6)N51&a$jSpvjLLu&`8QoU_=<86szf$9mTPM$gEgR(+g*oqnDdse#+YBW*L8K6rfCG(Ej4fBTx&%j zhC686+i=KM_Ce&3U7omyb~iEF<@8Y7D@b9P%A#m_t}u|>17`;ufdj+wUV;2RhjG%j z{RHaIS6~)pi-NmIqfG+aJQEZS?Z!;|b;DMe>RdbB#3u}-TWX}vnA^yTWY_C^%)br} zRG#rwi^yhs^7Dj0sk8RV{y~ zfg+8F(X)qJN{9+~uLnd|_3M9DV2e0Fu+#B;9@0VUJE)jHOa?;-ObjJ55W*scFaBJ! z2)vfkgTK@AfXJl0>guCtOXb`MM5x! zQo!M90;OOaWD1c&8%mlyEG>wb6hKfBU@)}1oHojZ4a*_4 zqp1{5W&8Qhxa(gpnRwqH2pCCFf)r)~cznlPhWIg?H8{aXM@L2|Ma{PnE>&8&lW<>i8f(bjTG#3bK?O6`5gwf|YkkrT{~w-3@P_#LoRJ~%6Q4^O|2eG9q}c?Y zIMQax81l|W(b!p5A*456f?#lPjE%v>QxI8=}2MrlDycNz?Tiytb#YT0EKgZ-k!K28|&72^nXdo^RD2R@X5J@IY z6sW+?!%!Yr#XK?AusIl65}5$r0gf0pmAi#ti-5wT5_&TB08^B+2vV{Hw-Y3oLxGb9 zYbqMdatTUQhJ>UUB9b;nXuvRv8Z;8ckTC@dxH6bP*k&k^6H#>oG-`r`Q5ay!0);eb zFjrDiYA7fM2ns@Dag`M;lT&Zjl21JLGL^6~vRBbyiFyYWVTU$Z|$pTA3C?%|H# z8Lj2rHq>k|nTZA}%2GtV=XV3CG}A}J?*#%dK81r3!|PF%E_Z$NG3IGA=R(8pjy^3P zAaMm!kYY6W>Jf4J=DM8xy8eHUxA%?8tX^~Vwis_lOZO3DTs}lCt8wLs&~6i9rzr zMhb8$B}9lsGhu^+P7WAh84eK>lj1wlL++%SC!Pw(4j+jJAh0yG$ zMUIg$CzcVUJfedFWU=o_-;Qr0?)a7Y{rI)|6!|X2R$(otb!~m4f0bto?Kai(0wr(J z+tfKTI|pk!ijDXi?$fB?b3Aq9TRf)rsI=v#h{tFZ_R>>o4iqL|)_q~}wC`FIGjF-N z<1RLStfWRQaqXlM)%sgZ+lwkLSZ2vFw1WjUbSJSF+c)@HDeNHcgeSF%7Y4NuUWnvG**nFz zV=XEn6NRc-sG#<{OS+d7+y&BgXMNA=QI7UY8A-S1$bIm-UBaXuo&z-Ihbu%8Cwhjl zZHZWnt@MxQT-0@xU&`o6osao{>Hm-L`2g@_+0of3Jsk@J^_-TGV?wN$&iHWYhfEWv zL-_`D1NpE;1X6+r-?AiE~OGoINU9V^ik$wR49sx4~K4H zNkoTESu{xs$Oa_i$50f9_AuS6I7SnhNmJCE+v!eaK&eqPZb%|vnt=T-unt;+4~J=k z)TB{mWTQE0!SN!Kno^(;$#yRyP?smav}S~gV5jXnuI1}F^n0Ca-!9iS4T8~BO4;XT zOiiR?p}26ybTi@ee4FpSD61ddJnSZ;hBU0FkcxWVc5oUz2x7iI0*_%*z-4i#o`^b1 zsg6e#IOyh9VKBUTvqxwC%rWn5{(=13@!xwx2)=fCKGfBb*OP(~f1S9jfUBauqr?(l zh0bQ3H8Zv>_s7&~EXO68gDSVqhaRfzvq`)SLaH{n`&RVnR`PdN^N++WTrw`t_&e7;VShxC*4y}i6dZM|L3-{8#1!cil&1}J1Y2hAGK)MmMa z75KtL#2ooTbA+!6G)Tu8ks}clrsbccxkxM(6AjE@A~OUvFlQ3#ZOjxzix9lS7AP8) zC1w4>RVU~GIrlijs6cE9S*=(j0YDgzP%nZ~BP0cwg;Yf~D*I@_L>P=sWknGnDxwsD z0R+jA=CDkZNP$*L3T2Wh34;Y8eWZn8b8LDkP7-mT#CNL|3K3c&hy>t%-=OdWQV&-C zBR%ii#gEIHi#_G%ROPA~TR8{!g#`&yEygg{y@jb?nflITm z5P`?=+_U4D!#c!gg_xJOlf60~!!@}(y9_M zb>PCUEV>U_5!o9@XW)be#067}SEC?w+2rLZWrzm@?ti|gM=uLLiF51u9pPUOE#jU= zCI?Z46nvsYVcEE22iq-&%f;;lf{lK^d@`>O;;Wg|uiDC^1vQy0yHjLpiEu*-Ff5cV z(&g$_wJXn?uJi5&JiRmWFzXL3s0wuKEcmRD!)~GKbw09l7UCGifztiMjtDFdA63sn z-^QxrlpFgXJZ6}X{6h0m_(bBR_B#?7#iP# zA;cqUX8*{4Rt_L^#=J7klEpTOCE3CyzV(tp;xa{D+j#l%JKlPJk`IJ(r|Afmx@ymu zYO>BemxzJ##c!oMTD@Q8!T1O%fOF{%^?S#!lKVc!Jx3^OQqSmaJl*fz(<7ke3r?vk zkKFE?6@g)Qbg(g~ne_IG^f(XD%W-?$+YOFPpxAtftA`Z3_Sr6X}F$qjolz*$6h$0M} zv`EWJkVP;!7*`NyLfE`)L_{qKMA>QxlNt%jDpbrR;4rZmktQ?*I!PyN3|TnEiyq#l z42&zdEK(hq3=ZbK5S$R|5~7K@fl>_U5KiSz3^2nJ5Xu=O5MaVx{!d@O@CzVoIr)js zJwtf-`G}lv=YKx!^DmdAg@KqF;e2ldoNB=1R!UHyj6o_%RglY8BN&}R!2w8!V^A1V~UWB-B|JjKtg|svTfWw83IQL=Z<1=4hB`#gH`S;s~%9 zpkP3FsF&X_Zgql0O9F9MVx70aC6fk&0W{8}72z(Tr%6;eBy)=4>?EDwAIZFbqmPwa zCmd99_E~B!(QVPE9*#vD$4OZIBm7=LF$S6O)=fVMSYf?wCtJ?hlK#(l_)UYiWrqD? zJ_vmkfTf%O2=Vng_t|-*Zway@riURX9Pyr^>BmEtpMCSu20sxVgJ>Y8rF6XXc&vde zj~^+jCK#WXDzb}`#%CbhbHupka8>OE{R0|-sW1eVcV=ji8;tEm>r9( zy^oJSRN(NLN<@5nocn8(zYk0Gl7#LQAsWBp^pPZoi0Ebw`0yjT)oP27lR6y^M001p z1))kPk{BXGx7xL-5}1*t8SnxOLS%6KyWYeK1cPBdBEs&rgr1olKs>F>L^WOR%;+%I zWEs|o!%9l+uor?!i8$&VNvJ(3uNsFLE6RSb&e%h|E90V<0(sJ#!jg5YIGp?}G9E4^ zq%|fNBFHOHb#OoT_&yl!&yRke2?z-9@6szo4K6{!6~k7wV8;4IbDU=|nHyXv10m+o zj;3>hCkz|dqKM{Y6j5l>j8YOw1e`?_YYRaXT+W!5p$N$hTfnqB90cXfjF)~%{;a<^ zF*VZ1WB5w)9dp>x(-0sq@^%nJk~79H26|D)B{iT}3?`Tm++n!MCU6Jghbrfjk2PL= z{uKBy`Zu?%e=qsO`2SV_eLu{>Jh$JIvR}Ig@RdE=*}e$}>-#-E<^1>z`=2kntv;e4LC{wv1 zRIMz0W(bGoA*{f@%t5$kDm6%mAHniFKO_Hf{tV39m-_I*iF`=I-_tCrgi(G+C3>VY zrM>F#KbX3}h&f;&ZlIekxtyOjK>pLHSIa+pCNHztri2rVwK~i|`grug9&~#`afn`? z$yT^*eBnsv=*O^zT#-3_eepG;oaZr)3}jntV`u9e&+Vnewwh&vv9-wQhGo+${t9D@ zxoECcIde*lx&FLA`*iPGl&=-z$7O_20+s9lH(ae7>r}vxLZxM%Y}hymkVO0DQMD|`MQp78E$4{mJzge=F+CijK?<8 z*cA!1=QP)DV&ToXChcv@yIV!XizIoCH1Um9nRy`T5m+H|7S$sQ%aevcoROmmjuPy| zHmxOhcGAWcms1+ymyI!pQMX-r&S=HR+#bL4`hP`dZ;j}4DYV7=>im7bv(`SIIlg0j z-Q3;B;{Px1_}A}w>$>yf$B!O09pf1Kcb_@);;O69TlMN@XV$Zv=Q*7E_3PKKK0NvH z=hv?_==JN*pBH^=diB3uPmIoA9B^a%M(F(O$z8IMx*u+KS!`!@FLl;vcXo5p@0TeV zn(r*Tm$z8=yrNy`tqCYyh>^!aT3iE}9U1>px4qe(@`=?HZ|O&tcU7Q@S^VHls@asSNxaW?f1I7*PQPaFEcf} znLEP5cKfqcUff+oZ%=f2xC7tpK+VUuP~)SY7*fQHIN~+L9y0#yq{f;+n= zVUu+0wLtQ_3Y}+14nzbh9N}!6LvZ2RAkqTPYlL@)9v`ZG*+9XBeY0bhyv; zQSPKcXoPEX9>421H$$ji6Lr zz|WN$PN5rdc0W$*s}0&Yj-%(hx@p3^(uw!gH^o85)peePDJ-U0x0h}qM<;UW-lWjA z8Mij;BZ`f@L>YMo#jA}awrdpM*8AHJdreO5Wm#(Y@RnO+?VjAwjCPU}jW3lVg4(Q` zs1uYukOt%Safq+=XRUW?@fIGsk*3qI=$Gng^SQPuxGN;aML)2P8!w7=GLAmDKzjI^ z9lRMNsyte|v!vclHqPjrc^(X}7HVm#aEtk~+n6SUNh#0Ad{!Mh1U<7Ib%rLAs&z{* z=};uFaWQZ_rnMX1@kJw47XBHOv$~G*%dR zhd2sI$jP#hTZ=JVTeB49aX{`!xp9#UW9lo39~mY{$#T{r4d$bAZ?=_TvCuyYj3+J* z8Sx#A<;qxkQ_(yj=y929bo>ZPq5=Yorx1n0UuO8as6BK?EJqt| z!s9rR(1iVhDjnk9h$HF?IG}L`fTZKZXo+6-X3p3Y#nrI}xhRHji|HJg+YET{y!KO- zE*QkoTHYzIF{f8cakTXoO`~Es>fopxI@4yg8^K0^gVYxbGU*fe&z z#cjJv3*fLoi)cIMOx%L^iaufSjq8G5`8p$gqmWhhRciM&2wSEYSpsB%CM9;eN$7}L zjmI&p?D9acgI($mY>0vfBXH|HCP?qtLwC^`LGxC9%YD(ME7{#12;gk^5VBHi!OAgu zi1L(Yy>*o{9hDNveT4}7;v?ui-NX^Hw43z^+FrsfHdw$${U2d}Xy@N~ufySHa-s*4 z!$KV9u%MH<@Mz?6>*K4aR1>L`P&F#0Dg_L}LkyDu$03>p#ct=VH>7$vyt7e;lJ*bV z=CTeEV~?b3bddAel-!e3k&_s=(j<{7rUWOhfaz^xwv+UfWx>P`(R;)@iXtIvmCf02 zM3!zCWSEHzf@mVz45g9Ay>d!TqDeTI!f{Ey@uY)!CcA+5bd0IC(c?Bu*L}Rg8;-g!j{Nix0OH7Kk84kW28AsCV8ZbBvM<-)_m#4Uu(NGda;_rc2o;q@l&B zw!-b0u-9pV$gCd`#xv%=lri6trkv>W#nlgycJ<3I3lSwNFDl}m1|xEqjoG*B6Wr7D zj#^5zxHeB0rSya9A-4!U%WASZv!}KVntIa$!Xu+%YP#^EbaBfkd$87Ggu%;)bm^nA zPzjv4xH~$}2&~;lrxeXWUT%F#2}?+5D_U~h&sJlG>T=@Z$&Rd^NHcli>a6Fh&tSIN zJ(r`6#T6Ohm#d2-4W@V=F;MtPbDc+2&MokWvE8vY3$nUQcyNG>I&Xr_ z8J9@{YrB5Smo~`2H8Up%(no)gM>4dn%X!jJ<>p>nHzRCSueYvQl#&vgjbPLX@eh^K_0<_i zc5yJLUK-}7K~_4_+}<;#Q#-?#F-1c8x^$!^#v)Et0ncw!5TAE6d?UD#c=kZ(hf0hz zz%!tbbuv=uY&v*xLCHLY*C4_aJ`{bvlYv|CP$n^&3NF3g-MM5aIkcNKiW$k9c&8rT z&hBXwZAMH?Zva_yLJ6(n12BWBHXF|GuT(}W>c;9@)Z(ja5KFCYXer-O7je~1PYlDA zd2>eg5lJYgCF6O;Tf4Ry!=~el$7|RyZLrS1U4^GD7o3MStlJBC=0d}^{pXwx2~y+5 zjS;l?^28?h9Gv$D3J=%)?sIow$V+)nWL3@&p^nw#jB+b@VQJjAvg z^~_G|I%pkwxI*ye3u0pJ+)9&2FIM6-SqjA=0K(qJkfU8Eo0D7*lRaH8!O#i)GE`=k zFw|ac-qKAhDe!A#xEeVXy+aU&6YUMf8uICCZA5FWd50{@ut8M1NOv6+^?hYRj7O+l zW!y`trunx?`c58^jX9sU(0Q0kuXHmuc6^ofR%^?sxp)|ucUL(wS1ZZ7tOW9Z1)(7sqT!D zL6jIevsMqgHFRbcnA^Qua!Q!ZI#AST`?q-6tSpM|%W7C-wv!-O)?N6@w zdwuJk^v|Tx-WNqKEuP4t9Y#B=cePNR)7%e!f@{g4w(?thLaQ%6mTm4g-oijaDA{k@ z$;}c5Atgf$FLLF&cAISZbmdr`)~pu>UX#3-vmlLdb)j*WyKQ7ckC_54AW$VtC2xWw zQ$6}LnoQb>g302CO&gUoRX5f5wC@t+hzAhEnc4k|riwN@Ip{lXotbNJprkkBarF}K~ zylD|@a$@gewOK5bT+3@Yq$uA@Zyry}O_ zdAWF@S*V;*E!HmbNlZb-_B|lS1o9dh z=^ zS|SW_D{|pdjxC#%%T1-mTH4ogn1YqD3u(79qQM!B#=%q<7_zjp9JZ0Rvj&)1Z6#o? zZ7^Lnl?Q!^`s2QC*IF6p46UBe8RO*Nmyg^41H(vYaNiGi3H zPGX7}ftiU(R4bARDujVq5fLQ{RzajvLD~!mazm0JI2`%&&~-LSe?J}e;QV_ubR8N2 zjN$r%f{6nMM2x{^59cyj=LLg2AJ{xH2ykWiLNu~ih*`sjz=SdBoe{y03p>iu95^x% zIQT$8(@Z);1~y&bGvh>OMl&v`gy!+N+IE?VCh?5knQ1w@vAH1)Y#g95#&s}b@=_1I zH;AKvbqw3P%R6j~mj?DW26oFiXj(DJDTx(5^PKaM8+7+QPVC}s$tw#l5ciTx;?k|o zL*B9|FtScGAZjrT=MBS_K}BjzW)@8vIRqS7fP(}CXmH>x8%>bX+}^MU_NMm~hg}<``jPo*;mu0a=3v3mJk4KcB|r{eO@5X)i(6{|Ao~ zjH+Yc>Tl7X&-z z)+R+Xch!_33|K`S2nXs`CV@#GJN=+WM&*<9v#3tEaHk=qP=^sXKgnqAf~8tJd)otw zsCg5269G;Gww@@NXc1&J=_h-XM8 zL1b9XRZ&p7c4^g22Y1-%;rM-%5#&9*?_WIkO8!Qk4__ZR)`-`fUT1w3LpIko-VM-N z8({N5{fv|5g0nCPM;JpN zkY1d7dSv!DukVOFo%~xTa{l?|6>^^du>TdPkG>zg@A-Bb5L3~1-y=hB;bbagXAxQA zXDE2fnLb~76n1S&a)g8J2=^kr8|nwPfEwxI%4rNScuF;>paW9GQghLh3gY8+yiSOqj_p@lD{03+o z@QEzZXrVkm&`sIm=)>vQaN*Fy)_ziqMG`agHDp**^27LKnuqDC3CN296R8YbC}5^U zkU?>QvI9bqEJ?jI;VOj;6CAOT5Claqh=^BNOG#?f5d=vTM8zRR2xAnn0@5^%EesK+ zLsbR@7(ufPBD6*VQgy*gso5V#f33s-Qe61oZ`}g`Y(SI0_wMcczkB%Zxv9kGjJ1KP z$pM>$+Dick30P`hJ@Qixk+cUmNwo%e9z+lavQPW6jEeV?kom&eEq=;5+D zC|+n#?4rcr_ke>3W+1YXv)Dgx#9%Lu(n2&V(=wQl^GrjKL>V|j#YkkPWa(9^|N*%wW&6C6q9L^ct2i zfY{jqG{JbHD-0mJGYE%7E0|)$zRU<3sSJe-NGK2~B3z`LawEurV6YKIsTxyC6hWh8 z3nXiTi3(dN;cOC7Dy)+&C5S2rvKCT>vch4P1QF0UFgd|^G6HNO{*;#VP2c)|)c;e}?5e+I+7piK=*TF733fHoy-P5#NvXlccLY>~ zvq@f?=Hmxm5$HJw9F{!?HG~;QP;mg4`GgH#WE_qJ8sVQ82y7;G;|d!+@ewB+4g|qc ztgYM;jhv)>Nry0+K2XC{QipQOQ|xt5p;056A8dGng-JPQtz$#(dY;0HG()1NU5RAaFs<$S~OrcNueQARsXOjR1TR#d)3TO3^5 zE9CxP==QK44+m#N_ez?xw`RLe2sA?+!w&qBO7NAX8^mBsg_ctXBr=tPRux%*f>|u@ zEP#ljBqBnBA!gAbfdvM!ve&|v5oaAT7D)j_U*}*MmQ+RoP!$9s>19+H-HFX~0rgY))DN11P`%i4_M*bt5+EZ~~S7Kpfb zDZQJxFhZz0Au8$okJC=&-HbvKcwUz!j8`i=b)GC-wCgJ9Y@EjGZ3L4tLs&`Z+S?_b z;Y$C1`27gcqsg)k%?yEzkm&Mej@_y5e1#?AJE1%@(tD?-o`;1!<062hf{Z?Zf$*|J zAWSVwF-cHr%z~w~Bt`zvRgj>hwjby`*^2|Tu&7Z1WWZ!v&I}A0K3&D|K1fV1Yqaloe7OS=v#X}EC3|;r@pFFS5U^bd#_TjxooI{WN z?biQ4e^XtXo#WL6m~=Fl6jic8gt4|kGbw1$lk#R~V76@G$uF2$DBO@gk?(FD4_r@W(3R7kHq3ou{_Hh4uI}9x6qi~W3*PbO+m6bIeO->xiMVRM20(sl0w@MaT`NfSeZ>^ zBa)<4j73(Isis*r(5*k90{2F9ZrU~N@LSG-x zyY2>&Smev+()dw-&S=4Ziz4*WrwSlq*uTL3!4XBA*Co)tDH;morJfh`y??;i9MR$& zzf3D?zrzI;KZvmXEM5~zRN^%{{yXObCIu!CXy#^^6pNt+%veXywH_dJ<=jC8_Jg?+ zaq$S%Zt8QqMWa%FF@fV_l~UT5IQ8rBaAO4cxPH=4UDI~Z5dj=d?~MaY1kCiBQ#1hH z*9-X+nx)x&d~)g=$(og+(BTvP;Fz#dvG{n zC8T6w3c@>Ll^}2PEHMR;#97lho;?|?QFZRsJmwf$4=`(11mh&ct^^SzGMRx25WxXU z%)mG@?FLm4X}Ss!e=P}*5(OHkx?#VMoxJt0BA z9(?@rsR%vz^?l=+j%(g`z4TY1ts2c3$%Vm!gbe5utjf^j@sMVY!`mUrggFu%RDB<$b?ZQ7`pRi6%%9R@rb;ID)w*@qaMfm}lZzt$0p9#7mz;w*B?Mw{^bB zW91R=B+P}!11cO2C#(yHI>yfi!{26v((o?LF+!L;K*PGOow{(rj@h`$q6zV{1Q;xG zL>#)5$U5cJB_$7wPR&!<971SrQyIohU{(#JpSa1Q2}=s&H99%Nm_cO3f`tT%03{28 z5TRoVh7^NoQ9+EsuCs|wSZIT6l|&bw=1eTQ@h4nv-XSc&++?O$OjW&@ZfQ@8{?E~# zljQUJKi=&z4uSrmcM{}-Gd_l1YDU z6HRP@26#v|qYeA>1S-8zADPyZR3&X<4K4NgjwcU^P^*s(h+p3}r0k;s{yNZ!yKp!X zqCuw-sh*+)SB(RZ5*$5sD$*~q`y(Fap7Ot_54l;-S3#*a3aUBEbLLtCm>9_Ee%MmpjN zf{3FrsM=;HZo9CzxKbBe-R3CmIGJsA5fydH6r z4n4#qCl=d5EMUNhr9JF2Sj*8I2QK69RHTEy$uuU@@+^Xu1- zUcGts57)0gXPnLtS@jt29cmv@3uI6G8vPH!h1_k^jL9y`Qe6Z!EvHKIn2=g0^Udzt z#9pkM^To@&STzu>$=DxLqT(MOBR2oz)`3=^;nh9f_eNh$?lfigOXjIEho#lgc=bH! zj*P6!sjTdh*9$5id0yvlDAJW96YRY3u1QG#@mq16@NC^Z_eEXgZ?*EPvt8q*=5G6< z_9FXXBd2G(o!;)&L9ATl|HbnFNz;MT<52D+ng$jhHGKN}lCkEZvSG`{VjN2l&{Z;w ztAVLD2!Tde${z&9$mtz%8RI|e&nb!7U@XcQ$jSlrI-w{+7OtO zyJFkE2(B36ggAPLd9cYHlA2mbW|CAY3A$3DShRtno`SSqcY=fxGHzs}AhQ-rSf{2! z2ffEdZP4X}=(xIC+?F)o{@gpz@N*_|p!O(fJ=1n-vYk(R&?w`^_VMaUiNtBEI$IF& zcV@W)8U0GGi$!T-EG$GwT|4wWXFi-9a#iY(K#58K3IQnsnpB~nN>nIPk)&xtg&-m+ zB%U2M$+yghg{ht1%6r@l-jT_gqjBhHY1*Bx(pcNfi=!R%anxo@({kppc}g-cL&6iG z=R@r}Nz*(VeN7$~S)iL-vJ7^y%4{;zUG?pA+c2QTM^ZMGidZ9!je70tcS2b5WSmF@ z+~*cl(t8l&Zxjt#XA`DmUn5#fM=sB^*eSrK9vJrGK3xT44ZOpqIF|Iv@$mXxM&RNj zGu5%;4tpq>G}7xPW-O6zD}tYzJ--nbb~(Pb?ccT?{fUy>0;q;<8Q|! z;e<0db6$O9ziyC1y=I8vq%i6YS49X+V}6-}gH+HZjN!;>X7J|qb@47`+>T&U8-!Z7 z*x~Ol9GW`!r6=4RFpfC6T%VtCeJ^dWf+Vs8cBdW)`OMerguxP;{8y7iuPEO;$s*pY z$<>3P7YUi++KMa@Lt=!5kK350w7}yVOTKX;XxOLFGQ*jbJ33+3vlF^39l4gZ64652 z!t@diwXF2QLmXteqoKxjSqQ2^{2ju(qB&|^J18ry4N_VkV9@Ty&5}zU z?6KWe6CxBfj@`TCx=nLTie8R5ha8hpN=%{S)Iu%Djv}l~#uY`Y=Hl_>#zG$H#8_Tl zzEGW$`fx`S9gN!(Wz}^eBM&wmqd94scU|ibgm1biN75@LD^XpxJ4+*F6=+4mpks{~ zlA^k>#%3e9b@gupp5q4HOz&CS4eBjNZ5?rww~4j|k{D1s2*53n3A92hLPoN9W!ppo zY3+k1S*>>uBmLXGHh)x}AJKTPE z#SFXRtveX0UYOaoV<%$p_;l9jdF8_Xx!VJzH7BVefH4m&lua=M7?T0vq(Y8sXfeZv zDi(JuE*_h{gehpeOPOOGyDfBvgAU&|!qn_`EXdh%I2s?Ydl6&yaPllJoE@#1^yo4Q zy2wVeh6SHaN0%KjoJkpYXI_}w=hwX2?ks}is<9YrQ<<7j(SjedT3MQHovzF+#ZBWb zGsmSv^{Q?i)YUyN2)$Whnv4-{)W{+9mvm>1hc-4etQ>V?xh3m#EgTN9!U2nLYjIq@ zdpLNutvUtRB3l{CqNHnY63A>fuT8LSf#n!Wjc>%3ToCRtf*M_MFlOlQInfqCq`axs z#6ahE6ckJKGeZIznX|O=w!4RdA=Xn9GG!WOZ3F4Slr%hH-iog)rh+QRWOp$>R*%Fo zERhhi)Y%3(ccZgckBW5-G&9pEpW(A@WT!(JQ?U7AjuFz0pEJ~XEVmAo2e?cI_US#vQ7 zRi}lRa>L>Ir^llWFvRv4gSQbBiIbs@jMky;kbB2NvmMX7MkyLlIt)eKN^C>r#ZF&v z@dG&)qfXdpj5%yDa>A8Az9QA;iF%*!RU!3f^$0qH%__3s6L4>8j zcQm-c)s*!ko_)J|k85-zafE~KJxogUz_xPvE(a3Gd922|iRa&jCKAZv~+w#=?=>Nki=lbfBw ztk$lK!Y$d2Rl7Y+Qk6v<&>pEnt7AWC$mj@Ho5N=z(;WpSgaCANo z1Q7%4>A6P>6_L7T+mb*uUYPT;+s?BI`9x!fpz2{-=9a5k?sMId=fPY1HplpRw(A}K zij42gb1s|-9lnfpvj0^kuRLS>XsP4$#jCgS>I)^3YO~*UfQ}BK35>UwSnCcQ`u6cT z&ukrZ;=*d^HL--{fQS6LDg-nT-Db(dwiuJp%?`^CL;7R1=uyyE_7Y)Cf-FU>z|&n5 z#z%UF`ubtI#5~}Y-E_0Z=K2v@2ZSFy4&)u=-hgZ^$v(_edEn{8O=Cw}HDZDx)id0W zn{UOc(XtXI|3T#}VSdORBAyRK`flS9HV$dynu{efI7_Z7LEJRhPS=KPh1q*%mJi5O zVUmKpBd~z;05W<;Q&sJu`x#EkOk8ecxy!57^)II|BRrsV% zR3dh=CG#iRJs_QbE%e0mwNCWzY-waq>ZHQ*`JvJId8^}}rw=U6k2MyUw(M%HSJ!4e zk?8rsVdEZKD9ldhI6UZ?oOy2Hh2qt2=tSVFj|+9n*>N{(nCE8aZn5ya=J{oDkhbSr zdTwNUF#3CcKb2J9E=c?DoyIj$j|Fm89#m(`!s@8Z^;91Dsaa>&CE2TX%-Nq!Vxrur zdV%6`9#I)l@E5jlqF?IdXBDVoYZO$dC(`~p%sQUg@i*Og@s{_V>~*_ynS;6um(IHE zU(1QVv8Puq$EevjTaTL-BPH^cs##uIUEvcq+$vXRFu|a_G6@b}8**hCGQ5r5rjB~u z*-$|6wvOkb755deRma}nD?A&%-FbUYGj!&CwDF~sy>lz;QS$oRMi+=8^qio?EOniI zYi_Zf6OSpO(o>RQjYJJc#IchB#IS!H> zoFbW0`grDMw1#(zZ73w0)^L-WxaEGc?CfN}MPis~oyw!9M)4W#db*!ydSD5wH5l+( z5F}~UMmgwsJ*<~M380p>CA+gdbL@}%UR6CBi8d}yxBQRAkM-wOUqFiNu$h-20UV)Q ztvdA8?^}qM)|jK_4NO?3!=+c|f625)tH%b%|FU*~&B-58*=S#zNmF-#u;RoTVNtU| z!2PmtvVWg+xHD2;_BeC@6o-T~6er$wi>*d}EX^CuYHeE8TGnKW|Cyx4<-~HFaa@1K znIGe8l8Yu)|!xu5P3|ftf6|AhTE;Q9stTm+sT__~3C^ClBB{=~p%_Moez(B-)>><_j zd!KKp*&RnCn6`f?!Vdui0ojZ#OK37=rQk-)4-U-hHIY~d;71%ef;54sEZi8QhO8hY zmO~cQal$a|XDl>;gN_{H!vaNvB2EagxNm?QH%T<&32G|}+8D%dj2{nYadV38H<37* zu|n>GC_S2t-*HUdxG0BN?+BlGE!vT=Oi`IR5X@(CI?=)x7*N#((}~V-$7GJ1d^F(M z$RZIC&K+v=wH|L!i!EK4g45;Kvez^SB1K$Jmuh8}h?FA@TvNAKy2gaB(o045+5L1u z*Dlp6Uh+L6WX5p6PqSq@Gt!!HNrnf5Fksro6nIuXaE07iNKV6<#t1{{VP=|P1eQCR zXh{L4t!2eCHVqVD;~|W6&S#E@%?}Spge>4Fczh8o$)je>88$Gni)MpHi5(ASPu>3G z+VG6{&VMa<@QWM1vs%V)#yt7Pruoa`7{;7j@FO;C$=dzDtl%j+7sRksxo|Ve<|Mb8&e2QHlpq{)+n6kJuPfv zT5>`{oQStEwhS?_Y{pFs36^(*ALGE3#LJ_+w+D zQfSF~A0p>)i8C9=j4-sE8R?+BZG$+-_l_F8Yt#c=hiF4+0%sw_$ujaEhE)(pkU@h3 znXQ$ZVa9Ke(=qi7w%4iQ?}<-$C8!Nf<#zq~PV@O;F$I0MVfk?%!i5EruW652$37IX z5l32zG)25ZnqoZbw!AA((zYQK4W5f}X4Ou0UG7J`IHTC4n7ya4>8iaZzG6Xrt(!8 zuBL(-k_!;jhDsCxwnWvC;5fhz2o;-C!?P;K@(ce3$P=1RD`!Muj04 z=_HhBUyJo~nt!Q{-ZQ?rYR8qbCK%1v-)c=D*Xm-drVEHVv=+kcMfEhsrHTW+m;)_9 z(9d02v-3kP@y;FyP1mjCNk;LGb5r>5Aluh_<$tEcUH3f;>sa^IxF8^ zBZ&4vvyZX!1~h%agJ>viVtAx7Mevk2QM|@vY24}uMCwIc%p5Nkt!apeDIHu<0%R+>2V~P3j~89i8EC*% zF__K?4sw%TG6ldoFeWSw+6q*d8ESL2Lxrah6yU&xYPFJ#EubQ@q!x%T@%`iY+3wh0P-!pM}(Kj9(%<}O;xhxbphKO%+lyGOH2_T}z2Ru2NYyU;F zWjRmleu@GhijoC2M#)3H7J`a?Dt^P{K`r7Nj}8^to!3U=^|>ry4X6Po3QS4oJVX4> zVnuYb(SnNso zS!7_KcucBTkoRP;L7rgK(+>~t)h=?JSFruff1kTg;Q8A2OMnsDrlXE2mB_B5$ME6x z7cgq%rfKf{hvUA$=sOrdnV14m*(Y;@i@+-<8%c)&d?xR}B@G!{jgM$ub4jhGyNRFo%rx5WqF_Va*h?5#Pl|;+65Cm%p5ObDvl9)z8;`b2^>L!%-AO zlx&U@2b*s=%jt@Akn-pE+WGB@?Ee;%BCKI}Jwe02?_GEgL|CNRlETa?W_6&z(tj2? z@xC7S4QCPEg%@^L?e{rwMh9c~ddTMmxc4#Q@5ijU1i&*(0L($~$kd#+aPloaGHY?5 z?YV7l5t?7<2wopP{LVDgs)5^n`W|3a`4y=K-u?#)Y7Gw)AAJ!abGm8pSGHe??m6a2 z*2a_OptBLBP97j54e2{VOyl91xifs!$eE0vbi|hMN6}Sv?}lSwq&;66vCU+Ip|1P3 z-6PF|qAwD{3a#5Qw^?mr=wdeN4QpW zV99U|v3=7wNb06j7#K||#fvBNIGN1@Z6q=3f3e7TkuR9V1oHz=G{8h-8M&TmC=p`9 zYHDt7#q*UgUo@7d#58pp}5sz}rlWU&g3EJD9yj@K>r z!@H+YL^y1Cwh)FWm+!DwhY?o+4blmtx9=9XVAc@Hlz~q3mH|ngtQ3MB|zJ!AiP7xyj zV?cQn0Z7SlclZ7Io7R5DzH4{4_UnV)eb_tH84QoNRO4GyS}G@`S~rss62KQ z%&WL~oc-b2L*y7GgS?%_jqAZ%A5VvQ2@&Rli$NyQUFR+b^%zwWC~m|zh+y4+P->^^ zB(kiyd@=7&)h>z0rr`WH5Aw4F2Y&)Xf4>Yi$xU@@)&-x)%#v{NS3i}5{rY2SJ{+Kr zj48TN8GQBIlMP%x6wmfaZfA>)KES-2hrg3rDDh2cZ4M@L^^pCuA_6co-NIwLP9Ysc zi#-H2(}am)7{j&BtGaW(V50W{%sSY(b<1-yAM^J~;Mwt6K~#22L+@p&u6`#Fw!OYi z9p%<5X;LSYmf1b$!O6;|Zw?O*|~nH72Hr3Rewgi75<$!X_r! zBI-kQMP#G9WSWMZN<#&s24Wf^*NlRY#t`ETX1Dc43Y-Qann*388XE=u{zadCc%O>i zJmvb)(;r#E{O9w2i|YL9DHwQnFgX$+)D+pq0OwBlc-_7kz_89-yV0!*QB7uM6rgG5 zFWoAcPK#q`6EKBZn&?R;1zqHAiTI(huzx0laJfM_`jx(;mnhdo*f4J z?Hct0a#-~^b^O@4lZpzc9L^fUB*Sr_&{w_oT^(`Cfr>FA=gcgL1CYQ5Dq49@qA*cXzY=$Hte#s0)A|Z@FNeYnszvsh@f#%p%xTX>|(S|UG zG%VNBm}H9zL}j!X2<@VQjPW=nNsNZ1f}DU*Du-!9P*9y@IUs3KL^k3XZluvI4&ovr zh>40KA|fWp3Em?@8j1s`8VL_w9*J1%#=QJh&~f{yFf-dVjK(q5>mIj^bv178U}Chj({R{4wK(@*LsHc+H}V zv_N`!ojOQQ!(}t4hR@I=)=088!V;*7iyYm5yZ>C3KaSwTe_8lBbOUc*+V!h%1)C=93s&c7CsW) z5{Flzx-=X8UkhU)8c&U%VW~~L)3#o73r2mUp>JlaivF<45jH@K3pQ^;g(m$bwGn)A zr(^Mip8MmtGUMLszm0%>>0zW|{wf=RXi3G(9be=lh^*mZ9yj=k>#I2h`{TQgB~4J5 zIyG;--R50VyNxtsl$mj8qMssRIz+t2+$(+dlaGe){}cNX*iVfdA$#lkSXJe>$s6dh zFc~be40h8(;{bk0O7e;*n3y6ZNp}Ib?MX>l8%qeJF(jHE zbn|@YCUp!mxT~*nf`puSP{SuT0||&?1pnwyP<7+aJ$zSwed2s;o8<0pweMWxjy?`u z;Ks^YFhHh8Z5cL+&?Lzz%*dtZA_6cN}bLp05#k;$_|7nodt+-4!!QAx_|Z;2eroeFYOBng zJ}#FJMo)==%&cN*naW0$_qm?8_b2G|;;l174we1#d}k@>UwE<0L>OUX)*#6Og>$gY zOIiTCh*KfFSxdpn8ZZ`D1SItwy6B>1DyVQwLqn9qM9Khi+jCRQe z${1ojLf2~GJ&ae8i1oBCq$T@ z2io_3E7&?3|V5DH;qtF?8IWE73}udK~RI>6+TJrbjrP zH@rx;eHK>gAK$cpgANAp*%U5l;m{PZCW&eVh<^OxS6FcG~h(xn7 zx-BbYlQQbZPq`)5JW@fU2Q$sCrKNpNYuhly?j6OCZamSo3egiO8kN1&ftZHg$WrA#r*Z8IKcaF>eJ&Kz~-*P3lErE#yh zrVGO7F0{1Ut;{ggt%GUYo4alTH8`dz?-F* z<1=>!9BW52Ete$9%|?&?Kg0a~sNwtB=|^?t_#?-gEz1fZa_JQmY}DRKgxFn$*xG_9 zqQIXzTt^&XmKkM+4B{xX;etuF+ij!f?(fg9P5RDpj`N(?uU@@+_2b8%K7D%ddOdpc z=fxH2->!=B&Zx^;e!pAraJHGk9B;%@J7A7u68g?4>RCEySc1p9$ntB~TZV0Qno$u? zm(t@oQ05};LREQ{KgAf42?`doxuZxjZK{aRTVwBo4^|A^^+S}kZQqI~pK#UgmRzxv#>3l;>bz>K#1uL%I=%PdLbYx1rN*Om9W|-WX zN|OXp)-Ikh>muGJ9NW0&ynI_%uDIQMcv(^T9`S6N#d`8OlYBl`QJGBmmmKXCQv==2 z`t!ZhEg_3g^|;Q!@L`hdBXd-8~A8M8cf|J4~v7rd|81fN!hSH)1-5siRoefnK zH73q}m1<%!g#SgWZBG~2^v~<#CK9Nus=Q6D81e0TO-$*s$!QRb2-P*w%LfUYEQ<); zMMp)LXE>N?9PHhKMV)nxqE%_jKzSYo7z~>MOpPYbDt;%MCjr<+rzcb05lTxT^+uxQ zR+v_!O?}CDoHZEPca0<}2Q_-f$ITG%w38^_)~z&ovu{G=fctX_es>|h?W@Kv@FC~O% zLu9B}h!<;NuA}_$_NiyXa-?@579yt64{2wo8N+_k_1t7eH@69qc0WL1$%kSDPObFnpz*P|Ji?m|3dL zzBJ*=`%PGX2$j7~Zf1kghv^&CD;k%7)OJvE3qv0F+*r?k-1 z87+D~cMxYxheJ&ZtloJ?AL$E!35d=5Z&X$olJVIsFYYrR>JcY7GxJXyztl%B^L$~o_>qjp@xCf3yh{`unuk9nn}2gOHAviFD_SJYKw zyitX2HaellbL;3BWNDwIjQGKrLUyqBgZSJ>CvI z=^?WDdEW5pX{H|!o;Xa3s-9Y2y|6(1D06FIkc~MwOD7`nA+6_%SWRsP1Uhg|8-882GxotkA6#jvTvLgdqX z%8Z@elM}5+4R5TUC>A0+yQ*?_^J_^cD->vJI!1aZR$1dJIJftq{S-)RUhBDJsCx&u zuG@_y;YqPZzZn;lQ4R!&q~npPho=f6drVbA-0d`F#dytG}+jPJP)!CT9U?9B@(n2~Vq^3!5*i|&G4qoOTYylEMDW!upA z%qD|qEz9Q2=?Eudr)#um>q@rvQk67u(zxtw9K%}8ed8#ms0*Co#6LdHL4}X9jAf$@ zVa{|KDl0DQDa;Cnz-Tq?zPaRGk86lP^dzUpQUF7bJ7s z&rBUgiU6gIPRCiiW(>^o+s;y=5VGrbjwT>vL<;%J&TyjiU1PhhI|7ZxRaZ&y2Iv}@ z=d&T5J1QnM!sP{RiYSFW!$I8^*h-%6&fwR=8t1Q2{KAw7)`Cofl6r$McN3f@3z;S0 z%CMFtaKxL?`3GpN^JGkLS!tL~M2iGa38vmJvhDa(JZmNg9Ij!lxRR(IV2!ONjdGAV zJ)rbJ_$Q)7ZA&dy^&`5ohAQ8SwFOA|p2rNW7OY_NS=b^8AVh13of!l^1i^A3!wB&C zb!Jdx@DLkilfnuUXtdyb8aCXcjT#`MZ-``x<>DUgkA4TGK|52}_*iMDu9!y9i2`64fFtVo*HkSc~Tx9X)%tJ<-|`JL%iU zi*?xGj$T4%80dRuN3^q!;BHGp+c?Vhrx~tpI5pMCRy!`(xb7jfyt&JrXKy4dePr0O zBP_b=YpN~v*Jph-V3j^ww0UEEPm^A|1mc^WyDjpfTuUN|gDK_A4KFI2V@)Wlj`OK4 zOI7n`mMNB6b=1f%GZCuJ<)#}vWlmkoTInV$yLaaMEZ*eGc-eDiwNcg4GWfGrkV4FR zeWx~N-A73)VaZIOdoOb-njy1QWOZ~89Y(8~#HG^)sV^YcVY_?ooZK+e97K~gdSTE= z>KRigN}!qu5y=9j#KWfB){%&2#5RQ83;Ls<4xxLsN!7&1BC66yjUC-sGgbp=5$X&= z;bj;bG)tuz>!8s+JHTN~xlZ+<~dQ5Ggb1LVf`l#QZL6 z2pu7K#Zn_O+cJ`4Kh6ARZ8?b1o-15c=gigb7Xuo!vbo!)w5ZyMtD`R(M@ufl3AIF1})5#cGy~6+E(t|6t32WITo34#(L?rEufb3Gb=f#9ow5uSpbQ+MJYs4 zeuG3p6;(hK6j4Ay6siS8L{= zC?UeC%D6S~+kmQecc+Bm-EB)%2{$EC7UK@-?%<`DY{i#Z&pBP&{P&8iofM^<$5~#T znIJKY2O7yV+AXzJmS|yA5J|<%6b`~HYtuwnL0E4NW#w3DWJrxJsIWvDbc>q^Wo5?Y z3l1Q;3)E99hfNd^GsQukG^|4rz+w!H(8Zv$1_Ne-Nhb%}`G33X_P+D&gYFN0diCm` zlzH{+$@7ig_r32J`MqONw%c!kS|BX7YI+b*fP#@kDf=?AusSCDVRdVgmqb%bcvGp& z+f?ni>H6L@vf|=VD9r|Hla`b-$cJGwi{XwuaFIR%& zE8eQlGm@sCl{39OQ1DC={KdbpVhA0_9hr_7uBlG@Dn*J^UEyY?$wP;><`lmfuZI?_ zd($1vwB%&P%){h7S!N)oswPIm{CifBVUsxsDN)~jV;zAyoIZmI(@iQ71f4UW&Vj@X zkUK;I+N2nXX<~^gAKVy;DrD%5SW0M}KocX7kqek(Kz|s=SeQzIjg~`5;YATdz~nlE zEsUv!xpE96B~DnWq%}bPiQttv4;U^4xjU1Es3_M4w3?h|Dm7{}$XScBL&LALyPoO% zCX?>1&*Prn_dky(NK5fNd=KK93lKSC5$DaC6hlTnocage*?F29V`fp$sl8HAouBFT z7~OK2)x@YgZP`?E8iW+h{qcjvN6O(AtPMX8HrK>4!{ehGO&&sgC=)_FVZ~9{4Lv0s zyM2$O>$Hp4Fdv=1@n2a8`4>{fNLleD18|?xY4s7e5`M6fOXz}LqgNp2RFJGK%0zq7 z3EIa8fY@be;RRXr@q^cHk{PXsz2XcB@zQBP&%sYkDGuLgeJ9IK*Br7|yY+aaX>|WD zqD#e??S{~!a?dB)6$c^V@ZDz5(h46KO<`>Vk7E=RT6syKSA#uGjYshicDd~Hh~T% zu;I2yDFYBjz6=WM7EeUtL|vg-QbW(^{LA`2LjFEJe05Gv(>^|HGk$ln_g@^|vj-WR z+181&%01l)@+S)d@cv~9x&@b~pHIT}n`vPE@YIcM+jjT{ zK~STywcek&Z|-~CGBM-~!y`X)pLV4Nbq{UGqN%jNQlaSO0#T>476D_F_RF1tr)t^ zNd>7fkeY~`*In*1YmK5n>~`Gy(FfhgosSqGlJikThD85w@Gpg#@2Pj z$l_zex6~XZS#W>1c${86VRRTJcR#pROw-U+|VJcXK z*OE2L^QwLlUBFe}j}s3X)^*pL=IZsHr8cr+3ETt-;S0eT!AQL+>WvbVJ(moQqQ*sx zhkT*_vi>Q&1)M?HCmhJ~D8I1r7bOIaVUnnwrQR6}wTod$%#ZMl%g@Hdx7 zaOs8tg4giB+$q+gW zr)nj6Fc6mPNzYmjHJ6i2LO-9^^tu){xNv6Z>?o4^=@m3FmvIbbNJe7JjL8reMHW~| z;@VysN45~aM6f&{))*#AX@SYyxg(+qLnAE+7{lR~aa!Fe%%KAjMW)kP0F*#$zckXC zhAK@!l_W7Bq#;rUrX-30d|+z~LM)<)H7jhWgT#2g`mfcv7}uMKYB4je`Fq!j^Q_~X zt`5u>6V4W7N)zvarp9?zT{(cTJU@%USkJfA9?*(Pg+9|6`S^Z(<=o-z^|Q?MW2S+6 zYMI#r>4}{)#6ci!chGPKfj55$fKcY1?PB7eZ4h-Q4J@-;KyezI!foR$JUUITYl+-H z4j~El3V;(Zzk`oyr5JHNovZNY7b?dO%|t;c@v)Z6@l)bf89#)6KS7~!e;rxuKJoZc zJnJ>wme79{L>-;Ne7%>?i+5NLgp0la$_0&P*J2k$8z+VF9&3P>FLfl@JbPOPL3^3@3jIaJZu8A~sc1hW%K;xP7V8T9v7#;r(P*6xA z&lXY0`=!+*LD?ok(`F)fmZuG1tq{y93|0{RIwcUypo)TB41xWQprL|pSwD>~rX+^2 z)io$ek!X%pn1G-akd+jeGZ4fDkf;kWwot@Uy|40_%>8}O=-q+)-eQLL2d#VGxW~Qk zl{wxy%J4WrvMw-lqj*`e!vY?uRtpY4h?Q|+En2N)&)tc`xD-#{HcbXHGu3BV4amXJ z`cac91G6FybSRdNijr7Sp0aSj%bPkg#JXuV1;nEeyk1L5!;j8F2{^OkJ`c3UG^!k; zG2rRN81Lf@ge&^-tR-{~LMbz+vEcz%r_Ovgv;lgkpFEuXO#)y)Bk+z(q;rd@IRbtm zBE)c2RTR6T^rh*Yw`CZhLpCQc^ar`%T446|(vbgbFn<*CufliXkwrShTe#A~e03S} zapWiFRHm}-g?O)2+q}j)X`xeNgC^X~Ib(^sV^!enRx^Ux!vSj`kB46U^<=!FTqR?f zlFne`;bV|s*j(P4bf-!2XRN7E3X-J#7KcVnQ4L-2j%yVf81iPMq(f7Xg)5Z+WQ8Ib zOax1k?kF-Om?V{*Eet?_p@?IsvK53Wp|mJz5JQ2D2tO~P0!?+-RqoGMN0@%}YU>^Q z(Y~uW*Ck^RiY)Y8rq^9y$%8T}lhZ!X+UW*i`8ZO@Y51?u^G@_fFrQDz+nr?Jdm!7= zt|*95rKziqW|*7HO-;ISW#qwa;l7atqG=QDcrHjqscJ7vB=Q{9B0j%|1#l%2@F3!1R8O$Xycp?nW#X* zf(Io|(=c=p2<72&2#m1eNS47$Fo*L^+X$seIJrV`1qMRlm?4B@Axef4xjTTURK%Ff zLgkWT1~VcE%FzSI?nU?GuT}2+Rr+%n*0Jt9d*o+zo=pd~1PvL{D8`W-Y_gNI@X#}* znNc**hPV>PJ(Bpg#Rx(a8|f(5a@w~cf=3pvX0p(;>$Y=u(Uf`kv#rf0sWg;TWeBTD zP_FR%)aW3!F^)-M9|zTjF!rfYQ~kF08DS~|#L}6gGJfP9e&5^nl+oWAfn#RjT1YwZ z6VzViTWH)oSsiLS>*}N3B*>}q%?Rdw9P@EKh7#UDJ9LGS@iWaGH_qIhm5$woUSu9< zbskdvABacCvxjFq2MRkF&jpbnQYozFk67^7wtBOK2X}=%tUY9rKri#AIS{Tt(1H9M zp_II(3c^aU;t1<$+@*Ksdm=D5YRP z;J_Tf92gPIM?f4H#fP@3^doy8*E_B1qKG614L?i6VBF)K{OMJ0<&vt3D5?mV6i`6~ zFMTAENi8vq>L{YyYV}SJ_R-<*&tDjyA>a2JH6LSPkFA<#HOqkG7W0VAz6uvj^`@%W zOXmj52;WgrhupQ5k@IMte*ypN8N>jWXFy?yP~zL zKikV{wQIVmsNob~g!b=L!4YJHxoNv;Y`liT;I-RFE>`0a7F>1R<)&7OEv&qzV;Wmk z+jp0}s66EjNrr>0!M)rP+oC+o&Sfze*^U_+8I@XPt)|E@EW{Smr4 zg#(A?Ja|X>T-_49V=TW|c;(J>>-+B&t#fpPS)>r_jd7G^?O*eb@kzGtk>;@ zk9T<)Po-(MT=e%ZRkHh;%W@u0%I=*bl6tMHdhAPd-b}vVeD^P#b8b$%c)8hpdp+NJ zN$Dir_aSU|YwPA+XGCJ_{`XVqYtbFv-KYpUkS3?e%$zPOJZ9IF1?SnZ(TaW z$kN4Ic;|b%+J5yBLmZ1MxFw>KPPEp8ybJFw_lOdD>4lt|-GW?jf!94#+7 z=Ov>rPP-M|Hf2H`xq%AEY#p6EWeN&5O6OZzW&D*MHQx%b> zswLj;)nqM$rS9HfToz5N9)462C2~;v_-s12q zm)$v9Y}%lfH(!(LMT*PXy49SM5pSa?9y)Dwiar^D`g+iT;z^Txa%%eY+ir$RlPxNt7{3I?ZeOG1sqt1*ZuymPZNM?_&7`cx<}6&j(5=Jn30}g@UV@XQoXKg0Ya_*)AVZp?#z(j@OqRzDCJ|x?y9o#Ami<#zWhd}A^*mM?9 z4;z{@V;WmGki2&z=ZoQQPLMiOn=20EH+GWja?8n_v0{rvY{{l&Sam(iHpa^7fXvf5 z=31V_jYSNgCvhmgI!%q25yuXp*)6?|ml03PR4Njbh$}Avh^)W-5sWYoO1G#9Zw#EkmVBFAI``_r6CU2|n_4TTTJD$Ig5vzTUI z5sK_%5Y*wMk24313O&0G;bXlC`_bROd(y;ZI&Cs-XAdrpS=}tZddwC-b=9{cth^@} zwjRd34Hp^_nKC|+u9r^;XCSjAmj7A3$3H%K>s8%C+fPt= zl;e_9d8~pgg!7V-jNttrUmdciMqr7> z3)CKTeu4LVbHatEpeYBa_e{pBuhkvYK`A@~ z;?8U_s^sOv>2#6Pgb15X&Ty|Mu*QoYhlwmKa_&t#i!vFY$y2U%4yeIV0BY@q6~kE= z+Z7qM@vdFgSw{x}ghzJXQInkWQdT1&xydr*XiY2}6u~gSEh4mKq-CUN7&th|Mzu=ZUDXxg)@yBJ_Vw+Cx1jac>-S zmXQOLAw3$Bb-bRxHhFh3VYk4-{KHHbwf6@y9W>14`ehk*hkj&KBDVBSb(e$5-0EZ2QZdy~Yc5s+Xmtx?KKUJ{?9e9z>ZPe6{2yEz?RzgF4$0_q)Y{hZj;QAb9 zn}ks=7uk;&m%8AQ4uY37;&g!#|?lxfViuYBKMHz-uFD(n7 zB5=N(doCul!vs=#nTF}lwx_imhk2mfcY8(}L9;IR7+pz{`H4ICMeVfpYxGvrb4)yroyi*`u8y({ z>ywC^y^IyEDnvm_mv#j~l-7rb9EWB#WE^%CCc(Q0X*n%|1! z<7lnStWmb(#$Gn2zGr^|a%aalYepkWEJ zpq`}~?{iBwv9DFis2^HKi-759M^b&tkj6Mn?A_M-Oz=^#>ak(vq&e#NUpRE+L`(?9 zx^&VLW15*qY?6*phHH5@&P9bx(&|lnHG7gpBhFx>E7oqx(R$W5UREexrE>1>3%1b-S!Xj;9L#m+UC%7v zMEgl^FVVa?V!BYoNbTWA$;d_ok@x6 z7(tOk4})P8I_W+ax=C#LyM&?DbN0tV$$5Ot%z4*j_tY)CM(y9QSg^+YDJ;7+k1vn2 zGTOtfJ)-4o%kgS)$aku{JA#^!_YUV2cU-9>Z5c9#*^BI_+kw!EB?)GQG;ywq!F2VU zIfrhIXuWc6=~-Bv-O^tB!h+{=a~ z(j3-bebBA&SKybPTBoU7Z?yQxX`INXnKP#2(6hU-DA^ifAT@L)CEV`Kml5Aj4r;!* zd3I~n=4z?Ua|Tuj01&QI_Z#dH`%f`yCqmCbo*^CRo)e${B=D|kceQbHRPAp9qu zzm)a%guOoGcyA}#OUoThN6PuY!toU^j$RNrJ+T(a6<&j z(xygA$IExj3dye!;%(dvLl_DvSRx?tnB}O^f}<8F#-|*4bjlzrwi$&2nP3VS<+Cg^ z7FHFNn1f3EKP*Ka3q!!v7Ld;Wg7`Bq4iw0seY5#)*6>^65n2Qr_NU}L|3JX!Y zfh$#$J7@Z$fWWFiA;5sb2E;-E;1rQL3QNdj>XhnWHgB@>ymNQ>ZaUP90U#PT497j5f$!N*L=A(D7xF95flAS)?Wk2A5ufG_wpC zF4G}I4pBRN42>u>vAC015oaVJ7Uu!>r%nQXde^M>cbZGsqNYNxj2_`Amg&nUhAuX> zhbnBN}Q#~F*S*RTHUfbdp-b)?T%cSMP?$WD4b0dCrnYP8bVSn**9dr?G|CWYSaBgF zSc7cW5QP*gFt{^`FzVtA!bUZ$krY{>MTnCODaE8_O^{;f*(_4aRP<{fPw+G6<#Rgx zupT^hK3Gc}4AfsdZzr1S`HgFQLr7w6DM11EP8@*YT`nbXn< z?{)m;F-e3UMJk=za`$qz&NzwhA9;AAHs*C85g*?0d93=e`t9uRo=_#7;9$|ehHF#*`*?U}NRDC{;tlEo)y zhKA5(q@_+74-^g4Z^#VLKc<<^1`){!9Qruk2%SJ znR?AtH8dx07`#Ys9E^YtWV@ZprsXmQ%n>!1j;AGZpH6J#1PLuGvsWUz@i zTCwpptA!DQfDC9pS8$Jj@l6>WDARh%;lz5!kA!;JuYrk$bmU24J!dtfBPzk=p7F8@ zgW2?HbzOkv8^%^sx0eUVb|by%%|r0cN`%ZpAws$JlvC@lb8TFWF7eKx4%s>Kc;m#| zGt0MyIIdW4UE>3n32^ zcZNYN4k0R04RMe^K*LqaQhH@1!IDbAQU~GSQW;QWXj0M?vKTfaU+0sa9r>R+ z=Z{g0W0==CLrWROAyy$mL|GKl%$BA2GEzuX9wC(W(gb#{poD38Df@C|ShTikYx$KM zm_`Er(|P&hIp+l`9J->^hZ0-ex9yjwJPK2NY$>Dn#kpSizlV+*;C}m#Bt9?dF0zRn z&64jB-WEVKxc5ynpK-+^Pk7Xj{^-7#kHaQRFdE;2BrApYO?)XR_!CqIzL=o}7IeK@ ztC9JENdi6e997}>FmdiPGg=XCIm|vdj=T)RttQe1eU&WS9Z(Li$Uyie^s|qJ`sl*i z8Qt`HhLq+FN3z^_lMgdC+~Uhl?s&&KXr(jx+>U}g^ZOzz_n+_6VMpxQN8~szXRa)! zm--oqSdZFC?o%-Yp~!3aj9)=alBfN(50P_D~$C`rW7XI?Os2?~%kfOHJ936(Nn#1Juz5g>pj zU9H>%Vs5jiLzIn*j%*N#o?@P39 z9$yTf8`E>dsFPccxvc1~gj*LzmU>$hCh1wo65X1~%9waD_{FP@DhKjKI2cYW7q0crGI`sy8 z@OBZPIR?!fqmix=A51DlszD>%MEB;&)C1ZyIqY9apI*f8jH)#F@ucwO{qEwMH^rgRUl;8tsCB}GV0t`#G#j?;&R5k05A7rAD^r~g9DTE$-#M(^@i0~& z7Kc+;Q%*TsekiF~hDKmM^z@1t>3>&z_CyW{f-&MQWzbLeRiln|R76MDd5>d*p(I)q z2I$TlNu(m|Lkr)GX|jUsa>_nFAakrk%LM|x(o(ro77%2oSqNbUOQIBs2P6QXW}+lb z5}6Yqxeh>RD1k5`2*UutfD-}))Cy`f+lcN1tl9FvXZ<_(iy`Lm4x*FFyiqK;8mU&;pVm-z`V$^vjUO| zTo~FwF!xen7DzHZfu!k()AQR&R9qWooH-^&hMA;8!G1|$$9F|FXT;tTSatDJd3mM9 z)yg_;aIj{IYqK42ybx^omEYkG){M&!jnUm~j$}NUD&CMk7RtNMV># z{$I3X)xMrCy?HD=nX|hZ$E;`6PllS2r@$&=FF449!EGZ{iD4(V6W(-i#7|bv)3!PGv{jI_+0K? zIcE?eo(U%<{bIHh!3RzA(IC_%28(q3NsDXNf)zH`q_G z?v@i8J*CUR8{s9wzrM~~C}HM`zlVF{bbDC@U(o;wg;7_LStZ4M&AU)=J5c!*w`nX8 z#C-FPk&4A3@~@rb({>w^KZyT^3M}}tNc}l8#~`Ea$v%d22}SrD2q5Bz6KLoD3HgLb z5dil`NDPMOnK33wn=>J1R$ypMD5>$@K#eeNJEd^>u*gG{7hn2s?!Vr zRi#0!(#9Anf#(l7GFZ$evffXypz-aOd}2yx(S=BAU}*JaJ{?&srH^- zI!Q*FE7Crrs$^uCV#_6KUJ)}MdiStlDHGCjl~!!N6(`XtZv!~~KJ;8Rt4TGE6%0B> zb5Nn88@H^g5#!EBh-j`7R#u*b!;ypr7BuN)6nq0x8r2-jf}|RI0`8YY0BDGjOV@@Z zEKMLpsSpO?O~I0YXpww)VFqD@pgMp|fuTC%j_&Ty6JDQyL52W&#OH3Kd-J`w>baXz z(X`X-m-y{YJUX$O4I=)pp*~WSHAsEl5z{XH%pgdij=$INFWqY4)mh30ZhLOfXFrtoel$$zBmX*S0QY}{(DpQT?qQ=v#b zWk}+fM(q*18s``lO$aH{*%dfc;|d%|Lsj_sw<2cXD(?hd&b@WaZu$8t_+aSsStNqs>Kqs> zw1}f}pwu3NTE3mdltITuHm(KuOv+!}Jd%h)hVYtU zY^EPwK8@EyNp1s}iIzNM!8UXphz!RdMhH@9c^Wf36j;}GSWg8Z%Nj8EvWf&!6WSb% z(x_=kx-Jy?&Vux+eC%bjo?v=K(XzAK=bP=*IKqIFAd0Igu&bIZwubo@imCEu%331CCiw&FLq0-Ra>Sv&&!YX#?@~uQq*q0kQ#lSPW>o*!gM@f# z2N8#K6m9L3G)bI{;U=&aP+(_4;S3PG30H#QZVpd3)hAD{&lvl1rFtD(g zG7|`K&lI{ej$so^Q!+#%2pHP8V4@g}RMr(IIiL_tsEIE=fdIdCyV zZD3v&Aae9#CCrM!N`#?4)1Hw5JT{ro1$LW$G;D^S_g}XpC_Y-}1CkKm&+0y`CNxI@ zQ2qMxhy{oQeBg_hdbe5MV*(T#m+AD>L=?QC6vfJkgLb@OLvqS?qf0TXh=?BFsOQz} z53~O#;`$HMy{L=okresWLHoFVje81#q5M1+k$bTFTYTc85+HQyv1S+-5FVP(bN+s9 zpdH*DI)}QulL?KsBqm0xG@{F+cpRn6g;_YB7>II+V1gnRqanp6f*6QVjI5~?p)y8+ zkYSCeBNNCPbP|COAZgwr4nR??(T=L5 z)2CWtVo5N}3_wOPMMfepV{S7T#$`+xf`TTUSRzD$YX>tG$Y8eHXevmIQ4oTPixHWI zLqE#NQ&LnaLabIOU8Nil#3>*-Fqw#;#Zasfg)s;sft(?aZE=gn#KASI8lh=4gBSsv z$zUukk`j?)Z7L0cH1Qso|WLQgS$!vH5MABwJ8!2*`mJ!Na zR*<4>nYeCJlIKm`q~)es^2=>kEszugh6MS@U)_>dy^0D#+W}xgMT>1%<;j*UvZB`C zGXpJKOmU7<(%Wk)QC8bYO(b(EL`GOBg3*;)kr>%ZF?2%%XjGPz(@9juYI$=x6Ob7& zh^8|L>YHtn(9jDp3?#`i3~W)>69J?xB*{q{iZoh69Y!T3rLjn2a*G6Hi7{+s$t182 zGeidLEurC>ke1RREm4VLOOciZfI?$pkeG#oWE&*L(lD5o3eCl-G6O-bCsR_VI8qcH zh)5VT1SSX=IUvHN5fq_p46v~v&;(ACFh&VN99tGi7L^JDk)R3;LojDS3G~U8dC-Z$p#>) zSh)bOCB}-1j4-qm6h?&tjL2BBvjg)8XeMeSVQh3MgA*+2u`EbaPa6|T0k~5kO_&%U zPzgu|9B3UP6zmAt38Y+gK+Y74mQji#C?ep*NM_w+G?2I{Lcu9YVJSdm0Rqs{z^o+` zWr0C(gJOwkNoZLL6I;+48U&>_N?<||3>6h!87?rG86}B{oF$VQq$DJJSZaorr%XXwwvf;*@7*Qx<=7U_8eP(=o2RJwP5wlT3z(dZk?PUZ-ghqgf!En zOK-fZ{SLL-go`0B(qt9<2QP)!f-hQ+IDN~;K`7Xm3t6H@;3i(w)_!i5NlAeHGS z8X=OIxd>VpjUq*e&Q8~nMXbZ3|0seHPe)+RMzoz+vB9wzeKlVM6x)ED9!xyr|Hq%O zv-B(pnMY4MH*Wt(O7B^`5n=}?AbBcS{U701F{01kiyvYVv$fvks4o#>kh+$^3zB&~ z=dC>`1YmSzFxqmV@%KMK-EK@tH+b~#7r)0GDhiVXao(i9QdSn)wKoCdCtR+{UYN_Rg^RQ5X5uIB)tnM6b9q}Y7LWw^PSuyf$vA{54 z1j53H2p9tx1B*kX6h^_s9wul7SL@dEEkutpm@LQNbG$<4B(38CBZ6T&{!6Pv@tdC@liEc|3C_krP? zCs1(io4+oB7vYbYH>5T99gP;F&evUhJOR95J2h&{zt)Ppg@GaSlF$!xqto2)%{)0& zN9Pi1qm$dce$Gx&m_ne-WeHM`srMN+N8$)*+b0rFBB@`ANn;HE2JCVoAPs+@_V+zR zPSL9cIU=wI7HXjUZW)djoQSHh9n6aFh=TWp@Ij1HV6MP}`gDX(dHiO8o@XCG{P7cD zNRDFaVN}5*1l2vGP%#Z)gaKslz-_96xI8-;*j&HMN^R_N^)rT8IQxayOUZafb?%9RVv)4g7>JlL zdNCKH0v-$zAaHTT2c|!Lg3xGCX<#tt$DO*AVQ^-Z+Q(1LY=9|J-ZJtn&*>r*wgIBh zGi&;JwQ_I47c@!yTN1_5#rQNkP6a8WS4MOPG~pV2z^qz*P;i87Ps4Y-^w0YWC!|qN zC^h6~LmGtNfHf(-TrKRmG3!^K$AW>T_1DtQy*PAzO1Nm#h3)pAZGI3$7%2)m2x>V6 zbn4vziScWS!ynO5Y+Zl$Z zzDlKe7h@xuG=_v$J*AKY6v85zlnH>eno-=@2t}nmyp|BBksB#5xLZ1Y{gYyNO z2mDlb|Dq$l*GJE18~bC9qo6Pbh!phx$pR%yroXafXR{n;L80$+-)>%KegqCe;M!z^ z|FyE)hyo4~Lipz>dSjM%vCX`x6p_gb`cVOBU=Ei!i6i@uY}a6(t05Kn>9$Ou-Ti89!}Nw7Y!lUBOOI)({AjF#>>T zJa3Mm@Edp(e)oBGY+8$?pT56$SKVo*8X@GDzC$lt%gc(iaIdjet~k^ma#|yz^;UV~ z$*l9XP`*3VPi5mvG7}+wbh_8qS~Mo?YQ=pN*X>WAtaa=V-XbLusHTCRQW&*k6h`Te z#kqvU2Qf!bzc$zONkC`@dL+FN!&u(xLIza6|D*4CLGMYemM?TxPs+XY`W(W)A79=! za{Gora$I@-`l~^-@Jn0JzQCN-8(S238I@@ZR44SMHw+O3SCd;q_tb)Y#%P+iLr(PF z8MdVZ-W=8Gh;|WwA{^x}mpJ)+J@K}l%~xLcB93{!C)5D!C&B;PqE*AoxI}bVq0t&h z{pSzJNHgfM5)_&B&qb{QLlgKlvvLAypLBoYRsA~bL*KVhUf?c zOjujagHhw9DeY^HXE-y52QU!KkE{4Ni2`P&w%4ga8TFsaVe$7h?;UihC;|Pd1%6R_ zSDBqsSkTv2$o36U!joB4H_i~$N0{+w8QcGi{B{fWQP->Sxtx_}&g>p@d{$aED==Nw zmSlvHWk>WBb)ESVXbI9?_rf%wEx^S9IsYV=#QzHdc=uD0jwUANbit2f^V6@9=F@+I z1&NF?=)w94&7_(p?aN81Pr9uwG{vm!@Ql97hoLk8#lwI_h@WTqb9m8f4mQuLslQDtpS5M0-iA|THh0I!?MEg> z1hB-W>lhzXhxZiQ-tb`m#SDxvBtA zd|rhAb7VeS@sz0FUoHO8y7xi_l}Bs;E-I9*_FUbQK)Dr2X+nV;cwtuY!s3Z(*~td$ zgyfuGL=8Y+K*(iPfv@Q5J-@U358w8Et#Us-L}3tNL%L63oPyUs`%dby}P@*ztm_h?(3i3^d0}m-uJ!lfAr3Coa_33 zXZpWB_Oi<|&j6x|D58{5+j|NCiS@P}rjc4P6$tmA#1#OzVZ79AE~Xp06+O z>R|K3Yy%jCchTA1gU@w9tHX(0cEHaH^{I4a;r*_%{j*hNmKbE`@4ox0s;>X^{!cCW z`?tL3InS?H_3PKJ`}OP3o_X^8`0-e{^J=cLEVxJ)QC1NZnq2!iunY=)sb6*9jdqis z;jc-d{GF|QSJn6T^Xp-Ke!aC7ht0-p{Hh{;D8LMGwaxWLnEcpyTm$PKp*7c{0r`d= zXZ~B`N-W*`TeI6noLaT&z1wjMSmxDX##v`mQwc^$7{%)?@QVyE#)W_b7IjrsRd1>Y zFk(?f6j9AJl>{i563Z;I%T<|^^M5Bf&U5lz-QWLJiwMJvWA(59n-F4LV;}L9ORw&K z)&2O;hHQop&2ZpjLUcnP13?IgtbzGhLFkTrMMye;C~LH|H7*7GALIN-@!WHq=RadP z0p~fx{VM-ANb@?@b@)~NV;J$Bnaz1sRaIJ4ZE<4!xiP!N1o{k5P}QLsQM!grB6f&- ze|EVyzv3R%3J1xkSnBf2w~~0Ci=*dgcz+777`jOcDJi@ULoZ~K%a3}-x`J# zE@!I-Bv|tZsUFb$n7i+4$kzsx|ByE)`l)mWu|x(e+0PSYTYoj`NZr;9DlRJXvLi89CWymQh6%QD&yb%x2-LqKYV@jyRi+Hrp+< z(@eC}3?kA9sKWD@FpNOJz|=r&?-E4uSP&I)pWrNHZJ1nB^Tm%=LR3;&nt5i9fzuEW6#c6slgPuH@q4!CY#D8KqQh$B~Z6o#4K2;Q}(2Yc}xc}R^6}Il@*B+BuI#&iYVN` znrWt-D3a7sMHE1|!2MAb6jE&Dl1U^B5U2wRlz>DN8p5(7q5UrTTl-gdV1N@A0OSd? zYHb`>h1sy`G71FxA%^y9i#kS?1OW)bkI35Renz*T0V|ou^(LDHJJFyiHHk1mo}SlB zWU%_Fcp`Ri6NmstFqeE`@Q?*OTK=?%2l|5yHU*OwYG=WID}a#{%nBe#RRjbRjvZm! z1VDiTB>@m1K#0@ei8^T7X7#Rc)`e`xInI3m6xLEjAY;r1W|)^+5FkVgBF2Dlf|h;N z&EAu5z6yPg!RS1B<73+O8re;S=WS({SYeZ$mRV&KQAHMC*=*-+$jd6KiYlwFx}&Z* z%Z)VCjkej^Wt5d|B^V+I4h)A%U^sA|CdgXeONh)(Wba9o_z?R>?*%;O&ElVaS@?$~t|g0?1IP2Xm$xI@sd;f+RH4m z(=g9bMHEp)7CgliNi!y{q(KCdIj$$xYi#M=KX3#U4ca(m7hFNZU)UrXvxKUuDreM) zB$6o^{d#Nh8P-`Feiy!ijo>en+!#^9j{MkP&VdBFCd1f+CHcE2i^snVr^&w>l0 z9P7SUNOGaHN(iEzFa{~d6OB;kTSZf)^YhGDol@jLLl#f%ZnFb^pNAm%`K*Zx(L|&g z1_63hCNPWvo@>{m(;Bc?$)K9)GnJ+@*kyJ;R@~G6OtQlRt4JWzO*D!qqKj3rICGuJ zODwX>EV9cw>#8{0O*GR@Jlk!Zrddg*(hR{0J`+KFm}Q0V^}yjnDa0~^G!Tjo6Acl9 zK~j8Ab%*%X$!>Rp_Y0JErF*R=aqS5f&i>`9eWyAhI{9r~DdaRHI76{IOT1vlv6eov zvkzuFpO~U{#FMpciqly|aSPo03DsVkrvizcUj^ab0@ZhpKMZ6M!+nx-eTvj-);j2s z5seAO5J^Q3TPi{bF#(vw6*6k-B_O92Q7Ip*+z0x+yUt@2BlEF;5BYyj-^pgxon2f$tK%z^NM1;N zaQ{zr1jB6y7&}AUnMjdCA|{hC6+hy3h;7|g~wAb!ciA{!Ck z)Cm0luKc@PZIm zF+208PRd_K+f^Xc~rl8Q1|U0eI^jbAq&BTucUjcd6D1v;+4h4SmQ0 zA_PPNL{;DUzK9!vgMTJ$RIRWOh@dfm&Gy;`8#Dzrd-KbMt@KrM9~f*fy6hc}tg@OY zqKh)7HgmT9WtLS%6;;O^aaP%7mfA(5w9%MZcA7LFb`3!C39LBFJ5iBq#{UU_3$JF-xU;5Q=M7`wO|4%rhYn-Az2jgD1>Pm)d;Af zh&8$Jl8T9)H$i@F*v_y4UR8D1h}DXUD5M2bTmryi4=SpvPhCXQO+Jw(UN&wq3_yOd zfdT4s>AX^T1I(*f35d`Vxgdm4c!0zZ5VE|3`3;kIRwNSn1PG+R+L|dGhUkjU^}mS) zcZ@5bh569}Hd1^Yo5CQ|!WTEVck7l2rG-<~RUQe*FMK4fx=L_kj@*fI-s$ zYS1EaH;J*++gBVv4?`PW4x0?m5fCv>P!?M_QfGj{*&pa?_Nh95ZG0SmafiS_oho1S zU){q-*gS8lkEX@mvmr1PB7}l6`JG-JcA7 zK1?6i_j^8MeB@D`_i_q>izs* zHnx@h>kLza*x5dXt2!bg4ZILJeZL|B=|f=jQu+kduFW(iAqvKTND!rxK-5&pE*%ZJ z+%pP{_LPdEB1Wuucn$zB+nPIix_E=r+=*XEJLH<+<@3`!HIpR&wk}N+r z=0o{{rV3b;vB7);;A#VH&>mgr;fQWa-eDjLX{5AAJ&c09rQ8&UM|u)a!J6v2QL~Si zu*xSv2p`4@WuXV3d|g=r0VOM_0DetO1TN}! zP{3U2>b~-D%^H}93@$f0_e_~Yn4O|<{L9nuy;H zOMcds`ts2P791fxj^9#bNp9f@0ECvjij)Uh-xO79pvAcYm@OnI7(WoFiT~SDN3_=@ z&@{?nYX0Ep8U~j>Slx6Cgc6_tIT4pS2m%zr?-*}{m?9FzQ}1vb8XCL+PU@H3FXifB=q92`_+wOX}4K3pEUw z6_KGfA*RiQeFu?6RD}i1U?|;vDw1wT07thwFd+@EahvuA2c;-M$uOk;{Cv+{C2R}1 zV6eh-pDg|u<}*rx0NIQJaEBy1!4mx4ihu`$YFsTgI5pHp>aKengr=W^K!PEj2q62Q zi!MwD&N2I9Q<_oH|OL0`}vcp?r;E{Hd| zA_UN=*)hfkmV{P=!+1^_V2Fr88m|3-nkHLdA1Dh(6BPcg;G1L=wESofgJ2CUoC!uP zz{6;|Q_N-p!YAkQF$-XtfY}umBUCsy5a<~K!7?$8tYip|!b9*!nj_i3Ca}%F&G2T2 z^7_?ST~kd|es?VkRoJpXy0jJoAOQuih?@C8Jp8NPNR3fsfUJ;?AE_8W`Kmqu!aj$M z)Z+7aivhAzA|eDu$@q>VCI``qDm3MxB*5A>&K>721g<(ivGn~@%RpNm9_OFveEnc!fUx;zVCLR$Ii!>&p|2Nw2Fn#5_p>a z3Jo>Wiv7SU7mT@^66NESbIR5)d$EXZ7-jZvP9axQ?~%s;)Zghi6xN1;zHH*wL4SnO zw=^k}<$%>R!l=RV@$f2sxXBV%%xzzR=uMo7@<#xG%DPs=!KeVPgTKO8#L9 zkK?*(-7bGTyMILtfDdP#mHGuw@?Y-~B!--}F$sbLfJ_3_Tp7~0sq0aMy05aM5KE45 zrMjs_ffi^Q1V((qPg7Ab>H}l=P+d>+`w{kc?Q}#mOO$a%eMrViNAv4TDnuMz3ib=Z zfb!h8#bDZGze|)D#0g_bFd^!3$Pi83%g(qdl&a{GPIh1rU;(H{KoHVkLdk$3^k75e zj0kkDa6?&v4LptrTwv;)M(lHlqWQU8faUrb*GzellX%IFyl!Hhu`c-g-9nL|fm%1H zxQ}+kP$zyOoeVJmFh9%aBG+|y2>x3fA;Ya_btJ*s1CE^1vgdSsKct$jF&SxBoVuyA z&tO8O_1dY@)eG0$>rvutYe*E&YiNOqroGk$OO#pa6hra?D zjw8pO%!HiYDXm<~d2I$DLC!+#1LEPvtvavAOqD3AeY_I;bcLC3keOOC0V4|aw8OOc zL8C5Rt4vYa&ifwarUf_AN0wzt`mBGzL_`npt?3&r^F{d1|Aciq%7X?^IbRWI=5N>- zWn#0#KsO!1QxvThIyq2q13;P@twl21pYUSIx-@;$`?Cit?+C&B$`0@FbDt#$+33nSx%rw z7{L(`IG7#;&8+Y6rXvJE_aEu!D`>kIOVxg?;(nzY@wmdhR!`CdCjlr%#RIhSsN`=b z9+`mrFfYH9H_1p6oisp4Fvi=~za6A*w#aA7&QIik9B>W*AOzkLk8A=l5K`9S#2N+| z24wDq^=&(18~{WJkQv4%5Cajta!S6N6X82~p-8Ot)k<7ug%k zG1A%hBF8*YixplZR{5koj+-Q!WN@9+hE8#e!U?|VD7_3PKpsi_McQnTXn+Ucs^kGq z47jlIV*(ggKB?@WtYDz^x@2P&_{*>8&$XgrbQ(ayC{s*SP4bn5aA^G)66x_EZTjr| zYQWdKpANF+7^VB+IJD^DqZkmV@*IDs#5xS~66>all^GB9d4~{*!vV^_4S0s+%b|r| z*Q4#wtd7%EA$ll|6f4O_+~PG;$i!O@N0C`hQcb&pBtQZH7J-OkFhGtDHQ0@FcgzD% zuN#(FmOkX6ifbQ|8jZM5caeY*c7Jl^OV`qyeK6i@pFS(oxt;DFd{Rb}X1JumzZVYZ zmeUf!-;aPRw%JmtsK*kgTpKXrgSqe*a_hjw>h)-r$RK>I?)UWiUT{DlH@rIct1uPR zTFe8^9KUe+ZiFwh)fiR-#f!-aW&>mh!gxelImDJT%@RWiloJ(Brv(&Q2@OC6tr&?x zG4T^Y6Ocr}0Ck&=JdR=a$-seojJ>SJ_U~t*1XCk|F>YiW0|Wtt1wn?A)}#SS%4&c= zQ*~c~yJU;o?;jISvD{@piUB#wiJ(u5|8$0nu~E>d0$rEdM~zIOD?L;u?D`P?Sog+d z`528sZeA6J{kIeFtfuIo)IKr@FE}3D9OE!Vjw}CNuG8pm>z1~!$5-d>n{W`PEvtif z&NBiMilC_GX5#;Ud61RBJ{Po+nfFxkKMDa91`G&AL}?vC3E{B=^^PnsMN9BLc-BRO z6XgdnI!0fY2Nxi(8{pI@M-{3-Oz}T{5s%M3i4d--B0v^8*FXxq&IB9);4Oz;IP9aL z$pFC0{w@azGq92*9S&>pf^Nu2!PFCK78Et z|D}oHzj2iC-(}`CZ;Yu?7Wa-_N6j3CZ5J@%HfqzA}}Qn}F~4i%`K zk_%9thJ}afy8a`*@o{fe_wBi>A-mzu|JkkUPMI}=8WgK}sZfjUkcpspt8A)lE9Mt} zq3;Y}`vUg!Z+GW!>-(+!^2PNXHg?lItuMnkWvn-tv^=LBDM&E)f8e!<0V&rY1YsoM zi*LoOKGbuGDodNp2mppEX^Q3LRYCAzHJ`!~tVReBby@}! zOc)~``y9Q`-|&CetNRc0kFFTK9%1@OA|fB^VbRs=`Fn@hFq&sbGuM**IB40KuEe(4bWUjcl4#J0A_Vwf%{m|6nj!%ZqHmBTj6hnrmGe(Sjif|ei-;&9 zd6Etac(@7Jqfm?~aFRhd@$ENQ#!PGv2tdT(FeBJF+=$^K;uU#DRy(KM&<S1l; z#RWL$G$yy+;S&&H@W-}`Uen9%ou%ScFK z3Ahn3m=G_)Yv6JQU-}g0^q?jRxMz?Tj5cIAZz+*MBYeg=3O-=D0dVhn5u{gaJ4f!U z|1sDpcHn#w3!1gUUNIFqWA9=jAYA2VmI2faV0ZrBoaQKyIW;VDpCbK}g8R%U_sJ8m zA<8g-Vk1yEEDyD6vk5TZJryHu_(}>g5<5O(+tHQRbeM~|g3YLd2rne}XdEX1^iK5+ zP(jB@Vkj0zQ2d$z4R~k-Ap>aI5XU|XBETu80r>6+h=R7Hy-;#=bul^!z=4HpNDZD) zdX;cF>1UdLMISj3hGP&bH!83n5C}~<6)BixCfG(%=y6LCtU%L2e@^Fp1_*!(a0WMn z45$Eb0Mqq|T5b5@iBRYw1OO=1CcO3teW@9L_tdCNUkEc&0jl#tjM)5~BGO<9Q7FKO z5CEe{p+Xdos6>&0EC_)D1Wg~Apvy>r19~7iL*wuH9ir%Hphk_vm|4fpakk)MX$Z zHD8G%_5X6~l4A)xAZu1r=xAOuK~V_|K3pC1QV+p`e^NU*l2duP8|G^wm*kQBVFblv zMDY?X#0FyshE!J1{S3oaD^+vRTl0+RWtS*f=FCi(f@{D}{M)Q{(sIwWB^AUzCqxiP z7L$XF2KNBQ5QvaCFplBh0=6U77ljwYJ?KM7y1avtR8f8l{j0YO$56k%eO#%D9=d=EW z`wF73fcfW_`sd`yJ$@nVh!WQvCV&%C_w9+jl!Q$(|8-ul;pv1{j4UtO5ex6Nikeb= zOtbv^{|05}Rw^J#FwYf|AP9)55dcI*`Akb5Z%&!ed}$*k-R20 z@nCn6F6|p|t#!39Bc81xPW!zK0Y^2}7I7W=!c!4t%g7W9gHx{$28oxGb-@pY5x@~@ zclc=AqP5Wy+)BKvG)#>yBqRmQ1+~IRYh)AlV_P@bx%OTl3fhHiGP2BTSK$>io~1%i>Zo%P>p< zL@I88ZQLIK&F2Gv7<`^vWPz|*4?%8VT20KtHlPN;QkrW6tf5sY@unI~mhWp|Y~!p;B)pP&0YYMZsGg5(W^dev^4PN{Sc z1V5RAXfPrqOa+7M_$y*miXJ%4j-Hru8+@QT_0B|Hg2VI)jGTS0H5zj%%>Yxb3+p;) z8$MTV$RI-Th!GM5K!J!_rh%kNN?>9kC{VA3J|3VB2pztCZLd+ zL?RU!g@{!OL|RoLW`F{e0+eC}C5AnphhJ|AsUJx3JIbL28f6f zYrkDiLB#p#;~fR&>oZwh$d z3Vuxs4f-sXb4xJVZzlSLaY)plg6;wux}O=T7)1sM5viM^0DXD6Bq6nKS&Wc4QS2xI{dx$kdOgV651@+p!eRcDWy*tl^G|%*z1n>t>6x0E;Bl+K5f#h0(pqP75h_+q%v_qkZ%<=^QZl>~qHnQ;cZ|l15 zZ>J#01uiYQ#ji135x$z!XFcU>3X&_m^$2a2JRoZ zC8SaNeyPs60R>m!x-BAlR=p&IIQ;2q;T1b>t=1Ub*yG^ZuId>qBy~31hb!n>%uQ(KD-Kg0TBWsC*N4;3l|~`wx&Iv#TVtCe|<4GLX7>be@8^tE?2`R)PbHh z^#q%JxwjmEpbkQjfz1?CM+AN`Uv{t_VhEs#yT?pPP!x!7y;j8tB|2wlKs{|s-JnN> zqg(*VqAyb%Putc%Cm$N;&}KyQA?B;^g-8POsY6J|XM_eyWc%=yvy7wkbDcdsFn?5n zt~l_CwLZal0Kp=upcsd(eDh$7@8YQY+hc3_wR~Opr&rOPOO>Ivd>!q|qqI$3E{8B+o?K39Y)mGn^F zeBf6$IPgN&=E~0#-5Ik1s$)Xu4zZ|Dz)C%8In|Z-1{jyme7sfKhoD)hZ(7!_2hv7M-a5`HJ6dcGgMh52f!g>c&eapw6Yw z_^(VT&kwMmTj%{M+L-9<%OB&tPwG^tWugSZ z+2A{`d{%zRC()9yjBFZFmcd`7mbg( z5f7hPZC977gwLRXbQFnWlUFJdhVryQW@=KcC| z3!G~Cm!sV^+wT zd1#AQ7an+jzD9sQ3@e&Ducf%09Xbp{Vmv-u&t;*Zf7oLjcF2xn5rp^J-#W_^ z7L;p5;q>+yKOFv+u9!_f1_DQh(w~~fCzH`)wA5M)`U-1>movfMy8g2&yx+&sePKsD zsR`zXA%WFN(fZP>FAmFAsJ<^xeKB3x{d77T{<*Ni^=t0V6v76L*yq-8FPmhQ@qzhn z?~Ic%kRJ9om^@)NG}I<%TN>mBN|#)v`^GI(yN%e`Dh9jpSb%wXI_guIv#%|7EWp)) zC0(H!07i+gMwcTC5Pq0h?l&K7odQL9`+QWw-MoO60=<7yfe62P<_#w5TRB^;XqV&SOLoHkKbH*syj^lKU89JpzkV)LPbbx zzCo<=qK|9=_)1W%tDr^{rUBHxiX2vyoVl7GO{JfXr?Kg!FP>X5>HXvBzJ;Fj6;UR% zOS$>6{+>HwVEEUd1}&(^)Yco@-*>tR(lfSIw{}#1i*gw+eV-ob%SpvYtg!FY3**)9%7^V`ZHbdJYu20V(_K~CxNPX-vZag%QwCh&h?J_bp0s=UpARG z(Mw+F?EXz7OwZYf)Ar9~qCcqrp|01qUY* zuBQlB_-cMKOJXPEcRo2^pF;NI?=4E0#f;=Ym+73J~qAWEx!gWS)rXr}(?Ll%)LhY?&5h1Te=g{2o%Xhu6#Tt1)T&PwxF_$b_n;KEI?bX`lCua~&>)@I#RE zid~SEq4zXd`=O1|Y{m7+WWPLl^CU~*@k$&C_k2Krv?V_Yi8<;)#X{t3mv+~OJvmTl zy9ziQu&yUn^UWFT!rPs_`k@GBE-g`nvK9E!n^))c@QpEDIZp2$^CS< zy0kYo`kUj8stwfPy{+y~515x(c^%aoD5dk3C3R;nJ|@kDv|9kIM-;qdqiO#036*R9kkeZs2p8)D+ zgN)X9f)cU3-y7lR>W5ss=&2Q$199W)OHv7n@Soe2TB)j3G<^+Deu&T?B#&Vm?k~iT zqeNQ-Q2xk1=3E!LVeis7`>vq@nLE5~;mbnigzd_q#$PlXjYvr7i*0q*lxAWT zCaup&o|&Z!i;NpZ;#wxu{-@z(<9*vi_imGmDiR`3xtv^E61kM{AJwxT1k)supu{T z5qdBn1+_%92#BA?IRRflvr$qqxpuK(6RN)o0S1wj_ly=fc`Es#hDD=7eLkl_LQ%p- z?LC1;nxPOZfw=u4=E*rvxrh8csBJc@OuI)@TS!TAeNM+jz$xtvX(WM&B$5e#K0$I^ z7^kFxi1B`k0QTqQ9}P1j0Jk=+_QijESjb@7C#LN{g?)zNtmp(_%z$$VKoLN2PU&N0 ztF;=k)XeZ$pglFUf2A#Gz#C2Ug)u;K%khJ zD2f4Qts&U18fd6w9IK`)Stf4(zc)VJs2!Q_naXpWC_Csf+ z6kqQs1^M;J0Q*1eKfs|PB_?HN9iLzx59%7xqyNtF9%h9&huYswa~ivA{iptu7nfTf z>CiEMuYdjALw%fI|MC&Z@g`Bp;&`Kz#OX#TDLXuUxcp{=fI~9>f%Fvx^RkM;5g zQHRoh=Ph@g{~tde{{8-E9~k&`f{Fo%XY{lvh`d4Ff%!o4<_n|pAUqt74=|!WgFWO< zQmzjpnd=lpU$kN62U|D~qwxLh9lkTN0Z{Kw_Eq#so<48rDZ5Y2=JfXWpJO@r&(Gh6 zX3rOU+sN|f7^uHKe~tm`Jc$`Cp1lY|FVh}6k{|(jq#QEw~d`(e)%c}|}I+hcKR2|vxTj|8AKFaSN)Y12K z-`4ELA9C}c9zNPMMYvIg%Vh}-BSHMFQf^xnD7b}JW~hJMHJriwvtElWiHO_&VTH;N zw}bC=;Za*_$_q%-a8L6yw6YveU}$D`f*jU49B~|Lxg6LGR-iw`Zz-Ce@A!Y?(~dfR zQ;-UWtNC?)bJ{)rN3H_B$v#j;(ZQQfGC!hZc`*s$Lr(iW0jk%MF0L;*EC{6+}4ub>CGxP+JEaX5D5dcJpF#9}MjUqncSzeAfCfiR?9=qYB zrYGV&N%y`bHkCi8I@JIH3XSasl}JaYs20kTx?;&H{eYk`LOzsc$a~@Iuw!=m%j^|d z<5aQhTlQ4|O?}j?;WRFF(vnmYhK#ZU0h4}mAaGz+%oa5R05<>=I1ZYTq5GLp{FJDR zwPZ`3nk%+V^LLdo2AAAbb6AEy`dV85>^vutM=^z^&Gj}~;B7e^w~l|vK1z>rp1m1b zhzs9AEFw4Om;4hDnH>yB`TwkP-L9Uk?%9hsWPHE(nb2Sp@@$_Iq~S76lf=<4&K5#~ zK@o@m05xI&1B%#sntExbRaZFxbCk+vP8`S5P$QI}x{DB1QXmpB0wbUv`TyzDnFsXh z*RS{e&ePB+fiBPlf9v_3J(00#jx)XdV0_|>#)}TEU$4CVCBVz~^Z(Lf6NM0*CW;|8 zQ3@?zl$3f=Htyu(?rQGOOnK?FiMm#>!24?02vlKR`{}(->D5FhgM@1k|8V@h>Sm4 zd_M03kcIvJAIZn&>N~yIJGju46|w0=0e+^3*}>4URtE;Mt`QpBKwW3x$cEM+PpRca%2QTa{!}^r zV*Hk&g6c|qJ5VqF1>)cT3!8G_igq95S0@S|{Vr4x4J>(^3*^&Ch!7w|n37ln5Db)S zz{POD3@!#763q7fu}Z2mm=uk#eLwyU1Y8}U5fC5&9ill91VmEJPBl#8IBzSVHXY?>y? zvTT+o6;+}q2!mkcL(4(GdzII-l~%+=Y@s`LzMIRJ&x1`6Ib8H!*Cf57}ff z=ks9E&|zt9LYYvSYf_T@vcIZGR%P^9x?*`u>24Ya$ufzo$xjuGZS zn&FX{P*`x`LFwgbClIt4HW=`1r66NkjTf+=wS5ckKR5OMpZ<7^G{u_UcCtm=79Hg`%(C?xTal571QNR3FST}26^h&NQf@r{)PUL+a61mG2iV~6K^Zn;pu`E-OqUR(Odt&q5MX}%GWpa2fy5Z=3!-eCI1LP z#zI+$k&y$4%V!)KD9R3M7?F}CQ@UUFJ(JF`*Ma=;#Ww_c@vc7+?0uv3kgOk8jWQ<9 z-{-!s>Hd-->JxuYbihM{O9dVY{Ab$>>2O2{08~r@zGtekvUc_rN2Gw1v6_3$IN_xg-ac3&4Rnm+fH*O5Pfq6U9XuDr7u$Nr8!*?x}0 zIcKsMXy$wedG-wl2h;q-{o3jytnUjca=8#QGZG?f7=XxbUtJ>N*ql;fha!ZE3}F-r z)*Kt~`5iRmA~5E)S=NB|5^Ad%c4mv}CZ{Zusg8Xz#O^B8h7wUauEgoE+`1`xji z9`DHfgpu`p@2CFzdp-X@{2DfAX$X3c>|sUzPIL$Z1i>JV4i1rl`%5AK5CEf)vZ7&9 z7zhFrAB_2rwopOP@E^!fPxXl;f82pi57+(QB?pH>kPZfeVX$D~1wc4BtqchDz-7Sb zL=Ygs2$+FIij06n2mnWdY;XZl=nsFCMPs&r3!c%B#=v|C0!qK1{no(_^t`A6>~&oFn&II34GyW&vVCF!-wo)ygL!9 z6I1?~HQv^)*d2gpYl`0rnSj9>0qUx~2sOwr3{>=}aR z{6G2?w*>7O0T3XAgZOLzr2S1-TvJeAr;VYe`RDJTsc8;@Ck2#AOg6X-gIU2-jIlxW)CF+uaE zwMMPQeg;?c;6@Ec71yAW>&8nmT!tjI`G?LMn4;RHE)2n=kN%K`od7dDhqE6GqAvuj zOgx$O*&+ZC0Gj}SAIt?lZx(?7&>$Yr{g3E+e}^7N|8?BE_*4NAh7%DN8;YTlYq^L3 z1o(-82oS`ZgD0KtvwM>O2>~E*1v6K0MgQbZfxqwo1OWk08OShcAN|&NC+?6HI^*^T zgv@dp11xO&QI0@GAdUD4fJN*KTG<~qEIaWrYBq8YA$*>lpAb3ol>u_N9#8@n-e3LB zREW`XHb-GOH~w;aBh|UNMV0@jo9dV#Ug*3r#HqVr1MR`$8?`9BbeO2QL8!tG*K4$^ z=5xw>*d(Msj^5w(SM%eU_?=Yyy~ieMx=+yW+RiN+(0nG?EC%=Y44`>0xKjWGK!Fot zXS%XQf(t{`Zaf5aoCGeI0B)OXj7r|qbwEPk>WEO|z;>ortPmSQqLR7;|Na66q0q@o zf@}Y+&=cU)FjP@cM)-i?h(#c8NFOTkWFko2qAVDTJRnGDIDJae4LV69*CD5Cj?H9yp=j4E)Com#|?t7&r&Uc>10Kv9XK_pgKvL z2!Rcv4}8EcrZBwFl}<#89@3Wq?AU+%&;K^rHcgXc*(5=s{y2rS*u(kcTcD5tfdEdS z3V-@Ozs~UXzpty@{y%Tc&+hN?(&jnzdIK*p#-12nOdE&e|6h4#__x+KuY@Uh|eyyF1lww!#h1BTXx;Mrul&XKV>>c#I4hr2Y zgM5h5WLB@g9pL5)WeedAD;CPxd$gbY%yt2*jGGaIHUy^M%hNQ6YV{$Wg;98Z%h^gH zJum{3(5R!OpC3GR92YW=I?5Mpt zDGON;XMfqlFXPXYiFhKiH5z&`D+os*8$*&po9VxZ{%ed}j5&|mgZ6yrRj>^7ub=_n z3Wo$hgj^Irg%K7Q{)gi`kAv0t_ygVU{2!aq?_GV1?u4XDp2_un(CzY^&O@R(!OO#| z-Gk-|+zDuDT>_AOr{1`F^c^U+eKcf0xPqyHN+AqIqNmf8*)$ z=oAEzB3ACIC2K*BkY zA!-G2;7YXuA(TMD2u+}5VE;)IVI}wd(%a|~3^N*Z-~9L~{t=Y}(^bEGYx$E1IAWrg z2jH9E5K)xdsM|~Fmm>-s8Lr`n$C$eY%%jN(A z0Em`!%;DF1oO+1!AN+a^N{EZWu;hFGj==SNKms}g(be?- zw_x~tAa_E+DwMiS2bcW${vPe;JIB!OJ|FGuoM=b?WkdO%3NbMt;3I-m_o_z=2*JSE zvk(a&32l^MP1{U1V2yy-7v5PQ4->Hva5_K$^Lz9fX%Qs50F@UJ-aic6iVyyQ$s$|e zSbnx2b)gMo0s?6-vOWc@;u!d7!qQO_7aE@G_8`mHHnekSf^vrF$KhO8Uu-E;7c7&gc(cjUw z#P65=Ey9O&hoUB(6TW_ImTX?VB!GZmA`PRh#zibqg<A~|JRFW7}LXa3;`4DTQF z<0FI!0ZDOhHjlU5R=*(5rK=(!B zpZ%MxHXjelmj2@KX8mS9@y0Z)a55MKjS@3EeTyqto|+VkGAe43ar+~i6Q5M=3|v7o zBq%jfKC3zsRXYCPiV<4?zH{t-25)1PW$mC7hz^Ovv!M@DkrL6U*$K>SXg`1$>bIbtE4%gm29Z`ceRkN9EU&+-5c97^(SsA1QqE0t~49I%)!Dk z)&D;I*Vv10FKZC&>f@@ z03ZU(3B9e1ErWJZKokcDjx^0VApZFszP?WSf7L4jB$_$YtH-0R~6&s{0A|Jduf$efuf3* zIM(~CbU2r5L5~65W{G2cJM(O}R7|Zs40QX??{4ssG~r;1$aSgmvea|US<34To0sx4)jjxPudZ7B9%y!q> z$*=M-4+cRlv+)2AmqjS7mN@B$3CcmVeu{%6j2j&)a5Z6^SG) zU1Yv@%lJ1h#t${?3`kM+Td6irs-kG8!96}Lqj}?Xo&JRVlH14qpiWNeqv+^p#^M?N zZ*Hf6GY>0cnUV%itV5s?3A&S6SM2#sAA!HYu!H`s{3F8!i+NKx`>%63=mPs@{Mk~( zLky{rLo#Lt8fB~)z2}oFB^=`yXJNl+M*(R6h&w9x-Z0IkxXh;fA{$i+LZObN{dyPeGT>EZFG?`j5IrPPvW{(4*lc3-5I&(Y$}z=?_+?=F;%xi(ae*q;3f}Wl z%|>st&xSh25xxlE3@8d4@6GXE>U<^6qUo!8dl)#9{SyivkCAqUBOC12!T^X5xBK{N z{gac1?JE+bp(aTc71a>HU=RV22!R-~kRS#&{*wuj1pon0rGv8T6Ec)cDhy$*)KMX9 z!SY}j%m#uX0AgF5hZGo5t1hu$Ip3%^>E4MY%4R<7@Q)fVSj-v0P96Hoqxv5a`*0X?V>CWDO> zJbYWy^MmMr>)HKB&u{{E2VscUQvrmUXE4GEocw<#zW@zm^Q(un)^(r?6H)X*fG9*VJ z5HS^#05NI0{HnICH)~m6do}7Dm$!KUM=-L*6a^gb|38ud$BeJK*K;!rCKb`lC*ZMtL|Ig|lL}-AIWWmm?2@vOencws8`*^ga?+n778l1{- z*k1xuG1KPwYfA}+oD$v<1u^zIb-@8f%$;8BHMagU)|n#V!vpi1!);3)vF8!pgB9iC zkEy}??!tx1#8R4gAQpY)cLq&dSG#bLr`ew`Y0-j`9~A=IqOcG#(5Tkk$^Ux6HN3-` zaO4NxS)WSI$fC#5!Evam07Xc^5Rv`>*6l9O`U+@Aw1?ab9O(zjzgKB~V)v$NtjZ{t z`}}I8Iezpsr2mhdAD48w^%Kv`r%nF~O+;M0oN)w6PqKPEFDKorf%18)*{}~{5S!U$ z_ae;M3J<%%rW1b;h^*BJs|tQTSA1h6`2p}LWl81bKxO+W?O|BIUIPb%Pn5PJ_1cYV&E?tcGIVb%fl29pSt4x&CY-qNqE%$&%p z0#qOfW5h`5ln;x`NWYd>H-yRMG?DzsLqCD*$Aq?tqCeC@zXLv1J4cTQtsa7zi8_PG zd%xq_^!tafc6NtWV)}w7v(e!BKK#2S_{iCQpZoOqAPD;YQ;{7)h!1zP7jLk7L#V<- z^&TM$_-EVgJxS>0-`CH?lRp2KTIh89K7EPwO6x^uFDddSXu$mb2b%EYInS70Ue7`2 z1IQwez;KrR_ z)z9*m>9l#L38&W9H@Z}nB$y6Q&V9e{nIA9xgaNkM5GAYVApT`+HLsQ^L!q3__j$@O1PlP@Aa_TT`JY{m6rg z;O{?e#X3Fd_-*wF9{=h>Z;mqC&M)hU|4*$@Z@n@HwWg>dEwgYtp~kDS(`A}In{vJ} zRrufgZ3P6iv0iNA2^}%x-L6^};Ky7)`kR(a5ZgrnyX2YbQwpcF6{5XXRu$9aYBnzT z009F6E!QnJRqT*y2*9(jAm0jqszK2M=doO-o zN=L8P;ryJuLIVSDQVy%|t`tR24%JPN!qq!F;jIwlw9^hGXO_!{+#xgT5QRZowH&cS z3^U-dc6aVR-hYMtqWw!t44-P8eSE;%-5jr4HulWt=ku6mS+)p>0{Ub`M3qE+Vkp9b zDgFLm<^O)K^XvJ4Prt!1wMZHBqDcty(8+aS7e?7=Uo}Cv`37SAp)CNcu!vX;f zBg0Iba7kcffx?qjH`_5Yy8sg(}=ECjpYo_jzL^p=x#IeaCoSwd$HS4Euyhk^QX# zovFN>)A6!3s8`zuCYnF-n-2^zvoS88_J}IhWGoUsG(7)wvk$I<(Rg&#xoVbffO7)} zh5#{4brK*Degm}zgXJI6WLQU`nm9tg{hUa2J-R*USI|SA^;}UukKg?~xqiQU^ylgP zA1B=SP#(W98(|cg378(35C8%&01zMw_*F}kL7ssI7r&eTH)6YI3T#*zWB^|#D2f4+ zvN9#k{AVXZVtBxDxqlOx-4UdMA|VhF zF}IpXg2fj?iwon?`PBaYi1`}d?0I?3u&(G6-FWbz916;X6sc5>rsJ1##t3HCfbSJ) zXp5t;1{s0@VXYK-LTG_Ox{*}@(O@5X0=htm5CO2-BUpzNCYUh*0i6QyBOHXv$^e6+ zCuN8b4+%#d)Fegi(vKJrm%M(3L^t73M7TJZ5nKZxL`fJBD5?TTd`^V9r*=YvpBEYC z^LWg1NRC7iBM}`b6QK!7gBM5xL+l6fKQ;EYr?cknKR>d2C&9j70rNtiR*s;J9BPuL zsnHB3MHqkqM2Y*=2!a5StVBcziUoNMG81GPecfNb^XbN7Pl2RJ&&DugS8zLus&A1E zw(J+S00M&`K%{8^4lX4H4M;u`iPTD(2uF@tRI>l}!*5dvb+gpSGdm-=+s8Pz>E!sx z|ATK&gYv-M+4?aE%+&F0sJ)+c1P9LR&)2!G9N{|(yv zTQI3c`ic@*ro5=HM#-v(p5G}{l0Eo9Dc+EiS+mHNr%6NcASUXBmacbwwQnu2ocarKnV^cKoJpQesUlPh@qhR z!0?;;D>=8J_rMTW%pa_U{WC(-&%}DNjR$660pWwBkOv|rOKcATU`hoj?!Ng|CaDFs z*CdHzT$3b-dtR#f>?FI47|bx3J39~#{5ako-p!x_YH{CBqJU8nPXZ}`OuloCQp4ha z04I!JCOQ$!3=DH*W*PlYxOu$%zSqyx8W8b#@Bvq_^@JotqzCe54I`ZrcF&y&}Vfe-ZE3Zh;G;lNvZ-49zA^3tO66B=Jb}7fz;BbfAwZ)OEtXv zGJMyEKI?a#nV}gkw$ZeVMm(9!lqEn9S&j-Vd#XVBA7LoDpLW~F`yZ%%B&x+X>5s8T zFYlOLH`#3ncP7^B2tuBB)U&GwAR(L>VbgU7%yLi;8e`P@2`!V$^`JdTa`pZe(CJO} zzs<0Q5!*b?b7X0)91!dD3ll<&zG7HJ&F9p$mSWiw;6lAK_Ee-W?lu=Xxta*uHsT#@ zl%FKYg<(K&-U6wD08^7~moo(;K>}bv!U!OQ@8|%mqF|#EX&^I=wt&@Hbpo-vq5NrR z&Ab6wD`R%vsO%2G^Yr0BKHxuB%lE$F%s+3)pMo7Kq9?BR(EsmJT%Z+0N><4aO9AFQ zA^#XA9j2?P7=8vw@{hGu4GtkOsd8mH_AjgQP`z~p{X_ym#qNLs2N%AX8B(%^Ch z1hhxM7Taw!kT>!)r*KC-^L~RO8AJT*;LLRIqHuoBVZuKNCX<+*eEqAuihuqWaz!{$ IkdBY@G`hOGi*anu4e+v0w=zDx#tSBBC*hy(F?oFoZlGKpP=- zY|`{hCwUlRewqjEV^Y({eLf|4<^+UX>frv%aTDjHy7<4lfKZ4J!cShMjZI2j(KKs(Z?|Z@hD}?N$KN~xB(ys@TULwZ97NH1!;^Z+& zEq!L(M9BLALS|8)C(TZmzu@OW``Pfm?(@l0Xa6`^`3NyLqzGxJPfGfH?6;Sy%MdeE zhfw#9>652TxA1*43Nc&ap}#}vQ^%%vmcZ~x2k&!f=~E}C_c(G*2kU|PGl_`ehN-Jl zHMsT~Z4vQL#sRv8znXvanPh^$-E98ZY^t;$+#4U#2k@TcbHNGb_z0eVZZ=iyi9Tul z|)Xogpr$1j-&3p)TY4#2(6!Jx z13X9Pz#>B52Y8U;2+AlZ zv9t}$D*?*)QiL7I8Cd5NBkm~fX&pSf0p&F9hlHR}P?A}Mr@{M&pcGR2z`Z-vuY~s# z;r)}6lW1jYNe0~Kh8bI+*Ao(noHh1Es~E%3*8=_o*T+C_P#W zr3L#v^eYE^0p9;rk=%uPparGF#|3C`4rs9s;C(1>MEtkXfnI-HMEX8KQIr-R7fK6} z))d0JMcV%r!rDb%_%~4GQJ^{Sr(EO_%C9h2k#GMOkn%Ha|8F7iI^`?LV1PMjwutXA z!*zfJ*895kz5!qf;33a=k501XF#c5FQIHX6cUP1X;8n`6R9={PXhUHbT0tQ}t@l*` z7ec?i5JTxm$Nnqi7o*EicY{6?~eevm;b2d!}NhkGiQARDmue+j9~ zQn~pn6nTcykMhoc0ja!;GDmrg%3Q15i?Rpu|1oTpZyop0uvyeSApZan%n@-#K&MvP zQyTMYKC}^e4CuTBa4>^?0eUeXaQ>ZPp-9sONGdrDI-*{b5jnRE=&}n{0N&+vJ|I`6 zTr=pgR$NM=(Kz7QnUc*QJC=aIjxdfEm5cJBMLhv$DU_#}65+KGKgiaEC;kWY74%cW zJE3T<7HGHL(9EX;Pn*^`7!`4YVa+>G8mxN?=!87DA1U5jfi8meQvM;Ypd3V6W+b|x zNJJOpDd>VM0%-g-$ag<@_66vTY3PCk>iHzVQLC)9^5O#%FZ{PO0y#mZK1`768!GdE zl?xLeo5nCfSVs}8;~wSpKh3#SzNFMX0H1&0<<>cW7zgwc;62JT{s;IMIc{C!=~mca z8s7x}2cQ3yPh0uj#Mc~)3fQ)&H??V$2e?Oo)5AcUJkVW_0GeoL(nqcHF^%`{Amww) zU!)GL;;T_5`3`lYxRErYDYS5N3@tE*0(6=Twzv12$N6Tt0>*0?i;D z&DOz;6Isa|lW)lv-v6w58>r#sW4-VJx6) zsNQKU@a|2c4a3s_7XNV%_89CK*y+h)Y3&c{TxcPm(mv=lItMTx;7fr00hU2|#bg-_ z0DmQEF!#Y|4$}kAyK1n>{h^q~8w1Z^eAAdB{AkW}-tV)aJ@~gxzrb}GK=2-0 zeusC!@fGI`eYE(&T=>>?n${2fv@C-*&j6kUNY_o*WMzcSfUA}$U?2EvrhNoKfpO>@ zXn*wD&>rs7jitr6^?DW)j*4gjyq5u;3jtC-_?}yZRMdCj-Wi_p?+pJSJq*9_nTFT= zR>MPno8c~V1aVYesm`XhOuPm;p|V5eipmI;SE@VcGn21K^(cKt+fbj8-cz}xvP0|P z{Vw8j(5Li$TF>hc@3rIl(ugsT_x9NoE5M zpg&#>YlgM(Ltw2xqjuZ^G=RN}Qg{!jhq#Q}V(gE7jM}n&!KZ~WVD3jjhfJZmMI6uQ zpVhY7t4eA!MSO>#h0t~g*J?*aNNGfA&=+t{=>~0~&2oxsV=?4OYfz{Z?r9s5e$6nq z2gqI2m#s86(VY)P9mM{g1Kw!d0d2(sbcgn#bRH&t_&{@N(<#kqpC+1z!h7@3*HRu` zkOsp$2T-8I0_u$M$Yg0ZbRG13XVFikK4uB%*O#EX6H%b(^W6ssJiv8FCuw1Cpc9-E zYR}8yz7O0}n)HTiN_W5=+Zkv}eSslx4Y2_Sej8hf^7!{)XFZ@@5%T3-pzbJ?6rfKg zz^lfw#PPh54;`OAqdFXX3mTie5%qllYAI1f4>7>nxu@Bq4PBKnhFXqyPZ zui~$KR4;}5&2Zmv-t{?V0xcIevsI1o2h>hf(~kJlg*EX zHh>2{7HkPXQ9n`t1AH5>O{1X9CT?J>LdEOhKnpPsz-G3Kn~@}Z7C z1D+tALDr7Ly-vKRF{zk0`0!pY@S&())uIlp4($-%*@1e&7|3)Fb%(h1=#b=MYyULw zK>MZl{?Lx<8Y!B~+e2TFZy~c#B9jZY)Wkznr-3|)y6t1w%J(1QTAG8Qaq7Q;Cf@r` zklG*`XMOPNDX+u2MV|iv4L`%Z8tNHSJ=g;TGUF}U1&|$4o*|a~E2KOK?aBa(@p0?D zw-FldQyV~O^j9d#0L4F*g?|D6A{+lB-uM{$n)I6qex&#Q6g$In<2~RG=E=6^xw=prDaO?%e*51A z!H*Da;r~krd^H^SrU$_D0FVABdjGrU5>x#CAK+i<_91pR#qj?In(+T`A;MWkznMZ~ z3}=GOZjd3U!*ODcR?PEa$RVRTDF5P5%;`dIk-l&0Ln>a=T%@59bf7856CvvfzU{{a zp)hzaj4j7Ov@lCbXG{ivfaY~?wU#cB zPj#a2!+jUB6|INSEH3w@6)^# zw-nZx3=sO4Bq5dbpGYNN3D-lR4tz1mEYwA22K>+(Pf&YBbv?-RNpb+}h8^(I0;3Pi z&xiKEK>Ly453UjGI`f-QXDN$1)ArOir8bY^SoRjpp?y)vQGfO@Mv`PQ zgUlrh$SRUec9JV>7JG&LowMNLxY68lZWXU|-sb$f%Lx}j=dBy1o1$B*`&##n?uhPt zSLDjO%3Lj6)vlJVwyw^uZm!<0ey;6Z16@O0JG=ICUE;dc^@y9ZyPdnIyRXN1uWx+N zd;YzRp~YZ;Ss~arEBa_&B}}6@FGL2Cp(KGMlIh~SmcqQ&lHKGgyMn#SA+7^Aj7#EH z!n}}k5zMPahjanDblr4a5zOnb?k3EOz`V@Gd0D$Uy6RlLTz$oP1&i|<^9^XHW+3ah8cz$1{q=uQHEZIPYilPS3^5P8-tg@ z)u1!D7@Q4G21kQ~!Af`|ycYg0yb>lqo%eM1lW(8Qd@|$7=T8!z41dz+Nz{{GPrMq0 zhUSK*hPMs>YVC7 z{TYgxiV6HOBYj1T{U7!phTIipIr@jG>7(W2KX^!3j+aPfa)r{&+(M<+SZb}TZEWrA z9UPsUU39K)?jD|A-ac)7{o1x`?;p@1Feo@Av}32R@Xirkx^~ldkNl)Z&tAQw`t3hl6{IQ=qzmEisD$TO!eG=^rz&AQ`=pfU2gd8p z4|8qT_Aj?Ol|)y9VoJ>B=*kU-n0VHK8&<+OmJm;A3G3@Q^I+|zdng2x-n_GRjO6);j2_*!`q>9CR1;CFOViJ z`Q4Me3nahgk+GP zKypDKXP2qDvySA9HK`TIX@Q&)$Vq|J2;_u7ss(afAXNf6CXh-ssmSu=Dg;t~^cYtz zkfUWIxueI((M-1Nh$mMzQg0w-diIDXIV_NG^GK;cz7a@?K)x2pp%n6!IXU>HCwDM~ zd|9mFzVsx;8gc+8eV~c#7swX^*(Z>_8nQ`1(?FQ)(d1^&PZ3k?btfxVD7ckc zvO+xy@^a~B2$~llqQlckjVm>B#?=&DalBIj1b6hfeee6bHkcQyqpZRw&R8dk~o13 zfsuzqlEGGF5LR)6Y)Pz^4D4&k4HQU>f(#Hy^rtE=S|FdQNPmI!gD3q2(zlO_>uX8+ zIGJ&MR3yrb^cG03Jkm3d^bp7=OgrwACK7p!bni#>0_i4@u3a=-S1suhVZn9LkciG^ zT!h|WK{}g}aDjvgq*F&N*Qtqg3{`O*wInn|!G)?wh=K$=lOQt^*g?Ss3Z#RA1o$hs z05jsRAnn`9xb`a2PDa`W5}_L0O6ZtMhNn?h^=Q#JyzhL^1E zh?PLJ0#&n!y-3Xb;MOxoGiZw2;YQVxi_7cNyiwXEHp$j0^E~m|Z1af^MKK zgk_>oA-)0Yx`f`MC1fzO5Nv!9lM3@c2Yp?J_rb=ph`WL1NMQV+4rUKyC5!(%k#^h- z@$(8TgpmiMJ$yN@mAJzw6l44FY23(fL`CR2_<&Q$UA&BSXZN#FD94Bak_e}0Zs2_S z4xftWz}o32gZ9qMViR#O`iV`17$yUqp(}!s4>Pf_qEu7`Wfrf3HFd_z$V!+ged>fR zOZu|@@ILe)nGdT*aHc2(O@ONmbO@EAb|eqwKu_X&`Hm24=2b)Z5%U%{$Ngp!Yo=sZW2O!#=e>^*#-465C8{ zGrP^&Hv8IC`;PLx=zG)mk?%`C{sV^%df$&sjaqc+qUc4wQbj_ zU5|DN?Pj-I+U|V&g!Yr#XSQG0eqZ}j?H~Eq_}BU0@^A2e8z2qP2Iv9;1A26D?BLTO zxP!h!Oo!AC^Ewm|HDqeYf{?tB z@{s1xUZL@!6GG>Ot_>{;Ee)*>y%_qaBkHK>=+QB>V^qh%9TPj=>e$c;by9Y6?&RAk zqEl3-+0M|edxL_O-0)n{#=+CH!PcIunex32H4z774t`%UP#wqIqx`~8{zUHi}N zf4KjPPj#Orep>M9&1e*D9&H~T5#1v?CORQHEqZ!%W^{J+mgqgvCDAp}SEC!E-wj{~ zXa{%<2ptePAbP;?0jUF~4p=Z?)quPKg#(HQlnppF;L3nI1D?is#mtP!j@c5kC+2L- zwV3-cFJj&fWCofKbQ{=yVEDjZ0|yUG9Jpa%^}ve*Zw`Dk@a4d!SUy%0>m2JF8yXuK z8y!15HZ^u??1I=;v3aq(Vh_bu#-5G67JEPTMeN%_%pmhY_Jh0z1rF*usPCY-LCJ$A z4XPY09jqN3I(XFJk|FXT2}2eS*+1m)keVTNLv9Ue81iaJbDT6z8>fqF8`mkWM_f$Y z+_jW|4_VZ^%xWr8jtI3YPXaghLt;VV z{=}-pvx#pKg(PW`Cdo0$D=8o;JgG-gbkd5X4M_z_`;rbPol3fu^fc*JGMj9h?3>&v zIWoC_@~GtWx|IBsJt>tb_fy`D^%)yFRzJ4y*ui5*jZGUnb?nly zTgDz7TQ#;R)jZWcH8izv>V(vpshO!osl};>Q>#4e`oxo32i4Vosc(S|AfO6Y9`c8xHX~Svvr>}O!SzTH&OUJ=JU0mznG+% z6gz3tq=HEelOrehoxEc5wRE5K>FImYUrdRfQa+WL8Z$LvYTDH4Q!}S#Pi>gyGc94- zglRLU-I=bMo;W>k`gu5j(`kl&#>^ReW>n62H`8lo*39!Wn`imVN}Y9Qw)O1j+56`( zbNbKOGN)|LwYm0lW9G)sO`MxQ_gaQDLzQ8hq08u+k&v+|qab5{#^H>bjJk}bdHlS@ zd1>>~=PjPMYF_QUxAX1id(97=-*tZ6{894@=kJ?;YJq%#X2Hw_3l`Kbc(CC4Li>eo z3w;*`E{t0^YGLZaNefFeHJSFAy)tKJ?#jHi$aYcNMX8Hw7V8#IUp#N|izWIc2}^b@ zDPC&6bo$bROUswOUFNfF;<7Evik6*Uc6HgUWkMF8wKgj+>r~e3<<83oFV9lKq$oL^DD;=xM$m0l~SuAIAa@ybmr3s&A-C12HPRgYCMs}fdCUsb!RZdLti>FSu( zD^?#|eKi|p2V|#YZ^^#7Mzdz#npbPytwn1i*DhUqFlTB`aZXuIb0m-!O5*f(`37RBv?L7`}1h#)6GkHwv4=Hx1u3chja#hc?~GmFI@% zPRN~^yEu1OZcXmfJb7OGyx6>{dF%2H<<;dq-^^|f-kiGm{1&e*fm^z6iQ6)1%giln zw;bAXWy|ZW)?0(O#%`UtHGk`=tzb$p!x@~3K z?reKkU|kSiFsfi_L2*G%!PSE2+u7~P?b_{L+dFO7Z;#qOczfdZsoNK9U$s4Nd*Swd z+e^1sZ@;+x=JuC`Y@xDHTc|5+TiB_vM`281LSb6r^uo--?7}UDdkQNHuNK}be7-}o zBVxyj9aoB+izXHo7d_vp+ZnfW)Xwakn|2oLJiGJNE{|PtyYhCO-_^8RzkAZ|qTO%y z1n-I4GkwplJ+Jm^_J;0Vx3^{=voCnx?0v=i9(}=n5%ERp7l*!h@Wu1}w)=JaBlqX; zuik(5fb#*b15*#oJ+Sz|x&tK#$`9N>@TxezxUl&3m!V%~etGSn{9yls=fAT4D)y_X zUp+dMa47%KuCLv`PWk#yNq9+QNq$MwH_SI_-=u%jP}-|Bx^!J>^S9yOMt+<4?UloU zhrd!*NqxFg9&CLNi3BAtk%I}mvEq`4uRLCo=E8HpqE4o(nt%$2gu1K$#SFxgEQ$u#Jl0gjS81x8t9+|M zt0JpnsuHTws-{yP(89)CRL zc>3{q$5$NRbiC;J!QbUCU>PgjetFx*% zR2NnkS65b_t-e-$zxqY>+Y`(Q^Aq+byiNq3=z5~>iMSKVCnlYkdm`&Z-ici&4xOkx zarVTu6ZcQNIPtcIsWGpyukor0tm#_Qw5%Jr#Ot@Tv4ui%*rDx_?@E+Us=e z=}o5(pFVZ^%IOES@>=WKduLM4Oh1!(X5E>>GsR~r&(xh|&vrc(Oxq0U{ohv$b@Lc7&d*|MrSDp7cA9z0M{NVG+=ck{acRuTU$@z=t@1GYg zcw7j*F!(~&g~AI}7oJ{}UR-;z=92W1NeCB z)a|P)sjIB3t-DfptL{-I?s(nzdUd_BKE6Jsenb7)8>$;IHxh1?+?3y3ar6H76TYwf z{>80;Tb*vD-*zms-n_MH`Xw%pl& z=kT4XJLm7*y3=r{@y@%u(z}j#eeMR_jkw$Y?%=x#cT?_8ygU7F=G}F73-0c@TXMJN zZvEW{cc0&VbC12Jyr;eAc+cZr>JJ`2Z1^Gnhu8P}-rse<>Bm(M93KQf=>H()!Mq1s z9vpg5_t5%b_`@C#qaVgUob<5pVe!MVhp!)%KMs8y^*H76?8n&+J)ZP>y7pPz^Ms$) zzUce&`Nrm#fiL^MTmYY&zv_NX{PpUqfLH0S8vj1{@B9D$_I32@(%0|)zkVR2oGRq8 zsoWme-H;%Ay^?*8`1e@KEo4~aUt8bU0jcU6>l*_s)vjt!NcpF-sCgQ3XnrE(NzC89 zo(j843`FD55qAUnkf9L0g#;~O7co)^hY3W%a#eG`62;*73OG1f(`i^lV_;ZV2jt(- zTo-_0i&Uq8T+~RCG9RNLEvt*OcA!>u{7Fa;Cnm8%unJN5)`So z;P6rwEs{d^8*vOPrDJFY_bag+JOTz{=s?Z)=;YtPcmY^%5g^mcVq}T3bXk$?giJCL ztKDHm?rJ=_nDHovp>8mKw1{IB!YLjbt{T?kf)e!|9297|gmsc}c4o|S8%ql-wTrW( zgT0NlmDWr~BkHgt^<^$`)x5%mAsz{bG90KHm)6^ufuFw?U3 zYI}{=MT$pa*iKPkSIZ#cY6X{2+%3ft0{cEtSR3Jo!Pv7$8ul1pG!AzXcE;ka!nU-c zal+kkJJWZQVg|uwN(fN1>-OVZ%uCt%Rc^p^d zgZ$BP{SY@su8@0UFCRvskUL>#N5;R6zXQ{zjen%2TID8pXv5m@GGAAYvB|RLvpBW8 z{VMB~D&)J0gUpK5TJ9`qW3K_SyQyRZOT46J93MbwA*1x>C>i>dD1k1j!6W*WSct^o zke+hE8=Ht`n}|0JKqUW$#@hOZ#=u(DOVvxYCQKcs*4RJ^3xE{7M8*ChQJMduwh8+H z*k6XZ!54wrWA6}WY@=?ELxMv)h6Gu`jTKa?ow1dcmk_l%Kx-RyS9tEl98SUGuT4n( zZt@Qo?$o7>JTz#~*9nhrKE9bUeeRTp3m0Vw*Ks?hUAx2j?iioT^&4S#LUWEW@h1P=4b9;X3;?r zY(yRv7(kek{->q?nbZHwMErH2Sgmb*)2Mp+_9aCXaGI(i@J&R6SfhGr#2N=!<0zio zctAo>U?||gI}liwcX#swe0^N+8HC*}KYGS}H+0OHp+m-u8B$nzYc&yvSi5F*-7WZxH_xlmU0j~VyjhK$|X{Um#Hl+6hfwUkF{ z6f(jixij&xGUt7~`CMDST<=XD>us~mE#>VM<}%b?W94n`OxkO_UCq@NAaxoCRR>iw zaASR=>Z}pDz>Sn4sW_i)c>5GMRCSi}C@`o^D}w^6IU|4m3H<3sCH)^KQLv_mViX#Nhs%d(hT9K!85S_kIRkA&`FJa{ zS(>ZZXq9W7>$bI>i%cO?O4UklrH?J+AhT20DecsbT1P8uCzn8P+IzFHqE z|G>_&U`?21x4^!#{@Q+4z3c`A#^K?zVag$zVU`IlqXQ=>$EyiQif&!g^>_VL?ajoGd&l>C35N9IoLv>68B87r;E#@&kv3D$IE zGO`vgSyq&nyJ<78c`9^$_DtyfL!H>AM5ysmC<4qRFa{-G=$CF^B(6E+L1mi`# z`J-RUAZv}4mXWxJYC?jUJ{PgE=*r?8e~w7 zqV;W6W(veAWfB%lDA~%Xm0RW5e7#1hloJ`RCYUftYr!gHS~Fgws*h+0ya$D|H5|uG#WC!Ur%oqd z5|-mRmy%DP8gmKH5th?zJVv)cncn4C(4+2pHIm^13E>#{5{r$Tw~{JV_nN_)QhQMk zur>gz!B|o=9^$GdhnRLP*Y~$vhkX~e<$5u_D2CiWMui3qK8*y>(sp_!DTMF2!7hy* zvgLs!^>s$dbPTcrqxvRx4yXcMy4>)X%`w>=y(M3yK}E{-nrvH{ zqlGhZv~sY88N7ixs2ZrL2*7TPTBQjJ1c!z34n%4d0@;NBnbif`x5K~f+uviE@Z0SVsdBO@+JvI9v8JJ2#W33S>fp4fw3C11F(_sr@!7?K|x~jPl&mc-t0rv&I z8G8};ZQfJNPKzp!YPta@zMu=p{Ih*w&5kHv?+s@hh^?a<*hS58Y@}+ZdXrg^c0CI_ zKyavv!E#3%72%zz&|85AV%=&>VJ<|pp!JP4HKOtKZ-n`LgmO`D!_4%7L)bVjPBNFB z%guCHZU+b0SUc7pP8B##M>F{u_R}1uJ1$09c8l#7J1lnGkM=vLK^1z!5<)^zN73s5 zWhV*gih}}K>XGmWHl$8A_Xi{fC4Kru*68cA=hnwR$J(AF?1VSP#l^Gm`tZ*;_nDO! z`AJ=ez~`qD_NF@tKZ|QG0D4b@wfmrSeS2hODbJF*Wa%u6tjvmJ8+pef-A4EIe74o@ zHr9@oh-mE`y>u!^qIHq+Z72$?0R`Ym!0Kh<>cO=K6=EZ@TO%BqX;g`(&FFxEK9r?6 zC%Gi)Qe0V3?$n=RUERE>yJhqw{BVfz;!g`C-PZ3Gt_sgbotrTD{O8r@D)t^K%Pri! zWl;6hX%~h)#mcqB)1`LZ53fBvPj?8+%UPPcZ&v!W3=glvI^B1r^S-2fodPu813blm zrd_0W!e+z_5n>jJh(b~X5yc`IR?3khFJ+aY-c`WDjE<3#F04KR6q0DI8>n{r;6q*j zZ|DLgs;>h1q9`;BjYqR!>quga{g4;-BcV7N4^R#;i^HjS2A)fnVKX4647~FoH4RRv zo*}%zU?D`fapOYED9*F_F}d6vv|lK~iKj&x6#|V?VD3(6l-`}Sm#DK;PWD9-ZINoF z8B>H7nPp4%INLa4IdO!rh<8>sq5=Z9 zHYgBTfj9p#VJJO*Aa*T9ZR6WEVGp5R_;u9jwBa?MeRc8TR|9tr=57=V8!Rk@moNS< z{8Oj9)FGg(prFjdOVlYjF#kMJr+A=vy@w@_%(9fI$eJ&5wBD;KQm%Ac@0jhWbdx#S zIa@jsR~H9QP%^+s4WgQX6Ij%PH%?Knh5cE4nYm0ZvzNF_JgmIbnHdT3&PNU@7X1N+ zn3m$MqbkWY(3;t^V#kgZP_V53w*Kd@TXZh{>>=iaSC51i;U$j24*j>0&Xv1%9y_*k zS0yv2+`|h_i2XWrr10y{PlXqvl1j#Voncv^H}(Thr2$=dG)8aBsTsl$H48d}1DX(y zU{LP71cJ6&(N_C^qzjBLG$m5}aR`w0(3u2DfKKX;ordW(@eJmPJr~ABapOn{e0Ny_ zJOkDNyJOe=q^9N3bu6?5aW~?c7I8GR1PiemaJ*W?u{*?IpXfbp0mI&Wk#oBu&3fl- z@7)2mN)KO0D-TBt8EA1(B@w`DEQkJFWAetY%mx0$6nx3f97pFh8ya~3B}U%Yra6j+n!*R#uEO}2>gjl0Cf z4rd{|BKcmn2(7esDN?Ps&i0fzI=WgqBR4lkGm&k8rA^l9sqjw|*I3uuowBcSsBx@u zI^|sJA}Q8XX@1fW;G2%3^3hnfI+ZBM$SZDMSd498VG!p$>|f9ixFx)F;sfD5Ry~3k zLM?nFJn3J6yS8$a3-Ai~Dw?En}>32ILr=sxQ!FJyJS}@9?ZZM;tN<<0*l-!8fpOztr;S)d-MZ`Dri4V z0@=0ymC_s^jH?*tW*LI%^u;k*p1dj({Pzj|Wtcii4B7|+R|0%VfG@}D{XCpyJS%syWRW(@ za)m0_W<5~U$=*!Hv2tf@=4j740)3H}y`?Ah=#|uOu@tQ(xQaj_8VN$=M+0vEmv4nP zFIAVJin_jKb7XVnb9Kf%mZdugTsH`VAmaXD9;rZDK$IkbKnX9ubm`2APQ!}-#GG`y|S$KKD` zr;o_pnMJfqw10HBXcm}P05BxTn2z!G@}RgehD6pZ zjT~)w7L=8@F+2(dCC1u-22(-k*0gqB#+r3==j1T15!=Qc{QlOL;|eeqisi_ZGTZ$7JvS+csjK2_T?N(4uz*qvH<&%d zZ${1i;ldLv{~w0S6>r2nc5mOlTd2Z*o7S)2Bq$j6SySe`+`Yo9_btzv3oSn^U!A>- zNfo+Io;oFcU(GiwcWHH(ww%8Mj5!T*P2M2;b|_SDZ?@C?kUUq7cfwbEKq$p zL6wwI$r0q21CgVQ)xf00_}+*#urZ~HmLkGhZJwvAIF&XSZ+rvV&qa7BToNK-oKl=8 zqzN%X66gPZ7PiIhaa(M&PuMJELc)Zeo5CU;SHt)U1f%o0EPS1Eku;b6O3q=K1pHD~ zNl{W?Tl;}t0i`ZxFggu-#fTf=1ya&t&zx%sW8O7)r7mT!;+DroT~GPM9r~A{HhN8K z|Lj*_FvQNm=+VxNrW0&lsfFU>uH7$?;VtP*OiRf{+G|uX{YeTVEve7sgu?VX#5v$x z;*cxV>{K7J$~9jv&30yxqdJ%kvb9sFz^QI*ZfJ%fXy6Mp73xJ*<|*b0K*h9Dkri`M zCi=3cg)&AnLwH&w>=I_+)p*nfESa3%yjplE{DLj9=Cl1b@cMl%3kMCsTk+?365bls z>-*7(!WH2=;hJ#8(}Y{DvxwWadaX2<`3kluKlPA4Oj?v^z1OrJ_~}iP1I1Dotet zaK>a-4z~kRS(ecAg^SQ%6L_H5kSC;y{U}hR-crFJNiKX@d6ANn@?ou0q}lopeKv^R zCO9b69MHba^ky+;iDo%wJIutsReWnKc;VvZ$Dek~ngj!F6kfk6&O7x1Clg@aa`da- zN2&%-MWW`x)Kdps)R>V{a5@P3TE>G@!At2R6hryHuz&!d5 zS_ZR>Olr;ea6ZzGOehyD?alP!K9LS##xXOQS=yk4SLCX+;n9L7mzap}s{WHq;z&ynOP^T~F8 zyQGX9k(?oCB;S*plIP?n_Br>0|Bbxke&^ecoPtJ90mNfh2q0mr38-3#*%k+4FT8CD zqO@Jf%xZ~he$4!>r30X;RW2!>IPeygR47^ONW$T(sDKNaNor^e(8~fOF_KJ@$%2K2 z-l-s7WWH}64Jd~Ui74B=3-qBxC-lKYEs;tXHD;s~5Jo1KfpL<{BIOc>zz-vQEmeRO zf+NbDoOfiq$^q|YRCcJgrVL8sXcOj5CWtzYbW@=;-JD`Rjz}z|7BWU|#b_m#axcb9 zqLX;Zb@E_Ih%hxyrn*}U>rf>q{C!mr4wW` zrE@?Jt|7U28_|j}6d(>H0s<+(9&U%{IWp^l4;;b>qu}E;NV)AN* zS1l7@w(niohfRL$!}l(r|EXQN4Z2L+D}uaTt_I~A^LBO?LB!5VMe}wvP4*#gM?+$W z^x=PRqq-9RC*Jpj7EJEl!&orf!{K4pDQYQOTvS`wP~no0^&yYXZT*Y$oaSYZNu`c4f`J7 z{ozr|eu@j>T`Mk}P^{h;GLsfqX{I#CW@gGr3umQ>99u|gnmL;}Sb&#n=OCg;)bUg! zQ4OK06%(9cA309Iqc&lX>=6^3M$}mvwQAoC{#cEj>FKe)Q9jQE2C%z)4D{wErn z{wDnJE5s^$aS}zMh}33bt;w!Kb_Fo$h`!N>fPY8ikV1z*M-72aBpfWaBCJ)eOq*-A zNCDf{L=8TYwK*rZvt!lWv~ou!3%N=_bS=d+tW6X`if#=o?azyY1|WlaXUeCMb1gA^ zZ4Yzc{7G0VWQDbiHL-zjGJ9fA#*29KUa&9gCDS>F;!vg+?!}~WGuRp2EXx)A3dt6J zi^K&u7gBsSmUKsz(oXHFqi)y-vXV93GrC^BeWLH`+4nBu^B6TRX;~?3$j#lrR9UZE zAf(}idC4s+xf?fct*K-Nw7gutWXUqB(`b%*7x20_TA+_GQ!?fX#@WSLDq|#a#>K@s zQm$}zVXZK-+Ns@So2zDX(I!uD&U~EZ3Ks_na&xdVZzr+Sy7{Q?)q+ekKAs`O{*Kd_uE2@X=z4VqQLs1$Tc8yHUwd3b9n zqgEg;*F0N>7HOo8@=jn;yMs$58t36MoUk> zISZBuqe$3$`5Mu{2Yzb?OH6SODB(XgJWR<6(ayw3DUT;3;!Aq7y}99JK3PH_k1k=P zEY-(a#-6q3d?ADD#k67DaGtzQ+6lp)1rxzWa2@$5)D!n)`mlYt-uy5W$EPym+40<5 zG!w$2IqV#62A?T~y*0iK$bc&jl0iJg^ldqN9pA=xuC<&4-EG7E1dbC%J>c65`vAvE zoT2Z-+4CIOQ`TNCBld8Ff`PppI6=WvlMC|BwVGTdv{oaejFf|m!-E}CNR zqe6nrRQ0VVMc{bIzc#iXV!sce9};cvYo6gbMhTog_%cfCs=r)`&x38Cl>xi41;9PcBy?b9-XN zT1oAcDsvs{%ISEWL??BZdB{B#I&+mJUqFY6)yRH--Do5wR?#nj%Y)rzmCt9Wt2NWEMM}o5RnM z%#x-{XDb&f7n)}=%gG9MCAUnrN|9r}ncZRjwfP8YVJV3ymE2|6y+<9W>9EK2zstf( z0d)5%I5hNL!@i^i`~y`JWbuG@@LK_`etD{%H)G*YfD%~m9>h3@GtojhGZG|I^gyXU z5YVqAGA3TH72Q;s8mKG!sz68(D~YP{!#}+i9!Zc?#!3(;V|mQT36Cw{Z&>Rz=_K)@ z+jttDaa+(qE=@=fhTUPTT8|qAHNRsrT9y$fn4_T?bjCB_FDcrj_i6QxF$2j1>bn7b zC?iQDsWSt6>#UvwZ6cA0+C=;aWzlG!9(zC%toLWqcU&_C>L_{!3@+bypy!7B2Z)aKU^ z1)c*m1D+EA&(!~vp>=u((f^dvWP79(+*y*#0n6b?7V&bLU88v=xws+4iz&AH22e$y z7->pXJoaPs^y!w39{5~hD`^AnrO_pelFB%ukRpXOv6re8{)!M1Chex^P5Md)D29+> z(o`~DI$1G`%$6=x>`+)!#(|_fD9{k>I*rY3jv?pXcOfOs?xp zI3FcJo%I&%0lt(ufWCpym3)GvA2Nc7##$erHWQDvHP_KZD2?0c<_t{;yO!YnuU-kz zU(WB%Ib#2R+W!Tef#LVS3E&4#XZh7 zJKZO-)yqLu!w+;23_O3Yj`~?|>Of5cM^mOIRgB98Axen4zyQHpuH)6h4A^c5K5i78 zSgmjn;#7+x=m6+_Rz-6O^$?i?`dRJ!Tf)H{iVhgBn0>{p-4UAw-~1w=NOk5U5smtTa0(Q_cA9q&hN5Z zx7>A^+dA(e?^oW=rdLfbnO;bAPIO7sCAy|Nr@N%<(p@v1GhH%unXa}U?~!%E9f43E z5~!|!N+~ndKOS5(d22;^dAF(+2QRg}$IKU-6UzpVtsef5S4>c9M)I`VhuidTSyY^w zbaL168qLDh?b{c7dxNTBP$l4M5AeDIIigN_J5r&vkX6`PWm}XxY_>xhO>bKzFSYL_ z`lR3|P|0kdJ5Xm|29zZ_XF3--6Y%`S47c%o86><#SDS%kuQ!zd^5lyR8@`~WWo`I3 z8Fk2DsLS{!yrP2fzx3?cB`8d6N|I0|yn|0wQp$dq4W?)5$TOg!9qOicKv{SNYo2Ac zLSCU}D{O#x_7aU5iqiIk#2uWi0Y0J5KTXB|^JM^pB@QZwOow$2MGiD9`QY@?>@rQ@ ziSYpB7|FBf?J?h;J^O9U_UKRdj%)!hrXA*o>|#R>`uRP+eEG4TU$KV=EXW*daJW10 zDnsYR4u=`4jQFyzK<3&CPMU3AjyHq5jigL(wMNmC;tPB`n&L6ytM*U$qG=wHoNyQe zf;#Ju^Wq6l1TaY_Y7@Yy zxrYS7o=p(*u4K%o*kAarqNL=|abCMMCT&bkvp@MRC;Hfz6xTu=I~;JWfKwQKAp@>- zl4-Imtt%`@g_nD|ca^Nd;<&w&mmQKSd-EENt|uJ5peHp&cBpMIGK6r0Vmb_@$T!os z$oDT&WTRsK*w61GZk-som&%z_&Cnx7`+xi|qF=9+IxJY!DJ3M&|Bxy0K1YaXX#BVT2z6=p_ z%r7@rmn%2RAzg%`sc!5ghW(=8N6@WjdgcrA&{p6~&=Aom_;5k@bAXZAl=6A=at~Hi zM1DKt;FXFX7L4St3LY&y20$HFQdPfB#LFUy;$#U*E zs#1QVlBzgTz<3L(dKGQhh?jyZA zjPEawntijTAZaV_14FmsumIK~2TRlD-{&=}&}LI&Q;K^1IkDMb^7!d)=AROqDsgvb zG|R{#tLe?O;ryg=40zDeX^_oa%&g?rN;fij+-B)+Mnkiii~=&5KE#`)xlBLETc(jj zU$OQyOG%TI;M&nNTV(~~`E$!5=CfBV z=PGz@^LYHY}8s3NrNy>!!|A)Ev4y>xm_Q%gY=iJ^~lACsK>P-S6At8jGD6NvUeZ;-5aFE&IrR+Op!qk3M+jv4)Lu*@@|sR;aQHKQnj- z7wk!`&djOXpBZA7{LIvpdES9D^DU<)G@#!-HRzfSjmmcxaheken&Z;eIfXiNE&2I5 zZ9^rer_U{Ze!-*yZv~L&D|MCnN<*cw(o|utv{YIvZI$*)M}_mC_lDPj(X?v&>D}mkR{kZ!VFU7-A#0xk1s6i)Y`VhyzD&{$0ePzuu4G*d1hC@FWQp-X1s*>Fs zJXKL7d!<133hU*D#pta%y*sf_8jb66E4>_qG5GTQ^er7!evMQ0a{MdQa&SP$Wps9| zG1e4oZU=#)t*NcKtD&p0tEsEmkQ~@x++f;Z z-e3XFyTC+IYt)(~vt*I1l1;KpUMX6Nkzx^~6Ua(0NS}~inZ7E0d-}oj8|hKF{mpNd z1yuzg1wk}>GpY)}j#x%%^WY<6tEwjLDmeG}zdsy%_U>t~Ph7KQ>XX4I_k8;Hv>LhK zL|WR25y7GaYsTKH{VyaXozBY}Gju?4iY>W%&BMn-{$?;*ia%%`2CaZ(ZPn;)(oy&b zoYHSJnxOoItY~*yiNA6oB`0+4<@60K>DfQ1JeDLAcSKi`Q&RItLUFJqtU_5op#0^R z-+y%DMxY@5aa+T|s=@mX{Fhj^jrG99fYzRXoLVB6-Abpn7}+T^@%6!A@SL|pEa9@z zt#rx-mfoZS4Bb6W5OaU3wzk(Zi(Y+`ofHo@OgwPl^dYh0=E39BCPT@>bu4lv`qc_I zgMnN17g}hUpufmqfLq5Xiqsz@r53pM?;LH#IU z6dNOrk&E@yglTN1G*h0gnV~HM;^abBAyq(Az8n~F>sggl1#Y@Q`+)EO;vn`(d*nTu z-P$9XC$vxNU(tV}Z`Ah)>!(;!_p_{&m7Z0`{VJE$kC2YvJjmB(6s8~#b7W@!fDUn_ zszV$J9pXsRA&&fC=@8G{Mu$kVIN)gq`Q|w33-{7N1X0+E3q>;pVZlu{tP5dgxJ@22SuB#ofRrGoXcD!Fx)gl?TE_%a zlDV@4>#V*r=^Dj;QlT7#>t>Mbv-;l9Gxj!-o{`pZlvpee)c~AASF9gy7-1Y~nhZbw zsp2eYsys_GOFK(9$1u?}-8|O{3~aVcTq!M;S7LoDwaaytaFAJMs5Dd<7n@d^Hu9*BJN82jtzl`;FU;huKm25Ax%>$BYM! zvCuJTphq`BiswTydVe(s`(v|Wx9dx8)&bAaug_=Hw{-&S>I(#-p93zd^ zjM9$L0Vc#S##C&XYgx)FEf2C?x+mEo-P4wLET32!Em@d*gGlNst}~XWD0i`AA1No5 zlOM6?lm#ELbe1lcHGIzE zg3aPETkzT9uv&0%%?_ykds<8eyI|66lwP))PEky#(EyFV-X_~j_V5De`H>9WRozW@ z)pP2sQxG5QF)YhF}7mIG@udBFwV5jw3Rt3^h>QvZB@d(hV`cP z<|<2-waT{FP;II<@3Zc+9Wosk5q$7d&0eO-x!}K4wV}w7_^%w#iMdF5kna!RB zD;=*PX{0-3a&;x}sUw$Aph@8l=lB+pD@XSD<>=j8yLaDq*U?{k^uBM@opa`n9d+O7 z?Ypjiw|n8X^6DE`cWx`W@8^fMdSkZk|M@;F5o59v$4&r$SrVKtGT|8>u?NRu8qg(# zdchUs#4&B$&#;g1b!{;h8-pEvDKQadn?Ahf(1cYk+v7wzGX*n9B7ZZE_MNkN!}W6Xj}-XG)I4~$-0JSI|gPUsA;J_@l@O`il{2{yOuyiF58ZX>_&+OG}PVqMvpeHG1oVrK65Y?Vlae zyQ?fpnjV9OKRcvPH~w)T#MxFc{*!o&zqne~BPL4HfCq8)3KwL5q~+oP|1U!~62$01 zg)qMqFoE)rRYHx_M-8skCo87vMBD@jz)0Xta=3C`q5wbu&!cYn0|nl2+t^g)LDD51 zSKff1;T|xt1Yu~fjVr<}*v!nNgYwg4-(cHhu5(A2>f(H{wGmqqV?BZ)-et1sWT!U~ z_Jzw7lh4(1P=G@4wx3f~$owE+60=j(*m1fx1Q4A<`b`~%lS*DV`HoyyJQEM^JakC3 z_utf;6;}1TqiWE!? z5Y+rg9`vHsMe2C)acV#pP=k;21No6$2jpsDvXCm?S@3pBa%$S27QEASVfQXeyT3F4 zos^W+)OX6?$zK@kwrJdg3+6ri(ER!PrN8~D{OztwdK8p*MwPVGl$3YM-|n%vOK@SQ zx69uNq$DdV=Iz@zZ^8bD=)4ZYdY*+HElPMjSZEg=5e}PZwMEc3yG?J=TSbdS-_r&$ zSa>f|>omRRHrOqzMYF*wX(DWr$7x3-=`@!xmBm`788uUNk{3%1M`b9*!n4Ai^uEZU zV){>;_BKKTWCc#~UlzQ4LwI3V3AyX1ZLn>(9kv~`J#W(l!1x2!bbFd3&6#iQY~N_! zXkbC|d&erdsYb zXS|;JT9W;B^K0F9Bo$=gciFNlF4NFaa*ghsIofX+ZBC5toSG<&&Mg38_=12aKuK|y zFryHLi6fq)Bc_H&QVIP=_1$R+)1X=@3pmAt;UrA)R0s+l3*rjfqdu_!bMTpI z_UvO?e4bufTKeUh)t{G^PMAaS>@VAt!@I(A0>SNDUtJ&h+0q zXv!qzdXE7E3#KnwHfo+jKd9)FKb7Sw`=#EP_xClEq&C1SmV~Sq#qW@66?aK^^bw)_ zAG}v6nC5+PRKqdNzaZfg{XHu!lDcy~7A^RL4((abIpM5%M~q>t^G<1OR1D4^_X__J z-&%$I0@O!kC!{Ct&`}hM=gcWCo-=nyaB-V8!7B?~Lz7ah4$tCf2K z|H69JCR`Q&ZMtf6?(hm${XMwJK=Qc)Nf&w%qBrCP%qdM+)``qPcpQWrl4LtVX~Bg% z^~M7iW~OCkcBJ80VgW0eF|xz*euLI`-f=>CzLR8KFvr)4wJ+^CG%2YfHg?_Jo0TuJ z`S>P@_la*|d}%_zV1RHIt{Qw-{jRGX%T>eA+JDDh_5Yl-BR#?;xV`tJ+V3HRg>(!N zq56n(Q@xWRF4U`1ggRF4a@^YD5Q>>;JzTA59yj&$Go4o!c39GD_R_g`k18#lIAucG zw4p_-^0yxyE0;NE4_mRp<6agMJ*2Szz`F~&b?NSmEO$5;PwrEOJ9N4Htu!p`PbD__ zQ*r9?KlxLUep1~0hH`Q*+^IIv-heFuday5{JMkmtI0fN-QiN7Am?h@4X*b43kV!#! zIl*gil3Bq=b_E{s2OAaV4qp%`)%7c++~S7N7kr6jiSH!B;h~j@f!i8FY%?UZJ5JQz zyKz@_ZBmNCADdp3)MuD2XUC*z+cK0ptaB&%X z<-XHfKllfe;c7Qc>-*(z(qPBc+SA}6zcS7 zQlUa~$CBU>_bNWQ1Ygi<&>AiO1XPe<4@d?#(Q~2_S(ocEQ`vB#fwz52F)%eCj>zx0 zbaA`UZ4&!ub?w$Bv&YQrF?X8HYaO=icJZUTV=PrTN3Ur{q~|;cgCZIxf}bV3ZDBUOquuB<#QR$yZfxHGCi$#mVUl0}XAE zsYMdXAS+DavVslw(RM*EWQ4y(KrXOfm3PDnE(`PCrMug8mj(AwoW?MFgkB7EiO3qR zw(9GE7(rxGc|8s$XZEb*xwqebj?e^V-cvba=E@ad@N&%6GiUyK<@A}W<&SJyfAHY? zs)L|QuY#}lYv$|bYe3mE8cf#^!DP7xeYY759U5=VHF!ZwqI?a0l-g^U7YzgeXjyui z5#7c4x>=9-2>o26j?I;XdEo2a>OsHwO`j&F1z#s!YjbdUn4gFFJA%!Ls~cE~`t4Qr zzS0Ja{XIlohCU%+zjT;VdInU-e5Uy$aDN(wDqzG_YHrvAnz!Z64O8r?LWO|DU)r(2 z!Vmwx0KZqu18O-OBNkF^JU{6-&o63z9`gn44(T}dy&u}a4Z$pbG!U<}UV*DZgoL$8 z=4#iLq}3_fL~n!v8k^`ugrBg)*o0KTOhh2w{rY7dsTHZei^PvK%c3^(CRrD-8txff~|>K4apNM=`q-ftC+DL9_QXGF^9vL8?9j~&}3 zckS%KHD#r*Ot1a4XiQ0VD#D}BUAQ3k-amEC=#txp!gpj=1@mGD|3WObGZpVm^SMzz z#TMPBeEsdp9XjnMDi`cE8jHiIYZKJiEQsD7-=42YtF}>h1F!3@F}jm9sA~wiha~yk zSxNHm)L$2_@3ipx+0Fus;IvtIeVjGkzHT<|u2yKVE(S-K9Tsy;Y>d?r8xxQJagNy7 z7>gspmSA>R%{E(t-(gGe(a$~2F*b`qdeviyueKPr`eWncVx#=N1dCH^g*!uxFe)n6 zrXA&sO-O`(5OS>jG6`wwtv0Oc&Fc0Q1b2kTVtJdj2VsLx$RP>e)Dl?l{cyP*AM{6? z%gqm(DfTa>IBA+?rgf2}!n!PWS=?g(;)GR6W>Ofm)UvPy9$-T^B5Vi%!%@V!G-6Ca zaCAvQ!I(YD4KYC}>E7c&`GQ9Zx`}Qz0$n?{V9e+{3Q9_pe^6&8V>Jr0UMt2rjaE090>}Vjo>dJKq5wz-4oRa0m||!;)bPhuWTFqcraP9{mpC?< z*V`X(Y=>9j8IOTnBEwPA4!kCd1cTA#HN=FXrMoxWIQW)0f3xxeg9CjiaGKsn^Zvv2 zHze!`?A>x@5yh@!Pa~WNG+;S{Ycb9C{GLR^@sUhzqNe5e4BE<*HJF$f>O}T zXv_YlP1IRO&k6>Zcg#UM9R#&siWx?~ZPk9ItZ=`r%Gcknocg75L0Hg$LO%c>V;*| zoS2jGLUkN?JqO|ZxSM1L)BG`&F;B-x2Mh;{2TTWG!98F*U_anEV>n|xV>)97fV1t4 z{fxs7*K1b-j}c6#8*HwNFJ&m|{ylb(J%a%InFz2iJAeKnD^{NVCkut&Yu*n>*^8&P zv(J^d?G67O4!{r3GsUN34)OkY-wm>YIdRtru0)w=Nw%vX(eCmkhG|JCP89WX)H&A# z_?+KbzW#RQH0M+fx@L=x_n>`^FWL_HC3WswwLxRyb)#yeglq%qTCx)gvi%8J+4clq zw)S_PS;wDo*GRr-dd3j+4T-k#TLyLw%-Nd# zWZK@Z+O+qRO&f4Ff^k2$Y46m3(%734pxv7PB{%PK%K!=%PFjKj$xF7nQta>^!@; zOvz&xL8GTNp45D)jfDNsCA1M94t9(4MO)gmbs2Hjv!ti`-4;0`H9lIdPPJ4=??~O! zwoTg%cck4PpTw)grQ3Broi{1h?v1p!#l5ipI=9laP+j9i;MWCW^NMP~;TLJnhvDm( zFKNYnCv@H6?ad+6tlEwK#TpnhBfNfU5>M;REWG z{K5n{@`hye)J7~a}F|SWo{>3AV z2Mjn<0-6zuNyPqzk09sE-}3!?Yx#QlHs!Q`sT}9S=#B!-2pY27{wSZ@9u+BSIGL+Py@}{2;z>N#M>`Gch{#NbR_Fzziz%opNX<(1rAjK_ zy0y;Y|GAFnLmhpMDXpy=T&Ss^{BS>F9)9nxakuMcqFw24m(|VQ&esjQvZ<~;TvwQd zy8aq>W*XJ?RHn^ME6$vd7R(%ymYrFUCS=;ujLpyKwBhH(Ts)T&w5B3$Q>saq)5+Z_ z2QApo;a__pXeh`l$g<_xvgGmEmPu1Fll>As-s?8(lE!|V~w#7J)*LeJ5){@fS!fS`ry7kWP24`{b>*)lu0I=fAF+w9EjcG+3k*}*o! zw!zF`yI@u@ySPnp+v3dPcEwr6+3VY^&t4VW9y}O)I`~TP-QcJAdm|VJy9rKNfwjP< z3AYh`KKv{KP_%O`bFFi2Wo^qc%i5J?&1*X^b6&f7S*zNv%3RfMRaP7iOi^P{RA50E zJ5`N6H;kvMN(R!po+81hQOuamJfdro21riJu1* zeYoxA|7sa*we|h))Icn87e%nJ?6IZF)nCV+c{48$@h!`iEM5B2k>=>DG9@Y$nZ@_< zd}R^EJ7Mh$i5?;8DO`}Smnhz-lJD<+yu6pN`L^YYZ&&Wni9RaFPWHqn#)M@qwN2We zXw#uX4mPSo@}NH~4>rC5B6OJd`%kssMwo{%p6yT;&TUb?SS@e-80F)_<7#FCOtLaG$;6@(o#@Y6K~U+ zoz9_JXB36yKwkj@*~EpxgF|jFsvcXFDXc&Z)rbD`&)?{*Au&TwC@2LPbPZS>kAy0YEDfJ1kyStqe60@l(GJ? z36uPj5-NpCRw*u*D!9LXWeb1(N@u03(p}+M9>Q3Ch<3vZpJqwgCzWQ4ElDV%sJ7gSC zUQJ-$=f9|AgA$aFq@51?hi6ZH{PC&fr&#JX<`m@^E{l0c8{Z;GIKI3(TS-fsb2{qeSz$H`(dhZ8-r#KhXQwJF} z9eB+DEo%Q;7WMmOqZt~K1@IRFu;I zkjw~8Wln2%hug}G*w7%+*}-{ftRQoYdsOVmxKaLDo@v-$6>_DfvPDctrMbeg+*1)< z8B@vkRi&@eUy*ICm9HD%18tPLh{6|pCnHxISF!_Bu}YI@up9|W9M=AxQyvNb{}=Q zS9a{k9N&*W&};LA`|~;??4<0Gg3V=8Lc`M;Y1iHyvS?p=`aj<5H>ch1L9Z=gh&svb zaAe4HgI-@sktiK;ePLY-@%=X_8rt~wC`>$UwpfA+IJ`i-;ao<+h@~rw3pBx zGY9Z6auOE7v!WOj5xq!4Y3#0?4cxz8x?e;n_BaVh$TT*+f&K-WUCF%&aO z@iANUwTO+`ef!v$>uPMwt+6LOHb#a0{XfOV=uS60di&s*rg77IV%+qe7lH2zo65c z-(NsYNNT7VC5d!)HFL#E2{kbWwaxqO0kOUCHtQd1(^(TG=v~CSP*<3%7sqF#t}4^{ z?5Se=As>X=)Yl{mdW@I11>MQxn)lIG2k{F*06;&+N6#sXN~j}2zQ(+8XNIzUtE}9hn^)ln2%HRhsKHf4B-r7 z?gN-~JS$&kRcc={;+RptFY#jST8$gyhvYmVt{~1AN0KuiQ%LuMlXO1{)Ht*sv5yJk z7nVDn^qztJl2|81#MW8tTOw*TyG^3c3`keK-l*;Cb-MZxHZ&wfWO;$q+7u1l09Q4{ zzNW59J(xUi%RTI+RH#k#9BfwqWPUCG|ex6miCi&v-}8OZ#>Iorsg`tcPh30uzv0T z7wv4Jc3O`C_ElPYi~;2s1C1H`757n;cVL%zd1%ZiN4z&LU)r)hy<=E6NP9&-jGV)* zb$#kMCt~ff*V#5!VLyO zxMjP0yK9wul`H5*?B;k?&wx1~oUlk>uElFbCosVr=4uatMOuwIb0koRJ2@?G=o+G6 zmdVMvMEV9Y7jn$VD>*!s6vU9GV*~U^9>N}pA~v4@B##^+2uXYuKi0he>8GC_y7>pv zKg&Z89s2ZB3>kU`>>c?4&U1{=BbY!j;1SH~+-UJ=H%54C?V&($m(}4h0AU5TKI-+- zr5|DJgnAr?cq-s#T_{SMqrssw#bJhM6p9KzphktSTv^A;l!L#C4VV9QX!-I($|(wU zRo8=b!kFI;fFdK>3Vk!Ua=anR7rMhVz6WA7U7L@!%%fWb>im<}iPcBMh3Y^86T~q( z&Z8RJaUP|%1KcUtVYm*o@dwoDr}>G_eq&r?V^cdV>d^iOjc0SK@mLYp5pD-OMjWM{ z{Z`{?Q3ttW7Kth9S#F%d&n(7+_k956Cas&!awGOI_T@lc9_klo1N9s_?G~;ZcRdHF zCc)m#-mSe*Q=lu*f+4DF2|F`o>c)HfUlh*V5}R$ZYr?s0LZS4C%%&iEJWF$~Oq0H& zu?d-?Dgp4h3L=D$*|FMG=T&8t^bCzt7$kP$QUb;)=!25CFkB~$E6UG?x^}QxVD0q$ zEU9yjczwDn;(hro(WPa-+*$|YiPr!J6LscjVt{R>725GJoK)gv#M@K3e4LjL#%YC5C<3@B_l~6B<4Voe{*c(HU7U&0&i%KS0Z% zHKIL0^MmrSY%%up5X?{fGm=dEg;SR4b?+J=OB#9(OOg`X9cf%Y$H z`K-8(@3m#ZpM~^IuomD9!|xB4 zB0V&>CM&?XS*%&t1<;^YvJp|(OIV!+Tvhm|WY=Wdifss|hI>RxBxDj0FnEr?cae22 zR+a!_wRG2@zX9iH&tK;%-va4a>^f`C!@O@$bkGsdQIk*_1RR{6_r05v3>jcyTn=yx z<8qyV7`$#!nSIgJEy3|~dpfM>X6`f$u(*)ZaL{EBq3o8+%Z>9apIUBM3^X)cqd;si zus3Q~4m@95(f>7oYaAXs>plR$bA?EWD&2&4Bo4;c?C~c7I_PNx{lMRp==~70X05` z&i?z#D9G-_OZx{C94h9k-C^%(sx|_5O!$M{WwJ8|;l4Uz1-RY7_<}n!XQkxLc_oB2 zruuw9pW`F5t}B;7T-`bq2PD5^9vIyFwc=;B!-hVu{C#F>YD0W2Q0CUkD}Rmrb6MH` z?DkK|D{ro)@z7llbAwIZH5hAg2~w0tw^3`~7=<8|QyzGn3WHsd`iMfmdZ#C`m_QKV zI0oH(c1>BrI|&>pqDAM;tToruF&`%MNIp{BmZB?2>< z-?4aGTsGWHRzTEH+j0o{NNUS2_;6cm(H8h4?rY`5t<|>T^hob;OI!C*Ti9o43*+Tu z;Jl)vaFFvxdJ>qi7>XHdZih{{YtRS#KCJt~>L{}98=`<+>w!_<0o%UEYvJ(jFzdtr zfm|HO7IK{{Q%H}~Y^V2AR8K-=lKMSY_iGs2{N@MB5akYbhCMTVwQ`0MgRwhcs1IB1 zSFm}20$*_q@avxf9`h57Poi<_&T?Hm<$+umY_HRYoN$in+nMVkTxn9B{-wkeU#-`* zrGr+8NNjJg0e*2nd#7P&8)s~v4s>mTUp3det8O@4;SL{;u)3XVc~T1UCgjb_JCOHI z-n)4>@^oBzt}D1&66E_W@AVvfZ5x#1zdjv83=wzjdG5r+d0||qIkV@? z4x@z3z5A|t%GHfw6p=8!0A4PqQ`MZ0seVwPO;WWsM4PZ1aNbq=0(!*jgC5yA-BIhW zQQ`?ZgX97!ikIVw5IsVD&==Hm(0ynn=n>r`CgAd{-Xo|l++R=!&p5QAA5_I&RpdKPvAV0fS$PvMrnJW_2l)VErnzxQV73`{j` z{MN+8-}bFOPw$TBTh(f8Z2T2{1IHG0V0ke~r@*z~edj}N1-=E9|BcE=tL0(bTeOLq zyzg?%xxI#24BYPnbB~0#>fECSwSl^L8gmN zHBuEyHXL@SXM;f12j4{QMdGXohx>xaI`pL6Q5i_}F2NDP(6tf7(>%ukM+ifgm^+;4 z^Wdk$v2-cz-9?Js>3sQD?+>vTrXaM1~bZf%@ z5WvUj(OlFONdTil-4fKry-FXE8oI}*?Wz1h_?GhrYR_E*tPTs>qr0#~JR;1$ zd7J9}Nm$G8PimW5Nwl_Vlb`X;t;Ps?_ZvQ;j#1U2v>c;d&_}guPd@;A24jQFkSp9^ zeMoW%#s{7BvX~dOoeQXg@nB!)t~keQxPyK^9aN`z?(U;;VF#nV(6gl>p7S*4IcS6G zD^m$yS?w3PiVniBjW?)1&c`))W%ItMTnzB~&@AeJ6^ymnr1^=haA}1ue7-%RmaNLW z4ou-^dut}J| zmi4(_hR@zD^)Uw2$NDHQ0Xk}7dHKSN{3`%6v)e!VC?RG(`e^&?DMvIiX+E(` zjk~di#h{gxpC=u(>VJ`+CxgUL?)CfsmY>H#0E(3Civ9aPChA$Yc>gQ^Az6wqw0=^Z-MmGvbw(U@?RKX1aYs7!eeJ#o zy{j-lZv<=EIleU4o7d$w>yY3{`OR{b-?9eM;D)=z1ud6Jdf}E8(7F$^`d3=45#0#Y zcYsbJQpgROBTWdqwYSrlkcBzx3QhSr`z0XWYO2jonO1A7;p{_@gwJ_ACO1U8tZY6m zuqWC<_)0kylEAZ=964k#Wkc%y*x(@zE7)LUxZ|0S&I3d9#m&8YHC*l8OFq)D?=K%; z{fpe2?V$M+_#XENPQ?E82wEIYzssrZYw&alO?+p1!X z;W(Xp&SrC1)nRcdQ8hjBos5`~7Jj}Am}ku>uP0gJP;o&Rp$*g466qC#`%`^%3yijw z`I@qWG2RWrrif~3M>O(JB2k-ROLUCg<<(|eglL}o7|V;H!2yN7WVHZg(btdY_-X(sjUt4vh(D0`KO{rbH(p%l_;fTgj{ zr4vANaL3V()lDJm5uM^Nh69Y7YU?3L+0YNTl})q{pT-m5{C;w%#TLzLXD2O3YMkH8 z5tS^F%t3dbw=@^w6Mk#oiCQ}dODi;6slB0a7)PnR9jI+TdG68SWx%Z@WLsrgYh+uZ zOc7oSx_wb?Q0AV_4b|H6(QLc7AB~=?q^rGF7&Ft{xO-R&2 zN1i~LFq3of0SM+n)>}FC*h4tr*KSfGubXTzPSlIacVf~;Y3HwP=m@b_aDHel2=~{4 z`=-EkU9`2T>c)5XR#oK<*st`xx|Ch(oj+>iD1bQLIq{z0#ll77vQy@5 zM9_+XGCeEbTzWj1Jmfy*Mj`t!u4w+HiwnxHoqnTix=9PN#YjFx_9My<2BFWQF~kZc zod`z=ev77QHddQfi`r@(rde#BW>uahnL1DIQ{O}UnNZ;yqABatF){8KJ9!N6x`=cT zh%Isn(crhK%q{32(VdWmYIkI{17Dw#t4+xN5yRZk(a475_Cno_%|;NqAV8|m!;dZD zid_lh%?gMUqzhC}qF>05fXji9zewH&?|^SN*Uy{FboT>}Z8Oi0^P;l*ibZHd?0BO^ zLYNNADVy*?VLxTMaz9Ux^Wvqmfa!=m%je<{*1m$r0tSQ0NVvSoQmx&QE<{wjo=QjZ zcmxC`X60$e_(fYKDJ^1S{Merz z*@tVlGV@ns&X+GZJ$%n&4_Ci%;_z6Ml0HvTni++P2a1a-1fL zxkE6{5!zF+BJ#TsjI$@wH4uQ*1StR@9vA7SdA8k9=1q=}sKPh{9xDvvi~&+$@e9GY zVqjIb!g6kg@1;u>eEga)olm?B0dPE;r=CN6PM5PUs>+(X`||M5~N;~dnDfRUkV zCSU|YY$77E884{?C;4smxjP^0eV#Lu|CoZ#>pk_~U?#WZp@WmWGEB1=>krRPQuZ1#9N3XzDRuxjvX9| z%r1w+>C`8sIFgeQa%aEZ4M{M%z2L&u(xX6czy3m!1D~AybB#R(cpbK&9nn5gq$^pU zn1HKel2b41s5AbBL9`)S7C;aH3Ck{s62K?&fZCCqoYx`0V?L6&oaxv$)|cD1ZLTl2 zZAbRe#|KGF^c2a0`IxU7LPkH^-MbGuDt2zppP3)+#lPYXSW4j6DS6I04Y3eCd-66gS3KgX31ux!vNf!!bs zBkDMRVa|qvL7%^cBtDsceBjuR%*xw_3?L5UZTAT}L=!S~Aj=4Fonno8-gvijy!n?% zea5>$A33DGzJ8_KkH}+mo3w!3pMyeZ&R;ll2LE6@iBJ_QSPQ(1=Bnmn$fS^Od@MhZ z3ML0NJJtiSVsdehF2`qnQ#LTKZ^Ok47sR)ivHmMr>6&og!l(NMVtO@P7ncAD3YqgL za|*33-kWTLXz$fvTf4(zwLoOGT1!S5fla3KsA-)JeZeM%P)H?*u7IkDO3a1A&SmeHxY+&zWQGo3d zlBrDC{azs}X!6><+FY9pp}#!2EmWddeQQLu!3MF#j7t@6QxtFnK?+wV$WLLxi6x4< zgjA8K@>4kl0#O>ga9TmJ=Gu2!>7@3%hMr*oO8h%T|L`n$Jhh0XEJhfnNYqMvekR?KcN4bESDfs9hM>38F_w0?K_aUjJU4~jA!hC zCdHA;$P(tzVzd}?P9(B;cv(1w-yc@pD|Vi<{8TvqA?rGCA`5`bHRVA(B&|I3YmM~Y zA0N26`8{B_o@0;4{HXj;Pd*A<2G@*%&Bnm{1Tlh8-`u5|HUyS8ieGhzj|BpErTimvOlYCLVXSGVe*nGpHIjF@wgmhu#-!~+foKy!CEu_t< zjRb~!iexq%)$UG-cDnllbX4azBi%_M`S(E&hEqXaL0l#SYC37cR8aT8DkQ-9G@ydI zOJTAW$69C+TB{H0*kjKtU(X!atVU=J@t($s-kU8n3Af<9pT|2u?+Tnm_*H`MAq)$O zH(f-e3mlw_+mJXUU{^wy0up1VPikD&>Z#8f4cj{gG6r^?RN1%x;Ju!9OD-_+bqdr% zPBBDkDgEY;ak(Rv`!^*f@9SRhI$NKooM1oS&&)d-{sfxV2m84U`xY8t(npZeh9`W# zRlaYL82-S5zs&rJMPB%vN!8rL<}G@nl;MUC44w%=kZIn+&y zsXREaX4>1I?g38w)Gcc!zCP{lvtvK}_v7aZc1^0P8hd20To50B{NXj#$+nc@0Yk^+ z<(*DSdSQRn-VAF(QEFH^EM~$nIPyE-1Wx=@*s%w~!z6diOA`KK4o)GqX_&Ng{5pl_8BN0&G57iWA z&l;#{g#~|t9}#yGB0R%+4%^U5f*y;}tfr$BbPNe8p^>y`U_iT!`wLI>Oa?Rvk1Dzy zJX7qD_ZYs~n>%7qA~<#Gw$jS;(zDuTWWpid?>Lgk`sH3k|2%jX`4VJVkSQ&|14 zZ4H{QUIOK_lUpF?Be&1qp>&R5@0=F0H;zF5ziQ*lb}J?CwCicI1V~Ig-yU7`$k0gI zC4O)HkMq=IeRQZ9Jj0{(GS&JBfqd}iZ*kM(&F-p9E}z9-e5&!^+6kJ!!^Ya_rknVt z<_pd@p9a658RDDYa=uw25)BxP@^>^B;Cs>q`QWtPGz1*vM%c_=XM`R8CKSE`(oA{L zgI1T#2jz`@wck+f-QvfKa3L`Vl6+o*CmckS*TI>O9~0ngqY4SIZfV|WIP%Qv%FiEu zsQmklXB&>Nf`@k?F>`yC#a3^9L=*MwvlEq?3pbRHS<-hG*uaU;KD$}@b1l*`E@o9M z?~g2ve0(7PH!A#o8V&hR-PaC#WQ31F66qjjF%Q29;<^JV=)&}g*N~ElntyK29g~%x zao?5RtIt$^SiTSdb)i;S@6odlQ@{Kyk>q>EI<{ZFajLd+!&{`flB^gfVmdSr$n&7Z7j6NcMx#Ea z!@cDjLLnluCAn)wZ*cM>a;!F3W=VVXaSsLg=?;oSYk+z`1E7kA<6%VFK!9xw zH+3i>pA<@e^!yeZ4FwQ)jK3G-_zqSa;?g<=T>!_iUI|dCy$~25j3< z)c-KMa_oqb+$m%BjC*&FOpi-m=5nT-ZSVEcJfPp2=6>@%=p)G=NX=rZ2B2duZO8;l zfuX7i#N$=>RLeWZRMgG)YF?y4#XAQ$pU z5bq4VUu?=A7F9ZV%B&G@&OWWqfHF*cu>Jvdg}>mvlhTvpmN{K`!5qB)x&e6of9^a& zYYsgxunEg>J_S;Kgx=NBAq7gmBrF%rwcmq`RUWrkIbzU|p`(jOO;r5s0T%lYoTo1v zrb@GvhuK^u`!nTRkEiW(ev6fPzs*aTv_kB(^N2F#OXYg|sEKe6VH8Io_lGQ!i1oz$ z<*|G;&$Y*}PKE%XA)nyQapTjmD)H6&fviip@&x;ALQ3F?4HMp5y8LplvOVp9~g6kIm(<%jkEgyl-gC)3nLdj*uzu;N_}6Gu}n>G50GT zBu{No4&QbWIZ(;Boh|0&Lz>$8L2XAfftR-r&xsa_5vs50(V`sp@>|*;%Ikv%HRDsk z|DsBU?}MOy#tKh<@-4dsqd@e-4Fnz@Z2}?u0m!7SaB`}6EP$y-=V$1>$(OA0Q*03U zuE3W9@euHh@i&6fz@zJydSQJ5>gC{hjEB4~F%GhGHO1$WF9s$<`%H|PyvJ!BZpGWE zlK;iu!=q8(L-o6%{=t<(&zou@{U*lLQ8u?>Pt|VA7Mvn^-SD>gvmxK33f2|=B&S>U zNiq=4wD$gvE$Yi14BD}JT2Pa8ET(~ zi$Ay@$h=;7Z4-$KV0_!?w|JhfsjfZd;xLU5(PhI}SCrpcAN#YpK79ESh2H#qb~Nr( zUPXO9{D}JLI$*EO7e8PuSKKTtWl)>w~nuo#?6vR}xc`$P*p%~l7Q+ngX= zk>&&pjw~ZMrl200&5M+;4l0i-i`ZsXdOy?6ZDnuh)zF~4AUc<^dmD$3WP9Q4I*0A; zSJ=|t5O}_1-C^a=SO-;)BL52dWD+`H1T9r&a2@^Y-l(Xg&5*QGL~Z)xism-TJtloXB+Zs7?qCq%}wLUo== zSB982%yR~v5$yf`*u(Z`60G)aLEWx|5edl&JOC1Nug0fMwkL}I{teix{n12-9;xvu zILVK~cT5b&r-0`|2aUE7mqKkz(P%rPhS|;B_c0V3#u{HiGojcpwq01oR#8e7K|3CO zmc!2s_EG4>Iw({4CG4WGIHm!Eq`SoD z`b@OW@68Zt5+HZv@rXEZCRME*Ng{wlpE;#W`AYd_`V@r5QIK4Z?t6Fj?12nGV?SB7 zbm`*1Lp%m>Xv2PS%FXKsiU+eH0}hD?&hw1i1iuv8cu-tV7*wd!n$B(~0%kacm{#Mx{4els}=CYp(Nh zPCsb=wN!I4_G%0Ip`DEOK{wF;Vm7t00qumauBblH$*BH5zCSpg0k4md(cH&k?oq!r zJ=1Bo%3reO;qhpv*ptN3@}5Qo?SQV`rvAOaM)(qQSZZIbueN^_?YF4Ud21s4|A>!lmBvu}jc2jw ztJU_UX}o>#RJ4QkTh+f8_%dj}@pIIt7(k3)0w+NGYWiS;h;|Kl6{M=gqUc{W!{HyiV`G1nP zuh!qFxXHI2^lpv}aRciP29Nr46*u{|^Kz^V%12Q-^fPYmk52W6^KvLaQ9oaCbANOy z$H_wd(VRBySBA;uIJY=eE*x08h2R2YV|nUlT;J*T2jFP+EOS>IRg%|eb^G7=C zy8q6C!W%ztoi$|Wgvm4Kk6F5;Z1vPv)@|rJZ0Ws2$2_n`dG{~RD?bEF1}rPxI)8(2 z)|0ckFD}_$kypUFv@1T{Go#atna>`ZJb#dD_LBL3*;=uB95yl&`YJ=Xz81S8JT4O5 zTMUdYyuUZFzRy0rYe7lRJBD>G`0$ezllvA8E*m#v$n3I7<##^0Y-zCQ?iEGF8<#5I zpLQ_`ij{{7)2Sn>$`QLc&m1H8E=@h)PnKJv4wn6P1J5eHy zw(2L$T_N&_p8y{R*JL4{lH|A+V-5ggi0chn zjxjt$WF~8R8*%>j;lqXvXa3>ChYwS_bSPSV|FEI!*D20*>kr+(wR?wxN7@wiTf3&H zf7_PB95hIrHEiDA;Fy*pdp$8})PSwCO8j?Ry90j~F2St}XJ{OFGJMv7)+cB{x;dbF zKEzCDJ0RP7Sc1m)aK8mSVDIKn($n?R$vckiyE&KID#3l0 za>V^^Thd>{Z8hXkRyH+5TXS2;&$bhJ+UWdno~SDZO$H}GNL`L_js;P!@;E2T!Q1Sj zm@@%tTRLxuAt2lamB&fI|9X^{0~d^N9#9V62A;dTLOq|Yc?#|vlhks4f8%$KTH*z` zbCmNt$F21rnAxH}XlyD)_M=pE&x5v0WtG)HGj@4wN&6A)TgKi_AFg3x@3ri?V*-(>_8T|WQAXh3bSeH5F+#`=jJ-`V zJjVtw!F%3g65(~XQS-8J%8VdN?GUDVh``q&>|Uule3_bkLsZOwupKJz)!N6nuQ31w zws2dMN{2t!ZQ*n{g}hk9KCv2Z>E&6x10EbuegjnF4IN!!R!a4gp&d!HS@Mx1$`x^a zv*EW3YXSArrIx{yT)FZDDvG~`d}rH`8Mxtwa%$p~BOLdIyVimL-z(7qMw7GSWg2h=>&`hB7CvnipD+aOwh80Gm^ zhjff*Cg(#HUug3D#n>QopVX`XwyaZ#;NHc#E*6P&rBZ^8CFuf5$XSNWr3`4_5MiQ`mKw$lO`tcIDd$Huq&V9%1-UwLLOM3Dn21%I~)p7BWXC`CNmS zJ);a^qzb~mH=)1H=+8&;bY#E5YkYG9M=%}KY{zMEg`#0 z$PY?vd=~TA9`k6!$_WxO%aQt%sRpJbSZ}rcrgf6{Hhe3Novv6eDv2FLr*c^{bL5zw z#~MyFbS@DGHT)v}TkHURGpIL%yla=e*rSkUp*3mFM&9fz%*_*=^WqZ}ClF^~B!M+1 zq&(>;8K;Jmln)H2Fn_&xc*W>-2XChZQz9JgrCM|4TsU@BFc|}>@qGPJE-#rlGSJe&ij>a zS(h#mmPE-j9(YQ&f40)Y#tT8M)?pUu_sFVvDVxite6tbpSCMSQa|;I#F1>rvqV)Ow zm#vf|mGx}Nm@#*aQy!M4D^GUnw1M6u+-D3T)AdMY3SU7$=b+O|O})mcy&?oz2#T^_*P-O{Tjl-nVqwPxqZy72u$!gGNVLp)&DLaHz z$(bpU*@#Hd>1r1{Y38Cu$%{sqWBM%;K z%HeK-A&EZF*Bu!dGr2?F!i6bax{fegZ4R;CsF6E&`u~V~5BR96?QMAWDN`~jQ!?qj z0)YStN$43$Lg)}7AT`p9A`m)KLQ5i`v_w!q(5R3rpn{NSP(-?LRRk0-Ub|Qju`6Wu ze9zivCI$6<|KI!j-rol#%sF$;u4}Ko*4ocnYdY)WT7O@M@CYVJp0e0JX)el&X<8OA zB?1^Eym0?gY@6=UEoV<+i5)xNb9dq9g3RIfFEBT%1O9}dxkph)knr50v@SH7bo>Jg zR5nYeqsICJDdd8EqDO9zo@KwxncgKavDu`>Gh$=o`1?!xCO2=M+;@rmO~8OoBU`nS ziumu2!0g@s%7}_`>w-gCr-snkX{NMY{swjVqCb>f9RFlWFrGPQ;kAY@h%p<6Kvp7NDx%lr9|jHj zYT%%*U4~~nhm%U-S-)j^0Q_+wh|L4}X{w0>JQkR|Fe`z@XU|GYYumO>dV0qGVLf~1 zPG7E!bhgOqo8a{I4JiyX`3%pUGS=C{$~WItHkN@$t0Nm?Ft%QB8xRNSPwd-e(|h&I z8MZGYJ-toaw68q%eoywp{ zbM*%JNswy~5H%erwWJ9dX0%+I2AIkj^{T;Ii;Y{9R;A`KSPU6HS|F?t&$NxM@~;W1&kc8xe3k`A># zA$T<#Q>wSQE=!u7#FG;a=a;jnZH;nrfu@?I*kZaW<(5_3gW#GJr`sQjRYn2a{OWB!}7oRCtL^Ja~{lAzcNFP3DKGoex3))Sd&a zXphj>V(rgmoRui?Krq4T!vpTR2T6kNp&ilelJu!uf!PL6z*#-Grt~TAT2UcQtEgZt z`K7y_fsPM9Z!6wAUQr?IDk}IT){K$2f!1!J9*bT8PJq7kg^Ur=M>5RO0me zQygZCI;Cl-le7dK84ajDb{zHLQg>QyE_VP{*-tmj>2JQJ7<32yk))#o{jaR!(X!0>1PU(ih-CD{sj>IU|I0O;$q zL}%#f-55?*J-<~-R%T4s=%k)ei;6P343ADt4G386<1=h@o2e-1uo?+lb{6o0-|79Ch2a0 z@9h_B+@S03#KHI>MRyRcP%@UItipHd(zQ##P@{ds1c7bzHc(@NMnP7M66a!Rj zz4S*(an;9QAH0-6`k-02oBdbXrx?jULq@V(Y$qPja|TkP1yv^{O-*qg7?#h!lP6Se z+19qr_QDZop28UafHqptMp`rAuvrKio|SG0mPU;ledy(v4~-sm=R_DlchDwnSAZf zL&dUOa_mRe`jb!i!~3`P@4t@9WQYW}9r7wt%Io}Il;qZ+oELR6xGVuv7R{NXm+Q8P z=Sa@p0Q)2?Q_Q=0Qg7?EB+`!rPz|$3wpF1kkrkEpTWMO`jCLJ{rKChhk8ZXkt=)kB zr5(C<>FLbw+9iK@OvHoD?r+nkSMCaDhYqUWeL-e3M6QHDhs_w$BBlSZ^mHE|`}C-Q zfV5UEf&+t%j^-_T4{y^J-b83W+9k(gOlTZsCN?V?5INAze9JCeC}XxeWv{*pq3mt` z+Hb!hol45bAA8=zKA_1R{}*Hf#L?5qk?L^BTi_pTFW8+?k@ObC#lqSI4*XL0`P@7<9?bkZdKJwN_fQXeFBI*H+>&%nW@ZVZ4@|mD;B0#_Oky;TUa|Zr)gWX zvC!>B^d2P2^Nhuf6L8sty)8p3FLl+FD(~FhQ;L1{4c84h+kFMvFix5OoGJFO%gSeR zihiCgUhMPBA^XnKE!RoRq1=?d^Q?C;X7V(^j{|#{v!cSgSW)IpSE_7t--CTIU8nn_ zzv$;-K2PrB-T+>Qb(jjg#Qy;!;s?F_rx7DU7??fEEnb4Ne1opX9ZtjQcDrUNH{FB8 zy?Neyb+6-I7rG}!*WWv&M!NG5bJZYa)Ze?Rj&rw0>||J)fdCcd-MOJYqzlxWEe7>p zb#x1L)V;1YcelmaqCskV=MU|kt5WUBXTp|jkkaa4e-Y1JR&(9SbWb-;t3$_JS;|lR zcl~161>&5hzyhbb+_xaqul4yGVb{Vyx=wxY8&2t%Uu(K-!)Vj;0973nl_Z;K=Y0lO z*379>mJM$iuNdY>rMF7$+H1rFeO~&|9$mV{gqbWczR1@Q7uU>@&<^drp?vCwIUH?E zukY(G7?YR8m}GkUT6YrndWd^5+C8+lR=L4@>h}nF0_&LfEYJ#;FR*AF89>8hb?DXp|LRPcu-6V)5e&xKQ$kq8#6t!$>19NRqj`J1z zHwbgYEb$pZgc9N_ewsP+C-qJ4UW}Oie|-+}ReWHUBhIzq#|Oo8yi8tM#WW&!FaKhmo_|; zB+8+EiojqVF&WRjSc-qH_vtqkhqjvG|3`I_jEv%3q*S6H@!cX`;C=^O54O`}&DN1Y zYI7IX#v7q>`4&$|N=V$yH6PDk(4KE9p19_daPkd*d2s%6O)x3E0{-+kFX58}k4&r6 z{n;A156M&y43C+*{ql5xoR9m-sljT}C27g{^SueJ45_d4op z>mIK0hCe}N#5Z^*?hUmF-k>Z!M)wZkxjZp$;Ol?F>VbP#F*2=5hm?}Myzb5o9tq6v z^BD8)-f`0Ixo?8kuk()6optPnd!Ot}`{^v_a3n6o{R~7d>wN}=a$L7`#WW&`zWy?owE0L&J2oHeX_b}bU2@#a6=@ZIgp_r zE^ytFrc_pn?{0sO@7&sVM5DLAS8eQs_>$e3;(p3qi!%nAyJQx8=S-pe>)0^^l=B0% zcWv%h+#6xb_k4eQ;bb**QtoiQdM~~Qjr{5AVv;*46bDCz=9xY8a66xW7J>OZNc zBicj^8Z6C_!Xtcq1N>8(Ub@|PZYUjv43MnJ0GceoUlX+TKb1lLM&59(!u~W*e;>-5 zUB541hs-d}a1pfnY#pdv%-1Piz@Ktg;@;ERJ*>aWkY7^ty=i7-ZHdNSuHaWHqyjaP zj0>1QS2R!KpSr8H`6Fup{Y7L~SOmmR+JcG&^qd2HU-JE(|4CMu) zyeqWtr~(`BB1;9o)B>f!PEiMi%H0QhelmChlr4{WJ1gC5gN7RBH46g70xAg(a=E)d zFx?zv@k_GVpoFHUk4%b*itRpQx?f<^d#Zc#UX#C1LSlYNpWgm{k(2kB{pzpKhdiZ> zzo0+w=___l%3bcttEjkGQK3dxNIhTy0qxU>(jQBlevR%3oXT*>0fZs(vu5rc?&HMw z;aU(_6y7@*{F#+g^`rtFuc?W-|H66*#ia*8ZcYG7M|G7 zZYe2jF{52_03#lz$($cRMxsT$0f^Rtx-YSoTeybsuiPYeu7=D#4&ODci(H!s1V)H3 zS_7^HS}meR{o2KB0IC>>s!~$AIa{`%F>J>9o8S=J@YN~nJ(50^K%SA$lcuLGV+ z(Ed#Qba{i}vUblnNYvdzjg+pywh<4yq_aF>1oqChP-ba6t)~fPL&U(A2@^AN)u)tM zGtZ37?l3~!xvxVn#d`;K2(!&6p-nF_^Ks&$WnXdOZHIz(%s@N#X>G%N&gaeK&6rP; z{W8Qv#%I;d*B8+YE?vdn6f*=pZkIBLJt^c=t5c8sr;<*AGzq%}L`ph;*wyW|8F=I; zPGLppd0-Eo1b#)<;dx0`bW+3fiE_N1J&70cxIg6_fPDTuA z)0VKXz;Yj7|9D;y8z1BDCHG?|cNz{DpEQm&%A=j?SYv=u zn$<=;51Lh{Krcv^p5Y&2?dYW!#QpzBd2GL&i*_!gYxi|L2Y(Ck+#I0~9MaM5K;Hp9 zs*m=3w_JR8SoekJyYIn-mUzBfB)+SzfA1&Y|C#5zWuorano)V5qCDX%gEq|&@4U&X zJmvid->IH=rigb=XVSQWZ%NC+Ta%?{-Km7Bl->`Z`=Wn1>+$AQ0)1=o8g+>%5g0$u zdAh0#g`K~g73&O=62YKi*VUb;I4hV0foQRwB_}UL)4qKfRe8(BCqxr<`gYfqE5(St zWYo(BBwwQ!VY8(08%~?fie$jZDxg<&NK#>yWkp3iBFhc@LMWnpO)OT0sa>i?W{ZqF zHB!efr4Fk9oyYf3FfuV0)JDQwdGi2`!dw7LhHD5L=p()-3?#1cJgC=$al$7XPWIBA z5lXpzW1L*B+ZSgp4_g-(Z(#wULFvdr6=jJ-R0QOprU;beSS$XuVE_majt+PWTG3V@ z50e3{fSyTkb&B=IPD;mJUD>#6#VcSTyH>n>dGR%hzELZJTGSprS}V`2lGapK@-G2m zudb|QVJy57mm@i{?p}QF;zfkw828>qZ~FyKS>#Xg^amIR^anGEIr7XQM!K`p++ANT z6(d-Tg5wfxppn^A8)&^18l!4e6j^VTbXH&rn+$Y1Y#TUI`0}zC;)^_q23V!Fuhps7 z#Q<>fK! za-G)hJ_vAEtW(NmKMagPGy}<|i3lkdpEf#XtEwtKM27eTN>rPYq42ykfuEw8>_zFr zx~}YF9xK1#YR^7~N2N4VvQ|~Oe#TgN<6NUHK!D&H0=05ov`uSk5$N$MUCZ4>+d-us z`s^gyPT&6rZI48B#9)hGdAQ{8NAsf{5kZoFM0kKP!VpD=7M&@dEA;{qzC=*!*vw?G zSs5lTpi%*hwPNE7g~3V!Vpbn49cS!HEs`CqnDOwrhi9y~tX9`vVQkF{7taIXvkfux zzN%d3FaKB<;J=ROk?w3ge=+YSjpqQg>238oB5|ZU!_DPU8dlZ@I?Ru#iUl}*T5VRdT+_Td)Law0E}%B3Bvizq#Uev|1=SfCY1L8WSF6=R5ny%JNPIF_I^Vc) z!zli1i^yN*Rkk(OQdZ`-+@g+l+I!o3+j>Xzi5%e9Pd9+|_V0_J>rQJ&{|>f}*7lL@ zt=WE^bzK=kgP2qNQdkRJbN}X6yyq7h5aJ*17tX?Tp;n~Ha;hm&DbdnsMpBU`0D^Cl zh(Ri(HBLYL(X2(cNWa_ly9kS@X~=ZY{ruz`O;;)T;ctVT6CYJ#jae(R*8krptl zOLZMCQ5e8@t0fkJcMS@h-;?B^tQf0B%}}iE3^7)=u!dE!7bN)rfO8U$xODG>Cs_<{ z!=``B@8oc+UPg}kW&GxZ5&T!4h*&GV_cQDaVL?@TmV1ryGt^F|i$Ob=DTQ?Y=rmYl zgHiDf0IsL*5=DGK1kcy?M->Cs*B5DRRHuzujRwgoE3&^I!_0zwv3Vk(25q4?7)9el zlL^uVgAPNGnlW$kPSyOwmSfxIo&*c)Cr`LT!d;czbLmcPoCH1?ICqL;is%`7wVBd7 zC!(3nXRuANg~ZxyIjKa5VBs$<^I@a0K@!vygQiy#r3jr=6P8%xzb+NThc=(5@0|Le z$a_@1YVfxJA<%~4e~v&E^Y4wOZ6$pG3;_^EubSXF?*UJ{f#9gj*d#bAtNCaF4{016 zRkeDeqw??g?-U)C*|q4X%#zES-4z{`>BJgV9>Td(7iXOB8gr?o##o&mzBeR2c}=s@ z_?njM(%XfalLL)Pw6RT2y67*K9%caD!tO=ACn<)Id)jGK1NcJ|bn7D>2*F>(LjZ$@ zmd@7B?A&?wtP}mJ#@#n)aIg6}xjlQ#d16ah-hd%P9~(V%Xs;1Nh7P(}T>P*!Dx{lp z^!kAVLPDO4^z%zib>_Bexi!80@Dc6X!;}4A5&r%oNAA0S6Vc3co-b3J&PYUtHv9P7 zqLt8)2wPwj8hYsxGTs6yXBmvBfeE>!QMfOF|xtLT4xn3dOm^tdIdP zzFkI;raHyP$QII~9guRQbE^gp=`-l*oEFH|+|l(ElRDu*Ws z#wTX9Y$2ty8|>bi8oq@m^QnTaJ@L+P%GlN!q%ZNeRr}UTN6o>xGP3EI{EWW2K^SN3 z%2894iFOR3z#M(3r zn_bdWJ(&U))DttfnEaw^Wk60rdBr`wO%a&|o3{;i+F6%dW%zUJ$I`O0Qt1@Gylnf9 zhuK*cF=6NSrMyl$bm=|*FkgG=^5sixE}Qora1vtgm;qkkrwex)0`$o1p6d_sTd)Gv zuU0KFVx)jwX>>p=v+;2W_uu>Aq5OOXm&lZjsW=@TcS$-&bn-gnk<}>AjF>$pKfPjN zMl(egM6e*OOj%cJFjIcQHqIcU)dWF^#3G|=QjkVYvYJea!J^!-s5eZV5js@8VKLso znJ!Bw)C;VpufN7V|AhBqFt>~=dks0yTC;cg2v@Guy_jdCe#krU_j8~>xkwDf%&I>m zRZ+9vr^Ni2q_!rJ)fpmNnNF`*iDy_LyW$GT$MC+W(sbj73Kc&1K~vy z&NvXP@J;qzpVre0=YFP6y!`|PD^$`>E!_z;BKG6`;ICi8CtRM4`Y6`2 z!myT;!2biVmYXSYkr6SrkVIQxGOcHhWWRNR~h7?rk zA6B!~l9&K~OV+a(YoO{#u-l{$n=I>%tUv$y+B>qtwN|pYPDzLhbl2);FSC}z6PR)` zA1nN$*G*MHyq5onu@!pmOd_&!S8^=-2PS{mZ}BrX`m$Jaip6jr+i z+9)Ihk5%Cxd zuPO5;o+jR)ELP8tuesX}(*9X97C?B*x zJBv$ubA2? zz!-()pWCX%^6mWK#BqW@mpF6YnfL0X(wvVf_W#2Thkmo2pYbqOo4Ah zb4V(dlpKRCz%Ci1f||wK!g46>2b5V_@FcY&SzC=cs=9@oTw)Je=Q!E|vUb zhZP1360?)BSwVu;6Y37lvr1rCB%qK)4*gN?(rrv(0b@gRGdC<=ttjhPpFVPW4K#x( zmEAiI!~K4<LXy}O1=Bw65_?t^Yb?d^9M%2$q z=Qb({k5JXgD6VPj;tJZZHD1cOK7HjYL;E~*WMz+`udJMR?MP_iee-{o%3Mp2^y}^~ zU#@HE-+jmdso1rkZpQd{G6qtcO5C66o1sl%@DU5N+3XQH7MsIt^flNd)uu=}h{1mi z_B9CRH?Ti|W=v+AQtNLj0fPpqAjwr5HOAV`o-R40^fWmgq+x9*r`sI1!~|Kw(bs)X zoO+af{I*i1y#3!tPdy>=vHZul=8;nVcg)F;-QokKFxTg>H66G`*WbDJLCtBwFVntD zcE}}qpiU3*S-!6Y)d#i%Q zc?GoQXQI9H&|Wk7b}_72I!qv?LIp05G$lGglF6`xHrsoWcEP2tS$TQcTHV8Y-Ny_gf5vD}e)*fUe2ll39$ZeM9VK%*qMHzhq zV-jqZ9E3{65`>iutPxw3Eh?sj1y(l;iY_tvu5&zQK8g^j$kc-ez+UQzdwT_V4^PAv zm2R~QQo#hsR!jjAhE#WYby=Cl5KGsbJ~FHS5XK7n&pI-zpWux8Kt6sOGIL26y-hD)o)jNSDTby`S!cddDf!L_CJR)Bj2=< z%D(vc}) zk8~KBzx20QdyBhnCSBONk7fD9+}b|=e*XJI_ipStWYt4&?VWP}Cta*@H`mR)pP3rn zbbT_Z|A<|?XtEJ6nh%F<^cFC$p=crI0gZ&HqgmG_A@|TPc~y1YuA|vQ(+{e>d9`L~2TBu`cC9WgSIc7Tt3=(NTs-8-uT?9o`>4yH zmx??&F*{VfHoc5lf4s$PWz*!3uOmA2*JnY?{l#x;}KI{ zV^ba>73~ng0?Dl4$?JrLb+fc^Z`<+d3HdD-bnMHz@z>Xm+t*=IYTF5IhB@<<6}ujp zV6#<5M0OqgAV2%4D|^#3MUJ4#=-9qvX>1R=>y%3v+hAPCOa`q2yar;nGdmcjfxL^P z%o(!px5?q%SAI2kto?D9{&~-5rG$@UOI;-rF)Z<~ObEBHq`aVtk>mvvzV)a(ocNMR>$_L@@U5n3!f;7Gi%Pu&igR1PckK z%`+H=Tw*N-bwc~Gw}+JU=+$k_oZQ^gz4B%+>7Cc3WXPYRJ55-;@V!kFCnP6N=sCIa z!or8|TQ`pd9{NwuF48B*nPdBkT>ko#NBGtG4@{kM>c<~XO_}<@be4YPN!BfQ8FJK| zv5IA+YgePg->FCW|{WOZ!LN#`+0HkWvc zB(W))tn==wUv@6;ooKn=oRUrRQ-rt{dEjS}xWJHTX%Vzj8HB&bS`bU$o|!1!I8?ZL z#<(|6j2nOTYR@TCs@%HmPrdROYo_+Gt*YTS|NPh1t=pJcy75P`v|*Jq`|?Mu7t3VE z%R~qw9;rfp@nKp$Bq_vbNf(4$yvIN(t$lpZ>@oMSe%L8GzPRDT)nz-Exn!6B`1S7` zEuM4zEvfCFzmc!|Q+xin0apT)dzSZAKLZV544LcCqxtQOmW^M_hZQ~ zzSg-%)tf)o^uBM+lB-)wTV^gTy6{%fED-}nS$yy~cb(t;((=tY8NRE7(uOU1V9K&% zJ1W*7APh%%O4s9v2!lRJx>kq_wF%hMU|oOIE~=p|NgN-6#56rCQAlpFSodf~vJi{t z3$%-xiM>txD`Kypykg)iesL)=WdM7aR{mUNYzpo$P zH>2C&Aths13AI zkFPv5CO+g=%Yvs_2(#}-GRfb0$o9*u`PVmIV^6am|FdfQ`iY}AWoGZ5bbQ0cA3rz@ z>R$cwK|wPUpu0>1&BS1IL5P2;S46!h=@i*oQQA5^l8x$3IKC$=O zn}{m=@B!X><6hTE{=+tG$oC$fzU0As`p#{cR-C{6>*JN%Px4P**&ybV&NUCKKVW7d zfhWeAz)~=22$Q7EOAvx3ct1Hbsxp{JG>47`a4aU3eJIVq?ia|G^K167xa`oNoY)$!3Ypl_6o_5gqN0%t))_ zH`WSN)Uo%S>AgFKsyiW0++>xkON4)@Y*>#o^z^6<=%o6LsB}d!t~bb`{t*yvCL7hz zojXHSAwyA&BKVg@65fF&U>S&Eg?#CSCy2<%r0v@*+Ufyy91u z#{bR#crP;$EomS?z5{PuB{ffWBU_q5c}`N zSABevUraFS>$DWxZ0d+p;{z=H-G&}zj@!KJ|SeDf6e;|5m@;J`!?-ILXZrv?*Ll&o-n42RQ1G14i zXqVC=n8E0&1$wbTCdE-_f+xDmE7I`BHcyqsuwQrt_tDF(yb)az&p#)upIR^%KD?PYYxg4kY^tpVb*fe8&DHU_k; z%5^!$Ma8VTcs>gnSIqN@3q#oz0@-*|+^~f>U~xZQS-Fip|H{(J%7w2>%QcMv3sEGE zL6w*fYSRbkKlrbZoggzCU?db5685nDz6ATe?Lv?G(o+N5V(BW+_R9a-ML z&%i0u`7gpm={s>ovt)U{pHJBMQF}M+9W_2I^f_D5_U%%$?c0NlzM{SpSPLmyeRje7 zz~8Y9V&huV@dYtD3h*s>j6r`Qx!H_~%va=k{AK!-fqnWfr^;O;rDv$}Y2y>+{ZIQE zQHARRRAGBAw7zB^k9@A-Vs;68im-=^@jfQ5X}psWLsd^XRxlQj=LzSdLrd+kfL?*7 zAyFcbGz`g0a0bxoBwzLxUv>iVX=2&Ozz0S1P7Lj-$!iI zg}N^Y&mn^yE4vm`l8_E`@-#7p0TCb!mglkI+G)&o;0YgFI9$64HyI}zD5rK*bO&YykL zQzzlUl4M}B(3aK8eyY>kN9dj%oiPdJ@%s|Pc8BhdDtBy5H10O-SIYg?B__p(8smV{ zNQAjE4QAx?-otHi!cB+USb+76*{i6El^|R-X;C6}OrD{bLI}+%nlx?xyj6VPoA^T^ zhUQP1R7A0aN+*X(FG;8QPn&nNZjInU2?=k%!zQySZ@-fe-|O<&)~&bCKUGEJT7tEK z7?Pkz?7Ujv?#8}}>m=w_6qi?^dw}cF`52fN*Ml5ko_AUa+R8*s+142QAhE(@9e_To zSa&w$?4X=NA{{g3Xr|a6SbPfbzN^OZjhA}Nl^1-gC1vLQq;HX|`IAp}4;rYZT;?IX z%GLh4)IBUw%3$GIist&9%|y>wM~3sL(?&B6aGMa1X=m_M*tkAF*BV5yU3AV<7t8e4 zL})lIgzaByzkG!9zEoWx^}jtXqmTI8{ZJx+FFoV9q6z*)j(sY8}tEnY7=4&smTP{K|uigVb{WefsjCP_r)7ma6(i z1S=u1>QR}y-t17!5W zfPQ2+10;xU_6SR`9N`xj5sXt$g3SQ9CqPENa=BlzE$C=~F1S1paKtp~Tbo3JLlT*K zsT5O7B*f0(R4;s02;Z|R4a9l&?44t0tCZqP+{$0jD-o;rcY??d|>x*5)(?oyzo*x%?|uCwja`}o5JI>H=?qi+~Q38mY)v*+}vvp`8E zD8NhuLkiJRu`<~T#W%oe^YgVJqo_3iXD*bUu`#N&@#lMS;vz5tLQ%pkq8Hnn>Hb3Ph&~1AlAM9&a(%Ih zmFw1-tcp*B!5pDyBHfcX`2!N0)>RPQ2rt75!@iwzNiZ=_oqxgh z*5jqorY6{1&p6XMH|V0B76r&!Ne^TQ@+?Le6eHQ(1$c)r95fn4w`!+zh|(?a#3|qa zm+Qx%0ki9=r(PDh8%K+JJ$wgezTKSuz&WeyELb~stKN@JehEN=T(_uIpvnV~5R%B! zs{1>#yf+aP+$dNQNKtw;D0(uI^sZ~`Z*0Y5ud*UG_v*{(iHoZG2HB=5)9bd#_oLk; zqk_(W-xWBbWW)xGMzZV3u<+t!ld(L}mfYOp7aD8Rg-0Y>Bb3k}OXFh*oVK+lsIKJ~ z0oe88+=9~~?ua9DQY{4n5?-7TK*{=SaKuZ;E5@x@F%FAk-16o4@0XoNkM8*O+%G$7 zYj^x|PI<&JtmxFqqG1mFfASRmud@WL*~J1_!0wWuC!Y*nvz!0Of7-n!c!!{|E@;0t zzu*KkpWs&t`h&A3r$a9ln~xfS^!L+6nDh}?G7{mXF{v8X7;q>Ybl3BDcuc9C?mR;L z{j8V0gZ+qd4?uT5h;l8uc&AM&_uWS*W}CwNBM8E56^xL;RY2BY*1+;$#1V&|LCET! zZk500W3>&8EqF^hjjfAi@vBenlqL}FU!y|<_D8MVK9aszXDnC!6e&XXi7?YL7wx7~ zPTDHOxh5E^cV9|ZCP}7qe{ML3-&M3J(dMLlq>YDBLb(AzJcQ|eq~d_1zBD3MU4$P> z_6&-J1_gzChlR%FM8m*PMHn1I2dxHFqK%L8(VckIrj3zAF)#EXsLL071yJ)+xr`wy zSNGY=bs!^?4Zap~h~+#9X9DW&+3_$~&{aJf9mx_9BS}hQzw$1KvNk}IT7)FQYgtbr zwN(8@h|u_rK9~5AuBCDi5|v)=jj{D}>cbTlp>tTS)nV|O?9C2cg43>+`|UFq>&qR% zkR4Uu2(uz!d!9BT9ckk|8BE^0B{$xY>s~tNZK&((Mq9GhOw7ZB&`siDI~DRPE0^{q zns@u|Hlsd1nMXQR4O^Yc4 z^->uCblOXylS|z~hMh8h9s*>N49oYenm2zM$*@dUS}dKeIyHYg1lY^H;uGF^n{VaY z-g!GAA@4m1usb$m+$7z5$c1}eoL?c!i8ESP9=I{tSRS!1Ikr4$UqW$wGvCkd}KH%Kp<&^D%*MiO0tTpksB<#f$HG98Jz3?voHQ(R{QY96>n+ zdb9)ik^||$fi1^kE)U;lvP3C9ff0s~P&rZn(8S6Glcxp~$Hm5PmVNxK5Cbd#aR7~B zA;`wPh!qIHD;NeEjR+X<6YI(-7KRAbCrL|I))Fq zD`$vquWyohZ%{4Un`E_xHPhQ-b!KCbNM28Df&@z;8egIvnAn1_(lepmh>wZDj?wXr zK?`b#gk`gtzPNjKcFt0M`=_~GI(FRLD;}k@t#*^HbQ1LLS{Dl1seY;QPvFt& zKD5oDd%)=+dASzy@?O{igt%;MDlTI=6WHqiqPX057L!i!_t}t>{POH0v-#zdYzTk< z1e0bRk#@7!UB9~iC7E2mi=UyAnWFcg8|a4@@7@-EVzEhUl1t-iT2!Zn>a~jZ@fWHc2!V<6Z;GYqn4F2k*GS~A@4}E#0DM4R?*;0%E?bum5 z{?Nmm-yAe_$cSD;hmL-1=#T+$d>x&ylq;N#T-X*WBTLN(I zGVI4h6QVxK6DGAqe#P_9d54NIrE}ulXorvRGb7-%kFN^%NFzfmZnNO;C%g&iHAgcG zz|2MhHA_|%aB9uXOcC%k74DApKx*KqYZ~W>FXWMp)5Bv7Qc3?o-I{K&S6_=@P^25= z`WOvn<3H#IVr_VIgVckaXhmRkjEUS9zU*!G+$D7U^cud2*S)RL4En9+p$=bNf9wW6 zNUv^0Crx@^|6KT__@I-1=;Sp`;y-~@uE8RyI^;d8(Z?i{D+&PP%!*{g*b=_Ce2-s7 z%lG#-F)qG=C{$fpHd9{WZ&mYiF9ES`lWw9ZFSwGWt964s^IeK|n03j{K+|4HA&9zP zu2BIhorYS#*C8c&W*e|)3}ihMc%xbx259HrYSNZYwmub1lxeR_d=LH@<=^A2 zufhI}e&N7I$rSY^I{jqBUR^Ev0}|FFlHB<^GRIL8U-CN8Dx;i-#Mo4&E${v^?=Bdq zd{~q%V(u%2sB07^PsB>se<9@9cDf$Gk;ixNtx1lkj(x1BQ>kg~SZ6ufGbbm*mSQ!= z8q>P~Mi-jXlU9ufGKHb^;1q$8LK~RpG{(EanK-`&8?ahzw9-BBMf&LVf=IRs*%a(R zpnxHtw(Hqr_3E6SJ#$vC?$J{UYt_Hs#Itkeetm92|9+`8sr~y+c&i8rEY3~p*T1C{ z(WB?;H90vCuUXx*ht&GY0}nhfS4n9}kdn$LS$rtH|k zzvVw{e*$-0XXUHfE0?Z4@PHT}l5G}>@fnHn0T02R;}kR{^qyMMd-g)_F`D2bC?h5M z|61=+O6xiZx&l?zb&yZfE+WdUKs`E?Yt_X$tJ> zG~{*+p~p2|(|hvx-ffdcRkzES!kSl0rm+Rp-@Z4uQz!P?on2bHp)(MD34INEPp!_l zSM|%4jIxgrQJeKzyZ=$|k*~77)wfHk*&ghJr|;|%tzV~&hyEv&>(zT|h2FCldXLc$ zC3^Tfjr zg?aQITGJRaAsIJPbuH@V>wcDRVSJ(cMCOK)SAbXdA)b(faUr`T={|e? z%(eQx!J%lVP4$KEj4(-h)J*se{zdokwoxu_+{Ws^X`npA+dj;P=d27etqwRY2Vob2 zC^kJz7ubCrga*hY-*a~8*&Vwd|7uj6FK@>#`RyFKV8_nQN11s`$zxlT#ktQH9O^dg z(O<@-7gXgvzXM1q>ke}AlXPz&zJLYiQ2x-cNLQ(`S0@_b36&VVHzBSzHYvw!3sP)R z0nzcsxZFgsmyxbQ(}7-MI>d~K#ZAXnLdw(*!UbwhNC=vyqWEtqC>UBmNdE%YEc?u| zTZEt^FQ{dvE!EZX$3=6_o}E(!EZv;B{P=4C#%mC|9XmGu;rbm+yPJ>^F%JQl2eRY$ z#I7F#_H6Ur8{=b(&ou`djS)6Eu90e@QH)Sc0{s1C7=!GvQrc~IsU|pQB92NR7E(?i zJwiLtP$r!idwJT->Gxk{t7`V%*QrzXQ*Z9iXqUl0I5j`p>CB#gO7aU|H}$E(gYN8N zR}&Lv@lRRWn9NLewnd8}_oSqF_m^e*>A*Gj7@g^0j_5Hcm(UpZ95}2>7j=n zA6!tQDoZwRUc!e>OiPH072QP?a#&_95-%+syW8PJwN zXk=sh>*$P?*2tx*eT@xHk`AA}=2z7kUA1Ffq>rx&(QEQTbKpDsMOvNEzoE$fa?`@` z^XttvIGJ#WhSndc!p*>YjwDrjDVLq+Ej^T5%YWXo=CSg-D0kluKs-RXXfNynlur!% zT!9!%tWUO3oN4x>Yxgf87APEu@$s`**VEiMgSqRBNaRteKX*pfN2~?7s$qo_YO?-} zNYf;+?x1-?OKLbIl6Ug0^TzP=Btd=fFAt;HA&tTUfBI>#Ag>hVm8)o3^B3Ta=Ve8- z{=mm;1z!Q~w^7-u&|5U|h1NXPt^U!qd$B0lRq6Vux>|~__SDMyjcw72nA=Yj5*}-% z6ZA7rZA5IKDXbf!DMAFd2Y*X(g zv-5hL&dr^(rduyS5pR!eKVk9WcQq*D#7*xlTs)!E=s$s3WFs1&hx1vofF7>c&ac15 zC%vRW568TCh;2Q~{GVK=ffX;HpB^6!WQMvf`W=foz}c2XBDXZmeMj0;gq?-v9!k20 z#DGB|yJ5Pcu~Bbf!%k6BQhk8k+pvwu@A7jRWy$Y8O30K)U5h=NofucLM}@;KLRb@U zIh0JcB-%(C9p4hjqRAPr%yyhRcQID+($flp=WOPPJj56Ic<7%$KZTgj)f^1(ce zG)i_I<=~9U6e!w5sAV$?7SY5&?4m*N`Ju+?*PvalJFY))EIgKV)>?K=Yp2#e<~(Nu z1i6jQK7s{02hGLO0?HV04Hip~H$of(gd8icJ-2znipxhARPn*8jSs4vQ+s)N;UBE4 zYo&Cr>pAJ(h^3YMOE&J}nzqunE_>RFi-_YHwR_Py3ET?xOvn0wb1XiEp&zk!0R*(h zg8?UNl{&OajUkY;_;tl{S5L#E`6dWZ%V-ql zBQMC`b~if2Go9JIf_Nun49cU~7jxOb2|N&C+#nDHDS2K=10Tt9E3D`ES{M#7)n5F! zS6Y%@?L4xupx5Lzq5Q(^r?Y#FPhHh}!pNc7qeecr|8V)hfrIn6-t*e*q6ri4{c6pc zUcFXs9yGXU>#2f%Lt8Y937I?QUA;c(x#mWn9)+7X|tc$FSrWF^?np9E!)H>#c+AlK6KWAp3uVNlI8g z1+LE9d?8(HOtE1o%#32E%TnKAoihKyW;OGnhi~o~(5Y`sLa2S*v~~HZqdRpPzKU^P zSk|s%LHgvbU9~(L+uF7o+3#=7Ss@{t3U?n?rHJ^b;C|yn!&P(G+Bm(b{ot+ZJM~O( zC__EjD`@|u_4glOCM4;U*jGIMhq(R<$#>?tY@Oax2?^bWvsH;@TN! zq^tEO3Gld~fK?P{0k(MXc(PXm*})Qny|E8vfvE$tP?PQCRxK16ao))~Fhj*7uqAgvTJg}iMML@b`z996nOv2-0>=ejT|v0tY~PM? z5HYdzI7_A&t+8PCCOSf)JVjn$vE2Gg*Qxi|Ro1?!aKM)6uCYCXLVL&c8iF(WV7UuR z%kSYMAi+I8LUAaMY{1dzlY_N)s=-FZ9%SkJg3k~{)38%CjlM4gBE+x*NeFNQ2_f!< zd;W<-4y#SEQ|yxtZJj=*HAY`}pWAC~P@jGwHSsXyd8-{xxUl;vH;%wz5<_CK(j~$s zIm3Jd0!#r$v&BdDk$jnt&gd{%jW%PT!S1w#T0(WvL1ETNTZAJrFw*YyO<~O~&2`Nj zNr6drr!7689ZR#M>oOggftmI!Ydf1Wq>t3c(nr^ygNFsmNwB%`#0l)iEh>l6|V}LDPfA z2ZNoqhoog}k!6u%k#4^AA=})*dG;5EFvJMbJ3<}Fj!Z`%$4JLC$1;Zz&n$*2G%!_~S)`fp@n~!>vjgb>B5A;Huvz~JKK>8a(b0Ld8J=t(SJ{g2=jOf~l z__6=pJR=fz$$oZoP1%mJzn^f!bp8i3GX6U={jue5W*=)#%sqS)DgX6x=xUO@Nvu84 zIpu=2NbC#mHRV~w^_OTT_DaZJtw4j#$+no-z*Vtj8uVm7hf7VprisDH$|P z%8fRQ=X!V5MQP4^RgM6<_P1N@Rqx@X@$|)i*{z;CqTe(wyRlZ11TSvfZ+`~Yucp23 z3Ng^zX^|NB?q1V26WgfQ^6XZ-^9l;Gt6CX+Y%SZhwD}lXJ>9EdXx`J>ji7Kp)7ez+ zUQkvxhpDLslV5mHJGyB|Wzu}y!$*g4g;Gsn^u!r}UC zF57Bd;)xZ=-Q`r`ww3~RaSpZ{1|hr8je`vOF{&KnaW z2AmXv3}h$y_J01%t8a>om)}pBbRA$+eyeorEjIn^sdv~tl-sfw5U67)k0pO^#TM5K z=p$?&@M8o{opK}6iMz;TiQU5+Zle>a5zAUukLJzR1S6(xoboyULq8WBA30*kLnGb6|8N~c zfaBjQma-W|Czl&WL=J|{(C@Azt zlB`V|b~c>2)^*s1G{3Jkp7p@>-}kR{M@CB?{Ojg?dSj5)T(8NHJe;-w?4EKWqV^C`H|$G z2%>`)C(RsE`CXGD>&c94(912>&3JgAaGTha%fdH5SU&82ieyxyr9)osyY;!z z&lH_RpvZ6um%QFc8X zVV&t!JeV&QhRYIG80+tY8mjM19=*K7mH?K0qUX`~EA^m}&x!u#P-}up>;@ z3u6lWI%0cJ&R?>Z(+`YDy;e|6VkzGB(YY1!*X;W$ezdCYxZD-*w1*%`b`rcpjH2PS zS5~YbU<#sj6|!Hd*zqdhq6_Gw{ZR*g$HlL$vh0{j8FNbC$ z(_A*-Sl8gnLH&n5Zbn;RrS_If;@(}>evl-aT}^Gf%?!Euu=2n0JgodlZP&2tq~2HY zH+l{JlK`{PqB_k#0Sm>4!}}+59i~YYmxQ zMR@YNA=m`Nc46qTuVMYaf%g9|%U6fqUmg1wz={TC*+%f2yD=+-TXFqLI`4Kqm+Tcd zLs`@T5x8Yxy21U`e6D;(d5G@+o9+wsK+IDCVW^3hdHRd)0^bqKlsERC%yFf|thSRW zu5hhiZ@b#U$)Ze}@5vhZrVLI-9Kb}#UNGtkl4d~4V|IFTT<<)&IMg2kJ z>cy5&S#W>y6qk|Z5GZ;na-y@Q#yOEK{|*Vtr{7|$9{#SY)|U2Hr4=mS^@|6G3*PB% zlgIu~*>$uw!Ly5a%SK-fOj>zYA68M4}mYCqY8~I07xJ+G`pa^3%W4c&}Z-)vBo_$$2v4a8CNK(AU4br=d+ypBy9~uIobp2(3QtJ@6{y9MtFKDX8!7xs_Hw{CLR6tSP$^ zP<_{S@)>Hvu|&JDLC2z9(GC5U>;xVI^ELjLwwbB*E*8;BgZgXEsO7A`?DWx^cer?H;+t;q_D9Rok z@@x=0=EL5-$i@lpwYaWFvf#b81IokK&sL@;WG}n2Ag5PO?m`Zm0QxY?osT$Yi$SZ| z=mVs0Y{{C^Z_r}KdJL%sQvcASIP?hm2Dtz<^vGi*NSBAj1{Jhv-ZCWo(e(ZUR<0V* zzbv_Z-oz1IbMwC|%jnEq50^bw!Sq815AN4vMDL*o$B!R6aPW!M z$DbHBoDCoL%*&6rjA|FS)ApF2g5)yWjvZE8{MOJQ`>fd)a1f8ClWxoBl75AA;YF;K zjyP;r&CUV73*CtB>mC*N#}KW;$FV^91~i8=Jn#A-zeef(vuEFO-Bf;X-4qO$To>ti zor>oP`*ip73#zLL*#v--SW5C?dLHMxb>Khsan$j?2k%6AE=2NNuz_^xBtjd*dV~wbHSxRx{6KuRMhC1F4T_)!%vP5$Z4AC%+3iiPFYL#4QyK zQQn$)GLVnr_kJijcx%n~gvV(6(_+_ZIZ~>oyudCTLs1;P0>Uxc2hSX8s2>EE7W0VqAHX;~gnD6{_0kEfVGW)i%0UoJBi|2? z_|eD#1muHqDliVf7QxEgxE$|6Fj}SP(2mAnDvdQaLR5)z4uG!6PX)TZ$Wx-V1S&r5 z3qoLm6XS|bnlFlN!KML!>Pm@my+*{w)+J*9TXcv`7$=I|q$bq>5>Baus zb)dTXz%HXedZkE}$4?NxOER4};lX>gY0@^FV=|AlS?}e^773=Ud3chaXk+hANY=E5 z2|GRk=k0nr?EyauguN;dHj`LrraG@*fjt(XAt=VGULocq>+1n&iR6Y3A7A!TTtzK> z>wCQXD!Vfi_6^(Gx|t91KR5BGPS*NV&4ZIvcjlD$g^XLl^OoNyKk)ys_8#z26JmzTK~S*!;F=s9v{3t=DlIVM~xq;{=Q|c)Kh%*g-yr2M7htP zeI4UBghsu)V266^@t{-hB_$nb5MW`-hLvpbh9d{IaXR^_1wBGh%KZum2{p@naT=qjs{Z|F(+YyOSpb6nfsCV8#?nC z;s;o(7^J>6VZhVS+lm#uh?TS!KK<0?XpYV0o)_ltm#x3e5 zyOv^GX@&btRn5<$QzBzFuAq&k`q@{^ zZTJzY;%Kz9*5plS!H**9r>n`I;5dm`b(|XKS2e#v6Ud2%z*nFd4sngweVyv0*c{st z!#m_k_?8DTYvDM5xCnp03bMz#4yJ5l;>XO$J0pZ{Ne4u6z5 zq-wK$jr!Y6usTg8)CGHx(-U<$hwN0xXh|O<Z{tk1T zXr`Nn5F11#Wr8rl zMa+(ayyfST48auN)ax_M@E(BVQlK^<@toHMIT1y5Q2qkB9Jw0&j<}gU6=TCx*En+< zPr>Z%DI>Ko$#1Pb#IjLMJ_cb-A3+E?;@3FF9nk*sVkX3-Hy#p`+PGItT;nz|LSye3 zw`^($Hj%M2KU@ETqaNb~9y9j_|Bm$t-I>JCAMfDu3ac`~m@1_TjGCslX&-lSAtlh`- zBdPk3-a?zza&%D*IT~mbgKElA6YS41!UGHhm!o)BKM#&REs~3PTS>f5?XDKyRtsvY zpWfDX`xzOrLBM?mhofTr1MZ+6>Z7%MqA?!rOcMTJE%Bz6mqYf;^OZk%`BFQs0jB6S z2Rx_gB0AGu6CQmfe3x<^qQPVDh|?}gLa&JzaHA#hf)rfGm3SdFxK|xhaBv+5FYtYJ ziffbxYrHT;cnUf$xD7!A7f0O&2{QoS^?&G_k$=~po1yL;3+z9i!to1 z)BSCpQv*Duj3zv!QB*FBVc*PDnRH+s5rp%~5nxEEMJgqkW6vr}Ve2gRI-3K*n!bUe~ARc|P9pS9$efqO^2~XIS zX~5G%hy$L4p`HxV>I=(Fi}TRXO_UtxNT3~{E6FI9e&pEq8d7+q+kj9Huf#DqIA(2DG!LnN^cElKaytIt;CG%c%` z^8E9W#8aS=1lv0qnEc;_SLu;h)no#p_GD$h`pjsmRegFp((+U=R~Q^SU> zoL_@h&C-VgzrCPUN8E=4DfbWjFow?2Q`~Fu5BwzGe~XbSOzqIR)o7h)?@b)Wn&mw^ z6smUTUY!TF?@&#-f{_?UZW|~mpj~}#BmG}ck4z7F%KQI=T<^cn-dy}|6dJl(eZ<|T zL>Jge3qcpOt;>R^+kXaiq>CrY%KnWUbJIF#Yx0iIKHylZR+nxhNnuZeXOK99_P_WA zFFcx}nj@?=Ol+k^H4A(?dVEzHBZRd)H96*dBTdp0fK;2^ygiD8zmNG6!rS9933@(y znx{_9!TOe`%*?MIQaVM*4RBaaa>k3!BRET3p`9tLGQ>4mh`daVA@fC6#@j}0uu($W zwD#e*e!yE+-PKmiVHwLWIJc{r*w1M6io?_8m;6?}efhw- zvj;A_Hd>pDWpi@xzxy;<#~QE*X;)>zgR55`NXsg-I;9OBytiZgxCZgSy%hSWzVaLK z0oEjxITA60aAA=5(tuUDQ!Alt&Se(L>N3lkRhJK(J$FDHxNZn<#rB4@i$$;oIL&{f zc?h+$wWWFJwqQq~AR6rMT_YZHEGQTD&^*ia+ce<=Lc)w)) z%8l?~)@7l*i`GG}iIW|TsIAz!!?W+$URtMqs@_yTWVM0A!F65Wd7$xew2waiqjk+o zOZaGgS1g%Tt)h<^8CsX?tQ;igI-0BOB`te!by_C4XF0=2b$Qbes zb6L2#Mbh_<(X(EDota8X)CVO8zy3JdrwQ}^={pv1;YW41`jPsVqu0nz-TnB^9Vbrg z*vb3r!uyMT2P7G&W<}DlHNGR8;9^HZhb}v@%t1%RNHMs~@wYZ!cB=a~+H=4SB{f)* zPOmsuuaVMs12N>g{WGen*ZJ`!^*Zt6m~lVbBAlAgdGaN+(U5kCwH()45@Cv);SnqR z4g{@ri_>HarA!gJMody#_~eh?xca#TBJ0w#8;c2Okb!xjv5fDAtk6i_bF2FCiIA$R z1I!l~Z*Uz{lfFLA4r<45n_88Losi-CTlMFSE610-&py4ZPbGD$+V8bNR+_xhoA^S^ z_7ZDyXZB&XS{?78(45Ze?tuFobBB*JdO7XEHM`V=P;a zSO>CqO90vPf5SzoG&fx20hk-!pmdGVgZb&q9XN#Xg#!nG>%8z^1$zP7UcAH9tX3A3 z+K={prP+~*&lfg`ygX^(e=dxeq+YpbjvzdZFBqQ)&)x;uSwk_(_WOgYqeuO=(P@sF;Z+lzI}&Qe+4BN6z4CoA zM8~-DmK3j!1!WFYHge!~P&&=>5PiGC{vY{$$ek#m5oK$P=A=c+x92cL!m>J6Z5&F9u(FYA3EpG1It^HV&noay~)*X?=tkCW`S0 zw`v=H>;@k&=w_QoX(`0M6mIi?2H>KL#`OEuD={}W^69e!O8TH5jddKc zZY_(fnj7e&zW2+S*TEvNr<}(dF?qM0%mZfD2VIG>xswd2X(3eglIU0rz1A0UvJvJ# zSJK*f5Pqye4vDZPLKbp86OR2P?PxG6i2FxOwsh!u?okw9B(Y~8CS^TN$PvZxVvcC;-%b?VfX9oza7kLtD;JU5!217~W7 zG@*Mm%~prZ9g^1Ez9KHH%p%4lwV}($c90VfInKm?aYJ4&0N*0P+h)WeDBFGEQ{r5#7Z9?%paqhH9F4f7tg?X2l$~DjRQXwrZ-21 zBS#;L*OixF=vHv~z$zT}s9$pMazQ(#6Yb9Wrq8|wlSw(UZrv;DkJOPX%hNHJ9Ci)Q zV;%|R>+>%bjejV`wNgMmSv9!zV`qm4m!4(MFu%Pcz1sxVPVNPxX2UBtZ|-@C$c!ui#HIgDCaPxJ9pi@hHl#-L87J~89IE; zw;rV~nc@rYWfPJ^RvO#%PAkly45w8WZytXCrYx)p^tlU4ZZZg7K@T(oM{qKAKWVGngNt$JK`sA;jmi`f|&*)P5@ zBqL*pI9YUAH)Z0)nJd@LoY=R@bfVReL#~N8S=-kAvRk!dtbMD&16rp!*2wVXgZC1E zzvSQz>?Qbe?-`{b;Mm}RH7PL6G{wS`L4_i+)C!-Fg-)4q9hcxQ9-GuDCoN4aZ*FZ^ zCnbt0ao>EV-cr9G^UM5M(>k;}HF#vV!LNQVuC@K`p45Ks_|~nktGuYSm>Riicw%r{ zw}v;4-nbJN`*DYGKR2;aqm10WpADT1?r`^U;W8Tt! zDIfG}-+sZEaoSH*jkdPQ4{(279z5e|*s`FuzLicIlZkhHQI{Fw&Kw%%ljxV2K=R0F zsN5DZ2{`mm?xvo3vT^8)sIU({Y+hUb^=e-hQmO7?E;F|ki|lYu)HMjWl>#?-BAg)ZTIXcg7%j7;LVbR39WtsaMw}C>>|Q(%oEKcmlXe{7b=^ zGhDB1^mD7@BN&2RJS|1Ra(Ho2U9(Gh5TbEY=)yBf)`Tk;<5GR&V$x$K#;lClj{n|? zxgBGVab?-$UEqsU&AXtxVqnf_x5`-gW61Oa9ddIQ96WVwa>0teeUD9^zWlXg$Jz`W zIAi93{-4iok@Dv^;x5~;om+Bqc8N3TkJCHFnNPMK7!{Y$n&NON_H_jI|1HSlRgW11 zB$Jz5Wb!TZDtEKE?#7un*MOex-bP$`%#*Aji6^BWsk~yk`;e|22mVKLYkyQ*#C^=V zk3bLp)uNnXU`hLC&tA7r{MF`t>{z?Q1!pd>Mr?A)wo|**rq}>AxE&Zd;+K2s3z)As z^P$877k6mQlvJ;cQ!%cG1F)tt2V|6TLKE?HRdz`FW z9*WencX5~8`3lnof*Hw(^;7{QLq zgVgSORCoB;k%)q|th}=?Z}{`iJB^_k7GX-NX9zRNwO!1ee9dm!jkWp+`UV`6je*BZ zo@K`3V76O4=|i{HQU=bdF+}E-r$)|sSmi<2)hW&+S9#qrr0U;0pBg#aNBWp*<9EPb zN4f*L`6A1?hri-&_EKCVguDA8Tt4L{($--3+>9Wh7ZROqU^p&Xaphr!o>~@IIjvH} zzUtsIOspk8Z|nh=TRg5F?7pY+Q5RZCj*h~i2AyB{9P`J$@R(y5e}7qH4u4Fslm3`w zemy;nNMxkly{=6$jTHJ6vwTDsuxl$OajAMyU@wz}W5n_z|JEXIe@G#APBZZ%(o17iTAXe`TvgYpFp7eaX5v<+D5=B|o zH7QV=rj^n9VF>l_gF6Q8U}D2jvuE|3c5vmSNl^J@17LqtiN#oZz-yJ1>KR&3sO#bx z)JZY>cL>o%3e8q8mt*GQkYHhVouKl-4I#veK$_=Q;%h~19clGNVpT|GvD(k$FYQz> zyfCcS>#H~Q=v$^%bX)hQecqf$ET!zabadv>eV4xUtAGFQjJCi=I7}_`3>+ca=Ag+EuA!&9^N(GjpGrT ziMUoO$M$0xCYHfX!yDP1DM!-iRPT@=m*DgmC_ootrurP&N?d;qDJ>Uyn971{7llR? z2bH^Ra5;&~hbr#!3674u72_W$g$5CWzvU+wC65r!>rjXF)9X*Hzq0;z{P#}%+x6}B zp$_>99!YC8yO29M;AZFYN>_-QxUxzsAgi9=ckI~ksLZivh7WJuY<%&45?tdB4jTbl z^y+nLmqv`jfQ0GK-}~=|fhZAYJ=snoY}Q@QGv9y;be<|s$Vzoj2=OpSfMXhUh$oK0 zOgUmU*R?b<-Mm?Wo5ESh?zrIc_*%Oy8{%D##T4@d$UHe0I4JH&XuYtYFr>UnNqI}~ z3HA1=M|pWmy-Wg1AYjRi<30+kpO`ie=&I}}OF%Hu9vA+>E+R{Yvz&Nt@T+b6zP@^Y zb`wdosJHqCv~L!_re`c;-UE=c|NR4@i;KSbYu>zhlfICS4w`cO^7rez^vP-{HryC9 zpnK!UgRFi;-EDi+qivSHwtNL+J9aXcpAKx~x&&H=bcrwSDhcGg=tjI)%r>}{dz|zm zPV7mVgt!q25h*nxA4y$4`G4fEs}W80k^6o2*osmQQy{mzOigx&xE>2EgPnjoxT81l6aQRH-2{*;0mY@d<~E(*bbHe~O=WPG zv%vs68VhEw{xqw>ibG-AW=JA8x?9ph5Z?PLBZB=fzWqwgj$p#243;*nb#T2viw-GGgMub@vZlv*8NC~Yc1zag7q>6`k=x$GB1kT} zd7){C8rFro0Nv>hgG|#F&ejEkj(AGqLRl!y)hT3;>9!cA^i#$KKjbe~*%m=UV_{gT zhlm+2^bB$Fa_iW{RGGp}v7;u>#&u-Di&)_8+AgMgE}kY&o_3lY@{Gm&k1Uc5#jKv! z?%Lkv%zud=sZvT>$0aKSK&V@ctw{iUpJ4$f_zcqv%<=xogV-AdTb&25Y-biEjo1Eyr zf`mKsm}Pgsh6qDZRQ+OB9znSzIA`&0kR7E@0IV8g8Nb+<<};t?!Ia#FJdPx)^ob!! zZatbXxmC)tii#NjT0XhHvXNU^m@DFIh+@E8VH; zauFmJ=8txV7v;&-fe8PxMb%14P@$f<5Za1ic)@bUEWq`Vy!tV{a9 zH-m#mRbSL!-9Mnu+`KvfHN)!e!$Z#xS;L)C-#^G{Pajcx+#9PXCVR zPfO_6NMT?qaLETAKi+AWp%RxV{o3!ESMhQCZ%rO-F3>NsE<(sy2Z(k zgvm!E^`0R;am7(&GVuus4MCSGDxCTR(}^;BfZ521;>yF{53EK#i}6a-dKMkQItDXw z@Vf2+37<|GncMWG{Dwz;LeaC>)@@_i{+N^w!(Zt;GA3c>LDr&4%gqzV7r=LfzUlw4 zwm0BUQP9R}7WRGW3&T^r8g_^=E49(BFtbkwvLqb?=0=@qQ16(38H_|sdKxSDI(6%! zLy=ydQ8ZX7SQ24)N`<<$`KZ;cjZsT=jr57|@rv^F_A}YgU8{GV;c{jKlN8)Z( zxIu9JBYZS9hH=&MnB2h!uT5#+p``POmQ7oR4txjW>KM%A<~P{gr5#^+E`RUHWt&E_ zWtolR^HZKz-(ht|=45i49dTb%VJ`;?`Kg|PuA;fNzh;gh&mvz+nQq3XdgyDsz}ma( zxX}_XfrP~;v>}Z2^0c}MNJi~RIvCHpIZFU<0HBCKB`CSXAB}a ziZvUD8~41IWCmEJKH$65)(*k_!MwJea0z9G?KZnNeo<~8NHbfJoQtLOv7G6L`m669 zB!3uRAM$*=136zFz#5=29qdo4-vl$%4+cvWymqPU1_B{rm1tuIr)OfRiy0bd4n2(Zj_p-JiLLe(Aw3 zK^>!jMkRCuZoEkK@rLdwa|yJaYl|%FO-)AcIGo zxro0P49sBPinF+vLNlg^d;Yc6J)r_Z_ z*1Wd3`*&+zTian+G0t?4`XDZUuq6Xr&S0Wy_I=Pl?0bV;E@8bL3wr^#T+uR8H|`G} zgv7%5;9Mcu_L0Ka|200o&f^nQ&Nld+#0bH|@&9>*wB-xg_hhv25z-9EXO7Uc%%?_3 zj^(SHd-@P%z5e7DXSwPz5(NQtdI!8$3t6%Hr<#yo*SEIWy;Crf?7Coi%`XN@z*6hH z2^uFL?3j;N;4#Ie%&R!kuhwp}7;sW5kHpHbf|j_NpW^)eQX!xgP33@En96bf+`U8# zG3-T)Q1a2VR7cnj(=0KrLa*z``|Ve7)?fU=W;rG`r1dU+9_IJmqEuX1Q5eB1auFZ%B@HEs{fo;;@s+Jk>Z{k|e7u4qL(nGt^V_Qm=6OeY8$u z6E`^omJ#{;EaA0kH6q2D@>UZciyJZy;uQr-wWbR?xhWYtlv{|W0rd&5O=~y|EJ_p~ za{1z`*r@%8Im_d(b{qbE-pGkVHqNs44L>_{-0HbI%R2P0mC9O1vrgH`Lpn68CHnYx zIuYEZ4ijH#JT&*!HIs6gnAB^ny4%=z*tnn6FGdei$1BTO=oCo|>eX^ei-YiI?82VvwxF)W-j}%?1Ai~We-H3W4-#camT%7&SqR0Es%A&SG~l6$B^U% z=}r7#=McY7IkPY;6(-3-E#y~#&cFc%gJGd8EX1sgt%ys8SA;wx*i5{7RaK=vD$VI! zwo3{X@6%aL?C2!>^Gr^O0jz(>S06OGYv1bkx=9>fi?!Y9mAt1U16{^DUsA)Yg8bRo z`}R$g*a6B?!ZVMM+%Vai(EWcnSJ6>;8*%(1Ws5`kEL#(~G0t2?i5vv)Uy=zq#=842}r@rf3L zh1VW60IePP)Z+M1c@8hv@xhqkoC(@RjGxJ1Sa)Bmhx&^Nc8 zgv~m9fxOH}<4E`q7vqI5*r`;Z`O7BAJ>iu8ZULQ>(c20KOcBvom`UygZOr9xKIZjN zPJBC!k9jQS$KSlXi(c-*%XzG-u@>rUz{|r}0t@3~0zIqziE`*!jA0mFbMRD4UQa`< z9_GjE;eL%8^8yGFK57x2Lnhu)FxtQr@1dOL1)UWoUIT}tT!#nGI@M2S6R3XsPZ+Ba zy#923-f8eY>QsKeTo~0$bW(9kE$SE5sZ>Ak2OKZI&CB0cn>)jc(-b!ypXSc+;xu_3 zFBjBlB2x9C9z>sjo}KKV2kMVTIr0#pygSOcXiLS_l0p49K4Pw(Ep?dPVh_1-}fx74& zk}EfPInfpHCP#ZVg z!bs(q+$fjS7i9DSaG+%`c$5QD1Z; z!H)Nq$dd*0Gu~S_#_2ua6{WYc&i)pc(NDLtc2rIHXh`#8TnC^%8aL2;Ip>W;v`>1q zZ8dMe*4)K;qc5I8ucE8f?+|a$J0xQlX}rPVId2FzIB(!Rtqr9gmzh=_exZYxq^<@t z>giAQiwVA(KBT$bPoI0>dbEu9P!D)X>Z*;k6vE5#9@S6q#zfO_oVJ?D5>kcK@t9wq zR==bCVG0u_)v}}XGju_F=QOo}wl$ohgl~CyKlL=Vq2q-4XrIT+dF&4FLsPvEWxNmk zegry8CMHDEY#5-|Uj)9y-P&A!yvT9Id%$%9`tY94ul~FoZ=hVOpX?i|KU_?(?_z`a zc>Gp19@N%1d_3@uDNIZ#9zZizSm|gJdY;;hGQ513Y&q1VwMln47!R4ESUBD@V!XoG zc50Jwq&~@Cp`6BXv(_iVk;X;7jdF}j13oTv2e$kJr$Mp~KbgbhoA{eC7Px0<<@RtE z3~lom^&>|Kr@Q5YHChES?5rI=o{Jx+eW?O?=y0jC4%Qh6Zm zr=jv$yc~WMl$Wa02p(+%4m9c{{HDWCBY2bpj+d{{;BB{Rz!%7OGo*^0KaDjo=*5|Z#O_)oxPKe_0Mo8Ooj!!F$lWgZo$jJp$04Nq=**Mn5%$WDTF~!!7qLWJiix(@q1C6;f+Zo z8QC8!qGtWdJG{Ju{b0@dIgbJl;%U5&G{F2A5@nIXx5dHCd*?_eA|19`gMXYmIg_coWJw zyf8-7A6niVj(>_?|3qFtKg)}=!eJEYMsrfvH~6M#x*aXSP6!rGRmlr*fb=Do7uo!s z;5ynEXJL$?t5FxdL$(v7HEp zhjNSb1uusMrP=tbEiX^7YwJA+Pm}HNHlN!OT0P)tTKiIYC@)8S=&v?s9^g(Jz(HR2 zrn~_t*YX3*LOHcd<^8JRIXwy9VAu>YP(2(T^+y{v+c&7oup4+Guq9^s&xElO+Uhmgwr~U?`{9U~q z_6^`+U(h-hvX9oKB>T_;$|rG|NH$n!y?mJl4_UCxNc^M0_m;PD{^9Fz1M!ar-&~!LRDH=Rv(G89djANAdro0k5 zT?_bFYw*40Io0rp`*o}vHao8abXjqf(+TgPo~P~kEl=71(U1~v@o{@L{LX*C@3jA~ z`nQg(9yjW5v|(#ac#S^5f4xQrXZq;l2FhUE$lqrWgYkv>k&m+@=RjAiGwM%m0zU=H z@gBiLo_=rq%TYi2>sp(X&V=oeLDWAfB+atbQMh3j`uhc!AdF4uJ8zam1 zX&(2cLF)3R(SSXu!%C_lwOO-FW(v0kSP?@bKL6X2#lI>asDI>3{K`q>mzg5pm->Jg z3|Kup-M(m)1+;$}?W67#w2!mP2BX%#aftD$_OWM8?MsF(Z;BGNFQv-7edOE=_e=H< zV@rNpvg9}AgSFeXO8MB27{P9f^TdVN1MxX3Y!PK9$Rt9ESl9NgxNsMZ zi4JQvD2oYC{QrY2h%@l6>8Q9{_yI4+Ucjq}E1)elS*XNQzUcjb4eO%S>-`q$rD}DI zs9Iz)BS zR$IWk6;UNd383d}^SlfUtHS`{JqX(v&_nqqI9dYiCR=0AU z_iCTkH;Q>POV4qdaJ+fl3q5$PM&3frx@qrDCz4jT$T3#)stKl7{S-}f%7tq5D+K+- z=Qt7f)A;PyeuCD`?JcGEKu3P(wu^ksO~eqN^^h_Zmf@OdL{||U1uQ_ryASavsHlbU zBg-0cqrP#7O;A@IQdhAFI3<F&)^w=!p57+4%Q0XRZsY2= zU7N(9{PIlp|xRVu%4{(eG{j0!_GZ;rn5NI>C;`((} zCB8(tJeHRmaatNr=p(Jae%&^JKma5WjL}braTmft+z;+6oxgwYCeeM7$|s z8cQ_c9Kb8mD!X<~+DbD)xb4m%DYx`E7Tc zz6r-ZULtZ7cM}ezwvX_RjEao%M!wBU>-Bw;*JpGd!de-#{b?=VrU@NYjuefWvZ@T{{KG?>`|HLXd z2$FI)0bBjNJRuG@^cqbHE{0cr&J1JPO8hbR5;!tGioVH&5ROWlR; zxMj;H8QKN`OOEK-Xvd&glbSN8ze91^qpuU3^D~Q6xy!?h5hF7C4Q9 zC)BgY9T+b4{2vrhU*r_1>fyYbddV|sqFNn~t6snW$KZko%5wvr#aTEO zv;VSs8%4O_6y$<_#&Z#OF~FwBO5bEuN?0RDxkNerqP3Fh=OS#?n)ULtf!i~X8;2^c zQRhxx=gz0f;p-uiAb-F|6?zNwzI0qIUZ477P-nA#n*Reio(4$A}HQw$v zVYxU(4i^lFiH(%*$%-uAW1>R8B!o5^*ge6}PL#hFUNef4FhLn_q&PpCFApo4^C==@ zhPdb-nP!T=EAwYoaf*7CHC7wS;qTzU`NMbE&OX%7GiYx;Z?8*glyc9Yh>|GZlhD>Z zJXL@IV?sMcq6QTG%FeLsYC|-6RSs8k`lvbY;Lx}S zjmbGdR(?{hU>)|d&<(qaKK6TJPx>tez|z8RxfQ;{`Vs@=4*|ahzCa}1fWK6>=MY6< z{$O_y|0MqG5axpgk)9DmSGs6aOF>5b?ajQH(Tn*@kY~O=$*pm27r{K;-w6&GG&JW- ze%bBLg9gS%yBG}bUcUTp?o|-UsvlI-m@=8UWdrTvbUR;>HM|xhmC?aqR;7e zKclf`3klq=AL2^2prhlfQVDoK`_e$U?h_9wN)o!e?k#dqwi`qrpXbEi!! zm_B!OzE;0MHoRvX|F8AC$?gcNl+3u%CY(juDMeBiM`TG#bZN z_IHiv3=1)0*pIfs7b$qk^ji`R(dQ5@ntwwb2=K1r ztrdTNwL-iFaNyqsde*{yDq%;7^TH%Jgf*U2x@zSbM@rm&re5>%YF-Uvo2biZdjc4C zhr9@9SGZQU8j+^h8tO}l)QLZty89F9$el+l;tktYDdF6!ALr#6jiPrRTec`oO(I7$ zYzBKvxd`$O6lVyE)a9pM`s^na*E2oJGXy{STI%U@tL)T0yeA5uv$Il+ zYzDoFQi(oB92Ft$kSNYLcyO9HXW#z0vf1_~+c#(S-haYJ``|1I&8LQp6#;(k{(W;q zc9w~~$k5SwK{_XmHDm0F7pP4ZWH*cLAX_BpEzC@RklUYD2ox~}TODG-c7xlrm`i-# z7{@~n?*lyz%6`-|&{hMr$TqM4ow1$Pn;QxQ{V98AF0=kwDyJ z3tdNVF-m*3KbrJNEn!0+PkOu^A2w7ic|1w1kD}a1lOJt=JoyP5rf#FBk0ztXk6D6r zRL05_GYJ$2uR$ilzQ^bBMb_xz#f##~ix<_M_+5VSqSjaFDkb6{Itdy|T0}gilyKc7 zBO8~X^px-Eb$bJA)Cw-HYJufl6bD|ky`i^)b|zlDD24EL1O+*H{>1xVRlN^>q#6iE z!q0)H_$S`Kc(Jn4#hVw!CDoNwK15|6yfTqu_t*ihe<3l*YNU|BFDWDtwtQtY>`GY} zp?<5_48K&h$Kl8fMFJKMKjP|D`NGw!wypFYY)(~`7paeaqgCHT?8UX$>vu;6sJfUt zPvJ>pM#eoE_A>C)FlMv2+w#Os+r>@j2KC*6wz^0w-)tMX9drj)Ukd5yLu(zss$Nv} z1bu0(+PqZpPjmIo*g^)>`^uh7_e{u0Q}p(Z@|H?u3r1`YTZH=tnd1|jYH(GUEV$r+D-;aHY(n2i_fFQXWZz;_6FKLw*^KcWg4KA{Wm+9s;o(_O(|4LfP;eZ+}aWC9y z>rJM&iGKLd4{npYaZB7wNQL0?61;RvTp$pKnT|s3A#TSdGd;DRI}2j5$o$fUb(Aut z(b6($uXI9kXHXK}qPOC0@HTq8c)NRhczgN^!7Nw|R)P^C6zmf09_$h9NkI{vgl?XF zg~6U9g+;=v!dpVUY?h65-V&Vx2uGB2sFmGPFEeYvYehvX)nQ7Wnk@#}?mlZ4advsq|)UB)8JgKgiXWoH4KYvg;3vK)kK0xR$n$-D#CzybN z;>)j>Mxn80(~dJG?C`)u{2Q1-KljEbB*f2e-`*{%d5iX|`t=)_vFi0hRD)$^-s7Ye4ikZ=~pVf?S7&j#LSDE-iJ z;%If(3#_x6sN9aL{8_vUewBnw;9UW{JrHx)!ok7(U}#b_rQU%`K_VX_m60NXd_w0DQ(Lqc(KRmKY;KX9KBF!E&FI;@*@ZSyk&zK? z`A_2OzQFef;2TV_cD|H*govzVJ_NGPBMZ7$C!nIFC96QfxWe{nZs94-JFI*oW8kXS zGX{?3l)W-A5A^SEO-f1>59Ir~yLIcfDYkB%jf)C<^qeq3BP*LcDoZ1NR#Fntc&WHW zI;4!%Y!xt;F1N(qY>2vJw7P>0QO2qlho~1>vmsDQ_=k6-YtkV(5tQe=xKxU+ydfu& zttsN!P&|8;&wGtiQ7MPuP_O0`ahp__AS!Gn=uMi_ijWi5)VsU;PFR z>KnvGbMX?rI**BS=i=Q0@YB0WFl?Q;RHHwRjJvtRMRPMH_R1A3(|Zqm(;v5C$Cu9Y zXW0~1?&BfS^OW<~uEdc%fBHbEcz$Zno;l+R3hGblI%AG(Q5Uo6nVDm=)NSIFq0O2t z;r2j={a5k6)DN2S3T%)Oylg25^{$i#%MCV(UY3KhBLpYFi>{Xq!@D2wGT6a-SsTDT zq<57MtIF~Kca@iYR8^LRvfp{TA6J!)!@Jix+$U9KnSiU{aQ~?)>x;4_H2Cx8&G^%audYfZoB3q=Y zXUx;DW)J;*M%_B*&9&P$kJ{YU*Qc~}J9F{h^50bh=kyViTBoUJtZkK_Tzp5r8W4Cr zrT&u*IYX{??ku*+FxM;k&g}mY%V(oLKIYf0GI%2H=DNRDy6h`ISr_9^b1&C^7x!K~ zpxsxxk&7cp$s4O~4-Uh*Yf5IMr??2#E}ik0nhYH{CVS|O8R{i*? zFvyoN{yzBP7#MDH(B*n;k~GLRQB1cTdi?lO1)D2p>`^=KQQzvIzQ>w(;O`gW{bA@2 zjXAx~*FTB017kHo!(k-&=p$<{lpeAeTgAqe!4>bk^WJ-(-fOj?SN9iMt(}S#5i{5d zR-vBSvxl`?v0}v#ru-fpbhLi`&DT2PE8%(EeiCuBd!Zp{jCr~T$9XA!XfP=n`UN_` z`2=BdqI9KINQcvUilEnyd8rTPvzFH0JWtS}8C_EX=F6civu98H;~P3VwPOn%B^0;y zNvT{VJ&t$>N8NC)Fn^e(6S@k!5wlpKb&?2;7KSWH^?^&Yzi)K7zZ41^NV5dUWDAw( z<`JR+K8hvLDp{;zw_Zn^%{|XdSHC@f4*%2#`X8dX+1y^eq=O&g=A1Qaq$JxHNSOJ> ztTnT=Kg1~fIcp7WfBEo3w2VCNt{(yi7a^S}4j!khVU)8=OI!?_!a}IfJo5`^$*lYe zBf!Lhk!WpJH6-v{2J-}IngK$NJs(!|%i>k57PDK1Ni!>cImPx@%*?3O`v4oMZtgU0 zZ|;e~GZzink+NgO)w8*~J9pjIzpyZSS<7Raf4JQL?YzD3Z&YG!AFVE0vRb`zam*yT zC3aGu7Z_bXYumoGXSmgx*}GeMq<6%+1>5%3t9KwKreD9*E}>oxUS7K8Xm~g)`Hz?j zI`cldAXXWx9Pk+LqX}KKgiB4B)=BPWM7l?Qs9Yn#|Lh(P$gWXWuUofTd`G_VPS<76 z-^9(fOsHHqr|qoPgNNk~AG)A;~7<@%?eFFzg;uyXE^#M*WLN1x0t#5V?tZ8Oq(CRpd1#uS4Mwy`Eg zCt5<2`Ns&pp^v2hXI1JlhKH=KXiSU_#a~D3Ww(gG5-0k`{g-}x5Z^pIXy&%B)i2K7 zRPU6?r(b6`3bu;MKLx1wN0<$P&AeO9cn<%=&fxu8I; zbo^BS?gs6LV88rV;Oa@MBHu_#@y#_S3=1Ul#W#M)A7<|mT;^eChO(`P)HlnNmuxn> z`WRnWU%5>AkHm9cuVMopTzy)g@~V%dA!dMQL~n{4||WN?g~YNoyza%pSc z?!lSIa(`AY$6QTb#@N~9EitTV#js<_u*HGBo9O}mw)e^6bpX0&1ZYmf#RV@wjn1sNd3e@ zeyQrbDYjs`-BtX03Lkqv)FYuD?k^$lRVe%r0OsSWlm zSbui=cJ^ZGH%z`i8=J$|;-;}$to{1==}VHjipATzes>xxoYFfi6m`^Bdw0V?ftNvs_#oj-58YY4W>KQFkx&Z#OHef#YxH~txwV4HZwg+1U)8WevC5wykH87pO)$*%=wLl*q%A%W$tBtW7VTk#_e{^zJ zo<6u=|B)m6_ZysMojl@Zj7<;gWc(by8aMDp z43DmGY|ph~$yJB_q5CbGe}P}75YrqWAWReLLsPD=(K`es1|| zA6(cyA-{d$@T|3+&YlqueO}rAb7gnVgl03AE}hYALQa&oH_|nQb)m~Z9(fkh)BmOM5zV7cLCSGTqZP%EfX5!xl1re-9?k_kIAD83)q9omF->A&&c*?p$U=^-@z`60^fxR#CMWVUxG&jGOaTRiX5-} z?i54;(N+kpEQ|=PO_a2yho3<%Sa@uqtJ|0%Yj1?iC}Xi@(>s3g{MuJsdD^+Hv7P<< zav?jG-5X9B4wD2%r2LN|R!j(3rctSz*MJq#RjOf%lJ^gxmy7kiW z-`Ul z$-v_3XSC?HIHhCvj$7Jv+cGZQEx2G*=UH=@xwBe!qItdA&ke21JT6Yjvo>Ege$CRJ z{WoqDTNd=*-!ofXsQ!f<;sI--I%L=$ufll0kLwU0V7#M+*-9}+oS(78zAr3Y!?(&M z_#bOyd>RvOJe4-G!3d!thENy=X8eIwdbHwLap8gyZSTq_+~EF&+Ex7o_mcE6up=y< zCDd2{QXi{J6js0t%*bY(uw5-3K6dPI3UNAguxTlv68!FdWkB%F}f z8BcJ;7v5Bhe*F&34okH=)kt4KbxX1ZDV}_wwDrCk6|ql1Os@u6&*$eCFVD+w+$1%1 zWt-I0Hd(#frlzL$ZMq>ZKR<87&XM&@S5HigjhNfE-JBNj5p_cvuWV4c%YW0#9$mZE z3Qo-ndb^}}@M{g5z4zg?f`Vy>JUnI&$jHc8FK%8pFe78Yr2!dP1=F@{Ehs1m4;hx> z75`?&tl2s75u;`;oIfpXu-vy>mb$J}+Niu48$#S-;V+nm9^+b2tYhn9?H5fafZ@Bq zZe>(-2o|z%ggF+n7T-`LS0nq`CkhwgBA>e6w`i$J&%Bo|zLYyi-SxbmI$nGO%hpA+ zQ)jonqIN#j)pq;>yB`*%o@K40UThJQlM|I9PLF+G{g%}|-OPEVs*b|iRmyt&yW(jZ zFTNz(#?JHDBs%nqdq>(@#%t3CO)I_nSswzd|t+9H$KPkc^{t}_;^C!lCE`y zO09<-9c21y4h`#x2J7Gxgkt!Lxu*3t9S5fF{BM!8u46JXhx3DMO*jDc7y~v%UA}44 zauzaWzlsI_6UKTTICW3`fTjKL(Y1T5i^E-E8`6}V761Km-`FpIRF|k@5y@J~))8Hp zBrP+`lqmCo0P@J|)oSX|D^Cf*H(ZUH1D6;q+?mVD^Z?c3-**B_F z#5>{yHGqfF{ApV({<4_ev2B)f=U0YEcXIR8zw*=*dGHc^N1*}ef3&oQ?u>+N^h3mC zC=4AW$u@hrN{06lkWuK*T$N#x>o9lE;oif1hx_=OuHCJ?OEH2zd_xamf|dkCQJzP% zH15f&A_{ixH5ZxO^}wz@lg=eyo;>OD^2Jx)=)hXN+_gpT_Na=RYBV8s{!i6?~M>M3(Ftsjw*oy0d5bz-#gk?oB)FCeQ> zy8739rM5R%n{BJuJc#O8R`}8mrB-R_Q1!^A2kKWW{Fh6t`_R(TW$LG8>RELfTgt3w zS5Wcin#boKR>R{C`u zvaw|Q#v$$R_DJm4FD3W+PJ<4!wg(Tf4hIgXCl2{`@%3dB(-ZsjPU^+!0zBn#jG3z- z)CXa-jchr*@-=a#?U0y$X%8#gBLawU9%cVt>MGU8tfG}S**PL#4VWd;ZBmb&u+YYYbQSJuc>oX^`oh?n9OXSzj8sf;|HR;c>6d@qLgZDLRX%P56)Sm zK}*YrnQDd9<{A6iXh~oFEUx+=8VDXr=h?F1D-$Z8Y;N6d--uQNI{a}yc9^wz)2}EL z$FbT|@%tz~X7OXSV0iq3?tK#^WlI~tjv3deb+b0vL9xS|=J#K|`B&|sZ9Toi;f`v* z%&?g^Ao#I6=8h}p?hvf09kV8!Nuh9Mghz)WqK+mrBntj#8^ndGA1hbeZ;%$g#m3l$ z4Q%?0gVgqeilt9i{PE{X^&IQ7QvFH&VI|AOoKla@v;82ssA;0La{hPUN%PgitcTi1 zZNlcL3mM;MZwXqJfmTtZ9b750EWD{XnI&=;w}9vveyfdv?-4r$4G%fPNEwXMaaC^F z&T!mgRJQs<<%&^v7yil;mMn=&_^Pb$tNk;!wI98(Wy0Y8*R~INt&5l{x@2CSya=0V zEND$;hWhho^S>V6W=_h^cOxQ>#>P(=n3(@z?;QhIpKX(hVFbS;p2|3o+sCtDEkzp! zNmgzrBP)%K?(fK{dOr1;&*}Y~f4;ALOUzd5-7GM>XDeJg4`kKjZ!X=A`FlS7nG266{J4edM5_E(+h6B zKUB*#UVn4Pcf&>whwt>hf@o8`5BcZPsHzxw5uv7JW$T@IOwRK=ZDdA&+s#Z z(V(k=)*)K^Jg<}iT3-LobGI1uoGoV{8D}7mjDgNZ0v_MRAMjm2D=Bnm6CLGpW>tB# zRt`M6i+3E)4Q;EQ8-+}EmY1VnJePn029w?&{SFPFZ@*+~ODGWvI(uM6?W{QGgN!zm{Y&z%E*!3?|Ibq@5GC%ieq zpgpa;pvm|zh-K|JnO53g1}iIN>(xf z72#tW)cNXMbv+xy7O?qj^y5$9x^046IV?}6%S+WC)NAU0REmOwdL*8JU%L+WHlG}a zlBmlKPgfYBUQm|g`ticw!LVWJ?_gNPuJ{Na|Nmwcqc*cvn*}zu#bIMxU|v{YV_RTj zTfhny*w_}>*cRB>7TDMp*w_}>*cNoc0vp@HZEV6X@+R_)i@M)R1oDCKs}b^n_!|*> z{BK|U?S|+_Dt99*+uuQP{6TA8P~Nfa7^)8qTT@N$&P;gltG#p2k~M2e)O)PNF*xc_ zmU-Ag?b5R!eSA*bX1iBd{9+;d$}ucJ0pxUyKhZu09-}nyfCC3>BEQ)!6d4tNsf3;L9x*qyn~v(|ue4p>T_9PZE_}CnN>?uMg~khGh{u#5Ss9)SlpFRg$>DP!e{|M1OsrM-VsW7w>fk6xSJ-Xp+7jw#Rj)A@==?I5 zJq%tZ*svpnD~2|5Gq6|T5z*BEieI~SB_Y){RZMk_6XRUvY~05oDy~d0C|hs?0gedy zG;e;zbR{m;!^PEAa51_Vx8QAL*Zn`_y$O6&)%iYt&)pJ+eb+=}h$ILE0))sGmOv7S zh6F;wUNM9LB3Wn_z=f)rMci6sucC25tt_rU5LwD}I@Q)HYOPhVwXL;k_gx!E{?Gf| znJnN!t?jq}&rh5uXYQPP&U@bToO9m$-uK*lIz86L19v+aIxbsG!`zAcJS~Tx=!UH> z+S7&}+dpF{myF9uVzQ}D}pW2mpJ7j4*j;u)gl)4+u97F z$t-==e@4I7B`OlIY}~w1)VllqbusGJbsw6c#&l6{gukNSuG*UiV_Y5du39&Q*^d$q zcZOhHm$;V1xb?Mqw>w;&Q z??hoOy!{k9PwCXrR9wlG#?U_|@OA%8mbxEfVBZ)H597!O>(njMb*D31hRFx(n%1&AIb3AC zH2;C)rK|SS&uaci?QHFJ2RpmYa?OeXQ@c)aO^Jz>A=FMs(Xn!tj#>}5(^2c;b~=h4 zb_U$1>8Rbni|9y>IXY?`jPT5nG%Z8&{dG<2$erlWJU#8hb-1hsi;SZVhm>0zZPnxX ze;q)mF}MVS%e4C?$~{?6ZaQdOx$g7>kD4`;A3goRI^)WwgV1T){CzS0)gUz>&AO^3 zi~02AGe1(7^Mps+=TF3)wgGAkJV#c2n@rV{A7w?dVYyxTiG#!`*H;bbt(LUp8Qn&* z$QZCDTh1;B#P!4Qz%+^)CZERq*|b)sPvgSf`Y_=OCsQ4EF2>Fq`Y`J){dHIyt$V`d zMKl-|+!OwWrT?=@e|@)Hr@w)D_btoBb$VA#-inT9Kr&Gld>zJP-$KaTuy5(Z&b)eN zsHH3KZsl!SzZ>W7ZaG)>(stG69mWD{b8)w5tsK&9{B@ml{&vD&Io?_Ba#`@bb%wDc zmOy7%1v(^^w2ll0J~7BF=?*8w7bn-wlnW~};#eLNVH~l(W!~3h?QXJE<8IZc(q2H@ zznr}~*mHhs^CmOhPQ=}t$?8^Z7VXJn+T&)XSpH`{{zCY{G<*G3 zA0IZVhs|1gW&&kq`7tN4XA<$XXicqFt=-+ zEgtH>d}Lsne%Ji@zNSe9 z$}vkv%!f%r##pgd2g~K^*0p=r9$kC7diB(;+} z{~rB&#`TKp9oJ`|KF}Cwx-GZuju{v`u){#tkS;^I4(XQCJ*7uV&mp~r^d8bDO;0n@ z%n{ZIdqhlHY+8pj*Z3~uyN>TRx%=cElY5TuHNN-wK3RH}k!4PiXGp|k#b$NLa$Vl# z@~)S6%kQ4wBfsb6y)N&4d7rua`#<4+V!#s#Pb57t=!r}B501qK0L0HlOkt?FO(*m{ zs|OrQH6h8^JTg$|xe;C954Cj0#&#VMIPyr~%B_0J{Dn7{dIC3(iF8Px*53H}Bai=h zEiU1-e`qSEgWVIoG7{Hr*?96Qt_v0XecfRf%Pw4)!QCAuxbecM0Z#ZIe#6a&i1D0& zSGY!QZ(<`ejOR#zMw+y1bdrQqf>utDp-~2}^G}{>I(_KS4ZC;WaOjXSpHY`SQ|E1H zxN-OH8ygzDb-cRLNfJ#;N;@0GaXQp6e&E!+^PCw57w37 zjVw72B?(V2ne`tcIn3YJOr5~MXa*(I%Y!_AaF z$d-i9W%y*{GZ&xb_^iPvfX_C39>(V&K4E-*j87zzp$j4zy2$0C+@I-%YsX&EYsX%= zcI<^~$6mO0>;<~?!nI>BTs!u{wPP<_JNCl0V=r7g_QJJeFDyE}P$aGyyGLgJ?z}d< zfI_;E9*EgT1RjW0;38QCA|7|g*KI}p@3K`?hx0!sEm4AG2iRMhCd0WNYMT6_`s%S0 z>Z?Ee=R5=eUxa_(IM{RuPk}geP+kAVZr zXY^%1+(!|`^n+qXpb|-skn8`?>Qf9RYyoa{NIRiLm}0O&`h0p>&sY1;EG|&?fJrG! z@+SDIi|?HH;CDw%>i*Pu^!nFtn)#=M$wik=&Py7&KU7_ju%74rHnW?KvB)@K5yV7 z{eBVtPDQ^91Duq^P_gu6l%54eEhkAf{B=}|~ugf!j`JnplZXUV&t z+us(!ou$^rxP^%4!$RYk&TD@1ohcjUFIt~jTfM5}_B$8OU%Y7aHLI3vn0Wt*m7hz+ zZN^PsxnpPF_-~E4C_i_4-tFn*(`!DSo=|;0f0q*}< zMmn(o12HRIgxM+S=OJP^f{|TV!N%B=hJEW@ut71&KJCR#~lZ8 zgYEOyi2SBHea4wXcf9(lEE4V4h;izQ_PxqT!HL0vA5R+dsE_zi{=*h!o^eju{lVaqV7DK4HMWnVMChc7(8kJ zvuvQ{*dMg*k3Q)S%dtN!$NsP!`@?eV56iJXEJwUQ1)qcXgz@?&L*afL-C6_KJO*QBDE>~7`ETFEi_9m}kRFZnw9mIOTf8BolMKo`a=k*EPrX?K`$+-t3uI6ck)BbN1)b`@LB?IkRTZ$eER+*37Bdu%Two z8fADF-@1MKt&6=UCQh9?anjVOXRT|a&t2Chq0dD*GTF9z9uC9&b`0~B|0yp7*R@Gl z*Ct_In*>@+!n!sI>)Ir&Ym>09O~Sf13G3PmL` zgNJUcV4_|z>63ABBxD5o|S6%WUH z=DIPzUe>eYA3T?~>W#cbi)5|)T(X_HZRfz=oAW!TKfdM8{b$~Pv+3_W)&8Z67A=*J zT-&stW92#Flhobq=h(JBt|16sm*x+FDlUVgLDHACV<3C_-(LUNzyJ2S$5KXsB_pCN z5fgX>STX`E83C4z082)IB_qI+5n#y(uw(>SG6F0a0hWw#DEJ|o{ZD)%ank81B^{-t zqm*=%l8#c+QA#>WNk=K^C?y@Gq@$E{l#>40TpNa>M3KXw$X1`+VVLuScw8Jx=i{Tp zF7}wTG4#=$_2ftAVjDC(AIAOg-n~a^>zgJS=9H|gDU-9aC)aJ*Q0LvS;d9y6G)bQ{ z=$0X8F1u0x>GlU7*uMRN2e)7M?#n0NefQ+c?~31dw_0o0nI&LdN8F*(VK7-KBS!Y@ zo@jNq@S9oOSdVv{V5?BmZO<}44E!4F4Mex}kKEDf7Kv@?2A%Z4r}IgCPzEDa4aDKg z6I`%48+Y>h7+?E)?C+Zre%ImeH^kJcH}TFd^PQo6*4xv#YKsUUJG!(*JzA4>1bncE< ztH#}|U9jEm-{VNft|{s7jT+U2J;`{$?5Gj)>U3;Vjoeqmy)|t3LZuPL z9Y$mtGo@?aY!z#|I>p9zL%4Y^UegS%iTavEn$BH2KH9;&S=-*d!;#Lq2qJPo3f_Wj z)taL*{c>G}5>!R8b&0rp*PVCdr$zWViFPw5gN_O9&u|vAW_l}Jl z(n0HQ#}2%>LqbyS@K)7en>i%Hqbng&-}wHQJUS3hP|$`Q8}ei~ZF`@Xfk!Uvhu!FS z;Or#CPa_N$#LF zZDZ5e^%q>^esn;0{pL0Z0o|{vc zT|0Tg$dOwnf9K)ruK&qZi;K&am*5!{+1aCpJvn7hZtn8c2WHH)7B70>_N7<0Ysk$b zF3ZfiY_vJ~v7z024H-0VO5(r)U54(sW#^(r-FsYeEG;g6Sn}*EF1=((*MXN`QTK4( z+>ZVF-@N22>Z-*Xa@#dGFJtH^HFCrhgr;K7ZT@BKFQIn{j=;XFOPrVgM&C`%ty=@I zW2=SCy|KSRzDf@y_3qUlu07e+1+xV=>RQe=^E=>0<9J&-UNpXSpVc&H>y>j1V_x-| z1q-}hRn~W=d(6wf{pnR*CaAa7B)t87-ytWvaWHYf>5Y5`xmwr! zK6Ccbh?y_D)LI*0jcfYLRb6I|Y}1HtGev0is{ZFQU9P`=$DDZ)ku8tNb7bAjh}_P* z(?#ydgN{5q{o1D7-Ax_q>z6FOUrjju4rQgBO>-$HqVCU2PTcB;V-4eh+f|YHbP<0v z_32u^?tSatXFgB5wl5bywyW`N=n&6~Z;?&*B1XGkly%PDUW`Dw>38-U&C@Q#X`qU6 zU(;LBu18mYQ`ivE+s|KXs&1jkytz$pdA-I#r=y#4&lF47x9Qx*sSh}>J$GoaWC?y$ z)^*OaMIdj-yTM^ZU7nXNxw8_J$=Spmgd67Pq27|jg{w}4CylMRooy+5eCe|5uU~gQ zy1uE;s6V{_%kA@9iM#H)ci*kQmzp=Ui<=8$`^4nJqZA|0Lh4}lPE8vm*P-}_ZN4(^ zB+1T@-VPa@rxo{8W}I>Qw0YVzw*A1i?bx1uljko^82Gb8D^6Tl{B(YqH+9^?g=1rK zndS7E$C{cpUpG3v_l0r&ht6F%B`dc+ICk8TY1tJEMqZh=U~Zk~E*VG|Nm@EyvfZI+ zgr;@u_*d))7})$OFtND-I0Vmg?}oX$3OEY(X*XPT%aJk7nZR+)8-U}R_W>s~-vvx> z?hGuz)loNXLG$y##m%RHbu80M^b!5U0C5XT-b&m?+)ms^%aL1F_DPJNVr zoVA=F23cl^7$&|WGOHw!S&c_&1GR2AJ`hiXJq7GX9EiFGYDr8FA&w%BCXQ(?#;@b> zzS@Ck??zxck7V=L>BJet9O!MJR={*2aUO92bTv?02we??PHKVW%vr~Jy+j|;PYe)m z;kjFgTZ!9<+lf1f^_1jMrgszf5cd-I5%&`h5DyX?h=+*BDbERFkoAU$Vd8Vl^E~nU z#2*k}ApVf}BJm~S%fwfSuMuA-zCnD8_%`vU#CM3l5L8`=U5VX@>?75K>7K-a(q5Iw zbQ05pn7&N+tFb&jPFjQ>m;4);hdNQziF%Aj9w(k+9!jPD$RmFt{*}l7Cgqr? zrF`>@ly5dM-7INKleDFnzFP8It0cd5XVXW(P0fg_vNpq3Pb9k%HDOnxChSVoE+dX> zK7sUj@F5Yr+6XM?k@fslIFP6b2NE^mK%yobNYsP_iSUgI*7GdssYFfsC{dH%Nz|lY z5;f6tq9%Gy)I`sT+Pi|(cA^qJCsMLR8uCc23U#LGlBXce+SpMs*vMCve6y~(ub zEfHEmPUr^+%?MsC`K>#Nn~0mCE4=dv`IFF6L1}3cS^-2Yg5!yQ6+{Vwn~-A=W~WoY zaYWJ8AeJzQB@DtmBfolyKBAu(Ac~d-X+fq##IPXSHHhsRr2Z;-DDxo5{3_C$Fpmwg zHe>b}taWc{0QN&K4~8UiM0#*A=0m|u9+`m>2IKV-tAGX2z+kP2>G?dqn0e}mUZRia zCkBWQ5FaG&B0fZXnD_{BH%r??+)La?+|L>h5DyX?h=+*JGS3m>QQ|S;ah7?47$km& z7$Sa`7$$y?_!`f8o%javE#lk6Ke4@k6I5NLUe%r0lh~KXFC@kjg>{3Kunrr9h{C$T zO8R;*=54`Ci9@A)HH?@-97#+irV+=9gc##e@8d+_=U{b;_$MCuo8-Yb6_j2cY;DG? zSB9V;8-VFp%Z89wL&&QkU?z@068s9DAkDLefE%wOy%`J{%GG2jjyGsSar^{uGt$Gb z)(A>lhOx|HEOQvSI*eQ$rU_SvX~NZEns9X(%NfRUhM}B|@Pc=19t@OnhGQm?Bcq72 zHVxOtLWbd-Lxw~C2Bb5Ya|Wax4ju~5CoYE0heML}Kp8K?DZ_BeFq|?BrwqffcT{TG zLflH+M%+%^LA;yw?j+tryq8!{86IHy4-$6~A0j?Xe1y20Qtct`CGI2cCmtXkBsLHa z5uYU(3Kh?5~`6rBD3yrX!`_EdMyQdJ_Q_z4`NvG zYYN`&{2p*D@~2?t=?@$a=A>xpO@9Q=V18NgQ=nl%8RIEh9X=_Vm*^wpkmb{g? zjkuk-gLpUV+DW{JcrUS@HST6DvdX7uG7qO{vZAGEvdX7uvdX7uvdX7uvdX7uvdX7u z&k~Oij}ng&W$dSDGWJt6SpjjyB<+Qk&|YXsj*ORjv7!|NH=TJ8wjiuOV0X;qqi8{m zA~RtlBL65@gX@7ZKaV2kN0Dix$TYlJoq2@qqsX*TT)#$f1|G$cH41%!UpechqDNkZ z7qolR3E)7KoQjg=NM`dc;0$Oi74xkenT@kjIqRlk)|K>JqV!8DB}s)OQi7N0Bl?K} zVm-@wfF(aj+(mqd_%QJi;%?Tvhq#w0b55%EH0zRiI2C;%DD!YC`a)3V;Z*iTswRDr zs!3m@YSI^}&_8}vE=jAt#CYNW;w41skyPjk?X~X2nwVgs3i>=-UTcm&L=Kr z&T^ux-D%LOoaH6@h<;*#cnfQ(XPFPM%m<0Phz}7TCO$&k&06*l_Y(IJ_Y)5g4-y-Q zhltM-j}VU%j}ebk&J)DvD9MY&x8+yN31~ZbF6r?iA+(1h(4M3>qji^IHb?^25xqno z(N7Ej$3VlG!0x!d7y}LW2a2US1{&S~6boSt-psuZnBBAsID?prz8IqwFkRI2D$;YA zXMWT3NH1i1F_=FF?3MD@qZMPIZ7JDH^b!5U0Pz;q_yEs+khqKZ5bJ)ZX%8&78r;tQIs|gbHYc!e$5MjGBaRK;;)&|!#MC(P-cd4 zV6UX-!!jR-`T2QZd2=36^f``m!Z^+e<1jl(IWi}V!|Ws|w)Z&N-s5O{kE889j<)wW z?E#kjAaNJ*A>zZtM~J(Ldx(39`-uCA2Z#rW4a7slXDRIw;!)x;;&IA<2B4hh{bcGtrju(1{!oos5T0BwYmNkB4R&fQ!-6@z9LqmvKEF znvt}Z=p*`x0pbHJ^FiV+;zPuTiH{I>vz9%?y~KUQ{lo*rgTw~nA>y-?=LqpA@fcCA z^v7eh5`0^7VxENjDxNq}@?iYpS8`?ov~d^i+sYW90B)=Y%1E5RIc)-4IstZ${JMp| zZY6FbZYS;_%8WEYlNo6O)?7iEktS%*@!S`QGM`MKy*dFh6l)W}-hIH$&~`c`=?v_S zH8fr8hxIg_^Fumqxpc_35l1r7gXx$VENxPSZ?Xs1FY*o;x6Jt#D|HG5O=foJ;c4leZ>95 z1H^;G2I3*&vy}D-@hI^aQS7mFT$2jEEjhtkvK;AYgGM>{zW zd}u&guGjLQ?GwPoOp67Zr-=odr-=odr-=odr-=odr-=od2j9A!C6+)QxFIN(KpyNd zL9qeyXanTY2FRlgkOvz;YB@qYN<2n9&ip5cVh`j&ODDA1(8emDTtUx<xOlw z0D3qDT!cIY%u|3o4M@wnUj$tVcE{RL1YMm1W`m7I+H|I8Fnu}GR}g0r#f~b1HY8^u z(_&2(p_b=?qT3?vQU1D{xQDoxxQ{4SP!TjBB^)3gBsLHa5uYc%M0^=u-6D)=$^UaX zmsU^_Mz^HJ3Mzt~GZ(lS>%s!GORziGz5wmo2oz7k0`~X% zc@{!HgYk@vY@D?Sy?+8&Kon2fBJ`;o*+bk*+(+C`JU~21Y#<&YikEDWCVsF*Xv+z_ zeNmXa7^7aWA9`>xWmrrZ7DK{UwQ~4cPXT4sE7ydd<@6DiYr~ixgVvSPHY-*!5gt*K>tk&lPq(SJ?Gvi%bF9 z%ebiH%u|O}Z$MhSyLD)FEl|ct9sWtZ;@z#oD~ANdyIY4yCqZd@9ot^Vw%4)kb!>Yb z+g^vZizJUSr(E~dfs=xA-B-u!zB*p_)$zKoj@Ny4yzZ;xbzdFyCh~}Pw@wr9Zk;CH z-8w{92?{If@J0f`?-RvySf~AvC~T=CpX;=jnSPD#r+N^35(i2f>Cvr2KT29gL7fthZXG?kb@b@gDe>smp_e7kADQP* zg7nSSnc|PFqd&He{@6PB@sN}L*gE=S>o7AII3oU7FL~l6PrT%bmpp-ek21aFiI+U_ zk|$pB1bqpfc*zqldEzBcyyS_OJn@nzUh>3Co_NU3Co_NUdE(_r^pYoD^2DnNPrRD&#H$HUyyS@&v!bMh zCtiA_z2u3PJn@nzUh>3Co_NUj;v-vpWQ&h%@sTY)=nvN_WQ&h% z@sTY)vc*TX_{bI?+2SKxd}ND{Z1IsTKC;C}w)n^vAKBs~TYO}Tk8JUgEk3fvN4EIL z79ZK-BU^lAi;ryaku5&5#YeXI$QB>j;v-vpWQ&h%@sTY)vc*TX_{bI?+2SKxd}ND{ zZ1IsTKC;C}w)n^vAKBs~TYO}Tk8JUgEk3fvN4EIL79ZK-BU^lAi;ryaku5&5#YeXI z$QB>j;v-vpWQ&h%@sTY)vc*rf_{kPO+2SW#;4c7M{A7!tZ1IyVezFB?1K8pxTl{2; zpKS4yEq=1aPqz5U7C+hICtLhvi=S-qlP!L-#ZR{Q$reA^;wM}DWQ(6{@sllnvc*rf z_{kPO+2SW#{A7!tZ1IyVezL_+w)n{wKiT3ZTl{2;pKS4yEq=1aPqz5U7C+hICtLhv zi=S-qlP!L-#ZR{Q$reA^;wM}DWQ(6{@sllnvc*rf_{kPO+2SW#{A7!tZ1IyVezL_+ zw)n{wKiT3ZTl{2;pKS4yEq=1aPqz5U7C+hICr|w3iJv_2lP7-i#8001$rC?$;wMl1 zz@r471jv&Bc@iK`0^|v-2k<07o&?B~0C^H1PXgpgfIJD1Cjs&# zK%NB1lK^=VAWs71Nq{^FkS781BtV`7$ddqh5+F|k1jv&Bc@iK` z0^~`6JPD8|0rDh3o&?B~0C^H1PXgpgfIJD1Cjs&#K%NB1lK^=VAWs71Nq{^FkS781 zBtV`7$ddqh5+F|k1jv&Bc@iK`0^~`6JPD8|0rDh3o&?B~0C^H1 zPXgpgfIJD1Cjs&#z*!|gwgkwQ0ND~CTkxQ9ST6yxB|x?W$d&-v5+GYPSa%}N1{~Q1 zl)FL*GzL#@K@SSb)$T3m1t97L(lfjXR{be$6F4I%KKV_|zlr%b!9JJca?f-VJ@cD* z4`>rT^P5nbHsUyH5tMtTn;^NM+)djA37-ebJ<~1pNN)kd_aQA;pj#*p zVm_FbI|W-P)fP&%h4O5nJXASl4#ewVicsXI)OG(cCcMLSl15LwS#r-U|l;{*ACXTgLUm-T{~FU-Sp_*O^@zQrgt)Z57YNB zeJ|7ZGF^|^va?oCA6h+qX!Ve-7)Rt9wq6q-T0MPe_4J|D(}z}1A6h+qX!Ve}Kk|qV ztsaugx#C5yhvb6dL#v16g5pD~$BZW^KD2twc!J_XtH+EdC_c1$O?+ten)uM_HSwX< zYvMzz*TjcbuZa(>UK1Z$y(T`idQE(2^_uw5>NWA9)obEItH(1-1jUC|5ARTKp!m@0 zafe7yd}#HU12+Q2hgMG?TD=k0 z5x-oJD|nDAc#tc2kSlnQD|nDAc#tc2kSll)QZ?W#xrz*O1rKrs4{`+$as>}^?GAG7 z4sz`da_tUs?G9p`iVWgs2y*QXa_tUs?GAG74sz`da_tUs?GAG74sz`da_tUs?GB<0 zkwp9qL9X3FuH8Yd+Ci?`L9W_CuG&Ga*Fo)7)-G3$L9W_CuG&Ga+Ci?`L9W_CuGc}X z*Fmn=L9W+9B@7HI@ht?ETr&o_UI)2e2f1Dcxn2jkUI)2e2f1Dcxn2h`Q$Y`0uY+8# zgIuqJT(5&%uY+8#gIuqJT(5&%uY+8#gW#C11-V{_$c+%W5h6E2+z62yA#x)`ZiL8< z5V;W|H$vn_h};N~8zFKdL~ex0jS#sJqD2=XH$vn_h};N~8zFKdL~ex0jS#tk*L8vk zA#x)`ZiL8<5V;W|H$vn_h};N~8zFKdL~ex0jS#sJA~!)2$L0IvLZ}Y zgvp99SrH~H!em95tO%18VX`7jR)oofFqsf06T)Odm`n(h31KoJOeTcMgfN*9CKJMB zLYPbllL=umAxtKO$%HVO5GE7CWI~us2$KV0av)3&gvo(0IS?iX!sI}h90;@b!|eSq zdq2$H53~2f?ENr%Kg`|_v-iX7_b~fC%zl3ky>?1_j_b&CTt}XRCUFGi18K3p$UHAH z&x_3SBJ;e+JTEfONm^wmX_cKs{*Bs6=0C~&CuxbX(yBj+TJS5a`jcn{(pWuT1&URF602vX_6lo%g|)xJ+FxPqudw!4So4;W^vP zUqBQsHB(E?)KW9G)J!ckQ%lX%QZu#GOf5B2OL*M|^wUf&HB(E?)KW9G)J!ckQ%lX% zQZu#GOf5B2OU=|$Gqu!AEj3e1&D2sewbV>4HB(E?)KW9Ggy;T4OU=|$Gqu!AEj3e1 z&D2sewbU$HQo5GkJXyKGu~k4=yg*pIst>fc4~TdwAmXWjh^GP~o(hO~Dj?#ifQY98 zBAyC}cq$;`sep*50wSIYh;x2%=iU%T|3W#_rAmXWjh^GP~o(hO~Dj?#ifQY98 zBAyC}cq$;`sep*50wSIYi0B0%q8EUOUH~F`0f=}iAmXWjh^GP~o(hO~Dj?#ifQY98 zBAyC}cq$;`sep*50wSIYh;vZBWj7_v1`jj-{sZ<|ouMe~*>CI?eUubVV5O<}4 z@Cg8MR~iWG7l^ykK-`rE;;uAs7I8KaccpOzci(`xD-Fb5X&`K1Anr;7aaS6MyV5}1 zl?LLjH1KKW$6aZpaaS6MyV5}1l?LLjG!S>Cfw(IT#9e71?n(o3S6cN|E+XzqBaOS# zs;}IY2I8)?iX$uH$ci|!B95$xBP-&_ia4?&j;x3yE8@tCII<#+tcW8k;>e0PvLcSG zh$AcF$ci|!B95$xBP-&_ia4?&j;x3yE8@tCII<#+tcW8k;>e0PvLcSGh$AcF$ci|! zB95$xBP-&_ia4?&j;x3yE8@tCII<#+tcW8k;>e0PvLcSGh$AcF$ci|!B95$xBP-&` zig>ajo~(!`E8@wDc(Nj%tcWKo;>n75iTPCV(A%p(VMRPy5l>dclNIq~MLby%PgcZ} z74c+6JXsNsR!a%Oig>ajo~(!`E8@wDc(Nj1>=5J;R>YGP@nl835>~{M74c+6JXzt! z9Gj%vm?s5scM*uYMnK#R0K(U+5|}4}c@mf>fq4>`CxLme&k5rt3Hs>_M1&y_-VY!m z41r@%dy+&L0uf;dM1&y_5r#lS7y=Pt2tK}QVF*NoArKL9K=?+0@QncB z8v(*M0)%e_hzLUk5WXfL zd`&?3nt<>%0pV)`!q)_ZuL+2FEj1qF7soMjaRhpUmZ-PM(A6n58OH_X_+%N;7Vdd9 zzY4@&LLl}M0uFa%=f zpe6T%AR%V0&WIZu*z^%FvH66=UZY)iB0@&egNZ|UWGK_ah{K5~MA)LpnacENrqh_7 zfVST$+yf%Q1US2SBe0-(6|jiu1w6ixh{!Y?ucIVhqL1h&28bJ))+5g?%n3^sX;`X2 zSgJtSU_e-^!22k}{luquWzp>x4L#JAXm~i#B?~5+@BoE|?%s@y366Az_E~_()pUdZgz@(gu#-7D=00_w+|1 zX-n%iF(R9?wJsCaM~=s6F%w^kq+_)n6aU7vyzlUW3Hu^xsVgy(*0sLrjyy_9U0Wl^ zO|5_WGm*4~at1}xw$^px?U8hh)_daXk#wxqXHqQFctMReU_v;Omby|RX%lt55lLHG z_lb@^b;#d+;?BtNSgqTn{!AMvr}u>SBWb0@rjLuHMGt?9q%E!IL`PQ!%IQ4uvB+_> zebNY~O_X!dgr-PZsrtBwUIP-si)UR(k9w#MADXa(Zs7FX&c9nMAD+?-$l~s z_es;R&s~}FUJz_CkEE5>NBtm@*74efKSa_7jyFZprq)Nt+u3=pg)|=P$F!~W(yxxB zW3>eRwn)08HeNpwNq0^hZ{Ss5%-=;@IsR{Wa$Kdh8V_fx!b6%?Xe+fE&5id`m0)+K zJmYHw{-q+d6gk}5ROG4As`07PJX$g0C6jS9N2@^o;Yej@W%%dD+7vCTn%_J)$Afd$ z0GA=B>pW_`3}-sE7NVv#sOxG-S^*hFj$%mquhp1|y06B0bMf{GH{@N3w3H^YxsjF@ zxgmE2a5eHQMN3MN&kczyQF}3eb7|VN%GK9Ym9AJ>q5vlH_*SM#a)>PM2 zd5X)E-8mH{!`&HWW$psWRqZbDRC}t{c$N)!opb7Ca%y4mn)0hFD^|Ft7O(u26Ei(m z7tgJAm#i$VSmCL57gu@Qr4{bgwM)xNOWeyU%Zp1ZAX)n+&S3+qao9O|PH_dkOhscV zHM~P$YGozxd`>x^JaeJFDrmBleI(4m&Pz?3>#3?Pt*mg58jde*%Q;IpN4B;Z+<5q% zbhpsW4Rq)hZOih?3MjS)>efiv8g$usIG<9`Sxz^vK^G3kxs~`^g>Lk)yefA1aFpvo zncB*ln$_b|QkFqMYifsASJqaQc$QaIt?&%5@Zjg{HWEY$5*-@n4h0!DLUWb2#SkU4E~D6f(_Ka3WvL(qweVbXSQ|Yw(*)e)5qiR$5hpUu0=;;jgryhElX2 znZ?K@`Gki~>CqA-wFuK}r`rlt8jtlpEE_TBPJ`nU!Rr70pP0w{KBY&#gJoQll{g> z&m7H0ON+Kqe);S+MSEM;328wq!=$Bd$aB6Dw6EuEeVjXvsyP;1a+Q&A?|CumHd2poAivCEw&IHrE34QIF_aS}*z&Y4eab4`mkc?{xew5;#5KNHh(( zW}$A$F&%OhQVUX(v`%u0RE79G1EtFOQtK7W<>*j!BE2lKw3Z^*T~fCrha11ojg%)G zkoM=|pXgTFJBKx7;pj{pbINr}m8&;tiO4P5k-nGqiF`TuCN)gOZ%(g>K6Cj^ayoi* zxFCIsZQ3YDdRfkwmWW22-jTd*TOxgYcJF)=J6y=+)F5R^zlo-DS<4(~HVb_vB{@e# zBf=|T{xr0pm2nR5Mc>i9j{MR;dFUw%p{@*r(B0i&PX_WPI6}XEUas?LavUiYt=Z{ zv2>%?ea<@HYTGz#Pg}cFv=Lor+FAmR{WKk`kz55j*Cx??tw)`!C1=fQy?T=}qigcH z_JDBIaV<)|R;#zw`f#jA=bA{?L`QzHh{Qg3Y(TN~9IHguX}Oklq^qLU?_7~auT~u2 ziR6$~DcXu^$S7;SNa55KwNqNla_maU=hP+|cBGL~9BoD|gmbT)T$Dv}Mz0Lzid3xs zDwMO9=^9E^f$znT!pSRnuEqE0wMtw6PgMHWK5%?9XZJz0E$8ar)lUCn8CHWq&b3r2 zH7xeza7ZLA6G@%xGN)$wE*e4wV+x;D}i04yQ!BqHF0r zxz3e3;ENxkmK8uK5J{2MHwbN>|8-e&wZKx zAgT9Ue~`n5|DHccq;R}bpJa=-&J%4d`4VzC>Oqh^;+KeO?A)=|)|(jR^11VbtcxekJkC$;{T?Kh`>@|G(u|YV|P4c=-RHU&+;Oh5f(tD~TS(6Z603R}%l_ zxqhYAG5z21E4e;^&GvCWtm%0D5{YtVbeEEK**6|kg63N=10Gs%eZx<&} zRvaDOOD0kSXho%>g>B2PJ0}S=|AgT5-;4RX;-eIq8j|)_A;5;rOfLFLKFiA_Bjdm0WfDJ|c;wE<%OqFk z{~0fn_#iUif0~IG)`&O7@#$s2FY({=9m#d!xt_)UE8mgpEDxBhN&i>ABUu|i*>@E6 z)wKGA9DmP$!gnN0ZS|Xdw(m&BkMKx*WdB{?QPjKt=_|^)9-rv_&VR+@BlSc*5^|sS z%kuch)sI9aeKC)Zcy(m<|93q;F8EiX5kH@%$uG-8Q*(}GH3h7RMxMCnm6315H7%O~ zS`w!wL2@m@aqdg2Js$T`Pg&*K!Nc9>5!E)_J-zIj)hnyrrRA$Dt7<&U+{>#f%iS4O zo;7YK2rOC$qv&d#D7v=QxLmEZBOI;R?TFSAisu^kng6-Y4ca^Jc)vF7X3eG5u3~ph zRq--Ud2!V$cjfZd3{KRb%QeeWRbE=nn7Ptw_exKd2LXaBs){Sn^klRh+QVsx14NKo zvb(0zU0iXEdo`l$5M)=mv<7j2rBFe!y97asF669P>51y8q@=QZHL^>Fnw2OWv4ft9 zYV=S7Rgy3mg)MUzS65e-loq2t*Rslz+Hy}tO>vFH@GUPbL+Ih9QX)@qEqvli-4 z7)(j3JgciJm(`YdSj@6gghQ4tt*!Bh3@)jm<%DDeFP4tw9XLe&SG@c2-t^7gg@^N({J9YPP%Pn$@1=#i(ewBUJk~mKR@xL5b6sl`bz8 zq7|3bfO<%v(Bfsw*mCNaVW-7akh!+3xXLB!TIQ)PT~R@GuW-gHP7;O|m!J@g+=>>h zR=dxtNt*3K1yopZnfnt9h@2CZqqQ`MS5bD2yR;3>T{0b1c`Ay_o!*i}wHu0*eu)kb z4>;$kVmWIotCm%}6I!N-1ZlCfN`7!9$goYI%Fr{pk@2$BgOMbq)}jxj-_}%?k{WWJ zXI%|OjJtUCY7DR9rDdRhWn{`h$)a{wbljkx;u`nL;%eyLQ_-S*7K!Rw*}cqNTd^!6 zaI2^;3g>1EKdV=(E6Ze5yH}&zgdD|g^xO&*R~;F@_@!i3@e0h#7>5;=E*Wf+@%%{@ z?N(NW2@A2%p0ed4)Ql{5c79%=drp3K;k=B3EO*Wv_pE~axjC6xneK#)IryHC?4FlX zI3vHP(2X1g8F_^Z-1*t=jJyTzD{}HOligYKXBA}4nd8bYaOcdNm79}=V>x-#a*Hx^ z@}|3|;=H{4LU(S?%$!0LTA0sMBSqz8&5^=pW))1Efs!+(=H%uSE=YD|=M?6lObA!t z&T!AlC@9RCR+O7j;GR`fFe`sf7Rty(v3WUp*#)R2Yi1T2fr6&x&stEBGkr#3GEOSQ z!DLrqK}KfQ%#4C7lHDjQA5AWBGs|#Di89<-bLHeYGcs~>-BWW4=M)xXWz3YkqMhk^ z`7^Uz+4)6znHhyS`FZZCS!hbe)Lc;cB&52eb*_`IIs>3BG zOwY>8D#*x9cF&oWH7!RH&|^+P)-*^B#Xi^wZ| zB*)HW2Xe{T5iMqBW#pnjkR(s?LQ8F!1a@VuEAgzxSgVc>Zf9!bH0sQqSeP&-ok;+U zo?d~0>l|Ye%MwNwmp5m2YncZa#E)5Cre01Tm>#hbIaBYlH6F}>)iT>xR=Fx=GFe-S zg;bUmSSOXvn&+-AE<ze_eDBx5G5UX4|%bd9I%n&HS>C2N_;i&+_g?&XoD zb8alD86PzjYTPSCQ&{V2TnL9B?smCoaf!6m?rG5t5dXUAbiVr?z8pIU)>d>b6NN3O z^u_0A2f149AgJLB*+DK@8(L>^cAB%qmQe4sIz+IRUUSn-Y{!XY*S}*cIa@?vE4fHq|A6ToIFrtL_&wnOtX^OztmYGPyp{WODy2CX=f$WA4n$^TpE3nDK?IBUh`j`0rRp zu808!bM@b_j$Cc6BU(WJvUTKgY|OK)qxN?8zi1tax!-P}v=}~e-TBFek7LrDpW);B zY{RF;3-B3+kBg3h0HavT7LS3nu1#ucm8Vu@iKqn5nW!!b;Wa{uFzP--B^kBV*Lu*> z3OELHpz z^d4Br<+T;1+H_AjF7DAI@CbOyO0Qnk_JjiQRz%OQZqX#R4C9AtZH@xFTTOOK*G~1ycQ<Me~%l=5a5L^p>XSd|raqya(?Y`h@@N2XRm#m!X-OrP+Aj zd#u(0!A%{tPFiQJi`ErSs_m}z(0XdUwBA}Dt*>^0cA*xh#cLO7{j`g<{%|}G!0qTu zw1HY8o_jk8TmJ^*Nh(7Tq&W=3F$Me9M`9OpDxRg1rd_6u!EWSn2s503H*8JRCTWwk zDY%U`6*u$b_DD8vqs_ogt;-P%o{L*+5~Mv#n~hsJ63ktM+iml3GjsvkvIy@f`igd? zwnV!M&hWk3gLvkJUptB?s=SXUUVL4FaJ^oRZZD@9;&D6rF!GJWqs8J>OvKV=R19*eXK50{nW*(zjCVqDnVVM@b+;$ zJ!p`+R1H=`)KKl8+UqJ=4O7Dv-kPdLs!=LcjaF&uGBrkxRpapVoL^|aR1;LXny4nJ z$!dzqP*c@3m8r5+wwkVHs2uGH?MZdHx;9BDGk3MO~?usH;@5TB=IaGUZXr)e5yzm1@tbtJNx1rpmSVv|p*t-4NKuhy%tsT_NsmAG4;55LOrRTQctV>>VP_^8q^{6j5@5IRY%lObxa*s-&QA7P<=;*)OS@_ zeNR27o>$*jKTt2IAF3DCOX{S0S-qlORXP_{QI;GxLKUF_d@2H=v zU#MTIch#@dd+OKfef5F*Q2j>zR{c)>Uj0G+QT<8%S^Y)*RsBuYen?dKbN`-c9eW_t1Olz4YFCAHA=BfqtPL zr^o9T>HYMJ_5QkBAD}1bm*@laL_J9#q+hBJ)`#dr^<;gRK3q@HN9ZHO-meS)5@Pt+&rll3WjhCWrFrf2F|dbU1YpP}dImuo-Key(4k=jt={JUw5Z zrO(z2^f`K=UZl^}=jrqH1^PnmE$x){Hl9@UhW0akk-k{}ihiZOM88Te)|cuf`ZC?4 zFV|P-EA>+SYJHVnrkCp#dZoTv|EgZ4SL-!;t-eNItFP0q(XZ97)34Xp>tEAv&~Mal z((81u?$iBxK)+evpx>h3s^6yHuHT`5UH^u@QNL5)q;J-@=v(z|`gVPX{!RTZ{ce4y zevf{yUa#M$->*NQKdA50AJQMzAJM<1KdSH6_vm}|efneifPPSK z&=2X)=!f-Z^&|RG{g{4S|F(WY59;61L;831u>L*$IsJM4`}z;`7xW+MFX}JpC-s;0 zSM*o)AL*~@Kh|H@f1+kCy=pSnJ z`fv2#>c7)}um3^+qy8uT&-!2Vzv_R}|E~W-|49E>|EJ!lpVrUlO*&o^rQK~PLpKb= zG%Uk5VvJa$gW)nd8l8;JMi-;2(aq>?^e}oFy^P*QAEU2vfpMV`XT%#98U2iljsAw) z7+@qAmly+$L?g)_zb@hFm5(B7`GU=8n+p@8+RCAH@;zP zH10Gu8JmqQ##UpSvEA5VeABqgxZBui++*Bp)EoC1_Ztrw4;s6Shm41fM~rV7j~cs; zJ;q*RpYfRSxbcMXr16yTw6WhfU>r0Wj6=pV#$n@G=Xti^faFN#kYX72{RoN5*T$kB!%jpBQf#ZyIkIr;N9apBg_i z-Z6e|{KEL9@viYJ<2~co#{0$x#)rmljNcl+Gk$OU!T6)`C*#k?UyQ#Re>47W{KNRj z_}KWT(P*4D&KONbv#FWN)J?-QP0O^+7&F%FV7knXW+$_=*~RQ?b~C%1J{v%l#!2bc-wCFVdg(M&Q2nU|V_%^~JcGua$w4mVTG5#~s9 zl$mOdHq*?@%rWLzbDTNeoM5J#6U|BHWOIs{VNNxtnVDvmnQcxtXP7zW<>nP;t~t}p zGxN<^=4`XToMRT6Mdn;{o;lxKU@kNlnTyS@m{*!h%&W{|bE#QkE;Bvma&v{b(kwNv zHdmQtX1Q5mR+_8LubNe6wOM12Xu_n7yZ_2zx% z{pJJagXS*tA@gDL5%XK-qvmdNkGa>}XFg^=Za!f?X+C8>ZSFS@mShcg&xgzc7DkzH9!j%-@@T zF#l-&$^5hV7xS;?-^{<8|1du?KQ{kqHkzl+GiH<7Y-yIVbjz?z%d%`M#)`E%ST3uh z)ye8?b+Niy-K_3b538ru%j#|QvHDsUSQlDxR=jnQ)z7-v>TkKN0ak)_i8atlw34hr z)}_{9Ylt<}O16es!>tr+gf-F{Wu;o9tu*U0Ym7D48fT5SCRpj#L~D{Y*_vWySW~TO zR;HC@Wn0s&8CH&Uxpjq=Yt6LstbA*hHQOq%=2(SRku}$vXU(@3SPQL1)?(``)|J*0 z>nf|*T56S8%Pfzz+*)C+v`Ve3tyNZ;Rc=*SmDXzOt5%g&ZPi${)*5TAwa&W6y4JeR zy53rEea*VTy3xAHst<_%b&GYYb(?j&b%*tJ>l@Za>rQKvwb|NYZMC*p z+pQheH?6y@yRDtpJ=VQey>*{;zx9CiptZ|-$a>g%#QK)?sP+`z8L`{iW9`M0_Zqa2 zwGU6@JD`2ndJIok3u-r8k6TYzPilLtr?jy3w6)(lU>&p?tV7l_)?w|KcHDZ_I$|BQ zj#^SV7*}d(0b8&$vSDhY`tQ=YW>K1&HAzR zy7d$54eL$oE$fu^w)Io%XVyE`&#hlrzqH=9er3I9{n~op`oQ|o`i=El>vz`gtv^_Q zwEkrM+4_t1SL<)q->rXGA6Xw;|Fjyd)7Ba7A6ApqY-_f%b=$B_+p=vt#*Vc+*e<)H z-O283cd@(L-R$mm54)$`%kFLWvHRK=*caMycD#L&-Os+*?r*!b+wB2%f_;fS&`z|I z>_PUW_F#L6J=9LNhuOpJ6nlg{(jH}}+N13>`!aisJ=Pv)kGCh->Gni>l0Dg;VrSS> z?P+$Von>d+)9o2{j(xd(g`I29wDatIdzL-hF0kj=g?5oW*Pdt3w-?w8?M3!t`z!X9 z_7eLlyVzc8m)Of}kG)*`gT2CDsU5LP?W^rou;d@I%j|NyLfd3l+NvK_5=2V_AdJ&`(gVL`&;&- z_HKJmhw9}uD-j>#sffuaFD|L7tcWRg{@NM17+d49i}@!eqY@Wei$&fkvHN=mD6 zQ)79VXI;mV*0gIHZuu0KATFfFRnn5QGfRq5w7tyvlZkqYYhtn@6(X2LDz>wn3O)Se z%4#{=&y1%~#gui=FEzsEmKi zT(sUS1K4@a`4!Ijd2LSVRMF;(o#ⅈV8JGcy%ShawBdcPC;i*^=lOJh39wNqW z%y$}J$v>U*SHg2rTvc0MhP#lRE8Bjv3mh5XwLw!l6|||gQ&pQUc7Y>9mGftgb5=F~ zbez+wx{lSY=}v`h3g}eR=8IkE6jQ@LW}$RxjdW>|)1|demlj1@RU2tlk<+SL{;`Ux z;BT^O1v?kDZByskw%=lkB3)nW{OvfeRl<&I+oTt?Nng{Nwih~Wy_SDm3tPDR|2225 zL2?~e`R>fz*~g4zNtWX{en?h1eh{#yU-Jlw<$2mB#xjauA(YX`yV7nfY2{t5<;cMv zJEo{g0Y&kHg2cgVK^X%D1ql!5QJ5bP3<=>C6O$?^s^UDLibtRb75TAzr_Xoq&Pqxw z6Mk@~Zl80y@9op4Z}&N;``+%EIgz93A?*CNJc+5InrYSu4WT7;gq|=E)(IPgO~Mvo zo3KOJCF~LQ2?q*W|=f&kp77kavf?JLKIV z?+$r)$h$+{9rEswcZa+?ONqwyZ3!<53!HBT1;Gu{AA? zt!Zg&O-o~IS{hr^(%71o#@4hnwx+dVYg!w&rnO;fS{t^ewP9;o8@8skVGa2k@;Bsf z$ls8^A%8>urcr(On0l@*j}a=7VMz>2VptNxk{Fi6uq2ixu`G#YNi0iZSrW^VSeC@H zCM;{hvL-C~Tk^N$Z^_@1za@W1{*L?|`8)D=4xEJk^<{Iw>omr|gOLbw`+kQYl#~AxkA>se~+*j2$$l@s{ra`J#0HbW{z3#dhRsb~-vUV=>zF9F>5h z5^z)kuGZW%k8NG!7sq3FY5Q|j1&*q~Q586<0!LNgs0tiafukyLR0WQzz)=-Assd-U z4xG{U?~JxvM+M-h02~#7qXKYL0FDa4Q2{tA0B3C#9V{*ySQm;~z)=f0Y5_+r;HU*0 zwSc1*aMS{hTEI~YIBEe$E#RmH9JPR>7I4%8j#|J`3pl3@!LegFDgj3&;HU%~m4KrX za8v@0O2APGI4S{0CE&bva_3bGInSoxwIMoB{+$JKd1m6dC-oK#k>!E!YE>9NHli_4p47x1O|GFA%+ zHPb$H6kquWIz7ZEoO5`MIjr`NE-%1Mj?q(ntP+UnH)Et4vFe_~3o>+3;*PP4XZ9SH zx72d^)&*R?fma%Nl{$0BhUtw%3?;SK!PzCh(hno42!849^T0~NFnt%^;|?)=JG_5( zSopz}!mTTXyB9EsiX|xAwou$VznH#z;o#w6@%G`$Bui7gZGNHH#d+KELRIp~N^%}A z$mp42UIEp)F-fLS02N#0h}iZOP0wzPk!ifYv>%tJ2SuoK7B7*9lgz7h0trP)#CL}f zNis|Ciy|G0B556Tx`iVvg$EZV7ges}()?l>U-=&%nlysqF~~;#MSP=BycZ{mlj5t< zgTtz1n-%N4(~4PTp0T)9CPrc=-W*XaMz2zZYj=rg*Z|Z0W91Ve^A#gMVj)uU|5I7nFM?>If2pkQ8qakoK1diURqj&0P z7#t0QqhWCLP942dNAJ|pJ9RW1j^3%Gck1Y!I(ny$-l-d~{}0&j2JHU>_TK^f?|}V( zpiYRd)uO34wVHJq7EF%W99vKId0fb`dX6=6teIo#PJl-}=SKbEYrX8MddAE6JYSRN zX7b!jo}0~cvw4YamP^g%<+OQzHZP~mbGCWTbbC-vm*?#AoL!!?%j?4BJY3GhFTq%6YVM z9<7{5E9cS5d9-pKt(*tvJABA-@(__ckp%9oxZL%-q%%k z_`2#2Usv7X>#93^U3G`AtM2f1>JAQ2d|o>yZ;d9eSCh9(!}%oNU^yBrM}y^PupIOq ze1qj^upAARqrq}CSPsso`KHijk)_M!!+?eMe4I`&$+kEycIH%^bI>_2sejm%gIW^BYHP1OU&p9>EIW^y+>}~bO ze4Da!Ud?k}&2wJOb6(AJUd?k}&2wJOb6(AJUd?k}&2wJOb6(B2SqE+M=U~)xFzPuN z^&E_P4n{o(qn?9N&%vnYVAOLk>NyzooLlppTl1V-^BjnJ4n#c%qMid$&w;4tK-6;} z>NybgoLlppTk{;4dJarI2d16_Q_q2^=fKo+VCp#_^&F6T4oE$H7S92x=YZ66KK$}>A84%E}ou?r|077xp;amo}P=R=i=$PczQ0Lo{OjF;_10~ zdM=)xi>K$}>A84%E}ou?r|077xp;amo}P=R=i=$PczQ0Lo{OjF;_0~r&Wwecw&cK> zvA~(Jz?reYL2=-qIB-xLI5QTgJp*UP0*Awa!{NZ;aNuw_a5x+|0t_4h295v&M}UDN zz`zk;;0Q2q1Q<913>*OljsOEkfPo{xz!6~J2rzI27&rn9903N700T#Wfg`}c_7XS( z3>*OljsOEkfPo{xz!6~J2rzI27`*o25LAN%jtB!sgn=W%5LA1HpxQG8)t-UVRUxR> z3_-PK;D|AB#2A8Vj1b6=o?qa|G1OI423o5?YZYj%0{fmSNeN(EY} zKr0n!r2?%~pp^==Qh`<~G}TH5TB*=%N9%)ftNk*4?Kyx^GQcPqV3Z6nK0(0v1Oej{ z1dKTYMmq=?B?F946fizfz-R{nqa6f{PZTgdQPbCnBtY`li6qeEuMok#*r{yLEan*4Pl2{ifZM3U+2L=qt7*O_F{lwaqNKvRC5Ljq0tbq)zM<<~hR z(3D^2kU&#@okKExokIeo{Hj4fQ-0MTpees<5YUugH3(?RuNnk2?n)0g#0ZsW; zgP6W*5J1YW8U!@uR}BK1@~Z{`P5D)WfTsMaK|oV})gYiLziJTER}BJ4`Bj5}ru?cw zKvRCzAfPF~&NYFi{HjqvQ-0Mbpees<6ws7kePPpA%>qdIRkMJm{Hj?%Q-0Mfpees< z7SNPmH4A9UubKrkf?fD`%)hlG~1W@xS-j-)W-$Q_N6{9Xv(KPuIa0f3rP9Y#|2IK)W-!)`P9b+P5IQv z1x@+X#|6#$RUa2L>sNhT(^nrCkn*dK3!3t)j|-aetB(ts@~e*vn)0iU3!3t)j|-ae ztB(ts@~f|F`s(WfQhxPyK~sM9bwN{p^>sm0ex0KOP5IT+1x@+Y(*;fW)zdY7^>hI# zzk0f$DZhHUpeet4x}Yh)db*$~zk0f$DZhHUpeet4x}Yh)db*}RFy;4XM|*z++MCqR zMJli{a>p0Y)hSV=V(lDFI_G14cf8v6cZNAHZ14 zfRPVitYtubtyed7=s}sCaNr=&qQ5Ck&T7YP&6t@33kR_hZ5HpbqqBj+WZ9egrnpN9 zUI62Q{f9Q)zk>OD`37wX`zA=0AcI(Oc(?5~<7+g$)WP>qbJz}PY4fq;i({l-t!5Z+ zz)kt^!V&pgY8mgzjxaAZo=BzGYCJ(xY&D*sJJWLy-iz67lu7edbBUDLoB&xWHJ5nP z&WcuZ37QqHW)d_jSj{A8Reqnn*7yFf+l}8Pxyj>@~Sxk%^Fp61e!If<_I(!lA0sXvAY10 zkD4RU86VcKI=W~ubaD@_zpIyK@xfN9zp}K* zYsgKF1FogCY83GO1)rW80epYKr>9B~-(Bd_$HZXFFPj#u8_RZuNkOKl+(zAO+&P%K z`M}cfKCBImoe{Ti#~cHs2rceD>i)ghaD}Z_VNbJ(e$cE@$&87rG=xi@KPhy zYqmzcW|99 zEbAp~*@i9Kuw@&zY{QmqLVFrn%*o%X&R37k<9kZQmn#Rb?v!|S89L_(3FfcQ#Hd4P zjXH#Y+S80WgrN0V8FdIjQ*?C*L2FMl>JWm~o@Ue`1g$;5s6z-^dw@}g&>HqQ!yaeU zAw)c%J$s;G4>at7hCR@*2O9Q3!yahZ0}XqiVGlIyfkua#mLC`bY7aE*fkr0TmzEZf zADTOGY%*diN3oL@V&ax%nmD_7{D@-v@$eK|IXcT$qrRIp>bn85s#>kh_-1Pf3r=AR z&{Fksw2}B^tPTM!s;W9%hPhZ+z7GvbTMo*}i?jt<(?xS#lzjlvScj_3`L%)N*9I0J z1mMl_!9#d+eBc;%U;!3oh&gd~++uc|v^D_G2Edtdq^myQ%s6OOL7W)}tzEIM9-ytW zvp2Of4>~!FVuFqh3ozyj7#r50qtyV&bR7wU&e9{_0eph#*+aMJH?LDYzA;bR@+nz* zyL`i(-Y8#@%yjdwy3?+FvR#$$O7S7bwf7E}=hBW?BUs2oxZxU~e#mhB@@q*XJuFvA--Ynjoc5j#0OMI4p7kFbVKFbG|I_D*L zmZ#v3*Vj+OvwI~zyI$}Xua|pUSc|Odl_%n=9&+0hpW9_ontfO;zZL7qufcB?E7yN0 zZp*rq%wtvV1;JIvbQEnSS`C3&-rL!G5G*iBt4moup;SX@)+fi z`jdK@`VOn|QMh<$UqI1Ns5Tf-WL|Z_J zCy#I{hWLki;MEvzjv;yrVzwovQ6k4`)J_O5jQB;#)CjRjvM<5D50ZLmGBW}lV|K=v zUAxy_{r%^lkp+&B0{ARofv^Pl3D9N0PXbO6&H#Q2bQSO^z|DXs0j2+nmM@JU>F%|) ze?{I;13v%U+H0Usec-vZQ$GgyFwRGSj|2yN1W@otfj@@(Pt8!a+39^*HzA#Q)f1?}sEA;fa)SRaLISs@OY|%do-~f0?m{1L@M^vqSR9j*Yl* zk)tq*U=`u+wU>YDxwV&nT_Q>kN;pwNAXmyM@=1B_!TFmw{{iVJV?JekKn zCjq;Gd_R6m*x96qr$4~&0qkvZGxh?Jzo|Tdy-oI@MeN1zVeD#hXEHiV&CZ}rR?oT< z3yL>(XzLJ*ikd;)%9GJUTKMV5xnC`P195SGA$&l6MtP=Uk-Rw4o&D zQYX^iUq5fv2;)+oOWq>Jdfr>U&C^la`Q7E6J^5`>w~5UhKhDg1d)(JYHKDZn*ZYax z%B~sDdE=8my-qRg&Se+l>^ z&VK~{*MNV7^IO252mBPySAhR1;IlZ_fPW6~PXIp)_!+=I2mCys)NY~1BA&(&dONnDjn<3yt9()V4O!crz82Sh%R1->;!0?-J_+_> z(R?Lu$wzF0*r+2oe;((vIG>L?jy4K-2|GRQ!td-hN=u2`(Bsx|?V}Q_Z9%bf(CMfN zsm)gbrMAT;CV*cC{Sx3;G^5zNgFVMrJ%jPPJiLhgrP9Z=a^4*zx|Ti|7iccjOKXYhM-mINqexd`$~?~`Xeen{HINRv9+ zn0DzId0sYlqsq4<*%|M)W`Tn4BsBZcgFCB7A?@H%i0{7K*~ z;BvNszXK3YFX;i_4fsx6^9=ACfXn#s9r+j6UU1owTETRq{yr;^blMS8_Ra zDcML}f;~)dCL`=*a)pNFo%rp-UM6y0S(dsNsnxnlzCxka0HjC9TAC0{;&1xH1Um{= zB7O^Sw4{krQkcN}6~T?3Htv$v`4W3CDhnf;FqBN6(Rejz%RqEg1r}aY^x+Y@vC4D#>+3O zpk?g>etmL1;&o7BewAcjvJde?{3;l^>_?vRcfl3xZa9mw z-G>oO1-lp?M!1X-Od5AGEMolf0AfyH1XICYh7X}Uk77r|O7aW%RgzEOSHTW++Ynw| zxENux@HT|K!u1GmEDR8SxNy^`f<4$i0(`abQQ#*FPXT|r@XH9FDLj)@uwU8v2!E-# zI;vn_F2rNcrxOTeo^uj=0WBpJ?ESNn%wX@I5%9;;4+4K8{c+$=r5{aF?B;V4_|xgr zTPxVr=T~-AuxAf)juw70{aE@j#D6^fIO0DGzoCNtcs>U|;&0N=BYYwKLQ=wRJb#P$ zFQ#9_l`p0*;>s_lUqb3v(wC6>)%2@K{aX4pq<%g9I#ORw{|S6C2Ro{ii|K1g1-tA_ zA>2~NGsO-&s1xk4b3u|~mz_5Ozp8u@!aK{iAiS%5S5m^hH+LiTK>0n0IaofpwNjoh U&+n*UH=6~-JXU^;v)sx509?c+)&Kwi literal 0 HcmV?d00001 diff --git a/release/datafiles/blenderbuttons b/release/datafiles/blenderbuttons new file mode 100644 index 0000000000000000000000000000000000000000..d34acb7be0408739fc11320407a7ada337b11a48 GIT binary patch literal 66284 zcmX`S1y~f{`v*F^bV`YIcOxZ8gMfsTbeE)b=h9tL(jd|e(%s!im(tSRaOeBK_ji}w zg&F37XV0ATzMnebN}r@LP>E0h0KoVtBdG!aQ1C|xfQ$%!>x&yV|L@32MOqxF7$?~W z4-k#zq$Pou|GskC3KPIHDE2a1P5^+0``-%!q-79*Cy|^#DtthiN5O|;zRA~$qXGa5 z;G?A2XZNK;Jr8f(-%GyZrYG%6sEPS3W=Z*GDSe1Kc)|$&_>zfCy2RMJX93G?!>`47 zlbBKeFr`Cf(U6C!SbxHl7ONTLa+PG!@@W;)xtD2DFP`Fm7UWwdBf^hePzc|7fT1-@sByz+zZ{O_{=yOtR6 zz5NqP{@>d=@V^U0o^dwblgX#^M!Pdx+?{VXMAM#*T#Q%)&ftNc_MM}nqlK|C)!F>O z6Z6UC{)|3fyMCKzmjU@reXDBWCl6M3Vc};x_6ZZXjT7`#dG!N?;cZ7p_7tbSh}RTB zSbk$38UwiWpCrG0`7-7pD?4oPSMPYmrAF)nhofY-LGzeQcZ0ai9<1I_Ia+UUzQb#x zzRyc-;P#9!8d!<$Z+6-p@BO-5&v-bHCmov{L&E=dSKpm5QQKv=ZMgJpY7{;`J`^xE zF@bEfD^a;bGpGA+&vLnG9QQ{Puky~Cz9n4!WvM!LHdn3_pOK;Kl#!bH@r8vt$L(Yd z5BQYvPR!e3wf}nm3SNRtI3|h;XBxc~_?SL_l0xTEx$vG=$R z(X>`ARH?O=YysNAKkl_(uMxjg7%$g^!$d_8e+Am}0MJzE} z2ISuo5?(%2cam-vf+NCa7DW;-+DhrsfQ=u}Inq?x>yC4pS7 zzL7c<%W)NszBZWn{EH`r-4H1cQ2%wgVBxZ|f%7@gBO;z!`ddFY$NMw5PS#AEF!;5l z2jSTiwKyR^JM7e2%roq0`l_uTs!R>PbaK6^q z|LMj(9_CCRGt^SWID7x?!;9#1fS5zk<1k;Qe8 z?(gs80qPaHi+jApwfk7k8l}oq*2^0%=DmyGXP)SGvONlwulCWVukz6iB%#Nb7x$=^ zmX;8J3?6ICz8Ob!ZK=+hc_pdVxlbje%?vM!fJdq<;3Esx>77;JcWl%v5_X!&QCWF9 z-+huUCof;$=km@@QK{13jxqC>2lFSm1~@JBApshQ zo#UDBao@WhhBfA3anqr0$UHYV%Z~cpKBcW^Enibj;t|x^w@OEk5{f-U{H)Y#K?E#* zm#CGWT))h#1vVy73QJRWn!Ysw7romk+Ue&nq~~s}FU`7auTq9gnHq-HO`#)1My6Wd z|HX-H3r0>xlZ%iI#FAI?>(`i~sHmt|#c*+P5q~{=M<5t&>lf22;_z3pcVNJac0gkv z_IKpNr0o-5Kmp4KaD|4&ByOC~ji{f$LaQzS-~}5@?*eWiIh%`ejn`|sdt7teB$RP7 zh8zS+N=mS|JqXT{Q8U*6tw&<32gjz2g@=!>uC71m|2Pa3eQ)a!$hw%twwGGT+6%bP z;$vox#1W56Oq3+LXmyp(6iD*D`mGUNa`EfeFD1a_`grxhE@m?dlV))D%-tWnH!qqk zu1B9V9M{}0Fxn*<@X_FZh=wSNGbrM9p1FI+aBLv2i+c!C$5JD*PW(W_LmkuzbtCM} zOLJs!)RRh*&7a$M{sK%|)vYYsb?8alUhIr{l~*4L@$=syJlvF(mA!7?lZawI@jDK} zBN!ezlWG{ZA6;!Z3SLk_j@c6NytF9RWuyPEFjkN~1@qJ_6n`u~SnVpCxZpgv@Rm35 z#hb$K#hIrS1NB;Rg1L&ty@k)|jS zlFaosQ8wRYsH0!WRhlz(48L^O?pMh3!MBb+V}JF^t3ARa?7(K_z|m28(=T7<-XaQm zu4OFUE5#>lPQAAdd!+xA5f+U0W-hJ+#(pX@K8TIdn;cMlvl-4J6rm(kAY#!^%+Rh2 zFHkT-z9!pGyulX>?e0Dlvgo27-_ zOaT|B?Tfqb0xl)=r&2Wyw}@bdmcFU^Tc-_JM%k(KKcinL*t^y1NWQMo6gL zh5$bK5~UIoiS3UHx|sjgy5VbVy_k2UVuNsG4mq%Eqt52N<+9V3va)i_8q10ror{o> zd9I{eBANADZ6QBuw7Jjej|z0SzqDDot;Vvo>D2=ndpIe~UqThq-?s8XNru)xJ)-xB zvfxv5Fyttktu-CcxLiB9oE$f-Nz)*9WnAI_6bv^wzN|{x81+9>39oZ`5uc-_I`eg(n^k&Vn*~@5>3b-!^vg1^ zq=acIgWu`X;c~-CI=I#r?l-rAce0(SefW|5-NyC5xV7X--O(*6x459yu)yY`Qbxi*GnJdc&qkXzzE}6>sWFU}`Yz8h z`b7@ojyPIs&spHJhK5Am*$QAU4_WwAzT3fQf-CB;!}}w5P6}SU_&4(4VCU`Z=hzvD z%a8#DmM9I57z@4x3%=LYO5J^3LL#g*ac<#tx|nob-3eEVoHh$i1+puYw3k=H{fV!XhbXL=dUIY>8|u>ece!& zmYrc-65Yi7#l^)uy(bFmMX`_8gCP^4i#FHXq*xg#DL3nuGXNv}wq|9$LR38zAv@Ew@k^HqxQjtl;W1FwB)t_PV`# z>qO=;QRSD_?~*w?x`g5#RV^))a`niFh=`T~!NZG35Dw`v;~3JvkO_Hq8cxnL2v{|I zS@|rV?RUm6Plv1B-`iEF`IcB(HT*jtS9AxLqwP1 z_qx6@vMMhiOJSgM5`U z2n7wzR+a)9$9U_D!i(p!6;H}q(N%h(2}CNEjP>d9E*~g^d;Sj%+Gl7teqHAMa6YdH z0H4?%5&mn3YvrMChctbCeLQRJnU|zYZ-}B15d*u#!dKefwx0&L9EJ|r^e@($JN(=F zczHO5ix>#;Y=a=Sk*#|_@f^-K%}k}RXa!X0HFul7{qwgkk|SL+5ijNTGIJ^Rt2I6a zFYg>{UvF9zhfbN%3$?T_*cLz3NkxNYtcZy@S4E9`7^_wqO0@ZhrE85q zy7>6Lm3*}E?DwHhNSN*{GsjOCcTjkEcnSsvkq;1Y3Eirr74_nCj@p|tYm zJEGwd6x445(eL?C@$*e)yX&yf2t+#@d|P1+#jtM!?V`Q?;8fek!p4Rq$s#1l2KR)% z+62iDkI~<>13B4K<3@M|=rHj)EI;Pwzjrd@&#TYrPug~^PHr=B$KN^{viy7|(m}uj z5`m87vC(k+tru4VHPubFoU&=I?k$h}X` zu8)@KlM@qH^!{4dpi-R6QZm`(`bnclM|2x!xUC;l1>a6&zl*H;q!9Obg}ZP)dV}h< zu>R@U^<+Ik3sGn1;R}s0B|ONi0^6$RFltfZp~&#i|0>?rV7yz~x5K<=jWSJt->3U7 zLvC@q$sR-Em7jc?Gr&kPt5dN&$RYI_?I~IC(Lm^r0$C@jkB*G&N$M6)OiVP~?6>1| z_?xiM;>PY01<(Bxw&mD_1=FHSaJcdi&5~F9<@Mau)HJDnV1>?6CxubhjB4dlH=k?Y za$~21GRZ7q__sH_E@rvE|A*6?gPg{T-SIyWtbdhn1l%}IyZo_GKE%n;U`6&}g-bH9 zvbv-{>IL7o=}{XVN|#n6bmm>WyyD)(h&z)zwf4uMp(06%_^p1j-h(H)`WZGb19#;K z(@>&swWIY+7z$$Vc*Kziedc7dIjQ9oO~uS~EtzC4iRMDcQl-Bs2drj0ejL}WVYy0p zc-esj3M2geQ!6iZ&QvY1GnU?4uob9{uja{j=J0q=o^syb`}3-RIl2<>>O?x1;g zcGfSJkgGqxp<>|ym(Oan=t;<{f5LdIUz&Z}AYX6D;8-sq*FO|*`? z(^Z5rq2NiZ`>TVSk18rSKu&8b$>QQ7WvP038WJ!NLwYb@uG6r36AUrD87F`KBGIEC zf}{#PnzIA(Q`q5JS;!@+#0&kK=fCmW|4R9buWMZPrxDD@Gm1a3fE^kESekcJ^s&}h zx1`PyHai=eU+*;J=o}>Ks$s!r(?!fJYJkv8XmMUf!e3cncp7j86NQO7Y@TPhU_byR635pz zt>MQla7y=qm?ceq89b@-1aD1|0SY?Zfb8w^s=Ykx+rK~C#VljUL<~uh%{2~Pkor6X zSjQb6KbZ)<+&c&G)f{hK2oOQqE&SwC*q%-jcMA^xEw?C&L~D~8)qjtknwr|?)f@&^$h*0lA&5LUw-U zFc%7!Rew)%pUbI^6ErwOaFy{#Yn={c_FM76ANHQeiQCC9HoKj~m<+_^wzkqqE|39< zveuIOspeUCs?4Rw?|&pt7iN19jU@Znj-;kz6A{U-w5?-?OWLHEUlsfk81MpSJG4UK znpt!kPk+eMF(-^{3l2d1>n;6lnFStJZo~o+?;cmL_Gb!@^#Ps^uV!ct$dmZ_`JKVi zScm_wdgQu5h@OrPCt(pjp?_<}+>YV$WPc4X5z)qY$MSeFx$GAuH+^5!T1N$}67dSl zAtvR(i+2C89~GLyRtARAe(g=>!T}o{PCaKb>kPkqXx7VLmJ^C?2?+@!LXw4C^X@#}r3d*gWWN_5zJ1;h7l$MP%nr)$e- zoon&;*GG|=@7;)OeojD;8*$^2$a!$6Qbw!=A3_FSJ{g0mPR!XXQSjGnslD(9C;Iiu zyh9LFNwGhqfB!CngNsY7$EIQZ@Boeeh%%ZbM4ZBIaIK}aqO~@!n(frxkBToade`uhdKYo8f8Us!mF|?bK6HKv0=+L>8aub(Y=rgy`38> z6+^<NS~J0KhXuO11aV+`PbI%SU?@IRfB9I(d|Z8|#f3D>R# z3KY_Jt_ElCcfudGSG~@sXJ*>Iy&)&}OaDJ1Qm_4fYnA=#&;EPeCdX|(#_Y<2P20K3 zQp+D%?IH#v7Y8XV>?dS)6Vi$xuSZ|t{SJ?QqwROG0Gw`C#wIaq+#7VSqZ=6+p_k2Y z-KnXmk>t-hvL{WnpLn~v@?Q0cbG2(*PQ<EKQWP&3Cy&XZa_=}&EITc6ssn39wafY0q^z*jNJ&nliPZL)$pNZ5a9AOzZJknPMom}0TI zfjD4NRkq2i+`FAh(|`bQ%|F&u7Y~b9VX~6{3BwYH7!G}-t#d_B=XWXyz=Fy$o+&XZ z0~_sVl`dJSaruM8!{_dluMLJ<$bT>-sxWhLf19eV;r9ET?Jy z=4N55$okaiyPBGsHmek0)=Na%WQlmu-=A(|oo(%ZuYXKYrMpOT4L7>|$vCB^=3p$T zGxzk}EcH>-F^}5A+buC&o-PtPiPY)Pq^s{6>mfi1d;_8&RY_Ri6d2VWM2{O1r|H{h z7rYSAd$=urVu{~FuyDlFRAfgo^ycII#gTI>ThCFo8*F`+U32Ao|uzh*?HoYkWi zrAwINVMj1N-&p2L`O}Uz(44I$c#t~3rRo7r$Z)&%y8`3K+p{>?a^~esVIKhpaGFJc z(stnHyS*z<8ag`T+tWX6W~imV!ZX)aeh$i7Fn+!EcEkj}%Z-Js}6DVNCEf#yz! z=CE9Tcm8)+z}B{TU7p5c&6>F4Zh6nuZxOCkR56(lT*_PK_Yho&%@(f|I3)g3XOn~t zSgy6Abo}}}boo#1WjxI%{W!dZ3>S-cud9gmtc@DpdQLYY+KQ^_YN%8?8BagDA25ch6TEqfAF6|}Ao;V0aIdw92nqS6ia*<4{asVi z8~}pg8sn3b@ewIjU2O&w01NWyxXs#0R}6BN4RK31IPyK(jUhH?O%2*6iJA~vyVi}fTrxv(I%DC>DP zxH!5wi3}eUIK6LAB|$}VbaYe_s2fa6%?Zf65%#FUn(!_706HW;N>AG=w;`RNvW;h4 zO#nj2y6g9b1c)cC7ns$|Eu`;V8A4u>AJ;(BNcl^1j3J(hXs^vM|44Q#UAl+T0+C!u z6?FRRkKdv1mMD~EmK*ZRgK=7)|I(N^$0@lVj8ftZo}Qh@z59inuwiv9_QRYpHT4;t z8C;dFn8^JYo{^yBI?r7B5%-UTI3=~P_iaD(m&iXed&x)gMhftfOP?T>h@=} zs4Bab&?=hl<-d-wyy;D84qoqxzmXwuOn@0(a7eXw}7IYgKWNI zZRky!A*qguyqsJl;^`j{IL*9^*(7-vaq8Ym3$9-gP=|HWC4|_u-XR)L;YA`ql_`4Y zDHG{YH{1n~aOO;s>w;lg+0PP!YCDds@){Dl72gtu`Td76RAMTWDt_Agl*= zjd$!Q?@2nDfqN(ciXlDB1V~nqRnrd>G-RH4lx37gMuCs}@_xM>JLE&rku?QSM^9Ft zfE%YOk=Ke8;6!Q&WQ%WAu{BWj;sp-q)bUG<^08 z0r$dY?f;$k{1Slr#!cJJ$W+Q#Phx4s?T;ayDWmS!J=JW%mH;!l!J@)*hWzl*SLFRa zKPH@Rrx^U*8cGO9K|$ensl<-#ivYoS3vQ{Rjqfd=?)Sv79QFy=$|UXd4usdE*A)c^ zA!IHhYzM>6?7y2_@L~cbCS}0;&PMtsL>d9N4}+)w$|`uA(+EplA10nB&FqhC6h!ZC z{f|bQ6>nP(oIl7Yr5Xh#D!5aX29r2-O)rNVr;hRdC|fjQWt=}g(%@pz?UXXvhRv#d zK`x2vtsdhxom@J9M%Cy|O-o~P;UUWrp6IBc+z7`ud?}}V>neB>QFbt#m)>nR&$p>& zuc0sT=ea-5RWA<;P*K(Rh(FI1DAX3Lzr(a^Jwp_Jx||_82j#Y=fr$|gbj@TTT0GP- z;V}5m08FKLg@llhQH?1HRWSkzu#B8T%0|b>$vEAPR}N0vA8Zcr6AqB)DOO~aE*k>@R3~ut|1_j{=XPi{MqM^0EQjK>-vJODZk*(C`$Nz z0cM9V1^|l>jCHurRN{lmsq**|jI3w9fwVz_Ce#P9kWs`_ZWsYj3`8JPva85;T*H38 zU~J&zUpk404bJ@;OPpp$ri{fBe^y|8icN_&W+=OOPhJyjw<6_(4N8Q(2%TPl?99xJ z#)=6x%(lLU7LEY2QNkS9Pe_8Y9)EcdgJ$32#vdmF=&sz!vr=~wd&Hosv!&pIRtxFj zdIven$PZAan$Grn)&d=_A{m(~+u{)ilAVcc#nRGJN-Sg!*F(*eiLZk~h#@?AHEv~} zPcK~h@_#=}Js)AKPyb~&-$Aqd;KFekKtZF}vUe}^w)NjRS5q!xUNA~hn1yWR9CAFe zOmz*BKRWs5rp^p?N6McRa@RZsL#!vYymr)_1TKfBLT!0+EI(^Mtd4Rmi}pp|z0NZ+ zMBYtbKo^U`&u@*NGACJvd-F30V+ z1vO`NB(?fSp|4}$Tn6tdG6pX`B1yj@6C?lyr^|@PqpSu|iYj{&x9>&-s?^c2f@^l! zd=+eP5~wmI9Si>|si{$MK3u3S1g#$FGQAe{)a2wj&z=wr_m`)e`0VUh-mgnJzkVf- zrg9Y?w%x2fm@ZTq6@t37uPakLS0t+;6>?}YojofYJe7ak#0n0YyJwbU5q7w{R9-Od zxx%C9oXu86hG4!Q-9ObCZ1(~33MwELc=y?SV}TNgEz@mEN7OO=UlzbI3CZ*c52gX> zokJNb1sRzOF`nlR+JYwO|yrCc!*L8 zhuPajC!krVxpN(ZmX)T9+ zpPx7QIo;WLznU?jH=3A_DN2eOr!ZO_^^})7&_rd%Pp0rK z8)mRk;gE`X5P(bfNLm<}M1+Z%`+u7FgEOU5|2laORkoCMEa)$BewooNPu~8f;l|ayX-Lq(uUQQP zn<*Yk0;lW2=v>;}j*hupMNd`z6#c$JOka%;?vy_KF{O&mtekYsP}X8YNeX;K4`Qx@DQ ziHW9ty}jQzo@BhEH~m$L6Q!l3geyKXtxi1{2XnE-&$J>vM9zKTqg_y zS7kPWj}G>s%UM-LOVHfCb~%{)YA-4ZI5#gBhi?|~OIN#Tgkn1Ie_ig)+D4EYc9$$N zlZ28|V@_6ilc8Dtbud<~Dv%^}c3$82Rp`!ZaDSj8jsgZvYyJRp^Ji8!knf3ES?$B5 zuadF4YlAza-;a!_$|eQHodNaO;_Xh`tuTGN-vvvpM6S3OgJnQLqu3~ zP@GZXw9lF(fK15<;6p4V7=Po4BLa;~2}9h8)ADZAz}wQ|lbC5L#}?uZGDPS*S;qX{ zf4q7KIkZ8)YGN-=X`o8;n|4t*2Dr)OcPaAM;qd zCW{C)$JOBC>)d`~Mse@{I(8Co_PT&as4CSrb30qA^Xsp(LRgvZfB<)%Jg#A~!!5$x z+$GHEq3abTRhyRzzG5CO$RHsIIklEjwG#U{l&r6;d_@Gj65`E5!NNSToqJZFZI)9R zD6vjolR z2cM|IfgbppS>0V|Lp5K8keZ6>CwRdEkMrInHm{zXP^P7+#P{-!0_LRQByf->fTFOd zDDO|jpPL63~hCLL~$P9Dy=4-M>pUQuSI~gMV2} z{cxYm5kml(S*eDh?s5!K+ghCCMyEe(yaE-oxP*9x1OsZ$W?xB z=(}F5cHKv+(A9Xi`%BATwyQ*yZP(fg=~@l8q+?@aeI~I&uFF>t2n4lS^YF9&;r>jK z%_@nse!2?vNw-J?P5oH83P)_X9kZOWFj{=$pGC!#h)DBXvk?OTJts#{m(fqboVUlO z3UO#WIb}1#UvGe35>8wmyod|Zxk%B8U!7?V(fsarnk4RUsj2p{xY5k=jFS@{n-sND z+c+_Qo&paw%{3C!yF|t09O%^jGPSfo^8~4@ce`9ID)%ME^rp4iBp@A+~bW(#+ zk7rs!0^B!Co~WBv;;27PJOl#H41%fG8st>qR02*n0$=^JxmqUhC;=hvN8oV0Sh@J~ zvAsj=^bU<9P?DFIcaa5Fa!^}o)o>u~V zu7?ZHKnX_3{XB-OA7^HQ@Z(@LQuB@b{lZkgKT;djJftQ+m_?Y+c z6P*HsHm_g+->?%wr~SM2JQxHEAqNA7%VwHYr8kc^?v#KIP?pW`(!sfRORe1TF5cB| zVgT)-F8%(fzrH9=p%#gw0r;o2ou&e1)JF3(X4g@~St3>4pzrQsXDd03!&PrH^I+6w1As z!dTV3AF8%&?a?+&7!L2|&HC*v-sr)R*`f|ZJTBmWrJ;!j3&S(v#AZp<%Mn{$*AtSY zLu`&G=?ZXR^HKPisUE=uIA0aqaAbLiYVQKm`Rvx5^AuR2Sl|8H|Lzatrl%#Y7Ktt@ zVBC6}8P-MoQ2CmxkQZd+jcIZzHPYZ@K#Vu{OHMl%zW|fk z#h-m`BcbwDW60lgJ~MS#Z)8Q+BXid6AOG{X*lGLu+e#;6d_->g;HnF?PnZfPvh)8W zd|cpZw9im} z^}X}3#S*s_eJuOqPLJCgZYw1ZAH+^;UbJ0KU>AV@?X>L*|rxU^S~!*-BTN~2UDQU zMmgwyxVZkQz55G%nWgBOwvL3;u1E3FeaPDSK>c7pS-NtdK#d=C^0)e%J6?&Bq*6>v zog4|}b#c)w?R_xrBgmXEWiB!^S8E?TY!Yyq)S6=8dslBAf=Qaj<-Df^1we#&A%k+{ zeP@QF!ly7r#~@u(h6aJzIzp-u%?_z+E1MV5ZLW-SgE!z>t!Cpo#y+$&;zzEkk-&F8 zAk``&NH*A9ybFaj{{5knHKg=0od<(T%pYpZ>!74o^M#7?8&h_W`5d@ncJ`ZRJxd?wbOm;#$k61%CsGH&HZ79$OI36SnWy2A5u#D;e)9k< zK$bO3l*D25x_UwQstbA$=9!hgtqcshQrZ!h1&DbW|(ZVWq2k%Jd7~||E*5>QO z{F(8V1ijpb2QG3xX*9>(R1u#aPKEH)yO}r?nqYzw$keCX7)p1$WGEO>r1>wJle&?f z@8!dK;wvh4=3=5-s%~Ats(n`WM8a%1N9??EJpF?zS|{3aTh{ZS*Q#ctW&O*MCa=vw zd>)^E80xkZCpM)~A~Z-TZ)!Bjv6FRfFgR&tvetntk&}l<9(H3 z;CEq0X;ql*6LF6Y*zxk%e+jm)idncEd9WTXMIfGfD9bDS`E#o=E#<`=R5q1zXA~e% zdEm#pNt{6cRV8ih=TiEag0xHD7~2O^_$Iq zBtOl%>LQq2rJ<(oImiS~@I2Pov0*Ju@v&YL7SR|_7|j|CWyH{M`|M*x8PBVKS2qMy zpy2Ndn}CB#!jqW)p8Dc0GtA*F+mT*0;|IHKw=;dqTUQ736V@Kmv1Dy}`WZLd z?>*11&#z7vroeOO7bovMV!4$%(C|$s7i(2BpPyBQu842;sMi`&Rz+6VvdGWc+gJuw zrm-q==9=gn6g^o_=KAdHnAeLNDm}|(Hh1fqj#lUuWLuMOmdXhp3Ge^ue{=gc%UHSH z_h0f6RNpJ@BFY-hz4e3@w>)fscY#KEESRG2HRn+nuoM#w9BxDw9*n_Kn zD%Gw>D(JFA@U`lNdrKY+?=U0Qmn)L`2W~p^D)zA#Rudlgu0?G z9ysMbo_z6s>R<=LsxRh^IneRs*8Sex-MzsgUPh!sA)k-D$Yf)4^cZ>bnE_9nDn2JC z2VhML$w3i8X4MX*)WwMqH3pTuoD2j3Y;rZeQl+_pE8X*wfC*bK7&x(2f^o5@6lhj-;5=`dX)QWM0(b3ikT@5`6j@a+JYg+Xl`QG z-LfQ*5huc~)O+$Ux^W%JFN=Z1zVdj|6kQ|qH~hS|;#h(7w|@*#Jy7sZ_LLRf_q`Xy z(z5b#ii%((WrfFLT0p8xt+dM#{^5FCHuCCfBw=Vr8CgOMDsF#ngY7HyK%(yRpgML! zf+Q$lPoboTNPT7iX@R z35AJR$g(We{vwT~yR-Wzi7h|AC|JWA)*k@JN%qU-(979ecQ78XGm*Ak*Gm41RMtex z6$6M$k|nfDtn{9tvr-l3*=5M52%3GY%dRy@$@-U3Wj^tV_V`xH2w$*(De5eQ_@DN8mSh1{)#(S4eR-*Cd%G&~d{A77YnN*Lz z#bD}>zoey2inI`4getROvp49SEF`9_ZtzSWF6qQOW7G;;rTPc1*_3OPA62&c5eOin z5hXUbpZ(2fF!0IS->WtWKt~ix_C4pUwOM@I6Gg~n4CvmttS`5DxlMzE4 zLKAC!2{02?2(*;P&M_0~I=kUmsye$JIdq744bfu83t96R!~@{4XKGjl+)iK{6euMn zBg)$PsA|6zzN5o~{4OklD9FKNd~!_Z{crMq1HWkPfWX{cIPq#M&rGbcPso9q@WPyd z0Z4)EM4p+5tUC2d$R6IGMWYo(gn;;>KmFAft5hi%d)WyuiyJ3QNfC4W$E4WU@ruZt zO0su<{``R;ARxqp9z8$kBC@uA9qiuQ3+H)3iX*_hWm&3zOC9(rTUgJEiTOfiCpHvw z2n?q1+1Xd>bA(H3f-!YI+l4AqS?;jvC+!q+C(+$0P$dH z52Nexyw&Wna6o80HZpqqFzb((oN%ejR7NVh7Dk7LxeR@*>~*7l8`TRD8h>|Sq|h=a zdz|9wK}InJrGjD8BXd-WpR{i1Y!AQI?eNV60i7-p2}#DLm;oV|%|cavS=&QU(13yg3u;D2 zMlrw;Ndk5 zpbc2S1;&3E&g-GXG^w)fvE@LIyE`IE)P2^wmo(NL4_3Vz`ODDhK=Ljo5Y)qzMUANF zs#wtUV33Vo!y*KH$`3r&Fm=7(hKoM}qBbsQLHS2A6q6KdwM?Yb#IQO8kYF~NOf&lP zi=j>5zi3b=44oK0X{WsRp4TIuU^J&+2POue%qhmam8VSw7*N1Bieiz8)u|(aRTVGe zT~NdiDti*7kn>h6?$YEJqj!p_ynS_9zrGS%*$IHNw-&4=S8u?iDuK96qAuGD{@hq5 zlxQj$0W<>cLO>Qu#l?l|BjEBk7-Wunm~Z{&Sbjip81o~{Mv@r;QC{EHWqp*98fL_0 zfdnN6Nib(s?Xlj@qQl+!mEX;(bO{7AA6>7_JpTsq7;m56+=P;O7MWfj&MLX_GlTVb zrA?;+i>zm(uaI8Mj>C9J!+=th${$Rdid9Na-0C}slpBaV#eYl?c6sfR!F5542{=_( z#TColy0jGXO{|q%C|SDpr*nJEer9~#=V6BY?s!R>FSteUWI6zKbJMC0;UOW9!uo@u~vW-w>d(b|g`2Y$Cd0`O|;@;k^sYV3tJOU$P6j&5gR8UZ_ z>j8lV*mTJH8XY!Q{xJu|%?^-x9d7nTzVVwYRxR8P!ouu)1CT-Nfld-xOG?Tu48Un6 zzQMge>IAW{;2RhS37puK$W__^tNaIW9-M-y#SMQXvQ9Mi)=t0OOgH@X*sW~ghddFI zOa!|*Yxr3{G}xaDg7(xrqP8LLOe`u?oHNfLc+ebLaTBt@HRDdlJ1g%tO5C3OKmZUR?c99-h8ATH9;nhJxhY^o zh(imZ@80@VEJG+lCURVbqa{j_Q{FzcG4j@5L*kjP7D1{GrCFAgNr8pQndP$-1{2S3 zr6fxwWlPZybr-a=erhZ^K_HBP55n#;&gD3W$SH3P`!>z=xu`@rzdA?UOw_@FaXd>T zdbng}FMD!%e{D|?i0TKP@(+}rT``A$lqzYciR!8OmzpbX*!MGS*=mQL%cU3^@gH8YuU)YR0QNWfXW?2Ts^qmlEaJU{?OOuq~J zcrI37?A9t~@+a&?o`=Hm*PLw*fera5Kw+^oOWj1L^W6;GK4Y=;i*YT36OPM#yca+C zZ`NSX(nkZflzDH!@a6f56CiU_m0zzqJslSe>2hLZEGkpUyX|*DhW9?bn~N2tfXU#% zuB)rFbp?F8%g4Og@bUkqkBQ8BAG+HOng91%C|)?}!?nhN$?Rk16b|RDS&9@CvbV3efFg2^=bvh|lncc*82U?h<;LenuAv2?!BAyaW%+lrAI9C5lBa*^kmYLkHw z7K3)dAS^2QDsoY9vmzLcs3Oktf(UNNuFcIGyd0lp2@TyR;w5GX1jmXze}6a|Ab)WJ z<6H%(!GG_-kaUmfTO&}W1_234*aJySzbI=>rI)y%vi|c({`qTbOkK|-?~lL95EEZ1 zZB)NHl{<+&%Vk1%Xl8{c^FZr@vOQ1fS0~u)2P{|l7$87q2{Nxy-(dnw06ZK=u0kPv z*avUTQ7NT4*^;iVE+zG%4B_6w?AA}f#v!|bzme5@l#FLLf+)IEcw?+wp3nm2Qcior z9+!b#O|VARE~4j6g;|Y9G0nkWVephxXo%@)`=h$h%3=r<)g={i3y>e+k^Br^9PJv^ zR?^Csdd{aJ5sD8rh}rqGatFmTXbHArMN_E5=94Y4-??EP91{u#Ev!#w0%-y}Oso-# z**$hG*Ob;*^a~9RJP~MY{&{rvL9N1^5`E}xw++_g-3wI}aO?5cydP;xj(-IWTrs_F*U3=qsUNf90Wkd2)kn<7;d*Po zkO%Sb@Bj??perR2sV8lrd~1FkbggzTwj%X@ZuF0K(qKt`m}{;ZUyiM0!v zk$|&?j~(c_8$oE)^~R9?^n#kq;}3ykPasjkXY@ha)I(dJ_#alVM&5mUp4lYp7~2$a zeETW}8+x;W^$EXkdjaXm%)Ip@!cJtkUkPGGBgE(+h9Ui#;(X2*)i+^>Mt$e@m%}!8!qz-^4VXEoD*rm{w$Fu%MCN&CWqq0=^KXpZD1}#$ZHPV z+klOS7X(UX6yUPzp!z2Vk%Y4lDNsCkqw@jrQ^3bp&a(YOMVth@Ca*6Wn7YtVLX7uK z(f9AssLpFbpcY4mB70cVI33$x9jf?#RTZEpz=n{82jEN&Zge^t3epjy2~JvbvvS?J z*QPqD>j$s^DCcM|G@U#OB|#q%==L_|dDYHBWZH8svwyj7bN8HT7e@xP=7+Se5g> z=)&Fy!X50~>P4g2haixl9}7DCg$Hq=vQt|vNny#4A5Kd49Ja-ul}PxZ!aadgrU9QS zkp>)i0$-2O;g?PAeIj)N2y}>GP8PR_%O0%_TU?YtZ(o119{+<*-aj73D{9AQ(=UH3 z$_*I3Ing>3s{G2U4hvp#HI}Tg>W++lzizOl=n%KAQ$rLEp^7AgjKpv=NR+FGhSL~3 zTP&-4=ih2OnKj|yW@Y_cXyQYY6Vd+G7>zaa}f6)LF4ZOI2zh@ zR>5E{*58N#v>HK6VqUU1V=tvb$n)~n88iS}!3P-oS7`>BVx4}afheO3x1j+Er?KP| zxKDQ(N8Gk^s9!KB?v_wxKkeCDm@%90)vReiz`&-XOS3s+zQKE4fumKo^=&Tnz=#M` zT`)s)2m%s|`xHI^o!HD_D)(C#wP$}T78Uj-m(IJ_+1lb*a~W=V)4)?XljvY*zDl6+ zYc$Dv#GdNEA>yqmvsTXNX#R`Hy2E#fq&Vco4jb}iC{T_fUQM?mA8t;_x54j-Xpa_d z0ht{t$i1+tD{8|?%(-`%&|G9X0xX*9W0_{3U8zS`ZfOBace~xCuuTfnD-JQ_5KcJ6 zQe&=Ec@84@jWYxoBqxLC!z5jOxvG``91>YEuL5-pvX;+;~E3`zi`j%PNlt zWiSiPrc-6;kJpJ?3s$7H3cdH`QhCa0V>?7YPJ>=VULG$hK|cv=`RB*6p#?gHZX0D- zkw{)o6-#NA*Td($u8!v`c7mkgw0JvGoBoJSi{8yx5q)(P_3O{_qMi3G%De+&J~4MM z_mdzGq@k@VZEA0K0f0^$Q{^FbaO(jD3pbuII3kgRi7J{b_#mT57=jG2* zf5P}hK45HYi~+jt1^yJ!ORO9ff0zM>GVmK_7Zzdy>mz_WS_{W5e+miIvWhFAC%1tX zBgWCuG5udTSE5nyM@>;sDEc}Hv=CcofcLhCtD({owevt8GYkiWbZ>p;j@IlYKRjD| zjJPRmyiOK5&TzZhNR)i3s@nUnC^zrLNgDp+4P`W&yl4TAN+AG$yjp7OP%}(lb1}cJ z&Y%Drm_vucN5reb3+6_@(kU%QsdO}>6!qP;PPdtp!cYCL-pUZQn%|EvsA#*I^lg>s zUigPw`LpG}+h|~>uylN4@xzu?{>msl3&L8PU&PqU0`3ueFHN693$AGt?bEd;0AdV(TEA`URJLJu&1ZT zcF#sAdJaQX?F5jQv{wtf` zK;Oi@_nlby9`F9S!}3{nqDF*B@aw3{JX)qz(S^H1T&(|IFQ z5;6!#C!#k^l7p2A9X=MUrpE!0t50sN%Ss!0RC-{s{N*em7f~)*!A;Rq>y-xiv zO4ve7bo9!RI4C9a3k!Efd9fD?wKzc10WLr~WMi3M(GrK_Q&5BhM=(7nCpLLR?kfj} za*n%ZOVA$Z?aq`u&etq--HmqMiKdg4FajKVA>h^A1EXmnd$?N}%>7_!+LHK{Kq{BX z_L=H*Oyco>d&>sK9?r}Mok3VaAJ@^f%Z!a4t(4phSCvtWI}!gb+HDAT!^Ys&u$uMt zZMMWfl(+t+=Xq&ow9UA5O#kPRC)vr@8`$(L;$RaZ>du#MCrjPfK$gDrJuek2E#SEE zJs6aM;=8?ditBaoi?Xx`A{1+?Ylv!|)?n-Vr`PIR_tw_dq}rylS>=TzN+kb&iNthq zEK=gl=BAZvD$r8bBqWIoMCgo-1ffczN-+6s=$6~o?ab3R4aN2L!bP$&D zxpJmJ#eLbHTIL&c&}tkhUbsvbP6cK2LY@~iC`9OQD)rq>-g;@8?1_9Nc=3Su`Z4qG z-yx67J(mT`lXiLCS7S|!-y?@EMmfdRbXpnwMbGZWgOm0o&>-lZslqm&SWex& zv&4|k3KBw8=rwC&awxTH5WnXO>PP1#z@(?8g~K^yO{+CDckjOft@%UU#26*>KFVXB%1@bhtQdN}Cdlz_zx>)68w#;$vf-+9h5*IsjdZ z0aU{|hzd>*+VF0(>^SYFk0^qx*CxmF7MZV7KqP=it?i)oP9fWh|3mQE-`yvO64wx% z%G1+NT7VTe18u)PP}q}4_1h|ST%T?SfIk4H=p>bN5vEp$-*8Lknm1}~K6dX~tKYs9 z$L;T|TPn=sb?3V{SgcuFUCkIC9K12iR-@(Po0Pr>ZmQ>8 zZMuXPKvzOV4awSaeGy6L^2x0vQ2*GF=V|%d@YcTVv>6rg_Q%+b0S%hz*X__!zJVBDo-p?yeS-KzrmrRvBJorf#j)*Ba&_sqkA6(gZ{ zav`R?Q}hDD!aTFDvW(upXP&RIPW;pvh{3LtfdJ)1^X>8A<)-9A|E`EZon6FWA`b&6 zr*aZVTtK6CgFsXPC|!U65rD0sVPP-`R3Bu($9KLM!{(idcg&S@8u(aGQrP2k>z&h| zA&lX^zUbREng>(J3(1r&=Tu))GfvdqmnG09EAD=e)4u0h*{tM~4}{75u1thcr(GnO z|5Z&-PqW2Mob0dv;!uP#{Z99Mann6jzVlK0aXA#3`y8DWKk;7RAHmAoYDd@mcYM;WNGu37F8QVloSMC776->YoOGteoTjzy>;xixH04|*$j)u-+ZAMG(e@85(Wqf;f%Gi60c7QBStH205!!e% zQa_N1IkNcRRk07!hB=+pB2O3x%V}LM+FH6g2cDWDpU1G(sLklsHSNsElAjvOu=zva!Ctmnq`B;{?vFr;layeQ%F?J&oNr;u$04V>f$l z*0*A@z!?uBZ)Em<)?hVS&)NxRTP)NHx$aX!`In5SR-D^W`9`AK7Mb3;-{Q=4GbJjs z15gXZ`^l%uGE;bme#A=N&ml=c2;XERIPFvN@g{SHf0aIv=o%7}ktGY3J6S|M!7M$7 zF3FKru(@%il$BSbP*66|h%kfZBwq0nNJ%U+N{ORh_zpX4>;TH)Z&6X9%yh&qZ6GX% zb7yBqiVY=)a8uZ~nCRnbhh15v~#vA+AagR~Yuq8|Kh7e|-c6(*Ly-_8{4sDIM zh_+gn={o^l-orNm9f$Zir=l6hY5flcA(_kd`yGz2`y}I_?Njt6lPmIR!c67t zxc6(SUpz1o>-|G(DG%%_N*P1zx%^5|cREMjuhQiNS6iROb_O8hqJMGjARd^~oJztx z9yR=BlsmrpGGnOOU#rOQUaF+DMC7l%(>qAB7?Jwt@rv>pQS+4{=BWom;iFno=<#Dj z#nJxcUTcL=^4`xUL+2k2gl8L2jsno%i#1V7OT#RQSb-Rsh(?q>oN7ygE;L%-l>QkL z6xgm<@Cv_tF7XB*RVE=Q$iQVq8Y7=Su+y{{q1z`kk*25HZj;Mvz-slVc=#I4FS%vA z(e-6HCsMGkbTM*VHqM3QhqpaJv8SEkPb;maU)B*X9bB~u)*K|U=J1kYlk!`R#fOH5 zvH|VeK?{&A$v{zm*4M>$ypDmkAm0a=&fk(p^gNapvU{Pgum7Dz{OEKNYF5Jj@$Q#( z=y4k|BQH*L#lVZ~x27^G%74HWhZ>i8}-r^wxNzv(IK$mSF~xdR5!hqrN+R zW8(~`FTM6IatQk#DI?Qf9M!a;Ux_s2l#7M>1{mSpa4TQj>e&JHl4*a9f!^!7mSRD3 z71EoJQt!dx{NyF^<{>6grsSvz#@GXWi>BdL`ElFey#{arG069$DzM}qEFLP_Yr)IO zWha(?XeD&7)C949v5$f+lu5rpB+xHgRWUI#Mtkpgf7-iroNL@LXl~k*Qx&86)J2LnX0uY9`*jd4<27qAf-xy5X9{;Y;EgORK54q0LC>Sd-5Co^f zkM3?ijR6o`5r-f4+}Hw{G4K=@14Hi#D4xf|9<%6^MfCK*k*)^9cf{WQY@{>KjpaE( zSRt8;)P+wI7LlW(F7d4#LqeXA;a{h1MQ3_nyPFHF2dy~cdi7M?tnYUl0&rF&HG21_ zlPiwg9}XFI*4h#VimQVLt~T$K)@|eHAHeu1rY?kAC|0wW0s0H*& zT!hZ=vl@Hge5{;ternIlPt#Q?TK0vVY^3#fXEL&X*i_xKL5dhse~CdF8@g_JF&+i=?5Hvt*QCW;;)NtXN z>uo1+8ECpNNp;I&@UryuvYeCh_gzaZw~Bbu2z$C$M@G6t*18m%pUGed;S1R9 zg_f9jH86d%h`N_Irz!^NYzcCM<-D37_(Q)Az7s3{THTQ`71r}9zT70-`+uPp(rL#3Z@0gOiB)*Kq<+IJ0S?u&!)5|00^W*y*)hqS`J5A)~WVi!H ze{8Y{)b>+S;&(w_#_PPC7W%DdI(FZWQBtC&zGsqWqPQ5eY!!Dv0Cqj zc;?U3vf}J=eaJ7mdo%OswMT|ZZH~P0$p#xHH;Wij`Hw&QCgq23%Ez41x+U5`0uBQKddbPjg{T=&d|nDnJpgqBl5%=`i-d5HnS$^n z+zxG@oS>d=$Bq-ihRKjt{D++PwUOLna4y#woZjOi(+VXgT9i&wwCk5_kx+5%lFrkB z`*8DOME$Av#f2zkD#ML}Q0u|HPcPTPzRa4c2?m35k?xn&7jIcqGP>ij+6o}k<^2QA zzfI}!kI0Wm%Hk0qd8cFHv{idm;=pA)4(Iaz<1bs9LyO^*GjS+4KRl|i^5`E@ONS12h&+L86KSS-! zSEK5&9oWRR@0>U!41Q1A=ML3QW9y!DzZ}qj8GCPxi|YMS-rMVWMjpYNtc*jyhCXD% zG$!8sQgV+$Ih>dYbxxdhhI!x{#Ob}Zx>M7j(2LWIf?O_tHi=Qx$y<=L|YH^m<_ z$P=whyyaoXb{N>rv+ZCBgTv zmQ*G0)~lNH^Yb6v-Hkb*MXBEG0V7OcE&D6F@!K`m4#c7g(6obac=lhB}-1ZT@`9{37!{LfFnOm;MpXl`T5=CX@IAF%CsT*Yw5ST7He+8mVFK#-r zJzWh@7E@Bl!39|=dE~K-iG_7^;M+8+X3bB&-50|EERK@JCT*>Ymi#W(Hb!nBToX_R zZbrKx{iyuYwgw2hyGHxt2|bF1{Tg{L<->9QY_$n{lr4fLwP}zenSJ^d(l*FP1(28v zwv5U}Kvaz!g`FT}JAi}#1wPEf7s}rRd;)nd5d-#^z<0IQX+yLzFYo{?a(w(zQ(K#!kr8=gW5e6^?@uit(pW}o*K+Md#i0!S z@#FdP=ZizvU_mQAHaYdHL#y6u{d+Oj?l&^`l>b61=d$HFbdTkLE$E+cBjyD%U`YUa zon2o~TGqN_)ID$g=<{3g<30vBbPV?T8y!Q##Tr1I7q@5>1WM6bQjn9gAIfW+3;EtR zXEN@qA8($!7o#|onE}RqA})^5`Sr#kN9o>3*HY7m8j_a%SnLvQtQO;gaw)JA)41qb zXJ)t-J~mJS7AYq%+92}AAN()UXUBs)3@j{YAbQp|;ik^>!tQHosuEjHA8=HGpVU1k zD-E>mfO#;3@tRd6g#l%ThsU)%L;+kp%s{ofx6ZKXLWr~)hbS)Q9LRzFxz}MO{jd)pQ5mR5f+=j`&3ZcQ=xhrkj^6su{&UE6hVU4kG@E!q{cdKRP+x z?Jq4T-xq{SAVY7tJiBuU4ntTWJw3frYJOXrHl8-e%fmNBklyQf1VGImlCNx9jD5qW z53t4^emr&F(FD_O|s-^77h{iX}m z*cee+`4kAA0y6z38u&muuNJUT0`cDBU1Dx-ZlMs$&!`2g$lHd4G_b;+5P53vIg`|( z3kM8;!AQL@M<5i7w#mgqVp=9zgeDRcSUxIeG#56g5Zf2VgXv z26qAy2yM-i;bT(STnCE^c+S!9O?r8guYOj(8^nQLsH&1EJbzBh#1tgTd3B~^&{7N( zuj2Ul_)$6k{pVJ!N=-v!!o&P0JA}G$lWb+}+%@~tYn{7rPwtUP*nYY7Y-tW~pg{=m z=pr;egNH(RM*=-a22aMcMn8LY_h?vfS&BQ+v$%0x`93Txj60rWlMQYX2Q?U~5MrX( z77Atw_q?o{{{qsCWJ@sP^%Mv!kxA(B%1(^^X}(|m(&W26zo*~s8+ z`u;KlvWqrq^Jy7e1F1JZfWpqZQWbF_hp}wgEwFf1 ztlqCGT7`BWK&n}!$caXQ=1iI~gabBOCD<16c_-lXtPDuKnce=RTWdpRWo=DI5Qc|` zhX9xAZ(#Hd&@Pe#M?jr^iHnV{Zqfi!{|tkt>J!*-wi~tZ$N!eDB2dDB&^L;oJfd8e zQ|Qwc9x@yTBL1*Zk#rNBn|ndIC;vUhGfzA?Oz_XKNwsB67Z!+H^8;o{W{z)*g%FRK z0zcGgMCFizbBGC)h5r}~d?KQaLxjV2)%S1T9Dt^~+In_`Bl+gypcgDc6F7&`Hv5(( zd|Z~QKTK`}!&4}1&)Hgmk#6wj1VAfOtR0ZnS=tvy4%6+&;& zxZxeg>R# zVL0gtAUcaue*qkE^DRgb@_?iPNba^4AxKLQM%f!18w-QL6aC`F3s3~0or9+ImhSJT z*5#3thf+K$Dx)%u??ujYkm=LpED&p`qZ1MxjR({K?Pe7S4a}lxOh9D;HAd0&PVv~X z!|VvSIz48*yS5R*F#lIUhTJ-yWa0E5_M{jpVAMxTKsb54-Vc@n4Wt~>#w&tD0gsXr zTma$Vvh{z{9L_^2?(qqjdE-ui39c7B!$(`+qu^2@cQ+R%CmRy;M3@fd#Dd!HO7|lf z2ynyq=c;Cw!vE*1!otF-!!_Ihj=DC!`?zFC;R`99btFQ{q~y~k%zb+z=M}Rrj_mhf zTGvcWigOgq400|Jf!`?Ct( zIyaD5+@b-2n8aUnAZ2J3F!qOMvnEdK%NXqft_fl^Or~HBhNbTz+KoOM=-;}11~-#V z<{d+?pB&9hIErPc&Dlg?EeyY}T9)(aPl z-t4Bu*a+7_hzJwq+xPFVIe%CbrLcdCr|lE#w!3qR)z#JJX!)u3;r6y%`5pVYa_OCc zYx~eY$8d+wftu{`?jnNp^ky>P>C6DKrZf>}%skc19?ydo3mEOx?in~7L++CP;WlnN z1$klv%~VgIG^X_Q^uLE@jz9XuT_u3$4))TTqT0_ossVVp&*Ue?QovDlJ;DCBuhC z=Uq(*+yUH)>%vZdl+VET(4j%+lUE0)QBCv!bq=~(RR zd-1PC(gy%CF>x>`#4Pz!umFI&2NH?H^s3&wHyi7?LtYUu%S*d=@81(N7~gb1NkO!_+KNz4#WZ@9w`oE z=)fdFpJDy!A)WC7ltBw$pH{Oyiwiy5JvvP1XMi_!|ur3hV^52;CV{K zmvQTFqH>4Gmn?KnmW^3+8td!pnZTvywP03}1^9D(BnX-~Qq;$|v2Ew?1)5da4rV$h`0%xvY+Gb8M+Q)9>o)ausBnXcIPv4A0)U zE>ZJb--dzBMEoyLx~;nU6y^V5LUgjhrl4K|CQ~nbnqxGCzdyX!byGJM+-L^1zv$@c z{pVVcpF->^$qp%)hu6tq#70SltW4gKh8IguJV;MJ2Oaq3daNosWc<=S!*|JBB^SVv z<^yqT%?m3pGiY2h3C2jTnlz!5ROCCN)mw*YG;#x%KW&1pXZBmn%1OMq?P4YDO9R&X z=T{q78+T=cH`_H>61be|2d=$;6I|D|mN(>l9g3Q(tNGzjAYQ?|&A(6yP3Bk(nQXj7 zZllgvI`Q(ReDvU(CVFOOd1gFxDK;%6DKIC()|cAwCQTZB8#n70cu-wG?M#J%XpgUe zdu<^hC9TJ7e|PgygBjQocjS$gn(Cxf(X%0kqd8w~4*A4f8`jTaEH;94xpITrH4tl# zCOR!A&=jxQ9{B$M5R^JCrS(+X!G%5h*8he|3~y>QNvXeycwT?mYef*F`$)X>7W|+W zvB7Y`6VrS$*XUgI34}Bhp3d4VEbr4qfRI|_(RaT0bZoMrJ5&9!Ai*C5UyJHj+k{;n zJ$93v1^Ev%o{ml*KQ7K_fFt{;Vc8)l1>hSgGY13$=RAZEtg_2Hk*Eb8>h|-z-P zTj@!fohgd5g~Z9=*-U(ye3iV|zrc&3rJ>>fT;2N9)=y$*5hVB-@fZC|>>ftt-g6$l zaxOs~fj6DV^G0Jqss<%9k)Z0{14-N6;Gz-&g}627TVp}@%*7ID$(oaq3%5!W1Sz&B zO5>_6O+%5L%OSXy2IZUIhYfsU?-xB+=5Y6px#x*cXAVAG(l|YKPivK3Ur!Bdo6N+L=O8QXz({aO(sQ_ly{LF;Bp58N>9S2uJ&%MiVn=P(seR)5na&PXi z(hg%}VsgJ-xIsI}zPrJdbvY-Z9I0a}7WO_SgiJ?F+H&(ol;cs9F2xhU)~EtM-8(>h zmfJ5&)CDDZy~_SM=b4(T29nnZF}aQ0VqcRfh#9rbsW`DhDi{66>Cq%38RA%He})TP z*C%-yxAj67LSQnUm68eYV)Wt|vx&(9*1Opd&;&$Vf!NZgBUlb0rte5|jX>9#1v0e* z&~SUeZJZ2{7Wq5S4E64}J=|vpMi;qMzIR({B3|o>jJhwILO>L#b6iU2spj$!Q-huN?weL5LY5rKi8t~9{~`k7OPpHm$d5W&yxs1M zBGx)LJRQGI##iU#8-GFm)*@>_iB+XS3EV!fx8F357*Te++=bX~% zeUMQ)%#W7Wm{SMDI`#v-$s$fC%P3rrLJ#t|K_k6`0@xm-ry+fKZ2{>~cpoM)GY{;| zZpYS)#7HWD5KQ-W?0}bO5NVwyPi10+4s3<%VK2mjj=oz^6wZe9VRH6E6Q%9L0FNB2 zd$0WczSYoUxo0)$U8C2Mja{6>Kd+lV`>zIEEt>`M6HrJjNAaBhSKz|R`saRwYd(6M z%3A~3iidS;u0!fvr&pRyZqVgIw9gj|d$C){D|)T?`mtysVifWU?+Wq5XRxF8z4(>7 zY~n?y5Pu{`L)PWuyr2?!3nVb@m7Mhuwm*w<{q0rc+P}6Bq;__kW_X|I{M~H&%96I<=uHed z6}RfL(o!6%#tTUIaT0_;M=77u%r0H0EHz=5O^ngNb7T#jM@A>*Ol`tjt6J*xN5M*Q zRy&VlUkJ0o$l;$d<^6(MIwIKKgF@77|&2`4nlPitNK} z!DWw_r*!D%k=9S>*0Tvk6ze{Kga9c>Mx5f&kWDpC=U-O4jSyGM;)D8QZ1gJv$sEGU z+12RyM6wi26rcMYLDRUknpKp@)3fU{2z_T~hE~il3`7CB#r8P4NpWa3iEuC~WdxlC zqb3Xr(h`Q_Jx4}oh9hGIqLaMLDk=C8?;WB^_nP{n=vV{&*_~vi3mC=GnuH)|C#GKW zMyrdh#Sa+H|Vwr zqh*>%ph2u&O++41$;js0a+D7n=sqBHSxcvE6;x%z+Pc=j0HfjKofN31cmwiTy-#~6 z?6EHa2=N0{FmOKzm`?-2cm+Tb0OYH_5oN#l!BhraiS1EY^QXh!x`#6U+rg{!tnn~9 z;-^~#%pKDd%&hlsI#%9{cl;7_BLMh6YaY7LMR!l@jpI#6jIZnl;)p-g;jDGHL3k~; z*-lDZo46+C0Tt~^$wv(LZvSS7>cX<&yWj9C#SbK%vajt&bv+5*_1mFY7YKPfy|Z0TyG z^UR`sg*$~r%32G}yi7QnHpEk)4@rEcRIgdA3&vbJ~0 z;nhY>CRFPtuitQVh`E(V+&0J{YR&!f3(%jtjSE$uh(i=UA0`EztKFcqOK{vR@K;<25R1PD1z z4FiK+)=5Kvh7oh=6RLs=e>7kHd!xG=Bk*QkEFag!WiGX>-1_TGirN`WV6-J-sB3XR zN{G+;k1cnNoq1YoKecy7-F2^hl9883{oT_D+JdO%yL!I$g9)S+p-XNlZqMpihJ1YMMLCSZAgm-9KQv|_aOjGL-O`&fxhY!buM4w zmbS$OQ=~|JdP);Atq+Il51m3pXWj@NTt64Eka;f-n&QXjBJwy%pXUzO=9+iKr|a2n z(PBXRHwpL|7!lFhSfewyel;1oA{%M&Z=z65eayHx$~9&J=p`4wi0P%nLdL4uO4TSL z#Y##CYib9vQf_5zYi(2d0Nhg$0&rb45FQ!Xyp7%aO^NJZoh=j4VS3^+w<*c2l12(fLj4y z%<^mf>izVH%*xE3G7=2MG7Q*2yX8|^S%bto+w-a?fzeNYV(T+y3Q+*52)_sl01{mX zTL+$&%)Z^+gO$I6&0R;W_nx2&X`@=_4}Z223R%>xsehcPn2n46Jh0oJ+m8#6ksu&x z7*cvup|5T(AZ=gM{-UJZ-``_=o|vZ7NsUW3($>pL zYR1R^-nkldtv1J@riP`rG;JfP()Nwfn6%ltP|`5bAZ~}3^zL8x+#~Hfp2Buf{Dq)_x0h3-E_$Hju|fu5QEEm2_7tTTD1&$-DD#BK-DepB}i9 zRl32&u%lNAR0egEBxXf(-&PQw4A+@+e(`Ltfo6=Ara(HJrx`Oq?qO zC32nZ?eFJo#-0{*?|H67jRleq0X;3~5tYDW0^lnQnb7Jdoz#dp$aipcLgTa0NM zy>DFp(PUt{jI>BP4xk6HyTIr>x+hO!=K6oN_g1{)C+}9M9r}^fyWFwgTqWcxhp?hT z^21}DL|F~eA?}6O|46)PsDF%D{)C`$?YR!&5X9L`iBZgnR?N8s3BQz?Uuk%<2GoLP zx>`&w24g(c)Cd?QGeWjxP*~~kMoaTu7a1JGP|7t{zLpZ?XptM1&3r2?#nF$2%|@Ua z7EFFGE+rJZ6rn?BO zr9N_6r)f8qf;?gNuL!?YS5N)W`IF$p`7_r-sCIO_xc*Zub{-CO@AOH$YxA1jUh4V_Ya%|FmSL&!4H7^s_W}} zu+W4xK2h>mYIaZ4>J7)npyMv_#o3P(HusfcLZ5`2G}jVx)pEq7q+o7pbbVezdcxzu z2v8W__d}%3M?DnaMq@A0-aWp%sodi)#omen5AmRGg6-5ohdaC1S+kJB05G@=2!X(@ zq$JYh5KloDzz>!vDk)X?KKLxUE_>r)2I0J`0EdQG9)oU^*hG>2)VE^s>`UiOf-jMO zLrgIOR%kikNMGEx#y@aEuVjs;V?XvA(PVBzlKYgTuDDP5_^LLV-A{P!m&736meh0Z zp$%eWR7EdE`L9WqSTr~(Zm62=D-mU9IJ=oV{vxgkdiu!HN+m+sldHN~D3LnL?MGIR zRJQnqzR!N^)D6)OM@c*r>9ud{io-x2B*7~8s(=XLYMr#ss2zNKKa#{-xIE6RaEa-m zC8MXCJE}ktA+WgFEgnl`Qpt8KNAuHv%cYId%xPJT3t1D5!93h@#*$we@Po!ga#4|y z|CT;jp9-59Rn`6$zVTIxRN1vu`FZCG7`2#^Gk189%6va-pNjwZ{Q6bU@$b>MWXWXB zAC-#Ts9qTJ;$)*J_TA&7y?+WCX78P@Urn=7)HI^R=#Nn7=@Iw=1~T--QtgX`92nTA zLbQC?Ye~D3p68sPmfQ7Sa^IwCJ{b|M_eyTl>6!Lw;hUIfu4@N+fVUjl#SSm$yh?mo zW>2^rF&Cc=9xJ`Er$;VcLRSyjS8KkY{u&^QUpV4QnR%D^w)t$Fgw^=oq*>UKGdJk$ z2T0&h*U(r!zVqaKr8cSD|yt$Z)I~jX0A7JsvB`T<`FOXsp-AkCh?-kLqc- z2b9<}^}a#I3&zHSie73_11&9}&IkwdGXbeX45Bg6A3ZwzbTWr}Tnr3m*DMqFOa?b= zylHK^5$AO9ALn%SZ7gyQMcVODv7K9&iTw(7%{^>%5V8gtXn>mrlz9m898+nmYKlG3 z*vAZRfQ_mtCfbz2@ztIhF%$LWwa(jvz$LTiH7Ze6@A;k=538HJD@9UbV@0ITj!0WP zL4uGWbZo4iHE!Y-u#M_?9@hu@h_zS>&`+ftf@i22UP+bIe2v zm6GcoUJ-lZiNc)AaQ|$Jztphe(GO4^GL zoIOM7mfmoL+WTO&LvFsAZO9>!xa|t57W7UxRfR*yKFIf{aN*9b_>o{vesW>f;o2s4 zw#urQ6x;n>DFunon%LCgSgY!pa>tYx>*<`@KqL#~^#H zeo5q&PtL@QwnZlo508Sod&BI$caV%US#U#;CK#q0hWipR6*u8g0jW^KmP#EgW_`N0 zyjATUf)yika#6oM`;CWO(~e-tT}{VWJ0h>M;jv;Z4i*X3uj|bsW%Ky79p-zN5e3N2 z0Uw}?H;6;<2f-nASbNon50Nah@xCa-{1-0(q|Eu*#!9|bc8TDQ2 zh8i865F_)bb>`5437szK={rpAvQktF!iD?1bI&v*d#R6nDB<-LPxY20;;r^{+dtKC zaBHI?YDQ~arfPZz3k2p2#?ZK$PJd6!M_%$6H6laxz-QIP=kWKZKyUjF)>A${j70SO z-;{Rp@0owc;ofiai+eyD@e3IQ7r)b4Sy_!eYTS%xf`d7U3*NEaW6--tT)GhS;Y<$x`3# zBst#f3m(K+2`3nP9rGWm)WFkO4P?cv9O5M42aS{4jm9&a&^j74wFoKN@D?1j<fiJZ&s6I> z(&W%K-xOcoC@s-X)&FKv$cgZw>qe<)a;(5Fcpmcfsl2v0fpKm&o0lMZ1I+MLu%ErL zs5<8ZI(%~HNK4mqWH&aIVZD15%%E!(Y-2#kbT2=%_?@1jh#lsMr+mX}kUBJ#&`3g$ z=ZE*4vwi2whNXZV>A&Q_klg)^;+xxBujx>HhPObxWi?@+DekGAk(%lWVp?nfpL*Ja z-DMaR7S`{i`&5ORNe10e+=)dMaSSvBU2XbJk@#3}ZWZs3JEp;Js&Q3P_{gL}(=V+d zH4yq3JuCI$Br&cHtE2bsAQnDGi5VbzeDod>%l0+wW0}T42D|q57iQgJ?Nf3I!k7en z5YRIG}^ud4e@5ctid`)%|PJ`M#8kK?WInbz;5yZ@iqYNiBzx{a- zc78K=dG_ixyZ6K?jeBYAH9r5{)m&ft$~KBQmHR-0qm8WxH(2NB6}vFwer(&b=Ia#{ zyo3f;fh}8S$e-z>^9u{N8ndZ_hp;_zi>lG0kBU-GeU-iN{Q84e@teB?mB1~Y-G#-| zr@cS_o!$Myfbp|F!<2DzZ&sb@Ql}0bI%e;PbMj@*qmDr4^}lucT!+t4^Ro%sdj~EY zGW!7XTJ~CT63lD6@g*W663JFW5AT)%=B>Yn`C!~=Xt!AiNq59csadF#Y{`pihvdk3r!11D4%bo+gix|8{ANW2aaA53Jru(QovJka1~` z+m#W~D=Qs%pKX#t9ng6B{`-8UaFcT6@zN>HN%T$C4$SlO9cnK@Dr4%KrosRwqtx%o ze-_+vQ!2JT|4eQ0z#Rx2{m7cb2xcO_&Q3VJ%D;+qJ!5{OI{W z4OEIMJ=6*Bz(g_3gm+XNDtkq`F93gy0#)c@%b=eqeEI8hi6c?)9}EG~uYQz;UH#*} z7DdaUd?eZr?-@p3chD{oq1@FAuJ|VX4}o?;90=(j()xc{;b zF|Z_!|E<^WkY%L*Z^)JHalrlmY5^{Z{&(QjrHO)g;>iC{Yb&3$nm6qdNuKaSelQ(6 z0v-Q%wu7C>a8zvkxqAzA^fyvrW3{Nn#5N0b@EpS5%GPf4tsq^*6l|D6U z^XUE`BlqvuFK&0qyVKaw<8R---EVHVmq52=zeA8Lc)gOy-ee=>l@2F)2++ysm|s>f@j30<3kVCX%qZ`PeBL(A@OVQ&%C}S1k zhkcC14F*>+56R1_YpwS!V+BsE+(tt4;{VC2R&T%UzF77~%hAwt&ztQ9vFtB_u2Ho9 zFPOR)0%Qp|4@JMp+U~#om(aLYNfvdgQDK8pC_<*m5@jo2Qo#@`7j-}RRTl^ftN@-w z8+gdRFo6!5C82c=lw;?WXh*)s-Uk#Lbx4`(^oBQGCVqd<6S zNHzuKCDi>7v)|}Xx290q{*bJc_hbKk#PtKlHO^y2h#HjwP1o8$w;$J*QCDeFf$pX0 z|ByG1RJjE0Sin0upOKWr3JSdj-^RpM7N$pdR_DgIE5&LIhII=zR;F*k77dsXmc` zRg=?+R6ov^6@6l5Ef*acSdNLr`w6cj`Ub@`v@ZevnlU)^iT{fqwe?X8BV zdvnCSKElD>2d!FV-b%|pnNQ*V+2gWDccq49><1N`99-<|8tKALsD6HaAh#$E1gaLb zP!7EX+oFN;NYpt}4SL*qxf)IZ7Ev8e3PdXLuI6YaRqrGCffDn=`N4HkWV^jDp>UsS z7jJ?c!hVb#(BY360dpUS*PO6omB*&(DxwKSzNs3I49Bgr)ORsD>=ghm_l0wqBPv< zxSrA*PB(Z9{H(^2PaL7bBcu$(A{j8PsoYvDV2XUmh^oo^oYSv5>>`?Uf4%^_c9W6( zv^#^s;?srzgLQk)C zmupcCwq?x_m`^=5&$MSFEzgUa;y-r#8M0Mi2Khfr7?^IzK*}M+luIdOGY$aI&Hn4?W0|ZDM{E(&uI6 zunxOH18)xP5k3~{AjH`I$4&Ot_m5}sB#v6I!xNXhs>W+IwLfIF_)K$$3pxri`aU&{eyhNm}?seiWua?%?D!wcjPz=w}5Z<>-!CV0~VB6I}uJgnVLj>6F zL5xygK)^wkbrf}eskZF*f*@T^DYqo#&UUrBhE-Kz)x=Fl0 zqd3TYd$bvuI#?8)nOP?D80&cb&z}jva4|A7cTRtTXjF+5?jbcWo5+kb*Esbbvc6${ z3gmSILc+tp9p`V&cymj}8W`_Ket+?fTfJ~wTU*<8e+j}uvOO*a4$j*=SDdk>oZOL9 z9(Q*?>;6_;JjB5y1#*ZP@uV5)N%=6xcE1R@YGcQ!A!loaCgBsB#h}AsNNVs1;>)9a zJkCLQ{Zjtocgb`)TiZ1(%NeLWLIXE6ke{Ymo!9d*p}`0g41u@GI-uBsJpY%EGK_z z>5x^4b3&S64uyzFE5CGH_Paoq)@}!>`@>H6a!+SW=Irz~J6XcBockG);~o(s8Y4dbcdi4`|~GHQ3`Nh;qU2ILDj0 zNI>ko8e>S|Q3#w_T81mBz$OHI_JshU>^%aYB@x|zDha@@ow)hZ5)$Np{o+tvdt+us zpWDM;fzf_SBqDZbRkGkI>D74SIqeX+{8|}7Q@2bpmV~x~dv;J?d75f=Cs?klZfN-L z#T|1Cu;HQO^Q8qL@K<~3F;s|@c-{XWuHFKu$~9d7e(9Ew5|9Rw5JWm81Or7uI;5o= zq`L%^P$Z;7x}~L2N+gt&S|}+9yW6ciL2N%4lTLY!;E>U|LblP~z?yyC@FLx1{*{yZuu6Zt(U%y+}E zB`}$e&Dy5Fpj22c|5i@XkKM>eIp2dmN$`9#zpPtJnPao8iBEV57g6}P8h9g3m*qn| z_B&nU+6n=>7yglf>@ZPXW7LjWXEwk`vhW9b2l2Rxa0cT5tz-Q~p>c|yzFe9NLsmk3 zJd32{)Y{W(u-+58cCGvUDNABs??|EA%=ruiXma>Y+I#2@0VW9BUw_kycyasj^%o4w zPBnWa9$JyX*Pde{lhsyOzs;nDG+=^@>8NpXzZXWeb>Ikq3VJEosoSBMf363ZG=| z@gcDI%GIURy>)(4P{0LDsh-8k%uMFl;9Sk(s}@Wiv0&joVW_J5>o7ev^)*aFNbX1h zgKh+3`<}r;Ew~&_X>n5*Q4>vtlJ5+fcx|SX$_dGcj0CF+ZW(lRKBOA5EYAAAqMCIx zQ{Gh8(t|YSW7$k*z1KP}*0mNB81Dt#-+#3G%R1rH}X(ADL(sBk*q_(lU zVwj%jbEN;WI+7e38Xh78aUILMr!W6o7px&-N?6yfT`S(*-31%3a;3+QIl&Ikjlruv%Z$wM%TG-C**LFe{s%Q=rqbZZDRdOHMsa~T8dB-*YFYe66N zmLliQt+nRtYX0MjmLJW3sZLLK2T!#yrZ4?=kH)c#+%rVIEq`(jO$Ze(O2&N5$!hWd z7R+ipHrY)B%0zymc6@vVkh92>`&8SPyaHp%V@S(vF>!iQ>sAywsUCp~k5!T=%2lptwY_+I!7-!giem zFQsm8btBV~TLs8;6t&FDE4R#r{%l?e3zRiF`S;3c!sr-_Mge%aBW8&i@3PDJ< z6F+3d2QoAh#t$tiK8$7tUM?@H7`mdlJJskKgPeOsD zfvKH^rC#M}>>I`+V%I*TVz@bi;msitl}*TC^B>t4Q6D` zl>c;B435Uo-jo-y8RLCn+MTwvPme<**>>Hq)(Sh@zCeA;&hUoJ)ANnqn*L2Z?E7TQ zmt;HcV82CfVsc<76Jij?RENaZWZTeeF1?6X;wT-V&*Ynon0=-wwtw;0*VE_n=<)fj zxMm)^>wMl>Dsr`$IOIAMT$#M_r9F9u3tse&jlA5Evl+8%IGx2oT4gHr+}!H6JP+ID zvtld4b-Cg-xKt8;VDi}|i}a_9x61q=u)3e}fKGGy$YsQ>cIpO6^aWegZw&#lL^UPhv_63Nm5h_-88I zqn*vRsV~a>LWeC-Q>kgw4}QHL=HmNAoSbJ=MSlPJukf|WtCzd3x!AAdF22tGn63U? zNcVe=_q}TSQ3kC@2U(Zjm;=-X?di?kP7NV*p{*^y)s`C!-(CpFgdF)8Z00g7K0BmC zcQd#U_%9MUHse+%=}F>&V^3d|oLurUyMVJsI$?pH)%{8Lj3<@8-`ZowgJqwiduC-G z1GhzpZM0%eF_=AFWlr$=HyNpr+oWx0!NPsBO?Gr`JUDZHmkzgtk78~`GsMesQ=3j( z5(+71`3F&5d;C>aZD0JNh?}l78z=Mn&FD0;JKPxGsBhgceB-HjPD4nvHL+DmCgM*_ zL%7S_lpY}p`az$6o1_~LaK;ylwSaz907DKTpjb?_5~73uVlxr;~PiF-`<#G!M#Kw*KPa!AMh9gJ;$(ma4pQ_fZ=jvo1o|3yt+)^sj z2&Sm*B=Yx-j!F0(ltUCav8?LgX?z}(7yBZP-)bP$@tR_XOvqBiyJnX4yro-?S{A)A z5C0xm*PHuqdl->3F>T@>>Q(*ipNjTWM^4jXF6@^N4vMyegYMp8VNRA;5DN{tO?|%; z^ZplVg^-79xEO?36t+E*+#kJ(#4ZWK9sgm9jYa#g&cB1%K3KVdBRr}~Z$s{7o#`(d zhc{1dx40|GLhuxylEPzHYy1A|Psusb#Z|w%&pu{wqUK+}S6ZFR^8L`1%@DTcbw8Kf zayTphiBe}UuD67(%#8VW2{BD`D3L zo(FO2oJl2z_41eg)1&vBhRHfm^$rY#eYY&px)HCW!NS4T=hiMEN&Z$|0bAr7s5#TIDsYhbC@HtW%L#`mKT!Ja5B`n6Z3%lv!Fcc< zukFgHu!Lt{yT! zq|6^%1%_8qk-!AqgxZVb;$owZx)_K=@iT*$Z~W!*?VH8PWsrY#Vhs1xWyHfx`?bzr>P8*jQY?T6srUo@!u zRZ>!t@BVk9{cS5%0J$uJbXf`!f~E&lON$#)7zatGImev`6K{6URx>Bx$_Q|I+S4hj z4wB2)PCHl=x-6ds8YU*sjW}v<MV(oz~-MvlZ!UbZabF9bII_u2#;y{X-Wj5KV7Y^*pbB z9KsI?!^R4jpPBLeZf7dxg@sa(>>DC+7xcHZ$&4%}r;!@}nv1<{e+y zPbp8)-I4h=}}N=pD(d@eZCuo`TbI z*7w)USFZFLpiV$P&f!4#b7XAnD>!kh1NFo{#<0%co6;8~$7uYaQJhgLVGotP=Qv_y`Gx?mg+iM3iABw{=Zw z99@=XF(0x8QuGy!`#!t;!Mz7}K^V;~EF7QB^)-vw z!;_@$%?0>l3IOQJf)ryQRXhj8p;7ip@!iPkiucpS@=0Uvr#lVTo{s4tT6BqMvlP zr5K69$_KS?t&UOg)0Ukz@0v+=O1oucV0J)iYTDs`$_p{SzqAI10;HH2Bwbz1?6N^g z>A~u_!GSJ#Roc8e_G$dZ@_*YW{@)g9ZmMd3*j#&H!YLHz<1+rPM|Ea5uW+L!RdTLe^Q+Z zjfnsGCEeO^d08W|NIQ;0`y)O4B6=ZghQ$Up|AfPuT$-U=WulRls95a#NJ_t{R6zc* zx6Qg+s>CtTCwCu8-4u)5HyjsLjc)UsJQr(RgN3DvkL~y(-(9qo4R?Pp^}mdFKa?o+I!ugoGE9cIOWZ*B&V<7Ms5VVj+|j10@(vjeRj6pWQ}1pz;U zxqltuidP!(Ew9RaJyGwJGoH2&q=X$DBI<(MCx36rtG**dE-{G70?k1QJr9&oYknzV zXzl!DY4@XQsdCUAi!##_4myX8dgJ4ly7{Fwa~D2u3ctUuk4up0`0R2M1h3`pIj)?i za1g2eb^D?3v@*nU6h%M%ngTcnm#;nkYgf{Y#MW6+@qv&Q7XkE<>E@G^4_Xh)Z}A>s z$wIc5(+YeW6Hm3{se4sjzZXJH6x?kIMpng9-aq>ZwRy)rRZbGV>Wuu|m-s>1Gp}qG zYc|EvKP#Q*tC?Vyd*Y2EQE>gd`or_P*g z2(34fFqwQgjknL4NQ0n+oQw=f&LgL$#%(r;nbbWIX#?dK5Q4U>u`cD{uJFhG+8ZP_ zQsAF+#&E3Pm{`kTYV%*>F*3C^7)KSd$w=NN-JHVdFrpJ*9bTEq<&zI$KjgecLlAkh ze$|``)20Q-ZpDyJG0K2HPj=9D4e726T}XQ zucPG2$u77M79=N=yncVQMaNKm%2mK>V7`&ZN-XI^dk#OBz)n1KPX}Y5IxVj8Tk4mh zS2@opj)jHpi=PMQSph!tg;MpKJS%Ayc7}cC8ySh?Zhw9#N;@yy2QhUhH>cXEIag(wxbhclpjgWeu6sXlo|hYAfLv{!?5!++LD=d=BL# zRd1ea{QTv!?+Dg#<~|jF=r`Y0GOqX7W(A{{%CN~-lx;ak$mgy{CEVQH)(PMi59h)^ zKJIKNFJU0yztI_Y=Q0@ud;8aN(L`m4uC`$ubjf=PRc3cY);{wAe^rX~4^vBk!A#C} z&xAh<97)bJ&o^zQ9^_IW0r%NM3>^NgRV_Zam~C6@51Ee{Ru*hl`y1L2lKKnn7ZrJG3(Kmy%_L!RMP@#!b16ba-@D%Q zjJ!?vfJB+VvGV*`%}Q7}ihhl$0*|-`Y?vq_zWfq2!@2-}JD_2x=<5@c-}5wF-uO&p z`Z7q^fw0sKfU!OE0kQst0v9!b_`ART$`dAositc1Uv`-V2`C_@4UCyq)wU?y#(l>9 z!t-;7UljVMo}?k;fkj-*0eLr>^RU85qJFb?zbNxRyTw0uZ&)WYj{Hy=ADbZ1$@jZC zgXp|)?F+GQOG@D-)IRPUB(2{FJ7Wo+CTQ% zwcc-h^PDuR9Z9xZ5O!FAac#0FbEqqdf}!n|cjew3Tn}*gNZ`SWmEx461f6%y$^0hfzIunxtUo2#|2ad6l!e$OrvT) zTSW#u^nZ9o6uUJcfu&wcK*{+A@|1wHd5586>h+?S$drondYA?~1)&Zpf>0W^jC@$0 z92&tWC!3ZGZPOsgoOv%6LM9+(M%np)vjEr?H{Cb_vICT5%uPDJ^jb3h?6`?g@b7=6 z9(ukqRyeWUY;l0Rj4K(;Q6w9BZh(p{ZbZ#EIh6QoxwkgX57_*qzXLY{REGf1(I!9) zWS^@W{>=uYX^)pjDchC?QGv(ona$YR#BKi6*BLf0a&X!<$Nj?E`i_Sa3}ihlnOQrq zw(sj}Q9k3nXZ!$XQZb~%HHUb4Fs(e1DB$54$vc@Sxk#&tCcdjhXMgUWxUz8a=||2} zXEtTORyz|P+>?>ny7|qcTKb3RX6N>N;?|!CA6tfPhOI>wQ0$NQ;S7;Y(sES1cj&Mk z!$h)m>l72qo>7eodh><_eh(HImDl8Hi?SJ)CNG*{GZpHv6jH)S!oa4F>LMHG2y6is zLm!B?%U36Bc+3IBTJO2b38GIicM(XA9iqbZh#$7?mHr&EE|Pw0XKl?L zpZbrTm)Zs#J8C3&5TxSYOq~y>ZTiY4-*o?3qZiKVbwo({PVw*^S+xpXJ0twS_)5Gt zj3>>==dhTMjlKAR0o0jy9l}O!cS?*WZFeq}mKU;quDQf#YIMQuU6;kBLMgXdwydF< zqCBv-q`lTsX(XFbGJZG6rb$j)n-<<|mN)lR)YO83>~K#7=qw5V1Jfdu{rWcQaF7*8 z-W1t;FgN;~8=C+p>9CH}F}@+1B%=ibqyHJB&Dp^^{mY){o0jB18BCIc;#s-Mg=N)D z{}rC!K5``La$gUKjm5`Ss0{)~h@f>;PSH-}lc>XDQbXLOYx0)DYsU~-PBF$E)tKZFIyvHq=HxgQ+VpnX1oCDlkM z`?oy0(PjBD(gtDyN^mt+eUc>5ZhX_3^k>RW~k6ZCD_fU!g;i{JZQ z@4l9NkHf5j$z>mR# z91TpL?m;6hS=7Nmt9+WE@$}fUX_ud>Ix)bXpMf}SGz_OtaO-Eb8Skm9WC$e={~^=l z4c#HO>}C#(u|rxGoz{nW@lrjmdQ97uJNZ&y5071B|^j`cy!d9-ir9Gv2by ziX+HOR3evrfPMLzv(RYYp|dq>i6y zfr1FyUOpQztwn2DIdIYWQ>~)P^j^g@gojHAAXO}GR2i3gqSqm|Sl!EUctq0;SJ~QP< zeLP>kL*=K>WWh9Vi8+KV)NdqPE~74T$pCR5Yu)7zXxp+Z??I*QZ8B&`nw%?@_w?Q7 zvd$d-gXS`g$$S=wc6Xo(*i2{*&EYs9qqHMECZZ-pC*kt!tm+yDp#gc!9~zWps>b}M zwv1A5e8MmONgSa5E6jS$ED;1`upmF zbCrd!IXvpsAPeX1OHtU!Sn#*&I~v^a^4#&Cq`RnK*LDK8D`n(;aB#4pwEww}(f#}Q zW`b8bK7UpwbXqAsp z{;m4WQdTks=JuSK`EAQO1F|0h14f_YZQ^^>Ep&W>XoMTgn* z;Vv1by5<9f5dTtj_PuEi2C*OXz|%@C^|yFsNKJ=9UWtt9&8I1^9MPqrU(4W=^e<|2 zx{=81J)ndj3iqbs-+cY51Q=bh>5Ew|q=W+T325lO6L`VUM&l6Ez7U$hvi>=d`2$xt z$F%0(im{77JkM7~YQDe?*a~5D(@54xZVouQEvVpmybxHSaRX_CpYmedZ2@Z zgd|icw*#n$MG#cSou4v|{e~>Ylb#HmweDL9v4zV3W=h*+Szd)fkT^NRd!qpZAZgt; zHa2>?y!+4d$`&qQQr@I30K-&V$|9@wA7(<+!6gy9sX*1>W1}Y<-+y^j)CZ@=3nx*DBn zg^lZ6mp;J}5cuo6kuA04(RjOjgjC+d3!KIe=8%8w-S4B>ao5C5y?g*KMN61pdCGp>H73KZC6oH@B0xEK zedAB&QjD#CNGuzrVpJxV^#S1eIj_q2`G8dv)1SUnf77jQ3fWx2Z~PGT72`rg~8uAo=;x)oRQp`J)?$%N)B8a^c4FHsXDkZW=CG!A-qzqFfI9G`5hrG z0*CcT-dB?&)fZWq759En$fKF0bRFV&A_}Z;B-Gh=PWmg$`~o#dwfCa&JrWL^pS|k* zbUc{B-FBpggZ5Gd>Bo~VOmsg9%`dgT(Z4x=w&}PMFzK*!EL!F&gZN1_o+DYPhG2OF`E%leZloBJp+bk8n5cX51tUCb1;GN4- zE1=y}i#1D~ePE<|@7dtK+Q|-g-Tf`pM1#E{qSP z_Mmbw01r8uKE3Tu|9ATK!&6Jv?JAey$&bZD3C|RPFB-?|hrmrz-b@;mRq}Lgx28TQ zZR&t#`=s%FqT$R=;;K{au{V*TGV8g_Wqg*G7?0*{e$SeMLb?!XX?~hDuJ`Ef@=;GL zd=JK3&Id9H>S;5lq_Iys=WlRhq!O0`zx#H@|F&-q;{un81OET59K3P_-Te9QWt{)} z(`}W^S?&Pf^&B%OuG%;Do;(9eaNyvM*TIHw_u|osUy5kVfzE6{AY#^*AC6uxA)aP8 z^dy@?&Aio0ObRb6zJnR?Elo1<*IG_W8iCVyu{r-@djQ8DrcCbxyAf^*qF+F4%W@P!YX8W3y6&g(s+nnOAFdke2%*GDj zcWPoIX=r9r$vi z@2;z*zS4lP@@*XgBdSQq@kKQ9wLZe2VtC@k_=?xuOk?Z5X1aV1K@$xj*$Y4v`om1X zMK0Vv{r0m>5ueuGWR4*hl_3N#%zZ#N6(#?}yB*v5RD66*PCyt8Zx0rP(=XL!DI3=B zm%~@2n$49x8*Y{lb-(`Ti0$W^*HvL_N(`tFGPIJ>Hd0kQy|Q$$w~hWc!O&d1sM*PQ zYaW^WU%leS&-G5GRA@RY{A0hqbd$0LZM%2arK^!ZdW(h54mnt$G=OC)eJ;5gUSw8k zPKl4{S#~MY6*LV-?E@U@QH0bY=S2zb&<9bovOoA9Crd+XXa%F40+P4 zvv#w#myW78sgf1&2Np8Y(;q9p7Yr5a-8=Tv2@T>%{zM|vq{SuJ(R?_r5MwbC?fs@v zjQ^meQ5oTx~wg_)TV@B+TfAgg@?D#|rO(!DMpKl+LgLeHTP)4Rt)fC13UvfB zd9Hk$U0v0zJWB@t8;j{=)xPobow?KWJJ&)2X43kHZ`f^2ez==+BqAi_N`ZI*OBYzt zxKQwgAnL=@>s*o0j0?~#Ueu3)c7-!Emq0P~>))d-u%k19s&^5HQ;yCioMx_LA9PeD zym^zQq^z8qE`F=CG_+iuyZ4>UTdEBytaJg30R}XnI0qag{2FFqWs&6y5|fjApX!q8 z0ZJ9*H;r}hU`A*ReX`7ZTdz-~R+51X8xNjmy(3F~k1MA?0=SIsS{UO&WG8^IQv#nV z^l714Jsn?}uPbP?J(ipr?UMFIujE~#oR3m1cWKE70VUd799+WHVKGe6cwcfjLrLy9 zsACxQa?8k|-njkv>9vz!d6haO1CK-WYd}Xvd}4Zf*-kL=OZhjcsU=2hTgCu9!2%za zi1`Vq^NRDlhQ)~0Y#^r7VjP@hfP|eyQ~2s+GP_T!O!;(YNRfMevtD0W{X_?Ve89nC?Q789-7#`&Bn} zzYcliEgz)#q^14nQ@!?ill$Dp8~?A_q%({(B4aGCA|vnn`P~M%Seu{uGs#)k9ZBW$ z0Zm~^{F!pcbPA6N7!`smABu|`TmX^A2r>lc3Riu72B6#mTA5THAC1HUbZcZbw7BI| zDQ!jQ|9MG^ILyBO@}(5st|fm{zr=@{L>bS~>8#NN zgmDE`#3^}5>%&0jr*qmk32D27U>sst@wlS*ZwJ~ke{-h0hOcNRcNMyFajX&k}J`q#6 z(UMU5dwTFXs-isB7%_s0OARFXxrIeA94v(KGsmsIOqWkwku6_cjE~hi&RZUHy{)Pc z4Z=asHMVNei&~$~pfQ_C;^=vvJ`pE1K7U|+uL!(V#0G^gyLamh%EsLnmHt*fUP>=H zeyy)HtGyNwvvp}xJ-4i=85w71pw9pCBL!3=(EISGEi_>eNYkEO=c6V9aB%*0+p*>iY`4XYQQ1vLcR)b_#=j2a4phf@b%J%1i|J|ohTy*r{YNL1 zZ1dS67!{kfAT=XMTy7gBQlUASdtr;wSY-;-EpiG9`3CMrm|8mc2}ebnb&bSVToSqv z0R9`H21R_DUQaQ2Yif=ad}_EDMv}1{XKf28Wp5!p0|T0{Zu@eYj$JP7rEp$s>Mw5B zU$89v5Z75l>Gib&QuAQ z?=Y4d{L8+g>osW1JPe+K_?1ma=p8`9bHG|)`)}2t#6X-g9F048**h%SM((nn)zg`TBY~C*^d7F}Kg-@HKZFzrhFl^2K zD^u?aC()K(x0>@bst1Na7|%*Cx+vAk7Wm2VfmV!fL|Tx8fa4e@XtSXLc<72MxyeCE zcoXtY261QXx}~#*x<4?TzX7B~0R;Q=?X+UN0B{tjoq%H;pXE!IZKIxrf6Cs)Pr^r6 z9UJ##=4HHWrOYr`u$%J_x>B=1XSCxnjT)0_W4UYu-rAobQ73J~fy(d);DwxtTpN^2 zAKYDosDh=e9Nx>YXH;|5tZmnz28}KKjl>@Ag+rJzTdUzoIE{PzHul{+Yy|zKO-(vr z@4o)8&5jGxu_4gMGbn!vKY%L))!b@bK1jV_J=uy3_Dx-nls7le(;}P-ehm=Iac}W? zI53=-H}#iNpDmw0<2%U1c5XOXhq4!X&9!!6f?a_#W25#?zE$!_4gbrv3}ae!#Rx4^ zK+o;$)igC*a_z5A;Vr#1hhfa4oyBO2>I<^vdTB5fh{8jAio}mxNAfmXQA6m-T0Z#L zm-*>l)*+&Ol;z9%SU7}G?Ya1q@rNa;sPo|EH<<8cOjth+w-|dFek$#S0I^ifVHPFM zh=!a0o@gI^@uj4wDkNoL-|bq=ixV)5C_1CkNKQ)f5EK=yJ2^WH&?!b4ZupO_9*mt0 znn0sBdhp_~TLw)p#tOI+ki_AKz@qwa4X2Hah6WF++pw&FT@R?#|DeB_Ftgy*%m{cU zFp`EyW2eCA5JF-qjv{!Ag^#xKFs?CIRuoT}Tj+eT*VSM(oDkuLn@9^53KhHG*LP_<{Ao5t(1 zwkB7`lvAOBy`16ChtQ4cYTx(da61N`DwIQ^8!eyQ%fNr7Q1EGc2$n zVklf1GAMv>_vtcD!MHtqx}VM<(Qw|;oLQ$u#;q`(4CYkM!;CpN#p~~VyETXwEN=aI z-*}_-d24=te(_VKcS*n7e=tJy+5k;6w~gtaM!tqk9^^Gx4|4XxsNAAnWM5EH7aGH|YW36sH#YhJ^e&hT+2WdPgQJpaEQwCH|zCl{b72 z%07pe#`+$$Sx_`>4rOA_HBAq8j^0Dxgu+H&U;`V1)&1nH8FC*}C0Qu`3qug~o9Jkq2yyk=cq|t<>xDt5J`Jk&1(l(C zI=TV1_&StmU8Pd-=v$!T0!DirZjb6}%BvEtTM?%)Bx~%4|G8{_KeP1(_bm}d!CwNdlhM!?R z2A%W4i6F^bs=-*i51r)LQ0Y_38fU6F#|{0@MCLoF z9GbRqf6*-zs)u>L%U5?!xk&6~DC8$#!G?Vcqf@sBkH&X>PK)zq5AtF!An5#6F4AXa zH#7EA{BmaNP?9|O%1fjdZd#BcMuxa6%16y#&T7w5Ob<`(ud_z@HI~5@&ef#6xfVzp zUL`+&W9aK1?Y)kg0Wf=jgedV8KtkNW?u9*akI7dZZ4|q^%XrfSTNp$qZXpL&)=Q7O z5s%}6&fg`kE|otKGvIu0yoSH|l%1xx?q@J;MD|<-f+9awWlopjL<)ZdR_ov-W@}!nq zCx;qykdkRH%HX?|r&B>kcHZ@p%vHx$9)y(ev~mn(7~+dZN#AOa*ebf;Fg)fm!_Yc) zA&}A!a5VVgURhe2z2V?Vau5oMo)`btjNXYhgrg($)oM!b1`_IyjcFeOmAz2Ux0BI! zN`0qJCa$X%^V8L0%`>-geCL57@sSzE%N}(XGcOwpF}QEvP9OjBKSQ4}GFL2H2>*8g z)BxlE$^%=3$p6fNwg>-z#F9g$vx`RKxm<-iogJPF5VH+_`!=notsM>%op(6njDK~6 zVv3bEAIPN_t#o+)osGw;Q~-9$5-D3q!D0GwtQW$_4tKrRhzD%Tzm=vRvDcNRTRKoX zrzH8`d{S}wZWKOm_*$%no&4@uYCreN=>@3|Kf8k8@!X9N{Zqx<@f0J^*I^|jp#xgc zIfeqNR$ocy4+54cMGMEGxG~TmCRye-cmgcoRm-o*VpQq}W)Bd%fu%j9f~GKRYrpts z&x?|h(g-dgh{MPt6!y#niLv0r;0MHI!R-N{Oj~jNbRwToWMd&@&yl_TK8J?i;9LD` zzJkI+IR%A~Cs*#n3;LU0Ef4!%J{rTs4AjmozP_((4)RJ@iK{S;=O}*jX619}bh)ih zJ|`k2y$4ms9AC4sf?su`{Smh;GA~_f3tGJ3-I&Sup0d&EtKiXV7R~eC{IY7j&X_K- z>0eRkpY|)6NOod^x$jb0dJBqZ2d!eHm%f+teGXL1*Yw{Z2_-4kr6>Z=fdqdwKn+pk zA!NBv|2WOlMw=;Dei_g`8AxcoHR@z{>v1~a@6^Y%2sh9Ad-BhpU6>-Hz5dkcyK-w5 zM(z=Fx>3x%xzCg2h^bnS2veE#SQD>!+2(S~*hkAV4H?W-a6I@0s?Gpy-Y#$&WB9-~ z70sCPf3pA-5s)b2vw#-~9K3M+0wzC9Dc9QZ;q&A?<4SGEzY{l!8Kr0i-xI@-2TP0w z0wE$iBD6_U&i54!6V4i4J{o-NqU2;c;5xjEk8hR&emz~G`f(cn2e1Ii$Hxw0N?o9W zzp!1R&Yeblaw*yeudC=gjq<-_5J?-uGATLz#H|pw- zbT>Em+^23_95NjqbQ@+0+kK{C@=unuU3E==#w5FA(I>u+gG{GiObs7268LY795A=( z5Ljm81#oB+B1c{wb@s5O`Ujmj*CfVoFPgWxoj2c+n-j!oJFi=7EXJFYds(@f=M!Ei ztHD{3rN%YXay2kBpSC0VDvQV!_5~zuzSGgucP6}35*U`aoa-Q6<5M7)_)lamG3)Cg?(WBW)xp4lX-<_2Hg0iwM zptc(ezK0XwY9*3h;dkcM@Hk)X8AL}=qk|0r&PE2FK(;1k5L2P0r9G?>RcZq%-8I+| zO!^C*SH&Ee?Sa^i!o$UVyu=-2Oxy6&_U`lNxnFy85JdZvt5xss&R2R*;Kof-=iakE z&A~Bgu=%++D0A=Mp~&GutBjg9Z_Vwfd??|np8=y1ZJkhzgDDrT&fN($h^(iDV2c(7 z^RwQ+HZv>EPlZoC%CL3xTA`b1+|Dy7*qog*Y_rt-s%G}pDG&Ibu`iZ>qq= zn7$Ub=Kv$~pwi(LFsoth=J>}h70=azqUsNHd_kcrw2zo=2V@TqfXWw9rtKr%N>qL%~!WKFrF)i@emYOd~T{LOVux zTAk*@R?(KQLs?jNqv%3`W((pk^m!%*!F(cE{LyN!*~Mm7TKQ`W{)n!nD7f^N#xWn|qAEboN;= z)_K}dpZj?>UWcB!F>Wt6HMcI#JW!m2-9x^tb;khXi9zU8Pic$bTxougb;0x~Pa6*O z^mYJnSpa%bI$oFCW3;J*s49z?qP)Dj8$RD^N^XYG^2GXfhF_(*LTSS_&4p)a%w@@q z`A#)xlAbc!(Ae>JBsrBZ^*{W?f_g55A_5zHrrRJc0SArfiVA^{&`@w>nTLA>t_Ro? zQ5(5!UU=FZfRllQA>`%D9H_9MTR*C*WjvpUt@H=T;woE0}^JE{Vp+uAhK7NyS$$%u6gm@BAv z+Hd?&dCw0ndr~mFs9vgD^Azl}Ufg+3LNVTN!tlwwEhzwD;4&X7iow46=x8X_k32<2 z;?mMvYKdEN528o}SxAcaCFJQym*3f*R=0jj{*hN?HiH48 z$;g5Y+)K1^6Ijx<3lKv!8hU!B@dyoR8wkdYgy_CQX#)zucOe==?^ZAbe6+n*-da?q z-w*_Tj+f_FKDIh964L6v9@~zv9OJxHEsL#lpM6qV1UJ#YUp}qrVfq4@`~qZRFyl`F zzFC(*AsiylOjdwLLZ`rI(3C_>E6}DZYTp$KorcG9mBO5A+)=U$X8cLYy3-|G0lgot z*jKI`V;!R75hQ?qygcV|I(|TCpEMJAO6>rjSO8{((MLIw1Y`&TC|ccwOY9A-{^@mP zy&ENCrr%po+rMm-h#6C84T>8h{wbft9xujBR2orBBs}ZdFb+LNDkE5u1@Z7hNcdwWRZ?1^=(B+6pYmu3U=b_(x7fC$8 zZL3SJ1C*_xv{XYwON(bZ9?Tnr5C2AM&}9nW64SI-w2G%vZ6*AE>rCo~p+sm^>w9A= zLL+k|=e_J5T7|GTcL}CEkC^By{o&J9JD?b0@j2I@hRSEn`#9w9rn=x)Y`R-2RS+t_ znr-c;J#fYREC64thBR6}3;isgNj>NQ2^Hw3zC+RMQ>E=s!L@9~S9Hyukso;!aL-6q ztRtyJQdCKdWCBQGt}r$}eo=)}^2MszK6`nYF9#R{nL`P%OYU6e;`CPY^FHdH#huF8 zw->_A1cT-mk)CQ@Mmtq;nWCDeE(vrzE%!gyv7Ka@{?tfUX2N_9Ly+}6?-59TozjQ* z{-t%>VVzv%@Hbo@(fREjweRk9ruKrrZdqi+K&pnQY@Or!^#?PMODSq=Yv(*yMi0G7 zxNqpktjxqW1h-RT65%j3SjoTd50h5B`@w>?^1zyX;ME-`4I4Qpl3-n)%sPtutl82O zw;Ed@HgC7C0b(~McxOQwLK-fFoatxs%vzp*kI{iGq=)kOleKoQ&}$E<;c)vvC~sc% zbGubP4-f1G@L-Dos0^Bo8qceKLc>@YedTheJ$?ysDGNLM!hOF< ztyySOaKcud^^exCCD{mso$jg9m;2FVCoK;AiRLQf(1m(H&%eIQs2|aRVEJgHakB^dH(eFqd_C41B0Tn@8U&JG)O%#n78d@Q5VU7r zu+ux776q(CN6gv*S=lf~Szv&>Fjd7`bzuIcd;bpyqq5o2$z|&^QFi{#^|}YMQ+3lv zWhiM+)>DqbD=8tr)~-I2t=^n< z=sjO#SI?_w$rd6h#saiMFtgwacl6`$ME9WSa5bd=t=pZDeu__>CV@X~aTQg=qoNcw zG^oJROjSoG0@U(DLL^XTj_X}GjJgKX4&2Zz2!>I5iRre-^_5#SCV91yO z%DO@UrmQJ2e)yqaOGTaXEV`<(wW}~g^H)s9Q>UXuzStpRp7Jko3|T4#(UFl)VS)!8 z37`pvN-(IJMinUW1Zf7RNx<0j&)2+H*0n4ixWi7UP_=cVs4a7hECO?pQjyeXkf7{q z=<1Z#&Fojv8p#fy0Vj?P{B!%6Pb{3AxG#qBG^6h3fN`ZQHRQiSwi6Y0`cw99`%mx* z2s&c3V*bpZ{QD9@V{zw+j;euXgm`&V%yWXYq5RNIr5&I(^+1K=3lGLY1nbZS!VI71fac+DO2%jSS$y!b;dOE6#@`2y%c_>v`T3 z)*rK<#gfs3Lk;0Ruhf)j94Ut*cV)Dg2JRLx>Qm9s2%VcVf)gEq zJ@)2uCQFBTJOSj4k=f`PFJz8T;Dr<>3u<#UH8o(N8mz+Q+GE329#H%gu>863c6UOw z^(HPZ7|b9+M2og$g3mwxT(%gb&h~8-Ns@~-)YQV`p96}62%9V^G$eP11nIolZkw#Qf(eB0B$WBJ#oOi)|u z22RMW0wI?yQoYHR&k(}vJrrZRObWD}nuG)&Euobn!KwyE(F#2PTZ>>E5Pfs3h z9-ge>KXhw-dzZkwN)58omoSxMSFZLuy$EJeHsh6YZy~hJg?$h~+Jjr%C@2B@oZq^; zz^DojWaOgyi$g-C_M=7dCcy6m9Y^*m#4Pm?SHPOpfKugW07-7OUYwzA)l$p*tw)QC zg)FGqRO?&+_u-?Ibcr7xK{oP$Rg^_PnYPvtgv?PpIZ9G30ugr?F(+xmTo z?Jt*~FkictuSy!A!lh7d&KFc`uUk z;8`)xo0NXt(30b~+#hs!F@tnjmpVH;F0tLd-6F@2IO@VSU)AWL6a4?NEgJGEl_cfMxpxu zwe{WcRK@@Q=U#hXTq|T{CnF)NYp=|NWRHxjl0ELVg`^~v?3H9^WnCc@A#|-=GnKvf z^?Un#zTe;D_s7palm~UsIrp5`>p8v3$)9ljt3o4GK|d`S7$bWmxd0Ohj29dwA(_P# z=fi_wRv_HHHe?83Gytvy>EQqp0qp;P1MGED1tVQ$=;1?g*=`>9#70u)8UuTY7izo|QQ90I^4xfSdLQUW z`hIz(xj4GGTdaJz!1%>Z0)oyvH+9=ql7PP1Br^Oo>&@x3;JANKbaG+{@q_v90VHJ% zd+4)9Fz~hB!VBu692d~$Oc*jIg4N!VZl8Yb&r|*iVdna)RW;exR(qj*bMf{%^P_%0 zMPm;(j)8auY;xCmPuOA~G;9ES3;Ry@8aXRFJ5@qnB?zsWTqv`sf&)c;vM;cDcdvpQ zg(R@mVEN?H(0;Dl?#BlL(s2m3MLIAh?-L#3HbVjx4H*5igCr=qLN1?%4R5G(1zNVE%tzs zZos12iGoe`O5JpTp)T|^WCdoY^1~YsMZTFkZvDGP8eg{9TdNn|4{gJX>zx!Q za~&LwlsIV&G7>0mhn^UGuqlhPq-j20yMkn4DFrkFPns^s z;(z~2!XAE-i{Oy+!MN61c7fY05O;!kS6=6!daPkn>^-+iNFd3I6x{61L8D+$vEfRp?d7R*hMWrnNwBOxRGoEX z-)(v20y{Atqmm~(^UDQlQx;wMN{TKYn{G`f$2OCnCj+*az`?y{^IvJOx+c807aPa* z&&bFK0)syo>jB>RuFe~u47eRpaM6y~&_Y|Of`+^zBD&`ckvk}3g>t}h-nH|0cnD<5 z05=3RG_H{R1AE~M!3&prNFN3Y^Bj-7ovnyabEDmZR=`K-ocqwTu$n7stxqf2ruME4{cXIZ~XwULlN$4IdDJ z1svO-Ka7w4*(U0)p~^_5LCPj5?gk}_D#gRO@7|HS*IoelQ9v^RgK+k*T*Mm@*8?)Ed7fYuQw5HnLL#6 zvidNe34)5Mni+gpW_0&f2+;S%6A=h!aF&9{m&}tXuK<0N)tR!`a@w#oNtFfk+LZiR zyrxH-MCTWO_XqzDB37RWC!Al_B>)*z|?!yjHO*YpC(RhL_hg37i9Ojr9*s18z@#-bR?4=R41`^`K8Rn1WVbQAYQK1x*J91)VqF zUJu$Tn8L|)e4R1*ayv_O$X9rq_~p)cz;=T{Xk43K=Kw#=2GKGMc$_aZM&XvkS+0t< z<(|2%+%U*g-Wz%Gn3C*oQF)`O<^kEi$9nHXX7w7xe_#{Sx8 zt=xWL+xa8tJMNekzD{6zrNpVN2Wu52GI+~R{=-N+iR^bDq%8a?e)Cqr_Egu~rYmo5 z@lb+7g)V*l?}snXw^~Wh3F(C6alnDqK6oIqeR2qCZ~{?G;^FbSV{^=ziBN*nwlzo5 zr%w|rdi%;?qyf=(T0jODH1}9g-YOBunV+AWob0Uz>!Pvs{fw3aZ`l@8BaoW5j#E!vDr2Y)RTYrPVa<_D`yJnYvl458tHa5vf4w0aH@r*+(jp}fx zM>nP@A;VOBCn8x~73se2^>irVwd9(oNiJ*1S}Whfxjc6})4o6NB6zro59T(meYAL6 zTAs`$i#R*0E`Y~W z41RRYCb(DF5D@LWS8S8_UB9{49_^eop7-MpcmkbL$-=^dfAzq?fM7YC=lb==yWg$N z1J59dEwd-%_v+PhjW9xKfaUj(h0Xh5XYC{k-hZ7+c_no8>aHbF4u^uC10y7VV7Qif zJXE51mey_*f zw^>f0f){RmYnNA1Uj*qmFc~n0&jl~}_-zwb&gGa44wc`Q!8+u^psJy;!3uALL1vkm zl~4=K6V1o3=x5)R)x$7a9k}=84r{&y0$(rcvnyqUJEkb}8D_&MXHG;ykgdTx-uHNo zIDMxpiE955*hvEJAPb)?Oezu91khIiTB+mjFT=m*Yfk(kJ$KZLsL-@sg-YKaj5zjwwZU&)G+B1uL@ED_Ai5LB=74#9>ut;T z0B7tN8AiD!qEQ&?fJFFxHlO>3wBpQq?gzxEM{5RuQX`h2PL&GWuzQi7evYvJ25Im2 z)l^jhsg(f3&ic3xWG;J$FQzR66~gFfzJ&XTk5zNvP^wb>>Ur?Yk`MzAV3|sC9DgTZ zveXGC@x)iW=-8-t16WXS=$abnD&>^+=!{@~6U)B`)7c9H>W~~EUF0DVwm>IU0+{#y zWq7ypOizU7ia88MZ2YRFP`Nk6IY&0wyX_)K&CLAr+s$7z3+Mq#OgS^sgdWa=ad7iY ze+kJyfj;DaGUs47*BK|_F($DJ1T_$L<+}}7 zi|lH~15ai2hxbovzVV}#RWTLhLhCqN_Q0c$uYooYDI%1Hbe%&b{z}%&paG7#3GEwu z3UYF+NDVhZgSQ|if>dv(bz-fK925ZON=+(;m~SlwpGkd6KXHcn$SO8pF%b4(ft^H? zasuY4dd0+Zq2YjFu^q}#N0`4$>}IOXI?RRCc%Y~gS*=$a|CB3$6qPR+H6)o|>2fA~ z`7U(|CAS+rLJ8S}?;ZaWgq?-+W?jAC7eO;9$L_%GdWQ17q1MxuHWsZXEgEYAF`L zMdPX{Z5^F<&`BON3cXSa@qcjcZV`g?hso*aaFoCBb&s%neHic*VW{c=^PK+NsDL{0 z!9;SsaZKKrOi=Y+C<=--yZu_N+$P4aliX?zZ_6$jt~e;8&KGG{$okhUgxz+$xe~AZN>+h% z)uEN>f3*N%pRa-Y#$0E;tg(Ly^Wvg&-1(0%Lby;i4oMN~V~t*~?cC?2eHj$ZXR$R5 zc85$eXUhJ;1lpZ1@y35GtGfRUARybV_2laiAXFxl!+86eEH{bj$tpsqXp#FMQGqewuT^TM*CBXXosRjG^7 zMX-cg!JkDV$4je=P6ax3Iu4H1&O1~y+My>6-anSa z(G;kwTp{^fZ;cg?+Sx`nJJ7sbtBvtE{A$pB*p50dsh*>@pgi*PEkn-xiI8G6zup%& zU_4Finz*U0Eo7jrodb~hv>#(*u4W=>Aka0(?E)Bm0gZ1-(PPU%&pqG$82EAAt$)ii z)Jo|l&aTy$^j((vwhjBlBGSrPIKt^|KE}9xcYka1=RE->Kz#t%|AzK}BLcm(M@$9TF3eD< znv@jO1;{=tDHSv-weO*ut3?Z>3U|3mzbTZrDQ^K%YIhK!)#vb%#ouMUuc<}ycO&V6 z-08Q1DD& zlyB#ZHQkF2t~8kg2Vr~sapl4rAb0=+dQ%xDJuS`o_i@GtrI!a!Ij;Y>LVQxy{q|T1 znQz+_cbr-1_}aJ48?PyObX#SqFrb4fng@Gh|GH;?COzh0tVV*Bniz_vj0ir;7WPZO zZ?rwug$x6PFkSdr+m_QxC+{3sI*u>**PFgKeOvQvcrmXC2 zdCPtfu#t$?C1o)&{XvrPrU3EHrDLh^6FX5jr6uhvxaMOrAYvb|$$9bsB|HFfo3_BU#-&)I1~`g_uB#llpA@c(PK76W77J05Mzt@U z)`LvAr!ozz(TIY=LJIj@p#I-kKDNH8C=Br6t}Rb|Sb?|*9GiY}$O}TKmt;cYzcC(G z*tT5+)`!1?SImf=3?vXcoFpA>CPL-iH$Z?cB{X*C?Ccy(cPE7JtgZ)RSdmFH?5h-t z%O#QAYYsXnW!bhBzVc%W&K8u-pb~*xOEj4?6C+Y6Q`hHI31d_l->1%jc%uwEoTLhY zB|Uf*S#A|3%6~4FUw>aS-K0t}g*vE*c1cabTH` z2HtG0vjZ(T4qC;7nWzI`TJ!esm~?0xVAuusv6emd2M-=t<~oHFPJ(>H!jyn^>SHzH&ubv-2@MVU zrvyT#nSj^si4bg-#=!7K>JhMm#1BbO7~Lh$u0jVmt?GWAjwMly5ETMeC+?letjiL_iEHV(pD^kIxcEPvzErZ0tbWP5F^D*w@1@+jd1f*jq=gEn_lZ) z?P+g!gOxU2VpMQ3S?~C3^Se?$GvNHWc)Qw_`G7wi)C!BqTzCRh zc&oUS-Sh0gAnRc)7F*Ka-%r=s)umE8$}1{L1%Pg829$q$7|wngB%*h_i}kc%RMFWWN+_ljo@(k)zv>%m%u=V(3?q1O9S;5 zFJiFPq_R`%Vi$54{#EJee*@{{im|c1Ie7M_g>_Qo|4~(lh(!%?pSaTo3Yz@->(@aR-X+$UH!`- zqlXn!Ra@@wXC~q0`)nN0MB=yWC--oLv>boQXy3hkW=z1s(#w9qLLs)hb}oNkuhJXe ziadPQCW{R|Lu%w!R;BFmCo^BfNHK7p_V0+|Oo7TeI5;exBp&`) zcbG?6K;ES_Vh!?Bcw@L9Yiu$(jKXO4Wfy!q;=Y`@KWDwSEKhhOQNP)RpJrs2#i+fk zNG|tdlQ|XoRGG0UJo?dUoi&;k>$dqru7C_r9DiY)*yV6VSUC5`@bKY89;_2?2cGc2 z1(grph;--B{&_nock~R9$9w^`gg!t@1g;6kg`Q`wuCC-}LderFHrocDT&-t)nns`o zxqE*KgtS23#t^z0eTTdUo};I2Ts-VHE~#ctk6ld}+YGF7th)Sn;LWwfhqOfR?0edp zy1#utG6e2VAQIhVqS;LI|MO(JZR%?u%1{<$bECf6K)E{YY1k zwS0-hDCq==S8#1Zk1wTjlG;^;?5`PYKb`6$u@euzj7bGn%dGb%C929N8)_co)g*>W zyU3pvwsZ-3K8IV*z_S8e+#m+-gGE(juF%&dBJM?xqbz0O88J%kn0;|D1U>)k$1%>> zUhmn>9?P&q?I*aI{`sI=&*vWO5t1Y{7FGaX?gyCN=Uu{hJhb0pP)v09a<{cTjcxQA zr3@7|RcQhyU61%U@iz6;(v$c-Rw4V&T_`a#=eJBdT`h6<00`kkfy1e%r>9`e{)SYf zV%(>!nc4PYISCK)dssL3>5}w_NFdMVcy;1WTDSg3iZHnZadaQ618GA2C zm9CR5@^2up?XHxCiRk0Zc=B6MlP^_zf-*tD?x$Q@p!BwQ9mw<>t`!)C2^%A_(^ousGBLXy8?kwZhnL8w!N9KTrQz__Q zWc;2DE8K^LB<06(`r|V#AxKwOcP)5S`R6z1$5+nt_|yo|G@}0=$s4zI^uz5Yql5qR zk_V?j=ZEvpzmJ-^q^=w`WiWD&WQlu>dBuo_fbgg;ap(2V9Xc>OXv~uuKKgxlWbEdk zyI>9{s+Wz7gF2$(MGNra&*9I!Snd@FZT?}@mA=Lx{gbHw2~soZlFyj%JLH9tU-yg- zTWCrNsrcxs$g<$A@7vgS_Shm8Oq#cjIJ_WrVMOfmmOI1S*e zpxnLbqmGal;CV_(vf=#L_d|B(#uCTA?WLY+0Cs7W1=f`b#C&#}&xk_#G7^1;wwDGv z-d^_&wRsB8@blA4h>LL3X?P?Y77MjVW95}nQUw#C)(xgG1gMeYJ7W?xL&z}ZfM=)? za#5c=dd#CvAV$?5yvhq;Q9YOfo_bPH-YO-nUk{!LctyW|Ba6V2_F^BL_RkJg9>s1) z0zA?6kX<7DK_1-UNYs;MFXs8=%Y={4TWwk-mViL=i!-!uS)>yU<@J>_>z6=H}9>393ZMo z(b7`X=d$_Mi!vS-PM~9Pck7$DEO;?EU|wjb0%Y9yy_#!dt9xc~9rpCq9Sk%?kND}o zUJ_N4hjG`s;M1N(j*N^r*zkmNr93n{`xT!=erHE3!4)%j|Fiz`R)F^B(JZ5_^ogeR zzXMw4(`bgVq6uP3VkqrXDI&Yhk-YtO-T#mmCFQh399a5HmH*PEo^Os{!7^^6K@~U1 zmh6~6_t6|iPL%WPv2851IQ@V2^M<$_H%1tB+yPTV%~lR2Hm45va8&4j7W5=83M8Z| zw|-~N+*do>ZPH+m;M|i!a$YYP&KvgT=8=?Bpz*-}Z1+jo)t2FV<1UR zvHuweuvPuo0&=3Vo0Zz(DDI=p@p$VNLy@kzH&<7^uAu@ZAH{ugpwI-5yE}RIqL|$m zR;%Fr6@zs1y3`p^F!B*x(c%Qj_tpWp`I8`*dlpt!R`qKc;0-~={I9BpdtgqAm6;t4-d_)Dv@-?wfXbND^E~U%Ax1p`s;o+ z?fk_h_=lhX470`aS@M4Gt)_Hhldd2k_f~cRetrs>HLogG<~8jRzg(JDb~3HG%zl{Fc7Izk+w;oAP78_8LK0{Zging`?vZI0)Og7m+eSZnZ`Bwzex~VPbhV zI4|ez=(RUtgn=!Y#Kmw2dwE6uxunz2UhQD4K&?x!l8e%Kic4BMxnyOc-W} zv1@3&es#4Qlaw^I7ms1(*;pJG?+tsbw&_2e@rQAWjCvK5_VLYr*lES}W4cg-B2B|# zcj*h+sxv?kQXp16*qi@C1Cx|3Wss#fKHJiy+|LE$b|qk%Zm$$TFq4xy9=mp=a#j;K zlt5}^(H5=*eLM@O&zxbJ{2Vg>sOtuOG>^}WsOj0FoIx7SZs;Iu+pVi7eh)#?Q9V_wHREi^rt6LOhqcLhaiQ8_xon>2~$h zjVxH>pOC6?7`-2f*MA~*fYjI}k>J33Ktxa{OpanH&j?B} zBtJALB79#MsB28X(86=_@*+)5O(6&<58ACgNKtY7Ys&l4z}s9iS3JM)8W;$&g~{9!xu%3b7P z9CRQH2|}UdcFY(p=;RF__h-UOUn)P0Ho~{|0FHH@L-GvkO zb!J|dq1xLV8CtZwYH}^W)A;2((NR&1! z{_pJaui&GVvDU%k;10Y}cD}JF_ngh+zZ>|M^i+QKZ0qaw7M2p8e@%UV1oVvFxh4v7R2)=X8K zQNx%BW(E1gAXLAZ;_o1876w{n7Rvu3Ng71`pd?K`g+1_8r#zR?rlRa7LH|V1Xyg7h zHY4r0MyKBAR}}oOL^N(60Zaa~^mMJp43cj#B<4dqf1FYVZ=?QwbNze+(|7 zOv=NDj(Uo_5%s{4bdIot3$&(F-WSB@!uO^ZpQC}hsLSAlQA4`LwzxB;Sz%1d;aA-` z+Z~$w{u5=5Uk&|46CDTgi8w8Xy5lWIsow+LbfcqVb*GGqrz6$v5pPgJ+R*Q$Y{yS_ z)0e*9|4>%8d)&~tK!^3F2eKLzhzCp@vsgMzdi+?$Fo9TG|HP{qy;u9nk&^}kk>?1B zu%Z+(z7Xjxc$dhuEVngh=R8{lqg=5 zL(9KHDEGH_2{1dnH;#AyNj<9AAc_*zGb$N>CZkIj?Meiv`vn%Z9wbrRTKW_hJ6j8C% zkx?%`s`Rh7wf=F`_3PJ1KKU*8%&l^gz#yO+i1<`V9TT&-`Wjk^ZU;t)fQPiy9oTj# zI+vccpgpziAm(@4*^xNVgk#tgeR4ieOc9g8$mgMsgJf5I&@l%Dmh51BR8dn?Bb)8% zr$szxI=|Rtlzo{8JK?g^tIZJt% zcHUUnm)r}M$O<>ibhBD+>e(j|nv~tO7JX7=rFTc(-Ba& z>G)LXXSf#-y{nHAVly~_AiwKa4lsb)&Zi_!^H*KyW%IVzv)i21e%j8pr++yA&iS() z(1P|rX`iWl!}m8ehy!t3yRzlI{iURw<9O-wQz0mE+{b|6l_qSZ3LCs_r-X*Ib#;FL z0^ln9(LOirM*th#%e{2DF7<^xP0I3V6JNO5AM$bht;K7V=wnK+IZ^7HA&l?5QH}OY z4q0I!tLFn8Zi>kZ5mB)9B%M3D@wKT%ffoYle)@X11kGb4!(!{WQ8lNlX$Qk=sezl% zvhBz3qPra{&T8)pJgtU*ETe@ME97kC_!hvuCMejJB30 zzV-Ip>SkrV3GI86>D6VY!TS~0L)QLboRrc#~=wg^Z0v1(17dk3oyf9E(55l&q-G&9u&6`C< zq(J1aVMukX$3v_LUQQkaA~hk2%2iDr;uMk`t0M2mBq;My*anjRy!7MeZ6QED)fk0X z@&2LU_ivnTyMJU0N*?021q$4`MBx|19Iy8Hb3eRuF#)~J8vZhaj+i(nUGtY%_qYDd zfPG6RPUr$AZ*@ZCr1_$3dXYi-$&*~4PCdhcHO^}iU8FM~4T`CV5WIWAQ#^kg7iQyb zEJmNjgyA#D2E^$4%(WkBNOBwc@Q2Cp&bal=r|X3`mTs)a_*^bD9AK4q^uQ0cR!)?0 zN2AJ2^1uIxrinH*z#ek>j?>ekUh!CS9x zn3KmJmbcXsH9UpAJtUYx;*gv!`GcOF)y=8-h2B&NFdLYXVej+gl)opMxxzd1_)nKQ z>_o%75LWGQNnD&xAoX#{yLU4TuVp}IZQrDxIRwF}b<|Z%D+6j=Pnj{d4qU$It=G1# zC67y3FDl(a?$Tl=eTvQ${}wm04-_PMW;!2z+Gjl57KLTlLPJ@R(N4tE*$LM^=Bfa;f ze}t5j)c<&QCIKqxdGmyLN|cdsQU?DcPR>ILk@g^{4M{LlK-!~fX7=)K^-_7~Z}`>h z5Ac#^Lb*1PN5-rnKxA)E4#M;ZR{<(cqH%qK`IeMk%hRkcuL{fk#1RpYDG))5*S7>f z2Qh6jE~jg!&zqZ@ol<*=Q+u6Aa@>x$GY-auFk`;I6Bk%6j|7Yv2tCk~yaa-W)XKhD zY2}$|x=Bu*%A~#4xYxQ36X-I`v$V7{scWtx>2O%TN`#HMigz1!apu0lW3aRPO5RVT z7NpY{+=2Nwq1hZvQg@$v*0m*Nv61+A&Wk~zL35!>epQ*gc-6}UhO`m&?uo0fZ+1FK zl{74g%FA1hc-PXuSm4w&WIgteGJ^EKN1h-_xXHs8_8*paJE!(`{!Y6F9=`jD$;q@U z6iYvB4X4sQOJa#bpNAw@hDe|50(v70?bcTd4le2J`2qw_s_|=z21F +#include +#include + +int main(int argc, char**argv) { + FILE *fpin, *fpout; + char cname[256]; + char sizest[256]; + long size; + int i; + + if (argc<1) { + printf ("Usage: datatoc \n"); + exit(1); + } + + fpin= fopen(argv[1], "rb"); + if (!fpin) { + printf ("Unable to open input <%s>\n", argv[1]); + exit(1); + } + + fseek (fpin, 0L, SEEK_END); + size= ftell(fpin); + fseek (fpin, 0L, SEEK_SET); + + if (argv[1][0]=='.') argv[1]++; + + sprintf(cname, "%s.c", argv[1]); + printf ("Making C file <%s>\n", cname); + + for (i=0; i < (int)strlen(argv[1]); i++) + if (argv[1][i]=='.') argv[1][i]='_'; + + sprintf(sizest, "%d", (int)size); + printf ("Input filesize is %d, Output size should be %d\n", size, ((int)size)*4 + strlen("/* DataToC output of file <> */\n\n") + strlen("char datatoc_[]= {\"") + strlen ("\"};\n") + (strlen(argv[1])*3) + strlen(sizest) + strlen("int datatoc__size= ;\n") +(((int)(size/256)+1)*5)); + + fpout= fopen(cname, "w"); + if (!fpout) { + printf ("Unable to open output <%s>\n", cname); + exit(1); + } + + fprintf (fpout, "/* DataToC output of file <%s> */\n\n",argv[1]); + fprintf (fpout, "int datatoc_%s_size= %s;\n", argv[1], sizest); + /* + fprintf (fpout, "char datatoc_%s[]= {\"", argv[1]); + + while (size--) { + if(size%256==0) + fprintf(fpout, "\" \\\n\""); + + fprintf (fpout, "\\x%02x", getc(fpin)); + } + + fprintf (fpout, "\"};\n"); + */ + + fprintf (fpout, "char datatoc_%s[]= {\n", argv[1]); + while (size--) { + if(size%32==31) + fprintf(fpout, "\n"); + + /* fprintf (fpout, "\\x%02x", getc(fpin)); */ + fprintf (fpout, "%3d,", getc(fpin)); + } + + fprintf (fpout, "\n};\n\n"); + + fclose(fpin); + fclose(fpout); + return 0; +} diff --git a/release/datafiles/preview.blend b/release/datafiles/preview.blend new file mode 100644 index 0000000000000000000000000000000000000000..8d67a88f679aae5ad652f665feb290e7a1b830d6 GIT binary patch literal 459544 zcmeEP2VfM%_ugHIfFOh>RdVzWp-9c`T|$=@DN>{)K{@*t{bGJE&2BHFg9hjRp-+c4-y{X&o649YmrTH~{aUU{&~DYzwY-@Qf=tWsZsACZQ5VvAh`MoV zemc@j!Os(AlIKd0^}xk(5d1usU*EC4iAtxi$Ie3;vX(w?NThK})YEdm1{A@k4`s+I zUV>rO1C;A#eCRfw|G3@|w27z(eV6bK`}MI6Ls(DCMHIoW&k>BQI4*JU1S8ksO!`W) z4^VtRq7FGhaN&#aTlSgMNiNG37dE2*(B{fk*0phYJjpE&I~~voz0%&y-15OTZX~$S zjW)eJH`2z1KImpYN&f=$+UzY4o#lm2=;!f7@Y`GdFaT+9ge z>;s7C5V8h!fLHc*hKpwT`Bf`JR4r=H;eq8MMag?qubcq=?C?@Xe>i$)= zbW=MZbjf+B^!oi4zDmEVgt8rSYIjcSD;uvi)mx(z|J3g)q0le=uIgr=hmRU|&($82 z^{%zw#)H}MyQ&+eO24aNU8oY;dUV`9(Kqlo&-He8{H_-1_q%$O;jQY9%;LNTyljOI z(f7n=i}*K^{(PKQkHX<)f7ggLywxIeYIjcS=d?MpH@|DJZ=~Nf;|*{1sIEh!2aTTS zh#ob_(KUATl@Iu9?RWO(cg=Xe-?b79Z;jY)F_XrPkBbqGw;OfkTiUhuJA3oHR)XK} z+KGm@W_-u!SVyDZWn`U@xCw3S%YQ$JE$|Hxx#*7>`D(1>exz>JXZ(XaK=Jz}Fu;HzflvBHN zTK~#g`BHZF*0s>Xe!uIb8{WEUU9kU-y;NPck?YlO`sSbC_0s)**FR%;Ll1Kwi;25> z&#$%LS*_=WxBeNw-}TS<{cflk-g@aBhsDK>j&pR2iyk#LHru`ICtk09(?Y-B4Vjhe z`R&1M6S;pAzp8Mp{SGRbo%8eCgW;U?yOG22Hq^L(U(NZ7YNYGcZ~Er%??w*4-;F~J z@9n`kJ#V=&{B9iT_q&PP@HTRA{}$V~a^MP=xK@LP`R^60LGTZ!e}3N5#O?RHX{6z8 z9NIBv?9iN;d9D4<-g!&YNWb6Bq6}{ncgN9#h7BHe^*hv>qb;cXVhagGbJ(Ic< zlHqkGb>st6>zuyt*hS!~z)BB3o+VAYG=Mm|C zzgwI!yy1s)dVYSr`c2>b{oUe>-|tqM;f+Yo>3W{i>sZ*6a~zq7ZVw+{CE-Ns>fTWKvuj~tzY+f3T^>NkD!kMlMTzu#>`4R7n<&I5+W3>+t} zM8z#-lwVP>>R(ZnznuK%R}}Mf4SH+dkW`wcptr=k45n zzwd}Nylq2U#zkNHa+}YqKNqgG-`P8Fxg*l=cl#*A+s@r$^r*4p;-ZI*8h16ljrU{3 zJo)qX`MVg|+rQgK`Tgz?Yk2R7Y%y~5_(50avT)^EuWQ-s?+&qkzdObo-u6*l$BiF2 zaF}r6sy=QEzdOeJ{qB@tcss=Q7(F^imytJy-<=Ya-|Sq&+cDmHAIZ@ndh*rXW4qSx zGtrOB?PGjLP43@#FHyXUDBnxGKhb&**m~y@?r=rjFShG3~ywjadNlqK3ZfV6wXJ)dx>`@A=ShKu)%m~%MlqjIyNS5+^{RV zo7gTk2QNj?fSiW%+FD<~uFR~=e_kehm40_gW4ru6dLL80l}_hxF}!h!e!sh<0h4}r zJ31)O;q9U2^nTK{em^gJe)n?t{q7xVczXut)b5Cco*Mf1LM?^84K{*6{X;ywTt1(6r0W?|^-*U##En z{_%#lZ`6(cK1UYgJizb%@qWLf5)5y@*c<(Qj;#EqZ~k!}mEiX~I??diowglpg5SjI2&y+Fe|FwNiJ1Jhut?C(K`4ex-Y?sqv_M2{Reeq{8xVWUUUlPe3? ztKam(@Asg?$V$Is(%B}Fd^B)nu4ZCid%u0x-}e3cW*X`DJ0=}j>G$9>hIi267USb4 zSl^cFIzH|y2K%-5`|{&Fv)_Zy`28NL8Qz$5%kQgyLGRl8ecAICx^3%k@v5!t?_t4) zckmgT-#6s@d0Fh=0e%k)1|a<&?l8PVbA0`+Uegu_x<((DThD2Ve|`^lAS?YI5o&mc z1&fFJH}LnwvN%7d+cv*Pg!=s+={CH>9Xai$%YA@9&Xr0J6XDi8Q<; zLT~i%iDh-)fxh|uz9-V}_oyhtJJNlle@`r{bUxa6`N#Q~1i#;L ziH0{e$KP+iUi&+<-*Jh4zsDvS-Z2UPkKSwegXf`Rll*>wU5D1 z+qyO`&F}a4!-jWkQcms8X?@z4vyh$pOydvZ81lSjLb~A{mv*CnpMq`n=jZ1W(*1r< zJY#srAHLDQPmz`1^v%DXPdwxId$MMDC#0+UYy5$ltJ%-4{W#Cg_4i~pj~wSyf(`G) zGdX=ubiMjb-~9bOCD`xxREOc6taThea@?@ED|>f~ji#>06B~u-+SN8X` zP{TXrU-Ewav{1j_)7^%5>J9&XefI7sgK53xSOwSQmHx2|P6Kj*u7ay`d;$1|f~>I6hRsN69J zQik08P`{5#`I2C0+HQa?R%zPa;Ye{ide8cPBU`-D8}Ps_ht;0T|_kYae_qolvO zt3iVXm-Ejxb6>;cXK#DNdF#?>>T=dRe~WoGf3MX3=Xx{Wutm~dS5%E(%(E?OG4JkF z`wnwmkJtB9f3dSG9`?@Mce}IZ@8=qFG$BCOPSl_1imDmRJoFBPuJNefp83>wrl;*G zzG6rCiaE_i{RQcRJW-z&Pq}rOHw890!^&)MuWfkR)&I9=U9h3yUHR?`FR`P#=WMHO z9@yZHo;BY+tbLh?>PsGupbf*m?C-34w%g7fb&|F}vNvJp|7L7Ge>HFn5ZofVQ7p58&YbMwE zJ~{a@N56*LFLXlWbVonj9CO|5u-`VIEwLxU0$?%yrwmq)}&=v#Sd<7 z@f&GYaJTIEx_flQvDCMskB2>;8lT$no^h_@YtCuKP@YG#zAR0RT1E!-1csbofx50d zUlPAqq>1N*tZU5)y&C5Mvf~jkCuZSy&BYusvYHd%`9g~+nwE0lz+0{d5#upWkxxs+ zJV2B|jB~6Wr;vx7>p2^)@<@$SY-`5W!=tp8(BljFe9~owppan4WectZyiJku+wY?P zRNkN3eUi7 zHu@6rD_i~$^U{`cJU+_UatZV^K;~LAr)H4ZV{~4q|B25O6t)SC)1Rb?< z5d3rTGD=i4S#$F;1RvyYi`i^vUX-CN?n{tulj{%L;w4Rc<%my})`EGDrfu^>!Ir3e z_7^}xnZosHtjDN=T2sVIgS|^1skn-fYmsj>C@6=iY>Pzt4^?{*(H3*C=ZUt-ui7Fl zUd~&lGckXWV(k|x^Op}k`|WKa+CZ!Wv*NYZzd;{Tj^S_zw1{2$^4b(CZC*_~flWn( z&2vMg54R|r6+bZLvDMnaG%XRn+-tGepHMf_-cJDbTA1L_7nK*j2oxXG#YkV+Hr6WY zpQ_UCB-)D7HxXeszW-$TQ6MY3Q$dV?n%(hetFzeu1M->eH435_O!^=K?Twdt$f8^n zumrS{elNSufRXrN`@h1XyjmBk(L4BOv^p=%O1&IEIRCys z5ghToKXQ3as{SSd|JH%}8wRe<;TKtM53afEOR0QHSeF-*XY22zE`8@K{7b&~_n6!7_v4X<_tAgJ_x>J_^!vRy z%J4q+|M+`A<|tPGE6Wch5?1}SPN~Od zy}i5K@h^$X`WM$g2g_A(+49h(Qzt`m_18M1?orqASs#k}xc;kr--^O(aDB&PIdQ!g zHe0{oLZ0QDM$O;P>%lF1K5VoFHkjWR@16R2gH9gj3@w~CEHB-<^77KH)+{gGW-0g# z4H972*v{dUn?*S^*PVNVJS8i4OL^|xiIkCVmk66u`5Uupn;)HT7A}|5>rd(b)wkd6 zxqnW*J@-#*5G!rV{bTrm#7Akj2)Li}mp&KxJ@a#c=9SYAtLFmA9~U{6Tw-fwvt-3P zJ&hZ>Q;#qGxluaWvF9UA+-)lFlg|aL>uR0WU6;=VcxNu)xqyay5n>)pKpF03Es2$L zBsaZ~_bDh|8Vu`sVar6^Osj+YTA2Hd?|=2xmYt4Fc;&?B)moHVzV6aWe~kRuv%p;6 zi02EqRiW{wTrO%;GYiiGMavVT@z$K@bB`sQ=kmG7(lqI>eC~1SoM(L%?9T!?mj8Xv zJ(i}SE#z~LW!N7@TgvAim$u#C``lw$6l}rWPL9(j;|;H{O+NRy)E4mmA3yhaG9K>9 z=N?Zb8eY*h^0`MAZSm6o*XJHjC890%AYxoR9m}x+Sw8o;KQRqCF>jg9yk4GrJk2#} zDk5xN?l!!_2l?FN^8E*{IG^DCeg>v#iU0I-kL7M0T0Zx{{a>^<^76UIrFN&H@cMi1 z@r(mz*`9j{pX76oOML*B;jSxr?h#ivE@os*^w^lXgQCYp55~iivDfTjNZ@mi96$fa zt6{gt!0qneZ#6zE`@_(+1$O19lGZtx)|=0zMR3bBNGoNX>rp?0O0C@GKj9Z=okqw!s=zd6*cJ0N=C zhymjV|INp_TJ?3u-E*Bi)y(Wk-MWLvO^%Jx+*K-y0(U!|W7 z#rWpVL^5L07UH5D-@+X^UUZO`m~^s+zvlqa1=k%s-K(B^A-Pm zP>5#dN1{yeaURF|yn3;&ZS*(wwm~5s?EFNODgGJoS>J((O2Jy4biH0sNHshEjGw;} z=NT&!kuQ&EAWHjd+4w8nfTjMGSXWoDKDmg+pkHek6jI5~Pq6XR4ev^~#ijj%UpFYk zVdtl#T4+Qt4kF6jIX8k4Kr(f7tMf`s7Rf z+MuA2Vs`#vKYz6YeAWk7%a5q(7xg7UA#H8^)egW?|LR!qQD5|Lkl<(N=Yz_fxAS9d z{4~QW>brs6!v50F8!LlC+;)DNpT8y;eAag(atvwuulj32AuVnEHNk+TJ!_)CPea~; zSO`(mFK~QD+WAp{6+a34ChIe@jp*<6ppY;-KMAnpKdXTsMH(Xg)uA8!P#gbQz&?H? z_hqzCSzw0jU$kdlJ3rFKPc*!uKDgRVh|-=Wc77sYWzQM#QD5j+o`BC8Z6$W!jau5kaauA^AElg#GP1ob-+7H zTan8LIUe`&W)~Tap65T27kjs0YFd*cFZbC0$ah&0O-T{pL@6!ocgmxX<-4i{;cAlpSY|QSX#tj=c zGG>q}`q!mw3tM~qng1>4j>7m5Cu*`*i*VG5H@q*TAuWY?iMAHu)-SmFPq@Ki$jmHY zV!RP{Cspkb5!>qRaE{M!3$D2I+?A|93LRh*2EF&iSg*?JA`+Q9X;+crr6s=3+CE(Nqe{p;N8sA8D}FFYno~kf18!A6MiOlDSMmb zcVmCG^j-&Tvi>k!l5MgP4(4 zbqZW#q4GLfW4ENiJ=rE(&lq0OM#5uXn>1DpAk)m_M1Xdml^i%uNVLkX_i?iI3``Ym zLYob*Xd{YPW3zaR%ibp9G)(zwOVczhJkdG_QF}3UiZ(%deV(86=!{Jj*DvDUYZT11 zdy1^4_2`_%FBx3I#5qXkx(m%CMcuA~CEBsB8Y@h*3aU({lv5PbqQ0vjgRx??HG^# zsA>k4`w`!b<+WID0m*B}lH?-Xis;j5d{fTX3az`eY9+b3Z8*53x8e63T8isD@x2+p z4&WlR>C$;ZOkCWsK`{!Escqdv{UpP?^Ne+^=)3NuZAoCif=ItO=QQ5KVyc4850*>r z4xIOFPvZS3#bfH{?g&Lzabu~Q_oB#A!N!dRrns_ zC+rOdcd<{mjq9_QO2CD^1;AbA zzx+d9?_RN9ynoe6yt{?>ud=GlH9|!@$Mt%lk1L~$?~B=S%H-RFJx`f+)*xk|jQ7cg zDGqg}A`)Y{-9~a0k7X)c2}bVxhew5#ynjw2>zA6DagkUxW)S%9TGIW!-C64l`oh<% zLDt&95h8V@ z<+m!Y?3ze!{nEW}Lkux%bzjds%McIM?=hkz^PaOw%RRr0eAg3wQqCLSGoY3j+#KR! z6=jNW$sBoo@zy4^&x!AKGF5X#-M7t++r@v^9I@KP4YRDkyow6D($qNR2{lgb<^I-7 z)s=frZjLF5VgFA}_w6s3FTmy8$&I<=-(xb(o%*silYeaP9FDaeHCv)_>WL)#xXh~3 ze{<)*xnmz2#;Hy5#;KP%M=mpWo=B2h%$<}d|J=##050ba&I_%%B&eC@j{P3tKQ?zh zb_+wU;KMk6lNL63w&q?PThR6OJ7SH!T=nn@&uo@)Q($>KfX%&r6Au{eW!8G^5e#X4>_u`dMMl*JqpveevN>R=plkf!x(=kA&CDXxaey zN#;Y>MVv|jr{3?cw`P9VZTA;RP1*luvwRD-N}c5abF27w?mJ(9rx{=Wcn1FS*_Q~u zeFtMohJbx1uLHQ8JGl12`yG;pJv*!WKDKi<-y8O-)?b&}pM6}3*6>kHYq;~rednG$ za8g$F)OZaXi>@KPyL)!l#x=o_v4M3j;l}$JX2#k3U3XNiY`#?b0ivn3im!I=X;IeI z{G3>`T>0PpJ+(~jk6gv_)MdHdMr8|edk8!p%d*07{0DeU9)~>Gv5?2c@oF=l3fofl zw8-az4b1OeRPa&vx6>=8X%o9!I&+sT#sbcrY+Tp;`8k_45ie)2b(oxfx_t_G3>AIg zUn0os8r&0rIypyhF9G)+lzMB9_%CM^p6T4|Z=EClXJNi$XG2JRyF<6#ZB}k}Z{GQK zR&>>-fqnQ-%@Mne%9cP|18rk@Rv71Kz#LhCIkFyeq!#O8j#R=NDXiv*D`i${+R$f` z(r({#pQZD^Il^|z9Ml{Mb^w=iq!{Lim@|Uvn8*b@;-M3ujeDjmy9>ms+Uv8>s~bZE=0uCpNHdAlIJvM7{c=t81CZT|pB>i=+&w)kXqz1c(x|){Vz`Wf?Weah8uyyT$#v-37PBr#d&izdL@;ZI;ge<_Oyc|u{q*@pCrJ7Kg_26{^+l}OKJzxhR$x06;X}Lz%lnv%@Mne z%9cP|18rk@R@i0c2+y_b*CRaFDyrs)J899QsW03b?f#`~8L9KXITF|b>RF`qtX9qu z2j+;FGlK1#Bew@s{>SFXrl^1;XDb`tsQRMRvC~SXHTz&?Ru$B^3>8Gf_9L!Bkq?lc>W*mYe0$=3sa1ZRAoBTYR!*%|sG`ewH;(z;HXD^K z#O=YZU*TC{JU))uBsE{nisZtM1vvJ298X+Vr8eJwIOXk$i(IgQ<-4_cuXr9iKXZ5J z*1S^Ze{+NllPRb;T`nRy7BT!Q>%YlKJhza zEKf~&#*v!5x^CLi{F^K1cY(_HPP?_t+I{Hogguv_IR6+-ZopBj%Ezc8>7$O<#N)-P4@o%&^0y;Hvg*+|O}tFoc_a^}|` z=%;Or>b#s7^Uar<^LC8t_mS)SHWQ>y`3;(X>ANeZo^u$d)*VLETsn6!rr2f(a;H%H zPD2MUId__1?ufZW9?ss>FG2BZ)wbvJ|JdAlGf^0ljSs`S3*VJM{HA(Z>U+C>bj^Ku zkGtZai&<3-FRT58_zP1z$2D(MsM-Aat*QE0ajl-IEZ&~We4Z43Q@wp@k1ZRU`qh|R zWVwg`_Kf@PLn+}wFNifO?XD;4r2XD+x_j|VaZP2n@voRW&aE3Ba+V8CObMRw1&^P+ z^tP4GE$6B@?^rpOd1u?=g;I+Cmgs!GX;0=|^+)9P9H`UN)%oBiId}3BN4TNh`{H0$ z?I-;ZPF(4SalChwajNeb)Vp-&&f=WIsdUa`BS$1I%ut8dI0lj}JsLuLG)7)L%6;q4KJs53NBY zUU|*Xhz19LJMRL{{Q5V}gr!1maKQC4^Sjpf9k#n?(z=}!8upidi1+?cbVJQa&G8q_ zNpIf6hWD0u_cf?#GFVlXO>G9|FJa@hs;%Ihri01P4 zYwkMH%_|(a%!g}K^4%)hi+L^>4}dW+*yjq%?0M=6^4%5U6;~x zC75e|c;cG*;m;thVExL-6RTFVjyU(MU2x{Pq{Xj115A`ByCQGfb+o@3en-(B@;Jfr zxc|<%bLw-qacVr<;L^E+F(un3VD7ky%em7Mb4Sc2LACEYw`-xHzP-mjcf{LPQuAM& z*nijNN>r!3@?^X_`Qc*WJwNT2RXsIc1IMRp?$*yLFZ6^~Y})ujVBJf&@qPx&SZ59D z60IB?|A~2FQ$tt3zQTsex6Wyp3Yi$o?KUb~h}%Qp@mQ7>M!a(H`4VedC+#I~!-?LJ zJhnRCy3;K+&xK9(f%Rv(bHjkeyAxu%yDv=JD|Nc%-|Mm+0_`|<%zWCvm+bF zqN6J%Cokkg!J}czi^YW9*K0TP71nq4B;VI74H$plP77=OLH^VhHJz@IA9hHc zZsG_x*8T#6Rr_78ZG=bJ_%Ker6>FUOF&)%P_ZN&QsX~r+HFw%NfXlhl0dq&pB|-Jg zoq^*A#Au8%{9|*cV7xkHc2nb1y~yF*{Bncit*3TqlmDx>knlBscAr2^C$RIt^E1tq|tJzHRty>Q`S3c87f3 zn0dR6s_%*0gI&MEv%<_FV{i7vPImC-%T>!+LH zNn&iI1t*P4%hzVP>*wBMrOw>sA^c0{&QYA3y+i*mojVv)EI@=}{D`AZYS`(2t+hAD0pNWon^!g3KbH^a-pRIBxBEcae+f=JQ8NxOVxthSDcaKZLS(`&W7vOnHXQ5 z4nMV`GK{|@IsV!)pIYFZWKUw!KG&^JiQkhT#vt!`){_0hIp=Rn!MOB;zdga3U3L$j)?p3|vkX^QtxJ*%_Z$gz33@p&cKpFXRrRZ`p7Z%w-ISzY5Rf-?F2bIC%| zFLMVqmxcoi4~d0 za(rgnR0Y+ZY7Ck!&m{{P>y;|=aqpeHPpwlbWtneW)z@yyRanc#c$MoF=d~DMe>$#k z{udO|&B5cVpnNdAd)*4lZW`!ocIyT5{Ogsl!5UZUToq))`?@=@PGJ6$^(x-hcfpp- zI?7*PDlxTQS+?ZLE8EF|Vyk`m84%1*tNo9VYkKTzp|9lo!e`C2+t2H%=%dwo_E1gyE4=3xBg*IiLheyFuZ)gvtAD_C>M z$4oXfp6BW~&qch_HCO&LZMN53+8Gqm$H7zuyAKM>ZmQZLyZo$p{&P!Vn*+T6);TnS z=o{H+Y-?YPw`3OiFv@=e&SU%+u4M~!!?ObZ{WWo|R{@sb{$u9*RNY#s>-m^TnJg7& zVisb?YnnSzjuFUe-rG~R1`eVfQ!-#*a66=^^atUYjgnF1tHW#6T=o)CPprOSxNj)6 z*b}*=iTQ8G17y`Eq8%!rQ0TOun{{h7IC@0P*rCybMo+|FfQcD3NV6KpX6N7BCe?61 zCATvC?{AZi94EyLulU{uf2j`RB=hfHcWl)HFLwlPhN|@}ON~>B>6YaGG`^`F92BzM zk#}&CBkv0dj-Zez#QPm&1cjUwDP?;wya&>eXTR{Sl6c3$@E*h+2Om}dGRE~GHxlk) zbHzZDBw=?TNB*J-4*`N8q&QiUQl^iYnXyWUF1Oj+4IOoqqjSb9TamVf$B2 zG`r_}s?YQnS{Fa2Wq3+|USDCWW?Pu~$P8z4-pXH?bzdIX;q0E&JC7L|o+djURoIq% z7G^%3G%NX|yWesC^8L@&^_@#xJ{fdrFiT{0wS4$k+!8Y5sZ0y@A!pKNoUE)`TwdrVK&X-Q~bWUFOjOloN%M;r&hThS@$OxM|`H;ef zwzn|nkIPF5499q}Q^w-{zd&E)o>2hC-tFxWh2$;G9W2f*eD5f3SB%1{fV zZ_a}!mzm(bP_pMO6?<8}DXjZR3!`slQ0Mg~j=TTY@Xz}Fj5e*gJVarQ^H>=DHOp*m zM1OZS=yX@RPL{t4YxS0evF*+9n?|!Q^BW_Uw2ZU*NMS!;v@pS|ShJw$%h&JT+OweK zN$iKl7Dk@a`^sGV^{db zvHL^ViZ0RC*j3n;LKeocOW!zlyKZUoba-uR>?&+sM+-BPdOgjycb?Q+jINe3#x)+i zak1SLmhhp4nJY$oC;F(Gd%>X4jAfnIf_K+rKP&9X!xm;P$TLV_cXkS$G5+GVqC4P6 z^*6s#*sKK>W%0Dr8MXU@ zS8nNYg{|yrVWORX-}HhxWb=;v`NoDc`q1hRr^J3fYhmW?K?gas|nsq71nQakG1qEtlj4p zChX%piaU0pFoM*UTdp=1IP|*lb+} z?^OMMVCHuc>(n`wZLevI%eVR75OqBTKYN7pQqu;N?VKig?+h%*xu9u_wl{y&;+X~Z z%`tC!-lJ(l9%|pz;+c0>8R$GcsjQ}T8XHqVV!M6{_8k1}1x*{}Nqtw=?J@jpYX0=i zcxygkPJvwFxXDkiDUzD6Sb0r*f6v_aq%9+BIy{M8ztXh1%RU%mWN1*_9ulEmQV}6fLp@?d<9FrNZWfSs44nleW_!Z~EE-j}$v< z&0mGx+snetmPDkx`zESzBX=8p|RC+J;{kZ5&h0T7*!ptsT*7cl^eZ{$FbZY(rav&E=tHw_DY_Z!)rA+zD9k&?!q}Io#?j|E z&o%Ad_9cs>4X~D^ocXZ`ZK)eKe|+AP7#r9J6?S-$g_)ZhcTIWdn-b0=PwnbhYT3S9 z-Un||&D{#ye8R%a^v_F&J?MSO8C$&Gm=E`zEsz1;3(0F0wy2tgnJ2sbB*vQYeU~vq z8-$c|fVa6pyuubOu`qLQdaPN$q{l4$sp0-`_?KlSV~tqkxuCGrY8GZDB+fO57c0hn zy8Zl^F2!1d*YILhg>9W^VP@ybub9jFwBXpS^25ZUr5mA5Uww6_!agcwVPX$>IL|f{ zYtzQ!QH@F#kb8i{B2QVEbM3FsnYX`N!|eFT-X}M7h%f$xmJzlmG(lm5x>%T*d)A$1 z@T?z9tYM|J?{ZJORm(`;{ZlW6osgLGtE6Gh?e`Vtc}Yg%$r;lz-*#<&{(XgMQ5ME= zs`lwBL*+g_tkw3E#$EcDjq5b8Fns^SQNb90zXh#Q*k_9^jBS;?D}Jnr^||qiLt#V5 zT5YAU{rxRWtoMaWzr}s9*|wuo?|C0QuJ;mqwY`OzTZ`v&Zn~u@dG($??i^bQys0N@ zE9~Gv3o~Cxn=01WN^?T09{hIW#J%7RGlLcOVSNiTXKj98?6p`UN}3tnr>_UEM1_3{ zJF&;Y%-V~7F>9h1qwCd;Klh0`x&CcviRhai93v+(j^kL7@$U|ncZ`K-fKe}&90WD*v_lJ%OyD-JV zI1W7D%`R#-h&y!tmiM2ZT*Mj&3d{AAg$Y|Q_c=~A?UTh*w#qfJ$dZd3LwG@=PS*|= z#yM!M#Y10hHy7Aj?Y~SpH}n*-N)2x}M(xrvnr~UYMPZ*DurQ7xPx-kUsIUL7cMGT{1jG=5-j*nDT$rwU75U}5ICiRV+E=zp5yrQVRePY=EY z{gL7S(>a6oiZLaqbgFnhY zI2`&OnKDdaDa$O(JkX=97#ldBY}Dh}qFBr=&*IzPQ`qazTbP;JrjwXQ5mE6qx}1%k zG#$sCU-=V-y|=-_xYn7Se-7b(R6XtDhm$TqAJ#gBz3;X#uJ`7&lu&a*;;^zG<+**@ z42&zR_X_)}s)dR3$uSRj%^4-aGo}aCn)wxYJfD=9HrvA3Z(?1Wa`$`R-)r=m@v7Bt z3M)Lr!q{&qZ$9&pIbu}h5@U~-nTkD+b6;U67h0HE`s(i*bbj?Y*F;VGDs~#y4epI* zoxWW-c8fQ=`0Wf_r*Lmn*th#EjJAaJtMCHn!uyp^j+(H_T6Yyz{Symwo~jxyj)Ar0 z-{!Fz6FNpFAALaK8FpUQgpwjd^|*u{LqR?Ksy9 zD?Yc3!cux!82u3Q9AkXKob(SWokrWk4~5O2YGGXeQofnml=|*m+kaundWKm46t0iR;rTNc_wF%?- z#LiB=2H?6e?81pI3M<*#!suH{#uu+}+}G@B&K>-n<(tCZea^zfn$2|$$Eb7mn_lB^ zEiTq`+g@VnZ(EpXd#-=rXUmxTzMq6G04JrZpOOgb^RcC zY5z9h;oMAN>#AFrm|L)q$DLBLVv9m<9G7!TVslPfn6UZOn!eWlao2)=9j$iueDm5` zVh0mi@9#Gq>p0q3VfA7yOpGDUbJ()_Lg9OQwg-=6NMd*AvM|AW)7zSJ@XLkI_2^ku z@+4Mntc3|%-gCdp>wQgordZdda-6>P`gyJ;$AdQgHlUcSE3s0)TbMY;r!TMP++R|p zWZu@vk|(ht-&+{Rkmq=T=3GlYFJ14)*w4VDZxSni+`@z{C%*ZCJbZ(x$e19k5qZN> zoE?rV;@B;h`{%w>F(#A0IJi?`U!J!xv(T2u#kCO5&GNPRy~4}{wEZo6JPP||hlQDU zJ@uqmv#~}LzSFp4#sTo&-7;KZ-*2=q-j6VgIs1uoy^k+!ntm77N!)8u*zqbBX3l)U zZRX2gioD`4oq2nDQ|wzshxAt1w|7{WxSr-U7|t!qKJ?wMQ^#Z9;`Ow|z8Yg;=Gve_ z&gU0La~u>p^2F(#gpI#8{g7Z#=ef^?^@j7|u zoIOX`A9?crwrD2o<8`va&YiO`&KYs;2wsKf&lpo`T60EWpY^aX?t|i70K76YPLG^= z0{XBID(u+37RI?H?xCRH+(!@HG9Vp1%q@kbma{Ok=xALW1H7o)zJ5OPPVmYmjZ)Y% zUs)LMOErIMct@UhHm=lWN^gu^-j`C?{!cATv`dRmS8yH`@6f3?*9g%r68mdyEQml(aDOnMIAA zD?{eU|h^y2plE7Hiq%&=+Cim{7*x@yUHCyc>0VoKuJSql5`q=kuj z#Or2>QBHZPxr@wyDpB$AyC`^9#6 za@p`7i-L#iGKFo4u`qG3U~hHJxoC9xCI=RkzU2Y%c&|WWuQjwVuEi$q(^T-3CgKjrEo@5$i0$K!oJKmO8Sqh}9T_ijA*d)B8+TeLvaW^Flz zYXjCz)qi@6{%YD2FKs&@>wf&v*{~)Be$cefPTaRrVkUtLS zIF$Uzy9+h#(f{p=#<)5@(dit%?sUq9nk%NSKDF(Zr{G6Y_cs)FZyyWeJqqV*WA=FJ zmhLoT!}lf5M}UWW6bhTw#lqOm&PVHg=-K-5wmVzj^4Ri1x@c#GZP;mHoaelT_59r7 zXtSxsk0rFuCFZ%pUY%oM<{OhA;k8xD_s%oDI;>uB(+bSD$9je+?AfgrWu#Q_NNiqn3lrx)Q%fF6 z_6|O}G`)x0UB~7<5aXs@$ z(dN!PkM|!Kr03nh^`6%=5_{@*3lsOvaGm13b#@^$e8*SMr9&U@n@MbUs)g}6gy+!O z&0*V?JQ+OaNe+ACiT&v+Alw3|FrVY8hUCa&{v zZp-;L>9!NYD(wc3*Lf0~_mzc-`A3QN{4%>oT&Mf24#T}>!IM~8VG9%Ut>x}d z*v|E)4$f$b`##)PO^F?xV`01>!L_sbxpn;qENZu};!WV;euToFjyH440F;C2{h_cmQ zgCAVSCAO@Ug$W++DR?3`l^*kQvzF&3N}j|PwX-mB+$A#>dM4!Rde^DG-(Pr39#>+| z7q>9Mo42Kk=cVlB(oxUW*mUS~d0dG-+}px< z--pkhJRf#$(!QDAbjdiZYq;;Du&w(njQe0pwLvfP{(b9qyB=M?AL|hIL51yjnHbjR zFSJ3T?qpAD+@9)@RSvdy*W*U`dUb$;wG_MS~4?fNt-aIy!U2c#DLa;?Hv zys=hIJ5 z=~ez+@Hk#17Cg|x*v`E7&-uGN@11Yt+hMh{!lKVv7{`J0zLwR>cH>?{9OS)iTw2#k3 z$QyC!;=Y!@fd~5(_E5 z8u0l(c@kT2+QPU#^PV}!)tJ}=|0{?4G~7QFwkW~ExUTV8H23q~!*)2E@OmHXn!?sR zVPS%Y^J34E&u;FLdSGyu6R|;F0dF0G+(dXcGeXYdizDK}&^59v8 zt!rvw>|Zg4z-u>PzuuGkKKfT-FDk}3x)-{e(=sQx= ztqqze*ENaNdC$UJH$S9{F@$xzbi+Ppy5)j>pPzqNVP7AxFtNUHoT7j8HXA+8i~*19 zi^R_EvoQ1GjwxaeE}u|4a^HJ{d*S|zXaADC3ftJs!Z;3iPlo$esr$8ir;h{=<3(Y| zCs~;J+r@&s$K!cw$;2{7xn`4xg17h6rxbSVqJ_C~|L+Ul8{xXv_~Q#R##RLHoi{ot zY=0FCb7}3Dh(5wI`s%AQUYnd3yf?;s6!v}}3*&yoYckDeS|d z7Us%7{Zl@x@arG91Fv{$ zUxm%RU}3HrZA*%ChBsYim*)H1Z^ZRwYN5ta3S0lGg^7J8d2=-n#_6wf*KA)i3-)oJ zk=RXBEX@31{)6IL664_48LOtOeGBJnD~6U**iH9Zn0S`2KNik*-rYAmea+Y4@mapa z%vBcVe?L*YL#f_RCALzC%h*4MbI!81qUGfA5C!O^8aS zPUeZ{LChy*>QplIu#6mrn-M8fhmy(7FLC;%WR@3@IMaesW?dzddyB-0@kiE_ol55M z`5rBCa*9g1uuUeHd2)&%;@u@7vmW!rX+v=-Q-_kty;b70Mae8LA#tXqq|CZXE(y7` z#95Dd9*a5^PHq{A(?%t;9Pdu~Y*sS)Arj|z1C`8r%u|0kM2D2AN6FN|GID5hc_~we zk{uEwN7+l6)g(?El}x@G&*XA^ zvo85+Jd>-&Gi_6IipQ^mNIvm;Qm$*0$z`4#^6N{P^+Ki0RN-ug1`?+}C9{4*iIb~j zwlmfQp`TnOvuztmoLnVyTs4+Bxk~2vX(DlQmCSM5RN~|+nPat?#K~1M=bcmHT-ioU*+ZLE zUD~Pm^j+cfSK(|!g|poh&c0AM+h5`AQ-!l172X5#i-@$1>3S*mvdQEyPtH0U-c#m@ zQ&ybrke^2+&Q$3qPF=)bK%_3pcgehxsf%(~#I;gps&o>kE^?kjq%O+cWM0YCOZiU3 zHBx4(bP}g7a-Kz`F3MeGUdhx;xijJ_DKk|%iBlIjs}ZS-a-_^FnR+RAMC>hPrVmM( z=?W>6qvX3GCrG>#Qs$|L@=7VQT*=hgN8(H$mNNA#xi92LBu;(IQz!K(oOSz2oav)d zrVb_dhy0ktse^gyp$>(!ZWJPMrjJXRI+Pp@d9lQ)gL(3)L*Y@72Ott>`h=9JL&*an zFOfKPFi$>pD4cZ%Nu23YDN~1%V<0b+ICU^jJ=CFa)*UQyrcX+lI+Q#F@>3G04(6$c zIuy>jLnY4iX(>~Ol7~TFE^+E$o_eT5;jBAc;!K~BGIc0<1mr}CQwQ_ZLmi1y4o9l= zP>zr|Q>BNvs!Kc(k$OfVPM0!MWj}FMcLro-^F5H6XI;vPQfA#GDYG4vOn)~?ob{AE z6|(9(%8EY?vg$9&ia!~$8Z(qxhc-+>RO5s)>kyxasKzQ~)*(I#QH@W^tV4V}qM9R= zS%>%pL^UrcvkvjGh@4kSW*y4o5Y>F7%sRx!AgXnPGV2qML*yJ*GV4%|MOtSnQ#X&>>oR>y%H$}S+yfG4s&Lw~SK>@xl``#8 zGVy&9r(H^B`D+qSv&k&qFLAbslF5Bt;_M40v-}N-voDm)a^)8>Wk2mvbtx-8W#!j= z$SV-pCT!OYQhosGN-4Ad4@;R`C9}_uNSs_HFNFNI#K~1M$J;v+Cs)a-;d93#&POg$W+BltTcx%Xa9;7c%qIGaK<^DKl044awjqlQ>gVm$KqhR`#%5 z*}!sjT<&Ej5Gx>lZIijbF;ATP+DR#Me>*N^rV1zbcZrX($)h2kmpJ)KCijBGN803j zAYYU?xk{#uze+q7>2Ffz@s&IV@>z*9Rs1-}=OoTl@y9~`pTwD}y5k`KB5|gw?s&*Q zNt~&wI|1^~5@)LFPK5k}#F?tPlOX>nai*&7WXPu_&Q#T%0{M)@nX0-|A%7=vrmF5V z$lptxsj8a<`5TEdRdqK({#N2lRo&^3Pf477CC`BDl{ooIX1VH9Vyf?mWgv1aA=L{@ z8GN4%t`1mmP**Qv$;5mz>gh!#2ln`6*q|4aeAM&Fg=`%7sv|G-!#_P(@{#)Zx7avn zOC5Q^NBijoB_FA;ZhjjFeWfEW_~;+KfaD|f)y-$)U@Yj!3qJZ^zghB;`s(JfaWK|& z zt&NncARms1ys&2k@X|I8WpaiBFJs}SZMku9A7pt=}eb)KfCAt@UyeM?EF; zT3-*5IO-{x*YvtW;;5%&-doViOC0rtOgjfcX1gNl4k;6lf?N?Panw^X?_ubbB+fD^ z^PY-cS>mXtWZpZ`sZVm1%zHU{Rf(gXl6lWYuO@NSQ!?)@>D48UdP?SfBfW;iQO_sW zgIpgtbs*JSNe)uIvy{nEGC8enc%+np=}HcTj5y~aE<-Nb%cDRI>x<_YfHH*^5h^d#!Lic%rS9X;>i2>#KG4&7o;AI zeT}@}Q&xI7@01?m$O}CjW0J4efsDMbF7m<#&OyZ|2YFGKb4v0>-TIQxxuZDj3&mmk zE1Y&WmwFo5c&YKn66~j9WU{*HW@l}Eon~)Q2~QJP|m@ z1NBg58xU9e$)6G!veM6fRL5n%D4kJ|)p6M`)WfXrfr^~D%24cTGIf`c;Z7c$C( z+{Vfaegp7_SUBgOuErJd+a-?FHIZgL`CS7zcS*dPjZc4F5=W{}hRkt=aVKPsVK?FwiL*_R7j|L{3Y?s9MAoGoVZ(v> ze5AkXSkUM5g?=fWeIY9w`axF5odtQJ)KB?IDL-VBQLZB|Y`7QlQ#N^#l#%KQQby|I zP|w2>Ul1Ux7=Z1=+GaPocRGV^a|U+)gP1c1CUW);FJ{(9s1)EpBErQ zui%5LFP8HCkWpXYlobvg`V$hL6Cgvc;Df6#k@8%~s4sBJ3WpATsl;ao$j~eJ;Ofhy zd>>@g7dT~wQ_l*CKVy@jTSs2-6CtmZGIc5$I&_o?4*gmsW$5$C;OeU-PQR4Q_FN-z z)bq(G*PoR*+f&Kx$F&kiJ)ewn{W*!VAC=7U^Ss1S&nKf?e?j6LKT5{<)t{C)QXd~< zR$nf0q&`09&JKycY?HZeATQd4^Ju4(xo&KiGEyH-J?KBdXPYaXtb3ot+0IJO?U0rJ zMv#@xsgPfkeEOnf;+UU8KYdvz5; zl^)oxCri%O09onWXsf#kGU^L^h$AoLBwJm|n?83u*)YChc3Z^ExJd_ z8vw6^5V|^@TU_P1c@TSD6N6EDLfQ_$Yw*TuAN9yCV{ojx{QeR#6 z-D?s@>Z{8>+AndWzPcPIuSy)LuP(>QK8Yjs)#aFcMdC<(bvY*YN*t-L?lX`-u<@0g z2>e4EU&(I)SM7=QLq}fpBi0H1pp=pN+LQc45?^bRxy~H6@s$j&enjG2$CS)<>}`pI z>yuHgzaw$3lS<|~`L4uK&nKf?e^25oZ1PIT?@Ju@d@{Jc_CdL?P1qNoN&Y7`nSF}9 zXcP9!=Tc^$ekx_8J{&sqFC>ms{}QqTDRolj9Dxo!UCOL`RLa1F>_E!8UrYQen+zQ~ z@!$E6G%`Y|aZ_2JN=pO83G{TnG$r;?#VKWVG`t(1Z3O2!!R9hYN3)y16i9hc)o z@pnU3{_cUSe8l|owI}ABuMIIyeeI92>1$8+mugS;SGu%~{jS=F{j1u6<45_+aiaX< zI8-)syeT_pL;j!C`ID5ZBAtVXylCh9ApauexsZRBGE#w){{tfVl;>G_QTKkxKT1AQ zQJ0+4l0$jEl^6U6AfJ(Zq@pf4-$@ST1y)}0AB6n9yv@eb9bBK6R@0L7VyN(tfm&&`CR0n>2>3j@v}?so#aj zexd9}Wcx!F?@|AX6t)R@vrQgjlUGQ&7}8iN2ixR)Hu)AM`@ctU$PJ7(1|jA~%y!^! zL4(YCJhlkk@9GvaNo6jR^0%V_--PH!6rsiFkxIO5n$>ShUzVIhQ2x%b_?>I0YKZ<| zAJ>*@4Wu;@b;MjUt%J0dlvzd&+p)UD*goWvQ$u3pTwV}bomF6$6u899Xzd2C{8tdK(+h>=qiu`nXJ#EKxQF~&N? zc+BF6KVo5}DS%(_FffzXO!;r!&WiB&@+ z*MUeIh>^pwP#uw6V(fd40diS~7>~)ZMK0?QBc~1`k4-Kya>%WRSQn94eMEA|4MkM? z%0q5|NG`F4i1dM6)*(g?+vavea)~uUWSfx7I>g9f-!(=gmsk@-_8GaXLyR1bg{Fw) z5^ILYF+eWs5F>|U)rm+hF%ywvlw8&!Mh=4ukz8VKnUc#o#2DB%Y!h;cu`Spp_Bzdx zXE}KcisyzLMgV~rk3}B&48&OOM&vOWh_RgZlg~hm<+R_fk36;qxeVly!}bW|v3<#9 zAdeijZy=BTMJ@w*sWgTMV z^h10Ukz8VrA@)ZkmvxAd6NUIVBDusCBSs^V%R0oO5dV+8cMsR8>cYnNb}n)XIVDMv zR7wfiWA3E03ef>MCFGPON%gkVSt@TuQnW>)S1Oed5+z9vC1+mboT8JE@{M~vmK)*bIik8$dy3b4?P zRJmORSlB=ZOc#|`RDgx!F^PviK z@BzQT;5>9V2fsK+-J@E5Tm@?i)(+rMhVC&HtRc`1QUMkitR2wd959clU=4vTO9fb9 zuy#O)bHF^Tf;9xXu`1J4rmDQ50^LU{(^bZ)j8}m!O9ec@01F+?f#+cr*g*G;%Eu}* zRKN=z%FsQl0$%9Af%7@DClhfWtZX zCk|}_AMoUZ4mjYULmZz{8KZ)E1KsN?gH>>jI$+SROI3gcZkY=D63i! z-M1>}4`5*f9WWTDV^x5KZk!6nDX_4C?s}EQD!>3sz9m|2rUD!2fLX2rpX7tD?^J*# z-?dsEqXHc8umukFzfJ{s=(1EEQn_4ZtqOD~L-(-CIu+;!sbr}Dvswi@oCD?&l{G5R zJ*omMFe_D{!#Q9cQ(2_~-Qz020<%H|I-COr=cvOGn9V9%RDksM1FTzEKD0fVoTM4;5gc+pp4B1z6ZX2h80nzpDTX z-9D9mD!{@9I$-Wm`Bep2=zde_uL3M=pabS!m7i6Bh3*%X0V=@420CEwQ`w^eEOdKS z2C4uH8|Z+!U*$&?V4?d- z4t3Xh0TaEW3mnd&UfPD}eOov{EEEe&`UzSFu4Dp(m_+Z{0{63uVu6X?$psE$LotYP zdNDl$hrUuQFwwiXz~LPFLHjIvuNFA;y<&k$FRW$Yj!$4P2BP4Oc{u z7$-WW(hDVY(b!ZhFwr}=;KMnLI~}9x1q_F=uHzV(=v`aja1P^G$9#G@!=W#94n^8{@^=DBajn~Gx7tLhOr#iVu6;%O?1g)Y6i z9y_WiHnIV(gGxL7e!7ZcBitE!Y_Fo&$ObsY;NCI4hKgb%TunXRs-oC**Z`*(+>7F! zSYRVuEj_kTQEWPF6o+?L`7Uhw^`^VrbU4?{baf1?nDlE+r{^MjoV(6+=V}?>6_eiF zbb2n*;arP^F1p9RMZZHwoR*{K0XGM@R;s%xfr;KtMV-N+7~JcpH`OEBdxMH%fl0q2 zp^MHb2KV~W`>Vjgmtuj5-Yo^+l?e>)_0zA`GIThPHe9cAmFdu4v__ij8oK^?-IDKFbrjbi_m3 z8tsR^GaTv<--wUeM0|(`c$6=~A};7t(~9cCjAony!(Sb^c(krC*TH;eE{X z1}fU-=-pD-YFpDA>UZ>?#v|f8OAoiHbX2KrI$b01zGynmQK!cUgZa<#*Fkl_0%JNH z@m?r=M}FW}eWoim!oW9lr>dN$(pBXS({452|0{`?2e~2HjY7^mrL4Tk(tbkRGN-~;bj30=g4^H^V~tDxmdDtayQ z*O@9>uB=i~rK;kU57$YYk9?|qq(j}RswfVekzcH9ijBVO!Pf;CJr{kzhp~dOUspxP zOvI;SJsR^EGddn39nN2CD!|e&&ZCaN;6pytP4UqOI`G}3qMTj_uA5bq&+8Bu zr*fYP$NfMpXR07B9QO?p=Of%DY7HO2>G^1WG&Y^aB8mz4l-J|3v?wZ>rbCQxRRK<8 z?Q!k2h*&E=(y6ZqquA&JzresZeBuM$Gb#_OyrS})>0Z_HAeCoTh6Xr2pZ;%^r%m^K z;(UY~Vmdt+VP4SVQ>J@S%fKooeX!~DTsknrRGu*1a4iF?nDi%2r{^NfOL~0FbR)D3 ztYXq1H=UltJDYglGW`+Ljnp!*ib;Rebij;Jc}+#JQ4F&6@VW}HY7^;Dudyn?s!gN= zW}FIqD>l-h4R5Fbt2U7inDHuTi((@k;`XKruxbPXg#3sfKz;=!+gWony&JZ>1JpdV@l^x`ZUu4qj8Jkr`X6A@zc0P zShb0Cb@c#F<-$4>>69blxiCLqsM{o!2UK)?MLP5s`r<>2Mx6v}KOz&`w|#gFcCD^<0E`Rgc;?kxpY4@d10k>A(X%jh$al zfkTW@KlShHhgbur_(%r~VxqX{ldfg71F=Eh;sc%5DXQD2dR%R~xmup1qIFAOV>;9y zZT(6`v61Z}J)q6Ns!gN=2C@E9MX`}?p&k%pVAUql0i*qZcLsrtbPM#L{SaZ*Cei_e zKKoonv5{`R9?*Bds!gN=24iKOiee+(XL`Vx0ak4y9WWSID^(O5=~n3>TLoCPiFBB2 zh>gZ1dXEsX(pW?>!JJ!cxHq*7?AIzwOsD6fd5QVC)O48Nz$zwvnd$UgG|w^LzcC%w z3t$zK{;lcsT(oYC)8lf}jnOi&ib?;@bb2mYhp-;4Fdfrl2@BO8JZ@O)&16DEVTTG|t z@a`Mlb4%Z8x*b{uRx#bATz~=gOVa@ZEaJj(I#0_OQ;46&F|tKWFt$EZ(Ktpr^aElC9Qy;fjVkCD z_6PbEaRHY73k>3derEq-oFI0j8Q-S5NF^pmhnl~ z|8O2SjCp*ZdrajKmEToA7gH@vI(qo9j{q%f<%QRhve%JF6PWvzN0i2$XuIJi+ zdSiV_%S-ez&0c$#uaT;LbCvt#m)%pQyGjpilpUA+;HtQxvU%Q4S9L^x+5P6}`F2mN zsueD%_IqX7j(oDY>;_rctBY)ZVS{}4L}l4sV3K@YufF_npd7GTkqAqB&v)t%J!Rbw zpS#mvS|+>4+>*q*aA;FmmodZh8=uU(C`*3$_3|WM)~~`vW#qr7rMn7K7RZX7*E-`* z;$55mysWsmv8>&{UpDmH=lRWF5-;0d{?JXb?ao^r`ORN4uko$x-CwqTdYzAl#V3iE zeC6hqlO3(+xiW1&k?%`?O8z9?t?#@pn>$aDjT`sN_DNHP{8s-YUe=F%rQY~h))(5u zcqH-uQ0XmMck>D%KjUHXN#Z46>C)q5_m^+G6Sj{+e>vk%;{D~N9q1p~b;&B(U1_xE zH-AaIY=7B>MP>J_bVq*km&8lH&EFQ2-NpC$cv$_Dc*$38;Y#`WfgfF&J06sMS9ty; z-mNdzlHW%t-?BckckyN+zxhkz_4PBpQg7FmL<+9!b1E6k9BRZeJthXZs2pn8PRP%ASbUOr$!F^q*BfX2NxZhcaQ*W9 z<}Znt?dN()e)E^a%k_)vBjaK9PvRvX`770^B|oP(aFq@Wk=--yPU2lvezEMm;T#`d z@~`MuM0OYJlEh0s_Fwt^h2)nuy3Qx~lX%zNTTXs{d$R8@*4O+c@sf|@?W8kC$=^Z!`k1vh~^OwX+K0lvtIYD-R_J=e6B;HLQYJ1D=^7EJT+59E(dOll! zPdfEx*?I0|u3UmYiFaf5KC(LOzb;yzp|Kkw2&Ul8^H)FT7kA z$e$Ch=i@pN*KZsTwvLfMCtj{QT-WkaUt1Tsj^!9%@^QSy@s|91vQ#^}ojYOn^>WUq z*)IPV>!keJTlBa#V{7Ho!T2r7bMou(;&Sfwi)8oyAyRGO)EuyxuIz|ua^bmCUCC|- z<)XVvdVcd4@Md|wpPDR?`qEUsU-FUEyXGMIL#!*;;3>(twYe)fW3gQMa4XMm{sL^8 zknhKj=g3w4=gQ_014YKqCVz-^UX;MjowS%9Z$au{^m%<6->fFT@J@_I%n_p31mO*4L^hk5yPk{t)Xb z?YUFNU;COny2%c}O1$sc0nlewK_Rl8a;ZOI^6T&b4l zH-914k?;JiXUOKN6Wv+YzbD)0E+l`5m5;t`B-_`tkO?(Dlg&jJdw%m5VjcPFJT7ve z$La2@*(2pZ+8pwSSeZI|upBt=G?}z@k{o!bpXWD!A=Z)aoST1g`TqO7tGVQU`TLzU zyXkG0|F|xm-~5GGN4{#K*SX_QddF3{_Ft~x&99O_#L739+~Nw3 zt}kEqdcYlj-<6)<{DoLYzKVBLc17p@;wlXI%@zLTI`W5DSyv;?6=`@#)?BsD6+303 z=Qn>L){(E=Z*RMzD|fqc=PqAW`yK-2* z7xNQh-RXB#kUvJ9#_{U;&0mQ1DzxfNXe*NY8zN&m7S=t~=j6cM> zQXNakifTG96W0gNZ~j88zh2n&L3S@#Ei2A@T#P@&dfwu{4b$sY0hfQ<3$paw>*yy5 zYv<(Wq0h+r3x4ywIbDZ1-?%PtuAWfg3i)+xzhvIT9OwM{XTF`CCcjQ!oP;%dzb@oo zw^FvxdeNPbFH^RyydVk7bLLxqPw>g_o!82?ZPSvm)^5hZ_|#9tA7W|GIQW?5fOUm4 z4obaKUUc~vek$ipUco&W_fsLSKSylZP47s()_-z;m4rQRMH6ZK<37*N{h#gELM-ha z`Tl&Wn_SxVeeSP9tShqqM`_b~jUzwzf3{x>v9uTR{q=GUX)~`9_g5j-@1KfPy;h#C zalAY3o^sOhtLM3&3bAsi_Z;ce_(QDUpK<@k z`kKEG>yCTyUK!n|u*<*mav53aW|x2K5At-+j?U_zgylKI%Axn)kkLcNvi?a}wwrPA zwk!9^?e(8a!rD3VFfJ~CPS|f=kQ>{t_wk^g9I)gOYro5HwmD#3v3dpN&5vff<8&NP zSaHY|d2WP^?Qu5a6V_M$ezLQSz5fjPt442`u(7NB(WH~Sx%hd;BgDGnKYK!^EWN-L z*;zr}>D|xso4*k2`Tm;MMc(N$O%4|CBvTd+BY%i>1xj5eQ{TPA6&ie*y!Syf&u{)h ztQen5Kd-pFH(Y2-{t)Z(Kd?;ROS|0V-%(U17Z~FC&0i9he8kc=CoIPo#~b6Df5&ne zJ)&XA>*H(V>z}cCBv$Jg+57$~+~z(RU-xmBfBV<+`miKkm)5VgjIV!~{N6SvtZ&oK z74p`|`L0m!oiceuJH{iduS;*SMJ5kvuk}n|X>0LG!m_`}S9tfu^7j2Fvj0M?9G<>f z-tO1d^BW)gGsM!~k+1N9Rx#`(^$`gVPx9jWt^WCgT|YytBVVQWs>`b{jb{7FA7XucS7oQksM-$+`E#l-pKEX& zu;0v2j=bEb^0|ij39&&k=$1rpX$GsdgY2FVa?w2abKAe)^x0&D_DM?G#*~j<^TFS$=tCn zi8tRPCrjf=PYlHZxXoUw^`vi&*o zGQJjjM?X37vfb=2#`nnQ)oE<6Bfs(G@C-VQ_fwAdLnT)gkd5WDU5Nz)Wc%TkVcX=# zPw$nDXUyjPkiS3L^KDt#QF?lab-aJ${gv^#lK+_|KR;G8#ERK_KHk6mcxa9MoGl^N z@qUy1#^+9~eUTh2dt-_|%gb``(vcz7x1aalCtkQ()_hyiSv*3l?9}yT z&F04bzL@vP7M~F7@4NZDpyK?mWyQ1yobiWPS-oPFtk}4Q_wSzH{DoNm{DIFmPI>ZG zSvz>HGyV`OORM}XYu{VM=MA3U{DoNmyoAqVsvmc~Y~9$-8GneC`Ey>BZAGW@`H1H? ze<9XC-{JG4>be)-bMs%$_(QDBzoMh;88(N{b3DKK3$gxr6rXpUcIvP4`*Y2l@rPJh zaNAAt`|3%2{^a@1Ux@Y3&-i@q0F#ERMbc=&j4dQbkm=F$+${_*_A z=PJ)@Ci}-H?FnRU!ru2E$H#Z=_1XB3Ws-O~UOB#u&z(B1ocwxC^sa>c9-Ag+@5dX* z^H+T@kzb#CEs2-&i~Ppts%2M^pU#~aV#VzJ{NViiGHa&%)cao{mh+YKi+rxy&_`tZ zO@D=0F?&Csxn6uZ`x)6j&^~LiWpR2O8tgN3pImC+D`}K$G+p@$CX_v7V3n z5oh^A})C`rl*udvCqB=gFb&dz|qH z*euDezEBR;ZRdaAwll;`vhlZzbaGTsqc(G zz^2K}eR17HKC7yK&xY^u7@w;${!_VXLekzy%%1Pn@I4q=Hou-+vp0N) zD9yiT!}oZM&s9&mM*5w*HK=bI?L8mgv-x8Cw{q`~t3oX6#s25`%8}Q`lkY#Pr^NBH z{fzIC<1Ed`m+>I)k>f1QRUdo044Lo=>*woh^CN7VAHP;V`69EBJX`1v&X*ADpZD>7 zCW|Zmg;=(i?-%*!ea0VR{qw%+joQfY4eQ;hZ*7p#|GL`c^jvPyt}Ep=S6{yPeYlJ$ z(aJyX%jvls-;eU~Fn)W!7}mk_vHg5M%AO~NSpR+$pHH&Br!4Oxt=}c>!k7c_paz8|*FVFx8F^)Z-7C+u+u}O!x>1HVZt2>M>??2IxXpEHe7(H>Tp8E>?b;#M-8Aq@ zks_;H%kB&1uIW#?E3e%w_my4buGlnMnpC?hz?PJ!sy-_BUGkyycz=R)eduZF`@%Pp z(Qmmt``~_QR-j6N&7{5Ot6R8;44P5Uoi{$ebZD?6z^3W?SXv(IbEfAvKAF7bKIwIR z@^9{D@5smNggJv9 z>cvG|rT#Yu*fi--wVduX8_RJ^4P%>^)zrr>}G; z*6r$A-Mh}6a>cbtyqRBQy3#c(dVb@ROFyaYs@&2##M0i8uk&|XT$xv|bRAlhcGVsW z@4K@k{rt_YOp|Fse&dt!i{`p&GpYu>S=`@oKjs>JeYgCj?^R_MAMXk@YaU=r$_uS# z%b|DM`28REmqYH;_hmo7I>2Vq-t%46wTVmHztde)On+-woOG`zcV9eI4nNn$^BbS^ zc;Y%&cxqB#(B6@+#Y=l!{{Pza4bFWq`}q^bXhc z{kL4PJDw$2OLab}Bcb+?G z@bTpF>yNER0XEIokM$j1SpOYNu?}2+LM-otdEd(W%pC3u)BJrb?~{2Se&l^&nyY{E zyROXQn;ql9I9ofyI;B=lxa9DA3+;t`uXgY0 z%8h(J$KP9c-^%+;yZ&$;3hGc*?0VzxJ9%Gg>s*NCb<8#IzFKyyDDKxETQ37_nqO~P z-g>iax#N8A=Sbc(&v)y{?y|GuX21T}`j*7Y_3YI2EZO|czerq zv3?!1bd$N~uPx~sVr9^Q1M<{6`}}@~`;##R=g4a{ zw}e=~Uoaj=-fLH{l2Ka<2iPpnYdn5GacBRLGNR{z5bO6N+@F%)_9p>0O~}XldOkO> z{Yr@S`(5s*c|VX-9Jv4I{+j$b#eqEBm$AM%%?s9-aWy|V&I`7m`*qekCtlW*`*o{t zPQ3Da?ai*kkcZ{_Cu+Id^EH&U6P|SKck46oDo?o9XD$e0wpX6oyUN|VxwQ=J+S|1~ zyjupeyxQGRwVMq7w5q!yf5{{)_j|_UdF{R+2}@q%5$^x&z97Up8&7_Gwaz$I9#}HZ zwceC1Pu`(svHWinSTGz`wQ~gI1aFBo|pF*yx*|- zl7!`b5aVk1Lpk(CAAdi@cv$;$!n$5lPLVB5Ho7iT&e7+|o!#w!c9!qw|KxhS-A*BiM-{Ku&Gst&q&up2!q!jy){2|tlue)BFEGxEFbmX`3 z5n?mQ_rxp36>znfk%-5bM`p8?PK+&iDgtNscFuSI=+$0&J$=pYgea)sy?H z0GlROFTZc#KG614A=YtU)^6)(vTRQ|Z9tiG|1*#3#@W{CCe<~(b+ z@;I4MuRsoQNRu-MHj;N5mgKziaXB&$X|DZs+ho?x0`A6{Rb{r+CZ99@unxZ8uIPWA zOg*oXoWAJ-dB0dq`U|nH?fA>(^YLk(mwwuxuvzAg2>(7zn&%77uG?@SEqh&`TDGFQsv-enP04;7=MU$>@V`t zPp58eW#yBfhgi=;UiM#!i$3{5g53zDu@gef=iKlX%@%-j5#B$y8`;ks<`pDF*Vb1tNteo6q zi%i_s-mjBfH_cy&<@M2zHydBBSEXvQ;_p{NEXR`{U%W0)n_OKM4q6pr{dJw!dE;|; zJ${)iZ}Dn~%`kgjfBkiTaNkDqc}DWSkNXhr8;sBOeXf=)nNU87*X%tX_bHFInkKWp zEf-?_zKQ(C=lVYQl`QDnA;e~wz2En6U-j=1CFT7U$@_Kg^SCcFKG$o`dop|Ph$LRK z_xm*NE0=E0lt~Sfenau&fc(biY+NMqnmzZGeq7i%39%gi9Ivj+(<|lEUL{=TbL+|c zyJv)0DLApMynpuuKR-DCPUv{P%%~Oq=AK4-&v(bqlVw4XMXu}4D`ZivDIssh*8gmg z>9x-E{Kl8@>;AU#Nx7uHpuHns&(rJ5*ZB{)?#uO_>Zc@Z#=_eM$n5jxke_@R-!99R zd9Niu2RD01zTQ{Wm&NzaaJ@b`N508yn^fQTcl{=_*Y5TF#+UKo!=K4##TSKG&MU6t ztY?nAZd3~^Wdfpta7i=%v&+7;0cT#=H>#q}ualp8TSh0Q*UN`JIK|dkZ zk24!ryiVk}u9J`a9A`PL>s)WSK63o#wEp_>YwIP~-=qpVRta^TLlat`|A24_v=EZpok1dd7Ldam@8Cr}d2Mt<3{R{+!ld^4WOJ z;Ch_X`pfGBdFdyIeU#@RuU$WK+(+4S20j;X9V(QQVf**Ff$zR9V^;n<=!-0=w<}YI ztbLyMS$yu0G3)0^@@S6}0_;D}HOOy#?q7#z%KZJ|-zm$az2~#%8V$!5Nt4$vs}b;K z`R6e9+=YB@V4-tm)u{aeHjVat?!xCVjf(Hr=R40_9$-uQ=SKFNh=!}NWLhVGV;$4lGtHQm)Mic6oOecW}AjS8{k zb;X{3(%rsuuq$+SKX=#feds5|O7*o(T=N+RFQbUV8Z0 z=U4=eMc`Njjz!>D1dc`ESOktm;8+BXMc`Njjz!>D1dc`ESOktm;8+BXMc`Njjz!>D z1dc`ESOktm;8+BXMc`Njjz!>D1dc`EaN;-hd+HQ(6ovrrKs$-qpyj&rN8#TvKwdrrIX?JxVUtRNExKN6F2aYMbQuD7jiw zZIk>mw;glmF*mB!C)GCD@BTz?Smw@Sye*e&s%?^A`eQCY=1w*LskTXenTwUV0O{Xy zv!>c6`DOd)FD3VDs%?_rqvV23wN3I%f6R@Vk{dSFHp%Z%a>b_FCi!K2nah#>tv;!? zNq(7&mAM=lZ;OAbZIWO5V{S_3ZZ-d@wn=`O3zoSl>EG&;YMbQOw=d`1v#GX8evgui zHq|!CFWbl5u_?J}Q*D#{9wk?8s%?^A#+SK8>EG&;YMbmgK9_B(ZIWO5W3E)@jy3ip9;JV)PpWN_-=pNxO|?z(OMmpAl3O>`Hpwq@NV0!<{k5EuskTXe>5t=!IWWzC zs%?^A=EUT9qJOJTs%?^A`r~|JPEYfnYMbPjIX<~w(ZAIv)i%j5{rUAWId^ZWZIWN+ zEam!0|5l$=+a$lxZaH?&RU*=%t{GorVPpWN_U*`N} zJDK~{-jPqWHNSnL{WJZt-6=U>Q*F&}WP7yS!>P7Oe$7vAxrkG3ll{i$CQh|Y_8Xt8 zIMp^szsxPn+{k%}Gv^WK@&6QOw%2lq(|=z4(jV8Y{~Nztm$^>n#jp35b1vjO#hKS3 z`p=7BUKe;>`oC!}=MVko#V`GFKK(C#`8QvgTQ4QIa%!w>JV$>IhPnKhdyjv!m46d9 z7u(F}{+EBVmAUum-|CZ#ZC12yFt;;vC-ZN_TCV3fTmLs>eJ(xA{cQEg#WpSSOMlF* zmy)YF&es1;S>{%zfBPG=akk7g=yUt=Z_JwiI9va>R&&Yi9B1qOF*hOqmZ|xVv-N+2 zlz*!^CHHfjtECjf#@YJ6P0hchosv5`&erE%<=?)h zf6K)hXY2pgHvcwwN^a>mTc1mof6JTxEw^l(t^eEM{9ETKxu@f7eQsR-ZF2gzT)A?39B1qQRz3f= zeoAiZI9s3NnSTqP{w>#aoUQ-c`^*)<9Jl5_&erF+<=^(Ff6DYD#p zTViv`l^tu#94|hHjO7r|gI^zK=6qqUCCkwr>zDqR!-nH3FL7p$bmp+3|GdPRxp+8# z=-28IS7$$-bIHXWXX|qdalN2_t52M*pTD`}>W;JZxstd((!b?SinI0WRW7-_<7|EI zCteTe-*Q34+4}W4mt5a*wmz3tjj`orRr|@QxxeFV{q-o9T;OrGJ~tPy_w;YMy5em8 z^*5JX;c>P;*BEm$(!b>%i?j9n4d!S}$t50V>-{o^TuN^7SlgrI8jrQ*dc}2_YoFzY zi?#K+!uy`)@_)9|=d7~abFsF}Jx71cKW@41Vr_}_{*!Z+$J@r|E|0VIx%Dhp9dofV z?|Gc9&vEJVN`A3U%CEhJxy@s3{k@dsMQ3huyMKwbWll}z!1VV=iTjl}Ti%Z`Cnj@l zGM9OrtGJ#P0)akf5}EOUl4x3}Fd#o5YHa;eAJ`u6gEjQ3~e zKhDDK;OTViv`#U5+RxH8V3E0J$K*4D7Oy+H`akjpHbICOyXY2FF(;stSkF#Yiclzh} z=KPAYb;o5KlnE;iIiI7x&3!Vy?&Hq-JJy!{YdP!bkK--Ymi_Ae?!H*wzW+pLagVe0 z?KHp4Y0tRF*?O#vLC5iI^@z2#_Bz^H8yNps+XAI7ld13C;nz#<-)(OkXDi&VA1vNU zrYs!h*SvMy(V5^}zhIK5@4HT#p{SS4Q_K%v|*J zA7?9;i(YKK^8T$pakhTH!RtPs2bVZlTSlh!inA3y|2=%mT6y~Ve%`;;C(hPCf3{p% zzP;u@&epfra%cJ6Usj(uTb~PzxwT5B^^tM={-*ypTVemM%1)C}wIA}i!Sd4HN_*~< z@z=iQIF9Mp>X9eE9M{b8W%Y=&_50ZTw$Ea2cgyu2YfG%z3iq*xHP`ozI~vB?@;;%+ z`X8lD>otzK+j3F{}0N@Whb|Dg<4FI24^*k zvn4<8Q+S``(wo$g1}(?O**e|_^1jUcss3xJSFT8`t?_$*3x0JiMaI z|Mhp0xno_d-+YgpER83XWBXXwJlV2+)}OA>4K?KQzMs&4tl#u&rpx8o8yIiz-|7=< zOMe_sh3+gMO()f)|5)4fx}&7&n$iD^uf%wAR-af~`tx&Q=`OkEtmmEikG0KjShJ;n zXZ6XOZK6LJ-#qzc|Jqn^tVdq_GOip??BDp`oul7F8Ba(5=8u2dEw;V(yvXsn8FL+% zSTI1gA8r|E>vJ93^Bn(t$8sOX**ZSIqJQ(pT+VT}K6mr)o!82?ZPUb_moZm#oUP;Y zI{IfWYRf4fXG?zXkH0TiZt6H&AKy|POUR09>wIo)i+7x@&#lepp^UfX+K#jJ&qeL| ztIrjF;)Sba&9^1vY<;fqRpkrG(gs;V|CT#E&elJFw&%@0_j$$nU(1SV55(E}+~$#x-%a{(1Wu!-mM#_GkE9?x#HYs;nJ6H_q1Qa{qM51ljsc?F#TQ|0gv-P>@=N!L5_GXP0`nO#5akl>V6#MlvHRyK`YE`P0TBm7;E{;fW7wvPU|ZrM8J%zvD%*t+C@ zSD=5ZPn<3J9sQMg<2d=_w*Bs;v@-H%gFurE#_#Kic3Ey2ROv@%#D2`TSMiOXSz*UW>Ek`r!SWKUXbV^OBuA zG0s+u->)CGUdWeOGv%k=|BAEq>v8q-ip!px|Dr!vZRjJi{ieU-Y{~D}OIsi1%h}J! z_93y?6o37(^_c!#m8E56{nW|veiQuu`e4@sS@zfjS--w+oUOm!+VzM2T*Wn6vU+io zI9u}j>!Dr$Wc8?`vijG|I9tEJuGyYBH*Fn@v*mu(asOJnz!=RHH`tl~I9vIl)kxW~xUJvM{&;AO{G2VUPn@my z$9P+Oo%xTmWjy`<-S+FOPn@kjBY)8qEj7-+A9TWiRqmwb*{(o|7u-qvzmKyO=1{fw zkvvx(Y`s6ee|6H%cA9T`26MW``ehDRzW>Dcp{zb}w*LJqzHe5!{yJCuU}NTxjkEPR zWcj`q{abzFZ2kLYe7~+n?OyK0^*xxgHqKToN3HPvHu_&NW|S+@du^Ppf4`3J6V`9` zi!1b7ZRW_$#Ws4ESeVIN$M+|hqt^WAVw-pmnK^0s{v!Qbed28W z`;&ZMlsR$De=fF(_A)0s-`Avnt4}VriT2XpSq*NI#SJ(39IWO)7u!U8nRAuzr_#UG zC(hQtAItZFne+6#d-lrw!Q*nVO^e>UW=>YVk4yhnpEz4r=g=F{>eRfEwO3e0`n`!|2?^ar!$oNv$1#Ww0A@_T=iK5r)l7W9&N_f?QOf1Q(yZ8SDqnc77& z##Suj{hL2mzHLn@J8eZSwpF7z8^6%swt+)3#_V4x8%|gy<@#-ivvvG;1o^*Mo3XWW zX}$A3q#?y0SE z!ItT9w*KD{(7*X}RmOiRS51h$*AU|u`s2SNST?_&T(h@yE`FoA;Qt+g{ksABbJf$X zk$&fHjk6Ww7y9GBBlu$bw{q`~tKw|EAC4!E=e+o}`NHw*>+!$%WqfTs9c3OxvGV=P zc(eWS^C%JL>SIrrArn4fT)AFw{fLW|pTE{V`69EBJX`1vt|xJ}{`azS2M)^3e`b6C zR-ZUqp+EL3|GkF!kF)i^modjRb5Q5ycPr+kW-e|1UYD2OttvDxBahZE<$SywwUOZ) z*0Vlwbr$+#eA!;}A7|_TeF}dcWP2?Kcbu)Tz5IQUztdSx?l@cTm$|-q9klCWoUQOW z$lTxbYuCkC+qw64b1i0#6XvY8T-7qY{u!>#$SZTP-5XsOo@uwmb>4NOSk7vB`^Igq zQ{(I9_2-S>rWB%|MQ zdG^8m(yTz0Tx=891>^U*znQcByz%*^LxUZ;*e2Eu=4_{b^Cy$H+$X)RzaY-m8NZ`H z?l)}z5ogQwL9f51<*`0z(jWI9akhT`&>#KVe2%mA{43ESLK%0akk`l^w;^jEw0R~SGo=@O1o;0<@Q`OD_S?w&)@9IG?^y!Z~mnG zqPecxjH9o)te^$>pTk<>lYqPPf zD>!tIYyILFcS8H;<80-Onp5;$`r<-zp%uGk&V z(w{T`v3`v|WBZvCT+tgwXISnp)+f%^ar|;TTRT~gI9s;Mk7pa-tVf)!pFdnLtY6vg zI9v9kpTC?>d5JUqalNu}%zlsc%W=f@it9&S#ufcF`k{p@R;-erS9zI7oHzg8cAYD_ z=|#U@=4Bo==zoeUcKtTLe%N~9tRA_vw`#Or(J$AF5nrUaVvn65R*yJa*I@5FchcbF z>BnCm?0S)lZDRg1zHIOC!hg7vign=iAdbfwB^0KK2Ptf@H)i(j_q%FoyeumiE(B78R7nh*Co47#MwIfVXk;yAME;+i*2HR zc|BsTc-AA{Z=!$ckGU9meK7yAetA8xocBWiR-ZUqp97NDA^Np?#M%1mkX@Jjb;0Tp zXY2Rtyg#|>?~yX3#S~Y6W@~wEN!K`A8Fb))JoU~#;r#;l?_&zik=JT&iL>?lW%J|c z_uAE~WYm_zx!7h!>lOW)AK`xb&i*51M9%?nw*I*?Y-Nu}zFC`s4j5 z_wVLE&eqW%@3;B9Aun;}{XXx%=|3-VrXSuHvAua&H`reGtJNb<>jvA)`+c@MFMioh z-tSv`^WxX%JhdFBvUb9guKjNPjlIefuJxGT{qD{;~cbs{%wF1CsLh2~2- zN$>PtejeNW5zEz@i)|+6pntx==Nt5E^~l9GF^}k%&o{V!*u0Ll<^3-E)t=`ZWo-0` z)(t+-VLw}Z^J43BD>FCm?SFQb@8|#Idc56EHVv8(SLcia%k&+n$1i8@UY{HJvqzfB zs*az<*?Pa`$Mx+pRMwp|pE;!CY%>OotuIRtHOw$S-mm45jzNZf z&NkzslZVROkCu4<%vrttPR)h=Z09&z@;mzLUuL*`*1M6j9NclX8C^f`Aa5-$LH|By zw&nPavn9Wyzn-s@k||#fa+Xs(&NgG;p%*2)-#G8z{4vLPoGtks{k8p|ti0WRA#LF_oD!J-Fe-nK5dr>sYmkOer?Ung2LjsXo1qj4xa= zV||;N^5)zE^w0Xl+4}h2y{V> znds=>`a8}xgZ^&qnJu%Il;ZfJ|2SJef9`r|vaHxz(b2z+?>O5G`g`J)V)A8;@qRwp z{ED;Xy5xH7*&=H$7DxZKe#F^k(BHgsvt&upLVo?Q^(4;L`{nxBm}DMt4Exz-%r~9(X~2lw|w~JICov!`ZBZcd%4(FjjjvL+6^q-4u;`(dzm-E&8xBBE_o4Ee+{>b*NY^SsPmt1TU z*I#Rw-#7FA$nIC-Y#r~5+HL(zHqOg(zMrR@qwitGuI=nssr+$IS$$(2pTpjA+Q<6k zy2y2^-OA%+M!f<@iF2a8XAW#6?=&pQb&Kni#K$?Zb?vX)CbM=Ha5v7ZDzl|F{WGlp?-#2nR-ZUq*LM8n^7;5Q@0ayxf5K*&JL2>>TknT{&wlP% znR)t;Qhi%@nN}&c_Zh6ct@q24ft_9J13hK=7Y)6Ct52+7`m0mFw|srpHmP!Ovdk}5 zQOtjwt>bv2-}Y9IPTktd$|paMv-N)Hm*cC%#mi;!`5WVG{rIJS^XF{cinA5t=XmD$ z<~kN<%X#YKO#gYg-)H;SUOs2Y%l$r|Z`iu%``6+gS7$$txqi^E)g#WJw+{=#T41yPsRg{H`^f`H!=e z(>9fnndjHweD(gVK5@2wy|VSmbxiLs^ERLB%zvD%R6eViOnYwz*C+4a>Jw+{=#T4T z$Ghsvte4u-f1ItHd}%j%?~8_hy|nd_^@+3f*9BgOI$YL4K7MS3Gyie6a$4~r^6rVJ z@;c!CTYchedEN2*^-gX2$keQ1&iu#O%E>*p$i!{!{dJJnMXOJoE%$F+7dd}iuS(Tq z#ow>Q*>b-4`NMtXw8_C{S~qQw$$H;(ZBg~z2>|pv-ggO^=th8K8g2*OE+iAq=vEYocM9f z`#|&OY+T3sHGbX~`f+XJJkFNu1Lv#j^7Kmiv{wn&`P_Ok|Lz%awo-6nTY3NP34Zt`!|0XzwU1< zpOlLo8{~KN*Yotc@^$_LuKRL*M)XsxZN|de2FUF5=FmU=Wqi9VTjsqM|2w%gkakgBS{5r*YmjeldAa^_ed0W#-#n~WoVR`++4{xna%`Nr z9&;Yie_qySTQ~eX;(DEz^_kZn&RhD=%k_xs2In!aPkFf>@p^0X)zN=muD|qW^VMIE z^K$*={(^p4k38I`ct7-O`;R=`r`U65KKFGUDwLC9`}etl@4hZ$R{lGev5^%$zpA$@ zQ--X4p3jl^+&N>`&y(cQ9w+2to46j?b9Mh5+WfhH9iA!k_urk1Z6^GZ-}|%Y-VMhV zNt4$vtC5RsRA>L3pZ?9C8(8RESv6{ZF1Asf$)92V_?*8{@%{Sy!ZVlWVjDek^S^7{ zd-q4O^1LDR=kD$FxNJH-_L@R|`pe+&8e6|SXZ~k2O$A6Q3nYsPj(#)uTjoFPtW|IP)j&mEu3_VdzQkJO+SWmz7pob<0&Z!s{x$yhL>?R5y}3Y5MgD)vZ$9tJLZD zW@hp29m>XLnI>slni_r^o5A5J^$(6((|k5}FE zX=$d*N~>hLXT1)w+Saw0;)YN+8!^p6ms;ltmlBsqmlAu`4b?tL?%!=)9#J2Klj;mz zqK}>p#>+#}bZKSas8hb@XE$AXWx_TwUZm;Q!&O&ab^pX!$BXJ}s?Nts`75igzUq8T zwQkK*`7lmZceCO&el{je_eoY_&4|XS*{Tj}lOMbAp}J^QiEvgI)kPoZSm#e3I{Y`3 z(6MbveA~K2G5Dmy%dccbjL|%LWOmappH$szfiA+$Zo25xKo{Xuw=B>_IBB|QZJ>*A zs{1O?MK~Qxp^pfsy09*Z`e_W zhxH)YZ(7o!fG+H+*ysT?jvaR|k%=IN&pW!3a+1jMK zLLO&pnCkQzoft1VXNIVcBC6B*W@8A~53E;#Ux(`l*1u4P>qkPT>p`M^%7?ZUQQT+Q`Bb;XOP~6d|@AvPj%xw zj`6GTayE73Q=G1oJ_gY>Mc1LjT!%Csi*W7vBwWKZ2C92kb@@C_uOF#nDDt7#yl`Cu zpU(5uY8!o`H4!n@YiKH;>XOE3#HZKfBlz^%eFPuoQA+(>%3M&sXwQ(s7ws)l_@X_C z>i${BZLgxbf7W~Kb97Imx&pyk7wvsQ-R!1cXGzm9`>C$rLs6tlV!eOTJ#@HEims1d zKQhrr0j`hQwp3kqLRT8L16+j>vsE`P(2Y>Ob5u7W&_#SYhUTU6sqWhV7xAg?`#=}* zsqWW67x78cMe9@fRQGj&i}+MGE6_!Js(U-oMSRY;Es9IjUe#F)e0%4sZbV=k@ulbz z@zeg;-fnxlM^{FCiCF2Hldz3+9o+lp|A{^dbXj`ss*~b3!l^EdeS}MCZ-i5w#U-k9 zgqxil=Ln}d>yLkMpCtQ8)Gs*(SYwaJc=>hAowv@d7PTYNX}`Y+UB-rg+NQeULEEAj zsBUPWOT=Drh}HdPMz+zI1YdxQ#%`$7b*Or@&#Cb8DC}O+(()hH^BYvxOxrQW>ngn5 z&vb84r!lInx^9Y_NFDh!F7v(4_*AF&Z|1}JRJV;f@~Lhgb>!1?YrM|*RJYLUj8Anl zsMB&(KRv!ho$^&fdvzSV=5-GpUWc}+?iH`A@N!?%y+obzAXeQJ=XIvOA%>h#_vIR>FlxudbBx}n5rIU19C)cY;t zv$3l>?;~*!i+lU%`2+9mqjf%U)jInB`Ml%k$p3c`c5nZHwN0P5M9*BxY71JZR8uLV za)Xsm)MHC4m)2t|E0@zFp3?x2>#6cY<;r@jXJtL4U1a4-daQ5dll54~$~sptHzHf~ z4ZedDdlGy{86SK{8Q9~jtaHVeVTbR)=-$+q!GZ74>t58C!H4hAgYN_@DJsB2PP1cGJ)UZ1*in!A!UkBz31!5Rc*MJ^3iN0r`D<#q zlj&>d@ir@;p~ucvK3$KuTlq{qUTNj(dOY9Cz{4K=(8C60@WTe>x+=Y_3_Ef*(Q-S} zXX>%Fl^f~tMk`|uwXpI9dc4lc;OT4SOM>#HTE5%#z_W}xgk{>+Qa!j(&$Cp{wlehi z4n4}Xt&AfvD4%2cbM<(hm7&9T*rLq2k0UWyC%8Uf{ouNRbp_vHi}Q#D$`=P^VDTOL zhCvy2_zr!8pbSoYhaP;HR(3%deE1HG1ZD8yJMcjQ6e5rY__J-{HgY!~{1^+A7;=Q1t#RssHUmF`x)LXTanjB(w` z%2(;Jqm{4LV{Mvu2xxv3soS@~K$Hn%eP!3$sD!8w${1ACNFAL?Ppx;4}Cohraw zuhPfL*Xi*tD?<+)FfCPBha2oW^et5I9c7$noo^1xu*G*^ZVJkj%r=!*}QrTXG_1 z9aNx442ef+|Bg2**RcP?rQo@_8oeZIj+FRbq3{LD!_n`zEJLI zdhpQ~$~{aEKKeqLV;FoK8{i;6${au7AV10+W8fe^${dH_yITeI1PA$HM^0eLbDx%n zs$dO$P~}-GKdi?gR(?#6gRMM3k55>+zaAe~nW6$7*nH!{bkRRnN73jf1ev}_FJvhjZ^1oE3sDKacfo+xw`B8pU1$uB~1?5Mq3=Z<6 zJjnF0BPX!r!Fk#~rDettN5=N)pbQMYqYgOFzIY}mL&yGlE+_+o@34I`(BGqF^w$)X zepUtsW%eCnkMGa}&%Q$$T;%+>mcjG9$_rM;akvUF!&F{U0p>+3Lys~r(4+0JfgbUJ z4fKc;Y@tW|V1qK^O8!^0{2!ImR7R@2W#yOkIMK=@^fIzC(}lt5yczSSy2r{3yR}dT@{*v@$rzkMelagM<7izhU}p zJ(3^gaVn@Y?8pf$d2pV#h#6xzSZ9`Obb^yp9UqC8b)nw3A&uE!Zx z1|M+1qaDDZjCK)^*btAH!5$dYC*uF-K0SIT;1|^wR4Jg6=MUafP%!Mu(5TgoEpH#d zFF73XUW2L&sbs1|pG)uT$zqPj+}?Z05&ZvAnTSilz1Fr1l&+~tX_ay+6;;q)e9-0- zRS>iMD){6}9HM)yvR1}<*c_))#B{*HrmzZPfe+4CP${o+f(kx351V2tMOE;rtOA?k zRnk@P!Fkw}QYoo|56;7;gi3K0d~p6Gl`1NysNjS1u&JtYstP{UR4`snR-tVzEnlM2 zSLJ*ae9l&>t%7rBso-;tN&}S)6`aH8Je4{sICriJKHx_EFI2%fe9$(0E>fu%l@jIp zT5hCrvFTug^9@zt3m=qm-l>QRJ}76ZG*P)!1s~K4=Nqe_J^0+MQdb2!;@Ia+Ro6-d zANF}mE#DAn68F>S>lP}gCq6h2n_E247VRMtpjVk!y{52|9tK6!B56;7;tx6je ze9(5-v{uPf!3XDI(@~{^3O+awoAxU0RPe$1t5mL4X|93~&Ua90rgFUsKG&&Spn_P@ z_H->*S3!T@u7XczmD^NmsGOmKPbZZtRnAnYse;cPD&16or)^g)cToWz9QYvay;Okj ztAbBYl^!a~-2e`Xc&_1*iAG90o2Ob>w zAU=rGWh&snr=Q9bDg#vRRVk_RpvnU((A}p3-Tf*9Rr;$Cm!;*0RB#S>;2u+XR3%I0 zVHM~eQ5mH2FBRaSdr{>j6`TVex))T2tAJy$3Up6dd59jLHXX{~Mm?W3-7{7ms>kO{ zhcfDakIIv#`;Q(!RC!P36_tD{BUN5jnW*xX3Unh>-c^~TGC>8p*HlKU08iUdT7Fdp zcyIvszRFk?;HRiS_qxg$72v@EUAD?(m3LIY0o|J_<5hqM2Xt?!j8n;00S9zbRi>!` z|A7j0(^Y1u01po6K34fiMBh*c=4^@c95@LZy6p{|0ljH z1`A6%j_#33WubG;v!1u(u;}>6q;f}KN5AxabZ+`1lar34U)pp8ws}^9$9$^qeUVM` ztY?qFlGl7{oytep(JyU20&6_lwi|IykF6qXr3rr=fhCXm)HV){u-4|JIIvCT)A2a{ zk#~>aC6D>kwne_lpTtWZ#+hv#{nExGc#Vf`VjGoz{}EX7ur562+;34FowY@eiT=x} z4nrQf&7FB}Q`cAXcwB$UZhtgA+NOgnF?L=XGREbv{EedxkETz;^4$MFyjS{ql0T>V zHr+JY-P5v*J7dWO?wR-R^heVt)t8vGnKNDX%(oqnrcc7sC;6LhniTmleG-=E$j_tc zldwET-#o_GA>o^Ta;n1_OX^4MCx*uycxTPLql1oz0kiu*RA2jg9goz9^_3RwE27;Q z-C8ctvGbc9f1y6aYCLCaT>m2Z^0d3JbRMoacepsgz-o!k^oWVLtKRL}e%v&9=QH)Rr^TRrY zyc+Z3s6$4#7DJ`Yf3u`TyTKVxoK=T)3bD#F8}m)iJ%o7>^@aM0c(qO;HtI{xnfxcG z(GTksV#%vKiFLx(od~OQHN^fO_TB=ziezg8O#;E)o#5^gET;>1cMt9^!3hNS!JR;G zC%Bz1oMCWxcemj3zTK&PQVDRvyt)5-chwKWR^j#QtcT<9UGbsvtJ1Rk zfW{b(`_J?6`(sw{nD={Q;eXHA{abSl_Pwz6#=Kq^VSO@`Z=!B=*|0tt;+w%^j4sP* zv3|$>Cu0kz$@=-uysnqaI zH(-677hSK_m;B~9&t*{hoz5RPZImh8c}egZDWX(+bA>T|%^mjlQvZAYp9TJBf&W?H z-(rE_J}vG^`rRe^TiTbbMEx%I3Y_l!ge@QM16gr-kKz}5K~CfH9uDs<@LlZ@7Ks8)BQ_eHq>(Qu{MbX^Z@lNA% zI$Y0eGqn%oG;TP1Q%>V@I-GaDE8b~b&hsz!uAIgVXU{2YT;A8R+Cn(Uitp_^8C}iws6vQ zy7%TRZg_KEXK}-uTRV#z-W=Xp-0;>4&fhKF!%)qtm$I>^(Y-%X@^>$NXe3 z(rMgq_9mUi)%(ex>{U9AOZ}pgy-R0t(O#VHWjc#%^*K)VHl4+_+NqPhPG@mBUB~{T z8W(=YC%J#%_R9G{Tx&1XS-RZTL;9)Ed!x?cI`Yc(%=iEMu`KxSXgqfE{ddw0lSh;x zSeN3RmiM2`88{uzE8l-F&rbJZo#r{5y;-Mm|Gjh3U+(QXD=)V-9uN4=ywkWLe}nwn zV|Um#7}6Gl_kx|KtM+WU4{+QS?<_9&7o0xdnRga9tZmpv%sY$AdE|8X&b+g@oJY11 z-hU&`mf{i*!EYw+Ev`oe6Ue?)NIdkXEV?8_mvA)mS-J?eP;tqA`D;b6PODx}I*2wC1@ozsQ0 zyG-9OXIg|k=i+DQVfY50-G#W8-TC|@{NDXMIO|g9AN_a^hdR3pa^x@gwYGH@n00m+ zIQr%-n4|MVd_$lAVWYEQe8Zd*Li)m-Cjyxt&mH;6`6QOUu;-ZkX}vxLA| z=O5|iV9u`DiaFGqqrAk0Js-!C3*(a(7v`KAa6g>wWSy%O<_su{``KAhzCWBPWu1+M z{DnSy3i?nE{fsI1T`ip^p8*>1T5N z{Om61Lz~dg__FkY)6XCyePPcGv-CkO^x0x$KllrIq}ASjepcB}&orYm*TSUx%QMo# zl-H6YyXfhXK6_|8TXNujIK#~heHK`7{xlod)ERi_U%qkwg1lO1;Gw+MrTSCr3_Nfl z{WIDY&Iu_;c5%ej&b!m{>^K+C!Kt{x=W96n>>tnBQ+a_LePeC)%NP zBYoO=N|wKX)6WKUoFT}0;Wk5YSsys-JhUG;w85|(wN;%%JFxl)aN~me2sIv|uLFng z)2ZJG>9fI2W)5Yu&MFJm7c55{jRD{sHb5O61sCd^M?;M%kfU$rgYBZmo?v|r`;Ei+ z7W#Zi>i@!=LrMC;g+8y6$`-~3R-Q42B8`yxAbl8XL*<$Dq5X!%Du;N;r>C0z)S)3IY?N^;;WpQ0mmb~En z=|mbAmk>F$eRVEWh#WX|PFIMW&2i3Dh#WX|{#J+_{7X;6N*A1-m*D(iybR8ZRW>>+ zYA?#6&dUleFWCy5lC#pF^SAOtpE{Gv;wbKsFdUs9)iF%E!M1ng&q~A6hjOU%!5sSb zf>Y;+S)8RWOnEJR;MDnBA^Pl&^UFf?fm7$4h3EsP+u70wPSr<KwKZ zec*K4Tl&B$+gti9pA7LAi?e)J=iuLTepDgyKWh2pFTg*ZYxI-zk8J8JE6Ah23XY5R z5$4=4E8XC;olw8Q=ca{l2Fei}H-v-UYhgLERalP7%N%?j;~mbZ($17(4sqWF%b{#a z4r$;wJF2`mE0p3QFZgXyFo*ZS=ZN{zZw-~)PtMC?Tais2a(sT7HBWTtBRhvar|T!@ zc|qTg=YIX$B^&Qu@H%XE`n}xbqH9=>vC= zIUCzguMf6g(pgJbj`gA57CJb#pLYIR$Qs+)2jDffHK(9n?sqQUclaIIe~XM-W2aDM zE1>p1us$Jww0^TnHlpXW2(-?nXTo&RGhvdAsxbWBfhit6lML1}4oo`enRu*w9GLXc zGx4M^royye!6v)Ki4`V2^h`YAL<*BW z`beF4(!u%(r%*iUVEu%XE1q<)e!|HVPx{g*OgdOUVGqTV4%SaNwc<$!>nEH_@gBId zPLic($}_#^xb)0+BU`d<-84+T#C9fsV|n&p(vcA%69VDP2w4=)ihDMNv*S+tek4PA zpg4pn&m5O*Lh*?wo3kGB9nwWS`4#IVA11xTQ+`-KZGx6lJldS~8(fmXH@}Xvk-UIQ zAP}D$!B99S?ly%<55;F0dS;wo;as>=eBue`Q<(J7Gx3D;Dopw)AH0V0Vk{TwijN(gcm}Kag;?jGrud*5z8g>QdIsy!ZxxR>Jo0B}(7h!=wX{ABnGEzHZ z8zu$jI!Xvkbw={B5QM^!aOXT!1g@m`^0-$}nDSp)VWDBt!}76#DL(0^zL4X_1twj@ z*Fb2ZaCO|9DqIbBZ-uMk-b~>txYtye?}W+?y+0A9v0_$&(!Afn?|%;l>E8rx9=m#W%#gqrwev@1$XRM{!A> z;uEHFv{KkxJrhs3B?4ixpSOlvC`@@|+Y)ZBc+$t^CCqjseVi8Iwg{x3^l@5*+bEv& zaax4gR-}*1MLJkNVJm*s$QyiH5hVowmf&GWt z2l)Z<)Ye%i^#SA)#8cnE_DKcIb&(pF>V{-I5V*e508?EO-wk0XLOO&V2!0B8#eJB< z-EkkTa8KL^D%=bAK?;)|icfkdF5v)$DL(NeL-C2HJH;oyH^N{I_feR*$p|DrL1B`g zgfInx@DL6ADopZ(DK5$QAh3SIteHTPg0EAHr6Hl`AOn9V*{nRt@BQ#7p>6v)aH(ud!8YX@8Ofq9NO#11W z_%RwLee_H`>H7mA0D){yn0V4h&x9vxnDo&z@l;=oNgq8EPxZxme1TbpY{-5{w&ik> z{W(8WU#w>a@KOZQIUQk{!qaeHuJBacS13Fa_t^*m2*i^d$0c2a=OF|tJQw%13eUlP zrNX3x(m=^}oX!o<%<*o;8@0)!0;`{TYw;f1(!o=KkMNZucT-Vt7e zK>7$TMp&XSm7C*|J=hMEU$zgu=d@O9m}Kdhbgt4c#iM89$p(x`C)cnLUC_-9-Vpg55b1cG&if5z1q4<-74ehapX`(ahK z{7A3@0@*z+f^MS>cutQH0l^J{E_$B>Av;1;1iI)w*)Xgby<)kY7Xk) zLNWxBCmnPZK}dr@@&ys-@<2$9K=P!6u2cva5i%i=4!Rm3G(_+~ARTlyLTHRY@}z^V zJP5fFs4iR)=&}Xhta(0{jr<`WLM{Z7r>ihRAq09?0D&$~1j;MfhvexhhENoN-jO_A zoe^pw&^s>#y1F3LMxb(&JY7`~Y9f?CD2_lEVTwcPmqMVcBm&_w2&EC|B24+BGL}Q2 zt1JRxflwKNu4)KX5t<=*Bhb|pp$S3_gz5-%QJz~NkR0WSu9gTb5J=t|fv)BV^$_YK zkPf=qA+$vxdD1~w8-&&fBu_f%A{%rXQ`yxz6AZ{AMRD=}>%Mpm1fiN9m8NyNo;^_TC1b>7z2*lBQ zinAJF6#{Xy5h%_|ggFSr(R+%s0bxA?arBgG8OT68xKpP_p`W)^vu7Ix~gOaS0{M=eDTdM<5;REEYb;C6uf> z)5Y-{4%VxFm!Zr4P{({ef%;ZdmksMXp?oOJIYIn=tV6%j$Gomr`}Xsv-xTYzoF;z{ z%Xj8=Sx4GjCcgjwQ#R|nTDBpVS)fROK-sKsYFR(ukryjZdLI7PSuY{q z_6PswF3h+8q4b9HdxTK3A?@O)zyAv*8zxQmFRLBm46;zN>bI8s&T&_H3nd$phv45N za9qWQk`2j&_5HKcJS-Tu2)|9@Gu_H@TgMqr)>&_%^oH|0*HE(I{DvWv?0-hDb>>tk zz5F|5{!Ov^-80S`{PC&eU!QfzY4h*W`8VE*50wZ0%{rgS$YoS{2_+lyTlL_xA32?$m(8*xY!rOXqU7*fEfIjQYOU_d$*4jl zjZJTPtm6C6#;m_H&a)oO8~9wKUyrdNzjX?C?B+h-kryZP9i9UqFV;DWd}m&-H-|o+ zyYT%da~Rgcb0WSoA4+dX*}|Q3{Wp{?c%LewzxwSA_5fTnhy7j8|DOM6f&W?He-`*} zu|RO26}O&thExUWgSnsQe%X4~_F%&1pT}^D`@?t;W>3ahTu$d#do<4CB3-9@HqPQ= zoyF&zTKh)Ux=Y)`aTeDquai9;XK@|r&>ZC_dpyqKQo7Fee4NF#(xttmU+e)njTV@XAjP4+;H|OoW}k2eu%Yi z;WY05O}f@TjMH>O_Ja5@hlx8_u4i z)41X6K{}25>oypETll|ega6lU-|3!aSX=394Qn1t|Bs70*M;X>%sY+yPx|(MGNy!# z3qSpTWqvcye}4@9Cu8?NnKOjg`ETbLbKd{gbEJPVH~U9(!jOH-zdaXa|8?X&%pR>X z-{AED&++-rytBBD^mtvwca^@gxSS5JG5F5Bv$(vL;XLx4d1rC|eYWDWoGuGYJ@O*p zET_9TKj|DjTUW?gPV`#4T&>StEW+*KW}&?a=AK^hb$fdArQ6e6(mho{5BJ!+JlvjM zk3%orp5CbzRz8@&Lf`R_Vt0fD!Q9oGxHA_cn7biykAOgOtSd3F2SOACzCtny#;9~G zqGzT9s}1Y-s4Sx0Q(5|gQ`6|+Jt-HQ*>uHM(U#s|p3ZWz^8Fg`C_jJeBD?&p2>$|M zWtXF>Y=w~J#3pP{S+^fOdJ>#|3wQImqQAP4JiF%x$p+=TGN24YSgZWdnEC5m%KB z+{=bM9Js?Q7vlF;+ho6|_W0Wu_XWQl;a?!A?1FyJ>gNg|%N_{yonaz`bO_w95vG1B zp5kNS9#dhGXH5MJ^?4*uS9Ao{Lvn=aPI82)jWMP>T`W)OF(x^dkF4Pc3P-}7F~y6f zc)~1C_o#{|dFF{@dCD*6KQ?e21WK3gT=uvcCK-Ar8G27+0O9x=CXVe%A1E>=8G0sp zvZuv|_^LH#u&-Ku5oCVrqHzp@Tz6KS@P5NU;~oUbE&{>2!ut)wuf|1=|DU`E+r`CS zl`TJXQ{A%9aJ`XlQMuW#=$Qi5HTwv?BaZ5v>Ym<_F5f2mbZ)IC7yIi8!M#~t+z}t(w-gTU$-f-DBH5!k7AYNhrHutzwnUTC4mx=XImCqgAkwxv?AO-NAGBkU4aS zT*zEIL@s1b9wGR^$WQ3%-PlY3fx)deq6t} zVNDixo#Te}Nbq{iaI8T>(mHnY<8B%^M$EE_tmZa6tLEH#jam6DC=jhZ3f_C}WC8&&1Q(gE7UUXX0t@%RH5Z zc`7UAiDbwQoHsXMP8Tp(KEzia`GR9#rFg%6(KrTS$CyMB!(XdB@r4-WRUlYb_-mD) zkBc1tKY0(f3$0bGvgLu@2^)#r-GgA{}eZ`YYdYmTq{ym!#P- zE+F1bjZy3Dd;(K-RO&bZ~+#V;cEpqy8rY_rTSQ10|Zrj#otd}a5UIy zuea(uiKl$?ILI=;btk+0mf*igNZG5JDjTg;B3iZ|{QWx@WAJyJTkDIzCm`@e9G+dx z!Qa1z;s$^J1X&&vaSCjN?;*Cg{DW=pkm2~w?&0~Pv$+4Q@09IxtFje9KDkZMyds^- zH+eW=wijbdCd9T@J7e3Dp5MOow*T9a{>ufGZ4;=nQHRJq1=*2oN6)x(zxw7To>jm4 z0sX4g&w?U}uH9SpZr93(9=f(|)x8w~T%<)^Zcom7Fy_14(;$y19pfPQdPG_6?cwgR z(j!WT^_EsR0TYMkm<->(NpWg$6=gUf9wrmnuhlts`#TyBdH zJ8t$8J7YE!J6`%*MA(1A?N@_5RFp9Ns+Di{zpz@JK9gOX3j7OS2K!&$%&KhYSKWr1 z<42{iy?qlyZmo0h!P#iNhMEz+OTX4Hh0oSh=AjjxmKLcs|Jr@@wJ$pQh`F`T$;?G| zWxm_~#KF-KzKh8to0_o-8nX4?S1psjxw0WggzvWTwO+`1SL4X?Zm}XonVM;59q3#1 zVwjAv~rF=ZNx$knjBKqn;`CZ0anevD|ZjSiIq;OgX8@ zozh*09m$Ef?b0hzVV|+^GktSV*qZd&o|i@rw~6&+mn1@T4N+uvmS;rnac@?5;`E^P2|eLISBds8iLVvYj0`M$U5lO&BXG}&6e z9giO*Dg-W|aT}4*ca$;fNzF+u3*Ags0bKek&&84%!;DV1mmFH(Elq-IuuGR`NyN6b zy=}A8o=q@tQ1(buk?zp90b+QOdG^~)2iEs#=>87%CXj}KG)$y1piIJ~j}C)F8WL%k zNTbW#Lmv0GfI}J*X_!c(P_+p+o~(!ckcLDWcBJvdZ^+q?9g!ELA(4g+X)GPR_;Xa$ zxkPyd$}3RbJ@d+ps;J_gq;QK+&k~%A=xvd9H=9SIufX( z6gwvlC~zA3U}p(C3)p#0>cfqyr2vQe@IrkE)W?}7E?<3uQ0K6{fb9irA8kcpTQ~Tm zK>Zr1UxE6q8jvV)vt8ieFB1MD;4dXU9ZuDF73vNCBH=Fr{_-xz&iEbLAdP5&8H_(4 zjFC$xPCGRu&A9P@fa^Rgf~fu18(E^mjJ0vf&$pjK+_ejP8n0$nmmAzVzrU0@_6XR| znB8!U7{2kc?05ZCa+gM_R#BVDUn8=Z_N9h&KO**IYIW!IX5@KljE!RHwa+q3-CdDo zx0?qOLN4XIi}vwzOZi8+7UsF`Rb|a|TjwUb5@CA`aPy1w5NY}h zF`s8SICW5=o)<`N?fl+mnyGE1>)dgpF26i@<}b2KEKghO;Z5a^iKn9$a?kAB4K`@x zb=AJ$ejz!-D^jHIKbL{q=(XNF-Fb}t?$sp2PhT1O_BptfTguxT#2F=$?rkvk z=9ef1)`FYmSy9xj647oe7-Poa3MoHr1h+8$6XSG@6C(BN)06Y2ed~!jl1(ZW6VrR_ zwl6!gV`KBydEReDUUr*1#BvWqL~eQR=ECk~E-&PH$FbL9L-FzE>??ykYV_G~7o2Tf zPzw-R|S`xejK9OW(3=(d>d7sWhUc}s~sZ8BW-05@~*VNr9=Cc}1VcH0wW zTg9yl4tcgA&k}j==@H?>ks9DoHUnj|p=|wfrXLhN9ysLLM4lz`-0AqW7>CjJ1qM0D@KfYjBF`rB{4weX z^TK?T7iE(un}M?3SUa+6a>SL$vqYXvMa{U%@7HbUug$RFxgpne7Fw_((> z8w=J42j4Z|y8^!JlQDLY>;=HV$0dB+fRA?=dT3l`j0*zoNTMAHv?F9OWsZs{8`_aX zI}&I|AH)QY!cUMF__KsR3;44fy>eLDXyD+_Cj42zpZ&)?K2l>EIJ5;D+JZn^*tjTi ztk!*@4{gSdHY3nx-W~pQaqz?l-@V}D0zNL_<8HC*Txv|~6|@BdZ9$+d#A}}D>3}K7 zAKI#cwkpt8Tij3owai;^Xwx>dX@NGK|CGCTPbvrc5{bSwy3+#-(M4~Sd=u7Uo1l+ELKGudl$3&ka(C0+Sbm3KB_=b#MDZLmnBdKiu z?d)_8w-(mgPgsi^sPH3p3FcSv_G_;6l47x%RXt$w_BSWTPYED!l2W} z^E}yPtyEp-@66P63)+Hgwq%S^Eovh@>BYXqdq~dl8km{u-upI-3Mr8ARnAa3=vamHB)9&;XycVFsr|~gjUzT@dicHyxE<3|6iX3jx*0jD>D$}Y zF9>Z*ZXTA_XjH6)F|GO~zs>QUC;kHaRd~HlY+bY1{G;8SPrU~EKTHidw>wwFn#JB` zm9mG=F80a){5JB}XxwJ8En`I^!_@UpZw`DGV*$#$plwCtDaw*^(94czvMl{8D!5?_ zE{JB^YRPEXQ#D*)DgG&p`(kmwrXu^qLuRQe1-iy98u!_Da0SGAA9QC9^7nOoUb$>ee)IC?m1hQyUwQ?c%u-~rT$XmV*Nlh94?GPC zKcpd$#%`ohBuV#}-!T^z$e%#|4CJp$zh==>kR0k`7wW@6eGDG+ZD2I?;{x?zqCQO2 z$AF5@;ypyV0(EJkE^VmGzLhT~iGutI)Q3cU7^shIjYb`fn+kbBeMr=YiTa4|F*N?0 zW@tyKONqKPP?zpwhk7Tzg>s-iBU2KqD`A<(*kYU9{aXv zHys@M1Bw1Xpg%Z~*F4jrEy|1jz(ju_&>!56bY-(oByeZu&NqhL-7eRkuwPxA@WBZ5 zlQK&s7vX-$E@#cFd2n)$iqkO%kppWU741A%$OMbtt|(Xa-EoYUvf+h5VS932cKl}F zbfI|Nb>z=Qjn~G^XQ$ZPfGP)N*2#Y+dEcezf#b+aMBkla+2-RiL!$~o zg}ZwnLj9T#;>_?mwbWk*HeGgUl-vH{LC{zFaDbU{VxXL#d+M$?ucJ>v|0n0jZ04s( zGi0V3E2mXG`~J`aaKm~(GS_suB>VR(xuoUoA}g1Gn_T<3sB$dOyjHNx+^uCtT*jPQ zE*o9RxRbhz`ML1?@sBeVJXaLl%88lGt+AJxUuu6Id+ElCb1}iKJ0HbXV890H_Uibk z#1ZPBX@q{w-@meLOM<9!$HR^vqC|e>>x;4lOiJUmW6}({HCNu`&D`P-MPDL@Y`kv2 zIpwh&u_FZSc!pVANc04{4cck@-()N;K~>{pF1)EbHU^;+#&OimPu zWVd&V-IC86wia#GK6}kFS@UKWIeW#ykE6EMpMC~uj2b?}T=X%j>~W=i<8}9Pt%*SS z8_-#1jxGWp;^8A0ZdlWs&T*-;h2p^5==R zMy#5IyhOgVNY3q*P*!|?J!tH-1UqPb6lu~bIca`ZS^Cw%({tx}?&<+<>hsPrZ>JtI z=7F8FR_=RnGA=mpFI8oa%;RM4B|QUguW7#TDY(^lTbdtyFPYODM;X)bT!DKu{%%=? zKK#=~+mzU`{rcVh@&Z1wE|D}P+Sk2D4sFEh|p{C2Uv67D37sX>FG|%i@r{Y{E3Of^NVhWeQYU@?`WQ&My3eF!OnKr zS;Ed8Z+u?8>pVEv*?^r**tzfE81fR@zCgVhs5b-k)@w=DzmlPk6{t4@^=3!C4H%I! z(kGhR!p0oCGJ4@L4`^Ir|4*R1nVP^?Do3QiiI72@?>g{sS_>S3{fkVAX)SC_UcCVSAh&Bp!4m(TO*@T@Z-`gMSHu5K7X9+voVdr^I*IfES z9O_M?-URCHNYv@kb2SEsdXuO(1NFB4-Mn{+ZXpe{OM!MN&@P{RXl1V$8FFZs0_{?u zT^@f|L)Jq6B-*)wb}rD)7gbMos>WAvXy*d$T%etA9#!a8-Q2Jr+OI(S6==WFdbNLA zn)Xo8eg)dEK>N+nviYAS$Ad%r6==T#?YDKEVo7to0EhM~(0&ElZ{<`q<`+u<4*jly ze%C<1+cT3#-K=lGq2INm-xcV0eI9*TmVGfe^y3o!xPgAWMfq+0GQd^>{kVyK+(19x zJ<-J@Sr352cqB0%85oZ$*IASy6UGIB@knAk5*UwiCY$1)Hx=xH@knAk5*UvjM4fb? z2-?1Z@knAk5*Ux79UAXn2y<$Q{#l}b7U-Yxht-6hu=xxisuuwh&f7#EhVi7Fdr1c!0KhH*h) zT-X;WV$`m^G2g&AW5+lnFwR8&@FDhKj58+2ncWy?1jd=W3%))Zh= zPhZ#yc*yn4pe$gR^ zaoWH*Eig`(j2SbiV;XRnmq^S@1m-1mwylqrXDv9)OC;tc0`roJS?nvSVIFH>o?~L3 zBQVcN*XVK5zSz4FnCD2$a|Gr&g*%_#+%6hyfO(0;yhLDLa&5{SpR)D9VO}CJFAonxzMB5?qxBn=od_8@9i_LG&L5!C#(=--k z51Dd)t_eZsOJ|;XD8l!hWpl{@YU^{~ZNKPrXZe8HlV{=g-a#VF`MttEZ2VYMTFf?fX@^s)9zba$< ze7UvEU1Q?J>(Ni|LtJCc{Zpds$Om%faAp(`6A!(8gkh3OeOv*W-NXU zxt4yTMDnI_CZ)!%hDw9 zoDpm9_~qc5jBR6lnmkL69$&6v{A_aAy02)2!+~>;B8}~H%9uru#E_fn1b9q)QGPheX3N$rrF82(Nv?Y^Fk<`D{-fG} z+uyU9EVMov_SpMGS-dyFr0US;?zUZ4YIjLaSTi!m<(*aM7lQ34y$O)zvwV@WOH92# zVpsX;@B^7(_!K$7^Res@Vg1q0EBCKM|00X+$ZGEPy&~siOKfJjzI!_A(pq~vN2==P{EzKM_@`Q8%}Z8~$syuS>ux*z*Wl5gbFYeu{K+j%q8YC4xy>cj>-f!$ zk>qX@aQM5B{r%$%wn2ra_zrv5DpF2x+o~MhU4Kt}V|>8Qp^3hoO!Nxe+K26on>%M1 zv$oD1H9F(yq?ntTrFv%->({h09}VmNyl|fh7caq9=IZKV$H|iRivjy0R~+p3egWhz zyLA(*W~?^PChdOZO|PC;(I?7;Z$FFGF;aN>&WL&JUa$SGw;^{UQ$Dew$p@oSzqXg= z^o?X~JF-WD%jLlN{#8Ykjx|7fxp>xFUZR=_JB#7#hKs(_Qkcun=4%wOR-HRE7npV? zifFR5mYFh1saDr2rFzv3+`1L1jc4n}m~EEF_L-U4_X+uK;VS)PpBOh~twNE7ZPoj& zFTmxl;3DTN2{P~0J?WKkdZ|kiT+5ENWu;s_WWAfyD!1O=V2dBP>E;^g`RI=Mt<}NS zePz{in45{I&3t72G>6UUx01Aqye0cR8l&p0swk(|Om7ZPpQzl`S$+>aV5{n%d&;rZ zddO%43U9COU*P07aQ$ACkz=kFu-~cEZB;4%Vej^VOOZF0oE0%hCeAee&z&F!(?i;rk&jqweZ7mzb+uCNXN^Umg! zGb=|N1%1e~K%NccdDci{Lsra7B+4dGHi5DQ&MvdGJl3HSnk%Cm z0_8AJj;-li4@`U$9Bd_ED+9LLd%4}Ni~<~NDqvFqo0@xTMJ*Q>?Gkww$g_bwr^(fK zPr~M~3(6)?Hi5DgEZsIs-W!lZIRwh#g>qyv`_8rIgeZqVIqWD$g*$CFe#ZP%z*Yjb zvcXohb~POk)e9VKDqvFqo0eJE^siiQ;LsLqXbX0kAX(4BCf8`>>;Zd@t==@0}fE1=^rQ8?>Pfe%S0gFiJDTMO&3-sc3B5G^w|P^wm_e~|Ep(}7Wu)UZ#U4l3-s;BqsG70 z6XUOme%wGmF3^wP=n!XXKdi;==*I>6ae;pP^Yk3vKC@tZ^qm5Ir$FCX@=K-bl?H=D zA8VkG73gCtN6FHyF|~d4*#dpGK%bp&a_wT(uogEay;&^Kw+r;`N&A)D+HM*+^w|P^ zwm_eqa#Ox+-Fy)jeY=6aU7&9l7t)k$2m1+(wI;?|fw8tz>RbLrXM@9-EHNevjL9`4 zpG;nh*1s4-?HEG^#?Y>5-{vef863u117oegSleh&wB~iMfy0>Wg)v!ROs-bNEnf?i zS77WmF?I`#-Q_P|?%xb?4a@~3<^lq9fdrdoWG&M@!uO(>Gf2!C1m+B`an>|#27fUy z2a%YA2+Tn;ex6;bB*p-Nxr)SGMPRN{1b-W@+YcP(B@*)zfq6-u3VQ~&EQ0McRE~=J_`=01Lj$l+V|JRBN_2^rS&nbH>Pd#`e=eYLI`G*f zF=|v&+0C`@tzM0Gud%^?C2E`(Gkf^T+DRA3dDS-g)>M`L^4? z^*L;{cT7n!rr8ELV1C6YU7L(pnG*V%w4X0hwO=Nez5Mp{UV)wCF~2wObx$M`c<+&m zmVLdHC~xCQZ^11(ox`|!=8;@ma@*a~8G=TE!`^=e5i9C_nQ7zbnYD9oJ%~O+j@$WA z*t{djRPQ_ZM=oCK2-$wvh@K+z(9E*(iDyg37M`{v6}TZoVi;?NJdnNv7c8@-jJ>=+ zxDj2y*-lIzB!|XdusC*9pJlzkP3ybc=prY`22Cr?ZknLOChFT46^~&~s})^lKeGCd zV)t_$s0eOJp9=P6Rhr7&`NmEx_+i{W%HQ;bUS|Dk9c2A(y=P^9R&@)_6H64zZyTHW zxb*Lt&>k~V{K(&A;>4;y7I_hw zCjKFsE$(Iy*Uh&JyY~Ug-A1a0pv&(kgF>>6l-*EjJ)W`J|l|8Xsqa3F{?2%>s>iEd(s*%Nf#_k4X(!J zK*RNYpqxGAOu2N?BTm1Bbld)Q(&!dxvfS$4G5)Xw)BWlDKjxuqqEn^~=9F`D zWuxo9|dIr;aKSV@_b-*{`rBS?%LzE;_YE zZY{s^`>DH=hLT+7`%BCuUEay<)APoP|0doLv{ifF9R2P0 zkK!X9(Kx*#pooZdVw*X&QMPgYa(}wN2i&%ruZ&)=(%3(gK04GRLD0KI;C2Mov)xX! z$+qN7Y2R7Vibq17%guXR8i5(^*vx#z{SKwP6!}kZ%S(+j3b$M&QfFx}zG3Wr1!=5Z z(|xtEoa?nowfOlWH#RKfSn z{K2I^VVp7JAKNI_{gKA_I-~WQfj+CUErb7!=pG=pHmPpRJ6--$<^eC0=YiaeOJA{n z*uV&Uclv()zLQgt4e}oDAQmT#XvX_8aqqn@yWe2UlPSkt5djw$n>+mjj<|K1dNVn= zN=6hhv(YqjUZg*_e`~Yt9@?N-mb$euyjwh(a(cgR=Mzmk;tpH=>m@5>c-kgQ>OngbgPWSVx5(LIl1%ulX{%O6#~owG);5_ZAQcxlT*%J zzE388*&^5KX$Akn-zJPdcXyVvQ{HhrHt1#)pc6UuQV2g-_3dgt--&%1-> zG%W|!mfg>^k=fSotWs?CtAo_X4)2;$w#~8J{FuFIgW2o7&!NqTrhB9u<9^M2aV2Y| z&5OLwZvZzUVG23)!FJp5)9V`gF5MCd{k`bX%2!Tk+1`F^?fIG>3u3&d{(i!zow8g1 zK>O=H4VtxBGa(3Ll$chthfLBtsm$W;-D=-auY>8q4Q=*Rrv0#4)*Y6oe%!;`woC#y zsm%`aany#g+U@DhXI|{PZ6@k`RE3kWZ?6aD@I4-jKCH_6@FTcMwNlHv@spTmiWity zVatarH^KF95Lxzp-obo-r^m`ft6a}r23N4_LOHi`6LWuu6MGI$OMCYApEjHEIQYQMb#S<2!M%iSM zgmI<+shdWrj$0vGYi47s*`StDcP3#X@!_Kbx&oH>1c0lD_ebMyA<4EMW_ zI&>)kxby99$%Pxv$dvc|uN?Se-4U8o*E?sE%gXGL9+%EOyEgve;rq}By9n4tz%EN) zc$O>Q6&&nhz%BxInb$Vc$g*w0!KMN>6|m`SuYCIoUj>J{6sSuBb-AQe4`6ZmigNUzV!i;0FSJAm9fZ_ScME_#5&99}@5(0Ux^dt(}*^SRvs<0zM?*L&x_u zJzkpT7Vtj-{}b@PleO9($sZ9M{6N4DZ198CH@)9R83GP|Am9f!_`&>nHM&QO0S-PS z;6rx!&|=^E6+Yg8@4_wub`h{k`l6ky7eKuku#13Q1nd$oUH2rO$-u#;0yZ^Z)1(u8 z3TH$=E>M>Ob!nh3^PTB2BVH|Vs7rymG*FkNGq>Lp%LWd9Am9ha{thQ?McO~|fWHX% zkbn;v@S)~g%122L-w^O20Ut8pL$x2*`kobaB;bDn{%64d8b_&hK5=Al@B;xqFyRMA z!A{$r)dmMY5by&NevqSM?>}FS00$ou@F5dEl($j0W;bCMfqvYEe%wGmK459&+$nN^ zLqBeyA2-mC_p6(9V)9wwFa{VH18f)r26@KI5j{3Ij6HUYJ$8&egWCj|AB%y**kfYs zv19BRQ22JH59r4Q#w`=$mJQ?9z?)B^M|}(qW1hsAXJE|hFy7uT5yo?YF;8O5Gce}$ z7;z#}QUe^uONsH)hVio7nFIGD!*>P7EfeFGiE*oU{=3sJlm>@!%Z_o&#JJVB&xgQ^ z7`p|=JQHJ{#F*E8$xE+4i9V^Twz6v*c^6*-gw(1?Hy$^V2u2DvxXhKQ%G8 z6`0!!%xzyZZeXv6Jqi zfjRZ%dFcxGf{&Y+Qwz+g1?JQbhvsS2V;AZOb6Xqcw)Cxi#H3M&4aS&P6!T&O^J0N{ zu}iMxT?bMcm=_zE7YodbUp;9!eUuDe6dIekw3O6_}say`5WDEeQ^DTYzW^4oEY;EMRI6ypMm zh#qUt#h&5qStAH(U|lP*t`%6O@;{|c;sn|`$KDnN2rCrhl81=h)J zR-GtcI2AaoYfY?c1=h8#7CxC)k@^y>f9+WR3aoz{zIr#h-dJ#0C!1I&3#^mt?Y;e~ z?r?Beo0?dg3am}@zI?T;C&^(AYhn#6u!gm*yLYN%e{fjq+OgIZSnC#l^YK}yk>Ic< zHn1iZSQEFt7;i&)n)_hwY{S}FVC~%XNaUWyFdhl4u??)T1=iS|_a{A7WHaWh*gufi zKM>eIct2@jzuI@;L)d$e*n1Gzdw3Ch#=UYwF@MJ1gT&s0z}|za@AP8j;=z8{w~*Mk z5ZJd!H8!AR4a_49?0HD+c?j%zWX`-{P@@Cju;(GM=OM7?k>JW&Pw&Fuu=ikM??GVi zA^FbB(S49V1N#;d`xXNG7V(oGDcyYrIP6{|%zTV#BEET9XO1A8qJdo2QcEhW~k zEmp24IPB9%?9&MB(-b*=l6-hOG9 z2^`kqcC5t(*5WIAf2h_N^8<;sxQVs6z*>B*%l&3eZh^x(USb_Du#P`)<7Ce^OJFPP z0Z8lt2Bub%T%Z##-FOT3lc){_V)aqXW@Tnpnr1 zSjP*j-eBvmzwuQJ2$cSAhGu#u=jB3(fS#UFprSfw~*Mk z5ZJdk6mL_++ULMw-$G*FLSWzGbgHFGs-jJY{HDwL-4Fk!Cc@wO84Ul<=LvaibXBHYsCdiVI!9s| z0`rXNS7FN)pF_hWze3{~Q+`$|KBtE1oPbpt&zSVDR(viEll&TuXAH{ve~T%f^xN09 z2!!c8f^`ZL&zOEsM!zj1nLHXM`3)M+nDQT}_`Dj91H4h=8I%4^iqEHElHaWHj6u0< zQ9S*Qk8xb!ts2ib0=R98hmSZg$#2(q#$?YOiZ7_)c)&X~o-yg)rFc&bll*RtXAH{4 zu6X)=E#vsWrp7a--)>697uGPz@6mY1l%KtdFQVZD!22|wG3np0_@Wvn`2!lynB)&C zp3ay4U_zz8qb*Ik0{=z;Y7fHX*}a-;EpQZ&@jm#(|E?@pT`w1 zG@KatgvK)_{U;S)T*D-PO5+)m{?m#tq2VOJXEdHMofC3a@g+4(^5-<3G5P0t#h21B z_Gw%$Xgp)me^K$JHB9oCG@dc(zpVH&8cqg$MdKMq26t8QWi?Fl*EF6n`R8@Tm(y@^ z;2RpxnDpONe0dF%{4I@VO!{vtzJi8R0N>Gg#!75w&zSVTQ+zEArvZMi@r=oT zJ}ADnhDrXT#xo}QPl~Uj;k3Y?HJ&lm?-#|_)iB9_)p*7v|4s4rG@K6jyT&ty{ary@ z<8OTpL*6CdC_j7dJP;=5}Y{_C1g;~A6v^DDlG zhDlEWjb}{q1r^^@!=&F+;~7&u7E*jK4WoUy7S?#iBws}Fy)}$B=UPNziOoTks3yS?Alo4 z8Iyby#gEc3`AJiaXH2}e;zw(k^f%LZ#^hJc6+cG9X@Og4JY$l_IBNC7V>L{E(n{kQ z6OVDxk{_pG(%(ko8IxaOoU`P|Yd9TnJB?>d@))-)`3V{(Kk14{(G0CIfxAHSt!=xYmyMt%!0UrIh#ZS>N z##q;08qb*Idn4jb}`L)lc!$HJk~!zs55r`2mWbp<&WL zP~#aBKS=R2HB9;kYdmA}D__OW(lF)}u0u4QG06{A{A>-Aem{+8Og#D#%l>mTO!|jw zJY({!5sIIy;Vi%-HJ&laqn%s&=V_Sqqdhx##>AuDTKs$slYX>M2hW)N3hmJ17igI3 z9qrA*GbVYoD~tEnFzHA8aqx^u588>vFVrx}qdhoy#yP>m?=8NyhO+^~zg^%jE+oU4 zc=)kHUdQlPi*ExN9m6jzzAbphlotHY!86VQ9)4z}n=1^4KRM(XlRW&!!86Vd9{yqR zlpn@ff#C-Zo-y&LZ!2Aj%Q!DE>eZ5Or(v=K>d%rV8OFr>Yw|iqeOP+XU%Kjek>Wdm zXH01YXguRQ;1`3ZddU|CFVW-~ll)SRXPg`SGR0GV7?T~AYdmA(SAeHj;yZ(9Olhstc*X_5uLn>0^bCVHX!49nK2YNs z=Lf%0@suCN*?~7{JY(WFgQs*UF5@D=Taq?<@KK8ukQ!pyWx0G4T&Ic^yAe`~b-4__5*#f@e%= zJ<)i^Wx+oMPx&k#20zo}8I$~Tjb~g2{0qfXei#=7eyQ<{iGKy2(xteJD*?Y&@`E&7 z6!?vjCmF`Xzt!Y*9HjWckkRow#ruM1OliH>c*YgMe*jPUtQ-b^)Z`hH{3nfPTmk%N z#Z!J57XkjF@r;T83ZBxXxQwd-e^c^9H0%ZZUCEOSWAJXEt$7aQLt$6N4+XDd5=w{Q z2c9v-jiB+2tAdXRJ`FuG@fx4@R1cy`C(iPIEuzICO#^7N|)j?t_d7X z$q&rtU&l+KHTuq)a$;Z=p z#wEbVS3Kp1u>ek>@r;R22%gfVxQuH7CsOhwHC!4vv63el#>6Ml@uMK4<7A2- z4W2Qjm0aT)mj#~!Jms@?7@Sg*XH4>`G@dc~5VzEdr~EK31?-{mjESc-DNtO-b%4_< z`7s(s-{_W3$&(CY;?ryLI?kZ@v5?VmM#YZ<&zRE6r16Z=pSWcPPx-4G24~Ua8Iycg zjb~f|d^W{Xei)Yn&aUx{iO&I^(xteJ>jCFf^5ZpJ890}cCmF`X=hozPoJa8!Afw~F zik}FcF{PDH;~7^4pC3Hsvwj#{K$B-o@&z@XaTV~Mil_WAt^{02;~5iQ7(As*aTzxN zM&E7qpOZ9P9k{5HCmF`Xqc3yF>ll5v#s2{r9orN?89ZZ3%g}hnxVs7Pl+T7?aB*)Jei&B+Mq6^^lQGGo@37J(8OBY3(cUciDH^T;jJ9pblMG|x z;foG=9i#18{8Y&382)PU)4(&Pw9qyjJmbdTQI}S_O~YXLu0x(N$)mm!^n$UdnG?t!>Av(4oaS67!%)7lh<)4 z#m|F`jyo%UK6u8IRu_$DOg8BXp7IGBgu>l4dB!B)UE>*3o%T>X<%cnR)2*k*GbX+l zcuJSzGKPP-^;Yr=G)#S?kCG=D#>Ds0aX#P;n!{hz_WcA z6F*RsXG}I6r16ZYP6sRAU&9T6eKnpj@k78Z$wDxFH_dviZ>U!W>!I(LnI|2*cTL}kI56>ew(>I#82y(6&rlc~ z?`d1*O09U@L-8!1O4E}P7|)hY!b(4Vi*405ICeug;SW4G`;B|jIu!q#{0OM`jB z4j!BX2ZZRMZ{Z#Gr+R@d%U19w$Nv0AVDc}r72)|x26td~Z()`J=a8YYC_UD1EOsb)+?l6uwfJuz z^c|K16OU&rU22c2?DU@h4nmv*Q@OG!dE7(sr~^w+R`9GR3oxE7p0MIwwgHphkll7^ z7(6{&^5kRi2?s{ourT?F!t~n(hki;|=UJZesr0z)23GmEF!Ni%qitLIDW3}eKkU7E zm>pHsJ$&zF3`C|t0?H7kAjlLF=I*MFfdpg-5T-B&kOl+{V@Los2m&$)3W5O@1VI_~ zeFIK7L_j8k$S5GQ5GDZyK@>2*wRY`wZgutUYrW6&egE}&a-Z5~@3q$1=bSoK)%R9a z_$-C)Poq!2(U^^W(eT{o-L_|9ep2{pCqI12=6(ncxpsWh_;X&|&wJL=?>l!?Y{aZx zY9ha6bL^l=U;3?w%??6hF>}x!A9NuwB6sB3)}Y-KDUu<`1KqIeND`_acTeBZSDhZ z^VyN4&vwgx;hCrF@L3S$Z?^oufghigr`rwsk+=D2&n?+#+x+m^?^fI&xbG+j&aY$W zOE%{h9CB^{)cA8=+|PRq)9+t*S8T+rUCuA|tz=^y&4w@i7RK?}r10BV2?Jlk%x&v% zUedELceVZ0&~InFpE23=qi*eTY{5x3@-~|~ve~cA-H&Y_zc8DXbjHF)-E?TXKF?Y9 zdmP8`o{|l}p3`Bxd9QP6-{&@bvia;+(r3GlF~9K4({=c)kMcKLejGdXTORKNmCfhR zbYCca`i;-*`#qm|@Vjl#v1$L|K2!21oBJU+9246=HU69z_w%06^!wlguu(TW?LTB&>u9voOJhpxOe{{|NE%>Hi(zI(IwMFiOC7rF@#y0s8*YAwn>UT!Q zlg)m0JD2vuZo`-CF4*APKC^YjM$Gc$m_O3C)3Z_Nllvvdg^*b!%$!5RCJD2veZo`-CPs0Y^#%El`M$Gc$zVTe! zPS2)sUfj=Z^Z5e9t$xon{|nCLekD!X?x!!=%*}Q9tXm)3`@(1P(r>}Ek$1}fFK%P2 z--x-j--6dHc(U!8U0*wV{;%v$_6;SSp0>^BdYhYCce_Eq=4A)iZ@VVuGu<;!+x^_y@9)gv9en=bn)JKf;5Er-+>dP^zc6>g z55CRI{E`j7o{^-6e!Dk&N7uwQ`QL^8p8K)Y@A!--oBf*P7~21I8@^=k3|l%oRcyp8 z&lll;zip>yGhb=@8E^i}^|96c0OtR+o66KDPIT&!nb%31}m4 zn_uStf!o;X9s_ReUINY?{U3Qgw`1$aKyJ(aWZwZl_@>YCcbm_J>lq3@(~#~@cndb_ zHg2^4<6La*{siW*0N*{rZJO}Qwrjjy+>dS9pX__uI*m6=HvFucCb`YFt!FE^m7iPP z=fJJ*b1?rx&Sk&$XxqZjm+al!I($|`nzYk18aTGt{SxSV19n4e5L@}VZ7ou?#jWm_ zF#n>3zky>((u6GxeaU8SuG7GAqHL=#4ID?)y%w}dE z16vsSWHg)@Btz}F0a&E(y?k#z=q|bI8(|}*L<>@*N z9_Nv_jTLO^^ZG~kqFA2890Nb=mJfWoM}=6s7lnB)-?kfn0QMp0!WM?UWIs@FEC<*c zf14L*(a&dw()}$s#+Pk9Peh;H-@+VdujqM>XxnzZx1ZKI*os|^QWEse}=tUq0gLU+jSA@ zmJi~sktKU|x8bwoj0%{B2&KWn*;+Fl)HZ2Yu}(VwMl$ zcK;9BC06(U&?noj_YQWQ=iB}!dz2E5K5O8RWqF??r+Z00MS#z*b^X(#_*V1KI6XU?+ix(Id42XWow#JJtdg#77~ZGW%4 zP~d4NKYYo4w%}0H{)+)VA$7zd-G`5!B!ah zlYJCyaBLio1RizS^7ER{R>b)P_O5gC^ zg$|$B)O~35vu^ny-pWdL?lye7Cylu`k9Qqx%l>2^*Vbts13c=~r!D=)JlH+%U$|}4 zulJBJ-Wpe6%>K07@U`4-++WgXyCuJD<|`e(%OvFwTmHuHVUI8LEl;=UXWhmJKHVcn ztlbN@X5o`<-yObL;Q6;p*`MsU+Byx`8h@LYZ9In)ftld;lE9#DV+dP*Zd(%zKexKS z&ivaIe!Jc~!MWH9Lw~a0ZtL)!E7Ih3sNTWCXLEIL9_{9I*ThzSZgrm?x4KWy{5v=v z{b=|vH=1F~RJ;Td)$=LmV7=PM&_Y1f3bKBafXp39j?`Qse98_v&z4_9y#Y z_`x@Qj=$S{Pg0tfQ{dmtF-yaby5V8V&#m2m$Q&l)vwMLtzuR`bcd~P_6~?apgn7TM z!*}XPlh>ho$4-;nJ=!{YR+?M+xz&A)-0D6?^Y7(c^rQKuwk-^O$^K$nhtFP1leV6@ zw*6#p*TFuccl&T__epY05N}N>Fx={XNb~RGT@J*lN?{)+JG%u&Ye}H3# z!H>G(Vaw00-Ji)E4#a0_fib_^cD*;N@Hep)#;*N@`LM0ScP2@b*P(icl5r1e>*(2b zZd>l>R`+>w+d8Dco8N8rL(j9*7KXlLpV8Lgv+~lUt!LzIKhbp~_8GmqiCepObj@Ph zI@EK(R`-iCE}Q#9(&WC;>wRPnvYDIf@Lf=4JN1R@`Y`8my(3qfFXr!lZgmeTw|3tt z^Q0fwf5h`|m$YWNmP`I*e*i!DrqA(ry8(Zim$TsioMT47kGkPu%g?Rdzsekr#OJ62 zV}7^odhbl&$wpW@d?!}2;nzE|_^txo`$}8yBH&hjZgn3lx4IA3{L?%K^h56- zV4sAcFWKj`b(&x8YwMi`wx1m1n%HObZZ2-^-dc_c;;mx~47a+U*8Img7yCofI(!#}G->Ny6Skk= z*loEj4nOuA*>)c?#{_ZRd(5rwH#R@cPlm_-kTkh($j=;PGdJ)JKcugn`oeXM^PFM0 z-jS=>%-{Xowq_N6Zd*A15@UY1`8P`wYuLD4%O!uZ7i#O+_(RL^@E7yaepmKCe~j4M z_+Y*pn9urU@uQX*2{d_FpGDbY&)pB@jx|tO{HR$Y5#v77gO8Q*(|9NwxGaA3)R6;6 z|G$kCt_ib#^J>FB@=*8H5!&~Dx(!K#(##rEM;Cx_p_^r@K46z#)F5>K-Z`7-L zym#DUgp&KIqHgz;yU#GxLq1lh_ixX2}Pe_f=brZsvzRSbp$ZVJ^gwcUZ}HNm1{ocPX%p zu}}}^UDoX$c=ypZUU~dDhn&0B2tr}Iunk+DU-kj@etP7gEi2?Q2e!Rx$p@SFsrShb zeX{)Ew?Zy4E}{=>Gffn$T!>1W{>z&7kg<|+C%8#d}yJ>Hvd z_uCUnF8cti-LvmL!!QrzV}-cu@Ik))`U^da5l9?4!1mK)f6L>?{MdG7KI~o}##pGw zKCpfh9Vqm{HXi2F3VlDoXMOlDFI>dg^8p-p##o3$A6VxcSRsz{K_2ER`MzD$`{{iL zSjJeWw_Z`V=L+0M+jz*w3USxEeU)$NgKa#;=pzU9svfay%L;Io1M63}eY9;YmGeWN zh^5~OxwOd}TDWYiz6<*Z#8xl)XwQL@tNb=@ENH$p^c6B|c?6 zwuw6ZR+t}b!02KfTovD~(@sEyq^#TN7Ny zSg5yjQE$R;1wPuAANrSk9OKdW@LGk1T-vt)%NPrNW4sQ(75ZosyNG!VXB=X$DfwXY zd6GVQXfr*FLMZeMLtc6O*eCRb_w-s}yRZ#g?k~p=b$f1wK-V)K`^Q4x+Sn3X$**y% z#~f#KMlAeR*e)^Tp?_AW$79^a`247F*;v7DuIVwl$>l!9;~)H1$fZpl`^Q2b^@uH< zd-S}F#T>^rP47B7P{@UCy!8qfeRlj}_2!ZfwmnZ%+K22I$NjvbXFT?gg?d-x1O0ya zt>H0j497JEY`^u!exZL>px0an)=}7AU-Hqu&0}=4-Q~OvzZLq3A$GIEMVvizgL+ku z&+Ax>P;zm;WZj}K3CKyzmFAl`mHb*V#qtXrJ@U|&6>^ya+g`8agWX)$V{}uG zeE^nzE94SG-m-09<7copg`dYU7UF3C5+BA`sK*cM^s}%I+pwFPr{MB9g?d$w&qmpE zP=u1pKJYjOzZLil!?ux+e0*+*`S$BCd5p18j~vwd>9N0P%L?0Ier&rkAB|smj6mwK z55&T6g+5})!+cty@2B{Tg&)@)4UTIvc52)L7Z6uS+^+F!^O&0o?AM1>+AP##4jjKye)jy^h8}aAts&+IzZG(cA@7)ykH=Wl`|0sq!x#(OKenjb zGj#5wZM^dMaSl0mqX|M`yRZ#go?rF>^?rKfp)D)qG6&R~8<%{rn;UtIZsx~60876W za)}{tSlic_3wulWOUE^{?}VQ*7V0gG&s==yXQ2i z2Odx0x5E60VIIgwzQ%81A>V%eC66%{>XCzbKRx!hJbuiNZI8y5h3(S*9kz_IP>+3J z9eykH5koBI(+YjR!DkEjxn-dqY#aBI&&FJS;W!_}V6Lo?I~Nw`uEaGx_Kh(XwmY_{ z+jEKTqisCoV}&@4Z|V4A$2pFjV#JZd@u#1KxzHvLZCRmjE-co$Hd)ApZEI;R9Vqm% z4|5AYU8cviN8Yk@piplNw#Q*xTIXip?J>tSR`5FfR@eqHxa+s~-S7z_2-2h^*2#w+d5mILc^@nIo%Eq>m?j9hV5?S>{(OPt9pDk)nbIQ zzwE=k_`q+4?Gi(M9%ERD`yYIeZ@>PM#~2H7E*_4zN`{J4Tj{r_a6VY(AfCZPCsA*e0;_TcI8? z#Z%ismC^fwdd~LXBhHMrUQj-jK>!9Q=MPKGR8tZ zaER@v$N4RdpFM9+Y&Aa~b3RQm6zZ*5)a_Y%_t7>U`ey~W=5w&nE}x0BLN4vcJw_*e z+j<>-EA-JOc2V;b{e2ELvCo%$u=zd!Ym07j#}{?_t-xm(^2+1KKA|ssrp^kvunk-8 zFUJJ+s-E%Cmbf+_#8&dNXVpqLn={s*Xmbri9{Ohmx!8LPm`CZnMcc;uFKwLdQ>a(x z!+7i;i}bkvy;!)+2fO(aK4m@jm3r`7A(t5PHf;Os{)r~)rSm0i<6U3Ek%M|w&v@l= zz5zI3`{maIKVvM&h4(zz{V6@zvM|3M=au)r`G}nYe|b!4bG`%a7nP0;)#zH-CnyB~FBd;`mP4=DGYJL;p zD~(Iz<3+s*zZK?340-5Z^8FPSF;5jP%Z2uHz%s_d{Foc-&*8&D-*fm7yBIz!Y=anL z-!M<%gU$C@^wFDG)akcEE-~bl$B%tNUm8yvs%RIsVaxsHn4n(OGalNq!ZtYO#8&ca z;J9Wn0@*jt8L_3~q+!UTpM`pFVat8$&vc-W3){w;F&6qT=Ju|QaxS#VWB*vBN9^AU zm-%4x{TtSnh0)t_^r@K46&;eE*mTA5&KTb z2fO(X=hICt+XR+=E6jx$^0sdK8oz_RJp7+&`)C`FF&65PgL*$b^3awQ;_k!;*lK=_ z`5q&XxP`q=KMQ@ZjfehOfv@>4EcT_EAIE?(7IME-)SG24G323tR-{MldnF%izTc#e z9@~Vzz4wGra)}{t79A+`O~MxQQ=MPKGRDIEW);|edYs?V_%(NSY&E}~z-NqwdMg+8 zCj3^I3o+!Of64bgEVl7t;W94mSAb=Vg?i+&4!;%pXcN1*d5ZoLL+rmwKG=L8OCLS7 z$-2F#g;3^440*HYK%tL)LSGs$(SgEtVH>vG-&qB=s%Jd*kA-?1^I6zd@@u^6F~`}Q z5evT+wo43oi+f%KP7cP(Ka0U9n{W*X*~jWsHS-yLcUbEA$aV-fD%*xa1JKpyY$yLbZ<`+XR+= zE6_6xdEITFegC@xu+X%^{9qgJ-nP#;sQ1$&4{cdt&iCL0{c3)VH$6rmaf^7Jeir&* z8?Tg0s|i2*Qu5Jm?uJ|#Vt@X@L zYwiIX^HZH)@+?LuHNauLs%Jd3WrdvG3v4yN=46i%NWE2yI{jA2g>5|aPrlZ|u(;0u zTDXi$`)|N9#zH;pXI6*b3VpPR9bz8C8HQNS9}94_TZ=m1eQc9h`mGR040)%web!&} zrSV4FN1IrS(al`IVZEwnJob+TI2&_dtNHQy_CE8$Ipf^HZ-s5ZHXiyXAKzcp;Bol% z!ezO@wy|c6g6}8lg)z36KK`!Q;5@!o z^1(J9V=T;%9Mr3N#$*3jh`SpfV5|Arx?+rlIIbzwtLx2prTwqD7jS1lZwYK!*bmz8 zg3A~S^+tLfek=6BHf(7hw|6daKd(}fmryh&_|otQr|2Gj^D=&Wn9|L zy({^l55&@M1$wlN_m#G9+!(VVFmG{5Xdr(bm3(GA?am z`^+!L57?@n@z9nPw!s`wZ|>9f(QZ!h7~RZ|eE^nzEAY`a-imEs;}O{7fnBEUGaG*! zSd4D!E$VgpS?GgpSe!?!z}H$97V1?!z7NY{1d_|~1J>S?G z<1xlU966|0^^8{@Kjz2rtIS8^ol1V}1F`U1VH>cGH?nY9yAQ+uG_b?kKH4_!jIof* zF-N^RAI2;1f6D{MxvS{${ayC{FN966r>NU|z1(LQ@{o@ew)+r1O?>`fo`MV8c#N?S zM-J*$J>&Ht#sZw>&;$DcI#9@kZEK0Sv(U#rpk7^X#^dpX1-Rz^*q#OKaPt&x(Eg{# z=%(K4UWeZbeXxzUd)sI43`4!D$M=m{j8Jm7E$Z}JfzL2(8~MoB+z-}D_&ia#j0>As zi_uLza9FSE84qn)VH@l_>yH;MZ3UN>4 z!+uOPk8x=mk1-bF$U(iTXT0+Gp-mgV%6!;6MHpkD9{a%hzvw`r54Oz*=FpJ6m|Nouw7!vLq75~o`luH z=dr?NT-e5AjD>pSpkCE89@?_PHb%l?{ZHm8xUg+4F~&kY_F-hQ%kgI`A>Z!d%WP>hxP-yTmY$ z^7tKsI>xklSOK$~VH0cfNjLR4e!y1sjEA9@jmiDBEwM?U-h4*6F5YrL0AIC4<0>KU&*e$0X6SD6ocCr&v(_JQ?}N^QV49_G^u z`|%fiJ_GEh3YU!^Y#VpRScpR(?0dn=d>HRsf>3~Kt&c70RlU{*9&=n{yP{6N6>^DT z9>_;N``(Z3KU4C-Hr@**A33O3^^AwMtSCR$pKbeS+gf7oENqW`K)t%&jK|{%3vkUN zust8x4b4-G0qq4IqnmnbdL4c%^uadX-fdrNBiN`{^;#Rl#~2H_I~8^Mt-xm(wvBw` zYaR}Z=fPJCmvLbeYcaa12M+61J>#J*D{O-~u>MNnGA`}^c#Ll9u@A(;Z-qYE#4c_g z!&we!yEVG)quu;mB|r3mSo*C%kGAo?*7mhFfsJ}quQdif##ork1x1~HEASbHc_1J8 zY<|~7TSu3Cu!*%8-P8kz^{Srn(3Tap!5mO;9@X~IZXW3|x~a!L0876W_-Gq%)wa*R zzncW?*tU;$lhwbrefAw6>gK1Lde|6mN*mYO6gKKrz1C*%F~-9DIDV+pZv{TXFc0J- zpM8Iae5?I6-Ww$xIjC3ljEA9@i-KE~Up?Q3lf8}+JQs|!BHSg5gUQK#PuwTNLJ$Va~B=V7ge&)*A|abXi{ zF}kS-4(nAtup~vgN=Gsua(2c7z_2jQPkKPAhSz#N@0rlo_Z6EFCF&?9vdh7$R^jm?Cw(*9yeT{jr*|#2SS=dGoa9lHt zu~2Ubd{8&P`)Id%P}vtB7IMd7i+ZaETNc-AecEI0v+)C#ek;Tg(}P-ROzr+<W1$}VfI9tF;IsFck%#$|ukm|W80XgbwvV=r zJ7X-=&5IeEtgWcM$qK7t#rQZtsMhtnowSD&e??|+BLfc2%c<;1*#zDQR zXFRlJh5dLNALv)}YjS-t#zNep_@Hin_t7>U`e%hXZx0Ll)%=>%Jw_n)E-vcyTY-aAVW>9@lE!ZsfICtr)_^8FE8yzQgi911LBEYv%&sMBwSda#YRWZP#P zVs|R}V7GRz=%Gzw>9+zs!;n`VKlX`zDWCIT6Wgc196w;Idd5RrR+uyA1K4VQ&5wDE zK=zk&1}yzn$c1e@^iRIlBv|_)wpiOo+s2wP7V2@ILcKa4#zX(C0B3r{mXA3+*6r#s z0;z{KiKX8Pxx|n+x$U#x46$zPU6OPIN85P+DB;LKy{czCv}J|uzKajA)% zNi6+Vm+Q$1=+h-iqt9r&mTUOYQ_wj*#HNWOk9wU%A?oYs) z-+i==H{Z^o781lZ=_E~?~ zm+El{Jc|*^{J>$os%Jd3WraCojESx0*Id?P1X7Q41}yzn$c1e@^iRGPt`i$LANRX1 z;aD@qLOqN*>(%)%9{OhmIO7moI_A)B?e8%HsfRX+rQZs<#E@57)ApMoj(7d8BglKN zpqd^zs8{ujhqkP+-GAc4<3uGtTUU&+5XUuzdUd@S5B;;koT)tHZ#UT9Ir=EH^2L68xQ@n!kiC+#qpa}xX7i=cY#}sZt7iD z)akcE9BkvQ(e@dK*n>+x*sVhlbzUt-wdyc<7&et||`%*m)f!C+M96w;IddA~E!or*}#?-Io z*IdD4jEMqL-+Wv=nbv}%T{#gOeINbjZFZp2e z{r7$JrWSR3FFv8<5KSh;Vl34A03Tqh z`PsT+jDn$;3^|-bou#B-#kH;|7?Opfoqiwt;=|BO_IK&=XxXcH;b)3f>XU9nB z(Qk!ZV#q6xAN$0wl{`iua5iU{5BjZ;3)^_; zpM0(3Vd0$D@4AFz%@_;yxKE*8oe$%oe^!7q4zVYce6U+5dW>%B@th1j`mK;l40(IE zefFE-;%IldwvV>){?qmu2lc9+@pw*WVY>_PfqpeVTUU&+5Vs~is8`pU@yh$(bl|Q4 z?tE-nz@^>9F}uYW3-$IZ>hxP74z}^uZu^Ww>`5gb?ADBm9@-?9ek;&340-#uea%H+ zuZ4EbEBRm(YcaZ+A2_U6^^AwMtT5+=3v4yN=As@Wka|lLb^5K43)^_;pM0&EusD8| z{F+|_mN6FUU0KxWw?aMG#zX()GtQO3o?P<5ZkUvmifjIpr4oHNwvx59Q|8xQ@Huk|HZI3M#`L_XR!){L=G z?@Dk{ug-_@&_64{nI5sT3YU!^?AB=>qnmnYlUVw#kW0)g)b=S{#5G&6**9D}SfLL# zu@<9~df>2L)iWO2vO=z7tNGblVvL1btSMrv>&hY1%*36+7zU>G}FsKAgC-0_^c) z*2*_nd98#IC&DTw{oZBw%0D&sr7(x7yKa$>-TeAo7;z$9#SYqGNS?pCUoLKhoih8J zylc=%59c<6dC(d3F_DwPAiyP^xO<}}|u!>1v zeT}dhBVouHJ#^B5`7(CkPwvk@`QkHa>>^#wm-NMnu!^Z|Zr8qNgD?m6U*mD~!YU^Ht*(1v29Ce; zBW(V~dDC!yn3>O7Z>C{RU*hb6^34_d^7&Wd_ z=1UlHBCKN4=a$!A5q5{!<8eGYHsAi{&*1#|+kBhdPt7-<7hj(#HsQP1VZGgxiyP_g zwECSmK0ci=;zU@*q~C+%;|43Q*fC$}@AmxjIR0J}Vinuy* zK3fb;7;z%3V$$!l-qfb_w;Fl2rZU$N7$`z zIKz$yQ*~GS^hwdEC8!?QnfBLOhZ;$8VM!K6k z(`CnBVZ@2BibsiDk*;DJj`*7$f5nZk>c24JL|Db7uepw}nlH^C z+ZpKl2gRf>ZltR=g%KyhDkgpPHNt8=NMC)7u!?PY&|Y>v7B|B7`1%z_oCvF!^flKJ zcC$nOjqAxV*l(xX^&htbUGFHS^&xJg%Y1qK6-Jy0tC;k;lSSaBTj@>O#13; zgk@hi|LT+a7-1FD`BU5o%UJRKVWBThgjG!XJp&(qv&AR=0N>{<*8S4l>v0aer~9$P ze~;tYjA$+t>;6yoy;yG#h#O(Em1f_B^W`Um5hubbmh|si>qj_tzZhb_z2?{XeM7fn z#0jz9m+q_I9*N`c)Nbd7SpWV-7;!?Z^rY`&7h-RIbXlB_Zz%meYu`tNSbbL^edmT) z&6o6@6Jn(&eeY|C)%a>W_}vx0p9--a>%MfCO>sVcR$~`pHDA(qPKcGB^qC93%L=jT zzmG@O`owj(o}3q973;op!U$aNT-4oZeEmB+VZ@1a6_Y;p{VQ?oUMj+7qet-j-#dg6 zC&YSRfV~mdzekB1VtaP`8`keng%KyjO3(GR_Cu^6AD~yP=k;E{3D?8_39%ki+gke( zR&5F+PJ~q~lfL&g#Ath#U8Jjr!MH>gqK~`sf zkiK&V)a86hzfQi|A3E*7>c7UL&UzcW{1G@G-_>z^HDA(qPS`i;X}$T{53%h30UK^* z<8Z`ri)TH}`M918zY9`KYsWa?4yeodlD@C05Ucg(ZR2<`;PJP6{=whp_rJm@r%<=8 zcLlD09}+jh;{5&wu3?7@1AXH}SjE(~#xBIN|0mq`O8Wj+-`CQQ4~u@EM-C71+BoUY zaxS;{un4O*Z3}&I!W_IW(pO(2toknuw)Xvfi1nDxpW;SXU*o}Tr*kaN-REsJ)6U18##i$tedmNZNYC50 zvBSAM#H#-qj~|?{5w9;ptjDrTPkPI)cRGzP+va>p-#MYK^rSy$%;*8He}Db<`pED8 z%rRM=e7Tl*{p;K?hr2F#jDNoh1AXI!Sm`O>PW!Kp4_eQ+J+%S@|-#=vc z9g6S4E}xM(rdGaxT4)B2zXysN=AikKzH>sX^pvlUU5MrQPQ0vXg*5FckTeX z#e7M>PQKb7I_9>DO6r((iQqy<)*qygpCI-#YnH57)n$bHjXjzTowL zSs$DbD?R1wV;5rQ_nv9r_xkt0x?T;j%z@Xk(ifM0d|1-;ujb1!;)J@=o8|i4qOT!V z{dbJz+v#r{{_UjmXQ%OH4){(fjc=XvF>}!0W;mBe`R0qy*x&BwTWHnuaQ?hEZ;s*h zFYfQ^KV~Vm=!P3&y*-?`5q9Xjr*QqdX2OUQVHNYXvjuyuisNs1|5^6VqtEdCkT5m! z&ECCt7LLCMh#U0{>#R7QN#8jkRx!1$u?zZ^z5nH{asIt79e+C?Q;TD@@^x;ML+))R zedQG8AUz$cJDo4oe~kw@1APB$ed4+M?e7h-^RaWId^KO1193vE^t^4Gn*qN6RsS^} z`J!(efa}Zn{$Gz}A3ZZ2*E<&{ZZu|Wo5x?xpL4=|6;s>X_XoQFcexw)w)}(+c6)zKVVP`kB1`?Kr;7fpaQ-aiSa)lYXb)WBFS+?`hC);;Y?! z4~}owh50Hra{Dn@Z%_Z%dnI@egY?CT@>NXwE4_Igj=%Bq7c2IzgY&~lxiI2Hx{9rO z%X>Kf?w5-jVKraEh!bHIlfK3-!ZODD9W)1;lL)Jr^u>*^YEu|-BCKN4S6?Hn`Y(+3 z`3S4nup`g0^Rc)QR`Vr{I1yGc>2u%b+K;dtSN`6u-^7RazK-k5twXG0S|8#Lq|194 zgb^pgDkgoc)d;)LCiCq2To`d8tYSmwJ!kj-iW^{YjZyk`hK@RzD ze;Sq#Tjj%q5hubbrnYyS_uITtTz@lX7X96l^rXMbx=-b+bsZ7*O|k9&{QZ3O5jQ37 ztl-*S{nvPi6JZsTey96Wb#HSI+T{I{<8N3bUt`(F!+aH!zPM2iYEu|-BCKN4S6?Hn z?!A@1`WRsq+jIFR^OeuLAQv~n^1ff5kA)E@!YU?x&2@zB!MKhX`IEH&s*e#?v98@e zusIMn!fv_zF18+o5hubbCVg@Sx_@1I((n5Ab@`GfObz!3#l|19mtn+>a?qR#BTj@> zO#0+B@QJV!dZ*_2e`a&7Nv+WctC;k~jj%o5rZD0}SjD8TzDC$B@jDswmA?8IVHMkK zg&*57PuvJQW=w8lB#bx_Rx#;ot|M$uqmeza)&BXG-4|w0+&L`oI%SXSuK6E@bD`My zGj1@9xRLIJ+mA6lVZ@2Bib2&$ltAjP>x*mapvhAoaVl2aX$X zT}V&*)N9}q=q5ea@7inpW7s!8A7S&;Za&*$Us&oT95z`Y%l46nP+>_BFU- z($}-Kk*=Pl)iboypBas7uNT666_dWWk*?YlMw|$%nDjN*0anj~>lyG)im>_dW7fy@?=RE*sgFV5a>b^dy&C4=`NWN|M@>8d z>*1Az5hubbCVkCygjK%MpZ36`xVHUl*f+(dUxGDx!l5abNLOJU?2qwuk$zfBdBewjPVplz($6h<82I2J5PS25|Uud@Q|QSc24JL|Db7uepw}nlH`Y5eHq5>)&x{Ui1|wYWA2`li?+L&o7c;^6^ZiTNxbYj|To6Am;<0S+pYw0LeZ-B9 zCD~`+>%n?>PZ)7Rtn{S6Bc88m6#HX!Z6-bG?=x-+_RRxAU5{ns7C#dE`1Rt3SoL4y z;hYdFJ?VFPUPR9l==q^fZu>Z{y`BnnJ(lwA^o)X@XOMoKe5LPw4Rg@5Fw(CxzQ?{X z8Ef*(9iOq`zQ^Zrr0<+C2kB{ieXc|7O0#dl_3zKq{#$2!mw4kVn1es#o_ga(y4@c< zdJ)#ci^62iiLi=g8sAROi+Gz!f9TNhxVAkw)b&`l&N^!lqg+C)_Fs*Mb3&~2q`%Va zTL)ZkW5(>q>&eX5WUb?a^qm{#;B98ouamEi51sa3yvyJ6m41!!?f%PiNAsAMIXB9; zd)~Z1ag2l!C&Wt6+tyr1Sj_32y#DR}Xtf)7y_zj~Ruk8@@$&&5%htJZHZb$W4Ryy} z&FkOAgb^piN>BPL&3+8mzu`M|lAiQOy?!6AZC4L4|9w2fiLi=g z((knY`kZS1x?jBZ1G`oX&V`C4{SNyB`eJKF`-3>0@|C{&8e+8`q+e%zd!DsEX)T4i zTEEhFPKcGB#@FXM!gl}u#r1Iguy*&iPj2FT|DWz#-o6pn22(?<$Fz3D4Y7Xw6-Jy8 z>+4NzYpz4A@|FIJd;AgC26IBJ$GZRLFOTqhH02Uv)qm+bC&Wrm`kkKlZ$Are-yd~< z`P^%9uKjwb>#>w?r)SLdJi7Gj{HgaKM7mgS_WZRl;)GZ~ zS9fcCeXc|7{foZK{WtsV5|`Wc@7;^NG~o5G$Fhg+*n|6c=G;*C@#kl8JqROCh?So7 z=gqrs!1J;4mHxwLEotBJ2FJ6^W7%D=oyUD#xr8~W|I&9(h?So7J3TL=X9?!uc_cm$ z_=~T0^V%!a^;pWc(=!Tso z`qyLG&;Rv|UH^8rc^=QK7&p|N`?D47dRqF<39-_X{+ux@40!!3J?a1asr7hm z8|r#2yYZY)@EW;ezUsg9ofGOxPx_tqU(J{1?}`f-8tD2r^H|Ea)Bd3SOZs*4mA>~i z?3>nu^y`f8U5|}ppR|@jU9Df~J14|SPvh%z9b#u6c%XfMcK#X9+4o%+UCnzV_YJWg z%d|e68)9{QlzyG{CVijlP*-}=zv7hN^SiMS>#^(`&+g9e*s@Ofs{hh=PN*wA>34eG zzx*sXzdt%_$e#SJDb)2?%D2-q=6W7o`gQV^zV|iELGLn1veT}es7DoE&V}w;~jpyfLO@1vGH^TBc z5&nK7j5rZiG3jfrBka(5kJ$YW>XZ5yVHF#)`U9AQ7jRE~!HuwsJiiLo!>b7+PJ~rV z`kLzqt2U)SSKgetn~us0LMIWBWwfX!;diHL|Db7 zuepw}L+9Ov>)-A2MVHu#*Q@!E?Uo(r`ZvXv+4V$Vp2hx9a3kGe7xX}H;e-(h7mW)LH!p-oCvF!^flKJR`b>H`D=ZU4RrmR zD<*w$BVDyAj5rZiG3l$X5mxI#`s!nZRc!co_e7t@rL`JiwSJ{9PJ~rV`kLzin=Sa= ztGIqxCwu4hLvgUvE29iK7x zHiZ!<)K&kb?|qH1xxdRm&%3LSAy#9r^QYc}5R5O5W5qL=!iW=L6_dW^I>PSp<~iAI zPi>d)cGHvDL;G!>Px{qM*{}Y1Q<$$}yZw89cI~fE%*Bm#r_BClcFo=QCX6@{Rx#=C zc+y?jb(icD=CJ*=>$BgUwM{OJIFYVmJO1d$*`rs?&Bcwdy2oD_aU!f@(%0BU*hxPc zo4q>n$@cR@{;WcT)pG|)-?O!^wT2&*-&^}PQ!SJ?3) z!YU?xaU-nS6h@o~tC;lF*9fcr3vv*rQ?%|cbI8nZeNx%2D&*AvHS(w8iCr-fm z;qqJ#iTE8gjJiuh!bHIlfL>IVby+E+Jc;95`23qn1oiUMW?W)zf9Zy$ar_+{Vo$y5?>IlKl?x+I(6_eU3;)3JcTO&Dgw;L% z!hFd&5mqs^{pG)Xjbj()d)l#ESfx{4+J5*K)u^o)Yql)gB#&;~v% z39Fd&)z?`8R{a-7&&EVp#b)mE6+0h`8(}qH!iW=L6_dWs4%k7~>AzVF$BQh)dQ5F=?MGO(DU3J~ zR(8g8^@sh3MeCy5W8Jf7Uxxi*C5>IE>vJlMI3ZSg()W9ZBdqTC z)jgrzFW>qBj&I@rU8PvoTx%ZI+XQh#UB8D{7;!?Z>q)=+0bGL(aQ)kT>o#lR7(H7U zaUxyCy6?aB`#ApIB5sIH^X2-^39-`ivC`OuSij#__k?QBL#*aY`kn3-_WQNdJ-v1E zm42uFSL3VksI%TK-)|DmpZj(kU!PN9x}6h_gY>lC{9GPlbx*JEe?4u9&*J*>*bwV6 ztsUL38)ALU2qR92)q0bDr{nL4Gmd6{>G)eG-yP@ei|gN~x}6*4pl7s&fxdAftYY2D zx6}Q!y64uPAFuP=c+&55udwDT>DS0t&!zjj2g1Jj7->8@z4t(|bpGrxzG=Rs@8|F+ z2kA*)=kf@f9XpxVzmu}h?waHL*_G}6_0Qw@7QQc2vFy;V?2GkwjJTohEPQ8o&E0}&vQuMIU!bh()Y0o zv3u|NYn*?dPR|e3dF~+T7u--c&6o6xK89H7>A8ju&ogL@GL45n8x!j4xtUFtdKBm5 zoy85YKBvND&Iz&7lYXb?aWuXfkK>NJ7T1?~sOzz;xA%*@-pQOBV)eX;^qmu8r6+yt z`vZOdo1J;rP0Y{U3yy2CtWLgMOAr3~o8pE!od2hTZ2gw>$qBL2Q@)+{UmYLF;d(x6 z&mlZsgt{JM-z;C}hFHy4S^vM~D}C>4sH^^KJT7|Vdt84Z)??Xu^L}glgL6YH`ouZa z9EcNQr6>JP_ao|_TiyS9<>a67_!jDVEW7soOKiP$x>wlm;mxG)oKRPK(!Xr{R|h=) zUi8!Ld49+olhw(0_QN;W@z=Rw4r#tz-#H;xddj!c{j|F0R`>tb*&n3e>0V*YSJE%~ z*fC%251sa3jjzU|&U!n)dpA2DcN$;KSJE#yVZPGSdh@j(Vs+20?teY=hacej^2iYD zF|D1f)4jrJzKZ*a#R+w_-lXqqHN+lw^ODRj9e?ZOOTA$SKbSc;)YbF&Wqoi$tn`#` zr~7Gj&n-E;|F_O_zH6H$MgK!-5-h*`hEaoP}vQG^h zf2CjNd@OxGmxsE~E|c^7ob2(hy~^*8vWISdpMT$nSdV2-eDV$cy_q>T#Ln;C4(H3C z3L{R4m7etHt?{FQzJJK>TJAKQAJ)zsQ!C$j-?)_DKZqOVpyxS~e!&T`(o?=Zb|Lnm zuV2sapR#$yGksZ|=MIv7!3}lOd`Z7XzIv{q)AJ1Kzs94^b2Gm=`ZAo4x9K>(nlI@) zC+wT_^juD-=W#T?8jokMxPjlVhPochp0MxxR?M6mVl`jVcTR|vp7iJYyRx`u@nO+- zj@cU&F_E34RiQM_uW{(8wvw`W{=M}ISbvX(SdV4zjM*WvtdNiK{yk*;EmRfgjDJ121iY?kIr`UNK(2iI$lhu=FL=%#ym z8-D)OoCMfRG3o1m-2j{J*A_;c2%Gv}?2GDa)HjWhFj<}T_RiJc$N6}QxRI{rOPI_# z5mqs^jrDBj@(}Cy+@||~-&h*&IgP*n%{-RYo9@>Q$4v88+)pe{n1j}v^gA7YpZ(Qg z$nThR{H>Gkd_22??|(DrhB@eY{ILGL|C=g(qpLadIz(ywzqmcF0MBi($B+YZ9{Y`c85lm8dz z&&~6d&-n$8Z)(45Mw|$%nDkfL=8}P~fAis8r`Y*H z7;z$9#a24?D>(k%nz#{G_xLA$=R{cPNnc|ZVOKtNDV%?wY(GEb&niS%J$I1wof~1* zX40>buk_W|NLT$AW*L9hCc-MV+-r;3`B>ZttN9W}oCvF!^mQ(eur8!cY%)v~h8r01R{a-d<6Y+2`iroN ztv~Ni*dIo89AD&Mb1HptB3;F#-|2n)`adW1e-c|V z^x(S^{vQ@e-#Jmf(v$v}v$w+WH-7$N<4=DA=ZBkeVZ@1a6&th5E;#1*sFtp3jl&4K15!YY>ZJN#c6YBTBA$XEL6YnX%gUl{H45mvDc7Wp{N$0v3i zU(J{1K%7WdG3jgVM_B!z6Z$_9*8RoXyuJ+gU&Ye;=z1D|;zU@*M)e+R_y39;VfBo*Fycg5#iXyXi?I4XC-nTdo(+$%iY5IH|5t|EZ0i?& zjC7?Zef2fMs{g|1-3Ad>v2_0QxrwlvFX@XDVHK0U&gBvI$kTqA&D!A8`5_Zu&t~lS zO#ZpG56C7Tw0pS!D#rUU54!aIT-->Pn6oBdnlR!Fgr#0tf9$mQ_^URhf7B^o%Pzez z{{KQ1J9Lwmvv1tHY|16dLH(D$I1yGc>Fe2o2&-oa^bEoNZw}8cJoKG#d=-SKgeY>#bM$S&+%C>J-vPI`TtY{pJ&CyY1|Rx#;ot|P44l>X#jte8#s@w;K)6gzO{ zaA4-8Tq0e~sr1E(u!>24%It4tBUZaB%;B(;y0cY3nuGsGVO+*FsWlquDkgn#BdppK zMw|$%nDo`x2)n~=?<3#8W2}lksgDs>vF$(h7>;?j=Hf=!9$Zh3opxWsh!bHIlfLFU z!XnS^i`JdS|5vU1mT7m`cI>!m;am{I*omV@b&u_No_#cKq>K52-sFT4C&DTw{h81F z@qgbM(i`TWHl=^am>aua-f-g(tJtIkX8|)K1?qHcjw|pSgl`S#EG$m zUR%G|mm=)M|2Y}g4>Rol1w3o=leRtRTgMMLzKm&oh#To@%?Kk-gjK8ub4z`0xmF{r z^rXLYV>?_MguivxPMrGudzRbpynI#I zH^ro{=g1>nwJD4^5mqtjbIZO)SiQ?Y`s!nZRZQnkaU-nGsltd8VHK0U<~qQ3zx#tZ z*nhX{p7X>3y#DQe?aupfE(rfWD#h?F;zzKbwZx6a0hq@yM&A}joB^vC}>m zVM}_2{zua@?3*`-SdVqzF?v&8|B4%8)qjnLb3&~2q~Gaz5j{(w=K;UE#3Q)=eKXYc zSjxB4GYWd1LHc#_mA>~i%0bV`q~}{|j4$TvQLM?&iW}a;?d~0judvkvJ5tmt?PM`jxfyOsi?9_3q;+VHj;s(dbbp0=V zaU!f@(m(Bj3EY>Wz9G+V;~JL#w_kCMp=;4dSFy7$ex>UR-@Pz#11#q2Pq@Z9ynEKW zCsQBw=j@s}z~<7EeuwMdl3t-dXY(nzwvC_H^H|p(FPh40WO2iBQ2#X^r_Jsi=(;-T zxjxp#fctNnQ(gbnx$aZjn(JuHw0{XBPJ~rVZL6;VHmwJ(j~e5PxqSlHzw^Y6#y73s z_IftX0N6s$+t$7mVe^w;oNM2oaeVn51-JYzE9hH_X?=(rVYOz25hubbrnb2q==(G2 zNq^StdvR^BRG6<~GhchlzGD+N%0c}XMw|$nV&1l%4G*#YY&rG${SmkPZYaVkCVf3e z9%0p{Fycg5#iY;eK;K8{T?W$E7zVmq&%Wnuj=j#Go!*gvHE!=y5JsG692Aqj&b1LX zyZVnKvHwoWF52%R9HT$XzBi&5=YsI>H^uNC^WnVy6*tu7J)5}x6-Jx^u!Wwt4eSco zf5Ug8mh=k!Ywoxm`)2t5zRY9UrJJ0Iab88-FbDNteR4*u_Qw!=`EBdsdh&j)NgV@1tk$peof~4k z%}n}r@|Aw4{dc>s-fa0wzs~q}KRAZRyv(^_zWnUvCVYpz4A_AlvsP9awLO5gh$ zVznNmUuS&hj2Xu3U#+E3*UzcKV1F>q0N6rLe_VQb%Ig;B zW(B&6mGuYu`%P_~B1A18nNQ#zUM4tC-r>vmg;x&nD>k zp|_TvfbSk(jm9kVnDW(g2oW|t&meu}6y@Ntq_4RSu(_UvQJ>Vu5bI;lx%ke@`y_6J zC5C^$N?)9Tu%=hi=UfL^do}~#|7!l!#}KRWefn2B@H=>ML+ryteu(w(j4+vVLag+p z-|2Y~#+a}4pZvit1ARZ4c`SQ-?QMurE@2Knr^1L6Vx=d2<}|?fzjsX^rY`|9b)JA=Jx%pu2=oqHpD76bl$J*`q#M;md9UQ|4zm@m_F*p830@8>AJep z^>16R(ErzEhY$2UZRWA;;Z4>fCgl>%vHGv^a88tO(vyCN{a16E{(h@--KTtguEQL> z&7@x^UtOnmxSmYwLHaeu*Uq)P|DnTrGYr?SFkH{%1al!h%^&OBmm+L-`z6D0{ji;l zFTd~d@5Vx`zBkkQaBhgz@lpD9)|>Qwt%kbNll}u^=HS|3*%0foZ0=RZ;u_;-^)sfH>^ZJ+D|MtC+^gBIcuIJIE@0^bLdfS@o5UY0?NWaeb>ip^4 zP?zh0?^BR|o%6BAx5M!_-(u%8vH#-U`Q?9U_d9O(_IfxMgx{y;iuK@HocGy?8?7N? zc#nuM;tYhPURi&j`*+HE)ZcQuy|8bF|DSM*jb89G?BiooE>RBZzx2h4u!^Z|JzEfA z^(=v&Az1Ghuj9MNMWQ**6_dWWk*?YlMw|$%nDo`x2&-pdq^~}PSReZy%r);x5;wvU z!~2(n5oaK*>6P>cy5ET7%KLxSC-pJXRcwuAU&Hn9JGr#;WL(`WRsqTj9y8aLn617dOJ{`d=7v zBCKN4*IY+f-2c!=kNO)oPR6zE zjBx)|Y~^`-*fp|piE_|2mN4Q(SjD6d&Vc)`=1cR(?SHxM%cU=Fl!Mw7Mw|$%nA%of zBdpeg^wq}*t5^??t-PmM+z3ky&#A(QGZ2<~C4JkMBJA>C+y>VVJ$B8^?0&+GLXLd80jje^QX8GR_9b< z#EGzqNndjvV7D2!`?yA9m&W2pPaWB4G`4IsmTxQ=EQ2F3I0AzsFgOB(BQQ7ugCj6F z0)rzkI0AzsFgOB(BQQ7ugCj6F0)rzkI0AzsFgOB(BQQ7ugCj6F0)rzkI0AzsFgOB( zBQQ7ugCj6F0)rzkI0AzsFgOB(BQQ7ugCj6F0)rzkI0AzsFgOB(BQQ7ugCj6F0)rzk zI0AzsFgOB(BQQ7ugCj6F0)rzkI0AzsFgOB(BQQ7ugCj6F0)rzkI0AzsFgOB(BQQ7u zgCj6F0)rzkI0AzsFgOB(BQQ7u|G$rby%Vsxeq-?)?VW&Q8jVHpYC!zIEuVkp+I;i- zhvY|`@kl=IulMGM&3-c9?DCWJF2-tN`hR1LE9_AhPtVuC^5LX4tN8z5I&zO6vsS*r z%4;Q#H0p4LRr|fm?v;OP>`S$Bp1SK6`Pj{`&&82OopyyiXon$r{_1|YwCZrD%swaY z+H-W`NTUu{ShcUYs>40_2Z!Z5tnsLv_N7&)UF9f_H0p4L zRr?ydI$X_(IMf(DbW-j95_{lJ?$1B@;xlQk>a?rTrcs`t(UAMovuwOp^N}PWW z%#&7)>kaKs;z*;${B~V^_>yc-{ncF687pA_kx#s=W#f!}Li8|B94v$b-2RLeDEP$Pd<{g>TtC`X?~?qhbyew=dpmt+B)1bdk@SH z*l<$L?GeWf&riL7Y<|ecx2nZWSU=WCt46!ppRj$6?dup+tKC`Np4!*3uSUE15wlmY z{)r=vI$U9oA2TvP`m#roRvj*{H;y=NSmH>d4p&&UueqwjCH92d-p;q4y^xLVl-Xxn zy$)AcwJ)tYT;(W^H0p4LRr?ydI$X`KINTnv;ZC*oD`9ngC#^c|YJU<(8g;nBs(o(x zw@w}I4ztJOd~|HS{mq}j_1$mtZFWC3-+W%ZzmJ5S@ZIZhyt*fsR-JZtTK!I(|DH}9 zY1H8gtM+?v{@Y;X75`8DRr|X=|2)pW*VN()yXz~<;CwhGk#k_SqTud+@Hbel=!wxWexA^u@S-KQEV7 z9c~ZS+&)_jO&n>|;R>tv|1ZZY<*4?z8hN($zfQZtk~@CH=Th!Trcs`_ihzRgU6FqYhVCwXdiA`#QC!_Q&@A%C0}^v@7g}BmQRR zUuo6hYJA0!MjfuOYG3q%+V;r96PQ5tvwQttpZg%Lu@%P{utlR1K_Zhc!|6UMQ#}8@M zX_x)w`Bxli)Zq%N_POP;uMSu3sr~IQTh#hrhbt_(M_=}blzSa6bL8K@<@TvjhpYC~ zKCd_aAA4^CCRbIh4WFt6LKuT#lv$9W1tjS(DCtv~LnMKi4gn0%RCQN(7d=!{RXqh2 z5ETay6a|BN!FfQ@djZ7}RKzJbgNn+a2ns};@H%0>_g#Cxr#oCPtm=FJ?|J;5zhT$e z=bZJfwfEXdu8#`%2&3i^2Yi3ma+Mu33F7;>r8fRxYgUN%A8P7gq8lpJm71 zj0-FMMt!IGeLjr&VD@h>KU4n|ZQC8o_QZVQsBOb0YM|qMDUvNFf@|``{ zbk3gK|NXKs;^D$Z-2nSh%zyjE%Y|LA=C|;VpAtqqTv*AA^5tt?*yx`jFZj!r$3BMn z@IPGGNUO5S*LtujqcGy(!HPDO{HQw@R_!Z&um9Qy;J>bNVIyt&(pk@gJzt`>a$%zl z3L_patmH{P$Luu^?c~CecFvA3OnIEYZgyHe=q!v+Z*gHGZQAq3o#C&(YCOQpg{8db ze{D};#KVP^Jjp-hz=tvZe&2;%{*U_+Uv#GtGo|_#U%V&A-=%5f<&rCVlKjZSg_S(j zH@1}vOWNfdA2L0|Ceo?cv*br!Zn?B4$)8GnWzWs@U+Gu+o{GPkw_64AZ4{~AUuVPu@ zuifKs+ry>zasO8s)xjlqLf&`kpL znE&pZ$&Wl-Sjm(8w?A>Yd;Gn;x`y#Z8ZoMaORnTyQF;>N?~*j~a$#xn9FHVF@^E1# zPx511xv+29=VOc?tslu>Vmx+XS!Ryik{@}wu(Bt~pGtitKkCjUSNfH{d2A*oWGs5w zi^naVY^Hr>Pm&*bxXLVfv8>ish)rEs=~w#xVB>|HAG)xSHoa!_37ao8)4nV#?Md<@ z50_lYll+@n=eXy;U-_#H3THFMSW^zmb=#%y(XK57!5UfqdiP!b+a%+f4tJ zf0n=e>`#y4dZkNlq*YnvYh75`(`5P3nG37>N`BOx3#;~(zJKtN&vE_Eg^jf7w|=vM z>p5yG7gqKp`H_bUD|wRtaQCawH(bv@r=-RD9F7-bd^k4!(SPpC^;wtPNSogKficIVg8#&UatBw-r)MeWclFX!b+a%8{5i-eYpFzw%;4~e>ER< zVOeI*T_s<cRtwkX=_0+ep-PqaoKH0SWFGGCy^+K+d^IyE5^XzSu(QbS6(ePK_&v<#TJ8t?Z z=D!DL81e96MH|bSZdtcK#$VU_N9iB#zK`)mhM7Wr( z75?gHO+P!$XO<;jJUsOkt>o|hn-63B^?iS1ukOPTUyK%n5f6`C(e8iqpD_NORS+)^ zR`w)}czCd)m3+082TNK$?<|{;jd-x4m3;B?U{yw8#KVIXt>jC09<1~$jC_CxE85w8 zZ?Je$ygXRhlQ81p!HQP$=?myuzH4A^WWy? zuwm{j`Qqi1tLN#%^VZ_w!A4r>%;aaf^I)TXg|Q>wZ+Bott9UYND+d;B6vki4SB&Vu zN?s;E#-^S!7gqlI?!xZJ99&rT*e42meD~*t6_2hi>`-+*f0fam`n6nP=G)K7csa^k zSo6c#h1vW4J;R8H2P;~Yb>*fn7LqVuXPuvET_uwz`KyokY2kqR6_>6=yW%JBD;%`v z$1+}?GE2YGw|IE4qLut+-VfEg(hHy;zCXD5hHVPZ+x17T`ifTa#miG>l~EY+@L)wN z`O=*St9NN7Upn((MZ0dddkgzsc11zFJXpT>%Xm^4@$g_pEBUfb4|W0Cbp`Hh&?EczCd)m3;E>zP~Sdl0W~QA1>_BIM-#*qFvm1x?#l2 zQ)bzqFyi6CidOQ;BSG?Dmvx_8NOFHH$j8a&d9b3DeDU&N7sN6OBOV^CXeD2|^I%_u z=b%_$$(PPNSkWH0`zLG+6E6?8wY6YvB8+%=u%eZG*`^1(AW706zxeFJi`uSCe|*R6 z!u$(POYeO6DVJ@CcJZrkFpPM4h=&I&TFIAfda$i~yujk;qYmF}@$50j zZ?Ra|gB7j(hj@9g@-f1QhX*TK$(L<*Hthck#IwIHykfsMAa=Og)xM&=_!ZZM zJ|B5GM&o$p4UzqugYIpk*g6(-{m%KeOUcF{_{zIEu4t8W|Xn}#Fz&B0vf=dSvSR`SKm zBUfbXg$fuqF<`=N%z{?|d{K=ajZ`%wb z9v-Y{Rn~gzLd<`!ca>RXl>CuPKaIKU{w}O&tM}b(81eFyS^5=5JUm#@O1^Bh=&I&TFIAf zda#lw`IXaO9%5m~xFFijnF|p|4-~}9BUkzrMm#)N(MrDltqu=%^1sc&`S02L7i@3D zgB7jhi6D)zI5inidONRczLjj0fi9{4_362FWYor(^U%> zqW>P49(&T;5zqcIUAXv#h#h?28;P{(8K35w*UQAq(Z=;lfIuf6jWCG= zBtPX~aZRUF;v5cAg9d}%exopWLH`1nu9riq8RCX6u{a5;qJX~1Gll;9m-s1LGt*vKq zKA1)yHzofp`H`2a%(0BAMQwEXy3M9JTSm9ERDQ8^=;d<>4$6+ zVZ_6QmAqJ1*`@~z8@z+_-?pa?xPkN0bcaiGn9KUU&k$+T!#=tZn1{v7C3oI?Iscs@ zjCi=Pk|+6lZ@dTdU)R5(kjaz$Lm&GF=CTL5~xI_*@q@(#qF}mkS%m zUtz?fNSoESnQx-%d#aK@mHJA4)Sau$@mt2(_kpL-zKZYkonnt% z_$&Lqr!eB-!p7LMP3;?P(}lfj+b7w7(=TrS4x9geb;d8<^WR9De(%etvCpTGmrL%C z9=wSDLKyLIVI@!UH*NZcJDya1CI9=E?qGYmj`1jswCSCXUdBGJvb)MG{Yrl1;lfIu z)SZjamkIeS$&)Nri8vnA^B6OujEJFxyr0>vq=6_+V}pm z_n?n!>YFfp-=D(4bOYZyE-)#Ou z@*@uyR`S%o(KcOJ$&>t#_E+8W-$h0NjF(I9?YHi3 z^KHqGJX~1Gll+@ncX!W!B~S7{{nHlCWnFS3ZTitS?87;8Q}va8B|q|T$(20GZ>Ims zo@8IwT{+D=|4k!pR^MjqS^Y=yr&3?ZkGgZ|O8!Ffr_#Q6-m{Q8lJ9ZJm4B4{$isz| zJhgAMO&4}!M~CenUH<9^Y(M9!_wrr9^)76rP31o#FBewhpX5))UrBznO_yBBll<#0 z_$K#)T-ZpPzUBV4+;d8ssju`a`H_c9uH;F6GvCXd{B2V1Z(KTa9rs3DawBb4-)6pv zs_&^v{#5EK`B8VSGV9yIl0TL9ReaaXH;pwvk^HH|lWN~4#^1u;pS&6U_t3)ZTQ5UA z`>VnppLzjehqrljmC^3|*89=t&&hZ>#_qxa?|l;f;;9TH9v-Y{Ro1;XzQY?&X7VI| z-#^`kzBu5juW0x9(5unsZ_apm$}Ig#-{RrHidORVtp^WQ-*(V99cGO_h`G*#uKJ2r z^2N&|S7j7NJUm#@O1^aG!Rp&Ak}sWku%dn5gSW%Sy{RBx9xT5z!slaz5f2Ymw308| z^k8?~^aFeTSvr!=JXq1rJm}l7iJ#*e1c8?ayUm09!C(A3!-$6mD_Y5yZF;aOqvX%5 zj9@NXcGl>}h=&I&TFIAfdayfg zx)bx?lM35zzl!tG!pxI)_0E4Y+F36h2IhX)bKvEXJNt?SkT*TUh=&I&T9tLjO}Dw9 ze^wbKf7U@OF_-l{|18>>W6KRAUY;^bzru)z2P<01mu-5mvZo~4SN?CQcm7)tt>lZB zN3O~!jCgpkqLqB<&V!Y|kbLRPgB9%_|F#Y~TA2Ah4_5wB^2Ni06|LmUHXYb>%U6Dl z`1!E(508}*&;C9A>&#bMEbPIGHu?|oa*but$7C4!Acx$7 z%^T9s{`926nvdO^e($W~3#Wemm+9xf^D$R_MZ4y&52qja!f-*nJaW(6__p-@U;TQ9 z5f2Ymw35Ga^v?9dSHH|v<`vbCq+h&rNkJI#@W>VI%8!2{z5BY`3*zO$>YEC}h=&I& zTFF;id9bH`d|vwN1Mi*qeop+hga@ndLS*tIFAr8_%;ZO%d9acv`O=*SEBy+iZ?$-^ zqFuIMTYBShwWiuv_LRwwJUntGPx2Qu@jV&oSNdLe+zIKg_jLXH3kA`(w;qvh`TJf4 z@$!^e-y0D|JUm#@O8%J}uX4`^&-(ilRzG3H!y{L;z^32*!W9Ma@?g(>%_-&|g%J-A zRAd9k=D$2x(ROV4 zhuO1ud9Wz6*`P4u;lYYl@|$^|PVdm_9m~p>UxV@K`L3}{v;({U1^#MbQ|}Jzon6Tn z4^MqXEBW1@JrCpWajr6V4lhG|@s5Hp;^C1i+U`p(!1#MhLA*TJ%$_7a^6+3KPx94P z9<1J>l}*S-JXq0Y@|$>fSY^!QPoch&FWtGy9Q7-Ve1Hcl+H+4>j(D=OsrHpU$tJ|Z zBUiMNFJJ4y>K$6WV|mtZb}!7lddSrmM4S1KCf*&+>?vZz!&7F_O1^xb2fJ?R&Q?ER z#KVIX?U@^|D9kSXq##}%tiA~6!hexhxC11MpV5MJS^sN>TRijt=b!MdLAI~@Z`&T%bYOmXyvH^~JAc!rPjJ28Rg}gb@!HHtGhxX9?!Nmx`AQ`>s3ALZ6!> zjCi=Pk{9Kxtz6jXpEG}X$!#;>uTvK`(yFZTwH~a>D2#Y`u%c~~{HQw@R_!Z&-}31* zGyjGD@Jv3ZEz-7a+;}bQd2h9qOK!A5VZ_6Ql|0Fh?-F~kdf!*?ShhWK%il0Q9qPe~ zHq9Nf3I1xCczLjR-^$+E6-GQ<*eFl(+rEuCk8}RpcFU53F=lTRMm#)nMca1QE$_ql zd$V}Cu$etY`H_bUD|xYP)K)HReBW2^Sjt9SSlN^0H}mdre4jjfhj%LVmHcMcOVxw{!k`YTEVE0^+;*=^1Yx#Q5a;_ZCH)mS3|T{%T0PTyhc1VE+3pVZ_6Q zmAqKi^yIN8F#axcVGCzmiTL7ZVN?efR`OP!@ez!_pG_k#7gpcdHOCz6W^myo21fr{8o!guD9E$tMpNR`OKeX8N!E zGkMToUb=23{k2POq@}K`zLA#;D|?zOzuEdqe$<^yuJkK?U-g4`(|@_Jkv6?-(-+O2 zn`vL@h&Cvj5D%AJ$&>tM-lx+$w0b}F`u1BnKDp#Z+Vlf|zS{g%Gw%+^cXm_Bk33v* zB~S9NUHp3Y_KB`s%x?&3sQ)`jx)p zw}xGM)^~}s_%7Ir3rig(7=I;yD)FS`$Jo>*_x@Q0?kA)_deg7Dzmb0L#y@j?)`g9< z>5mWJ%=Nl7@^WDx?mh|e+^2*Q4;NPQB!AQMKJHzAPVaoq#fUGSpGM4->bvPJ*Kqw= zyj*40_dYWDfrkq#d8%)0D;M^AZ~h4PPtr}{8)4~Gz6+7b54>D*GkcQ!Db!crrD*1R z6wjgVwXf_+@*@wIt|U+2m1*XCGHPGx`~K^0;QpvfZlq0rZ2M(< zrID8lD|?ds$isz|Jjs7J{@XM3fk@A^$CqwCYB$vHc>G)E_V3lCQ>pL6-DhzBSG-(h z{$tx$;UA9{2J(%E3oCi5Z!`T@{#pKV^XEF@ujjkuMp~6szSf1!>?w{9Q>m}yN8P#P zs(q#Jzn-`|{MX$sY@|*9(0VMNXHZ+Yu(Bt~k33vh$x~S|j(gX0vUhm(j^(tocft5{ zh(~TgwA+6C0{E+i881gaD(IbEy~8UW9;|33KUw=bjK8kuuhPHn_hG~rR~Lj4506~Y zCj0G(@%N^Tmjjz-_9Xd%hfB{<-h{s6yV?%9**m;RjPGP44s0q~$=Cb14s7;5xiI44 z!DjjmeNVdc=t^xOOga^R^@sPq5Ao!g;^mPmdlDv%JUm#@s;uyr7Mr@T@g3Ui{ol>I z;NS7|?f<5cHuG0{AJ^4JvZwIAv3R)3EPo~W&5XbIf4&Fx8_LGtsnqvjd@BX}ziH&< zDzm;+vF@$g_pEBSjbx!ODbE$lJ>0*fz%5f6`C(eC~7*I@j; zCFAA6>YECg{K&(Dl|0E;TY0eizIeeeH@_P`|1 z`9eXwJaYBD5n;r`gB7jhAKE?Oo-Z8n^{-j|gb@#qT+srH`R^44@$z7gT63uRM`6Un zgB7jhtF1g(`DgjdmR(28Uwg2km3;B?U{yw8#KVIXt>jC09<1~$%rUDsng8-&MSJ9? zAHtsZY^r@xX0t)b7Y~nI(Mmo(S?0Fq`4^mqZ&y84cv0Jx_#V~l!f{uw!}zqsHU5hB zML)j-{;F0GFHe~lV6FY;>i08@czCd)mHgJ%y%^)K@B16aEZPV0#m5T5h=)h6Xj@mW z#`t@CLA*TJ%$_7a^6+3KPx94P9_(>PUxaTtom`Mj$VNO^(Pr`^FAr8_%;Zm@zLGE9 zdE}~1gpm*MU`2b>HqS*oIowqH%APX$k%vdF`;8~>hglVZ>n#Vda$C+Cv7jTb@gA- z@_ohPHGeLMmq#u!m$qM%VZ_6WrM$`V=T&{URnNwtG=R@eDU(gRT+g54-Zzfk}utP zu=+NOiux!`*drr;zuXN_YiuSan zyQf!nPb-L*2Yc#cOVY7b&(AR8;lYYl@@1PItjZ|)?Vs5zUG|A5UAhu&$M_z=Y|6^+ zkt-XNeDUyLMJxGdZhU*X=K*)R%G@*BmhS)5O$FK$eVlxrN3LikU%Wh6l~EY+@L)wN z`O=*Sd-7-hjQai#Z4-1Poq4dLU9rh=&gw zWgv-R(_9|h4a`_zXKbN{3uULLtDBlRncczCd)m3)1x)P;@TF{OO27xMV7N8aPo zm1rej-#PWjRT+g54-ZzflFuV`=fUdR!jdnYd9b2Yd?#KWtYSc6#KVIXt>nu#9oV)f zKX?=R?@4Vp{rDWtf7>3t;~R(_x;(lPExx7k1N5W3czLk){f$f8-zkiEII%%qEUWRF zS3S>zoh0ub*u*>Ao*GHf7jJZ7BW>H4=N!xVuXwqz(y#O#dAP8WC;82MZ$#gA(D%k( zzx@v||NV_iZlulX+srp5^gRm6pGtitKkCj?W_`yc`@YH)+86e8H+)=|c)8^2doubK zP2}OknmpN}`i2LKZw-A8^WS5${yUZSo$;D)!zLaVFOS^$%ipsF{^Cc%v_&2stZ3WR zzRi4ZB-U5*=l|@6FJLbFC68Ruw!N+NC1O-|4>r@U^c{J)u#q;Czw)jxB7Xjm3ww9_ zot*#5$I0iqu+cwe^^Lq-*jUE4h!GDLR{E9vCi-vTl~0_A`rcT$q;jq4=#r6-d)v1l z+LtffA7j|dGG2~xFk4@ceDUyLMJxFiU$KmR!=o$I^PQNpmMP!nqncZKu%cC2r8@^U z^B3|TQ)pk<;*T-^-6UR~_Raj`gugT%PHd1D%c{QN!4@_=bi3^zv3JG<&D+VMx9ustX7@|0Qn6-GQf*o-!o zRo^OgVdJ+@DWCfrJaVtXgB7jh>pQ0&tjZ{iczCd)m3$t(`ziXiu;i=F9CAv7rZ>zV|x^qW_+nUUk-07_)$U+BW-%k+}EO= z_Y*HynWbOpJMwU0B~S93`QC`W?Ew3=@8`VkL;q=eeGYq0BW+gS$jen`eUC!&r&3?Z zkGgZo)wfwBe=6-udwSO+C4E=MB{#maD~#DBc(}2Yr}m9~!-ZwL*57kx)_9tQX7ItAHZ8~r46^yx?s;~4b`H_c9uH;F6GvCYAw@E4g=IZ;=zP4B4 zlB<0b$#3SHsQR9&Z|WWc(B>`C?sEX@RT{yX7Xj54s1c+W|5AhGZ!}60&U}6kGw47<-roe z^+CxO4=>i_O_ERBbYSgU9oYYseMx67tlIZypFf$;1c;Xl`~8_8g1@*=m^AWmVI@!U zoB7@dX<1*%zxRWyz59b{q)mVS{3XPw?5;9L8x%%7Tv*AIeAdCa|69n-`ikv`(w^w! zsM2mm#Mzd zHeF?oWz6JHrM{YnHZdQ}{DtICp?xhj_$$NEKMF&CNgfW{kUZHJ&+SrIG-cXeSSZF>8A z&PU9BqjcxO#ytUH#KVP^Jjrk7d%5~HDdlti%VV?q8j|14H&OLHRmqP$nyPOst8CMS z)whKue=6;(_%8Bt$)&&G_mCxjD)FS+w~6t$aKb6CMgPUO26p?Lz0Y^t?^_T%xb{N} zqFsQwJKrM^FNfdA-j@(YJiJ)Sn=Ie^{=#H=d?x-yC!LPI_!CbXWwdj)+=@Owuc`V< zzmhK=p8ASbW!1MHJXn3(LEm&}`OIV3>)XavU(rgwczNWijKYYA2P<01m+m}ReVaw{ zr85^c+QI_ZGvDzLFAtU&z8@ltczCfUZ<2iP`x0P+JLkU{Mm#)N(MrB-(}PtRCI7(JK8m^QCYL>n_Q<8b2Ik4E>>jz&ujGq|2P<01 zKeW3S^IzZlzw?&N#C-5~**jYDc^jC09_(JP`!eUhXq%uT z>CA%_?e6!!2V>aUf_QnbT3--GJUm#@O1^B*_Y~%#v<-U?SiC%PiQ)UO z!ia|#%lD2|)+U~R-bx$OYUxm|JW?r-9(~L)B*^}9SuV*xl3P7-7IOK={|Y|;_)h-uEwl2E z*3Qj8{2T}PoN{kl7(v*B0HURikEWv$G>!LxSr#6 zmf`nEEJIU&)Js!n%?*3v;1kLG=f3Zf&+mNJV>>={P{(WbowjA7JLf&K%xw?$eYvc=VYW&i2%zwH|o#MBi)g) zKJ$5<_RqvW9iN^Dcrt!gtlNt~H~s0)=0q9u>2Gnr70IyACgq-$Y(*gTzfM*Wj+H4^`5tFn8$fS+u9*!T9(2GCXh_`|;PQ4wr) ze75lcb&B*DAMSV{>ocL;>N8uhe72K3^zv*p|7!Q6ovw~`#fVcI_#AEs@& z?V_iT54iSU#)nB`L9h?$o;KnBlRdft{{ngG^e_21~$+M0H@D(6yZY=n3dH9!uV*vr| z1Nu|m`bE5sMq#@o5kD*X$)?5v;>CM%UUHs&ESN!m8pnd2FXDWGeE2tcEMVocKPz=O z%Rlxl`tYs(@|(B2GQW8z*yK(_VJw*W+x+Got|t+$(UN6;o|1ZCJ=5PJf{~DChmRHBR{eL_bn0-k1v#vu=7RGn~eq3ALj-<@^97B#lxj?$Zz#Kc`SH%pRI23B)@r= z+w+@upM~^^{G*MF@|$-(Fu!^Bf#KdB5AgW(KVaw=pEefkI{8{03uZq6x~Go?+u<7T z+n|jj|8lJtCCSZ}wegbisl}-A($CKhyG$) zUK#r?#}@W6_EF9w4o2c1&y}ann9t@J$a5UwxWMZ?vX3&)sVq~Ra$iKnpB zaLwo^+Rprf+OEm5Yxh~;*W}o>`zL^5c@`kq-?Of1ZT{!JPx$}MV{E%I`eE?p*u}E) zPwht?vYn)R-lqAt1=`q7=jMZLaO~gf>GQY$?eo}YdO0>j9+&*AJ#fr)J2@{sKfN52 z+h;QUujQ!kE`yAp^Wt>DmKDFyi4d1oiX^`z2S z9qizZp;~pQTx(RyxQ5e8SE;|+*~g;xmyM|jojdQCvlCvLID;Udi?#A#Bk3HjjgsKa9#4j21`L5v#3Lu-;$kD%Yrw zn4?l^0%B#8Z6^}wKh;}fFX3)!s;eO)RRHpt|#HQ1$FIDTI%KgepaqCL9R1t86NDac9e#@ z6U(sXmN8bH)qx@EG^w+^^>VonZCbCFp+dCSP;Ze1rLbk{@9j=v`FZK0WgM@6UQmn_T zHMC%;J1W(eKufi9XCvvZq0)o3aD?pc?s^%7xC{#@cT@&Yxbe>Zq}rDZ4EHxG9hJc@ zY!~$x$6>InQUdre7*wDMD7-jWK~vXiNxce9l|fiB(Q&GWZWW3$%LP)SQC+mLTk4sQX$yxV6_1=L60ewQ6|)VsL`9i=!)n(Gz+uq!D^*mwj3*X{l(7V!D6j~eu1-UX9K#;zbH2QYV692nwB zHySE7nCXX?IDFw~=e6Q^N1e3FjAywGS+2uKG4d2UAQmHG$Wl(08=uH-VE2Q=w=(t? z`>XW^{0qF{;PAjuZ?#c{gAHf(ay1ih z34;tz`(dA5Xa?qc`m3W7rv<#qd>*t_H!%KC-N8-1~e$g5gI8FTY z@TZg%2TC>mSgwb;q&!eTBf#Gf2H~b6!m6OOF$H6$-Ap#n^f3Z=C7>I`u-I81>>P)a zFV_dl{T%>J&UaL@GqM#G^1NdmE@_N)^jBB_WV+!jAi(6uUX7NtTn8ES!oy+6!}!ME zxn^h`{Tx}*`{A^pcNlkE% zA;L5}vJn<#>?vWihQkhag!b*=AW-KOIy@fxX@eM>>F@{oJIqGAD&5^QI0Po9Qsoh% z_4Fb%sKb-N!FFN{#0W}XSQ~(kE7tn#W(zJ3(ObYDGsh-_z7Q0c4^cL|Z2ipWNfgeq zn~+@{Wx&vCIJm)#l6j+RVXYdqGDgS{Mt0XKoejG2ZaUrWejDt2&4Y}M+s&kF9K#5m zfEg!@6z#^}9{Vlvw=1|v=7vV?ZdV=3!Z~7GMhd)h9?Zf9tGUNwcnF9VSZ-xba^9Sz zZ%$H~o18Z{>4W1y;8g9WUGO+JIe*xO61ce`IH9p2#Cu~y?E76zphuU17i{4u6GA~7 zB@yBA0^$g2c(j6|&>tW=MRQrU(Ti)n7|Q4j>F|meaFY;wk~RBn@0_G}Zqhv`>Bets z(u*L}0BB2a??6m5G}x#Q+wTaN*Q@=*;V^<24U&e#VZ>s_Vf#hc--mGzsBpx2X$Yyj z0Ye)4MWt&jfg>MG1~J<4`Us*8gc=OtLJl6kIv7H1#61`>TNv4b5UtecWpIhS6$TaW z!hHbd@Mmr;Vh7X^i)q<9qNlPoGjohr7}c5~)O+Crli;*RQ6(cyhWjm+?eDcnJsGQZ zC*w#&1&N41fGQ4D`p4IEhS4(8jnO(DP%AsF=)A(N#k#Y-O4YFh-kFD%Mu~PncYyAV z*dG0voGXLfRfgGiG_#sB_XIY{SPgC+Ja|B`W1bbK2v-`6RH%bm5rYW^qDo_+SjW7k zt5(77q>Q165#0c~3p&U^BOK#lz&NxFl)HLxvn!ri-^J9U(%Cm|u^>WvnpDdG%Svul z%mM1d1JxLujoADqOryFjkHQ&G98DmO5zCke(PMCS1J!CYS4{G{DkGfh;Q+q_H#l4i zV`a+#M|+r)h0%yh8G&JPh+@+D&^y)9ko9vr0}MiA2=pg}YFyDbX$5T>-Q(QxwHGsL#2&^F-;NKXf!3u1~3B&6j=|?Sk$~?k}@({W^bM)%g zUM7V8TT)Hngy?F27e+5DC9}K%%CZfi=pq$Nc}(q4|60zvgNT)(WG&@^#YIG7FoAG{ z9*biL_NWUwKC@)laS!8Mj8@fwIQfHNTaWHQ)YTHAQf5PrYB!(B%mCuBvW1%%cpG8N ziU70spcj+csP>m31qNLo>IW?%15Obzh}m2aJt>r=3+^$D1SoG$ZK%Wg6c-lIs-|>? zOi+}~W#CwcP_{4w;xq@?YOQWT3*9if2qGzXf89xn9Dgu14M)t4%9!_|@u=s;){F=? z$%a>{UaAQ*Ssuod=wuMT*D%I`6((<87y@C+17+46ey6+46PhjNQ#Lw>m59oq^#a%@ zSyO$AOfbd4EH${CV8(z#Q(XNh+Nfx=aYUzZMhKti=tpta{JkCE;=@I%ec0AuM(lSq z>4vL^&mT>?hLf(51ih#QMYEyf1RHDMLM#Ti#T`c4ob}V3aGb-Rx%_G654(6=-Qe;$)h;o#HrBsav)LO9}JuuHhlnioXakae$%lVBubOf;z(#;N2N) zF`VjwpMrm>Aa12~g!bfg#0a6$K*Sp2X42Kb|278EVU!1k8i-u6$P(M9YYx>gaoIdH zYQXq#u#S!pCZ<&^x*-o?2w-@%WC1I&xJGN}!35nZrVN4^6v{4PnWBzitU6TbTo$7= zA}5-V>ra^bVhsyXO10VtA2r0mk&~O-72FtXypDUR_1LtwLvo?3APuC%LC41sQ~FU(zrddKUP&N?Gzt`Sv>{SnD*AjLG9 zCoGvAQ6)Qa42yyF@P-ZJ7UW|cC6olA3RRCd1G66#sa)eCE;<>05j6tKHh{Jn%c1kc zy4aFs8O@Hs%W4FZEMaby@W*t)3_=iegnFs7!-BXX0!5Bn@ZN*{)ha9mMGcwG-fEu( z^T)zgI^pOrz2(%Qqu4dVfugHAM32F#3u9U4$Hq5c24t_7;3CfuBJ`Wp_Y7B-U_}bO zeii2kVJMt@1zoqZTF0`>x?=w@LT8;Cd3LsR4BeUI0UHHNa`?rP9DX<0a$UO(nq0VB ziukXGqXH|m1}25|Su9YkEBBAZ<9Ix7z#v-dSrwu&{I(-V!eE1O87GStA#SQ!0Ja(d zGXhjhw@W3H!(N7Lbaw3W>^kry)d6_UQ>yUWSU5~Zpqzp73M`JTjb6Lajs@CKO%QMl zDX)c-rVr5hYWVm{XFuWzipRZni|c5px?o`)SBVj?bYa(E$?(7c#>)s?G1$$LO+H^} zv-<90Z5jKQ-L*Qh!l!WM8eVco`DoqAe*56|roJp9-d~$l(XNDUOkn&K_<7 z#sj;>e3Zq-NC7I$5I8c`5g}pl?;l#mc7~JdAA*HpiJ`L;uXL8eh3?KyGgBN-vSnfv zboAu%_%f^{l$SyX*7ZhTI$T7I$lRjwM!CMaTx&PSgA1_>jIN;H>MvvQG=R|XT!!zQ zn1Z!*b_J0LRWKh226;XVX)7u_O^U-^l`4XA+=6H5Dr2Xlf)D|#_2G`rda76)q1o5q z->^7hB+M7bvV2%d3}getV^~YWVrXOH+%Ra&aO6@iBXab0t`c;hSJyD_M#J`VWqINp zo-GcI^$>$FChQn9V~BMR@mQ>)opg6woh)xF>=qLvkc75vM}bp0td80RPHM5UVE({n zFKg^~x&1CeAPMh|IT?t?=x390`^Ea(`If<2YYjVjHO%j8Ty;hJl!FO(AqX1eB0UBU zTZW;D4wxRt>hSvG{24<;o{aNnj6S9g_I5x7#tA+|aEq%lVBHut8*>Q#%v9=e)gU;2 zn12;T#n?gJV)9^XY}TL9olskhs%UDCOdONzMFj0wwy<>)TeGp_uRuo1+OvzrJz@nOY{UKU&_zg{usCmakA*m#^rwnc4Cc17&QUb>Ws4dzY^W z6CkcsEnJ9S`aDcP2Ksqruv)^pFms*kvRExl#=B9&Ip7eMHpzOpuKZAC452l`8M+Wm zwI#WoB$qt2r`*xM;@}Y5x8(+r~!MNNee3vm<&VPoqgzO>utvgp=rq2>O;uF zEwNM4(&6s#v;H{D3R+6FVJwR@s&HDJ)f!`Q4o3*S8l~Y7@1DmntyT#!SXa4+V*oe( zhOrLDMH}0wfft9{v?b?nrWY1ApnNQUa2E*`vxU5P#zhtD0`VOE z5vma_&S2L)gF3gaAC_Y};_?f+@{sLxU>GkB>T0drs18*_@WnMS%+5#P%eiwK@)T0U zn!V|P+h2&jut1F7X(L9sUbko<d(sm@To$Ei@kp50erbAuv+buu@u2&O@&WHrE12u>}3T3-zoc!p5Q$vTR5MU7c9A zY?xc#P{k7gVdDx;F&Rg)g-x?ddt@OlQFH$Ygm?lXEaBDGW1W!=I5Fqt*~Bsf`~Ac{ zo=w~X8E(yqbLGfo@+tZ;XVS?Aj`eUc$8eOz-K&)*ttN+ga$YL3{^&|4eWd% zVCuo>Xg?Hz#kDbO$3a^fMl=ot7OnZqxE)JI=mXeu1}*xxU9qmj7LTi&jWC;ro!}Y_ z$L=>qX_qlOp+r9U5OvnVJU6_$G0>4X*#LipEl~^=#LYEf7^rNGbP(%Q2oZZ=v6CKa z!4$KKZoq|ntOFwmh8bbTMWpS?6aH@zxa>8mI zi@gqmA$uPiG59TXU_P%b_+x1w3yF}P)T?Y0aq{vbPo@9h6fWS&O5N=Iv5{Um~<8G zT_tt*q>3&Uc73@L0lyQTKC*q_4lK>< zCV`w3b|iR4faVTv7_tC2mgs(U^RK91=PiA=6*RdI(#Jw+G=N(SQgo@RS9M zfai-!2*m+`apcPU03vYgL|Ko9rotWUwDNg_8lL!y z2P+Z7L0;>?{3qtnrIgFA^-|@8(zxJt*zlO54aCbt2Z9cumCLU6V!@OA>zHA6)v=_7 zALOw9!5`*$t&D5kq{9z$xP~7hx_Xi04-xpmT_W(q6^d?L;i@_c+wSP+|`%COr91RD{!y6z>QC=9`h+nYcG05 zM$<%KhZTBeZV1yYtEW9x5Gusy3#>X5@;JnjoV(gQ1}!qj2?~$Y(}>+OSI6o|y zl@8Xq9?qK_3h~%UmWvI;3!JX$__WJ74bL@@hEG4#Ot_sPf?=;Cl35)mao}Y|E1te7*^V!#iUis@#NS6LWq(#CKl;lu}C zd88GO--O=BVIQ$AHntme1Yr#he+{hhKtX7I3LG+np4cc7*BN$ zc4cSd-C;7FT|i^mszfqU8|b(4Y5Sv|jP{l}YeMiCMx5a=Kw}l6XP6NihKd>j5^SVl z zc;oDAv?I(b0+Z2Twp2e>Z&(Rr87RR?hLx-GfURPLNw7_Mpc1H*lPJy@Iz&nC)p0%3IRoEH@iR$XQvqMQ5$w=%Wy6fW`5QU@I)Yje*EB} zYOuy)Bz}?Sbb^tMty&?&B`ga^5go&24Ho+lb%#|*PNw)k`UrPMvFnd`4bLN(7c`}F z@qm$w77`dAWG4tJ5o~i1g%Mz@3=5(N_!+ihv4FQi1|@=SZ1DvKf@Mj#Sn!0TRwQnC zv3y}_hF-&tLx;>KNN|w{p2o6AUmd22=)oKX?F9G7NYCABv_gFpC9zzYYcsqPt}zoX z@h+SIL*bZZl#G!R#SN2Di-?CSVLBSL!kvTC2>c(5$!zFMYJ zEVQW>L$uH|_P{}CNqV3V(c&pZY$$bywHppnEqrL3vwpNqy*!sctqEGS3w|0WbjeoE zY7H94I`YJm!`QDH!Ma79kWwzZOaqSvOumf9r+ec{zRh-EPE>=PV^<3;gDW93faN;| zq;`*0;w?MksdKX^v+z(Rs~mz0Y$+ByyN|J7tHJr<*D7*;D~8VVqeuxF1tK~u(i2tK8Oe#Q-Z_NCM9 zk*x422F71J%H0L~7z%dOy$btTN%vyg9OzzT&oy=};XJGBrE$@iyadT{;2Bnxsth6!Ez!UkXDW-LN{RKyJDtrl~ zeE!_TSaM|o4CA#geh2Jz_E^Jzj-loXAcN+a4kx~wV0z7VNb{Q-k~@Q=e3>=JRlo$h)MdZ*s}^( zC-N|_>S~xmW+zxMjcv|$UduT+{k)k62Uc+Df(y&ed#ac=bRz!J^G_&JcnTtvEz83# zW8~xG5h$@egTO16vCEcgiMt>VGdLKF4$hSwYHXal6>%(D|TajA|cl8hJ~nK!}#!M3eX8uLn@9m0ImvMsDE z23t%{F^TW9C7+g(tv0iAVfk`WH941i`l*y-_oN+*aA5$U2jZ;)*Z}kPs0$yh;Yp>B z)?D?+0(CTo0R5RYc#-8Oh>vt4XSVcXx-0$&?kzByU=GsHjfQCjZf=pNn+ zh~n`c1h)vnyJ4s)pDV66hT*_0>Nj0rJ=Zjkl^}Q(%WeQF*#I2o znFBQTRiQGtLIeoN&>7-j4{3&0V3&q1&|4eK zF#t0gu0tQ#6ry*-YIv9zL40Rld<&6##@IugbP4;O7^SP7ctf#@7hbTM9Z4J2n1Sac zTP{sw%;yBfUI?+F9RMo<21xBAKzEg3B*6&r&ZZgTT&!G`@dWW0H@*3Tu@x`GVlfND z8=l>6VX1A#Zv(W=;UPL4`TV98f~WSDsg2224~zvN9_#G0?hD1Mo8mhY}2^s!hDPvt1yDfL--;F_Y74-b{`p%%Ps39GWb9B{(Y zHf+#dqAJCGSFC08QDCSVb2scZ;C{%UF;RDJ*)WH;VV08(Jb#FeNm}gvlo>hN3GQH- z0J})|wWTjShl6D}IEB$(^kHU7qo8IcJXKAG6>P!O;#RUv#PJjWDLVVj{h6D=VvN1b z2#15x1;TtXRU3 z0b%m^5^ft#oFWTZrCJeFx@CwO!fh;3om?JYgnrY<3?>Pvv1-V!6FXzit^; z4ift{rmHYfTgpk}B1R^7kS*brMSR|JQF+5!R2CIlwAvmiJ%w-QEJkCl;F=xeHb}qN z43AG0CM$-jOTxP)$c5|nJmRWlSTsmht+hk=UA2x|k*k(sc9^VMV$a!zE2w3%syz$@ ztJ-a`JUO+~BrY}|6N(Mvwx`fm!|kG;>kxL9xVS$qZl{O$bXG+|V>^)#1&ZfeorDs_ zJNAx4A|6mPwVAAnkBnPM+QaK8TU}d;zz)x5Y<11lvDKAD!-ycZy0Q=*j?b0a1L>ij z_9Ej}msr4dzT2?XRZN&M0zOUVY3pF?ocnA|iYW^Mm92|MtJ#WbAs?{ALy%itJPD6o zZ*`#^Pa!kb-s&Re@O)Hct7|A<-@;S3x)imPltS|d`&>zrE-kc8kEFDk5Am~!L1NEU zQ{E!TOO`$Tne8Rvk!`cLQ%fvp(!Pi$g$_hSFk$A}5i-N+v@b$mwx@wlx5qrz*s~Yr zX%>!D7Nem%tqEQ_jG%<$$;72)%T^7QdnV2o^0B^P4O|Kg-Fl@3Vj*w$mcuP9!?FW~ zuLZwV_9#d22dnvnO}ifTSY!{)tc4o4z7$39nT|=>_V`#$J7p($6l59pWHBvYw49Gk zti!r->yo6M>vrb0Q0s+!#3PiMg^zOiL5vRCzsT~t( z%a{km(l-J>IMPK3e!5PwrO$BtR4(DuAGO=YbCxq76quX84BaLAHM@QaHU=z1#}kE` zGmbtv-h^U9&bq2N!jVwXORzt9>R>sz6%LNLmaOFx_h~D_(Ev%wt|jfR)+1u((s0#IU3}xC+WzivTdy3 z1#6X(21X1TnEtohs~t&c6&Lt*vbKtGTqhV0OI57p>0Ef7qhxqq0+U-^Ko^_fy9QQK z9hkT^t}ME69a|qd)iG8KGux!}lIpn46?AXu7y=%9xQtZr8@4|a^6(}0Itsi>S63Kc zCtWf}GjVP$GI6?i$wZ!w@^rX$xd{>}VB*Tt0q8jsH$$8-={$Q|Y2uoB#fj6Pw2AYm ztBDJAG81PL!(w)A8O%2ZD5Z7_bz#%AL&jNfAhp=F%rs4Uj7b(T?kj0n2)-G?fIX=b z9kx!b6G0-^HA-j&M9TDUx;^PqQaTwC6h@j#=L8+PAK&#_i$z~SlhPW-(C}b=@WT^V zS7I&ezg}Hc8C+Eyn@rb^jhd%pLjfmKfm@%6o_ukc%{m$1OumZo%)S<4)5gg+temL$ zf(r zZ6+Bm+t^@N!+DHe!^v7sHtA3;cwNZYm1m3a5VwsOJUMB&+>ZHCMr8v5&ldM$Vpp^q z%kiW(-p3!elQ1|lFe4R%08Ao7IEhFrjMo|l5*rd1+uUO!3=BhTvUcUtQ}9)_9KPO` z#~0qhfBbspcKC0){m#Ny{&r0EN@n4|1MPRWWMwihe>kTp`0URZuI+{6ZplTUJ22P4 z^&}aaHVbUmCVNfWF8L77UyUzboshdV=}(sAmf#$FFv;tZ6Ou!awo7K^_+`k;lC`zvtq=n{jUe@^~T) zwDa+MWb(S)tAY6rIM`qAa9rIt`9yMMatygnTY%rypnf~*wjFpS)87fg`S^(4A<3qI zK}`<@v^OYGjM$uXr|-abGzbPbTe@N9Gr`GJDkss)YHL-^yIjk{RZB| z%)o!U{(&qXRCm5@4t=|UOty7svw<* z*4QuB@gUT#&wA_;$pG$=mY6{#wh66%HF#EW96~xDsfJWXY9I~c-U!kt>OY3EjiY26 zaDD;qy&UNkNUub?5W2VsExkAL7bCq2=@O(@qt#!7R(~z@c`4HCkY11U2BbHF*JVhT zgYHd8S0H~S(wmXqf^-$qTan&|bT!g7NN-2l2n*T;_-i5a9XQf2z6)jgH>B%u?RwC> z8|ghr@5QzE;oAF=K7jlOk#>Rgu|H0h^&y-efqRF-BDXHfZ8Iae1(;7FeG2JT zq)#J#2I;d%pF{dQ(if0!L%JR5i%4HW`ZCfTNMAv^6X~l+Ujy&2BYgwun@F3G?n3$& z(zlUVAC>bvp#Lt?_mIAi>pwuc8|faTE|iu1WWv^FBtHb*kC3j0Hhye&N*x@P+zVa( z1bX=?dMtg_&yemzx*T}+gZq&lKza~*`#HYi8R{L%@e9bh0_h>#pWF^?^Isx8jPwZ7 zuaJI?^eEC}NYe4+$Ztma4R}0(^joCgA@TdVe?a;p@=qfD3F$wP{*3e&(EkI zIu`vg_yN|7^`BI)+>YR}6VlE|yCBU%+7;3F0QkY0rJV(>T-I>o=0mczGkb8Wz;NCl(?NDGk`AuR^&5~QU_ z%aE2ModjJ3fAGTGisXg4mjHh<(n_RNNT&dID$;7uqHS|)OuxtF+D)g&BVL=4I}K?a z(&PH>echHA&14x750sDZTuyH+C1>Yg0^O0&u zb)*K;Fz&NWN03G_I_+ZiK{-3*#*oH?-Q+ez-WP!Dn}A_Ix*Q38Dfe=uS0KF-BOBs? z+=WONAzh3FADe@ZWgMA%4HA584n8*bx+Dd9M(*_)Z65dYxK0e~UqEb7K)nm7x7988 z2D=~X_(tR}L%JO4O-Qik+?7agMtTc)T!r-3B+b1oY0F&={ak}`?}CvPelz!WB>MK* zNV_1v-bUF8eW6?!*A}4#*jIusHkvM8kh?Z{LGB$$?=-zE&b=!+Aop*{vCz*Bx$A(N z&h+K}Cq|Vb* zfKHl<_yacP3)fGjaD!;9ipZdvbd2sbpR5 zAITZHEy)h~1SyxiEKhp23EKnh0==){ydXafgV=PWZIHG_nt`+(5~BY6_TaipY}X$r z`TP!uN}=OCV$1wa$@2Wp$;tU$CU}xR=+~p%>w#R4@=ymHM=Wm7&qBmHBUzt^J?Ams zfb4u8wuzoSGrt?s?(n?R>^|c^V$MN(kzVKd{2nORo``V6^%;4LdHKCjp64R%gNS#B zK%d_?c|m?Z+{4(H$Jhs&8TkW2a}d(=P^LvV9&8ayD9<4%2gcO=^ARnFGR(*yYIL2b zGii>@ABOvwujDaC=39`*7@0p3a*jd-6zcVY{L#r_`4>k1$AAW7WqvM3dGW*?B|i_* z-A=Kb$C_Nm)HCuJL-QCz^BhCrm+}}#^Djm^5otbB8zOe-*7S$5lrcE^mFWiM=|xYG zu4d#5pkIKr5b{`8jI;SArqc@Ag>)FHGWzNHr8wIKQGY1s^gPDm{Bq31_cH&G&qe>9 z=h%!k%dbFs3DU{v7ijG~#^yZ6=KLv;!8T`oPDNUcgfTk52B{rsZIb3s%lr)e$pB;y z05yPevCU7!`HcKJ@Zb!27t}J3bByB{-v)8TV(k1GcJBrGGg1HEP)5kj=U;}p!q?=_ zLOL7eIR|#t0h&Y5PUj*OkxEFN*?7V6q?*SwS@|+Fcog~s$J%e;*kfbN4*6c>D>kOs zc#=O4<>|BX%*glSh%q-mfHte*h;cs8BlM40e|ml>>g#-z4RfS?9jSpdj5LBYiZq5a zj)XBie*rKrM|uU)E0Hb)FO1!JjNN&R!}&{)UXAn`q}L){iiG)59`mC-eZvJfz7gp% zB*X*xH(5NhL;ecX;Yy@8BfZ7^^^E*gXgkEZ`M09%4@1`5kgmr0H7N5 zBE2IyKmX38mVZ}reE#1+a~;z4Nbg4C7G=;qKHC!GY<>x5mpdW<5u_V}F3q+u?&dM><}vQ(KaPZP zH~;TQ|AEA^-;5b3{qgHDGi9H>1?iK?X#P{lSpHVrr#?T8gt=4xvq+yq`aIGXkZwb| z9qEfm7+3QcPxE&m{}rS=QKwGu`YO`ba2@lf{5O)3{5NsF3HQ)<^LHVA3+dZP-@*Ow zB7G0(`$#`Px*K|jRYPC-{5{Ed{)d=3A0F%cBV41ey%*S@;P_J{jFWkck$H@d`3I1H z5b5Vgzd(8j>6b`szejNV6%yt?`A3sw`NxnRN5VLm{|&A^f%IFm`+WX)xQ2O8{{Iwq zCh$6yX#juDd6(n%;iBu_hAg2)H#2CNCQ&n^eWQIcrKF-w`(BhKTT-a35wdd$Q4|W5 ziCm#YqJ@aaMRxOl-tYTN(_Brz-~XQTo%1fwdEWPZmiHXLO1QS2x;r@T1pG~mzlnEq zz6bWgKDjX7PX?ckzp^=4$c5qq+&?G@ZX_}2+pty*>(^Ky)-{?7Rf0S?lHZ9~Q-)&> z5RaG?kms0kP#%Z}Oa*j7?qMqOo4Q8pQQr_3n|vq$?7qRKn<`Khj)rQ~tqwJyCLF`H zT2LF9bLLpCk?R=ZB!j+9U9MrrO<~Z9=4cxGKh9i?4SA2L2jo3!@64Z|J~V)aa59j| z8SJ+?4Oy|P+hM=SG-eHSW*4NKa%}gE@0=xQRhOqi0c;zA0XxuX&?4{u)T)8CUY6!A53$&oVwcX z6>udGbr|fcxrUW#IbMs*&U!vKp^681v%BUkUtx>r}`Y%!wt}q-I|v2q`6U^ zGB-(k(~4`Xi|pDkt@(XRrp;TKBTv)EZO{hV0yfm#fiB3C%w2Fdw4?kKj`sle(qJ#m z{eZnBM~{iRVuRf@*iD1oG}ujp-89%uL(FK{TQck|nWvyV8Kv(m-9$#dyE)I6jayK7ZAp9$DO zgB>)pIG+vJL4zGMb2y(1*g=CGG}u9d9W>+>W+7k$4K^_7=_BcE7IBX^4d!E53`>Gc z>KnQeyXY7SF_f53U?~)He-FERdD7i13weB3^Qm+-%V7nqgwNn}`uT$T`#EA4$-~5~ zg0EmTd<|=0EqnvtvQv0$hzknMck-C|UV4~yWJqHf-}Ul@!A_bDun~TQO<{f~W;5;o z1Y2M${WKQcSI99x%j0HS@S7b?i9BnzGyi)_2eU)eW~2;$)ck^c&4Mn}zV|e{xV9Vi zV7IaL_|$G@FHuZRkVE&y4&{vKB{BOzpYH%1BwKCDZkGV#XtA$0lHN8ZT*tn0A+e0V z#lG4Eu&Fi&jv($>#}T_~%Tl%+Z54~^pwO0==WMR@vK8b7TTx!Lm86d)=eBv2!Oq#r z={0WiIWK^tfHwuUN|;|^PugN@Ew_%q+Io zVtXyN*Vd)ZiBKqw>`9Wc^|*!%njcwgt+`bpXQWU#%THXe{6_Ce%( z2p-PJ^$6uvSC7f7yy5!2_BH3z^*q!*PTg-o$Mgvxjt|dUT(<9f0{xEHW`ikjvVx&<(mn59kT( zzuR8$JhJp=O}zjw%5ZE|X>E_NeZqXtwmFh`r?hf9XTsdDedTqjbl5UgY(G}lpOKGw zfQ*TKiSc>)kdD*_pJrb{zW%hAE2E@&scnfJK$(HG!5G*VyI4lsCGZK)wiJqC8GH)M(bWoA37=8-bHGp9FJYC8 zv0uSz&cB8=VayuXwdhvY(w%t2Jle-!+Hc`I_#W25diVi0z()8HHUYVWWiQQcfvrFu zVaX$G2|o8aj@xCN)aSSZvgLPj{tN5^_Oa|9*bDnW?al!>nEv1Lxrk#7Boq#(=Nx!Q zpbW4t<=B^UDJTo&pgiP41t1o3l>nROcs5rV*fVkka1`Lr9RAEzg`=SwREHW+6OMse zGM;_k@mR(2_+E{H$GX}w&eefq;W#)RPJp^_A{4?&P!IkHe}ekJTR+#3Hct-iP9QeR z+Dgs26L$)8yqipvhUx3>RI%^U z?i{Y+YutH&y>q;eb{7J+$6XBg4Ts-wm(fNuNjZFmyBzQp?n<~yCOG_r!%sMTg!>1u zr{dUCaoBHnJ-=^&mT)6ryIm{Vx*1xt?s8=k>srVajp3xNi$`tNT(eZN+!y|w#caH%!I@`C}o0v84u+{EKcnaF{oE>C}dzuKZI_NI1 z_Mh&j$UVb(N15b0F@BvTKbj}`t_xseU03J^?8PvB#r5F4Cp^b_FThGVT68aPjXc8j z0rCjs2yvwAhrV8dmx&g2j=#eF{xATrYYv;{uxaEvIc^A$SGb`tOr~Ok#l0pC+;Exd zM!-nGwz1n7av3*Drr}q}2!NOpADDh`Tb25wDLV$4TXH@Y#>sT@Nr_tH0R~cI5M}8L z%bR{zP7b5q!HtIrT+{dEugjZK7X%`C(@o?W>y6ovw(I1ktSif&t#y;22qwc6c!PU- zoC?#>>vZ6K3HjtSHv`#bhImTnk$y>(IPw+uHZp!eKeJ#qyo27}l^Jf1%ye_PKM&rc zJ#rQ|A2}CruFsq+Z}ImnBzp@vQ|<%mekgAf`=uQFezcKti!w564!BTeQ9g11f{)Sv zVpt-xDWAAcU?~&>HrZj5-Ew&cJtq#k?6Ax3Ga%M?U%;2J3fR+etKn4BlrALoi>!}i2>MyTd|yCc3x3@f`>Np`C?&(Y zThCZ|6Y8hDm4&R)h16L{9rY8TAFnn(k9K{!KlGC0`6|nokq?kX%Y_`x=TPPd%I3<4 z{5>?TnH=&Xu7&*y%4Pb(_j!DuuOR=T?ezN=e$$6|e4(!-A5$m& zTc16T@oq$2;-jdAEY8Zqyw<(Apr5#oEI~I~N5|j#%EBxUzqO2b{HZTUw}GtIA0R`dU80k;?vF->YEYfu&4LWtkM6rK^EKEPV@~^;a7@t4r>rBr zpVkd)5!tM-1+_uXkA>slcv-Gv;7^bh95wD;h96o+?PdI4=IdtKP#v6@?q6l{g+T_* z*Ryi0M2=#A66MQtzaD+AV3spi{2zl%D&yzK)y`|4S`qL$tR2hR2|Dx4Yu^AGGFMK< zLLCvx#Qu~+oSgsKUeQ&ezRWvd2l{l z02jhV%+ieRe%lwZX86u3)0f%`tXF2fvM1{K=FVSA8r$u7quQrq9i`Axz1>G&tU72FK1 z;TE_RZlg_ng>QqbZQ*vfLpJg}+GgVMmtM#3Ze%3J^7qJ(%xxkO;JGj}*}Wyr*VKOo z`@npSBl4c8D6JRE9tFDEM7u=xpzm_NLB4zGU;TG38JrD$ru==JwF%cY69bSnKm>Ip zux5i{~Ai=N+5xgM7M%p5r;%A#Y#k2QLA+t$zjj!vGja znZeA>L2?iJO?hHGor``5&#pRn6^6=ITHA_5Tait_AJcc0s<*V=877QwMhAoCXU3zn zG0yIZ=sVAJAFtty$rb!?ju&wpL0=jslO*vKRic_Cl2u`)*@rGR35eU zT7Pf0e*6G3y%DbMLr>a&=-W@FKKFRPyFc@6S}%Ot%i7Vks^26W;NEY))lNKdub(al z59x&X*U#YEOdwkI<8W~7^9I=KRr^Bxk*ycT($%^1H{^X9uP;W?$K99?-AdqgTQ~{PVw)j%lP?fKO#p4MN|Y@M(Y!s z_yw>q%yHGdzAp>kdT4y=KY$P6Bj%IZ#6>`Cj^9oE$LMJ>EMaZ5jl4c5`E_b;?gYRJ-td|1+ z18jhe(Gl`!l=44D{96JL(0(_;W@P$F<-$UwzgtiFE%dXMXZtyfrS;p8y#%(?#tztt zz4`@qacy^0mN}UIp7&;a{3!If2lgU+Zd8srcPM}M`;d!$0>7VosvGt1SPjpf4(~zn z7g2d)r^FwW1SKa@KFZ~<=9P!u)0qyO^Ujhyh4<=F1@0$F1Tj!IV*Ml*9Qa5_CVUr8 zp-P!CJCd~^30g=Pfke-dQDsZYQl}i02YQZfiSp=)NCEKKI>t$bs515An7urHhj-Em z^F86+bHeW=FUm_QLp~J9P;8sp82#?MAUO*D5LHg9P_8N*4b^mBM){P`ec>d*2S?mz zU3AHeN9fn=r^F@PufhG%9BaZcp=@~1MS0#yNBK#us3437@m9vZS@tY+e(8K}E-ora ah=&v6;e>cNAs&|8b1rTAH_H6ifByz9qNqv$ literal 0 HcmV?d00001 diff --git a/release/datafiles/prvicons b/release/datafiles/prvicons new file mode 100644 index 0000000000000000000000000000000000000000..de3980f967662a2c685e548a9bcf0202c66608de GIT binary patch literal 13732 zcmd6uWmH?y*XDz}Q(TK%vEnYp-KDrYh2j>hP`r3?cbDSc;#%B_yBCK*=Jx;2to5#$ z`81y<>n1lVxk=7F_w0S1^Luu_s;S6gppu}1Kp+fxIcW`G-}~>5j0ikxtT`e9J4ACu zS!rMo+#aPmf`A>0tDL?&2!w|B?+ydX$RYw>MEWeR`~hhZnG{EWnk7zt40wtB^9Q}p zQZ7zTR?eS6Qf^jepRFvZyzD;PQfb**QOU|Ht6f;qIfFn{AbDvCE$@}H03Uy?`NvoH z^DgeBksNe+xh1$^bG;9e^b*+k#fRBTaWs&yO8P0n&B-DZY{Z<Ets~6B84+VGs`IA#c11VL{Teva5veJ}x=I zHrdV66QLstKOGis@?#=lQS5SYb7Rrc)6*A~lvsbhm%8zMMeRhY>2P6`$6cs3iAO*q z$aC4~zP!JeH8+2|y}iw!qL5Ovc*5}H7XF`Ot3ZgMFnxV}k&%&LD&%SV=6~DCEs=m5 zZK+Nr_l<8rR;`Yl%Rz1L7^<3{9&)zIqIcDdElD^dCnwH81lGa4{q5JVurN~pdP!fQ zAOvF_aBr`;UbRlC`|Im#Y;I8z?a#qM)WE<%ecvw8g+=C~mTTQjD}?Ez&m7;CswerH z3Jj_V&aR4_jal4FwbgF`}K zf!4fbW=55Yz(kn3mQz*^pRo;Nj0z-)rB|(8#8OaHWV!YHU!MnYIIX<*e>y6~{(uuN z_R4QPnT679aHeHFQ}6+3y`uRUU(EtmNfM7O}!4vuQ>yg?cwbU0m zoyz&~YsgDCmH58_!_EQ%AxjQbvxtd_$uOl5S&*3E6f~92& zFl=5FRvsf5PgKmc{R&!{()@5`NfF5Vi4g?OsObfI~zrBUK0>vaXS;CzKHW%h4; zJ7G%>gR$iZPNopQf;o1A9lgxWZOEPs_(WBC6=dMqJ?}-NM$s)?+zTB1>sjp=iVl7+ zijb;N|2#8y({V}MegvKmWA%?YCb?yV)@d+aS2=7Z6HN6z3_c_3=GsaR^it_Pt3IJs z6b6&cF>T456_)GTB8xKqhf*vMMln9<2IT#r3Lin-t{DL;k`pa~L#_8&k<9uhhW$RF z<@`P99X_~Wr>h#5*aC!&l&5qBgU>(&s-xaRm;Sz;Z^svcy_s)kQFriJ6tsDo;$~@S zZI;|sGJiiFlMMnV#+M@fo#RF7m6Q1zy7S2(`S4rW1_kd^87u@o&j5$17|GUgPeAf= zv#EWr(VYQ9N>5yK`%AN*Vdhi8IBSR7uHs(hPVSbKAtzBc>_BB$T??_*Dtz3oc9n|W zarB!bSN>6Ai!Z)5dVRN5AX)e5Pj?Ce)^WsPuUirzP;Ast$WQfHE8bk@aBWZCw92Zc zO~OwV9v~k=ad5QZGk2ZpsHmLYUZ@ALdE@fazb5n%q$e@X1FQR!^LbqTJAT za?u^mB*&kfPV?kqNXeFW8HkVslBltXOpz{CVgD)u8zPx2U1->V`=5#?>zQ1ctpk2c z=9FW`;{x$f+soSukYW5s@#gtBBwSeuwx&2_(X}dFxmwI2E5oE>DW=nc@$&^Xp(a{? z{iiRNR!5|t-vqY64BM?^Yz{i$m|{_v{6R7WX+?P(MW9Y&Kbr_oc$}9#K7G5yYkfLI z>HD%B9J`45@jaB~$t&WXf8??9nNCu#A$loVb#JeHYJz1hNG@RA9v`P84u4bQD+L)mwkEtkVmjgxv8L32pPGrd6arEf)OjfMdj$}G3K4x8CrzjL9hiIV6C-Q?Z z)}twp#|02XW1Pv69=62^h~N@sFvYC{zplFBg)(1Z9BagV^ms4}vZ94`Kw~FzpslR@ z8J;-xgEO9SV>n&O7#0@G%OV#%NJGf9mmli%IYh^QfjK$R@cxkn9Sk|U3KaSskY7dTe%e7P#dOu}Jar)J0BG|eH znzXCN7kztKPfdza>9rS*k8T$~71b#PVGeGwia8Qd3pAk3ZlerhuQd#8S@|EKy;+(j zEz@GoG^loV1;6>Is^aPs`(`!%z+BD}8CUkkWmT&p7e;Wrhky@B_kE5S+dZYyNvRfZ z-s!*yH_?FNyO;ttvmT+(%Mqtg4GC;-M!c<>DT>X?xkgtxE`oJ8nw8b^%108giOk-P zoCiOMYKnl?|0?K7)j7JtJJyx)fY`YdeJam`ai;&%uD(fybj|^scTTNY40!|>;o;K> z%)+@CMjSS4d+|#EO-3#3vyU`2M44glui*-yVYpu(^-M8WW*Ht4OqmamJKk&W?||m6K+Qw@y`4Ify-F5tD@AR~Kn34h9hx~A)N?B&u=aUNGSK?9M(mU$U@mDU zc~T|DJ&jvy1l@~VsBb;&&pYub*qa54UP~?%V&Xrm&}B=mt1xWlv4*u@7x(snTB!sL z0=h)AQm1=7tLs;nL8?^)>sTUf%AC-*Y@VS1 zXbtJ>R-V$?qg1%V=n_^NE(@i%VZ$+;-?88F2+3v|IqJhb8zGYd2`d$OG`%= zO8~!xql&)6J=kxhPccd4CqPGMmCHaOzEykKql3`OKu>QykR{;W?(x;k)00;vTQGch zSPoEk%<{jRl9QA1u{uHFJ^j#(0`bVWxF75vTkBRSOlM1!If&4`Z)RlsK9ONk2oGCX zTT{p>DJcO`=IqY9xZh-JL;Lfycsi}TUQeJ10jnOkJK(v0V}tVR*RPS$(K}kq+U>@* zxrbxC`TfwR?Ts^3Qw}0*GP0P+NMz&?P_+&kuyq;7f1{Cgvu_rZs$CpTq2&yHz*u>`>SX54HX9mwoawHCtgqx zbWl}81J~Tb0zpiyhqcR?^2C8%d@Cs6>caECM4&+!^2Z&P(5vb@)xS5t)1W0gul19$H>MO{>!{?voDl7s^IB( zzVhJK_a&jJsma{L8wM465*^gS0yd}~e7M^AmXrjStr7u;gqfF@2db~HkBo}ypU#)+ zyB5~a)HHif0(?WROyS7v$!+NG-@iL^&XoVP@_v{=9_aId(%e8)b^NP`op=jCwX0Rm zt5^}R8Nervgn67Sn2n{f87LfOf^xuEN{T>Vi9tjfsOYJwVS#2I*TYHeWn;RDat83Tux7=LH!eoUQP7HtA=DZH$O1^6` zUqDT9p${{01&?Z27Fnn_L8H__nsTckajU7ympJM|OF9ic-B6)3k*x#)s9lp)TXsScGeO zXi^Iybv9@igf5At8VFt+3WV=5);1e++sv4God`{m2oZgJ!G-Tw$J9?1&`+HQNltqP zE*$SK3KfBJ&nA8rCr&zfCuXNc9jYf?jt*+cVG2!V^+f7+tH2Dk{NcY)Q${x7bv>3l z0j205Q{rPJc!tYq?8HB~Srud5f||O`1GvP>q>}p>2cp>H3rx}p1j181V5f+P3iHN` z1>l!Wsu8D|5Qe#RsC%lOG6XI@-gEwLaXFP!=K%|yh`F?A-pPP$1dBmWI4^7Gk9(Ln zI&e`>4_oK*1D8j#7u3@mlw$FeTkZWCEwkpDf%&_prA3#)8@M?xV!up_7k(S{OH`t7 zN(%87ICFhBZCu8F^JX6MUP{xLit?=Q7=GO`?NiP00__c;eD)XcVHY38w+alMPYDJ~ zq(4`uz*OITKTL;>IW0Zu6j2j|7yCFWkvtlV zksA;~%x!J@x6U@rs!$8_*u;skF*VJkYGln1StQGR?UT7kYb1`^&`ZI3gSNJIx{%j9 z&x=3ne~Z;j+(U>hu=fN5J_ZiSMgB#$d9n0>ianH8k7EY6a)pDyMgi?+_0iG=Q0C_Q zjxlH#DFb`j$BvyGofe^YeD;VBpER>;&V21)=3wLPW=p6=M94vTGq!G9gd&)fShC3F`sKQPK5YEcfmgp9GkxDFCyiedAm%0b>+40<(1&BNwgqp$F;HCM#7ujj1k zoiRVFJTq%=LuH*$Qf++x_~KsJoc2cfZC_mu^qfZad$n(!CcyI35+{4q*zm17E_HaZ zTk6YLTGCoiyb?PW?9zM6iTl7z+X}38&0)14-ceefvE0Qypk}MXuBrwhAY;v!b*!*u zr=)}nU3B6JdGVf~9^~H+9~KOC{*;A|f?CJZmvYx?s!tdEg|N$&Z1r}^cxC(@ZahWuhUsr z2D9i?^^&@D&R9PJ*?gt`H(W+R%NP}Nrsi58=0F~!~vhAyCWH{#w{wcUSEGWvM> z+kANZ{#5Sr2jRX1+oi}3+-H25LL6W&f&&TP&S~m(`wRRDf(ER4Z3LX5^h_;Ht0>eR zVAu*!NS@x@O^8O&NG2A&0r3_(*A)+`J2o^Coa%hb=2fDy5xZFH97(ASjuJXCgzVF+ z4L}Est{$#KTYOKdePmz+1+jnZy`-rb8^;9>>}>K~Is13sv+@Ss!;!%;&{Wkv%YQlI z>65$y8`A3|*?*RFy-^nB#vWv>>M#kt^Q7ocC_h^iEv7j>8_$K|xZlleiRK!usCGi- zC;C+uXhuYVhZ@9VQcH{8aew*^HO6Wgx3;SYlQKaWT;&qveg^@otrD7QG(|5^-dfLa z=#IXgdlB=SXl>0LygXd#*X+XrO)S~q$4>epxDpqYB^Zo0G@EyV7aa8B$M&}1Y5O*1 zs-TF95bFI(Eq#9yFPkd*)r9rqT>FX2s)}O8JL7~?xzgbFmrd<6u}H?d7_d6=f>Euw z-w-J_BAw?hY0Df-9~o#NM+1~Y1F~>-g4Bug1d6%fI#Z}&zBNMBoBeXf_nd+|Vq9~K zrvQ<~sEne|^9oVek+ABHU7$480J9+ICGex_blAAVqtzfCrpw|}@iI59a}mbRkL)~o zn3(SG*8kIP-Ou}#gD1LZwVP*YCcVRboZg$kNLk&hvUH;`&AN*Av4hdg-~Ckk7w=Yz zajS$(zIZNVf&|~ozUY89U|LDR)eMZN!V#CCHwsGTETp;Mt!AVW(~nD7oAwO`0lH!o z!g`0cYCcWTIuzB(dGa`JYJB&DDAt*9^EyM&IFvb@vp=ia1dnrr@2V+=SDa&6HacSJ#-LEDVF0jSuVB$rakSqTLV7)~M?AaEu-1{gFg;92Q zIZeja->Xf81tz@x2&sGwXQ;$rAxUlbiiHTmL2an#WCtUkM{8O@4?{R5=!-P`wxzLr zrR%{V%of%5(ZYhHVYRSFKK$fCZ9;4Ec2QB0j&SOWW1`nKK~5Cxi`6QQCFu&L!w9C3 zib-o2or5QM6t{_5(Epou=&itWf=4l|;=(D|G8)8Cb_qEU!XcX3#kbLpD33y#YMqdn zvw&CLlp=QvQAJS%CEui9PQ8FW9*XxSZ>VoUja1QkJ0JQU&gCd9mj%{{4@+V5n^h(Q zh72C}M`yN4E(yJa17D`H`Ew4ISy_-a9<(bt%7%Qwy5|=O*Ab6Hd^_y-8(}bTh@0e( zZ<{jSvYK?0ja}bw6-Oj)9vnod2blyrxroAaFE<_9v&3Vb%c91ndt$FYqtHKA!EearM<%H@%roQ18Z$(rS)^iZ6`oD zgP_kFSAekGxd?&^8GCOb&@wPcCDO)_@?j3eQ_2Pgik`RbU@~mE?01bNYvg9Atm$tZ z_`H(prv@D;Pxf@vUyX`JxV* zN^I3?nVs$9)1?=eAtfGYjdMJZ$Ejr=I64`ahJ|% zartyoyE91Y@-u_SVa<;Hwm7(M5;aIoZ5k&<;a1|qhj3k=N_b2~>tALgRRk!>%6>4+ z?e9Hao7t9fKJETIm@!+(HGWiv?l9-nTX*&O;Cj_*iZn24w%}3vS>YchWiuo=R2}n2 z&$R4>RwG@FZY&fYO7d2W#U_w>#O~pGU#j?X^vz61TolZ9_c zb{xTLOApC*P9INKK-ieAb$JAFl0l$5mFEy+w~(!g;JSVOPuuX_kiUvb*@AD}4<->n z=;VU<4FK~5lQIm<3-ui;_g}C;R<%L%roCBzteYY@zD9h+a3vA1p$Dk|SHH4WWbE#2 zRUL32K#cF4kL?(X@n(`KKZ}90D0D#zO#2g=5iGhjn>+DhgI7C4oNl{v0BrBIZ+^?c zF`aU@ug#GDaDUWr`3wui>`Lp^-(-ytud*@96wjjqqaFk~Bk?2Be+8vJZ8ugKcac2b zow?KbxvTLZp@Ar_qhRM27Pd!ISYk(~r?&|S38nBqc;Qe1Xk@J}tSTbE?U56_Bc%1i zq$g0N{{jsnRIAf=kFUS+p=+SUjyAe!CXy~Wsvlbd5A=2ESSAj2BlyNaJ=tQwH zVd3FzL1KT#s}>}-kk$^WPRYNYA=`?-1vV<(V186_GDOGa&Y7GvuPt|Xr#)SZFDPOY zK~Gt#Vna*y7TIwvPOJ0>`}@WmnG+F8^s{Y~4+#`kFucxdk&DKDfFi#m?uNel0b%8T z*@tu%P_0`kbLs(kRO4`BO!s8fm^@9oyO9%?=s00JpKoAI zveHkbEiV%7GPRM)Lk$WKN_*s^bldwZxb6lDm`UDKvW}4t!~V`m4}cx(1KUOii~}pl zNUfe$Bj;8b)5McZ zS11l)jEXf_$P1r{KamPT2a#b$Bq8ES>NToL>Fco)l=``n4IxukH8dp7>l)}T{$_%_ zdClHeT@g5E^tVDR{l{5o!a5KD=L#0QOg6NBKdUOncJ5?`6fTyKoc!JZJ4_atdi|YZ zOuegqY6SP7v5LI>^1)X@?Dq1v&oGRt^78c_brA1ngRU^nJC|;=Uw}=^G(Mg3Y1Q>_= zB}GLXe0wwkaeivmI?!AyWc917s|@)hdKAEEbLoC8nLv{)yu6@)otc@r3r8dL%!GAZ zX+i;fz3qFL>xpVQI=Ty3?~)IXZ9r4x^@LAo#MfVgNv-5RFkQE34v@+o#Og-@oJT(_sO8h69o(iQVT^IO+uW)u?8P z63W-;=+In~q~Bt9OBOH}UH5 zFE#?W3>g#CdCgzCa$Yjk>hRWAF7fBy?ylwG?bDT=ot-{~HrV&Tnsew=JR%}u#m>$S z9KBL{Z$wyFE9=F@MLeBi>O-w@*Aq>(&Ph6#Rg~xU&#(S~eb=Hrd2=-TymaQ7k&|OQ z1JkGe;P)*^_g|XIuCbGS8!H2+pGrN(g^Py=JO%-a5In#YeT zU;e8zg|LZ;mPT2x@9$mK=73>=(!h$A_ReVZ_sJ~{(2;-JKfnOv0T*6kNyvJf$oG1J z?|Eo&uz=+o8-V4UD`No9Sp^Ll+55Xj1~xW!UaHk&A;3!_NVooTCSDSyvwfEKB4{0b z_=#3+5-3^-2naR+U#kPM)c_9*I5&60Vfy^(I|zgi`Bw|z^~a}FkeWI;l#nyv>9a)Y z-ZSLo#pLS#{sOugiiN0@E1J!!SJ!J@uP5quFB0D4_2@-dP*9+zsR>s(j|x!7JZFpk z-@i2g-B}3WJ%VV2P$aA`j8Vsxy0tlrC$~}nmW%4B0s$dM14FBv@qWZ1g%Y>{c62Io zNS!$_8Z#m&d>L&=lbNW(Oz+RvvEjG0e0`rj@Ku-gZ$v{n@c!Qn;j=_o+xHo1B`Vn! ze`S*M+S^IUhRT6d5>2m~6JzpntP8`p<{GN`{a*$iH$G1LqUNI=RctE&1LaK9e0XcE+=Jj5m-u-r#v*cb#298pd?(tiDVP4R2? zB(Ptk0ri{l?iA7G?I*Ye3TCjjV~`OtT!PEuW?E=-tKkydnAeagr2rfxp&Ywli0>Vq zQ+yA@|0JZXMu981QeV)&p(BQVKX`mrPfKszLG8VUOfe{D6kYAY$tQ+c48>8iv0=c# z!05HQQkN)a?sI*J(sZzHu>fezoPG1_gb}gJ->G4?L8Hp<;Cbq;bFc2cZe7B+f~<8z zk7=3Y-p@ns{07sHSr9zflkOdM?Y?i#2*WF|+l1(52^5ZCis!qgi4D!evdcvzY@%W< z^BBA75tJNQQ2(c#tFCct?%%VspB^sFVn}#U0s3%wS@R84=dvM+9O6pL##UXOwQIbU z>%=(F>DAJIT;@Q8Hd^uNA~&i2y7&=!!QMBfXM}#MC6ilSZRXLk3BLCsZ$TgHdo{^+ z8+mUV`NO?qfdXhDygU z8aw~&mWDa*3bfB@DtKD4w@0b;sE{zSl2AI^m5Gq94t~!=W;8K6Q;nLCmKFiH7Wf1N z=I3i||M2bfeE!4Q+Q*MwzS=Qyaj!0_^LDZiY3Z!#jrMpoI&FUnT}*UDQ~ev@*#8Lp z-hn{B`w|NbX8bVpfjyMHkyX+Ijq~E9SPNmAFv41)9W#PE>eBY`O2e%bpAL?uuIUA&FW*}i;3PQ(6AB;VNYFn`>2(_ zdJ-IHU)9P$frcxaALN}d+dM``@87h;k7!~qk~@xw0Wn1)`t_a5Y-dfZr0SNAG(wwD zqGq^ywb5x~6}vGBX9r26hbqVO7t$dv872}YxnS7M&F7no4N6tvEBNi5of&epP)A=)7lBG3NC=d_AJu^!`##@L{qG*3N@muAs|0d^vdHK*|Ij9(|M>91b6l|J0%_g3KT5)fVLF>D zC?a;s20paU#fib_7^XeUY4u02MwE7?ju~L*tUo3A-JJ$gAp>z-{^4I!E=yy!zQwm# z1bIr71`bR*nCu_a3NpBSY|9sF1A=6Dxc2k%62>%w**yyyr#RtUTnD41LyaE=4yEgG_Qz9;M=*{$`FWir8_RtZ`%P_Mm+MZ9Eh?u^5*k7tMA;(+C zaetzv2=Cqi8g+Pl{3js3JB%JkvrHP7*VGSYb|7g1KS+V1fy2>4?EX5P)}Z;A^W7er zO6+lERcM6I(_J_v_@l9n3|N<%V+-Yha}mvgk$vMNdW!-G*}z69a=~xj98#R}ocHgu z$e5ow%!*|Fz=g8$Z>g#CCqCvH{c3YRP}9&b7xKQ`R8iG7wt47zRc01l&GcatD@9DG zGPs;%+g@bPI>vl0w=q%;BwJ!2LQ9hIVl~!tL!=^WYUx2VbH)96YB_CBD2hOXB4WL< zm@3XJj40>Hp$~6~MD#|Y41T{ZM8Lj}tQl+z)0lbk>e9u1%-FxQ^%o0o|0G8NTEF@R ztPurB{!Yl>F^clAf5TN;9Ri|INSPsi4SK%f|06Ft=S^0mZ6UKpwIq!qmeaZ0E{TG@ zS;lXv5$*s|Dib3gXMFCv2-fyp)n#EfVS$dN=zwhvjSN4J#j0JAlWOMC+2nsUK{az- z7wxIo;x-ez3y&5>7il=E{cOfi<+tHUH*F-rL9}XoWd;G9YfNah2ws^cf6%LNNJt1a zA>ra#ifO%G9gx)d$>M^1D++{0p(jmb!Y$5}1p}~G4^BImXHh;J{(pm(E?3)}E`mSM z#W2dhv^Cl7NuyX|!{or$k%|}5S|FVV7ZH#PNfRZ@xIZDD34o>%QDC3Js7dD%Z@S zXQ&`jX3h`Kl%A;ga4F}P<~nhkU;O_0$ODA~IDfWoZdkWLIrm7D|XO z{ry|VB&8^NXGrvz`O<8}8%zWYPj*=e2^i;&Gv0Wueqfp!pP!$<@cr3+N)^;-6xNGF z=KDX1U7I&qUk$qvRc$|uAEF%LeQ*24nT&+_{P#RmGl}oc}qtI8~@lQ$2c z+^El6Jay-RT`8B95fk8^*G15lD?bhSm1<{HD`Afmq(X$~ZcPRP`OfEhWsVtkSdZKW zHK7WeC~c_os}#)=E-Hp?ijv~1efXkkZB73LgY?Vm%d^+>^}^g76%S9!lH(86j)h^r zG-$JzM)r=FmABZU1bj!NPtbA{)(=VqkP-#KEH!NNP*2F0q%|UcN1J%&t~T^kr?D;m ztK5ZPaS1r+(G)D`@88LtgG#R*@9@T;Ym-paYv|1zT6K8B-&n`gz6@y+B@nk35s*by zeLtOi2(5hV5P;=|I(@E%|4s{eorf7z|M^t?Xx;g%M`)rs?lM=%jz|(>l=%tiShlj+ z9>xOkLz9d3ZmERmEu~kQlQfO$C0%tb{x zRo%y}DQFoQZ3Uu|^GtrdEJl#>v>=msX!df$yqz}=u)YK&JqpUY5WOVRuN)D-I?po$ zfUb1=v4!klysn>>eohWb(213GCSTnb89JdYTlr3LG5ku9N~sfK<6J5oG*5F4B@TaC zGSF)ggR}P#lhTf~C)pJWm|xpxyH+^K@-^$7U}HxpZ=x-0!y6}IZtq*Rmy?{k6aWC! zzftjdu^&%AwccUzo&VjkO`RTV98h?|h8RjM%+LR@e|&sQlU?1Nv#)B`@)TyY4FyU` z^cqj3cS5pK(|b+Ae0I!{X{@CJ2FR&`J@9tYZNqoAMUyH1fUyk&4K*2*x!7xOT2G^O zmOQ&)%Qq9;r6wx-dVyFnSj8u&#I5NI=EcpAaY;u$G#$YhA_q$4eiwDHfTPHp#43%P=Xojs6XMEfjm^5SpD_S4&9aJ99~X z4(3pBvrzj7WaCK4#5ePJ)SfPa1*j;}a{3u$wU6^M_m=)t_7#Dthsl67CC32*JwiI~ z4>Ddx{MM|qrIr%5+%gyII#yiW$iStdoZX+tW+Hw~`003#iI$dj)4)whkPOow`f~rT zHWolC)n#RjZDnPLesMc7F`R|8@`Du>6~7(qzWF6WwVAfxKW*-x$KADV=LS5z|1zlD zi=`jFJ$%p)$i^V)c>Y)Ze#cv zcuAtH!y=HI55=iXPlWZH5fKj;=4z0|PbsLh=}?Dkq$_GS=2}kFp8~;ZUS(gEkSe5p z<0O^*6^%M)y;1R<@G&jq<1px9{f_G)5=UjP6)d{>{0F&>zfyn7Eaa#%0>^cgGLJ%# zTzJZ2Ax6Jisd9y!U6Pf5t)ixHDL2bEYd^mwmG=;sMg-poR#jL30zhv4ryUtJ1t2E3 zG8-BiUSc?DfMGwFUSCl$8d-B8y<~k@SNc%dM18eR_tt1n6`8|F?>#+M^k9XF%D|N{ z4e$AwxZ9Im4AyBftXzy4($1j+&KOsmdD}suF(gm=GGIvjodDW=yrcEfP`w;cf0M4?gNbvjp4ND$~GY*A+hiDzA9L! zxhv|Y9J=$57~i!-&!6k0S#9mw;J5Fw^4^rr784`+8GfYdn$Fo^eCF!^269^8kc0k= zn?mq<@4wbcRjO=tq_ zDwzEr_tG%N&>S!j2ljz@YeFQ=)vyQFyMqMdKE7IoMR;Jr1v4 zJr`p>Re~#4uG317JP)FLy+5GwrW&PW5c~q1i>S}sd5fd)<}q8_zoLma&EcPJ-S2Jz z*m?Pj(BvP{NuVuXG39V9uc;9oCF15?8Ue)s@KMCz1U2a5?*$X`fOUV*hIFJ&cc}Ni zAxER(*aV2`JKQqvN=uM}p#w4eAd$l|f=R0@jH<{yJ_-vnbN@kZP#jPcCZ0&E85sDQ zy0Ws8grSa;a}b+IOU%N;;wNmFuKO^yrha+DvltdRaqxI=?z+NZ>ui8N5%$63F_?_N z|Hr-*DVso}j}oP?r)5lCL!y>am9m3qh6dtv~Kw%55umk9lf zi-UthBQiBznc=wEuFoGmU~O~bDFVPztfUcIOG``d>w6zboy5u3t}H1pF7|m z2*^Mt1fC90O##&}4rLFG6NZ`Ap?Y(K%qCkG9z@a6(W=!3%~36@XEQOJJRqH1vv{88 zyjNid)G;BG|E*%PRQ7ZZ83P6kpa>CFrT{eXsVl#IR8-WD`Gtj?9sZiWK~}SvH;bx< z37Zyb56@rJ3;t8oX;_=Zb&R{9@P8rxxw|_5jrdd3y#Mc2ohmHiB3fHpTk0|O9C15M zph(s+&$yk@fq?-v+B%}T2_5AChJNz=pW&okDGCulQ!wiN+Sge9KYKHIn@BoFId(-M8x&5I4 R`12G<{)38ijihPF{{U%zlVJb= literal 0 HcmV?d00001 diff --git a/release/datafiles/splash.jpg b/release/datafiles/splash.jpg new file mode 100644 index 0000000000000000000000000000000000000000..da88c0b8eaa25949fcb6fb74401fb7fc7b67ff19 GIT binary patch literal 79258 zcmb4qbx<79*X2Nf;0Xk`U_+1q2^KuT-5Feh!@%GS79b(GyE_cb;68YQyAL|J1(%?K zkZgXn_0_jq`^WB{?!K?9`_z4>x?a7iEB$xz?*`zxvb>T!00RR9p!n|q{M`gl$oV+f z0sv}i08Rh^fcx+Ihreim%zs$_S72gdVEj8VF#ikxeTVrUC;y9s|Bd!v^#AMl_d9?D z7vmYm^%D$c0452>6B3NSeSnt$0LBySf6o7>+^xEqwf(Mo}AG%G$Uka<(||sH^1<2BKm(4aGw0P zj(<`x|LJ&&frX3r@3kfg022cf>pwc4Vm}2u#RL3D2MGY1lnLj>TdAkaT4WY(=eR6< zUkazmrL`05x@TDVEsHksWOQ`hgD(VxWkH@Pv;Wk2d`(JjZ2G$lApAEOCdm^Lzt7{GiN}m!6|5;<8Rn75?(*@;@8X9LSh5Y8$ff&I=`*Uv#jD%W^e2 zU1iVI(BjnAXN_B}vmtpF>G>?EKo%3H?e|}~5bqIJzDX7lbAe@FQOr8QP%h!rNoJpFk`oN$^mWocz-TAWXxrBK!DBGx=5P?GS_>rdTS zF<77Wqd6oJA$_7DRZT#9%^__?#;=z&x77savx5@o#tG?$cdQz1PEdMTp;A#3zn!Kf zDIy9qF9SGNqT2i?@$*XyAouIfX-#M}&u!B!&KJxdja+XkQozwti?d9k^iumGXt(#3 zqX&A@XanV`0_h~;K7L>Jc86fjRxDs5h6YFx0t0lS8QlJi@Ewqdeq8Ol3|~o zJhnTz{w@kz>3s3ho19Wu1Z<26YX%ipVD3S<>}}85KtLL%c)~Pt)!5i%w^h|MGcz;w z{r}M}5Cs(fSs}{X2tLoRpU2KQ{pC`{oks4dg|5nW9zqYk>aq01T@d^pKBdiyiD)X_e zYbR_*ru`EY6?AUrMWptctfJQe6twNpW87^6RC%66hJn$TJSKYk{S^{z+XC;bddyj? zU_53!SS8(_frw@~(YG1H`X>tIFN-NI%Zt?OpJTf zJiWVQDg3uqM)XS4a#e;L_Tp?~KeXD$kTBuDvy9sO@Y<;$=R-X&ZHMRIWnq^p~6Si9PE(hsU%p-7V3jErW9-PXB_n~9Ek(R7`pfVX2++m9t*tF z@z4@ZGhFERb_TcfYPmnu^o;Azxat=wG!b)hXx;hkQjz-K;NIi@G!rkKz^dDM%F}wo zCqJ6d%U^>0g`Yi(tZVL>Uh(Katb#y9b9$9Ce_(%j)zJ}Vo7c)39sYyoYv$2gfn_bo z;rkI(GsDv@hlUko*f)ir4LQpgT7-Ox5x(*qY}li3NRT|QfOHkX0;z@J^y{k$nO4n{p%Fy^$!^7``{6sZr6}jWkAKl(&=F4}SsK4AVhJ zrrUo3`!j!jT?PeRS}pTFI(7s-(qshP(r>-{a}fQHRQeZiX!+tVV2hyV?D6{DUjR`5 zFJPu`(zB`b_mc||!>zx7(As(6tX}A9Bt4S#?K1UyrD1{tjfgM!ok78{^S3bb$kMM=Ef2K z<>{wF?%#~WK7(efG;vge2=Pp+;r->Hv{D4hL8gZhDdgl8T(Zl^PESZ^mt|yMdPdF` zZ(N4)Nt%Owp7gz+W3n}v+5<>tOeMZE?HDmM*r|%*2*Uy z?(D^HSAAeCML$eA6gBGk7vK#kD<_n5m$64E!uZbFp`{UWTSJTqHIaZ8l4>&Xb!t*` z-@%2hQ$?L9oe`7h_MA2tX?@L1AX3PSHI$Y8c>%5jE(_!1@>CwX@Ib8)sPzU`Op)$= z>L8tIB7{nZ&$m~o%Uu5=fTXK zEZwalOrpkCmf-%exs?;vmGqpSPd?;8*LG0R=h?uDTDr=+r>^N?t#&lFnU%k9^2#x7 z!X(}f_|C4&dM1)oQqGkB6pZFC-;Q4pT<;6bJpI;#F7rC+73;edn0HJk!yYEG>eJyK zN=fDB-~=SRO^*3t&}%%{;cf~Ed-uxKT70X=$fhE%?I`YbekePHZ`i0|5ujd|J#f`_ zOS+lvZrT*tw7e=eJ;|&+^3~xLk!)CxYeXVR4pZq&3M-VFHFvdxmpk#s-nH%Qh1jaR z>5~6^eyCDI6)ret4!qsYS!b51-gH0;Y_3x*tE1qbM3tq@Q#*@=0C&p;ynUbc%J|S4Pc{IRK%t+T;$H)y0a-oonSqa)F?5 z{|QwjC6AigGLhCc(_o}=61~qL5Uib|q;;w!Itn!oddC}{o$6k7K>7k>7?%<|Uyqcw z6g9K7tLex0T^B!CD(RZV1Y@=3@2I4J=A7DwhDA$4_Ef7M%z|aO;2^SMVVjp(% zUJBFi6``#>lBKm2M^c4j$_dLjq+-6k>CeSpp7?Iw?{_#oC`&G0ur%#Qjjw`%H?XSK z8H?e-j4RG)r{=b~e9&_{X1+BDAJb4ov&qvQ;^D)|=YgNs*zOdPhQTB8eUdpg+eQdkhHxoEp^PFU~dKJczx~6O(^>mWVS;JiI zuh{brL`7UD6@4kq#(Ij%QD0~_YzLh~J*;l^!aWCd!)U%}-IxC;#ZJL%^fo6sOjviK zn6)u~BmJd{&KlBJ{v%mudPDVOe>yN1-*)Hh) zk0LWYuTku_T+Cf0n54YXsPCzA(n?!^G)t7T4z{A^o^-^B;wkRDA^d}D%}M9#W7uZC zt&jg^aj3&Xr}lC-jiBhSHm*ujK?8fZm}IfUl@7a*fQ<-g&SDZEl~Y^yXX{Yhq5|K& zV7J}Oo7#8j?%a=sTmImz#iOXbiUyaNnk;TxIr#z0PVSp6=~9y^uD8pXjzT;AK4w=) z8$NUmqaw*Nfv$i&p`uw)rcjPZ-!Z+WoYdc3c21NL6yJUBX5 z7|%8fR1NvTG>Z8xCp+y)oRQ!;8@?=4L9$n6c$~RR+E!skM3*h*iXX&#c{Le7OJR{D zC|C+&=JDyyep96Re2IZi>?YNlysxd9AKA^^ZLEHCmxIlnP`y#|+>Z#VAOFlnR`TVo z;VHF`&T`nhA3pnDRP&vqM&)99iHD`Ajt#Monl5u{WpkyFvhGt5&pITYh~fu!GcQd_ zh3#$o2^Z4!;6cZrp1m|`eAC*Tj~%qUa}VlSmG*b?QRSENNSseA1ZIU8620p6{8_hf z=g{BC!s`Ry8h5x9>CB^smop(E%j(3FE?RMKaJsL8r2t8|eP4MljK6YCSSRbNC8KuV zJgA;8%xWm{&8`r;#>rxDw{wqx8J{Zx*6CAbP$o#0gO^2@1=9zgs9g(N+KXHHncs_U zfA!HRPdC5!SUyY;n?8tnR`7xjHZUm?}a3^#xmkxR8nx7xKaIDwc zTPZzl{kY`DbHuGrE{N9qff!Sh%%?ePa?a#qPz9pQ;(Dv=AJpY|!YS$dLam(c6b37# zKxV&q;;r<&KaW3cjF`D~10)RTTk0C?eDT!7GMDw4-JG=*@b&aPNJi&c#TDqF{FxF@ zO8GUdNWv}w1NT;JGkggUE_xrgfhEXbu92}r3HKnKA)XAR5U65=@&ht4CVl$6K>S#; zhF;Cx&^r*5uvvcQqW6nAn;2$N_|`yEg6s0$U~kQXo1v8jnjoh2{=;9lnj}$fU=N31uw3Goc#mm zw>{iyXil`biBZUAE;kw86= z0A#Wc+X-dELg)aJySYToGSPMIc{ToSzuWgRQSIwN1{88n)^?$Y8-tSouHsqP1k<=9 z7TFYJ-7?4ZpfO{s9QLu7FvT%c!MYaoa__~`qLxXrPHeR=9#JkpZD1-fk}|JwY?~Px z_N0j1lGkh5iZt2CNpRDX>7dl!gcM*3r)RQcw-El2CIx-K`fL*pgXf_0))`*6xUZ`C zyF3>DW_^de;=KI|^g2?{HZ3sG+&>$Z^{%*TgV-X3@_lEw*FSUo7!A;bSci8fE65#=xfm=xYPj83P zNmD;>XzP$woX^HMRJh->*VknFDj*fQtc^BDHDw((V#!e-(^huRDHkp z6iNNGR5!Bl%4fSGsvZw<$g!+b%41EO^PTRPT88_EmA-DN%C*?_F_i9|d4~h)uBd9H zV!^4st=P1SHz1>CBv-#+9%)nqiq(eh_%-mj!-ku7lmZ+0Y)Gy}s69*_8ihHqJqt$8 zznyfgc(FTZ@hMxT3;5L3@NvJ067OsKZq)qGrT=tZbHx?ek%XoilNr#(8`hG8v4S@ zZk+nYekn8}O)QvNg(MWgwh=_OPtoMSGWqj3sU@N$i&9tcd5NGusRz} zL?G+LhcdC*r>4cn5k&hVDGj$uJ zCrnRU`eQR#QhHL3r47lI{4X{4Ww3hh?=(kMG1(tY?~kIG+%( zg_21XE#F)-td~eX&5(s@AubM3``rfAM165H{?F!SW6PQA6>Tfav+^X>#OuYF14sBt z|9wz!g5jV9_(~lbKp>UYLcR=~+v~kV(t6s0~N9pux z#9BV#UF^>;+m*xLaya;lxTr=IHO<4AdUz;lINoL$v2UusXDc0(IJp^r(B3%LXs&iT zody+-ZiRcY$31Fqs{{Xq$w?DAWrg2b1cgX(1#f?IIB8l5YfJ3HQ28o#g}BMBrpFOC zW^>^A)WLzj020(v!zq4MmB%Wr#D`Xjouvqne6l3?)^hhn64H8wbpCL)#Aj4H%UQa- z8hhA}pw5~2$>woGcs=TZGKOhEfgp4Qp4EL+UbB;~^bOVby*>#Ss2V~pYv}Nj#3x;7 z%V}PNP?$N;)N?w0f@^-4orC*F2w&p$PXzu5E+bzbt^05qWy9((AZyF`FTnAm;H3Hg0|{)Kf8X!=<1YaF)nC9=O}|+3zsx~zzxnS^ zL4N^-Y1?IM!xIcQ>Q@`IVTX^?P1ymal@sXwiScrf6B=5mnRYf0VokSEO;`UHrtB&! z@S)TJN7Zpbtbgc&evvJoJxVqG^Ft1oIiC3W;0UHAKtjWbp?i1B{wyESZxJ_9H)l?p zTJJ;1ZU|e=O`6<5`=jNiho3q&{sOR)j>)+jOU1245-O8zJ6rOm|4`g=2-T3hDEBW@ zEYM}??zn09bz0PeJgQiw!iHtJ!pJeP_2Nz6s(>9pdWUbjB)w$yBlO|wZkzAP_m=X4 zjFT?}vAtAuQIp47`ige4zL|+sSi2=@HrmxAQD_fQ%kH7yHXFawIW|WK&qDcMwq{+PZC-Lxr6RdpcR&KC$fd}1nPvhygew(yN2`^| z%EVRuAfX`>N|?pdnGmjjo`9dD9j~okZ~B%_(Cr114&>As-Q};Z2@S{(n88+l;f{8Q z%H^>leOWfo4$2to*kYdl2-;E)=WZ0{m#^>uwU~2$2}a(Q4Z!f+_o>@@KyqK z6W4Q*d%1cOQaxW-yX_K{Px3P=R|aQskb*@crZ;_t*r!FqViRJc_!4wuE9Gh%{~=81 z&3}eB|7_ED7kli708Qcel>zR@IfNk|QmD-Nlom?hpYCVGw^A7$m6xel&;1Z!3+(rN zkEgBO%!Xqq>q285#Spj1E5e}uYt>4tWD7@^7mjdQkZt<%v?5sj25_vtxPX9@O<&?4 zQa05%_x%OD_Wq%wb!8Vtzl(0`+F~0+yt9^BIc2`(zMoqPkSZBZwx574LM6<;fKldc z*8N4slS=7&IhhP%2<=$Gt3F86yKwi5fo~M#j?esWMaj>aH93Au^lsjOj8;pQ>YVWd z{+#Y}(v!lOSJ^5htG`?qv5sjM3v6oJgjsftLV(U5@-5#!hyo09hxUtpxVW|sdJ8nYL>EU9Ewtahhty>12avV~ zE>Whx(6;|AKFd8UaFC{O&fHyHv{bedKf7iseUPY|tl|{5qPXW495HI4?9tP{Ebe)s zV3v=hczo|FR9f@i%lno6iM_|JCgk9n;O)_-R~7`Es@KeIwC@#V3}VqR4*atNE(1zH z@}#%s6ILiQap&fXXhTq&(bdV-a!l%9D>0}cQ2d_X4U8BO)G?wFoU2aURsmnG(H@Ro z^e1uG2ad_p>uX#*>7D)+`f%f0?(UDL$Buf%Eu=L>W8pOG{MqPizuneN2$pX}0fBTX z&Tf^S3aL%Ptd?g!3q}y1M-88;j<52l6>WqEw$B_O6a!YmSoYv|a;6~eZ6HC0c5(V;0HILL-rT>oR z)I+!1%iW4dhxazkwW0hfQvK{f%BHF&DB&s}B1E%U%+E~ouzJ?Qj-Y@Fz4^^k0*b-s zx{me5zOS4<(ND_8B9Kms2gN7X2PWmSV8OOALxGW3EYVTTR&OzFjC8b6J?AZFO4RXT z6|B-d_J0Nnoh>Mdqeccl5R?cNdE?BR>RA?6u;46f7(-9-un5iq^G*nx>1iInvYDG& znPu7uX*<@u3tx>+I$3TfonP~}z5LS3e>1d#4s~8?UP%|aseu~OPP(s%1@;-7N?>Od z1$|CYC~VM?X%Z$X{0pe0%}7rmb?~vQ2SWJ=?bCIV$1t3tPFiFFn5qJro=bxrzl2uB zMqp@Um#N({dY|2SH;X1$$U)ncn-AO_$uk|oF?mB$TQ@r%COVl=3elu=isMyFv+F5G z+;8bqxPPqq5($L1G?p}rzc-^K`qc=n8uc2972OO#C#CAbWy4lQvSOmaN7ZO%*eM|# zNwh?yh4vjlKhn?zC^-Q!IEWGqpB) z^i)qCZU7(Xbc@Av_SyqfpUFe6ZfP2-%(hjv zky#DA>g7&>NgdApOrVL|c`QJo#;KVSQr#Ym&|S-24`@sMGb3(|vKNxeW_`MG z5?Y&zIhsc4ta7^UcjYiDHk>?#&5rvruIe6Io8TZXf9tF!XfQ&GftW<8yOOa zFecj{hxL1jXn)aSO;UQLz63EdPZLi9Y5qw>P)rf9$BM3NH@cg)8Glr;ETKI_^=fI7 zv*a&ruWJF)B)Bc9okZ8+w0u2ZS4SI})GiVm*%D${4>i+kzx zf&>FZhJ!RvCvPeQTeuu>f3o_;oOjTf?1wq7^r+4sDF>#b-)>jz@Kg5VZni)Uj2~0U z`88s7t${2xvhTjceRk|J(Sqd7yRpc$IGv2xigRHO6r(tA$?s<0W>;wfkt4sMRm<7a zt2!FxUV;VNYOIJI8DGZwp9hm7J%j$@FaERCTte2BCVpGt|h-N2wcb<2fDshXIb1UuC zw$N0%)UrmetT%mGG_F<83oO3UI~}D>6}8n=diEitz00OX`K_ugc++Y^%xU z>e!T&@5KGSzcwv3OCt;kddgsA>V{O(x4rI{#Jv>*LmS*E?TngPRWKQjKyXiLqQOd( zBe6c$^kT+%C(~IV9;7_k!Cgh=`C=5h&Xh+I9Y(9H;3$Z-Wgp_(*w5Zi=8kQn2_SOY zb0tfqbd1J?KyF)kGaV^lD&rG2Ew4NrJ!wDt8Jry*{HO2%|MTv=kzTqGGa1KJ9l^&f znu{q`UpkTX;8r9X(?bxin9Q_`RX?JcO8zepz)_mcLgfiI-~R=ybjBjk?a-rWM3Z6Z z95^K`k5J4_i;-VoxTvw|d8(+b7>=?g46s>-bD0V-Xvr6-8W#2!9sjvfuKM#EcWIiv z1M{DsMY7VPq>C@0EJYO}l(?1i+K)ZIK*YX%hHM&{d(%6Hfi^mX{CX;ntK#m$`l;0* zr-Ex+U7Y?^y<>r|QRenoZG-bd6#Z&`MC|E>b4Y9sWBx;;Ysfsr^ELK|sOoQ%`U< zMlNfi7hgtC@2Z;KxpR0_8AE9gE*xAovpPZl@|D&<*&jmQ17GKpf7om+lVtXHw1vPb ztkF)!0$^Eo&v^?fW)?!GmV>zFQAc~BrQbeo6fJiG51?d8{jKW|VP zDb|RZ#rko+5B(ZTx?kejl#Rbstv{G58Xp2G7f;mLEoL{+?Gb}Pt+Q;fc?soe`A*$#z2%w?+=H4lMJnTZ+&YSKyjB-%(0R94X7E?cacYErXuk#MIGDIY}>O`j>u-LVs?1X1WV z^D{S$KTd9S20BaFg^hPXub~R_ylpqbnso5@T6-6&;qw`02W)oH3j=O)pH_XF!p_#I zxw;_ULcI=<{H;r8I*aFEDw52~dBiaw43UTZ{)!Czj#-;;m;$$~25^A)lz9DR4q<&>IrE!}&DJ>`73=Y`>od ziTlcA#6jsO-%7Ro{jY-(SS-n0v2S)>_nucQIvrbdh(SAaPce0P7QI$M+UmR71johw zs@Lk6%I=`-`ypDij8iozBtHB~ouzD2O##`hGl^yLw6t)`XTP-~Qj*8F2m7nixpqNy zL74Q@)vCnBsw%|k-u4v4$4R{0CuQvLcO#Qri)X}Xp|(hlVh@8)Nd3Hj)rQ+hD#^@C z2g(MVmyORHg}hy6+q9v%Vmhv%QylZJb_(qzdgOireu}|X?QS}uBCktD^-^K#q1a?( zgxHP=K}%-@J2_t2clmvMf;e(oZ_9{TpoXl|TCAsu1Jp~FzLv4d6-3&i>q9rk-)>^s zE}n+B>W6+3B;6C2(Ez~TX0qtTN!kdw%KuaxikcZDo2iBBlnO7e8>HI?1iL~x5#J?O zvY*_EKF$)$`F1YGlJ(!;OWf`H!A;$FA+P#XCbUV^b%7%1<(LL43b>jiRX6uUIr@$2 z8+O)oMehxqM;fSCu9wy2pl?@ee9Nh0TTTS!npQXpITuvdbhg}REt!j!_zv*MpC!oRyOw341kzJP0Ed|_F~BunMy8_}bc zx$JhC-bPm?tvCijy??ltoPow6y35sCRg(xUxq23T7V*sIhpABDSSsg!Kqj8bIMeQ6 zoGIWN{dvwyO+IJV^M6J3yRrzM`}~-)3EQ!Lt!Q4d43w_GNN3%x0_0Y5j zy}K*ubnQFh)FwKa_wD|XYA`eXPiX~6jc>9Kkx`WjHX3CkDj;8%M=R=t=9Dt?w6ugz z3Z#VJ-bF7a(z>_Ylw34X2HMSl)K+5KR#;C)pg&pRyLy=Wj&h79d*=`-gmlDbvs=v4 zfL&Rpp2Yl)paddP)9Z-e(X}K(<@vRX;ON)=?sv-hb znsmIM^x3;dC0@?!kDbcA@zw&a3?2yw2w*FyuiA?y4q@H2UZoQ7K;y+vm|zA75Z{&j*fcGkKr`o zu2gR+1W!8J7(0|Lujsf=Gmz$Pa#!VZCW+(kwvRcpq27RDEM_wnq^!O8wG`=Hxhve{PM8fOpG23xDCFD%M% z-GTI@BRhVAU9dMI+J`Jdxb))Waao7R7lA|VFFy&hE}s%O1q{?c0$@%0O%y+i^A%shFe@R!5cBitjE{NVkCYsh45gmbUr=!7r<5gsTk4++ zx@xT5Ns75f=Or}OQ0Yqr*!Pb$l^Kgc#golKp!Z*Bu;)m>Vzgav`kHysCc#S4hR7bMgo5`w(Eb~R5`HaxiU(G#&VRGO!XM?x<5H1;Kbb%o)9cB@qQp*-sXyq(jXgNN6d>|?b8NeEyY4m;0FQ< z)>}58Z)UB&ecGxeuV1CFKKraQp8jQr#F=W_DePeN1e?K`mAKg$v+MzGh+_YRQ2o_HhA*%xgo9N;p z`>{zK3uw5{>|e_b*7k#KMbuWTW+FI<3%s44jdTfS=Lmc3=N<*CSx+e1-ErS5(+nGs zbdILvPl2K6zW}w(5lVvWY%!m7o7f}|C$6}apGO)xYM7w56QUo~s=z8Ux=eMJ@AsW= ze_ke$)5&1}oNwJc!M_0>uha1tIGghA`Ym`IbvUs6{D^3mW{d0l%?N( zI;Sc%BZ*AjR2P={jd4g^>iiEfralK5ys>pi%wCaIguiW!1;G2FMepSPm8A%$z34Lm zwKRVuPY2mXFwn2i@nVu~S^YjRqcB1I**&YxbKRU|)L z)HNWT*0F!$$0_7ddIS9lQkAt5Vw6wp|KP+} zBD$QKa+87tF!Z+BVTqy5S2>JlPLH*!xk$fRs5czZdf~OFCu__YH~8W@ep_l3CU)LKN{saN{|Lflh?2rrEMQC>zmRv zkiry7VJb`+XLybfe0EY_Ozl^5dEBn10p2fm6ZhP@m9hs_udbWONKvyM#c~Q^MQMuj z@>-+Pm71_6w03=U`Br#$oY<)QAJTD~5$il8Yg)Bv7LCaOr*gGyJ^!Etw~4j@ct>$_ zA%kHk3Y40y@!lun#?4>p_T~r;Dcg#UiH+*0sh{&}Z-UZa1b!%8^{`Sh70P#2Z{|om z5uO1P3GaYCoSDS`aD?bCQ=U$8RK2`GILYsxPs(p3TY9?}E0nLb2lUQC(|#WkMv@-L zM{_~X46lUiN=7Zp=m}+$jKzl(H5io@*lAA9#vU1Hb{?TyU4*mnTL{mu%Enfg$pFp=UbUl z+e>fjMeikhl{iiqH}{M~(aPr+*XaGvWnQXS&#-{Qn}Fkq^%Fb1Y=RFBRrdjGPsA*& zQ6?nCLL+;i!}$}TGJ{H0?HB2X+K1ZKiUD)hRfCh(Atf$vsHo_}rAkL_kAWwFiw5m} zts{tRJ`}RbOU}r}xCk zEjZMY<-I1Pv*ZYdtO*#XP)Pnwhnya2ta?rg|H-CnDzz7{1{?LQMQWneJ$%EE?y~0AbfY}Le~=4`MhlOS!->itL8s$CCIh<}jI69Yem&&oY^d8q_Nf>Q> zkd69k4O1+HHPb;BufLb}-@lif9DGg7eadso6IbfOJz2uWu>2jaVDu6Ro&K?$!sXzw z^9(;AP}V+)#sHr=nUrS9m8}ri=|;Qs7tkxY{h-ydT)m#%&sXSyCNeo(m3V9e0_T^j z-|N6znNzJ~-==&4fPf0_T&jGfi8!&!>8BlG0=DV*q|41GqH~3_@DzArK~GsvY8BZUk{d^P`!lC>;fi$HA$OsVha(lFS1#pE?h8e!@zU1sTirMl!Jl-^r z2`rFEA92#lWY(LT@Splat2uv{I3W1vwcV6}FNi=wNJ;e}MD}&5zbBg*GQ&hrH>o~# zhmjgzn=~OM2J186>Pf+Zq(lkB6n)oCfRpTMcXcUwZ!1#SZtBLx*(AX@@U$&6ZaD|8 zn=p!iN@S~$7AaOJNlD@QW;j)O2m~^e2f?5_}%g%k8MPUo%^iuZ9LH%ZtOP$Qop1U9;C+Zd8 zuC7;PPWn)+LRFlYs2-a2p{}k40&Gn9z`V0<()+G-m~;Qm($8kAquWz+P)k6I!g2(d zB$ycfwjeS~&Y15AM2MeFweHF#x0J`-0&Dky-9%lmG<%l&QyP0qD6g-K4y=}-Zne*i zvJy$Lvi)=rszeR2UNEiMewsnpB}A^I2clU#=8ze%Vm2LQmm|^Awl84DD;(f;dqQ(X z87tqd z38@HcnYedRnV5!qfh*KRoiy+kIL=?Dg{|x~cAuk4KL|5!>=uAOe~Vb7&-Rv*KZ~Eq0(Y6> zAKp`yR&ry_nNW>&`zEfy7bL0wGF>W?hs}p)u|tb3H!|gm0`|mN_dUA4%-74yyYyZG!Oq+B2jRARwF1ptT=V!-DESWjtQ zm)ATKbL$)Dj3lPmSQLv?s;v-=7_#J_Q^EXMrnjofnTX8^=b@idFXntMzQ@OT`HPhF zp`6qOi=kl0FIM5j0jG-`($O`s84WzU$m#Sph9bP5kj0ZU0JFJV5P}Y%@|h`-lo{+n z{l;R!gwJQ4L+pmP-p|X?J!RGA&wZ>G3GmDcp3VkraIT!sA9mzguS06k6g4p%>EFU~ zjPGSRLOCMiLCtXDyvfo>+S~$ev>XDjzumT13h@h`cXSziQ#qDZ3`>8m?Ia;E+ zxSM41Y2I>j%1BCNgh%_}5~~_Vj;y*KYKulsPG_TyQeRr#wtMU;K*f!Jcoa-IfW45K zY~Sl3^JJ|TD42UY)tqyAjiONxx2WW^(xHblif^$zGhbq;~~-ODLj&plk`7XiPg z?mKV0#i@-_&j&-WO@DPw?3mZEqf{*(TG=GtZ#Fgm=ck4_?`W}q4fQHAPYCpWz^@|t z(D}^i>Vf{s4iGgzLOYwrW-_vo?4;(XsS% zWTZjqIMNzMYS!4iC3L`*8MtAbkDblEf7)-LJymvrFKPXGzWJ3=P1_3dN%fhDe&?wB zNOgncug0oudH0V>7R?8B_V2Ka#+AKZ^;yWjKI|0DmWQF{lF|>Z!VGt*SkHF%LQ5?& zMqj&g7-?N2 z7EbJ4sn-J+@}zT$Y=g4bHvEN zuE*<*wHz_0v2(xLR#}grGh!O;KxA(l1j}u6i@Y?X;{-Xoq&~;z|8AH7L*mAL2WGP*oaSt za(;eBZ@wWq0bk8#7=&eVjZ|6jln4zy^S==uc2?&Wnu%9vm!p~J0#mN$kNdYkK9f*BmOwpzmSEUXYGu49Dm-29Bu$wq{h;M=eX{ z5}o6yD!q{11EqLOHNBaFkuvSHUE7T^5m5Gd9bK@47uK7mZ!|JWLucw_`?sdsE$K~S zZfEVHHEquw$;9f&a3IuLY{sA?nx4AD6xO$H#yT=Y)k3S9J4Gs=lBuAojkOQe-))!Bl!rVkj+rz8^3pXNdVEJiFr}Oo1VM0A5sl1c+H+ai zQpP@+uraMm+pKpVsVj{(8)H=h4Jq`xVq^P9`LYRdZpP(DN}kl!KEy9~ZP%22bp2t{ zA?5U#b3zU}1dgkD35}@~1$99B-36+;>Q`F-0=}jk1^qTvJ<2??06 znV*uaNJ6!1cIr{jqtKsZNwpyNTMU&}$Z(qA?+8RAt=uK@u*(tI#4v?Oukt2Wjn<$f z*Gucm@+%s3&wh(i^j%U`EfIKt^_(2hOgB_Pk}FkXwL+WqPp9;Gz;kGYVgBD;YcR1T~iD{rR%sLW4tF`)~FJ z81A}N-`%_2Pjm}27@0oQV(w(eekMA&`?^Tz?0CI+yf{;xZTo_s>JOoEt9^oUV6|;f zv?{a)J6+1jKR>PsIic*EWTu_MN8GsJ2}36^&NVL_;tTqfafWlILRaVH=Mm(NVI3p8 zdSFtlkLc9eqLWV7Q|QMR&AyX;HzkqeQd;D9fr>(=ChBfw>4} zBU&xz@v2`Le}eeMnEz3N*z^m}G8GT!Lje!RIUe*(zSTG79hkHg(gLbI78?akgj{rVwZ!x=&vaU6x!O7?M=&6uS6=?)HS+t?zhRma(TmL%r3 zQr#nENdKjhk;hd)v7<9@cD! zLK1V>j}=VZS{nQ1Y8Y8@r1Bvxx)wuPctkJ-UggYSbFfRV7)sMZIE_}!zoQ)#N7A-X zuFFrgl^6kHxAS8f%MRjdG8Lyn6K&ToUD>O25Q58uRG!GpRRXu*6@EWsRS-oQjVet^ zQZFAJzRtzyk;`D%4!3O@WdoO6wOz6LN?Rqq&Xez6_N|9Oz0@Zhj3w2AHHtdA_VMoI zNhN70vaZ$vtOlN{QNElmQD19i{jYX<7KnUH697R=Kvb=<10%!{Co2LB22; zdQ!`}h$%`Eh?M;OMw|;0pb_LfzYNW5eZ5R!-3ubmP_L?``odJQz@x}-sK3AB_I;H( zsN(N3*AFv%*WOu_PNC6YuT_o7C_aFVp5#uOP? zZK%XXt;h&Du%Dwp)mqZ;s~Zlu7534-=6H&LiMcbHAw!>{B!4St<7-Y za>U$&luGp56764BdbD<|g?tCv6e6p5-$#kX#$$dKix)}V|7>LXuH6Xxc#98+N0%q} z1z`(Q_HCsa?$V|BjwzFHA*e0kQ<5V}2s4i9AYBz&K7xoPjCaTmp^Ip$eJNrVS*p?y_r>Oe!ryna!OFgdR^x1*}kK8nZSex-DwuzvxWvaEElUAYac7p zREb|MBv%&E9-{YFccJDoKps%i?h?J~=XiTiT9ItagI385)mP$`p{$O!;-vPN z_rb@fa+>5H0Dyn(ZcX39e*b4d5EA~M*8bV^baN`9GZKFtI|!jJN=OAN*UU@1h)yy3 z+D_Hk*kWUX4x!{!)dof%j-;y<%miFSh0isKdPc_F;Te7S;l&kk2KE{>Y<2L$7eI5$ zcCIWR@zrUB*QL*ap^G2d?vk1z`2A*m@D*Anjpo}Y5T@ghiqc|(3PG<`aLBGCy&{U^ zf>jAj_fA_57Vj>LRq`R(IX;p?n9p<-Vsg)t{R#xC`fS(W~NvWVK^^Ig^>(psj(*E8a}7mcBMZ_1UvW?*tA zOnmBB4K{V~k*`~}i;v>^=xeIT#TruSz^#g)vQ5qXOiovCZKoX}{v|}7o^E6Q*OpL| z&Kmk%#49e)g|*p@BdvFk-pzGvSE7$GrR^A`>DCwmN41b3=F->~u7{yh|AVowjEbuX zwjG?{AwX~^Ft`UMxDPG^1ot4p21$Z@kl^kPgIjQd1%mtF65QRL-1+Xh@Bdrt{5`$8 zx~r?ZtM=ageDFph&kapFy=Xj&Ne(EsU{_5gVgpq(DpbFNZ1~%M>YqNGeFyIjt)nRA zOn`E-{{y(TG>PK(Hxl(;>%N1}8@^2!35-F{OngZkfG&*DC1(gr+k%f{dEjvAHWmMi zh?TIOAEMLsXm4(_oX)B#tFf&wp*Un{0@?;rwQ_~2n<4e|O6<1eA-Wk#Zwk>Q8Oi{~ z^NySN_&GoB9P!9XHWXVyjA=zlU3ykos4m$T`NbbANB#j`L`!#{HI)AW1}yw;z%P|tWx$+!9H*B-@tM*}waBZagkf#H z^)VG~ZJy~1FctzGv67X~-tSnL0EZKROprg@*lrZ&pUaCB6#CmL<+F6+u~f7XB%7=0=@ZI2GD1O>8ouUckLk#(R-D2-Dn+kJHpC@JOnYK-(D^uAaoFMjmfqL0W!j=C zk>B%qL&F)H6B$_&F8k8+&RwcfST{!ULql0gN`x@z-jHYPIPPSCp8ljgWqiADM<~3x`So$RfHEm-$n%uX$&QE5$0EOe6KU0 ze8DzmKD@I*AhGXTM( zFaZ@MH4}3IjE9_4475S>SD;b`SBioFmtdM@rys>KgbaCtc$m){^TGHvuieCG80lo( zxt2zI-cvrF2vT3JM^nkI*EZ^D|0s57GhNnXL0}D+J>p3naZeQ@QY<(tmdV-WNCU3z zVXSdErDIx9Y}FJk`rxkMP!Y>ME6#-YH3{tTrF=+m1yLnXQ_VRSQye;zl=>|vO&40p zOc7a@#AZuR5XOkl&g2HBc;iw*S{R9hF=YRB&o1-lZ{>2XHP*jK_8V1-e@Z;7#z)0~3yVPq4cWz>tuC56n6pPj$5=IOxd)4jo7aXnrM)u~`L{!f}m zEjmGXGus&I6{6~P7AKX=z0k1&m86ueul4Xnvvzhz&VK-jc}}bK7~&?K-8evs^vhUgGVKmDbcFm@M~l)XYS1Q+Ey%^t zIxMehpt@ngoo_6s9jg*uhK54bBu=J=ROd7YN@+EvK*o1-9Yl97b9|I zl}S%&5a>WsHDy#@<4*zYC$*isM=9fCDZS+p^5%DHKhy}9t~AhYz7nqHpMLN=1J&BX zcljFtdR5EBo&`fH*sX>AX1JVEuh%O7)HRWM{Q~L7!-%vi6r+$olr-iWxPCS)5nOHF z`#O(X^Vj8W*iabTH^Ud>em!d;Dl_-!x-LRnM1Z$R07uxk^1J5HPREq6{tx0B@ormo z#?sddQ~)Nsq1gi14<#jy{o>?&-E?bSFkK7tt|j zgOGutb$WhudM5L`8T$ut$A!?Sz(m{AvL5}SogPaL&av)x;WEO4~> zqFnTzV8C?;`)~OX3Hxzo1Y#z>s-t|r+$GSj1(uU?F@P}ANK*FIVNQzL_-;ozsw;lV z_}unBoLqT__=~vFi}p(<(=p-o+#UY#n<6#19vC&}Q<>I&HgD+oi(MxN;T&B3{LSd| zsIj`2U$mI(KY*2kq>!{_388<%YRl;b+3~8bAbfZT0Qf@1vz;AuGG)zEN%HX0xvsX~ zhbz;bfhZ3!E9Ml(tNDHE%Z@(?${Y9Jn_u-;-&fdShXdkr#MS!G zCV?2kfG@(wF)F4z+MVZ}LpktBFXh#y|N58x@{IiwRsCr0*E-f7Q|uRue=B&NbHDx% z&^ntt5sP`?b=80TyvWE*<^AxLs@*Mal&v2zEEmjePeT3mqYjI`UZLCJgE7T!Y7g)6 zou1Cx{1!eN_rrylJAZzq;(PgK;^cR3u)n14Bo*o;@`6D+iFx9qaJowKb+<9XRsZ>= zWA+~a%TE>in9q&(JT0%r$7P?nQvU%) z{NlwCLvAGT58!dfwH@B>=d1S*AW!fQaO$^x`0}~cWHs4u@(+T!^bc@rG))^Qr>d3d z5xogBJFE_1W;D&-+`_MN6Ia?1zogkhOrB^}K{fBoA)=+ue*j+{XSG|QHVg4hzr%S1 z1L`F9!OC(A-}=>n&_BS3^Oziyt@aX0$~S}Axi~)U@PNmEJ2&gnBlta-4)w@Q zlu#B4R(0|?pC8ARZFXLt%?y|FdI~;RG|!1vB5$=ewnr_$x2qu2mI>FWOphA*GL~*9 zaCf!4o*rZi;|;5ueUe*_XGod5fAk{!rUr9zB6PWJeJtS7Ui?d1Fy$ohJJbJKZ0oOL zK{ZurQWwPie9xnJd2S5}#$>$Daa~8J{`^{X@wYi9v+2$LB-K|buWjR5*&Mc-v!#+#P4js)L_)Ul3A~NKWLBu@+U6%^N*nU*OW2sjy7|z3#+~ecsac`QCD4CqWTom7wh94ioxp;9l}`%qxs~lDiGJRF`(#<%i1H&SP1+>(SnUj3gbOWar^#^A%LZac>PO&!sj>I#$PpmFU?TImsgw0r+Q;Uk3lyxj-5ZVmuucD zVxXY-HqxJXWY{4Xq`I$F_1=8xhZc35PT!24+BVf(ccU+tODl@Osv-iSIPEBl2V>Cn zBGSA)#Fc*q!56wP_otx&Ti*WwqponHvo?F|w;t>ib2d$4)36hgMMu#lgWA(!soV)| z&b3@^bL3~ynLLjmZlU}uumZh|@bulqCP!161Ndq8+s=*MX%o7Lrtz|vmi=h=ih)KW z?)gvMnKql{_lz04Hg*?A1jCti7VvrRnrT@6xT3DP3A5YD<@LwIC6N5!W!L zqER+vU9Bi7X-b9oJkg2(fugRud0qmDV2bOYFYrwIEJR;-+g?ru(k=C-G}rY;=R{vB z#tG=6;Lt!N!JhdK(8+Zme=8&}nRD57eT>jVTJe5)>iP$GYzF!52RwGh@8szj*KoCI zxV(0szfG#LDDO#lVrVG8BID#XuXSS5TU>{ z_fp<^=bQG83jb$l_3)3EoR|wl;FHhhes#Dy^4$657mPWtyI<>qF=wU7@Ban9?)I|$ z)xQY;RzO5#q^sdUA?h)_&Ic33CUerkwx5dX@7L0kqb}5WAhvprXfE2@|Mbr7^6`2N z8R7~@Y4vm$cN)mTpSq8E>c4;U0L`(>d0|GJ8dR|#FU}GF{<-yId+BTnS>ZYz?o)dn zV+h!Ns&4f`aAe!y>VZa)Ew~~r!j#u*v1$rI+Us%wC9^L;3E9$?Nz^_uXn?h zd)J<*cvErczIXqN#Z%lrfGW?i_FEdg|61#eDgLPTAmn+y|5S}w+E2Qkhx>>S|MkXs zQ~a{?@Xn8EMd}So2QPwdHfyARnE<}%HN@iex}HI!eeKVe{p=?m zSMicE!tPg(7=IZ*c;qAGAK-tte#DxY4ul@9Fk{f{2HgDv3_6+M!{0MB{rpCq_75P! zwea%U=NjYMpD!TfYagB%0{4ei5qU-Bd38Q5n z)!v7_O@V4!YCn@R*wxyh2G3jG|BhiB+E)|8ev=Jxhfg*C04vszakw;RTAE*7|;{eo5jm!1QQSMs>6A$IS2tThf7-oql_Z zCn%!B3l@->tEqdx$?BYkP2bb4>JomSsDc<`XOAuc3W*h3)A)k+HhC-m0iygKwH}~x z8o<4O0RN|2;h$G<=+Z)E!v0e&qCY0a_;B?;zZ1KgiTi#-vl4-JJoY+R&zlyS(E95dailJ_=keXZ&w2__3(Ik){^tQ8eqiPZQ2D@#p1bU2Z{14 z<9I15f)9A^5r;wy<%gFMyFgxf!?o*{Mg9oAe8ar=UvF_i7S+9AELt z=c{KIz$6dz6UNfoQ?w&LH76EoLAP3Iu;h3@b!aPg5dX|gEA_8Ra%-=Q(0AMeSK9TN)^rQIp7Y4zJmxGZFrFe8+HhzUBj`Ld(-E&2gdFCd_f-IPa&;B z3gbVOg%lqbZyWFW)MLH;F~=pBGw(gKbmYY7Vt&q@K8ZX2q9x>Az(ZQj1G~aoB!!Oi zDZn})e;*7#6H%+MRo_m(9`c7E>>$5yrx7J!q5Wwb>JEv6pFV2#{*ox2D~|%#EJq;g z4$tS#HtpC*wo;VwEf;)~g~Br)2s3N<-iLsI#K>(z?(*QggUTpIh;xk=WfScnY& z=Tl4!4&_PS4FDX@5@@OOeo+_H<@+*2~DvTw)4#xjeV^U< zISK0F%}@SlS?*fX}%05}`%i;L#3FvSw$)RjMUD6fq>NM(0KLt}?A~9)yhZ_u2 zj|tIESxF_VljTaa&?H;%MfJ&Erj>KLt6kriZL1oBIFGDM{0;6~E}tItu)$F{KM_n( zDS#Jp2w5+eo~Jt~ZmVfZe7B}_O|-I#Bb^y()5Dv)jeT`TVKBWhzt)M?{1}bnl)U}! zd$c-cb|DceA;2z?o|=)IfLzw{Qm&=3j~;kuql1S6B|L z4B3}@HkWn}t@rOThjos2ZH9hiCFyD(Az^hm2KMbBt|$Q|cTEA!pWm$y;ZYZ4a1Gd6 zsJzqjhumnD{HNnuCHd8@)841835 zQi0f*9wkML@eM#cc4C&bkCujYkS8Dx=zHnWDv{7@8iQ<_nMpei?fmI?0;keB%fJ6x zmcL>GI&p+BeVaWwA&zr&JQlEtB218M%bnSPY$&nwr>n>nI1SvUo*hnXy1=@ictm9E zg&!z8H-tjt#-dym&t&C(fHsVbvshE!EtF3dbP_5l7@Wi4pA&Tsalb{a0r8c)uc{>ev!ch^m?~q+6$zRrv0hmFDImpSh zUzvuqVIVRLWUg6VDPNj9VX0%C*~coF+;6~)e&+&tbZil1n54n|V-TShGnPCpeBu3W zn*ahnn;B8!jX`Ac3iXH@N;ub3$aCZ!B=MTJomMxB1%PWm6D3^Kg7u-`0h{LdsxR?s zR@H-}OCuSd{Oiem2q}}zdu*}rv<-jouq#4kbET5#%^5*NT0?b*HbN-mKI>)QV7qhL zQO6UZ1r<{)lXOzfjY-^FF{rJVL$Tk($m z<<-fPcKx1V%%Q|>9|}CGEOH(8wNEDXm7*_7Dx?L@6*TUvk`!m?$8g)n6=^G_Gs)#~ z7A{?86g8RTYXL`^n`pkhL+RkK+8f?wQFhhh^;0A&jB#eUctvAwsHPU68aa&Z5pk_B zXVt>f%bfj&keIP38{%5fYkT14#{MJ{Q{i%dV0(Od@Npw0$rM6wL^4O^kBZU|)ihsH z+frO`Rvadca~&rDIRT^<*P4zH>b{T7XqAg+smlH>hvIo1-|Ta(EiEG zf24TILrpGKkHtmbqXk>CxPNcOqkZ5fYpRi<(oRF@A>oK@>gN?DWQ7CSDo#9F5y|y; z((0dXGFwceC0ZrP=h@I%(34iOra6<1WMv%Pf`I)j?|1jAotazt_mi?IZezX)xm8uB z5z2q!rkn$~2X zpZM)Q*D?(#>)Aq~i$Y&;-dpiv?Yz~|W}2HIfptl%l**3z*pJqFg=++FshsVorQ2SW z$yCUdaj;*$-5&KX3h85&b`+_piCxyoP|B=s)?~VOBGHyuWM$+`J}lR{t!ZsRtKiy- z?BirtIPggLA;N4}lUCv`6WO;YAB$ohAu*j}4T+ou(Be=AdHeF(_7TSuAt%QKZy^Go z!|b%=ouT6I_`*!0QYKbFP|;G}0f-Q^<^3XWQtVV;F#q~D2F=+CNB830v?KXlWo)?S z*tQ-v5= zwm|((@WkiGmqz$C+m~W^j{bsIxPt%_G^4HY;LxhR)>S=mL&6QPJiuALa==5cKuuO# z_cWWs9nKgPnv;iqpt`H_$PHN0?;rZ(PCIK`c0gXyDoF*gk`&af#hRnVjfzMLyfyXtdy1SkO32)W8E);FI>iJC(diA6?Oa~W6}qFw zgp!H6K8jQM>_@(g%|BhwP0romAT4`5Kl5{gylTS6Wv=&kqYJHX>;jkiUR{XFd0(mG zfg(MS<#=wMI;$b$jzP>f*5cECu#e~nF{a2hrrfoA>$&FflBe5=G6}#gBca#BQ-^-D z@Mw0kC}_9C2jp=*aYB2si|W1y+N~Zwnw8x1w4lviQRVo9#7uil#gm=dU-gSgtsOqJ$lcmHF%kGQGhaA?BuWIL+59TSKG?6KDX5zl%iw!2Ls{jXOgzI@0Nl^}y9+ z#F(Vec<#kSf9b%ui6P#K_?IM%TxQs~N%ox}ny&JeHQ94cn^c9{7{2QKbK%u7T&}`0 zI`wdw`WcbL5%VPL-O98?n%Hbq+p@XieK7DdG??>u#sf3M@~FJ_TvtmDvpbt@`rpKA z!Nq*rMa6M()a6uNeDK#-L3*BM8lO?7=BaEi$;LwT6_}gS9>rFZ-E7GoTOX{qeD%p} z$G`((zCItGAGFmBvT9`KW4|^%n9_4Y5qNemGeh+ne|;4`ba{UBfG1{ul7$pyckc4m z&c6>GiH2cS8$R;EpJ#tn6tqwH1!Z?7a-&Y<0dZ~6o?L#;YWEZGglNRj&5az?p?mJu z9^YTQR1#!`cc5dcIy=i@c*pc!UGC>o9Qd9d%%J+T|LXK@CzQ~^!=&~>8b>6vKQ+vU zbgQmK_hSgU!bK4mHD3$aLOg#0FZ`6FnfCa7Mb$UaX^+n0F0jS zSFsg|N(%3JS#-jVCtm@gOYg0jtE(5vBnai>_IG!@cDKv+1{mF_LWfH(#jG1^z@lEJ zFyhHfqzSy9^UHgiM3ni=tu^Zhcgb7@DiF$U0l|OH2Zw_@tHKW(0 zt=63s8+v>ftQ+sFzUNJ6m9)B>X13w)O?f@jz-eU~94mPzX02J4@Kvpx-(nVrB2Z|+ zkS#p{T>S@1n`GLc9d@EMSL`C{PVHoFgo`t_;drmEXcX{i;Y$LxC`p1|#b_B=3Ig)4 zm$G?%G3ThQCq}QRN|;Yrr;4mVdif+Uo=rE)|4UlLU@=~(0R1Hw+}UwK@P0o=x+C&Q znDp!~R*RV)I#gFz7zYWJJunp+vmpW=vl?jtZB}1f_0;#f`?KET6s4-DNZE3PZt2iI zHI(!Z@S7~dfuoVy4X@b+)Xl(1<#OmN8n%~4ZPoKz^#D6skr1X)|DmfHLJ_y-`)+-S zA^;Z{pzZxq?x1GJx-5itrmAKX<;&-omtv%#IrBiA;Gds!QIYAU)MXlT?LX^aMgP-B z*L*4Y7uX$Ceu$|A{RrLa2+U1H55)LgQ!t&4;2GF&FiHQ>d(me9ENOV*?=a+75&0M> za20fru2MxDa&8M%^M4_SI^ZhbH%gLdsT0&z6=H+=z5KpS$>j^%d#T13J(R8zgmm6) zJT8{ER+>4g6gkf~6`^hO=rlUoxlRvN$fB`es4o>HTQUVC7jnZsx{JSYWT7(K@4h6Z zdWdOuo7;=&5F6o0*f4RVU!v64UYDqZ)1xlva$t0Mx!DWjG5o>pu4oK8<^NrASATD{ zS3dY#y@JI~JL`!1##oQX6g%08;6sZ#n--x_$zRB$U=DCL>iP2H%_7Jp7EY4@oi#jEL?nP{SM-xzNbysx4(=mSDMjPGqe z%eZJEf9U5d8IhB%eHgI(mgT()0f(Ee2g-SnU>*;Jm_AT$DwNOyK=IH>8u66B0-`%U z@g0N8ViW5xPrCjK&UcU9Un>8gGN)ctVpF-oY2CZwvaQD5Io4>mO7GGCF1Ov*mPI2V z1k)7BQQlL`a*DBAjT`-K`+r5=Vk7lpXkH)+z^rE}(OR`C8=Oj7TtJQP+V>ap08VfV zNz>{{2iajq%nR#wt(UAWURgP@I!PWjpD+>xIoBv0#YH@t0jW#vXNKS1Q%BLn%~T5c z^3syN3{OkjBQ_h>tTf$UyOZiuE6lv-#>cT~${zoZvy;$+@Du2tP8PYzA zI`sL4W6R$;wSDJmHO!PTnb@CE87}=*Jhi;TQ8PuLuvH(ue1oZE@0HKQRzu5ky{p};oy*F0&7?FnUQYyru#rJ1Db#?(YGLj zbO;zM)0Z6%#*$p=n>}rK_}+4WDGFVn#(5?J@-~-VW^;tNDqpd?xE$$YIef8_#c+^y zlqtTYy)r=aT%Hz7=VoIq77{{+z$O0EfLqT5uZe7WVsB~2kFSX26gq181 zp=CyzUQHKFe zA~Jo&YZ*42d=VPfF&)EO7gmD*rR zPj39e{6ZO4EgK(@uvrg_4a^0T9xEmS>zmKl2fnN|?8=9kL-KN{n;ey_#yzb^+D~lGwX6_SeiQy{)SnPoE~iMr5JWS)GW#n78zXN$ zFc+Bw!0pmoSF8RWUUwp~>hk44Zlm|0BiH$XW$(Zom#SVtF%%TQ7yVHM+L@#rBBdNH z$P>uwmM2EhVNdln_NX={E!2*{R8-e9Xp(RoVioG>0c)Na;XwF3N! zt+r6Q+1Bk|xw#OP^~2fQYx4|f$^;M7e3jHk%?FNwfuV2(^1NQnd-mf_7cZ5etxjBC z`h@ANwYAMS>lag_fGt>>@gYLGJfW0I zV}kygNsUP^iBDh_Rxq^AN*^`VA#{9)x#)gqZlCW2Kx)J#|p8Fl&DQIYLIsXuvM z^2Q?}ncMPw&;!h;i}^1U=R6PfNiX(Ou{ek98+c_GEx!O7xM=}U0WXg7{omIhr|iiQuE7mI5(Gtyod1Ef2ZPEt|?5-m3(V3+Su7 z%aJIObtw9Ppt;iMkM^r0#mapAp@_oX2yjj^d{_h65e@5cCgNU7!^kas$lH7-Kj9I=x?KN zh%A#~d#Dta)(@v6*VUKv3cbIu<0|laL};-w`}x16O=yzSf9fMC_+%aJiqBudtiZ)2 z6B6|CM{k@=9S^G@>bq>a*S-mOS&H#9^s{!kC~C(4r>Hd*38HK9a+ zk1XWG@ii^5<{{rCwKx!`l;ds{ zb*5BNU%(%3#j08O-XT;k0jOBeo7#Z9jThWoYU={|eaM7AQ#7pjH#!zmso5=_?9fZa zSAaZ+_iuqFy>8hgeSZ<$yf==OpTev$QMoi`?CTW=8u3eo1N`lxlv5mgarLyGlsD+T|6tu?9*M_+}<&WycFQ-z$oE5 z1hNZ>3+m^qaH3dFh7bzVHXObC`l$`MqVhT-Z_}04L7+(wngUlUg7MInFH`FiU5;uM z(pf6$ws&-R5EDMga~m7jDzSMe?rd{dzxAedo;k)|P%Q2~XR`k3u5NT25mMl)W&FAc z+n&?1XdcSNMty_>bfbuBf)5eKHaCz=n2-G6BwV%$rCwJS(y*Nl;Re=k%jJ*xzB4pW z9Fr>SE-vJ-Egz7H{5H&F#wAkaauusiRnA&Oox#J$)S#gjjNj6ml5*fe&3*@j+MwQ@ zG$(e{H!J?)ZzMQK*8q7ByS^%AMi$1gxzVg3A1P3ve`e=5G&oAa32|r=JGXu%tD&OB zKatE%ArQ*|f7sNJrZ{wx-oRP79G`xZJX~c0zJXpu4FCxj$vgvyU zlJjxpQtkSXv{EWuWLO3L7Une~__HE-7s-6sB^cXGWKoOEP+O_2my$Yh$1B!zB_gQwoJ8X)q=FiLBgsBOO;Ys1Ki%6$q2O9nl z;XzuL=lRpT)2@AcFXsGE)poI-n|r%3ELCT)x+ru44(qzx082sg2yY#j}x|O}B2uzYar)mnp3nat|-AX+A~hlXxiX@$KI3-rBe`i-M3p znBLnQNOb1*Nxr{DRB`cgc}2oW$3WJ@qM(ELQ146+i(DGMrK2Y|@EDIj-|p_CmtElG zd~_;pj(Cp}UNgjaj!Nyp^!=N;R~Q{?#n9<2toq$5z9s5{9Z~OVXJbqTq5fphi@4cD z72}PXYVgDEaCPo+QDO#m)EUy-ntlJo>}SvHuG=wRUn4ixB~f3x=sPO^6N$%q^FW2e zSl37k<~h+0eJWca+NWsmj@2FzX!Yd9gc-fdPJy(4y!4t{Keq;5&2Y0R?*7ZYO%Y5q zQB}<7<kfv=uZOQQ#5k4~;y-uulLMAOKp_lVPFLQNAWsG-@mwytI zh6oF1Dt2%N!F<~l`tTya3V?g-DzDqizJ@{O_D*&R1iGOxAOJ3YbiIEGqBUb+jHHp= zy}94Bya*w{Qw3#bVZ?%%P#Gy<85kv}tBnclU#XyxIWwfVx;pW;UYEL>XlT(mR3$0Z7x?U8Z=ymvU6Mj?E6h^IwHdO=_F@`$o^{A2j2b zmWG|u-7d`(BO~~?^B6rCg^Dc1{64k%fa*$$*3RtfH|;nsOF~eV)_~6znUvlQfnIE) zX|${w4e=hb3R=lW3d8Nyi4c0+g#&qfnJVX>lAoGC{98XEk|J2r%DCntBQ z-`%uIPN&!QP6%EJ)|B~9g{bPX^_<5S1yH-Ps%aiTG>Jq7ma|E0pf|4OrMglD^*bA@ z+&Nj-`3nwn`;b8V@6!S>R*OHXkOtUBzqtT4R>8I4fm3hn(4=OulDb2~BcLBi?J-UqN0KinRA~JzHraSo!-eV#Rw_DWAx4w+{bfX^c;{{COnyd* z9AOO?cH670H8h?EhuAJ`mEvrvrTsZEp=lhK)K-^``8jQKAAgrSu=0~+*lvSM#7Kt6 z&^Y>*c!rt8Xav3GR$twP8gf-tT$m|_2qqtf8KxeCp7d}z41aL)E`=!)y}F|W(#D8& zc>dBNEEK%3l9zO0CkYl{acQGgI(@4tsc^6+Dd*$iPOZyP5m1tyaqJuF3U6;a5)<-^ z4h)P)=TRg5_Whu&+pFHxpcG4r5I;r5A9Z6_KGM!{IM#%nH;C2no>M4qsFyZuFpAWa zv7>45H(wGlrTc7~)2GJUSeu-KHJ}^=5~piCK>}GJ=YP@M0js} z{wh7FF3z7U)t5%IwrL|?Z!!4nfY-!pr_)Gk3v&*sEE!@`-%;!55TcU?ZEdw}KLjsu zDM{Cvf-bZ~3xzf&HYOUX`+PWISqvNQGHj_Vw6rXdRyQCpVM2VUGTi?n?sHjfYu~Hm zhtcMi`NgGu=Mx2?Ch^jdZOW&Z&>|j97KXzz!ePddO4FfWQghs<@>iu&`s$lp{^|{MBc-fr^l`BiCyYZXoTBpa*#;`~ z>H+E=yk{BkwE<@rK(Dm$B|d;Wtq!0OIK@!14U}? zO+?KRO1YJbmS6PflvsAaCdQf=?|v@2+cKo5h!(=>dFvHDS`&^(3y4MXsT>(b3Yq3l zxa+^i-=WpFU+%%h3`?E!wlt`tvT9J2DxeE?mP7pYsp8;&#co zY8^Y2C~zg?!bz7SG%a;t(%RZ+3&et2^`d<-da~#Zb!zDAEUBcY-a^88O^7S(UE-*3>L!ob z^1E^k9RnHiHrzWrSu-()n21bg5-T7+A;|{T@35Vn{qKIP=uBh%?pACKtuggV$c|uB zH2)e__AC`jqy~ANVxgYgkj-RzEN+p3BDsY4l7bO=4(&wbZnA$5<1d#=;3u1>rdh0C;2{oS> zLC9eJhRg8qQsX59%*dh~>hlfZ=muYUMWt4t5ra!vS-7 zBuR2*j2!mmG;0EAm!Ji!Ikj#wwH7*BW~8DHDc(?gjyA7NPMB^TM<2QCe>jHOSaO5R zfpYT1FOWEz6f8_wA2upY=%4XJCT7J!A)=q$%gDKU;S}79kA{nD6!wh`$L;zv&i#K{ zn54vc$u+O(T8WW?R7taIKs`Tg2|z|bVM&jN-BcD2LA|usitXFr6!RF&kcL9ZsS^26NdBNfI31^}R*|xm zsTI(W-Fm>zJ@Uv0`!{e28ybURHQyRuhpkR95i zXWRdHZG3XYvq}l9E`tGm-2^`@lQsa~UK$xon$`L+=L$6%63MExtWQlW;&{}~URwoM zClC#cm#RqP}}KT8dIsrMuf;wQ58^E9g*TFme({=84+fwbB1DB zRFF*S_|j9}>L}jpv+_>RwhBp`KT2sq;V=4`G+-@K8eT##tu6aF@}7L znC_-gnT}PU?|Y=UX2(yTMc-LFZA?NTCWI=pNuuzE&+_1~gt~iBO=iolDzS2gjo4$x z1uJ&PDkv$=2oiHB8{8}!|9IU^sY8Xw={hleFRda0Q-~#MNebPl&$fyi>S57}irpMQ zz9ydMH@q{I%hP(YHvbccpXsXVz$2CAfaExu3L~igDmgqBSg|e3`c}Jn=AE0T3J>+A zGk2$FW;Ng&|6TfmVG;`oRlIg-!qWqAWNrtDH2kDP;>Wi1^;ZYp#XyLGBp0v15nWRUNI%*ude6K#KRxW2i)X*Gi7{#lA2T}g=hLOIO zEQL7YYn#g(Vi_Fw7 zX?km_g)M%3W&1Jn_HU`?W+%tq^dh#Zy!nTiJSa0ni8BpXxq@T+k|~tR=CPjN$`O6) zD6v!#Cn8cYjhAnXu2#7){{y%jtYD*B^2cY_TO6I+;ZyX0$N}ZHrV+-KjV-gmxowmM z(@SX&w*KsLtN?Y&{yehS#<+$WlY{_La>0%Mm^Y#M@t6Mv54_v+ol~*0w^q}|!&6b(<#?2vnx~l>{>R?#fJp@7{!nT} zlu>DvtUC23+7;Vh%_7E2#Cn_n+U0Ki)zqRaHD|#B>n{(=@V_KGA;+$_{mhV!4D@Rx|vE;GKlQB88C5Yq;(YrVtuN17>f4<67JcvtbhMr{93+3sj}&Xa%e5= zjnC?G`|&Lk@lU2%4Rw!BBo2b&KpI;*J0;~Lp@Om6fl+8wPY7R>D$ZTPdU8$ThqqrF zi+382h4IajZBruUbhT?f5AaevqtrTqj5>K5D1perBHfAu*_KJ4NTxaw3hu*RpOGIR zuYbNSV`BV>&QXIDDspbDKK184FF!1v;$2d0)Ypf0c23-vC4#^1sLRW%7X&~ofQK~$ zl{iCHEFeB$chB?b@#bR2+I9xSKX|48B->RrQ6@l6?1JJSYO1pbr!LmsKXEk;snz@e zEV3R=sHQ^^R{M>o>fJwlH2th#N~W4ChX^V2%QVVbkGCX3=h2dLx#P+)4BMAes%o(c z%nz+`(Tfj?VPt)-69LQK*SC!E-kl3qN4}%hew`@P3IjXaV;~Rw{<%l@BQ%<8g$s-h zu~p@LmylSO!s|W^NdzowuEWqzXw902s}nB0vL6t^Chwhz-;1}>dNomwg3?(mF^B+_ z9_&p66G(#PZ526NzZ=jJQ2G2OgyY=*dYGAHQDD;(QeZA_mG9}SV~ciVwCF8gq7c=p zJ0>$rA^&x2t}i$i^zOs9_&R@M`T3|+T_S%qL9qy$E2A0PP(qeRIk5DIDUt2H>_Pup z{#K52-zXE6k@v3%ay_=z?M<^ij-PqpU*`n`O~*4-ASpI81FmcRrIS@kUzD3iT6kBp)Do9! zv!KP(ij-2ZM2iho!w1|LIcmoL08Uy__FBV~1Mz)}1+mDW=#Jd^)n(bUjDAMKVVnW; zY!XYi54?3*?1hNJnB;9FPA-Vh6X*F^{HJtz$$%&*@_ut1hG3(KS5CZMg$^~r7e^uKVE2V7IOw?_J`JzP(ecMXzZ`~%o{TFW-eDF`EUTB*ES zeQAD5afuaBXM5bcO$~wH3IXgz1-pj2ySq_u$J{{uIn~np`MQVOk)EaxPgkIT!GVEC zXwZ_-WPjhhAo@puC3E#KZ1<6$Er^*BS>gzhWf3LWRkpkud=&W}tWN!F#m}bu`jNjZ zWA(EE8ObU#I}V{7&(gH}ah~qw0lpJEjp61Cqr{j*@532HIMj{a2oDV#|kv*?2$5Ygd^rvBo`9!=q^x1a| z%~w;Y$hYtJxIdI@YA1@J5P)=19e3%f6u8Ph#Cs!c6ADz`dyq!;hcvy7U`*mB!+V``(%-t%9LpYUqp-pf} zj0j#o>E-pk-~RxkKwQ68sGwkH&&%`njSz(3$Erp+laTlf*qoqls(>YfjrMNCI;z>-&1TDC0BPeAhX(3K$UCyh|s7;>o*6O8r z&MoloIa9pLB>X;|3Gb>i#4a#tC6g+kmrM|nC17o-fg4v<)c#y%uV0%|E}~?Y(Cn8~R)?Kak1b%5UXHaK zl^^FPJ@rD3bIpl4uL1WiGEhHRvU+6p9rg9vJCmd>PCnN%%9Ms> z{)O~Dk&LvwdiH}$;W@57s}e5>5>@iQHW430V`{dF0O*bw*#rvFJ>2tEsmz%5GotDY|~K+ z=%YsWo4T6~u2Wou00^q3hQJ1MCk1Lq%ZOG<>88(v&Cqjfu32`4&g!GsJCddpsVY*4 zpGUvW!KN4`{jQpao9zF`>Nm8U1 zUr0X!TM9xJa0pUDxqciSPmxhjs47I&KMW`dBJM zt*9)7Az^7zS;E1<4;8l}UA+;7t;E$>mW90UGc3oI9W9Pl(o%;4CPZ+Mkd&w?Cm@9Y z0$IpVnssfu)MUqtP-P7v*iOfCGwvlyTTZ+@kpiI^ z)VnOiLe&y{Zv|^)rWBN^#?uUQubC=JP)1HpGp4%0tg;4eh}?C(z2kMU9-td{>5C4Y zq9=|3WkOwm3in3Xf^62XU~ED2U$46x2XE3FsJ7E|$Cpk^=x$Tdsj(V;3VldhkGmow zjv}l8fq;Z9Nk|DRI8e@`%DC8l-x{8p;W$uojR}pN-skGQzYA;WMfIao*&~ePqBG;Uh_tajh8KZ5KOpFEfDcb&y2-RzJEH7c@ zH^$9NRUJqF07*nuV6vp2Z(_=`N9AHghJwmX?f_F@?^0`2YNVLW))4g(OZR0KD*@=^@=D}e=N)wN*z8A8 zFJN}K1m5Rz1}WYw&1nQl9L+5UEy1z+)Qy$9A1sM$kbJCdX1H|$^E*j$c_>a-8FU29G+F%DIxPp-Cw^=A*k(zN5aR5AYAFVGQ+8FSw~L zDXzf|sc($up(w_B<5>j~1F)Kp2Byjh0ZETNu5`zBV+(#Sh7wf4#xB zsHS-J*$;(ysFK`Q+b$fd1~hPMDeR*u@|&50S$%0_(q4P*wU8M&nkdIhCDlvXr;rM*+7Z$d1`48Axr^ z$x^u#dXS}_WS)Sl8OAdG(I|*Zi8xvi^k$3LJmp-j6rc{^JMrN@X~^`}Gi$?arI!$r z78HdP0!l!6Jc>bAOkj1-atQMSPX#r$l0Z4ZZ;>OiR8Zm^=%s$5vD+W&6WnRvEQEPj z-%ZB-`gcD4_xy27aUOR(uOI~Zy6?YR{5G)O*0{f}GFcSEQIANFw5?BuRN}A$&I*GH zF`Rgn47LLyWFIBGN$w7;E>R@cYEFn!4KAM@^sU;AVgr*_f|M$sPi54UxLQ&Pb@D(b zowim$Ct0J81kxIDYH$*%Xl)IYAeR)|313y5qbpbiKoA3+GD+9RD=k4&aa#_dh>;mo z#Kr;V7F$XbmfLF~Ds-F@r4Tt(I*x-Ct^45KZtNxh}6d<$F|yOr)lx|N|MvHmt09TR|1vJmI+KY-9S)n z#ULwKyg{x;#j!S0kGaB%q`3JIY4MLNXV7^vq>|$Bw%m6F>m{T?nOsnbYDSAveV3%g zn_Z}T#CtB5`v~y-5$-4|xvJhGn^27qmRROXa%D4ujc0Lo-c;nre&}EDYKRcmz1mjm z$u+q&+>%jpTnT5y0Q!lnU|wKVLXHrIiek3rz~&r&=$|nO&ME%XPBlR^gczD+*fK zVQj6GNo~T#B8ruOVz8c85}>posl^hj^9)D4Cn~PZJrXTQsVy{+wNf6Q?pC<7+lHXp zqf(Nf;cX5&+p-i)hxrm)Z8+nw8JSCoQMsnL)J{afrBNX`6vI^~3JX%DFu^ZZ>WT2t z%7C6os76~tO4jhZ(V`iX9q~}}6eumZ73yn}IjZxL>#VZl6Mf-?B*a_ADnxLX98z9T zane2wI?`%Fw@V`tsC8j&#^exh)a}0DTE%e}tY>wezDl-}Fi>M@K+_5VWzkNkV z3Ml91ap(_3i&v&K8a&2cdNV{vl=_qzXFsA-CUN% zbvUw|TIVhGz8!Fa*T3%89?S}2yUX_0cPJ-!DIHUw_r(U zFJ)0w=2Xoz5~PMmqnyekjNPPmVpXM<)@>(BqDb~fNWDCm^1p52EqNhD-oW4Jx~_SBy~ zmMw_}-u8!V{@_AGiF8-=k-lnE}V-bbj8Wpcr2EZ5L@kYP zf3lm|3kP-R^d2U-uA$3oXXp48ZLQi#zVS||?=uakshhU)>Fw;LOJJ`r9OIp_vgK!61y8O`mAH_NgJ z1;=PGosacpjS#pwn~zJ1(%B^DQ{?lWmqnnvF@7Y4I_rTWE<9G^k6weBMD`d1$adAr zhf4Sx9E7N(DMtf5r?QFf%zF<&H0aal_)0)PBOOPQN$Zkv)L{P2Yg#Bva>k!lChTqd zOi3o&{i1EqTNdI`Q_#Sav~=l5PQ4N}R9@SVw!0qeZq3x2;v~OGgN3*b?f%B`YeuFe zs?7?l_Q&oF=2}QI=+y>gTswa>gS*&o940Izi8`ZoT>t4m7g#9{d#A{-4jb1#sgh zzB7)4A9%-3nh`|u^BH+8m0PE$VRFjd{_H+Phg77|h?d6Wy`+T&bjfJ-#KRvOK z0X~<&ib)yeImtQy0B7*f-TUap0y0Jb>zp3rJu*FXGQb^y^(V{h{B){y`P&L81a!B^ z#kuDB$0;htMp8Ow8SY1xbTf^(0qe>FaF75bkDsTWt||Z?gr51&u7r8Aq@Go&2PYW* zciZYSrLb*C&0l>Y#fB$L!*)6n$qrLRS`wg6I;;XO&f>GJQTp=0TcEGASrju|tJ^ujlfsbH$;Gf5#`?Om>7jeti8SZ-xQ*9%l z>({T}jS`fD&~)jZ-)57+O^xn$!AMWodUpBx|= zK*oJP;iOu?kUn~099A6;I*fUrKAyVTt_yg1pT!pvdsnlOf|F0VZYa*&vO-Br8%ma> z&$#8RkJSdA%G(G1X(L*!0nTxdJCC3B>PP;;t+Ha0jrHOpr4~QDQmK%3>eH6`LY`t> zQxofsM#%jd{ombNDi}S+m^ha*IaW*nc;6Vv$B|eczj)+X9 zF_Y5;Eo70@=One}P<1Z!B>Jk`Je5VC?B?l*|Cm)WQ7VGikt3~ zG8zoOE2gE69#l}MT_6oQRa9xQumNqbTLaT$hls?HCNyc%OnFbb3QTpWEyzJ1s-QvX zjA(?%LXe?8GTm#GmX@UWsBJ?bN>&C($b+CM(cm~^%5+E%GTB1jeM>;V7yzTqBiH4u zq9bfL+I`+=VR^wSQE@U7qDcX@b^|&^$CQ*p<7@QT?Y`T891^Ni2`lEZ9-&GExi$-= zwSXI6O~^ZoVNt2d_lD#{S|>*&HzE_q4+g;)TUqL$2W?i|-M>XzRkd?OU@k-kj0cL7 zm6lSVrqH~Ms3#{G^695KiASc%j>5@~)Y!xZHkbd22nB-)UEI?%z-?+C=jjiiqZ;HE!c!^`Hf@L}$CS+|^Qp&?l z)N#Sxc0fqEt^#zpIa2pIu8bT4>EG%ck;1Z}Gi{^Y819e9X9-Y54yD zA)$BEOI1?@WOlHVR{rgU{uqb_LE|P;k;>vHDQ>uzxt#GEE)kWq(ih13OQ~%jEh<3k z&&sa!;Z)TIMMK}=y;Pp3gK^J+9hTUNP?WZr)bN)R0QiM|@U-)Im``qi2R)`=N?lWv zUH55RuSsRTMMr5$%9#pmg4B*=qbOMBB!Zw*$}~+HMCj!n8&7+U)9M{oU_zuonZa+h3=lboB$svE84dgs@?@UTq3TM_{NHC7*?9OTh_Kgs3TB4xUOa z8taoHOt|!ht0-v9Q<5pKM50WL8g)#eGwIJC0CS<0r9KLWIalfooi>z;dj(O2pC)W4 z7Q^!AL_(OI0z`n&Q?5A$_XCg;jE-q3TWeWaPli;UZET&Ks{H~OZcPD7L24YAYBV`b z&V=lC{{TpqpQouQl-tU5C48#!5~UC_3W(HhzF7cfTRAogtzdmE_Llds*;tG9xwylL z&7@=^nPaJvD-K-BQbKm-YCcIBM@xopDHlcr0q&HFTTinBqbi|mE8W?V4Hq;8(;Q61 zl)fYLyx)N(yraWu#$Exz)Fnh|$Bk^%XFQpb=}=^(NpUKkhNFN&(tzJP!LnLcC>>Ht zxldH*uCwbQs$Eh|L7I~hE=;npDOD(pEohMVKuQfhb7^xaWiF(-;j54zgpQebXq#JS zI>di=r8{iNmeVqfi&m#orM%G!LJ<*g7W0fe5J*wyVQF)dnO*f3lB|ZbiqS|q^f$e( zN7*CPk2d>@9<8 zL2XIGk`x%_N|l~ds+XNw7TQ~Ni@R|VNwut-Rfc8PZnf28{Y^+>M24Y8537|D49BHE z9y=^B(~{&m@Jk4Al@O#*^E~%5KF58>!ATd}V||ZO0Pj%oClyD;mC;jD)UIn$P~te^ zQ0AgWlj`D%Au>l$?(P+1iVb?0s(`}74;*@vq9|$fI)o+P5(DSL>he|`ayz9f9vb=9 zq~w6xyvoYCz}504QI{T%CB-@7Fas+q2@5Q^u4bK6U(Q+y( za$9xScNMR3Qz2I9b$ITsOlqwfQbUntLVdssjV%O%l7OTsCAT?TLec}1a{H6bE;duj zvH}$1P=ujisYwbXc&&lVjFZe1K*l?kq9t`I1%|@?Y(dy=eMd_R`do`uEelIiRY=ja zGsMn}tQi>?9S)Ks0MWQ0hEgsV5;q!7@LJU$(1KP81QLQsN##%~=4^hk$1ZR|8P8oh z(IMq&b)R}b3?ZI%@Y1YNDY(RdiTd&n6rZp~? zPlys^Opz%=^h_r$qm%_H#}S2xBEvL;+&Lm(9U z$p~2R5R#-RL$bg@!jqBM=L*JsbmEKcGns8=*e!{$RRAa^+xbBATlTsFMj&xe`z%o` zgHwW8je)x{)Wn0eixNO4z*^*tG#5t_n;W+Gg%@qF-R9ekw7Bj_(d5yo_tnDO3bj@g z$xcCsK0Ifm`>ZARCgYeLZwi{lPTyXrt54Om3c}``mI4S z8bgh^CH!6_BErzN+Kf>Yv{G3LZAn>!542-(AHI0m;%WC4B{1#1!FtJr+~*rw*te`Y zGz(%SD7KX;35?R=$_%HQm1&luv7VaVk7YNso^646TU;jb0d`cSY{kh_g+tmq!m(6! z18MF$f{_-HX4fiCsJ=FWr!~f7w1Dq{L7O3&C`u{MOhOW)%o1v;X=jKmagwPe&4-u^ zH$WAM`(oNb0f8EvcV~&;K@8@bz}^?}LxFgXqdCu}%4u_4^CEaq$s|+KM_D<`UM(+C zB@&XYMLx4xq35KLClJw3D9Yu|%Q9T2($H%X`4R8pEO+V=;I^aAweWqA>Q^H`s419;rz0)K>5zoFw4t7#p(;7ncGGQA zkYl1edTUXVxYA+<(HRV_rKl;n4YZM!rQqOMIX%HWHH|-VA?XWM76PgUDpb_DE_hI= z$#qSXwpg5?wMl&hqbX?%ASjaJ6hPFmDEVmGh+Q24_wGmQTCljH z?@N|XT{5DU&1Y>yYX0Uly0yuWs>rA}9Kx{xSxP!F!-B;wmq(9ToQN_I;*;+!+>+)? zTeTMChE*;#K`L~q*BeoE6_1EGuv6bf(PhGRXn54TX(@EJ@)=Xkl{VVeptZX4!h@)6 zwo}de$ZP|X@acwrQ;xM2>!8&XiD_+!^#LK3MT1sJO5~yv;V;5sLa>j8&>cx6g)D$H z?OPF@Tai@ssgJbdL={VIh4UeAffPz|IPoX8RIXA+6s4_2Iq#=!_H7M&KmKB9=R<7H+?W{zgTXxmGPkO0au2v^3A~iah0f0;IE8LE$5coNLtfk z1M`WcWm1D2~cRKB-vD4Yt1B%_nsqZ%N(p4*mEt{*tO?s60Q*3Ug<0TDL zsT*FEj1}9FV=65BkxiVbhoVxskh#wU_9ua_qr0^hMJ|oFTy)l?-&c8Mx{Qs4v8!&= zY+4a14kDR--xRf?b>%z*$to>1*i_)5$d}~=l`FAKTN`n;^ca>7(pWa8*zLW%xgSy3 z)+HJh2HmC^Zu3i!%ovS?u50e$$r2qaenWvOdDj<$8}ls9q^Bzy7@;S2W2M}73cqPo zotU$TI})#ik3S#raotpg|rDr*;Kg<$V(QshfoU)WJ;Q;^00(9 z%WXEpEJuvXQQ}649i+1g1W4?qEyIS?W?M^bwv@KpOrZ!$P!f>nT5tmSU3D2klF>&( z7NVnu@zeE|v7eYaYG`p>QoJV?IiGcFkgRfs(2x}CP5JUAJ{w^9oS%@{J3gKlA)=s? z8bds&?13TChJuDL0vaP9Gt*79E_5`<;5M)xfDYCjhTGd>4li*|6-WbDd;ac+-hS{q zTMnHTo*HSStOck9^Pkn{d3}-4V;)^Rfzyi`BW*S@g%R8kPgCeT`t~2YR*GaqrAY|o zQI0?=R&ci#kQIUtRU{Mg9NNp;PBHMQDMms{dZk2;s?VS~Nc;X+*bZ9e`w#T_{(Ugh zSEe@71oj#GPS>X0Zt%uX%UIIIeu-@&0oZKl@h-l)}XYAkp$(%Wg~ zDpR3n{g8v?HTjfEqgElZADv04L}5uK4@-#jW|o3-3LSN@m3Q(d2c~uUDSk$zd=qfeSzE)@f8B6TH2~3{4j1~>5%+N&4V4vhTha? ztP+G=J9jnmhGQ+WU-ENyuzEk<4WD*`!jk$1)me2>@K(82T&vp232#?4%3g zq|UfoILJYgt^q9|+n*6H7~aEO!n}LfUDP2YD!UwW<ykY*^bWuQwj-b)Tn^_TNlLos z%NYBK^w4DklprXjIqW>i(S<)6x~S*LN8ug2c@0rkGI|hm_6&TnqmJI}X9Fk$(;d1V zz46yM(90Mk4?~Rn$Ir_}FVJVEbLEqP*FL%#K=kGve2=ej*VO4%y@B=X^YF$+tbTnk zDuKZsf0LnA_M8#d%mN6<*`ky>k`#Jp&!?YLpE=hDU+B_{*R8Osk6)dzGR_Z7 zA5cf&e%xqPsN)>HeLa58nk8gs1IV28^ZDp?<2mc;^82*5GJZBV8Dp=XQRn6I($})A zcgXa{4u2m#EhsNx<-f@P08g9XemJ6#Kpwx3o~olheTnFE-1=&t?A1jhoP*3qrawQN z={DP-++!o-Y!rjg4&-@b=lgU}I3u|E`e+t8k_b`iJ0DOy^Y`e{*mcj(MBh!w^!`{F zEf~*S=gUPS&$sW;t$fd1et&j~KmIwTFK*8uS-ydPpEKghPf7AUinYUqzfG7oL(BOCLse5}VXmG7g0TaExah-yK>1dQOEM%LOa=(e8^<5Ul>HR0a<~d-l;` ziDWu?WECdcfqnh^pUZqgGs=oJ4XMiAcM8jJy+_z!0UL|yvG065HhWh5#Gx&sGMnWG zs!9rh?gmG2bo|q3@X;M9jIKl!8Gxg!^}zdWwy2ytPcdpZV5xG7O90Lq;A~BX+jlnD?Qw%`=>nB7r9`D3CP4?W&N>sU3y%6|yZA`GoMiLK zpwzAE(;+2G05>$mc${{+#`dq2d^)Y0MC+lwJKg?X5a$fH*5 z&#YfVEY(~x9aW!q@^sZpeZLf zQ*I=X0M#wGrTetuIo2uD=Po;jAe%XfOD{O3F#FF36xdsSR%X^)*9`*%()*cI9 z&vNB;$?Zj?%6P?(HdRucCAX6nJL_yghNVWr;636YEs*CoFT~=}m2}%{CvI!cp_(f- zMZjs?J1sNdGgd&C;)j@M$UsBWS_c?PUMX)0<^buOu(rufsS>J*bKfe#m~dlT^PZ0* z$4ZdmBubMFz=@Dh-~^WfiBiHqB{&<|W?I*UDKQ&`RAQw$;Gd4Y1(F(ZBbn@&ift~b zMHyF#g^YD15;Y31k;?^&P;JmKI}ubYN}S@qK7l{ocMYc)z__9HZ;rSln0hjYyGMtL1d zvD1`bD^DG}VqdH}Y7wMRLoGNAN^M4D+3-~utC=iCadA@YH53Gu6)8mpCn;72vwL=( zT#X$NoVTINb*U{WRS3048*MMG)cEX2YE)x{uOuXe@?_ye1dTfJC8;E}QKHVHqr^*X zt@W`Y14Sp8z3;IKlHplT=+J;k!huLVb*WEAXD65fvv%q|=GW8G#DQW!9gXo%XWV6( z9&$#IRVxAw5LV*0D?$tZjTPX2)rlJQ0g8*bNmLY5!6RX2bCy9 z#+z}#NuzTv`>^RVf5jS8E(*W?i)rHY01cQ*8ECKS-p)K=9p z$p%wREdGK`-15N+2_i&dr$uq^b7G>=mgA{pq%!&*j+qKWXfL60xt03a!RiNmbvlHn zv9`Sy1s()4im3UnCOM$el_{ z9C8aXf;*k;tlb#b=M5JnlTmgVsO-J{E|}U~ke6jOX5Wp!bX&d?YaG#GN32DKNXat~Yrpp_0}?IjkT@FazbN9YPBwCpJGpS!js`N-OCY}t8fv9t8R{93CxOYx-#PULFQf( z(&~!ZbSOBG$^9zi0+3SZeJ7inxfsWzMsZ6$HA2%Ez-CbTt+522fb4B+8}#%y*m(8B z)Lb*-cNFnFQ!~)$kS5vA+933w3U54xb9Mbz8Pe&)iP8QiTqv1W&8jx|z2XDN@p6Bq<4VE~+|C#JTMB z;M%)uJ9FHeNAG^*?X3ceyQ*tc<}FKB1;IgWhvhW`6T zTX6Jn>Gcr~EO@Ro%ZyBDvn{s}hZ%Y_f{u97n{^~S%ZWe*wWUc|2RZ09gKrdiwYRqy zWwmMeG>QdEOiKHd`gCCd5ZtR!HBWRk77uaQ^^{++j@yS;L$)#1%Xi&zMa-^3aMj z6-!c-kd}ESqMELrvIK#-bu{%UsU%QQUIcbv=)3d0G&(i67PE0wsWrq=p!@YH$v*V; zB_0?NX|)LodC>Jummo6YwtetlO@L=Th8*j@pZtZI&;$}o0ZaeP7ie} zp~kQE?a+m^dri3;wNt~d(24%V4?Ft<)zm^qyaB`a;G8V$IX&rpNTu&f@b2?ZD+X`7KvpHHzj z*7$m3W)9ZwB{svSA@nV^&yd{()yymv5SNNr@uc)1r^Y~1Kq<&I8;vM-lS~gSsXh!D z^8!{B>JY^~6G5e;V`ib*{dvC0QRMXLu4(=d%hVZC(M127f_Wll}n>cdFNHiCtMRc|a zDpL=ZR8p+1E93xV1LusUs#cm6YqOvVSnh71i<5Fq{yXk^ zJf537%o>iIMW#4uo~h)57^7HuL1BrKH6W8@1&ztJ1zttw3SN;ep8HQNXq40j7Y<6> zc^np)tJiMx9nW}T%Agv``mGEPg ze5napZMga3Vjl(E74N?h56Fm{mesPR()RW{NsRwwSgA|k~#s@++1P{#&y)x)bl#k6ip1$Hj*@i9&KP9 z^s1Y?IVu2P#ZAlv{jA%|FNu%Cc6Opv}j_r{pzUZ!f5CpID#YC2RaS9FJ; zP0_s5qCAW`;}V~i#T{n}6D3NTjFy=qQ0RH*R$juF&Qzu4SyP0Zm1O?_JE`tfo@5}8=bsd} zjOX=q=iaje?6SfVpq@kUpVsF;2*~y32li_ax9O{W+>|L^8o^RXI35@(83(pqQh)xR zkkdtBYKoZSQ?ULf-tLzC4^fLwHAF5*uv2S%I{o**^Tu&((-Y&V!q-2B%VPyy8)cFf z_6|NJE%FEd07qLlXj8;k$XksSKH`1h#E!|3=>fK~q0j-y2c8meG}_t}A`3`TFsB_t zR-y?dsN=?SB>Aai51xK{*h*bErLdqdP@v{dVCuo-7|&3a`t|cV*pb47g*$qC_v!pS zI(x9Iym7^;&4%B8)))Kw*!mOS7q~4gEu{K_l2L-CI#0%-&C|_CCmn~`tMXEz%90L3 zKu=r}a1w+N2U16uZl|tKK;bdW21=9&!aSFb%TNIH&N4nca>4sjvJl3u`vYSv`Sc>|xB9ci<&Ba;wg|*l9S17D0UAbExU3GC~vXmqgr#!hK zAai_u@_Qf=>*P9TItH5sG1&nFDM&~wP|Ev!4W~Kh=2vu%yvoY8dUu_q^0t65a!S%2 zQk1Uel>`oOdSIL+4CqpV6c)A5Q}OHke}*P?@y3XdLOhWuL4LMS15k3PC>w-Up$w>rzYcI$F2N)7d5UG%vWd$P>A;ImYr*D2D_ zT2nIPypPe!LJu=C8ZF9<>QMA|TUtRb6orJ95_v*WlAfpI0|^V~>CJ^4bm{Qt=c@## zf|5paf(I$)0lr~{jHq|!8CNf-LUVxRq%!Fs6(gY+2jUM=>MicXPO1Rffn7-V3C5j+irV7T8W>c1jXFz8NdV-lGcN6RR%1bNj|{F$GS^Wl8Dçy@O?VuZfbmHbRe#urtVawH~ z9ywW7GC4n6Bd>0n`g5F+dinnU0G_^tW1&9|2QD+rdU^Efb@fQ)9Wrt1at43mH2yAj z#3Ty~bij@%=b#uJ&#&jEhf;~|KD3@T;zRd3pBFpY~{F^vLrg_5qWk6^tB={&As{a0u(yIPLg-npJSH zy@)3Rr~nUr@^xGfBY-@hNIgOPbB>>%T_cPzxa({b zj1mFwo`=it(WwWf4o{K&x&fYq5tRAynfS6#|C(v?ZWxPztT%eS`#N-ZA+Hwk92=Z55Y|V&>UOZ{gs#6-53BMgu-b$TZ=RgO; zT2Da0^z<5MKZBKMbsCgJxWjEzr3$qPfWat3ou=kS#}L;mstU@ z3)BN*PfObyL$|d`^w#G%X#O>bW)waV%Sx-g9Tw9QE^?g04E9wEA{IQc1F+9&2l{)oH z98D6HH(gg7i{pZOzs9c+8~3<1EzrMrM(0&pqbbMfw3!%zK`)zk?Vrq1I2Z*V&cWY)JafnE)N?K*#)>BI%v`(eeT|Cuz zZI6j@pHhmF*$u4=#-on9>ukKFsnw-+ccDl!UK#BrjmaC;a<(y~)Zfn=nS2lsCqCrdV@ET{Bh+Uges+G%N z-V|lmQ)fK-zOK9D!3D=ATaPT1#ICZ?dzDD)r6nm>GE_#UU%^Kc`#HqE-BPzBW^V|0 zB@N)y6{Ss>-ZG&L|y7*wc48fonZ*%LtAnb#Cp(wv1@ktTdkcV$JR5~hIjZ6zoHETO3> zb*^OfN*PK30|Qz!MX}WNmy}Qxyi{Jb!_zU!WvKn z$gi;l)UhFuf%aICO6t>bxboqLfcTQGpDK?mtaC{Dcn=hkBR?{jNZJ|{U8J+DkgdrG z>O*O>3>~)gh`#KLqASxZ+6a*9==C@Y5$hF(oOGBJhETAiIMGNekI07>g=I={Io9s& zyZeI6OhcDQr&MBvs$116l<5piiojBo+tNgF%BqUn!C6T|YDg+5$oRG1g$Mj5Jzl8n zFxn!Osl>LXWXV*g1Bs%c!boHW%9;sMkA^%l!#Z;rd5Qu81^S!p0*2V!U#RX4g}O;| z+}PDnO3zCTOh|z0kZLg~P@!X$N;H)OjmEWCaCDAZyO)C0sohn;QAeUhj}hsyLh99d z(j9I2Xj6zU(__Vsl`1+L4TNN&Dg-1B>ej$gsLuvuNRsn&By%O-cvC_shL)Gew&6o( z;BCJXn2*+9Va=w>-LK1fWGZzI8!%uk*=@UBkc3I3l|c(}$kYg`P!*NnB`J9FMhXfE zQ=nr`D|G0R5~A%^sWvN5G=)DZthS>nQ@$X0rKS+l8%se&vJ##^qEa$Zoo`V@6@dsA z<7K_=du?(7x$JG|FKgn7;*Cuy9?KqA6rNzH8hMHnZ>)B9vl5@(i4<6FmQ}$uNs;2J zE@i|_q_`aL42GFsD+)@RF162)dBO)i2~v+QZ0ZC)(mF`no;tXjwMS}r zf5_amBX!0l2sq_-pIJ(P@>fHHolcIbic`^^MIJN;pf==)axNxgGPTZ35SXz@1&!hvg>Y;H3xBIP0r-o=dyu^SJ7y^bwEqkj?9 zaDNnW9W^GoYV(}2#8Enh=G0PEQ&cQ$sjQ$hrmJD8qXS!V$Qa@Tn#AI}tOl2L?4a#KqyOKxOJm)Xz8)hCHI?mdOw z3bZPJ6?;gh+o{2lsPS6givlcmsx&RnvO-ExP`FsPrqhkbOlO^HAvNfM*wSXA6g#2U zdFoLsR9mXCXWq;$t77qrn{uI9MM{*kJ5G;WdY2KGQ*cs*MYzPsfrUFJ8GVJY^NqBX z^jC!54fu?>FUu!!czLVGzwTYRVm143Tl-^Grq{1mDex-so2AyanlHa8Tajqf>MB!Q zlxI^_qsMhr`o$rL;bFPXal(0RWg9JhP@}5?Ut=aId4_YMPC}4{CXI^C%2Z~Sc;}0j zhFWN&o=e2}j%nhw)LC|2rK5_fib~wdO6<7NP|(QlK`voe8`VcuNc^_T7d3_9hAIrh zDXP-bMViZ1md&Q)r9B1(HepJf65~Z~BaF1AsrgczLk&lY+Ewwn;<(yd9|=;{GJ5n2 za&H@QgSPv}BL4u0nl1OR^*R>XZx-0KQIA!)E#1SsS+}8C6e?t&bzoeSyN$cT-*$ym zW;=1JNPb9ZDRK;?H%nu8df=`z^#>E%S#WUIy4*b6kgq-0O~GteuI-gJAt)U&Byf=c`#;ewXb{DAXaEnD775W(G4^;zb1!PWo_0IROP%iO3$C6 zp{K8wI97R#annO&H#2Kxok@~Nw2=!csFRtZ#gd}QIB?Q&jV@2b6!j7{I;~VgE?;VD z^+_qJ0?^MGH1$wcP$fvEmY#B2da4PB)R$M|6lg717*$r<@hX%@ZY!$OOw=@%glhGd za#d{$qJdOssQZ;_op8}Aapf?)I@;roY#~jlS{3bHsNNQZ-^2dO3SClNv9v3vv zQ52byV(xwANr79V)vt6kzZNw@9lZUmN2gIaOqPY!QI#Q4+?3NwmbT&ATrzO?!=;%` zrCQr{V_TLyE3Wje-!W|)hUD7H&Hn&v)Rhu+`}1;W&&jAWc}Uy`(V4$g$|a>C)>ol`Z6m1?0K4oRz4Dyx}Ue5vMnBC)nx zL3D2}^TgWytM~iPw{+ENlH_hJO}1Hxi*_88#kzM1HuEnAZEH4|j~Xo|Ba8n41&s+# zzEvscjH+`}R@C(wj1|;BqUWKFBz-H&rY$3^(@6?Hn5ihR29?~p!+4@-?jpaq4?f`h z+k~>tGvU51JWIi5uD&;@uC)22bh&Lb`Bq&^nN-6d_GgW2D|4PwW%){$&EuB0F{iC| z{UbDwV!Z`6pR@CAO=V&P-Ne3kM{rtZwG{}9Tcp&kShmCpj8!-i+wk1}3CJmPAxh^` zl9Jk+D(bt@8>6`GT1coWg2?ctK#wL;o}jHt4GC1XoqR4`IZ0Xym`N*StSO+hb09Gr z2~DwWU5nX^V{hX~kGIy=+1hrkqXw;+6Ig?6(qqtNL9T~Wl+>M{PnPtx6qI|+b~@a>9g&$gLlqHc&wW zs3PEj=t0%E+;kVm0CAROHx%)I6mb*lr5W{oRYS(aY_n9hn7M_4Ns(D14&2K~2xsM% zR`*eETQR3jq1PqU+i}&U+EqpH^csXVfeSI@wH+=(sEqYXoWXpdw;LSER=!c2eQ1Xw z407CgDJWu{HRP%zaunuP-5OBHrzojso;#@s%5Z>#kUZ0)N0_(fQ{}$|g{hfLhO<1z zS#9VJ)Zso>-9Zhxl%>RFP9XCo(Sj41(2|BxDH97Z)>asKrLv_(s3;$Y0YIrPl_?}B z{*VPElDuRlhA{KXMQ~_Sw6_8!@ zn-)c7(S5h5(P6&&%tn|6K*)@ymdmhL@t0nRpt6SAS>{rJ%5tKlWCArDZ)-d|`;R|p z7YlyPsslA@F3D}JH5>l`y>+Jf*oj(`F%oI4%0iN^M`BSeW@<4QD#10Iz2%?<#YxwD zFOAb;j;F1gS-~ph8EQRhaNhF#iLISSL z#Mr1{R_kHAj;nFA08d~mPAABx&!|AGsW8Jlu=683nW@!*kqNjcvVbGK$#~iBNFkU? zEx&Hs6bc2OXi}q4Z7VX7PPVOz6eJ~>bjl?rIw3)b+h`aVVX&nuy4IyFSyGACLclCI zGC)HA095u$7OuRf=1*;TTyj_9g!2UuqLG{}K1De0q38B$?*cj8ER7YY%n?goPA^@-2Y?SOK+w9R<4%mfN7l4_u77bBaJJ zN5C*Ml=Ui62kpo0#id`F#lm#Q< zBPTu72gFW1`vH$Vdyx~FMMVTDY6wD8)Z-u}AZNZipH+N@kg?r~`R{+>hH8xDO)-s6 z)y99*^ET~^RCZZy4m~N zq?Z%^QX@(TFC=tRfgq9r8pP2Jn80|wNF?}epg0161wW%tTxSC(pzJ#7Jw~CzrtwC1 zKeWT+*?$)JDa5abpjtTO%qK!?YL?L{2JymdOIu^ETLZt@i~+wkMZiol8*dFZNk9op zi&C2aE2%7i2|isw!9C7_m|rPUiqIB8NDQPPr2r(9qnMD{>XVV*B;;TXU7u5~XO$o* zwthD=&V-T4@Sz7IK4Tz(p83`{Ez~7oDJgiTm;jUjft9Bxl;I%Y_dQ3Zbl{#_ZMhrU z=ly?m@a-eBl1-V9{l~X+u;1Z}OYWnSkQFFkj&zQsrAMmXQoA3B1dQ_m<=0sJw?Rk? zQc8Xh2pqUlNC`q#yb=<8us&qqom?k4;8Kzo%%ZMe2?Q&j{9K^*z}77> z(2j5w@vEvqPE~+1Qc8j4JfM%esp>Vbhp%uC^B=pf$-^yD4fpH(KK}r_w*9Y*RQFP# zqk;)1B&VOR#0rW+uoKt6kvSRH20gr7BSqp9gvndSZc@X$p~DJhUGW@@z$1F$v z5sEGlMluXUe*Xa7t-ve*^uQgy zI2~ER>Hh!@{WKzuao^9l1Mtyn?cW_o=kw{IoFD=-ljn}VKAKerd@3w=z^fz6KYnrN z*jI${>=#AQc$*Y|w&?Ib9W4`YMhq0&w^_+Vq-jE?yj0B0G>PK#`n zfz$we@z<#7)9?M75VQd}03_s}Pb`!3{=HUhK_m{i#sZJa)cx8(n{~j!?I)K5uR?ow zKR=Ms2wyXaNlrO)@gChgvVM99JdBirRoLKlSD$?Sr|{7~3yJu;9Q-4w&)fLv7V2?> z>+|W0yFe?Vh(9rt>*@Du_eQDIXjNKuZjmX-HCjaYbvj(elu+zijXq0K;Yw{os#J+A zw6D00SeOdsPhc=PvD+i3Purr?oG5l4N4WX*^68?G7!_e~b|CMB55%b+n-E8EM?;Ch z@aee}J}h{A+dc57Oh>;|X^c@f4x0r)Nu}SEHk*f8i!}&2XT^EH85#X#NI?XHt)aBi z^(eOrEHwBItC{yCD3;LEWDvEh$z2CeQ>dYPDEQ)u!q)A-VQx&v2E=a^%5^I5acWYV zv#wH85{G-Tl7B@RDsc=>$Nnpo)1E`Aj4s@0w$FgL(r8bz#YUe{fZ`-Zt3i^4y%Jn` zO{k^#t~9pP3P}f>R3{Md>C1B&V_3<8L#iX#sXZ^;t@NAs^ATnk?~e;SP;MvT+E{C6 z518eukkuh#Jn8^h>^CBHU1HmF1I7r^hf>6^)Y@@{##D7CM<7E^Wdyd4od^E_7JYpG z01bKKlVPdcWb7^b!~ND^Q(3rRH#*(8oJWc+i_(|RBHXE=UBq!D_)>A*i3{|`taLtR zWVIcjJ?E7?j$`0ur1k?HfEnqnfTT(iW5!8zw;8o^JhC}Vmk=_dq7HmKf%fZCo&u$I z(#v8k*!8~KUi}B(i$ZMHdO7H`OtBJ{wvEIen(B$()oTX(l5YZ!?xDnJio{B=oNaY&+6Mdk5&K;@tg;;Rn*4u$(Zw0>+ zL|YSd+k_mH+$PYqH9@*#v_h)3>31F(C&r3ar80R+kYOFf-?Q6_?hdO}Djx1_Mauo2 ziIN(nUzX)P%H@??hTDZHn-Z-Jr3PD4FswPswC4pHv$87sIpIiZl~$=r=`3{I9j_a9 zd)S58f;*0q`kpGS;@3*dzP+;Ar-jzGjc*_lj`Bp?RM5(zMR)qgL^>uBwVqaD&0_Vq zo3r-5g>_LY)J4r*Yj3N`_q5y=eM_p{k4>yYMkzDYLX+V>w8N5lm~|;qk(noZ4mfnW zcB6`3$y)p-o(NqrB9X-B&BC zND5ym)WZ1L;5%UN%hPVSouk~_cf*e0?7dnw$8heAwAD6)R=BNNQ1PCk%xQ@%ME8=| zcqUVbQn_DSY7QiXX)3W*Uq!@JwCfEm4Lb4Ki}( zhBPZ^pl&p3q<^ z_?h8ab&C$)y4jG_xc3bu+4br&9z>eFFLnj>nGGZbRN?qQEpiZr1b79v(vgQ3su6gm z_IlFq2>bO(-70L#eKu8Y42X0YZYrewwYs+?RAfh;$n&t&`(Y@WfE!R(Dga5>9QgS5 zitgVZ8_{G9y}qwKuGtNRxTyDT+%DIsNVY37uNoJKhORn=LMaZ_U_FqJag#}bgGjGz#Lv!!oZ)~43nH$xOk7U$oV zOk1{9wE=}fpx5WcpHigEs#;LpC-f?Inz=92n^|%yq_5qO0=XGSm{#NmEcz%*TJiRTc72yEv$- zsnp$UGFyu3!SLgykeI`w|6+*ytqgR$bof>z2NeVTf`#+wnR z00^eWmG4eG?oW${A5cq+Mz_*P&?T4-gKM4k*nziAhTV;~Hp2|LWL1&E)Qf#Yc}12< zBt{&l)s5XyCi3rj8Jn4QH;KZoR4J5Iw?LwJ6$wL#_cZ*fp*`4)yLMo5dAh4RMxg3v0O9FGUYD$gzuNE0>_zWWmTaGrh`~`Yg z)yo`_OHSn_r(q(u?35vt-(W?>x3E8E*4R4mzC?2R^OzSC#|U!rNJ!@vyll;|Wr@|D zil8NxgL(A=V5_$jiF+Tvm0K@+=v5m&T?Vxx+`jFb)`Ys;ShLxd+(&?wOMQx!sai|R zVAF0YTaU1%xWeVbemlu|Q-9d6X2!try}(Y>U6-vwg9~|X8+vU{%Hn5+nDnY0{{U)B zO;CRalXl3rs!^#MiF`q36eg=R1Q>43@e<;sd*cnt({}Me(CVJX;f@VEnjRa zJ0nG5`i%;T=Gj{NFpCN4FRfFjTo;A0RYfkg)bud7R^-@l-z$n=@g3&m6RJ)r$#V?a znzuH~tTwvfoh(OCpaLK0-$N5mQZFNd&YJSoLvAkT7Kh>zqnL-d%W#dLS1INL5Dq?lASh0bycbz z1@?sPOsihkwKnT#w&P>%+cJ}6-IsN`{U)0xk8)a91ZvbZ-12tv!nB~XOQumLRO@g= z*^E8nGSv4LS#~2$>r=SO_Q!B+L;U$RWz$A%~;g6$xD^dC0kKslrvFFF){|(t+$)JRCcYNAgt?Gb~dK7 zx0TC=-r@2d*HGy;m+_@!)oS&6oQmD!0-%;IDx~Xzp*dFjgfmU4K&`H)COcIGI2r?O zc6)~@{9tZ}7xiua-Myu#+pSxBVOQAuzOT32Rb$)Kn|{%^*@?FbgF>lHsm-wAMy0}2 zv~+z~+pm7azkz}{pGN(3eCr7?)~j!Rql71dgq->uGdQL z2N^Dy&(_?XI!UTZZ4w?!ZoVCPv@E463FsB@qL(<~E)b6-&9Ye5x`MFIwKCMsC8&*I zy*G&JZP!?) z8pS3x>2z(z-&@AsP^;1EcLm);q#2hA1yzV4nq4s^5)bKQ%3+p^gM|B6v-?l8!r+r- z*!0Q;TIHV+ca_sfZbdHmZlfL9D}h3*PkMBxBU(&IlO@>fCD&rhb$<0NGGubP-i6yd zO>q$1W*vKo3)ZSu!rA7OiMNeX?LwQk$1;i zX^JY*sqn4K)+}Va)3OlFZkW)Aa4@jf#R{tpZG1&-$YEa?*5ZCH%=m*fsr@3)8a0qd z1Wy$>5rr1zmghMd0WTuE0xUGfs*5tpeu924cyGXM!u&a!<=jD(3C(o0iJI05x~ifI ziEUd&N0!Fx844B|siR~?X?>=2Mt<$^t-SK-5@hXN>nc3TZE{?SzTDl>#AuYYOiB={ zot0c^ZiLb+@=6mbo}_cep6Vnpj|M`J()Y1d%6wHRG8gXZV5{6zgUL~+y7EHYXTorF zh^H~k+J`1`l_ZW*ju>st`DAZxyqb-vS9yd*l^L3a3`S-n^s1uDwtEX=2n75Q#?MJ`2~QOLx)5kE~QBe9)qt?`nf>IN~-sDyKht1UaQNAL5EL6kFKH5DGff14-iur zX{RMr98pq&<3(xpEk`LrzgtX&SA46xf*q&XOx5lCYC^ruccL6(CC65d5Tdy@>kKJs zwW0DYW5;)zqA*ZV5T2U0%|3NjvfV=NmrBB+kJ(WQ9Q=46okl_-@d(n^-K6)csjCt;w`#7bg{)64;7 zCn@NlR8U)1dIfdQ*{fZrO6G08cH@^a5<^K)WzW%LkY@=2~p36PwN~J^ZaqCr8PLFM6e@B7xf(lx4%xC{ur+6s|`$wlAYvlG1y+@ zZ`-ZO7Pb2Ng3monQ%-@&h|V5n)<5w|J=;<8Pf?9rAyW$rD@sOB>wqwlpI^6GyD$*= zalTGuf>NNcK_DCjW7nwsH9^>-B9h1JCm#aH!RgnK=TA}2q;={1ef{v&S4&353Y(r^ zhs4MLXF16HbFGTERF)FfPcJG`K*-3z89yR3t!8V1wf_K~AvNmB1mJAK_WRGzuY5V^ zZL~AWNce(rj`&UhA0zAb>A$=x&O&U#r-c1yDYXDc{{RAvu7*h?^;{<*9(n8KtBqRZ zY6~DVQ0%u!3`PXyN(UY*m_Gw49aMW9;AHCs4XwpFE<=ia`7U^pUs(NhoM9*@^;-bp zBd{H`jUaP zr*eV{f>22K8Xq1(01%}E(C4l_JvD*Uyfg^A+@`S;GLWO|ty>LmL|py||l*nI4F#gcTyE1VY;>aapn7%VapPeSX2r=LAC zG7<^S4^ylK!hkAAHWAD`&PsB65_E9Z(mUVr z+wi{P`*i!B$*>9+Nj;BWjkY~H5U1jH#TVQdDpJam`ZDT*lG!aJsD&+FN3X@#t})-P zvFS3XMw22CZ@wP_(5;P;eBH&ZH?^iveJ^kgPa@6b>=~CphViE{$R~^!{HR_r`@xTF$0A zuj#VwVebB2z1OnLDj{7!D)@*|IqQ?rU(G!;oOR{zjB5~{2P%`!N{UtStCSIpV3F8h z41N6uvgug?Dp>&Fj3^M2v&^J7$=E!enH_RFWOl`B3ePAbs!8S~a+PPBp$S)3@ssD( zSiw46G1}jUZlAl|?)}(jkpLpwd%Ap&lZXxba_xrgk7+LQNevc->1}O&_~XR^D1JqD z$EL-Uw)p_@0D6+HWgm#Bo?=dQ$ilR!eu-sR@9Fkyw|__&w6ADmo*SXp6T|+^CH8^; z03x)*xO_B}5thoBEw8D`3kLvWTt-uA$5D*-ZPTzMbnDyl$20LV zEPO?tBA+j{)F1xWJ{vlwn^M zMoNI}I{E2D>x=__o8!SGoc?j8uL?iyWA4s$w0%Cdzt6uJ$F!0UL7$hdtEF9zI*#K# zMu#7G{*n82TwwJce=hnZyuS~_=jVJ3R`C;@b?fJjpMHpM3c*Ud9Ag;CKEH_kH9-jg zgWUA{I_RX~J+cR0-Tv(M(o7hOeEi=T+wa9ips080-Ca%wG1z^&A*6F8DEA#gN1*BJ zsz8Mg&vDm9B=X?&^drz|A^<18F^_0vD(*Q|*Qmxw`@HmfXh=vH$xlwdyQYLeC*nvM z^e3m7`?OjXkO5c2ljr>G`h4`67ucSk>5LJ49M(E=^cX!pUB9PBAPi?G<~)hVUYZTE z7uTpA{X1j&^<4`|UoUb#e`bGYmXpFK-M$TMfsu^l5THg%x=bblZS#36FPS8{(`>P9TR_sUcAnZp`(+>F-dzobEM$VwN}!EM)*Zts0g$TzN9nyzqsNs71$K!tpID(*VY4!kaM9$m zQKZ%&%0gXgWj>)9N^RDb(vng_x^rp9rPACjHk<&`5`qw%kc6Ouaq6SjKW4u_jtxDi zyjpNrBU`(9ce8hGYNa;0dsDap+SRPXN^lt;!ROv^ziv9D72q(i*D(jf#&tU_q2hv- zd~KbBemiL*8NO{QHN?2_9uLNf?M@?7AB@wd_1i++DF?n2s;4;1rO0KBRh4Mw)yrkQ zn@*eDby5Q^#^ZY{wTZ`K_<7<4JZl_~QPVUThF+-i!yyf&Sm_TGmjXo82p3d!xYU3f zovxFT*E#72gxaobty+kRR`zGsn$R9#L;7r!v~dvP{vVrr6U z3A8B{d!mg{mp++pTjWt`)Y`I~@ghyBNP^-^0y*VcTSs3L89gzsX79HU8}-EXKvHh2 zwzV$VUZT**~M#~uczq<{+CaF9s*HP*@>va+LgI-1twZp8YHVolFHj#GibP>Z)i6HWm9rC#=^g;O>RWp zv7|p$uh#8Y@zYY1OpQ)}7F$=2mSW9HRfPDf_>MKLmQz$y%TX+ji=Z0m0br1}V ze@0LVBYpAd?}91dCT9(GHba@s;#VASzF#eUT+&lkyYk{HvaV2-aiuIl^rXU5CntCdt;}c7zfJeMI zvaWN?Qjvfp1MTbI>fYCIH@4d!R$@K1yWDVJ(6@g5v|%>f6>Yx_n^_@oHeYJmr7{vI zl$Ph3YsNP!L-HxJU2!ULN>-v_u`tmmaiKau4b$OElrxMZrM^^;pFyijhq9<^@>;Cc zv@<*E5QY)Hg+LTHo;CtTlHrH|uAM7kx${5iKlJDELZ8HD;SUZoCE&b|gb9wJa-7dM zrFxpvw8>Lnl;&Al8IHQXRDAV{8Fg)q=AFsmFJrE_lTju6D!I8EZSQpI zZ9?061e;R#s#RflO+Qk3#wsmSZfZgIwj`wvxZ;+=83}O%Znl?;ebl#vXcvodHxh{$ zAu6lNmWoa13OZ1fDc5RgWpVBo0sw6WV<~^&0KQanu37ssZnkf2q2dE&Bs$ZTiWOek z-pfuS%26&-=f_2Xe!-`-KV8;m!n3L}Fb^tc6{r!Du7cUNF*BN5vAkxGq&g#zzw)UW zW1p0KNC)E2P%+Pg*i&3ZMI8oXUr8eC2>O)l2@Vm(iiHB#(sbEwq+4NWcZNP8(D;|( zc3H$6Q5;qI)mzoQSz{!R?T=F_sdbWBrKtvKi%Y6WYR%9+LhbB3PA=|X)7V1+x zp}-2NstAxFvPbD19`e7?wS~X7eSsE<7`WRIY4mz@zEQYEYaT$$n}`PDg7 z7Nrv5Qr>YzN(o2mLqq8VGO#xQLsD93EK@AOXyTb=-;>WJQf3Dqp#|By2#~DFb~>cVIT^);cx$+zU?V zj*!BD7i9qkuhu?iaNGG(#Z>NW5pFb#b}t>c;n!{|yREp)&qz>Jr?<8w39UxBZ)(6o zs&w0GlHkPvlAQB(5ZPxD~!T^SPWwRG+HuO?~OqK;UwjU{IZv zO50m;sK^P6Podhazv0aHc7hUT&k|}9Tnc^X!q!lii`qTJ3tPv;#qAcAQBpRH&4wOrc6`w4ih6iR))}IDeC9**Bc~Yj3aX zvfPbzR&7g~dvWd^x1(1AS8CJmN-~y_K)vde=N+D!B$ckEOQ)tZio6(#pB07dQ*ivb zw5bTG6tL<55?BYYCt1^ScLYYgETNPZzMo6HE8))!zKot0vi z9b{l7D0N9vV$4ZctSFtIB`@T}kB`I3)m# z>6_Q??6Ohy2Ij=LCP;O1lFSO75`5l7H}2&Pz*RmotBZ!uBPopO=gN|kkab|D@8s|w7^kx@_Nsjz=<{eFi+mX4jvk?@W{#6GtjjWaDdj3f+5;YT z@yY=6$SGc>ffg!Q&N}MSaO=MdKx8cR1gMd$dt!IGy||Qi zjYgEkGQV%nLdmD0`84_QD%9l%%nyD-Ty6u5p-FZV%28o#l%dBPTTW|MckbBTE9U(A zwhcPBE|W$LCImQixwE20F0|i`QI5EbDU&I3RPsx!QdGiQNajFV*0mwX$*L<^UeFkT z52ivC*aL8HU|4QWpLUzvW1u`@`eSg2fM{W-iJ3SKnw=L?lYw5cI`l}J{>(ynh7LxZnaw`^s#%aR4aCicLD(+cNZN z$%S%W3^?Ob;VJfN6l;D;0SXmqksVW49cj0RT4N3vY^dg;A<~f*d4|RDoy4aNcg(x* zW%pj>v}aXaO740a?+b#&zFA5GL5ufq>S{E*m?eS8%fXn_Vm1SCWyNd+h3hyv3glPH zN3xiP@=JFU8{XkqmLL9LHX_!I)qx&OKl@6)k{mz8^%Y(z@ljfeiSBr3hv;%zGm)nH zq0B1t9KSeoP^=Lo$!Z>}F{NWV*VkoLw8t)+rBwRP=WwUGRLbQ#R4J3Gh4}8puUmIr z65YG#l2qWR+P8hHdQhp7MLt_irNuI~$GXZ|CB=Q2OrhOLLuR41x*JPj?uC_0t~GDp zR?}B)Hr2T!O_J>qi4Mr8RH;o?7Z|?OXjM3J*5Ex#L$-EizfJd*6>}-X)vqb^$nj8Bj*H2{i3!h5bDxO+0HogK zi5{a5hQ1BtRhbD_)mx>%SInm^D6TC`w#=zk4%o(JU^><*)CfdJc&^FI){T9!9ybLc9iAE`|$)UhBAf)e83 z05v%P*zPyP!!1M>)6J5wg*KNIgb#(~=a4AiB?Unzmz$Ilo|x;WFilI%rXvdRB%VN| zG(1lU3C}Q7pmLRGlwfDJN!R8FE8ENMPo2K@=KVdywA4$rUYyl4W$Cuv7T@90MFObf z3#r<*eW#+Z)Oyqz2#(r*u$uI$(?kbYsJ7}-vDM3`=?rnx$A#;*yf*M-u;XR!`~D>^ zhf%lo)^Wb~UvMucVkOIgHl4>-h{F~&jKOMK{Na_%ViQYtRJ5fB5~;FEszoz6NzoTk z(%>rFbIdXYZ6e#1R|9j~5G3(OAj}q3r;4N741pkkCFGc~0d!c{T=r`b+UCO(eXCsd z%^q4HRIBu;l?4zz%~M(Tw3FC4+8300_r|h%eHI0BD4L3z7Se`LW3;z$PojtcUv_)z znA{P2KlcM??HWzn#Z~_RGjeyXpvo#0S`13Gs+F~9%6KKk)84B|QF7(0wzVifC0Jy* zm3S%S!jDUtWiYv0Yng_d0SIlSDJe=o0U!k6V*^lUPBYA9ow>9*6$+9fQ52OExa`hf zl(B=@Xb*0vr))gYwtG4Dim8%?TXl{mX_$Z4D_Izk`w9o~#Z;Pg4qHePlOry2VQ5op zDkm8L`TldKLJQ?hc#QzR(G?*Xh?MXIkA}O;Tlcnv{a{R^7_v{{TEEpygTq zcgXkC%Lb%aX_i6kl!KGiI2g`8-7UlIna(SzGj~a3qBGlJ9o~$$f{(7 zpcN@N0VIafg=Cy^p2NT4s-~*bY50}Y{{TBUB%EXqKymi#7^~IdJPM9HRP;-U=%i=$ zK~hIhI%IVRPtj8HlSMmp^&6jE`fu>-@xydgkWDx;!{r-!dMFkG%6kF+A@}0tCQ8)O zil0kh0s>hBoRUbuE_U+j2C#~Q(1MRUX^^z@VRBTrN=J1bReUK(AZMV->JL&iWU1Dr zG}?nswp#}U<#Q`3K4l60Rbw4PQ)Btsx?;JEwbh*(%M?{W#){6Oz(gVOzPU}}d6@mpG$n&43ib+@u>h~-vLM>kHiR?~`F+HKN=ttu$PVd9{?l9fHm5g7aj1e1W2l5(?;qDVp% zT~b>h^Opb(xZ-(N`Zm(o134)8a8xk7cj<7BR_Yx~e669L>u`lKOPsDa_Ckj+0}2WN zfItca9c)JWcE98Nx9x6*-+iy6P>kJ+4_?C7`?~wh?~HD2QkK2sA=EbE3XUCYD5wF^ zC_z619H|8=$iZJwM|=*b64F)`%gR!q2mq-m7zt54xL3rb;0zob=f0fE%PV9&w7V`- zj(}Q3rxZp?l#r(Z>y;y&NBP)D03|(}YMM-$DTtK>spq4_Ldt;&b@d^hVxVwGh~OZe zgnk-SFar99-|4@8oqhdq*zpp|p+Pqt0N(bshwdGI{6J&de{i*MdrG&hrW{iL0D{)e z)LF7putHj&L$GNtOG8AH%-4xh7$eLcn&hg^GuY>*I%DnoHMcx@?mS)G<70}w$b{*7 zopNu5^qO+{mb99E2B@oE8ECBJGFhRaNF9P)0CXDEW%f8dJ7D8K@znP#jHLwheOx%=lRBkQ3E;o;CJoiq8ulw`T2f*G#beJ$A7a*Eym-1*vS3( zpt3SL1Jlnxxc$0X@S~HT!|c-1xEQahs68>)r{SRxaC)3{)nWK&q5CtW*jnSRt^WW# zWc4Q2z79z^0FIdNk@s}fLa+x?td7|E_RrolI#g5B9S3jhI`UAWu4OL>J%G+f-UqI9 zgWlfkWkvpfmM)E`U;sIZ&Po1}^T5~DEUifhCkZ%Ld}sId{*6#+yz-K+QJ#QxJu%lA z^wG_yIl#_;q;>82?WC+v&!#YK+Z9?kBO@S>F5NwS4}BatNKc?Xf6e1w$FKJ378WF7GP~TH-{=1TI3+6x$2z*7AUpK=Xp-(mag6!;AmHP#UZ8sP&Zj5rrrdV-bAg?u zl>C%Qt5`~@?e$$DNiH_JEQKZkaXm^wgyeo)<0GilDt6awZoSjFV%t`=F;nMB1?9Tq ziHlCB!a{(NRjpKAPlrmRxBT~<>Y_p#L#~vd%NN-K*4J?HYVK~)*LP-*BDGhS0`I6y ztV?c-Y&A8A$%P^nv+wQ&xY|s^-~xZqop4I9B|yzFVR5+f#}hEg)>qaoG20MAxNwX0@$2)EhZn{#|FJBl^s zY0zw1dsY<+Lf@Mzvw7DcrbW|y-O^v`^wTZpQyH;<*v5LKYipwKmct;FIlQ}W>A_2l zBIBn#f|4+_Eg|9*2qz=Y8V=&)2ZkNDwrjTxt;nO*srIxNC(WZ-jeT=gRA#!YQ>l=F zRE2-CfPU>k;f|J`QsSZ^sdNBYZ*oP*7dxGWw>^hjW3%$UKH?mQA(Kz7V)`zAF<04m6F)+?#5yDOC4xLS)0Y zDbZHBPM{889&rdb__}9NkKzl6o%iB@a%Aov{q8M(^t_&F)}qI)KB&!6sqQGO)2LS8 zz}*I#G6yS6pr`@PwVt|v%Q$?`E};_BBK@W|4hGk>XUrJ)GAeR5as{7x%QXBpd zUP^X+8Z1{_cAIHiQF)?UHjN*|KMgt!I|=5%FFy0q7xB7vuUt9AVan~(Inc8FDk75@ z0n;v(1rj{{2Ce(#=QZ0MfI;^v3`gDbJa4Xdiy8)Qu^4e8m{i8X|x$b{xQWJCnCkNhhf!?~XM!bro~gR#i&V)l{^y zNauEED$Gf+?t1_L=l~mHZ9hlffa-nA!w(RgO5F6Wd&hEP$lC3jku9-^bbDf4THV=G zhLxw`RZ_bW9XPrV#U7ZX4vIP0sP++|)gO-JbuwC#>tPD!OW_DOiYiV&)5xZk;ZRe-7l!Pf&ilip$wP_A?9L}zM$H^zId+Dg+7lx~r zU2fvsTP8g^p+S)U0M?SIEIzg??aq|&_n0)O31^b0&o#w5$^(c$rcho2K{S^W(Kcfo zS&AmAgLZ#Xj&&$KH;GE1_YLpY9g*R*((qQr6LnsF%0273qYh!3M2-00*be7U2!ErA^ z4T0gu%VmegPwPr?g((VI1t1WV@~0%KR}VYOM^Y5#-%ON%hL_DsnM=56mo?vaiS$X4jf9|a%f0TQIpv9#-dSV)k;8;l0sXy zhV&Nb4ei&{($*NVPJKqY=K{~zga+XBLPZQva6$T?d_gbxnHW#@9N9)CWKPsZPwV{`P<*-DFBXta;CQG ziikf5=R$n?ch-peZ)$s&!Vj}obhle)_fp}qw^27X-&+uGD|x8Y`P9l~$#Ag-u@;Eq zsC95^FUBiFbGiNHkV=?SOTvVvlZUf6r;@Q~+6bdDgDk6MQt~8eWhGs%?f}vaiPgBi zA{obtd>fW98J$_rX<|v5T1pwwWtl`y#YI;pq6o<<3v&^P7eE%_mNR^G?mo`&U3uL# zeT!oLx3{M3t<^4j5{tf0TWjCVw~up5omCrz{@KwY$ceD@lsP+^-<5W~BL1ib!_>+p z0kY*~5!|>gdxq?;Rc>pBw^z7sI^^kfD&@&toc&6_TBy!_awkoxRAjhT>+eWf*5Cvs zN>%~5F-OiwCnVY`wMmtVrAoD2ojRvjtkk7eD>Z7A*;Oj7VzW?l#-CTK)aJUk>XkR1 zB~HkF#~pC>T8;*QZDnp@BnGqbfJZStx$+vYavmR}$sw{1bxgl%LIuUbjS2fGG=LW6 zh*j3kRY;`#c=}0ro%DdrsU+hZ?qkE*JaI!smWic!5h=k~W~+B%)z!mOzqC#Da7jHt zpn{4S65vn-C}4sz2s+HEn~!nP(-o<1z`3AA z3lZqItu?!gn3RuZ02cn7e?ms!zHKZ#f4!Owu zpO&8|rh=g~O$y4Rrl1Xp?hUS|-YiFBif@N_r-=AUs%pL)&Z;tLD!@vGhC;B_L=E{h zl;-sHwB-G&YPhC>{{UV#7Q zfu6YS-(FO)p4bH7A0SEX_G{@0P){;}#!tdPBiB8C&23+AFKxZps#OB%TWJag-2eli z9-f1xvE|f-po4&Ya5K~F^U!Gv<~+#=ZNH1+_)bTk&--+G6cjQCk;pyAmtVg_sU$a- zG1sBV1pJ8r_UWOsZ`%g32HpF9{{Z8PZhN}GQi7HU$ihhjwn-m7OXKL*aKmHY+aty% z<8Fn6Y3>cLxXQQqeO;}2P#|13{dUhqEz7F*r%r=ZVQsEFiPd@|PK5HSFc6@mt+Xga z7?qC*HlB(~lg*HjwPP3q9S?0yd)a5WXJ@^S_PcZjq*1GTmAc#GRjtiWG-;}&Qm&}h zi%!Row5P+5Fj8GZPoSv^W*X9mIf}VroMW58l4VI*Pz;JC3bBg@mO`z`jS1*Xp$Q}q zh#ANsNX3ESepYjCFQTMKxzdQ_We0V;6ol&Z8f9<3*54e#-#=kb1ar8;xzV#5@3}Uw z4s?f>FI}ahQ)!jD?Z0}>LZqU^+U?i5ACTOeBrx+nJc-aJ&!;$~MU3S^PI%032Gsi+ zeVcoII@q~w%QuLMZsSlT#(LP?8aEYp-LHAu^~kZpk#bS0R+TCOX%(i_JW%5(OD(K~ zhL+#LY#T>$%bi=eD#apElX_hhMf7P3S?5X^MIC`5md3r1`BCXPyssLn@Z(& zqb8(zT8PvL%u^z?%7bp6VkA_bQ(+veEh}4XB}nF9D@p{UkTpkV++)VCI>_1eL@dl_OP9 zoi`3~)Z1f->f~x=5}Q{-E30ZF6z1mDR;5;IQR$J}kM*5iqRLVy)t(4SPvIMZXEX;OHy9!8;K|$M;1uvlggrc08Y749`x`eRSRKD zk3xpcCM1w@m#S{IWJ_QKtD=zVqoqM0^-8h`8VWtzDToov?;m`Q%$l694bq-ph&0J; zj;TH}lzv6OmXyl4$2O7U|W3wI9^c(4Fad)Ri@*5q#V5h~id z_=K}z+qGyYkjb>>-bt*krzYaV>n^~r)zHIeeIZ`#cLXbE2hCN5$Y1bJ`!d22_t-+Ag z)6p(lM3sW9-eZ~w?_PGiVk0R60TJc$LY zUa^#2yxC~4m?2BI76V3k`GLtm^mO5oo0}31h3&z&oV|x z1eA3-$j?)d20-o0^XipFI!>A-7xX>B>~HJS`HXHuQ7sgrXbtVLQ*y39WyaSY{fNE6 zQ@$^4*JZiLg5+kxTv|({I_D~qN##&+BRsu|i1D#7vbcqy2V4|7C;I-ji~d03X)3HTR|WtN+~K^AmjX)>Iu&= zBUhDFT#VUT8A?2L1R*b_)yKohDs7;FmBx_bjuXx?lklUI^J$)oQc{Wmaa@iQ%OSU% zB}9TqQi$o;YHt*~$4l5wAGf=EYYqboYc{g;yTV#Ic121ZCFpkJ z5m2=c8bg;YMvU51pZsFFd1?KbRxbw$b08}%DSX~A$XGrnQ^=o;bvY`)>F22B{ULrN z(PeP=x12LkrWD+J{dSAK>S+#gy%TFTs%tL}Wj3rB^-aK)OpK;n<>qSNeL*AzV|JYy zs(N}fCsj)TeL{719X`qiJ9>1!#wnjyrc;yVS)&k!iY8>ex0ryCsU3XMvMJwSN!t+g zT$xgq?8<|o>WufFolt!sVd{j}mnLiAV02ukURTeXLac++&pmVYe{P6#sU3%Np;zXv znDy`2dH#I0X`lcLY(Fiw$09214b9K4{SF3JGI9AoFP4W<3i80~pP$V7XodQM6iEE^ z8Wl&OK7CK$r4$lI6~O8sb@||D=k|QGGlMzm0R;8YS`oqydiOcU%jc!XQGtO~)2C8T zbMo}ZrgSRE&un$a+t<%Tx$^D@pKo8^pq5X5m_5PsJ%2xTltE$A_xb+-Tnthq0(yb> z{{H|yEm2?Vck=u`U!Pqq9|LSw9s6hHqBJU3+dU7F$4rCes)0nFUTk#FZ=YViz4S){ z-E2kztQ!v{8d6@A}7L!t*?BldadCh$6Blk@!d{;d|3_4GboeqUyi!8&v}DWS{M zoMXuR^Vn$C$nyaG_$NT6SslL-=jVf+R%{e3sH_mI0iQ3k?$T}PZHMy4ac~O30Ye1& zf#2;T^VdYD1E|O+p&h?wdUnvMQ6LNqjCbvf0gR74=zy$boMd3+V3YP^<^4KO7{QIG zcRg{_@9Bg1XoMW#^*HPE>FbXz0EK4*s08{B{{U&#eryqiDLK#T`u_mKNH<=$#x48s zV8YZv&JSapW2aN!rm|~Rg)Zc-Q>awtgYxIgW-BRK!$sE=dcNTQ03{s_rEWN{=C;y^ z>x|-!m8_H~@}!LO0CVN%r&DWc$)ndBW;>{Ap-@Dq5v8aOc>eUtd6eHbcht*nr9U;F zEaytGq>7qpA^^yWNcj4nlebOq=aSIFndcc^TTwZtr>>qDoyS#Ibyh2VwGeE#+ff(V z_}+?T&2Mcryo(Ob23)ynVcVXi6d|d#+LLMJOVi~itZHjYDoj}U?Xeb{ zN~OnCxzlCHbcD9jBQ)}kPH>z6P6n$C?yc(HSmd0fY6&CPpaR3OJ-s?y;Agq!X_g?T zr)C<#QU|5C2HRTO0lqlR#b>q8f2|G6xOUfts*N9LY|9eksoQdHCapViuXx^7iVVjo zwVIrnHJW?z=#+(2qe^Z(R#;NpX|Ut&lDrEJOt zMiaCVnuL%6y3MDWgd5vSE}n~J*l{j##2J=lnAO!wSkt7ExkVvL1k`i@Ep3*<{Y|dK zl1>>N;tn}^&2i|01CG<-xFey``#hc)!kKYOC&K73Gw}A)_3Zni!nyd5vn_d36BYW^ z%WJg>rAKyGzq-|C8-fE-m_n5E?r=(lNRs~x#b(`)q`a-sE2S`%)9lvJ5{l?GNu zQeGuL5ClwWk*49w*rRh3nsxw<^bxkNFmJPK*n`u2H}Lf`W_j%$B<>+f+JKBe8*>e; zy+9`RTY>`-a7NhuJZ#IVJto?tMXA!)275H93@Q>HN|g;Q#cdt}i0D+DV2;BW)2(C8 zhhIaZ!&2C3;;u)0l$8QA>w%4FEL!8Q%WgWKJnE6i zq)Nf{=>X~~0;-UIWC6Xc>D6>OUT2u)S@vd()e+>$46{ijfI1245}7n8wxZHVw+H}L z1&x3h>QokCzM#{Lpe0EOB`237%LH~kHFB9wnMZ5uC=NX`p58oIXe7GNY%8Jon;kzL zVHC;AFK3u^>&j1lo?fTr^3%(1$oGy`x-Bali%Q2uB#bB=j=9t5jvAHHe2@C9HX!!t z)O(L?S2@9`%UDW&x*o2KZWtS1bGo;q3t0QMCR&w~QD-Z0DkNno1YtkygZ64UpGv=U zVp{&sJ11?uX5sH%fl^jc{at)Abo;suDCTJs?4z+wTO zM@)-VUr)Uxuo9bF%`oKX>-Ljdy|*Wn#>4_~7ikROj$CqpIdkSb!5^O5rrdO3l&2%P z03L_ugWEGjk#5gN*4t&ORk2WP((WRTTI83D?9l+7=va7ZgbfNgxn9bpsuBZ&S;X_bGIt zzF?w^^*~Q?_V>}PhTL#Eg04iI6=0`09gcju>lY^C*6nN<00`gbY*flnwJl2}3hayy zR1?q@6Zy`O@LO3U1gHYFCnN!nKhN8*4z&1Nhv6(N6U*jtp2{P>lSoUvxC&vkr)S(duND7%m#&aFaH#(P;?hAU)2YE8 zzuTe7TVZ7jC1!D2d7`2vY>(P_+tbM+tY8K zyBAw}*skA~Evsi+9x$z57cBzQp{a&^Wv01x)}Y&TM-t9INR-v8u*!#SRGjK`yhd79 z*2wLRzr+2J7A+dY*~=c(+dFoQ*bg*mwpBFJ+>qpw2fR5tyAG{UdDUgdWLDjE)djCn z1@?L=mw4ylF{Lf18Ako>tBP$z28x)uBS=Czq<}nDQH+lG7}Te@uDR7vl7&ewy()BN zu=A^Qh|Z;4wHWdpLV7r_iS!JBu4c+}$`h(n#R+Ao&bVtXB=Td|Ik6kCA$JG%0P>&l zk+*)7`Z(pV&7D`~Bm*>3LlW(}DvohrPTq1B{qBlE#)jVCPH!*kZ!&|Xb34YKrw_{0F;!5y?ABy>cD^73UzQTn{OY7awkWAC?X_2>z= zYun&D<3FX2zMe2mp8jGt*>)rj_65iXa6lF#rrXjlxl-v+gKKg;*;5{$HvwS^eq)b2 z$XzES_)j$0N|II3l^o+&I+o=_n#u%VBS@=FZY)V;B(&u^ors8AhzjO!oxvs75zuAy zsN{9lwLrU`dRtQH)|r4Gbx3K)C$ZrdlBAq4!W4&{TY!uyl=EZ}oKkh>+_`Qp zmg>w_($yvs&qT8J6vEx;IiD>>LxoF72uj%m^BikIa)unh6G)cV*mT(U9gpxM*A(_= zk}UO3{IIU=t57!32o6IYwgjmFf(VV4*Bfl5Qt&}rf;{53gr{Y|mmTg?85G5MQJzZL zSN-rFN}L5aC{mC{PBiUWUenGW?mgF64g0%z)AnP1*rwYx8!krS)v2_tyx-a#eiU@m z?h6k7b=Kh9w{q(OrA?h~*OvwV0IVsG8hq)=Uxe2$>zjuCF{z1*AraXPcyLk=G4LZS zqr-5iApCB4WDfrT22@UU#cyeb-0ofHLEA0&r)|~6TG{(Ln{w@y;kpoMW~pz{ZyJTp z?cWC6x+O#|IY&xqb$IW`eq&6-TI#B0nF@Ulwu=LRvf~bM$YwFcUXm#qx;hSIOaV4# z1Ttyw&1*1i@fqT3I^G@On(XG9m{m4d(XogrJlNW0iNPuu#^{f)Rf?#Ii(N?uaJMB+ zqXJ9NmWQF#QrMXhsg13du%^STb28`|j`J$OSojo&L#a}d0oERFX5|K?CFS@JrWp~$R=HSmM&YT}=T7*sno+S@ztvNVOTA#FbC)hcsW zZd1||&l_yF6@|N2uvuCV-eRFs=<5mi=}ONqk>3se)b0nzRzEcl>ytyK%kzTTna6CDM%hF($j%FiX>+jDP0N7==Iet zDZo-37!L*YLwy18(~s6ABw<~Y2sj5i)LAtxn|_=6^u71ogVw{|2T&wa0B>!NLN~DK z+pzTX=yA5tXDMw0f(RU{3I`ZS8N!<*s)DoF5Odc9I&Uiqa*sJa2vc?t9$4qInG^Z65&J8#$G zq=b-rk4N8NRGaiWYF>wbRNAp92yIQPm=&$Cqu{AWnMi#KN$8+QPF6$;*<(yBGu^=_i1w@#tZXt3l}D|MO9ElCN95|&#dN&32!fflE3Y$% zw4P>TF#?eHD&Csdj5^6GS2tYs81g<{GtgsJ7Yb#rsB=n%v&^Al1a2d^CQttWQ*A%s z0f8b+bBBu@OC3c-d^1HZsHk6ETPe6{z_LSr{DmaQH~QAlKzMhg;?F_`I%7Tke{QHK zk`7Oi1F-6K?5`kHpMsw!`I)B8X4ZBzHonMU&p?PPy`(Lb?NfZ ztL#4Cze=i*Hy->O1FQ@a>D%!d6~cOCU=K2SW2ehREm#Mr#(xZV&(A0JXeSOq?t1jk zTy^u&@G(ikdY*@;PTjxZpw>n)=6|nM)_k+}{_PB+bAyBC56eoZumk7+05}+=p`3g< z`|+i(Dp3T0dueF+J=dY?J;MnE5rd45-=DWtLBR+9IMC@hIsA209QE?;^Uw8Y5Dwk2 zbFi@3_WP}Zka5&?AJLQhG(b@Y13AZB4CC$4sUw#-?c93fuB)M8KwuH+_aEubkRyHj z;W7`}wYq;S9N9gI&rjRaMWAy8-)pvQS4c z7#*{KdY|gfs-fhp;{`u6&}xE#IV21#_6%qGHT5AW9H}R$$S0}uKAP8YZq~rTMN3dA z3n)nPPwOmo#tx2(RKZHnwWZKfq^vBZ*3^Xsw&QD0R5+CYQb%lhbk(>ObRY~Q5U*T$ zWAHjD3sS(wGMoXPpO4Q;kO&~|4h6^{gJK9E`^Mw<9Beg>zSV1NhAXtTtIT{U6C*r` zRT7ba3(c<$x}ZGLq?H_;4Q!3I#WvhVQpG}-bi;W_%97nNxozbj^h=FPJl)4%U319< zqiZ|xI9^&f428G^%}_cGl%Ll7za5 zl&00m+w`+$;1WmrsskOg#PJ2kR_JfV0s9Ct-IKPDIMdVZIy|RjO1Yej;$Di?*H=?* z`{g~iklUW(!)T1-jiGOs`BIUh1C)YX1;7*(l;@N;)Z+vWx;>&+u#(|WIOM`{$=jjN z>vTBNbuR^Q^%Ycg$wkkqgoa0z+D!}yA(ctxhEguAqf(KnNFW?F@ehi;VZ?OvQq@$$ zMNLo&$h5F5Mb!0EBN-+N+lEzioa2MK$6SsgemQ zP**aB08dZAcF>M2G=fyGi8%O@F^@ocb?K^+-cdqAN%*o!S5i-G4E7y0Bt14AK1M5E zwSTE70sypdV{!IS>P^@F1<|ptv#&~DlIlCFemdEb&6^350 zH$Kv@y0sh+aF17xijq`u*;LnMC;tGYr*+zFYRx{eL|Ot}olkhBNA*O8QdZjYQny!M54t0{ayRx6qQnC z`GqZHTS)|w%Dq0+Y_2~LG5WOA?#T5eL#xxA55lfNfmx?51QfjrtreM()`fYXvhsTQ z=f1S>*;%~us2pW+-@`RZr4{(`Zpb^AX)u&F)RtpaLK&+@TGNF{2zkbp*Ciu8f!2y} z@$C||_V?LU!^aml-ML)6S8l4_*qfe*MscWBN`=)zn(elU(d5(uTK7>B40o2YtSBg@ zB&=gxOyR@YD{ySTv_$cvSBW*+4b^#74f}0Hbx%9|UEI<=)>S!_j0v-;@C;X482ux# z&nH!k)n3V8Sy@psL|El1EKOl@(}^K6MuPjXjTj4l(t>>0>Rk7WvTh!ShgKT!tDMwD zHAG+%Mp--#5?L-Sp=M~N02247YXAoS0Hy^hXE{Mqxj-O=_riuc9R0tyPrauof`t!= zf)6myT=eQbf4^GSw$*wq`D|J@#ji0{3tsr3({5XGdy(YBT&hh{GjgLT=rdYv=&pv` z0HwqwLmjoX7Ofz#+7_$;I*<=ABcbRs)3%kR%mC8*wqOW1*n?{k>Ikt1(BBOFYV^@X zEKlWdSxTOugQb*?p@RYl>Ifj%i(^#1rd&y0TqN*EzC1{6{i=(;^V<7S%C!cV_dmJC zmo@fjh^$ls2QuJ8RJ6!-BLt<40-odYd)y7dytiidyEjJv0ItfpuYJL|YIk+nUz*`u znx$&9AyTEtJ%2{ZN`e|d_*-qXAs{6qU$AEpTR~6a17J6sWNJxh!`&UUyey)p!V59v z*JzU=L6WebM=MhtVb76kI{bcbt+%diW#4k`&B*f(SFCG>w`f)s6~wl=2XBAF>{ zK8}wvwZ|$-hx+*P)6EMP&1b2oxss}$E>oXGW?FwgD zjZf(6Im}WJ285nfGEl`n>|loJbDj3BZ8#!E5pd> zRgje)zGtB8qlyYql%YKVInTra?d8`xvq?#00U)VuuL^91bwNEqBh$X5AxBQQiUthb zY=6`FW6RAFypoip9-VS>G1Pi_>*MV$)B*=or?@%h`~Lve(rLu!;mJr&a7UrR@A>PZ zqc-E`3FT%u8CHHJ5;~5ani@dgrLmLKb8tHR{NEPUMs=2wu*p$a<|iYV0sTF5pZI8~ zl91=<%KrdWI4I=+9-U5n^>R}MK}ZYAdX9qx9>n#~DTv%RIf782tmR4tM;JN4J-q(_ z4Q9ix3Jv!4+vn%=!b@sGii^s5K1nAjK=k?R!>^?s5Tt?E1F#D8?eaPe_f{05((%pP z3CB!!IsE+eIeE7h5~6YlE+nU>dLD#&lb``Tdf?h^useMG^ub9!D*4i&pau#$1oL(6 z*RH9`bdZ#z2_q@!a7iN?^x~D_EHv6v$}$FUNdu-7Ji2PgCO8(K87V4Ch~*-W6I?)WQkNlxJqjl}nQy;^)T4hNZMtu2cFjQjyGc z42C2iI$4n0jYO0jVb>XOhkPjwmL3h1oVLFW#o&&h;E!ENYQf$Kd)>pH)ovwJ1>CW% zkz?Je30hM1(_tZtLb~f}aVZj6kliMiP;Jhs@v2V)g{4H*ejw$A^9+MEQRIlt1D&s_ z)g+7GYey*b1&2~?j*|K}<}t^f=Gk1$rKXN5n8$CcV+^hFywvOe0Cn%>vDXSMbklb$ zaOtWgw&qN?E3ptTLygpE%coRS(pCD%_qr!4hfJw|5y=^TDYfM#UiO0Hi&J8rhSId4 zhKq!$2;}NHojk;MA)q<~tv1|hqUgJmK&>Ev-Ey5)wq>XSaO`4kI!7u1$Wok(RcxpX zB`*$R*IDf<@p>v*d6jsNMDXNCL&0Gxa1{7xQj!i)l_V=Yf|bfoO*Wch$xkp{ofp^j zK#czKxAy~a*4XN~YgJmlnaF2`NeH>M#Es7Ydf8u1$EG$CpIN}Y9TQbFe{DkPqy9A~zeTeEQ%%TgbZangp94#y5K_R}zQ34JsCZ7b+uSLdX~+If>Aup&rV3DaE(3lVCT(byD@=`lAbmeZ`)s4$ijN zrc0^pU2?vh_>H}6#9F59sd>b;`f4bXPaZLJQQJ;+8Xh6|THlTq?loHb>$eq4O{tRP zLZV#g4Oe#h@9-A!OP0OqP79~j3YlZZ5zCFtZMC6KMQD&UK04AHj_dCghZzi@PHZ58 z0u+|ooY!nTl&vXP2P#1r9LX8MuFHCZblcU7Zt=G0H?5&?MpP@R&$_8p>ixHI)0k~x zE>vjsRveD)Mmq)K#DIjzLKe1~eUebL$+F%is;AQ(NA}28-)P!J9RXLdy}IdO)*e+T z0640+kHeggJQ7qz7wDY9_Y%UOM(wxvu-#OWPuo))ZXL^#Z4Dk5J)<0C@Y^PpYwfn= zNxkfpI+ohnJ=jB+-H4`;(i!k62B|GI3pGMIIZ(Px_+h?cpxTb4ZL*%$?WeCnp?@iD zwZHgEu2s~;NcW9)pH{uNcDN=u^TtF}zBzcI_Id7gYlki>HuluseYQf^Ox)d-zJ;4}zfrcOs#Gabt((S@)Yvkg@SAza z@#`#1Va`y8n2fTQT6wCHEZz|=PfZnNT9DF2(i&Qg7aE-yB(X^1;N8JOJf>tPYUXLU z_ko@itdM3IIADTF3r!8INL6wK(6B%5+{OS5!CKqRYi~Ce-nngRP0MLq)ElbNtheLQ zE_+(DPq{6++b^IjH%_lm=06$Nf)o_vNOZi;KzXzijc2b{%!ZVOFPM~kDq4q8$^cI) zjyZtopY}i}IXa3j5F1B$a9?86J)~aC4bQIGd@}AGyJl`i+Q=UZ)Ba`$6w?5)C) zY_U^KS}nZ&+e3?2dXo;M^S&(jEx9FPJC9}Z!kZEgya!2-*2E*HimC~@)YCI1nRH7W zfGIIc9nF|us+Lo++Ut8OhI7@=+DN^P>8h#KU6kF?k&cyk+$g=su>>g_00_Cp*KL&+ zCEIXIr%9z;6~A`3ZW_ZBYgOb#u2iK`Y0k=GELU8j)G(zjw5h}+)!ziaL-=R==zQ|>CfHQYPPF3H+`&Z*lr zl4GW1q}Y<`662u)odT!K4n94qd&k3u_3sxAyJ=>^wxv_{?yG53w^23ps`ZIi+-ohj z>2JdGQ+Hm zQ!AEJCoe*kx;(d1jc(!aC&b;GQNQQjjak(u}TuU73_y3?Oo zV(f9s_Vr7?YSEZ(+GIU&R3y|KTM!o9X{w8VpX~D9x=kAIrdQ~2>DSe_b6RS4yf+(a zT-lmEfb9c`$9D>`a^Fqei%T_nHQ&QE{Yh{~@nW?$$gES{adY3JGdbpy#|5{$w#O8U zymsl!VxLsHw{wYGA~YNBRI0o^?A%@;EX%8GDD6vYZeNX9piq%tx=mq;%~Kh!)1tg% zR4A1+K#wk+OWIRqO}c3lqUI!oZ6ed+4x0k)6RpeFjZMe8t=ac|V`8ch zsR#0zf*=!gY-_P?zE7>)V{<9XOkQCn5%O(`;`YD&7tG{k73m%yQwR3J$mD^#f#>Cw&3AYXve&4ZT*-)6bZHW=M zC$`v?N%yI9UY&l_Ca%1yZ9b7gh-48JT}R9>)8pLRb8o}pYyoQv{QU2RYCp5bbA_9I z*Q>jSvv%#pYHpUvZOsbbnYs2f`W5*PdaOOyy{Q*ft$WgLSK?Knq207aG9wV0ne~N6 zWmYGT5@o+KE3G|)!Cw0Aj`40b$XSrAY4?`bUO&bC(KdeOSeE^q_2%{Nox7!5cFpH- zSEAFe8r4eb53@;&OMYC6voNGfr?)06E;^m8YuZO@ySU9=mj=piCB<&huN{WItoA4I z4F&znpj|vZZHE$e)r)XR+zO7!Nu^Y(v3Ea+2p2p?+O*-)*^jpIC~~QF15le*3AT-nQ?b8Sbr8)|o6$hX?v*j8Q5Zr)oZxQ6-L_byw+ZCzG1<3}-NRH4=5 zvqhvkJ=qORizb?uRT1@V71UnB=KXqh?fgG>Gv(Xo`C-buJ)4`ycJFn$x0@|*+c2q@ z{iU_{9gxNU0J>I1nz^yBr#8QC=`|^pE84vYxNO(=zWJL)pfc*x{XzOQO~|Y&pGuc4 zrsIYl9d>_s_PW0=^gEQsV%EDYdR38a+>eO1?`@;y{dL^@vpc0vASF`)h~+Gg+tgIaZ0tfx(?q| zu6i#Ecdp9cI~@+Cf7X&#P?I@eI}^7T zCAl|iD%YL%#q^EJ+MB(-#D{L$_EqTK+upl%8l!kvj&0>eM&U(>i@;SOM~_~hAvFpl zbj>vgD}Eb?0xe2!osK>-_PbFJtrn0E}(r(ZD^6L;f}mH-;WK?w{iKhP|cT zn^;os8ajWCI)>mKxc(7tg|+VdB}(Mk$|vx?rSB1A{baw;G2`74xm@veE{C$aBT*b5 z)gQOFx~m_0tewnV@n+iBotHZ4ymvOtxNlop&Y}6JCAp!G6=W> z=YNN$F-|IWqKmPdMDF&`P(OrCQ?~Z=UGG7eb=!3)DP&fx+m@+IroxF{uTd*1 zpGcQeg$f)hoQflr2vH)%lG6>XSh#`RlfGNQdhUWK3bmqKlIg6{ZRcw*T$3pD3wDP~ ywe8q7OO8Y+s<>-Np;2kx{X9g5iIWTRT7?a_Q5B`E6*oFY-MVzaw5i|MAOG2PSm-YR literal 0 HcmV?d00001 diff --git a/release/freedesktop/icons/16x16/blender.png b/release/freedesktop/icons/16x16/blender.png new file mode 100644 index 0000000000000000000000000000000000000000..238d67321a77f54a43a8f11671cd89720040c6e3 GIT binary patch literal 746 zcmVwkh|;1dluV)^f^PZ)y67q) z@-h^|>c$i{P@y0%B0^mfG zlreS^ys;ttbam#>oWtInKX|IXj5nEICwt1z{j)&VROq?y*}&3G*~N`Dz9*=v>s^cswE~H<`V-e;7zfbXKRTfL9*MWg__!V5FUi%0K$W6 zDtMzA00RgQR@g#eyPz&41^~icjy%u5*%8d&bq^MZxlP?xjNZ_R4NqmbL~#1R1?$22 zs==rRCZ?gjdjv@omF3B}kr*wJogD;w#cP_zqM%gw1ds3I2*3p!5MQ*TwtEmQ4@VK7 zGr-vN7#3y8QtJ0_vhA%0JA!1)+sq1be`QN2;Vn)M(mF`lG4zcj0RWk-jJ}a1n8gd` z^26WGvP_{&H-^RfVHULn_%q@o!YHT;pjlH7K z>HWMSM;xBgh~Mw7Vn4nD(Fs^9&wy$gs!Rv$l8a^2#SIKrDDE0sjw=_07w3zyGa5e#^2 zCdPy5P$`GZYW8PtIYqu?^p5BlM#vHZ+LDM^oJoYmNN*P2+Bk?Dn=)K`I cviL9f1u^LfjggmX%m4rY07*qoM6N<$f}-+L`~Uy| literal 0 HcmV?d00001 diff --git a/release/freedesktop/icons/16x16/blender.xcf.bz2 b/release/freedesktop/icons/16x16/blender.xcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..67cb725ea798c9c017a0bdb6b2c865939d4cf06b GIT binary patch literal 1405 zcmV-@1%moQT4*^jL0KkKSugssV*mo*|NsC0|LRNk|LIx3UXTC(|M#fZ`-m<2nq&%b zmHqzz|Nqbg4*(MEWCKB}dJr`|CTNMZCz_cA1lcE)WPYM)p`+COP!CP1l=Oqp(gq08 zwLM3sMx!!MQ)+rgq%=05Jf>-*)fpa|6Ura}Xa-D!L8eSYAO;`|hMF)CGz|kl05Jwl zG-T1HhC?Pp2nLN~)xpg{=)h($FD^ zn?iz2l=CS_9&3_$C?>ZHA?Y&78`V_Qym z6!!KPbFVwIPGgfjn@%JYF-7M z%`+xU%*P~cjM-q{9Bvhj{eK(%O=W`!buIu1(Oib*DjpC3u zmCZYYeAVRJ419K)z-`>#mciddwuwvWGdyDQQE*p|ch+Xq3oCZVINT|hIRm3Eu zetm|W&a)qmsHU0yP61mk(4M`sZ_v{|E$q!$T$X#hnRiTUSQwThsKauUMzAc>uPqw| zBQU#+PK22gNj2;(YYkIuEE0UiQ4-`_1Go|>WZD2{#cbZETS6gb*s*A%>l?a(UVr7Q zTA%LHe)sVGr)g=Mi>Um}@y`(k^f2zPZ(8`oV>Rs(lC=}$_q##+po+eCp+?Z-N7cc8 zc7MBwn0eBIhOM@-s|`~fq*l~ z9&7A0Yi!jiWPx`Wc%9rrb7&VRDw59&a<0JjW!=;oRWe;BO37M!SGW>12INTgc!m@ zZF~{IL`@$Q5`BXRNm}={Ge@*G~SVCsa~j{bA3+e+|C$_8eXO@FoHQ6E&J~ zI(KgBHj7Kw-3~7A1U%f?@lNLOR*cl|_%f}=>=)mkkx%wEo?OGDw~e@EHT52^x7I8w zE|<~-ArT0W5|BXvEd;^IWkjkT(xxGWh%TUQ`>QEElG%J;BOl!wyo&x<-QFnZzb8^q zEP3S=T5FV(*V6O}O6St?>FW+!JXYP1ICv{?Yt38x=IQgF3xq@%elY!D_z|YhrTRch zwAP>2AV%ieUZFwrCZ1wcQU3`CYDc1V@fqErmg^(u7ab$2}xjl332VUn|J4PT3 z*%V?@4WeW!Ake7+f&a#P?1~GIVr)39D&rv7}bK#qBgQPa@fV*V4n*RUWwxg zapZJ2oqcIC**wWqj+dX9M_ElR>dyn{p(G{I36+_l>^9($aqyX!LazZ0RT~@8iQ`D& z1A7D=EJp<<5x9|+{!rb#4Z98J!dJBK{W?!BQwL1SUF~{4P%&j9@gGq8H()P$mp4|-;n~F%Shi+X zc?i=0&h5d7A43#H8R$#eKmtG(MWWK_KS#&DrnDH%EStZR_Xe~4(ev{mTU()Y`gZC9?CeNhDRme?oLWskP?XD4y=V_tfGi+( zFXQ8yS5p+HPfY>V#6_x%)pE=oJMsY!pa8 z5Ndp!@2aLxn0xo)r6#?n(bq47R_em zfF;~018$qx1@I|A7^qqq^H(pO>01zCs3PJgECuAX$Y(_`{ZpT@f6LKSGZ1&dSApDE z#2&!sIuS0|>pBbq)7-4ao;?T1yD|r4T;Mfe6mUerV>EV1ySvbd&y^J1g>da`z;Yef hV+`>h{ge7;#a~-B(>hfpJ;?w7002ovPDHLkV1hH1Ff;%F literal 0 HcmV?d00001 diff --git a/release/freedesktop/icons/22x22/blender.xcf.bz2 b/release/freedesktop/icons/22x22/blender.xcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..fb4396252abfc741b470003812f207b12912893f GIT binary patch literal 1792 zcmV+b2mkm&T4*^jL0KkKS=U2D;Q#{~fB*mg|NsAQ_y7O>Tl@d_-~GP-@Bjb*7w8>- z#d&}C|Nqbg?++JRw_UV0#TB?3f=w|o0GNTK%}qTc0GfJ&VU&4K2++|pO;1zGc~4CP zK*DJ-9-%Qb^#`C$GB9WpAYmS+)6!_j#1Bx@YH6wZpw!X<6EqXh1dk?DG@3NpMxLY8 z9-z^okO85f8UgA6WN6bs000Jn0000000004000J!000J!GypPa00E$A0MIf30Aw^Y z0j7X7&;Z2HWB_Oy00E(sAVl3001%o000000000D0000027y^c zt(~o)uUZOyBC=I*0D4kVU)gH0ZWIZu<~89zbVwEpkfxI;G9nTS5X(kr#4$`#$ay#f znNe}TMNt2Y>>$D#Bn<%l3tMvI~+f!iWwaB%ONd1$4NfS!EYcfGiYovGnW+ zF7{RgcBm)g34CoU_tVZf_(IwiX{TANbD0Au(~hn{j)nRF0|)>CP#`+h6h~QXqfIo! z1)62nBn~3#Qjt#$b=0KNnz)sYd{9V69Rt4v%F{C*RZ=ADQWX?WdQfG%1kv7zC7q7NY8X`i*+_x;F4|xUg`h4&LIlh#3gpbfl2S|P4q*e()+EVDP&H77ys}a4 z^!(A4-ky1DZwA}Nd5f_a?rMKrVAAm zl8!^EvoeALT*OIbfQwvE%?ikCW0r; zLn67vSzBBH!|=&d*Ik~{vLLpjO9onfcdZ7B#+pH3wlEWKsbm5s%%#2tOP-f_oY31Y6qe=VFvflJ z`=hWjs1&`76VoHJL|KcG@=}7z0~WM>;3?1ZhMD&Osyy=M|(dwuEHVNR3XkC{RQ@C4GL1g|%s?z(DGa1l=9xR{rti^CC!r zqcLA1Ay^O@AVDuzCPkPq`8tIs+HV|hslsxCmr`~l_pV7+EP@kr=)ogqY@L#Fon@n? zv{9N$*m|cl(U~*pK+w)=X{MdL)gqdi#OYGgJQ+KZI5V$RY&vauzYttqZS3kRBRBX$JVIxxpBOr(x+ybU~8R;|1^ zB)}-aP+25y3B(&4e1|RQaR2P2A5&!|U~oB~C5 zIO#hhfQ+-#iVCC>sJ48Vih9IIiU4HaCXJ6-E)O)p|Qk%Kjr>MQY zsGof`m;%ffnxr7Be)g93^cbygq#8GO1|sWuTZX;-0x zfrTMzcJ6|hjch!D1#+IeGvZN1O{o86b3UH>l9d(CA#53W-4j|`v0S1nhxuMA^Z5acM!PBe#7P#D680ZMf>5a3z3WD@bB2t?Fn zk`e*{A_TxsGhFhNZ#59opwbVV;-OI~*(g|*Ql#J;rMPW2Si|Q>#wC3H`&sbUD8p!$ iQ>lHnhEK+I$Cmpa4$9EeA%xP8_`8xR!i0vp8XpLd_#qDf literal 0 HcmV?d00001 diff --git a/release/freedesktop/icons/32x32/blender.png b/release/freedesktop/icons/32x32/blender.png new file mode 100644 index 0000000000000000000000000000000000000000..4c9acf10d639a5a7110d8a40478a6176a031c186 GIT binary patch literal 1929 zcmV;42X^?0P)cq-#CpL)HYR`fWV|8kESGqtX&ckz!+@& zwz0k5-Py-HZa?gjxC*$CsI79PqnXjwod55hd*+-wqP6D#In>8>5Q|Fj$9Z2qY6N0Y zi6|kaMKufFfakHVtwSHWSw9~q0(-($)eXz<+UlF%x~|y_MGkiDmd9gJG5%KoM^e*q z(iw-)ye3*UZ4DRK&3{lSUW-L#-i$Xfsqi^|emYXxxJZF!s_(o#a{7&g z=Xqaf>(HQE5?%A85@^ zG`<^w&>(;juBxNy_U#x&A-t@`!0Vk>YV^`8p2x1X4jsQCfPe0h;}y+|H&rZLY8d_i z7=BPbP<})ip!}eWyomxaK%_vTK`BHOXcz4|TzU5md+hXU6P~B3j~zEW?bH>-k&0Dn%7_=~RWy8k%gG$?I z+d`Ezpf>D7%rGK??YIn0B&n^45HJh%$jM+I|1sWh7lbOw#jkMT_;V?(scGxb)_=_M zSX92~^P30iHr^jDU9eo~)HoUqW*Am|4ebk(&g3|8W`y3M8LX@g8fwZzY-w+#qPPfI z`whG&+tI0U{Ppcbs%s@NHnIcw{dECiQ3)#H$zXNUuBJOaA2dxrIBBr0d_vZ?;e~6! zbvbsbpT5x~+S4R6HgBC9qknXULnnIq#Y3BsU^T4&7X0n|=)@4^^J+uZ#K^wu0>q-S zN(s+Zt-7POYWdoLWa4OlDWVkGa}Wf#qzPOX+x6%fh~sKa&%iWqU!1^pJOJM7pJH%4 z!MySys^PYLYNW;qwXDQLt%*gY_Co+&yJf#WRPt!!#(RrG#l@nNBk1BrrrtYA#jOT>e|1yns{Mg6q0?cJ`X$w>Fnk8uH;d z4!*%RKbSBhh?4;*QU&of%I7;<*S_`k#x)y4GVwMNs=`XUy7$m;Qn~4|pEw!ILu+tz z;O0;RC$KDwbUMx6?Mv8rOZC5ruWqT}p|7mKwrw28K`wOWCzJtZm~7fIfPP;rDn7$7 z4mNH0Oj#)4p@+MXruAIuJ!_A3y)@=&wg6++m67jgy7$P@_=VG-D7pv5J5HF#^~91vI4(q?a-bAy6x1IvZmuCa|XRH{?STYKKDz{MHf4YR9#t>wB5?j$jEOVoY!bP0mO#&6DLecCWyijWWb=(s zRW8AHgvq|1tfzSd3Y9Pxm3s`uW59&#@pxN@?gS8#01yO1K=6efJbX**>fQCrSD9|l zvHVut;E<9A)Z)+5_ww`U;gPZL-gS_lYOTHNmSPbx3&P>THPl=}#nbok+v@oXYa7>Z zH5uu`8#p<)vSDI0Z^A8I$iV9_W+sO&#kT#4FHdDj0?D}mf(7xb0AV0pY*O;Gt?XUV z5V>dJru)pIpouqi2|Y82o*4o+iv&s`T!n2^hq{vQ>k(wNLW(F_j5~G(B z2hOnni7vVe!WJ;2wNB634MoI13m{mqqJjk$l~J~HF|A80Shk>)TT4t?VEFt+j-5-* zqX6Lo9^e%29l+6AyVv#iiT^qM!~^^bt3o#zWULjs P00000NkvXXu0mjfF6y;L literal 0 HcmV?d00001 diff --git a/release/freedesktop/icons/32x32/blender.svg b/release/freedesktop/icons/32x32/blender.svg new file mode 100644 index 00000000000..241111c5c64 --- /dev/null +++ b/release/freedesktop/icons/32x32/blender.svg @@ -0,0 +1,238 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + + + + + + + + + + + + + + + + + + + + diff --git a/release/freedesktop/icons/scalable/blender.svg b/release/freedesktop/icons/scalable/blender.svg new file mode 100644 index 00000000000..bc1a3a970f6 --- /dev/null +++ b/release/freedesktop/icons/scalable/blender.svg @@ -0,0 +1,235 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + + + + + + + + + + + + + + + + + + + + diff --git a/release/irix-6.2-mips/extra/blender.icon b/release/irix-6.2-mips/extra/blender.icon new file mode 100644 index 0000000000000000000000000000000000000000..32b8bc3b94ad0db898b0d9c1eb86c9361fe669a0 GIT binary patch literal 638 zcmeIwy$%6U5QgD*N&K_pe|2h=R*OPMBsv9!N_Mr}g=-KJL5XN2EI^c5WJ>KJ)lzpz&mq%Rx=Yy& Q" $CFILE` +LIBC=`fgrep "#include +#include "plugin.h" + +/* ******************** GLOBAL VARIABLES ***************** */ + + +char name[24]= "Blur"; + +/* structure for buttons, + * butcode name default min max 0 + */ + +VarStruct varstr[]= { + LABEL, "Input: 1 strip", 0.0, 0.0, 0.0, "", + NUMSLI|FLO, "Blur", 0.5, 0.0, 10.0, "Maximum filtersize", + NUMSLI|FLO, "Gamma", 1.0, 0.4, 2.0, "Gamma correction", + TOG|INT, "Animated", 0.0, 0.0, 1.0, "For (Ipo) animated blur", + NUM|INT, "debug", 0.0, 0.0, 2.0, + "0:off 1: show primary blur buffer 2: show 2nd blur buffer", + +}; + +/* The cast struct is for input in the main doit function + Varstr and Cast must have the same variables in the same order */ + +typedef struct Cast { + int dummy; /* because of the 'label' button */ + float blur; + float gamma; + float use_ipo; + int show; +} Cast; + + +/* cfra: the current frame */ + +float cfra; + +void plugin_seq_doit(Cast *, float, float, int, int, ImBuf *, ImBuf *, ImBuf *, ImBuf *); + +/* ******************** Fixed functions ***************** */ + +int plugin_seq_getversion(void) +{ + return B_PLUGIN_VERSION; +} + +void plugin_but_changed(int but) +{ +} + +void plugin_init(void) +{ +} + +void plugin_getinfo(PluginInfo *info) +{ + info->name= name; + info->nvars= sizeof(varstr)/sizeof(VarStruct); + info->cfra= &cfra; + + info->varstr= varstr; + + info->init= plugin_init; + info->seq_doit= (SeqDoit) plugin_seq_doit; + info->callback= plugin_but_changed; +} + + +void blurbuf(struct ImBuf *ibuf, int nr, Cast *cast) +{ + /* nr = number of blurs */ + /* the ibuf->rect is replaced */ + struct ImBuf *tbuf, *ttbuf; + int i, x4; + + tbuf= dupImBuf(ibuf); + x4= ibuf->x/4; + + /* This doesn't seem to work... paprmh */ + if(cast->gamma != 1.0) gamwarp(tbuf, cast->gamma); + + /* reduce */ + for(i=0; ix<4 || tbuf->y<4) break; + } + + /* enlarge */ + for(i=0; ix > x4) { + scaleImBuf(tbuf, ibuf->x, ibuf->y); + break; + } + } + + /* this doesn't seem to work...paprmh*/ + if(cast->gamma != 1.0) gamwarp(tbuf, 1.0 / cast->gamma); + + if(ibuf->rect)memcpy(ibuf->rect, tbuf->rect, 4*ibuf->x*ibuf->y); + + if(ibuf->rect_float) + memcpy(ibuf->rect_float, tbuf->rect_float, 4*ibuf->x*ibuf->y*sizeof(float)); + + freeImBuf(tbuf); + +} + +void doblur(struct ImBuf *mbuf, float fac, Cast *cast) +{ + /* make two filtered images, like a mipmap structure + * fac is filtersize in pixels + */ + struct ImBuf *ibuf, *pbuf; + float ifac, pfac, infac; + int n, b1, b2; + char *irect, *prect, *mrect; + float *irectf, *prectf, *mrectf; + + /* wich buffers ? */ + + if(fac>7.0) fac= 7.0; + if(fac<=1.0) return; + + pfac= 2.0; + pbuf= dupImBuf(mbuf); + n= 1; + while(pfac < fac) { + blurbuf(pbuf, n, cast); + blurbuf(pbuf, n, cast); + + n++; + pfac+= 1.0; + } + + ifac= pfac; + pfac-= 1.0; + + ibuf= dupImBuf(pbuf); + blurbuf(ibuf, n, cast); + blurbuf(ibuf, n, cast); + + fac= (fac-pfac)/(ifac-pfac); + n= mbuf->x*mbuf->y; + + if(cast->show) fac=cast->show-1; + + if(mbuf->rect_float){ + if(fac>=1) { + memcpy(mbuf->rect_float, ibuf->rect_float, 4*n*sizeof(float)); + } + else if(fac<=0) { + memcpy(mbuf->rect_float, pbuf->rect_float, 4*n*sizeof(float)); + } + else { /* interpolate */ + infac= 1-fac; + + irectf= (float *)ibuf->rect_float; + prectf= (float *)pbuf->rect_float; + mrectf= (float *)mbuf->rect_float; + while(n--) { + mrectf[0]= irectf[0]*fac+ prectf[0]*infac; + mrectf[1]= irectf[1]*fac+ prectf[1]*infac; + mrectf[2]= irectf[2]*fac+ prectf[2]*infac; + mrectf[3]= irectf[3]*fac+ prectf[3]*infac; + mrectf+= 4; + irectf+= 4; + prectf+= 4; + } + } + } + else if(mbuf->rect){ + b1= (int)fac*255.0; + if(b1>255) b1= 255; + b2= 255-b1; + + if(b1==255) { + memcpy(mbuf->rect, ibuf->rect, 4*n); + } + else if(b1==0) { + memcpy(mbuf->rect, pbuf->rect, 4*n); + } + else { /* interpolate */ + irect= (char *)ibuf->rect; + prect= (char *)pbuf->rect; + mrect= (char *)mbuf->rect; + while(n--) { + mrect[0]= (irect[0]*b1+ prect[0]*b2)>>8; + mrect[1]= (irect[1]*b1+ prect[1]*b2)>>8; + mrect[2]= (irect[2]*b1+ prect[2]*b2)>>8; + mrect[3]= (irect[3]*b1+ prect[3]*b2)>>8; + mrect+= 4; + irect+= 4; + prect+= 4; + } + } + } + + freeImBuf(ibuf); + freeImBuf(pbuf); +} + + +void plugin_seq_doit(Cast *cast, float facf0, float facf1, int x, int y, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *out, ImBuf *use) +{ + float bfacf0, bfacf1; + + if(cast->use_ipo==0) { + bfacf0= bfacf1= cast->blur+1.0; + } + else { + bfacf0 = (facf0 * 6.0) + 1.0; + bfacf1 = (facf1 * 6.0) + 1.0; + } + + if(out->rect) memcpy(out->rect, ibuf1->rect, 4*out->x*out->y); + if(out->rect_float) memcpy(out->rect_float, ibuf1->rect_float, 4*out->x*out->y*sizeof(float)); + +/****************I can't get this field code to work... works ok without...paprmh****************/ + + + /* it blurs interlaced, only tested with even fields */ + +/* de_interlace(out);*/ + /* otherwise scaling goes wrong */ +/* out->flags &= ~IB_fields;*/ + + doblur(out, bfacf0, cast); /*fieldA*/ + +/* if(out->rect)out->rect += out->x * out->y; + if(out->rect_float)out->rect_float += out->x * out->y; + + doblur(out, bfacf1, cast);*/ /*fieldB*/ + +/* if(out->rect)out->rect -= out->x * out->y; + if(out->rect_float)out->rect_float -= out->x * out->y; + out->flags |= IB_fields; + + interlace(out);*/ + +} + diff --git a/release/plugins/sequence/color-correction-hsv.c b/release/plugins/sequence/color-correction-hsv.c new file mode 100644 index 00000000000..ec8478706f1 --- /dev/null +++ b/release/plugins/sequence/color-correction-hsv.c @@ -0,0 +1,291 @@ +/* + * Color Correction Plugin (YUV Version) 0.01 + * + * Copyright (c) 2005 Peter Schlaile + * + * 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. + * + */ + +#include "math.h" +#include "plugin.h" +#include + +char name[]= "Color Correction"; + +VarStruct varstr[]= { + { NUMSLI|FLO, "St Y:", 0.0, -1.0, 1.0, "Setup Y"}, + { NUMSLI|FLO, "Gn Y:", 1.0, 0.0, 10.0,"Gain Y"}, + { NUMSLI|FLO, "Ga Y:", 1.0, 0.0, 10.0, "Gamma Y"}, + + { NUMSLI|FLO, "Lo S:", 1.0, 0.0, 10.0,"Saturation Shadows"}, + { NUMSLI|FLO, "Md S:", 1.0, 0.0, 10.0,"Saturation Midtones"}, + { NUMSLI|FLO, "Hi S:", 1.0, 0.0, 10.0,"Saturation Highlights"}, + + { NUMSLI|FLO, "MA S:", 1.0, 0.0, 10.0,"Master Saturation"}, + + { NUMSLI|FLO, "Lo T:", 0.25, 0.0, 1.0, + "Saturation Shadow Thres"}, + { NUMSLI|FLO, "Hi T:", 0.75, 0.0, 1.0, + "Saturation Highlights Thres"}, + { TOG|INT, "Debug", 0.0, 0.0, 1.0, + "Show curves as overlay."}, +}; + +typedef struct Cast { + float setup_y; + float gain_y; + float gamma_y; + float sat_shadows; + float sat_midtones; + float sat_highlights; + + float master_sat; + float lo_thres; + float hi_thres; + int debug; +} Cast; + +float cfra; + +void plugin_seq_doit(Cast *, float, float, int, int, ImBuf *, ImBuf *, ImBuf *, ImBuf *); + +int plugin_seq_getversion(void) { return B_PLUGIN_VERSION;} +void plugin_but_changed(int but) {} +void plugin_init() {} + +void plugin_getinfo(PluginInfo *info) { + info->name= name; + info->nvars= sizeof(varstr)/sizeof(VarStruct); + info->cfra= &cfra; + + info->varstr= varstr; + + info->init= plugin_init; + info->seq_doit= (SeqDoit) plugin_seq_doit; + info->callback= plugin_but_changed; +} + +static void hsv_to_rgb (double h, double s, double v, + double *r, double *g, double *b) +{ + int i; + double f, w, q, t; + + if (s == 0.0) + s = 0.000001; + + if (h == -1.0) + { + *r = v; + *g = v; + *b = v; + } + else + { + if (h == 360.0) + h = 0.0; + h = h / 60.0; + i = (int) h; + f = h - i; + w = v * (1.0 - s); + q = v * (1.0 - (s * f)); + t = v * (1.0 - (s * (1.0 - f))); + + switch (i) + { + case 0: + *r = v; + *g = t; + *b = w; + break; + case 1: + *r = q; + *g = v; + *b = w; + break; + case 2: + *r = w; + *g = v; + *b = t; + break; + case 3: + *r = w; + *g = q; + *b = v; + break; + case 4: + *r = t; + *g = w; + *b = v; + break; + case 5: + *r = v; + *g = w; + *b = q; + break; + } + } +} + +static void rgb_to_hsv (double r, double g, double b, + double *h, double *s, double *v) +{ + double max, min, delta; + + max = r; + if (g > max) + max = g; + if (b > max) + max = b; + + min = r; + if (g < min) + min = g; + if (b < min) + min = b; + + *v = max; + + if (max != 0.0) + *s = (max - min) / max; + else + *s = 0.0; + + if (*s == 0.0) + *h = -1.0; + else + { + delta = max - min; + + if (r == max) + *h = (g - b) / delta; + else if (g == max) + *h = 2.0 + (b - r) / delta; + else if (b == max) + *h = 4.0 + (r - g) / delta; + + *h = *h * 60.0; + + if (*h < 0.0) + *h = *h + 360; + } +} + +void plugin_seq_doit(Cast *cast, float facf0, float facf1, int width, + int height, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *out, ImBuf *use) { + char *dest, *src1; + int x, y, c; + double gamma_table[256]; + double uv_table[256]; + float *destf = out->rect_float; + float *src1f = ibuf1->rect_float; + + if (!ibuf1) return; + + dest= (char *) out->rect; + src1= (char *) ibuf1->rect; + + for (y = 0; y < 256; y++) { + float v = 1.0 * y / 255; + v += cast->setup_y; + v *= cast->gain_y; + v = pow(v, cast->gamma_y); + if ( v > 1.0) { + v = 1.0; + } else if (v < 0.0) { + v = 0.0; + } + gamma_table[y] = v * 255; + } + + for (y = 0; y < 256; y++) { + float v = 1.0; + v *= cast->master_sat; + if (y < cast->lo_thres * 255) { + v *= cast->sat_shadows; + } else if (y > cast->hi_thres * 255) { + v *= cast->sat_highlights; + } else { + v *= cast->sat_midtones; + } + uv_table[y] = v; + } + + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + double h,s,v,r,g,b; + double fac; + + if (ibuf1->rect_float) rgb_to_hsv(src1f[0], src1f[1], + src1f[2],&h,&s,&v); + else rgb_to_hsv((double) src1[0]/255.0, + (double) src1[1]/255.0, + (double) src1[2]/255.0, + &h, &s, &v); + v = gamma_table[(int) (v * 255.0)] / 255.0; + + fac = uv_table[(int) (255.0 * v)]; + + s *= fac; + if (s >= 1.0) { + s = 1.0; + } + hsv_to_rgb(h,s,v, &r, &g, &b); + + if (out->rect_float) { + destf[0] = r; + destf[1] = g; + destf[2] = b; + destf = destf + 4; + src1f +=4; + } else { + dest[0] = r*255.0; + dest[1] = g*255.0; + dest[2] = b*255.0; + dest += 4; + } + + src1 += 4; + } + } + + if (cast->debug) { + dest= (char *) out->rect; + for (c = 0; c < 10; c++) { + x = 0; + for (y = 0; y < 256; y++) { + char val = gamma_table[y]; + while (x < y * width / 255) { + *dest++ = val; + *dest++ = val; + *dest++ = val; + dest++; + x++; + } + } + } + for (c = 0; c < 10; c++) { + x = 0; + for (y = 0; y < 256; y++) { + char val = uv_table[y] * 255.0/10.0; + while (x < y * width / 255) { + *dest++ = val; + *dest++ = val; + *dest++ = val; + dest++; + x++; + } + } + } + } +} diff --git a/release/plugins/sequence/color-correction-yuv.c b/release/plugins/sequence/color-correction-yuv.c new file mode 100644 index 00000000000..54290ba37a2 --- /dev/null +++ b/release/plugins/sequence/color-correction-yuv.c @@ -0,0 +1,235 @@ +/* + * Color Correction Plugin (YUV Version) 0.01 + * + * Copyright (c) 2005 Peter Schlaile + * + * 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. + * + */ + +#include "math.h" +#include "plugin.h" +#include + +char name[]= "Color Correction"; + +VarStruct varstr[]= { + { NUMSLI|FLO, "St Y:", 0.0, -1.0, 1.0, "Setup Y"}, + { NUMSLI|FLO, "Gn Y:", 1.0, 0.0, 10.0,"Gain Y"}, + { NUMSLI|FLO, "Ga Y:", 1.0, 0.0, 10.0, "Gamma Y"}, + + { NUMSLI|FLO, "Lo S:", 1.0, 0.0, 10.0,"Saturation Shadows"}, + { NUMSLI|FLO, "Md S:", 1.0, 0.0, 10.0,"Saturation Midtones"}, + { NUMSLI|FLO, "Hi S:", 1.0, 0.0, 10.0,"Saturation Highlights"}, + + { NUMSLI|FLO, "MA S:", 1.0, 0.0, 10.0,"Master Saturation"}, + { NUMSLI|FLO, "Lo T:", 0.25, 0.0, 1.0, + "Saturation Shadow Thres"}, + { NUMSLI|FLO, "Hi T:", 0.75, 0.0, 1.0, + "Saturation Highlights Thres"}, + { TOG|INT, "Debug", 0.0, 0.0, 1.0, + "Show curves as overlay."}, +}; + +typedef struct Cast { + float setup_y; + float gain_y; + float gamma_y; + + float sat_shadows; + float sat_midtones; + float sat_highlights; + + float master_sat; + float lo_thres; + float hi_thres; + int debug; +} Cast; + +float cfra; + +void plugin_seq_doit(Cast *, float, float, int, int, ImBuf *, ImBuf *, ImBuf *, ImBuf *); + +int plugin_seq_getversion(void) { return B_PLUGIN_VERSION;} +void plugin_but_changed(int but) {} +void plugin_init() {} + +void plugin_getinfo(PluginInfo *info) { + info->name= name; + info->nvars= sizeof(varstr)/sizeof(VarStruct); + info->cfra= &cfra; + + info->varstr= varstr; + + info->init= plugin_init; + info->seq_doit= (SeqDoit) plugin_seq_doit; + info->callback= plugin_but_changed; +} + +static void rgb_to_yuv(float rgb[3], float yuv[3]) { + yuv[0]= 0.299*rgb[0] + 0.587*rgb[1] + 0.114*rgb[2]; + yuv[1]= 0.492*(rgb[2] - yuv[0]); + yuv[2]= 0.877*(rgb[0] - yuv[0]); + + /* Normalize */ + yuv[1] /= 0.436; + yuv[2] /= 0.615; +} + +static void yuv_to_rgb(float yuv[3], float rgb[3]) { + yuv[1] *= 0.436; + yuv[2] *= 0.615; + + rgb[0] = yuv[2]/0.877 + yuv[0]; + rgb[2] = yuv[1]/0.492 + yuv[0]; + rgb[1] = (yuv[0] - 0.299*rgb[0] - 0.114*rgb[2]) / 0.587; + if (rgb[0] > 1.0) { + rgb[0] = 1.0; + } + if (rgb[0] < 0.0) { + rgb[0] = 0.0; + } + if (rgb[1] > 1.0) { + rgb[1] = 1.0; + } + if (rgb[1] < 0.0) { + rgb[1] = 0.0; + } + if (rgb[2] > 1.0) { + rgb[2] = 1.0; + } + if (rgb[2] < 0.0) { + rgb[2] = 0.0; + } +} + +void plugin_seq_doit(Cast *cast, float facf0, float facf1, int width, + int height, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *out, ImBuf *use) { + char *dest, *src1, *src2; + int x, y, c; + float rgb[3]; + float yuv[3]; + float gamma_table[256]; + float uv_table[256]; + float *destf = out->rect_float; + float *src1f = ibuf1->rect_float; + + if (!ibuf1) return; + + dest= (char *) out->rect; + src1= (char *) ibuf1->rect; + + for (y = 0; y < 256; y++) { + float v = 1.0 * y / 255; + v += cast->setup_y; + v *= cast->gain_y; + v = pow(v, cast->gamma_y); + if ( v > 1.0) { + v = 1.0; + } else if (v < 0.0) { + v = 0.0; + } + gamma_table[y] = v * 255; + } + + for (y = 0; y < 256; y++) { + float v = 1.0; + v *= cast->master_sat; + if (y < cast->lo_thres * 255) { + v *= cast->sat_shadows; + } else if (y > cast->hi_thres * 255) { + v *= cast->sat_highlights; + } else { + v *= cast->sat_midtones; + } + uv_table[y] = v; + } + + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + float fac; + if (out->rect_float) { + rgb[0]= (float)src1f[0]/255.0; + rgb[1]= (float)src1f[1]/255.0; + rgb[2]= (float)src1f[2]/255.0; + } else { + rgb[0]= (float)src1[0]/255.0; + rgb[1]= (float)src1[1]/255.0; + rgb[2]= (float)src1[2]/255.0; + } + rgb_to_yuv(rgb, yuv); + + yuv[0] = gamma_table[(int) (yuv[0] * 255.0)] / 255.0; + fac = uv_table[(int) (255.0 * yuv[0])]; + + yuv[1] = yuv[1] * fac; + yuv[2] = yuv[2] * fac; + if (yuv[1] > 1.0) { + yuv[1] = 1.0; + } + if (yuv[1] < -1.0) { + yuv[1] = -1.0; + } + if (yuv[2] > 1.0) { + yuv[2] = 1.0; + } + if (yuv[2] < -1.0) { + yuv[2] = -1.0; + } + yuv_to_rgb(yuv, rgb); + + if (out->rect_float) { + *destf++ = rgb[0]; + *destf++ = rgb[1]; + *destf++ = rgb[2]; + destf++; + src1f += 4; + } else { + *dest++ = rgb[0]*255.0; + *dest++ = rgb[1]*255.0; + *dest++ = rgb[2]*255.0; + dest++; + src1 += 4; + } + } + } + + if (cast->debug) { + dest= (char *) out->rect; + for (c = 0; c < 10; c++) { + x = 0; + for (y = 0; y < 256; y++) { + char val = gamma_table[y]; + while (x < y * width / 255) { + *dest++ = val; + *dest++ = val; + *dest++ = val; + dest++; + x++; + } + } + } + for (c = 0; c < 10; c++) { + x = 0; + for (y = 0; y < 256; y++) { + char val = uv_table[y] * 255.0/10.0; + while (x < y * width / 255) { + *dest++ = val; + *dest++ = val; + *dest++ = val; + dest++; + x++; + } + } + } + } +} diff --git a/release/plugins/sequence/dnr.c b/release/plugins/sequence/dnr.c new file mode 100644 index 00000000000..7e7c168750e --- /dev/null +++ b/release/plugins/sequence/dnr.c @@ -0,0 +1,149 @@ +/* + * Dynamic Noise Reduction (based on the VirtualDub filter by Steven Don) + * + * Copyright (c) 2005 Peter Schlaile + * + * 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. + * + */ + +#include "math.h" +#include "plugin.h" +#include + +char name[]= "Dynamic Noise Reduction"; + +VarStruct varstr[]= { + { NUMSLI|INT, "Level:", 10.0, 0.0, 15.0, "Level"}, +}; + +typedef struct Cast { + int level; +} Cast; + +float cfra; +void * plugin_private_data; + +struct my_data { + unsigned char lookup_table[65536]; + int last_level; + float last_cfra; + int last_width; + int last_height; + unsigned char * last_frame; +}; + +void plugin_seq_doit(Cast *, float, float, int, int, + ImBuf *, ImBuf *, ImBuf *, ImBuf *); + +int plugin_seq_getversion(void) { return B_PLUGIN_VERSION;} + +static void precalculate(unsigned char * table, int level) +{ + int ap_, bp; + + for (ap_ = 0; ap_ < 256; ap_++) { + for (bp = 0; bp < 256; bp++) { + int ap = ap_; + int diff = ap - bp; + if (diff < 0) { + diff = -diff; + } + if (diff < level) { + if (diff > (level >> 1)) { + ap = (ap + ap + bp)/3; + } else { + ap = bp; + } + } + + *table++ = ap; + } + } +} + +void plugin_but_changed(int but) { } +void plugin_init() { } + +void * plugin_seq_alloc_private_data() +{ + struct my_data * result = (struct my_data*) calloc( + sizeof(struct my_data), 1); + result->last_cfra = -1; + return result; +} + +void plugin_seq_free_private_data(void * data) +{ + struct my_data * d = (struct my_data*) data; + if (d->last_frame) { + free(d->last_frame); + } + free(d); +} + +void plugin_getinfo(PluginInfo *info) { + info->name= name; + info->nvars= sizeof(varstr)/sizeof(VarStruct); + info->cfra= &cfra; + + info->varstr= varstr; + + info->init= plugin_init; + info->seq_doit= (SeqDoit) plugin_seq_doit; + info->callback= plugin_but_changed; +} + +static void doit(unsigned char * src_, unsigned char * dst_, + unsigned char * table, int width, int height) +{ + int count = width * height; + unsigned char * src = src_; + unsigned char * dst = dst_; + + while (count--) { + *dst++ = table[(*src++ << 8) | *dst]; + *dst++ = table[(*src++ << 8) | *dst]; + *dst++ = table[(*src++ << 8) | *dst]; + *dst++ = *src++; + } + + memcpy(src_, dst_, width * height * 4); +} + +void plugin_seq_doit(Cast *cast, float facf0, float facf1, int width, + int height, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *out, ImBuf *use) { + + struct my_data * d = (struct my_data*) plugin_private_data; + + if (!ibuf1) return; + + if (cast->level != d->last_level) { + precalculate(d->lookup_table, cast->level); + d->last_level = cast->level; + } + + if (width != d->last_width || height != d->last_height + || cfra != d->last_cfra + 1) { + free(d->last_frame); + d->last_frame = (unsigned char*) calloc(width * height, 4); + + d->last_width = width; + d->last_height = height; + } + + memcpy(out->rect, ibuf1->rect, width * height * 4); + + doit((unsigned char*) out->rect, + d->last_frame, d->lookup_table, width, height); + + d->last_cfra = cfra; +} diff --git a/release/plugins/sequence/gamma.c b/release/plugins/sequence/gamma.c new file mode 100644 index 00000000000..e1380746cea --- /dev/null +++ b/release/plugins/sequence/gamma.c @@ -0,0 +1,182 @@ +/* + * Gamma Correction Plugin (RGB Version) 0.01 + * + * Copyright (c) 2005 Peter Schlaile + * + * 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. + * + */ + +#include "math.h" +#include "plugin.h" +#include "util.h" +#include + +#define alpha_epsilon 0.0001f +char name[]= "Gamma Correction"; + +VarStruct varstr[]= { + { NUMSLI|FLO, "St M:", 0.0, -1.0, 1.0, "Setup Main"}, + { NUMSLI|FLO, "Gn M:", 1.0, 0.0, 10.0,"Gain Main"}, + { NUMSLI|FLO, "Ga M:", 1.0, 0.0, 10.0, "Gamma Main"}, + + { NUMSLI|FLO, "St R:", 0.0, -1.0, 1.0, "Setup Red"}, + { NUMSLI|FLO, "Gn R:", 1.0, 0.0, 10.0,"Gain Red"}, + { NUMSLI|FLO, "Ga R:", 1.0, 0.0, 10.0, "Gamma Red"}, + + { NUMSLI|FLO, "St G:", 0.0, -1.0, 1.0, "Setup Green"}, + { NUMSLI|FLO, "Gn G:", 1.0, 0.0, 10.0,"Gain Green"}, + { NUMSLI|FLO, "Ga G:", 1.0, 0.0, 10.0, "Gamma Green"}, + + { NUMSLI|FLO, "St B:", 0.0, -1.0, 1.0, "Setup Blue"}, + { NUMSLI|FLO, "Gn B:", 1.0, 0.0, 10.0,"Gain Blue"}, + { NUMSLI|FLO, "Ga B:", 1.0, 0.0, 10.0, "Gamma Blue"}, +}; + +typedef struct Cast { + float setup_m; + float gain_m; + float gamma_m; + + float setup_r; + float gain_r; + float gamma_r; + + float setup_g; + float gain_g; + float gamma_g; + + float setup_b; + float gain_b; + float gamma_b; +} Cast; + +float cfra; + +void plugin_seq_doit(Cast *, float, float, int, int, ImBuf *, ImBuf *, ImBuf *, ImBuf *); + +int plugin_seq_getversion(void) { return B_PLUGIN_VERSION; } +void plugin_but_changed(int but) {} +void plugin_init() {} + +void plugin_getinfo(PluginInfo *info) { + info->name= name; + info->nvars= sizeof(varstr)/sizeof(VarStruct); + info->cfra= &cfra; + + info->varstr= varstr; + + info->init= plugin_init; + info->seq_doit= (SeqDoit) plugin_seq_doit; + info->callback= plugin_but_changed; +} + +static void make_gamma_table(float setup, float gain, float gamma, + unsigned char * table) +{ + int y; + + for (y = 0; y < 256; y++) { + float v = 1.0 * y / 255; + v += setup; + v *= gain; + v = pow(v, gamma); + if ( v > 1.0) { + v = 1.0; + } else if (v < 0.0) { + v = 0.0; + } + table[y] = v * 255; + } + +} + + +void plugin_seq_doit(Cast *cast, float facf0, float facf1, int width, + int height, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *out, ImBuf *use) { + if (!out->rect_float) + { + unsigned char *dest, *src1, *src2; + int x, y, c; + unsigned char gamma_table_m[256]; + unsigned char gamma_table_r[256]; + unsigned char gamma_table_g[256]; + unsigned char gamma_table_b[256]; + + if (!ibuf1) return; + + dest= (unsigned char *) out->rect; + src1= (unsigned char *) ibuf1->rect; + + make_gamma_table(cast->setup_m, cast->gain_m, cast->gamma_m, + gamma_table_m); + make_gamma_table(cast->setup_r, cast->gain_r, cast->gamma_r, + gamma_table_r); + make_gamma_table(cast->setup_g, cast->gain_g, cast->gamma_g, + gamma_table_g); + make_gamma_table(cast->setup_b, cast->gain_b, cast->gamma_b, + gamma_table_b); + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + *dest++ = gamma_table_r[gamma_table_m[*src1++]]; + *dest++ = gamma_table_g[gamma_table_m[*src1++]]; + *dest++ = gamma_table_b[gamma_table_m[*src1++]]; + dest++; src1++; + } + } + } + else + { + float *i=ibuf1->rect_float; + float *o=out->rect_float; + unsigned int size=width*height; + unsigned int k; + float val_r[3]={cast->setup_r,cast->gain_r,cast->gamma_r}; + float val_g[3]={cast->setup_g,cast->gain_g,cast->gamma_g}; + float val_b[3]={cast->setup_b,cast->gain_b,cast->gamma_b}; + float *vals[3]={val_r,val_g,val_b}; + for (k=0;kgamma_m!=1.f || cast->setup_m!=0.f || cast->gain_m!=1.f) + { + float alpha=CLAMP(i[3],0.f,1.f); + if (alpha>alpha_epsilon) { + int l; + for (l=0;l<3;++l) + { + float *val=vals[l]; + o[l]=i[l]/alpha; + o[l]=pow((o[l]+cast->setup_m)*cast->gain_m,cast->gamma_m); + if (val[2]!=1.f || val[0]!=0.f || val[1]!=1.f) + { + o[l]=pow((o[l]+val[0])*val[1],val[2]); + } + o[l]*=alpha; + o[l]=CLAMP(o[l],0.f,1.f); + } + } else { + o[0]=o[1]=o[2]=0.0; + } + o[3]=1.0; + } + else + { + int l; + for (l=0;l<3;++l) + o[l]=CLAMP(i[l],0.f,1.f); + o[3]=1.0; + } + i+=4; + o+=4; + } + } +} diff --git a/release/plugins/sequence/scatter.c b/release/plugins/sequence/scatter.c new file mode 100644 index 00000000000..277529690c4 --- /dev/null +++ b/release/plugins/sequence/scatter.c @@ -0,0 +1,263 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "plugin.h" + +/* ******************** GLOBAL VARIABLES ***************** */ + + +char name[24]= "scatter"; + +/* structure for buttons, + * butcode name default min max 0 + */ + +VarStruct varstr[]= { + LABEL, "Input: 1 strip", 0.0, 0.0, 0.0, "", + NUM|INT, "seed: ", 1.0, 0.0, 10.0, "Offset in random table", + NUMSLI|FLO, "swing: ", 1.0, 0.0, 3.0, "The amplitude, width of the effect", + TOG|INT, "wrap", 0.0, 0.0, 1.0, "Cyclic wrap around the left/right edges", + NUM|INT, "type: ", 1.0, 0.0, 1.0, "Type 1 is random for each frame", +}; + +/* The cast struct is for input in the main doit function + Varstr and Cast must have the same variables in the same order */ + +typedef struct Cast { + int dummy; /* because of the 'label' button */ + int seed; + float swing; + int wrap; + int type; +} Cast; + +/* cfra: the current frame */ + +float cfra; + +void plugin_seq_doit(Cast *, float, float, int, int, ImBuf *, ImBuf *, ImBuf *, ImBuf *); + + +/* ******************** Fixed functions ***************** */ + +int plugin_seq_getversion(void) +{ + return B_PLUGIN_VERSION; +} + +void plugin_but_changed(int but) +{ +} + +void plugin_init() +{ +} + +void plugin_getinfo(PluginInfo *info) +{ + info->name= name; + info->nvars= sizeof(varstr)/sizeof(VarStruct); + info->cfra= &cfra; + + info->varstr= varstr; + + info->init= plugin_init; + info->seq_doit= (SeqDoit) plugin_seq_doit; + info->callback= plugin_but_changed; +} + + +/* ************************************************************ + Scatter + + ************************************************************ */ + +static void rectcpy(ImBuf *dbuf, ImBuf *sbuf, + int destx, int desty, + int srcx, int srcy, int width, int height) +{ + uint *drect,*srect; + float *dfrect, *sfrect; + int tmp; + + if (dbuf == 0) return; + + if (destx < 0){ + srcx -= destx ; + width += destx ; + destx = 0; + } + if (srcx < 0){ + destx -= srcx ; + width += destx ; + srcx = 0; + } + if (desty < 0){ + srcy -= desty ; + height += desty ; + desty = 0; + } + if (srcy < 0){ + desty -= srcy ; + height += desty ; + srcy = 0; + } + + if (width > dbuf->x - destx) width = dbuf->x - destx; + if (height > dbuf->y - desty) height = dbuf->y - desty; + if (sbuf){ + if (width > sbuf->x - srcx) width = sbuf->x - srcx; + if (height > sbuf->y - srcy) height = sbuf->y - srcy; + srect = sbuf->rect; + sfrect = sbuf->rect_float; + } + + if (width <= 0) return; + if (height <= 0) return; + + drect = dbuf->rect; + dfrect = dbuf->rect_float; + + tmp = (desty * dbuf->x + destx); + + if (dbuf->rect_float) dfrect += 4 * tmp; + else drect += tmp; + + destx = dbuf->x; + + if (sbuf) { + tmp = (srcy * sbuf->x + srcx ); + if (dbuf->rect_float) sfrect += 4 * tmp; + else srect += tmp; + srcx = sbuf->x; + } else{ + if (dbuf->rect_float) sfrect = dfrect; + else srect = drect; + srcx = destx; + } + + for (;height > 0; height--){ + if (dbuf->rect_float) { + memcpy(dfrect,sfrect, 4 * width * sizeof(float)); + dfrect += destx; + sfrect += srcx; + } else { + memcpy(drect,srect, width * sizeof(int)); + drect += destx; + srect += srcx; + } + } +} + +static void fill_out(ImBuf *out, float r, float g, float b, float a) +{ + int tot,x; + float *rectf = out->rect_float; + unsigned char *rect = (unsigned char *)out->rect; + + tot = out->x * out->y; + if (out->rect_float) { + for (x = 0;x < tot; x++) { + rectf[0] = r; + rectf[1] = g; + rectf[2] = b; + rectf[3] = a; + rectf += 4; + } + } else { + for (x=0;x < tot;x++) { + rect[0] = (int)(r * 255); + rect[1] = (int)(g * 255); + rect[2] = (int)(b * 255); + rect[3] = (int)(a * 255); + rect += 4; + } + } +} + + +void plugin_seq_doit(Cast *cast, float facf0, float facf1, int sx, int sy, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *out, ImBuf *use) +{ + float f1, f2, t1, t2, t3; + int x, y, lr; + + /* fill imbuf 'out' with black */ + fill_out(out, 0,0,0,0); + + + switch (cast->type) { + case 0: + srand48(cast->seed); + break; + case 1: + srand48(cast->seed + facf0 * 1000); + break; + } + + for (y = 0; y < sy; y++) { + switch (cast->type) { + case 0: + if ((y & 1) == 0) { + f1 = drand48() - 0.5; + f2 = drand48() - 0.5; + f1 = cast->swing * f1; + f2 = cast->swing * f2; + if (cast->wrap) f2 += 1.0; + lr = drand48()>0.5; + t1 = facf0; + } else t1 = facf1; + + t2 = 1.0 - t1; + t3 = 3.0 * (f1 * t1 * t1 * t2 + f2 * t1 * t2 * t2); + if (cast->wrap) t3 += t2 * t2 * t2; + x = sx * t3; + if (lr) x = -x; + break; + case 1: + f1 = drand48() - 0.5; + f1 = f1 * cast->swing; + if ((y & 1) == 0) f1 *= facf0; + else f1 *= facf1; + x = f1 * sx; + break; + } + + rectcpy(out, ibuf1, 0, y, x, y, 32767, 1); + if (cast->wrap) { + rectcpy(out, ibuf1, 0, y, x + sx, y, 32767, 1); + rectcpy(out, ibuf1, 0, y, x + sx + sx, y, 32767, 1); + rectcpy(out, ibuf1, 0, y, x - sx, y, 32767, 1); + rectcpy(out, ibuf1, 0, y, x - sx - sx, y, 32767, 1); + } + } +} + diff --git a/release/plugins/texture/Makefile b/release/plugins/texture/Makefile new file mode 100644 index 00000000000..dc632c5d2e7 --- /dev/null +++ b/release/plugins/texture/Makefile @@ -0,0 +1,38 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +all: plugins + +plugins: + @/bin/sh -c 'for i in *.c; do ../bmake $$i; done;' + +clean: + rm -rf *.o *.so diff --git a/release/plugins/texture/clouds2.c b/release/plugins/texture/clouds2.c new file mode 100644 index 00000000000..69f890e4df3 --- /dev/null +++ b/release/plugins/texture/clouds2.c @@ -0,0 +1,182 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "math.h" +#include "plugin.h" + +/* ******************** GLOBAL VARIABLES ***************** */ + +/* Texture name */ + +char name[24]= "Clouds2"; + +/* Subtype names must be less than 15 characters */ + +#define NR_TYPES 3 +char stnames[NR_TYPES][16]= {"Intens", "Col", "Bump" }; + +/* Structure for buttons, + * butcode name default min max 0 + */ + +VarStruct varstr[]= { +{ NUM|FLO, "Offset", -0.5, -20.0, 20.0, ""}, +{ NUM|INT, "Depth", 8.0, 1.0, 12.0, ""}, +{ NUM|FLO, "Scale", 2.2, -20.0, 20.0, ""}, +{ NUM|FLO, "Falloff", 1.0, -20.0, 20.0, ""} +}; + +/* The cast struct is for input in the main doit function + Varstr and Cast must have the same variables in the same order, + INCLUDING dummy variables for label fields. */ + +typedef struct Cast { + float offset; + int depth; + float txtscale; + float falloff; +} Cast; + +/* result: + Intensity, R, G, B, Alpha, nor.x, nor.y, nor.z + */ + +float result[8]; + +/* cfra: the current frame */ + +float cfra; + +int plugin_tex_doit(int, Cast*, float*, float*, float*); +void plugin_instance_init(Cast*); + +/* ******************** Fixed functions ***************** */ + +int plugin_tex_getversion(void) +{ + return B_PLUGIN_VERSION; +} + +void plugin_but_changed(int but) +{ +} + +void plugin_init(void) +{ + +} + +/* + * initialize any data for a particular instance of + * the plugin here + */ +void plugin_instance_init(Cast *cast) +{ +} + +/* this function should not be changed: */ + +void plugin_getinfo(PluginInfo *info) +{ + info->name= name; + info->stypes= NR_TYPES; + info->nvars= sizeof(varstr)/sizeof(VarStruct); + + info->snames= stnames[0]; + info->result= result; + info->cfra= &cfra; + info->varstr= varstr; + + info->init= plugin_init; + info->tex_doit= (TexDoit) plugin_tex_doit; + info->callback= plugin_but_changed; + info->instance_init= (void (*)(void *)) plugin_instance_init; +} + +/* ********************* the texture ******************** */ + + +int plugin_tex_doit(int stype, Cast *cast, float *texvec, float *dxt, float *dyt) +{ + float val = 0.0; + float a = 1.0; + float p[3]; + float tv[3]; + int i; + int res = TEX_INT; + + tv[0]=(texvec[0]+1.0)/2.0; + tv[1]=(texvec[1]+1.0)/2.0; + tv[2]=(texvec[2]+1.0)/2.0; + + p[0] = cast->txtscale * tv[0]; + p[1] = cast->txtscale * tv[1]; + p[2] = cast->txtscale * tv[2]; + + for (i=0; idepth; i++) { + val += a * hnoise(1.0, p[0], p[1], p[2]); + + p[0] *= 2.0; + p[1] *= 2.0; + p[2] *= 2.0; + a *= 0.5; + } + + /* always return this value */ + result[0] = CLAMP (val+cast->offset, 0.0, 1.0) * pow (fabs(sqrt(tv[0]*tv[0]+tv[1]*tv[1]+tv[2]*tv[2])), cast->falloff); + + if(stype==1) { + /* + * this is r, g, b, a: + */ + result[1]= 0.5*result[0]; + result[2]= 1.0-val; + result[3]= fsqrt(fabs(result[0])); + result[4]= 1.0; + + res |= TEX_RGB; + } + if(stype==2) { + /* + * This value is the displacement of the actual normal in + * the Material calculation. + */ + result[5]+= val; + result[6]+= 1.0-val; + result[7]= 0.0; + + res |= TEX_NOR; + } + + return res; +} + diff --git a/release/plugins/texture/tiles.c b/release/plugins/texture/tiles.c new file mode 100644 index 00000000000..2bdf669f9ca --- /dev/null +++ b/release/plugins/texture/tiles.c @@ -0,0 +1,181 @@ + /** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "math.h" +#include "plugin.h" + +/* ******************** GLOBAL VARIABLES ***************** */ + +char name[]= "tiles"; + +/* Subtype names must be less than 15 characters */ + +#define NR_TYPES 2 +char stnames[NR_TYPES][16]= {"Square", "Deformed"}; + +VarStruct varstr[]= { + NUM|FLO, "size", 1.0, 0.0, 1.0, "The size of each tile", + NUM|FLO, "Noise", 1.0, 0.01, 10.0, "" +}; + +/* The cast struct is for input in the main doit function + Varstr and Cast must have the same variables in the same order */ + +typedef struct Cast { + float size; + float noise; +} Cast; + +/* result: + Intensity, R, G, B, Alpha, nor.x, nor.y, nor.z + */ + +float result[8]; + +/* cfra: the current frame */ + +float cfra; + +int plugin_tex_doit(int, Cast *, float *, float *, float *); +void plugin_instance_init(Cast*); + +/* ******************** Fixed functions ***************** */ + +int plugin_tex_getversion(void) +{ + return B_PLUGIN_VERSION; +} + +void plugin_but_changed(int but) +{ +} + +void plugin_init(void) +{ +} + +/* + * initialize any data for a particular instance of + * the plugin here + */ +void plugin_instance_init(Cast *cast) +{ +} + +/* this function should not be changed: */ + +void plugin_getinfo(PluginInfo *info) +{ + info->name= name; + info->stypes= NR_TYPES; + info->nvars= sizeof(varstr)/sizeof(VarStruct); + + info->snames= stnames[0]; + info->result= result; + info->cfra= &cfra; + info->varstr= varstr; + + info->init= plugin_init; + info->tex_doit= (TexDoit) plugin_tex_doit; + info->callback= plugin_but_changed; + info->instance_init= (void (*)(void *)) plugin_instance_init; + +} + +/* ************************************************************ + Tiles + + Demonstration of a simple square wave function sampled + with anti-aliasing. + It is not mipmapped yet... + + ************************************************************ */ + + +/* square wave, antialiased, no mipmap! */ + +float sample_wave(float freq, float coord, float pixsize) +{ + float fac, frac, retval; + int part1, part2; + + if(pixsize > freq) return 0.5; + + pixsize/= freq; + + fac= coord/freq; + part1= ffloor(fac); + frac= fac - part1; + + if(part1 & 1) retval= 0.0; + else retval= 1.0; + + if(pixsize != 0.0) { + + /* is coord+pixsize another value? */ + + part2= ffloor(fac + pixsize); + if(part1==part2) return retval; + + /* antialias */ + if(retval==1.0) retval= (1.0-frac)/pixsize; + else retval= 1.0-(1.0-frac)/pixsize; + } + return retval; +} + +int plugin_tex_doit(int stype, Cast *cast, float *texvec, float *dxt, float *dyt) +{ + float xwave, ywave; + + if(stype==1) { + texvec[0]+= hnoise(cast->noise, texvec[0], texvec[1], texvec[2]); + texvec[1]+= hnoise(cast->noise, texvec[1], texvec[2], texvec[0]); + } + + if(dxt && dyt) { + xwave= sample_wave(cast->size, texvec[0], fabs(dxt[0]) + fabs(dyt[0]) ); + ywave= sample_wave(cast->size, texvec[1], fabs(dxt[1]) + fabs(dyt[1]) ); + + if(xwave > ywave) result[0]= xwave-ywave; + else result[0]= ywave-xwave; + } + else { + xwave= sample_wave(cast->size, texvec[0], 0.0 ); + ywave= sample_wave(cast->size, texvec[1], 0.0 ); + + if(xwave > ywave) result[0]= xwave-ywave; + else result[0]= ywave-xwave; + } + + return TEX_INT; +} diff --git a/release/scripts/3ds_export.py b/release/scripts/3ds_export.py new file mode 100644 index 00000000000..0209b04844a --- /dev/null +++ b/release/scripts/3ds_export.py @@ -0,0 +1,1013 @@ +#!BPY + +""" +Name: '3D Studio (.3ds)...' +Blender: 243 +Group: 'Export' +Tooltip: 'Export to 3DS file format (.3ds).' +""" + +__author__ = ["Campbell Barton", "Bob Holcomb", "Richard Lärkäng", "Damien McGinnes", "Mark Stijnman"] +__url__ = ("blenderartists.org", "www.blender.org", "www.gametutorials.com", "lib3ds.sourceforge.net/") +__version__ = "0.90a" +__bpydoc__ = """\ + +3ds Exporter + +This script Exports a 3ds file. + +Exporting is based on 3ds loader from www.gametutorials.com(Thanks DigiBen) and using information +from the lib3ds project (http://lib3ds.sourceforge.net/) sourcecode. +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Bob Holcomb +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +###################################################### +# Importing modules +###################################################### + +import Blender +import bpy +from BPyMesh import getMeshFromObject +from BPyObject import getDerivedObjects +import struct + +# So 3ds max can open files, limit names to 12 in length +# this is verry annoying for filenames! +name_unique = [] +name_mapping = {} +def sane_name(name): + name_fixed = name_mapping.get(name) + if name_fixed != None: + return name_fixed + + if len(name) > 12: + new_name = name[:12] + else: + new_name = name + + i = 0 + + while new_name in name_unique: + new_name = new_name[:-4] + '.%.3d' % i + i+=1 + + name_unique.append(new_name) + name_mapping[name] = new_name + return new_name + +###################################################### +# Data Structures +###################################################### + +#Some of the chunks that we will export +#----- Primary Chunk, at the beginning of each file +PRIMARY= long("0x4D4D",16) + +#------ Main Chunks +OBJECTINFO = long("0x3D3D",16); #This gives the version of the mesh and is found right before the material and object information +VERSION = long("0x0002",16); #This gives the version of the .3ds file +KFDATA = long("0xB000",16); #This is the header for all of the key frame info + +#------ sub defines of OBJECTINFO +MATERIAL=45055 #0xAFFF // This stored the texture info +OBJECT=16384 #0x4000 // This stores the faces, vertices, etc... + +#>------ sub defines of MATERIAL +MATNAME = long("0xA000",16); # This holds the material name +MATAMBIENT = long("0xA010",16); # Ambient color of the object/material +MATDIFFUSE = long("0xA020",16); # This holds the color of the object/material +MATSPECULAR = long("0xA030",16); # SPecular color of the object/material +MATSHINESS = long("0xA040",16); # ?? +MATMAP = long("0xA200",16); # This is a header for a new material +MATMAPFILE = long("0xA300",16); # This holds the file name of the texture + +RGB1= long("0x0011",16) +RGB2= long("0x0012",16) + +#>------ sub defines of OBJECT +OBJECT_MESH = long("0x4100",16); # This lets us know that we are reading a new object +OBJECT_LIGHT = long("0x4600",16); # This lets un know we are reading a light object +OBJECT_CAMERA= long("0x4700",16); # This lets un know we are reading a camera object + +#>------ sub defines of CAMERA +OBJECT_CAM_RANGES= long("0x4720",16); # The camera range values + +#>------ sub defines of OBJECT_MESH +OBJECT_VERTICES = long("0x4110",16); # The objects vertices +OBJECT_FACES = long("0x4120",16); # The objects faces +OBJECT_MATERIAL = long("0x4130",16); # This is found if the object has a material, either texture map or color +OBJECT_UV = long("0x4140",16); # The UV texture coordinates +OBJECT_TRANS_MATRIX = long("0x4160",16); # The Object Matrix + +#>------ sub defines of KFDATA +KFDATA_KFHDR = long("0xB00A",16); +KFDATA_KFSEG = long("0xB008",16); +KFDATA_KFCURTIME = long("0xB009",16); +KFDATA_OBJECT_NODE_TAG = long("0xB002",16); + +#>------ sub defines of OBJECT_NODE_TAG +OBJECT_NODE_ID = long("0xB030",16); +OBJECT_NODE_HDR = long("0xB010",16); +OBJECT_PIVOT = long("0xB013",16); +OBJECT_INSTANCE_NAME = long("0xB011",16); +POS_TRACK_TAG = long("0xB020",16); +ROT_TRACK_TAG = long("0xB021",16); +SCL_TRACK_TAG = long("0xB022",16); + +def uv_key(uv): + return round(uv.x, 6), round(uv.y, 6) + +# size defines: +SZ_SHORT = 2 +SZ_INT = 4 +SZ_FLOAT = 4 + +class _3ds_short(object): + '''Class representing a short (2-byte integer) for a 3ds file. + *** This looks like an unsigned short H is unsigned from the struct docs - Cam***''' + __slots__ = 'value' + def __init__(self, val=0): + self.value=val + + def get_size(self): + return SZ_SHORT + + def write(self,file): + file.write(struct.pack("= mat_ls_len: + mat_index = f.mat = 0 + mat = mat_ls[mat_index] + if mat: mat_name = mat.name + else: mat_name = None + # else there alredy set to none + + img = f.image + if img: img_name = img.name + else: img_name = None + + materialDict.setdefault((mat_name, img_name), (mat, img) ) + + + else: + for mat in mat_ls: + if mat: # material may be None so check its not. + materialDict.setdefault((mat.name, None), (mat, None) ) + + # Why 0 Why! + for f in data.faces: + if f.mat >= mat_ls_len: + f.mat = 0 + + # Make material chunks for all materials used in the meshes: + for mat_and_image in materialDict.itervalues(): + object_info.add_subchunk(make_material_chunk(mat_and_image[0], mat_and_image[1])) + + # Give all objects a unique ID and build a dictionary from object name to object id: + """ + name_to_id = {} + for ob, data in mesh_objects: + name_to_id[ob.name]= len(name_to_id) + #for ob in empty_objects: + # name_to_id[ob.name]= len(name_to_id) + """ + + # Create object chunks for all meshes: + i = 0 + for ob, blender_mesh in mesh_objects: + # create a new object chunk + object_chunk = _3ds_chunk(OBJECT) + + # set the object name + object_chunk.add_variable("name", _3ds_string(sane_name(ob.name))) + + # make a mesh chunk out of the mesh: + object_chunk.add_subchunk(make_mesh_chunk(blender_mesh, materialDict)) + object_info.add_subchunk(object_chunk) + + ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX + # make a kf object node for the object: + kfdata.add_subchunk(make_kf_obj_node(ob, name_to_id)) + ''' + blender_mesh.verts = None + i+=i + + # Create chunks for all empties: + ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX + for ob in empty_objects: + # Empties only require a kf object node: + kfdata.add_subchunk(make_kf_obj_node(ob, name_to_id)) + pass + ''' + + # Add main object info chunk to primary chunk: + primary.add_subchunk(object_info) + + ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX + # Add main keyframe data chunk to primary chunk: + primary.add_subchunk(kfdata) + ''' + + # At this point, the chunk hierarchy is completely built. + + # Check the size: + primary.get_size() + # Open the file for writing: + file = open( filename, 'wb' ) + + # Recursively write the chunks to file: + primary.write(file) + + # Close the file: + file.close() + + # Debugging only: report the exporting time: + Blender.Window.WaitCursor(0) + print "3ds export time: %.2f" % (Blender.sys.time() - time1) + + # Debugging only: dump the chunk hierarchy: + #primary.dump() + + +if __name__=='__main__': + Blender.Window.FileSelector(save_3ds, "Export 3DS", Blender.sys.makename(ext='.3ds')) +# save_3ds('/test_b.3ds') diff --git a/release/scripts/3ds_import.py b/release/scripts/3ds_import.py new file mode 100644 index 00000000000..07da4df1603 --- /dev/null +++ b/release/scripts/3ds_import.py @@ -0,0 +1,982 @@ +#!BPY +""" +Name: '3D Studio (.3ds)...' +Blender: 244 +Group: 'Import' +Tooltip: 'Import from 3DS file format (.3ds)' +""" + +__author__= ['Bob Holcomb', 'Richard L?rk?ng', 'Damien McGinnes', 'Campbell Barton'] +__url__ = ("blenderartists.org", "www.blender.org", "www.gametutorials.com", "lib3ds.sourceforge.net/") +__version__= '0.995' +__bpydoc__= '''\ + +3ds Importer + +This script imports a 3ds file and the materials into Blender for editing. + +Loader is based on 3ds loader from www.gametutorials.com (Thanks DigiBen). + + +0.995 by Campbell Barton
+- workaround for buggy mesh vert delete +- minor tweaks + +0.99 by Bob Holcomb
+- added support for floating point color values that previously broke on import. + +0.98 by Campbell Barton
+- import faces and verts to lists instead of a mesh, convert to a mesh later +- use new index mapping feature of mesh to re-map faces that were not added. + +0.97 by Campbell Barton
+- Strip material names of spaces +- Added import as instance to import the 3ds into its own + scene and add a group instance to the current scene +- New option to scale down imported objects so they are within a limited bounding area. + +0.96 by Campbell Barton
+- Added workaround for bug in setting UV's for Zero vert index UV faces. +- Removed unique name function, let blender make the names unique. + +0.95 by Campbell Barton
+- Removed workarounds for Blender 2.41 +- Mesh objects split by material- many 3ds objects used more then 16 per mesh. +- Removed a lot of unneeded variable creation. + +0.94 by Campbell Barton
+- Face import tested to be about overall 16x speedup over 0.93. +- Material importing speedup. +- Tested with more models. +- Support some corrupt models. + +0.93 by Campbell Barton
+- Tested with 400 3ds files from turbosquid and samples. +- Tactfully ignore faces that used the same verts twice. +- Rollback to 0.83 sloppy un-reorganized code, this broke UV coord loading. +- Converted from NMesh to Mesh. +- Faster and cleaner new names. +- Use external comprehensive image loader. +- Re intergrated 0.92 and 0.9 changes +- Fixes for 2.41 compat. +- Non textured faces do not use a texture flag. + +0.92
+- Added support for diffuse, alpha, spec, bump maps in a single material + +0.9
+- Reorganized code into object/material block functions
+- Use of Matrix() to copy matrix data
+- added support for material transparency
+ +0.83 2005-08-07: Campell Barton +- Aggressive image finding and case insensitivy for posisx systems. + +0.82a 2005-07-22 +- image texture loading (both for face uv and renderer) + +0.82 - image texture loading (for face uv) + +0.81a (fork- not 0.9) Campbell Barton 2005-06-08 +- Simplified import code +- Never overwrite data +- Faster list handling +- Leaves import selected + +0.81 Damien McGinnes 2005-01-09 +- handle missing images better + +0.8 Damien McGinnes 2005-01-08 +- copies sticky UV coords to face ones +- handles images better +- Recommend that you run 'RemoveDoubles' on each imported mesh after using this script + +''' + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Bob Holcomb +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +# Importing modules + +import Blender +import bpy +from Blender import Mesh, Object, Material, Image, Texture, Lamp, Mathutils +from Blender.Mathutils import Vector +import BPyImage + +import BPyMessages + +import struct +from struct import calcsize, unpack + +import os + +# If python version is less than 2.4, try to get set stuff from module +try: + set +except: + from sets import Set as set + +BOUNDS_3DS= [] + + +#this script imports uvcoords as sticky vertex coords +#this parameter enables copying these to face uv coords +#which shold be more useful. + +def createBlenderTexture(material, name, image): + texture= bpy.data.textures.new(name) + texture.setType('Image') + texture.image= image + material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL) + + + +###################################################### +# Data Structures +###################################################### + +#Some of the chunks that we will see +#----- Primary Chunk, at the beginning of each file +PRIMARY= long('0x4D4D',16) + +#------ Main Chunks +OBJECTINFO = long('0x3D3D',16); #This gives the version of the mesh and is found right before the material and object information +VERSION = long('0x0002',16); #This gives the version of the .3ds file +EDITKEYFRAME= long('0xB000',16); #This is the header for all of the key frame info + +#------ sub defines of OBJECTINFO +MATERIAL=45055 #0xAFFF // This stored the texture info +OBJECT=16384 #0x4000 // This stores the faces, vertices, etc... + +#>------ sub defines of MATERIAL +#------ sub defines of MATERIAL_BLOCK +MAT_NAME = long('0xA000',16) # This holds the material name +MAT_AMBIENT = long('0xA010',16) # Ambient color of the object/material +MAT_DIFFUSE = long('0xA020',16) # This holds the color of the object/material +MAT_SPECULAR = long('0xA030',16) # SPecular color of the object/material +MAT_SHINESS = long('0xA040',16) # ?? +MAT_TRANSPARENCY= long('0xA050',16) # Transparency value of material +MAT_SELF_ILLUM = long('0xA080',16) # Self Illumination value of material +MAT_WIRE = long('0xA085',16) # Only render's wireframe + +MAT_TEXTURE_MAP = long('0xA200',16) # This is a header for a new texture map +MAT_SPECULAR_MAP= long('0xA204',16) # This is a header for a new specular map +MAT_OPACITY_MAP = long('0xA210',16) # This is a header for a new opacity map +MAT_REFLECTION_MAP= long('0xA220',16) # This is a header for a new reflection map +MAT_BUMP_MAP = long('0xA230',16) # This is a header for a new bump map +MAT_MAP_FILENAME = long('0xA300',16) # This holds the file name of the texture + +MAT_FLOAT_COLOR = long ('0x0010', 16) #color defined as 3 floats +MAT_24BIT_COLOR = long ('0x0011', 16) #color defined as 3 bytes + +#>------ sub defines of OBJECT +OBJECT_MESH = long('0x4100',16); # This lets us know that we are reading a new object +OBJECT_LAMP = long('0x4600',16); # This lets un know we are reading a light object +OBJECT_LAMP_SPOT = long('0x4610',16); # The light is a spotloght. +OBJECT_LAMP_OFF = long('0x4620',16); # The light off. +OBJECT_LAMP_ATTENUATE = long('0x4625',16); +OBJECT_LAMP_RAYSHADE = long('0x4627',16); +OBJECT_LAMP_SHADOWED = long('0x4630',16); +OBJECT_LAMP_LOCAL_SHADOW = long('0x4640',16); +OBJECT_LAMP_LOCAL_SHADOW2 = long('0x4641',16); +OBJECT_LAMP_SEE_CONE = long('0x4650',16); +OBJECT_LAMP_SPOT_RECTANGULAR= long('0x4651',16); +OBJECT_LAMP_SPOT_OVERSHOOT= long('0x4652',16); +OBJECT_LAMP_SPOT_PROJECTOR= long('0x4653',16); +OBJECT_LAMP_EXCLUDE= long('0x4654',16); +OBJECT_LAMP_RANGE= long('0x4655',16); +OBJECT_LAMP_ROLL= long('0x4656',16); +OBJECT_LAMP_SPOT_ASPECT= long('0x4657',16); +OBJECT_LAMP_RAY_BIAS= long('0x4658',16); +OBJECT_LAMP_INNER_RANGE= long('0x4659',16); +OBJECT_LAMP_OUTER_RANGE= long('0x465A',16); +OBJECT_LAMP_MULTIPLIER = long('0x465B',16); +OBJECT_LAMP_AMBIENT_LIGHT = long('0x4680',16); + + + +OBJECT_CAMERA= long('0x4700',16); # This lets un know we are reading a camera object + +#>------ sub defines of CAMERA +OBJECT_CAM_RANGES= long('0x4720',16); # The camera range values + +#>------ sub defines of OBJECT_MESH +OBJECT_VERTICES = long('0x4110',16); # The objects vertices +OBJECT_FACES = long('0x4120',16); # The objects faces +OBJECT_MATERIAL = long('0x4130',16); # This is found if the object has a material, either texture map or color +OBJECT_UV = long('0x4140',16); # The UV texture coordinates +OBJECT_TRANS_MATRIX = long('0x4160',16); # The Object Matrix + +global scn +scn= None + +#the chunk class +class chunk: + ID=0 + length=0 + bytes_read=0 + + #we don't read in the bytes_read, we compute that + binary_format='3): + print '\tNon-Fatal Error: Version greater than 3, may not load correctly: ', version + + #is it an object info chunk? + elif (new_chunk.ID==OBJECTINFO): + #print 'elif (new_chunk.ID==OBJECTINFO):' + # print 'found an OBJECTINFO chunk' + process_next_chunk(file, new_chunk, importedObjects, IMAGE_SEARCH) + + #keep track of how much we read in the main chunk + new_chunk.bytes_read+=temp_chunk.bytes_read + + #is it an object chunk? + elif (new_chunk.ID==OBJECT): + tempName= read_string(file) + contextObName= tempName + new_chunk.bytes_read += len(tempName)+1 + + #is it a material chunk? + elif (new_chunk.ID==MATERIAL): + #print 'elif (new_chunk.ID==MATERIAL):' + contextMaterial= bpy.data.materials.new('Material') + + elif (new_chunk.ID==MAT_NAME): + #print 'elif (new_chunk.ID==MAT_NAME):' + material_name= read_string(file) + + #plus one for the null character that ended the string + new_chunk.bytes_read+= len(material_name)+1 + + contextMaterial.name= material_name.rstrip() # remove trailing whitespace + MATDICT[material_name]= (contextMaterial.name, contextMaterial) + + elif (new_chunk.ID==MAT_AMBIENT): + #print 'elif (new_chunk.ID==MAT_AMBIENT):' + read_chunk(file, temp_chunk) + if (temp_chunk.ID==MAT_FLOAT_COLOR): + temp_data=file.read(calcsize('3f')) + temp_chunk.bytes_read+=12 + contextMaterial.mirCol=[float(col) for col in unpack('<3f', temp_data)] + elif (temp_chunk.ID==MAT_24BIT_COLOR): + temp_data=file.read(calcsize('3B')) + temp_chunk.bytes_read+= 3 + contextMaterial.mirCol= [float(col)/255 for col in unpack('<3B', temp_data)] # data [0,1,2] == rgb + else: + skip_to_end(file, temp_chunk) + new_chunk.bytes_read+= temp_chunk.bytes_read + + elif (new_chunk.ID==MAT_DIFFUSE): + #print 'elif (new_chunk.ID==MAT_DIFFUSE):' + read_chunk(file, temp_chunk) + if (temp_chunk.ID==MAT_FLOAT_COLOR): + temp_data=file.read(calcsize('3f')) + temp_chunk.bytes_read+=12 + contextMaterial.rgbCol=[float(col) for col in unpack('<3f', temp_data)] + elif (temp_chunk.ID==MAT_24BIT_COLOR): + temp_data=file.read(calcsize('3B')) + temp_chunk.bytes_read+= 3 + contextMaterial.rgbCol= [float(col)/255 for col in unpack('<3B', temp_data)] # data [0,1,2] == rgb + else: + skip_to_end(file, temp_chunk) + new_chunk.bytes_read+= temp_chunk.bytes_read + + elif (new_chunk.ID==MAT_SPECULAR): + #print 'elif (new_chunk.ID==MAT_SPECULAR):' + read_chunk(file, temp_chunk) + if (temp_chunk.ID==MAT_FLOAT_COLOR): + temp_data=file.read(calcsize('3f')) + temp_chunk.bytes_read+=12 + contextMaterial.mirCol=[float(col) for col in unpack('<3f', temp_data)] + elif (temp_chunk.ID==MAT_24BIT_COLOR): + temp_data=file.read(calcsize('3B')) + temp_chunk.bytes_read+= 3 + contextMaterial.mirCol= [float(col)/255 for col in unpack('<3B', temp_data)] # data [0,1,2] == rgb + else: + skip_to_end(file, temp_chunk) + new_chunk.bytes_read+= temp_chunk.bytes_read + + elif (new_chunk.ID==MAT_TEXTURE_MAP): + #print 'elif (new_chunk.ID==MAT_TEXTURE_MAP):' + new_texture= bpy.data.textures.new('Diffuse') + new_texture.setType('Image') + img = None + while (new_chunk.bytes_read BOUNDS_3DS[i+3]: + BOUNDS_3DS[i+3]= v[i] # min + + # Get the max axis x/y/z + max_axis= max(BOUNDS_3DS[3]-BOUNDS_3DS[0], BOUNDS_3DS[4]-BOUNDS_3DS[1], BOUNDS_3DS[5]-BOUNDS_3DS[2]) + # print max_axis + if max_axis < 1<<30: # Should never be false but just make sure. + + # Get a new scale factor if set as an option + SCALE=1.0 + while (max_axis*SCALE) > IMPORT_CONSTRAIN_BOUNDS: + SCALE/=10 + + # SCALE Matrix + SCALE_MAT= Blender.Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1]) + + for ob in importedObjects: + ob.setMatrix(ob.matrixWorld*SCALE_MAT) + + # Done constraining to bounds. + + # Select all new objects. + print 'finished importing: "%s" in %.4f sec.' % (filename, (Blender.sys.time()-time1)) + file.close() + Blender.Window.WaitCursor(0) + + +DEBUG= False +if __name__=='__main__' and not DEBUG: + Blender.Window.FileSelector(load_3ds, 'Import 3DS', '*.3ds') + +# For testing compatibility +#load_3ds('/metavr/convert/vehicle/truck_002/TruckTanker1.3DS', False) +#load_3ds('/metavr/archive/convert/old/arranged_3ds_to_hpx-2/only-need-engine-trains/Engine2.3DS', False) +''' + +else: + # DEBUG ONLY + TIME= Blender.sys.time() + import os + print 'Searching for files' + os.system('find /metavr/ -iname "*.3ds" > /tmp/temp3ds_list') + # os.system('find /storage/ -iname "*.3ds" > /tmp/temp3ds_list') + print '...Done' + file= open('/tmp/temp3ds_list', 'r') + lines= file.readlines() + file.close() + # sort by filesize for faster testing + lines_size = [(os.path.getsize(f[:-1]), f[:-1]) for f in lines] + lines_size.sort() + lines = [f[1] for f in lines_size] + + + def between(v,a,b): + if v <= max(a,b) and v >= min(a,b): + return True + return False + + for i, _3ds in enumerate(lines): + if between(i, 650,800): + #_3ds= _3ds[:-1] + print 'Importing', _3ds, '\nNUMBER', i, 'of', len(lines) + _3ds_file= _3ds.split('/')[-1].split('\\')[-1] + newScn= Blender.Scene.New(_3ds_file) + newScn.makeCurrent() + load_3ds(_3ds, False) + + print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME) + +''' \ No newline at end of file diff --git a/release/scripts/Axiscopy.py b/release/scripts/Axiscopy.py new file mode 100644 index 00000000000..6a31432edb6 --- /dev/null +++ b/release/scripts/Axiscopy.py @@ -0,0 +1,125 @@ +#!BPY + +""" Registration info for Blender menus: <- these words are ignored +Name: 'Axis Orientation Copy' +Blender: 242 +Group: 'Object' +Tip: 'Copy local axis orientation of active object to all selected meshes (changes mesh data)' +""" + +__author__ = "A Vanpoucke (xand)" +__url__ = ("blenderartists.org", "www.blender.org", +"French Blender support forum, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender") +__version__ = "2 17/12/05" + +__bpydoc__ = """\ +This script copies the axis orientation -- X, Y and Z rotations -- of the +active object to all selected meshes. + +It's useful to align the orientations of all meshes of a structure, a human +skeleton, for example. + +Usage: + +Select all mesh objects that need to have their orientations changed +(reminder: keep SHIFT pressed after the first, to add each new one to the +selection), then select the object whose orientation will be copied from and +finally run this script to update the angles. + +Notes:
+ This script changes mesh data: the vertices are transformed.
+ Before copying the orientation to each object, the script stores its +transformation matrix. Then the angles are copied and after that the object's +vertices are transformed "back" so that they still have the same positions as +before. In other words, the rotations are updated, but you won't notice that +just from looking at the objects.
+ Checking their X, Y and Z rotation values with "Transform Properties" in +the 3D View's Object menu shows the angles are now the same of the active +object. Or simply look at the transform manipulator handles in local transform +orientation. +""" + + +# $Id$ +# +#---------------------------------------------- +# A Vanpoucke (xand) +#from the previous script realignaxis +#---------------------------------------------- +# Communiquer les problemes et erreurs sur: +# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2003, 2004: A Vanpoucke +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +from Blender import * +from Blender import Mathutils +from Blender.Mathutils import * +import BPyMessages + +def realusers(data): + users = data.users + if data.fakeUser: users -= 1 + return users + + + +def main(): + + scn_obs= Scene.GetCurrent().objects + ob_act = scn_obs.active + scn_obs = scn_obs.context + + if not ob_act: + BPyMessages.Error_NoActive() + + obs = [(ob, ob.getData(mesh=1)) for ob in scn_obs if ob != ob_act] + + for ob, me in obs: + + if ob.type != 'Mesh': + Draw.PupMenu("Error%t|Selection must be made up of mesh objects only") + return + + if realusers(me) != 1: + Draw.PupMenu("Error%t|Meshes must be single user") + return + + if len(obs) < 1: + Draw.PupMenu("Error: you must select at least 2 objects") + return + + result = Draw.PupMenu("Copy axis orientation from: " + ob_act.name + " ?%t|OK") + if result == -1: + return + + for ob_target, me_target in obs: + if ob_act.rot != ob_target.rot: + rot_target = ob_target.matrixWorld.rotationPart().toEuler().toMatrix() + rot_source = ob_act.matrixWorld.rotationPart().toEuler().toMatrix() + rot_source_inv = rot_source.copy().invert() + tx_mat = rot_target * rot_source_inv + tx_mat.resize4x4() + me_target.transform(tx_mat) + ob_target.rot=ob_act.rot + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/release/scripts/DirectX8Exporter.py b/release/scripts/DirectX8Exporter.py new file mode 100644 index 00000000000..3dbd8d9d539 --- /dev/null +++ b/release/scripts/DirectX8Exporter.py @@ -0,0 +1,1167 @@ +#!BPY + +""" +# Name: 'DirectX (.x)...' +# Blender: 242 +# Group: 'Export' +# Tooltip: 'Export to DirectX text file format format for XNA Animation Component Library.' +""" +__author__ = "minahito (original:Arben (Ben) Omari)" +__url__ = ("blender", "elysiun", "Adjuster's site http://sunday-lab.blogspot.com/, Author's site http://www.omariben.too.it") +__version__ = "3.0" + +__bpydoc__ = """\ +This script exports a Blender mesh with armature to DirectX 8's text file +format. + +Notes:
+ Check author's site or the elYsiun forum for a new beta version of the +DX exporter. +""" +# DirectXExporter.py version 3.0 +# Copyright (C) 2006 Arben OMARI -- omariarben@everyday.com +# +# 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. + +# This script export meshes created with Blender in DirectX8 file format +# it exports meshes,armatures,materials,normals,texturecoords and animations + +# Grab the latest version here :www.omariben.too.it + +# [Notice] +# This script is the custom version of Mr.Arben Omari's great work. +# If you have a question about the adjusted part, visit http://sunday-lab.blogspot.com/. + +import Blender +from Blender import Types, Object, NMesh, Material,Armature,Mesh +from Blender.Mathutils import * +from Blender import Draw, BGL +from Blender.BGL import * +import math + +global mat_flip,index_list,space,bone_list,mat_dict +global anim,flip_norm,swap_zy,flip_z,speed,ticks,no_light,recalc_norm,Bl_norm +bone_list =[] +index_list = [] +mat_dict = {} +space = 0;flip_z = 1;anim=0;swap_yz=0;flip_norm=0;speed=0;ticks= 25 +Bl_norm = 1;recalc_norm = 0;no_light = 0 + +toggle_val = 0 +toggle1_val = 0 +toggle2_val = 0 +toggle3_val = 1 +toggle4_val = 0 +toggle5_val = 1 +toggle6_val = 0 +toggle7_val = 0 +anim_tick = Draw.Create(25) + +#*********************************************** +# DirectX file spec only allows letters, digits, and +# underscore in Names. +#*********************************************** +def make_legal_name(starting_name): + new_name = starting_name.replace('.','_') + new_name = new_name.replace(' ','_') + if new_name[0].isdigit(): + new_name = '_' + new_name + return new_name + +#*********************************************** +# MAIN +#*********************************************** + +def my_callback(filename): + if filename.find('.x', -2) <= 0: filename += '.x' + xexport = xExport(filename) + xexport.SelectObjs() + +def my_callback_sel(filename): + if filename.find('.x', -2) <= 0: filename += '.x' + xexport = xExport(filename) + xexport.exportSelMesh() +def event(evt, val): + if evt == Draw.ESCKEY: + Draw.Exit() + return + +def button_event(evt): + global toggle_val,toggle1_val,toggle2_val,toggle3_val,toggle4_val,toggle5_val,toggle6_val,toggle7_val + global flip_z,swap_yz,flip_norm,anim,ticks,speed,no_light,Bl_norm,recalc_norm + arg = __script__['arg'] + if evt == 1: + toggle_val = 1 - toggle_val + anim = toggle_val + Draw.Redraw(1) + if evt == 2: + toggle1_val = 1 - toggle1_val + flip_norm = toggle1_val + Draw.Redraw(1) + if evt == 3: + toggle2_val = 1 - toggle2_val + swap_yz = toggle2_val + Draw.Redraw(1) + if evt == 4: + toggle3_val = 1 - toggle3_val + flip_z = toggle3_val + Draw.Redraw(1) + if evt == 5: + toggle4_val = 1 - toggle4_val + speed = toggle4_val + Draw.Redraw(1) + if evt == 10: + toggle5_val = 1 - toggle5_val + if toggle5_val==1: + toggle6_val = 0 + toggle7_val = 0 + else : + toggle6_val = 1 + toggle7_val = 1 + no_light = toggle7_val + recalc_norm = toggle6_val + Bl_norm = toggle5_val + Draw.Redraw(1) + if evt == 11: + toggle6_val = 1 - toggle6_val + if toggle6_val==1: + toggle5_val = 0 + toggle7_val = 0 + else : + toggle5_val = 1 + toggle7_val = 1 + no_light = toggle7_val + recalc_norm = toggle6_val + Bl_norm = toggle5_val + Draw.Redraw(1) + if evt == 12: + toggle7_val = 1 - toggle7_val + if toggle7_val==1: + toggle6_val = 0 + toggle5_val = 0 + else : + toggle6_val = 1 + toggle5_val = 1 + no_light = toggle7_val + recalc_norm = toggle6_val + Bl_norm = toggle5_val + Draw.Redraw(1) + if evt == 6: + ticks = anim_tick.val + if evt == 7: + fname = Blender.sys.makename(ext = ".x") + Blender.Window.FileSelector(my_callback, "Export DirectX", fname) + if evt == 8: + fname = Blender.sys.makename(ext = ".x") + Blender.Window.FileSelector(my_callback_sel, "Export DirectX", fname) + if evt == 9: + Draw.Exit() + + +def draw(): + global animsg,flipmsg,swapmsg,anim_tick + global flip_z,swap_yz,flip_norm,anim,ticks,speed,recalc_norm,Bl_norm,no_light + glClearColor(0.55,0.6,0.6,1) + glClear(BGL.GL_COLOR_BUFFER_BIT) + #external box + glColor3f(0.2,0.3,0.3) + rect(10,402,300,382) + #-- + #glColor3f(0.3,0.4,0.4) + #rect(11,399,298,398) + #-- + glColor3f(0.5,0.75,0.65) + rect(14,398,292,30) + #-- + glColor3f(0.5,0.75,0.65) + rect(14,366,292,160) + #-- + glColor3f(0.5,0.75,0.65) + rect(14,202,292,60) + #-- + glColor3f(0.5,0.75,0.65) + rect(14,138,292,40) + #-- + glColor3f(0.5,0.75,0.65) + rect(14,94,292,70) + + glColor3f(0.8,.8,0.6) + glRasterPos2i(20, 380) + Draw.Text("DirectX Exporter ",'large') + Draw.Text("(for Blender 2.41)", 'small') + #-------Aniamtion toggle--------------------------------------------- + Draw.Toggle("Anim", 1, 20, 330, 55, 20, toggle_val,"export animations") + if toggle_val : + anim = 1 + animsg = "animation will be exported" + else: + anim = 0 + animsg = "animation will be not exported" + glRasterPos2i(100,335) + Draw.Text(animsg) + #---Flip normals toggle----------------------------------------------- + Draw.Toggle("Flip norm", 2, 20, 300, 55, 20, toggle1_val,"invert normals") + if toggle1_val : + flip_norm = 1 + flipmsg = "flipped normals" + else: + flip_norm = 0 + flipmsg = "not flipped normals" + glRasterPos2i(100,305) + Draw.Text(flipmsg) + #------Swap yz toggle---------------------------------------------------------------- + Draw.Toggle("Swap zy", 3, 20, 270, 55, 20, toggle2_val,"swap z,y axis(y up)") + if toggle2_val : + swap_yz = 1 + swapmsg = "Y-axis up" + else: + swap_yz = 0 + swapmsg = "Z-axis up" + glRasterPos2i(100,275) + Draw.Text(swapmsg) + #------Flip z toggle---------------------------------------------------------------- + Draw.Toggle("Flip z", 4, 20, 240, 55, 20, toggle3_val,"flip z axis") + if toggle3_val : + flip_z = 1 + zmsg = "left handed system" + else: + flip_z = 0 + zmsg = "right handed system" + glRasterPos2i(100,245) + Draw.Text(zmsg) + #------Speed toggle---------------------------------------------------------------- + Draw.Toggle("Speed", 5, 20, 210, 55, 20, toggle4_val,"Animation speed") + if toggle4_val : + speed = 1 + spedmsg = "set speed" + anim_tick = Draw.Number("", 6,200, 210, 85, 20, anim_tick.val,1,100000,"ticks per second") + else: + speed = 0 + spedmsg = "" + glRasterPos2i(100,215) + Draw.Text(spedmsg) + #------Blender Normals toggle---------------------------------------------------------------- + Draw.Toggle("Bl.normals", 10, 20, 105, 75, 25, toggle5_val,"export normals as in Blender") + if toggle5_val : + Bl_norm = 1 + #------Recalculute Normals toggle---------------------------------------------------------------- + Draw.Toggle("recalc.no", 11, 120, 105, 75, 25, toggle6_val,"export recalculated normals") + if toggle6_val : + recalc_norm = 1 + #------Recalculute Normals toggle---------------------------------------------------------------- + Draw.Toggle("no smooth", 12, 220, 105, 75, 25, toggle7_val,"every vertex has the face normal,no smoothing") + if toggle7_val : + no_light = 1 + #------Draw Button export---------------------------------------------------------------- + exp_butt = Draw.Button("Export All",7,20, 155, 75, 30, "export all the scene objects") + sel_butt = Draw.Button("Export Sel",8,120, 155, 75, 30, "export the selected object") + exit_butt = Draw.Button("Exit",9,220, 155, 75, 30, "exit") + glRasterPos2i(20,75) + Draw.Text("(C) 2006 Arben OMARI ") + glRasterPos2i(20,55) + Draw.Text("http://www.omariben.too.it") + glRasterPos2i(20,35) + Draw.Text("aromar@tin.it") + +def rect(x,y,width,height): + glBegin(GL_LINE_LOOP) + glVertex2i(x,y) + glVertex2i(x+width,y) + glVertex2i(x+width,y-height) + glVertex2i(x,y-height) + glEnd() + +def rectFill(x,y,width,height): + glBegin(GL_POLYGON) + glVertex2i(x,y) + glVertex2i(x+width,y) + glVertex2i(x+width,y-height) + glVertex2i(x,y-height) + glEnd() + + + +Draw.Register(draw, event, button_event) + + +#*********************************************** +#*********************************************** +# EXPORTER +#*********************************************** +#*********************************************** + +class xExport: + def __init__(self, filename): + self.file = open(filename, "w") + +#********************************************************************************************************************************************* + #*********************************************** + #Select Scene objects + #*********************************************** + def analyzeScene(self): + parent_list = [] + for obj in Blender.Scene.GetCurrent().objects: + if obj.type in ('Mesh', 'Armature', 'Empty'): + if obj.parent == None : + parent_list.append(obj) + + return parent_list + + def getChildren(self,obj): + obs = Blender.Scene.GetCurrent().objects + return [ ob for ob in obs if ob.parent == obj ] + + def getArmChildren(self,obj): + for ob in Blender.Scene.GetCurrent().objects: #Object.Get(): + if ob.parent == obj : + return ob + + def getLocMat(self, obj): + pare = obj.parent + mat = obj.matrixWorld + mat_id = Matrix([1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]) + if pare: + mat_p = pare.matrixWorld + mat_c = Matrix(mat_p) + mat_c.invert() + mat_f = mat * mat_c + else : + mat_id.invert() + mat_f = mat * mat_id + return mat_f + + def writeObjFrames(self,obj): + global space,chld_obj,ch_list + mesh = obj.getData() + if obj.type == "Empty" : + mat = self.getLocMat(obj) + mat_c = Matrix(mat) + self.writeArmFrames(mat_c, make_legal_name(obj.name)) + if type(mesh) == Types.ArmatureType : + Child_obj = self.getArmChildren(obj) + chld_obj = obj + ch_list.append(Child_obj) + self.writeRootBone(obj, Child_obj) + if obj.type == 'Mesh' and obj not in ch_list: + self.exportMesh(obj) + + + def writeChildObj(self,obj): + global space,ch_list + space += 1 + if obj : + for ob in obj: + if ob not in ch_list: + self.writeObjFrames(ob) + ch_list.append(ob) + ch_ob = self.getChildren(ob) + self.writeChildObj(ch_ob) + self.closeBrackets() + self.file.write(" // End of the Object %s \n" % (ob.name)) + + + def writeRootFrame(self): + global flip_z,swap_yz,speed + if speed: + self.writeAnimTicks() + if flip_z: + mat_flip = Matrix([1, 0, 0, 0], [0, 1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]) + else : + mat_flip = Matrix([1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]) + if swap_yz : + mat_rot = RotationMatrix(-90, 4, 'x') + mat_flip = mat_rot * mat_flip + self.writeArmFrames(mat_flip, "RootFrame") + + ################################################################## + def SelectObjs(self): + global space,chld_obj,ch_list,flip_z,swap_yz,speed + print "exporting..." + self.writeHeader() + self.writeRootFrame() + obj_list = self.analyzeScene() + space += 1 + ch_list = [] + for obj in obj_list: + self.writeObjFrames(obj) + ch_l = self.getChildren(obj) + for ch in ch_l: + + + if ch and ch.type == "Armature": + ch_list.append(ch) + self.writeObjFrames(ch) + else : + self.writeChildObj(ch_l) + if obj.type != "Armature": + self.file.write(" } // SI End of the Object %s \n" % (obj.name)) + + + + self.file.write("} // End of the Root Frame\n") + if anim : + self.file.write("AnimationSet AnimationSet0 {\n") + for obj in Blender.Scene.GetCurrent().objects: + if obj.type in ('Mesh', 'Empty'): + ip_list = obj.ipo + if ip_list != None : + self.writeAnimationObj(obj) + elif obj.type == 'Armature': + act_list = obj.getAction() + if act_list != None : + self.writeAnimation(obj) + #ip_list = obj.ipo + #if ip_list != None : + # self.writeAnimationObj(obj) + + self.file.write("} // End of Animation Set\n") + self.writeEnd() + ####################################################### + + + def writeAnimTicks(self): + global ticks + self.file.write("AnimTicksPerSecond {\n") + self.file.write("%d; \n" % (ticks)) + self.file.write("}\n") + + #*********************************************** + #Export Mesh without Armature + #*********************************************** + def exportMesh(self, obj): + tex = [] + mesh = obj.getData() + self.writeTextures(obj, tex) + self.writeMeshcoordArm(obj, arm_ob = None) + self.writeMeshMaterialList(obj, mesh, tex) + self.writeMeshNormals(obj, mesh) + self.writeMeshTextureCoords(obj, mesh) + self.file.write(" } // End of the Mesh %s \n" % (obj.name)) + + + #*********************************************** + #Export the Selected Mesh + #*********************************************** + def exportSelMesh(self): + print "exporting ..." + self.writeHeader() + self.writeRootFrame() + tex = [] + objs = Object.GetSelected() + for obj in objs: + if obj.type == 'Mesh': + mesh = obj.data + self.writeTextures(obj, tex) + self.writeMeshcoordArm(obj, arm_ob = None) + self.writeMeshMaterialList(obj, mesh, tex) + self.writeMeshNormals(obj, mesh) + self.writeMeshTextureCoords(obj, mesh) + self.file.write(" }\n") + self.file.write("}\n") + ind = objs.index(obj) + if ind == len(objs)-1: + self.file.write("}\n") + ip_list = obj.ipo + if ip_list != None : + self.file.write("AnimationSet AnimationSet0 {\n") + self.writeAnimationObj(obj) + self.file.write("}\n") + else : + print "The selected object is not a mesh" + print "...finished" + #*********************************************** + #Export Mesh with Armature + #*********************************************** + def exportMeshArm(self,arm,arm_ob,ch_obj): + tex = [] + mesh = ch_obj.getData() + self.writeTextures(ch_obj, tex) + self.writeMeshcoordArm(ch_obj ,arm_ob) + self.writeMeshMaterialList(ch_obj, mesh, tex) + self.writeMeshNormals(ch_obj, mesh) + self.writeMeshTextureCoords(ch_obj, mesh) + self.writeSkinWeights(arm,mesh) + #self.file.write(" } // End of the Frame %s \n" % (ch_obj.name)) + self.file.write(" } // End of the Object %s \n" % (ch_obj.name)) + + #*********************************************** + #Export Root Bone + #*********************************************** + def writeRootBone(self, chld_obj, child_obj): + global space,root_bon + arms = chld_obj.getData() + mat_arm = self.getLocMat(chld_obj) + for bon in arms.bones.values(): + if bon.hasParent(): + pass + else: + root_bon = bon + space += 1 + mat_r = self.writeAnimCombineMatrix(root_bon,1) + self.writeArmFrames(mat_r, make_legal_name(root_bon.name)) + + bon_c = root_bon.children + self.writeChildren(bon_c) + self.file.write(" } // End of the Bone %s \n" % (root_bon.name)) + self.exportMeshArm(arms, chld_obj ,child_obj) + + #*********************************************** + #Create Children structure + #*********************************************** + def writeBon(self,bon): + global space + mat_r = self.writeAnimCombineMatrix(bon,1) + self.writeArmFrames(mat_r, make_legal_name(bon.name)) + + + def writeChildren(self,bon_c): + global space,bone_list + space += 1 + if bon_c: + for bo in bon_c: + if bo.name not in bone_list: + self.writeBon(bo) + bone_list.append(bo.name) + bo_c = bo.children + self.writeChildren(bo_c) + self.closeBrackets() + + + + def closeBrackets(self): + global space + space = space-1 + tab = " " + self.file.write("%s" % (tab * space)) + self.file.write("}\n") + + + + #*********************************************** + #Offset Matrix + #*********************************************** + def writeMatrixOffset(self,bon): + global chld_obj + Blender.Set('curframe', 1) + pose = chld_obj.getPose() + pos_b = pose.bones[bon.name] + mat_b = pos_b.poseMatrix + mat_c = Matrix(mat_b) + mat_c.invert() + return mat_c + + + #*********************************************** + #Combine Matrix + #*********************************************** + def writeCombineMatrix(self,bon): + global chld_obj + + Blender.Set('curframe', 1) + pose = chld_obj.getPose() + pos_b = pose.bones[bon.name] + mat_b = pos_b.poseMatrix + if bon.hasParent(): + pare = bon.parent + pos_p = pose.bones[pare.name] + mat_p = pos_p.poseMatrix + + else: + mat_p = Matrix([1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]) + mat_c = Matrix(mat_p) + mat_c.invert() + mat_f = mat_b * mat_c + + return mat_f + #*********************************************** + #Combine Matrix + #*********************************************** + def writeAnimCombineMatrix(self,bon,fre): + global chld_obj + Blender.Set('curframe', fre) + pose = chld_obj.getPose() + pos_b = pose.bones[bon.name] + mat_b = pos_b.poseMatrix + if bon.hasParent(): + pare = bon.parent + pos_p = pose.bones[pare.name] + mat_p = pos_p.poseMatrix + + else: + mat_p = Matrix([1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]) + mat_c = Matrix(mat_p) + mat_c.invert() + mat_f = mat_b * mat_c + + return mat_f + + +#********************************************************************************************************************************************* + #*********************************************** + #Write SkinWeights + #*********************************************** + def writeSkinWeights(self, arm, mesh): + global index_list + v_dict = {} + Blender.Set('curframe',1) + self.file.write(" XSkinMeshHeader {\n") + max_infl = 0 + for bo in arm.bones.values() : + name = bo.name + try : + vertx_list = mesh.getVertsFromGroup(name,1) + for inde in vertx_list : + vert_infl = mesh.getVertexInfluences(inde[0]) + ln_infl = len(vert_infl) + if ln_infl > max_infl : + max_infl = ln_infl + + except: + pass + + self.file.write(" %d; \n" % (max_infl)) + self.file.write(" %d; \n" % (max_infl * 3)) + self.file.write(" %d; \n" % (len(arm.bones.values()))) + self.file.write(" }\n") + + for bo in arm.bones.values() : + bo_list = [] + weight_list = [] + name = bo.name + f_name = make_legal_name(name) + try : + vert_list = mesh.getVertsFromGroup(name,1) + le = 0 + for indx in vert_list: + ver_infl = mesh.getVertexInfluences(indx[0]) + infl = 0.0 + if len(ver_infl) != 0: + sum = 0.0 + for bone_n, weight in ver_infl: + if bone_n == name: + infl = weight + sum += weight + infl /= sum + + i = -1 + for el in index_list : + i += 1 + if el == indx[0] : + le +=1 + bo_list.append(i) + weight_list.append(infl) + + + self.file.write(" SkinWeights {\n") + self.file.write(' "%s"; \n' % (f_name)) + self.file.write(' %d; \n' % (le)) + count = 0 + for ind in bo_list : + count += 1 + if count == len(bo_list): + self.file.write(" %d; \n" % (ind)) + else : + self.file.write(" %d, \n" % (ind)) + cou = 0 + for wegh in weight_list : + cou += 1 + + if cou == len(weight_list): + self.file.write(" %f; \n" % (round(wegh,6))) + else : + self.file.write(" %f, \n" % (round(wegh,6))) + + + matx = self.writeMatrixOffset(bo) + self.writeOffsFrames(matx, name) + except : + pass + self.file.write(" } // End of XSkinMeshHeader\n") + + + #*********************************************** + # Write Matrices + #*********************************************** + def writeArmFrames(self, matx, name): + global space + tab = " " + self.file.write("%s" % (tab * space)) + self.file.write("Frame ") + self.file.write("%s {\n\n" % (name)) + self.file.write("%s" % (tab * space)) + self.file.write(" FrameTransformMatrix {\n") + self.writeFrame(matx) + + #*********************************************** + # Write Frames + #*********************************************** + def writeOffsFrames(self, matx, name): + space = 1 + self.writeFrame(matx) + + #*********************************************** + # Write Frames + #*********************************************** + def writeFrame(self, matx): + tab = " " + self.file.write("%s" % (tab * space)) + self.file.write(" %f,%f,%f,%f,\n" % + (round(matx[0][0],4),round(matx[0][1],4),round(matx[0][2],4),round(matx[0][3],4))) + self.file.write("%s" % (tab * space)) + self.file.write(" %f,%f,%f,%f,\n" % + (round(matx[1][0],4),round(matx[1][1],4),round(matx[1][2],4),round(matx[1][3],4))) + self.file.write("%s" % (tab * space)) + self.file.write(" %f,%f,%f,%f,\n" % + (round(matx[2][0],4),round(matx[2][1],4),round(matx[2][2],4),round(matx[2][3],4))) + self.file.write("%s" % (tab * space)) + self.file.write(" %f,%f,%f,%f;;\n" % + (round(matx[3][0],4),round(matx[3][1],4),round(matx[3][2],4),round(matx[3][3],4))) + self.file.write("%s" % (tab * space)) + self.file.write(" }\n") +#********************************************************************************************************************************************* + + #*********************************************** + #HEADER + #*********************************************** + def writeHeader(self): + self.file.write("xof 0303txt 0032\n\n\n") + self.file.write("template VertexDuplicationIndices { \n\ + \n\ + DWORD nIndices;\n\ + DWORD nOriginalVertices;\n\ + array DWORD indices[nIndices];\n\ +}\n\ +template XSkinMeshHeader {\n\ + <3cf169ce-ff7c-44ab-93c0-f78f62d172e2>\n\ + WORD nMaxSkinWeightsPerVertex;\n\ + WORD nMaxSkinWeightsPerFace;\n\ + WORD nBones;\n\ +}\n\ +template SkinWeights {\n\ + <6f0d123b-bad2-4167-a0d0-80224f25fabb>\n\ + STRING transformNodeName;\n\ + DWORD nWeights;\n\ + array DWORD vertexIndices[nWeights];\n\ + array float weights[nWeights];\n\ + Matrix4x4 matrixOffset;\n\ +}\n\n") + + #*********************************************** + #CLOSE FILE + #*********************************************** + def writeEnd(self): + self.file.close() + print "... finished" + + + #*********************************************** + #EXPORT TEXTURES + #*********************************************** + def writeTextures(self,name, tex): + mesh = name.data + for face in mesh.faces: + if face.image and face.image.name not in tex: + tex.append(face.image.name) + + + + #*********************************************** + #EXPORT MESH DATA with Armature + #*********************************************** + def writeMeshcoordArm(self, obj ,arm_ob): + global index_list,flip_z + #TransformMatrix + mat = self.getLocMat(obj) + self.writeArmFrames(mat, make_legal_name(obj.name)) + mesh = NMesh.GetRawFromObject(obj.name) + self.file.write("Mesh {\n") + numface=len(mesh.faces) + #VERTICES NUMBER + numvert = 0 + for face in mesh.faces: + numvert = numvert + len(face.v) + self.file.write("%d;\n" % (numvert)) + if numvert == 0: + print "Mesh named",mesh.name,"has no vertices.Problems may occur using the .x file" + #VERTICES COORDINATES + counter = 0 + for face in mesh.faces: + counter += 1 + for n in range(len(face.v)): + index_list.append(face.v[n].index) + vec_vert = Vector([(face.v[n].co[0]), face.v[n].co[1], face.v[n].co[2], 1]) + if arm_ob : + f_vec_vert = vec_vert * mat + else : + f_vec_vert = vec_vert + self.file.write("%f; %f; %f;" % (round(f_vec_vert[0],4), round(f_vec_vert[1],4), round(f_vec_vert[2],4))) + if counter == numface : + if n == len(face.v)-1 : + self.file.write(";\n") + else : + self.file.write(",\n") + else : + self.file.write(",\n") + if flip_z: + a3 = 0;b3 = 2;c3 = 1 + a4 = 0;b4 = 3;c4 = 2;d4 = 1 + else: + a3 = 0;b3 = 1;c3 = 2 + a4 = 0;b4 = 1;c4 = 2;d4 = 3 + + #FACES NUMBER + self.file.write("%s;\n" % (numface)) + coun,counter = 0, 0 + for face in mesh.faces : + coun += 1 + separator = ',' + if coun == numface: + separator = ';' + if len(face.v) == 3: + self.file.write("3; %d, %d, %d;%c\n" % (counter + a3, counter + b3, counter + c3, separator)) + counter += 3 + elif len(face.v) == 4: + self.file.write("4; %d, %d, %d, %d;%c\n" % (counter + a4, counter + b4, counter + c4, counter + d4, separator)) + counter += 4 + elif len(face.v) < 3: + print "WARNING:the mesh has faces with less then 3 vertices" + print " It my be not exported correctly." + + + #*********************************************** + #MESH MATERIAL LIST + #*********************************************** + def writeMeshMaterialList(self, obj, mesh, tex): + self.file.write(" MeshMaterialList {\n") + #HOW MANY MATERIALS ARE USED + count = 0 + for mat in mesh.getMaterials(): + count+=1 + self.file.write(" %d;\n" % (len(tex) + count)) + #HOW MANY FACES IT HAS + numfaces=len(mesh.faces) + self.file.write(" %d;\n" % (numfaces)) + ##MATERIALS INDEX FOR EVERY FACE + counter = 0 + for face in mesh.faces : + counter += 1 + mater = face.materialIndex + if counter == numfaces: + if face.image and face.image.name in tex : + self.file.write(" %d;;\n" % (tex.index(face.image.name) + count)) + else : + self.file.write(" %d;;\n" % (mater)) + else : + if face.image and face.image.name in tex : + self.file.write(" %d,\n" % (tex.index(face.image.name) + count)) + else : + self.file.write(" %d,\n" % (mater)) + + ##MATERIAL NAME + for mat in mesh.getMaterials(): + self.file.write(" Material") + self.file.write(" %s "% (make_legal_name(mat.name))) + self.file.write("{\n") + self.file.write(" %f; %f; %f;" % (mat.R, mat.G, mat.B)) + self.file.write("%s;;\n" % (mat.alpha)) + self.file.write(" %f;\n" % (mat.spec)) + self.file.write(" %f; %f; %f;;\n" % (mat.specR, mat.specG, mat.specB)) + self.file.write(" 0.0; 0.0; 0.0;;\n") + self.file.write(" } //End of Material\n") + + for mat in tex: + self.file.write(" Material Mat") + self.file.write("%s "% (len(tex))) + self.file.write("{\n") + self.file.write(" 1.0; 1.0; 1.0; 1.0;;\n") + self.file.write(" 1.0;\n") + self.file.write(" 1.0; 1.0; 1.0;;\n") + self.file.write(" 0.0; 0.0; 0.0;;\n") + self.file.write(" TextureFilename {") + self.file.write(' "%s";'% (mat)) + self.file.write(" }\n") + self.file.write(" } // End of Material\n") + self.file.write(" } //End of MeshMaterialList\n") + + #*********************************************** + #MESH NORMALS + #*********************************************** + def writeMeshNormals(self,name,mesh): + global flip_norm,flip_z,no_light,recalc_norm,Bl_norm + + self.file.write(" MeshNormals {\n") + #VERTICES NUMBER + numvert = 0 + for face in mesh.faces: + numvert = numvert + len(face.v) + self.file.write("%d;\n" % (numvert)) + numfaces=len(mesh.faces) + if flip_norm : + fl = -1 + else : + fl = 1 + #VERTICES NORMAL + if Bl_norm: + self.writeBlenderNormals(mesh,fl) + if recalc_norm: + self.writeRecalcNormals(mesh,fl) + if no_light: + self.writeNoSmothing(mesh,fl) + + + + if flip_z: + a3 = 0;b3 = 2;c3 = 1 + a4 = 0;b4 = 3;c4 = 2;d4 = 1 + else: + a3 = 0;b3 = 1;c3 = 2 + a4 = 0;b4 = 1;c4 = 2;d4 = 3 + + #FACES NUMBER + self.file.write("%s;\n" % (numfaces)) + coun,counter = 0, 0 + for face in mesh.faces : + coun += 1 + if coun == numfaces: + if len(face.v) == 3: + self.file.write("3; %d, %d, %d;;\n" % (counter + a3, counter + b3, counter + c3)) + counter += 3 + else : + self.file.write("4; %d, %d, %d, %d;;\n" % (counter + a4, counter + b4, counter + c4, counter + d4)) + counter += 4 + else: + + if len(face.v) == 3: + self.file.write("3; %d, %d, %d;,\n" % (counter + a3, counter + b3, counter + c3)) + counter += 3 + else : + self.file.write("4; %d, %d, %d, %d;,\n" % (counter + a4, counter + b4, counter + c4, counter + d4)) + counter += 4 + self.file.write("} //End of MeshNormals\n") + + def writeBlenderNormals(self,mesh,fl): + numfaces=len(mesh.faces) + #VERTICES NORMAL + counter = 0 + for face in mesh.faces: + counter += 1 + for n in range(len(face.v)): + self.file.write(" %f; %f; %f;" % ( + (round(face.v[n].no[0],6)*fl),(round(face.v[n].no[1],6)*fl),(round(face.v[n].no[2],6)*fl))) + if counter == numfaces : + if n == len(face.v)-1 : + self.file.write(";\n") + else : + self.file.write(",\n") + else : + self.file.write(",\n") + + def writeRecalcNormals(self,mesh,fl): + numfaces=len(mesh.faces) + normal_list = {} + idx = 0 + for vertex in mesh.verts: + v_norm = Vector([0, 0, 0]) + normal_list[idx] = v_norm + idx += 1 + for face in mesh.faces: + for verts in face.v: + if verts.index == vertex.index : + v_norm[0] += face.no[0] + v_norm[1] += face.no[1] + v_norm[2] += face.no[2] + + v_norm.normalize() + + counter = 0 + for face in mesh.faces: + counter += 1 + n = 0 + for vert in face.v: + n += 1 + norm = normal_list[vert.index] + + self.file.write(" %f; %f; %f;" % ( + (round(norm[0],6)*fl),(round(norm[1],6)*fl),(round(norm[2],6)*fl))) + if counter == numfaces : + if n == len(face.v) : + self.file.write(";\n") + else : + self.file.write(",\n") + else : + self.file.write(",\n") + + def writeNoSmothing(self,mesh,fl): + numfaces=len(mesh.faces) + counter = 0 + for face in mesh.faces: + counter += 1 + n = 0 + for n in range(len(face.v)): + n += 1 + self.file.write(" %f; %f; %f;" % ( + (round(face.no[0],6)*fl),(round(face.no[1],6)*fl),(round(face.no[2],6)*fl))) + + + if counter == numfaces : + if n == len(face.v) : + self.file.write(";\n") + else : + self.file.write(",\n") + else : + self.file.write(",\n") + #*********************************************** + #MESH TEXTURE COORDS + #*********************************************** + def writeMeshTextureCoords(self, name, mesh): + if mesh.hasFaceUV(): + self.file.write("MeshTextureCoords {\n") + #VERTICES NUMBER + numvert = 0 + for face in mesh.faces: + numvert += len(face.v) + self.file.write("%d;\n" % (numvert)) + #UV COORDS + numfaces = len(mesh.faces) + counter = -1 + co = 0 + for face in mesh.faces: + counter += 1 + co += 1 + for n in range(len(face.v)): + self.file.write("%f;%f;" % (mesh.faces[counter].uv[n][0], -mesh.faces[counter].uv[n][1])) + if co == numfaces : + if n == len(face.v) - 1 : + self.file.write(";\n") + else : + self.file.write(",\n") + else : + self.file.write(",\n") + + self.file.write("} //End of MeshTextureCoords\n") +#***********************************************#***********************************************#*********************************************** + #*********************************************** + #FRAMES + #*********************************************** + def writeFrames(self, matx): + + self.file.write("%f,%f,%f,%f," % + (round(matx[0][0],4),round(matx[0][1],4),round(matx[0][2],4),round(matx[0][3],4))) + self.file.write("%f,%f,%f,%f," % + (round(matx[1][0],4),round(matx[1][1],4),round(matx[1][2],4),round(matx[1][3],4))) + self.file.write("%f,%f,%f,%f," % + (round(matx[2][0],4),round(matx[2][1],4),round(matx[2][2],4),round(matx[2][3],4))) + self.file.write("%f,%f,%f,%f;;" % + (round(matx[3][0],4),round(matx[3][1],4),round(matx[3][2],4),round(matx[3][3],4))) + + + + + + #*********************************************** + #WRITE ANIMATION KEYS + #*********************************************** + def writeAnimation(self,arm_ob): + global mat_dict, root_bon + arm = arm_ob.getData() + act_list = arm_ob.getAction() + ip = act_list.getAllChannelIpos() + for bon in arm.bones.values() : + point_list = [] + name = bon.name + name_f = make_legal_name(name) + try : + ip_bon_channel = ip[bon.name] + ip_bon_name = ip_bon_channel.getName() + + ip_bon = Blender.Ipo.Get(ip_bon_name) + poi = ip_bon.getCurves() + + for po in poi[3].getPoints(): + a = po.getPoints() + point_list.append(int(a[0])) + #point_list.pop(0) + + self.file.write(" Animation { \n") + self.file.write(" { %s }\n" %(name_f)) + self.file.write(" AnimationKey { \n") + self.file.write(" 4;\n") + self.file.write(" %d; \n" % (len(point_list))) + + for fr in point_list: + + if name == root_bon.name : + + + mat_b = self.writeAnimCombineMatrix(bon,fr) + mat_arm = self.getLocMat(arm_ob) + mat = mat_b * mat_arm + else: + mat = self.writeAnimCombineMatrix(bon,fr) + + self.file.write(" %d;" % (fr)) + self.file.write("16;") + + self.writeFrames(mat) + + if fr == point_list[len(point_list)-1]: + self.file.write(";\n") + else: + self.file.write(",\n") + self.file.write(" }\n") + self.file.write(" }\n") + self.file.write("\n") + except: + pass + + + + #*********************************************** + #WRITE ANIMATION KEYS + #*********************************************** + def writeAnimationObj(self, obj): + point_list = [] + ip = obj.ipo + poi = ip.getCurves() + for po in poi[0].getPoints(): + a = po.getPoints() + point_list.append(int(a[0])) + + self.file.write(" Animation {\n") + self.file.write(" { ") + self.file.write("%s }\n" % (make_legal_name(obj.name))) + self.file.write(" AnimationKey { \n") + self.file.write(" 4;\n") + self.file.write(" %d; \n" % (len(point_list))) + for fr in point_list: + self.file.write(" %d;" % (fr)) + self.file.write("16;") + Blender.Set('curframe',fr) + + #mat_new = self.getLocMat(obj) + mat_new = obj.matrixLocal + self.writeFrames(mat_new) + + if fr == point_list[len(point_list)-1]: + self.file.write(";\n") + else: + self.file.write(",\n") + self.file.write(" }\n") + self.file.write(" }\n") + + + +#***********************************************#***********************************************#*********************************************** + + + + + diff --git a/release/scripts/DirectX8Importer.py b/release/scripts/DirectX8Importer.py new file mode 100644 index 00000000000..0dda654944d --- /dev/null +++ b/release/scripts/DirectX8Importer.py @@ -0,0 +1,238 @@ +#!BPY + +""" Registration info for Blender menus: +Name: 'DirectX(.x)...' +Blender: 244 +Group: 'Import' + +Tip: 'Import from DirectX text file format format.' +""" +# DirectXImporter.py version 1.2 +# Copyright (C) 2005 Arben OMARI -- omariarben@everyday.com +# +# 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. + +# This script import meshes from DirectX text file format + +# Grab the latest version here :www.omariben.too.it +import bpy +import Blender +from Blender import Mesh,Object,Material,Texture,Image,Draw + + +class xImport: + def __init__(self, filename): + global my_path + self.file = open(filename, "r") + my_path = Blender.sys.dirname(filename) + + # + self.lines = [l_split for l in self.file.readlines() for l_split in (' '.join(l.split()),) if l_split] + + def Import(self): + lines = self.lines + print "importing into Blender ..." + scene = bpy.data.scenes.active + + mesh_indicies = {} # the index of each 'Mesh' is used as the key for those meshes indicies + context_indicies = None # will raise an error if used! + + + #Get the line of Texture Coords + nr_uv_ind = 0 + + #Get Materials + nr_fac_mat = 0 + i = -1 + mat_list = [] + tex_list = [] + mesh_line_indicies = [] + for j, line in enumerate(lines): + l = line.strip() + words = line.split() + if words[0] == "Material" : + #context_indicies["Material"] = j + self.loadMaterials(j, mat_list, tex_list) + elif words[0] == "MeshTextureCoords" : + context_indicies["MeshTextureCoords"] = j + #nr_uv_ind = j + elif words[0] == "MeshMaterialList" : + context_indicies["MeshMaterialList"] = j+2 + #nr_fac_mat = j + 2 + elif words[0] == "Mesh": # Avoid a second loop + context_indicies = mesh_indicies[j] = {'MeshTextureCoords':0, 'MeshMaterialList':0} + + for mesh_index, value in mesh_indicies.iteritems(): + mesh = Mesh.New() + self.loadVertices(mesh_index, mesh, value['MeshTextureCoords'], value['MeshMaterialList'], tex_list) + + mesh.materials = mat_list[:16] + if value['MeshMaterialList']: + self.loadMeshMaterials(value['MeshMaterialList'], mesh) + scene.objects.new(mesh) + + self.file.close() + print "... finished" + + #------------------------------------------------------------------------------ + # CREATE THE MESH + #------------------------------------------------------------------------------ + def loadVertices(self, nr_vr_ind, mesh, nr_uv, nr_fac_mat, tex_list): + v_ind = nr_vr_ind + 1 + lin = self.lines[v_ind] + if lin : + lin_c = self.CleanLine(lin) + nr_vert = int((lin_c.split()[0])) + else : + v_ind = nr_vr_ind + 2 + lin = self.lines[v_ind] + lin_c = self.CleanLine(lin) + nr_vert = int((lin_c.split()[0])) + + #-------------------------------------------------- + nr_fac_li = v_ind + nr_vert +1 + lin_f = self.lines[nr_fac_li] + if lin_f : + lin_fc = self.CleanLine(lin_f) + nr_face = int((lin_fc.split()[0])) + else : + nr_fac_li = v_ind + nr_vert +1 + lin_f = self.lines[nr_fac_li] + lin_fc = self.CleanLine(lin_f) + nr_face = int((lin_fc.split()[0])) + + #Get Coordinates + verts_list = [(0,0,0)] # WARNING - DUMMY VERT - solves EEKADOODLE ERROR + for l in xrange(v_ind + 1, (v_ind + nr_vert +1)): + line_v = self.lines[l] + lin_v = self.CleanLine(line_v) + words = lin_v.split() + if len(words)==3: + verts_list.append((float(words[0]),float(words[1]),float(words[2]))) + + mesh.verts.extend(verts_list) + del verts_list + + face_list = [] + #Make Faces + i = 0 + mesh_verts = mesh.verts + for f in xrange(nr_fac_li + 1, (nr_fac_li + nr_face + 1)): + i += 1 + line_f = self.lines[f] + lin_f = self.CleanLine(line_f) + + # +1 for dummy vert only! + words = lin_f.split() + if len(words) == 5: + face_list.append((1+int(words[1]), 1+int(words[2]), 1+int(words[3]), 1+int(words[4]))) + elif len(words) == 4: + face_list.append((1+int(words[1]), 1+int(words[2]), 1+int(words[3]))) + + mesh.faces.extend(face_list) + del face_list + + if nr_uv : + mesh.faceUV = True + for f in mesh.faces: + fuv = f.uv + for ii, v in enumerate(f): + # _u, _v = self.CleanLine(self.lines[nr_uv + 2 + v.index]).split() + + # Use a dummy vert + _u, _v = self.CleanLine(self.lines[nr_uv + 1 + v.index]).split() + + fuv[ii].x = float(_u) + fuv[ii].y = float(_v) + + if nr_fac_mat : + fac_line = self.lines[nr_fac_mat + i] + fixed_fac = self.CleanLine(fac_line) + w_tex = int(fixed_fac.split()[0]) + f.image = tex_list[w_tex] + + # remove dummy vert + mesh.verts.delete([0,]) + + def CleanLine(self,line): + return line.replace(\ + ";", " ").replace(\ + '"', ' ').replace(\ + "{", " ").replace(\ + "}", " ").replace(\ + ",", " ").replace(\ + "'", " ") + + #------------------------------------------------------------------ + # CREATE MATERIALS + #------------------------------------------------------------------ + def loadMaterials(self, nr_mat, mat_list, tex_list): + + def load_image(name): + try: + return Image.Load(Blender.sys.join(my_path,name)) + except: + return None + + mat = bpy.data.materials.new() + line = self.lines[nr_mat + 1] + fixed_line = self.CleanLine(line) + words = fixed_line.split() + mat.rgbCol = [float(words[0]),float(words[1]),float(words[2])] + mat.setAlpha(float(words[3])) + mat_list.append(mat) + l = self.lines[nr_mat + 5] + fix_3_line = self.CleanLine(l) + tex_n = fix_3_line.split() + + if tex_n and tex_n[0] == "TextureFilename" : + + if len(tex_n) > 1: + tex_list.append(load_image(tex_n[1])) + + if len(tex_n) <= 1 : + + l_succ = self.lines[nr_mat + 6] + fix_3_succ = self.CleanLine(l_succ) + tex_n_succ = fix_3_succ.split() + tex_list.append(load_image(tex_n_succ[0])) + else : + tex_list.append(None) # no texture for this index + + return mat_list, tex_list + #------------------------------------------------------------------ + # SET MATERIALS + #------------------------------------------------------------------ + def loadMeshMaterials(self, nr_fc_mat, mesh): + for face in mesh.faces: + nr_fc_mat += 1 + line = self.lines[nr_fc_mat] + fixed_line = self.CleanLine(line) + wrd = fixed_line.split() + mat_idx = int(wrd[0]) + face.mat = mat_idx + +#------------------------------------------------------------------ +# MAIN +#------------------------------------------------------------------ +def my_callback(filename): + if not filename.lower().endswith('.x'): print "Not an .x file" + ximport = xImport(filename) + ximport.Import() + +arg = __script__['arg'] + +if __name__ == '__main__': + Blender.Window.FileSelector(my_callback, "Import DirectX", "*.x") + +#my_callback('/fe/x/directxterrain.x') +#my_callback('/fe/x/Male_Normal_MAX.X') +#my_callback('/fe/x/male_ms3d.x') diff --git a/release/scripts/IDPropBrowser.py b/release/scripts/IDPropBrowser.py new file mode 100644 index 00000000000..2a14760270a --- /dev/null +++ b/release/scripts/IDPropBrowser.py @@ -0,0 +1,523 @@ +#!BPY + +""" +Name: 'ID Property Browser' +Blender: 242 +Group: 'Help' +Tooltip: 'Browse ID properties' +""" + +__author__ = "Joe Eagar" +__version__ = "0.3.108" +__email__ = "joeedh@gmail.com" +__bpydoc__ = """\ + +Allows browsing, creating and editing of ID Properties +for various ID block types such as mesh, scene, object, +etc. +""" + +# -------------------------------------------------------------------------- +# ID Property Browser. +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +from Blender import * +from Blender.BGL import * +from Blender.Types import IDGroupType, IDArrayType +import Blender + +def IsInRectWH(mx, my, x, y, wid, hgt): + if mx >= x and mx <= x + wid: + if my >= y and my <= y + hgt: + return 1 + return 0 + +Button_Back = 1 +Button_New = 2 +Button_MatMenu = 3 +Button_TypeMenu = 4 + +ButStart = 55 + +IDP_String = 0 +IDP_Int = 1 +IDP_Float = 2 +IDP_Array = 5 +IDP_Group = 6 + +ButDelStart = 255 +#max limit for string input button +strmax = 100 + +State_Normal = 0 +State_InArray = 1 + +#IDTypeModules entries are of form [module, active_object_index, module_name] +IDTypeModules = [[Scene, 0, "Scenes"], [Object, 0, "Objects"], [Mesh, 0, "Meshes"]] +IDTypeModules += [[Material, 0, "Materials"], [Texture, 0, "Textures"]] +IDTypeModules += [[Image, 0, "Images"]] + +class IDArrayBrowser: + array = 0 + parentbrowser = 0 + buts = 0 + + def __init__(self): + self.buts = [] + + def Draw(self): + pb = self.parentbrowser + x = pb.x + y = pb.y + width = pb.width + height = pb.height + pad = pb.pad + itemhgt = pb.itemhgt + cellwid = 65 + y = y + height - itemhgt - pad + + Draw.PushButton("Back", Button_Back, x, y, 40, 20) + y -= itemhgt + pad + + self.buts = [] + Draw.BeginAlign() + for i in xrange(len(self.array)): + st = "" + if type(self.array[0]) == float: + st = "%.5f" % self.array[i] + else: st = str(self.array[i]) + + b = Draw.String("", ButStart+i, x, y, cellwid, itemhgt, st, 30) + self.buts.append(b) + x += cellwid + pad + if x + cellwid + pad > width: + x = 0 + y -= itemhgt + pad + Draw.EndAlign() + def Button(self, bval): + if bval == Button_Back: + self.parentbrowser.state = State_Normal + self.parentbrowser.array = 0 + self.buts = [] + Draw.Draw() + self.array = 0 + elif bval >= ButStart: + i = bval - ButStart + st = self.buts[i].val + n = 0 + if type(self.array[0]) == float: + try: + n = int(st) + except: + return + elif type(self.array[0]) == int: + try: + n = float(st) + except: + return + + self.array[i] = n + Draw.Draw() + + def Evt(self, evt, val): + if evt == Draw.ESCKEY: + Draw.Exit() + +class IDPropertyBrowser: + width = 0 + height = 0 + x = 0 + y = 0 + scrollx = 0 + scrolly = 0 + itemhgt = 22 + pad = 2 + + group = 0 + parents = 0 #list stack of parent groups + active_item = -1 + mousecursor = 0 + _i = 0 + buts = [] + + state = 0 + array = 0 + prop = 0 + + IDList = 0 + idindex = 0 + idblock = 0 + + type = 0 # attach buildin type() method to class + # since oddly it's not available to button + # callbacks! EEK! :( + + def __init__(self, idgroup, mat, x, y, wid, hgt): + self.group = idgroup + self.prop = idgroup + self.x = x + self.y = y + self.width = wid + self.height = hgt + self.mousecursor = [0, 0] + self.parents = [] + self.idblock = mat + self.type = type + + def DrawBox(self, glmode, x, y, width, height): + glBegin(glmode) + glVertex2f(x, y) + glVertex2f(x+width, y) + glVertex2f(x+width, y+height) + glVertex2f(x, y+height) + glEnd() + + def Draw(self): + global IDTypeModules + + #first draw outlining box :) + glColor3f(0, 0, 0) + self.DrawBox(GL_LINE_LOOP, self.x, self.y, self.width, self.height) + + itemhgt = self.itemhgt + pad = self.pad + x = self.x + y = self.y + self.height - itemhgt - pad + + if self.state == State_InArray: + self.array.Draw() + return + + plist = [] + self.buts = [] + for p in self.group.iteritems(): + plist.append(p) + + #-------do top buttons----------# + Draw.BeginAlign() + Draw.PushButton("New", Button_New, x, y, 40, 20) + x += 40 + pad + #do the menu button for all materials + st = "" + + blocks = IDTypeModules[self.IDList][0].Get() + i = 1 + mi = 0 + for m in blocks: + if m.name == self.idblock.name: + mi = i + st += m.name + " %x" + str(i) + "|" + i += 1 + + self.menubut = Draw.Menu(st, Button_MatMenu, x, y, 100, 20, mi) + + x += 100 + pad + + st = "" + i = 0 + for e in IDTypeModules: + st += e[2] + " %x" + str(i+1) + "|" + i += 1 + + cur = self.IDList + 1 + self.idmenu = Draw.Menu(st, Button_TypeMenu, x, y, 100, 20, cur) + x = self.x + y -= self.itemhgt + self.pad + Draw.EndAlign() + + + #-----------do property items---------# + i = 0 + while y > self.y - 20 - pad and i < len(plist): + k = plist[i][0] + p = plist[i][1] + if i == self.active_item: + glColor3f(0.5, 0.4, 0.3) + self.DrawBox(GL_POLYGON, x+pad, y, self.width-pad*2, itemhgt) + + glColor3f(0, 0, 0) + self.DrawBox(GL_LINE_LOOP, x+pad, y, self.width-pad*2, itemhgt) + + glRasterPos2f(x+pad*2, y+5) + Draw.Text(str(k)) #str(self.mousecursor) + " " + str(self.active_item)) #p.name) + tlen = Draw.GetStringWidth(str(k)) + + type_p = type(p) + if type_p == str: + b = Draw.String("", ButStart+i, x+pad*5+tlen, y, 200, itemhgt, p, strmax) + self.buts.append(b) + elif type_p in [int, float]: + #only do precision to 5 points on floats + st = "" + if type_p == float: + st = "%.5f" % p + else: st = str(p) + b = Draw.String("", ButStart+i, x+pad*5+tlen, y, 75, itemhgt, st, strmax) + self.buts.append(b) + else: + glRasterPos2f(x+pad*2 +tlen+10, y+5) + if type_p == Types.IDArrayType: + Draw.Text('(array, click to edit)') + elif type_p == Types.IDGroupType: + Draw.Text('(group, click to edit)') + + + self.buts.append(None) + + Draw.PushButton("Del", ButDelStart+i, x+self.width-35, y, 30, 20) + + i += 1 + y -= self.itemhgt + self.pad + + if len(self.parents) != 0: + Draw.PushButton("Back", Button_Back, x, y, 40, 20) + x = x + 40 + pad + + def SetActive(self): + m = self.mousecursor + itemhgt = self.itemhgt + pad = self.pad + + x = self.x + pad + y = self.y + self.height - itemhgt - pad - itemhgt + + plist = [] + for p in self.group.iteritems(): + plist.append(p) + + self.active_item = -1 + i = 0 + while y > self.y and i < len(plist): + p = plist[i] + if IsInRectWH(m[0], m[1], x, y, self.width-pad, itemhgt): + self.active_item = i + + i += 1 + y -= self.itemhgt + self.pad + + def EventIn(self, evt, val): + if self.state == State_InArray: + self.array.Evt(evt, val) + + if evt == Draw.ESCKEY: + Draw.Exit() + if evt == Draw.MOUSEX or evt == Draw.MOUSEY: + size = Buffer(GL_FLOAT, 4) + glGetFloatv(GL_SCISSOR_BOX, size) + if evt == Draw.MOUSEX: + self.mousecursor[0] = val - size[0] + else: + self.mousecursor[1] = val - size[1] + del size + + self.SetActive() + self._i += 1 + if self._i == 5: + Draw.Draw() + self._i = 0 + + + if evt == Draw.LEFTMOUSE and val == 1: + plist = list(self.group.iteritems()) + a = self.active_item + if a >= 0 and a < len(plist): + p = plist[a] + + basictypes = [IDGroupType, float, str, int] + if type(p[1]) == IDGroupType: + self.parents.append(self.group) + self.group = p[1] + self.active_item = -1 + Draw.Draw() + elif type(p[1]) == IDArrayType: + self.array = IDArrayBrowser() + self.array.array = p[1] + self.array.parentbrowser = self + self.state = State_InArray + Draw.Draw() + + if evt == Draw.TKEY and val == 1: + try: + self.prop['float'] = 0.0 + self.prop['int'] = 1 + self.prop['string'] = "hi!" + self.prop['float array'] = [0, 0, 1.0, 0] + self.prop['int array'] = [0, 0, 0, 0] + self.prop.data['a subgroup'] = {"int": 0, "float": 0.0, "anothergroup": {"a": 0.0, "intarr": [0, 0, 0, 0]}} + Draw.Draw() + except: + Draw.PupMenu("Can only do T once per block, the test names are already taken!") + + + def Button(self, bval): + global IDTypeModules + if self.state == State_InArray: + self.array.Button(bval) + return + + if bval == Button_MatMenu: + global IDTypeModules + + val = self.idindex = self.menubut.val - 1 + i = self.IDList + block = IDTypeModules[i][0].Get()[val] + self.idblock = block + self.prop = block.properties + self.group = self.prop + self.active_item = -1 + self.parents = [] + Draw.Draw() + + if bval == Button_TypeMenu: + i = IDTypeModules[self.idmenu.val-1] + if len(i[0].Get()) == 0: + Draw.PupMenu("Error%t|There are no " + i[2] + "!") + return + + IDTypeModules[self.IDList][1] = self.idindex + self.IDList = self.idmenu.val-1 + val = self.idindex = IDTypeModules[self.IDList][1] + i = self.IDList + block = IDTypeModules[i][0].Get()[val] + self.idblock = block + self.prop = block.properties + self.group = self.prop + self.active_item = -1 + self.parents = [] + Draw.Draw() + + if bval >= ButDelStart: + plist = [p for p in self.group] + prop = plist[bval - ButDelStart] + del self.group[prop] + Draw.Draw() + + elif bval >= ButStart: + plist = list(self.group.iteritems()) + + prop = plist[bval - ButStart] + print prop + + if self.type(prop[1]) == str: + self.group[prop[0]] = self.buts[bval - ButStart].val + elif self.type(prop[1]) == int: + i = self.buts[bval - ButStart].val + try: + i = int(i) + self.group[prop[0]] = i + except: + Draw.Draw() + return + Draw.Draw() + elif self.type(prop[1]) == float: + f = self.buts[bval - ButStart].val + try: + f = float(f) + self.group[prop[0]] = f + except: + Draw.Draw() + return + Draw.Draw() + + elif bval == Button_Back: + self.group = self.parents[len(self.parents)-1] + self.parents.pop(len(self.parents)-1) + Draw.Draw() + + elif bval == Button_New: + name = Draw.Create("untitled") + stype = Draw.Create(0) + gtype = Draw.Create(0) + ftype = Draw.Create(0) + itype = Draw.Create(0) + atype = Draw.Create(0) + + block = [] + block.append(("Name: ", name, 0, 30, "Click to type in the name of the new ID property")) + block.append("Type") + block.append(("String", stype)) + block.append(("Subgroup", gtype)) + block.append(("Float", ftype)) + block.append(("Int", itype)) + block.append(("Array", atype)) + + retval = Blender.Draw.PupBlock("New IDProperty", block) + if retval == 0: return + + name = name.val + i = 1 + stop = 0 + while stop == 0: + stop = 1 + for p in self.group: + if p == name: + d = name.rfind(".") + if d != -1: + name = name[:d] + name = name + "." + str(i).zfill(3) + i += 1 + stop = 0 + + type = "String" + if stype.val: + self.group[name] = "" + elif gtype.val: + self.group[name] = {} + elif ftype.val: + self.group[name] = 0.0 + elif itype.val: + self.group[name] = 0 #newProperty("Int", name, 0) + elif atype.val: + arrfloat = Draw.Create(1) + arrint = Draw.Create(0) + arrlen = Draw.Create(3) + block = [] + block.append("Type") + block.append(("Float", arrfloat, "Make a float array")) + block.append(("Int", arrint, "Make an integer array")) + block.append(("Len", arrlen, 2, 200)) + + if Blender.Draw.PupBlock("Array Properties", block): + if arrfloat.val: + tmpl = 0.0 + elif arrint.val: + tmpl = 0 + else: + return + + self.group[name] = [tmpl] * arrlen.val + + + def Go(self): + Draw.Register(self.Draw, self.EventIn, self.Button) + +scenes = Scene.Get() + +size = Window.GetAreaSize() +browser = IDPropertyBrowser(scenes[0].properties, scenes[0], 2, 2, size[0], size[1]) +browser.Go() + +#a = prop.newProperty("String", "hwello!", "bleh") +#b = prop.newProperty("Group", "subgroup") + +#for p in prop: + #print p.name diff --git a/release/scripts/ac3d_export.py b/release/scripts/ac3d_export.py new file mode 100644 index 00000000000..bccb7978f5f --- /dev/null +++ b/release/scripts/ac3d_export.py @@ -0,0 +1,828 @@ +#!BPY + +""" Registration info for Blender menus: +Name: 'AC3D (.ac)...' +Blender: 243 +Group: 'Export' +Tip: 'Export selected meshes to AC3D (.ac) format' +""" + +__author__ = "Willian P. Germano" +__url__ = ("blender", "elysiun", "AC3D's homepage, http://www.ac3d.org", + "PLib 3d gaming lib, http://plib.sf.net") +__version__ = "2.44 2007-05-05" + +__bpydoc__ = """\ +This script exports selected Blender meshes to AC3D's .ac file format. + +AC3D is a simple commercial 3d modeller also built with OpenGL. +The .ac file format is an easy to parse text format well supported, +for example, by the PLib 3d gaming library (AC3D 3.x). + +Supported:
+ UV-textured meshes with hierarchy (grouping) information. + +Missing:
+ The 'url' tag, specific to AC3D. It is easy to add by hand to the exported +file, if needed. + +Known issues:
+ The ambient and emit data we can retrieve from Blender are single values, +that this script copies to R, G, B, giving shades of gray.
+ Loose edges (lines) receive the first material found in the mesh, if any, or a default white material.
+ In AC3D 4 "compatibility mode":
+ - shininess of materials is taken from the shader specularity value in Blender, mapped from [0.0, 2.0] to [0, 128];
+ - crease angle is exported, but in Blender it is limited to [1, 80], since there are other more powerful ways to control surface smoothing. In AC3D 4.0 crease's range is [0.0, 180.0]; + +Config Options:
+ toggle:
+ - AC3D 4 mode: unset it to export without the 'crease' tag that was +introduced with AC3D 4.0 and with the old material handling;
+ - global coords: transform all vertices of all meshes to global coordinates;
+ - skip data: set it if you don't want mesh names (ME:, not OB: field) +to be exported as strings for AC's "data" tags (19 chars max);
+ - rgb mirror color can be exported as ambient and/or emissive if needed, +since Blender handles these differently;
+ - default mat: a default (white) material is added if some mesh was +left without mats -- it's better to always add your own materials;
+ - no split: don't split meshes (see above);
+ - set texture dir: override the actual textures path with a given default +path (or simply export the texture names, without dir info, if the path is +empty);
+ - per face 1 or 2 sided: override the "Double Sided" button that defines this behavior per whole mesh in favor of the UV Face Select mode "twosided" per face atribute;
+ - only selected: only consider selected objects when looking for meshes +to export (read notes below about tokens, too);
+ strings:
+ - export dir: default dir to export to;
+ - texture dir: override textures path with this path if 'set texture dir' +toggle is "on". + +Notes:
+ This version updates:
+ - modified meshes are correctly exported, no need to apply the modifiers in Blender;
+ - correctly export each used material, be it assigned to the object or to its mesh data;
+ - exporting lines (edges) is again supported; color comes from first material found in the mesh, if any, or a default white one.
+ - there's a new option to choose between exporting meshes with transformed (global) coordinates or local ones;
+ Multiple textures per mesh are supported (mesh gets split);
+ Parents are exported as a group containing both the parent and its children;
+ Start mesh object names (OB: field) with "!" or "#" if you don't want them to be exported;
+ Start mesh object names (OB: field) with "=" or "$" to prevent them from being split (meshes with multiple textures or both textured and non textured faces are split unless this trick is used or the "no split" option is set. +""" + +# $Id$ +# +# -------------------------------------------------------------------------- +# AC3DExport version 2.44 +# Program versions: Blender 2.42+ and AC3Db files (means version 0xb) +# new: updated for new Blender version and Mesh module; supports lines (edges) again; +# option to export vertices transformed to global coordinates or not; now the modified +# (by existing mesh modifiers) mesh is exported; materials are properly exported, no +# matter if each of them is linked to the mesh or to the object. New (2.43.1): loose +# edges use color of first material found in the mesh, if any. +# -------------------------------------------------------------------------- +# Thanks: Steve Baker for discussions and inspiration; for testing, bug +# reports, suggestions, patches: David Megginson, Filippo di Natale, +# Franz Melchior, Campbell Barton, Josh Babcock, Ralf Gerlich, Stewart Andreason. +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2004-2007: Willian P. Germano, wgermano _at_ ig.com.br +# +# 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, +# -------------------------------------------------------------------------- + +import Blender +from Blender import Object, Mesh, Material, Image, Mathutils, Registry +from Blender import sys as bsys + +# Globals +REPORT_DATA = { + 'main': [], + 'errors': [], + 'warns': [], + 'nosplit': [], + 'noexport': [] +} +TOKENS_DONT_EXPORT = ['!', '#'] +TOKENS_DONT_SPLIT = ['=', '$'] + +MATIDX_ERROR = 0 + +# flags: +LOOSE = Mesh.EdgeFlags['LOOSE'] +FACE_TWOSIDED = Mesh.FaceModes['TWOSIDE'] +MESH_TWOSIDED = Mesh.Modes['TWOSIDED'] + +REG_KEY = 'ac3d_export' + +# config options: +GLOBAL_COORDS = True +SKIP_DATA = False +MIRCOL_AS_AMB = False +MIRCOL_AS_EMIS = False +ADD_DEFAULT_MAT = True +SET_TEX_DIR = True +TEX_DIR = '' +AC3D_4 = True # export crease value, compatible with AC3D 4 loaders +NO_SPLIT = False +ONLY_SELECTED = True +EXPORT_DIR = '' +PER_FACE_1_OR_2_SIDED = True + +tooltips = { + 'GLOBAL_COORDS': "transform all vertices of all meshes to global coordinates", + 'SKIP_DATA': "don't export mesh names as data fields", + 'MIRCOL_AS_AMB': "export mirror color as ambient color", + 'MIRCOL_AS_EMIS': "export mirror color as emissive color", + 'ADD_DEFAULT_MAT': "always add a default white material", + 'SET_TEX_DIR': "don't export default texture paths (edit also \"tex dir\")", + 'EXPORT_DIR': "default / last folder used to export .ac files to", + 'TEX_DIR': "(see \"set tex dir\") dir to prepend to all exported texture names (leave empty for no dir)", + 'AC3D_4': "compatibility mode, adds 'crease' tag and slightly better material support", + 'NO_SPLIT': "don't split meshes with multiple textures (or both textured and non textured polygons)", + 'ONLY_SELECTED': "export only selected objects", + 'PER_FACE_1_OR_2_SIDED': "override \"Double Sided\" button in favor of per face \"twosided\" attribute (UV Face Select mode)" +} + +def update_RegistryInfo(): + d = {} + d['SKIP_DATA'] = SKIP_DATA + d['MIRCOL_AS_AMB'] = MIRCOL_AS_AMB + d['MIRCOL_AS_EMIS'] = MIRCOL_AS_EMIS + d['ADD_DEFAULT_MAT'] = ADD_DEFAULT_MAT + d['SET_TEX_DIR'] = SET_TEX_DIR + d['TEX_DIR'] = TEX_DIR + d['AC3D_4'] = AC3D_4 + d['NO_SPLIT'] = NO_SPLIT + d['EXPORT_DIR'] = EXPORT_DIR + d['ONLY_SELECTED'] = ONLY_SELECTED + d['PER_FACE_1_OR_2_SIDED'] = PER_FACE_1_OR_2_SIDED + d['tooltips'] = tooltips + d['GLOBAL_COORDS'] = GLOBAL_COORDS + Registry.SetKey(REG_KEY, d, True) + +# Looking for a saved key in Blender.Registry dict: +rd = Registry.GetKey(REG_KEY, True) + +if rd: + try: + AC3D_4 = rd['AC3D_4'] + SKIP_DATA = rd['SKIP_DATA'] + MIRCOL_AS_AMB = rd['MIRCOL_AS_AMB'] + MIRCOL_AS_EMIS = rd['MIRCOL_AS_EMIS'] + ADD_DEFAULT_MAT = rd['ADD_DEFAULT_MAT'] + SET_TEX_DIR = rd['SET_TEX_DIR'] + TEX_DIR = rd['TEX_DIR'] + EXPORT_DIR = rd['EXPORT_DIR'] + ONLY_SELECTED = rd['ONLY_SELECTED'] + NO_SPLIT = rd['NO_SPLIT'] + PER_FACE_1_OR_2_SIDED = rd['PER_FACE_1_OR_2_SIDED'] + GLOBAL_COORDS = rd['GLOBAL_COORDS'] + except KeyError: update_RegistryInfo() + +else: + update_RegistryInfo() + +VERBOSE = True +CONFIRM_OVERWRITE = True + +# check General scripts config key for default behaviors +rd = Registry.GetKey('General', True) +if rd: + try: + VERBOSE = rd['verbose'] + CONFIRM_OVERWRITE = rd['confirm_overwrite'] + except: pass + + +# The default material to be used when necessary (see ADD_DEFAULT_MAT) +DEFAULT_MAT = \ +'MATERIAL "DefaultWhite" rgb 1 1 1 amb 1 1 1 emis 0 0 0 \ +spec 0.5 0.5 0.5 shi 64 trans 0' + +# This transformation aligns Blender and AC3D coordinate systems: +BLEND_TO_AC3D_MATRIX = Mathutils.Matrix([1,0,0,0], [0,0,-1,0], [0,1,0,0], [0,0,0,1]) + +def Round_s(f): + "Round to default precision and turn value to a string" + r = round(f,6) # precision set to 10e-06 + if r == int(r): + return str(int(r)) + else: + return str(r) + +def transform_verts(verts, m): + vecs = [] + for v in verts: + x, y, z = v.co + vec = Mathutils.Vector([x, y, z, 1]) + vecs.append(vec*m) + return vecs + +def get_loose_edges(mesh): + loose = LOOSE + return [e for e in mesh.edges if e.flag & loose] + +# --- + +# meshes with more than one texture assigned +# are split and saved as these foomeshes +class FooMesh: + + class FooVert: + def __init__(self, v): + self.v = v + self.index = 0 + + class FooFace: + def __init__(self, foomesh, f): + self.f = f + foov = foomesh.FooVert + self.v = [foov(f.v[0]), foov(f.v[1])] + len_fv = len(f.v) + if len_fv > 2 and f.v[2]: + self.v.append(foov(f.v[2])) + if len_fv > 3 and f.v[3]: self.v.append(foov(f.v[3])) + + def __getattr__(self, attr): + if attr == 'v': return self.v + return getattr(self.f, attr) + + def __len__(self): + return len(self.f) + + def __init__(self, tex, faces, mesh): + self.name = mesh.name + self.mesh = mesh + self.looseEdges = [] + self.faceUV = mesh.faceUV + self.degr = mesh.degr + vidxs = [0]*len(mesh.verts) + foofaces = [] + for f in faces: + foofaces.append(self.FooFace(self, f)) + for v in f.v: + if v: vidxs[v.index] = 1 + i = 0 + fooverts = [] + for v in mesh.verts: + if vidxs[v.index]: + fooverts.append(v) + vidxs[v.index] = i + i += 1 + for f in foofaces: + for v in f.v: + if v: v.index = vidxs[v.v.index] + self.faces = foofaces + self.verts = fooverts + + +class AC3DExport: # the ac3d exporter part + + def __init__(self, scene_objects, file): + + global ARG, SKIP_DATA, ADD_DEFAULT_MAT, DEFAULT_MAT + + header = 'AC3Db' + self.file = file + self.buf = '' + self.mbuf = [] + self.mlist = [] + world_kids = 0 + parents_list = self.parents_list = [] + kids_dict = self.kids_dict = {} + objs = [] + exp_objs = self.exp_objs = [] + tree = {} + + file.write(header+'\n') + + objs = \ + [o for o in scene_objects if o.type in ['Mesh', 'Empty']] + + # create a tree from parents to children objects + + for obj in objs[:]: + parent = obj.parent + lineage = [obj] + + while parent: + parents_list.append(parent.name) + obj = parent + parent = parent.getParent() + lineage.insert(0, obj) + + d = tree + for i in xrange(len(lineage)): + lname = lineage[i].getType()[:2] + lineage[i].name + if lname not in d.keys(): + d[lname] = {} + d = d[lname] + + # traverse the tree to get an ordered list of names of objects to export + self.traverse_dict(tree) + + world_kids = len(tree.keys()) + + # get list of objects to export, start writing the .ac file + + objlist = [Object.Get(name) for name in exp_objs] + + meshlist = [o for o in objlist if o.type == 'Mesh'] + + # create a temporary mesh to hold actual (modified) mesh data + TMP_mesh = Mesh.New('tmp_for_ac_export') + + # write materials + + self.MATERIALS(meshlist, TMP_mesh) + mbuf = self.mbuf + if not mbuf or ADD_DEFAULT_MAT: + mbuf.insert(0, "%s\n" % DEFAULT_MAT) + mbuf = "".join(mbuf) + file.write(mbuf) + + file.write('OBJECT world\nkids %s\n' % world_kids) + + # write the objects + + for obj in objlist: + self.obj = obj + + objtype = obj.type + objname = obj.name + kidsnum = kids_dict[objname] + + # A parent plus its children are exported as a group. + # If the parent is a mesh, its rot and loc are exported as the + # group rot and loc and the mesh (w/o rot and loc) is added to the group. + if kidsnum: + self.OBJECT('group') + self.name(objname) + if objtype == 'Mesh': + kidsnum += 1 + if not GLOBAL_COORDS: + localmatrix = obj.getMatrix('localspace') + if not obj.getParent(): + localmatrix *= BLEND_TO_AC3D_MATRIX + self.rot(localmatrix.rotationPart()) + self.loc(localmatrix.translationPart()) + self.kids(kidsnum) + + if objtype == 'Mesh': + mesh = TMP_mesh # temporary mesh to hold actual (modified) mesh data + mesh.getFromObject(objname) + self.mesh = mesh + if mesh.faceUV: + meshes = self.split_mesh(mesh) + else: + meshes = [mesh] + if len(meshes) > 1: + if NO_SPLIT or self.dont_split(objname): + self.export_mesh(mesh, ob) + REPORT_DATA['nosplit'].append(objname) + else: + self.OBJECT('group') + self.name(objname) + self.kids(len(meshes)) + counter = 0 + for me in meshes: + self.export_mesh(me, obj, + name = '%s_%s' % (obj.name, counter), foomesh = True) + self.kids() + counter += 1 + else: + self.export_mesh(mesh, obj) + self.kids() + + + def traverse_dict(self, d): + kids_dict = self.kids_dict + exp_objs = self.exp_objs + keys = d.keys() + keys.sort() # sort for predictable output + keys.reverse() + for k in keys: + objname = k[2:] + klen = len(d[k]) + kids_dict[objname] = klen + if self.dont_export(objname): + d.pop(k) + parent = Object.Get(objname).getParent() + if parent: kids_dict[parent.name] -= 1 + REPORT_DATA['noexport'].append(objname) + continue + if klen: + self.traverse_dict(d[k]) + exp_objs.insert(0, objname) + else: + if k.find('Em', 0) == 0: # Empty w/o children + d.pop(k) + parent = Object.Get(objname).getParent() + if parent: kids_dict[parent.name] -= 1 + else: + exp_objs.insert(0, objname) + + def dont_export(self, name): # if name starts with '!' or '#' + length = len(name) + if length >= 1: + if name[0] in TOKENS_DONT_EXPORT: # '!' or '#' doubled (escaped): export + if length > 1 and name[1] == name[0]: + return 0 + return 1 + + def dont_split(self, name): # if name starts with '=' or '$' + length = len(name) + if length >= 1: + if name[0] in TOKENS_DONT_SPLIT: # '=' or '$' doubled (escaped): split + if length > 1 and name[1] == name[0]: + return 0 + return 1 + + def split_mesh(self, mesh): + tex_dict = {0:[]} + for f in mesh.faces: + if f.image: + if not f.image.name in tex_dict: tex_dict[f.image.name] = [] + tex_dict[f.image.name].append(f) + else: tex_dict[0].append(f) + keys = tex_dict.keys() + len_keys = len(keys) + if not tex_dict[0]: + len_keys -= 1 + tex_dict.pop(0) + keys.remove(0) + elif len_keys > 1: + lines = [] + anyimgkey = [k for k in keys if k != 0][0] + for f in tex_dict[0]: + if len(f.v) < 3: + lines.append(f) + if len(tex_dict[0]) == len(lines): + for l in lines: + tex_dict[anyimgkey].append(l) + len_keys -= 1 + tex_dict.pop(0) + if len_keys > 1: + foo_meshes = [] + for k in keys: + faces = tex_dict[k] + foo_meshes.append(FooMesh(k, faces, mesh)) + foo_meshes[0].edges = get_loose_edges(mesh) + return foo_meshes + return [mesh] + + def export_mesh(self, mesh, obj, name = None, foomesh = False): + file = self.file + self.OBJECT('poly') + if not name: name = obj.name + self.name(name) + if not SKIP_DATA: + meshname = obj.getData(name_only = True) + self.data(len(meshname), meshname) + if mesh.faceUV: + texline = self.texture(mesh.faces) + if texline: file.write(texline) + if AC3D_4: + self.crease(mesh.degr) + + # If exporting using local coordinates, children object coordinates should not be + # transformed to ac3d's coordinate system, since that will be accounted for in + # their topmost parents (the parents w/o parents) transformations. + if not GLOBAL_COORDS: + # We hold parents in a list, so they also don't get transformed, + # because for each parent we create an ac3d group to hold both the + # parent and its children. + if obj.name not in self.parents_list: + localmatrix = obj.getMatrix('localspace') + if not obj.getParent(): + localmatrix *= BLEND_TO_AC3D_MATRIX + self.rot(localmatrix.rotationPart()) + self.loc(localmatrix.translationPart()) + matrix = None + else: + matrix = obj.getMatrix() * BLEND_TO_AC3D_MATRIX + + self.numvert(mesh.verts, matrix) + self.numsurf(mesh, foomesh) + + def MATERIALS(self, meshlist, me): + for meobj in meshlist: + me.getFromObject(meobj) + mats = me.materials + mbuf = [] + mlist = self.mlist + for m in mats: + if not m: continue + name = m.name + if name not in mlist: + mlist.append(name) + M = Material.Get(name) + material = 'MATERIAL "%s"' % name + mirCol = "%s %s %s" % (Round_s(M.mirCol[0]), Round_s(M.mirCol[1]), + Round_s(M.mirCol[2])) + rgb = "rgb %s %s %s" % (Round_s(M.R), Round_s(M.G), Round_s(M.B)) + ambval = Round_s(M.amb) + amb = "amb %s %s %s" % (ambval, ambval, ambval) + spec = "spec %s %s %s" % (Round_s(M.specCol[0]), + Round_s(M.specCol[1]), Round_s(M.specCol[2])) + if AC3D_4: + emit = Round_s(M.emit) + emis = "emis %s %s %s" % (emit, emit, emit) + shival = int(M.spec * 64) + else: + emis = "emis 0 0 0" + shival = 72 + shi = "shi %s" % shival + trans = "trans %s" % (Round_s(1 - M.alpha)) + if MIRCOL_AS_AMB: + amb = "amb %s" % mirCol + if MIRCOL_AS_EMIS: + emis = "emis %s" % mirCol + mbuf.append("%s %s %s %s %s %s %s\n" \ + % (material, rgb, amb, emis, spec, shi, trans)) + self.mlist = mlist + self.mbuf.append("".join(mbuf)) + + def OBJECT(self, type): + self.file.write('OBJECT %s\n' % type) + + def name(self, name): + if name[0] in TOKENS_DONT_EXPORT or name[0] in TOKENS_DONT_SPLIT: + if len(name) > 1: name = name[1:] + self.file.write('name "%s"\n' % name) + + def kids(self, num = 0): + self.file.write('kids %s\n' % num) + + def data(self, num, str): + self.file.write('data %s\n%s\n' % (num, str)) + + def texture(self, faces): + tex = "" + for f in faces: + if f.image: + tex = f.image.name + break + if tex: + image = Image.Get(tex) + texfname = image.filename + if SET_TEX_DIR: + texfname = bsys.basename(texfname) + if TEX_DIR: + texfname = bsys.join(TEX_DIR, texfname) + buf = 'texture "%s"\n' % texfname + xrep = image.xrep + yrep = image.yrep + buf += 'texrep %s %s\n' % (xrep, yrep) + self.file.write(buf) + + def rot(self, matrix): + rot = '' + not_I = 0 # not identity + matstr = [] + for i in [0, 1, 2]: + r = map(Round_s, matrix[i]) + not_I += (r[0] != '0')+(r[1] != '0')+(r[2] != '0') + not_I -= (r[i] == '1') + for j in [0, 1, 2]: + matstr.append(' %s' % r[j]) + if not_I: # no need to write identity + self.file.write('rot%s\n' % "".join(matstr)) + + def loc(self, loc): + loc = map(Round_s, loc) + if loc != ['0', '0', '0']: # no need to write default + self.file.write('loc %s %s %s\n' % (loc[0], loc[1], loc[2])) + + def crease(self, crease): + self.file.write('crease %f\n' % crease) + + def numvert(self, verts, matrix): + file = self.file + nvstr = [] + nvstr.append("numvert %s\n" % len(verts)) + + if matrix: + verts = transform_verts(verts, matrix) + for v in verts: + v = map (Round_s, v) + nvstr.append("%s %s %s\n" % (v[0], v[1], v[2])) + else: + for v in verts: + v = map(Round_s, v.co) + nvstr.append("%s %s %s\n" % (v[0], v[1], v[2])) + + file.write("".join(nvstr)) + + def numsurf(self, mesh, foomesh = False): + + global MATIDX_ERROR + + # local vars are faster and so better in tight loops + lc_ADD_DEFAULT_MAT = ADD_DEFAULT_MAT + lc_MATIDX_ERROR = MATIDX_ERROR + lc_PER_FACE_1_OR_2_SIDED = PER_FACE_1_OR_2_SIDED + lc_FACE_TWOSIDED = FACE_TWOSIDED + lc_MESH_TWOSIDED = MESH_TWOSIDED + + faces = mesh.faces + hasFaceUV = mesh.faceUV + if foomesh: + looseEdges = mesh.looseEdges + else: + looseEdges = get_loose_edges(mesh) + + file = self.file + + file.write("numsurf %s\n" % (len(faces) + len(looseEdges))) + + if not foomesh: verts = list(self.mesh.verts) + + materials = self.mesh.materials + mlist = self.mlist + matidx_error_reported = False + objmats = [] + for omat in materials: + if omat: objmats.append(omat.name) + else: objmats.append(None) + for f in faces: + if not objmats: + m_idx = 0 + elif objmats[f.mat] in mlist: + m_idx = mlist.index(objmats[f.mat]) + else: + if not lc_MATIDX_ERROR: + rdat = REPORT_DATA['warns'] + rdat.append("Object %s" % self.obj.name) + rdat.append("has at least one material *index* assigned but not") + rdat.append("defined (not linked to an existing material).") + rdat.append("Result: some faces may be exported with a wrong color.") + rdat.append("You can assign materials in the Edit Buttons window (F9).") + elif not matidx_error_reported: + midxmsg = "- Same for object %s." % self.obj.name + REPORT_DATA['warns'].append(midxmsg) + lc_MATIDX_ERROR += 1 + matidx_error_reported = True + m_idx = 0 + if lc_ADD_DEFAULT_MAT: m_idx -= 1 + refs = len(f) + flaglow = 0 # polygon + if lc_PER_FACE_1_OR_2_SIDED and hasFaceUV: # per face attribute + two_side = f.mode & lc_FACE_TWOSIDED + else: # global, for the whole mesh + two_side = self.mesh.mode & lc_MESH_TWOSIDED + two_side = (two_side > 0) << 1 + flaghigh = f.smooth | two_side + surfstr = "SURF 0x%d%d\n" % (flaghigh, flaglow) + if lc_ADD_DEFAULT_MAT and objmats: m_idx += 1 + matstr = "mat %s\n" % m_idx + refstr = "refs %s\n" % refs + u, v, vi = 0, 0, 0 + fvstr = [] + if foomesh: + for vert in f.v: + fvstr.append(str(vert.index)) + if hasFaceUV: + u = f.uv[vi][0] + v = f.uv[vi][1] + vi += 1 + fvstr.append(" %s %s\n" % (u, v)) + else: + for vert in f.v: + fvstr.append(str(verts.index(vert))) + if hasFaceUV: + u = f.uv[vi][0] + v = f.uv[vi][1] + vi += 1 + fvstr.append(" %s %s\n" % (u, v)) + + fvstr = "".join(fvstr) + + file.write("%s%s%s%s" % (surfstr, matstr, refstr, fvstr)) + + # material for loose edges + edges_mat = 0 # default to first material + for omat in objmats: # but look for a material from this mesh + if omat in mlist: + edges_mat = mlist.index(omat) + if lc_ADD_DEFAULT_MAT: edges_mat += 1 + break + + for e in looseEdges: + fvstr = [] + #flaglow = 2 # 1 = closed line, 2 = line + #flaghigh = 0 + #surfstr = "SURF 0x%d%d\n" % (flaghigh, flaglow) + surfstr = "SURF 0x02\n" + + fvstr.append("%d 0 0\n" % verts.index(e.v1)) + fvstr.append("%d 0 0\n" % verts.index(e.v2)) + fvstr = "".join(fvstr) + + matstr = "mat %d\n" % edges_mat # for now, use first material + refstr = "refs 2\n" # 2 verts + + file.write("%s%s%s%s" % (surfstr, matstr, refstr, fvstr)) + + MATIDX_ERROR = lc_MATIDX_ERROR + +# End of Class AC3DExport + +from Blender.Window import FileSelector + +def report_data(): + global VERBOSE + + if not VERBOSE: return + + d = REPORT_DATA + msgs = { + '0main': '%s\nExporting meshes to AC3D format' % str(19*'-'), + '1warns': 'Warnings', + '2errors': 'Errors', + '3nosplit': 'Not split (because name starts with "=" or "$")', + '4noexport': 'Not exported (because name starts with "!" or "#")' + } + if NO_SPLIT: + l = msgs['3nosplit'] + l = "%s (because OPTION NO_SPLIT is set)" % l.split('(')[0] + msgs['3nosplit'] = l + keys = msgs.keys() + keys.sort() + for k in keys: + msgk = msgs[k] + msg = '\n'.join(d[k[1:]]) + if msg: + print '\n-%s:' % msgk + print msg + +# File Selector callback: +def fs_callback(filename): + global EXPORT_DIR, OBJS, CONFIRM_OVERWRITE, VERBOSE + + if not filename.endswith('.ac'): filename = '%s.ac' % filename + + if bsys.exists(filename) and CONFIRM_OVERWRITE: + if Blender.Draw.PupMenu('OVERWRITE?%t|File exists') != 1: + return + + Blender.Window.WaitCursor(1) + starttime = bsys.time() + + export_dir = bsys.dirname(filename) + if export_dir != EXPORT_DIR: + EXPORT_DIR = export_dir + update_RegistryInfo() + + try: + file = open(filename, 'w') + except IOError, (errno, strerror): + error = "IOError #%s: %s" % (errno, strerror) + REPORT_DATA['errors'].append("Saving failed - %s." % error) + error_msg = "Couldn't save file!%%t|%s" % error + Blender.Draw.PupMenu(error_msg) + return + + try: + test = AC3DExport(OBJS, file) + except: + file.close() + raise + else: + file.close() + endtime = bsys.time() - starttime + REPORT_DATA['main'].append("Done. Saved to: %s" % filename) + REPORT_DATA['main'].append("Data exported in %.3f seconds." % endtime) + + if VERBOSE: report_data() + Blender.Window.WaitCursor(0) + + +# -- End of definitions + +scn = Blender.Scene.GetCurrent() + +if ONLY_SELECTED: + OBJS = list(scn.objects.context) +else: + OBJS = list(scn.objects) + +if not OBJS: + Blender.Draw.PupMenu('ERROR: no objects selected') +else: + fname = bsys.makename(ext=".ac") + if EXPORT_DIR: + fname = bsys.join(EXPORT_DIR, bsys.basename(fname)) + FileSelector(fs_callback, "Export AC3D", fname) diff --git a/release/scripts/ac3d_import.py b/release/scripts/ac3d_import.py new file mode 100644 index 00000000000..9a7004e4b4d --- /dev/null +++ b/release/scripts/ac3d_import.py @@ -0,0 +1,771 @@ +#!BPY + +""" Registration info for Blender menus: +Name: 'AC3D (.ac)...' +Blender: 243 +Group: 'Import' +Tip: 'Import an AC3D (.ac) file.' +""" + +__author__ = "Willian P. Germano" +__url__ = ("blender", "elysiun", "AC3D's homepage, http://www.ac3d.org", + "PLib 3d gaming lib, http://plib.sf.net") +__version__ = "2.43.1 2007-02-21" + +__bpydoc__ = """\ +This script imports AC3D models into Blender. + +AC3D is a simple and affordable commercial 3d modeller also built with OpenGL. +The .ac file format is an easy to parse text format well supported, +for example, by the PLib 3d gaming library. + +Supported:
+ UV-textured meshes with hierarchy (grouping) information. + +Missing:
+ The url tag is irrelevant for Blender. + +Known issues:
+ - Some objects may be imported with wrong normals due to wrong information in the model itself. This can be noticed by strange shading, like darker than expected parts in the model. To fix this, select the mesh with wrong normals, enter edit mode and tell Blender to recalculate the normals, either to make them point outside (the usual case) or inside.
+ +Config Options:
+ - display transp (toggle): if "on", objects that have materials with alpha < 1.0 are shown with translucency (transparency) in the 3D View.
+ - subdiv (toggle): if "on", ac3d objects meant to be subdivided receive a SUBSURF modifier in Blender.
+ - textures dir (string): if non blank, when imported texture paths are +wrong in the .ac file, Blender will also look for them at this dir. + +Notes:
+ - When looking for assigned textures, Blender tries in order: the actual +paths from the .ac file, the .ac file's dir and the default textures dir path +users can configure (see config options above). +""" + +# $Id$ +# +# -------------------------------------------------------------------------- +# AC3DImport version 2.43.1 Feb 21, 2007 +# Program versions: Blender 2.43 and AC3Db files (means version 0xb) +# changed: better triangulation of ngons, more fixes to support bad .ac files, +# option to display transp mats in 3d view, support "subdiv" tag (via SUBSURF modifier) +# -------------------------------------------------------------------------- +# Thanks: Melchior Franz for extensive bug testing and reporting, making this +# version cope much better with old or bad .ac files, among other improvements; +# Stewart Andreason for reporting a serious crash. +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2004-2007: Willian P. Germano, wgermano _at_ ig.com.br +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +from math import radians + +import Blender +from Blender import Scene, Object, Mesh, Lamp, Registry, sys as bsys, Window, Image, Material, Modifier +from Blender.sys import dirsep +from Blender.Mathutils import Vector, Matrix, Euler +from Blender.Geometry import PolyFill + +# Default folder for AC3D textures, to override wrong paths, change to your +# liking or leave as "": +TEXTURES_DIR = "" + +DISPLAY_TRANSP = True + +SUBDIV = True + +tooltips = { + 'DISPLAY_TRANSP': 'Turn transparency on in the 3d View for objects using materials with alpha < 1.0.', + 'SUBDIV': 'Apply a SUBSURF modifier to objects meant to appear subdivided.', + 'TEXTURES_DIR': 'Additional folder to look for missing textures.' +} + +def update_registry(): + global TEXTURES_DIR, DISPLAY_TRANSP + rd = dict([('tooltips', tooltips), ('TEXTURES_DIR', TEXTURES_DIR), ('DISPLAY_TRANSP', DISPLAY_TRANSP), ('SUBDIV', SUBDIV)]) + Registry.SetKey('ac3d_import', rd, True) + +rd = Registry.GetKey('ac3d_import', True) + +if rd: + if 'GROUP' in rd: + update_registry() + try: + TEXTURES_DIR = rd['TEXTURES_DIR'] + DISPLAY_TRANSP = rd['DISPLAY_TRANSP'] + SUBDIV = rd['SUBDIV'] + except: + update_registry() +else: update_registry() + +if TEXTURES_DIR: + oldtexdir = TEXTURES_DIR + if dirsep == '/': TEXTURES_DIR = TEXTURES_DIR.replace('\\', '/') + if TEXTURES_DIR[-1] != dirsep: TEXTURES_DIR = "%s%s" % (TEXTURES_DIR, dirsep) + if oldtexdir != TEXTURES_DIR: update_registry() + + +VERBOSE = True +rd = Registry.GetKey('General', True) +if rd: + if rd.has_key('verbose'): + VERBOSE = rd['verbose'] + + +errmsg = "" + +# Matrix to align ac3d's coordinate system with Blender's one, +# it's a -90 degrees rotation around the x axis: +AC_TO_BLEND_MATRIX = Matrix([1, 0, 0], [0, 0, 1], [0, -1, 0]) + +AC_WORLD = 0 +AC_GROUP = 1 +AC_POLY = 2 +AC_LIGHT = 3 +AC_OB_TYPES = { + 'world': AC_WORLD, + 'group': AC_GROUP, + 'poly': AC_POLY, + 'light': AC_LIGHT + } + +AC_OB_BAD_TYPES_LIST = [] # to hold references to unknown (wrong) ob types + +def inform(msg): + global VERBOSE + if VERBOSE: print msg + +def euler_in_radians(eul): + "Used while there's a bug in the BPY API" + eul.x = radians(eul.x) + eul.y = radians(eul.y) + eul.z = radians(eul.z) + return eul + +class Obj: + + def __init__(self, type): + self.type = type + self.dad = None + self.name = '' + self.data = '' + self.tex = '' + self.texrep = [1,1] + self.texoff = None + self.loc = [] + self.rot = [] + self.size = [] + self.crease = 30 + self.subdiv = 0 + self.vlist = [] + self.flist_cfg = [] + self.flist_v = [] + self.flist_uv = [] + self.elist = [] + self.matlist = [] + self.kids = 0 + + self.bl_obj = None # the actual Blender object created from this data + +class AC3DImport: + + def __init__(self, filename): + + global errmsg + + self.scene = Scene.GetCurrent() + + self.i = 0 + errmsg = '' + self.importdir = bsys.dirname(filename) + try: + file = open(filename, 'r') + except IOError, (errno, strerror): + errmsg = "IOError #%s: %s" % (errno, strerror) + Blender.Draw.PupMenu('ERROR: %s' % errmsg) + inform(errmsg) + return None + header = file.read(5) + header, version = header[:4], header[-1] + if header != 'AC3D': + file.close() + errmsg = 'AC3D header not found (invalid file)' + Blender.Draw.PupMenu('ERROR: %s' % errmsg) + inform(errmsg) + return None + elif version != 'b': + inform('AC3D file version 0x%s.' % version) + inform('This importer is for version 0xb, so it may fail.') + + self.token = {'OBJECT': self.parse_obj, + 'numvert': self.parse_vert, + 'numsurf': self.parse_surf, + 'name': self.parse_name, + 'data': self.parse_data, + 'kids': self.parse_kids, + 'loc': self.parse_loc, + 'rot': self.parse_rot, + 'MATERIAL': self.parse_mat, + 'texture': self.parse_tex, + 'texrep': self.parse_texrep, + 'texoff': self.parse_texoff, + 'subdiv': self.parse_subdiv, + 'crease': self.parse_crease} + + self.objlist = [] + self.mlist = [] + self.kidsnumlist = [] + self.dad = None + + self.lines = file.readlines() + self.lines.append('') + self.parse_file() + file.close() + + self.testAC3DImport() + + def parse_obj(self, value): + kidsnumlist = self.kidsnumlist + if kidsnumlist: + while not kidsnumlist[-1]: + kidsnumlist.pop() + if kidsnumlist: + self.dad = self.dad.dad + else: + inform('Ignoring unexpected data at end of file.') + return -1 # bad file with more objects than reported + kidsnumlist[-1] -= 1 + if value in AC_OB_TYPES: + new = Obj(AC_OB_TYPES[value]) + else: + if value not in AC_OB_BAD_TYPES_LIST: + AC_OB_BAD_TYPES_LIST.append(value) + inform('Unexpected object type keyword: "%s". Assuming it is of type: "poly".' % value) + new = Obj(AC_OB_TYPES['poly']) + new.dad = self.dad + new.name = value + self.objlist.append(new) + + def parse_kids(self, value): + kids = int(value) + if kids: + self.kidsnumlist.append(kids) + self.dad = self.objlist[-1] + self.objlist[-1].kids = kids + + def parse_name(self, value): + name = value.split('"')[1] + self.objlist[-1].name = name + + def parse_data(self, value): + data = self.lines[self.i].strip() + self.objlist[-1].data = data + + def parse_tex(self, value): + line = self.lines[self.i - 1] # parse again to properly get paths with spaces + texture = line.split('"')[1] + self.objlist[-1].tex = texture + + def parse_texrep(self, trash): + trep = self.lines[self.i - 1] + trep = trep.split() + trep = [float(trep[1]), float(trep[2])] + self.objlist[-1].texrep = trep + self.objlist[-1].texoff = [0, 0] + + def parse_texoff(self, trash): + toff = self.lines[self.i - 1] + toff = toff.split() + toff = [float(toff[1]), float(toff[2])] + self.objlist[-1].texoff = toff + + def parse_mat(self, value): + i = self.i - 1 + lines = self.lines + line = lines[i].split() + mat_name = '' + mat_col = mat_amb = mat_emit = mat_spec_col = [0,0,0] + mat_alpha = 1 + mat_spec = 1.0 + + while line[0] == 'MATERIAL': + mat_name = line[1].split('"')[1] + mat_col = map(float,[line[3],line[4],line[5]]) + v = map(float,[line[7],line[8],line[9]]) + mat_amb = (v[0]+v[1]+v[2]) / 3.0 + v = map(float,[line[11],line[12],line[13]]) + mat_emit = (v[0]+v[1]+v[2]) / 3.0 + mat_spec_col = map(float,[line[15],line[16],line[17]]) + mat_spec = float(line[19]) / 64.0 + mat_alpha = float(line[-1]) + mat_alpha = 1 - mat_alpha + self.mlist.append([mat_name, mat_col, mat_amb, mat_emit, mat_spec_col, mat_spec, mat_alpha]) + i += 1 + line = lines[i].split() + + self.i = i + + def parse_rot(self, trash): + i = self.i - 1 + ob = self.objlist[-1] + rot = self.lines[i].split(' ', 1)[1] + rot = map(float, rot.split()) + matrix = Matrix(rot[:3], rot[3:6], rot[6:]) + ob.rot = matrix + size = matrix.scalePart() # vector + ob.size = size + + def parse_loc(self, trash): + i = self.i - 1 + loc = self.lines[i].split(' ', 1)[1] + loc = map(float, loc.split()) + self.objlist[-1].loc = Vector(loc) + + def parse_crease(self, value): + # AC3D: range is [0.0, 180.0]; Blender: [1, 80] + value = float(value) + self.objlist[-1].crease = int(value) + + def parse_subdiv(self, value): + self.objlist[-1].subdiv = int(value) + + def parse_vert(self, value): + i = self.i + lines = self.lines + obj = self.objlist[-1] + vlist = obj.vlist + n = int(value) + + while n: + line = lines[i].split() + line = map(float, line) + vlist.append(line) + n -= 1 + i += 1 + + if vlist: # prepend a vertex at 1st position to deal with vindex 0 issues + vlist.insert(0, line) + + self.i = i + + def parse_surf(self, value): + i = self.i + is_smooth = 0 + double_sided = 0 + lines = self.lines + obj = self.objlist[-1] + vlist = obj.vlist + matlist = obj.matlist + numsurf = int(value) + NUMSURF = numsurf + + badface_notpoly = badface_multirefs = 0 + + while numsurf: + flags = lines[i].split()[1][2:] + if len(flags) > 1: + flaghigh = int(flags[0]) + flaglow = int(flags[1]) + else: + flaghigh = 0 + flaglow = int(flags[0]) + + is_smooth = flaghigh & 1 + twoside = flaghigh & 2 + nextline = lines[i+1].split() + if nextline[0] != 'mat': # the "mat" line may be missing (found in one buggy .ac file) + matid = 0 + if not matid in matlist: matlist.append(matid) + i += 2 + else: + matid = int(nextline[1]) + if not matid in matlist: matlist.append(matid) + nextline = lines[i+2].split() + i += 3 + refs = int(nextline[1]) + face = [] + faces = [] + edges = [] + fuv = [] + fuvs = [] + rfs = refs + + while rfs: + line = lines[i].split() + v = int(line[0]) + 1 # + 1 to avoid vindex == 0 + uv = [float(line[1]), float(line[2])] + face.append(v) + fuv.append(Vector(uv)) + rfs -= 1 + i += 1 + + if flaglow: # it's a line or closed line, not a polygon + while len(face) >= 2: + cut = face[:2] + edges.append(cut) + face = face[1:] + + if flaglow == 1 and edges: # closed line + face = [edges[-1][-1], edges[0][0]] + edges.append(face) + + else: # polygon + + # check for bad face, that references same vertex more than once + lenface = len(face) + if lenface < 3: + # less than 3 vertices, not a face + badface_notpoly += 1 + elif sum(map(face.count, face)) != lenface: + # multiple references to the same vertex + badface_multirefs += 1 + else: # ok, seems fine + if len(face) > 4: # ngon, triangulate it + polyline = [] + for vi in face: + polyline.append(Vector(vlist[vi])) + tris = PolyFill([polyline]) + for t in tris: + tri = [face[t[0]], face[t[1]], face[t[2]]] + triuvs = [fuv[t[0]], fuv[t[1]], fuv[t[2]]] + faces.append(tri) + fuvs.append(triuvs) + else: # tri or quad + faces.append(face) + fuvs.append(fuv) + + obj.flist_cfg.extend([[matid, is_smooth, twoside]] * len(faces)) + obj.flist_v.extend(faces) + obj.flist_uv.extend(fuvs) + obj.elist.extend(edges) # loose edges + + numsurf -= 1 + + if badface_notpoly or badface_multirefs: + inform('Object "%s" - ignoring bad faces:' % obj.name) + if badface_notpoly: + inform('\t%d face(s) with less than 3 vertices.' % badface_notpoly) + if badface_multirefs: + inform('\t%d face(s) with multiple references to a same vertex.' % badface_multirefs) + + self.i = i + + def parse_file(self): + i = 1 + lines = self.lines + line = lines[i].split() + + while line: + kw = '' + for k in self.token.keys(): + if line[0] == k: + kw = k + break + i += 1 + if kw: + self.i = i + result = self.token[kw](line[1]) + if result: + break # bad .ac file, stop parsing + i = self.i + line = lines[i].split() + + # for each group of meshes we try to find one that can be used as + # parent of the group in Blender. + # If not found, we can use an Empty as parent. + def found_parent(self, groupname, olist): + l = [o for o in olist if o.type == AC_POLY \ + and not o.kids and not o.rot and not o.loc] + if l: + for o in l: + if o.name == groupname: + return o + #return l[0] + return None + + def build_hierarchy(self): + blmatrix = AC_TO_BLEND_MATRIX + + olist = self.objlist[1:] + olist.reverse() + + scene = self.scene + + newlist = [] + + for o in olist: + kids = o.kids + if kids: + children = newlist[-kids:] + newlist = newlist[:-kids] + if o.type == AC_GROUP: + parent = self.found_parent(o.name, children) + if parent: + children.remove(parent) + o.bl_obj = parent.bl_obj + else: # not found, use an empty + empty = scene.objects.new('Empty', o.name) + o.bl_obj = empty + + bl_children = [c.bl_obj for c in children if c.bl_obj != None] + + o.bl_obj.makeParent(bl_children, 0, 1) + for child in children: + blob = child.bl_obj + if not blob: continue + if child.rot: + eul = euler_in_radians(child.rot.toEuler()) + blob.setEuler(eul) + if child.size: + blob.size = child.size + if not child.loc: + child.loc = Vector(0.0, 0.0, 0.0) + blob.setLocation(child.loc) + + newlist.append(o) + + for o in newlist: # newlist now only has objs w/o parents + blob = o.bl_obj + if not blob: + continue + if o.size: + o.bl_obj.size = o.size + if not o.rot: + blob.setEuler([1.5707963267948966, 0, 0]) + else: + matrix = o.rot * blmatrix + eul = euler_in_radians(matrix.toEuler()) + blob.setEuler(eul) + if o.loc: + o.loc *= blmatrix + else: + o.loc = Vector(0.0, 0.0, 0.0) + blob.setLocation(o.loc) # forces DAG update, so we do it even for 0, 0, 0 + + # XXX important: until we fix the BPy API so it doesn't increase user count + # when wrapping a Blender object, this piece of code is needed for proper + # object (+ obdata) deletion in Blender: + for o in self.objlist: + if o.bl_obj: + o.bl_obj = None + + def testAC3DImport(self): + + FACE_TWOSIDE = Mesh.FaceModes['TWOSIDE'] + FACE_TEX = Mesh.FaceModes['TEX'] + MESH_AUTOSMOOTH = Mesh.Modes['AUTOSMOOTH'] + + MAT_MODE_ZTRANSP = Material.Modes['ZTRANSP'] + MAT_MODE_TRANSPSHADOW = Material.Modes['TRANSPSHADOW'] + + scene = self.scene + + bl_images = {} # loaded texture images + missing_textures = [] # textures we couldn't find + + objlist = self.objlist[1:] # skip 'world' + + bmat = [] + has_transp_mats = False + for mat in self.mlist: + name = mat[0] + m = Material.New(name) + m.rgbCol = (mat[1][0], mat[1][1], mat[1][2]) + m.amb = mat[2] + m.emit = mat[3] + m.specCol = (mat[4][0], mat[4][1], mat[4][2]) + m.spec = mat[5] + m.alpha = mat[6] + if m.alpha < 1.0: + m.mode |= MAT_MODE_ZTRANSP + has_transp_mats = True + bmat.append(m) + + if has_transp_mats: + for mat in bmat: + mat.mode |= MAT_MODE_TRANSPSHADOW + + obj_idx = 0 # index of current obj in loop + for obj in objlist: + if obj.type == AC_GROUP: + continue + elif obj.type == AC_LIGHT: + light = Lamp.New('Lamp') + object = scene.objects.new(light, obj.name) + #object.select(True) + obj.bl_obj = object + if obj.data: + light.name = obj.data + continue + + # type AC_POLY: + + # old .ac files used empty meshes as groups, convert to a real ac group + if not obj.vlist and obj.kids: + obj.type = AC_GROUP + continue + + mesh = Mesh.New() + object = scene.objects.new(mesh, obj.name) + #object.select(True) + obj.bl_obj = object + if obj.data: mesh.name = obj.data + mesh.degr = obj.crease # will auto clamp to [1, 80] + + if not obj.vlist: # no vertices? nothing more to do + continue + + mesh.verts.extend(obj.vlist) + + objmat_indices = [] + for mat in bmat: + if bmat.index(mat) in obj.matlist: + objmat_indices.append(bmat.index(mat)) + mesh.materials += [mat] + if DISPLAY_TRANSP and mat.alpha < 1.0: + object.transp = True + + for e in obj.elist: + mesh.edges.extend(e) + + if obj.flist_v: + mesh.faces.extend(obj.flist_v) + + facesnum = len(mesh.faces) + + if facesnum == 0: # shouldn't happen, of course + continue + + mesh.faceUV = True + + # checking if the .ac file had duplicate faces (Blender ignores them) + if facesnum != len(obj.flist_v): + # it has, ugh. Let's clean the uv list: + lenfl = len(obj.flist_v) + flist = obj.flist_v + uvlist = obj.flist_uv + cfglist = obj.flist_cfg + for f in flist: + f.sort() + fi = lenfl + while fi > 0: # remove data related to duplicates + fi -= 1 + if flist[fi] in flist[:fi]: + uvlist.pop(fi) + cfglist.pop(fi) + + img = None + if obj.tex != '': + if obj.tex in bl_images.keys(): + img = bl_images[obj.tex] + elif obj.tex not in missing_textures: + texfname = None + objtex = obj.tex + baseimgname = bsys.basename(objtex) + if bsys.exists(objtex) == 1: + texfname = objtex + elif bsys.exists(bsys.join(self.importdir, objtex)): + texfname = bsys.join(self.importdir, objtex) + else: + if baseimgname.find('\\') > 0: + baseimgname = bsys.basename(objtex.replace('\\','/')) + objtex = bsys.join(self.importdir, baseimgname) + if bsys.exists(objtex) == 1: + texfname = objtex + else: + objtex = bsys.join(TEXTURES_DIR, baseimgname) + if bsys.exists(objtex): + texfname = objtex + if texfname: + try: + img = Image.Load(texfname) + # Commented because it's unnecessary: + #img.xrep = int(obj.texrep[0]) + #img.yrep = int(obj.texrep[1]) + if img: + bl_images[obj.tex] = img + except: + inform("Couldn't load texture: %s" % baseimgname) + else: + missing_textures.append(obj.tex) + inform("Couldn't find texture: %s" % baseimgname) + + for i in range(facesnum): + f = obj.flist_cfg[i] + fmat = f[0] + is_smooth = f[1] + twoside = f[2] + bface = mesh.faces[i] + bface.smooth = is_smooth + if twoside: bface.mode |= FACE_TWOSIDE + if img: + bface.mode |= FACE_TEX + bface.image = img + bface.mat = objmat_indices.index(fmat) + fuv = obj.flist_uv[i] + if obj.texoff: + uoff = obj.texoff[0] + voff = obj.texoff[1] + urep = obj.texrep[0] + vrep = obj.texrep[1] + for uv in fuv: + uv[0] *= urep + uv[1] *= vrep + uv[0] += uoff + uv[1] += voff + + mesh.faces[i].uv = fuv + + # finally, delete the 1st vertex we added to prevent vindices == 0 + mesh.verts.delete(0) + + mesh.calcNormals() + + mesh.mode = MESH_AUTOSMOOTH + + # subdiv: create SUBSURF modifier in Blender + if SUBDIV and obj.subdiv > 0: + subdiv = obj.subdiv + subdiv_render = subdiv + # just to be safe: + if subdiv_render > 6: subdiv_render = 6 + if subdiv > 3: subdiv = 3 + modif = object.modifiers.append(Modifier.Types.SUBSURF) + modif[Modifier.Settings.LEVELS] = subdiv + modif[Modifier.Settings.RENDLEVELS] = subdiv_render + + obj_idx += 1 + + self.build_hierarchy() + scene.update() + +# End of class AC3DImport + +def filesel_callback(filename): + + inform("\nTrying to import AC3D model(s) from:\n%s ..." % filename) + Window.WaitCursor(1) + starttime = bsys.time() + test = AC3DImport(filename) + Window.WaitCursor(0) + endtime = bsys.time() - starttime + inform('Done! Data imported in %.3f seconds.\n' % endtime) + +Window.EditMode(0) + +Window.FileSelector(filesel_callback, "Import AC3D", "*.ac") diff --git a/release/scripts/add_mesh_empty.py b/release/scripts/add_mesh_empty.py new file mode 100644 index 00000000000..537bd1e2c3d --- /dev/null +++ b/release/scripts/add_mesh_empty.py @@ -0,0 +1,13 @@ +#!BPY +""" +Name: 'Empty mesh' +Blender: 243 +Group: 'AddMesh' +""" +import BPyAddMesh +import Blender + +def main(): + BPyAddMesh.add_mesh_simple('EmptyMesh', [], [], []) + +main() \ No newline at end of file diff --git a/release/scripts/add_mesh_torus.py b/release/scripts/add_mesh_torus.py new file mode 100644 index 00000000000..de2db42d482 --- /dev/null +++ b/release/scripts/add_mesh_torus.py @@ -0,0 +1,64 @@ +#!BPY +""" +Name: 'Torus' +Blender: 243 +Group: 'AddMesh' +""" +import BPyAddMesh +import Blender +from math import cos, sin, pi + +def add_torus(PREF_MAJOR_RAD, PREF_MINOR_RAD, PREF_MAJOR_SEG, PREF_MINOR_SEG): + Vector = Blender.Mathutils.Vector + RotationMatrix = Blender.Mathutils.RotationMatrix + verts = [] + faces = [] + i1 = 0 + tot_verts = PREF_MAJOR_SEG * PREF_MINOR_SEG + for major_index in xrange(PREF_MAJOR_SEG): + verts_tmp = [] + mtx = RotationMatrix( 360 * float(major_index)/PREF_MAJOR_SEG, 3, 'z' ) + + for minor_index in xrange(PREF_MINOR_SEG): + angle = 2*pi*minor_index/PREF_MINOR_SEG + + verts.append( Vector(PREF_MAJOR_RAD+(cos(angle)*PREF_MINOR_RAD), 0, (sin(angle)*PREF_MINOR_RAD)) * mtx ) + if minor_index+1==PREF_MINOR_SEG: + i2 = (major_index)*PREF_MINOR_SEG + i3 = i1 + PREF_MINOR_SEG + i4 = i2 + PREF_MINOR_SEG + + else: + i2 = i1 + 1 + i3 = i1 + PREF_MINOR_SEG + i4 = i3 + 1 + + if i2>=tot_verts: i2 = i2-tot_verts + if i3>=tot_verts: i3 = i3-tot_verts + if i4>=tot_verts: i4 = i4-tot_verts + + faces.append( (i3,i4,i2,i1) ) + i1+=1 + + return verts, faces + +def main(): + Draw = Blender.Draw + PREF_MAJOR_RAD = Draw.Create(1.0) + PREF_MINOR_RAD = Draw.Create(0.25) + PREF_MAJOR_SEG = Draw.Create(48) + PREF_MINOR_SEG = Draw.Create(16) + + if not Draw.PupBlock('Add Torus', [\ + ('Major Radius:', PREF_MAJOR_RAD, 0.01, 100, 'Radius for the main ring of the torus'),\ + ('Minor Radius:', PREF_MINOR_RAD, 0.01, 100, 'Radius for the minor ring of the torus setting the thickness of the ring.'),\ + ('Major Segments:', PREF_MAJOR_SEG, 3, 256, 'Radius for the main ring of the torus'),\ + ('Minor Segments:', PREF_MINOR_SEG, 3, 256, 'Radius for the minor ring of the torus setting the thickness of the ring.'),\ + ]): + return + + verts, faces = add_torus(PREF_MAJOR_RAD.val, PREF_MINOR_RAD.val, PREF_MAJOR_SEG.val, PREF_MINOR_SEG.val) + + BPyAddMesh.add_mesh_simple('Torus', verts, [], faces) + +main() \ No newline at end of file diff --git a/release/scripts/animation_trajectory.py b/release/scripts/animation_trajectory.py new file mode 100644 index 00000000000..55a670b66b1 --- /dev/null +++ b/release/scripts/animation_trajectory.py @@ -0,0 +1,575 @@ +#!BPY + +""" Registration info for Blender menus: <- these words are ignored +Name: 'Trajectory' +Blender: 243 +Group: 'Animation' +Tip: 'See Trajectory of selected object' +""" + +__author__ = '3R - R3gis' +__version__ = '2.43' +__url__ = ["Script's site , http://blenderfrance.free.fr/python/Trajectory_en.htm","Author's site , http://cybercreator.free.fr", "French Blender support forum, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender"] +__email__=["3R, r3gis@free.fr"] + + +__bpydoc__ = """ + +Usage: + +* Launch with alt+P (or put it in .script folder) + +Allow to see in real time trajectory of selected object. + +On first run, it ask you +- If you want that actually selected object have they trajectory always shown +- If you want to use Space Handler or a Scriptlink in Redraw mode +- Future and Past : it is the frame in past and future +of the beggining and the end of the path +- Width of line that represent the trajectory + +Then the object's trajectory will be shown in all 3D areas. +When trajectory is red, you can modifiy it by moving object. +When trajectory is blue and you want to be able to modify it, inser a Key (I-Key) + +Points appears on trajectory : +- Left Clic to modify position +- Right Clic to go to the frame it represents + +Notes:
+In scriptlink mode, it create one script link so make sure that 'Enable Script Link' toogle is on +In SpaceHandler mode, you have to go in View>>SpaceHandlerScript menu to activate Trajectory + + +""" + + +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2004-2006: Regis Montoya +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- +################################# +# by 3R - 26/08/05 +# for any problem : +# r3gis@free.fr +# ou sur le newsgroup: +# http://zoo-logique.org/3D.Blender/ +################################# +#Many thanks to cambo for his fixes +################################# + + + +import Blender + + +scene= Blender.Scene.GetCurrent() + + +#Writing +def write_script(name, script): + global scene + #List texts and their name + #write : type of writing : 1->New, 2->Overwrite + scripting= None + for text in Blender.Text.Get(): + if text.name==name and text.asLines()[1] != "#"+str(__version__): + scripting = text + scripting.clear() + scripting.write(script) + break + + if not scripting: + scripting= Blender.Text.New(name) + scripting.write(script) + +def link_script(name, type): + global scene + scriptlinks = scene.getScriptLinks(type) # none or list + if not scriptlinks or name not in scriptlinks: + scene.addScriptLink(name, type) + + +#Deleting of a text +def text_remove(name): + global scene + #try to delete text if already linked + try: + text= Blender.Text.Get(name) + # Texte.clear() + scene.clearScriptLinks([name]) + Blender.Text.unlink(text) + except: + print('---Initialisation of Trajectory_'+str(__version__)+'.py---') + +#Whether is already running, also check if it's the last version of the script : second line contain the version fo the script +ask_modif= 0 # Default +for text in Blender.Text.Get(): + if text.name == 'Trajectory' and text.asLines()[1] == "#"+str(__version__): + #We ask if script modify his seetings, keep it or stop script + ask_modif= Blender.Draw.PupMenu("Script already launch %t|Modify settings%x0|Keep settings%x1|Stop script%x2|") + if ask_modif==-1: # user canceled. + ask_modif= 1 + break + +selection_mode= 0 +future= 35 +past= 20 +width= 2 + +#In modify case +if ask_modif==0: + handle_mode= Blender.Draw.Create(0) + selection_mode= Blender.Draw.Create(0) + future= Blender.Draw.Create(35) + past= Blender.Draw.Create(20) + width= Blender.Draw.Create(2) + + block= [] + block.append(("Space Handlers", handle_mode, "You have to activate for each area by View>>SpaceHandler")) #You can delete this option... + block.append(("Always Draw", selection_mode, "Selected object will have their trajectory always shown")) + block.append(("Past :", past, 1, 900)) + block.append(("Futur:", future, 1, 900)) + block.append(("Width:", width, 1,5)) + + if not Blender.Draw.PupBlock("Trajectory seetings", block): + ask_modif=1 + + handle_mode= handle_mode.val + selection_mode= selection_mode.val + future= future.val + past= past.val + width= width.val + + +#put names of selected objects in objects_select if option choosen by user +if selection_mode==1: + objects_select= [ob.name for ob in scene.objects.context] +else: + objects_select= [] + + +try: + if handle_mode==1: + DrawPart="#SPACEHANDLER.VIEW3D.DRAW\n" + else: + DrawPart="#!BPY\n" +except:DrawPart="#BadlyMade" + + +#Here is the script to write in Blender and to link, options are also written now +DrawPart=DrawPart+"#"+str(__version__)+""" +#This script is a part of Trajectory.py and have to be linked to the scene in Redraw if not in HANDLER mode. +#Author : 3R - Regis Montoya +#It's better to use the Trajectory_"version_number".py +#You can modify the two following value to change the path settings +future="""+str(future)+""" +past="""+str(past)+""" +object_init_names="""+str(objects_select)+""" + + +import Blender, math +from Blender import BGL, Draw, Ipo +from Blender.BGL import * +from Blender.Draw import * +from math import * + +from Blender.Mathutils import Vector + +#take actual frame +frameC=Blender.Get('curframe') +scene = Blender.Scene.GetCurrent() +render_context=scene.getRenderingContext() +#ajust number of frames with NewMap and OldMapvalue values +k=1.00*render_context.oldMapValue()/render_context.newMapValue() +if k<1: + tr=-1*int(log(k*0.1, 10)) +else: + tr=-1*int(log(k, 10)) +#The real and integer frame to compare to ipos keys frames +frameCtr=round(frameC*k, tr) +frameCr=frameC*k +frameC=int(round(frameC*k, 0)) + + +#List objects that we have to show trajectory in $objects +# In this case, using a dict for unique objects is the fastest way. +object_dict= dict([(ob.name, ob) for ob in scene.objects.context]) +for obname in object_init_names: + if not object_dict.has_key(obname): + try: # Object may be removed. + object_dict[obname]= Blender.Object.Get(obname) + except: + pass # object was removed. + +#This fonction give the resulting matrix of all parents at a given frame +#parent_list is the list of all parents [object, matrix, locX_ipo, locY, Z, rotX, Y, Z, sizeX, Y, Z] of current object +def matrixForTraj(frame, parent_list): + DecMatC=Blender.Mathutils.Matrix([1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]) + + for parent_data in parent_list: + parent_ob= parent_data[0] + + try: X= parent_data[5][frame]*pi/18 + except: X= parent_ob.RotX + try: Y= parent_data[6][frame]*pi/18 + except: Y= parent_ob.RotY + try: Z= parent_data[7][frame]*pi/18 + except: Z= parent_ob.RotZ + try: LX= parent_data[2][frame] + except: LX= parent_ob.LocX + try: LY= parent_data[3][frame] + except: LY= parent_ob.LocY + try: LZ= parent_data[4][frame] + except: LZ= parent_ob.LocZ + try: SX= parent_data[8][frame] + except: SX= parent_ob.SizeX + try: SY= parent_data[9][frame] + except: SY= parent_ob.SizeY + try: SZ= parent_data[10][frame] + except: SZ= parent_ob.SizeZ + + NMat=Blender.Mathutils.Matrix([cos(Y)*cos(Z)*SX,SX*cos(Y)*sin(Z),-SX*sin(Y),0], + [(-cos(X)*sin(Z)+sin(Y)*sin(X)*cos(Z))*SY,(sin(X)*sin(Y)*sin(Z)+cos(X)*cos(Z))*SY,sin(X)*cos(Y)*SY,0], + [(cos(X)*sin(Y)*cos(Z)+sin(X)*sin(Z))*SZ,(cos(X)*sin(Y)*sin(Z)-sin(X)*cos(Z))*SZ,SZ*cos(X)*cos(Y),0], + [LX,LY,LZ,1]) + DecMatC=DecMatC*parent_data[1]*NMat + return DecMatC + +##### +TestLIST=[] +matview=Blender.Window.GetPerspMatrix() +########### +#Fonction to draw trajectories +########### + +def Trace_Traj(ob): + global TestLIST, matview + #we draw trajectories for all objects in list + + LocX=[] + LocY=[] + LocZ=[] + #List with trajectories' vertexs + vertexX=[] + + contextIpo= ob.ipo + if contextIpo: + ipoLocX=contextIpo[Ipo.OB_LOCX] + ipoLocY=contextIpo[Ipo.OB_LOCY] + ipoLocZ=contextIpo[Ipo.OB_LOCZ] + ipoTime=contextIpo[Ipo.OB_TIME] + else: # only do if there is no IPO (if no ipo curves : return None object and don't go in this except) + ipoLocX= ipoLocY= ipoLocZ= ipoTime= None + + if ipoTime: + return 0 + + #Get all parents of ob + parent=ob.parent + backup_ob= ob + child= ob + parent_list= [] + + #Get parents's infos : + #list of [name, initial matrix at make parent, ipo in X,Y,Z,rotX,rotY,rotZ,sizeX,Y,Z] + while parent: + Init_Mat=Blender.Mathutils.Matrix(child.getMatrix('worldspace')) #must be done like it (it isn't a matrix otherwise) + Init_Mat.invert() + Init_Mat=Init_Mat*child.getMatrix('localspace') + Init_Mat=parent.getMatrix()*Init_Mat + Init_Mat.invert() + + contextIpo= parent.ipo # None or IPO + if contextIpo: + ipo_Parent_LocX=contextIpo[Ipo.OB_LOCX] + ipo_Parent_LocY=contextIpo[Ipo.OB_LOCY] + ipo_Parent_LocZ=contextIpo[Ipo.OB_LOCZ] + ipo_Parent_RotX=contextIpo[Ipo.OB_ROTX] + ipo_Parent_RotY=contextIpo[Ipo.OB_ROTY] + ipo_Parent_RotZ=contextIpo[Ipo.OB_ROTZ] + ipo_Parent_SizeX=contextIpo[Ipo.OB_SIZEX] + ipo_Parent_SizeY=contextIpo[Ipo.OB_SIZEY] + ipo_Parent_SizeZ=contextIpo[Ipo.OB_SIZEZ] + else: + ipo_Parent_LocX=ipo_Parent_LocY=ipo_Parent_LocZ=\ + ipo_Parent_RotX=ipo_Parent_RotY=ipo_Parent_RotZ=\ + ipo_Parent_SizeX=ipo_Parent_SizeY=ipo_Parent_SizeZ= None + + parent_list.append([parent, Init_Mat, ipo_Parent_LocX, ipo_Parent_LocY, ipo_Parent_LocZ, ipo_Parent_RotX, ipo_Parent_RotY, ipo_Parent_RotZ, ipo_Parent_SizeX, ipo_Parent_SizeY, ipo_Parent_SizeZ]) + + child=parent + parent=parent.parent + + #security : if one of parents object are a path>>follow : trajectory don't work properly so it have to draw nothing + for parent in parent_list: + if parent[0].type == 'Curve': + if parent[0].data.flag & 1<<4: # Follow path, 4th bit + return 1 + + #ob >> re-assign obj and not parent + ob= backup_ob + ob= backup_ob + + + if ipoLocX: LXC= ipoLocX[frameC] + else: LXC= ob.LocX + if ipoLocY: LYC= ipoLocY[frameC] + else: LYC= ob.LocY + if ipoLocZ: LZC= ipoLocZ[frameC] + else: LZC= ob.LocZ + + vect= Vector([ob.LocX, ob.LocY, ob.LocZ, 1]) + color=[0, 1] + + #If trajectory is being modified and we are at a frame where a ipo key already exist + if round(ob.LocX, 5)!=round(LXC, 5): + for bez in ipoLocX.bezierPoints: + if round(bez.pt[0], tr)==frameCtr: + bez.pt = [frameCr, vect[0]] + ipoLocX.recalc() + if round(ob.LocY, 5)!=round(LYC, 5): + for bez in ipoLocY.bezierPoints: + if round(bez.pt[0], tr)==frameCtr: + bez.pt = [frameCr, vect[1]] + ipoLocY.recalc() + if round(ob.LocZ, 5)!=round(LZC, 5): + for bez in ipoLocZ.bezierPoints: + if round(bez.pt[0], tr)==frameCtr: + bez.pt = [frameCr, vect[2]] + ipoLocZ.recalc() + + #change trajectory color if at an ipoKey + VertexFrame=[] + bezier_Coord=0 + if ipoLocX: # FIXED like others it was just in case ipoLocX==None + for bez in ipoLocX.bezierPoints: + bezier_Coord=round(bez.pt[0], tr) + if bezier_Coord not in VertexFrame: + VertexFrame.append(bezier_Coord) + if bezier_Coord==frameCtr: + color=[1, color[1]-0.3] + if ipoLocY: # FIXED + for bez in ipoLocY.bezierPoints: + bezier_Coord=round(bez.pt[0], tr) + if bezier_Coord not in VertexFrame: + VertexFrame.append(bezier_Coord) + if round(bez.pt[0], tr)==frameCtr: + color=[1, color[1]-0.3] + if ipoLocZ: # FIXED + for bez in ipoLocZ.bezierPoints: + bezier_Coord=round(bez.pt[0], tr) + if bezier_Coord not in VertexFrame: + VertexFrame.append(bezier_Coord) + if round(bez.pt[0], tr)==frameCtr: + color=[1, color[1]-0.3] + + + #put in LocX, LocY and LocZ all points of trajectory + for frame in xrange(frameC-past, frameC+future): + DecMat=matrixForTraj(frame, parent_list) + + if ipoLocX: LX= ipoLocX[frame] + else: LX= ob.LocX + if ipoLocY: LY= ipoLocY[frame] + else: LY= ob.LocY + if ipoLocZ: LZ= ipoLocZ[frame] + else: LZ= ob.LocZ + + vect=Vector(LX, LY, LZ)*DecMat + LocX.append(vect[0]) + LocY.append(vect[1]) + LocZ.append(vect[2]) + + + #draw part : get current view + MatPreBuff= [matview[i][j] for i in xrange(4) for j in xrange(4)] + + MatBuff=BGL.Buffer(GL_FLOAT, 16, MatPreBuff) + + glLoadIdentity() + glMatrixMode(GL_PROJECTION) + glPushMatrix() + glLoadMatrixf(MatBuff) + + #draw trajectory line + glLineWidth("""+str(width)+""") + + glBegin(GL_LINE_STRIP) + for i in xrange(len(LocX)): + glColor3f((i+1)*1.00/len(LocX)*color[0], 0, (i+1)*1.00/len(LocX)*color[1]) + glVertex3f(LocX[i], LocY[i], LocZ[i]) + + glEnd() + + #draw trajectory's "vertexs" + if not Blender.Window.EditMode(): + glPointSize(5) + glBegin(GL_POINTS) + TestPOINTS=[] + TestFRAME=[] + i=0 + for frame in VertexFrame: + ix=int(frame)-frameC+past + if ix>=0 and ixpt[0]-4 and mouse_co[1]>pt[1]-4 and mouse_co[1]R and R>L can use the same code + def IS_XMIRROR_SOURCE(xval): + '''Source means is this the value we want to copy from''' + + if PREF_MODE_L2R: + if xval<0: return True + else: return False + else: # PREF_MODE_R2L + if xval<0: return False + else: return True + + if IS_XMIRROR_SOURCE( h1.x ):# head bone 1s negative, so copy it to h2 + editbone2.head= VecXFlip(h1) + else: + ''' + assume h2.x<0 - not a big deal if were wrong, + its unlikely to ever happen because the bones would both be on the same side. + ''' + + # head bone 2s negative, so copy it to h1 + editbone1.head= VecXFlip(h2) + + # Same as above for tail + if IS_XMIRROR_SOURCE(t1.x): + editbone2.tail= VecXFlip(t1) + else: + editbone1.tail= VecXFlip(t2) + + # Copy roll from 1 bone to another, use the head's location to decide which side it's on. + if IS_XMIRROR_SOURCE(editbone1.head): + editbone2.roll= -editbone1.roll + else: + editbone1.roll= -editbone2.roll + + +def armature_symetry(\ + arm_ob,\ + PREF_MAX_DIST,\ + PREF_XMID_SNAP,\ + PREF_XZERO_THRESH,\ + PREF_MODE_L2R,\ + PREF_MODE_R2L,\ + PREF_SEL_ONLY): + + ''' + Main function that does all the work, + return the number of + ''' + arm_data= arm_ob.data + arm_data.makeEditable() + + # Get the bones + bones= [] + HIDDEN_EDIT= Blender.Armature.HIDDEN_EDIT + BONE_SELECTED= Blender.Armature.BONE_SELECTED + + if PREF_SEL_ONLY: + for eb in arm_data.bones.values(): + options= eb.options + if HIDDEN_EDIT not in options and BONE_SELECTED in options: + bones.append(eb) + else: + # All non hidden bones + for eb in arm_data.bones.values(): + options= eb.options + if HIDDEN_EDIT not in options: + bones.append(eb) + + del HIDDEN_EDIT # remove temp variables + del BONE_SELECTED + + # Store the numder of bones we have modified for a message + tot_editbones= len(bones) + tot_editbones_modified= 0 + + if PREF_XMID_SNAP: + # Remove bones that are in the middle (X Zero) + # reverse loop so we can remove items in the list. + for eb_idx in xrange(len(bones)-1, -1, -1): + edit_bone= bones[eb_idx] + if abs(edit_bone.head.x) + abs(edit_bone.tail.x) <= PREF_XZERO_THRESH/2: + + # This is a center bone, clamp and remove from the bone list so we dont use again. + if edit_bone.tail.x or edit_bone.head.x: + tot_editbones_modified += 1 + + edit_bone.tail.x= edit_bone.head.x= 0 + del bones[eb_idx] + + + + + bone_comparisons= [] + + # Compare every bone with every other bone, shouldn't be too slow. + # These 2 "for" loops only compare once + for eb_idx_a in xrange(len(bones)-1, -1, -1): + edit_bone_a= bones[eb_idx_a] + for eb_idx_b in xrange(eb_idx_a-1, -1, -1): + edit_bone_b= bones[eb_idx_b] + # Error float the first value from editbone_mirror_diff() so we can sort the resulting list. + bone_comparisons.append(editbone_mirror_diff(edit_bone_a, edit_bone_b)) + + + bone_comparisons.sort() # best matches first + + # Make a dict() of bone names that have been used so we dont mirror more then once + bone_mirrored= {} + + for error, editbone1, editbone2 in bone_comparisons: + # print 'Trying to merge at error %.3f' % error + if error > PREF_MAX_DIST: + # print 'breaking, max error limit reached PREF_MAX_DIST: %.3f' % PREF_MAX_DIST + break + + if not bone_mirrored.has_key(editbone1.name) and not bone_mirrored.has_key(editbone2.name): + # Were not used, execute the mirror + editbone_mirror_merge(editbone1, editbone2, PREF_MODE_L2R, PREF_MODE_R2L) + # print 'Merging bones' + + # Add ourselves so we aren't touched again + bone_mirrored[editbone1.name] = None # dummy value, would use sets in python 2.4 + bone_mirrored[editbone2.name] = None + + # If both options are enabled, then we have changed 2 bones + tot_editbones_modified+= PREF_MODE_L2R + PREF_MODE_R2L + + arm_data.update() # get out of armature editmode + return tot_editbones, tot_editbones_modified + + +def main(): + ''' + User interface function that gets the options and calls armature_symetry() + ''' + + scn= bpy.data.scenes.active + arm_ob= scn.objects.active + + if not arm_ob or arm_ob.type!='Armature': + Blender.Draw.PupMenu('No Armature object selected.') + return + + # Cant be in editmode for armature.makeEditable() + is_editmode= Blender.Window.EditMode() + if is_editmode: Blender.Window.EditMode(0) + Draw= Blender.Draw + + # Defaults for the user input + PREF_XMID_SNAP= Draw.Create(1) + PREF_MAX_DIST= Draw.Create(0.4) + PREF_XZERO_THRESH= Draw.Create(0.02) + + PREF_MODE_L2R= Draw.Create(1) + PREF_MODE_R2L= Draw.Create(0) + PREF_SEL_ONLY= Draw.Create(1) + + pup_block = [\ + 'Left (-), Right (+)',\ + ('Left > Right', PREF_MODE_L2R, 'Copy from the Left to Right of the mesh. Enable Both for a mid loc.'),\ + ('Right > Left', PREF_MODE_R2L, 'Copy from the Right to Left of the mesh. Enable Both for a mid loc.'),\ + '',\ + ('MaxDist:', PREF_MAX_DIST, 0.0, 4.0, 'Maximum difference in mirror bones to match up pairs.'),\ + ('XZero limit:', PREF_XZERO_THRESH, 0.0, 2.0, 'Tolerance for locking bones into the middle (X/zero).'),\ + ('XMidSnap Bones', PREF_XMID_SNAP, 'Snap middle verts to X Zero (uses XZero limit)'),\ + ('Selected Only', PREF_SEL_ONLY, 'Only xmirror selected bones.'),\ + ] + + # Popup, exit if the user doesn't click OK + if not Draw.PupBlock("X Mirror mesh tool", pup_block): + return + + # Replace the variables with their button values. + PREF_XMID_SNAP= PREF_XMID_SNAP.val + PREF_MAX_DIST= PREF_MAX_DIST.val + PREF_MODE_L2R= PREF_MODE_L2R.val + PREF_MODE_R2L= PREF_MODE_R2L.val + PREF_XZERO_THRESH= PREF_XZERO_THRESH.val + PREF_SEL_ONLY= PREF_SEL_ONLY.val + + # If both are off assume mid-point and enable both + if not PREF_MODE_R2L and not PREF_MODE_L2R: + PREF_MODE_R2L= PREF_MODE_L2R= True + + + tot_editbones, tot_editbones_modified = armature_symetry(\ + arm_ob,\ + PREF_MAX_DIST,\ + PREF_XMID_SNAP,\ + PREF_XZERO_THRESH,\ + PREF_MODE_L2R,\ + PREF_MODE_R2L,\ + PREF_SEL_ONLY) + + if is_editmode: Blender.Window.EditMode(1) + + # Redraw all views before popup + Blender.Window.RedrawAll() + + # Print results + if PREF_SEL_ONLY: + msg= 'moved %i bones of %i selected' % (tot_editbones_modified, tot_editbones) + else: + msg= 'moved %i bones of %i visible' % (tot_editbones_modified, tot_editbones) + + + Blender.Draw.PupMenu(msg) + +# Check for __main__ so this function can be imported by other scripts without running the script. +if __name__=='__main__': + main() diff --git a/release/scripts/bevel_center.py b/release/scripts/bevel_center.py new file mode 100644 index 00000000000..0ea305a0120 --- /dev/null +++ b/release/scripts/bevel_center.py @@ -0,0 +1,474 @@ +#!BPY + +""" Registration info for Blender menus +Name: 'Bevel Center' +Blender: 243 +Group: 'Mesh' +Tip: 'Bevel selected faces, edges, and vertices' +""" + +__author__ = "Loic BERTHE" +__url__ = ("blender", "elysiun") +__version__ = "2.0" + +__bpydoc__ = """\ +This script implements vertex and edges bevelling in Blender. + +Usage: + +Select the mesh you want to work on, enter Edit Mode and select the edges +to bevel. Then run this script from the 3d View's Mesh->Scripts menu. + +You can control the thickness of the bevel with the slider -- redefine the +end points for bigger or smaller ranges. The thickness can be changed even +after applying the bevel, as many times as needed. + +For an extra smoothing after or instead of direct bevel, set the level of +recursiveness and use the "Recursive" button. + +This "Recursive" Button, won't work in face select mode, unless you choose +"faces" in the select mode menu. + +Notes:
+ You can undo and redo your steps just like with normal mesh operations in +Blender. +""" + +###################################################################### +# Bevel Center v2.0 for Blender + +# This script lets you bevel the selected vertices or edges and control the +# thickness of the bevel + +# (c) 2004-2006 Loïc Berthe (loic+blender@lilotux.net) +# released under Blender Artistic License + +###################################################################### + +import Blender +from Blender import NMesh, Window, Scene +from Blender.Draw import * +from Blender.Mathutils import * +from Blender.BGL import * +import BPyMessages +#PY23 NO SETS# +''' +try: + set() +except: + from sets import set +''' + +###################################################################### +# Functions to handle the global structures of the script NF, NE and NC +# which contain informations about faces and corners to be created + +global E_selected +E_selected = NMesh.EdgeFlags['SELECT'] + +old_dist = None + +def act_mesh_ob(): + scn = Scene.GetCurrent() + ob = scn.objects.active + if ob == None or ob.type != 'Mesh': + BPyMessages.Error_NoMeshActive() + return + + if ob.getData(mesh=1).multires: + BPyMessages.Error_NoMeshMultiresEdit() + return + + return ob + +def make_sel_vert(*co): + v= NMesh.Vert(*co) + v.sel = 1 + me.verts.append(v) + return v + +def make_sel_face(verts): + f = NMesh.Face(verts) + f.sel = 1 + me.addFace(f) + +def add_to_NV(old,dir,new): + try: + NV[old][dir] = new + except: + NV[old] = {dir:new} + +def get_v(old, *neighbors): + # compute the direction of the new vert + if len(neighbors) == 1: dir = (neighbors[0].co - old.co).normalize() + #dir + else: dir = (neighbors[0].co - old.co).normalize() + (neighbors[1].co-old.co).normalize() + + # look in NV if this vert already exists + key = tuple(dir) + if old in NV and key in NV[old] : return NV[old][key] + + # else, create it + new = old.co + dist.val*dir + v = make_sel_vert(new.x,new.y,new.z) + add_to_NV(old,key,v) + return v + +def make_faces(): + """ Analyse the mesh, make the faces corresponding to selected faces and + fill the structures NE and NC """ + + # make the differents flags consistent + for e in me.edges: + if e.flag & E_selected : + e.v1.sel = 1 + e.v2.sel = 1 + + NF =[] # NF : New faces + for f in me.faces: + V = f.v + nV = len(V) + enumV = range(nV) + E = [me.findEdge(V[i],V[(i+1) % nV]) for i in enumV] + Esel = [x.flag & E_selected for x in E] + + # look for selected vertices and creates a list containing the new vertices + newV = V[:] + changes = False + for (i,v) in enumerate(V): + if v.sel : + changes = True + if Esel[i-1] == 0 and Esel[i] == 1 : newV[i] = get_v(v,V[i-1]) + elif Esel[i-1] == 1 and Esel[i] == 0 : newV[i] = get_v(v,V[(i+1) % nV]) + elif Esel[i-1] == 1 and Esel[i] == 1 : newV[i] = get_v(v,V[i-1],V[(i+1) % nV]) + else : newV[i] = [get_v(v,V[i-1]),get_v(v,V[(i+1) % nV])] + + if changes: + # determine and store the face to be created + + lenV = [len(x) for x in newV] + if 2 not in lenV : + new_f = NMesh.Face(newV) + if sum(Esel) == nV : new_f.sel = 1 + NF.append(new_f) + + else : + nb2 = lenV.count(2) + + if nV == 4 : # f is a quad + if nb2 == 1 : + ind2 = lenV.index(2) + NF.append(NMesh.Face([newV[ind2-1],newV[ind2][0],newV[ind2][1],newV[ind2-3]])) + NF.append(NMesh.Face([newV[ind2-1],newV[ind2-2],newV[ind2-3]])) + + elif nb2 == 2 : + # We must know if the tuples are neighbours + ind2 = ''.join([str(x) for x in lenV+lenV[:1]]).find('22') + + if ind2 != -1 : # They are + NF.append(NMesh.Face([newV[ind2][0],newV[ind2][1],newV[ind2-3][0],newV[ind2-3][1]])) + NF.append(NMesh.Face([newV[ind2][0],newV[ind2-1],newV[ind2-2],newV[ind2-3][1]])) + + else: # They aren't + ind2 = lenV.index(2) + NF.append(NMesh.Face([newV[ind2][0],newV[ind2][1],newV[ind2-2][0],newV[ind2-2][1]])) + NF.append(NMesh.Face([newV[ind2][1],newV[ind2-3],newV[ind2-2][0]])) + NF.append(NMesh.Face([newV[ind2][0],newV[ind2-1],newV[ind2-2][1]])) + + elif nb2 == 3 : + ind2 = lenV.index(3) + NF.append(NMesh.Face([newV[ind2-1][1],newV[ind2],newV[ind2-3][0]])) + NF.append(NMesh.Face([newV[ind2-1][0],newV[ind2-1][1],newV[ind2-3][0],newV[ind2-3][1]])) + NF.append(NMesh.Face([newV[ind2-3][1],newV[ind2-2][0],newV[ind2-2][1],newV[ind2-1][0]])) + + else: + if (newV[0][1].co-newV[3][0].co).length + (newV[1][0].co-newV[2][1].co).length \ + < (newV[0][0].co-newV[1][1].co).length + (newV[2][0].co-newV[3][1].co).length : + ind2 = 0 + else : + ind2 = 1 + NF.append(NMesh.Face([newV[ind2-1][0],newV[ind2-1][1],newV[ind2][0],newV[ind2][1]])) + NF.append(NMesh.Face([newV[ind2][1],newV[ind2-3][0],newV[ind2-2][1],newV[ind2-1][0]])) + NF.append(NMesh.Face([newV[ind2-3][0],newV[ind2-3][1],newV[ind2-2][0],newV[ind2-2][1]])) + + else : # f is a tri + if nb2 == 1: + ind2 = lenV.index(2) + NF.append(NMesh.Face([newV[ind2-2],newV[ind2-1],newV[ind2][0],newV[ind2][1]])) + + elif nb2 == 2: + ind2 = lenV.index(3) + NF.append(NMesh.Face([newV[ind2-1][1],newV[ind2],newV[ind2-2][0]])) + NF.append(NMesh.Face([newV[ind2-2][0],newV[ind2-2][1],newV[ind2-1][0],newV[ind2-1][1]])) + + else: + ind2 = min( [((newV[i][1].co-newV[i-1][0].co).length, i) for i in enumV] )[1] + NF.append(NMesh.Face([newV[ind2-1][1],newV[ind2][0],newV[ind2][1],newV[ind2-2][0]])) + NF.append(NMesh.Face([newV[ind2-2][0],newV[ind2-2][1],newV[ind2-1][0],newV[ind2-1][1]])) + + # Preparing the corners + for i in enumV: + if lenV[i] == 2 : NC.setdefault(V[i],[]).append(newV[i]) + + + old_faces.append(f) + + # Preparing the Edges + for i in enumV: + if Esel[i]: + verts = [newV[i],newV[(i+1) % nV]] + if V[i].index > V[(i+1) % nV].index : verts.reverse() + NE.setdefault(E[i],[]).append(verts) + + # Create the faces + for f in NF: me.addFace(f) + +def make_edges(): + """ Make the faces corresponding to selected edges """ + + for old,new in NE.iteritems() : + if len(new) == 1 : # This edge was on a border + oldv = [old.v1, old.v2] + if old.v1.index < old.v2.index : oldv.reverse() + + make_sel_face(oldv+new[0]) + + me.findEdge(*oldv).flag |= E_selected + me.findEdge(*new[0]).flag |= E_selected + + #PY23 NO SETS# for v in oldv : NV_ext.add(v) + for v in oldv : NV_ext[v]= None + + else: + make_sel_face(new[0] + new[1][::-1]) + + me.findEdge(*new[0]).flag |= E_selected + me.findEdge(*new[1]).flag |= E_selected + +def make_corners(): + """ Make the faces corresponding to corners """ + + for v in NV.iterkeys(): + V = NV[v].values() + nV = len(V) + + if nV == 1: pass + + elif nV == 2 : + #PY23 NO SETS# if v in NV_ext: + if v in NV_ext.iterkeys(): + make_sel_face(V+[v]) + me.findEdge(*V).flag |= E_selected + + else: + #PY23 NO SETS# if nV == 3 and v not in NV_ext : make_sel_face(V) + if nV == 3 and v not in NV_ext.iterkeys() : make_sel_face(V) + + + else : + + # We need to know which are the edges around the corner. + # First, we look for the quads surrounding the corner. + eed = [] + for old, new in NE.iteritems(): + if v in (old.v1,old.v2) : + if v.index == min(old.v1.index,old.v2.index) : ind = 0 + else : ind = 1 + + if len(new) == 1: eed.append([v,new[0][ind]]) + else : eed.append([new[0][ind],new[1][ind]]) + + # We will add the edges coming from faces where only one vertice is selected. + # They are stored in NC. + if v in NC: eed = eed+NC[v] + + # Now we have to sort these vertices + hc = {} + for (a,b) in eed : + hc.setdefault(a,[]).append(b) + hc.setdefault(b,[]).append(a) + + for x0,edges in hc.iteritems(): + if len(edges) == 1 : break + + b = [x0] # b will contain the sorted list of vertices + + for i in xrange(len(hc)-1): + for x in hc[x0] : + if x not in b : break + b.append(x) + x0 = x + + b.append(b[0]) + + # Now we can create the faces + if len(b) == 5: make_sel_face(b[:4]) + + else: + New_V = Vector(0.0, 0.0,0.0) + New_d = [0.0, 0.0,0.0] + + for x in hc.iterkeys(): New_V += x.co + for dir in NV[v] : + for i in xrange(3): New_d[i] += dir[i] + + New_V *= 1./len(hc) + for i in xrange(3) : New_d[i] /= nV + + center = make_sel_vert(New_V.x,New_V.y,New_V.z) + add_to_NV(v,tuple(New_d),center) + + for k in xrange(len(b)-1): make_sel_face([center, b[k], b[k+1]]) + + if 2 < nV and v in NC : + for edge in NC[v] : me.findEdge(*edge).flag |= E_selected + +def clear_old(): + """ Erase old faces and vertices """ + + for f in old_faces: me.removeFace(f) + + for v in NV.iterkeys(): + #PY23 NO SETS# if v not in NV_ext : me.verts.remove(v) + if v not in NV_ext.iterkeys() : me.verts.remove(v) + + for e in me.edges: + if e.flag & E_selected : + e.v1.sel = 1 + e.v2.sel = 1 + + +###################################################################### +# Interface + +global dist + +dist = Create(0.2) +left = Create(0.0) +right = Create(1.0) +num = Create(2) + +# Events +EVENT_NOEVENT = 1 +EVENT_BEVEL = 2 +EVENT_UPDATE = 3 +EVENT_RECURS = 4 +EVENT_EXIT = 5 + +def draw(): + global dist, left, right, num, old_dist + global EVENT_NOEVENT, EVENT_BEVEL, EVENT_UPDATE, EVENT_RECURS, EVENT_EXIT + + glClear(GL_COLOR_BUFFER_BIT) + Button("Bevel",EVENT_BEVEL,10,100,280,25) + + BeginAlign() + left=Number('', EVENT_NOEVENT,10,70,45, 20,left.val,0,right.val,'Set the minimum of the slider') + dist=Slider("Thickness ",EVENT_UPDATE,60,70,180,20,dist.val,left.val,right.val,0, \ + "Thickness of the bevel, can be changed even after bevelling") + right = Number("",EVENT_NOEVENT,245,70,45,20,right.val,left.val,200,"Set the maximum of the slider") + + EndAlign() + glRasterPos2d(8,40) + Text('To finish, you can use recursive bevel to smooth it') + + + if old_dist != None: + num=Number('', EVENT_NOEVENT,10,10,40, 16,num.val,1,100,'Recursion level') + Button("Recursive",EVENT_RECURS,55,10,100,16) + + Button("Exit",EVENT_EXIT,210,10,80,20) + +def event(evt, val): + if ((evt == QKEY or evt == ESCKEY) and not val): Exit() + +def bevent(evt): + if evt == EVENT_EXIT : Exit() + elif evt == EVENT_BEVEL : bevel() + elif evt == EVENT_UPDATE : + try: bevel_update() + except NameError : pass + elif evt == EVENT_RECURS : recursive() + +Register(draw, event, bevent) + +###################################################################### +def bevel(): + """ The main function, which creates the bevel """ + global me,NV,NV_ext,NE,NC, old_faces,old_dist + + ob = act_mesh_ob() + if not ob: return + + Window.WaitCursor(1) # Change the Cursor + t= Blender.sys.time() + is_editmode = Window.EditMode() + if is_editmode: Window.EditMode(0) + + me = ob.data + + NV = {} + #PY23 NO SETS# NV_ext = set() + NV_ext= {} + NE = {} + NC = {} + old_faces = [] + + make_faces() + make_edges() + make_corners() + clear_old() + + old_dist = dist.val + print '\tbevel in %.6f sec' % (Blender.sys.time()-t) + me.update(1) + if is_editmode: Window.EditMode(1) + Window.WaitCursor(0) + Blender.Redraw() + +def bevel_update(): + """ Use NV to update the bevel """ + global dist, old_dist + + if old_dist == None: + # PupMenu('Error%t|Must bevel first.') + return + + is_editmode = Window.EditMode() + if is_editmode: Window.EditMode(0) + + fac = dist.val - old_dist + old_dist = dist.val + + for old_v in NV.iterkeys(): + for dir in NV[old_v].iterkeys(): + for i in xrange(3): + NV[old_v][dir].co[i] += fac*dir[i] + + me.update(1) + if is_editmode: Window.EditMode(1) + Blender.Redraw() + +def recursive(): + """ Make a recursive bevel... still experimental """ + global dist + from math import pi, sin + + if num.val > 1: + a = pi/4 + ang = [] + for k in xrange(num.val): + ang.append(a) + a = (pi+2*a)/4 + + l = [2*(1-sin(x))/sin(2*x) for x in ang] + R = dist.val/sum(l) + l = [x*R for x in l] + + dist.val = l[0] + bevel_update() + + for x in l[1:]: + dist.val = x + bevel() + diff --git a/release/scripts/blenderLipSynchro.py b/release/scripts/blenderLipSynchro.py new file mode 100644 index 00000000000..ef765086e25 --- /dev/null +++ b/release/scripts/blenderLipSynchro.py @@ -0,0 +1,729 @@ +#!BPY + +""" +Name: 'BlenderLipSynchro' +Blender: 242 +Group: 'Animation' +Tooltip: 'Import phonemes from Papagayo or JLipSync for lip synchronization' +""" + +__author__ = "Dienben: Benoit Foucque dienben_mail@yahoo.fr" +__url__ = ["blenderLipSynchro Blog, http://blenderlipsynchro.blogspot.com/", +"Papagayo (Python), http://www.lostmarble.com/papagayo/index.shtml", +"JLipSync (Java), http://jlipsync.sourceforge.net/"] +__version__ = "2.0" +__bpydoc__ = """\ +Description: + +This script imports Voice Export made by Papagayo or JLipSync and maps the export with your shapes. + +Usage: + +Import a Papagayo or JLipSync voice export file and link it with your shapes. + +Note:
+- Naturally, you need files exported from one of the supported lip synching +programs. Check their sites to learn more and download them. + +""" + +# -------------------------------------------------------------------------- +# BlenderLipSynchro +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + + +#il y a 3 etapes +#la deuxieme on charge le dictionnaire de correspondance +#la troisieme on fait le choix des correpondance +#la quatrieme on construit les cles a partir du fichiers frame + +#there are 3 stages +#the second one load the mapping dictionnary +#the tird make the mapping +#the fourth make the key in the IPO Curve + +#voici mes differents imports +#the imports +import os +import Blender + +from Blender import Ipo +from Blender.Draw import * +from Blender.BGL import * +from Blender.sys import basename + + + +#ici commencent mes fonctions +#here begin my functions +#cette fonction trace l'interface graphique +#this functions draw the User interface +def trace(): + #voici mes variables pouvant etre modifie + #my variables + global nbr_phoneme, mon_fichier_dico + global let01, let02, let03, let04,let05, let06, let07, let08, let09, let10 + global let11, let12, let13, let14,let15, let16, let17, let18, let19, let20 + global let21, let22, let23, let24 + + global let01selectkey,let02selectkey,let03selectkey,let04selectkey,let05selectkey + global let06selectkey,let07selectkey,let08selectkey,let09selectkey,let10selectkey,let11selectkey + global let12selectkey,let13selectkey,let14selectkey,let15selectkey,let16selectkey,let17selectkey + global let18selectkey,let19selectkey,let20selectkey,let21selectkey,let22selectkey,let23selectkey + global let24selectkey + + glClearColor(0.4,0.5,0.6 ,0.0) + glClear(GL_COLOR_BUFFER_BIT) + + glColor3d(1,1,1) + glRasterPos2i(87, 375) + Text("Blendersynchro V 2.0") + glColor3d(1,1,1) + glRasterPos2i(84, 360) + Text("Programming: Dienben") + + glColor3d(0,0,0) + glRasterPos2i(13, 342) + Text("Lip Synchronization Tool") + glColor3d(0,0,0) + glRasterPos2i(13, 326) + Text("Thanks to Chris Clawson and Liubomir Kovatchev") + + glColor3d(1,1,1) + glRasterPos2i(5, 320) + Text("_______________________________________________________") + glColor3d(0,0,0) + glRasterPos2i(6, 318) + Text("_______________________________________________________") + + + if (etape==1): + #cette etape permet de choisi la correspondance entre les phonemes et les cles + #this stage offer the possibility to choose the mapping between phonems and shapes + + glColor3d(1,1,1) + glRasterPos2i(140, 300) + Text("Objet: "+Blender.Object.GetSelected()[0].getName() ) + + glColor3d(1,1,1) + glRasterPos2i(5, 215) + Text("Assign phonems to shapes:") + + #on mesure la taille de la liste de phonemes + #this is the lenght of the phonem list + nbr_phoneme=len(liste_phoneme) + + #on dessine les listes de choix + #we draw the choice list + + # + if (nbr_phoneme > 0): + let01 = String(" ", 4, 5, 185, 30, 16, liste_phoneme[0], 3) + glColor3d(0,0,0) + glRasterPos2i(40, 188) + Text("=") + let01selectkey = Menu(key_menu, 50, 50, 185, 70, 16, let01selectkey.val) + + # + if (nbr_phoneme > 1): + let02 = String(" ", 4, 150, 185, 30, 16, liste_phoneme[1], 2) + glColor3d(0,0,0) + glRasterPos2i(185, 188) + Text("=") + let02selectkey = Menu(key_menu, 51, 195, 185, 70, 16, let02selectkey.val) + + # + if (nbr_phoneme > 2): + let03 = String(" ", 4, 5, 165, 30, 16, liste_phoneme[2], 2) + glColor3d(0,0,0) + glRasterPos2i(40, 168) + Text("=") + let03selectkey = Menu(key_menu, 52, 50, 165, 70, 16, let03selectkey.val) + + # + if (nbr_phoneme > 3): + let04 = String(" ", 4, 150, 165, 30, 16, liste_phoneme[3], 2) + glColor3d(0,0,0) + glRasterPos2i(185, 168) + Text("=") + let04selectkey = Menu(key_menu, 53, 195, 165, 70, 16, let04selectkey.val) + + # + if (nbr_phoneme > 4): + let05 = String(" ", 4, 5, 145, 30, 16, liste_phoneme[4], 2) + glColor3d(0,0,0) + glRasterPos2i(40, 148) + Text("=") + let05selectkey = Menu(key_menu, 54, 50, 145, 70, 16, let05selectkey.val) + + # + if (nbr_phoneme > 5): + let06 = String(" ", 4, 150, 145, 30, 16, liste_phoneme[5], 2) + glColor3d(0,0,0) + glRasterPos2i(185, 148) + Text("=") + let06selectkey = Menu(key_menu, 55, 195, 145, 70, 16, let06selectkey.val) + + # + if (nbr_phoneme > 6): + let07 = String(" ", 4, 5, 125, 30, 16, liste_phoneme[6], 2) + glColor3d(0,0,0) + glRasterPos2i(40, 128) + Text("=") + let07selectkey = Menu(key_menu, 56, 50, 125, 70, 16, let07selectkey.val) + + # + if (nbr_phoneme > 7): + let08 = String(" ", 4, 150, 125, 30, 16, liste_phoneme[7], 2) + glColor3d(0,0,0) + glRasterPos2i(185, 128) + Text("=") + let08selectkey = Menu(key_menu, 57, 195, 125, 70, 16,let08selectkey.val) + + # + if (nbr_phoneme > 8): + let09 = String(" ", 4, 5, 105, 30, 16, liste_phoneme[8], 2) + glColor3d(0,0,0) + glRasterPos2i(40, 108) + Text("=") + let09selectkey = Menu(key_menu, 58, 50, 105, 70, 16,let09selectkey.val) + + # + if (nbr_phoneme > 9): + let10 = String(" ", 4, 150, 105, 30, 16, liste_phoneme[9], 2) + glColor3d(0,0,0) + glRasterPos2i(185, 108) + Text("=") + let10selectkey = Menu(key_menu, 59, 195, 105, 70, 16, let10selectkey.val) + + # + if (nbr_phoneme > 10): + let11 = String(" ", 4, 5, 85, 30, 16, liste_phoneme[10], 2) + glColor3d(0,0,0) + glRasterPos2i(40, 88) + Text("=") + let11selectkey = Menu(key_menu, 60, 50, 85, 70, 16, let11selectkey.val) + + # + if (nbr_phoneme > 11): + let12 = String(" ", 4, 150, 85, 30, 16, liste_phoneme[11], 2) + glColor3d(0,0,0) + Text("=") + let12selectkey = Menu(key_menu, 61, 195, 85, 70, 16, let12selectkey.val) + + # + if (nbr_phoneme > 12): + let13 = String(" ", 4, 5, 65, 30, 16, liste_phoneme[12], 2) + glColor3d(0,0,0) + glRasterPos2i(40, 68) + Text("=") + let13selectkey = Menu(key_menu, 62, 50, 65, 70, 16, let13selectkey.val) + + # + if (nbr_phoneme > 13): + let14 = String(" ", 4, 150, 65, 30, 16, liste_phoneme[13], 2) + glColor3d(0,0,0) + glRasterPos2i(185, 68) + Text("=") + let14selectkey = Menu(key_menu, 63, 195, 65, 70, 16, let14selectkey.val) + + # + if (nbr_phoneme > 14): + let15 = String(" ", 4, 5, 45, 30, 16, liste_phoneme[14], 2) + glColor3d(0,0,0) + glRasterPos2i(40, 48) + Text("=") + let15selectkey = Menu(key_menu, 64, 50, 45, 70, 16, let15selectkey.val) + + # + if (nbr_phoneme > 15): + let16 = String(" ", 4, 150, 45, 30, 16, liste_phoneme[15], 2) + glColor3d(0,0,0) + glRasterPos2i(185, 48) + Text("=") + let16selectkey = Menu(key_menu, 65, 195, 45, 70, 16, let16selectkey.val) + + # + if (nbr_phoneme > 16): + let17 = String(" ", 4, 295, 185, 30, 16, liste_phoneme[16], 2) + glColor3d(0,0,0) + glRasterPos2i(330, 188) + Text("=") + let17selectkey = Menu(key_menu, 66, 340, 185, 70, 16, let17selectkey.val) + + # + if (nbr_phoneme > 17): + let18 = String(" ", 4, 440, 185, 70, 16, liste_phoneme[17], 8) + glColor3d(0,0,0) + glRasterPos2i(515, 188) + Text("=") + let18selectkey = Menu(key_menu, 67, 525, 185, 70, 16, let18selectkey.val) + + # + if (nbr_phoneme > 18): + let19 = String(" ", 4, 295, 165, 30, 16, liste_phoneme[18], 2) + glColor3d(0,0,0) + glRasterPos2i(330, 168) + Text("=") + let19selectkey = Menu(key_menu, 68, 340, 165, 70, 16, let19selectkey.val) + + # + if (nbr_phoneme > 19): + let20 = String(" ", 4, 440, 165, 70, 16, liste_phoneme[19], 8) + glColor3d(0,0,0) + glRasterPos2i(515, 168) + Text("=") + let20selectkey = Menu(key_menu, 69, 525, 165, 70, 16, let20selectkey.val) + + # + if (nbr_phoneme > 20): + let21 = String(" ", 4, 295, 145, 30, 16, liste_phoneme[20], 2) + glColor3d(0,0,0) + glRasterPos2i(330, 148) + Text("=") + let21selectkey = Menu(key_menu, 70, 340, 145, 70, 16, let21selectkey.val) + + # + if (nbr_phoneme > 21): + let22 = String(" ", 4, 440, 145, 70, 16, liste_phoneme[21], 8) + glColor3d(0,0,0) + glRasterPos2i(515, 148) + Text("=") + let22selectkey = Menu(key_menu, 71, 525, 145, 70, 16, let22selectkey.val) + + # + if (nbr_phoneme > 22): + let23 = String(" ", 4, 295, 125, 30, 16, liste_phoneme[22], 2) + glColor3d(0,0,0) + glRasterPos2i(330, 128) + Text("=") + let23selectkey = Menu(key_menu, 72, 340, 125, 70, 16,let23selectkey.val) + + # + if (nbr_phoneme > 23): + let24 = String(" ", 4, 440, 125, 70, 16, liste_phoneme[23], 8) + glColor3d(0,0,0) + glRasterPos2i(515, 128) + Text("=") + let24selectkey = Menu(key_menu, 73, 525, 125, 70, 16, let24selectkey.val) + + # + if (nbr_phoneme > 24): + let25 = String(" ", 4, 295, 105, 30, 16, liste_phoneme[24], 2) + glColor3d(0,0,0) + glRasterPos2i(330, 108) + Text("=") + let25selectkey = Menu(key_menu, 74, 340, 105, 70, 16, let25selectkey.val) + + # + if (nbr_phoneme > 25): + let26 = String(" ", 4, 440, 105, 70, 16, liste_phoneme[25], 8) + glColor3d(0,0,0) + glRasterPos2i(515, 108) + Text("=") + let26selectkey = Menu(key_menu, 75, 525, 105, 70, 16,let26selectkey.val) + + # + if (nbr_phoneme > 26): + let27 = String(" ", 4, 295, 85, 30, 16, liste_phoneme[26], 2) + glColor3d(0,0,0) + glRasterPos2i(330, 88) + Text("=") + let27selectkey = Menu(key_menu, 76, 340, 85, 70, 16, let27selectkey.val) + + # + if (nbr_phoneme > 27): + let28 = String(" ", 4, 440, 85, 70, 16, liste_phoneme[27], 8) + glColor3d(0,0,0) + glRasterPos2i(515, 88) + Text("=") + let28selectkey = Menu(key_menu, 77, 525, 85, 70, 16,let28selectkey.val) + + # + if (nbr_phoneme > 28): + let29 = String(" ", 4, 295, 65, 30, 16, liste_phoneme[28], 2) + glColor3d(0,0,0) + glRasterPos2i(330, 68) + Text("=") + let29selectkey = Menu(key_menu, 78, 340, 65, 70, 16, let29selectkey.val) + + # + if (nbr_phoneme > 29): + let30 = String(" ", 4, 440, 65, 70, 16, liste_phoneme[29], 8) + glColor3d(0,0,0) + glRasterPos2i(515, 68) + Text("=") + let30selectkey = Menu(key_menu, 79, 525, 65, 70, 16, let30selectkey.val) + + # + if (nbr_phoneme > 30): + let31 = String(" ", 4, 295, 45, 30, 16, liste_phoneme[30], 2) + glColor3d(0,0,0) + glRasterPos2i(330, 48) + Text("=") + let31selectkey = Menu(key_menu, 80, 340, 45, 70, 16, let31selectkey.val) + + # + if (nbr_phoneme > 31): + let32 = String(" ", 4, 440, 45, 70, 16, liste_phoneme[31], 8) + glColor3d(0,0,0) + glRasterPos2i(515, 48) + Text("=") + let32selectkey = Menu(key_menu, 81, 525, 45, 70, 16, let32selectkey.val) + + Button("Go", 3, 155, 5, 145, 22) + + if (etape==2): + glColor3d(1,1,1) + glRasterPos2i(125, 200) + Text("Operation Completed") + + if (etape==0): + glColor3d(1,1,1) + glRasterPos2i(125, 200) + Text("Please select a Mesh'Object and Create all the IPO Curves for your Shapes") + + if (etape==3): + #this stage permits to load a custom dictionnary + load_file_text = "Load File" + if mon_fichier_dico: + Button("Import Loaded File", 2, 5, 5, 145, 22) + glColor3d(1,1,1) + glRasterPos2i(6, 50) + Text("loaded file: %s" % basename(mon_fichier_dico)) + load_file_text = "Choose Another File" + Button(load_file_text, 8, 125, 180, 145, 22) + + glRasterPos2i(6, 40) + Text("_______________________________________________________") + glColor3d(0,0,0) + glRasterPos2i(6, 38) + Text("_______________________________________________________") + + Button("Exit", 1, 305, 5, 80, 22) + + + +#cette fonction sur evenement quite en cas d'ESC +#this functions catch the ESC event and quit +def event(evt,val): + if (evt == ESCKEY and not val): Exit() + +#cette fonction gere les evenements +#the event functions +def bevent(evt): + global etape,soft_type,liste_phoneme,dico_phoneme_export + + if (evt == 1): + Exit() + + elif (evt == 2): + #c'est l'import du dictionnaire + #we create and import the dictionnary + lecture_chaine(mon_fichier_dico,dico_phoneme_export) + construction_dictionnaire_phoneme() + #we change the stage + etape=1 + + elif (evt == 3): + #c'est l'import + #we import + lecture_chaine(mon_fichier_export,dico_phoneme_export) + construction_dico_correspondance() + construction_lipsynchro() + #on change d'etape + #we change the stage + etape=2 + + elif (evt == 8): + #we choose the file + Blender.Window.FileSelector(selectionner_fichier,"Select File") + + Blender.Redraw() + +#cette fonction recupere le nom et le chemin du fichier dictionnaire +#we catch the name and the path of the dictionnary +def selectionner_fichier(filename): + global mon_fichier_dico,mon_fichier_export + mon_fichier_dico=filename + mon_fichier_export=filename + +#fonction de lecture de la liste frame phoneme +#we read the frame and phonems +def lecture_chaine(fichier,liste): + mon_fichier=open(fichier) + #je lis la premiere ligne qui contiens la version de moho + #first, we read the moho version + mon_fichier.readline() + + #je lis jusqu'a la fin + #then we read until the end of the file + while 1: + ma_ligne=mon_fichier.readline() + if ma_ligne=='': + break + decoup=ma_ligne.split() + liste[decoup[0]]=decoup[1] + print liste + + + + +#fonction qui construit la liste dictionnaire simple +#we make the dictionnary +def construction_dictionnaire_phoneme(): + global liste_phoneme + index_liste=0 + #je transforme mon dictionnaire en list de tulpes + #we transform the list in tulpes + ma_liste=dico_phoneme_export.items() + #je parcours ma liste a la recherche d'elements non existant + #we read the list to find non existing elements + print dico_phoneme + for index in range(len(ma_liste)): + if ma_liste[index][1] not in liste_phoneme: + liste_phoneme[index_liste:index_liste]=[ma_liste[index][1]] + index_liste=index_liste+1 + print liste_phoneme + + +#cette fonction recupere les courbes cible +#this functon catch the IPO curve +def recuperation_courbe(): + global key_menu,dico_key + + #on recupere le nom des shapes + #we catch the shapes + key=Blender.Object.GetSelected()[0].getData().getKey().getBlocks() + for n in range(len(key)): + #on vire la première cle (en effet basic n'est pas une cle en tant que telle) + #we threw away the basic shapes + if (n>0): + key_menu=key_menu+key[n].name + " %x" + str(n-1) + "|" + dico_key[str(n-1)]=Blender.Object.GetSelected()[0].getData().getKey().getIpo().getCurves()[n-1] + + + print "dico_key" + print dico_key + print 'end dico_key' + +#cette fonction construit un dictionnaire de correspondance entre les phonemes prononces et les cles a utiliser +#we make the dictionnary for the mapping between shapes and phonems +def construction_dico_correspondance(): + global dico_correspondance + #je parcours les phonemes + #we read the phonems + if (nbr_phoneme>0): + dico_correspondance[liste_phoneme[0]]=dico_key[str(let01selectkey.val)] + if (nbr_phoneme>1): + dico_correspondance[liste_phoneme[1]]=dico_key[str(let02selectkey.val)] + if (nbr_phoneme>2): + dico_correspondance[liste_phoneme[2]]=dico_key[str(let03selectkey.val)] + if (nbr_phoneme>3): + dico_correspondance[liste_phoneme[3]]=dico_key[str(let04selectkey.val)] + if (nbr_phoneme>4): + dico_correspondance[liste_phoneme[4]]=dico_key[str(let05selectkey.val)] + if (nbr_phoneme>5): + dico_correspondance[liste_phoneme[5]]=dico_key[str(let06selectkey.val)] + if (nbr_phoneme>6): + dico_correspondance[liste_phoneme[6]]=dico_key[str(let07selectkey.val)] + if (nbr_phoneme>7): + dico_correspondance[liste_phoneme[7]]=dico_key[str(let08selectkey.val)] + if (nbr_phoneme>8): + dico_correspondance[liste_phoneme[8]]=dico_key[str(let09selectkey.val)] + if (nbr_phoneme>9): + dico_correspondance[liste_phoneme[9]]=dico_key[str(let10selectkey.val)] + if (nbr_phoneme>10): + dico_correspondance[liste_phoneme[10]]=dico_key[str(let11selectkey.val)] + if (nbr_phoneme>11): + dico_correspondance[liste_phoneme[11]]=dico_key[str(let12selectkey.val)] + if (nbr_phoneme>12): + dico_correspondance[liste_phoneme[12]]=dico_key[str(let13selectkey.val)] + if (nbr_phoneme>13): + dico_correspondance[liste_phoneme[13]]=dico_key[str(let14selectkey.val)] + if (nbr_phoneme>14): + dico_correspondance[liste_phoneme[14]]=dico_key[str(let15selectkey.val)] + if (nbr_phoneme>15): + dico_correspondance[liste_phoneme[15]]=dico_key[str(let16selectkey.val)] + if (nbr_phoneme>16): + dico_correspondance[liste_phoneme[16]]=dico_key[str(let17selectkey.val)] + if (nbr_phoneme>17): + dico_correspondance[liste_phoneme[17]]=dico_key[str(let18selectkey.val)] + if (nbr_phoneme>18): + dico_correspondance[liste_phoneme[18]]=dico_key[str(let19selectkey.val)] + if (nbr_phoneme>19): + dico_correspondance[liste_phoneme[19]]=dico_key[str(let20selectkey.val)] + if (nbr_phoneme>20): + dico_correspondance[liste_phoneme[20]]=dico_key[str(let21selectkey.val)] + if (nbr_phoneme>21): + dico_correspondance[liste_phoneme[21]]=dico_key[str(let22selectkey.val)] + if (nbr_phoneme>22): + dico_correspondance[liste_phoneme[22]]=dico_key[str(let23selectkey.val)] + if (nbr_phoneme>23): + dico_correspondance[liste_phoneme[23]]=dico_key[str(let24selectkey.val)] + if (nbr_phoneme>24): + dico_correspondance[liste_phoneme[24]]=dico_key[str(let25selectkey.val)] + if (nbr_phoneme>25): + dico_correspondance[liste_phoneme[25]]=dico_key[str(let26selectkey.val)] + if (nbr_phoneme>26): + dico_correspondance[liste_phoneme[26]]=dico_key[str(let27selectkey.val)] + if (nbr_phoneme>27): + dico_correspondance[liste_phoneme[27]]=dico_key[str(let28selectkey.val)] + if (nbr_phoneme>28): + dico_correspondance[liste_phoneme[28]]=dico_key[str(let29selectkey.val)] + if (nbr_phoneme>29): + dico_correspondance[liste_phoneme[29]]=dico_key[str(let30selectkey.val)] + if (nbr_phoneme>30): + dico_correspondance[liste_phoneme[30]]=dico_key[str(let31selectkey.val)] + if (nbr_phoneme>31): + dico_correspondance[liste_phoneme[31]]=dico_key[str(let32selectkey.val)] + + print dico_correspondance + + +#cette fonction ajoute un points a la cle donnee a la frame donnee +#we add a point to the IPO curve Target +def ajoute_point(cle,frame,valeur): + cle.setInterpolation('Linear') + cle.append((frame,valeur)) + cle.Recalc() + +#cette fonction parcours le dictionnaire des frame à ajouter et construit les points +#we add all the point to the IPO Curve +def construction_lipsynchro(): + print "je construit" + doublet_old="" + #construction de la liste des frame + cpt=0 + liste_frame=[] + for frame in dico_phoneme_export: + liste_frame.append(int(frame)) + cpt=cpt+1 + liste_frame.sort() + print "listeframe" + print liste_frame + print "fini" + + for doublet in liste_frame: + ajoute_point(dico_correspondance[dico_phoneme_export[str(doublet)]],doublet,1) + if (doublet_old==""): + ajoute_point(dico_correspondance[dico_phoneme_export[str(doublet)]],(doublet-2),0) + if (doublet_old!=''): + if (dico_correspondance[dico_phoneme_export[str(doublet)]]!=dico_correspondance[dico_phoneme_export[doublet_old]]): + print "doublet:"+str(doublet) + print "doublet old:"+doublet_old + ajoute_point(dico_correspondance[dico_phoneme_export[doublet_old]],(int(doublet_old)+2),0) + ajoute_point(dico_correspondance[dico_phoneme_export[str(doublet)]],(doublet-2),0) + doublet_old=str(doublet) + + +#end of my functions we begin the execution +#je commence l execution----------------------------------------------------------------------------------------------- +#voici mes variables + +#declaration et instanciation +#decleration and instanciation + + +#voici mon objet de travail +objet_travail=Create(0) + +#my soft type +soft_type=1 + +#voici la liste des phoneme effectivement utilise +#the phonems'list +#liste_phoneme_papagayo=['AI','E','O','U','FV','L','WQ','MBP','etc','rest'] +#liste_phoneme_jlipsinch=['A','B','C','Closed','D','E','F','G','I','K','L','M','N','O','P','Q','R','S','SH','T','TH','U','V','W'] + +liste_phoneme=[] +#voici mon dictionnaire des frames o +dico_phoneme_export = Create(0) +dico_phoneme_export={} +dico_phoneme={} + + +#voici mes cle +key_menu="" +dico_key={} + +#voici mes ipo +dico_bloc={} +iponame = Create(0) + +#voici mon dictionnaire de correspondance +dico_correspondance={} + +try: + #on verifie est bien une mesh et qu'il a des courbes + if ((Blender.Object.GetSelected()[0].getType()=='Mesh')): + #on verifie que l'objet a bien toute ses Courbes + if (len(Blender.Object.GetSelected()[0].getData().getKey().getBlocks())-1==Blender.Object.GetSelected()[0].getData().getKey().getIpo().getNcurves()): + etape=3 + #on lance la creation du dictionnaire + recuperation_courbe() + else: + print "not the good number of IPO Curve" + etape = 0 + else: + print "error: bad object Type:" + print Blender.Object.GetSelected()[0].getType() + etape = 0 +except: + print 'error: exception' + etape = 0 + + +#voici le fichier dictionnaire +mon_fichier_dico="" + +#voici le fichier export pamela +mon_fichier_export="" + + +let01selectkey = Create(0) +let02selectkey = Create(0) +let03selectkey = Create(0) +let04selectkey = Create(0) +let05selectkey = Create(0) +let06selectkey = Create(0) +let07selectkey = Create(0) +let08selectkey = Create(0) +let09selectkey = Create(0) +let10selectkey = Create(0) +let11selectkey = Create(0) +let12selectkey = Create(0) +let13selectkey = Create(0) +let14selectkey = Create(0) +let15selectkey = Create(0) +let16selectkey = Create(0) +let17selectkey = Create(0) +let18selectkey = Create(0) +let19selectkey = Create(0) +let20selectkey = Create(0) +let21selectkey = Create(0) +let22selectkey = Create(0) +let23selectkey = Create(0) +let24selectkey = Create(0) + + +Register (trace,event,bevent) diff --git a/release/scripts/bpydata/KUlang.txt b/release/scripts/bpydata/KUlang.txt new file mode 100644 index 00000000000..38605d69c9f --- /dev/null +++ b/release/scripts/bpydata/KUlang.txt @@ -0,0 +1,121 @@ +Version 3.233-2004 +****************** +Espanol +Sale del programa +Utilidades de...%t|Alinea objetos%x1|Creacion%x2|Edita mallas%x3|Edita objetos%x4 +11 +Mov +Esc +Encaja +Abarca +Separa +Alinea +Rota +Incr. +Crea nuevos objetos +Es+ +Es* +Separar entre:%t|Origenes%x1|Centros geometricos%x2|Minimos%x3|Maximos%x4|Baricentro%x5|Objetos%x6 +Crear%t|Arco (3 ptos.)%x1|Arco (interactivo)%x2|Circunferencia (3 ptos.)%x3 +12 +Puntos +Centro +Orden +Objeto +AngIni: +AngFin: +Angulo: +Radio: +Puntos: +Centro +Nombre: +Puntos +Modifica vertices%t|Subdivide%x1|Envia a un plano%x2|Aplica LocRotSize%x3 +Partes +Proyectar en el plano:%t|Coordenado global...%x1|Coordenado local...%x2 +Actuar sobre el plano%t|Yz%x1|Zx%x2|Xy%x3 +En la dirección%t|X%x1|Y%x2|Z%x3|Ortogonal al plano%x4 +Captura +Buffer%t|Copia vector diferencia%x1|Copia distancia%x2|Copia diferencia de rotacion%x3|Copia media LocRotSiz%x4|Ver buffer en consola%x5 +Transformar LocRotSize%t|Hacia el obj. activo%x1|Aleatoriamente%x2 +Poner a distancia fija%x1|Sumar (desp. absoluto)%x2|Multiplicar (desp. relativo)%x3 +******************** +English +Exit program +Utils about:%t|Align Objects%x1|Create%x2|Edit Meshes%x3|Edit Objects%x4 +11 +Mov +Sca +Fit +Embrace +Separate +Align +Rota +Incr. +Create new objects +Sc+ +Sc* +Separate between:%t|Origins%x1|Geometric centers%x2|Minimum%x3|Maximum%x4|Baricenter%x5|Objects%x6 +Create what%t|Arc (3 pts.)%x1|Arc (interactive)%x2|Circunference (3 pts.)%x3 +12 +Points +Centre +Sort +Object +AngIni: +AngEnd: +Angle: +Radius: +Points: +Centre +ObjName: +Points +Modify vertices%t|Subdivide edges%x1|Send to a plane%x2|Set LocRotSize%x3 +Parts +Project onto the plane:%t|Global coordinated...%x1|Local coordinated...%x2 +Act on plane%t|Yz%x1|Zx%x2|Xy%x3 +In direction%t|X%x1|Y%x2|Z%x3|Ortogonal to plane%x4 +Get +Buffer%t|Copy diference vector%x1|Copy distance%x2|Copy rot diference%x3|Copy LocRotSiz average%x4|Show Buffer in Console%x5 +Transform LocRotSize%t|Close to active%x1|Randomly%x2 +Set at fixed distance%x1|Add (absolute displ.)%x2|Multiply (relative displ.)%x3 +******************** +Catala +Surt del programa +Utilitats de...%t|Alinea objectes%x1|Creacio%x2|Edita malles%x3|Edita objetes%x4 +11 +Mov +Esc +Encaixa +Abarca +Separa +Alinea +Rotacio +Incr. +Crea objectes nous +Es+ +Es* +Separa entra:%t|Origens%x1|Centres geometrics%x2|Minims%x3|Maxims%x4|Baricentre%x5|Objectes%x6 +Crear%t|Arc (3 pts.)%x1|Arc (interactiu)%x2|Circumferencia (3 pts.)%x3 +12 +Punts +Centre +Ordre +Objecte +AngIni: +AngFi: +Angle: +Radi: +Punts: +Centre +Nom: +Punts +Modifica vertex%t|Subdivideix%x1|Envia a un pla%x2|Aplica LocRotSize%x3 +Parts +Projectar en el pla:%t|Coordenacio global...%x1|Coordenacio local...%x2 +Actuar sobre el pla%t|Yz%x1|Zx%x2|Xy%x3 +En la direccio%t|X%x1|Y%x2|Z%x3|Ortogonal al pla%x4 +Captura +Buffer%t|Copia vector diferencia%x1|Copia distancia%x2|Copia diferencia de rotacio%x3|Copia mitjana LocRotSiz%x4|Veure buffer en consola%x5 +Transformar LocRotSize%t|Cap al obj. actiu%x1|Aleatoriamente%x2 +Posar a distancia fixa%x1|Sumar (desp. absolut)%x2|Multiplicar (desp. relatiu)%x3 diff --git a/release/scripts/bpydata/config/readme.txt b/release/scripts/bpydata/config/readme.txt new file mode 100644 index 00000000000..4b5cb61b063 --- /dev/null +++ b/release/scripts/bpydata/config/readme.txt @@ -0,0 +1,6 @@ +This folder is for automatically saved scripts configuration data. + +To use this feature scripts just need to set a proper Blender.Registry key. + +To know more, check the API Reference doc (specifically the API_related and +Registry parts) and the documentation for the "Scripts Config Editor" script. diff --git a/release/scripts/bpydata/readme.txt b/release/scripts/bpydata/readme.txt new file mode 100644 index 00000000000..3e640e27c4b --- /dev/null +++ b/release/scripts/bpydata/readme.txt @@ -0,0 +1,9 @@ +This directory is the default place for scripts to put their data, +like internal files needed by the script and its saved configuration. + +Scripts can find the path to this dir using Blender.Get("datadir"). +Ex: + +import Blender +print Blender.Get("datadir") + diff --git a/release/scripts/bpymodules/BPyAddMesh.py b/release/scripts/bpymodules/BPyAddMesh.py new file mode 100644 index 00000000000..6ffb394320a --- /dev/null +++ b/release/scripts/bpymodules/BPyAddMesh.py @@ -0,0 +1,152 @@ +import Blender +from Blender.Window import EditMode, GetCursorPos, GetViewQuat +import bpy +import BPyMessages + +def add_mesh_simple(name, verts, edges, faces): + ''' + Adds a mesh from verts, edges and faces + + name - new object/mesh name + verts - list of 3d vectors + edges - list of int pairs + faces - list of int triplets/quads + ''' + + scn = bpy.data.scenes.active + if scn.lib: return + ob_act = scn.objects.active + + cursor = GetCursorPos() + try: quat = Blender.Mathutils.Quaternion(GetViewQuat()) + except: quat = None + + # Exist editmode for non mesh types + if ob_act and ob_act.type != 'Mesh' and EditMode(): + EditMode(0) + + # We are in mesh editmode + if EditMode(): + me = ob_act.getData(mesh=1) + + if me.multires: + BPyMessages.Error_NoMeshMultiresEdit() + return + + # Add to existing mesh + # must exit editmode to modify mesh + EditMode(0) + + me.sel = False + + vert_offset = len(me.verts) + edge_offset = len(me.edges) + face_offset = len(me.faces) + + # transform the verts + txmat = Blender.Mathutils.TranslationMatrix(Blender.Mathutils.Vector(cursor)) + if quat: + mat = quat.toMatrix() + mat.invert() + mat.resize4x4() + txmat = mat * txmat + + txmat = txmat * ob_act.matrixWorld.copy().invert() + + + me.verts.extend(verts) + # Transform the verts by the cursor and view rotation + me.transform(txmat, selected_only=True) + + if vert_offset: + me.edges.extend([[i+vert_offset for i in e] for e in edges]) + me.faces.extend([[i+vert_offset for i in f] for f in faces]) + else: + # Mesh with no data, unlikely + me.edges.extend(edges) + me.faces.extend(faces) + + EditMode(1) + + else: + + # Object mode add new + + me = bpy.data.meshes.new(name) + me.verts.extend(verts) + me.edges.extend(edges) + me.faces.extend(faces) + me.sel = True + + # Object creation and location + scn.objects.selected = [] + ob_act = scn.objects.new(me, name) + scn.objects.active = ob_act + + if quat: + mat = quat.toMatrix() + mat.invert() + mat.resize4x4() + ob_act.setMatrix(mat) + + ob_act.loc = cursor + + EditMode(1) + + +def write_mesh_script(filepath, me): + ''' + filepath - path to py file + me - mesh to write + ''' + + name = me.name + file = open(filepath, 'w') + + file.write('#!BPY\n') + file.write('"""\n') + file.write('Name: \'%s\'\n' % name) + file.write('Blender: 243\n') + file.write('Group: \'AddMesh\'\n') + file.write('"""\n\n') + file.write('import BPyAddMesh\n') + file.write('from Blender.Mathutils import Vector\n\n') + + file.write('verts = [\\\n') + for v in me.verts: + file.write('Vector(%f,%f,%f),\\\n' % tuple(v.co)) + file.write(']\n') + + file.write('edges = []\n') # TODO, write loose edges + + file.write('faces = [\\\n') + for f in me.faces: + file.write('%s,\\\n' % str(tuple([v.index for v in f]))) + file.write(']\n') + + file.write('BPyAddMesh.add_mesh_simple("%s", verts, edges, faces)\n' % name) + +# The script below can make a file from a mesh with teh above function... +''' +#!BPY +""" +Name: 'Mesh as AddMesh Script' +Blender: 242 +Group: 'Mesh' +Tip: '' +""" +import BPyAddMesh +reload(BPyAddMesh) + +import bpy + +def main(): + # Add error checking + scn = bpy.data.scenes.active + ob = scn.objects.active + me = ob.getData(mesh=1) + + BPyAddMesh.write_mesh_script('/test.py', me) + +main() +''' diff --git a/release/scripts/bpymodules/BPyArmature.py b/release/scripts/bpymodules/BPyArmature.py new file mode 100644 index 00000000000..d0b41dc35c5 --- /dev/null +++ b/release/scripts/bpymodules/BPyArmature.py @@ -0,0 +1,137 @@ +# 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 + +import Blender +import bpy +def getBakedPoseData(ob_arm, start_frame, end_frame): + ''' + If you are currently getting IPO's this function can be used to + return a list of frame aligned bone dictionary's + + The data in these can be swaped in for the IPO loc and quat + + If you want to bake an action, this is not as hard and the ipo hack can be removed. + ''' + + # --------------------------------- Dummy Action! Only for this functon + backup_action = ob_arm.action + backup_frame = Blender.Get('curframe') + + DUMMY_ACTION_NAME = '~DONT_USE~' + # Get the dummy action if it has no users + try: + new_action = bpy.data.actions[DUMMY_ACTION_NAME] + if new_action.users: + new_action = None + except: + new_action = None + + if not new_action: + new_action = bpy.data.actions.new(DUMMY_ACTION_NAME) + new_action.fakeUser = False + # ---------------------------------- Done + + Matrix = Blender.Mathutils.Matrix + Quaternion = Blender.Mathutils.Quaternion + Vector = Blender.Mathutils.Vector + POSE_XFORM= [Blender.Object.Pose.LOC, Blender.Object.Pose.ROT] + + # Each dict a frame + bake_data = [{} for i in xrange(1+end_frame-start_frame)] + + pose= ob_arm.getPose() + armature_data= ob_arm.getData(); + pose_bones= pose.bones + + # --------------------------------- Build a list of arma data for reuse + armature_bone_data = [] + bones_index = {} + for bone_name, rest_bone in armature_data.bones.items(): + pose_bone = pose_bones[bone_name] + rest_matrix = rest_bone.matrix['ARMATURESPACE'] + rest_matrix_inv = rest_matrix.copy().invert() + armature_bone_data.append( [len(bones_index), -1, bone_name, rest_bone, rest_matrix, rest_matrix_inv, pose_bone, None ]) + bones_index[bone_name] = len(bones_index) + + # Set the parent ID's + for bone_name, pose_bone in pose_bones.items(): + parent = pose_bone.parent + if parent: + bone_index= bones_index[bone_name] + parent_index= bones_index[parent.name] + armature_bone_data[ bone_index ][1]= parent_index + # ---------------------------------- Done + + + + # --------------------------------- Main loop to collect IPO data + frame_index = 0 + for current_frame in xrange(start_frame, end_frame+1): + ob_arm.action = backup_action + #pose.update() # not needed + Blender.Set('curframe', current_frame) + #Blender.Window.RedrawAll() + #frame_data = bake_data[frame_index] + ob_arm.action = new_action + ###for i,pose_bone in enumerate(pose_bones): + + for index, parent_index, bone_name, rest_bone, rest_matrix, rest_matrix_inv, pose_bone, ipo in armature_bone_data: + matrix= pose_bone.poseMatrix + + parent_bone= rest_bone.parent + + if parent_index != -1: + parent_pose_matrix = armature_bone_data[parent_index][6].poseMatrix + parent_bone_matrix_inv = armature_bone_data[parent_index][5] + matrix= matrix * parent_pose_matrix.copy().invert() + rest_matrix= rest_matrix * parent_bone_matrix_inv + + matrix=matrix * rest_matrix.copy().invert() + + pose_bone.quat= matrix.toQuat() + pose_bone.loc= matrix.translationPart() + pose_bone.insertKey(ob_arm, 1, POSE_XFORM) # always frame 1 + + # THIS IS A BAD HACK! IT SUCKS BIGTIME BUT THE RESULT ARE NICE + # - use a temp action and bake into that, always at the same frame + # so as not to make big IPO's, then collect the result from the IPOs + + # Now get the data from the IPOs + if not ipo: ipo = armature_bone_data[index][7] = new_action.getChannelIpo(bone_name) + + loc = Vector() + quat = Quaternion() + + for curve in ipo: + val = curve.evaluate(1) + curve_name= curve.name + if curve_name == 'LocX': loc[0] = val + elif curve_name == 'LocY': loc[1] = val + elif curve_name == 'LocZ': loc[2] = val + elif curve_name == 'QuatW': quat[3] = val + elif curve_name == 'QuatX': quat[0] = val + elif curve_name == 'QuatY': quat[1] = val + elif curve_name == 'QuatZ': quat[2] = val + + bake_data[frame_index][bone_name] = loc, quat + + + frame_index+=1 + + ob_arm.action = backup_action + Blender.Set('curframe', backup_frame) + return bake_data + + + diff --git a/release/scripts/bpymodules/BPyBlender.py b/release/scripts/bpymodules/BPyBlender.py new file mode 100644 index 00000000000..681dff63cf8 --- /dev/null +++ b/release/scripts/bpymodules/BPyBlender.py @@ -0,0 +1,36 @@ +# $Id$ +# +# -------------------------------------------------------------------------- +# BPyBlender.py version 0.3 Mar 20, 2005 +# -------------------------------------------------------------------------- +# helper functions to be used by other scripts +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +# Basic set of modules Blender should have in all supported platforms. +# The second and third lines are the contents of the Python23.zip file +# included with Windows Blender binaries along with zlib.pyd. +# Other platforms are assumed to have Python installed. +basic_modules = [ +'Blender', +'chunk','colorsys','copy','copy_reg','gzip','os','random','repr','stat', +'string','StringIO','types','UserDict','webbrowser', 'zlib', 'math', +'BPyBlender', 'BPyRegistry' +] diff --git a/release/scripts/bpymodules/BPyCurve.py b/release/scripts/bpymodules/BPyCurve.py new file mode 100644 index 00000000000..3dd5f1784f2 --- /dev/null +++ b/release/scripts/bpymodules/BPyCurve.py @@ -0,0 +1,79 @@ +# -------------------------------------------------------------------------- +# BPyImage.py version 0.15 +# -------------------------------------------------------------------------- +# helper functions to be used by other scripts +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +from Blender import * + +def curve2vecs(ob, WORLDSPACE= True): + ''' + Takes a curve object and retuirns a list of vec lists (polylines) + one list per curve + + This is usefull as a way to get a polyline per curve + so as not to have to deal with the spline types directly + ''' + if ob.type != 'Curve': + raise 'must be a curve object' + + me_dummy = Mesh.New() + me_dummy.getFromObject(ob) + + if WORLDSPACE: + me_dummy.transform(ob.matrixWorld) + + # build an edge dict + edges = {} # should be a set + + def sort_pair(i1, i2): + if i1 > i2: return i2, i1 + else: return i1, i2 + + for ed in me_dummy.edges: + edges[sort_pair(ed.v1.index,ed.v2.index)] = None # dummy value + + # now set the curves + first_time = True + + current_vecs = [] + vec_list = [current_vecs] + + for v in me_dummy.verts: + if first_time: + first_time = False + current_vecs.append(v.co.copy()) + last_index = v.index + else: + index = v.index + if edges.has_key(sort_pair(index, last_index)): + current_vecs.append( v.co.copy() ) + else: + current_vecs = [] + vec_list.append(current_vecs) + + last_index = index + + me_dummy.verts = None + + return vec_list + + diff --git a/release/scripts/bpymodules/BPyImage.py b/release/scripts/bpymodules/BPyImage.py new file mode 100644 index 00000000000..2c342ddec39 --- /dev/null +++ b/release/scripts/bpymodules/BPyImage.py @@ -0,0 +1,301 @@ +# -------------------------------------------------------------------------- +# BPyImage.py version 0.15 +# -------------------------------------------------------------------------- +# helper functions to be used by other scripts +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +#===========================================================================# +# Comprehensive image loader, will search and find the image # +# Will return a blender image or a new image if the image is missing # +#===========================================================================# +import bpy +from Blender import sys +try: + import os +except: + os=None + +#==============================================# +# Return directory, where the file is # +#==============================================# +def stripFile(path): + lastSlash = max(path.rfind('\\'), path.rfind('/')) + if lastSlash != -1: + path = path[:lastSlash] + newpath= '%s%s' % (path, sys.sep) + else: + newpath= path + return newpath + +#==============================================# +# Strips the slashes from the back of a string # +#==============================================# +def stripPath(path): + return path.split('/')[-1].split('\\')[-1] + +#====================================================# +# Strips the prefix off the name before writing # +#====================================================# +def stripExt(name): # name is a string + index = name.rfind('.') + if index != -1: + return name[ : index ] + else: + return name + +def getExt(name): + index = name.rfind('.') + if index != -1: + return name[index+1:] + return name + +#====================================================# +# Adds a slash to the end of a path if its not there # +#====================================================# +def addSlash(path): + if not path: + return '' + + elif path.endswith('\\') or path.endswith('/'): + return path + return path + sys.sep + + +def comprehensiveImageLoad(imagePath, filePath, PLACE_HOLDER= True, RECURSIVE=True, VERBOSE=False): + ''' + imagePath: The image filename + If a path precedes it, this will be searched as well. + + filePath: is the directory where the image may be located - any file at teh end will be ignored. + + PLACE_HOLDER: if True a new place holder image will be created. + this is usefull so later you can relink the image to its original data. + + VERBOSE: If True debug info will be printed. + + RECURSIVE: If True, directories will be recursivly searched. + Be carefull with this if you have files in your root directory because it may take a long time. + ''' + + if VERBOSE: print 'img:', imagePath, 'file:', filePath + # When we have the file load it with this. try/except niceness. + def imageLoad(path): + #if path.endswith('\\') or path.endswith('/'): + # raise 'INVALID PATH' + try: + img = bpy.data.images.new(filename=path) + if VERBOSE: print '\t\tImage loaded "%s"' % path + return img + except: + if VERBOSE: + if sys.exists(path): print '\t\tImage failed loading "%s", mabe its not a format blender can read.' % (path) + else: print '\t\tImage not found, making a place holder "%s"' % (path) + if PLACE_HOLDER: + img= bpy.data.images.new(stripPath(path),4,4) + img.filename= path + return img #blank image + else: + return None + + # Image formats blender can read + IMAGE_EXT = ['jpg', 'jpeg', 'png', 'tga', 'bmp', 'rgb', 'sgi', 'bw', 'iff', 'lbm', # Blender Internal + 'gif', 'psd', 'tif', 'tiff', 'pct', 'pict', 'pntg', 'qtif'] # Quacktime, worth a try. + + imageFileName = stripPath(imagePath) # image path only + imageFileName_lower = imageFileName.lower() # image path only + + if VERBOSE: print '\tSearchingExisting Images for "%s"' % imagePath + for i in bpy.data.images: + if stripPath(i.filename.lower()) == imageFileName_lower: + if VERBOSE: print '\t\tUsing existing image.' + return i + + + if VERBOSE: print '\tAttempting to load "%s"' % imagePath + if sys.exists(imagePath): + if VERBOSE: print '\t\tFile found where expected "%s".' % imagePath + return imageLoad(imagePath) + + + + imageFileName_noext = stripExt(imageFileName) # With no extension. + imageFileName_noext_lower = stripExt(imageFileName_lower) # With no extension. + imageFilePath = stripFile(imagePath) + + # Remove relative path from image path + if imageFilePath.startswith('./') or imageFilePath.startswith('.\\'): + imageFilePath = imageFilePath[2:] + + + # Attempt to load from obj path. + tmpPath = stripFile(filePath) + stripPath(imageFileName) + if sys.exists(tmpPath): + if VERBOSE: print '\t\tFile found in path (1)"%s".' % tmpPath + return imageLoad(tmpPath) + + + # os needed if we go any further. + if not os: + if VERBOSE: print '\t\tCreating a placeholder with a face path: "%s".' % imagePath + return imageLoad(imagePath) # Will jus treturn a placeholder. + + + # We have os. + # GATHER PATHS. + paths = {} # Store possible paths we may use, dict for no doubles. + tmpPath = addSlash(sys.expandpath('//')) # Blenders path + if sys.exists(tmpPath): + if VERBOSE: print '\t\tSearching in %s' % tmpPath + paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading + paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list. + paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext + else: + if VERBOSE: print '\tNo Path: "%s"' % tmpPath + + tmpPath = imageFilePath + if sys.exists(tmpPath): + if VERBOSE: print '\t\tSearching in %s' % tmpPath + paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading + paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list. + paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext + else: + if VERBOSE: print '\tNo Path: "%s"' % tmpPath + + tmpPath = stripFile(filePath) + if sys.exists(tmpPath): + if VERBOSE: print '\t\tSearching in %s' % tmpPath + paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading + paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list. + paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext + else: + if VERBOSE: print '\tNo Path: "%s"' % tmpPath + + tmpPath = addSlash(bpy.config.textureDir) + if tmpPath and sys.exists(tmpPath): + if VERBOSE: print '\t\tSearching in %s' % tmpPath + paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading + paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list. + paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext + else: + if VERBOSE: print '\tNo Path: "%s"' % tmpPath + + # Add path if relative image patrh was given. + tmp_paths= paths.keys() + for k in tmp_paths: + tmpPath = k + imageFilePath + if sys.exists(tmpPath): + paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading + paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list. + paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext + else: + if VERBOSE: print '\tNo Path: "%s"' % tmpPath + # DONE + # + for path, files in paths.iteritems(): + if sys.exists(path + imageFileName): + if VERBOSE: print '\tFound image at path: "%s" file" "%s"' % (path, imageFileName) + return imageLoad(path + imageFileName) + + # If the files not there then well do a case insensitive seek. + filesOrigCase = files[0] + filesLower = files[1] + filesLowerNoExt = files[2] + + # We are going to try in index the file directly, if its not there just keep on + + index = None + try: + # Is it just a case mismatch? + index = filesLower.index(imageFileName_lower) + except: + try: + # Have the extensions changed? + index = filesLowerNoExt.index(imageFileName_noext_lower) + + ext = getExt( filesLower[index] ) # Get the extension of the file that matches all but ext. + + # Check that the ext is useable eg- not a 3ds file :) + if ext.lower() not in IMAGE_EXT: + index = None + + except: + index = None + + if index != None: + tmpPath = path + filesOrigCase[index] + img = imageLoad( tmpPath ) + if img != None: + if VERBOSE: print '\t\tImage Found "%s"' % tmpPath + return img + + if RECURSIVE: + # IMAGE NOT FOUND IN ANY OF THE DIRS!, DO A RECURSIVE SEARCH. + if VERBOSE: print '\t\tImage Not Found in any of the dirs, doing a recusrive search' + for path in paths.iterkeys(): + # Were not going to use files + if path == '/' or len(path) == 3 and path[1:] == ':\\': + continue + + # print path , 'ASS' + + #------------------ + # finds the file starting at the root. + # def findImage(findRoot, imagePath): + #W--------------- + + # ROOT, DIRS, FILES + pathWalk = os.walk(path) + pathList = [True] + + matchList = [] # Store a list of (match, size), choose the biggest. + while True: + try: + pathList = pathWalk.next() + except: + break + + for file in pathList[2]: + file_lower = file.lower() + # FOUND A MATCH + if (file_lower == imageFileName_lower) or\ + (stripExt(file_lower) == imageFileName_noext_lower and getExt(file_lower) in IMAGE_EXT): + name = pathList[0] + sys.sep + file + size = os.path.getsize(name) + if VERBOSE: print '\t\t\tfound:', name + matchList.append( (name, size) ) + + if matchList: + # Sort by file size + matchList.sort(lambda A, B: cmp(B[1], A[1]) ) + + if VERBOSE: print '\t\tFound "%s"' % matchList[0][0] + + # Loop through all we have found + img = None + for match in matchList: + img = imageLoad(match[0]) # 0 - first, 0 - pathname + if img != None: + break + return img + + # No go. + if VERBOSE: print '\t\tImage Not Found after looking everywhere! "%s"' % imagePath + return imageLoad(imagePath) # Will jus treturn a placeholder. diff --git a/release/scripts/bpymodules/BPyMathutils.py b/release/scripts/bpymodules/BPyMathutils.py new file mode 100644 index 00000000000..27736b4169e --- /dev/null +++ b/release/scripts/bpymodules/BPyMathutils.py @@ -0,0 +1,239 @@ +# $Id$ +# +# -------------------------------------------------------------------------- +# helper functions to be used by other scripts +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender +from Blender.Mathutils import * + +# ------ Mersenne Twister - start + +# Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. +# Any feedback is very welcome. For any question, comments, +# see http://www.math.keio.ac.jp/matumoto/emt.html or email +# matumoto@math.keio.ac.jp + +# The link above is dead, this is the new one: +# http://www.math.sci.hiroshima-u.ac.jp/m-mat/MT/emt.html +# And here the license info, from Mr. Matsumoto's site: +# Until 2001/4/6, MT had been distributed under GNU Public License, +# but after 2001/4/6, we decided to let MT be used for any purpose, including +# commercial use. 2002-versions mt19937ar.c, mt19937ar-cok.c are considered +# to be usable freely. +# +# So from the year above (1997), this code is under GPL. + +# Period parameters +N = 624 +M = 397 +MATRIX_A = 0x9908b0dfL # constant vector a +UPPER_MASK = 0x80000000L # most significant w-r bits +LOWER_MASK = 0x7fffffffL # least significant r bits + +# Tempering parameters +TEMPERING_MASK_B = 0x9d2c5680L +TEMPERING_MASK_C = 0xefc60000L + +def TEMPERING_SHIFT_U(y): + return (y >> 11) + +def TEMPERING_SHIFT_S(y): + return (y << 7) + +def TEMPERING_SHIFT_T(y): + return (y << 15) + +def TEMPERING_SHIFT_L(y): + return (y >> 18) + +mt = [] # the array for the state vector +mti = N+1 # mti==N+1 means mt[N] is not initialized + +# initializing the array with a NONZERO seed +def sgenrand(seed): + # setting initial seeds to mt[N] using + # the generator Line 25 of Table 1 in + # [KNUTH 1981, The Art of Computer Programming + # Vol. 2 (2nd Ed.), pp102] + + global mt, mti + + mt = [] + + mt.append(seed & 0xffffffffL) + for i in xrange(1, N + 1): + mt.append((69069 * mt[i-1]) & 0xffffffffL) + + mti = i +# end sgenrand + + +def genrand(): + global mt, mti + + mag01 = [0x0L, MATRIX_A] + # mag01[x] = x * MATRIX_A for x=0,1 + y = 0 + + if mti >= N: # generate N words at one time + if mti == N+1: # if sgenrand() has not been called, + sgenrand(4357) # a default initial seed is used + + for kk in xrange((N-M) + 1): + y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK) + mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1] + + for kk in xrange(kk, N): + y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK) + mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1] + + y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK) + mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1] + + mti = 0 + + y = mt[mti] + mti += 1 + y ^= TEMPERING_SHIFT_U(y) + y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B + y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C + y ^= TEMPERING_SHIFT_L(y) + + return ( float(y) / 0xffffffffL ) # reals + +#------ Mersenne Twister -- end + + + + +""" 2d convexhull +Based from Dinu C. Gherman's work, +modified for Blender/Mathutils by Campell Barton +""" +###################################################################### +# Public interface +###################################################################### +from Blender.Mathutils import DotVecs +def convexHull(point_list_2d): + """Calculate the convex hull of a set of vectors + The vectors can be 3 or 4d but only the Xand Y are used. + returns a list of convex hull indicies to the given point list + """ + + ###################################################################### + # Helpers + ###################################################################### + + def _myDet(p, q, r): + """Calc. determinant of a special matrix with three 2D points. + + The sign, "-" or "+", determines the side, right or left, + respectivly, on which the point r lies, when measured against + a directed vector from p to q. + """ + return (q.x*r.y + p.x*q.y + r.x*p.y) - (q.x*p.y + r.x*q.y + p.x*r.y) + + def _isRightTurn((p, q, r)): + "Do the vectors pq:qr form a right turn, or not?" + #assert p[0] != q[0] and q[0] != r[0] and p[0] != r[0] + if _myDet(p[0], q[0], r[0]) < 0: + return 1 + else: + return 0 + + # Get a local list copy of the points and sort them lexically. + points = [(p, i) for i, p in enumerate(point_list_2d)] + + try: points.sort(key = lambda a: (a[0].x, a[0].y)) + except: points.sort(lambda a,b: cmp((a[0].x, a[0].y), (b[0].x, b[0].y))) + + # Build upper half of the hull. + upper = [points[0], points[1]] # cant remove these. + for i in xrange(len(points)-2): + upper.append(points[i+2]) + while len(upper) > 2 and not _isRightTurn(upper[-3:]): + del upper[-2] + + # Build lower half of the hull. + points.reverse() + lower = [points.pop(0), points.pop(1)] + for p in points: + lower.append(p) + while len(lower) > 2 and not _isRightTurn(lower[-3:]): + del lower[-2] + + # Concatenate both halfs and return. + return [p[1] for ls in (upper, lower) for p in ls] + + +def plane2mat(plane, normalize= False): + ''' + Takes a plane and converts to a matrix + points between 0 and 1 are up + 1 and 2 are right + assumes the plane has 90d corners + ''' + cent= (plane[0]+plane[1]+plane[2]+plane[3] ) /4.0 + + + up= cent - ((plane[0]+plane[1])/2.0) + right= cent - ((plane[1]+plane[2])/2.0) + z= CrossVecs(up, right) + + if normalize: + up.normalize() + right.normalize() + z.normalize() + + mat= Matrix(up, right, z) + + # translate + mat.resize4x4() + tmat= Blender.Mathutils.TranslationMatrix(cent) + return mat * tmat + + +# Used for mesh_solidify.py and mesh_wire.py + +# returns a length from an angle +# Imaging a 2d space. +# there is a hoz line at Y1 going to inf on both X ends, never moves (LINEA) +# down at Y0 is a unit length line point up at (angle) from X0,Y0 (LINEB) +# This function returns the length of LINEB at the point it would intersect LINEA +# - Use this for working out how long to make the vector - differencing it from surrounding faces, +# import math +from math import pi, sin, cos, sqrt + +def angleToLength(angle): + # Alredy accounted for + if angle < 0.000001: + return 1.0 + + angle = 2*pi*angle/360 + x,y = cos(angle), sin(angle) + # print "YX", x,y + # 0 d is hoz to the right. + # 90d is vert upward. + fac=1/x + x=x*fac + y=y*fac + return sqrt((x*x)+(y*y)) diff --git a/release/scripts/bpymodules/BPyMesh.py b/release/scripts/bpymodules/BPyMesh.py new file mode 100644 index 00000000000..415c2a12c69 --- /dev/null +++ b/release/scripts/bpymodules/BPyMesh.py @@ -0,0 +1,1328 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +import Blender +import bpy +import BPyMesh_redux # seperated because of its size. +# reload(BPyMesh_redux) +redux= BPyMesh_redux.redux + +# python 2.3 has no reversed() iterator. this will only work on lists and tuples +try: + reversed +except: + def reversed(l): return l[::-1] + + +# If python version is less than 2.4, try to get set stuff from module +try: + set +except: + try: + from sets import Set as set + except: + set= None + + + + + +def meshWeight2List(me): + ''' Takes a mesh and return its group names and a list of lists, one list per vertex. + aligning the each vert list with the group names, each list contains float value for the weight. + These 2 lists can be modified and then used with list2MeshWeight to apply the changes. + ''' + + # Clear the vert group. + groupNames= me.getVertGroupNames() + len_groupNames= len(groupNames) + + if not len_groupNames: + # no verts? return a vert aligned empty list + return [[] for i in xrange(len(me.verts))], [] + + else: + vWeightList= [[0.0]*len_groupNames for i in xrange(len(me.verts))] + + for group_index, group in enumerate(groupNames): + for vert_index, weight in me.getVertsFromGroup(group, 1): # (i,w) tuples. + vWeightList[vert_index][group_index]= weight + + # removed this because me may be copying teh vertex groups. + #for group in groupNames: + # me.removeVertGroup(group) + + return groupNames, vWeightList + + +def list2MeshWeight(me, groupNames, vWeightList): + ''' Takes a list of groups and a list of vertex Weight lists as created by meshWeight2List + and applys it to the mesh.''' + + if len(vWeightList) != len(me.verts): + raise 'Error, Lists Differ in size, do not modify your mesh.verts before updating the weights' + + act_group = me.activeGroup + + # Clear the vert group. + currentGroupNames= me.getVertGroupNames() + for group in currentGroupNames: + me.removeVertGroup(group) # messes up the active group. + + # Add clean unused vert groupNames back + currentGroupNames= me.getVertGroupNames() + for group in groupNames: + me.addVertGroup(group) + + add_ = Blender.Mesh.AssignModes.ADD + + vertList= [None] + for i, v in enumerate(me.verts): + vertList[0]= i + for group_index, weight in enumerate(vWeightList[i]): + if weight: + try: + me.assignVertsToGroup(groupNames[group_index], vertList, min(1, max(0, weight)), add_) + except: + pass # vert group is not used anymore. + + try: me.activeGroup = act_group + except: pass + + me.update() + + + + +def meshWeight2Dict(me): + ''' Takes a mesh and return its group names and a list of dicts, one dict per vertex. + using the group as a key and a float value for the weight. + These 2 lists can be modified and then used with dict2MeshWeight to apply the changes. + ''' + + vWeightDict= [dict() for i in xrange(len(me.verts))] # Sync with vertlist. + + # Clear the vert group. + groupNames= me.getVertGroupNames() + + for group in groupNames: + for vert_index, weight in me.getVertsFromGroup(group, 1): # (i,w) tuples. + vWeightDict[vert_index][group]= weight + + # removed this because me may be copying teh vertex groups. + #for group in groupNames: + # me.removeVertGroup(group) + + return groupNames, vWeightDict + + +def dict2MeshWeight(me, groupNames, vWeightDict): + ''' Takes a list of groups and a list of vertex Weight dicts as created by meshWeight2Dict + and applys it to the mesh.''' + + if len(vWeightDict) != len(me.verts): + raise 'Error, Lists Differ in size, do not modify your mesh.verts before updating the weights' + + act_group = me.activeGroup + + # Clear the vert group. + currentGroupNames= me.getVertGroupNames() + for group in currentGroupNames: + if group not in groupNames: + me.removeVertGroup(group) # messes up the active group. + else: + me.removeVertsFromGroup(group) + + # Add clean unused vert groupNames back + currentGroupNames= me.getVertGroupNames() + for group in groupNames: + if group not in currentGroupNames: + me.addVertGroup(group) + + add_ = Blender.Mesh.AssignModes.ADD + + vertList= [None] + for i, v in enumerate(me.verts): + vertList[0]= i + for group, weight in vWeightDict[i].iteritems(): + try: + me.assignVertsToGroup(group, vertList, min(1, max(0, weight)), add_) + except: + pass # vert group is not used anymore. + + try: me.activeGroup = act_group + except: pass + + me.update() + +def dictWeightMerge(dict_weights): + ''' + Takes dict weight list and merges into 1 weight dict item and returns it + ''' + + if not dict_weights: + return {} + + keys= [] + for weight in dict_weights: + keys.extend([ (k, 0.0) for k in weight.iterkeys() ]) + + new_wdict = dict(keys) + + len_dict_weights= len(dict_weights) + + for weight in dict_weights: + for group, value in weight.iteritems(): + new_wdict[group] += value/len_dict_weights + + return new_wdict + + +FLIPNAMES=[\ +('Left','Right'),\ +('_L','_R'),\ +('-L','-R'),\ +('.L','.R'),\ +] + +def dictWeightFlipGroups(dict_weight, groupNames, createNewGroups): + ''' + Returns a weight with flip names + dict_weight - 1 vert weight. + groupNames - because we may need to add new group names. + dict_weight - Weather to make new groups where needed. + ''' + + def flipName(name): + for n1,n2 in FLIPNAMES: + for nA, nB in ( (n1,n2), (n1.lower(),n2.lower()), (n1.upper(),n2.upper()) ): + if createNewGroups: + newName= name.replace(nA,nB) + if newName!=name: + if newName not in groupNames: + groupNames.append(newName) + return newName + + newName= name.replace(nB,nA) + if newName!=name: + if newName not in groupNames: + groupNames.append(newName) + return newName + + else: + newName= name.replace(nA,nB) + if newName!=name and newName in groupNames: + return newName + + newName= name.replace(nB,nA) + if newName!=name and newName in groupNames: + return newName + + return name + + if not dict_weight: + return dict_weight, groupNames + + + new_wdict = {} + for group, weight in dict_weight.iteritems(): + flipname= flipName(group) + new_wdict[flipname]= weight + + return new_wdict, groupNames + + +def mesh2linkedFaces(me): + ''' + Splits the mesh into connected parts, + these parts are returned as lists of faces. + used for seperating cubes from other mesh elements in the 1 mesh + ''' + + # Build vert face connectivity + vert_faces= [[] for i in xrange(len(me.verts))] + for f in me.faces: + for v in f: + vert_faces[v.index].append(f) + + # sort faces into connectivity groups + face_groups= [[f] for f in me.faces] + face_mapping = range(len(me.faces)) # map old, new face location + + # Now clump faces iterativly + ok= True + while ok: + ok= False + + for i, f in enumerate(me.faces): + mapped_index= face_mapping[f.index] + mapped_group= face_groups[mapped_index] + + for v in f: + for nxt_f in vert_faces[v.index]: + if nxt_f != f: + nxt_mapped_index= face_mapping[nxt_f.index] + + # We are not a part of the same group + if mapped_index != nxt_mapped_index: + + ok= True + + # Assign mapping to this group so they all map to this group + for grp_f in face_groups[nxt_mapped_index]: + face_mapping[grp_f.index] = mapped_index + + # Move faces into this group + mapped_group.extend(face_groups[nxt_mapped_index]) + + # remove reference to the list + face_groups[nxt_mapped_index]= None + + + # return all face groups that are not null + # this is all the faces that are connected in their own lists. + return [fg for fg in face_groups if fg] + + +def getFaceLoopEdges(faces, seams=[]): + ''' + Takes me.faces or a list of faces and returns the edge loops + These edge loops are the edges that sit between quads, so they dont touch + 1 quad, not not connected will make 2 edge loops, both only containing 2 edges. + + return a list of edge key lists + [ [(0,1), (4, 8), (3,8)], ...] + + optionaly, seams are edge keys that will be removed + ''' + + OTHER_INDEX = 2,3,0,1 # opposite face index + + edges = {} + + for f in faces: + if len(f) == 4: + edge_keys = f.edge_keys + for i, edkey in enumerate(f.edge_keys): + edges.setdefault(edkey, []).append(edge_keys[OTHER_INDEX[i]]) + + for edkey in seams: + edges[edkey] = [] + + # Collect edge loops here + edge_loops = [] + + for edkey, ed_adj in edges.iteritems(): + if 0 face indicies + face_edges[i] -> list referencs local faces v indicies 1,2,3 &| 4 + face_edges[i][j] -> list of faces that this edge uses. + crap this is tricky to explain :/ + ''' + face_edges= [ [-1] * len(f) for f in me.faces ] + + face_edges_dict= dict([(ed.key, []) for ed in me.edges]) + for fidx, f in enumerate(me.faces): + for i, edkey in enumerate(f.edge_keys): + edge_face_users= face_edges_dict[edkey] + edge_face_users.append(f) + face_edges[fidx][i]= edge_face_users + + return face_edges + + +def facesPlanerIslands(me): + DotVecs= Blender.Mathutils.DotVecs + + def roundvec(v): + return round(v[0], 4), round(v[1], 4), round(v[2], 4) + + face_props= [(cent, no, roundvec(no), DotVecs(cent, no)) for f in me.faces for no, cent in ((f.no, f.cent),)] + + face_edge_users= face_edges(me) + islands= [] + + used_faces= [0] * len(me.faces) + while True: + new_island= False + for i, used_val in enumerate(used_faces): + if used_val==0: + island= [i] + new_island= True + used_faces[i]= 1 + break + + if not new_island: + break + + island_growing= True + while island_growing: + island_growing= False + for fidx1 in island[:]: + if used_faces[fidx1]==1: + used_faces[fidx1]= 2 + face_prop1= face_props[fidx1] + for ed in face_edge_users[fidx1]: + for f2 in ed: + fidx2= f2.index + if fidx1 != fidx2 and used_faces[fidx2]==0: + island_growing= True + face_prop2= face_props[fidx2] + # normals are the same? + if face_prop1[2]==face_prop2[2]: + if abs(face_prop1[3] - DotVecs(face_prop1[1], face_prop2[0])) < 0.000001: + used_faces[fidx2]= 1 + island.append(fidx2) + islands.append([me.faces[i] for i in island]) + return islands + + + +def facesUvIslands(me, PREF_IMAGE_DELIMIT=True): + DotVecs= Blender.Mathutils.DotVecs + def roundvec(v): + return round(v[0], 4), round(v[1], 4) + + if not me.faceUV: + return [ list(me.faces), ] + + # make a list of uv dicts + face_uvs= [ [roundvec(uv) for uv in f.uv] for f in me.faces] + + # key - face uv || value - list of face idxs + uv_connect_dict= dict([ (uv, [] ) for f_uvs in face_uvs for uv in f_uvs]) + + for i, f_uvs in enumerate(face_uvs): + for uv in f_uvs: # loops through rounded uv values + uv_connect_dict[uv].append(i) + islands= [] + + used_faces= [0] * len(me.faces) + while True: + new_island= False + for i, used_val in enumerate(used_faces): + if used_val==0: + island= [i] + new_island= True + used_faces[i]= 1 + break + + if not new_island: + break + + island_growing= True + while island_growing: + island_growing= False + for fidx1 in island[:]: + if used_faces[fidx1]==1: + used_faces[fidx1]= 2 + for uv in face_uvs[fidx1]: + for fidx2 in uv_connect_dict[uv]: + if fidx1 != fidx2 and used_faces[fidx2]==0: + if not PREF_IMAGE_DELIMIT or me.faces[fidx1].image==me.faces[fidx2].image: + island_growing= True + used_faces[fidx2]= 1 + island.append(fidx2) + + islands.append([me.faces[i] for i in island]) + return islands + +#def faceUvBounds(me, faces= None): + + +def facesUvRotate(me, deg, faces= None, pivot= (0,0)): + ''' + Faces can be None an all faces will be used + pivot is just the x/y well rotated about + + positive deg value for clockwise rotation + ''' + if faces==None: faces= me.faces + pivot= Blender.Mathutils.Vector(pivot) + + rotmat= Blender.Mathutils.RotationMatrix(-deg, 2) + + for f in faces: + f.uv= [((uv-pivot)*rotmat)+pivot for uv in f.uv] + +def facesUvScale(me, sca, faces= None, pivot= (0,0)): + ''' + Faces can be None an all faces will be used + pivot is just the x/y well rotated about + sca can be wither an int/float or a vector if you want to + scale x/y seperately. + a sca or (1.0, 1.0) will do nothing. + ''' + def vecmulti(v1,v2): + '''V2 is unchanged''' + v1[:]= (v1.x*v2.x, v1.y*v2.y) + return v1 + + sca= Blender.Mathutils.Vector(sca) + if faces==None: faces= me.faces + pivot= Blender.Mathutils.Vector(pivot) + + for f in faces: + f.uv= [vecmulti(uv-pivot, sca)+pivot for uv in f.uv] + + +def facesUvTranslate(me, tra, faces= None, pivot= (0,0)): + ''' + Faces can be None an all faces will be used + pivot is just the x/y well rotated about + ''' + if faces==None: faces= me.faces + tra= Blender.Mathutils.Vector(tra) + + for f in faces: + f.uv= [uv+tra for uv in f.uv] + + + +def edgeFaceUserCount(me, faces= None): + ''' + Return an edge aligned list with the count for all the faces that use that edge. - + can spesify a subset of the faces, so only those will be counted. + ''' + if faces==None: + faces= me.faces + max_vert= len(me.verts) + else: + # find the lighest vert index + pass + + edge_users= [0] * len(me.edges) + + edges_idx_dict= dict([(ed.key, ed.index) for ed in me.edges]) + + for f in faces: + for edkey in f.edge_keys: + edge_users[edges_idx_dict[edkey]] += 1 + + return edge_users + + +#============================================================================# +# Takes a face, and a pixel x/y on the image and returns a worldspace x/y/z # +# will return none if the pixel is not inside the faces UV # +#============================================================================# +def getUvPixelLoc(face, pxLoc, img_size = None, uvArea = None): + TriangleArea= Blender.Mathutils.TriangleArea + Vector= Blender.Mathutils.Vector + + if not img_size: + w,h = face.image.size + else: + w,h= img_size + + scaled_uvs= [Vector(uv.x*w, uv.y*h) for uv in f.uv] + + if len(scaled_uvs)==3: + indicies= ((0,1,2),) + else: + indicies= ((0,1,2), (0,2,3)) + + for fidxs in indicies: + for i1,i2,i3 in fidxs: + # IS a point inside our triangle? + # UVArea could be cached? + uv_area = TriangleArea(scaled_uvs[i1], scaled_uvs[i2], scaled_uvs[i3]) + area0 = TriangleArea(pxLoc, scaled_uvs[i2], scaled_uvs[i3]) + area1 = TriangleArea(pxLoc, scaled_uvs[i1], scaled_uvs[i3]) + area2 = TriangleArea(pxLoc, scaled_uvs[i1], scaled_uvs[i2]) + if area0 + area1 + area2 > uv_area + 1: # 1 px bleed/error margin. + pass # if were a quad the other side may contain the pixel so keep looking. + else: + # We know the point is in the tri + area0 /= uv_area + area1 /= uv_area + area2 /= uv_area + + # New location + return Vector(\ + face.v[i1].co[0]*area0 + face.v[i2].co[0]*area1 + face.v[i3].co[0]*area2,\ + face.v[i1].co[1]*area0 + face.v[i2].co[1]*area1 + face.v[i3].co[1]*area2,\ + face.v[i1].co[2]*area0 + face.v[i2].co[2]*area1 + face.v[i3].co[2]*area2\ + ) + + return None + + +# Used for debugging ngon +""" +def draw_loops(loops): + + me= Blender.Mesh.New() + for l in loops: + #~ me= Blender.Mesh.New() + + + i= len(me.verts) + me.verts.extend([v[0] for v in l]) + try: + me.verts[0].sel= 1 + except: + pass + me.edges.extend([ (j-1, j) for j in xrange(i+1, len(me.verts)) ]) + # Close the edge? + me.edges.extend((i, len(me.verts)-1)) + + + #~ ob= Blender.Object.New('Mesh') + #~ ob.link(me) + #~ scn= Blender.Scene.GetCurrent() + #~ scn.link(ob) + #~ ob.Layers= scn.Layers + #~ ob.sel= 1 + + + + # Fill + #fill= Blender.Mathutils.PolyFill(loops) + #me.faces.extend(fill) + + + ob= Blender.Object.New('Mesh') + ob.link(me) + scn= Blender.Scene.GetCurrent() + scn.link(ob) + ob.Layers= scn.Layers + ob.sel= 1 + Blender.Window.RedrawAll() +""" + +def ngon(from_data, indices, PREF_FIX_LOOPS= True): + ''' + Takes a polyline of indices (fgon) + and returns a list of face indicie lists. + Designed to be used for importers that need indices for an fgon to create from existing verts. + + from_data: either a mesh, or a list/tuple of vectors. + indices: a list of indicies to use this list is the ordered closed polyline to fill, and can be a subset of the data given. + PREF_FIX_LOOPS: If this is enabled polylines that use loops to make multiple polylines are delt with correctly. + ''' + + if not set: # Need sets for this, otherwise do a normal fill. + PREF_FIX_LOOPS= False + + Vector= Blender.Mathutils.Vector + if not indices: + return [] + + # return [] + def rvec(co): return round(co.x, 6), round(co.y, 6), round(co.z, 6) + def mlen(co): return abs(co[0])+abs(co[1])+abs(co[2]) # manhatten length of a vector, faster then length + + def vert_treplet(v, i): + return v, rvec(v), i, mlen(v) + + def ed_key_mlen(v1, v2): + if v1[3] > v2[3]: + return v2[1], v1[1] + else: + return v1[1], v2[1] + + + if not PREF_FIX_LOOPS: + ''' + Normal single concave loop filling + ''' + if type(from_data) in (tuple, list): + verts= [Vector(from_data[i]) for ii, i in enumerate(indices)] + else: + verts= [from_data.verts[i].co for ii, i in enumerate(indices)] + + for i in xrange(len(verts)-1, 0, -1): # same as reversed(xrange(1, len(verts))): + if verts[i][1]==verts[i-1][0]: + verts.pop(i-1) + + fill= Blender.Geometry.PolyFill([verts]) + + else: + ''' + Seperate this loop into multiple loops be finding edges that are used twice + This is used by lightwave LWO files a lot + ''' + + if type(from_data) in (tuple, list): + verts= [vert_treplet(Vector(from_data[i]), ii) for ii, i in enumerate(indices)] + else: + verts= [vert_treplet(from_data.verts[i].co, ii) for ii, i in enumerate(indices)] + + edges= [(i, i-1) for i in xrange(len(verts))] + if edges: + edges[0]= (0,len(verts)-1) + + if not verts: + return [] + + + edges_used= set() + edges_doubles= set() + # We need to check if any edges are used twice location based. + for ed in edges: + edkey= ed_key_mlen(verts[ed[0]], verts[ed[1]]) + if edkey in edges_used: + edges_doubles.add(edkey) + else: + edges_used.add(edkey) + + # Store a list of unconnected loop segments split by double edges. + # will join later + loop_segments= [] + + v_prev= verts[0] + context_loop= [v_prev] + loop_segments= [context_loop] + + for v in verts: + if v!=v_prev: + # Are we crossing an edge we removed? + if ed_key_mlen(v, v_prev) in edges_doubles: + context_loop= [v] + loop_segments.append(context_loop) + else: + if context_loop and context_loop[-1][1]==v[1]: + #raise "as" + pass + else: + context_loop.append(v) + + v_prev= v + # Now join loop segments + + def join_seg(s1,s2): + if s2[-1][1]==s1[0][1]: # + s1,s2= s2,s1 + elif s1[-1][1]==s2[0][1]: + pass + else: + return False + + # If were stuill here s1 and s2 are 2 segments in the same polyline + s1.pop() # remove the last vert from s1 + s1.extend(s2) # add segment 2 to segment 1 + + if s1[0][1]==s1[-1][1]: # remove endpoints double + s1.pop() + + s2[:]= [] # Empty this segment s2 so we dont use it again. + return True + + joining_segments= True + while joining_segments: + joining_segments= False + segcount= len(loop_segments) + + for j in xrange(segcount-1, -1, -1): #reversed(xrange(segcount)): + seg_j= loop_segments[j] + if seg_j: + for k in xrange(j-1, -1, -1): # reversed(xrange(j)): + if not seg_j: + break + seg_k= loop_segments[k] + + if seg_k and join_seg(seg_j, seg_k): + joining_segments= True + + loop_list= loop_segments + + for verts in loop_list: + while verts and verts[0][1]==verts[-1][1]: + verts.pop() + + loop_list= [verts for verts in loop_list if len(verts)>2] + # DONE DEALING WITH LOOP FIXING + + + # vert mapping + vert_map= [None]*len(indices) + ii=0 + for verts in loop_list: + if len(verts)>2: + for i, vert in enumerate(verts): + vert_map[i+ii]= vert[2] + ii+=len(verts) + + fill= Blender.Geometry.PolyFill([ [v[0] for v in loop] for loop in loop_list ]) + #draw_loops(loop_list) + #raise 'done loop' + # map to original indicies + fill= [[vert_map[i] for i in reversed(f)] for f in fill] + + + if not fill: + print 'Warning Cannot scanfill, fallback on a triangle fan.' + fill= [ [0, i-1, i] for i in xrange(2, len(indices)) ] + else: + # Use real scanfill. + # See if its flipped the wrong way. + flip= None + for fi in fill: + if flip != None: + break + for i, vi in enumerate(fi): + if vi==0 and fi[i-1]==1: + flip= False + break + elif vi==1 and fi[i-1]==0: + flip= True + break + + if not flip: + for i, fi in enumerate(fill): + fill[i]= tuple([ii for ii in reversed(fi)]) + + + + + return fill + + + +# EG +''' +scn= Scene.GetCurrent() +me = scn.getActiveObject().getData(mesh=1) +ind= [v.index for v in me.verts if v.sel] # Get indices + +indices = ngon(me, ind) # fill the ngon. + +# Extand the faces to show what the scanfill looked like. +print len(indices) +me.faces.extend([[me.verts[ii] for ii in i] for i in indices]) +''' + +def meshCalcNormals(me, vertNormals=None): + ''' + takes a mesh and returns very high quality normals 1 normal per vertex. + The normals should be correct, indipendant of topology + + vertNormals - a list of vectors at least as long as the number of verts in the mesh + ''' + Ang= Blender.Mathutils.AngleBetweenVecs + Vector= Blender.Mathutils.Vector + SMALL_NUM=0.000001 + # Weight the edge normals by total angle difference + # EDGE METHOD + + if not vertNormals: + vertNormals= [ Vector() for v in xrange(len(me.verts)) ] + else: + for v in vertNormals: + v.zero() + + edges={} + for f in me.faces: + f_v = f.v + for edkey in f.edge_keys: + edges.setdefault(edkey, []).append(f.no) + + # Weight the edge normals by total angle difference + for fnos in edges.itervalues(): + + len_fnos= len(fnos) + if len_fnos>1: + totAngDiff=0 + for j in xrange(len_fnos-1, -1, -1): # same as reversed(xrange(...)) + for k in xrange(j-1, -1, -1): # same as reversed(xrange(...)) + #print j,k + try: + totAngDiff+= (Ang(fnos[j], fnos[k])) # /180 isnt needed, just to keeop the vert small. + except: + pass # Zero length face + + # print totAngDiff + if totAngDiff > SMALL_NUM: + ''' + average_no= Vector() + for no in fnos: + average_no+=no + ''' + average_no= reduce(lambda a,b: a+b, fnos, Vector()) + fnos.append(average_no*totAngDiff) # average no * total angle diff + #else: + # fnos[0] + else: + fnos.append(fnos[0]) + + for ed, v in edges.iteritems(): + vertNormals[ed[0]]+= v[-1] + vertNormals[ed[1]]+= v[-1] + for i, v in enumerate(me.verts): + v.no= vertNormals[i] + + + + +def pointInsideMesh(ob, pt): + Intersect = Blender.Mathutils.Intersect # 2 less dict lookups. + Vector = Blender.Mathutils.Vector + + def ptInFaceXYBounds(f, pt): + f_v = f.v + co= f_v[0].co + xmax= xmin= co.x + ymax= ymin= co.y + + co= f_v[1].co + xmax= max(xmax, co.x) + xmin= min(xmin, co.x) + ymax= max(ymax, co.y) + ymin= min(ymin, co.y) + + co= f_v[2].co + xmax= max(xmax, co.x) + xmin= min(xmin, co.x) + ymax= max(ymax, co.y) + ymin= min(ymin, co.y) + + if len(f_v)==4: + co= f_v[3].co + xmax= max(xmax, co.x) + xmin= min(xmin, co.x) + ymax= max(ymax, co.y) + ymin= min(ymin, co.y) + + # Now we have the bounds, see if the point is in it. + if\ + pt.x < xmin or\ + pt.y < ymin or\ + pt.x > xmax or\ + pt.y > ymax: + return False # point is outside face bounds + else: + return True # point inside. + #return xmax, ymax, xmin, ymin + + def faceIntersect(f): + f_v = f.v + isect = Intersect(f_v[0].co, f_v[1].co, f_v[2].co, ray, obSpacePt, 1) # Clipped. + if not isect and len(f) == 4: + isect = Intersect(f_v[0].co, f_v[2].co, f_v[3].co, ray, obSpacePt, 1) # Clipped. + + if isect and isect.z > obSpacePt.z: # This is so the ray only counts if its above the point. + return True + else: + return False + + obSpacePt = pt*ob.matrixWorld.copy().invert() + ray = Vector(0,0,-1) + me= ob.getData(mesh=1) + + # Here we find the number on intersecting faces, return true if an odd number (inside), false (outside) if its true. + return len([None for f in me.faces if ptInFaceXYBounds(f, obSpacePt) if faceIntersect(f)]) % 2 + + +def faceAngles(f): + ''' + Returns the angle between all corners in a tri or a quad + + ''' + AngleBetweenVecs = Blender.Mathutils.AngleBetweenVecs + def Ang(a1,a2): + try: return AngleBetweenVecs(a1,a2) + except: return 180 + + if len(f) == 3: + if type(f) in (tuple, list): v1,v2,v3 = f + else: v1,v2,v3 = [v.co for v in f] + a1= Ang(v2-v1,v3-v1) + a2= Ang(v1-v2,v3-v2) + a3 = 180 - (a1+a2) # a3= Mathutils.AngleBetweenVecs(v2-v3,v1-v3) + return a1,a2,a3 + + else: + if type(f) in (tuple, list): v1,v2,v3,v4 = f + else: v1,v2,v3,v4 = [v.co for v in f] + a1= Ang(v2-v1,v4-v1) + a2= Ang(v1-v2,v3-v2) + a3= Ang(v2-v3,v4-v3) + a4= Ang(v3-v4,v1-v4) + return a1,a2,a3,a4 + +# NMesh wrapper +Vector= Blender.Mathutils.Vector +class NMesh(object): + __slots__= 'verts', 'faces', 'edges', 'faceUV', 'materials', 'realmesh' + def __init__(self, mesh): + ''' + This is an NMesh wrapper that + mesh is an Mesh as returned by Blender.Mesh.New() + This class wraps NMesh like access into Mesh + + Running NMesh.update() - with this wrapper, + Will update the realmesh. + ''' + self.verts= [] + self.faces= [] + self.edges= [] + self.faceUV= False + self.materials= [] + self.realmesh= mesh + + def addFace(self, nmf): + self.faces.append(nmf) + + def Face(self, v=[]): + return NMFace(v) + def Vert(self, x,y,z): + return NMVert(x,y,z) + + def hasFaceUV(self, flag): + if flag: + self.faceUV= True + else: + self.faceUV= False + + def addMaterial(self, mat): + self.materials.append(mat) + + def update(self, recalc_normals=False): # recalc_normals is dummy + mesh= self.realmesh + mesh.verts= None # Clears the + + # Add in any verts from faces we may have not added. + for nmf in self.faces: + for nmv in nmf.v: + if nmv.index==-1: + nmv.index= len(self.verts) + self.verts.append(nmv) + + + mesh.verts.extend([nmv.co for nmv in self.verts]) + for i, nmv in enumerate(self.verts): + nmv.index= i + mv= mesh.verts[i] + mv.sel= nmv.sel + + good_faces= [nmf for nmf in self.faces if len(nmf.v) in (3,4)] + #print len(good_faces), 'AAA' + + + #mesh.faces.extend([nmf.v for nmf in self.faces]) + mesh.faces.extend([[mesh.verts[nmv.index] for nmv in nmf.v] for nmf in good_faces]) + if len(mesh.faces): + if self.faceUV: + mesh.faceUV= 1 + + #for i, nmf in enumerate(self.faces): + for i, nmf in enumerate(good_faces): + mf= mesh.faces[i] + if self.faceUV: + if len(nmf.uv) == len(mf.v): + mf.uv= [Vector(uv[0], uv[1]) for uv in nmf.uv] + if len(nmf.col) == len(mf.v): + for c, i in enumerate(mf.col): + c.r, c.g, c.b= nmf.col[i].r, nmf.col[i].g, nmf.col[i].b + if nmf.image: + mf.image= nmf.image + + mesh.materials= self.materials[:16] + +class NMVert(object): + __slots__= 'co', 'index', 'no', 'sel', 'uvco' + def __init__(self, x,y,z): + self.co= Vector(x,y,z) + self.index= None # set on appending. + self.no= Vector(0,0,1) # dummy + self.sel= 0 + self.uvco= None +class NMFace(object): + __slots__= 'col', 'flag', 'hide', 'image', 'mat', 'materialIndex', 'mode', 'normal',\ + 'sel', 'smooth', 'transp', 'uv', 'v' + + def __init__(self, v=[]): + self.col= [] + self.flag= 0 + self.hide= 0 + self.image= None + self.mat= 0 # materialIndex needs support too. + self.mode= 0 + self.normal= Vector(0,0,1) + self.uv= [] + self.sel= 0 + self.smooth= 0 + self.transp= 0 + self.uv= [] + self.v= [] # a list of nmverts. + +class NMCol(object): + __slots__ = 'r', 'g', 'b', 'a' + def __init__(self): + self.r= 255 + self.g= 255 + self.b= 255 + self.a= 255 + + +''' +# +verts_split= [dict() for i in xrange(len(me.verts))] + +tot_verts= 0 +for f in me.faces: + f_uv= f.uv + for i, v in enumerate(f.v): + vert_index= v.index # mesh index + vert_dict= verts_split[vert_index] # get the dict for this vert + + uv= f_uv[i] + # now we have the vert and the face uv well make a unique dict. + + vert_key= v.x, v.y, v.x, uv.x, uv.y # ADD IMAGE NAME HETR IF YOU WANT TO SPLIT BY THAT TOO + value= vert_index, tot_verts # ADD WEIGHT HERE IF YOU NEED. + try: + vert_dict[vert_key] # if this is missing it will fail. + except: + # this stores a mapping between the split and orig vert indicies + vert_dict[vert_key]= value + tot_verts+= 1 + +# a flat list of split verts - can add custom weight data here too if you need +split_verts= [None]*tot_verts + +for vert_split_dict in verts_split: + for key, value in vert_split_dict.iteritems(): + local_index, split_index= value + split_verts[split_index]= key + +# split_verts - Now you have a list of verts split by their UV. +''' diff --git a/release/scripts/bpymodules/BPyMesh_octree.py b/release/scripts/bpymodules/BPyMesh_octree.py new file mode 100644 index 00000000000..368a33496eb --- /dev/null +++ b/release/scripts/bpymodules/BPyMesh_octree.py @@ -0,0 +1,332 @@ +from Blender import * + +try: + import psyco + psyco.full() +except: + print 'no psyco for you!' + +DotVecs= Mathutils.DotVecs +#======================================================== +# SPACIAL TREE - Seperate Class - use if you want to +# USed for getting vert is a proximity +LEAF_SIZE = 128 +class octreeNode: + def __init__(self, verts, parent): + + # Assunme we are a leaf node, until split is run. + self.verts = verts + self.children = [] + + if parent == None: # ROOT NODE, else set bounds when making children, + # BOUNDS + v= verts[0] + maxx,maxy,maxz= v.co + minx,miny,minz= maxx,maxy,maxz + + for v in verts: + x,y,z= v.co + if x>maxx: maxx= x + if y>maxy: maxy= y + if z>maxz: maxz= z + + if x LEAF_SIZE: + self.makeChildren() # 8 new children, + self.verts = None + # Alredy assumed a leaf not so dont do anything here. + + def makeChildren(self): + verts= self.verts + # Devide into 8 children. + axisDividedVerts = [[],[],[],[],[],[],[],[]] # Verts Only + + + divx = (self.maxx + self.minx) / 2 + divy = (self.maxy + self.miny) / 2 + divz = (self.maxz + self.minz) / 2 + + # Sort into 8 + for v in verts: + x,y,z = v.co + + if x > divx: + if y > divy: + if z > divz: + axisDividedVerts[0].append(v) + else: + axisDividedVerts[1].append(v) + else: + if z > divz: + axisDividedVerts[2].append(v) + else: + axisDividedVerts[3].append(v) + else: + if y > divy: + if z > divz: + axisDividedVerts[4].append(v) + else: + axisDividedVerts[5].append(v) + else: + if z > divz: + axisDividedVerts[6].append(v) + else: + axisDividedVerts[7].append(v) + + # populate self.children + for i in xrange(8): + octNode = octreeNode(axisDividedVerts[i], self) + # Set bounds manually + if i == 0: + octNode.minx = divx + octNode.maxx = self.maxx + octNode.miny = divy + octNode.maxy = self.maxy + octNode.minz = divz + octNode.maxz = self.maxz + elif i == 1: + octNode.minx = divx + octNode.maxx = self.maxx + octNode.miny = divy + octNode.maxy = self.maxy + octNode.minz = self.minz # + octNode.maxz = divz # + elif i == 2: + octNode.minx = divx + octNode.maxx = self.maxx + octNode.miny = self.miny # + octNode.maxy = divy # + octNode.minz = divz + octNode.maxz = self.maxz + elif i == 3: + octNode.minx = divx + octNode.maxx = self.maxx + octNode.miny = self.miny # + octNode.maxy = divy # + octNode.minz = self.minz # + octNode.maxz = divz # + elif i == 4: + octNode.minx = self.minx # + octNode.maxx = divx # + octNode.miny = divy + octNode.maxy = self.maxy + octNode.minz = divz + octNode.maxz = self.maxz + elif i == 5: + octNode.minx = self.minx # + octNode.maxx = divx # + octNode.miny = divy + octNode.maxy = self.maxy + octNode.minz = self.minz # + octNode.maxz = divz # + elif i == 6: + octNode.minx = self.minx # + octNode.maxx = divx # + octNode.miny = self.miny # + octNode.maxy = divy # + octNode.minz = divz + octNode.maxz = self.maxz + elif i == 7: + octNode.minx = self.minx # + octNode.maxx = divx # + octNode.miny = self.miny # + octNode.maxy = divy # + octNode.minz = self.minz # + octNode.maxz = divz # + #octNode.setCornerPoints() + octNode.splitNode() # Splits the node if it can. + self.children.append(octNode) + + # GETS VERTS IN A Distance RANGE- + def getVertsInRange(self, loc, normal, range_val, vertList): + #loc= Mathutils.Vector(loc) # MUST BE VECTORS + #normal= Mathutils.Vector(normal) + + ''' + loc: Vector of the location to search from + normal: None or Vector - if a vector- will only get verts on this side of the vector + range_val: maximum distance. A negative value will fill the list with teh closest vert only. + vertList: starts as an empty list + list that this function fills with verts that match + ''' + xloc,yloc,zloc= loc + + if range_val<0: + range_val= -range_val + FIND_CLOSEST= True + vertList.append(None) # just update the 1 vertex + else: + FIND_CLOSEST= False + + if self.children: + # Check if the bounds are in range_val, + for childNode in self.children: + # First test if we are surrounding the point. + if\ + childNode.minx - range_val < xloc and\ + childNode.maxx + range_val > xloc and\ + childNode.miny - range_val < yloc and\ + childNode.maxy + range_val > yloc and\ + childNode.minz - range_val < zloc and\ + childNode.maxz + range_val > zloc: + # Recurse down or get virts. + childNode.getVertsInRange(loc, normal, range_val, vertList) + #continue # Next please + + else: # we are a leaf node. Test vert locations. + if not normal: + # Length only check + for v in self.verts: + length = (loc - v.co).length + if length < range_val: + if FIND_CLOSEST: + # Just update the 1 vert + vertList[0]= (v, length) + range_val= length # Shink the length so we only get verts from their. + else: + vertList.append((v, length)) + else: + # Lengh and am I infront of the vert. + for v in self.verts: + length = (loc - v.co).length + if length < range_val: + # Check if the points in front + dot= DotVecs(normal, loc) - DotVecs(normal, v.co) + if dot<0: + vertList.append((v, length)) + +# END TREE + + + + +# EXAMPLE RADIO IN PYTHON USING THE ABOVE FUNCTION +""" +import BPyMesh +# Radio bake +def bake(): + + _AngleBetweenVecs_= Mathutils.AngleBetweenVecs + def AngleBetweenVecs(a1,a2): + try: + return _AngleBetweenVecs_(a1,a2) + except: + return 180 + + + + scn = Scene.GetCurrent() + ob = scn.getActiveObject() + me = ob.getData(mesh=1) + + dist= Draw.PupFloatInput('MaxDist:', 2.0, 0.1, 20.0, 0.1, 3) + if dist==None: + return + + # Make nice normals + BPyMesh.meshCalcNormals(me) + + + len_verts= len(me.verts) + #me.sel= False + meshOctTree = octreeNode(me.verts, None) + + + + # Store face areas + vertex_areas= [0.0] * len_verts + + # Get vertex areas - all areas of face users + for f in me.faces: + a= f.area + for v in f.v: + vertex_areas[v.index] += a + + + + bias= 0.001 + + t= sys.time() + + # Tone for the verts + vert_tones= [0.0] * len_verts + maxtone= 0.0 + mintone= 100000000 + for i, v in enumerate(me.verts): + if not i%10: + print 'verts to go', len_verts-i + v_co= v.co + v_no= v.no + verts_in_range= [] + meshOctTree.getVertsInRange(v_co, v_no, dist, verts_in_range) + + tone= 0.0 + # These are verts in our range + for test_v, length in verts_in_range: + if bias 90: # were facing this vert + #if 1: + # Current value us between zz90 and 180 + # make between 0 and 90 + # so 0 is right angles and 90 is direct opposite vertex normal + normal_diff= (normal_diff-90) + + # Vertex area needs to be taken into account so we dont have small faces over influencing. + vertex_area= vertex_areas[test_v.index] + + # Get the angle the vertex is in location from the location and normal of the vert. + above_diff= AngleBetweenVecs(test_v.co-v.co, v_no) + ## Result will be between 0 :above and 90: horizon.. invert this so horizon has littel effect + above_diff= 90-above_diff + # dist-length or 1.0/length both work well + tone= (dist-length) * vertex_area * above_diff * normal_diff + vert_tones[i] += tone + + if maxtonevert_tones[i]: + mintone= vert_tones[i] + + + if not maxtone: + Draw.PupMenu('No verts in range, use a larger range') + return + + # Apply tones + for f in me.faces: + f_col= f.col + for i, v in enumerate(f.v): + c= f_col[i] + v_index= v.index + tone= int(((maxtone - vert_tones[v.index]) / maxtone) * 255 ) + #print tone + c.r= c.g= c.b= tone + + print 'time', sys.time()-t + + +if __name__=="__main__": + bake() +""" \ No newline at end of file diff --git a/release/scripts/bpymodules/BPyMesh_redux.py b/release/scripts/bpymodules/BPyMesh_redux.py new file mode 100644 index 00000000000..1bcc6e9f7c8 --- /dev/null +++ b/release/scripts/bpymodules/BPyMesh_redux.py @@ -0,0 +1,653 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# (C) Copyright 2006 MetaVR, Inc. +# http://www.metavr.com +# Written by Campbell Barton +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender +import bpy +Vector= Blender.Mathutils.Vector +Ang= Blender.Mathutils.AngleBetweenVecs +CrossVecs= Blender.Mathutils.CrossVecs +MidpointVecs= Blender.Mathutils.MidpointVecs +import BPyMesh + +# If python version is less than 2.4, try to get set stuff from module + +try: + set +except: + try: + from sets import Set as set + except: + set= None + +def uv_key(uv): + return round(uv.x, 5), round(uv.y, 5) + +def uv_key_mix(uv1, uv2, w1, w2): + # Weighted mix. w1+w2==1.0 + return w1*uv1[0]+w2*uv2[0], w1*uv1[1]+w2*uv2[1] + +def col_key(col): + return col.r, col.g, col.b + +def col_key_mix(col1, col2, w1, w2): + # Weighted mix. w1+w2==1.0 + return int(w1*col1[0] + w2*col2[0]), int(w1*col1[1] + w2*col2[1]), int(w1*col1[2]+col2[2]*w2) + + +def redux(ob, REDUX=0.5, BOUNDRY_WEIGHT=2.0, REMOVE_DOUBLES=False, FACE_AREA_WEIGHT=1.0, FACE_TRIANGULATE=True, DO_UV=True, DO_VCOL=True, DO_WEIGHTS=True, VGROUP_INF_REDUX= None, VGROUP_INF_WEIGHT=0.5): + """ + BOUNDRY_WEIGHT - 0 is no boundry weighting. 2.0 will make them twice as unlikely to collapse. + FACE_AREA_WEIGHT - 0 is no weight. 1 is normal, 2.0 is higher. + """ + + if REDUX<0 or REDUX>1.0: + raise 'Error, factor must be between 0 and 1.0' + elif not set: + raise 'Error, this function requires Python 2.4 or a full install of Python 2.3' + + BOUNDRY_WEIGHT= 1+BOUNDRY_WEIGHT + + """ # DEBUG! + if Blender.Get('rt') == 1000: + DEBUG=True + else: + DEBUG= False + """ + + me= ob.getData(mesh=1) + me.hide= False # unhide all data,. + if len(me.faces)<5: + return + + + + if FACE_TRIANGULATE or REMOVE_DOUBLES: + me.sel= True + + if FACE_TRIANGULATE: + me.quadToTriangle() + + if REMOVE_DOUBLES: + me.remDoubles(0.0001) + + vgroups= me.getVertGroupNames() + + if not me.getVertGroupNames(): + DO_WEIGHTS= False + + if (VGROUP_INF_REDUX!= None and VGROUP_INF_REDUX not in vgroups) or\ + VGROUP_INF_WEIGHT==0.0: + VGROUP_INF_REDUX= None + + try: + VGROUP_INF_REDUX_INDEX= vgroups.index(VGROUP_INF_REDUX) + except: + VGROUP_INF_REDUX_INDEX= -1 + + # del vgroups + len_vgroups= len(vgroups) + + + + OLD_MESH_MODE= Blender.Mesh.Mode() + Blender.Mesh.Mode(Blender.Mesh.SelectModes.VERTEX) + + if DO_UV and not me.faceUV: + DO_UV= False + + if DO_VCOL and not me.vertexColors: + DO_VCOL = False + + current_face_count= len(me.faces) + target_face_count= int(current_face_count * REDUX) + # % of the collapseable faces to collapse per pass. + #collapse_per_pass= 0.333 # between 0.1 - lots of small nibbles, slow but high q. and 0.9 - big passes and faster. + collapse_per_pass= 0.333 # between 0.1 - lots of small nibbles, slow but high q. and 0.9 - big passes and faster. + + """# DEBUG! + if DEBUG: + COUNT= [0] + def rd(): + if COUNT[0]< 330: + COUNT[0]+=1 + return + me.update() + Blender.Window.RedrawAll() + print 'Press key for next, count "%s"' % COUNT[0] + try: input() + except KeyboardInterrupt: + raise "Error" + except: + pass + + COUNT[0]+=1 + """ + + class collapseEdge(object): + __slots__ = 'length', 'key', 'faces', 'collapse_loc', 'v1', 'v2','uv1', 'uv2', 'col1', 'col2', 'collapse_weight' + def __init__(self, ed): + self.init_from_edge(ed) # So we can re-use the classes without using more memory. + + def init_from_edge(self, ed): + self.key= ed.key + self.length= ed.length + self.faces= [] + self.v1= ed.v1 + self.v2= ed.v2 + if DO_UV or DO_VCOL: + self.uv1= [] + self.uv2= [] + self.col1= [] + self.col2= [] + + # self.collapse_loc= None # new collapse location. + # Basic weighting. + #self.collapse_weight= self.length * (1+ ((ed.v1.no-ed.v2.no).length**2)) + self.collapse_weight= 1.0 + + def collapse_locations(self, w1, w2): + ''' + Generate a smart location for this edge to collapse to + w1 and w2 are vertex location bias + ''' + + v1co= self.v1.co + v2co= self.v2.co + v1no= self.v1.no + v2no= self.v2.no + + # Basic operation, works fine but not as good as predicting the best place. + #between= ((v1co*w1) + (v2co*w2)) + #self.collapse_loc= between + + # normalize the weights of each vert - se we can use them as scalers. + wscale= w1+w2 + if not wscale: # no scale? + w1=w2= 0.5 + else: + w1/=wscale + w2/=wscale + + length= self.length + between= MidpointVecs(v1co, v2co) + + # Collapse + # new_location = between # Replace tricky code below. this code predicts the best collapse location. + + # Make lines at right angles to the normals- these 2 lines will intersect and be + # the point of collapsing. + + # Enlarge so we know they intersect: self.length*2 + cv1= CrossVecs(v1no, CrossVecs(v1no, v1co-v2co)) + cv2= CrossVecs(v2no, CrossVecs(v2no, v2co-v1co)) + + # Scale to be less then the edge lengths. + cv2.length = cv1.length = 1 + + cv1 = cv1 * (length* 0.4) + cv2 = cv2 * (length* 0.4) + + smart_offset_loc= between + (cv1 + cv2) + + # Now we need to blend between smart_offset_loc and w1/w2 + # you see were blending between a vert and the edges midpoint, so we cant use a normal weighted blend. + if w1 > 0.5: # between v1 and smart_offset_loc + #self.collapse_loc= v1co*(w2+0.5) + smart_offset_loc*(w1-0.5) + w2*=2 + w1= 1-w2 + new_loc_smart= v1co*w1 + smart_offset_loc*w2 + else: # w between v2 and smart_offset_loc + w1*=2 + w2= 1-w1 + new_loc_smart= v2co*w2 + smart_offset_loc*w1 + + if new_loc_smart.x != new_loc_smart.x: # NAN LOCATION, revert to between + new_loc_smart= None + + return new_loc_smart, between, v1co*0.99999 + v2co*0.00001, v1co*0.00001 + v2co*0.99999 + + + class collapseFace(object): + __slots__ = 'verts', 'normal', 'area', 'index', 'orig_uv', 'orig_col', 'uv', 'col' # , 'collapse_edge_count' + def __init__(self, f): + self.init_from_face(f) + + def init_from_face(self, f): + self.verts= f.v + self.normal= f.no + self.area= f.area + self.index= f.index + if DO_UV: + self.orig_uv= [uv_key(uv) for uv in f.uv] + self.uv= f.uv + if DO_VCOL: + self.orig_col= [col_key(col) for col in f.col] + self.col= f.col + + collapse_edges= collapse_faces= None + + # So meshCalcNormals can avoid making a new list all the time. + reuse_vertNormals= [ Vector() for v in xrange(len(me.verts)) ] + + while target_face_count <= len(me.faces): + BPyMesh.meshCalcNormals(me, reuse_vertNormals) + + if DO_WEIGHTS: + #groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me) + groupNames, vWeightList= BPyMesh.meshWeight2List(me) + + # THIS CRASHES? Not anymore. + verts= list(me.verts) + edges= list(me.edges) + faces= list(me.faces) + + # THIS WORKS + #verts= me.verts + #edges= me.edges + #faces= me.faces + + # if DEBUG: DOUBLE_CHECK= [0]*len(verts) + me.sel= False + + if not collapse_faces: # Initialize the list. + collapse_faces= [collapseFace(f) for f in faces] + collapse_edges= [collapseEdge(ed) for ed in edges] + else: + for i, ed in enumerate(edges): + collapse_edges[i].init_from_edge(ed) + + # Strip the unneeded end off the list + collapse_edges[i+1:]= [] + + for i, f in enumerate(faces): + collapse_faces[i].init_from_face(f) + + # Strip the unneeded end off the list + collapse_faces[i+1:]= [] + + + collapse_edges_dict= dict( [(ced.key, ced) for ced in collapse_edges] ) + + # Store verts edges. + vert_ed_users= [[] for i in xrange(len(verts))] + for ced in collapse_edges: + vert_ed_users[ced.key[0]].append(ced) + vert_ed_users[ced.key[1]].append(ced) + + # Store face users + vert_face_users= [[] for i in xrange(len(verts))] + + # Have decieded not to use this. area is better. + #face_perim= [0.0]* len(me.faces) + + for ii, cfa in enumerate(collapse_faces): + for i, v1 in enumerate(cfa.verts): + vert_face_users[v1.index].append( (i,cfa) ) + + # add the uv coord to the vert + v2 = cfa.verts[i-1] + i1= v1.index + i2= v2.index + + if i1>i2: ced= collapse_edges_dict[i2,i1] + else: ced= collapse_edges_dict[i1,i2] + + ced.faces.append(cfa) + if DO_UV or DO_VCOL: + # if the edge is flipped from its order in the face then we need to flip the order indicies. + if cfa.verts[i]==ced.v1: i1,i2 = i, i-1 + else: i1,i2 = i-1, i + + if DO_UV: + ced.uv1.append( cfa.orig_uv[i1] ) + ced.uv2.append( cfa.orig_uv[i2] ) + + if DO_VCOL: + ced.col1.append( cfa.orig_col[i1] ) + ced.col2.append( cfa.orig_col[i2] ) + + + # PERIMITER + #face_perim[ii]+= ced.length + + + + # How weight the verts by the area of their faces * the normal difference. + # when the edge collapses, to vert weights are taken into account + + vert_weights= [0.5] * len(verts) + + for ii, vert_faces in enumerate(vert_face_users): + for f in vert_faces: + try: + no_ang= (Ang(verts[ii].no, f[1].normal)/180) * f[1].area + except: + no_ang= 1.0 + + vert_weights[ii] += no_ang + + # Use a vertex group as a weighting. + if VGROUP_INF_REDUX!=None: + + # Get Weights from a vgroup. + """ + vert_weights_map= [1.0] * len(verts) + for i, wd in enumerate(vWeightDict): + try: vert_weights_map[i]= 1+(wd[VGROUP_INF_REDUX] * VGROUP_INF_WEIGHT) + except: pass + """ + vert_weights_map= [1+(wl[VGROUP_INF_REDUX_INDEX]*VGROUP_INF_WEIGHT) for wl in vWeightList ] + + + # BOUNDRY CHECKING AND WEIGHT EDGES. CAN REMOVE + # Now we know how many faces link to an edge. lets get all the boundry verts + if BOUNDRY_WEIGHT > 0: + verts_boundry= [1] * len(verts) + #for ed_idxs, faces_and_uvs in edge_faces_and_uvs.iteritems(): + for ced in collapse_edges: + if len(ced.faces) < 2: + for key in ced.key: # only ever 2 key indicies. + verts_boundry[key]= 2 + + for ced in collapse_edges: + b1= verts_boundry[ced.key[0]] + b2= verts_boundry[ced.key[1]] + if b1 != b2: + # Edge has 1 boundry and 1 non boundry vert. weight higher + ced.collapse_weight= BOUNDRY_WEIGHT + #elif b1==b2==2: # if both are on a seam then weigh half as bad. + # ced.collapse_weight= ((BOUNDRY_WEIGHT-1)/2) +1 + # weight the verts by their boundry status + del b1 + del b2 + + for ii, boundry in enumerate(verts_boundry): + if boundry==2: + vert_weights[ii] *= BOUNDRY_WEIGHT + + vert_collapsed= verts_boundry + del verts_boundry + else: + vert_collapsed= [1] * len(verts) + + + + + # Best method, no quick hacks here, Correction. Should be the best but needs tweaks. + def ed_set_collapse_error(ced): + # Use the vertex weights to bias the new location. + new_locs= ced.collapse_locations(vert_weights[ced.key[0]], vert_weights[ced.key[1]]) + + + # Find the connecting faces of the 2 verts. + i1, i2= ced.key + test_faces= set() + for i in (i1,i2): # faster then LC's + for f in vert_face_users[i]: + test_faces.add(f[1].index) + for f in ced.faces: + test_faces.remove(f.index) + + + v1_orig= Vector(ced.v1.co) + v2_orig= Vector(ced.v2.co) + + def test_loc(new_loc): + ''' + Takes a location and tests the error without changing anything + ''' + new_weight= ced.collapse_weight + ced.v1.co= ced.v2.co= new_loc + + new_nos= [faces[i].no for i in test_faces] + + # So we can compare the befire and after normals + ced.v1.co= v1_orig + ced.v2.co= v2_orig + + # now see how bad the normals are effected + angle_diff= 1.0 + + for ii, i in enumerate(test_faces): # local face index, global face index + cfa= collapse_faces[i] # this collapse face + try: + # can use perim, but area looks better. + if FACE_AREA_WEIGHT: + # Psudo code for wrighting + # angle_diff= The before and after angle difference between the collapsed and un-collapsed face. + # ... devide by 180 so the value will be between 0 and 1.0 + # ... add 1 so we can use it as a multiplyer and not make the area have no eefect (below) + # area_weight= The faces original area * the area weight + # ... add 1.0 so a small area face dosent make the angle_diff have no effect. + # + # Now multiply - (angle_diff * area_weight) + # ... The weight will be a minimum of 1.0 - we need to subtract this so more faces done give the collapse an uneven weighting. + + angle_diff+= ((1+(Ang(cfa.normal, new_nos[ii])/180)) * (1+(cfa.area * FACE_AREA_WEIGHT))) -1 # 4 is how much to influence area + else: + angle_diff+= (Ang(cfa.normal), new_nos[ii])/180 + + except: + pass + + + # This is very arbirary, feel free to modify + try: no_ang= (Ang(ced.v1.no, ced.v2.no)/180) + 1 + except: no_ang= 2.0 + + # do *= because we face the boundry weight to initialize the weight. 1.0 default. + new_weight *= ((no_ang * ced.length) * (1-(1/angle_diff)))# / max(len(test_faces), 1) + return new_weight + # End testloc + + + # Test the collapse locatons + collapse_loc_best= None + collapse_weight_best= 1000000000 + ii= 0 + for collapse_loc in new_locs: + if collapse_loc: # will only ever fail if smart loc is NAN + test_weight= test_loc(collapse_loc) + if test_weight < collapse_weight_best: + iii= ii + collapse_weight_best = test_weight + collapse_loc_best= collapse_loc + ii+=1 + + ced.collapse_loc= collapse_loc_best + ced.collapse_weight= collapse_weight_best + + + # are we using a weight map + if VGROUP_INF_REDUX: + v= vert_weights_map[i1]+vert_weights_map[i2] + ced.collapse_weight*= v + # End collapse Error + + # We can calculate the weights on __init__ but this is higher qualuity. + for ced in collapse_edges: + if ced.faces: # dont collapse faceless edges. + ed_set_collapse_error(ced) + + # Wont use the function again. + del ed_set_collapse_error + # END BOUNDRY. Can remove + + # sort by collapse weight + try: collapse_edges.sort(key = lambda ced: ced.collapse_weight) # edges will be used for sorting + except: collapse_edges.sort(lambda ced1, ced2: cmp(ced1.collapse_weight, ced2.collapse_weight)) # edges will be used for sorting + + + vert_collapsed= [0]*len(verts) + + collapse_edges_to_collapse= [] + + # Make a list of the first half edges we can collapse, + # these will better edges to remove. + collapse_count=0 + for ced in collapse_edges: + if ced.faces: + i1, i2= ced.key + # Use vert selections + if vert_collapsed[i1] or vert_collapsed[i2]: + pass + else: + # Now we know the verts havnyt been collapsed. + vert_collapsed[i2]= vert_collapsed[i1]= 1 # Dont collapse again. + collapse_count+=1 + collapse_edges_to_collapse.append(ced) + + # Get a subset of the entire list- the first "collapse_per_pass", that are best to collapse. + if collapse_count > 4: + collapse_count = int(collapse_count*collapse_per_pass) + else: + collapse_count = len(collapse_edges) + # We know edge_container_list_collapse can be removed. + for ced in collapse_edges_to_collapse: + """# DEBUG! + if DEBUG: + if DOUBLE_CHECK[ced.v1.index] or\ + DOUBLE_CHECK[ced.v2.index]: + raise 'Error' + else: + DOUBLE_CHECK[ced.v1.index]=1 + DOUBLE_CHECK[ced.v2.index]=1 + + tmp= (ced.v1.co+ced.v2.co)*0.5 + Blender.Window.SetCursorPos(tmp.x, tmp.y, tmp.z) + Blender.Window.RedrawAll() + """ + + # Chech if we have collapsed our quota. + collapse_count-=1 + if not collapse_count: + break + + current_face_count -= len(ced.faces) + + # Find and assign the real weights based on collapse loc. + + # Find the weights from the collapse error + if DO_WEIGHTS or DO_UV or DO_VCOL: + i1, i2= ced.key + # Dont use these weights since they may not have been used to make the collapse loc. + #w1= vert_weights[i1] + #w2= vert_weights[i2] + w1= (ced.v2.co-ced.collapse_loc).length + w2= (ced.v1.co-ced.collapse_loc).length + + # Normalize weights + wscale= w1+w2 + if not wscale: # no scale? + w1=w2= 0.5 + else: + w1/= wscale + w2/= wscale + + + # Interpolate the bone weights. + if DO_WEIGHTS: + + # add verts vgroups to eachother + wl1= vWeightList[i1] # v1 weight dict + wl2= vWeightList[i2] # v2 weight dict + for group_index in xrange(len_vgroups): + wl1[group_index]= wl2[group_index]= (wl1[group_index]*w1) + (wl2[group_index]*w2) + # Done finding weights. + + + + if DO_UV or DO_VCOL: + # Handel UV's and vert Colors! + for v, my_weight, other_weight, edge_my_uvs, edge_other_uvs, edge_my_cols, edge_other_cols in (\ + (ced.v1, w1, w2, ced.uv1, ced.uv2, ced.col1, ced.col2),\ + (ced.v2, w2, w1, ced.uv2, ced.uv1, ced.col2, ced.col1)\ + ): + uvs_mixed= [ uv_key_mix(edge_my_uvs[iii], edge_other_uvs[iii], my_weight, other_weight) for iii in xrange(len(edge_my_uvs)) ] + cols_mixed= [ col_key_mix(edge_my_cols[iii], edge_other_cols[iii], my_weight, other_weight) for iii in xrange(len(edge_my_cols)) ] + + for face_vert_index, cfa in vert_face_users[v.index]: + if len(cfa.verts)==3 and cfa not in ced.faces: # if the face is apart of this edge then dont bother finding the uvs since the face will be removed anyway. + + if DO_UV: + # UV COORDS + uvk= cfa.orig_uv[face_vert_index] + try: + tex_index= edge_my_uvs.index(uvk) + except: + tex_index= None + """ # DEBUG! + if DEBUG: + print 'not found', uvk, 'in', edge_my_uvs, 'ed index', ii, '\nwhat about', edge_other_uvs + """ + if tex_index != None: # This face uses a uv in the collapsing face. - do a merge + other_uv= edge_other_uvs[tex_index] + uv_vec= cfa.uv[face_vert_index] + uv_vec.x, uv_vec.y= uvs_mixed[tex_index] + + # TEXFACE COLORS + if DO_VCOL: + colk= cfa.orig_col[face_vert_index] + try: tex_index= edge_my_cols.index(colk) + except: pass + if tex_index != None: + other_col= edge_other_cols[tex_index] + col_ob= cfa.col[face_vert_index] + col_ob.r, col_ob.g, col_ob.b= cols_mixed[tex_index] + + # DEBUG! if DEBUG: rd() + + # Execute the collapse + ced.v1.sel= ced.v2.sel= True # Select so remove doubles removed the edges and faces that use it + ced.v1.co= ced.v2.co= ced.collapse_loc + + # DEBUG! if DEBUG: rd() + if current_face_count <= target_face_count: + break + + # Copy weights back to the mesh before we remove doubles. + if DO_WEIGHTS: + #BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict) + BPyMesh.list2MeshWeight(me, groupNames, vWeightList) + + doubles= me.remDoubles(0.0001) + current_face_count= len(me.faces) + + if current_face_count <= target_face_count or not doubles: # not doubles shoule never happen. + break + + me.update() + Blender.Mesh.Mode(OLD_MESH_MODE) + + +# Example usage +def main(): + Blender.Window.EditMode(0) + scn= bpy.data.scenes.active + active_ob= scn.objects.active + t= Blender.sys.time() + redux(active_ob, 0.5) + print '%.4f' % (Blender.sys.time()-t) + +if __name__=='__main__': + main() diff --git a/release/scripts/bpymodules/BPyMessages.py b/release/scripts/bpymodules/BPyMessages.py new file mode 100644 index 00000000000..0ff8e178ac1 --- /dev/null +++ b/release/scripts/bpymodules/BPyMessages.py @@ -0,0 +1,59 @@ +from Blender import Draw, sys +def Error_NoMeshSelected(): + Draw.PupMenu('Error%t|No mesh objects selected') +def Error_NoActive(): + Draw.PupMenu('Error%t|No active object') +def Error_NoMeshActive(): + Draw.PupMenu('Error%t|Active object is not a mesh') +def Error_NoMeshUvSelected(): + Draw.PupMenu('Error%t|No mesh objects with texface selected') +def Error_NoMeshUvActive(): + Draw.PupMenu('Error%t|Active object is not a mesh with texface') +def Error_NoMeshMultiresEdit(): + Draw.PupMenu('Error%t|Unable to complete action with multires enabled') + +# File I/O messages +def Error_NoFile(path): + '''True if file missing, False if files there + + Use simply by doing... + if Error_NoFile(path): return + ''' + if not sys.exists(sys.expandpath(path)): + Draw.PupMenu("Error%t|Can't open file: " + path) + return True + return False + +def Error_NoDir(path): + '''True if dirs missing, False if dirs there + + Use simply by doing... + if Error_NoDir(path): return + ''' + if not sys.exists(sys.expandpath(path)): + Draw.PupMenu("Error%t|Path does not exist: " + path) + return True + return False + + +def Warning_MeshDistroyLayers(mesh): + '''Returns true if we can continue to edit the mesh, warn when using NMesh''' + if len(mesh.getUVLayerNames()) >1 and len(mesh.getColorLayerNames()) >1: + return True + + ret = Draw.PupMenu('Warning%t|This script will distroy inactive UV and Color layers, OK?') + if ret == -1: + return False + + return True + +def Warning_SaveOver(path): + '''Returns - True to save, False dont save''' + if sys.exists(sys.expandpath(path)): + ret= Draw.PupMenu('Save over%t|' + path) + if ret == -1: + return False + + return True + + diff --git a/release/scripts/bpymodules/BPyNMesh.py b/release/scripts/bpymodules/BPyNMesh.py new file mode 100644 index 00000000000..043d8514db9 --- /dev/null +++ b/release/scripts/bpymodules/BPyNMesh.py @@ -0,0 +1,48 @@ +# $Id$ +# +# -------------------------------------------------------------------------- +# BPyNMesh.py version 0.1 +# -------------------------------------------------------------------------- +# helper functions to be used by other scripts +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +# -------------------------------------------------------------------------- +# "Apply size and rotation" function by Jonas Petersen +# -------------------------------------------------------------------------- +# This function does (hopefully) exactly what the +# "Apply size and rotation" command does (CTRL-A in Object Mode). +def ApplySizeAndRotation(obj): + if obj.getType() != "Mesh": return + if obj.SizeX==1.0 and obj.SizeY==1.0 and obj.SizeZ==1.0 and obj.RotX == 0.0 and obj.RotY == 0.0 and obj.RotZ == 0.0: return + mesh = obj.getData() + matrix = obj.matrix + v = [0,0,0] + for vert in mesh.verts: + co = vert.co + v[0] = co[0]*matrix[0][0] + co[1]*matrix[1][0] + co[2]*matrix[2][0] + v[1] = co[0]*matrix[0][1] + co[1]*matrix[1][1] + co[2]*matrix[2][1] + v[2] = co[0]*matrix[0][2] + co[1]*matrix[1][2] + co[2]*matrix[2][2] + co[0], co[1], co[2] = v + obj.SizeX = obj.SizeY = obj.SizeZ = 1.0 + obj.RotX = obj.RotY = obj.RotZ = 0.0 + mesh.update() + diff --git a/release/scripts/bpymodules/BPyObject.py b/release/scripts/bpymodules/BPyObject.py new file mode 100644 index 00000000000..54ff949218d --- /dev/null +++ b/release/scripts/bpymodules/BPyObject.py @@ -0,0 +1,108 @@ +import Blender + +def getObjectArmature(ob): + ''' + This returns the first armature the mesh uses. + remember there can be more then 1 armature but most people dont do that. + ''' + if ob.type != 'Mesh': + return None + + arm = ob.parent + if arm and arm.type == 'Armature' and ob.parentType == Blender.Object.ParentTypes.ARMATURE: + return arm + + for m in ob.modifiers: + if m.type== Blender.Modifier.Types.ARMATURE: + arm = m[Blender.Modifier.Settings.OBJECT] + if arm: + return arm + + return None + + +def getDerivedObjects(ob, PARTICLES= True): + ''' + Takes an objects and returnes a list of (ob, maxrix4x4) pairs + that are derived from this object - + This will include the object its self if it would be rendered. + all dupli's for eg are not rendered themselves. + + currently supports + * dupligroups + * dupliverts + * dupliframes + * static particles as a mesh + + it is possible this function will return an empty list. + ''' + + ob_mtx_pairs = ob.DupObjects + effects= ob.effects + + # Ignore self if were a dupli* or our parent is a duplivert. + if ob.enableDupFrames or ob.enableDupGroup or ob.enableDupVerts: + pass + else: + parent= ob.parent + if parent and parent.enableDupVerts: + pass + else: + if effects and (not effects[0].flag & Blender.Effect.Flags.EMESH): + # Particles mesh wont render + pass + else: + ob_mtx_pairs.append((ob, ob.matrixWorld)) + + + if PARTICLES: + type_vec= type(Blender.Mathutils.Vector()) + type_tp= type((0,0)) + type_ls= type([]) + + # TODO, particles per child object. + # TODO Support materials + me= Blender.Mesh.New() + for eff in effects: + par= eff.getParticlesLoc() + + if par: + type_par= type(par[0]) + + if type_par == type_vec: + # point particles + me.verts.extend(par) + + elif type_par == type_tp: + # edge pairs + start_index= len(me.verts) + me.verts.extend([v for p in par for v in p]) + me.edges.extend( [(i, i+1) for i in xrange(start_index, start_index + len(par) - 1 )] ) + + elif type_par == type_ls: + # lines of edges + start_index= len(me.verts) + me.verts.extend([v for line in par for v in line]) + + edges= [] + for line in par: + edges.extend( [(i,i+1) for i in xrange(start_index, start_index+len(line)-1) ] ) + start_index+= len(line) + + me.edges.extend(edges) + + if me.verts: + # If we have verts, then add the mesh + ob_par = Blender.Object.New('Mesh') + ob_par.link( me ) + + LOOSE= Blender.Mesh.EdgeFlags.LOOSE + for ed in me.edges: + ed.flag |= LOOSE + + # Particle's are in worldspace so an identity matrix is fine. + ob_mtx_pairs.append( (ob_par, Blender.Mathutils.Matrix()) ) + + return ob_mtx_pairs + + diff --git a/release/scripts/bpymodules/BPyRegistry.py b/release/scripts/bpymodules/BPyRegistry.py new file mode 100644 index 00000000000..f0d6da82d52 --- /dev/null +++ b/release/scripts/bpymodules/BPyRegistry.py @@ -0,0 +1,258 @@ +# -------------------------------------------------------------------------- +# Module BPyRegistry version 0.1 +# Helper functions to store / restore configuration data. +# -------------------------------------------------------------------------- +# $Id$ +# +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2004: Willian P. Germano, wgermano _at_ ig.com.br +# +# 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, +# -------------------------------------------------------------------------- + +# The Registry is a Python dictionary that is kept in Blender for as long as +# the program is running, where scripts can store / restore persistent data +# (data that is not lost when the script exits). This module provides +# functions to save and restore Registry entries as config data in the +# bpydata/config folder. Scripts just need to give an extra parameter to +# the Blender.Registry.Get/Set() functions to have their data automatically +# saved and restored when needed. +# +# Note: entries starting with an underscore are not saved, so script authors +# can use that fact to define data that is not meant to be stored in a +# config file. Example: data to be passed to another script and references to +# invalid data, like Blender objects and any function or method. +# +# Check the Blender.Registry documentation for more information. + +import Blender +from Blender import Registry, sys as bsys + +_EXT = '.cfg' # file extension for saved config data + +# limits: +#MAX_ITEMS_NUM = 60 # max number of keys per dict and itens per list and tuple +#MAX_STR_LEN = 300 # max string length (remember this is just for config data) + +_CFG_DIR = '' +if Blender.Get('udatadir'): + _CFG_DIR = Blender.sys.join(Blender.Get('udatadir'), 'config') +if not _CFG_DIR or not bsys.exists(_CFG_DIR): + _CFG_DIR = Blender.sys.join(Blender.Get('datadir'), 'config') +if not bsys.exists(_CFG_DIR): + _CFG_DIR = '' + +# to compare against, so we don't write to a cvs tree: +_CVS_SUBPATH = 'release/scripts/bpydata/config/' +if bsys.dirsep == '\\': + _CVS_SUBPATH = _CVS_SUBPATH.replace('/', '\\') + +_KEYS = [k for k in Registry.Keys() if k[0] != '_'] + +# _ITEMS_NUM = 0 + +def _sanitize(o): + "Check recursively that all objects are valid, set invalid ones to None" + + # global MAX_ITEMS_NUM, MAX_STR_LEN, _ITEMS_NUM + + valid_types = [int, float, bool, long, type] + valid_checked_types = [str, unicode] + # Only very simple types are considered valid for configuration data, + # functions, methods and Blender objects (use their names instead) aren't. + + t = type(o) + + if t == dict: + ''' + _ITEMS_NUM += len(o) + if _ITEMS_NUM > MAX_ITEMS_NUM: + return None + ''' + for k, v in o.iteritems(): + o[k] = _sanitize(v) + elif t in [list, tuple]: + ''' + _ITEMS_NUM += len(o) + if _ITEMS_NUM > MAX_ITEMS_NUM: + return None + ''' + return [_sanitize(i) for i in o] + elif t in valid_types: + return o + elif t in valid_checked_types: + ''' + if len(o) > MAX_STR_LEN: + o = o[:MAX_STR_LEN] + ''' + return o + else: return None + + return o + + +def _dict_to_str(name, d): + "Return a pretty-print version of the passed dictionary" + if not d: return 'None' # d can be None if there was no config to pass + + if name: l = ['%s = {' % name] + else: l = ['{'] + #keys = d.keys() + for k,v in d.iteritems(): # .keys() + if type(v) == dict: + l.append("'%s': %s" % (k, _dict_to_str(None, v))) + else: + l.append("'%s': %s," % (k, repr(v))) + if name: l.append('}') + else: l.append('},') + return "\n".join(l) + +_HELP_MSG = """ +Please create a valid scripts config dir tree either by +copying release/scripts/ tree to your dir +or by copying release/scripts/bpydata/ tree to a user +defined scripts dir that you can set in the +User Preferences -> Paths tab -> Python path input box. +""" + +def _check_dir(): + global _CFG_DIR, _CVS_SUBPATH, _HELP_MSG + + if not _CFG_DIR: + errmsg = "scripts config dir not found!\n%s" % _HELP_MSG + raise IOError, errmsg + elif _CFG_DIR.find(_CVS_SUBPATH) > 0: + errmsg = """ +Your scripts config dir:\n%s +seems to reside in your local Blender's cvs tree.\n%s""" % (_CFG_DIR, _HELP_MSG) + raise SystemError, errmsg + else: return + + +# API: + +BPY_KEY_MISSING = 0 +BPY_KEY_IN_REGISTRY = 1 +BPY_KEY_IN_FILE = 2 + +def HasConfigData (key): + """ + Check if the given key exists, either already loaded in the Registry dict or + as a file in the script data config dir. + @type key: string + @param key: a given key name. + @returns: + - 0: key does not exist; + - 1: key exists in the Registry dict only; + - 2: key exists as a file only; + - 3: key exists in the Registry dict and also as a file. + @note: for readability it's better to check against the constant bitmasks + BPY_KEY_MISSING = 0, BPY_KEY_IN_REGISTRY = 1 and BPY_KEY_IN_FILE = 2. + """ + + fname = bsys.join(_CFG_DIR, "%s%s" % (key, _EXT)) + + result = BPY_KEY_MISSING + if key in Registry.Keys(): result |= BPY_KEY_IN_REGISTRY + if bsys.exists(fname): result |= BPY_KEY_IN_FILE + + return result + + +def LoadConfigData (key = None): + """ + Load config data from file(s) to the Registry dictionary. + @type key: string + @param key: a given key name. If None (default), all available keys are + loaded. + @returns: None + """ + + _check_dir() + + import os + + if not key: + files = \ + [bsys.join(_CFG_DIR, f) for f in os.listdir(_CFG_DIR) if f.endswith(_EXT)] + else: + files = [] + fname = bsys.join(_CFG_DIR, "%s%s" % (key, _EXT)) + if bsys.exists(fname): files.append(fname) + + for p in files: + f = file(p, 'r') + lines = f.readlines() + f.close() + if lines: # Lines may be blank + mainkey = lines[0].split('=')[0].strip() + pysrc = "\n".join(lines) + exec(pysrc) + exec("Registry.SetKey('%s', %s)" % (str(mainkey), mainkey)) + + +def RemoveConfigData (key = None): + """ + Remove this key's config file from the <(u)datadir>/config/ folder. + @type key: string + @param key: the name of the key to be removed. If None (default) all + available config files are deleted. + """ + + _check_dir() + + if not key: + files = \ + [bsys.join(_CFG_DIR, f) for f in os.listdir(_CFG_DIR) if f.endswith(_EXT)] + else: + files = [] + fname = bsys.join(_CFG_DIR, "%s%s" % (key, _EXT)) + if bsys.exists(fname): files.append(fname) + + import os + + for p in files: + os.remove(p) # remove the file(s) + + +def SaveConfigData (key = None): + """ + Save Registry key(s) as file(s) in the <(u)datadir>/config/ folder. + @type key: string + @param key: the name of the key to be saved. If None (default) all + available keys are saved. + """ + + global _KEYS, _CFG_DIR + + _check_dir() + + if key: keys = [key] + else: keys = _KEYS + + for mainkey in keys: + cfgdict = Registry.GetKey(mainkey).copy() + for k in cfgdict: # .keys() + if not k or k[0] == '_': + del cfgdict[k] + + if not cfgdict: continue + + filename = bsys.join(_CFG_DIR, "%s%s" % (mainkey, _EXT)) + f = file(filename, 'w') + output = _dict_to_str(mainkey, _sanitize(cfgdict)) + if output!='None': + f.write(output) + f.close() diff --git a/release/scripts/bpymodules/BPyRender.py b/release/scripts/bpymodules/BPyRender.py new file mode 100644 index 00000000000..e335ee7f6a8 --- /dev/null +++ b/release/scripts/bpymodules/BPyRender.py @@ -0,0 +1,498 @@ +import Blender +from Blender import Scene, sys, Camera, Object, Image +from Blender.Scene import Render +Vector= Blender.Mathutils.Vector + + +def extFromFormat(format): + if format == Render.TARGA: return 'tga' + if format == Render.RAWTGA: return 'tga' + if format == Render.HDR: return 'hdr' + if format == Render.PNG: return 'png' + if format == Render.BMP: return 'bmp' + if format == Render.JPEG: return 'jpg' + if format == Render.HAMX: return 'ham' + if format == Render.TIFF: return 'tif' + if format == Render.CINEON: return 'cine' + if format == Render.DPX: return 'tif' + if format == Render.OPENEXR: return 'exr' + if format == Render.IRIS: return 'rgb' + return '' + + + +def imageFromObjectsOrtho(objects, path, width, height, smooth, alpha= True, camera_matrix= None, format=Render.PNG): + ''' + Takes any number of objects and renders them on the z axis, between x:y-0 and x:y-1 + Usefull for making images from a mesh without per pixel operations + - objects must be alredy placed + - smooth, anti alias True/False + - path renders to a PNG image + - alpha weather to render background as alpha + + returns the blender image + ''' + ext = '.' + extFromFormat(format) + print ext + # remove an extension if its alredy there + if path.lower().endswith(ext): + path= path[:-4] + + path_expand= sys.expandpath(path) + ext + + print path_expand, 'path' + + # Touch the path + try: + f= open(path_expand, 'w') + f.close() + except: + raise 'Error, could not write to path:' + path_expand + + + # RENDER THE FACES. + scn= Scene.GetCurrent() + render_scn= Scene.New() + render_scn.makeCurrent() + render_scn.Layers |= (1<<20)-1 # all layers enabled + + # Add objects into the current scene + for ob in objects: + render_scn.link(ob) + + render_context= render_scn.getRenderingContext() + render_context.setRenderPath('') # so we can ignore any existing path and save to the abs path. + + + render_context.imageSizeX(width) + render_context.imageSizeY(height) + + if smooth: + render_context.enableOversampling(True) + render_context.setOversamplingLevel(16) + else: + render_context.enableOversampling(False) + + render_context.setRenderWinSize(100) + render_context.setImageType(format) + render_context.enableExtensions(True) + #render_context.enableSky() # No alpha needed. + if alpha: + render_context.alphaMode= 1 + render_context.enableRGBAColor() + else: + render_context.alphaMode= 0 + render_context.enableRGBColor() + + render_context.displayMode= 0 # fullscreen + + # New camera and object + render_cam_data= Camera.New('ortho') + render_cam_ob= Object.New('Camera') + render_cam_ob.link(render_cam_data) + render_scn.link(render_cam_ob) + render_scn.objects.camera = render_cam_ob + + render_cam_data.type= 'ortho' + + + + # Position the camera + if camera_matrix: + render_cam_ob.setMatrix(camera_matrix) + # We need to take into account the matrix scaling when setting the size + # so we get the image bounds defined by the matrix + # first get the x and y factors from the matrix. + # To render the correct dimensions we must use the aspy and aspy to force the matrix scale to + # override the aspect enforced by the width and weight. + cent= Vector() * camera_matrix + xvec= Vector(1,0,0) * camera_matrix + yvec= Vector(0,1,0) * camera_matrix + # zvec= Vector(0,0,1) * camera_matrix + xlen = (cent-xvec).length # half height of the image + ylen = (cent-yvec).length # half width of the image + # zlen = (cent-zvec).length # dist to place the camera? - just use the loc for now. + + + # less then 1.0 portrate, 1.0 or more is portrate + asp_cam_mat= xlen/ylen # divide by zero? - possible but scripters fault. + asp_image_res= float(width)/height + #print 'asp quad', asp_cam_mat, 'asp_image', asp_image_res + #print 'xylen', xlen, ylen, 'w/h', width, height + # Setup the aspect + + if asp_cam_mat > asp_image_res: + # camera is wider then image res. + # to make the image wider, reduce the aspy + asp_diff= asp_image_res/asp_cam_mat + min_asp= int(round(asp_diff * 200)) + #print 'X', min_asp + + elif asp_cam_mat < asp_image_res: # asp_cam_mat < asp_image_res + # camera is narrower then image res + # to make the image narrower, reduce the aspx + asp_diff= asp_cam_mat/asp_image_res + min_asp= int(round(asp_diff * 200)) + #print 'Y', min_asp + else: + min_asp= 200 + + # set the camera size + if xlen > ylen: + if asp_cam_mat > asp_image_res: + render_context.aspectX= 200 # get the greatest range possible + render_context.aspectY= min_asp # get the greatest range possible + else: + render_context.aspectY= 200 # get the greatest range possible + render_context.aspectX= min_asp # get the greatest range possible + #print "xlen bigger" + render_cam_data.scale= xlen * 2 + elif xlen < ylen:# ylen is bigger + if asp_cam_mat > asp_image_res: + render_context.aspectX= 200 # get the greatest range possible + render_context.aspectY= min_asp # get the greatest range possible + else: + render_context.aspectY= 200 # get the greatest range possible + render_context.aspectX= min_asp # get the greatest range possible + #print "ylen bigger" + render_cam_data.scale= ylen *2 + else: + # asppect 1:1 + #print 'NOLEN Bigger' + render_cam_data.scale= xlen * 2 + + #print xlen, ylen, 'xlen, ylen' + + else: + if width > height: + min_asp = int((float(height) / width) * 200) + render_context.aspectX= min_asp + render_context.aspectY= 200 + else: + min_asp = int((float(width) / height) * 200) + render_context.aspectX= 200 + render_context.aspectY= min_asp + + + render_cam_data.scale= 1.0 + render_cam_ob.LocZ= 1.0 + render_cam_ob.LocX= 0.5 + render_cam_ob.LocY= 0.5 + + Blender.Window.RedrawAll() + + render_context.threads= 2 # good for dual core cpu's + render_context.render() + render_context.saveRenderedImage(path) + Render.CloseRenderWindow() + #if not B.sys.exists(PREF_IMAGE_PATH_EXPAND): + # raise 'Error!!!' + + scn.makeCurrent() + Scene.Unlink(render_scn) + + # NOW APPLY THE SAVED IMAGE TO THE FACES! + #print PREF_IMAGE_PATH_EXPAND + try: + target_image= Image.Load(path_expand) + return target_image + except: + raise 'Error: Could not render or load the image at path "%s"' % path_expand + return + + + +#-----------------------------------------------------------------------------# +# UV Baking functions, make a picture from mesh(es) uvs # +#-----------------------------------------------------------------------------# + +def mesh2uv(me_s, PREF_SEL_FACES_ONLY=False): + ''' + Converts a uv mapped mesh into a 2D Mesh from UV coords. + returns a triple - + (mesh2d, face_list, col_list) + "mesh" is the new mesh and... + "face_list" is the faces that were used to make the mesh, + "material_list" is a list of materials used by each face + These are in alligned with the meshes faces, so you can easerly copy data between them + + ''' + render_me= Blender.Mesh.New() + render_me.verts.extend( [Vector(0,0,0),] ) # 0 vert uv bugm dummy vert + face_list= [] + material_list= [] + for me in me_s: + me_materials= me.materials + if PREF_SEL_FACES_ONLY: + me_faces= [f for f in me.faces if f.sel] + else: + me_faces= me.faces + + face_list.extend(me_faces) + + # Dittro + if me_materials: + material_list.extend([me_materials[f.mat] for f in me_faces]) + else: + material_list.extend([None]*len(me_faces)) + + # Now add the verts + render_me.verts.extend( [ Vector(uv.x, uv.y, 0) for f in face_list for uv in f.uv ] ) + + # Now add the faces + tmp_faces= [] + vert_offset= 1 + for f in face_list: + tmp_faces.append( [ii+vert_offset for ii in xrange(len(f))] ) + vert_offset+= len(f) + + render_me.faces.extend(tmp_faces) + render_me.faceUV=1 + return render_me, face_list, material_list + + +def uvmesh_apply_normals(render_me, face_list): + '''Worldspace normals to vertex colors''' + for i, f in enumerate(render_me.faces): + face_orig= face_list[i] + f_col= f.col + for j, v in enumerate(face_orig): + c= f_col[j] + nx, ny, nz= v.no + c.r= int((nx+1)*128)-1 + c.g= int((ny+1)*128)-1 + c.b= int((nz+1)*128)-1 + +def uvmesh_apply_image(render_me, face_list): + '''Copy the image and uvs from the original faces''' + for i, f in enumerate(render_me.faces): + f.uv= face_list[i].uv + f.image= face_list[i].image + + +def uvmesh_apply_vcol(render_me, face_list): + '''Copy the vertex colors from the original faces''' + for i, f in enumerate(render_me.faces): + face_orig= face_list[i] + f_col= f.col + for j, c_orig in enumerate(face_orig.col): + c= f_col[j] + c.r= c_orig.r + c.g= c_orig.g + c.b= c_orig.b + +def uvmesh_apply_matcol(render_me, material_list): + '''Get the vertex colors from the original materials''' + for i, f in enumerate(render_me.faces): + mat_orig= material_list[i] + f_col= f.col + if mat_orig: + for c in f_col: + c.r= int(mat_orig.R*255) + c.g= int(mat_orig.G*255) + c.b= int(mat_orig.B*255) + else: + for c in f_col: + c.r= 255 + c.g= 255 + c.b= 255 + +def uvmesh_apply_col(render_me, color): + '''Get the vertex colors from the original materials''' + r,g,b= color + for i, f in enumerate(render_me.faces): + f_col= f.col + for c in f_col: + c.r= r + c.g= g + c.b= b + + +def vcol2image(me_s,\ + PREF_IMAGE_PATH,\ + PREF_IMAGE_SIZE,\ + PREF_IMAGE_BLEED,\ + PREF_IMAGE_SMOOTH,\ + PREF_IMAGE_WIRE,\ + PREF_IMAGE_WIRE_INVERT,\ + PREF_IMAGE_WIRE_UNDERLAY,\ + PREF_USE_IMAGE,\ + PREF_USE_VCOL,\ + PREF_USE_MATCOL,\ + PREF_USE_NORMAL,\ + PREF_USE_TEXTURE,\ + PREF_SEL_FACES_ONLY): + + + def rnd_mat(): + render_mat= Blender.Material.New() + mode= render_mat.mode + + # Dont use lights ever + mode |= Blender.Material.Modes.SHADELESS + + if PREF_IMAGE_WIRE: + # Set the wire color + if PREF_IMAGE_WIRE_INVERT: + render_mat.rgbCol= (1,1,1) + else: + render_mat.rgbCol= (0,0,0) + + mode |= Blender.Material.Modes.WIRE + if PREF_USE_VCOL or PREF_USE_MATCOL or PREF_USE_NORMAL: # both vcol and material color use vertex cols to avoid the 16 max limit in materials + mode |= Blender.Material.Modes.VCOL_PAINT + if PREF_USE_IMAGE: + mode |= Blender.Material.Modes.TEXFACE + + # Copy back the mode + render_mat.mode |= mode + return render_mat + + + render_me, face_list, material_list= mesh2uv(me_s, PREF_SEL_FACES_ONLY) + + # Normals exclude all others + if PREF_USE_NORMAL: + uvmesh_apply_normals(render_me, face_list) + else: + if PREF_USE_IMAGE: + uvmesh_apply_image(render_me, face_list) + uvmesh_apply_vcol(render_me, face_list) + + elif PREF_USE_VCOL: + uvmesh_apply_vcol(render_me, face_list) + + elif PREF_USE_MATCOL: + uvmesh_apply_matcol(render_me, material_list) + + elif PREF_USE_TEXTURE: + # if we have more then 16 materials across all the mesh objects were stuffed :/ + # get unique materials + tex_unique_materials= dict([(mat.name, mat) for mat in material_list]).values()[:16] # just incase we have more then 16 + tex_me= Blender.Mesh.New() + + # Backup the original shadless setting + tex_unique_materials_shadeless= [ mat.mode & Blender.Material.Modes.SHADELESS for mat in tex_unique_materials ] + + # Turn shadeless on + for mat in tex_unique_materials: + mat.mode |= Blender.Material.Modes.SHADELESS + + # Assign materials + render_me.materials= tex_unique_materials + + + + tex_material_indicies= dict([(mat.name, i) for i, mat in enumerate(tex_unique_materials)]) + + tex_me.verts.extend([Vector(0,0,0),]) # dummy + tex_me.verts.extend( [ Vector(v.co) for f in face_list for v in f ] ) + + # Now add the faces + tmp_faces= [] + vert_offset= 1 + for f in face_list: + tmp_faces.append( [ii+vert_offset for ii in xrange(len(f))] ) + vert_offset+= len(f) + + tex_me.faces.extend(tmp_faces) + + # Now we have the faces, put materials and normal, uvs into the mesh + if len(tex_me.faces) != len(face_list): + # Should never happen + raise "Error face length mismatch" + + # Copy data to the mesh that could be used as texture coords + for i, tex_face in enumerate(tex_me.faces): + orig_face= face_list[i] + + # Set the material index + try: + render_face.mat= tex_material_indicies[ material_list[i].name ] + except: + # more then 16 materials + pass + + + # set the uvs on the texmesh mesh + tex_face.uv= orig_face.uv + + orig_face_v= orig_face.v + # Set the normals + for j, v in enumerate(tex_face): + v.no= orig_face_v[j].no + + # Set the texmesh + render_me.texMesh= tex_me + # END TEXMESH + + + # Handel adding objects + render_ob= Blender.Object.New('Mesh') + render_ob.link(render_me) + + if not PREF_USE_TEXTURE: # textures use the original materials + render_me.materials= [rnd_mat()] + + + obs= [render_ob] + + + if PREF_IMAGE_WIRE_UNDERLAY: + # Make another mesh with the material colors + render_me_under, face_list, material_list= mesh2uv(me_s, PREF_SEL_FACES_ONLY) + + uvmesh_apply_matcol(render_me_under, material_list) + + # Handel adding objects + render_ob= Blender.Object.New('Mesh') + render_ob.link(render_me_under) + render_ob.LocZ= -0.01 + + # Add material and disable wire + mat= rnd_mat() + mat.rgbCol= 1,1,1 + mat.alpha= 0.5 + mat.mode &= ~Blender.Material.Modes.WIRE + mat.mode |= Blender.Material.Modes.VCOL_PAINT + + render_me_under.materials= [mat] + + obs.append(render_ob) + + elif PREF_IMAGE_BLEED and not PREF_IMAGE_WIRE: + # EVIL BLEEDING CODE!! - Just do copys of the mesh and place behind. Crufty but better then many other methods I have seen. - Cam + BLEED_PIXEL= 1.0/PREF_IMAGE_SIZE + z_offset= 0.0 + for i in xrange(PREF_IMAGE_BLEED): + for diag1, diag2 in ((-1,-1),(-1,1),(1,-1),(1,1), (1,0), (0,1), (-1,0), (0, -1)): # This line extends the object in 8 different directions, top avoid bleeding. + + render_ob= Blender.Object.New('Mesh') + render_ob.link(render_me) + + render_ob.LocX= (i+1)*diag1*BLEED_PIXEL + render_ob.LocY= (i+1)*diag2*BLEED_PIXEL + render_ob.LocZ= -z_offset + + obs.append(render_ob) + z_offset += 0.01 + + + + image= imageFromObjectsOrtho(obs, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PREF_IMAGE_SIZE, PREF_IMAGE_SMOOTH) + + # Clear from memory as best as we can + render_me.verts= None + + if PREF_IMAGE_WIRE_UNDERLAY: + render_me_under.verts= None + + if PREF_USE_TEXTURE: + tex_me.verts= None + # Restire Shadeless setting + for i, mat in enumerate(tex_unique_materials): + # we know there all on so turn it off of its not set + if not tex_unique_materials_shadeless[i]: + mat.mode &= ~Blender.Material.Modes.SHADELESS + + return image diff --git a/release/scripts/bpymodules/BPySys.py b/release/scripts/bpymodules/BPySys.py new file mode 100644 index 00000000000..594264fad84 --- /dev/null +++ b/release/scripts/bpymodules/BPySys.py @@ -0,0 +1,14 @@ + +## This was used to make V, but faster not to do all that +##valid = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_' +##v = range(255) +##for c in valid: v.remove(ord(c)) +v = [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,46,47,58,59,60,61,62,63,64,91,92,93,94,96,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] +invalid = ''.join([chr(i) for i in v]) +## del v, c, i, valid +del v, i + +def cleanName(name): + for ch in invalid: name = name.replace(ch, '_') + return name + diff --git a/release/scripts/bpymodules/BPyWindow.py b/release/scripts/bpymodules/BPyWindow.py new file mode 100644 index 00000000000..f48f5dfc0ad --- /dev/null +++ b/release/scripts/bpymodules/BPyWindow.py @@ -0,0 +1,206 @@ +import Blender +from Blender import Mathutils, Window, Scene, Draw, Mesh +from Blender.Mathutils import CrossVecs, Matrix, Vector, Intersect + +# DESCRIPTION: +# screen_x, screen_y the origin point of the pick ray +# it is either the mouse location +# localMatrix is used if you want to have the returned values in an objects localspace. +# this is usefull when dealing with an objects data such as verts. +# or if useMid is true, the midpoint of the current 3dview +# returns +# Origin - the origin point of the pick ray +# Direction - the direction vector of the pick ray +# in global coordinates +epsilon = 1e-3 # just a small value to account for floating point errors + +def mouseViewRay(screen_x, screen_y, localMatrix=None, useMid = False): + + # Constant function variables + p = mouseViewRay.p + d = mouseViewRay.d + + for win3d in Window.GetScreenInfo(Window.Types.VIEW3D): # we search all 3dwins for the one containing the point (screen_x, screen_y) (could be the mousecoords for example) + win_min_x, win_min_y, win_max_x, win_max_y = win3d['vertices'] + # calculate a few geometric extents for this window + + win_mid_x = (win_max_x + win_min_x + 1.0) * 0.5 + win_mid_y = (win_max_y + win_min_y + 1.0) * 0.5 + win_size_x = (win_max_x - win_min_x + 1.0) * 0.5 + win_size_y = (win_max_y - win_min_y + 1.0) * 0.5 + + #useMid is for projecting the coordinates when we subdivide the screen into bins + if useMid: # == True + screen_x = win_mid_x + screen_y = win_mid_y + + # if the given screencoords (screen_x, screen_y) are within the 3dwin we fount the right one... + if (win_max_x > screen_x > win_min_x) and ( win_max_y > screen_y > win_min_y): + # first we handle all pending events for this window (otherwise the matrices might come out wrong) + Window.QHandle(win3d['id']) + + # now we get a few matrices for our window... + # sorry - i cannot explain here what they all do + # - if you're not familiar with all those matrices take a look at an introduction to OpenGL... + pm = Window.GetPerspMatrix() # the prespective matrix + pmi = Matrix(pm); pmi.invert() # the inverted perspective matrix + + if (1.0 - epsilon < pmi[3][3] < 1.0 + epsilon): + # pmi[3][3] is 1.0 if the 3dwin is in ortho-projection mode (toggled with numpad 5) + hms = mouseViewRay.hms + ortho_d = mouseViewRay.ortho_d + + # ortho mode: is a bit strange - actually there's no definite location of the camera ... + # but the camera could be displaced anywhere along the viewing direction. + + ortho_d.x, ortho_d.y, ortho_d.z = Window.GetViewVector() + ortho_d.w = 0 + + # all rays are parallel in ortho mode - so the direction vector is simply the viewing direction + #hms.x, hms.y, hms.z, hms.w = (screen_x-win_mid_x) /win_size_x, (screen_y-win_mid_y) / win_size_y, 0.0, 1.0 + hms[:] = (screen_x-win_mid_x) /win_size_x, (screen_y-win_mid_y) / win_size_y, 0.0, 1.0 + + # these are the homogenious screencoords of the point (screen_x, screen_y) ranging from -1 to +1 + p=(hms*pmi) + (1000*ortho_d) + p.resize3D() + d[:] = ortho_d[:3] + + + # Finally we shift the position infinitely far away in + # the viewing direction to make sure the camera if outside the scene + # (this is actually a hack because this function + # is used in sculpt_mesh to initialize backface culling...) + else: + # PERSPECTIVE MODE: here everything is well defined - all rays converge at the camera's location + vmi = Matrix(Window.GetViewMatrix()); vmi.invert() # the inverse viewing matrix + fp = mouseViewRay.fp + + dx = pm[3][3] * (((screen_x-win_min_x)/win_size_x)-1.0) - pm[3][0] + dy = pm[3][3] * (((screen_y-win_min_y)/win_size_y)-1.0) - pm[3][1] + + fp[:] = \ + pmi[0][0]*dx+pmi[1][0]*dy,\ + pmi[0][1]*dx+pmi[1][1]*dy,\ + pmi[0][2]*dx+pmi[1][2]*dy + + # fp is a global 3dpoint obtained from "unprojecting" the screenspace-point (screen_x, screen_y) + #- figuring out how to calculate this took me quite some time. + # The calculation of dxy and fp are simplified versions of my original code + #- so it's almost impossible to explain what's going on geometrically... sorry + + p[:] = vmi[3][:3] + + # the camera's location in global 3dcoords can be read directly from the inverted viewmatrix + #d.x, d.y, d.z =normalize_v3(sub_v3v3(p, fp)) + d[:] = p.x-fp.x, p.y-fp.y, p.z-fp.z + + #print 'd', d, 'p', p, 'fp', fp + + + # the direction vector is simply the difference vector from the virtual camera's position + #to the unprojected (screenspace) point fp + + # Do we want to return a direction in object's localspace? + + if localMatrix: + localInvMatrix = Matrix(localMatrix) + localInvMatrix.invert() + localInvMatrix_notrans = localInvMatrix.rotationPart() + p = p * localInvMatrix + d = d * localInvMatrix # normalize_v3 + + # remove the translation from d + d.x -= localInvMatrix[3][0] + d.y -= localInvMatrix[3][1] + d.z -= localInvMatrix[3][2] + + + d.normalize() + ''' + # Debugging + me = Blender.Mesh.New() + me.verts.extend([p[0:3]]) + me.verts.extend([(p-d)[0:3]]) + me.edges.extend([0,1]) + ob = Blender.Scene.GetCurrent().objects.new(me) + ''' + return True, p, d # Origin, Direction + + # Mouse is not in any view, return None. + return False, None, None + +# Constant function variables +mouseViewRay.d = Vector(0,0,0) # Perspective, 3d +mouseViewRay.p = Vector(0,0,0) +mouseViewRay.fp = Vector(0,0,0) + +mouseViewRay.hms = Vector(0,0,0,0) # ortho only 4d +mouseViewRay.ortho_d = Vector(0,0,0,0) # ortho only 4d + + +LMB= Window.MButs['L'] +def mouseup(): + # Loop until click + mouse_buttons = Window.GetMouseButtons() + while not mouse_buttons & LMB: + Blender.sys.sleep(10) + mouse_buttons = Window.GetMouseButtons() + while mouse_buttons & LMB: + Blender.sys.sleep(10) + mouse_buttons = Window.GetMouseButtons() + + +if __name__=='__main__': + mouseup() + x,y= Window.GetMouseCoords() + isect, point, dir= mouseViewRay(x,y) + if isect: + scn= Blender.Scene.GetCurrent() + me = Blender.Mesh.New() + ob= Blender.Object.New('Mesh') + ob.link(me) + scn.link(ob) + ob.sel= 1 + me.verts.extend([point, dir]) + me.verts[0].sel= 1 + + print isect, point, dir + + + +def spaceRect(): + ''' + Returns the space rect + xmin,ymin,width,height + ''' + + __UI_RECT__ = Blender.BGL.Buffer(Blender.BGL.GL_FLOAT, 4) + Blender.BGL.glGetFloatv(Blender.BGL.GL_SCISSOR_BOX, __UI_RECT__) + __UI_RECT__ = __UI_RECT__.list + __UI_RECT__ = int(__UI_RECT__[0]), int(__UI_RECT__[1]), int(__UI_RECT__[2])-1, int(__UI_RECT__[3]) + + return __UI_RECT__ + +def mouseRelativeLoc2d(__UI_RECT__= None): + if not __UI_RECT__: + __UI_RECT__ = spaceRect() + + mco = Window.GetMouseCoords() + if mco[0] > __UI_RECT__[0] and\ + mco[1] > __UI_RECT__[1] and\ + mco[0] < __UI_RECT__[0] + __UI_RECT__[2] and\ + mco[1] < __UI_RECT__[1] + __UI_RECT__[3]: + + return (mco[0] - __UI_RECT__[0], mco[1] - __UI_RECT__[1]) + + else: + return None + + + + + + + + + \ No newline at end of file diff --git a/release/scripts/bpymodules/defaultdoodads.py b/release/scripts/bpymodules/defaultdoodads.py new file mode 100644 index 00000000000..987b8b8ae71 --- /dev/null +++ b/release/scripts/bpymodules/defaultdoodads.py @@ -0,0 +1,941 @@ +# Default Doodad Set for Discombobulator +# by Evan J. Rosky, 2005 +# GPL- http://www.gnu.org/copyleft/gpl.html +# +# $Id$ +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2005: Evan J. Rosky +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +#Run discombobulator.py, not this. + +import Blender +from Blender import NMesh,Object,Material +from Blender.NMesh import Vert,Face +from Blender.Mathutils import * + +import BPyMathutils +from BPyMathutils import genrand +a = BPyMathutils.sgenrand(4859) + +#Create random numbers +def randnum(low,high): + num = genrand() + num = num*(high-low) + num = num+low + return num + +face = Face() +xmin = Vector([0,0,0]) +xmax = Vector([0,0,0]) +ymin = Vector([0,0,0]) +ymax = Vector([0,0,0]) +mxmin = Vector([0,0,0]) +mxmax = Vector([0,0,0]) +mymin = Vector([0,0,0]) +mymax = Vector([0,0,0]) +doodadCenter = Vector([0,0,0]) +orientation = 0 +center = Vector([0,0,0]) +tosel = 0 +seltopsonly = 0 +tempx = [] +doodadMesh = NMesh.GetRaw() + +global materialArray +global reassignMats +global thereAreMats +global currmat +global doodSideMat +global doodTopMat + +#face is the face to add the doodad to. +#sizeX and sizeY are values from 0.0 to 1.0 that represents a percentage the face that is covered by the doodad. +#height is how tall the doodad is. + +def settings(seltops,matArr,reasMats,therMats,sidemat,topmat): + global seltopsonly + global materialArray + global reassignMats + global thereAreMats + global currmat + global doodSideMat + global doodTopMat + materialArray = matArr + reassignMats = reasMats + thereAreMats = therMats + seltopsonly = seltops + doodSideMat = sidemat + doodTopMat = topmat + +def setCurrMat(curma): + global currmat + currmat = curma + +#Find center and orientation of doodad +def findDoodadCenter(sizeX, sizeY): + #globalizing junk + global face + global xmin + global xmax + global ymin + global ymax + global orientation + global doodadCenter + global center + global tosel + global mxmin + global mxmax + global mymin + global mymax + global tempx + global seltopsonly + + #Find the center of the face + center = Vector([0,0,0]) + for pt in face.v: + center = center + pt.co + center = divideVectorByInt(center,len(face.v)) + + #Find Temp Location Range by looking at the sizes + txmin = ((divideVectorByInt((face.v[0].co + face.v[3].co),2)) - center)*(1-sizeX) + center + txmax = ((divideVectorByInt((face.v[1].co + face.v[2].co),2)) - center)*(1-sizeX) + center + tymin = ((divideVectorByInt((face.v[0].co + face.v[1].co),2)) - center)*(1-sizeY) + center + tymax = ((divideVectorByInt((face.v[2].co + face.v[3].co),2)) - center)*(1-sizeY) + center + + #Find Center of doodad + amtx = randnum(0.0,1.0) + amty = randnum(0.0,1.0) + thepoint = (((((txmin - txmax)*amtx + txmax) - ((tymin - tymax)*amty + tymax))*.5 + ((tymin - tymax)*amty + tymax)) - center)*2 + center + doodadCenter = Vector([thepoint[0],thepoint[1],thepoint[2]]) + + #Find Main Range by looking at the sizes + mxmin = divideVectorByInt((face.v[0].co + face.v[3].co),2) + mxmax = divideVectorByInt((face.v[1].co + face.v[2].co),2) + mymin = divideVectorByInt((face.v[0].co + face.v[1].co),2) + mymax = divideVectorByInt((face.v[2].co + face.v[3].co),2) + + #Find x/y equivs for whole face + ve1 = (txmin - txmax)*amtx + txmax + ve1 = ve1 - mxmax + nax = ve1.length + ve1 = (mxmin - mxmax) + nax = nax/ve1.length + + ve1 = (tymin - tymax)*amty + tymax + ve1 = ve1 - mymax + nay = ve1.length + ve1 = (mymin - mymax) + nay = nay/ve1.length + + #Find new box thing + tempx = [] + amtx = nax-sizeX/2 + amty = nay-sizeY/2 + tempx.append((((((mxmin - mxmax)*amtx + mxmax) - ((mymin - mymax)*amty + mymax))*.5 + ((mymin - mymax)*amty + mymax)) - center)*2 + center) + + amtx = nax-sizeX/2 + amty = nay+sizeY/2 + tempx.append((((((mxmin - mxmax)*amtx + mxmax) - ((mymin - mymax)*amty + mymax))*.5 + ((mymin - mymax)*amty + mymax)) - center)*2 + center) + + amtx = nax+sizeX/2 + amty = nay+sizeY/2 + tempx.append((((((mxmin - mxmax)*amtx + mxmax) - ((mymin - mymax)*amty + mymax))*.5 + ((mymin - mymax)*amty + mymax)) - center)*2 + center) + + amtx = nax+sizeX/2 + amty = nay-sizeY/2 + tempx.append((((((mxmin - mxmax)*amtx + mxmax) - ((mymin - mymax)*amty + mymax))*.5 + ((mymin - mymax)*amty + mymax)) - center)*2 + center) + + #Find New Location Range by looking at the sizes + xmin = divideVectorByInt((tempx[0] + tempx[3]),2) + xmax = divideVectorByInt((tempx[1] + tempx[2]),2) + ymin = divideVectorByInt((tempx[0] + tempx[1]),2) + ymax = divideVectorByInt((tempx[2] + tempx[3]),2) + +#Make a point +def makePoint(x,y,z=0): + global xmin + global xmax + global ymin + global ymax + global doodadCenter + global tosel + global seltopsonly + global face + + amtx = x + amty = y + thepoint = (((((xmin - xmax)*amtx + xmax) - ((ymin - ymax)*amty + ymax))*.5 + ((ymin - ymax)*amty + ymax)) - doodadCenter)*2 + doodadCenter + thepoint = thepoint + z*Vector(face.no) + tver = Vert(thepoint[0],thepoint[1],thepoint[2]) + if tosel == 1 and seltopsonly == 0 and z == 0: + tver.sel = 1 + return tver + +#extrude ground-plane(s) +def extrudedoodad(vArray,heig): + global face + global doodadMesh + global tosel + + topVArray = [] + + doodadMesh.verts.extend(vArray) + + #Create array for extruded verts + for ind in range(0,(len(vArray))): + point = vArray[ind].co + heig*Vector(face.no) + ver = Vert(point[0],point[1],point[2]) + if tosel == 1: + ver.sel = 1 + topVArray.append(ver) + doodadMesh.verts.append(topVArray[ind]) + + #make faces around sides + for ind in range(0,(len(vArray) - 1)): + face = Face() + face.v.extend([vArray[ind],vArray[ind+1],topVArray[ind+1],topVArray[ind]]) + if tosel == 1 and seltopsonly == 0: face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodSideMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vArray[len(vArray) - 1],vArray[0],topVArray[0],topVArray[len(topVArray) - 1]]) + if tosel == 1 and seltopsonly == 0: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodSideMat-1 + doodadMesh.faces.append(face) + + return topVArray + +#For switching face vertices +def fixvertindex(ind): + if ind > 3: + indx = ind - 4 + else: + indx = ind + return indx + +#runs doodads +def createDoodad(indexArray,facec,minsi,maxsi,minhei,maxhei,selec,amtmin,amtmax,facpercent): + global doodadMesh + global seltopsonly + global tosel + + doodadMesh = NMesh.GetRaw() + + theamt = round(randnum(amtmin,amtmax),0) + theamt = int(theamt) + tosel = selec + + for i in range(0,(theamt)): + if randnum(0,1) <= facpercent: + index = round(randnum(1,len(indexArray)),0) + index = indexArray[(int(index) - 1)] + + Xsi = randnum(minsi,maxsi) + Ysi = randnum(minsi,maxsi) + hei = randnum(minhei,maxhei) + + #Determine orientation + orient = int(round(randnum(0.0,3.0))) + + #face to use as range + facer = Face() + facer.v.extend([facec.v[orient],facec.v[fixvertindex(1+orient)],facec.v[fixvertindex(2+orient)],facec.v[fixvertindex(3+orient)]]) + + if index == 1: + singleBox(facer,Xsi,Ysi,hei) + if index == 2: + doubleBox(facer,Xsi,Ysi,hei) + if index == 3: + tripleBox(facer,Xsi,Ysi,hei) + if index == 4: + LShape(facer,Xsi,Ysi,hei) + if index == 5: + TShape(facer,Xsi,Ysi,hei) + if index == 6: + if randnum(0.0,1.0) > .5: + SShape(facer,Xsi,Ysi,hei) + else: + ZShape(facer,Xsi,Ysi,hei) + + return doodadMesh + +def divideVectorByInt(thevect,theint): + thevect.x = thevect.x/theint + thevect.y = thevect.y/theint + thevect.z = thevect.z/theint + return thevect + +#Single Box Doodad +def singleBox(facel, Xsize, Ysize, height): + #globaling junk + global face + global tosel + global doodadMesh + + face = Face() + face = facel + + findDoodadCenter(Xsize, Ysize) + + vertArray = [] + + #place four points + vertArray.append(makePoint(0,0)) + vertArray.append(makePoint(0,1)) + vertArray.append(makePoint(1,1)) + vertArray.append(makePoint(1,0)) + topVertArray = extrudedoodad(vertArray,height) + + face = Face() + face.v.extend(vertArray) + face.v.reverse() + doodadMesh.faces.append(face) + face = Face() + face.v.extend(topVertArray) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + +#Double Box Doodad +def doubleBox(facel, Xsize, Ysize, height): + #globaling junk + global face + global tosel + global doodadMesh + + face = Face() + face = facel + + findDoodadCenter(Xsize, Ysize) + + vertArray = [] + + #place first box + vertArray.append(makePoint(0,0)) + vertArray.append(makePoint(0,1)) + vertArray.append(makePoint(0.45,1)) + vertArray.append(makePoint(0.45,0)) + topVertArray = extrudedoodad(vertArray,height) + + face = Face() + face.v.extend(vertArray) + face.v.reverse() + doodadMesh.faces.append(face) + face = Face() + face.v.extend(topVertArray) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + + vertArray = [] + + #place second box + vertArray.append(makePoint(0.55,0)) + vertArray.append(makePoint(0.55,1)) + vertArray.append(makePoint(1,1)) + vertArray.append(makePoint(1,0)) + topVertArray = extrudedoodad(vertArray,height) + + face = Face() + face.v.extend(vertArray) + face.v.reverse() + doodadMesh.faces.append(face) + face = Face() + face.v.extend(topVertArray) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + +#Triple Box Doodad +def tripleBox(facel, Xsize, Ysize, height): + #globaling junk + global face + global tosel + global doodadMesh + + face = Face() + face = facel + + findDoodadCenter(Xsize, Ysize) + + vertArray = [] + + #place first box + vertArray.append(makePoint(0,0)) + vertArray.append(makePoint(0,1)) + vertArray.append(makePoint(0.3,1)) + vertArray.append(makePoint(0.3,0)) + topVertArray = extrudedoodad(vertArray,height) + + face = Face() + face.v.extend(vertArray) + face.v.reverse() + doodadMesh.faces.append(face) + face = Face() + face.v.extend(topVertArray) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + + vertArray = [] + + #place second box + vertArray.append(makePoint(0.35,0)) + vertArray.append(makePoint(0.35,1)) + vertArray.append(makePoint(0.65,1)) + vertArray.append(makePoint(0.65,0)) + topVertArray = extrudedoodad(vertArray,height) + + face = Face() + face.v.extend(vertArray) + face.v.reverse() + doodadMesh.faces.append(face) + face = Face() + face.v.extend(topVertArray) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + + vertArray = [] + + #place third box + vertArray.append(makePoint(0.7,0)) + vertArray.append(makePoint(0.7,1)) + vertArray.append(makePoint(1,1)) + vertArray.append(makePoint(1,0)) + topVertArray = extrudedoodad(vertArray,height) + + face = Face() + face.v.extend(vertArray) + face.v.reverse() + doodadMesh.faces.append(face) + face = Face() + face.v.extend(topVertArray) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + +#The "L" Shape +def LShape(facel, Xsize, Ysize, height): + #globaling junk + global face + global tosel + global doodadMesh + + face = Face() + face = facel + + findDoodadCenter(Xsize, Ysize) + + rcon1 = randnum(0.2,0.8) + rcon2 = randnum(0.2,0.8) + + vertArray = [] + + #place L shape + vertArray.append(makePoint(0,0)) + vertArray.append(makePoint(0,rcon1)) + vertArray.append(makePoint(0,1)) + vertArray.append(makePoint(rcon2,1)) + vertArray.append(makePoint(rcon2,rcon1)) + vertArray.append(makePoint(1,rcon1)) + vertArray.append(makePoint(1,0)) + vertArray.append(makePoint(rcon2,0)) + topVertArray = extrudedoodad(vertArray,height) + + #This fills in the bottom of doodad with faceness + face = Face() + face.v.extend([vertArray[0],vertArray[1],vertArray[4],vertArray[7]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[1],vertArray[2],vertArray[3],vertArray[4]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[4],vertArray[5],vertArray[6],vertArray[7]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + + #This fills in the top with faceness + face = Face() + face.v.extend([topVertArray[0],topVertArray[1],topVertArray[4],topVertArray[7]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[1],topVertArray[2],topVertArray[3],topVertArray[4]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[4],topVertArray[5],topVertArray[6],topVertArray[7]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + +#The "T" Shape +def TShape(facel, Xsize, Ysize, height): + #globaling junk + global face + global tosel + global doodadMesh + + face = Face() + face = facel + + findDoodadCenter(Xsize, Ysize) + + rcony = randnum(0.25,0.75) + rconx1 = randnum(0.1,0.49) + rconx2 = randnum(0.51,0.9) + + vertArray = [] + + #place T shape + vertArray.append(makePoint(0,0)) + vertArray.append(makePoint(0,rcony)) + vertArray.append(makePoint(rconx1,rcony)) + vertArray.append(makePoint(rconx1,1)) + vertArray.append(makePoint(rconx2,1)) + vertArray.append(makePoint(rconx2,rcony)) + vertArray.append(makePoint(1,rcony)) + vertArray.append(makePoint(1,0)) + vertArray.append(makePoint(rconx2,0)) + vertArray.append(makePoint(rconx1,0)) + topVertArray = extrudedoodad(vertArray,height) + + #fills bottom with faceness + face = Face() + face.v.extend([vertArray[0],vertArray[1],vertArray[2],vertArray[9]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[2],vertArray[3],vertArray[4],vertArray[5]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[5],vertArray[6],vertArray[7],vertArray[8]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[8],vertArray[9],vertArray[2],vertArray[5]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + + #fills top with faceness + face = Face() + face.v.extend([topVertArray[0],topVertArray[1],topVertArray[2],topVertArray[9]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[2],topVertArray[3],topVertArray[4],topVertArray[5]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[5],topVertArray[6],topVertArray[7],topVertArray[8]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[8],topVertArray[9],topVertArray[2],topVertArray[5]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + +#The "S" or "Z" Shapes +def SShape(facel, Xsize, Ysize, height): + #globaling junk + global face + global tosel + global doodadMesh + + face = Face() + face = facel + + findDoodadCenter(Xsize, Ysize) + + rcony1 = randnum(0.1,0.49) + rcony2 = randnum(0.51,0.9) + rconx1 = randnum(0.1,0.49) + rconx2 = randnum(0.51,0.9) + + vertArray = [] + + #place S shape + vertArray.append(makePoint(0,0)) + vertArray.append(makePoint(0,rcony1)) + vertArray.append(makePoint(rconx1,rcony1)) + vertArray.append(makePoint(rconx1,rcony2)) + vertArray.append(makePoint(rconx1,1)) + vertArray.append(makePoint(rconx2,1)) + vertArray.append(makePoint(1,1)) + vertArray.append(makePoint(1,rcony2)) + vertArray.append(makePoint(rconx2,rcony2)) + vertArray.append(makePoint(rconx2,rcony1)) + vertArray.append(makePoint(rconx2,0)) + vertArray.append(makePoint(rconx1,0)) + topVertArray = extrudedoodad(vertArray,height) + + #fills bottom with faceness + face = Face() + face.v.extend([vertArray[0],vertArray[1],vertArray[2],vertArray[11]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[2],vertArray[9],vertArray[10],vertArray[11]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[2],vertArray[3],vertArray[8],vertArray[9]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[3],vertArray[4],vertArray[5],vertArray[8]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[5],vertArray[6],vertArray[7],vertArray[8]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + + #fills top with faceness + face = Face() + face.v.extend([topVertArray[0],topVertArray[1],topVertArray[2],topVertArray[11]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[2],topVertArray[9],topVertArray[10],topVertArray[11]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[2],topVertArray[3],topVertArray[8],topVertArray[9]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[3],topVertArray[4],topVertArray[5],topVertArray[8]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[5],topVertArray[6],topVertArray[7],topVertArray[8]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + +def ZShape(facel, Xsize, Ysize, height): + #globaling junk + global face + global tosel + global doodadMesh + + face = Face() + face = facel + + findDoodadCenter(Xsize, Ysize) + + rcony1 = randnum(0.1,0.49) + rcony2 = randnum(0.51,0.9) + rconx1 = randnum(0.1,0.49) + rconx2 = randnum(0.51,0.9) + + vertArray = [] + + #place Z shape + vertArray.append(makePoint(0,0)) + vertArray.append(makePoint(0,rcony1)) + vertArray.append(makePoint(0,rcony2)) + vertArray.append(makePoint(rconx1,rcony2)) + vertArray.append(makePoint(rconx2,rcony2)) + vertArray.append(makePoint(rconx2,1)) + vertArray.append(makePoint(1,1)) + vertArray.append(makePoint(1,rcony2)) + vertArray.append(makePoint(1,rcony1)) + vertArray.append(makePoint(rconx2,rcony1)) + vertArray.append(makePoint(rconx1,rcony1)) + vertArray.append(makePoint(rconx1,0)) + topVertArray = extrudedoodad(vertArray,height) + + #fills bottom with faceness + face = Face() + face.v.extend([vertArray[0],vertArray[1],vertArray[10],vertArray[11]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[1],vertArray[2],vertArray[3],vertArray[10]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[3],vertArray[4],vertArray[9],vertArray[10]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[4],vertArray[7],vertArray[8],vertArray[9]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[4],vertArray[5],vertArray[6],vertArray[7]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + + #fills top with faceness + face = Face() + face.v.extend([topVertArray[0],topVertArray[1],topVertArray[10],topVertArray[11]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[1],topVertArray[2],topVertArray[3],topVertArray[10]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[3],topVertArray[4],topVertArray[9],topVertArray[10]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[4],topVertArray[7],topVertArray[8],topVertArray[9]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[4],topVertArray[5],topVertArray[6],topVertArray[7]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + diff --git a/release/scripts/bpymodules/dxfColorMap.py b/release/scripts/bpymodules/dxfColorMap.py new file mode 100644 index 00000000000..66c0bd4e9a2 --- /dev/null +++ b/release/scripts/bpymodules/dxfColorMap.py @@ -0,0 +1,282 @@ +# dictionary mapping AutoCAD color indexes with Blender colors + +# -------------------------------------------------------------------------- +# color_map.py Final by Ed Blake (AKA Kitsu) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +color_map = { + 0:[0.0, 0.0, 0.0], + 1:[0.99609375, 0.0, 0.0], + 2:[0.99609375, 0.99609375, 0.0], + 3:[0.0, 0.99609375, 0.0], + 4:[0.0, 0.99609375, 0.99609375], + 5:[0.0, 0.0, 0.99609375], + 6:[0.99609375, 0.0, 0.99609375], + 7:[0.99609375, 0.99609375, 0.99609375], + 8:[0.25390625, 0.25390625, 0.25390625], + 9:[0.5, 0.5, 0.5], + 10:[0.99609375, 0.0, 0.0], + 11:[0.99609375, 0.6640625, 0.6640625], + 12:[0.73828125, 0.0, 0.0], + 13:[0.73828125, 0.4921875, 0.4921875], + 14:[0.50390625, 0.0, 0.0], + 15:[0.50390625, 0.3359375, 0.3359375], + 16:[0.40625, 0.0, 0.0], + 17:[0.40625, 0.26953125, 0.26953125], + 18:[0.30859375, 0.0, 0.0], + 19:[0.30859375, 0.20703125, 0.20703125], + 20:[0.99609375, 0.24609375, 0.0], + 21:[0.99609375, 0.74609375, 0.6640625], + 22:[0.73828125, 0.1796875, 0.0], + 23:[0.73828125, 0.55078125, 0.4921875], + 24:[0.50390625, 0.12109375, 0.0], + 25:[0.50390625, 0.375, 0.3359375], + 26:[0.40625, 0.09765625, 0.0], + 27:[0.40625, 0.3046875, 0.26953125], + 28:[0.30859375, 0.07421875, 0.0], + 29:[0.30859375, 0.23046875, 0.20703125], + 30:[0.99609375, 0.49609375, 0.0], + 31:[0.99609375, 0.828125, 0.6640625], + 32:[0.73828125, 0.3671875, 0.0], + 33:[0.73828125, 0.61328125, 0.4921875], + 34:[0.50390625, 0.25, 0.0], + 35:[0.50390625, 0.41796875, 0.3359375], + 36:[0.40625, 0.203125, 0.0], + 37:[0.40625, 0.3359375, 0.26953125], + 38:[0.30859375, 0.15234375, 0.0], + 39:[0.30859375, 0.2578125, 0.20703125], + 40:[0.99609375, 0.74609375, 0.0], + 41:[0.99609375, 0.9140625, 0.6640625], + 42:[0.73828125, 0.55078125, 0.0], + 43:[0.73828125, 0.67578125, 0.4921875], + 44:[0.50390625, 0.375, 0.0], + 45:[0.50390625, 0.4609375, 0.3359375], + 46:[0.40625, 0.3046875, 0.0], + 47:[0.40625, 0.37109375, 0.26953125], + 48:[0.30859375, 0.23046875, 0.0], + 49:[0.30859375, 0.28515625, 0.20703125], + 50:[0.99609375, 0.99609375, 0.0], + 51:[0.99609375, 0.99609375, 0.6640625], + 52:[0.73828125, 0.73828125, 0.0], + 53:[0.73828125, 0.73828125, 0.4921875], + 54:[0.50390625, 0.50390625, 0.0], + 55:[0.50390625, 0.50390625, 0.3359375], + 56:[0.40625, 0.40625, 0.0], + 57:[0.40625, 0.40625, 0.26953125], + 58:[0.30859375, 0.30859375, 0.0], + 59:[0.30859375, 0.30859375, 0.20703125], + 60:[0.74609375, 0.99609375, 0.0], + 61:[0.9140625, 0.99609375, 0.6640625], + 62:[0.55078125, 0.73828125, 0.0], + 63:[0.67578125, 0.73828125, 0.4921875], + 64:[0.375, 0.50390625, 0.0], + 65:[0.4609375, 0.50390625, 0.3359375], + 66:[0.3046875, 0.40625, 0.0], + 67:[0.37109375, 0.40625, 0.26953125], + 68:[0.23046875, 0.30859375, 0.0], + 69:[0.28515625, 0.30859375, 0.20703125], + 70:[0.49609375, 0.99609375, 0.0], + 71:[0.828125, 0.99609375, 0.6640625], + 72:[0.3671875, 0.73828125, 0.0], + 73:[0.61328125, 0.73828125, 0.4921875], + 74:[0.25, 0.50390625, 0.0], + 75:[0.41796875, 0.50390625, 0.3359375], + 76:[0.203125, 0.40625, 0.0], + 77:[0.3359375, 0.40625, 0.26953125], + 78:[0.15234375, 0.30859375, 0.0], + 79:[0.2578125, 0.30859375, 0.20703125], + 80:[0.24609375, 0.99609375, 0.0], + 81:[0.74609375, 0.99609375, 0.6640625], + 82:[0.1796875, 0.73828125, 0.0], + 83:[0.55078125, 0.73828125, 0.4921875], + 84:[0.12109375, 0.50390625, 0.0], + 85:[0.375, 0.50390625, 0.3359375], + 86:[0.09765625, 0.40625, 0.0], + 87:[0.3046875, 0.40625, 0.26953125], + 88:[0.07421875, 0.30859375, 0.0], + 89:[0.23046875, 0.30859375, 0.20703125], + 90:[0.0, 0.99609375, 0.0], + 91:[0.6640625, 0.99609375, 0.6640625], + 92:[0.0, 0.73828125, 0.0], + 93:[0.4921875, 0.73828125, 0.4921875], + 94:[0.0, 0.50390625, 0.0], + 95:[0.3359375, 0.50390625, 0.3359375], + 96:[0.0, 0.40625, 0.0], + 97:[0.26953125, 0.40625, 0.26953125], + 98:[0.0, 0.30859375, 0.0], + 99:[0.20703125, 0.30859375, 0.20703125], + 100:[0.0, 0.99609375, 0.24609375], + 101:[0.6640625, 0.99609375, 0.74609375], + 102:[0.0, 0.73828125, 0.1796875], + 103:[0.4921875, 0.73828125, 0.55078125], + 104:[0.0, 0.50390625, 0.12109375], + 105:[0.3359375, 0.50390625, 0.375], + 106:[0.0, 0.40625, 0.09765625], + 107:[0.26953125, 0.40625, 0.3046875], + 108:[0.0, 0.30859375, 0.07421875], + 109:[0.20703125, 0.30859375, 0.23046875], + 110:[0.0, 0.99609375, 0.49609375], + 111:[0.6640625, 0.99609375, 0.828125], + 112:[0.0, 0.73828125, 0.3671875], + 113:[0.4921875, 0.73828125, 0.61328125], + 114:[0.0, 0.50390625, 0.25], + 115:[0.3359375, 0.50390625, 0.41796875], + 116:[0.0, 0.40625, 0.203125], + 117:[0.26953125, 0.40625, 0.3359375], + 118:[0.0, 0.30859375, 0.15234375], + 119:[0.20703125, 0.30859375, 0.2578125], + 120:[0.0, 0.99609375, 0.74609375], + 121:[0.6640625, 0.99609375, 0.9140625], + 122:[0.0, 0.73828125, 0.55078125], + 123:[0.4921875, 0.73828125, 0.67578125], + 124:[0.0, 0.50390625, 0.375], + 125:[0.3359375, 0.50390625, 0.4609375], + 126:[0.0, 0.40625, 0.3046875], + 127:[0.26953125, 0.40625, 0.37109375], + 128:[0.0, 0.30859375, 0.23046875], + 129:[0.20703125, 0.30859375, 0.28515625], + 130:[0.0, 0.99609375, 0.99609375], + 131:[0.6640625, 0.99609375, 0.99609375], + 132:[0.0, 0.73828125, 0.73828125], + 133:[0.4921875, 0.73828125, 0.73828125], + 134:[0.0, 0.50390625, 0.50390625], + 135:[0.3359375, 0.50390625, 0.50390625], + 136:[0.0, 0.40625, 0.40625], + 137:[0.26953125, 0.40625, 0.40625], + 138:[0.0, 0.30859375, 0.30859375], + 139:[0.20703125, 0.30859375, 0.30859375], + 140:[0.0, 0.74609375, 0.99609375], + 141:[0.6640625, 0.9140625, 0.99609375], + 142:[0.0, 0.55078125, 0.73828125], + 143:[0.4921875, 0.67578125, 0.73828125], + 144:[0.0, 0.375, 0.50390625], + 145:[0.3359375, 0.4609375, 0.50390625], + 146:[0.0, 0.3046875, 0.40625], + 147:[0.26953125, 0.37109375, 0.40625], + 148:[0.0, 0.23046875, 0.30859375], + 149:[0.20703125, 0.28515625, 0.30859375], + 150:[0.0, 0.49609375, 0.99609375], + 151:[0.6640625, 0.828125, 0.99609375], + 152:[0.0, 0.3671875, 0.73828125], + 153:[0.4921875, 0.61328125, 0.73828125], + 154:[0.0, 0.25, 0.50390625], + 155:[0.3359375, 0.41796875, 0.50390625], + 156:[0.0, 0.203125, 0.40625], + 157:[0.26953125, 0.3359375, 0.40625], + 158:[0.0, 0.15234375, 0.30859375], + 159:[0.20703125, 0.2578125, 0.30859375], + 160:[0.0, 0.24609375, 0.99609375], + 161:[0.6640625, 0.74609375, 0.99609375], + 162:[0.0, 0.1796875, 0.73828125], + 163:[0.4921875, 0.55078125, 0.73828125], + 164:[0.0, 0.12109375, 0.50390625], + 165:[0.3359375, 0.375, 0.50390625], + 166:[0.0, 0.09765625, 0.40625], + 167:[0.26953125, 0.3046875, 0.40625], + 168:[0.0, 0.07421875, 0.30859375], + 169:[0.20703125, 0.23046875, 0.30859375], + 170:[0.0, 0.0, 0.99609375], + 171:[0.6640625, 0.6640625, 0.99609375], + 172:[0.0, 0.0, 0.73828125], + 173:[0.4921875, 0.4921875, 0.73828125], + 174:[0.0, 0.0, 0.50390625], + 175:[0.3359375, 0.3359375, 0.50390625], + 176:[0.0, 0.0, 0.40625], + 177:[0.26953125, 0.26953125, 0.40625], + 178:[0.0, 0.0, 0.30859375], + 179:[0.20703125, 0.20703125, 0.30859375], + 180:[0.24609375, 0.0, 0.99609375], + 181:[0.74609375, 0.6640625, 0.99609375], + 182:[0.1796875, 0.0, 0.73828125], + 183:[0.55078125, 0.4921875, 0.73828125], + 184:[0.12109375, 0.0, 0.50390625], + 185:[0.375, 0.3359375, 0.50390625], + 186:[0.09765625, 0.0, 0.40625], + 187:[0.3046875, 0.26953125, 0.40625], + 188:[0.07421875, 0.0, 0.30859375], + 189:[0.23046875, 0.20703125, 0.30859375], + 190:[0.49609375, 0.0, 0.99609375], + 191:[0.828125, 0.6640625, 0.99609375], + 192:[0.3671875, 0.0, 0.73828125], + 193:[0.61328125, 0.4921875, 0.73828125], + 194:[0.25, 0.0, 0.50390625], + 195:[0.41796875, 0.3359375, 0.50390625], + 196:[0.203125, 0.0, 0.40625], + 197:[0.3359375, 0.26953125, 0.40625], + 198:[0.15234375, 0.0, 0.30859375], + 199:[0.2578125, 0.20703125, 0.30859375], + 200:[0.74609375, 0.0, 0.99609375], + 201:[0.9140625, 0.6640625, 0.99609375], + 202:[0.55078125, 0.0, 0.73828125], + 203:[0.67578125, 0.4921875, 0.73828125], + 204:[0.375, 0.0, 0.50390625], + 205:[0.4609375, 0.3359375, 0.50390625], + 206:[0.3046875, 0.0, 0.40625], + 207:[0.37109375, 0.26953125, 0.40625], + 208:[0.23046875, 0.0, 0.30859375], + 209:[0.28515625, 0.20703125, 0.30859375], + 210:[0.99609375, 0.0, 0.99609375], + 211:[0.99609375, 0.6640625, 0.99609375], + 212:[0.73828125, 0.0, 0.73828125], + 213:[0.73828125, 0.4921875, 0.73828125], + 214:[0.50390625, 0.0, 0.50390625], + 215:[0.50390625, 0.3359375, 0.50390625], + 216:[0.40625, 0.0, 0.40625], + 217:[0.40625, 0.26953125, 0.40625], + 218:[0.30859375, 0.0, 0.30859375], + 219:[0.30859375, 0.20703125, 0.30859375], + 220:[0.99609375, 0.0, 0.74609375], + 221:[0.99609375, 0.6640625, 0.9140625], + 222:[0.73828125, 0.0, 0.55078125], + 223:[0.73828125, 0.4921875, 0.67578125], + 224:[0.50390625, 0.0, 0.375], + 225:[0.50390625, 0.3359375, 0.4609375], + 226:[0.40625, 0.0, 0.3046875], + 227:[0.40625, 0.26953125, 0.37109375], + 228:[0.30859375, 0.0, 0.23046875], + 229:[0.30859375, 0.20703125, 0.28515625], + 230:[0.99609375, 0.0, 0.49609375], + 231:[0.99609375, 0.6640625, 0.828125], + 232:[0.73828125, 0.0, 0.3671875], + 233:[0.73828125, 0.4921875, 0.61328125], + 234:[0.50390625, 0.0, 0.25], + 235:[0.50390625, 0.3359375, 0.41796875], + 236:[0.40625, 0.0, 0.203125], + 237:[0.40625, 0.26953125, 0.3359375], + 238:[0.30859375, 0.0, 0.15234375], + 239:[0.30859375, 0.20703125, 0.2578125], + 240:[0.99609375, 0.0, 0.24609375], + 241:[0.99609375, 0.6640625, 0.74609375], + 242:[0.73828125, 0.0, 0.1796875], + 243:[0.73828125, 0.4921875, 0.55078125], + 244:[0.50390625, 0.0, 0.12109375], + 245:[0.50390625, 0.3359375, 0.375], + 246:[0.40625, 0.0, 0.09765625], + 247:[0.40625, 0.26953125, 0.3046875], + 248:[0.30859375, 0.0, 0.07421875], + 249:[0.30859375, 0.20703125, 0.23046875], + 250:[0.19921875, 0.19921875, 0.19921875], + 251:[0.3125, 0.3125, 0.3125], + 252:[0.41015625, 0.41015625, 0.41015625], + 253:[0.5078125, 0.5078125, 0.5078125], + 254:[0.7421875, 0.7421875, 0.7421875], + 255:[0.99609375, 0.99609375, 0.99609375], +} diff --git a/release/scripts/bpymodules/dxfImportObjects.py b/release/scripts/bpymodules/dxfImportObjects.py new file mode 100644 index 00000000000..960c4c1ac15 --- /dev/null +++ b/release/scripts/bpymodules/dxfImportObjects.py @@ -0,0 +1,1326 @@ +"""This module provides wrapper objects for dxf entities. + + The wrappers expect a "dxf object" as input. The dxf object is + an object with a type and a data attribute. Type is a lowercase + string matching the 0 code of a dxf entity. Data is a list containing + dxf objects or lists of [code, data] pairs. + + This module is not general, and is only for dxf import. +""" + +# -------------------------------------------------------------------------- +# DXF Import Objects v0.8 by Ed Blake (AKA Kitsu) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- +from math import * + + +# from Stani's dxf writer v1.1 (c)www.stani.be (GPL) +#---color values +BYBLOCK=0 +BYLAYER=256 + +#---block-type flags (bit coded values, may be combined): +ANONYMOUS =1 # This is an anonymous block generated by hatching, associative dimensioning, other internal operations, or an application +NON_CONSTANT_ATTRIBUTES =2 # This block has non-constant attribute definitions (this bit is not set if the block has any attribute definitions that are constant, or has no attribute definitions at all) +XREF =4 # This block is an external reference (xref) +XREF_OVERLAY =8 # This block is an xref overlay +EXTERNAL =16 # This block is externally dependent +RESOLVED =32 # This is a resolved external reference, or dependent of an external reference (ignored on input) +REFERENCED =64 # This definition is a referenced external reference (ignored on input) + +#---mtext flags +#attachment point +TOP_LEFT = 1 +TOP_CENTER = 2 +TOP_RIGHT = 3 +MIDDLE_LEFT = 4 +MIDDLE_CENTER = 5 +MIDDLE_RIGHT = 6 +BOTTOM_LEFT = 7 +BOTTOM_CENTER = 8 +BOTTOM_RIGHT = 9 +#drawing direction +LEFT_RIGHT = 1 +TOP_BOTTOM = 3 +BY_STYLE = 5 #the flow direction is inherited from the associated text style +#line spacing style (optional): +AT_LEAST = 1 #taller characters will override +EXACT = 2 #taller characters will not override + +#---polyline flags +CLOSED =1 # This is a closed polyline (or a polygon mesh closed in the M direction) +CURVE_FIT =2 # Curve-fit vertices have been added +SPLINE_FIT =4 # Spline-fit vertices have been added +POLYLINE_3D =8 # This is a 3D polyline +POLYGON_MESH =16 # This is a 3D polygon mesh +CLOSED_N =32 # The polygon mesh is closed in the N direction +POLYFACE_MESH =64 # The polyline is a polyface mesh +CONTINOUS_LINETYPE_PATTERN =128 # The linetype pattern is generated continuously around the vertices of this polyline + +#---text flags +#horizontal +LEFT = 0 +CENTER = 1 +RIGHT = 2 +ALIGNED = 3 #if vertical alignment = 0 +MIDDLE = 4 #if vertical alignment = 0 +FIT = 5 #if vertical alignment = 0 +#vertical +BASELINE = 0 +BOTTOM = 1 +MIDDLE = 2 +TOP = 3 +class Object: + """Empty container class for dxf objects""" + + def __init__(self, _type=''): + """_type expects a string value.""" + self.type = _type + self.name = '' + self.data = [] + + def __str__(self): + if self.name: + return self.name + else: + return self.type + + def __repr__(self): + return str(self.data) + + def get_type(self, kind=''): + """Despite the name, this method actually returns all objects of type 'kind' from self.data.""" + if type: + objects = [] + for item in self.data: + if type(item) != list and item.type == kind: + # we want this type of object + objects.append(item) + elif type(item) == list and item[0] == kind: + # we want this type of data + objects.append(item[1]) + return objects + + +class Layer: + """Class for objects representing dxf layers.""" + + def __init__(self, obj): + """Expects an entity object of type line as input.""" + self.type = obj.type + self.data = obj.data[:] + + self.name = obj.get_type(2)[0] + self.color = obj.get_type(62)[0] + self.flags = obj.get_type(70)[0] + self.frozen = self.flags&1 + + + + def __repr__(self): + return "%s: name - %s, color - %s" %(self.__class__.__name__, self.name, self.color) + + + +class Line: + """Class for objects representing dxf lines.""" + + def __init__(self, obj): + """Expects an entity object of type line as input.""" + if not obj.type == 'line': + raise TypeError, "Wrong type %s for line object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + self.space = obj.get_type(67) + if self.space: + self.space = self.space[0] + else: + self.space = 0 + + self.color_index = obj.get_type(62) + if self.color_index: + self.color_index = self.color_index[0] + else: + self.color_index = BYLAYER + + discard, self.layer, discard_index = get_layer(obj.data) + del obj.data[discard_index] + + self.points = self.get_points(obj.data) + + + + + def get_points(self, data): + """Gets start and end points for a line type object. + + Lines have a fixed number of points (two) and fixed codes for each value. + """ + + # start x, y, z and end x, y, z = 0 + sx, sy, sz, ex, ey, ez = 0, 0, 0, 0, 0, 0 + for item in data: + if item[0] == 10: # 10 = x + sx = item[1] + elif item[0] == 20: # 20 = y + sy = item[1] + elif item[0] == 30: # 30 = z + sz = item[1] + elif item[0] == 11: # 11 = x + ex = item[1] + elif item[0] == 21: # 21 = y + ey = item[1] + elif item[0] == 31: # 31 = z + ez = item[1] + return [[sx, sy, sz], [ex, ey, ez]] + + + + def __repr__(self): + return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) + + + +class LWpolyline: + """Class for objects representing dxf LWpolylines.""" + + def __init__(self, obj): + """Expects an entity object of type lwpolyline as input.""" + if not obj.type == 'lwpolyline': + raise TypeError, "Wrong type %s for polyline object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.num_points = obj.get_type(90)[0] + + # optional data (with defaults) + self.space = obj.get_type(67) + if self.space: + self.space = self.space[0] + else: + self.space = 0 + + self.color_index = obj.get_type(62) + if self.color_index: + self.color_index = self.color_index[0] + else: + self.color_index = BYLAYER + + self.elevation = obj.get_type(38) + if self.elevation: + self.elevation = self.elevation[0] + else: + self.elevation = 0 + + self.flags = obj.get_type(70) + if self.flags: + self.flags = self.flags[0] + else: + self.flags = 0 + + self.closed = self.flags&1 # byte coded, 1 = closed, 128 = plinegen + discard, self.layer, discard_index = get_layer(obj.data) + del obj.data[discard_index] + self.points = self.get_points(obj.data) + self.extrusion = self.get_extrusion(obj.data) + + + + + + + def get_points(self, data): + """Gets points for a polyline type object. + + Polylines have no fixed number of verts, and + each vert can have a number of properties. + Verts should be coded as + 10:xvalue + 20:yvalue + 40:startwidth or 0 + 41:endwidth or 0 + 42:bulge or 0 + for each vert + """ + num = self.num_points + point = None + points = [] + for item in data: + if item[0] == 10: # 10 = x + if point: + points.append(point) + point = Vertex() + point.x = item[1] + elif item[0] == 20: # 20 = y + point.y = item[1] + elif item[0] == 40: # 40 = start width + point.swidth = item[1] + elif item[0] == 41: # 41 = end width + point.ewidth = item[1] + elif item[0] == 42: # 42 = bulge + point.bulge = item[1] + points.append(point) + return points + + + def get_extrusion(self, data): + """Find the axis of extrusion. + + Used to get the objects Object Coordinate System (ocs). + """ + vec = [0,0,1] + for item in data: + if item[0] == 210: # 210 = x + vec[0] = item[1] + elif item[0] == 220: # 220 = y + vec[1] = item[1] + elif item[0] == 230: # 230 = z + vec[2] = item[1] + return vec + + + def __repr__(self): + return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) + + + +class Polyline: + """Class for objects representing dxf LWpolylines.""" + + def __init__(self, obj): + """Expects an entity object of type polyline as input.""" + if not obj.type == 'polyline': + raise TypeError, "Wrong type %s for polyline object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + self.points = [] + + # optional data (with defaults) + self.space = obj.get_type(67) + if self.space: + self.space = self.space[0] + else: + self.space = 0 + + self.color_index = obj.get_type(62) + if self.color_index: + self.color_index = self.color_index[0] + else: + self.color_index = BYLAYER + + self.elevation = obj.get_type(30) + if self.elevation: + self.elevation = self.elevation[0] + else: + self.elevation = 0 + + self.flags = obj.get_type(70) + if self.flags: + self.flags = self.flags[0] + else: + self.flags = 0 + + self.closed = self.flags&1 # byte coded, 1 = closed, 128 = plinegen + + discard, self.layer, discard_index = get_layer(obj.data) + del obj.data[discard_index] + self.extrusion = self.get_extrusion(obj.data) + + + + + + def get_extrusion(self, data): + """Find the axis of extrusion. + + Used to get the objects Object Coordinate System (ocs). + """ + vec = [0,0,1] + for item in data: + if item[0] == 210: # 210 = x + vec[0] = item[1] + elif item[0] == 220: # 220 = y + vec[1] = item[1] + elif item[0] == 230: # 230 = z + vec[2] = item[1] + return vec + + + def __repr__(self): + return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) + + + +class Vertex(object): + """Generic vertex object used by polylines (and maybe others).""" + + def __init__(self, obj=None): + """Initializes vertex data. + + The optional obj arg is an entity object of type vertex. + """ + self.loc = [0,0,0] + self.bulge = 0 + self.swidth = 0 + self.ewidth = 0 + self.flags = 0 + + if obj is not None: + if not obj.type == 'vertex': + raise TypeError, "Wrong type %s for vertex object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + self.get_props(obj.data) + + + def get_props(self, data): + """Gets coords for a vertex type object. + + Each vert can have a number of properties. + Verts should be coded as + 10:xvalue + 20:yvalue + 40:startwidth or 0 + 41:endwidth or 0 + 42:bulge or 0 + """ + for item in data: + if item[0] == 10: # 10 = x + self.x = item[1] + elif item[0] == 20: # 20 = y + self.y = item[1] + elif item[0] == 30: # 30 = z + self.z = item[1] + elif item[0] == 40: # 40 = start width + self.swidth = item[1] + elif item[0] == 41: # 41 = end width + self.ewidth = item[1] + elif item[0] == 42: # 42 = bulge + self.bulge = item[1] + elif item[0] == 70: # 70 = vert flags + self.flags = item[1] + + + def __len__(self): + return 3 + + + def __getitem__(self, key): + return self.loc[key] + + + def __setitem__(self, key, value): + if key in [0,1,2]: + self.loc[key] + + + def __iter__(self): + return self.loc.__iter__() + + + def __str__(self): + return str(self.loc) + + + def __repr__(self): + return "Vertex %s, swidth=%s, ewidth=%s, bulge=%s" %(self.loc, self.swidth, self.ewidth, self.bulge) + + + def getx(self): + return self.loc[0] + + def setx(self, value): + self.loc[0] = value + + x = property(getx, setx) + + + def gety(self): + return self.loc[1] + + def sety(self, value): + self.loc[1] = value + + y = property(gety, sety) + + + def getz(self): + return self.loc[2] + + def setz(self, value): + self.loc[2] = value + + z = property(getz, setz) + + + +class Text: + """Class for objects representing dxf Text.""" + + def __init__(self, obj): + """Expects an entity object of type text as input.""" + if not obj.type == 'text': + raise TypeError, "Wrong type %s for text object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.height = obj.get_type(40)[0] + self.value = obj.get_type(1)[0] # The text string value + + # optional data (with defaults) + self.space = obj.get_type(67) + if self.space: + self.space = self.space[0] + else: + self.space = 0 + + self.color_index = obj.get_type(62) + if self.color_index: + self.color_index = self.color_index[0] + else: + self.color_index = BYLAYER + + self.rotation = obj.get_type(50) # radians? + if not self.rotation: + self.rotation = 0 + else: + self.rotation = self.rotation[0] + + self.width_factor = obj.get_type(41) # Scaling factor along local x axis + if not self.width_factor: + self.width_factor = 1 + else: + self.width_factor = self.width_factor[0] + + self.oblique = obj.get_type(51) # skew in degrees -90 <= oblique <= 90 + if not self.oblique: + self.oblique = 0 + else: + self.oblique = self.oblique[0] + + self.halignment = obj.get_type(72) # horiz. alignment + if not self.halignment: # 0=left, 1=center, 2=right, 3=aligned, 4=middle, 5=fit + self.halignment = 0 + else: + self.halignment = self.halignment[0] + + self.valignment = obj.get_type(73) # vert. alignment + if not self.valignment: # 0=baseline, 1=bottom, 2=middle, 3=top + self.valignment = 0 + else: + self.valignment = self.valignment[0] + + discard, self.layer, discard_index = get_layer(obj.data) + del obj.data[discard_index] + self.loc = self.get_loc(obj.data, self.halignment, self.valignment) + self.extrusion = self.get_extrusion(obj.data) + + + + + def get_loc(self, data, halign, valign): + """Gets adjusted location for text type objects. + + If group 72 and/or 73 values are nonzero then the first alignment point values + are ignored and AutoCAD calculates new values based on the second alignment + point and the length and height of the text string itself (after applying the + text style). If the 72 and 73 values are zero or missing, then the second + alignment point is meaningless. + + I don't know how to calc text size... + """ + # bottom left x, y, z and justification x, y, z = 0 + x, y, z, jx, jy, jz = 0, 0, 0, 0, 0, 0 + for item in data: + if item[0] == 10: # 10 = x + x = item[1] + elif item[0] == 20: # 20 = y + y = item[1] + elif item[0] == 30: # 30 = z + z = item[1] + elif item[0] == 11: # 11 = x + jx = item[1] + elif item[0] == 21: # 21 = y + jy = item[1] + elif item[0] == 31: # 31 = z + jz = item[1] + + if halign or valign: + x, y, z = jx, jy, jz + return [x, y, z] + + def get_extrusion(self, data): + """Find the axis of extrusion. + + Used to get the objects Object Coordinate System (ocs). + """ + vec = [0,0,1] + for item in data: + if item[0] == 210: # 210 = x + vec[0] = item[1] + elif item[0] == 220: # 220 = y + vec[1] = item[1] + elif item[0] == 230: # 230 = z + vec[2] = item[1] + return vec + + + def __repr__(self): + return "%s: layer - %s, value - %s" %(self.__class__.__name__, self.layer, self.value) + + + +class Mtext: + """Class for objects representing dxf Mtext.""" + + def __init__(self, obj): + """Expects an entity object of type mtext as input.""" + if not obj.type == 'mtext': + raise TypeError, "Wrong type %s for mtext object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.height = obj.get_type(40)[0] + self.width = obj.get_type(41)[0] + self.alignment = obj.get_type(71)[0] # alignment 1=TL, 2=TC, 3=TR, 4=ML, 5=MC, 6=MR, 7=BL, 8=BC, 9=BR + self.value = self.get_text(obj.data) # The text string value + + # optional data (with defaults) + self.space = obj.get_type(67) + if self.space: + self.space = self.space[0] + else: + self.space = 0 + + self.color_index = obj.get_type(62) + if self.color_index: + self.color_index = self.color_index[0] + else: + self.color_index = BYLAYER + + self.rotation = obj.get_type(50) # radians + if not self.rotation: + self.rotation = 0 + else: + self.rotation = self.rotation[0] + + self.width_factor = obj.get_type(42) # Scaling factor along local x axis + if not self.width_factor: + self.width_factor = 1 + else: + self.width_factor = self.width_factor[0] + + self.line_space = obj.get_type(44) # percentage of default + if not self.line_space: + self.line_space = 1 + else: + self.line_space = self.line_space[0] + + discard, self.layer, discard_index = get_layer(obj.data) + del obj.data[discard_index] + self.loc = self.get_loc(obj.data) + self.extrusion = self.get_extrusion(obj.data) + + + + + + def get_text(self, data): + """Reconstructs mtext data from dxf codes.""" + primary = '' + secondary = [] + for item in data: + if item[0] == 1: # There should be only one primary... + primary = item[1] + elif item[0] == 3: # There may be any number of extra strings (in order) + secondary.append(item[1]) + if not primary: + #raise ValueError, "Empty Mtext Object!" + string = "Empty Mtext Object!" + if not secondary: + string = primary.replace(r'\P', '\n') + else: + string = ''.join(secondary)+primary + string = string.replace(r'\P', '\n') + return string + def get_loc(self, data): + """Gets location for a mtext type objects. + + Mtext objects have only one point indicating location. + """ + loc = [0,0,0] + for item in data: + if item[0] == 10: # 10 = x + loc[0] = item[1] + elif item[0] == 20: # 20 = y + loc[1] = item[1] + elif item[0] == 30: # 30 = z + loc[2] = item[1] + return loc + + + + + def get_extrusion(self, data): + """Find the axis of extrusion. + + Used to get the objects Object Coordinate System (ocs). + """ + vec = [0,0,1] + for item in data: + if item[0] == 210: # 210 = x + vec[0] = item[1] + elif item[0] == 220: # 220 = y + vec[1] = item[1] + elif item[0] == 230: # 230 = z + vec[2] = item[1] + return vec + + + def __repr__(self): + return "%s: layer - %s, value - %s" %(self.__class__.__name__, self.layer, self.value) + + + +class Circle: + """Class for objects representing dxf Circles.""" + + def __init__(self, obj): + """Expects an entity object of type circle as input.""" + if not obj.type == 'circle': + raise TypeError, "Wrong type %s for circle object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.radius = obj.get_type(40)[0] + + # optional data (with defaults) + self.space = obj.get_type(67) + if self.space: + self.space = self.space[0] + else: + self.space = 0 + + self.color_index = obj.get_type(62) + if self.color_index: + self.color_index = self.color_index[0] + else: + self.color_index = BYLAYER + + discard, self.layer, discard_index = get_layer(obj.data) + del obj.data[discard_index] + self.loc = self.get_loc(obj.data) + self.extrusion = self.get_extrusion(obj.data) + + + + + + def get_loc(self, data): + """Gets the center location for circle type objects. + + Circles have a single coord location. + """ + loc = [0, 0, 0] + for item in data: + if item[0] == 10: # 10 = x + loc[0] = item[1] + elif item[0] == 20: # 20 = y + loc[1] = item[1] + elif item[0] == 30: # 30 = z + loc[2] = item[1] + return loc + + + + def get_extrusion(self, data): + """Find the axis of extrusion. + + Used to get the objects Object Coordinate System (ocs). + """ + vec = [0,0,1] + for item in data: + if item[0] == 210: # 210 = x + vec[0] = item[1] + elif item[0] == 220: # 220 = y + vec[1] = item[1] + elif item[0] == 230: # 230 = z + vec[2] = item[1] + return vec + + + def __repr__(self): + return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius) + + + +class Arc: + """Class for objects representing dxf arcs.""" + + def __init__(self, obj): + """Expects an entity object of type arc as input.""" + if not obj.type == 'arc': + raise TypeError, "Wrong type %s for arc object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.radius = obj.get_type(40)[0] + self.start_angle = obj.get_type(50)[0] + self.end_angle = obj.get_type(51)[0] + + # optional data (with defaults) + self.space = obj.get_type(67) + if self.space: + self.space = self.space[0] + else: + self.space = 0 + + self.color_index = obj.get_type(62) + if self.color_index: + self.color_index = self.color_index[0] + else: + self.color_index = BYLAYER + + discard, self.layer, discard_index = get_layer(obj.data) + del obj.data[discard_index] + self.loc = self.get_loc(obj.data) + self.extrusion = self.get_extrusion(obj.data) + + + + + + def get_loc(self, data): + """Gets the center location for arc type objects. + + Arcs have a single coord location. + """ + loc = [0, 0, 0] + for item in data: + if item[0] == 10: # 10 = x + loc[0] = item[1] + elif item[0] == 20: # 20 = y + loc[1] = item[1] + elif item[0] == 30: # 30 = z + loc[2] = item[1] + return loc + + + + def get_extrusion(self, data): + """Find the axis of extrusion. + + Used to get the objects Object Coordinate System (ocs). + """ + vec = [0,0,1] + for item in data: + if item[0] == 210: # 210 = x + vec[0] = item[1] + elif item[0] == 220: # 220 = y + vec[1] = item[1] + elif item[0] == 230: # 230 = z + vec[2] = item[1] + return vec + + + def __repr__(self): + return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius) + + + +class BlockRecord: + """Class for objects representing dxf block_records.""" + + def __init__(self, obj): + """Expects an entity object of type block_record as input.""" + if not obj.type == 'block_record': + raise TypeError, "Wrong type %s for block_record object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.name = obj.get_type(2)[0] + + # optional data (with defaults) + self.insertion_units = obj.get_type(70) + if not self.insertion_units: + self.insertion_units = None + else: + self.insertion_units = self.insertion_units[0] + + self.insert_units = obj.get_type(1070) + if not self.insert_units: + self.insert_units = None + else: + self.insert_units = self.insert_units[0] + + + + + + + def __repr__(self): + return "%s: name - %s, insert units - %s" %(self.__class__.__name__, self.name, self.insertion_units) + + + + +class Block: + """Class for objects representing dxf blocks.""" + + def __init__(self, obj): + """Expects an entity object of type block as input.""" + if not obj.type == 'block': + raise TypeError, "Wrong type %s for block object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.flags = obj.get_type(70)[0] + self.entities = Object('block_contents') + self.entities.data = objectify([ent for ent in obj.data if type(ent) != list]) + + # optional data (with defaults) + self.name = obj.get_type(3) + if self.name: + self.name = self.name[0] + else: + self.name = '' + + self.path = obj.get_type(1) + if self.path: + self.path = self.path[0] + else: + self.path = '' + + self.discription = obj.get_type(4) + if self.discription: + self.discription = self.discription[0] + else: + self.discription = '' + + discard, self.layer, discard_index = get_layer(obj.data) + del obj.data[discard_index] + self.loc = self.get_loc(obj.data) + + + + + + def get_loc(self, data): + """Gets the insert point of the block.""" + loc = [0, 0, 0] + for item in data: + if type(item) != list: + continue + if item[0] == 10: # 10 = x + loc[0] = item[1] + elif item[0] == 20: # 20 = y + loc[1] = item[1] + elif item[0] == 30: # 30 = z + loc[2] = item[1] + return loc + + + + def __repr__(self): + return "%s: name - %s, description - %s, xref-path - %s" %(self.__class__.__name__, self.name, self.discription, self.path) + + + + +class Insert: + """Class for objects representing dxf inserts.""" + + def __init__(self, obj): + """Expects an entity object of type insert as input.""" + if not obj.type == 'insert': + raise TypeError, "Wrong type %s for insert object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.block = obj.get_type(2)[0] + + # optional data (with defaults) + self.rotation = obj.get_type(50) + if self.rotation: + self.rotation = self.rotation[0] + else: + self.rotation = 0 + + self.space = obj.get_type(67) + if self.space: + self.space = self.space[0] + else: + self.space = 0 + + self.color_index = obj.get_type(62) + if self.color_index: + self.color_index = self.color_index[0] + else: + self.color_index = BYLAYER + + discard, self.layer, discard_index = get_layer(obj.data) + del obj.data[discard_index] + self.loc = self.get_loc(obj.data) + self.scale = self.get_scale(obj.data) + self.rows, self.columns = self.get_array(obj.data) + self.extrusion = self.get_extrusion(obj.data) + + + + + + def get_loc(self, data): + """Gets the center location for circle type objects. + + Circles have a single coord location. + """ + loc = [0, 0, 0] + for item in data: + if item[0] == 10: # 10 = x + loc[0] = item[1] + elif item[0] == 20: # 20 = y + loc[1] = item[1] + elif item[0] == 30: # 30 = z + loc[2] = item[1] + return loc + + + + def get_scale(self, data): + """Gets the x/y/z scale factor for the block. + """ + scale = [1, 1, 1] + for item in data: + if item[0] == 41: # 41 = x scale + scale[0] = item[1] + elif item[0] == 42: # 42 = y scale + scale[1] = item[1] + elif item[0] == 43: # 43 = z scale + scale[2] = item[1] + return scale + + + + def get_array(self, data): + """Returns the pair (row number, row spacing), (column number, column spacing).""" + columns = 1 + rows = 1 + cspace = 0 + rspace = 0 + for item in data: + if item[0] == 70: # 70 = columns + columns = item[1] + elif item[0] == 71: # 71 = rows + rows = item[1] + if item[0] == 44: # 44 = columns + cspace = item[1] + elif item[0] == 45: # 45 = rows + rspace = item[1] + return (rows, rspace), (columns, cspace) + + + + def get_extrusion(self, data): + """Find the axis of extrusion. + + Used to get the objects Object Coordinate System (ocs). + """ + vec = [0,0,1] + for item in data: + if item[0] == 210: # 210 = x + vec[0] = item[1] + elif item[0] == 220: # 220 = y + vec[1] = item[1] + elif item[0] == 230: # 230 = z + vec[2] = item[1] + return vec + + + def __repr__(self): + return "%s: layer - %s, block - %s" %(self.__class__.__name__, self.layer, self.block) + + + + +class Ellipse: + """Class for objects representing dxf ellipses.""" + + def __init__(self, obj): + """Expects an entity object of type ellipse as input.""" + if not obj.type == 'ellipse': + raise TypeError, "Wrong type %s for ellipse object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.ratio = obj.get_type(40)[0] + self.start_angle = obj.get_type(41)[0] + self.end_angle = obj.get_type(42)[0] + + # optional data (with defaults) + self.space = obj.get_type(67) + if self.space: + self.space = self.space[0] + else: + self.space = 0 + + self.color_index = obj.get_type(62) + if self.color_index: + self.color_index = self.color_index[0] + else: + self.color_index = BYLAYER + + discard, self.layer, discard_index = get_layer(obj.data) + del obj.data[discard_index] + self.loc = self.get_loc(obj.data) + self.major = self.get_major(obj.data) + self.extrusion = self.get_extrusion(obj.data) + self.radius = sqrt(self.major[0]**2 + self.major[0]**2 + self.major[0]**2) + + + + + def get_loc(self, data): + """Gets the center location for arc type objects. + + Arcs have a single coord location. + """ + loc = [0, 0, 0] + for item in data: + if item[0] == 10: # 10 = x + loc[0] = item[1] + elif item[0] == 20: # 20 = y + loc[1] = item[1] + elif item[0] == 30: # 30 = z + loc[2] = item[1] + return loc + + + + def get_major(self, data): + """Gets the major axis for ellipse type objects. + + The ellipse major axis defines the rotation of the ellipse and its radius. + """ + loc = [0, 0, 0] + for item in data: + if item[0] == 11: # 11 = x + loc[0] = item[1] + elif item[0] == 21: # 21 = y + loc[1] = item[1] + elif item[0] == 31: # 31 = z + loc[2] = item[1] + return loc + + + + def get_extrusion(self, data): + """Find the axis of extrusion. + + Used to get the objects Object Coordinate System (ocs). + """ + vec = [0,0,1] + for item in data: + if item[0] == 210: # 210 = x + vec[0] = item[1] + elif item[0] == 220: # 220 = y + vec[1] = item[1] + elif item[0] == 230: # 230 = z + vec[2] = item[1] + return vec + + + def __repr__(self): + return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius) + + + +class Face: + """Class for objects representing dxf 3d faces.""" + + def __init__(self, obj): + """Expects an entity object of type 3dfaceplot as input.""" + if not obj.type == '3dface': + raise TypeError, "Wrong type %s for 3dface object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # optional data (with defaults) + self.space = obj.get_type(67) + if self.space: + self.space = self.space[0] + else: + self.space = 0 + + self.color_index = obj.get_type(62) + if self.color_index: + self.color_index = self.color_index[0] + else: + self.color_index = BYLAYER + + discard, self.layer, discard_index = get_layer(obj.data) + del obj.data[discard_index] + self.points = self.get_points(obj.data) + + + + + def get_points(self, data): + """Gets 3-4 points for a 3d face type object. + + Faces have three or optionally four verts. + """ + + a = [0, 0, 0] + b = [0, 0, 0] + c = [0, 0, 0] + d = False + for item in data: + # ----------- a ------------- + if item[0] == 10: # 10 = x + a[0] = item[1] + elif item[0] == 20: # 20 = y + a[1] = item[1] + elif item[0] == 30: # 30 = z + a[2] = item[1] + # ----------- b ------------- + elif item[0] == 11: # 11 = x + b[0] = item[1] + elif item[0] == 21: # 21 = y + b[1] = item[1] + elif item[0] == 31: # 31 = z + b[2] = item[1] + # ----------- c ------------- + elif item[0] == 12: # 12 = x + c[0] = item[1] + elif item[0] == 22: # 22 = y + c[1] = item[1] + elif item[0] == 32: # 32 = z + c[2] = item[1] + # ----------- d ------------- + elif item[0] == 13: # 13 = x + d = [0, 0, 0] + d[0] = item[1] + elif item[0] == 23: # 23 = y + d[1] = item[1] + elif item[0] == 33: # 33 = z + d[2] = item[1] + out = [a,b,c] + if d: + out.append(d) + return out + + + def __repr__(self): + return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) + + +def get_name(data): + """Get the name of an object from its object data. + + Returns a pair of (data_item, name) where data_item is the list entry where the name was found + (the data_item can be used to remove the entry from the object data). Be sure to check + name not None before using the returned values! + """ + value = None + for i, item in enumerate(data): + if item[0] == 2: + value = item[1] + break + return item, value, i + +def get_layer(data): + """Expects object data as input. + + Returns (entry, layer_name, entry_index) where entry is the data item that provided the layer name. + """ + value = None + for i, item in enumerate(data): + if item[0] == 8: + value = item[1] + break + return item, value, i + + +# type to object map +type_map = { + 'line':Line, + 'lwpolyline':LWpolyline, + 'text':Text, + 'mtext':Mtext, + 'circle':Circle, + 'arc':Arc, + 'layer':Layer, + 'block_record':BlockRecord, + 'block':Block, + 'insert':Insert, + 'ellipse':Ellipse, + '3dface':Face +} + +def objectify(data): + """Expects a section type object's data as input. + + Maps object data to the correct object type. + """ + objects = [] # colector for finished objects + known_types = type_map.keys() # so we don't have to call foo.keys() every iteration + index = 0 + while index < len(data): + item = data[index] + if type(item) != list and item.type in known_types: + # proccess the object and append the resulting object + objects.append(type_map[item.type](item)) + elif type(item) != list and item.type == 'table': + item.data = objectify(item.data) # tables have sub-objects + objects.append(item) + elif type(item) != list and item.type == 'polyline': + pline = Polyline(item) + while 1: + index += 1 + item = data[index] + if item.type == 'vertex': + v = Vertex(item) + pline.points.append(v) + elif item.type == 'seqend': + break + else: + print "Error: non-vertex found before seqend!" + index -= 1 + break + objects.append(pline) + else: + # we will just let the data pass un-harrased + objects.append(item) + index += 1 + return objects +if __name__ == "__main__": + print "No example yet!" \ No newline at end of file diff --git a/release/scripts/bpymodules/dxfReader.py b/release/scripts/bpymodules/dxfReader.py new file mode 100644 index 00000000000..d4a39cf63d6 --- /dev/null +++ b/release/scripts/bpymodules/dxfReader.py @@ -0,0 +1,382 @@ +"""This module provides a function for reading dxf files and parsing them into a useful tree of objects and data. + + The convert function is called by the readDXF fuction to convert dxf strings into the correct data based + on their type code. readDXF expects a (full path) file name as input. +""" + +# -------------------------------------------------------------------------- +# DXF Reader v0.9 by Ed Blake (AKA Kitsu) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +#from dxfImportObjects import * + +class Object: + """Empty container class for dxf objects""" + + def __init__(self, _type='', block=False): + """_type expects a string value.""" + self.type = _type + self.name = '' + self.data = [] + + def __str__(self): + if self.name: + return self.name + else: + return self.type + + def __repr__(self): + return str(self.data) + + def get_type(self, kind=''): + """Despite the name, this method actually returns all objects of type 'kind' from self.data.""" + if type: + objects = [] + for item in self.data: + if type(item) != list and item.type == kind: + # we want this type of object + objects.append(item) + elif type(item) == list and item[0] == kind: + # we want this type of data + objects.append(item[1]) + return objects + + +class InitializationError(Exception): pass + +class StateMachine: + """(finite) State Machine from the great David Mertz's great Charming Python article.""" + + def __init__(self): + self.handlers = [] + self.startState = None + self.endStates = [] + + def add_state(self, handler, end_state=0): + """All states and handlers are functions which return + a state and a cargo.""" + self.handlers.append(handler) + if end_state: + self.endStates.append(handler) + def set_start(self, handler): + """Sets the starting handler function.""" + self.startState = handler + + + def run(self, cargo=None): + if not self.startState: + raise InitializationError,\ + "must call .set_start() before .run()" + if not self.endStates: + raise InitializationError, \ + "at least one state must be an end_state" + handler = self.startState + while 1: + (newState, cargo) = handler(cargo) + #print cargo + if newState in self.endStates: + return newState(cargo) + #break + elif newState not in self.handlers: + raise RuntimeError, "Invalid target %s" % newState + else: + handler = newState + +def get_name(data): + """Get the name of an object from its object data. + + Returns a pair of (data_item, name) where data_item is the list entry where the name was found + (the data_item can be used to remove the entry from the object data). Be sure to check + name not None before using the returned values! + """ + value = None + for item in data: + if item[0] == 2: + value = item[1] + break + return item, value + +def get_layer(data): + """Expects object data as input. + + Returns (entry, layer_name) where entry is the data item that provided the layer name. + """ + value = None + for item in data: + if item[0] == 8: + value = item[1] + break + return item, value + + +def convert(code, value): + """Convert a string to the correct Python type based on its dxf code. + code types: + ints = 60-79, 170-179, 270-289, 370-389, 400-409, 1060-1070 + longs = 90-99, 420-429, 440-459, 1071 + floats = 10-39, 40-59, 110-139, 140-149, 210-239, 460-469, 1010-1059 + hex = 105, 310-379, 390-399 + strings = 0-9, 100, 102, 300-309, 410-419, 430-439, 470-479, 999, 1000-1009 + """ + if 59 < code < 80 or 169 < code < 180 or 269 < code < 290 or 369 < code < 390 or 399 < code < 410 or 1059 < code < 1071: + value = int(value) + elif 89 < code < 100 or 419 < code < 430 or 439 < code < 460 or code == 1071: + value = long(value) + elif 9 < code < 60 or 109 < code < 150 or 209 < code < 240 or 459 < code < 470 or 1009 < code < 1060: + value = float(value) + elif code == 105 or 309 < code < 380 or 389 < code < 400: + value = int(value, 16) # should be left as string? + else: # it's already a string so do nothing + pass + return value + + +def findObject(infile, kind=''): + """Finds the next occurance of an object.""" + obj = False + while 1: + line = infile.readline() + if not line: # readline returns '' at eof + return False + if not obj: # We're still looking for our object code + if line.lower().strip() == '0': + obj = True # found it + else: # we are in an object definition + if kind: # if we're looking for a particular kind + if line.lower().strip() == kind: + obj = Object(line.lower().strip()) + break + else: # otherwise take anything non-numeric + if line.lower().strip() not in string.digits: + obj = Object(line.lower().strip()) + break + obj = False # whether we found one or not it's time to start over + return obj + +def handleObject(infile): + """Add data to an object until end of object is found.""" + line = infile.readline() + if line.lower().strip() == 'section': + return 'section' # this would be a problem + elif line.lower().strip() == 'endsec': + return 'endsec' # this means we are done with a section + else: # add data to the object until we find a new object + obj = Object(line.lower().strip()) + obj.name = obj.type + done = False + data = [] + while not done: + line = infile.readline() + if not data: + if line.lower().strip() == '0': + #we've found an object, time to return + return obj + else: + # first part is always an int + data.append(int(line.lower().strip())) + else: + data.append(convert(data[0], line.strip())) + obj.data.append(data) + data = [] + +def handleTable(table, infile): + """Special handler for dealing with nested table objects.""" + item, name = get_name(table.data) + if name: # We should always find a name + table.data.remove(item) + table.name = name.lower() + # This next bit is from handleObject + # handleObject should be generalized to work with any section like object + while 1: + obj = handleObject(infile) + if obj.type == 'table': + print "Warning: previous table not closed!" + return table + elif obj.type == 'endtab': + return table # this means we are done with the table + else: # add objects to the table until one of the above is found + table.data.append(obj) + + + + +def handleBlock(block, infile): + """Special handler for dealing with nested table objects.""" + item, name = get_name(block.data) + if name: # We should always find a name + block.data.remove(item) + block.name = name + # This next bit is from handleObject + # handleObject should be generalized to work with any section like object + while 1: + obj = handleObject(infile) + if obj.type == 'block': + print "Warning: previous block not closed!" + return block + elif obj.type == 'endblk': + return block # this means we are done with the table + else: # add objects to the table until one of the above is found + block.data.append(obj) + + + + +"""These are the states/functions used in the State Machine. +states: + start - find first section + start_section - add data, find first object + object - add obj-data, watch for next obj (called directly by start_section) + end_section - look for next section or eof + end - return results +""" + +def start(cargo): + """Expects the infile as cargo, initializes the cargo.""" + #print "Entering start state!" + infile = cargo + drawing = Object('drawing') + section = findObject(infile, 'section') + if section: + return start_section, (infile, drawing, section) + else: + return error, (infile, "Failed to find any sections!") + +def start_section(cargo): + """Expects [infile, drawing, section] as cargo, builds a nested section object.""" + #print "Entering start_section state!" + infile = cargo[0] + drawing = cargo[1] + section = cargo[2] + # read each line, if it is an object declaration go to object mode + # otherwise create a [index, data] pair and add it to the sections data. + done = False + data = [] + while not done: + line = infile.readline() + + if not data: # if we haven't found a dxf code yet + if line.lower().strip() == '0': + # we've found an object + while 1: # no way out unless we find an end section or a new section + obj = handleObject(infile) + if obj == 'section': # shouldn't happen + print "Warning: failed to close previous section!" + return end_section, (infile, drawing) + elif obj == 'endsec': # This section is over, look for the next + drawing.data.append(section) + return end_section, (infile, drawing) + elif obj.type == 'table': # tables are collections of data + obj = handleTable(obj, infile) # we need to find all there contents + section.data.append(obj) # before moving on + elif obj.type == 'block': # the same is true of blocks + obj = handleBlock(obj, infile) # we need to find all there contents + section.data.append(obj) # before moving on + else: # found another sub-object + section.data.append(obj) + else: + data.append(int(line.lower().strip())) + else: # we have our code, now we just need to convert the data and add it to our list. + data.append(convert(data[0], line.strip())) + section.data.append(data) + data = [] +def end_section(cargo): + """Expects (infile, drawing) as cargo, searches for next section.""" + #print "Entering end_section state!" + infile = cargo[0] + drawing = cargo[1] + section = findObject(infile, 'section') + if section: + return start_section, (infile, drawing, section) + else: + return end, (infile, drawing) + +def end(cargo): + """Expects (infile, drawing) as cargo, called when eof has been reached.""" + #print "Entering end state!" + infile = cargo[0] + drawing = cargo[1] + #infile.close() + return drawing + +def error(cargo): + """Expects a (infile, string) as cargo, called when there is an error during processing.""" + #print "Entering error state!" + infile = cargo[0] + err = cargo[1] + infile.close() + print "There has been an error:" + print err + return False + +def readDXF(filename, objectify): + """Given a file name try to read it as a dxf file. + + Output is an object with the following structure + drawing + header + header data + classes + class data + tables + table data + blocks + block data + entities + entity data + objects + object data + where foo data is a list of sub-objects. True object data + is of the form [code, data]. +""" + infile = open(filename) + + sm = StateMachine() + sm.add_state(error, True) + sm.add_state(end, True) + sm.add_state(start_section) + sm.add_state(end_section) + sm.add_state(start) + sm.set_start(start) + try: + drawing = sm.run(infile) + if drawing: + drawing.name = filename + for obj in drawing.data: + item, name = get_name(obj.data) + if name: + obj.data.remove(item) + obj.name = name.lower() + setattr(drawing, name.lower(), obj) + # Call the objectify function to cast + # raw objects into the right types of object + obj.data = objectify(obj.data) + #print obj.name + finally: + infile.close() + return drawing +if __name__ == "__main__": + filename = r".\examples\block-test.dxf" + drawing = readDXF(filename) + for item in drawing.entities.data: + print item + + diff --git a/release/scripts/bpymodules/mesh_gradient.py b/release/scripts/bpymodules/mesh_gradient.py new file mode 100644 index 00000000000..936f4958467 --- /dev/null +++ b/release/scripts/bpymodules/mesh_gradient.py @@ -0,0 +1,229 @@ +# This is not to be used directly, vertexGradientPick can be used externaly + +import Blender +import BPyMesh +import BPyWindow + +mouseViewRay= BPyWindow.mouseViewRay +from Blender import Mathutils, Window, Scene, Draw, sys +from Blender.Mathutils import CrossVecs, Vector, Intersect, LineIntersect, AngleBetweenVecs +LMB= Window.MButs['L'] + +def mouseup(): + # Loop until click + mouse_buttons = Window.GetMouseButtons() + while not mouse_buttons & LMB: + sys.sleep(10) + mouse_buttons = Window.GetMouseButtons() + while mouse_buttons & LMB: + sys.sleep(10) + mouse_buttons = Window.GetMouseButtons() + +def mousedown_wait(): + # If the menu has just been pressed dont use its mousedown, + mouse_buttons = Window.GetMouseButtons() + while mouse_buttons & LMB: + mouse_buttons = Window.GetMouseButtons() + +eps= 0.0001 +def vertexGradientPick(ob, MODE): + #MODE 0 == VWEIGHT, 1 == VCOL + + me= ob.getData(mesh=1) + if not me.faceUV: me.faceUV= True + + Window.DrawProgressBar (0.0, '') + + mousedown_wait() + + if MODE==0: + act_group= me.activeGroup + if act_group == None: + mousedown_wait() + Draw.PupMenu('Error, mesh has no active group.') + return + + # Loop until click + Window.DrawProgressBar (0.25, 'Click to set gradient start') + mouseup() + + obmat= ob.matrixWorld + screen_x, screen_y = Window.GetMouseCoords() + mouseInView, OriginA, DirectionA = mouseViewRay(screen_x, screen_y, obmat) + if not mouseInView or not OriginA: + return + + # get the mouse weight + + if MODE==0: + pickValA= BPyMesh.pickMeshGroupWeight(me, act_group, OriginA, DirectionA) + if MODE==1: + pickValA= BPyMesh.pickMeshGroupVCol(me, OriginA, DirectionA) + + Window.DrawProgressBar (0.75, 'Click to set gradient end') + mouseup() + + TOALPHA= Window.GetKeyQualifiers() & Window.Qual.SHIFT + + screen_x, screen_y = Window.GetMouseCoords() + mouseInView, OriginB, DirectionB = mouseViewRay(screen_x, screen_y, obmat) + if not mouseInView or not OriginB: + return + + if not TOALPHA: # Only get a second opaque value if we are not blending to alpha + if MODE==0: pickValB= BPyMesh.pickMeshGroupWeight(me, act_group, OriginB, DirectionB) + else: + pickValB= BPyMesh.pickMeshGroupVCol(me, OriginB, DirectionB) + else: + if MODE==0: pickValB= 0.0 + else: pickValB= [0.0, 0.0, 0.0] # Dummy value + + # Neither points touched a face + if pickValA == pickValB == None: + return + + # clicking on 1 non face is fine. just set the weight to 0.0 + if pickValA==None: + pickValA= 0.0 + + # swap A/B + OriginA, OriginB= OriginB, OriginA + DirectionA, DirectionB= DirectionB, DirectionA + pickValA, pickValB= pickValA, pickValB + + TOALPHA= True + + if pickValB==None: + pickValB= 0.0 + TOALPHA= True + + # set up 2 lines so we can measure their distances and calc the gradient + + # make a line 90d to the grad in screenspace. + if (OriginA-OriginB).length <= eps: # Persp view. same origin different direction + cross_grad= CrossVecs(DirectionA, DirectionB) + ORTHO= False + + else: # Ortho - Same direction, different origin + cross_grad= CrossVecs(DirectionA, OriginA-OriginB) + ORTHO= True + + cross_grad.normalize() + cross_grad= cross_grad * 100 + + lineA= (OriginA, OriginA+(DirectionA*100)) + lineB= (OriginB, OriginB+(DirectionB*100)) + + if not ORTHO: + line_angle= AngleBetweenVecs(lineA[1], lineB[1])/2 + line_mid= (lineA[1]+lineB[1])*0.5 + + VSEL= [False] * (len(me.verts)) + + # Get the selected faces and apply the selection to the verts. + for f in me.faces: + if f.sel: + for v in f.v: + VSEL[v.index]= True + groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me) + + + + def grad_weight_from_co(v): + ''' + Takes a vert and retuens its gradient radio between A and B + ''' + + if not VSEL[v.index]: # Not bart of a selected face? + return None, None + + v_co= v.co + # make a line 90d to the 2 lines the user clicked. + vert_line= (v_co - cross_grad, v_co + cross_grad) + + xA= LineIntersect(vert_line[0], vert_line[1], lineA[0], lineA[1]) + xB= LineIntersect(vert_line[0], vert_line[1], lineB[0], lineB[1]) + + if not xA or not xB: # Should never happen but support it anyhow + return None, None + + wA= (xA[0]-xA[1]).length + wB= (xB[0]-xB[1]).length + + wTot= wA+wB + if not wTot: # lines are on the same point. + return None, None + + ''' + Get the length of the line between both intersections on the + 2x view lines. + if the dist between lineA+VertLine and lineB+VertLine is + greater then the lenth between lineA and lineB intersection points, it means + that the verts are not inbetween the 2 lines. + ''' + lineAB_length= (xA[1]-xB[1]).length + + # normalzie + wA= wA/wTot + wB= wB/wTot + + if ORTHO: # Con only use line length method with parelelle lines + if wTot > lineAB_length+eps: + # vert is outside the range on 1 side. see what side of the grad + if wA>wB: wA, wB= 1.0, 0.0 + else: wA, wB= 0.0, 1.0 + else: + # PERSP, lineA[0] is the same origin as lineB[0] + + # Either xA[0] or xB[0] can be used instead of a possible x_mid between the 2 + # as long as the point is inbetween lineA and lineB it dosent matter. + a= AngleBetweenVecs(lineA[0]-xA[0], line_mid) + if a>line_angle: + # vert is outside the range on 1 side. see what side of the grad + if wA>wB: wA, wB= 1.0, 0.0 + else: wA, wB= 0.0, 1.0 + + return wA, wB + + + grad_weights= [grad_weight_from_co(v) for v in me.verts] + + + if MODE==0: + for v in me.verts: + i= v.index + if VSEL[i]: + wA, wB = grad_weights[i] + if wA != None: # and wB + if TOALPHA: + # Do alpha by using the exiting weight for + try: pickValB= vWeightDict[i][act_group] + except: pickValB= 0.0 # The weights not there? assume zero + # Mix2 2 opaque weights + vWeightDict[i][act_group]= pickValB*wA + pickValA*wB + + else: # MODE==1 VCol + for f in me.faces: + if f.sel: + f_v= f.v + for i in xrange(len(f_v)): + v= f_v[i] + wA, wB = grad_weights[v.index] + + c= f.col[i] + + if TOALPHA: + pickValB= c.r, c.g, c.b + + c.r = int(pickValB[0]*wA + pickValA[0]*wB) + c.g = int(pickValB[1]*wA + pickValA[1]*wB) + c.b = int(pickValB[2]*wA + pickValA[2]*wB) + + + + + # Copy weights back to the mesh. + BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict) + Window.DrawProgressBar (1.0, '') + + diff --git a/release/scripts/bpymodules/meshtools.py b/release/scripts/bpymodules/meshtools.py new file mode 100644 index 00000000000..274a12ea6da --- /dev/null +++ b/release/scripts/bpymodules/meshtools.py @@ -0,0 +1,355 @@ +# $Id$ +# +# +---------------------------------------------------------+ +# | Copyright (c) 2001 Anthony D'Agostino | +# | http://www.redrival.com/scorpius | +# | scorpius@netzero.com | +# | September 28, 2002 | +# +---------------------------------------------------------+ +# | Common Functions & Global Variables For All IO Modules | +# +---------------------------------------------------------+ + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** + +import Blender +import sys + +show_progress = 1 # Set to 0 for faster performance +average_vcols = 1 # Off for per-face, On for per-vertex +overwrite_mesh_name = 0 # Set to 0 to increment object-name version + +blender_version = Blender.Get('version') +blender_version_str = `blender_version`[0] + '.' + `blender_version`[1:] + +try: + import operator +except: + msg = "Error: you need a full Python install to run this script." + meshtools.print_boxed(msg) + Blender.Draw.PupMenu("ERROR%t|"+msg) + +# ================================= +# === Append Faces To Face List === +# ================================= +def append_faces(mesh, faces, facesuv, uvcoords): + for i in xrange(len(faces)): + if not i%100 and show_progress: Blender.Window.DrawProgressBar(float(i)/len(faces), "Generating Faces") + numfaceverts=len(faces[i]) + if numfaceverts == 2: #This is not a face is an edge + if mesh.edges == None: #first run + mesh.addEdgeData() + #rev_face = revert(cur_face) + i1 = faces[i][0] + i2 = faces[i][1] + ee = mesh.addEdge(mesh.verts[i1],mesh.verts[i2]) + ee.flag |= Blender.NMesh.EdgeFlags.EDGEDRAW + ee.flag |= Blender.NMesh.EdgeFlags.EDGERENDER + elif numfaceverts in [3,4]: # This face is a triangle or quad + face = Blender.NMesh.Face() + for j in xrange(numfaceverts): + index = faces[i][j] + face.v.append(mesh.verts[index]) + if len(uvcoords) > 1: + uvidx = facesuv[i][j] + face.uv.append(uvcoords[uvidx]) + face.mode = 0 + face.col = [Blender.NMesh.Col()]*4 + mesh.faces.append(face) + else: # Triangulate n-sided convex polygon. + a, b, c = 0, 1, 2 # Indices of first triangle. + for j in xrange(numfaceverts-2): # Number of triangles in polygon. + face = Blender.NMesh.Face() + face.v.append(mesh.verts[faces[i][a]]) + face.v.append(mesh.verts[faces[i][b]]) + face.v.append(mesh.verts[faces[i][c]]) + b = c; c += 1 + mesh.faces.append(face) + #face.smooth = 1 + +# =================================== +# === Append Verts to Vertex List === +# =================================== +def append_verts(mesh, verts, normals): + #print "Number of normals:", len(normals) + #print "Number of verts :", len(verts) + for i in xrange(len(verts)): + if not i%100 and show_progress: Blender.Window.DrawProgressBar(float(i)/len(verts), "Generating Verts") + x, y, z = verts[i] + mesh.verts.append(Blender.NMesh.Vert(x, y, z)) + if normals: + mesh.verts[i].no[0] = normals[i][0] + mesh.verts[i].no[1] = normals[i][1] + mesh.verts[i].no[2] = normals[i][2] + +# =========================== +# === Create Blender Mesh === +# =========================== +def create_mesh(verts, faces, objname, facesuv=[], uvcoords=[], normals=[]): + if normals: normal_flag = 0 + else: normal_flag = 1 + mesh = Blender.NMesh.GetRaw() + append_verts(mesh, verts, normals) + append_faces(mesh, faces, facesuv, uvcoords) + if not overwrite_mesh_name: + objname = versioned_name(objname) + ob= Blender.NMesh.PutRaw(mesh, objname, normal_flag) # Name the Mesh + ob.name= objname # Name the Object + Blender.Redraw() + +# ============================== +# === Increment Name Version === +# ============================== +def versioned_name(objname): + existing_names = [] + for object in Blender.Object.Get(): + existing_names.append(object.name) + existing_names.append(object.getData(name_only=1)) + if objname in existing_names: # don't over-write other names + try: + name, ext = objname.split('.') + except ValueError: + name, ext = objname, '' + try: + num = int(ext) + root = name + except ValueError: + root = objname + for i in xrange(1, 1000): + objname = "%s.%03d" % (root, i) + if objname not in existing_names: + break + return objname + +# =========================== +# === Print Text In A Box === +# =========================== +def print_boxed(text): + lines = text.splitlines() + maxlinelen = max(map(len, lines)) + if sys.platform[:3] == "win": + print chr(218)+chr(196) + chr(196)*maxlinelen + chr(196)+chr(191) + for line in lines: + print chr(179) + ' ' + line.ljust(maxlinelen) + ' ' + chr(179) + print chr(192)+chr(196) + chr(196)*maxlinelen + chr(196)+chr(217) + else: + print '+-' + '-'*maxlinelen + '-+' + for line in lines: print '| ' + line.ljust(maxlinelen) + ' |' + print '+-' + '-'*maxlinelen + '-+' + print '\a\r', # beep when done + +# =============================================== +# === Get euler angles from a rotation matrix === +# =============================================== +def mat2euler(mat): + angle_y = -math.asin(mat[0][2]) + c = math.cos(angle_y) + if math.fabs(c) > 0.005: + angle_x = math.atan2(mat[1][2]/c, mat[2][2]/c) + angle_z = math.atan2(mat[0][1]/c, mat[0][0]/c) + else: + angle_x = 0.0 + angle_z = -math.atan2(mat[1][0], mat[1][1]) + return (angle_x, angle_y, angle_z) + +# ========================== +# === Transpose A Matrix === +# ========================== +def transpose(A): + S = len(A) + T = len(A[0]) + B = [[None]*S for i in xrange(T)] + for i in xrange(T): + for j in xrange(S): + B[i][j] = A[j][i] + return B + +# ======================= +# === Apply Transform === +# ======================= +def apply_transform(vertex, matrix): + x, y, z = vertex + xloc, yloc, zloc = matrix[3][0], matrix[3][1], matrix[3][2] + xcomponent = x*matrix[0][0] + y*matrix[1][0] + z*matrix[2][0] + xloc + ycomponent = x*matrix[0][1] + y*matrix[1][1] + z*matrix[2][1] + yloc + zcomponent = x*matrix[0][2] + y*matrix[1][2] + z*matrix[2][2] + zloc + vertex = [xcomponent, ycomponent, zcomponent] + return vertex + +# ========================= +# === Has Vertex Colors === +# ========================= +def has_vertex_colors(mesh): + # My replacement/workaround for hasVertexColours() + # The docs say: + # "Warning: If a mesh has both vertex colours and textured faces, + # this function will return False. This is due to the way Blender + # deals internally with the vertex colours array (if there are + # textured faces, it is copied to the textured face structure and + # the original array is freed/deleted)." + try: + return mesh.faces[0].col[0] + except: + return 0 + +# =========================== +# === Generate Edge Table === +# =========================== +def generate_edgetable(mesh): + edge_table = {} + numfaces = len(mesh.faces) + + for i in xrange(numfaces): + if not i%100 and show_progress: + Blender.Window.DrawProgressBar(float(i)/numfaces, "Generating Edge Table") + if len(mesh.faces[i].v) == 4: # Process Quadrilaterals + generate_entry_from_quad(mesh, i, edge_table) + elif len(mesh.faces[i].v) == 3: # Process Triangles + generate_entry_from_tri(mesh, i, edge_table) + else: # Skip This Face + print "Face #", i, "was skipped." + + # === Sort Edge_Table Keys & Add Edge Indices === + i = 0 + keys = edge_table.keys() + keys.sort() + for key in keys: + edge_table[key][6] = i + i += 1 + + # === Replace Tuples With Indices === + for key in keys: + for i in [2,3,4,5]: + if edge_table.has_key(edge_table[key][i]): + edge_table[key][i] = edge_table[edge_table[key][i]][6] + else: + keyrev = (edge_table[key][i][1], edge_table[key][i][0]) + edge_table[key][i] = edge_table[keyrev][6] + + return edge_table + +# ================================ +# === Generate Entry From Quad === +# ================================ +def generate_entry_from_quad(mesh, i, edge_table): + vertex4, vertex3, vertex2, vertex1 = mesh.faces[i].v + + if has_vertex_colors(mesh): + vcolor4, vcolor3, vcolor2, vcolor1 = mesh.faces[i].col + Acol = (vcolor1.r/255.0, vcolor1.g/255.0, vcolor1.b/255.0) + Bcol = (vcolor2.r/255.0, vcolor2.g/255.0, vcolor2.b/255.0) + Ccol = (vcolor3.r/255.0, vcolor3.g/255.0, vcolor3.b/255.0) + Dcol = (vcolor4.r/255.0, vcolor4.g/255.0, vcolor4.b/255.0) + + # === verts are upper case, edges are lower case === + A, B, C, D = vertex1.index, vertex2.index, vertex3.index, vertex4.index + a, b, c, d = (A, B), (B, C), (C, D), (D, A) + + if edge_table.has_key((B, A)): + edge_table[(B, A)][1] = i + edge_table[(B, A)][4] = d + edge_table[(B, A)][5] = b + if has_vertex_colors(mesh): edge_table[(B, A)][8] = Bcol + else: + if has_vertex_colors(mesh): + edge_table[(A, B)] = [i, None, d, b, None, None, None, Bcol, None] + else: + edge_table[(A, B)] = [i, None, d, b, None, None, None] + + if edge_table.has_key((C, B)): + edge_table[(C, B)][1] = i + edge_table[(C, B)][4] = a + edge_table[(C, B)][5] = c + if has_vertex_colors(mesh): edge_table[(C, B)][8] = Ccol + else: + if has_vertex_colors(mesh): + edge_table[(B, C)] = [i, None, a, c, None, None, None, Ccol, None] + else: + edge_table[(B, C)] = [i, None, a, c, None, None, None] + + if edge_table.has_key((D, C)): + edge_table[(D, C)][1] = i + edge_table[(D, C)][4] = b + edge_table[(D, C)][5] = d + if has_vertex_colors(mesh): edge_table[(D, C)][8] = Dcol + else: + if has_vertex_colors(mesh): + edge_table[(C, D)] = [i, None, b, d, None, None, None, Dcol, None] + else: + edge_table[(C, D)] = [i, None, b, d, None, None, None] + + if edge_table.has_key((A, D)): + edge_table[(A, D)][1] = i + edge_table[(A, D)][4] = c + edge_table[(A, D)][5] = a + if has_vertex_colors(mesh): edge_table[(A, D)][8] = Acol + else: + if has_vertex_colors(mesh): + edge_table[(D, A)] = [i, None, c, a, None, None, None, Acol, None] + else: + edge_table[(D, A)] = [i, None, c, a, None, None, None] + +# ==================================== +# === Generate Entry From Triangle === +# ==================================== +def generate_entry_from_tri(mesh, i, edge_table): + vertex3, vertex2, vertex1 = mesh.faces[i].v + + if has_vertex_colors(mesh): + vcolor3, vcolor2, vcolor1, _vcolor4_ = mesh.faces[i].col + Acol = (vcolor1.r/255.0, vcolor1.g/255.0, vcolor1.b/255.0) + Bcol = (vcolor2.r/255.0, vcolor2.g/255.0, vcolor2.b/255.0) + Ccol = (vcolor3.r/255.0, vcolor3.g/255.0, vcolor3.b/255.0) + + # === verts are upper case, edges are lower case === + A, B, C = vertex1.index, vertex2.index, vertex3.index + a, b, c = (A, B), (B, C), (C, A) + + if edge_table.has_key((B, A)): + edge_table[(B, A)][1] = i + edge_table[(B, A)][4] = c + edge_table[(B, A)][5] = b + if has_vertex_colors(mesh): edge_table[(B, A)][8] = Bcol + else: + if has_vertex_colors(mesh): + edge_table[(A, B)] = [i, None, c, b, None, None, None, Bcol, None] + else: + edge_table[(A, B)] = [i, None, c, b, None, None, None] + + if edge_table.has_key((C, B)): + edge_table[(C, B)][1] = i + edge_table[(C, B)][4] = a + edge_table[(C, B)][5] = c + if has_vertex_colors(mesh): edge_table[(C, B)][8] = Ccol + else: + if has_vertex_colors(mesh): + edge_table[(B, C)] = [i, None, a, c, None, None, None, Ccol, None] + else: + edge_table[(B, C)] = [i, None, a, c, None, None, None] + + if edge_table.has_key((A, C)): + edge_table[(A, C)][1] = i + edge_table[(A, C)][4] = b + edge_table[(A, C)][5] = a + if has_vertex_colors(mesh): edge_table[(A, C)][8] = Acol + else: + if has_vertex_colors(mesh): + edge_table[(C, A)] = [i, None, b, a, None, None, None, Acol, None] + else: + edge_table[(C, A)] = [i, None, b, a, None, None, None] + diff --git a/release/scripts/bpymodules/paths_ai2obj.py b/release/scripts/bpymodules/paths_ai2obj.py new file mode 100644 index 00000000000..dcf56853184 --- /dev/null +++ b/release/scripts/bpymodules/paths_ai2obj.py @@ -0,0 +1,502 @@ +""" +paths_ai2obj.py +# --------------------------------------------------------------- +Copyright (c) jm soler juillet/novembre 2004-april 2007, +# --------------------------------------------------------------- + released under GNU Licence + for the Blender 2.45 Python Scripts Bundle. +Ce programme est libre, vous pouvez le redistribuer et/ou +le modifier selon les termes de la Licence Publique Générale GNU +publiée par la Free Software Foundation (version 2 ou bien toute +autre version ultérieure choisie par vous). + +Ce programme est distribué car potentiellement utile, mais SANS +AUCUNE GARANTIE, ni explicite ni implicite, y compris les garanties +de commercialisation ou d'adaptation dans un but spécifique. +Reportez-vous à la Licence Publique Générale GNU pour plus de détails. + +Vous devez avoir reçu une copie de la Licence Publique Générale GNU +en même temps que ce programme ; si ce n'est pas le cas, écrivez à la +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +MA 02111-1307, États-Unis. + + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# --------------------------------------------------------------- +#---------------------------------------------- +# +# Page officielle : +# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_ai_en.htm +# Communiquer les problemes et erreurs sur: +# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender +#---------------------------------------------- +#---------------------------------------------- +#Chagelog +#---------------------------------------------- +# 0.1.1 : 2004/08/03, bug in boudingbox reading when Value are negative +# 0.1.2 : 2005/06/12, gmove tranformation properties +# 0.1.3 : 2005/06/25, added a __name__ test to use the script alone +# 0.1.4 : 2005/06/25, closepath improvements +# 0.1.5 : 2005/06/25, ... +# 0.1.6 : 2005/06/26, warning for compacted file + compatibility increased up to AI 10.0 plain text +# 0.1.7 : 2005/06/25, two more closepath improvements +# +# 0.1.8 : 2006/07/03, two more closepath improvements +# 0.1.9 : 2007/05/06, modif on the method that gets the last object on + the list data +""" +SHARP_IMPORT=0 +SCALE=1 +NOTHING_TODO=1 +AI_VERSION='' + +GSTACK = [] +GSCALE = [] +GTRANSLATE = [] + +import sys +#oldpath=sys.path +import Blender +BLversion=Blender.Get('version') + +try: + import nt + os=nt + os.sep='\\' + +except: + import posix + os=posix + os.sep='/' + +def isdir(path): + try: + st = os.stat(path) + return 1 + except: + return 0 + +def split(pathname): + if pathname.find(os.sep)!=-1: + k0=pathname.split(os.sep) + else: + if os.sep=='/': + k0=pathname.split('\\') + else: + k0=pathname.split('/') + + directory=pathname.replace(k0[len(k0)-1],'') + Name=k0[len(k0)-1] + return directory, Name + +def join(l0,l1): + return l0+os.sep+l1 + +os.isdir=isdir +os.split=split +os.join=join + +def filtreFICHIER(nom): + f=open(nom,'rU') + t=f.readlines() + f.close() + + if len(t)>1 and t[0].find('EPSF')==-1: + return t + else: + name = "OK?%t| Not a valid file or an empty file ... " # if no %xN int is set, indices start from 1 + result = Blender.Draw.PupMenu(name) + + return 'false' + +#=============================== +# Data +#=============================== +#=============================== +# Blender Curve Data +#=============================== +objBEZIER=0 +objSURFACE=5 +typBEZIER3D=1 #3D +typBEZIER2D=9 #2D + +class Bez: + def __init__(self): + self.co=[] + self.ha=[0,0] + self.tag='' + +class ITEM: + def __init__(self): + self.type = typBEZIER3D, + self.pntsUV = [0,0] + self.resolUV = [32,0] + self.orderUV = [0,0] + self.flagUV = [0,0] + self.Origine = [0.0,0.0] + self.beziers_knot = [] + +class COURBE: + def __init__(self): + self.magic_number='3DG3' + self.type = objBEZIER + self.number_of_items = 0 + self.ext1_ext2 = [0,0] + self.matrix = """0.0 0.0 1.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 1.0 """ + self.ITEM = {} + +courbes=COURBE() + +PATTERN={} + +BOUNDINGBOX={'rec':[],'coef':1.0} +npat=0 +#===================================================================== +#======== name of the curve in teh courbes dictionnary =============== +#===================================================================== +n0=0 + +#===================================================================== +#====================== current Point ================================ +#===================================================================== +CP=[0.0,0.0] #currentPoint + + +# modifs 12/06/2005 +#===================================================================== +#====================== current transform ============================ +#===================================================================== +class transform: + def __init__(self,matrix=[1,0,01],x=0.0,y=0.0): + self.matrix=matrix[:] + self.xy=[x,y] + +def G_move(l,a): + global GSCALE, GTRANSLATE, GSTACK + #print GSCALE, GTRANSLATE, GSTACK + return str((float(l)+GTRANSLATE[a]+GSTACK[-1].xy[a])*GSCALE[a]) +# modifs 12/06/2005 + + +#===================================================================== +#===== to compare last position to the original move to displacement = +#===== needed for cyclic efinition ================================= +#===================================================================== +def test_egalitedespositions(f1,f2): + if f1[0]==f2[0] and f1[1]==f2[1]: + return Blender.TRUE + else: + return Blender.FALSE + + +def Open_GEOfile(dir,nom): + if BLversion>=233: + in_editmode = Blender.Window.EditMode() + if in_editmode: Blender.Window.EditMode(0) + Blender.Load(dir+nom+'OOO.obj', 1) + BO=Blender.Scene.GetCurrent().objects.active + BO.RotY=0.0 + BO.RotX=1.57 + BO.makeDisplayList() + Blender.Window.RedrawAll() + else: + print "Not yet implemented" + +def create_GEOtext(courbes): + global SCALE, B, BOUNDINGBOX + r=BOUNDINGBOX['rec'] + + if SCALE==1: + SCALE=1.0 + elif SCALE==2: + SCALE=r[2]-r[0] + elif SCALE==3: + SCALE=r[3]-r[1] + + t=[] + t.append(courbes.magic_number+'\n') + t.append(str(courbes.type)+'\n') + t.append(str(courbes.number_of_items)+'\n') + t.append(str(courbes.ext1_ext2[0])+' '+str(courbes.ext1_ext2[1])+'\n') + t.append(courbes.matrix+'\n') + + for k in courbes.ITEM.keys(): + if len(courbes.ITEM[k].beziers_knot)>1 : + t.append("%s\n"%courbes.ITEM[k].type) + t.append("%s %s \n"%(courbes.ITEM[k].pntsUV[0],courbes.ITEM[k].pntsUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].resolUV[0],courbes.ITEM[k].resolUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].orderUV[0],courbes.ITEM[k].orderUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].flagUV[0],courbes.ITEM[k].flagUV[1])) + + flag =courbes.ITEM[k].flagUV[0] + + for k2 in range(len(courbes.ITEM[k].beziers_knot)): + #print k2 + k1 =courbes.ITEM[k].beziers_knot[k2] + t.append("%4f 0.0 %4f \n"%(float(k1.co[2])/SCALE,float(k1.co[3])/SCALE)) + t.append("%4f 0.0 %4f \n"%(float(k1.co[4])/SCALE,float(k1.co[5])/SCALE)) + t.append("%4f 0.0 %4f \n"%(float(k1.co[0])/SCALE,float(k1.co[1])/SCALE)) + + t.append(str(k1.ha[0])+' '+str(k1.ha[1])+'\n') + return t + +def save_GEOfile(dir,nom,t): + f=open(dir+nom+'OOO.obj','w') + f.writelines(t) + f.close() + #warning = "REMINDER : %t | Do not forget to rename your blender file NOW ! %x1" + #result = Blender.Draw.PupMenu(warning) + + +#===================================================================== +#===== AI format : DEBUT ========================= +#===================================================================== +def mouvement_vers(l,n0,CP): + if n0 in courbes.ITEM.keys(): + n0+=1 + + CP=[l[-3].replace('d',''),l[-2]] + courbes.ITEM[n0]=ITEM() + courbes.ITEM[n0].Origine=[l[-3].replace('d',''),l[-2]] + + B=Bez() + B.co=[CP[0],CP[1],CP[0],CP[1],CP[0],CP[1]] + B.ha=[0,0] + B.tag=l[-1] + + courbes.ITEM[n0].beziers_knot.append(B) + + return courbes,n0,CP + +def courbe_vers_c(l,l2, n0,CP): #c,C + + B=Bez() + B.co=[l[4],l[5],l[2],l[3],l[4],l[5]] + B.tag=l[-1] + B.ha=[0,0] + + BP=courbes.ITEM[n0].beziers_knot[-1] + + BP.co[0]=l[0] + BP.co[1]=l[1] + + courbes.ITEM[n0].beziers_knot.append(B) + + CP=[B.co[4],B.co[5]] + return courbes,n0,CP + + +def courbe_vers_v(l,n0,CP): #v-V + + B=Bez() + B.tag=l[-1] + B.co=[l[2],l[3],l[0],l[1],l[2],l[3]] + B.ha=[0,0] + + courbes.ITEM[n0].beziers_knot.append(B) + + CP=[B.co[4],B.co[5]] + return courbes,n0,CP + +def courbe_vers_y(l,n0,CP): #y + B=Bez() + B.tag=l[-1] + B.co=[l[2],l[3],l[2],l[3],l[2],l[3]] + B.ha=[0,0] + + BP=courbes.ITEM[n0].beziers_knot[-1] + BP.co[0]=l[0] + BP.co[1]=l[1] + + courbes.ITEM[n0].beziers_knot.append(B) + CP=[B.co[4],B.co[5]] + return courbes,n0,CP + + +def ligne_tracee_l(l,n0,CP): + B=Bez() + B.tag=l[-1] + B.co=[l[0],l[1],l[0],l[1],l[0],l[1]] + B.ha=[0,0] + + BP=courbes.ITEM[n0].beziers_knot[-1] + + courbes.ITEM[n0].beziers_knot.append(B) + CP=[B.co[4],B.co[5]] + return courbes,n0,CP + +def ligne_fermee(l,n0,CP): + courbes.ITEM[n0].flagUV[0]=1 + + if len(courbes.ITEM[n0].beziers_knot)>1: + BP=courbes.ITEM[n0].beziers_knot[-1] + BP0=courbes.ITEM[n0].beziers_knot[0] + + if BP.tag not in ['l','L']: + BP.co[0]=BP0.co[0] #4-5 point prec + BP.co[1]=BP0.co[1] + + del courbes.ITEM[n0].beziers_knot[0] + return courbes,n0,CP + +def passe(l,n0,CP): + return courbes,n0,CP + +Actions= { "C" : courbe_vers_c, + "c" : courbe_vers_c, + "V" : courbe_vers_v, + "v" : courbe_vers_v, + "Y" : courbe_vers_y, + "y" : courbe_vers_y, + "m" : mouvement_vers, + "l" : ligne_tracee_l, + "L" : ligne_tracee_l, + "F" : passe, + "f" : ligne_fermee, + "B" : passe, + "b" : ligne_fermee, + "S" : passe, + "s" : ligne_fermee, + "N" : ligne_fermee, + "n" : passe, + } + +TAGcourbe=Actions.keys() + +def pik_pattern(t,l): + global npat, PATTERN, BOUNDINGBOX, AI_VERSION + while t[l].find('%%EndSetup')!=0: + if t[l].find('%%Creator: Adobe Illustrator(R)')!=-1: + print t[l] + AI_VERSION=t[l].split()[-1] + print AI_VERSION + + if t[l].find('%%BoundingBox:')!=-1: + t[l]=t[l][t[l].find(':')+1:] + l0=t[l].split() + BOUNDINGBOX['rec']=[float(l0[-4]),float(l0[-3]),float(l0[-2]),float(l0[-1])] + r=BOUNDINGBOX['rec'] + BOUNDINGBOX['coef']=(r[3]-r[1])/(r[2]-r[0]) + #print l, + if t[l].find('BeginPattern')!=-1: + nomPattern=t[l][t[l].find('(')+1:t[l].find(')')] + PATTERN[nomPattern]={} + + if t[l].find('BeginPatternLayer')!=-1: + npat+=1 + PATTERN[nomPattern][npat]=[] + while t[l].find('EndPatternLayer')==-1: + #print t[l] + PATTERN[nomPattern][npat].append(l) + l+=1 + if l+10: + if len(PATTERN.keys() )>0: + #print len(PATTERN.keys() ) + warning = "Pattern list (for info not used): %t| " + p0=1 + for P in PATTERN.keys(): + warning+="%s %%x%s|"%(P,p0) + p0+=1 + Padd = Blender.Draw.PupMenu(warning) + + t=create_GEOtext(courbes) + save_GEOfile(dir,name[0],t) + + # 0.1.8 --------------------------------- + # [O.select(0) for O in Blender.Scene.getCurrent().getChildren()] + # 0.1.8 --------------------------------- + + Open_GEOfile(dir,name[0]) + + # 0.1.8 --------------------------------- + Blender.Object.Get()[-1].setName(name[0]) + # 0.1.8 --------------------------------- + + else: + pass +#===================================================================== +#====================== AI format mouvements ========================= +#===================================================================== +#========================================================= +# une sorte de contournement qui permet d'utiliser la fonction +# et de documenter les variables Window.FileSelector +#========================================================= +def fonctionSELECT(nom): + global NOTHING_TODO,AI_VERSION + scan_FILE(nom) + if NOTHING_TODO==1: + warning = "AI %s compatible file "%AI_VERSION+" but nothing to do ? %t| Perhaps a compacted file ... " + NOTHING = Blender.Draw.PupMenu(warning) + +if __name__=="__main__": + Blender.Window.FileSelector (fonctionSELECT, 'SELECT AI FILE') +#sys.path=oldpath diff --git a/release/scripts/bpymodules/paths_eps2obj.py b/release/scripts/bpymodules/paths_eps2obj.py new file mode 100644 index 00000000000..e1643c3bf40 --- /dev/null +++ b/release/scripts/bpymodules/paths_eps2obj.py @@ -0,0 +1,452 @@ +#---------------------------------------------- +# (c) jm soler juillet 2004-juin 2005 , released under Blender Artistic Licence +# for the Blender 2.34-2.37 Python Scripts Bundle. +# +# last update: 06/05/2007 +#---------------------------------------------- +# Page officielle : +# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_eps.htm +# Communiquer les problemes et erreurs sur: +# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender +#---------------------------------------------- +SHARP_IMPORT = 0 +SCALE = 1.0 +scale = 1 + +import sys +#oldpath=sys.path + +import Blender +from Blender import Draw +BLversion=Blender.Get('version') + +try: + import nt + os=nt + os.sep='\\' + +except: + import posix + os=posix + os.sep='/' + +def isdir(path): + try: + st = os.stat(path) + return 1 + except: + return 0 + +def split(pathname): + if pathname.find(os.sep)!=-1: + k0=pathname.split(os.sep) + else: + if os.sep=='/': + k0=pathname.split('\\') + else: + k0=pathname.split('/') + + directory=pathname.replace(k0[len(k0)-1],'') + Name=k0[len(k0)-1] + return directory, Name + +def join(l0,l1): + return l0+os.sep+l1 + +os.isdir=isdir +os.split=split +os.join=join + +def filtreFICHIER(nom): + f=open(nom,'rU') + t=f.readlines() + f.close() + if len(t)==1 and t[0].find('\r'): + t=t[0].split('\r') + if len(t)>1 and t[0].find('PS-Adobe-3.0')==-1 and t[0].find('EPSF')==-1: + return t + else: + name = "OK?%t| Not a valid file or an empty file or... %x1| not a pure PS-Adobe-2.0 file %x2 " + result = Blender.Draw.PupMenu(name) + return 'false' + +#=============================== +# Data +#=============================== +#=============================== +# Blender Curve Data +#=============================== +objBEZIER=0 +objSURFACE=5 +typBEZIER3D=1 #3D +typBEZIER2D=9 #2D + +class Bez: + def __init__(self): + self.co=[] + self.ha=[0,0] + +class ITEM: + def __init__(self): + self.type = typBEZIER3D, + self.pntsUV = [0,0] + self.resolUV = [32,0] + self.orderUV = [0,0] + self.flagUV = [0,0] + self.Origine = [0.0,0.0] + self.beziers_knot = [] + +class COURBE: + def __init__(self): + self.magic_number='3DG3' + self.type = objBEZIER + self.number_of_items = 0 + self.ext1_ext2 = [0,0] + self.matrix = """0.0 0.0 1.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 1.0 """ #- right-handed object matrix. Used to determine position, rotation and size + self.ITEM = {} + +courbes=COURBE() +PATTERN={} +BOUNDINGBOX={'rec':[],'coef':1.0} +npat=0 +#===================================================================== +#======== name of the curve in teh courbes dictionnary =============== +#===================================================================== +n0=0 + +#===================================================================== +#====================== current Point ================================ +#===================================================================== +CP=[0.0,0.0] #currentPoint + +# modifs 12/06/2005 +#===================================================================== +#====================== current transform ============================ +#===================================================================== +class transform: + def __init__(self,matrix=[1,0,01],x=0.0,y=0.0): + self.matrix=matrix[:] + self.xy=[x,y] + +GSTACK = [] +stack=transform() +GSTACK.append(stack) + +GSCALE = [1.0,1.0] +GTRANSLATE = [0.0,0.0] + +def G_move(l,a): + global GSCALE, GTRANSLATE, GSTACK + #print GSCALE, GTRANSLATE, GSTACK + return str((float(l)+GTRANSLATE[a]+GSTACK[-1].xy[a])*GSCALE[a]) +# modifs 12/06/2005 + +#===================================================================== +#===== to compare last position to the original move to displacement = +#===== needed for cyclic efinition ================================= +#===================================================================== +def test_egalitedespositions(f1,f2): + if f1[0]==f2[0] and f1[1]==f2[1]: + return Blender.TRUE + else: + return Blender.FALSE + + +def Open_GEOfile(dir,nom): + global SCALE,BOUNDINGBOX, scale + if BLversion>=233: + Blender.Load(dir+nom+'OOO.obj', 1) + BO=Blender.Scene.GetCurrent().objects.active + BO.RotY=3.1416 + BO.RotZ=3.1416 + BO.RotX=3.1416/2.0 + if scale==1: + BO.LocY+=BOUNDINGBOX['rec'][3] + else: + BO.LocY+=BOUNDINGBOX['rec'][3]/SCALE + + BO.makeDisplayList() + Blender.Window.RedrawAll() + else: + print "Not yet implemented" + +def create_GEOtext(courbes): + global SCALE, B, BOUNDINGBOX,scale + r=BOUNDINGBOX['rec'] + + if scale==1: + SCALE=1.0 + elif scale==2: + SCALE=r[2]-r[0] + elif scale==3: + SCALE=r[3]-r[1] + + t=[] + t.append(courbes.magic_number+'\n') + t.append(str(courbes.type)+'\n') + t.append(str(courbes.number_of_items)+'\n') + t.append(str(courbes.ext1_ext2[0])+' '+str(courbes.ext1_ext2[1])+'\n') + t.append(courbes.matrix+'\n') + + for k in courbes.ITEM.keys(): + t.append("%s\n"%courbes.ITEM[k].type) + t.append("%s %s \n"%(courbes.ITEM[k].pntsUV[0],courbes.ITEM[k].pntsUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].resolUV[0],courbes.ITEM[k].resolUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].orderUV[0],courbes.ITEM[k].orderUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].flagUV[0],courbes.ITEM[k].flagUV[1])) + + flag =courbes.ITEM[k].flagUV[0] + + for k2 in range(flag,len(courbes.ITEM[k].beziers_knot)): + k1 =courbes.ITEM[k].beziers_knot[k2] + t.append("%4f 0.0 %4f \n"%(float(k1.co[0])/SCALE,float(k1.co[1])/SCALE)) + t.append("%4f 0.0 %4f \n"%(float(k1.co[2])/SCALE,float(k1.co[3])/SCALE)) + t.append("%4f 0.0 %4f \n"%(float(k1.co[4])/SCALE,float(k1.co[5])/SCALE)) + t.append(str(k1.ha[0])+' '+str(k1.ha[1])+'\n') + return t + +def save_GEOfile(dir,nom,t): + f=open(dir+nom+'OOO.obj','w') + f.writelines(t) + f.close() + + #name = "REMINDER : %t | Do not forget to rename your blender file NOW ! %x1" + #result = Blender.Draw.PupMenu(name) + + +#===================================================================== +#===== EPS format : DEBUT ========================= +#===================================================================== +def mouvement_vers(l,n0,CP): + if n0 in courbes.ITEM.keys(): + #if test_egalitedespositions(courbes.ITEM[n0].Origine,CP): + # courbes.ITEM[n0].flagUV[0]=1 + n0+=1 + CP=[l[-3].replace('d',''),l[-2]] + else: + CP=[l[-3].replace('d',''),l[-2]] + #i= + courbes.ITEM[n0]=ITEM() + courbes.ITEM[n0].Origine=[l[-3].replace('d',''),l[-2]] + + B=Bez() + B.co=[G_move(CP[0],0), + G_move(CP[1],1), + G_move(CP[0],0), + G_move(CP[1],1), + G_move(CP[0],0), + G_move(CP[1],1)] + + B.ha=[0,0] + courbes.ITEM[n0].beziers_knot.append(B) + + return courbes,n0,CP + +def rmouvement_vers(l,n0,CP): + if n0 in courbes.ITEM.keys(): + #if test_egalitedespositions(courbes.ITEM[n0].Origine,CP): + # courbes.ITEM[n0].flagUV[0]=1 + n0+=1 + CP=["%4f"%(float(l[-3])+float(CP[0])),"%4f"%(float(l[-2])+float(CP[1]))] + else: + CP=["%4f"%(float(l[-3])+float(CP[0])),"%4f"%(float(l[-2])+float(CP[1]))] + #i= + courbes.ITEM[n0]=ITEM() + courbes.ITEM[n0].Origine=[l[-3].replace('d',''),l[-2]] + + B=Bez() + B.co=[CP[0],CP[1],CP[0],CP[1],CP[0],CP[1]] + B.ha=[0,0] + courbes.ITEM[n0].beziers_knot.append(B) + return courbes,n0,CP + +def courbe_vers_c(l, l2, n0,CP): #c,C + """ + B=Bez() + B.co=[l[0],l[1],l[2],l[3],l[4],l[5]] + B.ha=[0,0] + + courbes.ITEM[n0].beziers_knot.append(B) + """ + B=Bez() + B.co=[G_move(l[2],0), + G_move(l[3],1), + G_move(l[4],0), + G_move(l[5],1), + G_move(l[0],0), + G_move(l[1],1)] + if len(courbes.ITEM[n0].beziers_knot)==1: + CP=[l[0],l[1]] + courbes.ITEM[n0].Origine=[l[0],l[1]] + if l[-1]=='C': + B.ha=[2,2] + else: + B.ha=[0,0] + courbes.ITEM[n0].beziers_knot.append(B) + if len(l2)>1 and l2[-1] in Actions.keys(): + B.co[-2]=G_move(l2[0],0) + B.co[-1]=G_move(l2[1],1) + else: + B.co[-2]=G_move(CP[0],0) + B.co[-1]=G_move(CP[1],1) + return courbes,n0,CP + +def ligne_tracee_l(l,n0,CP): + B=Bez() + B.co=[G_move(l[0],0), + G_move(l[1],1), + G_move(l[0],0), + G_move(l[1],1), + G_move(l[0],0), + G_move(l[1],1)] + B.ha=[0,0] + courbes.ITEM[n0].beziers_knot.append(B) + CP=[l[0],l[1]] + return courbes,n0,CP + +def rligne_tracee_l(l,n0,CP): + B=Bez() + B.co=["%4f"%(float(l[0])+float(CP[0])), + "%4f"%(float(l[1])+float(CP[1])), + "%4f"%(float(l[0])+float(CP[0])), + "%4f"%(float(l[1])+float(CP[1])), + "%4f"%(float(l[0])+float(CP[0])), + "%4f"%(float(l[1])+float(CP[1]))] + B.ha=[0,0] + courbes.ITEM[n0].beziers_knot.append(B) + CP=[l[0],l[1]] + return courbes,n0,CP + +Actions= { "curveto" : courbe_vers_c, + "curveto" : courbe_vers_c, + "moveto" : mouvement_vers, + "rmoveto" : mouvement_vers, + "lineto" : ligne_tracee_l, + "rlineto" : rligne_tracee_l +} + +TAGcourbe=Actions.keys() + +""" +def pik_pattern(t,l): + global npat, PATTERN, BOUNDINGBOX + while t[l].find('%%EndSetup')!=0: + if t[l].find('%%BoundingBox:')!=-1: + l0=t[l].split() + BOUNDINGBOX['rec']=[float(l0[-4]),float(l0[-3]),float(l0[-2]),float(l0[-1])] + r=BOUNDINGBOX['rec'] + BOUNDINGBOX['coef']=(r[3]-r[1])/(r[2]-r[0]) + print l, + if t[l].find('BeginPatternLayer')!=-1: + npat+=1 + PATTERN[npat]=[] + while t[l].find('EndPatternLayer')==-1: + print t[l] + PATTERN[npat].append(l) + l+=1 + if l+10: + if len(PATTERN.keys() )>0: + #print len(PATTERN.keys() ) + pass + t=create_GEOtext(courbes) + save_GEOfile(dir,name[0],t) + Open_GEOfile(dir,name[0]) + + # 03 juillet 2006 ---------------------- + Blender.Object.Get()[-1].setName(name[0]) + # 03 juillet 2006 ---------------------- + + else: + pass + + +#===================================================================== +#====================== EPS format mouvements ========================= +#===================================================================== +#========================================================= +# une sorte de contournement qui permet d'utiliser la fonction +# et de documenter les variables Window.FileSelector +#========================================================= +def fonctionSELECT(nom): + scan_FILE(nom) + +if __name__=="__main__": + Blender.Window.FileSelector (fonctionSELECT, 'SELECT EPS FILE') + + diff --git a/release/scripts/bpymodules/paths_gimp2obj.py b/release/scripts/bpymodules/paths_gimp2obj.py new file mode 100644 index 00000000000..8b31c5d7294 --- /dev/null +++ b/release/scripts/bpymodules/paths_gimp2obj.py @@ -0,0 +1,359 @@ +""" +#---------------------------------------------- +# (c) jm soler juillet 2004, +#---------------------------------------------- + released under GNU Licence + for the Blender 2.45 Python Scripts Bundle. +Ce programme est libre, vous pouvez le redistribuer et/ou +le modifier selon les termes de la Licence Publique Générale GNU +publiée par la Free Software Foundation (version 2 ou bien toute +autre version ultérieure choisie par vous). + +Ce programme est distribué car potentiellement utile, mais SANS +AUCUNE GARANTIE, ni explicite ni implicite, y compris les garanties +de commercialisation ou d'adaptation dans un but spécifique. +Reportez-vous à la Licence Publique Générale GNU pour plus de détails. + +Vous devez avoir reçu une copie de la Licence Publique Générale GNU +en même temps que ce programme ; si ce n'est pas le cas, écrivez à la +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +MA 02111-1307, États-Unis. + + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +""" + +# --------------------------------------------------------------- +# last update : 07/05/2007 +#---------------------------------------------- +# Page officielle : +# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_gimp.htm +# Communiquer les problemes et erreurs sur: +# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender +#--------------------------------------------- + +SHARP_IMPORT=0 +SCALE=1 + +import sys +#oldpath=sys.path + +import Blender +BLversion=Blender.Get('version') + +try: + import nt + os=nt + os.sep='\\' + +except: + import posix + os=posix + os.sep='/' + +def isdir(path): + try: + st = os.stat(path) + return 1 + except: + return 0 + +def split(pathname): + if pathname.find(os.sep)!=-1: + k0=pathname.split(os.sep) + else: + if os.sep=='/': + k0=pathname.split('\\') + else: + k0=pathname.split('/') + + directory=pathname.replace(k0[len(k0)-1],'') + Name=k0[len(k0)-1] + return directory, Name + +def join(l0,l1): + return l0+os.sep+l1 + +os.isdir=isdir +os.split=split +os.join=join + +def filtreFICHIER(nom): + f=open(nom,'r') + t=f.readlines() + f.close() + if len(t)==1 and t[0].find('\r'): + t=t[0].split('\r') + if len(t)>1 and t[1].find('#POINTS:')==0: + return t + else: + warning = "OK?%t| Not a valid file or an empty file ... " # if no %xN int is set, indices start from 1 + result = Blender.Draw.PupMenu(warning) + return "false" + +#=============================== +# Data +#=============================== +#=============================== +# Blender Curve Data +#=============================== +objBEZIER=0 +objSURFACE=5 +typBEZIER3D=1 #3D +typBEZIER2D=9 #2D + +class Bez: + def __init__(self): + self.co=[] + self.ha=[0,0] + + def echo(self): + #print 'co = ', self.co + #print 'ha = ', self.ha + pass + +class ITEM: + def __init__(self): + self.type = typBEZIER3D, + self.pntsUV = [0,0] + self.resolUV = [32,0] + self.orderUV = [0,0] + self.flagUV = [0,0] + self.Origine = [0.0,0.0] + self.beziers_knot = [] + +class COURBE: + def __init__(self): + self.magic_number='3DG3' + self.type = objBEZIER + self.number_of_items = 0 + self.ext1_ext2 = [0,0] + self.matrix = """0.0 0.0 1.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 1.0 """ #- right-handed object matrix. Used to determine position, rotation and size + self.ITEM = {} + +courbes=COURBE() +PATTERN={} +BOUNDINGBOX={'rec':[],'coef':1.0} +npat=0 +#===================================================================== +#======== name of the curve in the courbes dictionnary =============== +#===================================================================== +n0=0 + +#===================================================================== +#====================== current Point ================================ +#===================================================================== +CP=[0.0,0.0] #currentPoint + +def MINMAX(b): + global BOUNDINGBOX + r=BOUNDINGBOX['rec'] + for m in range(0,len(b)-2,2): + #print m, m+1 , len(b)-1 + #print b[m], r, r[0] + if float(b[m])r[2]: r[2]=float(b[m]) + + if float(b[m+1])r[3]: r[3]=float(b[m+1]) + +#===================================================================== +#===== to compare last position to the original move to displacement = +#===== needed for cyclic efinition ================================= +#===================================================================== +def test_egalitedespositions(f1,f2): + if f1[0]==f2[0] and f1[1]==f2[1]: + return Blender.TRUE + else: + return Blender.FALSE + + +def Open_GEOfile(dir,nom): + if BLversion>=233: + Blender.Load(dir+nom+'OOO.obj', 1) + BO=Blender.Scene.GetCurrent().objects.active + BO.LocZ=1.0 + BO.makeDisplayList() + Blender.Window.RedrawAll() + else: + print "Not yet implemented" + +def create_GEOtext(courbes): + global SCALE, B, BOUNDINGBOX + r=BOUNDINGBOX['rec'] + if SCALE==1: + SCALE=1.0 + elif SCALE==2: + SCALE=r[2]-r[0] + elif SCALE==3: + SCALE=r[3]-r[1] + + t=[] + t.append(courbes.magic_number+'\n') + t.append(str(courbes.type)+'\n') + t.append(str(courbes.number_of_items)+'\n') + t.append(str(courbes.ext1_ext2[0])+' '+str(courbes.ext1_ext2[1])+'\n') + t.append(courbes.matrix+'\n') + + for k in courbes.ITEM.keys(): + + t.append("%s\n"%courbes.ITEM[k].type) + + t.append("%s %s \n"%(courbes.ITEM[k].pntsUV[0],courbes.ITEM[k].pntsUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].resolUV[0],courbes.ITEM[k].resolUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].orderUV[0],courbes.ITEM[k].orderUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].flagUV[0],courbes.ITEM[k].flagUV[1])) + + flag =0#courbes.ITEM[k].flagUV[0] + + for k2 in range(flag,len(courbes.ITEM[k].beziers_knot)): + k1 =courbes.ITEM[k].beziers_knot[k2] + t.append("%4f 0.0 %4f \n"%(float(k1.co[0])/SCALE,float(k1.co[1])/SCALE)) + t.append("%4f 0.0 %4f \n"%(float(k1.co[4])/SCALE,float(k1.co[5])/SCALE)) + t.append("%4f 0.0 %4f \n"%(float(k1.co[2])/SCALE,float(k1.co[3])/SCALE)) + t.append(str(k1.ha[0])+' '+str(k1.ha[1])+'\n') + return t + +def save_GEOfile(dir,nom,t): + f=open(dir+nom+'OOO.obj','w') + f.writelines(t) + f.close() + #warning = "REMINDER : %t | Do not forget to rename your blender file NOW ! %x1" + #result = Blender.Draw.PupMenu(warning) + + +#===================================================================== +#===== GIMP format : DEBUT ========================= +#===================================================================== +CLOSED=0 + +def mouvement_vers(l,l1,l2,n0): + global BOUNDINGBOX, CP + if l[1] == '3' : + n0+=1 + courbes.ITEM[n0]=ITEM() + courbes.ITEM[n0].Origine=[l[-3],l[-1],] + courbes.ITEM[n0-1].beziers_knot[0].co[0]=CP[0] + courbes.ITEM[n0-1].beziers_knot[0].co[1]=CP[1] + CP=[l2[-3], l2[-1]] + + elif l[1]=='1' and (n0 not in courbes.ITEM.keys()): + courbes.ITEM[n0]=ITEM() + courbes.ITEM[n0].Origine=[l[-3],l[-1],] + CP=[l2[-3], l2[-1]] + + B=Bez() + B.co=[ CP[0],CP[1], + l1[-3], l1[-1], + l[-3], l[-1]] + + CP=[l2[-3], l2[-1]] + + if BOUNDINGBOX['rec']==[]: + BOUNDINGBOX['rec']=[float(l2[-3]), float(l2[-1]), float(l[-3]), float(l[-1])] + B.ha=[0,0] + + """ + if len( courbes.ITEM[n0].beziers_knot)>=1: + courbes.ITEM[n0].beziers_knot[-1].co[2]=l1[-3] + courbes.ITEM[n0].beziers_knot[-1].co[3]=l1[-1] + """ + + MINMAX(B.co) + courbes.ITEM[n0].beziers_knot.append(B) + return courbes,n0 + +Actions= { "1" : mouvement_vers, + "3" : mouvement_vers } + +TAGcourbe=Actions.keys() + +def scan_FILE(nom): + global CP, courbes, SCALE, MAX, MIN, CLOSED + dir,name=split(nom) + name=name.split('.') + #print name + n0=0 + result=0 + t=filtreFICHIER(nom) + if t!="false": + if not SHARP_IMPORT: + warning = "Select Size : %t| As is %x1 | Scale on Height %x2| Scale on Width %x3" + SCALE = Blender.Draw.PupMenu(warning) + npat=0 + l=0 + while l 0: + t=create_GEOtext(courbes) + save_GEOfile(dir,name[0],t) + Open_GEOfile(dir,name[0]) + # 0.1.8 --------------------------------- + Blender.Object.Get()[-1].setName(name[0]) + # 0.1.8 --------------------------------- + + else: + pass + +#===================================================================== +#====================== GIMP Path format mouvements ========================= +#===================================================================== +#========================================================= +# une sorte de contournement qui permet d'utiliser la fonction +# et de documenter les variables Window.FileSelector +#========================================================= +def fonctionSELECT(nom): + scan_FILE(nom) + +if __name__=="__main__": + Blender.Window.FileSelector (fonctionSELECT, 'SELECT GIMP FILE') + diff --git a/release/scripts/bpymodules/paths_svg2obj.py b/release/scripts/bpymodules/paths_svg2obj.py new file mode 100644 index 00000000000..e535af705df --- /dev/null +++ b/release/scripts/bpymodules/paths_svg2obj.py @@ -0,0 +1,1585 @@ +# -*- coding: latin-1 -*- +""" +SVG 2 OBJ translater, 0.5.9h +Copyright (c) jm soler juillet/novembre 2004-april 2007, +# --------------------------------------------------------------- + released under GNU Licence + for the Blender 2.42 Python Scripts Bundle. +Ce programme est libre, vous pouvez le redistribuer et/ou +le modifier selon les termes de la Licence Publique Générale GNU +publiée par la Free Software Foundation (version 2 ou bien toute +autre version ultérieure choisie par vous). + +Ce programme est distribué car potentiellement utile, mais SANS +AUCUNE GARANTIE, ni explicite ni implicite, y compris les garanties +de commercialisation ou d'adaptation dans un but spécifique. +Reportez-vous à la Licence Publique Générale GNU pour plus de détails. + +Vous devez avoir reçu une copie de la Licence Publique Générale GNU +en même temps que ce programme ; si ce n'est pas le cas, écrivez à la +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +MA 02111-1307, États-Unis. + + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# --------------------------------------------------------------- + +#--------------------------------------------------------------------------- +# Page officielle : +# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_svg.htm +# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_svg_en.htm +# Communiquer les problemes et erreurs sur: +# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender +#--------------------------------------------------------------------------- + +--Old Concept : translate SVG file in GEO .obj file and try to load it. + was removed for the Blender 2.4x release. + .-- Curiousity : the original matrix must be : + | + | 0.0 0.0 1.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 1.0 + | + | and not: + | 1.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 1.0 + | + '-- Possible bug : sometime, the new curves object's RotY value + jumps to -90.0 degrees without any reason. + +--Options : + SHARP_IMPORT = 0 + choise between "As is", "Devide by height" and "Devide by width" + SHARP_IMPORT = 1 + no choise + + + +All commands are managed: + M : absolute move to + Z : close path + L : absolute line to + C : absolute curve to + S : absolute curve to with only one handle + H : absolute horizontal line to + V : absolute vertical line to + + l : relative line to 2004/08/03 + c : relative curve to 2004/08/03 + s : relative curve to with only one handle + h : relative horizontal line to + v : relative vertical line to + + A : curve_to_a, + V : draw_line_v, + H : draw_line_h, + Z : close_z, + Q : curve_to_q, + T : curve_to_t, + a : curve_to_a, + v : draw_line_v, + h : draw_line_h, + z : close_z, + q : curve_to_q, + + transfrom for tag + transform for tag + +The circle, rectangle closed or open polygons lines are managed too. + +Changelog: + 0.1.1 : - control file without extension + 0.2.0 : - improved reading of several data of the same type + following the same command (for gimp import) + 0.2.1 : - better choice for viewboxing ( takes the viewbox if found, + instead of x,y,width and height + 0.2.2 : - read compact path data from Illustrator 10 + 0.2.3 : - read a few new relative displacements + 0.2.4 : - better hash for command followed by a lone data + (h,v) or uncommun number (a) + 0.2.5 : - correction for gimp import + 0.2.6 : - correction for illustrator 10 SVG + 0.2.7 : - correction for inskape 0.40 cvs SVG + 0.2.8 : - correction for inskape plain SVG + 0.3 : - reading of the transform properties added : + translate + 0.3.1 : - compatibility restored with gimp + 0.3.2 : - transform properties added (june, 15-16): + scale, + rotate, + matrix, + skew + - added a test on __name__ to load the script + outside from the blender menu + 0.3.3 : - matrix transform content control + 0.3.4 : - paths data reading rewritten (19/06/05) + 0.3.5 : - test on empty curve (22/06/05) + - removed overlayed points + 0.3.6 : - rewriting of the bezier point contruction to correct + a problem in the connection between L type point and + C or S type point + 0.3.7 : - code correction for bezier knot in Curveto command when + the command close a path + 0.3.8 : - code was aded to manage quadratic bezier, + Q,q command and T,t commands, as a normal blender's bezier point + - The last modications does not work with gimp 2.0 svg export . + corrected too . + 0.3.9 : - Path's A,a command for ellipse's arc . + 0.4.0 : - To speed up the function filter_DATA was removed and text + variables are changed into numeric variables + 0.4.1 : - svg, groups and shapes hierarchy added + - now transform properties are computed using a stack with all + parented groups + - removed or replaced useless functions : + - skewY, skewX transforms + - radians in rotate transform + 0.4.2 : - Added functon to translate others shapes in path + rect, line, polyline, polygon + 0.4.3 : - various corrections + text font (id property exported by Adobe Illustrator are between coma) + function to code s tag has been rewritten + 0.4.4 : - various corrections + to oblige the script to understand a line feed just after + a tag . Rarely encountered problem, but it exits in a svg file + format exported by a outliner script for mesh . + 0.4.5 : - update for CVS only, at least blender 2.38 and upper + no BezTriple module in older version + added a createCURVES function to avoid to use + the OBJ format export/import . + Perhaps problems with cyclic curves . If a closed curve + does not appear closed in blender, enter edit mode select + all knot with Akey, do a Hkey to set handle type (without + this the knot are recalculated) , and finally use the Ckey + to close the curve . + Should work ... not guaranted . + 0.4.6 : - cyclic flag ... + 0.4.7 : - Management of the svgz files . the complete python or the + gzip.py file is needed . + Little improvement of the curve drawing using the createCURVES + function + 0.4.8 : - short modif for a fantasy font case in the OOo svg format + ('viewbox' is written 'viewBox', for instance) . + Note that (at this time, 2006/05/01, 1OOo exports in svg + but does not read its own export + 0.4.9 : - skipped version : private test + 0.5.0 : - the script worked perfectly with Blender 2.41 but in Blender + 2.42, use the original svg name file + 'OOO.obj' to + write a videoscape file made blender crash under window XP when + the script loaded it . Curiously, use a more simple + name with a sole 'O' solved this problem . + - script returned errors on open path : corrected + - in b2.42, several successive imports seem to be added to + the same original curve . So now the script automaticaly + renames the last group of imported curve with the original + name file . + 0.5.1 : - without join option in the internal curve creation function + 0.5.2 : - the createCURVES() function has been cleanded . Now it works + fine but all bezier curves are joined in the same curve object . + 0.5.3 : - removed two things : + 1/ the ajustement function to increase speed . 35 % faster : + 5690 curves and 30254 points in 11 seconds . User should do + a ctrl-a on the object . + 2/ the import method menu . No reason to choose between the + old extern curve creat and the new intern curve creation + this last one is largely faster . + 0.5.4 : - translation of the functions' name + improvment in the dict lookup . + Quite 15% faster . 9.75 seconds instead of 11 to load the file test . + A test was also added to find the fill style so now the script closes + these curves even if they are not defined as closed in the strict path + commands . + The old non used functions have been completely removed . + 0.5.5 : - Modifs for architect users . + 0.5.6 : - Exec was removed from the collect_ATTRIBUTS function . + Other uses was evaluated. + 0.5.7 : - Wash down of some handle problems. + + 0.5.8 : - 2007/3/9 + Wash down of the last exec and correction of a + problem with the curve's first beztriple handle + which was not recorded at first time . + - Added some units managements + - Correction of the rotate matrix + - Correction of the skew matrix + - change in the wash_DATA function suggested by cambo + - added __slot__ in class Bez, ITEM and CURVE suggested by cambo + - remove unused properties in class ITEM and CURVE + + 0.5.9 : - 2007/3/28 + - many improvements for faster and clearer code suggested by cambo and martin. + replacement of "%s" statement by str function. + - correction of an error in the scale transform management + - correction in the management of the stack transformation that rise an error + under python 2.5 but curiously not with python 2.4 + + 0.5.9a : - 2007/3/29 + - Again a lot of minors corrections + - Backward to 0.5.8 of the function that manages float numbers exported + by the Adobe Illustrator's SVG. After a lot of tests it seems that this oldest + version is also faster too . + - correction (bad) on handle management with V and H commands. + + 0.5.9b : - 2007/3/31 + - one or two minor corrections + - now the new object curve is added in the current layer. + - short modif in the scale menu... + + 0.5.9d : - 2007/4/5 + - when a svg file containts several curves they can be imported in + separate object. + - managment of paths' name when paths are imported as separate curves. + - a menu was added to select between separate or joined curves + - management of colors + + 0.5.9e : - 2007/4/7 + - corrected a scale problem that only appears when one uses beveldepth + - in separate curve option, name is also given to the curve data + - added the list of svg's color names (147) and modified the color's method + to work with. + + 0.5.9h : - 2007/5/2 + - script was updated with the modifs by cambo + - removed all debug statements + - correction of a zero division error in the calc_arc function. + +================================================================================== +==================================================================================""" +SHARP_IMPORT=0 +SCALE=1 +scale_=1 +DEBUG = 0#print +DEVELOPPEMENT=0 +TESTCOLOR=0 + +LAST_ID='' +LAST_COLOR=[0.0,0.0,0.0,0.0] +SEPARATE_CURVES=0 +USE_COLORS=0 + +SVGCOLORNAMELIST={ 'aliceblue':[240, 248, 255] ,'antiquewhite':[250, 235, 215] +,'aqua':[ 0, 255, 255], 'aquamarine':[127, 255, 212] +,'azure':[240, 255, 255], 'beige':[245, 245, 220] +,'bisque':[255, 228, 196], 'black':[ 0, 0, 0] +,'blanchedalmond':[255, 235, 205] ,'blue':[ 0, 0, 255] +,'blueviolet':[138, 43, 226],'brown':[165, 42, 42] +,'burlywood':[222, 184, 135],'cadetblue':[ 95, 158, 160] +,'chartreuse':[127, 255, 0] ,'chocolate':[210, 105, 30] +,'coral':[255, 127, 80],'cornflowerblue':[100, 149, 237] +,'cornsilk':[255, 248, 220],'crimson':[220, 20, 60] +,'cyan':[ 0, 255, 255],'darkblue':[ 0, 0, 139] +,'darkcyan':[ 0, 139, 139],'darkgoldenrod':[184, 134, 11] +,'darkgray':[169, 169, 169],'darkgreen':[ 0, 100, 0] +,'darkgrey':[169, 169, 169],'darkkhaki':[189, 183, 107] +,'darkmagenta':[139, 0, 139],'darkolivegreen':[ 85, 107, 47] +,'darkorange':[255, 140, 0],'darkorchid':[153, 50, 204] +,'darkred':[139, 0, 0],'darksalmon':[233, 150, 122] +,'darkseagreen':[143, 188, 143],'darkslateblue':[ 72, 61, 139] +,'darkslategray':[ 47, 79, 79],'darkslategrey':[ 47, 79, 79] +,'darkturquoise':[ 0, 206, 209],'darkviolet':[148, 0, 211] +,'deeppink':[255, 20, 147],'deepskyblue':[ 0, 191, 255] +,'dimgray':[105, 105, 105],'dimgrey':[105, 105, 105] +,'dodgerblue':[ 30, 144, 255],'firebrick':[178, 34, 34] +,'floralwhite':[255, 250, 240],'forestgreen':[ 34, 139, 34] +,'fuchsia':[255, 0, 255],'gainsboro':[220, 220, 220] +,'ghostwhite':[248, 248, 255],'gold':[255, 215, 0] +,'goldenrod':[218, 165, 32],'gray':[128, 128, 128] +,'grey':[128, 128, 128],'green':[ 0, 128, 0] +,'greenyellow':[173, 255, 47],'honeydew':[240, 255, 240] +,'hotpink':[255, 105, 180],'indianred':[205, 92, 92] +,'indigo':[ 75, 0, 130],'ivory':[255, 255, 240] +,'khaki':[240, 230, 140],'lavender':[230, 230, 250] +,'lavenderblush':[255, 240, 245],'lawngreen':[124, 252, 0] +,'lemonchiffon':[255, 250, 205],'lightblue':[173, 216, 230] +,'lightcoral':[240, 128, 128],'lightcyan':[224, 255, 255] +,'lightgoldenrodyellow':[250, 250, 210],'lightgray':[211, 211, 211] +,'lightgreen':[144, 238, 144],'lightgrey':[211, 211, 211] +,'lightpink':[255, 182, 193],'lightsalmon':[255, 160, 122] +,'lightseagreen':[ 32, 178, 170],'lightskyblue':[135, 206, 250] +,'lightslategray':[119, 136, 153],'lightslategrey':[119, 136, 153] +,'lightsteelblue':[176, 196, 222],'lightyellow':[255, 255, 224] +,'lime':[ 0, 255, 0],'limegreen':[ 50, 205, 50] +,'linen':[250, 240, 230],'magenta':[255, 0, 255] +,'maroon':[128, 0, 0],'mediumaquamarine':[102, 205, 170] +,'mediumblue':[ 0, 0, 205],'mediumorchid':[186, 85, 211] +,'mediumpurple':[147, 112, 219],'mediumseagreen':[ 60, 179, 113] +,'mediumslateblue':[123, 104, 238],'mediumspringgreen':[ 0, 250, 154] +,'mediumturquoise':[ 72, 209, 204],'mediumvioletred':[199, 21, 133] +,'midnightblue':[ 25, 25, 112],'mintcream':[245, 255, 250] +,'mistyrose':[255, 228, 225],'moccasin':[255, 228, 181] +,'navajowhite':[255, 222, 173],'navy':[ 0, 0, 128] +,'oldlace':[253, 245, 230],'olive':[128, 128, 0] +,'olivedrab':[107, 142, 35],'orange':[255, 165, 0] +,'orangered':[255, 69, 0],'orchid':[218, 112, 214] +,'palegoldenrod':[238, 232, 170],'palegreen':[152, 251, 152] +,'paleturquoise':[175, 238, 238],'palevioletred':[219, 112, 147] +,'papayawhip':[255, 239, 213],'peachpuff':[255, 218, 185] +,'peru':[205, 133, 63],'pink':[255, 192, 203] +,'plum':[221, 160, 221],'powderblue':[176, 224, 230] +,'purple':[128, 0, 128],'red':[255, 0, 0] +,'rosybrown':[188, 143, 143],'royalblue':[ 65, 105, 225] +,'saddlebrown':[139, 69, 19],'salmon':[250, 128, 114] +,'sandybrown':[244, 164, 96],'seagreen':[ 46, 139, 87] +,'seashell':[255, 245, 238],'sienna':[160, 82, 45] +,'silver':[192, 192, 192],'skyblue':[135, 206, 235] +,'slateblue':[106, 90, 205],'slategray':[112, 128, 144] +,'slategrey':[112, 128, 144],'snow':[255, 250, 250] +,'springgreen':[ 0, 255, 127],'steelblue':[ 70, 130, 180] +,'tan':[210, 180, 140],'teal':[ 0, 128, 128] +,'thistle':[216, 191, 216],'tomato':[255, 99, 71] +,'turquoise':[ 64, 224, 208],'violet':[238, 130, 238] +,'wheat':[245, 222, 179],'white':[255, 255, 255] +,'whitesmoke':[245, 245, 245],'yellow':[255, 255, 0] +,'yellowgreen':[154, 205, 50]} + + +import sys +from math import cos,sin,tan, atan2, pi, ceil +PI=pi +import Blender +from Blender import Mathutils + +try: + import nt + os=nt + os.sep='\\' + +except: + import posix + os=posix + os.sep='/' + +def isdir(path): + try: + st = os.stat(path) + return 1 + except: + return 0 + +def split(pathname): + if os.sep in pathname: + k0=pathname.split(os.sep) + else: + if os.sep=='/': + k0=pathname.split('\\') + else: + k0=pathname.split('/') + directory=pathname.replace(k0[len(k0)-1],'') + Name=k0[len(k0)-1] + return directory, Name + +def join(l0,l1): + return l0+os.sep+l1 + +os.isdir=isdir +os.split=split +os.join=join + +def filterFILE(nom): + """ + Function filterFILE + + in : string nom , filename + out : string t , if correct filecontaint + + read the file's content and try to see if the format + is correct . + + Lit le contenu du fichier et en fait une pre-analyse + pour savoir s'il merite d'etre traite . + """ + # ---------- + # 0.4.7 + # ---------- + if nom.upper().endswith('.SVGZ'): + try : + import gzip + tz=gzip.GzipFile(nom) + t=tz.read() + except: + name = "ERROR: fail to import gzip module or gzip error ... " + result = Blender.Draw.PupMenu(name) + return "false" + else: + f=open(nom,'rU') + t=f.read() + f.close() + # ---------- + # 0.4.7 : end + # ---------- + # ----------------- + # pre-format ... + # ----------------- + # -------------------- + # 0.4.4 '\r','' --> '\r',' ' + # '\n','' --> '\n',' ' + #-------------------- + t=t.replace('\r',' ') + t=t.replace('\n',' ') + t=t.replace('svg:','') + #-------------------- + # may be needed in some import case when the + # file is saved from a mozilla display + #-------------------- + t=t.replace(chr(0),'') + if not '= 0.0\ + and abs(f1[5])-abs(f2[5])< EPSILON and abs(f1[5])-abs(f2[5])>= 0.0 : + return 1 + else: + return 0 + + +#-------------------- +# 0.4.5 : for blender cvs 2.38 .... +#-------------------- +def createCURVES(curves, name): + """ + internal curves creation + """ + global SCALE, B, BOUNDINGBOX,scale_, SEPARATE_CURVES + global USE_COLORS + from Blender import Curve, Object, Scene, BezTriple + HANDLE={'C':BezTriple.HandleTypes.FREE,'L':BezTriple.HandleTypes.VECT} + r=BOUNDINGBOX['rec'] + + if scale_==3: + SCALE=1.0 + elif scale_==1: + SCALE=r[2]-r[0] + elif scale_==2: + SCALE=r[3]-r[1] + + scene = Scene.GetCurrent() + scene.objects.selected = [] + + if not SEPARATE_CURVES: + c = Curve.New() + c.setResolu(24) + + MATNAME=[] + nloc=0.0 + + def new_MATERIAL(val): + # ----------------------- + # have to create a material + #------------------------ + if val.matname and val.matname in MATNAME: + mat = Blender.Material.Get(val.matname) + elif val.matname: + mat = Blender.Material.New(val.matname) + mat.rgbCol = [val.color[0]/255.0, val.color[1]/255.0, val.color[2]/255.0] + else: + mat = Blender.Material.New(val.id) + mat.rgbCol = [val.color[0]/255.0, val.color[1]/255.0, val.color[2]/255.0] + return [mat] + + for I,val in curves.ITEM.iteritems(): + if SEPARATE_CURVES: + c = Curve.New() + c.setResolu(24) + if USE_COLORS and val.mat: + c.materials=new_MATERIAL(val) + + bzn=0 + if val.beziers_knot[-1].tag in ['L','l','V','v','H','h'] and\ + test_samelocations(val.beziers_knot[-1].co,val.beziers_knot[0].co): + del val.beziers_knot[-1] + + for k2 in xrange(0,len(val.beziers_knot)): + bz= [co for co in val.beziers_knot[k2].co] + if bzn==0: + cp1 = bz[4]/SCALE, bz[5]/-SCALE,0.0, bz[0]/SCALE, bz[1]/-SCALE,0.0, bz[2]/SCALE,bz[3]/-SCALE,0.0, + beztriple1 = BezTriple.New(cp1) + bez = c.appendNurb(beztriple1) + bez[0].handleTypes=(HANDLE[val.beziers_knot[k2].ha[0]],HANDLE[val.beziers_knot[k2].ha[1]]) + bzn = 1 + else: + cp2 = bz[4]/SCALE,bz[5]/-SCALE,0.0 , bz[0]/SCALE, bz[1]/-SCALE,0.0, bz[2]/SCALE,bz[3]/-SCALE,0.0 + beztriple2 = BezTriple.New(cp2) + beztriple2.handleTypes= (HANDLE[val.beziers_knot[k2].ha[0]],HANDLE[val.beziers_knot[k2].ha[1]]) + bez.append(beztriple2) + + if val.flagUV[0]==1 or val.fill==1: + #-------------------- + # 0.4.6 : cyclic flag ... + #-------------------- + bez.flagU += 1 + + if SEPARATE_CURVES: + ob = scene.objects.new(c,val.id) + scene.objects.active = ob + ob.setLocation(0.0,0.0,nloc) + nloc+=0.0001 + c.update() + + if not SEPARATE_CURVES: + ob = scene.objects.new(c,name) + scene.objects.active = ob + c.update() + +#===================================================================== +#===== SVG format : DEBUT ========================= +#===================================================================== +#-------------------- +# 0.5.8, needed with the new +# tranform evaluation +#-------------------- +pxUNIT={'pt':1.25, + 'pc':15.0, + 'mm':3.543307, + 'cm':35.43307, + 'in':90.0, + 'em':1.0, # should be taken from font size + # but not currently managed + 'ex':1.0, # should be taken from font size + # but not currently managed + '%':1.0, + } + +#-------------------- +# 0.4.2 +# 0.5.8, to remove exec +#-------------------- +def rect(prp): + """ + build rectangle paths + """ + D=[] + if 'x' not in prp: x=0.0 + else : x=float(prp['x']) + if 'y' not in prp: y=0.0 + else : y=float(prp['y']) + #-------------------- + # 0.5.8 + #-------------------- + try: + height=float(prp['height']) + except: + pxUNIT['%']=(BOUNDINGBOX['rec'][3]-BOUNDINGBOX['rec'][1])/100.0 + for key in pxUNIT:#.keys(): + if key in prp['height']: + height=float(prp['height'].replace(key,''))*pxUNIT[key] + try: + width=float(prp['width']) + except: + pxUNIT['%']=(BOUNDINGBOX['rec'][2]-BOUNDINGBOX['rec'][0])/100.0 + for key in pxUNIT:#.keys(): + if key in prp['width']: + width=float(prp['width'].replace(key,''))*pxUNIT[key] + #-------------------- + # 0.5.8, end + #-------------------- + """ + normal rect + x,y + h1 + *----------* + | | + | | + | | + *----------* v1 + h2 + """ + if 'rx' not in prp or 'rx' not in prp: + D=['M',str(x),str(y),'h',str(width),'v',str(height),'h',str(-width),'z'] + else : + rx=float(prp['rx']) + if 'ry' not in prp : + ry=float(prp['rx']) + else : ry=float(prp['ry']) + if 'rx' in prp and prp['rx']<0.0: rx*=-1 + if 'ry' in prp and prp['ry']<0.0: ry*=-1 + """ + rounded corner + + x,y M h1 + ---*----------* + / \ + / \ + v2 * * c1 + | | + | | + | | + c3 * * v2 + \ / + \ / + *----------* + h2 c2 + """ + + D=['M',str(x+rx),str(y), + 'h',str(width-2*rx), + 'c',str(rx),'0.0',str(rx),str(ry),str(rx),str(ry), + 'v',str(height-ry), + 'c','0.0',str(ry),str(-rx),str(ry),str(-rx),str(ry), + 'h',str(-width+2*rx), + 'c',str(-rx),'0.0',str(-rx),str(-ry),str(-rx),str(-ry), + 'v',str(-height+ry), + 'c','0.0','0.0','0.0',str(-ry),str(rx),str(-ry), + 'z'] + + return D + +#-------------------- +# 0.4.2 +# 0.5.8, to remove exec +#-------------------- +def circle(prp): + if 'cx' not in prp: cx=0.0 + else : cx =float(prp['cx']) + if 'cy' not in prp: cy=0.0 + else : cy =float(prp['cy']) + #print prp.keys() + r = float(prp['r']) + D=['M',str(cx),str(cy+r), + 'C',str(cx-r), str(cy+r*0.552),str(cx-0.552*r),str(cy+r), str(cx),str(cy+r), + 'C',str(cx+r*0.552), str(cy+r), str(cx+r), str(cy+r*0.552), str(cx+r),str(cy), + 'C',str(cx+r), str(cy-r*0.552),str(cx+r*0.552),str(cy-r),str(cx), str(cy-r), + 'C',str(cx-r*0.552), str(cy-r), str(cx-r), str(cy-r*0.552),str(cx-r),str(cy), + 'Z'] + return D + +#-------------------- +# 0.4.2 +# 0.5.8, to remove exec +#-------------------- +def ellipse(prp): + if 'cx' not in prp: cx=0.0 + else : cx =float(prp['cx']) + if 'cy' not in prp: cy=0.0 + else : cy =float(prp['cy']) + ry = float(prp['rx']) + rx = float(prp['ry']) + D=['M',str(cx),str(cy+rx), + 'C',str(cx-ry),str(cy+rx*0.552),str(cx-0.552*ry),str(cy+rx),str(cx),str(cy+rx), + 'C',str(cx+ry*0.552),str(cy+rx),str(cx+ry),str(cy+rx*0.552),str(cx+ry),str(cy), + 'C',str(cx+ry),str(cy-rx*0.552),str(cx+ry*0.552),str(cy-rx),str(cx),str(cy-rx), + 'C',str(cx-ry*0.552),str(cy-rx),str(cx-ry),str(cy-rx*0.552),str(cx-ry),str(cy), + 'z'] + return D + +#-------------------- +# 0.4.2 +# 0.5.8, to remove exec +#-------------------- +def line(prp): + D=['M',str(prp['x1']),str(prp['y1']), + 'L',str(prp['x2']),str(prp['y2'])] + return D + +#-------------------- +# 0.4.2 +# 0.5.8, to remove exec +#-------------------- +def polyline(prp): + if 'points' in prp: + points=prp['points'].split(' ') + np=0 + for p in points: + if p!='': + p=p.split(',') + if np==0: + D=['M',str(p[0]),str(p[1])] + np+=1 + else: + D.append('L'); D.append(str(p[0])); D.append(str(p[1])) + return D + else: + return [] + +#-------------------- +# 0.4.2 +# 0.5.8, to remove exec +#-------------------- +def polygon(prp): + D=polyline(prp) + if D!=[]: + D.append('Z') + return D + +#-------------------- +# 0.5.8, to remove exec +#-------------------- +OTHERSSHAPES={ 'rect' : rect, + 'line' : line, + 'polyline': polyline, + 'polygon' : polygon, + 'circle' : circle, + 'ellipse' : ellipse} + +#-------------------- +# 0.3.9 +#-------------------- +def calc_arc (cpx,cpy, rx, ry, ang, fa , fs , x, y) : + """ + Calc arc paths + """ + rx=abs(rx) + ry=abs(ry) + px=abs((cos(ang)*(cpx-x)+sin(ang)*(cpy-y))*0.5)**2.0 + py=abs((cos(ang)*(cpy-y)-sin(ang)*(cpx-x))*0.5)**2.0 + rpx=rpy=0.0 + if abs(rx)>0.0: rpx=px/(rx**2.0) + if abs(ry)>0.0: rpy=py/(ry**2.0) + pl=rpx+rpy + if pl>1.0: + pl=pl**0.5;rx*=pl;ry*=pl + carx=sarx=cary=sary=0.0 + if abs(rx)>0.0: + carx=cos(ang)/rx;sarx=sin(ang)/rx + if abs(ry)>0.0: + cary=cos(ang)/ry;sary=sin(ang)/ry + x0=(carx)*cpx+(sarx)*cpy + y0=(-sary)*cpx+(cary)*cpy + x1=(carx)*x+(sarx)*y + y1=(-sary)*x+(cary)*y + d=(x1-x0)*(x1-x0)+(y1-y0)*(y1-y0) + if abs(d)>0.0 :sq=1.0/d-0.25 + else: sq=-0.25 + if sq<0.0 :sq=0.0 + sf=sq**0.5 + if fs==fa :sf=-sf + xc=0.5*(x0+x1)-sf*(y1-y0) + yc=0.5*(y0+y1)+sf*(x1-x0) + ang_0=atan2(y0-yc,x0-xc) + ang_1=atan2(y1-yc,x1-xc) + ang_arc=ang_1-ang_0; + if (ang_arc < 0.0 and fs==1) : + ang_arc += 2.0 * PI + elif (ang_arc>0.0 and fs==0) : + ang_arc-=2.0*PI + n_segs=int(ceil(abs(ang_arc*2.0/(PI*0.5+0.001)))) + P=[] + for i in xrange(n_segs): + ang0=ang_0+i*ang_arc/n_segs + ang1=ang_0+(i+1)*ang_arc/n_segs + ang_demi=0.25*(ang1-ang0) + t=2.66666*sin(ang_demi)*sin(ang_demi)/sin(ang_demi*2.0) + x1=xc+cos(ang0)-t*sin(ang0) + y1=yc+sin(ang0)+t*cos(ang0) + x2=xc+cos(ang1) + y2=yc+sin(ang1) + x3=x2+t*sin(ang1) + y3=y2-t*cos(ang1) + P.append([[(cos(ang)*rx)*x1+(-sin(ang)*ry)*y1, + (sin(ang)*rx)*x1+(cos(ang)*ry)*y1], + [(cos(ang)*rx)*x3+(-sin(ang)*ry)*y3, + (sin(ang)*rx)*x3+(cos(ang)*ry)*y3], + [(cos(ang)*rx)*x2+(-sin(ang)*ry)*y2, + (sin(ang)*rx)*x2+(cos(ang)*ry)*y2]]) + return P + +#-------------------- +# 0.3.9 +#-------------------- +def curve_to_a(c,D,n0,CP): #A,a + global SCALE + l=[float(D[c[1]+1]),float(D[c[1]+2]),float(D[c[1]+3]), + int(D[c[1]+4]),int(D[c[1]+5]),float(D[c[1]+6]),float(D[c[1]+7])] + if c[0]=='a': + l[5]=l[5] + CP[0] + l[6]=l[6] + CP[1] + B=Bez() + B.co=[ CP[0], CP[1], CP[0], CP[1], CP[0], CP[1] ] + B.ha=['C','C'] + B.tag=c[0] + POINTS= calc_arc (CP[0],CP[1], + l[0], l[1], l[2]*(PI / 180.0), + l[3], l[4], + l[5], l[6] ) + #if DEBUG == 1 : print POINTS + for p in POINTS : + B=Bez() + B.co=[ p[2][0],p[2][1], p[0][0],p[0][1], p[1][0],p[1][1]] + B.ha=['C','C'] + B.tag='C' + BP=curves.ITEM[n0].beziers_knot[-1] + BP.co[2]=B.co[2] + BP.co[3]=B.co[3] + curves.ITEM[n0].beziers_knot.append(B) + BP=curves.ITEM[n0].beziers_knot[-1] + BP.co[2]=BP.co[0] + BP.co[3]=BP.co[1] + CP=[l[5], l[6]] + return curves,n0,CP + +def move_to(c, D, n0,CP, proprietes): + global DEBUG,TAGcourbe, LAST_ID + global USE_COLORS + + l=[float(D[c[1]+1]),float(D[c[1]+2])] + if c[0]=='m': + l=[l[0]+CP[0], + l[1] + CP[1]] + if n0 in curves.ITEM: + n0+=1 + CP=[l[0],l[1]] + curves.ITEM[n0]=ITEM() + + if 'id' in proprietes: + curves.ITEM[n0].id=proprietes['id'] + else: + curves.ITEM[n0].id=LAST_ID + + proprietes['n'].append(n0) + if USE_COLORS: + pr= proprietes.get('fill') # None or the property + if pr != None: + if '#' in pr: + i=1 + curves.ITEM[n0].color=[int(pr[i:i+2],16),int(pr[i+2:i+4],16),int(pr[i+4:i+6],16)] + curves.ITEM[n0].mat=1 + elif pr in SVGCOLORNAMELIST: + Courbe[n].color=SVGCOLORNAMELIST[pr] + Courbe[n].mat=1 + + B=Bez() + B.co=[CP[0],CP[1],CP[0],CP[1],CP[0],CP[1]] + B.ha=['L','C'] + B.tag=c[0] + curves.ITEM[n0].beziers_knot.append(B) + #if DEBUG==1: print curves.ITEM[n0], CP + return curves,n0,CP + +def close_z(c,D,n0,CP): #Z,z + curves.ITEM[n0].flagUV[0]=1 + if len(curves.ITEM[n0].beziers_knot)>1: + #print len(curves.ITEM[n0].beziers_knot) + BP=curves.ITEM[n0].beziers_knot[-1] + BP0=curves.ITEM[n0].beziers_knot[0] + if BP.tag in ['c','C','s','S',]: + BP.co[2]=BP0.co[2] #4-5 point prec + BP.co[3]=BP0.co[3] + del curves.ITEM[n0].beziers_knot[0] + else: + del curves.ITEM[n0] + n0-=1 + return curves,n0,CP + +def curve_to_q(c,D,n0,CP): #Q,q + l=[float(D[c[1]+1]),float(D[c[1]+2]),float(D[c[1]+3]),float(D[c[1]+4])] + if c[0]=='q': + l=[l[0]+CP[0], l[1]+CP[1], l[2]+CP[0], l[3]+CP[1]] + B=Bez() + B.co=[l[2], l[3], l[2], l[3], l[0], l[1]] #plus toucher au 2-3 + B.ha=['C','C'] + B.tag=c[0] + BP=curves.ITEM[n0].beziers_knot[-1] + BP.co[2]=BP.co[0] + BP.co[3]=BP.co[1] + curves.ITEM[n0].beziers_knot.append(B) + #if DEBUG==1: print B.co,BP.co + CP=[l[2],l[3]] + #if DEBUG==1: pass + if len(D)>c[1]+5 and D[c[1]+5] not in TAGcourbe : + c[1]+=4 + curve_to_q(c, D, n0,CP) + return curves,n0,CP + +def curve_to_t(c,D,n0,CP): #T,t + l=[float(D[c[1]+1]),float(D[c[1]+2])] + if c[0]=='t': + l=[l[0]+CP[0], l[1]+CP[1]] + B=Bez() + B.co=[l[0], l[1], l[0], l[1], l[0], l[1]] #plus toucher au 2-3 + B.ha=['C','C'] + B.tag=c[0] + BP=curves.ITEM[n0].beziers_knot[-1] + l0=build_SYMETRIC([BP.co[0],BP.co[1],BP.co[4],BP.co[5]]) + if BP.tag in ['q','Q','t','T','m','M']: + BP.co[2]=l0[2] + BP.co[3]=l0[3] + curves.ITEM[n0].beziers_knot.append(B) + #if DEBUG==1: print B.co,BP.co + CP=[l[0],l[1]] + if len(D)>c[1]+3 and D[c[1]+3] not in TAGcourbe : + c[1]+=4 + curve_to_t(c, D, n0,CP) + return curves,n0,CP + +#-------------------- +# 0.4.3 : rewritten +#-------------------- +def build_SYMETRIC(l): + X=l[2]-(l[0]-l[2]) + Y=l[3]-(l[1]-l[3]) + return X,Y + +def curve_to_s(c,D,n0,CP): #S,s + l=[float(D[c[1]+1]), + float(D[c[1]+2]), + float(D[c[1]+3]), + float(D[c[1]+4])] + if c[0]=='s': + l=[l[0]+CP[0], l[1]+CP[1], + l[2]+CP[0], l[3]+CP[1]] + B=Bez() + B.co=[l[2],l[3],l[2],l[3],l[0],l[1]] #plus toucher au 2-3 + B.ha=['C','C'] + B.tag=c[0] + BP=curves.ITEM[n0].beziers_knot[-1] + #-------------------- + # 0.4.3 + #-------------------- + BP.co[2],BP.co[3]=build_SYMETRIC([BP.co[4],BP.co[5],BP.co[0],BP.co[1]]) + curves.ITEM[n0].beziers_knot.append(B) + #if DEBUG==1: print B.co,BP.co + #-------------------- + # 0.4.3 + #-------------------- + CP=[l[2],l[3]] + if len(D)>c[1]+5 and D[c[1]+5] not in TAGcourbe : + c[1]+=4 + curve_to_c(c, D, n0,CP) + return curves,n0,CP + +def curve_to_c(c, D, n0,CP): #c,C + l=[float(D[c[1]+1]),float(D[c[1]+2]),float(D[c[1]+3]), + float(D[c[1]+4]),float(D[c[1]+5]),float(D[c[1]+6])] + if c[0]=='c': + l=[l[0]+CP[0], + l[1]+CP[1], + l[2]+CP[0], + l[3]+CP[1], + l[4]+CP[0], + l[5]+CP[1]] + B=Bez() + B.co=[l[4], + l[5], + l[4], + l[5], + l[2], + l[3]] #plus toucher au 2-3 + B.ha=['C','C'] + B.tag=c[0] + BP=curves.ITEM[n0].beziers_knot[-1] + BP.co[2]=l[0] + BP.co[3]=l[1] + BP.ha[1]='C' + curves.ITEM[n0].beziers_knot.append(B) + #if DEBUG==1: print B.co,BP.co + CP=[l[4],l[5]] + if len(D)>c[1]+7 and D[c[1]+7] not in TAGcourbe : + c[1]+=6 + curve_to_c(c, D, n0,CP) + return curves,n0,CP + +def draw_line_l(c, D, n0,CP): #L,l + l=[float(D[c[1]+1]),float(D[c[1]+2])] + if c[0]=='l': + l=[l[0]+CP[0], + l[1]+CP[1]] + B=Bez() + B.co=[l[0],l[1],l[0],l[1],l[0],l[1]] + B.ha=['L','L'] + B.tag=c[0] + BP=curves.ITEM[n0].beziers_knot[-1] + BP.ha[1]='L' + curves.ITEM[n0].beziers_knot.append(B) + CP=[B.co[0],B.co[1]] + if len(D)>c[1]+3 and D[c[1]+3] not in TAGcourbe : + c[1]+=2 + draw_line_l(c, D, n0,CP) #L + return curves,n0,CP + +def draw_line_h(c,D,n0,CP): #H,h + if c[0]=='h': + l=[float(D[c[1]+1])+float(CP[0]),CP[1]] + else: + l=[float(D[c[1]+1]),CP[1]] + B=Bez() + B.co=[l[0],l[1],l[0],l[1],l[0],l[1]] + B.ha=['L','L'] + B.tag=c[0] + #BP=curves.ITEM[n0].beziers_knot[-1] + #BP.ha[0]='L' + curves.ITEM[n0].beziers_knot.append(B) + CP=[l[0],l[1]] + return curves,n0,CP + +def draw_line_v(c,D,n0,CP): #V, v + if c[0]=='v': + l=[CP[0], float(D[c[1]+1])+CP[1]] + else: + l=[CP[0], float(D[c[1]+1])] + + B=Bez() + B.co=[l[0],l[1],l[0],l[1],l[0],l[1]] + B.ha=['L','L'] + B.tag=c[0] + #BP=curves.ITEM[n0].beziers_knot[-1] + #BP.ha[0]='L' + curves.ITEM[n0].beziers_knot.append(B) + CP=[l[0],l[1]] + return curves,n0,CP + +Actions= { "C" : curve_to_c, + "A" : curve_to_a, + "S" : curve_to_s, + "M" : move_to, + "V" : draw_line_v, + "L" : draw_line_l, + "H" : draw_line_h, + "Z" : close_z, + "Q" : curve_to_q, + "T" : curve_to_t, + + "c" : curve_to_c, + "a" : curve_to_a, + "s" : curve_to_s, + "m" : move_to, + "v" : draw_line_v, + "l" : draw_line_l, + "h" : draw_line_h, + "z" : close_z, + "q" : curve_to_q, + "T" : curve_to_t +} + +TAGcourbe=Actions.keys() +TAGtransform=['M','L','C','S','H','V','T','Q'] +tagTRANSFORM=0 + +def wash_DATA(ndata): + if ndata: + #if DEBUG==1: print ndata + ndata = ndata.strip() + if ndata[0]==',':ndata=ndata[1:] + if ndata[-1]==',':ndata=ndata[:-1] + #-------------------- + # 0.4.0 : 'e' + #-------------------- + i = ndata.find('-') + if i != -1 and ndata[i-1] not in ' ,e': + ndata=ndata.replace('-',',-') + ndata=ndata.replace(',,',',') + ndata=ndata.replace(' ',',') + ndata=ndata.split(',') + ndata=[i for i in ndata if i] #059a + + return ndata + +#-------------------- +# 0.3.4 : - read data rewrittten +#-------------------- +def list_DATA(DATA): + """ + This function translate a text in a list of + correct commandswith the right number of waited + values for each of them . For example : + d="'M0,14.0 z" becomes ['M','0.0','14.0','z'] + """ + # ---------------------------------------- + # borner les differents segments qui devront etre + # traites + # pour cela construire une liste avec chaque + # la position de chaqe emplacement tag de type + # commande path... + # ---------------------------------------- + tagplace=[] + for d in Actions: + b1=0 + while True: + i = DATA.find(d,b1) + if i==-1: break + tagplace.append(i) + b1=i+1 + #------------------------------------------ + # cette liste doit etre traites dans l'ordre + # d'apparition des tags + #------------------------------------------ + tagplace.sort() + + tpn=range(len(tagplace)) + #-------------------- + # 0.3.5 :: short data, only one tag + #-------------------- + if len(tagplace)-1>0: + DATA2=[] + for t in tpn[:-1]: + DATA2.append(DATA[tagplace[t]:tagplace[t]+1]) + ndata=DATA[tagplace[t]+1:tagplace[t+1]] + if DATA2[-1] not in ['z','Z'] : + ndata=wash_DATA(ndata) + DATA2.extend(ndata) + DATA2.append(DATA[tagplace[t+1]:tagplace[t+1]+1]) + if DATA2[-1] not in ['z','Z'] and len(DATA)-1>=tagplace[t+1]+1: + ndata=DATA[tagplace[t+1]+1:] + ndata=wash_DATA(ndata) + DATA2.extend(ndata) #059a + else: + #-------------------- + # 0.3.5 : short data,only one tag + #-------------------- + DATA2=[] + DATA2.append(DATA[tagplace[0]:tagplace[0]+1]) + ndata=DATA[tagplace[0]+1:] + ndata=wash_DATA(ndata) + DATA2.extend(ndata) + return DATA2 + +#---------------------------------------------- +# 0.3 +# 0.5.8, to remove exec +#---------------------------------------------- +def translate(t): + tx=t[0] + ty=t[1] + return [1, 0, tx], [0, 1, ty],[0,0,1] + +#---------------------------------------------- +# 0.3.2 +# 0.5.8, to remove exec +#---------------------------------------------- +def scale(s): + sx=s[0] + if len(s)>1: sy=s[1] + else: sy=sx + return [sx, 0, 0], [0, sy, 0],[0,0,1] + +#---------------------------------------------- +# 0.4.1 : transslate a in radians +# 0.5.8, to remove exec +#---------------------------------------------- +def rotate(t): + a=t[0] + return [cos(a*3.1416/180.0), -sin(a*3.1416/180.0), 0], [sin(a*3.1416/180.0), cos(a*3.1416/180.0),0],[0,0,1] + +#---------------------------------------------- +# 0.3.2 +# 0.5.8, to remove exec +#---------------------------------------------- +def skewx(t): + a=t[0] + return [1, tan(a*3.1416/180.0), 0], [0, 1, 0],[0,0,1] + +#---------------------------------------------- +# 0.4.1 +# 0.5.8, to remove exec +#---------------------------------------------- +def skewy(t): + a=t[0] + return [1, 0, 0], [tan(a*3.1416/180.0), 1 , 0],[0,0,1] + +#---------------------------------------------- +# 0.3.2 +# 0.5.8, to remove exec +#---------------------------------------------- +def matrix(t): + a,b,c,d,e,f=t + return [a,c,e],[b,d,f],[0,0,1] + +#-------------------- +# 0.5.8, to remove exec +#-------------------- +matrixTRANSFORM={ 'translate':translate, + 'scale':scale, + 'rotate':rotate, + 'skewx':skewx, + 'skewy':skewy, + 'matrix':matrix + } + +#---------------------------------------------- +# 0.4.2 : rewritten +# 0.5.8 : to remove exec uses. +#---------------------------------------------- +def control_CONTAINT(txt): + """ + the transforms' descriptions can be sole or several + and separators might be forgotten + """ + t0=0 + tlist=[] + while txt.count(')',t0)>0: + t1=txt.find(')',t0) + nt0=txt[t0:t1+1] + t2=nt0[nt0.find('(')+1:-1] + val=nt0[:nt0.find('(')] + while t2.find(' ')!=-1: + t2=t2.replace(' ',' ') + t2=t2.replace(' ',',') + + """ + t2=t2.split(',') + for index, t in enumerate(t2): + t2[index]=float(t) + """ + t2=[float(t) for t in t2.split(',')] + + if val=='rotate' : + t3=t2 + if len(t3)==3: + tlist.append(['translate',[t3[1],t3[2]]]) + tlist.append(['rotate',[t3[0]/180.0*3.1416]]) + tlist.append(['translate',[-t3[1],-t3[2]]]) + else: + tlist.append(['rotate',[t3[0]]]) + else: + tlist.append([val,t2]) + t0=t1+1 + return tlist + + +def curve_FILL(Courbe,proprietes): + global USE_COLORS + for n in proprietes['n']: + pr = proprietes['style'] + if n in Courbe and 'fill:' in pr: + if not 'fill:none' in pr: + Courbe[n].fill=1 + if USE_COLORS: + if '#' in pr: + i= pr.find('fill:#')+6 + Courbe[n].color=[int(pr[i:i+2],16),int(pr[i+2:i+4],16),int(pr[i+4:i+6],16)] + Courbe[n].mat=1 + elif ';fill-opacity' in pr: + i= pr.find('fill:')+5 + i2= pr.find(';',i) + COLORNAME= pr[i:i2] + Courbe[n].color=SVGCOLORNAMELIST[COLORNAME] + Courbe[n].mat=1 +#---------------------------------------------- +# 0.4.1 : apply transform stack +#---------------------------------------------- +def curve_TRANSFORM(Courbe,proprietes): + # 1/ unpack the STACK + # create a matrix for each transform + ST=[] + for st in proprietes['stack'] : + if st and type(st)==list: + for t in st: + code = control_CONTAINT(t) + a,b,c=matrixTRANSFORM[code[0][0]](code[0][1][:]) + T=Mathutils.Matrix(a,b,c) + ST.append(T) + elif st : + code = control_CONTAINT(st) + a,b,c=matrixTRANSFORM[code[0][0]](code[0][1][:]) + T=Mathutils.Matrix(a,b,c) + ST.append(T) + if 'transform' in proprietes: + for trans in control_CONTAINT(proprietes['transform']): + #-------------------- + # 0.5.8, to remove exec + #-------------------- + a,b,c=matrixTRANSFORM[trans[0].strip()](trans[1][:]) #059 + T=Mathutils.Matrix(a,b,c) + ST.append(T) + ST.reverse() + for n in proprietes['n']: + if n in Courbe: + for bez0 in Courbe[n].beziers_knot: + bez=bez0.co + for b in [0,2,4]: + for t in ST: + v=t * Mathutils.Vector([bez[b],bez[b+1],1.0]) #059a + bez[b]=v[0] + bez[b+1]=v[1] + +def filter(d): + for nn in d: + if nn not in '0123456789.': #059a + d=d.replace(nn,"") + return d + +def get_BOUNDBOX(BOUNDINGBOX,SVG): + if 'viewbox' not in SVG: + h=float(filter(SVG['height'])) + #if DEBUG==1 : print 'h : ',h + w=float(filter(SVG['width'])) + #if DEBUG==1 : print 'w :',w + BOUNDINGBOX['rec']=[0.0,0.0,w,h] + r=BOUNDINGBOX['rec'] + BOUNDINGBOX['coef']=w/h + else: + viewbox=SVG['viewbox'].split() + BOUNDINGBOX['rec']=[float(viewbox[0]),float(viewbox[1]),float(viewbox[2]),float(viewbox[3])] + r=BOUNDINGBOX['rec'] + BOUNDINGBOX['coef']=(r[2]-r[0])/(r[3]-r[1]) + return BOUNDINGBOX + +#---------------------------------------------- +# 0.4.1 : attributs ex : 'id=', 'transform=', 'd=' ... +#---------------------------------------------- +def collect_ATTRIBUTS(data): + #---------------------------------------------- + # 0.4.8 : short modif for a fantasy font case + # in the OOo svg format ('viewbox' is + # written 'viewBox', for instance) + #---------------------------------------------- + data=data.replace(' ',' ').lower() + ELEM={'TYPE':data[1:data.find(' ')]} + t1=len(data) + t2=0 + ct=data.count('="') + while ct>0: + t0=data.find('="',t2) + t2=data.find(' ',t2)+1 + id=data[t2:t0] + t2=data.find('"',t0+2) + if id!='d': + ELEM[id]=data[t0+2:t2].replace('\\','/') + else: + ELEM[id]=[] + ELEM[id].append(t0+2) + ELEM[id].append(t2) + ct=data.count('="',t2) + return ELEM + +# -------------------------------------------- +# 0.4.1 : to avoid to use sax and ths xml +# tools of the complete python +# -------------------------------------------- +def build_HIERARCHY(t): + global CP, curves, SCALE, DEBUG, BOUNDINGBOX, scale_, tagTRANSFORM + global LAST_ID + TRANSFORM=0 + t=t.replace('\t',' ') + while t.find(' ')!=-1: t=t.replace(' ',' ') + n0=0 + t0=t1=0 + baliste=[] + balisetype=['?','?','/','/','!','!'] + BALISES=['D', #DECL_TEXTE', + 'D', #DECL_TEXTE', + 'F', #FERMANTE', + 'E', #ELEM_VIDE', + 'd', #DOC', + 'R', #REMARQUES', + 'C', #CONTENU', + 'O' #OUVRANTE' + ] + STACK=[] + while t1-1: + t0=t.find('<',t0) + t1=t.find('>',t0) + ouvrante=0 + #-------------------- + # 0.4.4 , add 'else:' and 'break' to the 'if' statement + #-------------------- + if t0>-1 and t1>-1: + if t[t0+1] in balisetype: + b=balisetype.index(t[t0+1]) + if t[t0+2]=='-': + b=balisetype.index(t[t0+1])+1 + #print t[t0:t1] + balise=BALISES[b] + if b==2: + parent=STACK.pop(-1) + if parent!=None and TRANSFORM>0: + TRANSFORM-=1 + elif t[t1-1] in balisetype: + balise=BALISES[balisetype.index(t[t1-1])+1] + else: + t2=t.find(' ',t0) + if t2>t1: t2=t1 + ouvrante=1 + NOM=t[t0+1:t2] + if '-1: + balise=BALISES[-1] + else: + balise=BALISES[-2] + + if balise=='E' or balise=='O': + proprietes=collect_ATTRIBUTS(t[t0:t1+ouvrante]) + + #print proprietes + if 'id' in proprietes: + LAST_ID=proprietes['id'] + #print LAST_ID + + + + if balise=='O' and 'transform' in proprietes: + STACK.append(proprietes['transform']) + TRANSFORM+=1 + elif balise=='O' : + STACK.append(None) + + proprietes['stack']=STACK[:] + D=[] + + if proprietes['TYPE'] in ['path'] and (proprietes['d'][1]-proprietes['d'][0]>1): + D=list_DATA(t[proprietes['d'][0]+t0:proprietes['d'][1]+t0]) + + elif proprietes['TYPE'] in OTHERSSHAPES: + #-------------------- + # 0.5.8, to remove exec + #-------------------- + D=OTHERSSHAPES[proprietes['TYPE']](proprietes) + + if len(D)>0: + cursor=0 + proprietes['n']=[] + for cell in D: + #if DEBUG==2 : print 'cell : ',cell ,' --' + if len(cell)>=1 and cell[0] in TAGcourbe: + #-------------------- + # 0.5.8, to remove exec + #-------------------- + if cell[0] in ['m','M']: + curves,n0,CP=Actions[cell]([cell,cursor], D, n0,CP,proprietes) + else: + curves,n0,CP=Actions[cell]([cell,cursor], D, n0,CP) + + cursor+=1 + if TRANSFORM>0 or 'transform' in proprietes : + curve_TRANSFORM(curves.ITEM,proprietes) + + if 'style' in proprietes : + curve_FILL(curves.ITEM,proprietes) + + + elif proprietes['TYPE'] == 'svg': + #print 'proprietes.keys()',proprietes.keys() + BOUNDINGBOX = get_BOUNDBOX(BOUNDINGBOX,proprietes) + else: + #-------------------- + # 0.4.4 + #-------------------- + break + t1+=1 + t0=t1 + +def scan_FILE(nom): + global CP, curves, SCALE, DEBUG, BOUNDINGBOX, scale_, tagTRANSFORM + global SEPARATE_CURVES, USE_COLORS + + dir,name=split(nom) + name=name.split('.') + result=0 + #Choise=1 + t1=Blender.sys.time() + t=filterFILE(nom) + if t!='false': + Blender.Window.EditMode(0) + if not SHARP_IMPORT: + togH = Blender.Draw.Create(1) + togW = Blender.Draw.Create(0) + togAS = Blender.Draw.Create(0) + togSP = Blender.Draw.Create(0) + togCOL = Blender.Draw.Create(0) + block=[\ + ("Clamp Width 1", togW, "Rescale the import with a Width of one unit"),\ + ("Clamp Height 1", togH, "Rescale the import with a Heightof one unit"),\ + ("No Rescaling", togAS, "No rescaling, the result can be very large"),\ + ("Separate Curves", togSP, "Create an object for each curve, Slower. May manage colors"),\ + ("Import Colors", togCOL, "try to import color if the path is set as 'fill'. Only With separate option")] + + retval = Blender.Draw.PupBlock("Import Options", block) + if togW.val: scale_=1 + elif togH.val: scale_=2 + elif togAS.val: scale_=3 + + if togSP.val: SEPARATE_CURVES=1 + + if togCOL.val and SEPARATE_CURVES : USE_COLORS=1 + + t1=Blender.sys.time() + # 0.4.1 : to avoid to use sax and the xml + # tools of the complete python + build_HIERARCHY(t) + r=BOUNDINGBOX['rec'] + curves.number_of_items=len(curves.ITEM) + for k, val in curves.ITEM.iteritems(): + val.pntsUV[0] =len(val.beziers_knot) + if curves.number_of_items>0 : #and Choise==1 : + #-------------------- + # 0.4.5 and 0.4.9 + #-------------------- + createCURVES(curves, name[0]) + else: + pass + print ' elapsed time : ',Blender.sys.time()-t1 + Blender.Redraw() + +#===================================================================== +#====================== SVG format mouvements ======================== +#===================================================================== +def functionSELECT(nom): + scan_FILE(nom) + + +if __name__=='__main__': + Blender.Window.FileSelector (functionSELECT, 'SELECT an .SVG FILE', '*.svg') diff --git a/release/scripts/bvh_import.py b/release/scripts/bvh_import.py new file mode 100644 index 00000000000..2093ac109f7 --- /dev/null +++ b/release/scripts/bvh_import.py @@ -0,0 +1,752 @@ +#!BPY + +""" +Name: 'Motion Capture (.bvh)...' +Blender: 242 +Group: 'Import' +Tip: 'Import a (.bvh) motion capture file' +""" + +__author__ = "Campbell Barton" +__url__ = ("blender.org", "blenderartists.org") +__version__ = "1.90 06/08/01" + +__bpydoc__ = """\ +This script imports BVH motion capture data to Blender. +as empties or armatures. +""" + +# -------------------------------------------------------------------------- +# BVH Import v2.0 by Campbell Barton (AKA Ideasman) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender +import bpy +import BPyMessages +Vector= Blender.Mathutils.Vector +Euler= Blender.Mathutils.Euler +Matrix= Blender.Mathutils.Matrix +RotationMatrix = Blender.Mathutils.RotationMatrix +TranslationMatrix= Blender.Mathutils.TranslationMatrix + +DEG2RAD = 0.017453292519943295 + +class bvh_node_class(object): + __slots__=(\ + 'name',# bvh joint name + 'parent',# bvh_node_class type or None for no parent + 'children',# a list of children of this type. + 'rest_head_world',# worldspace rest location for the head of this node + 'rest_head_local',# localspace rest location for the head of this node + 'rest_tail_world',# # worldspace rest location for the tail of this node + 'rest_tail_local',# # worldspace rest location for the tail of this node + 'channels',# list of 6 ints, -1 for an unused channel, otherwise an index for the BVH motion data lines, lock triple then rot triple + 'rot_order',# a triple of indicies as to the order rotation is applied. [0,1,2] is x/y/z - [None, None, None] if no rotation. + 'anim_data',# a list one tuple's one for each frame. (locx, locy, locz, rotx, roty, rotz) + 'has_loc',# Conveinience function, bool, same as (channels[0]!=-1 or channels[1]!=-1 channels[2]!=-1) + 'has_rot',# Conveinience function, bool, same as (channels[3]!=-1 or channels[4]!=-1 channels[5]!=-1) + 'temp')# use this for whatever you want + + def __init__(self, name, rest_head_world, rest_head_local, parent, channels, rot_order): + self.name= name + self.rest_head_world= rest_head_world + self.rest_head_local= rest_head_local + self.rest_tail_world= None + self.rest_tail_local= None + self.parent= parent + self.channels= channels + self.rot_order= rot_order + + # convenience functions + self.has_loc= channels[0] != -1 or channels[1] != -1 or channels[2] != -1 + self.has_rot= channels[3] != -1 or channels[4] != -1 or channels[5] != -1 + + + self.children= [] + + # list of 6 length tuples: (lx,ly,lz, rx,ry,rz) + # even if the channels arnt used they will just be zero + # + self.anim_data= [(0,0,0,0,0,0)] + + + def __repr__(self): + return 'BVH name:"%s", rest_loc:(%.3f,%.3f,%.3f), rest_tail:(%.3f,%.3f,%.3f)' %\ + (self.name,\ + self.rest_head_world.x, self.rest_head_world.y, self.rest_head_world.z,\ + self.rest_head_world.x, self.rest_head_world.y, self.rest_head_world.z) + + + +# Change the order rotation is applied. +MATRIX_IDENTITY_3x3 = Matrix([1,0,0],[0,1,0],[0,0,1]) +MATRIX_IDENTITY_4x4 = Matrix([1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]) + +def eulerRotate(x,y,z, rot_order): + # Clamp all values between 0 and 360, values outside this raise an error. + mats=[RotationMatrix(x%360,3,'x'), RotationMatrix(y%360,3,'y'), RotationMatrix(z%360,3,'z')] + # print rot_order + # Standard BVH multiplication order, apply the rotation in the order Z,X,Y + return (mats[rot_order[2]]*(mats[rot_order[1]]* (mats[rot_order[0]]* MATRIX_IDENTITY_3x3))).toEuler() + +def read_bvh(file_path, GLOBAL_SCALE=1.0): + # File loading stuff + # Open the file for importing + file = open(file_path, 'rU') + + # Seperate into a list of lists, each line a list of words. + file_lines = file.readlines() + # Non standard carrage returns? + if len(file_lines) == 1: + file_lines = file_lines[0].split('\r') + + # Split by whitespace. + file_lines =[ll for ll in [ l.split() for l in file_lines] if ll] + + + # Create Hirachy as empties + + if file_lines[0][0].lower() == 'hierarchy': + #print 'Importing the BVH Hierarchy for:', file_path + pass + else: + raise 'ERROR: This is not a BVH file' + + bvh_nodes= {None:None} + bvh_nodes_serial = [None] + + channelIndex = -1 + + + lineIdx = 0 # An index for the file. + while lineIdx < len(file_lines) -1: + #... + if file_lines[lineIdx][0].lower() == 'root' or file_lines[lineIdx][0].lower() == 'joint': + + # Join spaces into 1 word with underscores joining it. + if len(file_lines[lineIdx]) > 2: + file_lines[lineIdx][1] = '_'.join(file_lines[lineIdx][1:]) + file_lines[lineIdx] = file_lines[lineIdx][:2] + + # MAY NEED TO SUPPORT MULTIPLE ROOT's HERE!!!, Still unsure weather multiple roots are possible.?? + + # Make sure the names are unique- Object names will match joint names exactly and both will be unique. + name = file_lines[lineIdx][1] + + #print '%snode: %s, parent: %s' % (len(bvh_nodes_serial) * ' ', name, bvh_nodes_serial[-1]) + + lineIdx += 2 # Incriment to the next line (Offset) + rest_head_local = Vector( GLOBAL_SCALE*float(file_lines[lineIdx][1]), GLOBAL_SCALE*float(file_lines[lineIdx][2]), GLOBAL_SCALE*float(file_lines[lineIdx][3]) ) + lineIdx += 1 # Incriment to the next line (Channels) + + # newChannel[Xposition, Yposition, Zposition, Xrotation, Yrotation, Zrotation] + # newChannel references indecies to the motiondata, + # if not assigned then -1 refers to the last value that will be added on loading at a value of zero, this is appended + # We'll add a zero value onto the end of the MotionDATA so this is always refers to a value. + my_channel = [-1, -1, -1, -1, -1, -1] + my_rot_order= [None, None, None] + rot_count= 0 + for channel in file_lines[lineIdx][2:]: + channel= channel.lower() + channelIndex += 1 # So the index points to the right channel + if channel == 'xposition': my_channel[0] = channelIndex + elif channel == 'yposition': my_channel[1] = channelIndex + elif channel == 'zposition': my_channel[2] = channelIndex + + elif channel == 'xrotation': + my_channel[3] = channelIndex + my_rot_order[rot_count]= 0 + rot_count+=1 + elif channel == 'yrotation': + my_channel[4] = channelIndex + my_rot_order[rot_count]= 1 + rot_count+=1 + elif channel == 'zrotation': + my_channel[5] = channelIndex + my_rot_order[rot_count]= 2 + rot_count+=1 + + channels = file_lines[lineIdx][2:] + + my_parent= bvh_nodes_serial[-1] # account for none + + + # Apply the parents offset accumletivly + if my_parent==None: + rest_head_world= Vector(rest_head_local) + else: + rest_head_world= my_parent.rest_head_world + rest_head_local + + bvh_node= bvh_nodes[name]= bvh_node_class(name, rest_head_world, rest_head_local, my_parent, my_channel, my_rot_order) + + # If we have another child then we can call ourselves a parent, else + bvh_nodes_serial.append(bvh_node) + + # Account for an end node + if file_lines[lineIdx][0].lower() == 'end' and file_lines[lineIdx][1].lower() == 'site': # There is somtimes a name after 'End Site' but we will ignore it. + lineIdx += 2 # Incriment to the next line (Offset) + rest_tail = Vector( GLOBAL_SCALE*float(file_lines[lineIdx][1]), GLOBAL_SCALE*float(file_lines[lineIdx][2]), GLOBAL_SCALE*float(file_lines[lineIdx][3]) ) + + bvh_nodes_serial[-1].rest_tail_world= bvh_nodes_serial[-1].rest_head_world + rest_tail + bvh_nodes_serial[-1].rest_tail_local= rest_tail + + + # Just so we can remove the Parents in a uniform way- End end never has kids + # so this is a placeholder + bvh_nodes_serial.append(None) + + if len(file_lines[lineIdx]) == 1 and file_lines[lineIdx][0] == '}': # == ['}'] + bvh_nodes_serial.pop() # Remove the last item + + if len(file_lines[lineIdx]) == 1 and file_lines[lineIdx][0].lower() == 'motion': + #print '\nImporting motion data' + lineIdx += 3 # Set the cursor to the first frame + break + + lineIdx += 1 + + + # Remove the None value used for easy parent reference + del bvh_nodes[None] + # Dont use anymore + del bvh_nodes_serial + + bvh_nodes_list= bvh_nodes.values() + + while lineIdx < len(file_lines) -1: + line= file_lines[lineIdx] + for bvh_node in bvh_nodes_list: + #for bvh_node in bvh_nodes_serial: + lx= ly= lz= rx= ry= rz= 0.0 + channels= bvh_node.channels + anim_data= bvh_node.anim_data + if channels[0] != -1: + lx= GLOBAL_SCALE * float( line[channels[0]] ) + + if channels[1] != -1: + ly= GLOBAL_SCALE * float( line[channels[1]] ) + + if channels[2] != -1: + lz= GLOBAL_SCALE * float( line[channels[2]] ) + + if channels[3] != -1 or channels[4] != -1 or channels[5] != -1: + rx, ry, rz = eulerRotate(float( line[channels[3]] ), float( line[channels[4]] ), float( line[channels[5]] ), bvh_node.rot_order) + #x,y,z = x/10.0, y/10.0, z/10.0 # For IPO's 36 is 360d + + # Make interpolation not cross between 180d, thjis fixes sub frame interpolation and time scaling. + # Will go from (355d to 365d) rather then to (355d to 5d) - inbetween these 2 there will now be a correct interpolation. + + while anim_data[-1][3] - rx > 180: rx+=360 + while anim_data[-1][3] - rx < -180: rx-=360 + + while anim_data[-1][4] - ry > 180: ry+=360 + while anim_data[-1][4] - ry < -180: ry-=360 + + while anim_data[-1][5] - rz > 180: rz+=360 + while anim_data[-1][5] - rz < -180: rz-=360 + + # Done importing motion data # + anim_data.append( (lx, ly, lz, rx, ry, rz) ) + lineIdx += 1 + + # Assign children + for bvh_node in bvh_nodes.itervalues(): + bvh_node_parent= bvh_node.parent + if bvh_node_parent: + bvh_node_parent.children.append(bvh_node) + + # Now set the tip of each bvh_node + for bvh_node in bvh_nodes.itervalues(): + + if not bvh_node.rest_tail_world: + if len(bvh_node.children)==1: + bvh_node.rest_tail_world= Vector(bvh_node.children[0].rest_head_world) + bvh_node.rest_tail_local= Vector(bvh_node.children[0].rest_head_local) + else: + if not bvh_node.children: + raise 'error, bvh node has no end and no children. bad file' + + # Removed temp for now + rest_tail_world= Vector(0,0,0) + rest_tail_local= Vector(0,0,0) + for bvh_node_child in bvh_node.children: + rest_tail_world += bvh_node_child.rest_head_world + rest_tail_local += bvh_node_child.rest_head_local + + bvh_node.rest_tail_world= rest_tail_world * (1.0/len(bvh_node.children)) + bvh_node.rest_tail_local= rest_tail_local * (1.0/len(bvh_node.children)) + + # Make sure tail isnt the same location as the head. + if (bvh_node.rest_tail_local-bvh_node.rest_head_local).length <= 0.001*GLOBAL_SCALE: + + bvh_node.rest_tail_local.y= bvh_node.rest_tail_local.y + GLOBAL_SCALE/10 + bvh_node.rest_tail_world.y= bvh_node.rest_tail_world.y + GLOBAL_SCALE/10 + + + + return bvh_nodes + + + +def bvh_node_dict2objects(bvh_nodes, IMPORT_START_FRAME= 1, IMPORT_LOOP= False): + + if IMPORT_START_FRAME<1: + IMPORT_START_FRAME= 1 + + scn= bpy.data.scenes.active + scn.objects.selected = [] + + objects= [] + + def add_ob(name): + ob = scn.objects.new('Empty') + objects.append(ob) + return ob + + # Add objects + for name, bvh_node in bvh_nodes.iteritems(): + bvh_node.temp= add_ob(name) + + # Parent the objects + for bvh_node in bvh_nodes.itervalues(): + bvh_node.temp.makeParent([ bvh_node_child.temp for bvh_node_child in bvh_node.children ], 1, 0) # ojbs, noninverse, 1 = not fast. + + # Offset + for bvh_node in bvh_nodes.itervalues(): + # Make relative to parents offset + bvh_node.temp.loc= bvh_node.rest_head_local + + # Add tail objects + for name, bvh_node in bvh_nodes.iteritems(): + if not bvh_node.children: + ob_end= add_ob(name + '_end') + bvh_node.temp.makeParent([ob_end], 1, 0) # ojbs, noninverse, 1 = not fast. + ob_end.loc= bvh_node.rest_tail_local + + + # Animate the data, the last used bvh_node will do since they all have the same number of frames + for current_frame in xrange(len(bvh_node.anim_data)): + Blender.Set('curframe', current_frame+IMPORT_START_FRAME) + + for bvh_node in bvh_nodes.itervalues(): + lx,ly,lz,rx,ry,rz= bvh_node.anim_data[current_frame] + + rest_head_local= bvh_node.rest_head_local + bvh_node.temp.loc= rest_head_local.x+lx, rest_head_local.y+ly, rest_head_local.z+lz + + bvh_node.temp.rot= rx*DEG2RAD,ry*DEG2RAD,rz*DEG2RAD + + bvh_node.temp.insertIpoKey(Blender.Object.IpoKeyTypes.LOCROT) + + scn.update(1) + return objects + + + +def bvh_node_dict2armature(bvh_nodes, IMPORT_START_FRAME= 1, IMPORT_LOOP= False): + + if IMPORT_START_FRAME<1: + IMPORT_START_FRAME= 1 + + + # Add the new armature, + scn = bpy.data.scenes.active + scn.objects.selected = [] + + arm_data= bpy.data.armatures.new() + arm_ob = scn.objects.new(arm_data) + scn.objects.context = [arm_ob] + scn.objects.active = arm_ob + + # Put us into editmode + arm_data.makeEditable() + + # Get the average bone length for zero length bones, we may not use this. + average_bone_length= 0.0 + nonzero_count= 0 + for bvh_node in bvh_nodes.itervalues(): + l= (bvh_node.rest_head_local-bvh_node.rest_tail_local).length + if l: + average_bone_length+= l + nonzero_count+=1 + + # Very rare cases all bones couldbe zero length??? + if not average_bone_length: + average_bone_length = 0.1 + else: + # Normal operation + average_bone_length = average_bone_length/nonzero_count + + + + ZERO_AREA_BONES= [] + for name, bvh_node in bvh_nodes.iteritems(): + # New editbone + bone= bvh_node.temp= Blender.Armature.Editbone() + + bone.name= name + arm_data.bones[name]= bone + + bone.head= bvh_node.rest_head_world + bone.tail= bvh_node.rest_tail_world + + # ZERO AREA BONES. + if (bone.head-bone.tail).length < 0.001: + if bvh_node.parent: + ofs= bvh_node.parent.rest_head_local- bvh_node.parent.rest_tail_local + if ofs.length: # is our parent zero length also?? unlikely + bone.tail= bone.tail+ofs + else: + bone.tail.y= bone.tail.y+average_bone_length + else: + bone.tail.y= bone.tail.y+average_bone_length + + ZERO_AREA_BONES.append(bone.name) + + + for bvh_node in bvh_nodes.itervalues(): + if bvh_node.parent: + # bvh_node.temp is the Editbone + + # Set the bone parent + bvh_node.temp.parent= bvh_node.parent.temp + + # Set the connection state + if not bvh_node.has_loc and\ + bvh_node.parent and\ + bvh_node.parent.temp.name not in ZERO_AREA_BONES and\ + bvh_node.parent.rest_tail_local == bvh_node.rest_head_local: + bvh_node.temp.options= [Blender.Armature.CONNECTED] + + # Replace the editbone with the editbone name, + # to avoid memory errors accessing the editbone outside editmode + for bvh_node in bvh_nodes.itervalues(): + bvh_node.temp= bvh_node.temp.name + + arm_data.update() + + # Now Apply the animation to the armature + + # Get armature animation data + pose= arm_ob.getPose() + pose_bones= pose.bones + + action = Blender.Armature.NLA.NewAction("Action") + action.setActive(arm_ob) + #xformConstants= [ Blender.Object.Pose.LOC, Blender.Object.Pose.ROT ] + + # Replace the bvh_node.temp (currently an editbone) + # With a tuple (pose_bone, armature_bone, bone_rest_matrix, bone_rest_matrix_inv) + for bvh_node in bvh_nodes.itervalues(): + bone_name= bvh_node.temp # may not be the same name as the bvh_node, could have been shortened. + pose_bone= pose_bones[bone_name] + rest_bone= arm_data.bones[bone_name] + bone_rest_matrix = rest_bone.matrix['ARMATURESPACE'].rotationPart() + + bone_rest_matrix_inv= Matrix(bone_rest_matrix) + bone_rest_matrix_inv.invert() + + bone_rest_matrix_inv.resize4x4() + bone_rest_matrix.resize4x4() + bvh_node.temp= (pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv) + + + # Make a dict for fast access without rebuilding a list all the time. + xformConstants_dict={ + (True,True): [Blender.Object.Pose.LOC, Blender.Object.Pose.ROT],\ + (False,True): [Blender.Object.Pose.ROT],\ + (True,False): [Blender.Object.Pose.LOC],\ + (False,False): [],\ + } + + + # KEYFRAME METHOD, SLOW, USE IPOS DIRECT + + # Animate the data, the last used bvh_node will do since they all have the same number of frames + for current_frame in xrange(len(bvh_node.anim_data)-1): # skip the first frame (rest frame) + # print current_frame + + #if current_frame==40: # debugging + # break + + # Dont neet to set the current frame + for bvh_node in bvh_nodes.itervalues(): + pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv= bvh_node.temp + lx,ly,lz,rx,ry,rz= bvh_node.anim_data[current_frame+1] + + if bvh_node.has_rot: + # Set the rotation, not so simple + bone_rotation_matrix= Euler(rx,ry,rz).toMatrix() + bone_rotation_matrix.resize4x4() + pose_bone.quat= (bone_rest_matrix * bone_rotation_matrix * bone_rest_matrix_inv).toQuat() + + if bvh_node.has_loc: + # Set the Location, simple too + pose_bone.loc= (\ + TranslationMatrix(Vector(lx, ly, lz) - bvh_node.rest_head_local ) *\ + bone_rest_matrix_inv).translationPart() # WHY * 10? - just how pose works + + # Get the transform + xformConstants= xformConstants_dict[bvh_node.has_loc, bvh_node.has_rot] + + + if xformConstants: + # Insert the keyframe from the loc/quat + pose_bone.insertKey(arm_ob, current_frame+IMPORT_START_FRAME, xformConstants, True ) + + # First time, set the IPO's to linear + if current_frame==0: + for ipo in action.getAllChannelIpos().itervalues(): + if ipo: + for cur in ipo: + cur.interpolation = Blender.IpoCurve.InterpTypes.LINEAR + if IMPORT_LOOP: + cur.extend = Blender.IpoCurve.ExtendTypes.CYCLIC + + + + + # END KEYFRAME METHOD + + + """ + # IPO KEYFRAME SETTING + # Add in the IPOs by adding keyframes, AFAIK theres no way to add IPOs to an action so I do this :/ + for bvh_node in bvh_nodes.itervalues(): + pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv= bvh_node.temp + + # Get the transform + xformConstants= xformConstants_dict[bvh_node.has_loc, bvh_node.has_rot] + if xformConstants: + pose_bone.loc[:]= 0,0,0 + pose_bone.quat[:]= 0,0,1,0 + # Insert the keyframe from the loc/quat + pose_bone.insertKey(arm_ob, IMPORT_START_FRAME, xformConstants) + + + action_ipos= action.getAllChannelIpos() + + + for bvh_node in bvh_nodes.itervalues(): + has_loc= bvh_node.has_loc + has_rot= bvh_node.has_rot + + if not has_rot and not has_loc: + # No animation data + continue + + ipo= action_ipos[bvh_node.temp[0].name] # posebones name as key + + if has_loc: + curve_xloc= ipo[Blender.Ipo.PO_LOCX] + curve_yloc= ipo[Blender.Ipo.PO_LOCY] + curve_zloc= ipo[Blender.Ipo.PO_LOCZ] + + curve_xloc.interpolation= \ + curve_yloc.interpolation= \ + curve_zloc.interpolation= \ + Blender.IpoCurve.InterpTypes.LINEAR + + + if has_rot: + curve_wquat= ipo[Blender.Ipo.PO_QUATW] + curve_xquat= ipo[Blender.Ipo.PO_QUATX] + curve_yquat= ipo[Blender.Ipo.PO_QUATY] + curve_zquat= ipo[Blender.Ipo.PO_QUATZ] + + curve_wquat.interpolation= \ + curve_xquat.interpolation= \ + curve_yquat.interpolation= \ + curve_zquat.interpolation= \ + Blender.IpoCurve.InterpTypes.LINEAR + + # Get the bone + pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv= bvh_node.temp + + + def pose_rot(anim_data): + bone_rotation_matrix= Euler(anim_data[3], anim_data[4], anim_data[5]).toMatrix() + bone_rotation_matrix.resize4x4() + return tuple((bone_rest_matrix * bone_rotation_matrix * bone_rest_matrix_inv).toQuat()) # qw,qx,qy,qz + + def pose_loc(anim_data): + return tuple((TranslationMatrix(Vector(anim_data[0], anim_data[1], anim_data[2])) * bone_rest_matrix_inv).translationPart()) + + + last_frame= len(bvh_node.anim_data)+IMPORT_START_FRAME-1 + + if has_loc: + pose_locations= [pose_loc(anim_key) for anim_key in bvh_node.anim_data] + + # Add the start at the end, we know the start is just 0,0,0 anyway + curve_xloc.append((last_frame, pose_locations[-1][0])) + curve_yloc.append((last_frame, pose_locations[-1][1])) + curve_zloc.append((last_frame, pose_locations[-1][2])) + + if len(pose_locations) > 1: + ox,oy,oz= pose_locations[0] + x,y,z= pose_locations[1] + + for i in xrange(1, len(pose_locations)-1): # from second frame to second last frame + + nx,ny,nz= pose_locations[i+1] + xset= yset= zset= True # we set all these by default + if abs((ox+nx)/2 - x) < 0.00001: xset= False + if abs((oy+ny)/2 - y) < 0.00001: yset= False + if abs((oz+nz)/2 - z) < 0.00001: zset= False + + if xset: curve_xloc.append((i+IMPORT_START_FRAME, x)) + if yset: curve_yloc.append((i+IMPORT_START_FRAME, y)) + if zset: curve_zloc.append((i+IMPORT_START_FRAME, z)) + + # Set the old and use the new + ox,oy,oz= x,y,z + x,y,z= nx,ny,nz + + + if has_rot: + pose_rotations= [pose_rot(anim_key) for anim_key in bvh_node.anim_data] + + # Add the start at the end, we know the start is just 0,0,0 anyway + curve_wquat.append((last_frame, pose_rotations[-1][0])) + curve_xquat.append((last_frame, pose_rotations[-1][1])) + curve_yquat.append((last_frame, pose_rotations[-1][2])) + curve_zquat.append((last_frame, pose_rotations[-1][3])) + + + if len(pose_rotations) > 1: + ow,ox,oy,oz= pose_rotations[0] + w,x,y,z= pose_rotations[1] + + for i in xrange(1, len(pose_rotations)-1): # from second frame to second last frame + + nw, nx,ny,nz= pose_rotations[i+1] + wset= xset= yset= zset= True # we set all these by default + if abs((ow+nw)/2 - w) < 0.00001: wset= False + if abs((ox+nx)/2 - x) < 0.00001: xset= False + if abs((oy+ny)/2 - y) < 0.00001: yset= False + if abs((oz+nz)/2 - z) < 0.00001: zset= False + + if wset: curve_wquat.append((i+IMPORT_START_FRAME, w)) + if xset: curve_xquat.append((i+IMPORT_START_FRAME, x)) + if yset: curve_yquat.append((i+IMPORT_START_FRAME, y)) + if zset: curve_zquat.append((i+IMPORT_START_FRAME, z)) + + # Set the old and use the new + ow,ox,oy,oz= w,x,y,z + w,x,y,z= nw,nx,ny,nz + + # IPO KEYFRAME SETTING + """ + pose.update() + return arm_ob + + +#=============# +# TESTING # +#=============# + +#('/metavr/mocap/bvh/boxer.bvh') +#('/d/staggered_walk.bvh') +#('/metavr/mocap/bvh/dg-306-g.bvh') # Incompleate EOF +#('/metavr/mocap/bvh/wa8lk.bvh') # duplicate joint names, \r line endings. +#('/metavr/mocap/bvh/walk4.bvh') # 0 channels + +''' +import os +DIR = '/metavr/mocap/bvh/' +for f in ('/d/staggered_walk.bvh',): + #for f in os.listdir(DIR)[5:6]: + #for f in os.listdir(DIR): + if f.endswith('.bvh'): + s = Blender.Scene.New(f) + s.makeCurrent() + #file= DIR + f + file= f + print f + bvh_nodes= read_bvh(file, 1.0) + bvh_node_dict2armature(bvh_nodes, 1) +''' + +def load_bvh_ui(file, PREF_UI= True): + + if BPyMessages.Error_NoFile(file): + return + + Draw= Blender.Draw + + IMPORT_SCALE = Draw.Create(0.1) + IMPORT_START_FRAME = Draw.Create(1) + IMPORT_AS_ARMATURE = Draw.Create(1) + IMPORT_AS_EMPTIES = Draw.Create(0) + IMPORT_LOOP = Draw.Create(0) + + # Get USER Options + if PREF_UI: + pup_block = [\ + ('As Armature', IMPORT_AS_ARMATURE, 'Imports the BVH as an armature'),\ + ('As Empties', IMPORT_AS_EMPTIES, 'Imports the BVH as empties'),\ + ('Scale: ', IMPORT_SCALE, 0.001, 100.0, 'Scale the BVH, Use 0.01 when 1.0 is 1 metre'),\ + ('Start Frame: ', IMPORT_START_FRAME, 1, 30000, 'Frame to start BVH motion'),\ + ('Loop Animation', IMPORT_LOOP, 'Enable cyclic IPOs'),\ + ] + + if not Draw.PupBlock('BVH Import...', pup_block): + return + + print 'Attempting import BVH', file + + IMPORT_SCALE = IMPORT_SCALE.val + IMPORT_START_FRAME = IMPORT_START_FRAME.val + IMPORT_AS_ARMATURE = IMPORT_AS_ARMATURE.val + IMPORT_AS_EMPTIES = IMPORT_AS_EMPTIES.val + IMPORT_LOOP = IMPORT_LOOP.val + + if not IMPORT_AS_ARMATURE and not IMPORT_AS_EMPTIES: + Blender.Draw.PupMenu('No import option selected') + return + Blender.Window.WaitCursor(1) + # Get the BVH data and act on it. + t1= Blender.sys.time() + print '\tpassing bvh...', + bvh_nodes= read_bvh(file, IMPORT_SCALE) + print '%.4f' % (Blender.sys.time()-t1) + t1= Blender.sys.time() + print '\timporting to blender...', + if IMPORT_AS_ARMATURE: bvh_node_dict2armature(bvh_nodes, IMPORT_START_FRAME, IMPORT_LOOP) + if IMPORT_AS_EMPTIES: bvh_node_dict2objects(bvh_nodes, IMPORT_START_FRAME, IMPORT_LOOP) + + print 'Done in %.4f\n' % (Blender.sys.time()-t1) + Blender.Window.WaitCursor(0) + +def main(): + Blender.Window.FileSelector(load_bvh_ui, 'Import BVH', '*.bvh') + +if __name__ == '__main__': + #def foo(): + main() + ''' + scn = bpy.data.scenes.active + for ob in list(scn.objects): + if ob.name!='arm__': + scn.objects.unlink(ob) + load_bvh_ui('/test.bvh', False) + ''' \ No newline at end of file diff --git a/release/scripts/camera_changer.py b/release/scripts/camera_changer.py new file mode 100644 index 00000000000..7ae1bd64c8c --- /dev/null +++ b/release/scripts/camera_changer.py @@ -0,0 +1,121 @@ +#!BPY + +""" Registration info for Blender menus: <- these words are ignored +Name: 'Camera Changer' +Blender: 234 +Group: 'Animation' +Tip: 'Create script link to change cameras (based on their names) during an animation' +""" + +__author__ = '3R - R3gis' +__version__ = '1.2' +__url__ = ["Author's site , http://cybercreator.free.fr", "French Blender support forum, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender"] +__email__=["3R, r3gis@free.fr"] + + +__bpydoc__ = """\ +This script creates an script link to change cameras during an animation. + +The created script link (a Blender Text) is linked to Scene Frame Changed events. + +Usage: + +Run the script, then name the camera Object with the number of the frame(s) +where you want this camera to become active. + +For example:
+ - a camera called "10" will become active at frame 10.
+ - a camera called "10,25,185" will become active at frames 10, 25 and 185. + +Notes:
+ - This script creates another script named camera.py, which is linked to the current scene.
+ - If there is already a text called "camera.py", but it's from an old version or is not recognized, +you can choose if you want to rename or overwrite it. + - Script inspired by Jean-Michel (jms) Soler's:
+ http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_changerdecamera.htm +""" + + +# $Id$ +# +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2004-2005: Regis Montoya +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +#Script inspired of the idea of this one : +#http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_changerdecamera.htm +# +#---------------------------------------------- +# R3gis Montoya (3R) +# +# Pout tout probleme a: +# cybercreator@free.fr +# --------------------------------------------- + +import Blender +from Blender import * +import string + +header = '# camera.py 1.3 scriptlink' + +camera_change_scriptlink = header + \ +''' +import Blender +def main(): + scn = Blender.Scene.GetCurrent() + frame = str(Blender.Get('curframe')) + + # change the camera if it has the current frame + for ob_cam in [ob for ob in scn.objects if ob.type == 'Camera']: + for number in ob_cam.name.split(','): + if number == frame: + scn.setCurrentCamera(ob_cam) + return +main() +''' + +def main(): + + # Get the text + try: cam_text = Blender.Text.Get('camera.py') + except: cam_text = None + + if cam_text: + if cam_text.asLines()[0] != header: + ret = Blender.Draw.PupMenu("WARNING: An old camera.py exists%t|Overwrite|Rename old version text") + if ret == -1: return # EXIT DO NOTHING + elif ret == 1: Text.unlink(cam_text) + elif ret == 2: cam_text.name = 'old_camera.txt' + cam_text = None + + if not cam_text: + scripting=Blender.Text.New('camera.py') + scripting.write(camera_change_scriptlink) + + scn=Scene.GetCurrent() + scriptlinks = scn.getScriptLinks('FrameChanged') + if not scriptlinks or ('camera.py' not in scriptlinks): + scn.addScriptLink('camera.py','FrameChanged') + Blender.Draw.PupMenu('FrameChange Scriptlink Added%t|Name camera objects to their activation frame numbers(s) seperated by commas|valid names are "1,10,46" or "1,10,200" or "200" (without quotation marks)') + Blender.Window.RedrawAll() + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/release/scripts/config.py b/release/scripts/config.py new file mode 100644 index 00000000000..69f929dab97 --- /dev/null +++ b/release/scripts/config.py @@ -0,0 +1,797 @@ +#!BPY + +""" +Name: 'Scripts Config Editor' +Blender: 236 +Group: 'System' +Tooltip: 'View and edit available scripts configuration data' +""" + +__author__ = "Willian P. Germano" +__version__ = "0.1 2005/04/14" +__email__ = ('scripts', 'Author, wgermano:ig*com*br') +__url__ = ('blender', 'elysiun') + +__bpydoc__ ="""\ +This script can be used to view and edit configuration data stored +by other scripts. + +Technical: this data is saved as dictionary keys with the +Blender.Registry module functions. It is persistent while Blender is +running and, if the script's author chose to, is also saved to a file +in the scripts config data dir. + +Usage: + +- Start Screen: + +To access any available key, select it from (one of) the menu(s). + +Hotkeys:
+ ESC or Q: [Q]uit
+ H: [H]elp + +- Keys Config Screen: + +This screen exposes the configuration data for the chosen script key. If the +buttons don't fit completely on the screen, you can scroll up or down with +arrow keys or a mouse wheel. Leave the mouse pointer over any button to get +a tooltip about that option. + +Any change can be reverted -- unless you have already applied it. + +If the key is already stored in a config file, there will be a toggle button +(called 'file') that controls whether the changes will be written back to +the file or not. If you just want to change the configuration for the current +session, simply unset that button. Note, though, that data from files has +precedence over those keys already loaded in Blender, so if you re-run this +config editor, unsaved changes will not be seen. + +Hotkeys:
+ ESC: back to Start Screen
+ Q: [Q]uit
+ U: [U]ndo changes
+ ENTER: apply changes (can't be reverted, then)
+ UP, DOWN Arrows and mouse wheel: scroll text up / down + +Notes: + +a) Available keys are determined by which scripts you use. If the key you +expect isn't available (or maybe there are none or too few keys), either the +related script doesn't need or still doesn't support this feature or the key +has not been stored yet, in which case you just need to run that script once +to make its config data available. + +b) There are two places where config data files can be saved: the +bpydata/config/ dir (1) inside the default scripts dir or (2) inside the user +defined Python scripts dir +(User Preferences window -> File Paths tab -> Python path). If available, +(2) is the default and also the recommended option, because then fresh Blender +installations won't delete your config data. To use this option, simply set a +dir for Python scripts at the User Preferences window and make sure this dir +has the subdirs bpydata/ and bpydata/config/ inside it. + +c) The key called "General" in the "Other" menu has general config options. +All scripts where that data is relevant are recommended to access it and set +behaviors accordingly. +""" + +# $Id$ +# +# -------------------------------------------------------------------------- +# config.py version 0.1 2005/04/08 +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2004: Willian P. Germano, wgermano _at_ ig.com.br +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender +from Blender import Draw, BGL, Registry, Window, sys as bsys +from Blender.Window import Theme +from BPyRegistry import LoadConfigData, SaveConfigData, HasConfigData,\ + BPY_KEY_IN_FILE + +MAX_STR_LEN = 300 # max length for a string +MAX_ITEMS_NUM = 100 # max number for each type of button + +# --- +# The "General" configure options key is managed from this script. +verbose = True +confirm_overwrite = True + +tooltips = { + 'verbose': 'print script messages (info, warnings, errors) to the console', + 'confirm_overwrite': 'scripts should always confirm before overwriting files' +} + +CFG_LIST = ['verbose', 'confirm_overwrite', 'tooltips'] +KEY_NAME = 'General' + +def update_registry(): + rd = {} + for var in CFG_LIST: + exec("rd['%s']=%s" % (var, var)) + Registry.SetKey(KEY_NAME, rd, True) + +rd = Registry.GetKey('General', True) +if rd: + try: + for var in CFG_LIST[:-1]: # no need to update tooltips + exec("%s=rd['%s']" % (var, var)) + except: update_registry() + +else: + update_registry() +# --- + +# script globals: +CFGKEY = '' +LABELS = [] +GD = {} # groups dict (includes "Other" for unmapped keys) +INDEX = 0 # to pass button indices to fs callbacks +FREEKEY_IDX = 0 # index of set of keys not mapped to a script name +KEYMENUS = [] +ALL_SCRIPTS = {} +ALL_GROUPS = [] +START_SCREEN = 0 +CONFIG_SCREEN = 1 +DISK_UPDATE = True # write changed data to its config file + +ACCEPTED_TYPES = [bool, int, float, str, unicode] + +SCREEN = START_SCREEN + +SCROLL_DOWN = 0 + +# events: +BEVT_START = 50 +BEVT_EXIT = 0 + BEVT_START +BEVT_BACK = 1 + BEVT_START +BEVT_DISK = 2 + BEVT_START +BEVT_CANCEL = 3 + BEVT_START +BEVT_APPLY = 4 + BEVT_START +BEVT_HELP = 5 + BEVT_START +BEVT_DEL = 6 + BEVT_START +BEVT_KEYMENU = [] +BUT_KEYMENU = [] +BEVT_BOOL = 100 +BEVT_INT = BEVT_BOOL + MAX_ITEMS_NUM +BEVT_FLOAT = BEVT_BOOL + 2*MAX_ITEMS_NUM +BEVT_STR = BEVT_BOOL + 3*MAX_ITEMS_NUM +BEVT_BROWSEDIR = BEVT_BOOL + 4*MAX_ITEMS_NUM +BEVT_BROWSEFILE = BEVT_BOOL + 5*MAX_ITEMS_NUM +BUT_TYPES = { + bool: 0, + int: 0, + float: 0, + str: 0 +} + +# Function definitions: + +def get_keys(): + LoadConfigData() # loads all data from files in (u)scripts/bpydata/config/ + return [k for k in Registry.Keys() if k[0] != "_"] + + +def show_help(script = 'config.py'): + Blender.ShowHelp(script) + + +def fs_dir_callback(pathname): + global CFGKEY, INDEX + + pathname = bsys.dirname(pathname) + datatypes = CFGKEY.sorteddata + datatypes[str][INDEX][1] = pathname + + +def fs_file_callback(pathname): + global CFGKEY, INDEX + + datatypes = CFGKEY.sorteddata + datatypes[str][INDEX][1] = pathname + + +# parse Bpymenus file to get all script filenames +# (used to show help for a given key) +def fill_scripts_dict(): + global ALL_SCRIPTS, ALL_GROUPS + + group = '' + group_len = 0 + sep = bsys.sep + home = Blender.Get('homedir') + if not home: + errmsg = """ +Can't find Blender's home dir and so can't find the +Bpymenus file automatically stored inside it, which +is needed by this script. Please run the +Help -> System -> System Information script to get +information about how to fix this. +""" + raise SystemError, errmsg + fname = bsys.join(home, 'Bpymenus') + if not bsys.exists(fname): return False + f = file(fname, 'r') + lines = f.readlines() + f.close() + for l in lines: + if l.rfind('{') > 0: + group = l.split()[0] + ALL_GROUPS.append(group) + group_len += 1 + continue + elif l[0] != "'": continue + fields = l.split("'") + if len(fields) > 2: + menuname = fields[1].replace('...','') + fields = fields[2].split() + if len(fields) > 1: + fname = fields[1].split(sep)[-1] + ALL_SCRIPTS[fname] = (menuname, group_len - 1) + return True + + +def map_to_registered_script(name): + global ALL_SCRIPTS + + if not name.endswith('.py'): + name = "%s.py" % name + if ALL_SCRIPTS.has_key(name): + return ALL_SCRIPTS[name] # == (menuname, group index) + return None + + +def reset(): + global LABELS, GD, KEYMENUS, KEYS + + # init_data is recalled when a key is deleted, so: + LABELS = [] + GD = {} + KEYMENUS = [] + KEYS = get_keys() + + +# gather all script info, fill gui menus +def init_data(): + global KEYS, GD, ALL_GROUPS, ALL_SCRIPTS, KEYMENUS, LABELS + global BUT_KEYMENU, BEVT_KEYMENU, FREEKEY_IDX + + for k in ALL_GROUPS: + GD[k] = [] + GD[None] = [] + + for k in KEYS: + res = map_to_registered_script(k) + if res: + GD[ALL_GROUPS[res[1]]].append((k, res[0])) + else: GD[None].append((k, k)) + + for k in GD.keys(): + if not GD[k]: GD.pop(k) + + if GD.has_key(None): + GD['Other'] = GD[None] + GD.pop(None) + FREEKEY_IDX = -1 + + BUT_KEYMENU = range(len(GD)) + + for k in GD.keys(): + kmenu = ['Configuration Keys: %s%%t' % k] + for j in GD[k]: + kmenu.append(j[1]) + kmenu = "|".join(kmenu) + KEYMENUS.append(kmenu) + LABELS.append(k) + + if FREEKEY_IDX < 0: + FREEKEY_IDX = LABELS.index('Other') + + length = len(KEYMENUS) + BEVT_KEYMENU = range(1, length + 1) + BUT_KEYMENU = range(length) + + +# for theme colors: +def float_colors(cols): + return map(lambda x: x / 255.0, cols) + + + +class Config: + + def __init__(self, key, has_group = True): + global DISK_UPDATE + + self.key = key + self.has_group = has_group + self.name = key + self.fromdisk = HasConfigData(key) & BPY_KEY_IN_FILE + if not self.fromdisk: DISK_UPDATE = False + else: DISK_UPDATE = True + + self.origdata = Registry.GetKey(key, True) + data = self.data = self.origdata.copy() + + if not data: + Draw.PupMenu('ERROR: couldn\'t find requested data') + self.data = None + return + + keys = data.keys() + nd = {} + for k in keys: + nd[k.lower()] = k + + if nd.has_key('tooltips'): + ndval = nd['tooltips'] + self.tips = data[ndval] + data.pop(ndval) + else: self.tips = 0 + + if nd.has_key('limits'): + ndval = nd['limits'] + self.limits = data[ndval] + data.pop(ndval) + else: self.limits = 0 + + if self.has_group: + scriptname = key + if not scriptname.endswith('.py'): + scriptname = "%s.py" % scriptname + elif nd.has_key('script'): + ndval = nd['script'] + scriptname = data[ndval] + data.pop(ndval) + if not scriptname.endswith('.py'): + scriptname = "%s.py" % scriptname + else: scriptname = None + + self.scriptname = scriptname + + self.sort() + + + def needs_update(self): # check if user changed data + data = self.data + new = self.sorteddata + + for vartype in new.keys(): + for i in new[vartype]: + if data[i[0]] != i[1]: return 1 + + return 0 # no changes + + + def update(self): # update original key + global DISK_UPDATE + + data = self.data + odata = self.origdata + new = self.sorteddata + for vartype in new.keys(): + for i in new[vartype]: + if data[i[0]] != i[1]: data[i[0]] = i[1] + if odata[i[0]] != i[1]: odata[i[0]] = i[1] + + if DISK_UPDATE: Registry.SetKey(self.key, odata, True) + + def delete(self): + global DISK_UPDATE + + delmsg = 'OK?%t|Delete key from memory' + if DISK_UPDATE: + delmsg = "%s and from disk" % delmsg + if Draw.PupMenu(delmsg) == 1: + Registry.RemoveKey(self.key, DISK_UPDATE) + return True + + return False + + + def revert(self): # revert to original key + data = self.data + new = self.sorteddata + for vartype in new.keys(): + for i in new[vartype]: + if data[i[0]] != i[1]: i[1] = data[i[0]] + + + def sort(self): # create a new dict with types as keys + global ACCEPTED_TYPES, BUT_TYPES + + data = self.data + datatypes = {} + keys = [k for k in data.keys() if k[0] != '_'] + for k in keys: + val = data[k] + tval = type(val) + if tval not in ACCEPTED_TYPES: continue + if not datatypes.has_key(tval): + datatypes[tval] = [] + datatypes[type(val)].append([k, val]) + if datatypes.has_key(unicode): + if not datatypes.has_key(str): datatypes[str] = datatypes[unicode] + else: + for i in datatypes[unicode]: datatypes[str].append(i) + datatypes.pop(unicode) + for k in datatypes.keys(): + dk = datatypes[k] + dk.sort() + dk.reverse() + BUT_TYPES[k] = range(len(dk)) + self.sorteddata = datatypes + + +# GUI: + +# gui callbacks: + +def gui(): # drawing the screen + + global SCREEN, START_SCREEN, CONFIG_SCREEN, KEYMENUS, LABELS + global BEVT_KEYMENU, BUT_KEYMENU, CFGKEY + global BUT_TYPES, SCROLL_DOWN, VARS_NUM + + WIDTH, HEIGHT = Window.GetAreaSize() + + theme = Theme.Get()[0] + tui = theme.get('ui') + ttxt = theme.get('text') + + COL_BG = float_colors(ttxt.back) + COL_TXT = ttxt.text + COL_TXTHI = ttxt.text_hi + + BGL.glClearColor(COL_BG[0],COL_BG[1],COL_BG[2],COL_BG[3]) + BGL.glClear(BGL.GL_COLOR_BUFFER_BIT) + BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2]) + + if SCREEN == START_SCREEN: + x = 10 + y = 10 + h = 20 + w = 90 + BGL.glRasterPos2i(x, y) + Draw.Text('Select a configuration key to access it. Press Q or ESC to leave.') + km_len = len(KEYMENUS) + km_columns = (WIDTH - x) / w + if km_columns == 0: km_rows = km_len + else: + km_rows = km_len / km_columns + if (km_len % km_columns): km_rows += 1 + if km_rows == 0: km_rows = 1 + ystart = y + 2*h*km_rows + if ystart > (HEIGHT - 70): ystart = HEIGHT - 70 + y = ystart + column = 1 + for i, km in enumerate(KEYMENUS): + column += 1 + BGL.glRasterPos2i(x + 2, y + h + 5) + Draw.Text(LABELS[i]) + BUT_KEYMENU[i] = Draw.Menu(km, BEVT_KEYMENU[i], + x, y, w - 10, h, 0, 'Choose a key to access its configuration data') + if column > km_columns: + column = 1 + y -= 2*h + if y < 35: break + x = 10 + else: x += w + x = 10 + y = 50 + ystart + BGL.glColor3ub(COL_TXTHI[0], COL_TXTHI[1], COL_TXTHI[2]) + BGL.glRasterPos2i(x, y) + Draw.Text('Scripts Configuration Editor') + Draw.PushButton('help', BEVT_HELP, x, 22, 45, 16, + 'View help information about this script (hotkey: H)') + + elif SCREEN == CONFIG_SCREEN: + x = y = 10 + h = 18 + data = CFGKEY.sorteddata + tips = CFGKEY.tips + fromdisk = CFGKEY.fromdisk + limits = CFGKEY.limits + VARS_NUM = 0 + for k in data.keys(): + VARS_NUM += len(data[k]) + lines = VARS_NUM + 5 # to account for header and footer + y = lines*h + if y > HEIGHT - 20: y = HEIGHT - 20 + BGL.glColor3ub(COL_TXTHI[0],COL_TXTHI[1], COL_TXTHI[2]) + BGL.glRasterPos2i(x, y) + Draw.Text('Scripts Configuration Editor') + y -= 20 + BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2]) + txtsize = 10 + if HEIGHT < lines*h: + BGL.glRasterPos2i(10, 5) + txtsize += Draw.Text('Arrow keys or mouse wheel to scroll, ') + BGL.glRasterPos2i(txtsize, 5) + Draw.Text('Q or ESC to return.') + BGL.glRasterPos2i(x, y) + Draw.Text('Key: "%s"' % CFGKEY.name) + bh = 16 + bw = 45 + by = 16 + i = -1 + if CFGKEY.scriptname: + i = 0 + Draw.PushButton('help', BEVT_HELP, x, by, bw, bh, + 'Show documentation for the script that owns this key (hotkey: H)') + Draw.PushButton('back', BEVT_BACK, x + (1+i)*bw, by, bw, bh, + 'Back to config keys selection screen (hotkey: ESC)') + Draw.PushButton('exit', BEVT_EXIT, x + (2+i)*bw, by, bw, bh, + 'Exit from Scripts Config Editor (hotkey: Q)') + Draw.PushButton('revert', BEVT_CANCEL, x + (3+i)*bw, by, bw, bh, + 'Revert data to original values (hotkey: U)') + Draw.PushButton('apply', BEVT_APPLY, x + (4+i)*bw, by, bw, bh, + 'Apply changes, if any (hotkey: ENTER)') + delmsg = 'Delete this data key from memory' + if fromdisk: delmsg = "%s and from disk" % delmsg + Draw.PushButton('delete', BEVT_DEL, x + (5+i)*bw, by, bw, bh, + '%s (hotkey: DELETE)' % delmsg) + if fromdisk: + Draw.Toggle("file", BEVT_DISK, x + 3 + (6+i)*bw, by, bw, bh, DISK_UPDATE, + 'Update also the file where this config key is stored') + i = -1 + top = -1 + y -= 20 + yend = 30 + if data.has_key(bool) and y > 0: + lst = data[bool] + for l in lst: + top += 1 + i += 1 + if top < SCROLL_DOWN: continue + y -= h + if y < yend: break + w = 20 + tog = data[bool][i][1] + if tips and tips.has_key(l[0]): tooltip = tips[l[0]] + else: tooltip = "click to toggle" + BUT_TYPES[bool][i] = Draw.Toggle("", BEVT_BOOL + i, + x, y, w, h, tog, tooltip) + BGL.glRasterPos2i(x + w + 3, y + 5) + Draw.Text(l[0].lower().replace('_', ' ')) + i = -1 + y -= 5 + if data.has_key(int) and y > 0: + lst = data[int] + for l in lst: + w = 70 + top += 1 + i += 1 + if top < SCROLL_DOWN: continue + y -= h + if y < yend: break + val = data[int][i][1] + if limits: min, max = limits[l[0]] + else: min, max = 0, 10 + if tips and tips.has_key(l[0]): tooltip = tips[l[0]] + else: tooltip = "click / drag to change" + BUT_TYPES[int][i] = Draw.Number("", BEVT_INT + i, + x, y, w, h, val, min, max, tooltip) + BGL.glRasterPos2i(x + w + 3, y + 3) + Draw.Text(l[0].lower().replace('_', ' ')) + i = -1 + y -= 5 + if data.has_key(float) and y > 0: + lst = data[float] + for l in lst: + w = 70 + top += 1 + i += 1 + if top < SCROLL_DOWN: continue + y -= h + if y < yend: break + val = data[float][i][1] + if limits: min, max = limits[l[0]] + else: min, max = 0.0, 1.0 + if tips and tips.has_key(l[0]): tooltip = tips[l[0]] + else: tooltip = "click and drag to change" + BUT_TYPES[float][i] = Draw.Number("", BEVT_FLOAT + i, + x, y, w, h, val, min, max, tooltip) + BGL.glRasterPos2i(x + w + 3, y + 3) + Draw.Text(l[0].lower().replace('_', ' ')) + i = -1 + y -= 5 + if data.has_key(str) and y > 0: + lst = data[str] + for l in lst: + top += 1 + i += 1 + if top < SCROLL_DOWN: continue + y -= h + if y < yend: break + name = l[0].lower() + is_dir = is_file = False + if name.find('_dir', -4) > 0: is_dir = True + elif name.find('_file', -5) > 0: is_file = True + w = WIDTH - 20 + wbrowse = 50 + if is_dir and w > wbrowse: w -= wbrowse + if tips and tips.has_key(l[0]): tooltip = tips[l[0]] + else: tooltip = "click to write a new string" + name = name.replace('_',' ') + ': ' + if len(l[1]) > MAX_STR_LEN: + l[1] = l[1][:MAX_STR_LEN] + BUT_TYPES[str][i] = Draw.String(name, BEVT_STR + i, + x, y, w, h, l[1], MAX_STR_LEN, tooltip) + if is_dir: + Draw.PushButton('browse', BEVT_BROWSEDIR + i, x+w+1, y, wbrowse, h, + 'click to open a file selector (pick any file in the desired dir)') + elif is_file: + Draw.PushButton('browse', BEVT_BROWSEFILE + i, x + w + 1, y, 50, h, + 'click to open a file selector') + + +def fit_scroll(): + global SCROLL_DOWN, VARS_NUM + max = VARS_NUM - 1 # so last item is always visible + if SCROLL_DOWN > max: + SCROLL_DOWN = max + elif SCROLL_DOWN < 0: + SCROLL_DOWN = 0 + + +def event(evt, val): # input events + + global SCREEN, START_SCREEN, CONFIG_SCREEN + global SCROLL_DOWN, CFGKEY + + if not val: return + + if evt == Draw.ESCKEY: + if SCREEN == START_SCREEN: Draw.Exit() + else: + if CFGKEY.needs_update(): + if Draw.PupMenu('UPDATE?%t|Data was changed') == 1: + CFGKEY.update() + SCREEN = START_SCREEN + SCROLL_DOWN = 0 + Draw.Redraw() + return + elif evt == Draw.QKEY: + if SCREEN == CONFIG_SCREEN and CFGKEY.needs_update(): + if Draw.PupMenu('UPDATE?%t|Data was changed') == 1: + CFGKEY.update() + Draw.Exit() + return + elif evt == Draw.HKEY: + if SCREEN == START_SCREEN: show_help() + elif CFGKEY.scriptname: show_help(CFGKEY.scriptname) + return + + elif SCREEN == CONFIG_SCREEN: + if evt in [Draw.DOWNARROWKEY, Draw.WHEELDOWNMOUSE]: + SCROLL_DOWN += 1 + fit_scroll() + elif evt in [Draw.UPARROWKEY, Draw.WHEELUPMOUSE]: + SCROLL_DOWN -= 1 + fit_scroll() + elif evt == Draw.UKEY: + if CFGKEY.needs_update(): + CFGKEY.revert() + elif evt == Draw.RETKEY or evt == Draw.PADENTER: + if CFGKEY.needs_update(): + CFGKEY.update() + elif evt == Draw.DELKEY: + if CFGKEY.delete(): + reset() + init_data() + SCREEN = START_SCREEN + SCROLL_DOWN = 0 + else: return + Draw.Redraw() + + +def button_event(evt): # gui button events + + global SCREEN, START_SCREEN, CONFIG_SCREEN, CFGKEY, DISK_UPDATE + global BEVT_KEYMENU, BUT_KEYMENU, BUT_TYPES, SCROLL_DOWN, GD, INDEX + global BEVT_EXIT, BEVT_BACK, BEVT_APPLY, BEVT_CANCEL, BEVT_HELP, FREEKEY_IDX + + if SCREEN == START_SCREEN: + for e in BEVT_KEYMENU: + if evt == e: + index = e - 1 + k = BUT_KEYMENU[index].val - 1 + CFGKEY = Config(GD[LABELS[index]][k][0], index != FREEKEY_IDX) + if CFGKEY.data: + SCREEN = CONFIG_SCREEN + Draw.Redraw() + return + if evt == BEVT_EXIT: + Draw.Exit() + elif evt == BEVT_HELP: + show_help() + return + + elif SCREEN == CONFIG_SCREEN: + datatypes = CFGKEY.sorteddata + if evt >= BEVT_BROWSEFILE: + INDEX = evt - BEVT_BROWSEFILE + Window.FileSelector(fs_file_callback, 'Choose file') + elif evt >= BEVT_BROWSEDIR: + INDEX = evt - BEVT_BROWSEDIR + Window.FileSelector(fs_dir_callback, 'Choose any file') + elif evt >= BEVT_STR: + var = BUT_TYPES[str][evt - BEVT_STR].val + datatypes[str][evt - BEVT_STR][1] = var + elif evt >= BEVT_FLOAT: + var = BUT_TYPES[float][evt - BEVT_FLOAT].val + datatypes[float][evt - BEVT_FLOAT][1] = var + elif evt >= BEVT_INT: + var = BUT_TYPES[int][evt - BEVT_INT].val + datatypes[int][evt - BEVT_INT][1] = var + elif evt >= BEVT_BOOL: + var = datatypes[bool][evt - BEVT_BOOL][1] + if var == True: var = False + else: var = True + datatypes[bool][evt - BEVT_BOOL][1] = var + + elif evt == BEVT_BACK: + if SCREEN == CONFIG_SCREEN: + SCREEN = START_SCREEN + SCROLL_DOWN = 0 + Draw.Redraw() + elif evt == BEVT_EXIT: + if CFGKEY.needs_update(): + if Draw.PupMenu('UPDATE?%t|Data was changed') == 1: + CFGKEY.update() + Draw.Exit() + return + elif evt == BEVT_APPLY: + if CFGKEY.needs_update(): + CFGKEY.update() + elif evt == BEVT_CANCEL: + if CFGKEY.needs_update(): + CFGKEY.revert() + elif evt == BEVT_DEL: + if CFGKEY.delete(): + reset() + init_data() + SCREEN = START_SCREEN + SCROLL_DOWN = 0 + elif evt == BEVT_DISK: + if DISK_UPDATE: DISK_UPDATE = False + else: DISK_UPDATE = True + elif evt == BEVT_HELP: + show_help(CFGKEY.scriptname) + return + else: + return + Draw.Redraw() + +# End of definitions + + +KEYS = get_keys() + +if not KEYS: + Draw.PupMenu("NO DATA: please read this help screen") + Blender.ShowHelp('config.py') +else: + fill_scripts_dict() + init_data() + Draw.Register(gui, event, button_event) diff --git a/release/scripts/console.py b/release/scripts/console.py new file mode 100644 index 00000000000..7d9d8be5e9e --- /dev/null +++ b/release/scripts/console.py @@ -0,0 +1,849 @@ +#!BPY + +""" +Name: 'Interactive Console' +Blender: 237 +Group: 'System' +Tooltip: 'Interactive Python Console' +""" + +__author__ = "Campbell Barton AKA Ideasman" +__url__ = ["Author's homepage, http://members.iinet.net.au/~cpbarton/ideasman/", "blender", "elysiun", "Official Python site, http://www.python.org"] +__bpydoc__ = """\ +This is an interactive console, similar to Python's own command line interpreter. Since it is embedded in Blender, it has access to all Blender Python modules. + +Those completely new to Python are recommended to check the link button above +that points to its official homepage, with news, downloads and documentation. + +Usage:
+ Type your code and hit "Enter" to get it executed.
+ - Right mouse click: Console Menu (Save output, etc);
+ - Mousewheel: Scroll text + - Arrow keys: command history and cursor;
+ - Shift + Backspace: Backspace whole word;
+ - Shift + Arrow keys: jump words;
+ - Ctrl + (+/- or mousewheel): Zoom text size;
+ - Ctrl + Enter: auto compleate based on variable names and modules loaded -- multiple choices popup a menu;
+ - Shift + Enter: multiline functions -- delays executing code until only Enter is pressed. +""" +__author__ = "Campbell Barton AKA Ideasman" +__url__ = ["http://members.iinet.net.au/~cpbarton/ideasman/", "blender", "elysiun"] + +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender +import bpy +from Blender import * +import sys as python_sys +import StringIO + +# Constants +__DELIMETERS__ = '. ,=+-*/%<>&~][{}():\t' +__VARIABLE_DELIMETERS__ = ' ,=+-*/%<>&~{}():\t' + +__LINE_HISTORY__ = 500 + +global __FONT_SIZE__ + +__FONT_SIZES__ = ( ('tiny', 10), ('small', 12), ('normal', 14), ('large', 16) ) +__FONT_SIZE__ = 2 # index for the list above, normal default. + +global __CONSOLE_LINE_OFFSET__ +__CONSOLE_LINE_OFFSET__ = 0 + +''' +# Generic Blender functions +def getActScriptWinRect(): + area = Window.GetAreaSize() + area = (area[0]-1, area[1]-1) + for scrInfo in Window.GetScreenInfo(Window.Types['SCRIPT'], 'win', ''): + if scrInfo['vertices'][2]-scrInfo['vertices'][0] == area[0]: + if scrInfo['vertices'][3]-scrInfo['vertices'][1] == area[1]: + return scrInfo['vertices'] + return None +''' + + +# menuText, # per group +def PupMenuLess(menu, groupSize=35): + more = [' more...'] + less = [' less...'] + + menuList= menu.split('|') + + # No Less Needed, just call. + if len(menuList) < groupSize: + return Draw.PupMenu(menu) + + title = menuList[0].split('%t')[0] + + # Split the list into groups + menuGroups = [[]] + for li in menuList[1:]: + if len(menuGroups[-1]) < groupSize: + menuGroups[-1].append(li) + else: + menuGroups.append([li]) + + # Stores teh current menu group we are looking at + groupIdx = 0 + while 1: + # Give us a title with the menu number + numTitle = [ ' '.join([title, str(groupIdx + 1), 'of', str(len(menuGroups)), '%t'])] + if groupIdx == 0: + menuString = '|'.join(numTitle + menuGroups[groupIdx] + more) + elif groupIdx == len(menuGroups)-1: + menuString = '|'.join(numTitle + less + menuGroups[groupIdx]) + else: # In the middle somewhere so Show a more and less + menuString = '|'.join(numTitle + less + menuGroups[groupIdx] + more) + result = Draw.PupMenu(menuString) + # User Exit + if result == -1: + return -1 + + if groupIdx == 0: # First menu + if result-1 < groupSize: + return result + else: # must be more + groupIdx +=1 + elif groupIdx == len(menuGroups): # Last Menu + if result == 1: # Must be less + groupIdx -= 1 + else: # Must be a choice + return result + (groupIdx*groupSize) + + else: + if result == 1: # Must be less + groupIdx -= 1 + elif result-2 == groupSize: + groupIdx +=1 + else: + return result - 1 + (groupIdx*groupSize) + + + +# Use newstyle classes, Im not bothering with inheretence +# but slots are faster. +class cmdLine(object): + __slots__ = [\ + 'cmd', # is the command string, or any other message + 'type',# type: 0:user input 1:program feedback 2:error message. 3:option feedback + 'exe' # 0- not yet executed 1:executed + ] + def __init__(self, cmd, type, exe): + self.cmd = cmd + self.type = type + self.exe = exe + +# Include external file with internal namespace +def include(filename): + file = open(filename, 'r') + filedata = file.read() + file.close() + return compile(filedata, filename, 'exec') + +# Writes command line data to a blender text file. +def writeCmdData(cmdLineList, type): + if type == 3: + typeList = [0,1,2, 3, None] # all + else: + typeList = [type] # so we can use athe lists 'in' methiod + + newText = Text.New('command_output.py', 1) + for myCmd in cmdLineList: + if myCmd.type in typeList: # user input + newText.write('%s\n' % myCmd.cmd) + Draw.PupMenu('%s written' % newText.name) + +def insertCmdData(cmdBuffer): + texts = list(bpy.data.texts) + textNames = [tex.name for tex in texts] + if textNames: + choice = Draw.PupMenu('|'.join(textNames)) + if choice != -1: + text = texts[choice-1] + + # Add the text! + for l in text.asLines(): + cmdBuffer.append(cmdLine('%s ' % l, 0, 0)) + Draw.Redraw() + + +COLLECTED_VAR_NAMES = {} # a list of keys, each key has a list of absolute paths + +# Pain and simple recursice dir(), accepts a string +unused_types = str, dict, list, float, int, str, type, tuple, type(dir), type(None) +def rdir(dirString, depth=0): + #print ' ' * depth, dirString + # MAX DEPTH SET HERE + if depth > 5: + # print 'maxdepoth reached.' + return + + global COLLECTED_VAR_NAMES + dirStringSplit = dirString.split('.') + + exec('value=' + dirString) + + if type(value) in unused_types: + # print 'bad type' + return + dirList = dir(value) + + for dirItem in dirList: + if dirItem.startswith('_'): + continue + + dirData = None + try: + # Rare cases this can mess up, material.shader was a problem. + exec('dirData = %s.%s' % (dirString, dirItem)) + #print dirData + except: + # Dont bother with this data. + continue + #print 'HEY', dirData, dirItem + #if type(dirItem) != str: + # print dirItem, type(dirItem) + + if dirItem not in COLLECTED_VAR_NAMES: # .keys() + COLLECTED_VAR_NAMES[dirItem] = [] + + # Add the string + # splitD = dirString.split('"')[-2] + + # Example of dirString + # __CONSOLE_VAR_DICT__["Main"].scenes.active.render + + # Works but can be faster + # splitD = dirString.replace('__CONSOLE_VAR_DICT__["', '').replace('"]', '') + + splitD = dirString[22:].replace('"]', '') + + if splitD not in COLLECTED_VAR_NAMES[dirItem]: + # print dirItem, dirString, splitD, + COLLECTED_VAR_NAMES[dirItem].append(splitD) + + + # Stops recursice stuff, overlooping + #print type(dirItem) + #if type(dirData) == types.ClassType or \ + # type(dirData) == types.ModuleType: + type_dirData = type(dirData) + if type_dirData not in unused_types: + # print type(dirData), dirItem + # Dont loop up dirs for strings ints etc. + if dirItem not in dirStringSplit: + rdir( '%s.%s' % (dirString, dirItem), depth+1) + ''' + elif depth == 0: # Add local variables + # print type(dirData), dirItem + # Dont loop up dirs for strings ints etc. + if dirItem not in dirStringSplit: + rdir( '%s.%s' % (dirString, dirItem), depth+1) + ''' + +def recursive_dir(): + global COLLECTED_VAR_NAMES + + for name in __CONSOLE_VAR_DICT__: # .keys() + if not name.startswith('_'): # Dont pick names like __name__ + rdir('__CONSOLE_VAR_DICT__["%s"]' % name) + #print COLLECTED_VAR_NAMES + COLLECTED_VAR_NAMES[name] = [''] + return COLLECTED_VAR_NAMES + +# Runs the code line(s) the user has entered and handle errors +# As well as feeding back the output into the blender window. +def runUserCode(__USER_CODE_STRING__): + global __CONSOLE_VAR_DICT__ # We manipulate the variables here. loading and saving from localspace to this global var. + + # Open A File like object to write all output to, that would useually be printed. + python_sys.stdout.flush() # Get rid of whatever came before + __FILE_LIKE_STRING__ = StringIO.StringIO() # make a new file like string, this saves up from making a file. + __STD_OUTPUT__ = python_sys.stdout # we need to store the normal output. + python_sys.stdout=__FILE_LIKE_STRING__ # Now anything printed will be written to the file like string. + + # Try and run the user entered line(s) + try: + # Load all variabls from global dict to local space. + __TMP_VAR_NAME__ = __TMP_VAR__ = '' # so as not to raise an error when del'ing + + for __TMP_VAR_NAME__, __TMP_VAR__ in __CONSOLE_VAR_DICT__.items(): + exec('%s%s' % (__TMP_VAR_NAME__,'=__TMP_VAR__')) + del __TMP_VAR_NAME__ + del __TMP_VAR__ + + # Now all the vars are loaded, execute the code. # Newline thanks to phillip, + exec(compile(__USER_CODE_STRING__, 'blender_cmd.py', 'single')) #exec(compile(__USER_CODE_STRING__, 'blender_cmd.py', 'exec')) + + # Flush global dict, allow the user to remove items. + __CONSOLE_VAR_DICT__ = {} + + __TMP_VAR_NAME__ = '' # so as not to raise an error when del'ing + # Write local veriables to global __CONSOLE_VAR_DICT__ + for __TMP_VAR_NAME__ in dir(): + if __TMP_VAR_NAME__ != '__FILE_LIKE_STRING__' and\ + __TMP_VAR_NAME__ != '__STD_OUTPUT__' and\ + __TMP_VAR_NAME__ != '__TMP_VAR_NAME__' and\ + __TMP_VAR_NAME__ != '__USER_CODE_STRING__': + + # Execute the local > global coversion. + exec('%s%s' % ('__CONSOLE_VAR_DICT__[__TMP_VAR_NAME__]=', __TMP_VAR_NAME__)) + del __TMP_VAR_NAME__ + + except: # Prints the REAL exception. + error = '%s: %s' % (python_sys.exc_type, python_sys.exc_value) + for errorLine in error.split('\n'): + cmdBuffer.append(cmdLine(errorLine, 2, None)) # new line to type into + + python_sys.stdout = __STD_OUTPUT__ # Go back to output to the normal blender console + + # Copy all new output to cmdBuffer + + __FILE_LIKE_STRING__.seek(0) # the readline function requires that we go back to the start of the file. + + for line in __FILE_LIKE_STRING__.readlines(): + cmdBuffer.append(cmdLine(line, 1, None)) + + cmdBuffer.append(cmdLine(' ', 0, 0)) # new line to type into + python_sys.stdout=__STD_OUTPUT__ + __FILE_LIKE_STRING__.close() + + + + + +#------------------------------------------------------------------------------# +# event handling code # +#------------------------------------------------------------------------------# +def handle_event(evt, val): + + # Insert Char into the cammand line + def insCh(ch): # Instert a char + global cmdBuffer + global cursor + # Later account for a cursor variable + cmdBuffer[-1].cmd = ('%s%s%s' % ( cmdBuffer[-1].cmd[:cursor], ch, cmdBuffer[-1].cmd[cursor:])) + + #------------------------------------------------------------------------------# + # Define Complex Key Actions # + #------------------------------------------------------------------------------# + def actionEnterKey(): + global histIndex, cursor, cmdBuffer + + def getIndent(string): + # Gather white space to add in the previous line + # Ignore the last char since its padding. + whiteSpace = '' + #for i in range(len(cmdBuffer[-1].cmd)): + for i in xrange(len(string)-1): + if cmdBuffer[-1].cmd[i] == ' ' or cmdBuffer[-1].cmd[i] == '\t': + whiteSpace += string[i] + else: + break + return whiteSpace + + # Autocomplete + if Window.GetKeyQualifiers() & Window.Qual.CTRL: + actionAutoCompleate() + return + + # Are we in the middle of a multiline part or not? + # try be smart about it + if cmdBuffer[-1].cmd.split('#')[0].rstrip().endswith(':'): + # : indicates an indent is needed + cmdBuffer.append(cmdLine('\t%s ' % getIndent(cmdBuffer[-1].cmd), 0, 0)) + print ': indicates an indent is needed' + + elif cmdBuffer[-1].cmd[0] in [' ', '\t'] and len(cmdBuffer[-1].cmd) > 1 and cmdBuffer[-1].cmd.split(): + # white space at the start means he havnt finished the multiline. + cmdBuffer.append(cmdLine('%s ' % getIndent(cmdBuffer[-1].cmd), 0, 0)) + print 'white space at the start means he havnt finished the multiline.' + + elif Window.GetKeyQualifiers() & Window.Qual.SHIFT: + # Crtl forces multiline + cmdBuffer.append(cmdLine('%s ' % getIndent(cmdBuffer[-1].cmd), 0, 0)) + print 'Crtl forces multiline' + + else: # Execute multiline code block + + # Multiline code will still run with 1 line, + multiLineCode = ['if 1:'] # End of the multiline first. + + # Seek the start of the file multiline + i = 1 + while cmdBuffer[-i].exe == 0: + i+=1 + + while i > 1: + i-=1 + + if cmdBuffer[-i].cmd == ' ':# Tag as an output type so its not used in the key history + cmdBuffer[-i].type = 1 + else: # Tab added at the start for added if 1: statement + multiLineCode.append('\t%s' % cmdBuffer[-i].cmd ) + + # Mark as executed + cmdBuffer[-i].exe = 1 + + multiLineCode.append('\tpass') # reverse will make this the start. + + # Dubug, print the code that is executed. + #for m in multiLineCode: print m + + runUserCode('\n'.join(multiLineCode)) + + # Clear the output based on __LINE_HISTORY__ + if len(cmdBuffer) > __LINE_HISTORY__: + cmdBuffer = cmdBuffer[-__LINE_HISTORY__:] + + histIndex = cursor = -1 # Reset cursor and history + + def actionUpKey(): + global histIndex, cmdBuffer + if abs(histIndex)+1 >= len(cmdBuffer): + histIndex = -1 + histIndex -= 1 + while cmdBuffer[histIndex].type != 0 and abs(histIndex) < len(cmdBuffer): + histIndex -= 1 + if cmdBuffer[histIndex].type == 0: # we found one + cmdBuffer[-1].cmd = cmdBuffer[histIndex].cmd + + def actionDownKey(): + global histIndex, cmdBuffer + if histIndex >= -2: + histIndex = -len(cmdBuffer) + histIndex += 1 + while cmdBuffer[histIndex].type != 0 and histIndex != -2: + histIndex += 1 + if cmdBuffer[histIndex].type == 0: # we found one + cmdBuffer[-1].cmd = cmdBuffer[histIndex].cmd + + def actionRightMouse(): + global __FONT_SIZE__ + choice = Draw.PupMenu('Console Menu%t|Write Input Data (white)|Write Output Data (blue)|Write Error Data (red)|Write All Text|%l|Insert Blender text|%l|Font Size|%l|Quit') + + if choice == 1: + writeCmdData(cmdBuffer, 0) # type 0 user + elif choice == 2: + writeCmdData(cmdBuffer, 1) # type 1 user output + elif choice == 3: + writeCmdData(cmdBuffer, 2) # type 2 errors + elif choice == 4: + writeCmdData(cmdBuffer, 3) # All + elif choice == 6: + insertCmdData(cmdBuffer) # Insert text from Blender and run it. + elif choice == 8: + # Fontsize. + font_choice = Draw.PupMenu('Font Size%t|Large|Normal|Small|Tiny') + if font_choice != -1: + if font_choice == 1: + __FONT_SIZE__ = 3 + elif font_choice == 2: + __FONT_SIZE__ = 2 + elif font_choice == 3: + __FONT_SIZE__ = 1 + elif font_choice == 4: + __FONT_SIZE__ = 0 + Draw.Redraw() + + elif choice == 10: # Exit + Draw.Exit() + + + # Auto compleating, quite complex- use recutsice dir for the moment. + def actionAutoCompleate(): # Ctrl + Tab + if not cmdBuffer[-1].cmd[:cursor].split(): + return + + + RECURSIVE_DIR = recursive_dir() + + # get last name of user input + editVar = cmdBuffer[-1].cmd[:cursor] + # Split off spaces operators etc from the staryt of the command so we can use the startswith function. + for splitChar in __VARIABLE_DELIMETERS__: + editVar = editVar[:-1].split(splitChar)[-1] + editVar[-1] + + + # Now we should have the var by its self + if editVar: + possibilities = [] + + for __TMP_VAR_NAME__ in RECURSIVE_DIR: #.keys(): + #print '\t', __TMP_VAR_NAME__ + if __TMP_VAR_NAME__ == editVar: + # print 'ADITVAR IS A VAR' + pass + ''' + elif __TMP_VAR_NAME__.startswith( editVar ): + print __TMP_VAR_NAME__, 'aaa' + possibilities.append( __TMP_VAR_NAME__ ) + ''' + possibilities.append( __TMP_VAR_NAME__ ) + + if len(possibilities) == 1: + cmdBuffer[-1].cmd = ('%s%s%s' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], possibilities[0], cmdBuffer[-1].cmd[cursor:])) + + elif possibilities: # If its not just [] + # -1 with insert is the second last. + + # Text choice + #cmdBuffer.insert(-1, cmdLine('options: %s' % ' '.join(possibilities), 3, None)) + + menuList = [] # A lits of tuples- ABSOLUTE, RELATIVE + + for __TMP_VAR_NAME__ in possibilities: + for usage in RECURSIVE_DIR[__TMP_VAR_NAME__]: + # Account for non absolute (variables for eg.) + if usage: # not '' + absName = '%s.%s' % (usage, __TMP_VAR_NAME__) + + if __TMP_VAR_NAME__.startswith(editVar): + menuList.append( # Used for names and can be entered when pressing shift. + (absName, # Absolute name + __TMP_VAR_NAME__) # Relative name, non shift + ) + + #else: + # if absName.find(editVar) != -1: + # menuList.append((__TMP_VAR_NAME__, __TMP_VAR_NAME__)) # Used for names and can be entered when pressing shift. + + # No items to display? no menu + if not menuList: + return + + menuList.sort() + + choice = PupMenuLess( # Menu for the user to choose the autocompleate + 'Choices (Shift for local name, Ctrl for Docs)%t|' + # Title Text + '|'.join(['%s, %s' % m for m in menuList])) # Use Absolute names m[0] + + if choice != -1: + if Window.GetKeyQualifiers() & Window.Qual.CTRL: # Help + cmdBuffer[-1].cmd = ('help(%s%s) ' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], menuList[choice-1][0])) + elif Window.GetKeyQualifiers() & Window.Qual.SHIFT: # Put in the long name + cmdBuffer[-1].cmd = ('%s%s%s' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], menuList[choice-1][1], cmdBuffer[-1].cmd[cursor:])) + else: # Only paste in the Short name + cmdBuffer[-1].cmd = ('%s%s%s' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], menuList[choice-1][0], cmdBuffer[-1].cmd[cursor:])) + + + else: + # print 'NO EDITVAR' + return + + # ------------------end------------------ # + + # Quit from menu only + #if (evt == Draw.ESCKEY and not val): + # Draw.Exit() + if evt == Draw.MOUSEX or evt == Draw.MOUSEY: # AVOID TOO MANY REDRAWS. + return + + + global cursor + global histIndex + global __FONT_SIZE__ + global __CONSOLE_LINE_OFFSET__ + + ascii = Blender.event + + resetScroll = True + + #------------------------------------------------------------------------------# + # key codes and key handling # + #------------------------------------------------------------------------------# + + # UP DOWN ARROW KEYS, TO TRAVERSE HISTORY + if (evt == Draw.UPARROWKEY and val): actionUpKey() + elif (evt == Draw.DOWNARROWKEY and val): actionDownKey() + + elif (evt == Draw.RIGHTARROWKEY and val): + if Window.GetKeyQualifiers() & Window.Qual.SHIFT: + wordJump = False + newCursor = cursor+1 + while newCursor<0: + + if cmdBuffer[-1].cmd[newCursor] not in __DELIMETERS__: + newCursor+=1 + else: + wordJump = True + break + if wordJump: # Did we find a new cursor pos? + cursor = newCursor + else: + cursor = -1 # end of line + else: + cursor +=1 + if cursor > -1: + cursor = -1 + + elif (evt == Draw.LEFTARROWKEY and val): + if Window.GetKeyQualifiers() & Window.Qual.SHIFT: + wordJump = False + newCursor = cursor-1 + while abs(newCursor) < len(cmdBuffer[-1].cmd): + + if cmdBuffer[-1].cmd[newCursor] not in __DELIMETERS__ or\ + newCursor == cursor: + newCursor-=1 + else: + wordJump = True + break + if wordJump: # Did we find a new cursor pos? + cursor = newCursor + else: + cursor = -len(cmdBuffer[-1].cmd) # Start of line + + else: + if len(cmdBuffer[-1].cmd) > abs(cursor): + cursor -=1 + + elif (evt == Draw.HOMEKEY and val): + cursor = -len(cmdBuffer[-1].cmd) + + elif (evt == Draw.ENDKEY and val): + cursor = -1 + + elif (evt == Draw.TABKEY and val): + insCh('\t') + + elif (evt == Draw.BACKSPACEKEY and val): + if Window.GetKeyQualifiers() & Window.Qual.SHIFT: + i = -1 + for d in __DELIMETERS__: + i = max(i, cmdBuffer[-1].cmd[:cursor-1].rfind(d)) + if i == -1: + i=0 + cmdBuffer[-1].cmd = ('%s%s' % (cmdBuffer[-1].cmd[:i] , cmdBuffer[-1].cmd[cursor:])) + + else: + # Normal backspace. + cmdBuffer[-1].cmd = ('%s%s' % (cmdBuffer[-1].cmd[:cursor-1] , cmdBuffer[-1].cmd[cursor:])) + + elif (evt == Draw.DELKEY and val) and cursor < -1: + cmdBuffer[-1].cmd = cmdBuffer[-1].cmd[:cursor] + cmdBuffer[-1].cmd[cursor+1:] + cursor +=1 + + elif ((evt == Draw.RETKEY or evt == Draw.PADENTER) and val): + actionEnterKey() + + elif (evt == Draw.RIGHTMOUSE and not val): actionRightMouse(); return + + elif (evt == Draw.PADPLUSKEY or evt == Draw.EQUALKEY or evt == Draw.WHEELUPMOUSE) and val and Window.GetKeyQualifiers() & Window.Qual.CTRL: + __FONT_SIZE__ += 1 + __FONT_SIZE__ = min(len(__FONT_SIZES__)-1, __FONT_SIZE__) + elif (evt == Draw.PADMINUS or evt == Draw.MINUSKEY or evt == Draw.WHEELDOWNMOUSE) and val and Window.GetKeyQualifiers() & Window.Qual.CTRL: + __FONT_SIZE__ -=1 + __FONT_SIZE__ = max(0, __FONT_SIZE__) + + + elif evt == Draw.WHEELUPMOUSE and val: + __CONSOLE_LINE_OFFSET__ += 1 + __CONSOLE_LINE_OFFSET__ = min(len(cmdBuffer)-2, __CONSOLE_LINE_OFFSET__) + resetScroll = False + + elif evt == Draw.WHEELDOWNMOUSE and val: + __CONSOLE_LINE_OFFSET__ -= 1 + __CONSOLE_LINE_OFFSET__ = max(0, __CONSOLE_LINE_OFFSET__) + resetScroll = False + + + elif ascii: + insCh(chr(ascii)) + else: + return # dont redraw. + + # If the user types in anything then scroll to bottom. + if resetScroll: + __CONSOLE_LINE_OFFSET__ = 0 + Draw.Redraw() + + +def draw_gui(): + # Get the bounds from ObleGL directly + __CONSOLE_RECT__ = BGL.Buffer(BGL.GL_FLOAT, 4) + BGL.glGetFloatv(BGL.GL_SCISSOR_BOX, __CONSOLE_RECT__) + __CONSOLE_RECT__= __CONSOLE_RECT__.list + + # Clear the screen + BGL.glClearColor(0.0, 0.0, 0.0, 1.0) + BGL.glClear(BGL.GL_COLOR_BUFFER_BIT) # use it to clear the color buffer + + + # Fixed margin. use a margin since 0 margin can be hard to seewhen close to a crt's edge. + margin = 4 + + # Draw cursor location colour + if __CONSOLE_LINE_OFFSET__ == 0: + cmd2curWidth = Draw.GetStringWidth(cmdBuffer[-1].cmd[:cursor], __FONT_SIZES__[__FONT_SIZE__][0]) + BGL.glColor3f(0.8, 0.2, 0.2) + if cmd2curWidth == 0: + BGL.glRecti(margin,2,margin+2, __FONT_SIZES__[__FONT_SIZE__][1]+2) + else: + BGL.glRecti(margin + cmd2curWidth-2,2, margin+cmd2curWidth, __FONT_SIZES__[__FONT_SIZE__][1]+2) + + BGL.glColor3f(1,1,1) + # Draw the set of cammands to the buffer + consoleLineIdx = __CONSOLE_LINE_OFFSET__ + 1 + wrapLineIndex = 0 + while consoleLineIdx < len(cmdBuffer) and __CONSOLE_RECT__[3] > (consoleLineIdx - __CONSOLE_LINE_OFFSET__) * __FONT_SIZES__[__FONT_SIZE__][1]: + if cmdBuffer[-consoleLineIdx].type == 0: + BGL.glColor3f(1, 1, 1) + elif cmdBuffer[-consoleLineIdx].type == 1: + BGL.glColor3f(.3, .3, 1) + elif cmdBuffer[-consoleLineIdx].type == 2: + BGL.glColor3f(1.0, 0, 0) + elif cmdBuffer[-consoleLineIdx].type == 3: + BGL.glColor3f(0, 0.8, 0) + else: + BGL.glColor3f(1, 1, 0) + + if consoleLineIdx == 1: # user input + BGL.glRasterPos2i(margin, (__FONT_SIZES__[__FONT_SIZE__][1] * (consoleLineIdx-__CONSOLE_LINE_OFFSET__)) - 8) + Draw.Text(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZES__[__FONT_SIZE__][0]) + else: + BGL.glRasterPos2i(margin, (__FONT_SIZES__[__FONT_SIZE__][1] * ((consoleLineIdx-__CONSOLE_LINE_OFFSET__)+wrapLineIndex)) - 8) + Draw.Text(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZES__[__FONT_SIZE__][0]) + + # Wrapping is totally slow, can even hang blender - dont do it! + ''' + if consoleLineIdx == 1: # NEVER WRAP THE USER INPUT + BGL.glRasterPos2i(margin, (__FONT_SIZES__[__FONT_SIZE__][1] * (consoleLineIdx-__CONSOLE_LINE_OFFSET__)) - 8) + # BUG, LARGE TEXT DOSENT DISPLAY + Draw.Text(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZES__[__FONT_SIZE__][0]) + + + else: # WRAP? + # LINE WRAP + if Draw.GetStringWidth(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZES__[__FONT_SIZE__][0]) > __CONSOLE_RECT__[2]: + wrapLineList = [] + copyCmd = [cmdBuffer[-consoleLineIdx].cmd, ''] + while copyCmd != ['','']: + while margin + Draw.GetStringWidth(copyCmd[0], __FONT_SIZES__[__FONT_SIZE__][0]) > __CONSOLE_RECT__[2]: + #print copyCmd + copyCmd[1] = '%s%s'% (copyCmd[0][-1], copyCmd[1]) # Add the char on the end + copyCmd[0] = copyCmd[0][:-1]# remove last chat + + # Now we have copyCmd[0] at a good length we can print it. + if copyCmd[0] != '': + wrapLineList.append(copyCmd[0]) + + copyCmd[0]='' + copyCmd = [copyCmd[1], copyCmd[0]] + + # Now we have a list of lines, draw them (OpenGLs reverse ordering requires this odd change) + wrapLineList.reverse() + for wline in wrapLineList: + BGL.glRasterPos2i(margin, (__FONT_SIZES__[__FONT_SIZE__][1]*((consoleLineIdx-__CONSOLE_LINE_OFFSET__) + wrapLineIndex)) - 8) + Draw.Text(wline, __FONT_SIZES__[__FONT_SIZE__][0]) + wrapLineIndex += 1 + wrapLineIndex-=1 # otherwise we get a silly extra line. + + else: # no wrapping. + + BGL.glRasterPos2i(margin, (__FONT_SIZES__[__FONT_SIZE__][1] * ((consoleLineIdx-__CONSOLE_LINE_OFFSET__)+wrapLineIndex)) - 8) + Draw.Text(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZES__[__FONT_SIZE__][0]) + ''' + consoleLineIdx += 1 + + +# This recieves the event index, call a function from here depending on the event. +def handle_button_event(evt): + pass + + +# Run the console +__CONSOLE_VAR_DICT__ = {} # Initialize var dict + + +# Print Startup lines, add __bpydoc__ to the console startup. +cmdBuffer = [] +for l in __bpydoc__.split('
'): + cmdBuffer.append( cmdLine(l, 1, None) ) + + +histIndex = cursor = -1 # How far back from the first letter are we? - in current CMD line, history if for moving up and down lines. + +# Autoexec, startup code. +scriptDir = Get('scriptsdir') +console_autoexec = None +if scriptDir: + if not scriptDir.endswith(Blender.sys.sep): + scriptDir += Blender.sys.sep + + console_autoexec = '%s%s' % (scriptDir, 'console_autoexec.py') + + if not sys.exists(console_autoexec): + # touch the file + try: + open(console_autoexec, 'w').close() + cmdBuffer.append(cmdLine('...console_autoexec.py not found, making new in scripts dir', 1, None)) + except: + cmdBuffer.append(cmdLine('...console_autoexec.py could not write, this is ok', 1, None)) + scriptDir = None # make sure we only use this for console_autoexec.py + + if not sys.exists(console_autoexec): + console_autoexec = None + + else: + cmdBuffer.append(cmdLine('...Using existing console_autoexec.py in scripts dir', 1, None)) + + + +#-Autoexec---------------------------------------------------------------------# +# Just use the function to jump into local naming mode. +# This is so we can loop through all of the autoexec functions / vars and add them to the __CONSOLE_VAR_DICT__ +def include_console(includeFile): + global __CONSOLE_VAR_DICT__ # write autoexec vars to this. + + # Execute an external py file as if local + exec(include(includeFile)) + +def standard_imports(): + # Write local to global __CONSOLE_VAR_DICT__ for reuse, + for ls in (dir(), dir(Blender)): + for __TMP_VAR_NAME__ in ls: + # Execute the local > global coversion. + exec('%s%s' % ('__CONSOLE_VAR_DICT__[__TMP_VAR_NAME__]=', __TMP_VAR_NAME__)) + + exec('%s%s' % ('__CONSOLE_VAR_DICT__["bpy"]=', 'bpy')) + +if scriptDir and console_autoexec: + include_console(console_autoexec) # pass the blender module + +standard_imports() # import Blender and bpy + +#-end autoexec-----------------------------------------------------------------# + + +# Append new line to write to +cmdBuffer.append(cmdLine(' ', 0, 0)) + +#------------------------------------------------------------------------------# +# register the event handling code, GUI # +#------------------------------------------------------------------------------# +def main(): + Draw.Register(draw_gui, handle_event, handle_button_event) + +if __name__ == '__main__': + main() diff --git a/release/scripts/discombobulator.py b/release/scripts/discombobulator.py new file mode 100644 index 00000000000..6dbb4e5382b --- /dev/null +++ b/release/scripts/discombobulator.py @@ -0,0 +1,1526 @@ +#!BPY + +""" +Name: 'Discombobulator' +Blender: 237 +Group: 'Mesh' +Tip: 'Adds random geometry to a mesh' +""" + +__author__ = "Evan J. Rosky (syrux)" +__url__ = ("Script's homepage, http://evan.nerdsofparadise.com/programs/discombobulator/index.html") +__version__ = "237" +__bpydoc__ = """\ +Discombobulator adds random geometry to a mesh. + +As an example, this script can easily give a "high-tech" +look to walls and spaceships. + +Definitions:
+ - Protrusions: extrusions of each original face on the mesh. +You may have from 1 to 4 protrusions on each face.
+ - Taper: The tips of each protrusion will be a percentage +smaller than the base.
+ - Doodads: small extruded blocks/shapes that are randomly placed +about the top of a protrusion or face. + + +Usage:
+ Input your settings, make sure the mesh you would like to modify +is selected (active) and then click on "Discombobulate".
+ See the scripts tutorial page (on the homepage) for more info. + + +New Features:
+ - Will use existing materials if there are any.
+ - Clicking "Assign materials by part" will allow assigning +of different material indices to Protrusion or Doodad Sides +and Tops in the gui element below it.
+ - Setting a material index to 0 will use whatever material +is assigned to the face that is discombobulated. + - You can now scroll using the arrow keys. + + +Notes:
+ - Modifications can be restricted to selected faces +by setting "Only selected faces" for protrusions and/or +doodads.
+ - It's possible to restrict mesh generation to add only +protrusions or only doodads instead of both.
+ - You may also choose to have Discombobulator select the +tops of created protrusions by clicking the corresponding +number of protrusion buttons under "Select Tops". You may +also do the same for doodads by choosing "Select Doodads" and +"Only Select Tops". You may choose to select the whole doodads +by leaving "Only Select Tops" off.
+ - By selecting "Deselect Selected" you can have +discombobulator deselect everything but the selections it +makes.
+ - The "Face %" option will set the percentage of faces that +will be modified either for the doodads or the protrusions.
+ - "Copy Before Modifying" will create a new object with the +modifications where leaving it off will overwrite the original +mesh.
+ +You can find more information at the Link above. +""" + + +# $Id$ +# +# Updated 2006-09-26 +# Changes since last version: +# > Works with Blender CVS and hopefully with Blender 2.40. +# > Swaps min/max values when min>max rather than complaining. +# > Will keep previously assigned materials. +# > Now allows user to assign custom material indices to +# Protrusion and Doodad Sides and Tops. +# > The initial Gui Layout will change depending on the aspect +# ratio of the window it is in. +# > Using the arrow keys will scroll the gui. +# +# -------------------------------------------------------------------------- +# Discombobulator v2.1b +# by Evan J. Rosky, 2005 +# This plugin is protected by the GPL: Gnu Public Licence +# GPL - http://www.gnu.org/copyleft/gpl.html +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2005: Evan J. Rosky +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +#Hit Alt-P to run + +import Blender +from Blender import NMesh,Object,Material,Window,Types,Scene +from Blender.NMesh import Vert,Face +from Blender.Mathutils import * + +import defaultdoodads +import BPyMathutils +from BPyMathutils import genrand +a = BPyMathutils.sgenrand(int(round(Rand(1000,99999),0))) + +#Create random numbers +def randnum(low,high): + num = genrand() + num = num*(high-low) + num = num+low + return num + +#Object Vars +newmesh = NMesh.GetRaw() +materialArray = [0] + +#Material Vars +reassignMats = 0 +protSideMat = 1 +protTopMat = 2 +doodSideMat = 3 +doodTopMat = 4 +thereAreMats = 0 +currmat = 0 + +#Global Vars +makenewobj = 1 +errortext = "Remember to select an object." +editmode = 0 + +#Protrusion Vars +makeprots = 1 +faceschangedpercent = 1.0 +minimumheight = 0.2 +maximumheight = 0.4 +subface1 = 1 +subface2 = 1 +subface3 = 1 +subface4 = 1 +subfaceArray = [1,2,3,4] +minsubfaces = 1 +minimumtaperpercent = 0.15 +maximumtaperpercent = 0.35 +useselectedfaces = 0 +selectface1 = 1 +selectface2 = 1 +selectface3 = 1 +selectface4 = 1 +deselface = 1 + +#Doodad Vars +makedoodads = 1 +doodadfacepercent = 1.0 +selectdoodad = 0 +onlyonprotrusions = 0 +doodonselectedfaces = 0 +selectdoodadtoponly = 0 +doodad1 = 1 +doodad2 = 1 +doodad3 = 1 +doodad4 = 1 +doodad5 = 1 +doodad6 = 1 +doodadminperface = 2 +doodadmaxperface = 6 +doodadminsize = 0.15 +doodadmaxsize = 0.45 +doodadminheight = 0.0 +doodadmaxheight = 0.1 +doodadArray = [1,2,3,4,5,6] + +def makeSubfaceArray(): + global subfaceArray + global subface1 + global subface2 + global subface3 + global subface4 + + subfaceArray = [] + if subface1 > 0: + subfaceArray.append(1) + if subface2 > 0: + subfaceArray.append(2) + if subface3 > 0: + subfaceArray.append(3) + if subface4 > 0: + subfaceArray.append(4) + +def makeDoodadArray(): + global doodadArray + global doodad1 + global doodad2 + global doodad3 + global doodad4 + global doodad5 + global doodad6 + + doodadArray = [] + if doodad1 > 0: + doodadArray.append(1) + if doodad2 > 0: + doodadArray.append(2) + if doodad3 > 0: + doodadArray.append(3) + if doodad4 > 0: + doodadArray.append(4) + if doodad5 > 0: + doodadArray.append(5) + if doodad6 > 0: + doodadArray.append(6) + +def extrude(mid,nor,protrusion,v1,v2,v3,v4,tosel=1,flipnor=0): + taper = 1 - randnum(minimumtaperpercent,maximumtaperpercent) + newmesh_verts = newmesh.verts + newmesh_faces = newmesh.faces + + vert = newmesh_verts[v1] + point = (vert.co - mid)*taper + mid + protrusion*Vector(nor) + ver = Vert(point[0],point[1],point[2]) + ver.sel = tosel + newmesh_verts.append(ver) + vert = newmesh_verts[v2] + point = (vert.co - mid)*taper + mid + protrusion*Vector(nor) + ver = Vert(point[0],point[1],point[2]) + ver.sel = tosel + newmesh_verts.append(ver) + vert = newmesh_verts[v3] + point = (vert.co - mid)*taper + mid + protrusion*Vector(nor) + ver = Vert(point[0],point[1],point[2]) + ver.sel = tosel + newmesh_verts.append(ver) + vert = newmesh_verts[v4] + point = (vert.co - mid)*taper + mid + protrusion*Vector(nor) + ver = Vert(point[0],point[1],point[2]) + ver.sel = tosel + newmesh_verts.append(ver) + + faceindex = len(newmesh_verts) - 4 + + #side face 1 + face = Face([newmesh_verts[v1], newmesh_verts[v2], newmesh_verts[faceindex+1], newmesh_verts[faceindex]]) + if flipnor != 0: + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh_faces.append(face) + + #side face 2 + face = Face([newmesh_verts[v2], newmesh_verts[v3], newmesh_verts[faceindex+2], newmesh_verts[faceindex+1]]) + if flipnor != 0: + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh_faces.append(face) + + #side face 3 + face = Face([newmesh_verts[v3], newmesh_verts[v4], newmesh_verts[faceindex+3], newmesh_verts[faceindex+2]]) + if flipnor != 0: + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh_faces.append(face) + + #side face 4 + face = Face([newmesh_verts[v4], newmesh_verts[v1], newmesh_verts[faceindex], newmesh_verts[faceindex+3]]) + if flipnor != 0: + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh_faces.append(face) + + #top face + face = Face(newmesh_verts[-4:]) + if flipnor != 0: + face.v.reverse() + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or protTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protTopMat-1 + newmesh_faces.append(face) + return face + +#Sets the global protrusion values +def setProtrusionValues(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15): + + #Protrusions + global makeprots + global minimumtaperpercent + global maximumtaperpercent + global faceschangedpercent + global minimumheight + global maximumheight + global subface1 + global subface2 + global subface3 + global subface4 + global useselectedfaces + global selectface1 + global selectface2 + global selectface3 + global selectface4 + global deselface + global subfaceArray + + #Protrusions + makeprots = p0 + faceschangedpercent = p1 + minimumheight = p2 + maximumheight = p3 + subface1 = p4 + subface2 = p5 + subface3 = p6 + subface4 = p7 + minimumtaperpercent = p8 + maximumtaperpercent = p9 + useselectedfaces = p10 + selectface1 = p11 + selectface2 = p12 + selectface3 = p13 + selectface4 = p14 + deselface = p15 + makeSubfaceArray() + if len(subfaceArray) == 0: + makeprots = 0 + + if minimumheight > maximumheight: + a = maximumheight + maximimheight = minimumheight + minimumheight = a + elif minimumtaperpercent > maximumtaperpercent: + a = maximumtaperpercent + maximimtaperpercent = minimumtaperpercent + minimumtaperpercent = a + +#Sets the global Doodad values +def setDoodadValues(d0,d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,d13,d14,d15,d16,d17): + + #Doodads + global makedoodads + global doodadfacepercent + global selectdoodad + global onlyonprotrusions + global doodad1 + global doodad2 + global doodad3 + global doodad4 + global doodad5 + global doodad6 + global doodadminperface + global doodadmaxperface + global doodadminsize + global doodadmaxsize + global doodadminheight + global doodadmaxheight + global doodadArray + global doodonselectedfaces + global selectdoodadtoponly + + #Doodads + makedoodads = d0 + doodadfacepercent = d1 + selectdoodad = d2 + onlyonprotrusions = d3 + doodad1 = d4 + doodad2 = d5 + doodad3 = d6 + doodad4 = d7 + doodad5 = d8 + doodad6 = d9 + doodadminperface = d10 + doodadmaxperface = d11 + doodadminsize = d12 + doodadmaxsize = d13 + doodadminheight = d14 + doodadmaxheight = d15 + doodonselectedfaces = d16 + selectdoodadtoponly = d17 + makeDoodadArray() + if len(doodadArray) == 0: + makedoodads = 0 + + elif doodadminperface > doodadmaxperface: + a = doodadmaxperface + doodadmaxperface = doodadminperface + doodadminperface = a + elif doodadminsize > doodadmaxsize: + a = doodadmaxsize + doodadmaxsize = doodadminsize + doodadminsize = a + elif doodadminheight > doodadmaxheight: + a = doodadmaxheight + doodadmaxheight = doodadminheight + doodadminheight = a + +#Sets other global values +def setOtherValues(g0,m0,m1,m2,m3,m4): + + #Global + global reassignMats + global makenewobj + global protSideMat + global protTopMat + global doodSideMat + global doodTopMat + + #Get Misc Variables + makenewobj = g0 + reassignMats = m0 + protSideMat = m1 + protTopMat = m2 + doodSideMat = m3 + doodTopMat = m4 + +def discombobulate(): + + #Global + global origmesh + global newmesh + global makenewobj + global origobj + global newobj + global messagetext + global errortext + global editmode + + #Protrusions + global makeprots + global minimumtaperpercent + global maximumtaperpercent + global faceschangedpercent + global minimumheight + global maximumheight + global subface1 + global subface2 + global subface3 + global subface4 + global useselectedfaces + global selectface1 + global selectface2 + global selectface3 + global selectface4 + global deselface + global subfaceArray + + #Doodads + global makedoodads + global doodadfacepercent + global selectdoodad + global onlyonprotrusions + global doodad1 + global doodad2 + global doodad3 + global doodad4 + global doodad5 + global doodad6 + global doodadminperface + global doodadmaxperface + global doodadminsize + global doodadmaxsize + global doodadminheight + global doodadmaxheight + global doodadArray + global doodonselectedfaces + global selectdoodadtoponly + + #Global + global materialArray + global reassignMats + global protSideMat + global protTopMat + global doodSideMat + global doodTopMat + global thereAreMats + global currmat + + origobj = Scene.GetCurrent().objects.active + if not origobj: + glRasterPos2d(10,50) + errortext = "YOU MUST SELECT AN OBJECT!" + messagetext = ErrorText(errortext) + Blender.Redraw() + return + + #Leave Editmode + editmode = Window.EditMode() + if editmode: Window.EditMode(0) + + #Get Major Variables + + origmesh = origobj.getData() + + if origobj.type != 'Mesh': + glRasterPos2d(10,50) + errortext = "OBJECT MUST BE MESH!" + messagetext = ErrorText(errortext) + Blender.Redraw() + return + + newmesh = NMesh.GetRaw() + materialArray = origmesh.getMaterials() + if len(materialArray) < 1: + thereAreMats = 0 + else: + thereAreMats = 1 + + #add material indices if necessary (only up to 4) + if thereAreMats == 1 and reassignMats == 1: + if len(materialArray) < 4: + if protSideMat > 4: protSideMat = 4 + if protTopMat > 4: protTopMat = 4 + if doodSideMat > 4: doodSideMat = 4 + if doodTopMat > 4: doodTopMat = 4 + else: + if protSideMat > len(materialArray): protSideMat = len(materialArray) + if protTopMat > len(materialArray): protTopMat = len(materialArray) + if doodSideMat > len(materialArray): doodSideMat = len(materialArray) + if doodTopMat > len(materialArray): doodTopMat = len(materialArray) + + #This only does something if there are less than 4 verts + for matind in [protSideMat,protTopMat,doodSideMat,doodTopMat]: + if matind > len(materialArray) and matind <= 4: + for i in xrange(len(materialArray),matind+1): + materialArray.append(Material.New("AddedMat " + str(i))) + + #Sets the materials + newmesh.setMaterials(materialArray) + + #Set the doodad settings + defaultdoodads.settings(selectdoodadtoponly,materialArray,reassignMats,thereAreMats,doodSideMat,doodTopMat) + #defaultdoodads.settings(selectdoodadtoponly,materialArray,reassignMats,thereAreMats,currmat) + + newmesh.verts.extend(origmesh.verts) + + #Start modifying faces + for currface in origmesh.faces: + + currmat = currface.materialIndex + defaultdoodads.setCurrMat(currmat) + + #Check if it is a triangle + if len(currface.v)<4: + face = Face([newmesh.verts[currface.v[0].index],newmesh.verts[currface.v[1].index],newmesh.verts[currface.v[2].index]]) + if thereAreMats == 1: + face.materialIndex = currmat + newmesh.faces.append(face) + continue + + #Check whether or not to make protrusions + if makeprots == 0: + face = Face([newmesh.verts[currface.v[0].index],newmesh.verts[currface.v[1].index],newmesh.verts[currface.v[2].index],newmesh.verts[currface.v[3].index]]) + if thereAreMats == 1: + face.materialIndex = currmat + newmesh.faces.append(face) + if makedoodads == 1 and onlyonprotrusions == 0: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray,face, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + else: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray,face, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + continue + + #Check if only changing selected faces + if useselectedfaces == 1: + #check if currface is selected + if currface.sel: + a = 1 + else: + face = Face([newmesh.verts[currface.v[0].index],newmesh.verts[currface.v[1].index],newmesh.verts[currface.v[2].index],newmesh.verts[currface.v[3].index]]) + if thereAreMats == 1: + face.materialIndex = currmat + newmesh.faces.append(face) + if makedoodads == 1 and onlyonprotrusions == 0: + if doodonselectedfaces != 1: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray,face, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + continue + #Check if face should be modified by random chance + if randnum(0,1)>faceschangedpercent: + face = Face([newmesh.verts[currface.v[0].index],newmesh.verts[currface.v[1].index],newmesh.verts[currface.v[2].index],newmesh.verts[currface.v[3].index]]) + if thereAreMats == 1: + face.materialIndex = currmat + newmesh.faces.append(face) + if makedoodads == 1 and onlyonprotrusions == 0: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray,face, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + else: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray,face, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + continue + + center = Vector([0,0,0]) + for pt in currface.v: + center = center + pt.co + center = center / len(currface.v) + + #Determine amount of subfaces + subfaces = round(randnum(1,len(subfaceArray)),0) + subfaces = subfaceArray[(int(subfaces) - 1)] + + ######################## START DEALING WITH PROTRUSIONS ##################### + + if subfaces == 1: + prot = randnum(minimumheight,maximumheight) + tempface = extrude(center,currface.no,prot,currface.v[0].index,currface.v[1].index,currface.v[2].index,currface.v[3].index,selectface1) + if makedoodads == 1: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + else: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + + elif subfaces == 2: + orientation = int(round(randnum(0,1))) + p1 = currface.v[orientation] + p2 = currface.v[orientation + 1] + p3 = ((p2.co - p1.co)/2) + p1.co + ve1 = Vert(p3[0],p3[1],p3[2]) + ve1.sel = 0 + p1 = currface.v[2 + orientation] + if orientation < 0.5: + p2 = currface.v[3] + else: + p2 = currface.v[0] + p3 = ((p2.co - p1.co)/2) + p1.co + ve2 = Vert(p3[0],p3[1],p3[2]) + ve2.sel = 0 + if orientation < 0.5: + verti = currface.v[3] + p3 = verti.index + v1 = p3 + verti = currface.v[0] + p0 = verti.index + v2 = p0 + else: + verti = currface.v[0] + p0 = verti.index + v1 = p0 + verti = currface.v[1] + p1 = verti.index + v2 = p1 + newmesh.verts.append(ve1) + newmesh.verts.append(ve2) + index = len(newmesh.verts) - 2 + v4 = index + 1 + v3 = index + center = Vector([0, 0, 0]) + for pt in [newmesh.verts[v1],newmesh.verts[v2],newmesh.verts[v3],newmesh.verts[v4]]: + center += pt.co + center = center/4 + prot = randnum(minimumheight,maximumheight) + tempface = extrude(center,currface.no,prot,v1,v2,v3,v4,selectface2) + if makedoodads == 1: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + else: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + if orientation < 0.5: + verti = currface.v[1] + p1 = verti.index + v1 = p1 + verti = currface.v[2] + p2 = verti.index + v2 = p2 + else: + verti = currface.v[2] + p2 = verti.index + v1 = p2 + verti = currface.v[3] + p3 = verti.index + v2 = p3 + center = Vector([0]*3) + for pt in [newmesh.verts[v1],newmesh.verts[v2],newmesh.verts[v3],newmesh.verts[v4]]: + center += pt.co + center = center/4 + prot = randnum(minimumheight,maximumheight) + tempface = extrude(center,currface.no,prot,v1,v2,v4,v3,selectface2) + if makedoodads == 1: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + else: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + if orientation < 0.5: + face = Face([newmesh.verts[p0],newmesh.verts[p1],newmesh.verts[v3]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + face = Face([newmesh.verts[p2],newmesh.verts[p3],newmesh.verts[v4]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + else: + face = Face([newmesh.verts[p1],newmesh.verts[p2],newmesh.verts[v3]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + face = Face([newmesh.verts[p3],newmesh.verts[p0],newmesh.verts[v4]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + + elif subfaces == 3: + layer2inds = [] + layer2verts = [] + orientation = int(round(randnum(0,1))) + rotation = int(round(randnum(0,1))) + p1 = currface.v[orientation] + p2 = currface.v[orientation + 1] + p3 = ((p2.co - p1.co)/2) + p1.co + ve1 = Vert(p3[0],p3[1],p3[2]) + ve1.sel = 0 + p1 = currface.v[2 + orientation] + if orientation < 0.5: + p2 = currface.v[3] + else: + p2 = currface.v[0] + p3 = ((p2.co - p1.co)/2) + p1.co + ve2 = Vert(p3[0],p3[1],p3[2]) + ve2.sel = 0 + fp = [] + + #make first protrusion + if rotation < 0.5: + if orientation < 0.5: + verti = currface.v[3] + fp.append(verti.index) + v1 = verti.index + verti = currface.v[0] + fp.append(verti.index) + v2 = verti.index + layer2verts.extend([newmesh.verts[currface.v[1].index],newmesh.verts[currface.v[2].index]]) + else: + verti = currface.v[0] + fp.append(verti.index) + v1 = verti.index + verti = currface.v[1] + fp.append(verti.index) + v2 = verti.index + layer2verts.extend([newmesh.verts[currface.v[2].index],newmesh.verts[currface.v[3].index]]) + newmesh.verts.append(ve1) + newmesh.verts.append(ve2) + index = len(newmesh.verts) - 2 + v4 = index + 1 + v3 = index + center = Vector([0]*3) + for pt in [newmesh.verts[v1],newmesh.verts[v2],newmesh.verts[v3],newmesh.verts[v4]]: + center += pt.co + center = center/4 + prot = randnum(minimumheight,maximumheight) + layer2inds.extend([v3,v4]) + tempface = extrude(center,currface.no,prot,v1,v2,v3,v4,selectface3) + if makedoodads == 1: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + else: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + #Still first protrusion + else: + if orientation < 0.5: + verti = currface.v[1] + fp.append(verti.index) + v1 = verti.index + verti = currface.v[2] + fp.append(verti.index) + v2 = verti.index + layer2verts.extend([newmesh.verts[currface.v[0].index],newmesh.verts[currface.v[3].index]]) + else: + verti = currface.v[2] + fp.append(verti.index) + v1 = verti.index + verti = currface.v[3] + fp.append(verti.index) + v2 = verti.index + layer2verts.extend([newmesh.verts[currface.v[1].index],newmesh.verts[currface.v[0].index]]) + newmesh.verts.append(ve2) + newmesh.verts.append(ve1) + index = len(newmesh.verts) - 2 + v4 = index + v3 = index + 1 + center = Vector([0]*3) + for pt in [newmesh.verts[v1],newmesh.verts[v2],newmesh.verts[v3],newmesh.verts[v4]]: + center += pt.co + center = center/4 + prot = randnum(minimumheight,maximumheight) + layer2inds.extend([index, index +1]) + tempface = extrude(center,currface.no,prot,v1,v2,v4,v3,selectface3) + if makedoodads == 1: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + else: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + + #split next rect(pre-arranged, no orientation crud)--make flag in extruder for only one existing vert in mesh + p1 = newmesh.verts[layer2inds[0]] + p2 = newmesh.verts[layer2inds[1]] + p3 = ((p2.co - p1.co)/2) + p1.co + ve3 = Vert(p3[0],p3[1],p3[2]) + ve3.sel = 0 + p1 = layer2verts[0] + p2 = layer2verts[1] + p3 = ((p2.co - p1.co)/2) + p1.co + ve4 = Vert(p3[0],p3[1],p3[2]) + ve4.sel = 0 + newmesh.verts.append(ve3) + newmesh.verts.append(ve4) + tempindex = len(newmesh.verts) - 2 + v5 = tempindex + v6 = tempindex + 1 + verti = layer2verts[0] + t0 = verti.index + center = Vector([0]*3) + for pt in [newmesh.verts[v5],newmesh.verts[v6],newmesh.verts[t0],newmesh.verts[v3]]: + center += pt.co + center = center/4 + prot = randnum(minimumheight,maximumheight) + if rotation < 0.5: flino = 1 + else: flino = 0 + tempface = extrude(center,currface.no,prot,v3,v5,v6,t0,selectface3,flino) + if makedoodads == 1: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + if rotation < 0.5: + fpt = t0 + face = Face([newmesh.verts[fp[1]],newmesh.verts[fpt],newmesh.verts[v3]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + else: + fpt = t0 + face = Face([newmesh.verts[fp[0]],newmesh.verts[v3],newmesh.verts[fpt]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + verti = layer2verts[1] + tempindex = verti.index + center = Vector([0]*3) + for pt in [newmesh.verts[v5],newmesh.verts[v6],newmesh.verts[tempindex],newmesh.verts[v4]]: + center += pt.co + center = center/4 + prot = randnum(minimumheight,maximumheight) + tempface = extrude(center,currface.no,prot,v6,v5,v4,tempindex,selectface3,flino) + if makedoodads == 1: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + else: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + if rotation < 0.5: + face = Face([newmesh.verts[tempindex],newmesh.verts[fp[0]],newmesh.verts[v4]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + face = Face([newmesh.verts[fpt],newmesh.verts[tempindex],newmesh.verts[v6]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + else: + face = Face([newmesh.verts[tempindex],newmesh.verts[v4],newmesh.verts[fp[1]]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + face = Face([newmesh.verts[tempindex],newmesh.verts[fpt],newmesh.verts[v6]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + + else: + #get all points + verti = currface.v[0] + p0 = verti.index + + verti = currface.v[1] + p1 = verti.index + + pt = ((newmesh.verts[p1].co - newmesh.verts[p0].co)/2) + newmesh.verts[p0].co + v1 = Vert(pt[0],pt[1],pt[2]) + v1.sel = 0 + + verti = currface.v[2] + p2 = verti.index + + pt = ((newmesh.verts[p2].co - newmesh.verts[p1].co)/2) + newmesh.verts[p1].co + v2 = Vert(pt[0],pt[1],pt[2]) + v2.sel = 0 + + verti = currface.v[3] + p3 = verti.index + + pt = ((newmesh.verts[p3].co - newmesh.verts[p2].co)/2) + newmesh.verts[p2].co + v3 = Vert(pt[0],pt[1],pt[2]) + v3.sel = 0 + + pt = ((newmesh.verts[p0].co - newmesh.verts[p3].co)/2) + newmesh.verts[p3].co + v4 = Vert(pt[0],pt[1],pt[2]) + v4.sel = 0 + + pt = ((v3.co - v1.co)/2) + v1.co + m = Vert(pt[0],pt[1],pt[2]) + m.sel = 0 + + #extrusion 1 + newmesh.verts.extend([v1,m,v4]) + index = len(newmesh.verts) - 3 + v1 = index + m = index + 1 + v4 = index + 2 + center = Vector([0]*3) + for pt in [newmesh.verts[p0],newmesh.verts[v1],newmesh.verts[m],newmesh.verts[v4]]: + center += pt.co + center = center/4 + prot = randnum(minimumheight,maximumheight) + tempface = extrude(center,currface.no,prot,p0,v1,m,v4,selectface4) + if makedoodads == 1: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + else: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + + #extrusion 2 + newmesh.verts.extend([v2]) + index = len(newmesh.verts) - 1 + v2 = index + center = Vector([0]*3) + for pt in [newmesh.verts[m],newmesh.verts[v1],newmesh.verts[p1],newmesh.verts[v2]]: + center += pt.co + center = center/4 + prot = randnum(minimumheight,maximumheight) + tempface = extrude(center,currface.no,prot,m,v1,p1,v2,selectface4) + if makedoodads == 1: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + else: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + + #extrusion 3 + newmesh.verts.extend([v3]) + index = len(newmesh.verts) - 1 + v3 = index + center = Vector([0]*3) + for pt in [newmesh.verts[m],newmesh.verts[v2],newmesh.verts[p2],newmesh.verts[v3]]: + center += pt.co + center = center/4 + prot = randnum(minimumheight,maximumheight) + tempface = extrude(center,currface.no,prot,m,v2,p2,v3,selectface4) + if makedoodads == 1: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + else: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + + #extrusion 4 + center = Vector([0]*3) + for pt in [newmesh.verts[m],newmesh.verts[v3],newmesh.verts[p3],newmesh.verts[v4]]: + center += pt.co + center = center/4 + prot = randnum(minimumheight,maximumheight) + tempface = extrude(center,currface.no,prot,v4,m,v3,p3,selectface4) + if makedoodads == 1: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + else: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + + face = Face([newmesh.verts[p0],newmesh.verts[p1],newmesh.verts[v1]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + face = Face([newmesh.verts[p1],newmesh.verts[p2],newmesh.verts[v2]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + face = Face([newmesh.verts[p2],newmesh.verts[p3],newmesh.verts[v3]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + face = Face([newmesh.verts[p3],newmesh.verts[p0],newmesh.verts[v4]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + + #NMesh.PutRaw(newmesh) + if deselface == 1: + for unvert in origmesh.verts: + newmesh.verts[unvert.index].sel = 0 + if makenewobj == 1: + newobj = origobj.__copy__() + newobj.link(newmesh) + scene = Blender.Scene.GetCurrent() + scene.objects.link(newobj) + origobj.sel = 0 + else: + origobj.link(newmesh) + + #Return to Editmode if previously in it + if editmode: Window.EditMode(1) + +####################### gui ###################### +from Blender.BGL import * +from Blender.Draw import * + +def ErrorText(errortext): + Window.WaitCursor(0) + Text(errortext) + PupMenu("ERROR: %s" % errortext.lower()) + +#Global Buttons +makenewobject = Create(makenewobj) +messagetext = Create(errortext) + +#Protrusion Buttons +doprots = Create(makeprots) +facechange = Create(faceschangedpercent*100) +minheight = Create(minimumheight) +maxheight = Create(maximumheight) +sub1 = Create(subface1) +sub2 = Create(subface2) +sub3 = Create(subface3) +sub4 = Create(subface4) +mintaper = Create(minimumtaperpercent*100) +maxtaper = Create(maximumtaperpercent*100) +useselected = Create(useselectedfaces) +selface1 = Create(selectface1) +selface2 = Create(selectface2) +selface3 = Create(selectface3) +selface4 = Create(selectface4) +deselectvertices = Create(deselface) +#selectbyverts = Create(vertselected) + +#Doodad Buttons +dodoodads = Create(makedoodads) +doodadfacechange = Create(doodadfacepercent*100) +seldoodad = Create(selectdoodad) +onprot = Create(onlyonprotrusions) +dood1 = Create(doodad1) +dood2 = Create(doodad2) +dood3 = Create(doodad3) +dood4 = Create(doodad4) +dood5 = Create(doodad5) +dood6 = Create(doodad6) +doodadminamount = Create(doodadminperface) +doodadmaxamount = Create(doodadmaxperface) +doodsizemin = Create(doodadminsize*100) +doodsizemax = Create(doodadmaxsize*100) +doodheightmin = Create(doodadminheight) +doodheightmax = Create(doodadmaxheight) +doodonselface = Create(doodonselectedfaces) +seldoodtop = Create(selectdoodadtoponly) + +#Material Buttons +assignNewMats = Create(reassignMats) +replProtSideIndex = Create(protSideMat) +replProtTopIndex = Create(protTopMat) +replDoodSideIndex = Create(doodSideMat) +replDoodTopIndex = Create(doodTopMat) + +# Events +EVENT_NONE = 1 +EVENT_DISCOMBOBULATE = 2 +EVENT_EXIT = 3 + +# Additions for moving gui +hadd = 0 +wadd = 0 +thadd = 410 +phadd = 245 +pwadd = 0 +dhadd = 55 +dwadd = 0 +ghadd = 10 +gwadd = 0 +mhadd = 55 +mwadd = 312 + +def colorbox(x,y,xright,bottom): + glColor3f(0.75, 0.75, 0.75) + glRecti(x + 1, y + 1, xright - 1, bottom - 1) + +firstDraw = 1 + +def draw(): + + #Protrusions + global doprots + global facechange + global minheight + global maxheight + global sub1 + global sub2 + global sub3 + global sub4 + global mintaper + global maxtaper + global useselected + global selface1 + global selface2 + global selface3 + global selface4 + global deselectvertices + #global selectbyverts + + #Doodads + global dodoodads + global doodadfacechange + global seldoodad + global onprot + global dood1 + global dood2 + global dood3 + global dood4 + global dood5 + global dood6 + global doodadminamount + global doodadmaxamount + global doodsizemin + global doodsizemax + global doodheightmin + global doodheightmax + global doodonselface + global seldoodtop + + #Materials + global assignNewMats + global replProtSideIndex + global replProtTopIndex + global replDoodSideIndex + global replDoodTopIndex + + #Global Settings + global makenewobject + global messagetext + global errortext + global EVENT_NONE,EVENT_DRAW,EVENT_EXIT,EVENT_UP,EVENT_DOWN,EVENT_LEFT,EVENT_RIGHT + + # Additions for moving gui + global hadd + global wadd + global thadd + global phadd + global pwadd + global dhadd + global dwadd + global ghadd + global gwadd + global mhadd + global mwadd + + #This is for creating the initial layout + global firstDraw + if(firstDraw == 1): + if(((Window.GetAreaSize()[1])*1.7) < Window.GetAreaSize()[0]): + thadd = 180 + phadd = 10 + dhadd = 10 + mhadd = 55 + ghadd = 10 + pwadd = 0 + dwadd = 305 + mwadd = 610 + gwadd = 610 + else: + thadd = 505 + phadd = 346 + dhadd = 160 + mhadd = 56 + ghadd = 10 + pwadd = 0 + dwadd = 0 + mwadd = 0 + gwadd = 0 + firstDraw = 0 + + + #Title :420high + glClearColor(0.6, 0.6, 0.6, 1.0) + glClear(GL_COLOR_BUFFER_BIT) + glColor3f(0.0,0.0,0.0) + glRasterPos2d(8+wadd, thadd+hadd) + Text("Discombobulator v2.1b") + + #Protrusion + colorbox(8+pwadd+wadd,150+phadd+hadd,312+pwadd+wadd,phadd-5+hadd) + glColor3f(0.0,0.0,0.0) + glRasterPos2d(12+pwadd+wadd, 140+phadd+hadd) + Text("Protrusions:") + doprots = Toggle("Make Protrusions",EVENT_NONE,12+pwadd+wadd,117+phadd+hadd,145,18,doprots.val,"Make Protrusions?") + facechange = Number("Face %: ",EVENT_NONE,162+pwadd+wadd,117+phadd+hadd,145,18,facechange.val,0,100,"Percentage of faces that will grow protrusions") + useselected = Toggle("Only selected faces",EVENT_NONE,12+pwadd+wadd,97+phadd+hadd,145,18,useselected.val,"If on, only selected faces will be modified") + deselectvertices = Toggle("Deselect Selected",EVENT_NONE,162+pwadd+wadd,97+phadd+hadd,145,18,deselectvertices.val,"Deselects any selected vertex except for ones selected by \"Select Tops\"") + + #Protrusion properties + glColor3f(0.0,0.0,0.0) + glRasterPos2d(12+pwadd+wadd, 80+phadd+hadd) + Text("Protrusion Properties:") + BeginAlign() + minheight = Number("Min Height: ",EVENT_NONE,12+pwadd+wadd,57+phadd+hadd,145,18,minheight.val,-100.0,100.0,"Minimum height of any protrusion") + maxheight = Number("Max Height: ",EVENT_NONE,162+pwadd+wadd,57+phadd+hadd,145,18,maxheight.val,-100.0,100.0,"Maximum height of any protrusion") + EndAlign() + BeginAlign() + mintaper = Number("Min Taper %: ",EVENT_NONE,12+pwadd+wadd,37+phadd+hadd,145,18,mintaper.val,0,100,"Minimum taper percentage of protrusion") + maxtaper = Number("Max Taper %: ",EVENT_NONE,162+pwadd+wadd,37+phadd+hadd,145,18,maxtaper.val,0,100,"Maximum taper percentage of protrusion") + EndAlign() + glRasterPos2d(19+pwadd+wadd, 22+phadd+hadd) + Text("Number of protrusions:") + BeginAlign() + sub1 = Toggle("1",EVENT_NONE,12+pwadd+wadd,phadd+hadd,34,18,sub1.val,"One Protrusion") + sub2 = Toggle("2",EVENT_NONE,48+pwadd+wadd,phadd+hadd,34,18,sub2.val,"Two Protrusions") + sub3 = Toggle("3",EVENT_NONE,84+pwadd+wadd,phadd+hadd,34,18,sub3.val,"Three Protrusions") + sub4 = Toggle("4",EVENT_NONE,120+pwadd+wadd,phadd+hadd,34,18,sub4.val,"Four Protrusions") + EndAlign() + glRasterPos2d(195+pwadd+wadd, 22+phadd+hadd) + Text("Select tops of:") + BeginAlign() + selface1 = Toggle("1",EVENT_NONE,165+pwadd+wadd,phadd+hadd,34,18,selface1.val,"Select the tip of the protrusion when it is created") + selface2 = Toggle("2",EVENT_NONE,201+pwadd+wadd,phadd+hadd,34,18,selface2.val,"Select the tips of each protrusion when they are created") + selface3 = Toggle("3",EVENT_NONE,237+pwadd+wadd,phadd+hadd,34,18,selface3.val,"Select the tips of each protrusion when they are created") + selface4 = Toggle("4",EVENT_NONE,273+pwadd+wadd,phadd+hadd,34,18,selface4.val,"Select the tips of each protrusion when they are created") + EndAlign() + #Doodads + colorbox(8+dwadd+wadd,175+dhadd+hadd,312+dwadd+wadd,dhadd-5+hadd) + glColor3f(0.0,0.0,0.0) + glRasterPos2d(12+dwadd+wadd, 165+dhadd+hadd) + Text("Doodads:") + BeginAlign() + dood1 = Toggle("1 Box",EVENT_NONE,12+dwadd+wadd,142+dhadd+hadd,45,18,dood1.val,"Creates a rectangular box") + dood2 = Toggle("2 Box",EVENT_NONE,61+dwadd+wadd,142+dhadd+hadd,45,18,dood2.val,"Creates 2 side-by-side rectangular boxes") + dood3 = Toggle("3 Box",EVENT_NONE,110+dwadd+wadd,142+dhadd+hadd,45,18,dood3.val,"Creates 3 side-by-side rectangular boxes") + EndAlign() + BeginAlign() + dood4 = Toggle("\"L\"",EVENT_NONE,164+dwadd+wadd,142+dhadd+hadd,45,18,dood4.val,"Creates a Tetris-style \"L\" shape") + dood5 = Toggle("\"T\"",EVENT_NONE,213+dwadd+wadd,142+dhadd+hadd,45,18,dood5.val,"Creates a Tetris-style \"T\" shape") + dood6 = Toggle("\"S\"",EVENT_NONE,262+dwadd+wadd,142+dhadd+hadd,45,18,dood6.val,"Creates a sort-of \"S\" or \"Z\" shape") + EndAlign() + dodoodads = Toggle("Make Doodads",EVENT_NONE,12+dwadd+wadd,120+dhadd+hadd,145,18,dodoodads.val,"Make Doodads?") + doodadfacechange = Number("Face %: ",EVENT_NONE,162+dwadd+wadd,120+dhadd+hadd,145,18,doodadfacechange.val,0,100,"Percentage of faces that will gain doodads") + seldoodad = Toggle("Select Doodads",EVENT_NONE,12+dwadd+wadd,100+dhadd+hadd,145,18,seldoodad.val,"Selects doodads when they are created") + seldoodtop = Toggle("Only Select Tops",EVENT_NONE,162+dwadd+wadd,100+dhadd+hadd,145,18,seldoodtop.val,"Only Selects tops of doodads when\"Select Doodads\" is on") + doodonselface = Toggle("Only selected faces",EVENT_NONE,12+dwadd+wadd,80+dhadd+hadd,145,18,doodonselface.val,"Only create doodads on selected faces") + onprot = Toggle("Only on Protrusions",EVENT_NONE,162+dwadd+wadd,80+dhadd+hadd,145,18,onprot.val,"Only place doodads on protrusions") + + #Doodad Properties + glColor3f(0.0,0.0,0.0) + glRasterPos2d(12+dwadd+wadd, 63+dhadd+hadd) + Text("Doodad Properties:") + BeginAlign() + doodadminamount = Number("Min Amount: ",EVENT_NONE,12+dwadd+wadd,40+dhadd+hadd,145,18,doodadminamount.val,0,100,"Minimum number of doodads per face") + doodadmaxamount = Number("Max Amount: ",EVENT_NONE,162+dwadd+wadd,40+dhadd+hadd,145,18,doodadmaxamount.val,0,100,"Maximum number of doodads per face") + EndAlign() + BeginAlign() + doodheightmin = Number("Min Height: ",EVENT_NONE,12+dwadd+wadd,20+dhadd+hadd,145,18,doodheightmin.val,0.0,100.0,"Minimum height of any doodad") + doodheightmax = Number("Max Height: ",EVENT_NONE,162+dwadd+wadd,20+dhadd+hadd,145,18,doodheightmax.val,0.0,100.0,"Maximum height of any doodad") + EndAlign() + BeginAlign() + doodsizemin = Number("Min Size %: ",EVENT_NONE,12+dwadd+wadd,dhadd+hadd,145,18,doodsizemin.val,0.0,100.0,"Minimum size of any doodad in percentage of face") + doodsizemax = Number("Max Size %: ",EVENT_NONE,162+dwadd+wadd,dhadd+hadd,145,18,doodsizemax.val,0.0,100.0,"Maximum size of any doodad in percentage of face") + EndAlign() + + #Materials + colorbox(8+mwadd+wadd,93+mhadd+hadd,312+mwadd+wadd,mhadd-5+hadd) + glColor3f(0.0,0.0,0.0) + glRasterPos2d(12+mwadd+wadd, 83+mhadd+hadd) + Text("Materials:") + glRasterPos2d(12+mwadd+wadd, 43+mhadd+hadd) + Text("Assigned Material Indices:") + assignNewMats = Toggle("Assign materials by part",EVENT_NONE,32+mwadd+wadd,60+mhadd+hadd,256,18,assignNewMats.val,"Otherwise, previous materials will be preserved") + replProtSideIndex = Number("Protrusion Sides:",EVENT_NONE,12+mwadd+wadd,20+mhadd+hadd,145,18,replProtSideIndex.val,0,16,"Material index assigned to sides of protrusions") + replProtTopIndex = Number("Protrusion Tops:",EVENT_NONE,162+mwadd+wadd,20+mhadd+hadd,145,18,replProtTopIndex.val,0,16,"Material index assigned to tops of protrusions") + replDoodSideIndex = Number("Doodad Sides:",EVENT_NONE,12+mwadd+wadd,mhadd+hadd,145,18,replDoodSideIndex.val,0,16,"Material index assigned to sides of doodads") + replDoodTopIndex = Number("Doodad Tops:",EVENT_NONE,162+mwadd+wadd,mhadd+hadd,145,18,replDoodTopIndex.val,0,16,"Material index assigned to tops and bottoms of doodads") + + #Global Parts + colorbox(8+gwadd+wadd,35+ghadd+hadd,312+gwadd+wadd,ghadd-5+hadd) + glColor3f(1.0,0.0,0.0) + glRasterPos2d(12+gwadd+wadd,25+ghadd+hadd) + messagetext = Text(errortext) + glColor3f(0.0,0.0,0.0) + makenewobject = Toggle("Copy Before Modifying",EVENT_NONE,162+gwadd+wadd,ghadd+hadd,145,18,makenewobject.val,"If selected, the original object will be copied before it is changed") + Button("Discombobulate",EVENT_DISCOMBOBULATE,12+gwadd+wadd,ghadd+hadd,100,18) + Button("Exit",EVENT_EXIT,120+gwadd+wadd,ghadd+hadd,30,18) + +def event(evt, val): + global wadd + global hadd + + if (evt == RIGHTARROWKEY and val): + wadd = wadd + 20 + Redraw(1) + if (evt == LEFTARROWKEY and val): + wadd = wadd - 20 + Redraw(1) + if (evt == UPARROWKEY and val): + hadd = hadd + 20 + Redraw(1) + if (evt == DOWNARROWKEY and val): + hadd = hadd - 20 + Redraw(1) + if (evt == QKEY and not val): + Exit() + +def bevent(evt): + + #Protrusions + global doprots + global facechange + global minheight + global maxheight + global sub1 + global sub2 + global sub3 + global sub4 + global mintaper + global maxtaper + global useselected + global selface1 + global selface2 + global selface3 + global selface4 + global deselectvertices + #global selectbyverts + + #Doodads + global dodoodads + global doodadfacechange + global seldoodad + global onprot + global dood1 + global dood2 + global dood3 + global dood4 + global dood5 + global dood6 + global doodadminamount + global doodadmaxamount + global doodsizemin + global doodsizemax + global doodheightmin + global doodheightmax + global doodonselface + global seldoodtop + + #Materials + global assignNewMats + global replProtSideIndex + global replProtTopIndex + global replDoodSideIndex + global replDoodTopIndex + + #Global Settings + global makenewobject + global messagetext + global errortext + global EVENT_NONE,EVENT_DRAW,EVENT_EXIT + + ######### Manages GUI events + if evt==EVENT_EXIT: + Exit() + elif evt==EVENT_DISCOMBOBULATE: + Window.WaitCursor(1) + setProtrusionValues(doprots.val,facechange.val/100,minheight.val,maxheight.val,sub1.val,sub2.val,sub3.val,sub4.val,mintaper.val/100,maxtaper.val/100,useselected.val,selface1.val,selface2.val,selface3.val,selface4.val,deselectvertices.val) + setDoodadValues(dodoodads.val,doodadfacechange.val/100,seldoodad.val,onprot.val,dood1.val,dood2.val,dood3.val,dood4.val,dood5.val,dood6.val,doodadminamount.val,doodadmaxamount.val,doodsizemin.val/100,doodsizemax.val/100,doodheightmin.val,doodheightmax.val,doodonselface.val,seldoodtop.val) + setOtherValues(makenewobject.val,assignNewMats.val,replProtSideIndex.val,replProtTopIndex.val,replDoodSideIndex.val,replDoodTopIndex.val) + discombobulate() + Window.WaitCursor(0) + Blender.Redraw() + +Register(draw, event, bevent) diff --git a/release/scripts/envelope_symmetry.py b/release/scripts/envelope_symmetry.py new file mode 100644 index 00000000000..935dae9aabe --- /dev/null +++ b/release/scripts/envelope_symmetry.py @@ -0,0 +1,174 @@ +#!BPY + +""" +Name: 'Envelope Symmetry' +Blender: 234 +Group: 'Animation' +Tooltip: 'Make envelope symetrical' +""" + +__author__ = "Jonas Petersen" +__url__ = ("blender", "elysiun", "Script's homepage, http://www.mindfloaters.de/blender/", "thread at blender.org, http://www.blender.org/modules.php?op=modload&name=phpBB2&file=viewtopic&t=4858 ") +__version__ = "0.9 2004-11-10" +__doc__ = """\ +This script creates perfectly symmetrical envelope sets. It is part of the +envelop assignment tools. + +"Envelopes" are Mesh objects with names following this naming convention: + +: + +Please check the script's homepage and the thread at blender.org (last link button above) for more info. + +For this version users need to edit the script code to change default options. +""" + +# -------------------------------------------------------------------------- +# "Envelope Symmetry" by Jonas Petersen +# Version 0.9 - 10th November 2004 - first public release +# -------------------------------------------------------------------------- +# +# A script for creating perfectly symmetrical envelope sets. It is +# part of the envelope assignment tool. +# +# It is available in Object Mode via the menu item: +# +# Object -> Scripts -> Envelope Symmetry +# +# With default settings it will: +# +# - Look for bones +# +# Find the latest version at: http://www.mindfloaters.de/blender/ +# +# -------------------------------------------------------------------------- +# $Id$ +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2004: Jonas Petersen, jonas at mindfloaters dot de +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** + +# -------------------------------------------------------------------------- +# CONFIGURATION +# -------------------------------------------------------------------------- + +# Note: Theses values will later be editable via a gui interface +# within Blender. + +# The suffix for the reference and opposite envelope. +# The configuration of of the opposite envelope will be overwritten by +# the configuration of the reference envelope (shape, position, bone, weight). +# The default is REF_SUFFIX = '.L' and OPP_SUFFIX = '.R'. +REF_SUFFIX = '.R' +OPP_SUFFIX = '.L' + +# MIRROR_AXIS defines the axis in which bones are mirrored/aligned. +# Values: +# 0 for X (default) +# 1 for Y +# 2 for Z +MIRROR_AXIS = 0 + +# SEPARATOR is the character used to delimit the bone name and the weight +# in the envelope name. +SEPARATOR = ":" + +# -------------------------------------------------------------------------- +# END OF CONFIGURATION +# -------------------------------------------------------------------------- + +import Blender, math, sys +from Blender import Mathutils +from BPyNMesh import * + +def flipFace(v): + if len(v) == 3: v[0], v[1], v[2] = v[2], v[1], v[0] + elif len(v) == 4: v[0], v[1], v[2], v[3] = v[3], v[2], v[1], v[0] + +# return object with given object name (with variable parts) and mesh name +def getObjectByName(obj_name, mesh_name): + for obj in Blender.Scene.GetCurrent().objects: + if obj.type == "Mesh": +# if obj.getName()[0:len(obj_name)] == obj_name and obj.getData().name == mesh_name: + # use only mesh_name so bone name and weight (in the envelope name) + # can be changed by the user and mirrored by the script. + if obj.getData(name_only=1) == mesh_name: + return obj + return False + +SUFFIX_LEN = len(REF_SUFFIX); + +Blender.Window.EditMode(0) + +count = 0 +for obj in Blender.Scene.GetCurrent().objects: + if obj.type != 'Mesh': + continue + + count += 1 + name = obj.name + pos = name.find(SEPARATOR) + if (pos > -1): + ApplySizeAndRotation(obj) + + base_name = name[0:pos-SUFFIX_LEN] + suffix = name[pos-SUFFIX_LEN:pos] + weight = name[pos:len(name)] # the SEPARATOR following a float value + + if suffix == REF_SUFFIX: + mesh = obj.getData() + mirror_name = base_name + OPP_SUFFIX + weight + mirror_mesh_name = mesh.name + ".mirror" + + mirror_obj = getObjectByName(base_name + OPP_SUFFIX, mirror_mesh_name) + + if mirror_obj: + + # update vertices + + mirror_mesh = mirror_obj.getData() + for i in xrange(len(mesh.verts)): + org = mesh.verts[i] + mir = mirror_mesh.verts[i] + mir.co[0], mir.co[1], mir.co[2] = org.co[0], org.co[1], org.co[2] + mir.co[MIRROR_AXIS] *= -1 + + mirror_mesh.update() + else: + + # create mirror object + + mirror_mesh = obj.data + for face in mirror_mesh.faces: + flipFace(face.v) + for vert in mirror_mesh.verts: + vert.co[MIRROR_AXIS] *= -1 + + mirror_obj = Blender.NMesh.PutRaw(mirror_mesh, mirror_mesh_name) + + # update name, drawType and location + + mirror_obj.setName(mirror_name) + mirror_obj.drawType = obj.drawType + + loc = [obj.LocX, obj.LocY, obj.LocZ] + loc[MIRROR_AXIS] *= -1 + mirror_obj.setLocation(loc) + +Blender.Window.EditMode(0) diff --git a/release/scripts/export-iv-0.1.py b/release/scripts/export-iv-0.1.py new file mode 100644 index 00000000000..647dd9c5518 --- /dev/null +++ b/release/scripts/export-iv-0.1.py @@ -0,0 +1,304 @@ +#!BPY + +""" +Name: 'OpenInventor (.iv)...' +Blender: 236 +Group: 'Export' +Tip: 'Export to OpenInventor file format. (.iv)' +""" +__author__ = ("Radek Barton") +__url__ = ["http://blackhex.no-ip.org/"] +__email__ = ["scripts"] +__version__ = "0.1" + + +__bpydoc__ = """\ +This script exports to the Open Inventor format. + +Usage: + +Run this script from "File->Export" menu. + +Note: +""" +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Radek Barton +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# + +import Blender +math_pi= 3.1415926535897931 + +def WriteHeader(file): + file.write("#Inventor V2.1 ascii\n\n") + file.write("Separator\n") + file.write("{\n") + file.write(" ShapeHints\n") + file.write(" {\n") + file.write(" vertexOrdering COUNTERCLOCKWISE\n") + file.write(" }\n") + +def WriteFooter(file): + file.write("}\n") + +def WriteMesh(file, ob): + file.write(" Separator\n") + file.write(" {\n") + file.write(" # %s\n" % ob.name) + WriteMatrix(file, ob) + mesh = ob.getData() + WriteMaterials(file, mesh) + WriteTexture(file, mesh) + WriteNormals(file, mesh) + WriteVertices(file, mesh) + WriteFaces(file, mesh) + file.write(" }\n") + +def WriteMatrix(file, ob): + matrix = ob.getMatrix() + file.write(" MatrixTransform\n") + file.write(" {\n") + file.write(" matrix\n") + for line in matrix: + file.write(" %.6f %.6f %.6f %.6f\n" % (line[0], line[1], line[2], line[3])) + file.write(" }\n") + +def WriteColors(file, mesh): + file.write(" vertexProperty VertexProperty\n") + file.write(" {\n") + file.write(" orderedRGBA\n") + file.write(" [\n") + for face in mesh.faces: + for I in xrange(len(face)): + file.write(" 0x%02x%02x%02x%02x,\n" % (face.col[I].r, + face.col[I].g, face.col[I].b, face.col[I].a)) + file.write(" ]\n") + file.write(" materialBinding PER_VERTEX\n") + file.write(" }\n") + +def WriteMaterials(file, mesh): + if mesh.materials: + file.write(" Material\n") + file.write(" {\n") + file.write(" ambientColor\n") + file.write(" [\n") + for mat in mesh.materials: + file.write(" %.6f %.6f %.6f,\n" % (mat.mirCol[0], mat.mirCol[1], + mat.mirCol[2])) + file.write(" ]\n") + file.write(" diffuseColor\n") + file.write(" [\n") + for mat in mesh.materials: + file.write(" %.6f %.6f %.6f,\n" % (mat.rgbCol[0], mat.rgbCol[1], + mat.rgbCol[2])) + file.write(" ]\n") + file.write(" specularColor\n") + file.write(" [\n") + for mat in mesh.materials: + file.write(" %.6f %.6f %.6f,\n" % (mat.specCol[0] * mat.spec / 2.0, + mat.specCol[1] * mat.spec / 2.0, mat.specCol[2] * mat.spec / 2.0)) + file.write(" ]\n") + file.write(" emissiveColor\n") + file.write(" [\n") + for mat in mesh.materials: + file.write(" %.6f %.6f %.6f,\n" % (mat.rgbCol[0] * mat.emit, + mat.rgbCol[1] * mat.emit, mat.rgbCol[0] * mat.emit)) + file.write(" ]\n") + file.write(" shininess\n") + file.write(" [\n") + for mat in mesh.materials: + file.write(" %.6f,\n" % (mat.hard / 255.0)) + file.write(" ]\n") + file.write(" transparency\n") + file.write(" [\n") + for mat in mesh.materials: + file.write(" %.6f,\n" % (1.0 - mat.alpha)) + file.write(" ]\n") + file.write(" }\n") + file.write(" MaterialBinding\n") + file.write(" {\n") + file.write(" value PER_FACE_INDEXED\n") + file.write(" }\n") + +def WriteTexture(file, mesh): + texture = mesh.faces[0].image # BAD Ju Ju + if texture: + file.write(" Texture2\n") + file.write(" {\n") + file.write(' filename "%s"\n' % texture.getName()) + file.write(" }\n") + file.write(" TextureCoordinate2\n") + file.write(" {\n") + file.write(" point\n") + file.write(" [\n") + if mesh.hasVertexUV(): + for vert in mesh.verts: + file.write(" %s %s,\n" % (vert.uvco[0], vert.uvco[1])) + file.write(" ]\n") + file.write(" }\n") + file.write(" TextureCoordinateBinding\n") + file.write(" {\n") + file.write(" value PER_VERTEX_INDEXED\n") + file.write(" }\n") + elif mesh.hasFaceUV(): + for face in mesh.faces: + for uv in face.uv: + file.write(" %.6f %.6f,\n" % (uv[0], uv[1])) + file.write(" ]\n") + file.write(" }\n") + file.write(" TextureCoordinateBinding\n") + file.write(" {\n") + file.write(" value PER_VERTEX\n") + file.write(" }\n") + +def WriteVertices(file, mesh): + file.write(" Coordinate3\n") + file.write(" {\n") + file.write(" point\n") + file.write(" [\n") + for vert in mesh.verts: + file.write(" %.6f %.6f %.6f,\n" % (vert[0], vert[1], vert[2])) + file.write(" ]\n") + file.write(" }\n") + +def WriteNormals(file, mesh): + file.write(" Normal\n") + file.write(" {\n") + file.write(" vector\n") + file.write(" [\n") + + # make copy of vertex normals + normals = [] + for face in mesh.faces: + if len(face.v) in [3, 4]: + if face.smooth: + for v in face.v: + normals.append(v.no) + else: + for v in face.v: + normals.append(face.no) + + # write normals + for no in normals: + file.write(" %.6f %.6f %.6f,\n" % (no[0], no[1], no[2])) + file.write(" ]\n") + file.write(" }\n") + + # write way how normals are binded + file.write(" NormalBinding\n") + file.write(" {\n") + file.write(" value PER_VERTEX\n") + file.write(" }\n") + +def WriteFaces(file, mesh): + file.write(" IndexedFaceSet\n") + file.write(" {\n") + + # write vertex paint + if mesh.hasVertexColours(): + WriteColors(file, mesh) + + # write material indexes + file.write(" materialIndex\n") + file.write(" [\n") + for face in mesh.faces: + file.write(" %i,\n" % face.mat); + file.write(" ]\n") + + # write faces with coordinate indexes + file.write(" coordIndex\n") + file.write(" [\n") + for face in mesh.faces: + face_v= face.v + if len(face_v) == 3: + file.write(" %i, %i, %i, -1,\n" % (face_v[0].index, + face_v[1].index, face_v[2].index)) + elif len(face_v) == 4: + file.write(" %i, %i, %i, %i, -1,\n" % (face_v[0].index, + face_v[1].index, face_v[2].index, face_v[3].index)) + file.write(" ]\n") + file.write(" }\n") + + +def WriteCamera(file, ob): + camera = ob.getData(); + # perspective camera + if camera.type == 0: + file.write(" PerspectiveCamera\n") + file.write(" {\n") + file.write(" nearDistance %s\n" % (camera.clipStart)) + file.write(" farDistance %s\n" % (camera.clipEnd)) + file.write(" }\n") + # ortho camera + else: + print camera.type + +def WriteLamp(file, ob): + lamp = ob.getData(); + # spot lamp + if lamp.type == 2: + file.write(" SpotLight\n") + file.write(" {\n") + file.write(" intensity %s\n" % (lamp.energy / 10.0)) + file.write(" color %s %s %s\n" % (lamp.col[0], lamp.col[1], lamp.col[2])) + #file.write(" location %s\n" % ()) + #file.write(" direction %s\n" % ()) + file.write(" dropOffRate %s\n" % (lamp.spotBlend)) + file.write(" cutOffAngle %s\n" % (lamp.spotSize * math_pi / 180.0)) + file.write(" }\n") + +# script main function +def ExportToIv(file_name): + scene = Blender.Scene.GetCurrent() + file = open(file_name, "w") + + # make lists of individual ob types + meshes = [] + lamps = [] + cameras = [] + for ob in scene.objects: + obtype= ob.type + if obtype == "Mesh": + meshes.append(ob); + #elif obtype == "Lamp": + # lamps.append(ob); + #elif obtype == "Camera": + # cameras.append(ob); + #else: + # print "Exporting %s objects isn't supported!" % ob.type + + # write header, footer and groups of ob types + WriteHeader(file); + #for camera in cameras: + # WriteCamera(file, camera); + #for lamp in lamps: + # WriteLamp(file, lamp) + for mesh in meshes: + WriteMesh(file, mesh) + WriteFooter(file) + + file.close() + +def FileSelectorCB(file_name): + if not file_name.lower().endswith('.iv'): + file_name += '.iv' + ExportToIv(file_name) + +if __name__ == '__main__': + Blender.Window.FileSelector(FileSelectorCB, "Export IV", Blender.sys.makename(ext='.iv')) diff --git a/release/scripts/export_cal3d.py b/release/scripts/export_cal3d.py new file mode 100644 index 00000000000..990ac480e3d --- /dev/null +++ b/release/scripts/export_cal3d.py @@ -0,0 +1,1112 @@ +#!BPY +""" +Name: 'Cal3D (.cfg .xaf .xsf .xmf .xrf)...' +Blender: 243 +Group: 'Export' +Tip: 'Export armature/bone/mesh/action data to the Cal3D format.' +""" + +# export_cal3d.py +# Copyright (C) 2003-2004 Jean-Baptiste LAMY -- jibalamy@free.fr +# Copyright (C) 2004 Matthias Braun -- matze@braunis.de +# +# 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 + + +__version__ = '0.9f' +__author__ = 'Jean-Baptiste, Jiba, Lamy, Campbell Barton (Ideasman42)' +__email__ = ['Authors email, jibalamy:free*fr'] +__url__ = ['Soya3ds homepage, http://home.gna.org/oomadness/en/soya/', 'Cal3d, http://cal3d.sourceforge.net'] +__bpydoc__ =\ +'''This script is a Blender => Cal3D converter. +(See http://blender.org and http://cal3d.sourceforge.net) + +USAGE: + +To install it, place the script in your $HOME/.blender/scripts directory. + +Then open the File->Export->Cal3d v0.9 menu. And select the filename of the .cfg file. +The exporter will create a set of other files with same prefix (ie. bla.cfg, bla.xsf, +bla_Action1.xaf, bla_Action2.xaf, ...). + +You should be able to open the .cfg file in cal3d_miniviewer. + + +NOT (YET) SUPPORTED: + + - Rotation, translation, or stretching Blender objects is still quite +buggy, so AVOID MOVING / ROTATING / RESIZE OBJECTS (either mesh or armature) ! +Instead, edit the object (with tab), select all points / bones (with "a"), +and move / rotate / resize them.
+ - no support for exporting springs yet
+ - no support for exporting material colors (most games should only use images +I think...) + + +KNOWN ISSUES: + + - Cal3D versions <=0.9.1 have a bug where animations aren't played when the root bone +is not animated;
+ - Cal3D versions <=0.9.1 have a bug where objects that aren't influenced by any bones +are not drawn (fixed in Cal3D CVS). + + +NOTES: + +It requires a very recent version of Blender (>= 2.44). + +Build a model following a few rules:
+ - Use only a single armature;
+ - Use only a single rootbone (Cal3D doesn't support floating bones);
+ - Use only locrot keys (Cal3D doesn't support bone's size change);
+ - Don't try to create child/parent constructs in blender object, that gets exported +incorrectly at the moment;
+ - Objects or animations whose names start by "_" are not exported (hidden object). + +You can pass as many parameters as you want at the end, "EXPORT_FOR_SOYA=1" is just an +example. The parameters are the same as below. +''' + +# True (=1) to export for the Soya 3D engine +# (http://oomadness.tuxfamily.org/en/soya). +# (=> rotate meshes and skeletons so as X is right, Y is top and -Z is front) +# EXPORT_FOR_SOYA = 0 + +# Enables LODs computation. LODs computation is quite slow, and the algo is +# surely not optimal :-( +LODS = 0 + +# Scale the model (not supported by Soya). + +# See also BASE_MATRIX below, if you want to rotate/scale/translate the model at +# the exportation. + +######################################################################################### +# Code starts here. +# The script should be quite re-useable for writing another Blender animation exporter. +# Most of the hell of it is to deal with Blender's head-tail-roll bone's definition. + +import math +import Blender +import BPyMesh +import BPySys +import BPyArmature +import BPyObject +import bpy + +def best_armature_root(armature): + ''' + Find the armature root bone with the most children, return that bone + ''' + + bones = [bone for bone in armature.bones.values() if bone.hasChildren() == True] + if len(bones) == 1: + return bones[0] + + # Get the best root since we have more then 1 + bones = [(len(bone.getAllChildren()), bone) for bone in bones] + bones.sort() + return bones[-1][1] # bone with most children + + +Vector = Blender.Mathutils.Vector +Quaternion = Blender.Mathutils.Quaternion +Matrix = Blender.Mathutils.Matrix + +# HACK -- it seems that some Blender versions don't define sys.argv, +# which may crash Python if a warning occurs. +# if not hasattr(sys, 'argv'): sys.argv = ['???'] + +def matrix_multiply(b, a): + return [ [ + a[0][0] * b[0][0] + a[0][1] * b[1][0] + a[0][2] * b[2][0], + a[0][0] * b[0][1] + a[0][1] * b[1][1] + a[0][2] * b[2][1], + a[0][0] * b[0][2] + a[0][1] * b[1][2] + a[0][2] * b[2][2], + 0.0, + ], [ + a[1][0] * b[0][0] + a[1][1] * b[1][0] + a[1][2] * b[2][0], + a[1][0] * b[0][1] + a[1][1] * b[1][1] + a[1][2] * b[2][1], + a[1][0] * b[0][2] + a[1][1] * b[1][2] + a[1][2] * b[2][2], + 0.0, + ], [ + a[2][0] * b[0][0] + a[2][1] * b[1][0] + a[2][2] * b[2][0], + a[2][0] * b[0][1] + a[2][1] * b[1][1] + a[2][2] * b[2][1], + a[2][0] * b[0][2] + a[2][1] * b[1][2] + a[2][2] * b[2][2], + 0.0, + ], [ + a[3][0] * b[0][0] + a[3][1] * b[1][0] + a[3][2] * b[2][0] + b[3][0], + a[3][0] * b[0][1] + a[3][1] * b[1][1] + a[3][2] * b[2][1] + b[3][1], + a[3][0] * b[0][2] + a[3][1] * b[1][2] + a[3][2] * b[2][2] + b[3][2], + 1.0, + ] ] + +# multiplies 2 quaternions in x,y,z,w notation +def quaternion_multiply(q1, q2): + return Quaternion(\ + q2[3] * q1[0] + q2[0] * q1[3] + q2[1] * q1[2] - q2[2] * q1[1], + q2[3] * q1[1] + q2[1] * q1[3] + q2[2] * q1[0] - q2[0] * q1[2], + q2[3] * q1[2] + q2[2] * q1[3] + q2[0] * q1[1] - q2[1] * q1[0], + q2[3] * q1[3] - q2[0] * q1[0] - q2[1] * q1[1] - q2[2] * q1[2],\ + ) + +def matrix_translate(m, v): + m[3][0] += v[0] + m[3][1] += v[1] + m[3][2] += v[2] + return m + +def matrix2quaternion(m): + s = math.sqrt(abs(m[0][0] + m[1][1] + m[2][2] + m[3][3])) + if s == 0.0: + x = abs(m[2][1] - m[1][2]) + y = abs(m[0][2] - m[2][0]) + z = abs(m[1][0] - m[0][1]) + if (x >= y) and (x >= z): return Quaternion(1.0, 0.0, 0.0, 0.0) + elif (y >= x) and (y >= z): return Quaternion(0.0, 1.0, 0.0, 0.0) + else: return Quaternion(0.0, 0.0, 1.0, 0.0) + + q = Quaternion([ + -(m[2][1] - m[1][2]) / (2.0 * s), + -(m[0][2] - m[2][0]) / (2.0 * s), + -(m[1][0] - m[0][1]) / (2.0 * s), + 0.5 * s, + ]) + q.normalize() + #print q + return q + +def vector_by_matrix_3x3(p, m): + return [p[0] * m[0][0] + p[1] * m[1][0] + p[2] * m[2][0], + p[0] * m[0][1] + p[1] * m[1][1] + p[2] * m[2][1], + p[0] * m[0][2] + p[1] * m[1][2] + p[2] * m[2][2]] + +def vector_add(v1, v2): + return [v1[0]+v2[0], v1[1]+v2[1], v1[2]+v2[2]] + +def vector_sub(v1, v2): + return [v1[0]-v2[0], v1[1]-v2[1], v1[2]-v2[2]] + +def quaternion2matrix(q): + xx = q[0] * q[0] + yy = q[1] * q[1] + zz = q[2] * q[2] + xy = q[0] * q[1] + xz = q[0] * q[2] + yz = q[1] * q[2] + wx = q[3] * q[0] + wy = q[3] * q[1] + wz = q[3] * q[2] + return Matrix([1.0 - 2.0 * (yy + zz), 2.0 * (xy + wz), 2.0 * (xz - wy), 0.0], + [ 2.0 * (xy - wz), 1.0 - 2.0 * (xx + zz), 2.0 * (yz + wx), 0.0], + [ 2.0 * (xz + wy), 2.0 * (yz - wx), 1.0 - 2.0 * (xx + yy), 0.0], + [0.0 , 0.0 , 0.0 , 1.0]) + +def matrix_invert(m): + det = (m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]) + - m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2]) + + m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2])) + if det == 0.0: return None + det = 1.0 / det + r = [ [ + det * (m[1][1] * m[2][2] - m[2][1] * m[1][2]), + - det * (m[0][1] * m[2][2] - m[2][1] * m[0][2]), + det * (m[0][1] * m[1][2] - m[1][1] * m[0][2]), + 0.0, + ], [ + - det * (m[1][0] * m[2][2] - m[2][0] * m[1][2]), + det * (m[0][0] * m[2][2] - m[2][0] * m[0][2]), + - det * (m[0][0] * m[1][2] - m[1][0] * m[0][2]), + 0.0 + ], [ + det * (m[1][0] * m[2][1] - m[2][0] * m[1][1]), + - det * (m[0][0] * m[2][1] - m[2][0] * m[0][1]), + det * (m[0][0] * m[1][1] - m[1][0] * m[0][1]), + 0.0, + ] ] + r.append([ + -(m[3][0] * r[0][0] + m[3][1] * r[1][0] + m[3][2] * r[2][0]), + -(m[3][0] * r[0][1] + m[3][1] * r[1][1] + m[3][2] * r[2][1]), + -(m[3][0] * r[0][2] + m[3][1] * r[1][2] + m[3][2] * r[2][2]), + 1.0, + ]) + return r + + +def point_by_matrix(p, m): + return [p[0] * m[0][0] + p[1] * m[1][0] + p[2] * m[2][0] + m[3][0], + p[0] * m[0][1] + p[1] * m[1][1] + p[2] * m[2][1] + m[3][1], + p[0] * m[0][2] + p[1] * m[1][2] + p[2] * m[2][2] + m[3][2]] + +# Hack for having the model rotated right. +# Put in BASE_MATRIX your own rotation if you need some. + +BASE_MATRIX = None + + +# Cal3D data structures + +CAL3D_VERSION = 910 +MATERIALS = {} # keys are (mat.name, img.name) + +class Cal3DMaterial(object): + __slots__ = 'amb', 'diff', 'spec', 'shininess', 'maps_filenames', 'id' + def __init__(self, blend_world, blend_material, blend_images): + + # Material Settings + if blend_world: amb = [ int(c*255) for c in blend_world.amb ] + else: amb = [0,0,0] # Default value + + if blend_material: + self.amb = tuple([int(c*blend_material.amb) for c in amb] + [255]) + self.diff = tuple([int(c*255) for c in blend_material.rgbCol] + [int(blend_material.alpha*255)]) + self.spec = tuple([int(c*255) for c in blend_material.rgbCol] + [int(blend_material.alpha*255)]) + self.shininess = (float(blend_material.hard)-1)/5.10 + else: + self.amb = tuple(amb + [255]) + self.diff = (255,255,255,255) + self.spec = (255,255,255,255) + self.shininess = 1.0 + + self.maps_filenames = [] + for image in blend_images: + if image: + self.maps_filenames.append( image.filename.split('\\')[-1].split('/')[-1] ) + + self.id = len(MATERIALS) + MATERIALS[blend_material, blend_images] = self + + # new xml format + def writeCal3D(self, file): + file.write('\n') + file.write('

\n' % CAL3D_VERSION) + file.write('\n' % len(self.maps_filenames)) + file.write('\t%i %i %i %i\n' % self.amb) + file.write('\t%i %i %i %i\n' % self.diff) + file.write('\t%i %i %i %i\n' % self.spec) + file.write('\t%.6f\n' % self.shininess) + + for map_filename in self.maps_filenames: + file.write('\t%s\n' % map_filename) + + file.write('\n') + + +class Cal3DMesh(object): + __slots__ = 'name', 'submeshes', 'matrix', 'matrix_normal' + def __init__(self, ob, blend_mesh, blend_world): + self.name = ob.name + self.submeshes = [] + + BPyMesh.meshCalcNormals(blend_mesh) + + self.matrix = ob.matrixWorld + self.matrix_normal = self.matrix.copy().rotationPart() + + #if BASE_MATRIX: + # matrix = matrix_multiply(BASE_MATRIX, matrix) + + face_groups = {} + blend_materials = blend_mesh.materials + uvlayers = () + mat = None # incase we have no materials + if blend_mesh.faceUV: + uvlayers = blend_mesh.getUVLayerNames() + if len(uvlayers) == 1: + for f in blend_mesh.faces: + image = (f.image,) # bit in a tuple so we can match multi UV code + if blend_materials: mat = blend_materials[f.mat] # if no materials, mat will always be None + face_groups.setdefault( (mat,image), (mat,image,[]) )[2].append( f ) + else: + # Multi UV's + face_multi_images = [[] for i in xrange(len(blend_mesh.faces))] + face_multi_uvs = [[[] for i in xrange(len(f)) ] for f in blend_mesh.faces] + for uvlayer in uvlayers: + blend_mesh.activeUVLayer = uvlayer + for i, f in enumerate(blend_mesh.faces): + face_multi_images[i].append(f.image) + if f.image: + for j, uv in enumerate(f.uv): + face_multi_uvs[i][j].append( tuple(uv) ) + + # Convert UV's to tuples so they can be compared with eachother + # when creating new verts + for fuv in face_multi_uvs: + for i, uv in enumerate(fuv): + fuv[i] = tuple(uv) + + for i, f in enumerate(blend_mesh.faces): + image = tuple(face_multi_images[i]) + if blend_materials: mat = blend_materials[f.mat] + face_groups.setdefault( (mat,image), (mat,image,[]) )[2].append( f ) + else: + # No UV's + for f in blend_mesh.faces: + if blend_materials: mat = blend_materials[f.mat] + face_groups.setdefault( (mat,()), (mat,(),[]) )[2].append( f ) + + for blend_material, blend_images, faces in face_groups.itervalues(): + + try: material = MATERIALS[blend_material, blend_images] + except: material = MATERIALS[blend_material, blend_images] = Cal3DMaterial(blend_world, blend_material, blend_images) + + submesh = Cal3DSubMesh(self, material, len(self.submeshes)) + self.submeshes.append(submesh) + + # Check weather we need to write UVs, dont do it if theres no image + # Multilayer UV's have alredy checked that they have images when + # building face_multi_uvs + if len(uvlayers) == 1: + if blend_images == (None,): + write_single_layer_uvs = False + else: + write_single_layer_uvs = True + + + for face in faces: + + if not face.smooth: + normal = face.no + + face_vertices = [] + face_v = face.v + + + if len(uvlayers)>1: + for i, blend_vert in enumerate(face_v): + if face.smooth: normal = blend_vert.no + vertex = submesh.getVertex(blend_mesh, blend_vert, normal, face_multi_uvs[face.index][i]) + face_vertices.append(vertex) + + elif len(uvlayers)==1: + if write_single_layer_uvs: + face_uv = face.uv + + for i, blend_vert in enumerate(face_v): + if face.smooth: normal = blend_vert.no + if write_single_layer_uvs: uvs = (tuple(face_uv[i]),) + else: uvs = () + + vertex = submesh.getVertex(blend_mesh, blend_vert, normal, uvs ) + face_vertices.append(vertex) + else: + # No UVs + for i, blend_vert in enumerate(face_v): + if face.smooth: normal = blend_vert.no + vertex = submesh.getVertex(blend_mesh, blend_vert, normal, () ) + face_vertices.append(vertex) + + + # Split faces with more than 3 vertices + for i in xrange(1, len(face) - 1): + submesh.faces.append(Cal3DFace(face_vertices[0], face_vertices[i], face_vertices[i + 1])) + + def writeCal3D(self, file): + file.write('\n') + file.write('
\n' % CAL3D_VERSION) + file.write('\n' % len(self.submeshes)) + for submesh in self.submeshes: + submesh.writeCal3D(file, self.matrix, self.matrix_normal) + file.write('\n') + + +class Cal3DSubMesh(object): + __slots__ = 'material', 'vertices', 'vert_mapping', 'vert_count', 'faces', 'nb_lodsteps', 'springs', 'id' + def __init__(self, mesh, material, id): + self.material = material + self.vertices = [] + self.vert_mapping = {} # map original indicies to local + self.vert_count = 0 + self.faces = [] + self.nb_lodsteps = 0 + self.springs = [] + self.id = id + + def getVertex(self, blend_mesh, blend_vert, normal, maps): + ''' + Request a vertex, and create a new one or return a matching vertex + ''' + blend_index = blend_vert.index + index_map = self.vert_mapping.get(blend_index) + + if index_map == None: + vertex = Cal3DVertex(blend_vert.co, normal, maps, blend_mesh.getVertexInfluences(blend_index)) + self.vertices.append([vertex]) + self.vert_mapping[blend_index] = len(self.vert_mapping) + self.vert_count +=1 + return vertex + else: + vertex_list = self.vertices[index_map] + + for v in vertex_list: + if v.normal == normal and\ + v.maps == maps: + return v # reusing + + # No match, add a new vert + # Use the first verts influences + vertex = Cal3DVertex(blend_vert.co, normal, maps, vertex_list[0].influences) + vertex_list.append(vertex) + # self.vert_mapping[blend_index] = len(self.vert_mapping) + self.vert_count +=1 + return vertex + + + def compute_lods(self): + '''Computes LODs info for Cal3D (there's no Blender related stuff here).''' + + print 'Start LODs computation...' + vertex2faces = {} + for face in self.faces: + for vertex in (face.vertex1, face.vertex2, face.vertex3): + l = vertex2faces.get(vertex) + if not l: vertex2faces[vertex] = [face] + else: l.append(face) + + couple_treated = {} + couple_collapse_factor = [] + for face in self.faces: + for a, b in ((face.vertex1, face.vertex2), (face.vertex1, face.vertex3), (face.vertex2, face.vertex3)): + a = a.cloned_from or a + b = b.cloned_from or b + if a.id > b.id: a, b = b, a + if not couple_treated.has_key((a, b)): + # The collapse factor is simply the distance between the 2 points :-( + # This should be improved !! + if vector_dotproduct(a.normal, b.normal) < 0.9: continue + couple_collapse_factor.append((point_distance(a.loc, b.loc), a, b)) + couple_treated[a, b] = 1 + + couple_collapse_factor.sort() + + collapsed = {} + new_vertices = [] + new_faces = [] + for factor, v1, v2 in couple_collapse_factor: + # Determines if v1 collapses to v2 or v2 to v1. + # We choose to keep the vertex which is on the smaller number of faces, since + # this one has more chance of being in an extrimity of the body. + # Though heuristic, this rule yields very good results in practice. + if len(vertex2faces[v1]) < len(vertex2faces[v2]): v2, v1 = v1, v2 + elif len(vertex2faces[v1]) == len(vertex2faces[v2]): + if collapsed.get(v1, 0): v2, v1 = v1, v2 # v1 already collapsed, try v2 + + if (not collapsed.get(v1, 0)) and (not collapsed.get(v2, 0)): + collapsed[v1] = 1 + collapsed[v2] = 1 + + # Check if v2 is already colapsed + while v2.collapse_to: v2 = v2.collapse_to + + common_faces = filter(vertex2faces[v1].__contains__, vertex2faces[v2]) + + v1.collapse_to = v2 + v1.face_collapse_count = len(common_faces) + + for clone in v1.clones: + # Find the clone of v2 that correspond to this clone of v1 + possibles = [] + for face in vertex2faces[clone]: + possibles.append(face.vertex1) + possibles.append(face.vertex2) + possibles.append(face.vertex3) + clone.collapse_to = v2 + for vertex in v2.clones: + if vertex in possibles: + clone.collapse_to = vertex + break + + clone.face_collapse_count = 0 + new_vertices.append(clone) + + # HACK -- all faces get collapsed with v1 (and no faces are collapsed with v1's + # clones). This is why we add v1 in new_vertices after v1's clones. + # This hack has no other incidence that consuming a little few memory for the + # extra faces if some v1's clone are collapsed but v1 is not. + new_vertices.append(v1) + + self.nb_lodsteps += 1 + len(v1.clones) + + new_faces.extend(common_faces) + for face in common_faces: + face.can_collapse = 1 + + # Updates vertex2faces + vertex2faces[face.vertex1].remove(face) + vertex2faces[face.vertex2].remove(face) + vertex2faces[face.vertex3].remove(face) + vertex2faces[v2].extend(vertex2faces[v1]) + + new_vertices.extend(filter(lambda vertex: not vertex.collapse_to, self.vertices)) + new_vertices.reverse() # Cal3D want LODed vertices at the end + for i in xrange(len(new_vertices)): new_vertices[i].id = i + self.vertices = new_vertices + + new_faces.extend(filter(lambda face: not face.can_collapse, self.faces)) + new_faces.reverse() # Cal3D want LODed faces at the end + self.faces = new_faces + + print 'LODs computed : %s vertices can be removed (from a total of %s).' % (self.nb_lodsteps, len(self.vertices)) + + + def writeCal3D(self, file, matrix, matrix_normal): + + file.write('\t\n' % \ + (self.nb_lodsteps, len(self.springs), + len(self.material.maps_filenames))) + + i = 0 + for v in self.vertices: + for item in v: + item.id = i + item.writeCal3D(file, matrix, matrix_normal) + i += 1 + + for item in self.springs: + item.writeCal3D(file) + for item in self.faces: + item.writeCal3D(file) + + file.write('\t\n') + +class Cal3DVertex(object): + __slots__ = 'loc','normal','collapse_to','face_collapse_count','maps','influences','weight','cloned_from','clones','id' + def __init__(self, loc, normal, maps, blend_influences): + self.loc = loc + self.normal = normal + self.collapse_to = None + self.face_collapse_count = 0 + self.maps = maps + self.weight = None + + self.cloned_from = None + self.clones = [] + + self.id = -1 + + if len(blend_influences) == 0 or isinstance(blend_influences[0], Cal3DInfluence): + # This is a copy from another vert + self.influences = blend_influences + else: + # Pass the blender influences + + self.influences = [] + # should this really be a warning? (well currently enabled, + # because blender has some bugs where it doesn't return + # influences in python api though they are set, and because + # cal3d<=0.9.1 had bugs where objects without influences + # aren't drawn. + #if not blend_influences: + # print 'A vertex of object "%s" has no influences.\n(This occurs on objects placed in an invisible layer, you can fix it by using a single layer)' % ob.name + + # sum of influences is not always 1.0 in Blender ?!?! + sum = 0.0 + + for bone_name, weight in blend_influences: + sum += weight + + for bone_name, weight in blend_influences: + bone = BONES.get(bone_name) + if not bone: # keys + # print 'Couldnt find bone "%s" which influences object "%s"' % (bone_name, ob.name) + continue + + if weight: + self.influences.append(Cal3DInfluence(bone, weight / sum)) + + + def writeCal3D(self, file, matrix, matrix_normal): + if self.collapse_to: + collapse_id = self.collapse_to.id + else: + collapse_id = -1 + file.write('\t\t\n' % \ + (self.id, len(self.influences))) + file.write('\t\t\t%.6f %.6f %.6f\n' % tuple(self.loc*matrix)) + file.write('\t\t\t%.6f %.6f %.6f\n' % tuple( (self.normal*matrix_normal).normalize() )) + if collapse_id != -1: + file.write('\t\t\t%i\n' % collapse_id) + file.write('\t\t\t%i\n' % \ + self.face_collapse_count) + + for uv in self.maps: + # we cant have more UV's then our materials image maps + # check for this + file.write('\t\t\t%.6f %.6f\n' % uv) + + for item in self.influences: + item.writeCal3D(file) + + if self.weight != None: + file.write('\t\t\t%.6f\n' % len(self.weight)) + file.write('\t\t\n') + +class Cal3DInfluence(object): + __slots__ = 'bone', 'weight' + def __init__(self, bone, weight): + self.bone = bone + self.weight = weight + + def writeCal3D(self, file): + file.write('\t\t\t%.6f\n' % \ + (self.bone.id, self.weight)) + +class Cal3DSpring(object): + __slots__ = 'vertex1', 'vertex2', 'spring_coefficient', 'idlelength' + def __init__(self, vertex1, vertex2): + self.vertex1 = vertex1 + self.vertex2 = vertex2 + self.spring_coefficient = 0.0 + self.idlelength = 0.0 + + def writeCal3D(self, file): + file.write('\t\t\n' % \ + (self.vertex1.id, self.vertex2.id, self.spring_coefficient, self.idlelength)) + +class Cal3DFace(object): + __slots__ = 'vertex1', 'vertex2', 'vertex3', 'can_collapse', + def __init__(self, vertex1, vertex2, vertex3): + self.vertex1 = vertex1 + self.vertex2 = vertex2 + self.vertex3 = vertex3 + self.can_collapse = 0 + + def writeCal3D(self, file): + file.write('\t\t\n' % \ + (self.vertex1.id, self.vertex2.id, self.vertex3.id)) + +class Cal3DSkeleton(object): + __slots__ = 'bones' + def __init__(self): + self.bones = [] + + def writeCal3D(self, file): + file.write('\n') + file.write('
\n' % CAL3D_VERSION) + file.write('\n' % len(self.bones)) + for item in self.bones: + item.writeCal3D(file) + + file.write('\n') + +BONES = {} +POSEBONES= {} +class Cal3DBone(object): + __slots__ = 'head', 'tail', 'name', 'cal3d_parent', 'loc', 'quat', 'children', 'matrix', 'lloc', 'lquat', 'id' + def __init__(self, skeleton, blend_bone, arm_matrix, cal3d_parent=None): + + # def treat_bone(b, parent = None): + head = blend_bone.head['BONESPACE'] + tail = blend_bone.tail['BONESPACE'] + #print parent.quat + # Turns the Blender's head-tail-roll notation into a quaternion + #quat = matrix2quaternion(blender_bone2matrix(head, tail, blend_bone.roll['BONESPACE'])) + quat = matrix2quaternion(blend_bone.matrix['BONESPACE'].copy().resize4x4()) + + # Pose location + ploc = POSEBONES[blend_bone.name].loc + + if cal3d_parent: + # Compute the translation from the parent bone's head to the child + # bone's head, in the parent bone coordinate system. + # The translation is parent_tail - parent_head + child_head, + # but parent_tail and parent_head must be converted from the parent's parent + # system coordinate into the parent system coordinate. + + parent_invert_transform = matrix_invert(quaternion2matrix(cal3d_parent.quat)) + parent_head = vector_by_matrix_3x3(cal3d_parent.head, parent_invert_transform) + parent_tail = vector_by_matrix_3x3(cal3d_parent.tail, parent_invert_transform) + ploc = vector_add(ploc, blend_bone.head['BONESPACE']) + + # EDIT!!! FIX BONE OFFSET BE CAREFULL OF THIS PART!!! ?? + #diff = vector_by_matrix_3x3(head, parent_invert_transform) + parent_tail= vector_add(parent_tail, head) + # DONE!!! + + parentheadtotail = vector_sub(parent_tail, parent_head) + # hmm this should be handled by the IPos, but isn't for non-animated + # bones which are transformed in the pose mode... + loc = parentheadtotail + + else: + # Apply the armature's matrix to the root bones + head = point_by_matrix(head, arm_matrix) + tail = point_by_matrix(tail, arm_matrix) + + loc = head + quat = matrix2quaternion(matrix_multiply(arm_matrix, quaternion2matrix(quat))) # Probably not optimal + + self.head = head + self.tail = tail + + self.cal3d_parent = cal3d_parent + self.name = blend_bone.name + self.loc = loc + self.quat = quat + self.children = [] + + self.matrix = matrix_translate(quaternion2matrix(quat), loc) + if cal3d_parent: + self.matrix = matrix_multiply(cal3d_parent.matrix, self.matrix) + + # lloc and lquat are the bone => model space transformation (translation and rotation). + # They are probably specific to Cal3D. + m = matrix_invert(self.matrix) + self.lloc = m[3][0], m[3][1], m[3][2] + self.lquat = matrix2quaternion(m) + + self.id = len(skeleton.bones) + skeleton.bones.append(self) + BONES[self.name] = self + + if not blend_bone.hasChildren(): return + for blend_child in blend_bone.children: + self.children.append(Cal3DBone(skeleton, blend_child, arm_matrix, self)) + + + def writeCal3D(self, file): + file.write('\t\n' % \ + (self.id, self.name, len(self.children))) + # We need to negate quaternion W value, but why ? + file.write('\t\t%.6f %.6f %.6f\n' % \ + (self.loc[0], self.loc[1], self.loc[2])) + file.write('\t\t%.6f %.6f %.6f %.6f\n' % \ + (self.quat[0], self.quat[1], self.quat[2], -self.quat[3])) + file.write('\t\t%.6f %.6f %.6f\n' % \ + (self.lloc[0], self.lloc[1], self.lloc[2])) + file.write('\t\t%.6f %.6f %.6f %.6f\n' % \ + (self.lquat[0], self.lquat[1], self.lquat[2], -self.lquat[3])) + if self.cal3d_parent: + file.write('\t\t%i\n' % self.cal3d_parent.id) + else: + file.write('\t\t%i\n' % -1) + + for item in self.children: + file.write('\t\t%i\n' % item.id) + + file.write('\t\n') + +class Cal3DAnimation: + def __init__(self, name, duration = 0.0): + self.name = name + self.duration = duration + self.tracks = {} # Map bone names to tracks + + def writeCal3D(self, file): + file.write('\n') + file.write('
\n' % CAL3D_VERSION) + file.write('\n' % \ + (self.duration, len(self.tracks))) + + for item in self.tracks.itervalues(): + item.writeCal3D(file) + + file.write('\n') + +class Cal3DTrack(object): + __slots__ = 'bone', 'keyframes' + def __init__(self, bone): + self.bone = bone + self.keyframes = [] + + def writeCal3D(self, file): + file.write('\t\n' % + (self.bone.id, len(self.keyframes))) + for item in self.keyframes: + item.writeCal3D(file) + file.write('\t\n') + +class Cal3DKeyFrame(object): + __slots__ = 'time', 'loc', 'quat' + def __init__(self, time, loc, quat): + self.time = time + self.loc = loc + self.quat = quat + + def writeCal3D(self, file): + file.write('\t\t\n' % self.time) + file.write('\t\t\t%.6f %.6f %.6f\n' % \ + (self.loc[0], self.loc[1], self.loc[2])) + # We need to negate quaternion W value, but why ? + file.write('\t\t\t%.6f %.6f %.6f %.6f\n' % \ + (self.quat[0], self.quat[1], self.quat[2], -self.quat[3])) + file.write('\t\t\n') + +def export_cal3d(filename, PREF_SCALE=0.1, PREF_BAKE_MOTION = True, PREF_ACT_ACTION_ONLY=True, PREF_SCENE_FRAMES=False): + if not filename.endswith('.cfg'): + filename += '.cfg' + + file_only = filename.split('/')[-1].split('\\')[-1] + file_only_noext = file_only.split('.')[0] + base_only = filename[:-len(file_only)] + + def new_name(dataname, ext): + return file_only_noext + '_' + BPySys.cleanName(dataname) + ext + + #if EXPORT_FOR_SOYA: + # global BASE_MATRIX + # BASE_MATRIX = matrix_rotate_x(-math.pi / 2.0) + # Get the sce + + sce = bpy.data.scenes.active + blend_world = sce.world + # ---- Export skeleton (armature) ---------------------------------------- + + skeleton = Cal3DSkeleton() + blender_armature = [ob for ob in sce.objects.context if ob.type == 'Armature'] + if len(blender_armature) > 1: print "Found multiple armatures! using ",armatures[0].name + if blender_armature: blender_armature = blender_armature[0] + else: + # Try find a meshes armature + for ob in sce.objects.context: + blender_armature = BPyObject.getObjectArmature(ob) + if blender_armature: + break + + if not blender_armature: + Blender.Draw.PupMenu('Aborting%t|No Armature in selection') + return + + # we need pose bone locations + for pbone in blender_armature.getPose().bones.values(): + POSEBONES[pbone.name] = pbone + + Cal3DBone(skeleton, best_armature_root(blender_armature.getData()), blender_armature.matrixWorld) + + # ---- Export Mesh data --------------------------------------------------- + meshes = [] + for ob in sce.objects.context: + if ob.type != 'Mesh': continue + blend_mesh = ob.getData(mesh=1) + + if not blend_mesh.faces: continue + meshes.append( Cal3DMesh(ob, blend_mesh, blend_world) ) + + # ---- Export animations -------------------------------------------------- + backup_action = blender_armature.action + + ANIMATIONS = [] + SUPPORTED_IPOS = 'QuatW', 'QuatX', 'QuatY', 'QuatZ', 'LocX', 'LocY', 'LocZ' + + if PREF_ACT_ACTION_ONLY: action_items = [(blender_armature.action.name, blender_armature.action)] + else: action_items = Blender.Armature.NLA.GetActions().items() + + print len(action_items), 'action_items' + + for animation_name, blend_action in action_items: + + # get frame range + if PREF_SCENE_FRAMES: + action_start= Blender.Get('staframe') + action_end= Blender.Get('endframe') + else: + _frames = blend_action.getFrameNumbers() + action_start= min(_frames); + action_end= max(_frames); + del _frames + + blender_armature.action = blend_action + + if PREF_BAKE_MOTION: + # We need to set the action active if we are getting baked data + pose_data = BPyArmature.getBakedPoseData(blender_armature, action_start, action_end) + + # Fake, all we need is bone names + blend_action_ipos_items = [(pbone, True) for pbone in POSEBONES.iterkeys()] + else: + # real (bone_name, ipo) pairs + blend_action_ipos_items = blend_action.getAllChannelIpos().items() + + # Now we mau have some bones with no channels, easiest to add their names and an empty list here + # this way they are exported with dummy keyfraames at teh first used frame + action_bone_names = [name for name, ipo in blend_action_ipos_items] + for bone_name in BONES: # iterkeys + if bone_name not in action_bone_names: + blend_action_ipos_items.append( (bone_name, []) ) + + animation = Cal3DAnimation(animation_name) + # ---------------------------- + ANIMATIONS.append(animation) + animation.duration = 0.0 + + for bone_name, ipo in blend_action_ipos_items: + # Baked bones may have no IPO's width motion still + if bone_name not in BONES: + print '\tNo Bone "' + bone_name + '" in (from Animation "' + animation_name + '") ?!?' + continue + + # So we can loop without errors + if ipo==None: ipo = [] + + bone = BONES[bone_name] + track = animation.tracks[bone_name] = Cal3DTrack(bone) + + if PREF_BAKE_MOTION: + for i in xrange(action_end - action_start): + cal3dtime = i / 25.0 # assume 25FPS by default + + if cal3dtime > animation.duration: + animation.duration = cal3dtime + + #print pose_data[i][bone_name], i + loc, quat = pose_data[i][bone_name] + + loc = vector_by_matrix_3x3(loc, bone.matrix) + loc = vector_add(bone.loc, loc) + quat = quaternion_multiply(quat, bone.quat) + quat = Quaternion(quat) + + quat.normalize() + quat = tuple(quat) + + track.keyframes.append( Cal3DKeyFrame(cal3dtime, loc, quat) ) + + else: + #run 1: we need to find all time values where we need to produce keyframes + times = set() + for curve in ipo: + curve_name = curve.name + if curve_name in SUPPORTED_IPOS: + for p in curve.bezierPoints: + times.add( p.pt[0] ) + + times = list(times) + times.sort() + + # Incase we have no keys here or ipo==None + if not times: times.append(action_start) + + # run2: now create keyframes + for time in times: + cal3dtime = (time-1) / 25.0 # assume 25FPS by default + if cal3dtime > animation.duration: + animation.duration = cal3dtime + + trans = Vector() + quat = Quaternion() + + for curve in ipo: + val = curve.evaluate(time) + # val = 0.0 + curve_name= curve.name + if curve_name == 'LocX': trans[0] = val + elif curve_name == 'LocY': trans[1] = val + elif curve_name == 'LocZ': trans[2] = val + elif curve_name == 'QuatW': quat[3] = val + elif curve_name == 'QuatX': quat[0] = val + elif curve_name == 'QuatY': quat[1] = val + elif curve_name == 'QuatZ': quat[2] = val + + transt = vector_by_matrix_3x3(trans, bone.matrix) + loc = vector_add(bone.loc, transt) + quat = quaternion_multiply(quat, bone.quat) + quat = Quaternion(quat) + + quat.normalize() + quat = tuple(quat) + + track.keyframes.append( Cal3DKeyFrame(cal3dtime, loc, quat) ) + + + if animation.duration <= 0: + print 'Ignoring Animation "' + animation_name + '": duration is 0.\n' + continue + + # Restore the original armature + blender_armature.action = backup_action + # ------------------------------------- End Animation + + + + cfg = open((filename), 'wb') + cfg.write('# Cal3D model exported from Blender with export_cal3d.py\n# from %s\n' % Blender.Get('filename')) + + if PREF_SCALE != 1.0: cfg.write('scale=%.6f\n' % PREF_SCALE) + + fname = file_only_noext + '.xsf' + file = open( base_only + fname, 'wb') + skeleton.writeCal3D(file) + file.close() + + cfg.write('skeleton=%s\n' % fname) + + for animation in ANIMATIONS: + if not animation.name.startswith('_'): + if animation.duration > 0.1: # Cal3D does not support animation with only one state + fname = new_name(animation.name, '.xaf') + file = open(base_only + fname, 'wb') + animation.writeCal3D(file) + file.close() + cfg.write('animation=%s\n' % fname) + + for mesh in meshes: + if not mesh.name.startswith('_'): + fname = new_name(mesh.name, '.xmf') + file = open(base_only + fname, 'wb') + mesh.writeCal3D(file) + file.close() + + cfg.write('mesh=%s\n' % fname) + + materials = MATERIALS.values() + materials.sort(key = lambda a: a.id) + for material in materials: + # Just number materials, its less trouble + fname = new_name(str(material.id), '.xrf') + + file = open(base_only + fname, 'wb') + material.writeCal3D(file) + file.close() + + cfg.write('material=%s\n' % fname) + + print 'Cal3D Saved to "%s.cfg"' % file_only_noext + + # Warnings + if len(animation.tracks) < 2: + Blender.Draw.PupMenu('Warning, the armature has less then 2 tracks, file may not load in Cal3d') + + +def export_cal3d_ui(filename): + + PREF_SCALE= Blender.Draw.Create(1.0) + PREF_BAKE_MOTION = Blender.Draw.Create(1) + PREF_ACT_ACTION_ONLY= Blender.Draw.Create(1) + PREF_SCENE_FRAMES= Blender.Draw.Create(0) + + block = [\ + ('Scale: ', PREF_SCALE, 0.01, 100, 'The scale to set in the Cal3d .cfg file (unsupported by soya)'),\ + ('Baked Motion', PREF_BAKE_MOTION, 'use final pose position instead of ipo keyframes (IK and constraint support)'),\ + ('Active Action', PREF_ACT_ACTION_ONLY, 'Only export action applied to this armature, else export all actions.'),\ + ('Scene Frames', PREF_SCENE_FRAMES, 'Use scene frame range, else the actions start/end'),\ + ] + + if not Blender.Draw.PupBlock('Cal3D Options', block): + return + + Blender.Window.WaitCursor(1) + export_cal3d(filename, 1.0/PREF_SCALE.val, PREF_BAKE_MOTION.val, PREF_ACT_ACTION_ONLY.val, PREF_SCENE_FRAMES.val) + Blender.Window.WaitCursor(0) + + +#import os +if __name__ == '__main__': + Blender.Window.FileSelector(export_cal3d_ui, 'Cal3D Export', Blender.Get('filename').replace('.blend', '.cfg')) + #export_cal3d('/cally/data/skeleton/skeleton' + '.cfg', 1.0, True, False, False) + #export_cal3d('/test' + '.cfg') + #export_cal3d_ui('/test' + '.cfg') + #os.system('cd /; wine /cal3d_miniviewer.exe /skeleton.cfg') + #os.system('cd /cally/;wine cally') diff --git a/release/scripts/export_fbx.py b/release/scripts/export_fbx.py new file mode 100644 index 00000000000..99d036b38bc --- /dev/null +++ b/release/scripts/export_fbx.py @@ -0,0 +1,2976 @@ +#!BPY +""" +Name: 'Autodesk FBX (.fbx)...' +Blender: 244 +Group: 'Export' +Tooltip: 'Selection to an ASCII Autodesk FBX ' +""" +__author__ = "Campbell Barton" +__url__ = ['www.blender.org', 'blenderartists.org'] +__version__ = "1.1" + +__bpydoc__ = """\ +This script is an exporter to the FBX file format. + +http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_fbx +""" +# -------------------------------------------------------------------------- +# FBX Export v0.1 by Campbell Barton (AKA Ideasman) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +try: + import time + # import os # only needed for batch export, nbot used yet +except: + time = None # use this to check if they have python modules installed + +# for python 2.3 support +try: + set() +except: + try: + from sets import Set as set + except: + set = None # so it complains you dont have a ! + +# os is only needed for batch 'own dir' option +try: + import os +except: + os = None + +import Blender +import bpy +from Blender.Mathutils import Matrix, Vector, RotationMatrix + +import BPyObject +import BPyMesh +import BPySys +import BPyMessages + +import sys + +## This was used to make V, but faster not to do all that +##valid = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_,.()[]{}' +##v = range(255) +##for c in valid: v.remove(ord(c)) +v = [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,42,43,47,58,59,60,61,62,63,64,92,94,96,124,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] +invalid = ''.join([chr(i) for i in v]) +def cleanName(name): + for ch in invalid: name = name.replace(ch, '_') + return name +del v, i + + +def copy_file(source, dest): + file = open(source, 'rb') + data = file.read() + file.close() + + file = open(dest, 'wb') + file.write(data) + file.close() + + +def copy_images(dest_dir, textures): + if not dest_dir.endswith(Blender.sys.sep): + dest_dir += Blender.sys.sep + + image_paths = set() + for img in textures: + image_paths.add(Blender.sys.expandpath(img.filename)) + + # Now copy images + copyCount = 0 + for image_path in image_paths: + if Blender.sys.exists(image_path): + # Make a name for the target path. + dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1] + if not Blender.sys.exists(dest_image_path): # Image isnt alredy there + print '\tCopying "%s" > "%s"' % (image_path, dest_image_path) + try: + copy_file(image_path, dest_image_path) + copyCount+=1 + except: + print '\t\tWarning, file failed to copy, skipping.' + + print '\tCopied %d images' % copyCount + +mtx4_identity = Matrix() + +# testing +mtx_x90 = RotationMatrix( 90, 3, 'x') # used +#mtx_x90n = RotationMatrix(-90, 3, 'x') +#mtx_y90 = RotationMatrix( 90, 3, 'y') +#mtx_y90n = RotationMatrix(-90, 3, 'y') +#mtx_z90 = RotationMatrix( 90, 3, 'z') +#mtx_z90n = RotationMatrix(-90, 3, 'z') + +#mtx4_x90 = RotationMatrix( 90, 4, 'x') +mtx4_x90n = RotationMatrix(-90, 4, 'x') # used +#mtx4_y90 = RotationMatrix( 90, 4, 'y') +mtx4_y90n = RotationMatrix(-90, 4, 'y') # used +mtx4_z90 = RotationMatrix( 90, 4, 'z') # used +mtx4_z90n = RotationMatrix(-90, 4, 'z') # used + +def strip_path(p): + return p.split('\\')[-1].split('/')[-1] + +# Used to add the scene name into the filename without using odd chars +sane_name_mapping_ob = {} +sane_name_mapping_mat = {} +sane_name_mapping_tex = {} +sane_name_mapping_take = {} +sane_name_mapping_group = {} + +# Make sure reserved names are not used +sane_name_mapping_ob['Scene'] = 'Scene_' +sane_name_mapping_ob['blend_root'] = 'blend_root_' + +def increment_string(t): + name = t + num = '' + while name and name[-1].isdigit(): + num = name[-1] + num + name = name[:-1] + if num: return '%s%d' % (name, int(num)+1) + else: return name + '_0' + + + +# todo - Disallow the name 'Scene' and 'blend_root' - it will bugger things up. +def sane_name(data, dct): + #if not data: return None + name = data.name + + # dont cache, only ever call once for each data type now, + # so as to avoid namespace collision between types - like with objects <-> bones + #try: return dct[name] + #except: pass + + orig_name = name + if not name: + name = 'unnamed' # blank string, ASKING FOR TROUBLE! + else: + #name = BPySys.cleanName(name) + name = cleanName(name) # use our own + + while name in dct.itervalues(): name = increment_string(name) + + dct[orig_name] = name + return name + +def sane_obname(data): return sane_name(data, sane_name_mapping_ob) +def sane_matname(data): return sane_name(data, sane_name_mapping_mat) +def sane_texname(data): return sane_name(data, sane_name_mapping_tex) +def sane_takename(data): return sane_name(data, sane_name_mapping_take) +def sane_groupname(data): return sane_name(data, sane_name_mapping_group) + + + + +def mat4x4str(mat): + return '%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f' % tuple([ f for v in mat for f in v ]) + +def meshNormalizedWeights(me): + try: # account for old bad BPyMesh + groupNames, vWeightList = BPyMesh.meshWeight2List(me) + except: + return [],[] + + if not groupNames: + return [],[] + + for i, vWeights in enumerate(vWeightList): + tot = 0.0 + for w in vWeights: + tot+=w + + if tot: + for j, w in enumerate(vWeights): + vWeights[j] = w/tot + + return groupNames, vWeightList + +header_comment = \ +'''; FBX 6.1.0 project file +; Created by Blender FBX Exporter +; for support mail: ideasman42@gmail.com +; ---------------------------------------------------- + +''' + +# This func can be called with just the filename +def write(filename, batch_objects = None, \ + EXP_OBS_SELECTED = True, + EXP_MESH = True, + EXP_MESH_APPLY_MOD = True, + EXP_MESH_HQ_NORMALS = False, + EXP_ARMATURE = True, + EXP_LAMP = True, + EXP_CAMERA = True, + EXP_EMPTY = True, + EXP_IMAGE_COPY = False, + GLOBAL_MATRIX = Matrix(), + ANIM_ENABLE = True, + ANIM_OPTIMIZE = True, + ANIM_OPTIMIZE_PRECISSION = 6, + ANIM_ACTION_ALL = False, + BATCH_ENABLE = False, + BATCH_GROUP = True, + BATCH_SCENE = False, + BATCH_FILE_PREFIX = '', + BATCH_OWN_DIR = False + ): + + # ----------------- Batch support! + if BATCH_ENABLE: + if os == None: BATCH_OWN_DIR = False + + fbxpath = filename + + # get the path component of filename + tmp_exists = Blender.sys.exists(fbxpath) + + if tmp_exists != 2: # a file, we want a path + while fbxpath and fbxpath[-1] not in ('/', '\\'): + fbxpath = fbxpath[:-1] + if not filename: + Draw.PupMenu('Error%t|Directory does not exist!') + return + + tmp_exists = Blender.sys.exists(fbxpath) + + if tmp_exists != 2: + Draw.PupMenu('Error%t|Directory does not exist!') + return + + if not fbxpath.endswith(Blender.sys.sep): + fbxpath += Blender.sys.sep + del tmp_exists + + + if BATCH_GROUP: + data_seq = bpy.data.groups + else: + data_seq = bpy.data.scenes + + # call this function within a loop with BATCH_ENABLE == False + orig_sce = bpy.data.scenes.active + + + new_fbxpath = fbxpath # own dir option modifies, we need to keep an original + for data in data_seq: # scene or group + newname = BATCH_FILE_PREFIX + BPySys.cleanName(data.name) + + + if BATCH_OWN_DIR: + new_fbxpath = fbxpath + newname + Blender.sys.sep + # path may alredy exist + # TODO - might exist but be a file. unlikely but should probably account for it. + + if Blender.sys.exists(new_fbxpath) == 0: + os.mkdir(new_fbxpath) + + + filename = new_fbxpath + newname + '.fbx' + + print '\nBatch exporting %s as...\n\t"%s"' % (data, filename) + + if BATCH_GROUP: #group + # group, so objects update properly, add a dummy scene. + sce = bpy.data.scenes.new() + sce.Layers = (1<<20) -1 + bpy.data.scenes.active = sce + for ob_base in data.objects: + sce.objects.link(ob_base) + + sce.update(1) + + # TODO - BUMMER! Armatures not in the group wont animate the mesh + + else:# scene + + + data_seq.active = data + + + # Call self with modified args + # Dont pass batch options since we alredy usedt them + write(filename, data.objects, + False, + EXP_MESH, + EXP_MESH_APPLY_MOD, + EXP_MESH_HQ_NORMALS, + EXP_ARMATURE, + EXP_LAMP, + EXP_CAMERA, + EXP_EMPTY, + EXP_IMAGE_COPY, + GLOBAL_MATRIX, + ANIM_ENABLE, + ANIM_OPTIMIZE, + ANIM_OPTIMIZE_PRECISSION, + ANIM_ACTION_ALL + ) + + if BATCH_GROUP: + # remove temp group scene + bpy.data.scenes.unlink(sce) + + bpy.data.scenes.active = orig_sce + + return # so the script wont run after we have batch exported. + + # end batch support + + + # ---------------------------------------------- + # storage classes + class my_bone_class: + __slots__ =(\ + 'blenName',\ + 'blenBone',\ + 'blenMeshes',\ + 'restMatrix',\ + 'parent',\ + 'blenName',\ + 'fbxName',\ + 'fbxArm',\ + '__pose_bone',\ + '__anim_poselist') + + def __init__(self, blenBone, fbxArm): + + # This is so 2 armatures dont have naming conflicts since FBX bones use object namespace + self.fbxName = sane_obname(blenBone) + + self.blenName = blenBone.name + self.blenBone = blenBone + self.blenMeshes = {} # fbxMeshObName : mesh + self.fbxArm = fbxArm + self.restMatrix = blenBone.matrix['ARMATURESPACE'] + + # not used yet + # self.restMatrixInv = self.restMatrix.copy().invert() + # self.restMatrixLocal = None # set later, need parent matrix + + self.parent = None + + # not public + pose = fbxArm.blenObject.getPose() + self.__pose_bone = pose.bones[self.blenName] + + # store a list if matricies here, (poseMatrix, head, tail) + # {frame:posematrix, frame:posematrix, ...} + self.__anim_poselist = {} + + ''' + def calcRestMatrixLocal(self): + if self.parent: + self.restMatrixLocal = self.restMatrix * self.parent.restMatrix.copy().invert() + else: + self.restMatrixLocal = self.restMatrix.copy() + ''' + def setPoseFrame(self, f): + # cache pose info here, frame must be set beforehand + + # Didnt end up needing head or tail, if we do - here it is. + ''' + self.__anim_poselist[f] = (\ + self.__pose_bone.poseMatrix.copy(),\ + self.__pose_bone.head.copy(),\ + self.__pose_bone.tail.copy() ) + ''' + + self.__anim_poselist[f] = self.__pose_bone.poseMatrix.copy() + + # get pose from frame. + def getPoseMatrix(self, f):# ---------------------------------------------- + return self.__anim_poselist[f] + ''' + def getPoseHead(self, f): + #return self.__pose_bone.head.copy() + return self.__anim_poselist[f][1].copy() + def getPoseTail(self, f): + #return self.__pose_bone.tail.copy() + return self.__anim_poselist[f][2].copy() + ''' + # end + + def getAnimParRelMatrix(self, frame): + #arm_mat = self.fbxArm.matrixWorld + #arm_mat = self.fbxArm.parRelMatrix() + if not self.parent: + #return mtx4_z90 * (self.getPoseMatrix(frame) * arm_mat) # dont apply arm matrix anymore + return mtx4_z90 * self.getPoseMatrix(frame) + else: + #return (mtx4_z90 * ((self.getPoseMatrix(frame) * arm_mat))) * (mtx4_z90 * (self.parent.getPoseMatrix(frame) * arm_mat)).invert() + return (mtx4_z90 * (self.getPoseMatrix(frame))) * (mtx4_z90 * self.parent.getPoseMatrix(frame)).invert() + + # we need thes because cameras and lights modified rotations + def getAnimParRelMatrixRot(self, frame): + return self.getAnimParRelMatrix(frame) + + def flushAnimData(self): + self.__anim_poselist.clear() + + + class my_object_generic: + # Other settings can be applied for each type - mesh, armature etc. + def __init__(self, ob, matrixWorld = None): + self.fbxName = sane_obname(ob) + self.blenObject = ob + self.fbxGroupNames = [] + self.fbxParent = None # set later on IF the parent is in the selection. + if matrixWorld: self.matrixWorld = matrixWorld * GLOBAL_MATRIX + else: self.matrixWorld = ob.matrixWorld * GLOBAL_MATRIX + self.__anim_poselist = {} # we should only access this + + def parRelMatrix(self): + if self.fbxParent: + return self.matrixWorld * self.fbxParent.matrixWorld.copy().invert() + else: + return self.matrixWorld + + def setPoseFrame(self, f): + self.__anim_poselist[f] = self.blenObject.matrixWorld.copy() + + def getAnimParRelMatrix(self, frame): + if self.fbxParent: + #return (self.__anim_poselist[frame] * self.fbxParent.__anim_poselist[frame].copy().invert() ) * GLOBAL_MATRIX + return (self.__anim_poselist[frame] * GLOBAL_MATRIX) * (self.fbxParent.__anim_poselist[frame] * GLOBAL_MATRIX).invert() + else: + return self.__anim_poselist[frame] * GLOBAL_MATRIX + + def getAnimParRelMatrixRot(self, frame): + type = self.blenObject.type + if self.fbxParent: + matrix_rot = (((self.__anim_poselist[frame] * GLOBAL_MATRIX) * (self.fbxParent.__anim_poselist[frame] * GLOBAL_MATRIX).invert())).rotationPart() + else: + matrix_rot = (self.__anim_poselist[frame] * GLOBAL_MATRIX).rotationPart() + + # Lamps need to be rotated + if type =='Lamp': + matrix_rot = mtx_x90 * matrix_rot + elif ob and type =='Camera': + y = Vector(0,1,0) * matrix_rot + matrix_rot = matrix_rot * RotationMatrix(90, 3, 'r', y) + + return matrix_rot + + # ---------------------------------------------- + + + + + + print '\nFBX export starting...', filename + start_time = Blender.sys.time() + try: + file = open(filename, 'w') + except: + return False + + sce = bpy.data.scenes.active + world = sce.world + + + # ---------------------------- Write the header first + file.write(header_comment) + if time: + curtime = time.localtime()[0:6] + else: + curtime = [0,0,0,0,0,0] + # + file.write(\ +'''FBXHeaderExtension: { + FBXHeaderVersion: 1003 + FBXVersion: 6100 + CreationTimeStamp: { + Version: 1000 + Year: %.4i + Month: %.2i + Day: %.2i + Hour: %.2i + Minute: %.2i + Second: %.2i + Millisecond: 0 + } + Creator: "FBX SDK/FBX Plugins build 20070228" + OtherFlags: { + FlagPLE: 0 + } +}''' % (curtime)) + + file.write('\nCreationTime: "%.4i-%.2i-%.2i %.2i:%.2i:%.2i:000"' % curtime) + file.write('\nCreator: "Blender3D version %.2f"' % Blender.Get('version')) + + pose_items = [] # list of (fbxName, matrix) to write pose data for, easier to collect allong the way + + # --------------- funcs for exporting + def object_tx(ob, loc, matrix, matrix_mod = None): + ''' + Matrix mod is so armature objects can modify their bone matricies + ''' + if isinstance(ob, Blender.Types.BoneType): + + # we know we have a matrix + # matrix = mtx4_z90 * (ob.matrix['ARMATURESPACE'] * matrix_mod) + matrix = mtx4_z90 * ob.matrix['ARMATURESPACE'] # dont apply armature matrix anymore + + parent = ob.parent + if parent: + #par_matrix = mtx4_z90 * (parent.matrix['ARMATURESPACE'] * matrix_mod) + par_matrix = mtx4_z90 * parent.matrix['ARMATURESPACE'] # dont apply armature matrix anymore + matrix = matrix * par_matrix.copy().invert() + + matrix_rot = matrix.rotationPart() + + loc = tuple(matrix.translationPart()) + scale = tuple(matrix.scalePart()) + rot = tuple(matrix_rot.toEuler()) + + else: + # This is bad because we need the parent relative matrix from the fbx parent (if we have one), dont use anymore + #if ob and not matrix: matrix = ob.matrixWorld * GLOBAL_MATRIX + if ob and not matrix: raise "error: this should never happen!" + + matrix_rot = matrix + #if matrix: + # matrix = matrix_scale * matrix + + if matrix: + loc = tuple(matrix.translationPart()) + scale = tuple(matrix.scalePart()) + + matrix_rot = matrix.rotationPart() + # Lamps need to be rotated + if ob and ob.type =='Lamp': + matrix_rot = mtx_x90 * matrix_rot + rot = tuple(matrix_rot.toEuler()) + elif ob and ob.type =='Camera': + y = Vector(0,1,0) * matrix_rot + matrix_rot = matrix_rot * RotationMatrix(90, 3, 'r', y) + rot = tuple(matrix_rot.toEuler()) + else: + rot = tuple(matrix_rot.toEuler()) + else: + if not loc: + loc = 0,0,0 + scale = 1,1,1 + rot = 0,0,0 + + return loc, rot, scale, matrix, matrix_rot + + def write_object_tx(ob, loc, matrix, matrix_mod= None): + ''' + We have loc to set the location if non blender objects that have a location + + matrix_mod is only used for bones at the moment + ''' + loc, rot, scale, matrix, matrix_rot = object_tx(ob, loc, matrix, matrix_mod) + + file.write('\n\t\t\tProperty: "Lcl Translation", "Lcl Translation", "A+",%.15f,%.15f,%.15f' % loc) + file.write('\n\t\t\tProperty: "Lcl Rotation", "Lcl Rotation", "A+",%.15f,%.15f,%.15f' % rot) + file.write('\n\t\t\tProperty: "Lcl Scaling", "Lcl Scaling", "A+",%.15f,%.15f,%.15f' % scale) + return loc, rot, scale, matrix, matrix_rot + + def write_object_props(ob=None, loc=None, matrix=None, matrix_mod=None): + # if the type is 0 its an empty otherwise its a mesh + # only difference at the moment is one has a color + file.write(''' + Properties60: { + Property: "QuaternionInterpolate", "bool", "",0 + Property: "Visibility", "Visibility", "A+",1''') + + loc, rot, scale, matrix, matrix_rot = write_object_tx(ob, loc, matrix, matrix_mod) + + # Rotation order, note, for FBX files Iv loaded normal order is 1 + # setting to zero. + # eEULER_XYZ = 0 + # eEULER_XZY + # eEULER_YZX + # eEULER_YXZ + # eEULER_ZXY + # eEULER_ZYX + + file.write(''' + Property: "RotationOffset", "Vector3D", "",0,0,0 + Property: "RotationPivot", "Vector3D", "",0,0,0 + Property: "ScalingOffset", "Vector3D", "",0,0,0 + Property: "ScalingPivot", "Vector3D", "",0,0,0 + Property: "TranslationActive", "bool", "",0 + Property: "TranslationMin", "Vector3D", "",0,0,0 + Property: "TranslationMax", "Vector3D", "",0,0,0 + Property: "TranslationMinX", "bool", "",0 + Property: "TranslationMinY", "bool", "",0 + Property: "TranslationMinZ", "bool", "",0 + Property: "TranslationMaxX", "bool", "",0 + Property: "TranslationMaxY", "bool", "",0 + Property: "TranslationMaxZ", "bool", "",0 + Property: "RotationOrder", "enum", "",0 + Property: "RotationSpaceForLimitOnly", "bool", "",0 + Property: "AxisLen", "double", "",10 + Property: "PreRotation", "Vector3D", "",0,0,0 + Property: "PostRotation", "Vector3D", "",0,0,0 + Property: "RotationActive", "bool", "",0 + Property: "RotationMin", "Vector3D", "",0,0,0 + Property: "RotationMax", "Vector3D", "",0,0,0 + Property: "RotationMinX", "bool", "",0 + Property: "RotationMinY", "bool", "",0 + Property: "RotationMinZ", "bool", "",0 + Property: "RotationMaxX", "bool", "",0 + Property: "RotationMaxY", "bool", "",0 + Property: "RotationMaxZ", "bool", "",0 + Property: "RotationStiffnessX", "double", "",0 + Property: "RotationStiffnessY", "double", "",0 + Property: "RotationStiffnessZ", "double", "",0 + Property: "MinDampRangeX", "double", "",0 + Property: "MinDampRangeY", "double", "",0 + Property: "MinDampRangeZ", "double", "",0 + Property: "MaxDampRangeX", "double", "",0 + Property: "MaxDampRangeY", "double", "",0 + Property: "MaxDampRangeZ", "double", "",0 + Property: "MinDampStrengthX", "double", "",0 + Property: "MinDampStrengthY", "double", "",0 + Property: "MinDampStrengthZ", "double", "",0 + Property: "MaxDampStrengthX", "double", "",0 + Property: "MaxDampStrengthY", "double", "",0 + Property: "MaxDampStrengthZ", "double", "",0 + Property: "PreferedAngleX", "double", "",0 + Property: "PreferedAngleY", "double", "",0 + Property: "PreferedAngleZ", "double", "",0 + Property: "InheritType", "enum", "",0 + Property: "ScalingActive", "bool", "",0 + Property: "ScalingMin", "Vector3D", "",1,1,1 + Property: "ScalingMax", "Vector3D", "",1,1,1 + Property: "ScalingMinX", "bool", "",0 + Property: "ScalingMinY", "bool", "",0 + Property: "ScalingMinZ", "bool", "",0 + Property: "ScalingMaxX", "bool", "",0 + Property: "ScalingMaxY", "bool", "",0 + Property: "ScalingMaxZ", "bool", "",0 + Property: "GeometricTranslation", "Vector3D", "",0,0,0 + Property: "GeometricRotation", "Vector3D", "",0,0,0 + Property: "GeometricScaling", "Vector3D", "",1,1,1 + Property: "LookAtProperty", "object", "" + Property: "UpVectorProperty", "object", "" + Property: "Show", "bool", "",1 + Property: "NegativePercentShapeSupport", "bool", "",1 + Property: "DefaultAttributeIndex", "int", "",0''') + if ob and type(ob) != Blender.Types.BoneType: + # Only mesh objects have color + file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8') + file.write('\n\t\t\tProperty: "Size", "double", "",100') + file.write('\n\t\t\tProperty: "Look", "enum", "",1') + + return loc, rot, scale, matrix, matrix_rot + + + # -------------------------------------------- Armatures + #def write_bone(bone, name, matrix_mod): + def write_bone(my_bone): + file.write('\n\tModel: "Model::%s", "Limb" {' % my_bone.fbxName) + file.write('\n\t\tVersion: 232') + + #poseMatrix = write_object_props(my_bone.blenBone, None, None, my_bone.fbxArm.parRelMatrix())[3] + poseMatrix = write_object_props(my_bone.blenBone)[3] # dont apply bone matricies anymore + pose_items.append( (my_bone.fbxName, poseMatrix) ) + + + # file.write('\n\t\t\tProperty: "Size", "double", "",%.6f' % ((my_bone.blenData.head['ARMATURESPACE'] - my_bone.blenData.tail['ARMATURESPACE']) * my_bone.fbxArm.parRelMatrix()).length) + file.write('\n\t\t\tProperty: "Size", "double", "",1') + + #((my_bone.blenData.head['ARMATURESPACE'] * my_bone.fbxArm.matrixWorld) - (my_bone.blenData.tail['ARMATURESPACE'] * my_bone.fbxArm.parRelMatrix())).length) + + """ + file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' %\ + ((my_bone.blenBone.head['ARMATURESPACE'] - my_bone.blenBone.tail['ARMATURESPACE']) * my_bone.fbxArm.parRelMatrix()).length) + """ + + file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' %\ + (my_bone.blenBone.head['ARMATURESPACE'] - my_bone.blenBone.tail['ARMATURESPACE']).length) + + #file.write('\n\t\t\tProperty: "LimbLength", "double", "",1') + file.write('\n\t\t\tProperty: "Color", "ColorRGB", "",0.8,0.8,0.8') + file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8') + file.write('\n\t\t}') + file.write('\n\t\tMultiLayer: 0') + file.write('\n\t\tMultiTake: 1') + file.write('\n\t\tShading: Y') + file.write('\n\t\tCulling: "CullingOff"') + file.write('\n\t\tTypeFlags: "Skeleton"') + file.write('\n\t}') + + def write_camera_switch(): + file.write(''' + Model: "Model::Camera Switcher", "CameraSwitcher" { + Version: 232''') + + write_object_props() + file.write(''' + Property: "Color", "Color", "A",0.8,0.8,0.8 + Property: "Camera Index", "Integer", "A+",100 + } + MultiLayer: 0 + MultiTake: 1 + Hidden: "True" + Shading: W + Culling: "CullingOff" + Version: 101 + Name: "Model::Camera Switcher" + CameraId: 0 + CameraName: 100 + CameraIndexName: + }''') + + def write_camera_dummy(name, loc, near, far, proj_type, up): + file.write('\n\tModel: "Model::%s", "Camera" {' % name ) + file.write('\n\t\tVersion: 232') + write_object_props(None, loc) + + file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8') + file.write('\n\t\t\tProperty: "Roll", "Roll", "A+",0') + file.write('\n\t\t\tProperty: "FieldOfView", "FieldOfView", "A+",40') + file.write('\n\t\t\tProperty: "FieldOfViewX", "FieldOfView", "A+",1') + file.write('\n\t\t\tProperty: "FieldOfViewY", "FieldOfView", "A+",1') + file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",0') + file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",0') + file.write('\n\t\t\tProperty: "BackgroundColor", "Color", "A+",0.63,0.63,0.63') + file.write('\n\t\t\tProperty: "TurnTable", "Real", "A+",0') + file.write('\n\t\t\tProperty: "DisplayTurnTableIcon", "bool", "",1') + file.write('\n\t\t\tProperty: "Motion Blur Intensity", "Real", "A+",1') + file.write('\n\t\t\tProperty: "UseMotionBlur", "bool", "",0') + file.write('\n\t\t\tProperty: "UseRealTimeMotionBlur", "bool", "",1') + file.write('\n\t\t\tProperty: "ResolutionMode", "enum", "",0') + file.write('\n\t\t\tProperty: "ApertureMode", "enum", "",2') + file.write('\n\t\t\tProperty: "GateFit", "enum", "",0') + file.write('\n\t\t\tProperty: "FocalLength", "Real", "A+",21.3544940948486') + file.write('\n\t\t\tProperty: "CameraFormat", "enum", "",0') + file.write('\n\t\t\tProperty: "AspectW", "double", "",320') + file.write('\n\t\t\tProperty: "AspectH", "double", "",200') + file.write('\n\t\t\tProperty: "PixelAspectRatio", "double", "",1') + file.write('\n\t\t\tProperty: "UseFrameColor", "bool", "",0') + file.write('\n\t\t\tProperty: "FrameColor", "ColorRGB", "",0.3,0.3,0.3') + file.write('\n\t\t\tProperty: "ShowName", "bool", "",1') + file.write('\n\t\t\tProperty: "ShowGrid", "bool", "",1') + file.write('\n\t\t\tProperty: "ShowOpticalCenter", "bool", "",0') + file.write('\n\t\t\tProperty: "ShowAzimut", "bool", "",1') + file.write('\n\t\t\tProperty: "ShowTimeCode", "bool", "",0') + file.write('\n\t\t\tProperty: "NearPlane", "double", "",%.6f' % near) + file.write('\n\t\t\tProperty: "FarPlane", "double", "",%.6f' % far) + file.write('\n\t\t\tProperty: "FilmWidth", "double", "",0.816') + file.write('\n\t\t\tProperty: "FilmHeight", "double", "",0.612') + file.write('\n\t\t\tProperty: "FilmAspectRatio", "double", "",1.33333333333333') + file.write('\n\t\t\tProperty: "FilmSqueezeRatio", "double", "",1') + file.write('\n\t\t\tProperty: "FilmFormatIndex", "enum", "",4') + file.write('\n\t\t\tProperty: "ViewFrustum", "bool", "",1') + file.write('\n\t\t\tProperty: "ViewFrustumNearFarPlane", "bool", "",0') + file.write('\n\t\t\tProperty: "ViewFrustumBackPlaneMode", "enum", "",2') + file.write('\n\t\t\tProperty: "BackPlaneDistance", "double", "",100') + file.write('\n\t\t\tProperty: "BackPlaneDistanceMode", "enum", "",0') + file.write('\n\t\t\tProperty: "ViewCameraToLookAt", "bool", "",1') + file.write('\n\t\t\tProperty: "LockMode", "bool", "",0') + file.write('\n\t\t\tProperty: "LockInterestNavigation", "bool", "",0') + file.write('\n\t\t\tProperty: "FitImage", "bool", "",0') + file.write('\n\t\t\tProperty: "Crop", "bool", "",0') + file.write('\n\t\t\tProperty: "Center", "bool", "",1') + file.write('\n\t\t\tProperty: "KeepRatio", "bool", "",1') + file.write('\n\t\t\tProperty: "BackgroundMode", "enum", "",0') + file.write('\n\t\t\tProperty: "BackgroundAlphaTreshold", "double", "",0.5') + file.write('\n\t\t\tProperty: "ForegroundTransparent", "bool", "",1') + file.write('\n\t\t\tProperty: "DisplaySafeArea", "bool", "",0') + file.write('\n\t\t\tProperty: "SafeAreaDisplayStyle", "enum", "",1') + file.write('\n\t\t\tProperty: "SafeAreaAspectRatio", "double", "",1.33333333333333') + file.write('\n\t\t\tProperty: "Use2DMagnifierZoom", "bool", "",0') + file.write('\n\t\t\tProperty: "2D Magnifier Zoom", "Real", "A+",100') + file.write('\n\t\t\tProperty: "2D Magnifier X", "Real", "A+",50') + file.write('\n\t\t\tProperty: "2D Magnifier Y", "Real", "A+",50') + file.write('\n\t\t\tProperty: "CameraProjectionType", "enum", "",%i' % proj_type) + file.write('\n\t\t\tProperty: "UseRealTimeDOFAndAA", "bool", "",0') + file.write('\n\t\t\tProperty: "UseDepthOfField", "bool", "",0') + file.write('\n\t\t\tProperty: "FocusSource", "enum", "",0') + file.write('\n\t\t\tProperty: "FocusAngle", "double", "",3.5') + file.write('\n\t\t\tProperty: "FocusDistance", "double", "",200') + file.write('\n\t\t\tProperty: "UseAntialiasing", "bool", "",0') + file.write('\n\t\t\tProperty: "AntialiasingIntensity", "double", "",0.77777') + file.write('\n\t\t\tProperty: "UseAccumulationBuffer", "bool", "",0') + file.write('\n\t\t\tProperty: "FrameSamplingCount", "int", "",7') + file.write('\n\t\t}') + file.write('\n\t\tMultiLayer: 0') + file.write('\n\t\tMultiTake: 0') + file.write('\n\t\tHidden: "True"') + file.write('\n\t\tShading: Y') + file.write('\n\t\tCulling: "CullingOff"') + file.write('\n\t\tTypeFlags: "Camera"') + file.write('\n\t\tGeometryVersion: 124') + file.write('\n\t\tPosition: %.6f,%.6f,%.6f' % loc) + file.write('\n\t\tUp: %i,%i,%i' % up) + file.write('\n\t\tLookAt: 0,0,0') + file.write('\n\t\tShowInfoOnMoving: 1') + file.write('\n\t\tShowAudio: 0') + file.write('\n\t\tAudioColor: 0,1,0') + file.write('\n\t\tCameraOrthoZoom: 1') + file.write('\n\t}') + + def write_camera_default(): + # This sucks but to match FBX converter its easier to + # write the cameras though they are not needed. + write_camera_dummy('Producer Perspective', (0,71.3,287.5), 10, 4000, 0, (0,1,0)) + write_camera_dummy('Producer Top', (0,4000,0), 1, 30000, 1, (0,0,-1)) + write_camera_dummy('Producer Bottom', (0,-4000,0), 1, 30000, 1, (0,0,-1)) + write_camera_dummy('Producer Front', (0,0,4000), 1, 30000, 1, (0,1,0)) + write_camera_dummy('Producer Back', (0,0,-4000), 1, 30000, 1, (0,1,0)) + write_camera_dummy('Producer Right', (4000,0,0), 1, 30000, 1, (0,1,0)) + write_camera_dummy('Producer Left', (-4000,0,0), 1, 30000, 1, (0,1,0)) + + def write_camera(my_cam): + ''' + Write a blender camera + ''' + render = sce.render + width = render.sizeX + height = render.sizeY + aspect = float(width)/height + + data = my_cam.blenObject.data + + file.write('\n\tModel: "Model::%s", "Camera" {' % my_cam.fbxName ) + file.write('\n\t\tVersion: 232') + loc, rot, scale, matrix, matrix_rot = write_object_props(my_cam.blenObject, None, my_cam.parRelMatrix()) + + file.write('\n\t\t\tProperty: "Roll", "Roll", "A+",0') + file.write('\n\t\t\tProperty: "FieldOfView", "FieldOfView", "A+",%.6f' % data.angle) + file.write('\n\t\t\tProperty: "FieldOfViewX", "FieldOfView", "A+",1') + file.write('\n\t\t\tProperty: "FieldOfViewY", "FieldOfView", "A+",1') + file.write('\n\t\t\tProperty: "FocalLength", "Real", "A+",14.0323972702026') + file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",%.6f' % data.shiftX) # not sure if this is in the correct units? + file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",%.6f' % data.shiftY) # ditto + file.write('\n\t\t\tProperty: "BackgroundColor", "Color", "A+",0,0,0') + file.write('\n\t\t\tProperty: "TurnTable", "Real", "A+",0') + file.write('\n\t\t\tProperty: "DisplayTurnTableIcon", "bool", "",1') + file.write('\n\t\t\tProperty: "Motion Blur Intensity", "Real", "A+",1') + file.write('\n\t\t\tProperty: "UseMotionBlur", "bool", "",0') + file.write('\n\t\t\tProperty: "UseRealTimeMotionBlur", "bool", "",1') + file.write('\n\t\t\tProperty: "ResolutionMode", "enum", "",0') + file.write('\n\t\t\tProperty: "ApertureMode", "enum", "",2') + file.write('\n\t\t\tProperty: "GateFit", "enum", "",0') + file.write('\n\t\t\tProperty: "CameraFormat", "enum", "",0') + file.write('\n\t\t\tProperty: "AspectW", "double", "",%i' % width) + file.write('\n\t\t\tProperty: "AspectH", "double", "",%i' % height) + + '''Camera aspect ratio modes. + 0 If the ratio mode is eWINDOW_SIZE, both width and height values aren't relevant. + 1 If the ratio mode is eFIXED_RATIO, the height value is set to 1.0 and the width value is relative to the height value. + 2 If the ratio mode is eFIXED_RESOLUTION, both width and height values are in pixels. + 3 If the ratio mode is eFIXED_WIDTH, the width value is in pixels and the height value is relative to the width value. + 4 If the ratio mode is eFIXED_HEIGHT, the height value is in pixels and the width value is relative to the height value. + + Definition at line 234 of file kfbxcamera.h. ''' + + file.write('\n\t\t\tProperty: "PixelAspectRatio", "double", "",2') + + file.write('\n\t\t\tProperty: "UseFrameColor", "bool", "",0') + file.write('\n\t\t\tProperty: "FrameColor", "ColorRGB", "",0.3,0.3,0.3') + file.write('\n\t\t\tProperty: "ShowName", "bool", "",1') + file.write('\n\t\t\tProperty: "ShowGrid", "bool", "",1') + file.write('\n\t\t\tProperty: "ShowOpticalCenter", "bool", "",0') + file.write('\n\t\t\tProperty: "ShowAzimut", "bool", "",1') + file.write('\n\t\t\tProperty: "ShowTimeCode", "bool", "",0') + file.write('\n\t\t\tProperty: "NearPlane", "double", "",%.6f' % data.clipStart) + file.write('\n\t\t\tProperty: "FarPlane", "double", "",%.6f' % data.clipStart) + file.write('\n\t\t\tProperty: "FilmWidth", "double", "",1.0') + file.write('\n\t\t\tProperty: "FilmHeight", "double", "",1.0') + file.write('\n\t\t\tProperty: "FilmAspectRatio", "double", "",%.6f' % aspect) + file.write('\n\t\t\tProperty: "FilmSqueezeRatio", "double", "",1') + file.write('\n\t\t\tProperty: "FilmFormatIndex", "enum", "",0') + file.write('\n\t\t\tProperty: "ViewFrustum", "bool", "",1') + file.write('\n\t\t\tProperty: "ViewFrustumNearFarPlane", "bool", "",0') + file.write('\n\t\t\tProperty: "ViewFrustumBackPlaneMode", "enum", "",2') + file.write('\n\t\t\tProperty: "BackPlaneDistance", "double", "",100') + file.write('\n\t\t\tProperty: "BackPlaneDistanceMode", "enum", "",0') + file.write('\n\t\t\tProperty: "ViewCameraToLookAt", "bool", "",1') + file.write('\n\t\t\tProperty: "LockMode", "bool", "",0') + file.write('\n\t\t\tProperty: "LockInterestNavigation", "bool", "",0') + file.write('\n\t\t\tProperty: "FitImage", "bool", "",0') + file.write('\n\t\t\tProperty: "Crop", "bool", "",0') + file.write('\n\t\t\tProperty: "Center", "bool", "",1') + file.write('\n\t\t\tProperty: "KeepRatio", "bool", "",1') + file.write('\n\t\t\tProperty: "BackgroundMode", "enum", "",0') + file.write('\n\t\t\tProperty: "BackgroundAlphaTreshold", "double", "",0.5') + file.write('\n\t\t\tProperty: "ForegroundTransparent", "bool", "",1') + file.write('\n\t\t\tProperty: "DisplaySafeArea", "bool", "",0') + file.write('\n\t\t\tProperty: "SafeAreaDisplayStyle", "enum", "",1') + file.write('\n\t\t\tProperty: "SafeAreaAspectRatio", "double", "",%.6f' % aspect) + file.write('\n\t\t\tProperty: "Use2DMagnifierZoom", "bool", "",0') + file.write('\n\t\t\tProperty: "2D Magnifier Zoom", "Real", "A+",100') + file.write('\n\t\t\tProperty: "2D Magnifier X", "Real", "A+",50') + file.write('\n\t\t\tProperty: "2D Magnifier Y", "Real", "A+",50') + file.write('\n\t\t\tProperty: "CameraProjectionType", "enum", "",0') + file.write('\n\t\t\tProperty: "UseRealTimeDOFAndAA", "bool", "",0') + file.write('\n\t\t\tProperty: "UseDepthOfField", "bool", "",0') + file.write('\n\t\t\tProperty: "FocusSource", "enum", "",0') + file.write('\n\t\t\tProperty: "FocusAngle", "double", "",3.5') + file.write('\n\t\t\tProperty: "FocusDistance", "double", "",200') + file.write('\n\t\t\tProperty: "UseAntialiasing", "bool", "",0') + file.write('\n\t\t\tProperty: "AntialiasingIntensity", "double", "",0.77777') + file.write('\n\t\t\tProperty: "UseAccumulationBuffer", "bool", "",0') + file.write('\n\t\t\tProperty: "FrameSamplingCount", "int", "",7') + + file.write('\n\t\t}') + file.write('\n\t\tMultiLayer: 0') + file.write('\n\t\tMultiTake: 0') + file.write('\n\t\tShading: Y') + file.write('\n\t\tCulling: "CullingOff"') + file.write('\n\t\tTypeFlags: "Camera"') + file.write('\n\t\tGeometryVersion: 124') + file.write('\n\t\tPosition: %.6f,%.6f,%.6f' % loc) + file.write('\n\t\tUp: %.6f,%.6f,%.6f' % tuple(Vector(0,1,0) * matrix_rot) ) + file.write('\n\t\tLookAt: %.6f,%.6f,%.6f' % tuple(Vector(0,0,-1)*matrix_rot) ) + + #file.write('\n\t\tUp: 0,0,0' ) + #file.write('\n\t\tLookAt: 0,0,0' ) + + file.write('\n\t\tShowInfoOnMoving: 1') + file.write('\n\t\tShowAudio: 0') + file.write('\n\t\tAudioColor: 0,1,0') + file.write('\n\t\tCameraOrthoZoom: 1') + file.write('\n\t}') + + def write_light(my_light): + light = my_light.blenObject.data + file.write('\n\tModel: "Model::%s", "Light" {' % my_light.fbxName) + file.write('\n\t\tVersion: 232') + + write_object_props(my_light.blenObject, None, my_light.parRelMatrix()) + + # Why are these values here twice?????? - oh well, follow the holy sdk's output + + # Blender light types match FBX's, funny coincidence, we just need to + # be sure that all unsupported types are made into a point light + #ePOINT, + #eDIRECTIONAL + #eSPOT + light_type = light.type + if light_type > 3: light_type = 0 + + mode = light.mode + if mode & Blender.Lamp.Modes.RayShadow or mode & Blender.Lamp.Modes.Shadows: + do_shadow = 1 + else: + do_shadow = 0 + + if mode & Blender.Lamp.Modes.OnlyShadow or (mode & Blender.Lamp.Modes.NoDiffuse and mode & Blender.Lamp.Modes.NoSpecular): + do_light = 0 + else: + do_light = 1 + + scale = abs(GLOBAL_MATRIX.scalePart()[0]) # scale is always uniform in this case + + file.write('\n\t\t\tProperty: "LightType", "enum", "",%i' % light_type) + file.write('\n\t\t\tProperty: "CastLightOnObject", "bool", "",1') + file.write('\n\t\t\tProperty: "DrawVolumetricLight", "bool", "",1') + file.write('\n\t\t\tProperty: "DrawGroundProjection", "bool", "",1') + file.write('\n\t\t\tProperty: "DrawFrontFacingVolumetricLight", "bool", "",0') + file.write('\n\t\t\tProperty: "GoboProperty", "object", ""') + file.write('\n\t\t\tProperty: "Color", "Color", "A+",1,1,1') + file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (min(light.energy*100, 200))) # clamp below 200 + file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spotSize * scale)) + file.write('\n\t\t\tProperty: "Fog", "Fog", "A+",50') + file.write('\n\t\t\tProperty: "Color", "Color", "A",%.2f,%.2f,%.2f' % tuple(light.col)) + file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (min(light.energy*100, 200))) # clamp below 200 + file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spotSize * scale)) + file.write('\n\t\t\tProperty: "Fog", "Fog", "A+",50') + file.write('\n\t\t\tProperty: "LightType", "enum", "",%i' % light_type) + file.write('\n\t\t\tProperty: "CastLightOnObject", "bool", "",%i' % do_light) + file.write('\n\t\t\tProperty: "DrawGroundProjection", "bool", "",1') + file.write('\n\t\t\tProperty: "DrawFrontFacingVolumetricLight", "bool", "",0') + file.write('\n\t\t\tProperty: "DrawVolumetricLight", "bool", "",1') + file.write('\n\t\t\tProperty: "GoboProperty", "object", ""') + file.write('\n\t\t\tProperty: "DecayType", "enum", "",0') + file.write('\n\t\t\tProperty: "DecayStart", "double", "",%.2f' % light.dist) + file.write('\n\t\t\tProperty: "EnableNearAttenuation", "bool", "",0') + file.write('\n\t\t\tProperty: "NearAttenuationStart", "double", "",0') + file.write('\n\t\t\tProperty: "NearAttenuationEnd", "double", "",0') + file.write('\n\t\t\tProperty: "EnableFarAttenuation", "bool", "",0') + file.write('\n\t\t\tProperty: "FarAttenuationStart", "double", "",0') + file.write('\n\t\t\tProperty: "FarAttenuationEnd", "double", "",0') + file.write('\n\t\t\tProperty: "CastShadows", "bool", "",%i' % do_shadow) + file.write('\n\t\t\tProperty: "ShadowColor", "ColorRGBA", "",0,0,0,1') + file.write('\n\t\t}') + file.write('\n\t\tMultiLayer: 0') + file.write('\n\t\tMultiTake: 0') + file.write('\n\t\tShading: Y') + file.write('\n\t\tCulling: "CullingOff"') + file.write('\n\t\tTypeFlags: "Light"') + file.write('\n\t\tGeometryVersion: 124') + file.write('\n\t}') + + # matrixOnly is not used at the moment + def write_null(my_null = None, fbxName = None, matrixOnly = None): + # ob can be null + if not fbxName: fbxName = my_null.fbxName + + file.write('\n\tModel: "Model::%s", "Null" {' % fbxName) + file.write('\n\t\tVersion: 232') + + # only use this for the root matrix at the moment + if matrixOnly: + poseMatrix = write_object_props(None, None, matrixOnly)[3] + + else: # all other Null's + if my_null: poseMatrix = write_object_props(my_null.blenObject, None, my_null.parRelMatrix())[3] + else: poseMatrix = write_object_props()[3] + + pose_items.append((fbxName, poseMatrix)) + + file.write(''' + } + MultiLayer: 0 + MultiTake: 1 + Shading: Y + Culling: "CullingOff" + TypeFlags: "Null" + }''') + + # Material Settings + if world: world_amb = world.getAmb() + else: world_amb = (0,0,0) # Default value + + def write_material(matname, mat): + file.write('\n\tMaterial: "Material::%s", "" {' % matname) + + # Todo, add more material Properties. + if mat: + mat_cold = tuple(mat.rgbCol) + mat_cols = tuple(mat.specCol) + #mat_colm = tuple(mat.mirCol) # we wont use the mirror color + mat_colamb = tuple([c for c in world_amb]) + + mat_dif = mat.ref + mat_amb = mat.amb + mat_hard = (float(mat.hard)-1)/5.10 + mat_spec = mat.spec/2.0 + mat_alpha = mat.alpha + mat_emit = mat.emit + mat_shadeless = mat.mode & Blender.Material.Modes.SHADELESS + if mat_shadeless: + mat_shader = 'Lambert' + else: + if mat.diffuseShader == Blender.Material.Shaders.DIFFUSE_LAMBERT: + mat_shader = 'Lambert' + else: + mat_shader = 'Phong' + else: + mat_cols = mat_cold = 0.8, 0.8, 0.8 + mat_colamb = 0.0,0.0,0.0 + # mat_colm + mat_dif = 1.0 + mat_amb = 0.5 + mat_hard = 20.0 + mat_spec = 0.2 + mat_alpha = 1.0 + mat_emit = 0.0 + mat_shadeless = False + mat_shader = 'Phong' + + file.write('\n\t\tVersion: 102') + file.write('\n\t\tShadingModel: "%s"' % mat_shader.lower()) + file.write('\n\t\tMultiLayer: 0') + + file.write('\n\t\tProperties60: {') + file.write('\n\t\t\tProperty: "ShadingModel", "KString", "", "%s"' % mat_shader) + file.write('\n\t\t\tProperty: "MultiLayer", "bool", "",0') + file.write('\n\t\t\tProperty: "EmissiveColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cold) # emit and diffuse color are he same in blender + file.write('\n\t\t\tProperty: "EmissiveFactor", "double", "",%.4f' % mat_dif) + + file.write('\n\t\t\tProperty: "AmbientColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_colamb) + file.write('\n\t\t\tProperty: "AmbientFactor", "double", "",%.4f' % mat_amb) + file.write('\n\t\t\tProperty: "DiffuseColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cold) + file.write('\n\t\t\tProperty: "DiffuseFactor", "double", "",%.4f' % mat_emit) + file.write('\n\t\t\tProperty: "Bump", "Vector3D", "",0,0,0') + file.write('\n\t\t\tProperty: "TransparentColor", "ColorRGB", "",1,1,1') + file.write('\n\t\t\tProperty: "TransparencyFactor", "double", "",%.4f' % (1.0 - mat_alpha)) + if not mat_shadeless: + file.write('\n\t\t\tProperty: "SpecularColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cols) + file.write('\n\t\t\tProperty: "SpecularFactor", "double", "",%.4f' % mat_spec) + file.write('\n\t\t\tProperty: "ShininessExponent", "double", "",80.0') + file.write('\n\t\t\tProperty: "ReflectionColor", "ColorRGB", "",0,0,0') + file.write('\n\t\t\tProperty: "ReflectionFactor", "double", "",1') + file.write('\n\t\t\tProperty: "Emissive", "ColorRGB", "",0,0,0') + file.write('\n\t\t\tProperty: "Ambient", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_colamb) + file.write('\n\t\t\tProperty: "Diffuse", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_cold) + if not mat_shadeless: + file.write('\n\t\t\tProperty: "Specular", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_cols) + file.write('\n\t\t\tProperty: "Shininess", "double", "",%.1f' % mat_hard) + file.write('\n\t\t\tProperty: "Opacity", "double", "",%.1f' % mat_alpha) + if not mat_shadeless: + file.write('\n\t\t\tProperty: "Reflectivity", "double", "",0') + + file.write('\n\t\t}') + file.write('\n\t}') + + def write_video(texname, tex): + # Same as texture really! + file.write('\n\tVideo: "Video::%s", "Clip" {' % texname) + + file.write(''' + Type: "Clip" + Properties60: { + Property: "FrameRate", "double", "",0 + Property: "LastFrame", "int", "",0 + Property: "Width", "int", "",0 + Property: "Height", "int", "",0''') + if tex: + fname = tex.filename + fname_strip = strip_path(fname) + else: + fname = fname_strip = '' + + file.write('\n\t\t\tProperty: "Path", "charptr", "", "%s"' % fname_strip) + + + file.write(''' + Property: "StartFrame", "int", "",0 + Property: "StopFrame", "int", "",0 + Property: "PlaySpeed", "double", "",1 + Property: "Offset", "KTime", "",0 + Property: "InterlaceMode", "enum", "",0 + Property: "FreeRunning", "bool", "",0 + Property: "Loop", "bool", "",0 + Property: "AccessMode", "enum", "",0 + } + UseMipMap: 0''') + + file.write('\n\t\tFilename: "%s"' % fname_strip) + if fname_strip: fname_strip = '/' + fname_strip + file.write('\n\t\tRelativeFilename: "fbx%s"' % fname_strip) # make relative + file.write('\n\t}') + + + def write_texture(texname, tex, num): + # if tex == None then this is a dummy tex + file.write('\n\tTexture: "Texture::%s", "TextureVideoClip" {' % texname) + file.write('\n\t\tType: "TextureVideoClip"') + file.write('\n\t\tVersion: 202') + # TODO, rare case _empty_ exists as a name. + file.write('\n\t\tTextureName: "Texture::%s"' % texname) + + file.write(''' + Properties60: { + Property: "Translation", "Vector", "A+",0,0,0 + Property: "Rotation", "Vector", "A+",0,0,0 + Property: "Scaling", "Vector", "A+",1,1,1''') + file.write('\n\t\t\tProperty: "Texture alpha", "Number", "A+",%i' % num) + + + # WrapModeU/V 0==rep, 1==clamp, TODO add support + file.write(''' + Property: "TextureTypeUse", "enum", "",0 + Property: "CurrentTextureBlendMode", "enum", "",1 + Property: "UseMaterial", "bool", "",0 + Property: "UseMipMap", "bool", "",0 + Property: "CurrentMappingType", "enum", "",0 + Property: "UVSwap", "bool", "",0''') + + file.write('\n\t\t\tProperty: "WrapModeU", "enum", "",%i' % tex.clampX) + file.write('\n\t\t\tProperty: "WrapModeV", "enum", "",%i' % tex.clampY) + + file.write(''' + Property: "TextureRotationPivot", "Vector3D", "",0,0,0 + Property: "TextureScalingPivot", "Vector3D", "",0,0,0 + Property: "VideoProperty", "object", "" + }''') + + file.write('\n\t\tMedia: "Video::%s"' % texname) + if tex: + fname = tex.filename + file.write('\n\t\tFileName: "%s"' % strip_path(fname)) + file.write('\n\t\tRelativeFilename: "fbx/%s"' % strip_path(fname)) # need some make relative command + else: + file.write('\n\t\tFileName: ""') + file.write('\n\t\tRelativeFilename: "fbx"') + + file.write(''' + ModelUVTranslation: 0,0 + ModelUVScaling: 1,1 + Texture_Alpha_Source: "None" + Cropping: 0,0,0,0 + }''') + + def write_deformer_skin(obname): + ''' + Each mesh has its own deformer + ''' + file.write('\n\tDeformer: "Deformer::Skin %s", "Skin" {' % obname) + file.write(''' + Version: 100 + MultiLayer: 0 + Type: "Skin" + Properties60: { + } + Link_DeformAcuracy: 50 + }''') + + # in the example was 'Bip01 L Thigh_2' + def write_sub_deformer_skin(my_mesh, my_bone, weights): + + ''' + Each subdeformer is spesific to a mesh, but the bone it links to can be used by many sub-deformers + So the SubDeformer needs the mesh-object name as a prefix to make it unique + + Its possible that there is no matching vgroup in this mesh, in that case no verts are in the subdeformer, + a but silly but dosnt really matter + ''' + file.write('\n\tDeformer: "SubDeformer::Cluster %s %s", "Cluster" {' % (my_mesh.fbxName, my_bone.fbxName)) + + file.write(''' + Version: 100 + MultiLayer: 0 + Type: "Cluster" + Properties60: { + Property: "SrcModel", "object", "" + Property: "SrcModelReference", "object", "" + } + UserData: "", ""''') + + # Support for bone parents + if my_mesh.fbxBoneParent: + if my_mesh.fbxBoneParent == my_bone: + # TODO - this is a bit lazy, we could have a simple write loop + # for this case because all weights are 1.0 but for now this is ok + # Parent Bones arent used all that much anyway. + vgroup_data = [(j, 1.0) for j in xrange(len(my_mesh.blenData.verts))] + else: + # This bone is not a parent of this mesh object, no weights + vgroup_data = [] + + else: + # Normal weight painted mesh + if my_bone.blenName in weights[0]: + # Before we used normalized wright list + #vgroup_data = me.getVertsFromGroup(bone.name, 1) + group_index = weights[0].index(my_bone.blenName) + vgroup_data = [(j, weight[group_index]) for j, weight in enumerate(weights[1]) if weight[group_index]] + else: + vgroup_data = [] + + file.write('\n\t\tIndexes: ') + + i = -1 + for vg in vgroup_data: + if i == -1: + file.write('%i' % vg[0]) + i=0 + else: + if i==23: + file.write('\n\t\t') + i=0 + file.write(',%i' % vg[0]) + i+=1 + + file.write('\n\t\tWeights: ') + i = -1 + for vg in vgroup_data: + if i == -1: + file.write('%.8f' % vg[1]) + i=0 + else: + if i==38: + file.write('\n\t\t') + i=0 + file.write(',%.8f' % vg[1]) + i+=1 + + if my_mesh.fbxParent: + # TODO FIXME, this case is broken in some cases. skinned meshes just shouldnt have parents where possible! + m = mtx4_z90 * (my_bone.restMatrix * my_bone.fbxArm.matrixWorld.copy() * my_mesh.matrixWorld.copy().invert() ) + else: + # Yes! this is it... - but dosnt work when the mesh is a. + m = mtx4_z90 * (my_bone.restMatrix * my_bone.fbxArm.matrixWorld.copy() * my_mesh.matrixWorld.copy().invert() ) + + #m = mtx4_z90 * my_bone.restMatrix + matstr = mat4x4str(m) + matstr_i = mat4x4str(m.invert()) + + file.write('\n\t\tTransform: %s' % matstr_i) # THIS IS __NOT__ THE GLOBAL MATRIX AS DOCUMENTED :/ + file.write('\n\t\tTransformLink: %s' % matstr) + file.write('\n\t}') + + def write_mesh(my_mesh): + + me = my_mesh.blenData + + # if there are non NULL materials on this mesh + if [mat for mat in my_mesh.blenMaterials if mat]: do_materials = True + else: do_materials = False + + if my_mesh.blenTextures: do_textures = True + else: do_textures = False + + + file.write('\n\tModel: "Model::%s", "Mesh" {' % my_mesh.fbxName) + file.write('\n\t\tVersion: 232') # newline is added in write_object_props + + write_object_props(my_mesh.blenObject, None, my_mesh.parRelMatrix()) + + file.write('\n\t\t}') + file.write('\n\t\tMultiLayer: 0') + file.write('\n\t\tMultiTake: 1') + file.write('\n\t\tShading: Y') + file.write('\n\t\tCulling: "CullingOff"') + + + # Write the Real Mesh data here + file.write('\n\t\tVertices: ') + i=-1 + + for v in me.verts: + if i==-1: + file.write('%.6f,%.6f,%.6f' % tuple(v.co)); i=0 + else: + if i==7: + file.write('\n\t\t'); i=0 + file.write(',%.6f,%.6f,%.6f'% tuple(v.co)) + i+=1 + + file.write('\n\t\tPolygonVertexIndex: ') + i=-1 + for f in me.faces: + fi = [v.index for v in f] + # flip the last index, odd but it looks like + # this is how fbx tells one face from another + fi[-1] = -(fi[-1]+1) + fi = tuple(fi) + if i==-1: + if len(f) == 3: file.write('%i,%i,%i' % fi ) + else: file.write('%i,%i,%i,%i' % fi ) + i=0 + else: + if i==13: + file.write('\n\t\t') + i=0 + if len(f) == 3: file.write(',%i,%i,%i' % fi ) + else: file.write(',%i,%i,%i,%i' % fi ) + i+=1 + + ed_val = [None, None] + LOOSE = Blender.Mesh.EdgeFlags.LOOSE + for ed in me.edges: + if ed.flag & LOOSE: + ed_val[0] = ed.v1.index + ed_val[1] = -(ed.v2.index+1) + if i==-1: + file.write('%i,%i' % tuple(ed_val) ) + i=0 + else: + if i==13: + file.write('\n\t\t') + i=0 + file.write(',%i,%i' % tuple(ed_val) ) + i+=1 + del LOOSE + + file.write('\n\t\tGeometryVersion: 124') + + file.write(''' + LayerElementNormal: 0 { + Version: 101 + Name: "" + MappingInformationType: "ByVertice" + ReferenceInformationType: "Direct" + Normals: ''') + + i=-1 + for v in me.verts: + if i==-1: + file.write('%.15f,%.15f,%.15f' % tuple(v.no)); i=0 + else: + if i==2: + file.write('\n '); i=0 + file.write(',%.15f,%.15f,%.15f' % tuple(v.no)) + i+=1 + file.write('\n\t\t}') + + # Write VertexColor Layers + # note, no programs seem to use this info :/ + collayers = [] + if me.vertexColors: + collayers = me.getColorLayerNames() + collayer_orig = me.activeColorLayer + for colindex, collayer in enumerate(collayers): + me.activeColorLayer = collayer + file.write('\n\t\tLayerElementColor: %i {' % colindex) + file.write('\n\t\t\tVersion: 101') + file.write('\n\t\t\tName: "%s"' % collayer) + + file.write(''' + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + Colors: ''') + + i = -1 + ii = 0 # Count how many Colors we write + + for f in me.faces: + for col in f.col: + if i==-1: + file.write('%i,%i,%i' % (col[0], col[1], col[2])) + i=0 + else: + if i==7: + file.write('\n\t\t\t\t') + i=0 + file.write(',%i,%i,%i' % (col[0], col[1], col[2])) + i+=1 + ii+=1 # One more Color + + file.write('\n\t\t\tColorIndex: ') + i = -1 + for j in xrange(ii): + if i == -1: + file.write('%i' % j) + i=0 + else: + if i==55: + file.write('\n\t\t\t\t') + i=0 + file.write(',%i' % j) + i+=1 + + file.write('\n\t\t}') + + + + # Write UV and texture layers. + uvlayers = [] + if me.faceUV: + uvlayers = me.getUVLayerNames() + uvlayer_orig = me.activeUVLayer + for uvindex, uvlayer in enumerate(uvlayers): + me.activeUVLayer = uvlayer + file.write('\n\t\tLayerElementUV: %i {' % uvindex) + file.write('\n\t\t\tVersion: 101') + file.write('\n\t\t\tName: "%s"' % uvlayer) + + file.write(''' + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: ''') + + i = -1 + ii = 0 # Count how many UVs we write + + for f in me.faces: + for uv in f.uv: + if i==-1: + file.write('%.6f,%.6f' % tuple(uv)) + i=0 + else: + if i==7: + file.write('\n ') + i=0 + file.write(',%.6f,%.6f' % tuple(uv)) + i+=1 + ii+=1 # One more UV + + file.write('\n\t\t\tUVIndex: ') + i = -1 + for j in xrange(ii): + if i == -1: + file.write('%i' % j) + i=0 + else: + if i==55: + file.write('\n\t\t\t\t') + i=0 + file.write(',%i' % j) + i+=1 + + file.write('\n\t\t}') + + if do_textures: + file.write('\n\t\tLayerElementTexture: %i {' % uvindex) + file.write('\n\t\t\tVersion: 101') + file.write('\n\t\t\tName: "%s"' % uvlayer) + + if len(my_mesh.blenTextures) == 1: + file.write('\n\t\t\tMappingInformationType: "AllSame"') + else: + file.write('\n\t\t\tMappingInformationType: "ByPolygon"') + + file.write('\n\t\t\tReferenceInformationType: "IndexToDirect"') + file.write('\n\t\t\tBlendMode: "Translucent"') + file.write('\n\t\t\tTextureAlpha: 1') + file.write('\n\t\t\tTextureId: ') + + if len(my_mesh.blenTextures) == 1: + file.write('0') + else: + #texture_mapping_local = {None:0} + texture_mapping_local = {None:-1} + + i = 0 # 1 for dummy + for tex in my_mesh.blenTextures: + texture_mapping_local[tex] = i + i+=1 + + i=-1 + for f in me.faces: + img_key = f.image + + if i==-1: + i=0 + file.write( '%s' % texture_mapping_local[img_key]) + else: + if i==55: + file.write('\n ') + i=0 + + file.write(',%s' % texture_mapping_local[img_key]) + i+=1 + + else: + file.write(''' + LayerElementTexture: 0 { + Version: 101 + Name: "" + MappingInformationType: "NoMappingInformation" + ReferenceInformationType: "IndexToDirect" + BlendMode: "Translucent" + TextureAlpha: 1 + TextureId: ''') + file.write('\n\t\t}') + + me.activeUVLayer = uvlayer_orig + + # Done with UV/textures. + + if do_materials: + file.write('\n\t\tLayerElementMaterial: 0 {') + file.write('\n\t\t\tVersion: 101') + file.write('\n\t\t\tName: ""') + + if len(my_mesh.blenMaterials) == 1: + file.write('\n\t\t\tMappingInformationType: "AllSame"') + else: + file.write('\n\t\t\tMappingInformationType: "ByPolygon"') + + file.write('\n\t\t\tReferenceInformationType: "IndexToDirect"') + file.write('\n\t\t\tMaterials: ') + + if len(my_mesh.blenMaterials) == 1: + file.write('0') + else: + # Build a material mapping for this + #material_mapping_local = [0] * 16 # local-index : global index. + material_mapping_local = [-1] * 16 # local-index : global index. + i= 0 # 1 + for j, mat in enumerate(my_mesh.blenMaterials): + if mat: + material_mapping_local[j] = i + i+=1 + # else leave as -1 + + len_material_mapping_local = len(material_mapping_local) + + i=-1 + for f in me.faces: + f_mat = f.mat + if f_mat >= len_material_mapping_local: + f_mat = 0 + + if i==-1: + i=0 + file.write( '%s' % (material_mapping_local[f_mat])) + else: + if i==55: + file.write('\n\t\t\t\t') + i=0 + + file.write(',%s' % (material_mapping_local[f_mat])) + i+=1 + + file.write('\n\t\t}') + + file.write(''' + Layer: 0 { + Version: 100 + LayerElement: { + Type: "LayerElementNormal" + TypedIndex: 0 + }''') + + if do_materials: + file.write(''' + LayerElement: { + Type: "LayerElementMaterial" + TypedIndex: 0 + }''') + + # Always write this + if do_textures: + file.write(''' + LayerElement: { + Type: "LayerElementTexture" + TypedIndex: 0 + }''') + + if me.vertexColors: + file.write(''' + LayerElement: { + Type: "LayerElementColor" + TypedIndex: 0 + }''') + + if me.faceUV: + file.write(''' + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 0 + }''') + + + file.write('\n\t\t}') + + if len(uvlayers) > 1: + for i in xrange(1, len(uvlayers)): + + file.write('\n\t\tLayer: %i {' % i) + file.write('\n\t\t\tVersion: 100') + + file.write(''' + LayerElement: { + Type: "LayerElementUV"''') + + file.write('\n\t\t\t\tTypedIndex: %i' % i) + file.write('\n\t\t\t}') + + if do_textures: + + file.write(''' + LayerElement: { + Type: "LayerElementTexture"''') + + file.write('\n\t\t\t\tTypedIndex: %i' % i) + file.write('\n\t\t\t}') + + file.write('\n\t\t}') + + if len(collayers) > 1: + # Take into account any UV layers + layer_offset = 0 + if uvlayers: layer_offset = len(uvlayers)-1 + + for i in xrange(layer_offset, len(collayers)+layer_offset): + file.write('\n\t\tLayer: %i {' % i) + file.write('\n\t\t\tVersion: 100') + + file.write(''' + LayerElement: { + Type: "LayerElementColor"''') + + file.write('\n\t\t\t\tTypedIndex: %i' % i) + file.write('\n\t\t\t}') + file.write('\n\t\t}') + file.write('\n\t}') + + def write_group(name): + file.write('\n\tGroupSelection: "GroupSelection::%s", "Default" {' % name) + + file.write(''' + Properties60: { + Property: "MultiLayer", "bool", "",0 + Property: "Pickable", "bool", "",1 + Property: "Transformable", "bool", "",1 + Property: "Show", "bool", "",1 + } + MultiLayer: 0 + }''') + + + # add meshes here to clear because they are not used anywhere. + meshes_to_clear = [] + + ob_meshes = [] + ob_lights = [] + ob_cameras = [] + # in fbx we export bones as children of the mesh + # armatures not a part of a mesh, will be added to ob_arms + ob_bones = [] + ob_arms = [] + ob_null = [] # emptys + + # List of types that have blender objects (not bones) + ob_all_typegroups = [ob_meshes, ob_lights, ob_cameras, ob_arms, ob_null] + + groups = [] # blender groups, only add ones that have objects in the selections + materials = {} + textures = {} + + tmp_ob_type = ob_type = None # incase no objects are exported, so as not to raise an error + + # if EXP_OBS_SELECTED is false, use sceens objects + if not batch_objects: + if EXP_OBS_SELECTED: tmp_objects = sce.objects.context + else: tmp_objects = sce.objects + else: + tmp_objects = batch_objects + + if EXP_ARMATURE: + # This is needed so applying modifiers dosnt apply the armature deformation, its also needed + # ...so mesh objects return their rest worldspace matrix when bone-parents are exported as weighted meshes. + # set every armature to its rest, backup the original values so we done mess up the scene + ob_arms_orig_rest = [arm.restPosition for arm in bpy.data.armatures] + + for arm in bpy.data.armatures: + arm.restPosition = True + + if ob_arms_orig_rest: + for ob_base in bpy.data.objects: + #if ob_base.type == 'Armature': + ob_base.makeDisplayList() + + # This causes the makeDisplayList command to effect the mesh + Blender.Set('curframe', Blender.Get('curframe')) + + + for ob_base in tmp_objects: + for ob, mtx in BPyObject.getDerivedObjects(ob_base): + #for ob in [ob_base,]: + tmp_ob_type = ob.type + if tmp_ob_type == 'Camera': + if EXP_CAMERA: + ob_cameras.append(my_object_generic(ob, mtx)) + elif tmp_ob_type == 'Lamp': + if EXP_LAMP: + ob_lights.append(my_object_generic(ob, mtx)) + elif tmp_ob_type == 'Armature': + if EXP_ARMATURE: + # TODO - armatures dont work in dupligroups! + if ob not in ob_arms: ob_arms.append(ob) + # ob_arms.append(ob) # replace later. was "ob_arms.append(sane_obname(ob), ob)" + elif tmp_ob_type == 'Empty': + if EXP_EMPTY: + ob_null.append(my_object_generic(ob, mtx)) + elif EXP_MESH: + origData = True + if tmp_ob_type != 'Mesh': + me = bpy.data.meshes.new() + try: me.getFromObject(ob) + except: me = None + if me: + meshes_to_clear.append( me ) + mats = me.materials + origData = False + else: + # Mesh Type! + if EXP_MESH_APPLY_MOD: + me = bpy.data.meshes.new() + me.getFromObject(ob) + + # so we keep the vert groups + if EXP_ARMATURE: + orig_mesh = ob.getData(mesh=1) + if orig_mesh.getVertGroupNames(): + ob.copy().link(me) + # If new mesh has no vgroups we can try add if verts are teh same + if not me.getVertGroupNames(): # vgroups were not kept by the modifier + if len(me.verts) == len(orig_mesh.verts): + groupNames, vWeightDict = BPyMesh.meshWeight2Dict(orig_mesh) + BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict) + + # print ob, me, me.getVertGroupNames() + meshes_to_clear.append( me ) + origData = False + mats = me.materials + else: + me = ob.getData(mesh=1) + mats = me.materials + + # Support object colors + tmp_colbits = ob.colbits + if tmp_colbits: + tmp_ob_mats = ob.getMaterials(1) # 1 so we get None's too. + for i in xrange(16): + if tmp_colbits & (1< fbxObject mapping + # this is needed for groups as well as fbxParenting + bpy.data.objects.tag = False + tmp_obmapping = {} + for ob_generic in ob_all_typegroups: + for ob_base in ob_generic: + ob_base.blenObject.tag = True + tmp_obmapping[ob_base.blenObject] = ob_base + + # Build Groups from objects we export + for blenGroup in bpy.data.groups: + fbxGroupName = None + for ob in blenGroup.objects: + if ob.tag: + if fbxGroupName == None: + fbxGroupName = sane_groupname(blenGroup) + groups.append((fbxGroupName, blenGroup)) + + tmp_obmapping[ob].fbxGroupNames.append(fbxGroupName) # also adds to the objects fbxGroupNames + + groups.sort() # not really needed + + # Assign parents using this mapping + for ob_generic in ob_all_typegroups: + for my_ob in ob_generic: + parent = my_ob.blenObject.parent + if parent and parent.tag: # does it exist and is it in the mapping + my_ob.fbxParent = tmp_obmapping[parent] + + + del tmp_obmapping + # Finished finding groups we use + + + materials = [(sane_matname(mat), mat) for mat in materials.itervalues() if mat] + textures = [(sane_texname(img), img) for img in textures.itervalues() if img] + materials.sort() # sort by name + textures.sort() + + camera_count = 8 + file.write(''' + +; Object definitions +;------------------------------------------------------------------ + +Definitions: { + Version: 100 + Count: %i''' % (\ + 1+1+camera_count+\ + len(ob_meshes)+\ + len(ob_lights)+\ + len(ob_cameras)+\ + len(ob_arms)+\ + len(ob_null)+\ + len(ob_bones)+\ + bone_deformer_count+\ + len(materials)+\ + (len(textures)*2))) # add 1 for the root model 1 for global settings + + del bone_deformer_count + + file.write(''' + ObjectType: "Model" { + Count: %i + }''' % (\ + 1+camera_count+\ + len(ob_meshes)+\ + len(ob_lights)+\ + len(ob_cameras)+\ + len(ob_arms)+\ + len(ob_null)+\ + len(ob_bones))) # add 1 for the root model + + file.write(''' + ObjectType: "Geometry" { + Count: %i + }''' % len(ob_meshes)) + + if materials: + file.write(''' + ObjectType: "Material" { + Count: %i + }''' % len(materials)) + + if textures: + file.write(''' + ObjectType: "Texture" { + Count: %i + }''' % len(textures)) # add 1 for an empty tex + file.write(''' + ObjectType: "Video" { + Count: %i + }''' % len(textures)) # add 1 for an empty tex + + tmp = 0 + # Add deformer nodes + for my_mesh in ob_meshes: + if my_mesh.fbxArm: + tmp+=1 + + # Add subdeformers + for my_bone in ob_bones: + tmp += len(my_bone.blenMeshes) + + if tmp: + file.write(''' + ObjectType: "Deformer" { + Count: %i + }''' % tmp) + del tmp + + # we could avoid writing this possibly but for now just write it + + file.write(''' + ObjectType: "Pose" { + Count: 1 + }''') + + if groups: + file.write(''' + ObjectType: "GroupSelection" { + Count: %i + }''' % len(groups)) + + file.write(''' + ObjectType: "GlobalSettings" { + Count: 1 + } +}''') + + file.write(''' + +; Object properties +;------------------------------------------------------------------ + +Objects: {''') + + # To comply with other FBX FILES + write_camera_switch() + + # Write the null object + write_null(None, 'blend_root')# , GLOBAL_MATRIX) + + for my_null in ob_null: + write_null(my_null) + + for my_arm in ob_arms: + write_null(my_arm) + + for my_cam in ob_cameras: + write_camera(my_cam) + + for my_light in ob_lights: + write_light(my_light) + + for my_mesh in ob_meshes: + write_mesh(my_mesh) + + #for bonename, bone, obname, me, armob in ob_bones: + for my_bone in ob_bones: + write_bone(my_bone) + + write_camera_default() + + for matname, mat in materials: + write_material(matname, mat) + + # each texture uses a video, odd + for texname, tex in textures: + write_video(texname, tex) + i = 0 + for texname, tex in textures: + write_texture(texname, tex, i) + i+=1 + + for groupname, group in groups: + write_group(groupname) + + # NOTE - c4d and motionbuilder dont need normalized weights, but deep-exploration 5 does and (max?) do. + + # Write armature modifiers + # TODO - add another MODEL? - because of this skin definition. + for my_mesh in ob_meshes: + if my_mesh.fbxArm: + write_deformer_skin(my_mesh.fbxName) + + # Get normalized weights for temorary use + if my_mesh.fbxBoneParent: + weights = None + else: + weights = meshNormalizedWeights(my_mesh.blenData) + + #for bonename, bone, obname, bone_mesh, armob in ob_bones: + for my_bone in ob_bones: + if me in my_bone.blenMeshes.itervalues(): + write_sub_deformer_skin(my_mesh, my_bone, weights) + + # Write pose's really weired, only needed when an armature and mesh are used together + # each by themselves dont need pose data. for now only pose meshes and bones + + file.write(''' + Pose: "Pose::BIND_POSES", "BindPose" { + Type: "BindPose" + Version: 100 + Properties60: { + } + NbPoseNodes: ''') + file.write(str(len(pose_items))) + + + for fbxName, matrix in pose_items: + file.write('\n\t\tPoseNode: {') + file.write('\n\t\t\tNode: "Model::%s"' % fbxName ) + if matrix: file.write('\n\t\t\tMatrix: %s' % mat4x4str(matrix)) + else: file.write('\n\t\t\tMatrix: %s' % mat4x4str(mtx4_identity)) + file.write('\n\t\t}') + + file.write('\n\t}') + + + # Finish Writing Objects + # Write global settings + file.write(''' + GlobalSettings: { + Version: 1000 + Properties60: { + Property: "UpAxis", "int", "",1 + Property: "UpAxisSign", "int", "",1 + Property: "FrontAxis", "int", "",2 + Property: "FrontAxisSign", "int", "",1 + Property: "CoordAxis", "int", "",0 + Property: "CoordAxisSign", "int", "",1 + Property: "UnitScaleFactor", "double", "",100 + } + } +''') + file.write('}') + + file.write(''' + +; Object relations +;------------------------------------------------------------------ + +Relations: {''') + + file.write('\n\tModel: "Model::blend_root", "Null" {\n\t}') + + for my_null in ob_null: + file.write('\n\tModel: "Model::%s", "Null" {\n\t}' % my_null.fbxName) + + for my_arm in ob_arms: + file.write('\n\tModel: "Model::%s", "Null" {\n\t}' % my_arm.fbxName) + + for my_mesh in ob_meshes: + file.write('\n\tModel: "Model::%s", "Mesh" {\n\t}' % my_mesh.fbxName) + + # TODO - limbs can have the same name for multiple armatures, should prefix. + #for bonename, bone, obname, me, armob in ob_bones: + for my_bone in ob_bones: + file.write('\n\tModel: "Model::%s", "Limb" {\n\t}' % my_bone.fbxName) + + for my_cam in ob_cameras: + file.write('\n\tModel: "Model::%s", "Camera" {\n\t}' % my_cam.fbxName) + + for my_light in ob_lights: + file.write('\n\tModel: "Model::%s", "Light" {\n\t}' % my_light.fbxName) + + file.write(''' + Model: "Model::Producer Perspective", "Camera" { + } + Model: "Model::Producer Top", "Camera" { + } + Model: "Model::Producer Bottom", "Camera" { + } + Model: "Model::Producer Front", "Camera" { + } + Model: "Model::Producer Back", "Camera" { + } + Model: "Model::Producer Right", "Camera" { + } + Model: "Model::Producer Left", "Camera" { + } + Model: "Model::Camera Switcher", "CameraSwitcher" { + }''') + + for matname, mat in materials: + file.write('\n\tMaterial: "Material::%s", "" {\n\t}' % matname) + + if textures: + for texname, tex in textures: + file.write('\n\tTexture: "Texture::%s", "TextureVideoClip" {\n\t}' % texname) + for texname, tex in textures: + file.write('\n\tVideo: "Video::%s", "Clip" {\n\t}' % texname) + + # deformers - modifiers + for my_mesh in ob_meshes: + if my_mesh.fbxArm: + file.write('\n\tDeformer: "Deformer::Skin %s", "Skin" {\n\t}' % my_mesh.fbxName) + + #for bonename, bone, obname, me, armob in ob_bones: + for my_bone in ob_bones: + for fbxMeshObName in my_bone.blenMeshes: # .keys() - fbxMeshObName + # is this bone effecting a mesh? + file.write('\n\tDeformer: "SubDeformer::Cluster %s %s", "Cluster" {\n\t}' % (fbxMeshObName, my_bone.fbxName)) + + # This should be at the end + # file.write('\n\tPose: "Pose::BIND_POSES", "BindPose" {\n\t}') + + for groupname, group in groups: + file.write('\n\tGroupSelection: "GroupSelection::%s", "Default" {\n\t}' % groupname) + + file.write('\n}') + file.write(''' + +; Object connections +;------------------------------------------------------------------ + +Connections: {''') + + # NOTE - The FBX SDK dosnt care about the order but some importers DO! + # for instance, defining the material->mesh connection + # before the mesh->blend_root crashes cinema4d + + + # write the fake root node + file.write('\n\tConnect: "OO", "Model::blend_root", "Model::Scene"') + + for ob_generic in ob_all_typegroups: # all blender 'Object's we support + for my_ob in ob_generic: + if my_ob.fbxParent: + file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_ob.fbxName, my_ob.fbxParent.fbxName)) + else: + file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % my_ob.fbxName) + + if materials: + for my_mesh in ob_meshes: + # Connect all materials to all objects, not good form but ok for now. + for mat in my_mesh.blenMaterials: + if mat: + file.write('\n\tConnect: "OO", "Material::%s", "Model::%s"' % (sane_name_mapping_mat[mat.name], my_mesh.fbxName)) + + if textures: + for my_mesh in ob_meshes: + if my_mesh.blenTextures: + # file.write('\n\tConnect: "OO", "Texture::_empty_", "Model::%s"' % my_mesh.fbxName) + for tex in my_mesh.blenTextures: + if tex: + file.write('\n\tConnect: "OO", "Texture::%s", "Model::%s"' % (sane_name_mapping_tex[tex.name], my_mesh.fbxName)) + + for texname, tex in textures: + file.write('\n\tConnect: "OO", "Video::%s", "Texture::%s"' % (texname, texname)) + + for my_mesh in ob_meshes: + if my_mesh.fbxArm: + file.write('\n\tConnect: "OO", "Deformer::Skin %s", "Model::%s"' % (my_mesh.fbxName, my_mesh.fbxName)) + + #for bonename, bone, obname, me, armob in ob_bones: + for my_bone in ob_bones: + for fbxMeshObName in my_bone.blenMeshes: # .keys() + file.write('\n\tConnect: "OO", "SubDeformer::Cluster %s %s", "Deformer::Skin %s"' % (fbxMeshObName, my_bone.fbxName, fbxMeshObName)) + + # limbs -> deformers + # for bonename, bone, obname, me, armob in ob_bones: + for my_bone in ob_bones: + for fbxMeshObName in my_bone.blenMeshes: # .keys() + file.write('\n\tConnect: "OO", "Model::%s", "SubDeformer::Cluster %s %s"' % (my_bone.fbxName, fbxMeshObName, my_bone.fbxName)) + + + #for bonename, bone, obname, me, armob in ob_bones: + for my_bone in ob_bones: + # Always parent to armature now + if my_bone.parent: + file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_bone.fbxName, my_bone.parent.fbxName) ) + else: + # the armature object is written as an empty and all root level bones connect to it + file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_bone.fbxName, my_bone.fbxArm.fbxName) ) + + # groups + if groups: + for ob_generic in ob_all_typegroups: + for ob_base in ob_generic: + for fbxGroupName in ob_base.fbxGroupNames: + file.write('\n\tConnect: "OO", "Model::%s", "GroupSelection::%s"' % (ob_base.fbxName, fbxGroupName)) + + for my_arm in ob_arms: + file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % my_arm.fbxName) + + file.write('\n}') + + + # Needed for scene footer as well as animation + render = sce.render + + # from the FBX sdk + #define KTIME_ONE_SECOND KTime (K_LONGLONG(46186158000)) + def fbx_time(t): + # 0.5 + val is the same as rounding. + return int(0.5 + ((t/fps) * 46186158000)) + + fps = float(render.fps) + start = render.sFrame + end = render.eFrame + if end < start: start, end = end, start + if start==end: ANIM_ENABLE = False + + # animations for these object types + ob_anim_lists = ob_bones, ob_meshes, ob_null, ob_cameras, ob_lights, ob_arms + + if ANIM_ENABLE and [tmp for tmp in ob_anim_lists if tmp]: + + frame_orig = Blender.Get('curframe') + + if ANIM_OPTIMIZE: + ANIM_OPTIMIZE_PRECISSION_FLOAT = 0.1 ** ANIM_OPTIMIZE_PRECISSION + + # default action, when no actions are avaioable + tmp_actions = [None] # None is the default action + blenActionDefault = None + action_lastcompat = None + + if ANIM_ACTION_ALL: + bpy.data.actions.tag = False + tmp_actions = list(bpy.data.actions) + + + # find which actions are compatible with the armatures + # blenActions is not yet initialized so do it now. + tmp_act_count = 0 + for my_arm in ob_arms: + + # get the default name + if not blenActionDefault: + blenActionDefault = my_arm.blenAction + + arm_bone_names = set([my_bone.blenName for my_bone in my_arm.fbxBones]) + + for action in tmp_actions: + + action_chan_names = arm_bone_names.intersection( set(action.getChannelNames()) ) + + if action_chan_names: # at least one channel matches. + my_arm.blenActionList.append(action) + action.tag = True + tmp_act_count += 1 + + # incase there is no actions applied to armatures + action_lastcompat = action + + if tmp_act_count: + # unlikely to ever happen but if no actions applied to armatures, just use the last compatible armature. + if not blenActionDefault: + blenActionDefault = action_lastcompat + + del action_lastcompat + + file.write(''' +;Takes and animation section +;---------------------------------------------------- + +Takes: {''') + + if blenActionDefault: + file.write('\n\tCurrent: "%s"' % sane_takename(blenActionDefault)) + else: + file.write('\n\tCurrent: "Default Take"') + + for blenAction in tmp_actions: + # we have tagged all actious that are used be selected armatures + if blenAction: + if blenAction.tag: + print '\taction: "%s" exporting...' % blenAction.name + else: + print '\taction: "%s" has no armature using it, skipping' % blenAction.name + continue + + if blenAction == None: + # Warning, this only accounts for tmp_actions being [None] + file.write('\n\tTake: "Default Take" {') + act_start = start + act_end = end + else: + # use existing name + if blenAction == blenActionDefault: # have we alredy got the name + file.write('\n\tTake: "%s" {' % sane_name_mapping_take[blenAction.name]) + else: + file.write('\n\tTake: "%s" {' % sane_takename(blenAction)) + + tmp = blenAction.getFrameNumbers() + if tmp: + act_start = min(tmp) + act_end = max(tmp) + del tmp + else: + # Fallback on this, theres not much else we can do? :/ + # when an action has no length + act_start = start + act_end = end + + # Set the action active + for my_bone in ob_arms: + if blenAction in my_bone.blenActionList: + ob.action = blenAction + # print '\t\tSetting Action!', blenAction + # sce.update(1) + + file.write('\n\t\tFileName: "Default_Take.tak"') # ??? - not sure why this is needed + file.write('\n\t\tLocalTime: %i,%i' % (fbx_time(act_start-1), fbx_time(act_end-1))) # ??? - not sure why this is needed + file.write('\n\t\tReferenceTime: %i,%i' % (fbx_time(act_start-1), fbx_time(act_end-1))) # ??? - not sure why this is needed + + file.write(''' + + ;Models animation + ;----------------------------------------------------''') + + + # set pose data for all bones + # do this here incase the action changes + ''' + for my_bone in ob_bones: + my_bone.flushAnimData() + ''' + i = act_start + while i <= act_end: + Blender.Set('curframe', i) + for ob_generic in ob_anim_lists: + for my_ob in ob_generic: + #Blender.Window.RedrawAll() + if ob_generic == ob_meshes and my_ob.fbxArm: + # We cant animate armature meshes! + pass + else: + my_ob.setPoseFrame(i) + + i+=1 + + + #for bonename, bone, obname, me, armob in ob_bones: + for ob_generic in (ob_bones, ob_meshes, ob_null, ob_cameras, ob_lights, ob_arms): + + for my_ob in ob_generic: + + if ob_generic == ob_meshes and my_ob.fbxArm: + # do nothing, + pass + else: + + file.write('\n\t\tModel: "Model::%s" {' % my_ob.fbxName) # ??? - not sure why this is needed + file.write('\n\t\t\tVersion: 1.1') + file.write('\n\t\t\tChannel: "Transform" {') + + context_bone_anim_mats = [ (my_ob.getAnimParRelMatrix(frame), my_ob.getAnimParRelMatrixRot(frame)) for frame in xrange(act_start, act_end+1) ] + + # ---------------- + # ---------------- + for TX_LAYER, TX_CHAN in enumerate('TRS'): # transform, rotate, scale + + if TX_CHAN=='T': context_bone_anim_vecs = [mtx[0].translationPart() for mtx in context_bone_anim_mats] + elif TX_CHAN=='R': context_bone_anim_vecs = [mtx[1].toEuler() for mtx in context_bone_anim_mats] + else: context_bone_anim_vecs = [mtx[0].scalePart() for mtx in context_bone_anim_mats] + + file.write('\n\t\t\t\tChannel: "%s" {' % TX_CHAN) # translation + + for i in xrange(3): + # Loop on each axis of the bone + file.write('\n\t\t\t\t\tChannel: "%s" {'% ('XYZ'[i])) # translation + file.write('\n\t\t\t\t\t\tDefault: %.15f' % context_bone_anim_vecs[0][i] ) + file.write('\n\t\t\t\t\t\tKeyVer: 4005') + + if not ANIM_OPTIMIZE: + # Just write all frames, simple but in-eficient + file.write('\n\t\t\t\t\t\tKeyCount: %i' % (1 + act_end - act_start)) + file.write('\n\t\t\t\t\t\tKey: ') + frame = act_start + while frame <= act_end: + if frame!=act_start: + file.write(',') + + # Curve types are + # C,n is for bezier? - linear is best for now so we can do simple keyframe removal + file.write('\n\t\t\t\t\t\t\t%i,%.15f,C,n' % (fbx_time(frame-1), context_bone_anim_vecs[frame-act_start][i] )) + #file.write('\n\t\t\t\t\t\t\t%i,%.15f,L' % (fbx_time(frame-1), context_bone_anim_vecs[frame-act_start][i] )) + frame+=1 + else: + # remove unneeded keys, j is the frame, needed when some frames are removed. + context_bone_anim_keys = [ (vec[i], j) for j, vec in enumerate(context_bone_anim_vecs) ] + + # last frame to fisrt frame, missing 1 frame on either side. + # removeing in a backwards loop is faster + for j in xrange( (act_end-act_start)-1, 0, -1 ): + # Is this key reduenant? + if abs(context_bone_anim_keys[j][0] - context_bone_anim_keys[j-1][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT and\ + abs(context_bone_anim_keys[j][0] - context_bone_anim_keys[j+1][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT: + del context_bone_anim_keys[j] + + if len(context_bone_anim_keys) == 2 and context_bone_anim_keys[0][0] == context_bone_anim_keys[1][0]: + # This axis has no moton, its okay to skip KeyCount and Keys in this case + pass + else: + # We only need to write these if there is at least one + file.write('\n\t\t\t\t\t\tKeyCount: %i' % len(context_bone_anim_keys)) + file.write('\n\t\t\t\t\t\tKey: ') + for val, frame in context_bone_anim_keys: + if frame != context_bone_anim_keys[0][1]: # not the first + file.write(',') + # frame is alredy one less then blenders frame + file.write('\n\t\t\t\t\t\t\t%i,%.15f,C,n' % (fbx_time(frame), val )) + #file.write('\n\t\t\t\t\t\t\t%i,%.15f,L' % (fbx_time(frame), val )) + + if i==0: file.write('\n\t\t\t\t\t\tColor: 1,0,0') + elif i==1: file.write('\n\t\t\t\t\t\tColor: 0,1,0') + elif i==2: file.write('\n\t\t\t\t\t\tColor: 0,0,1') + + file.write('\n\t\t\t\t\t}') + file.write('\n\t\t\t\t\tLayerType: %i' % (TX_LAYER+1) ) + file.write('\n\t\t\t\t}') + + # --------------- + + file.write('\n\t\t\t}') + file.write('\n\t\t}') + + # end the take + file.write('\n\t}') + + # end action loop. set original actions + # do this after every loop incase actions effect eachother. + for my_bone in ob_arms: + my_bone.blenObject.action = my_bone.blenAction + + file.write('\n}') + + Blender.Set('curframe', frame_orig) + + else: + # no animation + file.write('\n;Takes and animation section') + file.write('\n;----------------------------------------------------') + file.write('\n') + file.write('\nTakes: {') + file.write('\n\tCurrent: ""') + file.write('\n}') + + + # write meshes animation + #for obname, ob, mtx, me, mats, arm, armname in ob_meshes: + + + # Clear mesh data Only when writing with modifiers applied + for me in meshes_to_clear: + me.verts = None + + + + # --------------------------- Footer + if world: + has_mist = world.mode & 1 + mist_intense, mist_start, mist_end, mist_height = world.mist + world_hor = world.hor + else: + has_mist = mist_intense = mist_start = mist_end = mist_height = 0 + world_hor = 0,0,0 + + file.write('\n;Version 5 settings') + file.write('\n;------------------------------------------------------------------') + file.write('\n') + file.write('\nVersion5: {') + file.write('\n\tAmbientRenderSettings: {') + file.write('\n\t\tVersion: 101') + file.write('\n\t\tAmbientLightColor: %.1f,%.1f,%.1f,0' % tuple(world_amb)) + file.write('\n\t}') + file.write('\n\tFogOptions: {') + file.write('\n\t\tFlogEnable: %i' % has_mist) + file.write('\n\t\tFogMode: 0') + file.write('\n\t\tFogDensity: %.3f' % mist_intense) + file.write('\n\t\tFogStart: %.3f' % mist_start) + file.write('\n\t\tFogEnd: %.3f' % mist_end) + file.write('\n\t\tFogColor: %.1f,%.1f,%.1f,1' % tuple(world_hor)) + file.write('\n\t}') + file.write('\n\tSettings: {') + file.write('\n\t\tFrameRate: "%i"' % int(fps)) + file.write('\n\t\tTimeFormat: 1') + file.write('\n\t\tSnapOnFrames: 0') + file.write('\n\t\tReferenceTimeIndex: -1') + file.write('\n\t\tTimeLineStartTime: %i' % fbx_time(start-1)) + file.write('\n\t\tTimeLineStopTime: %i' % fbx_time(end-1)) + file.write('\n\t}') + file.write('\n\tRendererSetting: {') + file.write('\n\t\tDefaultCamera: "Producer Perspective"') + file.write('\n\t\tDefaultViewingMode: 0') + file.write('\n\t}') + file.write('\n}') + file.write('\n') + + # Incase sombody imports this, clean up by clearing global dicts + sane_name_mapping_ob.clear() + sane_name_mapping_mat.clear() + sane_name_mapping_tex.clear() + + ob_arms[:] = [] + ob_bones[:] = [] + ob_cameras[:] = [] + ob_lights[:] = [] + ob_meshes[:] = [] + ob_null[:] = [] + + + # copy images if enabled + if EXP_IMAGE_COPY: + copy_images( Blender.sys.dirname(filename), [ tex[1] for tex in textures if tex[1] != None ]) + + print 'export finished in %.4f sec.' % (Blender.sys.time() - start_time) + return True + + +# -------------------------------------------- +# UI Function - not a part of the exporter. +# this is to seperate the user interface from the rest of the exporter. +from Blender import Draw, Window +EVENT_NONE = 0 +EVENT_EXIT = 1 +EVENT_REDRAW = 2 +EVENT_FILESEL = 3 + +GLOBALS = {} + +# export opts + +def do_redraw(e,v): GLOBALS['EVENT'] = e + +# toggle between these 2, only allow one on at once +def do_obs_sel(e,v): + GLOBALS['EVENT'] = e + GLOBALS['EXP_OBS_SCENE'].val = 0 + GLOBALS['EXP_OBS_SELECTED'].val = 1 + +def do_obs_sce(e,v): + GLOBALS['EVENT'] = e + GLOBALS['EXP_OBS_SCENE'].val = 1 + GLOBALS['EXP_OBS_SELECTED'].val = 0 + +def do_obs_sce(e,v): + GLOBALS['EVENT'] = e + GLOBALS['EXP_OBS_SCENE'].val = 1 + GLOBALS['EXP_OBS_SELECTED'].val = 0 + +def do_batch_type_grp(e,v): + GLOBALS['EVENT'] = e + GLOBALS['BATCH_GROUP'].val = 1 + GLOBALS['BATCH_SCENE'].val = 0 + +def do_batch_type_sce(e,v): + GLOBALS['EVENT'] = e + GLOBALS['BATCH_GROUP'].val = 0 + GLOBALS['BATCH_SCENE'].val = 1 + +def do_anim_act_all(e,v): + GLOBALS['EVENT'] = e + GLOBALS['ANIM_ACTION_ALL'][0].val = 1 + GLOBALS['ANIM_ACTION_ALL'][1].val = 0 + +def do_anim_act_cur(e,v): + if GLOBALS['BATCH_ENABLE'].val and GLOBALS['BATCH_GROUP'].val: + Draw.PupMenu('Warning%t|Cant use this with batch export group option') + else: + GLOBALS['EVENT'] = e + GLOBALS['ANIM_ACTION_ALL'][0].val = 0 + GLOBALS['ANIM_ACTION_ALL'][1].val = 1 + +def fbx_ui_exit(e,v): + GLOBALS['EVENT'] = e + +def do_help(e,v): + url = 'http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_fbx' + print 'Trying to open web browser with documentation at this address...' + print '\t' + url + + try: + import webbrowser + webbrowser.open(url) + except: + print '...could not open a browser window.' + + + +# run when export is pressed +#def fbx_ui_write(e,v): +def fbx_ui_write(filename): + + # Dont allow overwriting files when saving normally + if not GLOBALS['BATCH_ENABLE'].val: + if not BPyMessages.Warning_SaveOver(filename): + return + + GLOBALS['EVENT'] = EVENT_EXIT + + # Keep the order the same as above for simplicity + # the [] is a dummy arg used for objects + + Blender.Window.WaitCursor(1) + + # Make the matrix + GLOBAL_MATRIX = mtx4_identity + GLOBAL_MATRIX[0][0] = GLOBAL_MATRIX[1][1] = GLOBAL_MATRIX[2][2] = GLOBALS['_SCALE'].val + if GLOBALS['_XROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_x90n + if GLOBALS['_YROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_y90n + if GLOBALS['_ZROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_z90n + + ret = write(\ + filename, None,\ + GLOBALS['EXP_OBS_SELECTED'].val,\ + GLOBALS['EXP_MESH'].val,\ + GLOBALS['EXP_MESH_APPLY_MOD'].val,\ + GLOBALS['EXP_MESH_HQ_NORMALS'].val,\ + GLOBALS['EXP_ARMATURE'].val,\ + GLOBALS['EXP_LAMP'].val,\ + GLOBALS['EXP_CAMERA'].val,\ + GLOBALS['EXP_EMPTY'].val,\ + GLOBALS['EXP_IMAGE_COPY'].val,\ + GLOBAL_MATRIX,\ + GLOBALS['ANIM_ENABLE'].val,\ + GLOBALS['ANIM_OPTIMIZE'].val,\ + GLOBALS['ANIM_OPTIMIZE_PRECISSION'].val,\ + GLOBALS['ANIM_ACTION_ALL'][0].val,\ + GLOBALS['BATCH_ENABLE'].val,\ + GLOBALS['BATCH_GROUP'].val,\ + GLOBALS['BATCH_SCENE'].val,\ + GLOBALS['BATCH_FILE_PREFIX'].val,\ + GLOBALS['BATCH_OWN_DIR'].val,\ + ) + + Blender.Window.WaitCursor(0) + GLOBALS.clear() + + if ret == False: + Draw.PupMenu('Error%t|Path cannot be written to!') + + +def fbx_ui(): + # Only to center the UI + x,y = GLOBALS['MOUSE'] + x-=180; y-=0 # offset... just to get it centered + + Draw.Label('Export Objects...', x+20,y+165, 200, 20) + + if not GLOBALS['BATCH_ENABLE'].val: + Draw.BeginAlign() + GLOBALS['EXP_OBS_SELECTED'] = Draw.Toggle('Selected Objects', EVENT_REDRAW, x+20, y+145, 160, 20, GLOBALS['EXP_OBS_SELECTED'].val, 'Export selected objects on visible layers', do_obs_sel) + GLOBALS['EXP_OBS_SCENE'] = Draw.Toggle('Scene Objects', EVENT_REDRAW, x+180, y+145, 160, 20, GLOBALS['EXP_OBS_SCENE'].val, 'Export all objects in this scene', do_obs_sce) + Draw.EndAlign() + + Draw.BeginAlign() + GLOBALS['_SCALE'] = Draw.Number('Scale:', EVENT_NONE, x+20, y+120, 140, 20, GLOBALS['_SCALE'].val, 0.01, 1000.0, 'Scale all data, (Note! some imports dont support scaled armatures)') + GLOBALS['_XROT90'] = Draw.Toggle('Rot X90', EVENT_NONE, x+160, y+120, 60, 20, GLOBALS['_XROT90'].val, 'Rotate all objects 90 degrese about the X axis') + GLOBALS['_YROT90'] = Draw.Toggle('Rot Y90', EVENT_NONE, x+220, y+120, 60, 20, GLOBALS['_YROT90'].val, 'Rotate all objects 90 degrese about the Y axis') + GLOBALS['_ZROT90'] = Draw.Toggle('Rot Z90', EVENT_NONE, x+280, y+120, 60, 20, GLOBALS['_ZROT90'].val, 'Rotate all objects 90 degrese about the Z axis') + Draw.EndAlign() + + y -= 35 + + Draw.BeginAlign() + GLOBALS['EXP_EMPTY'] = Draw.Toggle('Empty', EVENT_NONE, x+20, y+120, 60, 20, GLOBALS['EXP_EMPTY'].val, 'Export empty objects') + GLOBALS['EXP_CAMERA'] = Draw.Toggle('Camera', EVENT_NONE, x+80, y+120, 60, 20, GLOBALS['EXP_CAMERA'].val, 'Export camera objects') + GLOBALS['EXP_LAMP'] = Draw.Toggle('Lamp', EVENT_NONE, x+140, y+120, 60, 20, GLOBALS['EXP_LAMP'].val, 'Export lamp objects') + GLOBALS['EXP_ARMATURE'] = Draw.Toggle('Armature', EVENT_NONE, x+200, y+120, 60, 20, GLOBALS['EXP_ARMATURE'].val, 'Export armature objects') + GLOBALS['EXP_MESH'] = Draw.Toggle('Mesh', EVENT_REDRAW, x+260, y+120, 80, 20, GLOBALS['EXP_MESH'].val, 'Export mesh objects', do_redraw) #, do_axis_z) + Draw.EndAlign() + + if GLOBALS['EXP_MESH'].val: + # below mesh but + Draw.BeginAlign() + GLOBALS['EXP_MESH_APPLY_MOD'] = Draw.Toggle('Modifiers', EVENT_NONE, x+260, y+100, 80, 20, GLOBALS['EXP_MESH_APPLY_MOD'].val, 'Apply modifiers to mesh objects') #, do_axis_z) + GLOBALS['EXP_MESH_HQ_NORMALS'] = Draw.Toggle('HQ Normals', EVENT_NONE, x+260, y+80, 80, 20, GLOBALS['EXP_MESH_HQ_NORMALS'].val, 'Generate high quality normals') #, do_axis_z) + Draw.EndAlign() + + GLOBALS['EXP_IMAGE_COPY'] = Draw.Toggle('Copy Image Files', EVENT_NONE, x+20, y+80, 160, 20, GLOBALS['EXP_IMAGE_COPY'].val, 'Copy image files to the destination path') #, do_axis_z) + + + Draw.Label('Export Armature Animation...', x+20,y+45, 300, 20) + + GLOBALS['ANIM_ENABLE'] = Draw.Toggle('Enable Animation', EVENT_REDRAW, x+20, y+25, 160, 20, GLOBALS['ANIM_ENABLE'].val, 'Export keyframe animation', do_redraw) + if GLOBALS['ANIM_ENABLE'].val: + Draw.BeginAlign() + GLOBALS['ANIM_OPTIMIZE'] = Draw.Toggle('Optimize Keyframes', EVENT_REDRAW, x+20, y+0, 160, 20, GLOBALS['ANIM_OPTIMIZE'].val, 'Remove double keyframes', do_redraw) + if GLOBALS['ANIM_OPTIMIZE'].val: + GLOBALS['ANIM_OPTIMIZE_PRECISSION'] = Draw.Number('Precission: ', EVENT_NONE, x+180, y+0, 160, 20, GLOBALS['ANIM_OPTIMIZE_PRECISSION'].val, 3, 16, 'Tolerence for comparing double keyframes (higher for greater accuracy)') + Draw.EndAlign() + + Draw.BeginAlign() + GLOBALS['ANIM_ACTION_ALL'][1] = Draw.Toggle('Current Action', EVENT_REDRAW, x+20, y-25, 160, 20, GLOBALS['ANIM_ACTION_ALL'][1].val, 'Use actions currently applied to the armatures (use scene start/end frame)', do_anim_act_cur) + GLOBALS['ANIM_ACTION_ALL'][0] = Draw.Toggle('All Actions', EVENT_REDRAW, x+180,y-25, 160, 20, GLOBALS['ANIM_ACTION_ALL'][0].val, 'Use all actions for armatures', do_anim_act_all) + Draw.EndAlign() + + + Draw.Label('Export Batch...', x+20,y-60, 300, 20) + GLOBALS['BATCH_ENABLE'] = Draw.Toggle('Enable Batch', EVENT_REDRAW, x+20, y-80, 160, 20, GLOBALS['BATCH_ENABLE'].val, 'Automate exporting multiple scenes or groups to files', do_redraw) + + if GLOBALS['BATCH_ENABLE'].val: + Draw.BeginAlign() + GLOBALS['BATCH_GROUP'] = Draw.Toggle('Group > File', EVENT_REDRAW, x+20, y-105, 160, 20, GLOBALS['BATCH_GROUP'].val, 'Export each group as an FBX file', do_batch_type_grp) + GLOBALS['BATCH_SCENE'] = Draw.Toggle('Scene > File', EVENT_REDRAW, x+180, y-105, 160, 20, GLOBALS['BATCH_SCENE'].val, 'Export each scene as an FBX file', do_batch_type_sce) + + # Own dir requires OS module + if os: + GLOBALS['BATCH_OWN_DIR'] = Draw.Toggle('Own Dir', EVENT_NONE, x+20, y-125, 80, 20, GLOBALS['BATCH_OWN_DIR'].val, 'Create a dir for each exported file') + GLOBALS['BATCH_FILE_PREFIX'] = Draw.String('Prefix: ', EVENT_NONE, x+100, y-125, 240, 20, GLOBALS['BATCH_FILE_PREFIX'].val, 64, 'Prefix each file with this name ') + else: + GLOBALS['BATCH_FILE_PREFIX'] = Draw.String('Prefix: ', EVENT_NONE, x+20, y-125, 320, 20, GLOBALS['BATCH_FILE_PREFIX'].val, 64, 'Prefix each file with this name ') + + + Draw.EndAlign() + + #y+=80 + + ''' + Draw.BeginAlign() + GLOBALS['FILENAME'] = Draw.String('path: ', EVENT_NONE, x+20, y-170, 300, 20, GLOBALS['FILENAME'].val, 64, 'Prefix each file with this name ') + Draw.PushButton('..', EVENT_FILESEL, x+320, y-170, 20, 20, 'Select the path', do_redraw) + ''' + # Until batch is added + # + + + #Draw.BeginAlign() + Draw.PushButton('Online Help', EVENT_REDRAW, x+20, y-160, 100, 20, 'Open online help in a browser window', do_help) + Draw.PushButton('Cancel', EVENT_EXIT, x+130, y-160, 100, 20, 'Exit the exporter', fbx_ui_exit) + Draw.PushButton('Export', EVENT_FILESEL, x+240, y-160, 100, 20, 'Export the fbx file', do_redraw) + + #Draw.PushButton('Export', EVENT_EXIT, x+180, y-160, 160, 20, 'Export the fbx file', fbx_ui_write) + #Draw.EndAlign() + + # exit when mouse out of the view? + # GLOBALS['EVENT'] = EVENT_EXIT + +#def write_ui(filename): +def write_ui(): + + # globals + GLOBALS['EVENT'] = 2 + #GLOBALS['MOUSE'] = Window.GetMouseCoords() + GLOBALS['MOUSE'] = [i/2 for i in Window.GetScreenSize()] + GLOBALS['FILENAME'] = '' + ''' + # IF called from the fileselector + if filename == None: + GLOBALS['FILENAME'] = filename # Draw.Create(Blender.sys.makename(ext='.fbx')) + else: + GLOBALS['FILENAME'].val = filename + ''' + GLOBALS['EXP_OBS_SELECTED'] = Draw.Create(1) # dont need 2 variables but just do this for clarity + GLOBALS['EXP_OBS_SCENE'] = Draw.Create(0) + + GLOBALS['EXP_MESH'] = Draw.Create(1) + GLOBALS['EXP_MESH_APPLY_MOD'] = Draw.Create(1) + GLOBALS['EXP_MESH_HQ_NORMALS'] = Draw.Create(0) + GLOBALS['EXP_ARMATURE'] = Draw.Create(1) + GLOBALS['EXP_LAMP'] = Draw.Create(1) + GLOBALS['EXP_CAMERA'] = Draw.Create(1) + GLOBALS['EXP_EMPTY'] = Draw.Create(1) + GLOBALS['EXP_IMAGE_COPY'] = Draw.Create(0) + # animation opts + GLOBALS['ANIM_ENABLE'] = Draw.Create(1) + GLOBALS['ANIM_OPTIMIZE'] = Draw.Create(1) + GLOBALS['ANIM_OPTIMIZE_PRECISSION'] = Draw.Create(6) # decimal places + GLOBALS['ANIM_ACTION_ALL'] = [Draw.Create(0), Draw.Create(1)] # not just the current action + + # batch export options + GLOBALS['BATCH_ENABLE'] = Draw.Create(0) + GLOBALS['BATCH_GROUP'] = Draw.Create(1) # cant have both of these enabled at once. + GLOBALS['BATCH_SCENE'] = Draw.Create(0) # see above + GLOBALS['BATCH_FILE_PREFIX'] = Draw.Create(Blender.sys.makename(ext='_').split('\\')[-1].split('/')[-1]) + GLOBALS['BATCH_OWN_DIR'] = Draw.Create(0) + # done setting globals + + # Used by the user interface + GLOBALS['_SCALE'] = Draw.Create(1.0) + GLOBALS['_XROT90'] = Draw.Create(True) + GLOBALS['_YROT90'] = Draw.Create(False) + GLOBALS['_ZROT90'] = Draw.Create(False) + + # horrible ugly hack so tooltips draw, dosnt always work even + # Fixed in Draw.UIBlock for 2.45rc2, but keep this until 2.45 is released + Window.SetKeyQualifiers(0) + while Window.GetMouseButtons(): Blender.sys.sleep(10) + for i in xrange(100): Window.QHandle(i) + # END HORRID HACK + + # best not do move the cursor + # Window.SetMouseCoords(*[i/2 for i in Window.GetScreenSize()]) + + # hack so the toggle buttons redraw. this is not nice at all + while GLOBALS['EVENT'] != EVENT_EXIT: + + if GLOBALS['BATCH_ENABLE'].val and GLOBALS['BATCH_GROUP'].val and GLOBALS['ANIM_ACTION_ALL'][1].val: + #Draw.PupMenu("Warning%t|Cant batch export groups with 'Current Action' ") + GLOBALS['ANIM_ACTION_ALL'][0].val = 1 + GLOBALS['ANIM_ACTION_ALL'][1].val = 0 + + if GLOBALS['EVENT'] == EVENT_FILESEL: + if GLOBALS['BATCH_ENABLE'].val: + txt = 'Batch FBX Dir' + name = Blender.sys.expandpath('//') + else: + txt = 'Export FBX' + name = Blender.sys.makename(ext='.fbx') + + Blender.Window.FileSelector(fbx_ui_write, txt, name) + #fbx_ui_write('/test.fbx') + break + + Draw.UIBlock(fbx_ui) + + + # GLOBALS.clear() +#test = [write_ui] +if __name__ == '__main__': + # Cant call the file selector first because of a bug in the interface that crashes it. + # Blender.Window.FileSelector(write_ui, 'Export FBX', Blender.sys.makename(ext='.fbx')) + #write('/scratch/test.fbx') + #write_ui('/scratch/test.fbx') + + if not set: + Draw.PupMenu('Error%t|A full install of python2.3 or python 2.4+ is needed to run this script.') + else: + write_ui() diff --git a/release/scripts/export_lightwave_motion.py b/release/scripts/export_lightwave_motion.py new file mode 100644 index 00000000000..cabc4cf5fc6 --- /dev/null +++ b/release/scripts/export_lightwave_motion.py @@ -0,0 +1,156 @@ +#!BPY + +""" Registration info for Blender menus: <- these words are ignored +Name: 'Lightwave Motion (.mot)...' +Blender: 241 +Group: 'Export' +Tip: 'Export Loc Rot Size chanels to a Lightwave .mot file' +""" + +__author__ = "Daniel Salazar (ZanQdo)" +__url__ = ("blender", "elysiun", +"e-mail: zanqdo@gmail.com") +__version__ = "24/03/06" + +__bpydoc__ = """\ +This script exports the selected object's motion channels to a Lightwave +motion file (.mot). + +Usage: +Run the script with one or more objects selected (any kind), frames exported +are between Start and End frames in Render buttons. + +""" + +# $Id$ +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2003, 2004: A Vanpoucke +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- +import Blender as B +#------------------------------------ +#Declarados: +TotalCanales = 9 +#------------------------------------ + +def FuncionPrincipal (Dir): + B.Window.WaitCursor(1) + ObjSelect = B.Object.GetSelected() + + if not ObjSelect: + B.Draw.PupMenu('Select 1 or more objects, aborting.') + return + + if not Dir.lower().endswith('.mot'): + Dir += '.mot' + + + SC = B.Scene.GetCurrent() + SCR = SC.getRenderingContext() + + for ob in ObjSelect: + origName= NombreObjeto= ob.name + print '----\nExporting Object "%s" motion file...' % origName + + FrameA = B.Get('curframe') + FrameP = B.Get('staframe') + FrameF = B.Get('endframe') + + FrameRate = float(SCR.framesPerSec()) + + #--------------------------------------------- + + # Replace danger characters by '_' + for ch in ' /\\~!@#$%^&*()+=[];\':",./<>?\t\r\n': + NombreObjeto = NombreObjeto.replace(ch, '_') + + # Check for file path extension + if len(ObjSelect) > 1: + DirN= '%s_%s.mot' % (Dir[:-4], NombreObjeto) + else: + DirN= Dir + + # Open the file + File = open(DirN,'w') + File.write ('LWMO\n3\n\n') # 3 is the version number. + + # number of channels + File.write ('NumChannels %i\n' % TotalCanales) + + # ---------------------------- + # Main Cycle + + def CicloPrimario(NumCanal): + B.Set('curframe', FrameP) + + File.write ('Channel %i\n{ Envelope\n %i\n' % (NumCanal, (FrameF - FrameP + 1))) + + FrameA = FrameP + while FrameA < (FrameF + 1): + + B.Set('curframe', FrameA) + + mat= ob.mat # Worldspace matrix + + if NumCanal == 0: + Val = mat.translationPart().x + elif NumCanal == 1: + Val = mat.translationPart().z + elif NumCanal == 2: + Val = mat.translationPart().y + elif NumCanal == 3: + Val = -mat.toEuler().z + elif NumCanal == 4: + Val = -mat.toEuler().x + elif NumCanal == 5: + Val = -mat.toEuler().y + elif NumCanal == 6: + Val = mat.scalePart().x + elif NumCanal == 7: + Val = mat.scalePart().z + elif NumCanal == 8: + Val = mat.scalePart().y + File.write (' Key %f %f 3 0 0 0 0 0 0\n' % (Val, (FrameA/FrameRate))) + + FrameA += 1 + # Ending Stuff + File.write (' Behaviors 1 1\n}\n') + + NumObjetoActual = len(ObjSelect) + Iteraciones = 0 + ProgBarVal = 0.0 + while Iteraciones < TotalCanales: + CicloPrimario(Iteraciones) + + # Start Progress Bar + B.Window.DrawProgressBar(ProgBarVal, origName) + ProgBarVal = (float(Iteraciones) / TotalCanales) * 0.98 + Iteraciones += 1 + + B.Window.DrawProgressBar(1.0, '') # Done + print '\nDone, %s motion file location is:\n%s\n' % (origName, DirN) + B.Window.WaitCursor(0) + +# Check if there are selected objects +def main(): + B.Window.FileSelector(FuncionPrincipal, "Write .mot File", B.sys.makename(ext='.mot')) + +if __name__=='__main__': + main() \ No newline at end of file diff --git a/release/scripts/export_m3g.py b/release/scripts/export_m3g.py new file mode 100644 index 00000000000..afb019fcc1e --- /dev/null +++ b/release/scripts/export_m3g.py @@ -0,0 +1,3047 @@ +#!BPY +""" Registration info for Blender menus: +Name: 'M3G (.m3g, .java)...' +Blender: 244 +Group: 'Export' +Tooltip: 'Export to M3G' +""" +#------------------------------------------------------------------------ +# M3G exporter for blender 2.37 or above +# +# Source: http://www.nelson-games.de/bl2m3g/source +# +# $Id: m3g_export.py,v 0.1 2005/04/19 12:25 gerhardv Exp gerhardv $ +# +# Author: Gerhard Völkl +# +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2005: gerhard völkl gkvoelkl@yahoo.de +# +# 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. + +# ***** END GPL LICENCE BLOCK ***** +# +# To use script: +# 1.) load this file in the text window. +# (press SHIFT+F11, Open New via Datablock button) +# 2.) make sure your mouse is over the text edit window and +# run this script. (press ALT+P) +# Or: +# copy to the scripts directory and it will appear in the +# export list. (Needs 2.32 or higher) +# +# Based on informations from: +# wrl2export.py from Rick Kimball and others +# --------------------------------------------------------------------------# +# History 0.2 +# * maximal Precision in VertexArray (with algorithms from Kalle Raita) +# * IPO Animation with mesh: Rotation, Translation and Size +# History 0.3 +# * to find a 3d object in your java programm you can assign a userID +# your blender object has name 'cube#01' your 3d object will have ID 01 +# the number after '#' is taken +# * more than one material per mesh can be used +# * uv texture support (implemented by Aki Koskinen and Juha Laitinen) +# The image which is bound to the faces will be exportet within m3g-file +# Limitations by M3G-API: +# The width and height of the image must be non-negative powers of two, +# but they need not to be equal. Maximum value is 256. +# *.java export: Only PNG images can be used. +# History 0.4 +# * check limitation of texture images (credit to MASTER_ZION for Brasil) +# * Better light: The light modeles of Blender and M3G are naturally +# different. So the export script trys to translate as much as possible +# +# M3G Light type Blender Light type +# -------------------------------------------------------------- +# AMIENT Light Not available as light type in Blender +# DIRECTIONAL Light SUN +# OMNIdirectional light LAMP +# SPOT light SPOT +# not translated HEMI +# not translated AREA +# +# Attributs of M3G Lights: +# +# Attenuation (OMNI,SPOT): +# Intensity of light changes with distance +# The attenuation factor is 1 / (c + l d + q d2) +# where d is the distance between the light and the vertex being lighted +# and c, l, q are the constant, linear, and quadratic coefficients. +# In Blender exists much complex posibilies. To simplify exporter uses +# only button Dist: distance at which the light intensity is half +# the Energy +# Color (ALL) +# Color of light +# Intensity (ALL) +# The RGB color of this Light is multiplied component-wise with the +# intensity. In Blender : energy +# SpotAngle (SPOT) +# the spot cone angle for this Light +# In Blender: spotSize +# SpotExponent (SPOT) +# The spot exponent controls the distribution of the intensity of +# this Light within the spot cone, such that larger values yield +# a more concentrated cone. In Blender: SpotBl +# +# * Some GUI for options +# First prototype of GUI was created using RipSting's Blender-Python +# GUI designer. Download at Http://oregonstate.edu/~dennisa/Blender/BPG/ +# +# * Ambiente light +# Information is taken by world ambiente attribute +# +# * Parenting Part 1 +# In Blender the Empty object is used to group objects. All objects +# which have the same empty as parent are the member of the same group. +# +# empty <-- Parent of -- element 1 +# <-- Parent of -- element 2 +# +# is translated in M3G +# +# group-Node -- Member --> element 1 +# -- Member --> element 2 +# +# In Blender every object can be the parent of every other object +# In M3G that is not possible. Only a group object can be parent. +# (Or the world object which is derived from group). +# That will come later as Parenting Part 2 +# +# * Backface Culling +# you can use backface culling, if option "use backface culloing" is on. +# Culling will be set in PolygonMode object of every mesh. The correct +# winding is controlled. +# History 0.5 +#* Bone Animation - Armature (Part 1) +# +# Armature is the skeleton for skinned meshes. It stores the bones in +# rest position (more information http://www.blender.org/cms/How_Armatures_work.634.0.html) +# You can work in Blender with bones and meshes in different ways. In +# this first attempt only the use of vertex groups is assisted. +# +# Blender-Objekts translated into M3G-Objects +# +# MESH SkinnedMesh +# | | +# v v +# ARMATURE Group +# | | +# v v +# BONE_1 Group +# Group_second +# | | +# V v +# BONE_2 Group +# Group_secound +# +# Every bone is translated into two groups at the moment, because +# the second bone is needed to do the animation in an easy way. +# +# The animations in Blender for meshes are stored in action objects. +# +# Blender Objects translated into M3G-Objects +# +# ARMATURE +# | activ +# v +# ACTION ANIMATIONCONTROLLER +# | 1..n ^ +# v ANIMATIONTRACK --> Group_second +# IPOs | +# v +# KEYSEQUENZE +# +# One action is translated into one animationcontroller. One IPO is +# translated in one KEYSEQUENZE and one ANIMATIONTRACK. +# +# At the moment only the active action of the armature object is translated. +# +#* Print Info, if type of light is used that is not supported +# +# History 0.5 +# +#* New Option exportAllAction (default value: false) +# If that option is true, all actions will be exported - not only the active +# action. +# At the moment you can only assign one action to one armature. +# To know which action is used with which armature the action +# needs a special name : +# #AE# + +# Example: Name of action : walk#A10E250#02 +# Name of armature : man#10 +# End Frame: 250 +# +# History 0.6 +# Include the same image only one time into the m3g-file +# +# All the following changes of this version was made by Claus Hoefele +# +#* Until now all vertices of the faces was been written. +# Now the vertices will be used again if possible: +# normal and texture coordinates of to vertices have to be the same +# +#* Smooth/solid shading can now be defined for every single material: +# in Editing panel (F9)>Link and Materials +# +#* This script uses now correctly the TexFace and Shadless Buttons in +# Shading panel (F5)>Material buttons>Material box. +# TexFace switches on/off the Export of texture coordinates. +# Shadeless does the some with the normal coordinates +# +#* The GUI was redesigned in a PupBlock +# +#* Options: +# +#** Texturing Enabled: Switches on/off export of textures and texture +# coordinates. Attention: the TextFace button switches only +# for one mesh +#** Texturing External: the textures will be included it mg3-file or +# exported in seperate file +#** Lighting Enabled: turns on/off export of lights and normal completly +# Attention: Shadeless only for one mesh +#** Persp. Correction: turns on/off perspective correction in PolygonMode. +#** Smooth Shading: turns on/off smooth shading in PolygonMode. +# +#* Textures in external references are used again (with ImageFactory) +# +#* Blender function: Double Sided button in Editing Context +# (F9)>Mesh panel) +# turn on/off PolygonMode.CULL_BACK anzuschalten. +# +#* Script ingnores meshes that have no faces +# +# History 0.7 +# +# * Exporter can work with texture coordinates greater 1 and smaller 0 +# +# * Adler32 did not work always correct. New implementation made. +# +# * Modul shutil is not needed any longer. Exporter has its own copy_file. +# (realized and inspired by ideasman_42 and Martin Neumann) +# --------------------------------------------------------------------------# +# TODO: Export only selected mesh +# TODO: Optimize Bones <--> Vertex Group mapping +# TODO: Compressed File +# TODO: MTex - Support +# TODO: By Rotating use SQUAD instead of Beziere. It's smoother +import Blender +from Blender import Types,Lamp,Material,Texture,Window,Registry,Draw +from Blender.BGL import * +from Blender.Object import * +from Blender.Camera import * +from Blender.Mesh import * +from array import array +import sys, struct, zlib +from inspect import * +from types import * +from Blender.Mathutils import * +from os.path import * +#import rpdb2 + +# ---- Helper Functions -------------------------------------------------------# +def copy_file(source, dest): + file = open(source, 'rb') + data = file.read() + file.close() + + file = open(dest, 'wb') + file.write(data) + file.close() + +def tracer(frame, event, arg): + '''Global trace function''' + if event=='call': + tmp = getargvalues(frame) + print event, frame.f_code.co_name, frame.f_lineno, \ + formatargvalues(tmp[0],tmp[1],tmp[2],tmp[3]) + elif event=='line': + print event, frame.f_code.co_name, frame.f_lineno + #print event, frame.f_code.co_name, frame.f_lineno, \ + # getsourcelines(frame.f_code)[frame.f_lineno] + elif event=='return': + print event, frame.f_code.co_name, frame.f_lineno, "->", arg + return tracer + +def doSearchDeep(inList,outList): + '''Does deepsearch for all elements in inList''' + for element in inList: + if element != None : outList = element.searchDeep(outList) + return outList + + +def getId(aObject): + ''' returns 0 if Object is None: M3G value for null''' + if aObject == None: return 0 + return aObject.id + +def toJavaBoolean(aValue): + ''' returns java equivalent to boolean''' + if aValue: + return 'true' + else : + return 'false' + +def sign(a): + if a<0 : return -1 + elif a>0 : return 1 + else : return 0 + +def isOrderClockWise(v,normal): + ''' returns true, if order of vertices is clockwise. Important for + culling ''' + # (v2-v0)x(v2-v1)=surface_normal + # + if type(v[0]) is Types.MVertType: + mNormal = TriangleNormal(Vector(v[0].co),Vector(v[1].co),Vector(v[2].co)) + else: + mNormal = TriangleNormal(Vector(v[0]),Vectot(v[1]),Vector(v[2])) + #print "normal ",mNormal.normalize() + #print "BNormal ",normal.normalize() + + # Do not use any longer. Blender does it correct + + result = (sign(normal.x)==sign(mNormal.x) and + sign(normal.y)==sign(mNormal.y) and + sign(normal.z)==sign(mNormal.z)) + #print "Result ",result + + return True + + +# ---- M3G Types --------------------------------------------------------------# +class M3GVertexList: + def __init__(self, wrapList): + self.mlist = wrapList + + def __getitem__(self, key): + item = self.mlist[key] + if type(item) is Types.MVertType: + result =(item.co[0],item.co[1],item.co[2]) + else: + result = item + return result + +class M3GBoneReference: + def __init__(self,first,count): + self.firstVertex=first #UInt32 + self.vertexCount=count #UInt32 + + +class M3GBone: + def __init__(self): + self.verts=[] #List of influenced verts + self.transformNode=None #ObjectIndex + self.references = [] #References to Verts that are needed + self.weight=0 #Int32 + + + def setVerts(self,aVerts): + self.verts = aVerts + self.createReferences() + + def createReferences(self): + #print "createReference::len(verts) ",len(self.verts) + if len(self.verts)==0: return #No Verts available + self.verts.sort() + ref = [] + list = [] + last = self.verts[0]-1 + count = 0 + for vert in self.verts: + #print "vert ",vert + if vert==last+1: + list.append(vert) + else: + ref.append(M3GBoneReference(list[0],len(list))) + #print list[0],len(list) + list=[vert] + last=vert + #print "list ",list + if len(list)>0: + ref.append(M3GBoneReference(list[0],len(list))) + self.references = ref + + +class M3GVector3D: + def __init__(self,ax=0.0,ay=0.0,az=0.0): + self.x = ax #Float32 + self.y = ay #Float32 + self.z = az #Float32 + + def writeJava(self): + return str(self.x)+"f, "+str(self.y)+"f, "+str(self.z)+"f" + + def getData(self): + return struct.pack("<3f",self.x,self.y,self.z) + + def getDataLength(self): + return struct.calcsize("<3f") + +class M3GMatrix: + """ A 4x4 generalized matrix. The 16 elements of the + matrix are output in the same order as they are + retrieved using the API Transform.get method. In + other words, in this order: + 0 1 2 3 + 4 5 6 7 + 8 9 10 11 + 12 13 14 15 """ + def __init__(self): + self.elements=16 * [0.0] #Float32 + + def identity(self): + self.elements[ 0] = 1.0 + self.elements[ 5] = 1.0 + self.elements[10] = 1.0 + self.elements[15] = 1.0 + + def getData(self): + return struct.pack('<16f',self.elements[0],self.elements[1], + self.elements[2],self.elements[3], + self.elements[4],self.elements[5], + self.elements[6],self.elements[7], + self.elements[8],self.elements[9], + self.elements[10],self.elements[11], + self.elements[12],self.elements[13], + self.elements[14],self.elements[15]) + + def getDataLength(self): + return struct.calcsize('<16f') + + +class M3GColorRGB: + """ A color, with no alpha information. Each compo- + nent is scaled so that 0x00 is 0.0, and 0xFF is 1.0. + """ + def __init__(self,ared=0,agreen=0,ablue=0): + self.red = ared #Byte + self.green = agreen #Byte + self.blue = ablue #Byte + + def writeJava(self): + return "0x"+("%02X%02X%02X%02X" % (0.0, self.red, self.green, self.blue)) + + def getData(self): + return struct.pack('3B',self.red,self.green,self.blue) + + def getDataLength(self): + return struct.calcsize('3B') + + +class M3GColorRGBA: + """ A color, with alpha information. Each component + is scaled so that 0x00 is 0.0, and 0xFF is 1.0. The + alpha value is scaled so that 0x00 is completely + transparent, and 0xFF is completely opaque. + """ + def __init__(self,ared=0,agreen=0,ablue=0,aalpha=0): + self.red = ared #Byte + self.green = agreen #Byte + self.blue = ablue #Byte + self.alpha = aalpha #Byte + + def writeJava(self): + return "0x"+("%02X%02X%02X%02X" % (self.alpha, self.red, self.green, self.blue)) + + def getData(self): + return struct.pack('4B',self.red,self.green,self.blue,self.alpha) + + def getDataLength(self): + return struct.calcsize('4B') + + +#ObjectIndex +#The index of a previously encountered object in +#the file. Although this is serialized as a single +#unsigned integer, it is included in the compound +#type list because of the additional semantic infor- +#mation embodied in its type. A value of 0 is +#reserved to indicate a null reference; actual object indices start from 1. Object indices must refer +#only to null or to an object which has already been +#created during the input deserialization of a file - +#they must be less than or equal to the index of the +#object in which they appear. Other values are dis- +#allowed and must be treated as errors. +#UInt32 +#index; + +# ---- M3G Proxy --------------------------------------------------------------- # +class M3GProxy: + def __init__(self): + self.name = "" + self.id=0 + self.ObjectType=0 + self.binaryFormat='' + + def __repr__(self): + return "<"+str(self.__class__)[9:] + ":" + str(self.name) + ":" + str(self.id) + ">" + + +class M3GHeaderObject(M3GProxy): + def __init__(self): + M3GProxy.__init__(self) + self.M3GHeaderObject_binaryFormat = ' 0: + value += struct.calcsize('<'+str(len(self.animationTracks))+'I') + return value + + def writeJava(self,aWriter,aCreate): + if aCreate : pass #Abstract! Could not be created + if len(self.animationTracks) > 0 : + aWriter.write(2) + for iTrack in self.animationTracks: + aWriter.write(2,"BL%i.addAnimationTrack(BL%i);" % (self.id,iTrack.id)) + + +class M3GTransformable(M3GObject3D): + def __init__(self): + M3GObject3D.__init__(self) + self.hasComponentTransform=False #Boolean + #IF hasComponentTransform==TRUE, THEN + self.translation=M3GVector3D(0,0,0) #Vector3D + self.scale=M3GVector3D(1,1,1) #Vector3D + self.orientationAngle=0 #Float32 + self.orientationAxis=M3GVector3D(0,0,0) #Vector3D undefined + #END + self.hasGeneralTransform=False #Boolean + #IF hasGeneralTransform==TRUE, THEN + self.transform = M3GMatrix() #Matrix identity + self.transform.identity() + #END + #If either hasComponentTransform or hasGeneralTransform is false, the omitted fields will be + #initialized to their default values (equivalent to an identity transform in both cases). + + def writeJava(self,aWriter,aCreate): + if aCreate: pass #Abstract Base Class! Cant't be created + M3GObject3D.writeJava(self,aWriter,False) + if self.hasGeneralTransform : + aWriter.write(2,"float[] BL%i_matrix = {" % (self.id)) + aWriter.writeList(self.transform.elements,4,"f") + aWriter.write(2,"};") + aWriter.write(2) + aWriter.write(2,"Transform BL%i_transform = new Transform();" % (self.id)) + aWriter.write(2,"BL%i_transform.set(BL%i_matrix);" % (self.id,self.id)) + aWriter.write(2,"BL%i.setTransform(BL%i_transform);" % (self.id,self.id)) + aWriter.write(2) + if self.hasComponentTransform: + aWriter.write(2,("BL%i.setTranslation("+self.translation.writeJava()+");") + %(self.id)) + + def getData(self): + data = M3GObject3D.getData(self) + data += struct.pack(" 1: + aWriter.write(2,"IndexBuffer[] BL%i_indexArray = {" % (self.id)) + aWriter.write(4,",".join(["BL%i" %(i.id) for i in self.indexBuffer ])) + aWriter.write(2," };") + aWriter.write(2) + aWriter.write(2,"Appearance[] BL%i_appearanceArray = {" % (self.id)) + aWriter.write(4,",".join(["BL%i" %(i.id) for i in self.appearance ])) + aWriter.write(2," };") + aWriter.write(2) + aWriter.write(2,"%s BL%i = new %s(BL%i,BL%i_indexArray,BL%i_appearanceArray%s);" % \ + (aClassName,self.id,aClassName,self.vertexBuffer.id, self.id,self.id,aExtension)) + else: + #print "indexBuffer", len(self.indexBuffer) + #print "appearance", len(self.appearance) + aWriter.write(2,"%s BL%i = new %s(BL%i,BL%i,BL%i%s);" % \ + (aClassName, + self.id, + aClassName, + self.vertexBuffer.id, + self.indexBuffer[0].id, + self.appearance[0].id, + aExtension)) + M3GNode.writeJava(self,aWriter,False) + aWriter.write(2) + + +class M3GSkinnedMesh(M3GMesh): + def __init__(self,aVertexBuffer=None, aIndexBuffer=[], aAppearance=[]): + M3GMesh.__init__(self,aVertexBuffer, aIndexBuffer, aAppearance) + self.ObjectType=16 + self.skeleton=None #ObjectIndex + self.bones={} + #print"M3GSkinnedMesh.__init__::self.vertexBuffer:",self.vertexBuffer + ##ObjectIndex skeleton; + ##UInt32 transformReferenceCount; + ##FOR each bone reference... + ## ObjectIndex transformNode; + ## UInt32 firstVertex; + ## UInt32 vertexCount; + ## Int32 weight; + ##END + + def searchDeep(self,alist): + alist = doSearchDeep([self.skeleton],alist) + return M3GMesh.searchDeep(self,alist) + + def addSecondBone(self): + secondBones = {} + for bone in self.bones.values(): + bone2 = M3GBone() + bone2.verts=bone.verts + bone.verts=[] + mGroup = M3GGroup() + mGroup.name=bone.transformNode.name+"_second" + bone2.transformNode=mGroup + bone2.references = bone.references + bone.references = [] + bone2.weight = bone.weight + bone.weight=0 + mGroup.children = bone.transformNode.children + bone.transformNode.children = [mGroup] + mGroup.animationTracks=bone.transformNode.animationTracks + bone.transformNode.animationTracks = [] + secondBones[bone.transformNode.name+"_second"]=bone2 + for bone in secondBones.values(): + self.bones[bone.transformNode.name] = bone + + def getBlenderIndexes(self): + #print "M3GSkinnedMesh.vertexBuffer:",self.vertexBuffer + return self.vertexBuffer.positions.blenderIndexes + + def writeJava(self,aWriter,aCreate): + self.writeBaseJava(aWriter,aCreate,"SkinnedMesh", + (",BL%i" % (self.skeleton.id))) + aWriter.write(2,"//Transforms") + for bone in self.bones.values(): + #print "bone: ", bone + #print "bone.references: ", bone.references + for ref in bone.references: + aWriter.write(2,"BL%i.addTransform(BL%i,%i,%i,%i);" % + (self.id, + bone.transformNode.id,bone.weight, + ref.firstVertex, ref.vertexCount)) + aWriter.write(2) + + def getDataLength(self): + value = M3GMesh.getDataLength(self) + value += struct.calcsize(' element[i] : minimum[i] = element[i] + if maximum[i] < element[i] : maximum[i] = element[i] + #print i, maximum[i],element[i] + lrange=[0,0,0] + maxRange=0.0 + maxDimension=-1 + for i in range(3): #set bias + lrange[i] = maximum[i]-minimum[i] + self.bias[i] = minimum[i]*0.5+maximum[i]*0.5 + #print "Bias",i,self.bias[i],"min-max",minimum[i],maximum[i],"lrang",lrange[i] + if lrange[i] > maxRange: + maxRange = lrange[i] + maxDimension=i + self.scale = maxRange/65533.0 + #print "MaxRange ",maxRange + #print "scale",self.scale + + + def internalAutoScaling(self): + print "internalAutoScaling" + #Already done? + print self.components.typecode + if not self.autoscaling or self.components.typecode!="f":return + #Find bais and scale + minimum=[] + maximum=[] + for i in range(self.componentCount): + minimum.append(self.components[i]) + maximum.append(self.components[i]) + for i in range(0,len(self.components),self.componentCount): + for j in range(self.componentCount): + if minimum[j] > self.components[i+j] : minimum[j] = self.components[i+j] + if maximum[j] < self.components[i+j] : maximum[j] = self.components[i+j] + #print "i+j=",i+j,"min=",minimum[j],"max=",maximum[j],"elem=",self.components[i+j] + #print "min=", minimum + #print "max=", maximum + lrange=[0] * self.componentCount + maxRange=0.0 + maxDimension=-1 + for i in range(self.componentCount): #set bias + lrange[i] = maximum[i]-minimum[i] + self.bias[i] = minimum[i]*0.5+maximum[i]*0.5 + #print "Bias",i,self.bias[i],"min-max",minimum[i],maximum[i],"lrang",lrange[i] + if lrange[i] > maxRange: + maxRange = lrange[i] + maxDimension=i + maxValue=(2**(8*self.componentSize)*1.0)-2.0 + #print "MaxValue=",maxValue + self.scale = maxRange/maxValue + #print "MaxRange ",maxRange + #print "scale",self.scale + #Copy Components + oldArray=self.components + self.components=self.createComponentArray() + for i in range(0,len(oldArray),self.componentCount): + for j in range(self.componentCount): + element=int((oldArray[i+j]-self.bias[j])/self.scale) + #print "element",element + self.components.append(element) + # Reverse t coordinate because M3G uses a different 2D coordinate system than Blender. + if self.uvmapping: + for i in range(0,len(self.components),2): + self.components[i]= int(self.components[i]*(-1)) + for i in range(len(self.components)): + if abs(self.components[i])>maxValue:raise Exception( i+". element too great/small!") + + def writeJava(self,aWriter,aCreate): + self.internalAutoScaling() + if aCreate: + aWriter.write(2,"// VertexArray " + self.name) + if self.componentSize == 1: + aWriter.write(2,"byte[] BL%i_array = {" % (self.id)) + else: + aWriter.write(2,"short[] BL%i_array = {" % (self.id)) + aWriter.writeList(self.components) + aWriter.write(2,"};") + aWriter.write(2) + aWriter.write(2,"VertexArray BL%i = new VertexArray(BL%i_array.length/%i,%i,%i);" % + (self.id,self.id, + self.componentCount,self.componentCount,self.componentSize)) + aWriter.write(2,"BL%i.set(0,BL%i_array.length/%i,BL%i_array);" % + (self.id,self.id,self.componentCount,self.id)) + M3GObject3D.writeJava(self,aWriter,False) + aWriter.write(2) + + + def getData(self): + self.internalAutoScaling() + self.vertexCount = len(self.components)/self.componentCount + data = M3GObject3D.getData(self) + data += struct.pack('<3BH',self.componentSize, + self.componentCount, + self.encoding, + self.vertexCount) + componentType = "" + if self.componentSize == 1: + componentType = "b" + else: + componentType = "h" + for element in self.components: + data += struct.pack('<'+componentType,element) + return data + + def getDataLength(self): + self.internalAutoScaling() + value = M3GObject3D.getDataLength(self) + value += struct.calcsize('<3BH') + componentType = "" + if self.componentSize == 1: + componentType = "b" + else: + componentType = "h" + value += struct.calcsize('<'+str(len(self.components))+componentType) + return value + + def append(self,element,index=None): + #print "type(element):",type(element) + if type(element) is Types.vectorType : + for i in range(3): + value = int((element[i]-self.bias[i])/self.scale) + #print "append:",i,element[i],(element[i]-self.bias[i]),value + self.components.append(value) + elif type(element) is Types.MVertType: + for i in range(3): + value = int((element.co[i]-self.bias[i])/self.scale) + #print "append:",i,element[i],(element[i]-self.bias[i]),value + self.components.append(value) + if index!=None: + key=str(len(self.blenderIndexes)) + #print"key,index:",key,index + self.blenderIndexes[key]=index + #print"blenderIndexes",self.blenderIndexes + else: + # print "VertexArray.append: element=",element + self.components.append(element) + +class M3GVertexBuffer(M3GObject3D): + def __init__(self): + M3GObject3D.__init__(self) + self.ObjectType=21 + self.defaultColor=M3GColorRGBA(255,255,255) #ColorRGBA 0xFFFFFFFF (opaque white). + self.positions = None #ObjectIndex + self.positionBias = [0.0,0.0,0.0] #Float32[3] + self.positionScale = 1.0 #Float32 + self.normals = None #ObjectIndex + self.colors = None #ObjectIndex + self.texCoordArrays = [] + self.texcoordArrayCount = 0 #UInt32 +## #FOR each texture coordinate array... +## self.texCoords = [] #ObjectIndex +## self.texCoordBias=[] #Float32[3] +## self.texCoordScale=[] #;Float32 +## #END +## #If a texture coordinate array has only two components, the corresponding texCoordBias[2] element +## #must be 0.0. +## #Null texture coordinate arrays are never serialized, regardless of their position. A single texture +## #coordinate array will therefore always be serialized as belonging to texturing unit 0, regardless of +## #its original unit it was assigned to. +## #There are as many references in the texture coordinates array as there are active texture units for +## #this geometry. The texture coordinate references are loaded sequentially from texture unit 0. If the +## #implementation supports more texture units than are specified, these are left in their default, inactive +## #state, with a null texture coordinate reference and an undefined bias and scale. +## #If more texture coordinate references are specified than are supported by the implementation, then +## #this must be treated as an error, as it would be in the API. The application can then decide on an +## #appropriate course of action to handle this case. + + def searchDeep(self,alist): + if self.positions!=None: alist = self.positions.searchDeep(alist) + if self.normals != None: alist = self.normals.searchDeep(alist) + if self.colors!= None: alist = self.colors.searchDeep(alist) + alist = doSearchDeep(self.texCoordArrays, alist) + return M3GObject3D.searchDeep(self,alist) + + def setPositions(self,aVertexArray): + self.positions = aVertexArray + self.positionBias = aVertexArray.bias + self.positionScale = aVertexArray.scale + + def writeJava(self,aWriter,aCreate): + if aCreate: + aWriter.write(2,"//VertexBuffer"+self.name ) + aWriter.write(2,"VertexBuffer BL%i = new VertexBuffer();" % (self.id)) + aWriter.write(2,"float BL%i_Bias[] = { %ff, %ff, %ff};" % + (self.id,self.positionBias[0], + self.positionBias[1],self.positionBias[2])) + aWriter.write(2,"BL%i.setPositions(BL%i,%ff,BL%i_Bias);" % + (self.id, self.positions.id, + self.positionScale,self.id)) + aWriter.write(2,"BL%i.setNormals(BL%i);" % (self.id,self.normals.id)) + #if self.colors != None: aWriter.write(2,"BL%i.setTexCoords(0,BL%i,1.0f,null);" % + # (self.id,self.colors.id)) + lIndex = 0 + for iTexCoord in self.texCoordArrays: + aWriter.write(2,"float BL%i_%i_TexBias[] = { %ff, %ff, %ff};" % + (self.id,lIndex, iTexCoord.bias[0], + iTexCoord.bias[1],iTexCoord.bias[2])) + #int index, javax.microedition.m3g.VertexArray194 texCoords, float scale, float[] bias + aWriter.write(2,"BL%i.setTexCoords(%i,BL%i,%ff,BL%i_%i_TexBias);" % + (self.id, lIndex, iTexCoord.id, iTexCoord.scale,self.id,lIndex)) + lIndex += 1 + + M3GObject3D.writeJava(self,aWriter,False) + + + def getData(self): + self.texcoordArrayCount = len(self.texCoordArrays) + data = M3GObject3D.getData(self) + data += self.defaultColor.getData() + data += struct.pack(' 0 : + value += struct.calcsize('<' + str(len(self.indices)) + 'I') + value += struct.calcsize(' 0: + value+= struct.calcsize('<'+str(len(self.stripLengths))+'I') + return value + + +class M3GAppearance(M3GObject3D): + def __init__(self): + M3GObject3D.__init__(self) + self.ObjectType=3 + self.layer=0 #Byte + self.compositingMode=None #ObjectIndex + self.fog=None #ObjectIndex + self.polygonMode=None #ObjectIndex + self.material=None #ObjectIndex + self.textures=[] #;ObjectIndex[] + + def searchDeep(self,alist): + alist = doSearchDeep([self.compositingMode,self.fog, + self.polygonMode,self.material] + + self.textures,alist) + return M3GObject3D.searchDeep(self,alist) + + def getData(self): + data = M3GObject3D.getData(self) + data += struct.pack(" 0 : + value += struct.calcsize("<"+str(len(self.textures))+'I') + return value + + + def writeJava(self,aWriter,aCreate): + if aCreate: + aWriter.write(2,"//Appearance") + aWriter.write(2,"Appearance BL%i = new Appearance();" % (self.id)) + if self.compositingMode!= None: + aWriter.write(2,"BL%i.setPolygonMode(BL%i);" % + (self.id,self.compositingMode.id)) + if self.fog!=None: + aWriter.write(2,"BL%i.setFog(BL%i);" % + (self.id,self.fog.id)) + if self.polygonMode!=None: + aWriter.write(2,"BL%i.setPolygonMode(BL%i);" % + (self.id,self.polygonMode.id)) + if self.material!=None: + aWriter.write(2,"BL%i.setMaterial(BL%i);" % + (self.id,self.material.id)) + i=0 + for itexture in self.textures: + aWriter.write(2,"BL%i.setTexture(%i,BL%i);" % + (self.id,i,itexture.id)) + i =+ 1 + M3GObject3D.writeJava(self,aWriter,False) + aWriter.write(2) + +class M3GTexture2D(M3GTransformable): + #M3G imposes the following restrictions when assigning textures to a model: + #The dimensions must be powers of two (4, 8, 16, 32, 64, 128...). + + WRAP_REPEAT = 241 + WRAP_CLAMP = 240 + FILTER_BASE_LEVEL=208 + FILTER_LINEAR=209 + FILTER_NEAREST=210 + FUNC_ADD=224 + FUNC_BLEND=225 + FUNC_DECAL=226 + FUNC_MODULATE=227 + FUNC_REPLACE=228 + + def __init__(self,aImage): + M3GTransformable.__init__(self) + self.ObjectType=17 + self.Image = aImage #ObjectIndex + self.blendColor=M3GColorRGB(0,0,0) + self.blending=M3GTexture2D.FUNC_MODULATE #Byte + self.wrappingS=M3GTexture2D.WRAP_REPEAT #Byte + self.wrappingT=M3GTexture2D.WRAP_REPEAT #Byte + self.levelFilter=M3GTexture2D.FILTER_BASE_LEVEL #Byte + self.imageFilter=M3GTexture2D.FILTER_NEAREST #Byte + + def searchDeep(self,alist): + alist = doSearchDeep([self.Image],alist) + return M3GTransformable.searchDeep(self,alist) + + def getData(self): + data = M3GTransformable.getData(self) + data += struct.pack('#AE# + lError = "Armature name " + name + " is not ok. Perhaps you should set option 'ExportAllAction' to false." + #print "name ", name + lLetter = name.find("#") + if lLetter == -1 :raise Exception(lError) + if name[lLetter+1]!='A': raise Exception(lError) + lName = name[lLetter+2:] + #print "lName ", lName + lLetter = lName.find("E") + #print "lLetter ", lLetter + if lLetter == -1 :raise Exception(lError) + #print "lName[:]", lName[:0] + lArmatureID = int(lName[:lLetter]) + lName = lName[lLetter+1:] + lLetter = lName.find("#") + if lLetter == -1:raise Exception(lError) + lEndFrame = int(lName[:lLetter]) + lActionID = int(lName[lLetter+1:]) + return (lArmatureID,lEndFrame,lActionID) + + + def translateWorld(self,scene): + "creates world object" + world = M3GWorld() + + #Background + world.background = M3GBackground() + blWorld= scene.world + #AllWorlds = Blender.World.Get() # Set Color + #if len(AllWorlds)>=1: # world object available + if blWorld != None: + world.background.backgroundColor=self.translateRGBA(blWorld.getHor(),0) # horizon color of the first world + if mOptions.createAmbientLight & mOptions.lightingEnabled: + lLight = M3GLight() + lLight.mode = lLight.modes['AMBIENT'] + lLight.color = self.translateRGB(AllWorlds[0].getAmb()) + self.nodes.append(lLight) + + #TODO: Set background picture from world + + return world + + def translateEmpty(self,obj): + print "translate empty ..." + mGroup = M3GGroup() + self.translateToNode(obj,mGroup) + + def translateCamera(self,obj): + print "translate camera ..." + camera = obj.getData() + if camera.getType()!=0: + print "Only perscpectiv cameras will work korrekt" + return #Type=0 'perspectiv' Camera will be translated + mCamera = M3GCamera() + mCamera.projectionType=mCamera.PERSPECTIVE + mCamera.fovy=60.0 # TODO: Calculate fovy from Blender.lens + mCamera.AspectRatio=4.0/3.0 # TODO: different in every device + mCamera.near=camera.getClipStart() + mCamera.far=camera.getClipEnd() + self.translateToNode(obj,mCamera) + self.world.activeCamera = mCamera # Last one is always the active one + + + def translateMaterials(self, aMaterial, aMesh, aMatIndex, createNormals, createUvs): + print "translate materials ..." + + mAppearance = M3GAppearance() + + if createNormals: + mMaterial = M3GMaterial() + mMaterial.name = aMaterial.name + mMaterial.diffuseColor = self.translateRGBA(aMaterial.rgbCol,1.0) #ColorRGBA + #material.specularColor= self.translateRGB(mat.specCol) #ColorRGB + mAppearance.material = mMaterial + + if createUvs: + # Search file name in mesh face. + lImage = None + for iface in aMesh.faces: + if iface.mat==aMatIndex: + if iface.image != None: + lImage = iface.image + break + if lImage==None: + raise Exception("Mesh " + aMesh.name + ": No image found for uv-texture! Perhaps no uv-coordinates ?") + + # M3G requires textures to have power-of-two dimensions. + [width, height] = lImage.getSize() + powerWidth = 1 + while (powerWidth < width): + powerWidth *= 2 + powerHeight = 1 + while (powerHeight < height): + powerHeight *= 2 + if powerWidth != width or powerHeight != height: + raise Exception("Image " + lImage.filename + ": width and height must be power-of-two!") + + # ImageFactory reuses existing images. + mImage = ImageFactory.getImage(lImage, mOptions.textureExternal) + mTexture = M3GTexture2D(mImage) + mAppearance.textures.append(mTexture) + + mPolygonMode=M3GPolygonMode() + mPolygonMode.perspectiveCorrectionEnabled = mOptions.perspectiveCorrection + if not aMesh.mode & Modes.TWOSIDED: + mPolygonMode.culling=M3GPolygonMode.CULL_BACK + else: + mPolygonMode.culling=M3GPolygonMode.CULL_NONE + if mOptions.smoothShading: + mPolygonMode.shading=M3GPolygonMode.SHADE_SMOOTH + else: + mPolygonMode.shading=M3GPolygonMode.SHADE_FLAT + + mAppearance.polygonMode = mPolygonMode + + return mAppearance + + + def translateMesh(self,obj): + print "translate mesh ..." + str(obj) + + # Mesh data. + mesh = obj.getData(False, True) # get Mesh not NMesh object + if len(mesh.faces) <= 0: # no need to process empty meshes + print "Empty mesh " + str(obj) + " not processed." + return + + vertexBuffer = M3GVertexBuffer() + positions = M3GVertexArray(3, 2) # 3 coordinates - 2 bytes + if mOptions.autoscaling: positions.useMaxPrecision(mesh.verts) + indexBuffers = [] + appearances = [] + print str(len(mesh.materials)) + " material(s) found." + + # Texture coordinates. + createUvs = False + if mOptions.textureEnabled & mesh.faceUV: + for material in mesh.materials: + if material.getMode() & Material.Modes.TEXFACE: createUvs = True; + + if createUvs: + if mOptions.autoscaling: + uvCoordinates = M3GVertexArray(2,2,True,True) #2 coordinates - 2 bytes - autoscaling + else: + uvCoordinates = M3GVertexArray(2, 2) #2 coordinates - 2 bytes + uvCoordinates.bias[0] = 0.5 + uvCoordinates.bias[1] = 0.5 + uvCoordinates.bias[2] = 0.5 + uvCoordinates.scale = 1.0/65535.0 + else: + uvCoordinates = None + + # Normals. + createNormals = False + if mOptions.lightingEnabled: + for material in mesh.materials: + if not (material.getMode() & Material.Modes.SHADELESS): createNormals = True; + + if createNormals: + normals = M3GVertexArray(3, 1) # 3 coordinates - 1 byte + else: + normals = None + + # Create a submesh for each material. + for materialIndex, material in enumerate(mesh.materials): + faces = [face for face in mesh.faces if face.mat == materialIndex] + if len(faces) >= 0: + indexBuffers.append(self.translateFaces(faces, positions, normals, uvCoordinates, createNormals, createUvs)) + appearances.append(self.translateMaterials(material, mesh, materialIndex, createNormals, createUvs)) + + # If the above didn't result in any IndexBuffer (e.g. there's no material), write a single IndexBuffer + # with all faces and a default Appearance. + if len(indexBuffers) == 0: + indexBuffers.append(self.translateFaces(mesh.faces, positions, normals, uvCoordinates, createNormals, createUvs)) + appearances.append(M3GAppearance()) + + vertexBuffer.setPositions(positions) + if createNormals: vertexBuffer.normals = normals + if createUvs: vertexBuffer.texCoordArrays.append(uvCoordinates) + + parent = obj.getParent() + if parent!=None and parent.getType()=='Armature': #Armatures ? + mMesh = M3GSkinnedMesh(vertexBuffer,indexBuffers,appearances) + #print"vertexBuffer.positions:",vertexBuffer.positions + print"mMesh.vertexBuffer:",mMesh.vertexBuffer + self.translateArmature(parent,obj,mMesh) + else: + mMesh = M3GMesh(vertexBuffer,indexBuffers,appearances) + + self.translateToNode(obj,mMesh) + + #Do Animation + self.translateObjectIpo(obj,mMesh) + + def translateFaces(self, faces, positions, normals, uvCoordinates, createNormals, createUvs): + """Translates a list of faces into vertex data and triangle strips.""" + + # Create vertices and triangle strips. + indices = [0, 0, 0, 0] + triangleStrips = M3GTriangleStripArray() + + for face in faces: + for vertexIndex, vertex in enumerate(face.verts): + # Find candidates for sharing (vertices with same Blender ID). + vertexCandidateIds = [int(k) for k, v in positions.blenderIndexes.items() if v == vertex.index] + + # Check normal. + if createNormals and not face.smooth: + # For solid faces, a vertex can only be shared if the the face normal is + # the same as the normal of the shared vertex. + for candidateId in vertexCandidateIds[:]: + for j in range(3): + if face.no[j]*127 != normals.components[candidateId*3 + j]: + vertexCandidateIds.remove(candidateId) + break + + # Check texture coordinates. + if createUvs: + # If texture coordinates are required, a vertex can only be shared if the + # texture coordinates match. + for candidateId in vertexCandidateIds[:]: + s = int((face.uv[vertexIndex][0]-0.5)*65535) + t = int((0.5-face.uv[vertexIndex][1])*65535) + if (s != uvCoordinates.components[candidateId*2 + 0]) or (t != uvCoordinates.components[candidateId*2 + 1]): + vertexCandidateIds.remove(candidateId) + + if len(vertexCandidateIds) > 0: + # Share the vertex. + indices[vertexIndex] = vertexCandidateIds[0] + else: + # Create new vertex. + positions.append(vertex, vertex.index) + indices[vertexIndex] = len(positions.components)/3 - 1 + + # Normal. + if createNormals: + for j in range(3): + if face.smooth: + normals.append(int(vertex.no[j]*127)) # vertex normal + else: + normals.append(int(face.no[j]*127)) # face normal + + # Texture coordinates. + if createUvs: + lUvCoordinatesFound = True + print "face.uv[vertexIndex][0]:",face.uv[vertexIndex][0] + print "face.uv[vertexIndex][1]:",face.uv[vertexIndex][1] + if mOptions.autoscaling: + uvCoordinates.append(face.uv[vertexIndex][0]) + uvCoordinates.append(face.uv[vertexIndex][1]) + else: + uvCoordinates.append(int((face.uv[vertexIndex][0]-0.5)*65535)) + # Reverse t coordinate because M3G uses a different 2D coordinate system than Blender. + uvCoordinates.append(int((0.5-face.uv[vertexIndex][1])*65535)) + + # IndexBuffer. + triangleStrips.stripLengths.append(len(face.verts)) + if len(face.verts) > 3 : + triangleStrips.indices += [indices[1], indices[2], indices[0], indices[3]] # quad + else : + triangleStrips.indices += [indices[0], indices[1], indices[2]] # tri + + return triangleStrips + + + def translateObjectIpo(self,obj,aM3GObject): + if obj.getIpo() == None : return #No Ipo available + print "translate Ipo ..." + + lIpo = obj.getIpo() + self.translateIpo(lIpo,aM3GObject) + + + def translateIpo(self,aIpo,aM3GObject,aM3GAnimContr=None,aEndFrame=0): + #Print info about curves + #for iCurve in lIpo.getCurves(): + # print "Extrapolation",iCurve.getExtrapolation() #Constant, Extrapolation, Cyclic or Cyclic_extrapolation + # print "Interpolation",iCurve.getInterpolation() #Constant, Bezier, or Linear + # print "Name",iCurve.getName() + # for iPoint in iCurve.getPoints(): + # print "Knode points",iPoint.getPoints() + types = ['Loc','Rot','Size','Quat'] + + for type in types: + if aIpo.getCurve(type+'X'): + self.translateIpoCurve(aIpo,aM3GObject,type,aM3GAnimContr,aEndFrame) + + + def translateIpoCurve(self,aIpo,aM3GObject,aCurveType,aM3GAnimContr,aEndFrame=0): + + lContext = self.scene.getRenderingContext() + if aEndFrame==0: + lEndFrame = lContext.endFrame() + else: + lEndFrame = aEndFrame + + lTimePerFrame = 1.0 / lContext.framesPerSec() * 1000 + + lCurveX = aIpo.getCurve(aCurveType+'X') + lCurveY = aIpo.getCurve(aCurveType+'Y') + lCurveZ = aIpo.getCurve(aCurveType+'Z') + if aCurveType=='Quat': lCurveW = aIpo.getCurve(aCurveType+'W') + + lInterpolation = None + if aCurveType == 'Rot' or aCurveType == 'Quat': + lTrackType = M3GAnimationTrack.ORIENTATION + lNumComponents=4 + lCurveFactor= 10 #45 Degrees = 4,5 + if aCurveType == 'Quat': + lTrackType = M3GAnimationTrack.ORIENTATION + lNumComponents=4 + lCurveFactor= 1 + lInterpolation = M3GKeyframeSequence.SLERP + #lInterpolation = M3GKeyframeSequence.SQUAD + elif aCurveType == 'Size': + lTrackType = M3GAnimationTrack.SCALE + lNumComponents=3 + lCurveFactor=1 + else: + lTrackType = M3GAnimationTrack.TRANSLATION + lNumComponents=3 + lCurveFactor=1 + + mSequence = M3GKeyframeSequence(len(lCurveX.getPoints()), + lNumComponents, + lCurveX.getInterpolation(), + lInterpolation) + + #print 'ComponentCount',mSequence.componentCount + + mSequence.duration = lEndFrame * lTimePerFrame + mSequence.setRepeatMode(lCurveX.getExtrapolation()) + + lIndex = 0 + for iPoint in lCurveX.getPoints(): + lPoint = iPoint.getPoints() + + lPointList = [(lPoint[1]*lCurveFactor), + (lCurveY.evaluate(lPoint[0])*lCurveFactor), + (lCurveZ.evaluate(lPoint[0])*lCurveFactor)] + + #print "aCurveType ", aCurveType + + if aCurveType == 'Loc': + #print "PointList ", lPointList + #lorgTransVector = aM3GObject.blenderTransformMatrix.translationPart() + #ltrans = TranslationMatrix(Vector(lPointList)) + #ltrans2 = self.calculateChildMatrix(ltrans,aM3GObject.blenderTransformMatrix) + #lVector = ltrans2.translationPart() + lorgTransVector + #lPointList = [lVector.x, lVector.y,lVector.z] + #print "PointList ", lPointList + pass + + if aCurveType == 'Quat': + lPointList.append(lCurveW.evaluate(lPoint[0])*lCurveFactor) + #lQuat = Quaternion([lPointList[3],lPointList[0],lPointList[1],lPointList[2]]) + #print "Quat ", lQuat + #print "Quat.angel ", lQuat.angle + #print "Quat.axis ", lQuat.axis + #print "PointList ", lPointList + + #print "PointList",lPointList + + if aCurveType =='Rot': + lQuat = Euler(lPointList).toQuat() + #lPointList = [lQuat.w,lQuat.x,lQuat.y,lQuat.z] + lPointList = [lQuat.x,lQuat.y,lQuat.z,lQuat.w] + #print " Quat=", lPointList + + mSequence.setKeyframe(lIndex, + lPoint[0]*lTimePerFrame, + lPointList) + lIndex += 1 + mSequence.validRangeFirst = 0 + mSequence.validRangeLast = lIndex - 1 + + mTrack = M3GAnimationTrack(mSequence,lTrackType) + aM3GObject.animationTracks.append(mTrack) + if aM3GAnimContr==None: aM3GAnimContr = M3GAnimationController() + mTrack.animationController = aM3GAnimContr + + + def translateLamp(self,obj): + print "translate lamp ..." + lamp = obj.getData() + + #Type + lampType=lamp.getType() + if not lampType in [Lamp.Types.Lamp,Lamp.Types.Spot,Lamp.Types.Sun]: + print "INFO: Type of light is not supported. See documentation" + return #create not light; type not supported + mLight = M3GLight() + if lampType == Lamp.Types.Lamp: + mLight.mode = mLight.modes['OMNI'] + elif lampType == Lamp.Types.Spot: + mLight.mode = mLight.modes['SPOT'] + elif lampType == Lamp.Types.Sun: + mLight.mode = mLight.modes['DIRECTIONAL'] + #Attenuation (OMNI,SPOT): + if lampType in [Lamp.Types.Lamp,Lamp.Types.Spot]: + mLight.attenuationConstant = 0.0 + mLight.attenuationLinear = 2.0/lamp.dist + mLight.attenuationQuadratic = 0.0 + #Color + mLight.color = self.translateRGB(lamp.col) + #Energy + mLight.intensity = lamp.energy + #SpotAngle, SpotExponent (SPOT) + if lampType == Lamp.Types.Spot: + mLight.spotAngle = lamp.spotSize + mLight.spotExponent = lamp.spotBlend + self.translateToNode(obj,mLight) + + + def translateCore(self,obj,node): + #Name + node.name = obj.name + node.userID = self.translateUserID(obj.name) + #Location + #node.translation=self.translateLoc(obj.LocX,obj.LocY,obj.LocZ + #node.hasComponentTransform=True + #Transform + #node.transform = self.translateMatrix(obj.getMatrix('localspace')) + if type(obj) is Types.BoneType: + #print "BoneMatrix ",obj.matrix['BONESPACE'] + node.transform = self.translateMatrix(obj.matrix['ARMATURESPACE']) + #'ARMATURESPACE' - this matrix of the bone in relation to the armature + #'BONESPACE' - the matrix of the bone in relation to itself + else: + node.transform = self.translateMatrix(obj.matrixWorld) + node.hasGeneralTransform=True + + + def translateToNode(self,obj,node): + self.translateCore(obj,node) + #Nodes + self.nodes.append(node) + #Link to Blender Object + node.blenderObj = obj + node.blenderMatrixWorld = obj.matrixWorld + lparent = None + if obj.getParent()!=None: + if obj.getParent().getType()!='Armature': + lparent = obj.getParent() + else: + if obj.getParent().getParent()!=None and obj.getParent().getParent().getType()!='Armature': + lparent = obj.getParent().getParent() + node.parentBlenderObj = lparent + + + def translateUserID(self, name): + id = 0 + start = name.find('#') + + # Use digits that follow the # sign for id. + if start != -1: + start += 1 + end = start + for char in name[start:]: + if char.isdigit(): + end += 1 + else: + break + + if end > start: + id = int(name[start:end]) + + return id + + def translateLoc(self,aLocX,aLocY,aLocZ): + return M3GVector3D(aLocX,aLocY,aLocZ) + + def translateRGB(self,color): + return M3GColorRGB(int(color[0]*255), + int(color[1]*255), + int(color[2]*255)) + + def translateRGBA(self,color,alpha): + return M3GColorRGBA(int(color[0]*255), + int(color[1]*255), + int(color[2]*255), + int(alpha*255)) + + def translateMatrix(self,aPyMatrix): + """ +  0   1   2   3  + 4   5   6   7  + 8   9  10  11 + 12  13  14  15 """ + #print "Matrix:", aPyMatrix + lMatrix = M3GMatrix() + lMatrix.elements[0] = aPyMatrix[0][0] + lMatrix.elements[1] = aPyMatrix[1][0] + lMatrix.elements[2] = aPyMatrix[2][0] + lMatrix.elements[3] = aPyMatrix[3][0] + lMatrix.elements[4] = aPyMatrix[0][1] + lMatrix.elements[5] = aPyMatrix[1][1] + lMatrix.elements[6] = aPyMatrix[2][1] + lMatrix.elements[7] = aPyMatrix[3][1] + lMatrix.elements[8] = aPyMatrix[0][2] + lMatrix.elements[9] = aPyMatrix[1][2] + lMatrix.elements[10] = aPyMatrix[2][2] + lMatrix.elements[11] = aPyMatrix[3][2] + lMatrix.elements[12] = aPyMatrix[0][3] + lMatrix.elements[13] = aPyMatrix[1][3] + lMatrix.elements[14] = aPyMatrix[2][3] + lMatrix.elements[15] = aPyMatrix[3][3] + return lMatrix + + +# ---- Exporter ---------------------------------------------------------------- # + +class M3GExporter: + "Exports Blender-Scene to M3D" + def __init__(self, aWriter): + self.writer = aWriter + + + def start(self): + print "Info: starting export ..." + #rpdb2.start_embedded_debugger("t",True) + Translator = M3GTranslator() + world = Translator.start() + + #sys.settrace(tracer) + exportList = self.createDeepSearchList(world) + externalReferences = [element for element in exportList if element.__class__ is M3GExternalReference] + exportList = [element for element in exportList if element.__class__ is not M3GExternalReference] + #sys.settrace(None) + + # 1 is reservated for HeaderObject. + i=1 + + # Next are the external references. + for element in externalReferences: + i += 1 + element.id = i + print "object ",element.id, element + + # And the standard scene objects. + for element in exportList: + i += 1 + element.id = i + print "object ",element.id, element + + self.writer.writeFile(world, exportList, externalReferences) + + print("Ready!") + + + def createDeepSearchList(self,aWorld): + "creates the right order for saving m3g : leafs first" + return aWorld.searchDeep([]) + + + +# ---- Writer ---------------------------------------------------------------- # +class JavaWriter: + "writes a java class which creates m3g-Scene in a j2me programm" + def __init__(self,aFilename): + self.filename = aFilename + self.classname = Blender.sys.basename(aFilename) + self.classname = self.classname[:-5] #without extention ".java" + self.outFile = file(aFilename,"w") + + def write(self, tab, zeile=""): + "writes to file" + #print "\t" * tab + zeile + print >>self.outFile, "\t" * tab + zeile + + def writeFile(self,aWorld,aExportList,externalReferences): + self.world = aWorld + self.writeHeader() + for element in aExportList: + element.writeJava(self,True) + self.writeFooter() + self.outFile.close() + + def writeHeader(self): + "writes class header" + self.write(0,"import javax.microedition.lcdui.Image;") + self.write(0,"import javax.microedition.m3g.*;") + self.write(0,"public final class "+self.classname+" {") + self.write(1,"public static World getRoot(Canvas3D aCanvas) {") + + def writeFooter(self): + self.write(1) + self.write(1,"return BL"+str(self.world.id)+";") + self.write(0,"}}") + + def writeList(self,alist,numberOfElementsPerLine=12,aType=""): + '''Writes numberOfElementsPerLine''' + line="" + lastLine="" + counter=0 + for element in alist: + if counter!=0: + line = line + "," + str(element) + aType + else: + line = str(element) + aType + counter = counter + 1 + if counter == numberOfElementsPerLine: + if len(lastLine)>0: + self.write(3,lastLine+",") + lastLine=line + line="" + counter = 0 + if len(lastLine)>0: + if len(line)>0: + self.write(3,lastLine+",") + else: + self.write(3,lastLine) + if len(line) > 0: self.write(3,line) + + def writeClass(self,aName,aM3GObject): + self.write(2) + self.write(2,"//"+aName+":"+aM3GObject.name) + + +class M3GSectionObject: + def __init__(self,aObject): + """Object Structure + Each object in the file represents one object in the + scene graph tree, and is stored in a chunk. The + structure of an object chunk is as follows: + Byte ObjectType + UInt32 Length + Byte[] Data""" + #ObjectType + #This field describes what type of object has been serialized. + #The values 0 and 0xFF are special: 0 represents the header object, + #and 0xFF represents an external reference. + #Example: Byte ObjectType = 14 + self.ObjectType = aObject.ObjectType + self.data = aObject.getData() + self.length = aObject.getDataLength() + + def getData(self): + data = struct.pack(' 2,1,0 + for v in f.v[2::-1]: + file.write(format_vec % tuple(v.co) ) + + try: mode= f.mode + except: mode= 0 + + if mode & Mesh.FaceModes.INVISIBLE: + file.write(PREF_INVIS_TEX.val) + else: + try: image= f.image + except: image= None + + if image: file.write(sys.splitext(sys.basename(image.filename))[0]) + else: file.write(PREF_NULL_TEX.val) + + # Texture stuff ignored for now + file.write(PREF_DEF_TEX_OPTS.val) + file.write('}\n') + + +def round_vec(v): + if PREF_GRID_SNAP.val: + return round(v.x), round(v.y), round(v.z) + else: + return tuple(v) + +def write_face2brush(file, face): + ''' + takes a face and writes it as a brush + each face is a cube/brush + ''' + + if PREF_GRID_SNAP.val: format_vec= '( %d %d %d ) ' + else: format_vec= '( %.8f %.8f %.8f ) ' + + + image_text= PREF_NULL_TEX.val + + try: mode= face.mode + except: mode= 0 + + if mode & Mesh.FaceModes.INVISIBLE: + image_text= PREF_INVIS_TEX.val + else: + try: image= face.image + except: image= None + if image: image_text = sys.splitext(sys.basename(image.filename))[0] + + # original verts as tuples for writing + orig_vco= [tuple(v.co) for v in face] + + # new verts that give the face a thickness + dist= PREF_SCALE.val * PREF_FACE_THICK.val + new_vco= [round_vec(v.co - (v.no * dist)) for v in face] + #new_vco= [round_vec(v.co - (face.no * dist)) for v in face] + + file.write('// brush from face\n{\n') + # front + for co in orig_vco[2::-1]: + file.write(format_vec % co ) + file.write(image_text) + # Texture stuff ignored for now + file.write(PREF_DEF_TEX_OPTS.val) + + + for co in new_vco[:3]: + file.write(format_vec % co ) + if mode & Mesh.FaceModes.TWOSIDE: + file.write(image_text) + else: + file.write(PREF_INVIS_TEX.val) + + # Texture stuff ignored for now + file.write(PREF_DEF_TEX_OPTS.val) + + # sides. + if len(orig_vco)==3: # Tri, it seemms tri brushes are supported. + index_pairs= ((0,1), (1,2), (2,0)) + else: + index_pairs= ((0,1), (1,2), (2,3), (3,0)) + + for i1, i2 in index_pairs: + for co in orig_vco[i1], orig_vco[i2], new_vco[i2]: + file.write( format_vec % co ) + file.write(PREF_INVIS_TEX.val) + file.write(PREF_DEF_TEX_OPTS.val) + + file.write('}\n') + +def is_cube_facegroup(faces): + ''' + Returens a bool, true if the faces make up a cube + ''' + # cube must have 6 faces + if len(faces) != 6: + print '1' + return False + + # Check for quads and that there are 6 unique verts + verts= {} + for f in faces: + if len(f)!= 4: + return False + + for v in f: + verts[v.index]= 0 + + if len(verts) != 8: + return False + + # Now check that each vert has 3 face users + for f in faces: + for v in f: + verts[v.index] += 1 + + for v in verts.itervalues(): + if v != 3: # vert has 3 users? + return False + + # Could we check for 12 unique edges??, probably not needed. + return True + +def is_tricyl_facegroup(faces): + ''' + is the face group a tri cylinder + Returens a bool, true if the faces make an extruded tri solid + ''' + return False + # cube must have 5 faces + if len(faces) != 5: + print '1' + return False + + # Check for quads and that there are 6 unique verts + verts= {} + tottri= 0 + for f in faces: + if len(f)== 3: + tottri+=1 + + for v in f: + verts[v.index]= 0 + + if len(verts) != 6 or tottri != 2: + return False + + # Now check that each vert has 3 face users + for f in faces: + for v in f: + verts[v.index] += 1 + + for v in verts.itervalues(): + if v != 3: # vert has 3 users? + return False + + # Could we check for 12 unique edges??, probably not needed. + return True + +def write_node_map(file, ob): + ''' + Writes the properties of an object (empty in this case) + as a MAP node as long as it has the property name - classname + returns True/False based on weather a node was written + ''' + props= [(p.name, p.data) for p in ob.properties] + + IS_MAP_NODE= False + for name, value in props: + if name=='classname': + IS_MAP_NODE= True + break + + if not IS_MAP_NODE: + return False + + # Write a node + file.write('{\n') + for name_value in props: + file.write('"%s" "%s"\n' % name_value) + file.write('}\n') + return True + + +def export_map(filepath): + + pup_block = [\ + ('Scale:', PREF_SCALE, 1, 1000, 'Scale the blender scene by this value.'),\ + ('Face Width:', PREF_FACE_THICK, 0.01, 10, 'Thickness of faces exported as brushes.'),\ + ('Grid Snap', PREF_GRID_SNAP, 'snaps floating point values to whole numbers.'),\ + 'Null Texture',\ + ('', PREF_NULL_TEX, 1, 128, 'Export textureless faces with this texture'),\ + 'Unseen Texture',\ + ('', PREF_INVIS_TEX, 1, 128, 'Export invisible faces with this texture'),\ + ] + + if not Draw.PupBlock('map export', pup_block): + return + + Window.WaitCursor(1) + time= sys.time() + print 'Map Exporter 0.0' + file= open(filepath, 'w') + + + obs_mesh= [] + obs_lamp= [] + obs_surf= [] + obs_empty= [] + + SCALE_MAT= Mathutils.Matrix() + SCALE_MAT[0][0]= SCALE_MAT[1][1]= SCALE_MAT[2][2]= PREF_SCALE.val + + dummy_mesh= Mesh.New() + + TOTBRUSH= TOTLAMP= TOTNODE= 0 + + for ob in Object.GetSelected(): + type= ob.getType() + if type == 'Mesh': obs_mesh.append(ob) + elif type == 'Surf': obs_surf.append(ob) + elif type == 'Lamp': obs_lamp.append(ob) + elif type == 'Empty': obs_empty.append(ob) + + if obs_mesh or obs_surf: + # brushes and surf's must be under worldspan + file.write('\n// entity 0\n') + file.write('{\n') + file.write('"classname" "worldspawn"\n') + + + print '\twriting cubes from meshes' + for ob in obs_mesh: + dummy_mesh.getFromObject(ob.name) + + #print len(mesh_split2connected(dummy_mesh)) + + # Is the object 1 cube? - object-is-a-brush + dummy_mesh.transform(ob.matrixWorld*SCALE_MAT) # 1 to tx the normals also + + if PREF_GRID_SNAP.val: + for v in dummy_mesh.verts: + co= v.co + co.x= round(co.x) + co.y= round(co.y) + co.z= round(co.z) + + # High quality normals + BPyMesh.meshCalcNormals(dummy_mesh) + + # Split mesh into connected regions + for face_group in BPyMesh.mesh2linkedFaces(dummy_mesh): + if is_cube_facegroup(face_group): + write_cube2brush(file, face_group) + TOTBRUSH+=1 + elif is_tricyl_facegroup(face_group): + write_cube2brush(file, face_group) + TOTBRUSH+=1 + else: + for f in face_group: + write_face2brush(file, f) + TOTBRUSH+=1 + + #print 'warning, not exporting "%s" it is not a cube' % ob.name + + + dummy_mesh.verts= None + + + valid_dims= 3,5,7,9,11,13,15 + for ob in obs_surf: + ''' + Surf, patches + ''' + surf_name= ob.getData(name_only=1) + data= Curve.Get(surf_name) + mat = ob.matrixWorld*SCALE_MAT + + # This is what a valid patch looks like + + """ +// brush 0 +{ +patchDef2 +{ +NULL +( 3 3 0 0 0 ) +( +( ( -64 -64 0 0 0 ) ( -64 0 0 0 -2 ) ( -64 64 0 0 -4 ) ) +( ( 0 -64 0 2 0 ) ( 0 0 0 2 -2 ) ( 0 64 0 2 -4 ) ) +( ( 64 -64 0 4 0 ) ( 64 0 0 4 -2 ) ( 80 88 0 4 -4 ) ) +) +} +} + """ + for i, nurb in enumerate(data): + u= nurb.pointsU + v= nurb.pointsV + if u in valid_dims and v in valid_dims: + + file.write('// brush %d surf_name\n' % i) + file.write('{\n') + file.write('patchDef2\n') + file.write('{\n') + file.write('NULL\n') + file.write('( %d %d 0 0 0 )\n' % (u, v) ) + file.write('(\n') + + u_iter = 0 + for p in nurb: + + if u_iter == 0: + file.write('(') + + u_iter += 1 + + # add nmapping 0 0 ? + if PREF_GRID_SNAP.val: + file.write(' ( %d %d %d 0 0 )' % round_vec(Mathutils.Vector(p[0:3]) * mat)) + else: + file.write(' ( %.6f %.6f %.6f 0 0 )' % tuple(Mathutils.Vector(p[0:3]) * mat)) + + # Move to next line + if u_iter == u: + file.write(' )\n') + u_iter = 0 + + file.write(')\n') + file.write('}\n') + file.write('}\n') + + + # Debugging + # for p in nurb: print 'patch', p + + else: + print "NOT EXPORTING PATCH", surf_name, u,v, 'Unsupported' + + + file.write('}\n') # end worldspan + + + print '\twriting lamps' + for ob in obs_lamp: + print '\t\t%s' % ob.name + lamp= ob.data + file.write('{\n') + file.write('"classname" "light"\n') + file.write('"light" "%.6f"\n' % (lamp.dist* PREF_SCALE.val)) + if PREF_GRID_SNAP.val: + file.write('"origin" "%d %d %d"\n' % tuple([round(axis*PREF_SCALE.val) for axis in ob.getLocation('worldspace')]) ) + else: + file.write('"origin" "%.6f %.6f %.6f"\n' % tuple([axis*PREF_SCALE.val for axis in ob.getLocation('worldspace')]) ) + file.write('"_color" "%.6f %.6f %.6f"\n' % tuple(lamp.col)) + file.write('"style" "0"\n') + file.write('}\n') + TOTLAMP+=1 + + + print '\twriting empty objects as nodes' + for ob in obs_empty: + if write_node_map(file, ob): + print '\t\t%s' % ob.name + TOTNODE+=1 + else: + print '\t\tignoring %s' % ob.name + + Window.WaitCursor(0) + + print 'Exported Map in %.4fsec' % (sys.time()-time) + print 'Brushes: %d Nodes: %d Lamps %d\n' % (TOTBRUSH, TOTNODE, TOTLAMP) + + +def main(): + Window.FileSelector(export_map, 'EXPORT MAP', '*.map') + +if __name__ == '__main__': main() +# export_map('/foo.map') \ No newline at end of file diff --git a/release/scripts/export_mdd.py b/release/scripts/export_mdd.py new file mode 100644 index 00000000000..42a85029505 --- /dev/null +++ b/release/scripts/export_mdd.py @@ -0,0 +1,153 @@ +#!BPY + +""" + Name: 'Vertex Keyframe Animation (.mdd)...' + Blender: 242 + Group: 'Export' + Tooltip: 'Animated mesh to MDD vertex keyframe file.' +""" + +__author__ = "Bill L.Nieuwendorp" +__bpydoc__ = """\ +This script Exports Lightwaves MotionDesigner format. + +The .mdd format has become quite a popular Pipeline format
+for moving animations from package to package. + +Be sure not to use modifiers that change the number or order of verts in the mesh +""" +#Please send any fixes,updates,bugs to Slow67_at_Gmail.com or cbarton_at_metavr.com +#Bill Niewuendorp +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** + +import bpy +import Blender +from Blender import * +import BPyMessages +try: + from struct import pack +except: + pack = None + + +def zero_file(filepath): + ''' + If a file fails, this replaces it with 1 char, better not remove it? + ''' + file = open(filepath, 'w') + file.write('\n') # aparently macosx needs some data in a blank file? + file.close() + +def mdd_export(filepath, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS): + + Window.EditMode(0) + Blender.Window.WaitCursor(1) + mesh_orig = ob.getData(mesh=1) + + #Flip y and z + ''' + mat = Mathutils.Matrix() + mat[2][2] = -1 + rotmat = Mathutils.RotationMatrix(90, 4, 'x') + mat_flip = mat*rotmat + ''' + # Above results in this matrix + mat_flip= Mathutils.Matrix(\ + [1.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, 1.0],\ + ) + + me_tmp = Mesh.New() # container mesh + + numverts = len(mesh_orig.verts) + numframes = PREF_ENDFRAME-PREF_STARTFRAME+1 + PREF_FPS= float(PREF_FPS) + f = open(filepath, 'wb') #no Errors yet:Safe to create file + + # Write the header + f.write(pack(">2i", numframes-1, numverts)) + + # Write the frame times (should we use the time IPO??) + f.write( pack(">%df" % (numframes-1), *[frame/PREF_FPS for frame in xrange(numframes-1)]) ) # seconds + + Blender.Set('curframe', PREF_STARTFRAME) + for frame in xrange(PREF_STARTFRAME,PREF_ENDFRAME+1):#in order to start at desired frame + Blender.Set('curframe', frame) + # Blender.Window.RedrawAll() # not needed + me_tmp.getFromObject(ob.name) + + if len(me_tmp.verts) != numverts: + Blender.Draw.PupMenu('Error%t|Number of verts has changed during animation|cannot export') + Blender.Window.WaitCursor(0) + f.close() # should we zero? + zero_file(filepath) + return + + me_tmp.transform(ob.matrixWorld * mat_flip) + + # Write the vertex data + f.write(pack(">%df" % (numverts*3), *[axis for v in me_tmp.verts for axis in v.co])) + + me_tmp.verts= None + f.close() + + print'MDD Exported: %s frames:%d\n'% (filepath, numframes-1) + Blender.Window.WaitCursor(0) + + +def mdd_export_ui(filepath): + # Dont overwrite + if not BPyMessages.Warning_SaveOver(filepath): + return + + scn= bpy.data.scenes.active + ob_act= scn.objects.active + if not ob_act or ob_act.type != 'Mesh': + BPyMessages.Error_NoMeshActive() + + ctx = scn.getRenderingContext() + orig_frame = Blender.Get('curframe') + PREF_STARTFRAME= Blender.Draw.Create(int(ctx.startFrame())) + PREF_ENDFRAME= Blender.Draw.Create(int(ctx.endFrame())) + PREF_FPS= Blender.Draw.Create(ctx.fps) + + block = [\ + ("Start Frame: ", PREF_STARTFRAME, 1, 30000, "Start Bake from what frame?: Default 1"),\ + ("End Frame: ", PREF_ENDFRAME, 1, 30000, "End Bake on what Frame?"),\ + ("FPS: ", PREF_FPS, 1, 100, "Frames per second")\ + ] + + if not Blender.Draw.PupBlock("Export MDD", block): + return + + PREF_STARTFRAME, PREF_ENDFRAME=\ + min(PREF_STARTFRAME.val, PREF_ENDFRAME.val),\ + max(PREF_STARTFRAME.val, PREF_ENDFRAME.val) + + print (filepath, ob_act, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS.val) + mdd_export(filepath, ob_act, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS.val) + Blender.Set('curframe', orig_frame) + +if __name__=='__main__': + if not pack: + Draw.PupMenu('Error%t|This script requires a full python install') + + Blender.Window.FileSelector(mdd_export_ui, 'EXPORT MDD', sys.makename(ext='.mdd')) diff --git a/release/scripts/export_obj.py b/release/scripts/export_obj.py new file mode 100644 index 00000000000..101a1ab1e84 --- /dev/null +++ b/release/scripts/export_obj.py @@ -0,0 +1,649 @@ +#!BPY + +""" +Name: 'Wavefront (.obj)...' +Blender: 243 +Group: 'Export' +Tooltip: 'Save a Wavefront OBJ File' +""" + +__author__ = "Campbell Barton, Jiri Hnidek" +__url__ = ['www.blender.org', 'blenderartists.org'] +__version__ = "1.1" + +__bpydoc__ = """\ +This script is an exporter to OBJ file format. + +Usage: + +Select the objects you wish to export and run this script from "File->Export" menu. +Selecting the default options from the popup box will be good in most cases. +All objects that can be represented as a mesh (mesh, curve, metaball, surface, text3d) +will be exported as mesh data. +""" + + +# -------------------------------------------------------------------------- +# OBJ Export v1.1 by Campbell Barton (AKA Ideasman) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +import Blender +from Blender import Mesh, Scene, Window, sys, Image, Draw +import BPyMesh +import BPyObject +import BPySys +import BPyMessages + +# Returns a tuple - path,extension. +# 'hello.obj' > ('hello', '.obj') +def splitExt(path): + dotidx = path.rfind('.') + if dotidx == -1: + return path, '' + else: + return path[:dotidx], path[dotidx:] + +def fixName(name): + if name == None: + return 'None' + else: + return name.replace(' ', '_') + +# A Dict of Materials +# (material.name, image.name):matname_imagename # matname_imagename has gaps removed. +MTL_DICT = {} + +def write_mtl(filename): + + world = Blender.World.GetCurrent() + if world: + worldAmb = world.getAmb() + else: + worldAmb = (0,0,0) # Default value + + file = open(filename, "w") + file.write('# Blender3D MTL File: %s\n' % Blender.Get('filename').split('\\')[-1].split('/')[-1]) + file.write('# Material Count: %i\n' % len(MTL_DICT)) + # Write material/image combinations we have used. + for key, (mtl_mat_name, mat, img) in MTL_DICT.iteritems(): + + # Get the Blender data for the material and the image. + # Having an image named None will make a bug, dont do it :) + + file.write('newmtl %s\n' % mtl_mat_name) # Define a new material: matname_imgname + + if mat: + file.write('Ns %.6f\n' % ((mat.getHardness()-1) * 1.9607843137254901) ) # Hardness, convert blenders 1-511 to MTL's + file.write('Ka %.6f %.6f %.6f\n' % tuple([c*mat.amb for c in worldAmb]) ) # Ambient, uses mirror colour, + file.write('Kd %.6f %.6f %.6f\n' % tuple([c*mat.ref for c in mat.rgbCol]) ) # Diffuse + file.write('Ks %.6f %.6f %.6f\n' % tuple([c*mat.spec for c in mat.specCol]) ) # Specular + file.write('Ni %.6f\n' % mat.IOR) # Refraction index + file.write('d %.6f\n' % mat.alpha) # Alpha (obj uses 'd' for dissolve) + + # 0 to disable lighting, 1 for ambient & diffuse only (specular color set to black), 2 for full lighting. + if mat.getMode() & Blender.Material.Modes['SHADELESS']: + file.write('illum 0\n') # ignore lighting + elif mat.getSpec() == 0: + file.write('illum 1\n') # no specular. + else: + file.write('illum 2\n') # light normaly + + else: + #write a dummy material here? + file.write('Ns 0\n') + file.write('Ka %.6f %.6f %.6f\n' % tuple([c for c in worldAmb]) ) # Ambient, uses mirror colour, + file.write('Kd 0.8 0.8 0.8\n') + file.write('Ks 0.8 0.8 0.8\n') + file.write('d 1\n') # No alpha + file.write('illum 2\n') # light normaly + + # Write images! + if img: # We have an image on the face! + file.write('map_Kd %s\n' % img.filename.split('\\')[-1].split('/')[-1]) # Diffuse mapping image + + elif not mat: # No face image. if we havea material search for MTex image. + for mtex in mat.getTextures(): + if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE: + try: + filename = mtex.tex.image.filename.split('\\')[-1].split('/')[-1] + file.write('map_Kd %s\n' % filename) # Diffuse mapping image + break + except: + # Texture has no image though its an image type, best ignore. + pass + + file.write('\n\n') + + file.close() + +def copy_file(source, dest): + file = open(source, 'rb') + data = file.read() + file.close() + + file = open(dest, 'wb') + file.write(data) + file.close() + + +def copy_images(dest_dir): + if dest_dir[-1] != sys.sep: + dest_dir += sys.sep + + # Get unique image names + uniqueImages = {} + for matname, mat, image in MTL_DICT.itervalues(): # Only use image name + # Get Texface images + if image: + uniqueImages[image] = image # Should use sets here. wait until Python 2.4 is default. + + # Get MTex images + if mat: + for mtex in mat.getTextures(): + if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE: + image_tex = mtex.tex.image + if image_tex: + try: + uniqueImages[image_tex] = image_tex + except: + pass + + # Now copy images + copyCount = 0 + + for bImage in uniqueImages.itervalues(): + image_path = sys.expandpath(bImage.filename) + if sys.exists(image_path): + # Make a name for the target path. + dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1] + if not sys.exists(dest_image_path): # Image isnt alredy there + print '\tCopying "%s" > "%s"' % (image_path, dest_image_path) + copy_file(image_path, dest_image_path) + copyCount+=1 + print '\tCopied %d images' % copyCount + +def write(filename, objects,\ +EXPORT_TRI=False, EXPORT_EDGES=False, EXPORT_NORMALS=False, EXPORT_NORMALS_HQ=False,\ +EXPORT_UV=True, EXPORT_MTL=True, EXPORT_COPY_IMAGES=False,\ +EXPORT_APPLY_MODIFIERS=True, EXPORT_ROTX90=True, EXPORT_BLEN_OBS=True,\ +EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False): + ''' + Basic write function. The context and options must be alredy set + This can be accessed externaly + eg. + write( 'c:\\test\\foobar.obj', Blender.Object.GetSelected() ) # Using default options. + ''' + + def veckey3d(v): + return round(v.x, 6), round(v.y, 6), round(v.z, 6) + + #def veckey2d(v): + # return round(v.x, 6), round(v.y, 6) + + print 'OBJ Export path: "%s"' % filename + temp_mesh_name = '~tmp-mesh' + + time1 = sys.time() + scn = Scene.GetCurrent() + + file = open(filename, "w") + + # Write Header + file.write('# Blender3D v%s OBJ File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] )) + file.write('# www.blender3d.org\n') + + # Tell the obj file what material file to use. + if EXPORT_MTL: + mtlfilename = '%s.mtl' % '.'.join(filename.split('.')[:-1]) + file.write('mtllib %s\n' % ( mtlfilename.split('\\')[-1].split('/')[-1] )) + + # Get the container mesh. - used for applying modifiers and non mesh objects. + containerMesh = meshName = tempMesh = None + for meshName in Blender.NMesh.GetNames(): + if meshName.startswith(temp_mesh_name): + tempMesh = Mesh.Get(meshName) + if not tempMesh.users: + containerMesh = tempMesh + if not containerMesh: + containerMesh = Mesh.New(temp_mesh_name) + + if EXPORT_ROTX90: + mat_xrot90= Blender.Mathutils.RotationMatrix(-90, 4, 'x') + + del meshName + del tempMesh + + # Initialize totals, these are updated each object + totverts = totuvco = totno = 1 + + face_vert_index = 1 # used for uvs now + + globalNormals = {} + + # Get all meshs + for ob_main in objects: + for ob, ob_mat in BPyObject.getDerivedObjects(ob_main): + # Will work for non meshes now! :) + # getMeshFromObject(ob, container_mesh=None, apply_modifiers=True, vgroups=True, scn=None) + me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scn) + if not me: + continue + faceuv= me.faceUV + + # We have a valid mesh + if EXPORT_TRI and me.faces: + # Add a dummy object to it. + has_quads = False + for f in me.faces: + if len(f) == 4: + has_quads = True + break + + if has_quads: + oldmode = Mesh.Mode() + Mesh.Mode(Mesh.SelectModes['FACE']) + + me.sel = True + tempob = scn.objects.new(me) + me.quadToTriangle(0) # more=0 shortest length + oldmode = Mesh.Mode(oldmode) + scn.objects.unlink(tempob) + + Mesh.Mode(oldmode) + + # Make our own list so it can be sorted to reduce context switching + faces = [ f for f in me.faces ] + + if EXPORT_EDGES: + edges = me.edges + else: + edges = [] + + if not (len(faces)+len(edges)+len(me.verts)): # Make sure there is somthing to write + continue # dont bother with this mesh. + + if EXPORT_ROTX90: + me.transform(ob_mat*mat_xrot90) + else: + me.transform(ob_mat) + + # High Quality Normals + if EXPORT_NORMALS and faces: + if EXPORT_NORMALS_HQ: + BPyMesh.meshCalcNormals(me) + else: + # transforming normals is incorrect + # when the matrix is scaled, + # better to recalculate them + me.calcNormals() + + # # Crash Blender + #materials = me.getMaterials(1) # 1 == will return None in the list. + materials = me.materials + + materialNames = [] + materialItems = materials[:] + if materials: + for mat in materials: + if mat: # !=None + materialNames.append(mat.name) + else: + materialNames.append(None) + # Cant use LC because some materials are None. + # materialNames = map(lambda mat: mat.name, materials) # Bug Blender, dosent account for null materials, still broken. + + # Possible there null materials, will mess up indicies + # but at least it will export, wait until Blender gets fixed. + materialNames.extend((16-len(materialNames)) * [None]) + materialItems.extend((16-len(materialItems)) * [None]) + + # Sort by Material, then images + # so we dont over context switch in the obj file. + if EXPORT_MORPH_TARGET: + pass + elif faceuv and EXPORT_UV: + try: faces.sort(key = lambda a: (a.mat, a.image, a.smooth)) + except: faces.sort(lambda a,b: cmp((a.mat, a.image, a.smooth), (b.mat, b.image, b.smooth))) + elif len(materials) > 1: + try: faces.sort(key = lambda a: (a.mat, a.smooth)) + except: faces.sort(lambda a,b: cmp((a.mat, a.smooth), (b.mat, b.smooth))) + else: + # no materials + try: faces.sort(key = lambda a: a.smooth) + except: faces.sort(lambda a,b: cmp(a.smooth, b.smooth)) + + # Set the default mat to no material and no image. + contextMat = (0, 0) # Can never be this, so we will label a new material teh first chance we get. + contextSmooth = None # Will either be true or false, set bad to force initialization switch. + + if EXPORT_BLEN_OBS or EXPORT_GROUP_BY_OB: + name1 = ob.name + name2 = ob.getData(1) + if name1 == name2: + obnamestring = fixName(name1) + else: + obnamestring = '%s_%s' % (fixName(name1), fixName(name2)) + + if EXPORT_BLEN_OBS: + file.write('o %s\n' % obnamestring) # Write Object name + else: # if EXPORT_GROUP_BY_OB: + file.write('g %s\n' % obnamestring) + + + # Vert + for v in me.verts: + file.write('v %.6f %.6f %.6f\n' % tuple(v.co)) + + # UV + if faceuv and EXPORT_UV: + for f in faces: + for uv in f.uv: + file.write('vt %.6f %.6f 0.0\n' % tuple(uv)) + + # NORMAL, Smooth/Non smoothed. + if EXPORT_NORMALS: + for f in faces: + if f.smooth: + for v in f: + noKey = veckey3d(v.no) + if not globalNormals.has_key( noKey ): + globalNormals[noKey] = totno + totno +=1 + file.write('vn %.6f %.6f %.6f\n' % noKey) + else: + # Hard, 1 normal from the face. + noKey = veckey3d(f.no) + if not globalNormals.has_key( noKey ): + globalNormals[noKey] = totno + totno +=1 + file.write('vn %.6f %.6f %.6f\n' % noKey) + if not faceuv: + f_image = None + + for f in faces: + f_v= f.v + f_smooth= f.smooth + f_mat = min(f.mat, len(materialNames)-1) + if faceuv: + f_image = f.image + f_uv= f.uv + + # MAKE KEY + if EXPORT_UV and faceuv and f_image: # Object is always true. + key = materialNames[f_mat], f_image.name + else: + key = materialNames[f_mat], None # No image, use None instead. + + # CHECK FOR CONTEXT SWITCH + if key == contextMat: + pass # Context alredy switched, dont do anythoing + else: + if key[0] == None and key[1] == None: + # Write a null material, since we know the context has changed. + if EXPORT_GROUP_BY_MAT: + file.write('g %s_%s\n' % (fixName(ob.name), fixName(ob.getData(1))) ) # can be mat_image or (null) + file.write('usemtl (null)\n') # mat, image + + else: + mat_data= MTL_DICT.get(key) + if not mat_data: + # First add to global dict so we can export to mtl + # Then write mtl + + # Make a new names from the mat and image name, + # converting any spaces to underscores with fixName. + + # If none image dont bother adding it to the name + if key[1] == None: + mat_data = MTL_DICT[key] = ('%s'%fixName(key[0])), materialItems[f_mat], f_image + else: + mat_data = MTL_DICT[key] = ('%s_%s' % (fixName(key[0]), fixName(key[1]))), materialItems[f_mat], f_image + + if EXPORT_GROUP_BY_MAT: + file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.getData(1)), mat_data[0]) ) # can be mat_image or (null) + file.write('usemtl %s\n' % mat_data[0]) # can be mat_image or (null) + + contextMat = key + if f_smooth != contextSmooth: + if f_smooth: # on now off + file.write('s 1\n') + contextSmooth = f_smooth + else: # was off now on + file.write('s off\n') + contextSmooth = f_smooth + + file.write('f') + if faceuv and EXPORT_UV: + if EXPORT_NORMALS: + if f_smooth: # Smoothed, use vertex normals + for vi, v in enumerate(f_v): + file.write( ' %d/%d/%d' % (\ + v.index+totverts,\ + face_vert_index + vi,\ + globalNormals[ veckey3d(v.no) ])) # vert, uv, normal + + else: # No smoothing, face normals + no = globalNormals[ veckey3d(f.no) ] + for vi, v in enumerate(f_v): + file.write( ' %d/%d/%d' % (\ + v.index+totverts,\ + face_vert_index + vi,\ + no)) # vert, uv, normal + + else: # No Normals + for vi, v in enumerate(f_v): + file.write( ' %d/%d' % (\ + v.index+totverts,\ + face_vert_index + vi)) # vert, uv + + face_vert_index += len(f_v) + + else: # No UV's + if EXPORT_NORMALS: + if f_smooth: # Smoothed, use vertex normals + for v in f_v: + file.write( ' %d//%d' % (\ + v.index+totverts,\ + globalNormals[ veckey3d(v.no) ])) + else: # No smoothing, face normals + no = globalNormals[ veckey3d(f.no) ] + for v in f_v: + file.write( ' %d//%d' % (\ + v.index+totverts,\ + no)) + else: # No Normals + for v in f_v: + file.write( ' %d' % (\ + v.index+totverts)) + + file.write('\n') + + # Write edges. + if EXPORT_EDGES: + LOOSE= Mesh.EdgeFlags.LOOSE + for ed in edges: + if ed.flag & LOOSE: + file.write('f %d %d\n' % (ed.v1.index+totverts, ed.v2.index+totverts)) + + # Make the indicies global rather then per mesh + totverts += len(me.verts) + me.verts= None + file.close() + + + # Now we have all our materials, save them + if EXPORT_MTL: + write_mtl(mtlfilename) + if EXPORT_COPY_IMAGES: + dest_dir = filename + # Remove chars until we are just the path. + while dest_dir and dest_dir[-1] not in '\\/': + dest_dir = dest_dir[:-1] + if dest_dir: + copy_images(dest_dir) + else: + print '\tError: "%s" could not be used as a base for an image path.' % filename + + print "OBJ Export time: %.2f" % (sys.time() - time1) + + + +def write_ui(filename): + + if not filename.lower().endswith('.obj'): + filename += '.obj' + + if not BPyMessages.Warning_SaveOver(filename): + return + + EXPORT_APPLY_MODIFIERS = Draw.Create(1) + EXPORT_ROTX90 = Draw.Create(1) + EXPORT_TRI = Draw.Create(0) + EXPORT_EDGES = Draw.Create(1) + EXPORT_NORMALS = Draw.Create(0) + EXPORT_NORMALS_HQ = Draw.Create(1) + EXPORT_UV = Draw.Create(1) + EXPORT_MTL = Draw.Create(1) + EXPORT_SEL_ONLY = Draw.Create(1) + EXPORT_ALL_SCENES = Draw.Create(0) + EXPORT_ANIMATION = Draw.Create(0) + EXPORT_COPY_IMAGES = Draw.Create(0) + EXPORT_BLEN_OBS = Draw.Create(1) + EXPORT_GROUP_BY_OB = Draw.Create(0) + EXPORT_GROUP_BY_MAT = Draw.Create(0) + EXPORT_MORPH_TARGET = Draw.Create(0) + + # removed too many options are bad! + + # Get USER Options + pup_block = [\ + ('Context...'),\ + ('Selection Only', EXPORT_SEL_ONLY, 'Only export objects in visible selection. Else export whole scene.'),\ + ('All Scenes', EXPORT_ALL_SCENES, 'Each scene as a separate OBJ file.'),\ + ('Animation', EXPORT_ANIMATION, 'Each frame as a numbered OBJ file.'),\ + ('Object Prefs...'),\ + ('Apply Modifiers', EXPORT_APPLY_MODIFIERS, 'Use transformed mesh data from each object. May break vert order for morph targets.'),\ + ('Rotate X90', EXPORT_ROTX90 , 'Rotate on export so Blenders UP is translated into OBJs UP'),\ + ('Morph Target', EXPORT_MORPH_TARGET, 'Keep vert and face order, disables some other options.'),\ + ('Extra Data...'),\ + ('Edges', EXPORT_EDGES, 'Edges not connected to faces.'),\ + ('Normals', EXPORT_NORMALS, 'Export vertex normal data (Ignored on import).'),\ + ('High Quality Normals', EXPORT_NORMALS_HQ, 'Calculate high quality normals for rendering.'),\ + ('UVs', EXPORT_UV, 'Export texface UV coords.'),\ + ('Materials', EXPORT_MTL, 'Write a separate MTL file with the OBJ.'),\ + ('Copy Images', EXPORT_COPY_IMAGES, 'Copy image files to the export directory, never overwrite.'),\ + ('Triangulate', EXPORT_TRI, 'Triangulate quads.'),\ + ('Grouping...'),\ + ('Objects', EXPORT_BLEN_OBS, 'Export blender objects as "OBJ objects".'),\ + ('Object Groups', EXPORT_GROUP_BY_OB, 'Export blender objects as "OBJ Groups".'),\ + ('Material Groups', EXPORT_GROUP_BY_MAT, 'Group by materials.'),\ + ] + + if not Draw.PupBlock('Export...', pup_block): + return + + if EXPORT_MORPH_TARGET.val: + EXPORT_BLEN_OBS.val = False + EXPORT_GROUP_BY_OB.val = False + EXPORT_GROUP_BY_MAT.val = False + EXPORT_GROUP_BY_MAT.val = False + EXPORT_APPLY_MODIFIERS.val = False + + Window.EditMode(0) + Window.WaitCursor(1) + + EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS.val + EXPORT_ROTX90 = EXPORT_ROTX90.val + EXPORT_TRI = EXPORT_TRI.val + EXPORT_EDGES = EXPORT_EDGES.val + EXPORT_NORMALS = EXPORT_NORMALS.val + EXPORT_NORMALS_HQ = EXPORT_NORMALS_HQ.val + EXPORT_UV = EXPORT_UV.val + EXPORT_MTL = EXPORT_MTL.val + EXPORT_SEL_ONLY = EXPORT_SEL_ONLY.val + EXPORT_ALL_SCENES = EXPORT_ALL_SCENES.val + EXPORT_ANIMATION = EXPORT_ANIMATION.val + EXPORT_COPY_IMAGES = EXPORT_COPY_IMAGES.val + EXPORT_BLEN_OBS = EXPORT_BLEN_OBS.val + EXPORT_GROUP_BY_OB = EXPORT_GROUP_BY_OB.val + EXPORT_GROUP_BY_MAT = EXPORT_GROUP_BY_MAT.val + EXPORT_MORPH_TARGET = EXPORT_MORPH_TARGET.val + + + + base_name, ext = splitExt(filename) + context_name = [base_name, '', '', ext] # basename, scene_name, framenumber, extension + + # Use the options to export the data using write() + # def write(filename, objects, EXPORT_EDGES=False, EXPORT_NORMALS=False, EXPORT_MTL=True, EXPORT_COPY_IMAGES=False, EXPORT_APPLY_MODIFIERS=True): + orig_scene = Scene.GetCurrent() + if EXPORT_ALL_SCENES: + export_scenes = Scene.Get() + else: + export_scenes = [orig_scene] + + # Export all scenes. + for scn in export_scenes: + scn.makeCurrent() # If alredy current, this is not slow. + context = scn.getRenderingContext() + orig_frame = Blender.Get('curframe') + + if EXPORT_ALL_SCENES: # Add scene name into the context_name + context_name[1] = '_%s' % BPySys.cleanName(scn.name) # WARNING, its possible that this could cause a collision. we could fix if were feeling parranoied. + + # Export an animation? + if EXPORT_ANIMATION: + scene_frames = xrange(context.startFrame(), context.endFrame()+1) # up to and including the end frame. + else: + scene_frames = [orig_frame] # Dont export an animation. + + # Loop through all frames in the scene and export. + for frame in scene_frames: + if EXPORT_ANIMATION: # Add frame to the filename. + context_name[2] = '_%.6d' % frame + + Blender.Set('curframe', frame) + if EXPORT_SEL_ONLY: + export_objects = scn.objects.context + else: + export_objects = scn.objects + + full_path= ''.join(context_name) + + # erm... bit of a problem here, this can overwrite files when exporting frames. not too bad. + # EXPORT THE FILE. + write(full_path, export_objects,\ + EXPORT_TRI, EXPORT_EDGES, EXPORT_NORMALS,\ + EXPORT_NORMALS_HQ, EXPORT_UV, EXPORT_MTL,\ + EXPORT_COPY_IMAGES, EXPORT_APPLY_MODIFIERS,\ + EXPORT_ROTX90, EXPORT_BLEN_OBS,\ + EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_MORPH_TARGET) + + Blender.Set('curframe', orig_frame) + + # Restore old active scene. + orig_scene.makeCurrent() + Window.WaitCursor(0) + + +if __name__ == '__main__': + Window.FileSelector(write_ui, 'Export Wavefront OBJ', sys.makename(ext='.obj')) diff --git a/release/scripts/faceselect_same_weights.py b/release/scripts/faceselect_same_weights.py new file mode 100644 index 00000000000..b8d50cf09b6 --- /dev/null +++ b/release/scripts/faceselect_same_weights.py @@ -0,0 +1,111 @@ +#!BPY +""" +Name: 'Same Weights...' +Blender: 241 +Group: 'FaceSelect' +Tooltip: 'Select same faces with teh same weight for the active group.' +""" + +__author__ = ["Campbell Barton"] +__url__ = ("blender", "elysiun", "http://members.iinet.net.au/~cpbarton/ideasman/") +__version__ = "0.1" +__bpydoc__ = """\ + +Select Same Weights + +Select same weights as the active face on the active group. +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Campbell J Barton +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +from Blender import Scene, Draw, Mesh +import BPyMesh + +def selSameWeights(me, PREF_TOLERENCE): + + # Check for missing data + if not me.faceUV: return + + act_group= me.activeGroup + if not act_group: return + + act_face = me.faces[me.activeFace] + if act_face == None: return + + + + groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me) + + def get_face_weight(f): + ''' + Return the faces median weight and weight range. + ''' + wmin = 1.0 + wmax = 0.0 + w = 0.0 + for v in f: + try: + new_weight = vWeightDict[v.index][act_group] + if wmin > new_weight: wmin = new_weight + if wmax < new_weight: wmax = new_weight + w += new_weight + except: + pass + return w, wmax-wmin # weight, range + + weight_from, weight_range_from = get_face_weight(act_face) + for f in me.faces: + if (not f.sel) and f != act_face: + weight, weight_range = get_face_weight(f) + + # Compare the 2 faces weight difference and difference in their contrast. + if\ + abs(weight - weight_from) <= PREF_TOLERENCE and\ + abs(weight_range - weight_range_from) <= PREF_TOLERENCE: + f.sel = True + + +def main(): + scn= Scene.GetCurrent() + ob= scn.objects.active + + if not ob or ob.type != 'Mesh': + Draw.PupMenu('Error, no active mesh object, aborting.') + return + + me= ob.getData(mesh=1) + + PREF_TOLERENCE= Draw.Create(0.1) + + pup_block= [\ + ('Tolerence:', PREF_TOLERENCE, 0.01, 1.0, 'Tolerence for selecting faces of the same weight.'),\ + ] + + if not Draw.PupBlock('Select Same Weight...', pup_block): + return + + PREF_TOLERENCE= PREF_TOLERENCE.val + + selSameWeights(me, PREF_TOLERENCE) + +if __name__=='__main__': + main() \ No newline at end of file diff --git a/release/scripts/flt_export.py b/release/scripts/flt_export.py new file mode 100644 index 00000000000..283c24a3ad0 --- /dev/null +++ b/release/scripts/flt_export.py @@ -0,0 +1,722 @@ +#!BPY +""" Registration info for Blender menus: +Name: 'OpenFlight (.flt)...' +Blender: 237 +Group: 'Export' +Tip: 'Export to OpenFlight v16.0 (.flt)' +""" + +__author__ = "Greg MacDonald" +__version__ = "1.2 10/20/05" +__url__ = ("blender", "elysiun", "Author's homepage, http://sourceforge.net/projects/blight/") +__bpydoc__ = """\ +This script exports v16.0 OpenFlight files. OpenFlight is a +registered trademark of MultiGen-Paradigm, Inc. + +Run from "File->Export" menu. + +Options are available from Blender's "Scripts Config Editor," accessible through +the "Scripts->System" menu from the scripts window. + +Features:
+* Heirarchy retained.
+* Normals retained.
+* First texture exported.
+* Diffuse material color is exported as the face color, material color, or both +depending on the option settings.
+* Double sided faces are exported as two faces.
+* Object transforms exported. + +Things To Be Aware Of:
+* Object names are exported, not mesh or data names. +* Material indices that don't have a material associated with them will confuse the +exporter. If a warning appears about this, correct it by deleting the offending +material indices in Blender. + +What's Not Handled:
+* Animations.
+* Vetex colors.
+""" + +# flt_export.py is an OpenFlight exporter for blender. +# Copyright (C) 2005 Greg MacDonald +# +# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +import Blender +from flt_filewalker import FltOut + +class ExporterOptions: + def __init__(self): + self.defaults = { 'Diffuse Color To OpenFlight Material': False, + 'Diffuse Color To OpenFlight Face': True} + + d = Blender.Registry.GetKey('flt_export', True) + + if d == None or d.keys() != self.defaults.keys(): + d = self.defaults + Blender.Registry.SetKey('flt_export', d, True) + + self.verbose = 1 + self.tolerance = 0.001 + self.use_mat_color = d['Diffuse Color To OpenFlight Material'] + self.use_face_color = d['Diffuse Color To OpenFlight Face'] + +options = ExporterOptions() + +FLOAT_TOLERANCE = options.tolerance + +identity_matrix = [[1.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, 1.0]] + +def is_identity(m): + for i in xrange(4): + for j in xrange(4): + if abs(m[i][j] - identity_matrix[i][j]) > FLOAT_TOLERANCE: + return False + return True + +class MaterialDesc: + def __init__(self): + self.name = 'Blender' + + # Colors, List of 3 floats. + self.diffuse = [1.0, 1.0, 1.0] + self.specular = [1.0, 1.0, 1.0] + + # Scalars + self.ambient = 0.1 # [0.0, 1.0] + self.emissive = 0.0 # [0.0, 1.0] + self.shininess = 32.0 # Range is [0.0, 128.0] + self.alpha = 1.0 # Range is [0.0, 1.0] + +class VertexDesc: + def __init__(self, co=None, no=None, uv=None): + if co: self.x, self.y, self.z = tuple(co) + else: self.x = self.y = self.z = 0.0 + if no: self.nx, self.ny, self.nz = tuple(no) + else: self.nx = self.ny = self.nz = 0.0 + if uv: self.u, self.v = tuple(uv) + else: self.u = self.v = 0.0 + +class GlobalResourceRepository: + def new_face_name(self): + self.face_name += 1 + return 'f%i' % (self.face_name-1) + + def vertex_count(self): + return len(self.vertex_lst) + + def request_vertex_desc(self, i): + return self.vertex_lst[i] + + def request_vertex_index(self, desc): + match = None + for i, v in enumerate(self.vertex_lst): + if\ + abs(v.x - desc.x) > FLOAT_TOLERANCE or\ + abs(v.y - desc.y) > FLOAT_TOLERANCE or\ + abs(v.z - desc.z) > FLOAT_TOLERANCE or\ + abs(v.nx - desc.nx) > FLOAT_TOLERANCE or\ + abs(v.ny - desc.ny) > FLOAT_TOLERANCE or\ + abs(v.nz - desc.nz) > FLOAT_TOLERANCE or\ + abs(v.u - desc.u) > FLOAT_TOLERANCE or\ + abs(v.v - desc.v) > FLOAT_TOLERANCE: + pass + else: + match = i + break + + if match != None: + return match + else: + self.vertex_lst.append(desc) + return len(self.vertex_lst) - 1 + + def request_texture_index(self, filename): + match = None + for i in xrange(len(self.texture_lst)): + if self.texture_lst[i] != filename: + continue + match = i + break + if match != None: + return match + else: + self.texture_lst.append(filename) + return len(self.texture_lst) - 1 + + def request_texture_filename(self, index): + return self.texture_lst[index] + + def texture_count(self): + return len(self.texture_lst) + + def request_material_index(self, desc): + match = None + for i in xrange(len(self.material_lst)): + if self.material_lst[i].diffuse != desc.diffuse: + continue + if self.material_lst[i].specular != desc.specular: + continue + if self.material_lst[i].ambient != desc.ambient: + continue + if self.material_lst[i].emissive != desc.emissive: + continue + if self.material_lst[i].shininess != desc.shininess: + continue + if self.material_lst[i].alpha != desc.alpha: + continue + match = i + break + + if match != None: + return i + else: + self.material_lst.append(desc) + return len(self.material_lst) - 1 + + def request_material_desc(self, index): + return self.material_lst[index] + + def material_count(self): + return len(self.material_lst) + + # Returns not actual index but one that includes intensity information. + # color_index = 127*intensity + 128*actual_index + def request_color_index(self, col): + r,g,b = tuple(col) + m = max(r, g, b) + if m > 0.0: + intensity = m / 1.0 + r = int(round(r/m * 255.0)) + g = int(round(g/m * 255.0)) + b = int(round(b/m * 255.0)) + brightest = [r, g, b] + else: + brightest = [255, 255, 255] + intensity = 0.0 + + match = None + for i in xrange(len(self.color_lst)): + if self.color_lst[i] != brightest: + continue + + match = i + break + + if match != None: + index = match + else: + length = len(self.color_lst) + if length <= 1024: + self.color_lst.append(brightest) + index = length + else: + if options.verbose >= 1: + print 'Warning: Exceeded max color limit.' + index = 0 + + color_index = int(round(127.0*intensity)) + 128*index + return color_index + + # Returns color from actual index. + def request_max_color(self, index): + return self.color_lst[index] + + def color_count(self): + return len(self.color_lst) + + def __init__(self): + self.vertex_lst = [] + self.texture_lst = [] + self.material_lst = [] + self.color_lst = [[255, 255, 255]] + self.face_name = 0 + +class Node: + # Gathers info from blender needed for export. + # The =[0] is a trick to emulate c-like static function variables + # that are persistant between calls. + def blender_export(self, level=[0]): + if self.object: + if options.verbose >= 2: + print '\t' * level[0], self.name, self.object.type + + level[0] += 1 + + for child in self.children: + child.blender_export() + + level[0] -= 1 + + # Exports this node's info to file. + def write(self): + pass + + def write_matrix(self): + if self.matrix and not is_identity(self.matrix): + self.header.fw.write_short(49) # Matrix opcode + self.header.fw.write_ushort(68) # Length of record + for i in xrange(4): + for j in xrange(4): + self.header.fw.write_float(self.matrix[i][j]) + + def write_push(self): + self.header.fw.write_short(10) + self.header.fw.write_ushort(4) + + def write_pop(self): + self.header.fw.write_short(11) + self.header.fw.write_ushort(4) + + def write_longid(self, name): + length = len(name) + if length >= 8: + self.header.fw.write_short(33) # Long ID opcode + self.header.fw.write_ushort(length+5) # Length of record + self.header.fw.write_string(name, length+1) # name + zero terminator + + # Initialization sets up basic tree structure. + def __init__(self, parent, header, object, object_lst): + self.header = header + self.object = object + if object: + self.name = self.object.name + self.matrix = self.object.getMatrix('localspace') + else: + self.name = 'no name' + self.matrix = None + + self.children = [] + self.parent = parent + if parent: + parent.children.append(self) + + left_over = object_lst[:] + self.child_objects = [] + + # Add children to child list and remove from left_over list. + + # Pop is faster then remove + i = len(object_lst) + while i: + i-=1 + if object_lst[i].parent == object: + self.child_objects.append(left_over.pop(i)) + + # Spawn children. + self.has_object_child = False # For Database class. + for child in self.child_objects: + if child.type == 'Mesh': + BlenderMesh(self, header, child, left_over) + self.has_object_child = True + else: # Treat all non meshes as emptys + BlenderEmpty(self, header, child, left_over) + +class FaceDesc: + def __init__(self): + self.vertex_index_lst = [] + self.texture_index = -1 + self.material_index = -1 + self.color_index = 127 + +class BlenderMesh(Node): + def blender_export(self): + Node.blender_export(self) + + mesh = self.object.getData() + mesh_hasuv = mesh.hasFaceUV() + # Gather materials and textures. + tex_index_lst = [] + mat_index_lst = [] + color_index_lst = [] + materials = mesh.getMaterials() + + if not materials: + materials = [Blender.Material.New()] + + for mat in materials: + # Gather Color. + if options.use_face_color: + color_index_lst.append(self.header.GRR.request_color_index(mat.getRGBCol())) + else: + color_index_lst.append(127) # white + # Gather Texture. + mtex_lst = mat.getTextures() + + index = -1 + mtex = mtex_lst[0] # Not doing multi-texturing at the moment. + if mtex != None: + tex = mtex_lst[0].tex + if tex != None: + image = tex.getImage() + if image != None: + filename = image.getFilename() + index = self.header.GRR.request_texture_index(filename) + + tex_index_lst.append(index) + + # Gather Material + mat_desc = MaterialDesc() + mat_desc.name = mat.name + mat_desc.alpha = mat.getAlpha() + mat_desc.shininess = mat.getSpec() * 64.0 # 2.0 => 128.0 + if options.use_mat_color: + mat_desc.diffuse = mat.getRGBCol() + else: + mat_desc.diffuse = [1.0, 1.0, 1.0] + + mat_desc.specular = mat.getSpecCol() + amb = mat.getAmb() + mat_desc.ambient = [amb, amb, amb] + emit = mat.getEmit() + mat_desc.emissive = [emit, emit, emit] + + mat_index_lst.append(self.header.GRR.request_material_index(mat_desc)) + + # Faces described as lists of indices into the GRR's vertex_lst. + for face in mesh.faces: + + face_v = face.v # Faster access + + # Create vertex description list for each face. + if mesh_hasuv: + vertex_lst = [VertexDesc(v.co, v.no, face.uv[i]) for i, v in enumerate(face_v)] + else: + vertex_lst = [VertexDesc(v.co, v.no) for i, v in enumerate(face_v)] + + index_lst = [] + for vert_desc in vertex_lst: + index_lst.append(self.header.GRR.request_vertex_index(vert_desc)) + + face_desc = FaceDesc() + face_desc.vertex_index_lst = index_lst + + if face.materialIndex < len(materials): + face_desc.color_index = color_index_lst[face.materialIndex] + face_desc.texture_index = tex_index_lst[face.materialIndex] + face_desc.material_index = mat_index_lst[face.materialIndex] + else: + if options.verbose >=1: + print 'Warning: Missing material for material index. Materials will not be imported correctly. Fix by deleting abandoned material indices in Blender.' + + self.face_lst.append(face_desc) + + # Export double sided face as 2 faces with opposite orientations. + if mesh_hasuv and face.mode & Blender.NMesh.FaceModes['TWOSIDE']: + # Create vertex description list for each face. they have a face mode, so we know they have a UV too. + vertex_lst = [VertexDesc(v.co, -v.no, face.uv[i]) for i, v in enumerate(face_v)] + vertex_lst.reverse() # Reversing flips the face. + + index_lst = [] + for vert_desc in vertex_lst: + index_lst.append(self.header.GRR.request_vertex_index(vert_desc)) + + face_desc = FaceDesc() + face_desc.vertex_index_lst = index_lst + if face.materialIndex < len(materials): + face_desc.color_index = color_index_lst[face.materialIndex] + face_desc.texture_index = tex_index_lst[face.materialIndex] + face_desc.material_index = mat_index_lst[face.materialIndex] + else: + if options.verbose >=1: + print 'Error: No material for material index. Delete abandoned material indices in Blender.' + + self.face_lst.append(face_desc) + + def write_faces(self): + for face_desc in self.face_lst: + face_name = self.header.GRR.new_face_name() + + self.header.fw.write_short(5) # Face opcode + self.header.fw.write_ushort(80) # Length of record + self.header.fw.write_string(face_name, 8) # ASCII ID + self.header.fw.write_int(-1) # IR color code + self.header.fw.write_short(0) # Relative priority + self.header.fw.write_char(0) # Draw type + self.header.fw.write_char(0) # Draw textured white. + self.header.fw.write_ushort(0) # Color name index + self.header.fw.write_ushort(0) # Alt color name index + self.header.fw.write_char(0) # Reserved + self.header.fw.write_char(1) # Template + self.header.fw.write_short(-1) # Detail tex pat index + self.header.fw.write_short(face_desc.texture_index) # Tex pattern index + self.header.fw.write_short(face_desc.material_index) # material index + self.header.fw.write_short(0) # SMC code + self.header.fw.write_short(0) # Feature code + self.header.fw.write_int(0) # IR material code + self.header.fw.write_ushort(0) # transparency 0 = opaque + self.header.fw.write_uchar(0) # LOD generation control + self.header.fw.write_uchar(0) # line style index + self.header.fw.write_int(0x00000000) # Flags + self.header.fw.write_uchar(2) # Light mode + self.header.fw.pad(7) # Reserved + self.header.fw.write_uint(-1) # Packed color + self.header.fw.write_uint(-1) # Packed alt color + self.header.fw.write_short(-1) # Tex map index + self.header.fw.write_short(0) # Reserved + self.header.fw.write_uint(face_desc.color_index) # Color index + self.header.fw.write_uint(127) # Alt color index + self.header.fw.write_short(0) # Reserved + self.header.fw.write_short(-1) # Shader index + + self.write_longid(face_name) + + self.write_push() + + # Vertex list record + self.header.fw.write_short(72) # Vertex list opcode + num_verts = len(face_desc.vertex_index_lst) + self.header.fw.write_ushort(4*num_verts+4) # Length of record + + for vert_index in face_desc.vertex_index_lst: + # Offset into vertex palette + self.header.fw.write_int(vert_index*64+8) + + self.write_pop() + + def write(self): + if self.open_flight_type == 'Object': + self.header.fw.write_short(4) # Object opcode + self.header.fw.write_ushort(28) # Length of record + self.header.fw.write_string(self.name, 8) # ASCII ID + self.header.fw.pad(16) + + self.write_longid(self.name) + + self.write_matrix() + + if self.face_lst != []: + self.write_push() + + self.write_faces() + + self.write_pop() + else: + self.header.fw.write_short(2) # Group opcode + self.header.fw.write_ushort(44) # Length of record + self.header.fw.write_string(self.name, 8) # ASCII ID + self.header.fw.pad(32) + + self.write_longid(self.name) + + # Because a group can contain faces as well as children. + self.write_push() + + self.write_faces() + + for child in self.children: + child.write() + + self.write_pop() + + def __init__(self, parent, header, object, object_lst): + Node.__init__(self, parent, header, object, object_lst) + self.face_lst = [] + + if self.children: + self.open_flight_type= 'Group' + else: # Empty list. + self.open_flight_type = 'Object' + + +class BlenderEmpty(Node): + def write(self): + self.header.fw.write_short(2) # Group opcode + self.header.fw.write_ushort(44) # Length of record + self.header.fw.write_string(self.name, 8) # ASCII ID + self.header.fw.pad(32) + + self.write_longid(self.name) + + self.write_matrix() + + if self.children: # != [] + self.write_push() + + for child in self.children: + child.write() + + self.write_pop() + +class Database(Node): + def write_header(self): + if options.verbose >= 2: + print 'Writing header.' + self.fw.write_short(1) # Header opcode + self.fw.write_ushort(324) # Length of record + self.fw.write_string('db', 8) # ASCII ID + self.fw.write_int(1600) # Revision Number + self.fw.pad(44) + self.fw.write_short(1) # Unit multiplier. + self.fw.write_char(0) # Units, 0 = meters + self.fw.write_char(0) # texwhite on new faces 0 = false + self.fw.write_uint(0x80000000) # misc flags set to saving vertex normals + self.fw.pad(24) + self.fw.write_int(0) # projection type, 0 = flat earth + self.fw.pad(30) + self.fw.write_short(1) # double precision + self.fw.pad(140) + self.fw.write_int(0) # ellipsoid model, 0 = WSG 1984 + self.fw.pad(52) + + def write_vert_pal(self): + if options.verbose >= 2: + print 'Writing vertex palette.' + # Write record for vertex palette + self.fw.write_short(67) # Vertex palette opcode. + self.fw.write_short(8) # Length of record + self.fw.write_int(self.GRR.vertex_count() * 64 + 8) # Length of everything. + + # Write records for individual vertices. + for i in xrange(self.GRR.vertex_count()): + desc = self.GRR.request_vertex_desc(i) + self.fw.write_short(70) # Vertex with color normal and uv opcode. + self.fw.write_ushort(64) # Length of record + self.fw.write_ushort(0) # Color name index + self.fw.write_short(0x2000) # Flags set to no color + self.fw.write_double(desc.x) + self.fw.write_double(desc.y) + self.fw.write_double(desc.z) + self.fw.write_float(desc.nx) + self.fw.write_float(desc.ny) + self.fw.write_float(desc.nz) + self.fw.write_float(desc.u) + self.fw.write_float(desc.v) + self.fw.pad(12) + + def write_tex_pal(self): + if options.verbose >= 2: + print 'Writing texture palette.' + # Write record for texture palette + for i in xrange(self.GRR.texture_count()): + self.fw.write_short(64) # Texture palette opcode. + self.fw.write_short(216) # Length of record + self.fw.write_string(self.GRR.request_texture_filename(i), 200) # Filename + self.fw.write_int(i) # Texture index + self.fw.write_int(0) # X + self.fw.write_int(0) # Y + + def write_mat_pal(self): + if options.verbose >= 2: + print 'Writing material palette.' + for i in xrange(self.GRR.material_count()): + desc = self.GRR.request_material_desc(i) + self.fw.write_short(113) # Material palette opcode. + self.fw.write_short(84) # Length of record + self.fw.write_int(i) # Material index + self.fw.write_string(desc.name, 12) # Material name + self.fw.write_uint(0x80000000) # Flags + self.fw.write_float(desc.ambient[0]) # Ambient color. + self.fw.write_float(desc.ambient[1]) # Ambient color. + self.fw.write_float(desc.ambient[2]) # Ambient color. + self.fw.write_float(desc.diffuse[0]) # Diffuse color. + self.fw.write_float(desc.diffuse[1]) # Diffuse color. + self.fw.write_float(desc.diffuse[2]) # Diffuse color. + self.fw.write_float(desc.specular[0]) # Specular color. + self.fw.write_float(desc.specular[1]) # Specular color. + self.fw.write_float(desc.specular[2]) # Specular color. + self.fw.write_float(desc.emissive[0]) # Emissive color. + self.fw.write_float(desc.emissive[1]) # Emissive color. + self.fw.write_float(desc.emissive[2]) # Emissive color. + self.fw.write_float(desc.shininess) + self.fw.write_float(desc.alpha) + self.fw.write_int(0) # Reserved + + def write_col_pal(self): + if options.verbose >= 2: + print 'Writing color palette.' + self.fw.write_short(32) # Color palette opcode. + self.fw.write_short(4228) # Length of record + self.fw.pad(128) + count = self.GRR.color_count() + for i in xrange(count): + col = self.GRR.request_max_color(i) + self.fw.write_uchar(255) # alpha + self.fw.write_uchar(col[2]) # b + self.fw.write_uchar(col[1]) # g + self.fw.write_uchar(col[0]) # r + self.fw.pad(max(4096-count*4, 0)) + + def write(self): + self.write_header() + self.write_vert_pal() + self.write_tex_pal() + self.write_mat_pal() + self.write_col_pal() + + # Wrap everything in a group if it has an object child. + if self.has_object_child: + self.header.fw.write_short(2) # Group opcode + self.header.fw.write_ushort(44) # Length of record + self.header.fw.write_string('g1', 8) # ASCII ID + self.header.fw.pad(32) + + self.write_push() + + for child in self.children: + child.write() + + self.write_pop() + + def __init__(self, scene, fw): + self.fw = fw + self.scene = scene + self.all_objects = list(scene.objects) + self.GRR = GlobalResourceRepository() + + Node.__init__(self, None, self, None, self.all_objects) + +def fs_callback(filename): + Blender.Window.WaitCursor(True) + + if Blender.sys.exists(filename): + r = Blender.Draw.PupMenu('Overwrite ' + filename + '?%t|Yes|No') + if r != 1: + if options.verbose >= 1: + print 'Export cancelled.' + return + + time1 = Blender.sys.time() # Start timing + + fw = FltOut(filename) + + db = Database(Blender.Scene.GetCurrent(), fw) + + if options.verbose >= 1: + print 'Pass 1: Exporting from Blender.\n' + + db.blender_export() + + if options.verbose >= 1: + print 'Pass 2: Writing %s\n' % filename + + db.write() + + fw.close_file() + if options.verbose >= 1: + print 'Done in %.4f sec.\n' % (Blender.sys.time() - time1) + + Blender.Window.WaitCursor(False) + +if options.verbose >= 1: + print '\nOpenFlight Exporter' + print 'Version:', __version__ + print 'Author: Greg MacDonald' + print __url__[2] + print + +fname = Blender.sys.makename(ext=".flt") +Blender.Window.FileSelector(fs_callback, "Export OpenFlight v16.0", fname) diff --git a/release/scripts/flt_filewalker.py b/release/scripts/flt_filewalker.py new file mode 100644 index 00000000000..442c9728e91 --- /dev/null +++ b/release/scripts/flt_filewalker.py @@ -0,0 +1,279 @@ +#!BPY + +# flt_filewalker.py is an utility module for OpenFlight IO scripts for blender. +# Copyright (C) 2005 Greg MacDonald +# +# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +import Blender +from struct import * +import re + +class FltIn: + def __init__(self, filename): + self.file = open(filename, 'rb') + self.position = 0 + self.next_position = 100000 + self.opcode = 0 + self.length = 0 + self.level = 0 + self.repeat = False # Repeat the last record. + + def begin_record(self): + if self.repeat == True: + self.repeat = False + else: + self.position += self.length + try: + self.file.seek(self.position) + input = self.file.read(4) + except: + print 'Parse Error!' + return False + + if not input: + self.close_file() + return False + + self.opcode = unpack('>h', input[:2])[0] + self.length = unpack('>H', input[-2:])[0] + + self.next_position = self.position + self.length + + return True + + def repeat_record(self): + self.repeat = True + + def get_opcode(self): + return self.opcode + + def get_level(self): + return self.level + + def up_level(self): + self.level += 1 + + def down_level(self): + self.level -= 1 + + def read_string(self, length): + s = '' + if self.file.tell() + length <= self.next_position: + start = self.file.tell() + for i in xrange(length): + char = self.file.read(1) + if char == '\x00': + break + s = s + char + + self.file.seek(start+length) +# else: +# print 'Warning: string truncated' + + return s + + def read_int(self): + if self.file.tell() + 4 <= self.next_position: + return unpack('>i', self.file.read(4))[0] + else: + #print 'Warning: int truncated' + return 0 + + def read_uint(self): + if self.file.tell() + 4 <= self.next_position: + return unpack('>I', self.file.read(4))[0] + else: + #print 'Warning: uint truncated' + return 0 + + def read_double(self): + if self.file.tell() + 8 <= self.next_position: + return unpack('>d', self.file.read(8))[0] + else: + #print 'Warning: double truncated' + return 0.0 + + def read_float(self): + if self.file.tell() + 4 <= self.next_position: + return unpack('>f', self.file.read(4))[0] + else: + #print 'Warning: float truncated' + return 0.0 + + def read_ushort(self): + if self.file.tell() + 2 <= self.next_position: + return unpack('>H', self.file.read(2))[0] + else: + #print 'Warning: ushort truncated' + return 0 + + def read_short(self): + if self.file.tell() + 2 <= self.next_position: + return unpack('>h', self.file.read(2))[0] + else: + #print 'Warning: short trunated' + return 0 + + def read_uchar(self): + if self.file.tell() + 1 <= self.next_position: + return unpack('>B', self.file.read(1))[0] + else: + #print 'Warning: uchar truncated' + return 0 + + def read_char(self): + if self.file.tell() + 1 <= self.next_position: + return unpack('>b', self.file.read(1))[0] + else: + #print 'Warning: char truncated' + return 0 + + def read_ahead(self, i): + if self.file.tell() + i <= self.next_position: + self.file.seek(i, 1) +# else: +# print 'Warning: attempt to seek past record' + + def get_length(self): + return self.length + + def close_file(self): + self.file.close() + +class FltOut: + # Length includes terminating null + def write_string(self, string, length): + if len(string) > length - 1: + str_len = length - 1 + else: + str_len = len(string) + + pad_len = length - str_len + + self.file.write(string[:str_len]) + + self.pad(pad_len) + + def write_int(self, a): + self.file.write( pack('>i', a) ) + + def write_uint(self, a): + self.file.write( pack('>I', a) ) + + def write_double(self, a): + self.file.write( pack('>d', a) ) + + def write_float(self, a): + self.file.write( pack('>f', a) ) + + def write_ushort(self, a): + self.file.write( pack('>H', a) ) + + def write_short(self, a): + self.file.write( pack('>h', a) ) + + def write_uchar(self, a): + self.file.write( pack('>B', a) ) + + def write_char(self, a): + self.file.write( pack('>b', a) ) + + def pad(self, reps): + for i in xrange(reps): + self.file.write('\x00') + + def close_file(self): + self.file.close() + + def __init__(self, filename): + self.file = open(filename, 'wb') + +class FileFinder: + def add_file_to_search_path(self, filename): + dir = Blender.sys.dirname(filename) + if dir != None and dir != '': + self.search_dirs.append(dir) + + def strip_path(self, full_path): + # One of my flt files had a windows path with unix seperation. Basename + # returned the whole path + filename, which isn't expected. So my + # attempt to fix it is to replace all / or \ with the platform specific + # dir seperator. + # + # note: \\\\ is actually just one \ indirected twice, once for python + # then again for re.sub + if Blender.sys.sep == '\\': + full_path = re.sub('/', '\\\\', full_path) + elif Blender.sys.sep == '/': + full_path = re.sub('\\\\', '/', full_path) + + filename = Blender.sys.basename(full_path) + return filename + + def find(self, full_path): + if full_path == '': + return None + + # Seperate out the path. + dirname = Blender.sys.dirname(full_path) + + # Try it first. + if Blender.sys.exists(full_path): + if not dirname in self.search_dirs: + self.search_dirs.append(dirname) + return full_path + + # Maybe it's relative. + for path in self.search_dirs: + rel_full_path = Blender.sys.join(path, full_path) + if Blender.sys.exists(rel_full_path): + return rel_full_path + + # Search previous directories that have worked. + filename = self.strip_path(full_path) + for path in self.search_dirs: + t = Blender.sys.join(path, filename) + if Blender.sys.exists(t): + return t + + # Ask user where it is. + self.user_input = Blender.Draw.PupStrInput(filename + "? ", '', 100) + #self.user_input = None + if self.user_input != None: + t = Blender.sys.join(self.user_input, filename) + if Blender.sys.exists(t): + user_dirname = Blender.sys.dirname(t) + if not user_dirname in self.search_dirs: + self.search_dirs.append(user_dirname) + return t + + # Couldn't find it. + return None + + def __init__(self): + self.user_input = '' + self.current_file = '' + self.search_dirs = [] + + dir = Blender.Get('texturesdir') + if dir != None and dir != '': + self.search_dirs.append(dir) + + dir = Blender.sys.dirname(Blender.Get('filename')) + if dir != None and dir != '': + print dir + self.search_dirs.append(dir) + \ No newline at end of file diff --git a/release/scripts/flt_import.py b/release/scripts/flt_import.py new file mode 100644 index 00000000000..ca0db650447 --- /dev/null +++ b/release/scripts/flt_import.py @@ -0,0 +1,1890 @@ +#!BPY +""" Registration info for Blender menus: +Name: 'OpenFlight (.flt)...' +Blender: 238 +Group: 'Import' +Tip: 'Import OpenFlight (.flt)' +""" + +__author__ = "Greg MacDonald, Campbell Barton" +__version__ = "1.2 10/20/05" +__url__ = ("blender", "elysiun", "Author's homepage, http://sourceforge.net/projects/blight/") +__bpydoc__ = """\ +This script imports OpenFlight files into Blender. OpenFlight is a +registered trademark of MultiGen-Paradigm, Inc. + +Run from "File->Import" menu. + +Options are available from Blender's "Scripts Config Editor," accessible through +the "Scripts->System" menu from the scripts window. + +All global_prefs are toggle switches that let the user choose what is imported. Most +are straight-forward, but one option could be a source of confusion. The +"Diffuse Color From Face" option when set pulls the diffuse color from the face +colors. Otherwise the diffuse color comes from the material. What may be +confusing is that this global_prefs only works if the "Diffuse Color" option is set. + +New Features:
+* Importer is 14 times faster.
+* External triangle module is no longer required, but make sure the importer +has a 3d View screen open while its running or triangulation won't work.
+* Should be able to import all versions of flight files. + +Features:
+* Heirarchy retained.
+* First texture imported.
+* Colors imported from face or material.
+* LOD seperated out into different layers.
+* Asks for location of unfound textures or external references.
+* Searches Blender's texture directory in the user preferences panel.
+* Triangles with more than 4 verts are triangulated if the Triangle python +module is installed.
+* Matrix transforms imported.
+* External references to whole files are imported. + +Things To Be Aware Of:
+* Each new color and face attribute creates a new material and there are only a maximum of 16 +materials per object.
+* For triangulated faces, normals must be recomputed outward manually by typing +CTRL+N in edit mode.
+* You can change global_prefs only after an initial import.
+* External references are imported as geometry and will be exported that way.
+* A work around for not using the Triangle python module is to simply to +triangulate in Creator before importing. This is only necessary if your +model contains 5 or more vertices.
+* You have to manually blend the material color with the texture color. + +What's Not Handled:
+* Special texture repeating modes.
+* Replications and instancing.
+* Comment and attribute fields.
+* Light points.
+* Animations.
+* External references to a node within a file.
+* Multitexturing.
+* Vetex colors.
+""" + +# flt_import.py is an OpenFlight importer for blender. +# Copyright (C) 2005 Greg MacDonald +# +# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +import Blender +import os +import BPyMesh +import BPyImage +import flt_filewalker + +Vector= Blender.Mathutils.Vector + +def col_to_gray(c): + return 0.3*c[0] + 0.59*c[1] + 0.11*c[2] + + +global_prefs = dict() +global_prefs['verbose']= 1 +global_prefs['get_texture'] = True +global_prefs['get_diffuse'] = True +global_prefs['get_specular'] = False +global_prefs['get_emissive'] = False +global_prefs['get_alpha'] = True +global_prefs['get_ambient'] = False +global_prefs['get_shininess'] = True +global_prefs['color_from_face'] = True +global_prefs['fltfile']= '' +msg_once = False + +class MaterialDesc: + # Was going to use int(f*1000.0) instead of round(f,3), but for some reason + # round produces better results, as in less dups. + def make_key(self): + key = list() + if global_prefs['get_texture']: + if self.tex0: + key.append(self.tex0.getName()) + else: + key.append(None) + + if global_prefs['get_alpha']: + key.append(round(self.alpha, 3)) + else: + key.append(None) + + if global_prefs['get_shininess']: + key.append(round(self.shininess, 3)) + else: + key.append(None) + + if global_prefs['get_emissive']: + key.append(round(self.emissive, 3)) + else: + key.append(None) + + if global_prefs['get_ambient']: + key.append(round(self.ambient, 3)) + else: + key.append(None) + + if global_prefs['get_specular']: + for n in self.specular: + key.append(round(n, 3)) + else: + key.extend([None, None, None]) + + if global_prefs['get_diffuse']: + for n in self.diffuse: + key.append(round(n, 3)) + else: + key.extend([None, None, None]) + +# key.extend(self.face_props.values()) + + return tuple(key) + + def __init__(self): + self.name = 'Material' + # Colors, List of 3 floats. + self.diffuse = [1.0, 1.0, 1.0] + self.specular = [1.0, 1.0, 1.0] + + # Scalars + self.ambient = 0.0 # [0.0, 1.0] + self.emissive = 0.0 # [0.0, 1.0] + self.shininess = 0.5 # Range is [0.0, 2.0] + self.alpha = 1.0 # Range is [0.0, 1.0] + + self.tex0 = None + + # OpenFlight Face attributes + self.face_props = dict.fromkeys(['comment', 'ir color', 'priority', + 'draw type', 'texture white', 'template billboard', + 'smc', 'fid', 'ir material', 'lod generation control', + 'flags', 'light mode']) + +class VertexDesc: + def make_key(self): + return round(self.x, 6), round(self.y, 6), round(self.z, 6) + + def __init__(self): + + # Assign later, save memory, all verts have a loc + self.x = 0.0 + self.y = 0.0 + self.z = 0.0 + + ''' # IGNORE_NORMALS + self.nx = 0.0 + self.ny = 1.0 + self.nz = 0.0 + ''' + self.uv= Vector(0,0) + self.r = 1.0 + self.g = 1.0 + self.b = 1.0 + self.a = 1.0 + +class LightPointAppDesc: + def make_key(self): + d = dict(self.props) + del d['id'] + del d['type'] + + if d['directionality'] != 0: # not omni + d['nx'] = 0.0 + d['ny'] = 0.0 + d['nz'] = 0.0 + + return tuple(d.values()) + + def __init__(self): + self.props = dict() + self.props.update({'type': 'LPA'}) + self.props.update({'id': 'ap'}) + # Attribs not found in inline lightpoint. + self.props.update({'visibility range': 0.0}) + self.props.update({'fade range ratio': 0.0}) + self.props.update({'fade in duration': 0.0}) + self.props.update({'fade out duration': 0.0}) + self.props.update({'LOD range ratio': 0.0}) + self.props.update({'LOD scale': 0.0}) + +class GlobalResourceRepository: + def request_lightpoint_app(self, desc): + match = self.light_point_app.get(desc.make_key()) + + if match: + return match.getName() + else: + # Create empty and fill with properties. + name = desc.props['type'] + ': ' + desc.props['id'] + object = Blender.Object.New('Empty', name) + scene.link(object) + object.Layers= current_layer + object.sel= 1 + + # Attach properties + for name, value in desc.props.iteritems(): + object.addProperty(name, value) + + self.light_point_app.update({desc.make_key(): object}) + + return object.getName() + + # Dont use request_vert - faster to make it from the vector direct. + """ + def request_vert(self, desc): + match = self.vert_dict.get(desc.make_key()) + + if match: + return match + else: + vert = Blender.Mathutils.Vector(desc.x, desc.y, desc.z) + ''' IGNORE_NORMALS + vert.no[0] = desc.nx + vert.no[1] = desc.ny + vert.no[2] = desc.nz + ''' + self.vert_dict.update({desc.make_key(): vert}) + return vert + """ + def request_mat(self, mat_desc): + match = self.mat_dict.get(mat_desc.make_key()) + if match: return match + + mat = Blender.Material.New(mat_desc.name) + + if mat_desc.tex0 != None: + mat.setTexture(0, mat_desc.tex0, Blender.Texture.TexCo.UV) + + mat.setAlpha(mat_desc.alpha) + mat.setSpec(mat_desc.shininess) + mat.setHardness(255) + mat.setEmit(mat_desc.emissive) + mat.setAmb(mat_desc.ambient) + mat.setSpecCol(mat_desc.specular) + mat.setRGBCol(mat_desc.diffuse) + + # Create a text object to store openflight face attribs until + # user properties can be set on materials. +# t = Blender.Text.New('FACE: ' + mat.getName()) +# +# for name, value in mat_desc.face_props.items(): +# t.write(name + '\n' + str(value) + '\n\n') + + self.mat_dict.update({mat_desc.make_key(): mat}) + + return mat + + def request_image(self, filename_with_path): + if not global_prefs['get_texture']: return None + return BPyImage.comprehensiveImageLoad(filename_with_path, global_prefs['fltfile']) # Use join in case of spaces + + def request_texture(self, image): + if not global_prefs['get_texture']: + return None + + tex = self.tex_dict.get(image.filename) + if tex: return tex + + tex = Blender.Texture.New(Blender.sys.basename(image.filename)) + tex.setImage(image) + tex.setType('Image') + self.tex_dict.update({image.filename: tex}) + return tex + + def __init__(self): + # material + self.mat_dict = dict() + mat_lst = Blender.Material.Get() + for mat in mat_lst: + mat_desc = MaterialDesc() + mapto_lst = mat.getTextures() + if mapto_lst[0]: + mat_desc.tex0 = mapto_lst[0].tex + else: + mat_desc.tex0 = None + mat_desc.alpha = mat.getAlpha() + mat_desc.shininess = mat.getSpec() + mat_desc.emissive = mat.getEmit() + mat_desc.ambient = mat.getAmb() + mat_desc.specular = mat.getSpecCol() + mat_desc.diffuse = mat.getRGBCol() + + self.mat_dict.update({mat_desc.make_key(): mat}) + + # texture + self.tex_dict = dict() + tex_lst = Blender.Texture.Get() + + for tex in tex_lst: + img = tex.getImage() + # Only interested in textures with images. + if img: + self.tex_dict.update({img.filename: tex}) + + # vertex + # self.vert_dict = dict() + + # light point + self.light_point_app = dict() + +# Globals +GRR = GlobalResourceRepository() +FF = flt_filewalker.FileFinder() +scene = Blender.Scene.GetCurrent() # just hope they dont chenge scenes once the file selector pops up. +current_layer = 0x01 + + +# Opcodes that indicate its time to return control to parent. +throw_back_opcodes = [2, 73, 4, 11, 96, 14, 91, 98, 63] +do_not_report_opcodes = [76, 78, 79, 80, 81, 82, 94, 83, 33, 112, 100, 101, 102, 97, 31, 103, 104, 117, 118, 120, 121, 124, 125] + +opcode_name = { 0: 'db', + 1: 'head', + 2: 'grp', + 4: 'obj', + 5: 'face', + 10: 'push', + 11: 'pop', + 14: 'dof', + 19: 'push sub', + 20: 'pop sub', + 21: 'push ext', + 22: 'pop ext', + 23: 'cont', + 31: 'comment', + 32: 'color pal', + 33: 'long id', + 49: 'matrix', + 50: 'vector', + 52: 'multi-tex', + 53: 'uv lst', + 55: 'bsp', + 60: 'rep', + 61: 'inst ref', + 62: 'inst def', + 63: 'ext ref', + 64: 'tex pal', + 67: 'vert pal', + 68: 'vert w col', + 69: 'vert w col & norm', + 70: 'vert w col, norm & uv', + 71: 'vert w col & uv', + 72: 'vert lst', + 73: 'lod', + 74: 'bndin box', + 76: 'rot edge', + 78: 'trans', + 79: 'scl', + 80: 'rot pnt', + 81: 'rot and/or scale pnt', + 82: 'put', + 83: 'eyepoint & trackplane pal', + 84: 'mesh', + 85: 'local vert pool', + 86: 'mesh prim', + 87: 'road seg', + 88: 'road zone', + 89: 'morph vert lst', + 90: 'link pal', + 91: 'snd', + 92: 'rd path', + 93: 'snd pal', + 94: 'gen matrix', + 95: 'txt', + 96: 'sw', + 97: 'line styl pal', + 98: 'clip reg', + 100: 'ext', + 101: 'light src', + 102: 'light src pal', + 103: 'reserved', + 104: 'reserved', + 105: 'bndin sph', + 106: 'bndin cyl', + 107: 'bndin hull', + 108: 'bndin vol cntr', + 109: 'bndin vol orient', + 110: 'rsrvd', + 111: 'light pnt', + 112: 'tex map pal', + 113: 'mat pal', + 114: 'name tab', + 115: 'cat', + 116: 'cat dat', + 117: 'rsrvd', + 118: 'rsrvd', + 119: 'bounding hist', + 120: 'rsrvd', + 121: 'rsrvd', + 122: 'push attrib', + 123: 'pop attrib', + 124: 'rsrvd', + 125: 'rsrvd', + 126: 'curv', + 127: 'road const', + 128: 'light pnt appear pal', + 129: 'light pnt anim pal', + 130: 'indexed lp', + 131: 'lp sys', + 132: 'indx str', + 133: 'shdr pal'} + +class Handler: + def in_throw_back_lst(self, opcode): + return opcode in self.throw_back_lst + + def handle(self, opcode): + return self.handler[opcode]() + + def handles(self, opcode): + return opcode in self.handler.iterkeys() + + def throws_back_all_unhandled(self): + return self.throw_back_unhandled + + def set_throw_back_lst(self, a): + self.throw_back_lst = a + + def set_throw_back_all_unhandled(self): + self.throw_back_unhandled = True + + def set_only_throw_back_specified(self): + self.throw_back_unhandled = False + + def set_handler(self, d): + self.handler = d + + def __init__(self): + # Dictionary of opcodes to handler methods. + self.handler = dict() + # Send all opcodes not handled to the parent node. + self.throw_back_unhandled = False + # If throw_back_unhandled is False then only throw back + # if the opcodes in throw_back are encountered. + self.throw_back_lst = list() + +class Node: + def blender_import(self): + if self.opcode in opcode_name and global_prefs['verbose'] >= 2: + for i in xrange(self.get_level()): + print ' ', + print opcode_name[self.opcode], + print '-', self.props['id'], + print '-', self.props['comment'], + + print + + for child in self.children: + child.blender_import() + + # Import comment. +# if self.props['comment'] != '': +# name = 'COMMENT: ' + self.props['id'] +# t = Blender.Text.New(name) +# t.write(self.props['comment']) +# self.props['comment'] = name + + # Always ignore extensions and anything in between them. + def parse_push_extension(self): + self.saved_handler = self.active_handler + self.active_handler = self.extension_handler + return True + + def parse_pop_extension(self): + self.active_handler = self.saved_handler + return True + + def parse_push(self): + self.header.fw.up_level() + # Ignore unknown children. + self.ignore_unhandled = True + # Don't do child records that might overwrite parent info. ex: longid + self.active_handler = self.child_handler + return True + + def parse_pop(self): + self.header.fw.down_level() + + if self.header.fw.get_level() == self.level: + return False + + return True + + def parse(self): + while self.header.fw.begin_record(): + opcode = self.header.fw.get_opcode() + + # Print out info on opcode and tree level. + if global_prefs['verbose'] >= 3: + p = '' + for i in xrange(self.header.fw.get_level()): + p = p + ' ' + if opcode in opcode_name: + p = p + opcode_name[opcode] + else: + if global_prefs['verbose'] >= 1: + print 'undocumented opcode', opcode + continue + + if self.global_handler.handles(opcode): + if global_prefs['verbose'] >= 3: + print p + ' handled globally' + if self.global_handler.handle(opcode) == False: + break + + elif self.active_handler.handles(opcode): + if global_prefs['verbose'] >= 4: + print p + ' handled' + if self.active_handler.handle(opcode) == False: + break + + else: + if self.active_handler.throws_back_all_unhandled(): + if global_prefs['verbose'] >= 3: + print p + ' handled elsewhere' + self.header.fw.repeat_record() + break + + elif self.active_handler.in_throw_back_lst(opcode): + if global_prefs['verbose'] >= 3: + print p + ' handled elsewhere' + self.header.fw.repeat_record() + break + + else: + if global_prefs['verbose'] >= 3: + print p + ' ignored' + elif global_prefs['verbose'] >= 1 and not opcode in do_not_report_opcodes and opcode in opcode_name: + print opcode_name[opcode], 'not handled' + + def get_level(self): + return self.level + + def parse_long_id(self): + self.props['id'] = self.header.fw.read_string(self.header.fw.get_length()-4) + return True + + def parse_comment(self): + self.props['comment'] = self.header.fw.read_string(self.header.fw.get_length()-4) + return True + + def __init__(self, parent, header): + self.root_handler = Handler() + self.child_handler = Handler() + self.extension_handler = Handler() + self.global_handler = Handler() + + self.global_handler.set_handler({21: self.parse_push_extension}) + self.active_handler = self.root_handler + + # used by parse_*_extension + self.extension_handler.set_handler({22: self.parse_pop_extension}) + self.saved_handler = None + + self.header = header + self.children = list() + + self.parent = parent + + if parent: + parent.children.append(self) + + self.level = self.header.fw.get_level() + self.opcode = self.header.fw.get_opcode() + + self.props = {'id': 'unnamed', 'comment': '', 'type': 'untyped'} + +class VertexPalette(Node): + def __init__(self, parent): + Node.__init__(self, parent, parent.header) + self.root_handler.set_handler({68: self.parse_vertex_c, + 69: self.parse_vertex_cn, + 70: self.parse_vertex_cnuv, + 71: self.parse_vertex_cuv}) + self.root_handler.set_throw_back_all_unhandled() + + self.vert_desc_lst = list() + self.blender_verts = list() + self.offset = 8 + # Used to create a map from byte offset to vertex index. + self.index = dict() + + + def blender_import(self): + self.blender_verts.extend([Vector(vert_desc.x, vert_desc.y, vert_desc.z) for vert_desc in self.vert_desc_lst ]) + + def parse_vertex_common(self): + # Add this vertex to an offset to index dictionary. + #self.index_lst.append( (self.offset, self.next_index) ) + self.index[self.offset]= len(self.index) + + # Get ready for next record. + self.offset += self.header.fw.get_length() + + v = VertexDesc() + + self.header.fw.read_ahead(2) + v.flags = self.header.fw.read_short() + + v.x = self.header.fw.read_double() + v.y = self.header.fw.read_double() + v.z = self.header.fw.read_double() + + return v + + def parse_vertex_post_common(self, v): + if not v.flags & 0x2000: # 0x2000 = no color + if v.flags & 0x1000: # 0x1000 = packed color + v.a = self.header.fw.read_uchar() + v.b = self.header.fw.read_uchar() + v.g = self.header.fw.read_uchar() + v.r = self.header.fw.read_uchar() + else: + self.header.fw.read_ahead(4) + + color_index = self.header.fw.read_uint() + v.r, v.g, v.b, v.a= self.header.get_color(color_index) + + self.vert_desc_lst.append(v) + + return True + + def parse_vertex_c(self): + v = self.parse_vertex_common() + + self.parse_vertex_post_common(v) + + return True + + def parse_vertex_cn(self): + v = self.parse_vertex_common() + + ''' + v.nx = self.header.fw.read_float() + v.ny = self.header.fw.read_float() + v.nz = self.header.fw.read_float() + ''' + # Just to advance + self.header.fw.read_float() + self.header.fw.read_float() + self.header.fw.read_float() + + self.parse_vertex_post_common(v) + + return True + + def parse_vertex_cuv(self): + v = self.parse_vertex_common() + + v.uv[:] = self.header.fw.read_float(), self.header.fw.read_float() + + self.parse_vertex_post_common(v) + + return True + + def parse_vertex_cnuv(self): + v = self.parse_vertex_common() + ''' + v.nx = self.header.fw.read_float() + v.ny = self.header.fw.read_float() + v.nz = self.header.fw.read_float() + ''' + # Just to advance + self.header.fw.read_float() + self.header.fw.read_float() + self.header.fw.read_float() + + v.uv[:] = self.header.fw.read_float(), self.header.fw.read_float() + + self.parse_vertex_post_common(v) + + return True + + def parse(self): # Run once per import + Node.parse(self) + +class InterNode(Node): + def __init__(self): + self.object = None + self.mesh = None + self.isMesh = False + self.faceLs= [] + self.matrix = None + + def blender_import_my_faces(self): + + # Add the verts onto the mesh + mesh = self.mesh + blender_verts= self.header.vert_pal.blender_verts + vert_desc_lst= self.header.vert_pal.vert_desc_lst + + vert_list= [ i for flt_face in self.faceLs for i in flt_face.indices] + + mesh.verts.extend([blender_verts[i] for i in vert_list]) + + + new_faces= [] + new_faces_props= [] + ngon= BPyMesh.ngon + vert_index= 1 + for flt_face in self.faceLs: + material_index= flt_face.blen_mat_idx + image= flt_face.blen_image + + face_len= len(flt_face.indices) + + # Get the indicies in reference to the mesh. + + uvs= [vert_desc_lst[j].uv for j in flt_face.indices] + if face_len <=4: # tri or quad + new_faces.append( [i+vert_index for i in xrange(face_len)] ) + new_faces_props.append((material_index, image, uvs)) + + else: # fgon + mesh_face_indicies = [i+vert_index for i in xrange(face_len)] + tri_ngons= ngon(mesh, mesh_face_indicies) + new_faces.extend([ [mesh_face_indicies[t] for t in tri] for tri in tri_ngons]) + new_faces_props.extend( [ (material_index, image, (uvs[tri[0]], uvs[tri[1]], uvs[tri[2]]) ) for tri in tri_ngons ] ) + + vert_index+= face_len + + mesh.faces.extend(new_faces) + + try: mesh.faceUV= True + except: pass + + for i, f in enumerate(mesh.faces): + f.mat, f.image, f.uv= new_faces_props[i] + + def blender_import(self): +# name = self.props['type'] + ': ' + self.props['id'] + name = self.props['id'] + if self.isMesh: + self.object = Blender.Object.New('Mesh', name) + #self.mesh = self.object.getData() + self.mesh = Blender.Mesh.New() + self.mesh.verts.extend( Vector() ) # DUMMYVERT + self.object.link(self.mesh) + else: + self.object = Blender.Object.New('Empty', name) + + if self.parent: + self.parent.object.makeParent([self.object]) + + scene.link(self.object) + self.object.Layer = current_layer + self.object.sel = 1 + + Node.blender_import(self) # Attach faces to self.faceLs + + if self.isMesh: + # Add all my faces into the mesh at once + self.blender_import_my_faces() + + if self.matrix: + self.object.setMatrix(self.matrix) + + # Attach properties + #for name, value in self.props.items(): + # self.object.addProperty(name, value) + + def parse_face(self): + child = Face(self) + child.parse() + return True + + def parse_group(self): + child = Group(self) + child.parse() + return True + + def move_to_next_layer(self): + global current_layer + current_layer = current_layer << 1 + if current_layer > 0x80000: + current_layer = 1 + + def parse_lod(self): + child = LOD(self) + child.parse() + return True + + def parse_unhandled(self): + child = Unhandled(self) + child.parse() + return True + + def parse_object(self): + child = Object(self) + child.parse() + return True + + def parse_xref(self): + child = XRef(self) + child.parse() + return True + + def parse_indexed_light_point(self): + child = IndexedLightPoint(self) + child.parse() + return True + + def parse_inline_light_point(self): + child = InlineLightPoint(self) + child.parse() + return True + + def parse_matrix(self): + m = list() + for i in xrange(4): + m.append([]) + for j in xrange(4): + f = self.header.fw.read_float() + m[i].append(f) + self.matrix = Blender.Mathutils.Matrix(m[0], m[1], m[2], m[3]) + +EDGE_FGON= Blender.Mesh.EdgeFlags['FGON'] +FACE_TEX= Blender.Mesh.FaceModes['TEX'] + +class Face(Node): + def __init__(self, parent): + Node.__init__(self, parent, parent.header) + self.root_handler.set_handler({31: self.parse_comment, + 10: self.parse_push}) + self.root_handler.set_throw_back_lst(throw_back_opcodes) + + self.child_handler.set_handler({72: self.parse_vertex_list, + 10: self.parse_push, + 11: self.parse_pop}) + + if parent: + parent.isMesh = True + + self.indices = list() # face verts here + + self.comment = '' + self.props = dict.fromkeys(['ir color', 'priority', + 'draw type', 'texture white', 'template billboard', + 'smc', 'fid', 'ir material', 'lod generation control', + 'flags', 'light mode']) + + self.header.fw.read_ahead(8) # face id + # Load face. + self.props['ir color'] = self.header.fw.read_int() + self.props['priority'] = self.header.fw.read_short() + self.props['draw type'] = self.header.fw.read_char() + self.props['texture white'] = self.header.fw.read_char() + self.header.fw.read_ahead(4) # color name indices + self.header.fw.read_ahead(1) # reserved + self.props['template billboard'] = self.header.fw.read_uchar() + self.detail_tex_index = self.header.fw.read_short() + self.tex_index = self.header.fw.read_short() + self.mat_index = self.header.fw.read_short() + self.props['smc'] = self.header.fw.read_short() + self.props['fid'] = self.header.fw.read_short() + self.props['ir material'] = self.header.fw.read_int() + self.alpha = 1.0 - float(self.header.fw.read_ushort()) / 65535.0 + self.props['lod generation control'] = self.header.fw.read_uchar() + self.header.fw.read_ahead(1) # line style index + self.props['flags'] = self.header.fw.read_int() + self.props['light mode'] = self.header.fw.read_uchar() + self.header.fw.read_ahead(7) + a = self.header.fw.read_uchar() + b = self.header.fw.read_uchar() + g = self.header.fw.read_uchar() + r = self.header.fw.read_uchar() + self.packed_color = [r, g, b, a] + a = self.header.fw.read_uchar() + b = self.header.fw.read_uchar() + g = self.header.fw.read_uchar() + r = self.header.fw.read_uchar() + self.alt_packed_color = [r, g, b, a] + self.tex_map_index = self.header.fw.read_short() + self.header.fw.read_ahead(2) + self.color_index = self.header.fw.read_uint() + self.alt_color_index = self.header.fw.read_uint() + #self.header.fw.read_ahead(2) + #self.shader_index = self.header.fw.read_short() + + + """ + def blender_import_face(self, material_index, image): + + + mesh = self.parent.mesh + face_len= len(self.indices) + + mesh_vert_len_orig= len(mesh.verts) + mesh.verts.extend([ self.header.vert_pal.blender_verts[i] for i in self.indices]) + + # Exception for an edge + if face_len==2: + mesh.edges.extend((mesh.verts[-1], mesh.verts[-2])) + return + + + mesh_face_indicies = range(mesh_vert_len_orig, mesh_vert_len_orig+face_len) + + #print mesh_face_indicies , 'mesh_face_indicies ' + + # First we need to triangulate NGONS + if face_len>4: + tri_indicies = [[i+mesh_vert_len_orig for i in t] for t in BPyMesh.ngon(mesh, mesh_face_indicies) ] # use range because the verts are in order. + else: + tri_indicies= [mesh_face_indicies] # can be a quad but thats ok + + # Extend face or ngon + + mesh.faces.extend(tri_indicies) + #print mesh.faces, 'mesh.faces' + mesh.faceUV= True + + # Now set UVs + for i in xrange(len(mesh.faces)-len(tri_indicies), len(mesh.faces)): + f= mesh.faces[i] + f_v= f.v + for j, uv in enumerate(f.uv): + vertex_index_flt= self.indices[f_v[j].index - mesh_vert_len_orig] + + vert_desc = self.header.vert_pal.vert_desc_lst[vertex_index_flt] + uv.x, uv.y= vert_desc.u, vert_desc.v + + # Only a bug in 2.42, fixed in cvs + for c in f.col: + c.r=c.g=c.b= 255 + + f.mat = material_index + if image: + f.image = image + else: + f.mode &= ~FACE_TEX + + # FGon + + if face_len>4: + # Add edges we know are not fgon + end_index= len(mesh.verts) + start_index= end_index - len(self.indices) + edge_dict= dict([ ((i, i+1), None) for i in xrange(start_index, end_index-1)]) + edge_dict[(start_index, end_index)]= None # wish this was a set + + fgon_edges= {} + for tri in tri_indicies: + for i in (0,1,2): + i1= tri[i] + i2= tri[i-1] + + # Sort + if i1>i2: + i1,i2= i2,i1 + + if not edge_dict.has_key( (i1,i2) ): # if this works its an edge vert + fgon_edges[i1,i2]= None + + + # Now set fgon flags + for ed in mesh.edges: + i1= ed.v1.index + i2= ed.v2.index + if i1>i2: + i1,i2= i2,i1 + + if fgon_edges.has_key( (i1,i2) ): + # This is an edge tagged for fgonning? + fgon_edges[i1, i2] + ed.flag |= EDGE_FGON + del fgon_edges[i1, i2] # make later searches faster? + + if not fgon_edges: + break + """ + + def parse_comment(self): + self.comment = self.header.fw.read_string(self.header.fw.get_length()-4) + return True + + # returns a tuple (material, image) where material is the blender material and + # image is the blender image or None. + def create_blender_material(self): + # Create face material. + mat_desc = MaterialDesc() + + if self.mat_index != -1: + if not self.mat_index in self.header.mat_desc_pal: + if global_prefs['verbose'] >= 1: + #print 'Warning: Material index', self.mat_index, 'not in material palette.' + pass + else: + mat_pal_desc = self.header.mat_desc_pal[self.mat_index] + mat_desc.alpha = mat_pal_desc.alpha * self.alpha # combine face and mat alphas + mat_desc.ambient = mat_pal_desc.ambient + mat_desc.diffuse = mat_pal_desc.diffuse + mat_desc.specular = mat_pal_desc.specular + mat_desc.emissive = mat_pal_desc.emissive + mat_desc.shininess = mat_pal_desc.shininess + else: + # if no material get alpha from just face. + mat_desc.alpha = self.alpha + + # Color. + if global_prefs['color_from_face']: + color = None + if not self.props['flags'] & 0x40000000: + if self.props['flags'] & 0x10000000: # packed color + color = self.packed_color + else: + color = self.header.get_color(self.color_index) + + if color: + r = float(color[0])/255.0 + g = float(color[1])/255.0 + b = float(color[2])/255.0 + mat_desc.diffuse = [r, g, b] + + # Texture + image = None + if self.tex_index != -1 and self.tex_index in self.header.bl_tex_pal: + mat_desc.tex0 = self.header.bl_tex_pal[self.tex_index] + if mat_desc.tex0: + mat_desc.name = FF.strip_path(self.header.tex_pal[self.tex_index]) + image = mat_desc.tex0.image + + # OpenFlight Face Attributes + mat_desc.face_props = self.props + + # Get material. + mat = GRR.request_mat(mat_desc) + + # Add material to mesh. + mesh = self.parent.mesh + + # Return where it is in the mesh for faces. + mesh_materials= mesh.materials + + material_index= -1 + for i,m in enumerate(mesh_materials): + if m.name==mat.name: + material_index= i + break + + if material_index==-1: + material_index= len(mesh_materials) + if material_index==16: + material_index= 15 + if global_prefs['verbose'] >= 1: + print 'Warning: Too many materials per mesh object. Only a maximum of 16 ' + \ + 'allowed. Using 16th material instead.' + + else: + mesh_materials.append(mat) + mesh.materials= mesh_materials + + return (material_index, image) + + + def blender_import(self): + vert_count = len(self.indices) + if vert_count < 3: + if global_prefs['verbose'] >= 2: + print 'Warning: Ignoring face with no vertices.' + return + + # Assign material and image + + self.parent.faceLs.append(self) + self.blen_mat_idx, self.blen_image= self.create_blender_material() + + + + + # Store comment info in parent. + if self.comment != '': + if self.parent.props['comment'] != '': + self.parent.props['comment'] += '\n\nFrom Face:\n' + self.comment + else: + self.parent.props['comment'] = self.comment + + def parse_vertex_list(self): + length = self.header.fw.get_length() + fw = self.header.fw + vert_pal = self.header.vert_pal + + count = (length-4)/4 + + # If this ever fails the chunk below does error checking + self.indices= [vert_pal.index[fw.read_int()] for i in xrange(count)] + ''' + for i in xrange(count): + byte_offset = fw.read_int() + if byte_offset in vert_pal.index: + index = vert_pal.index[byte_offset] + self.indices.append(index) + elif global_prefs['verbose'] >= 1: + print 'Warning: Unable to map byte offset %s' + \ + ' to vertex index.' % byte_offset + ''' + return True + + +class Object(InterNode): + def __init__(self, parent): + Node.__init__(self, parent, parent.header) + InterNode.__init__(self) + + self.root_handler.set_handler({33: self.parse_long_id, + 31: self.parse_comment, + 10: self.parse_push, + 49: self.parse_matrix}) + self.root_handler.set_throw_back_lst(throw_back_opcodes) + + self.child_handler.set_handler({5: self.parse_face, + #130: self.parse_indexed_light_point, + #111: self.parse_inline_light_point, + 10: self.parse_push, + 11: self.parse_pop}) + + self.props['type'] = 'Object' + self.props['id'] = self.header.fw.read_string(8) + + + +class Group(InterNode): + def __init__(self, parent): + Node.__init__(self, parent, parent.header) + InterNode.__init__(self) + + self.root_handler.set_handler({33: self.parse_long_id, + 31: self.parse_comment, + 10: self.parse_push, + 49: self.parse_matrix}) + self.root_handler.set_throw_back_lst(throw_back_opcodes) + + self.child_handler.set_handler({5: self.parse_face, + #130: self.parse_indexed_light_point, + #111: self.parse_inline_light_point, + 2: self.parse_group, + 73: self.parse_lod, + 4: self.parse_object, + 10: self.parse_push, + 11: self.parse_pop, + 96: self.parse_unhandled, + 14: self.parse_unhandled, + 91: self.parse_unhandled, + 98: self.parse_unhandled, + 63: self.parse_xref}) + self.props = dict.fromkeys(['type', 'id', 'comment', 'priority', 'flags', 'special1', + 'special2', 'significance', 'layer code', 'loop count', + 'loop duration', 'last frame duration']) + + self.props['type'] = 'Group' + self.props['comment'] = '' + self.props['id'] = self.header.fw.read_string(8) + self.props['priority'] = self.header.fw.read_short() + self.header.fw.read_ahead(2) + self.props['flags'] = self.header.fw.read_int() + self.props['special1'] = self.header.fw.read_short() + self.props['special2'] = self.header.fw.read_short() + self.props['significance'] = self.header.fw.read_short() + self.props['layer code'] = self.header.fw.read_char() + self.header.fw.read_ahead(5) + self.props['loop count'] = self.header.fw.read_int() + self.props['loop duration'] = self.header.fw.read_float() + self.props['last frame duration'] = self.header.fw.read_float() + +class XRef(InterNode): + def parse(self): + if self.xref: + self.xref.parse() + Node.parse(self) + + def __init__(self, parent): + Node.__init__(self, parent, parent.header) + InterNode.__init__(self) + + self.root_handler.set_handler({49: self.parse_matrix}) + self.root_handler.set_throw_back_lst(throw_back_opcodes) + + xref_filename = self.header.fw.read_string(200) + filename = FF.find(xref_filename) + + self.props['type'] = 'XRef' + + if filename != None: + self.xref = Database(filename, self) + self.props['id'] = 'X: ' + Blender.sys.splitext(Blender.sys.basename(filename))[0] + else: + self.xref = None + self.props['id'] = 'X: broken' + +class LOD(InterNode): + def blender_import(self): + self.move_to_next_layer() + InterNode.blender_import(self) + + def __init__(self, parent): + Node.__init__(self, parent, parent.header) + InterNode.__init__(self) + + self.root_handler.set_handler({33: self.parse_long_id, + 31: self.parse_comment, + 10: self.parse_push, + 49: self.parse_matrix}) + self.root_handler.set_throw_back_lst(throw_back_opcodes) + + self.child_handler.set_handler({2: self.parse_group, + 73: self.parse_lod, + 4: self.parse_object, + 10: self.parse_push, + 11: self.parse_pop, + 96: self.parse_unhandled, # switch + 14: self.parse_unhandled, # DOF + 91: self.parse_unhandled, # sound + 98: self.parse_unhandled, # clip + 63: self.parse_xref}) + + self.props['type'] = 'LOD' + self.props['id'] = self.header.fw.read_string(8) + +class InlineLightPoint(InterNode): + def __init__(self, parent): + Node.__init__(self, parent, parent.header) + InterNode.__init__(self) + self.root_handler.set_handler({33: self.parse_long_id, + 31: self.parse_comment, + 10: self.parse_push, + 49: self.parse_matrix}) + self.root_handler.set_throw_back_lst(throw_back_opcodes) + + self.child_handler.set_handler({72: self.parse_vertex_list, + 10: self.parse_push, + 11: self.parse_pop}) + + self.indices = list() + + self.props = dict.fromkeys(['id', 'type', 'comment', 'draw order', 'appearance']) + self.app_props = dict() + + self.props['comment'] = '' + self.props['type'] = 'Light Point' + self.props['id'] = self.header.fw.read_string(8) + + self.app_props.update({'smc': self.header.fw.read_short()}) + self.app_props.update({'fid': self.header.fw.read_short()}) + self.app_props.update({'back color: a': self.header.fw.read_uchar()}) + self.app_props.update({'back color: b': self.header.fw.read_uchar()}) + self.app_props.update({'back color: g': self.header.fw.read_uchar()}) + self.app_props.update({'back color: r': self.header.fw.read_uchar()}) + self.app_props.update({'display mode': self.header.fw.read_int()}) + self.app_props.update({'intensity': self.header.fw.read_float()}) + self.app_props.update({'back intensity': self.header.fw.read_float()}) + self.app_props.update({'minimum defocus': self.header.fw.read_float()}) + self.app_props.update({'maximum defocus': self.header.fw.read_float()}) + self.app_props.update({'fading mode': self.header.fw.read_int()}) + self.app_props.update({'fog punch mode': self.header.fw.read_int()}) + self.app_props.update({'directional mode': self.header.fw.read_int()}) + self.app_props.update({'range mode': self.header.fw.read_int()}) + self.app_props.update({'min pixel size': self.header.fw.read_float()}) + self.app_props.update({'max pixel size': self.header.fw.read_float()}) + self.app_props.update({'actual size': self.header.fw.read_float()}) + self.app_props.update({'trans falloff pixel size': self.header.fw.read_float()}) + self.app_props.update({'trans falloff exponent': self.header.fw.read_float()}) + self.app_props.update({'trans falloff scalar': self.header.fw.read_float()}) + self.app_props.update({'trans falloff clamp': self.header.fw.read_float()}) + self.app_props.update({'fog scalar': self.header.fw.read_float()}) + self.app_props.update({'fog intensity': self.header.fw.read_float()}) + self.app_props.update({'size threshold': self.header.fw.read_float()}) + self.app_props.update({'directionality': self.header.fw.read_int()}) + self.app_props.update({'horizontal lobe angle': self.header.fw.read_float()}) + self.app_props.update({'vertical lobe angle': self.header.fw.read_float()}) + self.app_props.update({'lobe roll angle': self.header.fw.read_float()}) + self.app_props.update({'dir falloff exponent': self.header.fw.read_float()}) + self.app_props.update({'dir ambient intensity': self.header.fw.read_float()}) + self.header.fw.read_ahead(12) # Animation settings. + self.app_props.update({'significance': self.header.fw.read_float()}) + self.props['draw order'] = self.header.fw.read_int() + self.app_props.update({'flags': self.header.fw.read_int()}) + #self.fw.read_ahead(12) # More animation settings. + + # return dictionary: lp_app name => index list + def group_points(self, props): + + name_to_indices = {} + + for i in self.indices: + vert_desc = self.header.vert_pal.vert_desc_lst[i] + app_desc = LightPointAppDesc() + app_desc.props.update(props) + # add vertex normal and color + app_desc.props.update({'nx': vert_desc.nx}) + app_desc.props.update({'ny': vert_desc.ny}) + app_desc.props.update({'nz': vert_desc.nz}) + + app_desc.props.update({'r': vert_desc.r}) + app_desc.props.update({'g': vert_desc.g}) + app_desc.props.update({'b': vert_desc.b}) + app_desc.props.update({'a': vert_desc.a}) + + app_name = GRR.request_lightpoint_app(app_desc) + + if name_to_indices.get(app_name): + name_to_indices[app_name].append(i) + else: + name_to_indices.update({app_name: [i]}) + + return name_to_indices + + def blender_import(self): + name = '%s: %s' % (self.props['type'], self.props['id']) + + name_to_indices = self.group_points(self.app_props) + + for app_name, indices in name_to_indices.iteritems(): + self.object = Blender.Object.New('Mesh', name) + #self.mesh = self.object.getData() + self.mesh= Blender.Mesh.New() + self.mesh.verts.extend( Vector() ) # DUMMYVERT + self.object.link(self.mesh) + + if self.parent: + self.parent.object.makeParent([self.object]) + + for i in indices: + vert = self.header.vert_pal.blender_verts[i] + self.mesh.verts.append(vert) + + scene.link(self.object) + self.object.Layer = current_layer + self.object.sel= 1 + + if self.matrix: + self.object.setMatrix(self.matrix) + + # Import comment. + if self.props['comment'] != '': + name = 'COMMENT: ' + self.props['id'] + t = Blender.Text.New(name) + t.write(self.props['comment']) + self.props['comment'] = name + + # Attach properties. + self.props.update({'appearance': app_name}) + for name, value in self.props.iteritems(): + self.object.addProperty(name, value) + + self.mesh.update() + + def parse_vertex_list(self): + length = self.header.fw.get_length() + fw = self.header.fw + vert_pal = self.header.vert_pal + + count = (length-4)/4 + + # If this ever fails the chunk below does error checking + self.indices= [vert_pal.index[fw.read_int()] for i in xrange(count)] + + ''' + for i in xrange(count): + byte_offset = fw.read_int() + if byte_offset in vert_pal.index: + index = vert_pal.index[byte_offset] + self.indices.append(index) + elif global_prefs['verbose'] >= 1: + print 'Warning: Unable to map byte offset %s' + \ + ' to vertex index.' % byte_offset + ''' + + return True + + + +class IndexedLightPoint(InterNode): + # return dictionary: lp_app name => index list + def group_points(self, props): + + name_to_indices = {} + + for i in self.indices: + vert_desc = self.header.vert_pal.vert_desc_lst[i] + app_desc = LightPointAppDesc() + app_desc.props.update(props) + # add vertex normal and color + app_desc.props.update({'nx': vert_desc.nx}) + app_desc.props.update({'ny': vert_desc.ny}) + app_desc.props.update({'nz': vert_desc.nz}) + + app_desc.props.update({'r': vert_desc.r}) + app_desc.props.update({'g': vert_desc.g}) + app_desc.props.update({'b': vert_desc.b}) + app_desc.props.update({'a': vert_desc.a}) + + app_name = GRR.request_lightpoint_app(app_desc) + + if name_to_indices.get(app_name): + name_to_indices[app_name].append(i) + else: + name_to_indices.update({app_name: [i]}) + + return name_to_indices + + def blender_import(self): + name = self.props['type'] + ': ' + self.props['id'] + + name_to_indices = self.group_points(self.header.lightpoint_appearance_pal[self.index]) + + for app_name, indices in name_to_indices.iteritems(): + self.object = Blender.Object.New('Mesh', name) + #self.mesh = self.object.getData() + self.mesh= Blender.Mesh.New() + self.mesh.verts.extend( Vector() ) # DUMMYVERT + self.object.link(self.mesh) + + if self.parent: + self.parent.object.makeParent([self.object]) + + for i in indices: + vert = self.header.vert_pal.blender_verts[i] + self.mesh.verts.append(vert) + + scene.link(self.object) + + self.object.Layer = current_layer + + if self.matrix: + self.object.setMatrix(self.matrix) + + # Import comment. + if self.props['comment'] != '': + name = 'COMMENT: ' + self.props['id'] + t = Blender.Text.New(name) + t.write(self.props['comment']) + self.props['comment'] = name + + # Attach properties. + self.props.update({'appearance': app_name}) + for name, value in self.props.iteritems(): + self.object.addProperty(name, value) + + self.mesh.update() + + def parse_vertex_list(self): + length = self.header.fw.get_length() + fw = self.header.fw + vert_pal = self.header.vert_pal + + count = (length-4)/4 + + # If this ever fails the chunk below does error checking + self.indices= [vert_pal.index[fw.read_int()] for i in xrange(count)] + + ''' + for i in xrange(count): + byte_offset = fw.read_int() + if byte_offset in vert_pal.index: + index = vert_pal.index[byte_offset] + self.indices.append(index) + elif global_prefs['verbose'] >= 1: + print 'Warning: Unable to map byte offset %s' + \ + ' to vertex index.' % byte_offset + ''' + return True + + def __init__(self, parent): + Node.__init__(self, parent, parent.header) + InterNode.__init__(self) + self.root_handler.set_handler({33: self.parse_long_id, + 31: self.parse_comment, + 10: self.parse_push, + 49: self.parse_matrix}) + self.root_handler.set_throw_back_lst(throw_back_opcodes) + + self.child_handler.set_handler({72: self.parse_vertex_list, + 10: self.parse_push, + 11: self.parse_pop}) + + self.indices = list() + + self.props = dict.fromkeys(['id', 'type', 'comment', 'draw order', 'appearance']) + self.props['comment'] = '' + self.props['type'] = 'Light Point' + self.props['id'] = self.header.fw.read_string(8) + self.index = self.header.fw.read_int() + self.header.fw.read_ahead(4) # animation index + self.props['draw order'] = self.header.fw.read_int() + +class Unhandled(InterNode): + def __init__(self, parent): + Node.__init__(self, parent, parent.header) + InterNode.__init__(self) + + self.root_handler.set_handler({33: self.parse_long_id, + 31: self.parse_comment, + 10: self.parse_push, + 49: self.parse_matrix}) + self.root_handler.set_throw_back_lst(throw_back_opcodes) + + self.child_handler.set_handler({2: self.parse_group, + 73: self.parse_lod, + 4: self.parse_object, + 10: self.parse_push, + 11: self.parse_pop, + 96: self.parse_unhandled, # switch + 14: self.parse_unhandled, # DOF + 91: self.parse_unhandled, # sound + 98: self.parse_unhandled, # clip + 63: self.parse_xref}) + + self.props['id'] = self.header.fw.read_string(8) + +class Database(InterNode): + def blender_import(self): + self.tex_pal = dict(self.tex_pal_lst) + del self.tex_pal_lst + + # Setup Textures + bl_tex_pal_lst = list() + for i in self.tex_pal.iterkeys(): + path_filename = FF.find(self.tex_pal[i]) + if path_filename != None: + img = GRR.request_image(path_filename) + if img: + tex = GRR.request_texture(img) + tex.setName(FF.strip_path(self.tex_pal[i])) + bl_tex_pal_lst.append( (i, tex) ) + else: + bl_tex_pal_lst.append( (i, None) ) + elif global_prefs['verbose'] >= 1: + print 'Warning: Unable to find', self.tex_pal[i] + + self.bl_tex_pal = dict(bl_tex_pal_lst) + + # Setup Materials + self.mat_desc_pal = dict(self.mat_desc_pal_lst) + + InterNode.blender_import(self) + + def parse_appearance_palette(self): + props = dict() + self.fw.read_ahead(4) # reserved + props.update({'id': self.fw.read_string(256)}) + index = self.fw.read_int() + props.update({'smc': self.fw.read_short()}) + props.update({'fid': self.fw.read_short()}) + props.update({'back color: a': self.fw.read_uchar()}) + props.update({'back color: b': self.fw.read_uchar()}) + props.update({'back color: g': self.fw.read_uchar()}) + props.update({'back color: r': self.fw.read_uchar()}) + props.update({'display mode': self.fw.read_int()}) + props.update({'intensity': self.fw.read_float()}) + props.update({'back intensity': self.fw.read_float()}) + props.update({'minimum defocus': self.fw.read_float()}) + props.update({'maximum defocus': self.fw.read_float()}) + props.update({'fading mode': self.fw.read_int()}) + props.update({'fog punch mode': self.fw.read_int()}) + props.update({'directional mode': self.fw.read_int()}) + props.update({'range mode': self.fw.read_int()}) + props.update({'min pixel size': self.fw.read_float()}) + props.update({'max pixel size': self.fw.read_float()}) + props.update({'actual size': self.fw.read_float()}) + props.update({'trans falloff pixel size': self.fw.read_float()}) + props.update({'trans falloff exponent': self.fw.read_float()}) + props.update({'trans falloff scalar': self.fw.read_float()}) + props.update({'trans falloff clamp': self.fw.read_float()}) + props.update({'fog scalar': self.fw.read_float()}) + props.update({'fog intensity': self.fw.read_float()}) + props.update({'size threshold': self.fw.read_float()}) + props.update({'directionality': self.fw.read_int()}) + props.update({'horizontal lobe angle': self.fw.read_float()}) + props.update({'vertical lobe angle': self.fw.read_float()}) + props.update({'lobe roll angle': self.fw.read_float()}) + props.update({'dir falloff exponent': self.fw.read_float()}) + props.update({'dir ambient intensity': self.fw.read_float()}) + props.update({'significance': self.fw.read_float()}) + props.update({'flags': self.fw.read_int()}) + props.update({'visibility range': self.fw.read_float()}) + props.update({'fade range ratio': self.fw.read_float()}) + props.update({'fade in duration': self.fw.read_float()}) + props.update({'fade out duration': self.fw.read_float()}) + props.update({'LOD range ratio': self.fw.read_float()}) + props.update({'LOD scale': self.fw.read_float()}) + + self.lightpoint_appearance_pal.update({index: props}) + + def parse_header(self): + self.props['type'] = 'Header' + self.props['comment'] = '' + self.props['id'] = self.fw.read_string(8) + self.props['version'] = self.fw.read_int() + self.fw.read_ahead(46) + self.props['units'] = self.fw.read_char() + self.props['set white'] = bool(self.fw.read_char()) + self.props['flags'] = self.fw.read_int() + self.fw.read_ahead(24) + self.props['projection type'] = self.fw.read_int() + self.fw.read_ahead(36) + self.props['sw x'] = self.fw.read_double() + self.props['sw y'] = self.fw.read_double() + self.props['dx'] = self.fw.read_double() + self.props['dy'] = self.fw.read_double() + self.fw.read_ahead(24) + self.props['sw lat'] = self.fw.read_double() + self.props['sw lon'] = self.fw.read_double() + self.props['ne lat'] = self.fw.read_double() + self.props['ne lon'] = self.fw.read_double() + self.props['origin lat'] = self.fw.read_double() + self.props['origin lon'] = self.fw.read_double() + self.props['lambert lat1'] = self.fw.read_double() + self.props['lambert lat2'] = self.fw.read_double() + self.fw.read_ahead(16) + self.props['ellipsoid model'] = self.fw.read_int() + self.fw.read_ahead(4) + self.props['utm zone'] = self.fw.read_short() + self.fw.read_ahead(6) + self.props['dz'] = self.fw.read_double() + self.props['radius'] = self.fw.read_double() + self.fw.read_ahead(8) + self.props['major axis'] = self.fw.read_double() + self.props['minor axis'] = self.fw.read_double() + + if global_prefs['verbose'] >= 1: + print 'OpenFlight Version:', float(self.props['version']) / 100.0 + print + + return True + + def parse_mat_palette(self): + mat_desc = MaterialDesc() + index = self.fw.read_int() + + name = self.fw.read_string(12) + if len(mat_desc.name) > 0: + mat_desc.name = name + + flag = self.fw.read_int() + # skip material if not used + if not flag & 0x80000000: + return True + + ambient_col = [self.fw.read_float(), self.fw.read_float(), self.fw.read_float()] + mat_desc.diffuse = [self.fw.read_float(), self.fw.read_float(), self.fw.read_float()] + mat_desc.specular = [self.fw.read_float(), self.fw.read_float(), self.fw.read_float()] + emissive_col = [self.fw.read_float(), self.fw.read_float(), self.fw.read_float()] + + mat_desc.shininess = self.fw.read_float() / 64.0 # [0.0, 128.0] => [0.0, 2.0] + mat_desc.alpha = self.fw.read_float() + + # Convert ambient and emissive colors into intensitities. + mat_desc.ambient = col_to_gray(ambient_col) + mat_desc.emissive = col_to_gray(emissive_col) + + self.mat_desc_pal_lst.append( (index, mat_desc) ) + + return True + + def get_color(self, color_index): + index = color_index / 128 + intensity = float(color_index - 128.0 * index) / 127.0 + + if index >= 0 and index <= 1023: + brightest = self.col_pal[index] + r = int(brightest[0] * intensity) + g = int(brightest[1] * intensity) + b = int(brightest[2] * intensity) + a = int(brightest[3]) + + color = [r, g, b, a] + + return color + + def parse_color_palette(self): + self.header.fw.read_ahead(128) + for i in xrange(1024): + a = self.header.fw.read_uchar() + b = self.header.fw.read_uchar() + g = self.header.fw.read_uchar() + r = self.header.fw.read_uchar() + self.col_pal.append((r, g, b, a)) + return True + + def parse_vertex_palette(self): + self.vert_pal = VertexPalette(self) + self.vert_pal.parse() + return True + + def parse_texture_palette(self): + name = self.fw.read_string(200) + index = self.fw.read_int() + self.tex_pal_lst.append( (index, name) ) + return True + + def __init__(self, filename, parent=None): + if global_prefs['verbose'] >= 1: + print 'Parsing:', filename + print + + self.fw = flt_filewalker.FltIn(filename) + Node.__init__(self, parent, self) + InterNode.__init__(self) + + self.root_handler.set_handler({1: self.parse_header, + 67: self.parse_vertex_palette, + 33: self.parse_long_id, + 31: self.parse_comment, + 64: self.parse_texture_palette, + 32: self.parse_color_palette, + 113: self.parse_mat_palette, + 128: self.parse_appearance_palette, + 10: self.parse_push}) + if parent: + self.root_handler.set_throw_back_lst(throw_back_opcodes) + + self.child_handler.set_handler({#130: self.parse_indexed_light_point, + #111: self.parse_inline_light_point, + 2: self.parse_group, + 73: self.parse_lod, + 4: self.parse_object, + 10: self.parse_push, + 11: self.parse_pop, + 96: self.parse_unhandled, + 14: self.parse_unhandled, + 91: self.parse_unhandled, + 98: self.parse_unhandled, + 63: self.parse_xref}) + + self.vert_pal = None + self.lightpoint_appearance_pal = dict() + self.tex_pal = dict() + self.tex_pal_lst = list() + self.bl_tex_pal = dict() + self.col_pal = list() + self.mat_desc_pal_lst = list() + self.mat_desc_pal = dict() + self.props = dict.fromkeys(['id', 'type', 'comment', 'version', 'units', 'set white', + 'flags', 'projection type', 'sw x', 'sw y', 'dx', 'dy', 'dz', 'sw lat', + 'sw lon', 'ne lat', 'ne lon', 'origin lat', 'origin lon', 'lambert lat1', + 'lambert lat2', 'ellipsoid model', 'utm zone', 'radius', 'major axis', 'minor axis']) + +def select_file(filename): + if not Blender.sys.exists(filename): + msg = 'Error: File ' + filename + ' does not exist.' + Blender.Draw.PupMenu(msg) + return + + if not filename.lower().endswith('.flt'): + msg = 'Error: Not a flight file.' + Blender.Draw.PupMenu(msg) + print msg + print + return + + global_prefs['fltfile']= filename + global_prefs['verbose']= 1 + global_prefs['get_texture'] = True + global_prefs['get_diffuse'] = True + global_prefs['get_specular'] = False + global_prefs['get_emissive'] = False + global_prefs['get_alpha'] = True + global_prefs['get_ambient'] = False + global_prefs['get_shininess'] = True + global_prefs['color_from_face'] = True + + # Start loading the file, + # first set the context + Blender.Window.WaitCursor(True) + Blender.Window.EditMode(0) + for ob in scene.objects: + ob.sel=0 + + + FF.add_file_to_search_path(filename) + + if global_prefs['verbose'] >= 1: + print 'Pass 1: Loading.' + print + + load_time = Blender.sys.time() + db = Database(filename) + db.parse() + load_time = Blender.sys.time() - load_time + + if global_prefs['verbose'] >= 1: + print + print 'Pass 2: Importing to Blender.' + print + + import_time = Blender.sys.time() + db.blender_import() + import_time = Blender.sys.time() - import_time + + Blender.Window.ViewLayer(range(1,21)) + + # FIX UP AFTER DUMMY VERT AND REMOVE DOUBLES + Blender.Mesh.Mode(Blender.Mesh.SelectModes['VERTEX']) + for ob in scene.objects.context: + if ob.type=='Mesh': + me=ob.getData(mesh=1) + me.verts.delete(0) # remove the dummy vert + me.sel= 1 + me.remDoubles(0.0001) + + + + Blender.Window.RedrawAll() + + if global_prefs['verbose'] >= 1: + print 'Done.' + print + print 'Time to parse file: %.3f seconds' % load_time + print 'Time to import to blender: %.3f seconds' % import_time + print 'Total time: %.3f seconds' % (load_time + import_time) + + Blender.Window.WaitCursor(False) + + +if global_prefs['verbose'] >= 1: + print + print 'OpenFlight Importer' + print 'Version:', __version__ + print 'Author: Greg MacDonald' + print __url__[2] + print + + +if __name__ == '__main__': + Blender.Window.FileSelector(select_file, "Import OpenFlight", "*.flt") + #select_file('/fe/flt/helnwsflt/helnws.flt') + #select_file('/fe/flt/Container_006.flt') + #select_file('/fe/flt/NaplesORIGINALmesh.flt') + #select_file('/Anti_tank_D30.flt') + #select_file('/metavr/file_examples/flt/cherrypoint/CherryPoint_liter_runway.flt') + + +""" +TIME= Blender.sys.time() +import os +PATH= 'c:\\flt_test' +for FNAME in os.listdir(PATH): + if FNAME.lower().endswith('.flt'): + FPATH= os.path.join(PATH, FNAME) + newScn= Blender.Scene.New(FNAME) + newScn.makeCurrent() + scene= newScn + select_file(FPATH) + +print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME) +""" + \ No newline at end of file diff --git a/release/scripts/help_bpy_api.py b/release/scripts/help_bpy_api.py new file mode 100644 index 00000000000..484663b32b3 --- /dev/null +++ b/release/scripts/help_bpy_api.py @@ -0,0 +1,41 @@ +#!BPY +""" +Name: 'Blender/Python Scripting API' +Blender: 244 +Group: 'Help' +Tooltip: 'The Blender Python API reference manual' +""" + +__author__ = "Matt Ebb" +__url__ = ("blender", "blenderartist") +__version__ = "1.0" +__bpydoc__ = """\ +This script opens the user's default web browser at http://www.blender.org's +"Blenders Python API" page. +""" + +# -------------------------------------------------------------------------- +# Blender/Python Scripting Reference Help Menu Item +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender, webbrowser +version = str(int(Blender.Get('version'))) +webbrowser.open('http://www.blender.org/documentation/'+ version +'PythonDoc/index.html') diff --git a/release/scripts/help_browser.py b/release/scripts/help_browser.py new file mode 100644 index 00000000000..d321ffa6256 --- /dev/null +++ b/release/scripts/help_browser.py @@ -0,0 +1,789 @@ +#!BPY + +""" +Name: 'Scripts Help Browser' +Blender: 234 +Group: 'Help' +Tooltip: 'Show help information about a chosen installed script.' +""" + +__author__ = "Willian P. Germano" +__version__ = "0.1 11/02/04" +__email__ = ('scripts', 'Author, wgermano:ig*com*br') +__url__ = ('blender', 'elysiun') + +__bpydoc__ ="""\ +This script shows help information for scripts registered in the menus. + +Usage: + +- Start Screen: + +To read any script's "user manual" select a script from one of the +available category menus. If the script has help information in the format +expected by this Help Browser, it will be displayed in the Script Help +Screen. Otherwise you'll be offered the possibility of loading the chosen +script's source file in Blender's Text Editor. The programmer(s) may have +written useful comments there for users. + +Hotkeys:
+ ESC or Q: [Q]uit + +- Script Help Screen: + +This screen shows the user manual page for the chosen script. If the text +doesn't fit completely on the screen, you can scroll it up or down with +arrow keys or a mouse wheel. There may be link and email buttons that if +clicked should open your default web browser and email client programs for +further information or support. + +Hotkeys:
+ ESC: back to Start Screen
+ Q: [Q]uit
+ S: view script's [S]ource code in Text Editor
+ UP, DOWN Arrows and mouse wheel: scroll text up / down +""" + +# $Id$ +# +# -------------------------------------------------------------------------- +# sysinfo.py version 0.1 Jun 09, 2004 +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2004: Willian P. Germano, wgermano _at_ ig.com.br +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender +from Blender import sys as bsys, Draw, Window, Registry + +WEBBROWSER = True +try: + import webbrowser +except: + WEBBROWSER = False + +DEFAULT_EMAILS = { + 'scripts': ['Bf-scripts-dev', 'bf-scripts-dev@blender.org'] +} + +DEFAULT_LINKS = { + 'blender': ["blender.org\'s Python forum", "http://www.blender.org/modules.php?op=modload&name=phpBB2&file=viewforum&f=9"], + 'elysiun': ["elYsiun\'s Python and Plugins forum", "http://www.elysiun.com/forum/viewforum.php?f=5"] +} + +PADDING = 15 +COLUMNS = 1 +TEXT_WRAP = 100 +WIN_W = WIN_H = 200 +SCROLL_DOWN = 0 + +def screen_was_resized(): + global WIN_W, WIN_H + + w, h = Window.GetAreaSize() + if WIN_W != w or WIN_H != h: + WIN_W = w + WIN_H = h + return True + return False + +def fit_on_screen(): + global TEXT_WRAP, PADDING, WIN_W, WIN_H, COLUMNS + + COLUMNS = 1 + WIN_W, WIN_H = Window.GetAreaSize() + TEXT_WRAP = int((WIN_W - PADDING) / 6) + if TEXT_WRAP < 40: + TEXT_WRAP = 40 + elif TEXT_WRAP > 100: + if TEXT_WRAP > 110: + COLUMNS = 2 + TEXT_WRAP /= 2 + else: TEXT_WRAP = 100 + +def cut_point(text, length): + "Returns position of the last space found before 'length' chars" + l = length + c = text[l] + while c != ' ': + l -= 1 + if l == 0: return length # no space found + c = text[l] + return l + +def text_wrap(text, length = None): + global TEXT_WRAP + + wrapped = [] + lines = text.split('
') + llen = len(lines) + if llen > 1: + if lines[-1] == '': llen -= 1 + for i in range(llen - 1): + lines[i] = lines[i].rstrip() + '
' + lines[llen-1] = lines[llen-1].rstrip() + + if not length: length = TEXT_WRAP + + for l in lines: + while len(l) > length: + cpt = cut_point(l, length) + line, l = l[:cpt], l[cpt + 1:] + wrapped.append(line) + wrapped.append(l) + return wrapped + +def load_script_text(script): + global PATHS, SCRIPT_INFO + + if script.userdir: + path = PATHS['uscripts'] + else: + path = PATHS['scripts'] + + fname = bsys.join(path, script.fname) + + source = Blender.Text.Load(fname) + if source: + Draw.PupMenu("File loaded%%t|Please check the file \"%s\" in the Text Editor window" % source.name) + + +# for theme colors: +def float_colors(cols): + return map(lambda x: x / 255.0, cols) + +# globals + +SCRIPT_INFO = None + +PATHS = { + 'home': Blender.Get('homedir'), + 'scripts': Blender.Get('scriptsdir'), + 'uscripts': Blender.Get('uscriptsdir') +} + +if not PATHS['home']: + errmsg = """ +Can't find Blender's home dir and so can't find the +Bpymenus file automatically stored inside it, which +is needed by this script. Please run the +Help -> System -> System Information script to get +information about how to fix this. +""" + raise SystemError, errmsg + +BPYMENUS_FILE = bsys.join(PATHS['home'], 'Bpymenus') + +f = file(BPYMENUS_FILE, 'r') +lines = f.readlines() +f.close() + +AllGroups = [] + +class Script: + + def __init__(self, data): + self.name = data[0] + self.version = data[1] + self.fname = data[2] + self.userdir = data[3] + self.tip = data[4] + +# End of class Script + + +class Group: + + def __init__(self, name): + self.name = name + self.scripts = [] + + def add_script(self, script): + self.scripts.append(script) + + def get_name(self): + return self.name + + def get_scripts(self): + return self.scripts + +# End of class Group + + +class BPy_Info: + + def __init__(self, script, dict): + + self.script = script + + self.d = dict + + self.header = [] + self.len_header = 0 + self.content = [] + self.len_content = 0 + self.spaces = 0 + self.fix_urls() + self.make_header() + self.wrap_lines() + + def make_header(self): + + sc = self.script + d = self.d + + header = self.header + + title = "Script: %s" % sc.name + version = "Version: %s for Blender %1.2f or newer" % (d['__version__'], + sc.version / 100.0) + + if len(d['__author__']) == 1: + asuffix = ':' + else: asuffix = 's:' + + authors = "%s%s %s" % ("Author", asuffix, ", ".join(d['__author__'])) + + header.append(title) + header.append(version) + header.append(authors) + self.len_header = len(header) + + + def fix_urls(self): + + emails = self.d['__email__'] + fixed = [] + for a in emails: + if a in DEFAULT_EMAILS.keys(): + fixed.append(DEFAULT_EMAILS[a]) + else: + a = a.replace('*','.').replace(':','@') + ltmp = a.split(',') + if len(ltmp) != 2: + ltmp = [ltmp[0], ltmp[0]] + fixed.append(ltmp) + + self.d['__email__'] = fixed + + links = self.d['__url__'] + fixed = [] + for a in links: + if a in DEFAULT_LINKS.keys(): + fixed.append(DEFAULT_LINKS[a]) + else: + ltmp = a.split(',') + if len(ltmp) != 2: + ltmp = [ltmp[0], ltmp[0]] + fixed.append([ltmp[0].strip(), ltmp[1].strip()]) + + self.d['__url__'] = fixed + + + def wrap_lines(self, reset = 0): + + lines = self.d['__bpydoc__'].split('\n') + self.content = [] + newlines = [] + newline = [] + + if reset: + self.len_content = 0 + self.spaces = 0 + + for l in lines: + if l == '' and newline: + newlines.append(newline) + newline = [] + newlines.append('') + else: newline.append(l) + if newline: newlines.append(newline) + + for lst in newlines: + wrapped = text_wrap(" ".join(lst)) + for l in wrapped: + self.content.append(l) + if l: self.len_content += 1 + else: self.spaces += 1 + + if not self.content[-1]: + self.len_content -= 1 + + +# End of class BPy_Info + +def parse_pyobj_close(closetag, lines, i): + i += 1 + l = lines[i] + while l.find(closetag) < 0: + i += 1 + l = "%s%s" % (l, lines[i]) + return [l, i] + +def parse_pyobj(var, lines, i): + "Bad code, was in a hurry for release" + + l = lines[i].replace(var, '').replace('=','',1).strip() + + i0 = i - 1 + + if l[0] == '"': + if l[1:3] == '""': # """ + if l.find('"""', 3) < 0: # multiline + l2, i = parse_pyobj_close('"""', lines, i) + if l[-1] == '\\': l = l[:-1] + l = "%s%s" % (l, l2) + elif l[-1] == '"' and l[-2] != '\\': # single line: "..." + pass + else: + l = "ERROR" + + elif l[0] == "'": + if l[-1] == '\\': + l2, i = parse_pyobj_close("'", lines, i) + l = "%s%s" % (l, l2) + elif l[-1] == "'" and l[-2] != '\\': # single line: '...' + pass + else: + l = "ERROR" + + elif l[0] == '(': + if l[-1] != ')': + l2, i = parse_pyobj_close(')', lines, i) + l = "%s%s" % (l, l2) + + elif l[0] == '[': + if l[-1] != ']': + l2, i = parse_pyobj_close(']', lines, i) + l = "%s%s" % (l, l2) + + return [l, i - i0] + +# helper functions: + +def parse_help_info(script): + + global PATHS, SCRIPT_INFO + + if script.userdir: + path = PATHS['uscripts'] + else: + path = PATHS['scripts'] + + fname = bsys.join(path, script.fname) + + if not bsys.exists(fname): + Draw.PupMenu('IO Error: couldn\'t find script %s' % fname) + return None + + f = file(fname, 'r') + lines = f.readlines() + f.close() + + # fix line endings: + if lines[0].find('\r'): + unixlines = [] + for l in lines: + unixlines.append(l.replace('\r','')) + lines = unixlines + + llen = len(lines) + has_doc = 0 + + doc_data = { + '__author__': '', + '__version__': '', + '__url__': '', + '__email__': '', + '__bpydoc__': '', + '__doc__': '' + } + + i = 0 + while i < llen: + l = lines[i] + incr = 1 + for k in doc_data.keys(): + if l.find(k, 0, 20) == 0: + value, incr = parse_pyobj(k, lines, i) + exec("doc_data['%s'] = %s" % (k, value)) + has_doc = 1 + break + i += incr + + # fix these to seqs, simplifies coding elsewhere + for w in ['__author__', '__url__', '__email__']: + val = doc_data[w] + if val and type(val) == str: + doc_data[w] = [doc_data[w]] + + if not doc_data['__bpydoc__']: + if doc_data['__doc__']: + doc_data['__bpydoc__'] = doc_data['__doc__'] + + if has_doc: # any data, maybe should confirm at least doc/bpydoc + info = BPy_Info(script, doc_data) + SCRIPT_INFO = info + return True + + else: + return False + + +def parse_script_line(l): + + try: + pieces = l.split("'") + name = pieces[1].replace('...','') + version, fname, userdir = pieces[2].strip().split() + tip = pieces[3] + except: + return None + + return [name, int(version), fname, int(userdir), tip] + + +def parse_bpymenus(lines): + + global AllGroups + + llen = len(lines) + + for i in range(llen): + l = lines[i].strip() + if not l: continue + if l[-1] == '{': + group = Group(l[:-2]) + AllGroups.append(group) + i += 1 + l = lines[i].strip() + while l != '}': + if l[0] != '|': + data = parse_script_line(l) + if data: + script = Script(data) + group.add_script(script) + i += 1 + l = lines[i].strip() + +# AllGroups.reverse() + + +def create_group_menus(): + + global AllGroups + menus = [] + + for group in AllGroups: + + name = group.get_name() + menu = [] + scripts = group.get_scripts() + for s in scripts: menu.append(s.name) + menu = "|".join(menu) + menu = "%s%%t|%s" % (name, menu) + menus.append([name, menu]) + + return menus + + +# Collecting data: +fit_on_screen() +parse_bpymenus(lines) +GROUP_MENUS = create_group_menus() + + +# GUI: + +from Blender import BGL +from Blender.Window import Theme + +# globals: + +START_SCREEN = 0 +SCRIPT_SCREEN = 1 + +SCREEN = START_SCREEN + +# gui buttons: +len_gmenus = len(GROUP_MENUS) + +BUT_GMENU = range(len_gmenus) +for i in range(len_gmenus): + BUT_GMENU[i] = Draw.Create(0) + +# events: +BEVT_LINK = None # range(len(SCRIPT_INFO.links)) +BEVT_EMAIL = None # range(len(SCRIPT_INFO.emails)) +BEVT_GMENU = range(100, len_gmenus + 100) +BEVT_VIEWSOURCE = 1 +BEVT_EXIT = 2 +BEVT_BACK = 3 + +# gui callbacks: + +def gui(): # drawing the screen + + global SCREEN, START_SCREEN, SCRIPT_SCREEN + global SCRIPT_INFO, AllGroups, GROUP_MENUS + global BEVT_EMAIL, BEVT_LINK + global BEVT_VIEWSOURCE, BEVT_EXIT, BEVT_BACK, BEVT_GMENU, BUT_GMENU + global PADDING, WIN_W, WIN_H, SCROLL_DOWN, COLUMNS, FMODE + + theme = Theme.Get()[0] + tui = theme.get('ui') + ttxt = theme.get('text') + + COL_BG = float_colors(ttxt.back) + COL_TXT = ttxt.text + COL_TXTHI = ttxt.text_hi + + BGL.glClearColor(COL_BG[0],COL_BG[1],COL_BG[2],COL_BG[3]) + BGL.glClear(BGL.GL_COLOR_BUFFER_BIT) + BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2]) + + resize = screen_was_resized() + if resize: fit_on_screen() + + if SCREEN == START_SCREEN: + x = PADDING + bw = 85 + bh = 25 + hincr = 50 + + butcolumns = (WIN_W - 2*x)/ bw + if butcolumns < 2: butcolumns = 2 + elif butcolumns > 7: butcolumns = 7 + + len_gm = len(GROUP_MENUS) + butlines = len_gm / butcolumns + if len_gm % butcolumns: butlines += 1 + + h = hincr * butlines + 20 + y = h + bh + + BGL.glColor3ub(COL_TXTHI[0],COL_TXTHI[1], COL_TXTHI[2]) + BGL.glRasterPos2i(x, y) + Draw.Text('Scripts Help Browser') + + y -= bh + + BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2]) + + i = 0 + j = 0 + for group_menu in GROUP_MENUS: + BGL.glRasterPos2i(x, y) + Draw.Text(group_menu[0]+':') + BUT_GMENU[j] = Draw.Menu(group_menu[1], BEVT_GMENU[j], + x, y-bh-5, bw, bh, 0, + 'Choose a script to read its help information') + if i == butcolumns - 1: + x = PADDING + i = 0 + y -= hincr + else: + i += 1 + x += bw + 3 + j += 1 + + x = PADDING + y = 10 + BGL.glRasterPos2i(x, y) + Draw.Text('Select script for its help. Press Q or ESC to leave.') + + elif SCREEN == SCRIPT_SCREEN: + if SCRIPT_INFO: + + if resize: + SCRIPT_INFO.wrap_lines(1) + SCROLL_DOWN = 0 + + h = 18 * SCRIPT_INFO.len_content + 12 * SCRIPT_INFO.spaces + x = PADDING + y = WIN_H + bw = 38 + bh = 16 + + BGL.glColor3ub(COL_TXTHI[0],COL_TXTHI[1], COL_TXTHI[2]) + for line in SCRIPT_INFO.header: + y -= 18 + BGL.glRasterPos2i(x, y) + size = Draw.Text(line) + + for line in text_wrap('Tooltip: %s' % SCRIPT_INFO.script.tip): + y -= 18 + BGL.glRasterPos2i(x, y) + size = Draw.Text(line) + + i = 0 + y -= 28 + for data in SCRIPT_INFO.d['__url__']: + Draw.PushButton('link %d' % (i + 1), BEVT_LINK[i], + x + i*bw, y, bw, bh, data[0]) + i += 1 + y -= bh + 1 + + i = 0 + for data in SCRIPT_INFO.d['__email__']: + Draw.PushButton('email', BEVT_EMAIL[i], x + i*bw, y, bw, bh, data[0]) + i += 1 + y -= 18 + + y0 = y + BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2]) + for line in SCRIPT_INFO.content[SCROLL_DOWN:]: + if line: + line = line.replace('
', '') + BGL.glRasterPos2i(x, y) + Draw.Text(line) + y -= 18 + else: y -= 12 + if y < PADDING + 20: # reached end, either stop or go to 2nd column + if COLUMNS == 1: break + elif x == PADDING: # make sure we're still in column 1 + x = 6*TEXT_WRAP + PADDING / 2 + y = y0 + + x = PADDING + Draw.PushButton('source', BEVT_VIEWSOURCE, x, 17, 45, bh, + 'View this script\'s source code in the Text Editor (hotkey: S)') + Draw.PushButton('exit', BEVT_EXIT, x + 45, 17, 45, bh, + 'Exit from Scripts Help Browser (hotkey: Q)') + if not FMODE: Draw.PushButton('back', BEVT_BACK, x + 2*45, 17, 45, bh, + 'Back to scripts selection screen (hotkey: ESC)') + BGL.glColor3ub(COL_TXTHI[0],COL_TXTHI[1], COL_TXTHI[2]) + BGL.glRasterPos2i(x, 5) + Draw.Text('use the arrow keys or the mouse wheel to scroll text', 'small') + +def fit_scroll(): + global SCROLL_DOWN + if not SCRIPT_INFO: + SCROLL_DOWN = 0 + return + max = SCRIPT_INFO.len_content + SCRIPT_INFO.spaces - 1 + if SCROLL_DOWN > max: SCROLL_DOWN = max + if SCROLL_DOWN < 0: SCROLL_DOWN = 0 + + +def event(evt, val): # input events + + global SCREEN, START_SCREEN, SCRIPT_SCREEN + global SCROLL_DOWN, FMODE + + if not val: return + + if evt == Draw.ESCKEY: + if SCREEN == START_SCREEN or FMODE: Draw.Exit() + else: + SCREEN = START_SCREEN + SCROLL_DOWN = 0 + Draw.Redraw() + return + elif evt == Draw.QKEY: + Draw.Exit() + return + elif evt in [Draw.DOWNARROWKEY, Draw.WHEELDOWNMOUSE] and SCREEN == SCRIPT_SCREEN: + SCROLL_DOWN += 1 + fit_scroll() + Draw.Redraw() + return + elif evt in [Draw.UPARROWKEY, Draw.WHEELUPMOUSE] and SCREEN == SCRIPT_SCREEN: + SCROLL_DOWN -= 1 + fit_scroll() + Draw.Redraw() + return + elif evt == Draw.SKEY: + if SCREEN == SCRIPT_SCREEN and SCRIPT_INFO: + load_script_text(SCRIPT_INFO.script) + return + +def button_event(evt): # gui button events + + global SCREEN, START_SCREEN, SCRIPT_SCREEN + global BEVT_LINK, BEVT_EMAIL, BEVT_GMENU, BUT_GMENU, SCRIPT_INFO + global SCROLL_DOWN, FMODE + + if evt >= 100: # group menus + for i in range(len(BUT_GMENU)): + if evt == BEVT_GMENU[i]: + group = AllGroups[i] + index = BUT_GMENU[i].val - 1 + if index < 0: return # user didn't pick a menu entry + script = group.get_scripts()[BUT_GMENU[i].val - 1] + if parse_help_info(script): + SCREEN = SCRIPT_SCREEN + BEVT_LINK = range(20, len(SCRIPT_INFO.d['__url__']) + 20) + BEVT_EMAIL = range(50, len(SCRIPT_INFO.d['__email__']) + 50) + Draw.Redraw() + else: + res = Draw.PupMenu("No help available%t|View Source|Cancel") + if res == 1: + load_script_text(script) + elif evt >= 20: + if not WEBBROWSER: + Draw.PupMenu('Missing standard Python module%t|You need module "webbrowser" to access the web') + return + + if evt >= 50: # script screen email buttons + email = SCRIPT_INFO.d['__email__'][evt - 50][1] + webbrowser.open("mailto:%s" % email) + else: # >= 20: script screen link buttons + link = SCRIPT_INFO.d['__url__'][evt - 20][1] + webbrowser.open(link) + elif evt == BEVT_VIEWSOURCE: + if SCREEN == SCRIPT_SCREEN: load_script_text(SCRIPT_INFO.script) + elif evt == BEVT_EXIT: + Draw.Exit() + return + elif evt == BEVT_BACK: + if SCREEN == SCRIPT_SCREEN and not FMODE: + SCREEN = START_SCREEN + SCRIPT_INFO = None + SCROLL_DOWN = 0 + Draw.Redraw() + +keepon = True +FMODE = False # called by Blender.ShowHelp(name) API function ? + +KEYNAME = '__help_browser' +rd = Registry.GetKey(KEYNAME) +if rd: + rdscript = rd['script'] + keepon = False + Registry.RemoveKey(KEYNAME) + for group in AllGroups: + for script in group.get_scripts(): + if rdscript == script.fname: + parseit = parse_help_info(script) + if parseit == True: + keepon = True + SCREEN = SCRIPT_SCREEN + BEVT_LINK = range(20, len(SCRIPT_INFO.d['__url__']) + 20) + BEVT_EMAIL = range(50, len(SCRIPT_INFO.d['__email__']) + 50) + FMODE = True + elif parseit == False: + Draw.PupMenu("ERROR: script doesn't have proper help data") + break + +if not keepon: + Draw.PupMenu("ERROR: couldn't find script") +else: + Draw.Register(gui, event, button_event) diff --git a/release/scripts/help_getting_started.py b/release/scripts/help_getting_started.py new file mode 100644 index 00000000000..19eac9e2e20 --- /dev/null +++ b/release/scripts/help_getting_started.py @@ -0,0 +1,43 @@ +#!BPY +""" +Name: 'Getting Started' +Blender: 234 +Group: 'Help' +Tooltip: 'Help for new users' +""" + +__author__ = "Matt Ebb" +__url__ = ("blender", "elysiun") +__version__ = "1.0" +__bpydoc__ = """\ +This script opens the user's default web browser at www.blender3d.org's +"Getting Started" page. +""" + +# $Id$ +# +# -------------------------------------------------------------------------- +# Getting Started Help Menu Item +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender, webbrowser +version = str(Blender.Get('version')) +webbrowser.open('http://www.blender3d.org/Help/?pg=GettingStarted&ver=' + version) diff --git a/release/scripts/help_manual.py b/release/scripts/help_manual.py new file mode 100644 index 00000000000..75d93522c31 --- /dev/null +++ b/release/scripts/help_manual.py @@ -0,0 +1,41 @@ +#!BPY +""" +Name: 'Manual' +Blender: 234 +Group: 'Help' +Tooltip: 'The Blender reference manual' +""" + +__author__ = "Matt Ebb" +__url__ = ("blender", "elysiun") +__version__ = "1.0" +__bpydoc__ = """\ +This script opens the user's default web browser at www.blender3d.org's +"Blender Manual" page. +""" + +# -------------------------------------------------------------------------- +# Manual Help Menu Item +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender, webbrowser +version = str(Blender.Get('version')) +webbrowser.open('http://www.blender3d.org/Help/?pg=Manual&ver=' + version) diff --git a/release/scripts/help_release_notes.py b/release/scripts/help_release_notes.py new file mode 100644 index 00000000000..49382755163 --- /dev/null +++ b/release/scripts/help_release_notes.py @@ -0,0 +1,41 @@ +#!BPY +""" +Name: 'Release Notes' +Blender: 234 +Group: 'Help' +Tooltip: 'Information about the changes in this version of Blender' +""" + +__author__ = "Matt Ebb" +__url__ = ("blender", "elysiun") +__version__ = "1.0" +__bpydoc__ = """\ +This script opens the user's default web browser at www.blender3d.org's +"Release Notes" page. +""" + +# -------------------------------------------------------------------------- +# Release Notes Help Menu Item +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender, webbrowser +version = str(Blender.Get('version')) +webbrowser.open('http://www.blender3d.org/Help/?pg=ReleaseNotes&ver=' + version) diff --git a/release/scripts/help_tutorials.py b/release/scripts/help_tutorials.py new file mode 100644 index 00000000000..1fbabc43eb6 --- /dev/null +++ b/release/scripts/help_tutorials.py @@ -0,0 +1,42 @@ +#!BPY + +""" +Name: 'Tutorials' +Blender: 234 +Group: 'Help' +Tooltip: 'Tutorials for learning to use Blender' +""" + +__author__ = "Matt Ebb" +__url__ = ("blender", "elysiun") +__version__ = "1.0" +__bpydoc__ = """\ +This script opens the user's default web browser at www.blender3d.org's +"Blender Tutorials" page. +""" + +# -------------------------------------------------------------------------- +# Tutorials Help Menu Item +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender, webbrowser +version = str(Blender.Get('version')) +webbrowser.open('http://www.blender3d.org/Help/?pg=Tutorials&ver=' + version) diff --git a/release/scripts/help_web_blender.py b/release/scripts/help_web_blender.py new file mode 100644 index 00000000000..999746c1f9c --- /dev/null +++ b/release/scripts/help_web_blender.py @@ -0,0 +1,42 @@ +#!BPY + +""" +Name: 'Blender Website' +Blender: 234 +Group: 'HelpWebsites' +Tooltip: 'The official Blender website' +""" + +__author__ = "Matt Ebb" +__url__ = ("blender", "elysiun") +__version__ = "1.0" +__bpydoc__ = """\ +This script opens the user's default web browser at Blender's main site, +www.blender3d.org. +""" + + +# -------------------------------------------------------------------------- +# Blender Website Help Menu -> Websites Item +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender, webbrowser +webbrowser.open('http://www.blender3d.org/') diff --git a/release/scripts/help_web_devcomm.py b/release/scripts/help_web_devcomm.py new file mode 100644 index 00000000000..afe9ef064d9 --- /dev/null +++ b/release/scripts/help_web_devcomm.py @@ -0,0 +1,41 @@ +#!BPY + +""" +Name: 'Developer Community' +Blender: 234 +Group: 'HelpWebsites' +Tooltip: 'Get involved with Blender development' +""" + +__author__ = "Matt Ebb" +__url__ = ("blender", "elysiun") +__version__ = "1.0" +__bpydoc__ = """\ +This script opens the user's default web browser at www.blender.org, the +Blender development portal. +""" + +# -------------------------------------------------------------------------- +# Blender Website Help Menu -> Websites Item +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import webbrowser +webbrowser.open('http://www.blender.org') diff --git a/release/scripts/help_web_eshop.py b/release/scripts/help_web_eshop.py new file mode 100644 index 00000000000..997d07ca255 --- /dev/null +++ b/release/scripts/help_web_eshop.py @@ -0,0 +1,41 @@ +#!BPY + +""" +Name: 'Blender E-Shop' +Blender: 234 +Group: 'HelpWebsites' +Tooltip: 'Buy official Blender resources and merchandise online' +""" + +__author__ = "Matt Ebb" +__url__ = ("blender", "elysiun") +__version__ = "1.0" +__bpydoc__ = """\ +This script opens the user's default web browser at www.blender3d.org's +"E-Shop" section. +""" + +# -------------------------------------------------------------------------- +# Blender Website Help Menu -> Websites Item +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender, webbrowser +webbrowser.open('http://www.blender3d.org/e-shop') diff --git a/release/scripts/help_web_usercomm.py b/release/scripts/help_web_usercomm.py new file mode 100644 index 00000000000..56f64764ac7 --- /dev/null +++ b/release/scripts/help_web_usercomm.py @@ -0,0 +1,41 @@ +#!BPY + +""" +Name: 'User Community' +Blender: 234 +Group: 'HelpWebsites' +Tooltip: 'Get involved with other Blender users' +""" + +__author__ = "Matt Ebb" +__url__ = ("blender", "elysiun") +__version__ = "1.0" +__bpydoc__ = """\ +This script opens the user's default web browser at www.blender3d.org's +"User Community" page. +""" + +# -------------------------------------------------------------------------- +# Blender Website Help Menu -> Websites Item +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import webbrowser +webbrowser.open('http://www.blender3d.org/Community') diff --git a/release/scripts/hotkeys.py b/release/scripts/hotkeys.py new file mode 100644 index 00000000000..bfaac252b21 --- /dev/null +++ b/release/scripts/hotkeys.py @@ -0,0 +1,921 @@ +#!BPY + +""" Registration info for Blender menus: +Name: 'HotKey and MouseAction Reference' +Blender: 242 +Group: 'Help' +Tip: 'All the hotkeys/short keys' +""" + +__author__ = "Jean-Michel Soler (jms)" +__url__ = ("blender", "blenderartist", +"Script's homepage, http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_hotkeyscript.htm", +"Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender") +__version__ = "21/01/2007" + +__bpydoc__ = """\ +This script is a reference about all hotkeys and mouse actions in Blender. + +Usage: + +Open the script from the Help menu and select group of keys to browse. + +Notes:
+ Additional entries in the database (c) 2004 by Bart. + Additional entries in the database for blender 2.37 --> 2.43 (c) 2003-2007/01 by jms. + +""" + +#------------------------ +# Hotkeys script +# (c) jm soler (2003-->01/2007) +# ----------------------- +# Page officielle : +# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_hotkeyscript.htm +# Communiquer les problemes et les erreurs sur: +# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender +#--------------------------------------------- +# ce script est proposé sous licence GPL pour etre associe +# a la distribution de Blender 2.33 et suivant +# -------------------------------------------------------------------------- +# this script is released under GPL licence +# for the Blender 2.33 scripts package +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) 2003, 2004: Jean-Michel Soler +# Additionnal entries in the original data base (c) 2004 by Bart (bart@neeneenee.de) +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender +from Blender.Draw import * +from Blender.BGL import * + +# INTERNATIONAL={0:'English','1':'French'} +# LANGUAGE=0 + +hotkeys={ +'Search ':[['', '']], +'Specials 1 ':[ +[',', 'Set Bounding Box rotation scaling pivot'], +['Ctrl-,', 'Set Median Point rotation scaling pivot'], +['.', 'Set 3D cursor as rotation scaling pivot'], +['.', 'Outliner : to get the current active data in center of view'], +['Ctrl-.', 'Set Individual Object Centers as rotation scaling pivot'], +['~', 'Display all layers (German keys: ö,french keyboard: ù)'], +['Shift-~', 'Display all/previous layers (German keys: Shift-ö, french keyboard: shift-ù)'], +['ENTER', 'Outliner : to open a subtree, works on entire item line. '], +['HOME', 'Outliner : to show the entire Object hierarchy. '], +['SHIFT+BACKSPACE',' Text edit mode: Clear text '], +['SPACE', 'Popup menu'], +['SPACE', '3D View: camera selected'], +['Ctrl-SPACE', 'Manipulator (transform widget) Menu'], +['TAB', 'Enter/exit Edit Mode'], +['TAB', 'Edit Mode and Numerical Edit (see N key) : move to next input value'], +['TAB', 'Sequencer: Edit meta strip'], +['TAB', 'IPO: Edit selected'], +['TAB', 'Text Editor : indent'], +['TAB', 'NODE window : Edit group'], #243 +['Shift-TAB', 'Text Editor : unindent'], +['Shift-TAB', 'Edit Mode: Toggle snaping'], +['Ctrl-TAB', 'ARMATURE : Enter/exit Pose Mode'], +['Ctrl-TAB','MESH : all views, enter exit weight paint mode.'], +['Shift-TAB', 'Edit Mode : Enter Object Mode'], +['Ctrl-Open menu /', ''], +['Ctrl-Load Image', 'Opens a thumbnail browser instead of file browser for images'], +['.', '...'] +], + +'Mouse ':[ +['Actions:', ''], +['LMB', '3D View: Set 3D Cursor'], +['LMB', '3D View: camera selected'], +['LMB drag', 'Border select circle: add to selection'], +['LMB hold down', 'Popup menu'], +['LMB hold down drag', 'Gesture'], +['Ctrl-LMB', 'IPO: Add key'], +['Ctrl-LMB', '3D View: OBJECT or EDIT mode, select with the Lasso tool'], +['Ctrl-LMB', '3D View: ARMATURE EDIT mode, add a new bone to the selected end '], +['Shift-LMB','MANIPULATOR (transform widget): select the axe to remove in the current'], +['Shift-LMB','MANIPULATOR transformation ( if there is a problem with small step adjustment'], +['Shift-LMB','MANIPULATOR first select the axe or axes with LBM alone)'], +['Shift-LMB', 'Outliner : Hold Shift while clicking on a triangle arrow to open/close the subtree below'], +['MMB', 'Rotate'], +['Ctrl-MMB', 'Zoom view'], +['Ctrl-LMB', 'Outliner : Hold CTRL while clicking on a name allows you to edit a name.'], +['Ctrl-LMB', 'Outliner : This works for all visualized data, including bones or vertex groups,'], +['Ctrl-LMB', 'Outliner : but not for \'nameless\' items that draw the links to Hooks, Deform '], +['Ctrl-LMB', 'Outliner : Groups or Constraints.'], +['Shift-MMB', 'Move view'], +['RMB', 'Select'], +['RMB drag', 'Border select circle: subtract from selection'], +['RMB hold down', 'Popup menu'], +['Alt-RMB', 'Object Mode :Select but in a displayed list of objects located under the mouse cursor'], +['Alt-RMB', 'Edit Mode: Select EDGES LOOP '], +['Alt+Ctrl-RMB', 'Edit Mode: Select FACES LOOP'], +['Alt+Ctrl-RMB', 'UV Image Editor: Select face'], +['Shift-RMB', 'Add/subtract to/from selection'], +['Wheel', 'Zoom view'], +['Transformations:', ''], +['Drag+Ctrl', 'Step adjustment'], +['Drag+Ctrl+Shift', 'Small step adjustment (Transform Widget : first select the axe or axes with LBM alone)'], +['Drag+Shift', 'Fine adjustment (Transform Widget : first select the axe or axes with LBM alone)'], +['LMB', 'Confirm transformation'], +['MMB', 'Toggle optional transform feature'], +['RMB', 'Abort transformation'], +['.', '...'] +], + +'F-Keys ':[ +['F1', 'Open File'], +['Shift-F1', 'Library Data Select'], +['F2', 'Save File'], +['Shift-F2', 'Export DXF'], +['Ctrl-F2', 'Save/export in vrml 1.0 format' ], +['F3', 'Save image'], +['Ctrl-F3', 'Save image : dump 3d view'], +['Ctrl-Shift-F3', 'Save image : dump screen'], +['F4', 'Logic Window (may change)'], +['Shift-F4', 'Object manager Data Select '], +['F5', 'Material Window'], +['Shift-F5', '3D Window'], +['F6', 'Texture Window'], +['Shift-F6', 'IPO Window'], +['F7', 'Object Window'], +['Shift-F7', 'Buttons Window'], +['F8', 'World Window'], +['Shift-F8', 'Video Sequencer Window'], +['F9', 'Edit Mode Window'], +['Shift-F9', 'OOP Window'], +['Alt-Shift-F9', 'OutLiner Window'], +['F10', 'Render Window'], +['Shift-F10', 'UV Image Editor'], +['F11', 'Recall the last rendered image'], +['Shift-F11', 'Text Editor'], +['ctrl-F11', 'replay the last rendered animation'], +['F12', 'Render current Scene'], +['Ctrl-F12', 'Render animation'], +['Ctrl-Shift-F12', 'NLA Editor'], +['Shift-F12', 'Action Editor'], +['Shift-F12', 'Action Editor'], +['.', '...'] +], + +'Numbers ':[ +['1..2..0-=', 'Show layer 1..2..12'], +['1..2..0-=', 'Edit Mode with Size, Grab, rotate tools : enter value'], +['Alt-1..2..0', 'Show layer 11..12..20'], +['Shift-1..2..0', 'Toggle layer 1..2..12'], +['Ctrl-1..4', 'Object/Edit Mode : change subsurf level to the selected value'], +['Shift-ALT-...', 'Toggle layer 11..12..20'], +['Crtl-Shift-ALT-3', 'Edit Mode & Face Mode : Triangle faces'], +['Crtl-Shift-ALT-4', 'Edit Mode & Face Mode : Quad faces'], +['Crtl-Shift-ALT-5', 'Edit Mode & Face Mode : Non quad or triangle faces'], +['.', '...'] +], + +'Numpad ':[ +['Numpad DEL', 'Zoom on object'], +['Numpad /', 'Local view on object (hide others)'], +['Numpad *', 'Rotate view to objects local axes'], +['Numpad +', 'Zoom in (works everywhere)'], +['Numpad -', 'OutLiner window, Collapse one level of the hierarchy'], +['Alt-Numpad +', 'Proportional vertex Edit Mode: Increase range of influence'], +['Ctrl-Numpad +', 'Edit Mode: Select More vertices'], +['Numpad -', 'Zoom out (works everywhere)'], +['Numpad +', 'OutLiner window, Expand one level of the hierarchy'], +['Alt-Numpad -', 'Proportional vertex Edit Mode: Decrease range of influence'], +['Ctrl-Numpad +', 'Edit Mode: Select Less vertices'], +['Numpad 0', 'Set Camera view'], +['Ctrl-Numpad 0', 'Set active object as camera'], +['Alt-Numbad 0', 'Restore old camera'], +['Ctrl-Alt-Numpad 0', 'Align active camera to view'], +['Numpad 1', 'Front view'], +['Ctrl-Numpad 1', 'Back view'], +['Numpad 3', 'Right view'], +['Ctrl-Numpad 3', 'Left view'], +['Numpad 7', 'Top view'], +['Ctrl-Numpad 7', 'Bottom view '], +['Numpad 5', 'Toggle orthogonal/perspective view'], +['Numpad 9', 'Redraw view'], +['Numpad 4', 'Rotate view left'], +['ctrl-Shift-Numpad 4', 'Previous Screen'], +['Numpad 6', 'Rotate view right'], +['ctrl-Shift-Numpad 6', 'Next Screen'], +['Numpad 8', 'Rotate view up'], +['Numpad 2', 'Rotate view down'], +['.', '...'] +], + +'Arrows ':[ +['Home/Pos1', 'View all',''], +['Home', 'OutLiner Windows, Show hierarchy'], +['PgUp', 'Edit Mode and Proportionnal Editing Tools, increase influence'], +['PgUp', 'Strip Editor, Move Down'], +['PgUn', 'TimeLine: Jump to next marker'], +['PgUp', 'IPO: Select next keyframe'], +['Ctrl-PgUp', 'IPO: Select and jump to next keyframe'], +['Ctrl-PgUn', 'TimeLine: Jump to next key'], +['PgDn', 'Edit Mode and Proportionnal Editing Tools, decrease influence'], +['PgDn', 'Strip Editor, Move Up'], +['PgDn', 'TimeLine: Jump to prev marker'], +['PgDn', 'IPO: Select previous keyframe'], +['Ctrl-PgDn', 'IPO: Select and jump to previous keyframe'], +['Ctrl-PgDn', 'TimeLine: Jump to prev key'], +['Left', 'One frame backwards'], +['Right', 'One frame forwards'], +['Down', '10 frames backwards'], +['Up', '10 frames forwards'], +['Alt-Down', 'Blender in Window mode'], +['Alt-Up', 'Blender in Fullscreen mode'], +['Ctrl-Left', 'Previous screen'], +['Ctrl-Right', 'Next screen'], +['Ctrl-Alt-C', 'Object Mode : Add Constraint'], +['Ctrl-Down', 'Maximize window toggle'], +['Ctrl-Up', 'Maximize window toggle'], +['Shift-Arrow', 'Toggle first frame/ last frame'], +['.', '...'] +], + +'Letters ':[ +{ +"A":[ +['A', 'Select all/Deselect all'], +['A', 'Outliner : Select all/Deselect all'], +['A', 'Ipo Editor : Object mode, Select all/Deselect all displayed Curves'], #243 +['A', 'Ipo Editor : Edit mode, Select all/Deselect all vertices'], #243 +['A', 'Render window (F12) : Display alpha plane'], +['Alt-A', 'Play animation in current window'], +['Ctrl-A', 'Apply objects size/rotation to object data'], +['Ctrl-A', 'Text Editor: Select all'], +['Shift-A', 'Sequencer: Add menu'], +['Shift-A', '3D-View: Add menu'], +['Shift-ALT-A', 'Play animation in all windows'], +['Shift-CTRL-A', 'Apply lattice / Make dupliverts real'], +['Shift-CTRL-A', 'Apply Deform '], +['.', '...'] +], + +"B":[ +['B', 'Border select'], +['BB', 'Circle select'], +['Alt+B', 'Object Mode: Select visible view section in 3D space'], +['Shift-B', 'Set render border (in active camera view)'], +['Ctrl-Alt+B', 'Object Mode: in 3D view, Bake (on an image in the uv editor window) the selected Meshes'], #243 +['Ctrl-Alt+B', 'Object Mode: in 3D view, Bake Full render of selected Meshes'], #243 +['Ctrl-Alt+B', 'Object Mode: in 3D view, Bake Ambient Occlusion of selected Meshes'], #243 +['Ctrl-Alt+B', 'Object Mode: in 3D view, Bake Normals of the selected Meshes'], #243 +['Ctrl-Alt+B', 'Object Mode: in 3D view, Bake Texture Only of selected Meshes'], #243 +['.', '...'] +], + +"C":[ +['C', 'Center view on cursor'], +['C', 'UV Image Editor: Active Face Select toggle'], +['C', 'Sequencer: Change content of the strip '], #243 +['C', 'IPO: Snap current frame to selected key'], +['C', 'TimeLine: Center View'], +['C', 'File Selector : Copy file'], +['C', 'NODE window : Show cyclic referencies'], #243 +['Alt-C', 'Object Mode: Convert menu'], +['Alt-C', 'Text Editor: Copy '], +['Ctrl-Shift-C', 'Text Editor: Copy selection to clipboard'], +['Ctrl-C', 'Copy menu (Copy properties of active to selected objects)'], +['Ctrl-C', 'UV Image Editor: Stick UVs to mesh vertex'], +['Ctrl-C','ARMATURE : posemode, Copy pose attributes'], +['Ctrl+Alt-C',' ARMATURE : posemode, add constraint to new empty object.'], +['Shift-C', 'Center and zoom view on selected objects'], +['Shift-C', 'UV Image Editor: Stick local UVs to mesh vertex'], +['.', '...'] +], + +"D":[ +['D', 'Set 3d draw mode'], +['Alt-D', 'Object Mode: Create new instance of object'], +['Ctrl-D', 'Display alpha of image texture as wire'], +['Ctrl-D', 'Text Editor : uncomment'], +['Shift-D', 'Create full copy of object'], +['Shift-D', 'NODE window : duplicate'], #243 +['CTRL-SHIFT-D', 'NLA editor : Duplicate markers'], +['CTRL-SHIFT-D', 'Action editor : Duplicate markers'], +['CTRL-SHIFT-D', 'IPO editor : Duplicate markers'], +['.', '...'] +], + +"E":[ +['E', 'Edit Mode: Extrude'], +['E', 'UV Image Editor: LSCM Unwrap'], +['E', 'TimeLine: Set current frame as End '], +['E', 'NODE window : Execute composite'], #243 +['ER', 'Edit Mode: Extrude Rotate'], +['ES', 'Edit Mode: Extrude Scale'], +['ESX', 'Edit Mode: Extrude Scale X axis'], +['ESY', 'Edit Mode: Extrude Scale Y axis'], +['ESZ', 'Edit Mode: Extrude Scale Z axis'], +['EX', 'Edit Mode: Extrude along X axis'], +['EY', 'Edit Mode: Extrude along Y axis'], +['EZ', 'Edit Mode: Extrude along Z axis'], +['Alt-E', 'Edit Mode: exit Edit Mode'], +['Ctrl-E', 'Edit Mode: Edge Specials menu'], +['Ctrl-E', 'Edit Mode: Edge Specials menu, Mark seams'], +['Ctrl-E', 'Edit Mode: Edge Specials menu, Clear seams'], +['Ctrl-E', 'Edit Mode: Edge Specials menu, Rotate Edge CW'], +['Ctrl-E', 'Edit Mode: Edge Specials menu, Rotate Edge CCW'], +['Ctrl-E', 'Edit Mode: Edge Specials menu, Loop Cut'], +['Ctrl-E', 'Edit Mode: Edge Specials menu, Edge Slide'], +['Shift-E', 'Edit Mode: SubSurf Edge Sharpness'], +['.', '...'] +], + +"F":[ +['F', 'Edit mode: Make edge/face'], +['F', 'Sequencer: Set Filter Y'], +['F', 'Object Mode: UV/Face Select mode'], +['Alt-F', 'Edit Mode: Beautify fill'], +['Alt-F,','Text editor : find again '], +['Alt-Ctrl-F,','Text editor : find '], +['Ctrl-F', 'Object Mode: Sort faces in Z direction'], +['Ctrl-F', 'Edit Mode: Flip triangle edges'], +['Shift-F', 'Edit Mode: Fill with triangles'], +['Shift-F', 'Object Mode: fly mode (see header for fly mode keys)'], +['.', '...'] +], + +"G":[ +['G', 'Grab (move)'], +['G', 'Timeline : Grab (move) Marker'], +['Alt-G', 'Clear location (this does only make sense in Object mode)'], +['Alt-G', 'NODE window : ungroup'], #243 +['Shift-ALT-G', 'Object mode: Remove selected objects from group'], +['Ctrl-G', 'NODE window : group'], #243 +['Ctrl-G', 'Add selected objects to group'], +['Ctrl-G', 'IPO editor, Grab/move marker'], +['Ctrl-Alt-G', 'MANIPULATOR (transform widget): set in Grab Mode'], +['Shift-G', 'Object mode: Selected Group menu'], +['Shift-G', 'Object mode: Selected Group menu 1, Children'], +['Shift-G', 'Object mode: Selected Group menu 2, Immediate Children'], +['Shift-G', 'Object mode: Selected Group menu 3, Parent'], +['Shift-G', 'Object mode: Selected Group menu 4, Sibling'], +['Shift-G', 'Object mode: Selected Group menu 5, Object of same type'], +['Shift-G', 'Object mode: Selected Group menu 6, Object in same shared layers'], +['Shift-G', 'Object mode: Selected Group menu 7, Objects in same group'], +['.', '...'] +], + +"H":[ +['H', 'Hide selected vertices/faces'], +['H', 'Curves: Set handle type'], +['H', 'Action editor: Handle type aligned'], +['H', 'Action editor: Handle type free'], +['H', 'NODE window : hide/unhide'], #243 +['Alt-H', 'Edit Mode : Show Hidden vertices/faces'], +['Shift-H', 'Curves: Automatic handle calculation'], +['Shift-H', 'Action editor: Handle type auto'], +['Shift-H', 'Edit Mode : Hide deselected vertices/faces'], +['Ctrl-H', 'Edit Mode : Add a hook on selected points or show the hook menu .'], +['.', '...'] +], + +"I":[ +['I', 'Keyframe menu'], +['Alt-I','ARMATURE : posemode, remove IK constraints.'], +['Ctrl-I','ARMATURE : add IK constraint'], +['.', '...'] +], + +"J":[ +['J', 'IPO: Join menu'], +['J', 'Mesh: Join all adjacent triangles to quads'], +['J', 'Render Window: Swap render buffer'], +['Alt-J,','Text editor : Jump '], +['Ctrl-J', 'Join selected objects'], +['Ctrl-J', 'Nurbs: Add segment'], +['Ctrl-J', 'IPO: Join keyframes menu'], +['.', '...'] +], + +"K":[ +['K', '3d Window: Show keyframe positions'], +['K', 'Edit Mode: Loop/Cut menu'], +['K', 'IPO: Show keyframe positions'], +['K', 'Nurbs: Print knots'], +['K', 'VIDEO editor : cut at current frame'], #243 +['Ctrl-K', 'Make skeleton from armature'], +['Shift-K', 'Show and select all keyframes for object'], +['Shift-K', 'Edit Mode: Knife Mode select'], +['Shift-K', 'UV Face Select: Clear vertex colours'], +['Shift-K', 'Vertex Paint: All vertex colours are erased; they are changed to the current drawing colour.'], +['.', '...'] +], + +"L":[ +['L', 'Make local menu'], +['L', 'Edit Mode: Select linked vertices (near mouse pointer)'], +['L', 'NODE window: Select linked from '], #243 +['L', 'OOPS window: Select linked objects'], +['L', 'UV Face Select: Select linked faces'], +['Ctrl-L', 'Make links menu (for instance : to scene...)'], +['Shift-L', 'Select links menu'], +['Shift-L', 'NODE window: Select linked to '], #243 +['.', '...'] +], + +"M":[ +['M', 'Object mode : Move object to different layer'], +['M', 'Sequencer: Make meta strip (group) from selected strips'], +['M', 'Edit Mode: Mirros Axis menu'], +['M', 'File Selector: rename file'], +['M', 'Video Sequence Editor : Make Meta strip...'], +['M', 'NLA editor: Add marker'], +['M', 'Action editor: Add marker'], +['M', 'IPO editor: Add marker'], +['M', 'TimeLine: Add marker'], +['Alt-M', 'Edit Mode: Merge vertices menu'], +['Alt-M', 'Video Sequence Editor : Separate Meta strip...'], +['Ctrl-M', 'Object Mode: Mirros Axis menu'], +['Shift-M', 'TimeLine: Name marker'], +['Shift-M', 'IPO editor : Name marker'], +['Shift-M', 'NLA editor : Name marker'], +['Shift-M', 'Actions editor : Name marker'], +['.', '...'] +], + +"N":[ +['N', 'Transform Properties panel'] , +['N', 'OOPS window: Rename object'], +['N', 'VIDEO SEQUENCE editor : display strip properties '], #243 +['Alt-N', 'Text Editor : New text '], +['Ctrl-N', 'Armature: Recalculate bone roll angles'] , +['Ctrl-N', 'Edit Mode: Recalculate normals to outside'] , +['Ctrl-Shift-N', 'Edit Mode: Recalculate normals to inside'], +['.', '...'] +], + +"O":[ +['O', 'Edit Mode/UV Image Editor: Toggle proportional vertex editing'], +['O', 'IPO editor: Clean ipo curves (beware to the thresold needed value)'], #243 +['Alt-O', 'Clear object origin'], +['Alt-O', 'Edit mode, 3dview with prop-edit-mode, enables/disables connected'], +['Alt-O', 'Text Editor : Open file '], +['Ctrl-O', 'Open a panel with the ten most recent projets files'], #243 +['Shift-O', 'Proportional vertex Edit Mode: Toggle smooth/steep falloff'], +['Shift-O', 'Object Mode: Add a subsurf modifier to the selected mesh'], +['Shift-O', 'IPO editor: Smooth ipo curves'], #243 +['.', '...'] +], + +"P":[ +['P', 'Object Mode: Start realtime engine'], +['P', 'Edit mode: Seperate vertices to new object'], +['shift-P', 'Edit mode: Push-Pull'], +['shift-P', 'Object mode: Add a preview window in the D window'], +['P', 'UV Image Editor: Pin selected vertices. Pinned vertices will stay in place on the UV editor when executing an LSCM unwrap.'], +['Alt-P', 'Clear parent relationship'], +['Alt-P', 'UV Image Editor: Unpin UVs'], +['Alt-P', 'Text Editor : Run current script '], +['Ctrl-P', 'Make active object parent of selected object'], +['Ctrl-Shift-P', 'Make active object parent of selected object without inverse'], +['Ctrl-P', 'Edit mode: Make active vertex parent of selected object'], +['Ctrl-P', 'ARMATURE : editmode, make bone parent.'], +['.', '...'] +], + +"Q":[['Ctrl-Q', 'Quit'], + ['.', '...'] + ], + +"R":[ +['R', 'FileSelector : remove file'], +['R', 'Rotate'], +['R', 'IPO: Record mouse movement as IPO curve'], +['R', 'UV Face Select: Rotate menu uv coords or vertex colour'], +['R', 'NODE window : read saved render result'], #243 +['R', 'SEQUENCER window : re-assign entries to another strip '], #243 +['RX', 'Rotate around X axis'], +['RXX', "Rotate around object's local X axis"], +['RY', 'Rotate around Y axis'], +['RYY', "Rotate around object's local Y axis"], +['RZ', 'Rotate around Z axis'], +['RZZ', "Rotate around object's local Z axis"], +['Alt-R', 'Clear object rotation'], +['Alt-R', 'Text editor : reopen text.'], +['Ctrl-R', 'Edit Mode: Knife, cut selected edges, accept left mouse/ cancel right mouse'], +['Ctrl-Alt-R', 'MANIPULATOR (transform widget): set in Rotate Mode'], +['Shift-R', 'Edit Mode: select Face Loop'], +['Shift-R', 'Nurbs: Select row'], +['.', '...'] +], + +"S":[ +['S', 'Scale'] , +['S', 'TimeLine: Set Start'], +['SX', 'Flip around X axis'] , +['SY', 'Flip around Y axis'] , +['SZ', 'Flip around Z axis'] , +['SXX', 'Flip around X axis and show axis'] , +['SYY', 'Flip around Y axis and show axis'] , +['SZZ', 'Flip around Z axis and show axis'] , +['Alt-S', 'Edit mode: Shrink/fatten (Scale along vertex normals)'] , +['Alt-S', 'Text Editor : Save the current text to file '], +['Alt-S',' ARMATURE : posemode editmode: Scale envalope.'], +['Ctrl-Shift-S', 'Edit mode: To Sphere'] , +['Ctrl-Alt-Shift-S', 'Edit mode: Shear'] , +['Alt-S', 'Clear object size'] , +['Ctrl-S', 'Edit mode: Shear'] , +['Alt-Shift-S,','Text editor : Select the line '], +['Ctrl-Alt-G', 'MANIPULATOR (transform widget): set in Size Mode'], +['Shift-S', 'Cursor/Grid snap menu'], +['Shift-S+1', 'VIDEO SEQUENCE editor : jump to the current frame '], +['.', '...'] +], + +"T":[ +['T', 'Adjust texture space'], +['T', 'Edit mode: Flip 3d curve'], +['T', 'IPO: Menu Change IPO type, 1 Constant'], +['T', 'IPO: Menu Change IPO type, 2 Linear'], +['T', 'IPO: Menu Change IPO type, 3 Bezier'], +['T', 'TimeLine: Show second'], +['T', 'VIDEO SEQUENCE editor : toggle between show second andd show frame'], #243 +['Alt-T', 'Clear tracking of object'], +['Ctrl-T', 'Make selected object track active object'], +['Ctrl-T', 'Edit Mode: Convert to triangles'], +['Ctrl-ALT-T', 'Benchmark'], +['.', '...'] +], + +"U":[ +['U', 'Make single user menu (for import completly linked object to another scene for instance) '] , +['U', '3D View: Make Single user Menu'] , +['U', 'UV Face Select: Automatic UV calculation menu'] , +['U', 'Vertex-/Weightpaint mode: Undo'] , +['Ctrl-U', 'Save current state as user default'], +['Shift-U', 'Edit Mode: Redo Menu'], +['Alt-U', 'Edit Mode & Object Mode: Undo Menu'], +['.', '...'] +], + +"V":[ +['V', 'Curves/Nurbs: Vector handle'], +['V', 'Edit Mode : Rip selected vertices'], +['V', 'Vertexpaint mode'], +['V', 'UV Image Editor: Stitch UVs'], +['Ctrl-V',' UV Image Editor: maximize stretch.'], +['V', 'Action editor: Vector'], +['Alt-V', "Scale object to match image texture's aspect ratio"], +['Alt-V', 'Text Editor : Paste '], +['Alt-Shift-V', 'Text Editor : View menu'], +['Alt-Shift-V', 'Text Editor : View menu 1, Top of the file '], +['Alt-Shift-V', 'Text Editor : View menu 2, Bottom of the file '], +['Alt-Shift-V', 'Text Editor : View menu 3, PageUp'], +['Alt-Shift-V', 'Text Editor : View menu 4, PageDown'], +['Ctrl-Shift-V', 'Text Editor: Paste from clipboard'], +['Shift-V', 'Edit mode: Align view to selected vertices'], +['Shift-V', 'UV Image Editor: Limited Stitch UVs popup'], +['.', '...'] +], + +"W":[ +['W', 'Edit Mode: Specials menu'], +['W', 'Edit Mode: Specials menu, ARMATURE 1 Subdivide'], +['W', 'Edit Mode: Specials menu, ARMATURE 2 Flip Left-Right Name'], +['W', 'Edit Mode: Specials menu, CURVE 1 Subdivide'], +['W', 'Edit Mode: Specials menu, CURVE 2 Swich Direction'], +['W', 'Edit Mode: Specials menu, MESH 1 Subdivide'], +['W', 'Edit Mode: Specials menu, MESH 2 Subdivide Multi'], +['W', 'Edit Mode: Specials menu, MESH 3 Subdivide Multi Fractal'], +['W', 'Edit Mode: Specials menu, MESH 4 Subdivide Smooth'], +['W', 'Edit Mode: Specials menu, MESH 5 Merge'], +['W', 'Edit Mode: Specials menu, MESH 6 Remove Double'], +['W', 'Edit Mode: Specials menu, MESH 7 Hide'], +['W', 'Edit Mode: Specials menu, MESH 8 Reveal'], +['W', 'Edit Mode: Specials menu, MESH 9 Select Swap'], +['W', 'Edit Mode: Specials menu, MESH 10 Flip Normal'], +['W', 'Edit Mode: Specials menu, MESH 11 Smooth'], +['W', 'Edit Mode: Specials menu, MESH 12 Bevel'], +['W', 'Edit Mode: Specials menu, MESH 13 Set Smooth'], +['W', 'Edit Mode : Specials menu, MESH 14 Set Solid'], +['W', 'Object Mode : on MESH objects, Boolean Tools menu'], +['W', 'Object Mode : on MESH objects, Boolean Tools 1 Intersect'], +['W', 'Object Mode : on MESH objects, Boolean Tools 2 union'], +['W', 'Object Mode : on MESH objects, Boolean Tools 3 difference'], +['W', 'Object Mode : on MESH objects, Boolean Tools 4 Add an intersect Modifier'], +['W', 'Object Mode : on MESH objects, Boolean Tools 5 Add an union Modifier'], +['W', 'Object Mode : on MESH objects, Boolean Tools 6 Add a difference Modifier'], +['W', 'Object mode : on TEXT object, Split characters, a new TEXT object by character in the selected string '], +['W', 'UV Image Editor: Weld/Align'], +['WX', 'UV Image Editor: Weld/Align X axis'], +['WY', 'UV Image Editor: Weld/Align Y axis'], +['Ctrl-W', 'Save current file'] , +['Shift-W', 'Warp/bend selected vertices around cursor'], +['alt-W', 'Export in videoscape format'], +['.', '...'] + ], + +"X":[ +['X', 'Delete menu'] , +['X', 'TimeLine : Remove marker'], +['X', 'NLA : Remove marker'], +['X', 'IPO : Remove marker'], +['X', 'NODE window : delete'], #243 +['Alt-X', 'Text Editor : Cut '], +['Ctrl-X', 'Restore default state (Erase all)'], +['.', '...'] + ], + +"Y":[ +['Y', 'Edit Mode & Mesh : Split selected vertices/faces from the rest'], +['Ctrl-Y', 'Object Mode : Redo'], +['.', '...'] +], + +"Z":[ +['Z', 'Render Window: 200% zoom from mouse position'], +['Z', 'Switch 3d draw type : solide/ wireframe (see also D)'], +['Alt-Z', 'Switch 3d draw type : solid / textured (see also D)'], +['Alt-Z,','Text editor : undo '], +['Ctrl-Z', 'Object Mode : Undo'], +['Ctrl-Z,','Text editor : undo '], +['Ctrl-Shift-Z,','Text editor : Redo '], +['Shift-Z', 'Switch 3d draw type : shaded / wireframe (see also D)'], +['.', '...'] +]}]} + +up=128 +down=129 +UP=0 +SEARCH=131 +OLDSEARCHLINE='' +SEARCHLINE=Create('') +LINE=130 +FINDED=[] +LEN=0 + +for k in hotkeys.keys(): + hotkeys[k].append(Create(0)) + +for k in hotkeys['Letters '][0]: + hotkeys['Letters '][0][k].append(Create(0)) + +hotL=hotkeys['Letters '][0].keys() +hotL.sort() + +hot=hotkeys.keys() +hot.sort() + +def searchfor(SEARCHLINE): + global hotkeys, hot + FINDLIST=[] + for k in hot: + if k not in ['Letters ', 'Search '] : + for l in hotkeys[k][:-1]: + #print 'k, l : ', k, l, l[1] + if l[1].upper().find(SEARCHLINE.upper())!=-1: + FINDLIST.append(l) + + elif k == 'Letters ': + for l in hotL : + for l0 in hotkeys['Letters '][0][l][:-1]: + #print 'k, l : ',l, k, l0 + if l0[1].upper().find(SEARCHLINE.upper())!=-1: + FINDLIST.append(l0) + #print 'FINDLIST',FINDLIST + FINDLIST.append(['Find list','Entry']) + return FINDLIST + + +glCr=glRasterPos2d +glCl3=glColor3f +glCl4=glColor4f +glRct=glRectf + +cf=[0.95,0.95,0.9,0.0] +c1=[0.95,0.95,0.9,0.0] +c=cf +r=[0,0,0,0] + +def trace_rectangle4(r,c): + glCl4(c[0],c[1],c[2],c[3]) + glRct(r[0],r[1],r[2],r[3]) + +def trace_rectangle3(r,c,c1): + glCl3(c[0],c[1],c[2]) + glRct(r[0],r[1],r[2],r[3]) + glCl3(c1[0],c1[1],c1[2]) + +def draw(): + global r,c,c1,hotkeys, hot, hotL, up, down, UP, SEARCH, SEARCHLINE,LINE + global OLDSEARCHLINE, FINDED, SCROLL, LEN + size=Buffer(GL_FLOAT, 4) + glGetFloatv(GL_SCISSOR_BOX, size) + size= size.list + + for s in [0,1,2,3]: size[s]=int(size[s]) + + c=[0.75,0.75,0.75,0] + c1=[0.6,0.6,0.6,0] + + r=[0,size[3],size[2],0] + trace_rectangle4(r,c) + + c=[0.64,0.64,0.64,0] + c1=[0.95,0.95,0.9,0.0] + + r=[0,size[3],size[2],size[3]-40] + trace_rectangle4(r,c) + + c1=[0.7,0.7,0.9,0.0] + c=[0.2,0.2,0.4,0.0] + c2=[0.71,0.71,0.71,0.0] + + glColor3f(1, 1, 1) + glRasterPos2f(42, size[3]-25) + + Text("HotKey and MouseAction Reference") + + l=0 + listed=0 + Llisted=0 + size[3]=size[3]-18 + + BeginAlign() + for i, k in enumerate(hot): + hotkeys[k][-1]=Toggle(k, i+10, 78*i, size[3]-(47), 78, 24, hotkeys[k][-1].val ) + l+=len(k) + if hotkeys[k][-1].val==1.0: + listed= i + EndAlign() + l=0 + size[3]=size[3]-4 + + if hot[listed]!='Letters ' and hot[listed]!='Search ' : + size[3]=size[3]-8 + SCROLL=size[3]/21 + END=-1 + if SCROLL < len(hotkeys[hot[listed]][:-1]): + BeginAlign() + Button('/\\',up,4,size[3]+8,20,14,'Scroll up') + Button('\\/',down,4,size[3]-8,20,14,'Scroll down') + EndAlign() + if (SCROLL+UP)0: + LEN=len(FINDED) + size[3]=size[3]-8 + SCROLL=size[3]/21 + END=-1 + + if SCROLL < len(FINDED): + BeginAlign() + Button('/\\',up,4,size[3]+8,20,14,'Scroll up') + Button('\\/',down,4,size[3]-8,20,14,'Scroll down') + EndAlign() + if (SCROLL+UP)4: + UP-=5 + elif (evt== UPARROWKEY): + if (UP+SCROLL)0: + UP-=1 + Redraw() + +def bevent(evt): + global hotkeysmhot, hotL, up,down,UP, FINDED + global SEARCH, SEARCHLINE,LINE, OLDSEARCHLINE + + if (evt== 1): + Exit() + + elif 9 < evt < 20: + for i, k in enumerate(hot): + if i+10!=evt: + hotkeys[k][-1].val=0 + UP=0 + Blender.Window.Redraw() + + elif 19 < evt < 46: + for i, k in enumerate(hotL): + if i+20!=evt: + hotkeys['Letters '][0][k][-1].val=0 + UP=0 + Blender.Window.Redraw() + + elif (evt==up): + UP+=1 + Blender.Window.Redraw() + + elif (evt==down): + if UP>0: UP-=1 + Blender.Window.Redraw() + + elif (evt==LINE): + if SEARCHLINE.val!='' and SEARCHLINE.val!=OLDSEARCHLINE: + OLDSEARCHLINE=SEARCHLINE.val + FINDED=searchfor(OLDSEARCHLINE) + Blender.Window.Redraw() + +if __name__ == '__main__': + Register(draw, event, bevent) \ No newline at end of file diff --git a/release/scripts/image_auto_layout.py b/release/scripts/image_auto_layout.py new file mode 100644 index 00000000000..19ee396c3b1 --- /dev/null +++ b/release/scripts/image_auto_layout.py @@ -0,0 +1,451 @@ +#!BPY + +""" +Name: 'Consolidate into one image' +Blender: 243 +Group: 'Image' +Tooltip: 'Pack all texture images into 1 image and remap faces.' +""" + +__author__ = "Campbell Barton" +__url__ = ("blender", "blenderartists.org") +__version__ = "1.1 2007/02/15" + +__bpydoc__ = """\ +This script makes a new image from the used areas of all the images mapped to the selected mesh objects. +Image are packed into 1 new image that is assigned to the original faces. +This is usefull for game models where 1 image is faster then many, and saves the labour of manual texture layout in an image editor. + +""" +# -------------------------------------------------------------------------- +# Auto Texture Layout v1.0 by Campbell Barton (AKA Ideasman) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +# Function to find all the images we use +import Blender as B +from Blender.Mathutils import Vector, RotationMatrix +from Blender.Scene import Render +import BPyMathutils +BIGNUM= 1<<30 +TEXMODE= B.Mesh.FaceModes.TEX + +def pointBounds(points): + ''' + Takes a list of points and returns the + area, center, bounds + ''' + ymax= xmax= -BIGNUM + ymin= xmin= BIGNUM + + for p in points: + x= p.x + y= p.y + + if x>xmax: xmax=x + if y>ymax: ymax=y + + if x 0.1: + mat_pos= RotationMatrix( rot_angle, 2) + mat_neg= RotationMatrix( -rot_angle, 2) + + new_points_pos= [v*mat_pos for v in current_points] + area_pos, cent_pos, bounds_pos= pointBounds(new_points_pos) + + # 45d rotations only need to be tested in 1 direction. + if rot_angle == 45: + area_neg= area_pos + else: + new_points_neg= [v*mat_neg for v in current_points] + area_neg, cent_neg, bounds_neg= pointBounds(new_points_neg) + + + # Works! + #print 'Testing angle', rot_angle, current_area, area_pos, area_neg + + best_area= min(area_pos, area_neg, current_area) + if area_pos == best_area: + current_area= area_pos + cent= cent_pos + bounds= bounds_pos + current_points= new_points_pos + total_rot_angle+= rot_angle + elif rot_angle != 45 and area_neg == best_area: + current_area= area_neg + cent= cent_neg + bounds= bounds_neg + current_points= new_points_neg + total_rot_angle-= rot_angle + + rot_angle *= 0.5 + + # Return the optimal rotation. + return total_rot_angle + + +class faceGroup(object): + ''' + A Group of faces that all use the same image, each group has its UVs packed into a square. + ''' + __slots__= 'xmax', 'ymax', 'xmin', 'ymin',\ + 'image', 'faces', 'box_pack', 'size', 'ang', 'rot_mat', 'cent'\ + + def __init__(self, mesh_list, image, size, PREF_IMAGE_MARGIN): + self.image= image + self.size= size + self.faces= [f for me in mesh_list for f in me.faces if f.mode & TEXMODE and f.image == image] + + # Find the best rotation. + all_points= [uv for f in self.faces for uv in f.uv] + bountry_indicies= BPyMathutils.convexHull(all_points) + bountry_points= [all_points[i] for i in bountry_indicies] + + # Pre Rotation bounds + self.cent= pointBounds(bountry_points)[1] + + # Get the optimal rotation angle + self.ang= bestBoundsRotation(bountry_points) + self.rot_mat= RotationMatrix(self.ang, 2), RotationMatrix(-self.ang, 2) + + # Post rotation bounds + bounds= pointBounds([\ + ((uv-self.cent) * self.rot_mat[0]) + self.cent\ + for uv in bountry_points])[2] + + # Break the bounds into useable values. + xmin, ymin, xmax, ymax= bounds + + # Store the bounds, include the margin. + # The bounds rect will need to be rotated to the rotation angle. + self.xmax= xmax + (PREF_IMAGE_MARGIN/size[0]) + self.xmin= xmin - (PREF_IMAGE_MARGIN/size[0]) + self.ymax= ymax + (PREF_IMAGE_MARGIN/size[1]) + self.ymin= ymin - (PREF_IMAGE_MARGIN/size[1]) + + self.box_pack=[\ + 0.0, 0.0,\ + size[0]*(self.xmax - self.xmin),\ + size[1]*(self.ymax - self.ymin),\ + image.name] + + ''' + # default. + self.scale= 1.0 + + def set_worldspace_scale(self): + scale_uv= 0.0 + scale_3d= 0.0 + for f in self.faces: + for i in xrange(len(f.v)): + scale_uv+= (f.uv[i]-f.uv[i-1]).length * 0.1 + scale_3d+= (f.v[i].co-f.v[i-1].co).length * 0.1 + self.scale= scale_3d/scale_uv + ''' + + + + def move2packed(self, width, height): + ''' + Moves the UV coords to their packed location + using self.box_pack as the offset, scaler. + box_pack must be set to its packed location. + width and weight are the w/h of the overall packed area's bounds. + ''' + # packedLs is a list of [(anyUniqueID, left, bottom, width, height)...] + # Width and height in float pixel space. + + # X Is flipped :/ + #offset_x= (1-(self.box_pack[1]/d)) - (((self.xmax-self.xmin) * self.image.size[0])/d) + offset_x= self.box_pack[0]/width + offset_y= self.box_pack[1]/height + + for f in self.faces: + for uv in f.uv: + uv_rot= ((uv-self.cent) * self.rot_mat[0]) + self.cent + uv.x= offset_x+ (((uv_rot.x-self.xmin) * self.size[0])/width) + uv.y= offset_y+ (((uv_rot.y-self.ymin) * self.size[1])/height) + +def consolidate_mesh_images(mesh_list, scn, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PREF_KEEP_ASPECT, PREF_IMAGE_MARGIN): #, PREF_SIZE_FROM_UV=True): + ''' + Main packing function + + All meshes from mesh_list must have faceUV else this function will fail. + ''' + face_groups= {} + + for me in mesh_list: + for f in me.faces: + if f.mode & TEXMODE: + image= f.image + if image: + try: + face_groups[image.name] # will fail if teh groups not added. + except: + try: + size= image.size + except: + B.Draw.PupMenu('Aborting: Image cold not be loaded|' + image.name) + return + + face_groups[image.name]= faceGroup(mesh_list, image, size, PREF_IMAGE_MARGIN) + + if not face_groups: + B.Draw.PupMenu('No Images found in mesh(es). Aborting!') + return + + if len(face_groups)<2: + B.Draw.PupMenu('Only 1 image found|Select a mesh(es) using 2 or more images.') + return + + ''' + if PREF_SIZE_FROM_UV: + for fg in face_groups.itervalues(): + fg.set_worldspace_scale() + ''' + + # RENDER THE FACES. + render_scn= B.Scene.New() + render_scn.makeCurrent() + render_context= render_scn.getRenderingContext() + render_context.setRenderPath('') # so we can ignore any existing path and save to the abs path. + + PREF_IMAGE_PATH_EXPAND= B.sys.expandpath(PREF_IMAGE_PATH) + '.png' + + # TEST THE FILE WRITING. + try: + # Can we write to this file??? + f= open(PREF_IMAGE_PATH_EXPAND, 'w') + f.close() + except: + B.Draw.PupMenu('Error%t|Could not write to path|' + PREF_IMAGE_PATH_EXPAND) + return + + render_context.imageSizeX(PREF_IMAGE_SIZE) + render_context.imageSizeY(PREF_IMAGE_SIZE) + render_context.enableOversampling(True) + render_context.setOversamplingLevel(16) + render_context.setRenderWinSize(100) + render_context.setImageType(Render.PNG) + render_context.enableExtensions(True) + render_context.enableSky() # No alpha needed. + render_context.enableRGBColor() + render_context.threads = 2 + + #Render.EnableDispView() # Broken?? + + # New Mesh and Object + render_mat= B.Material.New() + render_mat.mode |= B.Material.Modes.SHADELESS + render_mat.mode |= B.Material.Modes.TEXFACE + + + render_me= B.Mesh.New() + render_me.verts.extend([Vector(0,0,0)]) # Stupid, dummy vert, preverts errors. when assigning UV's/ + render_ob= B.Object.New('Mesh') + render_ob.link(render_me) + render_scn.link(render_ob) + render_me.materials= [render_mat] + + + # New camera and object + render_cam_data= B.Camera.New('ortho') + render_cam_ob= B.Object.New('Camera') + render_cam_ob.link(render_cam_data) + render_scn.link(render_cam_ob) + render_scn.objects.camera = render_cam_ob + + render_cam_data.type= 'ortho' + render_cam_data.scale= 1.0 + + + # Position the camera + render_cam_ob.LocZ= 1.0 + render_cam_ob.LocX= 0.5 + render_cam_ob.LocY= 0.5 + + # List to send to to boxpack function. + boxes2Pack= [ fg.box_pack for fg in face_groups.itervalues()] + packWidth, packHeight = B.Geometry.BoxPack2D(boxes2Pack) + + if PREF_KEEP_ASPECT: + packWidth= packHeight= max(packWidth, packHeight) + + + # packedLs is a list of [(anyUniqueID, left, bottom, width, height)...] + # Re assign the face groups boxes to the face_group. + for box in boxes2Pack: + face_groups[ box[4] ].box_pack= box # box[4] is the ID (image name) + + + # Add geometry to the mesh + for fg in face_groups.itervalues(): + # Add verts clockwise from the bottom left. + _x= fg.box_pack[0] / packWidth + _y= fg.box_pack[1] / packHeight + _w= fg.box_pack[2] / packWidth + _h= fg.box_pack[3] / packHeight + + render_me.verts.extend([\ + Vector(_x, _y, 0),\ + Vector(_x, _y +_h, 0),\ + Vector(_x + _w, _y +_h, 0),\ + Vector(_x + _w, _y, 0),\ + ]) + + render_me.faces.extend([\ + render_me.verts[-1],\ + render_me.verts[-2],\ + render_me.verts[-3],\ + render_me.verts[-4],\ + ]) + + target_face= render_me.faces[-1] + target_face.image= fg.image + target_face.mode |= TEXMODE + + # Set the UV's, we need to flip them HOZ? + target_face.uv[0].x= target_face.uv[1].x= fg.xmax + target_face.uv[2].x= target_face.uv[3].x= fg.xmin + + target_face.uv[0].y= target_face.uv[3].y= fg.ymin + target_face.uv[1].y= target_face.uv[2].y= fg.ymax + + for uv in target_face.uv: + uv_rot= ((uv-fg.cent) * fg.rot_mat[1]) + fg.cent + uv.x= uv_rot.x + uv.y= uv_rot.y + + render_context.render() + Render.CloseRenderWindow() + render_context.saveRenderedImage(PREF_IMAGE_PATH_EXPAND) + + #if not B.sys.exists(PREF_IMAGE_PATH_EXPAND): + # raise 'Error!!!' + + + # NOW APPLY THE SAVED IMAGE TO THE FACES! + #print PREF_IMAGE_PATH_EXPAND + try: + target_image= B.Image.Load(PREF_IMAGE_PATH_EXPAND) + except: + B.Draw.PupMenu('Error: Could not render or load the image at path|' + PREF_IMAGE_PATH_EXPAND) + return + + # Set to the 1 image. + for me in mesh_list: + for f in me.faces: + if f.mode & TEXMODE and f.image: + f.image= target_image + + for fg in face_groups.itervalues(): + fg.move2packed(packWidth, packHeight) + + scn.makeCurrent() + render_me.verts= None # free a tiny amount of memory. + B.Scene.Unlink(render_scn) + target_image.makeCurrent() + + +def main(): + scn= B.Scene.GetCurrent() + scn_objects = scn.objects + ob= scn_objects.active + + if not ob or ob.type != 'Mesh': + B.Draw.PupMenu('Error, no active mesh object, aborting.') + return + + # Create the variables. + # Filename without path or extension. + newpath= B.Get('filename').split('/')[-1].split('\\')[-1].replace('.blend', '') + + PREF_IMAGE_PATH = B.Draw.Create('//%s_grp' % newpath) + PREF_IMAGE_SIZE = B.Draw.Create(1024) + PREF_IMAGE_MARGIN = B.Draw.Create(6) + PREF_KEEP_ASPECT = B.Draw.Create(0) + PREF_ALL_SEL_OBS = B.Draw.Create(0) + + pup_block = [\ + 'Image Path: (no ext)',\ + ('', PREF_IMAGE_PATH, 3, 100, 'Path to new Image. "//" for curent blend dir.'),\ + 'Image Options', + ('Pixel Size:', PREF_IMAGE_SIZE, 64, 4096, 'Image Width and Height.'),\ + ('Pixel Margin:', PREF_IMAGE_MARGIN, 0, 64, 'Use a margin to stop mipmapping artifacts.'),\ + ('Keep Aspect', PREF_KEEP_ASPECT, 'If disabled, will stretch the images to the bounds of the texture'),\ + 'Texture Source',\ + ('All Sel Objects', PREF_ALL_SEL_OBS, 'Combine all selected objects into 1 texture, otherwise active object only.'),\ + ] + + if not B.Draw.PupBlock('Consolidate images...', pup_block): + return + + PREF_IMAGE_PATH= PREF_IMAGE_PATH.val + PREF_IMAGE_SIZE= PREF_IMAGE_SIZE.val + PREF_IMAGE_MARGIN= PREF_IMAGE_MARGIN.val + PREF_KEEP_ASPECT= PREF_KEEP_ASPECT.val + PREF_ALL_SEL_OBS= PREF_ALL_SEL_OBS.val + + if PREF_ALL_SEL_OBS: + mesh_list= [ob.getData(mesh=1) for ob in scn_objects.context if ob.type=='Mesh'] + # Make sure we have no doubles- dict by name, then get the values back. + + for me in mesh_list: me.tag = False + + mesh_list_new = [] + for me in mesh_list: + if me.faceUV and me.tag==False: + me.tag = True + mesh_list_new.append(me) + + # replace list with possible doubles + mesh_list = mesh_list_new + + else: + mesh_list= [ob.getData(mesh=1)] + if not mesh_list[0].faceUV: + B.Draw.PupMenu('Error, active mesh has no images, Aborting!') + return + + consolidate_mesh_images(mesh_list, scn, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PREF_KEEP_ASPECT, PREF_IMAGE_MARGIN) + B.Window.RedrawAll() + +if __name__=='__main__': + main() diff --git a/release/scripts/image_billboard.py b/release/scripts/image_billboard.py new file mode 100644 index 00000000000..b1cd9d38891 --- /dev/null +++ b/release/scripts/image_billboard.py @@ -0,0 +1,280 @@ +#!BPY +""" +Name: 'Billboard Render on Active' +Blender: 242 +Group: 'Image' +Tooltip: 'Selected objects and lamps to rendered faces on the act mesh' +""" +__author__= "Campbell Barton" +__url__= ["blender", "blenderartist"] +__version__= "1.0" + +__bpydoc__= """\ +Render Billboard Script +This can texture a simple billboard mesh from any number of selected objects. + +Renders objects in the selection to quad faces on the active mesh. + +Usage +* Light your model or enable the shadless flag so it is visible +* Make a low poly mesh out of quads with 90d corners. (this will be you billboard mesh) +* Select the model and any lamps that light it +* Select the billboard mesh so that it is active +* Run this script, Adjust settings such as image size or oversampling. +* Select a place to save the PNG image. +* Once the script has finished running return to the 3d view by pressing Shift+F5 +* To see the newly applied textures change the drawtype to 'Textured Solid' +""" +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Campbell J Barton 2006 +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender as B +import BPyMathutils +import bpy +import BPyRender +from Blender.Scene import Render + +import os +Vector= B.Mathutils.Vector + +def alpha_mat(image): + # returns a material useable for + mtl= bpy.data.materials.new() + mtl.mode |= (B.Material.Modes.SHADELESS | B.Material.Modes.ZTRANSP | B.Material.Modes.FULLOSA ) + mtl.alpha= 0.0 # so image sets the alpha + + tex= bpy.data.textures.new() + tex.type= B.Texture.Types.IMAGE + image.antialias = True + tex.setImageFlags('InterPol', 'UseAlpha') + tex.setExtend('Clip') + tex.image= image + + mtl.setTexture(0, tex, B.Texture.TexCo.UV, B.Texture.MapTo.COL | B.Texture.MapTo.ALPHA) + + return mtl + +# PupBlock Settings +GLOBALS= {} +PREF_RES= B.Draw.Create(512) +PREF_TILE_RES= B.Draw.Create(256) +PREF_AA = B.Draw.Create(1) +PREF_ALPHA= B.Draw.Create(1) +PREF_Z_OFFSET = B.Draw.Create(10.0) +PREF_IMG_PACK= B.Draw.Create(1) + + +def save_billboard(PREF_IMAGE_PATH): + B.Window.WaitCursor(1) + # remove png, add it later + PREF_IMAGE_PATH= PREF_IMAGE_PATH.replace('.png', '') + + ob_sel= GLOBALS['ob_sel'] + me_ob = GLOBALS['me_ob'] + me_data = GLOBALS['me_data'] + + time= B.sys.time() + + me_mat= me_ob.matrixWorld + + # Render images for all faces + face_data= [] # Store faces, images etc + boxes2Pack= [] + me_data.faceUV= True + + for i, f in enumerate(me_data.faces): + no= f.no + # Offset the plane by the zoffset on the faces normal + plane= [v.co * me_mat for v in f] + + # Horizontal stacking, make sure 0,1 and 2,3 are the longest + if\ + (plane[0]-plane[1]).length + (plane[2]-plane[3]).length < \ + (plane[1]-plane[2]).length + (plane[3]-plane[0]).length: + plane.append(plane.pop(0)) + rot90= True + else: + rot90= False + + + #plane.reverse() + no= B.Mathutils.QuadNormal(*plane) + plane= [v + no*PREF_Z_OFFSET.val for v in plane] + + cent= (plane[0]+plane[1]+plane[2]+plane[3] ) /4.0 + camera_matrix= BPyMathutils.plane2mat(plane) + tmp_path= '%s_%d' % (PREF_IMAGE_PATH, i) + img= BPyRender.imageFromObjectsOrtho(ob_sel, tmp_path, PREF_TILE_RES.val, PREF_TILE_RES.val, PREF_AA.val, PREF_ALPHA.val, camera_matrix) + img.reload() + #img.pack() # se we can keep overwriting the path + #img.filename= "" + + + if not PREF_IMG_PACK.val: + f.mode |= B.Mesh.FaceModes.TEX + f.image = img + f.uv=Vector(0,1), Vector(0,0), Vector(1,0), Vector(1,1) + + if PREF_ALPHA.val: + f.transp |= B.Mesh.FaceTranspModes.ALPHA + else: + w= ((plane[0]-plane[1]).length + (plane[2]-plane[3]).length)/2 + h= ((plane[1]-plane[2]).length + (plane[3]-plane[0]).length)/2 + + face_data.append( (f, img, rot90) ) + boxes2Pack.append( [0.0,0.0,h, w, i] ) + + if PREF_IMG_PACK.val: + # pack the quads into a square + packWidth, packHeight = B.Geometry.BoxPack2D(boxes2Pack) + + render_obs= [] + + # Add geometry to the mesh + for box in boxes2Pack: + i= box[4] + + orig_f, img, rot90= face_data[i] + + # New Mesh and Object + render_mat= alpha_mat(img) + + render_me= bpy.data.meshes.new() + + render_ob= B.Object.New('Mesh') + render_me.materials= [render_mat] + render_ob.link(render_me) + + render_obs.append(render_ob) + + # Add verts clockwise from the bottom left. + _x= box[0] / packWidth + _y= box[1] / packHeight + _w= box[2] / packWidth + _h= box[3] / packHeight + + + render_me.verts.extend([\ + Vector(_x, _y, 0),\ + Vector(_x, _y +_h, 0),\ + Vector(_x + _w, _y +_h, 0),\ + Vector(_x + _w, _y, 0),\ + ]) + + render_me.faces.extend(list(render_me.verts)) + render_me.faceUV= True + + # target_face= render_me.faces[-1] + # TEXFACE isnt used because of the renderign engine cant to alpha's for texdface. + #target_face.image= img + #target_face.mode |= B.Mesh.FaceModes.TEX + + # Set the UV's, we need to flip them HOZ? + uv1, uv2, uv3, uv4= orig_f.uv + uv3.x= uv4.x= _x+_w + uv1.x= uv2.x= _x + + uv2.y= uv3.y= _y+_h + uv1.y= uv4.y= _y + + if rot90: + orig_f.uv= Vector(uv4), Vector(uv1), Vector(uv2), Vector(uv3) + + target_image= BPyRender.imageFromObjectsOrtho(render_obs, PREF_IMAGE_PATH, PREF_RES.val, PREF_RES.val, PREF_AA.val, PREF_ALPHA.val, None) + + # Set to the 1 image. + for f in me_data.faces: + f.image= target_image + if PREF_ALPHA.val: + f.transp |= B.Mesh.FaceTranspModes.ALPHA + + # Free the images data and remove + for data in face_data: + img= data[1] + os.remove(img.filename) + img.reload() + # Finish pack + + me_data.update() + me_ob.makeDisplayList() + B.Window.WaitCursor(0) + print '%.2f secs taken' % (B.sys.time()-time) + + + + +def main(): + scn= bpy.data.scenes.active + ob_sel= list(scn.objects.context) + + PREF_KEEP_ASPECT= False + + # Error Checking + if len(ob_sel) < 2: + B.Draw.PupMenu("Error%t|Select 2 mesh objects") + return + + me_ob= scn.objects.active + + if not me_ob: + B.Draw.PupMenu("Error%t|No active mesh selected.") + + try: + ob_sel.remove(me_ob) + except: + pass + + if me_ob.type != 'Mesh': + B.Draw.PupMenu("Error%t|Active Object must be a mesh to write billboard images too") + return + + me_data= me_ob.getData(mesh=1) + + for f in me_data.faces: + if len(f) != 4: + B.Draw.PupMenu("Error%t|Active mesh must have only quads") + return + + + # Get user input + block = [\ + 'Image Pixel Size',\ + ("Packed Size: ", PREF_RES, 128, 2048, "Pixel width and height to render the billboard to"),\ + ("Tile Size: ", PREF_TILE_RES, 64, 1024, "Pixel width and height for each tile to render to"),\ + 'Render Settings',\ + ("Pack Final", PREF_IMG_PACK , "Pack all images into 1 image"),\ + ("Oversampling", PREF_AA , "Higher quality woth extra sampling"),\ + ("Alpha Clipping", PREF_ALPHA , "Render empty areas as transparent"),\ + ("Cam ZOffset: ", PREF_Z_OFFSET, 0.1, 100, "Distance to place the camera away from the quad when rendering")\ + ] + + if not B.Draw.PupBlock("Billboard Render", block): + return + + # Set globals + GLOBALS['ob_sel'] = ob_sel + GLOBALS['me_ob'] = me_ob + GLOBALS['me_data'] = me_data + + B.Window.FileSelector(save_billboard, 'SAVE BILLBOARD', B.sys.makename(ext='.png')) + +if __name__=='__main__': + main() diff --git a/release/scripts/image_edit.py b/release/scripts/image_edit.py new file mode 100644 index 00000000000..14ab57515ba --- /dev/null +++ b/release/scripts/image_edit.py @@ -0,0 +1,136 @@ +#!BPY +""" +Name: 'Edit Externaly' +Blender: 242a +Group: 'Image' +Tooltip: 'Open in an application for editing. (hold Shift to configure)' +""" + +__author__ = "Campbell Barton" +__url__ = ["blender", "elysiun"] +__version__ = "1.0" + +__bpydoc__ = """\ +This script opens the current image in an external application for editing. + +Useage: +Choose an image for editing in the UV/Image view. + +To configure the application to open the image with, hold Shift as you click on +this menu item. + +For first time users try running the default application for your operating system. +If the application does not open you can type in the full path. +You can choose that the last entered application will be saved as a default. + +* Note, default commants for opening an image are "start" for win32 and "open" for macos. +This will use the system default assosiated application. +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Campbell J Barton 2006 +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +try: + import os + import sys as py_sys + platform = py_sys.platform +except: + Draw.PupMenu('Error, python not installed') + os=None + +import Blender +from Blender import Image, sys, Draw, Registry + +def edit_extern(image=None): + + if not image: + image = Image.GetCurrent() + + if not image: # Image is None + Draw.PupMenu('ERROR: You must select an active Image.') + return + if image.packed: + Draw.PupMenu('ERROR: Image is packed, unpack before editing.') + return + + imageFileName = sys.expandpath( image.filename ) + + if not sys.exists(imageFileName): + Draw.PupMenu('ERROR: Image path does not exist.') + return + + pupblock = [imageFileName.split('/')[-1].split('\\')[-1]] + + new_text= False + try: + appstring = Registry.GetKey('ExternalImageEditor', True) + appstring = appstring['path'] + + # for ZanQdo if he removed the path from the textbox totaly. ;) - Cam + if not appstring or appstring.find('%f')==-1: + new_text= True + except: + new_text= True + + if new_text: + pupblock.append('first time, set path.') + if platform == 'win32': + appstring = 'start "" /B "%f"' + elif platform == 'darwin': + appstring = 'open "%f"' + else: + appstring = 'gimp-remote "%f"' + + appstring_but = Draw.Create(appstring) + save_default_but = Draw.Create(0) + + pupblock.append(('editor: ', appstring_but, 0, 48, 'Path to application, %f will be replaced with the image path.')) + pupblock.append(('Set Default', save_default_but, 'Store this path in the blender registry.')) + + # Only configure if Shift is held, + if Blender.Window.GetKeyQualifiers() & Blender.Window.Qual.SHIFT: + if not Draw.PupBlock('External Image Editor...', pupblock): + return + + appstring = appstring_but.val + save_default= save_default_but.val + + if save_default: + Registry.SetKey('ExternalImageEditor', {'path':appstring}, True) + + if appstring.find('%f') == -1: + Draw.PupMenu('ERROR: The comment you entered did not contain the filename ("%f")') + return + + # ------------------------------- + + appstring = appstring.replace('%f', imageFileName) + print '\tediting image with command "%s"' % appstring + os.system(appstring) + + +def main(): + edit_extern() + + +if __name__ == '__main__' and os != None: + main() \ No newline at end of file diff --git a/release/scripts/image_find_paths.py b/release/scripts/image_find_paths.py new file mode 100644 index 00000000000..266ecee9435 --- /dev/null +++ b/release/scripts/image_find_paths.py @@ -0,0 +1,167 @@ +#!BPY + +""" +Name: 'Fix Broken Paths' +Blender: 242 +Group: 'Image' +Tooltip: 'Search for new image paths to make relative links to' +""" + +__author__ = "Campbell Barton AKA Ideasman" +__url__ = ["blenderartist.org"] + +__bpydoc__ = """\ +Find image target paths + +This script searches for images whos +file paths do not point to an existing image file, +all image paths are made relative where possible. +usefull when moving projects between computers, when absolute paths links are broken. +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Campbell J Barton +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +from Blender import * + +try: + import os +except: + Draw.PupMenu('You need a full python install to use this script') + os= None + + +#==============================================# +# Strips the slashes from the back of a string # +#==============================================# +def stripPath(path): + return path.split('/')[-1].split('\\')[-1] + +# finds the file starting at the root. +def findImage(findRoot, imagePath): + newImageFile = None + + imageFile = imagePath.split('/')[-1].split('\\')[-1] + + # ROOT, DIRS, FILES + pathWalk = os.walk(findRoot) + pathList = [True] + + matchList = [] # Store a list of (match, size), choose the biggest. + while True: + try: + pathList = pathWalk.next() + except: + break + + for file in pathList[2]: + # FOUND A MATCH + if file.lower() == imageFile.lower(): + name = pathList[0] + sys.sep + file + try: + size = os.path.getsize(name) + except: + size = 0 + + if size: + print ' found:', name + matchList.append( (name, size) ) + + if matchList == []: + print 'no match for:', imageFile + return None + else: + # Sort by file size + matchList.sort(lambda A, B: cmp(B[1], A[1]) ) + + print 'using:', matchList[0][0] + # First item is the largest + return matchList[0][0] # 0 - first, 0 - pathname + + +# Makes the pathe relative to the blend file path. +def makeRelative(path, blendBasePath): + if path.startswith(blendBasePath): + path = path.replace(blendBasePath, '//') + path = path.replace('//\\', '//') + return path + +def find_images(findRoot): + print findRoot + + # findRoot = Draw.PupStrInput ('find in: ', '', 100) + + if findRoot == '': + Draw.PupMenu('No Directory Selected') + return + + # Account for // + findRoot = sys.expandpath(findRoot) + + # Strip filename + while findRoot[-1] != '/' and findRoot[-1] != '\\': + findRoot = findRoot[:-1] + + + if not findRoot.endswith(sys.sep): + findRoot += sys.sep + + + if findRoot != '/' and not sys.exists(findRoot[:-1]): + Draw.PupMenu('Directory Dosent Exist') + + blendBasePath = sys.expandpath('//') + + + Window.WaitCursor(1) + # ============ DIR DONE\ + images = Image.Get() + len_images = float(len(images)) + for idx, i in enumerate(images): + + progress = idx / len_images + Window.DrawProgressBar(progress, 'searching for images') + + # If files not there? + if not sys.exists(sys.expandpath(i.filename )): + newImageFile = findImage(findRoot, i.filename) + if newImageFile != None: + newImageFile= makeRelative(newImageFile, blendBasePath) + print 'newpath relink:', newImageFile + i.filename = newImageFile + i.reload() + else: + # Exists + newImageFile= makeRelative(i.filename, blendBasePath) + if newImageFile!=i.filename: + print 'newpath relative:', newImageFile + i.filename = newImageFile + + + Window.RedrawAll() + Window.DrawProgressBar(1.0, '') + Window.WaitCursor(0) + +if __name__ == '__main__' and os: + Window.FileSelector(find_images, 'SEARCH ROOT DIR', sys.expandpath('//')) + + diff --git a/release/scripts/import_dxf.py b/release/scripts/import_dxf.py new file mode 100644 index 00000000000..3f2fef72aa2 --- /dev/null +++ b/release/scripts/import_dxf.py @@ -0,0 +1,4139 @@ +#!BPY + +""" +Name: 'Autodesk DXF (.dxf)' +Blender: 244 +Group: 'Import' +Tooltip: 'Import for DXF geometry data (Drawing eXchange Format).' +""" +__author__ = 'Kitsu(Ed Blake) & migius(Remigiusz Fiedler)' +__version__ = '1.0.beta10 - 2007.09.09 by migius' +__url__ = ["http://blenderartists.org/forum/showthread.php?t=84319", + "http://wiki.blender.org/index.php/Scripts/Manual/Import/DXF-3D"] +__email__ = ["Kitsune_e(at)yahoo.com", "migius(at)4d-vectors.de"] +__bpydoc__ = """\ +This script imports DXF objects (2d/3d) into Blender. + +This script imports 2d and 3d Geometery from DXFr12 format files. +This version is focused on import of 3d-objects. + +Supported DXF Objects: +LINE +POINT +SOLID +TRACE +TEXT +INSERT (=block) +MINSERT (=array) +CIRCLE +ARC +3DFACE +2d-POLYLINE (=plane, incl. arc, variable-width, curve, spline) +3d-POLYLINE (=no-plane) +3d-POLYMESH +3d-POLYFACE +under construction, partly supported DXF>r12: +LWPOLYLINE (LightWeight), MLINE, MTEXT, ELLIPSE + +Unsupported DXF Objects: +DXF r12: DIMENSION, XREF (External Reference) +DXF>r12: SPLINE, GROUP, RAY/XLINE, LEADER, 3DSOLID, BODY, REGION, dynamic BLOCK + +Supported Properties: +Hierarchy: Entire DXF BLOCKs hierarchy is preserved after import into Blender +visibility, frozen +COLOR +LAYER +thickness +width +(todo: grouped, XDATA) +It is recommended to use DXF-object properties for coding Blender materials. + +Notes: +- Recommend that you run 'RemoveDoubles' on each imported mesh after using this script +- Blocks are created on layer 19 then referenced at each insert point. +* Big DXF-files (over 1500 objects) decrease import performance. The problem is not the inefficiency of python-scripting but Blenders performance in creating new objects in his database - probably a database management problem. +* The Blender curves of imported ARCs and POLYLINE-arc-segments have light malformed ends.(to fix in beta10) + +TODO: +- the new style object visibility +- support for Spline-curves, Besier-curves +- support for real 3d-solids (ACIS) +- (to see more, search for "-todo-" in script) + + +History: + v1.0 - 2007.09 by migius: "full 3d"-release + planned tasks: + -- filtering of unused/not-inserted BLOCKs + -- human-formating of data in INI-File + -- suport for MLine + -- suport for Ellipse + -- suport for Mtext + -- blender_object.ID.properties[dxf_layer_name] + -- Configuration files(.ini) should/can handle various material setups + -- added f_layerFilter + -- to-check: obj/mat/group/_mapping-idea from ideasman42: + -- better support for long dxf-layer-names + -- support width_force for LINEs/ARCs/CIRCLEs/ELLIPSEs = "solidify" + -- curves: added fill/non-fill option for closed curves: CIRCLEs,ELLIPSEs,POLYLINEs + -- bug:? object = Object.Get(obname) -> = SCENE.getChildren(obname) + -- command-line-mode/batch-mode + -- fixed malformed endpoints of Blender curves of imported ARCs and POLYLINE-arc segments. + beta10: 2007.09.09 by migius + a1 added "fill_on" option to draw top and bottom sides of CIRCLEs and ELLIPSEs + a1 rewrite f_CIRCLE.Draw: from Mesh.Primitive to Mesh + a1 bugfix "newScene"-mode: Cylinders/Arcs were drawn at <0,0,0>location + beta09: 2007.09.02 by migius + g5 redesign UI: grouping of buttons + g3 update multi-import-mode: <*.*> button + g- added multi-import-mode: (path/*) for importing many dxf-files at once + g- added import into newScene + g- redesign UI: user presets, into newScene-import + f- cleanup code + f- bugfix: thickness for Bezier/Bsplines into Blender-curves + f- BlenderWiki documentation, on-line Manual + f- added import POLYLINE-Bsplines into Blender-NURBSCurves + f- added import POLYLINE-arc-segments into Blender-BezierCurves + f- added import POLYLINE-Bezier-curves into Blender-Curves + d5 rewrite: Optimization Levels, added 'directDrawing' + d4 added: f_set_thick(cntrolled by ini-parameters) + d4 bugfix: face-normals in objects with minus thickness + d4 added: placeholder'Empty'-size in f_Insert.draw + d3 rewrite f_Text.Draw: added suport for all Text's parameters + d2 redesign: progressbar + e- tuning by ideasman42: better use of the Py API. + c- tuning by ideasman42 + b- rewrite f_Text.Draw rotation/transform + b- bugfix: POLYLINE-segment-intersection more reliable now + b- bugfix: circle:_thic, 'Empties':no material_assignement + b- added material assignment (from layer and/or color) + a- added empty, cylinder and UVsphere for POINTs + a- added support for 2d-POLYLINE: splines, fitted curves, fitted surfaces + a- redesign f_Drawer for block_definitions + a- rewrite import into Blender-Curve-Object + beta08: 2007.07.27 by migius + l- bugfix: solid_vgroups, clean:scene.objects.new() + l- redesign UI to standard Draw.Register+FileSelector, advanced_config_option + k- bugfix UI:fileSelect() for MacOSX os.listdir() + k- added reset/save/load for config-data + k- redesign keywords/drawTypes/Draw.Create_Buttons + j- new interface using UIBlock() with own FileSelector, cause Window.FileSelector() too buggy + i- rewritten Class:Settings for better config-parameter management + h- bugfix: face-normals in objects with minus thickness + h- added Vertex-Groups in polylines and solids generated Meshes, for easier material assignment + h- beautify code, whitespace->tabs + h- added settings.thic_force switch for forcing thickness + h- added one Object/Mesh for all simple-entities from the same Layer, + sorted in Vertex-Groups(color_name) (fewer objects = better import performance) + g- rewrote: insert-point-handle-object is a small tetrahedron + e- bugfix: closed-polymesh3d + - rewrote: startUI, type_map.keys, f_drawer, for all class_f_draw(added "settings" as attribut) + - added 2d/3d-support for Polyline_Width incl. angleintersection + beta07: 2007.06.19 by migius + - added 3d-support for LWPolylines + - added 2d/3d-support for Points + beta06: 2007.06.15 by migius + - cleanup code + - added 2d/3d-support for MINSERT=BlockArray in f_drawer, added f_rotXY_Vec + beta05: 2007.06.14 by migius + - added 2d/3d-support for 3d-PolyLine, PolyMesh and PolyFace + - added Global-Scale for size control of imported scenes + beta04: 2007.06.12 by migius + - rewrote the f_drawBulge for correct import the arc-segments of Polylines + beta03: 2007.06.10 by migius + - rewrote interface + beta02: 2007.06.09 by migius + - added 3d-support for Arcs and Circles + - added support for Object_Thickness(=height) + beta01: 2007.06.08 by migius + - added 3d-support for Blocks/Inserts within nested-structures + - rewrote f_transform for correct 3d-location/3d-rotation + - added 3d-support Lines, 3dFaces + - added 2d+3d-support for Solids and Traces + + v0.9 - 2007.01 by kitsu: (for 2.43) + - + + v0.8 - 2006.12 by kitsu: + - + + v0.5b - 2006.10 by kitsu: (for 2.42a) + - + +""" + +# -------------------------------------------------------------------------- +# DXF Import v1.0 by Ed Blake (AKA kitsu) and Remigiusz Fiedler (AKA migius) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender +import bpy +from Blender import * +#from Blender.Mathutils import Vector, Matrix +#import BPyMessages + + +from dxfReader import readDXF # get_name, get_layer +from dxfReader import Object as dxfObject +from dxfColorMap import color_map +from math import * + +try: + import os + if os.name:# != 'mac': + import psyco + psyco.log() + psyco.full(memory=100) + psyco.profile(0.05, memory=100) + psyco.profile(0.2) +except ImportError: + pass + +print '\n\n\n\n' +print 'Import DXF to Blender *** START ***' #--------------------- + +SCENE = None +WORLDX = Mathutils.Vector((1,0,0)) +WORLDY = Mathutils.Vector((1,1,0)) +WORLDZ = Mathutils.Vector((0,0,1)) + +G_SCALE = 1.0 #(0.0001-1000) global scaling factor for all dxf data +MIN_DIST = 0.001 #cut-off value for sort out short-distance polyline-"duoble_vertex" +ARC_RESOLUTION = 64 #(4-500) arc/circle resolution - number of segments +ARC_RADIUS = 1.0 #(0.01-100) arc/circle radius for number of segments algorithm +THIN_RESOLUTION = 8 #(4-500) thin_cylinder arc_resolution - number of segments +MIN_THICK = MIN_DIST * 10.0 #minimal thickness by forced thickness +MIN_WIDTH = MIN_DIST * 10.0 #minimal width by forced width +ANGLECUT_LIMIT = 3.0 #limit for anglecut of polylines-wide-segments (values:1.0 - 5.0) +TARGET_LAYER = 3 #target blender_layer +GROUP_BYLAYER = 0 #(0/1) all entities from same layer import into one blender-group + +FILENAME_MAX = 180 #max length of path+file_name string (FILE_MAXDIR + FILE_MAXFILE) +MAX_NAMELENGTH = 17 #max_effective_obnamelength in blender =21=17+(.001) +INIFILE_DEFAULT_NAME = 'importDXF' +INIFILE_EXTENSION = '.ini' +INIFILE_HEADER = 'ImportDXF.py ver.1.0 config data' + +AUTO = BezTriple.HandleTypes.AUTO +FREE = BezTriple.HandleTypes.FREE +VECT = BezTriple.HandleTypes.VECT +ALIGN = BezTriple.HandleTypes.ALIGN +cur_COUNTER = 0 #counter for progress_bar + + +"""This module provides wrapper objects for dxf entities. + + The wrappers expect a "dxf object" as input. The dxf object is + an object with a type and a data attribute. Type is a lowercase + string matching the 0 code of a dxf entity. Data is a list containing + dxf objects or lists of [code, data] pairs. + + This module is not general, and is only for dxf import. +""" + +# from Stani's dxf writer v1.1 (c)www.stani.be (GPL) +#---color values +BYBLOCK=0 +BYLAYER=256 + +#---block-type flags (bit coded values, may be combined): +ANONYMOUS =1 # This is an anonymous block generated by hatching, associative dimensioning, other internal operations, or an application +NON_CONSTANT_ATTRIBUTES =2 # This block has non-constant attribute definitions (this bit is not set if the block has any attribute definitions that are constant, or has no attribute definitions at all) +XREF =4 # This block is an external reference (xref) +XREF_OVERLAY =8 # This block is an xref overlay +EXTERNAL =16 # This block is externally dependent +RESOLVED =32 # This is a resolved external reference, or dependent of an external reference (ignored on input) +REFERENCED =64 # This definition is a referenced external reference (ignored on input) + +#---polyline flags +CLOSED =1 # This is a closed polyline (or a polygon mesh closed in the M direction) +CURVE_FIT =2 # Curve-fit vertices have been added +SPLINE_FIT =4 # Spline-fit vertices have been added +POLYLINE_3D =8 # This is a 3D polyline +POLYGON_MESH =16 # This is a 3D polygon mesh +CLOSED_N =32 # The polygon mesh is closed in the N direction +POLYFACE_MESH =64 # The polyline is a polyface mesh +CONTINOUS_LINETYPE_PATTERN =128 # The linetype pattern is generated continuously around the vertices of this polyline + +#---text flags +#horizontal +LEFT = 0 +CENTER = 1 +RIGHT = 2 +ALIGNED = 3 #if vertical alignment = 0 +MIDDLE = 4 #if vertical alignment = 0 +FIT = 5 #if vertical alignment = 0 +#vertical +BASELINE = 0 +BOTTOM = 1 +MIDDLE = 2 +TOP = 3 + +#---mtext flags +#attachment point +TOP_LEFT = 1 +TOP_CENTER = 2 +TOP_RIGHT = 3 +MIDDLE_LEFT = 4 +MIDDLE_CENTER = 5 +MIDDLE_RIGHT = 6 +BOTTOM_LEFT = 7 +BOTTOM_CENTER = 8 +BOTTOM_RIGHT = 9 +#drawing direction +LEFT_RIGHT = 1 +TOP_BOTTOM = 3 +BY_STYLE = 5 #the flow direction is inherited from the associated text style +#line spacing style (optional): +AT_LEAST = 1 #taller characters will override +EXACT = 2 #taller characters will not override + + + +class Layer: #----------------------------------------------------------------- + """Class for objects representing dxf layers. + """ + def __init__(self, obj, name=None, color=None, frozen=None): + """Expects an object of type layer as input. + """ + self.type = obj.type + self.data = obj.data[:] + + if name: + self.name = name + #self.bfname = name #remi--todo----------- + else: + self.name = obj.get_type(2)[0] #layer name of object + + if color: + self.color = color + else: + self.color = obj.get_type(62)[0] #color of object + + if frozen: + self.frozen = frozen + else: + self.flags = obj.get_type(70)[0] + self.frozen = self.flags&1 + + + def __repr__(self): + return "%s: name - %s, color - %s" %(self.__class__.__name__, self.name, self.color) + + + +def getit(obj, typ, default=None): #------------------------------------------ + """Universal procedure for geting data from list/objects. + """ + it = default + if type(obj) == list: #if obj is a list, then searching in a list + for item in obj: + #print 'deb:getit item, type(item)', item, type(item) + try: + if item[0] == typ: + it = item[1] + break #as soon as the first found + except: + # TODO - I found one case where item was a text instance + # that failed with no __getitem__ + pass + else: #else searching in Object with get_type-Methode + item = obj.get_type(typ) + if item: + it = item[0] + #print 'deb:getit:typ, it', typ, it #---------- + return it + + + +def get_extrusion(data): #------------------------------------------------- + """Find the axis of extrusion. + + Used to get from object_data the objects Object Coordinate System (ocs). + """ + #print 'deb:get_extrusion: data: \n', data #--------------- + vec = [0,0,1] + vec[0] = getit(data, 210, 0) # 210 = x + vec[1] = getit(data, 220, 0) # 220 = y + vec[2] = getit(data, 230, 1) # 230 = z + #print 'deb:get_extrusion: vec: ', vec #--------------- + return vec + + + + + +class Solid: #----------------------------------------------------------------- + """Class for objects representing dxf solid or trace. + """ + def __init__(self, obj): + """Expects an entity object of type solid or trace as input. + """ + if obj.type == 'trace': + obj.type = 'solid' + if not obj.type == 'solid': + raise TypeError, "Wrong type \'%s\' for solid/trace object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + self.space = getit(obj, 67, 0) + self.thic = getit(obj, 39, 0) + self.color_index = getit(obj, 62, BYLAYER) + + self.layer = getit(obj.data, 8, None) + self.extrusion = get_extrusion(obj.data) + self.points = self.get_points(obj.data) + + + + def get_points(self, data): + """Gets start and end points for a solid type object. + + Solids have 3 or 4 points and fixed codes for each value. + """ + + # start x, y, z and end x, y, z = 0 + a = [0, 0, 0] + b = [0, 0, 0] + c = [0, 0, 0] + d = [0, 0, 0] + a[0] = getit(data, 10, None) # 10 = x + a[1] = getit(data, 20, None) # 20 = y + a[2] = getit(data, 30, 0) # 30 = z + b[0] = getit(data, 11, None) + b[1] = getit(data, 21, None) + b[2] = getit(data, 31, 0) + c[0] = getit(data, 12, None) + c[1] = getit(data, 22, None) + c[2] = getit(data, 32, 0) + out = [a,b,c] + + d[0] = getit(data, 13, None) + if d[0] != None: + d[1] = getit(data, 23, None) + d[2] = getit(data, 33, 0) + out.append(d) + #print 'deb:solid.vertices:---------\n', out #----------------------- + return out + + + def __repr__(self): + return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) + + + def draw(self, settings): + """for SOLID: generate Blender_geometry. + """ + points = self.points + if not points: return + edges, faces = [], [] + l = len(self.points) + + obname = 'so_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + + vg_left, vg_right, vg_top, vg_bottom, vg_start, vg_end = [], [], [], [], [], [] + thic = set_thick(self.thic, settings) + if thic != 0: + thic_points = [[v[0], v[1], v[2] + thic] for v in points[:]] + if thic < 0.0: + thic_points.extend(points) + points = thic_points + else: + points.extend(thic_points) + + if l == 4: + faces = [[0,1,3,2], [4,6,7,5], [0,4,5,1], + [1,5,7,3], [3,7,6,2], [2,6,4,0]] + vg_left = [2,6,4,0] + vg_right = [1,5,7,3] + vg_top = [4,6,7,5] + vg_bottom = [0,1,3,2] + vg_start = [0,4,5,1] + vg_end = [3,7,6,2] + elif l == 3: + faces = [[0,1,2], [3,5,4], [0,3,4,1], [1,4,5,2], [2,5,3,0]] + vg_top = [3,4,5] + vg_bottom = [0,1,2] + vg_left = [2,5,3,0] + vg_right = [1,4,5,2] + vg_start = [0,3,4,1] + elif l == 2: faces = [[0,1,3,2]] + else: + if l == 4: faces = [[0,1,3,2]] + elif l == 3: faces = [[0,1,2]] + elif l == 2: edges = [[0,1]] + + + + me = Mesh.New(obname) # create a new mesh + me.verts.extend(points) # add vertices to mesh + if faces: me.faces.extend(faces) # add faces to the mesh + if edges: me.edges.extend(edges) # add faces to the mesh + + ob = SCENE.objects.new(me) # create a new mesh_object + if settings.var['vGroup_on']: + # each MeshSite becomes vertexGroup for easier material assignment --------------------- + replace = Blender.Mesh.AssignModes.ADD #or .AssignModes.ADD/REPLACE + if vg_left: me.addVertGroup('side.left') ; me.assignVertsToGroup('side.left', vg_left, 1.0, replace) + if vg_right:me.addVertGroup('side.right') ; me.assignVertsToGroup('side.right', vg_right, 1.0, replace) + if vg_top: me.addVertGroup('side.top') ; me.assignVertsToGroup('side.top', vg_top, 1.0, replace) + if vg_bottom:me.addVertGroup('side.bottom'); me.assignVertsToGroup('side.bottom',vg_bottom, 1.0, replace) + if vg_start:me.addVertGroup('side.start') ; me.assignVertsToGroup('side.start', vg_start, 1.0, replace) + if vg_end: me.addVertGroup('side.end') ; me.assignVertsToGroup('side.end', vg_end, 1.0, replace) + + transform(self.extrusion, 0, ob) + + return ob + + + + +class Line: #----------------------------------------------------------------- + """Class for objects representing dxf lines. + """ + def __init__(self, obj): + """Expects an entity object of type line as input. + """ + if not obj.type == 'line': + raise TypeError, "Wrong type \'%s\' for line object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + self.space = getit(obj, 67, 0) + self.thic = getit(obj, 39, 0) + #print 'deb:self.thic: ', self.thic #--------------------- + self.color_index = getit(obj, 62, BYLAYER) + + self.layer = getit(obj.data, 8, None) + self.extrusion = get_extrusion(obj.data) + self.points = self.get_points(obj.data) + + + def get_points(self, data): + """Gets start and end points for a line type object. + + Lines have a fixed number of points (two) and fixed codes for each value. + """ + # start x,y,z and end x,y,z = 0 + a = [0, 0, 0] + b = [0, 0, 0] + a[0] = getit(data, 10, None) # 10 = x + a[1] = getit(data, 20, None) # 20 = y + a[2] = getit(data, 30, 0) # 30 = z + b[0] = getit(data, 11, None) + b[1] = getit(data, 21, None) + b[2] = getit(data, 31, 0) + out = [a,b] + return out + + + def __repr__(self): + return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) + + + def draw(self, settings): + """for LINE: generate Blender_geometry. + """ + # Generate the geometery + #settings.var['curves_on']=False + + points = self.points + + global activObjectLayer + global activObjectName + #print 'deb:draw:line.ob IN activObjectName: ', activObjectName #--------------------- + + if activObjectLayer == self.layer and settings.var['one_mesh_on']: + obname = activObjectName + #print 'deb:line.draw obname from activObjectName: ', obname #--------------------- + ob = Object.Get(obname) # open an existing mesh_object + #ob = SCENE.getChildren(obname) # open an existing mesh_object + me = Mesh.Get(ob.name) # open objects mesh data + else: + obname = 'li_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + activObjectName = ob.name + activObjectLayer = self.layer + #print ('deb:line.draw new line.ob+mesh:"%s" created!' %ob.name) #--------------------- + + #if settings.var['width_force']: # -todo----------- + + faces, edges = [], [] + n = len(me.verts) + thic = set_thick(self.thic, settings) + if thic != 0: + t, e = thic, self.extrusion + #print 'deb:thic, extr: ', t, e #--------------------- + points.extend([[v[0]+t*e[0], v[1]+t*e[1], v[2]+t*e[2]] for v in points[:]]) + faces = [[0+n, 1+n, 3+n, 2+n]] + else: + me.verts.extend(points) # add vertices to mesh + edges = [[0+n, 1+n]] + + me.verts.extend(points) # add vertices to mesh + if faces: me.faces.extend(faces) # add faces to the mesh + if edges: me.edges.extend(edges) # add faces to the mesh + + if settings.var['vGroup_on']: + # entities with the same color build one vertexGroup for easier material assignment --------------------- + ob.link(me) # link mesh to that object + vG_name = 'color_%s' %self.color_index + if edges: faces = edges + replace = Blender.Mesh.AssignModes.ADD #or .AssignModes.REPLACE or ADD + try: + me.assignVertsToGroup(vG_name, faces[0], 1.0, replace) + #print 'deb: existed vGroup:', vG_name #--------------------- + except: + me.addVertGroup(vG_name) + me.assignVertsToGroup(vG_name, faces[0], 1.0, replace) + #print 'deb: create new vGroup:', vG_name #--------------------- + + + #print 'deb:draw:line.ob OUT activObjectName: ', activObjectName #--------------------- + return ob + + + +class Point: #----------------------------------------------------------------- + """Class for objects representing dxf points. + """ + def __init__(self, obj): + """Expects an entity object of type point as input. + """ + if not obj.type == 'point': + raise TypeError, "Wrong type %s for point object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + self.space = getit(obj, 67, 0) + self.thic = getit(obj, 39, 0) + #print 'deb:self.thic: ', self.thic #--------------------- + self.color_index = getit(obj, 62, BYLAYER) + + self.layer = getit(obj.data, 8, None) + self.extrusion = get_extrusion(obj.data) + self.points = self.get_points(obj.data) + + + def get_points(self, data): + """Gets coordinates for a point type object. + + Points have fixed codes for each value. + """ + a = [0, 0, 0] + a[0] = getit(data, 10, None) # 10 = x + a[1] = getit(data, 20, None) # 20 = y + a[2] = getit(data, 30, 0) # 30 = z + out = [a] + return out + + + def __repr__(self): + return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) + + + def draw(self, settings): + """for POINT: generate Blender_geometry. + """ + points = self.points + obname = 'po_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + points_as = settings.var['points_as'] + thic = settings.var['thick_min'] + if thic < settings.var['dist_min']: thic = settings.var['dist_min'] + + if points_as in [1,3,4]: + if points_as == 1: # as 'empty' + c = 'Empty' + if points_as == 3: # as 'thin sphere' + res = settings.var['thin_res'] + c = Mesh.Primitives.UVsphere(res,res,thic) + if points_as == 4: # as 'thin box' + c = Mesh.Primitives.Cube(thic) + ob = SCENE.objects.new(c, obname) # create a new object + transform(self.extrusion, 0, ob) + ob.loc = tuple(points[0]) + + elif points_as == 2: # as 'vertex' + global activObjectLayer + global activObjectName + #print 'deb:draw:point.ob IN activObjectName: ', activObjectName #--------------------- + if activObjectLayer == self.layer and settings.var['one_mesh_on']: + obname = activObjectName + #print 'deb:draw:point.ob obname from activObjectName: ', obname #--------------------- + ob = Object.Get(obname) # open an existing mesh_object + #ob = SCENE.getChildren(obname) # open an existing mesh_object + me = Mesh.Get(ob.name) # open objects mesh data + else: + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + activObjectName = ob.name + activObjectLayer = self.layer + #print ('deb:draw:point new point.ob+mesh:"%s" created!' %ob.name) #--------------------- + me.verts.extend(points) # add vertices to mesh + + return ob + + + + +class LWpolyline: #----------------------------------------------------------------- + """Class for objects representing dxf LWpolylines. + """ + def __init__(self, obj): + """Expects an entity object of type lwpolyline as input. + """ + #print 'deb:LWpolyline.START:----------------' #------------------------ + if not obj.type == 'lwpolyline': + raise TypeError, "Wrong type %s for polyline object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.num_points = obj.get_type(90)[0] + + # optional data (with defaults) + self.space = getit(obj, 67, 0) + + self.color_index = getit(obj, 62, BYLAYER) + + self.elevation = getit(obj, 30, 0) + self.thic = getit(obj, 39, 0) + self.flags = getit(obj, 70, 0) + + self.closed = self.flags&1 # byte coded, 1 = closed, 128 = plinegen + + self.layer = getit(obj.data, 8, None) + self.points = self.get_points(obj.data) + self.extrusion = get_extrusion(obj.data) + + #print 'deb:LWpolyline.obj.data:\n', obj.data #------------------------ + #print 'deb:LWpolyline.ENDinit:----------------' #------------------------ + + + def get_points(self, data): + """Gets points for a polyline type object. + + LW-Polylines have no fixed number of verts, and + each vert can have a number of properties. + Verts should be coded as + 10:xvalue + 20:yvalue + 40:startwidth or 0 + 41:endwidth or 0 + 42:bulge or 0 + for each vert + """ + num = self.num_points + point = None + points = [] + for item in data: + if item[0] == 10: # 10 = x + if point: + points.append(point) + point = Vertex() + point.x = item[1] + elif item[0] == 20: # 20 = y + point.y = item[1] + elif item[0] == 40: # 40 = start width + point.swidth = item[1] + elif item[0] == 41: # 41 = end width + point.ewidth = item[1] + elif item[0] == 42: # 42 = bulge + point.bulge = item[1] + points.append(point) + return points + + + + def __repr__(self): + return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) + + + def draw(self, settings): + """for LWPOLYLINE: generate Blender_geometry. + """ + #print 'deb:LWpolyline.draw.START:----------------' #------------------------ + points = [] + obname = 'lw_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + #settings.var['curves_on'] == True + #print 'deb:index_len: ', len(self.points) #------------------ + for i, point in enumerate(self.points): + #print 'deb:index: ', i #------------------ + if not point.bulge: + points.append(point.loc) + elif point.bulge and not self.closed and i == len(self.points)-1: + points.append(point.loc) + elif point.bulge: # + if i == len(self.points)-1: + point2 = self.points[0] + else: + point2 = self.points[i+1] + arc_res = settings.var['arc_res']/sqrt(settings.var['arc_rad']) + verts = drawBulge(point, point2, arc_res) +# if i == len(self.points)-1: +# if self.closed: +# verts.pop() #remove last(=first) vertex +# else: +# verts.pop() #remove last vertex, because this point will be writen as the next vertex + points.extend(verts) + + thic = self.thic + if settings.var['thick_force'] and thic == 0: thic = settings.var['thick_min'] + if settings.var['thick_on'] and thic != 0: + len1 = len(points) + points.extend([[point[0], point[1], point[2]+thic] for point in points]) + faces = [] + #print 'deb:len1:', len1 #----------------------- + faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)] + if self.closed: + faces.append([len1-1, 0, len1, 2*len1-1]) + #print 'deb:faces_list:\n', faces #----------------------- + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + me.verts.extend(points) # add vertices to mesh + me.faces.extend(faces) # add faces to the mesh + else: + edges = [[num, num+1] for num in xrange(len(points)-1)] + if self.closed: + edges.append([len(points)-1, 0]) + #print 'deb:edges_list:\n', edges #----------------------- + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + me.verts.extend(points) # add vertices to mesh + me.edges.extend(edges) # add edges to the mesh + + ob.LocZ = self.elevation + transform(self.extrusion, 0, ob) + + #print 'deb:LWpolyline.draw.END:----------------' #------------------------ + return ob + + + +class Polyline: #----------------------------------------------------------------- + """Class for objects representing dxf Polylines. + """ + def __init__(self, obj): + """Expects an entity object of type polyline as input. + """ + #print 'deb:polyline.init.START:----------------' #------------------------ + if not obj.type == 'polyline': + raise TypeError, "Wrong type %s for polyline object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + #print 'deb:polyline.obj.data[:]:\n', obj.data[:] #------------------------ + self.points = [] + + # optional data (with defaults) + self.space = getit(obj, 67, 0) + self.elevation = getit(obj, 30, 0) + #print 'deb:elevation: ', self.elevation #--------------- + self.thic = getit(obj, 39, 0) + self.color_index = getit(obj, 62, BYLAYER) + + self.flags = getit(obj, 70, 0) + self.closed = self.flags & 1 # closed in the M direction + self.curved = self.flags & 2 # Bezier-curve-fit vertices have been added + self.spline = self.flags & 4 # Bspline-fit vertices have been added + self.poly3d = self.flags & 8 # 3D-polyline + self.plmesh = self.flags & 16 # 3D-polygon mesh + self.closeN = self.flags & 32 # closed in the N direction + self.plface = self.flags & 64 # 3D-polyface mesh + self.contin = self.flags & 128 # the linetype pattern is generated continuously + + if self.poly3d or self.plface or self.plmesh: + self.poly2d = False # its not a 2D-polyline + else: + self.poly2d = True # it is a 2D-polyline + + self.swidth = getit(obj, 40, 0) # default start width + self.ewidth = getit(obj, 41, 0) # default end width + #self.bulge = getit(obj, 42, None) # bulge of the segment + self.vectorsM = getit(obj, 71, None) # PolyMesh: expansion in M-direction / PolyFace: number of the vertices + self.vectorsN = getit(obj, 72, None) # PolyMesh: expansion in M-direction / PolyFace: number of faces + #self.resolM = getit(obj, 73, None) # resolution of surface in M direction + #self.resolN = getit(obj, 74, None) # resolution of surface in N direction + self.curvetyp = getit(obj, 75, 0) # type of curve/surface: 0=None/5=Quadric/6=Cubic/8=Bezier + self.curvNormal = False + self.curvQBspline = False + self.curvCBspline = False + self.curvBezier = False + if self.curvetyp == 0: self.curvNormal = True + elif self.curvetyp == 5: self.curvQBspline = True + elif self.curvetyp == 6: self.curvCBspline = True + elif self.curvetyp == 8: self.curvBezier = True + + self.layer = getit(obj.data, 8, None) + self.extrusion = get_extrusion(obj.data) + + self.points = [] #list with vertices coordinats + self.faces = [] #list with vertices assigment to faces + #print 'deb:polyline.init.ENDinit:----------------' #------------ + + + + def __repr__(self): + return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) + + + + def draw(self, settings): #-------------%%%% DRAW POLYLINE %%%--------------- + """for POLYLINE: generate Blender_geometry. + """ + ob = [] + if self.plface: #---- 3dPolyFace - mesh with free topology + ob = self.drawPlFace(settings) + elif self.plmesh: #---- 3dPolyMesh - mesh with ortogonal topology + ob = self.drawPlMesh(settings) + #---- 2dPolyline - plane polyline with arc/wide/thic segments + #---- 3dPolyline - noplane polyline (thin segments = without arc/wide/thic) + elif self.poly2d or self.poly3d: + if settings.var['curves_on']: # and self.spline: + ob = self.drawPolyCurve(settings) + else: + ob = self.drawPoly2d(settings) + return ob + + + + def drawPlFace(self, settings): #---- 3dPolyFace - mesh with free topology + """Generate the geometery of polyface. + """ + #print 'deb:polyface.draw.START:----------------' #------------------------ + points = [] + faces = [] + #print 'deb:len of pointsList ====== ', len(self.points) #------------------------ + for point in self.points: + if point.face: + faces.append(point.face) + else: + points.append(point.loc) + + + #print 'deb:len of points_list:\n', len(points) #----------------------- + #print 'deb:points_list:\n', points #----------------------- + #print 'deb:faces_list:\n', faces #----------------------- + obname = 'pf_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + me.verts.extend(points) # add vertices to mesh + me.faces.extend(faces) # add faces to the mesh + + transform(self.extrusion, 0, ob) + #print 'deb:polyface.draw.END:----------------' #------------------------ + + return ob + + + + def drawPlMesh(self, settings): #---- 3dPolyMesh - mesh with orthogonal topology + """Generate the geometery of polymesh. + """ + #print 'deb:polymesh.draw.START:----------------' #------------------------ + #points = [] + #print 'deb:len of pointsList ====== ', len(self.points) #------------------------ + faces = [] + m = self.vectorsM + n = self.vectorsN + for j in xrange(m - 1): + for i in xrange(n - 1): + nn = j * n + faces.append([nn+i, nn+i+1, nn+n+i+1, nn+n+i]) + + if self.closed: #mesh closed in N-direction + nn = (m-1)*n + for i in xrange(n - 1): + faces.append([nn+i, nn+i+1, i+1, i]) + + if self.closeN: #mesh closed in M-direction + for j in xrange(m-1): + nn = j * n + faces.append([nn+n-1, nn, nn+n, nn+n-1+n]) + + if self.closed and self.closeN: #mesh closed in M/N-direction + faces.append([ (n*m)-1, (m-1)*n, 0, n-1]) + + #print 'deb:len of points_list:\n', len(points) #----------------------- + #print 'deb:faces_list:\n', faces #----------------------- + obname = 'pm_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + me.verts.extend([point.loc for point in self.points]) # add vertices to mesh + me.faces.extend(faces) # add faces to the mesh + + transform(self.extrusion, 0, ob) + #print 'deb:polymesh.draw.END:----------------' #------------------------ + return ob + + + def drawPolyCurve(self, settings): #---- Polyline - draw as Blender-curve + """Generate the geometery of polyline as Blender-curve. + """ + #print 'deb:polyline2dCurve.draw.START:----------------' #--- + if len(self.points) < 2: + #print 'deb:drawPoly2d exit, cause POLYLINE has less than 2 vertices' #--------- + return + + if self.spline: pline_typ = 'ps' # Polyline-nurbSpline + elif self.curved: pline_typ = 'pc' # Polyline-bezierCurve + else: pline_typ = 'pl' # Polyline + obname = '%s_%s' %(pline_typ, self.layer) # create object_name from layer name + obname = obname[:MAX_NAMELENGTH] + d_points = [] + #for DXFr10-format: update all points[].loc[2] == None -> 0.0 + for point in self.points: + if point.loc[2] == None: + point.loc[2] = self.elevation + d_points.append(point) + + thic = set_thick(self.thic, settings) + + if thic != 0.0: #hack: Blender<2.45 curve-extrusion + LocZ = d_points[0].loc[2] + temp_points = [] + for point in d_points: + point.loc[2] = 0.0 + temp_points.append(point) + d_points = temp_points + + #print 'deb:polyline2dCurve.draw d_points=', d_points #--------------- + pline = Curve.New(obname) # create new curve data + + if False: #self.spline: # NURBSplines-----FAKE(with Bezier)----- + #print 'deb:polyline2dCurve.draw self.spline!' #--------------- + curve = pline.appendNurb(BezTriple.New(d_points[0])) + for p in d_points[1:]: + curve.append(BezTriple.New(p)) + for point in curve: + point.handleTypes = [AUTO, AUTO] + if self.closed: + curve.flagU = 1 # Set curve cyclic=close + else: + curve.flagU = 0 # Set curve not cyclic=open + curve[0].handleTypes = [FREE, ALIGN] #remi--todo----- + curve[-1].handleTypes = [ALIGN, FREE] #remi--todo----- + + elif self.spline: # NURBSplines-----TODO--:if curvQBspline: generate middlepoints--- + #print 'deb:polyline2dCurve.draw self.spline!' #--------------- + weight1 = 0.5 + weight2 = 1.0 + # generate middlepoints except start/end-segments --- + if self.curvQBspline: + temp_points = [] + point = d_points[0].loc + point.append(weight1) + temp_points.append(point) + for i in xrange(1,len(d_points)-2): + point1 = d_points[i].loc + point2 = d_points[i+1].loc + mpoint = list((Mathutils.Vector(point1) + Mathutils.Vector(point2)) * 0.5) + mpoint.append(weight2) + point1.append(weight1) + temp_points.append(point1) + temp_points.append(mpoint) + point2.append(weight1) + temp_points.append(point2) + point = d_points[-1].loc + point.append(weight1) + temp_points.append(point) + d_points = temp_points + else: + temp_points = [] + for d in d_points: + d = d.loc + d.append(weight1) + temp_points.append(d) + d_points = temp_points + + if not self.closed: + # generate extended startpoint and endpoint------ + point1 = Mathutils.Vector(d_points[0][:3]) + point2 = Mathutils.Vector(d_points[1][:3]) + startpoint = list(point1 - point2 + point1) + startpoint.append(weight1) + point1 = Mathutils.Vector(d_points[-1][:3]) + point2 = Mathutils.Vector(d_points[-2][:3]) + endpoint = list(point1 - point2 + point1) + endpoint.append(weight1) + temp_points = [] + temp_points.append(startpoint) + temp_points.extend(d_points) + d_points = temp_points + d_points.append(endpoint) + + point = d_points[0] + curve = pline.appendNurb(point) + curve.setType(4) #NURBS curve + for point in d_points[1:]: + curve.append(point) + if self.closed: + curve.flagU = 1 # Set curve cyclic=close + else: + curve.flagU = 0 # Set curve not cyclic=open + + elif self.curved: #--Bezier-curves---OK------- + #print 'deb:polyline2dCurve.draw self.curved!' #--------------- + curve = pline.appendNurb(BezTriple.New(d_points[0])) + for p in d_points[1:]: + curve.append(BezTriple.New(p)) + for point in curve: + point.handleTypes = [AUTO, AUTO] + if self.closed: + curve.flagU = 1 # Set curve cyclic=close + else: + curve.flagU = 0 # Set curve not cyclic=open + curve[0].handleTypes = [FREE, ALIGN] #remi--todo----- + curve[-1].handleTypes = [ALIGN, FREE] #remi--todo----- + + else: #--straight line/arc-segments----OK------ + points = [] + d_points.append(d_points[0]) #------ first vertex added ------------- + #curve.setType(0) #polygon_type of Blender_curve + for i in xrange(len(d_points)-1): + point1 = d_points[i] + point2 = d_points[i+1] + if point1.bulge and (i < len(d_points)-2 or self.closed): + verts = drawBulge(point1, point2, arc_res=8, curve_on=True) #calculate additional points for bulge + if i == 0: curve = pline.appendNurb(BezTriple.New(verts[0])) + else: curve.append(BezTriple.New(verts[0])) + curve[-1].handleTypes = [VECT, VECT] #--todo--calculate bezier-tangents + for p in verts[1:]: + curve.append(BezTriple.New(p)) + curve[-1].handleTypes = [AUTO, AUTO] #--todo--calculate bezier-tangents +# curve[-1].handleTypes = [VECT, VECT] #--todo--calculate bezier-tangents + else: + if i == 0: curve = pline.appendNurb(BezTriple.New(point1.loc)) + else: curve.append(BezTriple.New(point1.loc)) + curve[-1].handleTypes = [VECT, VECT] #--todo--calculate bezier-tangents + if self.closed: + curve.flagU = 1 # Set curve cyclic=close +# curve[0].handleTypes = [VECT, VECT] #--todo--calculate bezier-tangents + else: + curve.flagU = 0 # Set curve not cyclic=open + curve[0].handleTypes = [FREE, VECT] #--todo--calculate bezier-tangents + curve[-1].handleTypes = [VECT, FREE] #--todo--calculate bezier-tangents + + pline.update() + ob = SCENE.objects.new(pline) # create a new curve_object + + if thic != 0.0: #hack: Blender<2.45 curve-extrusion + thic = thic * 0.5 + pline.setExt1(1.0) # curve-extrusion accepts only (0.0 - 2.0) + ob.LocZ = thic + LocZ + + transform(self.extrusion, 0, ob) + if thic != 0.0: + ob.SizeZ *= abs(thic) + + #print 'deb:polyline2dCurve.draw.END:----------------' #----- + return ob + + + def drawPoly2d(self, settings): #---- 2dPolyline - plane wide/thic lines + """Generate the geometery of regular polyline. + """ + #print 'deb:polyline2d.draw.START:----------------' #------------------------ + points = [] + d_points = [] + swidths = [] + ewidths = [] + swidth_default = self.swidth #default start width of POLYLINEs segments + ewidth_default = self.ewidth #default end width of POLYLINEs segments + thic = set_thick(self.thic, settings) + if self.spline: pline_typ = 'ps' + elif self.curved: pline_typ = 'pc' + else: pline_typ = 'pl' + obname = '%s_%s' %(pline_typ, self.layer) # create object_name from layer name +# obname = 'pl_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + + if len(self.points) < 2: + #print 'deb:drawPoly2d exit, cause POLYLINE has less than 2 vertices' #--------- + return + #d_points = self.points[:] + #for DXFr10-format: update all points[].loc[2] == None -> 0.0 + for point in self.points: + if point.loc[2] == None: + point.loc[2] = self.elevation + d_points.append(point) + #print 'deb:len of d_pointsList ====== ', len(d_points) #------------------------ + + #add duplic of the first vertex at the end of pointslist + d_points.append(d_points[0]) + + #print 'deb:len of d_pointsList ====== ', len(d_points) #------------------------ + #print 'deb:d_pointsList ======:\n ', d_points #------------------------ + + + #routine to sort out of "double.vertices" -------- + minimal_dist = settings.var['dist_min'] * 0.1 + temp_points = [] + for i in xrange(len(d_points)-1): + point = d_points[i] + point2 = d_points[i+1] + #print 'deb:double.vertex p1,p2', point, point2 #------------------------ + delta = Mathutils.Vector(point2.loc) - Mathutils.Vector(point.loc) + if delta.length > minimal_dist: + temp_points.append(point) + #else: print 'deb:double.vertex sort out!' #------------------------ + temp_points.append(d_points[-1]) #------ last vertex added ------------- + d_points = temp_points #-----vertex.list without "double.vertices" + #print 'deb:d_pointsList =after DV-outsorting=====:\n ', d_points #------------------------ + + #print 'deb:len of d_pointsList ====== ', len(d_points) #------------------------ + if len(d_points) < 2: + #print 'deb:drawPoly2d corrupted Vertices' #--------- + return + + #analyse of straight- and bulge-segments (generation of additional points for bulge) + exist_wide_segment = False + for i in xrange(len(d_points)-1): + point1 = d_points[i] + point2 = d_points[i+1] + #print 'deb:pline.tocalc.point1:', point1 #------------------------ + #print 'deb:pline.tocalc.point2:', point2 #------------------------ + + swidth = point1.swidth + ewidth = point1.ewidth + if swidth == None: swidth = swidth_default + if ewidth == None: ewidth = ewidth_default + + if swidth != 0.0 or ewidth != 0.0: exist_wide_segment = True + + if settings.var['width_force']: # force minimal width for thin segments + if swidth < settings.var['width_min']: swidth = settings.var['width_min'] + if ewidth < settings.var['width_min']: ewidth = settings.var['width_min'] + if not settings.var['width_on']: # then force minimal width for all segments + swidth = settings.var['width_min'] + ewidth = settings.var['width_min'] + + if point1.bulge and (i < (len(d_points)-2) or self.closed): + arc_res = settings.var['arc_res']/sqrt(settings.var['arc_rad']) + verts = drawBulge(point1, point2, arc_res) #calculate additional points for bulge + points.extend(verts) + delta_width = (ewidth - swidth) / len(verts) + width_list = [swidth + (delta_width * ii) for ii in xrange(len(verts)+1)] + swidths.extend(width_list[0:-1]) + ewidths.extend(width_list[1:]) + else: + points.append(point1.loc) + swidths.append(swidth) + ewidths.append(ewidth) + + + #--calculate width_vectors: left-side- and right-side-points ---------------- + # 1.level:IF width --------------------------------------- + if (settings.var['width_on'] and exist_wide_segment) or settings.var['width_force']: + points.append(d_points[0].loc) #temporarly add first vertex at the end (for better loop) + + pointsLs = [] # list of left-start-points + pointsLe = [] # list of left-end-points + pointsRs = [] # list of right-start-points + pointsRe = [] # list of right-end-points + pointsW = [] # list of entire-border-points + #rotMatr90 = Mathutils.Matrix(rotate 90 degree around Z-axis) = normalvectorXY + rotMatr90 = Mathutils.Matrix([0, -1, 0], [1, 0, 0], [0, 0, 1]) + for i in xrange(len(points)-1): + point1 = points[i] + point2 = points[i+1] + point1vec = Mathutils.Vector(point1) + point2vec = Mathutils.Vector(point2) + swidth05 = swidths[i] * 0.5 + ewidth05 = ewidths[i] * 0.5 + if swidth05 == 0: swidth05 = 0.5 * settings.var['dist_min'] #minimal width + if ewidth05 == 0: ewidth05 = 0.5 * settings.var['dist_min'] #minimal width + + normal_vector = rotMatr90 * (point2vec-point1vec).normalize() + swidth05vec = swidth05 * normal_vector + ewidth05vec = ewidth05 * normal_vector + pointsLs.append(point1vec + swidth05vec) #vertex left start + pointsRs.append(point1vec - swidth05vec) #vertex right start + pointsLe.append(point2vec + ewidth05vec) #vertex left end + pointsRe.append(point2vec - ewidth05vec) #vertex right end + + pointsLc, pointsRc = [], [] + + # 2.level:IF width and corner-intersection activated + if settings.var['pl_section_on']: #optional clean corner-intersections + if not self.closed: + pointsLc.append(pointsLs[0]) + pointsRc.append(pointsRs[0]) + lenL = len(pointsLs)-2 #without the last point at the end of the list + else: + pointsLs.append(pointsLs[0]) + pointsRs.append(pointsRs[0]) + pointsLe.append(pointsLe[0]) + pointsRe.append(pointsRe[0]) + points.append(points[0]) + lenL = len(pointsLs)-1 #without the duplic of the first point at the end of the list + #print 'deb:pointsLs():\n', pointsLs #---------------- + #print 'deb:lenL, len.pointsLs():', lenL,',', len(pointsLs) #---------------- + for i in xrange(lenL): + pointVec = Mathutils.Vector(points[i+1]) + #print 'deb:pointVec: ', pointVec #------------- + #compute left-corner-points + vecL1 = pointsLs[i] + vecL2 = pointsLe[i] + vecL3 = pointsLs[i+1] + vecL4 = pointsLe[i+1] + #print 'deb:vectorsL:---------\n', vecL1,'\n',vecL2,'\n',vecL3,'\n',vecL4 #------------- + #cornerpointL = Geometry.LineIntersect2D(vec1, vec2, vec3, vec4) + cornerpointL = Mathutils.LineIntersect(vecL1, vecL2, vecL3, vecL4) + #print 'deb:cornerpointL: ', cornerpointL #------------- + + #compute right-corner-points + vecR1 = pointsRs[i] + vecR2 = pointsRe[i] + vecR3 = pointsRs[i+1] + vecR4 = pointsRe[i+1] + #print 'deb:vectorsR:---------\n', vecR1,'\n',vecR2,'\n',vecR3,'\n',vecR4 #------------- + #cornerpointR = Geometry.LineIntersect2D(vec1, vec2, vec3, vec4) + cornerpointR = Mathutils.LineIntersect(vecR1, vecR2, vecR3, vecR4) + #print 'deb:cornerpointR: ', cornerpointR #------------- + + #if diststance(cornerL-center-cornerR) < limiter * (seg1_endWidth + seg2_startWidth) + if cornerpointL != None and cornerpointR != None: + cornerpointL = cornerpointL[0] + cornerpointR = cornerpointR[0] + max_cornerDist = (vecL2 - vecR2).length + (vecL3 - vecR3).length + is_cornerDist = (cornerpointL - pointVec).length + (cornerpointR - pointVec).length + # anglecut --------- limited by ANGLECUT_LIMIT (1.0 - 5.0) + if is_cornerDist < max_cornerDist * settings.var['angle_cut']: + pointsLc.append(cornerpointL) + pointsRc.append(cornerpointR) + else: + pointsLc.extend((pointsLe[i],pointsLs[i+1])) + pointsRc.extend((pointsRe[i],pointsRs[i+1])) + else: + pointsLc.extend((pointsLe[i],pointsLs[i+1])) + pointsRc.extend((pointsRe[i],pointsRs[i+1])) + if not self.closed: + pointsLc.append(pointsLe[-2]) + pointsRc.append(pointsRe[-2]) + else: + """ """ + + # 2.level:IF width but not corner-intersection activated + else: + # points_multiplexer of start-points and end-points + lenL = len(pointsLs) - 1 #without the duplic of the first point at the end of list + if self.closed: lenL += 1 #inclusive the duplic of the first point at the end of list + for i in xrange(lenL): + pointsLc.extend((pointsLs[i], pointsLe[i])) + pointsRc.extend((pointsRs[i], pointsRe[i])) + + pointsW = pointsLc + pointsRc # all_points_List = left_side + right_side + #print 'deb:pointsW():\n', pointsW #---------------- + len1 = int(len(pointsW) * 0.5) + #print 'deb:len1:', len1 #----------------------- + + # 2.level:IF width and thickness --------------------- + if thic != 0: + thic_pointsW = [] + thic_pointsW.extend([[point[0], point[1], point[2]+thic] for point in pointsW]) + if thic < 0.0: + thic_pointsW.extend(pointsW) + pointsW = thic_pointsW + else: + pointsW.extend(thic_pointsW) + faces = [] + f_start, f_end = [], [] + f_bottom = [[num, num+1, len1+num+1, len1+num] for num in xrange(len1-1)] + f_top = [[num, len1+num, len1+num+1, num+1] for num in xrange(len1+len1, len1+len1+len1-1)] + f_left = [[num, len1+len1+num, len1+len1+num+1, num+1] for num in xrange(len1-1)] + f_right = [[num, num+1, len1+len1+num+1, len1+len1+num] for num in xrange(len1, len1+len1-1)] + + if self.closed: + f_bottom.append([len1-1, 0, len1, len1+len1-1]) #bottom face + f_top.append( [len1+len1+len1-1, len1+len1+len1+len1-1, len1+len1+len1, len1+len1+0]) #top face + f_left.append( [0, len1-1, len1+len1+len1-1, len1+len1]) #left face + f_right.append( [len1, len1+len1+len1, len1+len1+len1+len1-1, len1+len1-1]) #right face + else: + f_start = [[0, len1, len1+len1+len1, len1+len1]] + f_end = [[len1+len1-1, 0+len1-1, len1+len1+len1-1, len1+len1+len1+len1-1]] + + faces = f_bottom + f_top + f_left + f_right + f_start + f_end + #faces = f_bottom + f_top + #faces = f_left + f_right + f_start + f_end + #print 'deb:faces_list:\n', faces #----------------------- + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + me.verts.extend(pointsW) # add vertices to mesh + me.faces.extend(faces) # add faces to the mesh + + # each MeshSite becomes vertexGroup for easier material assignment --------------------- + # The mesh must first be linked to an object so the method knows which object to update. + # This is because vertex groups in Blender are stored in the object -- not in the mesh, + # which may be linked to more than one object. + if settings.var['vGroup_on']: + # each MeshSite becomes vertexGroup for easier material assignment --------------------- + replace = Blender.Mesh.AssignModes.REPLACE #or .AssignModes.ADD + vg_left, vg_right, vg_top, vg_bottom = [], [], [], [] + for v in f_left: vg_left.extend(v) + for v in f_right: vg_right.extend(v) + for v in f_top: vg_top.extend(v) + for v in f_bottom: vg_bottom.extend(v) + me.addVertGroup('side.left') ; me.assignVertsToGroup('side.left', list(set(vg_left)), 1.0, replace) + me.addVertGroup('side.right') ; me.assignVertsToGroup('side.right', list(set(vg_right)), 1.0, replace) + me.addVertGroup('side.top') ; me.assignVertsToGroup('side.top', list(set(vg_top)), 1.0, replace) + me.addVertGroup('side.bottom'); me.assignVertsToGroup('side.bottom',list(set(vg_bottom)), 1.0, replace) + if not self.closed: + me.addVertGroup('side.start'); me.assignVertsToGroup('side.start', f_start[0], 1.0, replace) + me.addVertGroup('side.end') ; me.assignVertsToGroup('side.end', f_end[0], 1.0, replace) + + + # 2.level:IF width, but no-thickness --------------------- + else: + faces = [] + faces = [[num, len1+num, len1+num+1, num+1] for num in xrange(len1 - 1)] + if self.closed: + faces.append([len1, 0, len1-1, len1+len1-1]) + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + me.verts.extend(pointsW) # add vertices to mesh + me.faces.extend(faces) # add faces to the mesh + + + # 1.level:IF no-width, but thickness --------------------- + elif thic != 0: + len1 = len(points) + thic_points = [] + thic_points.extend([[point[0], point[1], point[2]+thic] for point in points]) + if thic < 0.0: + thic_points.extend(points) + points = thic_points + else: + points.extend(thic_points) + faces = [] + faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)] + if self.closed: + faces.append([len1-1, 0, len1, 2*len1-1]) + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + me.verts.extend(points) # add vertices to mesh + me.faces.extend(faces) # add faces to the mesh + + # 1.level:IF no-width and no-thickness --------------------- + else: + edges = [[num, num+1] for num in xrange(len(points)-1)] + if self.closed: + edges.append([len(points)-1, 0]) + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + me.verts.extend(points) # add vertices to mesh + me.edges.extend(edges) # add edges to the mesh + + transform(self.extrusion, 0, ob) + #print 'deb:polyline.draw.END:----------------' #----------------------- + return ob + + + + +class Vertex(object): #----------------------------------------------------------------- + """Generic vertex object used by polylines (and maybe others). + """ + + def __init__(self, obj=None): + """Initializes vertex data. + + The optional obj arg is an entity object of type vertex. + """ + #print 'deb:Vertex.init.START:----------------' #----------------------- + self.loc = [0,0,0] + self.face = [] + self.swidth = 0 + self.ewidth = 0 + self.bulge = 0 + if obj is not None: + if not obj.type == 'vertex': + raise TypeError, "Wrong type %s for vertex object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + self.get_props(obj.data) + #print 'deb:Vertex.init.END:----------------' #------------------------ + + + def get_props(self, data): + """Gets coords for a VERTEX type object. + + Each vert can have a number of properties. + Verts should be coded as + 10:xvalue + 20:yvalue + 40:startwidth or 0 + 41:endwidth or 0 + 42:bulge or 0 + """ + self.x = getit(data, 10, None) + self.y = getit(data, 20, None) + self.z = getit(data, 30, None) + + self.flags = getit(data, 70, 0) # flags + self.curved = self.flags&1 # Bezier-curve-fit:additional-vertex + self.curv_t = self.flags&2 # Bezier-curve-fit:tangent exists + self.spline = self.flags&8 # Bspline-fit:additional-vertex + self.splin2 = self.flags&16 # Bspline-fit:control-vertex + self.poly3d = self.flags&32 # polyline3d:control-vertex + self.plmesh = self.flags&64 # polymesh3d:control-vertex + self.plface = self.flags&128 # polyface + + # if PolyFace.Vertex with Face_definition + if self.curv_t: + self.curv_tangent = getit(data, 50, None) # curve_tangent + + if self.plface and not self.plmesh: + v1 = getit(data, 71, 0) # polyface:Face.vertex 1. + v2 = getit(data, 72, 0) # polyface:Face.vertex 2. + v3 = getit(data, 73, 0) # polyface:Face.vertex 3. + v4 = getit(data, 74, None) # polyface:Face.vertex 4. + self.face = [abs(v1)-1,abs(v2)-1,abs(v3)-1] + if v4 != None: + self.face.append(abs(v4)-1) + else: #--parameter for polyline2d + self.swidth = getit(data, 40, None) # start width + self.ewidth = getit(data, 41, None) # end width + self.bulge = getit(data, 42, 0) # bulge of segment + + + def __len__(self): + return 3 + + + def __getitem__(self, key): + return self.loc[key] + + + def __setitem__(self, key, value): + if key in [0,1,2]: + self.loc[key] + + + def __iter__(self): + return self.loc.__iter__() + + + def __str__(self): + return str(self.loc) + + + def __repr__(self): + return "Vertex %s, swidth=%s, ewidth=%s, bulge=%s, face=%s" %(self.loc, self.swidth, self.ewidth, self.bulge, self.face) + + + def getx(self): + return self.loc[0] + def setx(self, value): + self.loc[0] = value + x = property(getx, setx) + + + def gety(self): + return self.loc[1] + def sety(self, value): + self.loc[1] = value + y = property(gety, sety) + + + def getz(self): + return self.loc[2] + def setz(self, value): + self.loc[2] = value + z = property(getz, setz) + + + +class Text: #----------------------------------------------------------------- + """Class for objects representing dxf Text. + """ + def __init__(self, obj): + """Expects an entity object of type text as input. + """ + if not obj.type == 'text': + raise TypeError, "Wrong type %s for text object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.height = 1.7 * obj.get_type(40)[0] #text.height + self.value = obj.get_type(1)[0] #The text string value + + # optional data (with defaults) + self.space = getit(obj, 67, 0) + self.color_index = getit(obj, 62, BYLAYER) + self.thic = getit(obj, 39, 0) + + self.rotation = getit(obj, 50, 0) # radians + self.width_factor = getit(obj, 41, 1) # Scaling factor along local x axis + self.oblique = getit(obj, 51, 0) # oblique angle: skew in degrees -90 <= oblique <= 90 + + #self.style = getit(obj, 7, 'STANDARD') # --todo---- Text style name (optional, default = STANDARD) + + #Text generation flags (optional, default = 0): + #2 = backward (mirrored in X), + #4 = upside down (mirrored in Y) + self.flags = getit(obj, 71, 0) + self.mirrorX, self.mirrorY = 1.0, 1.0 + if self.flags&2: self.mirrorX = - 1.0 + if self.flags&4: self.mirrorY = - 1.0 + + # vertical.alignment: 0=baseline, 1=bottom, 2=middle, 3=top + self.valignment = getit(obj, 73, 0) + #Horizontal text justification type (optional, default = 0) integer codes (not bit-coded) + #0=left, 1=center, 2=right + #3=aligned, 4=middle, 5=fit + self.halignment = getit(obj, 72, 0) + + self.layer = getit(obj.data, 8, None) + self.loc1, self.loc2 = self.get_loc(obj.data) + if self.loc2[0] != None and self.halignment != 5: + self.loc = self.loc2 + else: + self.loc = self.loc1 + self.extrusion = get_extrusion(obj.data) + + + + def get_loc(self, data): + """Gets adjusted location for text type objects. + + If group 72 and/or 73 values are nonzero then the first alignment point values + are ignored and AutoCAD calculates new values based on the second alignment + point and the length and height of the text string itself (after applying the + text style). If the 72 and 73 values are zero or missing, then the second + alignment point is meaningless. + I don't know how to calc text size... + """ + # bottom left x, y, z and justification x, y, z = 0 + #x, y, z, jx, jy, jz = 0, 0, 0, 0, 0, 0 + x = getit(data, 10, None) #First alignment point (in OCS). + y = getit(data, 20, None) + z = getit(data, 30, 0.0) + jx = getit(data, 11, None) #Second alignment point (in OCS). + jy = getit(data, 21, None) + jz = getit(data, 31, 0.0) + return [x, y, z],[jx, jy, jz] + + + def __repr__(self): + return "%s: layer - %s, value - %s" %(self.__class__.__name__, self.layer, self.value) + + + def draw(self, settings): + """for TEXTs: generate Blender_geometry. + """ + obname = 'tx_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + txt = Text3d.New(obname) + ob = SCENE.objects.new(txt) # create a new text_object + + txt.setText(self.value) + txt.setSize(1.0) #Blender<2.45 accepts only (0.0 - 5.0) + #txt.setSize(self.height) + #txt.setWidth(self.bold) + #setLineSeparation(sep) + txt.setShear(self.oblique/90) + + thic = set_thick(self.thic, settings) + if thic != 0.0: + thic = self.thic * 0.5 + self.loc[2] += thic + txt.setExtrudeDepth(1.0) #Blender<2.45 accepts only (0.1 - 10.0) + if self.halignment == 0: + align = Text3d.LEFT + elif self.halignment == 1: + align = Text3d.MIDDLE + elif self.halignment == 2: + align = Text3d.RIGHT + else: + align = Text3d.LEFT + txt.setAlignment(align) + + if self.valignment == 1: + txt.setYoffset(0.0) + elif self.valignment == 2: + txt.setYoffset(- self.height * 0.5) + elif self.valignment == 3: + txt.setYoffset(- self.height) + + # move the object center to the text location + ob.loc = tuple(self.loc) + transform(self.extrusion, self.rotation, ob) + + # flip it and scale it to the text width + ob.SizeX *= self.height * self.width_factor * self.mirrorX + ob.SizeY *= self.height * self.mirrorY + if thic != 0.0: ob.SizeZ *= abs(thic) + return ob + + + +def set_thick(thickness, settings): + """Set thickness relative to settings variables. + + Set thickness relative to settings variables: + 'thick_on','thick_force','thick_min'. + Accepted also minus values of thickness + python trick: sign(x)=cmp(x,0) + """ + if settings.var['thick_force']: + if settings.var['thick_on']: + if abs(thickness) < settings.var['thick_min']: + thic = settings.var['thick_min'] * cmp(self.thic,0) + else: thic = thickness + else: thic = settings.var['thick_min'] + else: + if settings.var['thick_on']: thic = thickness + else: thic = 0.0 + return thic + + + + +class Mtext: #----------------------------------------------------------------- + """Class for objects representing dxf Mtext. + """ + + def __init__(self, obj): + """Expects an entity object of type mtext as input. + """ + if not obj.type == 'mtext': + raise TypeError, "Wrong type %s for mtext object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.height = obj.get_type(40)[0] + self.width = obj.get_type(41)[0] + self.alignment = obj.get_type(71)[0] # alignment 1=TL, 2=TC, 3=TR, 4=ML, 5=MC, 6=MR, 7=BL, 8=BC, 9=BR + self.value = self.get_text(obj.data) # The text string value + + # optional data (with defaults) + self.space = getit(obj, 67, 0) + self.color_index = getit(obj, 62, BYLAYER) + self.rotation = getit(obj, 50, 0) # radians + + self.width_factor = getit(obj, 42, 1) # Scaling factor along local x axis + self.line_space = getit(obj, 44, 1) # percentage of default + + self.layer = getit(obj.data, 8, None) + self.loc = self.get_loc(obj.data) + self.extrusion = get_extrusion(obj.data) + + + def get_text(self, data): + """Reconstructs mtext data from dxf codes. + """ + primary = '' + secondary = [] + for item in data: + if item[0] == 1: # There should be only one primary... + primary = item[1] + elif item[0] == 3: # There may be any number of extra strings (in order) + secondary.append(item[1]) + if not primary: + #raise ValueError, "Empty Mtext Object!" + string = "Empty Mtext Object!" + if not secondary: + string = primary.replace(r'\P', '\n') + else: + string = ''.join(secondary)+primary + string = string.replace(r'\P', '\n') + return string + + + def get_loc(self, data): + """Gets location for a mtext type objects. + + Mtext objects have only one point indicating + """ + loc = [0, 0, 0] + loc[0] = getit(data, 10, None) + loc[1] = getit(data, 20, None) + loc[2] = getit(data, 30, 0.0) + return loc + + + def __repr__(self): + return "%s: layer - %s, value - %s" %(self.__class__.__name__, self.layer, self.value) + + + def draw(self, settings): + """for MTEXTs: generate Blender_geometry. + """ + # Now Create an object + obname = 'tm_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + txt = Text3d.New(obname) + ob = SCENE.objects.new(txt) # create a new text_object + + txt.setSize(1) + # Blender doesn't give access to its text object width currently + # only to the text3d's curve width... + #txt.setWidth(text.width/10) + txt.setLineSeparation(self.line_space) + txt.setExtrudeDepth(0.5) + txt.setText(self.value) + + # scale it to the text size + ob.SizeX = self.height * self.width_factor + ob.SizeY = self.height + ob.SizeZ = self.height + + # move the object center to the text location + ob.loc = tuple(self.loc) + transform(self.extrusion, self.rotation, ob) + + return ob + + + + +class Circle: #----------------------------------------------------------------- + """Class for objects representing dxf Circles. + """ + + def __init__(self, obj): + """Expects an entity object of type circle as input. + """ + if not obj.type == 'circle': + raise TypeError, "Wrong type %s for circle object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.radius = obj.get_type(40)[0] + + # optional data (with defaults) + self.space = getit(obj, 67, 0) + self.thic = getit(obj, 39, 0) + self.color_index = getit(obj, 62, BYLAYER) + + self.layer = getit(obj.data, 8, None) + self.loc = self.get_loc(obj.data) + self.extrusion = get_extrusion(obj.data) + + + + def get_loc(self, data): + """Gets the center location for circle type objects. + + Circles have a single coord location. + """ + loc = [0, 0, 0] + loc[0] = getit(data, 10, None) + loc[1] = getit(data, 20, None) + loc[2] = getit(data, 30, 0.0) + return loc + + + + def __repr__(self): + return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius) + + + def draw(self, settings): + """for CIRCLE: generate Blender_geometry. + """ + obname = 'ci_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + radius = self.radius + + thic = set_thick(self.thic, settings) + if settings.var['curves_on']: + c = Curve.New(obname) # create new curve data + p1 = (0, -radius, 0) + p2 = (radius, 0, 0) + p3 = (0, radius, 0) + p4 = (-radius, 0, 0) + + p1 = BezTriple.New(p1) + p2 = BezTriple.New(p2) + p3 = BezTriple.New(p3) + p4 = BezTriple.New(p4) + + curve = c.appendNurb(p1) + curve.append(p2) + curve.append(p3) + curve.append(p4) + for point in curve: + point.handleTypes = [AUTO, AUTO] + curve.flagU = 1 # Set curve cyclic=closed + c.update() + + #remi --todo-----to check--------------------------- + ob = SCENE.objects.new(c) # create a new circle_mesh_object + ob.loc = tuple(self.loc) + if thic != 0.0: #hack: Blender<2.45 curve-extrusion + thic = thic * 0.5 + c.setExt1(1.0) # curve-extrusion accepts only (0.0 - 2.0) + ob.LocZ = thic + self.loc[2] + transform(self.extrusion, 0, ob) + if thic != 0.0: + ob.SizeZ *= abs(thic) + return ob + + elif False: + verts_num = settings.var['arc_res'] * sqrt(radius / settings.var['arc_rad']) + if verts_num > 100: verts_num = 100 # Blender accepts only values [3:500] + if verts_num < 4: verts_num = 4 # Blender accepts only values [3:500] + if thic != 0: + loc2 = thic * 0.5 #-----blenderAPI draw Cylinder with 2*thickness + self.loc[2] += loc2 #---new location for the basis of cylinder + #print 'deb:circleDraw:self.loc2:', self.loc #----------------------- + c = Mesh.Primitives.Cylinder(int(verts_num), radius*2, abs(thic)) + else: + c = Mesh.Primitives.Circle(int(verts_num), radius*2) + + #c.update() + ob = SCENE.objects.new(c, obname) # create a new circle_mesh_object + ob.loc = tuple(self.loc) + transform(self.extrusion, 0, ob) + return ob + + else: + cir = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(cir) # create a new arc_object + # set a number of segments in entire circle + arc_res = settings.var['arc_res'] * sqrt(radius) / sqrt(settings.var['arc_rad']) + start, end = 0.0 , 360.0 + verts, edges = drawArc(None, radius, start, end, arc_res) + verts = verts[:-2] #list without last point (cause first piont equal) + edges = edges[:-1] + edges[-1][1] = 0 + print 'deb:edges:', edges #remi-todo----- why is this List inhomogene ? ---------- + if thic != 0: + len1 = len(verts) + thic_verts = [] + thic_verts.extend([[point[0], point[1], point[2]+thic] for point in verts]) + if thic < 0.0: + thic_verts.extend(verts) + verts = thic_verts + else: + verts.extend(thic_verts) + faces = [] + faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)] + faces.append([len1 - 1, 0, len1, len1 + len1 -1]) + if settings.var['fill_on']: + if thic < 0.0: + verts.append([0,0,thic]) #center of top side + verts.append([0,0,0]) #center of bottom side + else: + verts.append([0,0,0]) #center of bottom side + verts.append([0,0,thic]) #center of top side + center1 = len(verts)-2 + center2 = len(verts)-1 + faces.extend([num+1, num, center1] for num in xrange(len1 - 1)) + faces.append([0, len1 - 1, center1]) + faces.extend([num+len1, num+1+len1, center2] for num in xrange(len1 - 1)) + faces.append([len1-1+len1, 0+len1, center2]) + #print 'deb:verts:', verts #--------------- + #print 'deb:faces:', faces #--------------- + cir.verts.extend(verts) # add vertices to mesh + cir.faces.extend(faces) # add faces to the mesh + else: + cir.verts.extend(verts) # add vertices to mesh + cir.edges.extend(edges) # add edges to the mesh + + ob.loc = tuple(self.loc) + transform(self.extrusion, 0, ob) + return ob + + + + +class Arc: #----------------------------------------------------------------- + """Class for objects representing dxf arcs. + """ + + def __init__(self, obj): + """Expects an entity object of type arc as input. + """ + if not obj.type == 'arc': + raise TypeError, "Wrong type %s for arc object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.radius = obj.get_type(40)[0] + self.start_angle = obj.get_type(50)[0] + self.end_angle = obj.get_type(51)[0] + + # optional data (with defaults) + self.space = getit(obj, 67, 0) + self.thic = getit(obj, 39, 0) + self.color_index = getit(obj, 62, BYLAYER) + + self.layer = getit(obj.data, 8, None) + self.loc = self.get_loc(obj.data) + self.extrusion = get_extrusion(obj.data) + + + + def get_loc(self, data): + """Gets the center location for arc type objects. + + Arcs have a single coord location. + """ + loc = [0, 0, 0] + loc[0] = getit(data, 10, None) + loc[1] = getit(data, 20, None) + loc[2] = getit(data, 30, 0.0) + return loc + + + + def __repr__(self): + return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius) + + + def draw(self, settings): + """for ARC: generate Blender_geometry. + """ + obname = 'ar_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + + center = self.loc + radius = self.radius + start = self.start_angle + end = self.end_angle + #print 'deb:drawArc: center, radius, start, end:\n', center, radius, start, end #--------- + thic = set_thick(self.thic, settings) + + if settings.var['curves_on']: + arc_res = 8 + verts, edges = drawArc(None, radius, start, end, arc_res) + arc = Curve.New(obname) # create new curve data + curve = arc.appendNurb(BezTriple.New(verts[0])) + for p in verts[1:]: + curve.append(BezTriple.New(p)) + for point in curve: + point.handleTypes = [AUTO, AUTO] + #print 'deb:arc.draw point=', point #--------------- + curve[0].handleTypes = [FREE, VECT] #remi--todo----- + curve[-1].handleTypes = [VECT, FREE] #remi--todo----- + curve.flagU = 0 # Set curve not cyclic=open + arc.update() + + #remi --todo-----to check--------------------------- + ob = SCENE.objects.new(arc) # create a new circle_mesh_object + ob.loc = tuple(self.loc) + if thic != 0.0: #hack: Blender<2.45 curve-extrusion + thic = thic * 0.5 + arc.setExt1(1.0) # curve-extrusion accepts only (0.0 - 2.0) + ob.LocZ = thic + self.loc[2] + transform(self.extrusion, 0, ob) + if thic != 0.0: + ob.SizeZ *= abs(thic) + return ob + + else: + arc = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(arc) # create a new arc_object + # set a number of segments in entire circle + arc_res = settings.var['arc_res'] * sqrt(radius) / sqrt(settings.var['arc_rad']) + verts, edges = drawArc(None, radius, start, end, arc_res) + if thic != 0: + len1 = len(verts) + thic_verts = [] + thic_verts.extend([[point[0], point[1], point[2]+thic] for point in verts]) + if thic < 0.0: + thic_verts.extend(verts) + verts = thic_verts + else: + verts.extend(thic_verts) + faces = [] + #print 'deb:len1:', len1 #----------------------- + #print 'deb:verts:', verts #remi-todo----- why is this List inhomogene ---------- + faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)] + + arc.verts.extend(verts) # add vertices to mesh + arc.faces.extend(faces) # add faces to the mesh + else: + arc.verts.extend(verts) # add vertices to mesh + arc.edges.extend(edges) # add edges to the mesh + + #arc.update() + #ob = SCENE.objects.new(arc) # create a new arc_object + #ob.link(arc) + ob.loc = tuple(center) + #ob.loc = Mathutils.Vector(ob.loc) + transform(self.extrusion, 0, ob) + #ob.size = (1,1,1) + return ob + + +class BlockRecord: #----------------------------------------------------------------- + """Class for objects representing dxf block_records. + """ + + def __init__(self, obj): + """Expects an entity object of type block_record as input. + """ + if not obj.type == 'block_record': + raise TypeError, "Wrong type %s for block_record object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.name = getit(obj, 2, None) + + # optional data (with defaults) + self.insertion_units = getit(obj, 70, None) + self.insert_units = getit(obj, 1070, None) + """code 1070 Einfügeeinheiten: + 0 = Keine Einheiten; 1 = Zoll; 2 = Fuß; 3 = Meilen; 4 = Millimeter; + 5 = Zentimeter; 6 = Meter; 7 = Kilometer; 8 = Mikrozoll; + 9 = Mils; 10 = Yard; 11 = Angstrom; 12 = Nanometer; + 13 = Mikrons; 14 = Dezimeter; 15 = Dekameter; + 16 = Hektometer; 17 = Gigameter; 18 = Astronomische Einheiten; + 19 = Lichtjahre; 20 = Parsecs + """ + + + def __repr__(self): + return "%s: name - %s, insert units - %s" %(self.__class__.__name__, self.name, self.insertion_units) + + + + +class Block: #----------------------------------------------------------------- + """Class for objects representing dxf blocks. + """ + + def __init__(self, obj): + """Expects an entity object of type block as input. + """ + if not obj.type == 'block': + raise TypeError, "Wrong type %s for block object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + self.name = obj.name + + # required data + self.flags = obj.get_type(70)[0] + self.entities = dxfObject('block_contents') #creates empty entities_container for this block + self.entities.data = objectify([ent for ent in obj.data if type(ent) != list]) + + # optional data (with defaults) + self.path = getit(obj, 1, '') + self.discription = getit(obj, 4, '') + + self.layer = getit(obj.data, 8, None) + self.loc = self.get_loc(obj.data) + + + def get_loc(self, data): + """Gets the insert point of the block. + """ + loc = [0, 0, 0] + loc[0] = getit(data, 10, None) # 10 = x + loc[1] = getit(data, 20, None) # 20 = y + loc[2] = getit(data, 30, 0.0) # 30 = z + return loc + + + def __repr__(self): + return "%s: name - %s, description - %s, xref-path - %s" %(self.__class__.__name__, self.name, self.discription, self.path) + + + + +class Insert: #----------------------------------------------------------------- + """Class for objects representing dxf inserts. + """ + + def __init__(self, obj): + """Expects an entity object of type insert as input. + """ + if not obj.type == 'insert': + raise TypeError, "Wrong type %s for insert object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.blockname = obj.get_type(2)[0] + + # optional data (with defaults) + self.rotation = getit(obj, 50, 0) + self.space = getit(obj, 67, 0) + self.color_index = getit(obj, 62, BYLAYER) + + self.layer = getit(obj.data, 8, None) + self.loc = self.get_loc(obj.data) + self.scale = self.get_scale(obj.data) + self.rows, self.columns = self.get_array(obj.data) + self.extrusion = get_extrusion(obj.data) + + + + def get_loc(self, data): + """Gets the center location for block type objects. + """ + loc = [0, 0, 0] + loc[0] = getit(data, 10, 0.0) + loc[1] = getit(data, 20, 0.0) + loc[2] = getit(data, 30, 0.0) + return loc + + + + def get_scale(self, data): + """Gets the x/y/z scale factor for the block. + """ + scale = [1, 1, 1] + scale[0] = getit(data, 41, 1.0) + scale[1] = getit(data, 42, 1.0) + scale[2] = getit(data, 43, 1.0) + return scale + + + + def get_array(self, data): + """Returns the pair (row number, row spacing), (column number, column spacing). + """ + columns = getit(data, 70, 1) + rows = getit(data, 71, 1) + cspace = getit(data, 44, 0.0) + rspace = getit(data, 45, 0.0) + return (rows, rspace), (columns, cspace) + + + + def __repr__(self): + return "%s: layer - %s, blockname - %s" %(self.__class__.__name__, self.layer, self.blockname) + + + def draw(self, settings, deltaloc): + """for INSERT(block): draw empty-marker for duplicated Blender_Group. + + Blocks are made of three objects: + the block_record in the tables section + the block in the blocks section + the insert object in the entities section + + block_records give the insert units, blocks provide the objects drawn in the + block, and the insert object gives the location/scale/rotation of the block + instances. To draw a block you must first get a group with all the + blocks entities drawn in it, then scale the entities to match the world + units, then dupligroup that data to an object matching each insert object. + """ + + obname = 'in_%s' %self.blockname # create object name from block name + obname = obname[:MAX_NAMELENGTH] + + if settings.drawTypes['insert']: #if insert_drawType activated + ob = SCENE.objects.new('Empty', obname) # create a new empty_object + empty_size = 1.0 * settings.var['g_scale'] + if empty_size < 0.01: empty_size = 0.01 + elif empty_size > 10.0: empty_size = 10.0 + ob.drawSize = empty_size + + # get our block_def-group + block = settings.blocks(self.blockname) + ob.DupGroup = block + ob.enableDupGroup = True + + #print 'deb:draw.block.deltaloc:', deltaloc #-------------------- + ob.loc = tuple(self.loc) + if deltaloc: + deltaloc = rotXY_Vec(self.rotation, deltaloc) + #print 'deb:draw.block.loc:', deltaloc #-------------------- + ob.loc = [ob.loc[0]+deltaloc[0], ob.loc[1]+deltaloc[1], ob.loc[2]+deltaloc[2]] + transform(self.extrusion, self.rotation, ob) + ob.size = tuple(self.scale) + return ob + + + + +class Ellipse: #----------------------------------------------------------------- + """Class for objects representing dxf ellipses. + """ + + def __init__(self, obj): + """Expects an entity object of type ellipse as input. + """ + if not obj.type == 'ellipse': + raise TypeError, "Wrong type %s for ellipse object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.ratio = obj.get_type(40)[0] + self.start_angle = obj.get_type(41)[0] + self.end_angle = obj.get_type(42)[0] + + # optional data (with defaults) + self.space = getit(obj, 67, 0) + self.thic = getit(obj, 39, 0.0) + self.color_index = getit(obj, 62, BYLAYER) + + self.layer = getit(obj.data, 8, None) + self.loc = self.get_loc(obj.data) + self.major = self.get_major(obj.data) + self.extrusion = get_extrusion(obj.data) + self.radius = sqrt(self.major[0]**2 + self.major[0]**2 + self.major[0]**2) + + + def get_loc(self, data): + """Gets the center location for arc type objects. + + Arcs have a single coord location. + """ + loc = [0.0, 0.0, 0.0] + loc[0] = getit(data, 10, 0.0) + loc[1] = getit(data, 20, 0.0) + loc[2] = getit(data, 30, 0.0) + return loc + + + def get_major(self, data): + """Gets the major axis for ellipse type objects. + + The ellipse major axis defines the rotation of the ellipse and its radius. + """ + loc = [0.0, 0.0, 0.0] + loc[0] = getit(data, 11, 0.0) + loc[1] = getit(data, 21, 0.0) + loc[2] = getit(data, 31, 0.0) + return loc + + + def __repr__(self): + return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius) + + + def draw(self, settings): + """for ELLIPSE: generate Blender_geometry. + """ + # Generate the geometery + center = self.loc + thic = set_thick(self.thic, settings) + + if settings.var['curves_on']: + ob = drawCurveArc(self) + else: + obname = 'el_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + + major = Mathutils.Vector(self.major) + #remi--todo----AngleBetweenVecs makes abs(value)!----- + delta = Mathutils.AngleBetweenVecs(major, WORLDX) + radius = major.length + start = degrees(self.start_angle) + end = degrees(self.end_angle) + + # set a number of segments in entire circle + arc_res = settings.var['arc_res'] * sqrt(radius) / sqrt(settings.var['arc_rad']) + verts, edges = drawArc(None, radius, start, end, arc_res) + + if thic != 0: + len1 = len(verts) + thic_verts = [] + thic_verts.extend([[point[0], point[1], point[2]+thic] for point in verts]) + if thic < 0.0: + thic_verts.extend(verts) + verts = thic_verts + else: + verts.extend(thic_verts) + faces = [] + #print 'deb:len1:', len1 #----------------------- + #print 'deb:verts:', verts #remi--todo----- why is this List inhomogene? ---------- + faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)] + + me.verts.extend(verts) # add vertices to mesh + me.faces.extend(faces) # add faces to the mesh + else: + me.verts.extend(verts) # add vertices to mesh + me.edges.extend(edges) # add edges to the mesh + + ob.loc = tuple(center) + ob.SizeY = self.ratio + transform(self.extrusion, 0, ob) + + return ob + + + +class Face: #----------------------------------------------------------------- + """Class for objects representing dxf 3d faces. + """ + + def __init__(self, obj): + """Expects an entity object of type 3dfaceplot as input. + """ + if not obj.type == '3dface': + raise TypeError, "Wrong type %s for 3dface object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # optional data (with defaults) + self.space = getit(obj, 67, 0) + self.color_index = getit(obj, 62, BYLAYER) + + self.layer = getit(obj.data, 8, None) + self.points = self.get_points(obj.data) + + + def get_points(self, data): + """Gets 3-4 points for a 3d face type object. + + Faces have three or optionally four verts. + """ + a = [0, 0, 0] + b = [0, 0, 0] + c = [0, 0, 0] + d = [0, 0, 0] + a[0] = getit(data, 10, None) # 10 = x + a[1] = getit(data, 20, None) # 20 = y + a[2] = getit(data, 30, 0.0) # 30 = z + b[0] = getit(data, 11, None) + b[1] = getit(data, 21, None) + b[2] = getit(data, 31, 0.0) + c[0] = getit(data, 12, None) + c[1] = getit(data, 22, None) + c[2] = getit(data, 32, 0.0) + out = [a,b,c] + + d[0] = getit(data, 13, None) + if d[0] != None: + d[1] = getit(data, 23, None) + d[2] = getit(data, 33, 0.0) + out.append(d) + + #if len(out) < 4: print '3dface with only 3 vertices:\n',a,b,c,d #----------------- + return out + + + def __repr__(self): + return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) + + + def draw(self, settings): + """for 3DFACE: generate Blender_geometry. + """ + # Generate the geometery + points = self.points + + global activObjectLayer + global activObjectName + #print 'deb:draw:face.ob IN activObjectName: ', activObjectName #--------------------- + + if activObjectLayer == self.layer and settings.var['one_mesh_on']: + obname = activObjectName + #print 'deb:face.draw obname from activObjectName: ', obname #--------------------- + ob = Object.Get(obname) # open an existing mesh_object + #ob = SCENE.getChildren(obname) # open an existing mesh_object + else: + obname = 'fa_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + activObjectName = ob.name + activObjectLayer = self.layer + #print ('deb:except. new face.ob+mesh:"%s" created!' %ob.name) #--------------------- + + me = Mesh.Get(ob.name) # open objects mesh data + faces, edges = [], [] + n = len(me.verts) + if len(self.points) == 4: + faces = [[0+n,1+n,2+n,3+n]] + elif len(self.points) == 3: + faces = [[0+n,1+n,2+n]] + elif len(self.points) == 2: + edges = [[0+n,1+n]] + + me.verts.extend(points) # add vertices to mesh + if faces: me.faces.extend(faces) # add faces to the mesh + if edges: me.edges.extend(edges) # add faces to the mesh + if settings.var['vGroup_on']: + # entities with the same color build one vertexGroup for easier material assignment --------------------- + ob.link(me) # link mesh to that object + vG_name = 'color_%s' %self.color_index + if edges: faces = edges + replace = Blender.Mesh.AssignModes.ADD #or .AssignModes.REPLACE or ADD + try: + me.assignVertsToGroup(vG_name, faces[0], 1.0, replace) + #print 'deb: existed vGroup:', vG_name #--------------------- + except: + me.addVertGroup(vG_name) + me.assignVertsToGroup(vG_name, faces[0], 1.0, replace) + #print 'deb: create new vGroup:', vG_name #-------------------- + + #print 'deb:draw:face.ob OUT activObjectName: ', activObjectName #--------------------- + return ob + + +#--------------------------------------------------------------------------------------- +# type to object maping (sorted-dictionary for f_obiectify ONLY!, format={'key':Class} ) +type_map = { + 'layer':Layer, + 'block_record':BlockRecord, + 'block':Block, + 'insert':Insert, + 'point':Point, + '3dface':Face, + 'line':Line, +# 'mline':MLine, + 'polyline':Polyline, + 'lwpolyline':LWpolyline, +# 'region':Region, + 'trace':Solid, + 'solid':Solid, + 'text':Text, + 'mtext':Mtext, + 'circle':Circle, + 'ellipse':Ellipse, + 'arc':Arc +} + + + +def objectify(data): #----------------------------------------------------------------- + """Expects a section type object's data as input. + + Maps object data to the correct object type. + """ + #print 'deb:objectify start %%%%%%%%%%%' #--------------- + objects = [] # colector for finished objects + known_types = type_map.keys() # so we don't have to call foo.keys() every iteration + curves_on = GUI_A['curves_on'].val + index = 0 + while index < len(data): + item = data[index] + #print 'deb:objectify item: \n', item #------------ + if type(item) != list and item.type == 'table': + item.data = objectify(item.data) # tables have sub-objects + objects.append(item) + elif type(item) != list and item.type == 'polyline': #remi --todo----------- + #print 'deb:gosub Polyline\n' #------------- + pline = Polyline(item) + while 1: + index += 1 + item = data[index] + if item.type == 'vertex': + #print 'deb:objectify gosub Vertex--------' #------------- + v = Vertex(item) + if pline.spline: # Bspline-curve + # then for Blender-mesh filter only additional_vertices + # OR + # then for Blender-curve filter only spline_control_vertices + if (v.spline and not curves_on) or (curves_on and v.splin2): #correct for real NURBS-import + #if (v.spline and not curves_on) or (curves_on and not v.splin2): #fake for Bezier-emulation of NURBS-import + pline.points.append(v) + elif pline.curved: # Bezier-curve + # then for Blender-mesh filter only curve_additional_vertices + # OR + # then for Blender-curve filter curve_control_vertices + if not curves_on or (curves_on and not v.curved): + pline.points.append(v) + else: + pline.points.append(v) + elif item.type == 'seqend': + #print 'deb:objectify it is seqEND ---------\n' #------------- + break + else: + print "Error: non-vertex found before seqend!" + index -= 1 #so go back one step + break + objects.append(pline) + elif type(item) != list and item.type in known_types: + # proccess the object and append the resulting object + objects.append(type_map[item.type](item)) + else: + # we will just let the data pass un-harrased + objects.append(item) + index += 1 + #print 'deb:objectify objects:\n', objects #------------ + #print 'deb:objectify END %%%%%%%%' #------------ + return objects + + + +class MatColors: #----------------------------------------------------------------- + """A smart container for dxf-color based materials. + + This class is a wrapper around a dictionary mapping dxf-color indicies to materials. + When called with a color index it returns a material corrisponding to that index. + Behind the scenes it checks if that index is in its keys, and if not it creates + a new material. It then adds the new index:material pair to its dict and returns + the material. + """ + + def __init__(self, map): + """Expects a map - a dictionary mapping layer names to layers. + """ + self.map = map # a dictionary of layername:layer + self.colMaterials = {} # a dictionary of color_index:blender_material + #print 'deb:init_MatColors argument.map: ', map #------------------ + + + def __call__(self, color=None): + """Return the material associated with color. + + If a layer name is provided, the color of that layer is used. + """ + if not color: + color = 0 + if type(color) == str: + #print 'deb:color is string:--------------: ', color #--todo---bug with ARC from ARC-T0.DXF layer="T-3DARC-1"----- + try: + color = self.map[color].color + #print 'deb:color=self.map[color].color:', color #------------------ + except KeyError: + layer = Layer(name=color, color=0, frozen=False) + self.map[color] = layer + color = 0 + color = abs(color) + if color not in self.colMaterials.keys(): + self.add(color) + return self.colMaterials[color] + + + def add(self, color): + """Create a new material 'ColorNr-N' using the provided color index-N. + """ + global color_map + mat = Material.New('ColorNr-%s' %color) + mat.setRGBCol(color_map[color]) + mat.mode |= Material.Modes.SHADELESS + mat.mode |= Material.Modes.WIRE +# try: mat.setMode('Shadeless', 'Wire') #work-around for 2.45rc-bug +# except: pass + self.colMaterials[color] = mat + + + +class MatLayers: #----------------------------------------------------------------- + """A smart container for dxf-layer based materials. + + This class is a wrapper around a dictionary mapping dxf-layer names to materials. + When called with a layer name it returns a material corrisponding to that. + Behind the scenes it checks if that layername is in its keys, and if not it creates + a new material. It then adds the new layername:material pair to its dict and returns + the material. + """ + + def __init__(self, map): + """Expects a map - a dictionary mapping layer names to layers. + """ + self.map = map # a dictionary of layername:layer + self.layMaterials = {} # a dictionary of layer_name:blender_material + #print 'deb:init_MatLayers argument.map: ', map #------------------ + + + def __call__(self, layername=None): + """Return the material associated with dxf-layer. + + If a dxf-layername is not provided, create a new material + """ + if layername not in self.layMaterials.keys(): + self.add(layername) + return self.layMaterials[layername] + + + def add(self, layername): + """Create a new material 'layername'. + """ + try: mat = Material.Get('Lay-%s' %layername) + except: mat = Material.New('Lay-%s' %layername) + #print 'deb:MatLayers material: ', mat #---------- + #print 'deb:MatLayers getMode: ', mat.getMode() #---------- + global layersmap + color = layersmap[layername].color + #print 'deb:MatLayers layer_color: ', color #----------- + global color_map + mat.setRGBCol(color_map[color]) + mat.mode |= Material.Modes.SHADELESS + mat.mode |= Material.Modes.WIRE +# try: mat.setMode('Shadeless', 'Wire') #work-around for 2.45rc-bug +# except: pass + self.layMaterials[layername] = mat + + + + +class Blocks: #----------------------------------------------------------------- + """A smart container for blocks. + + This class is a wrapper around a dictionary mapping block names to Blender data blocks. + When called with a name string it returns a block corresponding to that name. + Behind the scenes it checks if that name is in its keys, and if not it creates + a new data block. It then adds the new name:block_data pair to its dict and returns + the block. + """ + + def __init__(self, blocksmap, settings): + """Expects a dictionary mapping block_name:block_data. + """ + self.blocksmap = blocksmap #a dictionary mapping block_name:block_data + self.settings = settings + self.blocks = {} #container for blocks + + + def __call__(self, name=None): + """Return the data block associated with that block_name. + + If that name is not in its keys, it creates a new data block. + If no name is provided return entire self.blocks container. + """ + if not name: + return self.blocks + if name not in self.blocks.keys(): + self.addBlock(name) + return self.blocks[name] + + + def addBlock(self, name): + """Create a new 'block group' for the block name. + """ + block_def = Group.New('bl_%s' %name) # groupObject contains definition of BLOCK + block = self.blocksmap[name] + self.settings.write("\nDrawing block:\'%s\' ..." % name) + drawEntities(block.entities, self.settings, block_def) + self.settings.write("Drawing block:\'%s\' done!" %name) + self.blocks[name] = block_def + + + + + +class Settings: #----------------------------------------------------------------- + """A container for all the import settings and objects used by the draw functions. + + This is like a collection of globally accessable persistant properties and functions. + """ + # Optimization constants + MIN = 0 + MID = 1 + PRO = 2 + MAX = 3 + + def __init__(self, keywords, drawTypes): + """initialize all the important settings used by the draw functions. + """ + self.obj_number = 1 #global object_number for progress_bar + + self.var = dict(keywords) #a dictionary of (key_variable:Value) control parameter + self.drawTypes = dict(drawTypes) #a dictionary of (entity_type:True/False) = import on/off for this entity_type + + self.var['colorFilter_on'] = False #deb:remi------------ + self.acceptedColors = [0,2,3,4,5,6,7,8,9, + 10 ] + + self.var['layerFilter_on'] = False #deb:remi------------ + self.acceptedLayers = ['3', + '0' + ] + + self.var['blockFilter_on'] = False #deb:remi------------ + self.acceptedBlocks = ['BOX01', + 'BOX02' + ] + + + def update(self, keywords, drawTypes): + """update all the important settings used by the draw functions. + """ + + for k, v in keywords.iteritems(): + self.var[k] = v + #print 'deb:settings_update var %s= %s' %(k, self.var[k]) #-------------- + for t, v in drawTypes.iteritems(): + self.drawTypes[t] = v + #print 'deb:settings_update drawType %s= %s' %(t, self.drawTypes[t]) #-------------- + + #print 'deb:self.drawTypes', self.drawTypes #--------------- + + + def validate(self, drawing): + """Given the drawing, build dictionaries of Layers, Colors and Blocks. + """ + + #de: paßt die distance parameter an globalScale + if self.var['g_scale'] != 1: + self.var['dist_min'] = self.var['dist_min'] / self.var['g_scale'] + self.var['thick_min'] = self.var['thick_min'] / self.var['g_scale'] + self.var['width_min'] = self.var['width_min'] / self.var['g_scale'] + + # First sort out all the section_items + sections = dict([(item.name, item) for item in drawing.data]) + + # The section:header may be omited + if 'header' in sections.keys(): + self.write("Found section:header!") + else: + self.write("File contains no section:header!") + + # The section:tables may be partialy or completely missing. + self.layersTable = False + self.colMaterials = MatColors({}) + self.layMaterials = MatLayers({}) + if 'tables' in sections.keys(): + self.write("Found section:tables!") + # First sort out all the tables + tables = dict([(item.name, item) for item in sections["tables"].data]) + if 'layer' in tables.keys(): + self.write("Found table:layers!") + self.layersTable = True + # Read the layers table and get the layer colors + global layersmap + layersmap = getLayersmap(drawing) + self.colMaterials = MatColors(layersmap) + self.layMaterials = MatLayers(layersmap) + else: + self.write("File contains no table:layers!") + else: + self.write("File contains no section:tables!") + self.write("File contains no table:layers!") + + # The section:blocks may be omited + if 'blocks' in sections.keys(): + self.write("Found section:blocks!") + # Read the block definitions and build our block object + if self.drawTypes['insert']: #if drawing of type 'Insert' activated + blocksmap, self.obj_number = getBlocksmap(drawing) #Build a dictionary of blockname:block_data pairs + self.blocks = Blocks(blocksmap, self) # initiates container for blocks_data + + #print 'deb: self.obj_number', self.obj_number #---------- + else: + self.write("File contains no section:blocks!") + self.drawTypes['insert'] = False + + # The section:entities + if 'entities' in sections.keys(): + self.write("Found section:entities!") + + self.obj_number += len(drawing.entities.data) + #print 'deb: self.obj_number', self.obj_number #---------- + self.obj_number = 1.0 / self.obj_number + + + def write(self, text, newline=True): + """Wraps the built-in print command in a optimization check. + """ + if self.var['optimization'] <= self.MID: + if newline: + print text + else: + print text, + + + def redraw(self): + """Update Blender if optimization level is low enough. + """ + if self.var['optimization'] <= self.MIN: + Blender.Redraw() + + + def progress(self, done, text): + """Wrapper for Blender.Window.DrawProgressBar. + """ + if self.var['optimization'] <= self.PRO: + progressbar = done * self.obj_number + Window.DrawProgressBar(progressbar, text) + #print 'deb:drawer done, progressbar: ', done, progressbar #----------------------- + + + def layer_isOff(self, name): + """Given a layer name, and return its visible status. + """ + # colors are negative if layer is off + try: + #print 'deb:layer_isOff self.colMaterials.map:\n', self.colMaterials.map #-------------- + layer = self.colMaterials.map[name] + except KeyError: return False + if layer.color < 0: return True + #print 'deb:layer_isOff: layer is ON' #--------------- + return False + + + def layer_isFrozen(self, name): + """Given a layer name, and return its frozen status. + """ + # colors are negative if layer is off + try: + #print 'deb:layer_isFrozen self.colMaterials.map:\n', self.colMaterials.map #--------------- + layer = self.colMaterials.map[name] + except KeyError: return False + if layer.frozen: return True + #print 'deb:layer_isFrozen: layer is not FROZEN' #--------------- + return False + + + + +def main(dxfFile): #---------------#############################----------- + #print 'deb:filename:', filename #-------------- + global SCENE + editmode = Window.EditMode() # are we in edit mode? If so ... + if editmode: + Window.EditMode(0) # leave edit mode before + + #SCENE = bpy.data.scenes.active + #SCENE.objects.selected = [] # deselect all + + global cur_COUNTER #counter for progress_bar + cur_COUNTER = 0 + + try: + print "Getting settings..." + global GUI_A, GUI_B + if GUI_A['g_scale_on'].val: + GUI_A['g_scale'].val = 10.0 ** int(GUI_A['g_scale_as'].val) + else: + GUI_A['g_scale'].val = 1.0 + + keywords = {} + drawTypes = {} + for k, v in GUI_A.iteritems(): + keywords[k] = v.val + for k, v in GUI_B.iteritems(): + drawTypes[k] = v.val + #print 'deb:startUInew keywords: ', keywords #-------------- + #print 'deb:startUInew drawTypes: ', drawTypes #-------------- + + # The settings object controls how dxf entities are drawn + settings.update(keywords, drawTypes) + #print 'deb:settings.var:\n', settings.var #----------------------- + + if not settings: + #Draw.PupMenu('DXF importer: EXIT!%t') + print '\nDXF Import: terminated by user!' + Window.WaitCursor(False) + if editmode: Window.EditMode(1) # and put things back how we fond them + return None + + #no more used dxfFile = dxfFileName.val + #print 'deb: dxfFile file: ', dxfFile #---------------------- + if dxfFile.lower().endswith('.dxf') and sys.exists(dxfFile): + Window.WaitCursor(True) # Let the user know we are thinking + print 'start reading DXF file: %s.' % dxfFile + time1 = Blender.sys.time() #time marker1 + drawing = readDXF(dxfFile, objectify) + print 'finished reading DXF file in %.4f sec.' % (Blender.sys.time()-time1) + Window.WaitCursor(False) + else: + if UI_MODE: Draw.PupMenu('DXF importer: EXIT----------!%t| no valid DXF-file selected!') + print "DXF importer: error, no DXF-file selected. Abort!" + Window.WaitCursor(False) + if editmode: Window.EditMode(1) # and put things back how we fond them + return None + + settings.validate(drawing) + + Window.WaitCursor(True) # Let the user know we are thinking + settings.write("\n\nDrawing entities...") + + # Draw all the know entity types in the current scene + global oblist + oblist = [] # a list of all created AND linked objects for final f_globalScale + time2 = Blender.sys.time() #time marker2 + + drawEntities(drawing.entities, settings) + + #print 'deb:drawEntities after: oblist:', oblist #----------------------- + if oblist: # and settings.var['g_scale'] != 1: + globalScale(oblist, settings.var['g_scale']) + + # Set the visable layers + SCENE.setLayers([i+1 for i in range(18)]) + SCENE.update(1) + #Blender.Redraw(-1) + SCENE.objects.selected = [i[0] for i in oblist] #select only the imported objects + #SCENE.objects.selected = SCENE.objects #select all objects in current scene + Blender.Redraw() + + time_text = Blender.sys.time() - time2 + Window.WaitCursor(False) + message = 'DXF Import to Blender: done in %.4f sec. --------------------' % time_text + settings.progress(1.0/settings.obj_number, 'DXF import done!') + print message + #settings.write(message) + if UI_MODE: Draw.PupMenu('DXF importer: Done!|finished in %.4f sec.' % time_text) + + finally: + # restore state even if things didn't work + #print 'deb:drawEntities finally!' #----------------------- + Window.WaitCursor(False) + if editmode: Window.EditMode(1) # and put things back how we fond them + + + +def getOCS(az): #----------------------------------------------------------------- + """An implimentation of the Arbitrary Axis Algorithm. + """ + #decide if we need to transform our coords + if az[0] == 0 and az[1] == 0: + return False + #elif abs(az[0]) < 0.0001 and abs(az[1]) < 0.0001: + # return False + + az = Mathutils.Vector(az) + + cap = 0.015625 # square polar cap value (1/64.0) + if abs(az.x) < cap and abs(az.y) < cap: + ax = Mathutils.CrossVecs(WORLDY, az) + else: + ax = Mathutils.CrossVecs(WORLDZ, az) + ax = ax.normalize() + ay = Mathutils.CrossVecs(az, ax) + ay = ay.normalize() + return ax, ay, az + + + +def transform(normal, rotation, obj): #-------------------------------------------- + """Use the calculated ocs to determine the objects location/orientation in space. + + Quote from dxf docs: + The elevation value stored with an entity and output in DXF files is a sum + of the Z-coordinate difference between the UCS XY plane and the OCS XY + plane, and the elevation value that the user specified at the time the entity + was drawn. + """ + ma = Mathutils.Matrix([1,0,0],[0,1,0],[0,0,1]) + o = Mathutils.Vector(obj.loc) + ocs = getOCS(normal) + if ocs: + ma = Mathutils.Matrix(ocs[0], ocs[1], ocs[2]) + o = ma.invert() * o + ma = Mathutils.Matrix(ocs[0], ocs[1], ocs[2]) + + if rotation != 0: + g = radians(-rotation) + rmat = Mathutils.Matrix([cos(g), -sin(g), 0], [sin(g), cos(g), 0], [0, 0, 1]) + ma = rmat * ma + + obj.setMatrix(ma) + obj.loc = o + #print 'deb:new obj.matrix:\n', obj.getMatrix() #-------------------- + + + +def rotXY_Vec(rotation, vec): #---------------------------------------------------- + """Rotate vector vec in XY-plane. vec must be in radians + """ + if rotation != 0: + o = Mathutils.Vector(vec) + g = radians(-rotation) + vec = o * Mathutils.Matrix([cos(g), -sin(g), 0], [sin(g), cos(g), 0], [0, 0, 1]) + return vec + + + +def getLayersmap(drawing): #------------------------------------------------------ + """Build a dictionary of layername:layer pairs for the given drawing. + """ + tables = drawing.tables + for table in tables.data: + if table.name == 'layer': + layers = table + break + layersmap = {} + for item in layers.data: + if type(item) != list and item.type == 'layer': + layersmap[item.name] = item + return layersmap + + + +def getBlocksmap(drawing): #-------------------------------------------------------- + """Build a dictionary of blockname:block_data pairs for the given drawing. + """ + blocksmap = {} + obj_number = 0 + for item in drawing.blocks.data: + #print 'deb:getBlocksmap item=' ,item #-------- + #print 'deb:getBlocksmap item.entities=' ,item.entities #-------- + #print 'deb:getBlocksmap item.entities.data=' ,item.entities.data #-------- + if type(item) != list and item.type == 'block': + obj_number += len(item.entities.data) + try: + blocksmap[item.name] = item + except KeyError: + # annon block + print 'Cannot map "%s" - "%s" as Block!' %(item.name, item) + return blocksmap, obj_number + + + + + +def drawEntities(entities, settings, block_def=None): #---------------------------------------- + """Draw every kind of thing in the entity list. + + If provided 'block_def': the entities are to be added to the Blender 'group'. + """ + for _type in type_map.keys(): + #print 'deb:drawEntities_type:', _type #------------------ + # for each known type get a list of that type and call the associated draw function + drawer(_type, entities.get_type(_type), settings, block_def) + + +def drawer(_type, entities, settings, block_def): #------------------------------------------ + """Call with a list of entities and a settings object to generate Blender geometry. + + If 'block_def': the entities are to be added to the Blender 'group'. + """ + if entities: + # Break out early if settings says we aren't drawing the current dxf-type + global cur_COUNTER #counter for progress_bar + group = None + #print 'deb:drawer.check:_type: ', _type #-------------------- + if _type == '3dface':_type = 'face' # hack, while python_variable_name can not beginn with a nummber + if not settings.drawTypes[_type] or _type == 'block_record': + message = 'Skipping dxf\'%ss\' entities' %_type + settings.write(message, True) + cur_COUNTER += len(entities) + settings.progress(cur_COUNTER, message) + return + #print 'deb:drawer.todo:_type:', _type #----------------------- + + len_temp = len(entities) + # filtering only model-space enitities (no paper-space enitities) + entities = [entity for entity in entities if entity.space == 0] + + # filtering only objects with color from acceptedColorsList + if settings.var['colorFilter_on']: + entities = [entity for entity in entities if entity.color in settings.acceptedColors] + + # filtering only objects on layers from acceptedLayersList + if settings.var['layerFilter_on']: +# entities = [entity for entity in entities if entity.layer[0] in ['M','3','0'] and not entity.layer.endswith('H')] + entities = [entity for entity in entities if entity.layer in settings.acceptedLayers] + + # filtering only objects on not-frozen layers + entities = [entity for entity in entities if not settings.layer_isFrozen(entity.layer)] + + global activObjectLayer, activObjectName + activObjectLayer = '' + activObjectName = '' + + message = "Drawing dxf\'%ss\'..." %_type + cur_COUNTER += len_temp - len(entities) + settings.write(message, False) + settings.progress(cur_COUNTER, message) + if len(entities) > 0.1 / settings.obj_number: + show_progress = int(0.03 / settings.obj_number) + else: show_progress = 0 + cur_temp = 0 + + #print 'deb:drawer cur_COUNTER: ', cur_COUNTER #----------------------- + + for entity in entities: #----loop------------------------------------- + settings.write('\b.', False) + cur_COUNTER += 1 + if show_progress: + cur_temp += 1 + if cur_temp == show_progress: + settings.progress(cur_COUNTER, message) + cur_temp = 0 + #print 'deb:drawer show_progress=',show_progress #----------------------- + + # get the layer group (just to make things a little cleaner) + if settings.var['group_bylayer_on'] and not block_def: + group = getGroup('l:%s' % entity.layer[:MAX_NAMELENGTH-2]) + + if _type == 'insert': #---- INSERT and MINSERT=array ------------------------ + #print 'deb:insert entity.loc:', entity.loc #---------------- + columns = entity.columns[0] + coldist = entity.columns[1] + rows = entity.rows[0] + rowdist = entity.rows[1] + deltaloc = [0,0,0] + #print 'deb:insert columns, rows:', columns, rows #----------- + for col in xrange(columns): + deltaloc[0] = col * coldist + for row in xrange(rows): + deltaloc[1] = row * rowdist + #print 'deb:insert col=%s, row=%s,deltaloc=%s' %(col, row, deltaloc) #------ + ob = entity.draw(settings, deltaloc) #-----draw BLOCK---------- + setObjectProperties(ob, group, entity, settings, block_def) + if ob: + if settings.var['optimization'] <= settings.MIN: + if settings.var['g_scale'] != 1: globalScaleOne(ob, True, settings.var['g_scale']) + settings.redraw() + else: oblist.append((ob, True)) + + else: #---draw entities except BLOCKs/INSERTs--------------------- + alt_obname = activObjectName + ob = entity.draw(settings) + if ob and ob.name != alt_obname: + setObjectProperties(ob, group, entity, settings, block_def) + if settings.var['optimization'] <= settings.MIN: + if settings.var['g_scale'] != 1: globalScaleOne(ob, False, settings.var['g_scale']) + settings.redraw() + else: oblist.append((ob, False)) + + #print 'deb:Finished drawing:', entities[0].type #------------------------ + message = "\nDrawing dxf\'%ss\' done!" % _type + settings.write(message, True) + + + +def globalScale(oblist, SCALE): #--------------------------------------------------------- + """Global_scale for list of all imported objects. + + oblist is a list of pairs (ob, insertFlag), where insertFlag=True/False + """ + #print 'deb:globalScale.oblist: ---------%\n', oblist #--------------------- + for l in oblist: + ob, insertFlag = l[0], l[1] + globalScaleOne(ob, insertFlag, SCALE) + + +def globalScaleOne(ob, insertFlag, SCALE): #--------------------------------------------------------- + """Global_scale imported object. + """ + #print 'deb:globalScaleOne ob: ', ob #--------------------- + SCALE_MAT= Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1]) + if insertFlag: # by BLOCKs/INSERTs only insert-point must be scaled------------ + ob.loc = Mathutils.Vector(ob.loc) * SCALE_MAT + else: # entire scaling for all other imported objects ------------ + ob.setMatrix(ob.matrixWorld*SCALE_MAT) + + + +def setObjectProperties(ob, group, entity, settings, block_def): #----------------------- + """Link object to scene. + """ + + if not ob: #remi--todo----------------------- + message = "\nObject \'%s\' not found!" %entity + settings.write(message) + return + + if group: + setGroup(group, ob) # if object belongs to group + + if block_def: # if object belongs to BLOCK_def - Move it to layer nr19 + setGroup(block_def, ob) + #print 'deb:setObjectProperties \'%s\' set to block_def_group!' %ob.name #--------- + ob.layers = [19] + else: + #ob.layers = [i+1 for i in xrange(20)] #remi--todo------------ + ob.layers = [settings.var['target_layer']] + + # Set material for any objects except empties + if ob.type != 'Empty': + setMaterial_from(entity, ob, settings, block_def) + + # Set the visibility + if settings.layer_isOff(entity.layer): + #ob.layers = [20] #remi--todo------------- + ob.restrictDisplay = True + ob.restrictRender = True + + #print 'deb:\n---------linking Object %s!' %ob.name #---------- + + + +def getGroup(name): #----------------------------------------------------------------- + """Returns a Blender group-object. + """ + try: + group = Group.Get(name) + except: # What is the exception? + group = Group.New(name) + return group + + +def setGroup(group, ob): #------------------------------------------------------------ + """Assigns object to Blender group. + """ + try: + group.objects.link(ob) + except: + group.objects.append(ob) #remi?--------------- + + + +def setMaterial_from(entity, ob, settings, block_def): #------------------------------------------------ + """ Set Blender-material for the object controled by item. + + Set Blender-material for the object + - controlled by settings.var['material_from'] + """ + if settings.var['material_from'] == 1: # 1= material from color + if entity.color_index == BYLAYER: + mat = settings.colMaterials(entity.layer) + else: + mat = settings.colMaterials(entity.color_index) + elif settings.var['material_from'] == 2: # 2= material from layer + mat = settings.layMaterials(entity.layer) +# elif settings.var['material_from'] == 3: # 3= material from layer+color +# mat = settings.layMaterials(entity.layer) +# color = entity.color_index +# if type(color) == int: +# mat.setRGBCol(color_map[abs(color)]) +# elif settings.var['material_from'] == 4: # 4= material from block +# elif settings.var['material_from'] == 5: # 5= material from INI-file + else: # set neutral material + try: + mat = Material.Get('dxf-neutral') + except: + mat = Material.New('dxf-neutral') + mat.mode |= Material.Modes.SHADELESS + mat.mode |= Material.Modes.WIRE +# try:mat.setMode('Shadeless', 'Wire') #work-around for 2.45rc1-bug +# except: pass + try: + #print 'deb:material mat:', mat #----------- + ob.setMaterials([mat]) #assigns Blender-material to object + except ValueError: + settings.write("material error - \'%s\'!" %mat) + ob.colbits = 0x01 # Set OB materials. + + + +def drawBulge(p1, p2, arc_res, curve_on=False): #------------------------------------------------- + """return the center, radius, start angle, and end angle given two points. + + Needs to take into account bulge sign. + negative = clockwise + positive = counter-clockwise + + to find center given two points, and arc angle + calculate radius + Cord = sqrt(start^2 + end^2) + S = (bulge*Cord)/2 + radius = ((Cord/2)^2+S^2)/2*S + angle of arc = 4*atan( bulge ) + angle from p1 to center is (180-angle)/2 + get vector pointing from p1 to p2 (p2 - p1) + normalize it and multiply by radius + rotate around p1 by angle to center, point to center. + start angle = angle between (center - p1) and worldX + end angle = angle between (center - p2) and worldX + """ + + bulge = p1.bulge + p2 = Mathutils.Vector(p2.loc) + p1 = Mathutils.Vector(p1.loc) + cord = p2 - p1 # vector from p1 to p2 + clength = cord.length + s = (bulge * clength)/2.0 # sagitta (height) + radius = abs(((clength/2.0)**2.0 + s**2.0)/(2.0*s)) # magic formula + angle = (degrees(4.0*atan(bulge))) # theta (included angle) + if curve_on: + verts_num = 8 + else: + verts_num = arc_res * sqrt(radius) # set a number of segments in entire circle + if verts_num > 1024: verts_num = 1024 # Blender accepts only values [3:500] + if verts_num < 4: verts_num = 4 # Blender accepts only values [3:500] + pieces = int(abs(angle)/(360.0/verts_num)) + if pieces < 3: pieces = 3 #bulge under arc_resolution + #if pieces < 3: points = [p1, p2] ;return points + step = angle/pieces # set step so pieces * step = degrees in arc + delta = (180.0 - abs(angle))/2.0 # the angle from cord to center + if bulge < 0: delta = -delta + radial = cord.normalize() * radius # a radius length vector aligned with cord + rmat = Mathutils.RotationMatrix(-delta, 3, 'Z') + center = p1 + (rmat * radial) # rotate radial by delta degrees, then add to p1 to find center + #length = radians(abs(angle)) * radius + #print 'deb:drawBulge:\n angle, delta: ', angle, delta #---------------- + #print 'deb:center, radius: ', center, radius #---------------------- + + startpoint = p1 - center + #endpoint = p2 - center + stepmatrix = Mathutils.RotationMatrix(-step, 3, "Z") + points = [startpoint] + point = Mathutils.Vector(startpoint) + for i in xrange(int(pieces)-1): #fast (but not so acurate as: vector * RotMatrix(step * i) + point = stepmatrix * point + points.append(point) + points = [[point[0]+center[0], point[1]+center[1], point[2]+center[2]] for point in points] + return points + + + +def drawArc(center, radius, start, end, arc_res): #----------------------------------------- + """Draw a mesh arc with the given parameters. + """ + # center is currently set by object + # if start > end: start = start - 360 + if end > 360: end = end%360.0 + + startmatrix = Mathutils.RotationMatrix(-start, 3, "Z") + startpoint = startmatrix * Mathutils.Vector(radius, 0, 0) + endmatrix = Mathutils.RotationMatrix(-end, 3, "Z") + endpoint = endmatrix * Mathutils.Vector(radius, 0, 0) + + if end < start: end +=360.0 + angle = end - start + #length = radians(angle) * radius + + #if radius < MIN_DIST * 10: # if circumfence is too small + if arc_res > 1024: arc_res = 1024 + if arc_res < 4: arc_res = 4 + pieces = int(abs(angle)/(360.0/arc_res)) # set a fixed step of ARC_RESOLUTION + if pieces < 3: pieces = 3 #cambo----- + step = angle/pieces # set step so pieces * step = degrees in arc + + stepmatrix = Mathutils.RotationMatrix(-step, 3, "Z") + points = [startpoint] + point = Mathutils.Vector(startpoint) + for i in xrange(int(pieces)): + point = stepmatrix * point + points.append(point) + points.append(endpoint) + + if center: + points = [[point[0]+center[0], point[1]+center[1], point[2]+center[2]] for point in points] + edges = [[num, num+1] for num in xrange(len(points)-1)] + + return points, edges + + + +def drawCurveCircle(circle): #--- no more used -------------------------------------------- + """Given a dxf circle object return a blender circle object using curves. + """ + c = Curve.New('circle') # create new curve data + center = circle.loc + radius = circle.radius + + p1 = (0, -radius, 0) + p2 = (radius, 0, 0) + p3 = (0, radius, 0) + p4 = (-radius, 0, 0) + + p1 = BezTriple.New(p1) + p2 = BezTriple.New(p2) + p3 = BezTriple.New(p3) + p4 = BezTriple.New(p4) + + curve = c.appendNurb(p1) + curve.append(p2) + curve.append(p3) + curve.append(p4) + for point in curve: + point.handleTypes = [AUTO, AUTO] + curve.flagU = 1 # Set curve cyclic + c.update() + + ob = Object.New('Curve', 'circle') # make curve object + return ob + + +def drawCurveArc(self): #---- only for ELLIPSE ------------------------------------------------------------- + """Given a dxf ELLIPSE object return a blender_curve. + """ + center = self.loc + radius = self.radius + start = self.start_angle + end = self.end_angle + + if start > end: + start = start - 360.0 + startmatrix = Mathutils.RotationMatrix(start, 3, "Z") + startpoint = startmatrix * Mathutils.Vector((radius, 0, 0)) + endmatrix = Mathutils.RotationMatrix(end, 3, "Z") + endpoint = endmatrix * Mathutils.Vector((radius, 0, 0)) + # Note: handles must be tangent to arc and of correct length... + + a = Curve.New('arc') # create new curve data + + p1 = (0, -radius, 0) + p2 = (radius, 0, 0) + p3 = (0, radius, 0) + p4 = (-radius, 0, 0) + + p1 = BezTriple.New(p1) + p2 = BezTriple.New(p2) + p3 = BezTriple.New(p3) + p4 = BezTriple.New(p4) + + curve = a.appendNurb(p1) + curve.append(p2) + curve.append(p3) + curve.append(p4) + for point in curve: + point.handleTypes = [AUTO, AUTO] + curve.flagU = 1 # Set curve cyclic + a.update() + + ob = Object.New('Curve', 'arc') # make curve object + return ob + + + + +# GUI STUFF -----#################################################----------------- +from Blender.BGL import * + +EVENT_NONE = 1 +EVENT_START = 2 +EVENT_REDRAW = 3 +EVENT_LOAD_INI = 4 +EVENT_SAVE_INI = 5 +EVENT_PRESET = 6 +EVENT_CHOOSE_INI = 7 +EVENT_CHOOSE_DXF = 8 +EVENT_HELP = 9 +EVENT_CONFIG = 10 +EVENT_PRESETS = 11 +EVENT_DXF_DIR = 12 +EVENT_PRESET2D = 20 +EVENT_EXIT = 100 +GUI_EVENT = EVENT_NONE + +GUI_A = {} # GUI-buttons dictionary for parameter +GUI_B = {} # GUI-buttons dictionary for drawingTypes + +# settings default, initialize ------------------------ + +points_as_menu = "convert to: %t|empty %x1|mesh.vertex %x2|thin sphere %x3|thin box %x4" +lines_as_menu = "convert to: %t|*edge %x1|mesh %x2|*thin cylinder %x3|*thin box %x4" +mlines_as_menu = "convert to: %t|*edge %x1|*mesh %x2|*thin cylinder %x3|*thin box %x4" +plines_as_menu = "convert to: %t|*edge %x1|mesh %x2|*thin cylinder %x3|*thin box %x4" +plines3_as_menu = "convert to: %t|*edge %x1|mesh %x2|*thin cylinder %x3|*thin box %x4" +plmesh_as_menu = "convert to: %t|mesh %x1" +solids_as_menu = "convert to: %t|mesh %x1" +blocks_as_menu = "convert to: %t|dupl.group %x1|*real.group %x2|*exploded %x3" +texts_as_menu = "convert to: %t|text %x1|*mesh %x2" +material_from_menu= "material from: %t|COLOR %x1|LAYER %x2|*LAYER+COLOR %x3|*BLOCK %x4|*XDATA %x5|*INI-File %x6" +g_scale_list = "scale factor: %t|x 1000 %x3|x 100 %x2|x 10 %x1|x 1 %x0|x 0.1 %x-1|x 0.01 %x-2|x 0.001 %x-3|x 0.0001 %x-4|x 0.00001 %x-5" + +dxfFileName = Draw.Create("") +iniFileName = Draw.Create(INIFILE_DEFAULT_NAME + INIFILE_EXTENSION) +user_preset = 0 +config_UI = Draw.Create(0) #switch_on/off extended config_UI + +keywords_org = { + 'curves_on' : 0, + 'optimization': 2, + 'one_mesh_on': 1, + 'vGroup_on' : 1, + 'dummy_on' : 0, + 'newScene_on' : 1, + 'target_layer' : TARGET_LAYER, + 'group_bylayer_on' : GROUP_BYLAYER, + 'g_scale' : float(G_SCALE), + 'g_scale_as': int(log10(G_SCALE)), # 0, + 'g_scale_on': 1, + 'thick_on' : 1, + 'thick_min' : float(MIN_THICK), + 'thick_force': 0, + 'width_on' : 1, + 'width_min' : float(MIN_WIDTH), + 'width_force': 0, + 'dist_on' : 1, + 'dist_min' : float(MIN_DIST), + 'dist_force': 0, + 'material_on': 1, + 'material_from': 2, + 'pl_3d' : 1, + 'fill_on' : 1, + 'arc_res' : ARC_RESOLUTION, + 'arc_rad' : ARC_RADIUS, + 'thin_res' : THIN_RESOLUTION, + 'angle_cut' : ANGLECUT_LIMIT, + 'pl_section_on': 1, + 'points_as' : 2, + 'lines_as' : 2, + 'mlines_as' : 2, + 'plines_as' : 2, + 'plines3_as': 2, + 'plmesh_as' : 1, + 'solids_as' : 1, + 'blocks_as' : 1, + 'texts_as' : 1 + } + +drawTypes_org = { + 'point' : 1, + 'line' : 1, + 'arc' : 1, + 'circle': 1, + 'ellipse': 0, + 'mline' : 0, + 'polyline': 1, + 'plmesh': 1, + 'pline3': 1, + 'lwpolyline': 1, + 'text' : 1, + 'mtext' : 0, + 'block' : 1, + 'insert': 1, + 'face' : 1, + 'solid' : 1, + 'trace' : 1 + } + +# creating of GUI-buttons +# GUI_A - GUI-buttons dictionary for parameter +# GUI_B - GUI-buttons dictionary for drawingTypes +for k, v in keywords_org.iteritems(): + GUI_A[k] = Draw.Create(v) +for k, v in drawTypes_org.iteritems(): + GUI_B[k] = Draw.Create(v) +#print 'deb:init GUI_A: ', GUI_A #--------------- +#print 'deb:init GUI_B: ', GUI_B #--------------- +# initialize settings-object controls how dxf entities are drawn +settings = Settings(keywords_org, drawTypes_org) + + + +def saveConfig(): #remi--todo----------------------------------------------- + """Save settings/config/materials from GUI to INI-file. + + Write all config data to INI-file. + """ + global iniFileName + + iniFile = iniFileName.val + #print 'deb:saveConfig inifFile: ', inifFile #---------------------- + if iniFile.lower().endswith(INIFILE_EXTENSION): + output = '[%s,%s]' %(GUI_A, GUI_B) + if output =='None': + Draw.PupMenu('DXF importer: INI-file: Alert!%t|no config-data present to save!') + else: + #if BPyMessages.Warning_SaveOver(iniFile): #<- remi find it too abstarct + if sys.exists(iniFile): + f = file(iniFile, 'r'); header_str = f.readline(); f.close() + if header_str.startswith(INIFILE_HEADER[0:12]): + if Draw.PupMenu(' OK ? %t|SAVE OVER: ' + '\'%s\'' %iniFile) == 1: + save_ok = True + elif Draw.PupMenu(' OK ? %t|SAVE OVER: ' + '\'%s\'' %iniFile + + '|Alert: this file has no valid ImportDXF-format| ! it may belong to another aplication !') == 1: + save_ok = True + else: save_ok = False + else: save_ok = True + + if save_ok: + try: + f = file(iniFile, 'w') + f.write(INIFILE_HEADER + '\n') + f.write(output) + f.close() + Draw.PupMenu('DXF importer: INI-file: Done!%t|config-data saved in ' + '\'%s\'' %iniFile) + except: + Draw.PupMenu('DXF importer: INI-file: Error!%t|failure by writing to ' + '\'%s\'|no config-data saved!' %iniFile) + + else: + Draw.PupMenu('DXF importer: INI-file: Alert!%t|no valid name/extension for INI-file selected!') + print "DXF importer: Alert!: no valid INI-file selected." + if not iniFile: + if dxfFileName.val.lower().endswith('.dxf'): + iniFileName.val = dxfFileName.val[0:-4] + INIFILE_EXTENSION + + +def loadConfig(): #remi--todo----------------------------------------------- + """Load settings/config/materials from INI-file. + + Read material-assignements from config-file. + """ + #070724 buggy Window.FileSelector(loadConfigFile, 'Load config data from INI-file', inifilename) + global iniFileName, GUI_A, GUI_B + + iniFile = iniFileName.val + #print 'deb:loadConfig iniFile: ', iniFile #---------------------- + if iniFile.lower().endswith(INIFILE_EXTENSION) and sys.exists(iniFile): + f = file(iniFile, 'r') + header_str = f.readline() + if not header_str.startswith(INIFILE_HEADER): + f.close() + Draw.PupMenu('DXF importer: INI-file: Alert!%t|no valid header in INI-file: ' + '\'%s\'' %iniFile) + else: + data_str = f.read() + f.close() + #print 'deb:loadConfig data_str from %s: \n' %iniFile , data_str #-------------------------- + data = eval(data_str) + for k, v in data[0].iteritems(): + try: + GUI_A[k].val = v + except: + GUI_A[k] = Draw.Create(v) + for k, v in data[1].iteritems(): + try: + GUI_B[k].val = v + except: + GUI_B[k] = Draw.Create(v) + else: + Draw.PupMenu('DXF importer: INI-file: Alert!%t|no valid INI-file selected!') + print "DXF importer: Alert!: no valid INI-file selected." + if not iniFileName: + if dxfFileName.val.lower().endswith('.dxf'): + iniFileName.val = dxfFileName.val[0:-4] + INIFILE_EXTENSION + + + +def resetDefaultConfig(): #----------------------------------------------- + """Resets settings/config/materials to defaults. + + """ + global GUI_A, GUI_B + #print 'deb:lresetDefaultConfig keywords_org: \n', keywords_org #--------- + for k, v in keywords_org.iteritems(): + GUI_A[k].val = v + for k, v in drawTypes_org.iteritems(): + GUI_B[k].val = v + + +def resetDefaultConfig_2D(): #----------------------------------------------- + """Sets settings/config/materials to defaults 2D. + + """ + resetDefaultConfig() + global GUI_A, GUI_B + keywords2d = { + 'curves_on' : 0, + 'one_mesh_on': 1, + 'vGroup_on' : 1, + 'thick_on' : 0, + 'thick_force': 0, + 'width_on' : 1, + 'width_force': 0, + 'dist_on' : 1, + 'dist_force': 0, + 'pl_3d' : 0, + 'fill_on' : 0, + 'pl_section_on': 1, + 'points_as' : 2, + 'lines_as' : 2, + 'mlines_as' : 2, + 'plines_as' : 2, + 'solids_as' : 1, + 'blocks_as' : 1, + 'texts_as' : 1 + } + + drawTypes2d = { + 'point' : 1, + 'line' : 1, + 'arc' : 1, + 'circle': 1, + 'ellipse': 0, + 'mline' : 0, + 'polyline': 1, + 'plmesh': 0, + 'pline3': 0, + 'lwpolyline': 1, + 'text' : 1, + 'mtext' : 0, + 'block' : 1, + 'insert': 1, + 'face' : 0, + 'solid' : 1, + 'trace' : 1 + } + + for k, v in keywords2d.iteritems(): + GUI_A[k].val = v + for k, v in drawTypes2d.iteritems(): + GUI_B[k].val = v + + + +def draw_UI(): #----------------------------------------------------------------- + """ Draw startUI and setup Settings. + """ + global GUI_A, GUI_B #__version__ + global user_preset, iniFileName, dxfFileName, config_UI + + # This is for easy layout changes + but_0c = 70 #button 1.column width + but_1c = 70 #button 1.column width + but_2c = 70 #button 2.column + but_3c = 70 #button 3.column + menu_margin = 10 + butt_margin = 10 + menu_w = (3 * butt_margin) + but_0c + but_1c + but_2c + but_3c #menu width + + simple_menu_h = 110 + extend_menu_h = 380 + y = simple_menu_h # y is menu upper.y + if config_UI.val: y += extend_menu_h + x = 20 #menu left.x + but0c = x + menu_margin #buttons 0.column position.x + but1c = but0c + but_0c + butt_margin + but2c = but1c + but_1c + butt_margin + but3c = but2c + but_2c + butt_margin + + # Here starts menu ----------------------------------------------------- + #glClear(GL_COLOR_BUFFER_BIT) + #glRasterPos2d(8, 125) + + colorbox(x, y+20, x+menu_w+menu_margin*2, menu_margin) + Draw.Label("DXF Importer ver." + __version__, but0c, y, menu_w, 20) + + if config_UI.val: + y -= 30 + Draw.BeginAlign() + GUI_B['point'] = Draw.Toggle('POINT', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['point'].val, "support dxf-POINT on/off") + Draw.Label('-->', but2c, y, but_2c, 20) + GUI_A['points_as'] = Draw.Menu(points_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['points_as'].val, "select target Blender-object") + Draw.EndAlign() + + y -= 20 + Draw.BeginAlign() + GUI_B['line'] = Draw.Toggle('LINE.ARC.CIRCLE', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['line'].val, "support dxf-LINE,ARC,CIRCLE,ELLIPSE on/off") + Draw.Label('-->', but2c, y, but_2c, 20) + GUI_A['lines_as'] = Draw.Menu(lines_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['lines_as'].val, "select target Blender-object") + Draw.EndAlign() + + y -= 20 + Draw.BeginAlign() + GUI_B['mline'] = Draw.Toggle('*MLINE', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['mline'].val, "(*wip)support dxf-MLINE on/off") + Draw.Label('-->', but2c, y, but_2c, 20) + GUI_A['mlines_as'] = Draw.Menu(mlines_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['mlines_as'].val, "select target Blender-object") + Draw.EndAlign() + + y -= 20 + Draw.BeginAlign() + GUI_B['polyline'] = Draw.Toggle('2D-POLYLINE', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['polyline'].val, "support dxf-2D-POLYLINE on/off") + Draw.Label('-->', but2c, y, but_2c, 20) + GUI_A['plines_as'] = Draw.Menu(plines_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['plines_as'].val, "select target Blender-object") + Draw.EndAlign() + + y -= 20 + Draw.BeginAlign() + GUI_B['pline3'] = Draw.Toggle('3D-POLYLINE', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['pline3'].val, "support dxf-3D-POLYLINE on/off") + Draw.Label('-->', but2c, y, but_2c, 20) + GUI_A['plines3_as'] = Draw.Menu(plines3_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['plines3_as'].val, "select target Blender-object") + Draw.EndAlign() + + y -= 20 + Draw.BeginAlign() + GUI_B['plmesh'] = Draw.Toggle('POLYMESH/-FACE', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['plmesh'].val, "support dxf-POLYMESH/POLYFACE on/off") + Draw.Label('-->', but2c, y, but_2c, 20) + GUI_A['plmesh_as'] = Draw.Menu(plmesh_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['plmesh_as'].val, "select target Blender-object") + Draw.EndAlign() + + y -= 20 + Draw.BeginAlign() + GUI_B['solid'] = Draw.Toggle('3DFACE.SOLID.TRACE', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['solid'].val, "support dxf-3DFACE, SOLID and TRACE on/off") + Draw.Label('-->', but2c, y, but_2c, 20) + GUI_A['solids_as'] = Draw.Menu(solids_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['solids_as'].val, "select target Blender-object") + Draw.EndAlign() + + y -= 20 + Draw.BeginAlign() + GUI_B['text'] = Draw.Toggle('TEXT', EVENT_NONE, but0c, y, but_0c, 20, GUI_B['text'].val, "support dxf-TEXT on/off") + GUI_B['mtext'] = Draw.Toggle('*MTEXT', EVENT_NONE, but1c, y, but_1c-butt_margin, 20, GUI_B['mtext'].val, "(*wip)support dxf-MTEXT on/off") + Draw.Label('-->', but2c, y, but_2c, 20) + GUI_A['texts_as'] = Draw.Menu(texts_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['texts_as'].val, "select target Blender-object") + Draw.EndAlign() + + y -= 20 + Draw.BeginAlign() + GUI_B['block'] = Draw.Toggle('BLOCK / ARRAY', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['block'].val, "support dxf-BLOCK and ARRAY on/off") + Draw.Label('-->', but2c, y, but_2c, 20) + GUI_A['blocks_as'] = Draw.Menu(blocks_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['blocks_as'].val, "select target Blender-object") + Draw.EndAlign() + + + y -= 20 + Draw.BeginAlign() + GUI_A['material_from'] = Draw.Menu(material_from_menu, EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_A['material_from'].val, "material assignment from?") + Draw.Label('-->', but2c, y, but_2c, 20) + GUI_A['material_on'] = Draw.Toggle('material', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['material_on'].val, "support for material assignment on/off") + Draw.EndAlign() + + + y -= 30 + GUI_A['group_bylayer_on'] = Draw.Toggle('oneGroup', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['group_bylayer_on'].val, "grouping entities from the same layer on/off") + GUI_A['curves_on'] = Draw.Toggle('to Curves', EVENT_NONE, but1c, y, but_1c, 20, GUI_A['curves_on'].val, "drawing LINE/ARC/POLYLINE into Blender-Curves instead of Meshes on/off") + Draw.BeginAlign() + GUI_A['g_scale_on'] = Draw.Toggle('glob.Scale', EVENT_NONE, but2c, y, but_2c, 20, GUI_A['g_scale_on'].val, "scaling all DXF objects on/off") + GUI_A['g_scale_as'] = Draw.Menu(g_scale_list, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['g_scale_as'].val, "10^ factor for scaling the DXFdata") + Draw.EndAlign() + + + y -= 20 + #Draw.Label('', but1c+but_1c/2, y, but_1c/2, 20) + GUI_A['one_mesh_on'] = Draw.Toggle('oneMesh', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['one_mesh_on'].val, "drawing DXF-entities into one mesh-object. Recommended for big DXF-files. on/off") + GUI_A['vGroup_on'] = Draw.Toggle('vGroups', EVENT_NONE, but1c, y, but_1c, 20, GUI_A['vGroup_on'].val, "support Blender-VertexGroups on/off") + Draw.BeginAlign() + GUI_A['dist_on'] = Draw.Toggle('dist.:', EVENT_NONE, but2c, y, but_2c-20, 20, GUI_A['dist_on'].val, "support distance on/off") + GUI_A['dist_force'] = Draw.Toggle('F', EVENT_NONE, but2c+but_2c-20, y, 20, 20, GUI_A['dist_force'].val, "force minimal distance on/off") + GUI_A['dist_min'] = Draw.Number('', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['dist_min'].val, 0, 10, "minimal lenght/distance (double.vertex removing)") + Draw.EndAlign() + + y -= 20 + Draw.BeginAlign() + GUI_A['pl_section_on'] = Draw.Toggle('int.section', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['pl_section_on'].val, "support POLYLINE-wide-segment-intersection on/off") + GUI_A['angle_cut'] = Draw.Number('', EVENT_NONE, but1c, y, but_1c, 20, GUI_A['angle_cut'].val, 1, 5, "it limits POLYLINE-wide-segment-intersection: 1.0-5.0") + Draw.EndAlign() + Draw.BeginAlign() + GUI_A['thick_on'] = Draw.Toggle('thick:', EVENT_NONE, but2c, y, but_2c-20, 20, GUI_A['thick_on'].val, "support thickness on/off") + GUI_A['thick_force'] = Draw.Toggle('F', EVENT_NONE, but2c+but_2c-20, y, 20, 20, GUI_A['thick_force'].val, "force minimal thickness on/off") + GUI_A['thick_min'] = Draw.Number('', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['thick_min'].val, 0, 10, "minimal thickness") + Draw.EndAlign() + + + y -= 20 + Draw.BeginAlign() +# GUI_A['thin_res'] = Draw.Number('thin:', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['thin_res'].val, 4, 500, "thin cylinder resolution - number of segments") + GUI_A['arc_rad'] = Draw.Number('radi:', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['arc_rad'].val, 0.01, 100, "basis radius for arc/circle resolution") + GUI_A['arc_res'] = Draw.Number('res:', EVENT_NONE, but1c, y, but_1c-25, 20, GUI_A['arc_res'].val, 4, 500, "arc/circle resolution - number of segments") + GUI_A['fill_on'] = Draw.Toggle('cap', EVENT_NONE, but1c+but_1c-25, y, 25, 20, GUI_A['fill_on'].val, "draws top and bottom caps of CYLINDERs on/off") + Draw.EndAlign() + Draw.BeginAlign() + GUI_A['width_on'] = Draw.Toggle('width:', EVENT_NONE, but2c, y, but_2c-20, 20, GUI_A['width_on'].val, "support width on/off") + GUI_A['width_force'] = Draw.Toggle('F', EVENT_NONE, but2c+but_2c-20, y, 20, 20, GUI_A['width_force'].val, "force minimal width on/off") + GUI_A['width_min'] = Draw.Number('', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['width_min'].val, 0, 10, "minimal width") + Draw.EndAlign() + + y -= 30 + #GUI_A['dummy_on'] = Draw.Toggle(' - ', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['dummy_on'].val, "reserved") + GUI_A['newScene_on'] = Draw.Toggle('newScene', EVENT_NONE, but1c, y, but_1c, 20, GUI_A['newScene_on'].val, "creates new Blender-Scene for each import on/off") + GUI_A['target_layer'] = Draw.Number('layer', EVENT_NONE, but2c, y, but_2c, 20, GUI_A['target_layer'].val, 1, 18, "imports into this Blender-layer (<19> reserved for block_definitions)") + GUI_A['optimization'] = Draw.Number('optim:', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['optimization'].val, 0, 3, "Optimization Level: 0=Debug/directDrawing, 1=Verbose, 2=ProgressBar, 3=silentMode/fastest") + + y -= 30 + Draw.BeginAlign() + Draw.PushButton('INI file >', EVENT_CHOOSE_INI, but0c, y, but_0c, 20, 'Select INI-file from project directory') + iniFileName = Draw.String(' :', EVENT_NONE, but1c, y, menu_w-but_0c-butt_margin, 20, iniFileName.val, FILENAME_MAX, "write here the name of the INI-file") + Draw.EndAlign() + + y -= 20 + Draw.BeginAlign() + Draw.PushButton('Presets', EVENT_PRESETS, but0c, y, but_0c, 20, "tipist for Preset-INI-files") + Draw.PushButton('Load', EVENT_LOAD_INI, but1c, y, but_1c, 20, ' Loads configuration from ini-file: %s' % iniFileName.val) + Draw.PushButton('Save', EVENT_SAVE_INI, but2c, y, but_2c, 20, 'Saves configuration to ini-file: %s' % iniFileName.val) +# user_preset = Draw.Number('preset:', EVENT_PRESETS, but2c, y, but_2c, 20, user_preset.val, 0, 5, "call user Preset-INI-files") + Draw.PushButton('2D', EVENT_PRESET2D, but3c, y, but_3c/2, 20, 'resets configuration to 2D-defaults') + Draw.PushButton('3D', EVENT_PRESET, but3c+but_3c/2, y, but_3c/2, 20, 'resets configuration to 3D-defaults') + Draw.EndAlign() + + + y -= 30 + Draw.BeginAlign() + Draw.PushButton('DXFfile >', EVENT_CHOOSE_DXF, but0c, y, but_0c, 20, 'Select DXF-file from project directory') + dxfFileName = Draw.String(' :', EVENT_NONE, but1c, y, but_1c+but_2c+but_3c-20, 20, dxfFileName.val, FILENAME_MAX, "type the name of DXF-file or * for multi-import") + Draw.PushButton('*.*', EVENT_DXF_DIR, but3c+but_3c-20, y, 20, 20, 'Set asterisk * as filter') + Draw.EndAlign() + + + y -= 50 + Draw.BeginAlign() + Draw.PushButton('EXIT', EVENT_EXIT, but0c, y, but_0c, 40, '' ) + Draw.PushButton('HELP', EVENT_HELP, but1c, y, but_1c, 20, 'calls BlenderWiki for Manual, Updates and Support.') + Draw.PushButton('START IMPORT', EVENT_START, but2c, y, but_2c+but_3c+butt_margin, 40, 'Start the import procedure') + Draw.EndAlign() + + config_UI = Draw.Toggle('CONFIG', EVENT_CONFIG, but1c-butt_margin/2, y+20, but_1c+butt_margin, 20, config_UI.val, 'Advanced configuration on/off' ) + + y -= 20 + Draw.BeginAlign() + Draw.Label(' ', but0c-menu_margin, y, menu_margin, 20) + Draw.Label("*) parts under construction", but0c, y, menu_w, 20) + Draw.Label(' ', but0c+menu_w, y, menu_margin, 20) + Draw.EndAlign() + +#-- END GUI Stuf----------------------------------------------------- + +def colorbox(x,y,xright,bottom): + glColor3f(0.75, 0.75, 0.75) + glRecti(x + 1, y + 1, xright - 1, bottom - 1) + +def dxf_callback(input_filename): + global dxfFileName + dxfFileName.val=input_filename + +def ini_callback(input_texture): + global iniFileName + iniFileName.val=input_texture + +def event(evt, val): + if evt in (Draw.QKEY, Draw.ESCKEY) and not val: + Blender.Draw.Exit() + +def bevent(evt): +# global EVENT_NONE,EVENT_LOAD_DXF,EVENT_LOAD_INI,EVENT_SAVE_INI,EVENT_EXIT + global config_UI, user_preset + + ######### Manages GUI events + if (evt==EVENT_EXIT): + Blender.Draw.Exit() + elif (evt==EVENT_CHOOSE_INI): + Window.FileSelector(ini_callback, "INI-file Selection", '*.ini') + elif (evt==EVENT_CONFIG): + Draw.Redraw() + elif (evt==EVENT_PRESET): + resetDefaultConfig() + Draw.Redraw() + elif (evt==EVENT_PRESET2D): + resetDefaultConfig_2D() + Draw.Redraw() + elif (evt==EVENT_PRESETS): + user_preset += 1 + if user_preset > 5: user_preset = 1 + iniFileName.val = INIFILE_DEFAULT_NAME + str(user_preset) + INIFILE_EXTENSION + Draw.Redraw() + elif (evt==EVENT_HELP): + try: + import webbrowser + webbrowser.open('http://wiki.blender.org/index.php?title=Scripts/Manual/Import/DXF-3D') + except: + Draw.PupMenu('DXF importer: HELP Alert!%t|no connection to manual-page on Blender-Wiki! try:|\ +http://wiki.blender.org/index.php?title=Scripts/Manual/Import/DXF-3D') + Draw.Redraw() + elif (evt==EVENT_LOAD_INI): + loadConfig() + Draw.Redraw() + elif (evt==EVENT_SAVE_INI): + saveConfig() + Draw.Redraw() + elif (evt==EVENT_DXF_DIR): + dxfFile = dxfFileName.val + dxfPathName = '' + if '/' in dxfFile: + dxfPathName = '/'.join(dxfFile.split('/')[:-1]) + '/' + elif '\\' in dxfFile: + dxfPathName = '\\'.join(dxfFile.split('\\')[:-1]) + '\\' + dxfFileName.val = dxfPathName + '*.dxf' + global GUI_A + GUI_A['newScene_on'].val = 1 + Draw.Redraw() + elif (evt==EVENT_CHOOSE_DXF): + Window.FileSelector(dxf_callback, "DXF-file Selection", '*.dxf') + elif (evt==EVENT_START): + dxfFile = dxfFileName.val + #print 'deb: dxfFile file: ', dxfFile #---------------------- + if dxfFile.lower().endswith('*.dxf'): + if Draw.PupMenu('DXF importer: OK?|will import all DXF-files from:|%s' % dxfFile) == 1: + global UI_MODE + UI_MODE = False + multi_import(dxfFile[:-5]) # cut last char:'*.dxf' + Draw.Exit() + else: + Draw.Redraw() + elif dxfFile.lower().endswith('.dxf') and sys.exists(dxfFile): + if GUI_A['newScene_on'].val: + _dxf_file = dxfFile.split('/')[-1].split('\\')[-1] + _dxf_file = _dxf_file[:-4] # cut last char:'.dxf' + _dxf_file = _dxf_file[:MAX_NAMELENGTH] #? [-MAX_NAMELENGTH:]) + global SCENE + SCENE = Blender.Scene.New(_dxf_file) + SCENE.makeCurrent() + #or so? Blender.Scene.makeCurrent(_dxf_file) + #sce = bpy.data.scenes.new(_dxf_file) + #bpy.data.scenes.active = sce + else: + SCENE = Blender.Scene.GetCurrent() + SCENE.objects.selected = [] # deselect all + main(dxfFile) + #SCENE.objects.selected = SCENE.objects + #Window.RedrawAll() + #Blender.Redraw() + #Draw.Redraw() + else: + Draw.PupMenu('DXF importer: Alert!%t|no valid DXF-file selected!') + print "DXF importer: error, no valid DXF-file selected! try again" + Draw.Redraw() + + + + +def multi_import(DIR): + """Imports all DXF-files from directory DIR. + + """ + global SCENE + batchTIME = Blender.sys.time() + #if #DIR == "": DIR = os.path.curdir + if DIR == "": DIR = Blender.sys.dirname(Blender.Get('filename')) + print 'Searching for DXF-files in %s' %DIR + files = \ + [sys.join(DIR, f) for f in os.listdir(DIR) if f.lower().endswith('.dxf')] + if not files: + print '...None DXF-files found. Abort!' + return + + i = 0 + for dxfFile in files: + i += 1 + print 'Importing', dxfFile, ' NUMBER', i, 'of', len(files) + if GUI_A['newScene_on'].val: + _dxf_file = dxfFile.split('/')[-1].split('\\')[-1] + _dxf_file = _dxf_file[:-4] # cut last char:'.dxf' + _dxf_file = _dxf_file[:MAX_NAMELENGTH] #? [-MAX_NAMELENGTH:]) + SCENE = Blender.Scene.New(_dxf_file) + SCENE.makeCurrent() + #or so? Blender.Scene.makeCurrent(_dxf_file) + #sce = bpy.data.scenes.new(_dxf_file) + #bpy.data.scenes.active = sce + else: + SCENE = Blender.Scene.GetCurrent() + SCENE.objects.selected = [] # deselect all + main(dxfFile) + #Blender.Redraw() + + print 'TOTAL TIME: %.6f' % (Blender.sys.time() - batchTIME) + + + + +if __name__ == "__main__": + UI_MODE = True + Draw.Register(draw_UI, event, bevent) + + +""" +if 1: + # DEBUG ONLY + UI_MODE = False + TIME= Blender.sys.time() + #DIR = '/dxf_r12_testfiles/' + DIR = '/metavr/' + import os + print 'Searching for files' + os.system('find %s -iname "*.dxf" > /tmp/tempdxf_list' % DIR) + # os.system('find /storage/ -iname "*.dxf" > /tmp/tempdxf_list') + print '...Done' + file= open('/tmp/tempdxf_list', 'r') + lines= file.readlines() + file.close() + # sort by filesize for faster testing + lines_size = [(os.path.getsize(f[:-1]), f[:-1]) for f in lines] + lines_size.sort() + lines = [f[1] for f in lines_size] + + for i, _dxf in enumerate(lines): + if i >= 70: + #if 1: + print 'Importing', _dxf, '\nNUMBER', i, 'of', len(lines) + if True: + _dxf_file= _dxf.split('/')[-1].split('\\')[-1] + _dxf_file = _dxf_file[:-4] # cut last char:'.dxf' + _dxf_file = _dxf_file[:MAX_NAMELENGTH] #? [-MAX_NAMELENGTH:]) + sce = bpy.data.scenes.new(_dxf_file) + bpy.data.scenes.active = sce + dxfFileName.val = _dxf + main(_dxf) + + print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME) +""" \ No newline at end of file diff --git a/release/scripts/import_mdd.py b/release/scripts/import_mdd.py new file mode 100644 index 00000000000..8e7b9985d3d --- /dev/null +++ b/release/scripts/import_mdd.py @@ -0,0 +1,158 @@ +#!BPY + + #""" + #Name: 'Load MDD to Mesh RVKs' + #Blender: 242 + #Group: 'Import' + #Tooltip: 'baked vertex animation to active mesh object.' + #""" +__author__ = "Bill L.Nieuwendorp" +__bpydoc__ = """\ +This script Imports Lightwaves MotionDesigner format. + +The .mdd format has become quite a popular Pipeline format
+for moving animations from package to package. +""" +# mdd importer +# +# Warning if the vertex order or vertex count differs from the +# origonal model the mdd was Baked out from their will be Strange +# behavior +# +# +#vertex animation to ShapeKeys with ipo and gives the frame a value of 1.0 +#A modifier to read mdd files would be Ideal but thats for another day :) +# +#Please send any fixes,updates,bugs to Slow67_at_Gmail.com +#Bill Niewuendorp + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** + + + + +try: + from struct import unpack +except: + unpack = None + +import Blender +from Blender import Mesh, Object, Scene +import BPyMessages + +def mdd_import(filepath, ob, PREF_IPONAME, PREF_START_FRAME, PREF_JUMP): + + print '\n\nimporting mdd "%s"' % filepath + + Blender.Window.DrawProgressBar (0.0, "Importing mdd ...") + Blender.Window.EditMode(0) + Blender.Window.WaitCursor(1) + + file = open(filepath, 'rb') + frames, points = unpack(">2i", file.read(8)) + time = unpack((">%df" % frames), file.read(frames * 4)) + + print '\tpoints:%d frames:%d' % (points,frames) + + scn = Scene.GetCurrent() + ctx = scn.getRenderingContext() + Blender.Set("curframe", PREF_START_FRAME) + me = ob.getData(mesh=1) + + def UpdateMesh(me,fr): + for v in me.verts: + # 12 is the size of 3 floats + x,y,z= unpack('>3f', file.read(12)) + v.co[:] = x,z,y + me.update() + + Blender.Window.DrawProgressBar (0.4, "4 Importing mdd ...") + + + curfr = ctx.currentFrame() + print'\twriting mdd data...' + for i in xrange(frames): + Blender.Set("curframe", i+PREF_START_FRAME) + if len(me.verts) > 1 and (curfr >= PREF_START_FRAME) and (curfr <= PREF_START_FRAME+frames): + UpdateMesh(me, i) + ob.insertShapeKey() + + Blender.Window.DrawProgressBar (0.5, "5 Importing mdd ...") + + key= me.key + + # Add the key of its not there + if not key: + me.insertKey(1, 'relative') + key= me.key + + key.ipo = Blender.Ipo.New('Key', PREF_IPONAME) + ipo = key.ipo + # block = key.getBlocks() # not used. + all_keys = ipo.curveConsts + + for i in xrange(PREF_JUMP+1, len(all_keys), PREF_JUMP): + curve = ipo.getCurve(i) + if curve == None: + curve = ipo.addCurve(all_keys[i]) + + curve.append((PREF_START_FRAME+i-1,1)) + curve.append((PREF_START_FRAME+i- PREF_JUMP -1,0)) + curve.append((PREF_START_FRAME+i+ PREF_JUMP-1,0)) + curve.setInterpolation('Linear') + curve.recalc() + + print 'done' + Blender.Window.WaitCursor(0) + Blender.Window.DrawProgressBar (1.0, '') + + +def mdd_import_ui(filepath): + + if BPyMessages.Error_NoFile(filepath): + return + + scn= Scene.GetCurrent() + ob_act= scn.objects.active + + if ob_act == None or ob_act.type != 'Mesh': + BPyMessages.Error_NoMeshActive() + return + + PREF_IPONAME = Blender.Draw.Create(filepath.split('/')[-1].split('\\')[-1].split('.')[0]) + PREF_START_FRAME = Blender.Draw.Create(1) + PREF_JUMP = Blender.Draw.Create(1) + + block = [\ + ("Ipo Name: ", PREF_IPONAME, 0, 30, "Ipo name for the new shape key"),\ + ("Start Frame: ", PREF_START_FRAME, 1, 3000, "Start frame for the animation"),\ + ("Key Skip: ", PREF_JUMP, 1, 100, "KeyReduction, Skip every Nth Frame")\ + ] + + if not Blender.Draw.PupBlock("Import MDD", block): + return + orig_frame = Blender.Get('curframe') + mdd_import(filepath, ob_act, PREF_IPONAME.val, PREF_START_FRAME.val, PREF_JUMP.val) + Blender.Set('curframe', orig_frame) + +if __name__ == '__main__': + if not unpack: + Draw.PupMenu('Error%t|This script requires a full python install') + + Blender.Window.FileSelector(mdd_import_ui, 'IMPORT MDD', '*.mdd') diff --git a/release/scripts/import_obj.py b/release/scripts/import_obj.py new file mode 100644 index 00000000000..30c4c410434 --- /dev/null +++ b/release/scripts/import_obj.py @@ -0,0 +1,880 @@ +#!BPY + +""" +Name: 'Wavefront (.obj)...' +Blender: 242 +Group: 'Import' +Tooltip: 'Load a Wavefront OBJ File, Shift: batch import all dir.' +""" + +__author__= "Campbell Barton", "Jiri Hnidek" +__url__= ["blender.org", "blenderartists.org"] +__version__= "2.0" + +__bpydoc__= """\ +This script imports a Wavefront OBJ files to Blender. + +Usage: +Run this script from "File->Import" menu and then load the desired OBJ file. +Note, This loads mesh objects and materials only, nurbs and curves are not supported. +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Campbell J Barton 2007 +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +from Blender import * +import bpy +import BPyMesh +import BPyImage +import BPyMessages + +try: import os +except: os= False + + +# Generic path functions +def stripFile(path): + '''Return directory, where the file is''' + lastSlash= max(path.rfind('\\'), path.rfind('/')) + if lastSlash != -1: + path= path[:lastSlash] + return '%s%s' % (path, sys.sep) + +def stripPath(path): + '''Strips the slashes from the back of a string''' + return path.split('/')[-1].split('\\')[-1] + +def stripExt(name): # name is a string + '''Strips the prefix off the name before writing''' + index= name.rfind('.') + if index != -1: + return name[ : index ] + else: + return name +# end path funcs + + + +def line_value(line_split): + ''' + Returns 1 string represneting the value for this line + None will be returned if theres only 1 word + ''' + length= len(line_split) + if length == 1: + return None + + elif length == 2: + return line_split[1] + + elif length > 2: + return ' '.join( line_split[1:] ) + +def obj_image_load(imagepath, DIR, IMAGE_SEARCH): + ''' + Mainly uses comprehensiveImageLoad + but tries to replace '_' with ' ' for Max's exporter replaces spaces with underscores. + ''' + + if '_' in imagepath: + image= BPyImage.comprehensiveImageLoad(imagepath, DIR, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH) + if image: return image + # Did the exporter rename the image? + image= BPyImage.comprehensiveImageLoad(imagepath.replace('_', ' '), DIR, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH) + if image: return image + + # Return an image, placeholder if it dosnt exist + image= BPyImage.comprehensiveImageLoad(imagepath, DIR, PLACE_HOLDER= True, RECURSIVE= IMAGE_SEARCH) + return image + + +def create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH): + ''' + Create all the used materials in this obj, + assign colors and images to the materials from all referenced material libs + ''' + DIR= stripFile(filepath) + + #==================================================================================# + # This function sets textures defined in .mtl file # + #==================================================================================# + def load_material_image(blender_material, context_material_name, imagepath, type): + + texture= bpy.data.textures.new(type) + texture.setType('Image') + + # Absolute path - c:\.. etc would work here + image= obj_image_load(imagepath, DIR, IMAGE_SEARCH) + has_data = image.has_data + texture.image = image + + # Adds textures for materials (rendering) + if type == 'Kd': + if has_data and image.depth == 32: + # Image has alpha + blender_material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL | Texture.MapTo.ALPHA) + texture.setImageFlags('MipMap', 'InterPol', 'UseAlpha') + blender_material.mode |= Material.Modes.ZTRANSP + blender_material.alpha = 0.0 + else: + blender_material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL) + + # adds textures to faces (Textured/Alt-Z mode) + # Only apply the diffuse texture to the face if the image has not been set with the inline usemat func. + unique_material_images[context_material_name]= image, has_data # set the texface image + + elif type == 'Ka': + blender_material.setTexture(1, texture, Texture.TexCo.UV, Texture.MapTo.CMIR) # TODO- Add AMB to BPY API + + elif type == 'Ks': + blender_material.setTexture(2, texture, Texture.TexCo.UV, Texture.MapTo.SPEC) + + elif type == 'Bump': + blender_material.setTexture(3, texture, Texture.TexCo.UV, Texture.MapTo.NOR) + elif type == 'D': + blender_material.setTexture(4, texture, Texture.TexCo.UV, Texture.MapTo.ALPHA) + blender_material.mode |= Material.Modes.ZTRANSP + blender_material.alpha = 0.0 + # Todo, unset deffuse material alpha if it has an alpha channel + + elif type == 'refl': + blender_material.setTexture(5, texture, Texture.TexCo.UV, Texture.MapTo.REF) + + + # Add an MTL with the same name as the obj if no MTLs are spesified. + temp_mtl= stripExt(stripPath(filepath))+ '.mtl' + + if sys.exists(DIR + temp_mtl) and temp_mtl not in material_libs: + material_libs.append( temp_mtl ) + del temp_mtl + + #Create new materials + for name in unique_materials.iterkeys(): + unique_materials[name]= bpy.data.materials.new(name) + + unique_material_images[name]= None, False # assign None to all material images to start with, add to later. + + unique_materials[None]= None + + for libname in material_libs: + mtlpath= DIR + libname + if not sys.exists(mtlpath): + #print '\tError Missing MTL: "%s"' % mtlpath + pass + else: + #print '\t\tloading mtl: "%s"' % mtlpath + context_material= None + mtl= open(mtlpath) + for line in mtl: #.xreadlines(): + if line.startswith('newmtl'): + context_material_name= line_value(line.split()) + if unique_materials.has_key(context_material_name): + context_material = unique_materials[ context_material_name ] + else: + context_material = None + + elif context_material: + # we need to make a material to assign properties to it. + line_split= line.split() + line_lower= line.lower() + if line_lower.startswith('ka'): + context_material.setMirCol((float(line_split[1]), float(line_split[2]), float(line_split[3]))) + elif line_lower.startswith('kd'): + context_material.setRGBCol((float(line_split[1]), float(line_split[2]), float(line_split[3]))) + elif line_lower.startswith('ks'): + context_material.setSpecCol((float(line_split[1]), float(line_split[2]), float(line_split[3]))) + elif line_lower.startswith('ns'): + context_material.setHardness( int((float(line_split[1])*0.51)) ) + elif line_lower.startswith('ni'): # Refraction index + context_material.setIOR( max(1, min(float(line_split[1]), 3))) # Between 1 and 3 + elif line_lower.startswith('d') or line_lower.startswith('tr'): + context_material.setAlpha(float(line_split[1])) + elif line_lower.startswith('map_ka'): + img_filepath= line_value(line.split()) + if img_filepath: + load_material_image(context_material, context_material_name, img_filepath, 'Ka') + elif line_lower.startswith('map_ks'): + img_filepath= line_value(line.split()) + if img_filepath: + load_material_image(context_material, context_material_name, img_filepath, 'Ks') + elif line_lower.startswith('map_kd'): + img_filepath= line_value(line.split()) + if img_filepath: + load_material_image(context_material, context_material_name, img_filepath, 'Kd') + elif line_lower.startswith('map_bump'): + img_filepath= line_value(line.split()) + if img_filepath: + load_material_image(context_material, context_material_name, img_filepath, 'Bump') + elif line_lower.startswith('map_d') or line_lower.startswith('map_tr'): # Alpha map - Dissolve + img_filepath= line_value(line.split()) + if img_filepath: + load_material_image(context_material, context_material_name, img_filepath, 'D') + + elif line_lower.startswith('refl'): # Reflectionmap + img_filepath= line_value(line.split()) + if img_filepath: + load_material_image(context_material, context_material_name, img_filepath, 'refl') + mtl.close() + + + + +def split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP, SPLIT_MATERIALS): + ''' + Takes vert_loc and faces, and seperates into multiple sets of + (verts_loc, faces, unique_materials, dataname) + This is done so objects do not overload the 16 material limit. + ''' + + filename = stripExt(stripPath(filepath)) + + if not SPLIT_OB_OR_GROUP and not SPLIT_MATERIALS: + # use the filename for the object name since we arnt chopping up the mesh. + return [(verts_loc, faces, unique_materials, filename)] + + + def key_to_name(key): + # if the key is a tuple, join it to make a string + if type(key) == tuple: + return '%s_%s' % key + elif not key: + return filename # assume its a string. make sure this is true if the splitting code is changed + else: + return key + + # Return a key that makes the faces unique. + if SPLIT_OB_OR_GROUP and not SPLIT_MATERIALS: + def face_key(face): + return face[4] # object + + elif not SPLIT_OB_OR_GROUP and SPLIT_MATERIALS: + def face_key(face): + return face[2] # material + + else: # Both + def face_key(face): + return face[4], face[2] # object,material + + + face_split_dict= {} + + oldkey= -1 # initialize to a value that will never match the key + + for face in faces: + + key= face_key(face) + + if oldkey != key: + # Check the key has changed. + try: + verts_split, faces_split, unique_materials_split, vert_remap= face_split_dict[key] + except KeyError: + faces_split= [] + verts_split= [] + unique_materials_split= {} + vert_remap= [-1]*len(verts_loc) + + face_split_dict[key]= (verts_split, faces_split, unique_materials_split, vert_remap) + + oldkey= key + + face_vert_loc_indicies= face[0] + + # Remap verts to new vert list and add where needed + for enum, i in enumerate(face_vert_loc_indicies): + if vert_remap[i] == -1: + new_index= len(verts_split) + vert_remap[i]= new_index # set the new remapped index so we only add once and can reference next time. + face_vert_loc_indicies[enum] = new_index # remap to the local index + verts_split.append( verts_loc[i] ) # add the vert to the local verts + + else: + face_vert_loc_indicies[enum] = vert_remap[i] # remap to the local index + + matname= face[2] + if matname and not unique_materials_split.has_key(matname): + unique_materials_split[matname] = unique_materials[matname] + + faces_split.append(face) + + + # remove one of the itemas and reorder + return [(value[0], value[1], value[2], key_to_name(key)) for key, value in face_split_dict.iteritems()] + + +def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc, verts_tex, faces, unique_materials, unique_material_images, unique_smooth_groups, dataname): + ''' + Takes all the data gathered and generates a mesh, adding the new object to new_objects + deals with fgons, sharp edges and assigning materials + ''' + if not has_ngons: + CREATE_FGONS= False + + if unique_smooth_groups: + sharp_edges= {} + smooth_group_users= dict([ (context_smooth_group, {}) for context_smooth_group in unique_smooth_groups.iterkeys() ]) + context_smooth_group_old= -1 + + # Split fgons into tri's + fgon_edges= {} # Used for storing fgon keys + if CREATE_EDGES: + edges= [] + + context_object= None + + # reverse loop through face indicies + for f_idx in xrange(len(faces)-1, -1, -1): + + face_vert_loc_indicies,\ + face_vert_tex_indicies,\ + context_material,\ + context_smooth_group,\ + context_object= faces[f_idx] + + len_face_vert_loc_indicies = len(face_vert_loc_indicies) + + if len_face_vert_loc_indicies==1: + faces.pop(f_idx)# cant add single vert faces + + elif not face_vert_tex_indicies or len_face_vert_loc_indicies == 2: # faces that have no texture coords are lines + if CREATE_EDGES: + # generators are better in python 2.4+ but can't be used in 2.3 + # edges.extend( (face_vert_loc_indicies[i], face_vert_loc_indicies[i+1]) for i in xrange(len_face_vert_loc_indicies-1) ) + edges.extend( [(face_vert_loc_indicies[i], face_vert_loc_indicies[i+1]) for i in xrange(len_face_vert_loc_indicies-1)] ) + + faces.pop(f_idx) + else: + + # Smooth Group + if unique_smooth_groups and context_smooth_group: + # Is a part of of a smooth group and is a face + if context_smooth_group_old is not context_smooth_group: + edge_dict= smooth_group_users[context_smooth_group] + context_smooth_group_old= context_smooth_group + + for i in xrange(len_face_vert_loc_indicies): + i1= face_vert_loc_indicies[i] + i2= face_vert_loc_indicies[i-1] + if i1>i2: i1,i2= i2,i1 + + try: + edge_dict[i1,i2]+= 1 + except KeyError: + edge_dict[i1,i2]= 1 + + # FGons into triangles + if has_ngons and len_face_vert_loc_indicies > 4: + + ngon_face_indices= BPyMesh.ngon(verts_loc, face_vert_loc_indicies) + faces.extend(\ + [(\ + [face_vert_loc_indicies[ngon[0]], face_vert_loc_indicies[ngon[1]], face_vert_loc_indicies[ngon[2]] ],\ + [face_vert_tex_indicies[ngon[0]], face_vert_tex_indicies[ngon[1]], face_vert_tex_indicies[ngon[2]] ],\ + context_material,\ + context_smooth_group,\ + context_object)\ + for ngon in ngon_face_indices]\ + ) + + # edges to make fgons + if CREATE_FGONS: + edge_users= {} + for ngon in ngon_face_indices: + for i in (0,1,2): + i1= face_vert_loc_indicies[ngon[i ]] + i2= face_vert_loc_indicies[ngon[i-1]] + if i1>i2: i1,i2= i2,i1 + + try: + edge_users[i1,i2]+=1 + except KeyError: + edge_users[i1,i2]= 1 + + for key, users in edge_users.iteritems(): + if users>1: + fgon_edges[key]= None + + # remove all after 3, means we dont have to pop this one. + faces.pop(f_idx) + + + # Build sharp edges + if unique_smooth_groups: + for edge_dict in smooth_group_users.itervalues(): + for key, users in edge_dict.iteritems(): + if users==1: # This edge is on the boundry of a group + sharp_edges[key]= None + + + # mat the material names to an index + material_mapping= dict([(name, i) for i, name in enumerate(unique_materials.keys())]) + + materials= [None] * len(unique_materials) + + for name, index in material_mapping.iteritems(): + materials[index]= unique_materials[name] + + me= bpy.data.meshes.new(dataname) + + me.materials= materials[0:16] # make sure the list isnt too big. + #me.verts.extend([(0,0,0)]) # dummy vert + me.verts.extend(verts_loc) + + face_mapping= me.faces.extend([f[0] for f in faces], indexList=True) + + if verts_tex and me.faces: + me.faceUV= 1 + # TEXMODE= Mesh.FaceModes['TEX'] + + context_material_old= -1 # avoid a dict lookup + mat= 0 # rare case it may be un-initialized. + me_faces= me.faces + ALPHA= Mesh.FaceTranspModes.ALPHA + + for i, face in enumerate(faces): + if len(face[0]) < 2: + pass #raise "bad face" + elif len(face[0])==2: + if CREATE_EDGES: + edges.append(face[0]) + else: + face_index_map= face_mapping[i] + if face_index_map!=None: # None means the face wasnt added + blender_face= me_faces[face_index_map] + + face_vert_loc_indicies,\ + face_vert_tex_indicies,\ + context_material,\ + context_smooth_group,\ + context_object= face + + + + if context_smooth_group: + blender_face.smooth= True + + if context_material: + if context_material_old is not context_material: + mat= material_mapping[context_material] + if mat>15: + mat= 15 + context_material_old= context_material + + blender_face.mat= mat + + + if verts_tex: + if context_material: + image, has_data= unique_material_images[context_material] + if image: # Can be none if the material dosnt have an image. + blender_face.image= image + if has_data and image.depth == 32: + blender_face.transp |= ALPHA + + # BUG - Evil eekadoodle problem where faces that have vert index 0 location at 3 or 4 are shuffled. + if len(face_vert_loc_indicies)==4: + if face_vert_loc_indicies[2]==0 or face_vert_loc_indicies[3]==0: + face_vert_tex_indicies= face_vert_tex_indicies[2], face_vert_tex_indicies[3], face_vert_tex_indicies[0], face_vert_tex_indicies[1] + else: # length of 3 + if face_vert_loc_indicies[2]==0: + face_vert_tex_indicies= face_vert_tex_indicies[1], face_vert_tex_indicies[2], face_vert_tex_indicies[0] + # END EEEKADOODLE FIX + + # assign material, uv's and image + for ii, uv in enumerate(blender_face.uv): + uv.x, uv.y= verts_tex[face_vert_tex_indicies[ii]] + del me_faces + del ALPHA + + # Add edge faces. + me_edges= me.edges + if CREATE_FGONS and fgon_edges: + FGON= Mesh.EdgeFlags.FGON + for ed in me.findEdges( fgon_edges.keys() ): + if ed!=None: + me_edges[ed].flag |= FGON + del FGON + + if unique_smooth_groups and sharp_edges: + SHARP= Mesh.EdgeFlags.SHARP + for ed in me.findEdges( sharp_edges.keys() ): + if ed!=None: + me_edges[ed].flag |= SHARP + del SHARP + + if CREATE_EDGES: + me_edges.extend( edges ) + + del me_edges + + me.calcNormals() + + ob= scn.objects.new(me) + new_objects.append(ob) + +def get_float_func(filepath): + ''' + find the float function for this obj file + - weather to replace commas or not + ''' + file= open(filepath, 'rU') + for line in file: #.xreadlines(): + if line.startswith('v'): # vn vt v + if ',' in line: + return lambda f: float(f.replace(',', '.')) + elif '.' in line: + return float + +def load_obj(filepath, CLAMP_SIZE= 0.0, CREATE_FGONS= True, CREATE_SMOOTH_GROUPS= True, CREATE_EDGES= True, SPLIT_OBJECTS= True, SPLIT_GROUPS= True, SPLIT_MATERIALS= True, IMAGE_SEARCH=True): + ''' + Called by the user interface or another script. + load_obj(path) - should give acceptable results. + This function passes the file and sends the data off + to be split into objects and then converted into mesh objects + ''' + print '\nimporting obj "%s"' % filepath + + time_main= sys.time() + + verts_loc= [] + verts_tex= [] + faces= [] # tuples of the faces + material_libs= [] # filanems to material libs this uses + + + # Get the string to float conversion func for this file- is 'float' for almost all files. + float_func= get_float_func(filepath) + + # Context variables + context_material= None + context_smooth_group= None + context_object= None + + has_ngons= False + # has_smoothgroups= False - is explicit with len(unique_smooth_groups) being > 0 + + # Until we can use sets + unique_materials= {} + unique_material_images= {} + unique_smooth_groups= {} + # unique_obects= {} - no use for this variable since the objects are stored in the face. + + # when there are faces that end with \ + # it means they are multiline- + # since we use xreadline we cant skip to the next line + # so we need to know weather + multi_line_face= False + + print '\tpassing obj file "%s"...' % filepath, + time_sub= sys.time() + file= open(filepath, 'r') + for line in file: #.xreadlines(): + + if line.startswith('v '): + line_split= line.split() + # rotate X90: (x,-z,y) + verts_loc.append( (float_func(line_split[1]), -float_func(line_split[3]), float_func(line_split[2])) ) + + elif line.startswith('vn '): + pass + + elif line.startswith('vt '): + line_split= line.split() + verts_tex.append( (float_func(line_split[1]), float_func(line_split[2])) ) + + # Handel faces lines (as faces) and the second+ lines of fa multiline face here + # use 'f' not 'f ' because some objs (very rare have 'fo ' for faces) + elif line.startswith('f') or (line.startswith('l ') and CREATE_EDGES) or multi_line_face: + + if multi_line_face: + # use face_vert_loc_indicies and face_vert_tex_indicies previously defined and used the obj_face + line_split= line.split() + multi_line_face= False + + else: + line_split= line[2:].split() + face_vert_loc_indicies= [] + face_vert_tex_indicies= [] + + # Instance a face + faces.append((\ + face_vert_loc_indicies,\ + face_vert_tex_indicies,\ + context_material,\ + context_smooth_group,\ + context_object\ + )) + + if line_split[-1][-1]== '\\': + multi_line_face= True + if len(line_split[-1])==1: + line_split.pop() # remove the \ item + else: + line_split[-1]= line_split[-1][:-1] # remove the \ from the end last number + + isline= line.startswith('l') + + for v in line_split: + obj_vert= v.split('/') + + vert_loc_index= int(obj_vert[0])-1 + + # Make relative negative vert indicies absolute + if vert_loc_index < 0: + vert_loc_index= len(verts_loc) + vert_loc_index + 1 + + face_vert_loc_indicies.append(vert_loc_index) + + if not isline: + if len(obj_vert)>1 and obj_vert[1]: + # formatting for faces with normals and textures us + # loc_index/tex_index/nor_index + + vert_tex_index= int(obj_vert[1])-1 + # Make relative negative vert indicies absolute + if vert_tex_index < 0: + vert_tex_index= len(verts_tex) + vert_tex_index + 1 + + face_vert_tex_indicies.append(vert_tex_index) + else: + # dummy + face_vert_tex_indicies.append(0) + + if len(face_vert_loc_indicies) > 4: + has_ngons= True + + elif line.startswith('s'): + if CREATE_SMOOTH_GROUPS: + context_smooth_group= line_value(line.split()) + if context_smooth_group=='off': + context_smooth_group= None + elif context_smooth_group: # is not None + unique_smooth_groups[context_smooth_group]= None + + elif line.startswith('o'): + if SPLIT_OBJECTS: + context_object= line_value(line.split()) + # unique_obects[context_object]= None + + elif line.startswith('g'): + if SPLIT_GROUPS: + context_object= line_value(line.split()) + # print 'context_object', context_object + # unique_obects[context_object]= None + + elif line.startswith('usemtl'): + context_material= line_value(line.split()) + unique_materials[context_material]= None + elif line.startswith('mtllib'): # usemap or usemat + material_libs.extend( line.split()[1:] ) # can have multiple mtllib filenames per line + + ''' # How to use usemap? depricated? + elif line.startswith('usema'): # usemap or usemat + context_image= line_value(line.split()) + ''' + + file.close() + time_new= sys.time() + print '%.4f sec' % (time_new-time_sub) + time_sub= time_new + + + print '\tloading materials and images...', + create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH) + + time_new= sys.time() + print '%.4f sec' % (time_new-time_sub) + time_sub= time_new + + + # deselect all + scn = bpy.data.scenes.active + scn.objects.selected = [] + new_objects= [] # put new objects here + + print '\tbuilding geometry...\n\tverts:%i faces:%i materials: %i smoothgroups:%i ...' % ( len(verts_loc), len(faces), len(unique_materials), len(unique_smooth_groups) ), + # Split the mesh by objects/materials, may + if SPLIT_OBJECTS or SPLIT_GROUPS: SPLIT_OB_OR_GROUP = True + else: SPLIT_OB_OR_GROUP = False + + for verts_loc_split, faces_split, unique_materials_split, dataname in split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP, SPLIT_MATERIALS): + # Create meshes from the data + create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc_split, verts_tex, faces_split, unique_materials_split, unique_material_images, unique_smooth_groups, dataname) + + axis_min= [ 1000000000]*3 + axis_max= [-1000000000]*3 + + if CLAMP_SIZE: + # Get all object bounds + for ob in new_objects: + for v in ob.getBoundBox(): + for axis, value in enumerate(v): + if axis_min[axis] > value: axis_min[axis]= value + if axis_max[axis] < value: axis_max[axis]= value + + # Scale objects + max_axis= max(axis_max[0]-axis_min[0], axis_max[1]-axis_min[1], axis_max[2]-axis_min[2]) + scale= 1.0 + + while CLAMP_SIZE < max_axis * scale: + scale= scale/10.0 + + for ob in new_objects: + ob.setSize(scale, scale, scale) + + time_new= sys.time() + + print '%.4f sec' % (time_new-time_sub) + print 'finished importing: "%s" in %.4f sec.' % (filepath, (time_new-time_main)) + + +DEBUG= True + + +def load_obj_ui(filepath, BATCH_LOAD= False): + if BPyMessages.Error_NoFile(filepath): + return + + + CREATE_SMOOTH_GROUPS= Draw.Create(0) + CREATE_FGONS= Draw.Create(1) + CREATE_EDGES= Draw.Create(1) + SPLIT_OBJECTS= Draw.Create(1) + SPLIT_GROUPS= Draw.Create(1) + SPLIT_MATERIALS= Draw.Create(1) + MORPH_TARGET= Draw.Create(0) + CLAMP_SIZE= Draw.Create(10.0) + IMAGE_SEARCH= Draw.Create(1) + + + # Get USER Options + pup_block= [\ + 'Import...',\ + ('Smooth Groups', CREATE_SMOOTH_GROUPS, 'Surround smooth groups by sharp edges'),\ + ('Create FGons', CREATE_FGONS, 'Import faces with more then 4 verts as fgons.'),\ + ('Lines', CREATE_EDGES, 'Import lines and faces with 2 verts as edges'),\ + 'Separate objects from obj...',\ + ('Object', SPLIT_OBJECTS, 'Import OBJ Objects into Blender Objects'),\ + ('Group', SPLIT_GROUPS, 'Import OBJ Groups into Blender Objects'),\ + ('Material', SPLIT_MATERIALS, 'Import each material into a seperate mesh (Avoids > 16 per mesh error)'),\ + 'Options...',\ + ('Morph Target', MORPH_TARGET, 'Keep vert and face order, disables some other options.'),\ + ('Clamp Scale:', CLAMP_SIZE, 0.0, 1000.0, 'Clamp the size to this maximum (Zero to Disable)'),\ + ('Image Search', IMAGE_SEARCH, 'Search subdirs for any assosiated images (Warning, may be slow)'),\ + ] + + if not Draw.PupBlock('Import OBJ...', pup_block): + return + + if MORPH_TARGET.val: + SPLIT_OBJECTS.val = False + SPLIT_GROUPS.val = False + SPLIT_MATERIALS.val = False + + Window.WaitCursor(1) + + if BATCH_LOAD: # load the dir + try: + files= [ f for f in os.listdir(filepath) if f.lower().endswith('.obj') ] + except: + Window.WaitCursor(0) + Draw.PupMenu('Error%t|Could not open path ' + filepath) + return + + if not files: + Window.WaitCursor(0) + Draw.PupMenu('Error%t|No files at path ' + filepath) + return + + for f in files: + scn= bpy.data.scenes.new( stripExt(f) ) + scn.makeCurrent() + + load_obj(sys.join(filepath, f),\ + CLAMP_SIZE.val,\ + CREATE_FGONS.val,\ + CREATE_SMOOTH_GROUPS.val,\ + CREATE_EDGES.val,\ + SPLIT_OBJECTS.val,\ + SPLIT_GROUPS.val,\ + SPLIT_MATERIALS.val,\ + IMAGE_SEARCH.val,\ + ) + + else: # Normal load + load_obj(filepath,\ + CLAMP_SIZE.val,\ + CREATE_FGONS.val,\ + CREATE_SMOOTH_GROUPS.val,\ + CREATE_EDGES.val,\ + SPLIT_OBJECTS.val,\ + SPLIT_GROUPS.val,\ + SPLIT_MATERIALS.val,\ + IMAGE_SEARCH.val,\ + ) + + Window.WaitCursor(0) + + +def load_obj_ui_batch(file): + load_obj_ui(file, True) + +DEBUG= False + +if __name__=='__main__' and not DEBUG: + if os and Window.GetKeyQualifiers() & Window.Qual.SHIFT: + Window.FileSelector(load_obj_ui_batch, 'Import OBJ Dir', '') + else: + Window.FileSelector(load_obj_ui, 'Import a Wavefront OBJ', '*.obj') + + +''' +# For testing compatibility +else: + # DEBUG ONLY + TIME= sys.time() + import os + print 'Searching for files' + os.system('find /fe/obj -iname "*.obj" > /tmp/temp3ds_list') + + print '...Done' + file= open('/tmp/temp3ds_list', 'r') + lines= file.readlines() + file.close() + + def between(v,a,b): + if v <= max(a,b) and v >= min(a,b): + return True + return False + + for i, _obj in enumerate(lines): + if between(i, 0,20): + _obj= _obj[:-1] + print 'Importing', _obj, '\nNUMBER', i, 'of', len(lines) + _obj_file= _obj.split('/')[-1].split('\\')[-1] + newScn= bpy.data.scenes.new(_obj_file) + newScn.makeCurrent() + load_obj(_obj, False) + + print 'TOTAL TIME: %.6f' % (sys.time() - TIME) +''' +#load_obj('/test.obj') +#load_obj('/fe/obj/mba1.obj') diff --git a/release/scripts/lightwave_export.py b/release/scripts/lightwave_export.py new file mode 100644 index 00000000000..b0fc1cc7faf --- /dev/null +++ b/release/scripts/lightwave_export.py @@ -0,0 +1,688 @@ +#!BPY + +""" +Name: 'LightWave (.lwo)...' +Blender: 243 +Group: 'Export' +Tooltip: 'Export selected meshes to LightWave File Format (.lwo)' +""" + +__author__ = "Anthony D'Agostino (Scorpius)" +__url__ = ("blender", "elysiun", +"Author's homepage, http://www.redrival.com/scorpius") +__version__ = "Part of IOSuite 0.5" + +__bpydoc__ = """\ +This script exports meshes to LightWave file format. + +LightWave is a full-featured commercial modeling and rendering +application. The lwo file format is composed of 'chunks,' is well +defined, and easy to read and write. It is similar in structure to the +trueSpace cob format. + +Usage:
+ Select meshes to be exported and run this script from "File->Export" menu. + +Supported:
+ UV Coordinates, Meshes, Materials, Material Indices, Specular +Highlights, and Vertex Colors. For added functionality, each object is +placed on its own layer. Someone added the CLIP chunk and imagename support. + +Missing:
+ Not too much, I hope! :). + +Known issues:
+ Empty objects crash has been fixed. + +Notes:
+ For compatibility reasons, it also reads lwo files in the old LW +v5.5 format. +""" + +# $Id$ +# +# +---------------------------------------------------------+ +# | Copyright (c) 2002 Anthony D'Agostino | +# | http://www.redrival.com/scorpius | +# | scorpius@netzero.com | +# | April 21, 2002 | +# | Read and write LightWave Object File Format (*.lwo) | +# +---------------------------------------------------------+ + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** + +import Blender +import struct, cStringIO, operator +import BPyMesh + +VCOL_NAME = "\251 Per-Face Vertex Colors" +DEFAULT_NAME = "\251 Blender Default" +# ============================== +# === Write LightWave Format === +# ============================== +def write(filename): + start = Blender.sys.time() + file = open(filename, "wb") + + scn = Blender.Scene.GetCurrent() + objects = list(scn.objects.context) + + if not objects: + Blender.Draw.PupMenu('Error%t|No Objects selected') + return + + try: objects.sort( key = lambda a: a.name ) + except: objects.sort(lambda a,b: cmp(a.name, b.name)) + + text = generate_text() + desc = generate_desc() + icon = "" #generate_icon() + + meshes = [] + for obj in objects: + mesh = BPyMesh.getMeshFromObject(obj, None, True, False, scn) + if mesh: + mesh.transform(obj.matrixWorld) + meshes.append(mesh) + + material_names = get_used_material_names(meshes) + tags = generate_tags(material_names) + surfs = generate_surfs(material_names) + chunks = [text, desc, icon, tags] + + meshdata = cStringIO.StringIO() + + layer_index = 0 + + for mesh in meshes: + layr = generate_layr(obj.name, layer_index) + pnts = generate_pnts(mesh) + bbox = generate_bbox(mesh) + pols = generate_pols(mesh) + ptag = generate_ptag(mesh, material_names) + clip = generate_clip(mesh, material_names) + + if mesh.faceUV: + vmad_uv = generate_vmad_uv(mesh) # per face + + if mesh.vertexColors: + #if meshtools.average_vcols: + # vmap_vc = generate_vmap_vc(mesh) # per vert + #else: + vmad_vc = generate_vmad_vc(mesh) # per face + + write_chunk(meshdata, "LAYR", layr); chunks.append(layr) + write_chunk(meshdata, "PNTS", pnts); chunks.append(pnts) + write_chunk(meshdata, "BBOX", bbox); chunks.append(bbox) + write_chunk(meshdata, "POLS", pols); chunks.append(pols) + write_chunk(meshdata, "PTAG", ptag); chunks.append(ptag) + + if mesh.vertexColors: + #if meshtools.average_vcols: + # write_chunk(meshdata, "VMAP", vmap_vc) + # chunks.append(vmap_vc) + #else: + write_chunk(meshdata, "VMAD", vmad_vc) + chunks.append(vmad_vc) + + if mesh.faceUV: + write_chunk(meshdata, "VMAD", vmad_uv) + chunks.append(vmad_uv) + write_chunk(meshdata, "CLIP", clip) + chunks.append(clip) + + layer_index += 1 + mesh.verts = None # save some ram + + for surf in surfs: + chunks.append(surf) + + write_header(file, chunks) + write_chunk(file, "ICON", icon) + write_chunk(file, "TEXT", text) + write_chunk(file, "DESC", desc) + write_chunk(file, "TAGS", tags) + file.write(meshdata.getvalue()); meshdata.close() + for surf in surfs: + write_chunk(file, "SURF", surf) + write_chunk(file, "DATE", "August 19, 2005") + + Blender.Window.DrawProgressBar(1.0, "") # clear progressbar + file.close() + print '\a\r', + print "Successfully exported %s in %.3f seconds" % (filename.split('\\')[-1].split('/')[-1], Blender.sys.time() - start) + + +# ======================================= +# === Generate Null-Terminated String === +# ======================================= +def generate_nstring(string): + if len(string)%2 == 0: # even + string += "\0\0" + else: # odd + string += "\0" + return string + +# =============================== +# === Get Used Material Names === +# =============================== +def get_used_material_names(meshes): + matnames = {} + for mesh in meshes: + if (not mesh.materials) and mesh.vertexColors: + # vcols only + matnames[VCOL_NAME] = None + + elif mesh.materials and (not mesh.vertexColors): + # materials only + for material in mesh.materials: + if material: + matnames[material.name] = None + elif (not mesh.materials) and (not mesh.vertexColors): + # neither + matnames[DEFAULT_NAME] = None + else: + # both + for material in mesh.materials: + if material: + matnames[material.name] = None + return matnames.keys() + +# ========================================= +# === Generate Tag Strings (TAGS Chunk) === +# ========================================= +def generate_tags(material_names): + if material_names: + material_names = map(generate_nstring, material_names) + tags_data = reduce(operator.add, material_names) + else: + tags_data = generate_nstring(''); + return tags_data + +# ======================== +# === Generate Surface === +# ======================== +def generate_surface(name): + #if name.find("\251 Per-") == 0: + # return generate_vcol_surf(mesh) + if name == DEFAULT_NAME: + return generate_default_surf() + else: + return generate_surf(name) + +# ====================== +# === Generate Surfs === +# ====================== +def generate_surfs(material_names): + return map(generate_surface, material_names) + +# =================================== +# === Generate Layer (LAYR Chunk) === +# =================================== +def generate_layr(name, idx): + data = cStringIO.StringIO() + data.write(struct.pack(">h", idx)) # layer number + data.write(struct.pack(">h", 0)) # flags + data.write(struct.pack(">fff", 0, 0, 0)) # pivot + data.write(generate_nstring(name)) # name + return data.getvalue() + +# =================================== +# === Generate Verts (PNTS Chunk) === +# =================================== +def generate_pnts(mesh): + data = cStringIO.StringIO() + for i, v in enumerate(mesh.verts): + if not i%100: + Blender.Window.DrawProgressBar(float(i)/len(mesh.verts), "Writing Verts") + x, y, z = v.co + data.write(struct.pack(">fff", x, z, y)) + return data.getvalue() + +# ========================================== +# === Generate Bounding Box (BBOX Chunk) === +# ========================================== +def generate_bbox(mesh): + data = cStringIO.StringIO() + # need to transform verts here + if mesh.verts: + nv = [v.co for v in mesh.verts] + xx = [ co[0] for co in nv ] + yy = [ co[1] for co in nv ] + zz = [ co[2] for co in nv ] + else: + xx = yy = zz = [0.0,] + + data.write(struct.pack(">6f", min(xx), min(zz), min(yy), max(xx), max(zz), max(yy))) + return data.getvalue() + +# ======================================== +# === Average All Vertex Colors (Fast) === +# ======================================== +''' +def average_vertexcolors(mesh): + vertexcolors = {} + vcolor_add = lambda u, v: [u[0]+v[0], u[1]+v[1], u[2]+v[2], u[3]+v[3]] + vcolor_div = lambda u, s: [u[0]/s, u[1]/s, u[2]/s, u[3]/s] + for i, f in enumerate(mesh.faces): # get all vcolors that share this vertex + if not i%100: + Blender.Window.DrawProgressBar(float(i)/len(mesh.verts), "Finding Shared VColors") + col = f.col + for j in xrange(len(f)): + index = f[j].index + color = col[j] + r,g,b = color.r, color.g, color.b + vertexcolors.setdefault(index, []).append([r,g,b,255]) + i = 0 + for index, value in vertexcolors.iteritems(): # average them + if not i%100: + Blender.Window.DrawProgressBar(float(i)/len(mesh.verts), "Averaging Vertex Colors") + vcolor = [0,0,0,0] # rgba + for v in value: + vcolor = vcolor_add(vcolor, v) + shared = len(value) + value[:] = vcolor_div(vcolor, shared) + i+=1 + return vertexcolors +''' + +# ==================================================== +# === Generate Per-Vert Vertex Colors (VMAP Chunk) === +# ==================================================== +# Blender now has all vcols per face +""" +def generate_vmap_vc(mesh): + data = cStringIO.StringIO() + data.write("RGB ") # type + data.write(struct.pack(">H", 3)) # dimension + data.write(generate_nstring("Blender's Vertex Colors")) # name + vertexcolors = average_vertexcolors(mesh) + for i in xrange(len(vertexcolors)): + try: r, g, b, a = vertexcolors[i] # has a face user + except: r, g, b, a = 255,255,255,255 + data.write(struct.pack(">H", i)) # vertex index + data.write(struct.pack(">fff", r/255.0, g/255.0, b/255.0)) + return data.getvalue() +""" + +# ==================================================== +# === Generate Per-Face Vertex Colors (VMAD Chunk) === +# ==================================================== +def generate_vmad_vc(mesh): + data = cStringIO.StringIO() + data.write("RGB ") # type + data.write(struct.pack(">H", 3)) # dimension + data.write(generate_nstring("Blender's Vertex Colors")) # name + for i, f in enumerate(mesh.faces): + if not i%100: + Blender.Window.DrawProgressBar(float(i)/len(mesh.faces), "Writing Vertex Colors") + col = f.col + f_v = f.v + for j in xrange(len(f)-1, -1, -1): # Reverse order + r,g,b, dummy = tuple(col[j]) + data.write(struct.pack(">H", f_v[j].index)) # vertex index + data.write(struct.pack(">H", i)) # face index + data.write(struct.pack(">fff", r/255.0, g/255.0, b/255.0)) + return data.getvalue() + +# ================================================ +# === Generate Per-Face UV Coords (VMAD Chunk) === +# ================================================ +def generate_vmad_uv(mesh): + data = cStringIO.StringIO() + data.write("TXUV") # type + data.write(struct.pack(">H", 2)) # dimension + data.write(generate_nstring("Blender's UV Coordinates")) # name + + for i, f in enumerate(mesh.faces): + if not i%100: + Blender.Window.DrawProgressBar(float(i)/len(mesh.faces), "Writing UV Coordinates") + + uv = f.uv + f_v = f.v + for j in xrange(len(f)-1, -1, -1): # Reverse order + U,V = uv[j] + v = f_v[j].index + data.write(struct.pack(">H", v)) # vertex index + data.write(struct.pack(">H", i)) # face index + data.write(struct.pack(">ff", U, V)) + return data.getvalue() + +# ====================================== +# === Generate Variable-Length Index === +# ====================================== +def generate_vx(index): + if index < 0xFF00: + value = struct.pack(">H", index) # 2-byte index + else: + value = struct.pack(">L", index | 0xFF000000) # 4-byte index + return value + +# =================================== +# === Generate Faces (POLS Chunk) === +# =================================== +def generate_pols(mesh): + data = cStringIO.StringIO() + data.write("FACE") # polygon type + for i,f in enumerate(mesh.faces): + if not i%100: + Blender.Window.DrawProgressBar(float(i)/len(mesh.faces), "Writing Faces") + data.write(struct.pack(">H", len(f))) # numfaceverts + numfaceverts = len(f) + f_v = f.v + for j in xrange(numfaceverts-1, -1, -1): # Reverse order + data.write(generate_vx(f_v[j].index)) + return data.getvalue() + +# ================================================= +# === Generate Polygon Tag Mapping (PTAG Chunk) === +# ================================================= +def generate_ptag(mesh, material_names): + + def surf_indicies(mat): + try: + if mat: + return material_names.index(mat.name) + except: + pass + + return 0 + + + data = cStringIO.StringIO() + data.write("SURF") # polygon tag type + mesh_materials = mesh.materials + mesh_surfindicies = [surf_indicies(mat) for mat in mesh_materials] + + try: VCOL_NAME_SURF_INDEX = material_names.index(VCOL_NAME) + except: VCOL_NAME_SURF_INDEX = 0 + + try: DEFAULT_NAME_SURF_INDEX = material_names.index(DEFAULT_NAME) + except: DEFAULT_NAME_SURF_INDEX = 0 + len_mat = len(mesh_materials) + for i, f in enumerate(mesh.faces): # numfaces + f_mat = f.mat + if f_mat >= len_mat: f_mat = 0 # Rare annoying eror + + + if not i%100: + Blender.Window.DrawProgressBar(float(i)/len(mesh.faces), "Writing Surface Indices") + + data.write(generate_vx(i)) + if (not mesh_materials) and mesh.vertexColors: # vcols only + surfidx = VCOL_NAME_SURF_INDEX + elif mesh_materials and not mesh.vertexColors: # materials only + surfidx = mesh_surfindicies[f_mat] + elif (not mesh_materials) and (not mesh.vertexColors): # neither + surfidx = DEFAULT_NAME_SURF_INDEX + else: # both + surfidx = mesh_surfindicies[f_mat] + + data.write(struct.pack(">H", surfidx)) # surface index + return data.getvalue() + +# =================================================== +# === Generate VC Surface Definition (SURF Chunk) === +# =================================================== +def generate_vcol_surf(mesh): + data = cStringIO.StringIO() + if mesh.vertexColors: + surface_name = generate_nstring(VCOL_NAME) + data.write(surface_name) + data.write("\0\0") + + data.write("COLR") + data.write(struct.pack(">H", 14)) + data.write(struct.pack(">fffH", 1, 1, 1, 0)) + + data.write("DIFF") + data.write(struct.pack(">H", 6)) + data.write(struct.pack(">fH", 0.0, 0)) + + data.write("LUMI") + data.write(struct.pack(">H", 6)) + data.write(struct.pack(">fH", 1.0, 0)) + + data.write("VCOL") + data.write(struct.pack(">H", 34)) + data.write(struct.pack(">fH4s", 1.0, 0, "RGB ")) # intensity, envelope, type + data.write(generate_nstring("Blender's Vertex Colors")) # name + + data.write("CMNT") # material comment + comment = "Vertex Colors: Exported from Blender\256 243" + comment = generate_nstring(comment) + data.write(struct.pack(">H", len(comment))) + data.write(comment) + return data.getvalue() + +# ================================================ +# === Generate Surface Definition (SURF Chunk) === +# ================================================ +def generate_surf(material_name): + data = cStringIO.StringIO() + data.write(generate_nstring(material_name)) + data.write("\0\0") + + try: + material = Blender.Material.Get(material_name) + R,G,B = material.R, material.G, material.B + ref = material.ref + emit = material.emit + spec = material.spec + hard = material.hard + + except: + material = None + + R=G=B = 1.0 + ref = 1.0 + emit = 0.0 + spec = 0.2 + hard = 0.0 + + + data.write("COLR") + data.write(struct.pack(">H", 14)) + data.write(struct.pack(">fffH", R, G, B, 0)) + + data.write("DIFF") + data.write(struct.pack(">H", 6)) + data.write(struct.pack(">fH", ref, 0)) + + data.write("LUMI") + data.write(struct.pack(">H", 6)) + data.write(struct.pack(">fH", emit, 0)) + + data.write("SPEC") + data.write(struct.pack(">H", 6)) + data.write(struct.pack(">fH", spec, 0)) + + data.write("GLOS") + data.write(struct.pack(">H", 6)) + gloss = hard / (255/2.0) + gloss = round(gloss, 1) + data.write(struct.pack(">fH", gloss, 0)) + + data.write("CMNT") # material comment + comment = material_name + ": Exported from Blender\256 243" + comment = generate_nstring(comment) + data.write(struct.pack(">H", len(comment))) + data.write(comment) + + # Check if the material contains any image maps + if material: + mtextures = material.getTextures() # Get a list of textures linked to the material + for mtex in mtextures: + if (mtex) and (mtex.tex.type == Blender.Texture.Types.IMAGE): # Check if the texture is of type "IMAGE" + data.write("BLOK") # Surface BLOK header + data.write(struct.pack(">H", 104)) # Hardcoded and ugly! Will only handle 1 image per material + + # IMAP subchunk (image map sub header) + data.write("IMAP") + data_tmp = cStringIO.StringIO() + data_tmp.write(struct.pack(">H", 0)) # Hardcoded - not sure what it represents + data_tmp.write("CHAN") + data_tmp.write(struct.pack(">H", 4)) + data_tmp.write("COLR") + data_tmp.write("OPAC") # Hardcoded texture layer opacity + data_tmp.write(struct.pack(">H", 8)) + data_tmp.write(struct.pack(">H", 0)) + data_tmp.write(struct.pack(">f", 1.0)) + data_tmp.write(struct.pack(">H", 0)) + data_tmp.write("ENAB") + data_tmp.write(struct.pack(">HH", 2, 1)) # 1 = texture layer enabled + data_tmp.write("NEGA") + data_tmp.write(struct.pack(">HH", 2, 0)) # Disable negative image (1 = invert RGB values) + data_tmp.write("AXIS") + data_tmp.write(struct.pack(">HH", 2, 1)) + data.write(struct.pack(">H", len(data_tmp.getvalue()))) + data.write(data_tmp.getvalue()) + + # IMAG subchunk + data.write("IMAG") + data.write(struct.pack(">HH", 2, 1)) + data.write("PROJ") + data.write(struct.pack(">HH", 2, 5)) # UV projection + + data.write("VMAP") + uvname = generate_nstring("Blender's UV Coordinates") + data.write(struct.pack(">H", len(uvname))) + data.write(uvname) + + return data.getvalue() + +# ============================================= +# === Generate Default Surface (SURF Chunk) === +# ============================================= +def generate_default_surf(): + data = cStringIO.StringIO() + material_name = DEFAULT_NAME + data.write(generate_nstring(material_name)) + data.write("\0\0") + + data.write("COLR") + data.write(struct.pack(">H", 14)) + data.write(struct.pack(">fffH", 1, 1, 1, 0)) + + data.write("DIFF") + data.write(struct.pack(">H", 6)) + data.write(struct.pack(">fH", 0.8, 0)) + + data.write("LUMI") + data.write(struct.pack(">H", 6)) + data.write(struct.pack(">fH", 0, 0)) + + data.write("SPEC") + data.write(struct.pack(">H", 6)) + data.write(struct.pack(">fH", 0.5, 0)) + + data.write("GLOS") + data.write(struct.pack(">H", 6)) + gloss = 50 / (255/2.0) + gloss = round(gloss, 1) + data.write(struct.pack(">fH", gloss, 0)) + + data.write("CMNT") # material comment + comment = material_name + ": Exported from Blender\256 243" + + # vals = map(chr, xrange(164,255,1)) + # keys = xrange(164,255,1) + # keys = map(lambda x: `x`, keys) + # comment = map(None, keys, vals) + # comment = reduce(operator.add, comment) + # comment = reduce(operator.add, comment) + + comment = generate_nstring(comment) + data.write(struct.pack(">H", len(comment))) + data.write(comment) + return data.getvalue() + +# ============================================ +# === Generate Object Comment (TEXT Chunk) === +# ============================================ +def generate_text(): + comment = "Lightwave Export Script for Blender by Anthony D'Agostino" + return generate_nstring(comment) + +# ============================================== +# === Generate Description Line (DESC Chunk) === +# ============================================== +def generate_desc(): + comment = "Copyright 2002 Scorpius Entertainment" + return generate_nstring(comment) + +# ================================================== +# === Generate Thumbnail Icon Image (ICON Chunk) === +# ================================================== +def generate_icon(): + data = cStringIO.StringIO() + file = open("f:/obj/radiosity/lwo2_icon.tga", "rb") # 60x60 uncompressed TGA + file.read(18) + icon_data = file.read(3600) # ? + file.close() + data.write(struct.pack(">HH", 0, 60)) + data.write(icon_data) + #print len(icon_data) + return data.getvalue() + +# =============================================== +# === Generate CLIP chunk with STIL subchunks === +# =============================================== +def generate_clip(mesh, material_names): + data = cStringIO.StringIO() + clipid = 1 + for i, material in enumerate(mesh.materials): # Run through list of materials used by mesh + if material: + mtextures = material.getTextures() # Get a list of textures linked to the material + for mtex in mtextures: + if (mtex) and (mtex.tex.type == Blender.Texture.Types.IMAGE): # Check if the texture is of type "IMAGE" + pathname = mtex.tex.image.filename # If full path is needed use filename in place of name + pathname = pathname[0:2] + pathname.replace("\\", "/")[3:] # Convert to Modo standard path + imagename = generate_nstring(pathname) + data.write(struct.pack(">L", clipid)) # CLIP sequence/id + data.write("STIL") # STIL image + data.write(struct.pack(">H", len(imagename))) # Size of image name + data.write(imagename) + clipid += 1 + return data.getvalue() + +# =================== +# === Write Chunk === +# =================== +def write_chunk(file, name, data): + file.write(name) + file.write(struct.pack(">L", len(data))) + file.write(data) + +# ============================= +# === Write LWO File Header === +# ============================= +def write_header(file, chunks): + chunk_sizes = map(len, chunks) + chunk_sizes = reduce(operator.add, chunk_sizes) + form_size = chunk_sizes + len(chunks)*8 + len("FORM") + file.write("FORM") + file.write(struct.pack(">L", form_size)) + file.write("LWO2") + +def fs_callback(filename): + if not filename.lower().endswith('.lwo'): filename += '.lwo' + write(filename) + +Blender.Window.FileSelector(fs_callback, "Export LWO", Blender.sys.makename(ext='.lwo')) diff --git a/release/scripts/lightwave_import.py b/release/scripts/lightwave_import.py new file mode 100644 index 00000000000..24e072f018a --- /dev/null +++ b/release/scripts/lightwave_import.py @@ -0,0 +1,1694 @@ +#!BPY +""" +Name: 'LightWave (.lwo)...' +Blender: 239 +Group: 'Import' +Tooltip: 'Import LightWave Object File Format' +""" + +__author__ = ["Alessandro Pirovano, Anthony D'Agostino (Scorpius)", "Campbell Barton (ideasman42)", "ZanQdo"] +__url__ = ("www.blender.org", "blenderartist.org", +"Anthony's homepage, http://www.redrival.com/scorpius", "Alessandro's homepage, http://uaraus.altervista.org") + +importername = "lwo_import 0.4.0" + +# +---------------------------------------------------------+ +# | Save your work before and after use. | +# | Please report any useful comment to: | +# | uaraus-dem@yahoo.it | +# | Thanks | +# +---------------------------------------------------------+ +# +---------------------------------------------------------+ +# | Copyright (c) 2002 Anthony D'Agostino | +# | http://www.redrival.com/scorpius | +# | scorpius@netzero.com | +# | April 21, 2002 | +# | Import Export Suite v0.5 | +# +---------------------------------------------------------+ +# | Read and write LightWave Object File Format (*.lwo) | +# +---------------------------------------------------------+ +# +---------------------------------------------------------+ +# | Alessandro Pirovano tweaked starting on March 2005 | +# | http://uaraus.altervista.org | +# +---------------------------------------------------------+ +# +---------------------------------------------------------- +# | GPL license block +# | +# | 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 +# +---------------------------------------------------------- +# +---------------------------------------------------------+ +# | Release log: | +# | 0.4.0 : Updated for blender 2.44 | +# | ZanQdo - made the mesh import the right way up | +# | Ideasman42 - Updated functions for the bew API | +# | as well as removing the text object class | +# | 0.2.2 : This code works with Blender 2.42 RC3 | +# | Added a new PolyFill function for BPYMesh's | +# | ngon() to use, checked compatibility | +# | lightwaves ngons are imported as fgons | +# | Checked compatibility against 1711 lwo files | +# | 0.2.1 : This code works with Blender 2.40 RC1 | +# | modified material mode assignment to deal with | +# | Python API modification | +# | Changed script license to GNU GPL | +# | 0.2.0: This code works with Blender 2.40a2 or up | +# | Major rewrite to deal with large meshes | +# | - 2 pass file parsing | +# | - lower memory foot###if DEBUG: print | +# | (as long as python gc allows) | +# | 2.40a2 - Removed subsurf settings patches=poly | +# | 2.40a2 - Edge generation instead of 2vert faces | +# | 0.1.16: fixed (try 2) texture offset calculations | +# | added hint on axis mapping | +# | added hint on texture blending mode | +# | added hint on texture transparency setting | +# | search images in original directory first | +# | fixed texture order application | +# | 0.1.15: added release log | +# | fixed texture offset calculations (non-UV) | +# | fixed reverting vertex order in face generation | +# | associate texture on game-engine settings | +# | vector math definitely based on mathutils | +# | search images in "Images" and "../Images" dir | +# | revised logging facility | +# | fixed subsurf texture and material mappings | +# | 0.1.14: patched missing mod_vector (not definitive) | +# | 0.1.13: first public release | +# +---------------------------------------------------------+ + +#blender related import +import Blender +import bpy + +# use for comprehensiveImageLoad +import BPyImage + +# Use this ngon function +import BPyMesh + +import BPyMessages + +#python specific modules import +try: + import struct, chunk, cStringIO +except: + struct= chunk= cStringIO= None + +### # Debuggin disabled in release. +### # do a search replace to enabe debug prints +### DEBUG = False + +# =========================================================== +# === Utility Preamble ====================================== +# =========================================================== + +textname = None +#uncomment the following line to enable logging facility to the named text object +#textname = "lwo_log" + +TXMTX = Blender.Mathutils.Matrix(\ +[1, 0, 0, 0],\ +[0, 0, 1, 0],\ +[0, 1, 0, 0],\ +[0, 0, 0, 1]) + +# =========================================================== +# === Make sure it is a string ... deal with strange chars == +# =========================================================== +def safestring(st): + myst = "" + for ll in xrange(len(st)): + if st[ll] < " ": + myst += "#" + else: + myst += st[ll] + return myst + +# =========================================================== +# === Main read functions =================================== +# =========================================================== + +# ============================= +# === Read LightWave Format === +# ============================= +def read(filename): + if BPyMessages.Error_NoFile(filename): + return + + print "This is: %s" % importername + print "Importing file:", filename + bpy.data.scenes.active.objects.selected = [] + + start = Blender.sys.time() + file = open(filename, "rb") + + editmode = Blender.Window.EditMode() # are we in edit mode? If so ... + if editmode: Blender.Window.EditMode(0) # leave edit mode before getting the mesh # === LWO header === + + try: + form_id, form_size, form_type = struct.unpack(">4s1L4s", file.read(12)) + except: + Blender.Draw.PupMenu('Error%t|This is not a lightwave file') + return + + if (form_type == "LWOB"): + read_lwob(file, filename) + elif (form_type == "LWO2"): + read_lwo2(file, filename) + else: + print "Can't read a file with the form_type: %s" % form_type + return + + Blender.Window.DrawProgressBar(1.0, "") # clear progressbar + file.close() + end = Blender.sys.time() + seconds = " in %.2f %s" % (end-start, "seconds") + if form_type == "LWO2": fmt = " (v6.0 Format)" + if form_type == "LWOB": fmt = " (v5.5 Format)" + print "Successfully imported " + filename.split('\\')[-1].split('/')[-1] + fmt + seconds + + if editmode: Blender.Window.EditMode(1) # optional, just being nice + Blender.Redraw() + +# enddef read + + +# ================================= +# === Read LightWave 5.5 format === +# ================================= +def read_lwob(file, filename): + #This function is directly derived from the LWO2 import routine + #dropping all the material analysis parts + + ###if DEBUG: print "LightWave 5.5 format" + + dir_part = Blender.sys.dirname(filename) + fname_part = Blender.sys.basename(filename) + #ask_weird = 1 + + #first initialization of data structures + defaultname = Blender.sys.splitext(fname_part)[0] + tag_list = [] #tag list: global for the whole file? + surf_list = [] #surf list: global for the whole file? + clip_list = [] #clip list: global for the whole file? + object_index = 0 + object_list = None + objspec_list = None + + #add default material for orphaned faces, if any + surf_list.append({'NAME': "_Orphans", 'g_MAT': bpy.data.materials.new("_Orphans")}) + + #pass 2: effectively generate objects + ###if DEBUG: print "Pass 1: dry import" + file.seek(0) + objspec_list = ["imported", {}, [], [], {}, {}, 0, {}, {}] + # === LWO header === + form_id, form_size, form_type = struct.unpack(">4s1L4s", file.read(12)) + if (form_type != "LWOB"): + ###if DEBUG: print "??? Inconsistent file type: %s" % form_type + return + while 1: + try: + lwochunk = chunk.Chunk(file) + except EOFError: + break + ###if DEBUG: print ' ', + if lwochunk.chunkname == "LAYR": + ###if DEBUG: print "---- LAYR", + objname = read_layr(lwochunk) + ###if DEBUG: print objname + if objspec_list != None: #create the object + create_objects(clip_list, objspec_list, surf_list) + update_material(clip_list, objspec_list, surf_list) #give it all the object + objspec_list = [objname, {}, [], [], {}, {}, 0, {}, {}] + object_index += 1 + elif lwochunk.chunkname == "PNTS": # Verts + ###if DEBUG: print "---- PNTS", + verts = read_verts(lwochunk) + objspec_list[2] = verts + elif lwochunk.chunkname == "POLS": # Faces v5.5 + ###if DEBUG: print "-------- POLS(5.5)" + faces = read_faces_5(lwochunk) + flag = 0 + #flag is 0 for regular polygon, 1 for patches (= subsurf), 2 for anything else to be ignored + if flag<2: + if objspec_list[3] != []: + #create immediately the object + create_objects(clip_list, objspec_list, surf_list) + update_material(clip_list, objspec_list, surf_list) #give it all the object + #update with new data + objspec_list = [objspec_list[0], #update name + {}, #init + objspec_list[2], #same vertexes + faces, #give it the new faces + {}, #no need to copy - filled at runtime + {}, #polygon tagging will follow + flag, #patch flag + objspec_list[7], #same uvcoords + {}] #no vmad mapping + object_index += 1 + #end if already has a face list + objspec_list[3] = faces + objname = objspec_list[0] + if objname == None: + objname = defaultname + #end if processing a valid poly type + else: # Misc Chunks + ###if DEBUG: print "---- %s: skipping (definitely!)" % lwochunk.chunkname + lwochunk.skip() + #uncomment here to log data structure as it is built + # ###if DEBUG: print object_list + #last object read + create_objects(clip_list, objspec_list, surf_list) + update_material(clip_list, objspec_list, surf_list) #give it all the object + objspec_list = None + surf_list = None + clip_list = None + + + ###if DEBUG: print "\nFound %d objects:" % object_index + +# enddef read_lwob + + +# ============================= +# === Read LightWave Format === +# ============================= +def read_lwo2(file, filename, typ="LWO2"): + + ###if DEBUG: print "LightWave 6 (and above) format" + + dir_part = Blender.sys.dirname(filename) + fname_part = Blender.sys.basename(filename) + ask_weird = 1 + + #first initialization of data structures + defaultname = Blender.sys.splitext(fname_part)[0] + tag_list = [] #tag list: global for the whole file? + surf_list = [] #surf list: global for the whole file? + clip_list = [] #clip list: global for the whole file? + object_index = 0 + object_list = None + objspec_list = None + # init value is: object_list = [[None, {}, [], [], {}, {}, 0, {}, {}]] + #0 - objname #original name + #1 - obj_dict = {TAG} #objects created + #2 - verts = [] #object vertexes + #3 - faces = [] #object faces (associations poly -> vertexes) + #4 - obj_dim_dict = {TAG} #tuples size and pos in local object coords - used for NON-UV mappings + #5 - polytag_dict = {TAG} #tag to polygons mapping + #6 - patch_flag #0 = surf; 1 = patch (subdivision surface) - it was the image list + #7 - uvcoords_dict = {name} #uvmap coordinates (mixed mode per vertex/per face) + #8 - facesuv_dict = {name} #vmad only coordinates associations poly & vertex -> uv tuples + + #pass 1: look in advance for materials + ###if DEBUG: print "Starting Pass 1: hold on tight" + while 1: + try: + lwochunk = chunk.Chunk(file) + except EOFError: + break + ###if DEBUG: print ' ', + if lwochunk.chunkname == "TAGS": # Tags + ###if DEBUG: print "---- TAGS" + tag_list.extend(read_tags(lwochunk)) + elif lwochunk.chunkname == "SURF": # surfaces + ###if DEBUG: print "---- SURF" + surf_list.append(read_surfs(lwochunk, surf_list, tag_list)) + elif lwochunk.chunkname == "CLIP": # texture images + ###if DEBUG: print "---- CLIP" + clip_list.append(read_clip(lwochunk, dir_part)) + ###if DEBUG: print "read total %s clips up to now" % len(clip_list) + else: # Misc Chunks + if ask_weird: + ckname = safestring(lwochunk.chunkname) + if "#" in ckname: + choice = Blender.Draw.PupMenu("WARNING: file could be corrupted.%t|Import anyway|Give up") + if choice != 1: + ###if DEBUG: print "---- %s: Maybe file corrupted. Terminated by user" % lwochunk.chunkname + return + ask_weird = 0 + ###if DEBUG: print "---- %s: skipping (maybe later)" % lwochunk.chunkname + lwochunk.skip() + + #add default material for orphaned faces, if any + surf_list.append({'NAME': "_Orphans", 'g_MAT': bpy.data.materials.new("_Orphans")}) + + #pass 2: effectively generate objects + ###if DEBUG: print "Pass 2: now for the hard part" + file.seek(0) + # === LWO header === + form_id, form_size, form_type = struct.unpack(">4s1L4s", file.read(12)) + if (form_type != "LWO2"): + ###if DEBUG: print "??? Inconsistent file type: %s" % form_type + return + while 1: + try: + lwochunk = chunk.Chunk(file) + except EOFError: + break + ###if DEBUG: print ' ', + if lwochunk.chunkname == "LAYR": + ###if DEBUG: print "---- LAYR" + objname = read_layr(lwochunk) + ###if DEBUG: print objname + if objspec_list != None: #create the object + create_objects(clip_list, objspec_list, surf_list) + update_material(clip_list, objspec_list, surf_list) #give it all the object + objspec_list = [objname, {}, [], [], {}, {}, 0, {}, {}] + object_index += 1 + elif lwochunk.chunkname == "PNTS": # Verts + ###if DEBUG: print "---- PNTS" + verts = read_verts(lwochunk) + objspec_list[2] = verts + elif lwochunk.chunkname == "VMAP": # MAPS (UV) + ###if DEBUG: print "---- VMAP" + #objspec_list[7] = read_vmap(objspec_list[7], len(objspec_list[2]), lwochunk) + read_vmap(objspec_list[7], len(objspec_list[2]), lwochunk) + elif lwochunk.chunkname == "VMAD": # MAPS (UV) per-face + ###if DEBUG: print "---- VMAD" + #objspec_list[7], objspec_list[8] = read_vmad(objspec_list[7], objspec_list[8], len(objspec_list[3]), len(objspec_list[2]), lwochunk) + read_vmad(objspec_list[7], objspec_list[8], len(objspec_list[3]), len(objspec_list[2]), lwochunk) + elif lwochunk.chunkname == "POLS": # Faces v6.0 + ###if DEBUG: print "-------- POLS(6)" + faces, flag = read_faces_6(lwochunk) + #flag is 0 for regular polygon, 1 for patches (= subsurf), 2 for anything else to be ignored + if flag<2: + if objspec_list[3] != []: + #create immediately the object + create_objects(clip_list, objspec_list, surf_list) + update_material(clip_list, objspec_list, surf_list) #give it all the object + #update with new data + objspec_list = [objspec_list[0], #update name + {}, #init + objspec_list[2], #same vertexes + faces, #give it the new faces + {}, #no need to copy - filled at runtime + {}, #polygon tagging will follow + flag, #patch flag + objspec_list[7], #same uvcoords + {}] #no vmad mapping + object_index += 1 + #end if already has a face list + objspec_list[3] = faces + objname = objspec_list[0] + if objname == None: + objname = defaultname + #end if processing a valid poly type + elif lwochunk.chunkname == "PTAG": # PTags + ###if DEBUG: print "---- PTAG" + polytag_dict = read_ptags(lwochunk, tag_list) + for kk, polytag_dict_val in polytag_dict.iteritems(): objspec_list[5][kk] = polytag_dict_val + else: # Misc Chunks + ###if DEBUG: print "---- %s: skipping (definitely!)" % lwochunk.chunkname + lwochunk.skip() + #uncomment here to log data structure as it is built + + #last object read + create_objects(clip_list, objspec_list, surf_list) + update_material(clip_list, objspec_list, surf_list) #give it all the object + objspec_list = None + surf_list = None + clip_list = None + + ###if DEBUG: print "\nFound %d objects:" % object_index +# enddef read_lwo2 + + + + + + +# =========================================================== +# === File reading routines ================================= +# =========================================================== +# ================== +# === Read Verts === +# ================== +def read_verts(lwochunk): + #data = cStringIO.StringIO(lwochunk.read()) + numverts = lwochunk.chunksize/12 + return [struct.unpack(">fff", lwochunk.read(12)) for i in xrange(numverts)] +# enddef read_verts + + +# ================= +# === Read Name === +# ================= +# modified to deal with odd lenght strings +def read_name(file): + name = "" + while 1: + char = file.read(1) + if char == "\0": break + else: name += char + len_name = len(name) + 1 #count the trailing zero + if len_name%2==1: + char = file.read(1) #remove zero padding to even lenght + len_name += 1 + return name, len_name + + +# ================== +# === Read Layer === +# ================== +def read_layr(lwochunk): + data = cStringIO.StringIO(lwochunk.read()) + idx, flags = struct.unpack(">hh", data.read(4)) + pivot = struct.unpack(">fff", data.read(12)) + layer_name, discard = read_name(data) + if not layer_name: layer_name = "NoName" + return layer_name +# enddef read_layr + + +# ====================== +# === Read Faces 5.5 === +# ====================== +def read_faces_5(lwochunk): + data = cStringIO.StringIO(lwochunk.read()) + faces = [] + i = 0 + while i < lwochunk.chunksize: + #if not i%1000 and my_meshtools.show_progress: + # Blender.Window.DrawProgressBar(float(i)/lwochunk.chunksize, "Reading Faces") + + numfaceverts, = struct.unpack(">H", data.read(2)) + facev = [struct.unpack(">H", data.read(2))[0] for j in xrange(numfaceverts)] + facev.reverse() + faces.append(facev) + surfaceindex, = struct.unpack(">H", data.read(2)) + if surfaceindex < 0: + ###if DEBUG: print "***Error. Referencing uncorrect surface index" + return + i += (4+numfaceverts*2) + return faces + + +# ================================== +# === Read Variable-Length Index === +# ================================== +def read_vx(data): + byte1, = struct.unpack(">B", data.read(1)) + if byte1 != 0xFF: # 2-byte index + byte2, = struct.unpack(">B", data.read(1)) + index = byte1*256 + byte2 + index_size = 2 + else: # 4-byte index + byte2, byte3, byte4 = struct.unpack(">3B", data.read(3)) + index = byte2*65536 + byte3*256 + byte4 + index_size = 4 + return index, index_size + + +# ====================== +# === Read uvmapping === +# ====================== +def read_vmap(uvcoords_dict, maxvertnum, lwochunk): + + if maxvertnum == 0: + ###if DEBUG: print "Found VMAP but no vertexes to map!" + return uvcoords_dict + data = cStringIO.StringIO(lwochunk.read()) + map_type = data.read(4) + if map_type != "TXUV": + ###if DEBUG: print "Reading VMAP: No Texture UV map Were Found. Map Type: %s" % map_type + return uvcoords_dict + dimension, = struct.unpack(">H", data.read(2)) + name, i = read_name(data) #i initialized with string lenght + zeros + ###if DEBUG: print "TXUV %d %s" % (dimension, name) + #note if there is already a VMAD it will be lost + #it is assumed that VMAD will follow the corresponding VMAP + Vector = Blender.Mathutils.Vector + try: #if uvcoords_dict.has_key(name): + my_uv_dict = uvcoords_dict[name] #update existing + except: #else: + my_uv_dict = {} #start a brand new: this could be made more smart + while (i < lwochunk.chunksize - 6): #4+2 header bytes already read + vertnum, vnum_size = read_vx(data) + uv = struct.unpack(">ff", data.read(8)) + if vertnum >= maxvertnum: + ###if DEBUG: print "Hem: more uvmap than vertexes? ignoring uv data for vertex %d" % vertnum + pass + else: + my_uv_dict[vertnum] = Vector(uv) + i += 8 + vnum_size + #end loop on uv pairs + uvcoords_dict[name] = my_uv_dict + #this is a per-vertex mapping AND the uv tuple is vertex-ordered, so faces_uv is the same as faces + #return uvcoords_dict + return + +# ======================== +# === Read uvmapping 2 === +# ======================== +def read_vmad(uvcoords_dict, facesuv_dict, maxfacenum, maxvertnum, lwochunk): + if maxvertnum == 0 or maxfacenum == 0: + ###if DEBUG: print "Found VMAD but no vertexes to map!" + return uvcoords_dict, facesuv_dict + data = cStringIO.StringIO(lwochunk.read()) + map_type = data.read(4) + if map_type != "TXUV": + ###if DEBUG: print "Reading VMAD: No Texture UV map Were Found. Map Type: %s" % map_type + return uvcoords_dict, facesuv_dict + dimension, = struct.unpack(">H", data.read(2)) + name, i = read_name(data) #i initialized with string lenght + zeros + ###if DEBUG: print "TXUV %d %s" % (dimension, name) + try: #if uvcoords_dict.has_key(name): + my_uv_dict = uvcoords_dict[name] #update existing + except: #else: + my_uv_dict = {} #start a brand new: this could be made more smart + my_facesuv_list = [] + newindex = maxvertnum + 10 #why +10? Why not? + #end variable initialization + Vector = Blender.Mathutils.Vector + while (i < lwochunk.chunksize - 6): #4+2 header bytes already read + vertnum, vnum_size = read_vx(data) + i += vnum_size + polynum, vnum_size = read_vx(data) + i += vnum_size + uv = struct.unpack(">ff", data.read(8)) + if polynum >= maxfacenum or vertnum >= maxvertnum: + ###if DEBUG: print "Hem: more uvmap than vertexes? ignorig uv data for vertex %d" % vertnum + pass + else: + my_uv_dict[newindex] = Vector(uv) + my_facesuv_list.append([polynum, vertnum, newindex]) + newindex += 1 + i += 8 + #end loop on uv pairs + uvcoords_dict[name] = my_uv_dict + facesuv_dict[name] = my_facesuv_list + ###if DEBUG: print "updated %d vertexes data" % (newindex-maxvertnum-10) + return + + +# ================= +# === Read tags === +# ================= +def read_tags(lwochunk): + data = cStringIO.StringIO(lwochunk.read()) + tag_list = [] + current_tag = "" + i = 0 + while i < lwochunk.chunksize: + char = data.read(1) + if char == "\0": + tag_list.append(current_tag) + if (len(current_tag) % 2 == 0): char = data.read(1) + current_tag = "" + else: + current_tag += char + i += 1 + ###if DEBUG: print "read %d tags, list follows: %s" % (len(tag_list), tag_list) + return tag_list + + +# ================== +# === Read Ptags === +# ================== +def read_ptags(lwochunk, tag_list): + data = cStringIO.StringIO(lwochunk.read()) + polygon_type = data.read(4) + if polygon_type != "SURF": + ###if DEBUG: print "No Surf Were Found. Polygon Type: %s" % polygon_type + return {} + ptag_dict = {} + i = 0 + while(i < lwochunk.chunksize-4): #4 bytes polygon type already read + #if not i%1000 and my_meshtools.show_progress: + # Blender.Window.DrawProgressBar(float(i)/lwochunk.chunksize, "Reading PTAGS") + poln, poln_size = read_vx(data) + i += poln_size + tag_index, = struct.unpack(">H", data.read(2)) + if tag_index > (len(tag_list)): + ###if DEBUG: print "Reading PTAG: Surf belonging to undefined TAG: %d. Skipping" % tag_index + return {} + i += 2 + tag_key = tag_list[tag_index] + try: + ptag_dict[tag_list[tag_index]].append(poln) + except: #if not(ptag_dict.has_key(tag_key)): + ptag_dict[tag_list[tag_index]] = [poln] + + ###if DEBUG: for i, ptag_dict_val in ptag_dict.iteritems(): print "read %d polygons belonging to TAG %s" % (len(ptag_dict_val ), i) + return ptag_dict + + + +# ================== +# === Read Clips === +# ================== +def read_clip(lwochunk, dir_part): +# img, IMG, g_IMG refers to blender image objects +# ima, IMAG, g_IMAG refers to clip dictionary 'ID' entries: refer to blok and surf + clip_dict = {} + data = cStringIO.StringIO(lwochunk.read()) + image_index, = struct.unpack(">L", data.read(4)) + clip_dict['ID'] = image_index + i = 4 + while(i < lwochunk.chunksize): + subchunkname, = struct.unpack("4s", data.read(4)) + subchunklen, = struct.unpack(">H", data.read(2)) + if subchunkname == "STIL": + ###if DEBUG: print "-------- STIL" + clip_name, k = read_name(data) + #now split text independently from platform + #depend on the system where image was saved. NOT the one where the script is run + no_sep = "\\" + if Blender.sys.sep == no_sep: no_sep ="/" + if (no_sep in clip_name): + clip_name = clip_name.replace(no_sep, Blender.sys.sep) + short_name = Blender.sys.basename(clip_name) + if clip_name == "" or short_name == "": + ###if DEBUG: print "Reading CLIP: Empty clip name not allowed. Skipping" + discard = data.read(subchunklen-k) + clip_dict['NAME'] = clip_name + clip_dict['BASENAME'] = short_name + elif subchunkname == "XREF": #cross reference another image + ###if DEBUG: print "-------- XREF" + image_index, = struct.unpack(">L", data.read(4)) + clip_name, k = read_name(data) + clip_dict['NAME'] = clip_name + clip_dict['XREF'] = image_index + elif subchunkname == "NEGA": #negate texture effect + ###if DEBUG: print "-------- NEGA" + n, = struct.unpack(">H", data.read(2)) + clip_dict['NEGA'] = n + else: # Misc Chunks + ###if DEBUG: print "-------- CLIP:%s: skipping" % subchunkname + discard = data.read(subchunklen) + i = i + 6 + subchunklen + #end loop on surf chunks + ###if DEBUG: print "read image:%s" % clip_dict + if 'XREF' in clip_dict: # has_key + ###if DEBUG: print "Cross-reference: no image pre-allocated." + return clip_dict + #look for images + #img = load_image("",clip_dict['NAME']) + NAME= BASENAME= None + + try: + NAME= clip_dict['NAME'] + BASENAME= clip_dict['BASENAME'] + except: + clip_dict['g_IMG'] = None + return + # ###if DEBUG: print 'test', NAME, BASENAME + img = BPyImage.comprehensiveImageLoad(NAME, dir_part, PLACE_HOLDER= False, RECURSIVE=False) + if not img: + ###if DEBUG: print "***No image %s found: trying LWO file subdir" % NAME + img = BPyImage.comprehensiveImageLoad(BASENAME, dir_part, PLACE_HOLDER= False, RECURSIVE=False) + + ###if DEBUG: if not img: print "***No image %s found: giving up" % BASENAME + #lucky we are: we have an image + ###if DEBUG: print "Image pre-allocated." + clip_dict['g_IMG'] = img + + return clip_dict + + +# =========================== +# === Read Surfaces Block === +# =========================== +def read_surfblok(subchunkdata): + lenght = len(subchunkdata) + my_dict = {} + my_uvname = "" + data = cStringIO.StringIO(subchunkdata) + ############################################################## + # blok header sub-chunk + ############################################################## + subchunkname, = struct.unpack("4s", data.read(4)) + subchunklen, = struct.unpack(">h", data.read(2)) + accumulate_i = subchunklen + 6 + if subchunkname != 'IMAP': + ###if DEBUG: print "---------- SURF: BLOK: %s: block aborting" % subchunkname + return {}, "" + ###if DEBUG: print "---------- IMAP" + ordinal, i = read_name(data) + my_dict['ORD'] = ordinal + #my_dict['g_ORD'] = -1 + my_dict['ENAB'] = True + while(i < subchunklen): # ---------left 6------------------------- loop on header parameters + sub2chunkname, = struct.unpack("4s", data.read(4)) + sub2chunklen, = struct.unpack(">h", data.read(2)) + i = i + 6 + sub2chunklen + if sub2chunkname == "CHAN": + ###if DEBUG: print "------------ CHAN" + sub2chunkname, = struct.unpack("4s", data.read(4)) + my_dict['CHAN'] = sub2chunkname + sub2chunklen -= 4 + elif sub2chunkname == "ENAB": #only present if is to be disabled + ###if DEBUG: print "------------ ENAB" + ena, = struct.unpack(">h", data.read(2)) + my_dict['ENAB'] = ena + sub2chunklen -= 2 + elif sub2chunkname == "NEGA": #only present if is to be enabled + ###if DEBUG: print "------------ NEGA" + ena, = struct.unpack(">h", data.read(2)) + if ena == 1: + my_dict['NEGA'] = ena + sub2chunklen -= 2 + elif sub2chunkname == "OPAC": #only present if is to be disabled + ###if DEBUG: print "------------ OPAC" + opa, = struct.unpack(">h", data.read(2)) + s, = struct.unpack(">f", data.read(4)) + envelope, env_size = read_vx(data) + my_dict['OPAC'] = opa + my_dict['OPACVAL'] = s + sub2chunklen -= 6 + elif sub2chunkname == "AXIS": + ###if DEBUG: print "------------ AXIS" + ena, = struct.unpack(">h", data.read(2)) + my_dict['DISPLAXIS'] = ena + sub2chunklen -= 2 + else: # Misc Chunks + ###if DEBUG: print "------------ SURF: BLOK: IMAP: %s: skipping" % sub2chunkname + discard = data.read(sub2chunklen) + #end loop on blok header subchunks + ############################################################## + # blok attributes sub-chunk + ############################################################## + subchunkname, = struct.unpack("4s", data.read(4)) + subchunklen, = struct.unpack(">h", data.read(2)) + accumulate_i += subchunklen + 6 + if subchunkname != 'TMAP': + ###if DEBUG: print "---------- SURF: BLOK: %s: block aborting" % subchunkname + return {}, "" + ###if DEBUG: print "---------- TMAP" + i = 0 + while(i < subchunklen): # -----------left 6----------------------- loop on header parameters + sub2chunkname, = struct.unpack("4s", data.read(4)) + sub2chunklen, = struct.unpack(">h", data.read(2)) + i = i + 6 + sub2chunklen + if sub2chunkname == "CNTR": + ###if DEBUG: print "------------ CNTR" + x, y, z = struct.unpack(">fff", data.read(12)) + envelope, env_size = read_vx(data) + my_dict['CNTR'] = [x, y, z] + sub2chunklen -= (12+env_size) + elif sub2chunkname == "SIZE": + ###if DEBUG: print "------------ SIZE" + x, y, z = struct.unpack(">fff", data.read(12)) + envelope, env_size = read_vx(data) + my_dict['SIZE'] = [x, y, z] + sub2chunklen -= (12+env_size) + elif sub2chunkname == "ROTA": + ###if DEBUG: print "------------ ROTA" + x, y, z = struct.unpack(">fff", data.read(12)) + envelope, env_size = read_vx(data) + my_dict['ROTA'] = [x, y, z] + sub2chunklen -= (12+env_size) + elif sub2chunkname == "CSYS": + ###if DEBUG: print "------------ CSYS" + ena, = struct.unpack(">h", data.read(2)) + my_dict['CSYS'] = ena + sub2chunklen -= 2 + else: # Misc Chunks + ###if DEBUG: print "------------ SURF: BLOK: TMAP: %s: skipping" % sub2chunkname + pass + if sub2chunklen > 0: + discard = data.read(sub2chunklen) + #end loop on blok attributes subchunks + ############################################################## + # ok, now other attributes without sub_chunks + ############################################################## + while(accumulate_i < lenght): # ---------------------------------- loop on header parameters: lenght has already stripped the 6 bypes header + subchunkname, = struct.unpack("4s", data.read(4)) + subchunklen, = struct.unpack(">H", data.read(2)) + accumulate_i = accumulate_i + 6 + subchunklen + if subchunkname == "PROJ": + ###if DEBUG: print "---------- PROJ" + p, = struct.unpack(">h", data.read(2)) + my_dict['PROJ'] = p + subchunklen -= 2 + elif subchunkname == "AXIS": + ###if DEBUG: print "---------- AXIS" + a, = struct.unpack(">h", data.read(2)) + my_dict['MAJAXIS'] = a + subchunklen -= 2 + elif subchunkname == "IMAG": + ###if DEBUG: print "---------- IMAG" + i, i_size = read_vx(data) + my_dict['IMAG'] = i + subchunklen -= i_size + elif subchunkname == "WRAP": + ###if DEBUG: print "---------- WRAP" + ww, wh = struct.unpack(">hh", data.read(4)) + #reduce width and height to just 1 parameter for both + my_dict['WRAP'] = max([ww,wh]) + #my_dict['WRAPWIDTH'] = ww + #my_dict['WRAPHEIGHT'] = wh + subchunklen -= 4 + elif subchunkname == "WRPW": + ###if DEBUG: print "---------- WRPW" + w, = struct.unpack(">f", data.read(4)) + my_dict['WRPW'] = w + envelope, env_size = read_vx(data) + subchunklen -= (env_size+4) + elif subchunkname == "WRPH": + ###if DEBUG: print "---------- WRPH" + w, = struct.unpack(">f", data.read(4)) + my_dict['WRPH'] = w + envelope, env_size = read_vx(data) + subchunklen -= (env_size+4) + elif subchunkname == "VMAP": + ###if DEBUG: print "---------- VMAP" + vmp, i = read_name(data) + my_dict['VMAP'] = vmp + my_uvname = vmp + subchunklen -= i + else: # Misc Chunks + ###if DEBUG: print "---------- SURF: BLOK: %s: skipping" % subchunkname + pass + if subchunklen > 0: + discard = data.read(subchunklen) + #end loop on blok subchunks + return my_dict, my_uvname + + +# ===================== +# === Read Surfaces === +# ===================== +def read_surfs(lwochunk, surf_list, tag_list): + my_dict = {} + data = cStringIO.StringIO(lwochunk.read()) + surf_name, i = read_name(data) + parent_name, j = read_name(data) + i += j + if (surf_name == "") or not(surf_name in tag_list): + ###if DEBUG: print "Reading SURF: Actually empty surf name not allowed. Skipping" + return {} + if (parent_name != ""): + parent_index = [x['NAME'] for x in surf_list].count(parent_name) + if parent_index >0: + my_dict = surf_list[parent_index-1] + my_dict['NAME'] = surf_name + ###if DEBUG: print "Surface data for TAG %s" % surf_name + while(i < lwochunk.chunksize): + subchunkname, = struct.unpack("4s", data.read(4)) + subchunklen, = struct.unpack(">H", data.read(2)) + i = i + 6 + subchunklen #6 bytes subchunk header + if subchunkname == "COLR": #color: mapped on color + ###if DEBUG: print "-------- COLR" + r, g, b = struct.unpack(">fff", data.read(12)) + envelope, env_size = read_vx(data) + my_dict['COLR'] = [r, g, b] + subchunklen -= (12+env_size) + elif subchunkname == "DIFF": #diffusion: mapped on reflection (diffuse shader) + ###if DEBUG: print "-------- DIFF" + s, = struct.unpack(">f", data.read(4)) + envelope, env_size = read_vx(data) + my_dict['DIFF'] = s + subchunklen -= (4+env_size) + elif subchunkname == "SPEC": #specularity: mapped to specularity (spec shader) + ###if DEBUG: print "-------- SPEC" + s, = struct.unpack(">f", data.read(4)) + envelope, env_size = read_vx(data) + my_dict['SPEC'] = s + subchunklen -= (4+env_size) + elif subchunkname == "REFL": #reflection: mapped on raymirror + ###if DEBUG: print "-------- REFL" + s, = struct.unpack(">f", data.read(4)) + envelope, env_size = read_vx(data) + my_dict['REFL'] = s + subchunklen -= (4+env_size) + elif subchunkname == "TRNL": #translucency: mapped on same param + ###if DEBUG: print "-------- TRNL" + s, = struct.unpack(">f", data.read(4)) + envelope, env_size = read_vx(data) + my_dict['TRNL'] = s + subchunklen -= (4+env_size) + elif subchunkname == "GLOS": #glossiness: mapped on specularity hardness (spec shader) + ###if DEBUG: print "-------- GLOS" + s, = struct.unpack(">f", data.read(4)) + envelope, env_size = read_vx(data) + my_dict['GLOS'] = s + subchunklen -= (4+env_size) + elif subchunkname == "TRAN": #transparency: inverted and mapped on alpha channel + ###if DEBUG: print "-------- TRAN" + s, = struct.unpack(">f", data.read(4)) + envelope, env_size = read_vx(data) + my_dict['TRAN'] = s + subchunklen -= (4+env_size) + elif subchunkname == "LUMI": #luminosity: mapped on emit channel + ###if DEBUG: print "-------- LUMI" + s, = struct.unpack(">f", data.read(4)) + envelope, env_size = read_vx(data) + my_dict['LUMI'] = s + subchunklen -= (4+env_size) + elif subchunkname == "GVAL": #glow: mapped on add channel + ###if DEBUG: print "-------- GVAL" + s, = struct.unpack(">f", data.read(4)) + envelope, env_size = read_vx(data) + my_dict['GVAL'] = s + subchunklen -= (4+env_size) + elif subchunkname == "SMAN": #smoothing angle + ###if DEBUG: print "-------- SMAN" + s, = struct.unpack(">f", data.read(4)) + my_dict['SMAN'] = s + subchunklen -= 4 + elif subchunkname == "SIDE": #double sided? + ###if DEBUG: print "-------- SIDE" #if 1 side do not define key + s, = struct.unpack(">H", data.read(2)) + if s == 3: + my_dict['SIDE'] = s + subchunklen -= 2 + elif subchunkname == "RIND": #Refraction: mapped on IOR + ###if DEBUG: print "-------- RIND" + s, = struct.unpack(">f", data.read(4)) + envelope, env_size = read_vx(data) + my_dict['RIND'] = s + subchunklen -= (4+env_size) + elif subchunkname == "BLOK": #blocks + ###if DEBUG: print "-------- BLOK" + rr, uvname = read_surfblok(data.read(subchunklen)) + #paranoia setting: preventing adding an empty dict + if rr: # != {} + try: + my_dict['BLOK'].append(rr) + except: + my_dict['BLOK'] = [rr] + + if uvname: # != "": + my_dict['UVNAME'] = uvname #theoretically there could be a number of them: only one used per surf + # all are dictionaries - so testing keys + if not('g_IMAG' in my_dict) and ('CHAN' in rr) and ('OPAC' in rr) and ('IMAG' in rr): + if (rr['CHAN'] == 'COLR') and (rr['OPAC'] == 0): + my_dict['g_IMAG'] = rr['IMAG'] #do not set anything, just save image object for later assignment + subchunklen = 0 #force ending + else: # Misc Chunks + pass + ###if DEBUG: print "-------- SURF:%s: skipping" % subchunkname + if subchunklen > 0: + discard = data.read(subchunklen) + #end loop on surf chunks + try:#if my_dict.has_key('BLOK'): + my_dict['BLOK'].reverse() #texture applied in reverse order with respect to reading from lwo + except: + pass + + #uncomment this if material pre-allocated by read_surf + my_dict['g_MAT'] = bpy.data.materials.new(my_dict['NAME']) + ###if DEBUG: print "-> Material pre-allocated." + return my_dict + +# ========================= +# === Recalculate Faces === +# ========================= + +def get_uvface(complete_list, facenum): + # extract from the complete list only vertexes of the desired polygon + ''' + my_facelist = [] + for elem in complete_list: + if elem[0] == facenum: + my_facelist.append(elem) + return my_facelist + ''' + return [elem for elem in complete_list if elem[0] == facenum] + +def get_newindex(polygon_list, vertnum): + # extract from the polygon list the new index associated to a vertex + if not polygon_list: # == [] + return -1 + for elem in polygon_list: + if elem[1] == vertnum: + return elem[2] + # ###if DEBUG: print "WARNING: expected vertex %s for polygon %s. Polygon_list dump follows" % (vertnum, polygon_list[0][0]) + # ###if DEBUG: print polygon_list + return -1 + +def get_surf(surf_list, cur_tag): + for elem in surf_list: # elem can be None + if elem and elem['NAME'] == cur_tag: + return elem + return {} + + + +# ==================================== +# === Modified Create Blender Mesh === +# ==================================== +def my_create_mesh(clip_list, surf, objspec_list, current_facelist, objname, not_used_faces): + #take the needed faces and update the not-used face list + complete_vertlist = objspec_list[2] + complete_facelist = objspec_list[3] + uvcoords_dict = objspec_list[7] + facesuv_dict = objspec_list[8] + vertex_map = {} #implementation as dict + cur_ptag_faces = [] + cur_ptag_faces_indexes = [] + maxface = len(complete_facelist) + for ff in current_facelist: + if ff >= maxface: + ###if DEBUG: print "Non existent face addressed: Giving up with this object" + return None, not_used_faces #return the created object + cur_face = complete_facelist[ff] + cur_ptag_faces_indexes.append(ff) + if not_used_faces: # != [] + not_used_faces[ff] = -1 + for vv in cur_face: vertex_map[vv] = 1 + #end loop on faces + store_edge = 0 + + scn= bpy.data.scenes.active + msh = bpy.data.meshes.new() + obj = scn.objects.new(msh) + + mat = None + try: + msh.materials = [surf['g_MAT']] + except: + pass + + msh.mode |= Blender.Mesh.Modes.AUTOSMOOTH #smooth it anyway + if 'SMAN' in surf: # has_key + #not allowed mixed mode mesh (all the mesh is smoothed and all with the same angle) + #only one smoothing angle will be active! => take the max one + msh.degr = min(80, int(surf['SMAN']/3.1415926535897932384626433832795*180.0)) #lwo in radians - blender in degrees + + try: + img= lookup_imag(clip_list, surf['g_IMAG'])['g_IMG'] + except: + img= None + + #uv_flag = ((surf.has_key('UVNAME')) and (uvcoords_dict.has_key(surf['UVNAME'])) and (img != None)) + uv_flag = (('UVNAME' in surf) and (surf['UVNAME'] in uvcoords_dict)) + + ###if DEBUG: print "\n#===================================================================#" + ###if DEBUG: print "Processing Object: %s" % objname + ###if DEBUG: print "#===================================================================#" + + if uv_flag: + msh.verts.extend([(0.0,0.0,0.0),]) + j = 1 + else: + j = 0 + + def tmp_get_vert(k, i): + vertex_map[k] = i+j # j is the dummy vert + # ###if DEBUG: print complete_vertlist[i] + return complete_vertlist[k] + + + + msh.verts.extend([tmp_get_vert(k, i) for i, k in enumerate(vertex_map.iterkeys())]) + msh.transform(TXMTX) # faster then applying while reading. + #end sweep over vertexes + + #append faces + FACE_TEX= Blender.Mesh.FaceModes.TEX + FACE_ALPHA= Blender.Mesh.FaceTranspModes.ALPHA + EDGE_DRAW_FLAG= Blender.Mesh.EdgeFlags.EDGEDRAW | Blender.Mesh.EdgeFlags.EDGERENDER + + + edges = [] + face_data = [] # [(indicies, material, uvs, image), ] + face_uvs = [] + edges_fgon = [] + + if uv_flag: + uvcoords_dict_context = uvcoords_dict[surf['UVNAME']] + try: current_uvdict = facesuv_dict[surf['UVNAME']] + except: current_uvdict = None + + default_uv = Blender.Mathutils.Vector(0,0) + def tmp_get_face_uvs(cur_face, i): + uvs = [] + if current_uvdict: + uvface = get_uvface(current_uvdict,i) + for vi in cur_face: + ni = get_newindex(uvface, vi) + if ni == -1: ni = vi + + try: + uvs.append(uvcoords_dict_context[ ni ]) + except: + ###if DEBUG: print '\tWarning, Corrupt UVs' + uvs.append(default_uv) + else: + for vi in cur_face: + try: + uvs.append(uvcoords_dict_context[ vi ]) + except: + ###if DEBUG: print '\tWarning, Corrupt UVs' + uvs.append(default_uv) + + return uvs + cur_face + for i in cur_ptag_faces_indexes: + cur_face = complete_facelist[i] + numfaceverts = len(cur_face) + + if numfaceverts == 2: edges.append((vertex_map[cur_face[0]], vertex_map[cur_face[1]])) + elif numfaceverts == 3 or numfaceverts == 4: + rev_face = [__i for __i in reversed(cur_face)] + face_data.append( [vertex_map[j] for j in rev_face] ) + if uv_flag: face_uvs.append(tmp_get_face_uvs(rev_face, i)) + elif numfaceverts > 4: + meta_faces= BPyMesh.ngon(complete_vertlist, cur_face, PREF_FIX_LOOPS= True) + edge_face_count = {} + for mf in meta_faces: + # These will always be tri's since they are scanfill faces + mf = cur_face[mf[2]], cur_face[mf[1]], cur_face[mf[0]] + face_data.append( [vertex_map[j] for j in mf] ) + + if uv_flag: face_uvs.append(tmp_get_face_uvs(mf, i)) + + #if USE_FGON: + if len(meta_faces) > 1: + mf = face_data[-1] # reuse mf + for j in xrange(3): + v1= mf[j] + v2= mf[j-1] + if v1!=v2: + if v1>v2: + v2,v1= v1,v2 + try: + edge_face_count[v1,v2]+= 1 + except: + edge_face_count[v1,v2]= 0 + + + + if edge_face_count: + edges_fgon.extend( [vert_key for vert_key, count in edge_face_count.iteritems() if count] ) + + if edges: + msh.edges.extend(edges) + + face_mapping_removed = msh.faces.extend(face_data, indexList=True) + if 'TRAN' in surf or (mat and mat.alpha<1.0): # incase mat is null + transp_flag = True + else: + transp_flag = False + + if uv_flag: + msh.faceUV = True + msh_faces= msh.faces + for i, uvs in enumerate(face_uvs): + i_mapped = face_mapping_removed[i] + if i_mapped != None: + f = msh_faces[i_mapped] + f.uv = uvs + if img: + f.image = img + + if transp_flag: f.transp |= FACE_ALPHA + + if edges_fgon: + msh_edges = msh.edges + FGON= Blender.Mesh.EdgeFlags.FGON + edges_fgon = msh.findEdges( edges_fgon ) + if type(edges_fgon) != list: edges_fgon = [edges_fgon] + for ed in edges_fgon: + if ed!=None: + msh_edges[ed].flag |= FGON + + if not(uv_flag): #clear eventual UV data + msh.faceUV = False + + if uv_flag: + msh.verts.delete([0,]) + + return obj, not_used_faces #return the created object + + +# ============================================ +# === Set Subsurf attributes on given mesh === +# ============================================ +def set_subsurf(obj): + mods = obj.modifiers # get the object's modifiers + mod = mods.append(Blender.Modifier.Type.SUBSURF) # add a new subsurf modifier + mod[Blender.Modifier.Settings.LEVELS] = 2 # set subsurf subdivision levels to 2 + mod[Blender.Modifier.Settings.RENDLEVELS] = 2 # set subsurf rendertime subdivision levels to 2 + obj.makeDisplayList() + + +# ================================= +# === object size and dimension === +# ================================= +def obj_size_pos(obj): + bbox = obj.getBoundBox() + bbox_min = map(lambda *row: min(row), *bbox) #transpose & get min + bbox_max = map(lambda *row: max(row), *bbox) #transpose & get max + obj_size = (bbox_max[0]-bbox_min[0], bbox_max[1]-bbox_min[1], bbox_max[2]-bbox_min[2]) + obj_pos = ( (bbox_max[0]+bbox_min[0]) / 2, (bbox_max[1]+bbox_min[1]) / 2, (bbox_max[2]+bbox_min[2]) / 2) + return (obj_size, obj_pos) + + +# ========================= +# === Create the object === +# ========================= +def create_objects(clip_list, objspec_list, surf_list): + nf = len(objspec_list[3]) + not_used_faces = range(nf) + ptag_dict = objspec_list[5] + obj_dict = {} #links tag names to object, used for material assignments + obj_dim_dict = {} + obj_list = [] #have it handy for parent association + middlechar = "+" + endchar = "" + if (objspec_list[6] == 1): + middlechar = endchar = "#" + for cur_tag, ptag_dict_val in ptag_dict.iteritems(): + if ptag_dict_val != []: + cur_surf = get_surf(surf_list, cur_tag) + cur_obj, not_used_faces= my_create_mesh(clip_list, cur_surf, objspec_list, ptag_dict_val, objspec_list[0][:9]+middlechar+cur_tag[:9], not_used_faces) + # Works now with new modifiers + if objspec_list[6] == 1: + set_subsurf(cur_obj) + if cur_obj: # != None + obj_dict[cur_tag] = cur_obj + obj_dim_dict[cur_tag] = obj_size_pos(cur_obj) + obj_list.append(cur_obj) + #end loop on current group + #and what if some faces not used in any named PTAG? get rid of unused faces + orphans = [] + for tt in not_used_faces: + if tt > -1: orphans.append(tt) + #end sweep on unused face list + not_used_faces = None + if orphans: # != [] + cur_surf = get_surf(surf_list, "_Orphans") + cur_obj, not_used_faces = my_create_mesh(clip_list, cur_surf, objspec_list, orphans, objspec_list[0][:9]+middlechar+"Orphans", []) + if cur_obj: # != None + if objspec_list[6] == 1: + set_subsurf(cur_obj) + obj_dict["_Orphans"] = cur_obj + obj_dim_dict["_Orphans"] = obj_size_pos(cur_obj) + obj_list.append(cur_obj) + objspec_list[1]= obj_dict + objspec_list[4]= obj_dim_dict + + return + + + +# =========================================== +# === Lookup for image index in clip_list === +# =========================================== +def lookup_imag(clip_list, ima_id): + for ii in clip_list: + if ii and ii['ID'] == ima_id: + if 'XREF' in ii: # has_key + #cross reference - recursively look for images + return lookup_imag(clip_list, ii['XREF']) + else: + return ii + return None + + +# =================================================== +# === Create and assign image mapping to material === +# =================================================== +def create_blok(surf, mat, clip_list, obj_size, obj_pos): + + def output_size_ofs(size, pos, blok): + #just automate repetitive task + # 0 == X, 1 == Y, 2 == Z + size_default = [1.0] * 3 + size2 = [1.0] * 3 + ofs_default = [0.0] * 3 + offset = [1.0] * 3 + axis_default = [Blender.Texture.Proj.X, Blender.Texture.Proj.Y, Blender.Texture.Proj.Z] + axis = [1.0] * 3 + c_map_txt = [" X--", " -Y-", " --Z"] + c_map = [0,1,2] # standard, good for Z axis projection + if blok['MAJAXIS'] == 0: + c_map = [1,2,0] # X axis projection + if blok['MAJAXIS'] == 2: + c_map = [0,2,1] # Y axis projection + + ###if DEBUG: print "!!!axis mapping:" + #this is the smart way + ###if DEBUG: for mp in c_map: print c_map_txt[mp] + + if blok['SIZE'][0] != 0.0: #paranoia controls + size_default[0] = (size[0]/blok['SIZE'][0]) + ofs_default[0] = ((blok['CNTR'][0]-pos[0])/blok['SIZE'][0]) + if blok['SIZE'][1] != 0.0: + size_default[2] = (size[2]/blok['SIZE'][1]) + ofs_default[2] = ((blok['CNTR'][1]-pos[2])/blok['SIZE'][1]) + if blok['SIZE'][2] != 0.0: + size_default[1] = (size[1]/blok['SIZE'][2]) + ofs_default[1] = ((blok['CNTR'][2]-pos[1])/blok['SIZE'][2]) + + for mp in xrange(3): + axis[mp] = axis_default[c_map[mp]] + size2[mp] = size_default[c_map[mp]] + offset[mp] = ofs_default[c_map[mp]] + if offset[mp]>10.0: offset[mp]-10.0 + if offset[mp]<-10.0: offset[mp]+10.0 +# size = [size_default[mp] for mp in c_map] + + ###if DEBUG: print "!!!texture size and offsets:" + ###if DEBUG: print " sizeX = %.5f; sizeY = %.5f; sizeZ = %.5f" % (size[0],size[1],size[2]) + ###if DEBUG: print " ofsX = %.5f; ofsY = %.5f; ofsZ = %.5f" % (offset[0],offset[1],offset[2]) + return axis, size2, offset + + ti = 0 + alphaflag = 0 #switched to 1 if some tex in this block is using alpha + lastimag = 0 #experimental .... + for blok in surf['BLOK']: + ###if DEBUG: print "#...................................................................#" + ###if DEBUG: print "# Processing texture block no.%s for surf %s" % (ti,surf['NAME']) + ###if DEBUG: print "#...................................................................#" + # tobj.pdict (blok) + if ti > 9: break #only 8 channels 0..7 allowed for texture mapping + #if not blok['ENAB']: + # ###if DEBUG: print "***Image is not ENABled! Quitting this block" + # break + if not('IMAG' in blok): # has_key + ###if DEBUG: print "***No IMAGE for this block? Quitting" + break #extract out the image index within the clip_list + if blok['IMAG'] == 0: blok['IMAG'] = lastimag #experimental .... + ###if DEBUG: print "looking for image number %d" % blok['IMAG'] + ima = lookup_imag(clip_list, blok['IMAG']) + if ima == None: + ###if DEBUG: print "***Block index image not within CLIP list? Quitting Block" + break #safety check (paranoia setting) + img = ima['g_IMG'] + lastimag = blok['IMAG'] #experimental .... + if img == None: + ###if DEBUG: print "***Failed to pre-allocate image %s found: giving up" % ima['BASENAME'] + break + tname = str(ima['ID']) + if blok['ENAB']: + tname += "+" + else: + tname += "x" #let's signal when should not be enabled + if 'CHAN' in blok: # has_key + tname += blok['CHAN'] + newtex = bpy.data.textures.new(tname) + newtex.setType('Image') # make it anu image texture + newtex.image = img + #how does it extends beyond borders + if 'WRAP' in blok: # has_key + if (blok['WRAP'] == 3) or (blok['WRAP'] == 2): + newtex.setExtend('Extend') + elif (blok['WRAP'] == 1): + newtex.setExtend('Repeat') + elif (blok['WRAP'] == 0): + newtex.setExtend('Clip') + ###if DEBUG: print "generated texture %s" % tname + + #MapTo is determined by CHAN parameter + #assign some defaults + colfac = 1.0 + dvar = 1.0 + norfac = 0.5 + nega = False + mapflag = Blender.Texture.MapTo.COL #default to color + maptype = Blender.Texture.Mappings.FLAT + if 'CHAN' in blok: # has_key + if blok['CHAN'] == 'COLR' and 'OPACVAL' in blok: # has_key + colfac = blok['OPACVAL'] + # Blender needs this to be clamped + colfac = max(0.0, min(1.0, colfac)) + ###if DEBUG: print "!!!Set Texture -> MapTo -> Col = %.3f" % colfac + if blok['CHAN'] == 'BUMP': + mapflag = Blender.Texture.MapTo.NOR + if 'OPACVAL' in blok: norfac = blok['OPACVAL'] # has_key + ###if DEBUG: print "!!!Set Texture -> MapTo -> Nor = %.3f" % norfac + if blok['CHAN'] == 'LUMI': + mapflag = Blender.Texture.MapTo.EMIT + if 'OPACVAL' in blok: dvar = blok['OPACVAL'] # has_key + ###if DEBUG: print "!!!Set Texture -> MapTo -> DVar = %.3f" % dvar + if blok['CHAN'] == 'DIFF': + mapflag = Blender.Texture.MapTo.REF + if 'OPACVAL' in blok: dvar = blok['OPACVAL'] # has_key + ###if DEBUG: print "!!!Set Texture -> MapTo -> DVar = %.3f" % dvar + if blok['CHAN'] == 'SPEC': + mapflag = Blender.Texture.MapTo.SPEC + if 'OPACVAL' in blok: dvar = blok['OPACVAL'] # has_key + ###if DEBUG: print "!!!Set Texture -> MapTo -> DVar = %.3f" % dvar + if blok['CHAN'] == 'TRAN': + mapflag = Blender.Texture.MapTo.ALPHA + if 'OPACVAL' in blok: dvar = blok['OPACVAL'] # has_key + ###if DEBUG: print "!!!Set Texture -> MapTo -> DVar = %.3f" % dvar + alphaflag = 1 + nega = True + if 'NEGA' in blok: # has_key + ###if DEBUG: print "!!!Watch-out: effect of this texture channel must be INVERTED!" + nega = not nega + + blendmode_list = ['Mix', + 'Subtractive', + 'Difference', + 'Multiply', + 'Divide', + 'Mix with calculated alpha layer and stencil flag', + 'Texture Displacement', + 'Additive'] + set_blendmode = 7 #default additive + if 'OPAC' in blok: # has_key + set_blendmode = blok['OPAC'] + if set_blendmode == 5: #transparency + newtex.imageFlags |= Blender.Texture.ImageFlags.CALCALPHA + if nega: newtex.flags |= Blender.Texture.Flags.NEGALPHA + ###if DEBUG: print "!!!Set Texture -> MapTo -> Blending Mode = %s" % blendmode_list[set_blendmode] + + #the TexCo flag is determined by PROJ parameter + axis = [Blender.Texture.Proj.X, Blender.Texture.Proj.Y, Blender.Texture.Proj.Z] + size = [1.0] * 3 + ofs = [0.0] * 3 + if 'PROJ' in blok: # has_key + if blok['PROJ'] == 0: #0 - Planar + ###if DEBUG: print "!!!Flat projection" + coordflag = Blender.Texture.TexCo.ORCO + maptype = Blender.Texture.Mappings.FLAT + elif blok['PROJ'] == 1: #1 - Cylindrical + ###if DEBUG: print "!!!Cylindrical projection" + coordflag = Blender.Texture.TexCo.ORCO + maptype = Blender.Texture.Mappings.TUBE + elif blok['PROJ'] == 2: #2 - Spherical + ###if DEBUG: print "!!!Spherical projection" + coordflag = Blender.Texture.TexCo.ORCO + maptype = Blender.Texture.Mappings.SPHERE + elif blok['PROJ'] == 3: #3 - Cubic + ###if DEBUG: print "!!!Cubic projection" + coordflag = Blender.Texture.TexCo.ORCO + maptype = Blender.Texture.Mappings.CUBE + elif blok['PROJ'] == 4: #4 - Front Projection + ###if DEBUG: print "!!!Front projection" + coordflag = Blender.Texture.TexCo.ORCO + maptype = Blender.Texture.Mappings.FLAT # ??? could it be a FLAT with some other TexCo type? + elif blok['PROJ'] == 5: #5 - UV + ###if DEBUG: print "UVMapped" + coordflag = Blender.Texture.TexCo.UV + maptype = Blender.Texture.Mappings.FLAT #in case of UV default to FLAT mapping => effectively not used + if blok['PROJ'] != 5: #This holds for any projection map except UV + axis, size, ofs = output_size_ofs(obj_size, obj_pos, blok) + + # Clamp ofs and size else blender will raise an error + for ii in xrange(3): + ofs[ii]= min(10.0, max(-10, ofs[ii])) + size[ii]= min(100, max(-100, size[ii])) + + mat.setTexture(ti, newtex, coordflag, mapflag) + current_mtex = mat.getTextures()[ti] + current_mtex.mapping = maptype + current_mtex.colfac = colfac + current_mtex.dvar = dvar + current_mtex.norfac = norfac + current_mtex.neg = nega + current_mtex.xproj = axis[0] + current_mtex.yproj = axis[1] + current_mtex.zproj = axis[2] + current_mtex.size = tuple(size) + current_mtex.ofs = tuple(ofs) + if (set_blendmode == 5): #transparency + current_mtex.stencil = not (nega) + + ti += 1 + #end loop over bloks + return alphaflag + + +# ======================================== +# === Create and assign a new material === +# ======================================== +#def update_material(surf_list, ptag_dict, obj, clip_list, uv_dict, dir_part): +def update_material(clip_list, objspec, surf_list): + if (surf_list == []) or (objspec[5] == {}) or (objspec[1] == {}): + ###if DEBUG: print "something getting wrong in update_material: dump follows ..." + ###if DEBUG: print surf_list + ###if DEBUG: print objspec[5] + ###if DEBUG: print objspec[1] + return + obj_dict = objspec[1] + all_faces = objspec[3] + obj_dim_dict = objspec[4] + ptag_dict = objspec[5] + uvcoords_dict = objspec[7] + facesuv_dict = objspec[8] + for surf in surf_list: + if surf and surf['NAME'] in ptag_dict: # in ptag_dict.keys() + ###if DEBUG: print "#-------------------------------------------------------------------#" + ###if DEBUG: print "Processing surface (material): %s" % surf['NAME'] + ###if DEBUG: print "#-------------------------------------------------------------------#" + #material set up + facelist = ptag_dict[surf['NAME']] + #bounding box and position + cur_obj = obj_dict[surf['NAME']] + obj_size = obj_dim_dict[surf['NAME']][0] + obj_pos = obj_dim_dict[surf['NAME']][1] + ###if DEBUG: print surf + #uncomment this if material pre-allocated by read_surf + mat = surf['g_MAT'] + if mat == None: + ###if DEBUG: print "Sorry, no pre-allocated material to update. Giving up for %s." % surf['NAME'] + break + #mat = Blender.Material.New(surf['NAME']) + #surf['g_MAT'] = mat + if 'COLR' in surf: # has_key + mat.rgbCol = surf['COLR'] + if 'LUMI' in surf: + mat.setEmit(surf['LUMI']) + if 'GVAL' in surf: # has_key + mat.setAdd(surf['GVAL']) + if 'SPEC' in surf: # has_key + mat.setSpec(surf['SPEC']) #it should be * 2 but seems to be a bit higher lwo [0.0, 1.0] - blender [0.0, 2.0] + if 'DIFF' in surf: # has_key + mat.setRef(surf['DIFF']) #lwo [0.0, 1.0] - blender [0.0, 1.0] + if 'GLOS' in surf: # has_key #lwo [0.0, 1.0] - blender [0, 255] + glo = int(371.67 * surf['GLOS'] - 42.334) #linear mapping - seems to work better than exp mapping + if glo <32: glo = 32 #clamped to 32-255 + if glo >255: glo = 255 + mat.setHardness(glo) + if 'TRNL' in surf: # has_key + mat.setTranslucency(surf['TRNL']) #NOT SURE ABOUT THIS lwo [0.0, 1.0] - blender [0.0, 1.0] + + mm = mat.mode + mm |= Blender.Material.Modes.TRANSPSHADOW + if 'REFL' in surf: # has_key + mat.setRayMirr(surf['REFL']) #lwo [0.0, 1.0] - blender [0.0, 1.0] + mm |= Blender.Material.Modes.RAYMIRROR + if 'TRAN' in surf: # has_key + mat.setAlpha(1.0-surf['TRAN']) #lwo [0.0, 1.0] - blender [1.0, 0.0] + mm |= Blender.Material.Modes.RAYTRANSP + if 'RIND' in surf: # has_key + s = surf['RIND'] + if s < 1.0: s = 1.0 + if s > 3.0: s = 3.0 + mat.setIOR(s) #clipped to blender [1.0, 3.0] + mm |= Blender.Material.Modes.RAYTRANSP + if 'BLOK' in surf and surf['BLOK'] != []: + #update the material according to texture. + alphaflag = create_blok(surf, mat, clip_list, obj_size, obj_pos) + if alphaflag: + mm |= Blender.Material.Modes.RAYTRANSP + mat.mode = mm + #finished setting up the material + #end if exist SURF + #end loop on materials (SURFs) + return + + +# ====================== +# === Read Faces 6.0 === +# ====================== +def read_faces_6(lwochunk): + data = cStringIO.StringIO(lwochunk.read()) + faces = [] + polygon_type = data.read(4) + subsurf = 0 + if polygon_type != "FACE" and polygon_type != "PTCH": + ###if DEBUG: print "No FACE/PATCH Were Found. Polygon Type: %s" % polygon_type + return "", 2 + if polygon_type == 'PTCH': subsurf = 1 + i = 0 + while(i < lwochunk.chunksize-4): + #if not i%1000 and my_meshtools.show_progress: + # Blender.Window.DrawProgressBar(float(i)/lwochunk.chunksize, "Reading Faces") + facev = [] + numfaceverts, = struct.unpack(">H", data.read(2)) + i += 2 + + for j in xrange(numfaceverts): + index, index_size = read_vx(data) + i += index_size + facev.append(index) + faces.append(facev) + ###if DEBUG: print "read %s faces; type of block %d (0=FACE; 1=PATCH)" % (len(faces), subsurf) + return faces, subsurf + +def main(): + if not struct: + Blender.Draw.PupMenu('This importer requires a full python install') + return + + Blender.Window.FileSelector(read, "Import LWO", '*.lwo') + + +if __name__=='__main__': + main() + +# Cams debugging lwo loader +""" +TIME= Blender.sys.time() +import os +print 'Searching for files' +os.system('find /fe/lwo/Objects/ -follow -iname "*.lwo" > /tmp/templwo_list') +# os.system('find /storage/ -iname "*.lwo" > /tmp/templwo_list') +print '...Done' +file= open('/tmp/templwo_list', 'r') +lines= file.readlines() + +# sort by filesize for faster testing +lines_size = [(os.path.getsize(f[:-1]), f[:-1]) for f in lines] +lines_size.sort() +lines = [f[1] for f in lines_size] + +file.close() + +def between(v,a,b): + if v <= max(a,b) and v >= min(a,b): + return True + + return False +size= 0.0 +for i, _lwo in enumerate(lines): + #if i==425: # SCANFILL + #if 1: + #if i==520: # SCANFILL CRASH + #if i==47: # SCANFILL CRASH + #if between(i, 525, 550): + #if i > 1635: + #if i != 1519: # 730 + if i>141: + #if 1: + # _lwo= _lwo[:-1] + print 'Importing', _lwo, '\nNUMBER', i, 'of', len(lines) + _lwo_file= _lwo.split('/')[-1].split('\\')[-1] + newScn= bpy.data.scenes.new(_lwo_file) + bpy.data.scenes.active = newScn + size += ((os.path.getsize(_lwo)/1024.0))/ 1024.0 + read(_lwo) + # Remove objects to save memory? + ''' + for ob in newScn.objects: + if ob.type=='Mesh': + me= ob.getData(mesh=1) + me.verts= None + newScn.unlink(ob) + ''' + print 'mb size so far', size + +print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME) +""" \ No newline at end of file diff --git a/release/scripts/md2_export.py b/release/scripts/md2_export.py new file mode 100644 index 00000000000..71e056a5f53 --- /dev/null +++ b/release/scripts/md2_export.py @@ -0,0 +1,1247 @@ +#!BPY + +""" +Name: 'MD2 (.md2)' +Blender: 243 +Group: 'Export' +Tooltip: 'Export to Quake file format (.md2).' +""" + +__author__ = 'Bob Holcomb' +__version__ = '0.18.1' +__url__ = ["Bob's site, http://bane.servebeer.com", + "Support forum, http://bane.servebeer.com", "blender", "elysiun"] +__email__ = ["Bob Holcomb, bob_holcomb:hotmail*com", "scripts"] +__bpydoc__ = """\ +This script Exports a Quake 2 file (MD2). + + Additional help from: Shadwolf, Skandal, Rojo, Cambo
+ Thanks Guys! +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C): Bob Holcomb +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +import Blender +from Blender import * +from Blender.Draw import * +from Blender.BGL import * +from Blender.Window import * + +import struct, string +from types import * + + + +###################################################### +# GUI Loader +###################################################### + +# Export globals +g_filename=Create("tris.md2") +g_frame_filename=Create("default") + +g_filename_search=Create("") +g_frame_search=Create("default") + +g_texture_path=Create("") + +user_frame_list=[] + +#Globals +g_scale=Create(1.0) + +# Events +EVENT_NOEVENT=1 +EVENT_SAVE_MD2=2 +EVENT_CHOOSE_FILENAME=3 +EVENT_CHOOSE_FRAME=4 +EVENT_EXIT=100 + +###################################################### +# Callbacks for Window functions +###################################################### +def filename_callback(input_filename): + global g_filename + g_filename.val=input_filename + +def frame_callback(input_frame): + global g_frame_filename + g_frame_filename.val=input_frame + +def draw_gui(): + global g_scale + global g_filename + global g_frame_filename + global EVENT_NOEVENT,EVENT_SAVE_MD2,EVENT_CHOOSE_FILENAME,EVENT_CHOOSE_FRAME,EVENT_EXIT + global g_texture_path + + ########## Titles + glClear(GL_COLOR_BUFFER_BIT) + glRasterPos2d(10, 120) + Text("MD2 Export") + + ######### Parameters GUI Buttons + ######### MD2 Filename text entry + g_filename = String("MD2 file to save: ", EVENT_NOEVENT, 10, 75, 210, 18, + g_filename.val, 255, "MD2 file to save") + ########## MD2 File Search Button + Button("Search",EVENT_CHOOSE_FILENAME,220,75,80,18) + + ########## MD2 Frame List Text entry + g_frame_filename = String("Frame List file to load: ", EVENT_NOEVENT, 10, 55, 210, 18, + g_frame_filename.val, 255, "Frame List to load-overrides MD2 defaults") + ########## Frame List Search Button + Button("Search",EVENT_CHOOSE_FRAME,220,55,80,18) + + ########## Texture path to append + g_texture_path=String("Texture Path: ", EVENT_NOEVENT, 10,35,210,18, + g_texture_path.val,255, "Texture path to prepend") + + + ########## Scale slider-default is 1/8 which is a good scale for md2->blender + g_scale= Slider("Scale Factor: ", EVENT_NOEVENT, 10, 95, 210, 18, + 1.0, 0.001, 10.0, 1, "Scale factor for object Model"); + + ######### Draw and Exit Buttons + Button("Export",EVENT_SAVE_MD2 , 10, 10, 80, 18) + Button("Exit",EVENT_EXIT , 170, 10, 80, 18) + +def event(evt, val): + if (evt == QKEY and not val): + Exit() + +def bevent(evt): + global g_filename + global g_frame_filename + global EVENT_NOEVENT,EVENT_SAVE_MD2,EVENT_EXIT + + ######### Manages GUI events + if (evt==EVENT_EXIT): + Blender.Draw.Exit() + elif (evt==EVENT_CHOOSE_FILENAME): + FileSelector(filename_callback, "MD2 File Selection") + elif (evt==EVENT_CHOOSE_FRAME): + FileSelector(frame_callback, "Frame Selection") + elif (evt==EVENT_SAVE_MD2): + if (g_filename.val == "model"): + save_md2("blender.md2") + Blender.Draw.Exit() + return + else: + save_md2(g_filename.val) + Blender.Draw.Exit() + return + +Register(draw_gui, event, bevent) + +###################################################### +# MD2 Model Constants +###################################################### +MD2_MAX_TRIANGLES=4096 +MD2_MAX_VERTICES=2048 +MD2_MAX_TEXCOORDS=2048 +MD2_MAX_FRAMES=512 +MD2_MAX_SKINS=32 +MD2_MAX_FRAMESIZE=(MD2_MAX_VERTICES * 4 + 128) + +MD2_FRAME_NAME_LIST=(("stand",1,40), + ("run",41,46), + ("attack",47,54), + ("pain1",55,58), + ("pain2",59,62), + ("pain3",63,66), + ("jump",67,72), + ("flip",73,84), + ("salute", 85,95), + ("taunt",96,112), + ("wave",113,123), + ("point",124,135), + ("crstnd",136,154), + ("crwalk",155,160), + ("crattack",161,169), + ("crpain",170,173), + ("crdeath",174,178), + ("death1",179,184), + ("death2",185,190), + ("death3",191,198)) + #198 frames + +MD2_NORMALS=((-0.525731, 0.000000, 0.850651), + (-0.442863, 0.238856, 0.864188), + (-0.295242, 0.000000, 0.955423), + (-0.309017, 0.500000, 0.809017), + (-0.162460, 0.262866, 0.951056), + (0.000000, 0.000000, 1.000000), + (0.000000, 0.850651, 0.525731), + (-0.147621, 0.716567, 0.681718), + (0.147621, 0.716567, 0.681718), + (0.000000, 0.525731, 0.850651), + (0.309017, 0.500000, 0.809017), + (0.525731, 0.000000, 0.850651), + (0.295242, 0.000000, 0.955423), + (0.442863, 0.238856, 0.864188), + (0.162460, 0.262866, 0.951056), + (-0.681718, 0.147621, 0.716567), + (-0.809017, 0.309017, 0.500000), + (-0.587785, 0.425325, 0.688191), + (-0.850651, 0.525731, 0.000000), + (-0.864188, 0.442863, 0.238856), + (-0.716567, 0.681718, 0.147621), + (-0.688191, 0.587785, 0.425325), + (-0.500000, 0.809017, 0.309017), + (-0.238856, 0.864188, 0.442863), + (-0.425325, 0.688191, 0.587785), + (-0.716567, 0.681718, -0.147621), + (-0.500000, 0.809017, -0.309017), + (-0.525731, 0.850651, 0.000000), + (0.000000, 0.850651, -0.525731), + (-0.238856, 0.864188, -0.442863), + (0.000000, 0.955423, -0.295242), + (-0.262866, 0.951056, -0.162460), + (0.000000, 1.000000, 0.000000), + (0.000000, 0.955423, 0.295242), + (-0.262866, 0.951056, 0.162460), + (0.238856, 0.864188, 0.442863), + (0.262866, 0.951056, 0.162460), + (0.500000, 0.809017, 0.309017), + (0.238856, 0.864188, -0.442863), + (0.262866, 0.951056, -0.162460), + (0.500000, 0.809017, -0.309017), + (0.850651, 0.525731, 0.000000), + (0.716567, 0.681718, 0.147621), + (0.716567, 0.681718, -0.147621), + (0.525731, 0.850651, 0.000000), + (0.425325, 0.688191, 0.587785), + (0.864188, 0.442863, 0.238856), + (0.688191, 0.587785, 0.425325), + (0.809017, 0.309017, 0.500000), + (0.681718, 0.147621, 0.716567), + (0.587785, 0.425325, 0.688191), + (0.955423, 0.295242, 0.000000), + (1.000000, 0.000000, 0.000000), + (0.951056, 0.162460, 0.262866), + (0.850651, -0.525731, 0.000000), + (0.955423, -0.295242, 0.000000), + (0.864188, -0.442863, 0.238856), + (0.951056, -0.162460, 0.262866), + (0.809017, -0.309017, 0.500000), + (0.681718, -0.147621, 0.716567), + (0.850651, 0.000000, 0.525731), + (0.864188, 0.442863, -0.238856), + (0.809017, 0.309017, -0.500000), + (0.951056, 0.162460, -0.262866), + (0.525731, 0.000000, -0.850651), + (0.681718, 0.147621, -0.716567), + (0.681718, -0.147621, -0.716567), + (0.850651, 0.000000, -0.525731), + (0.809017, -0.309017, -0.500000), + (0.864188, -0.442863, -0.238856), + (0.951056, -0.162460, -0.262866), + (0.147621, 0.716567, -0.681718), + (0.309017, 0.500000, -0.809017), + (0.425325, 0.688191, -0.587785), + (0.442863, 0.238856, -0.864188), + (0.587785, 0.425325, -0.688191), + (0.688191, 0.587785, -0.425325), + (-0.147621, 0.716567, -0.681718), + (-0.309017, 0.500000, -0.809017), + (0.000000, 0.525731, -0.850651), + (-0.525731, 0.000000, -0.850651), + (-0.442863, 0.238856, -0.864188), + (-0.295242, 0.000000, -0.955423), + (-0.162460, 0.262866, -0.951056), + (0.000000, 0.000000, -1.000000), + (0.295242, 0.000000, -0.955423), + (0.162460, 0.262866, -0.951056), + (-0.442863, -0.238856, -0.864188), + (-0.309017, -0.500000, -0.809017), + (-0.162460, -0.262866, -0.951056), + (0.000000, -0.850651, -0.525731), + (-0.147621, -0.716567, -0.681718), + (0.147621, -0.716567, -0.681718), + (0.000000, -0.525731, -0.850651), + (0.309017, -0.500000, -0.809017), + (0.442863, -0.238856, -0.864188), + (0.162460, -0.262866, -0.951056), + (0.238856, -0.864188, -0.442863), + (0.500000, -0.809017, -0.309017), + (0.425325, -0.688191, -0.587785), + (0.716567, -0.681718, -0.147621), + (0.688191, -0.587785, -0.425325), + (0.587785, -0.425325, -0.688191), + (0.000000, -0.955423, -0.295242), + (0.000000, -1.000000, 0.000000), + (0.262866, -0.951056, -0.162460), + (0.000000, -0.850651, 0.525731), + (0.000000, -0.955423, 0.295242), + (0.238856, -0.864188, 0.442863), + (0.262866, -0.951056, 0.162460), + (0.500000, -0.809017, 0.309017), + (0.716567, -0.681718, 0.147621), + (0.525731, -0.850651, 0.000000), + (-0.238856, -0.864188, -0.442863), + (-0.500000, -0.809017, -0.309017), + (-0.262866, -0.951056, -0.162460), + (-0.850651, -0.525731, 0.000000), + (-0.716567, -0.681718, -0.147621), + (-0.716567, -0.681718, 0.147621), + (-0.525731, -0.850651, 0.000000), + (-0.500000, -0.809017, 0.309017), + (-0.238856, -0.864188, 0.442863), + (-0.262866, -0.951056, 0.162460), + (-0.864188, -0.442863, 0.238856), + (-0.809017, -0.309017, 0.500000), + (-0.688191, -0.587785, 0.425325), + (-0.681718, -0.147621, 0.716567), + (-0.442863, -0.238856, 0.864188), + (-0.587785, -0.425325, 0.688191), + (-0.309017, -0.500000, 0.809017), + (-0.147621, -0.716567, 0.681718), + (-0.425325, -0.688191, 0.587785), + (-0.162460, -0.262866, 0.951056), + (0.442863, -0.238856, 0.864188), + (0.162460, -0.262866, 0.951056), + (0.309017, -0.500000, 0.809017), + (0.147621, -0.716567, 0.681718), + (0.000000, -0.525731, 0.850651), + (0.425325, -0.688191, 0.587785), + (0.587785, -0.425325, 0.688191), + (0.688191, -0.587785, 0.425325), + (-0.955423, 0.295242, 0.000000), + (-0.951056, 0.162460, 0.262866), + (-1.000000, 0.000000, 0.000000), + (-0.850651, 0.000000, 0.525731), + (-0.955423, -0.295242, 0.000000), + (-0.951056, -0.162460, 0.262866), + (-0.864188, 0.442863, -0.238856), + (-0.951056, 0.162460, -0.262866), + (-0.809017, 0.309017, -0.500000), + (-0.864188, -0.442863, -0.238856), + (-0.951056, -0.162460, -0.262866), + (-0.809017, -0.309017, -0.500000), + (-0.681718, 0.147621, -0.716567), + (-0.681718, -0.147621, -0.716567), + (-0.850651, 0.000000, -0.525731), + (-0.688191, 0.587785, -0.425325), + (-0.587785, 0.425325, -0.688191), + (-0.425325, 0.688191, -0.587785), + (-0.425325, -0.688191, -0.587785), + (-0.587785, -0.425325, -0.688191), + (-0.688191, -0.587785, -0.425325)) + + +###################################################### +# MD2 data structures +###################################################### +class md2_point: + vertices=[] + lightnormalindex=0 + binary_format="<3BB" + def __init__(self): + self.vertices=[0]*3 + self.lightnormalindex=0 + def save(self, file): + temp_data=[0]*4 + temp_data[0]=self.vertices[0] + temp_data[1]=self.vertices[1] + temp_data[2]=self.vertices[2] + temp_data[3]=self.lightnormalindex + data=struct.pack(self.binary_format, temp_data[0], temp_data[1], temp_data[2], temp_data[3]) + file.write(data) + def dump(self): + print "MD2 Point Structure" + print "vertex X: ", self.vertices[0] + print "vertex Y: ", self.vertices[1] + print "vertex Z: ", self.vertices[2] + print "lightnormalindex: ",self.lightnormalindex + print "" + +class md2_face: + vertex_index=[] + texture_index=[] + binary_format="<3h3h" + def __init__(self): + self.vertex_index = [ 0, 0, 0 ] + self.texture_index = [ 0, 0, 0] + def save(self, file): + temp_data=[0]*6 + #swap vertices around so they draw right + temp_data[0]=self.vertex_index[0] + temp_data[1]=self.vertex_index[2] + temp_data[2]=self.vertex_index[1] + #swap texture vertices around so they draw right + temp_data[3]=self.texture_index[0] + temp_data[4]=self.texture_index[2] + temp_data[5]=self.texture_index[1] + data=struct.pack(self.binary_format,temp_data[0],temp_data[1],temp_data[2],temp_data[3],temp_data[4],temp_data[5]) + file.write(data) + def dump (self): + print "MD2 Face Structure" + print "vertex 1 index: ", self.vertex_index[0] + print "vertex 2 index: ", self.vertex_index[1] + print "vertex 3 index: ", self.vertex_index[2] + print "texture 1 index: ", self.texture_index[0] + print "texture 2 index: ", self.texture_index[1] + print "texture 3 index: ", self.texture_index[2] + print "" + +class md2_tex_coord: + u=0 + v=0 + binary_format="<2h" + def __init__(self): + self.u=0 + self.v=0 + def save(self, file): + temp_data=[0]*2 + temp_data[0]=self.u + temp_data[1]=self.v + data=struct.pack(self.binary_format, temp_data[0], temp_data[1]) + file.write(data) + def dump (self): + print "MD2 Texture Coordinate Structure" + print "texture coordinate u: ",self.u + print "texture coordinate v: ",self.v + print "" + +class md2_GL_command: + s=0.0 + t=0.0 + vert_index=0 + binary_format="<2fi" + + def __init__(self): + self.s=0.0 + self.t=0.0 + vert_index=0 + def save(self,file): + temp_data=[0]*3 + temp_data[0]=float(self.s) + temp_data[1]=float(self.t) + temp_data[2]=self.vert_index + data=struct.pack(self.binary_format, temp_data[0],temp_data[1],temp_data[2]) + file.write(data) + def dump (self): + print "MD2 OpenGL Command" + print "s: ", self.s + print "t: ", self.t + print "Vertex Index: ", self.vert_index + print "" + +class md2_GL_cmd_list: + num=0 + cmd_list=[] + binary_format="MD2_MAX_TRIANGLES: + print "Number of triangles exceeds MD2 standard: ", face_count,">",MD2_MAX_TRIANGLES + result=Blender.Draw.PupMenu("Number of triangles exceeds MD2 standard: Continue?%t|YES|NO") + if(result==2): + return False + if vert_count>MD2_MAX_VERTICES: + print "Number of verticies exceeds MD2 standard",vert_count,">",MD2_MAX_VERTICES + result=Blender.Draw.PupMenu("Number of verticies exceeds MD2 standard: Continue?%t|YES|NO") + if(result==2): + return False + if frame_count>MD2_MAX_FRAMES: + print "Number of frames exceeds MD2 standard of",frame_count,">",MD2_MAX_FRAMES + result=Blender.Draw.PupMenu("Number of frames exceeds MD2 standard: Continue?%t|YES|NO") + if(result==2): + return False + #model is OK + return True + +###################################################### +# Fill MD2 data structure +###################################################### +def fill_md2(md2, object): + #global defines + global user_frame_list + global g_texture_path + + Blender.Window.DrawProgressBar(0.25,"Filling MD2 Data") + + #get a Mesh, not NMesh + mesh=object.getData(False, True) + + #load up some intermediate data structures + tex_list={} + tex_count=0 + #create the vertex list from the first frame + Blender.Set("curframe", 1) + + #header information + md2.ident=844121161 + md2.version=8 + md2.num_vertices=len(mesh.verts) + md2.num_faces=len(mesh.faces) + + #get the skin information + #use the first faces' image for the texture information + mesh_image=mesh.faces[0].image + size=mesh_image.getSize() + md2.skin_width=size[0] + md2.skin_height=size[1] + md2.num_skins=1 + #add a skin node to the md2 data structure + md2.skins.append(md2_skin()) + md2.skins[0].name=g_texture_path.val+Blender.sys.basename(mesh_image.getFilename()) + if len(md2.skins[0].name)>64: + print "Texture Path and name is more than 64 characters" + result=Blender.Draw.PupMenu("Texture path and name is more than 64 characters-Quitting") + return False + + #put texture information in the md2 structure + #build UV coord dictionary (prevents double entries-saves space) + for face in mesh.faces: + for i in range(0,3): + t=(face.uv[i]) + tex_key=(t[0],t[1]) + if not tex_list.has_key(tex_key): + tex_list[tex_key]=tex_count + tex_count+=1 + md2.num_tex_coords=tex_count #each vert has its own UV coord + + for this_tex in range (0, md2.num_tex_coords): + md2.tex_coords.append(md2_tex_coord()) + for coord, index in tex_list.iteritems(): + #md2.tex_coords.append(md2_tex_coord()) + md2.tex_coords[index].u=int(coord[0]*md2.skin_width) + md2.tex_coords[index].v=int((1-coord[1])*md2.skin_height) + + #put faces in the md2 structure + #for each face in the model + for this_face in range(0, md2.num_faces): + md2.faces.append(md2_face()) + for i in range(0,3): + #blender uses indexed vertexes so this works very well + md2.faces[this_face].vertex_index[i]=mesh.faces[this_face].verts[i].index + #lookup texture index in dictionary + uv_coord=(mesh.faces[this_face].uv[i]) + tex_key=(uv_coord[0],uv_coord[1]) + tex_index=tex_list[tex_key] + md2.faces[this_face].texture_index[i]=tex_index + + Blender.Window.DrawProgressBar(0.5, "Computing GL Commands") + + #compute GL commands + md2.num_GL_commands=build_GL_commands(md2, mesh) + + #get the frame data + #calculate 1 frame size + (1 vert size*num_verts) + md2.frame_size=40+(md2.num_vertices*4) #in bytes + + #get the frame list + user_frame_list=get_frame_list() + if user_frame_list=="default": + md2.num_frames=198 + else: + temp=user_frame_list[len(user_frame_list)-1] #last item + md2.num_frames=temp[2] #last frame number + + + progress=0.5 + progressIncrement=0.25/md2.num_frames + + #fill in each frame with frame info and all the vertex data for that frame + for frame_counter in range(0,md2.num_frames): + + progress+=progressIncrement + Blender.Window.DrawProgressBar(progress, "Calculating Frame: "+str(frame_counter)) + + #add a frame + md2.frames.append(md2_frame()) + #update the mesh objects vertex positions for the animation + Blender.Set("curframe", frame_counter) #set blender to the correct frame + mesh.getFromObject(object.name) #update the mesh to make verts current + +#each frame has a scale and transform value that gets the vertex value between 0-255 +#since the scale and transform are the same for the all the verts in the frame, we only need +#to figure this out once per frame + + #we need to start with the bounding box + #bounding_box=object.getBoundBox() #uses the object, not the mesh data + #initialize with the first vertex for both min and max. X and Y are swapped for MD2 format + + #initialize + frame_min_x=100000.0 + frame_max_x=-100000.0 + frame_min_y=100000.0 + frame_max_y=-100000.0 + frame_min_z=100000.0 + frame_max_z=-100000.0 + + for face in mesh.faces: + for vert in face.verts: + if frame_min_x>vert.co[1]: frame_min_x=vert.co[1] + if frame_max_xvert.co[0]: frame_min_y=vert.co[0] + if frame_max_yvert.co[2]: frame_min_z=vert.co[2] + if frame_max_z maxdot): + maxdot = dot; + maxdotindex = j; + + md2.frames[frame_counter].vertices[vert_counter].lightnormalindex=maxdotindex+2 + + del maxdot, maxdotindex + del new_x, new_y, new_z + del frame_max_x, frame_max_y, frame_max_z, frame_min_x, frame_min_y, frame_min_z + del frame_scale_x, frame_scale_y, frame_scale_z, frame_trans_x, frame_trans_y, frame_trans_z + + + #output all the frame names-user_frame_list is loaded during the validation + for frame_set in user_frame_list: + for counter in range(frame_set[1]-1, frame_set[2]): + md2.frames[counter].name=frame_set[0]+"_"+str(counter-frame_set[1]+2) + + #compute these after everthing is loaded into a md2 structure + header_size=17*4 #17 integers, and each integer is 4 bytes + skin_size=64*md2.num_skins #64 char per skin * number of skins + tex_coord_size=4*md2.num_tex_coords #2 short * number of texture coords + face_size=12*md2.num_faces #3 shorts for vertex index, 3 shorts for tex index + frames_size=(((12+12+16)+(4*md2.num_vertices)) * md2.num_frames) #frame info+verts per frame*num frames + GL_command_size=md2.num_GL_commands*4 #each is an int or float, so 4 bytes per + + #fill in the info about offsets + md2.offset_skins=0+header_size + md2.offset_tex_coords=md2.offset_skins+skin_size + md2.offset_faces=md2.offset_tex_coords+tex_coord_size + md2.offset_frames=md2.offset_faces+face_size + md2.offset_GL_commands=md2.offset_frames+frames_size + md2.offset_end=md2.offset_GL_commands+GL_command_size + +###################################################### +# Get Frame List +###################################################### +def get_frame_list(): + global g_frame_filename + frame_list=[] + + if g_frame_filename.val=="default": + return MD2_FRAME_NAME_LIST + + else: + #check for file + if (Blender.sys.exists(g_frame_filename.val)==1): + #open file and read it in + file=open(g_frame_filename.val,"r") + lines=file.readlines() + file.close() + + #check header (first line) + if lines[0].stip()<>"# MD2 Frame Name List": + print "its not a valid file" + result=Blender.Draw.PupMenu("This is not a valid frame definition file-using default%t|OK") + return MD2_FRAME_NAME_LIST + else: + #read in the data + num_frames=0 + for counter in range(1, len(lines)): + current_line=lines[counter].strip() + if current_line[0]=="#": + #found a comment + pass + else: + data=current_line.split() + frame_list.append([data[0],num_frames+1, num_frames+int(data[1])]) + num_frames+=int(data[1]) + return frame_list + else: + print "Cannot find file" + result=Blender.Draw.PupMenu("Cannot find frame definion file-using default%t|OK") + return MD2_FRAME_NAME_LIST + +###################################################### +# Globals for GL command list calculations +###################################################### +used_tris=[] +edge_dict={} +strip_verts=[] +strip_st=[] +strip_tris=[] +strip_first_run=True +odd=False + +###################################################### +# Find Strip length function +###################################################### +def find_strip_length(mesh, start_tri, edge_key): + #print "Finding strip length" + + global used_tris + global edge_dict + global strip_tris + global strip_st + global strip_verts + global strip_first_run + global odd + + used_tris[start_tri]=2 + + strip_tris.append(start_tri) #add this tri to the potential list of tri-strip + + #print "I am face: ", start_tri + #print "Using edge Key: ", edge_key + + faces=edge_dict[edge_key] #get list of face indexes that share this edge + if (len(faces)==0): + #print "Cant find edge with key: ", edge_key + pass + + #print "Faces sharing this edge: ", faces + for face_index in faces: + face=mesh.faces[face_index] + if face_index==start_tri: #don't want to check myself + #print "I found myself, continuing" + pass + else: + if used_tris[face_index]!=0: #found a used tri-move along + #print "Found a used tri: ", face_index + pass + else: + #find non-shared vert + for vert_counter in range(0,3): + if (face.verts[vert_counter].index!=edge_key[0] and face.verts[vert_counter].index!=edge_key[1]): + next_vert=vert_counter + + if(odd==False): + #print "Found a suitable even connecting tri: ", face_index + used_tris[face_index]=2 #mark as dirty for this rum + odd=True + + #find the new edge + if(face.verts[next_vert].index < face.verts[(next_vert+2)%3].index): + temp_key=(face.verts[next_vert].index,face.verts[(next_vert+2)%3].index) + else: + temp_key=(face.verts[(next_vert+2)%3].index, face.verts[next_vert].index) + + #print "temp key: ", temp_key + temp_faces=edge_dict[temp_key] + + if(len(temp_faces)==0): + print "Can't find any other faces with key: ", temp_key + else: + #search the new edge + #print "found other faces, searching them" + find_strip_length(mesh, face_index, temp_key) #recursive greedy-takes first tri it finds as best + break; + else: + #print "Found a suitable odd connecting tri: ", face_index + used_tris[face_index]=2 #mark as dirty for this rum + odd=False + + #find the new edge + if(face.verts[next_vert].index < face.verts[(next_vert+1)%3].index): + temp_key=(face.verts[next_vert].index,face.verts[(next_vert+1)%3].index) + else: + temp_key=(face.verts[(next_vert+1)%3].index, face.verts[next_vert].index) + #print "temp key: ", temp_key + temp_faces=edge_dict[temp_key] + if(len(temp_faces)==0): + print "Can't find any other faces with key: ", temp_key + else: + #search the new edge + #print "found other faces, searching them" + find_strip_length(mesh, face_index, temp_key) #recursive greedy-takes first tri it finds as best + break; + + return len(strip_tris) + + +###################################################### +# Tri-Stripify function +###################################################### +def stripify_tri_list(mesh, edge_key): + global edge_dict + global strip_tris + global strip_st + global strip_verts + + shared_edge=[] + key=[] + + #print "*****Stripify the triangle list*******" + #print "strip tris: ", strip_tris + #print "strip_tri length: ", len(strip_tris) + + for tri_counter in range(0, len(strip_tris)): + face=mesh.faces[strip_tris[tri_counter]] + if (tri_counter==0): #first one only + #find non-edge vert + for vert_counter in range(0,3): + if (face.verts[vert_counter].index!=edge_key[0] and face.verts[vert_counter].index!=edge_key[1]): + start_vert=vert_counter + strip_verts.append(face.verts[start_vert].index) + strip_st.append(face.uv[start_vert]) + + strip_verts.append(face.verts[(start_vert+2)%3].index) + strip_st.append(face.uv[(start_vert+2)%3]) + + strip_verts.append(face.verts[(start_vert+1)%3].index) + strip_st.append(face.uv[(start_vert+1)%3]) + else: + for vert_counter in range(0,3): + if(face.verts[vert_counter].index!=strip_verts[-1] and face.verts[vert_counter].index!=strip_verts[-2]): + strip_verts.append(face.verts[vert_counter].index) + strip_st.append(face.uv[vert_counter]) + break + + + +###################################################### +# Build GL command List +###################################################### +def build_GL_commands(md2, mesh): + print "Building GL Commands" + + global used_tris + global edge_dict + global strip_verts + global strip_tris + global strip_st + + #globals initialization + used_tris=[0]*len(mesh.faces) + #print "Used: ", used_tris + num_commands=0 + + #edge dictionary generation + edge_dict=dict([(ed.key,[]) for ed in mesh.edges]) + for face in (mesh.faces): + for key in face.edge_keys: + edge_dict[key].append(face.index) + + #print "edge Dict: ", edge_dict + + for tri_counter in range(0,len(mesh.faces)): + if used_tris[tri_counter]!=0: + #print "Found a used triangle: ", tri_counter + pass + else: + #print "Found an unused triangle: ", tri_counter + + #intialization + strip_tris=[0]*0 + strip_verts=[0]*0 + strip_st=[0]*0 + strip_first_run=True + odd=True + + #find the strip length + strip_length=find_strip_length(mesh, tri_counter, mesh.faces[tri_counter].edge_keys[0]) + + #mark tris as used + for used_counter in range(0,strip_length): + used_tris[strip_tris[used_counter]]=1 + + stripify_tri_list(mesh, mesh.faces[tri_counter].edge_keys[0]) + + #create command list + cmd_list=md2_GL_cmd_list() + #number of commands in this list + print "strip length: ", strip_length + cmd_list.num=(len(strip_tris)+2) #positive for strips, fans would be negative, but not supported yet + num_commands+=1 + + #add s,t,vert for this command list + for command_counter in range(0, len(strip_tris)+2): + cmd=md2_GL_command() + cmd.s=strip_st[command_counter][0] + cmd.t=1.0-strip_st[command_counter][1] #flip upside down + cmd.vert_index=strip_verts[command_counter] + num_commands+=3 + cmd_list.cmd_list.append(cmd) + print "Cmd List length: ", len(cmd_list.cmd_list) + print "Cmd list num: ", cmd_list.num + print "Cmd List: ", cmd_list.dump() + md2.GL_commands.append(cmd_list) + + #add the null command at the end + temp_cmdlist=md2_GL_cmd_list() + temp_cmdlist.num=0 + md2.GL_commands.append(temp_cmdlist) + num_commands+=1 + + #cleanup and return + used=strip_vert=strip_st=strip_tris=0 + return num_commands + + + + +###################################################### +# Save MD2 Format +###################################################### +def save_md2(filename): + print "" + print "***********************************" + print "MD2 Export" + print "***********************************" + print "" + + Blender.Window.DrawProgressBar(0.0,"Begining MD2 Export") + + md2=md2_obj() #blank md2 object to save + + #get the object + mesh_objs = Blender.Object.GetSelected() + + #check there is a blender object selected + if len(mesh_objs)==0: + print "Fatal Error: Must select a mesh to output as MD2" + print "Found nothing" + result=Blender.Draw.PupMenu("Must select an object to export%t|OK") + return + + mesh_obj=mesh_objs[0] #this gets the first object (should be only one) + + #check if it's a mesh object + if mesh_obj.getType()!="Mesh": + print "Fatal Error: Must select a mesh to output as MD2" + print "Found: ", mesh_obj.getType() + result=Blender.Draw.PupMenu("Selected Object must be a mesh to output as MD2%t|OK") + return + + ok=validation(mesh_obj) + if ok==False: + return + + fill_md2(md2, mesh_obj) + md2.dump() + + Blender.Window.DrawProgressBar(1.0, "Writing to Disk") + + #actually write it to disk + file=open(filename,"wb") + md2.save(file) + file.close() + + #cleanup + md2=0 + + print "Closed the file" diff --git a/release/scripts/md2_import.py b/release/scripts/md2_import.py new file mode 100644 index 00000000000..e39b2ca85ec --- /dev/null +++ b/release/scripts/md2_import.py @@ -0,0 +1,598 @@ +#!BPY + +""" +Name: 'MD2 (.md2)' +Blender: 239 +Group: 'Import' +Tooltip: 'Import from Quake file format (.md2).' +""" + +__author__ = 'Bob Holcomb' +__version__ = '0.16' +__url__ = ["Bob's site, http://bane.servebeer.com", + "Support forum, http://scourage.servebeer.com/phpbb/", "blender", "elysiun"] +__email__ = ["Bob Holcomb, bob_holcomb:hotmail*com", "scripts"] +__bpydoc__ = """\ +This script imports a Quake 2 file (MD2), textures, +and animations into blender for editing. Loader is based on MD2 loader from www.gametutorials.com-Thanks DigiBen! and the md3 blender loader by PhaethonH
+ + Additional help from: Shadwolf, Skandal, Rojo and Campbell Barton
+ Thanks Guys! +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Bob Holcomb +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +import Blender +from Blender import Mesh, Object, sys +from Blender.BGL import * +from Blender.Draw import * +from Blender.Window import * +from Blender.Mathutils import Vector +import struct +from types import * + + +###################################################### +# Main Body +###################################################### + +#returns the string from a null terminated string +def asciiz (s): + n = 0 + while (ord(s[n]) != 0): + n = n + 1 + return s[0:n] + + +###################################################### +# MD2 Model Constants +###################################################### +MD2_MAX_TRIANGLES=4096 +MD2_MAX_VERTICES=2048 +MD2_MAX_TEXCOORDS=2048 +MD2_MAX_FRAMES=512 +MD2_MAX_SKINS=32 +MD2_MAX_FRAMESIZE=(MD2_MAX_VERTICES * 4 + 128) + +###################################################### +# MD2 data structures +###################################################### +class md2_alias_triangle(object): + __slots__ = 'vertices', 'lightnormalindex' + binary_format="<3BB" #little-endian (<), 3 Unsigned char + + def __init__(self): + self.vertices=[0]*3 + self.lightnormalindex=0 + + def load(self, file): + temp_data = file.read(struct.calcsize(self.binary_format)) + data = struct.unpack(self.binary_format, temp_data) + self.vertices[0]=data[0] + self.vertices[1]=data[1] + self.vertices[2]=data[2] + self.lightnormalindex=data[3] + return self + + def dump(self): + print "MD2 Alias_Triangle Structure" + print "vertex: ", self.vertices[0] + print "vertex: ", self.vertices[1] + print "vertex: ", self.vertices[2] + print "lightnormalindex: ",self.lightnormalindex + print "" + +class md2_face(object): + + binary_format="<3h3h" #little-endian (<), 3 short, 3 short + + __slots__ = 'vertex_index', 'texture_index' + + def __init__(self): + self.vertex_index = [ 0, 0, 0 ] + self.texture_index = [ 0, 0, 0] + + def load (self, file): + temp_data=file.read(struct.calcsize(self.binary_format)) + data=struct.unpack(self.binary_format, temp_data) + self.vertex_index[0]=data[0] + self.vertex_index[1]=data[1] + self.vertex_index[2]=data[2] + self.texture_index[0]=data[3] + self.texture_index[1]=data[4] + self.texture_index[2]=data[5] + return self + + def dump (self): + print "MD2 Face Structure" + print "vertex index: ", self.vertex_index[0] + print "vertex index: ", self.vertex_index[1] + print "vertex index: ", self.vertex_index[2] + print "texture index: ", self.texture_index[0] + print "texture index: ", self.texture_index[1] + print "texture index: ", self.texture_index[2] + print "" + +class md2_tex_coord(object): + __slots__ = 'u', 'v' + binary_format="<2h" #little-endian (<), 2 unsigned short + + def __init__(self): + self.u=0 + self.v=0 + + def load (self, file): + temp_data=file.read(struct.calcsize(self.binary_format)) + data=struct.unpack(self.binary_format, temp_data) + self.u=data[0] + self.v=data[1] + return self + + def dump (self): + print "MD2 Texture Coordinate Structure" + print "texture coordinate u: ",self.u + print "texture coordinate v: ",self.v + print "" + + +class md2_skin(object): + __slots__ = 'name' + binary_format="<64s" #little-endian (<), char[64] + + def __init__(self): + self.name="" + + def load (self, file): + temp_data=file.read(struct.calcsize(self.binary_format)) + data=struct.unpack(self.binary_format, temp_data) + self.name=asciiz(data[0]) + return self + + def dump (self): + print "MD2 Skin" + print "skin name: ",self.name + print "" + +class md2_alias_frame(object): + __slots__ = 'scale', 'translate', 'name', 'vertices' + binary_format="<3f3f16s" #little-endian (<), 3 float, 3 float char[16] + #did not add the "3bb" to the end of the binary format + #because the alias_vertices will be read in through + #thier own loader + + def __init__(self): + self.scale=[0.0]*3 + self.translate=[0.0]*3 + self.name="" + self.vertices=[] + + + def load (self, file): + temp_data=file.read(struct.calcsize(self.binary_format)) + data=struct.unpack(self.binary_format, temp_data) + self.scale[0]=data[0] + self.scale[1]=data[1] + self.scale[2]=data[2] + self.translate[0]=data[3] + self.translate[1]=data[4] + self.translate[2]=data[5] + self.name=asciiz(data[6]) + return self + + def dump (self): + print "MD2 Alias Frame" + print "scale x: ",self.scale[0] + print "scale y: ",self.scale[1] + print "scale z: ",self.scale[2] + print "translate x: ",self.translate[0] + print "translate y: ",self.translate[1] + print "translate z: ",self.translate[2] + print "name: ",self.name + print "" + +class md2_obj(object): + __slots__ =\ + 'tex_coords', 'faces', 'frames',\ + 'skins', 'ident', 'version',\ + 'skin_width', 'skin_height',\ + 'frame_size', 'num_skins', 'num_vertices',\ + 'num_tex_coords', 'num_faces', 'num_GL_commands',\ + 'num_frames', 'offset_skins', 'offset_tex_coords',\ + 'offset_faces', 'offset_frames', 'offset_GL_commands' + + ''' + #Header Structure + ident=0 #int 0 This is used to identify the file + version=0 #int 1 The version number of the file (Must be 8) + skin_width=0 #int 2 The skin width in pixels + skin_height=0 #int 3 The skin height in pixels + frame_size=0 #int 4 The size in bytes the frames are + num_skins=0 #int 5 The number of skins associated with the model + num_vertices=0 #int 6 The number of vertices (constant for each frame) + num_tex_coords=0 #int 7 The number of texture coordinates + num_faces=0 #int 8 The number of faces (polygons) + num_GL_commands=0 #int 9 The number of gl commands + num_frames=0 #int 10 The number of animation frames + offset_skins=0 #int 11 The offset in the file for the skin data + offset_tex_coords=0 #int 12 The offset in the file for the texture data + offset_faces=0 #int 13 The offset in the file for the face data + offset_frames=0 #int 14 The offset in the file for the frames data + offset_GL_commands=0#int 15 The offset in the file for the gl commands data + offset_end=0 #int 16 The end of the file offset + ''' + binary_format="<17i" #little-endian (<), 17 integers (17i) + + #md2 data objects + + def __init__ (self): + self.tex_coords=[] + self.faces=[] + self.frames=[] + self.skins=[] + + + def load (self, file): + temp_data = file.read(struct.calcsize(self.binary_format)) + data = struct.unpack(self.binary_format, temp_data) + + self.ident=data[0] + self.version=data[1] + + if (self.ident!=844121161 or self.version!=8): + print "Not a valid MD2 file" + Exit() + + self.skin_width=data[2] + self.skin_height=data[3] + self.frame_size=data[4] + + #make the # of skin objects for model + self.num_skins=data[5] + for i in xrange(0,self.num_skins): + self.skins.append(md2_skin()) + + self.num_vertices=data[6] + + #make the # of texture coordinates for model + self.num_tex_coords=data[7] + for i in xrange(0,self.num_tex_coords): + self.tex_coords.append(md2_tex_coord()) + + #make the # of triangle faces for model + self.num_faces=data[8] + for i in xrange(0,self.num_faces): + self.faces.append(md2_face()) + + self.num_GL_commands=data[9] + + #make the # of frames for the model + self.num_frames=data[10] + for i in xrange(0,self.num_frames): + self.frames.append(md2_alias_frame()) + #make the # of vertices for each frame + for j in xrange(0,self.num_vertices): + self.frames[i].vertices.append(md2_alias_triangle()) + + self.offset_skins=data[11] + self.offset_tex_coords=data[12] + self.offset_faces=data[13] + self.offset_frames=data[14] + self.offset_GL_commands=data[15] + + #load the skin info + file.seek(self.offset_skins,0) + for i in xrange(0, self.num_skins): + self.skins[i].load(file) + #self.skins[i].dump() + + #load the texture coordinates + file.seek(self.offset_tex_coords,0) + for i in xrange(0, self.num_tex_coords): + self.tex_coords[i].load(file) + #self.tex_coords[i].dump() + + #load the face info + file.seek(self.offset_faces,0) + for i in xrange(0, self.num_faces): + self.faces[i].load(file) + #self.faces[i].dump() + + #load the frames + file.seek(self.offset_frames,0) + for i in xrange(0, self.num_frames): + self.frames[i].load(file) + #self.frames[i].dump() + for j in xrange(0,self.num_vertices): + self.frames[i].vertices[j].load(file) + #self.frames[i].vertices[j].dump() + return self + + def dump (self): + print "Header Information" + print "ident: ", self.ident + print "version: ", self.version + print "skin width: ", self.skin_width + print "skin height: ", self.skin_height + print "frame size: ", self.frame_size + print "number of skins: ", self.num_skins + print "number of texture coordinates: ", self.num_tex_coords + print "number of faces: ", self.num_faces + print "number of frames: ", self.num_frames + print "number of vertices: ", self.num_vertices + print "offset skins: ", self.offset_skins + print "offset texture coordinates: ", self.offset_tex_coords + print "offset faces: ", self.offset_faces + print "offset frames: ",self.offset_frames + print "" + +###################################################### +# Import functions +###################################################### +def load_textures(md2, texture_filename): + #did the user specify a texture they wanted to use? + if texture_filename: + if (Blender.sys.exists(texture_filename)): + try: return Blender.Image.Load(texture_filename) + except: return -1 # could not load? + + #does the model have textures specified with it? + if int(md2.num_skins) > 0: + for i in xrange(0,md2.num_skins): + #md2.skins[i].dump() + if (Blender.sys.exists(md2.skins[i].name)): + try: return Blender.Image.Load(md2.skins[i].name) + except: return -1 + + +def animate_md2(md2, mesh): + ######### Animate the verts through keyframe animation + + # Fast access to the meshes vertex coords + verts = [v.co for v in mesh.verts] + scale = g_scale.val + + for i in xrange(1, md2.num_frames): + frame = md2.frames[i] + #update the vertices + for j in xrange(md2.num_vertices): + x=(frame.scale[0] * frame.vertices[j].vertices[0] + frame.translate[0]) * scale + y=(frame.scale[1] * frame.vertices[j].vertices[1] + frame.translate[1]) * scale + z=(frame.scale[2] * frame.vertices[j].vertices[2] + frame.translate[2]) * scale + + #put the vertex in the right spot + verts[j][:] = y,-x,z + + mesh.insertKey(i,"absolute") + # mesh.insertKey(i) + + #not really necissary, but I like playing with the frame counter + Blender.Set("curframe", i) + + + # Make the keys animate in the 3d view. + key = mesh.key + key.relative = False + + # Add an IPO to teh Key + ipo = Blender.Ipo.New('Key', 'md2') + key.ipo = ipo + # Add a curve to the IPO + curve = ipo.addCurve('Basis') + + # Add 2 points to cycle through the frames. + curve.append((1, 0)) + curve.append((md2.num_frames, (md2.num_frames-1)/10.0)) + curve.interpolation = Blender.IpoCurve.InterpTypes.LINEAR + + + +def load_md2(md2_filename, texture_filename): + #read the file in + file=open(md2_filename,"rb") + WaitCursor(1) + DrawProgressBar(0.0, 'Loading MD2') + md2=md2_obj() + md2.load(file) + #md2.dump() + file.close() + + ######### Creates a new mesh + mesh = Mesh.New() + + uv_coord=[] + #uv_list=[] + verts_extend = [] + #load the textures to use later + #-1 if there is no texture to load + mesh_image=load_textures(md2, texture_filename) + if mesh_image == -1 and texture_filename: + print 'MD2 Import, Warning, texture "%s" could not load' + + ######### Make the verts + DrawProgressBar(0.25,"Loading Vertex Data") + frame = md2.frames[0] + scale = g_scale.val + + def tmp_get_vertex(i): + #use the first frame for the mesh vertices + x=(frame.scale[0]*frame.vertices[i].vertices[0]+frame.translate[0])*scale + y=(frame.scale[1]*frame.vertices[i].vertices[1]+frame.translate[1])*scale + z=(frame.scale[2]*frame.vertices[i].vertices[2]+frame.translate[2])*scale + return y,-x,z + + mesh.verts.extend( [tmp_get_vertex(i) for i in xrange(0,md2.num_vertices)] ) + del tmp_get_vertex + + ######## Make the UV list + DrawProgressBar(0.50,"Loading UV Data") + + w = float(md2.skin_width) + h = float(md2.skin_height) + #for some reason quake2 texture maps are upside down, flip that + uv_list = [Vector(co.u/w, 1-(co.v/h)) for co in md2.tex_coords] + del w, h + + ######### Make the faces + DrawProgressBar(0.75,"Loading Face Data") + faces = [] + face_uvs = [] + for md2_face in md2.faces: + f = md2_face.vertex_index[0], md2_face.vertex_index[2], md2_face.vertex_index[1] + uv = uv_list[md2_face.texture_index[0]], uv_list[md2_face.texture_index[2]], uv_list[md2_face.texture_index[1]] + + if f[2] == 0: + # EEKADOODLE :/ + f= f[1], f[2], f[0] + uv= uv[1], uv[2], uv[0] + + #ditto in reverse order with the texture verts + faces.append(f) + face_uvs.append(uv) + + + face_mapping = mesh.faces.extend(faces, indexList=True) + print len(faces) + print len(mesh.faces) + mesh.faceUV= True #turn on face UV coordinates for this mesh + mesh_faces = mesh.faces + for i, uv in enumerate(face_uvs): + if face_mapping[i] != None: + f = mesh_faces[face_mapping[i]] + f.uv = uv + if (mesh_image!=-1): + f.image=mesh_image + + scn= Blender.Scene.GetCurrent() + mesh_obj= scn.objects.new(mesh) + animate_md2(md2, mesh) + DrawProgressBar(0.98,"Loading Animation Data") + + #locate the Object containing the mesh at the cursor location + cursor_pos=Blender.Window.GetCursorPos() + mesh_obj.setLocation(float(cursor_pos[0]),float(cursor_pos[1]),float(cursor_pos[2])) + DrawProgressBar (1.0, "") + WaitCursor(0) + +#*********************************************** +# MAIN +#*********************************************** + +# Import globals +g_md2_filename=Create("*.md2") +#g_md2_filename=Create("/d/warvet/tris.md2") +g_texture_filename=Create('') +# g_texture_filename=Create("/d/warvet/warvet.jpg") + +g_filename_search=Create("*.md2") +g_texture_search=Create('') +# g_texture_search=Create("/d/warvet/warvet.jpg") + +#Globals +g_scale=Create(1.0) + +# Events +EVENT_NOEVENT=1 +EVENT_LOAD_MD2=2 +EVENT_CHOOSE_FILENAME=3 +EVENT_CHOOSE_TEXTURE=4 +EVENT_SAVE_MD2=5 +EVENT_EXIT=100 + +###################################################### +# Callbacks for Window functions +###################################################### +def filename_callback(input_filename): + global g_md2_filename + g_md2_filename.val=input_filename + +def texture_callback(input_texture): + global g_texture_filename + g_texture_filename.val=input_texture + +###################################################### +# GUI Loader +###################################################### + + +def draw_gui(): + global g_scale + global g_md2_filename + global g_texture_filename + global EVENT_NOEVENT,EVENT_LOAD_MD2,EVENT_CHOOSE_FILENAME,EVENT_CHOOSE_TEXTURE,EVENT_EXIT + + ########## Titles + glClear(GL_COLOR_BUFFER_BIT) + glRasterPos2d(8, 125) + Text("MD2 loader") + + ######### Parameters GUI Buttons + BeginAlign() + g_md2_filename = String("MD2 file to load: ", EVENT_NOEVENT, 10, 55, 210, 18, + g_md2_filename.val, 255, "MD2 file to load") + ########## MD2 File Search Button + Button("Browse",EVENT_CHOOSE_FILENAME,220,55,80,18) + EndAlign() + + BeginAlign() + g_texture_filename = String("Texture file to load: ", EVENT_NOEVENT, 10, 35, 210, 18, + g_texture_filename.val, 255, "Texture file to load-overrides MD2 file") + ########## Texture Search Button + Button("Browse",EVENT_CHOOSE_TEXTURE,220,35,80,18) + EndAlign() + + ########## Scale slider-default is 1/8 which is a good scale for md2->blender + g_scale= Slider("Scale Factor: ", EVENT_NOEVENT, 10, 75, 210, 18, + 1.0, 0.001, 10.0, 1, "Scale factor for obj Model"); + + ######### Draw and Exit Buttons + Button("Load",EVENT_LOAD_MD2 , 10, 10, 80, 18) + Button("Exit",EVENT_EXIT , 170, 10, 80, 18) + +def event(evt, val): + if (evt == QKEY and not val): + Blender.Draw.Exit() + +def bevent(evt): + global g_md2_filename + global g_texture_filename + global EVENT_NOEVENT,EVENT_LOAD_MD2,EVENT_SAVE_MD2,EVENT_EXIT + + ######### Manages GUI events + if (evt==EVENT_EXIT): + Blender.Draw.Exit() + elif (evt==EVENT_CHOOSE_FILENAME): + FileSelector(filename_callback, "MD2 File Selection") + elif (evt==EVENT_CHOOSE_TEXTURE): + FileSelector(texture_callback, "Texture Selection") + elif (evt==EVENT_LOAD_MD2): + if not Blender.sys.exists(g_md2_filename.val): + PupMenu('Model file does not exist') + return + else: + load_md2(g_md2_filename.val, g_texture_filename.val) + Blender.Redraw() + Blender.Draw.Exit() + return + +if __name__ == '__main__': + Register(draw_gui, event, bevent) diff --git a/release/scripts/mesh_boneweight_copy.py b/release/scripts/mesh_boneweight_copy.py new file mode 100644 index 00000000000..8aa9a1e3213 --- /dev/null +++ b/release/scripts/mesh_boneweight_copy.py @@ -0,0 +1,287 @@ +#!BPY +""" +Name: 'Bone Weight Copy' +Blender: 243 +Group: 'Object' +Tooltip: 'Copy Bone Weights from 1 mesh, to all other selected meshes.' +""" + +__author__ = ["Campbell Barton"] +__url__ = ("blender", "elysiun", "http://members.iinet.net.au/~cpbarton/ideasman/") +__version__ = "0.1" +__bpydoc__ = """\ + +Bone Weight Copy + +This script is used to copy bone weights from 1 mesh with weights (the source mesh) to many (the target meshes). +Weights are copied from 1 mesh to another based on how close they are together. + +For normal operation, select 1 source mesh with vertex weights and any number of unweighted meshes that overlap the source mesh. +Then run this script using default options and check the new weigh. + + +A differnt way to use this script is to update the weights an an alredy weighted mesh. +this is done using the "Copy to Selected" option enabled and works a bit differently, +With the target mesh, select the verts you want to update. +since all meshes have weights we cant just use the weighted mesh as the source, +so the Active Object is used for the source mesh. +Run the script and the selected verts on all non active meshes will be updated. +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Campbell J Barton +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender +from Blender import Armature, Object, Mathutils, Window, Mesh +Vector= Mathutils.Vector +SMALL_NUM= 0.000001 +def copy_bone_influences(_from, _to, PREF_SEL_ONLY, PREF_NO_XCROSS): + ob_from, me_from, world_verts_from, from_groups= _from + ob_to, me_to, world_verts_to, dummy= _to + del dummy + + def getSnapIdx(seek_vec, vecs): + ''' + Returns the closest vec to snap_points + ''' + + # First seek the closest Z axis vert idx/v + seek_vec_x,seek_vec_y,seek_vec_z= seek_vec + + from_vec_idx= 0 + + len_vecs= len(vecs) + + upidx= len_vecs-1 + loidx= 0 + + while from_vec_idx < len_vecs and vecs[from_vec_idx][1].z < seek_vec_z: + from_vec_idx+=1 + + # Clamp if we overstepped. + if from_vec_idx >= len_vecs: + from_vec_idx-=1 + + close_dist= (vecs[from_vec_idx][1]-seek_vec).length + close_idx= vecs[from_vec_idx][0] + + upidx= from_vec_idx+1 + loidx= from_vec_idx-1 + + # Set uselo/useup. This means we can keep seeking up/down. + if upidx >= len_vecs: useup= False + else: useup= True + + if loidx < 0: uselo= False + else: uselo= True + + # Seek up/down to find the closest v to seek vec. + while uselo or useup: + if useup: + if upidx >= len_vecs: + useup= False + else: + i,v= vecs[upidx] + if (not PREF_NO_XCROSS) or ((v.x >= -SMALL_NUM and seek_vec_x >= -SMALL_NUM) or (v.x <= SMALL_NUM and seek_vec_x <= SMALL_NUM)): # enfoce xcrossing + if v.z-seek_vec_z > close_dist: + # the verticle distance is greater then the best distance sofar. we can stop looking up. + useup= False + elif abs(seek_vec_y-v.y) < close_dist and abs(seek_vec_x-v.x) < close_dist: + # This is in the limit measure it. + l= (seek_vec-v).length + if l= -SMALL_NUM and seek_vec_x >= -SMALL_NUM) or (v.x <= SMALL_NUM and seek_vec_x <= SMALL_NUM)): # enfoce xcrossing + if seek_vec_z-v.z > close_dist: + # the verticle distance is greater then the best distance sofar. we can stop looking up. + uselo= False + elif abs(seek_vec_y-v.y) < close_dist and abs(seek_vec_x-v.x) < close_dist: + # This is in the limit measure it. + l= (seek_vec-v).length + if l "%s" ' % (ob_from.name, ob_to.name)) + + from_idx= getSnapIdx(co, world_verts_from) + from_infs= me_from.getVertexInfluences(from_idx) + + for group, weight in from_infs: + + # Add where needed. + if PREF_SEL_ONLY and group not in to_groups: + me_to.addVertGroup(group) + to_groups.append(group) + + me_to.assignVertsToGroup(group, [i], weight, add_) + + me_to.update() + +# ZSORT return (i/co) tuples, used for fast seeking of the snapvert. +def worldspace_verts_idx(me, ob): + mat= ob.matrixWorld + verts_zsort= [ (i, v.co*mat) for i, v in enumerate(me.verts) ] + + # Sorts along the Z Axis so we can optimize the getsnap. + try: verts_zsort.sort(key = lambda a: a[1].z) + except: verts_zsort.sort(lambda a,b: cmp(a[1].z, b[1].z,)) + + return verts_zsort + + +def worldspace_verts(me, ob): + mat= ob.matrixWorld + return [ v.co*mat for v in me.verts ] + +def subdivMesh(me, subdivs): + oldmode = Mesh.Mode() + Mesh.Mode(Mesh.SelectModes['FACE']) + me.sel= 1 + for i in xrange(subdivs): + me.subdivide(0) + Mesh.Mode(oldmode) + + +def main(): + print '\nStarting BoneWeight Copy...' + scn= Blender.Scene.GetCurrent() + contextSel= Object.GetSelected() + if not contextSel: + Blender.Draw.PupMenu('Error%t|2 or more mesh objects need to be selected.|aborting.') + return + + PREF_QUALITY= Blender.Draw.Create(0) + PREF_NO_XCROSS= Blender.Draw.Create(0) + PREF_SEL_ONLY= Blender.Draw.Create(0) + + pup_block = [\ + ('Quality:', PREF_QUALITY, 0, 4, 'Generate interpolated verts for a higher quality result.'),\ + ('No X Crossing', PREF_NO_XCROSS, 'Do not snap across the zero X axis'),\ + '',\ + '"Update Selected" copies',\ + 'active object weights to',\ + 'selected verts on the other',\ + 'selected mesh objects.',\ + ('Update Selected', PREF_SEL_ONLY, 'Only copy new weights to selected verts on the target mesh. (use active object as source)'),\ + ] + + + if not Blender.Draw.PupBlock("Copy Weights for %i Meshs" % len(contextSel), pup_block): + return + + PREF_SEL_ONLY= PREF_SEL_ONLY.val + PREF_NO_XCROSS= PREF_NO_XCROSS.val + quality= PREF_QUALITY.val + + act_ob= scn.objects.active + if PREF_SEL_ONLY and act_ob==None: + Blender.Draw.PupMenu('Error%t|When dealing with 2 or more meshes with vgroups|There must be an active object|to be used as a source|aborting.') + return + + sel=[] + from_data= None + + for ob in contextSel: + if ob.type=='Mesh': + me= ob.getData(mesh=1) + groups= me.getVertGroupNames() + + # If this is the only mesh with a group OR if its one of many, but its active. + if groups and ((ob==act_ob and PREF_SEL_ONLY) or (not PREF_SEL_ONLY)): + if from_data: + Blender.Draw.PupMenu('More then 1 mesh has vertex weights, only select 1 mesh with weights. aborting.') + return + else: + # This uses worldspace_verts_idx which gets (idx,co) pairs, then zsorts. + if quality: + for _ob in contextSel: + _ob.sel=0 + ob.sel=1 + Object.Duplicate(mesh=1) + ob= scn.objects.active + me= ob.getData(mesh=1) + # groups will be the same + print '\tGenerating higher %ix quality weights.' % quality + subdivMesh(me, quality) + scn.unlink(ob) + from_data= (ob, me, worldspace_verts_idx(me, ob), groups) + + else: + data= (ob, me, worldspace_verts(me, ob), groups) + sel.append(data) + + if not from_data: + Blender.Draw.PupMenu('Error%t|No mesh with vertex groups found.') + return + + if not sel: + Blender.Draw.PupMenu('Error%t|Select 2 or more mesh objects, aborting.') + if quality: from_data[1].verts= None + return + + t= Blender.sys.time() + Window.WaitCursor(1) + + # Now do the copy. + print '\tCopying from "%s" to %i other mesh(es).' % (from_data[0].name, len(sel)) + for data in sel: + copy_bone_influences(from_data, data, PREF_SEL_ONLY, PREF_NO_XCROSS) + + # We cant unlink the mesh, but at least remove its data. + if quality: + from_data[1].verts= None + + print 'Copy Complete in %.6f sec' % (Blender.sys.time()-t) + Window.DrawProgressBar(1.0, '') + Window.WaitCursor(0) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/release/scripts/mesh_cleanup.py b/release/scripts/mesh_cleanup.py new file mode 100644 index 00000000000..1eb3e3968b2 --- /dev/null +++ b/release/scripts/mesh_cleanup.py @@ -0,0 +1,452 @@ +#!BPY +""" +Name: 'Clean Meshes' +Blender: 242 +Group: 'Mesh' +Tooltip: 'Clean unused data from all selected mesh objects.' +""" + +__author__ = ["Campbell Barton"] +__url__ = ("blender", "elysiun", "http://members.iinet.net.au/~cpbarton/ideasman/") +__version__ = "0.1" +__bpydoc__ = """\ +Clean Meshes + +Cleans unused data from selected meshes +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Campbell J Barton +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +from Blender import * +import bpy +from Blender.Mathutils import TriangleArea + +import Blender +import BPyMesh +dict2MeshWeight= BPyMesh.dict2MeshWeight +meshWeight2Dict= BPyMesh.meshWeight2Dict + +def rem_free_verts(me): + vert_users= [0] * len(me.verts) + for f in me.faces: + for v in f: + vert_users[v.index]+=1 + + for e in me.edges: + for v in e: # loop on edge verts + vert_users[v.index]+=1 + + verts_free= [i for i, users in enumerate(vert_users) if not users] + + if verts_free: + pass + me.verts.delete(verts_free) + return len(verts_free) + +def rem_free_edges(me, limit=None): + ''' Only remove based on limit if a limit is set, else remove all ''' + + edgeDict= {} # will use a set when python 2.4 is standard. + + for f in me.faces: + for edkey in f.edge_keys: + edgeDict[edkey] = None + + edges_free= [] + for e in me.edges: + if not edgeDict.has_key(e.key): + edges_free.append(e) + + if limit != None: + edges_free= [e for e in edges_free if e.length <= limit] + + me.edges.delete(edges_free) + return len(edges_free) + +def rem_area_faces(me, limit=0.001): + ''' Faces that have an area below the limit ''' + rem_faces= [f for f in me.faces if f.area <= limit] + if rem_faces: + me.faces.delete( 0, rem_faces ) + return len(rem_faces) + +def rem_perimeter_faces(me, limit=0.001): + ''' Faces whos combine edge length is below the limit ''' + def faceEdLen(f): + v= f.v + if len(v) == 3: + return\ + (v[0].co-v[1].co).length +\ + (v[1].co-v[2].co).length +\ + (v[2].co-v[0].co).length + else: # 4 + return\ + (v[0].co-v[1].co).length +\ + (v[1].co-v[2].co).length +\ + (v[2].co-v[3].co).length +\ + (v[3].co-v[0].co).length + rem_faces= [f for f in me.faces if faceEdLen(f) <= limit] + if rem_faces: + me.faces.delete( 0, rem_faces ) + return len(rem_faces) + +def rem_unused_materials(me): + materials= me.materials + len_materials= len(materials) + if len_materials < 2: + return 0 + + rem_materials= 0 + + material_users= dict( [(i,0) for i in xrange(len_materials)] ) + + for f in me.faces: + # Make sure the face index isnt too big. this happens sometimes. + if f.mat >= len_materials: + f.mat=0 + material_users[f.mat] += 1 + + mat_idx_subtract= 0 + reindex_mapping= dict( [(i,0) for i in xrange(len_materials)] ) + i= len_materials + while i: + i-=1 + + if material_users[i] == 0: + mat_idx_subtract+=1 + reindex_mapping[i]= mat_idx_subtract + materials.pop(i) + rem_materials+=1 + + for f in me.faces: + f.mat= f.mat - reindex_mapping[f.mat] + + me.materials= materials + return rem_materials + + +def rem_free_groups(me, groupNames, vWeightDict): + ''' cound how many vert users a group has and remove unused groups ''' + rem_groups = 0 + groupUserDict= dict([(group,0) for group in groupNames]) + + for vertexWeight in vWeightDict: + for group, weight in vertexWeight.iteritems(): + groupUserDict[group] += 1 + + i=len(groupNames) + while i: + i-=1 + group= groupNames[i] + if groupUserDict[group] == 0: + del groupNames[i] + print '\tremoving, vgroup', group + rem_groups+=1 + return rem_groups + +def rem_zero_weights(me, limit, groupNames, vWeightDict): + ''' remove verts from a group when their weight is zero.''' + rem_vweight_count= 0 + for vertexWeight in vWeightDict: + items= vertexWeight.items() + for group, weight in items: + if weight < limit: + del vertexWeight[group] + rem_vweight_count+= 1 + + return rem_vweight_count + + +def normalize_vweight(me, groupNames, vWeightDict): + for vertexWeight in vWeightDict: + unit= 0.0 + for group, weight in vertexWeight.iteritems(): + unit+= weight + + if unit != 1.0 and unit != 0.0: + for group, weight in vertexWeight.iteritems(): + vertexWeight[group]= weight/unit + +def isnan(f): + fstring = str(f).lower() + if 'nan' in fstring: + return True + if 'inf' in fstring: + return True + + return False + +def fix_nan_verts__internal(me): + rem_nan = 0 + for v in me.verts: + co = v.co + for i in (0,1,2): + if isnan(co[i]): + co[i] = 0.0 + rem_nan += 1 + return rem_nan + +def fix_nan_verts(me): + rem_nan = 0 + key = me.key + if key: + # Find the object, and get a mesh thats thinked to the oblink. + # this is a bit crap but needed to set the active key. + me_oblink = None + for ob in bpy.data.objects: + me_oblink = ob.getData(mesh=1) + if me_oblink == me: + me = me_oblink + break + if not me_oblink: + ob = None + + if key and ob: + blocks = key.blocks + # print blocks + orig_pin = ob.pinShape + orig_shape = ob.activeShape + orig_relative = key.relative + ob.pinShape = True + for i, block in enumerate(blocks): + ob.activeShape = i+1 + ob.makeDisplayList() + rem_nan += fix_nan_verts__internal(me) + me.update(block.name) # get the new verts + ob.pinShape = orig_pin + ob.activeShape = orig_shape + key.relative = orig_relative + + else: # No keys, simple operation + rem_nan = fix_nan_verts__internal(me) + + return rem_nan + +def fix_nan_uvs(me): + rem_nan = 0 + if me.faceUV: + orig_uvlayer = me.activeUVLayer + for uvlayer in me.getUVLayerNames(): + me.activeUVLayer = uvlayer + for f in me.faces: + for uv in f.uv: + for i in (0,1): + if isnan(uv[i]): + uv[i] = 0.0 + rem_nan += 1 + me.activeUVLayer = orig_uvlayer + return rem_nan + + +def has_vcol(me): + for f in me.faces: + for col in f.col: + if not (255 == col.r == col.g == col.b): + return True + return False + +def rem_white_vcol_layers(me): + vcols_removed = 0 + if me.vertexColors: + for col in me.getColorLayerNames(): + me.activeColorLayer = col + if not has_vcol(me): + me.removeColorLayer(col) + vcols_removed += 1 + + return vcols_removed + + +def main(): + sce= bpy.data.scenes.active + obsel= list(sce.objects.context) + actob= sce.objects.active + + is_editmode= Window.EditMode() + + # Edit mode object is not active, add it to the list. + if is_editmode and (not actob.sel): + obsel.append(actob) + + + #====================================# + # Popup menu to select the functions # + #====================================# + + CLEAN_ALL_DATA= Draw.Create(0) + CLEAN_VERTS_FREE= Draw.Create(1) + CLEAN_EDGE_NOFACE= Draw.Create(0) + CLEAN_EDGE_SMALL= Draw.Create(0) + CLEAN_FACE_PERIMETER= Draw.Create(0) + CLEAN_FACE_SMALL= Draw.Create(0) + + CLEAN_MATERIALS= Draw.Create(0) + CLEAN_WHITE_VCOL_LAYERS= Draw.Create(0) + CLEAN_GROUP= Draw.Create(0) + CLEAN_VWEIGHT= Draw.Create(0) + CLEAN_WEIGHT_NORMALIZE= Draw.Create(0) + limit= Draw.Create(0.01) + + CLEAN_NAN_VERTS= Draw.Create(0) + CLEAN_NAN_UVS= Draw.Create(0) + + # Get USER Options + + pup_block= [\ + ('Verts: free', CLEAN_VERTS_FREE, 'Remove verts that are not used by an edge or a face.'),\ + ('Edges: free', CLEAN_EDGE_NOFACE, 'Remove edges that are not in a face.'),\ + ('Edges: short', CLEAN_EDGE_SMALL, 'Remove edges that are below the length limit.'),\ + ('Faces: small perimeter', CLEAN_FACE_PERIMETER, 'Remove faces below the perimeter limit.'),\ + ('Faces: small area', CLEAN_FACE_SMALL, 'Remove faces below the area limit (may remove faces stopping T-face artifacts).'),\ + ('limit: ', limit, 0.001, 1.0, 'Limit for the area and length tests above (a higher limit will remove more data).'),\ + ('Material Clean', CLEAN_MATERIALS, 'Remove unused materials.'),\ + ('Color Layers', CLEAN_WHITE_VCOL_LAYERS, 'Remove vertex color layers that are totaly white'),\ + ('VGroup Clean', CLEAN_GROUP, 'Remove vertex groups that have no verts using them.'),\ + ('Weight Clean', CLEAN_VWEIGHT, 'Remove zero weighted verts from groups (limit is zero threshold).'),\ + ('WeightNormalize', CLEAN_WEIGHT_NORMALIZE, 'Make the sum total of vertex weights accross vgroups 1.0 for each vertex.'),\ + 'Clean NAN values',\ + ('NAN Verts', CLEAN_NAN_VERTS, 'Make NAN or INF verts (0,0,0)'),\ + ('NAN UVs', CLEAN_NAN_UVS, 'Make NAN or INF UVs (0,0)'),\ + '',\ + ('All Mesh Data', CLEAN_ALL_DATA, 'Warning! Operate on ALL mesh objects in your Blend file. Use with care'),\ + ] + + if not Draw.PupBlock('Clean Selected Meshes...', pup_block): + return + + CLEAN_VERTS_FREE= CLEAN_VERTS_FREE.val + CLEAN_EDGE_NOFACE= CLEAN_EDGE_NOFACE.val + CLEAN_EDGE_SMALL= CLEAN_EDGE_SMALL.val + CLEAN_FACE_PERIMETER= CLEAN_FACE_PERIMETER.val + CLEAN_FACE_SMALL= CLEAN_FACE_SMALL.val + CLEAN_MATERIALS= CLEAN_MATERIALS.val + CLEAN_WHITE_VCOL_LAYERS= CLEAN_WHITE_VCOL_LAYERS.val + CLEAN_GROUP= CLEAN_GROUP.val + CLEAN_VWEIGHT= CLEAN_VWEIGHT.val + CLEAN_WEIGHT_NORMALIZE= CLEAN_WEIGHT_NORMALIZE.val + limit= limit.val + CLEAN_ALL_DATA= CLEAN_ALL_DATA.val + CLEAN_NAN_VERTS= CLEAN_NAN_VERTS.val + CLEAN_NAN_UVS= CLEAN_NAN_UVS.val + + if is_editmode: Window.EditMode(0) + + if CLEAN_ALL_DATA: + if CLEAN_GROUP or CLEAN_VWEIGHT or CLEAN_WEIGHT_NORMALIZE: + # For groups we need the objects linked to the mesh + meshes= [ob.getData(mesh=1) for ob in bpy.data.objects if ob.type == 'Mesh' if not ob.lib] + else: + meshes= bpy.data.meshes + else: + meshes= [ob.getData(mesh=1) for ob in obsel if ob.type == 'Mesh'] + + tot_meshes = len(meshes) # so we can decrement libdata + rem_face_count= rem_edge_count= rem_vert_count= rem_material_count= rem_vcol_layer_count= rem_group_count= rem_vweight_count= fix_nan_vcount= fix_nan_uvcount= 0 + if not meshes: + if is_editmode: Window.EditMode(1) + Draw.PupMenu('No meshes to clean') + + Blender.Window.WaitCursor(1) + bpy.data.meshes.tag = False + for me in meshes: + + # Dont touch the same data twice + if me.tag: + tot_meshes -= 1 + continue + me.tag = True + + if me.lib: + tot_meshes -= 1 + continue + + if me.multires: + multires_level_orig = me.multiresDrawLevel + me.multiresDrawLevel = 1 + print 'Warning, cannot perform destructive operations on multires mesh:', me.name + else: + if CLEAN_FACE_SMALL: + rem_face_count += rem_area_faces(me, limit) + + if CLEAN_FACE_PERIMETER: + rem_face_count += rem_perimeter_faces(me, limit) + + if CLEAN_EDGE_SMALL: # for all use 2- remove all edges. + rem_edge_count += rem_free_edges(me, limit) + + if CLEAN_EDGE_NOFACE: + rem_edge_count += rem_free_edges(me) + + if CLEAN_VERTS_FREE: + rem_vert_count += rem_free_verts(me) + + if CLEAN_MATERIALS: + rem_material_count += rem_unused_materials(me) + + if CLEAN_WHITE_VCOL_LAYERS: + rem_vcol_layer_count += rem_white_vcol_layers(me) + + if CLEAN_VWEIGHT or CLEAN_GROUP or CLEAN_WEIGHT_NORMALIZE: + groupNames, vWeightDict= meshWeight2Dict(me) + + if CLEAN_VWEIGHT: + rem_vweight_count += rem_zero_weights(me, limit, groupNames, vWeightDict) + + if CLEAN_GROUP: + rem_group_count += rem_free_groups(me, groupNames, vWeightDict) + pass + + if CLEAN_WEIGHT_NORMALIZE: + normalize_vweight(me, groupNames, vWeightDict) + + # Copy back to mesh vertex groups. + dict2MeshWeight(me, groupNames, vWeightDict) + + if CLEAN_NAN_VERTS: + fix_nan_vcount = fix_nan_verts(me) + + if CLEAN_NAN_UVS: + fix_nan_uvcount = fix_nan_uvs(me) + + # restore multires. + if me.multires: + me.multiresDrawLevel = multires_level_orig + + Blender.Window.WaitCursor(0) + if is_editmode: Window.EditMode(0) + stat_string= 'Removed from ' + str(tot_meshes) + ' Mesh(es)%t|' + + if CLEAN_VERTS_FREE: stat_string+= 'Verts: %i|' % rem_vert_count + if CLEAN_EDGE_SMALL or CLEAN_EDGE_NOFACE: stat_string+= 'Edges: %i|' % rem_edge_count + if CLEAN_FACE_SMALL or CLEAN_FACE_PERIMETER: stat_string+= 'Faces: %i|' % rem_face_count + if CLEAN_MATERIALS: stat_string+= 'Materials: %i|' % rem_material_count + if CLEAN_WHITE_VCOL_LAYERS: stat_string+= 'Color Layers: %i|' % rem_vcol_layer_count + if CLEAN_VWEIGHT: stat_string+= 'VWeights: %i|' % rem_vweight_count + if CLEAN_GROUP: stat_string+= 'VGroups: %i|' % rem_group_count + if CLEAN_NAN_VERTS: stat_string+= 'Vert Nan Fix: %i|' % fix_nan_vcount + if CLEAN_NAN_UVS: stat_string+= 'UV Nan Fix: %i|' % fix_nan_uvcount + Draw.PupMenu(stat_string) + + +if __name__ == '__main__': + main() diff --git a/release/scripts/mesh_edges2curves.py b/release/scripts/mesh_edges2curves.py new file mode 100644 index 00000000000..fdf61298ebc --- /dev/null +++ b/release/scripts/mesh_edges2curves.py @@ -0,0 +1,174 @@ +#!BPY +""" Registration info for Blender menus: +Name: 'Edges to Curve' +Blender: 241 +Group: 'Mesh' +Tip: 'Edges not used by a face are converted into polyline(s)' +""" +__author__ = ("Campbell Barton") +__url__ = ("blender", "elysiun") +__version__ = "1.0 2006/02/08" + +__bpydoc__ = """\ +Edges to Curves + +This script converts open and closed edge loops into polylines + +Supported:
+ Polylines where each vert has no more then 2 edges attached to it. +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Campbell J Barton +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +from Blender import * + +def edkey(ed): + i1 = ed.v1.index + i2 = ed.v2.index + if i1>i2: + return (i2,i1), ed + else: + return (i1,i2), ed + +def polysFromMesh(me): + # a polyline is 2 + #polylines are a list + polyLines = [] + + # Get edges not used by a face + edgeDict= dict([ (ed.key, ed) for ed in me.edges ]) + for f in me.faces: + for key in f.edge_keys: + try: + del edgeDict[key] + except: + pass + + edges= edgeDict.values() + + + while edges: + currentEdge= edges.pop() + startVert= currentEdge.v2 + endVert= currentEdge.v1 + polyLine= [startVert, endVert] + ok= 1 + while ok: + ok= 0 + #for i, ed in enumerate(edges): + i=len(edges) + while i: + i-=1 + ed= edges[i] + if ed.v1 == endVert: + polyLine.append(ed.v2) + endVert= polyLine[-1] + ok=1 + del edges[i] + #break + elif ed.v2 == endVert: + polyLine.append(ed.v1) + endVert= polyLine[-1] + ok=1 + del edges[i] + #break + elif ed.v1 == startVert: + polyLine.insert(0, ed.v2) + startVert= polyLine[0] + ok=1 + del edges[i] + #break + elif ed.v2 == startVert: + polyLine.insert(0, ed.v1) + startVert= polyLine[0] + ok=1 + del edges[i] + #break + polyLines.append((polyLine, polyLine[0]==polyLine[-1])) + # print len(edges), len(polyLines) + return polyLines + + +def mesh2polys(): + scn= Scene.GetCurrent() + scn.objects.selected = [] + + meshOb= scn.objects.active + if meshOb==None or meshOb.type != 'Mesh': + Draw.PupMenu( 'ERROR: No Active Mesh Selected, Aborting' ) + return + Window.WaitCursor(1) + Window.EditMode(0) + me = meshOb.getData(mesh=1) + polygons= polysFromMesh(me) + w=t=1 + cu= Curve.New() + cu.name = me.name + cu.setFlag(1) + + ob = scn.objects.active = scn.objects.new(cu) + ob.setMatrix(meshOb.matrixWorld) + + i=0 + for poly, closed in polygons: + if closed: + vIdx= 1 + else: + vIdx= 0 + + v= poly[vIdx] + cu.appendNurb([v.co.x, v.co.y, v.co.z, w, t]) + cu[i].type= 0 # Poly Line + + # Close the polyline if its closed. + if closed: + cu[i].setFlagU(1) + + # Add all the points in the polyline. + while vIdx 0] + + else: + # Use a small margin verts must be outside before we mirror them. + neg_vts = [v for v in me.verts if v.sel if v.co.x < -PREF_XZERO_THRESH] + pos_vts = [v for v in me.verts if v.sel if v.co.x > PREF_XZERO_THRESH] + + + + #*Mirror Location*********************************************************# + if PREF_MIRROR_LOCATION: + mirror_pairs= [] + # allign the negative with the positive. + flipvec= Mathutils.Vector() + len_neg_vts= float(len(neg_vts)) + for i1, nv in enumerate(neg_vts): + if nv.sel: # we may alredy be mirrored, if so well be deselected + nv_co= nv.co + for i2, pv in enumerate(pos_vts): + if pv.sel: + # Enforce edge users. + if not PREF_EDGE_USERS or edge_users[i1]==edge_users[i2]: + flipvec[:]= pv.co + flipvec.x= -flipvec.x + l= (nv_co-flipvec).length + + if l==0.0: # Both are alredy mirrored so we dont need to think about them. + # De-Select so we dont use again/ + pv.sel= nv.sel= 0 + + # Record a match. + elif l<=PREF_MAX_DIST: + + # We can adjust the length by the normal, now we know the length is under the limit. + # DISABLED, WASNT VERY USEFULL + ''' + if PREF_NOR_WEIGHT>0: + # Get the normal and flipm reuse flipvec + flipvec[:]= pv.no + flipvec.x= -flipvec.x + try: + ang= Mathutils.AngleBetweenVecs(nv.no, flipvec)/180.0 + except: # on rare occasions angle between vecs will fail.- zero length vec. + ang= 0 + + l=l*(1+(ang*PREF_NOR_WEIGHT)) + ''' + # Record the pairs for sorting to see who will get joined + mirror_pairs.append((l, nv, pv)) + + # Update every 20 loops + if i1 % 10 == 0: + Window.DrawProgressBar(0.8 * (i1/len_neg_vts), 'Mirror verts %i of %i' % (i1, len_neg_vts)) + + Window.DrawProgressBar(0.9, 'Mirror verts: Updating locations') + + # Now we have a list of the pairs we might use, lets find the best and do them first. + # de-selecting as we go. so we can makke sure not to mess it up. + try: mirror_pairs.sort(key = lambda a: a[0]) + except: mirror_pairs.sort(lambda a,b: cmp(a[0], b[0])) + + for dist, v1,v2 in mirror_pairs: # dist, neg, pos + if v1.sel and v2.sel: + if PREF_MODE==0: # Middle + flipvec[:]= v2.co # positive + flipvec.x= -flipvec.x # negatve + v2.co= v1.co= (flipvec+v1.co)*0.5 # midway + v2.co.x= -v2.co.x + elif PREF_MODE==2: # Left + v2.co= v1.co + v2.co.x= -v2.co.x + elif PREF_MODE==1: # Right + v1.co= v2.co + v1.co.x= -v1.co.x + v1.sel= v2.sel= 0 + + + #*Mirror Weights**********************************************************# + if PREF_MIRROR_WEIGHTS: + + groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me) + mirror_pairs_l2r= [] # Stor a list of matches for these verts. + mirror_pairs_r2l= [] # Stor a list of matches for these verts. + + # allign the negative with the positive. + flipvec= Mathutils.Vector() + len_neg_vts= float(len(neg_vts)) + + # Here we make a tuple to look through, if were middle well need to look through both. + if PREF_MODE==0: # Middle + find_set= ((neg_vts, pos_vts, mirror_pairs_l2r), (pos_vts, neg_vts, mirror_pairs_r2l)) + elif PREF_MODE==1: # Left + find_set= ((neg_vts, pos_vts, mirror_pairs_l2r), ) + elif PREF_MODE==2: # Right + find_set= ((pos_vts, neg_vts, mirror_pairs_r2l), ) + + + # Do a locational lookup again :/ - This isnt that good form but if we havnt mirrored weights well need to do it anyway. + # The Difference with this is that we dont need to have 1:1 match for each vert- just get each vert to find another mirrored vert + # and use its weight. + # Use "find_set" so we can do a flipped search L>R and R>L without duplicate code. + for vtls_A, vtls_B, pair_ls in find_set: + for i1, vA in enumerate(vtls_A): + best_len=1<<30 # BIGNUM + best_idx=-1 + + # Find the BEST match + vA_co= vA.co + for i2, vB in enumerate(vtls_B): + # Enforce edge users. + if not PREF_EDGE_USERS or edge_users[i1]==edge_users[i2]: + flipvec[:]= vB.co + flipvec.x= -flipvec.x + l= (vA_co-flipvec).length + + if l Right', PREF_MODE_L2R, 'Copy from the Left to Right of the mesh. Enable Both for a mid loc/weight.'),\ + ('Right > Left', PREF_MODE_R2L, 'Copy from the Right to Left of the mesh. Enable Both for a mid loc/weight.'),\ + '',\ + ('MaxDist:', PREF_MAX_DIST, 0.0, 1.0, 'Generate interpolated verts so closer vert weights can be copied.'),\ + ('XZero limit:', PREF_XZERO_THRESH, 0.0, 1.0, 'Mirror verts above this distance from the middle, else lock to X/zero.'),\ + ('Sel Verts Only', PREF_SEL_ONLY, 'Only mirror selected verts. Else try and mirror all'),\ + ('Edge Users', PREF_EDGE_USERS, 'Only match up verts that have the same number of edge users.'),\ + 'Location Prefs',\ + ('Mirror Location', PREF_MIRROR_LOCATION, 'Mirror vertex locations.'),\ + ('XMidSnap Verts', PREF_XMID_SNAP, 'Snap middle verts to X Zero (uses XZero limit)'),\ + 'Weight Prefs',\ + ('Mirror Weights', PREF_MIRROR_WEIGHTS, 'Mirror vertex locations.'),\ + ('Flip Groups', PREF_FLIP_NAMES, 'Mirror flip names.'),\ + ('New Flip Groups', PREF_CREATE_FLIP_NAMES, 'Make new groups for flipped names.'),\ + ] + + if not Draw.PupBlock("X Mirror mesh tool", pup_block): + return + + # WORK OUT THE MODE 0 + # PREF_MODE, 0:middle, 1: Left. 2:Right. + PREF_MODE_R2L= PREF_MODE_R2L.val + PREF_MODE_L2R= PREF_MODE_L2R.val + + if PREF_MODE_R2L and PREF_MODE_L2R: + PREF_MODE= 0 # Middle + elif not PREF_MODE_R2L and PREF_MODE_L2R: + PREF_MODE= 1 # Left to Right + elif PREF_MODE_R2L and not PREF_MODE_L2R: + PREF_MODE= 2 # Right to Left + else: # Neither Selected. Do middle anyway + PREF_MODE= 0 + + + PREF_EDITMESH_ONLY= PREF_EDITMESH_ONLY.val + PREF_MIRROR_LOCATION= PREF_MIRROR_LOCATION.val + PREF_XMID_SNAP= PREF_XMID_SNAP.val + PREF_MAX_DIST= PREF_MAX_DIST.val + PREF_XZERO_THRESH= PREF_XZERO_THRESH.val + PREF_SEL_ONLY= PREF_SEL_ONLY.val + PREF_EDGE_USERS= PREF_EDGE_USERS.val + # weights + PREF_MIRROR_WEIGHTS= PREF_MIRROR_WEIGHTS.val + PREF_FLIP_NAMES= PREF_FLIP_NAMES.val + PREF_CREATE_FLIP_NAMES= PREF_CREATE_FLIP_NAMES.val + + t= sys.time() + + is_editmode = Window.EditMode() # Exit Editmode. + if is_editmode: Window.EditMode(0) + Mesh.Mode(Mesh.SelectModes['VERTEX']) + Window.WaitCursor(1) + + if act_ob: + mesh_mirror(act_ob.getData(mesh=1), PREF_MIRROR_LOCATION, PREF_XMID_SNAP, PREF_MAX_DIST, PREF_XZERO_THRESH, PREF_MODE, PREF_SEL_ONLY, PREF_EDGE_USERS, PREF_MIRROR_WEIGHTS, PREF_FLIP_NAMES, PREF_CREATE_FLIP_NAMES) + if (not PREF_EDITMESH_ONLY) and sel: + for ob in sel: + mesh_mirror(ob.getData(mesh=1), PREF_MIRROR_LOCATION, PREF_XMID_SNAP, PREF_MAX_DIST, PREF_XZERO_THRESH, PREF_MODE, PREF_SEL_ONLY, PREF_EDGE_USERS, PREF_MIRROR_WEIGHTS, PREF_FLIP_NAMES, PREF_CREATE_FLIP_NAMES) + + if is_editmode: Window.EditMode(1) + Window.WaitCursor(0) + Window.DrawProgressBar(1.0, '') + Window.RedrawAll() + + print 'Mirror done in %.6f sec.' % (sys.time()-t) + +if __name__ == '__main__': + main() diff --git a/release/scripts/mesh_poly_reduce.py b/release/scripts/mesh_poly_reduce.py new file mode 100644 index 00000000000..9d8bb61f652 --- /dev/null +++ b/release/scripts/mesh_poly_reduce.py @@ -0,0 +1,143 @@ +#!BPY +""" +Name: 'Poly Reducer' +Blender: 243 +Group: 'Mesh' +Tooltip: 'Removed polygons from a mesh while maintaining the shape, textures and weights.' +""" + +__author__ = "Campbell Barton" +__url__ = ("blender", "elysiun") +__version__ = "1.0 2006/02/07" + +__bpydoc__ = """\ +This script simplifies the mesh by removing faces, keeping the overall shape of the mesh. +""" + +from Blender import Draw, Window, Scene, Mesh, Mathutils, sys, Object +import BPyMesh +# reload(BPyMesh) +import BPyMessages + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Campbell J Barton +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +def main(): + scn = Scene.GetCurrent() + act_ob= scn.objects.active + if not act_ob or act_ob.type != 'Mesh': + BPyMessages.Error_NoMeshActive() + return + + act_me= act_ob.getData(mesh=1) + + if act_me.multires: + BPyMessages.Error_NoMeshMultiresEdit() + return + + act_group= act_me.activeGroup + if not act_group: act_group= '' + + + # Defaults + PREF_REDUX= Draw.Create(0.5) + PREF_BOUNDRY_WEIGHT= Draw.Create(5.0) + PREF_REM_DOUBLES= Draw.Create(1) + PREF_FACE_AREA_WEIGHT= Draw.Create(1.0) + PREF_FACE_TRIANGULATE= Draw.Create(1) + + VGROUP_INF_ENABLE= Draw.Create(0) + VGROUP_INF_REDUX= Draw.Create(act_group) + VGROUP_INF_WEIGHT= Draw.Create(10.0) + + PREF_DO_UV= Draw.Create(1) + PREF_DO_VCOL= Draw.Create(1) + PREF_DO_WEIGHTS= Draw.Create(1) + PREF_OTHER_SEL_OBS= Draw.Create(0) + + pup_block = [\ + ('Poly Reduce:', PREF_REDUX, 0.05, 0.95, 'Scale the meshes poly count by this value.'),\ + ('Boundry Weight:', PREF_BOUNDRY_WEIGHT, 0.0, 20.0, 'Weight boundry verts by this scale, 0.0 for no boundry weighting.'),\ + ('Area Weight:', PREF_FACE_AREA_WEIGHT, 0.0, 20.0, 'Collapse edges effecting lower area faces first.'),\ + ('Triangulate', PREF_FACE_TRIANGULATE, 'Convert quads to tris before reduction, for more choices of edges to collapse.'),\ + '',\ + ('VGroup Weighting', VGROUP_INF_ENABLE, 'Use a vertex group to influence the reduction, higher weights for higher quality '),\ + ('vgroup name: ', VGROUP_INF_REDUX, 0, 32, 'The name of the vertex group to use for the weight map'),\ + ('vgroup mult: ', VGROUP_INF_WEIGHT, 0.0, 100.0, 'How much to make the weight effect the reduction'),\ + ('Other Selected Obs', PREF_OTHER_SEL_OBS, 'reduce other selected objects.'),\ + '',\ + '',\ + '',\ + ('UV Coords', PREF_DO_UV, 'Interpolate UV Coords.'),\ + ('Vert Colors', PREF_DO_VCOL, 'Interpolate Vertex Colors'),\ + ('Vert Weights', PREF_DO_WEIGHTS, 'Interpolate Vertex Weights'),\ + ('Remove Doubles', PREF_REM_DOUBLES, 'Remove doubles before reducing to avoid boundry tearing.'),\ + ] + + if not Draw.PupBlock("Poly Reducer", pup_block): + return + + PREF_REDUX= PREF_REDUX.val + PREF_BOUNDRY_WEIGHT= PREF_BOUNDRY_WEIGHT.val + PREF_REM_DOUBLES= PREF_REM_DOUBLES.val + PREF_FACE_AREA_WEIGHT= PREF_FACE_AREA_WEIGHT.val + PREF_FACE_TRIANGULATE= PREF_FACE_TRIANGULATE.val + + VGROUP_INF_ENABLE= VGROUP_INF_ENABLE.val + VGROUP_INF_WEIGHT= VGROUP_INF_WEIGHT.val + + if VGROUP_INF_ENABLE and VGROUP_INF_WEIGHT: + VGROUP_INF_REDUX= VGROUP_INF_REDUX.val + else: + VGROUP_INF_WEIGHT= 0.0 + VGROUP_INF_REDUX= None + + + PREF_DO_UV= PREF_DO_UV.val + PREF_DO_VCOL= PREF_DO_VCOL.val + PREF_DO_WEIGHTS= PREF_DO_WEIGHTS.val + PREF_OTHER_SEL_OBS= PREF_OTHER_SEL_OBS.val + + + t= sys.time() + + is_editmode = Window.EditMode() # Exit Editmode. + if is_editmode: Window.EditMode(0) + Window.WaitCursor(1) + print 'reducing:', act_ob.name, act_ob.getData(1) + BPyMesh.redux(act_ob, PREF_REDUX, PREF_BOUNDRY_WEIGHT, PREF_REM_DOUBLES, PREF_FACE_AREA_WEIGHT, PREF_FACE_TRIANGULATE, PREF_DO_UV, PREF_DO_VCOL, PREF_DO_WEIGHTS, VGROUP_INF_REDUX, VGROUP_INF_WEIGHT) + + if PREF_OTHER_SEL_OBS: + for ob in scn.objects.context: + if ob.type == 'Mesh' and ob != act_ob: + print 'reducing:', ob.name, ob.getData(1) + BPyMesh.redux(ob, PREF_REDUX, PREF_BOUNDRY_WEIGHT, PREF_REM_DOUBLES, PREF_FACE_AREA_WEIGHT, PREF_FACE_TRIANGULATE, PREF_DO_UV, PREF_DO_VCOL, PREF_DO_WEIGHTS, VGROUP_INF_REDUX, VGROUP_INF_WEIGHT) + Window.RedrawAll() + + if is_editmode: Window.EditMode(1) + Window.WaitCursor(0) + Window.RedrawAll() + + print 'Reduction done in %.6f sec.' % (sys.time()-t) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/release/scripts/mesh_skin.py b/release/scripts/mesh_skin.py new file mode 100644 index 00000000000..fdb721bc9f3 --- /dev/null +++ b/release/scripts/mesh_skin.py @@ -0,0 +1,639 @@ +#!BPY + +""" +Name: 'Skin Faces/Edge-Loops' +Blender: 243 +Group: 'MeshFaceKey' +Tooltip: 'Select 2 vert loops, then run this script.' +""" + +__author__ = "Campbell Barton AKA Ideasman" +__url__ = ["blenderartists.org", "www.blender.org"] +__version__ = "1.1 2006/12/26" + +__bpydoc__ = """\ +With this script vertex loops can be skinned: faces are created to connect the +selected loops of vertices. + +Usage: + +In mesh Edit mode select the vertices of the loops (closed paths / curves of +vertices: circles, for example) that should be skinned, then run this script. +A pop-up will provide further options, if the results of a method are not adequate try one of the others. +""" + + +# $Id$ +# +# -------------------------------------------------------------------------- +# Skin Selected edges 1.0 By Campbell Barton (AKA Ideasman) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +# Made by Ideasman/Campbell 2005/06/15 - cbarton@metavr.com + +import Blender +import bpy +from Blender import Window +from Blender.Mathutils import MidpointVecs, Vector, CrossVecs +from Blender.Mathutils import AngleBetweenVecs as _AngleBetweenVecs_ +import BPyMessages + +from Blender.Draw import PupMenu + +BIG_NUM = 1<<30 + +global CULL_METHOD +CULL_METHOD = 0 + +def AngleBetweenVecs(a1,a2): + try: + return _AngleBetweenVecs_(a1,a2) + except: + return 180.0 + +class edge(object): + __slots__ = 'v1', 'v2', 'co1', 'co2', 'length', 'removed', 'match', 'cent', 'angle', 'next', 'prev', 'normal', 'fake' + def __init__(self, v1,v2): + self.v1 = v1 + self.v2 = v2 + co1, co2= v1.co, v2.co + self.co1= co1 + self.co2= co2 + + # uv1 uv2 vcol1 vcol2 # Add later + self.length = (co1 - co2).length + self.removed = 0 # Have we been culled from the eloop + self.match = None # The other edge were making a face with + + self.cent= MidpointVecs(co1, co2) + self.angle= 0.0 + self.fake= False + +class edgeLoop(object): + __slots__ = 'centre', 'edges', 'normal', 'closed', 'backup_edges' + def __init__(self, loop, me, closed): # Vert loop + # Use next and prev, nextDist, prevDist + + # Get Loops centre. + fac= len(loop) + verts = me.verts + self.centre= reduce(lambda a,b: a+verts[b].co/fac, loop, Vector()) + + # Convert Vert loop to Edges. + self.edges = [edge(verts[loop[vIdx-1]], verts[loop[vIdx]]) for vIdx in xrange(len(loop))] + + if not closed: + self.edges[0].fake = True # fake edge option + + self.closed = closed + + + # Assign linked list + for eIdx in xrange(len(self.edges)-1): + self.edges[eIdx].next = self.edges[eIdx+1] + self.edges[eIdx].prev = self.edges[eIdx-1] + # Now last + self.edges[-1].next = self.edges[0] + self.edges[-1].prev = self.edges[-2] + + + + # GENERATE AN AVERAGE NORMAL FOR THE WHOLE LOOP. + self.normal = Vector() + for e in self.edges: + n = CrossVecs(self.centre-e.co1, self.centre-e.co2) + # Do we realy need tot normalize? + n.normalize() + self.normal += n + + # Generate the angle + va= e.cent - e.prev.cent + vb= e.next.cent - e.cent + + e.angle= AngleBetweenVecs(va, vb) + + # Blur the angles + #for e in self.edges: + # e.angle= (e.angle+e.next.angle)/2 + + # Blur the angles + #for e in self.edges: + # e.angle= (e.angle+e.prev.angle)/2 + + self.normal.normalize() + + # Generate a normal for each edge. + for e in self.edges: + + n1 = e.co1 + n2 = e.co2 + n3 = e.prev.co1 + + a = n1-n2 + b = n1-n3 + normal1 = CrossVecs(a,b) + normal1.normalize() + + n1 = e.co2 + n3 = e.next.co2 + n2 = e.co1 + + a = n1-n2 + b = n1-n3 + + normal2 = CrossVecs(a,b) + normal2.normalize() + + # Reuse normal1 var + normal1 += normal1 + normal2 + normal1.normalize() + + e.normal = normal1 + #print e.normal + + + + def backup(self): + # Keep a backup of the edges + self.backup_edges = self.edges[:] + + def restore(self): + self.edges = self.backup_edges[:] + for e in self.edges: + e.removed = 0 + + def reverse(self): + self.edges.reverse() + self.normal.negate() + + for e in self.edges: + e.normal.negate() + e.v1, e.v2 = e.v2, e.v1 + e.co1, e.co2 = e.co2, e.co1 + e.next, e.prev = e.prev, e.next + + + def removeSmallest(self, cullNum, otherLoopLen): + ''' + Removes N Smallest edges and backs up the loop, + this is so we can loop between 2 loops as if they are the same length, + backing up and restoring incase the loop needs to be skinned with another loop of a different length. + ''' + global CULL_METHOD + if CULL_METHOD == 1: # Shortest edge + eloopCopy = self.edges[:] + + # Length sort, smallest first + try: eloopCopy.sort(key = lambda e1: e1.length) + except: eloopCopy.sort(lambda e1, e2: cmp(e1.length, e2.length )) + + # Dont use atm + #eloopCopy.sort(lambda e1, e2: cmp(e1.angle*e1.length, e2.angle*e2.length)) # Length sort, smallest first + #eloopCopy.sort(lambda e1, e2: cmp(e1.angle, e2.angle)) # Length sort, smallest first + + remNum = 0 + for i, e in enumerate(eloopCopy): + if not e.fake: + e.removed = 1 + self.edges.remove( e ) # Remove from own list, still in linked list. + remNum += 1 + + if not remNum < cullNum: + break + + else: # CULL METHOD is even + + culled = 0 + + step = int(otherLoopLen / float(cullNum)) * 2 + + currentEdge = self.edges[0] + while culled < cullNum: + + # Get the shortest face in the next STEP + step_count= 0 + bestAng= 360.0 + smallestEdge= None + while step_count<=step or smallestEdge==None: + step_count+=1 + if not currentEdge.removed: # 0 or -1 will not be accepted + if currentEdge.angle 2: + return None + + vert_used[i] = True + + # do an edgeloop seek + if len(sbl) == 2: + contextVertLoop= [sbl[0], i, sbl[1]] # start the vert loop + vert_used[contextVertLoop[ 0]] = True + vert_used[contextVertLoop[-1]] = True + else: + contextVertLoop= [i, sbl[0]] + vert_used[contextVertLoop[ 1]] = True + + # Always seek up + ok = True + while ok: + ok = False + closed = False + sbl = vert_siblings[contextVertLoop[-1]] + if len(sbl) == 2: + next = sbl[not sbl.index( contextVertLoop[-2] )] + if vert_used[next]: + closed = True + # break + else: + contextVertLoop.append( next ) # get the vert that isnt the second last + vert_used[next] = True + ok = True + + # Seek down as long as the starting vert was not at the edge. + if not closed and len(vert_siblings[i]) == 2: + + ok = True + while ok: + ok = False + sbl = vert_siblings[contextVertLoop[0]] + if len(sbl) == 2: + next = sbl[not sbl.index( contextVertLoop[1] )] + if vert_used[next]: + closed = True + else: + contextVertLoop.insert(0, next) # get the vert that isnt the second last + vert_used[next] = True + ok = True + + mainVertLoops.append((contextVertLoop, closed)) + + + verts = me.verts + # convert from indicies to verts + # mainVertLoops = [([verts[i] for i in contextVertLoop], closed) for contextVertLoop, closed in mainVertLoops] + # print len(mainVertLoops) + return mainVertLoops + + + +def skin2EdgeLoops(eloop1, eloop2, me, ob, MODE): + + new_faces= [] # + + # Make sure e1 loops is bigger then e2 + if len(eloop1.edges) != len(eloop2.edges): + if len(eloop1.edges) < len(eloop2.edges): + eloop1, eloop2 = eloop2, eloop1 + + eloop1.backup() # were about to cull faces + CULL_FACES = len(eloop1.edges) - len(eloop2.edges) + eloop1.removeSmallest(CULL_FACES, len(eloop1.edges)) + else: + CULL_FACES = 0 + # First make sure poly vert loops are in sync with eachother. + + # The vector allong which we are skinning. + skinVector = eloop1.centre - eloop2.centre + + loopDist = skinVector.length + + # IS THE LOOP FLIPPED, IF SO FLIP BACK. we keep it flipped, its ok, + if eloop1.closed or eloop2.closed: + angleBetweenLoopNormals = AngleBetweenVecs(eloop1.normal, eloop2.normal) + if angleBetweenLoopNormals > 90: + eloop2.reverse() + + + DIR= eloop1.centre - eloop2.centre + + # if eloop2.closed: + bestEloopDist = BIG_NUM + bestOffset = 0 + # Loop rotation offset to test.1 + eLoopIdxs = range(len(eloop1.edges)) + for offset in xrange(len(eloop1.edges)): + totEloopDist = 0 # Measure this total distance for thsi loop. + + offsetIndexLs = eLoopIdxs[offset:] + eLoopIdxs[:offset] # Make offset index list + + + # e1Idx is always from 0uu to N, e2Idx is offset. + for e1Idx, e2Idx in enumerate(offsetIndexLs): + e1= eloop1.edges[e1Idx] + e2= eloop2.edges[e2Idx] + + + # Include fan connections in the measurement. + OK= True + while OK or e1.removed: + OK= False + + # Measure the vloop distance =============== + diff= ((e1.cent - e2.cent).length) #/ nangle1 + + ed_dir= e1.cent-e2.cent + a_diff= AngleBetweenVecs(DIR, ed_dir)/18 # 0 t0 18 + + totEloopDist += (diff * (1+a_diff)) / (1+loopDist) + + # Premeture break if where no better off + if totEloopDist > bestEloopDist: + break + + e1=e1.next + + if totEloopDist < bestEloopDist: + bestOffset = offset + bestEloopDist = totEloopDist + + # Modify V2 LS for Best offset + eloop2.edges = eloop2.edges[bestOffset:] + eloop2.edges[:bestOffset] + + else: + # Both are open loops, easier to calculate. + + + # Make sure the fake edges are at the start. + for i, edloop in enumerate((eloop1, eloop2)): + # print "LOOPO" + if edloop.edges[0].fake: + # alredy at the start + #print "A" + pass + elif edloop.edges[-1].fake: + # put the end at the start + edloop.edges.insert(0, edloop.edges.pop()) + #print "B" + + else: + for j, ed in enumerate(edloop.edges): + if ed.fake: + #print "C" + edloop.edges = edloop.edges = edloop.edges[j:] + edloop.edges[:j] + break + # print "DONE" + ed1, ed2 = eloop1.edges[0], eloop2.edges[0] + + if not ed1.fake or not ed2.fake: + raise "Error" + + # Find the join that isnt flipped (juts like detecting a bow-tie face) + a1 = (ed1.co1 - ed2.co1).length + (ed1.co2 - ed2.co2).length + a2 = (ed1.co1 - ed2.co2).length + (ed1.co2 - ed2.co1).length + + if a1 > a2: + eloop2.reverse() + # make the first edge the start edge still + eloop2.edges.insert(0, eloop2.edges.pop()) + + + + + for loopIdx in xrange(len(eloop2.edges)): + e1 = eloop1.edges[loopIdx] + e2 = eloop2.edges[loopIdx] + + # Remember the pairs for fan filling culled edges. + e1.match = e2; e2.match = e1 + + if not (e1.fake or e2.fake): + new_faces.append([e1.v1, e1.v2, e2.v2, e2.v1]) + + # FAN FILL MISSING FACES. + if CULL_FACES: + # Culled edges will be in eloop1. + FAN_FILLED_FACES = 0 + + contextEdge = eloop1.edges[0] # The larger of teh 2 + while FAN_FILLED_FACES < CULL_FACES: + while contextEdge.next.removed == 0: + contextEdge = contextEdge.next + + vertFanPivot = contextEdge.match.v2 + + while contextEdge.next.removed == 1: + #if not contextEdge.next.fake: + new_faces.append([contextEdge.next.v1, contextEdge.next.v2, vertFanPivot]) + + # Should we use another var?, this will work for now. + contextEdge.next.removed = 1 + + contextEdge = contextEdge.next + FAN_FILLED_FACES += 1 + + # may need to fan fill backwards 1 for non closed loops. + + eloop1.restore() # Add culled back into the list. + + return new_faces + +def main(): + global CULL_METHOD + + is_editmode = Window.EditMode() + if is_editmode: Window.EditMode(0) + ob = bpy.data.scenes.active.objects.active + if ob == None or ob.type != 'Mesh': + BPyMessages.Error_NoMeshActive() + return + + me = ob.getData(mesh=1) + + if me.multires: + BPyMessages.Error_NoMeshMultiresEdit() + return + + time1 = Blender.sys.time() + selEdges = getSelectedEdges(me, ob) + vertLoops = getVertLoops(selEdges, me) # list of lists of edges. + if vertLoops == None: + PupMenu('Error%t|Selection includes verts that are a part of more then 1 loop') + if is_editmode: Window.EditMode(1) + return + # print len(vertLoops) + + + if len(vertLoops) > 2: + choice = PupMenu('Loft '+str(len(vertLoops))+' edge loops%t|loop|segment') + if choice == -1: + if is_editmode: Window.EditMode(1) + return + elif len(vertLoops) < 2: + PupMenu('Error%t|No Vertloops found!') + if is_editmode: Window.EditMode(1) + return + else: + choice = 2 + + + # The line below checks if any of the vert loops are differenyt in length. + if False in [len(v[0]) == len(vertLoops[0][0]) for v in vertLoops]: + CULL_METHOD = PupMenu('Small to large edge loop distrobution method%t|remove edges evenly|remove smallest edges') + if CULL_METHOD == -1: + if is_editmode: Window.EditMode(1) + return + + if CULL_METHOD ==1: # RESET CULL_METHOD + CULL_METHOD = 0 # shortest + else: + CULL_METHOD = 1 # even + + + time1 = Blender.sys.time() + # Convert to special edge data. + edgeLoops = [] + for vloop, closed in vertLoops: + edgeLoops.append(edgeLoop(vloop, me, closed)) + + + # VERT LOOP ORDERING CODE + # "Build a worm" list - grow from Both ends + edgeOrderedList = [edgeLoops.pop()] + + # Find the closest. + bestSoFar = BIG_NUM + bestIdxSoFar = None + for edLoopIdx, edLoop in enumerate(edgeLoops): + l =(edgeOrderedList[-1].centre - edLoop.centre).length + if l < bestSoFar: + bestIdxSoFar = edLoopIdx + bestSoFar = l + + edgeOrderedList.append( edgeLoops.pop(bestIdxSoFar) ) + + # Now we have the 2 closest, append to either end- + # Find the closest. + while edgeLoops: + bestSoFar = BIG_NUM + bestIdxSoFar = None + first_or_last = 0 # Zero is first + for edLoopIdx, edLoop in enumerate(edgeLoops): + l1 =(edgeOrderedList[-1].centre - edLoop.centre).length + + if l1 < bestSoFar: + bestIdxSoFar = edLoopIdx + bestSoFar = l1 + first_or_last = 1 # last + + l2 =(edgeOrderedList[0].centre - edLoop.centre).length + if l2 < bestSoFar: + bestIdxSoFar = edLoopIdx + bestSoFar = l2 + first_or_last = 0 # last + + if first_or_last: # add closest Last + edgeOrderedList.append( edgeLoops.pop(bestIdxSoFar) ) + else: # Add closest First + edgeOrderedList.insert(0, edgeLoops.pop(bestIdxSoFar) ) # First + + faces = [] + + for i in xrange(len(edgeOrderedList)-1): + faces.extend( skin2EdgeLoops(edgeOrderedList[i], edgeOrderedList[i+1], me, ob, 0) ) + if choice == 1 and len(edgeOrderedList) > 2: # Loop + faces.extend( skin2EdgeLoops(edgeOrderedList[0], edgeOrderedList[-1], me, ob, 0) ) + + # REMOVE SELECTED FACES. + MESH_MODE= Blender.Mesh.Mode() + if MESH_MODE & Blender.Mesh.SelectModes.EDGE or MESH_MODE & Blender.Mesh.SelectModes.VERTEX: pass + elif MESH_MODE & Blender.Mesh.SelectModes.FACE: + try: me.faces.delete(1, [ f for f in me.faces if f.sel ]) + except: pass + + me.faces.extend(faces) + + print '\nSkin done in %.4f sec.' % (Blender.sys.time()-time1) + + + if is_editmode: Window.EditMode(1) + +if __name__ == '__main__': + main() diff --git a/release/scripts/mesh_solidify.py b/release/scripts/mesh_solidify.py new file mode 100644 index 00000000000..9e11ed68c63 --- /dev/null +++ b/release/scripts/mesh_solidify.py @@ -0,0 +1,345 @@ +#!BPY +""" +Name: 'Solidify Selection' +Blender: 243 +Group: 'Mesh' +Tooltip: 'Makes the mesh solid by creating a second skin.' +""" + +__author__ = "Campbell Barton" +__url__ = ("www.blender.org", "blenderartists.org") +__version__ = "1.1" + +__bpydoc__ = """\ +This script makes a skin from the selected faces. +Optionaly you can skin between the original and new faces to make a watertight solid object +""" + +# -------------------------------------------------------------------------- +# Solidify Selection 1.0 by Campbell Barton (AKA Ideasman42) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +from Blender import * +import bpy +import BPyMesh +# reload(BPyMesh) +import BPyMessages +# reload(BPyMessages) + +from BPyMathutils import angleToLength + +# python 2.3 has no reversed() iterator. this will only work on lists and tuples +try: + reversed +except: + def reversed(l): return l[::-1] + +def copy_facedata_multilayer(me, from_faces, to_faces): + ''' + Tkes 2 lists of faces and copies multilayer data from 1 to another + make sure they are aligned, cant copy from a quad to a tri, used for solidify selection. + ''' + + def copy_default_face(data): + face_from, face_to = data + face_to.mat = face_from.mat + face_to.smooth = face_from.smooth + face_to.sel = True + face_from.sel = False + + def copy_tex_face(data): + face_from, face_to = data + face_to.uv = [c for c in reversed(face_from.uv)] + face_to.mode = face_from.mode + face_to.flag = face_from.flag + face_to.image = face_from.image + + def copy_col_face(data): + face_from, face_to = data + face_to.col = [c for c in reversed(face_from.col)] + + # make a list of face_from, face_to pairs + #face_pairs = zip(faces_sel, [me_faces[len_faces + i] for i in xrange(len(faces_sel))]) + face_pairs = zip(from_faces, to_faces) + + # Copy properties from 1 set of faces to another. + map(copy_default_face, face_pairs) + + for uvlayer in me.getUVLayerNames(): + me.activeUVLayer = uvlayer + map(copy_tex_face, face_pairs) + + for collayer in me.getColorLayerNames(): + me.activeColorLayer = collayer + map(copy_col_face, face_pairs) + + # Now add quads between if we wants + + +Ang= Mathutils.AngleBetweenVecs +SMALL_NUM=0.00001 + +def solidify(me, PREF_THICK, PREF_SKIN_SIDES=True, PREF_REM_ORIG=False, PREF_COLLAPSE_SIDES=False): + + # Main code function + me_faces = me.faces + faces_sel= [f for f in me_faces if f.sel] + + BPyMesh.meshCalcNormals(me) + normals= [v.no for v in me.verts] + vertFaces= [[] for i in xrange(len(me.verts))] + for f in me_faces: + no=f.no + for v in f: + vertFaces[v.index].append(no) + + # Scale the normals by the face angles from the vertex Normals. + for i in xrange(len(me.verts)): + length=0.0 + if vertFaces[i]: + for fno in vertFaces[i]: + try: + a= Ang(fno, normals[i]) + except: + a= 0 + if a>=90: + length+=1 + elif a < SMALL_NUM: + length+= 1 + else: + length+= angleToLength(a) + + length= length/len(vertFaces[i]) + #print 'LENGTH %.6f' % length + # normals[i]= (normals[i] * length) * PREF_THICK + normals[i] *= length * PREF_THICK + + + + len_verts = len( me.verts ) + len_faces = len( me_faces ) + + vert_mapping= [-1] * len(me.verts) + verts= [] + for f in faces_sel: + for v in f: + i= v.index + if vert_mapping[i]==-1: + vert_mapping[i]= len_verts + len(verts) + verts.append(v.co + normals[i]) + + #verts= [v.co + normals[v.index] for v in me.verts] + + me.verts.extend( verts ) + #faces= [tuple([ me.verts[v.index+len_verts] for v in reversed(f.v)]) for f in me_faces ] + faces= [ tuple([vert_mapping[v.index] for v in reversed(f.v)]) for f in faces_sel ] + me_faces.extend( faces ) + + + + + # Old method before multi UVs + """ + has_uv = me.faceUV + has_vcol = me.vertexColors + for i, orig_f in enumerate(faces_sel): + new_f= me_faces[len_faces + i] + new_f.mat = orig_f.mat + new_f.smooth = orig_f.smooth + orig_f.sel=False + new_f.sel= True + new_f = me_faces[i+len_faces] + if has_uv: + new_f.uv = [c for c in reversed(orig_f.uv)] + new_f.mode = orig_f.mode + new_f.flag = orig_f.flag + if orig_f.image: + new_f.image = orig_f.image + if has_vcol: + new_f.col = [c for c in reversed(orig_f.col)] + """ + copy_facedata_multilayer(me, faces_sel, [me_faces[len_faces + i] for i in xrange(len(faces_sel))]) + + if PREF_SKIN_SIDES or PREF_COLLAPSE_SIDES: + skin_side_faces= [] + skin_side_faces_orig= [] + # Get edges of faces that only have 1 user - so we can make walls + edges = {} + + # So we can reference indicies that wrap back to the start. + ROT_TRI_INDEX = 0,1,2,0 + ROT_QUAD_INDEX = 0,1,2,3,0 + + for f in faces_sel: + f_v= f.v + for i, edgekey in enumerate(f.edge_keys): + if edges.has_key(edgekey): + edges[edgekey]= None + else: + if len(f_v) == 3: + edges[edgekey] = f, f_v, i, ROT_TRI_INDEX[i+1] + else: + edges[edgekey] = f, f_v, i, ROT_QUAD_INDEX[i+1] + del ROT_QUAD_INDEX, ROT_TRI_INDEX + + # So we can remove doubles with edges only. + if PREF_COLLAPSE_SIDES: + me.sel = False + + # Edges are done. extrude the single user edges. + for edge_face_data in edges.itervalues(): + if edge_face_data: # != None + f, f_v, i1, i2 = edge_face_data + v1i,v2i= f_v[i1].index, f_v[i2].index + + if PREF_COLLAPSE_SIDES: + # Collapse + cv1 = me.verts[v1i] + cv2 = me.verts[vert_mapping[v1i]] + + cv3 = me.verts[v2i] + cv4 = me.verts[vert_mapping[v2i]] + + cv1.co = cv2.co = (cv1.co+cv2.co)/2 + cv3.co = cv4.co = (cv3.co+cv4.co)/2 + + cv1.sel=cv2.sel=cv3.sel=cv4.sel=True + + + + else: + # Now make a new Face + # skin_side_faces.append( (v1i, v2i, vert_mapping[v2i], vert_mapping[v1i]) ) + skin_side_faces.append( (v2i, v1i, vert_mapping[v1i], vert_mapping[v2i]) ) + skin_side_faces_orig.append((f, len(me_faces) + len(skin_side_faces_orig), i1, i2)) + + if PREF_COLLAPSE_SIDES: + me.remDoubles(0.0001) + else: + me_faces.extend(skin_side_faces) + # Now assign properties. + """ + # Before MultiUVs + for i, origfData in enumerate(skin_side_faces_orig): + orig_f, new_f_idx, i1, i2 = origfData + new_f= me_faces[new_f_idx] + + new_f.mat= orig_f.mat + new_f.smooth= orig_f.smooth + if has_uv: + new_f.mode= orig_f.mode + new_f.flag= orig_f.flag + if orig_f.image: + new_f.image= orig_f.image + + uv1= orig_f.uv[i1] + uv2= orig_f.uv[i2] + new_f.uv= (uv1, uv2, uv2, uv1) + + if has_vcol: + col1= orig_f.col[i1] + col2= orig_f.col[i2] + new_f.col= (col1, col2, col2, col1) + """ + + for i, origfData in enumerate(skin_side_faces_orig): + orig_f, new_f_idx, i2, i1 = origfData + new_f= me_faces[new_f_idx] + + new_f.mat= orig_f.mat + new_f.smooth= orig_f.smooth + + for uvlayer in me.getUVLayerNames(): + me.activeUVLayer = uvlayer + for i, origfData in enumerate(skin_side_faces_orig): + orig_f, new_f_idx, i2, i1 = origfData + new_f= me_faces[new_f_idx] + + new_f.mode= orig_f.mode + new_f.flag= orig_f.flag + new_f.image= orig_f.image + + uv1= orig_f.uv[i1] + uv2= orig_f.uv[i2] + new_f.uv= (uv1, uv2, uv2, uv1) + + for collayer in me.getColorLayerNames(): + me.activeColorLayer = collayer + for i, origfData in enumerate(skin_side_faces_orig): + orig_f, new_f_idx, i2, i1 = origfData + new_f= me_faces[new_f_idx] + + col1= orig_f.col[i1] + col2= orig_f.col[i2] + new_f.col= (col1, col2, col2, col1) + + + if PREF_REM_ORIG: + me_faces.delete(0, faces_sel) + + + + +def main(): + scn = bpy.data.scenes.active + ob = scn.objects.active + + if not ob or ob.type != 'Mesh': + BPyMessages.Error_NoMeshActive() + return + + me = ob.getData(mesh=1) + if me.multires: + BPyMessages.Error_NoMeshMultiresEdit() + return + + # Create the variables. + PREF_THICK = Draw.Create(-0.1) + PREF_SKIN_SIDES= Draw.Create(1) + PREF_COLLAPSE_SIDES= Draw.Create(0) + PREF_REM_ORIG= Draw.Create(0) + + pup_block = [\ + ('Thick:', PREF_THICK, -10, 10, 'Skin thickness in mesh space.'),\ + ('Skin Sides', PREF_SKIN_SIDES, 'Skin between the original and new faces.'),\ + ('Collapse Sides', PREF_COLLAPSE_SIDES, 'Skin between the original and new faces.'),\ + ('Remove Original', PREF_REM_ORIG, 'Remove the selected faces after skinning.'),\ + ] + + if not Draw.PupBlock('Solid Skin Selection', pup_block): + return + + is_editmode = Window.EditMode() + if is_editmode: Window.EditMode(0) + + Window.WaitCursor(1) + + me = ob.getData(mesh=1) + solidify(me, PREF_THICK.val, PREF_SKIN_SIDES.val, PREF_REM_ORIG.val, PREF_COLLAPSE_SIDES.val) + + + Window.WaitCursor(0) + if is_editmode: Window.EditMode(1) + + Window.RedrawAll() + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/release/scripts/mesh_unfolder.py b/release/scripts/mesh_unfolder.py new file mode 100644 index 00000000000..906e0f0a300 --- /dev/null +++ b/release/scripts/mesh_unfolder.py @@ -0,0 +1,1582 @@ +#!BPY +""" +Name: 'Unfold' +Blender: 245 +Group: 'Mesh' +Tip: 'Unfold meshes to create nets' +Version: v2.5 +Author: Matthew Chadwick +""" +import Blender +from Blender import * +from Blender.Mathutils import * +try: + import sys + import traceback + import math + import re + from math import * + import sys + import random + import xml.sax, xml.sax.handler, xml.sax.saxutils + + # annoying but need so classes dont raise errors + xml_sax_handler_ContentHandler = xml.sax.handler.ContentHandler + +except: + Draw.PupMenu('Error%t|A full python installation is required to run this script.') + xml = None + xml_sax_handler_ContentHandler = type(0) + +__author__ = 'Matthew Chadwick' +__version__ = '2.5 06102007' +__url__ = ["http://celeriac.net/unfolder/", "blender", "blenderartist"] +__email__ = ["post at cele[remove this text]riac.net", "scripts"] +__bpydoc__ = """\ + +Mesh Unfolder + +Unfolds the selected mesh onto a plane to form a net + +Not all meshes can be unfolded + +Meshes must be free of holes, +isolated edges (not part of a face), twisted quads and other rubbish. +Nice clean triangulated meshes unfold best + +This program is free software; you can distribute it and/or modify it under the terms +of the GNU General Public License as published by the Free Software Foundation; version 2 +or later, currently at http://www.gnu.org/copyleft/gpl.html + +The idea came while I was riding a bike. +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** + +# Face lookup +class FacesAndEdges: + def __init__(self, mesh): + self.nfaces = 0 + # straight from the documentation + self.edgeFaces = dict([(edge.key, []) for edge in mesh.edges]) + for face in mesh.faces: + face.sel = False + for key in face.edge_keys: + self.edgeFaces[key].append(face) + def findTakenAdjacentFace(self, bface, edge): + return self.findAdjacentFace(bface, edge) + # find the first untaken (non-selected) adjacent face in the list of adjacent faces for the given edge (allows for manifold meshes too) + def findAdjacentFace(self, bface, edge): + faces = self.edgeFaces[edge.key()] + for i in xrange(len(faces)): + if faces[i] == bface: + j = (i+1) % len(faces) + while(faces[j]!=bface): + if faces[j].sel == False: + return faces[j] + j = (j+1) % len(faces) + return None + def returnFace(self, face): + face.sel = False + self.nfaces-=1 + def facesTaken(self): + return self.nfaces + def takeAdjacentFace(self, bface, edge): + if (edge==None): + return None + face = self.findAdjacentFace(bface, edge) + if(face!=None): + face.sel = True + self.nfaces+=1 + return face + def takeFace(self, bface): + if(bface!=None): + bface.sel= True + self.nfaces+=1 + + +# A fold between two faces with a common edge +class Fold: + ids = -1 + def __init__(self, parent, refPoly, poly, edge, angle=None): + Fold.ids+=1 + self.id = Fold.ids + self.refPoly = refPoly + self.poly = poly + self.srcFace = None + self.desFace = None + self.edge = edge + self.foldedEdge = edge + self.rm = None + self.parent = parent + self.tree = None + if(refPoly!=None): + self.refPolyNormal = refPoly.normal() + self.polyNormal = poly.normal() + if(angle==None): + self.angle = self.calculateAngle() + self.foldingPoly = poly.rotated(edge, self.angle) + else: + self.angle = angle + self.foldingPoly = poly + self.unfoldedEdge = self.edge + self.unfoldedNormal = None + self.animAngle = self.angle + self.cr = None + self.nancestors = None + def reset(self): + self.foldingPoly = self.poly.rotated(self.edge, self.dihedralAngle()) + def getID(self): + return self.id + def getParent(self): + return self.parent + def ancestors(self): + if(self.nancestors==None): + self.nancestors = self.computeAncestors() + return self.nancestors + def computeAncestors(self): + if(self.parent==None): + return 0 + else: + return self.parent.ancestors()+1 + def dihedralAngle(self): + return self.angle + def unfoldTo(self, f): + self.animAngle = self.angle*f + self.foldingPoly = self.poly.rotated(self.edge, self.animAngle) + def calculateAngle(self): + sangle = Mathutils.AngleBetweenVecs(self.refPolyNormal, self.polyNormal) + if(sangle!=sangle): + sangle=0.0 + ncp = Mathutils.CrossVecs(self.refPolyNormal, self.polyNormal) + dp = Mathutils.DotVecs(ncp, self.edge.vector) + if(dp>0.0): + return +sangle + else: + return -sangle + def alignWithParent(self): + pass + def unfoldedNormal(self): + return self.unfoldedNormal + def getEdge(self): + return self.edge + def getFace(self): + return self.poly + def testFace(self): + return Poly.fromVectors([self.edge.v1, self.edge.v2, Vector([0,0,0])]) + def unfoldedFace(self): + return self.foldingPoly + def unfold(self): + if(self.parent!=None): + self.parent.foldFace(self) + def foldFace(self, child): + child.foldingPoly.rotate(self.edge, self.animAngle) + if(self.parent!=None): + self.parent.foldFace(child) + +class Cut(Fold): + pass + +# Trees build folds by traversing the mesh according to a local measure +class Tree: + def __init__(self, net, parent,fold,otherConstructor=None): + self.net = net + self.fold = fold + self.face = fold.srcFace + self.poly = Poly.fromBlenderFace(self.face) + self.generations = net.generations + self.growing = True + self.tooLong = False + self.parent = parent + self.grown = False + if not(otherConstructor): + self.edges = net.edgeIteratorClass(self) + def goodness(self): + return self.edges.goodness() + def compare(self, other): + if(self.goodness() > other.goodness()): + return +1 + else: + return -1 + def isGrowing(self): + return self.growing + def beGrowing(self): + self.growing = True + def grow(self): + self.tooLong = self.fold.ancestors()>self.generations + if(self.edges.hasNext() and self.growing): + edge = self.edges.next() + tface = self.net.facesAndEdges.takeAdjacentFace(self.face, edge) + if(tface!=None): + self.branch(tface, edge) + if(self.parent==None): + self.grow() + else: + self.grown = True + def isGrown(self): + return self.grown + def canGrow(self): + return (self.parent!=None and self.parent.grown) + def getNet(self): + return self.net + def getFold(self): + return self.fold + def getFace(self): + return self.face + def branch(self, tface, edge): + fold = Fold(self.fold, self.poly, Poly.fromBlenderFace(tface), edge) + fold.srcFace = tface + self.net.myFacesVisited+=1 + tree = Tree(self.net, self, fold) + fold.tree = tree + fold.unfold() + overlaps = self.net.checkOverlaps(fold) + nc = len(overlaps) + self.net.overlaps+=nc + if(nc>0 and self.net.avoidsOverlaps): + self.handleOverlap(fold, overlaps) + else: + self.addFace(fold) + def handleOverlap(self, fold, overlaps): + self.net.facesAndEdges.returnFace(fold.srcFace) + self.net.myFacesVisited-=1 + for cfold in overlaps: + ttree = cfold.tree + ttree.growing = True + ttree.grow() + def addFace(self, fold): + ff = fold.unfoldedFace() + fold.desFace = self.net.addFace(ff, fold.srcFace) + self.net.folds.append(fold) + self.net.addBranch(fold.tree) + fold.tree.growing = not(self.tooLong) + if(self.net.diffuse==False): + fold.tree.grow() + +# A Net is the result of the traversal of the mesh by Trees +class Net: + def __init__(self, src, des): + self.src = src + self.des = des + self.firstFace = None + self.firstPoly = None + self.refFold = None + self.edgeIteratorClass = RandomEdgeIterator + if(src!=None): + self.srcFaces = src.faces + self.facesAndEdges = FacesAndEdges(self.src) + self.myFacesVisited = 0 + self.facesAdded = 0 + self.folds = [] + self.cuts = [] + self.branches = [] + self.overlaps = 0 + self.avoidsOverlaps = True + self.frame = 1 + self.ff = 180.0 + self.firstFaceIndex = None + self.trees = 0 + self.foldIPO = None + self.perFoldIPO = None + self.IPOCurves = {} + self.generations = 128 + self.diffuse = True + self.noise = 0.0 + self.grownBranches = 0 + self.assignsUV = True + self.animates = False + self.showProgress = False + self.feedback = None + def setSelectedFaces(self, faces): + self.srcFaces = faces + self.facesAndEdges = FacesAndEdges(self.srcFaces) + def setShowProgress(self, show): + self.showProgress = show + # this method really needs work + def unfold(self): + selectedFaces = [face for face in self.src.faces if (self.src.faceUV and face.sel)] + if(self.avoidsOverlaps): + print "unfolding with overlap detection" + if(self.firstFaceIndex==None): + self.firstFaceIndex = random.randint(0, len(self.src.faces)-1) + else: + print "Using user-selected seed face ", self.firstFaceIndex + self.firstFace = self.src.faces[self.firstFaceIndex] + z = min([v.co.z for v in self.src.verts])-0.1 + ff = Poly.fromBlenderFace(self.firstFace) + if(len(ff.v)<3): + raise Exception("This mesh contains an isolated edge - it must consist only of faces") + testFace = Poly.fromVectors( [ Vector([0.0,0.0,0.0]), Vector([0.0,1.0,0.0]), Vector([1.0,1.0,0.0]) ] ) + # hmmm. I honestly can't remember why this needs to be done, but it does. + u=0 + v=1 + w=2 + if ff.v[u].x==ff.v[u+1].x and ff.v[u].y==ff.v[u+1].y: + u=1 + v=2 + w=0 + # here we make a couple of folds, not part of the net, which serve to get the net into the xy plane + xyFace = Poly.fromList( [ [ff.v[u].x,ff.v[u].y, z] , [ff.v[v].x,ff.v[v].y, z] , [ff.v[w].x+0.1,ff.v[w].y+0.1, z] ] ) + refFace = Poly.fromVectors([ ff.v[u], ff.v[v], xyFace.v[1], xyFace.v[0] ] ) + xyFold = Fold(None, xyFace, refFace, Edge(xyFace.v[0], xyFace.v[1] )) + self.refFold = Fold(xyFold, refFace, ff, Edge(refFace.v[0], refFace.v[1] )) + self.refFold.srcFace = self.firstFace + # prepare to grow the trees + trunk = Tree(self, None, self.refFold) + trunk.generations = self.generations + self.firstPoly = ff + self.facesAndEdges.takeFace(self.firstFace) + self.myFacesVisited+=1 + self.refFold.unfold() + self.refFold.tree = trunk + self.refFold.desFace = self.addFace(self.refFold.unfoldedFace(), self.refFold.srcFace) + self.folds.append(self.refFold) + trunk.grow() + i = 0 + # keep the trees growing while they can + while(self.myFacesVisited 0): + if self.edgeIteratorClass==RandomEdgeIterator: + i = random.randint(0,len(self.branches)-1) + tree = self.branches[i] + if(tree.isGrown()): + self.branches.pop(i) + else: + tree.beGrowing() + if(tree.canGrow()): + tree.grow() + i = 0 + else: + i = (i + 1) % len(self.branches) + if self.src.faceUV: + for face in self.src.faces: + face.sel = False + for face in selectedFaces: + face.sel = True + self.src.update() + Window.RedrawAll() + def assignUVs(self): + for fold in self.folds: + self.assignUV(fold.srcFace, fold.unfoldedFace()) + print " assigned uv to ", len(self.folds), len(self.src.faces) + self.src.update() + def checkOverlaps(self, fold): + #return self.getOverlapsBetween(fold, self.folds) + return self.getOverlapsBetweenGL(fold, self.folds) + def getOverlapsBetween(self, fold, folds): + if(fold.parent==None): + return [] + mf = fold.unfoldedFace() + c = [] + for afold in folds: + mdf = afold.unfoldedFace() + if(afold!=fold): + # currently need to get agreement from both polys because + # a touch by a vertex of one the other's edge is acceptable & + # they disagree on that + intersects = mf.intersects2D(mdf) and mdf.intersects2D(mf) + inside = ( mdf.containsAnyOf(mf) or mf.containsAnyOf(mdf) ) + if( intersects or inside or mdf.overlays(mf)): + c.append(afold) + return c + def getOverlapsBetweenGL(self, fold, folds): + b = fold.unfoldedFace().bounds() + polys = len(folds)*4+16 # the buffer is nhits, mindepth, maxdepth, name + buffer = BGL.Buffer(BGL.GL_INT, polys) + BGL.glSelectBuffer(polys, buffer) + BGL.glRenderMode(BGL.GL_SELECT) + BGL.glInitNames() + BGL.glPushName(0) + BGL.glPushMatrix() + BGL.glMatrixMode(BGL.GL_PROJECTION) + BGL.glLoadIdentity() + BGL.glOrtho(b[0].x, b[1].x, b[1].y, b[0].y, 0.0, 10.0) + #clip = BGL.Buffer(BGL.GL_FLOAT, 4) + #clip.list = [0,0,0,0] + #BGL.glClipPlane(BGL.GL_CLIP_PLANE1, clip) + # could use clipping planes here too + BGL.glMatrixMode(BGL.GL_MODELVIEW) + BGL.glLoadIdentity() + bx = (b[1].x - b[0].x) + by = (b[1].y - b[0].y) + cx = bx / 2.0 + cy = by / 2.0 + for f in xrange(len(folds)): + afold = folds[f] + if(fold!=afold): + BGL.glLoadName(f) + BGL.glBegin(BGL.GL_LINE_LOOP) + for v in afold.unfoldedFace().v: + BGL.glVertex2f(v.x, v.y) + BGL.glEnd() + BGL.glPopMatrix() + BGL.glFlush() + hits = BGL.glRenderMode(BGL.GL_RENDER) + buffer = [buffer[i] for i in xrange(3, 4*hits, 4)] + o = [folds[buffer[i]] for i in xrange(len(buffer))] + return self.getOverlapsBetween(fold, o) + def colourFace(self, face, cr): + for c in face.col: + c.r = int(cr[0]) + c.g = int(cr[1]) + c.b = int(cr[2]) + c.a = int(cr[3]) + self.src.update() + def setAvoidsOverlaps(self, avoids): + self.avoidsOverlaps = avoids + def addBranch(self, branch): + self.branches.append(branch) + if self.edgeIteratorClass!=RandomEdgeIterator: + self.branches.sort(lambda b1, b2: b1.compare(b2)) + def srcSize(self): + return len(self.src.faces) + def nBranches(self): + return len(self.branches) + def facesCreated(self): + return len(self.des.faces) + def facesVisited(self): + return self.myFacesVisited + def getOverlaps(self): + return self.overlaps + def sortOutIPOSource(self): + print "Sorting out IPO" + if self.foldIPO!=None: + return + o = None + try: + o = Blender.Object.Get("FoldRate") + except: + o = Blender.Object.New("Empty", "FoldRate") + Blender.Scene.GetCurrent().objects.link(o) + if(o.getIpo()==None): + ipo = Blender.Ipo.New("Object", "FoldRateIPO") + z = ipo.addCurve("RotZ") + print " added RotZ IPO curve" + z.addBezier((1,0)) + # again, why is this 10x out ? + z.addBezier((180, self.ff/10.0)) + z.addBezier((361, 0.0)) + o.setIpo(ipo) + z.recalc() + z.setInterpolation("Bezier") + z.setExtrapolation("Cyclic") + self.setIPOSource(o) + print " added IPO source" + def setIPOSource(self, object): + try: + self.foldIPO = object + for i in xrange(self.foldIPO.getIpo().getNcurves()): + self.IPOCurves[self.foldIPO.getIpo().getCurves()[i].getName()] = i + print " added ", self.foldIPO.getIpo().getCurves()[i].getName() + except: + print "Problem setting IPO object" + print sys.exc_info()[1] + traceback.print_exc(file=sys.stdout) + def setFoldFactor(self, ff): + self.ff = ff + def sayTree(self): + for fold in self.folds: + if(fold.getParent()!=None): + print fold.getID(), fold.dihedralAngle(), fold.getParent().getID() + def report(self): + p = int(float(self.myFacesVisited)/float(len(self.src.faces)) * 100) + print str(p) + "% unfolded" + print "faces created:", self.facesCreated() + print "faces visited:", self.facesVisited() + print "originalfaces:", len(self.src.faces) + n=0 + if(self.avoidsOverlaps): + print "net avoided at least ", self.getOverlaps(), " overlaps ", + n = len(self.src.faces) - self.facesCreated() + if(n>0): + print "but was unable to avoid ", n, " overlaps. Incomplete net." + else: + print "- A complete net." + else: + print "net has at least ", self.getOverlaps(), " collision(s)" + return n + # fold all my folds to a fraction of their total fold angle + def unfoldToCurrentFrame(self): + self.unfoldTo(Blender.Scene.GetCurrent().getRenderingContext().currentFrame()) + def unfoldTo(self, frame): + frames = Blender.Scene.GetCurrent().getRenderingContext().endFrame() + if(self.foldIPO!=None and self.foldIPO.getIpo()!=None): + f = self.foldIPO.getIpo().EvaluateCurveOn(self.IPOCurves["RotZ"],frame) + # err, this number seems to be 10x less than it ought to be + fff = 1.0 - (f*10.0 / self.ff) + else: + fff = 1.0-((frame)/(frames*1.0)) + for fold in self.folds: + fold.unfoldTo(fff) + for fold in self.folds: + fold.unfold() + tface = fold.unfoldedFace() + bface = fold.desFace + i = 0 + for v in bface.verts: + v.co.x = tface.v[i].x + v.co.y = tface.v[i].y + v.co.z = tface.v[i].z + i+=1 + Window.Redraw(Window.Types.VIEW3D) + return None + def addFace(self, poly, originalFace=None): + originalLength = len(self.des.verts) + self.des.verts.extend([Vector(vv.x, vv.y, vv.z) for vv in poly.v]) + self.des.faces.extend([ range(originalLength, originalLength + poly.size()) ]) + newFace = self.des.faces[len(self.des.faces)-1] + newFace.uv = [vv for vv in poly.v] + if(originalFace!=None and self.src.vertexColors): + newFace.col = [c for c in originalFace.col] + if(self.feedback!=None): + pu = str(int(self.fractionUnfolded() * 100))+"% unfolded" + howMuchDone = str(self.myFacesVisited)+" of "+str(len(self.src.faces))+" "+pu + self.feedback.say(howMuchDone) + #Window.DrawProgressBar (p, pu) + if(self.showProgress): + Window.Redraw(Window.Types.VIEW3D) + return newFace + def fractionUnfolded(self): + return float(self.myFacesVisited)/float(len(self.src.faces)) + def assignUV(self, face, uv): + face.uv = [Vector(v.x, v.y) for v in uv.v] + def unfoldAll(feedback=None): + objects = Blender.Object.Get() + for object in objects: + if(object.getType()=='Mesh' and not(object.getName().endswith("_net")) and len(object.getData(False, True).faces)>1): + net = Net.createNet(object, feedback) + net.searchForUnfolding() + svg = SVGExporter(net, object.getName()+".svg") + svg.export() + unfoldAll = staticmethod(unfoldAll) + def searchForUnfolding(self, limit=-1): + overlaps = 1 + attempts = 0 + while(overlaps > 0 or attempts=0 and (mesh.faces[mesh.activeFace].sel): + net.firstFaceIndex = mesh.activeFace + net.object = ob + net.feedback = feedback + return net + createNet = staticmethod(createNet) + def importNet(filename): + netName = filename.rstrip(".svg").replace("\\","/") + netName = netName[netName.rfind("/")+1:] + try: + netObject = Blender.Object.Get(netName) + except: + netObject = Blender.Object.New("Mesh", netName) + netObject.getData(mesh=1).name = netName + try: + Blender.Scene.GetCurrent().objects.link(netObject) + except: + pass + net = Net(None, netObject.getData(mesh=1)) + handler = NetHandler(net) + xml.sax.parse(filename, handler) + Window.Redraw(Window.Types.VIEW3D) + return net + importNet = staticmethod(importNet) + def getSourceMesh(self): + return self.src + +# determines the order in which to visit faces according to a local measure +class EdgeIterator: + def __init__(self, branch, otherConstructor=None): + self.branch = branch + self.bface = branch.getFace() + self.edge = branch.getFold().getEdge() + self.net = branch.getNet() + self.n = len(self.bface) + self.edges = [] + self.i = 0 + self.gooodness = 0 + self.createEdges() + self.computeGoodness() + if(otherConstructor==None): + self.sequenceEdges() + def createEdges(self): + edge = None + e = Edge.edgesOfBlenderFace(self.net.getSourceMesh(), self.bface) + for edge in e: + if not(edge.isBlenderSeam() and edge!=self.edge): + self.edges.append(edge) + def sequenceEdges(self): + pass + def next(self): + edge = self.edges[self.i] + self.i+=1 + return edge + def size(self): + return len(self.edges) + def reset(self): + self.i = 0 + def hasNext(self): + return (self.ilen(bface)-1): + return None + if(i==len(bface)-1): + j = 0 + else: + j = i+1 + edge = Edge( bface.v[i].co.copy(), bface.v[j].co.copy() ) + edge.bEdge = mesh.findEdge(bface.v[i], bface.v[j]) + edge.idx = i + return edge + fromBlenderFace=staticmethod(fromBlenderFace) + def edgesOfBlenderFace(mesh, bmFace): + edges = [mesh.edges[mesh.findEdges(edge[0], edge[1])] for edge in bmFace.edge_keys] + v = bmFace.verts + e = [] + vi = v[0] + i=0 + for j in xrange(1, len(bmFace)+1): + vj = v[j%len(bmFace)] + for ee in edges: + if((ee.v1.index==vi.index and ee.v2.index==vj.index) or (ee.v2.index==vi.index and ee.v1.index==vj.index)): + e.append(Edge(vi.co, vj.co, ee, i)) + i+=1 + vi = vj + return e + edgesOfBlenderFace=staticmethod(edgesOfBlenderFace) + def isBlenderSeam(self): + return (self.bmEdge.flag & Mesh.EdgeFlags.SEAM) + def isInFGon(self): + return (self.bmEdge.flag & Mesh.EdgeFlags.FGON) + def mapTo(self, poly): + if(self.idx==len(poly.v)-1): + j = 0 + else: + j = self.idx+1 + return Edge(poly.v[self.idx], poly.v[j]) + def isDegenerate(self): + return self.vector.length==0 + def vertices(s): + return [ [s.v1.x, s.v1.y, s.v1.z], [s.v2.x, s.v2.y,s.v2.z] ] + def key(self): + return self.bmEdge.key + def goodness(self): + return self.gooodness + def setGoodness(self, g): + self.gooodness = g + def compare(self, other): + if(self.goodness() > other.goodness()): + return +1 + else: + return -1 + # Does the given segment intersect this, for overlap detection. + # endpoints are allowed to touch the line segment + def intersects2D(self, s): + if(self.matches(s)): + return False + else: + i = Geometry.LineIntersect2D(self.v1, self.v2, s.v1, s.v2) + if(i!=None): + i.resize4D() + i.z = self.v1.z # hack to put the point on the same plane as this edge for comparison + return(i!=None and not(self.endsWith(i))) + def matches(self, s): + return ( (self.v1==s.v1 and self.v2==s.v2) or (self.v2==s.v1 and self.v1==s.v2) ) + # Is the given point on the end of this segment ? 10-5 seems to an acceptable limit for closeness in Blender + def endsWith(self, aPoint, e=0.0001): + return ( (self.v1-aPoint).length < e or (self.v2-aPoint).length < e ) + + +class Poly: + ids = -1 + def __init__(self): + Poly.ids+=1 + self.v = [] + self.id = Poly.ids + self.boundz = None + self.edges = None + def getID(self): + return self.id + def normal(self): + a =self.v[0] + b=self.v[1] + c=self.v[2] + p = b-a + p.resize3D() + q = a-c + q.resize3D() + return CrossVecs(p,q) + def makeEdges(self): + self.edges = [] + for i in xrange(self.nPoints()): + self.edges.append(Edge( self.v[i % self.nPoints()], self.v[ (i+1) % self.nPoints()] )) + def edgeAt(self, i): + if(self.edges==None): + self.makeEdges() + return self.edges[i] + def intersects2D(self, poly): + for i in xrange(self.nPoints()): + edge = self.edgeAt(i) + for j in xrange(poly.nPoints()): + if edge.intersects2D(poly.edgeAt(j)): + return True + return False + def isBad(self): + badness = 0 + for vv in self.v: + if(vv.x!=vv.x or vv.y!=vv.y or vv.z!=vv.z): # Nan check + badness+=1 + return (badness>0) + def midpoint(self): + x=y=z = 0.0 + n = 0 + for vv in self.v: + x+=vv.x + y+=vv.y + z+=vv.z + n+=1 + return [ x/n, y/n, z/n ] + def centerAtOrigin(self): + mp = self.midpoint() + mp = -mp + toOrigin = TranslationMatrix(mp) + self.v = [(vv * toOrigin) for vv in self.v] + def move(self, tv): + mv = TranslationMatrix(tv) + self.v = [(vv * mv) for vv in self.v] + def scale(self, s): + mp = Vector(self.midpoint()) + fromOrigin = TranslationMatrix(mp) + mp = -mp + toOrigin = TranslationMatrix(mp) + sm = ScaleMatrix(s, 4) + # Todo, the 3 lines below in 1 LC + self.v = [(vv * toOrigin) for vv in self.v] + self.v = [(sm * vv) for vv in self.v] + self.v = [(vv * fromOrigin) for vv in self.v] + def nPoints(self): + return len(self.v) + def size(self): + return len(self.v) + def rotated(self, axis, angle): + p = self.clone() + p.rotate(axis, angle) + return p + def rotate(self, axis, angle): + rotation = RotationMatrix(angle, 4, "r", axis.vector) + toOrigin = TranslationMatrix(axis.v1n) + fromOrigin = TranslationMatrix(axis.v1) + # Todo, the 3 lines below in 1 LC + self.v = [(vv * toOrigin) for vv in self.v] + self.v = [(rotation * vv) for vv in self.v] + self.v = [(vv * fromOrigin) for vv in self.v] + def moveAlong(self, vector, distance): + t = TranslationMatrix(vector) + s = ScaleMatrix(distance, 4) + ts = t*s + self.v = [(vv * ts) for vv in self.v] + def bounds(self): + if(self.boundz == None): + vv = [vv for vv in self.v] + vv.sort(key=lambda v: v.x) + minx = vv[0].x + maxx = vv[len(vv)-1].x + vv.sort(key=lambda v: v.y) + miny = vv[0].y + maxy = vv[len(vv)-1].y + self.boundz = [Vector(minx, miny, 0), Vector(maxx, maxy, 0)] + return self.boundz + def fromBlenderFace(bface): + p = Poly() + for vv in bface.v: + vec = Vector([vv.co[0], vv.co[1], vv.co[2] , 1.0]) + p.v.append(vec) + return p + fromBlenderFace = staticmethod(fromBlenderFace) + def fromList(list): + p = Poly() + for vv in list: + vec = Vector( [vvv for vvv in vv] ) + vec.resize4D() + p.v.append(vec) + return p + fromList = staticmethod(fromList) + def fromVectors(vectors): + p = Poly() + p.v.extend([v.copy().resize4D() for v in vectors]) + return p + fromVectors = staticmethod(fromVectors) + def clone(self): + p = Poly() + p.v.extend(self.v) + return p + def hasVertex(self, ttv): + v = Mathutils.Vector(ttv) + v.normalize() + for tv in self.v: + vv = Mathutils.Vector(tv) + vv.normalize() + t = 0.00001 + if abs(vv.x-v.x)0): j=i-1 + cv = self.v[i] + nv = self.v[j] + if ((((cv.y<=tp.y) and (tp.y") + self.e.endElement("style") + self.e.endElement("defs") + #self.addClipPath() + self.addMeta() + def addMeta(self): + self.e.startElement("metadata", xml.sax.xmlreader.AttributesImpl({})) + self.e.startElement("nets:net", xml.sax.xmlreader.AttributesImpl({})) + for i in xrange(1, len(self.net.folds)): + fold = self.net.folds[i] + # AttributesNSImpl - documentation is rubbish. using this hack. + atts = {} + atts["nets:id"] = "fold"+str(fold.getID()) + if(fold.parent!=None): + atts["nets:parent"] = "fold"+str(fold.parent.getID()) + else: + atts["nets:parent"] = "null" + atts["nets:da"] = str(fold.dihedralAngle()) + if(fold.parent!=None): + atts["nets:ofPoly"] = "poly"+str(fold.parent.foldingPoly.getID()) + else: + atts["nets:ofPoly"] = "" + atts["nets:toPoly"] = "poly"+str(fold.foldingPoly.getID()) + a = xml.sax.xmlreader.AttributesImpl(atts) + self.e.startElement("nets:fold", a) + self.e.endElement("nets:fold") + self.e.endElement("nets:net") + self.e.endElement("metadata") + def end(self): + self.e.endElement("svg") + self.e.endDocument() + print "grown." + def export(self): + self.net.unfoldTo(1) + bb = self.object.getBoundBox() + print bb + self.vxmin = bb[0][0] + self.vymin = bb[0][1] + self.vxmax = bb[7][0] + self.vymax = bb[7][1] + self.start() + atts = {} + atts["id"] = self.object.getName() + a = xml.sax.xmlreader.AttributesImpl(atts) + self.e.startElement("g", a) + #self.addUVImage() + self.addPolys() + self.addFoldLines() + #self.addCutLines() + self.e.endElement("g") + self.end() + def addClipPath(self): + atts = {} + atts["id"] = "netClip" + atts["clipPathUnits"] = "userSpaceOnUse" + atts["x"] = str(self.vxmin) + atts["y"] = str(self.vymin) + atts["width"] = "100%" + atts["height"] = "100%" + self.e.startElement("clipPath", atts) + self.addPolys() + self.e.endElement("clipPath") + def addUVImage(self): + image = Blender.Image.GetCurrent() #hmm - how to determine the desired image ? + if image==None: + return + ifn = image.getFilename() + ifn = self.filename.replace(".svg", ".jpg") + image.setFilename(ifn) + ifn = ifn[ifn.rfind("/")+1:] + image.save() + atts = {} + atts["clip-path"] = "url(#netClip)" + atts["xlink:href"] = ifn + self.e.startElement("image", atts) + self.e.endElement("image") + def addPolys(self): + atts = {} + atts["id"] = "polys" + a = xml.sax.xmlreader.AttributesImpl(atts) + self.e.startElement("g", a) + for i in xrange(len(self.net.folds)): + self.addPoly(self.net.folds[i]) + self.e.endElement("g") + def addFoldLines(self): + atts = {} + atts["id"] = "foldLines" + a = xml.sax.xmlreader.AttributesImpl(atts) + self.e.startElement("g", a) + for i in xrange( 1, len(self.net.folds)): + self.addFoldLine(self.net.folds[i]) + self.e.endElement("g") + def addFoldLine(self, fold): + edge = fold.edge.mapTo(fold.parent.foldingPoly) + if fold.dihedralAngle()>0: + foldType="valley" + else: + foldType="mountain" + atts={} + atts["x1"] = str(edge.v1.x) + atts["y1"] = str(edge.v1.y) + atts["x2"] = str(edge.v2.x) + atts["y2"] = str(edge.v2.y) + atts["id"] = "fold"+str(fold.getID()) + atts["class"] = foldType + a = xml.sax.xmlreader.AttributesImpl(atts) + self.e.startElement("line", a) + self.e.endElement("line") + def addCutLines(self): + atts = {} + atts["id"] = "cutLines" + a = xml.sax.xmlreader.AttributesImpl(atts) + self.e.startElement("g", a) + for i in xrange( 1, len(self.net.cuts)): + self.addCutLine(self.net.cuts[i]) + self.e.endElement("g") + def addCutLine(self, cut): + edge = cut.edge.mapTo(cut.parent.foldingPoly) + if cut.dihedralAngle()>0: + foldType="valley" + else: + foldType="mountain" + atts={} + atts["x1"] = str(edge.v1.x) + atts["y1"] = str(edge.v1.y) + atts["x2"] = str(edge.v2.x) + atts["y2"] = str(edge.v2.y) + atts["id"] = "cut"+str(cut.getID()) + atts["class"] = foldType + a = xml.sax.xmlreader.AttributesImpl(atts) + self.e.startElement("line", a) + self.e.endElement("line") + def addPoly(self, fold): + face = fold.foldingPoly + atts = {} + if fold.desFace.col: + col = fold.desFace.col[0] + rgb = "rgb("+str(col.r)+","+str(col.g)+","+str(col.b)+")" + atts["fill"] = rgb + atts["class"] = "poly" + atts["id"] = "poly"+str(face.getID()) + points = "" + first = True + for vv in face.v: + if(not(first)): + points+=',' + first = False + points+=str(vv[0]) + points+=' ' + points+=str(vv[1]) + atts["points"] = points + a = xml.sax.xmlreader.AttributesImpl(atts) + self.e.startElement("polygon", a) + self.e.endElement("polygon") + def fileSelected(filename): + try: + net = Registry.GetKey('unfolder')['net'] + exporter = SVGExporter(net, filename) + exporter.export() + except: + print "Problem exporting SVG" + traceback.print_exc(file=sys.stdout) + fileSelected = staticmethod(fileSelected) + +# for importing nets saved by the above exporter +class NetHandler(xml.sax.handler.ContentHandler): + def __init__(self, net): + self.net = net + self.first = (41==41) + self.currentElement = None + self.chars = None + self.currentAction = None + self.foldsPending = {} + self.polys = {} + self.actions = {} + self.actions["nets:fold"] = self.foldInfo + self.actions["line"] = self.cutOrFold + self.actions["polygon"] = self.createPoly + def setDocumentLocator(self, locator): + pass + def startDocument(self): + pass + def endDocument(self): + for fold in self.foldsPending.values(): + face = self.net.addFace(fold.unfoldedFace()) + fold.desFace = face + self.net.folds.append(fold) + self.net.addFace(self.first) + self.foldsPending = None + self.polys = None + def startPrefixMapping(self, prefix, uri): + pass + def endPrefixMapping(self, prefix): + pass + def startElement(self, name, attributes): + self.currentAction = None + try: + self.currentAction = self.actions[name] + except: + pass + if(self.currentAction!=None): + self.currentAction(attributes) + def endElement(self, name): + pass + def startElementNS(self, name, qname, attrs): + self.currentAction = self.actions[name] + if(self.currentAction!=None): + self.currentAction(attributes) + def endElementNS(self, name, qname): + pass + def characters(self, content): + pass + def ignorableWhitespace(self): + pass + def processingInstruction(self, target, data): + pass + def skippedEntity(self, name): + pass + def foldInfo(self, atts): + self.foldsPending[atts["nets:id"]] = atts + def createPoly(self, atts): + xy = re.split('[, ]' , atts["points"]) + vectors = [] + for i in xrange(0, len(xy)-1, 2): + v = Vector([float(xy[i]), float(xy[i+1]), 0.0]) + vectors.append(v) + poly = Poly.fromVectors(vectors) + if(self.first==True): + self.first = poly + self.polys[atts["id"]] = poly + def cutOrFold(self, atts): + fid = atts["id"] + try: + fi = self.foldsPending[fid] + except: + pass + p1 = Vector([float(atts["x1"]), float(atts["y1"]), 0.0]) + p2 = Vector([float(atts["x2"]), float(atts["y2"]), 0.0]) + edge = Edge(p1, p2) + parent = None + ofPoly = None + toPoly = None + try: + parent = self.foldsPending[fi["nets:parent"]] + except: + pass + try: + ofPoly = self.polys[fi["nets:ofPoly"]] + except: + pass + try: + toPoly = self.polys[fi["nets:toPoly"]] + except: + pass + fold = Fold(parent, ofPoly , toPoly, edge, float(fi["nets:da"])) + self.foldsPending[fid] = fold + def fileSelected(filename): + try: + net = Net.importNet(filename) + try: + Registry.GetKey('unfolder')['net'] = net + except: + Registry.SetKey('unfolder', {}) + Registry.GetKey('unfolder')['net'] = net + Registry.GetKey('unfolder')['lastpath'] = filename + except: + print "Problem importing SVG" + traceback.print_exc(file=sys.stdout) + fileSelected = staticmethod(fileSelected) + + +class GUI: + def __init__(self): + self.overlaps = Draw.Create(0) + self.ani = Draw.Create(0) + self.selectedFaces =0 + self.search = Draw.Create(0) + self.diffuse = True + self.ancestors = Draw.Create(0) + self.noise = Draw.Create(0.0) + self.shape = Draw.Create(0) + self.nOverlaps = 1==2 + self.iterators = [RandomEdgeIterator,Brightest,Curvature,EdgeIterator,OddEven,Largest] + self.iterator = RandomEdgeIterator + self.overlapsText = "*" + self.message = " " + def makePopupGUI(self): + useRandom = Draw.Create(0) + pub = [] + pub.append(("Search", self.search, "Search for non-overlapping net (maybe forever)")) + pub.append(("Random", useRandom, "Random style net")) + ok = True + while ok: + ok = Blender.Draw.PupBlock("Unfold", pub) + if ok: + if useRandom.val: + self.iterator = RandomEdgeIterator + else: + self.iterator = Curvature + self.unfold() + def makeStandardGUI(self): + Draw.Register(self.draw, self.keyOrMouseEvent, self.buttonEvent) + def installScriptLink(self): + print "Adding script link for animation" + s = Blender.Scene.GetCurrent().getScriptLinks("FrameChanged") + if(s!=None and s.count("frameChanged.py")>0): + return + try: + script = Blender.Text.Get("frameChanged.py") + except: + script = Blender.Text.New("frameChanged.py") + script.write("import Blender\n") + script.write("import mesh_unfolder as Unfolder\n") + script.write("u = Blender.Registry.GetKey('unfolder')\n") + script.write("if u!=None:\n") + script.write("\tn = u['net']\n") + script.write("\tif(n!=None and n.animates):\n") + script.write("\t\tn.unfoldToCurrentFrame()\n") + Blender.Scene.GetCurrent().addScriptLink("frameChanged.py", "FrameChanged") + def unfold(self): + anc = self.ancestors.val + n = 0.0 + s = True + self.nOverlaps = 0 + searchLimit = 10 + search = 1 + Draw.Redraw(1) + net = None + name = None + try: + self.say("Unfolding...") + Draw.Redraw(1) + while(s):# and search < searchLimit): + if(net!=None): + name = net.des.name + net = Net.fromSelected(self, name) + net.setAvoidsOverlaps(not(self.overlaps.val)) + print + print "Unfolding selected object" + net.edgeIteratorClass = self.iterator + print "Using ", net.edgeIteratorClass + net.animates = self.ani.val + self.diffuse = (self.ancestors.val==0) + net.diffuse = self.diffuse + net.generations = self.ancestors.val + net.noise = self.noise.val + print "even:", net.diffuse, " depth:", net.generations + net.unfold() + n = net.report() + t = "." + if(n<1.0): + t = "Overlaps>="+str(n) + else: + t = "A complete net." + self.nOverlaps = (n>=1) + if(self.nOverlaps): + self.say(self.message+" - unfolding failed - try again ") + elif(not(self.overlaps.val)): + self.say("Success. Complete net - no overlaps ") + else: + self.say("Unfolding complete") + self.ancestors.val = anc + s = (self.search.val and n>=1.0) + dict = Registry.GetKey('unfolder') + if(not(dict)): + dict = {} + dict['net'] = net + Registry.SetKey('unfolder', dict) + if(s): + net = net.clone() + search += 1 + except(IndexError): + self.say("Please select an object to unfold") + except: + self.say("Problem unfolding selected object - see console for details") + print "Problem unfolding selected object:" + print sys.exc_info()[1] + traceback.print_exc(file=sys.stdout) + if(self.ani): + if Registry.GetKey('unfolder')==None: + print "no net!" + return + Registry.GetKey('unfolder')['net'].sortOutIPOSource() + self.installScriptLink() + Draw.Redraw(1) + def keyOrMouseEvent(self, evt, val): + if (evt == Draw.ESCKEY and not val): + Draw.Exit() + def buttonEvent(self, evt): + if (evt == 1): + self.unfold() + if (evt == 5): + try: + Registry.GetKey('unfolder')['net'].setAvoidsOverlaps(self.overlaps.val) + except: + pass + if (evt == 2): + print "Trying to set IPO curve" + try: + s = Blender.Object.GetSelected() + if(s!=None): + Registry.GetKey('unfolder')['net'].setIPOSource( s[0] ) + print "Set IPO curve" + else: + print "Please select an object to use the IPO of" + except: + print "Problem setting IPO source" + Draw.Redraw(1) + if (evt == 6): + Draw.Exit() + if (evt == 7): + try: + if (Registry.GetKey('unfolder')['net']!=None): + Registry.GetKey('unfolder')['net'].animates = self.ani.val + if(self.ani): + Registry.GetKey('unfolder')['net'].sortOutIPOSource() + self.installScriptLink() + except: + print sys.exc_info()[1] + traceback.print_exc(file=sys.stdout) + Draw.Redraw(1) + if (evt == 19): + pass + if (evt == 87): + try: + if (Registry.GetKey('unfolder')['net']!=None): + Registry.GetKey('unfolder')['net'].assignUVs() + self.say("Assigned UVs") + except: + print sys.exc_info()[1] + traceback.print_exc(file=sys.stdout) + Draw.Redraw(1) + if(evt==91): + if( testOverlap() == True): + self.nOverlaps = 1 + else: + self.nOverlaps = 0 + Draw.Redraw(1) + if(evt==233): + f1 = Poly.fromBlenderFace(Blender.Object.GetSelected()[0].getData().faces[0]) + f2 = Poly.fromBlenderFace(Blender.Object.GetSelected()[1].getData().faces[0]) + print + print Blender.Object.GetSelected()[0].getName() + print Blender.Object.GetSelected()[1].getName() + print f1.intersects2D(f2) + print f2.intersects2D(f1) + if(evt==714): + Net.unfoldAll(self) + Draw.Redraw(1) + if(evt==713): + self.iterator = self.iterators[self.shape.val] + Draw.Redraw(1) + if(evt==92): + if( testContains() == True): + self.nOverlaps = 1 + else: + self.nOverlaps = 0 + Draw.Redraw(1) + if(evt==104): + try: + filename = "net.svg" + s = Blender.Object.GetSelected() + if(s!=None and len(s)>0): + filename = s[0].getName()+".svg" + else: + if (Registry.GetKey('unfolder')['net']!=None): + filename = Registry.GetKey('unfolder')['net'].des.name + if(filename==None): + filename="net.svg" + else: + filename=filename+".svg" + Window.FileSelector(SVGExporter.fileSelected, "Select filename", filename) + except: + print "Problem exporting SVG" + traceback.print_exc(file=sys.stdout) + if(evt==107): + try: + Window.FileSelector(NetHandler.fileSelected, "Select file") + except: + print "Problem importing SVG" + traceback.print_exc(file=sys.stdout) + def say(self, m): + self.message = m + Draw.Redraw(1) + Window.Redraw(Window.Types.SCRIPT) + def draw(self): + cw = 64 + ch = 16 + l = FlowLayout(32, cw, ch, 350, 64) + l.y = 70 + self.search = Draw.Toggle("search", 19, l.nx(), l.ny(), l.cw, l.ch, self.search.val, "Search for non-overlapping mesh (potentially indefinitely)") + self.overlaps = Draw.Toggle("overlaps", 5, l.nx(), l.ny(), l.cw, l.ch, self.overlaps.val, "Allow overlaps / avoid overlaps - if off, will not place overlapping faces") + self.ani = Draw.Toggle("ani", 7, l.nx(), l.ny(), l.cw, l.ch, self.ani.val, "Animate net") + Draw.Button("uv", 87, l.nx(), l.ny(), l.cw, l.ch, "Assign net as UV to source mesh (overwriting existing UV)") + Draw.Button("Unfold", 1, l.nx(), l.ny(), l.cw, l.ch, "Unfold selected mesh to net") + Draw.Button("save", 104, l.nx(), l.ny(), l.cw, l.ch, "Save net as SVG") + Draw.Button("load", 107, l.nx(), l.ny(), l.cw, l.ch, "Load net from SVG") + #Draw.Button("test", 233, l.nx(), l.ny(), l.cw, l.ch, "test") + # unfolding enthusiasts - try uncommenting this + self.ancestors = Draw.Number("depth", 654, l.nx(), l.ny(), cw, ch, self.ancestors.val, 0, 9999, "depth of branching 0=diffuse") + #self.noise = Draw.Number("noise", 631, l.nx(), l.ny(), cw, ch, self.noise.val, 0.0, 1.0, "noisyness of branching") + #Draw.Button("UnfoldAll", 714, l.nx(), l.ny(), l.cw, l.ch, "Unfold all meshes and save their nets") + options = "order %t|random %x0|brightest %x1|curvature %x2|winding %x3| 1010 %x4|largest %x5" + self.shape = Draw.Menu(options, 713, l.nx(), l.ny(), cw, ch, self.shape.val, "shape of net") + Draw.Button("exit", 6, l.nx(), l.ny(), l.cw, l.ch, "exit") + BGL.glClearColor(0.3, 0.3, 0.3, 1) + BGL.glColor3f(0.3,0.3,0.3) + l.newLine() + BGL.glRasterPos2i(32, 100) + Draw.Text(self.message) + +class FlowLayout: + def __init__(self, margin, cw, ch, w, h): + self.x = margin-cw-4 + self.y = margin + self.cw = cw + self.ch = ch + self.width = w + self.height = h + self.margin = margin + def nx(self): + self.x+=(self.cw+4) + if(self.x>self.width): + self.x = self.margin + self.y-=self.ch+4 + return self.x + def ny(self): + return self.y + def newLine(self): + self.y-=self.ch+self.margin + self.x = self.margin + +# if xml is None, then dont bother running the script +if xml: + try: + sys.setrecursionlimit(10000) + gui = GUI() + gui.makeStandardGUI() + #gui.makePopupGUI() + except: + traceback.print_exc(file=sys.stdout) diff --git a/release/scripts/mesh_wire.py b/release/scripts/mesh_wire.py new file mode 100644 index 00000000000..35cfa325497 --- /dev/null +++ b/release/scripts/mesh_wire.py @@ -0,0 +1,285 @@ +#!BPY +""" +Name: 'Solid Wireframe' +Blender: 243 +Group: 'Mesh' +Tooltip: 'Make a solid wireframe copy of this mesh' +""" + +# -------------------------------------------------------------------------- +# Solid Wireframe1.0 by Campbell Barton (AKA Ideasman42) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- +import Blender +from Blender import Scene, Mesh, Window, sys +from Blender.Mathutils import AngleBetweenVecs, TriangleNormal +from BPyMesh import faceAngles # get angles for face cornders +#import BPyMesh +#reload(BPyMesh) +#faceAngles = BPyMesh.faceAngles + +# works out the distanbce to inset the corners based on angles +from BPyMathutils import angleToLength +#import BPyMathutils +#reload(BPyMathutils) +#angleToLength = BPyMathutils.angleToLength + +import mesh_solidify + +import BPyMessages +import bpy + + +def solid_wire(ob_orig, me_orig, sce, PREF_THICKNESS, PREF_SOLID, PREF_SHARP, PREF_XSHARP): + if not PREF_SHARP and PREF_XSHARP: + PREF_XSHARP = False + + # This function runs out of editmode with a mesh + # error cases are alredy checked for + + inset_half = PREF_THICKNESS / 2 + del PREF_THICKNESS + + ob = ob_orig.copy() + me = me_orig.copy() + ob.link(me) + sce.objects.selected = [] + sce.objects.link(ob) + ob.sel = True + sce.objects.active = ob + + # Modify the object, should be a set + FGON= Mesh.EdgeFlags.FGON + edges_fgon = dict([(ed.key,None) for ed in me.edges if ed.flag & FGON]) + # edges_fgon.fromkeys([ed.key for ed in me.edges if ed.flag & FGON]) + + del FGON + + + + # each face needs its own verts + # orig_vert_count =len(me.verts) + new_vert_count = len(me.faces) * 4 + for f in me.faces: + if len(f) == 3: + new_vert_count -= 1 + + if PREF_SHARP == 0: + new_faces_edge= {} + + def add_edge(i1,i2, ni1, ni2): + + if i1>i2: + i1,i2 = i2,i1 + flip = True + else: + flip = False + new_faces_edge.setdefault((i1,i2), []).append((ni1, ni2, flip)) + + + new_verts = [] + new_faces = [] + vert_index = len(me.verts) + + for f in me.faces: + f_v_co = [v.co for v in f] + angles = faceAngles(f_v_co) + f_v_idx = [v.index for v in f] + + def new_vert(fi): + co = f_v_co[fi] + a = angles[fi] + if a > 180: + vert_inset = 1 * inset_half + else: + vert_inset = inset_half * angleToLength( abs((180-a) / 2) ) + + # Calculate the inset direction + co1 = f_v_co[fi-1] + co2 = fi+1 # Wrap this index back to the start + if co2 == len(f_v_co): co2 = 0 + co2 = f_v_co[co2] + + co1 = co1 - co + co2 = co2 - co + co1.normalize() + co2.normalize() + d = co1+co2 + # Done with inset direction + + d.length = vert_inset + return co+d + + new_verts.extend([new_vert(i) for i in xrange(len(f_v_co))]) + + if len(f_v_idx) == 4: + faces = [\ + (f_v_idx[1], f_v_idx[0], vert_index, vert_index+1),\ + (f_v_idx[2], f_v_idx[1], vert_index+1, vert_index+2),\ + (f_v_idx[3], f_v_idx[2], vert_index+2, vert_index+3),\ + (f_v_idx[0], f_v_idx[3], vert_index+3, vert_index),\ + ] + else: + faces = [\ + (f_v_idx[1], f_v_idx[0], vert_index, vert_index+1),\ + (f_v_idx[2], f_v_idx[1], vert_index+1, vert_index+2),\ + (f_v_idx[0], f_v_idx[2], vert_index+2, vert_index),\ + ] + + + if PREF_SHARP == 1: + if not edges_fgon: + new_faces.extend(faces) + else: + for nf in faces: + i1,i2 = nf[0], nf[1] + if i1>i2: i1,i2 = i2,i1 + + if edges_fgon and (i1,i2) not in edges_fgon: + new_faces.append(nf) + + + + elif PREF_SHARP == 0: + for nf in faces: + add_edge(*nf) + + vert_index += len(f_v_co) + + me.verts.extend(new_verts) + + if PREF_SHARP == 0: + def add_tri_flipped(i1,i2,i3): + try: + if AngleBetweenVecs(me.verts[i1].no, TriangleNormal(me.verts[i1].co, me.verts[i2].co, me.verts[i3].co)) < 90: + return i3,i2,i1 + else: + return i1,i2,i3 + except: + return i1,i2,i3 + + # This stores new verts that use this vert + # used for re-averaging this verts location + # based on surrounding verts. looks better but not needed. + vert_users = [set() for i in xrange(vert_index)] + + for (i1,i2), nf in new_faces_edge.iteritems(): + + if len(nf) == 2: + # Add the main face + if edges_fgon and (i1,i2) not in edges_fgon: + new_faces.append((nf[0][0], nf[0][1], nf[1][0], nf[1][1])) + + + if nf[0][2]: key1 = nf[0][1],nf[0][0] + else: key1 = nf[0][0],nf[0][1] + if nf[1][2]: key2 = nf[1][1],nf[1][0] + else: key2 = nf[1][0],nf[1][1] + + # CRAP, cont work out which way to flip so make it oppisite the verts normal. + + ###new_faces.append((i2, key1[0], key2[0])) # NO FLIPPING, WORKS THOUGH + ###new_faces.append((i1, key1[1], key2[1])) + new_faces.append(add_tri_flipped(i2, key1[0], key2[0])) + new_faces.append(add_tri_flipped(i1, key1[1], key2[1])) + + # Average vert loction so its not tooo pointy + # not realy needed but looks better + vert_users[i2].update((key1[0], key2[0])) + vert_users[i1].update((key1[1], key2[1])) + + if len(nf) == 1: + if nf[0][2]: new_faces.append((nf[0][0], nf[0][1], i2, i1)) # flipped + else: new_faces.append((i1,i2, nf[0][0], nf[0][1])) + + + # average points now. + for i, vusers in enumerate(vert_users): + if vusers: + co = me.verts[i].co + co.zero() + + for ii in vusers: + co += me.verts[ii].co + co /= len(vusers) + + + + me.faces.delete(1, range(len(me.faces))) + + me.faces.extend(new_faces) + + # External function, solidify + me.sel = True + if PREF_SOLID: + mesh_solidify.solidify(me, -inset_half*2, True, False, PREF_XSHARP) + + +def main(): + + # Gets the current scene, there can be many scenes in 1 blend file. + sce = bpy.data.scenes.active + + # Get the active object, there can only ever be 1 + # and the active object is always the editmode object. + ob_act = sce.objects.active + + if not ob_act or ob_act.type != 'Mesh': + BPyMessages.Error_NoMeshActive() + return + + # Create the variables. + PREF_THICK = Blender.Draw.Create(0.005) + PREF_SOLID = Blender.Draw.Create(1) + PREF_SHARP = Blender.Draw.Create(1) + PREF_XSHARP = Blender.Draw.Create(0) + + pup_block = [\ + ('Thick:', PREF_THICK, 0.0001, 2.0, 'Skin thickness in mesh space.'),\ + ('Solid Wire', PREF_SOLID, 'If Disabled, will use 6 sided wire segments'),\ + ('Sharp Wire', PREF_SHARP, 'Use the original mesh topology for more accurate sharp wire.'),\ + ('Extra Sharp', PREF_XSHARP, 'Use less geometry to create a sharper looking wire'),\ + ] + + if not Blender.Draw.PupBlock('Solid Wireframe', pup_block): + return + + # Saves the editmode state and go's out of + # editmode if its enabled, we cant make + # changes to the mesh data while in editmode. + is_editmode = Window.EditMode() + Window.EditMode(0) + + Window.WaitCursor(1) + me = ob_act.getData(mesh=1) # old NMesh api is default + t = sys.time() + + # Run the mesh editing function + solid_wire(ob_act, me, sce, PREF_THICK.val, PREF_SOLID.val, PREF_SHARP.val, PREF_XSHARP.val) + + # Timing the script is a good way to be aware on any speed hits when scripting + print 'Solid Wireframe finished in %.2f seconds' % (sys.time()-t) + Window.WaitCursor(0) + if is_editmode: Window.EditMode(1) + + +# This lets you can import the script without running it +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/release/scripts/obdatacopier.py b/release/scripts/obdatacopier.py new file mode 100644 index 00000000000..561e40e15da --- /dev/null +++ b/release/scripts/obdatacopier.py @@ -0,0 +1,215 @@ +#!BPY + +""" Registration info for Blender menus: <- these words are ignored +Name: 'Data Copier' +Blender: 232 +Group: 'Object' +Tip: 'Copy data from active object to other selected ones.' +""" + +__author__ = "Jean-Michel Soler (jms), Campbell Barton (Ideasman42)" +__url__ = ("blender", "elysiun", +"Script's homepage, http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_lampdatacopier.htm", +"Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender") +__version__ = "0.1.2" + +__bpydoc__ = """\ +Use "Data Copier" to copy attributes from the active object to other selected ones of +its same type. + +This script is still in an early version but is already useful for copying +attributes for some types of objects like lamps and cameras. + +Usage: + +Select the objects that will be updated, select the object whose data will +be copied (they must all be of the same type, of course), then run this script. +Toggle the buttons representing the attributes to be copied and press "Copy". +""" + +# ---------------------------------------------------------- +# Object DATA copier 0.1.2 +# (c) 2004 jean-michel soler +# ----------------------------------------------------------- +#---------------------------------------------- +# Page officielle/official page du blender python Object DATA copier: +# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_lampdatacopier.htm +# Communiquer les problemes et erreurs sur: +# To Communicate problems and errors on: +# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender +#--------------------------------------------- +# Blender Artistic License +# http://download.blender.org/documentation/html/x21254.html +#--------------------------------------------- + +import Blender +from Blender import * +from Blender.Draw import * +from Blender.BGL import * + + +scn= Blender.Scene.GetCurrent() + +type_func_method= type(dir) +type_func= type(lambda:i) +type_dict= type({}) +# type_list= type([]) + +IGNORE_VARS = 'users', 'fakeUser', 'edges', 'faces', 'verts', 'elements' + +def renew(): + scn= Blender.Scene.GetCurrent() + act_ob= scn.objects.active + if act_ob==None: + return {} + + act_ob_type= act_ob.getType() + act_ob_data= act_ob.getData(mesh=1) + + if act_ob_data==None: # Surf? + return {} + + PARAM={} + evt=4 + doc='doc' + + for prop_name in dir(act_ob_data): + if not prop_name.startswith('__') and prop_name not in IGNORE_VARS: + # Get the type + try: exec 'prop_type= type(act_ob_data.%s)' % prop_name + except: prop_type= None + + if prop_type != None and prop_type not in (type_func_method, type_func, type_dict): + + # Now we know that the attribute can be listed in the UI Create a button and tooltip. + + # Tooltip + try: + if prop_name=='mode': + try: + exec "doc=str(%s.Modes)+' ; value : %s'"%( act_ob_type, str(act_ob_data.mode) ) + except: + exec """doc= '%s'+' value = '+ str(act_ob.getData(mesh=1).%s)"""%(prop_name, prop_name) + elif prop_name=='type': + try: + exec "doc=str(%s.Types)+' ; value : %s'"%( act_ob_type, str(act_ob_data.type) ) + except: + exec """doc= '%s'+' value = '+ str(act_ob.getData(mesh=1).%s)"""%(prop_name, prop_name) + else: + exec """doc= '%s'+' value = '+ str(act_ob_data.%s)"""%(prop_name, prop_name) + if doc.find('built-in')!=-1: + exec """doc= 'This is a function ! Doc = '+ str(act_ob_data.%s.__doc__)"""% prop_name + except: + doc='Doc...' + + # Button + PARAM[prop_name]= [Create(0), evt, doc] + evt+=1 + + return PARAM + +def copy(): + global PARAM + + scn= Blender.Scene.GetCurrent() + act_ob= scn.getActiveObject() + if act_ob==None: + Blender.Draw.PupMenu('Error|No Active Object.') + return + + act_ob_type= act_ob.getType() + + if act_ob_type in ('Empty', 'Surf'): + Blender.Draw.PupMenu('Error|Copying Empty or Surf object data isnt supported.') + return + + act_ob_data= act_ob.getData(mesh=1) + + print '\n\nStarting copy for object "%s"' % act_ob.name + some_errors= False + for ob in scn.objects.context: + if ob != act_ob and ob.getType() == act_ob_type: + ob_data= None + for prop_name, value in PARAM.iteritems(): + if value[0].val==1: + + # Init the object data if we havnt alredy + if ob_data==None: + ob_data= ob.getData(mesh=1) + + try: + exec "ob_data.%s = act_ob_data.%s"%(prop_name, prop_name) + except: + some_errors= True + print 'Cant copy property "%s" for type "%s"' % (prop_name, act_ob_type) + if some_errors: + Blender.Draw.PupMenu('Some attributes could not be copied, see console for details.') + +PARAM= renew() + +def EVENT(evt,val): + pass + +def BUTTON(evt): + global PARAM + if (evt==1): + Exit() + + if (evt==2): + copy() + Blender.Redraw() + + if (evt==3): + PARAM= renew() + Blender.Redraw() + +def DRAW(): + global PARAM + + scn= Blender.Scene.GetCurrent() + act_ob= scn.objects.active + + glColor3f(0.7, 0.7, 0.7) + glClear(GL_COLOR_BUFFER_BIT) + glColor3f(0.1, 0.1, 0.15) + + size=Buffer(GL_FLOAT, 4) + glGetFloatv(GL_SCISSOR_BOX, size) + size= size.list + for s in [0,1,2,3]: size[s]=int(size[s]) + ligne=20 + + Button("Exit",1,20,4,80,ligne) + Button("Copy",2,102,4,80,ligne) + Button("Renew",3,184,4,80,ligne) + + glRasterPos2f(20, ligne*2-8) + if act_ob: + Text(act_ob.getType()+" DATA copier") + else: + Text("Please select an object") + + + max=size[3] / 22 -2 + pos = 0 + decal = 20 + key=PARAM.keys() + key.sort() + for p in key: + if pos==max: + decal+=102 + pos=1 + else: + pos+=1 + + PARAM[p][0]=Toggle(p, + PARAM[p][1], + decal, + pos*22+22, + 100, + 20, + PARAM[p][0].val, + str(PARAM[p][2])) + + +Register(DRAW,EVENT,BUTTON) diff --git a/release/scripts/object_apply_def.py b/release/scripts/object_apply_def.py new file mode 100644 index 00000000000..67e4179a674 --- /dev/null +++ b/release/scripts/object_apply_def.py @@ -0,0 +1,174 @@ +#!BPY + +""" +Name: 'Apply Deformation' +Blender: 242 +Group: 'Object' +Tooltip: 'Make copys of all the selected objects with modifiers, softbodies and fluid baked into a mesh' +""" + +__author__ = "Martin Poirier (theeth), Jean-Michel Soler (jms), Campbell Barton (ideasman)" +# This script is the result of merging the functionalities of two other: +# Martin Poirier's Apply_Def.py and +# Jean-Michel Soler's Fix From Everything + +__url__ = ("http://www.blender.org", "http://blenderartists.org", "http://members.iinet.net.au/~cpbarton/ideasman/", "http://jmsoler.free.fr") +__version__ = "1.6 07/07/2006" + +__bpydoc__ = """\ +This script creates "raw" copies of deformed meshes. + +Usage: + +Select any number of Objects and run this script. A fixed copy of each selected object +will be created, with the word "_def" appended to its name. If an object with +the same name already exists, it appends a number at the end as Blender itself does. + +Objects in Blender can be deformed by armatures, lattices, curve objects and subdivision, +but this will only change its appearance on screen and rendered +images -- the actual mesh data is still simpler, with vertices in an original +"rest" position and less vertices than the subdivided version. + +Use this script if you want a "real" version of the deformed mesh, so you can +directly manipulate or export its data. + +This script will work with object types: Mesh, Metaballs, Text3d, Curves and Nurbs Surface. +""" + + +# $Id$ +# +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2003: Martin Poirier, theeth@yahoo.com +# +# Thanks to Jonathan Hudson for help with the vertex groups part +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** + + +import Blender +import bpy +import BPyMesh + +def copy_vgroups(source_ob, target_ob): + + source_me = source_ob.getData(mesh=1) + + vgroups= source_me.getVertGroupNames() + if vgroups: + ADD= Blender.Mesh.AssignModes.ADD + target_me = target_ob.getData(mesh=1) + for vgroupname in vgroups: + target_me.addVertGroup(vgroupname) + if len(target_me.verts) == len(source_me.verts): + vlist = source_me.getVertsFromGroup(vgroupname, True) + try: + for vpair in vlist: + target_me.assignVertsToGroup(vgroupname, [vpair[0]], vpair[1], ADD) + except: + pass + + +def apply_deform(): + scn= bpy.data.scenes.active + #Blender.Window.EditMode(0) + + NAME_LENGTH = 19 + SUFFIX = "_def" + SUFFIX_LENGTH = len(SUFFIX) + # Get all object and mesh names + + + ob_list = list(scn.objects.context) + ob_act = scn.objects.active + + # Assume no soft body + has_sb= False + + # reverse loop so we can remove objects (metaballs in this case) + for ob_idx in xrange(len(ob_list)-1, -1, -1): + ob= ob_list[ob_idx] + + ob.sel = 0 # deselect while where checking the metaballs + + # Test for a softbody + if not has_sb and ob.isSB(): + has_sb= True + + # Remove all numbered metaballs because their disp list is only on the main metaball (un numbered) + if ob.type == 'MBall': + name= ob.name + # is this metaball numbered? + dot_idx= name.rfind('.') + 1 + if name[dot_idx:].isdigit(): + # Not the motherball, ignore it. + del ob_list[ob_idx] + + + if not ob_list: + Blender.Draw.PupMenu('No objects selected, nothing to do.') + return + + + if has_sb: + curframe=Blender.Get('curframe') + for f in xrange(curframe): + Blender.Set('curframe',f+1) + Blender.Window.RedrawAll() + + used_names = [ob.name for ob in Blender.Object.Get()] + used_names.extend(Blender.NMesh.GetNames()) + + + deformedList = [] + for ob in ob_list: + + # Get the mesh data + new_me= BPyMesh.getMeshFromObject(ob, vgroups=False) + + if not new_me: + continue # Object has no display list + + + name = ob.name + new_name = "%s_def" % name[:NAME_LENGTH-SUFFIX_LENGTH] + num = 0 + + while new_name in used_names: + new_name = "%s_def.%.3i" % (name[:NAME_LENGTH-(SUFFIX_LENGTH+SUFFIX_LENGTH)], num) + num += 1 + used_names.append(new_name) + + new_me.name= new_name + + new_ob= scn.objects.new(new_me) + new_ob.setMatrix(ob.matrixWorld) + + # Make the active duplicate also active + if ob == ob_act: + scn.objects.active = new_ob + + # Original object was a mesh? see if we can copy any vert groups. + if ob.type =='Mesh': + copy_vgroups(ob, new_ob) + + Blender.Window.RedrawAll() + +if __name__=='__main__': + apply_deform() \ No newline at end of file diff --git a/release/scripts/object_batch_name_edit.py b/release/scripts/object_batch_name_edit.py new file mode 100644 index 00000000000..05ca5868d19 --- /dev/null +++ b/release/scripts/object_batch_name_edit.py @@ -0,0 +1,274 @@ +#!BPY +""" +Name: 'Batch Object Name Edit' +Blender: 240 +Group: 'Object' +Tooltip: 'Apply the chosen rule to rename all selected objects at once.' +""" +__author__ = "Campbell Barton" +__url__ = ("blender", "elysiun") +__version__ = "1.0" + +__bpydoc__ = """\ +"Batch Object Name Edit" allows you to change multiple names of Blender +objects at once. It provides options to define if you want to: replace text +in the current names, truncate their beginnings or endings or prepend / append +strings to them. + +Usage: +Select the objects to be renamed and run this script from the Object->Scripts +menu of the 3d View. +""" +# $Id$ +# +# -------------------------------------------------------------------------- +# Batch Name Edit by Campbell Barton (AKA Ideasman) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- +from Blender import * +import bpy + +global renameCount +renameCount = 0 +obsel = [ob for ob in bpy.data.scenes.active.objects.context if not ob.lib] + +def setDataNameWrapper(ob, newname): + if ob.getData(name_only=1) == newname: + return False + + data= ob.getData(mesh=1) + + if data and not data.lib: + data.name= newname + return True + return False + +def main(): + global renameCount + # Rename the datablocks that are used by the object. + def renameLinkedDataFromObject(): + + # Result 1, we want to rename data + for ob in obsel: + if ob.name == ob.getData(name_only=1): + return # Alredy the same name, dont bother. + + data = ob.getData(mesh=1) # use mesh so we dont have to update the nmesh. + if data and not data.lib: + data.name = ob.name + + + def new(): + global renameCount + NEW_NAME_STRING = Draw.Create('') + RENAME_LINKED = Draw.Create(0) + pup_block = [\ + ('New Name: ', NEW_NAME_STRING, 19, 19, 'New Name'),\ + ('Rename ObData', RENAME_LINKED, 'Renames objects data to match the obname'),\ + ] + + if not Draw.PupBlock('Replace in name...', pup_block): + return 0 + + NEW_NAME_STRING= NEW_NAME_STRING.val + + Window.WaitCursor(1) + for ob in obsel: + if ob.name != NEW_NAME_STRING: + ob.name = NEW_NAME_STRING + renameCount+=1 + + return RENAME_LINKED.val + + def replace(): + global renameCount + REPLACE_STRING = Draw.Create('') + WITH_STRING = Draw.Create('') + RENAME_LINKED = Draw.Create(0) + + pup_block = [\ + ('Replace: ', REPLACE_STRING, 19, 19, 'Text to find'),\ + ('With:', WITH_STRING, 19, 19, 'Text to replace with'),\ + ('Rename ObData', RENAME_LINKED, 'Renames objects data to match the obname'),\ + ] + + if not Draw.PupBlock('Replace in name...', pup_block) or\ + ((not REPLACE_STRING.val) and (not WITH_STRING)): + return 0 + + REPLACE_STRING = REPLACE_STRING.val + WITH_STRING = WITH_STRING.val + + Window.WaitCursor(1) + for ob in obsel: + newname = ob.name.replace(REPLACE_STRING, WITH_STRING) + if ob.name != newname: + ob.name = newname + renameCount+=1 + return RENAME_LINKED.val + + + def prefix(): + global renameCount + PREFIX_STRING = Draw.Create('') + RENAME_LINKED = Draw.Create(0) + + pup_block = [\ + ('Prefix: ', PREFIX_STRING, 19, 19, 'Name prefix'),\ + ('Rename ObData', RENAME_LINKED, 'Renames objects data to match the obname'),\ + ] + + if not Draw.PupBlock('Prefix...', pup_block) or\ + not PREFIX_STRING.val: + return 0 + + PREFIX_STRING = PREFIX_STRING.val + + Window.WaitCursor(1) + for ob in obsel: + ob.name = PREFIX_STRING + ob.name + renameCount+=1 # we knows these are different. + return RENAME_LINKED.val + + def suffix(): + global renameCount + SUFFIX_STRING = Draw.Create('') + RENAME_LINKED = Draw.Create(0) + + pup_block = [\ + ('Suffix: ', SUFFIX_STRING, 19, 19, 'Name suffix'),\ + ('Rename ObData', RENAME_LINKED, 'Renames objects data to match the obname'),\ + ] + + if not Draw.PupBlock('Suffix...', pup_block) or\ + not SUFFIX_STRING.val: + return 0 + + SUFFIX_STRING = SUFFIX_STRING.val + + Window.WaitCursor(1) + for ob in obsel: + ob.name = ob.name + SUFFIX_STRING + renameCount+=1 # we knows these are different. + return RENAME_LINKED.val + + def truncate_start(): + global renameCount + TRUNCATE_START = Draw.Create(0) + RENAME_LINKED = Draw.Create(0) + + pup_block = [\ + ('Truncate Start: ', TRUNCATE_START, 0, 19, 'Truncate chars from the start of the name'),\ + ('Rename ObData', RENAME_LINKED, 'Renames objects data to match the obname'),\ + ] + + if not Draw.PupBlock('Truncate Start...', pup_block) or\ + not TRUNCATE_START.val: + return 0 + + Window.WaitCursor(1) + TRUNCATE_START = TRUNCATE_START.val + for ob in obsel: + newname = ob.name[TRUNCATE_START: ] + ob.name = newname + renameCount+=1 + + return RENAME_LINKED.val + + def truncate_end(): + global renameCount + TRUNCATE_END = Draw.Create(0) + RENAME_LINKED = Draw.Create(0) + + pup_block = [\ + ('Truncate End: ', TRUNCATE_END, 0, 19, 'Truncate chars from the end of the name'),\ + ('Rename ObData', RENAME_LINKED, 'Renames objects data to match the obname'),\ + ] + + if not Draw.PupBlock('Truncate End...', pup_block) or\ + not TRUNCATE_END.val: + return 0 + + Window.WaitCursor(1) + TRUNCATE_END = TRUNCATE_END.val + for ob in obsel: + newname = ob.name[: -TRUNCATE_END] + ob.name = newname + renameCount+=1 + + return RENAME_LINKED.val + + def renameObjectFromLinkedData(): + global renameCount + Window.WaitCursor(1) + + for ob in obsel: + newname = ob.getData(name_only=1) + if newname != None and ob.name != newname: + ob.name = newname + renameCount+=1 + return 0 + + def renameObjectFromDupGroup(): + global renameCount + Window.WaitCursor(1) + + for ob in obsel: + group= ob.DupGroup + if group != None: + newname= group.name + if newname != ob.name: + ob.name = newname + renameCount+=1 + return 0 + + def renameLinkedDataFromObject(): + global renameCount + Window.WaitCursor(1) + + for ob in obsel: + if setDataNameWrapper(ob, ob.name): + renameCount+=1 + return 0 + + name = "Selected Object Names%t|New Name|Replace Text|Add Prefix|Add Suffix|Truncate Start|Truncate End|Rename Objects to Data Names|Rename Objects to DupGroup Names|Rename Data to Object Names" + result = Draw.PupMenu(name) + renLinked = 0 # Rename linked data to the object name? + if result == -1: + return + elif result == 1: renLinked= new() + elif result == 2: renLinked= replace() + elif result == 3: renLinked= prefix() + elif result == 4: renLinked= suffix() + elif result == 5: renLinked= truncate_start() + elif result == 6: renLinked= truncate_end() + elif result == 7: renameObjectFromLinkedData() + elif result == 8: renameObjectFromDupGroup() + elif result == 9: renameLinkedDataFromObject() + + if renLinked: + renameLinkedDataFromObject() + + Window.WaitCursor(0) + + Draw.PupMenu('renamed: %d objects.' % renameCount) + +if __name__=='__main__': + main() diff --git a/release/scripts/object_cookie_cutter.py b/release/scripts/object_cookie_cutter.py new file mode 100644 index 00000000000..2a6e0ad6b2e --- /dev/null +++ b/release/scripts/object_cookie_cutter.py @@ -0,0 +1,667 @@ +#!BPY +""" +Name: 'Cookie Cut from View' +Blender: 234 +Group: 'Object' +Tooltip: 'Cut from the view axis, (Sel 3d Curves and Meshes (only edges) into other meshes with faces)' +""" +__author__= "Campbell Barton" +__url__= ["blender", "blenderartist"] +__version__= "1.0" + +__bpydoc__= """\ +This script takes the selected mesh objects, devides them into 2 groups +Cutters and The objects to be cut. + +Cutters are meshes with no faces, just edge loops. and any meshes with faces will be cut. + +Usage: + +Select 2 or more meshes, one with no faces (a closed polyline) and one with faces to cut. + +Align the view on the axis you want to cut. +For shapes that have overlapping faces (from the view), hide any backfacing faces so they will be ignored during the cut. +Run the script. + +You can choose to make the cut verts lie on the face that they were cut from or on the edge that cut them. +This script supports UV coordinates and images. +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Campbell Barton +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender +from math import sqrt +import BPyMesh +Vector= Blender.Mathutils.Vector +LineIntersect2D= Blender.Geometry.LineIntersect2D +PointInTriangle2D= Blender.Geometry.PointInTriangle2D + +# Auto class +def auto_class(slots): + exec('class container_class(object): __slots__=%s' % slots) + return container_class + + +bignum= 1<<30 +def bounds_xy(iter_item): + ''' + Works with types + MMesh.verts + MFace + MEdge + ''' + xmin= ymin= bignum + xmax= ymax= -bignum + for v in iter_item: + x= v.co.x + y= v.co.y + if xxmax: xmax= x + if y>ymax: ymax= y + + return xmin, ymin, xmax, ymax + +def bounds_intersect(a,b): + ''' + each tuple is + xmin, ymin, xmax, ymax + ''' + if\ + a[0]>b[2] or\ + a[1]>b[3] or\ + a[2]i2: + i1,i2= i2,i1 + return i1, i2 + +def sorted_indicies(i1, i2): + if i1>i2: + i1,i2= i2,i1 + return i1, i2 + +def fake_length2d(pt1, pt2): + ''' + Only used for comparison so dont sqrt + ''' + #return math.sqrt(abs(pow(x1-x2, 2)+ pow(y1-y2, 2))) + return pow(pt1[0]-pt2[0], 2) + pow(pt1[1]- pt2[1], 2) + +def length2d(pt1, pt2): + ''' + Only used for comparison so dont sqrt + ''' + #return math.sqrt(abs(pow(x1-x2, 2)+ pow(y1-y2, 2))) + return sqrt(pow(pt1[0]-pt2[0], 2) + pow(pt1[1]- pt2[1], 2)) + + + +def tri_area_2d(v1, v2, v3): + e1 = length2d(v1, v2) + e2 = length2d(v2, v3) + e3 = length2d(v3, v1) + p = e1+e2+e3 + return 0.25 * sqrt(abs(p*(p-2*e1)*(p-2*e2)*(p-2*e3))) + +def tri_pt_find_z_2d(pt, tri): + """ Takes a face and 3d vector and assigns teh vectors Z to its on the face""" + + l1= tri_area_2d(tri[1], tri[2], pt) + l2= tri_area_2d(tri[0], tri[2], pt) + l3= tri_area_2d(tri[0], tri[1], pt) + + tot= l1+l2+l3 + # Normalize + l1=l1/tot + l2=l2/tot + l3=l3/tot + + z1= tri[0].z*l1 + z2= tri[1].z*l2 + z3= tri[2].z*l3 + + return z1+z2+z3 + + +def tri_pt_find_uv_2d(pt, tri, uvs): + """ Takes a face and 3d vector and assigns teh vectors Z to its on the face""" + + l1= tri_area_2d(tri[1], tri[2], pt) + l2= tri_area_2d(tri[0], tri[2], pt) + l3= tri_area_2d(tri[0], tri[1], pt) + + tot= l1+l2+l3 + if not tot: # No area, just return the first uv + return Vector(uvs[0]) + + # Normalize + l1=l1/tot + l2=l2/tot + l3=l3/tot + + uv1= uvs[0]*l1 + uv2= uvs[1]*l2 + uv3= uvs[2]*l3 + + return uv1+uv2+uv3 + + + + +def mesh_edge_dict(me): + ed_dict= {} + for f in me.faces: + if not f.hide: + for edkey in f.edge_keys: + ed_dict.setdefault(edkey, []).append(f) + + return ed_dict + + + +def terrain_cut_2d(t, c, PREF_Z_LOC): + ''' + t is the terrain + c is the cutter + + PREF_Z_LOC: 0 - from terrain face + 1 - from cutter edge + + returns nothing + ''' + + # do we have a 2d intersection + if not bounds_intersect(t.bounds, c.bounds): + return + + # Local vars + me_t= t.mesh + me_c= c.mesh + + has_uv= me_t.faceUV + + Blender.Mesh.Mode(Blender.Mesh.SelectModes['VERTEX']) + ''' + first assign a face terrain face for each cutter verticie + ''' + cut_verts_temp= list(me_c.verts) + cut_vert_terrain_faces= [None] * len(me_c.verts) + vert_z_level= [-10.0] * len(me_c.verts) + + for v in me_c.verts: + v_index= v.index + v_co= v.co + for fidx, f in enumerate(me_t.faces): + if not f.hide: + if point_in_bounds(v_co, t.face_bounds[fidx]): + f_v= [vv.co for vv in f] + if point_in_poly2d(v_co, f_v): + + + if PREF_Z_LOC==0: + ''' + Get the z location from the face. + ''' + + if len(f_v)==3: + vert_z_level[v_index]= tri_pt_find_z_2d(v_co, (f_v[0], f_v[1], f_v[2]) ) + else: + # Quad, which side are we on? + a1= tri_area_2d(f_v[0], f_v[1], v_co) + a2= tri_area_2d(f_v[1], f_v[2], v_co) + + a3= tri_area_2d(f_v[0], f_v[1], f_v[2]) + + if a1+a2

Blender v2.3x series

+
+
    +
  1. About
  2. +
  3. Package Contents and Install
  4. +
  5. Getting Started:
  6. +
      +
    1. Running
    2. +
    3. First steps, +The 3d View
    4. +
    +
  7. Resources
  8. +
  9. Troubleshooting
  10. +
  11. (FAQ) A few remarks
  12. +
+ +

1. About

+ +

Welcome to the world of Blender! +The program you have now in your hands is a free and fully functional 3D +modeling, rendering, animation and game creation suite. It is available for +Unix-based (Linux, Mac OS X, etc.) and Windows systems and has a large +world-wide community.

+ +

Blender is free to be applied for any purpose, including commercial usage and +distribution. It's open-source software, released under a dual GPL / BL +licence. The full program sources are available online.

+ +

For impatient readers, here the two most important links:

+www.blender.org the developement/community website
+www.blender3d.org the general website
+ +

back to top

+ +

2. Package Contents and Install

+ +

This is what you should get from a downloaded Blender package:

+ +
    +
  • The Blender program for some specific platform;
  • +
  • This text, with links and the copyright notice;
  • +
  • A basic set of scripts, including importers and exporters to other 3d + formats.
  • +
+ +

The latest version for all supported platforms can always be found at the +main Blender site, along with documentation, sample .blend files, many scripts, +plugins and more.

+ +

If you are interested in the development of the program, information for +coders and the CVS repository with the sources can be found at the +developer's site.

+ +

Installation notes:

+ +

Installing is mostly a matter of executing a self-installer package or unpacking it to +some folder. Blender has a minimum of system dependencies (like OpenGL and SDL), and doesn't +install by overwriting libraries in your system. There are also some extra +files needed for a good install, like an antialiased font and standard python scripts, but these +are optional. Typically these will go to your HOME/.blender/ +directory. Below you find instructions for it per OS. +

+ +

Windows: the .exe installer handles registry of file types for you. The .zip download has +a .blender directory included, which can be manually copied.
+The directory .blender is located by Blender while checking the following list:
+- whether environment variable HOME exists,
+- or, if environment USERPROFILE exists, and the installer has created there the Application Data\Blender Foundation\Blender\ +directory,
+- or it uses the .blender directory from the installation directory (where blender.exe resides)
+Also note that Blender comes with two dll files, which have to reside next to blender.exe.

+ +

Linux, FreeBSD, Irix, Solaris: after unpacking the distribution, you can copy the .blender +directory from it to your home directory.

+ +

OSX: the .blender directory is in Blender.app/Contents/Resources/. This is being located +by default. If you like to alter some of the files, copy this directory to your home dir.

+ +

Other settings:
+There are many paths you can set in Blender itself, to tell it where to +look for your collections of texture and sound files, fonts, plugins and +additional scripts, besides where it should save rendered images, temporary +data, etc. If you're only starting, there's no need to worry about this now. +

+ +

Python:
+Some downloaded scripts may require extra Python modules not shipped with +Blender. Installing the whole Python distribution is a way to solve this +issue for most cases except scripts that require extensions (3rd party +modules), but we are starting to add more modules to Blender itself so that +most scripts don't depend on full Python installs anymore. This is mostly +about Windows, in other platforms Python is usually a standard component +nowadays, so unless there's a version mismatch or an incomplete py +installation, there should be no problems.

+ +

Even if you do have the right version of Python installed you may need to +tell the embedded Python interpreter where the installation is. To do that +it's enough to set a system variable called PYTHON to the full path to the +stand-alone Python executable (to find out execute "import sys; print +sys.executable" inside the stand-alone interpreter, not in Blender). To check +which Python was linked to your Blender binary, execute "import sys; print +sys.version" at Blender's text editor), it's probably 2.3.something -- only the +two first numbers should have to match with yours.

+ + +

back to top

+ +

3. Getting Started

+ +

Blender's main strength is at modeling, animating and rendering 3d +scenes, from simple cubes and monkey heads to the complex environments found in +videogames and movies with computer graphics (CG) art.

+ +

Rendering is the process of generating 2d images from 3d +data (basically lit 3d models) as if viewed by a virtual camera. In simple +terms, rendering is like taking a picture of the scene, but with many more +ways to influence the results. Blender comes with a very flexible renderer +and is well integrated with the open source YafRay package. There are also +scripts to export to other popular third party renderers like Povray and +Renderman compliant ones. By animating the data and rendering +pictures of each successive frame, movie sequences can be created.

+ +

In compositing a set of techniques is used to add effects +to movie strips and combine these into a single video. This is how, for +example, artists add laser beams, glows and dinossaurs to motion +pictures. Blender is not a specific tool for this purpose, but it has builtin +support for video sequencing and sound synchronization.

+ +

The game engine inside Blender lets users create and play +nifty 3d games, complete with 3d graphics, sound, physics and scripted rules. +

+ +

Via scripting the program's functionality can be automated +and extended in real-time with important new capabilities. True displacement +mapping, for example, is now part of the core program, but before that it was +already possible using scripts. Since they are written in a nice higher-level +programming language -- Python in our case +-- development is considerably faster and easier than normal C/C++ coding. +Naturally, they run slower than compiled code, but still fast enough for +many purposes or for mixed approaches like some plugins use.

+ +

Running:

+ +

Depending on your platform, the installation may have put an icon on your +desktop and a menu entry for Blender. If not, it's not hard to do that +yourself for your favorite window manager.

+ +

But for more flexibility, you can execute Blender from a shell window or +command-line prompt. Try "blender -h" to see all available options.

+ +

Blender saves data in its own custom binary format, using ".blend" as +extension. The default start-up configuration is saved in a file called +.B.blend. To save your changes to it, click on +File->Save Default Settings or use the Control+u shortcut +directly. To revert to factory defaults, erase the .B.blend file.

+ +

First steps:

+ +

This is the point where we stop and warn newcomers that 3d Computer +Graphics is a vast field and Blender has a lot of packed functionality. +If you already tried to run it and fell victim to the "too many buttons!" +syndrome, just relax and read this part of the F.A.Q.

+ +

Hoping the explanations helped, let's start Blender and take a look at it. +At the top header you can see the main menu. Under "File" you'll find entries +to save, load and quit. If someone ever messes with your workspace +and you can't find your way around: press q to quit. Then erase the .B.blend +file in your home dir and the program will be back to factory defaults.

+ +

Blender's screen is divided in "areas". Each of them has a top or bottom +header and can show any of the available builtin applications (called "spaces", +like the 3d View, the Text Editor, etc). If you started with a default +configuration, there should now be three areas: +

+ +
    +
  • A thin strip at the top where you can see the header of the User +Preferences Window (its header is also Blender's main menu);
  • +
  • A big one in the middle with the 3d View, where you +model and preview your scenes;
  • +
  • A smaller at the bottom with the Buttons Window, where +you add and configure most of your scene data.
  • +
+ +

These are the three most important spaces, at least when you are starting. +At the left corner of each header you can find the "Window Types" button, +which is like the "Start" buttom of many desktop environments. Clicking on +it lets you change what is shown in that area.

+ +

Highly configurable workspace

+ +

Blender's interface has been considerably improved for the 2.3x series. +Besides the goals of exposing functionality via menus and adding tooltips +for all buttons, there are even more ways now to change your workspace.

+ +

As before, areas can be resized, subdivided in two or joined; headers can +be moved to the top or bottom of an area or hidden completely. Just experiment +to find out how, it's trivial. Hint: the mouse cursor changes to a double arrow +when it is over the inter-area edges.

+ +

There should be a button with "SCR:" in the top header. It has some preset +workspaces that can be tried now for a tour of the possibilities. When you +change your current setup to something worth keeping, that same button has the +option to save the new screen.

+ +

Since version 2.30 Blender lets users define new color themes that can also +be shared with others when saved in the default startup .B.blend file.

+ +

The User Preferences space has many options there that you may want to +tweak, like turning button tooltips on/off, setting paths, etc. Just remember +to save your configuration if you want to keep it for the next session). +Since these preferences are not saved in regular .blend files, the presets will +retain working even when loading files from others. Note however, that the arrangement +of the UI itself - its screens and windows - are always saved in each file. +

+ +

The 3d View:

+ +

Mouse buttons and the toolbox

+ +

Pressing the SPACEBAR or Shift+a while the mouse pointer is inside a 3d +View space will open up the toolbox. The toolbox gives you faster access to +many functions, like adding new objects to your scene, editing their properties, +selecting and so on.

+ +

This is how the mouse buttons work in this space: +

    +
  • Left button: anchor the 3d cursor in a new location -- it defines where +your next added object will appear, among other things.
  • +
  • Right button: selection. If you hold it and move, you can move the +selected item around.
  • +
  • Middle button: 3d space rotation or translation -- choose which one in +one of the User Preferences tabs.
  • +
+Combinations of mouse buttons and Shift or Control will give you additional +options like zooming, panning and restricted movement. 3d scenes can be seen +from any position and orientation, but there are some default ones you can +reach with Numpad buttons or the "View" menu in the 3d View's header.

+ +

Edit Mode

+ +

When you want to edit the vertices of a mesh, for example, it's necessary to +select the object and enter "Edit Mode", either using the 3d View header "Mode" +button or by pressing TAB on your keyboard (press it again to return to object +mode).

+ +

And this was only the beginning ...

+ +

The above guidelines should have given new users enough to start playing +with the interface. The next section lists online references that can actually teach about 3d and this program, but it's a good idea to spend some time just +playing with Blender, looking at menus and finding what mouse actions do in +each space.

+ +

back to top

+ +

4. Resources

+ + + +

This short presentation is meant to guide newcomers to Blender through their +very first steps, giving directions to where you can find the +resources you will need. We can't teach you 3D in these few lines of text, +that would take a lengthy book.

+ +

The Blender Foundation has released a new guide, with hundreds of pages of +illustrated tutorials. It comes with a CD-ROM that has Blender version 2.32, +YafRay and many goodies: sample .blend files with models, textures and +animations, plugins, scripts, documentation, etc. It's an extensive reference +written by Blender gurus and also a good way to help Blender development.

+ +

New: the new guide's text is now available for download +online and the second edition of the printed book has also been released.

+ +

You can learn more about it at the main Blender site: +www.blender3d.org. There you'll also +find news, online documentation like tutorials, the 2.0 guide, the Blender +Python API Reference for script writers, docs for the newest features added +to the program, etc. There are also forums, galleries of images and movies, +games, scripts, plugins, links for many resources and more.

+ +

The main Blender community site is elYsiun: +www.elysiun.com. There's a lot of +activity in its user forums, where newbie and guru users share tips and tricks, +show their most recent images, movies and scripts, ask for help and generally +have a good time.

+ +

Irc users are invited to try #blenderchat on irc.freenode.net .

+ +

There are also local Blender community sites in some countries, that should +be listed at the links section of the main site.

+ +

If you are a coder wanting to get in touch with Blender development, the +developer's site is at www.blender.org. A +good way to start is to follow the mailing lists for a while and check bug +reports, to see if you can fix one. On irc.freenode.net: #blendersauce (open channel) +and #blendercoders (official channel, where also meetings take place).

+ +

Other useful links

+ +

In the realm of open-source cg programs, it's a pleasure to mention other +great projects that can help you achieve your visions. Note that these +programs are completely independent from Blender and have their own sites, +documentation and support channels. Note also that this list is not complete +and should be updated on future versions of this text.

+ +
+
The Gimp
+
The mighty GNU Image Manipulation Program. In 3d work it is a valuable +resource to create, convert and, of course, manipulate texture images. +It is also useful for work with rendered pictures, for example to add 2d text, +logos or to touch-up, apply factory or hand-made effects and compose with other +images.
+
The Wings 3D modeler
+
A great mesh modeler, with a different approach. Some things are much +easier to model in Wings, others in Blender, making them a powerful combination +for experienced users.
+
+ +

Renderers:

+ +
+
YafRay
+
A relatively new and already very impressive program. Blender has builtin +support for it.
+
Povray
+
One of the best and most popular renderers in the world. There is a +script to export Blender scenes to be rendered with it.
+
Renderman-compliant: +open-source: Aqsis, +Pixie. Closed-source: +3delight.
+
The Renderman spec was created by Pixar years ago to define both a +standard and powerful representation of 3d data for renderers and the expected +quality of the renderization itself. Think about 3d art from some movie -- it +was much probably created by Pixar's own Photorealistic Renderman (PRMan) +renderer. This is a good site to learn more: +The Renderman Academy. Neither +Pixar nor its products are affiliated with Blender.
+
+ +

back to top

+ +

5. Troubleshooting

+ +

If something isn't working, please read this entire section before looking +for help.

+ + + +

General start-up and usage problems

+ +

If the program crashes or something isn't working properly, try running +Blender in debug mode: execute it as "blender -d" from a +command prompt. This might give some info about what is wrong. There are also +other options that might be useful, "blender -h" lists all of them.
+Most likely an immediate crash is due to Blender's need for a compliant and +stable working OpenGL.

+ +

Video card blues

+ +

Although OpenGL is cherished as an excellent cross platform library, the enormous +growth of different 3D cards have made this a complicated affair for Blender. Unlike +other programs - or 3D games - Blender utilizes OpenGL for its entire GUI, including +buttons and pulldown menus. That means also the 2D options for OpenGL should +work good, something easily ignored or badly tested by 3D card manufacturors, who +target more at the latest SFX features for new 3D games.
+In general Blender performs +very well on 3D cards from renowned brands, such as NVidia, ATI or 3DLabs. Recently +however, new drivers (especially for ATI) have shown that they're dropping basic +OpenGL support needed for proper menu drawing in Blender. Downgrading drivers then +always works, but we're also working on rebuilding the (quite old) code for GUI +drawing to prevent such errors from ever happening again.

+ +

Some useful links to check:
+ +The graphics card FAQ
+3D card performance database
+ + +

+ +

Scripts

+ +

To be sure that some functionality is scripted: all scripts in Blender can +be accessed from the "Scripts" menu in the Scripts Window's header, even if the +same functionality is also in another menu somewhere. If you see an entry in +one of the submenus there, it refers to a script. Please don't report problems +with scripts to the bug tracker or other normal Blender channels. You should +find the author's site or contact email in the script's text itself, but +usually the Python & Plugins forum at +elYsiun is used for posting +announcements, questions, suggestions and bug reports related to scripts. It's +the recommended place to look first, specially if no site was specified at the +script's window or source file(s).

+

If some or all scripts that should appear in menus are not there, running +Blender in debug mode can possibly inform what is +wrong. Make sure the reported dir(s) really exist.

+ +

The Bug Tracker

+ +

If you really think you found a new bug in Blender, check the Bug Tracker +entries at the projects site and if +it was not reported yet, please log in (or register) and fill in detailed +information about the error. A small .blend file or script (if it is a problem +with the Blender Python API) showcasing the bug can help a lot.

+ +

back to top

+ +

6. (FAQ) A few remarks

+ +
    +
  1. Quick tips.
  2. +
  3. What's up with the interface?
  4. +
  5. How good is Blender? How does it compare to other 3d +programs?
  6. +
  7. Something doesn't work, what do I do?
  8. +
+ +

Quick tips:

+ +

Rendering: to see something when you render (F12) an image, +make sure the scene has a camera pointing at your models (camera view is +NumPad 0) and at least one light properly placed. Otherwise you'll only get a +black rectangle.

+ +

Setting texture map input to "uv" in the Material Buttons window is not enough +to assign a texture image and uv data to a mesh. It's necessary to select the mesh, +enter face select mode (modes can be accessed in the 3d view's header), load an +image in the UV/Image Editor window and then define the mapping. Only then +the mesh will have uv data available for exporting.

+ +

If you want the fastest possible access to Blender's functionality, remember +what a wise power user wrote: "keep one hand on the keyboard +and the other on the mouse". Learn and use the shortcuts, configure your +workspace to your needs.

+ +

What's up with the interface?

+ +

Blender does not follow the most common, somewhat standard rules for user +interfaces -- it doesn't look like most programs do -- which is not necessarily +a bad thing. There used to be two sides to this: Blender was both a powerful +production tool for professionals and enthusiasts who dedicated enough time to +master it and also a nightmare for some newcomers who might have tried one of +the commercial 3d modelers first. The main reason for this is that +Blender was born as an in-house studio tool, optimized to speed up daily heavy +work, not to please everyone. But it's true that in the past the interface +was far from newbie-friendly.

+ +

Hopefully this is not the case anymore: it has been considerably +improved for the 2.3x series, exposing most functionality via menus, adding +panels, color "themability", tooltips for all buttons and internationalization +support. This is an ongoing effort or, better, a goal to keep the best ideas +in Blender's design while expanding and making it more user-friendly.

+ +

Too many buttons!

+ +

Again, 3D Computer Graphics is a vast and fun field. If you're only +starting, Blender can seem daunting, specially because of all its packed +functionality. Don't let that upset you, there is no need to care about +all those buttons right now -- or ever.

+ +

There are basic things all users should learn early up:

+ +
    +
  • Start the program and access the main menus;
  • +
  • Find and configure user preferences;
  • +
  • Basic scene set-up: how to add and transform (move, scale, rotate) + lights, cameras and objects;
  • +
  • Create and link materials to objects, at least to color them;
  • +
  • Render your scenes.
  • +
+ +

One hour is enough time to assimilate and practice that before going on +with basic mesh editing and texturing, for example. There are many different +areas to learn about. Taste, interaction with other users and your main +interests (game art, rendered stills, movies) will guide you and define the +skills you'll want to master. Then it goes like a spiral: practice something +for a while, study and find about new tricks or whole new areas, practice a +little more and so on. Soon you'll become pleased to have all those buttons to +play with. A few more months and you'll probably be back asking for more ... +

+ +

How good is Blender?

+ +

If you ever get the impression that it's not possible to create great +looking or complex works with Blender, rejoice -- you are just plainly +uninformed, as browsing galleries and community forums can easily confirm.

+ +

How does it compare to other 3d programs?

+ +

In short: it takes considerable dedication to become good, no matter which +program you work with, as long as it is good enough not to get in your way. +Blender is. And, like the others, has strong and weak points.

+ +

Compared to commercial alternatives, Blender misses some features and isn't +as "newbie-friendly". It doesn't come packed with "one-click" or "wizard" +functionality, where you get much faster results in detriment of flexibility +and value. It also isn't bundled with tens of megabytes of sample models, +texture images, tutorials, etc. (which only partly explains how Blender can fit +in a less than 4 MB download).

+ +

Thankfully, these are not fatal shortcomings. The pace at which features +are being added or polished in Blender is impressive, now that it's a well +stablished open source project. More: through plugins and scripting, many +repetitive or otherwise cumbersome tasks can be made trivial. But plugin and +script authors go further, teaching Blender new tricks, from importers and +exporters to more advanced "applications".

+ +

About goodies, there are many places where you can get them (check +resources). Besides the book, the main site and +elYsiun are the best ones to start, specially because some resources you +find spread on the net are not up-to-date with current program versions. This +doesn't render old tutorials or books useless -- just a little harder to +follow, sometimes -- but older scripts probably won't work. For free texture +images, a simple search for "free textures" should bring many results, just pay +attention to their licenses if you plan to release your work later.

+ +

Commercial packages can make it easier for newbies to produce nice looking +material, but only another newbie would praise the results. There's a huge +difference between what a skilled artist and someone poking at buttons and +using presets can accomplish.

+ +

Last but best of all: Blender is open-source, free for all to use, study and +improve.

+ + +

Something doesn't work, what do I do?

+ +

First note again that errors and questions related to specific scripts +should not be sent to Blender developers or its bug tracker. Then +read this short section thoroughly, please.

+ +
+

Thanks for reading, we hope you enjoy Blender!

+ +

Document version 1.01, June 2004

+ +

back to top

+ + + diff --git a/release/text/copyright.txt b/release/text/copyright.txt new file mode 100644 index 00000000000..6082af3033f --- /dev/null +++ b/release/text/copyright.txt @@ -0,0 +1,120 @@ + + This version of Blender has been originally released at www.blender.org. + It is subject to the GPL license, which is part of this download. + For more information please review the Blender source code distribution, + which should be available at the same location as where you obtained + this version. + + IMPORTANT: PLEASE READ CAREFULLY BEFORE USING THE BLENDER SOFTWARE + + This License Agreement for the Blender software ("License + Agreement") is an agreement between Stichting Blender Foundation, + Amsterdam, the Netherlands ("BF") and you (either an individual or a + legal entity) ("You") with respect to the software product which this + License Agreement accompanies (the "Software"). + + By installing, copying or otherwise using the Software, You agree to be + bound by the terms of this License Agreement. If You do not agree to the + terms of this License Agreement do not install or use the Software. + + 1. Grant of License + + Subject to the provisions of this License Agreement, BF grants You a + limited, non-exclusive, personal, non-sublicenseable, non-transferable + license to use the Software at any computer You own or use. + Artwork you create with the Software - whether it is images, movies, + scripts, exported 3d files or the .blend files themselves - is your sole + property, and can be licensed or sold under any conditions you prefer. + + 2. Permitted copying and electronic distribution of Software + + You are hereby granted permission to copy and distribute the Software + without written agreement from BF. This entire License Agreement, and + the GPL-license.txt must appear in and/or accompany all copies of the + Software. The source code distribution, which can be found at the same + location where you obtained the Software, has to accompany all copies + of the Software as well. + + 3. Disclaimer of Warranties + + BF provides you with the Software "as is" and with all faults. BF + explicitly disclaims all warranties and guarantees and does not make any + representations with respect to the Software, whether express, implied, + or statutory, including, but not limited to any (if any) warranties of + or related to: fitness for a particular purpose, title, + non-infringement, lack of viruses, accuracy or completeness of + responses, results, lack of negligence or lack of workmanlike effort, + and correspondence to description. The entire risk arising out of use or + performance of the Software remains with You. + + 4. Limitation of Liability + + In no event shall BF or its employees, agents or suppliers be liable + for any direct, indirect, consequential, incidental, special, punitive, + or other damages whatsoever (including, without limitation, damages for + loss of business profits, business interruption, loss of business + information, claims of third parties, damages as a result of injury to + any person, or any other loss) arising out of or in connection with the + license granted under this License Agreement or the use of or inability + to use the Software, even if VF has been advised of the possibility of + such damages. + + 5. User warning and indemnification + + WARNING: use of the Software and use of any works that are (partially) + created with the Software (the "Works") may cause physical or + psychological reactions from You or from third parties, which may result + in damages, injuries, losses and/or other negative consequences. You + acknowledge that BF can not be held liable for any such damages, + injuries, losses and/or other negative consequences. You acknowledge + that it is your obligation to investigate, prevent and/or minimize such + reactions prior to having third parties use the Works. + + You shall indemnify and hold harmless BF from and against all actions, + claims, demands, proceedings, losses, damages, costs, charges and + expenses, including but not limited to legal fees and expenses, arising + out of or in connection with (i) the use of the Software by You and (ii) + the use of any Works created with the Software by You or any third + parties. + + 6. Term and Termination + + This License Agreement and the license granted hereunder is effective + until terminated. This License Agreement shall terminate automatically + and forthwith if You fail to comply with the terms of this License + Agreement. Upon termination, You shall cease the use of the Software, + remove the Software from (the memory of) your computer and destroy all + copies of the Software. + + 7. Entire Agreement + + This License Agreement is the entire agreement between BF and You in + respect of the subject matter of the License Agreement. This License + Agreement supersedes all prior written or oral agreements, proposals or + understandings, and any other communications between BF and You + relating to the subject matter of this License Agreement. + + 8. Enforceability + + If any provision of this License Agreement is held to be unenforceable + by a court of competent jurisdiction for any reason, such provision + shall be adapted or amended only to the extent necessary to make it + enforceable, and the remainder of the License Agreement shall remain in + effect. + + 9. Governing law and disputes + + This License Agreement and all disputes arising from it will be governed + by the laws of The Netherlands. All disputes arising in connection with + this Agreement that cannot be settled amicably shall be brought before + the competent court in Amsterdam, the Netherlands, to which jurisdiction + BF and You hereby irrevocably consent. + + Stichting Blender Foundation + Amsterdam + the Netherlands + Chamber of Commerce: 34176425 + + http://www.blender.org + foundation@blender.org + diff --git a/release/windows/contrib/vfapi/README b/release/windows/contrib/vfapi/README new file mode 100644 index 00000000000..f4081bfe02a --- /dev/null +++ b/release/windows/contrib/vfapi/README @@ -0,0 +1,26 @@ +VFAPI-Plugin + +This plugin enables TMPGEnc (or other VFAPI-compliant applications) +to directly connect to the blender frameserver. (Well, this was the +intention of the frameserver... ;-) + +Use mingw + +i586-mingw32msvc-gcc -shared vfapi-plugin.c -o blenderserver.vfp -lwsock32 +i586-mingw32msvc-strip blenderserver.vfp + +and copy the resulting plugin into your TMPGenc directory. + +Usage: + +Create a small file that only contains + +host:port + +where "host" is running blender frameserver on "port" + +and call it something.blu + +You can open the blu-file in TMPGenc. That's all. The rest is automagic. +By the way: the whole thing is developed completely under linux and +tested successfully with a vanilla wine-0.9.6... diff --git a/release/windows/contrib/vfapi/vfapi-plugin.c b/release/windows/contrib/vfapi/vfapi-plugin.c new file mode 100644 index 00000000000..c54f8234d2d --- /dev/null +++ b/release/windows/contrib/vfapi/vfapi-plugin.c @@ -0,0 +1,418 @@ +/* + * VFAPI-Plugin + * + * Copyright (c) 2006 Peter Schlaile + * + * 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. + * + */ + + +#include +#include +#include +#include +#include + +#define VF_STREAM_VIDEO 0x00000001 +#define VF_STREAM_AUDIO 0x00000002 +#define VF_OK 0x00000000 +#define VF_ERROR 0x80004005 + +typedef struct { + DWORD dwSize; + DWORD dwAPIVersion; + DWORD dwVersion; + DWORD dwSupportStreamType; + char cPluginInfo[256]; + char cFileType[256]; +} VF_PluginInfo,*LPVF_PluginInfo; + +typedef DWORD VF_FileHandle,*LPVF_FileHandle; + +typedef struct { + DWORD dwSize; + DWORD dwHasStreams; +} VF_FileInfo,*LPVF_FileInfo; + +typedef struct { + DWORD dwSize; + DWORD dwLengthL; + DWORD dwLengthH; + DWORD dwRate; + DWORD dwScale; + DWORD dwWidth; + DWORD dwHeight; + DWORD dwBitCount; +} VF_StreamInfo_Video,*LPVF_StreamInfo_Video; + +typedef struct { + DWORD dwSize; + DWORD dwLengthL; + DWORD dwLengthH; + DWORD dwRate; + DWORD dwScale; + DWORD dwChannels; + DWORD dwBitsPerSample; + DWORD dwBlockAlign; +} VF_StreamInfo_Audio,*LPVF_StreamInfo_Audio; + +typedef struct { + DWORD dwSize; + DWORD dwFrameNumberL; + DWORD dwFrameNumberH; + void *lpData; + long lPitch; +} VF_ReadData_Video,*LPVF_ReadData_Video; + +typedef struct { + DWORD dwSize; + LONGLONG dwSamplePos; + DWORD dwSampleCount; + DWORD dwReadedSampleCount; + DWORD dwBufSize; + void *lpBuf; +} VF_ReadData_Audio,*LPVF_ReadData_Audio; + +typedef struct { + DWORD dwSize; + HRESULT (__stdcall *OpenFile)( + char *lpFileName, LPVF_FileHandle lpFileHandle ); + HRESULT (__stdcall *CloseFile)( VF_FileHandle hFileHandle ); + HRESULT (__stdcall *GetFileInfo)( VF_FileHandle hFileHandle, + LPVF_FileInfo lpFileInfo ); + HRESULT (__stdcall *GetStreamInfo)( VF_FileHandle hFileHandle, + DWORD dwStream,void *lpStreamInfo ); + HRESULT (__stdcall *ReadData)( VF_FileHandle hFileHandle, + DWORD dwStream,void *lpData ); +} VF_PluginFunc,*LPVF_PluginFunc; + +__declspec(dllexport) HRESULT vfGetPluginInfo( + LPVF_PluginInfo lpPluginInfo ) +{ + if (!lpPluginInfo || lpPluginInfo->dwSize != sizeof(VF_PluginInfo)) { + return VF_ERROR; + } + + lpPluginInfo->dwAPIVersion = 1; + lpPluginInfo->dwVersion = 1; + lpPluginInfo->dwSupportStreamType = VF_STREAM_VIDEO; + strcpy(lpPluginInfo->cPluginInfo, "Blender Frameserver"); + strcpy(lpPluginInfo->cFileType, + "Blender Frame-URL-File (*.blu)|*.blu"); + + return VF_OK; +} + +static unsigned long getipaddress(const char * ipaddr) +{ + struct hostent *host; + unsigned long ip; + + if (((ip = inet_addr(ipaddr)) == INADDR_NONE) + && strcmp(ipaddr, "255.255.255.255") != 0) { + if ((host = gethostbyname(ipaddr)) != NULL) { + memcpy(&ip, host->h_addr, sizeof(ip)); + } + } + + return (ip); +} + +static void my_send(SOCKET sock, char * str) +{ + send(sock, str, strlen(str), 0); +} + +static int my_recv(SOCKET sock, char * line, int maxlen) +{ + int got = 0; + int toget = maxlen; + + while (toget > 0) { + got = recv(sock, line, toget, 0); + if (got <= 0) { + return got; + } + toget -= got; + line += got; + } + return maxlen; +} + +static int my_gets(SOCKET sock, char * line, int maxlen) +{ + int last_rval = 0; + + while (((last_rval = my_recv(sock, line, 1)) == 1) && maxlen > 0) { + if (*line == '\n') { + line++; + *line = 0; + break; + } else { + line++; + maxlen--; + } + } + return last_rval; +} + +typedef struct conndesc_ { + struct sockaddr_in addr; + int width; + int height; + int start; + int end; + int rate; + int ratescale; +} conndesc; + + + +HRESULT __stdcall VF_OpenFileFunc_Blen( + char *lpFileName, LPVF_FileHandle lpFileHandle ) +{ + conndesc * rval; + char * host; + char * p; + int port; + SOCKET s_in; + char buf[256]; + struct sockaddr_in addr; + FILE* fp; + + p = lpFileName; + while (*p && *p != '.') p++; + if (*p) p++; + if (strcmp(p, "blu") != 0) { + return VF_ERROR; + } + + fp = fopen(lpFileName, "r"); + if (!fp) { + return VF_ERROR; + } + fgets(buf, 256, fp); + fclose(fp); + + host = buf; + p = host; + while (*p && *p != ':') p++; + if (*p) p++; + p[-1] = 0; + port = atoi(p); + if (!port) { + port = 8080; + } + + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = getipaddress(host); + + s_in = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (s_in < 0) { + return VF_ERROR; + } + + if (connect(s_in, (struct sockaddr*) &addr, + sizeof(addr)) < 0) { + closesocket(s_in); + return VF_ERROR; + } + + rval = (conndesc*) malloc(sizeof(conndesc)); + + rval->addr = addr; + + my_send(s_in, "GET /info.txt HTTP/1.0\n\n"); + + for (;;) { + char * key; + char * val; + + if (my_gets(s_in, buf, 250) <= 0) { + break; + } + + key = buf; + val = buf; + while (*val && *val != ' ') val++; + if (*val) { + *val = 0; + val++; + + if (strcmp(key, "width") == 0) { + rval->width = atoi(val); + } else if (strcmp(key, "height") == 0) { + rval->height = atoi(val); + } else if (strcmp(key, "start") == 0) { + rval->start = atoi(val); + } else if (strcmp(key, "end") == 0) { + rval->end = atoi(val); + } else if (strcmp(key, "rate") == 0) { + rval->rate = atoi(val); + } else if (strcmp(key, "ratescale") == 0) { + rval->ratescale = atoi(val); + } + } + } + + closesocket(s_in); + + *lpFileHandle = (VF_FileHandle) rval; + + return VF_OK; +} + +HRESULT __stdcall VF_CloseFileFunc_Blen( + VF_FileHandle hFileHandle ) +{ + free((conndesc*) hFileHandle); + + return VF_OK; +} + +HRESULT __stdcall VF_GetFileInfoFunc_Blen( + VF_FileHandle hFileHandle, + LPVF_FileInfo lpFileInfo ) +{ + conndesc * c = (conndesc*) hFileHandle; + if (c == 0) { + return VF_ERROR; + } + + if (lpFileInfo->dwSize != sizeof(VF_FileInfo)) { + return VF_ERROR; + } + + lpFileInfo->dwHasStreams = VF_STREAM_VIDEO; + + return VF_OK; +} + +HRESULT __stdcall VF_GetStreamInfoFunc_Blen( + VF_FileHandle hFileHandle, + DWORD dwStream,void *lpStreamInfo ) +{ + conndesc * c = (conndesc*) hFileHandle; + + LPVF_StreamInfo_Video v = (LPVF_StreamInfo_Video) lpStreamInfo; + + if (c == 0 || dwStream != VF_STREAM_VIDEO || v == 0) { + return VF_ERROR; + } + + v->dwLengthL = c->end - c->start; + v->dwLengthH = 0; + v->dwScale = c->ratescale; + v->dwRate = c->rate; + v->dwWidth = c->width; + v->dwHeight = c->height; + v->dwBitCount = 24; + + return VF_OK; +} + +HRESULT __stdcall VF_ReadDataFunc_Blen( + VF_FileHandle hFileHandle, + DWORD dwStream,void *lpData ) +{ + char req[256]; + char buf[256]; + SOCKET s_in; + int width; + int height; + int y; + int rval; + unsigned char * framebuf; + + conndesc * c = (conndesc*) hFileHandle; + LPVF_ReadData_Video v = (LPVF_ReadData_Video) lpData; + + if (c == 0 || dwStream != VF_STREAM_VIDEO || v == 0) { + return VF_ERROR; + } + + s_in = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (s_in < 0) { + return VF_ERROR; + } + + if (connect(s_in, (struct sockaddr*) &c->addr, + sizeof(c->addr)) < 0) { + goto errout; + } + + sprintf(req, "GET /images/ppm/%d.ppm HTTP/1.0\n\n", + (int) (v->dwFrameNumberL) + c->start); + + my_send(s_in, req); + + do { + if (my_gets(s_in, buf, 256) <= 0) { + goto errout; + } + } while (strcmp(buf, "P6\n") != 0); + + do { + rval = my_gets(s_in, buf, 256); + } while ( (buf[0] == '#' || buf[0] == '\n') && rval >= 0); + + if (sscanf(buf, "%d %d\n", &width, &height) != 2) { + goto errout; + } + + if (width != c->width || height != c->height) { + goto errout; + } + + my_gets(s_in, buf, 256); /* 255 */ + + framebuf = (unsigned char*) v->lpData; + + for (y = 0; y < height; y++) { + unsigned char * p = framebuf + v->lPitch * y; + unsigned char * e = p + width * 3; + + my_recv(s_in, (char*) p, width * 3); + while (p != e) { + unsigned char tmp = p[2]; + p[2] = p[0]; + p[0] = tmp; + + p += 3; + } + } + closesocket(s_in); + return VF_OK; + errout: + closesocket(s_in); + return VF_ERROR; +} + +__declspec(dllexport) HRESULT vfGetPluginFunc( + LPVF_PluginFunc lpPluginFunc ) +{ + if (!lpPluginFunc || lpPluginFunc->dwSize != sizeof(VF_PluginFunc)) { + return VF_ERROR; + } + + lpPluginFunc->OpenFile = VF_OpenFileFunc_Blen; + lpPluginFunc->CloseFile = VF_CloseFileFunc_Blen; + lpPluginFunc->GetFileInfo = VF_GetFileInfoFunc_Blen; + lpPluginFunc->GetStreamInfo = VF_GetStreamInfoFunc_Blen; + lpPluginFunc->ReadData = VF_ReadDataFunc_Blen; + + return VF_OK; +} + + + diff --git a/release/windows/extra/Help.url b/release/windows/extra/Help.url new file mode 100644 index 00000000000..abc1b00fa70 --- /dev/null +++ b/release/windows/extra/Help.url @@ -0,0 +1,4 @@ +[DEFAULT] +BASEURL=http://www.blender3d.org/Support/ +[InternetShortcut] +URL=http://www.blender3d.org/Support/ diff --git a/release/windows/installer/00.blender.nsi b/release/windows/installer/00.blender.nsi new file mode 100644 index 00000000000..8666ed812b3 --- /dev/null +++ b/release/windows/installer/00.blender.nsi @@ -0,0 +1,450 @@ +; +; $Id$ +; +; Blender Self-Installer for Windows (NSIS - http://nsis.sourceforge.net) +; + +!include "MUI.nsh" + +Name "Blender VERSION" + +!define MUI_ABORTWARNING + +!define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of Blender.\r\n\r\nIt is recommended that you close all other applications before starting Setup.\r\n\r\nNote to Win2k/XP users: You may require administrator privileges to install Blender successfully." +!define MUI_WELCOMEFINISHPAGE_BITMAP "01.installer.bmp" +!define MUI_HEADERIMAGE +!define MUI_HEADERIMAGE_BITMAP "00.header.bmp" +!define MUI_COMPONENTSPAGE_SMALLDESC +!define MUI_FINISHPAGE_RUN "$INSTDIR\blender.exe" +!define MUI_CHECKBITMAP "00.checked.bmp" + +!insertmacro MUI_PAGE_WELCOME +!insertmacro MUI_PAGE_LICENSE "DISTDIR\Copyright.txt" +!insertmacro MUI_PAGE_COMPONENTS + +!insertmacro MUI_PAGE_DIRECTORY +Page custom DataLocation +!insertmacro MUI_PAGE_INSTFILES +!insertmacro MUI_PAGE_FINISH + +!insertmacro MUI_UNPAGE_WELCOME +!insertmacro MUI_UNPAGE_CONFIRM +!insertmacro MUI_UNPAGE_INSTFILES +!insertmacro MUI_UNPAGE_FINISH + + +Icon "00.installer.ico" +UninstallIcon "00.installer.ico" + +;-------------------------------- +;Languages + + !insertmacro MUI_LANGUAGE "English" + +;-------------------------------- +;Language Strings + + ;Description + LangString DESC_SecCopyUI ${LANG_ENGLISH} "Copy all required files to the application folder." + LangString DESC_Section2 ${LANG_ENGLISH} "Add shortcut items to the Start Menu. (Recommended)" + LangString DESC_Section3 ${LANG_ENGLISH} "Add a shortcut to Blender on your desktop." + LangString DESC_Section4 ${LANG_ENGLISH} "Blender can register itself with .blend files to allow double-clicking from Windows Explorer, etc." + LangString TEXT_IO_TITLE ${LANG_ENGLISH} "Specify User Data Location" +;-------------------------------- +;Data + +Caption "Blender VERSION Installer" +OutFile "DISTDIR\..\VERSION\blender-VERSION-windows.exe" + +InstallDir "$PROGRAMFILES\Blender Foundation\Blender" + +BrandingText "http://www.blender.org/bf" +ComponentText "This will install Blender VERSION on your computer." + +DirText "Use the field below to specify the folder where you want Blender to be copied to. To specify a different folder, type a new name or use the Browse button to select an existing folder." + +; GetWindowsVersion +; +; Based on Yazno's function, http://yazno.tripod.com/powerpimpit/ +; Updated by Joost Verburg +; +; Returns on top of stack +; +; Windows Version (95, 98, ME, NT x.x, 2000, XP, 2003) +; or +; '' (Unknown Windows Version) +; +; Usage: +; Call GetWindowsVersion +; Pop $R0 +; ; at this point $R0 is "NT 4.0" or whatnot + +Function GetWindowsVersion + + Push $R0 + Push $R1 + + ReadRegStr $R0 HKLM \ + "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion + + IfErrors 0 lbl_winnt + + ; we are not NT + ReadRegStr $R0 HKLM \ + "SOFTWARE\Microsoft\Windows\CurrentVersion" VersionNumber + + StrCpy $R1 $R0 1 + StrCmp $R1 '4' 0 lbl_error + + StrCpy $R1 $R0 3 + + StrCmp $R1 '4.0' lbl_win32_95 + StrCmp $R1 '4.9' lbl_win32_ME lbl_win32_98 + + lbl_win32_95: + StrCpy $R0 '95' + Goto lbl_done + + lbl_win32_98: + StrCpy $R0 '98' + Goto lbl_done + + lbl_win32_ME: + StrCpy $R0 'ME' + Goto lbl_done + + lbl_winnt: + + StrCpy $R1 $R0 1 + + StrCmp $R1 '3' lbl_winnt_x + StrCmp $R1 '4' lbl_winnt_x + + StrCpy $R1 $R0 3 + + StrCmp $R1 '5.0' lbl_winnt_2000 + StrCmp $R1 '5.1' lbl_winnt_XP + StrCmp $R1 '5.2' lbl_winnt_2003 lbl_error + + lbl_winnt_x: + StrCpy $R0 "NT $R0" 6 + Goto lbl_done + + lbl_winnt_2000: + Strcpy $R0 '2000' + Goto lbl_done + + lbl_winnt_XP: + Strcpy $R0 'XP' + Goto lbl_done + + lbl_winnt_2003: + Strcpy $R0 '2003' + Goto lbl_done + + lbl_error: + Strcpy $R0 '' + lbl_done: + + Pop $R1 + Exch $R0 + +FunctionEnd + +Var BLENDERHOME +Var winversion + +Function SetWinXPPath + StrCpy $BLENDERHOME "$PROFILE\Application Data\Blender Foundation\Blender" +FunctionEnd + +Function SetWin9xPath + StrCpy $BLENDERHOME $INSTDIR +FunctionEnd + +Function .onInit + Call GetWindowsVersion + Pop $R0 + Strcpy $winversion $R0 + !insertmacro MUI_INSTALLOPTIONS_EXTRACT "data.ini" +FunctionEnd + +Var HWND +Var DLGITEM +Var is2KXP + +Function DataLocation + !insertmacro MUI_HEADER_TEXT "$(TEXT_IO_TITLE)" "" + + ; Set default choice + !insertmacro MUI_INSTALLOPTIONS_WRITE "data.ini" "Field 3" "State" 1 + + StrCpy $R1 $winversion 2 + StrCmp $R1 "NT" do_win2kxp + StrCmp $winversion "2000" do_win2kxp + StrCmp $winversion "XP" do_win2kxp + StrCmp $winversion "2003" do_win2kxp + + ;else... + Strcpy $is2KXP "false" + + Goto continue + + do_win2kXP: + Strcpy $is2KXP "true" + + continue: + + !insertmacro MUI_INSTALLOPTIONS_INITDIALOG "data.ini" + Pop $HWND + + Strcmp $is2KXP "true" do_dlg + + ; Disable App Data option on Win9x + + GetDlgItem $DLGITEM $HWND 1201 + EnableWindow $DLGITEM 0 + + do_dlg: + + !insertmacro MUI_INSTALLOPTIONS_SHOW + !insertmacro MUI_INSTALLOPTIONS_READ $R0 "data.ini" "Field 2" "State" ; App Dir + Strcmp $R0 1 do_app_data + !insertmacro MUI_INSTALLOPTIONS_READ $R0 "data.ini" "Field 3" "State" ; Inst Dir + Strcmp $R0 1 do_inst_path + !insertmacro MUI_INSTALLOPTIONS_READ $R0 "data.ini" "Field 4" "State" ; Home Dir + Strcmp $R0 1 do_home_path + + Goto end + + do_app_data: + Call SetWinXPPath + Goto end + do_home_path: + ReadEnvStr $BLENDERHOME "HOME" + Goto end + do_inst_path: + Call SetWin9xPath + end: + +FunctionEnd + +Section "Blender-VERSION (required)" SecCopyUI + SectionIn RO + +; Sets $BLENDERHOME to suit Windows version... + + ; Set output path to the installation directory. + SetOutPath $INSTDIR + ; Put file there + File DISTDIR\blender.exe + File DISTDIR\blenderplayer.exe + File DISTDIR\python23.dll + File DISTDIR\python23.zip + File DISTDIR\sdl.dll + File DISTDIR\gnu_gettext.dll + File DISTDIR\Copyright.txt + File DISTDIR\Blender.html + File DISTDIR\python-license.txt + File DISTDIR\Release_SHORTVERS.txt + File DISTDIR\GPL-license.txt + File DISTDIR\Help.url + File DISTDIR\zlib.pyd + + SetOutPath $BLENDERHOME\.blender + File DISTDIR\.blender\.bfont.ttf + + SetOutPath $BLENDERHOME\.blender\scripts + File DISTDIR\.blender\scripts\ac3d_export.py + File DISTDIR\.blender\scripts\ac3d_import.py + File DISTDIR\.blender\scripts\Apply_def.py + File DISTDIR\.blender\scripts\Axiscopy.py + File DISTDIR\.blender\scripts\batch_name_edit.py + File DISTDIR\.blender\scripts\bevel_center.py + File DISTDIR\.blender\scripts\blender2cal3d.py + File DISTDIR\.blender\scripts\bvh_export.py + File DISTDIR\.blender\scripts\bvh_import.py + File DISTDIR\.blender\scripts\clean_mesh.py + File DISTDIR\.blender\scripts\config.py + File DISTDIR\.blender\scripts\DirectX8Exporter.py + File DISTDIR\.blender\scripts\DirectXExporter.py + File DISTDIR\.blender\scripts\disp_paint.py + File DISTDIR\.blender\scripts\doc_browser.py + File DISTDIR\.blender\scripts\fixfromarmature.py + File DISTDIR\.blender\scripts\help_browser.py + File DISTDIR\.blender\scripts\help_getting_started.py + File DISTDIR\.blender\scripts\help_manual.py + File DISTDIR\.blender\scripts\help_py_reference.py + File DISTDIR\.blender\scripts\help_release_notes.py + File DISTDIR\.blender\scripts\help_tutorials.py + File DISTDIR\.blender\scripts\help_web_blender.py + File DISTDIR\.blender\scripts\help_web_devcomm.py + File DISTDIR\.blender\scripts\help_web_eshop.py + File DISTDIR\.blender\scripts\help_web_usercomm.py + File DISTDIR\.blender\scripts\hotkeys.py + File DISTDIR\.blender\scripts\kloputils.py + File DISTDIR\.blender\scripts\knife.py + File DISTDIR\.blender\scripts\lightwave_export.py + File DISTDIR\.blender\scripts\lightwave_import.py + File DISTDIR\.blender\scripts\nendo_export.py + File DISTDIR\.blender\scripts\nendo_import.py + File DISTDIR\.blender\scripts\obdatacopier.py + File DISTDIR\.blender\scripts\obj_export.py + File DISTDIR\.blender\scripts\obj_import.py + File DISTDIR\.blender\scripts\off_export.py + File DISTDIR\.blender\scripts\off_import.py + File DISTDIR\.blender\scripts\paths_import.py + File DISTDIR\.blender\scripts\radiosity_export.py + File DISTDIR\.blender\scripts\radiosity_import.py + File DISTDIR\.blender\scripts\raw_export.py + File DISTDIR\.blender\scripts\raw_import.py + File DISTDIR\.blender\scripts\renameobjectbyblock.py + File DISTDIR\.blender\scripts\rvk1_torvk2.py + File DISTDIR\.blender\scripts\save_theme.py + File DISTDIR\.blender\scripts\sel_same.py + File DISTDIR\.blender\scripts\skin.py + File DISTDIR\.blender\scripts\slp_import.py + File DISTDIR\.blender\scripts\sysinfo.py + File DISTDIR\.blender\scripts\tex2uvbaker.py + File DISTDIR\.blender\scripts\truespace_export.py + File DISTDIR\.blender\scripts\truespace_import.py + File DISTDIR\.blender\scripts\unweld.py + File DISTDIR\.blender\scripts\uv_export.py + File DISTDIR\.blender\scripts\UVpaint05.py + File DISTDIR\.blender\scripts\videoscape_export.py + File DISTDIR\.blender\scripts\vrml97_export.py + File DISTDIR\.blender\scripts\wings_export.py + File DISTDIR\.blender\scripts\wings_import.py + File DISTDIR\.blender\scripts\wrl2export.py + SetOutPath $BLENDERHOME\.blender\scripts\bpymodules + File DISTDIR\.blender\scripts\bpymodules\ai2obj.py + File DISTDIR\.blender\scripts\bpymodules\BPyBlender.py + File DISTDIR\.blender\scripts\bpymodules\BPyRegistry.py + File DISTDIR\.blender\scripts\bpymodules\eps2obj.py + File DISTDIR\.blender\scripts\bpymodules\gimp2obj.py + File DISTDIR\.blender\scripts\bpymodules\meshtools.py + File DISTDIR\.blender\scripts\bpymodules\svg2obj.py + SetOutPath $BLENDERHOME\.blender\scripts\bpydata + File DISTDIR\.blender\scripts\bpydata\readme.txt + File DISTDIR\.blender\scripts\bpydata\KUlang.txt + SetOutPath $BLENDERHOME\.blender\scripts\bpydata\config + File DISTDIR\.blender\scripts\bpydata\config\readme.txt + + ; Additional Languages files + SetOutPath $BLENDERHOME\.blender + File DISTDIR\.blender\.Blanguages + SetOutPath $BLENDERHOME\.blender\locale\ca\LC_MESSAGES + File DISTDIR\.blender\locale\ca\LC_MESSAGES\blender.mo + SetOutPath $BLENDERHOME\.blender\locale\cs\LC_MESSAGES + File DISTDIR\.blender\locale\cs\LC_MESSAGES\blender.mo + SetOutPath $BLENDERHOME\.blender\locale\de\LC_MESSAGES + File DISTDIR\.blender\locale\de\LC_MESSAGES\blender.mo + SetOutPath $BLENDERHOME\.blender\locale\fi\LC_MESSAGES + File DISTDIR\.blender\locale\fi\LC_MESSAGES\blender.mo + SetOutPath $BLENDERHOME\.blender\locale\es\LC_MESSAGES + File DISTDIR\.blender\locale\es\LC_MESSAGES\blender.mo + SetOutPath $BLENDERHOME\.blender\locale\fr\LC_MESSAGES + File DISTDIR\.blender\locale\fr\LC_MESSAGES\blender.mo + SetOutPath $BLENDERHOME\.blender\locale\it\LC_MESSAGES + File DISTDIR\.blender\locale\it\LC_MESSAGES\blender.mo + SetOutPath $BLENDERHOME\.blender\locale\ja\LC_MESSAGES + File DISTDIR\.blender\locale\ja\LC_MESSAGES\blender.mo + SetOutPath $BLENDERHOME\.blender\locale\nl\LC_MESSAGES + File DISTDIR\.blender\locale\nl\LC_MESSAGES\blender.mo + SetOutPath $BLENDERHOME\.blender\locale\sv\LC_MESSAGES + File DISTDIR\.blender\locale\sv\LC_MESSAGES\blender.mo + SetOutPath $BLENDERHOME\.blender\locale\zh_cn\LC_MESSAGES + File DISTDIR\.blender\locale\zh_cn\LC_MESSAGES\blender.mo + SetOutPath $BLENDERHOME\.blender\locale\pt_br\LC_MESSAGES + File DISTDIR\.blender\locale\pt_br\LC_MESSAGES\blender.mo + SetOutPath $BLENDERHOME\.blender\locale\hr_HR\LC_MESSAGES + File DISTDIR\.blender\locale\hr_HR\LC_MESSAGES\blender.mo + SetOutPath $BLENDERHOME\.blender\locale\ru\LC_MESSAGES + File DISTDIR\.blender\locale\ru\LC_MESSAGES\blender.mo + SetOutPath $BLENDERHOME\.blender\locale\pl\LC_MESSAGES + File DISTDIR\.blender\locale\pl\LC_MESSAGES\blender.mo + + SetOutPath $INSTDIR + ; Write the installation path into the registry + WriteRegStr HKLM SOFTWARE\BlenderFoundation "Install_Dir" "$INSTDIR" + ; Write the uninstall keys for Windows + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Blender" "DisplayName" "Blender (remove only)" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Blender" "UninstallString" '"$INSTDIR\uninstall.exe"' + WriteUninstaller "uninstall.exe" +SectionEnd + +Section "Add Start Menu shortcuts" Section2 + SetOutPath $INSTDIR + CreateDirectory "$SMPROGRAMS\Blender Foundation\Blender\" + CreateShortCut "$SMPROGRAMS\Blender Foundation\Blender\Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0 + CreateShortCut "$SMPROGRAMS\Blender Foundation\Blender\Blender.lnk" "$INSTDIR\Blender.exe" "" "$INSTDIR\blender.exe" 0 + CreateShortCut "$SMPROGRAMS\Blender Foundation\Blender\Readme.lnk" "$INSTDIR\Blender.html" "" "" 0 + CreateShortCut "$SMPROGRAMS\Blender Foundation\Blender\Copyright.lnk" "$INSTDIR\Copyright.txt" "" "$INSTDIR\copyright.txt" 0 + CreateShortCut "$SMPROGRAMS\Blender Foundation\Blender\GPL-license.lnk" "$INSTDIR\GPL-license.txt" "" "$INSTDIR\GPL-license.txt" 0 + CreateShortCut "$SMPROGRAMS\Blender Foundation\Blender\Help.lnk" "$INSTDIR\Help.url" +SectionEnd + +Section "Add Desktop Blender-VERSION shortcut" Section3 + SetOutPath $INSTDIR + CreateShortCut "$DESKTOP\Blender.lnk" "$INSTDIR\blender.exe" "" "$INSTDIR\blender.exe" 0 +SectionEnd + +Section "Open .blend files with Blender-VERSION" Section4 + SetOutPath $INSTDIR + ;ExecShell "open" '"$INSTDIR\blender.exe"' "-R -b" + ;do it the manual way! ;) + + WriteRegStr HKCR ".blend" "" "blendfile" + WriteRegStr HKCR "blendfile" "" "Blender .blend File" + WriteRegStr HKCR "blendfile\shell" "" "open" + WriteRegStr HKCR "blendfile\DefaultIcon" "" $INSTDIR\blender.exe,1 + WriteRegStr HKCR "blendfile\shell\open\command" "" \ + '"$INSTDIR\blender.exe" "%1"' + +SectionEnd + +UninstallText "This will uninstall Blender VERSION. Hit next to continue." + +Section "Uninstall" + ; remove registry keys + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Blender" + DeleteRegKey HKLM SOFTWARE\BlenderFoundation + ; remove files + Delete $INSTDIR\blender.exe + Delete $INSTDIR\blenderplayer.exe + Delete $INSTDIR\python23.dll + Delete $INSTDIR\python23.zip + Delete $INSTDIR\sdl.dll + Delete $INSTDIR\gnu_gettext.dll + Delete $INSTDIR\Copyright.txt + Delete $INSTDIR\Blender.html + Delete $INSTDIR\GPL-license.txt + Delete $INSTDIR\python-license.txt + Delete $INSTDIR\Release_SHORTVERS.txt + Delete $INSTDIR\Help.url + Delete $INSTDIR\uninstall.exe + Delete $INSTDIR\zlib.pyd + Delete $INSTDIR\.blender\.bfont.ttf + Delete $INSTDIR\.blender\.Blanguages + ; remove shortcuts, if any. + Delete "$SMPROGRAMS\Blender Foundation\Blender\*.*" + Delete "$DESKTOP\Blender.lnk" + ; remove directories used. + RMDir /r $INSTDIR\.blender\locale + RMDir /r $INSTDIR\.blender\scripts + RMDir /r $INSTDIR\.blender\scripts\bpydata + RMDir /r $INSTDIR\.blender\scripts\bpydata\config + RMDir /r $INSTDIR\.blender\scripts\bpymodules + RMDir $INSTDIR\.blender + RMDir "$SMPROGRAMS\Blender Foundation\Blender" + RMDir "$SMPROGRAMS\Blender Foundation" + RMDir "$INSTDIR" + RMDir "$INSTDIR\.." +SectionEnd + +!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN + !insertmacro MUI_DESCRIPTION_TEXT ${SecCopyUI} $(DESC_SecCopyUI) + !insertmacro MUI_DESCRIPTION_TEXT ${Section2} $(DESC_Section2) + !insertmacro MUI_DESCRIPTION_TEXT ${Section3} $(DESC_Section3) + !insertmacro MUI_DESCRIPTION_TEXT ${Section4} $(DESC_Section4) +!insertmacro MUI_FUNCTION_DESCRIPTION_END diff --git a/release/windows/installer/00.checked.bmp b/release/windows/installer/00.checked.bmp new file mode 100644 index 0000000000000000000000000000000000000000..6c2e98d361c6764b7772e13b84c5ac026e00f577 GIT binary patch literal 2610 zcmeH{J#NB45QQg_6-CYhHdfrzrA9eH`rIK$q2M4CNp2CzbqdN<5iOd7cD(Dyr)f+Q(}?IEvu9+2yrLV7h-;#UTg?h3r^bv3Uz*MI2P39b z6a^Ju1#LdwsN8O8@;agUd`|DnC4H_|wBlT^Y0X)dRC40JEwZYrOI~_#*#rNy2R7do zy(|_u$9%AH(&fP8OiIOPlV}%)+qtkj$NcQTVdNuFkkM}p{vF%LBM}z0?Ic5@o#w7#cSxb{f|w+^Rt+AL3_SmL@(cq@b$xh z|I`G8j}rS$1ZqAWfvlpBkL%JfTyOhNOhEYQ7$JBPX8kl5Pp(U-J+V$*11J}e74Rl>hwP}0p%wtcZ@sa`P%z_zV=@E?fwr< zK=`A?3&aO}cY>ey`ZodP*8*7_`akk~#Xk?7{U0KHi#&fX@C*Lo_Q!T@zHgc}9-IaK RZ3SlSnqSG`r=j=f@&~`{p)>#h literal 0 HcmV?d00001 diff --git a/release/windows/installer/00.header.bmp b/release/windows/installer/00.header.bmp new file mode 100644 index 0000000000000000000000000000000000000000..b631ba73933924c2bfea42197c02c4e2b0fdcf47 GIT binary patch literal 25818 zcmbt-2XtH4mK}e3GD#*qleShSnaoVG(pIuE$)7*-i@zPTN z+i{SN+d4Q#`;-Jc#rYNmfDZ4E^tKUf?Ra(6);Vfd68e;54i$ht>vWAdy2b|7!1$oX zhl!z{i6Je)3Fs!#(hH4|)l2F-cweCYOPLKHve&GSi3o*wC)8S9&$ z8d{hIpCiQQ{Mhp11jFPCm|UJ-S@sb)x3U8EyaW=5i#`x<0+!d-h&?ZdKK9V@6Bt09 zkH#M)@cF9<1h=nxgoKc6%yK3kVr(OG zwh%a(Ch4$MPO!*_ds~Nl+W=B;AA!*bCOb!=Nrth3uJJ*rQSFr+qY?bLzz?8D%aqwO z0UDVmCpm{sEjs~J8>a}SDUW$-7_iI`lQxh!GiDc5IyJO7H@q}IO5$9cSX!D|Spu2F z=PIN~m?MxH7gkpn0j5Jvgf~8$1aWW>kQC(eF;}9&WpUjtRsaK7}A(_*c1o;DMeDMk7V&4Ou#bpzf;Q zfX2DW0dkuJ=lry5e#X5(@GQ&>FV2oE&W$e3L!z*^GtAif`P@L}`q~oUb&NmKuKoax zukwmNNMlF{MH^((I!5f&5n3BeDD=rxWWjgOI_4G+V3D~^EdcfDsT4<8i;mQ(Z^S{T zq0y;>nPpnlH@J;WIO4%u=wyCA-Xa_6Z503yX%`@nN#cYul^~NrIX0kTK&N3J>`MO#Vbcg2TQxj^SQ~$0{Q* z(%j}|qK2wVeY z**6PKj)Tm>`AI>L3o|Yf(JDC8E*GB>d;n3;}#HN|`==WRlNZ2ZUgi z4D53Of!6h98ku|iK|yY!M#MBWIcLLdY=rf58Q{mrm2tRD@M(=`$uOeNXbf&!UV4fn z1VMFHguDD49APh+5Wzy6jYIl6y0{V1Y?JU7`UOexk=ReE#bX7-GEXnTPcIbf=wKj6 z%KRsk$;GJ|ht=gK7q%C6nEIgCFIQsHV}ddT1B*asoCP|5O*#b{XFTL2VOr;yX(d4t znaj{5V{&DYMM9j(B_>WmpCnPAIEl&sCo)Noo5ZUdX$%P&($x;?st2{zL;704X{dJ@ z8yFB_5}bxQ1{@cTphL2Ry1X5qO5I?|+9I^p7JT>g6djw;;ZLc>&w;m0;r!xG+#0_Z z+z73JCjJ)2C#O{I>6Lr>T8H~uM;vV<4p0h^M8^h{jLa_hPjaDx8d(lWG$L??fkpCx zkd-mXG&w!mJ53P}G>M4E!TjVPdB~Sd>nxY$IAhYMNoHV)$yve71~SRXBzp_D2{Km* zBu=uiOqpxX*SRt`Xp)Dkh**CIlOZ94JraVpilDFY!3jQtP#-`qCz)Ee84_yp((XSl zyku#11MD2?^fFkQs6#I`v6gpuzsYH=$9;v*qpNZ1=@;ZO)R9(AO;9qCNy;P(JYr{- z79841nM{^`&p8gC2@Gn;-cnhBTV19}@}De?gdm5Rb!C|(X_7@eFs;m0B5I|Ghq+4f zmZZ$tktH7S`26GoXq;Mst6U`Oy6V&9G6cyqDKNQ2Os+Cnay}WEKg^_;##gE_BxInw zf@4t2n1m+v)lNf=(*O=@oW?o=`qY6GgW*?;S2lqs_+B+Px(H1^F!q>YNvlk#to0G@ z0%MGDm$}(xX>ys!_A+BmKN$isDTNeCjdrL};E;SK^OnqEQjX#^tv%z2W_e!1k`G=A z@P|8Nz0)j*BsHSaBLuF9c)+1I) z=<02B<9HBS+%_-zq{K6)x)06}Pz(b$IR!v0=t1-|3DbBQvVp zJqkv3o-w(w1}QQ%dd(^Kjlm)mIE04`bdQWcIL3{>k(h)IwdMUi;E(})LYBIU0WE{B zV$e`UYBUm@CTNlY9Y_(d5ZqQU#z%p*I$DPv6xj?TxakKd9U;?72~#_n z*}gUkTp>uInog1G1d6dj?OZ#FVk}kDL8f8KMddlTM{iw6@QoDZP#Vbv2^zT?Spw-( zn*I)KrEPU@f?V438AiVpU7j!+Q@ksB$$@&Jhr%QdqNrLtkXG!JNXVvM`m@ z7^p+^y^b+Rja-KgO<8|;8KgL3CZ+ITC z2eHpCJ#RFxg-MpTJzjhxZt;y+*2XQq`*876>2j5RZEArE@$=J8l+PF^po>WnTv4Z) zOO8}$mxC(?1tdr42RLb95BxCR2HHjj+CkvhpmJC{b;AdS;*jC?RbjxZX>U{?oF3SiX$R$@hr8sr#R z-slf*0(Ho}qR*BJ!HtkN@~~zTulVCRv?~h%M^}-ftJt9~;po?h2|Z%LsA?;RNTNU$ zSyVGn=d#uVPHQbVoN)C(V2dj+aynOcBrpCva^V&DC~+~hbrn?OkC+-Zf+(Vn45rlW zU?BPVAamQLfFQztxu;(-G6=DCj0|;-5|psd;B6FK4FNokQGq>5ESwb3&_S<1q`E7D z8@NP@Q7LI0>sQm57a3bVn1xYF{iM?XFj-orNs~4%NP$CS8-AB41gHU#jW5rbU0L!+ zHe^l%k_@j!^-D3xqEfLukj7W&(5A??wdM$D&#`sn**fz3R3e6gK2?FetI)3Y!_i&h z=q`2ilnv@DVQisH#0R*(*|WYsYv~o#ZFp&S+LC&39fF)3Ho%rTEw#+M*1LKeg3;)* z5xn6J3@k^B$KK*`NIedj#~}xX`xOKSS}s=-C+TyrgKbs@$Y=frmH(lRQ90?mw~Y4{lhh zK^f!hDly3-n`K6$H_z|}H{RTTEubE^(VV`5LrY7#MV4-nrdg!vy|N5~JhQho+t!{p z*i(seC5#WUHHW6OPg&5{nct^m^md8t>LREVbrIBqIvne7$NvubZQu}3e;d0{Z(0M5 z6Yd^xIAp3~s2(y^51C=f1;I0W4l_=&C)3SHb|a3ZFbIy6EU<@y9wF`_Z%IZNP%zue zEo}$cSkkJHZFpl;8pfjP_%KydG0uV53zZv+##r%YX0(qwr~tsIvS5`WRjRKt8mB14 zA)`8j#2-wK1AZD8Sk}LRMy|$m1Wpk zb6uw9#pz*u!Ru@o8POVYd}y*y2^#YlL`Vo>91QODt@nR2ft=D`M=!MX!Hchs4k(E_ zQw@?yGOeV{diX|oKV~73C3GNB1cyYawQ<-cV}-UhWEjLDC6-cD$6-HVB#9HZ4i1n4 z8u-tF_OZdvaaT7EPI`1;Pq3&oh6Np(sN6PYn;z?(8nqCIND(I-@YpmIH9L&@HKrsA5SSpMb^)1Hr$+UB1Kk!+dNlf!Occ<`a>KV>z|k! zlFUs{%`K_smNat{wS$_do1gZzM zWHp-^oav1-SJ7Ydnp1u|o-5Kd18EE#-Vk!dAg?G$F`)Vu5@M)(WT<-#m>Qm#8>WfzU zi=%m)Fd131f)nu7;s%cHYD-&zwWDZZX4Gkt$@4B(KmMjR>7Y`4Z){M9(?Bx5Ik&YP zrvYPwdN2vL@zRJxgVXAgzpH-qbjI<3l*UzPf}zeaO(v-!kdx#YHI1_ZTn~ zG2t}v9Pe6*nRY0@H(LNLVNuNF_a&BzkoOYrl|Prg&NG9SzyF6Dcyt-nZU-bnjzVipD` z>6F#wg{MdV-M#H0K=y_I9rM{=<9*)7@A-Su?DP2kaHcr=Q+`mEa{*767iMao9EjWX zw*${dKk>l7R8_>Rt}KGX+$(>=C>aC*dyFT1VqCO?jA;!^k>;hMNt(4}_# zEc?>Wqj&yQ9DMZcKU-Ox#hKQQ;*{fm5_H=35Pas+yW8-)pcC4Q_^W9r{}U(5%OT>M zAR3tzxl4SxZ1X#HXsQQ$$z)3z;2X`&DNbD-KEln))(d=0h6wGAhn zFIndP6Xz^1OlxbOR40605xY~GdDd;F-vxg})vj!KW0sO$!C#hg?2iJ!m1n2^bIzqd zfB4lu^c@6^II}!OMawFavvsd zY6Nc33U1p9!}xJr6Q{{?FY>2oAAI!>aQA1Y|BLSkI*<4N0Yo*RYl!{)Z}8)(C;k-T zuZ-XIVDInqBTeZiaVhAQKgAUohb!LblwwqtY6#UguSFGT^oKPsMW>tDQe!=HhK*0n zKr`YS1gL5D&Vt!d$He^elLZ@T{PW0#RE6LH;u?aeKxE^b!bhjauuYl%{eS0w0dHf! z_?xoKbNH3x)tRLipF9Z?@cB~8Ga#7M&_CwqKm6t&TiOe81aF!0*oq_G8s zVK0B$Q4$Ut$otTVt}zwY;g6QgGv%?{VHNq)ylcPWr>Q0Juxl&??IjM2Zt>%|CT`>t zb8+~)c#6BPtt|DaD?uGU?a85k1KHA{!xS)bBR&pW3vS>{q|%5pVBz4|d};&m`(AFLu7xQ|S-J*a{Nk?vr?D+@b%lO-t7*ps9U{1awZSkTMk%O@_u@s?`TxZ) z*phV?-jDYcqHB@|U-Ev;XMY{vJq#KLI8XTIpFI5f9|7=zu(A9!P4z?EX=WS=gdM+* z_Tt<8IIf8+^M2;J|A{*yyu{o$WEfxtyxrUJGrS5PXq0C0KAz%U{1&`@^zA=~!%W!s zPqQ!nAA>ZLUkx6C(XuMoPc{NY_A`(}e>4+7;7jQRrTSciehzh#2Y|6Q(cA!Y3Mr;q zWk?ahWJYgmj=i%86W{O`4@^AYG^7k9w%vh0n;tMP{IhS`4))aJ9LL0qUq$;l+@7?$ zx=uRuacF4Cz-h?Y#yvflX^)?_Pus1c>pmSqu80YR8}0ZRLJGJ<4p8d*01#M7oYEkuRzACqa2bKo?eb4v;RV{@wrx8P?|paX6hdXH!RSQwL* z=4V!E27r9uZEQwzh~(gYumcPv5d9|7EIo>DzsW!Qrmf2)$2kVii$D{7D2Mzc3{I+7 zhX^JXXU6Dq>;WP9e)@JzRn3!c`NccS?ji{gzN)>y505nAGLH`-C$#i-mU0^L)gt6C z^nR+;6aR5;(&fGIi{kKi_}lTjKoTH)<{dv%RmS?xfi)K0_$_}4Kc&$DZTz0U&z~ZR z!M%|8!13bNqMNVtd~{hN#+PsrKWnY@Uh3q0V_H#MjDwycVLI^)HQBY8nt zVjHu=J`VByAtwm@0(c)mIy8p2Z^$jWYaaPXh7UwO=FjUynt$93=s34sE8D(-ie$8?q6>nsWfx=N$E#WCIG zu{f@+ir3X77-}CGYEaHeG&iLUY3q=vqQrJv5)_nj8k1yX67g7=9;tq?$0rYb{M67t zvC8xKtL3_&pcKCdI72)rKV-QDzAbHiGQJ4}5MTq}0YU^M<0#$;R|w7zaS-7@SPEnw z??TQdw!ZZF99eN4$ zE0C-x|0+U4ltp);z^>A006Odtg}00Dpwm?rO(+MMaXpgwo~nm>M6gY%y^1`nb>p6@ zuxs_T7=K&>8sXwfx&@1hJB$tJjE!kMRSAx+N<`oMo-*4Dj131G($+rwCKplq_i+f$ z`?VDM;0W#o^N1fVo}xO6VFPqF=n&JEP{YLW=@C2L2tHA#gE_?!L?nFR0ku=#*bup$ z=j&h<66HArB1T*UBNHfT^Go3z+!uGpXTWtlHYK;ZoI`wK1eQ3y1m9|Hv#HAArSW@# znZ=bcL73H7mwgtJeUh0$Lo-T#Oop(c+$C~z`s(rw%&FIw2B{HOg$~#llaSC)?t>gOk1i_@d4OO!IE!py~C%s#~oVk}d|I-H^IDUStQ z(Kyk3BIhO{`-Uv* zIzaurFhy>dvgBT$N`fDP$+Ir&T~pZnQ1!2idp5})QM0*Hz9!PVXtBMJ^}Rp@6H)tO z+vDY*M+E8iig+1i1Q6A)DZ{KJ{4`)o@gx9xhT2;h$JzB=drf1X+X7ZO9Q6$&_r-H#T;`}(V@w1YWrR9joKt(a-hp4ZnQvUe8RRfYZPGE601n5J|K z3WQ+r6a->U*N_gAfoMvlF#89SCNa6#+=wa3AlXMI6id_lX*v#;-}n}4&@vmMl$O4k zXbmyV|K=;+`Y>wGt2OYYDDA;u!gJC*MLx%k7D@4$QEVE&FnG9O0GJQudrRFLX%sA~ z&-UU^BLqqDhd30+9jk~xE_rZL^6+H!<1Q`Obt0ZsW}PX+pzet-&-6Z8Can5vF>{Q&*sKg}Ary&|K)rPG?rKL4AnT9V2$Jjkohsq5U2n&qj4Xm-BMiL~O{EeY}-*k*k z$MIhtv7lU$bNKRn;f)!_%h72_h$#F(LBxT=h=WB@-*FV*`wl3II#e2aSR8v)9DAfG ze5!9uF}I|HQnNhE)|Nx!Y|jU!sL3)`Q6=U`Ffp~CQk zg%O9)5#2dd5P2v+{7^x}p~9%cC9%g9rHM-mv#zP<&`+Ln^%cO>HXvWM3fsFqX(Q*? z%9ke>o-Z%XniPeK!ibif>kKz!d0~J;bXy_1(^?qOUVN{kG`gcKx>Fq6DURzb2kt8? z;+2*0n(D{hbx#n#Ya3JbO=-rKbfYxGq{uP10=ee4JZpPFZ)YK3>nye@OJJz&>Wcnu zNxv4B7At?Su!q)dVVoOV1kf^QTN|yS#Z*O1TkKcURK-Cywav$&$E!w8;~341VpD2p zaukd?S0nR{fkstul0lBqHzR}193bCFj*-*&Q#cHWPNBoFefc-PDZIU36!vX#_`%}H zLqJK?5yHJACDF%9<3h!8$15M5QxrdPXcaT#?&XEKl_gAS*aV1sATa*8SGN)vf@10n zxW!Au{YGU?T7BlV>Xh@6r)R6v&R3@js7bp3)IPgZpLwMr>uN*RwZ@$5&3U(^`FCXb z;j)4VSy5zbaa4OrOh{Nwf#MH1NsIE_OY*r8B6OhXSvm5!|ZV7h+R42=o;!wN{WHJ4jxi{> z38ZoJ=v1(!K^*2?+ns-HPu{gXXmc;`##2$)HwAb072Mue6tTZ3lH*`;6o@@6d33fR zBdjGiN-m0(iDDInaf+h*isE>AA+?>A$pZ!&=UJD2bI7$Fzy#<)yLh6%X4g5;`gqIwg-gs}fb!NnN$cU9~Cd##BvHy0#@t zE6vu+@(isaV{4(gqr|E#v#QGbe3a@MFyUg*&_a}AM;B|m$JU7=+OQp)1N4khaX^nk z&bZSw>9$O|d#8qN)5G@ZQ3oo0v*VbBgSBq1`AIjDQp8)R5>UKKOinBz#F?LB17SSj znDdV2due1wl`N{?F(M1`mTfjhHUWtuv#22eDaPr(dp1ztWI#wJGyjbJk61E|`pv=0+$) zkw9xvR9kUOdud!}*~8BAhn*D(N^=2%ZKFfi+;5Z)7-d72Hm9Y-)vI*bFa)L^wrhqRJtG6U(Lw##kZIgy zMvyw`u}u#5O^*tWEv5Jv7zDQ(FqGA9hG1(32B@Hkx(TofNI1KWQ zFRL*yvU!=q$~#{J64qAU`KCPl8}aS0%ft6^R7UNW+&d_VIv}}wKoWCM5_?b*cUThp zU1jXS@@VvrNaBxHC7b{hd3UEr2CDUIu$h6O%>Bj{40y~>kK$`?cy^^O^;~`0`Fe1O zPWt(#^a~B?7n?FJH)ULE&bms-q_!m|OqP3FmK!D&-Ij{(NDIPSiz8c0?!u6^mBy$l z9;zgdx~dYoh{nh2+GKTIN>5{&wlQ7ToMVvY8)YJ+tiYrwGPM?)+ecvbGysZ>9(rey~3 zhjyf2KRRF-8#Ij$n#P>wahG-6-8=5KO?dhyhwW1%{V1(Xj}6X@gGtxyql- zz}yWCZ(xuE2R*$?O;w^a`$}W#ndbEK&FSZ)85f%~&Nn_ghl8^0%hcvvmFL`$=iX?| zyCu)N(JBg)<%hKv+-fUEd=u4H64_pIx4kr~y$qf(R#|ypT}2#r*F5Q}dZey?tgcDa z)IEVq?5TgMZAjHNr0E*r6*G;pEO`D%B-DbHdUp)tIE+0)zuH^ zng$Flg9ho4QSLOix~%Q)UZtn6i-hOs9-)FKRA(G_nlZ*i!gKdRds9T3V|uh7r8EV!-|U8lC_rmFakx-?u>dIue4QMkG^LQ@viQ+ZEQ5!GE8t*MOZmc({f z#r4!a)Yd)HH$BlcKGruS>lzWDCL#IIH9j>qKO<12nr@P1nq}E0MXsei-`ZK+t13l| zYNJ-%r>?MTB#xdM1UCq426XiU2CN}(K~m~8%Ul+PtG5lM22UTDL~w(N#yum5Z!khQ zWE>mPk2^6qX~vu$VsZp75j4Uj4$VP(6E0|vSy7+%FlCsuC$I7#22m5Lt?QeK|p#Jf}rsShQ%hS-7)Z?=B zld|+vip(>uS?5}_f%6@Cmz4$Al!e#2io?2!Z>q~~bytLg#-6Hs`nq^sZJeS0fwAea zu_@8m{Mf2Uv$j67wr2FUrT4aF*gCRp9at}t(}y|$76PHJqb#ti(2DxirKs-oYf7=m z%h4@H-Utlns;B~B#Hy|)CzhRCC^|)vfo<4>RZ)mevHh43onjTugwr_bLO=udEYqIe zX~Z-mSX61B8SS4PL#hD|nJ4szH9ltu9U`*v(HLk&nM)*pC?pwctK5n*5&FZL&8;XK zy1*E4#__j&$UOPB4_PPQ2}JhEcd}2tlYRP~>@(EnpZ_5L!nXVi)D~R+sNl*+#n(S6 zyZuFd;%Qa!{qCx#%A(lD+bg-hx9Y)HKuyBF zy2tw)o`Bx(faa%1np2O-(?jJMClr|{+p^CPa=-7$zo0Cp%v?VG^K+*<+My)Uqfq}u@sNW zaM;lS8+k}aY_vTCmMO9<5ewSbE>+lBgLeO;MW$>G6f32AXc-jJ3#9yWJXaLbMJM9Y z1xoo*M@3vZx+H|Az9K4%OPL!C2u;a~`Zx>>O@oK^eKZOR#D9px=fvT$H#3gEnFS_~ zZl(4(dwN3X;Av)H|M=T@ntk%^>{AS9-pM)pZtl7F^3K06y0}erX&cBaxGJFJ#`dyX z+e>b5FAd)b8pV;Hi=%dlqrND=x4S%gH`VBRr`5wk8dsFZ{U$=`bL@@DUhfMZG%AJpNYBiMP;Z9^cB55xO;l_0x}SA&G|4t65+&bZaKP z^cGs-zatc=bb|_~s|2VV@R3SX zF247L50x=s^^3|_@VQG82bF$V^Wdx6$6wbx{JK7IfBlpFO{s^QQ@?8lnHiz7%;WN` z6Rp|bw}Q<4bM2yw?M0WAC0CUt*VN@3p!+YxPY3pOO4RMC12ga5JqcqVZ zdt#C$Srn-j@Y$Zx+mUJO%*GNRy9(3q3mBzkSjk1Tb6U8L9R{$p3OhQ;X>m9$R>kHw zw95txsu<*=MN+7yj`m{6k?l0aH}PW?R9es$TssZi`Gjv3Cd?6LBN@Jp7W^Cr61buA z?e~OU4%3fr0iGRwg9Lf(&CF0Qy!|XlF%&|jHs|=8*}#c6vrf=c>IWRjIrDbj+4lg^ zB}U`L_Y1Fl$WeU#k__cNIKAx@?Fcb!_xF4vW!sBD9=8n$T_XZJJXhTzN7GB2Qhg~S$bVnep6K* z)-4I|sfpCqMrrF}bPf0QjSrzoV@sk@nq-nawX}i8bZbXuuQJD`%EtmruPk9~X#)vn zX|co^G&W;J73N0{)AIjz6jy1J25imAs^eI(A?zPUvsKyNnpmSKEcs?NI3J(1!4zAt z&-Op@?qS1cd-F}-SkZ0M;&;&K#mgL$sGzQ6TQfP(KkCIXI{pe|AKNM*bSsF>Ir$cl z_x-#1=ibf#{$0@p*x2{b7F>ai-Bxt%!{QrYk^n)L+=BnyE{@nCjzGH|e3nJ-Kr4>^ z%m;YRDwtW&cz;iI{9eei?$NgmNe3H}4oTCFL6h?A6Y`u>FtE^MyXZnk0hqk3EWN4{ z-{>k2Q&-$pgUQ-^UK+`?f<}`x32xIuArZ5#2!jy%fJSw3e-ESx8Y^js9&(rsf#X)> zFdZGVmY)R4O5<$fDca-)TTb!yinP6rcPl?(b0WTpM!<4mE=#s%AEO``)e2q-6)?W< z3u}TW*#wSWgoNascr)+RTX`q80y&{u2*S!gSWhc z{*l+y57Tiv0SJAauKE2tK*9NU3oa5wm!Qx03NF20cok-rC@s1ENlBO>%hEfamPKqY zkJ<^8MeHb#`m8eg^RlR&;(MP}#=^{g0RvkV|7G=qz10uDZb;nUka(aenW7)KN;#}+ zHZiH-Ocq}1EV|rT4C{KMtL&z_;*LfVsjFokvN7J+^w8A&*epvjLyhuOYa5JemJQJl zj4CWDXe1{Ii;4|Fu$K$bh=FA6H-_QI5!%lPQlzb@XkSi7BfKST0LM2b3S>4H$L;q&%cfJz*0T6FWP5geX+8xWm&TXgy@*0RoN z)}DHc4xWB1_vD)*969x7?#ZpW#|hb?Z)6|e!rC{`g4irjeJr4J?DfoJujib46UZYQ z%YeI_f0qDCFT7iL<%7a2+Xz>;72kyC{ICQ}hJRXq7lK5)v-~cY{Gu{uS5@4u>ib{T zKG<8Iu&*9zO5y>EW0MXyCm(4^3zemxkY}EfXP#E%d=I+JhQx!7$%mR#j<%#SCbP~cvc7N4In$bRzCHh9N8uG!(REcxn7W*CSQXV% z6RWMeud9EcZ+vWMN;FH8Ns5YRlwP)HLybr#vDTTUesqfmFrthc(pc-FkQE#7H1nAN zUW-azkwP5orh(nxXk$&<_l-w6-n~!|ukt8|4QY5cB=W8jW&`~+t|)AX>Yd3?xuSp8 zTc8yEa~1=2n0n|p&%P6oarC$8-@TT3^tV9vu`QX<)v-6w@gbMdLL@_t$F}C3B;=oF zte$?8KV|I}YENtl0y`Nr7M**q_|gYJ(WMVcuYFW{?L(mG^82ONKN8>kgaGz#e@X}k zhdat6cUIi{yb@VR%q~gn?yA^5wGY0kdjvu5tAG5hPm@h4WLim<8K>o7GW%>>?)i4n zRaMcAuF~6Tak!>DvK!@s>R4S}yuKlUIBZF_$iN{=1X;Fru0!S(p+jVn*bRh&8*qrN z%a}Q(2>{q34s!q?McTTEHuPgsq%Dfr{zPo2DVukzFt))h^NQXvDe{VJ!G3@_^$tk= z6b>od;9fB#B<0|*Qv>kq&~NY*Es%cXH4eBqc)YA5WGXX`yq0nJH)ykuf?kf-(aAde zo9v^nbHJ(MNM7icyyFb4lN0&|D9t~;HSg4x!t>DK`=wVtEWNU=gh7lz=lX|bH$D=F z5sekMKCQU@X+^}2%DX!y2vehXRmFT+8^5OxF>3tR4Tx+Y!UVMYn_*F(qVPjfMD3>~ z?WFwKX<7Oi1qweo7uxf#w2Q7N3vZ~3Z*_r2R<_et#gY^o5{ykSrzsXWf*TZjP~*v` zZC=PFg2M{NVSo-TejUP`^61pBLzq)xPgL)AZ~m=q0|Hda8~u|tC~4d{sEAyVrHj5< z;DI^}9*6RBnEdrGQuhBP@O1xQrXKiZ>i%D%1Ed_l(_itI=s3f(L%&Wt@GIfze&Jv` z4j%ed=HcJ?kahI6%tOESK7EZkN6@|op0kep2Crt}>CxBnPC~9*L}%YFz6fQ$Pq@6T zjF=>p-~L1rv7;(tXLZ!))i9*@cGtx1t&RJt{=vQmxWt70jR^-()M-Ij14Ej6T$*x1 zo^e_MbDH_RBI|5h&V`Qr%bf*RI||?xp~DDG`CU!Lz3$2wZS{R!?L%E%g1#Zq*pzIN zrkLf=dRsGLPOi*6@zzoDgXAw gd_y8^y}*-3woN#naPvda=>`silKr4u(aYig1+3!K=l}o! literal 0 HcmV?d00001 diff --git a/release/windows/installer/00.installer.adx b/release/windows/installer/00.installer.adx new file mode 100644 index 00000000000..af1b432e3c4 --- /dev/null +++ b/release/windows/installer/00.installer.adx @@ -0,0 +1,314 @@ +[ADX] +ADXVersion=1.00.00 +<=>2240 +CCM^8603:<;8=2 +CCM^8603:>;8=6 +CCM^8603:?;8=3 +CCM^8603:?;9=2 +CCM^8603:8;8=2 +CCM^8603:8;9=2 +CCM^8603::;8=2 +CCM^8603::;9=2 +CCM^8603::;:=2 +CCM^8603:;;8=2 +CCM^8603:4;:=2 +CCM^8603:4;<=2 +CCM^8603:5;8=$HM +CCM^8603:5;9=$Dgokcl +CCM^8603:5;:=$Naogte +CCM^8603:5;;=$^cr +CCM^8603:5;<=$Ii +CCM^8603:5;=$Etnue +CCM^8603:5;>=[bu!\i %K`g +CCM^8603:5;?=$Ucuz +CCM^8603:5;0=Qbjdkr %K`g +CCM^8603:5;1=G!~uzgcw*Emf&x' +CCM^8603:5:8=$Ciom +CCM^8603:5:9=Lbrvgtk-$" +CCM^8603:5::=$Fdnzr +CCM^8603;<;8=2 +CCM^8604:<;8=3 +CCM^8604:<;9=@kcolcr#',Ymz{n}v +CCM^8604:<;:=Rkc`{c pzihamw+zjb&qirh#~c+cghf"nrdeu tc`g(ik+kzst`kreg$,+Qd{+cc~&`duo#z~n{x.fg'Dsgqsf*n~|ae.vh&rmje`~,jf+ksgqsooo&pb~d%(+^jzjt&l}ut#cbhd~jn.c'bsape#fi|n|+ap'dd(g VDO+fjcn +CCM^8604:<:9=67?7 +CCM^8604:;8=3 +CCM^8604:;9=@kcolcr#',Ymz{n}v +CCM^8604:;:=Voc!nolf*eelbmjzgc&cmjot*mgznoow"b~h{rs-*,[zn}x. ^cr*&ie*ud}+yj`v'rn(ivfx{yak+zjb&gaje-*,[zn}x. Ii#(of#sc~(oae)v'q`fr we,d~n|||ksc!|ne#legm%.+^pbur($Cbdond).bh"~it(qam~,g+}ar'cy|ta`~eeo+.bzgju/ +CCM^8604::9=4625 +CCM^8604:>;8=3 +CCM^8604:>;9=@kcolcr#',Ymz{n}v +CCM^8604:>;:=Voc!nolf*eelbmjzgc&cmjot*mgznoow"b~h{rs#kbo(b}+\gfb,Ghlz$,+Xykx}"%_d{$ jl,rg~.|ols&ug&ouo~|zbzn.voc!nolf$,+Xykx}"%Hn*&ie*ud}+jd`%s&viht#~c+g}kyypnrd(rhf*jbdn +.Rucr{&"@kbhmg,+gd'n}&wbdx+|d.xzmw&dprrbixbfl.+gvbkr& +CCM^8604:>:9=4625 +CCM^8604:?;8=3 +CCM^8604:?;9=@kcolcr#',Ymz{n}v +CCM^8604:?;:=Voc!nolf*eelbmjzgc&cmjot*dj{+oe.gftmacr#|iy{bae.lrkcmt lx,oik+zjfh!|ne#ebn(jbykcc!gh zeyy(xwxzgj(!(Vrfy+*Rkx,"n`!qiu#}me|+zd.pbvmiee#~dn(mggk,'&Qzcsp*.Eg).bh"~it(bom-x+j`.vh&smvlbii+|ck+hkkc/(&Pqox()Mj`abj#(of#sc~(|oez"si!{ros*is|yohzkia!(otfg% +CCM^8604:?:9=4625 +CCM^8604:8;8=3 +CCM^8604:8;9=@kcolcr#',Ymz{n}v +CCM^8604:8;:=Rkc`{c fdxnz+zck"wgr{qoqn$x!+`nkfbb!|i frxyihz+zjb&h|cmp$,+Xykx}"%IJ*&tl*odfge{g'is($Cbdond).a"trnx&e{~~jkgei"nrdeu. +CCM^8604:8:9=7641 +CCM^8604:9;8=3 +CCM^8604:9;9=@kcolcr#',Np|jmvnio(Vrlm~n{x +CCM^8604:9;:=Voc!{raw+jnbdy"tnnu tbm({kymgir`oc ll,`n.bzgju!`gs#hinf+kszpfeumb. +CCM^8604:9:9=15170 +CCM^8604::;8=3 +CCM^8604::;9=@kcolcr#',Np|jmvnio(Vrlm~n{x +CCM^8604::;:=Voc!{raw+jnbdy"tnnu tbm({kymgir`oc ll,`n.bzgju!`gs#hinf+kszpfeumb.#*\ymx}+,Afhbmj"#~c+{a{.grsietjdk+akf}, +CCM^8604:::9=15170 +CCM^8604:;;8=3 +CCM^8604:;;9=@kcolcr#',Nzyay +CCM^8604:;;:=Voc!xgtk*eelbmjzgc&cmjot*od}gj+`ms&cm&cqommo.d|"cid{&nl~,jdykjj{'cyaut-*,_zr.x~gdogqond*m+lbhmkpbhu(vawb" +CCM^8604:;:9=4625 +CCM^8604:4;8=3 +CCM^8604:4;9=@kcolcr#',Nzyay +CCM^8604:4;:=Voc!nolf*eelbmjzgc&cmjot*od}gj+`ms&cm&ouo~|zbzkl) +CCM^8604:4:9=4625 +CCM^8604:5;8=3 +CCM^8604:5;9=@kcolcr#',Nzyay +CCM^8604:5;:=Voc!nolf*eelbmjzgc&cmjot*ex(j.Ykcc+Nfjy#legm+oej"ditdb mex+jn.dxguqsartfd" +CCM^8604:5:9=4625 +CCM^8604;<;8=3 +CCM^8604;<;9=@kcolcr#',Nzyay +CCM^8604;<;:=Voc!xgsp}cyl+wd{"tvdkofjoh+j}+gldiszccw$,+Xykx}"%E`feeo(,g+}ar'cy|ta`~eeo+gkot(!(Vrfy+*Bieapb$!|i pae{(dxn|"snd(vapy{dzo#{|mscb|cd#cxne% +CCM^8604;<:9=2 +CCM^8604;;8=3 +CCM^8604;;9=@kcolcr#',Nzyay +CCM^8604;;:=Mic!gt ne~n(dh+zjb&qzigqkax(fjz"pcsm&svz|d{n.a"uso(eovfh+fdz+lg'`n}hd-*,[dnoxk"dio|gcw*ud}y.xadsq`zc sxc}aoky.dht!`cls$ +CCM^8604;:9=2 +CCM^8604;>;8=3 +CCM^8604;>;9=@kcolcr#',Nzyay +CCM^8604;>;:=Onurahg#imiaek.dnjd u)- +CCM^8604;>:9=2 +CCM^8604;?;8=3 +CCM^8604;?;9=@kcolcr#',Nzyay +CCM^8604;?;:=Voc!ksswea+znib}vu!ahflxaj|bae.dnjd(rhb~,|ix.x{rwirmb we,im+cn|ebb!otk*xcm+}r}vbk!zcgjyxyq+md{nc&ogr ao,mg~`o "'Vmmgsf*odfohz"~itz&sllx|iyk+~phphlcr#lcy(ckg~, +CCM^8604;?:9=2 +CCM^8604;8;8=3 +CCM^8604;8;9=@kcolcr#',Nzyay +CCM^8604;8;:=Voc!aren*eelbmjzgc&hf&tko,manbo.`bjn&cl`o(ea.`b&smaip~iymo +.Rkc`{c `ebihz+wmrt!{ifw}mym+~yatnbdz&flx,cmg~% +CCM^8604;8:9=4625 +CCM^8604;9;8=3 +CCM^8604;9;9=@kcolcr#',Nzyay +CCM^8604;9;:=Voc!mhd#ej+|ck+]gk`,M~tqkoaei+tkw&gaje#}mx(ykjmjbb!jcflxi+igb+ad'rim&iwoax(ha~bf'dd(vrlziydr.nvvugb|cd-*,_`b}+]gk`,M~tqkoaei+tkw&gaje#gmr(ik+jcjgfmb.#*\gmj}n.mer`ah b*jymxf+mmw!ihd#~~r(jijgl) +CCM^8604;9:9=2 +CCM^8604;:;8=3 +CCM^8604;:;9=@kcolcr#',Nzyay +CCM^8604;:;:=Voc!m~tqkoad`+~phed{u gch+fdz+mmjvmmre#yyhkn}xhwkjx&& Wbex(for.jfpd(defd,hi~}nj"e!ih lziyiay.Afhbmj lx,d|cky.gutnz( #Z`nixk+mmir`kr zeyy(xamzuftd(vrl|eomy.map'nddv. +CCM^8604;::9=2 +CCM^8604;;;8=3 +CCM^8604;;;9=@kcolcr#',Nzyay +CCM^8604;;;:=[hss(uyp~if(oan}"iiu(nauo,nfd{lf"fp`ajaafi+encd|{'rn(uu`iix{m{gb{'cy|ta`~,`n.bzgju!nton*xcax.Xkna+Dprrbixbfl.qgr'`hdc.#*\gmj}n.ahhuiet#sc~z+}dhvpgsm&pqezbln|+hmu&imjp- +CCM^8604;;:9=2 +CCM^8604;4;8=0 +CCM^8604;4;9=@kcolcr#',Nzyay +CCM^8604;4;:=Voc!m~tqkoad`+~phed{u tk+kj`hknkce(deee~n(jbg.ma&u`c j~if{+yn|g'cy|ta`~io&+.Raw'k`q&nfoh+|d.y{l'rim&e{~~jkgd`"wtnkcsp*mlib`% +CCM^8604;4:9=2 +CCM^8604;5;8=3 +CCM^8604;5;9=@kcolcr#',Nzyay +CCM^8604;5;:=Voc!nolf*eelbmjzgc&cmjot*od}gj+`ms&cm&e{~~jkko "'Ou(kaz*mgznoow"ec!ah vyi+jr.fg'ux{ren*cy(gahegc&cq&amexcmy.j~rkobirild"+A.|gnk&cm&shc|{mo +CCM^8604;5:9=4625 +CCM^86048<;8=3 +CCM^86048<;9=@kcolcr#',Nzyay +CCM^86048<;:=Ci&dztoq*chk~|ykf'btzond*xcm+kszpfeuain#z~dkn}x "'Rim&aqidb~n.mgnb.r!&mbs,im+jjcc`ce&& Sfij{n.dlvfoo(g exix`+md~{'gol&tqs,jojge +CCM^86048<:9=2 +CCM^86048;8=3 +CCM^86048;9=@kcolcr#',Nzyay +CCM^86048;:=Uoomm&e{~~jkgei"nrdeu b*hj|j.n|pht!`gs#eoh}y|nj,'Riau Po`m%Nv|cdrhfa yc|+nbbn.of!jc gkajonj%."Wjdiue#enib`+o"atd{n `e|r(j`o.vu!iaajd" +CCM^86048:9=4625 +CCM^86048>;8=3 +CCM^86048>;9=@kcolcr#',Nzyay +CCM^86048>;:=Uoomm&e{~~jkgei"nrdeu wbiym+yj}l r!mhovmd+zdaf.mi&u`c goaeogmi&ezovf$,+Qd{+cc~&omcd#~c+zncdxg'unec ec`n{+lnhmuc!qiu#ime(nv|cdr!ijl#ej+|ck+gvbkr& +CCM^86048>:9=2 +CCM^86048?;8=0 +CCM^86048?;9=@kcolcr#',\iy`b`e +CCM^86048?;:=Uoomm&e{~~jkgei"nrdeu excf(fn.Qbjg%Cxwxmh|b`l.xnv!nolf*den.bzgju!crf*`a{~nj, +CCM^86048?:9=2 +CCM^860488;8=0 +CCM^860488;9=@kcolcr#',Bfmayccsonf +CCM^860488;:=Ckj!areny,|myk+}wded{ufvf`r(nv|cdrdl( +CCM^860488:9=2 +CCM^860489;8=3 +CCM^860489;9=Kiouagljpi +CCM^860489;:=Rucqitimm,mgy.Nvvugb|oom$,+Xgkj}g'Q`ar. +CCM^860489:9=2 +CCM^86048:;8=3 +CCM^86048:;9=@kcolcr#',Nzyay +CCM^86048:;:=Ci&dztoq*{j{+kemmrhumteg*{cagk+~pbv`zond*jdz+kszpfeuain-*,[dnoxk"dio|gcw*ud}y.xadsq`zc sxc}aoky.dht!`cls$ +CCM^86048::9=2 +CCM^860484;8=3 +CCM^860484;9=@kcolcr#',H`daxk"Aimlcr#Fchigd` +CCM^860484:9=2 +CCM^86048498=Fntdkroqcix +CCM^86048499=Fuowmu +CCM^860485;8=3 +CCM^860485;9=@kcolcr#',Xmgkhz"@tn}v ee~+[cayzarrr +CCM^860485:9=2 +CCM^86048598=Girdz&oq*ndnm.c'asgsp#dmfm+hd|"nhr|glocbl(xfd|vdsu{( +CCM^86049<;8=3 +CCM^86049<;9=@kcolcr#',Nzyay +CCM^86049<;:=Ci&dztoq*chk~|ykf'qiaje#kxmf~gl`&ug&imyxjdg.xfmurb}rs- +CCM^86049<:9=2 +CCM^86049;8=3 +CCM^86049;9=@kcolcr#',Ymz{n}v +CCM^86049;:=Mic!gt ne~n(mggkq'qdzc jdigbnj"sn`|&rf{ybzn.rawu&rqutfg,g+ln.pbuuittfn" +CCM^86049:9=2 +CCM^8604998=Pbuuitt#,Bd +CCM^8604999=Pbuuitt#,@j|n| +CCM^86049>;8=3 +CCM^86049>;9=@kcolcr#',Ymz{n}v +CCM^86049>;:=Rkc`{c jdnz.]anrkd(Hunhiy(.j+glsi!|ne#xifg}oibg'bsape- +CCM^86049>:9=67?7 +CCM^86049?;8=3 +CCM^86049?;9=@kcolcr#',Nzyay +CCM^86049?;:=[hs!`gvf*ee{n|kf'rim&wqebl(]ag{ob(!(Vlfkn(hfnmi'rim&mfnej(j`o.vu!iaajd" +CCM^86049?:9=2 +CCM^860498;8=3 +CCM^860498;9=@kcolcr#',Nzyay +CCM^860498;:=Voc!losh*ex(ea.pbgeq&flx,jkhkx},'&Qdcapo,h`nm`.vh&lime#yyym+zcov'rim&mfnej(b}+ypnrd(cnbh`nl+oej"wtnxcros,bfxkyzgc&hfro#~dn(o|bxg) +CCM^860498:9=2 +CCM^860::?31=Ahhgatm +CCM^860::?28='t&iiu mex+jnke.qbrtx( Bxi+qd{+}wuc!qiu#}me|+zd.gou7 +CCM^860::>31=Gutnz +CCM^860::>28=Qbrtx&hby,bfky`ck&dztoq$,[dnoxk"dio|gcw*ud}y.xadsq`zc sxc}aoky.dht!`cls$ +CCM^860::<;8=1 +CCM^8603:;9=^[udzpeqVdden}Wa`mZcdcngo~&kykjzmu+3&~x.}eeldyx gc +CCM^8603:;8=AZEGEUNOr:Tm|j`i[JNKGLPtW\nc{Rqa~7K0.yc| +CCM^8603:4;8=2 +CCM^8603:9;8=2 +CCM^8603:9;9=2 +CCM^8603:9;:=2 +CCM^8603:;;=^[udzpeqVdden}Wjgqcmgv\qo`nixkWykibnu\jdigbn|^76/ahswk`gmy bmm<6 +CCM^860334;8=2 +CCM^860334;9=2 +CCM^860339;8=@kcolcr8: +CCM^8603:8;;=2 +CCM^860::>=3 +CCM^860::38=3 +CCM^860::<;=>Nhr|gloLcgln|5RWioo{raof"npn +CCM^860::<;?=3 +CCM^860::<;1=3 +CCM^860::<9=JLCXWELBY_N[T\DAV[(cdcng1$Ommo~bv.zICCY\I@J[XKXQPHIUTdlfdhmagk0&Fb``}jt*vD@MRQHBCTUD[YRLEXWjgkejdnjdTuhff`Wg{keRahklihd8"Hnnj{gz+{NJM__@FMX[N]T\MHR]jjemnjbdnROkdfsm|Ocld7#Lnhj{ns/}@MEZU@DKJBTCCDNHFC\Pejj|nROnesguoe~P\aejdyq[Etztem~Znzxgd`^Rhhfutbf`WJgkejguEaupokuEifkwFIB_^DICBFSFIHFB@G[UnnrwbxiWEbmyaqh`uTQimnc|{WM~|pbhu^crpcceT^`b`qsgmdZBoobomy5^`kiuuijlP~~bflr +CCM^860::<;0=>Nhr|gloLcgln|5R@kcolcr-otnt7Ge}vfjmNilgo~5THa{wpnai|(t{~p7Ae}onk@ndbeq4PYmjjfk,s~ut:ImyxjdgHdbfbt?TNeoz"~zg505~;Oo{raofJddoky0^wu`in1:"odg505~ +CCM^860::>;=3 +CCM^860::8=3502:455 +CCM^860::?= +CCM^860::?>= +CCM^860::?0=2 +CCM^860::>:=3 +CCM^860::?=1 +CCM^860::0=3 +CCM^860::>3=2 +CCM^860::=>WtnotanLegmx0WLnbhemt +CCM^860::>=@kcolcr-otn37Ge}vfjmNilgo~5TIbn`fbt/m~e8:7;3;505~Diqqtidbx%|sz02KiuuijlEe`omy0WMmwsaahw$xs|0>0>97:3zRfkhfm%zsz9;Oo{raofJddoky0^Uc`lke-~t3;5;52<:tNeoz"~zg57Gltr`djFlfhnz5RCknw(tzj;31<08050rr~righ23$hgd02B`qsgmd@ooniy6W~rzjhh38(dof7;3;5;593>=3 +CCM^860::>3?=2 +CCM^860::<8=3 +CCM^860::>?8=2 +CCM^860::<9=3 +CCM^860::>?9=2 +CCM^860::<:=3 +CCM^860::>?:=2 +CCM^860::<;=3 +CCM^860::>?;=2 +CCM^860::<<=3 +CCM^860::>?<=2 +CCM^860::<=2 +CCM^860::>?=2 +CCM^860::<>=3 +CCM^860::>?>=2 +CCM^860::9=Lhr!i&Nvgnnz +CCM^860:::= +CCM^860::;=upq/jjemniy&eb +CCM^860::<= +CCM^860::>1=@kcolcr#I~niay +CCM^860::8=0)40k +CCM^860::9>9=2 +CCM^860::9>:=3 +CCM^860::9><=3 +CCM^860::9>=3 +CCM^860::5<<=2 +CCM^860::9>?= +CCM^860::<8;=2 +CCM^860::<8<= +CCM^860::<8=>Nhr|gloLcgln|5RJbjq&sro +CCM^860::<8>= +CCM^860::831=2 +CCM^860::59=^[udzpeqVdden}Wjgqcmgv\qo`nixkWykibnu\jdigbn|^77/ahswk`gmy icr +CCM^860::5:= +CCM^860::5;=2 +CCM^860::<9>=3 +CCM^860::<9?=3 +CCM^860::5<=2 +CCM^860::5=2 +CCM^860::5>=2 +CCM^860::5<=2 +CCM^860::5<>=2 +CCM^860::5=3 +CCM^860::52?=>Nhr|gloLcgln|5R@FEJ]V +CCM^860::520=2 +CCM^860::>>=2 +CCM^860::>?=2 +CCM^8603:?;:=3 +CCM^8603:?;;=2 +CCM^8603:>;:=>FBUmkp +CCM^8603:;;>=2 +CCM^860::9>;=JLCXWELBY_N[T\DAV[(cdcng1$Ommo~bv.cdcnglegm0]|kia}@MEZUOGIX]N]]UIN\Zboobonbbn5*Ccgislw#7Idn`okp'@hdc;P~~bflrCEG^YBDGSPO_TZDA_R`kcol`iooPx`nbgRmwcoTeongmel0&Okdfsm|/;!6Ee{ogbDhjemt>_H`nfoky gc#($%2(7X|ygei~OMDQYCOK_XMXQYAMSZcdcnglegmWJnhcrjuAeom1$Ommo~bv.#4Onp~mgdMagjgu8]Jjemniy&nvn,.6R|timmpCCNWTBMDGMWKA@BEEMW]dhvpgsmZMji~d{dhRUnhegqs_Iyyzn`Xguuhgh\Vdee{ogb^Ejdfbeq1Hb{{bjwLfkd3Dlfdhnz0]|kia}@MEZU@DKJBTCCDNHFC\Pejj|nROnesguoe~P\aejdyq[Etztem~Znzxgd`^Rhhfutbf`WJgkejguTfonp~mgdXzygl`Ahswk`gNdbokp9ZTfonp~mgd%ksk9Trsahg +CCM^860::28=Ubjbgke +CCM^860::>:8=^[udzpeqVdden}Wjgqcmgv\qo`nixkWykibnu\jdigbn|^77/cl`ean&yzm +CCM^860::>8=2 +CCM^860::521=[bu +CCM^860:;<;8=Lh +CCM^860::829=Rkc`{c qomo(fn.dhjmgqimm,Gahke}g'Gfzcenob&+.^}g'rim&s`xcgd+lj|"si!~oet*xcm+|n}v'ig(rhf*hdk~cn`v) +CCM^860::9:9=Fh&xgs bionx.jbn'rim&tfxax(dh+zjb&qzccfneeo+Bbmgiud(Ggqoifmez4."N`!qiu#iddgxk+@m+&rmrus*{bdg.hbmtc/(&Tl*ee{ogb"snd(vrlm~je'.raw'kt{r bionx.fkt&`otefgie|% +CCM^860::29=Nnedfue#Kkymncn`v +CCM^860::>:9=^[udzpeqVdden}Wjgqcmgv\qo`nixkWykibnu\jdigbn|^74/kipzxel` vv +CCM^860::>9=3 +CCM^860::2:=Ceit|&Boobomy.H|gfrnz +CCM^860::>::=^[udzpeqVdden}Wjgqcmgv\qo`nixkWykibnu\jdigbn|^75/zcaggi%|sz +CCM^860::>:=2 +CCM^860::82;=Kiuuijlb~edf+Hdbfbt +CCM^860::9:;=Wtc!|ne#lendo.iknhq!|i pzihamw+zjb&ggjdfx,|`n|n.{hs!gnw*xcm+o{~nne`|oom*jbdn}+zm'dd(eoscio(a%.Vh&rxccjlu+i+jbhdbtdfr ee`omy"+z{wc!i&nf},eifk'.mu&t{c wbi+Ti.I|mpudTd0#*n~|ae.vh&rmje`~,jf+ksgqsooo&flfhnz%.+^pbur(Zb#Dis|Wl;."si!kinwcb~m% +CCM^860::2;=Aoin{c Pox~x+Hdbfbt +CCM^860::>:;=^[udzpeqVdden}Wjgqcmgv\qo`nixkWykibnu\jdigbn|^72/nilgo~%zh +CCM^860::>;=2 +CCM^860::82<=Uhtjahg +CCM^860::9:<=Rkc`{c tke(|fbbg'#r(os#yi}{.d`"~itz&clg|~|n|% +CCM^860::2<=Qbrtx&Pqekymx} +CCM^860::>:<=^[udzpeqVdden}Wjgqcmgv\qo`nixkWykibnu\jdigbn|^73/xtodxix{%|h +CCM^860::><=2 +CCM^860::82>=Qbrtx&wby,x}hmn}qasm +CCM^860::9:>='t&viu pohmx}m{nk!{ctvz,df+wd{p'enevuwo~%(+^ykqt&]j&Fjdex`Wl;."si!m~iw*n|~~% +CCM^860::98>=Qsgs|&Boobomy +CCM^860::>3;=>Nhr|gloLcgln|5R`kcolcr-otn +CCM^860::>3<=2 +CCM^860::>39=3 +CCM^860::2>=Qbrtx&Clg|gmk +CCM^860::>:>=^[udzpeqVdden}Wjgqcmgv\qo`nixkWykibnu\jdigbn|^70/kimsfim%|h +CCM^860::>>=2 +CCM^860::<:8=Wioo{raofiy +CCM^860::<:9=Voc!}himyxjdg.{|m`t`e&wjf`+zncdxg'`hdcs#kbo(magjguu-(uhlxxh}}'.cib!zcgjyxyq+kezpncr(`rlg,`n.ogql(!(Grf*ud}+}~|g'n}&wbdx+|d.~`kiuuijl< +CCM^860::<::=Mic!g` `ea{gekezq'or(gcwczn&+.Nvks&u`c sxclzjc+lgaism&swk~aei+[lnhr|glo$ +CCM^860::<:;=Wioo{raof,x}hmn}qasmd! +CCM^860::<:<=Ci&dztoq*chk~|ykf'qiaje#~~raei+zm'soahswk`g(fn.ruifzgm-*,^fb`xzckj!`gs#hinf+mj`abjdl( +CCM^860::><=Qbrtx +CCM^860::<9;=Lhr!i&Nvgnnzwrwr~{Dmmhdfx,Hznoap{4/:7c +CCM^860::<;:=Giamauh#',^fbznj"Tr`|cs +CCM^860::<;9=3752 +CCM^86033:;8=>DAsgsp10BfxzjbnAimlcrVNgmejn|,b~d3Boobomy5059<6 +CCM^86033:;9=>DAsgsp10BfxzjbnAimlcrVYeae}onk(dpc;8_bbfxzjbn'Dmmhdfx70305; +CCM^86033:;:=>DAsgsp10BfxzjbnAimlcrV^niocn vr:3Tebnan305052 +CCM^86033:;;=>DAsgsp10BfxzjbnAimlcrVOdxr|bijs(upr;8Ic{qyglfv<:30 +CCM^86033:;<=>DAsgsp10BfxzjbnAimlcrVDnd{ ~|n<Imjp81703; +CCM^86033:;=>Ccrcros477Ae}onk@ndbeq4PIdn`okp)cym;Afieln|059<1 +CCM^860:;<;9=^[udzpeqVdden}Wa`mZcdcngo~&b`oautZ+&, \ No newline at end of file diff --git a/release/windows/installer/00.installer.ico b/release/windows/installer/00.installer.ico new file mode 100644 index 0000000000000000000000000000000000000000..922c9d472d9f2bc9fe7af5474217e1a4af5faec0 GIT binary patch literal 25214 zcmeHv2UJzb(rz1Z%sP%~bObSHP!KbYh&hWW=7?z=byQGPP(+e~C<2NK28@h=i6ACW z89+raM=*;@lyHdkzUsq4P{;B9_x|s#x7KYf`t04+UDegSdv|qJZ6V5tA4JWXHIbJW zt;z`DCIqept}BVT6@)mCd&+BdF}J)BE!2ciS6AY{Eh~gm6~0#DAFd?Cit4Isb#WN& z{8CSdPMwtab1MpQwIyE{;RClr2h}z3n+tKbrx2}}2LPHC%oiss`S)voP{M^)R>};2 z@e^PrE?&Hd0+Rm)5&r_0-)^*<$?6#bWlHxnjYB zg<{FlrDFN=6=Kb*uJXh3Rn=fVD-R7-mzAj6&b0pEjK3#Nk$P`^26r$Va0-?K&#E?z#V*Hj{qQB!i zVdC*Z^mWP-gSMrLVQ$%?|1J_nJ2S=P-5n=A5jbBc%Qzd!yff&XO*lqrL?S_s|tT_mA0<0tnm zSEgQL&32ltaid(H$sIdRoZP;tf$`uDO@$~we6oQ?djm~FquM{3wCf-$jGo-He_IVr z;~#6*9NxCAs5Ew3k7^UOH4TRS_@i;NwxY7hlx`+N2es7fH?n`*&O%g~Jgw`*R?S;A z@1UvK7VTG?GNs1MS<|OaZK1)JqS~}6RVu6L^&Hw#UWyvi$5kKEyGn&_W3kF1)tL2b zo599o$Ld#BE06V0)EM2Me#3@8|6*V~l9#`p`h(kb((2NzNf(`ZU2)y*hq`rtYN0(~ zV8wnz@QRU1zgyQDHAFS8{U2Uu)s^j+m)YO`>DR9x85kJQz<~q#wNonfaiKo}F9A0J zi%J#ZLSJ8>;^X5fCy(gTg-bMYJG5uq;q>YPp89J1_G zZD4(;lP6D7QgRZ__DZ7ZyWY{ucj=UzoJ`|(e59_9dE^%QfuiobppfgYY4YA&)R%2c z=Qbuxm_X4{k@O+y19=3!q#ll$G}b+hc3ns&J;z+yeJPC|-MUQse``S}97fZF_?I-m zy?~~A=g59eo;-!_-@8Xx|LDMh1LS-0A&qp;U>-?l6VZ)_Z^?gse{wb!w0(@A8xbM2 z@JKF=+M%pJW5x`MfBKlxQd7y(a~CaJv4UQ_Ng}gj>C|mg4s8udrdv^G>BurII^{5u zqHjH-9xjF4{wC(%)YOz-zj{F#>FMO+vW1>Le?x&c)5tG6orXHUL;v&1=0q}uMct;8 zSDz5xH#BR14%f$SM2Lk87t;H8Z)N?>4mR}cO)5>={+vd+yrMB%p3z9BXOLMQb=g!X z`?Kye%P*@o*X8v4;-!@FF%9sMtSv1lFGnFEJ6k~tKvJ55#yQ4Pce^w?9F_gW+*pqO zW@Ub)6pR=1!u^>wYbI^lw26Ftd?@60HW}Ezp{OTc)@Aw@78az)%Ai-zpVHb@=5*)g zbvkR7M+Ig*j_C{hZPnty=Pbbom zxJ)vdG`m!N?!&MB3{_8dwYD9!jXL)*aQtn_isvgD<}1m3mBklzUxZ^n zhy9in+W7+b{x|k>-bMR4b=1`dsP?@=uG_frMY1X)VpT*7Ip4ycf86(e(bnfT)UbO+ zD$1}y#&#BW@JD&yoQUsudV0F^4Kq7zrxj+rDGoNn{?^P{;pt3{*enAB*OqoU!57Fr z7-;svs9=t5v!}DC2bozaJl#?5tiX;t_(JxqITRd-YdkBc>9x_&&{A1Wyd`(uFl&~j zEO#bnH0_mTXsF=*JGS8pZh=;q=LB1!{XCQd!Gnma3(H`I9TVWh+i!DEWin+0;``I?+b!2&9}wp3U; zLqL2>B3OR(+-7Fy3?6Nj*DIN`Kr=f#Gg;r#Ld9JtzE*RV<%}cI&9arnz>@5nb>kw4 zer51UC4yO39-GBrK(@z!p`cZ$E z(mK*$uTOf?i2Wq>q*2h7#`-ArrTGVwq|RjS|4DCJc3dG${Yfl7^+|_XdzOmzDAu8N z?{JlRl*9J@!fEFbv1{)kvHeg;v0ioffVb4GjvqfR{C%Nk1q4bx>&%(cBIHbf)VG2| zFNpK!&x@Gz`^BYmK~n#+^NTN~gN24gOFhg!oP^6&`deKrB%x4*g@=hNm#;{jEG9Za z{1y3^xOOc{#KhbXaWTS=fG+z}5S+!Ie9+!pul-xm)aJQR-~KazS|Nu4d? zNv^p4GDqreuU@?pZ{NHTNr^8+V&Yq=!+m)FK_o+u`ynq3Cv`faJb`VSDCF~n|E7OS0{;Jr1kI=7#NvkP)UH{xPVp6fl(F;k zw5wjGq7r9%8~sN5>P>zu#wcUwv3w|sCrS0Wn7(5e)!-)zk>&N zw`r%Vr>mo-qpPRat_Y!wyOWEb<;aFVmYLQAK+zO}2Nu8xtP-;@Ro4*N~e(Q8|q8<6Eb zD|B?U`n1v0)!Xma;HRH{s=sePm{gYgxO)2S@-pk!y=Qwp-9dg!>LLBqz;BFB`%mR~ zk-81m(kWR!SVwP?Y~RPz$IlZ?xQy!FQ&(??vi!1e_2<BbSW#jl;ZtXZnKRa9NKb9{2ZQ;B*Q>QYKPsRQfEgfzBtgRP;J=1x!W}sN7 zWU;@Rjg9reg|kc-Eig5mHFatm)NWg`xOIR3${TI{7R_2Xv0{}v6DLiYJgrafKGn*W zD6i)3=ddsci6|%)y{5K^|EEklqqhZ znxE4z8cj8u^=Y$wrK6J*yaAmA7zF4J z;PanG0H#q5!18Jb=nY_;p+z}g^ZmL2J_0JqGcIM~do|0KFF&P4ixzLAuSLu0bNkk9 zI(+yrb?@Fiw@H&G33ck!xlpN6B_HtP0Q}zpES~{@zCX4fIZu74omX>{y`jxbye~By zzx!fi!_~*DH|@Cv<-Y-j16l)^*HS#Fsi~E%QKN<_*0FS^jXj8J`pUeJ3hDj(_jLL4 zWx{ziX=`ie{PN2$@junB9#XAg>jN#P9lO+ZV{$g1lY9HYqYvNs*Zb1w=vFifqcr$e@onpGZo4N!A{x zsGId`(sNKqx?SzFNPA-zb=Z(a*sl^_tN7_+`8=(9(_WsSI|a}jz;i;CYPD|NI^)^1 zXT-Gmtbo(GTWPdlZz4G#yh4eu;we2X6=zFHl$`XA9wsExFn0xYv6p8kl3veES!C*? zAU;=_doYK3ZC3K3S0ooL^E-)ZwVLpGmm#3|X~e2o3vYn*XV0HW+K(PSlJw{7&!py- zIi#~OofdC7OONi~rsVgDl=k5@IR(U1#|`rAi#nmNs{(T9exj^a{O3^;(b|(avRto7 z7V5(t&x7`K06$AIVb0fT+oo+gYyiZxc^o)d2c!{n0n)KoP-n<>_V&AU<#IU1Cp@DO zZXc}wo8BW`n9B;kdVNQ(c5=PwEp;eNxL)Cvdy9KE>CEk>v8J6Ig@nkvWR8= z1pQ>%d)5vm+o3|j#=(MiFK$EGDbMLe8WD6AIUl-iOvwY?MSx~1`ak^eL#+-SI;1Bi zCKA(r@!~l*NXZ}GQOf%_oxlcxr_h*#~l@tni%VfbIf7Qx*Mc)vDF%)TvYYhYuel?bokg$vUqgkJqnW zQqtRJbS3sVP4rBojy4L?#dxqRyVz#Y*qzzLqQ4X7Lk=TBf7~bfEQ3AP#rE(pT^s%nh z($UdLfBQyBJL*BQq#vIUPfwpbrH79m(SrvM=;_0I6#wuRIUS251B?gDLE9#i=J@1L zN*1bQzbCJaQ^{v-e>$*XEM>foqf96?i;sPpe;Om5Hi9Ux+sgBL{HR~IUM;M#>F*M8 zHVN9pwsT`dkDojS?T0uMyid1p#Zpjc7zLaTqM*P)+Ti9-eK#c&?1J+7n!Z;-SL2C3 z=0l6ZfN&o5lCTaa@SG~wp^i(V&y}z8V@r_a_ds!K*swt@{XV_Z@5jHDwEH+^OZwdB zdpM80dnb-o?TV&e_Q}-8A&K+>{Wra*UXJNl`?3Mbb%w`eu&aV5dFRqlH-(fpuZQxv zTlFxy>MuHNK(rKXW}->shPAr(=#w50^^TafiaxJ}w{OK!?9CgraPM2pf2>82xe{`u z{JYxoJWv9!F{Ueq1 zXCADG6CfywItXjT!*>ueIX&_P^@VBRtP1PIM>Zxy-e*CX@#I&zozbENOMn=(JfBi*a zVPSOf!g&h25JDG2&rnF<2?{)UoKE;1r9Th*kl&#_Was2c?0ndqY59T!JDt*)uh zwE4YX@?D3^(n&+3NiBnc!_ot9yq2`DNB@QOG?%VkxhiR&2W=dY(dkpC>BNZu^7Zwl zBS((V!Gj0sz}`J%X6Hrvj!C3tmruG5`D9`nMs*uDxd1A>2jP9tHn!gV|91Sj|C1+APUp3sX{V*7 zV2n@0j*=qhL3UOay~0|2>((v8xsa4Ujwp%gufkdSZ@(>|8Pg`y)X64ZG z3TQ3^unhQJQ*>B}U!Nt7rW&5h>d!n?IBzpbw1>V;W>E_Lwa-Mp7d(i^eN`?*{N?1?dV@~_n*9{|7vR7 zxN&XxPJHB59A{6|X~s^fFzymnoq3DuFT6)xSKp+G4q>!sS|W{gdDOu!hk9(uA;Yc7G-lglnzr#It=n^s z+thZC0`H!jb zinr9rB8?hb<&owFqSp3AonQmh*@C^qb|OPhBCtv04q}b>BU%!WOUqAWk@@itwA$+` zHEh)6CferrJj?!zH5d0}!k+(!_8r>$v)wK`4Bli+bfh}pu zVWP>%$Aa#7AEK#;U|%|v1KK&XBB+qoog>uIPODI%!e$T|4*1(OsA=?z4{VlfyD z`YGA$ze3|?F3IW9Z^-@DZ9954YSgF)i1M@l&38aa##**$S-H8UM$HyYe`yFkw7q8Y zRt6fH&4=SKWkS1-T^4KU_FUh(V`saLy1n)`Ytf4LvejC(X{XbsqxL*a&1S=~o^`@m z8tYhpyXL9rrPd%y5Eq+V#2mH47y-(BConG8sR3vL=mW4U0=_N@eFVw@O-h0Swv|@6 z(FrgOpt2iUeRZUOAgttnHWuO+0RQ+F{`~uPLo`@A!GgHB^d03D+s0HSpMD877#0;p z*JeFnTr8?A4UE#{X!ZwNx`MmP0yT3sJR-rchL;JauH3%rKCEymvtJ-r;QO%bk%DcL zp0K~+uNmLxd%@-krIiuwDPWB&x}WFi$zFb*9-u;~w+#(3J{k^m2A(r5n`KIQ(ln6y)Ujh69@OhB;ok{W%3~Tr@ z;F|)!6VrtXUu3$Zjlds>%FL%TSa){LVaYgW1K$#i$@|WX&)xL&LIrd1zeV;7d@7vT zrpg_V{q^Vj_{CO9I~I=zq=y{0CI5D?ftpKC#^4~-Vstn>dT{d=+yvTibct{Sd?s5Q{{z_BVXqW z%X~HD3Za(D*5*`3wiF_P^FBp+lcF3RVe-BzS1Y>y-dt5rm8;rS-F5-2<*JLF+_2HZpmMrJe@0p^l zc*z|xznuYpXSW|?WGrp>qm9OY)qc-D$e-KrmoA$Bw>EtCOU79Ze3Q$It&^*i@=reH zu|V{hYA5~^cKr?;lD^xv51qZpwx3nnwr~HX?{i7}zRCysTQ+|7h5k?3`BnbXDqH`) zJv+p~{kz4tZ2tQX{aMQH@8f&&3)}y>;FJGo|34OZrPvR9ptxB>lhHcOdbj(tm(`!HfL|GC%nbsC>eU{RavQ`FZ^R zGQkhy|3+dWu z<>^d8r+ksPE3ffA2K>{YYcO>2zR;lH6U;zgcc2DXTL&PU%@tZyQdX#B<$LUKcytI_ z?Au>g+cPj|BYyREjExP`fO^+hBRuxnSlrR6qQtLk6L{=ML}Y{mcdUQ!!Inpj@MFZ~ z*ytwpf#0Zpljzv(+=b>U{FA=E;Yiy?0IzTVLCZ#<`Kht7){Ko*-#Yd(3i`HC;#c(w z^!1Gl4+^??!U+BBYcOyqWHUQ9Rzo%qe2v(vV^Pq#2;V#Kq;F&pr+~@5m?xC=Li;80 zL9%bNB7C2~K;KA6F)-j{fCKj$srRU>vHnVS8a48dJ;isG=y5fDLjwaN7#sZv*gTep z3Kh09f%=Ua)CW7U)49JY{F8ye2MwV6`W`tjNmA%N;xu~PvF$#Ufy=Y4Gens?hbE!gI+LE^e=kIO0>@Sy?bp71Gd*5n>}_zN~Xb*h;AwL zIQ6N$(LNlOZ9Hv|Hdt9&u3fWwCDQysjQ<&WoaywgeNTn$@v^bmho%^EYaHD=3}Ez$-u(2Jg`Pqj=hpIzh=$*f3hbBVod zxi(no-*@1TWjnuVsdYJK(s0DkB)&DL$&wr$sWkoHo$ zO+J3U0Re%SfZkph#XV-lE3J~V`LVuUH8g<^`+tWHUAyQE9IUOq)WXVZ50dAeWtBhc z!2CcT@21>5(7Sar7%%{~1LLv7h7CcjrK{?E)_Ppr!q8BwW*s|rgo#y!Z!&S>G^qNs zXHVIv^|}1(`G$rr8E9-g!5BXJCML$lqm4(Km`t4Eh~%`zWvgl#FXF1s{K)7atr3i6 zY&>z=jG43M%yFDEXU>!^$bk;1O zySTZP?m!)L?Li|)kC)gp!StLtPFui*TgwWA!OqsLZXQ}CN4RR$s-2C;BN7EYl)N~B zXP~=Pj;rLzt-E`;S1ws0u5xqud^8(0Y}};j)8~Mbty_WR=75(;6_>5s9c){cErqTc zj5@VyR;^m4di5Huw6tw)9kek@RjXI4S?ebi!Z-4tYSygwH^nObRF(f%Pvs+(@7I4X zivOgZs*cv6^EQ{+zw(FA+G_$d09>2Tzu8ZT72kh669&%z%Tyl3e+CQyECH+p%muJN z82f>>1^m1HVQrt~paQ=BPb4)o(hN48^<6r5N$S;P5SN9Rt9)Hu-H)&gtadFIhs-(b3ZHfqik-8sF^k9FcJSFRilp&ToxR@I|XKl9UCX1Cv~{NTQo>)E9jw3&S>v4&=!P%!KW zFb42g@ECqIRjg34zP6V33kQ39x)~cQZRFes=AU`a1;03Fmyn&EO^79@OaR-|`I>$C z5UW5>pFSnna0oH*gxD7{7&IcU?d%f@ju-tF&&6f%xlsLv&tYC;!!>uo@D9Kf0QceV z#-X{9k&%?;ojZ4>E&clSYm$GKJI6id=44Y|b~DJUf+g^~fO zDfo@+^py8><;FuADcAg51-(nopvk-7_ht{0f|B=UEjL^!XfO=E=w{_W>%BFh*t6X@f2Dg9+t?Qs6H{vUsV z=~;kczf10fT17QYyt4|}hbJLEUXB6#{qfo&*B7j#nW^vT*yT6WU;3bak}uCE_KBV5 z5=S0hM`-xA6zP}A^myJFxMUH|ZzcbEx!H7V;~?pm$-J|lC>vAYvk$c@T|4VVcJOa?D&gO%^0VcB*bNsH za~@7BNH6d#@V5oJ7Ck#Gj}A*B--Bs>FaJ`^Jbpl5)0{eWYQbHs{m-92hyQOpJ;A$( z`RDHduum{QpRZoMruSH1o+P{=e9HxLSNg!J#+c`mig&)pbJzlY(W-RHeV*h|#q;O6 zE%-m_W-8HBvkPhT4#=g%d~G}L>~pZo`y<}t6({%(Yr=P`faeV20Oc64A6t5Q8of(= zM{iz(_m{8e1@;R(J};lg)2nAs$m8@A>b)tm)O=Uq!n)J*5e9dFo4afHpQnQrv|M}f;_+*!p^Zj$#!xo3K z@`Uf=Nd7N9$dl_u$u{fvn7n7cdxj`F`J(j$)f4r&>{LV1gl1=yUu2rRL zXZO&-wS5WSVlU%qPsUE$m_&48nQJV z{>`8EKD_7Qc@!1@sSnI+Zf24M72llizmiGa9hGaZN(PAecu}dgh5>jlHScjP)6YNu zths2>qJp=OxgsN({)|W@e9H+wo@r9j z2WgkL5AEN-k6;6p-}zwQc$Eyf4?V!whBG;I?O8shV_D+f5flBlR5}x{`#wU^eXxO{Bc6RLH%w%x}it zq+78u6nG(;#&3TOfA$a5$Ns$p{i58!F_C_SFSC61O6=*GFO?rXfA?gvw}MReWMkh3 zd1IdOd@uRD>a2VH4)ITu!D6ky?z^A_$u$SO{zY=nhe*$g(jrX)N-s$iA*KWc2qZMm5;j^4XMZ%C zYih2tuqc>!2(cV^r!xPCuB3qf6p8`wH*UmG^tEdg6$M}XNcK&?LXi>SwEx6avhaCA zD-Oidiv0|aY5CsAwAA|vE%st~Ouz4WOpA6ulJMKE$Fz9YT^YmF(?JWW3$Y83IqL>jq2I8M z78V{Z_1w#0=jqDDvvlcv5Ml}f>3qm33Jp3z!KeM{%!%W4%KsPz_#GjC-@|nL*g^6? z;!WG!cGCDQk1*d<^5-0Tz?JtCe(q<6uR_Q;hi}f8Qq1F`b;}l-8?CJhRvgcv7M5tw zF`FVDWl>goa*@m<5%YD0!o$Hk$3Z|xKY#8VorQmXNJucjl!w@W)AGAb0fv(UAkYY3=5H)Zc-hF=f0Q$L#6iIcQ@V^aSrFeolFf`Il4MHf=QR zHd+^$L-(0`D34;F=iqE11G-@nWF7(DS>{E2!*~B2^B!_m##5+b8cv)zLH_=J#BmOP z{`n{2+j}zZlH)559`GWwt!JpaeR^@MAMf?LZ_1@HW(TRRdVBU(915uZFEft{ZQHii z+-PH6@Cq?%@W((r$1aM)dc*q%n1mtoOG=razd)f<<{?t%9E-u<%3_%xhs>GpW516ndb@vpU0g!6DV{39gKOybB5)v;$6!8&|zgv3%v|YrVSf5$i8ts{)QQ!$HBjf z_U>|}T|2gs+xG1k=WVpzbvxw081ip;4*ZVJLQ_gw+aiD=bwC@%ZblH`8#oZ4$6DFQ>RXnhld9_I6BJnYV4_qVd)=#&Ybd_KkJ>b(Ac*SiaNLQ6|abKACU9D*s6iob{V z?_wSI!#&<*DN|u#KIP@|`lO6w=4V`~Cnw|lFa>8`$?`mo&jIdW4)QzWnD0^fEjZZe z<@}qE_#W)nW#2f~2=n&=&b@tchU@}%xF39G4G+)nONbHD+`fH#G5^ddKfhZLe>B%> z7ukCpCI7%n6d4^u_N!+Hb9 zDBVX~(GBPc;o+CCex1Ryv72DNm*0t-J9lml$6w*wffvCwpHcDI|92(CqBp}_mHhL} zcn?1I`W&MgLp`XxaX6_>j-tx5?jWY;Hfb)6p`KPTG{HHFmTW&qP6y7CUvM~Gx)LRI zf`q4!=oR8zU*T-=)w8FR@D#ek1L!-q! zr_sAJX#CDsG{y57&D-;kmhZSktKCk}=KVqB?sJlk`k$g59_}<~;J^>i!Fk`N4)~Y$ zKESU4ClfDtQWTxTzQQ;BLP&Q>5NTQ^Q!|TK)M!-_)wjr?pDgkagH}il*AX>AJXo`h zMEE{1bw)f`cUPkR;D7LLWlWec;+Hs1YbIitmIW$dIdb#BLb3?V!@1B0vOkqT%eVNE zhK9y1@WK3lakhYa-%Ndfr-Xrwurg$29fM^6@Bx1PWcT4!L z78wCJUTrMy^Y76(E@R+WHs*cU9`KLYuW=|d0Uo}!MfMj8ioxzeA#DyP+8Tj4FT`N& zjLxI}BgSW7?b!=P+5T7in+%sOEZe0^m!(*HWUOfx>?-N+U(m`;`$^w5od$!i!QMoJ z7`%vvARmc-j6a09w_`-Jv9vBieAo)e)dI0+R_Abb3|N02-#j?0gp~m)wA?S1{s0ck ze+};2TtE!j6(aYD0`j?)PnJ6Zsd1y9uY)zVGq(YJ*RzY*x~ll@Of}+OD)^p_Z&@w?-%G%c8RW@w zwuZdzFDYf}dbN;tL>AC)@OB_Jk0$-TK1W+e@7^p-m<^aWn*faC8I@0aujSHF-~=ZW zlBLTbs#mw}WiZX}FV-E){!<6=+&T{*Hsr4!`u*bcY#z`6%nN*Ln}$NpBan{)&l50D zrh@00koR1~FD^cf`4Xg@2kS9cY{B%1YcOj1 zOY5@=a)sP?M1uDld2|$W=k&t@f_Ubde*RKOCbi4Pl)z#~{MX!(H-d_DjpB_A6{;d%+R=gQKXLYL4e5;RB zS2$-cu-R9zVyiz{?Kw}jhoi~m#65gx^`*S-(zW|35b1(5${&XqO^IFNc!XxIu+KIz z{o~!hVPit{f9<#J*Ix}5wr}6AGxkAs;YY=`t$+0$pzO$Z{2e;ds6s!(!PR>9=vlK< zyViBObZp-O^!tq%JHd3&2%|On1_SN7>UDGM)u;c?k;cG|GW9;?W*XhaupvczATIAk}~HwBj$tst-dEOiuXZ~Pw93(zgD%&_*Q7Y bWR6SaS3XPRTwkUV`9<8|b_hYMmdO7P6G#4Z literal 0 HcmV?d00001 diff --git a/release/windows/installer/00.sconsblender.nsi b/release/windows/installer/00.sconsblender.nsi new file mode 100644 index 00000000000..ff7a198d0b9 --- /dev/null +++ b/release/windows/installer/00.sconsblender.nsi @@ -0,0 +1,419 @@ +; +; $Id$ +; +; Blender Self-Installer for Windows (NSIS - http://nsis.sourceforge.net) +; + +!include "MUI.nsh" +!include "FileFunc.nsh" +!include "WordFunc.nsh" + +SetCompressor /SOLID lzma + +Name "Blender VERSION" + +!define MUI_ABORTWARNING + +!define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of Blender.\r\n\r\nIt is recommended that you close all other applications before starting Setup.\r\n\r\nNote to Win2k/XP users: You may require administrator privileges to install Blender successfully." +!define MUI_WELCOMEFINISHPAGE_BITMAP "RELDIR\01.installer.bmp" +!define MUI_HEADERIMAGE +!define MUI_HEADERIMAGE_BITMAP "RELDIR\00.header.bmp" +!define MUI_COMPONENTSPAGE_SMALLDESC +!define MUI_FINISHPAGE_RUN "$INSTDIR\blender.exe" +!define MUI_CHECKBITMAP "RELDIR\00.checked.bmp" + +!insertmacro MUI_PAGE_WELCOME +!insertmacro MUI_PAGE_LICENSE "DISTDIR\Copyright.txt" +!insertmacro MUI_PAGE_COMPONENTS + +!insertmacro MUI_PAGE_DIRECTORY +Page custom DataLocation +!insertmacro MUI_PAGE_INSTFILES +!insertmacro MUI_PAGE_FINISH + +!insertmacro MUI_UNPAGE_WELCOME +!insertmacro MUI_UNPAGE_CONFIRM +!insertmacro MUI_UNPAGE_INSTFILES +!insertmacro MUI_UNPAGE_FINISH + +!insertmacro Locate +!insertmacro VersionCompare + + +Icon "RELDIR\00.installer.ico" +UninstallIcon "RELDIR\00.installer.ico" + +;-------------------------------- +;Languages + + !insertmacro MUI_LANGUAGE "English" + +;-------------------------------- +;Language Strings + + ;Description + LangString DESC_SecCopyUI ${LANG_ENGLISH} "Copy all required files to the application folder." + LangString DESC_Section2 ${LANG_ENGLISH} "Add shortcut items to the Start Menu. (Recommended)" + LangString DESC_Section3 ${LANG_ENGLISH} "Add a shortcut to Blender on your desktop." + LangString DESC_Section4 ${LANG_ENGLISH} "Blender can register itself with .blend files to allow double-clicking from Windows Explorer, etc." + LangString TEXT_IO_TITLE ${LANG_ENGLISH} "Specify User Data Location" +;-------------------------------- +;Data + +Caption "Blender VERSION Installer" +OutFile "DISTDIR\..\blender-VERSION-windows.exe" +InstallDir "$PROGRAMFILES\Blender Foundation\Blender" + +BrandingText "http://www.blender.org/bf" +ComponentText "This will install Blender VERSION on your computer." + +DirText "Use the field below to specify the folder where you want Blender to be copied to. To specify a different folder, type a new name or use the Browse button to select an existing folder." + +SilentUnInstall normal + +; GetWindowsVersion +; +; Based on Yazno's function, http://yazno.tripod.com/powerpimpit/ +; Updated by Joost Verburg +; +; Returns on top of stack +; +; Windows Version (95, 98, ME, NT x.x, 2000, XP, 2003) +; or +; '' (Unknown Windows Version) +; +; Usage: +; Call GetWindowsVersion +; Pop $R0 +; ; at this point $R0 is "NT 4.0" or whatnot + +Function GetWindowsVersion + + Push $R0 + Push $R1 + + ReadRegStr $R0 HKLM \ + "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion + + IfErrors 0 lbl_winnt + + ; we are not NT + ReadRegStr $R0 HKLM \ + "SOFTWARE\Microsoft\Windows\CurrentVersion" VersionNumber + + StrCpy $R1 $R0 1 + StrCmp $R1 '4' 0 lbl_error + + StrCpy $R1 $R0 3 + + StrCmp $R1 '4.0' lbl_win32_95 + StrCmp $R1 '4.9' lbl_win32_ME lbl_win32_98 + + lbl_win32_95: + StrCpy $R0 '95' + Goto lbl_done + + lbl_win32_98: + StrCpy $R0 '98' + Goto lbl_done + + lbl_win32_ME: + StrCpy $R0 'ME' + Goto lbl_done + + lbl_winnt: + + StrCpy $R1 $R0 1 + + StrCmp $R1 '3' lbl_winnt_x + StrCmp $R1 '4' lbl_winnt_x + + StrCpy $R1 $R0 3 + + StrCmp $R1 '5.0' lbl_winnt_2000 + StrCmp $R1 '5.1' lbl_winnt_XP + StrCmp $R1 '5.2' lbl_winnt_2003 lbl_error + + lbl_winnt_x: + StrCpy $R0 "NT $R0" 6 + Goto lbl_done + + lbl_winnt_2000: + Strcpy $R0 '2000' + Goto lbl_done + + lbl_winnt_XP: + Strcpy $R0 'XP' + Goto lbl_done + + lbl_winnt_2003: + Strcpy $R0 '2003' + Goto lbl_done + + lbl_error: + Strcpy $R0 '' + lbl_done: + + Pop $R1 + Exch $R0 + +FunctionEnd + +# Uses $0 +Function openLinkNewWindow + Push $3 + Push $2 + Push $1 + Push $0 + ReadRegStr $0 HKCR "http\shell\open\command" "" +# Get browser path + DetailPrint $0 + StrCpy $2 '"' + StrCpy $1 $0 1 + StrCmp $1 $2 +2 # if path is not enclosed in " look for space as final char + StrCpy $2 ' ' + StrCpy $3 1 + loop: + StrCpy $1 $0 1 $3 + DetailPrint $1 + StrCmp $1 $2 found + StrCmp $1 "" found + IntOp $3 $3 + 1 + Goto loop + + found: + StrCpy $1 $0 $3 + StrCmp $2 " " +2 + StrCpy $1 '$1"' + + Pop $0 + Exec '$1 $0' + Pop $1 + Pop $2 + Pop $3 +FunctionEnd + +Var BLENDERHOME +Var winversion +Var DLL_found + +Function SetWinXPPath + StrCpy $BLENDERHOME "$PROFILE\Application Data\Blender Foundation\Blender" +FunctionEnd + +Function SetWin9xPath + StrCpy $BLENDERHOME $INSTDIR +FunctionEnd + +Function .onInit + Call GetWindowsVersion + Pop $R0 + Strcpy $winversion $R0 + !insertmacro MUI_INSTALLOPTIONS_EXTRACT "RELDIR\data.ini" +FunctionEnd + +!define DLL_VER "8.00.50727.42" + +Function LocateCallback + + MoreInfo::GetProductVersion "$R9" + Pop $0 + + ${VersionCompare} "$0" "${DLL_VER}" $R1 + + StrCmp $R1 0 0 new + new: + StrCmp $R1 1 0 old + old: + StrCmp $R1 2 0 end + ; Found DLL is older + Call DownloadDLL + + end: + StrCpy "$0" StopLocate + StrCpy $DLL_found "true" + Push "$0" + +FunctionEnd + +Function DownloadDLL + MessageBox MB_OK "You will need to download the Microsoft Visual C++ 2005 Redistributable Package in order to run Blender. Pressing OK will take you to the download page, please follow the instructions on the page that appears." + StrCpy $0 "http://www.microsoft.com/downloads/details.aspx?familyid=32BC1BEE-A3F9-4C13-9C99-220B62A191EE&displaylang=en" + Call openLinkNewWindow +FunctionEnd + + +Var HWND +Var DLGITEM +Var is2KXP + +Function DataLocation + !insertmacro MUI_HEADER_TEXT "$(TEXT_IO_TITLE)" "" + + ; Set default choice + !insertmacro MUI_INSTALLOPTIONS_WRITE "data.ini" "Field 3" "State" 1 + + StrCpy $R1 $winversion 2 + StrCmp $R1 "NT" do_win2kxp + StrCmp $winversion "2000" do_win2kxp + StrCmp $winversion "XP" do_win2kxp + StrCmp $winversion "2003" do_win2kxp + + ;else... + Strcpy $is2KXP "false" + + Goto continue + + do_win2kXP: + Strcpy $is2KXP "true" + + continue: + + !insertmacro MUI_INSTALLOPTIONS_INITDIALOG "data.ini" + Pop $HWND + + Strcmp $is2KXP "true" do_dlg + + ; Disable App Data option on Win9x + + GetDlgItem $DLGITEM $HWND 1201 + EnableWindow $DLGITEM 0 + + do_dlg: + + !insertmacro MUI_INSTALLOPTIONS_SHOW + !insertmacro MUI_INSTALLOPTIONS_READ $R0 "data.ini" "Field 2" "State" ; App Dir + Strcmp $R0 1 do_app_data + !insertmacro MUI_INSTALLOPTIONS_READ $R0 "data.ini" "Field 3" "State" ; Inst Dir + Strcmp $R0 1 do_inst_path + !insertmacro MUI_INSTALLOPTIONS_READ $R0 "data.ini" "Field 4" "State" ; Home Dir + Strcmp $R0 1 do_home_path + + Goto end + + do_app_data: + Call SetWinXPPath + Goto end + do_home_path: + ReadEnvStr $BLENDERHOME "HOME" + Goto end + do_inst_path: + Call SetWin9xPath + end: + +FunctionEnd + +Section "Blender-VERSION (required)" SecCopyUI + SectionIn RO + +; Sets $BLENDERHOME to suit Windows version... + + ; Set output path to the installation directory. + SetOutPath $INSTDIR + ; Put file there + [ROOTDIRCONTS] + + SetOutPath $BLENDERHOME\.blender + [DOTBLENDERCONTS] + + SetOutPath $BLENDERHOME\.blender\scripts + [SCRIPTCONTS] + SetOutPath $BLENDERHOME\.blender\scripts\bpymodules + [SCRIPTMODCONTS] + SetOutPath $BLENDERHOME\.blender\scripts\bpymodules\colladaImEx + [SCRIPTMODCOLLADACONT] + SetOutPath $BLENDERHOME\.blender\scripts\bpydata + [SCRIPTDATACONTS] + SetOutPath $BLENDERHOME\.blender\scripts\bpydata\config + [SCRIPTDATACFGCONTS] + SetOutPath $BLENDERHOME\plugins\include + [PLUGINCONTS] + + ; Language files + [LANGUAGECONTS] + + SetOutPath $INSTDIR + ; Write the installation path into the registry + WriteRegStr HKLM SOFTWARE\BlenderFoundation "Install_Dir" "$INSTDIR" + ; Write the uninstall keys for Windows + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Blender" "DisplayName" "Blender (remove only)" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Blender" "UninstallString" '"$INSTDIR\uninstall.exe"' + WriteUninstaller "uninstall.exe" + + ; Check for msvcr80.dll - give notice to download if not found + MessageBox MB_OK "The installer will now check your system for the required system dlls." + StrCpy $1 $WINDIR + StrCpy $DLL_found "false" + ${Locate} "$1" "/L=F /M=MSVCR80.DLL /S=0B" "LocateCallback" + StrCmp $DLL_found "false" 0 +2 + Call DownloadDLL + +SectionEnd + +Section "Add Start Menu shortcuts" Section2 + SetOutPath $INSTDIR + CreateDirectory "$SMPROGRAMS\Blender Foundation\Blender\" + CreateShortCut "$SMPROGRAMS\Blender Foundation\Blender\Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0 + CreateShortCut "$SMPROGRAMS\Blender Foundation\Blender\Blender.lnk" "$INSTDIR\Blender.exe" "" "$INSTDIR\blender.exe" 0 + CreateShortCut "$SMPROGRAMS\Blender Foundation\Blender\Readme.lnk" "$INSTDIR\Blender.html" "" "" 0 + CreateShortCut "$SMPROGRAMS\Blender Foundation\Blender\Copyright.lnk" "$INSTDIR\Copyright.txt" "" "$INSTDIR\copyright.txt" 0 + CreateShortCut "$SMPROGRAMS\Blender Foundation\Blender\GPL-license.lnk" "$INSTDIR\GPL-license.txt" "" "$INSTDIR\GPL-license.txt" 0 + CreateShortCut "$SMPROGRAMS\Blender Foundation\Blender\Help.lnk" "$INSTDIR\Help.url" +SectionEnd + +Section "Add Desktop Blender-VERSION shortcut" Section3 + SetOutPath $INSTDIR + CreateShortCut "$DESKTOP\Blender.lnk" "$INSTDIR\blender.exe" "" "$INSTDIR\blender.exe" 0 +SectionEnd + +Section "Open .blend files with Blender-VERSION" Section4 + SetOutPath $INSTDIR + ;ExecShell "open" '"$INSTDIR\blender.exe"' "-R -b" + ;do it the manual way! ;) + + WriteRegStr HKCR ".blend" "" "blendfile" + WriteRegStr HKCR "blendfile" "" "Blender .blend File" + WriteRegStr HKCR "blendfile\shell" "" "open" + WriteRegStr HKCR "blendfile\DefaultIcon" "" $INSTDIR\blender.exe,1 + WriteRegStr HKCR "blendfile\shell\open\command" "" \ + '"$INSTDIR\blender.exe" "%1"' + +SectionEnd + +UninstallText "This will uninstall Blender VERSION. Hit next to continue." + +Section "Uninstall" + ; remove registry keys + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Blender" + DeleteRegKey HKLM SOFTWARE\BlenderFoundation + ; remove files + [DELROOTDIRCONTS] + + Delete $INSTDIR\.blender\.bfont.ttf + Delete $INSTDIR\.blender\.Blanguages + ; remove shortcuts, if any. + Delete "$SMPROGRAMS\Blender Foundation\Blender\*.*" + Delete "$DESKTOP\Blender.lnk" + ; remove directories used. + RMDir /r $INSTDIR\.blender\locale + MessageBox MB_YESNO "Erase .blender\scripts folder? (ALL contents will be erased!)" IDNO Next + RMDir /r $INSTDIR\.blender\scripts + RMDir /r $INSTDIR\.blender\scripts\bpymodules + RMDir /r $INSTDIR\.blender\scripts\bpydata + RMDir /r $INSTDIR\.blender\scripts\bpydata\config +Next: + RMDir /r $INSTDIR\plugins\include + RMDir /r $INSTDIR\plugins + RMDir $INSTDIR\.blender + RMDir "$SMPROGRAMS\Blender Foundation\Blender" + RMDir "$SMPROGRAMS\Blender Foundation" + RMDir "$INSTDIR" + RMDir "$INSTDIR\.." +SectionEnd + +!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN + !insertmacro MUI_DESCRIPTION_TEXT ${SecCopyUI} $(DESC_SecCopyUI) + !insertmacro MUI_DESCRIPTION_TEXT ${Section2} $(DESC_Section2) + !insertmacro MUI_DESCRIPTION_TEXT ${Section3} $(DESC_Section3) + !insertmacro MUI_DESCRIPTION_TEXT ${Section4} $(DESC_Section4) +!insertmacro MUI_FUNCTION_DESCRIPTION_END diff --git a/release/windows/installer/00.unchecked.bmp b/release/windows/installer/00.unchecked.bmp new file mode 100644 index 0000000000000000000000000000000000000000..6d3ff5cc58cae80915bb610242fffa87b597f919 GIT binary patch literal 358 zcmZ?rO=DyLgEAng0mLFu%*en37XJVwmAD~T0LTX6|Ns9p95`?Q$f7b3gaVMUAd7$i P?7YFuMs_pA$rvO6PqYeW literal 0 HcmV?d00001 diff --git a/release/windows/installer/01.installer.bmp b/release/windows/installer/01.installer.bmp new file mode 100644 index 0000000000000000000000000000000000000000..10fb01454a4d2d41e2069d6d0025f26c7f77cc85 GIT binary patch literal 154542 zcmeFa2XtIVb}eeJ_1E{TdCT@+^F9B~*c0A!nD4Ql?XjQjkwi&U7-eac<0xwss7Okp z0u?AmF#yat2M{0#f&>VF2qZ`lIp^2_8bAZxjhquHiun7SQ&oLC00b#{=9AM`Tg7v$ zt8e$MT_@D3x{X`z>)P~3eEcWMzsLV!`2V^;{-Zzo<3IWV*HdxRf0O@p#YFH3_CT-) zf;|xIfnW~=dmz{Y!5#?qK(GgbJrL}HU=IX)AlL)J9tie8um^%Y5bS|q4+MK4*aN{H z2=+j*2ZB8i?15kp1bZOZ1Hm2$_CT-)f;|xIfnW~=dmz{Y!5#?qK(GgbJrL}HU=IX) zAlL)J9tie8um^%Y5bS|q4+MK4*aN{H2=+j*2ZB8i?15kp1bZOZ1Hm2$_CT-)f;|xI zfnW~=dmz{Y!5#?qK(GgbJrL}HU=IX)AlL)J9tie8um^%Y5bS|q4+MK4*aN{H2=+j* z2ZB8i?15kpSbE^XG!9Gipm^o=z+?=6t&hnXnEJ`?*);gpg~>iKSRb$lto^T9y@Y?Q zZ@&!r50@rnP9z+e5mzyM3&n$cl`$_ zpa-nof{sGZOZN)5V`F2ZqoX4uBg1?Qc^^`VSJ6few4Z!XT>KTh-T%M)bTl`D8pp>{i4tx*}`B3Xe<0W~!d=dr&zQ5dv;oXq_heo&DuMBu$S(Klu|4-ETGZLfGCB<% z2y#JeOG`^rQ&VAKVSRnQ&HF%2LqkJjW24<}N1Nv6W{1Pk%7+;d7!TIN)Jrpzc#F@0 zPm}`}#DOd0z(?SNaNra1x$@ES>Cymi!PW3t7zz0D!aG#nkPgOirx?}#j9-;>TZtCe zj2^(qhYG+9LMfmf=qNCPPDaOq+v@7-`Sa)hX+1(W9WgsHmu< zq@sUXoA8)$mF9+F&2NW2_p|Mbj~!4db|dv24;OD6b~QCnFjoA6)^WVLYK1P!Q+~ z`VAeJpP&EWgAe}Q-~C-kNXU-uI~FZk`0&Gz{Oo5x1NC>^b=L4k&%&+m6es9 zot=}DgZ2e{$Y1~?)&s)>2VRmkXpAGz`^e=3m%@Q-;=si-Gc(iqICJJqT3Xs^eLzMH z4m3b}Tn!fo`xq@4Z@3GLSd3d}I>s<=(8@SSzlwDnTpJ$^|0Nm?qG9OZMn#>W5$Gkb z431)BWB=t}{^go$u35Nf5qdHeFq~BMn*<%-n{wq&p&_Qfd~HPZ~g}Qe*5jW zzx(dH`}XZS$wz8x>ZwzwKnS?79;iV*Ud4fiC-_LwN3!Ke(nn%q;_>6hfBn}#`SDM{`#bNvvvuoM3>6&ce>ouIU7+m9 zkt5O3(V!+ODhl*rJ{*<`0s0U3+Ca&L&NAj=zGjj<~=+j;$X!3_3OdH z-FM&pKlr%imRnwb{q;3#)I*F4(KUj0BEAmv0}xFWy_YK*#{qe{LK67@A)`!=E8>SmJeUMVstvVagqJ5kCUI8 zv*w*S@52b-gD}kC0^l{kIBo~`2qy(s1wW2K4x0uS2K#2FW>>U=Ta_9&B3#Q13j-T2 z40nyuj$k-GKK`Hn>7Q=6;f4hZ7aj;ZP+C%op5YL?0wbKXS^fjd=Tv$PzToUQWnj=( ze2k*^>T2uKGcsUEckkYV>qLZyuU)eihW)nNZu`-XegxjHz4qG2AAcM!9!?*OnB&t= zKgAe(`|YbT|OdZ8s6@>=Jd?=c6Q5Zy>P#qo~!a%C7sYdL4IO^~o;yvs@_<=R6*UWlt7R>u! z{^ehS_y7FQ|3r-U>Z`BLnKS2&H{N(+*8E%M<#<>F%K?cFSm~$xw|rLk?77u_OYdDNbO+=bj99sbHlf?!eB;fKl_4o7PE^pu zmI@Z=1UJhm=5w;b!P?9T)iKg&kW9zO$S?sG5n3{YR4G0JY14s${(=5}x66&|!FwVe zgU5zxh04Ptzx?vcFz*Nte)Qv?{@atQu3g&eAzHYb96j^mT6jBLFsJ0K+7_P9pAPA}_{u&d{KlzhCfv)Y^xzpsVK(R%x!kt2+#s2%) zZL->YAOQ`c2M5)Pi4cvCz(FiC(Fg@`AhQ9p*@@Vwy#wy!P<;CRA&r6A)MS10S8x2h z;>q8>2Ty@$5R(GT0WrS^-AM1?PDQ(?Hs)6x-QZd%gQ=CtHM;yyzVj!T6(NL1nv*H6 zrgSGH{7Ypuag8VpF&KqmY`4cohlfX?v)$dKs7v|ASsCIS zTb&IZ1wO&P7;e^QWw(WBQD-5VR;*mE^6L7hx48W|y2jfS`!}%GNaJa~<;MB7PrvXg zj5&gHOblf@2Hy>zg4s9bo`}rRA-Fr}0zwgtaA=2g9q7JNRNHWER2!xjUKON#=R4mG z3q!hNKe!`y&7n@1Yuq_j2+1{%f>2CR!xGEC*k7`6PwvjhBxEvS5Ai;i+YLolcDtvy zhiE3F-PPG;)R~BOyPKMuJ_&EOvZmzaqthhL8lro>Wy+y)>)gZ_Uwjc0J!EW3S3iA@IGxT)`c_q&)4h3(&8Q(IF@;DS&1 ztOjo(* zcy_tbrIDu_Zdf_pBndv~@f~9e63*_)`6|BRe434rP;q`=?pKQw&;DlDxEUu(n9|YT zJ8Ko@cSzbGl_wK13{+Th+&9KB0+_2nwXJkxxJq6H-2LgF{wb1O2vFF zhVJR`a%0Hoheyw5H=Z9mH>m|Z`_)8#^VeU*pS^kYw6ZQYEVRRtBax0&s;IV1x-t1c ztY~8LD_yk%(haWRyg)bD4S1lJHP7gPpfjdXj`KD0CwJ%@XnXjxb36F?Gh6-Kha8MpntF!E4a@I98-M3y@2Hz`KZ11|$=SC;j z<;j%%tFI?^WS&!(wUFyG0Ipx`eD38pu?+(WLoB@^AVl{(RL&G2jPlv4RzM3uz?3RU&PNowz^^Co+EMbaoD>cnF<8$ zu#Grc+u9=2nx>!_FI~5MbXWFQld(CS`q;9st`E70J^%IWT?oiw#=$ifz9qE+r{&|a zuUx&hc9c=@KmYSTkBr1p@*yzG2k+@JJG<%|@Gfx82~SFSu1Xr5nk>9}SEzgWwqw!J zN3eE=4s^7%w6?)`w?deEz%|9&VZ+y?2G-}V#z$JK(uxvRrR|-avh}y=2RlnSyKU%u95{|Ff=$8u{|z8aoG~4n-j{@j7TL zA04Uy=Y7aJv;Vy*$n}4zE;q`01z3seR*VM7ne$M*?~9D3 zOP9i+A*jG22=c=i;s_wI2!i`Xh=SzN)e)PSKKYC9fB$IAQEX9=o%hYy*AKqcHhiKV zEn&Bb=AIr}!9ZRNJgdobM}AG`(>qkOW}O`y21U4aW%v9IG4r>cQ1uqYmzvwwj`fXP zFy9J7kF#dov;WP9&?ziAS|0fLe}8@66WWb`HSzGaF`sW@PG>H2V{ZoHaAUx&DRIL! z@=jM)O5ECqKJxd!|9u$PxVU4@&2Uz@UEhPcopPQann>=XY#34`NO^Whj>OjNo)^^% zq9^5=nZ04fz@wqHGgh!2uy8H!dS=h~dGEwYR^(@fS%1N245-s5{X2u#e?a92fB{THWnm_WLbHZ)HZV4 z$c4GEItkOa?PTZ8t0uAM7G^!J+*-L}^qoWFR*oPaU3O1kLMIQ>&^|YMq4hfJPEG2v zXD;i&7D^<|utx=nK3K4;V_DOB`#$mye(*!A?qPEd=0xgfX<-4(J0PJw>och|J*p?_ zOeAwEjETnd8IN-%7dju@q-WpWRC-Kz!1@)V?;Z9E%rMW2`0U!t;QI9Lx2-q0C4Ew^ zA6iy|ZHLIBV3i(o1PoUnrM?o^G_CjUFaPj|Ka7u$!?Xyg4)q`Yp%ZoBEy_Eql`2}R za)M~qXO$#DK9n6mNo~u!5k1Byl3*p*DqCaY<)g2KkAH1-*B35CExhG2xXw86q4geD zrucGg9L;MhQ{cR?6A4o-_$}meVZJ0Pv!+nstgq-SinTYel^05#l$;FKFt$0rCI8|a zHLYk&+N`}Zt1}U;8arA^{h4SA>nL)!uS#h5OveK9>r=UW^nop72&JqCl4F;_bxlT? z^&)Q^)GMCWp~dpN_3@ZlL#biCaWAq52_c!8Y8g)rx~#IK;9qck(bPZj&ZB5`f{Q4DxoAw^T@)oSOe@NzIy`k6U znpd=dCvuV!lQ6TqIYY_jMxr3)~md5*MF<@Ei9c)*Jh6 zpwz~CV^!#Cvfk1y#C1{FHWSSeJI&5$CQjKkuCc!Pau^wK za?pNeWcKC)Osg?UF{3bU+9Xe|KI<*rf=6rd2mtbgu+!==0-vLq5KXZfjJ68HT8wuF z(G3lavPcGfCYG6K>_Drou7N|`m14hjl~?}UFz%Do+MDC8+7lDaC=Kj+_ zSF<4+LW(H0$(vc|#=6X*xKsFgqR|qMiJKPdElPd$={2~90Z&g)r#W+=1Kvs^HuBCC zg^_!PMzB8X#jpli@#g&vq|U-JvW_4cj~C#9p<@|!Pj8!K-;uDuJa|+Z~r#+RBC2sCW38>x8)xeM85F#1)7T~bta>Yq&Y8(D7#I296&VbG80|P z>Rer2$xo4BO#%Cg%gf6Oi_2y4+RS>Cc3W70v3+XiSo?sNC6|6~DL;Y8JnW-?+w#hP z2fy29{U~z&_32@AyB+j&q4mIq7EkzXy*NATTSIyiQgbmF)gXnR~b|bKi5st%p z*{eXt&tl*w50Fyeq!{hhr{ow)OsYxjM2w>CHhQSpu-w?d4x0C|fM^(Q(rDgWPU?&& zxQJ#V8vBuuo5ByQloS_lim$&ZG_XB4h8=V_cL(lgq`S|K4vvrXpBo!OzQw=)dxkH} ziJEHVdQo@~GDKV5^wmc+`s(LD`x%@y791(jjocVg-jpVjR2j-HI4{_3 zSrXBcDoYr~G_%_qqVL1y6iy}`}J-DIQ#7n+v&f53D=CRXt zzROVAU(6Gt-P`ZH-(Hh?6w4B;-f+I)#|2AFa7-IKgX}k z(lgS}q^IK}($1veS5!`)q90B871n+3+&QJrmRVJunp7bQBbGS|BfDK(T!KBrv9Yn(tcX45`|(7{e*O&& zJTkWrzpsOz(ojF9v1`|^cQ$0*xRUZMifiLrA!zxAkkJp0oQ*F(Z|}YUM{M$_5Rhkc z_Fp(zdmfJo+zOVxRhX`zFM^kDU)`6GW5=rX)BSjMec)%ofs8g&1|KmKE8MrL7Q zA#FJ6?P+!QKE7=POZ@0$yOWl!(I=$N$~jY#gq$<^W~0s=hE-I;TqmYxzq6&}kMVf# z`J>y%Zk}wHkvH%6tnE!LY(~f}!8R!NXZflp8eISLKmQ}_Eu1OVZ5y3^cdVoRV8~{J z>ux+u+uI8j@FYo03`PoF!%uQTn!rV;%xNxDY-D$_iA?0w_LP=w<4QQnH|FhBjNcK4-2>4)qoO2)4w@_Pxl8(FZs7oh)g`H@9;72S~2b zXc7MPU;h;wu6CVp_;)68&GS&Axki3xL3pn8BuUDUBq=E=rs;EGQQ_*ChU@)zfQw>I zhsS_z0#;6@?8`@A-rZB%(hcuy$o+#-ULSs~r~mrz|Bn2|?vt(lTqEH?&v6Y6SMw4E z$yh#u;coVRaOO|Jb3|<5)2WK*F zTsa8fDes$C_Fm_=FVW{a!>X)^YwzwIfNQqiV^EeJ_>ceicRZA_C$-I|-*5_=eKoVTNep87Y)}{_)`4+`KcH`Kjr-z{xW?C(?kdl+&5XshLTs8Hpz|;!-kWlQUwH zGL9yuA4xoOB;ibSeA?mo(}&|u0a0wy7yXENHfgaNx<3Zw0@+XbZ1L^KYtoSTExI`N#9rHDq7G@W?XEF(n< zo>PTqJU0iH!E;hF|CV%OQX+Ol9Y3CskN~2iqmOLgweRs2CBEv+N^L^2FAjIKcl8JD z_C*KtFMs(<%$qXGeD(UNo$~uABM8Oep20H5+GMnO4TBUKJm=>ZK%afpnRq6BM)noS za7u-=vTx=o#iLP6NzM^8T<3GjTz4bt=xR@*DLBgL|fxAPNDy5 z_29m=4h%@d+ZVmlV1pUgUW*x2M!7H7YffUyLI=_*u-hDMm*CfLc&!S$44O%wS(}wU zXJ?V!2G1EpG_)D39>g*c%}XBOnbaA-T6pp#n{BPnu-eQt)EPt{<8=Dx>!NR2rmc;i zcg6s?W?orNbr!)9xik0-_@hao~WcB8-<@%zd1TS zhUE{B*~V17K(kElnGO!avY2S0S@Fyv7%4Q_ZBk{A(I%cb1_RNE!4k-DL!;x49Xqx^ z{NVGUdB$!Vr)+9wtQeZLGHJ=uCHURiAcL3G12b-%fmN&e=Jv>fvEh+%*^q;MXJ35r z1W+{8<6~)a0$V-g-%Q8f<*yj2Sjt9d?;Poe_;;LrT=) z!@vFQZ?W)<)DsRohg)D~Rhnj4ZA~=C+w7hx*al=uSX;wuxlW zOh@d}z1fCek46j8%SRsxsoJ#T0Dhhei{N;~^46PzTwmJwojLPHEMsAN8Gg+$Ha2#_ zf(7_%DM)}b&-4?A*q5Y&FeW-Dht%23swfEKFih<{fj09&vnr0l{DN%+VTlQ_+N8`N zI-XfZI7Y|fy@9Ova{M^b@awD7u+afqAn=<__@&&CkkDIi3vzv_T+hVvG&ZE*r~DQ! zTnK_-#&OVcJ|Ea=NJ$cvBT?!Mg4t+Gv@LNM5+pci_DsIncxRqGL!T)K)4?`*XV&Lq z$Kr@)`X7HNCgxyt+yiU*2Whp@hMM2HqT{m-aroW2gZLpf`agoW4h^|2$n~XBJ#o{_ znb;nRA5OqeD|C1FASsHyIoM1H1*Z)<=e~k@r&L&OE|MhpyKCtg8TgHT{O z1HV0_>$!DR8+ILm-NsKU5zX`)i_CQhxW4TY@AVJ8`As+7ggv78?Hf#`5sBeZi0J5O z_-kY)K{Ym4;;B7Kh2>B#48b<|UA}xdjKC|eyz<<0&*85-;YZ;<|9t+EB}?$9b9U|8 zg@>B)OO@ae1QX3kNyjBi!gFWhSvzR5+88M6Pj?-qzugs$0)HU{f57YTA^HdY$ZH@j{YhT5?0uChIeh;xDh}3h~Mvh`st@J2JnY_a1qq3SiXGg)~$Q@ z?uBCFS7?+vv)PWtMB4BSeI}ymr?anx< zZ)|L21OWNN$jm^SF)hL$(81qe`ps{C^U_N%VHmvk-g_7TOO`H$3)r!9Ck6mWBu!Q{ zgJ}#U5DjG}kT$b-2Fs+-2bkxu1Nf6byLaz`UgOVte%qb#ZC%fh>mz(y*T2l`AezN9 zdH8Wz`q?Xc6Y~p(iDo&R&Niex;ekP4+Nm_qO4?3pjf0|f)ZoB#GB5?;8mr#068!Ub zeaOS$M|JQ>2%>TrUi|J5RQ~zrpNH|spK5}PzaoT*{HoBcE- z?PSct_wV0}-)x7z0r>@x zO#jotYVD=i!(zlOT=#)(<{I<&POy#04Q$Ipju*|K@Zjvc$mhKD@*$fJIK(7$^F)?89w2fTu= zG+lOa;rG81hiDej*Z8<+cNRJj2X!O;a{=m%KZ)DeXs23DwBq_4e6`kWrPtbq^Izub z>tV9x_p+F57s!TU({IK*6xqymeIxHnw$W1ti2Zoyc?H%;V7o&@L-1Ew5%R(H!~R3S z0GR#G><1rw5TQOsAO@-?T~nZ9p-VrdJ67QPCF}NW;gUw!e?? zL$^B7+0~7SFj6029P7~_0w$d{jgO3xwckjz8lhKVnKYoXt2f%~o6~ zHc>5#4X*8t`0Wkaf{sn-itMV2D(r=+!2Sr@B0>8jii(N~F>ixjf4Ow&yYIgH$Rm$D z^UO0~A7&qs0E`bN@YwrkAqX@B1+P+4=isE!wwi!@eDR!x2Ft@dck-TvCFx8ZFny&q# z_~!YU_bo_%<;%mLtUa`OZ`8p<(MX^nL5^t`JTV3UF)eBhu0b{ZVJ>aMjaGwdqt~Fi zj%~PyYu*u~^|}aDgX{v?2$PK?i&s;zOpdwy`|rQk)Y$O#SLeR|>MWP%@VqvISpX3M zfCic%YK%7KUEhju)?Co^@b62w>+ZWiis2fGGVoJT+i)r^Ei&rxfB*H0AHH(pM{|ma z>$%lG`MBYypE~}>{PzF3u=js1>i_Gdqkp~p+|NQMfPYvy@-NG}{%x`SSBvrf8Q4Zr6#VmQvdX` zHY?YEv*J96{`snj|Fw4Fe{Yz$cJst_TP9|1Biy$At2?(0{AzXU?JH~V{<84dkkjw2 zi(9%qW@}i?p_urTlc_}o1$fGUxP}EMe+{ZJ7pKrnQ%w$A{B@Dp{lqq$6*~)TBX0wj zjial>eg53I1!L#W`2!84(%MpFpT^vh`1Pru-f5tBnLhuYKF>yyU zPJKv_DQzYRIKAT*aP4-tJKf#bQw9~HfVkd9TFKm2Wyj{*1LS`4^w{T~}i zuSKbE-=(+)(T^M;uAezXT)!AS@$!+0SC3A-actu4IKu4Mvu{Rry|Tyt;?}C?HkQ1! zA@7~dnG3fkuiGEL|Io3R=*@HpPOVV&u^Z4`5APA6ed<`mvMUNjuVPgP;k z>OdUUhTl0N2TBIDu@OqMYj61X?_2p-Z{=8`vWBS*xDVG*YCyP#QcuS9d&ei{CK5hB zF){xnEnB#ipJb zfJ#e{X@W)yS0sj1p^J(x2K##+dgvi6Y+;KL=PzkGgmhN3!vV#4Zc)^otD8hI!4VV_ z8Y=b~h8jj2)?0#b$bbZ9Dk{^?8gBuNvxWf&e7F{+M!7Uikqe4J?%FJc4LK9Qrre2L zg%|dfOzbS2*ikUCE^Xk+7hXSl_~7VZ=g0uiLFjKE82})+j}CSK#G_C-*vU2Rqj+h+ zP353~nyHpvTz8HQ1B!0N_(-?ndb9^b3pCfvxFXu3+QhY@+iGTcdC5;ztV*g`y5C$f=EU#DV~Wom$M1XylpkOa@fB6Uh!vSL63)aeCY9^t%DjH=;=F&{Tp%LoOP)HNP|x#)brel-feEhi)R;aBWp; zvD<#7unc>y=%p^jfsigl6L{`!cYOwQmz2QZdK~Al8FOl6CbZR^uqJcX`onhkuJ@tsBriAs1HCcYJ_Y5lC63`>WTM$&%}-A2wu|! zYhY;&COK|YvByx)_)zcoP|p|`9PGv~r4t4^fsuZgG9{2B>u(0$FQi-yIbU>mnamU6Z!zM#s z5aW7fQ{n5;qv9RRyA082W2`rnTDabo+55<2Po$?Mjr7BkgI^EWVq1*1A$qt&>n~XL zxML%OZt~8`VjDrTuj=_UFz<@-aYMSc;ZR1N6li^<=>TK|lh8--2y{z1COlFoLP5xI zKUj0)_jMW0ps7<@=pgvDPz-xMq%qtvN<>=$x;w^3Iu)$J*htsd zl<-!0i;j==GRqd*uDPbbUSdTG8ab#C*MoS2d6aUv*QEhY+lGl*&2@zTxrKKW8u7v64& zhS|3gjmB1@W2z^@b9?T8;GvSjOwF=z?H(NhG|S$CH{C+Lk4Xpn!nF|;^+d5zZKc=U zc<2rMP6p$+$@26$8DP`N0F?xgINZ|)4E8t(L@4NM7O<>N`#YP6#P&v@SD~S|U4WW~ zUbhF`&bo&ld=QU5!!Kj`5J}OD%$$`G*$*twyMAFwK-2A`&PJF0jkZ;tVSbG|Tc=Sz zEW;r0${l@j*1Y*4TONJl>0i&;@?QK`RyQpcz=ULQ)1uKJI<9sip>E={Wt%>j`|ik~ z+Y3Wpr_8$^0K@H2@IX4Q6`VAk$sN@t(b_%6rLVsxqNfF>wRO0cFx2Bqy z)!nuG>&bN4$2I#HZRoPqXp1@)deGiE(4lgd8;#>4!2vBTI;g1;ay{3R>RvwbA%?EtLP3G zv$28)XrL@ScpU5!PMe8eQd`h!@9$`2H1xGM^ttN=nowJ>CXN}b(>#iR(gG*R-CTnb zO8xq*SLVF)_Os7CeeE^Z%$PCbn&(6A+;P^2Wt>iCw5>6iVHs8zuGtuEiMOXV+G2{K zq`>+_`|Wq#>u9VP>2G`GjoJ6l`tq}cA!EJa)5X+Vt+!}2hz1htE_}9l^@91Ik{Kt{ zt@T&9W))^F?v&EwphbU~Ute;es$fmZ0Q4!YF*bbP=xJ8RRf(sYjsK9>Fch!=GB*9+PqH zp8xH&ZymU6*LfeVeT=rOTm(#LTaC6g2J#37M7u*z>=`++i$;PxW9F{-%(#v zc+0Qucy)coiu4OG1p$e+Ds_@=0*K6NyX&qy9Zi*rXtL58BORlRu@Qt}0%NO{7xuE) zu->BG9y8wQsnLorEc=wInQ5b(zWS6NXSG6Gbx&J$cUu*q)u5VXD!Zmcr^BlOP7OL7 zRfHCXqpG4Pqr*|%(Mr_c_rN39zP9t0)os68-wE8lW$3PL!*^{Th0&HUTe4(Rv+QHE z!LlJ56dRT$2D7TO5PhKN?0X>xpMU995G`1|a`pYszqja^%V&~>_6WQU(J>WcQ3XBw z(;YjKYu85Q&VK*nC5yixt_{l~5Wk(E+o-cuHkB6_;IGBnlYsHSrD9VJ9vM_rs_&o$ zb{|4(S8FA)>8OMtWv8R^Qc%(90PvQI4o9UzOJzq(WqUINvM`P@&`OBHN-Zk^ChpxZ#v6~;CeeJ{V%y?$e%$L{x>dme9e3tO*g(n|dTk+)9 z<`?&O05*pLqJYJMX*`yGxfW`9gPcyQkZ=UgM>U z6ROyRCbBLQrz}f7mvUt^pa73(6|focj}R<1oh@aZ&1Ib}%EWN_SmeupPhTxvmZSCcIdb1~>x7Vl6 zk8T3KjCZX_>Rgr5xgmXMYu51YyfLxZR=X`kquiL>{QNuf!@~9m(IbOxBZJN@d&2I0 z?1jaLYd5C#u1jhSiLLu$*Xa*K!`}RC^^0%Jee{W^?tkEcw`b2;vvw7JjG?MBZ**AH z8Ko84jQeQ1K4rdC8!a2+AXqQO@{ntE*foNZA#tF{*3!g>K0-%RX*;2WOMh8v{L7N| z=2Ajasas$#bz9L~<|g*bJ6cHJyGWM_L@}I&I1X1$FM){eb=UT_*Y&sC5I^*HGz@e$ z40O~3gI$e--FA(pE@y3V{;86JGx0G8qYm!bzH{4WUo8A&{-S4JeC3JXJbUl`57T(K z?z-FWdEl-GpSb6-=O2H0F7VQaD_{C3^p(#xe6&9Hlg$as4;3RA+mO_>F}Y>?na&ka zr4K#ve0F9EC?*V1XATXtJ@V8GPrf<-rMb(VdikASKlsSQk32SK?uVPVY&ww=+h8jR zNbU%TumFmTQ;()=iv4PQIhF4~r6sVxbeV65ZwkX0x5g}kXrS0lrG~v&Ds>H=x|^gD z0>Nb`xEV^IdW?axj+S!e0@ypiK_D0)xM~bQai3fGwe@${!0#YK30)0?1kH7ieXyqq z80u{%^tBB4IjHP!9l?$8y)aq0skYkc{L-TItc>Ky$o>1m!@pdy^3#Q1zW33mPd@YF zV^2MQ%PnLgZocJL_dW9T-48zT*bDF6e#hOewp!i8itfU)vbpm<-?n3W+Ueu1EtT@B z(Bwm?4|iyZ8Y|1HJ&z*&DKw%8#Dx#1ToagR4}JW`OFMNp7P{?4R5li|z@?ol?S(FW z)zzS0bu|{b?8VN;B4>j}W3dac7Zc;mGF)~S`R)pG{X{fH0=;Cbt67U{`k=z@TBz^< z_$B2fiU&IDr6fTp2FpzJ5K(MLIn>((a+zNaqS&{BS+Tub!r`*dMI}t}kO15XboX*6 zx4Ud*C0QlKSqGz{ii-1e8`Ib-c-~0rY-UwPW`QWyFX^k{3wU2gOb59M^YuiYf;Db1 z=rk_Ia=)H?mwuqjP7Y^%zOz0La5WUTbSX7l<~tkmUG)XdhJvUCB3xoY}}A2xEo6DR*D?}JCAHyt#Vlk7u51XN~OLvG{a@hrKTwif=wtpz8;1dzCR67HY}X4Lu@eA&NWnu;I!o^)aA61 zskG&_*5!HuHT8L*9z?tBMdHdknu|M|OMtExsB>wTqpTYsqRV?hv9n4mGU+d=Fd1$5 zWm4q9Zs>2rU{534XRxeHwCY3dIv$zAh-eLuRi&y#hYVd2sMIe77R0!r4FoBZ3ZnnsD5p`1-FfvqxO&@;c)Y^cXY4zl1NfCZmZ2|t;=TQwASS~YBg$d9CfJ4ZDs1AG5%68(5Z-K zjdqlR-=4OLUT0+=QC!{Uu7<7d?*KH>qR5J0P~12uCK~#S-WUKJd|zsO^0!syl;mMH zuv~gfrPXYb?BJKA40wu{44d+yEkgs0eh}n^!M-M@j4TYjBqa-YiO_2g2yW>$PRvM9 zTq{E5n~2Yatemg9aRh9vk5Z~h7HKX4l}g~aj%sKaP>JiXOr^Od3H=VR?5N3hRC8IA z-2%CmNC(T%Zdh^(&p1NsXeuI#iDgpZ9wN80*ICi$Vsc$o{p~db;@8&SsW3qPSLv@J zm!oKkvWQ}`V;sP!FV6$j>oz%{rFo^m+5?b@+#xZ!xHYkg4yLbpXutq$GG9`HFA+3- zOdPng!al@oioprUsZ^qYd833D#I?S%9zVF*W?%128izY|8tx2(QX_Y&I5oVBxn}E4 z4YUu^_pbZ`8!#rBzvvt^2;Zy#Dr`pZ^@zdyN7nv*JzNxVarQ?E+u7WFC% z9@|UmOz@((znQhqKG?twq5l*O*-$IcpQ0T1J1{R*QwzV#+&6bVW+ue{yEZYlUsJmK9V4^{BPg{AP z+l%4>C~p@4{RPYQ+&SD2+ynGYwAWMinf!>v5>!eo!Gy9y;rPm;p{*Y8Y3!}Opt-UU zz^sqVTx%|fZcP~pOfItta`DXvx^2X=l$vq%5*o;RjiA(AQ;bs{SNaQh6b&~nN*BPc zDlelftxp5bX}`V#3%meFH6oxCnLeeL(buf}2r05Z)J&(nAs;H-(Od+6p~6Bjg;-Ew zhJ;v5F_DV_LsKLSazQWrnzqmEe?gYv4&-7ai{D|z)RUtDvA66-!Knc$Ci+mL&yJp? zQ?S<0GS}$t6-CyKsaYd8ZX^Lrp(Jp<)F|qG#(;G^2$jmz^9NZ;6b%(yYWRZt(D$VT z9^S@c8&|7+mWi2l?xo#hvCZy8nDhZB;1yq4hYHjjr(!@b3n0=tqiD*W<{^f%KyI(As@F}xL>OL}Laa`9!KA|43saPZ0WW<;-6G~oI$sS--y8RM8F4p5q>LKc z0IKU)PbuPM^N7Y2_j0gA#Aza|ja5r!RXja_h)DN_adw6pid6N)O=Qa{TqK3HT#5{L zV**GH6va>$v?Ps%JnlA(Aw>YNoH?d6y*_j!LyP5rWIWY+Qt(I+>Q*4Pf3aGE&Fl zLnYG)83Lo%RoUw%EjCfKcEQMUD6_8vY3MQqAy8z5J!D4Mn~;h2q@zuwVU0t`Tyu0G zvnp{|%8Ly_$BmU%vPYHlOP(4JW&G)$uOV4+Q<7S#&!uk&kXlK}u4KeLDxft%?+&+4 zTCFc#R5lEH3A7_B!*xJ`1^_Q(nOFJC7*26P z14FKdUv#+M^V2als)79>Mkc|VXtjICRO-fR?-1|rHL~9Rp+3d3@tZn|Pptz0R8k)r z(m9Pur&_=mU_dWK;GL)}t6@NDeld`(pn+uB#Hepln|`v|)$02Fzbe_(O48_q7eyY8-GucI^uIFVbEM8RgV>=Mw zwfIO|fHd_ygG2Cdtgapa+Ui<){~gK!xmHsf1d|p7Y>7&1o9W1tUB|nAoObDdbND>p zaoMNzTmY?Q2#_nIts|Tf#dI4RNCa4#gyO5EXC%#NM}eBW(?p4&qic)=)_rUEt!F)x z#^-?=i_JGPChsZCrLyCzw*I>L`>)Y1)#JXst-6=Oj^TNb%K;JH%5?MY0=>roq=Rl= zqonPfdIuow^Hc!)vK0`KJkl~0x~ut=B^a~vNLeOroF|L!F16lV&_|fYbuO7-e>yI) z=JE)d-n*vt>>g!DHK5d1nHQ#OSkti~P{E_`v~x^`0W3dl1f{*8Dxr#0Dyu)S?=xe< zsbw&D7QDWh*|*rwDFe1?hRR*zW7EOqDAz@}8}AvvWb}@YPYXRQwBA8W9<;Ey zDLLgBb*yttp=)gHTf;OTfTd>BqkxTAJ=_+jZ*q8<5 zJ!8|xrKo4`*tjpo&-Psg&Ypu}_MyB~jN^^oID2kL;I7S@4m#^|yBaYV^1JLb9=e-L zx=H<&{nxABvUe0(4=M$QxpOGbUnRO!qX6HV=Sl^X@Z3Fbw?3^{KfGq9=RH6h?bGFS%P|(#>NFd8Vq(f#wNXNz)?0r(SLQt`yM2s{55JPIxX@nGaw_ryc zmk`h%n_At~#6Hv?%j;NPp@lG7D^b(E5$ysn0H$XDa_E*3G8O4i`AhN$s`2za`?FL#uZ=6*5%%+N)%574|jJGYHr*h3(}s z&F2h^X8>SnTLpeSV`COv?g04RjtZZ_FgSj8u-yh*4XbNm8Gc!6z_Qe{&~D3u`fGAe zIxC3Wwz3mGAjT_C5vork7-+8}H5bF)QJ>9p6XTtYY}lI%x)chD>z1N!03>Qq!0)8c zPDTDsI<-Qzbdde`fJTD${${8cy4`qe0l^+`$dTt4+H1t`i{&Twk>&HJ-ow711-RTG z-zV6c`t;J(-)jmWjum0H=o(mNnanH?12)378P3X7Vz&H*v*LskS8od9g!suA%6wvlz znp1;stC{bBq^OB(X?|xD394*_>4v_uR@%T33w7!3fDJKuIzTd=W}t>k2pP_*)2MV- zpLSNlytD3CopRTtp{5;gp~li4Z^`Uz$Wed?Z&J`E9r_MUFYIbzK=(u9mww5GgL|? z*L$7HU{G(D5u)CUE8x8nxpDBum#XE9lcs01!<9F{wv%}`U#1iKPJnaIR+Tasn)5p~ zKz+BP$RDUTZH$0sJXE~j(u&xC1AD}BqV?{IUUzvfl>|6<1*7<#HGQ2m{hioQU8{sH zTYtBWx1(bRdlPMowLk}i^w62v#p<;pU|k&;agAIq{A`ZiCF`+5?vBPRVa;808dld; z4L?h+R^YCM&pnNj3^HV<+q+EnJ4FpaX>mQmduf9jeyJ7_JCyx&Th&RrcnzZWH1!r5 zX&LxRJmk{b>oF1(IvTS*u;+AW&`4;`(=a1}YcN!FGYHhONrT>!PwYDif$mngj3T%R zL9eUK05vQlq{kRg=xeVGfDZTq243x`?(eP}=(P>>!Vxs!k%S?7mO-HR#?!!H47Lmz zNR5BJYTy{cV{4N@xf|tl;CFn{R(YbeGP$)PxvlC1;H*w{)tq7=q9!=2Pcl%iY9NrB zLtC|AwB8Li>(fbQ3Tn1p09m^W2I>kSAgW?1Ptu*78I`MG~PZ z#lQ*Py^v}d1~M3^bk{*8)AaE0)T@_-CT>G~H85;xB+yG~nnVa9r#Wj<@ww{zRHm5k zARoaNz`P4%DFefa=tjwaP4J)z?CaBpEN+bUY$*I2PP+(c2Fxs5 z0MdO{d@hN489cD+JTUkz&~!xg-XG1^6e~gWS?F$u3m{~++ev`3(LA8h8mX4q&{OfE+<5bYH;3po{E4Uw2JkkD#`%$Af{MdMjGW<6Fw& zTFOv@^y3C?pt~x?QE}W+dAzMMv8@WH$@?9=d8A74a?Q;F(oO6$I8c{wMe!b768Rpdtol<)hB$z0| zD(F|udnJuv%I>zJ9#;t_0zh-=v6ix9Q0>-Acxu?{Bn41hM`}xKlCvhqtqgU2no9r% z>os7y0|Atw-jr^;MF&}_+nY!?3F;;Ah>jvqm_*SL`bt73oN^7_tS5rP6#!M!oXs+K zFTyQc++y=xwlp{H*;DFQb%PEE#XnRE$UKUXrkV6l0OK;36>$< zGaxZsX&9fto$4EpZ7z;!E)pDVEDVr=Z z=3=}28W_tnrQn%4>RF`6WQl47F3F~;_sY<+46w%R@Wz}7g}jKy{K&@qL-wL5#$kKW z;ilr~rVKsY-U$*_Z~rTGYjF|dJBvN0s9NZ}2?q}u3E)>sCsK&BENP>kmp7v>-Y70Q}Z zZCYu_5sb0bZ}cCBw)B0r%zd_uJ+_Q}4Vn81Sz!%1;Xq^FLENvsfKeD_2Oy)wNGOhK zDmenuTPosPtKjYvS}K(wrvb{E#8xY66I;EZhX)UsI(QHz#!6n|SdSOEKtzPofNgvcnp( z4>UmQq3n4P_JT+z8e9XB45j`cy{Rn5QAq)OYfS7m|dRCskJbs)K<$ze-{3j>cxM>Lhh04*i#>BQfWk&jmZ^{@aO z|8Ty70wEu$pa`Vnngof2&1n*i1e)fkFR8hffKaBlOu9A{Y&XQPX!AnG#DJ_yP3pGV zQ`_s(cGjiuu1nujmqulM#@>36p0Te!3lQGJ8*;-N^1>Sn#LlCPU^$|Zs6S*cKHOA# zq@_H@Q4vS{RwuMn9J9hv8AqsM$QTG*9(PoG&{}g`fZk}WNm65@noR^sfv2zZ+(C66 zox(ow@W3EZ@U|E-0H$5CwPzMilIN;T#t4U|Hx(ZxlpKZnJ7@w+>JLFca(My)`3ehK zD~~Jijj&Uo?~JLgf!u<`NaAbM0FZB@O11_bW(~z;E@WZ_rKmo+x%%W5p!U?Zy3;!p zK>g`mb!T>w%7gk$DEnUKeP4Y}SbZ*`A@2Z}7y}0y^1~aLdLi9jde~kT4bSeVItH{< zz|>n%8QX$N4IUV*{?*4E0Nx^kD&-|zR>4ZpKw>01ssYF%P}xQa0Y6|cTqJDpi6Yb~ zjT1zkx-^5tdNr<8Mis-!QI*(I8rxiS1fdQhUVAa(UW)FTF$_xK2x41`V zFa_GmL7GhgMcro#`G@SyMexfxs(Xx2WdKBs1#W$ zeO{7)5Z0c|GNBHDc0;c(3N(|(7jKX6j7SEdKIS`3V81~1TNCCxMT&ZK8dDGUb-#%~ zdCeFlYU4OxiOG$6}q zPDBGVnw0urW5FSysW6IxZ+;kd41>0%G={ttIct2Vg`g>9!<|w_=;lQLr$%nhyO~rH zeR$QBtf~P{EqXd_mZuyB^(Q=uCX;c}g5)CbHCihZ&`Z*LFopsQ1L{46qaNxt-Nd-~ zdec`Tc=xJOF?m;IT+PXCwW(0*U2xF0G+1mzW&4F+Dh<~}bOZsDahiiO@**1n%tH$f zHx)!T6&z{e`~x{A03iy#62=u!0hW2LL2(p1U&)3Y2}i~JdTbQ&61YEUwFQ|gv;HCi zFS^Ono2As*Et$irH5wJls!SkN`d!VxM$$o&8VWR#50n<*oD$MX0l>*6&N8*x#H6Gk zWldJShbO^>Zzm}|#=Q3AR;h^u;jV$d71&;!L<00;w27!b_Q4=%kZR z+T8zCQfiZxNR&+j$ZevTlwR#kzRu_Rv?WGoDlA{gyw_ZcvZfaYXHIAxLGE2IH_$8z zJ%$b>Yp)YKl-_|_A=OE}O;FS;jW*006N(AG8XJ{~8-SVa?@W;Kv@7V+jH*=C^A+9tov*>7G1k(CiCTXH%yIvsicKLzh$ zPzyTNFVC{D@3~FBaqE!4dXTaw=qnr90c_Sn{!twjjGwle(h@P8^1vvT8`JFzMvGky;6(Q7n}h%MMkWWl6^L2o6J4Mo5E()uM^u$sxsd_JZ3;HNdg#tg}s zBLm|ojf0UV9V`@=dW8F&ruOB>HvlEaRuvr$DLlFY0#2)vw^W@_s6Gkmx7X0TY!?H$ zHJNnpMIeWCI%zJb&kmy*cWwmKnZig~ID>@;?}rIwaHyV!0mW~4RT{)NN_jtw3EmX% zYJ&vgG+IlQ4JSS&Vl6cWbpGF#M!Si~s$T@2&BLBu#FMWq`z$&eIwl_pp8W<>Y%MS^ z`E5JF{u8x(E#OC(FJJ_-DNcV?SwF>UJ2o0|Tt_(^XmokPy0ZAy#j&9UN0tG_u_0w~ ztIOiopuQq$ePzm~>Jyu*Q;=SRk>ADu_1kNZemT7pz)VeG%i3$p+HcP}NXUzV(Y6Em zJd3nA7Yf=zI+l|>I6|{aOvY&?T}{wvjwV4JM;($tru9VH0*B25zVNIjQ@ky^8QBQX z#uAPPrdfJcTCJ&@refF4rlT%udooas?HZTMJyVs;%wyx>z@n)ZVp4qEl*(R4+ zcw{9sx;Sv7ak2M ziU}<`wyG2%-0}65i5trkVfNPxDpNLALF+*}v_5rfH5g~oYmt@#BNt~MT$~rRBrkdyPyp&w3MHGtJrSFm=j{!3k^%B%3G}&}FW$C?)c*=>rtPD5C!0!^Y z0a8J4w>JB(c@H-2!z7&8{$c9&kJ5I3dS>^h>HFpbnfvEw9+;o8Z~mFRpQ41E8L=Sy zAb4Mt6S*Ys@RvZrkrjnUR~E*sLnoBsGB#Br%saWYDs_9+ zscn@fHe)c*c#ulepW0S+dV39=KIPjvhruOq4@yvJ3X`2Mf~+a{mg=b}*-?M7(rjn-5`3ai zbIPed?=j|Cv-U(OfqWBQja&P6!ur{X8{SRa_-^u+xk;M|$=f~zFboJgK03Mc<5PP+ zIlcGOle^}f-uubveV=B8&CfXSMb^Q^SqB#}7H5Vp%sR9|^t5}|%W&H>sj z!_hvi9TY@KNiF~Z0Dv*T?to_;Jol%mhXq(#60l`}aqtE0uu`CaVKV5Yd9TEU#haK7 ztCI;T$dpiXijsCQ1%}rnHhz(+f9#4861D8r!^>ZdUjEvVkkP1^Q;(zf@Kw#`l1{z1z24*{?br0$-Vx(E35)V@zo@A>@9{x8zQ z7i2^%1~MZVhnD0Z5;zi)6TKooW>tR7O2~rzBO$0MjssSg#IG$mzP==JU1`dO(&P>0 zCpMR#*n+YmbxURHwn}(}v|Tmnz#g@ULanjVrYTx?%hic`8VQHg0H8R~0&Jf{no)Mp zLALCs!$g4UF*}gbOcSsMt#@5cCIs*x6k2dxVJ&$)1okNb9gVKkTUgCr)=Lp2IH^iG zwDi@;#jhOt^0gx?W<@W1EqeJZ2vJ|oI=o`mp=GlUFP{}1@&<4?WL9+O8_}y?KeGCb zW9#0DS@-6V)vu#Gw(hN%b#EQp_)h$$IdL23#BG`rznO4+>-#|Rwz{1bvgqAqb7q4MJ@K&Y`BJi zA)!wxE2y2tbOnC{!Zmu&lIJli&nmWA&X$!U*yqcjDI0j%6HM_g>t__v1FdkMj7|53NYpf|?H$wtR4W+Xso; zK1@U#$Xh>5fUy0;#GUg5$-6&E**!0L*T;!FKTO{9aq@13ls)r+6Brd?pPxD~pAbGj z?ck#HgG&gJOVXp3WMVuVUY>JwMP6)3UTkRIvCx9}RgBd|3G0fE6H1ad2})0Fv7-FM z_WzH(_l|BVP1AjuyXMZi=bU@i%h%aU`H zWF;p#XBz`Hm~2u(6;zn%p6O82r>nc5a_sxOdrQVp-959`{qwMX>*3ws{ z(jAzZY}q+;WEK+aa)MFzf)aCkHd9h2wTfW!^?5{_74QkIp0(v^YYmBG>#N%@MnVpURc5lAa8%BwFc>n*jbImWpz5 zh3=e%-khbr{H6Z1&wWWhm(t7iE=~P|_9E8_K$?1Fp58S|n zKGk}2T6lY={q~%e`S#oMUE2%Y+w+~bC~k+|n(IU(u>g8*FZFCM^fE1-H|IL2&s^KB z`L^%_Amx*Qc5_%usM+R&Zm6VODVK$IJ_E z&kI>7VU|SqmYB%}^9xNe3@cp^SGyms5sxnRy?sf%nJ3TqWC`guQEqLSH<^M2JS5nY_IeZOIj9@NR(;d=6w7086mha(@G#W{t9z~ zTMSHkh;Gjl?4(1w#IW48z1(#VKgbfBE!|XM)_RdAkJblv*qty;{AY4zCt;X6LkTlg z89Y-HGFKbU5HVL9F<*CKzJZ}JYN085p)qEOpRgiKUJ)ci*VR6!&GPTg3-8Pc zw&60Z-vqZ&lQC=03D8c=3Ag7l%Gy|H#I1I1FLi7$cHlikK=0&I&%?EWdux5rhwB5R z6bwFG$Iu&kbYK3tbQyd)z< zye56HEJoVgTkQkes64y4yV!Yy(xweupAlT26+pL;Gjl>Hwd?|o;MTlG5rEtCC|@1; zx$Z8CSm=jkc(6<>mWK?(1>QT16nKNNVxJLE^8zCUuRtw@ zObZkgd9#d{`>8AZiAsNUmH$L_z*JrEOkMD7W7r%o94zuLEDEBD)|f?6%yLKUN=N)! zcjBdW008PdA62 zVr9~D?{&Wh@WhVpIpUC9^J%GuS%iRctx^v_QwW~t_(i9#H0i=0p;TI;KR$* zf?|T0(gWuLSB8j984FBjYRFD8Q9Zf(D%Uid?_3+%z3b5xIVH@d96Y?D<&yl-C5q+Q zZaXM)-FHytdhAA(>!Hf?Q00553P{IFyvIs?#!5-m6@KbUzp0u4Fj*5YQx`PT5Ioxu zGRp~>_t8cE<8>i}=*gw_Czm?j z-RLGZyPsX_f40>ReRs3>88YFTPRm%Mi!pUB|ytoVZ)@(*swKe!=dKtQ~A z16St!u8-v28ZEdrR!EE&-kvN1cVDRc_B!u{>C6e6Z9&y27x^eYD1VwATFSV)Ns5(c{Y+kPn(Fu{HQ?Yw*2WlJ{;& zKe#O?kO_q1gWCWt%(q?c;0rJK5`_H2JGg6lnECz-(?VZ_(LyOiUzE^5S%lAd@gXk@ z?(Eu$+1u~Yq9AZaPXT*}Hggj%a|htFE#=cq`m7KEI^Y@+phg796AkjGoARfWJV*@r zW6Bx1BHL{^#|^5;c43icxyYGVmg!7GK8yA$;dqvdf_Aw9VrjeNC1kE+W^su>>@EsOg;ePm{5WYt&i7@Iftaik# z^~A1r#$4>dsE@xqn0$F45xOBs0h`j4tI~|CvW#o;jBARlYpSg4aDO=G)>uBcJyAeR zm$2NOE!zPtcW26poknJp+R?)9nk(O)uLAcLYwj)80ZNZG4tR8thXMlLzAOZkAsg-Q zZuC68+WT~icy@h&$q?!Lx8*EIi4V6`fXNNzhj%F^?hfNx+=tuvjtoEx1=N`~UjdCc z@78>w<~DA{M~*2;0dC~h>igGm!G}O2J~!0f%)dKO$ugY5P=*r?@Jv@lmKJTS#L&*d zz$YEfc2$8KS7i=uQoO5WxWIk1$P`ObpxY?=f{fAj}@LDFGX$lgsLl1+kGaheWz;SIDr8^-4HO_7&ONXp5sD; z;QK5u7&<2i-C;?H$sI(nEVo6jv`4LV#emCw36}>Fu1FFA`7TMmI+RMt)2=Dgwp5v0 z!we&tH^*~#b4#87V{T6s5tsHxCN(PI{R0CmZEbr~^Uj`8lPF87+KLU||ar)vVH>ovoCrYUfi z8#K=k0khoTd4A}kAZ(T&3>E|-455ocmax_K3*aIue0S`nzSztCv6lzpuZU6P6E-Eu zo6_XXA(oV@vXpCzG;m`i12kOD(&>MDt{`O-tu!o;w&X za39ZiW0VQ<8O?K}#(cMtT-R~5ZAYoISxG6~@h5%WARgrQ{m3DnN{rZR&iZgDE zWiwDF?AoNpo8vhwCg9;`M!xcEA#53ixja0aR@VkF09EY}r~xdm=xd5B%c;W!g( zTBwoQ8Fm8NL?%#U4pSVUInHQdb-d7BUF1QOcubagsY^X4%e>VX=4HfWmG=(QaJ<2P zy51i;#|xa}1%U;A2v`z?Eee8Hgkc&)5i6iQVy)xCT4&UHcQou~px|;pR&?>3gNd8s zq^r`TtMFQua#fBZ&yt2}e;wAV(ivsr9Zjc{V7M`wMT`+Q$Kn2K}zYfXj`61P5M|Vx(&cLa-zVT^5Ed3!xfTgyAdg8sPiI zE?7^%^o{<6je*3CK@FSm9i}tBUst3NO4ywVG`6zl?$)uK8w@wqx!^j6Kc)l5ebRA; z-Tg65Oyur@GC`XF%&GvVhtq$7*`hnIP9Y*iGAN=~sbY_09WTKk2ywn&U_W*(2a*d9f*c~>;J)E!IXy(i{U59ai^D_G7A z!1{zuX(G5fl(MBrWk}mnWL#IWj>Gh92CC|>z*hV5>>D(?b6D$NRd|Y%J`{Y)ioZbK zO|^#GQw4vK>7v^^%oN>zg_7GdFQKzV&H2KvV4;ki3+^sduwZi_)>fQ&3JfNmk|dp$ zB%Ve9#7WpZ!|tMXhM|yg6lwN5C^H-sDQC5t4iuzA9gq*obbIVo zVl%^GG#A6)dA!JdsthCDi>UCKCC7>R#(*Vm&=MzTnHRj=61Kz(S#AjjtE~~MI01*Y zMqKQSUhj$lm#|K2CucA9#%fx6;x6~bUFoB$ex)CSItg6C#hC%B>YKEgNat>dr8K8+ z$&(pUC|0Bs81FkXyEdR47|$WJ!7X*}OC}I&&-Hc(Q+c;ul7DMz7ZW%y$h$SE1&^>3 z|2UY+quiL@%}z?7aVIX)t_NsgaCf2n&U^{zi?!(o@pc0VT4L=609v%cAOh@VHyM>A zof=HAlO`iKD3BzadX1svGeb#)l=9~kHsvYUWP;?=@)UrU)AH0aK$Yb z_lc78DCtzyt9<6`{b%d^7Mg+Xs~x(bO%>%0i5Yi7yTGozs)jW*~SF7W(r?ts*o0k)4O1oi@RGW z{xgq{#@-kkE!KT;Hhu9naDO1)RzsXE2L1q)VKB~i5Sy{KgYmB*rc9s~wi`Cto}_W8 z8+Ozm9b#>z@pfXg#A`{g6DQb86YPc(Pbt#RD$?yoa?YX7gYiPQiBgXVEY}H-$x5%O zYVT>L&cprr#-Mpl@B%MnkpbgX)us< zO`Lp0K?oG1fcuMO*j9Xo=GXOiOPRb?e*J*dJ#@#FGwy7-R?of?X~B(bm}Pk0TYM z1KSgQcC&LJ(?~S|bs+65P-Z)-a-6W9S7o0YDR3DpbR8{pA@?gh!6eSpt9+(weP?R@ zW*TvchM2{PTT|c?H*~2vY^5b)O>_ZVY>TS;p2- z`j(7A&a|Krmtmm_kacr7n^9bq&1A^J-kZZYfZe<~M*dP|#(BEB;HBdlf3t6@wP;rL z+B3Te9HP0t_xj?E&e}AW`Y9lD{~GKn4t-u;=UJ$14K)>pnu@~AJ0dJtx}q$5qO5wN zHS|VX^+sDWihy8u?X;kC?=C1|{xgsOpznf}rYC}^A04%mb+OiiiME4DwnOQshtkf- zGS0}e9Kdj%vxa=!_BA< zVXo;MY0e&t!zmwPv}ogj1Z!#9X&_0llV+YC$~>dUb<~jOsK|31E+qHIO5DcFJb=2w zb2k&!UK6!mQ}sSjT&kUG!o~SO=prw8ksG?$61JO_)(EiL7P;OYwcbJNKw1j+#$N7= zyV{p{buj7LP#V}8%Dkz}B~-b$M~d#?0zuCc(}qB{g)Tw~d}>Qc^p zHU}-gGYgOgYyj0x-}vzEWh1k9ruYtc`5;Wp+Rg6z3(D~~X!JSO=ywcS>&4)Ctk&~b zwa1YPk0aHT35OBacpPc)(g%&+$C`YOar};Pkq?1J0uXE@2r_B~A;xVX#_gddq+uqY zBh0iT!n7mY6hT+G84>X+Y$KzcVWyoCW}RVXq*}U>PAo_&Ed%i=FO~!GCnag8Bx!bx zo|2^6$uiH%vKeyDlJ$A#lm$*23SE>8suEW)QtHMsR&jo;!egxRyqaOM#)qi)nXDt7 zZuFaO^v4N4uIABcKCa?&gBF`ZmvAXh5Vl0;fH*0@31H+}7tRQxH?cAtq(%PK!IZ0m zsn?{bH{{tjl-bCETf>F7$^DW$>XPlL3UFr%pRiQWhb*&|J1_FToig&Ou#m0cIp zs<-E>(a!ABUS7kcw!g%#OK>>#zB7+SI9;6sUE~FPfjh=+!DLoTpkcE=!SOrZ=zFx$ zhiG7^@uZ-}<7k5yRKLl%3jJrZjSUN(DJ3@>}S;CAvSg^?k;U;*&pgYrQB7Mp=& z8)?QVBK?#&jmAELp{z6V9D8}rS$U2Fk?Ww$cO+isgR`>88JRE)N{P`5xA963pa#_* z>e};Qvd#-kHTX<50$(u8@n7HtFSHQLf-t(4i>rCKlt)+dVpuNq#c$$tZ!qzi1S@~6 z4N|e%#{vMEaEq#a5x6r^tYH%Mx$N#VK7waHe}~uf>1zG`m4a9HtUPRFf{2z0)!fgf(%;%40!&`=|N;EQX zkWSwE>?1?@e#b#ez;PxeNZUXVLnw-dQ9J3MBh0w#f>~FzSr=Y8G}^2u&ayY&vNsW& z1pO)2yU`>An-ZC)kPot)v$7m}MiHD<3PI|&_2vmQ&gQK#FfGwepvY=+aUN79f6)`}!+dE!Y)tl2<}X?LVC+;7Kt z#Hb8BE(|!{;(xrw&w%Tz-{h;$V*(B;fVV!B1#!LS5rPRSJ@hKiAE|WHQ0l4!N?Z<= zx#+M|A~9Tb>fH5EBI?fTA%He`Qf_d3^f|r+&-WOf3jyEn7~jtTFGGkI6LeezLXNkG zonSC(4y=!!LmcE_26o&>9&L@QSNlaUE0#c9?IHj;E(mLVn+WZ7pZ0rKrN zZppbr#f}F-k>i0PhXW;!2P<3-l{*uZ74ACB zQMxtmy7lMv>b(e#&yn4<_#dN}!4ha73Na8x7`0t6X6d+K+!bTe9c$VXYu1xs-h(ut zz;ZVODOQ82)*8~RrJ1%vgdOF;Zt~8`^Xz4$4q&vzd9;kIhv{Iv%44kBeXPoTyap42 z=VZP21m=QzZ(19G2A>&@-!#W>o{x+F1U}tkuK6=LAPQSi#5t;gX?7oAFHqTK1Na;Jl3!1-W_^T7&C2MC-F7CF6D z?DSTdlTMN2TP5cX7T6ysa6FLju)hGBFp%k>A-T)$af0GMwH1`EOvmZi3EfX@PO@qfK9 zo<8C2$Bmi^q;$7l(iOUg2WtadAIKV~fou-Ok}Oz8;dQe42oxkTiXh3HfoVxJ9gZ`R z#~I6FjEAC)hoVkME*Od+-x&>HtcweE)+y$&~e z>v4RK@ci_f{q>vujtE1M3CG(b42f{Vjwqv!Xrs;;q=Zptv~f>7)&^#z@#dg6$+9=W zqBqF`1z{ldq&UL{NHT1t*{7sAr=+>3pzg|}W(HRKzI|B4O0`=Sc^xFKP`tANlg}!>Nz(-HuqsKe1 z+jw4w3w6_J@HkZKda&M&w8rINjqAZGm$#~%iHdV?ma#bQFFLm$G4v(Qn&FQMQ0Tb7 z@a+D))BBJQIi&mY&+N-*fNr&@~BPD(Ot2GdVUG4``; zDGhS$q&cUD^3DulF_3pwRph8DK1Y-glm;jQRW2;!)gG^bNdZjN)7imHqwgFq0G|cV z^KqY#h9yxL7*DetPq!LRvzo{_NpY&>Sc(OLv1IeH6!WoUv#}(zF_iIG6J?B%GTKN9 zuTj0DPslI4MC5Trlj8HSUfz=|ch}nSuUfOP0aZlR%tKbwHd+ z2_VB1kZ;eTaliPSqL|49q(SMqkxG}5N>?ymg(ZR8?i`q`_o8J0mW7RejQaso`KPAx zPqR$qo?@BGJvEtYJCSWWo@F(jeR3?zlE@@fsb;D)Gi8$LpCOSNWeLWz_!H7tLm-Ye z7>qI)h&-U5o>5n?vA9=Jtf|O~|?+MfIjX2s9as)w7h<;b_kvRabL-~eR!5Cmp7~257c?QRp)WA&hub{r%r>n4mUuLg%_yD z57uuDF=!1nXpJDKEJUB^h&j<2YupuQ3VIXG`jRaNQY`yYNhuR>nvi{JDEBl_7TOa< zm=3fQI}BI23|BZY>O5TGJXYlj)Ya~)6f@X2mT9HVwwcJYQRmuCbRgMqAdw9iO*9@zHttU}g!U#FBIr*z-kW&5C*Ghf`bb+8A&k-! zUeFVS9c~Fb#0xyY3pfDf`oD<)+T{Ocz0Vs>eg~R-4>SP31DrsXw>W`^TEg^r#F3Wp zV=Wg9S}q)i3ZqW&!wvWmC%9q98iJ34ngG38f8A<7y&50AN-y0iAKh|Ko!wNSQ3JJC zdg)Yn9@?R5*Ji25p>p>_W$p*dJxD=`+nc1WZtf>q;=|PB80D!Xm-EH^pKg z-5LyGI-pEAgR+1bfldty&!Pw@5{xw@8Y^LXhNU{kdIFB;+A%}kZmRIqRG!^*5yt+h ziF~_>{8Q>Y+n2!oT-bebgkdbtcC65rw7_;0E6bA0J3L(Vt}0lW@E{{#bY1v7R`CuJ~g;2^#H;IocI_v?K0lNA%IQC_TXi z-Ink}{BRv!$N_H90Um(kL7Er=C+I*!z?%(zZ$j%qpoUt%H*3)zxW7K=&04?xbpdbI z1s$jhK2R6(7H9}N#JQlyxuDODHEfPE;K!ffCm0D+%v(~-T2m|psg?q0k`*t}lpAl# zPcegXlT7)E=4jz3nsF0MIdNv3cvDV-87I-KF$RHoW1M+of;l(Aq9M+tF`hO#36>ma zv^jN-v*g4B3toa1loNwTHs{8f^J6VIQ6`)yqlOEH4H1ToQ3jkS(xwXr&9TNroKbVE z5kJiqU<;(-12z;Ay&>}II( zf1}#(=YRr#3MzenhM>xCZ%yDEM93SpA#c`(ARi7kMjYnH9c@iIAxt%H%e3swvFgsT z>&~_7FFey%WDo7mJ>8XK*Og-n?Z~oi%e3jpv}w(-Mv}Cq*^nk%BP&`GETFtNGaj-6 z2@`9|M-XewiL(%<*$Ol4glTrdjMHt|XGNK3KwI`1Vb*D3=IPeVQ>__5bVoFN-1l1{*G1`}nn z$!NOycn%eC8pwrq>O2&7+o__nlSOAH;VCH6YRTzIfEEnre4EjH>(P9xQ4D!ftI+~$ zigT@1*;c9?D^;$QGRIP$Z8nr{CQUPwq?t(4sJ!4})|*IlCmrieGVD$~+8uwi zD}jb~XWWsF*dx&Pm?NTS-S*fcq6@m9CE_4I6ugCzPJ=ygKL$HSHz#m^Q{Wr*0dF)0 z5(sL1_f>iStjdQ0fiDBIS?Tk0!uMyD{@~}(nt**({y(b?`gv{OzN&zqRR*&Bye{~S z`j9so!}d2uzQu_=+#IXhl7t*M+Ln5vE61WI*K)APZm{UoV9{ww*_okoCs~DyywU|a zP~Csh4$@*4(&w_9fgE2=TuwanYLW}_JVVwJg6gr_FTud9Q*cM=e8UN zMUv4=;Ctc;Y-;RIHKAR}Xd#9(EylAg$8%1O=i83w*^KA0YOM{>Vl!E2H(6{)T4*~C z$MdX*b1a6lEl2ZCYREasxNITMwvcC8$TXPCGR?)Q#^N+1ahh>|%JJSLOx6bEcr3iu z?~2uf%T&o@$Zn`8Mz0M6JmyGi^kEGb4ht?&VdsS&XbRfj6tJ%;U~ir8-Ui>F*ZTf* zjn_Zdkp7(1n~4!HRC@oE4M_ceUKg~t78YhVE|+Jpj0o z2Y68jxBx-SL0*gwKUPl=t0zi1CQLdaNeQ$w%Z=oZ_B@VsCj{W5>ePz!56>bAn z9s^|_gVpYeL__kIEM^qWGO;w_xFq%%>oQgN6fLPn%5*bjrU{l|jLYzvAs0$^kLR5n zFSHrSgVD@njrp3uvdvNnascc;sm!xfW?NuWK?5Ac+(e#fF3mKNW}6WiW-z@k#So@< zqmm~a?M^t>op`JxMxQkrL0b%#YC5fvI-;1v!e|`>z z{(Bohz|Wy|{(Bn(_BI9WWinwO97Knv5U`&M!T}w~i#WiIfT4$Y(K>)1b6Aj|2ZTxb zqGVWkv?Kjkcjoc#^yA%W$9u92L2s5(AILN6C5&0^C!>vb6hVJJd^hjQH}5YrA1JmI zm)Z;zT8c|-B&BweGCO&-y`tJlS?8*1a35~;7;W?(yAIvRV&WjkB!ARZ`_5 zt#Xu9xC~Xh4pzAgR5(eiJtS4`gB32)YIj*JdY)I1ddTWMl^kDXqmMk{xIFf_JpMQZ zi5es@I_5Z3o0%nRVa~64)ISW>9Ls++Gn-67~NwZ9)*`|_o6I!+LicMlbboWWb`!x4I56s< zAnH(StgbNrFc2jk=}6Ylo^-S;^%#JgU1T4F6NWhgm`O>wc6xWr0QYAq?V zmX<+nBo%hjN?RbWJR`3n)mV{oLX~DRlw_nz zH&LaV0yI(#$2BcxIKu+Nxt8#Htl;Euj^%JJtjDGmmf{-C!#dmo48inF)1eGgS%xXa z874y+CXx)}p-dBOVt^x-W?`*~0B9vfkHRwt;=t(i?Nhf+U40|$8 z^kkms%QD_!5T52453&xDn!sFgv%nOFii<5I#g>v1OVUy+NijGnE#EPewbfcyY6F+$ z<#5neUO~thRaDw(sIZe)*(#uwb}|M<)fsukDS6c?>REM4UP-Z{=8U}Zw4(Zqver>q z=Qv#NG}7cc+T=dUJwL|vRP%i&TYM)4zB8>sbHb2mVephNfSiq^K@Cq?f2oGUU({`? z=Wy9rmBu)mMivtpri%0vG@{`${Kc?kT-Ioo8Ol4rNfvgoXImKKqj^}NK~GXLAOZ3$ zu^Ojg4s$b1C7H(Lb(%4p6{i|X(izjUs9lnQ=ST*sna zzb_f*Xve5Ml~RHfq`yLMssZRrH|)zePRh^&e;N8RjX-~<(O{NIU#2l^9n3W&@=P^W z7Fmc3%*61t$V^&nB`rA#Pic4-pM-rxxvi|yR#wggh~Zb2orW4aW$hV7&1upqJ7vuo zq5(D`IIFC)CvC7-)-zgrcDT_|39WZj)Y`MiYcaG>%i%8$thFa_2=kbV+OrfhAS)E; zMwxJm>0plsA8B+LYjPgvy2;>mvLTS6M5mmP!*OhC0%JMO!qQBXX{JPq34tJ;*@S`& zQ_S6@EXagx3st6tD#HQ+ELP=OFjy)xvCCYQyBiBt4s{#Nx0L6Y%QHv*Hn7{fTnWt`(W-oz*ZifI#_ znZR{|!@zT!;JA%7o@0+T=tW5)IfKDMoBFTyzqFs?b_hOehL075SF3d<%KLC2J*OS%HP3$a1KVp}`2X-ky_|kjnsuT6wh_4*>#$Keuvo>@7Wg5S)n)EGSTcd z)$BIS_dtM_DZcA;iw6`;HoHtTQv%>w$o(cqmI;m%80R>SHL`Z^xPNA(0a-^3*V$w5 zSmPO>!lIgdWWXqfp)Bwk)jJ)|GA^fJUdBqyd^Fo)gk5W8SkU1i#3KCU zc+p99u`PoQX^|Zh+o{X!Cd*H&OYGF;ns}o8)MVvpFjZ|oS$Sr%>NHV(daA}=L$w2T zF*v9xCY`8toUC!2taY5KbD6AjoT#;*taZR9)8dSHwDR;=jRP1iw;ioKHC$nb0I14r zRAsiRayz1u0lTWt3|F2Wt~tX7qcvw#<)=ogPmk6RV>R~JHCkgoT5mtr;P?uSj%tj@ z2FFRR3(HiqyB3eBW;pfdnQ1vc)5;+9Vq!05(`!cPHPz}tum{3x!ktkz&^-PG&v^nV z1m!tTHM`94-6ps$YOa&Ii2(r%HnlOb1#4+Khho-RqnYLaC(*2q=hFut>KrRDo=adz zs*7x1QozI*s-<@1TKVazO8c2g`>9F?qQ((AQ*&;n-U;zcz4J_+(@dQ+HfI}LXB%8d z8{J8p+-Dn^7)rZb=bAj20DIlFvE~pw4%>&64tJU5xDz+cK=Lw7LK>Nz9y)F=h84~>j6o6KGhQij=fpV@YA=#0qo71}kMvz@zk z2|cIUc6CFacF);1&smX&hE|W+7LOT$+iWZ8OtTxQz!jSlsH>phq&nZ4tSrPZ#3eG@ z2^xc^CQ9ul%g98;GnHp&s)7A1%&Kvmt#zEOcATqso~vcRdtU1_Q|mNa??R3Bu5%5p z^9}B^wXU;>>pd1YKKQj}_=^C)esbl-?|%8s7caj3>a#Cj{Qmd9eEY*&liSmrHBsa| z*K4lPL!*se2zEfb295{ZpXYhbb3HYR0Pwx$d9N_X^O)m$kn%icx$cw+NPq?>Hh{9b z=D8k7HtNICw6N`S%^rB8W}7`2+^0BhQyeG*Eath-@H{Z3PVn$flFMYSzypf1JkyFn z>NzFyoN6VV?eLj_9c?~y9ey)yKG>Y=@8YtQVy43WCDrybRSq-N3^k;)HL%$ECABcuWv;<(p~+*e!F>VmYNI1fNlgebBfh!d`#GqyoPMfe*`^z-x}@IoEuCuGw>z=T2bwH!}gd$#chEG|utP zYdY+-^Uu#|nSqZCvwW{oBwPFLnkSmnufE8 zyFma2o&NJZA@jY#i+!Q9y#Wa3dqc2yzBh2LH+ZfmWDc91fwQm}zB8cPbes2Ns~4VS zlJ5p4cvuf$G2l3grC_z)NR8cSrOim0m9p4eS!|{#Fp=kEp?W25^b&wGL630>sB1is*HUuq4& zjZgo&J^S_Nf86cxm*4#GyHCD<|D*4o{`R|H{;%(!fBD0A-|yc4r%yh5|K1#bQ5d)= z2mouHp-ZCRWl`X=Fc8)gWNW~pC=kvrwNM&>g%iUF{AOGIXWIj2h42w> z24LI~WFnMoC1|L^P52lv*Tr~>mfm3ahzFVJz`*oI&R|sr)QwoQJC4@F$5SIUSY4b{ z6q(5jOonn#3}qc3$}||tHXsG;W~PBW*HE5&LQ!B0h0zEUdB*ZA*bT1@<(bFjnTCoi z!?_w1ST_xIZgZgCZK3h}LIVQ=&iMuI`GuzQi(F4qILq-`Z1!f<3%bPj(}2+@@LO&T zS{4y^ChI=`L3bOV!Ba_2$|!j#UGEhM2-GTOTeO#0zA%QyWc{) z|3XK=Y>OY!?l*^V+7UD>!YGFO{!E}9+8ut=0yyXeoow-(cc7;X}Agemsj~DoJVygVLjW{kE7rD|Mw$cScmOFyc2fEZ5giL_H@EuBE6S>hDtlbP;?g)a{V5uW; zQRp|<;x&UB&UK&UxJ+vdkX2#GswkLL5WFf1dH0IshaWVKEj|1?pzVcO#V0nkpPX)Ze!78G z1QefXc+P@Ncx_ot6pwuN?;mT*`e%Rm^>tMd?v2NHWY&9P)_d`r3?nY~L|*KQxYz|H z);hxh+Sy=7*Zc5`QzD@2z4&!W(WJdmYdw*yE_Z}2<3Qw3SHyBx*m76+QfDxR?P6Qd zLYwb=3+lG-ES7Ctj~Nav>ZYpCPE?(mtisJ0mZJq`qXnkJdH87Hge>)#H0g*WURM&Q zD@oFoCh18N^rXppVzk8Tk|vQ#6OPDI4I~Li#YuXybOVZ$kBZ}A8U5||e`=op!lL?y)s2#A}b#PwkfH%IZS@)5JYGynaYBk$qQG2hT`-a`N3 z_vjD13^Tu4AHQZ_iC@(D?#9r&m&H#m4Lrtg>|enjlj?X#e_FKd!Mq56H5h+J_WpFs z{YgH!H`#oDice5Xn~YMht>z)#p5P<6Gsd|y&e7;NcYA_&XPmpk-3i`qwC!}rT^y_F ziA_2LJ<)zcQN7llG?Hh_m3(<`|ee3WqtYoXCMD+d#ZlD^8!W+el5v*XY`gb z|C=vAWqY)*d|_Jt$*Fo8yxQT+#$+f)F{-y+J!|)lYQ{cBHzxG$f6>_e@+tqfjK2Q- zlYhOlxY!gr78=76P^00gMU_<|u*jYC&O#Ip?<`yPMw?GLx!|K|F$Z=QdlDbX0?@2n4A>WU-! z;(zt{65A8YF!%*S*#XNce8(6^J;!_vE1kG6&Ne}w9Os{X{M^~JBW z#r%IulVACvzyJQbr&mLrQMk;E{j!|SMnWHfCarm>Hfm_z*+-a|LFgJvaZ4~E2wfG1UKE7`m<~n7#V&#;cd;wrH1#pNg8?7WnJxiy7f zQG#Ff|J}D=qw!yU_niyxIlApsW(;j?;@Ftp7k%qrTz&e@`#9nH{r7MG`*(BqzOJAC z+)MDnyb?uVXMmISSg=)$f41{1KMubC{@X8J{NdA&Klu7>UmKRzSzQ^=Gh& zDc!7hwBqt?c`<+Q>#zPoRsPK%zOSA7oPB(4DWLjqQ}@ZXcH;izqhHLo$IJ;MXImpb z*j~QB(km;mX^Z^EP3!S?y+!~6IFSw8yU!OnrZga3H%?r^Fxyq3l4vMNtJN-?{M z^?_TF*UoUUUdr_+kI;=5#Y#l!mMAt3CDr1nl$f=xl2k9uo%+WFP(RTPkah zuP6i;{-Mri4_*Ks77tbLO%K}^_y2H%_B8nJsdU}5(wBmsc<{A>EKbnhpb<}s2cZ|> z!@L0BJ<9Uazx(B5bbIgi3_S?LvzxO!PyJf(&We~dR~~;9s1gi-EKZNzBy;0nt{$5S zq}Y{k6u$>x8Nc$8aeRU6hgo}p>oecrIa}v8TkAGmPd@q={EeQmhV%FUalFy< z`UL0s?|!-Sv$QRLffQn%g1km{x$~dn3>_Vi=Yq(;gLlp0dpJRR;I*W{Xhsk`QtK$V z@ZYf697gZ+oG1dF@2_;@E#(I95k~*tD6N0^_4}v*u!9@2hadiT^KFqgr+DjV5ardhL;yS%3b?$2d^kc)l@U4;XJezw@ftV4))xPQlipB6GC-^6e|UkiWw#;f2zR z8O%O9EeINGaKnJbQ{%+|xVA3MMd!=%5;pO0_&|=qhO+#+x^cYG1FsN{bAtZ%{&Ekx zeQ+1Q$BXh4ynknbecm4{u3gMmd&{F?uAV$rPZq7Kh|^cV-)LQe9pkLBEm71ynqfAY zVLF_SyGixs@rNa0Z%9J-4FvskAmFD1UjH=U`A^Wx&B^T3{rcnYv*n+{O01u?C7MRJ zzv#u*GtKl}GV&R&nP4y50ddzFO#$q`cdw1NC+x#JfVUm*4?7mx)=){`m3`>n!T( zi{F1V-yVf0Z4Slz|99_Rn_!;{`th&d8*A{sztZ&Gm4mq)|E!;NH6GU6agDY>U7%wWWfEO zI-P$aI`njYu zq`^qOwwlBKFZ{fC69Aj}Pz<7$i2wfE54PE-7{B!uJG7Z> z!3yn`>ZJmT9~W-qRlcli$2|uPgay7(vJ`X`u;h z!s){|Uwwvk)OX)~!>*<kBG5lg!5oH?llRjAO$C47M_3bxbps)jW>StQM`mcNa+3$ZNi993@J17Z1Gzg8< zk%UpeA`RD(gdBtp2EWxGcwjL2;9%&%PN$#1Xjse!4oWm?I0E?Fk@)|< ze|u3B`#-S@Z+>g^|LD!o=}kYhLtmzDA6hbWI+JzY*;LK8hO%C(n>=58iiOTNq#3-% zRF2}njA)vm@ps~0>-ptp&)eev0nd(~7m2qn$wh!46ZE9*AI#Ao$kB%m=IV=ckBRdP z26K=0XC0m3dOh7zH;4TVJG9@w`xk3Cp6;73KI;oP&=c@RSKu36{tSL^bYau~jZW`< zT|Nl*lLlaOFE#q?6FL0@=yE20`$@0cKVt74Y5n)#X=?T3fB!DB zn=XE0M6)wE+_A2GZr{kBDborZ!xO7(_I<#~QCs{^@Kfwqyc6IZz}wQDvJWRN=!`mm zYJiEJo%G>#-})nT44b z&Fq*!p>URlJeE>^doVA|3d7KX;xku^3b#UQq6g~HNg-68@62F?*P8`u)8vR>A6?rwO8oz&+Q&R6P^E=(Cw!}w|^G869V_2w!8fd?TFjme@4UE=_l|SR%+CZ zV%Bl87-gK@WJ>yCsox)d@ecc>pM3TMZ~hBZZ1!3=JCg{EC_KaQ(!YtMQsmnDLwRG0I0DYSv~={(DAhop5bo_s@QFiVK7AP^gx- zrkkH^C@`7g-PY9bl)Z>CW40&!Xy7IlR zty5*)>n*5zs|o}O66RtkYp{x;s3`?1nbbynO7MvRJ_13SFbR|e)L=oCg;c-+#h_6W zlW2^Ioi|5&hkllGK;{Wji+@fp6- zaaw%C_je8**w=GvvFvoLq-R!1_smRJV;bAqnAzH#+1eBthfSHwnlkVufL}E;-Pb5} zqh%*9)@I-qar(^Q*vE@*`Bdri58fHSJF8}jVAU#mD|5~=Rmnbm-G1MxWMaB;U8UpT zM>xv(YF})vb9^lBxQW+QXbBgOJgYQ5p0Bx<-~7()^Im=Cr+npozkT7ycl7kmPk<7j zq}gx2_S`QX*z2r!T$tMbhu8TT5ukw1JMK4+e>eW{RPJwXspW2bup8D^P+GZt>nHgz zdW$*7+;~a#%TN7?dHjzD_aph9b90=+ZCxKDA-uEq9Q+EYGV&`OvtN4RL6vCUc;(T% zca!t;Nw^6E(Dff){+FJ4IXDI*kD40(<)8Tv+627B$S1%5@NlotoM-y})&?(0$Z29UbBcA#Mcz z@uJ*?1*0X}xmb$lcJ;779N+rj0D?}n-P z7ruXpWwrYZ5#!7&_U}Kac|4o-HWu1vlF#rRTf>_g()F zykqu1=x?YYu5VTnldrsvcoiknE2*WrD=RaM&7)JUfqg5o| ziy!1$S1t6C7g*2TrR>gFt4zu?5x#}3uetE@^Zv&dE~zGj0)-!t8*&GtB{U!WYMbAO zAc;H~yko)fZ@sSd`_upYja|0fV>}n~Dp%?9GhiM3==RI}UGDq*svFi!y>Z>tf4X`J z6EwdzMGq!Z!Y_Ts?_E<){mlmx^RNGGncs@r5;}C}vyS<~B~{80EDyhb?@9(!4*h1| zdk`ml;`CL9fx23Sd(%#=OZeM!x(Up_) zR!)+wnw-CCl59n3u55hnstHlQ^tctJ$6Y)=_u|rAA#PIW7Ide~8JoUE8Fim7Elb*` zMYs*RNBG-6Q~T;K9`p}DtiJgN2T9dfg1IWeO%R6ucWr^pFhbwY?!ErTbyK#VpS*lt zaK-t@-?VYY&+pso>kiWJ_OHL=%X99)g*>?O{O`gg8@k5HrNOh0`Q>+RX8NY!NiFMZ z+s^#QD;GX|=Z<)l${U5Ot(M}fIl1q5FZ}Sft}ktwb@h^AR4I2Y8q8zi_wM;Dk<-5d zE%OK;#y<}q_o*M=ao6V-+{j-9tgg7N>x_rLv4gxT9!!Un`^g`C_5K^ye7$$>9o=Vr z``YD144mQ0#l_tgXPmWPLV4t_ou9t`vy-X&QF6KFGb3;7`s7dU+C}2(1NeRX-T4^w z(f%!$Hf^6j_&Z;?B>PS2-@bMAvhlgg#zjUyw$kY2xZEY9gXQCLW#e;q&&oh~&rGon zJKhJhi`rWb{S1f9-Ls2sId9xgZ|Q#Z@rMrl{*~;H@zAdhvpO~fNCJbwQT@!dYK zBi2#fEN1N^`3+GSj7X?LrXP5Vtdmqk|F3pQ4j(-5xrK#3r)0DCTN0}ezWpXUFMrKO z37?j5%_UhM=imPD@(Zi02K9r6>9|0L;0Cn$z>=}S;xVBu9UEZMbwhf0V`g_#M#PUY zcL1l1#v=##;-@CO@$ApD-#xp}qh;&9cz|sSkHfSUli%8P&%1>B?2&PwA}T9!Jj6gN z!K=LV%?q#Hzwdx%YX2wJpUOehTR#2)Yp!Ti_`i?bwVhft;g=u$&DVZ?)T{s1hlk#N zi;voAQTqP9M^Cl?`FFoz)p^9~eloknRTL^k|uoxSqc6WVdcSC4LgLdxV&K5QO z*~QP?{}unhZ|wi`Po8`4;b-1^_*of!^0Z&P_@^H}{T>B0TZ@J9ob@s&dEkVHRY=`` z{LEn_F0}~JB#<<{Qihl)oV{bN;0-{(FwP1IgP^9U;f2j zdg`HjuU~ur-nHMm<zDsc?it_YzCGJk zmnE2^S4`Ag98(t4EV5xAX*=tY!BzF?JxxU+aZ|T6-e?+cF4}XH8U0)5o&2XmDsKGp zrT0F0#s1oMCS~;Kt0a--kps56SR>Pq@%f4jvBQxqPA&l}*Wv)gZ5CEOm=2FFth)KY z@An-Y0hlOXc>Fu>?E6Fft^b>MApZJuKY#tXNB>rzleF`JJzXu;sr8k~H76(5lqJAT z-o;#uU0iw`^Ri@)icQEdZutW-yrBpaYYfVD)`^rZ$@}^EOnv6grKgfX@cFO1|KNm6 z-gMCHhWJ_-SZ;ANc8F1dMf7J_soXCyA%~!e1Gqu&x87w>?f?Hf>KAzBsYh>Fb2iK5 zO;Zb6Y6@DaWgDtetg4(ldARaz=T2+fowB!rTWdh+)MfTG7CCP8-fuI~S7A)+O+}pC zd-lZl4k=}N{KfYgy7uu<88wr?X#0+O6=(2R9XWtlqi(Y9um7a~L6P@(wBgXf$lm2m z|2r64C;!jvkMHsz?F&ylaL3oSEb43+-I0Z;q5bb><4$GcTEATvv}#3FNPB|-|_obZQe7t^18Vd*PUGvwr5xD zKC5E)9BaKZr{e0fDy}|LcIBDnN7xxcw_@kqid}B!RO~X_8MS?L%XyU+>;1&| z_J$IK+&V?3Dw%au3ad$NtW0iztkqJG_Ue;0i4)iAkXMNgjS7WBHk!ouC^K&P^`SSB|kU9LPfBS2Ur-=FY;I9tzbQx=BSfg$_ zOxYcGzH{J@VaollFFt$AMYFo66>P(%6m(Umw$&71UDXAhRVi6z)OyEGwpS$E%grj1 zZRHHtQq98-DR0XN*QG*Mp(&FKSCx5!Q(sCLG{T@9HKaYKea*4H4=ef1E}+;qXT-#qdi z--V2!{~tSd|NJn4+RI{quGzA${<3|yKGeT>eE!GxT{CAAh$GNq-Bl%nvVc}3VeK9L z@}cRxC>Ur#nJjCYl+^ER6hy?JsD)|vAtTFD@M65%rIQlbhny5&?rC?{OW8Il**Y=N zZxa%mCdxRo$zQ?&IOJnM+@V(`ouCs3y3C5(YO@WOaIb*4Ie^-!@_~@JbEg&eWNQ`N zt#(?b_vD>ft*&WwDdfPR09=m<_V_ysH@o#+IXLfvmsv6tSP-frLb8-@L zs^~1!Vh{Q8O;=n#qsUe4tt4#ba5tA3JMc|T2o`7z8RugQf9KLf%lO2)arqmpZL!0a zaXRU?aeRWyeX#QtjtPPi4)#mNCt9Np=jk(MQ>m^!$~cMfYWNoMRpWKu-w3ahlayOv zA+}Ve+Nx4*)v30c0@>7pwke^tPb+AjUO?N1aUNqw1K~%KkHzjv7kY~W{q2<0hAIp4 zCTi&#aHv&+HHZZ5nMJZ@P+Dt;JDM^(n*F7cU8fG(Ijdyn%o5tZS;g75y*bl2vv_+` zh7RpLz5n24F-j;ro5W(uA6_DEGeNJs>Ft-JM^^U#?v*>%pWj(+fm*Rz)-EAiur;9Y z-N=s#3w}?2Ni+SncG88@GD)vWL2$$|CM7j&d}95$d~D^YJh#=O)mc9_-;KjHWAbne zjKLetCB&UOm&##q3{Em8Y|R092}g4J4B$f1pD6PSL+JLB?qKHrrU9s)?^T&1u!}fW zV+L-AKDD47n>GOA9n%N2hb9M*8?ck*@{eW#c|yO1+Be@QP@Jzy_SUC+8`8av>E5Qa zBfbibP{vL*qjP%yA;hu1nMEPunIY@m=1gx>rn@oS-H=w>n7+Ju&~Kl49L@5e>4IzD z=8*%QMP!a9Cx`gn?;ec*D)Yt19=d8yRrq~z_1G%(JIFlrl_y)u64=H`iS^_2Lo-11 z*O{#xo40;KVtr|1&G`JajA7)2#73NiPHAG}gv9ExV!C2fZfr|O1j|PR7mvzaJt}Y6 zNx`xa!HSW&nEL}R!Fc+#va#wjk{0gXaUa;=LBst-8V`wYnxGDCj2@4bZjIq6v(w;%rM?#mhnhe3=uR+ZXPSwI5QQjy$HmcX3v zx=D$3AS1DykgxuP#G2Cl6=QN&1CAC1WAavv&Rsb=4~T$UHZoW?Dp)!yST;If06xI@ z(8jC7g|w^2=B*l&ckyUlvV3F+9rVkAep0Y%R306Gt{SZ%;7p}@(|CLccg2S>`BFXo zF>;BPu@=lD^e%t2jOvLtM1U~ncz_}tm5I1oWUi<#>zq~~n_{i?yK4&pjrBHUWJW6d z@l9?z;}m#qp}ue%t+@ehcQl~8F|(~fuVS!cOpoE)F|&BbtYRp~G`W>-XsxcXbRsCwWOu659yL+`~Rf_YMxQZgl>-QTeoJ*{wf5k5jaldC;~# zzM(_s9%XS+Hb@$u(gZ|ECyh7On<^5UDoNf*+Ks!R@2Dx*ieRUy?FL+3VNYFQZ+#YV zn>yhog$h}*GZGXdg6g~A!XXj3Dbv$bysaU#L)>zj92T5)_4xFTUY;myp8qSxBkrki$WZ?UwY!F*DPoP@rLrmhLaO4|HYKlkrkr0 zV)Is&=8;1xjbuZ1oDAH6UO7%O1mY4y375rAlh$m}aFJbjQm}BiKs#&D$HeKlj4>pajE!wo&Uc9aBa&(LT+RZzsv zG6tY=58z7J$kwz}WGQFHvO=qj6uHXgs^liDGC@mUR-J6GPGN-i5V~Y;QN2E`@ar;+ zlqj7>h8~Ie#s#LC&boBx3?zxD4Luzr&KO)m?on?>r;$ir(%W3z)0pXDjJ$=3pb+=) z$e>nJN#VD)ETiV{(^{4lW*> z%NYz^$0}YjDhLhMXcoR;1@5q5;fd-m86I4CVsPQmVDX27g`8x-hjfxLYKMh~OHT^i z(646d(YY8NwQd4)y)5KDDStJ-=f08MTC#^r5aivM(-qH2=iqBuy%q?QWnd*~IfvY1GmAu9Fj53q&m%Mj9pyS!5F=Ycu8S9}Qe~EM1_!3-mUEb~6Ed5Z2qIRTT~+z81+L z%d>4AqMYt-D(*48i+df}pb|*Dj?chSA}ks>Yp)E*X({a{oH(JIwZHGJFE-7FvDcZ> zM#RP1h>NxNIXu!F`hVC)+(GZ5Kpiu=ff-qPIDL-_JUtNo@rJ%EE8ru1=#LFeDIYd2 zZ?$C?3KVcBt7K^~A%DZ91P1pQJ=`}_Qj6$|wc%EZ?$FDb!4qK&2fAhHPBy!3hj?V+ z`RS6pR1byvLc%X?CxII1q|iKTijbi>vjlM6jZDoftOn6;Ya~w_)OY%jowJAZojRDl z&+o2u)Q#97?(072OZA-86rdnL{ts?e5EvcTwHF6eEj09$eSp5EjJj^V2Xpq{Nvjm7 zEz!~}Jlw)Ek$ISj8qm>6)Gb5T5%lm(bdr|{@(YKWSwHlIXuP~7cBiNlbN9qAo=V`} zkA8A~OF8MK&GnO6EQme^X!!=SKYcsHOB~_`aA#qtWuQ3#hoWC*8Cp3xsur8d)&T9s z+^w{Y8C=}MNN#W;tBgG&>z!;jpud@4zK$nO3)n0JG|)x4S*&dqHsv-K_p<0dbCk7W-tEqXIW@<<5hjEY(BY^n^Ox-Jd zOgPeAB6bx62c?JF7(ktfR3YAvS%@$fbR=NkNgCGCIYGZgADXCa|XqH%+kfy z@a0w*jh74M!| z0(A5acl|-Z>4U+I%+dJHj}F=S(V?`QQJlv;h~yUMk+!T!GXgttiuN-+^S7V@dYj^j z_P%F_(iIs@=~VnE_^_Mf&{s^%U1rQpRNQHC0HtS$ z*BqdqW_0N2X*C_dl;99KfJcTSe8a|EG+e7W49cJ~lp0+eE%n~Ugne((-W*$%Cn`@GrPDx}NXD|ixX(^AQl6h^x z+Om8(TSb0LO`?S{Q^QvUy-v_sDT8cllb{pZds($n7d?Ft#KnD91bw!1AKWLU58d@K z<9@0^*Fw)ScG_lJtiin@jo9%t(EBX!p@0P-?@PcJcdG$P@>c8xI$|e_lhP;WEgPq2 zEf$Rm4el2V3+4^ZIj2N+-k==%5`MN33L+Ewthpfc1j8L_InD;nH^TJ5BYZTi3;l56 zma%^K4z1O2#62=k^Azwsq+5nh%y;grrs-qUj$HNd6?e=3CHB(LaG3rq5pStTv?B28 zgpsxK=`>B*o2Mi>Dd_4X+r+&UU=EVb4oF zcSldG?mM-l@3a!yURg2i&eJ09iuQwcoI0p)wzMz#YjP+4YjrQNn>k!0PoBWvED%_r z-%f6?JkTb3TejnMs{JB!(>v%9yKmaEEz8r=Z>^p`0?cK0m0(D^bY!nxB|ZCbspqh>``tn zy_3e1%aPF;0!3_aS0q||L0zrIwX|=GeQ}Q{XLDa)rf@+^nF8)y+j>d@zWidYXrzs8 zs!3qf096~rs5_0;@|K0Izx(P5asZ+Cuw(84dNMke(q8oT`iT;93-S)pOXZ;79@cP5 z0KJ_e4D`)*G^@7b^E>qEs3v2M1bTF>nT47#lD9e!D+1Pi3iX!Yx#WF{hx<{}x<5*{ zfaP|U(&rZCV4!#IKz9SW902-56#QNFiu^FOe2+GyPbZ6P_B{UnzQ=jE%S`54KSrh? zZ^HNa9m(rwce5WKvfvZ+C;?+e<`7Q+y+hX+kG->h~Dr8JrN$4 z@KOL9K-v%Dy!{1};(T?Ah!p2?JYNTHa=8T~0?@nIAwDM~?y?dY0Uy;9^FuT36Zw6{ zXVMqzhA1!RR-FtlI@jAJz!w;x2k4au&s7LFIhbqxJo(&pzLm>q*KWD zN>6=Z59J+NoMC3<2~>D^sX-^jy)i8N!~q2E?UvOmv1eb8jDn>iDgAWQyFpj9pXOV5 zn%T)l2=Y8Bt!W+N!-5Nj2lIxC?^)@bIcc?+Ll<|1Kgi-gGk&Cf7rSTsn&L6zDDK{Y zdkoz>ab@6rFS*houId4jA8jS0Xq(2fde^&%Gr1e?Z0;gkp3fxP!i>yMp)K!JKmE#n z*5G#HjK|Ic^pQ3{5nvZ2g9XPM`gE|QI9M{sxJT$$4pTLldLWg5=!d(p{s;lvG&~|w zndEtr&MC64sgl1^!7O7op{B=l&{e0H5JI0-6h?riG~8uP@&pC^DAb41-f99QZ!UTG zI(L$J;(WN8GrcR5ukzNqtsBtYK)(d; zSc!zcVn{B;v9%wzO`mw*XKdn9dqRWafA~ySMY5wR)o}_1Uc$cUw@15m9s!sOdg}&i zE?~J=Pw+2P?q^|Nkst0zK7tPSZ1gtEYi|yj^B4w_SE#q$Iu(elaL0Ei&LaU^zA4CK zJW?yMj|}FY6wDc%a|XoIGSIu&oqOEI={?*vzq>KZ$K0*dL-YtWeiTZ!*nnt%YqOMs zzt#L{K@VToc-Yz$4}FI&?ql^NFs*L@N#n4FxJ#bazLB@C`t=q0JddO=Zru6$(2rTu ziE(=;#!V+CuFmnn!h&E?L9lpWup|>KA7u0g2djhPz< zDD$#mhn*tps-e!G>{8-apxIxNFW5G{p!Xx`?ahkwf*$v?w$a6%8jhJsUI_!$A>5nk zn;Z`x=xk&!kHVk|wtQvH?>u5%om^8c?(DqypTjV-!yV|&$z$t|JNC5Hv7z3Lehi(C zxD)D4@(T5q+9|tZjsU#}c`x*3qmLy&x}SS2UbzA2Ee`afkGRL^#eHlpl%2RbMjZ5^ zWplSwO_5vyKN+)jzOlyPOL)hK=MLQiyF*_H?&E_+7{uM+o(@)&}bYdeiH|Qbv(gctEb(W<%%Tt}v!<>Rn*hlr1+Q{o+YaaPq(XYE!xgXrIUi98r zDDGk{AL!Sm<$A0EsZl+&0zcFM8GHoPBwaSm}lOzjMJIKO*JKU~CpEucBwxcBSb{w{;? zjyYo2ySR^)`6K<__m`Z0NZi5#gG0UB^Z#7p+^I22^0X0jEu|;s(H^Dc_|QSq#-QVQ z9Nf-2y9GM7Y+$e~En8j`tQeHLVsP%tAws|5!--2rCoUZ$$pgKuG^y4e&1#>R6!bEI z_L$EWk2ZHePmzrdYkVvDb{laCzivQpQz0he9})3BCi+=Lq5Nm!1{UWHJ(5>;*F;5# zGGJjx{Qza`Qx)pl>j!kW-nE3Muw&e-;I52r>A2|c9LEL=M+fH(Q=A8S)!*ev^##YC zWtqGa_v{X(6XDNgA@Y~$*B)|%)Ow?+FCgxvSe24m=f~um265Nmtk1V?9S+_ zSWKnRM>|71bXEOQD^13f86EnrDtFtfGQo>9E|F51IN2DLX-~+Jq=a|2=nl8rN?j~X zXY2J&jcug{WUZRTQt#lyk=MlV$%GOZ>Y}dNELy21Z>?V87z7ZGW8V<3K~4lmO2{dQ zj*Ha9x?I@o%=yPC4?vnKS5kXq$d_Q9eZx6Y8N+zD!(-^7g26A!+cMS%;VFb)){6 zrXP;3SEFs!ptDovhIBpNV-X#K7ETd91xHz#S=Tl5=w^-YLXacDGX)1jAx)5kGLU6| zzCA5GrXyv-IgOZf6zl`Vs>NF-Eh*2CA=or9xq8{+Yqe-N_P*kkyR~_QoCktNqzO^~ z5~^ancTooWoTfsxGhjxMy2V_I0$G8Mpc5D2c(~iP>pq{ENghDwFI0 literal 0 HcmV?d00001 diff --git a/release/windows/installer/05.progress.rtf b/release/windows/installer/05.progress.rtf new file mode 100644 index 0000000000000000000000000000000000000000..5cf4ca96ef678b2b9332b8bba9d5dc07e9c865c6 GIT binary patch literal 214 zcmYL?F%H5o5Cp07ihBWaLa3;K575zEbBWKv!r0c?CPGpEP69=m(MqeGolvr=k$kd0 z^l_-0V}qKFQ7aw!p;ql-LKA$>om+xJlSZ2on*KqOI4d}dC3l+V3g4E;r}etU($^SC zG`Fm0%^CA41q3d6I9Ld^tQ?J6IYlr6x+89K%uck%Ii(^J>CY70_g}3aKe_huGe;qBe z3*&&rbeL2gQC}jqc+?xOZ?|l-%e$vAQihLAN@Bh%`7_kNl@$Y= zW65CRF%_Zwv=hGUcB;i7AQ4zp7P!ZTxI9Agq?o{XXJ(M8x{1uJ;|VnRxZE(ma~%z+ Y;nM}jQ{4_5n@&!ygKo0>lC^pG13-O&rT_o{ literal 0 HcmV?d00001 diff --git a/release/windows/installer/data.ini b/release/windows/installer/data.ini new file mode 100644 index 00000000000..d29efcc3fc9 --- /dev/null +++ b/release/windows/installer/data.ini @@ -0,0 +1,34 @@ +[Settings] +NumFields=4 + +[Field 1] +Type=label +Text=Please specify where you wish to install Blender's User Data files. +Left=0 +Right=-1 +Top=0 +Bottom=10 + +[Field 2] +Type=RadioButton +Text=Use Application Data Directory (Win2k/XP only) +Left=0 +Right=-1 +Top=20 +Bottom=30 + +[Field 3] +Type=RadioButton +Text=Use Installation Directory (ie. location chosen to install blender.exe). +Left=0 +Right=-1 +Top=40 +Bottom=50 + +[Field 4] +Type=RadioButton +Text=I have defined a %HOME% variable, please install files here. +Left=0 +Right=-1 +Top=60 +Bottom=70 diff --git a/release/windows/installer/input/24bits-image.bmp b/release/windows/installer/input/24bits-image.bmp new file mode 100644 index 0000000000000000000000000000000000000000..5c7fd0698a0fa469d778dc12c5d12aae7e99ae0a GIT binary patch literal 2786 zcmZ{mTZmRw6vw?hM3x~vlrKR&1X1t3Xo4DQnW+;_DVl;o`e2k0Ne^LJ6q;g|s3Alo zqK@IEETe)j5=9-SvCPYunt3TvXXd+{+umpO`>*p^l(yO5x$M0z|Mg#M?emS9^u^SH z12i7y_W-{|{CfEf959^gfB}nJ`~K3p#N3L)nx&^sY^ju`KpznR^%9TFZg8* zoifFR)y*1ip+p-{GJ+YFF%V<$wH(#lqWoNsg(ZY5S3ycK2O1I~Bk(Akbw!btF_RWP zu^)>h6hv93k=Md%x%DSjcT8m?Buz^iRzpiPcmzl%e-oqCe-BVVvdap#CirzrVn{+H zY_Y1CxB*mHi@Yo%G9fBU0f@vYgdRwUEJBXV5+7=8fISE_5xJYPvQ~)Fg4{$TF@TB- z1SHgUh_%bNBq*GYS=&*9gmMiSv*3!zecD_tx?jbxPFkS15m`l9t`)~MwTU=uRC%7R$o2mc@oy#;9hrUol5 zR8(&vl+LYyg1bTaSQaYqWRX3@`4vqoGKGar$0Ivb5CXaTyMf_q0sAzNraN+7g3V&1 zFwuea#7m;$83bZj;p59os7NgJs;bA0%Avz6hmIZzPxLuC$jbmXIN^Mv($vMkkk7nmHaQECz+IpinwHhAsEcjSqk_$1 zLXF5E4Omf?a0CjjpHX1Kyo2YMQ0}l-<;l^?KZ6`Na$MI7Dx8;_4m8!y|M2Wun1@|3 z`@pV<%!{NbLmEVqDwvWJ6j4dF(WaUr5aC27)w%5I+{&(>P9SjxL_tce5*SqjSh}@T zow`#rFrrqhc&1b;-V_HyIKgtsiA_!+jkm}mg_}_U9)d^?X`ay)oNS?vJEP9 zx#BJ43=EZ;tWvE?EdHv4A?hpwp~qTvfv`0C>n%t6(9jW_L&{f+v;W?dS;X}9sboAJ zXlaruwqif0k=a#x(;vt+^^;m`SXr&mws>^4s#Ap@F&0te8O8;JYgr&85*Zy6{ zI=7zd?l{%89ZRWBd63ZHy;sluuxID;Pu`oiX330Yi`v$`^Zd8l-oJF>d(Y!lOE3B% zoSy#WyQ2p_J#}PP*MXgV_4D*vUVRMpaZs{;I`q}igIkVubsX&65yDkbThSkS`+wi} z*~Y~mu6Sut;5Y}@?Ni>D87v2fb19q;~T%kcxdx(|GL`SMA}1NpGpZ^@aHhqmwT zcx%nlnJeFzy7uk%t?OPmxo4AIJ7Mv{bwkG>!}-xCg$E~`J1Rx!U%&d*Nu%y=A3d~v?2xtZwy#;*KI_T5CXX02d;HKj6YiM$ z$lxg>2Q8d_-}cq>t@)b@rU*YD-Z$-uhaMX-WX6P{bDz4u@6WT!9shzZc5Pn!(%dQc zOc^bm6pDn7dCzH^2~{U0Y^X#fdBvi literal 0 HcmV?d00001 diff --git a/release/windows/publ_installer/00.installer.adx b/release/windows/publ_installer/00.installer.adx new file mode 100644 index 00000000000..d0ecf549ae8 --- /dev/null +++ b/release/windows/publ_installer/00.installer.adx @@ -0,0 +1,308 @@ +[ADX] +ADXVersion=1.00.00 +<=>2240 +CCM^8603:<;8=2 +CCM^8603:>;8=6 +CCM^8603:?;8=3 +CCM^8603:?;9=2 +CCM^8603:8;8=2 +CCM^8603:8;9=2 +CCM^8603::;8=2 +CCM^8603::;9=2 +CCM^8603::;:=2 +CCM^8603:;;8=2 +CCM^8603:4;:=2 +CCM^8603:4;<=2 +CCM^8603:5;8=$HM +CCM^8603:5;9=$Dgokcl +CCM^8603:5;:=$Naogte +CCM^8603:5;;=$^cr +CCM^8603:5;<=$Ii +CCM^8603:5;=$Etnue +CCM^8603:5;>=[bu!\i %K`g +CCM^8603:5;?=$Ucuz +CCM^8603:5;0=Qbjdkr %K`g +CCM^8603:5;1=G!~uzgcw*Emf&x' +CCM^8603:5:8=$Ciom +CCM^8603:5:9=Lbrvgtk-$" +CCM^8603:5::=$Fdnzr +CCM^8603;<;8=2 +CCM^8604:<;8=3 +CCM^8604:<;9=@kcolcr#',Ymz{n}v +CCM^8604:<;:=Rkc`{c pzihamw+zjb&qirh#~c+cghf"nrdeu tc`g(ik+kzst`kreg$,+Qd{+cc~&`duo#z~n{x.fg'Dsgqsf*n~|ae.vh&rmje`~,jf+ksgqsooo&pb~d%(+^jzjt&l}ut#cbhd~jn.c'bsape#fi|n|+ap'dd(g VDO+fjcn +CCM^8604:<:9=67?7 +CCM^8604:;8=3 +CCM^8604:;9=@kcolcr#',Ymz{n}v +CCM^8604:;:=Voc!nolf*eelbmjzgc&cmjot*mgznoow"b~h{rs-*,[zn}x. ^cr*&ie*ud}+yj`v'rn(ivfx{yak+zjb&gaje-*,[zn}x. Ii#(of#sc~(oae)v'q`fr we,d~n|||ksc!|ne#legm%.+^pbur($Cbdond).bh"~it(qam~,g+}ar'cy|ta`~eeo+.bzgju/ +CCM^8604::9=4625 +CCM^8604:>;8=3 +CCM^8604:>;9=@kcolcr#',Ymz{n}v +CCM^8604:>;:=Voc!nolf*eelbmjzgc&cmjot*mgznoow"b~h{rs#kbo(b}+\gfb,Ghlz$,+Xykx}"%_d{$ jl,rg~.|ols&ug&ouo~|zbzn.voc!nolf$,+Xykx}"%Hn*&ie*ud}+jd`%s&viht#~c+g}kyypnrd(rhf*jbdn +.Rucr{&"@kbhmg,+gd'n}&wbdx+|d.xzmw&dprrbixbfl.+gvbkr& +CCM^8604:>:9=4625 +CCM^8604:?;8=3 +CCM^8604:?;9=@kcolcr#',Ymz{n}v +CCM^8604:?;:=Voc!nolf*eelbmjzgc&cmjot*dj{+oe.gftmacr#|iy{bae.lrkcmt lx,oik+zjfh!|ne#ebn(jbykcc!gh zeyy(xwxzgj(!(Vrfy+*Rkx,"n`!qiu#}me|+zd.pbvmiee#~dn(mggk,'&Qzcsp*.Eg).bh"~it(bom-x+j`.vh&smvlbii+|ck+hkkc/(&Pqox()Mj`abj#(of#sc~(|oez"si!{ros*is|yohzkia!(otfg% +CCM^8604:?:9=4625 +CCM^8604:8;8=3 +CCM^8604:8;9=@kcolcr#',Ymz{n}v +CCM^8604:8;:=Rkc`{c fdxnz+zck"wgr{qoqn$x!+`nkfbb!|i frxyihz+zjb&h|cmp$,+Xykx}"%IJ*&tl*odfge{g'is($Cbdond).a"trnx&e{~~jkgei"nrdeu. +CCM^8604:8:9=7641 +CCM^8604:9;8=3 +CCM^8604:9;9=@kcolcr#',Np|jmvnio(Vrlm~n{x +CCM^8604:9;:=Voc!{raw+jnbdy"tnnu tbm({kymgir`oc ll,`n.bzgju!`gs#hinf+kszpfeumb. +CCM^8604:9:9=15170 +CCM^8604::;8=3 +CCM^8604::;9=@kcolcr#',Np|jmvnio(Vrlm~n{x +CCM^8604::;:=Voc!{raw+jnbdy"tnnu tbm({kymgir`oc ll,`n.bzgju!`gs#hinf+kszpfeumb.#*\ymx}+,Afhbmj"#~c+{a{.grsietjdk+akf}, +CCM^8604:::9=15170 +CCM^8604:;;8=3 +CCM^8604:;;9=@kcolcr#',Nzyay +CCM^8604:;;:=Voc!xgtk*eelbmjzgc&cmjot*od}gj+`ms&cm&cqommo.d|"cid{&nl~,jdykjj{'cyaut-*,_zr.x~gdogqond*m+lbhmkpbhu(vawb" +CCM^8604:;:9=4625 +CCM^8604:4;8=3 +CCM^8604:4;9=@kcolcr#',Nzyay +CCM^8604:4;:=Voc!nolf*eelbmjzgc&cmjot*od}gj+`ms&cm&ouo~|zbzkl) +CCM^8604:4:9=4625 +CCM^8604:5;8=3 +CCM^8604:5;9=@kcolcr#',Nzyay +CCM^8604:5;:=Voc!nolf*eelbmjzgc&cmjot*ex(j.Ykcc+Nfjy#legm+oej"ditdb mex+jn.dxguqsartfd" +CCM^8604:5:9=4625 +CCM^8604;<;8=3 +CCM^8604;<;9=@kcolcr#',Nzyay +CCM^8604;<;:=Voc!xgsp}cyl+wd{"tvdkofjoh+j}+gldiszccw$,+Xykx}"%E`feeo(,g+}ar'cy|ta`~eeo+gkot(!(Vrfy+*Bieapb$!|i pae{(dxn|"snd(vapy{dzo#{|mscb|cd#cxne% +CCM^8604;<:9=2 +CCM^8604;;8=3 +CCM^8604;;9=@kcolcr#',Nzyay +CCM^8604;;:=Mic!gt ne~n(dh+zjb&qzigqkax(fjz"pcsm&svz|d{n.a"uso(eovfh+fdz+lg'`n}hd-*,[dnoxk"dio|gcw*ud}y.xadsq`zc sxc}aoky.dht!`cls$ +CCM^8604;:9=2 +CCM^8604;>;8=3 +CCM^8604;>;9=@kcolcr#',Nzyay +CCM^8604;>;:=Onurahg#imiaek.dnjd u)- +CCM^8604;>:9=2 +CCM^8604;?;8=3 +CCM^8604;?;9=@kcolcr#',Nzyay +CCM^8604;?;:=Voc!ksswea+znib}vu!ahflxaj|bae.dnjd(rhb~,|ix.x{rwirmb we,im+cn|ebb!otk*xcm+}r}vbk!zcgjyxyq+md{nc&ogr ao,mg~`o "'Vmmgsf*odfohz"~itz&sllx|iyk+~phphlcr#lcy(ckg~, +CCM^8604;?:9=2 +CCM^8604;8;8=3 +CCM^8604;8;9=@kcolcr#',Nzyay +CCM^8604;8;:=Voc!aren*eelbmjzgc&hf&tko,manbo.`bjn&cl`o(ea.`b&smaip~iymo +.Rkc`{c `ebihz+wmrt!{ifw}mym+~yatnbdz&flx,cmg~% +CCM^8604;8:9=4625 +CCM^8604;9;8=3 +CCM^8604;9;9=@kcolcr#',Nzyay +CCM^8604;9;:=Voc!mhd#ej+|ck+]gk`,M~tqkoaei+tkw&gaje#}mx(ykjmjbb!jcflxi+igb+ad'rim&iwoax(ha~bf'dd(vrlziydr.nvvugb|cd-*,_`b}+]gk`,M~tqkoaei+tkw&gaje#gmr(ik+jcjgfmb.#*\gmj}n.mer`ah b*jymxf+mmw!ihd#~~r(jijgl) +CCM^8604;9:9=2 +CCM^8604;:;8=3 +CCM^8604;:;9=@kcolcr#',Nzyay +CCM^8604;:;:=Voc!m~tqkoad`+~phed{u gch+fdz+mmjvmmre#yyhkn}xhwkjx&& Wbex(for.jfpd(defd,hi~}nj"e!ih lziyiay.Afhbmj lx,d|cky.gutnz( #Z`nixk+mmir`kr zeyy(xamzuftd(vrl|eomy.map'nddv. +CCM^8604;::9=2 +CCM^8604;;;8=3 +CCM^8604;;;9=@kcolcr#',Nzyay +CCM^8604;;;:=[hss(uyp~if(oan}"iiu(nauo,nfd{lf"fp`ajaafi+encd|{'rn(uu`iix{m{gb{'cy|ta`~,`n.bzgju!nton*xcax.Xkna+Dprrbixbfl.qgr'`hdc.#*\gmj}n.ahhuiet#sc~z+}dhvpgsm&pqezbln|+hmu&imjp- +CCM^8604;;:9=2 +CCM^8604;4;8=0 +CCM^8604;4;9=@kcolcr#',Nzyay +CCM^8604;4;:=Voc!m~tqkoad`+~phed{u tk+kj`hknkce(deee~n(jbg.ma&u`c j~if{+yn|g'cy|ta`~io&+.Raw'k`q&nfoh+|d.y{l'rim&e{~~jkgd`"wtnkcsp*mlib`% +CCM^8604;4:9=2 +CCM^8604;5;8=3 +CCM^8604;5;9=@kcolcr#',Nzyay +CCM^8604;5;:=Voc!nolf*eelbmjzgc&cmjot*od}gj+`ms&cm&e{~~jkko "'Ou(kaz*mgznoow"ec!ah vyi+jr.fg'ux{ren*cy(gahegc&cq&amexcmy.j~rkobirild"+A.|gnk&cm&shc|{mo +CCM^8604;5:9=4625 +CCM^86048<;8=3 +CCM^86048<;9=@kcolcr#',Nzyay +CCM^86048<;:=Ci&dztoq*chk~|ykf'btzond*xcm+kszpfeuain#z~dkn}x "'Rim&aqidb~n.mgnb.r!&mbs,im+jjcc`ce&& Sfij{n.dlvfoo(g exix`+md~{'gol&tqs,jojge +CCM^86048<:9=2 +CCM^86048;8=3 +CCM^86048;9=@kcolcr#',Nzyay +CCM^86048;:=Uoomm&e{~~jkgei"nrdeu b*hj|j.n|pht!`gs#eoh}y|nj,'Riau Po`m%Nv|cdrhfa yc|+nbbn.of!jc gkajonj%."Wjdiue#enib`+o"atd{n `e|r(j`o.vu!iaajd" +CCM^86048:9=4625 +CCM^86048>;8=3 +CCM^86048>;9=@kcolcr#',Nzyay +CCM^86048>;:=Uoomm&e{~~jkgei"nrdeu wbiym+yj}l r!mhovmd+zdaf.mi&u`c goaeogmi&ezovf$,+Qd{+cc~&omcd#~c+zncdxg'unec ec`n{+lnhmuc!qiu#ime(nv|cdr!ijl#ej+|ck+gvbkr& +CCM^86048>:9=2 +CCM^86048?;8=0 +CCM^86048?;9=@kcolcr#',\iy`b`e +CCM^86048?;:=Uoomm&e{~~jkgei"nrdeu excf(fn.Qbjg%Cxwxmh|b`l.xnv!nolf*den.bzgju!crf*`a{~nj, +CCM^86048?:9=2 +CCM^860488;8=0 +CCM^860488;9=@kcolcr#',Bfmayccsonf +CCM^860488;:=Ckj!areny,|myk+}wded{ufvf`r(nv|cdrdl( +CCM^860488:9=2 +CCM^860489;8=3 +CCM^860489;9=Kiouagljpi +CCM^860489;:=Rucqitimm,mgy.Nvvugb|oom$,+Xgkj}g'Q`ar. +CCM^860489:9=2 +CCM^86048:;8=3 +CCM^86048:;9=@kcolcr#',Nzyay +CCM^86048:;:=Ci&dztoq*{j{+kemmrhumteg*{cagk+~pbv`zond*jdz+kszpfeuain-*,[dnoxk"dio|gcw*ud}y.xadsq`zc sxc}aoky.dht!`cls$ +CCM^86048::9=2 +CCM^860484;8=3 +CCM^860484;9=@kcolcr#',H`daxk"Aimlcr#Fchigd` +CCM^860484:9=2 +CCM^86048498=Fntdkroqcix +CCM^86048499=Fuowmu +CCM^860485;8=3 +CCM^860485;9=@kcolcr#',Xmgkhz"@tn}v ee~+[cayzarrr +CCM^860485:9=2 +CCM^86048598=Girdz&oq*ndnm.c'asgsp#dmfm+hd|"nhr|glocbl(xfd|vdsu{( +CCM^86049<;8=3 +CCM^86049<;9=@kcolcr#',Nzyay +CCM^86049<;:=Ci&dztoq*chk~|ykf'qiaje#kxmf~gl`&ug&imyxjdg.xfmurb}rs- +CCM^86049<:9=2 +CCM^86049;8=3 +CCM^86049;9=@kcolcr#',Ymz{n}v +CCM^86049;:=Mic!gt ne~n(mggkq'qdzc jdigbnj"sn`|&rf{ybzn.rawu&rqutfg,g+ln.pbuuittfn" +CCM^86049:9=2 +CCM^8604998=Pbuuitt#,Bd +CCM^8604999=Pbuuitt#,@j|n| +CCM^86049>;8=3 +CCM^86049>;9=@kcolcr#',Ymz{n}v +CCM^86049>;:=Rkc`{c jdnz.]anrkd(Hunhiy(.j+glsi!|ne#xifg}oibg'bsape- +CCM^86049>:9=67?7 +CCM^86049?;8=3 +CCM^86049?;9=@kcolcr#',Nzyay +CCM^86049?;:=[hs!`gvf*ee{n|kf'rim&wqebl(]ag{ob(!(Vlfkn(hfnmi'rim&mfnej(j`o.vu!iaajd" +CCM^86049?:9=2 +CCM^860498;8=3 +CCM^860498;9=@kcolcr#',Nzyay +CCM^860498;:=Voc!losh*ex(ea.pbgeq&flx,jkhkx},'&Qdcapo,h`nm`.vh&lime#yyym+zcov'rim&mfnej(b}+ypnrd(cnbh`nl+oej"wtnxcros,bfxkyzgc&hfro#~dn(o|bxg) +CCM^860498:9=2 +CCM^860::?31=Ahhgatm +CCM^860::?28='t&iiu mex+jnke.qbrtx( Bxi+qd{+}wuc!qiu#}me|+zd.gou7 +CCM^860::>31=Gutnz +CCM^860::>28=Qbrtx&hby,bfky`ck&dztoq$,[dnoxk"dio|gcw*ud}y.xadsq`zc sxc}aoky.dht!`cls$ +CCM^860::<;8=1 +CCM^8603:;9=^[udzpeqVdden}Wa`mZcdcngo~&kykjzmu+3&~x.}eeldyx gc +CCM^8603:;8=AZEGEUNOr:Tm|j`i[JNKGLPtW\nc{Rqa~EN(zjz +CCM^8603:4;8=2 +CCM^8603:9;8=2 +CCM^8603:9;9=2 +CCM^8603:9;:=2 +CCM^8603:;;=^[udzpeqVdden}Wjgqcmgv\qo`nixkWykibnu\jdigbn|^76/ahswk`gmy bmm<6 +CCM^860334;8=2 +CCM^860334;9=2 +CCM^860339;8= +CCM^8603:8;;=2 +CCM^860::>=3 +CCM^860::38=3 +CCM^860::<;=>Nhr|gloLcgln|5RWioo{raof"npn +CCM^860::<;?=3 +CCM^860::<;1=3 +CCM^860::<9=JLCXWELBY_N[T\DAV[(cdcng1$Ommo~bv.zICCY\I@J[XKXQPHIUTdlfdhmagk0&Fb``}jt*vD@MRQHBCTUD[YRLEXWjgkejdnjdTuhff`Wg{keRahklihd8"Hnnj{gz+{NJM__@FMX[N]T\MHR]jjemnjbdnROkdfsm|Ocld7#Lnhj{ns/}@MEZU@DKJBTCCDNHFC\Pejj|nROnesguoe~P\aejdyq[Etztem~Znzxgd`^Rhhfutbf`WJgkejguEaupokuEifkwFIB_^DICBFSFIHFB@G[UnnrwbxiWEbmyaqh`uTQimnc|{WM~|pbhu^crpcceT^`b`qsgmdZBoobomy5^`kiuuijlP~~bflr +CCM^860::<;0=>Nhr|gloLcgln|5R@kcolcr-otnt7Ge}vfjmNilgo~5THa{wpnai|(t{~p7Ae}onk@ndbeq4PYmjjfk,s~ut:ImyxjdgHdbfbt?TNeoz"~zg505~;Oo{raofJddoky0^wu`in1:"odg505~ +CCM^860::>;=3 +CCM^860::8=3502:455 +CCM^860::?= +CCM^860::?>= +CCM^860::?0=2 +CCM^860::>:=3 +CCM^860::?=1 +CCM^860::0=3 +CCM^860::>3=2 +CCM^860::=>WtnotanLegmx0WLnbhemt +CCM^860::>=@kcolcr-otn37Ge}vfjmNilgo~5TIbn`fbt/m~e8:7;3;505~Diqqtidbx%|sz02KiuuijlEe`omy0WMmwsaahw$xs|0>0>97:3zRfkhfm%zsz9;Oo{raofJddoky0^Uc`lke-~t3;5;52<:tNeoz"~zg57Gltr`djFlfhnz5RCknw(tzj;31<08050rr~righ23$hgd02B`qsgmd@ooniy6W~rzjhh38(dof7;3;5;593>=3 +CCM^860::>3?=2 +CCM^860::<8=3 +CCM^860::>?8=2 +CCM^860::<9=3 +CCM^860::>?9=2 +CCM^860::<:=3 +CCM^860::>?:=2 +CCM^860::<;=3 +CCM^860::>?;=2 +CCM^860::<<=3 +CCM^860::>?<=2 +CCM^860::<=2 +CCM^860::>?=2 +CCM^860::<>=3 +CCM^860::>?>=2 +CCM^860::9=Lhr!i&Nvgnnz +CCM^860:::= +CCM^860::;=upq/jjemniy&eb +CCM^860::<= +CCM^860::>1=@kcolcr#Zyidb}ckp +CCM^860::8=0)43 +CCM^860::9>9=2 +CCM^860::9>:=3 +CCM^860::9><=3 +CCM^860::9>=3 +CCM^860::5<<=2 +CCM^860::9>?= +CCM^860::<8;=2 +CCM^860::<8<= +CCM^860::<8=>Nhr|gloLcgln|5RJbjq&sro +CCM^860::<8>= +CCM^860::831=2 +CCM^860::59=^[udzpeqVdden}Wjgqcmgv\qo`nixkWykibnu\sngWb`xzckjdzZ02$ee{ogbgu(cev +CCM^860::5:= +CCM^860::5;=2 +CCM^860::<9>=3 +CCM^860::<9?=3 +CCM^860::5<=2 +CCM^860::5=2 +CCM^860::5>=3 +CCM^860::5<=2 +CCM^860::5<>=2 +CCM^860::5=3 +CCM^860::52?=>Nhr|gloLcgln|5R@FEJ]V +CCM^860::520=2 +CCM^860::>>=2 +CCM^860::>?=2 +CCM^8603:?;:=3 +CCM^8603:?;;=2 +CCM^8603:>;:=>FBUmkp +CCM^8603:;;>=2 +CCM^860::9>;=JLCXWELBY_N[T\DAV[(cdcng1$Ommo~bv.cdcnglegm0]|kia}@MEZUOGIX]N]]UIN\Zboobonbbn5*Ccgislw#7Idn`okp'@hdc;P~~bflrCEG^YBDGSPO_TZDA_R`kcol`iooPx`nbgRmwcoTeongmel0&Okdfsm|/;!6Ee{ogbDhjemt>_H`nfoky gc#($%2(7X|ygei~OMDQYCOK_XMXQYAMSZcdcnglegmWJnhcrjuAeom1$Ommo~bv.#4Onp~mgdMagjgu8]Jjemniy&nvn,.6R|timmpCCNWTBMDGMWKA@BEEMW]dhvpgsmZMji~d{dhRUnhegqs_Iyyzn`Xguuhgh\Vdee{ogb^Ejdfbeq1Hb{{bjwLfkd3Dlfdhnz0]|kia}@MEZU@DKJBTCCDNHFC\Pejj|nROnesguoe~P\aejdyq[Etztem~Znzxgd`^Rhhfutbf`WJgkejguTfonp~mgdXzygl`Ahswk`gNdbokp9ZTfonp~mgd%ksk9Trsahg +CCM^860::28=Ubjbgke +CCM^860::>:8=^[udzpeqVdden}Wjgqcmgv\qo`nixkWykibnu\sngWb`xzckjdzZ02${ndhafk,urg +CCM^860::>8=2 +CCM^860::521=[bu +CCM^860:;<;8=Lh +CCM^860::829=Rkc`{c qomo(fn.dhjmgqimm,Gahke}g'Gfzcenob&+.^}g'rim&s`xcgd+lj|"si!~oet*xcm+|n}v'ig(rhf*hdk~cn`v) +CCM^860::9:9=Fh&xgs bionx.jbn'rim&tfxax(dh+zjb&qzccfneeo+Bbmgiud(Ggqoifmez4."N`!qiu#iddgxk+@m+&rmrus*{bdg.hbmtc/(&Tl*ee{ogb"snd(vrlm~je'.raw'kt{r bionx.fkt&`otefgie|% +CCM^860::29=Nnedfue#Kkymncn`v +CCM^860::>:9=^[udzpeqVdden}Wjgqcmgv\qo`nixkWykibnu\sngWb`xzckjdzZ01$odxr|bijs(upr +CCM^860::>9=3 +CCM^860::2:=Ceit|&Boobomy.H|gfrnz +CCM^860::>::=^[udzpeqVdden}Wjgqcmgv\qo`nixkWykibnu\sngWb`xzckjdzZ00$~niocn vr +CCM^860::>:=2 +CCM^860::82;=Kiuuijlb~edf+Hdbfbt +CCM^860::9:;=Wtc!|ne#lendo.iknhq!|i pzihamw+zjb&ggjdfx,|`n|n.{hs!gnw*xcm+o{~nne`|oom*jbdn}+zm'dd(eoscio(a%.Vh&rxccjlu+i+jbhdbtdfr ee`omy"+z{wc!i&nf},eifk'.mu&t{c wbi+Ti.I|mpudTd0#*n~|ae.vh&rmje`~,jf+ksgqsooo&flfhnz%.+^pbur(Zb#Dis|Wl;."si!kinwcb~m% +CCM^860::2;=Aoin{c Pox~x+Hdbfbt +CCM^860::>:;=^[udzpeqVdden}Wjgqcmgv\qo`nixkWykibnu\sngWb`xzckjdzZ07$jddoky ps` +CCM^860::>;=2 +CCM^860::82<=Uhtjahg +CCM^860::9:<=Rkc`{c tke(|fbbg'#r(os#yi}{.d`"~itz&clg|~|n|% +CCM^860::2<=Qbrtx&Pqekymx} +CCM^860::>:<=^[udzpeqVdden}Wjgqcmgv\qo`nixkWykibnu\sngWb`xzckjdzZ06$|ygl|n}q)tun +CCM^860::><=2 +CCM^860::82>=Qbrtx&wby,x}hmn}qasm +CCM^860::9:>='t&viu pohmx}m{nk!{ctvz,df+wd{p'enevuwo~%(+^ykqt&]j&Fjdex`Wl;."si!m~iw*n|~~% +CCM^860::98>=Qsgs|&Boobomy.[{`kor`cr +CCM^860::>3;=>Nhr|gloLcgln|5R`kcolcr-otn +CCM^860::>3<=2 +CCM^860::>39=3 +CCM^860::2>=Qbrtx&Clg|gmk +CCM^860::>:>=^[udzpeqVdden}Wjgqcmgv\qo`nixkWykibnu\sngWb`xzckjdzZ05$ode{bnzg)tun +CCM^860::>>=2 +CCM^860::<:8=Wioo{raofiy +CCM^860::<:9=Voc!}himyxjdg.{|m`t`e&wjf`+zncdxg'`hdcs#kbo(magjguu-(uhlxxh}}'.cib!zcgjyxyq+kezpncr(`rlg,`n.ogql(!(Grf*ud}+}~|g'n}&wbdx+|d.~`kiuuijl< +CCM^860::<::=Mic!g` `ea{gekezq'or(gcwczn&+.Nvks&u`c sxclzjc+lgaism&swk~aei+[lnhr|glo$ +CCM^860::<:;=Wioo{raof,x}hmn}qasmd! +CCM^860::<:<=Ci&dztoq*chk~|ykf'qiaje#~~raei+zm'soahswk`g(fn.ruifzgm-*,^fb`xzckj!`gs#hinf+mj`abjdl( +CCM^860::><=Qbrtx +CCM^860::<9;=Lhr!i&Nvgnnzwrwr~{Dmmhdfx,[}ibb}jbt}:(21v +CCM^860::<;:=Giamauh#',^fbznj"Tr`|cs +CCM^860::<;9=3752 +CCM^860:;<;9=^[udzpeqVdden}Wa`mZcdcngo~&b`oautZ+&, \ No newline at end of file diff --git a/release/windows/publ_installer/00.installer.ico b/release/windows/publ_installer/00.installer.ico new file mode 100644 index 0000000000000000000000000000000000000000..4daf11eb821ecf17b354150d78c97da19bbf943c GIT binary patch literal 1078 zcma))zmC&D5XQ%Mkqp)54dM!2Peo;l2s(HR>XSf3Q3|`mR|P4>$#TJCAXn!{aY>ot zBqvIg;Wx8^3#V|p&))g_&Ft>jB8gnccsv%vRU+~Von_Jgbs_SB*cCC0WUNF+NRiIv zIZ=x6N?AsQ#FVb<(3VhtMb#`8kA+Ogi>k^{7%oMsG8#+E5?*R)dQ*K{qQX#Bx~6!z zsbPfA+uPkO%mbsnoc)sP zFb6I#C3Z)ww;UYfTFpV@oHA%{ojO9oXNKodk|e`STp=-^IVb8KV`jL196j})&Zbs> zLQg-c4*&Oq=NZBg8hwWD2%1i()Axa?I8?oVu&)JzMk9W8|N58?Bal|zylGz-Xnc1Y zu)aO|WjlPz)VN#YQCOPLrM!b@VJn_=6=eZGKPO^2RfMtV^h+kM*q*>aU#K2be*-p-GF$)v literal 0 HcmV?d00001 diff --git a/release/windows/publ_installer/01.installer.bmp b/release/windows/publ_installer/01.installer.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d62832c0101560bd1def26b1ec524c789f872145 GIT binary patch literal 612 zcmXw$T}YDw6o#KK6q5+VZi)g6D#D8{O1kJO1*1Quj1hy#E{segS<_HSAyWb=EVUmM zMVpF0LutBAT{?e0b<3O$XJwi;(4{n-IA@!~);FVbc+Yvy%Q@%boVbLpOt$S*2pp4G zwuDs)0z0?$V2IrH5C4TgAOI4AE|DM&rtK=&)1b0q8kuM2^Cqs9byj}CqG`W2k$66Lm!@`HDm|bxP(wyhPiOE8Vq_<=Gy3J1TJem|(#^ z&HStl_v#WZ=K{)Wg0x$@4y~c|6bZY;D#GaP}bvn zd{1wNCA7w-LR)du(01QC<1vJ0t+jU zg9_RxG~#A<6`~o{?P*VMP5X~>k6ELmq%!aB_833Ekvg&kVWvU?xiT!+YpcP?^9SWk YWO{yjT9)P1@6UYpCzr4gt`h|L_sUKHFN6g099;6M zviMf%Sa>ORIJVtOryP0T%r)qEY@2>}RX#-#6Y8T;zD!(-^7f>2A!+cQS%b7g&-$_X9^C6LYg26WgyG` za&Ij>rW0ktC5@PL6zl`Vs>NY6flKYpm?79SFuD5K;%oJ2IQG5@DtXWI47m&hjYt!s z{w1W0@sUOu>~oq5)zp9)Md}`NEDB@=I)ctzgyZpH+pZfOGL?dA_@uKed^2vX^CP@Xb`8?1m1DZZW7h zVE?bk4jw+P*@*o%A;lIqJMNZLBB+Wp)QK&@&5|1^!oBpC)3h2VSPx48@8IK01npm; LWQxaqXK4;!cd||2 literal 0 HcmV?d00001 diff --git a/release/windows/publ_installer/06.complete.rtf b/release/windows/publ_installer/06.complete.rtf new file mode 100644 index 0000000000000000000000000000000000000000..d901313ec1a0dc82e38bb8eeaa2e0ec2141a668f GIT binary patch literal 431 zcmaKnu};J=42GHSDf|EkwdI(YU_iRaxPEyEo`VzGWHzrW8p zn=GLqz!`k1R=ez-D@SruR$yb&uyO#qUhh|L0j1(tiIun<>-g=7R`?Z!wvtPY6e zkqg3vryI*5Y>#~cPNG+`{3ppYjH1ou9_ENvX $DISTDIR/Readme.txt +#rm -f $DISTDIR/README +cp -f ../text/Blender.html $DISTDIR/Blender.html + +# Create ^M in copyright.txt +awk '{printf("%s\r\n", $0);}' $DISTDIR/copyright.txt > $DISTDIR/aCopyright.txt +rm -f $DISTDIR/copyright.txt +mv -f $DISTDIR/aCopyright.txt $DISTDIR/Copyright.txt +# PS. the whole aCopyright kludge is because of windows being braindead + +# Create ^M in copyright.txt +awk '{printf("%s\r\n", $0);}' $DISTDIR/GPL-license.txt > $DISTDIR/temp.txt +mv -f $DISTDIR/temp.txt $DISTDIR/GPL-license.txt + +# Add Release info text +cp -f ../text/Release_$SHORTVERS.txt $DISTDIR/Release_$SHORTVERS.txt +awk '{printf("%s\r\n", $0);}' $DISTDIR/Release_$SHORTVERS.txt > $DISTDIR/temp.txt +mv -f $DISTDIR/temp.txt $DISTDIR/Release_$SHORTVERS.txt + +# Add Python DLL to package +# Stupid windows needs the . removed : +PVERS=`echo $NAN_PYTHON_VERSION | sed 's/\.//'` +cp -f $NAN_PYTHON/lib/python$PVERS.dll $DISTDIR/python$PVERS.dll +chmod +x $DISTDIR/python$PVERS.dll + +#Add pthreads dll to package +cp -f $NAN_PTHREADS/lib/pthreadGC2.dll $DISTDIR/pthreadGC2.dll + +# Add fmod DLL to package +# cp -f $NAN_FMOD/lib/fmod.dll $DISTDIR/fmod.dll +# chmod +x $DISTDIR/fmod.dll + +# Add gettext DLL to package +cp -f $NAN_GETTEXT/lib/gnu_gettext.dll $DISTDIR/gnu_gettext.dll + +# Add SDL DLL to package +cp -f $NAN_SDL/lib/sdl.dll $DISTDIR/sdl.dll + +# Add the Help.url to the ditribution +cp -f extra/Help.url $DISTDIR/ + +# Add Python23.zip & zlib.pyd +cp -f extra/Python23.zip $DISTDIR/ +cp -f extra/zlib.pyd $DISTDIR/ + +# Add the language files to package +cp -f -R $NAN_OBJDIR/windows/bin/.blender $DISTDIR/ +# Remove the pesky CVS dirs +find $DISTDIR/.blender -name CVS -prune -exec rm -rf {} \; + +# Add .bfont.ttf and .Blanguages +cp -f $NANBLENDERHOME/bin/.blender/.bfont.ttf $DISTDIR/.blender/.bfont.ttf +cp -f $NANBLENDERHOME/bin/.blender/.Blanguages $DISTDIR/.blender/.Blanguages + +# make the installer package with NSIS +NSIS="$PROGRAMFILES/NSIS/makensis.exe" +if (`test -x "$NSIS"`) then + cd installer + TEMPFILE=00.blender_tmp.nsi + DISTDIR=`cygpath -m $DISTDIR` + # make a installer config for this release + cat 00.blender.nsi | sed "s|VERSION|$VERSION|g" | sed "s|DISTDIR|$DISTDIR|g" | sed "s|SHORTVERS|$SHORTVERS|g" | sed "s|MUI_$VERSION|MUI_VERSION|g" > $TEMPFILE + "$NSIS" $TEMPFILE + rm $TEMPFILE +fi diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt new file mode 100644 index 00000000000..9da00ddfc0d --- /dev/null +++ b/source/CMakeLists.txt @@ -0,0 +1,38 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SUBDIRS(blender kernel) + +IF(WITH_GAMEENGINE) + SUBDIRS(gameengine) +ENDIF(WITH_GAMEENGINE) + +IF(WINDOWS) + SUBDIRS(icons) +ENDIF(WINDOWS) diff --git a/source/Makefile b/source/Makefile new file mode 100644 index 00000000000..5161f6b73c5 --- /dev/null +++ b/source/Makefile @@ -0,0 +1,648 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# Top level makefile. Start looping through subdirs and link.... +# + +ifndef NANENV + export NANENV := $(shell env | grep NAN_) +endif + +include nan_definitions.mk + +DIRS = creator blender kernel + +ifneq ($(NAN_NO_KETSJI),true) + DIRS += gameengine +endif + +ifeq ($(OS),windows) + DIRS += icons +endif + +########## buildinfo kludge ################### +CPPFLAGS += -I../Physics/common +CPPFLAGS += -I../Physics/Dummy +ifdef NAN_BUILDINFO + BUILDINFO_O = $(DIR)/$(DEBUG_DIR)buildinfo.o + BUILDINFO_C = $(SRCHOME)/creator/buildinfo.c + BUILD_DATE := $(shell date "+%Y-%m-%d") + BUILD_TIME := $(shell date "+%H:%M:%S") +endif + +############# set pyplayerlib ################## + +PYPLAYERLIB ?= $(PYLIB) + +############# libraries ################## +# COMLIB COMmon LIBraries for all targets +# BPLIB Browser Plugin LIBraries +# SPLIB1 Standalone Player LIBraries (pre COMLIB) +# SPLIB Standalone Player LIBraries (post COMLIB) +# PULIB PUblisher LIBraries +# GRPLIB Gui and Render LIBraries for Publisher +# LLIBS dynamic system libraries +# SADD Static OpenGL libraries +# DADD Dynamic OpenGL libraries +# NSPLUGLIB PLUGin LIBraries for ns-style api +# PLUGAPPLIB libs that form the application to be plugged in +# Note: the order is important here + +GRPLIB = $(OCGDIR)/creator/$(DEBUG_DIR)libcreator.a +GRPLIB += $(OCGDIR)/blender/src/$(DEBUG_DIR)libsrcpublisher.a +GRPLIB += $(NAN_BSP)/lib/$(DEBUG_DIR)libbsp.a +GRPLIB += $(NAN_BOOLOP)/lib/$(DEBUG_DIR)libboolop.a +GRPLIB += $(NAN_SOUNDSYSTEM)/lib/$(DEBUG_DIR)libSoundSystem.a +GRPLIB += $(NAN_GHOST)/lib/$(DEBUG_DIR)libghost.a +GRPLIB += $(NAN_STRING)/lib/$(DEBUG_DIR)libstring.a +GRPLIB += $(OCGDIR)/blender/render/$(DEBUG_DIR)librender.a +GRPLIB += $(OCGDIR)/blender/radiosity/$(DEBUG_DIR)libradiosity.a +GRPLIB += $(NAN_OPENNL)/lib/$(DEBUG_DIR)libopennl.a +GRPLIB += $(NAN_SUPERLU)/lib/$(DEBUG_DIR)libsuperlu.a +GRPLIB += $(OCGDIR)/blender/python/$(DEBUG_DIR)libpython.a + +# nlin: the reason that some libraries appear more than once below is +# to handle circular dependencies in linking among libraries... some +# linkers (e.g. under Linux) need libs to be specified multiple times +# to properly resolve circular dependencies. ugly, but it works... +# the repeat entries could probably be trimmed down. +COMLIB = $(OCGDIR)/blender/blenkernel/$(DEBUG_DIR)libblenkernel.a +COMLIB += $(NAN_DECIMATION)/lib/libdecimation.a +COMLIB += $(OCGDIR)/blender/blenloader/$(DEBUG_DIR)libblenloader.a +COMLIB += $(OCGDIR)/blender/blenpluginapi/$(DEBUG_DIR)libblenpluginapi.a +COMLIB += $(OCGDIR)/blender/nodes_shd/$(DEBUG_DIR)libnodes_shd.a +COMLIB += $(OCGDIR)/blender/nodes_cmp/$(DEBUG_DIR)libnodes_cmp.a +COMLIB += $(OCGDIR)/blender/nodes/$(DEBUG_DIR)libnodes.a +COMLIB += $(OCGDIR)/blender/imbuf/$(DEBUG_DIR)libimbuf.a +COMLIB += $(OCGDIR)/blender/blenlib/$(DEBUG_DIR)libblenlib.a +COMLIB += $(OCGDIR)/blender/avi/$(DEBUG_DIR)libavi.a +COMLIB += $(NAN_JPEG)/lib/libjpeg.a + +ifneq ($(NAN_NO_KETSJI),true) + COMLIB += $(OCGDIR)/gameengine/bloutines/$(DEBUG_DIR)libbloutines.a + COMLIB += $(OCGDIR)/gameengine/blconverter/$(DEBUG_DIR)libblconverter.a + COMLIB += $(OCGDIR)/gameengine/blphys/common/$(DEBUG_DIR)libcommon.a + COMLIB += $(OCGDIR)/gameengine/ketsji/$(DEBUG_DIR)libketsji.a + COMLIB += $(OCGDIR)/gameengine/blconverter/$(DEBUG_DIR)libblconverter.a + COMLIB += $(OCGDIR)/gameengine/blconverter/$(DEBUG_DIR)libblconverter.a + COMLIB += $(NAN_SOLID)/lib/libsolid.a + COMLIB += $(NAN_SOLID)/lib/libsolid_broad.a + COMLIB += $(NAN_SOLID)/lib/libsolid_complex.a + COMLIB += $(NAN_SOLID)/lib/libsolid_convex.a + COMLIB += $(OCGDIR)/gameengine/blphys/sumo/$(DEBUG_DIR)libsumo.a + COMLIB += $(OCGDIR)/gameengine/blphys/fuzzics/$(DEBUG_DIR)libfuzzics.a + COMLIB += $(NAN_QHULL)/lib/libqhull.a + COMLIB += $(OCGDIR)/gameengine/blphys/dummy/$(DEBUG_DIR)libdummy.a + COMLIB += $(OCGDIR)/gameengine/blphys/common/$(DEBUG_DIR)libcommon.a +# COMLIB += $(OCGDIR)/gameengine/blphys/sumo/$(DEBUG_DIR)libsumo.a + COMLIB += $(OCGDIR)/gameengine/blphys/dummy/$(DEBUG_DIR)libdummy.a + COMLIB += $(OCGDIR)/gameengine/ketsji/$(DEBUG_DIR)libketsji.a + COMLIB += $(OCGDIR)/gameengine/blphys/common/$(DEBUG_DIR)libcommon.a +# COMLIB += $(OCGDIR)/gameengine/blphys/blode/$(DEBUG_DIR)libblode.a +# COMLIB += $(OCGDIR)/gameengine/blphys/sumo/$(DEBUG_DIR)libsumo.a + COMLIB += $(OCGDIR)/gameengine/blphys/dummy/$(DEBUG_DIR)libdummy.a + COMLIB += $(OCGDIR)/gameengine/blphys/blbullet/$(DEBUG_DIR)libblbullet.a + COMLIB += $(OCGDIR)/gameengine/blphys/common/$(DEBUG_DIR)libcommon.a +# COMLIB += $(OCGDIR)/gameengine/blphys/sumo/$(DEBUG_DIR)libsumo.a + COMLIB += $(OCGDIR)/gameengine/blphys/dummy/$(DEBUG_DIR)libdummy.a + COMLIB += $(OCGDIR)/gameengine/ketsji/$(DEBUG_DIR)libketsji.a + COMLIB += $(OCGDIR)/gameengine/logic/$(DEBUG_DIR)liblogic.a + COMLIB += $(OCGDIR)/gameengine/logic/Joystick/$(DEBUG_DIR)libJoystick.a + COMLIB += $(OCGDIR)/gameengine/rasterizer/$(DEBUG_DIR)librasterizer.a + COMLIB += $(OCGDIR)/gameengine/OpenGLrasterizer/$(DEBUG_DIR)libOpenGLrasterizer.a + COMLIB += $(OCGDIR)/gameengine/expression/$(DEBUG_DIR)libexpression.a + COMLIB += $(OCGDIR)/gameengine/scenegraph/$(DEBUG_DIR)libscenegraph.a +# COMLIB += $(OCGDIR)/sumo/$(DEBUG_DIR)libfuzzics.a +# COMLIB += $(OCGDIR)/sumo/$(DEBUG_DIR)libsolid.a + COMLIB += $(NAN_MOTO)/lib/libmoto.a + COMLIB += $(NAN_SND_LIBS) + COMLIB += $(OCGDIR)/kernel/gen_system/$(DEBUG_DIR)libgen_system.a + COMLIB += $(OCGDIR)/kernel/gen_messaging/$(DEBUG_DIR)libgen_messaging.a + COMLIB += $(OCGDIR)/gameengine/ketsji/KXNetwork/$(DEBUG_DIR)libKXNetwork.a + COMLIB += $(OCGDIR)/gameengine/Network/$(DEBUG_DIR)libNetwork.a + COMLIB += $(OCGDIR)/gameengine/Network/LoopBackNetwork/$(DEBUG_DIR)libLoopBackNetwork.a + COMLIB += $(NAN_BULLET2)/lib/libbullet2.a +endif + +COMLIB += $(NAN_GUARDEDALLOC)/lib/libguardedalloc.a +COMLIB += $(NAN_MEMUTIL)/lib/libmemutil.a +COMLIB += $(NAN_BMFONT)/lib/$(DEBUG_DIR)libbmfont.a +COMLIB += $(NAN_PNG)/lib/libpng.a +COMLIB += $(OCGDIR)/blender/yafray/$(DEBUG_DIR)libyafrayexport.a +COMLIB += $(OCGDIR)/blender/blenlib/$(DEBUG_DIR)libblenlib.a + +ifeq ($(WITH_QUICKTIME), true) + COMLIB += $(OCGDIR)/blender/blenderqt/$(DEBUG_DIR)libblenderqt.a +endif + +ifeq ($(WITH_OPENEXR), true) + COMLIB += $(OCGDIR)/blender/imbuf/openexr/$(DEBUG_DIR)libopenexr.a +endif + +COMLIB += $(OCGDIR)/blender/imbuf/cineon/$(DEBUG_DIR)libcineon.a + +ifeq ($(WITH_DDS), true) + COMLIB += $(OCGDIR)/blender/imbuf/dds/$(DEBUG_DIR)libdds.a +endif + +ifeq ($(WITH_FREETYPE2), true) + ifeq ($(OS), windows) + ifeq ($(FREE_WINDOWS), true) + COMLIB += $(NAN_FREETYPE)/lib/libfreetype.a + else + COMLIB += $(NAN_FREETYPE)/lib/freetype2ST.lib + endif + else + ifeq ($(OS), irix) + COMLIB += $(NAN_FREETYPE)/lib32/libfreetype.a + else + COMLIB += $(NAN_FREETYPE)/lib/libfreetype.a + endif + endif +endif + +ifeq ($(INTERNATIONAL), true) + COMLIB += $(OCGDIR)/blender/ftfont/$(DEBUG_DIR)libftfont.a + ifeq ($(OS), windows) + ifeq ($(FREE_WINDOWS), true) + COMLIB += $(NAN_GETTEXT)/lib/freegettext.a + COMLIB += $(NAN_FTGL)/lib/libftgl.a + #COMLIB += $(NAN_ICONV)/lib/freeiconv.a + else + COMLIB += $(NAN_GETTEXT)/lib/gnu_gettext.lib + COMLIB += $(NAN_FTGL)/lib/ftgl_static_ST.lib + COMLIB += $(NAN_FREETYPE)/lib/freetype2ST.lib + COMLIB += $(NAN_ICONV)/lib/iconv.lib + endif + else + COMLIB += $(NAN_FTGL)/lib/libftgl.a + ifeq ($(OS), irix) + COMLIB += $(NAN_FREETYPE)/lib32/libfreetype.a + COMLIB += $(NAN_FREETYPE)/lib32/libintl.a + else + COMLIB += $(NAN_FREETYPE)/lib/libfreetype.a + endif + endif + ifeq ($(OS), darwin) + COMLIB += $(NAN_GETTEXT)/lib/libintl.a + ifeq ($(CPU), i386) + COMLIB += $(NAN_GETTEXT)/lib/libiconv.a + endif + endif + ifeq ($(OS), solaris) + COMLIB += $(NAN_GETTEXT)/lib/libintl.a + endif +endif + +ifeq ($(WITH_VERSE), true) + ifeq ($(OS), windows) + ifeq ($(FREE_WINDOWS), true) + COMLIB += $(NAN_VERSE)/lib/libverse.a + else + COMLIB += $(NAN_VERSE)/lib/verse.lib + endif + else + COMLIB += $(NAN_VERSE)/lib/libverse.a + endif +endif + +ifeq ($(OS), irix) + COMLIB += $(NAN_SDL)/lib/libSDL.a +endif + +ifeq ($(OS), windows) + ifeq ($(FREE_WINDOWS), true) + COMLIB += $(NAN_SDL)/lib/libSDL.a + COMLIB += $(NAN_PTHREADS)/lib/libpthreadGC2.a + else + COMLIB += $(NAN_SDL)/lib/SDL.lib + endif +endif + +ifeq ($(WITH_OPENEXR), true) + COMLIB += $(NAN_OPENEXR_LIBS) +endif + +PULIB = $(NAN_IKSOLVER)/lib/libiksolver.a +PULIB += $(NAN_MOTO)/lib/libmoto.a +PULIB += $(NAN_ELBEEM)/lib/$(DEBUG_DIR)libelbeem.a +PULIB += $(OCGDIR)/blender/readblenfile/$(DEBUG_DIR)libreadblenfile.a +PULIB += $(OCGDIR)/blender/src/$(DEBUG_DIR)libsrcpublisher.a + +ifeq ($(NAN_NO_KETSJI),true) + PULIB += $(NAN_MOTO)/lib/libmoto.a + PULIB += $(OCGDIR)/kernel/gen_system/$(DEBUG_DIR)libgen_system.a + PULIB += $(OCGDIR)/kernel/gen_messaging/$(DEBUG_DIR)libgen_messaging.a + COMLIB += $(NAN_SND_LIBS) +endif + +SPLIB1 = $(OCGDIR)/gameengine/GamePlayer/ghost/$(DEBUG_DIR)libghost.a +SPLIB1 += $(OCGDIR)/gameengine/GamePlayer/common/$(DEBUG_DIR)libcommon.a +SPLIB1 += $(NAN_STRING)/lib/$(DEBUG_DIR)libstring.a +SPLIB1 += $(NAN_GHOST)/lib/$(DEBUG_DIR)libghost.a + +SPLIB = $(OCGDIR)/blender/makesdna/$(DEBUG_DIR)DNA.o +SPLIB += $(OCGDIR)/blender/readblenfile/$(DEBUG_DIR)libreadblenfile.a +# this is used for the plugin. It uses some things from libz.a, +# but somehow it consistently fails to resolve these symbols... or +# can I just not check them? nm claims they aren't... +SPLIB += $(OCGDIR)/blender/blenkernel/blenkernel_blc/$(DEBUG_DIR)libblenkernel_blc.a + +# These three need to be explicitly mentioned on the cl, because +# if they are offered as a lib, they are optimized away. (nzc) +NSPLUGLIB = $(OCGDIR)/gameengine/GamePlayer/netscape/src/$(DEBUG_DIR)UnixShell.o +NSPLUGLIB += $(OCGDIR)/gameengine/GamePlayer/netscape/src/$(DEBUG_DIR)stubs.o +NSPLUGLIB += $(OCGDIR)/gameengine/GamePlayer/netscape/src/$(DEBUG_DIR)winstubs.o +NSPLUGLIB += $(OCGDIR)/gameengine/GamePlayer/netscape/src/$(DEBUG_DIR)Blender3DPlugin_native_implementation.o + +# Here you can configure what sort of test to make for the plugin. +# PLUGTESTLIB = $(OCGDIR)/gameengine/GamePlayer/netscape/test/$(DEBUG_DIR)libns_api_test_stub.a +# PLUGTESTLIB = $(OCGDIR)/gameengine/GamePlayer/netscape/test/$(DEBUG_DIR)libns_api_test_colorcycle.a +# PLUGTESTLIB = $(OCGDIR)/gameengine/GamePlayer/netscape/test/$(DEBUG_DIR)libns_api_test_gears.a +PLUGTESTLIB = $(OCGDIR)/gameengine/GamePlayer/netscape/test/$(DEBUG_DIR)libns_api_test_threaded_gears.a + +# XPCOM is done only for Linux for now +ifeq ($(OS),$(findstring $(OS), "linux")) + ifeq ($(CPU),i386) + NSPLUGLIB += $(OCGDIR)/gameengine/GamePlayer/netscape/src/$(DEBUG_DIR)XPH_xpcom_hooks.o + endif +endif + +PLUGAPPLIB = $(OCGDIR)/gameengine/GamePlayer/netscape/src/$(DEBUG_DIR)libplugin_ketsji_hooks.a + +ifeq ($(OS),$(findstring $(OS), "freebsd linux irix solaris")) + NSPLUGLIB += $(OCGDIR)/gameengine/GamePlayer/netscape/src/$(DEBUG_DIR)PLG_X11_windowing.o + PLUGAPPLIB += $(OCGDIR)/gameengine/GamePlayer/common/unix/$(DEBUG_DIR)libunix.a +endif +ifeq ($(OS),$(findstring $(OS), "windows")) + NSPLUGLIB += $(OCGDIR)/gameengine/GamePlayer/netscape/src/$(DEBUG_DIR)PLG_MSWindows_windowing.o + NSPLUGLIB += $(OCGDIR)/gameengine/GamePlayer/netscape/src/$(DEBUG_DIR)npB3DPlg.res + PLUGAPPLIB += $(OCGDIR)/gameengine/GamePlayer/common/windows/$(DEBUG_DIR)libwindows.a +endif + +PLUGAPPLIB += $(OCGDIR)/gameengine/GamePlayer/common/$(DEBUG_DIR)libcommon.a + +ifeq ($(OS),$(findstring $(OS), "linux")) + ifeq ($(CPU),i386) + PLUGAPPLIB_XPLINK = $(OCGDIR)/gameengine/GamePlayer/netscape/src/$(DEBUG_DIR)_Blender3DPlugin_implementation_.o + endif +endif + +# A bit silly... but needed to resolve symbols. +PLUGREMLIB = $(NAN_STRING)/lib/$(DEBUG_DIR)libstring.a + +######################## OS dependencies (alphabetic!) ################ + +include nan_link.mk + +ifeq ($(NAN_JUST_BLENDERDYNAMIC),true) + BINTARGETS = blenderdynamic +endif + +ifeq ($(WITH_BF_DYNAMICOPENGL), true) + BINTARGETS += blenderdynamic +endif + +ifeq ($(WITH_BF_STATICOPENGL), true) + BINTARGETS += blenderstatic +endif + +ifeq ($(WITH_BF_BLENDERPLAYER), true) + export WITH_BF_GAMEENGINE=true + BINTARGETS += blenderplayer +endif + +ifeq ($(WITH_BF_WEBPLUGIN), true) + ifneq ($(NAN_NO_PLUGIN), true) + BINTARGETS += plugin + ifeq ($(OS),linux) + ifeq ($(CPU),i386) + BINTARGETS += xplink + endif + endif + endif +endif + +ifdef PY_FRAMEWORK + PYLIB = -framework Python +else + PYLIB = $(NAN_PYTHON)/lib/python$(NAN_PYTHON_VERSION)/config/libpython$(NAN_PYTHON_VERSION).a +endif + +ifeq ($(OS),solaris) + PYLIB += $(NAN_ZLIB)/lib/libz.a + PULIB += $(NAN_ZLIB)/lib/libz.a + SPLIB += $(NAN_ZLIB)/lib/libz.a +endif + +# OpenAL libs are already compiled as shared code! Check FMod if we switch to that. (nzc) + +# Some vars to keep the rest of this section mostly readable +# in an 80 char term +SOUNDSYSTEM = $(OCGDIR)/intern/SoundSystem/$(DEBUG_DIR)libSoundSystem.a +DUMMYSOUND = $(OCGDIR)/intern/DummySoundSystem/$(DEBUG_DIR)libDummySoundSystem.a +OPENALSOUND = $(OCGDIR)/intern/OpenALSoundSystem/$(DEBUG_DIR)libOpenALSoundSystem.a +SDLSOUND = $(OCGDIR)/intern/SDLSoundSystem/$(DEBUG_DIR)libSDLSoundSystem.a + +# Some kooky logic going on here ... +ifeq ($(NAN_NO_OPENAL), true) + NAN_SND_LIBS = $(SOUNDSYSTEM) + NAN_SND_LIBS += $(DUMMYSOUND) + NAN_SND_LIBS += $(SOUNDSYSTEM) +else + ifeq ($(OS),$(findstring $(OS), "freebsd linux windows")) + ifeq ($(CPU),$(findstring $(CPU), "i386 powerpc x86_64")) + NAN_SND_LIBS = $(SOUNDSYSTEM) + NAN_SND_LIBS += $(DUMMYSOUND) + NAN_SND_LIBS += $(OPENALSOUND) + NAN_SND_LIBS += $(SDLSOUND) + NAN_SND_LIBS += $(NAN_OPENAL)/lib/libopenal.a + ALUT = $(wildcard $(NAN_OPENAL)/lib/libalut.a) + NAN_SND_LIBS += $(ALUT) + NAN_SND_LIBS += $(SOUNDSYSTEM) + else + ifeq ($(OS),windows) + NAN_SND_LIBS = $(SOUNDSYSTEM) + NAN_SND_LIBS += $(DUMMYSOUND) + NAN_SND_LIBS += $(OPENALSOUND) + NAN_SND_LIBS += $(SDLSOUND) + NAN_SND_LIBS += $(NAN_OPENAL)/lib/openal_static.lib + ALUT = $(wildcard $(NAN_OPENAL)/lib/alut_static.lib) + NAN_SND_LIBS += $(ALUT) + NAN_SND_LIBS += $(SOUNDSYSTEM) + else + NAN_SND_LIBS = $(SOUNDSYSTEM) + NAN_SND_LIBS += $(DUMMYSOUND) + NAN_SND_LIBS += $(SOUNDSYSTEM) + endif + endif + else + ifeq ($(OS),darwin) + NAN_SND_LIBS = $(SOUNDSYSTEM) + NAN_SND_LIBS += $(DUMMYSOUND) + NAN_SND_LIBS += $(OPENALSOUND) + NAN_SND_LIBS += $(NAN_OPENAL)/lib/libopenal.a + ALUT = $(wildcard $(NAN_OPENAL)/lib/libalut.a) + NAN_SND_LIBS += $(ALUT) + NAN_SND_LIBS += $(SOUNDSYSTEM) + else + ifeq ($(OS), solaris) + NAN_SND_LIBS = $(SOUNDSYSTEM) + NAN_SND_LIBS += $(DUMMYSOUND) + NAN_SND_LIBS += $(OPENALSOUND) + NAN_SND_LIBS += $(SDLSOUND) + NAN_SND_LIBS += $(NAN_OPENAL)/lib/libopenal.a + ALUT = $(wildcard $(NAN_OPENAL)/lib/libalut.a) + NAN_SND_LIBS += $(ALUT) + NAN_SND_LIBS += $(SOUNDSYSTEM) + else + NAN_SND_LIBS = $(SOUNDSYSTEM) + NAN_SND_LIBS += $(DUMMYSOUND) + NAN_SND_LIBS += $(SOUNDSYSTEM) + endif + endif + endif +endif + +ifeq ($(OS),windows) + ifeq ($(FREE_WINDOWS),true) + PYLIB = $(NAN_PYTHON)/lib/freepy.a + else + PYLIB = $(NAN_PYTHON)/lib/python23.lib + endif + + PYPLAYERLIB = $(NAN_PYTHON)/static/*.obj + PYPLAYERLIB = $(PYLIB) + + # Might need to change this to $(NAN_MOZILLA_LIB)/nspr4.lib + NSPLUGLIB += $(NAN_NSPR)/lib/nspr4.lib + + BINTARGETS = blenderdynamic + ifeq ($(FREE_WINDOWS),true) + ifneq ($(NAN_NO_KETSJI),true) + BINTARGETS += blenderplayer + endif + else + BINTARGETS += blenderplayer + BINTARGETS += blenderdynplayer + BINTARGETS += plugin + endif + + PULIB += $(OCGDIR)/blender/icons/$(DEBUG_DIR)winblender.res + PULIB += $(NAN_ZLIB)/lib/libz.a + SPLIB += $(OCGDIR)/blender/icons/$(DEBUG_DIR)winblender.res + SPLIB += $(NAN_ZLIB)/lib/libz.a +endif + + +# prepare for NAN_BUILDINFO compile at the *sigh* link rules below + +ifdef NAN_BUILDINFO + CSRCS = + ALLTARGETS = + include nan_compile.mk +endif + +################## target rules ######################## + +all debug :: + @echo "****> Make $@ by $(ID)@$(HOST) at $(MAKE_START) on $(CONFIG_GUESS)" +ifdef NANENV + @for n in $(NANENV); do \ + echo " $$n"; \ + done +endif + +DIR = $(OCGDIR) +SOURCEDIR = source + +include nan_subdirs.mk + +################## target rules ######################## + +all:: link + +debug debuglink:: + @$(MAKE) link DEBUG_DIR="debug/" NANENV=$(NANENV) + +clean:: linkclean debuglinkclean + +link: $(BINTARGETS) + @echo "****> Build $(MAKE_START) - `date '+%H:%M:%S %d-%b-%Y'`" +ifdef NANENV + @for n in $(NANENV); do \ + echo " $$n"; \ + done +endif + +linkclean: + @$(RM) -r $(DIR)/blenderstatic* \ + $(DIR)/blenderplayer* \ + $(DIR)/bin/* + +debuglinkclean: + @$(RM) -r $(DIR)/debug/blenderstatic* \ + $(DIR)/debug/blenderplayer* \ + $(DIR)/debug/bin/* + +# Shortcut for Tinderbox release builds. Mortals don't use this. +release: + @$(MAKE) -C ../release/ all || exit 1; + +############### Linker rules ############### + +blenderstatic: $(DIR)/$(DEBUG_DIR)bin/blenderstatic +blenderdynamic: $(DIR)/$(DEBUG_DIR)bin/blender$(EXT) +blenderplayer: $(DIR)/$(DEBUG_DIR)bin/blenderplayer$(EXT) +blenderdynplayer: $(DIR)/$(DEBUG_DIR)bin/blenderdynplayer$(EXT) + +# XPCOM connector only for linux so far... +ifeq ($(OS),linux) + xplink: $(DIR)/$(DEBUG_DIR)bin/Blender3DPlugin$(SOEXT) +endif + +# Moz/NS plugin: +ifeq ($(OS),$(findstring $(OS), "freebsd linux irix solaris")) + plugin: $(DIR)/$(DEBUG_DIR)bin/npBlender3DPlugin$(SOEXT) + ptest: $(DIR)/$(DEBUG_DIR)bin/npTestPlugin$(SOEXT) +endif +# Windows needs a 8.3 name... Why? Dunno... +ifeq ($(OS),windows) + ifneq ($(FREE_WINDOWS),true) + plugin: $(DIR)/$(DEBUG_DIR)npB3DPlg$(SOEXT) + endif +endif + +$(DIR)/$(DEBUG_DIR)bin/blenderstatic: $(OBJS) $(GRPLIB) $(COMLIB) $(PULIB) + @echo "****> Link $@" +ifdef NAN_BUILDINFO + $(CCC) $(REL_CFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"static"' $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO +endif + mkdir -p $(DIR)/$(DEBUG_DIR)bin + $(CCC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)bin/blenderstatic $(BUILDINFO_O) $(OBJS) $(GRPLIB) $(COMLIB) $(PULIB) $(PYLIB) $(LLIBS) $(SADD) $(LOPTS) +ifdef NAN_BUILDINFO + /bin/rm $(BUILDINFO_O) +endif +ifeq ($(OS), darwin) + @$(MAKE) -C darwin/ APPLICATION=blenderstatic +endif + +$(DIR)/$(DEBUG_DIR)bin/blender$(EXT): $(OBJS) $(GRPLIB) $(COMLIB) $(PULIB) + @echo "****> Link $@" +ifdef NAN_BUILDINFO + $(CCC) $(REL_CFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO +endif + mkdir -p $(DIR)/$(DEBUG_DIR)bin + $(CCC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)bin/blender$(EXT) $(BUILDINFO_O) $(OBJS) $(GRPLIB) $(COMLIB) $(PULIB) $(PYLIB) $(LLIBS) $(DADD) $(LOPTS) +ifdef NAN_BUILDINFO + /bin/rm $(BUILDINFO_O) +endif +ifeq ($(OS), darwin) + @$(MAKE) -C darwin/ APPLICATION=blender +endif + +$(DIR)/$(DEBUG_DIR)bin/blenderplayer$(EXT): $(OBJS) $(SPLIB1) $(COMLIB) $(SPLIB) + @echo "****> Link $@" +ifdef NAN_BUILDINFO + $(CCC) $(REL_CFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO +endif + mkdir -p $(DIR)/$(DEBUG_DIR)bin + $(CCC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)bin/blenderplayer$(EXT) $(BUILDINFO_O) $(OBJS) $(SPLIB1) $(COMLIB) $(SPLIB) $(PYPLAYERLIB) $(LLIBS) $(DADD) $(LOPTS) +ifdef NAN_BUILDINFO + /bin/rm $(BUILDINFO_O) +endif +ifeq ($(OS), darwin) + @$(MAKE) -C darwin/ APPLICATION=blenderplayer +endif + +$(DIR)/$(DEBUG_DIR)bin/blenderdynplayer$(EXT): $(OBJS) $(COMLIB) $(SPLIB) + @echo "****> Link $@" +ifdef NAN_BUILDINFO + $(CCC) $(REL_CFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO +endif + mkdir -p $(DIR)/$(DEBUG_DIR)bin + $(CCC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)bin/blenderdynplayer$(EXT) $(BUILDINFO_O) $(OBJS) $(SPLIB1) $(COMLIB) $(SPLIB) $(PYLIB) $(LLIBS) $(DADD) $(LOPTS) +ifdef NAN_BUILDINFO + /bin/rm $(BUILDINFO_O) +endif +ifeq ($(OS), darwin) + @$(MAKE) -C darwin/ APPLICATION=blenderplayer +endif + +$(DIR)/$(DEBUG_DIR)bin/Blender3DPlugin$(SOEXT): $(PLUGAPPLIB_XPLINK) + @echo "****> Link $@" +ifdef NAN_BUILDINFO + $(CCC) $(REL_CFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO +endif + mkdir -p $(DIR)/$(DEBUG_DIR)bin + $(CCC) $(DYNLDFLAGS) -o $@ $(PLUGAPPLIB_XPLINK) $(LOPTS) +ifdef NAN_BUILDINFO + /bin/rm $(BUILDINFO_O) +endif + +# Windows build needs a def file? Why? For exposing functions from the +# dll to the outside world. However, this is alsi done internally.. +DEFFILE = ./gameengine/GamePlayer/netscape/src/npB3DPlg.def + +# Windows needs a specific name format for dll.s so we give it one. +$(DIR)/$(DEBUG_DIR)npB3DPlg$(SOEXT): $(NSPLUGLIB) $(PLUGAPPLIB) $(COMLIB) $(SPLIB) + @echo "****> Link $@" +ifdef NAN_BUILDINFO + $(CCC) $(REL_CFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO +endif +# $(CCC) $(DYNLDFLAGS) -o $@ $(NSPLUGLIB) $(PLUGAPPLIB) $(COMLIB) $(SPLIB) $(PYLIB) $(PLUGREMLIB) $(LLIBS) $(DADD) $(LOPTS) + $(CCC) $(DYNLDFLAGS) -o $@ $(NSPLUGLIB) $(PLUGAPPLIB) $(COMLIB) $(SPLIB) $(PYLIB) $(PLUGREMLIB) $(LLIBS) $(DADD) $(LOPTS) /def:$(DEFFILE) +ifdef NAN_BUILDINFO + /bin/rm $(BUILDINFO_O) +endif + +$(DIR)/$(DEBUG_DIR)bin/npBlender3DPlugin$(SOEXT): $(NSPLUGLIB) $(PLUGAPPLIB) $(COMLIB) $(SPLIB) + @echo "****> Link $@" +ifdef NAN_BUILDINFO + $(CCC) $(REL_CFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO +endif + mkdir -p $(DIR)/$(DEBUG_DIR)bin + $(CCC) $(DYNLDFLAGS) -o $@ $(NSPLUGLIB) $(PLUGAPPLIB) $(COMLIB) $(SPLIB) $(PYLIB) $(PLUGREMLIB) $(LLIBS) $(DADD) $(LOPTS) +ifdef NAN_BUILDINFO + /bin/rm $(BUILDINFO_O) +endif + +$(DIR)/$(DEBUG_DIR)bin/npTestPlugin$(SOEXT): $(NSPLUGLIB) + @echo "****> Link $@" +ifdef NAN_BUILDINFO + $(CCC) $(REL_CFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO +endif + mkdir -p $(DIR)/$(DEBUG_DIR)bin + $(CCC) $(DYNLDFLAGS) -o $@ $(NSPLUGLIB) $(PLUGTESTLIB) $(LLIBS) $(DADD) $(LOPTS) +ifdef NAN_BUILDINFO + /bin/rm $(BUILDINFO_O) +endif + diff --git a/source/SConscript b/source/SConscript new file mode 100644 index 00000000000..ca264579f6e --- /dev/null +++ b/source/SConscript @@ -0,0 +1,11 @@ +#!/usr/bin/python +Import ('env') + +SConscript(['blender/SConscript', + 'kernel/SConscript', + 'creator/SConscript']) +if env['WITH_BF_GAMEENGINE'] == 1: + SConscript (['gameengine/SConscript']) + +if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw'): + SConscript (['icons/SConscript']) diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt new file mode 100644 index 00000000000..fa9199006a8 --- /dev/null +++ b/source/blender/CMakeLists.txt @@ -0,0 +1,42 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SUBDIRS(avi nodes blenkernel blenlib blenloader blenpluginapi imbuf imbuf/intern/cineon makesdna python radiosity readblenfile render src yafray) + +IF(WITH_INTERNATIONAL) + SUBDIRS(ftfont) +ENDIF(WITH_INTERNATIONAL) + +IF(WITH_OPENEXR) + SUBDIRS(imbuf/intern/openexr) +ENDIF(WITH_OPENEXR) + +IF(WITH_QUICKTIME) + SUBDIRS(quicktime) +ENDIF(WITH_QUICKTIME) diff --git a/source/blender/Makefile b/source/blender/Makefile new file mode 100644 index 00000000000..c0001495210 --- /dev/null +++ b/source/blender/Makefile @@ -0,0 +1,53 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +include nan_definitions.mk + +DIRS = blenloader readblenfile +DIRS += avi imbuf render radiosity blenlib blenkernel blenpluginapi +DIRS += makesdna src yafray +DIRS += python nodes + +ifeq ($(INTERNATIONAL), true) + DIRS += ftfont +endif + +ifeq ($(WITH_QUICKTIME), true) + DIRS += quicktime +endif + +DIR = $(OCGDIR)/blender +SOURCEDIR = source/blender +TESTDIRS = deflate streamglue + +include nan_subdirs.mk diff --git a/source/blender/SConscript b/source/blender/SConscript new file mode 100644 index 00000000000..56a661238f8 --- /dev/null +++ b/source/blender/SConscript @@ -0,0 +1,33 @@ +#!/usr/bin/python +Import ('env') +import sys + +SConscript(['avi/SConscript', + 'blenkernel/SConscript', + 'blenlib/SConscript', + 'blenloader/SConscript', + 'blenpluginapi/SConscript', + 'imbuf/SConscript', + 'imbuf/intern/cineon/SConscript', + 'makesdna/SConscript', + 'python/SConscript', + 'radiosity/SConscript', + 'readblenfile/SConscript', + 'render/SConscript', + 'src/SConscript', + 'nodes/SConscript']) + +if env['WITH_BF_YAFRAY'] == 1: + SConscript(['yafray/SConscript']) + +if env['WITH_BF_INTERNATIONAL'] == 1: + SConscript (['ftfont/SConscript']) + +if env['WITH_BF_DDS'] == 1: + SConscript (['imbuf/intern/dds/SConscript']) + +if env['WITH_BF_OPENEXR'] == 1: + SConscript (['imbuf/intern/openexr/SConscript']) + +if env['WITH_BF_QUICKTIME'] == 1: + SConscript (['quicktime/SConscript']) diff --git a/source/blender/avi/AVI_avi.h b/source/blender/avi/AVI_avi.h new file mode 100644 index 00000000000..76442d9d55e --- /dev/null +++ b/source/blender/avi/AVI_avi.h @@ -0,0 +1,309 @@ +/** + * @mainpage AVI - AVI module external interface + * + * @section about About the AVI module + * + * This is external code. It provides avi file import/export and + * conversions. It has been adapted to make use of Blender memory + * management functions, and because of this it needs module + * blenlib. You need to provide this lib when linking with libavi.a . + * + * @section issues Known issues with AVI + * + * - avi uses mallocN, freeN from blenlib. + * - Not all functions that are used externally are properly + * prototyped. + * + * This header has not been split, since it interleaves type defines + * and functions. You would need the types to be able to include the + * function headers anyway. And, after all, it is someone else's + * code. So we keep it like this. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + */ + +#ifndef __AVI_H__ +#define __AVI_H__ + +#include /* for FILE */ + +typedef struct _AviChunk { + int fcc; + int size; +} AviChunk; + +typedef struct _AviList { + int fcc; + int size; + int ids; +} AviList; + +typedef struct _AviMainHeader { + int fcc; + int size; + int MicroSecPerFrame; /* MicroSecPerFrame - timing between frames */ + int MaxBytesPerSec; /* MaxBytesPerSec - approx bps system must handle */ + int PaddingGranularity; + int Flags; +#define AVIF_HASINDEX 0x00000010 /* had idx1 chunk */ +#define AVIF_MUSTUSEINDEX 0x00000020 /* must use idx1 chunk to determine order */ +#define AVIF_ISINTERLEAVED 0x00000100 /* AVI file is interleaved */ +#define AVIF_TRUSTCKTYPE 0x00000800 +#define AVIF_WASCAPTUREFILE 0x00010000 /* specially allocated used for capturing real time video */ +#define AVIF_COPYRIGHTED 0x00020000 /* contains copyrighted data */ + + int TotalFrames; + int InitialFrames; /* InitialFrames - initial frame before interleaving */ + int Streams; + int SuggestedBufferSize; + int Width; + int Height; + int Reserved[4]; +} AviMainHeader; + +typedef struct _AviStreamHeader { + int fcc; + int size; + int Type; +#define AVIST_VIDEO FCC("vids") +#define AVIST_AUDIO FCC("auds") +#define AVIST_MIDI FCC("mids") +#define AVIST_TEXT FCC("txts") + + int Handler; + int Flags; +#define AVISF_DISABLED 0x00000001 +#define AVISF_VIDEO_PALCHANGES 0x00010000 + + short Priority; + short Language; + int InitialFrames; + int Scale; + int Rate; + int Start; + int Length; + int SuggestedBufferSize; + int Quality; + int SampleSize; + short left; + short top; + short right; + short bottom; +} AviStreamHeader; + +typedef struct _AviBitmapInfoHeader { + int fcc; + int size; + int Size; + int Width; + int Height; + short Planes; + short BitCount; + int Compression; + int SizeImage; + int XPelsPerMeter; + int YPelsPerMeter; + int ClrUsed; + int ClrImportant; +} AviBitmapInfoHeader; + +typedef struct _AviMJPEGUnknown { + int a; + int b; + int c; + int d; + int e; + int f; + int g; +} AviMJPEGUnknown; + +typedef struct _AviIndexEntry { + int ChunkId; + int Flags; +#define AVIIF_LIST 0x00000001 +#define AVIIF_KEYFRAME 0x00000010 +#define AVIIF_NO_TIME 0x00000100 +#define AVIIF_COMPRESSOR 0x0FFF0000 + int Offset; + int Size; +} AviIndexEntry; + +typedef struct _AviIndex { + int fcc; + int size; + AviIndexEntry *entrys; +} AviIndex; + +typedef enum { + AVI_FORMAT_RGB24, /* The most basic of forms, 3 bytes per pixel, 1 per r, g, b */ + AVI_FORMAT_RGB32, /* The second most basic of forms, 4 bytes per pixel, 1 per r, g, b, alpha */ + AVI_FORMAT_AVI_RGB, /* Same as above, but is in the wierd AVI order (bottom to top, left to right) */ + AVI_FORMAT_MJPEG /* Motion-JPEG */ +} AviFormat; + +typedef struct _AviStreamRec { + AviStreamHeader sh; + void *sf; + int sf_size; + AviFormat format; +} AviStreamRec; + +typedef struct _AviMovie { + FILE *fp; + + int type; +#define AVI_MOVIE_READ 0 +#define AVI_MOVIE_WRITE 1 + + unsigned long size; + + AviMainHeader *header; + AviStreamRec *streams; + AviIndexEntry *entries; + int index_entries; + + int movi_offset; + int read_offset; + long *offset_table; + + /* Local data goes here */ + int interlace; + int odd_fields; +} AviMovie; + +typedef enum { + AVI_ERROR_NONE=0, + AVI_ERROR_COMPRESSION, + AVI_ERROR_OPEN, + AVI_ERROR_READING, + AVI_ERROR_WRITING, + AVI_ERROR_FORMAT, + AVI_ERROR_ALLOC, + AVI_ERROR_FOUND, + AVI_ERROR_OPTION +} AviError; + +/* belongs to the option-setting function. */ +typedef enum { + AVI_OPTION_WIDTH=0, + AVI_OPTION_HEIGHT, + AVI_OPTION_QUALITY, + AVI_OPTION_FRAMERATE +} AviOption; + +/* The offsets that will always stay the same in AVI files we + * write... used to seek around to the places where we need to write + * the sizes */ + +#define AVI_RIFF_SOFF 4L +#define AVI_HDRL_SOFF 16L + +/** + * This is a sort of MAKE_ID thing. Used in imbuf :( It is used + * through options in the AVI header (AviStreamHeader). */ +#define FCC(ch4) (ch4[0] | ch4[1]<<8 | ch4[2]<<16 | ch4[3] << 24) + +/** + * Test whether this is an avi-format. + */ +int AVI_is_avi (char *name); + + +/** + * Open a compressed file, decompress it into memory. + */ +AviError AVI_open_compress (char *name, AviMovie *movie, int streams, ...); + +/** + * Finalize a compressed output stream. + */ +AviError AVI_close_compress (AviMovie *movie); + +/** + * Choose a compression option for . Possible options are + * AVI_OPTION_TYPE_MAIN, AVI_OPTION_TYPE_STRH, AVI_OPTION_TYPE_STRF + */ +AviError AVI_set_compress_option (AviMovie *movie, + int option_type, + int stream, + AviOption option, + void *opt_data); +/* Hmmm... there should be some explanantion about what these mean */ +/** + * Compression option, for use in avi_set_compress_option + */ +#define AVI_OPTION_TYPE_MAIN 0 +/** + * Compression option, for use in avi_set_compress_option + */ +#define AVI_OPTION_TYPE_STRH 1 +/** + * Compression option, for use in avi_set_compress_option + */ +#define AVI_OPTION_TYPE_STRF 2 + +/** + * Direct the streams to . Redirect + * streams. + */ +int AVI_get_stream (AviMovie *movie, int avist_type, int stream_num); + +/** + * Open a movie stream from file. + */ +AviError AVI_open_movie (char *name, AviMovie *movie); + +/** + * Read a frame from a movie stream. + */ +void *AVI_read_frame (AviMovie *movie, + AviFormat format, + int frame, + int stream); +/** + * Close an open movie stream. + */ +AviError AVI_close (AviMovie *movie); + +/** + * Write frames to a movie stream. + */ +AviError AVI_write_frame (AviMovie *movie, int frame_num, ...); + +/** + * Unused but still external + */ +AviError AVI_print_error (AviError error); +void AVI_set_debug (int mode); + +#endif /* __AVI_H__ */ + diff --git a/source/blender/avi/CMakeLists.txt b/source/blender/avi/CMakeLists.txt new file mode 100644 index 00000000000..0bf69d735ce --- /dev/null +++ b/source/blender/avi/CMakeLists.txt @@ -0,0 +1,38 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +FILE(GLOB SRC intern/*.c) + +SET(INC + . ../../../intern/guardedalloc + ${JPEG_INC} +) + +BLENDERLIB(bf_avi "${SRC}" "${INC}") +#env.BlenderLib ('bf_avi', sources, Split(incs), [], libtype=['core','player'], priority = [90, 50] ) diff --git a/source/blender/avi/Makefile b/source/blender/avi/Makefile new file mode 100644 index 00000000000..457eebbb516 --- /dev/null +++ b/source/blender/avi/Makefile @@ -0,0 +1,37 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# Bounces make to subdirectories. + +SOURCEDIR = source/blender/avi +DIRS = intern + +include nan_subdirs.mk diff --git a/source/blender/avi/SConscript b/source/blender/avi/SConscript new file mode 100644 index 00000000000..91239c66ead --- /dev/null +++ b/source/blender/avi/SConscript @@ -0,0 +1,10 @@ +#!/usr/bin/python +#Import ('extra_includes') +Import ('env') + +sources = env.Glob('intern/*.c') + +incs = '. #/intern/guardedalloc' +incs += ' ' + env['BF_JPEG_INC'] + +env.BlenderLib ('bf_avi', sources, Split(incs), [], libtype=['core','player'], priority = [90, 50] ) diff --git a/source/blender/avi/intern/Makefile b/source/blender/avi/intern/Makefile new file mode 100644 index 00000000000..71e892e3db6 --- /dev/null +++ b/source/blender/avi/intern/Makefile @@ -0,0 +1,54 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = avi +DIR = $(OCGDIR)/blender/$(LIBNAME) + +include nan_compile.mk + +CFLAGS += $(LEVEL1_C_WARNINGS) + +ifeq ($(CPU),$(findstring $(CPU), "powerpc mips sparc")) + CPPFLAGS += -DWORDS_BIGENDIAN +else + # alpha i386 + CPPFLAGS += -DWORDS_LITTLEENDIAN +endif + +# the JPEG library +CPPFLAGS += -I$(NAN_JPEG)/include +# path to the guarded memory allocator +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include +# our own include +CPPFLAGS += -I.. + diff --git a/source/blender/avi/intern/avi.c b/source/blender/avi/intern/avi.c new file mode 100644 index 00000000000..3ad844bfdc1 --- /dev/null +++ b/source/blender/avi/intern/avi.c @@ -0,0 +1,843 @@ +/** + * avi.c + * + * This is external code. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + */ + +#include +#include +#include +#include +#include + +#include "AVI_avi.h" +#include "avi_intern.h" + +#include "endian.h" + +static int AVI_DEBUG=0; +static char DEBUG_FCC[4]; + +#define DEBUG(x) if(AVI_DEBUG) printf("AVI DEBUG: " x); + +/* local functions */ +char *fcc_to_char (unsigned int fcc); +char *tcc_to_char (unsigned int tcc); + + + +/* implemetation */ + +unsigned int GET_FCC (FILE *fp) { + unsigned char tmp[4]; + + tmp[0] = getc(fp); + tmp[1] = getc(fp); + tmp[2] = getc(fp); + tmp[3] = getc(fp); + + return FCC (tmp); +} + +unsigned int GET_TCC (FILE *fp) { + char tmp[5]; + + tmp[0] = getc(fp); + tmp[1] = getc(fp); + tmp[2] = 0; + tmp[3] = 0; + + return FCC (tmp); +} + +char *fcc_to_char (unsigned int fcc) { + DEBUG_FCC[0]= (fcc)&0177; + DEBUG_FCC[1]= (fcc>>8)&0177; + DEBUG_FCC[2]= (fcc>>16)&0177; + DEBUG_FCC[3]= (fcc>>24)&0177; + + return DEBUG_FCC; +} + +char *tcc_to_char (unsigned int tcc) { + DEBUG_FCC[0]= (tcc)&0177; + DEBUG_FCC[1]= (tcc>>8)&0177; + DEBUG_FCC[2]= 0; + DEBUG_FCC[3]= 0; + + return DEBUG_FCC; +} + +int AVI_get_stream (AviMovie *movie, int avist_type, int stream_num) { + int cur_stream; + + if (movie == NULL) + return -AVI_ERROR_OPTION; + + for (cur_stream=0; cur_stream < movie->header->Streams; cur_stream++) { + if (movie->streams[cur_stream].sh.Type == avist_type) { + if (stream_num == 0) + return cur_stream; + else + stream_num--; + } + } + + return -AVI_ERROR_FOUND; +} + +static int fcc_get_stream (int fcc) { + char fccs[4]; + + fccs[0] = fcc; + fccs[1] = fcc>>8; + fccs[2] = fcc>>16; + fccs[3] = fcc>>24; + + return 10*(fccs[0]-'0') + (fccs[1]-'0'); +} + +static int fcc_is_data (int fcc) { + char fccs[4]; + + fccs[0] = fcc; + fccs[1] = fcc>>8; + fccs[2] = fcc>>16; + fccs[3] = fcc>>24; + + if (!isdigit (fccs[0]) || !isdigit (fccs[1]) || (fccs[2] != 'd' && fccs[2] != 'w')) + return 0; + if (fccs[3] != 'b' && fccs[3] != 'c') + return 0; + + return 1; +} + +AviError AVI_print_error (AviError in_error) { + int error; + + if ((int) in_error < 0) + error = -in_error; + else + error = in_error; + + switch (error) { + case AVI_ERROR_NONE: + break; + case AVI_ERROR_COMPRESSION: + printf ("AVI ERROR: compressed in an unsupported format\n"); + break; + case AVI_ERROR_OPEN: + printf ("AVI ERROR: could not open file\n"); + break; + case AVI_ERROR_READING: + printf ("AVI ERROR: could not read from file\n"); + break; + case AVI_ERROR_WRITING: + printf ("AVI ERROR: could not write to file\n"); + break; + case AVI_ERROR_FORMAT: + printf ("AVI ERROR: file is in an illegal or unrecognized format\n"); + break; + case AVI_ERROR_ALLOC: + printf ("AVI ERROR: error encountered while allocating memory\n"); + break; + case AVI_ERROR_OPTION: + printf ("AVI ERROR: program made illegal request\n"); + break; + case AVI_ERROR_FOUND: + printf ("AVI ERROR: movie did not contain expected item\n"); + break; + default: + break; + } + + return in_error; +} + +void AVI_set_debug (int mode) { + AVI_DEBUG= mode; +} + +int AVI_is_avi (char *name) { + FILE *fp; + int ret; + + fp = fopen (name, "rb"); + if (fp == NULL) + return 0; + + if (GET_FCC (fp) != FCC("RIFF") || + !GET_FCC (fp) || + GET_FCC (fp) != FCC("AVI ")) { + ret = 0; + } else { + ret = 1; + } + + fclose(fp); + return ret; +} + +AviError AVI_open_movie (char *name, AviMovie *movie) { + int temp, fcca, size, j; + + DEBUG("opening movie\n"); + + memset(movie, 0, sizeof(AviMovie)); + + movie->type = AVI_MOVIE_READ; + movie->fp = fopen (name, "rb"); + movie->offset_table = NULL; + + if (movie->fp == NULL) + return AVI_ERROR_OPEN; + + if (GET_FCC (movie->fp) != FCC("RIFF") || + !(movie->size = GET_FCC (movie->fp))) + return AVI_ERROR_FORMAT; + + movie->header = (AviMainHeader *) MEM_mallocN (sizeof (AviMainHeader), "movieheader"); + + if (GET_FCC (movie->fp) != FCC("AVI ") || + GET_FCC (movie->fp) != FCC("LIST") || + !GET_FCC (movie->fp) || + GET_FCC (movie->fp) != FCC("hdrl") || + (movie->header->fcc = GET_FCC (movie->fp)) != FCC("avih") || + !(movie->header->size = GET_FCC (movie->fp))) { + DEBUG("bad initial header info\n"); + return AVI_ERROR_FORMAT; + } + + movie->header->MicroSecPerFrame = GET_FCC(movie->fp); + movie->header->MaxBytesPerSec = GET_FCC(movie->fp); + movie->header->PaddingGranularity = GET_FCC(movie->fp); + movie->header->Flags = GET_FCC(movie->fp); + movie->header->TotalFrames = GET_FCC(movie->fp); + movie->header->InitialFrames = GET_FCC(movie->fp); + movie->header->Streams = GET_FCC(movie->fp); + movie->header->SuggestedBufferSize = GET_FCC(movie->fp); + movie->header->Width = GET_FCC(movie->fp); + movie->header->Height = GET_FCC(movie->fp); + movie->header->Reserved[0] = GET_FCC(movie->fp); + movie->header->Reserved[1] = GET_FCC(movie->fp); + movie->header->Reserved[2] = GET_FCC(movie->fp); + movie->header->Reserved[3] = GET_FCC(movie->fp); + + fseek (movie->fp, movie->header->size-14*4, SEEK_CUR); + + if (movie->header->Streams < 1) { + DEBUG("streams less than 1\n"); + return AVI_ERROR_FORMAT; + } + + movie->streams = (AviStreamRec *) MEM_callocN (sizeof(AviStreamRec) * movie->header->Streams, "moviestreams"); + + for (temp=0; temp < movie->header->Streams; temp++) { + + if (GET_FCC(movie->fp) != FCC("LIST") || + !GET_FCC (movie->fp) || + GET_FCC (movie->fp) != FCC ("strl") || + (movie->streams[temp].sh.fcc = GET_FCC (movie->fp)) != FCC ("strh") || + !(movie->streams[temp].sh.size = GET_FCC (movie->fp))) { + DEBUG("bad stream header information\n"); + return AVI_ERROR_FORMAT; + } + + movie->streams[temp].sh.Type = GET_FCC (movie->fp); + movie->streams[temp].sh.Handler = GET_FCC (movie->fp); + + fcca = movie->streams[temp].sh.Handler; + + if (movie->streams[temp].sh.Type == FCC("vids")) { + if (fcca == FCC ("DIB ") || + fcca == FCC ("RGB ") || + fcca == FCC ("rgb ") || + fcca == FCC ("RAW ") || + fcca == 0) { + movie->streams[temp].format = AVI_FORMAT_AVI_RGB; + } else if (fcca == FCC ("mjpg")||fcca == FCC ("MJPG")) { + movie->streams[temp].format = AVI_FORMAT_MJPEG; + } else { + return AVI_ERROR_COMPRESSION; + } + } + + movie->streams[temp].sh.Flags = GET_FCC (movie->fp); + movie->streams[temp].sh.Priority = GET_TCC (movie->fp); + movie->streams[temp].sh.Language = GET_TCC (movie->fp); + movie->streams[temp].sh.InitialFrames = GET_FCC (movie->fp); + movie->streams[temp].sh.Scale = GET_FCC (movie->fp); + movie->streams[temp].sh.Rate = GET_FCC (movie->fp); + movie->streams[temp].sh.Start = GET_FCC (movie->fp); + movie->streams[temp].sh.Length = GET_FCC (movie->fp); + movie->streams[temp].sh.SuggestedBufferSize = GET_FCC (movie->fp); + movie->streams[temp].sh.Quality = GET_FCC (movie->fp); + movie->streams[temp].sh.SampleSize = GET_FCC (movie->fp); + movie->streams[temp].sh.left = GET_TCC (movie->fp); + movie->streams[temp].sh.top = GET_TCC (movie->fp); + movie->streams[temp].sh.right = GET_TCC (movie->fp); + movie->streams[temp].sh.bottom = GET_TCC (movie->fp); + + fseek (movie->fp, movie->streams[temp].sh.size-14*4, SEEK_CUR); + + if (GET_FCC (movie->fp) != FCC("strf")) { + DEBUG("no stream format information\n"); + return AVI_ERROR_FORMAT; + } + + movie->streams[temp].sf_size= GET_FCC(movie->fp); + if (movie->streams[temp].sh.Type == FCC("vids")) { + j = movie->streams[temp].sf_size - (sizeof(AviBitmapInfoHeader) - 8); + if (j >= 0) { + AviBitmapInfoHeader *bi; + + movie->streams[temp].sf= MEM_mallocN(sizeof(AviBitmapInfoHeader), "streamformat"); + + bi= (AviBitmapInfoHeader *) movie->streams[temp].sf; + + bi->fcc= FCC("strf"); + bi->size= movie->streams[temp].sf_size; + bi->Size= GET_FCC(movie->fp); + bi->Width= GET_FCC(movie->fp); + bi->Height= GET_FCC(movie->fp); + bi->Planes= GET_TCC(movie->fp); + bi->BitCount= GET_TCC(movie->fp); + bi->Compression= GET_FCC(movie->fp); + bi->SizeImage= GET_FCC(movie->fp); + bi->XPelsPerMeter= GET_FCC(movie->fp); + bi->YPelsPerMeter= GET_FCC(movie->fp); + bi->ClrUsed= GET_FCC(movie->fp); + bi->ClrImportant= GET_FCC(movie->fp); + + fcca = bi->Compression; + + if ( movie->streams[temp].format == + AVI_FORMAT_AVI_RGB) { + if (fcca == FCC ("DIB ") || + fcca == FCC ("RGB ") || + fcca == FCC ("rgb ") || + fcca == FCC ("RAW ") || + fcca == 0 ) { + } else if ( fcca == FCC ("mjpg") || + fcca == FCC ("MJPG")) { + movie->streams[temp].format = AVI_FORMAT_MJPEG; + } else { + return AVI_ERROR_COMPRESSION; + } + } + + } + if (j > 0) fseek (movie->fp, j, SEEK_CUR); + } else fseek (movie->fp, movie->streams[temp].sf_size, SEEK_CUR); + + /* Walk to the next LIST */ + while (GET_FCC (movie->fp) != FCC("LIST")) { + temp= GET_FCC (movie->fp); + if (temp<0 || ftell(movie->fp) > movie->size) { + DEBUG("incorrect size in header or error in AVI\n"); + return AVI_ERROR_FORMAT; + } + fseek(movie->fp, temp, SEEK_CUR); + } + + fseek(movie->fp, -4L, SEEK_CUR); + } + + while (1) { + temp = GET_FCC (movie->fp); + size = GET_FCC (movie->fp); + + if (size == 0) + break; + + if (temp == FCC("LIST")) { + if (GET_FCC(movie->fp) == FCC ("movi")) + break; + else + fseek (movie->fp, size-4, SEEK_CUR); + } else { + fseek (movie->fp, size, SEEK_CUR); + } + if (ftell(movie->fp) > movie->size) { + DEBUG("incorrect size in header or error in AVI\n"); + return AVI_ERROR_FORMAT; + } + } + + movie->movi_offset = ftell (movie->fp); + movie->read_offset = movie->movi_offset; + if (AVI_DEBUG) printf ("movi_offset is %d\n", movie->movi_offset); + + /* Read in the index if the file has one, otherwise create one */ + if (movie->header->Flags & AVIF_HASINDEX) { + fseek(movie->fp, size-4, SEEK_CUR); + + if (GET_FCC(movie->fp) != FCC("idx1")) { + DEBUG("bad index informatio\n"); + return AVI_ERROR_FORMAT; + } + + movie->index_entries = GET_FCC (movie->fp)/sizeof(AviIndexEntry); + if (movie->index_entries == 0) { + DEBUG("no index entries\n"); + return AVI_ERROR_FORMAT; + } + + movie->entries = (AviIndexEntry *) MEM_mallocN (movie->index_entries * sizeof(AviIndexEntry),"movieentries"); + + for (temp=0; temp < movie->index_entries; temp++) { + movie->entries[temp].ChunkId = GET_FCC (movie->fp); + movie->entries[temp].Flags = GET_FCC (movie->fp); + movie->entries[temp].Offset = GET_FCC (movie->fp); + movie->entries[temp].Size = GET_FCC (movie->fp); + + if (AVI_DEBUG) printf ("Index entry %04d: ChunkId:%s Flags:%d Offset:%d Size:%d\n", temp, fcc_to_char(movie->entries[temp].ChunkId), movie->entries[temp].Flags, movie->entries[temp].Offset, movie->entries[temp].Size); + } + +/* Some AVI's have offset entries in absolute coordinates + * instead of an offset from the movie beginning... this is... + * wacky, but we need to handle it. The wacky offset always + * starts at movi_offset it seems... so we'll check that. + * Note the the offset needs an extra 4 bytes for some + * undetermined reason */ + + if (movie->entries[0].Offset == movie->movi_offset) + movie->read_offset= 4; + } + + DEBUG("movie succesfully opened\n"); + return AVI_ERROR_NONE; +} + +void *AVI_read_frame (AviMovie *movie, AviFormat format, int frame, int stream) { + int cur_frame, temp, i, rewind=1; + void *buffer; + + /* Retrieve the record number of the desired frame in the index + If a chunk has Size 0 we need to rewind to previous frame */ + while(rewind && frame > -1) { + i=0; + cur_frame=-1; + rewind = 0; + + while (cur_frame < frame && i < movie->index_entries) { + if (fcc_is_data (movie->entries[i].ChunkId) && + fcc_get_stream (movie->entries[i].ChunkId) == stream) { + if ((cur_frame == frame -1) && (movie->entries[i].Size == 0)) { + rewind = 1; + frame = frame -1; + } else { + cur_frame++; + } + } + i++; + } + } + + if (cur_frame != frame) return NULL; + + + fseek (movie->fp, movie->read_offset + movie->entries[i-1].Offset, SEEK_SET); + + temp = GET_FCC(movie->fp); + buffer = MEM_mallocN (temp,"readbuffer"); + + if (fread (buffer, 1, temp, movie->fp) != temp) { + MEM_freeN(buffer); + + return NULL; + } + + buffer = avi_format_convert (movie, stream, buffer, movie->streams[stream].format, format, &temp); + + return buffer; +} + +AviError AVI_close (AviMovie *movie) { + int i; + + fclose (movie->fp); + + for (i=0; i < movie->header->Streams; i++) { + if (movie->streams[i].sf != NULL) + MEM_freeN (movie->streams[i].sf); + } + + if (movie->header != NULL) + MEM_freeN (movie->header); + if (movie->streams!= NULL) + MEM_freeN (movie->streams); + if (movie->entries != NULL) + MEM_freeN (movie->entries); + if (movie->offset_table != NULL) + MEM_freeN (movie->offset_table); + + return AVI_ERROR_NONE; +} + +AviError AVI_open_compress (char *name, AviMovie *movie, int streams, ...) { + va_list ap; + AviList list; + AviChunk chunk; + int i; + int header_pos1, header_pos2; + int stream_pos1, stream_pos2; + + movie->type = AVI_MOVIE_WRITE; + movie->fp = fopen (name, "wb"); + + movie->index_entries = 0; + + if (movie->fp == NULL) + return AVI_ERROR_OPEN; + + movie->offset_table = (long *) MEM_mallocN ((1+streams*2) * sizeof (long),"offsettable"); + + for (i=0; i < 1 + streams*2; i++) + movie->offset_table[i] = -1L; + + movie->entries = NULL; + + movie->header = (AviMainHeader *) MEM_mallocN (sizeof(AviMainHeader),"movieheader"); + + movie->header->fcc = FCC("avih"); + movie->header->size = 56; + movie->header->MicroSecPerFrame = 66667; + movie->header->MaxBytesPerSec = 0; + movie->header->PaddingGranularity = 0; + movie->header->Flags = AVIF_HASINDEX | AVIF_MUSTUSEINDEX; + movie->header->TotalFrames = 0; + movie->header->InitialFrames = 0; + movie->header->Streams = streams; + movie->header->SuggestedBufferSize = 0; + movie->header->Width = 0; + movie->header->Height = 0; + movie->header->Reserved[0] = 0; + movie->header->Reserved[1] = 0; + movie->header->Reserved[2] = 0; + movie->header->Reserved[3] = 0; + + movie->streams = (AviStreamRec *) MEM_mallocN (sizeof(AviStreamRec) * movie->header->Streams,"moviestreams"); + + va_start (ap, streams); + + for (i=0; i < movie->header->Streams; i++) { + movie->streams[i].format = va_arg(ap, AviFormat); + + movie->streams[i].sh.fcc = FCC ("strh"); + movie->streams[i].sh.size = 56; + movie->streams[i].sh.Type = avi_get_format_type (movie->streams[i].format); + if (movie->streams[i].sh.Type == 0) + return AVI_ERROR_FORMAT; + + movie->streams[i].sh.Handler = avi_get_format_fcc (movie->streams[i].format); + if (movie->streams[i].sh.Handler == 0) + return AVI_ERROR_FORMAT; + + movie->streams[i].sh.Flags = 0; + movie->streams[i].sh.Priority = 0; + movie->streams[i].sh.Language = 0; + movie->streams[i].sh.InitialFrames = 0; + movie->streams[i].sh.Scale = 66667; + movie->streams[i].sh.Rate = 1000000; + movie->streams[i].sh.Start = 0; + movie->streams[i].sh.Length = 0; + movie->streams[i].sh.SuggestedBufferSize = 0; + movie->streams[i].sh.Quality = 10000; + movie->streams[i].sh.SampleSize = 0; + movie->streams[i].sh.left = 0; + movie->streams[i].sh.top = 0; + movie->streams[i].sh.right = 0; + movie->streams[i].sh.bottom = 0; + + if (movie->streams[i].sh.Type == FCC("vids")) { +/* + if (movie->streams[i].format == AVI_FORMAT_MJPEG) { + movie->streams[i].sf = MEM_mallocN (sizeof(AviBitmapInfoHeader) + + sizeof(AviMJPEGUnknown),"moviestreamformatL"); + movie->streams[i].sf_size = sizeof(AviBitmapInfoHeader) + sizeof(AviMJPEGUnknown); + } else { +*/ + movie->streams[i].sf = MEM_mallocN (sizeof(AviBitmapInfoHeader), "moviestreamformatS"); + movie->streams[i].sf_size = sizeof(AviBitmapInfoHeader); + + ((AviBitmapInfoHeader *) movie->streams[i].sf)->fcc = FCC ("strf"); + ((AviBitmapInfoHeader *) movie->streams[i].sf)->size = movie->streams[i].sf_size - 8; + ((AviBitmapInfoHeader *) movie->streams[i].sf)->Size = movie->streams[i].sf_size - 8; + ((AviBitmapInfoHeader *) movie->streams[i].sf)->Width = 0; + ((AviBitmapInfoHeader *) movie->streams[i].sf)->Height = 0; + ((AviBitmapInfoHeader *) movie->streams[i].sf)->Planes = 1; + ((AviBitmapInfoHeader *) movie->streams[i].sf)->BitCount = 24; + ((AviBitmapInfoHeader *) movie->streams[i].sf)->Compression = avi_get_format_compression (movie->streams[i].format); + ((AviBitmapInfoHeader *) movie->streams[i].sf)->SizeImage = 0; + ((AviBitmapInfoHeader *) movie->streams[i].sf)->XPelsPerMeter = 0; + ((AviBitmapInfoHeader *) movie->streams[i].sf)->YPelsPerMeter = 0; + ((AviBitmapInfoHeader *) movie->streams[i].sf)->ClrUsed = 0; + ((AviBitmapInfoHeader *) movie->streams[i].sf)->ClrImportant = 0; + +/* + if (movie->streams[i].format == AVI_FORMAT_MJPEG) { + AviMJPEGUnknown *tmp; + + tmp = (AviMJPEGUnknown *) ((char*) movie->streams[i].sf +sizeof(AviBitmapInfoHeader)); + + tmp->a = 44; + tmp->b = 24; + tmp->c = 0; + tmp->d = 2; + tmp->e = 8; + tmp->f = 2; + tmp->g = 1; + } + } else if (movie->streams[i].sh.Type == FCC("auds")) { + ; +*/ + } + } + + list.fcc = FCC("RIFF"); + list.size = 0; + list.ids = FCC("AVI "); + + awrite (movie, &list, 1, sizeof(AviList), movie->fp, AVI_LIST); + + list.fcc = FCC("LIST"); + list.size = 0; + list.ids = FCC("hdrl"); + + awrite (movie, &list, 1, sizeof(AviList), movie->fp, AVI_LIST); + + header_pos1 = ftell(movie->fp); + + movie->offset_table[0] = ftell(movie->fp); + + awrite (movie, movie->header, 1, sizeof(AviMainHeader), movie->fp, AVI_MAINH); + + for (i=0; i < movie->header->Streams; i++) { + list.fcc = FCC("LIST"); + list.size = 0; + list.ids = FCC("strl"); + + awrite (movie, &list, 1, sizeof(AviList), movie->fp, AVI_LIST); + + stream_pos1 = ftell(movie->fp); + + movie->offset_table[1+i*2] = ftell(movie->fp); + awrite (movie, &movie->streams[i].sh, 1, sizeof(AviStreamHeader), movie->fp, AVI_STREAMH); + + movie->offset_table[1+i*2+1] = ftell(movie->fp); + awrite (movie, movie->streams[i].sf, 1, movie->streams[i].sf_size, movie->fp, AVI_BITMAPH); + + stream_pos2 = ftell(movie->fp); + + fseek (movie->fp, stream_pos1-8, SEEK_SET); + + PUT_FCCN((stream_pos2-stream_pos1+4L), movie->fp); + + fseek (movie->fp, stream_pos2, SEEK_SET); + } + + if (ftell(movie->fp) < 2024 - 8) { + chunk.fcc = FCC("JUNK"); + chunk.size = 2024-8-ftell(movie->fp); + + awrite (movie, &chunk, 1, sizeof(AviChunk), movie->fp, AVI_CHUNK); + + for (i=0; i < chunk.size; i++) + putc(0, movie->fp); + } + + header_pos2 = ftell(movie->fp); + + list.fcc = FCC("LIST"); + list.size = 0; + list.ids = FCC("movi"); + + awrite (movie, &list, 1, sizeof(AviList), movie->fp, AVI_LIST); + + movie->movi_offset = ftell(movie->fp)-8L; + + fseek (movie->fp, AVI_HDRL_SOFF, SEEK_SET); + + PUT_FCCN((header_pos2-header_pos1+4L), movie->fp); + + return AVI_ERROR_NONE; +} + +AviError AVI_write_frame (AviMovie *movie, int frame_num, ...) { + AviList list; + AviChunk chunk; + AviIndexEntry *temp; + va_list ap; + int stream; + long rec_off; + AviFormat format; + void *buffer; + int size; + + if (frame_num < 0) + return AVI_ERROR_OPTION; + + /* Allocate the new memory for the index entry */ + + if (frame_num+1 > movie->index_entries) { + temp = (AviIndexEntry *) MEM_mallocN ((frame_num+1) * + (movie->header->Streams+1) * sizeof(AviIndexEntry),"newidxentry"); + if (movie->entries != NULL) { + memcpy (temp, movie->entries, movie->index_entries * (movie->header->Streams+1) + * sizeof(AviIndexEntry)); + MEM_freeN (movie->entries); + } + + movie->entries = temp; + movie->index_entries = frame_num+1; + } + + /* Slap a new record entry onto the end of the file */ + + fseek (movie->fp, 0L, SEEK_END); + + list.fcc = FCC("LIST"); + list.size = 0; + list.ids = FCC("rec "); + + awrite (movie, &list, 1, sizeof(AviList), movie->fp, AVI_LIST); + + rec_off = ftell (movie->fp)-8L; + + /* Write a frame for every stream */ + + va_start (ap, frame_num); + + for (stream=0; stream < movie->header->Streams; stream++) { + unsigned int tbuf=0; + + format = va_arg (ap, AviFormat); + buffer = va_arg (ap, void*); + size = va_arg (ap, int); + + /* Convert the buffer into the output format */ + buffer = avi_format_convert (movie, stream, buffer, format, movie->streams[stream].format, &size); + + /* Write the header info for this data chunk */ + + fseek (movie->fp, 0L, SEEK_END); + + chunk.fcc = avi_get_data_id (format, stream); + chunk.size = size; + + if (size%4) chunk.size += 4 - size%4; + + awrite (movie, &chunk, 1, sizeof(AviChunk), movie->fp, AVI_CHUNK); + + /* Write the index entry for this data chunk */ + + movie->entries[frame_num * (movie->header->Streams+1) + stream + 1].ChunkId = chunk.fcc; + movie->entries[frame_num * (movie->header->Streams+1) + stream + 1].Flags = AVIIF_KEYFRAME; + movie->entries[frame_num * (movie->header->Streams+1) + stream + 1].Offset = ftell(movie->fp)-12L-movie->movi_offset; + movie->entries[frame_num * (movie->header->Streams+1) + stream + 1].Size = chunk.size; + + /* Write the chunk */ + awrite (movie, buffer, 1, size, movie->fp, AVI_RAW); + MEM_freeN (buffer); + + if (size%4) awrite (movie, &tbuf, 1, 4-size%4, movie->fp, AVI_RAW); + + /* Update the stream headers length field */ + movie->streams[stream].sh.Length++; + fseek (movie->fp, movie->offset_table[1+stream*2], SEEK_SET); + awrite (movie, &movie->streams[stream].sh, 1, sizeof(AviStreamHeader), movie->fp, AVI_STREAMH); + } + va_end (ap); + + /* Record the entry for the new record */ + + fseek (movie->fp, 0L, SEEK_END); + + movie->entries[frame_num * (movie->header->Streams+1)].ChunkId = FCC("rec "); + movie->entries[frame_num * (movie->header->Streams+1)].Flags = AVIIF_LIST; + movie->entries[frame_num * (movie->header->Streams+1)].Offset = rec_off-8L-movie->movi_offset; + movie->entries[frame_num * (movie->header->Streams+1)].Size = ftell(movie->fp)-(rec_off+4L); + + /* Update the record size */ + fseek (movie->fp, rec_off, SEEK_SET); + PUT_FCCN (movie->entries[frame_num * (movie->header->Streams+1)].Size, movie->fp); + + /* Update the main header information in the file */ + movie->header->TotalFrames++; + fseek (movie->fp, movie->offset_table[0], SEEK_SET); + awrite (movie, movie->header, 1, sizeof(AviMainHeader), movie->fp, AVI_MAINH); + + return AVI_ERROR_NONE; +} + +AviError AVI_close_compress (AviMovie *movie) { + int temp, movi_size, i; + + fseek (movie->fp, 0L, SEEK_END); + movi_size = ftell (movie->fp); + + PUT_FCC ("idx1", movie->fp); + PUT_FCCN ((movie->index_entries*(movie->header->Streams+1)*16), movie->fp); + + for (temp=0; temp < movie->index_entries*(movie->header->Streams+1); temp++) + awrite (movie, &movie->entries[temp], 1, sizeof(AviIndexEntry), movie->fp, AVI_INDEXE); + + temp = ftell (movie->fp); + + fseek (movie->fp, AVI_RIFF_SOFF, SEEK_SET); + + PUT_FCCN((temp-8L), movie->fp); + + fseek (movie->fp, movie->movi_offset, SEEK_SET); + + PUT_FCCN((movi_size-(movie->movi_offset+4L)),movie->fp); + + fclose (movie->fp); + + for (i=0; i < movie->header->Streams; i++) { + if (movie->streams[i].sf != NULL) + MEM_freeN (movie->streams[i].sf); + } + if (movie->header != NULL) + MEM_freeN (movie->header); + if (movie->entries != NULL) + MEM_freeN (movie->entries); + if (movie->streams != NULL) + MEM_freeN (movie->streams); + if (movie->offset_table != NULL) + MEM_freeN (movie->offset_table); + return AVI_ERROR_NONE; +} diff --git a/source/blender/avi/intern/avi_intern.h b/source/blender/avi/intern/avi_intern.h new file mode 100644 index 00000000000..189072eba8d --- /dev/null +++ b/source/blender/avi/intern/avi_intern.h @@ -0,0 +1,54 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef AVI_INTERN_H +#define AVI_INTERN_H + +#include /* for FILE */ + +#include "MEM_guardedalloc.h" + +unsigned int GET_FCC (FILE *fp); +unsigned int GET_TCC (FILE *fp); + +#define PUT_FCC(ch4, fp) putc(ch4[0],fp); putc(ch4[1],fp); putc(ch4[2],fp); putc(ch4[3],fp) +#define PUT_FCCN(num, fp) putc((num>>0)&0377,fp); putc((num>>8)&0377,fp); putc((num>>16)&0377,fp); putc((num>>24)&0377,fp) +#define PUT_TCC(ch2, fp) putc(ch2[0],fp); putc(ch2[1],fp) + +void *avi_format_convert (AviMovie *movie, int stream, void *buffer, AviFormat from, AviFormat to, int *size); + +int avi_get_data_id(AviFormat format, int stream); +int avi_get_format_type(AviFormat format); +int avi_get_format_fcc(AviFormat format); +int avi_get_format_compression(AviFormat format); + +#endif + diff --git a/source/blender/avi/intern/avirgb.c b/source/blender/avi/intern/avirgb.c new file mode 100644 index 00000000000..8461167efc8 --- /dev/null +++ b/source/blender/avi/intern/avirgb.c @@ -0,0 +1,153 @@ +/** + * avirgb.c + * + * This is external code. Converts rgb-type avi-s. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "AVI_avi.h" +#include +#include + +#include "MEM_guardedalloc.h" +#include "avirgb.h" + +#if defined(__sgi) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__) +#define WORDS_BIGENDIAN +#endif + + +/* implementation */ + +void *avi_converter_from_avi_rgb (AviMovie *movie, int stream, unsigned char *buffer, int *size) { + int x, y,i, rowstride; + unsigned char *buf; + AviBitmapInfoHeader *bi; + short bits= 32; + + bi= (AviBitmapInfoHeader *) movie->streams[stream].sf; + if (bi) bits= bi->BitCount; + + if (bits==16) { + unsigned short *pxl; + unsigned char *to; + #ifdef WORDS_BIGENDIAN + unsigned char *pxla; + #endif + + buf = MEM_mallocN (movie->header->Height * movie->header->Width * 3, "fromavirgbbuf"); + + y= movie->header->Height; + to= buf; + + while (y--) { + pxl= (unsigned short *) (buffer + y * movie->header->Width * 2); + + #ifdef WORDS_BIGENDIAN + pxla= (unsigned char *)pxl; + #endif + + x= movie->header->Width; + while (x--) { + #ifdef WORDS_BIGENDIAN + i= pxla[0]; + pxla[0]= pxla[1]; + pxla[1]= i; + + pxla+=2; + #endif + + *(to++)= ((*pxl>>10)&0x1f)*8; + *(to++)= ((*pxl>>5)&0x1f)*8; + *(to++)= (*pxl&0x1f)*8; + pxl++; + } + } + + MEM_freeN (buffer); + + return buf; + } else { + buf = MEM_mallocN (movie->header->Height * movie->header->Width * 3, "fromavirgbbuf"); + + rowstride = movie->header->Width*3; + if (bits!=16) if (movie->header->Width%2) rowstride++; + + for (y=0; y < movie->header->Height; y++) { + memcpy (&buf[y*movie->header->Width*3], &buffer[((movie->header->Height-1)-y)*rowstride], movie->header->Width*3); + } + + for (y=0; y < movie->header->Height*movie->header->Width*3; y+=3) { + i = buf[y]; + buf[y] = buf[y+2]; + buf[y+2] = i; + } + + MEM_freeN (buffer); + + return buf; + } +} + +void *avi_converter_to_avi_rgb (AviMovie *movie, int stream, unsigned char *buffer, int *size) { + int y, x, i, rowstride; + unsigned char *buf; + + *size= movie->header->Height * movie->header->Width * 3; + if (movie->header->Width%2) *size+= movie->header->Height; + + buf = MEM_mallocN (*size,"toavirgbbuf"); + + rowstride = movie->header->Width*3; + if (movie->header->Width%2) rowstride++; + + for (y=0; y < movie->header->Height; y++) { + memcpy (&buf[y*rowstride], &buffer[((movie->header->Height-1)-y)*movie->header->Width*3], movie->header->Width*3); + } + + for (y=0; y < movie->header->Height; y++) { + for (x=0; x < movie->header->Width*3; x+=3) { + i = buf[y*rowstride+x]; + buf[y*rowstride+x] = buf[y*rowstride+x+2]; + buf[y*rowstride+x+2] = i; + } + } + + MEM_freeN (buffer); + + return buf; +} diff --git a/source/blender/avi/intern/avirgb.h b/source/blender/avi/intern/avirgb.h new file mode 100644 index 00000000000..03c0682b024 --- /dev/null +++ b/source/blender/avi/intern/avirgb.h @@ -0,0 +1,35 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +void *avi_converter_from_avi_rgb (AviMovie *movie, int stream, unsigned char *buffer, int *size); +void *avi_converter_to_avi_rgb (AviMovie *movie, int stream, unsigned char *buffer, int *size); + diff --git a/source/blender/avi/intern/codecs.c b/source/blender/avi/intern/codecs.c new file mode 100644 index 00000000000..3daff52a947 --- /dev/null +++ b/source/blender/avi/intern/codecs.c @@ -0,0 +1,147 @@ +/** + * codecs.c + * + * This is external code. Identify and convert different avi-files. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "AVI_avi.h" +#include "avi_intern.h" + +#include "avirgb.h" +#include "mjpeg.h" +#include "rgb32.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +void *avi_format_convert (AviMovie *movie, int stream, void *buffer, AviFormat from, AviFormat to, int *size) { + if (from == to) + return buffer; + + if (from != AVI_FORMAT_RGB24 && + to != AVI_FORMAT_RGB24) + return avi_format_convert(movie, stream, + avi_format_convert (movie, stream, buffer, from, AVI_FORMAT_RGB24, size), + AVI_FORMAT_RGB24, to, size); + + switch (to) { + case AVI_FORMAT_RGB24: + switch (from) { + case AVI_FORMAT_AVI_RGB: + buffer = avi_converter_from_avi_rgb (movie, stream, buffer, size); + break; + case AVI_FORMAT_MJPEG: + buffer = avi_converter_from_mjpeg (movie, stream, buffer, size); + break; + case AVI_FORMAT_RGB32: + buffer = avi_converter_from_rgb32 (movie, stream, buffer, size); + break; + default: + break; + } + break; + case AVI_FORMAT_AVI_RGB: + buffer = avi_converter_to_avi_rgb (movie, stream, buffer, size); + break; + case AVI_FORMAT_MJPEG: + buffer = avi_converter_to_mjpeg (movie, stream, buffer, size); + break; + case AVI_FORMAT_RGB32: + buffer = avi_converter_to_rgb32 (movie, stream, buffer, size); + break; + default: + break; + } + + return buffer; +} + +int avi_get_data_id (AviFormat format, int stream) { + char fcc[5]; + + if (avi_get_format_type (format) == FCC("vids")) + sprintf (fcc,"%2.2ddc",stream); + else if (avi_get_format_type (format) == FCC("auds")) + sprintf (fcc,"%2.2ddc",stream); + else + return 0; + + return FCC(fcc); +} + +int avi_get_format_type (AviFormat format) { + switch (format) { + case AVI_FORMAT_RGB24: + case AVI_FORMAT_RGB32: + case AVI_FORMAT_AVI_RGB: + case AVI_FORMAT_MJPEG: + return FCC("vids"); + break; + default: + return 0; + break; + } +} + +int avi_get_format_fcc (AviFormat format) { + switch (format) { + case AVI_FORMAT_RGB24: + case AVI_FORMAT_RGB32: + case AVI_FORMAT_AVI_RGB: + return FCC("DIB "); + break; + case AVI_FORMAT_MJPEG: + return FCC("MJPG"); + break; + default: + return 0; + break; + } +} + +int avi_get_format_compression (AviFormat format) { + switch (format) { + case AVI_FORMAT_RGB24: + case AVI_FORMAT_RGB32: + case AVI_FORMAT_AVI_RGB: + return 0; + break; + case AVI_FORMAT_MJPEG: + return FCC("MJPG"); + break; + default: + return 0; + break; + } +} diff --git a/source/blender/avi/intern/endian.c b/source/blender/avi/intern/endian.c new file mode 100644 index 00000000000..152530dac0d --- /dev/null +++ b/source/blender/avi/intern/endian.c @@ -0,0 +1,216 @@ +/** + * endian.h + * + * This is external code. Streams bytes to output depending on the + * endianness of the system. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include "AVI_avi.h" +#include "endian.h" +#include "avi_intern.h" + +#if defined(__sgi) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__) +#define WORDS_BIGENDIAN +#endif + +static void invert (int *num) { + int new=0,i,j; + + for (j=0; j < 4; j++) { + for (i=0; i<8; i++) { + new |= ((*num>>(j*8+i))&1)<<((3-j)*8+i); + } + } + + *num = new; +} + +static void sinvert (short int *num) { + short int new=0; + int i,j; + + for (j=0; j < 2; j++) { + for (i=0; i<8; i++) { + new |= ((*num>>(j*8+i))&1)<<((1-j)*8+i); + } + } + + *num = new; +} + +static void Ichunk (AviChunk *chunk) { + invert (&chunk->fcc); + invert (&chunk->size); +} + +#ifdef WORDS_BIGENDIAN +static void Ilist (AviList *list){ + invert (&list->fcc); + invert (&list->size); + invert (&list->ids); +} + +static void Imainh (AviMainHeader *mainh) { + invert (&mainh->fcc); + invert (&mainh->size); + invert (&mainh->MicroSecPerFrame); + invert (&mainh->MaxBytesPerSec); + invert (&mainh->PaddingGranularity); + invert (&mainh->Flags); + invert (&mainh->TotalFrames); + invert (&mainh->InitialFrames); + invert (&mainh->Streams); + invert (&mainh->SuggestedBufferSize); + invert (&mainh->Width); + invert (&mainh->Height); + invert (&mainh->Reserved[0]); + invert (&mainh->Reserved[1]); + invert (&mainh->Reserved[2]); + invert (&mainh->Reserved[3]); +} + +static void Istreamh (AviStreamHeader *streamh) { + invert (&streamh->fcc); + invert (&streamh->size); + invert (&streamh->Type); + invert (&streamh->Handler); + invert (&streamh->Flags); + sinvert (&streamh->Priority); + sinvert (&streamh->Language); + invert (&streamh->InitialFrames); + invert (&streamh->Scale); + invert (&streamh->Rate); + invert (&streamh->Start); + invert (&streamh->Length); + invert (&streamh->SuggestedBufferSize); + invert (&streamh->Quality); + invert (&streamh->SampleSize); + sinvert (&streamh->left); + sinvert (&streamh->right); + sinvert (&streamh->top); + sinvert (&streamh->bottom); +} + +static void Ibitmaph (AviBitmapInfoHeader *bitmaph) { + invert (&bitmaph->fcc); + invert (&bitmaph->size); + invert (&bitmaph->Size); + invert (&bitmaph->Width); + invert (&bitmaph->Height); + sinvert (&bitmaph->Planes); + sinvert (&bitmaph->BitCount); + invert (&bitmaph->Compression); + invert (&bitmaph->SizeImage); + invert (&bitmaph->XPelsPerMeter); + invert (&bitmaph->YPelsPerMeter); + invert (&bitmaph->ClrUsed); + invert (&bitmaph->ClrImportant); +} + +static void Imjpegu (AviMJPEGUnknown *mjpgu) { + invert (&mjpgu->a); + invert (&mjpgu->b); + invert (&mjpgu->c); + invert (&mjpgu->d); + invert (&mjpgu->e); + invert (&mjpgu->f); + invert (&mjpgu->g); +} + +static void Iindexe (AviIndexEntry *indexe) { + invert (&indexe->ChunkId); + invert (&indexe->Flags); + invert (&indexe->Offset); + invert (&indexe->Size); +} +#endif /* WORDS_BIGENDIAN */ + +void awrite (AviMovie *movie, void *datain, int block, int size, FILE *fp, int type) { +#ifdef WORDS_BIGENDIAN + void *data; + + data = MEM_mallocN (size, "avi endian"); + + memcpy (data, datain, size); + + switch (type) { + case AVI_RAW: + fwrite (data, block, size, fp); + break; + case AVI_CHUNK: + Ichunk ((AviChunk *) data); + fwrite (data, block, size, fp); + break; + case AVI_LIST: + Ilist ((AviList *) data); + fwrite (data, block, size, fp); + break; + case AVI_MAINH: + Imainh ((AviMainHeader *) data); + fwrite (data, block, size, fp); + break; + case AVI_STREAMH: + Istreamh ((AviStreamHeader *) data); + fwrite (data, block, size, fp); + break; + case AVI_BITMAPH: + Ibitmaph ((AviBitmapInfoHeader *) data); + if (size==sizeof(AviBitmapInfoHeader) + sizeof(AviMJPEGUnknown)) { + Imjpegu((AviMJPEGUnknown*)((char*)data+sizeof(AviBitmapInfoHeader))); + } + fwrite (data, block, size, fp); + break; + case AVI_MJPEGU: + Imjpegu ((AviMJPEGUnknown *) data); + fwrite (data, block, size, fp); + break; + case AVI_INDEXE: + Iindexe ((AviIndexEntry *) data); + fwrite (data, block, size, fp); + break; + default: + break; + } + + MEM_freeN (data); +#else /* WORDS_BIGENDIAN */ + fwrite (datain, block, size, fp); +#endif /* WORDS_BIGENDIAN */ +} diff --git a/source/blender/avi/intern/endian.h b/source/blender/avi/intern/endian.h new file mode 100644 index 00000000000..907069c1f87 --- /dev/null +++ b/source/blender/avi/intern/endian.h @@ -0,0 +1,55 @@ +/** + * endian.h + * + * This is external code. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * */ + +#ifndef AVI_ENDIAN_H +#define AVI_ENDIAN_H + +#include +#include "AVI_avi.h" + +#define AVI_RAW 0 +#define AVI_CHUNK 1 +#define AVI_LIST 2 +#define AVI_MAINH 3 +#define AVI_STREAMH 4 +#define AVI_BITMAPH 5 +#define AVI_INDEXE 6 +#define AVI_MJPEGU 7 + +void awrite (AviMovie *movie, void *datain, int block, int size, FILE *fp, int type); + +#endif + diff --git a/source/blender/avi/intern/mjpeg.c b/source/blender/avi/intern/mjpeg.c new file mode 100644 index 00000000000..d51c04a1834 --- /dev/null +++ b/source/blender/avi/intern/mjpeg.c @@ -0,0 +1,458 @@ +/** + * mjpeg.c + * + * This is external code. Converts between avi and mpeg/jpeg. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * */ + +#include "AVI_avi.h" +#include +#include +#include "jpeglib.h" +#include "jerror.h" +#include "MEM_guardedalloc.h" + +#include "mjpeg.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define PADUP(num, amt) ((num+(amt-1))&~(amt-1)) + +static void jpegmemdestmgr_build (j_compress_ptr cinfo, unsigned char *buffer, int bufsize); +static void jpegmemsrcmgr_build (j_decompress_ptr dinfo, unsigned char *buffer, int bufsize); + +static int numbytes; + +static void add_huff_table (j_decompress_ptr dinfo, JHUFF_TBL **htblptr, const UINT8 *bits, const UINT8 *val) { + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) dinfo); + + memcpy((*htblptr)->bits, bits, sizeof((*htblptr)->bits)); + memcpy((*htblptr)->huffval, val, sizeof((*htblptr)->huffval)); + + /* Initialize sent_table FALSE so table will be written to JPEG file. */ + (*htblptr)->sent_table = FALSE; +} + +/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */ +/* IMPORTANT: these are only valid for 8-bit data precision! */ + +static void std_huff_tables (j_decompress_ptr dinfo) { + static const UINT8 bits_dc_luminance[17] = + { /* 0-base */ + 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }; + static const UINT8 val_dc_luminance[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + + static const UINT8 bits_dc_chrominance[17] = + { /* 0-base */ + 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }; + static const UINT8 val_dc_chrominance[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + + static const UINT8 bits_ac_luminance[17] = + { /* 0-base */ + 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d }; + static const UINT8 val_ac_luminance[] = + { + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa }; + static const UINT8 bits_ac_chrominance[17] = + { /* 0-base */ + 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 }; + static const UINT8 val_ac_chrominance[] = + { + 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, + 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, + 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, + 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, + 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, + 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, + 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, + 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa }; + + add_huff_table(dinfo, &dinfo->dc_huff_tbl_ptrs[0], + bits_dc_luminance, val_dc_luminance); + add_huff_table(dinfo, &dinfo->ac_huff_tbl_ptrs[0], + bits_ac_luminance, val_ac_luminance); + add_huff_table(dinfo, &dinfo->dc_huff_tbl_ptrs[1], + bits_dc_chrominance, val_dc_chrominance); + add_huff_table(dinfo, &dinfo->ac_huff_tbl_ptrs[1], + bits_ac_chrominance, val_ac_chrominance); +} + +static int Decode_JPEG(unsigned char *inBuffer, unsigned char *outBuffer, unsigned int width, unsigned int height, int bufsize) { + int rowstride; + unsigned int y; + struct jpeg_decompress_struct dinfo; + struct jpeg_error_mgr jerr; + + numbytes= 0; + + dinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&dinfo); + jpegmemsrcmgr_build(&dinfo, inBuffer, bufsize); + jpeg_read_header(&dinfo, TRUE); + if (dinfo.dc_huff_tbl_ptrs[0] == NULL){ + std_huff_tables(&dinfo); + } + dinfo.out_color_space = JCS_RGB; + dinfo.dct_method = JDCT_IFAST; + + jpeg_start_decompress(&dinfo); + + rowstride= dinfo.output_width*dinfo.output_components; + for (y= 0; y= height) return 0; + + inBuffer+= numbytes; + jpegmemsrcmgr_build(&dinfo, inBuffer, bufsize-numbytes); + + numbytes= 0; + jpeg_read_header(&dinfo, TRUE); + if (dinfo.dc_huff_tbl_ptrs[0] == NULL){ + std_huff_tables(&dinfo); + } + + jpeg_start_decompress(&dinfo); + rowstride= dinfo.output_width*dinfo.output_components; + for (y= 0; ysent_table = TRUE; + cinfo.dc_huff_tbl_ptrs[1]->sent_table = TRUE; + cinfo.ac_huff_tbl_ptrs[0]->sent_table = TRUE; + cinfo.ac_huff_tbl_ptrs[1]->sent_table = TRUE; + + cinfo.comp_info[0].component_id = 0; + cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[1].component_id = 1; + cinfo.comp_info[2].component_id = 2; + + cinfo.write_JFIF_header = FALSE; + + jpeg_start_compress(&cinfo, FALSE); + + i=0; + marker[i++] = 'A'; + marker[i++] = 'V'; + marker[i++] = 'I'; + marker[i++] = '1'; + marker[i++] = 0; + while (i<60) + marker[i++] = 32; + + jpeg_write_marker (&cinfo, JPEG_APP0, marker, 60); + + i=0; + while (i<60) + marker[i++] = 0; + + jpeg_write_marker (&cinfo, JPEG_COM, marker, 60); + + rowstride= cinfo.image_width*cinfo.input_components; + for (y = 0; y < cinfo.image_height; y++){ + jpeg_write_scanlines(&cinfo, (JSAMPARRAY) &inBuffer, 1); + inBuffer += rowstride; + } + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); +} + +static void interlace(unsigned char *to, unsigned char *from, int width, int height) { + int i, rowstride= width*3; + + for (i=0; iheader->Height * movie->header->Width * 3, "avi.avi_converter_from_mjpeg 1"); + + deint= check_and_decode_jpeg(buffer, buf, movie->header->Width, movie->header->Height, *size); + + MEM_freeN(buffer); + + if (deint) { + buffer = MEM_mallocN (movie->header->Height * movie->header->Width * 3, "avi.avi_converter_from_mjpeg 2"); + interlace (buffer, buf, movie->header->Width, movie->header->Height); + MEM_freeN (buf); + + buf= buffer; + } + + return buf; +} + +void *avi_converter_to_mjpeg (AviMovie *movie, int stream, unsigned char *buffer, int *size) { + unsigned char *buf; + int bufsize= *size; + + numbytes = 0; + *size= 0; + + buf = MEM_mallocN (movie->header->Height * movie->header->Width * 3, "avi.avi_converter_to_mjpeg 1"); + if (!movie->interlace) { + check_and_compress_jpeg(movie->streams[stream].sh.Quality/100, buf, buffer, movie->header->Width, movie->header->Height, bufsize); + } else { + deinterlace (movie->odd_fields, buf, buffer, movie->header->Width, movie->header->Height); + MEM_freeN (buffer); + + buffer= buf; + buf= MEM_mallocN (movie->header->Height * movie->header->Width * 3, "avi.avi_converter_to_mjpeg 2"); + + check_and_compress_jpeg(movie->streams[stream].sh.Quality/100, buf, buffer, movie->header->Width, movie->header->Height/2, bufsize/2); + *size+= numbytes; + numbytes=0; + check_and_compress_jpeg(movie->streams[stream].sh.Quality/100, buf+*size, buffer+(movie->header->Height/2)*movie->header->Width*3, movie->header->Width, movie->header->Height/2, bufsize/2); + } + *size += numbytes; + + MEM_freeN (buffer); + return buf; +} + + +/* Compression from memory */ + +static void jpegmemdestmgr_init_destination(j_compress_ptr cinfo) { + ; +} + +static boolean jpegmemdestmgr_empty_output_buffer(j_compress_ptr cinfo) { + return TRUE; +} + +static void jpegmemdestmgr_term_destination(j_compress_ptr cinfo) { + numbytes-= cinfo->dest->free_in_buffer; + + MEM_freeN(cinfo->dest); +} + +static void jpegmemdestmgr_build(j_compress_ptr cinfo, unsigned char *buffer, int bufsize) { + cinfo->dest= MEM_mallocN(sizeof(*(cinfo->dest)), "avi.jpegmemdestmgr_build"); + + cinfo->dest->init_destination= jpegmemdestmgr_init_destination; + cinfo->dest->empty_output_buffer= jpegmemdestmgr_empty_output_buffer; + cinfo->dest->term_destination= jpegmemdestmgr_term_destination; + + cinfo->dest->next_output_byte= buffer; + cinfo->dest->free_in_buffer= bufsize; + + numbytes= bufsize; +} + +/* Decompression from memory */ + +static void jpegmemsrcmgr_init_source(j_decompress_ptr dinfo) { + ; +} + +static boolean jpegmemsrcmgr_fill_input_buffer(j_decompress_ptr dinfo) { + unsigned char *buf= (unsigned char*) dinfo->src->next_input_byte-2; + + /* if we get called, must have run out of data */ + WARNMS(dinfo, JWRN_JPEG_EOF); + + buf[0]= (JOCTET) 0xFF; + buf[1]= (JOCTET) JPEG_EOI; + + dinfo->src->next_input_byte= buf; + dinfo->src->bytes_in_buffer= 2; + + return TRUE; +} + +static void jpegmemsrcmgr_skip_input_data(j_decompress_ptr dinfo, long skipcnt) { + if (dinfo->src->bytes_in_buffersrc->bytes_in_buffer; + + dinfo->src->next_input_byte+= skipcnt; + dinfo->src->bytes_in_buffer-= skipcnt; +} + +static void jpegmemsrcmgr_term_source(j_decompress_ptr dinfo) { + numbytes-= dinfo->src->bytes_in_buffer; + + MEM_freeN(dinfo->src); +} + +static void jpegmemsrcmgr_build(j_decompress_ptr dinfo, unsigned char *buffer, int bufsize) { + dinfo->src= MEM_mallocN(sizeof(*(dinfo->src)), "avi.jpegmemsrcmgr_build"); + + dinfo->src->init_source= jpegmemsrcmgr_init_source; + dinfo->src->fill_input_buffer= jpegmemsrcmgr_fill_input_buffer; + dinfo->src->skip_input_data= jpegmemsrcmgr_skip_input_data; + dinfo->src->resync_to_restart= jpeg_resync_to_restart; + dinfo->src->term_source= jpegmemsrcmgr_term_source; + + dinfo->src->bytes_in_buffer= bufsize; + dinfo->src->next_input_byte= buffer; + + numbytes= bufsize; +} diff --git a/source/blender/avi/intern/mjpeg.h b/source/blender/avi/intern/mjpeg.h new file mode 100644 index 00000000000..5b7f54a6e42 --- /dev/null +++ b/source/blender/avi/intern/mjpeg.h @@ -0,0 +1,35 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +void *avi_converter_from_mjpeg (AviMovie *movie, int stream, unsigned char *buffer, int *size); +void *avi_converter_to_mjpeg (AviMovie *movie, int stream, unsigned char *buffer, int *size); + diff --git a/source/blender/avi/intern/options.c b/source/blender/avi/intern/options.c new file mode 100644 index 00000000000..08c8cb254f0 --- /dev/null +++ b/source/blender/avi/intern/options.c @@ -0,0 +1,130 @@ +/** + * options.h + * + * This is external code. Sets some compression related options + * (width, height quality, framerate). + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * */ + +#include "AVI_avi.h" +#include "avi_intern.h" +#include "endian.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +/* avi_set_compress_options gets its own file... now don't WE feel important? */ + +AviError AVI_set_compress_option (AviMovie *movie, int option_type, int stream, AviOption option, void *opt_data) { + int i; + + if (movie->header->TotalFrames != 0) /* Can't change params after we have already started writing frames */ + return AVI_ERROR_OPTION; + + switch (option_type) { + case AVI_OPTION_TYPE_MAIN: + switch (option) { + case AVI_OPTION_WIDTH: + movie->header->Width = *((int *) opt_data); + movie->header->SuggestedBufferSize = movie->header->Width*movie->header->Height*3; + + for (i=0; i < movie->header->Streams; i++) { + if (avi_get_format_type(movie->streams[i].format) == FCC("vids")) { + ((AviBitmapInfoHeader *) movie->streams[i].sf)->Width = *((int *) opt_data); + movie->streams[i].sh.SuggestedBufferSize = movie->header->SuggestedBufferSize; + movie->streams[i].sh.right = *((int *) opt_data); + ((AviBitmapInfoHeader *) movie->streams[i].sf)->SizeImage = movie->header->SuggestedBufferSize; + fseek (movie->fp, movie->offset_table[1+i*2+1], SEEK_SET); + awrite (movie, movie->streams[i].sf, 1, movie->streams[i].sf_size, movie->fp, AVI_BITMAPH); + } + } + + break; + + case AVI_OPTION_HEIGHT: + movie->header->Height = *((int *) opt_data); + movie->header->SuggestedBufferSize = movie->header->Width*movie->header->Height*3; + + for (i=0; i < movie->header->Streams; i++) { + if (avi_get_format_type(movie->streams[i].format) == FCC("vids")) { + ((AviBitmapInfoHeader *) movie->streams[i].sf)->Height = *((int *) opt_data); + movie->streams[i].sh.SuggestedBufferSize = movie->header->SuggestedBufferSize; + movie->streams[i].sh.bottom = *((int *) opt_data); + ((AviBitmapInfoHeader *) movie->streams[i].sf)->SizeImage = movie->header->SuggestedBufferSize; + fseek (movie->fp, movie->offset_table[1+i*2+1], SEEK_SET); + awrite (movie, movie->streams[i].sf, 1, movie->streams[i].sf_size, movie->fp, AVI_BITMAPH); + } + } + + break; + + case AVI_OPTION_QUALITY: + for (i=0; i < movie->header->Streams; i++) { + if (avi_get_format_type(movie->streams[i].format) == FCC("vids")) { + movie->streams[i].sh.Quality = (*((int *) opt_data))*100; + fseek (movie->fp, movie->offset_table[1+i*2+1], SEEK_SET); + awrite (movie, movie->streams[i].sf, 1, movie->streams[i].sf_size, movie->fp, AVI_BITMAPH); + } + } + break; + + case AVI_OPTION_FRAMERATE: + if (1000000/(*((double *) opt_data))) + movie->header->MicroSecPerFrame = 1000000/(*((double *) opt_data)); + + for (i=0; i < movie->header->Streams; i++) { + if (avi_get_format_type(movie->streams[i].format) == FCC("vids")) { + movie->streams[i].sh.Scale = movie->header->MicroSecPerFrame; + fseek (movie->fp, movie->offset_table[1+i*2+1], SEEK_SET); + awrite (movie, movie->streams[i].sf, 1, movie->streams[i].sf_size, movie->fp, AVI_BITMAPH); + } + } + + } + + fseek (movie->fp, movie->offset_table[0], SEEK_SET); + awrite (movie, movie->header, 1, sizeof(AviMainHeader), movie->fp, AVI_MAINH); + + break; + case AVI_OPTION_TYPE_STRH: + break; + case AVI_OPTION_TYPE_STRF: + break; + default: + return AVI_ERROR_OPTION; + break; + } + + return AVI_ERROR_NONE; +} + diff --git a/source/blender/avi/intern/rgb32.c b/source/blender/avi/intern/rgb32.c new file mode 100644 index 00000000000..d838ba5b786 --- /dev/null +++ b/source/blender/avi/intern/rgb32.c @@ -0,0 +1,91 @@ +/** + * rgb32.c + * + * This is external code. Converts between rgb32 and avi. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * */ + +#include "AVI_avi.h" +#include +#include +#include "MEM_guardedalloc.h" +#include "rgb32.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +void *avi_converter_from_rgb32 (AviMovie *movie, int stream, unsigned char *buffer, int *size) { + int y, x, rowstridea, rowstrideb; + unsigned char *buf; + + buf = MEM_mallocN (movie->header->Height * movie->header->Width * 3, "fromrgb32buf"); + *size = movie->header->Height * movie->header->Width * 3; + + rowstridea = movie->header->Width*3; + rowstrideb = movie->header->Width*4; + + for (y=0; y < movie->header->Height; y++) { + for (x=0; x < movie->header->Width; x++) { + buf[y*rowstridea + x*3 + 0] = buffer[y*rowstrideb + x*4 + 3]; + buf[y*rowstridea + x*3 + 1] = buffer[y*rowstrideb + x*4 + 2]; + buf[y*rowstridea + x*3 + 2] = buffer[y*rowstrideb + x*4 + 1]; + } + } + + MEM_freeN (buffer); + + return buf; +} + +void *avi_converter_to_rgb32 (AviMovie *movie, int stream, unsigned char *buffer, int *size) { + int i; + unsigned char *buf; + unsigned char *to, *from; + + buf= MEM_mallocN (movie->header->Height * movie->header->Width * 4, "torgb32buf"); + *size= movie->header->Height * movie->header->Width * 4; + + memset(buf, 255, *size); + + to= buf; from= buffer; + i=movie->header->Height*movie->header->Width; + + while(i--) { + memcpy(to, from, 3); + to+=4; from+=3; + } + + MEM_freeN (buffer); + + return buf; +} diff --git a/source/blender/avi/intern/rgb32.h b/source/blender/avi/intern/rgb32.h new file mode 100644 index 00000000000..019869c6058 --- /dev/null +++ b/source/blender/avi/intern/rgb32.h @@ -0,0 +1,35 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +void *avi_converter_from_rgb32 (AviMovie *movie, int stream, unsigned char *buffer, int *size); +void *avi_converter_to_rgb32 (AviMovie *movie, int stream, unsigned char *buffer, int *size); + diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h new file mode 100644 index 00000000000..1852dc72a40 --- /dev/null +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -0,0 +1,461 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BKE_DERIVEDMESH_H +#define BKE_DERIVEDMESH_H + +/* TODO (Probably) + * + * o Make drawMapped* functions take a predicate function that + * determines whether to draw the edge (this predicate can + * also set color, etc). This will be slightly more general + * and allow some of the functions to be collapsed. + * o Once accessor functions are added then single element draw + * functions can be implemented using primitive accessors. + * o Add function to dispatch to renderer instead of using + * conversion to DLM. + */ + +#include "DNA_customdata_types.h" +#include "BKE_customdata.h" + +struct MVert; +struct MEdge; +struct MFace; +struct MTFace; +struct Object; +struct Mesh; +struct EditMesh; +struct ModifierData; +struct MCol; +struct ColorBand; + +/* number of sub-elements each mesh element has (for interpolation) */ +#define SUB_ELEMS_VERT 0 +#define SUB_ELEMS_EDGE 2 +#define SUB_ELEMS_FACE 4 + +typedef struct DerivedMesh DerivedMesh; +struct DerivedMesh { + /* Private DerivedMesh data, only for internal DerivedMesh use */ + CustomData vertData, edgeData, faceData; + int numVertData, numEdgeData, numFaceData; + int needsFree; /* checked on ->release, is set to 0 for cached results */ + + /* Misc. Queries */ + + /* Also called in Editmode */ + int (*getNumVerts)(DerivedMesh *dm); + /* Also called in Editmode */ + int (*getNumFaces)(DerivedMesh *dm); + + int (*getNumEdges)(DerivedMesh *dm); + + /* copy a single vert/edge/face from the derived mesh into + * *{vert/edge/face}_r. note that the current implementation + * of this function can be quite slow, iterating over all + * elements (editmesh, verse mesh) + */ + void (*getVert)(DerivedMesh *dm, int index, struct MVert *vert_r); + void (*getEdge)(DerivedMesh *dm, int index, struct MEdge *edge_r); + void (*getFace)(DerivedMesh *dm, int index, struct MFace *face_r); + + /* return a pointer to the entire array of verts/edges/face from the + * derived mesh. if such an array does not exist yet, it will be created, + * and freed on the next ->release(). consider using getVert/Edge/Face if + * you are only interested in a few verts/edges/faces. + */ + struct MVert *(*getVertArray)(DerivedMesh *dm); + struct MEdge *(*getEdgeArray)(DerivedMesh *dm); + struct MFace *(*getFaceArray)(DerivedMesh *dm); + + /* copy all verts/edges/faces from the derived mesh into + * *{vert/edge/face}_r (must point to a buffer large enough) + */ + void (*copyVertArray)(DerivedMesh *dm, struct MVert *vert_r); + void (*copyEdgeArray)(DerivedMesh *dm, struct MEdge *edge_r); + void (*copyFaceArray)(DerivedMesh *dm, struct MFace *face_r); + + /* return a copy of all verts/edges/faces from the derived mesh + * it is the caller's responsibility to free the returned pointer + */ + struct MVert *(*dupVertArray)(DerivedMesh *dm); + struct MEdge *(*dupEdgeArray)(DerivedMesh *dm); + struct MFace *(*dupFaceArray)(DerivedMesh *dm); + + /* return a pointer to a single element of vert/edge/face custom data + * from the derived mesh (this gives a pointer to the actual data, not + * a copy) + */ + void *(*getVertData)(DerivedMesh *dm, int index, int type); + void *(*getEdgeData)(DerivedMesh *dm, int index, int type); + void *(*getFaceData)(DerivedMesh *dm, int index, int type); + + /* return a pointer to the entire array of vert/edge/face custom data + * from the derived mesh (this gives a pointer to the actual data, not + * a copy) + */ + void *(*getVertDataArray)(DerivedMesh *dm, int type); + void *(*getEdgeDataArray)(DerivedMesh *dm, int type); + void *(*getFaceDataArray)(DerivedMesh *dm, int type); + + /* Iterate over each mapped vertex in the derived mesh, calling the + * given function with the original vert and the mapped vert's new + * coordinate and normal. For historical reasons the normal can be + * passed as a float or short array, only one should be non-NULL. + */ + void (*foreachMappedVert)( + DerivedMesh *dm, + void (*func)(void *userData, int index, float *co, + float *no_f, short *no_s), + void *userData); + + /* Iterate over each mapped edge in the derived mesh, calling the + * given function with the original edge and the mapped edge's new + * coordinates. + */ + void (*foreachMappedEdge)(DerivedMesh *dm, + void (*func)(void *userData, int index, + float *v0co, float *v1co), + void *userData); + + /* Iterate over each mapped face in the derived mesh, calling the + * given function with the original face and the mapped face's (or + * faces') center and normal. + */ + void (*foreachMappedFaceCenter)(DerivedMesh *dm, + void (*func)(void *userData, int index, + float *cent, float *no), + void *userData); + + /* Iterate over all vertex points, calling DO_MINMAX with given args. + * + * Also called in Editmode + */ + void (*getMinMax)(DerivedMesh *dm, float min_r[3], float max_r[3]); + + /* Direct Access Operations */ + /* o Can be undefined */ + /* o Must be defined for modifiers that only deform however */ + + /* Get vertex location, undefined if index is not valid */ + void (*getVertCo)(DerivedMesh *dm, int index, float co_r[3]); + + /* Fill the array (of length .getNumVerts()) with all vertex locations */ + void (*getVertCos)(DerivedMesh *dm, float (*cos_r)[3]); + + /* Get vertex normal, undefined if index is not valid */ + void (*getVertNo)(DerivedMesh *dm, int index, float no_r[3]); + + /* Drawing Operations */ + + /* Draw all vertices as bgl points (no options) */ + void (*drawVerts)(DerivedMesh *dm); + + /* Draw edges in the UV mesh (if exists) */ + void (*drawUVEdges)(DerivedMesh *dm); + + /* Draw all edges as lines (no options) + * + * Also called for *final* editmode DerivedMeshes + */ + void (*drawEdges)(DerivedMesh *dm, int drawLooseEdges); + + /* Draw all loose edges (edges w/ no adjoining faces) */ + void (*drawLooseEdges)(DerivedMesh *dm); + + /* Draw all faces + * o Set face normal or vertex normal based on inherited face flag + * o Use inherited face material index to call setMaterial + * o Only if setMaterial returns true + * + * Also called for *final* editmode DerivedMeshes + */ + void (*drawFacesSolid)(DerivedMesh *dm, int (*setMaterial)(int)); + + /* Draw all faces + * o If useTwoSided, draw front and back using col arrays + * o col1,col2 are arrays of length numFace*4 of 4 component colors + * in ABGR format, and should be passed as per-face vertex color. + */ + void (*drawFacesColored)(DerivedMesh *dm, int useTwoSided, + unsigned char *col1, unsigned char *col2); + + /* Draw all faces using MTFace + * o Drawing options too complicated to enumerate, look at code. + */ + void (*drawFacesTex)(DerivedMesh *dm, + int (*setDrawOptions)(struct MTFace *tface, + struct MCol *mcol, int matnr)); + + /* Draw mapped faces (no color, or texture) + * o Only if !setDrawOptions or + * setDrawOptions(userData, mapped-face-index, drawSmooth_r) + * returns true + * + * If drawSmooth is set to true then vertex normals should be set and + * glShadeModel called with GL_SMOOTH. Otherwise the face normal should + * be set and glShadeModel called with GL_FLAT. + * + * The setDrawOptions is allowed to not set drawSmooth (for example, when + * lighting is disabled), in which case the implementation should draw as + * smooth shaded. + */ + void (*drawMappedFaces)(DerivedMesh *dm, + int (*setDrawOptions)(void *userData, int index, + int *drawSmooth_r), + void *userData, int useColors); + + /* Draw mapped faces using MTFace + * o Drawing options too complicated to enumerate, look at code. + */ + void (*drawMappedFacesTex)(DerivedMesh *dm, + int (*setDrawOptions)(void *userData, + int index), + void *userData); + + /* Draw mapped edges as lines + * o Only if !setDrawOptions or setDrawOptions(userData, mapped-edge) + * returns true + */ + void (*drawMappedEdges)(DerivedMesh *dm, + int (*setDrawOptions)(void *userData, int index), + void *userData); + + /* Draw mapped edges as lines with interpolation values + * o Only if !setDrawOptions or + * setDrawOptions(userData, mapped-edge, mapped-v0, mapped-v1, t) + * returns true + * + * NOTE: This routine is optional! + */ + void (*drawMappedEdgesInterp)(DerivedMesh *dm, + int (*setDrawOptions)(void *userData, + int index), + void (*setDrawInterpOptions)(void *userData, + int index, + float t), + void *userData); + + /* Release reference to the DerivedMesh. This function decides internally + * if the DerivedMesh will be freed, or cached for later use. */ + void (*release)(DerivedMesh *dm); +}; + +/* utility function to initialise a DerivedMesh's function pointers to + * the default implementation (for those functions which have a default) + */ +void DM_init_funcs(DerivedMesh *dm); + +/* utility function to initialise a DerivedMesh for the desired number + * of vertices, edges and faces (doesn't allocate memory for them, just + * sets up the custom data layers) + */ +void DM_init(DerivedMesh *dm, int numVerts, int numEdges, int numFaces); + +/* utility function to initialise a DerivedMesh for the desired number + * of vertices, edges and faces, with a layer setup copied from source + */ +void DM_from_template(DerivedMesh *dm, DerivedMesh *source, + int numVerts, int numEdges, int numFaces); + +/* utility function to release a DerivedMesh's layers + * returns 1 if DerivedMesh has to be released by the backend, 0 otherwise + */ +int DM_release(DerivedMesh *dm); + +/* utility function to convert a DerivedMesh to a Mesh + */ +void DM_to_mesh(DerivedMesh *dm, struct Mesh *me); + +/* set the CD_FLAG_NOCOPY flag in custom data layers where the mask is + * zero for the layer type, so only layer types specified by the mask + * will be copied + */ +void DM_set_only_copy(DerivedMesh *dm, CustomDataMask mask); + +/* adds a vertex/edge/face custom data layer to a DerivedMesh, optionally + * backed by an external data array + * alloctype defines how the layer is allocated or copied, and how it is + * freed, see BKE_customdata.h for the different options + */ +void DM_add_vert_layer(struct DerivedMesh *dm, int type, int alloctype, + void *layer); +void DM_add_edge_layer(struct DerivedMesh *dm, int type, int alloctype, + void *layer); +void DM_add_face_layer(struct DerivedMesh *dm, int type, int alloctype, + void *layer); + +/* custom data access functions + * return pointer to data from first layer which matches type + * if they return NULL for valid indices, data doesn't exist + * note these return pointers - any change modifies the internals of the mesh + */ +void *DM_get_vert_data(struct DerivedMesh *dm, int index, int type); +void *DM_get_edge_data(struct DerivedMesh *dm, int index, int type); +void *DM_get_face_data(struct DerivedMesh *dm, int index, int type); + +/* custom data layer access functions + * return pointer to first data layer which matches type (a flat array) + * if they return NULL, data doesn't exist + * note these return pointers - any change modifies the internals of the mesh + */ +void *DM_get_vert_data_layer(struct DerivedMesh *dm, int type); +void *DM_get_edge_data_layer(struct DerivedMesh *dm, int type); +void *DM_get_face_data_layer(struct DerivedMesh *dm, int type); + +/* custom data setting functions + * copy supplied data into first layer of type using layer's copy function + * (deep copy if appropriate) + */ +void DM_set_vert_data(struct DerivedMesh *dm, int index, int type, void *data); +void DM_set_edge_data(struct DerivedMesh *dm, int index, int type, void *data); +void DM_set_face_data(struct DerivedMesh *dm, int index, int type, void *data); + +/* custom data copy functions + * copy count elements from source_index in source to dest_index in dest + * these copy all layers for which the CD_FLAG_NOCOPY flag is not set + */ +void DM_copy_vert_data(struct DerivedMesh *source, struct DerivedMesh *dest, + int source_index, int dest_index, int count); +void DM_copy_edge_data(struct DerivedMesh *source, struct DerivedMesh *dest, + int source_index, int dest_index, int count); +void DM_copy_face_data(struct DerivedMesh *source, struct DerivedMesh *dest, + int source_index, int dest_index, int count); + +/* custom data free functions + * free count elements, starting at index + * they free all layers for which the CD_FLAG_NOCOPY flag is not set + */ +void DM_free_vert_data(struct DerivedMesh *dm, int index, int count); +void DM_free_edge_data(struct DerivedMesh *dm, int index, int count); +void DM_free_face_data(struct DerivedMesh *dm, int index, int count); + +/* interpolates vertex data from the vertices indexed by src_indices in the + * source mesh using the given weights and stores the result in the vertex + * indexed by dest_index in the dest mesh + */ +void DM_interp_vert_data(struct DerivedMesh *source, struct DerivedMesh *dest, + int *src_indices, float *weights, + int count, int dest_index); + +/* interpolates edge data from the edges indexed by src_indices in the + * source mesh using the given weights and stores the result in the edge indexed + * by dest_index in the dest mesh. + * if weights is NULL, all weights default to 1. + * if vert_weights is non-NULL, any per-vertex edge data is interpolated using + * vert_weights[i] multiplied by weights[i]. + */ +typedef float EdgeVertWeight[SUB_ELEMS_EDGE][SUB_ELEMS_EDGE]; +void DM_interp_edge_data(struct DerivedMesh *source, struct DerivedMesh *dest, + int *src_indices, + float *weights, EdgeVertWeight *vert_weights, + int count, int dest_index); + +/* interpolates face data from the faces indexed by src_indices in the + * source mesh using the given weights and stores the result in the face indexed + * by dest_index in the dest mesh. + * if weights is NULL, all weights default to 1. + * if vert_weights is non-NULL, any per-vertex face data is interpolated using + * vert_weights[i] multiplied by weights[i]. + */ +typedef float FaceVertWeight[SUB_ELEMS_FACE][SUB_ELEMS_FACE]; +void DM_interp_face_data(struct DerivedMesh *source, struct DerivedMesh *dest, + int *src_indices, + float *weights, FaceVertWeight *vert_weights, + int count, int dest_index); + +void DM_swap_face_data(struct DerivedMesh *dm, int index, int *corner_indices); + +/* Temporary? A function to give a colorband to derivedmesh for vertexcolor ranges */ +void vDM_ColorBand_store(struct ColorBand *coba); + +/* Simple function to get me->totvert amount of vertices/normals, + correctly deformed and subsurfered. Needed especially when vertexgroups are involved. + In use now by vertex/weigt paint and particles */ +float *mesh_get_mapped_verts_nors(struct Object *ob); + + /* */ +DerivedMesh *mesh_get_derived_final(struct Object *ob, + CustomDataMask dataMask); +DerivedMesh *mesh_get_derived_deform(struct Object *ob, + CustomDataMask dataMask); + +DerivedMesh *mesh_create_derived_for_modifier(struct Object *ob, struct ModifierData *md); + +DerivedMesh *mesh_create_derived_render(struct Object *ob, + CustomDataMask dataMask); +/* same as above but wont use render settings */ +DerivedMesh *mesh_create_derived_view(struct Object *ob, + CustomDataMask dataMask); +DerivedMesh *mesh_create_derived_no_deform(struct Object *ob, + float (*vertCos)[3], + CustomDataMask dataMask); +DerivedMesh *mesh_create_derived_no_deform_render(struct Object *ob, + float (*vertCos)[3], + CustomDataMask dataMask); + +DerivedMesh *editmesh_get_derived_base(void); +DerivedMesh *editmesh_get_derived_cage(CustomDataMask dataMask); +DerivedMesh *editmesh_get_derived_cage_and_final(DerivedMesh **final_r, + CustomDataMask dataMask); + +/* returns an array of deform matrices for crazyspace correction, and the + number of modifiers left */ +int editmesh_get_first_deform_matrices(float (**deformmats)[3][3], + float (**deformcos)[3]); + +void weight_to_rgb(float input, float *fr, float *fg, float *fb); + +/* determines required DerivedMesh data according to view and edit modes */ +CustomDataMask get_viewedit_datamask(); + +/* repeate this pattern + X000X000 + 00000000 + 00X000X0 + 00000000 */ + +#define DM_FACE_STIPPLE \ +{ \ + 136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0, \ + 136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0, \ + 136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0, \ + 136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0, \ + 136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0, \ + 136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0, \ + 136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0, \ + 136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0 \ +} + +#endif + diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h new file mode 100644 index 00000000000..cbec4cf04fb --- /dev/null +++ b/source/blender/blenkernel/BKE_action.h @@ -0,0 +1,164 @@ +/* BKE_action.h May 2001 + * + * Blender kernel action functionality + * + * Reevan McKay + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Full recode, Ton Roosendaal, Crete 2005 + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BKE_ACTION_H +#define BKE_ACTION_H + +#include "DNA_listBase.h" + +/** + * The following structures are defined in DNA_action_types.h + */ + +struct bAction; +struct bActionChannel; +struct bPose; +struct bPoseChannel; +struct Object; + +/* Kernel prototypes */ +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Removes and deallocates all channels from a pose. + * Does not free the pose itself. + */ +void free_pose_channels(struct bPose *pose); + +/** + * Allocate a new pose on the heap, and copy the src pose and it's channels + * into the new pose. *dst is set to the newly allocated structure, and assumed to be NULL. + */ +void copy_pose(struct bPose **dst, struct bPose *src, + int copyconstraints); + +/** + * Deallocate the action's channels including constraint channels. + * does not free the action structure. + */ +void free_action(struct bAction * id); + +void make_local_action(struct bAction *act); + +/* only for armatures, doing pose actions only too */ +void do_all_pose_actions(struct Object *); +/* only for objects, doing only 1 channel */ +void do_all_object_actions(struct Object *); +/* only for Mesh, Curve, Surface, Lattice, doing only Shape channel */ +void do_all_shape_actions(struct Object *); + + +/** + * Return a pointer to the pose channel of the given name + * from this pose. + */ +struct bPoseChannel *get_pose_channel(const struct bPose *pose, + const char *name); + +/** + * Looks to see if the channel with the given name + * already exists in this pose - if not a new one is + * allocated and initialized. + */ +struct bPoseChannel *verify_pose_channel(struct bPose* pose, + const char* name); + +/* sets constraint flags */ +void update_pose_constraint_flags(struct bPose *pose); + +/* clears BONE_UNKEYED flags for frame changing */ +void framechange_poses_clear_unkeyed(void); + +/** + * Allocate a new bAction on the heap and copy + * the contents of src into it. If src is NULL NULL is returned. + */ + +struct bAction *copy_action(struct bAction *src); + +/** + * Some kind of bounding box operation on the action. + */ +void calc_action_range(const struct bAction *act, float *start, float *end, int incl_hidden); + +/** + * Set the pose channels from the given action. + */ +void extract_pose_from_action(struct bPose *pose, struct bAction *act, float ctime); + +/** + * Get the effects of the given action using a workob + */ +void what_does_obaction(struct Object *ob, struct bAction *act, float cframe); + +/** + * Iterate through the action channels of the action + * and return the channel with the given name. + * Returns NULL if no channel. + */ +struct bActionChannel *get_action_channel(struct bAction *act, const char *name); +/** + * Iterate through the action channels of the action + * and return the channel with the given name. + * Returns and adds new channel if no channel. + */ +struct bActionChannel *verify_action_channel(struct bAction *act, const char *name); + + /* baking */ +struct bAction *bake_obIPO_to_action(struct Object *ob); + +/* exported for game engine */ +void blend_poses(struct bPose *dst, struct bPose *src, float srcweight, short mode); +void extract_pose_from_pose(struct bPose *pose, const struct bPose *src); + +/* for proxy */ +void copy_pose_result(struct bPose *to, struct bPose *from); +/* clear all transforms */ +void rest_pose(struct bPose *pose); + +/* map global time (frame nr) to strip converted time, doesn't clip */ +float get_action_frame(struct Object *ob, float cframe); +/* map strip time to global time (frame nr) */ +float get_action_frame_inv(struct Object *ob, float cframe); + +#ifdef __cplusplus +}; +#endif + +#endif + diff --git a/source/blender/blenkernel/BKE_anim.h b/source/blender/blenkernel/BKE_anim.h new file mode 100644 index 00000000000..c7808331d7e --- /dev/null +++ b/source/blender/blenkernel/BKE_anim.h @@ -0,0 +1,61 @@ +/** + * blenlib/BKE_anim.h (mar-2001 nzc); + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_ANIM_H +#define BKE_ANIM_H + +struct Path; +struct Object; +struct PartEff; +struct Scene; +struct ListBase; + +typedef struct DupliObject { + struct DupliObject *next, *prev; + struct Object *ob; + unsigned int origlay; + int index, no_draw; + float mat[4][4], omat[4][4]; +} DupliObject; + +void free_path(struct Path *path); +void calc_curvepath(struct Object *ob); +int interval_test(int min, int max, int p1, int cycl); +int where_on_path(struct Object *ob, float ctime, float *vec, float *dir); + +struct ListBase *object_duplilist(struct Scene *sce, struct Object *ob); +void free_object_duplilist(struct ListBase *lb); +int count_duplilist(struct Object *ob); + +#endif + diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h new file mode 100644 index 00000000000..fb527051a0d --- /dev/null +++ b/source/blender/blenkernel/BKE_armature.h @@ -0,0 +1,122 @@ +/** + * blenlib/BKE_armature.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_ARMATURE_H +#define BKE_ARMATURE_H + +struct Bone; +struct Main; +struct bArmature; +struct bPose; +struct bPoseChannel; +struct bConstraint; +struct Object; +struct MDeformVert; +struct Mesh; +struct PoseTree; +struct ListBase; + +typedef struct PoseTarget +{ + struct PoseTarget *next, *prev; + + struct bConstraint *con; /* the constrait of this target */ + int tip; /* index of tip pchan in PoseTree */ +} PoseTarget; + +typedef struct PoseTree +{ + struct PoseTree *next, *prev; + + struct ListBase targets; /* list of targets of the tree */ + struct bPoseChannel **pchan; /* array of pose channels */ + int *parent; /* and their parents */ + int totchannel; /* number of pose channels */ + float (*basis_change)[3][3]; /* basis change result from solver */ + int iterations; /* iterations from the constraint */ + int stretch; /* disable stretching */ +} PoseTree; + +/* Core armature functionality */ +#ifdef __cplusplus +extern "C" { +#endif +struct bArmature *add_armature(char *name); +void free_boneChildren(struct Bone *bone); +void free_bones (struct bArmature *arm); +void unlink_armature(struct bArmature *arm); +void free_armature(struct bArmature *arm); +void make_local_armature(struct bArmature *arm); +struct bArmature *copy_armature(struct bArmature *arm); +void bone_flip_name (char *name, int strip_number); + +struct bArmature *get_armature (struct Object *ob); +struct Bone *get_named_bone (struct bArmature *arm, const char *name); + +float distfactor_to_bone (float vec[3], float b1[3], float b2[3], float rad1, float rad2, float rdist); + +void where_is_armature (struct bArmature *arm); +void where_is_armature_bone(struct Bone *bone, struct Bone *prevbone); +void armature_rebuild_pose(struct Object *ob, struct bArmature *arm); +void where_is_pose (struct Object *ob); + +/* get_objectspace_bone_matrix has to be removed still */ +void get_objectspace_bone_matrix (struct Bone* bone, float M_accumulatedMatrix[][4], int root, int posed); +void vec_roll_to_mat3(float *vec, float roll, float mat[][3]); +void mat3_to_vec_roll(float mat[][3], float *vec, float *roll); + +/* Common Conversions Between Co-ordinate Spaces */ +void armature_mat_world_to_pose(struct Object *ob, float inmat[][4], float outmat[][4]); +void armature_loc_world_to_pose(struct Object *ob, float *inloc, float *outloc); +void armature_mat_pose_to_bone(struct bPoseChannel *pchan, float inmat[][4], float outmat[][4]); +void armature_loc_pose_to_bone(struct bPoseChannel *pchan, float *inloc, float *outloc); +void armature_mat_pose_to_delta(float delta_mat[][4], float pose_mat[][4], float arm_mat[][4]); + +/* Animation functions */ +struct PoseTree *ik_tree_to_posetree(struct Object *ob, struct Bone *bone); +void solve_posetree(PoseTree *tree); +void free_posetree(PoseTree *tree); + +/* B-Bone support */ +typedef struct Mat4 { + float mat[4][4]; +} Mat4; + +Mat4 *b_bone_spline_setup(struct bPoseChannel *pchan, int rest); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/source/blender/blenkernel/BKE_bad_level_calls.h b/source/blender/blenkernel/BKE_bad_level_calls.h new file mode 100644 index 00000000000..b942add80e2 --- /dev/null +++ b/source/blender/blenkernel/BKE_bad_level_calls.h @@ -0,0 +1,235 @@ +/** + * blenlib/BKE_bad_level_calls.h (mar-2001 nzc) + * + * Stuff that definitely does not belong in the kernel! These will all + * have to be removed in order to restore sanity. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_BAD_LEVEL_CALLS_H +#define BKE_BAD_LEVEL_CALLS_H + +/* blender.c */ +void freeAllRad(void); +void free_editText(void); +void free_vertexpaint(void); + +/* readfile.c */ +struct SpaceButs; +void set_rects_butspace(struct SpaceButs *buts); +struct SpaceImaSel; +void check_imasel_copy(struct SpaceImaSel *simasel); +struct ScrArea; +struct bScreen; +void unlink_screen(struct bScreen *sc); +void setscreen(struct bScreen *sc); +void force_draw_all(int); + /* otherwise the WHILE_SEQ doesn't work */ +struct Sequence; +struct ListBase; +void build_seqar(struct ListBase *seqbase, struct Sequence ***seqar, int *totseq); + +/* BPython API */ +struct ID; +struct Script; +struct Text; +struct IpoDriver; /* DNA_curve_types.h */ +struct Object; +struct bPythonConstraint; +struct bConstraintOb; +struct bConstraintTarget; +void BPY_do_pyscript (struct ID *id, short int event); +void BPY_clear_script (struct Script *script); +void BPY_free_compiled_text (struct Text *text); +/* pydrivers */ +struct Object **BPY_pydriver_get_objects(struct IpoDriver *driver); +float BPY_pydriver_eval(struct IpoDriver *driver); +void BPY_pydriver_update(void); +/* button python evaluation */ +int BPY_button_eval(char *expr, double *value); +/* pyconstraints */ +void BPY_pyconstraint_eval(struct bPythonConstraint *con, struct bConstraintOb *cob, struct ListBase *targets); +void BPY_pyconstraint_targets(struct bPythonConstraint *con, struct bConstraintTarget *ct); + + +/* writefile.c */ +struct Oops; +void free_oops(struct Oops *oops); +void error(char *str, ...); + +/* anim.c */ +extern struct ListBase editNurb; + +void mainqenter (unsigned short event, short val); +void waitcursor(int); +void allqueue(unsigned short event, short val); +#define REDRAWVIEW3D 0x4010 +#define REDRAWBUTSEDIT 0x4019 +struct Material; +extern struct Material defmaterial; + + +/* exotic.c */ +void load_editMesh(void); +void make_editMesh(void); +struct EditMesh; +void free_editMesh(struct EditMesh *); +void free_editArmature(void); +void docenter_new(void); +int saveover(char *str); + +/* image.c */ +#include "DNA_image_types.h" +void free_realtime_image(Image *ima); // has to become a callback, opengl stuff + +/* ipo.c */ +void copy_view3d_lock(short val); // was a hack, to make scene layer ipo's possible + +/* library.c */ +void allspace(unsigned short event, short val) ; +#define OOPS_TEST 2 + +/* mball.c */ +extern struct ListBase editelems; + +/* object.c */ +struct ScriptLink; +void BPY_free_scriptlink(struct ScriptLink *slink); +void BPY_copy_scriptlink(struct ScriptLink *scriptlink); +float *give_cursor(void); // become a callback or argument +void exit_posemode(int freedata); + +/* packedFile.c */ +short pupmenu(char *instr); // will be general callback + +/* sca.c */ +#define LEFTMOUSE 0x001 // because of mouse sensor + +/* scene.c */ +#include "DNA_sequence_types.h" +void free_editing(struct Editing *ed); // scenes and sequences problem... +void BPY_do_all_scripts (short int event); +int BPY_call_importloader(char *name); + + +extern char texstr[20][12]; /* buttons.c */ + + +/* editsca.c */ +void make_unique_prop_names(char *str); + +/* DerivedMesh.c */ +void bglBegin(int mode); +void bglVertex3fv(float *vec); +void bglVertex3f(float x, float y, float z); +void bglEnd(void); + +struct Object; + +/* booleanops.c */ +struct DerivedMesh *NewBooleanDerivedMesh(struct Object *ob, + struct Object *ob_select, int int_op_type); + +/* verse_*.c */ +struct VerseVert; +struct VerseFace; +struct VerseSession; +struct VNode; +struct VTag; +struct VTagGroup; +struct VBitmapLayer; +struct VLink; +struct VLayer; +struct Mesh; + +void post_vertex_create(struct VerseVert *vvert); +void post_vertex_set_xyz(struct VerseVert *vvert); +void post_vertex_delete(struct VerseVert *vvert); +void post_vertex_free_constraint(struct VerseVert *vvert); +void post_polygon_create(struct VerseFace *vface); +void post_polygon_set_corner(struct VerseFace *vface); +void post_polygon_delete(struct VerseFace *vface); +void post_polygon_free_constraint(struct VerseFace *vface); +void post_polygon_set_uint8(struct VerseFace *vface); +void post_node_create(struct VNode *vnode); +void post_node_destroy(struct VNode *vnode); +void post_node_name_set(struct VNode *vnode); +void post_tag_change(struct VTag *vtag); +void post_taggroup_create(struct VTagGroup *vtaggroup); +char *verse_client_name(void); +void post_transform(struct VNode *vnode); +void post_transform_pos(struct VNode *vnode); +void post_transform_rot(struct VNode *vnode); +void post_transform_scale(struct VNode *vnode); +void post_object_free_constraint(struct VNode *vnode); +void post_link_set(struct VLink *vlink); +void post_link_destroy(struct VLink *vlink); +void post_connect_accept(struct VerseSession *session); +void post_connect_terminated(struct VerseSession *session); +void post_connect_update(struct VerseSession *session); +void add_screenhandler(struct bScreen *sc, short eventcode, short val); +void post_bitmap_dimension_set(struct VNode *vnode); +void post_bitmap_layer_create(struct VBitmapLayer *vblayer); +void post_bitmap_layer_destroy(struct VBitmapLayer *vblayer); +void post_bitmap_tile_set(struct VBitmapLayer *vblayer, unsigned int xs, unsigned int ys); +void create_meshdata_from_geom_node(struct Mesh *me, struct VNode *vnode); +void post_geometry_free_constraint(struct VNode *vnode); +void post_layer_create(struct VLayer *vlayer); +void post_layer_destroy(struct VLayer *vlayer); +void post_server_add(void); + +/* multires.c */ +struct Multires; +struct MultiresLevel; +struct MultiresLevel *multires_level_n(struct Multires *mr, int n); +void multires_free(struct Multires *mr); +void multires_set_level(struct Object *ob, struct Mesh *me, const int render); +void multires_update_levels(struct Mesh *me, const int render); +void multires_calc_level_maps(struct MultiresLevel *lvl); +struct Multires *multires_copy(struct Multires *orig); +/* sculptmode.c */ +void sculptmode_free_all(struct Scene *sce); +void sculptmode_init(struct Scene *sce); + +/* zbuf.c */ +void antialias_tagbuf(int xsize, int ysize, char *rectmove); + +/* imagetexture.c */ +void ibuf_sample(struct ImBuf *ibuf, float fx, float fy, float dx, float dy, float *result); + +/* modifier.c */ +struct MeshDeformModifierData; + +void harmonic_coordinates_bind(struct MeshDeformModifierData *mmd, + float (*vertexcos)[3], int totvert, float cagemat[][4]); + +#endif + diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h new file mode 100644 index 00000000000..55a542f51d5 --- /dev/null +++ b/source/blender/blenkernel/BKE_blender.h @@ -0,0 +1,79 @@ +/** + * blenlib/BKE_blender.h (mar-2001 nzc) + * + * Blender util stuff? + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_BLENDER_H +#define BKE_BLENDER_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct ListBase; +struct MemFile; + +#define BLENDER_VERSION 245 +#define BLENDER_SUBVERSION 7 + +#define BLENDER_MINVERSION 240 +#define BLENDER_MINSUBVERSION 0 + +int BKE_read_file(char *dir, void *type_r); +int BKE_read_file_from_memory(char* filebuf, int filelength, void *type_r); +int BKE_read_file_from_memfile(struct MemFile *memfile); + +void duplicatelist(struct ListBase *list1, struct ListBase *list2); +void free_blender(void); +void initglobals(void); + +void pushdata(void *data, int len); +void popfirst(void *data); +void poplast(void *data); +void free_pushpop(void); +void pushpop_test(void); + +/* global undo */ +extern void BKE_write_undo(char *name); +extern void BKE_undo_step(int step); +extern void BKE_reset_undo(void); +extern char *BKE_undo_menu_string(void); +extern void BKE_undo_number(int nr); +extern void BKE_undo_save_quit(void); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/source/blender/blenkernel/BKE_bmfont.h b/source/blender/blenkernel/BKE_bmfont.h new file mode 100644 index 00000000000..0d42b673769 --- /dev/null +++ b/source/blender/blenkernel/BKE_bmfont.h @@ -0,0 +1,65 @@ +/** + * blenlib/BKE_bmfont.h (mar-2001 nzc) + * + * + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_BMFONT_H +#define BKE_BMFONT_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct bmGlyph; +struct ImBuf; +struct bmFont; + +void printfGlyph(struct bmGlyph * glyph); +void calcAlpha(struct ImBuf * ibuf); +void readBitmapFontVersion0(struct ImBuf * ibuf, + unsigned char * rect, + int step); +void detectBitmapFont(struct ImBuf *ibuf); +int locateGlyph(struct bmFont *bmfont, unsigned short unicode); +void matrixGlyph(struct ImBuf * ibuf, unsigned short unicode, + float *centerx, float *centery, + float *sizex, float *sizey, + float *transx, float *transy, + float *movex, float *movey, float *advance); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/source/blender/blenkernel/BKE_bmfont_types.h b/source/blender/blenkernel/BKE_bmfont_types.h new file mode 100644 index 00000000000..a3bb43b5ca8 --- /dev/null +++ b/source/blender/blenkernel/BKE_bmfont_types.h @@ -0,0 +1,62 @@ +/** + * blenlib/BKE_bmfont_types.h (mar-2001 nzc) + * + * + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_BMFONT_TYPES_H +#define BKE_BMFONT_TYPES_H + +#define is_power_of_two(N) ((N ^ (N - 1)) == (2 * N - 1)) +/* +Moved to IMB_imbuf_types.h where it will live close to the ImBuf type. +It is used as a userflag bit mask. +#define IB_BITMAPFONT 1 +*/ +typedef struct bmGlyph { + unsigned short unicode; + short locx, locy; + signed char ofsx, ofsy; + unsigned char sizex, sizey; + unsigned char advance, reserved; +} bmGlyph; + +typedef struct bmFont { + char magic[4]; + short version; + short glyphcount; + short xsize, ysize; + bmGlyph glyphs[1]; +} bmFont; + +#endif + diff --git a/source/blender/blenkernel/BKE_booleanops.h b/source/blender/blenkernel/BKE_booleanops.h new file mode 100644 index 00000000000..4e98c81c067 --- /dev/null +++ b/source/blender/blenkernel/BKE_booleanops.h @@ -0,0 +1,52 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_BOOLEANOPS_H +#define BKE_BOOLEANOPS_H + +struct Object; +struct Base; +struct DerivedMesh; + +/* Performs a boolean between two mesh objects, it is assumed that both objects + are in fact a mesh object. On success returns 1 and creates a new mesh object + into blender data structures. On failure returns 0 and reports an error. */ +int NewBooleanMesh(struct Base *base, struct Base *base_select, int op); + + +/* Performs a boolean between two mesh objects, it is assumed that both objects + are in fact mesh object. On success returns a DerivedMesh. On failure + returns NULL and reports an error. */ +struct DerivedMesh *NewBooleanDerivedMesh(struct Object *ob, + struct Object *ob_select, + int op); +#endif + diff --git a/source/blender/blenkernel/BKE_booleanops_mesh.h b/source/blender/blenkernel/BKE_booleanops_mesh.h new file mode 100644 index 00000000000..7b0e703da04 --- /dev/null +++ b/source/blender/blenkernel/BKE_booleanops_mesh.h @@ -0,0 +1,120 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_PyBooleanOps_h +#define BKE_PyBooleanOps_h + +#include "CSG_BooleanOps.h" + +/** + * Internal mesh structure. + * Safe to copy by value... hopefully. + */ + +struct Base; +struct Object; +struct CSG_MeshDescriptor; + +typedef void (*CSG_DestroyMeshFunc)(struct CSG_MeshDescriptor *); + +typedef struct CSG_MeshDescriptor { + struct Base *base; // Ptr to base of original blender object - used in creating a new object + CSG_MeshPropertyDescriptor m_descriptor; + CSG_FaceIteratorDescriptor m_face_iterator; + CSG_VertexIteratorDescriptor m_vertex_iterator; + CSG_DestroyMeshFunc m_destroy_func; +} CSG_MeshDescriptor; + + +extern + int +CSG_LoadBlenderMesh( + struct Object * obj, + CSG_MeshDescriptor *output +); + +/** + * Destroy the contents of a mesh descriptor. + * If the internal descriptor refers to a blender + * mesh, no action is performed apart from freeing + * internal memory in the desriptor. + */ + +extern + void +CSG_DestroyMeshDescriptor( + CSG_MeshDescriptor *mesh +); + +/** + * Perform a boolean operation between 2 meshes and return the + * result as a new mesh descriptor. + * op_type is an integer code of the boolean operation type. + * 1 = intersection, + * 2 = union, + * 3 = difference. + */ + +extern + int +CSG_PerformOp( + CSG_MeshDescriptor *mesh1, + CSG_MeshDescriptor *mesh2, + int op_type, + CSG_MeshDescriptor *output +); + + + +/** + * Add a mesh to blender as a new object. + */ + +extern + int +CSG_AddMeshToBlender( + CSG_MeshDescriptor *mesh +); + +/** + * Test functionality. + */ + +extern + int +NewBooleanMeshTest( + struct Base * base, + struct Base * base_select, + int op_type +); + +#endif + diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h new file mode 100644 index 00000000000..2c0034ad234 --- /dev/null +++ b/source/blender/blenkernel/BKE_brush.h @@ -0,0 +1,77 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * General operations for brushes. + */ + +#ifndef BKE_BRUSH_H +#define BKE_BRUSH_H + +struct ID; +struct Brush; +struct ImBuf; + +/* datablock functions */ +struct Brush *add_brush(char *name); +struct Brush *copy_brush(struct Brush *brush); +void make_local_brush(struct Brush *brush); +void free_brush(struct Brush *brush); + +/* brush library operations used by different paint panels */ +int brush_set_nr(struct Brush **current_brush, int nr); +int brush_delete(struct Brush **current_brush); +void brush_check_exists(struct Brush **brush); +void brush_toggle_fake_user(struct Brush *brush); +int brush_texture_set_nr(struct Brush *brush, int nr); +int brush_texture_delete(struct Brush *brush); +int brush_clone_image_set_nr(struct Brush *brush, int nr); +int brush_clone_image_delete(struct Brush *brush); + +/* sampling */ +float brush_sample_falloff(struct Brush *brush, float dist); +void brush_sample_tex(struct Brush *brush, float *xy, float *rgba); +void brush_imbuf_new(struct Brush *brush, short flt, short texfalloff, int size, + struct ImBuf **imbuf); + +/* painting */ +struct BrushPainter; +typedef struct BrushPainter BrushPainter; +typedef int (*BrushFunc)(void *user, struct ImBuf *ibuf, float *lastpos, float *pos); + +BrushPainter *brush_painter_new(struct Brush *brush); +void brush_painter_require_imbuf(BrushPainter *painter, short flt, + short texonly, int size); +int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, + double time, float pressure, void *user); +void brush_painter_break_stroke(BrushPainter *painter); +void brush_painter_free(BrushPainter *painter); + +#endif + diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h b/source/blender/blenkernel/BKE_cdderivedmesh.h new file mode 100644 index 00000000000..a570b4fe598 --- /dev/null +++ b/source/blender/blenkernel/BKE_cdderivedmesh.h @@ -0,0 +1,109 @@ +/* +* $Id$ +* +* ***** BEGIN GPL LICENSE BLOCK ***** +* +* 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. +* +* The Original Code is Copyright (C) 2006 Blender Foundation. +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): Ben Batt +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +/* CDDerivedMesh interface. + * CDDerivedMesh (CD = Custom Data) is a DerivedMesh backend which stores + * mesh elements (vertices, edges and faces) as layers of custom element data. + */ + +#ifndef BKE_CDDERIVEDMESH_H +#define BKE_CDDERIVEDMESH_H + +#include "BKE_DerivedMesh.h" + +struct DerivedMesh; +struct EditMesh; +struct Mesh; +struct Object; + +/* creates a new CDDerivedMesh */ +struct DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces); + +/* creates a CDDerivedMesh from the given Mesh, this will reference the + original data in Mesh, but it is safe to apply vertex coordinates or + calculate normals as those functions will automtically create new + data to not overwrite the original */ +struct DerivedMesh *CDDM_from_mesh(struct Mesh *mesh, struct Object *ob); + +/* creates a CDDerivedMesh from the given EditMesh */ +struct DerivedMesh *CDDM_from_editmesh(struct EditMesh *em, struct Mesh *me); + +/* Copies the given DerivedMesh with verts, faces & edges stored as + * custom element data. + */ +struct DerivedMesh *CDDM_copy(struct DerivedMesh *dm); + +/* creates a CDDerivedMesh with the same layer stack configuration as the + * given DerivedMesh and containing the requested numbers of elements. + * elements are initialised to all zeros + */ +struct DerivedMesh *CDDM_from_template(struct DerivedMesh *source, + int numVerts, int numEdges, int numFaces); + +/* applies vertex coordinates or normals to a CDDerivedMesh. if the MVert + * layer is a referenced layer, it will be duplicate to not overwrite the + * original + */ +void CDDM_apply_vert_coords(struct DerivedMesh *cddm, float (*vertCoords)[3]); +void CDDM_apply_vert_normals(struct DerivedMesh *cddm, short (*vertNormals)[3]); + +/* recalculates vertex and face normals for a CDDerivedMesh + */ +void CDDM_calc_normals(struct DerivedMesh *dm); + +/* calculates edges for a CDDerivedMesh (from face data) + * this completely replaces the current edge data in the DerivedMesh + */ +void CDDM_calc_edges(struct DerivedMesh *dm); + +/* lowers the number of vertices/edges/faces in a CDDerivedMesh + * the layer data stays the same size + */ +void CDDM_lower_num_verts(struct DerivedMesh *dm, int numVerts); +void CDDM_lower_num_edges(struct DerivedMesh *dm, int numEdges); +void CDDM_lower_num_faces(struct DerivedMesh *dm, int numFaces); + +/* vertex/edge/face access functions + * should always succeed if index is within bounds + * note these return pointers - any change modifies the internals of the mesh + */ +struct MVert *CDDM_get_vert(struct DerivedMesh *dm, int index); +struct MEdge *CDDM_get_edge(struct DerivedMesh *dm, int index); +struct MFace *CDDM_get_face(struct DerivedMesh *dm, int index); + +/* vertex/edge/face array access functions - return the array holding the + * desired data + * should always succeed + * note these return pointers - any change modifies the internals of the mesh + */ +struct MVert *CDDM_get_verts(struct DerivedMesh *dm); +struct MEdge *CDDM_get_edges(struct DerivedMesh *dm); +struct MFace *CDDM_get_faces(struct DerivedMesh *dm); +#endif + diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h new file mode 100644 index 00000000000..e78882220a9 --- /dev/null +++ b/source/blender/blenkernel/BKE_colortools.h @@ -0,0 +1,62 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_COLORTOOLS_H +#define BKE_COLORTOOLS_H + +struct CurveMapping; +struct CurveMap; +struct ImBuf; +struct rctf; + +struct CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, float maxy); +void curvemapping_free(struct CurveMapping *cumap); +struct CurveMapping *curvemapping_copy(struct CurveMapping *cumap); +void curvemapping_set_black_white(struct CurveMapping *cumap, float *black, float *white); + +void curvemap_remove(struct CurveMap *cuma, int flag); +void curvemap_insert(struct CurveMap *cuma, float x, float y); +void curvemap_reset(struct CurveMap *cuma, struct rctf *clipr); +void curvemap_sethandle(struct CurveMap *cuma, int type); + +void curvemapping_changed(struct CurveMapping *cumap, int rem_doubles); + + /* single curve, no table check */ +float curvemap_evaluateF(struct CurveMap *cuma, float value); + /* single curve, with table check */ +float curvemapping_evaluateF(struct CurveMapping *cumap, int cur, float value); +void curvemapping_evaluate3F(struct CurveMapping *cumap, float *vecout, const float *vecin); +void curvemapping_evaluateRGBF(struct CurveMapping *cumap, float *vecout, const float *vecin); +void curvemapping_evaluate_premulRGBF(struct CurveMapping *cumap, float *vecout, const float *vecin); +void curvemapping_do_ibuf(struct CurveMapping *cumap, struct ImBuf *ibuf); +void curvemapping_premultiply(struct CurveMapping *cumap, int restore); +int curvemapping_RGBA_does_something(struct CurveMapping *cumap); +void curvemapping_initialize(struct CurveMapping *cumap); + +#endif + diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h new file mode 100644 index 00000000000..aa8e9cf18f8 --- /dev/null +++ b/source/blender/blenkernel/BKE_constraint.h @@ -0,0 +1,140 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): 2007 - Joshua Leung (major recode) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BKE_CONSTRAINT_H +#define BKE_CONSTRAINT_H + +struct bConstraint; +struct bConstraintTarget; +struct ListBase; +struct Object; +struct bConstraintChannel; +struct bPoseChannel; + +/* ---------------------------------------------------------------------------- */ + +/* special struct for use in constraint evaluation */ +typedef struct bConstraintOb { + struct Object *ob; /* if pchan, then armature that it comes from, otherwise constraint owner */ + struct bPoseChannel *pchan; /* pose channel that owns the constraints being evaluated */ + + float matrix[4][4]; /* matrix where constraints are accumulated + solved */ + float startmat[4][4]; /* original matrix (before constraint solving) */ + + short type; /* type of owner */ +} bConstraintOb; + +/* ---------------------------------------------------------------------------- */ + +/* Constraint Type-Info (shorthand in code = cti): + * This struct provides function pointers for runtime, so that functions can be + * written more generally (with fewer/no special exceptions for various constraints). + * + * Callers of these functions must check that they actually point to something useful, + * as some constraints don't define some of these. + * + * Warning: it is not too advisable to reorder order of members of this struct, + * as you'll have to edit quite a few ($NUM_CONSTRAINT_TYPES) of these + * structs. + */ +typedef struct bConstraintTypeInfo { + /* admin/ident */ + short type; /* CONSTRAINT_TYPE_### */ + short size; /* size in bytes of the struct */ + char name[32]; /* name constraint in interface */ + char structName[32]; /* name of struct for SDNA */ + + /* data management function pointers - special handling */ + /* free any data that is allocated separately (optional) */ + void (*free_data)(struct bConstraint *con); + /* adjust pointer to other ID-data using ID_NEW(), but not to targets (optional) */ + void (*relink_data)(struct bConstraint *con); + /* copy any special data that is allocated separately (optional) */ + void (*copy_data)(struct bConstraint *con, struct bConstraint *src); + /* set settings for data that will be used for bConstraint.data (memory already allocated) */ + void (*new_data)(void *cdata); + + /* target handling function pointers */ + /* for multi-target constraints: return that list; otherwise make a temporary list */ + void (*get_constraint_targets)(struct bConstraint *con, struct ListBase *list); + /* for single-target constraints only: flush data back to source data, and the free memory used */ + void (*flush_constraint_targets)(struct bConstraint *con, struct ListBase *list, short nocopy); + + /* evaluation */ + /* set the ct->matrix for the given constraint target (at the given ctime) */ + void (*get_target_matrix)(struct bConstraint *con, struct bConstraintOb *cob, struct bConstraintTarget *ct, float ctime); + /* evaluate the constraint for the given time */ + void (*evaluate_constraint)(struct bConstraint *con, struct bConstraintOb *cob, struct ListBase *targets); +} bConstraintTypeInfo; + +/* Function Prototypes for bConstraintTypeInfo's */ +bConstraintTypeInfo *constraint_get_typeinfo(struct bConstraint *con); +bConstraintTypeInfo *get_constraint_typeinfo(int type); + +/* ---------------------------------------------------------------------------- */ +/* Useful macros for testing various common flag combinations */ + +/* Constraint Target Macros */ +#define VALID_CONS_TARGET(ct) ((ct) && (ct->tar)) + + +/* ---------------------------------------------------------------------------- */ + +/* Constraint function prototypes */ +void unique_constraint_name(struct bConstraint *con, struct ListBase *list); + +void free_constraints(struct ListBase *conlist); +void copy_constraints(struct ListBase *dst, struct ListBase *src); +void relink_constraints(struct ListBase *list); +void free_constraint_data(struct bConstraint *con); + + +/* Constraint Channel function prototypes */ +struct bConstraintChannel *get_constraint_channel(struct ListBase *list, const char *name); +struct bConstraintChannel *verify_constraint_channel(struct ListBase *list, const char *name); +void do_constraint_channels(struct ListBase *conbase, struct ListBase *chanbase, float ctime, short onlydrivers); +void copy_constraint_channels(struct ListBase *dst, struct ListBase *src); +void clone_constraint_channels(struct ListBase *dst, struct ListBase *src); +void free_constraint_channels(struct ListBase *chanbase); + +/* Constraint Evaluation function prototypes */ +struct bConstraintOb *constraints_make_evalob(struct Object *ob, void *subdata, short datatype); +void constraints_clear_evalob(struct bConstraintOb *cob); + +void constraint_mat_convertspace(struct Object *ob, struct bPoseChannel *pchan, float mat[][4], short from, short to); + +void get_constraint_target_matrix(struct bConstraint *con, int n, short ownertype, void *ownerdata, float mat[][4], float ctime); +void solve_constraints(struct ListBase *conlist, struct bConstraintOb *cob, float ctime); + + +#endif + diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h new file mode 100644 index 00000000000..ee63f678505 --- /dev/null +++ b/source/blender/blenkernel/BKE_curve.h @@ -0,0 +1,91 @@ +/** + * blenlib/BKE_curve.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_CURVE_H +#define BKE_CURVE_H + +struct Curve; +struct ListBase; +struct Object; +struct Nurb; +struct ListBase; +struct BezTriple; +struct BevList; + +#define KNOTSU(nu) ( (nu)->orderu+ (nu)->pntsu+ (nu->orderu-1)*((nu)->flagu & 1) ) +#define KNOTSV(nu) ( (nu)->orderv+ (nu)->pntsv+ (nu->orderv-1)*((nu)->flagv & 1) ) + + +void unlink_curve( struct Curve *cu); +void free_curve( struct Curve *cu); +struct Curve *add_curve(char *name, int type); +struct Curve *copy_curve( struct Curve *cu); +void make_local_curve( struct Curve *cu); +short curve_type( struct Curve *cu); +void test_curve_type( struct Object *ob); +void tex_space_curve( struct Curve *cu); +int count_curveverts( struct ListBase *nurb); +int count_curveverts_without_handles( struct ListBase *nurb); +void freeNurb( struct Nurb *nu); +void freeNurblist( struct ListBase *lb); +struct Nurb *duplicateNurb( struct Nurb *nu); +void duplicateNurblist( struct ListBase *lb1, struct ListBase *lb2); +void test2DNurb( struct Nurb *nu); +void minmaxNurb( struct Nurb *nu, float *min, float *max); + +void makeknots( struct Nurb *nu, short uv, short type); + +void makeNurbfaces( struct Nurb *nu, float *data, int rowstride); +void makeNurbcurve( struct Nurb *nu, float *data, int resolu, int dim); +void forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride); +float *make_orco_curve( struct Object *ob); +float *make_orco_surf( struct Object *ob); +void makebevelcurve( struct Object *ob, struct ListBase *disp); + +void makeBevelList( struct Object *ob); +float calc_curve_subdiv_radius( struct Curve *cu, struct Nurb *nu, int cursubdiv); + +void calchandleNurb( struct BezTriple *bezt, struct BezTriple *prev, struct BezTriple *next, int mode); +void calchandlesNurb( struct Nurb *nu); +void testhandlesNurb( struct Nurb *nu); +void autocalchandlesNurb( struct Nurb *nu, int flag); +void autocalchandlesNurb_all(int flag); +void sethandlesNurb(short code); + +void switchdirectionNurb( struct Nurb *nu); + +float (*curve_getVertexCos(struct Curve *cu, struct ListBase *lb, int *numVerts_r))[3]; +void curve_applyVertexCos(struct Curve *cu, struct ListBase *lb, float (*vertexCos)[3]); + +#endif + diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h new file mode 100644 index 00000000000..d0535f1752e --- /dev/null +++ b/source/blender/blenkernel/BKE_customdata.h @@ -0,0 +1,244 @@ +/* +* $Id$ +* +* ***** BEGIN GPL LICENSE BLOCK ***** +* +* 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. +* +* The Original Code is Copyright (C) 2006 Blender Foundation. +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): Ben Batt +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +/* CustomData interface, see also DNA_customdata_types.h. */ + +#ifndef BKE_CUSTOMDATA_H +#define BKE_CUSTOMDATA_H + +struct CustomData; +struct CustomDataLayer; +typedef long CustomDataMask; + +extern const CustomDataMask CD_MASK_BAREMESH; +extern const CustomDataMask CD_MASK_MESH; +extern const CustomDataMask CD_MASK_EDITMESH; +extern const CustomDataMask CD_MASK_DERIVEDMESH; + +/* for ORIGINDEX layer type, indicates no original index for this element */ +#define ORIGINDEX_NONE -1 + +/* initialises a CustomData object with the same layer setup as source and + * memory space for totelem elements. mask must be an array of length + * CD_NUMTYPES elements, that indicate if a layer can be copied. */ + +/* add/copy/merge allocation types */ +#define CD_ASSIGN 0 /* use the data pointer */ +#define CD_CALLOC 1 /* allocate blank memory */ +#define CD_DEFAULT 2 /* allocate and set to default */ +#define CD_REFERENCE 3 /* use data pointers, set layer flag NOFREE */ +#define CD_DUPLICATE 4 /* do a full copy of all layers, only allowed if source + has same number of elements */ + +/* initialises a CustomData object with the same layer setup as source. + * mask is a bitfield where (mask & (1 << (layer type))) indicates + * if a layer should be copied or not. alloctype must be one of the above. */ +void CustomData_copy(const struct CustomData *source, struct CustomData *dest, + CustomDataMask mask, int alloctype, int totelem); + +/* same as the above, except that this will preserve existing layers, and only + * add the layers that were not there yet */ +void CustomData_merge(const struct CustomData *source, struct CustomData *dest, + CustomDataMask mask, int alloctype, int totelem); + +/* frees data associated with a CustomData object (doesn't free the object + * itself, though) + */ +void CustomData_free(struct CustomData *data, int totelem); + +/* frees all layers with CD_FLAG_TEMPORARY */ +void CustomData_free_temporary(struct CustomData *data, int totelem); + +/* adds a data layer of the given type to the CustomData object, optionally + * backed by an external data array. the different allocation types are + * defined above. returns the data of the layer. + * + * in editmode, use EM_add_data_layer instead of this function + */ +void *CustomData_add_layer(struct CustomData *data, int type, int alloctype, + void *layer, int totelem); +/*same as above but accepts a name */ +void *CustomData_add_layer_named(struct CustomData *data, int type, int alloctype, + void *layer, int totelem, char *name); + +/* frees the active or first data layer with the give type. + * returns 1 on succes, 0 if no layer with the given type is found + * + * in editmode, use EM_free_data_layer instead of this function + */ +int CustomData_free_layer(struct CustomData *data, int type, int totelem, int index); + +/* frees the layer index with the give type. + * returns 1 on succes, 0 if no layer with the given type is found + * + * in editmode, use EM_free_data_layer instead of this function + */ +int CustomData_free_layer_active(struct CustomData *data, int type, int totelem); + +/* same as above, but free all layers with type */ +void CustomData_free_layers(struct CustomData *data, int type, int totelem); + +/* returns 1 if a layer with the specified type exists */ +int CustomData_has_layer(const struct CustomData *data, int type); + +/* returns the number of layers with this type */ +int CustomData_number_of_layers(const struct CustomData *data, int type); + +/* duplicate data of a layer with flag NOFREE, and remove that flag. + * returns the layer data */ +void *CustomData_duplicate_referenced_layer(struct CustomData *data, int type); +void *CustomData_duplicate_referenced_layer_named(struct CustomData *data, + int type, char *name); + +/* set the CD_FLAG_NOCOPY flag in custom data layers where the mask is + * zero for the layer type, so only layer types specified by the mask + * will be copied + */ +void CustomData_set_only_copy(const struct CustomData *data, + CustomDataMask mask); + +/* copies data from one CustomData object to another + * objects need not be compatible, each source layer is copied to the + * first dest layer of correct type (if there is none, the layer is skipped) + * return 1 on success, 0 on failure + */ +void CustomData_copy_data(const struct CustomData *source, + struct CustomData *dest, int source_index, + int dest_index, int count); +void CustomData_em_copy_data(const struct CustomData *source, + struct CustomData *dest, void *src_block, + void **dest_block); + +/* frees data in a CustomData object + * return 1 on success, 0 on failure + */ +void CustomData_free_elem(struct CustomData *data, int index, int count); + +/* interpolates data from one CustomData object to another + * objects need not be compatible, each source layer is interpolated to the + * first dest layer of correct type (if there is none, the layer is skipped) + * if weights == NULL or sub_weights == NULL, they default to all 1's + * + * src_indices gives the source elements to interpolate from + * weights gives the weight for each source element + * sub_weights is an array of matrices of weights for sub-elements (matrices + * should be source->subElems * source->subElems in size) + * count gives the number of source elements to interpolate from + * dest_index gives the dest element to write the interpolated value to + * + * returns 1 on success, 0 on failure + */ +void CustomData_interp(const struct CustomData *source, struct CustomData *dest, + int *src_indices, float *weights, float *sub_weights, + int count, int dest_index); +void CustomData_em_interp(struct CustomData *data, void **src_blocks, + float *weights, float *sub_weights, int count, + void *dest_block); + +/* swaps the data in the element corners, to new corners with indices as + specified in corner_indices. for edges this is an array of length 2, for + faces an array of length 4 */ +void CustomData_swap(struct CustomData *data, int index, int *corner_indices); + +/* gets a pointer to the data element at index from the first layer of type + * returns NULL if there is no layer of type + */ +void *CustomData_get(const struct CustomData *data, int index, int type); +void *CustomData_em_get(const struct CustomData *data, void *block, int type); +void *CustomData_em_get_n(const struct CustomData *data, void *block, int type, int n); + +/* gets a pointer to the active or first layer of type + * returns NULL if there is no layer of type + */ +void *CustomData_get_layer(const struct CustomData *data, int type); +void *CustomData_get_layer_n(const struct CustomData *data, int type, int n); +void *CustomData_get_layer_named(const struct CustomData *data, int type, + char *name); + +int CustomData_get_layer_index(const struct CustomData *data, int type); +int CustomData_get_named_layer_index(const struct CustomData *data, int type, char *name); +int CustomData_get_active_layer_index(const struct CustomData *data, int type); +int CustomData_get_render_layer_index(const struct CustomData *data, int type); +int CustomData_get_active_layer(const struct CustomData *data, int type); +int CustomData_get_render_layer(const struct CustomData *data, int type); + +/* copies the data from source to the data element at index in the first + * layer of type + * no effect if there is no layer of type + */ +void CustomData_set(const struct CustomData *data, int index, int type, + void *source); +void CustomData_em_set(struct CustomData *data, void *block, int type, + void *source); +void CustomData_em_set_n(struct CustomData *data, void *block, int type, int n, + void *source); + +/* set the pointer of to the first layer of type. the old data is not freed. + * returns the value of ptr if the layer is found, NULL otherwise + */ +void *CustomData_set_layer(const struct CustomData *data, int type, void *ptr); +void *CustomData_set_layer_n(const struct CustomData *data, int type, int n, void *ptr); + +/* sets the nth layer of type as active */ +void CustomData_set_layer_active(struct CustomData *data, int type, int n); +void CustomData_set_layer_render(struct CustomData *data, int type, int n); + +/* same as above but works with an index from CustomData_get_layer_index */ +void CustomData_set_layer_active_index(struct CustomData *data, int type, int n); +void CustomData_set_layer_render_index(struct CustomData *data, int type, int n); + +/* adds flag to the layer flags */ +void CustomData_set_layer_flag(struct CustomData *data, int type, int flag); + +/* alloc/free a block of custom data attached to one element in editmode */ +void CustomData_em_set_default(struct CustomData *data, void **block); +void CustomData_em_free_block(struct CustomData *data, void **block); + +/* copy custom data to/from layers as in mesh/derivedmesh, to editmesh + blocks of data. the CustomData's must not be compatible */ +void CustomData_to_em_block(const struct CustomData *source, + struct CustomData *dest, int index, void **block); +void CustomData_from_em_block(const struct CustomData *source, + struct CustomData *dest, void *block, int index); + +/* query info over types */ +void CustomData_file_write_info(int type, char **structname, int *structnum); +int CustomData_sizeof(int type); + +/* get the name of a layer type */ +const char *CustomData_layertype_name(int type); + +/* make sure the name of layer at index is unique */ +void CustomData_set_layer_unique_name(struct CustomData *data, int index); + +/* for file reading compatibility, returns false if the layer was freed, + only after this test passes, layer->data should be assigned */ +int CustomData_verify_versions(struct CustomData *data, int index); + +#endif diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h new file mode 100644 index 00000000000..67e2a8948d5 --- /dev/null +++ b/source/blender/blenkernel/BKE_deform.h @@ -0,0 +1,53 @@ +/* BKE_deform.h June 2001 + * + * support for deformation groups and hooks + * + * Reevan McKay et al + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BKE_DEFORM_H +#define BKE_DEFORM_H + +struct Object; +struct ListBase; +struct bDeformGroup; + +void copy_defgroups (struct ListBase *lb1, struct ListBase *lb2); +struct bDeformGroup *copy_defgroup (struct bDeformGroup *ingroup); +struct bDeformGroup *get_named_vertexgroup (Object *ob, char *name); +int get_defgroup_num (struct Object *ob, struct bDeformGroup *dg); +int get_named_vertexgroup_num (Object *ob, char *name); +void unique_vertexgroup_name (struct bDeformGroup *dg, struct Object *ob); + +#endif + diff --git a/source/blender/blenkernel/BKE_depsgraph.h b/source/blender/blenkernel/BKE_depsgraph.h new file mode 100644 index 00000000000..294f61e54bd --- /dev/null +++ b/source/blender/blenkernel/BKE_depsgraph.h @@ -0,0 +1,113 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef DEPSGRAPH_API +#define DEPSGRAPH_API + +/* +#define DEPS_DEBUG +*/ + +struct Scene; +struct DagNodeQueue; +struct DagForest; +struct DagNode; + +/* **** DAG relation types *** */ + + /* scene link to object */ +#define DAG_RL_SCENE 1 + /* object link to data */ +#define DAG_RL_DATA 2 + + /* object changes object (parent, track, constraints) */ +#define DAG_RL_OB_OB 4 + /* object changes obdata (hooks, constraints) */ +#define DAG_RL_OB_DATA 8 + /* data changes object (vertex parent) */ +#define DAG_RL_DATA_OB 16 + /* data changes data (deformers) */ +#define DAG_RL_DATA_DATA 32 + +#define DAG_NO_RELATION 64 +#define DAG_RL_ALL 63 +#define DAG_RL_ALL_BUT_DATA 61 + + +typedef void (*graph_action_func)(void * ob, void **data); + +// queues are returned by all BFS & DFS queries +// opaque type +void *pop_ob_queue(struct DagNodeQueue *queue); +int queue_count(struct DagNodeQueue *queue); +void queue_delete(struct DagNodeQueue *queue); + +// queries +struct DagForest *build_dag(struct Scene *sce, short mask); +void free_forest(struct DagForest *Dag); + +// note : +// the meanings of the 2 returning values is a bit different : +// BFS return 1 for cross-edges and back-edges. the latter are considered harmfull, not the former +// DFS return 1 only for back-edges +int pre_and_post_BFS(struct DagForest *dag, short mask, graph_action_func pre_func, graph_action_func post_func, void **data); +int pre_and_post_DFS(struct DagForest *dag, short mask, graph_action_func pre_func, graph_action_func post_func, void **data); + +int pre_and_post_source_BFS(struct DagForest *dag, short mask, struct DagNode *source, graph_action_func pre_func, graph_action_func post_func, void **data); +int pre_and_post_source_DFS(struct DagForest *dag, short mask, struct DagNode *source, graph_action_func pre_func, graph_action_func post_func, void **data); + +struct DagNodeQueue *get_obparents(struct DagForest *dag, void *ob); +struct DagNodeQueue *get_first_ancestors(struct DagForest *dag, void *ob); +struct DagNodeQueue *get_all_childs(struct DagForest *dag, void *ob); // +short are_obs_related(struct DagForest *dag, void *ob1, void *ob2); +int is_acyclic(struct DagForest *dag); // +//int get_cycles(struct DagForest *dag, struct DagNodeQueue **queues, int *count); // + +void boundbox_deps(void); +void draw_all_deps(void); + +/* ********** API *************** */ +/* Note that the DAG never executes changes in Objects, only sets flags in Objects */ + +void DAG_scene_sort(struct Scene *sce); + + /* flag all objects that need recalc because they're animated */ +void DAG_scene_update_flags(struct Scene *sce, unsigned int lay); + /* flag all objects that need recalc because they're animated, influencing this object only */ +void DAG_object_update_flags(struct Scene *sce, struct Object *ob, unsigned int lay); + + /* flushes all recalc flags in objects down the dependency tree */ +void DAG_scene_flush_update(struct Scene *sce, unsigned int lay); + /* flushes all recalc flags for this object down the dependency tree */ +void DAG_object_flush_update(struct Scene *sce, struct Object *ob, short flag); + +void DAG_pose_sort(struct Object *ob); + +#endif diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h new file mode 100644 index 00000000000..979ed31fb20 --- /dev/null +++ b/source/blender/blenkernel/BKE_displist.h @@ -0,0 +1,127 @@ +/* display list (or rather multi purpose list) stuff */ +/* + $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + +*/ + +#ifndef BKE_DISPLIST_H +#define BKE_DISPLIST_H + +#include "DNA_customdata_types.h" +#include "BKE_customdata.h" + +/* dl->type */ +#define DL_POLY 0 +#define DL_SEGM 1 +#define DL_SURF 2 +#define DL_INDEX3 4 +#define DL_INDEX4 5 +#define DL_VERTCOL 6 +#define DL_VERTS 7 + +/* dl->flag */ +#define DL_CYCL_U 1 +#define DL_CYCL_V 2 +#define DL_FRONT_CURVE 4 +#define DL_BACK_CURVE 8 + +#define DL_SURFINDEX(cyclu, cyclv, sizeu, sizev) \ +\ +if( (cyclv)==0 && a==(sizev)-1) break; \ +if(cyclu) { \ + p1= sizeu*a; \ + p2= p1+ sizeu-1; \ + p3= p1+ sizeu; \ + p4= p2+ sizeu; \ + b= 0; \ +} \ +else { \ + p2= sizeu*a; \ + p1= p2+1; \ + p4= p2+ sizeu; \ + p3= p1+ sizeu; \ + b= 1; \ +} \ +if( (cyclv) && a==sizev-1) { \ + p3-= sizeu*sizev; \ + p4-= sizeu*sizev; \ +} + + +/* prototypes */ + +struct Base; +struct Object; +struct Curve; +struct ListBase; +struct Material; +struct Bone; +struct Mesh; + + +/* used for curves, nurbs, mball, importing */ +typedef struct DispList { + struct DispList *next, *prev; + short type, flag; + int parts, nr; + short col, rt; /* rt used by initrenderNurbs */ + float *verts, *nors; + int *index; + unsigned int *col1, *col2; + int charidx; + int totindex; /* indexed array drawing surfaces */ + + unsigned int *bevelSplitFlag; +} DispList; + +extern void copy_displist(struct ListBase *lbn, struct ListBase *lb); +extern void free_disp_elem(DispList *dl); +extern DispList *find_displist_create(struct ListBase *lb, int type); +extern DispList *find_displist(struct ListBase *lb, int type); +extern void addnormalsDispList(struct Object *ob, struct ListBase *lb); +extern void count_displist(struct ListBase *lb, int *totvert, int *totface); +extern void freedisplist(struct ListBase *lb); +extern int displist_has_faces(struct ListBase *lb); +extern void makeDerivedMesh(struct Object *ob, CustomDataMask dataMask); +extern void makeDispListSurf(struct Object *ob, struct ListBase *dispbase, int forRender); +extern void makeDispListCurveTypes(struct Object *ob, int forOrco); +extern void makeDispListMBall(struct Object *ob); +extern void shadeDispList(struct Base *base); +extern void shadeMeshMCol(struct Object *ob, struct Mesh *me); + +void imagestodisplist(void); +void reshadeall_displist(void); +void filldisplist(struct ListBase *dispbase, struct ListBase *to); + +void fastshade_free_render(void); + +#endif + diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h new file mode 100644 index 00000000000..5585735e0b5 --- /dev/null +++ b/source/blender/blenkernel/BKE_effect.h @@ -0,0 +1,79 @@ +/** + * blenlib/BKE_effect.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_EFFECT_H +#define BKE_EFFECT_H + +#include "DNA_object_types.h" + +struct Effect; +struct ListBase; +struct PartEff; +struct Particle; +struct Group; + +typedef struct pEffectorCache { + struct pEffectorCache *next, *prev; + Object *ob; + + /* precalculated variables */ + float oldloc[3], oldspeed[3]; + float scale, time_scale; + float guide_dist; + + Object obcopy; /* for restoring transformation data */ +} pEffectorCache; + + +struct Effect *add_effect(int type); +void free_effect(struct Effect *eff); +void free_effects(struct ListBase *lb); +struct Effect *copy_effect(struct Effect *eff); +void copy_act_effect(struct Object *ob); +void copy_effects(struct ListBase *lbn, struct ListBase *lb); +void deselectall_eff(struct Object *ob); +struct PartEff *give_parteff(struct Object *ob); +void where_is_particle(struct PartEff *paf, struct Particle *pa, float ctime, float *vec); +void build_particle_system(struct Object *ob); + +/* particle deflector */ +#define PE_WIND_AS_SPEED 0x00000001 + +struct ListBase *pdInitEffectors(struct Object *obsrc, struct Group *group); +void pdEndEffectors(struct ListBase *lb); +void pdDoEffectors(struct ListBase *lb, float *opco, float *force, float *speed, float cur_time, float loc_time, unsigned int flags); + + + +#endif + diff --git a/source/blender/blenkernel/BKE_endian.h b/source/blender/blenkernel/BKE_endian.h new file mode 100644 index 00000000000..11d39a2ecb6 --- /dev/null +++ b/source/blender/blenkernel/BKE_endian.h @@ -0,0 +1,47 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * Are we little or big endian? From Harbison&Steele. + * BKE_ENDIANNESS(a) returns 1 if big endian and returns 0 if little endian + */ +#ifndef BKE_ENDIAN_H +#define BKE_ENDIAN_H + +#define BKE_ENDIANNESS(a) { \ + union { \ + long l; \ + char c[sizeof (long)]; \ + } u; \ + u.l = 1; \ + a = (u.c[sizeof (long) - 1] == 1) ? 1 : 0; \ +} + +#endif + diff --git a/source/blender/blenkernel/BKE_exotic.h b/source/blender/blenkernel/BKE_exotic.h new file mode 100644 index 00000000000..2a56f894c42 --- /dev/null +++ b/source/blender/blenkernel/BKE_exotic.h @@ -0,0 +1,56 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * dxf/vrml/stl external file io function prototypes + */ + +#ifndef BKE_EXOTIC_H +#define BKE_EXOTIC_H + +struct Mesh; + +void mcol_to_rgba(unsigned int col, float *r, float *g, float *b, float *a); +unsigned int *mcol_to_vcol(struct Mesh *me); // used in py_main.c + +/** + * Reads all 3D fileformats other than Blender fileformat + * @retval 0 The file could not be read. + * @retval 1 The file was read succesfully. + * @attention Used in filesel.c + */ +int BKE_read_exotic(char *name); + +void write_dxf(char *str); +void write_vrml(char *str); +void write_videoscape(char *str); +void write_stl(char *str); + +#endif + diff --git a/source/blender/blenkernel/BKE_font.h b/source/blender/blenkernel/BKE_font.h new file mode 100644 index 00000000000..05621a4d9b2 --- /dev/null +++ b/source/blender/blenkernel/BKE_font.h @@ -0,0 +1,74 @@ +/** + * blenlib/BKE_vfont.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_VFONT_H +#define BKE_VFONT_H + +#include + +struct VFont; +struct Object; +struct Curve; +struct objfnt; + +struct chartrans { + float xof, yof; + float rot; + short linenr,charnr; + char dobreak; +}; + +typedef struct SelBox { + float x, y, w, h; +} SelBox; + +extern struct SelBox *selboxes; + +void BKE_font_register_builtin(void *mem, int size); + +void free_vfont(struct VFont *sc); +struct VFont *load_vfont(char *name); + +struct chartrans *text_to_curve(struct Object *ob, int mode); +int style_to_sel(int style, int toggle); +int mat_to_sel(void); + +int getselection(int *start, int *end); + +void chtoutf8(unsigned long c, char *o); +void wcs2utf8s(char *dst, wchar_t *src); +int wcsleninu8(wchar_t *src); +int utf8towchar_(wchar_t *w, char *c); + +#endif + diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h new file mode 100644 index 00000000000..da90c8e156c --- /dev/null +++ b/source/blender/blenkernel/BKE_global.h @@ -0,0 +1,264 @@ +/** + * blenlib/BKE_global.h (mar-2001 nzc) + * + * Global settings, handles, pointers. This is the root for finding + * any data in Blender. This block is not serialized, but built anew + * for every fresh Blender run. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_GLOBAL_H +#define BKE_GLOBAL_H + +#include "DNA_listBase.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* forwards */ +struct View3D; +struct View2D; +struct SpaceIpo; +struct SpaceButs; +struct SpaceImage; +struct SpaceOops; +struct SpaceText; +struct SpaceSound; +struct SpaceAction; +struct SpaceNla; +struct Main; +struct Scene; +struct bScreen; +struct Object; +struct bSoundListener; +struct BMF_Font; +struct EditMesh; + +typedef struct Global { + + /* active pointers */ + struct View3D *vd; + struct View2D *v2d; + struct SpaceIpo *sipo; + struct SpaceButs *buts; + struct SpaceImage *sima; + struct SpaceOops *soops; + struct SpaceSound *ssound; + struct SpaceAction *saction; /* __NLA */ + struct SpaceNla *snla; + struct Main *main; + struct Scene *scene; /* denk aan file.c */ + struct bScreen *curscreen; + struct Object *obedit; + char editModeTitleExtra[64]; + + /* fonts, allocated global data */ + struct BMF_Font *font, *fonts, *fontss; + + /* strings: lastsaved */ + char ima[256], sce[256], lib[256]; + + /* flag: if != 0 G.sce contains valid relative base path */ + int relbase_valid; + + /* strings of recent opend files */ + struct ListBase recent_files; + + /* totals */ + int totobj, totlamp, totobjsel, totcurve, totmesh; + int totbone, totbonesel; + int totvert, totedge, totface, totvertsel, totedgesel, totfacesel; + + short afbreek, moving; + short qual, background; + short winpos, displaymode; /* used to be in Render */ + short rendering; /* to indicate render is busy, prevent renderwindow events etc */ + /** + * The current version of Blender. + */ + short version; + short simulf, order, rt; + int f; + + /* Editmode lists */ + struct EditMesh *editMesh; + + float textcurs[4][2]; + + /* Frank's variables */ + int save_over; + + /* Reevan's __NLA variables */ + struct ListBase edbo; /* Armature Editmode bones */ + + /* Rob's variables */ + int have_quicktime; + int ui_international; + int charstart; + int charmin; + int charmax; + struct VFont *selfont; + struct ListBase ttfdata; + + /* libtiff flag used to determine if shared library loaded for libtiff*/ + int have_libtiff; + + /* this variable is written to / read from FileGlobal->fileflags */ + int fileflags; + + /* save the allowed windowstate of blender when using -W or -w */ + int windowstate; + + /* Janco's playing ground */ + struct bSoundListener* listener; + + /* Test thingy for Nzc */ + int compat; /* toggle compatibility mode for edge rendering */ + int notonlysolid;/* T-> also edge-render transparent faces */ + + /* confusing... G.f and G.flags */ + int flags; + +} Global; + +/* **************** GLOBAL ********************* */ + +/* G.f */ +#define G_DISABLE_OK (1 << 0) +#define G_PLAYANIM (1 << 1) +/* also uses G_FILE_AUTOPLAY */ +#define G_SIMULATION (1 << 3) +#define G_BACKBUFSEL (1 << 4) +#define G_PICKSEL (1 << 5) +#define G_DRAWNORMALS (1 << 6) +#define G_DRAWFACES (1 << 7) +#define G_FACESELECT (1 << 8) +#define G_DRAW_EXT (1 << 9) +#define G_VERTEXPAINT (1 << 10) +#define G_ALLEDGES (1 << 11) +#define G_DEBUG (1 << 12) +#define G_DOSCRIPTLINKS (1 << 13) +#define G_DRAW_VNORMALS (1 << 14) +#define G_WEIGHTPAINT (1 << 15) +#define G_TEXTUREPAINT (1 << 16) +/* #define G_NOFROZEN (1 << 17) also removed */ +#define G_DRAWEDGES (1 << 18) +#define G_DRAWCREASES (1 << 19) +#define G_DRAWSEAMS (1 << 20) +#define G_HIDDENEDGES (1 << 21) +#define G_HIDDENHANDLES (1 << 22) /* used for curves only */ + + +/* Measurement info Drawing */ +#define G_DRAW_EDGELEN (1 << 22) +#define G_DRAW_FACEAREA (1 << 23) +#define G_DRAW_EDGEANG (1 << 24) + +#define G_RECORDKEYS (1 << 25) + +/*#ifdef WITH_VERSE*/ +#define G_VERSE_CONNECTED (1 << 26) +#define G_DRAW_VERSE_DEBUG (1 << 27) +/*#endif*/ + +#define G_DRAWSHARP (1 << 28) /* draw edges with the sharp flag */ +#define G_SCULPTMODE (1 << 29) + +#define G_AUTOMATKEYS (1 << 30) + +/* macro for testing face select mode + * Texture paint could be removed since selected faces are not used + * however hiding faces is useful */ +#define FACESEL_PAINT_TEST ((G.f&G_FACESELECT) && (G.f & (G_VERTEXPAINT|G_WEIGHTPAINT|G_TEXTUREPAINT))) + +/* G.fileflags */ + +#define G_AUTOPACK (1 << 0) +#define G_FILE_COMPRESS (1 << 1) +#define G_FILE_AUTOPLAY (1 << 2) +#define G_FILE_ENABLE_ALL_FRAMES (1 << 3) +#define G_FILE_SHOW_DEBUG_PROPS (1 << 4) +#define G_FILE_SHOW_FRAMERATE (1 << 5) +#define G_FILE_SHOW_PROFILE (1 << 6) +#define G_FILE_LOCK (1 << 7) +#define G_FILE_SIGN (1 << 8) +#define G_FIle_PUBLISH (1 << 9) +#define G_FILE_NO_UI (1 << 10) +#define G_FILE_GAME_TO_IPO (1 << 11) +#define G_FILE_GAME_MAT (1 << 12) +#define G_FILE_DIAPLAY_LISTS (1 << 13) +#define G_FILE_SHOW_PHYSICS (1 << 14) + +/* G.windowstate */ +#define G_WINDOWSTATE_USERDEF 0 +#define G_WINDOWSTATE_BORDER 1 +#define G_WINDOWSTATE_FULLSCREEN 2 + +/* G.simulf */ +#define G_LOADFILE 2 +#define G_RESTART 4 +#define G_QUIT 8 +#define G_SETSCENE 16 + +/* G.qual */ +#define R_SHIFTKEY 1 +#define L_SHIFTKEY 2 +#define LR_SHIFTKEY 3 +#define R_ALTKEY 4 +#define L_ALTKEY 8 +#define LR_ALTKEY 12 +#define R_CTRLKEY 16 +#define L_CTRLKEY 32 +#define LR_CTRLKEY 48 +#define LR_COMMANDKEY 64 + +/* G.order: indicates what endianness the platform where the file was + * written had. */ +#define L_ENDIAN 1 +#define B_ENDIAN 0 + +/* G.moving, signals drawing in (3d) window to denote transform */ +#define G_TRANSFORM_OBJ 1 +#define G_TRANSFORM_EDIT 2 +#define G_TRANSFORM_MANIP 4 + +/* G.special1 */ + +/* Memory is allocated where? blender.c */ +extern Global G; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h new file mode 100644 index 00000000000..9038422795d --- /dev/null +++ b/source/blender/blenkernel/BKE_group.h @@ -0,0 +1,57 @@ +/** + * blenlib/BKE_group.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_GROUP_H +#define BKE_GROUP_H + +struct Group; +struct GroupObject; +struct Object; +struct bAction; + +void free_group_object(struct GroupObject *go); +void free_group(struct Group *group); +void unlink_group(struct Group *group); +struct Group *add_group(char *name); +void add_to_group(struct Group *group, struct Object *ob); +void rem_from_group(struct Group *group, struct Object *ob); +struct Group *find_group(struct Object *ob); +int object_in_group(struct Object *ob, struct Group *group); + +void group_tag_recalc(struct Group *group); +void group_handle_recalc_and_update(struct Object *parent, struct Group *group); +struct Object *group_get_member_with_action(struct Group *group, struct bAction *act); +void group_relink_nla_objects(struct Object *ob); + +#endif + diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h new file mode 100644 index 00000000000..737adea78be --- /dev/null +++ b/source/blender/blenkernel/BKE_icons.h @@ -0,0 +1,88 @@ +/** +* $Id$ +* +* ***** BEGIN GPL LICENSE BLOCK ***** +* +* 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. +* +* The Original Code is Copyright (C) 2006-2007 Blender Foundation. +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): none yet. +* +* ***** END GPL LICENSE BLOCK ***** +* +*/ + +#ifndef BKE_ICONS_H +#define BKE_ICONS_H + +/* + Resizable Icons for Blender +*/ + +typedef void (*DrawInfoFreeFP) (void *drawinfo); + +struct Icon +{ + void *drawinfo; + void *obj; + short type; + DrawInfoFreeFP drawinfo_free; +}; + +typedef struct Icon Icon; + +struct PreviewImage; + +void BKE_icons_init(int first_dyn_id); + +/* return icon id for library object or create new icon if not found */ +int BKE_icon_getid(struct ID* id); + +/* retrieve icon for id */ +struct Icon* BKE_icon_get(int icon_id); + +/* set icon for id if not already defined */ +/* used for inserting the internal icons */ +void BKE_icon_set(int icon_id, struct Icon* icon); + +/* remove icon and free date if library object becomes invalid */ +void BKE_icon_delete(struct ID* id); + +/* report changes - icon needs to be recalculated */ +void BKE_icon_changed(int icon_id); + +/* free all icons */ +void BKE_icons_free(); + +/* free the preview image */ +void BKE_previewimg_free(struct PreviewImage **prv); + +/* free the preview image belonging to the id */ +void BKE_previewimg_free_id(ID *id); + +/* create a new preview image */ +struct PreviewImage* BKE_previewimg_create() ; + +/* create a copy of the preview image */ +struct PreviewImage* BKE_previewimg_copy(struct PreviewImage *prv); + +/* retrieve existing or create new preview image */ +PreviewImage* BKE_previewimg_get(ID *id); + +#endif /* BKE_ICONS_H */ diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h new file mode 100644 index 00000000000..961cca511de --- /dev/null +++ b/source/blender/blenkernel/BKE_idprop.h @@ -0,0 +1,177 @@ +/** + * $Id: BKE_idprop.h + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Joseph Eagar + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef _BKE_IDPROP_H +#define _BKE_IDPROP_H + +#include "DNA_ID.h" + +/* +these two are included for their (new :P )function +pointers. +*/ +#include "BLO_readfile.h" +#include "BLO_writefile.h" + +struct WriteData; +struct FileData; + +struct IDProperty; +struct ID; + +typedef union { + int i; + float f; + char *str; + struct ID *id; + struct { + short type; + short len; + } array; + struct { + int matvec_size; + float *example; + } matrix_or_vector; +} IDPropertyTemplate; + +/* ----------- Array Type ----------- */ +/*this function works for strings too!*/ +void IDP_ResizeArray(struct IDProperty *prop, int newlen); +void IDP_FreeArray(struct IDProperty *prop); +void IDP_UnlinkArray(struct IDProperty *prop); + +/* ---------- String Type ------------ */ +void IDP_AssignString(struct IDProperty *prop, char *st); +void IDP_ConcatStringC(struct IDProperty *prop, char *st); +void IDP_ConcatString(struct IDProperty *str1, struct IDProperty *append); +void IDP_FreeString(struct IDProperty *prop); + +/*-------- ID Type -------*/ +void IDP_LinkID(struct IDProperty *prop, ID *id); +void IDP_UnlinkID(struct IDProperty *prop); + +/*-------- Group Functions -------*/ + +/*checks if a property with the same name as prop exists, and if so replaces it. + Use this to preserve order!*/ +void IDP_ReplaceInGroup(struct IDProperty *group, struct IDProperty *prop); + +/* +This function has a sanity check to make sure ID properties with the same name don't +get added to the group. + +The sanity check just means the property is not added to the group if another property +exists with the same name; the client code using ID properties then needs to detect this +(the function that adds new properties to groups, IDP_AddToGroup, returns 0 if a property can't +be added to the group, and 1 if it can) and free the property. + +Currently the code to free ID properties is designesd to leave the actual struct +you pass it un-freed, this is needed for how the system works. This means +to free an ID property, you first call IDP_FreeProperty then MEM_freeN the +struct. In the future this will just be IDP_FreeProperty and the code will +be reorganized to work properly. +*/ +int IDP_AddToGroup(struct IDProperty *group, struct IDProperty *prop); + +/*this is the same as IDP_AddToGroup, only you pass an item + in the group list to be inserted after.*/ +int IDP_InsertToGroup(struct IDProperty *group, struct IDProperty *previous, + struct IDProperty *pnew); + +/*NOTE: this does not free the property!! + + To free the property, you have to do: + IDP_FreeProperty(prop); //free all subdata + MEM_freeN(prop); //free property struct itself + +*/ +void IDP_RemFromGroup(struct IDProperty *group, struct IDProperty *prop); + +IDProperty *IDP_GetPropertyFromGroup(struct IDProperty *prop, char *name); + +/*Get an iterator to iterate over the members of an id property group. + Note that this will automatically free the iterator once iteration is complete; + if you stop the iteration before hitting the end, make sure to call + IDP_FreeIterBeforeEnd().*/ +void *IDP_GetGroupIterator(struct IDProperty *prop); + +/*Returns the next item in the iteration. To use, simple for a loop like the following: + while (IDP_GroupIterNext(iter) != NULL) { + . . . + }*/ +IDProperty *IDP_GroupIterNext(void *vself); + +/*Frees the iterator pointed to at vself, only use this if iteration is stopped early; + when the iterator hits the end of the list it'll automatially free itself.*/ +void IDP_FreeIterBeforeEnd(void *vself); + +/*-------- Main Functions --------*/ +/*Get the Group property that contains the id properties for ID id. Set create_if_needed + to create the Group property and attach it to id if it doesn't exist; otherwise + the function will return NULL if there's no Group property attached to the ID.*/ +struct IDProperty *IDP_GetProperties(struct ID *id, int create_if_needed); +struct IDProperty *IDP_CopyProperty(struct IDProperty *prop); + +/* +Allocate a new ID. + +This function takes three arguments: the ID property type, a union which defines +it's initial value, and a name. + +The union is simple to use; see the top of this header file for its definition. +An example of using this function: + + IDPropertyTemplate val; + IDProperty *group, *idgroup, *color; + group = IDP_New(IDP_GROUP, val, "group1"); //groups don't need a template. + + val.array.len = 4 + val.array.type = IDP_FLOAT; + color = IDP_New(IDP_ARRAY, val, "color1"); + + idgroup = IDP_GetProperties(some_id, 1); + IDP_AddToGroup(idgroup, color); + IDP_AddToGroup(idgroup, group); + +Note that you MUST either attach the id property to an id property group with +IDP_AddToGroup or MEM_freeN the property, doing anything else might result in +a memory leak. +*/ +struct IDProperty *IDP_New(int type, IDPropertyTemplate val, char *name); +\ +/*NOTE: this will free all child properties of list arrays and groups! + Also, note that this does NOT unlink anything! Plus it doesn't free + the actual struct IDProperty struct either.*/ +void IDP_FreeProperty(struct IDProperty *prop); + +/*Unlinks any struct IDProperty<->ID linkage that might be going on.*/ +void IDP_UnlinkProperty(struct IDProperty *prop); + +#endif /* _BKE_IDPROP_H */ diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h new file mode 100644 index 00000000000..b308342ac1e --- /dev/null +++ b/source/blender/blenkernel/BKE_image.h @@ -0,0 +1,156 @@ +/** + * blenlib/BKE_image.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_IMAGE_H +#define BKE_IMAGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct Image; +struct ImBuf; +struct Tex; +struct anim; + +/* call from library */ +void free_image(struct Image *me); + +void BKE_stamp_info(struct ImBuf *ibuf); +void BKE_stamp_buf(unsigned char *rect, float *rectf, int width, int height); +int BKE_write_ibuf(struct ImBuf *ibuf, char *name, int imtype, int subimtype, int quality); +void BKE_makepicstring(char *string, char *base, int frame, int imtype); +void BKE_add_image_extension(char *string, int imtype); +int BKE_ftype_to_imtype(int ftype); +int BKE_imtype_to_ftype(int imtype); +int BKE_imtype_is_movie(int imtype); + +struct anim *openanim(char * name, int flags); + +void converttopremul(struct ImBuf *ibuf); +void image_de_interlace(struct Image *ima, int odd); + +void tag_image_time(struct Image *ima); +void free_old_images(void); + +/* ********************************** NEW IMAGE API *********************** */ + +/* ImageUser is in Texture, in Nodes, Background Image, Image Window, .... */ +/* should be used in conjunction with an ID * to Image. */ +struct ImageUser; +struct RenderPass; +struct RenderResult; + +/* ima->source; where image comes from */ +#define IMA_SRC_CHECK 0 +#define IMA_SRC_FILE 1 +#define IMA_SRC_SEQUENCE 2 +#define IMA_SRC_MOVIE 3 +#define IMA_SRC_GENERATED 4 +#define IMA_SRC_VIEWER 5 + +/* ima->type, how to handle/generate it */ +#define IMA_TYPE_IMAGE 0 +#define IMA_TYPE_MULTILAYER 1 + /* generated */ +#define IMA_TYPE_UV_TEST 2 +#define IMA_TYPE_VERSE 3 + /* viewers */ +#define IMA_TYPE_R_RESULT 4 +#define IMA_TYPE_COMPOSITE 5 + +/* ima->ok */ +#define IMA_OK 1 +#define IMA_OK_LOADED 2 + +/* signals */ + /* reload only frees, doesn't read until image_get_ibuf() called */ +#define IMA_SIGNAL_RELOAD 0 +#define IMA_SIGNAL_FREE 1 + /* pack signals are executed */ +#define IMA_SIGNAL_PACK 2 +#define IMA_SIGNAL_REPACK 3 +#define IMA_SIGNAL_UNPACK 4 + /* source changes, from image to sequence or movie, etc */ +#define IMA_SIGNAL_SRC_CHANGE 5 + /* image-user gets a new image, check settings */ +#define IMA_SIGNAL_USER_NEW_IMAGE 6 + +/* depending Image type, and (optional) ImageUser setting it returns ibuf */ +/* always call to make signals work */ +struct ImBuf *BKE_image_get_ibuf(struct Image *ima, struct ImageUser *iuser); + +/* returns existing Image when filename/type is same */ +struct Image *BKE_add_image_file(const char *name); + +/* adds image, adds ibuf, generates color or pattern */ +struct Image *BKE_add_image_size(int width, int height, char *name, short uvtestgrid, float color[4]); + +/* for reload, refresh, pack */ +void BKE_image_signal(struct Image *ima, struct ImageUser *iuser, int signal); + +/* ensures an Image exists for viewing nodes or render */ +struct Image *BKE_image_verify_viewer(int type, const char *name); + +/* force an ImBuf to become part of Image */ +void BKE_image_assign_ibuf(struct Image *ima, struct ImBuf *ibuf); + +/* called on frame change or before render */ +void BKE_image_user_calc_imanr(struct ImageUser *iuser, int cfra, int fieldnr); + +/* fix things in ImageUser when new image gets assigned */ +void BKE_image_user_new_image(struct Image *ima, struct ImageUser *iuser); + +/* sets index offset for multilayer files */ +struct RenderPass *BKE_image_multilayer_index(struct RenderResult *rr, struct ImageUser *iuser); + +/* for multilayer images as well as for render-viewer */ +struct RenderResult *BKE_image_get_renderresult(struct Image *ima); + +/* goes over all textures that use images */ +void BKE_image_free_all_textures(void); + +/* does one image! */ +void BKE_image_free_anim_ibufs(struct Image *ima, int except_frame); + +/* does all images with type MOVIE or SEQUENCE */ +void BKE_image_all_free_anim_ibufs(int except_frame); + +void BKE_image_memorypack(struct Image *ima); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/source/blender/blenkernel/BKE_ipo.h b/source/blender/blenkernel/BKE_ipo.h new file mode 100644 index 00000000000..2a6065eb4f1 --- /dev/null +++ b/source/blender/blenkernel/BKE_ipo.h @@ -0,0 +1,118 @@ +/** + * blenlib/BKE_ipo.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_IPO_H +#define BKE_IPO_H + +typedef struct CfraElem { + struct CfraElem *next, *prev; + float cfra; + int sel; +} CfraElem; + +struct Ipo; +struct IpoCurve; +struct MTex; +struct Material; +struct Object; +struct Sequence; +struct ListBase; +struct BezTriple; +struct ID; +struct bPoseChannel; +struct bActionChannel; +struct rctf; + +float frame_to_float(int cfra); + +void free_ipo_curve(struct IpoCurve *icu); +void free_ipo(struct Ipo *ipo); +void ipo_default_v2d_cur(int blocktype, struct rctf *cur); +struct Ipo *add_ipo(char *name, int idcode); +struct Ipo *copy_ipo(struct Ipo *ipo); +void ipo_idnew(struct Ipo *ipo); +void make_local_obipo(struct Ipo *ipo); +void make_local_matipo(struct Ipo *ipo); +void make_local_keyipo(struct Ipo *ipo); +void make_local_ipo(struct Ipo *ipo); +struct IpoCurve *find_ipocurve(struct Ipo *ipo, int adrcode); + +void calchandles_ipocurve(struct IpoCurve *icu); +void testhandles_ipocurve(struct IpoCurve *icu); +void sort_time_ipocurve(struct IpoCurve *icu); +int test_time_ipocurve(struct IpoCurve *icu); +void correct_bezpart(float *v1, float *v2, float *v3, float *v4); +int findzero(float x, float q0, float q1, float q2, float q3, float *o); +void berekeny(float f1, float f2, float f3, float f4, float *o, int b); +void berekenx(float *f, float *o, int b); +float eval_icu(struct IpoCurve *icu, float ipotime); +void calc_icu(struct IpoCurve *icu, float ctime); +float calc_ipo_time(struct Ipo *ipo, float ctime); +void calc_ipo(struct Ipo *ipo, float ctime); +void write_ipo_poin(void *poin, int type, float val); +float read_ipo_poin(void *poin, int type); +void *give_mtex_poin(struct MTex *mtex, int adrcode ); + +void *get_ipo_poin(struct ID *id, struct IpoCurve *icu, int *type); +void *get_pchan_ipo_poin(struct bPoseChannel *pchan, int adrcode); + +void set_icu_vars(struct IpoCurve *icu); + +void execute_ipo(struct ID *id, struct Ipo *ipo); +void execute_action_ipo(struct bActionChannel *achan, struct bPoseChannel *pchan); + +void do_ipo_nocalc(struct Ipo *ipo); +void do_ipo(struct Ipo *ipo); +void do_mat_ipo(struct Material *ma); +void do_ob_ipo(struct Object *ob); +void do_seq_ipo(struct Sequence *seq); +void do_ob_ipodrivers(struct Object *ob, struct Ipo *ipo, float ctime); + +int has_ipo_code(struct Ipo *ipo, int code); +void do_all_data_ipos(void); +int calc_ipo_spec(struct Ipo *ipo, int adrcode, float *ctime); +void clear_delta_obipo(struct Ipo *ipo); +void add_to_cfra_elem(struct ListBase *lb, struct BezTriple *bezt); +void make_cfra_list(struct Ipo *ipo, struct ListBase *elems); + +/* the sort is an IPO_Channel... */ +int IPO_GetChannels(struct Ipo *ipo, short *channels); + +float IPO_GetFloatValue(struct Ipo *ipo, +/* struct IPO_Channel channel, */ + /* channels are shorts... bit ugly for now*/ + short c, + float ctime); + +#endif + diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h new file mode 100644 index 00000000000..5325b3a8bc1 --- /dev/null +++ b/source/blender/blenkernel/BKE_key.h @@ -0,0 +1,65 @@ +/** + * blenlib/BKE_key.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_KEY_H +#define BKE_KEY_H + +struct Key; +struct KeyBlock; +struct ID; +struct ListBase; +struct Curve; +struct Object; +struct Lattice; +struct Mesh; + +void free_key(struct Key *sc); +struct Key *add_key(struct ID *id); +struct Key *copy_key(struct Key *key); +void make_local_key(struct Key *key); +void sort_keys(struct Key *key); + +void set_four_ipo(float d, float *data, int type); +void set_afgeleide_four_ipo(float d, float *data, int type); + +/* only exported to curve.c! */ +void cp_cu_key(struct Curve *cu, struct KeyBlock *kb, int start, int end); + +int do_ob_key(struct Object *ob); + +struct Key *ob_get_key(struct Object *ob); +struct KeyBlock *ob_get_keyblock(struct Object *ob); +struct KeyBlock *key_get_keyblock(struct Key *key, int index); + +#endif + diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h new file mode 100644 index 00000000000..3dc4b49b52b --- /dev/null +++ b/source/blender/blenkernel/BKE_lattice.h @@ -0,0 +1,74 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * june-2001 ton + */ + +#ifndef BKE_LATTICE_H +#define BKE_LATTICE_H + +struct Lattice; +struct Object; +struct DerivedMesh; +struct BPoint; + +extern struct Lattice *editLatt; + + +void resizelattice(struct Lattice *lt, int u, int v, int w, struct Object *ltOb); +struct Lattice *add_lattice(char *name); +struct Lattice *copy_lattice(struct Lattice *lt); +void free_lattice(struct Lattice *lt); +void make_local_lattice(struct Lattice *lt); +void calc_lat_fudu(int flag, int res, float *fu, float *du); +void init_latt_deform(struct Object *oblatt, struct Object *ob); +void calc_latt_deform(float *co, float weight); +void end_latt_deform(void); +int object_deform_mball(struct Object *ob); +void outside_lattice(struct Lattice *lt); +void curve_deform_verts(struct Object *cuOb, struct Object *target, + struct DerivedMesh *dm, float (*vertexCos)[3], + int numVerts, char *vgroup, short defaxis); +void curve_deform_vector(struct Object *cuOb, struct Object *target, + float *orco, float *vec, float mat[][3], int no_rot_axis); + +void lattice_deform_verts(struct Object *laOb, struct Object *target, + struct DerivedMesh *dm, float (*vertexCos)[3], + int numVerts, char *vgroup); +void armature_deform_verts(struct Object *armOb, struct Object *target, + struct DerivedMesh *dm, float (*vertexCos)[3], + float (*defMats)[3][3], int numVerts, + int deformflag, const char *defgrp_name); +float (*lattice_getVertexCos(struct Object *ob, int *numVerts_r))[3]; +void lattice_applyVertexCos(struct Object *ob, float (*vertexCos)[3]); +void lattice_calc_modifiers(struct Object *ob); + +#endif + diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h new file mode 100644 index 00000000000..1954cfe1e37 --- /dev/null +++ b/source/blender/blenkernel/BKE_library.h @@ -0,0 +1,77 @@ +/** + * blenlib/BKE_library.h (mar-2001 nzc) + * + * Library + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_LIBRARY_TYPES_H +#define BKE_LIBRARY_TYPES_H + +struct ListBase; +struct ID; +struct Main; +struct Library; + +void *alloc_libblock(struct ListBase *lb, short type, const char *name); +void *copy_libblock(void *rt); + +void id_lib_extern(struct ID *id); +void id_us_plus(struct ID *id); + +int check_for_dupid(struct ListBase *lb, struct ID *id, char *name); +int new_id(struct ListBase *lb, struct ID *id, const char *name); + +struct ListBase *wich_libbase(struct Main *mainlib, short type); + +#define MAX_LIBARRAY 40 +int set_listbasepointers(struct Main *main, struct ListBase **lb); + +void free_libblock(struct ListBase *lb, void *idv); +void free_libblock_us(struct ListBase *lb, void *idv); +void free_main(struct Main *mainvar); + +void splitIDname(char *name, char *left, int *nr); +void rename_id(struct ID *id, char *name); +void test_idbutton(char *name); +void all_local(struct Library *lib, int untagged_only); +struct ID *find_id(char *type, char *name); +void clear_id_newpoins(void); + +void IDnames_to_pupstring(char **str, char *title, char *extraops, struct ListBase *lb,struct ID* link, short *nr); +void IMAnames_to_pupstring(char **str, char *title, char *extraops, struct ListBase *lb, struct ID *link, short *nr); +void IPOnames_to_pupstring(char **str, char *title, char *extraops, struct ListBase *lb, struct ID* link, short *nr, int blocktype); + +void flag_listbase_ids(ListBase *lb, short flag, short value); +void flag_all_listbases_ids(short flag, short value); + +#endif + diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h new file mode 100644 index 00000000000..6e0f2fdb284 --- /dev/null +++ b/source/blender/blenkernel/BKE_main.h @@ -0,0 +1,85 @@ +/** + * blenlib/BKE_main.h (mar-2001 nzc) + * + * Main is the root of the 'database' of a Blender context. All data + * is stuffed into lists, and all these lists are knotted to here. A + * Blender file is not much more but a binary dump of these + * lists. This list of lists is not serialized itself. + * + * Oops... this should be a _types.h file. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_MAIN_H +#define BKE_MAIN_H + +#include "DNA_listBase.h" + +struct Library; + +typedef struct Main { + struct Main *next, *prev; + char name[160]; + short versionfile, subversionfile; + short minversionfile, minsubversionfile; + + struct Library *curlib; + ListBase scene; + ListBase library; + ListBase object; + ListBase mesh; + ListBase curve; + ListBase mball; + ListBase mat; + ListBase tex; + ListBase image; + ListBase wave; + ListBase latt; + ListBase lamp; + ListBase camera; + ListBase ipo; + ListBase key; + ListBase world; + ListBase screen; + ListBase script; + ListBase vfont; + ListBase text; + ListBase sound; + ListBase group; + ListBase armature; + ListBase action; + ListBase nodetree; + ListBase brush; +} Main; + + +#endif + diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h new file mode 100644 index 00000000000..2add4b95080 --- /dev/null +++ b/source/blender/blenkernel/BKE_material.h @@ -0,0 +1,78 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * General operations, lookup, etc. for materials. + */ + +#ifndef BKE_MATERIAL_H +#define BKE_MATERIAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct Material; +struct ID; +struct Object; + +void init_def_material(void); +void free_material(struct Material *sc); +void test_object_materials(struct ID *id); +void init_material(struct Material *ma); +struct Material *add_material(char *name); +struct Material *copy_material(struct Material *ma); +void make_local_material(struct Material *ma); + +struct Material ***give_matarar(struct Object *ob); +short *give_totcolp(struct Object *ob); +struct Material *give_current_material(struct Object *ob, int act); +struct ID *material_from(struct Object *ob, int act); +void assign_material(struct Object *ob, struct Material *ma, int act); +void new_material_to_objectdata(struct Object *ob); + +void init_render_material(struct Material *, int, float *); +void init_render_materials(int, float *); +void end_render_material(struct Material *); +void end_render_materials(void); + +int material_in_material(struct Material *parmat, struct Material *mat); + +void automatname(struct Material *); +void delete_material_index(void); + +void ramp_blend(int type, float *r, float *g, float *b, float fac, float *col); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h new file mode 100644 index 00000000000..269e7150768 --- /dev/null +++ b/source/blender/blenkernel/BKE_mball.h @@ -0,0 +1,182 @@ +/** + * blenlib/BKE_mball.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_MBALL_H +#define BKE_MBALL_H + +struct MetaBall; +struct Object; +struct MetaElem; + +typedef struct point { /* a three-dimensional point */ + float x, y, z; /* its coordinates */ +} MB_POINT; + +typedef struct vertex { /* surface vertex */ + MB_POINT position, normal; /* position and surface normal */ +} VERTEX; + +typedef struct vertices { /* list of vertices in polygonization */ + int count, max; /* # vertices, max # allowed */ + VERTEX *ptr; /* dynamically allocated */ +} VERTICES; + +typedef struct corner { /* corner of a cube */ + int i, j, k; /* (i, j, k) is index within lattice */ + float x, y, z, value; /* location and function value */ + struct corner *next; +} CORNER; + +typedef struct cube { /* partitioning cell (cube) */ + int i, j, k; /* lattice location of cube */ + CORNER *corners[8]; /* eight corners */ +} CUBE; + +typedef struct cubes { /* linked list of cubes acting as stack */ + CUBE cube; /* a single cube */ + struct cubes *next; /* remaining elements */ +} CUBES; + +typedef struct centerlist { /* list of cube locations */ + int i, j, k; /* cube location */ + struct centerlist *next; /* remaining elements */ +} CENTERLIST; + +typedef struct edgelist { /* list of edges */ + int i1, j1, k1, i2, j2, k2; /* edge corner ids */ + int vid; /* vertex id */ + struct edgelist *next; /* remaining elements */ +} EDGELIST; + +typedef struct intlist { /* list of integers */ + int i; /* an integer */ + struct intlist *next; /* remaining elements */ +} INTLIST; + +typedef struct intlists { /* list of list of integers */ + INTLIST *list; /* a list of integers */ + struct intlists *next; /* remaining elements */ +} INTLISTS; + +typedef struct process { /* parameters, function, storage */ + /* what happens here? floats, I think. */ + /* float (*function)(void); */ /* implicit surface function */ + float (*function)(float, float, float); + float size, delta; /* cube size, normal delta */ + int bounds; /* cube range within lattice */ + MB_POINT start; /* start point on surface */ + CUBES *cubes; /* active cubes */ + VERTICES vertices; /* surface vertices */ + CENTERLIST **centers; /* cube center hash table */ + CORNER **corners; /* corner value hash table */ + EDGELIST **edges; /* edge and vertex id hash table */ +} PROCESS; + +/* dividing scene using octal tree makes polygonisation faster */ +typedef struct ml_pointer { + struct ml_pointer *next, *prev; + struct MetaElem *ml; +} ml_pointer; + +typedef struct octal_node { + struct octal_node *nodes[8]; /* children of current node */ + struct octal_node *parent; /* parent of current node */ + struct ListBase elems; /* ListBase of MetaElem pointers (ml_pointer) */ + float x_min, y_min, z_min; /* 1st border point */ + float x_max, y_max, z_max; /* 7th border point */ + float x,y,z; /* center of node */ + int pos, neg; /* number of positive and negative MetaElements in the node */ + int count; /* number of MetaElems, which belongs to the node */ +} octal_node; + +typedef struct octal_tree { + struct octal_node *first; /* first node */ + int pos, neg; /* number of positive and negative MetaElements in the scene */ + short depth; /* number of scene subdivision */ +} octal_tree; + +struct pgn_elements { + struct pgn_elements *next, *prev; + char *data; +}; + +void calc_mballco(struct MetaElem *ml, float *vec); +float densfunc(struct MetaElem *ball, float x, float y, float z); +octal_node* find_metaball_octal_node(octal_node *node, float x, float y, float z, short depth); +float metaball(float x, float y, float z); +void accum_mballfaces(int i1, int i2, int i3, int i4); +void *new_pgn_element(int size); + +void freepolygonize(PROCESS *p); +void docube(CUBE *cube, PROCESS *p, struct MetaBall *mb); +void testface(int i, int j, int k, CUBE* old, int bit, int c1, int c2, int c3, int c4, PROCESS *p); +CORNER *setcorner (PROCESS* p, int i, int j, int k); +int vertid (CORNER *c1, CORNER *c2, PROCESS *p, struct MetaBall *mb); +int setcenter(CENTERLIST *table[], int i, int j, int k); +int otherface (int edge, int face); +void makecubetable (void); +void setedge (EDGELIST *table[], int i1, int j1, int k1, int i2, int j2, int k2, int vid); +int getedge (EDGELIST *table[], int i1, int j1, int k1, int i2, int j2, int k2); +void addtovertices (VERTICES *vertices, VERTEX v); +void vnormal (MB_POINT *point, PROCESS *p, MB_POINT *v); +void converge (MB_POINT *p1, MB_POINT *p2, float v1, float v2, float (*function)(float, float, float), MB_POINT *p, struct MetaBall *mb, int f); +void add_cube(PROCESS *mbproc, int i, int j, int k, int count); +void find_first_points(PROCESS *mbproc, struct MetaBall *mb, int a); + +void fill_metaball_octal_node(octal_node *node, struct MetaElem *ml, short i); +void subdivide_metaball_octal_node(octal_node *node, float *size, short depth); +void free_metaball_octal_node(octal_node *node); +void init_metaball_octal_tree(int depth); +void polygonize(PROCESS *mbproc, struct MetaBall *mb); +float init_meta(struct Object *ob); + +void unlink_mball(struct MetaBall *mb); +void free_mball(struct MetaBall *mb); +struct MetaBall *add_mball(char *name); +struct MetaBall *copy_mball(struct MetaBall *mb); +void make_local_mball(struct MetaBall *mb); +void tex_space_mball( struct Object *ob); +void make_orco_mball( struct Object *ob); +struct Object *find_basis_mball( struct Object *ob); +int is_basis_mball(struct Object *ob); +void metaball_polygonize(struct Object *ob); +void calc_mballco(struct MetaElem *ml, float *vec); +float densfunc(struct MetaElem *ball, float x, float y, float z); +float metaball(float x, float y, float z); +void accum_mballfaces(int i1, int i2, int i3, int i4); +void *new_pgn_element(int size); +int nextcwedge (int edge, int face); +void BKE_freecubetable(void); + +#endif + diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h new file mode 100644 index 00000000000..a8e4969ad43 --- /dev/null +++ b/source/blender/blenkernel/BKE_mesh.h @@ -0,0 +1,127 @@ +/** + * blenlib/BKE_mesh.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_MESH_H +#define BKE_MESH_H + +/***/ + +struct BoundBox; +struct DispList; +struct ListBase; +struct MDeformVert; +struct Mesh; +struct MFace; +struct MVert; +struct MCol; +struct Object; +struct MTFace; +struct VecNor; +struct CustomData; + +#ifdef __cplusplus +extern "C" { +#endif + +void unlink_mesh(struct Mesh *me); +void free_mesh(struct Mesh *me); +struct Mesh *add_mesh(char *name); +struct Mesh *copy_mesh(struct Mesh *me); +void mesh_update_customdata_pointers(struct Mesh *me); +void make_local_tface(struct Mesh *me); +void make_local_mesh(struct Mesh *me); +void boundbox_mesh(struct Mesh *me, float *loc, float *size); +void tex_space_mesh(struct Mesh *me); +float *mesh_create_orco_render(struct Object *ob); +float *mesh_create_orco(struct Object *ob); +void test_index_face(struct MFace *mface, struct CustomData *mfdata, int mfindex, int nr); +struct Mesh *get_mesh(struct Object *ob); +void set_mesh(struct Object *ob, struct Mesh *me); +void mball_to_mesh(struct ListBase *lb, struct Mesh *me); +void nurbs_to_mesh(struct Object *ob); +void free_dverts(struct MDeformVert *dvert, int totvert); +void copy_dverts(struct MDeformVert *dst, struct MDeformVert *src, int totvert); /* __NLA */ +int update_realtime_texture(struct MTFace *tface, double time); +void mesh_delete_material_index(struct Mesh *me, int index); +void mesh_set_smooth_flag(struct Object *meshOb, int enableSmooth); + +struct BoundBox *mesh_get_bb(struct Mesh *me); +void mesh_get_texspace(struct Mesh *me, float *loc_r, float *rot_r, float *size_r); + +/* if old, it converts mface->edcode to edge drawflags */ +void make_edges(struct Mesh *me, int old); +void mesh_strip_loose_faces(struct Mesh *me); + + /* Calculate vertex and face normals, face normals are returned in *faceNors_r if non-NULL + * and vertex normals are stored in actual mverts. + */ +void mesh_calc_normals(struct MVert *mverts, int numVerts, struct MFace *mfaces, int numFaces, float **faceNors_r); + + /* Return a newly MEM_malloc'd array of all the mesh vertex locations + * (_numVerts_r_ may be NULL) */ +float (*mesh_getVertexCos(struct Mesh *me, int *numVerts_r))[3]; +float (*mesh_getRefKeyCos(struct Mesh *me, int *numVerts_r))[3]; + +/* map from uv vertex to face (for select linked, stitch, uv suburf) */ + +/* UvVertMap */ + +typedef struct UvVertMap { + struct UvMapVert **vert; + struct UvMapVert *buf; +} UvVertMap; + +typedef struct UvMapVert { + struct UvMapVert *next; + unsigned int f; + unsigned char tfindex, separate; +} UvMapVert; + +UvVertMap *make_uv_vert_map(struct MFace *mface, struct MTFace *tface, unsigned int totface, unsigned int totvert, int selected, float *limit); +UvMapVert *get_uv_map_vert(UvVertMap *vmap, unsigned int v); +void free_uv_vert_map(UvVertMap *vmap); + + +/* functions for making menu's from customdata layers */ +int mesh_layers_menu_charlen(struct CustomData *data, int type); /* use this to work out how many chars to allocate */ +void mesh_layers_menu_concat(struct CustomData *data, int type, char *str); +int mesh_layers_menu(struct CustomData *data, int type); + + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h new file mode 100644 index 00000000000..297443b883d --- /dev/null +++ b/source/blender/blenkernel/BKE_modifier.h @@ -0,0 +1,295 @@ +/** + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_MODIFIER_H +#define BKE_MODIFIER_H + +#include "DNA_modifier_types.h" /* needed for all enum typdefs */ +#include "BKE_customdata.h" + +struct EditMesh; +struct DerivedMesh; +struct DagForest; +struct DagNode; +struct Object; +struct ListBase; +struct LinkNode; +struct bArmature; +struct ModifierData; + +typedef enum { + /* Should not be used, only for None modifier type */ + eModifierTypeType_None, + + /* Modifier only does deformation, implies that modifier + * type should have a valid deformVerts function. OnlyDeform + * style modifiers implicitly accept either mesh or CV + * input but should still declare flags appropriately. + */ + eModifierTypeType_OnlyDeform, + + eModifierTypeType_Constructive, + eModifierTypeType_Nonconstructive, +} ModifierTypeType; + +typedef enum { + eModifierTypeFlag_AcceptsMesh = (1<<0), + eModifierTypeFlag_AcceptsCVs = (1<<1), + eModifierTypeFlag_SupportsMapping = (1<<2), + eModifierTypeFlag_SupportsEditmode = (1<<3), + + /* For modifiers that support editmode this determines if the + * modifier should be enabled by default in editmode. This should + * only be used by modifiers that are relatively speedy and + * also generally used in editmode, otherwise let the user enable + * it by hand. + */ + eModifierTypeFlag_EnableInEditmode = (1<<4), + + /* For modifiers that require original data and so cannot + * be placed after any non-deformative modifier. + */ + eModifierTypeFlag_RequiresOriginalData = (1<<5), +} ModifierTypeFlag; + +typedef void (*ObjectWalkFunc)(void *userData, Object *ob, Object **obpoin); +typedef void (*IDWalkFunc)(void *userData, Object *ob, ID **idpoin); + +typedef struct ModifierTypeInfo { + /* The user visible name for this modifier */ + char name[32]; + + /* The DNA struct name for the modifier data type, used to + * write the DNA data out. + */ + char structName[32]; + + /* The size of the modifier data type, used by allocation. */ + int structSize; + + ModifierTypeType type; + ModifierTypeFlag flags; + + + /********************* Non-optional functions *********************/ + + /* Copy instance data for this modifier type. Should copy all user + * level settings to the target modifier. + */ + void (*copyData)(struct ModifierData *md, struct ModifierData *target); + + /********************* Deform modifier functions *********************/ + + /* Only for deform types, should apply the deformation + * to the given vertex array. If the deformer requires information from + * the object it can obtain it from the derivedData argument if non-NULL, + * and otherwise the ob argument. + */ + void (*deformVerts)(struct ModifierData *md, struct Object *ob, + struct DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts); + + /* Like deformVerts but called during editmode (for supporting modifiers) + */ + void (*deformVertsEM)( + struct ModifierData *md, struct Object *ob, + struct EditMesh *editData, struct DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts); + + /* Set deform matrix per vertex for crazyspace correction */ + void (*deformMatricesEM)( + struct ModifierData *md, struct Object *ob, + struct EditMesh *editData, struct DerivedMesh *derivedData, + float (*vertexCos)[3], float (*defMats)[3][3], int numVerts); + + /********************* Non-deform modifier functions *********************/ + + /* For non-deform types: apply the modifier and return a derived + * data object (type is dependent on object type). + * + * The derivedData argument should always be non-NULL; the modifier + * should read the object data from the derived object instead of the + * actual object data. + * + * The useRenderParams argument indicates if the modifier is being + * applied in the service of the renderer which may alter quality + * settings. + * + * The isFinalCalc parameter indicates if the modifier is being + * calculated for a final result or for something temporary + * (like orcos). This is a hack at the moment, it is meant so subsurf + * can know if it is safe to reuse its internal cache. + * + * The modifier may reuse the derivedData argument (i.e. return it in + * modified form), but must not release it. + */ + struct DerivedMesh *(*applyModifier)( + struct ModifierData *md, struct Object *ob, + struct DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc); + + /* Like applyModifier but called during editmode (for supporting + * modifiers). + * + * The derived object that is returned must support the operations that + * are expected from editmode objects. The same qualifications regarding + * derivedData apply as for applyModifier. + */ + struct DerivedMesh *(*applyModifierEM)( + struct ModifierData *md, struct Object *ob, + struct EditMesh *editData, + struct DerivedMesh *derivedData); + + + /********************* Optional functions *********************/ + + /* Initialize new instance data for this modifier type, this function + * should set modifier variables to their default values. + * + * This function is optional. + */ + void (*initData)(struct ModifierData *md); + + /* Should return a CustomDataMask indicating what data this + * modifier needs. If (mask & (1 << (layer type))) != 0, this modifier + * needs that custom data layer. This function's return value can change + * depending on the modifier's settings. + * + * Note that this means extra data (e.g. vertex groups) - it is assumed + * that all modifiers need mesh data and deform modifiers need vertex + * coordinates. + * + * Note that this limits the number of custom data layer types to 32. + * + * If this function is not present or it returns 0, it is assumed that + * no extra data is needed. + * + * This function is optional. + */ + CustomDataMask (*requiredDataMask)(struct ModifierData *md); + + /* Free internal modifier data variables, this function should + * not free the md variable itself. + * + * This function is optional. + */ + void (*freeData)(struct ModifierData *md); + + /* Return a boolean value indicating if this modifier is able to be + * calculated based on the modifier data. This is *not* regarding the + * md->flag, that is tested by the system, this is just if the data + * validates (for example, a lattice will return false if the lattice + * object is not defined). + * + * This function is optional (assumes never disabled if not present). + */ + int (*isDisabled)(struct ModifierData *md); + + /* Add the appropriate relations to the DEP graph depending on the + * modifier data. + * + * This function is optional. + */ + void (*updateDepgraph)(struct ModifierData *md, struct DagForest *forest, + struct Object *ob, struct DagNode *obNode); + + /* Should return true if the modifier needs to be recalculated on time + * changes. + * + * This function is optional (assumes false if not present). + */ + int (*dependsOnTime)(struct ModifierData *md); + + /* Should call the given walk function on with a pointer to each Object + * pointer that the modifier data stores. This is used for linking on file + * load and for unlinking objects or forwarding object references. + * + * This function is optional. + */ + void (*foreachObjectLink)(struct ModifierData *md, struct Object *ob, + ObjectWalkFunc walk, void *userData); + + /* Should call the given walk function with a pointer to each ID + * pointer (i.e. each datablock pointer) that the modifier data + * stores. This is used for linking on file load and for + * unlinking datablocks or forwarding datablock references. + * + * This function is optional. If it is not present, foreachObjectLink + * will be used. + */ + void (*foreachIDLink)(struct ModifierData *md, struct Object *ob, + IDWalkFunc walk, void *userData); +} ModifierTypeInfo; + +ModifierTypeInfo *modifierType_getInfo (ModifierType type); + +/* Modifier utility calls, do call through type pointer and return + * default values if pointer is optional. + */ +struct ModifierData *modifier_new(int type); +void modifier_free(struct ModifierData *md); + +void modifier_copyData(struct ModifierData *md, struct ModifierData *target); +int modifier_dependsOnTime(struct ModifierData *md); +int modifier_supportsMapping(struct ModifierData *md); +int modifier_couldBeCage(struct ModifierData *md); +int modifier_isDeformer(struct ModifierData *md); +void modifier_setError(struct ModifierData *md, char *format, ...); + +void modifiers_foreachObjectLink(struct Object *ob, + ObjectWalkFunc walk, + void *userData); +void modifiers_foreachIDLink(struct Object *ob, + IDWalkFunc walk, + void *userData); +struct ModifierData *modifiers_findByType(struct Object *ob, ModifierType type); +void modifiers_clearErrors(struct Object *ob); +int modifiers_getCageIndex(struct Object *ob, + int *lastPossibleCageIndex_r); + +int modifiers_isSoftbodyEnabled(struct Object *ob); +struct Object *modifiers_isDeformedByArmature(struct Object *ob); +struct Object *modifiers_isDeformedByLattice(struct Object *ob); +int modifiers_usesArmature(struct Object *ob, struct bArmature *arm); +int modifiers_isDeformed(struct Object *ob); + +/* Calculates and returns a linked list of CustomDataMasks indicating the + * data required by each modifier in the stack pointed to by md for correct + * evaluation, assuming the data indicated by dataMask is required at the + * end of the stack. + */ +struct LinkNode *modifiers_calcDataMasks(struct ModifierData *md, + CustomDataMask dataMask); +struct ModifierData *modifiers_getVirtualModifierList(struct Object *ob); + +#endif + diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h new file mode 100644 index 00000000000..560e5d5c33c --- /dev/null +++ b/source/blender/blenkernel/BKE_nla.h @@ -0,0 +1,47 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BKE_NLA_H +#define BKE_NLA_H + +struct bActionStrip; +struct ListBase; +struct Object; + +void free_actionstrip (struct bActionStrip* strip); +void free_nlastrips (struct ListBase *nlalist); +void copy_nlastrips (struct ListBase *dst, struct ListBase *src); +void copy_actionstrip (struct bActionStrip **dst, struct bActionStrip **src); +void find_stridechannel(struct Object *ob, struct bActionStrip *strip); +struct bActionStrip *convert_action_to_strip (struct Object *ob); +#endif + diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h new file mode 100644 index 00000000000..e4ddc089a86 --- /dev/null +++ b/source/blender/blenkernel/BKE_node.h @@ -0,0 +1,347 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BKE_NODE_H +#define BKE_NODE_H + + + +struct ID; +struct bNodeTree; +struct bNode; +struct bNodeLink; +struct bNodeSocket; +struct bNodeStack; +struct uiBlock; +struct rctf; +struct ListBase; +struct RenderData; +struct Scene; + +#define SOCK_IN 1 +#define SOCK_OUT 2 + +/* ************** NODE TYPE DEFINITIONS ***** */ + +typedef struct bNodeSocketType { + int type, limit; + char *name; + float val1, val2, val3, val4; /* default alloc value for inputs */ + float min, max; /* default range for inputs */ + + /* after this line is used internal only */ + struct bNodeSocket *sock; /* used during verify_types */ + struct bNodeSocket *internsock; /* group nodes, the internal socket counterpart */ + int own_index; /* verify group nodes */ + +} bNodeSocketType; + +typedef struct bNodeType { + void *next,*prev; + int type; + char *name; + float width, minwidth, maxwidth; + short nclass, flag; + + bNodeSocketType *inputs, *outputs; + + char storagename[64]; /* struct name for DNA */ + + void (*execfunc)(void *data, struct bNode *, struct bNodeStack **, struct bNodeStack **); + + /* this line is set on startup of blender */ + int (*butfunc)(struct uiBlock *, struct bNodeTree *, struct bNode *, struct rctf *); + + void (*initfunc)(struct bNode *); + void (*freestoragefunc)(struct bNode *); + void (*copystoragefunc)(struct bNode *, struct bNode *); + + /* for use with dynamic typedefs */ + ID *id; + void *script; /* holds pointer to python script */ + void *dict; /* holds pointer to python script dictionary (scope)*/ + +} bNodeType; + +/* node->exec, now in use for composites (#define for break is same as ready yes) */ +#define NODE_PROCESSING 1 +#define NODE_READY 2 +#define NODE_BREAK 2 +#define NODE_FINISHED 4 +#define NODE_FREEBUFS 8 + +/* nodetype->nclass, for add-menu and themes */ +#define NODE_CLASS_INPUT 0 +#define NODE_CLASS_OUTPUT 1 +#define NODE_CLASS_OP_COLOR 3 +#define NODE_CLASS_OP_VECTOR 4 +#define NODE_CLASS_OP_FILTER 5 +#define NODE_CLASS_GROUP 6 +#define NODE_CLASS_FILE 7 +#define NODE_CLASS_CONVERTOR 8 +#define NODE_CLASS_MATTE 9 +#define NODE_CLASS_DISTORT 10 + +/* ************** GENERIC API, TREES *************** */ + +void ntreeVerifyTypes(struct bNodeTree *ntree); + +struct bNodeTree *ntreeAddTree(int type); +void ntreeInitTypes(struct bNodeTree *ntree); + +void ntreeMakeOwnType(struct bNodeTree *ntree); +void ntreeFreeTree(struct bNodeTree *ntree); +struct bNodeTree *ntreeCopyTree(struct bNodeTree *ntree, int internal_select); +void ntreeMakeLocal(struct bNodeTree *ntree); + +void ntreeSocketUseFlags(struct bNodeTree *ntree); + +void ntreeSolveOrder(struct bNodeTree *ntree); + +void ntreeBeginExecTree(struct bNodeTree *ntree); +void ntreeExecTree(struct bNodeTree *ntree, void *callerdata, int thread); +void ntreeCompositExecTree(struct bNodeTree *ntree, struct RenderData *rd, int do_previews); +void ntreeEndExecTree(struct bNodeTree *ntree); + +void ntreeInitPreview(struct bNodeTree *, int xsize, int ysize); +void ntreeClearPreview(struct bNodeTree *ntree); + +void ntreeFreeCache(struct bNodeTree *ntree); + +/* ************** GENERIC API, NODES *************** */ + +void nodeVerifyType(struct bNodeTree *ntree, struct bNode *node); + +void nodeAddToPreview(struct bNode *, float *, int, int); + +struct bNode *nodeAddNodeType(struct bNodeTree *ntree, int type, struct bNodeTree *ngroup); +void nodeFreeNode(struct bNodeTree *ntree, struct bNode *node); +struct bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node); + +struct bNodeLink *nodeAddLink(struct bNodeTree *ntree, struct bNode *fromnode, struct bNodeSocket *fromsock, struct bNode *tonode, struct bNodeSocket *tosock); +void nodeRemLink(struct bNodeTree *ntree, struct bNodeLink *link); + +struct bNodeLink *nodeFindLink(struct bNodeTree *ntree, struct bNodeSocket *from, struct bNodeSocket *to); +int nodeCountSocketLinks(struct bNodeTree *ntree, struct bNodeSocket *sock); + +void nodeSetActive(struct bNodeTree *ntree, struct bNode *node); +struct bNode *nodeGetActive(struct bNodeTree *ntree); +struct bNode *nodeGetActiveID(struct bNodeTree *ntree, short idtype); +void nodeClearActiveID(struct bNodeTree *ntree, short idtype); + +void NodeTagChanged(struct bNodeTree *ntree, struct bNode *node); +void NodeTagIDChanged(struct bNodeTree *ntree, struct ID *id); + +/* ************** Groups ****************** */ + +struct bNode *nodeMakeGroupFromSelected(struct bNodeTree *ntree); +int nodeGroupUnGroup(struct bNodeTree *ntree, struct bNode *gnode); + +void nodeVerifyGroup(struct bNodeTree *ngroup); +void nodeGroupSocketUseFlags(struct bNodeTree *ngroup); + +/* ************** COMMON NODES *************** */ + +#define NODE_GROUP 2 +#define NODE_GROUP_MENU 1000 + +extern bNodeType node_group_typeinfo; + + +/* ************** SHADER NODES *************** */ + +struct ShadeInput; +struct ShadeResult; + +/* note: types are needed to restore callbacks, don't change values */ +/* range 1 - 100 is reserved for common nodes */ +/* using toolbox, we add node groups by assuming the values below don't exceed NODE_GROUP_MENU for now */ + +#define SH_NODE_OUTPUT 1 + +#define SH_NODE_MATERIAL 100 +#define SH_NODE_RGB 101 +#define SH_NODE_VALUE 102 +#define SH_NODE_MIX_RGB 103 +#define SH_NODE_VALTORGB 104 +#define SH_NODE_RGBTOBW 105 +#define SH_NODE_TEXTURE 106 +#define SH_NODE_NORMAL 107 +#define SH_NODE_GEOMETRY 108 +#define SH_NODE_MAPPING 109 +#define SH_NODE_CURVE_VEC 110 +#define SH_NODE_CURVE_RGB 111 +#define SH_NODE_CAMERA 114 +#define SH_NODE_MATH 115 +#define SH_NODE_VECT_MATH 116 +#define SH_NODE_SQUEEZE 117 +#define SH_NODE_MATERIAL_EXT 118 +#define SH_NODE_INVERT 119 +#define SH_NODE_SEPRGB 120 +#define SH_NODE_COMBRGB 121 +#define SH_NODE_HUE_SAT 122 + + +/* custom defines options for Material node */ +#define SH_NODE_MAT_DIFF 1 +#define SH_NODE_MAT_SPEC 2 +#define SH_NODE_MAT_NEG 4 + +/* the type definitions array */ +extern struct ListBase node_all_shaders; + +/* API */ + +void ntreeShaderExecTree(struct bNodeTree *ntree, struct ShadeInput *shi, struct ShadeResult *shr); +void ntreeShaderGetTexcoMode(struct bNodeTree *ntree, int osa, short *texco, int *mode); +void nodeShaderSynchronizeID(struct bNode *node, int copyto); + + /* switch material render loop */ +extern void (*node_shader_lamp_loop)(struct ShadeInput *, struct ShadeResult *); +void set_node_shader_lamp_loop(void (*lamp_loop_func)(struct ShadeInput *, struct ShadeResult *)); + + +/* ************** COMPOSITE NODES *************** */ + +/* output socket defines */ +#define RRES_OUT_IMAGE 0 +#define RRES_OUT_ALPHA 1 +#define RRES_OUT_Z 2 +#define RRES_OUT_NORMAL 3 +#define RRES_OUT_UV 4 +#define RRES_OUT_VEC 5 +#define RRES_OUT_RGBA 6 +#define RRES_OUT_DIFF 7 +#define RRES_OUT_SPEC 8 +#define RRES_OUT_SHADOW 9 +#define RRES_OUT_AO 10 +#define RRES_OUT_REFLECT 11 +#define RRES_OUT_REFRACT 12 +#define RRES_OUT_RADIO 13 +#define RRES_OUT_INDEXOB 14 + +/* note: types are needed to restore callbacks, don't change values */ +#define CMP_NODE_VIEWER 201 +#define CMP_NODE_RGB 202 +#define CMP_NODE_VALUE 203 +#define CMP_NODE_MIX_RGB 204 +#define CMP_NODE_VALTORGB 205 +#define CMP_NODE_RGBTOBW 206 +#define CMP_NODE_NORMAL 207 +#define CMP_NODE_CURVE_VEC 208 +#define CMP_NODE_CURVE_RGB 209 +#define CMP_NODE_ALPHAOVER 210 +#define CMP_NODE_BLUR 211 +#define CMP_NODE_FILTER 212 +#define CMP_NODE_MAP_VALUE 213 +#define CMP_NODE_TIME 214 +#define CMP_NODE_VECBLUR 215 +#define CMP_NODE_SEPRGBA 216 +#define CMP_NODE_SEPHSVA 217 +#define CMP_NODE_SETALPHA 218 +#define CMP_NODE_HUE_SAT 219 +#define CMP_NODE_IMAGE 220 +#define CMP_NODE_R_LAYERS 221 +#define CMP_NODE_COMPOSITE 222 +#define CMP_NODE_OUTPUT_FILE 223 +#define CMP_NODE_TEXTURE 224 +#define CMP_NODE_TRANSLATE 225 +#define CMP_NODE_ZCOMBINE 226 +#define CMP_NODE_COMBRGBA 227 +#define CMP_NODE_DILATEERODE 228 +#define CMP_NODE_ROTATE 229 +#define CMP_NODE_SCALE 230 +#define CMP_NODE_SEPYCCA 231 +#define CMP_NODE_COMBYCCA 232 +#define CMP_NODE_SEPYUVA 233 +#define CMP_NODE_COMBYUVA 234 +#define CMP_NODE_DIFF_MATTE 235 +#define CMP_NODE_COLOR_SPILL 236 +#define CMP_NODE_CHROMA 237 +#define CMP_NODE_CHANNEL_MATTE 238 +#define CMP_NODE_FLIP 239 +#define CMP_NODE_SPLITVIEWER 240 +#define CMP_NODE_INDEX_MASK 241 +#define CMP_NODE_MAP_UV 242 +#define CMP_NODE_ID_MASK 243 +#define CMP_NODE_DEFOCUS 244 +#define CMP_NODE_DISPLACE 245 +#define CMP_NODE_COMBHSVA 246 +#define CMP_NODE_MATH 247 +#define CMP_NODE_LUMA_MATTE 248 +#define CMP_NODE_BRIGHTCONTRAST 249 +#define CMP_NODE_GAMMA 250 +#define CMP_NODE_INVERT 251 +#define CMP_NODE_NORMALIZE 252 +#define CMP_NODE_CROP 253 + +#define CMP_NODE_GLARE 301 +#define CMP_NODE_TONEMAP 302 +#define CMP_NODE_LENSDIST 303 + +/* channel toggles */ +#define CMP_CHAN_RGB 1 +#define CMP_CHAN_A 2 +#define CMP_CHAN_R 4 +#define CMP_CHAN_G 8 +#define CMP_CHAN_B 16 + +/* filter types */ +#define CMP_FILT_SOFT 0 +#define CMP_FILT_SHARP 1 +#define CMP_FILT_LAPLACE 2 +#define CMP_FILT_SOBEL 3 +#define CMP_FILT_PREWITT 4 +#define CMP_FILT_KIRSCH 5 +#define CMP_FILT_SHADOW 6 + +/* scale node type, in custom1 */ +#define CMP_SCALE_RELATIVE 0 +#define CMP_SCALE_ABSOLUTE 1 + + +/* the type definitions array */ +extern struct ListBase node_all_composit; + +/* API */ +struct CompBuf; +void ntreeCompositTagRender(struct Scene *sce); +int ntreeCompositTagAnimated(struct bNodeTree *ntree); +void ntreeCompositTagGenerators(struct bNodeTree *ntree); +void ntreeCompositForceHidden(struct bNodeTree *ntree); + +void free_compbuf(struct CompBuf *cbuf); /* internal...*/ + +void init_nodesystem(void); +void free_nodesystem(void); + +#endif diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h new file mode 100644 index 00000000000..6e363515f41 --- /dev/null +++ b/source/blender/blenkernel/BKE_object.h @@ -0,0 +1,118 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * General operations, lookup, etc. for blender objects. + */ + +#ifndef BKE_OBJECT_H +#define BKE_OBJECT_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct Base; +struct Object; +struct Camera; +struct BoundBox; +struct View3D; +struct SoftBody; +struct Group; +struct bAction; + +void clear_workob(void); +void copy_baseflags(void); +void copy_objectflags(void); +struct SoftBody *copy_softbody(struct SoftBody *sb); +void update_base_layer(struct Object *ob); + +void free_object(struct Object *ob); +void object_free_display(struct Object *ob); +void object_free_modifiers(struct Object *ob); + +void object_make_proxy(struct Object *ob, struct Object *target, struct Object *gob); + +void unlink_object(struct Object *ob); +int exist_object(struct Object *obtest); +void *add_camera(char *name); +struct Camera *copy_camera(struct Camera *cam); +void make_local_camera(struct Camera *cam); +float dof_camera(struct Object *ob); +void *add_lamp(char *name); +struct Lamp *copy_lamp(struct Lamp *la); +void make_local_lamp(struct Lamp *la); +void free_camera(struct Camera *ca); +void free_lamp(struct Lamp *la); +void *add_wave(void); + +struct Object *add_only_object(int type, char *name); +struct Object *add_object(int type); +void base_init_from_view3d(struct Base *base, struct View3D *v3d); + +struct Object *copy_object(struct Object *ob); +void expand_local_object(struct Object *ob); +void make_local_object(struct Object *ob); +void set_mblur_offs(float blur); +void set_field_offs(float field); +void disable_speed_curve(int val); + +float bsystem_time(struct Object *ob, float cfra, float ofs); +void object_to_mat3(struct Object *ob, float mat[][3]); +void object_to_mat4(struct Object *ob, float mat[][4]); + +void set_no_parent_ipo(int val); + +void disable_where_script(short on); +int during_script(void); +void disable_where_scriptlink(short on); +int during_scriptlink(void); + +void where_is_object_time(struct Object *ob, float ctime); +void where_is_object(struct Object *ob); +void where_is_object_simul(struct Object *ob); + +void what_does_parent(struct Object *ob); + +struct BoundBox *unit_boundbox(void); +void boundbox_set_from_min_max(struct BoundBox *bb, float min[3], float max[3]); +struct BoundBox *object_get_boundbox(struct Object *ob); +void object_boundbox_flag(struct Object *ob, int flag, int set); +void minmax_object(struct Object *ob, float *min, float *max); +void minmax_object_duplis(struct Object *ob, float *min, float *max); +void solve_tracking (struct Object *ob, float targetmat[][4]); + +void object_handle_update(struct Object *ob); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/source/blender/blenkernel/BKE_packedFile.h b/source/blender/blenkernel/BKE_packedFile.h new file mode 100644 index 00000000000..4b362bbb38f --- /dev/null +++ b/source/blender/blenkernel/BKE_packedFile.h @@ -0,0 +1,64 @@ +/** + * blenlib/BKE_packedFile.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_PACKEDFILE_H +#define BKE_PACKEDFILE_H + +#define RET_OK 0 +#define RET_ERROR 1 + +struct PackedFile; +struct VFont; +struct bSample; +struct bSound; +struct Image; + +struct PackedFile * newPackedFile(char * filename); +struct PackedFile * newPackedFileMemory(void *mem, int memlen); + +int seekPackedFile(struct PackedFile * pf, int offset, int whence); +void rewindPackedFile(struct PackedFile * pf); +int readPackedFile(struct PackedFile * pf, void * data, int size); +int countPackedFiles(void); +void freePackedFile(struct PackedFile * pf); +void packAll(void); +int writePackedFile(char * filename, struct PackedFile *pf, int guimode); +int checkPackedFile(char * filename, struct PackedFile * pf); +char * unpackFile(char * abs_name, char * local_name, struct PackedFile * pf, int how); +int unpackVFont(struct VFont * vfont, int how); +int unpackSample(struct bSample *sample, int how); +int unpackImage(struct Image * ima, int how); +void unpackAll(int how); + +#endif + diff --git a/source/blender/blenkernel/BKE_plugin_types.h b/source/blender/blenkernel/BKE_plugin_types.h new file mode 100644 index 00000000000..2b7c6c06832 --- /dev/null +++ b/source/blender/blenkernel/BKE_plugin_types.h @@ -0,0 +1,72 @@ +/** + * blenlib/BKE_plugin_types.h (mar-2001 nzc) + * + * Renderrecipe and scene decription. The fact that there is a + * hierarchy here is a bit strange, and not desirable. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_PLUGIN_TYPES_H +#define BKE_PLUGIN_TYPES_H + +struct ImBuf; + +typedef int (*TexDoit)(int, void*, float*, float*, float*); +typedef void (*SeqDoit)(void*, float, float, int, int, + struct ImBuf*, struct ImBuf*, + struct ImBuf*, struct ImBuf*); + +typedef struct VarStruct { + int type; + char name[16]; + float def, min, max; + char tip[80]; +} VarStruct; + +typedef struct _PluginInfo { + char *name; + char *snames; + + int stypes; + int nvars; + VarStruct *varstr; + float *result; + float *cfra; + + void (*init)(void); + void (*callback)(int); + TexDoit tex_doit; + SeqDoit seq_doit; + void (*instance_init)(void *); +} PluginInfo; + +#endif + diff --git a/source/blender/blenkernel/BKE_property.h b/source/blender/blenkernel/BKE_property.h new file mode 100644 index 00000000000..c8af07e3ee8 --- /dev/null +++ b/source/blender/blenkernel/BKE_property.h @@ -0,0 +1,55 @@ +/** + * blenkernel/BKE_property.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_PROPERTY_H +#define BKE_PROPERTY_H + +struct bProperty; +struct ListBase; +struct Object; + +void free_property(struct bProperty *prop); +void free_properties(struct ListBase *lb); +struct bProperty *copy_property(struct bProperty *prop); +void copy_properties(struct ListBase *lbn, struct ListBase *lbo); +void init_property(struct bProperty *prop); +struct bProperty *new_property(int type); +struct bProperty *get_property(struct Object *ob, char *name); +int compare_property(struct bProperty *prop, char *str); +void set_property(struct bProperty *prop, char *str); +void add_property(struct bProperty *prop, char *str); +void set_property_valstr(struct bProperty *prop, char *str); +void cp_property(struct bProperty *prop1, struct bProperty *prop2); + +#endif + diff --git a/source/blender/blenkernel/BKE_sca.h b/source/blender/blenkernel/BKE_sca.h new file mode 100644 index 00000000000..62ed06665fe --- /dev/null +++ b/source/blender/blenkernel/BKE_sca.h @@ -0,0 +1,75 @@ +/** + * blenlib/BKE_sca.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_SCA_H +#define BKE_SCA_H + +struct Text; +struct bSensor; +struct Object; +struct bController; +struct bActuator; + +void unlink_controller(struct bController *cont); +void unlink_controllers(struct ListBase *lb); +void free_controller(struct bController *cont); +void free_controllers(struct ListBase *lb); + +void unlink_actuator(struct bActuator *act); +void unlink_actuators(struct ListBase *lb); +void free_actuator(struct bActuator *act); +void free_actuators(struct ListBase *lb); + +void free_text_controllers(struct Text *txt); +void free_sensor(struct bSensor *sens); +void free_sensors(struct ListBase *lb); +struct bSensor *copy_sensor(struct bSensor *sens); +void copy_sensors(struct ListBase *lbn, struct ListBase *lbo); +void init_sensor(struct bSensor *sens); +struct bSensor *new_sensor(int type); +struct bController *copy_controller(struct bController *cont); +void copy_controllers(struct ListBase *lbn, struct ListBase *lbo); +void init_controller(struct bController *cont); +struct bController *new_controller(int type); +struct bActuator *copy_actuator(struct bActuator *act); +void copy_actuators(struct ListBase *lbn, struct ListBase *lbo); +void init_actuator(struct bActuator *act); +struct bActuator *new_actuator(int type); +void clear_sca_new_poins_ob(struct Object *ob); +void clear_sca_new_poins(void); +void set_sca_new_poins_ob(struct Object *ob); +void set_sca_new_poins(void); +void sca_remove_ob_poin(struct Object *obt, struct Object *ob); + +#endif + diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h new file mode 100644 index 00000000000..69ff6876acd --- /dev/null +++ b/source/blender/blenkernel/BKE_scene.h @@ -0,0 +1,84 @@ +/** + * blenlib/BKE_scene.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_SCENE_H +#define BKE_SCENE_H + +struct Scene; +struct Object; +struct Base; +struct AviCodecData; +struct QuicktimeCodecData; + +/* sequence related defines */ +#define WHILE_SEQ(base) { \ + int totseq_, seq_; Sequence **seqar; \ + build_seqar( base, &seqar, &totseq_); \ + for(seq_ = 0; seq_ < totseq_; seq_++) { \ + seq= seqar[seq_]; + + +#define END_SEQ } \ + if(seqar) MEM_freeN(seqar); \ +} + +/* note; doesn't work when scene is empty */ +#define SETLOOPER(s, b) sce= s, b= sce->base.first; b; b= (b->next?b->next:sce->set?(sce=sce->set)->base.first:NULL) + + +void free_avicodecdata(struct AviCodecData *acd); +void free_qtcodecdata(struct QuicktimeCodecData *acd); + +void free_scene(struct Scene *me); +struct Scene *add_scene(char *name); +struct Base *object_in_scene(struct Object *ob, struct Scene *sce); + +void set_scene_bg(struct Scene *sce); +void set_scene_name(char *name); + +int next_object(int val, struct Base **base, struct Object **ob); +struct Object *scene_find_camera(struct Scene *sc); + +struct Base *scene_add_base(struct Scene *sce, struct Object *ob); +void scene_deselect_all(struct Scene *sce); +void scene_select_base(struct Scene *sce, struct Base *selbase); + +/* checks for cycle, returns 1 if it's all OK */ +int scene_check_setscene(struct Scene *sce); + +void scene_update_for_newframe(struct Scene *sce, unsigned int lay); + +void scene_add_render_layer(struct Scene *sce); + +#endif + diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h new file mode 100644 index 00000000000..e20b00a00e7 --- /dev/null +++ b/source/blender/blenkernel/BKE_screen.h @@ -0,0 +1,40 @@ +/** + * blenlib/BKE_screen.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_SCREEN_H +#define BKE_SCREEN_H + +void free_screen(struct bScreen *sc); + +#endif + diff --git a/source/blender/blenkernel/BKE_script.h b/source/blender/blenkernel/BKE_script.h new file mode 100644 index 00000000000..70f3d58fcae --- /dev/null +++ b/source/blender/blenkernel/BKE_script.h @@ -0,0 +1,49 @@ +/** + * blenlib/BKE_script.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_SCRIPT_H +#define BKE_SCRIPT_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct Script; + +void free_script (struct Script *script); + +#ifdef __cplusplus +} +#endif + +#endif /* BKE_SCRIPT_H */ diff --git a/source/blender/blenkernel/BKE_softbody.h b/source/blender/blenkernel/BKE_softbody.h new file mode 100644 index 00000000000..15200bf46f8 --- /dev/null +++ b/source/blender/blenkernel/BKE_softbody.h @@ -0,0 +1,58 @@ +/** + * BKE_softbody.h + * + * $Id: BKE_softbody.h + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_SOFTBODY_H +#define BKE_SOFTBODY_H + +struct Object; +struct SoftBody; + +/* allocates and initializes general main data */ +extern struct SoftBody *sbNew(void); + +/* frees internal data and softbody itself */ +extern void sbFree(struct SoftBody *sb); + +/* do one simul step, reading and writing vertex locs from given array */ +extern void sbObjectStep(struct Object *ob, float framnr, float (*vertexCos)[3], int numVerts); + +/* makes totally fresh start situation, resets time */ +extern void sbObjectToSoftbody(struct Object *ob); + +/* links the softbody module to a 'test for Interrupt' function */ +/* pass NULL to unlink again */ +extern void sbSetInterruptCallBack(int (*f)(void)); + + +#endif + diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h new file mode 100644 index 00000000000..0a747847b11 --- /dev/null +++ b/source/blender/blenkernel/BKE_sound.h @@ -0,0 +1,55 @@ +/** + * sound.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_SOUND_H +#define BKE_SOUND_H + +struct PackedFile; +struct bSound; +struct bSample; +struct ListBase; + +/* bad bad global... */ +extern struct ListBase *samples; + +void sound_free_all_samples(void); + +/* void *sound_get_listener(void); implemented in src!also declared there now */ + +void sound_set_packedfile(struct bSample* sample, struct PackedFile* pf); +struct PackedFile* sound_find_packedfile(struct bSound* sound); +void sound_free_sample(struct bSample* sample); +void sound_free_sound(struct bSound* sound); + +#endif + diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h new file mode 100644 index 00000000000..459519913c5 --- /dev/null +++ b/source/blender/blenkernel/BKE_subsurf.h @@ -0,0 +1,49 @@ +/* $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_SUBSURF_H +#define BKE_SUBSURF_H + +struct Mesh; +struct Object; +struct DerivedMesh; +struct EditMesh; +struct SubsurfModifierData; + +struct DerivedMesh *subsurf_make_derived_from_derived( + struct DerivedMesh *dm, + struct SubsurfModifierData *smd, + int useRenderParams, float (*vertCos)[3], + int isFinalCalc, int editMode); + +void subsurf_calculate_limit_positions(Mesh *me, float (*positions_r)[3]); + +#endif + diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h new file mode 100644 index 00000000000..35f0ee841be --- /dev/null +++ b/source/blender/blenkernel/BKE_text.h @@ -0,0 +1,144 @@ +/** + * blenlib/BKE_text.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_TEXT_H +#define BKE_TEXT_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct Text; +struct TextLine; +struct SpaceText; + +void free_text (struct Text *text); +void txt_set_undostate (int u); +int txt_get_undostate (void); +struct Text* add_empty_text (char *name); +int reopen_text (struct Text *text); +struct Text* add_text (char *file); +struct Text* copy_text (struct Text *ta); + +void txt_free_cut_buffer (void); + +char* txt_to_buf (struct Text *text); +void txt_clean_text (struct Text *text); +void txt_order_cursors (struct Text *text); +int txt_find_string (struct Text *text, char *findstr); +int txt_has_sel (struct Text *text); +int txt_get_span (struct TextLine *from, struct TextLine *to); +void txt_move_up (struct Text *text, short sel); +void txt_move_down (struct Text *text, short sel); +void txt_move_left (struct Text *text, short sel); +void txt_move_right (struct Text *text, short sel); +void txt_move_bof (struct Text *text, short sel); +void txt_move_eof (struct Text *text, short sel); +void txt_move_bol (struct Text *text, short sel); +void txt_move_eol (struct Text *text, short sel); +void txt_move_toline (struct Text *text, unsigned int line, short sel); +void txt_pop_sel (struct Text *text); +void txt_delete_char (struct Text *text); +void txt_copy_sel (struct Text *text); +void txt_sel_all (struct Text *text); +void txt_sel_line (struct Text *text); +void txt_print_cutbuffer (void); +void txt_cut_sel (struct Text *text); +char* txt_sel_to_buf (struct Text *text); +void txt_insert_buf (struct Text *text, char *in_buffer); +void txt_paste (struct Text *text); +void txt_print_undo (struct Text *text); +void txt_undo_add_toop (struct Text *text, int op, unsigned int froml, unsigned short fromc, unsigned int tol, unsigned short toc); +void txt_do_undo (struct Text *text); +void txt_do_redo (struct Text *text); +void txt_split_curline (struct Text *text); +void txt_backspace_char (struct Text *text); +int txt_add_char (struct Text *text, char add); +void txt_find_panel (struct SpaceText *st, int again); +void run_python_script (struct SpaceText *st); +int jumptoline_interactive (struct SpaceText *st); +void txt_export_to_object (struct Text *text); +void txt_export_to_objects(struct Text *text); +void unindent (struct Text *text); +void comment (struct Text *text); +void indent (struct Text *text); +void uncomment (struct Text *text); +int setcurr_tab (struct Text *text); +void convert_tabs (struct SpaceText *st, int tab); + +/* Undo opcodes */ + +/* Simple main cursor movement */ +#define UNDO_CLEFT 001 +#define UNDO_CRIGHT 002 +#define UNDO_CUP 003 +#define UNDO_CDOWN 004 + +/* Simple selection cursor movement */ +#define UNDO_SLEFT 005 +#define UNDO_SRIGHT 006 +#define UNDO_SUP 007 +#define UNDO_SDOWN 021 + +/* Complex movement (opcode is followed + * by 4 character line ID + a 2 character + * position ID and opcode (repeat)) */ +#define UNDO_CTO 022 +#define UNDO_STO 023 + +/* Complex editing (opcode is followed + * by 1 character ID and opcode (repeat)) */ +#define UNDO_INSERT 024 +#define UNDO_BS 025 +#define UNDO_DEL 026 + +/* Text block (opcode is followed + * by 4 character length ID + the text + * block itself + the 4 character length + * ID (repeat) and opcode (repeat)) */ +#define UNDO_DBLOCK 027 /* Delete block */ +#define UNDO_IBLOCK 030 /* Insert block */ + +/* Misc */ +#define UNDO_SWAP 031 /* Swap cursors */ + +#define UNDO_INDENT 032 +#define UNDO_UNINDENT 033 +#define UNDO_COMMENT 034 +#define UNDO_UNCOMMENT 035 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h new file mode 100644 index 00000000000..902423482b1 --- /dev/null +++ b/source/blender/blenkernel/BKE_texture.h @@ -0,0 +1,80 @@ +/** + * blenlib/BKE_texture.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_TEXTURE_H +#define BKE_TEXTURE_H + +struct Tex; +struct MTex; +struct PluginTex; +struct LampRen; +struct ColorBand; +struct HaloRen; +struct TexMapping; +struct EnvMap; + +/* in ColorBand struct */ +#define MAXCOLORBAND 32 + + +void free_texture(struct Tex *t); +int test_dlerr(const char *name, const char *symbol); +void open_plugin_tex(struct PluginTex *pit); +struct PluginTex *add_plugin_tex(char *str); +void free_plugin_tex(struct PluginTex *pit); + +void init_colorband(struct ColorBand *coba, int rangetype); +struct ColorBand *add_colorband(int rangetype); +int do_colorband(struct ColorBand *coba, float in, float out[4]); + +void default_tex(struct Tex *tex); +struct Tex *add_texture(char *name); +void default_mtex(struct MTex *mtex); +struct MTex *add_mtex(void); +struct Tex *copy_texture(struct Tex *tex); +void make_local_texture(struct Tex *tex); +void autotexname(struct Tex *tex); +struct Tex *give_current_texture(struct Object *ob, int act); + +struct TexMapping *add_mapping(void); +void init_mapping(struct TexMapping *texmap); + + +void BKE_free_envmapdata(struct EnvMap *env); +void BKE_free_envmap(struct EnvMap *env); +struct EnvMap *BKE_add_envmap(void); +struct EnvMap *BKE_copy_envmap(struct EnvMap *env); + + +#endif + diff --git a/source/blender/blenkernel/BKE_utildefines.h b/source/blender/blenkernel/BKE_utildefines.h new file mode 100644 index 00000000000..a30617a2f15 --- /dev/null +++ b/source/blender/blenkernel/BKE_utildefines.h @@ -0,0 +1,192 @@ +/* + $Id$ + + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef BKE_UTILDEFINES_H +#define BKE_UTILDEFINES_H + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +/* these values need to be hardcoded in structs, dna does not recognize defines */ +/* also defined in DNA_space_types.h */ +#ifndef FILE_MAXDIR +#define FILE_MAXDIR 160 +#define FILE_MAXFILE 80 +#define FILE_MAX 240 +#endif + +#define ELEM(a, b, c) ( (a)==(b) || (a)==(c) ) +#define ELEM3(a, b, c, d) ( ELEM(a, b, c) || (a)==(d) ) +#define ELEM4(a, b, c, d, e) ( ELEM(a, b, c) || ELEM(a, d, e) ) +#define ELEM5(a, b, c, d, e, f) ( ELEM(a, b, c) || ELEM3(a, d, e, f) ) +#define ELEM6(a, b, c, d, e, f, g) ( ELEM(a, b, c) || ELEM4(a, d, e, f, g) ) +#define ELEM7(a, b, c, d, e, f, g, h) ( ELEM3(a, b, c, d) || ELEM4(a, e, f, g, h) ) +#define ELEM8(a, b, c, d, e, f, g, h, i) ( ELEM4(a, b, c, d, e) || ELEM4(a, f, g, h, i) ) +#define ELEM9(a, b, c, d, e, f, g, h, i, j) ( ELEM4(a, b, c, d, e) || ELEM5(a, f, g, h, i, j) ) + +/* string compare */ +#define STREQ(str, a) ( strcmp((str), (a))==0 ) +#define STREQ2(str, a, b) ( STREQ(str, a) || STREQ(str, b) ) +#define STREQ3(str, a, b, c) ( STREQ2(str, a, b) || STREQ(str, c) ) + +/* min/max */ +#define MIN2(x,y) ( (x)<(y) ? (x) : (y) ) +#define MIN3(x,y,z) MIN2( MIN2((x),(y)) , (z) ) +#define MIN4(x,y,z,a) MIN2( MIN2((x),(y)) , MIN2((z),(a)) ) + +#define MAX2(x,y) ( (x)>(y) ? (x) : (y) ) +#define MAX3(x,y,z) MAX2( MAX2((x),(y)) , (z) ) +#define MAX4(x,y,z,a) MAX2( MAX2((x),(y)) , MAX2((z),(a)) ) + +#define INIT_MINMAX(min, max) { (min)[0]= (min)[1]= (min)[2]= 1.0e30f; (max)[0]= (max)[1]= (max)[2]= -1.0e30f; } + +#define INIT_MINMAX2(min, max) { (min)[0]= (min)[1]= 1.0e30f; (max)[0]= (max)[1]= -1.0e30f; } + +#define DO_MINMAX(vec, min, max) { if( (min)[0]>(vec)[0] ) (min)[0]= (vec)[0]; \ + if( (min)[1]>(vec)[1] ) (min)[1]= (vec)[1]; \ + if( (min)[2]>(vec)[2] ) (min)[2]= (vec)[2]; \ + if( (max)[0]<(vec)[0] ) (max)[0]= (vec)[0]; \ + if( (max)[1]<(vec)[1] ) (max)[1]= (vec)[1]; \ + if( (max)[2]<(vec)[2] ) (max)[2]= (vec)[2]; } \ + +#define DO_MINMAX2(vec, min, max) { if( (min)[0]>(vec)[0] ) (min)[0]= (vec)[0]; \ + if( (min)[1]>(vec)[1] ) (min)[1]= (vec)[1]; \ + if( (max)[0]<(vec)[0] ) (max)[0]= (vec)[0]; \ + if( (max)[1]<(vec)[1] ) (max)[1]= (vec)[1]; } + +#define MINSIZE(val, size) ( ((val)>=0.0) ? (((val)<(size)) ? (size): (val)) : ( ((val)>(-size)) ? (-size) : (val))) + +/* some math and copy defines */ + +#define SWAP(type, a, b) { type sw_ap; sw_ap=(a); (a)=(b); (b)=sw_ap; } + +#define ABS(a) ( (a)<0 ? (-(a)) : (a) ) + +#define VECCOPY(v1,v2) {*(v1)= *(v2); *(v1+1)= *(v2+1); *(v1+2)= *(v2+2);} +#define VECCOPY2D(v1,v2) {*(v1)= *(v2); *(v1+1)= *(v2+1);} +#define QUATCOPY(v1,v2) {*(v1)= *(v2); *(v1+1)= *(v2+1); *(v1+2)= *(v2+2); *(v1+3)= *(v2+3);} +#define LONGCOPY(a, b, c) {int lcpc=c, *lcpa=(int *)a, *lcpb=(int *)b; while(lcpc-->0) *(lcpa++)= *(lcpb++);} + + +#define VECADD(v1,v2,v3) {*(v1)= *(v2) + *(v3); *(v1+1)= *(v2+1) + *(v3+1); *(v1+2)= *(v2+2) + *(v3+2);} +#define VECSUB(v1,v2,v3) {*(v1)= *(v2) - *(v3); *(v1+1)= *(v2+1) - *(v3+1); *(v1+2)= *(v2+2) - *(v3+2);} +#define VECADDFAC(v1,v2,v3,fac) {*(v1)= *(v2) + *(v3)*(fac); *(v1+1)= *(v2+1) + *(v3+1)*(fac); *(v1+2)= *(v2+2) + *(v3+2)*(fac);} + +#define INPR(v1, v2) ( (v1)[0]*(v2)[0] + (v1)[1]*(v2)[1] + (v1)[2]*(v2)[2] ) + + +/* some misc stuff.... */ +#define CLAMP(a, b, c) if((a)<(b)) (a)=(b); else if((a)>(c)) (a)=(c) +#define CLAMPIS(a, b, c) ((a)<(b) ? (b) : (a)>(c) ? (c) : (a)) +#define CLAMPTEST(a, b, c) if((b)<(c)) {CLAMP(a, b, c);} else {CLAMP(a, c, b);} + +#define IS_EQ(a,b) ((fabs((double)(a)-(b)) >= (double) FLT_EPSILON) ? 0 : 1) + +#define IS_EQT(a, b, c) ((a > b)? (((a-b) <= c)? 1:0) : ((((b-a) <= c)? 1:0))) +#define IN_RANGE(a, b, c) ((b < c)? ((bid.newid ) (a)= (void *)(a)->id.newid + +#define FORM MAKE_ID('F','O','R','M') +#define DDG1 MAKE_ID('3','D','G','1') +#define DDG2 MAKE_ID('3','D','G','2') +#define DDG3 MAKE_ID('3','D','G','3') +#define DDG4 MAKE_ID('3','D','G','4') + +#define GOUR MAKE_ID('G','O','U','R') + +#define BLEN MAKE_ID('B','L','E','N') +#define DER_ MAKE_ID('D','E','R','_') +#define V100 MAKE_ID('V','1','0','0') + +#define DATA MAKE_ID('D','A','T','A') +#define GLOB MAKE_ID('G','L','O','B') +#define IMAG MAKE_ID('I','M','A','G') + +#define DNA1 MAKE_ID('D','N','A','1') +#define TEST MAKE_ID('T','E','S','T') +#define REND MAKE_ID('R','E','N','D') +#define USER MAKE_ID('U','S','E','R') + +#define ENDB MAKE_ID('E','N','D','B') + + +/* This one rotates the bytes in an int */ +#define SWITCH_INT(a) { \ + char s_i, *p_i; \ + p_i= (char *)&(a); \ + s_i=p_i[0]; p_i[0]=p_i[3]; p_i[3]=s_i; \ + s_i=p_i[1]; p_i[1]=p_i[2]; p_i[2]=s_i; } + +#define SWITCH_SHORT(a) { \ + char s_i, *p_i; \ + p_i= (char *)&(a); \ + s_i=p_i[0]; p_i[0]=p_i[1]; p_i[1]=s_i; } + + +/* Bit operations */ +#define BTST(a,b) ( ( (a) & 1<<(b) )!=0 ) +#define BSET(a,b) ( (a) | 1<<(b) ) +#define BCLR(a,b) ( (a) & ~(1<<(b)) ) +/* bit-row */ +#define BROW(min, max) (((max)>=31? 0xFFFFFFFF: (1<<(max+1))-1) - ((min)? ((1<<(min))-1):0) ) + + +#ifdef GS +#undef GS +#endif +#define GS(a) (*((short *)(a))) + +#endif + diff --git a/source/blender/blenkernel/BKE_verse.h b/source/blender/blenkernel/BKE_verse.h new file mode 100644 index 00000000000..aba42302364 --- /dev/null +++ b/source/blender/blenkernel/BKE_verse.h @@ -0,0 +1,586 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributor(s): Jiri Hnidek. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* #define WITH_VERSE */ + +#ifndef BKE_VERSE_H +#define BKE_VERSE_H + +#include "DNA_listBase.h" +#include "BLI_dynamiclist.h" + +#include "verse.h" +#include "verse_ms.h" + +struct VNode; +struct VerseEdge; + +/* + * Verse Edge Hash (similar to edit edge hash) + */ +#define VEDHASHSIZE (512*512) +#define VEDHASH(a, b) ((a1 is 3D bitmap */ + /* blender internals */ + uint16 t_width; /* = (width/VN_B_TILE_SIZE + 1)*VN_B_TILE_SIZE */ + uint16 t_height; /* = (height/VN_B_TILE_SIZE + 1)*VN_B_TILE_SIZE */ + void *image; /* pointer at image */ + /* client dependent methods */ + void (*post_bitmap_dimension_set)(struct VNode *vnode); + void (*post_bitmap_layer_create)(struct VBitmapLayer *vblayer); + void (*post_bitmap_layer_destroy)(struct VBitmapLayer *vblayer); + void (*post_bitmap_tile_set)(struct VBitmapLayer *vblayer, unsigned int xs, unsigned int ys); +}VBitmapData; + +/* + * data of geometry node + */ +typedef struct VGeomData { + struct DynamicList layers; /* dynamic list with access array of Layers */ + struct VLink *vlink; /* pointer at VerseLink connecting object node and geom node */ + struct ListBase queue; /* queue of our layers waiting for receiving from verse server */ + void *mesh; /* pointer at Mesh (object node) */ + void *editmesh; /* pointer at EditMesh (edit mode) */ + struct HashVerseEdge *hash; /* verse edge hash */ + struct ListBase edges; /* list of fake verse edges */ + /* client dependent methods */ + void (*post_vertex_create)(struct VerseVert *vvert); + void (*post_vertex_set_xyz)(struct VerseVert *vvert); + void (*post_vertex_delete)(struct VerseVert *vvert); + void (*post_vertex_free_constraint)(struct VerseVert *vvert); + void (*post_polygon_create)(struct VerseFace *vface); + void (*post_polygon_set_corner)(struct VerseFace *vface); + void (*post_polygon_delete)(struct VerseFace *vface); + void (*post_polygon_free_constraint)(struct VerseFace *vface); + void (*post_geometry_free_constraint)(struct VNode *vnode); + void (*post_polygon_set_uint8)(struct VerseFace *vface); +} VGeomData; + +/* + * data of object node + */ +typedef struct VObjectData { + struct DynamicList links; /* dynamic list with access array of links between other nodes */ + struct ListBase queue; /* queue of links waiting for sending and receiving from verse server */ + float pos[3]; /* position of object VerseNode */ + float quat[4]; /* rotation of object VerseNode stored in quat */ + float scale[3]; /* scale of object VerseNode */ + void *object; /* pointer at object */ + short flag; /* flag: POS_RECEIVE_READY, ROT_RECEIVE_READY. SCALE_RECEIVE_READY */ + /* client dependent methods */ +/* void (*post_transform)(struct VNode *vnode);*/ + void (*post_transform_pos)(struct VNode *vnode); + void (*post_transform_rot)(struct VNode *vnode); + void (*post_transform_scale)(struct VNode *vnode); + void (*post_object_free_constraint)(struct VNode *vnode); +} VObjectData; + +/* + * Verse Tag + */ +typedef struct VTag { + struct VTag *next, *prev; + /* verse data*/ + struct VTagGroup *vtaggroup; /* pointer at Verse Tag Group */ + uint16 id; /* id of this tag */ + char *name; /* name of this tag*/ + VNTagType type; /* type: VN_TAG_BOOLEAN, VN_TAG_UINT32, VN_TAG_REAL64, VN_TAG_REAL64_VEC3, + VN_TAG_LINK, VN_TAG_ANIMATION, VN_TAG_BLOB */ + VNTag *tag; /* pointer at value (enum: vboolean, vuint32, vreal64, vstring, + vreal64_vec3, vlink, vanimation, vblob)*/ + /* blender internals */ + void *value; /* pointer at blender value */ +} VTag; + +/* + * Verse Tag Group (verse tags are grouped in tag groups) + */ +typedef struct VTagGroup { + struct VTagGroup *next, *prev; + /* verse data*/ + struct VNode *vnode; /* pointer at Verse Node */ + uint16 id; /* id of this tag group */ + char *name; /* name of this tag group */ + /* blender internals */ + struct DynamicList tags; /* dynamic list with access array containing tags */ + struct ListBase queue; /* list of tags waiting for receiving from verse server */ + /* client dependent methods */ + void (*post_tag_change)(struct VTag *vatg); + void (*post_taggroup_create)(struct VTagGroup *vtaggroup); +} VTagGroup; + + /* + * Verse Method Group + */ +typedef struct VMethodGroup +{ + struct VMethodGroup *next, *prev; + uint16 group_id; + char name[16]; + struct ListBase methods; +} VMethodGroup; + +/* + * Verse Method + */ +typedef struct VMethod +{ + struct VMethod *next, *prev; + uint16 id; + char name[500]; + uint8 param_count; + VNOParamType *param_type; + char **param_name; +} VMethod; + +/* + * Verse Node + */ +typedef struct VNode { + struct VNode *next, *prev; + /* verse data*/ + struct VerseSession *session; /* session pointer */ + VNodeID id; /* node id */ + VNodeID owner_id; /* owner's id of this node */ + char *name; /* name of this node */ + uint32 type; /* type of node (V_NT_OBJECT, V_NT_GEOMETRY, V_NT_BITMAP) */ + /* blender internals */ + char flag; /* flags: NODE_SENT, NODE_RECEIVED, NODE_DELTED, NODE_OBSOLETE */ + struct DynamicList taggroups; /* dynamic list with access array of taggroups */ + struct ListBase methodgroups; /* method groups */ + struct ListBase queue; /* list of taggroups waiting for receiving from verse server */ + void *data; /* generic pointer at some data (VObjectData, VGeomData, ...) */ + int counter; /* counter of verse link pointing at this vnode (vlink->target) */ + /* client dependent methods */ + void (*post_node_create)(struct VNode *vnode); + void (*post_node_destroy)(struct VNode *vnode); + void (*post_node_name_set)(struct VNode *vnode); +#ifdef VERSECHAT + /* verse chat */ + int chat_flag; /* CHAT_LOGGED, CHAT_NOTLOGGED */ +#endif +} VNode; + + +/* + * Verse Session: verse client can be connected to several verse servers + * it is neccessary to store some information about each session + */ +typedef struct VerseSession { + struct VerseSession *next, *prev; + /* verse data */ + VSession *vsession; /* pointer at VSeesion (verse.h) */ + uint32 avatar; /* id of avatar */ + char *address; /* string containg IP/domain name of verse server and number of port */ + void *connection; /* no clue */ + uint8 *host_id; /* no clue */ + /* blender internals */ + short flag; /* flag: VERSE_CONNECTING, VERSE_CONNECTED */ + DynamicList nodes; /* list of verse nodes */ + ListBase queue; /* list of nodes waiting for sending to verse server */ + unsigned int counter; /* count of events, when connection wasn't accepted */ + /* client dependent methods */ + void (*post_connect_accept)(struct VerseSession *session); + void (*post_connect_terminated)(struct VerseSession *session); + void (*post_connect_update)(struct VerseSession *session); +} VerseSession; + +typedef struct VerseServer { + struct VerseServer *next, *prev; + char *name; /* human-readable server name */ + char *ip; /* string containing IP/domain name of verse server and number of port */ + short flag; /* flag: VERSE_CONNECTING, VERSE_CONNECTED */ + struct VerseSession *session; /* pointer to related session */ +} VerseServer; +/* + * list of post callback functions + */ +typedef struct PostCallbackFunction { + void (*function)(void *arg); + void *param; +} PostCallbackFunction; + +/* VerseSession->flag */ +#define VERSE_CONNECTING 1 +#define VERSE_CONNECTED 2 +#define VERSE_AUTOSUBSCRIBE 4 + +/* max VerseSession->counter value */ +#define MAX_UNCONNECTED_EVENTS 100 + +/* VNode flags */ +#define NODE_SENT 1 +#define NODE_RECEIVED 2 +#define NODE_DELTED 4 +#define NODE_OBSOLETE 8 + +#ifdef VERSECHAT +#define CHAT_NOTLOGGED 0 +#define CHAT_LOGGED 1 +#endif + +/* VLayer flags */ +#define LAYER_SENT 1 +#define LAYER_RECEIVED 2 +#define LAYER_DELETED 4 +#define LAYER_OBSOLETE 8 + +/* VLink->flag */ +#define LINK_SEND_READY 1 + +/* VObjectData->flag */ +#define POS_RECEIVE_READY 1 +#define ROT_RECEIVE_READY 2 +#define SCALE_RECEIVE_READY 4 +#define POS_SEND_READY 8 +#define ROT_SEND_READY 16 +#define SCALE_SEND_READY 32 + +/* VLayer->content */ +#define VERTEX_LAYER 0 +#define POLYGON_LAYER 1 + +/* VerseVert->flag */ +#define VERT_DELETED 1 /* vertex delete command was received from verse server */ +#define VERT_RECEIVED 2 /* VerseVert was received from verse server (is not in sending queue) */ +#define VERT_LOCKED 4 /* VerseVert is ready to send local position to verse server */ +#define VERT_POS_OBSOLETE 8 /* position of vertex was changed during sending to verse server */ +#define VERT_OBSOLETE 16 /* vertex delete command was sent to verse server; it means, that + * no information related to this vertex shoudln't be sent to verse + * until verse vertex is completely deleted ... then this vertex id + * can be reused again for new vertex */ + +/* VerseFace->flag */ +#define FACE_SEND_READY 1 /* VerseFace is ready for sending to verse server */ +#define FACE_RECEIVED 2 /* VerseFace was received from verse server */ +#define FACE_SENT 4 /* VerseFace was sent to verse server and we expect receiving from verse server */ +#define FACE_DELETED 8 /* delete command was sent to verse server */ +#define FACE_CHANGED 16 /* VerseFace was only changed not created */ +#define FACE_OBSOLETE 32 /* VerseFace was changed during sending to verse server */ + +/* Queue type */ +#define VERSE_NODE 1 +#define VERSE_LINK 2 +#define VERSE_LAYER 3 +#define VERSE_VERT 4 +#define VERSE_FACE 5 + +#define VERSE_TAG 6 +#define VERSE_TAG_GROUP 7 + +#define VERSE_VERT_UINT32 8 +#define VERSE_VERT_REAL32 9 +#define VERSE_VERT_VEC_REAL32 10 + +#define VERSE_FACE_UINT8 11 +#define VERSE_FACE_UINT32 12 +#define VERSE_FACE_REAL32 13 +#define VERSE_FACE_QUAT_UINT32 14 +#define VERSE_FACE_QUAT_REAL32 15 + +/* Verse Bitmap Layer flags */ +#define VBLAYER_SUBSCRIBED 1 + +/* function prototypes */ + +/* functions from verse_session.c */ +void set_verse_session_callbacks(void); +struct VerseSession *versesession_from_vsession(VSession *vsession); +struct VerseSession *current_verse_session(void); +struct VerseSession *create_verse_session(const char *name, const char *pass, const char *address, uint8 *expected_key); +void free_verse_session(struct VerseSession *session); +void b_verse_update(void); +void b_verse_ms_get(void); +void b_verse_connect(char *address); +void end_verse_session(struct VerseSession *session); +void end_all_verse_sessions(void); + +/* functions from verse_node.c */ +void send_verse_tag(struct VTag *vtag); +void send_verse_taggroup(struct VTagGroup *vtaggroup); +void send_verse_node(struct VNode *vnode); +void free_verse_node_data(struct VNode *vnode); +void free_verse_node(struct VNode *vnode); +struct VNode* lookup_vnode(VerseSession *session, VNodeID node_id); +struct VNode* create_verse_node(VerseSession *session, VNodeID node_id, uint8 type, VNodeID owner_id); +void set_node_callbacks(void); + +/* functions from verse_object_node.c */ +struct VLink *find_unsent_parent_vlink(struct VerseSession *session, struct VNode *vnode); +struct VLink *find_unsent_child_vlink(struct VerseSession *session, struct VNode *vnode); +struct VLink *create_verse_link(VerseSession *session, struct VNode *source, struct VNode *target, uint16 link_id, uint32 target_id, const char *label); +void send_verse_object_position(struct VNode *vnode); +void send_verse_object_rotation(struct VNode *vnode); +void send_verse_object_scale(struct VNode *vnode); +void send_verse_link(struct VLink *vlink); + +void free_object_data(struct VNode *vnode); +void set_object_callbacks(void); +struct VObjectData *create_object_data(void); + + +/* functions from verse_method.c */ +void free_verse_methodgroup(VMethodGroup *vmg); +#ifdef VERSECHAT +void send_say(const char *chan, const char *utter); +void send_login(struct VNode *vnode); +void send_logout(struct VNode *vnode); +void send_join(struct VNode *vnode, const char *chan); +void send_leave(struct VNode *vnode, const char *chan); +#endif +void set_method_callbacks(void); + +/* functions from verse_geometry_node.c */ +struct VerseFace* create_verse_face(struct VLayer *vlayer, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3); +struct VerseVert* create_verse_vertex(struct VLayer *vlayer, uint32 vertex_id, real32 x, real32 y, real32 z); +struct VLayer *create_verse_layer(struct VNode *vnode, VLayerID layer_id, const char *name, VNGLayerType type, uint32 def_integer, real64 def_real); +struct VGeomData *create_geometry_data(void); + +void send_verse_layer(struct VLayer *vlayer); + +void send_verse_face_corner_quat_real32(struct quat_real32_item *item, short type); +void send_verse_face_corner_quat_uint32(struct quat_uint32_item *item, short type); +void send_verse_face_real32(struct real32_item *item, short type); +void send_verse_face_uint32(struct uint32_item *item, short type); +void send_verse_face_uint8(struct uint8_item *item, short type); + +void send_verse_vert_vec_real32(struct vec_real32_item *item, short type); +void send_verse_vert_real32(struct real32_item *item, short type); +void send_verse_vert_uint32(struct uint32_item *item, short type); + +void send_verse_vertex_delete(struct VerseVert *vvert); +void send_verse_vertex(struct VerseVert *vvert); +void send_verse_face_delete(struct VerseFace *vface); + +void destroy_geometry(struct VNode *vnode); + +struct VLayer* find_verse_layer_type(struct VGeomData *geom, short content); +void add_item_to_send_queue(struct ListBase *lb, void *item, short type); +void free_geom_data(struct VNode *vnode); +void set_geometry_callbacks(void); + +/* functions prototypes from verse_bitmap.c */ +void set_bitmap_callbacks(void); +void free_bitmap_layer_data(struct VBitmapLayer *vblayer); +struct VBitmapLayer *create_bitmap_layer(struct VNode *vnode, VLayerID layer_id, const char *name, VNBLayerType type); +void free_bitmap_node_data(struct VNode *vnode); +struct VBitmapData *create_bitmap_data(void); + +#endif diff --git a/source/blender/blenkernel/BKE_world.h b/source/blender/blenkernel/BKE_world.h new file mode 100644 index 00000000000..b51eaff420c --- /dev/null +++ b/source/blender/blenkernel/BKE_world.h @@ -0,0 +1,45 @@ +/** + * blenlib/BKE_world.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_WORLD_H +#define BKE_WORLD_H + +struct World; + +void free_world(struct World *sc); +struct World *add_world(char *name); +struct World *copy_world(struct World *wrld); +void make_local_world(struct World *wrld); + +#endif + diff --git a/source/blender/blenkernel/BKE_writeavi.h b/source/blender/blenkernel/BKE_writeavi.h new file mode 100644 index 00000000000..6faa5f44878 --- /dev/null +++ b/source/blender/blenkernel/BKE_writeavi.h @@ -0,0 +1,62 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BKE_WRITEAVI_H +#define BKE_WRITEAVI_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* generic blender movie support, could move to own module */ + +struct RenderData; +void start_avi(struct RenderData *rd, int rectx, int recty); +void end_avi(void); +void append_avi(int frame, int *pixels, int rectx, int recty); +void makeavistring (struct RenderData *rd, char *string); + +typedef struct bMovieHandle { + void (*start_movie)(struct RenderData *rd, int rectx, int recty); + void (*append_movie)(int frame, int *pixels, int rectx, int recty); + void (*end_movie)(void); + int (*get_next_frame)(void); /* can be null */ +} bMovieHandle; + +bMovieHandle *BKE_get_movie_handle(int imtype); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/source/blender/blenkernel/BKE_writeffmpeg.h b/source/blender/blenkernel/BKE_writeffmpeg.h new file mode 100644 index 00000000000..13084e925e0 --- /dev/null +++ b/source/blender/blenkernel/BKE_writeffmpeg.h @@ -0,0 +1,76 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BKE_WRITEFFMPEG_H +#define BKE_WRITEFFMPEG_H + +#ifdef WITH_FFMPEG + +#ifdef __cplusplus +extern "C" { +#endif + +#define FFMPEG_MPEG1 0 +#define FFMPEG_MPEG2 1 +#define FFMPEG_MPEG4 2 +#define FFMPEG_AVI 3 +#define FFMPEG_MOV 4 +#define FFMPEG_DV 5 +#define FFMPEG_H264 6 +#define FFMPEG_XVID 7 + +#define FFMPEG_CODEC_MPEG1 0 +#define FFMPEG_CODEC_MPEG2 1 +#define FFMPEG_CODEC_MPEG4 2 +#define FFMPEG_CODEC_HUFFYUV 3 +#define FFMPEG_CODEC_DV 4 +#define FFMPEG_CODEC_H264 5 +#define FFMPEG_CODEC_XVID 6 + +#define FFMPEG_PRESET_NONE 0 +#define FFMPEG_PRESET_DVD 1 +#define FFMPEG_PRESET_SVCD 2 +#define FFMPEG_PRESET_VCD 3 +#define FFMPEG_PRESET_DV 4 + +struct RenderData; + +extern void start_ffmpeg(struct RenderData *rd, int rectx, int recty); +extern void end_ffmpeg(void); +extern void append_ffmpeg(int frame, int *pixels, int rectx, int recty); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + diff --git a/source/blender/blenkernel/BKE_writeframeserver.h b/source/blender/blenkernel/BKE_writeframeserver.h new file mode 100644 index 00000000000..d8414e51f43 --- /dev/null +++ b/source/blender/blenkernel/BKE_writeframeserver.h @@ -0,0 +1,50 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BKE_WRITEFRAMESERVER_H +#define BKE_WRITEFRAMESERVER_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct RenderData; + +extern void start_frameserver(struct RenderData *rd, int rectx, int recty); +extern void end_frameserver(void); +extern void append_frameserver(int frame, int *pixels, int rectx, int recty); +extern int frameserver_loop(); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt new file mode 100644 index 00000000000..c0776583a04 --- /dev/null +++ b/source/blender/blenkernel/CMakeLists.txt @@ -0,0 +1,77 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +FILE(GLOB SRC intern/*.c) + +SET(INC + . ../../../intern/guardedalloc ../include ../blenlib ../makesdna + ../python ../render/extern/include ../../../intern/decimation/extern + ../imbuf ../avi ../../../intern/elbeem/extern + ../../../intern/iksolver/extern ../blenloader ../quicktime + ../../../intern/bmfont + ../nodes + ${SDL_INC} + ${ZLIB_INC} +) + +IF(WITH_VERSE) + ADD_DEFINITIONS(-DWITH_VERSE) + SET(INC ${INC} ${VERSE_INC}) +ENDIF(WITH_VERSE) + +IF(WITH_OPENEXR) + ADD_DEFINITIONS(-DWITH_OPENEXR) +ENDIF(WITH_OPENEXR) + +IF(WITH_QUICKTIME) + SET(INC ${INC} ${QUICKTIME_INC}) + ADD_DEFINITIONS(-DWITH_QUICKTIME) +ENDIF(WITH_QUICKTIME) + +IF(WITH_FFMPEG) + SET(INC ${INC} ${FFMPEG_INC}) + ADD_DEFINITIONS(-DWITH_FFMPEG) +ENDIF(WITH_FFMPEG) + +IF(WITH_PLAYER) + SUBDIRS(bad_level_call_stubs) +ENDIF(WITH_PLAYER) + +ADD_DEFINITIONS(-DWITH_CCGSUBSURF) + +BLENDERLIB(bf_blenkernel "${SRC}" "${INC}") + +IF(WITH_VERSE) + ADD_DEPENDENCIES(bf_blenkernel mkprot verse) +ENDIF(WITH_VERSE) + +IF(WITH_INTERNATIONAL) + ADD_DEFINITIONS(-DWITH_FREETYPE2) +ENDIF(WITH_INTERNATIONAL) + diff --git a/source/blender/blenkernel/Makefile b/source/blender/blenkernel/Makefile new file mode 100644 index 00000000000..239941ec59b --- /dev/null +++ b/source/blender/blenkernel/Makefile @@ -0,0 +1,37 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# Bounces make to subdirectories. + +SOURCEDIR = source/blender/blenkernel +DIRS = intern bad_level_call_stubs + +include nan_subdirs.mk diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript new file mode 100644 index 00000000000..9ecc76046c7 --- /dev/null +++ b/source/blender/blenkernel/SConscript @@ -0,0 +1,47 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.c') + +incs = '. #/intern/guardedalloc ../include ../blenlib ../makesdna' +incs += ' ../python ../render/extern/include #/intern/decimation/extern' +incs += ' ../imbuf ../avi #/intern/elbeem/extern ../nodes' +incs += ' #/intern/iksolver/extern ../blenloader ../quicktime' +incs += ' #/intern/bmfont' + +incs += ' ' + env['BF_OPENGL_INC'] +incs += ' ' + env['BF_ZLIB_INC'] +incs += ' ' + env['BF_SDL_INC'] + +defs = '' + +if env['WITH_BF_INTERNATIONAL']: + defs += 'WITH_FREETYPE2' + +if env['WITH_BF_VERSE']: + defs += ' WITH_VERSE' + incs += ' ' + env['BF_VERSE_INCLUDE'] + +if env['WITH_BF_VERSE']: + defs += ' WITH_VERSE' + +if env['WITH_BF_OPENEXR'] == 1: + defs += ' WITH_OPENEXR' + +if env['WITH_BF_DDS'] == 1: + defs += ' WITH_DDS' + +if env['WITH_BF_FFMPEG'] == 1: + defs += ' WITH_FFMPEG' + incs += ' ' + env['BF_FFMPEG_INC'] + +if env['WITH_BF_QUICKTIME'] == 1: + defs += ' WITH_QUICKTIME' + incs += ' ' + env['BF_QUICKTIME_INC'] + +defs += ' WITH_CCGSUBSURF' + +if env['WITH_BF_PLAYER']: + SConscript(['bad_level_call_stubs/SConscript']) + +env.BlenderLib ( libname = 'bf_blenkernel', sources = sources, includes = Split(incs), defines = Split(defs), libtype=['core','player'], priority = [65, 20] ) diff --git a/source/blender/blenkernel/bad_level_call_stubs/CMakeLists.txt b/source/blender/blenkernel/bad_level_call_stubs/CMakeLists.txt new file mode 100644 index 00000000000..67463f901c6 --- /dev/null +++ b/source/blender/blenkernel/bad_level_call_stubs/CMakeLists.txt @@ -0,0 +1,46 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +FILE(GLOB SRC stubs.c) + +SET(INC + . + .. + ../../render/extern/include + ../../../intern/iksolver/extern + ../../blenlib + ../../include + ../../makesdna +) + +IF(WITH_INTERNATIONAL) + ADD_DEFINITIONS(-DWITH_FREETYPE2) +ENDIF(WITH_INTERNATIONAL) + +BLENDERLIB_NOLIST(blenkernel_blc "${SRC}" "${INC}") diff --git a/source/blender/blenkernel/bad_level_call_stubs/Makefile b/source/blender/blenkernel/bad_level_call_stubs/Makefile new file mode 100644 index 00000000000..1d4db1037ea --- /dev/null +++ b/source/blender/blenkernel/bad_level_call_stubs/Makefile @@ -0,0 +1,51 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = blenkernel_blc +DIR = $(OCGDIR)/blender/blenkernel/$(LIBNAME) + +include nan_compile.mk + +CFLAGS += $(LEVEL_2_C_WARNINGS) +CFLAGS += $(FIX_STUBS_WARNINGS) + +CPPFLAGS += $(OGL_CPPFLAGS) +CPPFLAGS += -I../../makesdna +CPPFLAGS += -I../../include +CPPFLAGS += -I../../blenlib +CPPFLAGS += -I../../render/extern/include +CPPFLAGS += -I$(NAN_IKSOLVER)/include + +# path to our own external headerfiles +CPPFLAGS += -I.. + diff --git a/source/blender/blenkernel/bad_level_call_stubs/SConscript b/source/blender/blenkernel/bad_level_call_stubs/SConscript new file mode 100644 index 00000000000..955a989c9f9 --- /dev/null +++ b/source/blender/blenkernel/bad_level_call_stubs/SConscript @@ -0,0 +1,14 @@ +#!/usr/bin/python +Import ('env') + +sources = 'stubs.c' + +incs = '. .. ../../render/extern/include' +incs += ' #/intern/iksolver/extern ../../blenlib' +incs += ' ../../include ../../makesdna' + +defs = '' +if env['WITH_BF_INTERNATIONAL']: + defs += 'WITH_FREETYPE2' + +env.BlenderLib ('blenkernel_blc', sources = Split(sources), includes=Split(incs), defines=Split(defs), libtype='player',priority=225 ) diff --git a/source/blender/blenkernel/bad_level_call_stubs/stubs.c b/source/blender/blenkernel/bad_level_call_stubs/stubs.c new file mode 100644 index 00000000000..63bc23a71bf --- /dev/null +++ b/source/blender/blenkernel/bad_level_call_stubs/stubs.c @@ -0,0 +1,338 @@ + +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * BKE_bad_level_calls function stubs + */ + +#include + +#include "BKE_bad_level_calls.h" +#include "BLI_blenlib.h" +#include "BPI_script.h" +#include "DNA_texture_types.h" +#include "DNA_material_types.h" +#include "DNA_node_types.h" +#include "DNA_scene_types.h" + +#include "RE_render_ext.h" +#include "RE_shader_ext.h" +#include "RE_pipeline.h" + +int winqueue_break= 0; + +char bprogname[1]; + +struct IpoCurve; +struct FluidsimSettings; +struct Render; +struct RenderResult; +struct Object; +struct bPythonConstraint; +struct bConstraintOb; +struct bConstraintTarget; +struct ListBase; + +char *getIpoCurveName( struct IpoCurve * icu ); +void insert_vert_icu(struct IpoCurve *icu, float x, float y, short fast); +struct IpoCurve *verify_ipocurve(struct ID *id, short a, char *b, char *d, int e); +void elbeemDebugOut(char *msg); +void fluidsimSettingsFree(struct FluidsimSettings* sb); +void fluidsimSettingsCopy(struct FluidsimSettings* sb); + + +/* readfile.c */ + /* struct SpaceButs; */ +void set_rects_butspace(struct SpaceButs *buts){} + /* struct SpaceImaSel; */ +void check_imasel_copy(struct SpaceImaSel *simasel){} + /* struct ScrArea; */ +void unlink_screen(struct bScreen *sc){} +void freeAllRad(void){} +void free_editText(void){} +void free_editArmature(void){} +void free_vertexpaint(void){} + +char *getIpoCurveName( struct IpoCurve * icu ) +{ + return 0; +} + +void insert_vert_icu(struct IpoCurve *icu, float x, float y, short fast) +{ +} + + +struct IpoCurve *verify_ipocurve(struct ID *id, short a, char *b, char *d, int e) +{ + return 0; +} + + +void setscreen(struct bScreen *sc){} +void force_draw_all(int header){} + /* otherwise the WHILE_SEQ doesn't work */ + /* struct Sequence; */ + +/* MAART: added "seqar = 0; totseq = 0" because the loader will crash without it. */ +void build_seqar(struct ListBase *seqbase, struct Sequence ***seqar, int *totseq) +{ + *seqar = 0; + *totseq = 0; +} + +/* blender.c */ +void mainqenter (unsigned short event, short val){} + +void BPY_do_pyscript(ID *id, short int event){} +void BPY_clear_script(Script *script){} +void BPY_free_compiled_text(struct Text *text){} +void BPY_pydriver_update(void){} +float BPY_pydriver_eval(struct IpoDriver *driver) +{ + return 0; +} +/* depsgraph.c: */ +struct Object **BPY_pydriver_get_objects(struct IpoDriver *driver) +{ + return 0; +} +int BPY_button_eval(char *expr, double *value) +{ + return 0; +} + +/* PyConstraints - BPY_interface.c */ +void BPY_pyconstraint_eval(struct bPythonConstraint *con, struct bConstraintOb *cob, struct ListBase *targets) +{ +} +void BPY_pyconstraint_target(struct bPythonConstraint *con, struct bConstraintTarget *ct) +{ +} + + +/* writefile.c */ + /* struct Oops; */ +void free_oops(struct Oops *oops){} +void exit_posemode(int freedata){} +void error(char *str, ...){} + +/* anim.c */ +ListBase editNurb; + +void waitcursor(int val){} +void allqueue(unsigned short event, short val){} +#define REDRAWVIEW3D 0x4010 +Material defmaterial; + +/* exotic.c */ +void load_editMesh(void){} +void make_editMesh(void){} +void free_editMesh(struct EditMesh *em){} +void docenter_new(void){} +int saveover(char *str){ return 0;} + +/* image.c */ +#include "DNA_image_types.h" +void free_realtime_image(Image *ima){} // has to become a callback, opengl stuff + +/* ipo.c */ +void copy_view3d_lock(short val){} // was a hack, to make scene layer ipo's possible + +/* library.c */ +void allspace(unsigned short event, short val){} +#define OOPS_TEST 2 + +/* mball.c */ +ListBase editelems; + +/* object.c */ +void BPY_free_scriptlink(ScriptLink *slink){} +void BPY_copy_scriptlink(ScriptLink *scriptlink){} +float *give_cursor(void){ return 0;} // become a callback or argument + + +/* packedFile.c */ +short pupmenu(char *instr){ return 0;} // will be general callback + +/* sca.c */ +#define LEFTMOUSE 0x001 // because of mouse sensor + +/* scene.c */ +#include "DNA_sequence_types.h" +void free_editing(struct Editing *ed){} // scenes and sequences problem... +void BPY_do_all_scripts (short int event){} + +/* IKsolver stubs */ +#include "IK_solver.h" + +IK_Segment *IK_CreateSegment(int flag) { return 0; } +void IK_FreeSegment(IK_Segment *seg) {} + +void IK_SetParent(IK_Segment *seg, IK_Segment *parent) {} +void IK_SetTransform(IK_Segment *seg, float start[3], float rest_basis[][3], float basis[][3], float length) {} +void IK_GetBasisChange(IK_Segment *seg, float basis_change[][3]) {} +void IK_GetTranslationChange(IK_Segment *seg, float *translation_change) {}; +void IK_SetLimit(IK_Segment *seg, IK_SegmentAxis axis, float lower, float upper) {}; +void IK_SetStiffness(IK_Segment *seg, IK_SegmentAxis axis, float stiffness) {}; + +IK_Solver *IK_CreateSolver(IK_Segment *root) { return 0; } +void IK_FreeSolver(IK_Solver *solver) {}; + +void IK_SolverAddGoal(IK_Solver *solver, IK_Segment *tip, float goal[3], float weight) {} +void IK_SolverAddGoalOrientation(IK_Solver *solver, IK_Segment *tip, float goal[][3], float weight) {} +void IK_SolverSetPoleVectorConstraint(IK_Solver *solver, IK_Segment *tip, float goal[3], float polegoal[3], float poleangle, int getangle) {} +float IK_SolverGetPoleAngle(IK_Solver *solver) {} + +int IK_Solve(IK_Solver *solver, float tolerance, int max_iterations) { return 0; } + +/* exotic.c */ +int BPY_call_importloader(char *name) +{ + return 0; +} + + +/* texture.c */ +#define FLO 128 +#define INT 96 + + +char texstr[20][12]; /* buttons.c */ + +/* editsca.c */ +void make_unique_prop_names(char *str) {} + +/* DerivedMesh.c */ +void bglBegin(int mode) {} +void bglVertex3fv(float *vec) {} +void bglVertex3f(float x, float y, float z) {} +void bglEnd(void) {} + +/* booleanops.c */ +struct DerivedMesh *NewBooleanDerivedMesh(struct Object *ob, struct Object *ob_select, int int_op_type) { return 0; } + +// bobj read/write debug messages +void elbeemDebugOut(char *msg) {} +void fluidsimSettingsFree(struct FluidsimSettings* sb) {} +void fluidsimSettingsCopy(struct FluidsimSettings* sb) {} + +/*new render funcs */ +int externtex(struct MTex *mtex, float *vec, float *tin, float *tr, float *tg, float *tb, float *ta) { return 0; } + +void RE_FreeRenderResult(struct RenderResult *rr) {} +void RE_GetResultImage(struct Render *re, struct RenderResult *rr) {} +struct RenderResult *RE_MultilayerConvert(void *exrhandle, int rectx, int recty){return NULL;} +struct Render *RE_GetRender(const char *name) {return (struct Render *)NULL;} +struct RenderResult *RE_GetResult(Render *re) {return (struct RenderResult *)NULL;} +float *RE_RenderLayerGetPass(RenderLayer *rl, int passtype) {return NULL;} +float RE_filter_value(int type, float x) {return 0.0f;} +struct RenderLayer *RE_GetRenderLayer(RenderResult *rr, const char *name) {return (struct RenderLayer *)NULL;} +void RE_Database_Free (struct Render *re) {} +void RE_FreeRender(Render *re) {} +void RE_shade_external(Render *re, ShadeInput *shi, ShadeResult *shr) {} +void RE_DataBase_GetView(Render *re, float mat[][4]) {} +struct Render *RE_NewRender(const char *name) {return (struct Render *)NULL;} +void RE_Database_Baking(struct Render *re, struct Scene *scene, int make_faces) {}; + + +/* node_composite.c */ +void RE_zbuf_accumulate_vecblur(struct NodeBlurData *nd, int xsize, int ysize, float *newrect, float *imgrect, float *vecbufrect, float *zbufrect) {} + +int multitex_ext(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexResult *texres) +{ + return 1969; +} + +/* verse */ + +void post_vertex_create(struct VerseVert *vvert) {} +void post_vertex_set_xyz(struct VerseVert *vvert) {} +void post_vertex_delete(struct VerseVert *vvert) {} +void post_vertex_free_constraint(struct VerseVert *vvert) {} +void post_polygon_create(struct VerseFace *vface) {} +void post_polygon_set_corner(struct VerseFace *vface) {} +void post_polygon_delete(struct VerseFace *vface) {} +void post_polygon_free_constraint(struct VerseFace *vface) {} +void post_polygon_set_uint8(struct VerseFace *vface) {} +void post_node_create(struct VNode *vnode) {} +void post_node_destroy(struct VNode *vnode) {} +void post_node_name_set(struct VNode *vnode) {} +void post_tag_change(struct VTag *vtag) {} +void post_taggroup_create(struct VTagGroup *vtaggroup) {} +char *verse_client_name(void) { return NULL; } +void post_transform(struct VNode *vnode) {} +void post_transform_pos(struct VNode *vnode) {} +void post_transform_rot(struct VNode *vnode) {} +void post_transform_scale(struct VNode *vnode) {} +void post_object_free_constraint(struct VNode *vnode) {} +void post_link_set(struct VLink *vlink) {} +void post_link_destroy(struct VLink *vlink) {} +void post_connect_accept(struct VerseSession *session) {} +void post_connect_terminated(struct VerseSession *session) {} +void post_connect_update(struct VerseSession *session) {} +void add_screenhandler(struct bScreen *sc, short eventcode, short val) {} +void post_bitmap_dimension_set(struct VNode *vnode) {} +void post_bitmap_layer_create(struct VBitmapLayer *vblayer) {} +void post_bitmap_layer_destroy(struct VBitmapLayer *vblayer) {} +void post_bitmap_tile_set(struct VBitmapLayer *vblayer, unsigned int xs, unsigned int ys) {} +void create_meshdata_from_geom_node(struct Mesh *me, struct VNode *vnode) {} +void post_geometry_free_constraint(struct VNode *vnode) {} +void post_layer_create(struct VLayer *vlayer) {} +void post_layer_destroy(struct VLayer *vlayer) {} +void post_server_add(void) {} + /* Multires/sculpt stubs */ +struct MultiresLevel *multires_level_n(struct Multires *mr, int n) {return NULL;} +void multires_free(struct Multires *mr) {} +void multires_set_level(struct Object *ob, struct Mesh *me, const int render) {} +void multires_update_levels(struct Mesh *me, const int render) {} +void multires_calc_level_maps(struct MultiresLevel *lvl) {} +struct Multires *multires_copy(struct Multires *orig) {return NULL;} +void sculptmode_init(struct Scene *sce) {} +void sculptmode_free_all(struct Scene *sce) {} + +/* zbuf.c stub */ +void antialias_tagbuf(int xsize, int ysize, char *rectmove) {} + +/* imagetexture.c stub */ +void ibuf_sample(struct ImBuf *ibuf, float fx, float fy, float dx, float dy, float *result) {} + +void update_for_newframe() {} + +struct FileList; +void BIF_filelist_freelib(struct FileList* filelist) {}; + +/* edittime.c stub */ +TimeMarker *get_frame_marker(int frame){return 0;}; + +/* modifier.c stub */ +void harmonic_coordinates_bind(struct MeshDeformModifierData *mmd, + float (*vertexcos)[3], int totvert, float cagemat[][4]) {} + diff --git a/source/blender/blenkernel/depsgraph_private.h b/source/blender/blenkernel/depsgraph_private.h new file mode 100644 index 00000000000..15c06b8ae79 --- /dev/null +++ b/source/blender/blenkernel/depsgraph_private.h @@ -0,0 +1,133 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DEPSGRAPH_PRIVATE +#define DEPSGRAPH_PRIVATE + +#include "BKE_depsgraph.h" +#include "DNA_constraint_types.h" +#include "BKE_constraint.h" + + +#define DEPSX 5.0f +#define DEPSY 1.8f + +#define DAGQUEUEALLOC 50 + +enum { + DAG_WHITE = 0, + DAG_GRAY = 1, + DAG_BLACK = 2 +}; + + + +typedef struct DagAdjList +{ + struct DagNode *node; + short type; + int count; // number of identical arcs + unsigned int lay; // for flushing redraw/rebuild events + struct DagAdjList *next; +} DagAdjList; + + +typedef struct DagNode +{ + int color; + short type; + float x, y, k; + void * ob; + void * first_ancestor; + int ancestor_count; + int lay; // accumulated layers of its relations + itself + int lasttime; // if lasttime != DagForest->time, this node was not evaluated yet for flushing + int BFS_dist; // BFS distance + int DFS_dist; // DFS distance + int DFS_dvtm; // DFS discovery time + int DFS_fntm; // DFS Finishing time + struct DagAdjList *child; + struct DagAdjList *parent; + struct DagNode *next; +} DagNode; + +typedef struct DagNodeQueueElem { + struct DagNode *node; + struct DagNodeQueueElem *next; +} DagNodeQueueElem; + +typedef struct DagNodeQueue +{ + DagNodeQueueElem *first; + DagNodeQueueElem *last; + int count; + int maxlevel; + struct DagNodeQueue *freenodes; +} DagNodeQueue; + +// forest as we may have more than one DAG unnconected +typedef struct DagForest +{ + ListBase DagNode; + int numNodes; + int is_acyclic; + int time; // for flushing/tagging, compare with node->lasttime +} DagForest; + + +// queue operations +DagNodeQueue * queue_create (int slots); +void queue_raz(DagNodeQueue *queue); +void push_queue(DagNodeQueue *queue, DagNode *node); +void push_stack(DagNodeQueue *queue, DagNode *node); +DagNode * pop_queue(DagNodeQueue *queue); +DagNode * get_top_node_queue(DagNodeQueue *queue); + +// Dag management +DagForest *getMainDag(void); +void setMainDag(DagForest *dag); +DagForest * dag_init(void); +DagNode * dag_find_node (DagForest *forest,void * fob); +DagNode * dag_add_node (DagForest *forest,void * fob); +DagNode * dag_get_node (DagForest *forest,void * fob); +DagNode * dag_get_sub_node (DagForest *forest,void * fob); +void dag_add_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel); + +void graph_bfs(void); + +DagNodeQueue * graph_dfs(void); + +void set_node_xy(DagNode *node, float x, float y); +void graph_print_queue(DagNodeQueue *nqueue); +void graph_print_queue_dist(DagNodeQueue *nqueue); +void graph_print_adj_list(void); + +int build_deps(short mask); + +#endif diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c new file mode 100644 index 00000000000..4e00e29029c --- /dev/null +++ b/source/blender/blenkernel/intern/CCGSubSurf.c @@ -0,0 +1,2294 @@ +/* $Id$ */ + +#include +#include +#include +#include + +#include "CCGSubSurf.h" + +/***/ + +typedef unsigned char byte; + +/***/ + +static int kHashSizes[] = { + 1, 3, 5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209, + 16411, 32771, 65537, 131101, 262147, 524309, 1048583, 2097169, + 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, 268435459 +}; + +typedef struct _EHEntry EHEntry; +struct _EHEntry { + EHEntry *next; + void *key; +}; +typedef struct _EHash { + EHEntry **buckets; + int numEntries, curSize, curSizeIdx; + + CCGAllocatorIFC allocatorIFC; + CCGAllocatorHDL allocator; +} EHash; + +#define EHASH_alloc(eh, nb) ((eh)->allocatorIFC.alloc((eh)->allocator, nb)) +#define EHASH_free(eh, ptr) ((eh)->allocatorIFC.free((eh)->allocator, ptr)) + +#define EHASH_hash(eh, item) (((unsigned long) (item))%((unsigned int) (eh)->curSize)) + +static EHash *_ehash_new(int estimatedNumEntries, CCGAllocatorIFC *allocatorIFC, CCGAllocatorHDL allocator) { + EHash *eh = allocatorIFC->alloc(allocator, sizeof(*eh)); + eh->allocatorIFC = *allocatorIFC; + eh->allocator = allocator; + eh->numEntries = 0; + eh->curSizeIdx = 0; + while (kHashSizes[eh->curSizeIdx]curSizeIdx++; + eh->curSize = kHashSizes[eh->curSizeIdx]; + eh->buckets = EHASH_alloc(eh, eh->curSize*sizeof(*eh->buckets)); + memset(eh->buckets, 0, eh->curSize*sizeof(*eh->buckets)); + + return eh; +} +typedef void (*EHEntryFreeFP)(EHEntry *, void *); +static void _ehash_free(EHash *eh, EHEntryFreeFP freeEntry, void *userData) { + int numBuckets = eh->curSize; + + while (numBuckets--) { + EHEntry *entry = eh->buckets[numBuckets]; + + while (entry) { + EHEntry *next = entry->next; + + freeEntry(entry, userData); + + entry = next; + } + } + + EHASH_free(eh, eh->buckets); + EHASH_free(eh, eh); +} + +static void _ehash_insert(EHash *eh, EHEntry *entry) { + int numBuckets = eh->curSize; + int hash = EHASH_hash(eh, entry->key); + entry->next = eh->buckets[hash]; + eh->buckets[hash] = entry; + eh->numEntries++; + + if (eh->numEntries > (numBuckets*3)) { + EHEntry **oldBuckets = eh->buckets; + eh->curSize = kHashSizes[++eh->curSizeIdx]; + + eh->buckets = EHASH_alloc(eh, eh->curSize*sizeof(*eh->buckets)); + memset(eh->buckets, 0, eh->curSize*sizeof(*eh->buckets)); + + while (numBuckets--) { + for (entry = oldBuckets[numBuckets]; entry;) { + EHEntry *next = entry->next; + + hash = EHASH_hash(eh, entry->key); + entry->next = eh->buckets[hash]; + eh->buckets[hash] = entry; + + entry = next; + } + } + + EHASH_free(eh, oldBuckets); + } +} + +static void *_ehash_lookupWithPrev(EHash *eh, void *key, void ***prevp_r) { + int hash = EHASH_hash(eh, key); + void **prevp = (void**) &eh->buckets[hash]; + EHEntry *entry; + + for (; (entry = *prevp); prevp = (void**) &entry->next) { + if (entry->key==key) { + *prevp_r = (void**) prevp; + return entry; + } + } + + return NULL; +} + +static void *_ehash_lookup(EHash *eh, void *key) { + int hash = EHASH_hash(eh, key); + EHEntry *entry; + + for (entry = eh->buckets[hash]; entry; entry = entry->next) + if (entry->key==key) + break; + + return entry; +} + +/**/ + +typedef struct _EHashIterator { + EHash *eh; + int curBucket; + EHEntry *curEntry; +} EHashIterator; + +static EHashIterator *_ehashIterator_new(EHash *eh) { + EHashIterator *ehi = EHASH_alloc(eh, sizeof(*ehi)); + ehi->eh = eh; + ehi->curEntry = NULL; + ehi->curBucket = -1; + while (!ehi->curEntry) { + ehi->curBucket++; + if (ehi->curBucket==ehi->eh->curSize) + break; + ehi->curEntry = ehi->eh->buckets[ehi->curBucket]; + } + return ehi; +} +static void _ehashIterator_free(EHashIterator *ehi) { + EHASH_free(ehi->eh, ehi); +} + +static void *_ehashIterator_getCurrent(EHashIterator *ehi) { + return ehi->curEntry; +} + +static void _ehashIterator_next(EHashIterator *ehi) { + if (ehi->curEntry) { + ehi->curEntry = ehi->curEntry->next; + while (!ehi->curEntry) { + ehi->curBucket++; + if (ehi->curBucket==ehi->eh->curSize) + break; + ehi->curEntry = ehi->eh->buckets[ehi->curBucket]; + } + } +} +static int _ehashIterator_isStopped(EHashIterator *ehi) { + return !ehi->curEntry; +} + +/***/ + +static void *_stdAllocator_alloc(CCGAllocatorHDL a, int numBytes) { + return malloc(numBytes); +} +static void *_stdAllocator_realloc(CCGAllocatorHDL a, void *ptr, int newSize, int oldSize) { + return realloc(ptr, newSize); +} +static void _stdAllocator_free(CCGAllocatorHDL a, void *ptr) { + free(ptr); +} + +static CCGAllocatorIFC *_getStandardAllocatorIFC(void) { + static CCGAllocatorIFC ifc; + + ifc.alloc = _stdAllocator_alloc; + ifc.realloc = _stdAllocator_realloc; + ifc.free = _stdAllocator_free; + ifc.release = NULL; + + return &ifc; +} + +/***/ + +static int VertDataEqual(float *a, float *b) { + return a[0]==b[0] && a[1]==b[1] && a[2]==b[2]; +} +#define VertDataZero(av) { float *a = (float*) av; a[0] = a[1] = a[2] = 0.0f; } +#define VertDataCopy(av, bv) { float *a = (float*) av, *b = (float*) bv; a[0] =b[0]; a[1] =b[1]; a[2] =b[2]; } +#define VertDataAdd(av, bv) { float *a = (float*) av, *b = (float*) bv; a[0]+=b[0]; a[1]+=b[1]; a[2]+=b[2]; } +#define VertDataSub(av, bv) { float *a = (float*) av, *b = (float*) bv; a[0]-=b[0]; a[1]-=b[1]; a[2]-=b[2]; } +#define VertDataMulN(av, n) { float *a = (float*) av; a[0]*=n; a[1]*=n; a[2]*=n; } +#define VertDataAvg4(tv, av, bv, cv, dv) \ + { \ + float *t = (float*) tv, *a = (float*) av, *b = (float*) bv, *c = (float*) cv, *d = (float*) dv; \ + t[0] = (a[0]+b[0]+c[0]+d[0])*.25; \ + t[1] = (a[1]+b[1]+c[1]+d[1])*.25; \ + t[2] = (a[2]+b[2]+c[2]+d[2])*.25; \ + } +#define NormZero(av) { float *a = (float*) av; a[0] = a[1] = a[2] = 0.0f; } +#define NormCopy(av, bv) { float *a = (float*) av, *b = (float*) bv; a[0] =b[0]; a[1] =b[1]; a[2] =b[2]; } +#define NormAdd(av, bv) { float *a = (float*) av, *b = (float*) bv; a[0]+=b[0]; a[1]+=b[1]; a[2]+=b[2]; } + + +static int _edge_isBoundary(CCGEdge *e); + +/***/ + +enum { + Vert_eEffected= (1<<0), + Vert_eChanged= (1<<1), + Vert_eSeam= (1<<2), +} VertFlags; +enum { + Edge_eEffected= (1<<0), +} CCGEdgeFlags; +enum { + Face_eEffected= (1<<0), +} FaceFlags; + +struct _CCGVert { + CCGVert *next; /* EHData.next */ + CCGVertHDL vHDL; /* EHData.key */ + + short numEdges, numFaces, flags, pad; + + CCGEdge **edges; + CCGFace **faces; +// byte *levelData; +// byte *userData; +}; +#define VERT_getLevelData(v) ((byte*) &(v)[1]) + +struct _CCGEdge { + CCGEdge *next; /* EHData.next */ + CCGEdgeHDL eHDL; /* EHData.key */ + + short numFaces, flags; + float crease; + + CCGVert *v0,*v1; + CCGFace **faces; + +// byte *levelData; +// byte *userData; +}; +#define EDGE_getLevelData(e) ((byte*) &(e)[1]) + +struct _CCGFace { + CCGFace *next; /* EHData.next */ + CCGFaceHDL fHDL; /* EHData.key */ + + short numVerts, flags, pad1, pad2; + +// CCGVert **verts; +// CCGEdge **edges; +// byte *centerData; +// byte **gridData; +// byte *userData; +}; +#define FACE_getVerts(f) ((CCGVert**) &(f)[1]) +#define FACE_getEdges(f) ((CCGEdge**) &(FACE_getVerts(f)[(f)->numVerts])) +#define FACE_getCenterData(f) ((byte*) &(FACE_getEdges(f)[(f)->numVerts])) + +typedef enum { + eSyncState_None = 0, + eSyncState_Vert, + eSyncState_Edge, + eSyncState_Face, + eSyncState_Partial, +} SyncState; + +struct _CCGSubSurf { + EHash *vMap; /* map of CCGVertHDL -> Vert */ + EHash *eMap; /* map of CCGEdgeHDL -> Edge */ + EHash *fMap; /* map of CCGFaceHDL -> Face */ + + CCGMeshIFC meshIFC; + + CCGAllocatorIFC allocatorIFC; + CCGAllocatorHDL allocator; + + int subdivLevels; + int numGrids; + int allowEdgeCreation; + float defaultCreaseValue; + void *defaultEdgeUserData; + + void *q, *r; + + // data for calc vert normals + int calcVertNormals; + int normalDataOffset; + + // data for age'ing (to debug sync) + int currentAge; + int useAgeCounts; + int vertUserAgeOffset; + int edgeUserAgeOffset; + int faceUserAgeOffset; + + // data used during syncing + SyncState syncState; + + EHash *oldVMap, *oldEMap, *oldFMap; + int lenTempArrays; + CCGVert **tempVerts; + CCGEdge **tempEdges; +}; + +#define CCGSUBSURF_alloc(ss, nb) ((ss)->allocatorIFC.alloc((ss)->allocator, nb)) +#define CCGSUBSURF_realloc(ss, ptr, nb, ob) ((ss)->allocatorIFC.realloc((ss)->allocator, ptr, nb, ob)) +#define CCGSUBSURF_free(ss, ptr) ((ss)->allocatorIFC.free((ss)->allocator, ptr)) + +/***/ + +static CCGVert *_vert_new(CCGVertHDL vHDL, int levels, int dataSize, CCGSubSurf *ss) { + CCGVert *v = CCGSUBSURF_alloc(ss, sizeof(CCGVert) + ss->meshIFC.vertDataSize * (ss->subdivLevels+1) + ss->meshIFC.vertUserSize); + byte *userData; + + v->vHDL = vHDL; + v->edges = NULL; + v->faces = NULL; + v->numEdges = v->numFaces = 0; + v->flags = 0; + + userData = ccgSubSurf_getVertUserData(ss, v); + memset(userData, 0, ss->meshIFC.vertUserSize); + if (ss->useAgeCounts) *((int*) &userData[ss->vertUserAgeOffset]) = ss->currentAge; + + return v; +} +static void _vert_remEdge(CCGVert *v, CCGEdge *e, CCGSubSurf *ss) { + int i; + for (i=0; inumEdges; i++) { + if (v->edges[i]==e) { + v->edges[i] = v->edges[--v->numEdges]; + break; + } + } +} +static void _vert_remFace(CCGVert *v, CCGFace *f, CCGSubSurf *ss) { + int i; + for (i=0; inumFaces; i++) { + if (v->faces[i]==f) { + v->faces[i] = v->faces[--v->numFaces]; + break; + } + } +} +static void _vert_addEdge(CCGVert *v, CCGEdge *e, CCGSubSurf *ss) { + v->edges = CCGSUBSURF_realloc(ss, v->edges, (v->numEdges+1)*sizeof(*v->edges), v->numEdges*sizeof(*v->edges)); + v->edges[v->numEdges++] = e; +} +static void _vert_addFace(CCGVert *v, CCGFace *f, CCGSubSurf *ss) { + v->faces = CCGSUBSURF_realloc(ss, v->faces, (v->numFaces+1)*sizeof(*v->faces), v->numFaces*sizeof(*v->faces)); + v->faces[v->numFaces++] = f; +} +static CCGEdge *_vert_findEdgeTo(CCGVert *v, CCGVert *vQ) { + int i; + for (i=0; inumEdges; i++) { + CCGEdge *e = v->edges[v->numEdges-1-i]; // XXX, note reverse + if ( (e->v0==v && e->v1==vQ) || + (e->v1==v && e->v0==vQ)) + return e; + } + return 0; +} +static int _vert_isBoundary(CCGVert *v) { + int i; + for (i=0; inumEdges; i++) + if (_edge_isBoundary(v->edges[i])) + return 1; + return 0; +} + +static void *_vert_getCo(CCGVert *v, int lvl, int dataSize) { + return &VERT_getLevelData(v)[lvl*dataSize]; +} +static float *_vert_getNo(CCGVert *v, int lvl, int dataSize, int normalDataOffset) { + return (float*) &VERT_getLevelData(v)[lvl*dataSize + normalDataOffset]; +} + +static void _vert_free(CCGVert *v, CCGSubSurf *ss) { + CCGSUBSURF_free(ss, v->edges); + CCGSUBSURF_free(ss, v->faces); + CCGSUBSURF_free(ss, v); +} + +static int VERT_seam(CCGVert *v, CCGSubSurf *ss) { + return ((v->flags & Vert_eSeam) != 0); +} + +/***/ + +static CCGEdge *_edge_new(CCGEdgeHDL eHDL, CCGVert *v0, CCGVert *v1, float crease, int levels, int dataSize, CCGSubSurf *ss) { + CCGEdge *e = CCGSUBSURF_alloc(ss, sizeof(CCGEdge) + ss->meshIFC.vertDataSize *((ss->subdivLevels+1) + (1<<(ss->subdivLevels+1))-1) + ss->meshIFC.edgeUserSize); + byte *userData; + + e->eHDL = eHDL; + e->v0 = v0; + e->v1 = v1; + e->crease = crease; + e->faces = NULL; + e->numFaces = 0; + e->flags = 0; + _vert_addEdge(v0, e, ss); + _vert_addEdge(v1, e, ss); + + userData = ccgSubSurf_getEdgeUserData(ss, e); + memset(userData, 0, ss->meshIFC.edgeUserSize); + if (ss->useAgeCounts) *((int*) &userData[ss->edgeUserAgeOffset]) = ss->currentAge; + + return e; +} +static void _edge_remFace(CCGEdge *e, CCGFace *f, CCGSubSurf *ss) { + int i; + for (i=0; inumFaces; i++) { + if (e->faces[i]==f) { + e->faces[i] = e->faces[--e->numFaces]; + break; + } + } +} +static void _edge_addFace(CCGEdge *e, CCGFace *f, CCGSubSurf *ss) { + e->faces = CCGSUBSURF_realloc(ss, e->faces, (e->numFaces+1)*sizeof(*e->faces), e->numFaces*sizeof(*e->faces)); + e->faces[e->numFaces++] = f; +} +static int _edge_isBoundary(CCGEdge *e) { + return e->numFaces<2; +} + +static CCGVert *_edge_getOtherVert(CCGEdge *e, CCGVert *vQ) { + if (vQ==e->v0) { + return e->v1; + } else { + return e->v0; + } +} + +static void *_edge_getCo(CCGEdge *e, int lvl, int x, int dataSize) { + int levelBase = lvl + (1<v0) { + return &EDGE_getLevelData(e)[dataSize*(levelBase + x)]; + } else { + return &EDGE_getLevelData(e)[dataSize*(levelBase + (1<faces); + CCGSUBSURF_free(ss, e); +} +static void _edge_unlinkMarkAndFree(CCGEdge *e, CCGSubSurf *ss) { + _vert_remEdge(e->v0, e, ss); + _vert_remEdge(e->v1, e, ss); + e->v0->flags |= Vert_eEffected; + e->v1->flags |= Vert_eEffected; + _edge_free(e, ss); +} + +static float EDGE_getSharpness(CCGEdge *e, int lvl) { + if (!lvl) + return e->crease; + else if (!e->crease) + return 0.0; + else if (e->crease - lvl < 0.0) + return 0.0; + else + return e->crease - lvl; +} + +static CCGFace *_face_new(CCGFaceHDL fHDL, CCGVert **verts, CCGEdge **edges, int numVerts, int levels, int dataSize, CCGSubSurf *ss) { + int maxGridSize = 1 + (1<<(ss->subdivLevels-1)); + CCGFace *f = CCGSUBSURF_alloc(ss, sizeof(CCGFace) + sizeof(CCGVert*)*numVerts + sizeof(CCGEdge*)*numVerts + ss->meshIFC.vertDataSize *(1 + numVerts*maxGridSize + numVerts*maxGridSize*maxGridSize) + ss->meshIFC.faceUserSize); + byte *userData; + int i; + + f->numVerts = numVerts; + f->fHDL = fHDL; + f->flags = 0; + + for (i=0; imeshIFC.faceUserSize); + if (ss->useAgeCounts) *((int*) &userData[ss->faceUserAgeOffset]) = ss->currentAge; + + return f; +} + +static void *_face_getIECo(CCGFace *f, int lvl, int S, int x, int levels, int dataSize) { + int maxGridSize = 1 + (1<<(levels-1)); + int spacing = 1<<(levels-lvl); + byte *gridBase = FACE_getCenterData(f) + dataSize*(1 + S*(maxGridSize + maxGridSize*maxGridSize)); + return &gridBase[dataSize*x*spacing]; +} +static void *_face_getIFCo(CCGFace *f, int lvl, int S, int x, int y, int levels, int dataSize) { + int maxGridSize = 1 + (1<<(levels-1)); + int spacing = 1<<(levels-lvl); + byte *gridBase = FACE_getCenterData(f) + dataSize*(1 + S*(maxGridSize + maxGridSize*maxGridSize)); + return &gridBase[dataSize*(maxGridSize + (y*maxGridSize + x)*spacing)]; +} +static float *_face_getIFNo(CCGFace *f, int lvl, int S, int x, int y, int levels, int dataSize, int normalDataOffset) { + int maxGridSize = 1 + (1<<(levels-1)); + int spacing = 1<<(levels-lvl); + byte *gridBase = FACE_getCenterData(f) + dataSize*(1 + S*(maxGridSize + maxGridSize*maxGridSize)); + return (float*) &gridBase[dataSize*(maxGridSize + (y*maxGridSize + x)*spacing) + normalDataOffset]; +} +static int _face_getVertIndex(CCGFace *f, CCGVert *v) { + int i; + for (i=0; inumVerts; i++) + if (FACE_getVerts(f)[i]==v) + return i; + return -1; +} +static void *_face_getIFCoEdge(CCGFace *f, CCGEdge *e, int lvl, int eX, int eY, int levels, int dataSize) { + int maxGridSize = 1 + (1<<(levels-1)); + int spacing = 1<<(levels-lvl); + int S, x, y, cx, cy; + + for (S=0; SnumVerts; S++) + if (FACE_getEdges(f)[S]==e) + break; + + eX = eX*spacing; + eY = eY*spacing; + if (e->v0!=FACE_getVerts(f)[S]) { + eX = (maxGridSize*2 - 1)-1 - eX; + } + y = maxGridSize - 1 - eX; + x = maxGridSize - 1 - eY; + if (x<0) { + S = (S+f->numVerts-1)%f->numVerts; + cx = y; + cy = -x; + } else if (y<0) { + S = (S+1)%f->numVerts; + cx = -y; + cy = x; + } else { + cx = x; + cy = y; + } + return _face_getIFCo(f, levels, S, cx, cy, levels, dataSize); +} +static float *_face_getIFNoEdge(CCGFace *f, CCGEdge *e, int lvl, int eX, int eY, int levels, int dataSize, int normalDataOffset) { + return (float*) ((byte*) _face_getIFCoEdge(f, e, lvl, eX, eY, levels, dataSize) + normalDataOffset); +} +void _face_calcIFNo(CCGFace *f, int lvl, int S, int x, int y, float *no, int levels, int dataSize) { + float *a = _face_getIFCo(f, lvl, S, x+0, y+0, levels, dataSize); + float *b = _face_getIFCo(f, lvl, S, x+1, y+0, levels, dataSize); + float *c = _face_getIFCo(f, lvl, S, x+1, y+1, levels, dataSize); + float *d = _face_getIFCo(f, lvl, S, x+0, y+1, levels, dataSize); + float a_cX = c[0]-a[0], a_cY = c[1]-a[1], a_cZ = c[2]-a[2]; + float b_dX = d[0]-b[0], b_dY = d[1]-b[1], b_dZ = d[2]-b[2]; + float length; + + no[0] = b_dY*a_cZ - b_dZ*a_cY; + no[1] = b_dZ*a_cX - b_dX*a_cZ; + no[2] = b_dX*a_cY - b_dY*a_cX; + + length = sqrt(no[0]*no[0] + no[1]*no[1] + no[2]*no[2]); + + if (length>FLT_EPSILON) { + float invLength = 1.f/length; + + no[0] *= invLength; + no[1] *= invLength; + no[2] *= invLength; + } else { + NormZero(no); + } +} + +static void _face_free(CCGFace *f, CCGSubSurf *ss) { + CCGSUBSURF_free(ss, f); +} +static void _face_unlinkMarkAndFree(CCGFace *f, CCGSubSurf *ss) { + int j; + for (j=0; jnumVerts; j++) { + _vert_remFace(FACE_getVerts(f)[j], f, ss); + _edge_remFace(FACE_getEdges(f)[j], f, ss); + FACE_getVerts(f)[j]->flags |= Vert_eEffected; + } + _face_free(f, ss); +} + +/***/ + +CCGSubSurf *ccgSubSurf_new(CCGMeshIFC *ifc, int subdivLevels, CCGAllocatorIFC *allocatorIFC, CCGAllocatorHDL allocator) { + if (!allocatorIFC) { + allocatorIFC = _getStandardAllocatorIFC(); + allocator = NULL; + } + + if (subdivLevels<1) { + return NULL; + } else { + CCGSubSurf *ss = allocatorIFC->alloc(allocator, sizeof(*ss)); + + ss->allocatorIFC = *allocatorIFC; + ss->allocator = allocator; + + ss->vMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator); + ss->eMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator); + ss->fMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator); + + ss->meshIFC = *ifc; + + ss->subdivLevels = subdivLevels; + ss->numGrids = 0; + ss->allowEdgeCreation = 0; + ss->defaultCreaseValue = 0; + ss->defaultEdgeUserData = NULL; + + ss->useAgeCounts = 0; + ss->vertUserAgeOffset = ss->edgeUserAgeOffset = ss->faceUserAgeOffset = 0; + + ss->calcVertNormals = 0; + ss->normalDataOffset = 0; + + ss->q = CCGSUBSURF_alloc(ss, ss->meshIFC.vertDataSize); + ss->r = CCGSUBSURF_alloc(ss, ss->meshIFC.vertDataSize); + + ss->currentAge = 0; + + ss->syncState = eSyncState_None; + + ss->oldVMap = ss->oldEMap = ss->oldFMap = NULL; + ss->lenTempArrays = 0; + ss->tempVerts = NULL; + ss->tempEdges = NULL; + + return ss; + } +} + +void ccgSubSurf_free(CCGSubSurf *ss) { + CCGAllocatorIFC allocatorIFC = ss->allocatorIFC; + CCGAllocatorHDL allocator = ss->allocator; + + if (ss->syncState) { + _ehash_free(ss->oldFMap, (EHEntryFreeFP) _face_free, ss); + _ehash_free(ss->oldEMap, (EHEntryFreeFP) _edge_free, ss); + _ehash_free(ss->oldVMap, (EHEntryFreeFP) _vert_free, ss); + + CCGSUBSURF_free(ss, ss->tempVerts); + CCGSUBSURF_free(ss, ss->tempEdges); + } + + CCGSUBSURF_free(ss, ss->r); + CCGSUBSURF_free(ss, ss->q); + if (ss->defaultEdgeUserData) CCGSUBSURF_free(ss, ss->defaultEdgeUserData); + + _ehash_free(ss->fMap, (EHEntryFreeFP) _face_free, ss); + _ehash_free(ss->eMap, (EHEntryFreeFP) _edge_free, ss); + _ehash_free(ss->vMap, (EHEntryFreeFP) _vert_free, ss); + + CCGSUBSURF_free(ss, ss); + + if (allocatorIFC.release) { + allocatorIFC.release(allocator); + } +} + +CCGError ccgSubSurf_setAllowEdgeCreation(CCGSubSurf *ss, int allowEdgeCreation, float defaultCreaseValue, void *defaultUserData) { + if (ss->defaultEdgeUserData) { + CCGSUBSURF_free(ss, ss->defaultEdgeUserData); + } + + ss->allowEdgeCreation = !!allowEdgeCreation; + ss->defaultCreaseValue = defaultCreaseValue; + ss->defaultEdgeUserData = CCGSUBSURF_alloc(ss, ss->meshIFC.edgeUserSize); + + if (defaultUserData) { + memcpy(ss->defaultEdgeUserData, defaultUserData, ss->meshIFC.edgeUserSize); + } else { + memset(ss->defaultEdgeUserData, 0, ss->meshIFC.edgeUserSize); + } + + return eCCGError_None; +} +void ccgSubSurf_getAllowEdgeCreation(CCGSubSurf *ss, int *allowEdgeCreation_r, float *defaultCreaseValue_r, void *defaultUserData_r) { + if (allowEdgeCreation_r) *allowEdgeCreation_r = ss->allowEdgeCreation; + if (ss->allowEdgeCreation) { + if (defaultCreaseValue_r) *defaultCreaseValue_r = ss->defaultCreaseValue; + if (defaultUserData_r) memcpy(defaultUserData_r, ss->defaultEdgeUserData, ss->meshIFC.edgeUserSize); + } +} + +CCGError ccgSubSurf_setSubdivisionLevels(CCGSubSurf *ss, int subdivisionLevels) { + if (subdivisionLevels<=0) { + return eCCGError_InvalidValue; + } else if (subdivisionLevels!=ss->subdivLevels) { + ss->numGrids = 0; + ss->subdivLevels = subdivisionLevels; + _ehash_free(ss->vMap, (EHEntryFreeFP) _vert_free, ss); + _ehash_free(ss->eMap, (EHEntryFreeFP) _edge_free, ss); + _ehash_free(ss->fMap, (EHEntryFreeFP) _face_free, ss); + ss->vMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator); + ss->eMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator); + ss->fMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator); + } + + return eCCGError_None; +} + +void ccgSubSurf_getUseAgeCounts(CCGSubSurf *ss, int *useAgeCounts_r, int *vertUserOffset_r, int *edgeUserOffset_r, int *faceUserOffset_r) +{ + *useAgeCounts_r = ss->useAgeCounts; + + if (vertUserOffset_r) *vertUserOffset_r = ss->vertUserAgeOffset; + if (edgeUserOffset_r) *edgeUserOffset_r = ss->edgeUserAgeOffset; + if (faceUserOffset_r) *faceUserOffset_r = ss->faceUserAgeOffset; +} + +CCGError ccgSubSurf_setUseAgeCounts(CCGSubSurf *ss, int useAgeCounts, int vertUserOffset, int edgeUserOffset, int faceUserOffset) { + if (useAgeCounts) { + if ( (vertUserOffset+4>ss->meshIFC.vertUserSize) || + (edgeUserOffset+4>ss->meshIFC.edgeUserSize) || + (faceUserOffset+4>ss->meshIFC.faceUserSize)) { + return eCCGError_InvalidValue; + } else { + ss->useAgeCounts = 1; + ss->vertUserAgeOffset = vertUserOffset; + ss->edgeUserAgeOffset = edgeUserOffset; + ss->faceUserAgeOffset = faceUserOffset; + } + } else { + ss->useAgeCounts = 0; + ss->vertUserAgeOffset = ss->edgeUserAgeOffset = ss->faceUserAgeOffset = 0; + } + + return eCCGError_None; +} + +CCGError ccgSubSurf_setCalcVertexNormals(CCGSubSurf *ss, int useVertNormals, int normalDataOffset) { + if (useVertNormals) { + if (normalDataOffset<0 || normalDataOffset+12>ss->meshIFC.vertDataSize) { + return eCCGError_InvalidValue; + } else { + ss->calcVertNormals = 1; + ss->normalDataOffset = normalDataOffset; + } + } else { + ss->calcVertNormals = 0; + ss->normalDataOffset = 0; + } + + return eCCGError_None; +} + +/***/ + +CCGError ccgSubSurf_initFullSync(CCGSubSurf *ss) { + if (ss->syncState!=eSyncState_None) { + return eCCGError_InvalidSyncState; + } + + ss->currentAge++; + + ss->oldVMap = ss->vMap; + ss->oldEMap = ss->eMap; + ss->oldFMap = ss->fMap; + + ss->vMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator); + ss->eMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator); + ss->fMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator); + + ss->numGrids = 0; + + ss->lenTempArrays = 12; + ss->tempVerts = CCGSUBSURF_alloc(ss, sizeof(*ss->tempVerts)*ss->lenTempArrays); + ss->tempEdges = CCGSUBSURF_alloc(ss, sizeof(*ss->tempEdges)*ss->lenTempArrays); + + ss->syncState = eSyncState_Vert; + + return eCCGError_None; +} + +CCGError ccgSubSurf_initPartialSync(CCGSubSurf *ss) { + if (ss->syncState!=eSyncState_None) { + return eCCGError_InvalidSyncState; + } + + ss->currentAge++; + + ss->syncState = eSyncState_Partial; + + return eCCGError_None; +} + +CCGError ccgSubSurf_syncVertDel(CCGSubSurf *ss, CCGVertHDL vHDL) { + if (ss->syncState!=eSyncState_Partial) { + return eCCGError_InvalidSyncState; + } else { + void **prevp; + CCGVert *v = _ehash_lookupWithPrev(ss->vMap, vHDL, &prevp); + + if (!v || v->numFaces || v->numEdges) { + return eCCGError_InvalidValue; + } else { + *prevp = v->next; + _vert_free(v, ss); + } + } + + return eCCGError_None; +} + +CCGError ccgSubSurf_syncEdgeDel(CCGSubSurf *ss, CCGEdgeHDL eHDL) { + if (ss->syncState!=eSyncState_Partial) { + return eCCGError_InvalidSyncState; + } else { + void **prevp; + CCGEdge *e = _ehash_lookupWithPrev(ss->eMap, eHDL, &prevp); + + if (!e || e->numFaces) { + return eCCGError_InvalidValue; + } else { + *prevp = e->next; + _edge_unlinkMarkAndFree(e, ss); + } + } + + return eCCGError_None; +} + +CCGError ccgSubSurf_syncFaceDel(CCGSubSurf *ss, CCGFaceHDL fHDL) { + if (ss->syncState!=eSyncState_Partial) { + return eCCGError_InvalidSyncState; + } else { + void **prevp; + CCGFace *f = _ehash_lookupWithPrev(ss->fMap, fHDL, &prevp); + + if (!f) { + return eCCGError_InvalidValue; + } else { + *prevp = f->next; + _face_unlinkMarkAndFree(f, ss); + } + } + + return eCCGError_None; +} + +CCGError ccgSubSurf_syncVert(CCGSubSurf *ss, CCGVertHDL vHDL, void *vertData, int seam, CCGVert **v_r) { + void **prevp; + CCGVert *v = NULL; + short seamflag = (seam)? Vert_eSeam: 0; + + if (ss->syncState==eSyncState_Partial) { + v = _ehash_lookupWithPrev(ss->vMap, vHDL, &prevp); + if (!v) { + v = _vert_new(vHDL, ss->subdivLevels, ss->meshIFC.vertDataSize, ss); + VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData); + _ehash_insert(ss->vMap, (EHEntry*) v); + v->flags = Vert_eEffected|seamflag; + } else if (!VertDataEqual(vertData, _vert_getCo(v, 0, ss->meshIFC.vertDataSize)) || ((v->flags & Vert_eSeam) != seamflag)) { + int i, j; + + VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData); + v->flags = Vert_eEffected|seamflag; + + for (i=0; inumEdges; i++) { + CCGEdge *e = v->edges[i]; + e->v0->flags |= Vert_eEffected; + e->v1->flags |= Vert_eEffected; + } + for (i=0; inumFaces; i++) { + CCGFace *f = v->faces[i]; + for (j=0; jnumVerts; j++) { + FACE_getVerts(f)[j]->flags |= Vert_eEffected; + } + } + } + } else { + if (ss->syncState!=eSyncState_Vert) { + return eCCGError_InvalidSyncState; + } + + v = _ehash_lookupWithPrev(ss->oldVMap, vHDL, &prevp); + if (!v) { + v = _vert_new(vHDL, ss->subdivLevels, ss->meshIFC.vertDataSize, ss); + VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData); + _ehash_insert(ss->vMap, (EHEntry*) v); + v->flags = Vert_eEffected|seamflag; + } else if (!VertDataEqual(vertData, _vert_getCo(v, 0, ss->meshIFC.vertDataSize)) || ((v->flags & Vert_eSeam) != seamflag)) { + *prevp = v->next; + _ehash_insert(ss->vMap, (EHEntry*) v); + VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData); + v->flags = Vert_eEffected|Vert_eChanged|seamflag; + } else { + *prevp = v->next; + _ehash_insert(ss->vMap, (EHEntry*) v); + v->flags = 0; + } + } + + if (v_r) *v_r = v; + return eCCGError_None; +} + +CCGError ccgSubSurf_syncEdge(CCGSubSurf *ss, CCGEdgeHDL eHDL, CCGVertHDL e_vHDL0, CCGVertHDL e_vHDL1, float crease, CCGEdge **e_r) { + void **prevp; + CCGEdge *e = NULL, *eNew; + + if (ss->syncState==eSyncState_Partial) { + e = _ehash_lookupWithPrev(ss->eMap, eHDL, &prevp); + if (!e || e->v0->vHDL!=e_vHDL0 || e->v1->vHDL!=e_vHDL1 || crease!=e->crease) { + CCGVert *v0 = _ehash_lookup(ss->vMap, e_vHDL0); + CCGVert *v1 = _ehash_lookup(ss->vMap, e_vHDL1); + + eNew = _edge_new(eHDL, v0, v1, crease, ss->subdivLevels, ss->meshIFC.vertDataSize, ss); + + if (e) { + *prevp = eNew; + eNew->next = e->next; + + _edge_unlinkMarkAndFree(e, ss); + } else { + _ehash_insert(ss->eMap, (EHEntry*) eNew); + } + + eNew->v0->flags |= Vert_eEffected; + eNew->v1->flags |= Vert_eEffected; + } + } else { + if (ss->syncState==eSyncState_Vert) { + ss->syncState = eSyncState_Edge; + } else if (ss->syncState!=eSyncState_Edge) { + return eCCGError_InvalidSyncState; + } + + e = _ehash_lookupWithPrev(ss->oldEMap, eHDL, &prevp); + if (!e || e->v0->vHDL!=e_vHDL0 || e->v1->vHDL!=e_vHDL1|| e->crease!=crease) { + CCGVert *v0 = _ehash_lookup(ss->vMap, e_vHDL0); + CCGVert *v1 = _ehash_lookup(ss->vMap, e_vHDL1); + e = _edge_new(eHDL, v0, v1, crease, ss->subdivLevels, ss->meshIFC.vertDataSize, ss); + _ehash_insert(ss->eMap, (EHEntry*) e); + e->v0->flags |= Vert_eEffected; + e->v1->flags |= Vert_eEffected; + } else { + *prevp = e->next; + _ehash_insert(ss->eMap, (EHEntry*) e); + e->flags = 0; + if ((e->v0->flags|e->v1->flags)&Vert_eChanged) { + e->v0->flags |= Vert_eEffected; + e->v1->flags |= Vert_eEffected; + } + } + } + + if (e_r) *e_r = e; + return eCCGError_None; +} + +CCGError ccgSubSurf_syncFace(CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGVertHDL *vHDLs, CCGFace **f_r) { + void **prevp; + CCGFace *f = NULL, *fNew; + int j, k, topologyChanged = 0; + + if (numVerts>ss->lenTempArrays) { + int oldLen = ss->lenTempArrays; + ss->lenTempArrays = (numVertslenTempArrays*2)?ss->lenTempArrays*2:numVerts; + ss->tempVerts = CCGSUBSURF_realloc(ss, ss->tempVerts, sizeof(*ss->tempVerts)*ss->lenTempArrays, sizeof(*ss->tempVerts)*oldLen); + ss->tempEdges = CCGSUBSURF_realloc(ss, ss->tempEdges, sizeof(*ss->tempEdges)*ss->lenTempArrays, sizeof(*ss->tempEdges)*oldLen); + } + + if (ss->syncState==eSyncState_Partial) { + f = _ehash_lookupWithPrev(ss->fMap, fHDL, &prevp); + + for (k=0; ktempVerts[k] = _ehash_lookup(ss->vMap, vHDLs[k]); + } + for (k=0; ktempEdges[k] = _vert_findEdgeTo(ss->tempVerts[k], ss->tempVerts[(k+1)%numVerts]); + } + + if (f) { + if ( f->numVerts!=numVerts || + memcmp(FACE_getVerts(f), ss->tempVerts, sizeof(*ss->tempVerts)*numVerts) || + memcmp(FACE_getEdges(f), ss->tempEdges, sizeof(*ss->tempEdges)*numVerts)) + topologyChanged = 1; + } + + if (!f || topologyChanged) { + fNew = _face_new(fHDL, ss->tempVerts, ss->tempEdges, numVerts, ss->subdivLevels, ss->meshIFC.vertDataSize, ss); + + if (f) { + ss->numGrids += numVerts - f->numVerts; + + *prevp = fNew; + fNew->next = f->next; + + _face_unlinkMarkAndFree(f, ss); + } else { + ss->numGrids += numVerts; + _ehash_insert(ss->fMap, (EHEntry*) fNew); + } + + for (k=0; kflags |= Vert_eEffected; + } + } else { + if (ss->syncState==eSyncState_Vert || ss->syncState==eSyncState_Edge) { + ss->syncState = eSyncState_Face; + } else if (ss->syncState!=eSyncState_Face) { + return eCCGError_InvalidSyncState; + } + + f = _ehash_lookupWithPrev(ss->oldFMap, fHDL, &prevp); + + for (k=0; ktempVerts[k] = _ehash_lookup(ss->vMap, vHDLs[k]); + + if (!ss->tempVerts[k]) + return eCCGError_InvalidValue; + } + for (k=0; ktempEdges[k] = _vert_findEdgeTo(ss->tempVerts[k], ss->tempVerts[(k+1)%numVerts]); + + if (!ss->tempEdges[k]) { + if (ss->allowEdgeCreation) { + CCGEdge *e = ss->tempEdges[k] = _edge_new((CCGEdgeHDL) -1, ss->tempVerts[k], ss->tempVerts[(k+1)%numVerts], ss->defaultCreaseValue, ss->subdivLevels, ss->meshIFC.vertDataSize, ss); + _ehash_insert(ss->eMap, (EHEntry*) e); + e->v0->flags |= Vert_eEffected; + e->v1->flags |= Vert_eEffected; + if (ss->meshIFC.edgeUserSize) { + memcpy(ccgSubSurf_getEdgeUserData(ss, e), ss->defaultEdgeUserData, ss->meshIFC.edgeUserSize); + } + } else { + return eCCGError_InvalidValue; + } + } + } + + if (f) { + if ( f->numVerts!=numVerts || + memcmp(FACE_getVerts(f), ss->tempVerts, sizeof(*ss->tempVerts)*numVerts) || + memcmp(FACE_getEdges(f), ss->tempEdges, sizeof(*ss->tempEdges)*numVerts)) + topologyChanged = 1; + } + + if (!f || topologyChanged) { + f = _face_new(fHDL, ss->tempVerts, ss->tempEdges, numVerts, ss->subdivLevels, ss->meshIFC.vertDataSize, ss); + _ehash_insert(ss->fMap, (EHEntry*) f); + ss->numGrids += numVerts; + + for (k=0; kflags |= Vert_eEffected; + } else { + *prevp = f->next; + _ehash_insert(ss->fMap, (EHEntry*) f); + f->flags = 0; + ss->numGrids += f->numVerts; + + for (j=0; jnumVerts; j++) { + if (FACE_getVerts(f)[j]->flags&Vert_eChanged) { + for (k=0; knumVerts; k++) + FACE_getVerts(f)[k]->flags |= Vert_eEffected; + break; + } + } + } + } + + if (f_r) *f_r = f; + return eCCGError_None; +} + +static void ccgSubSurf__sync(CCGSubSurf *ss); +CCGError ccgSubSurf_processSync(CCGSubSurf *ss) { + if (ss->syncState==eSyncState_Partial) { + ss->syncState = eSyncState_None; + + ccgSubSurf__sync(ss); + } else if (ss->syncState) { + _ehash_free(ss->oldFMap, (EHEntryFreeFP) _face_unlinkMarkAndFree, ss); + _ehash_free(ss->oldEMap, (EHEntryFreeFP) _edge_unlinkMarkAndFree, ss); + _ehash_free(ss->oldVMap, (EHEntryFreeFP) _vert_free, ss); + CCGSUBSURF_free(ss, ss->tempEdges); + CCGSUBSURF_free(ss, ss->tempVerts); + + ss->lenTempArrays = 0; + + ss->oldFMap = ss->oldEMap = ss->oldVMap = NULL; + ss->tempVerts = NULL; + ss->tempEdges = NULL; + + ss->syncState = eSyncState_None; + + ccgSubSurf__sync(ss); + } else { + return eCCGError_InvalidSyncState; + } + + return eCCGError_None; +} + +static void ccgSubSurf__sync(CCGSubSurf *ss) { + CCGVert **effectedV; + CCGEdge **effectedE; + CCGFace **effectedF; + int numEffectedV, numEffectedE, numEffectedF; + int subdivLevels = ss->subdivLevels; + int vertDataSize = ss->meshIFC.vertDataSize; + int i,ptrIdx,cornerIdx; + int S,x,y; + void *q = ss->q, *r = ss->r; + int curLvl, nextLvl; + int j; + + effectedV = CCGSUBSURF_alloc(ss, sizeof(*effectedV)*ss->vMap->numEntries); + effectedE = CCGSUBSURF_alloc(ss, sizeof(*effectedE)*ss->eMap->numEntries); + effectedF = CCGSUBSURF_alloc(ss, sizeof(*effectedF)*ss->fMap->numEntries); + numEffectedV = numEffectedE = numEffectedF = 0; + for (i=0; ivMap->curSize; i++) { + CCGVert *v = (CCGVert*) ss->vMap->buckets[i]; + for (; v; v = v->next) { + if (v->flags&Vert_eEffected) { + effectedV[numEffectedV++] = v; + + for (j=0; jnumEdges; j++) { + CCGEdge *e = v->edges[j]; + if (!(e->flags&Edge_eEffected)) { + effectedE[numEffectedE++] = e; + e->flags |= Edge_eEffected; + } + } + + for (j=0; jnumFaces; j++) { + CCGFace *f = v->faces[j]; + if (!(f->flags&Face_eEffected)) { + effectedF[numEffectedF++] = f; + f->flags |= Face_eEffected; + } + } + } + } + } + +#define VERT_getCo(v, lvl) _vert_getCo(v, lvl, vertDataSize) +#define EDGE_getCo(e, lvl, x) _edge_getCo(e, lvl, x, vertDataSize) +#define FACE_getIECo(f, lvl, S, x) _face_getIECo(f, lvl, S, x, subdivLevels, vertDataSize) +#define FACE_getIFCo(f, lvl, S, x, y) _face_getIFCo(f, lvl, S, x, y, subdivLevels, vertDataSize) + curLvl = 0; + nextLvl = curLvl+1; + + for (ptrIdx=0; ptrIdxnumVerts; i++) { + VertDataAdd(co, VERT_getCo(FACE_getVerts(f)[i], curLvl)); + } + VertDataMulN(co, 1.0f/f->numVerts); + + f->flags = 0; + } + for (ptrIdx=0; ptrIdx=1.0) { + VertDataCopy(co, VERT_getCo(e->v0, curLvl)); + VertDataAdd(co, VERT_getCo(e->v1, curLvl)); + VertDataMulN(co, 0.5f); + } else { + int numFaces = 0; + VertDataCopy(q, VERT_getCo(e->v0, curLvl)); + VertDataAdd(q, VERT_getCo(e->v1, curLvl)); + for (i=0; inumFaces; i++) { + CCGFace *f = e->faces[i]; + VertDataAdd(q, FACE_getCenterData(f)); + numFaces++; + } + VertDataMulN(q, 1.0f/(2.0f+numFaces)); + + VertDataCopy(r, VERT_getCo(e->v0, curLvl)); + VertDataAdd(r, VERT_getCo(e->v1, curLvl)); + VertDataMulN(r, 0.5f); + + VertDataCopy(co, q); + VertDataSub(r, q); + VertDataMulN(r, sharpness); + VertDataAdd(co, r); + } + + // edge flags cleared later + } + for (ptrIdx=0; ptrIdxnumEdges; i++) { + CCGEdge *e = v->edges[i]; + float sharpness = EDGE_getSharpness(e, curLvl); + + if (seam && _edge_isBoundary(e)) + seamEdges++; + + if (sharpness!=0.0f) { + sharpCount++; + avgSharpness += sharpness; + } else { + allSharp = 0; + } + } + + avgSharpness /= sharpCount; + if (avgSharpness>1.0) { + avgSharpness = 1.0; + } + + if (seam && seamEdges < 2) + seam = 0; + + if (!v->numEdges) { + VertDataCopy(nCo, co); + } else if (_vert_isBoundary(v)) { + int numBoundary = 0; + + VertDataZero(r); + for (i=0; inumEdges; i++) { + CCGEdge *e = v->edges[i]; + if (_edge_isBoundary(e)) { + VertDataAdd(r, VERT_getCo(_edge_getOtherVert(e, v), curLvl)); + numBoundary++; + } + } + VertDataCopy(nCo, co); + VertDataMulN(nCo, 0.75); + VertDataMulN(r, 0.25f/numBoundary); + VertDataAdd(nCo, r); + } else { + int numEdges = 0, numFaces = 0; + + VertDataZero(q); + for (i=0; inumFaces; i++) { + CCGFace *f = v->faces[i]; + VertDataAdd(q, FACE_getCenterData(f)); + numFaces++; + } + VertDataMulN(q, 1.0f/numFaces); + VertDataZero(r); + for (i=0; inumEdges; i++) { + CCGEdge *e = v->edges[i]; + VertDataAdd(r, VERT_getCo(_edge_getOtherVert(e, v), curLvl)); + numEdges++; + } + VertDataMulN(r, 1.0f/numEdges); + + VertDataCopy(nCo, co); + VertDataMulN(nCo, numEdges-2.0f); + VertDataAdd(nCo, q); + VertDataAdd(nCo, r); + VertDataMulN(nCo, 1.0f/numEdges); + } + + if ((sharpCount>1 && v->numFaces) || seam) { + VertDataZero(q); + + if (seam) { + avgSharpness = 1.0f; + sharpCount = seamEdges; + allSharp = 1; + } + + for (i=0; inumEdges; i++) { + CCGEdge *e = v->edges[i]; + float sharpness = EDGE_getSharpness(e, curLvl); + + if (seam) { + if (_edge_isBoundary(e)) { + CCGVert *oV = _edge_getOtherVert(e, v); + VertDataAdd(q, VERT_getCo(oV, curLvl)); + } + } else if (sharpness != 0.0) { + CCGVert *oV = _edge_getOtherVert(e, v); + VertDataAdd(q, VERT_getCo(oV, curLvl)); + } + } + + VertDataMulN(q, (float) 1/sharpCount); + + if (sharpCount!=2 || allSharp) { + // q = q + (co-q)*avgSharpness + VertDataCopy(r, co); + VertDataSub(r, q); + VertDataMulN(r, avgSharpness); + VertDataAdd(q, r); + } + + // r = co*.75 + q*.25 + VertDataCopy(r, co); + VertDataMulN(r, .75); + VertDataMulN(q, .25); + VertDataAdd(r, q); + + // nCo = nCo + (r-nCo)*avgSharpness + VertDataSub(r, nCo); + VertDataMulN(r, avgSharpness); + VertDataAdd(nCo, r); + } + + // vert flags cleared later + } + + if (ss->useAgeCounts) { + for (i=0; ivertUserAgeOffset]) = ss->currentAge; + } + + for (i=0; iedgeUserAgeOffset]) = ss->currentAge; + } + + for (i=0; ifaceUserAgeOffset]) = ss->currentAge; + } + } + + for (i=0; iv0, nextLvl)); + VertDataCopy(EDGE_getCo(e, nextLvl, 2), VERT_getCo(e->v1, nextLvl)); + } + for (i=0; inumVerts; S++) { + CCGEdge *e = FACE_getEdges(f)[S]; + CCGEdge *prevE = FACE_getEdges(f)[(S+f->numVerts-1)%f->numVerts]; + + VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), FACE_getCenterData(f)); + VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), FACE_getCenterData(f)); + VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 1), VERT_getCo(FACE_getVerts(f)[S], nextLvl)); + VertDataCopy(FACE_getIECo(f, nextLvl, S, 1), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, 1)); + + VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 0), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize)); + VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 1), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize)); + } + } + + for (curLvl=1; curLvlnumVerts; S++) { + for (y=0; ynumVerts; S++) { + for (x=0; xnumVerts, 1, fx); + void *co3 = FACE_getIFCo(f, nextLvl, S, fx, 1); + void *co = FACE_getIECo(f, nextLvl, S, fx); + + VertDataAvg4(co, co0, co1, co2, co3); + } + + /* interior face interior edge midpoints + * o old interior face points + * o new interior face midpoints + */ + + /* vertical */ + for (x=1; x1.0) { + for (x=0; xnumFaces; i++) { + CCGFace *f = e->faces[i]; + VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx, 1, subdivLevels, vertDataSize)); + numFaces++; + } + + VertDataMulN(q, 1.0f/(2.0f+numFaces)); + + VertDataCopy(r, co0); + VertDataAdd(r, co1); + VertDataMulN(r, 0.5); + + VertDataCopy(co, q); + VertDataSub(r, q); + VertDataMulN(r, sharpness); + VertDataAdd(co, r); + } + } + } + + /* exterior vertex shift + * o old vertex points (shifting) + * o old exterior edge points + * o new interior face midpoints + */ + for (ptrIdx=0; ptrIdxnumEdges; i++) { + CCGEdge *e = v->edges[i]; + float sharpness = EDGE_getSharpness(e, curLvl); + + if (seam && _edge_isBoundary(e)) + seamEdges++; + + if (sharpness!=0.0f) { + sharpCount++; + avgSharpness += sharpness; + } else { + allSharp = 0; + } + } + + avgSharpness /= sharpCount; + if (avgSharpness>1.0) { + avgSharpness = 1.0; + } + + if (seam && seamEdges < 2) + seam = 0; + + if (!v->numEdges) { + VertDataCopy(nCo, co); + } else if (_vert_isBoundary(v)) { + int numBoundary = 0; + + VertDataZero(r); + for (i=0; inumEdges; i++) { + CCGEdge *e = v->edges[i]; + if (_edge_isBoundary(e)) { + VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1, vertDataSize)); + numBoundary++; + } + } + + VertDataCopy(nCo, co); + VertDataMulN(nCo, 0.75); + VertDataMulN(r, 0.25f/numBoundary); + VertDataAdd(nCo, r); + } else { + int cornerIdx = (1 + (1<<(curLvl))) - 2; + int numEdges = 0, numFaces = 0; + + VertDataZero(q); + for (i=0; inumFaces; i++) { + CCGFace *f = v->faces[i]; + VertDataAdd(q, FACE_getIFCo(f, nextLvl, _face_getVertIndex(f,v), cornerIdx, cornerIdx)); + numFaces++; + } + VertDataMulN(q, 1.0f/numFaces); + VertDataZero(r); + for (i=0; inumEdges; i++) { + CCGEdge *e = v->edges[i]; + VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1,vertDataSize)); + numEdges++; + } + VertDataMulN(r, 1.0f/numEdges); + + VertDataCopy(nCo, co); + VertDataMulN(nCo, numEdges-2.0f); + VertDataAdd(nCo, q); + VertDataAdd(nCo, r); + VertDataMulN(nCo, 1.0f/numEdges); + } + + if ((sharpCount>1 && v->numFaces) || seam) { + VertDataZero(q); + + if (seam) { + avgSharpness = 1.0f; + sharpCount = seamEdges; + allSharp = 1; + } + + for (i=0; inumEdges; i++) { + CCGEdge *e = v->edges[i]; + float sharpness = EDGE_getSharpness(e, curLvl); + + if (seam) { + if (_edge_isBoundary(e)) + VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize)); + } else if (sharpness != 0.0) { + VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize)); + } + } + + VertDataMulN(q, (float) 1/sharpCount); + + if (sharpCount!=2 || allSharp) { + // q = q + (co-q)*avgSharpness + VertDataCopy(r, co); + VertDataSub(r, q); + VertDataMulN(r, avgSharpness); + VertDataAdd(q, r); + } + + // r = co*.75 + q*.25 + VertDataCopy(r, co); + VertDataMulN(r, .75); + VertDataMulN(q, .25); + VertDataAdd(r, q); + + // nCo = nCo + (r-nCo)*avgSharpness + VertDataSub(r, nCo); + VertDataMulN(r, avgSharpness); + VertDataAdd(nCo, r); + } + } + + /* exterior edge interior shift + * o old exterior edge midpoints (shifting) + * o old exterior edge midpoints + * o new interior face midpoints + */ + for (ptrIdx=0; ptrIdx1.0) { + avgSharpness = 1.0; + } + } else { + sharpCount = 0; + avgSharpness = 0; + } + + if (_edge_isBoundary(e) && (!e->numFaces || sharpCount<2)) { + for (x=1; xnumFaces; i++) { + CCGFace *f = e->faces[i]; + VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx-1, 1, subdivLevels, vertDataSize)); + VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx+1, 1, subdivLevels, vertDataSize)); + + VertDataAdd(r, _face_getIFCoEdge(f, e, curLvl, x, 1, subdivLevels, vertDataSize)); + numFaces++; + } + VertDataMulN(q, 1.0/(numFaces*2.0f)); + VertDataMulN(r, 1.0/(2.0f + numFaces)); + + VertDataCopy(nCo, co); + VertDataMulN(nCo, (float) numFaces); + VertDataAdd(nCo, q); + VertDataAdd(nCo, r); + VertDataMulN(nCo, 1.0f/(2+numFaces)); + + if (sharpCount==2) { + VertDataCopy(q, co); + VertDataMulN(q, 6.0f); + VertDataAdd(q, EDGE_getCo(e, curLvl, x-1)); + VertDataAdd(q, EDGE_getCo(e, curLvl, x+1)); + VertDataMulN(q, 1/8.0f); + + VertDataSub(q, nCo); + VertDataMulN(q, avgSharpness); + VertDataAdd(nCo, q); + } + } + } + } + + for (ptrIdx=0; ptrIdxnumVerts; S++) { + VertDataAdd(q, FACE_getIFCo(f, nextLvl, S, 1, 1)); + } + VertDataMulN(q, 1.0f/f->numVerts); + VertDataZero(r); + for (S=0; SnumVerts; S++) { + VertDataAdd(r, FACE_getIECo(f, curLvl, S, 1)); + } + VertDataMulN(r, 1.0f/f->numVerts); + + VertDataMulN(FACE_getCenterData(f), f->numVerts-2.0f); + VertDataAdd(FACE_getCenterData(f), q); + VertDataAdd(FACE_getCenterData(f), r); + VertDataMulN(FACE_getCenterData(f), 1.0f/f->numVerts); + + for (S=0; SnumVerts; S++) { + /* interior face shift + * o old interior face point (shifting) + * o new interior edge midpoints + * o new interior face midpoints + */ + for (x=1; xnumVerts, 1, fx-1), + FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx+1), + FACE_getIFCo(f, nextLvl, S, fx+1, +1), + FACE_getIFCo(f, nextLvl, S, fx-1, +1)); + + VertDataAvg4(r, FACE_getIECo(f, nextLvl, S, fx-1), + FACE_getIECo(f, nextLvl, S, fx+1), + FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx), + FACE_getIFCo(f, nextLvl, S, fx, 1)); + + VertDataCopy(nCo, co); + VertDataSub(nCo, q); + VertDataMulN(nCo, 0.25f); + VertDataAdd(nCo, r); + } + } + } + + /* copy down */ + edgeSize = 1 + (1<<(nextLvl)); + gridSize = 1 + (1<<((nextLvl)-1)); + cornerIdx = gridSize-1; + for (i=0; iv0, nextLvl)); + VertDataCopy(EDGE_getCo(e, nextLvl, edgeSize-1), VERT_getCo(e->v1, nextLvl)); + } + for (i=0; inumVerts; S++) { + CCGEdge *e = FACE_getEdges(f)[S]; + CCGEdge *prevE = FACE_getEdges(f)[(S+f->numVerts-1)%f->numVerts]; + + VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), FACE_getCenterData(f)); + VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), FACE_getCenterData(f)); + VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], nextLvl)); + VertDataCopy(FACE_getIECo(f, nextLvl, S, cornerIdx), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, cornerIdx)); + for (x=1; xnumVerts, 0, x), co); + } + for (x=0; xcalcVertNormals) { + int lvl = ss->subdivLevels; + int edgeSize = 1 + (1<normalDataOffset; + + for (ptrIdx=0; ptrIdxnumVerts; S++) { + for (y=0; ynumVerts)%f->numVerts]->flags&Edge_eEffected) + for (x=0; xflags&Edge_eEffected) + for (y=0; yflags&Vert_eEffected) + NormZero(FACE_getIFNo(f, lvl, S, gridSize-1, gridSize-1)); + } + } + + for (ptrIdx=0; ptrIdxnumVerts; S++) { + int yLimit = !(FACE_getEdges(f)[(S-1+f->numVerts)%f->numVerts]->flags&Edge_eEffected); + int xLimit = !(FACE_getEdges(f)[S]->flags&Edge_eEffected); + int yLimitNext = xLimit; + int xLimitPrev = yLimit; + + for (y=0; yflags&Vert_eEffected) { + NormAdd(FACE_getIFNo(f, lvl, S, x+1, y+1), no); + } + } + + if (x==0 && y==0) { + int K; + + if (!yLimitNext || 1numVerts, 0, 1), no); + if (!xLimitPrev || 1numVerts)%f->numVerts, 1, 0), no); + + for (K=0; KnumVerts; K++) { + if (K!=S) { + NormAdd(FACE_getIFNo(f, lvl, K, 0, 0), no); + } + } + } else if (y==0) { + NormAdd(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, x), no); + if (!yLimitNext || xnumVerts, 0, x+1), no); + } else if (x==0) { + NormAdd(FACE_getIFNo(f, lvl, (S-1+f->numVerts)%f->numVerts, y, 0), no); + if (!xLimitPrev || ynumVerts)%f->numVerts, y+1, 0), no); + } + } + } + } + } + // XXX can I reduce the number of normalisations here? + for (ptrIdx=0; ptrIdxnumFaces; i++) { + CCGFace *f = v->faces[i]; + NormAdd(no, FACE_getIFNo(f, lvl, _face_getVertIndex(f,v), gridSize-1, gridSize-1)); + } + + length = sqrt(no[0]*no[0] + no[1]*no[1] + no[2]*no[2]); + + if (length>FLT_EPSILON) { + float invLength = 1.0f/length; + no[0] *= invLength; + no[1] *= invLength; + no[2] *= invLength; + } else { + NormZero(no); + } + + for (i=0; inumFaces; i++) { + CCGFace *f = v->faces[i]; + NormCopy(FACE_getIFNo(f, lvl, _face_getVertIndex(f,v), gridSize-1, gridSize-1), no); + } + } + for (ptrIdx=0; ptrIdxnumFaces) { + CCGFace *fLast = e->faces[e->numFaces-1]; + int x; + + for (i=0; inumFaces-1; i++) { + CCGFace *f = e->faces[i]; + + for (x=1; xnumFaces-1; i++) { + CCGFace *f = e->faces[i]; + + for (x=1; xnumVerts; S++) { + NormCopy(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, gridSize-1), + FACE_getIFNo(f, lvl, S, gridSize-1, 0)); + } + } + for (ptrIdx=0; ptrIdxnumVerts; S++) { + for (y=0; yFLT_EPSILON) { + float invLength = 1.0f/length; + no[0] *= invLength; + no[1] *= invLength; + no[2] *= invLength; + } else { + NormZero(no); + } + } + } + } + } + } +#undef FACE_getIFNo + + for (ptrIdx=0; ptrIdxflags = 0; + } + for (ptrIdx=0; ptrIdxflags = 0; + } + +#undef VERT_getCo +#undef EDGE_getCo +#undef FACE_getIECo +#undef FACE_getIFCo + + CCGSUBSURF_free(ss, effectedF); + CCGSUBSURF_free(ss, effectedE); + CCGSUBSURF_free(ss, effectedV); +} + +/*** External API accessor functions ***/ + +int ccgSubSurf_getNumVerts(CCGSubSurf *ss) { + return ss->vMap->numEntries; +} +int ccgSubSurf_getNumEdges(CCGSubSurf *ss) { + return ss->eMap->numEntries; +} +int ccgSubSurf_getNumFaces(CCGSubSurf *ss) { + return ss->fMap->numEntries; +} + +CCGVert *ccgSubSurf_getVert(CCGSubSurf *ss, CCGVertHDL v) { + return (CCGVert*) _ehash_lookup(ss->vMap, v); +} +CCGEdge *ccgSubSurf_getEdge(CCGSubSurf *ss, CCGEdgeHDL e) { + return (CCGEdge*) _ehash_lookup(ss->eMap, e); +} +CCGFace *ccgSubSurf_getFace(CCGSubSurf *ss, CCGFaceHDL f) { + return (CCGFace*) _ehash_lookup(ss->fMap, f); +} + +int ccgSubSurf_getSubdivisionLevels(CCGSubSurf *ss) { + return ss->subdivLevels; +} +int ccgSubSurf_getEdgeSize(CCGSubSurf *ss) { + return ccgSubSurf_getEdgeLevelSize(ss, ss->subdivLevels); +} +int ccgSubSurf_getEdgeLevelSize(CCGSubSurf *ss, int level) { + if (level<1 || level>ss->subdivLevels) { + return -1; + } else { + return 1 + (1<subdivLevels); +} +int ccgSubSurf_getGridLevelSize(CCGSubSurf *ss, int level) { + if (level<1 || level>ss->subdivLevels) { + return -1; + } else { + return 1 + (1<<(level-1)); + } +} + +/* Vert accessors */ + +CCGVertHDL ccgSubSurf_getVertVertHandle(CCGSubSurf *ss, CCGVert *v) { + return v->vHDL; +} +int ccgSubSurf_getVertAge(CCGSubSurf *ss, CCGVert *v) { + if (ss->useAgeCounts) { + byte *userData = ccgSubSurf_getVertUserData(ss, v); + return ss->currentAge - *((int*) &userData[ss->vertUserAgeOffset]); + } else { + return 0; + } +} +void *ccgSubSurf_getVertUserData(CCGSubSurf *ss, CCGVert *v) { + return VERT_getLevelData(v) + ss->meshIFC.vertDataSize*(ss->subdivLevels+1); +} +int ccgSubSurf_getVertNumFaces(CCGSubSurf *ss, CCGVert *v) { + return v->numFaces; +} +CCGFace *ccgSubSurf_getVertFace(CCGSubSurf *ss, CCGVert *v, int index) { + if (index<0 || index>=v->numFaces) { + return NULL; + } else { + return v->faces[index]; + } +} +int ccgSubSurf_getVertNumEdges(CCGSubSurf *ss, CCGVert *v) { + return v->numEdges; +} +CCGEdge *ccgSubSurf_getVertEdge(CCGSubSurf *ss, CCGVert *v, int index) { + if (index<0 || index>=v->numEdges) { + return NULL; + } else { + return v->edges[index]; + } +} +void *ccgSubSurf_getVertData(CCGSubSurf *ss, CCGVert *v) { + return ccgSubSurf_getVertLevelData(ss, v, ss->subdivLevels); +} +void *ccgSubSurf_getVertLevelData(CCGSubSurf *ss, CCGVert *v, int level) { + if (level<0 || level>ss->subdivLevels) { + return NULL; + } else { + return _vert_getCo(v, level, ss->meshIFC.vertDataSize); + } +} + +/* Edge accessors */ + +CCGEdgeHDL ccgSubSurf_getEdgeEdgeHandle(CCGSubSurf *ss, CCGEdge *e) { + return e->eHDL; +} +int ccgSubSurf_getEdgeAge(CCGSubSurf *ss, CCGEdge *e) { + if (ss->useAgeCounts) { + byte *userData = ccgSubSurf_getEdgeUserData(ss, e); + return ss->currentAge - *((int*) &userData[ss->edgeUserAgeOffset]); + } else { + return 0; + } +} +void *ccgSubSurf_getEdgeUserData(CCGSubSurf *ss, CCGEdge *e) { + return EDGE_getLevelData(e) + ss->meshIFC.vertDataSize *((ss->subdivLevels+1) + (1<<(ss->subdivLevels+1))-1); +} +int ccgSubSurf_getEdgeNumFaces(CCGSubSurf *ss, CCGEdge *e) { + return e->numFaces; +} +CCGFace *ccgSubSurf_getEdgeFace(CCGSubSurf *ss, CCGEdge *e, int index) { + if (index<0 || index>=e->numFaces) { + return NULL; + } else { + return e->faces[index]; + } +} +CCGVert *ccgSubSurf_getEdgeVert0(CCGSubSurf *ss, CCGEdge *e) { + return e->v0; +} +CCGVert *ccgSubSurf_getEdgeVert1(CCGSubSurf *ss, CCGEdge *e) { + return e->v1; +} +void *ccgSubSurf_getEdgeDataArray(CCGSubSurf *ss, CCGEdge *e) { + return ccgSubSurf_getEdgeData(ss, e, 0); +} +void *ccgSubSurf_getEdgeData(CCGSubSurf *ss, CCGEdge *e, int x) { + return ccgSubSurf_getEdgeLevelData(ss, e, x, ss->subdivLevels); +} +void *ccgSubSurf_getEdgeLevelData(CCGSubSurf *ss, CCGEdge *e, int x, int level) { + if (level<0 || level>ss->subdivLevels) { + return NULL; + } else { + return _edge_getCo(e, level, x, ss->meshIFC.vertDataSize); + } +} +float ccgSubSurf_getEdgeCrease(CCGSubSurf *ss, CCGEdge *e) { + return e->crease; +} + +/* Face accessors */ + +CCGFaceHDL ccgSubSurf_getFaceFaceHandle(CCGSubSurf *ss, CCGFace *f) { + return f->fHDL; +} +int ccgSubSurf_getFaceAge(CCGSubSurf *ss, CCGFace *f) { + if (ss->useAgeCounts) { + byte *userData = ccgSubSurf_getFaceUserData(ss, f); + return ss->currentAge - *((int*) &userData[ss->faceUserAgeOffset]); + } else { + return 0; + } +} +void *ccgSubSurf_getFaceUserData(CCGSubSurf *ss, CCGFace *f) { + int maxGridSize = 1 + (1<<(ss->subdivLevels-1)); + return FACE_getCenterData(f) + ss->meshIFC.vertDataSize *(1 + f->numVerts*maxGridSize + f->numVerts*maxGridSize*maxGridSize); +} +int ccgSubSurf_getFaceNumVerts(CCGSubSurf *ss, CCGFace *f) { + return f->numVerts; +} +CCGVert *ccgSubSurf_getFaceVert(CCGSubSurf *ss, CCGFace *f, int index) { + if (index<0 || index>=f->numVerts) { + return NULL; + } else { + return FACE_getVerts(f)[index]; + } +} +CCGEdge *ccgSubSurf_getFaceEdge(CCGSubSurf *ss, CCGFace *f, int index) { + if (index<0 || index>=f->numVerts) { + return NULL; + } else { + return FACE_getEdges(f)[index]; + } +} +int ccgSubSurf_getFaceEdgeIndex(CCGSubSurf *ss, CCGFace *f, CCGEdge *e) { + int i; + + for (i=0; inumVerts; i++) + if (FACE_getEdges(f)[i]==e) + return i; + + return -1; +} +void *ccgSubSurf_getFaceCenterData(CCGSubSurf *ss, CCGFace *f) { + return FACE_getCenterData(f); +} +void *ccgSubSurf_getFaceGridEdgeDataArray(CCGSubSurf *ss, CCGFace *f, int gridIndex) { + return ccgSubSurf_getFaceGridEdgeData(ss, f, gridIndex, 0); +} +void *ccgSubSurf_getFaceGridEdgeData(CCGSubSurf *ss, CCGFace *f, int gridIndex, int x) { + return _face_getIECo(f, ss->subdivLevels, gridIndex, x, ss->subdivLevels, ss->meshIFC.vertDataSize); +} +void *ccgSubSurf_getFaceGridDataArray(CCGSubSurf *ss, CCGFace *f, int gridIndex) { + return ccgSubSurf_getFaceGridData(ss, f, gridIndex, 0, 0); +} +void *ccgSubSurf_getFaceGridData(CCGSubSurf *ss, CCGFace *f, int gridIndex, int x, int y) { + return _face_getIFCo(f, ss->subdivLevels, gridIndex, x, y, ss->subdivLevels, ss->meshIFC.vertDataSize); +} + +/*** External API iterator functions ***/ + +CCGVertIterator *ccgSubSurf_getVertIterator(CCGSubSurf *ss) { + return (CCGVertIterator*) _ehashIterator_new(ss->vMap); +} +CCGEdgeIterator *ccgSubSurf_getEdgeIterator(CCGSubSurf *ss) { + return (CCGEdgeIterator*) _ehashIterator_new(ss->eMap); +} +CCGFaceIterator *ccgSubSurf_getFaceIterator(CCGSubSurf *ss) { + return (CCGFaceIterator*) _ehashIterator_new(ss->fMap); +} + +CCGVert *ccgVertIterator_getCurrent(CCGVertIterator *vi) { + return (CCGVert*) _ehashIterator_getCurrent((EHashIterator*) vi); +} +int ccgVertIterator_isStopped(CCGVertIterator *vi) { + return _ehashIterator_isStopped((EHashIterator*) vi); +} +void ccgVertIterator_next(CCGVertIterator *vi) { + _ehashIterator_next((EHashIterator*) vi); +} +void ccgVertIterator_free(CCGVertIterator *vi) { + _ehashIterator_free((EHashIterator*) vi); +} + +CCGEdge *ccgEdgeIterator_getCurrent(CCGEdgeIterator *vi) { + return (CCGEdge*) _ehashIterator_getCurrent((EHashIterator*) vi); +} +int ccgEdgeIterator_isStopped(CCGEdgeIterator *vi) { + return _ehashIterator_isStopped((EHashIterator*) vi); +} +void ccgEdgeIterator_next(CCGEdgeIterator *vi) { + _ehashIterator_next((EHashIterator*) vi); +} +void ccgEdgeIterator_free(CCGEdgeIterator *vi) { + _ehashIterator_free((EHashIterator*) vi); +} + +CCGFace *ccgFaceIterator_getCurrent(CCGFaceIterator *vi) { + return (CCGFace*) _ehashIterator_getCurrent((EHashIterator*) vi); +} +int ccgFaceIterator_isStopped(CCGFaceIterator *vi) { + return _ehashIterator_isStopped((EHashIterator*) vi); +} +void ccgFaceIterator_next(CCGFaceIterator *vi) { + _ehashIterator_next((EHashIterator*) vi); +} +void ccgFaceIterator_free(CCGFaceIterator *vi) { + _ehashIterator_free((EHashIterator*) vi); +} + +/*** Extern API final vert/edge/face interface ***/ + +int ccgSubSurf_getNumFinalVerts(CCGSubSurf *ss) { + int edgeSize = 1 + (1<subdivLevels); + int gridSize = 1 + (1<<(ss->subdivLevels-1)); + int numFinalVerts = ss->vMap->numEntries + ss->eMap->numEntries*(edgeSize-2) + ss->fMap->numEntries + ss->numGrids*((gridSize-2) + ((gridSize-2)*(gridSize-2))); + return numFinalVerts; +} +int ccgSubSurf_getNumFinalEdges(CCGSubSurf *ss) { + int edgeSize = 1 + (1<subdivLevels); + int gridSize = 1 + (1<<(ss->subdivLevels-1)); + int numFinalEdges = ss->eMap->numEntries*(edgeSize-1) + ss->numGrids*((gridSize-1) + 2*((gridSize-2)*(gridSize-1))); + return numFinalEdges; +} +int ccgSubSurf_getNumFinalFaces(CCGSubSurf *ss) { + int gridSize = 1 + (1<<(ss->subdivLevels-1)); + int numFinalFaces = ss->numGrids*((gridSize-1)*(gridSize-1)); + return numFinalFaces; +} diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h new file mode 100644 index 00000000000..91f3ffab43b --- /dev/null +++ b/source/blender/blenkernel/intern/CCGSubSurf.h @@ -0,0 +1,152 @@ +/* $Id$ */ + +typedef void* CCGMeshHDL; +typedef void* CCGVertHDL; +typedef void* CCGEdgeHDL; +typedef void* CCGFaceHDL; + +typedef struct _CCGVert CCGVert; +typedef struct _CCGEdge CCGEdge; +typedef struct _CCGFace CCGFace; + +typedef struct _CCGMeshIFC CCGMeshIFC; +struct _CCGMeshIFC { + int vertUserSize, edgeUserSize, faceUserSize; + + int vertDataSize; +}; + +/***/ + +typedef void* CCGAllocatorHDL; + +typedef struct _CCGAllocatorIFC CCGAllocatorIFC; +struct _CCGAllocatorIFC { + void* (*alloc) (CCGAllocatorHDL a, int numBytes); + void* (*realloc) (CCGAllocatorHDL a, void *ptr, int newSize, int oldSize); + void (*free) (CCGAllocatorHDL a, void *ptr); + void (*release) (CCGAllocatorHDL a); +}; + +/***/ + +typedef enum { + eCCGError_None = 0, + + eCCGError_InvalidSyncState, + eCCGError_InvalidValue, +} CCGError; + +/***/ + +typedef struct _CCGSubSurf CCGSubSurf; + +CCGSubSurf* ccgSubSurf_new (CCGMeshIFC *ifc, int subdivisionLevels, CCGAllocatorIFC *allocatorIFC, CCGAllocatorHDL allocator); +void ccgSubSurf_free (CCGSubSurf *ss); + +CCGError ccgSubSurf_sync (CCGSubSurf *ss); + +CCGError ccgSubSurf_initFullSync (CCGSubSurf *ss); +CCGError ccgSubSurf_initPartialSync (CCGSubSurf *ss); + +CCGError ccgSubSurf_syncVert (CCGSubSurf *ss, CCGVertHDL vHDL, void *vertData, int seam, CCGVert **v_r); +CCGError ccgSubSurf_syncEdge (CCGSubSurf *ss, CCGEdgeHDL eHDL, CCGVertHDL e_vHDL0, CCGVertHDL e_vHDL1, float crease, CCGEdge **e_r); +CCGError ccgSubSurf_syncFace (CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGVertHDL *vHDLs, CCGFace **f_r); + +CCGError ccgSubSurf_syncVertDel (CCGSubSurf *ss, CCGVertHDL vHDL); +CCGError ccgSubSurf_syncEdgeDel (CCGSubSurf *ss, CCGEdgeHDL eHDL); +CCGError ccgSubSurf_syncFaceDel (CCGSubSurf *ss, CCGFaceHDL fHDL); + +CCGError ccgSubSurf_processSync (CCGSubSurf *ss); + +CCGError ccgSubSurf_setSubdivisionLevels (CCGSubSurf *ss, int subdivisionLevels); + +CCGError ccgSubSurf_setAllowEdgeCreation (CCGSubSurf *ss, int allowEdgeCreation, float defaultCreaseValue, void *defaultUserData); +void ccgSubSurf_getAllowEdgeCreation (CCGSubSurf *ss, int *allowEdgeCreation_r, float *defaultCreaseValue_r, void *defaultUserData_r); + +void ccgSubSurf_getUseAgeCounts (CCGSubSurf *ss, int *useAgeCounts_r, int *vertUserOffset_r, int *edgeUserOffset_r, int *faceUserOffset_r); +CCGError ccgSubSurf_setUseAgeCounts (CCGSubSurf *ss, int useAgeCounts, int vertUserOffset, int edgeUserOffset, int faceUserOffset); + +CCGError ccgSubSurf_setCalcVertexNormals (CCGSubSurf *ss, int useVertNormals, int normalDataOffset); + +/***/ + +int ccgSubSurf_getNumVerts (CCGSubSurf *ss); +int ccgSubSurf_getNumEdges (CCGSubSurf *ss); +int ccgSubSurf_getNumFaces (CCGSubSurf *ss); + +int ccgSubSurf_getSubdivisionLevels (CCGSubSurf *ss); +int ccgSubSurf_getEdgeSize (CCGSubSurf *ss); +int ccgSubSurf_getEdgeLevelSize (CCGSubSurf *ss, int level); +int ccgSubSurf_getGridSize (CCGSubSurf *ss); +int ccgSubSurf_getGridLevelSize (CCGSubSurf *ss, int level); + +CCGVert* ccgSubSurf_getVert (CCGSubSurf *ss, CCGVertHDL v); +CCGVertHDL ccgSubSurf_getVertVertHandle (CCGSubSurf *ss, CCGVert *v); +int ccgSubSurf_getVertNumFaces (CCGSubSurf *ss, CCGVert *v); +CCGFace* ccgSubSurf_getVertFace (CCGSubSurf *ss, CCGVert *v, int index); +int ccgSubSurf_getVertNumEdges (CCGSubSurf *ss, CCGVert *v); +CCGEdge* ccgSubSurf_getVertEdge (CCGSubSurf *ss, CCGVert *v, int index); + +int ccgSubSurf_getVertAge (CCGSubSurf *ss, CCGVert *v); +void* ccgSubSurf_getVertUserData (CCGSubSurf *ss, CCGVert *v); +void* ccgSubSurf_getVertData (CCGSubSurf *ss, CCGVert *v); +void* ccgSubSurf_getVertLevelData (CCGSubSurf *ss, CCGVert *v, int level); + +CCGEdge* ccgSubSurf_getEdge (CCGSubSurf *ss, CCGEdgeHDL e); +CCGEdgeHDL ccgSubSurf_getEdgeEdgeHandle (CCGSubSurf *ss, CCGEdge *e); +int ccgSubSurf_getEdgeNumFaces (CCGSubSurf *ss, CCGEdge *e); +CCGFace* ccgSubSurf_getEdgeFace (CCGSubSurf *ss, CCGEdge *e, int index); +CCGVert* ccgSubSurf_getEdgeVert0 (CCGSubSurf *ss, CCGEdge *e); +CCGVert* ccgSubSurf_getEdgeVert1 (CCGSubSurf *ss, CCGEdge *e); +float ccgSubSurf_getEdgeCrease (CCGSubSurf *ss, CCGEdge *e); + +int ccgSubSurf_getEdgeAge (CCGSubSurf *ss, CCGEdge *e); +void* ccgSubSurf_getEdgeUserData (CCGSubSurf *ss, CCGEdge *e); +void* ccgSubSurf_getEdgeDataArray (CCGSubSurf *ss, CCGEdge *e); +void* ccgSubSurf_getEdgeData (CCGSubSurf *ss, CCGEdge *e, int x); +void* ccgSubSurf_getEdgeLevelData (CCGSubSurf *ss, CCGEdge *e, int x, int level); + +CCGFace* ccgSubSurf_getFace (CCGSubSurf *ss, CCGFaceHDL f); +CCGFaceHDL ccgSubSurf_getFaceFaceHandle (CCGSubSurf *ss, CCGFace *f); +int ccgSubSurf_getFaceNumVerts (CCGSubSurf *ss, CCGFace *f); +CCGVert* ccgSubSurf_getFaceVert (CCGSubSurf *ss, CCGFace *f, int index); +CCGEdge* ccgSubSurf_getFaceEdge (CCGSubSurf *ss, CCGFace *f, int index); +int ccgSubSurf_getFaceEdgeIndex (CCGSubSurf *ss, CCGFace *f, CCGEdge *e); + +int ccgSubSurf_getFaceAge (CCGSubSurf *ss, CCGFace *f); +void* ccgSubSurf_getFaceUserData (CCGSubSurf *ss, CCGFace *f); +void* ccgSubSurf_getFaceCenterData (CCGSubSurf *ss, CCGFace *f); +void* ccgSubSurf_getFaceGridEdgeDataArray (CCGSubSurf *ss, CCGFace *f, int gridIndex); +void* ccgSubSurf_getFaceGridEdgeData (CCGSubSurf *ss, CCGFace *f, int gridIndex, int x); +void* ccgSubSurf_getFaceGridDataArray (CCGSubSurf *ss, CCGFace *f, int gridIndex); +void* ccgSubSurf_getFaceGridData (CCGSubSurf *ss, CCGFace *f, int gridIndex, int x, int y); + +int ccgSubSurf_getNumFinalVerts (CCGSubSurf *ss); +int ccgSubSurf_getNumFinalEdges (CCGSubSurf *ss); +int ccgSubSurf_getNumFinalFaces (CCGSubSurf *ss); + +/***/ + +typedef struct _CCGVertIterator CCGVertIterator; +typedef struct _CCGEdgeIterator CCGEdgeIterator; +typedef struct _CCGFaceIterator CCGFaceIterator; + +CCGVertIterator* ccgSubSurf_getVertIterator (CCGSubSurf *ss); +CCGEdgeIterator* ccgSubSurf_getEdgeIterator (CCGSubSurf *ss); +CCGFaceIterator* ccgSubSurf_getFaceIterator (CCGSubSurf *ss); + +CCGVert* ccgVertIterator_getCurrent (CCGVertIterator *vi); +int ccgVertIterator_isStopped (CCGVertIterator *vi); +void ccgVertIterator_next (CCGVertIterator *vi); +void ccgVertIterator_free (CCGVertIterator *vi); + +CCGEdge* ccgEdgeIterator_getCurrent (CCGEdgeIterator *ei); +int ccgEdgeIterator_isStopped (CCGEdgeIterator *ei); +void ccgEdgeIterator_next (CCGEdgeIterator *ei); +void ccgEdgeIterator_free (CCGEdgeIterator *ei); + +CCGFace* ccgFaceIterator_getCurrent (CCGFaceIterator *fi); +int ccgFaceIterator_isStopped (CCGFaceIterator *fi); +void ccgFaceIterator_next (CCGFaceIterator *fi); +void ccgFaceIterator_free (CCGFaceIterator *fi); diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c new file mode 100644 index 00000000000..4e6d4a31173 --- /dev/null +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -0,0 +1,3310 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "PIL_time.h" + +#include "MEM_guardedalloc.h" + +#include "DNA_effect_types.h" +#include "DNA_mesh_types.h" +#include "DNA_key_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force.h" +#include "DNA_object_fluidsim.h" // N_T +#include "DNA_scene_types.h" // N_T +#include "DNA_texture_types.h" +#include "DNA_view3d_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" +#include "BLI_edgehash.h" +#include "BLI_editVert.h" +#include "BLI_linklist.h" + +#include "BKE_cdderivedmesh.h" +#include "BKE_customdata.h" +#include "BKE_DerivedMesh.h" +#include "BKE_deform.h" +#include "BKE_displist.h" +#include "BKE_effect.h" +#include "BKE_global.h" +#include "BKE_key.h" +#include "BKE_material.h" +#include "BKE_modifier.h" +#include "BKE_mesh.h" +#include "BKE_object.h" +#include "BKE_subsurf.h" +#include "BKE_texture.h" +#include "BKE_utildefines.h" + +#ifdef WITH_VERSE +#include "BKE_verse.h" +#endif + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "multires.h" + +// headers for fluidsim bobj meshes +#include +#include "LBM_fluidsim.h" +#include "elbeem.h" + +/////////////////////////////////// +/////////////////////////////////// + +MVert *dm_getVertArray(DerivedMesh *dm) +{ + MVert *mvert = CustomData_get_layer(&dm->vertData, CD_MVERT); + + if (!mvert) { + mvert = CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, + dm->getNumVerts(dm)); + CustomData_set_layer_flag(&dm->vertData, CD_MVERT, CD_FLAG_TEMPORARY); + dm->copyVertArray(dm, mvert); + } + + return mvert; +} + +MEdge *dm_getEdgeArray(DerivedMesh *dm) +{ + MEdge *medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE); + + if (!medge) { + medge = CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, + dm->getNumEdges(dm)); + CustomData_set_layer_flag(&dm->edgeData, CD_MEDGE, CD_FLAG_TEMPORARY); + dm->copyEdgeArray(dm, medge); + } + + return medge; +} + +MFace *dm_getFaceArray(DerivedMesh *dm) +{ + MFace *mface = CustomData_get_layer(&dm->faceData, CD_MFACE); + + if (!mface) { + mface = CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, + dm->getNumFaces(dm)); + CustomData_set_layer_flag(&dm->faceData, CD_MFACE, CD_FLAG_TEMPORARY); + dm->copyFaceArray(dm, mface); + } + + return mface; +} + +MVert *dm_dupVertArray(DerivedMesh *dm) +{ + MVert *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumVerts(dm), + "dm_dupVertArray tmp"); + + if(tmp) dm->copyVertArray(dm, tmp); + + return tmp; +} + +MEdge *dm_dupEdgeArray(DerivedMesh *dm) +{ + MEdge *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumEdges(dm), + "dm_dupEdgeArray tmp"); + + if(tmp) dm->copyEdgeArray(dm, tmp); + + return tmp; +} + +MFace *dm_dupFaceArray(DerivedMesh *dm) +{ + MFace *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumFaces(dm), + "dm_dupFaceArray tmp"); + + if(tmp) dm->copyFaceArray(dm, tmp); + + return tmp; +} + +void DM_init_funcs(DerivedMesh *dm) +{ + /* default function implementations */ + dm->getVertArray = dm_getVertArray; + dm->getEdgeArray = dm_getEdgeArray; + dm->getFaceArray = dm_getFaceArray; + dm->dupVertArray = dm_dupVertArray; + dm->dupEdgeArray = dm_dupEdgeArray; + dm->dupFaceArray = dm_dupFaceArray; + + dm->getVertData = DM_get_vert_data; + dm->getEdgeData = DM_get_edge_data; + dm->getFaceData = DM_get_face_data; + dm->getVertDataArray = DM_get_vert_data_layer; + dm->getEdgeDataArray = DM_get_edge_data_layer; + dm->getFaceDataArray = DM_get_face_data_layer; +} + +void DM_init(DerivedMesh *dm, + int numVerts, int numEdges, int numFaces) +{ + CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, numVerts); + CustomData_add_layer(&dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges); + CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, numFaces); + + dm->numVertData = numVerts; + dm->numEdgeData = numEdges; + dm->numFaceData = numFaces; + + DM_init_funcs(dm); + + dm->needsFree = 1; +} + +void DM_from_template(DerivedMesh *dm, DerivedMesh *source, + int numVerts, int numEdges, int numFaces) +{ + CustomData_copy(&source->vertData, &dm->vertData, CD_MASK_DERIVEDMESH, + CD_CALLOC, numVerts); + CustomData_copy(&source->edgeData, &dm->edgeData, CD_MASK_DERIVEDMESH, + CD_CALLOC, numEdges); + CustomData_copy(&source->faceData, &dm->faceData, CD_MASK_DERIVEDMESH, + CD_CALLOC, numFaces); + + dm->numVertData = numVerts; + dm->numEdgeData = numEdges; + dm->numFaceData = numFaces; + + DM_init_funcs(dm); + + dm->needsFree = 1; +} + +int DM_release(DerivedMesh *dm) +{ + if (dm->needsFree) { + CustomData_free(&dm->vertData, dm->numVertData); + CustomData_free(&dm->edgeData, dm->numEdgeData); + CustomData_free(&dm->faceData, dm->numFaceData); + + return 1; + } + else { + CustomData_free_temporary(&dm->vertData, dm->numVertData); + CustomData_free_temporary(&dm->edgeData, dm->numEdgeData); + CustomData_free_temporary(&dm->faceData, dm->numFaceData); + + return 0; + } +} + +void DM_to_mesh(DerivedMesh *dm, Mesh *me) +{ + /* dm might depend on me, so we need to do everything with a local copy */ + Mesh tmp = *me; + int totvert, totedge, totface; + + memset(&tmp.vdata, 0, sizeof(tmp.vdata)); + memset(&tmp.edata, 0, sizeof(tmp.edata)); + memset(&tmp.fdata, 0, sizeof(tmp.fdata)); + + totvert = tmp.totvert = dm->getNumVerts(dm); + totedge = tmp.totedge = dm->getNumEdges(dm); + totface = tmp.totface = dm->getNumFaces(dm); + + CustomData_copy(&dm->vertData, &tmp.vdata, CD_MASK_MESH, CD_DUPLICATE, totvert); + CustomData_copy(&dm->edgeData, &tmp.edata, CD_MASK_MESH, CD_DUPLICATE, totedge); + CustomData_copy(&dm->faceData, &tmp.fdata, CD_MASK_MESH, CD_DUPLICATE, totface); + + /* not all DerivedMeshes store their verts/edges/faces in CustomData, so + we set them here in case they are missing */ + if(!CustomData_has_layer(&tmp.vdata, CD_MVERT)) + CustomData_add_layer(&tmp.vdata, CD_MVERT, CD_ASSIGN, dm->dupVertArray(dm), totvert); + if(!CustomData_has_layer(&tmp.edata, CD_MEDGE)) + CustomData_add_layer(&tmp.edata, CD_MEDGE, CD_ASSIGN, dm->dupEdgeArray(dm), totedge); + if(!CustomData_has_layer(&tmp.fdata, CD_MFACE)) + CustomData_add_layer(&tmp.fdata, CD_MFACE, CD_ASSIGN, dm->dupFaceArray(dm), totface); + + mesh_update_customdata_pointers(&tmp); + + CustomData_free(&me->vdata, me->totvert); + CustomData_free(&me->edata, me->totedge); + CustomData_free(&me->fdata, me->totface); + + /* if the number of verts has changed, remove invalid data */ + if(tmp.totvert != me->totvert) { + if(me->key) me->key->id.us--; + me->key = NULL; + } + + *me = tmp; +} + +void DM_set_only_copy(DerivedMesh *dm, CustomDataMask mask) +{ + CustomData_set_only_copy(&dm->vertData, mask); + CustomData_set_only_copy(&dm->edgeData, mask); + CustomData_set_only_copy(&dm->faceData, mask); +} + +void DM_add_vert_layer(DerivedMesh *dm, int type, int alloctype, void *layer) +{ + CustomData_add_layer(&dm->vertData, type, alloctype, layer, dm->numVertData); +} + +void DM_add_edge_layer(DerivedMesh *dm, int type, int alloctype, void *layer) +{ + CustomData_add_layer(&dm->edgeData, type, alloctype, layer, dm->numEdgeData); +} + +void DM_add_face_layer(DerivedMesh *dm, int type, int alloctype, void *layer) +{ + CustomData_add_layer(&dm->faceData, type, alloctype, layer, dm->numFaceData); +} + +void *DM_get_vert_data(DerivedMesh *dm, int index, int type) +{ + return CustomData_get(&dm->vertData, index, type); +} + +void *DM_get_edge_data(DerivedMesh *dm, int index, int type) +{ + return CustomData_get(&dm->edgeData, index, type); +} + +void *DM_get_face_data(DerivedMesh *dm, int index, int type) +{ + return CustomData_get(&dm->faceData, index, type); +} + +void *DM_get_vert_data_layer(DerivedMesh *dm, int type) +{ + return CustomData_get_layer(&dm->vertData, type); +} + +void *DM_get_edge_data_layer(DerivedMesh *dm, int type) +{ + return CustomData_get_layer(&dm->edgeData, type); +} + +void *DM_get_face_data_layer(DerivedMesh *dm, int type) +{ + return CustomData_get_layer(&dm->faceData, type); +} + +void DM_set_vert_data(DerivedMesh *dm, int index, int type, void *data) +{ + CustomData_set(&dm->vertData, index, type, data); +} + +void DM_set_edge_data(DerivedMesh *dm, int index, int type, void *data) +{ + CustomData_set(&dm->edgeData, index, type, data); +} + +void DM_set_face_data(DerivedMesh *dm, int index, int type, void *data) +{ + CustomData_set(&dm->faceData, index, type, data); +} + +void DM_copy_vert_data(DerivedMesh *source, DerivedMesh *dest, + int source_index, int dest_index, int count) +{ + CustomData_copy_data(&source->vertData, &dest->vertData, + source_index, dest_index, count); +} + +void DM_copy_edge_data(DerivedMesh *source, DerivedMesh *dest, + int source_index, int dest_index, int count) +{ + CustomData_copy_data(&source->edgeData, &dest->edgeData, + source_index, dest_index, count); +} + +void DM_copy_face_data(DerivedMesh *source, DerivedMesh *dest, + int source_index, int dest_index, int count) +{ + CustomData_copy_data(&source->faceData, &dest->faceData, + source_index, dest_index, count); +} + +void DM_free_vert_data(struct DerivedMesh *dm, int index, int count) +{ + CustomData_free_elem(&dm->vertData, index, count); +} + +void DM_free_edge_data(struct DerivedMesh *dm, int index, int count) +{ + CustomData_free_elem(&dm->edgeData, index, count); +} + +void DM_free_face_data(struct DerivedMesh *dm, int index, int count) +{ + CustomData_free_elem(&dm->faceData, index, count); +} + +void DM_interp_vert_data(DerivedMesh *source, DerivedMesh *dest, + int *src_indices, float *weights, + int count, int dest_index) +{ + CustomData_interp(&source->vertData, &dest->vertData, src_indices, + weights, NULL, count, dest_index); +} + +void DM_interp_edge_data(DerivedMesh *source, DerivedMesh *dest, + int *src_indices, + float *weights, EdgeVertWeight *vert_weights, + int count, int dest_index) +{ + CustomData_interp(&source->edgeData, &dest->edgeData, src_indices, + weights, (float*)vert_weights, count, dest_index); +} + +void DM_interp_face_data(DerivedMesh *source, DerivedMesh *dest, + int *src_indices, + float *weights, FaceVertWeight *vert_weights, + int count, int dest_index) +{ + CustomData_interp(&source->faceData, &dest->faceData, src_indices, + weights, (float*)vert_weights, count, dest_index); +} + +void DM_swap_face_data(DerivedMesh *dm, int index, int *corner_indices) +{ + CustomData_swap(&dm->faceData, index, corner_indices); +} + +static DerivedMesh *getMeshDerivedMesh(Mesh *me, Object *ob, float (*vertCos)[3]) +{ + DerivedMesh *dm = CDDM_from_mesh(me, ob); + int i, dofluidsim; + + dofluidsim = ((ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) && + (ob->fluidsimSettings->type & OB_FLUIDSIM_DOMAIN)&& + (ob->fluidsimSettings->meshSurface) && + (1) && (!give_parteff(ob)) && // doesnt work together with particle systems! + (me->totvert == ((Mesh *)(ob->fluidsimSettings->meshSurface))->totvert)); + + if (vertCos && !dofluidsim) + CDDM_apply_vert_coords(dm, vertCos); + + CDDM_calc_normals(dm); + + /* apply fluidsim normals */ + if (dofluidsim) { + // use normals from readBobjgz + // TODO? check for modifiers!? + MVert *fsvert = ob->fluidsimSettings->meshSurfNormals; + short (*normals)[3] = MEM_mallocN(sizeof(short)*3*me->totvert, "fluidsim nor"); + + for (i=0; itotvert; i++) { + VECCOPY(normals[i], fsvert[i].no); + //mv->no[0]= 30000; mv->no[1]= mv->no[2]= 0; // DEBUG fixed test normals + } + + CDDM_apply_vert_normals(dm, normals); + + MEM_freeN(normals); + } + + return dm; +} + +/// + +typedef struct { + DerivedMesh dm; + + EditMesh *em; + float (*vertexCos)[3]; + float (*vertexNos)[3]; + float (*faceNos)[3]; +} EditMeshDerivedMesh; + +static void emDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData) +{ + EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + EditVert *eve; + int i; + + for (i=0,eve= emdm->em->verts.first; eve; i++,eve=eve->next) { + if (emdm->vertexCos) { + func(userData, i, emdm->vertexCos[i], emdm->vertexNos[i], NULL); + } else { + func(userData, i, eve->co, eve->no, NULL); + } + } +} +static void emDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData) +{ + EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + EditEdge *eed; + int i; + + if (emdm->vertexCos) { + EditVert *eve; + + for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next) + eve->tmp.l = (long) i++; + for(i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) + func(userData, i, emdm->vertexCos[(int) eed->v1->tmp.l], emdm->vertexCos[(int) eed->v2->tmp.l]); + } else { + for(i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) + func(userData, i, eed->v1->co, eed->v2->co); + } +} +static void emDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) +{ + EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + EditEdge *eed; + int i; + + if (emdm->vertexCos) { + EditVert *eve; + + for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next) + eve->tmp.l = (long) i++; + + glBegin(GL_LINES); + for(i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) { + if(!setDrawOptions || setDrawOptions(userData, i)) { + glVertex3fv(emdm->vertexCos[(int) eed->v1->tmp.l]); + glVertex3fv(emdm->vertexCos[(int) eed->v2->tmp.l]); + } + } + glEnd(); + } else { + glBegin(GL_LINES); + for(i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) { + if(!setDrawOptions || setDrawOptions(userData, i)) { + glVertex3fv(eed->v1->co); + glVertex3fv(eed->v2->co); + } + } + glEnd(); + } +} +static void emDM_drawEdges(DerivedMesh *dm, int drawLooseEdges) +{ + emDM_drawMappedEdges(dm, NULL, NULL); +} +static void emDM_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void (*setDrawInterpOptions)(void *userData, int index, float t), void *userData) +{ + EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + EditEdge *eed; + int i; + + if (emdm->vertexCos) { + EditVert *eve; + + for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next) + eve->tmp.l = (long) i++; + + glBegin(GL_LINES); + for (i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) { + if(!setDrawOptions || setDrawOptions(userData, i)) { + setDrawInterpOptions(userData, i, 0.0); + glVertex3fv(emdm->vertexCos[(int) eed->v1->tmp.l]); + setDrawInterpOptions(userData, i, 1.0); + glVertex3fv(emdm->vertexCos[(int) eed->v2->tmp.l]); + } + } + glEnd(); + } else { + glBegin(GL_LINES); + for (i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) { + if(!setDrawOptions || setDrawOptions(userData, i)) { + setDrawInterpOptions(userData, i, 0.0); + glVertex3fv(eed->v1->co); + setDrawInterpOptions(userData, i, 1.0); + glVertex3fv(eed->v2->co); + } + } + glEnd(); + } +} + +static void emDM_drawUVEdges(DerivedMesh *dm) +{ + EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + EditFace *efa; + MTFace *tf; + + glBegin(GL_LINES); + for(efa= emdm->em->faces.first; efa; efa= efa->next) { + tf = CustomData_em_get(&emdm->em->fdata, efa->data, CD_MTFACE); + + if(tf && !(efa->h)) { + glVertex2fv(tf->uv[0]); + glVertex2fv(tf->uv[1]); + + glVertex2fv(tf->uv[1]); + glVertex2fv(tf->uv[2]); + + if (!efa->v4) { + glVertex2fv(tf->uv[2]); + glVertex2fv(tf->uv[0]); + } else { + glVertex2fv(tf->uv[2]); + glVertex2fv(tf->uv[3]); + glVertex2fv(tf->uv[3]); + glVertex2fv(tf->uv[0]); + } + } + } + glEnd(); +} + +static void emDM__calcFaceCent(EditFace *efa, float cent[3], float (*vertexCos)[3]) +{ + if (vertexCos) { + VECCOPY(cent, vertexCos[(int) efa->v1->tmp.l]); + VecAddf(cent, cent, vertexCos[(int) efa->v2->tmp.l]); + VecAddf(cent, cent, vertexCos[(int) efa->v3->tmp.l]); + if (efa->v4) VecAddf(cent, cent, vertexCos[(int) efa->v4->tmp.l]); + } else { + VECCOPY(cent, efa->v1->co); + VecAddf(cent, cent, efa->v2->co); + VecAddf(cent, cent, efa->v3->co); + if (efa->v4) VecAddf(cent, cent, efa->v4->co); + } + + if (efa->v4) { + VecMulf(cent, 0.25f); + } else { + VecMulf(cent, 0.33333333333f); + } +} +static void emDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData) +{ + EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + EditVert *eve; + EditFace *efa; + float cent[3]; + int i; + + if (emdm->vertexCos) { + for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next) + eve->tmp.l = (long) i++; + } + + for(i=0,efa= emdm->em->faces.first; efa; i++,efa= efa->next) { + emDM__calcFaceCent(efa, cent, emdm->vertexCos); + func(userData, i, cent, emdm->vertexCos?emdm->faceNos[i]:efa->n); + } +} +static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors) +{ + GLubyte act_face_stipple[32*32/8] = DM_FACE_STIPPLE; + EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + EditFace *efa; + int i, draw; + + if (emdm->vertexCos) { + EditVert *eve; + + for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next) + eve->tmp.l = (long) i++; + + for (i=0,efa= emdm->em->faces.first; efa; i++,efa= efa->next) { + int drawSmooth = (efa->flag & ME_SMOOTH); + draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, i, &drawSmooth); + if(draw) { + if (draw==2) { /* enabled with stipple */ + glEnable(GL_POLYGON_STIPPLE); + glPolygonStipple(act_face_stipple); + } + + glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT); + + glBegin(efa->v4?GL_QUADS:GL_TRIANGLES); + if (!drawSmooth) { + glNormal3fv(emdm->faceNos[i]); + glVertex3fv(emdm->vertexCos[(int) efa->v1->tmp.l]); + glVertex3fv(emdm->vertexCos[(int) efa->v2->tmp.l]); + glVertex3fv(emdm->vertexCos[(int) efa->v3->tmp.l]); + if(efa->v4) glVertex3fv(emdm->vertexCos[(int) efa->v4->tmp.l]); + } else { + glNormal3fv(emdm->vertexNos[(int) efa->v1->tmp.l]); + glVertex3fv(emdm->vertexCos[(int) efa->v1->tmp.l]); + glNormal3fv(emdm->vertexNos[(int) efa->v2->tmp.l]); + glVertex3fv(emdm->vertexCos[(int) efa->v2->tmp.l]); + glNormal3fv(emdm->vertexNos[(int) efa->v3->tmp.l]); + glVertex3fv(emdm->vertexCos[(int) efa->v3->tmp.l]); + if(efa->v4) { + glNormal3fv(emdm->vertexNos[(int) efa->v4->tmp.l]); + glVertex3fv(emdm->vertexCos[(int) efa->v4->tmp.l]); + } + } + glEnd(); + + if (draw==2) + glDisable(GL_POLYGON_STIPPLE); + } + } + } else { + for (i=0,efa= emdm->em->faces.first; efa; i++,efa= efa->next) { + int drawSmooth = (efa->flag & ME_SMOOTH); + draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, i, &drawSmooth); + if(draw) { + if (draw==2) { /* enabled with stipple */ + glEnable(GL_POLYGON_STIPPLE); + glPolygonStipple(act_face_stipple); + } + glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT); + + glBegin(efa->v4?GL_QUADS:GL_TRIANGLES); + if (!drawSmooth) { + glNormal3fv(efa->n); + glVertex3fv(efa->v1->co); + glVertex3fv(efa->v2->co); + glVertex3fv(efa->v3->co); + if(efa->v4) glVertex3fv(efa->v4->co); + } else { + glNormal3fv(efa->v1->no); + glVertex3fv(efa->v1->co); + glNormal3fv(efa->v2->no); + glVertex3fv(efa->v2->co); + glNormal3fv(efa->v3->no); + glVertex3fv(efa->v3->co); + if(efa->v4) { + glNormal3fv(efa->v4->no); + glVertex3fv(efa->v4->co); + } + } + glEnd(); + + if (draw==2) + glDisable(GL_POLYGON_STIPPLE); + } + } + } +} + +static void emDM_drawFacesTex_common(DerivedMesh *dm, + int (*drawParams)(MTFace *tface, MCol *mcol, int matnr), + int (*drawParamsMapped)(void *userData, int index), + void *userData) +{ + EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + EditMesh *em= emdm->em; + float (*vertexCos)[3]= emdm->vertexCos; + float (*vertexNos)[3]= emdm->vertexNos; + EditFace *efa; + int i; + + if (vertexCos) { + EditVert *eve; + + for (i=0,eve=em->verts.first; eve; eve= eve->next) + eve->tmp.l = (long) i++; + + for (i=0,efa= em->faces.first; efa; i++,efa= efa->next) { + MTFace *tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + MCol *mcol= CustomData_em_get(&em->fdata, efa->data, CD_MCOL); + unsigned char *cp= NULL; + int drawSmooth= (efa->flag & ME_SMOOTH); + int flag; + + if(drawParams) + flag= drawParams(tf, mcol, efa->mat_nr); + else if(drawParamsMapped) + flag= drawParamsMapped(userData, i); + else + flag= 1; + + if(flag != 0) { /* flag 0 == the face is hidden or invisible */ + if (flag==1 && mcol) + cp= (unsigned char*)mcol; + + glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT); + + glBegin(efa->v4?GL_QUADS:GL_TRIANGLES); + if (!drawSmooth) { + glNormal3fv(emdm->faceNos[i]); + + if(tf) glTexCoord2fv(tf->uv[0]); + if(cp) glColor3ub(cp[3], cp[2], cp[1]); + glVertex3fv(vertexCos[(int) efa->v1->tmp.l]); + + if(tf) glTexCoord2fv(tf->uv[1]); + if(cp) glColor3ub(cp[7], cp[6], cp[5]); + glVertex3fv(vertexCos[(int) efa->v2->tmp.l]); + + if(tf) glTexCoord2fv(tf->uv[2]); + if(cp) glColor3ub(cp[11], cp[10], cp[9]); + glVertex3fv(vertexCos[(int) efa->v3->tmp.l]); + + if(efa->v4) { + if(tf) glTexCoord2fv(tf->uv[3]); + if(cp) glColor3ub(cp[15], cp[14], cp[13]); + glVertex3fv(vertexCos[(int) efa->v4->tmp.l]); + } + } else { + if(tf) glTexCoord2fv(tf->uv[0]); + if(cp) glColor3ub(cp[3], cp[2], cp[1]); + glNormal3fv(vertexNos[(int) efa->v1->tmp.l]); + glVertex3fv(vertexCos[(int) efa->v1->tmp.l]); + + if(tf) glTexCoord2fv(tf->uv[1]); + if(cp) glColor3ub(cp[7], cp[6], cp[5]); + glNormal3fv(vertexNos[(int) efa->v2->tmp.l]); + glVertex3fv(vertexCos[(int) efa->v2->tmp.l]); + + if(tf) glTexCoord2fv(tf->uv[2]); + if(cp) glColor3ub(cp[11], cp[10], cp[9]); + glNormal3fv(vertexNos[(int) efa->v3->tmp.l]); + glVertex3fv(vertexCos[(int) efa->v3->tmp.l]); + + if(efa->v4) { + if(tf) glTexCoord2fv(tf->uv[3]); + if(cp) glColor3ub(cp[15], cp[14], cp[13]); + glNormal3fv(vertexNos[(int) efa->v4->tmp.l]); + glVertex3fv(vertexCos[(int) efa->v4->tmp.l]); + } + } + glEnd(); + } + } + } else { + for (i=0,efa= em->faces.first; efa; i++,efa= efa->next) { + MTFace *tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + MCol *mcol= CustomData_em_get(&em->fdata, efa->data, CD_MCOL); + unsigned char *cp= NULL; + int drawSmooth= (efa->flag & ME_SMOOTH); + int flag; + + if(drawParams) + flag= drawParams(tf, mcol, efa->mat_nr); + else if(drawParamsMapped) + flag= drawParamsMapped(userData, i); + else + flag= 1; + + if(flag != 0) { /* flag 0 == the face is hidden or invisible */ + if (flag==1 && mcol) + cp= (unsigned char*)mcol; + + glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT); + + glBegin(efa->v4?GL_QUADS:GL_TRIANGLES); + if (!drawSmooth) { + glNormal3fv(efa->n); + + if(tf) glTexCoord2fv(tf->uv[0]); + if(cp) glColor3ub(cp[3], cp[2], cp[1]); + glVertex3fv(efa->v1->co); + + if(tf) glTexCoord2fv(tf->uv[1]); + if(cp) glColor3ub(cp[7], cp[6], cp[5]); + glVertex3fv(efa->v2->co); + + if(tf) glTexCoord2fv(tf->uv[2]); + if(cp) glColor3ub(cp[11], cp[10], cp[9]); + glVertex3fv(efa->v3->co); + + if(efa->v4) { + if(tf) glTexCoord2fv(tf->uv[3]); + if(cp) glColor3ub(cp[15], cp[14], cp[13]); + glVertex3fv(efa->v4->co); + } + } else { + if(tf) glTexCoord2fv(tf->uv[0]); + if(cp) glColor3ub(cp[3], cp[2], cp[1]); + glNormal3fv(efa->v1->no); + glVertex3fv(efa->v1->co); + + if(tf) glTexCoord2fv(tf->uv[1]); + if(cp) glColor3ub(cp[7], cp[6], cp[5]); + glNormal3fv(efa->v2->no); + glVertex3fv(efa->v2->co); + + if(tf) glTexCoord2fv(tf->uv[2]); + if(cp) glColor3ub(cp[11], cp[10], cp[9]); + glNormal3fv(efa->v3->no); + glVertex3fv(efa->v3->co); + + if(efa->v4) { + if(tf) glTexCoord2fv(tf->uv[3]); + if(cp) glColor3ub(cp[15], cp[14], cp[13]); + glNormal3fv(efa->v4->no); + glVertex3fv(efa->v4->co); + } + } + glEnd(); + } + } + } +} + +static void emDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr)) +{ + emDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL); +} + +static void emDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) +{ + emDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData); +} + +static void emDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3]) +{ + EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + EditVert *eve; + int i; + + if (emdm->em->verts.first) { + for (i=0,eve= emdm->em->verts.first; eve; i++,eve= eve->next) { + if (emdm->vertexCos) { + DO_MINMAX(emdm->vertexCos[i], min_r, max_r); + } else { + DO_MINMAX(eve->co, min_r, max_r); + } + } + } else { + min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0; + } +} +static int emDM_getNumVerts(DerivedMesh *dm) +{ + EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + + return BLI_countlist(&emdm->em->verts); +} + +static int emDM_getNumEdges(DerivedMesh *dm) +{ + EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + + return BLI_countlist(&emdm->em->edges); +} + +static int emDM_getNumFaces(DerivedMesh *dm) +{ + EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + + return BLI_countlist(&emdm->em->faces); +} + +void emDM_getVert(DerivedMesh *dm, int index, MVert *vert_r) +{ + EditVert *ev = ((EditMeshDerivedMesh *)dm)->em->verts.first; + int i; + + for(i = 0; i < index; ++i) ev = ev->next; + + VECCOPY(vert_r->co, ev->co); + + vert_r->no[0] = ev->no[0] * 32767.0; + vert_r->no[1] = ev->no[1] * 32767.0; + vert_r->no[2] = ev->no[2] * 32767.0; + + /* TODO what to do with vert_r->flag and vert_r->mat_nr? */ + vert_r->mat_nr = 0; +} + +void emDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r) +{ + EditMesh *em = ((EditMeshDerivedMesh *)dm)->em; + EditEdge *ee = em->edges.first; + EditVert *ev, *v1, *v2; + int i; + + for(i = 0; i < index; ++i) ee = ee->next; + + edge_r->crease = (unsigned char) (ee->crease*255.0f); + /* TODO what to do with edge_r->flag? */ + edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER; + if (ee->seam) edge_r->flag |= ME_SEAM; + if (ee->sharp) edge_r->flag |= ME_SHARP; +#if 0 + /* this needs setup of f2 field */ + if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE; +#endif + + /* goddamn, we have to search all verts to find indices */ + v1 = ee->v1; + v2 = ee->v2; + for(i = 0, ev = em->verts.first; v1 || v2; i++, ev = ev->next) { + if(ev == v1) { + edge_r->v1 = i; + v1 = NULL; + } + if(ev == v2) { + edge_r->v2 = i; + v2 = NULL; + } + } +} + +void emDM_getFace(DerivedMesh *dm, int index, MFace *face_r) +{ + EditMesh *em = ((EditMeshDerivedMesh *)dm)->em; + EditFace *ef = em->faces.first; + EditVert *ev, *v1, *v2, *v3, *v4; + int i; + + for(i = 0; i < index; ++i) ef = ef->next; + + face_r->mat_nr = ef->mat_nr; + face_r->flag = ef->flag; + + /* goddamn, we have to search all verts to find indices */ + v1 = ef->v1; + v2 = ef->v2; + v3 = ef->v3; + v4 = ef->v4; + if(!v4) face_r->v4 = 0; + + for(i = 0, ev = em->verts.first; v1 || v2 || v3 || v4; + i++, ev = ev->next) { + if(ev == v1) { + face_r->v1 = i; + v1 = NULL; + } + if(ev == v2) { + face_r->v2 = i; + v2 = NULL; + } + if(ev == v3) { + face_r->v3 = i; + v3 = NULL; + } + if(ev == v4) { + face_r->v4 = i; + v4 = NULL; + } + } + + test_index_face(face_r, NULL, 0, ef->v4?4:3); +} + +void emDM_copyVertArray(DerivedMesh *dm, MVert *vert_r) +{ + EditVert *ev = ((EditMeshDerivedMesh *)dm)->em->verts.first; + + for( ; ev; ev = ev->next, ++vert_r) { + VECCOPY(vert_r->co, ev->co); + + vert_r->no[0] = ev->no[0] * 32767.0; + vert_r->no[1] = ev->no[1] * 32767.0; + vert_r->no[2] = ev->no[2] * 32767.0; + + /* TODO what to do with vert_r->flag and vert_r->mat_nr? */ + vert_r->mat_nr = 0; + vert_r->flag = 0; + } +} + +void emDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r) +{ + EditMesh *em = ((EditMeshDerivedMesh *)dm)->em; + EditEdge *ee = em->edges.first; + EditVert *ev; + int i; + + /* store vertex indices in tmp union */ + for(ev = em->verts.first, i = 0; ev; ev = ev->next, ++i) + ev->tmp.l = (long) i++; + + for( ; ee; ee = ee->next, ++edge_r) { + edge_r->crease = (unsigned char) (ee->crease*255.0f); + /* TODO what to do with edge_r->flag? */ + edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER; + if (ee->seam) edge_r->flag |= ME_SEAM; + if (ee->sharp) edge_r->flag |= ME_SHARP; +#if 0 + /* this needs setup of f2 field */ + if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE; +#endif + + edge_r->v1 = (int)ee->v1->tmp.l; + edge_r->v2 = (int)ee->v2->tmp.l; + } +} + +void emDM_copyFaceArray(DerivedMesh *dm, MFace *face_r) +{ + EditMesh *em = ((EditMeshDerivedMesh *)dm)->em; + EditFace *ef = em->faces.first; + EditVert *ev; + int i; + + /* store vertexes indices in tmp union */ + for(ev = em->verts.first, i = 0; ev; ev = ev->next, ++i) + ev->tmp.l = (long) i; + + for( ; ef; ef = ef->next, ++face_r) { + face_r->mat_nr = ef->mat_nr; + face_r->flag = ef->flag; + + face_r->v1 = (int)ef->v1->tmp.l; + face_r->v2 = (int)ef->v2->tmp.l; + face_r->v3 = (int)ef->v3->tmp.l; + if(ef->v4) face_r->v4 = (int)ef->v4->tmp.l; + else face_r->v4 = 0; + + test_index_face(face_r, NULL, 0, ef->v4?4:3); + } +} + +static void emDM_release(DerivedMesh *dm) +{ + EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + + if (DM_release(dm)) { + if (emdm->vertexCos) { + MEM_freeN(emdm->vertexCos); + MEM_freeN(emdm->vertexNos); + MEM_freeN(emdm->faceNos); + } + + MEM_freeN(emdm); + } +} + +static DerivedMesh *getEditMeshDerivedMesh(EditMesh *em, Object *ob, + float (*vertexCos)[3]) +{ + EditMeshDerivedMesh *emdm = MEM_callocN(sizeof(*emdm), "emdm"); + + DM_init(&emdm->dm, BLI_countlist(&em->verts), + BLI_countlist(&em->edges), BLI_countlist(&em->faces)); + + emdm->dm.getMinMax = emDM_getMinMax; + + emdm->dm.getNumVerts = emDM_getNumVerts; + emdm->dm.getNumEdges = emDM_getNumEdges; + emdm->dm.getNumFaces = emDM_getNumFaces; + + emdm->dm.getVert = emDM_getVert; + emdm->dm.getEdge = emDM_getEdge; + emdm->dm.getFace = emDM_getFace; + emdm->dm.copyVertArray = emDM_copyVertArray; + emdm->dm.copyEdgeArray = emDM_copyEdgeArray; + emdm->dm.copyFaceArray = emDM_copyFaceArray; + + emdm->dm.foreachMappedVert = emDM_foreachMappedVert; + emdm->dm.foreachMappedEdge = emDM_foreachMappedEdge; + emdm->dm.foreachMappedFaceCenter = emDM_foreachMappedFaceCenter; + + emdm->dm.drawEdges = emDM_drawEdges; + emdm->dm.drawMappedEdges = emDM_drawMappedEdges; + emdm->dm.drawMappedEdgesInterp = emDM_drawMappedEdgesInterp; + emdm->dm.drawMappedFaces = emDM_drawMappedFaces; + emdm->dm.drawMappedFacesTex = emDM_drawMappedFacesTex; + emdm->dm.drawFacesTex = emDM_drawFacesTex; + emdm->dm.drawUVEdges = emDM_drawUVEdges; + + emdm->dm.release = emDM_release; + + emdm->em = em; + emdm->vertexCos = vertexCos; + + if(CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) { + EditVert *eve; + int i; + + DM_add_vert_layer(&emdm->dm, CD_MDEFORMVERT, CD_CALLOC, NULL); + + for(eve = em->verts.first, i = 0; eve; eve = eve->next, ++i) + DM_set_vert_data(&emdm->dm, i, CD_MDEFORMVERT, + CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT)); + } + + if(vertexCos) { + EditVert *eve; + EditFace *efa; + int totface = BLI_countlist(&em->faces); + int i; + + for (i=0,eve=em->verts.first; eve; eve= eve->next) + eve->tmp.l = (long) i++; + + emdm->vertexNos = MEM_callocN(sizeof(*emdm->vertexNos)*i, "emdm_vno"); + emdm->faceNos = MEM_mallocN(sizeof(*emdm->faceNos)*totface, "emdm_vno"); + + for(i=0, efa= em->faces.first; efa; i++, efa=efa->next) { + float *v1 = vertexCos[(int) efa->v1->tmp.l]; + float *v2 = vertexCos[(int) efa->v2->tmp.l]; + float *v3 = vertexCos[(int) efa->v3->tmp.l]; + float *no = emdm->faceNos[i]; + + if(efa->v4) { + float *v4 = vertexCos[(int) efa->v4->tmp.l]; + + CalcNormFloat4(v1, v2, v3, v4, no); + VecAddf(emdm->vertexNos[(int) efa->v4->tmp.l], emdm->vertexNos[(int) efa->v4->tmp.l], no); + } + else { + CalcNormFloat(v1, v2, v3, no); + } + + VecAddf(emdm->vertexNos[(int) efa->v1->tmp.l], emdm->vertexNos[(int) efa->v1->tmp.l], no); + VecAddf(emdm->vertexNos[(int) efa->v2->tmp.l], emdm->vertexNos[(int) efa->v2->tmp.l], no); + VecAddf(emdm->vertexNos[(int) efa->v3->tmp.l], emdm->vertexNos[(int) efa->v3->tmp.l], no); + } + + for(i=0, eve= em->verts.first; eve; i++, eve=eve->next) { + float *no = emdm->vertexNos[i]; + /* following Mesh convention; we use vertex coordinate itself + * for normal in this case */ + if (Normalize(no)==0.0) { + VECCOPY(no, vertexCos[i]); + Normalize(no); + } + } + } + + return (DerivedMesh*) emdm; +} + +#ifdef WITH_VERSE + +/* verse derived mesh */ +typedef struct { + struct DerivedMesh dm; + struct VNode *vnode; + struct VLayer *vertex_layer; + struct VLayer *polygon_layer; + struct ListBase *edges; + float (*vertexCos)[3]; +} VDerivedMesh; + +/* this function set up border points of verse mesh bounding box */ +static void vDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3]) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + struct VerseVert *vvert; + + if(!vdm->vertex_layer) return; + + vvert = (VerseVert*)vdm->vertex_layer->dl.lb.first; + + if(vdm->vertex_layer->dl.da.count > 0) { + while(vvert) { + DO_MINMAX(vdm->vertexCos ? vvert->cos : vvert->co, min_r, max_r); + vvert = vvert->next; + } + } + else { + min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0; + } +} + +/* this function return number of vertexes in vertex layer */ +static int vDM_getNumVerts(DerivedMesh *dm) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + + if(!vdm->vertex_layer) return 0; + else return vdm->vertex_layer->dl.da.count; +} + +/* this function return number of 'fake' edges */ +static int vDM_getNumEdges(DerivedMesh *dm) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + + return BLI_countlist(vdm->edges); +} + +/* this function returns number of polygons in polygon layer */ +static int vDM_getNumFaces(DerivedMesh *dm) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + + if(!vdm->polygon_layer) return 0; + else return vdm->polygon_layer->dl.da.count; +} + +/* this function doesn't return vertex with index of access array, + * but it return 'indexth' vertex of dynamic list */ +void vDM_getVert(DerivedMesh *dm, int index, MVert *vert_r) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + struct VerseVert *vvert; + int i; + + if(!vdm->vertex_layer) return; + + for(vvert = vdm->vertex_layer->dl.lb.first, i=0 ; inext; + + if(vvert) { + VECCOPY(vert_r->co, vvert->co); + + vert_r->no[0] = vvert->no[0] * 32767.0; + vert_r->no[1] = vvert->no[1] * 32767.0; + vert_r->no[2] = vvert->no[2] * 32767.0; + + /* TODO what to do with vert_r->flag and vert_r->mat_nr? */ + vert_r->mat_nr = 0; + vert_r->flag = 0; + } +} + +/* this function returns fake verse edge */ +void vDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + struct VerseEdge *vedge; + struct VLayer *vert_vlayer = vdm->vertex_layer; + struct VerseVert *vvert; + int j; + + if(!vdm->vertex_layer || !vdm->edges) return; + + if(vdm->edges->first) { + struct VerseVert *vvert1, *vvert2; + + /* store vert indices in tmp union */ + for(vvert = vdm->vertex_layer->dl.lb.first, j = 0; vvert; vvert = vvert->next, j++) + vvert->tmp.index = j; + + for(vedge = vdm->edges->first; vedge; vedge = vedge->next) { + if(vedge->tmp.index==index) { + vvert1 = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vedge->v0); + vvert2 = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vedge->v1); + + if(vvert1 && vvert2) { + edge_r->v1 = vvert1->tmp.index; + edge_r->v2 = vvert2->tmp.index; + } + else { + edge_r->v1 = 0; + edge_r->v2 = 0; + } + /* not supported yet */ + edge_r->flag = 0; + edge_r->crease = 0; + break; + } + } + } +} + +/* this function doesn't return face with index of access array, + * but it returns 'indexth' vertex of dynamic list */ +void vDM_getFace(DerivedMesh *dm, int index, MFace *face_r) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + struct VerseFace *vface; + struct VerseVert *vvert; + struct VerseVert *vvert0, *vvert1, *vvert2, *vvert3; + int i; + + if(!vdm->vertex_layer || !vdm->polygon_layer) return; + + for(vface = vdm->polygon_layer->dl.lb.first, i = 0; i < index; ++i) vface = vface->next; + + face_r->mat_nr = 0; + face_r->flag = 0; + + /* goddamn, we have to search all verts to find indices */ + vvert0 = vface->vvert0; + vvert1 = vface->vvert1; + vvert2 = vface->vvert2; + vvert3 = vface->vvert3; + if(!vvert3) face_r->v4 = 0; + + for(vvert = vdm->vertex_layer->dl.lb.first, i = 0; vvert0 || vvert1 || vvert2 || vvert3; i++, vvert = vvert->next) { + if(vvert == vvert0) { + face_r->v1 = i; + vvert0 = NULL; + } + if(vvert == vvert1) { + face_r->v2 = i; + vvert1 = NULL; + } + if(vvert == vvert2) { + face_r->v3 = i; + vvert2 = NULL; + } + if(vvert == vvert3) { + face_r->v4 = i; + vvert3 = NULL; + } + } + + test_index_face(face_r, NULL, 0, vface->vvert3?4:3); +} + +/* fill array of mvert */ +void vDM_copyVertArray(DerivedMesh *dm, MVert *vert_r) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + struct VerseVert *vvert; + + if(!vdm->vertex_layer) return; + + for(vvert = vdm->vertex_layer->dl.lb.first ; vvert; vvert = vvert->next, ++vert_r) { + VECCOPY(vert_r->co, vvert->co); + + vert_r->no[0] = vvert->no[0] * 32767.0; + vert_r->no[1] = vvert->no[1] * 32767.0; + vert_r->no[2] = vvert->no[2] * 32767.0; + + vert_r->mat_nr = 0; + vert_r->flag = 0; + } +} + +/* dummy function, edges arent supported in verse mesh */ +void vDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + + if(!vdm->vertex_layer || !vdm->edges) return; + + if(vdm->edges->first) { + struct VerseEdge *vedge; + struct VLayer *vert_vlayer = vdm->vertex_layer; + struct VerseVert *vvert, *vvert1, *vvert2; + int j; + + /* store vert indices in tmp union */ + for(vvert = vdm->vertex_layer->dl.lb.first, j = 0; vvert; vvert = vvert->next, ++j) + vvert->tmp.index = j; + + for(vedge = vdm->edges->first, j=0 ; vedge; vedge = vedge->next, ++edge_r, j++) { + /* create temporary edge index */ + vedge->tmp.index = j; + vvert1 = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vedge->v0); + vvert2 = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vedge->v1); + if(vvert1 && vvert2) { + edge_r->v1 = vvert1->tmp.index; + edge_r->v2 = vvert2->tmp.index; + } + else { + printf("error: vDM_copyEdgeArray: %d, %d\n", vedge->v0, vedge->v1); + edge_r->v1 = 0; + edge_r->v2 = 0; + } + /* not supported yet */ + edge_r->flag = 0; + edge_r->crease = 0; + } + } +} + +/* fill array of mfaces */ +void vDM_copyFaceArray(DerivedMesh *dm, MFace *face_r) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + struct VerseFace *vface; + struct VerseVert *vvert; + int i; + + if(!vdm->vertex_layer || !vdm->polygon_layer) return; + + /* store vertexes indices in tmp union */ + for(vvert = vdm->vertex_layer->dl.lb.first, i = 0; vvert; vvert = vvert->next, ++i) + vvert->tmp.index = i; + + for(vface = vdm->polygon_layer->dl.lb.first; vface; vface = vface->next, ++face_r) { + face_r->mat_nr = 0; + face_r->flag = 0; + + face_r->v1 = vface->vvert0->tmp.index; + face_r->v2 = vface->vvert1->tmp.index; + face_r->v3 = vface->vvert2->tmp.index; + if(vface->vvert3) face_r->v4 = vface->vvert3->tmp.index; + else face_r->v4 = 0; + + test_index_face(face_r, NULL, 0, vface->vvert3?4:3); + } +} + +/* return coordination of vertex with index */ +static void vDM_getVertCo(DerivedMesh *dm, int index, float co_r[3]) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + struct VerseVert *vvert = NULL; + + if(!vdm->vertex_layer) return; + + vvert = BLI_dlist_find_link(&(vdm->vertex_layer->dl), index); + + if(vvert) { + VECCOPY(co_r, vdm->vertexCos ? vvert->cos : vvert->co); + } + else { + co_r[0] = co_r[1] = co_r[2] = 0.0; + } +} + +/* return array of vertex coordiantions */ +static void vDM_getVertCos(DerivedMesh *dm, float (*cos_r)[3]) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + struct VerseVert *vvert; + int i = 0; + + if(!vdm->vertex_layer) return; + + vvert = vdm->vertex_layer->dl.lb.first; + while(vvert) { + VECCOPY(cos_r[i], vdm->vertexCos ? vvert->cos : vvert->co); + i++; + vvert = vvert->next; + } +} + +/* return normal of vertex with index */ +static void vDM_getVertNo(DerivedMesh *dm, int index, float no_r[3]) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + struct VerseVert *vvert = NULL; + + if(!vdm->vertex_layer) return; + + vvert = BLI_dlist_find_link(&(vdm->vertex_layer->dl), index); + if(vvert) { + VECCOPY(no_r, vvert->no); + } + else { + no_r[0] = no_r[1] = no_r[2] = 0.0; + } +} + +/* draw all VerseVertexes */ +static void vDM_drawVerts(DerivedMesh *dm) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + struct VerseVert *vvert; + + if(!vdm->vertex_layer) return; + + vvert = vdm->vertex_layer->dl.lb.first; + + bglBegin(GL_POINTS); + while(vvert) { + bglVertex3fv(vdm->vertexCos ? vvert->cos : vvert->co); + vvert = vvert->next; + } + bglEnd(); +} + +/* draw all edges of VerseFaces ... it isn't optimal, because verse + * specification doesn't support edges :-( ... bother eskil ;-) + * ... some edges (most of edges) are drawn twice */ +static void vDM_drawEdges(DerivedMesh *dm, int drawLooseEdges) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + struct VerseEdge *vedge; + struct VLayer *vert_vlayer = vdm->vertex_layer; + + if(vert_vlayer && vdm->edges && (BLI_countlist(vdm->edges) > 0)) { + struct VerseVert *vvert1, *vvert2; + + glBegin(GL_LINES); + for(vedge = vdm->edges->first; vedge; vedge = vedge->next) { + vvert1 = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vedge->v0); + vvert2 = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vedge->v1); + if(vvert1 && vvert2) { + glVertex3fv(vdm->vertexCos ? vvert1->cos : vvert1->co); + glVertex3fv(vdm->vertexCos ? vvert2->cos : vvert2->co); + } + } + glEnd(); + } +} + +/* verse spec doesn't support edges ... loose edges can't exist */ +void vDM_drawLooseEdges(DerivedMesh *dm) +{ +} + +/* draw uv edges, not supported yet */ +static void vDM_drawUVEdges(DerivedMesh *dm) +{ +} + +/* draw all VerseFaces */ +static void vDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int)) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + struct VerseFace *vface; + + if(!vdm->polygon_layer) return; + + vface = vdm->polygon_layer->dl.lb.first; + + glShadeModel(GL_FLAT); + while(vface) { + glBegin(vface->vvert3?GL_QUADS:GL_TRIANGLES); + glNormal3fv(vface->no); + glVertex3fv(vdm->vertexCos ? vface->vvert0->cos : vface->vvert0->co); + glVertex3fv(vdm->vertexCos ? vface->vvert1->cos : vface->vvert1->co); + glVertex3fv(vdm->vertexCos ? vface->vvert2->cos : vface->vvert2->co); + if(vface->vvert3) + glVertex3fv(vdm->vertexCos ? vface->vvert3->cos : vface->vvert3->co); + glEnd(); + vface = vface->next; + } +} + +/* this function should draw mesh with mapped texture, but it isn't supported yet */ +static void vDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr)) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + struct VerseFace *vface; + + if(!vdm->polygon_layer) return; + + vface = vdm->polygon_layer->dl.lb.first; + + while(vface) { + glBegin(vface->vvert3?GL_QUADS:GL_TRIANGLES); + glVertex3fv(vdm->vertexCos ? vface->vvert0->cos : vface->vvert0->co); + glVertex3fv(vdm->vertexCos ? vface->vvert1->cos : vface->vvert1->co); + glVertex3fv(vdm->vertexCos ? vface->vvert2->cos : vface->vvert2->co); + if(vface->vvert3) + glVertex3fv(vdm->vertexCos ? vface->vvert3->cos : vface->vvert3->co); + glEnd(); + + vface = vface->next; + } +} + +/* this function should draw mesh with colored faces (weight paint, vertex + * colors, etc.), but it isn't supported yet */ +static void vDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned char *col1, unsigned char *col2) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + struct VerseFace *vface; + + if(!vdm->polygon_layer) return; + + vface = vdm->polygon_layer->dl.lb.first; + + while(vface) { + glBegin(vface->vvert3?GL_QUADS:GL_TRIANGLES); + glVertex3fv(vdm->vertexCos ? vface->vvert0->cos : vface->vvert0->co); + glVertex3fv(vdm->vertexCos ? vface->vvert1->cos : vface->vvert1->co); + glVertex3fv(vdm->vertexCos ? vface->vvert2->cos : vface->vvert2->co); + if(vface->vvert3) + glVertex3fv(vdm->vertexCos ? vface->vvert3->cos : vface->vvert3->co); + glEnd(); + + vface = vface->next; + } +} + +/**/ +static void vDM_foreachMappedVert( + DerivedMesh *dm, + void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), + void *userData) +{ +} + +/**/ +static void vDM_foreachMappedEdge( + DerivedMesh *dm, + void (*func)(void *userData, int index, float *v0co, float *v1co), + void *userData) +{ +} + +/**/ +static void vDM_foreachMappedFaceCenter( + DerivedMesh *dm, + void (*func)(void *userData, int index, float *cent, float *no), + void *userData) +{ +} + +/**/ +static void vDM_drawMappedFacesTex( + DerivedMesh *dm, + int (*setDrawParams)(void *userData, int index), + void *userData) +{ +} + +/**/ +static void vDM_drawMappedFaces( + DerivedMesh *dm, + int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), + void *userData, + int useColors) +{ +} + +/**/ +static void vDM_drawMappedEdges( + DerivedMesh *dm, + int (*setDrawOptions)(void *userData, int index), + void *userData) +{ +} + +/**/ +static void vDM_drawMappedEdgesInterp( + DerivedMesh *dm, + int (*setDrawOptions)(void *userData, int index), + void (*setDrawInterpOptions)(void *userData, int index, float t), + void *userData) +{ +} + +/* free all DerivedMesh data */ +static void vDM_release(DerivedMesh *dm) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + + if (DM_release(dm)) { + if(vdm->vertexCos) MEM_freeN(vdm->vertexCos); + MEM_freeN(vdm); + } +} + +/* create derived mesh from verse mesh ... it is used in object mode, when some other client can + * change shared data and want to see this changes in real time too */ +DerivedMesh *derivedmesh_from_versemesh(VNode *vnode, float (*vertexCos)[3]) +{ + VDerivedMesh *vdm = MEM_callocN(sizeof(*vdm), "vdm"); + + vdm->vnode = vnode; + vdm->vertex_layer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); + vdm->polygon_layer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); + vdm->edges = &((VGeomData*)vnode->data)->edges; + + /* vertex and polygon layer has to exist */ + if(vdm->vertex_layer && vdm->polygon_layer) + DM_init(&vdm->dm, vdm->vertex_layer->dl.da.count, BLI_countlist(vdm->edges), vdm->polygon_layer->dl.da.count); + else + DM_init(&vdm->dm, 0, 0, 0); + + vdm->dm.getMinMax = vDM_getMinMax; + + vdm->dm.getNumVerts = vDM_getNumVerts; + vdm->dm.getNumEdges = vDM_getNumEdges; + vdm->dm.getNumFaces = vDM_getNumFaces; + + vdm->dm.getVert = vDM_getVert; + vdm->dm.getEdge = vDM_getEdge; + vdm->dm.getFace = vDM_getFace; + vdm->dm.copyVertArray = vDM_copyVertArray; + vdm->dm.copyEdgeArray = vDM_copyEdgeArray; + vdm->dm.copyFaceArray = vDM_copyFaceArray; + + vdm->dm.foreachMappedVert = vDM_foreachMappedVert; + vdm->dm.foreachMappedEdge = vDM_foreachMappedEdge; + vdm->dm.foreachMappedFaceCenter = vDM_foreachMappedFaceCenter; + + vdm->dm.getVertCos = vDM_getVertCos; + vdm->dm.getVertCo = vDM_getVertCo; + vdm->dm.getVertNo = vDM_getVertNo; + + vdm->dm.drawVerts = vDM_drawVerts; + + vdm->dm.drawEdges = vDM_drawEdges; + vdm->dm.drawLooseEdges = vDM_drawLooseEdges; + vdm->dm.drawUVEdges = vDM_drawUVEdges; + + vdm->dm.drawFacesSolid = vDM_drawFacesSolid; + vdm->dm.drawFacesTex = vDM_drawFacesTex; + vdm->dm.drawFacesColored = vDM_drawFacesColored; + + vdm->dm.drawMappedFacesTex = vDM_drawMappedFacesTex; + vdm->dm.drawMappedFaces = vDM_drawMappedFaces; + vdm->dm.drawMappedEdges = vDM_drawMappedEdges; + vdm->dm.drawMappedEdgesInterp = vDM_drawMappedEdgesInterp; + + vdm->dm.release = vDM_release; + + vdm->vertexCos = vertexCos; + + return (DerivedMesh*) vdm; +} + +#endif + +/***/ + +DerivedMesh *mesh_create_derived_for_modifier(Object *ob, ModifierData *md) +{ + Mesh *me = ob->data; + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + DerivedMesh *dm; + + if (!(md->mode&eModifierMode_Realtime)) return NULL; + if (mti->isDisabled && mti->isDisabled(md)) return NULL; + + if (mti->type==eModifierTypeType_OnlyDeform) { + int numVerts; + float (*deformedVerts)[3] = mesh_getVertexCos(me, &numVerts); + + mti->deformVerts(md, ob, NULL, deformedVerts, numVerts); +#ifdef WITH_VERSE + if(me->vnode) dm = derivedmesh_from_versemesh(me->vnode, deformedVerts); + else dm = getMeshDerivedMesh(me, ob, deformedVerts); +#else + dm = getMeshDerivedMesh(me, ob, deformedVerts); +#endif + + MEM_freeN(deformedVerts); + } else { + DerivedMesh *tdm = getMeshDerivedMesh(me, ob, NULL); + dm = mti->applyModifier(md, ob, tdm, 0, 0); + + if(tdm != dm) tdm->release(tdm); + } + + return dm; +} + +CustomDataMask get_viewedit_datamask() +{ + CustomDataMask mask = CD_MASK_BAREMESH; + ScrArea *sa; + + /* check if we need tfaces & mcols due to face select or texture paint */ + if(FACESEL_PAINT_TEST || G.f & G_TEXTUREPAINT) { + mask |= CD_MASK_MTFACE | CD_MASK_MCOL; + } else { + /* check if we need tfaces & mcols due to view mode */ + for(sa = G.curscreen->areabase.first; sa; sa = sa->next) { + if(sa->spacetype == SPACE_VIEW3D) { + View3D *view = sa->spacedata.first; + if(view->drawtype == OB_SHADED) { + /* this includes normals for mesh_create_shadedColors */ + mask |= CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_NORMAL; + } + if((view->drawtype == OB_TEXTURE) || ((view->drawtype == OB_SOLID) && (view->flag2 & V3D_SOLID_TEX))) { + mask |= CD_MASK_MTFACE | CD_MASK_MCOL; + } + } + } + } + + /* check if we need mcols due to vertex paint or weightpaint */ + if(G.f & G_VERTEXPAINT || G.f & G_WEIGHTPAINT) + mask |= CD_MASK_MCOL; + + return mask; +} + +static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], + DerivedMesh **deform_r, DerivedMesh **final_r, + int useRenderParams, int useDeform, + int needMapping, CustomDataMask dataMask) +{ + Mesh *me = ob->data; + ModifierData *md = modifiers_getVirtualModifierList(ob); + LinkNode *datamasks, *curr; + float (*deformedVerts)[3] = NULL; + DerivedMesh *dm; + int numVerts = me->totvert; + int fluidsimMeshUsed = 0; + int required_mode; + + modifiers_clearErrors(ob); + + /* we always want to keep original indices */ + dataMask |= CD_MASK_ORIGINDEX; + + datamasks = modifiers_calcDataMasks(md, dataMask); + curr = datamasks; + + if(deform_r) *deform_r = NULL; + *final_r = NULL; + + /* replace original mesh by fluidsim surface mesh for fluidsim + * domain objects + */ + if((G.obedit!=ob) && !needMapping) { + if((ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) && + (1) && (!give_parteff(ob)) ) { // doesnt work together with particle systems! + if(ob->fluidsimSettings->type & OB_FLUIDSIM_DOMAIN) { + loadFluidsimMesh(ob,useRenderParams); + fluidsimMeshUsed = 1; + /* might have changed... */ + me = ob->data; + numVerts = me->totvert; + } + } + } + + if(useRenderParams) required_mode = eModifierMode_Render; + else required_mode = eModifierMode_Realtime; + + if(useDeform) { + if(do_ob_key(ob)) /* shape key makes deform verts */ + deformedVerts = mesh_getVertexCos(me, &numVerts); + + /* Apply all leading deforming modifiers */ + for(; md; md = md->next, curr = curr->next) { + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + if((md->mode & required_mode) != required_mode) continue; + if(mti->isDisabled && mti->isDisabled(md)) continue; + + if(mti->type == eModifierTypeType_OnlyDeform) { + if(!deformedVerts) + deformedVerts = mesh_getVertexCos(me, &numVerts); + + mti->deformVerts(md, ob, NULL, deformedVerts, numVerts); + } else { + break; + } + } + + /* Result of all leading deforming modifiers is cached for + * places that wish to use the original mesh but with deformed + * coordinates (vpaint, etc.) + */ + if (deform_r) { +#ifdef WITH_VERSE + if(me->vnode) *deform_r = derivedmesh_from_versemesh(me->vnode, deformedVerts); + else { + *deform_r = CDDM_from_mesh(me, ob); + if(deformedVerts) { + CDDM_apply_vert_coords(*deform_r, deformedVerts); + CDDM_calc_normals(*deform_r); + } + } +#else + *deform_r = CDDM_from_mesh(me, ob); + if(deformedVerts) { + CDDM_apply_vert_coords(*deform_r, deformedVerts); + CDDM_calc_normals(*deform_r); + } +#endif + } + } else { + if(!fluidsimMeshUsed) { + /* default behaviour for meshes */ + if(inputVertexCos) + deformedVerts = inputVertexCos; + else + deformedVerts = mesh_getRefKeyCos(me, &numVerts); + } else { + /* the fluid sim mesh might have more vertices than the original + * one, so inputVertexCos shouldnt be used + */ + deformedVerts = mesh_getVertexCos(me, &numVerts); + } + } + + + /* Now apply all remaining modifiers. If useDeform is off then skip + * OnlyDeform ones. + */ + dm = NULL; + +#ifdef WITH_VERSE + /* hack to make sure modifiers don't try to use mesh data from a verse + * node + */ + if(me->vnode) dm = derivedmesh_from_versemesh(me->vnode, deformedVerts); +#endif + + for(; md; md = md->next, curr = curr->next) { + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + if((md->mode & required_mode) != required_mode) continue; + if(mti->type == eModifierTypeType_OnlyDeform && !useDeform) continue; + if((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) { + modifier_setError(md, "Internal error, modifier requires " + "original data (bad stack position)."); + continue; + } + if(mti->isDisabled && mti->isDisabled(md)) continue; + if(needMapping && !modifier_supportsMapping(md)) continue; + + /* How to apply modifier depends on (a) what we already have as + * a result of previous modifiers (could be a DerivedMesh or just + * deformed vertices) and (b) what type the modifier is. + */ + + if(mti->type == eModifierTypeType_OnlyDeform) { + /* No existing verts to deform, need to build them. */ + if(!deformedVerts) { + if(dm) { + /* Deforming a derived mesh, read the vertex locations + * out of the mesh and deform them. Once done with this + * run of deformers verts will be written back. + */ + numVerts = dm->getNumVerts(dm); + deformedVerts = + MEM_mallocN(sizeof(*deformedVerts) * numVerts, "dfmv"); + dm->getVertCos(dm, deformedVerts); + } else { + deformedVerts = mesh_getVertexCos(me, &numVerts); + } + } + + mti->deformVerts(md, ob, dm, deformedVerts, numVerts); + } else { + DerivedMesh *ndm; + + /* apply vertex coordinates or build a DerivedMesh as necessary */ + if(dm) { + if(deformedVerts) { + DerivedMesh *tdm = CDDM_copy(dm); + dm->release(dm); + dm = tdm; + + CDDM_apply_vert_coords(dm, deformedVerts); + CDDM_calc_normals(dm); + } + } else { + dm = CDDM_from_mesh(me, ob); + + if(deformedVerts) { + CDDM_apply_vert_coords(dm, deformedVerts); + CDDM_calc_normals(dm); + } + } + + /* set the DerivedMesh to only copy needed data */ + DM_set_only_copy(dm, (CustomDataMask)curr->link); + + ndm = mti->applyModifier(md, ob, dm, useRenderParams, + !inputVertexCos); + + if(ndm) { + /* if the modifier returned a new dm, release the old one */ + if(dm && dm != ndm) dm->release(dm); + + dm = ndm; + + if(deformedVerts) { + if(deformedVerts != inputVertexCos) + MEM_freeN(deformedVerts); + + deformedVerts = NULL; + } + } + } + } + + /* Yay, we are done. If we have a DerivedMesh and deformed vertices + * need to apply these back onto the DerivedMesh. If we have no + * DerivedMesh then we need to build one. + */ + if(dm && deformedVerts) { + *final_r = CDDM_copy(dm); + + dm->release(dm); + + CDDM_apply_vert_coords(*final_r, deformedVerts); + CDDM_calc_normals(*final_r); + } else if(dm) { + *final_r = dm; + } else { +#ifdef WITH_VERSE + if(me->vnode) + *final_r = derivedmesh_from_versemesh(me->vnode, deformedVerts); + else { + *final_r = CDDM_from_mesh(me, ob); + if(deformedVerts) { + CDDM_apply_vert_coords(*final_r, deformedVerts); + CDDM_calc_normals(*final_r); + } + } +#else + *final_r = CDDM_from_mesh(me, ob); + if(deformedVerts) { + CDDM_apply_vert_coords(*final_r, deformedVerts); + CDDM_calc_normals(*final_r); + } +#endif + } + + if(deformedVerts && deformedVerts != inputVertexCos) + MEM_freeN(deformedVerts); + + BLI_linklist_free(datamasks, NULL); + + /* restore mesh in any case */ + if(fluidsimMeshUsed) ob->data = ob->fluidsimSettings->orgMesh; +} + +static float (*editmesh_getVertexCos(EditMesh *em, int *numVerts_r))[3] +{ + int i, numVerts = *numVerts_r = BLI_countlist(&em->verts); + float (*cos)[3]; + EditVert *eve; + + cos = MEM_mallocN(sizeof(*cos)*numVerts, "vertexcos"); + for (i=0,eve=em->verts.first; inext) { + VECCOPY(cos[i], eve->co); + } + + return cos; +} + +static int editmesh_modifier_is_enabled(ModifierData *md, DerivedMesh *dm) +{ + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + int required_mode = eModifierMode_Realtime | eModifierMode_Editmode; + + if((md->mode & required_mode) != required_mode) return 0; + if((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) { + modifier_setError(md, "Internal error, modifier requires" + "original data (bad stack position)."); + return 0; + } + if(mti->isDisabled && mti->isDisabled(md)) return 0; + if(!(mti->flags & eModifierTypeFlag_SupportsEditmode)) return 0; + if(md->mode & eModifierMode_DisableTemporary) return 0; + + return 1; +} + +static void editmesh_calc_modifiers(DerivedMesh **cage_r, + DerivedMesh **final_r, + CustomDataMask dataMask) +{ + Object *ob = G.obedit; + EditMesh *em = G.editMesh; + ModifierData *md; + float (*deformedVerts)[3] = NULL; + DerivedMesh *dm; + int i, numVerts = 0, cageIndex = modifiers_getCageIndex(ob, NULL); + LinkNode *datamasks, *curr; + + modifiers_clearErrors(ob); + + if(cage_r && cageIndex == -1) { + *cage_r = getEditMeshDerivedMesh(em, ob, NULL); + } + + dm = NULL; + md = ob->modifiers.first; + + /* we always want to keep original indices */ + dataMask |= CD_MASK_ORIGINDEX; + + datamasks = modifiers_calcDataMasks(md, dataMask); + + curr = datamasks; + for(i = 0; md; i++, md = md->next, curr = curr->next) { + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + if(!editmesh_modifier_is_enabled(md, dm)) + continue; + + /* How to apply modifier depends on (a) what we already have as + * a result of previous modifiers (could be a DerivedMesh or just + * deformed vertices) and (b) what type the modifier is. + */ + + if(mti->type == eModifierTypeType_OnlyDeform) { + /* No existing verts to deform, need to build them. */ + if(!deformedVerts) { + if(dm) { + /* Deforming a derived mesh, read the vertex locations + * out of the mesh and deform them. Once done with this + * run of deformers verts will be written back. + */ + numVerts = dm->getNumVerts(dm); + deformedVerts = + MEM_mallocN(sizeof(*deformedVerts) * numVerts, "dfmv"); + dm->getVertCos(dm, deformedVerts); + } else { + deformedVerts = editmesh_getVertexCos(em, &numVerts); + } + } + + mti->deformVertsEM(md, ob, em, dm, deformedVerts, numVerts); + } else { + DerivedMesh *ndm; + + /* apply vertex coordinates or build a DerivedMesh as necessary */ + if(dm) { + if(deformedVerts) { + DerivedMesh *tdm = CDDM_copy(dm); + if(!(cage_r && dm == *cage_r)) dm->release(dm); + dm = tdm; + + CDDM_apply_vert_coords(dm, deformedVerts); + CDDM_calc_normals(dm); + } else if(cage_r && dm == *cage_r) { + /* dm may be changed by this modifier, so we need to copy it + */ + dm = CDDM_copy(dm); + } + + } else { + dm = CDDM_from_editmesh(em, ob->data); + + if(deformedVerts) { + CDDM_apply_vert_coords(dm, deformedVerts); + CDDM_calc_normals(dm); + } + } + + /* set the DerivedMesh to only copy needed data */ + DM_set_only_copy(dm, (CustomDataMask)curr->link); + + ndm = mti->applyModifierEM(md, ob, em, dm); + + if (ndm) { + if(dm && dm != ndm) + dm->release(dm); + + dm = ndm; + + if (deformedVerts) { + MEM_freeN(deformedVerts); + deformedVerts = NULL; + } + } + } + + if(cage_r && i == cageIndex) { + if(dm && deformedVerts) { + *cage_r = CDDM_copy(dm); + CDDM_apply_vert_coords(*cage_r, deformedVerts); + } else if(dm) { + *cage_r = dm; + } else { + *cage_r = + getEditMeshDerivedMesh(em, ob, + deformedVerts ? MEM_dupallocN(deformedVerts) : NULL); + } + } + } + + BLI_linklist_free(datamasks, NULL); + + /* Yay, we are done. If we have a DerivedMesh and deformed vertices need + * to apply these back onto the DerivedMesh. If we have no DerivedMesh + * then we need to build one. + */ + if(dm && deformedVerts) { + *final_r = CDDM_copy(dm); + + if(!(cage_r && dm == *cage_r)) dm->release(dm); + + CDDM_apply_vert_coords(*final_r, deformedVerts); + CDDM_calc_normals(*final_r); + } else if (dm) { + *final_r = dm; + } else if (!deformedVerts && cage_r && *cage_r) { + *final_r = *cage_r; + } else { + *final_r = getEditMeshDerivedMesh(em, ob, deformedVerts); + deformedVerts = NULL; + } + + if(deformedVerts) + MEM_freeN(deformedVerts); +} + +/***/ + + + /* Something of a hack, at the moment deal with weightpaint + * by tucking into colors during modifier eval, only in + * wpaint mode. Works ok but need to make sure recalc + * happens on enter/exit wpaint. + */ + +void weight_to_rgb(float input, float *fr, float *fg, float *fb) +{ + float blend; + + blend= ((input/2.0f)+0.5f); + + if (input<=0.25f){ // blue->cyan + *fr= 0.0f; + *fg= blend*input*4.0f; + *fb= blend; + } + else if (input<=0.50f){ // cyan->green + *fr= 0.0f; + *fg= blend; + *fb= blend*(1.0f-((input-0.25f)*4.0f)); + } + else if (input<=0.75){ // green->yellow + *fr= blend * ((input-0.50f)*4.0f); + *fg= blend; + *fb= 0.0f; + } + else if (input<=1.0){ // yellow->red + *fr= blend; + *fg= blend * (1.0f-((input-0.75f)*4.0f)); + *fb= 0.0f; + } +} +static void calc_weightpaint_vert_color(Object *ob, ColorBand *coba, int vert, unsigned char *col) +{ + Mesh *me = ob->data; + float colf[4], input = 0.0f; + int i; + + if (me->dvert) { + for (i=0; idvert[vert].totweight; i++) + if (me->dvert[vert].dw[i].def_nr==ob->actdef-1) + input+=me->dvert[vert].dw[i].weight; + } + + CLAMP(input, 0.0f, 1.0f); + + if(coba) + do_colorband(coba, input, colf); + else + weight_to_rgb(input, colf, colf+1, colf+2); + + col[3] = (unsigned char)(colf[0] * 255.0f); + col[2] = (unsigned char)(colf[1] * 255.0f); + col[1] = (unsigned char)(colf[2] * 255.0f); + col[0] = 255; +} + +static ColorBand *stored_cb= NULL; + +void vDM_ColorBand_store(ColorBand *coba) +{ + stored_cb= coba; +} + +static unsigned char *calc_weightpaint_colors(Object *ob) +{ + Mesh *me = ob->data; + MFace *mf = me->mface; + ColorBand *coba= stored_cb; /* warning, not a local var */ + unsigned char *wtcol; + int i; + + wtcol = MEM_callocN (sizeof (unsigned char) * me->totface*4*4, "weightmap"); + + memset(wtcol, 0x55, sizeof (unsigned char) * me->totface*4*4); + for (i=0; itotface; i++, mf++) { + calc_weightpaint_vert_color(ob, coba, mf->v1, &wtcol[(i*4 + 0)*4]); + calc_weightpaint_vert_color(ob, coba, mf->v2, &wtcol[(i*4 + 1)*4]); + calc_weightpaint_vert_color(ob, coba, mf->v3, &wtcol[(i*4 + 2)*4]); + if (mf->v4) + calc_weightpaint_vert_color(ob, coba, mf->v4, &wtcol[(i*4 + 3)*4]); + } + + return wtcol; +} + +static void clear_mesh_caches(Object *ob) +{ + Mesh *me= ob->data; + + /* also serves as signal to remake texspace */ + if (me->bb) { + MEM_freeN(me->bb); + me->bb = NULL; + } + + freedisplist(&ob->disp); + + if (ob->derivedFinal) { + ob->derivedFinal->needsFree = 1; + ob->derivedFinal->release(ob->derivedFinal); + ob->derivedFinal= NULL; + } + if (ob->derivedDeform) { + ob->derivedDeform->needsFree = 1; + ob->derivedDeform->release(ob->derivedDeform); + ob->derivedDeform= NULL; + } +} + +static void mesh_build_data(Object *ob, CustomDataMask dataMask) +{ + Mesh *me = ob->data; + float min[3], max[3]; + + clear_mesh_caches(ob); + + if(ob!=G.obedit) { + Object *obact = G.scene->basact?G.scene->basact->object:NULL; + int editing = (FACESEL_PAINT_TEST); + int needMapping = editing && (ob==obact); + + if( (G.f & G_WEIGHTPAINT) && ob==obact ) { + MCol *wpcol = (MCol*)calc_weightpaint_colors(ob); + int layernum = CustomData_number_of_layers(&me->fdata, CD_MCOL); + + /* ugly hack here, we temporarily add a new active mcol layer with + weightpaint colors in it, that is then duplicated in CDDM_from_mesh */ + CustomData_add_layer(&me->fdata, CD_MCOL, CD_ASSIGN, wpcol, me->totface); + CustomData_set_layer_active(&me->fdata, CD_MCOL, layernum); + + mesh_calc_modifiers(ob, NULL, &ob->derivedDeform, + &ob->derivedFinal, 0, 1, + needMapping, dataMask); + + CustomData_free_layer_active(&me->fdata, CD_MCOL, me->totface); + } else { + mesh_calc_modifiers(ob, NULL, &ob->derivedDeform, + &ob->derivedFinal, 0, 1, + needMapping, dataMask); + } + + INIT_MINMAX(min, max); + + ob->derivedFinal->getMinMax(ob->derivedFinal, min, max); + + boundbox_set_from_min_max(mesh_get_bb(ob->data), min, max); + + ob->derivedFinal->needsFree = 0; + ob->derivedDeform->needsFree = 0; + ob->lastDataMask = dataMask; + } +} + +static void editmesh_build_data(CustomDataMask dataMask) +{ + float min[3], max[3]; + + EditMesh *em = G.editMesh; + + clear_mesh_caches(G.obedit); + + if (em->derivedFinal) { + if (em->derivedFinal!=em->derivedCage) { + em->derivedFinal->needsFree = 1; + em->derivedFinal->release(em->derivedFinal); + } + em->derivedFinal = NULL; + } + if (em->derivedCage) { + em->derivedCage->needsFree = 1; + em->derivedCage->release(em->derivedCage); + em->derivedCage = NULL; + } + + editmesh_calc_modifiers(&em->derivedCage, &em->derivedFinal, dataMask); + em->lastDataMask = dataMask; + + INIT_MINMAX(min, max); + + em->derivedFinal->getMinMax(em->derivedFinal, min, max); + + boundbox_set_from_min_max(mesh_get_bb(G.obedit->data), min, max); + + em->derivedFinal->needsFree = 0; + em->derivedCage->needsFree = 0; +} + +void makeDerivedMesh(Object *ob, CustomDataMask dataMask) +{ + if (ob==G.obedit) { + editmesh_build_data(dataMask); + } else { + PartEff *paf= give_parteff(ob); + + mesh_build_data(ob, dataMask); + + if(paf) { + if((paf->flag & PAF_STATIC) || (ob->recalc & OB_RECALC_TIME)==0) + build_particle_system(ob); + } + } +} + +/***/ + +DerivedMesh *mesh_get_derived_final(Object *ob, CustomDataMask dataMask) +{ + /* if there's no derived mesh or the last data mask used doesn't include + * the data we need, rebuild the derived mesh + */ + if(!ob->derivedFinal || (dataMask & ob->lastDataMask) != dataMask) + mesh_build_data(ob, dataMask); + + return ob->derivedFinal; +} + +DerivedMesh *mesh_get_derived_deform(Object *ob, CustomDataMask dataMask) +{ + /* if there's no derived mesh or the last data mask used doesn't include + * the data we need, rebuild the derived mesh + */ + if(!ob->derivedDeform || (dataMask & ob->lastDataMask) != dataMask) + mesh_build_data(ob, dataMask); + + return ob->derivedDeform; +} + +/* Move to multires Pin level, returns a copy of the original vertex coords. */ +float *multires_render_pin(Object *ob, Mesh *me, int *orig_lvl) +{ + float *vert_copy= NULL; + + if(me->mr) { + MultiresLevel *lvl= NULL; + int i; + + /* Make sure all mesh edits are properly stored in the multires data*/ + multires_update_levels(me, 1); + + /* Copy the highest level of multires verts */ + *orig_lvl= me->mr->current; + lvl= multires_level_n(me->mr, BLI_countlist(&me->mr->levels)); + vert_copy= MEM_callocN(sizeof(float)*3*lvl->totvert, "multires vert_copy"); + for(i=0; itotvert; ++i) + VecCopyf(&vert_copy[i*3], me->mr->verts[i].co); + + /* Goto the pin level for multires */ + me->mr->newlvl= me->mr->pinlvl; + multires_set_level(ob, me, 1); + } + + return vert_copy; +} + +/* Propagate the changes to render level - fails if mesh topology changed */ +void multires_render_final(Object *ob, Mesh *me, DerivedMesh **dm, float *vert_copy, const int orig_lvl) +{ + if(me->mr) { + if((*dm)->getNumVerts(*dm) == me->totvert && + (*dm)->getNumFaces(*dm) == me->totface) { + MultiresLevel *lvl= multires_level_n(me->mr, BLI_countlist(&me->mr->levels)); + DerivedMesh *old= NULL; + int i; + + (*dm)->copyVertArray(*dm, me->mvert); + (*dm)->release(*dm); + + me->mr->newlvl= me->mr->renderlvl; + multires_set_level(ob, me, 1); + (*dm)= getMeshDerivedMesh(me, ob, NULL); + + /* Some of the data in dm is referenced externally, so make a copy */ + old= *dm; + (*dm)= CDDM_copy(old); + old->release(old); + + /* Restore the original verts */ + me->mr->newlvl= BLI_countlist(&me->mr->levels); + multires_set_level(ob, me, 1); + for(i=0; itotvert; ++i) + VecCopyf(me->mvert[i].co, &vert_copy[i*3]); + } + + if(vert_copy) + MEM_freeN(vert_copy); + + me->mr->newlvl= orig_lvl; + multires_set_level(ob, me, 1); + } +} + +/* Multires note - if mesh has multires enabled, mesh is first set to the Pin level, + where all modifiers are applied, then if the topology hasn't changed, the changes + from modifiers are propagated up to the Render level. */ +DerivedMesh *mesh_create_derived_render(Object *ob, CustomDataMask dataMask) +{ + DerivedMesh *final; + Mesh *me= get_mesh(ob); + float *vert_copy= NULL; + int orig_lvl= 0; + + vert_copy= multires_render_pin(ob, me, &orig_lvl); + mesh_calc_modifiers(ob, NULL, NULL, &final, 1, 1, 0, dataMask); + multires_render_final(ob, me, &final, vert_copy, orig_lvl); + + return final; +} + +DerivedMesh *mesh_create_derived_view(Object *ob, CustomDataMask dataMask) +{ + DerivedMesh *final; + + mesh_calc_modifiers(ob, NULL, NULL, &final, 0, 1, 0, dataMask); + + return final; +} + +DerivedMesh *mesh_create_derived_no_deform(Object *ob, float (*vertCos)[3], + CustomDataMask dataMask) +{ + DerivedMesh *final; + + mesh_calc_modifiers(ob, vertCos, NULL, &final, 0, 0, 0, dataMask); + + return final; +} + +DerivedMesh *mesh_create_derived_no_deform_render(Object *ob, + float (*vertCos)[3], + CustomDataMask dataMask) +{ + DerivedMesh *final; + Mesh *me= get_mesh(ob); + float *vert_copy= NULL; + int orig_lvl= 0; + + vert_copy= multires_render_pin(ob, me, &orig_lvl); + mesh_calc_modifiers(ob, vertCos, NULL, &final, 1, 0, 0, dataMask); + multires_render_final(ob, me, &final, vert_copy, orig_lvl); + + return final; +} + +/***/ + +DerivedMesh *editmesh_get_derived_cage_and_final(DerivedMesh **final_r, + CustomDataMask dataMask) +{ + /* if there's no derived mesh or the last data mask used doesn't include + * the data we need, rebuild the derived mesh + */ + if(!G.editMesh->derivedCage || + (G.editMesh->lastDataMask & dataMask) != dataMask) + editmesh_build_data(dataMask); + + *final_r = G.editMesh->derivedFinal; + return G.editMesh->derivedCage; +} + +DerivedMesh *editmesh_get_derived_cage(CustomDataMask dataMask) +{ + /* if there's no derived mesh or the last data mask used doesn't include + * the data we need, rebuild the derived mesh + */ + if(!G.editMesh->derivedCage || + (G.editMesh->lastDataMask & dataMask) != dataMask) + editmesh_build_data(dataMask); + + return G.editMesh->derivedCage; +} + +DerivedMesh *editmesh_get_derived_base(void) +{ + return getEditMeshDerivedMesh(G.editMesh, G.obedit, NULL); +} + + +/* ********* For those who don't grasp derived stuff! (ton) :) *************** */ + +static void make_vertexcosnos__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s) +{ + float *vec = userData; + + vec+= 6*index; + + /* check if we've been here before (normal should not be 0) */ + if(vec[3] || vec[4] || vec[5]) return; + + VECCOPY(vec, co); + vec+= 3; + if(no_f) { + VECCOPY(vec, no_f); + } + else { + VECCOPY(vec, no_s); + } +} + +/* always returns original amount me->totvert of vertices and normals, but fully deformed and subsurfered */ +/* this is needed for all code using vertexgroups (no subsurf support) */ +/* it stores the normals as floats, but they can still be scaled as shorts (32767 = unit) */ +/* in use now by vertex/weight paint and particle generating */ + +float *mesh_get_mapped_verts_nors(Object *ob) +{ + Mesh *me= ob->data; + DerivedMesh *dm; + float *vertexcosnos; + + /* lets prevent crashing... */ + if(ob->type!=OB_MESH || me->totvert==0) + return NULL; + + dm= mesh_get_derived_final(ob, CD_MASK_BAREMESH); + vertexcosnos= MEM_callocN(6*sizeof(float)*me->totvert, "vertexcosnos map"); + + if(dm->foreachMappedVert) { + dm->foreachMappedVert(dm, make_vertexcosnos__mapFunc, vertexcosnos); + } + else { + float *fp= vertexcosnos; + int a; + + for(a=0; a< me->totvert; a++, fp+=6) { + dm->getVertCo(dm, a, fp); + dm->getVertNo(dm, a, fp+3); + } + } + + dm->release(dm); + return vertexcosnos; +} + +/* ********* crazyspace *************** */ + +int editmesh_get_first_deform_matrices(float (**deformmats)[3][3], float (**deformcos)[3]) +{ + Object *ob = G.obedit; + EditMesh *em = G.editMesh; + ModifierData *md; + DerivedMesh *dm; + int i, a, numleft = 0, numVerts = 0; + int cageIndex = modifiers_getCageIndex(ob, NULL); + float (*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL; + + modifiers_clearErrors(ob); + + dm = NULL; + md = ob->modifiers.first; + + /* compute the deformation matrices and coordinates for the first + modifiers with on cage editing that are enabled and support computing + deform matrices */ + for(i = 0; md && i <= cageIndex; i++, md = md->next) { + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + if(!editmesh_modifier_is_enabled(md, dm)) + continue; + + if(mti->type==eModifierTypeType_OnlyDeform && mti->deformMatricesEM) { + if(!defmats) { + dm= getEditMeshDerivedMesh(em, ob, NULL); + deformedVerts= editmesh_getVertexCos(em, &numVerts); + defmats= MEM_callocN(sizeof(*defmats)*numVerts, "defmats"); + + for(a=0; adeformMatricesEM(md, ob, em, dm, deformedVerts, defmats, + numVerts); + } + else + break; + } + + for(; md && i <= cageIndex; md = md->next, i++) + if(editmesh_modifier_is_enabled(md, dm) && modifier_isDeformer(md)) + numleft++; + + if(dm) + dm->release(dm); + + *deformmats= defmats; + *deformcos= deformedVerts; + + return numleft; +} + +/* ************************* fluidsim bobj file handling **************************** */ + +#ifndef DISABLE_ELBEEM + +#ifdef WIN32 +#ifndef snprintf +#define snprintf _snprintf +#endif +#endif + +/* write .bobj.gz file for a mesh object */ +void writeBobjgz(char *filename, struct Object *ob, int useGlobalCoords, int append, float time) +{ + char debugStrBuffer[256]; + int wri,i,j,totvert,totface; + float wrf; + gzFile gzf; + DerivedMesh *dm; + float vec[3]; + float rotmat[3][3]; + MVert *mvert; + MFace *mface; + //if(append)return; // DEBUG + + if(!ob->data || (ob->type!=OB_MESH)) { + snprintf(debugStrBuffer,256,"Writing GZ_BOBJ Invalid object %s ...\n", ob->id.name); + elbeemDebugOut(debugStrBuffer); + return; + } + if((ob->size[0]<0.0) || (ob->size[0]<0.0) || (ob->size[0]<0.0) ) { + snprintf(debugStrBuffer,256,"\nfluidSim::writeBobjgz:: Warning object %s has negative scaling - check triangle ordering...?\n\n", ob->id.name); + elbeemDebugOut(debugStrBuffer); + } + + snprintf(debugStrBuffer,256,"Writing GZ_BOBJ '%s' ... ",filename); elbeemDebugOut(debugStrBuffer); + if(append) gzf = gzopen(filename, "a+b9"); + else gzf = gzopen(filename, "wb9"); + if (!gzf) { + snprintf(debugStrBuffer,256,"writeBobjgz::error - Unable to open file for writing '%s'\n", filename); + elbeemDebugOut(debugStrBuffer); + return; + } + + dm = mesh_create_derived_render(ob, CD_MASK_BAREMESH); + //dm = mesh_create_derived_no_deform(ob,NULL); + + mvert = dm->getVertArray(dm); + mface = dm->getFaceArray(dm); + totvert = dm->getNumVerts(dm); + totface = dm->getNumFaces(dm); + + // write time value for appended anim mesh + if(append) { + gzwrite(gzf, &time, sizeof(time)); + } + + // continue with verts/norms + if(sizeof(wri)!=4) { snprintf(debugStrBuffer,256,"Writing GZ_BOBJ, Invalid int size %d...\n", wri); elbeemDebugOut(debugStrBuffer); return; } // paranoia check + wri = dm->getNumVerts(dm); + mvert = dm->getVertArray(dm); + gzwrite(gzf, &wri, sizeof(wri)); + for(i=0; iobmat, vec); } + for(j=0; j<3; j++) { + wrf = vec[j]; + gzwrite(gzf, &wrf, sizeof( wrf )); + } + } + + // should be the same as Vertices.size + wri = totvert; + gzwrite(gzf, &wri, sizeof(wri)); + EulToMat3(ob->rot, rotmat); + for(i=0; iid.name, i, face[0],face[1],face[2],face[3] ); elbeemDebugOut(debugStrBuffer); + //VecSubf(side1, mvert[face[1]].co,mvert[face[0]].co); + //VecSubf(side2, mvert[face[2]].co,mvert[face[0]].co); + //Crossf(norm1,side1,side2); + gzwrite(gzf, &(face[0]), sizeof( face[0] )); + gzwrite(gzf, &(face[1]), sizeof( face[1] )); + gzwrite(gzf, &(face[2]), sizeof( face[2] )); + if(face[3]) { + //VecSubf(side1, mvert[face[2]].co,mvert[face[0]].co); + //VecSubf(side2, mvert[face[3]].co,mvert[face[0]].co); + //Crossf(norm2,side1,side2); + //inpf = Inpf(norm1,norm2); + //if(inpf>0.) { + gzwrite(gzf, &(face[0]), sizeof( face[0] )); + gzwrite(gzf, &(face[2]), sizeof( face[2] )); + gzwrite(gzf, &(face[3]), sizeof( face[3] )); + //} else { + //gzwrite(gzf, &(face[0]), sizeof( face[0] )); + //gzwrite(gzf, &(face[3]), sizeof( face[3] )); + //gzwrite(gzf, &(face[2]), sizeof( face[2] )); + //} + } // quad + } + } + + snprintf(debugStrBuffer,256,"Done. #Vertices: %d, #Triangles: %d\n", totvert, totface ); + elbeemDebugOut(debugStrBuffer); + + gzclose( gzf ); + dm->release(dm); +} + +void initElbeemMesh(struct Object *ob, + int *numVertices, float **vertices, + int *numTriangles, int **triangles, + int useGlobalCoords) +{ + DerivedMesh *dm = NULL; + MVert *mvert; + MFace *mface; + int countTris=0, i, totvert, totface; + float *verts; + int *tris; + + dm = mesh_create_derived_render(ob, CD_MASK_BAREMESH); + //dm = mesh_create_derived_no_deform(ob,NULL); + + mvert = dm->getVertArray(dm); + mface = dm->getFaceArray(dm); + totvert = dm->getNumVerts(dm); + totface = dm->getNumFaces(dm); + + *numVertices = totvert; + verts = MEM_callocN( totvert*3*sizeof(float), "elbeemmesh_vertices"); + for(i=0; iobmat, &verts[i*3]); } + } + *vertices = verts; + + for(i=0; irelease(dm); +} + +/* read .bobj.gz file into a fluidsimDerivedMesh struct */ +Mesh* readBobjgz(char *filename, Mesh *orgmesh, float* bbstart, float *bbsize) //, fluidsimDerivedMesh *fsdm) +{ + int wri,i,j; + char debugStrBuffer[256]; + float wrf; + Mesh *newmesh; + const int debugBobjRead = 1; + // init data from old mesh (materials,flags) + MFace *origMFace = &((MFace*) orgmesh->mface)[0]; + int mat_nr = -1; + int flag = -1; + MFace *fsface = NULL; + int gotBytes; + gzFile gzf; + + if(!orgmesh) return NULL; + if(!origMFace) return NULL; + mat_nr = origMFace->mat_nr; + flag = origMFace->flag; + + // similar to copy_mesh + newmesh = MEM_dupallocN(orgmesh); + newmesh->mat= orgmesh->mat; + + newmesh->mvert= NULL; + newmesh->medge= NULL; + newmesh->mface= NULL; + newmesh->mtface= NULL; + + newmesh->dvert = NULL; + + newmesh->mcol= NULL; + newmesh->msticky= NULL; + newmesh->texcomesh= NULL; + memset(&newmesh->vdata, 0, sizeof(newmesh->vdata)); + memset(&newmesh->edata, 0, sizeof(newmesh->edata)); + memset(&newmesh->fdata, 0, sizeof(newmesh->fdata)); + + newmesh->key= NULL; + newmesh->totface = 0; + newmesh->totvert = 0; + newmesh->totedge = 0; + newmesh->medge = NULL; + + + snprintf(debugStrBuffer,256,"Reading '%s' GZ_BOBJ... ",filename); elbeemDebugOut(debugStrBuffer); + gzf = gzopen(filename, "rb"); + // gzf = fopen(filename, "rb"); + // debug: fread(b,c,1,a) = gzread(a,b,c) + if (!gzf) { + //snprintf(debugStrBuffer,256,"readBobjgz::error - Unable to open file for reading '%s'\n", filename); // DEBUG + MEM_freeN(newmesh); + return NULL; + } + + //if(sizeof(wri)!=4) { snprintf(debugStrBuffer,256,"Reading GZ_BOBJ, Invalid int size %d...\n", wri); return NULL; } // paranoia check + gotBytes = gzread(gzf, &wri, sizeof(wri)); + newmesh->totvert = wri; + newmesh->mvert = CustomData_add_layer(&newmesh->vdata, CD_MVERT, CD_CALLOC, NULL, newmesh->totvert); + if(debugBobjRead){ snprintf(debugStrBuffer,256,"#vertices %d ", newmesh->totvert); elbeemDebugOut(debugStrBuffer); } //DEBUG + for(i=0; itotvert;i++) { + //if(debugBobjRead) snprintf(debugStrBuffer,256,"V %d = ",i); + for(j=0; j<3; j++) { + gotBytes = gzread(gzf, &wrf, sizeof( wrf )); + newmesh->mvert[i].co[j] = wrf; + //if(debugBobjRead) snprintf(debugStrBuffer,256,"%25.20f ", wrf); + } + //if(debugBobjRead) snprintf(debugStrBuffer,256,"\n"); + } + + // should be the same as Vertices.size + gotBytes = gzread(gzf, &wri, sizeof(wri)); + if(wri != newmesh->totvert) { + // complain #vertices has to be equal to #normals, reset&abort + CustomData_free_layer_active(&newmesh->vdata, CD_MVERT, newmesh->totvert); + MEM_freeN(newmesh); + snprintf(debugStrBuffer,256,"Reading GZ_BOBJ, #normals=%d, #vertices=%d, aborting...\n", wri,newmesh->totvert ); + return NULL; + } + for(i=0; itotvert;i++) { + for(j=0; j<3; j++) { + gotBytes = gzread(gzf, &wrf, sizeof( wrf )); + newmesh->mvert[i].no[j] = (short)(wrf*32767.0f); + //newmesh->mvert[i].no[j] = 0.5; // DEBUG tst + } + //fprintf(stderr," DEBDPCN nm%d, %d = %d,%d,%d \n", + //(int)(newmesh->mvert), i, newmesh->mvert[i].no[0], newmesh->mvert[i].no[1], newmesh->mvert[i].no[2]); + } + //fprintf(stderr," DPCN 0 = %d,%d,%d \n", newmesh->mvert[0].no[0], newmesh->mvert[0].no[1], newmesh->mvert[0].no[2]); + + + /* compute no. of triangles */ + gotBytes = gzread(gzf, &wri, sizeof(wri)); + newmesh->totface = wri; + newmesh->mface = CustomData_add_layer(&newmesh->fdata, CD_MFACE, CD_CALLOC, NULL, newmesh->totface); + if(debugBobjRead){ snprintf(debugStrBuffer,256,"#faces %d ", newmesh->totface); elbeemDebugOut(debugStrBuffer); } //DEBUG + fsface = newmesh->mface; + for(i=0; itotface; i++) { + int face[4]; + + gotBytes = gzread(gzf, &(face[0]), sizeof( face[0] )); + gotBytes = gzread(gzf, &(face[1]), sizeof( face[1] )); + gotBytes = gzread(gzf, &(face[2]), sizeof( face[2] )); + face[3] = 0; + + fsface[i].v1 = face[0]; + fsface[i].v2 = face[1]; + fsface[i].v3 = face[2]; + fsface[i].v4 = face[3]; + } + + // correct triangles with v3==0 for blender, cycle verts + for(i=0; itotface; i++) { + if(!fsface[i].v3) { + int temp = fsface[i].v1; + fsface[i].v1 = fsface[i].v2; + fsface[i].v2 = fsface[i].v3; + fsface[i].v3 = temp; + } + } + + gzclose( gzf ); + for(i=0;itotface;i++) { + fsface[i].mat_nr = mat_nr; + fsface[i].flag = flag; + fsface[i].edcode = ME_V1V2 | ME_V2V3 | ME_V3V1; + //snprintf(debugStrBuffer,256,"%d : %d,%d,%d\n", i,fsface[i].mat_nr, fsface[i].flag, fsface[i].edcode ); + } + + snprintf(debugStrBuffer,256," (%d,%d) done\n", newmesh->totvert,newmesh->totface); elbeemDebugOut(debugStrBuffer); //DEBUG + return newmesh; +} + +/* read zipped fluidsim velocities into the co's of the fluidsimsettings normals struct */ +void readVelgz(char *filename, Object *srcob) +{ + char debugStrBuffer[256]; + int wri, i, j; + float wrf; + gzFile gzf; + MVert *vverts = srcob->fluidsimSettings->meshSurfNormals; + int len = strlen(filename); + Mesh *mesh = srcob->data; + // mesh and vverts have to be valid from loading... + + // clean up in any case + for(i=0; itotvert;i++) { + for(j=0; j<3; j++) { + vverts[i].co[j] = 0.; + } + } + if(srcob->fluidsimSettings->domainNovecgen>0) return; + + if(len<7) { + //printf("readVelgz Eror: invalid filename '%s'\n",filename); // DEBUG + return; + } + + // .bobj.gz , correct filename + // 87654321 + filename[len-6] = 'v'; + filename[len-5] = 'e'; + filename[len-4] = 'l'; + + snprintf(debugStrBuffer,256,"Reading '%s' GZ_VEL... ",filename); elbeemDebugOut(debugStrBuffer); + gzf = gzopen(filename, "rb"); + if (!gzf) { + //printf("readVelgz Eror: unable to open file '%s'\n",filename); // DEBUG + return; + } + + gzread(gzf, &wri, sizeof( wri )); + if(wri != mesh->totvert) { + //printf("readVelgz Eror: invalid no. of velocities %d vs. %d aborting.\n" ,wri ,mesh->totvert ); // DEBUG + return; + } + + for(i=0; itotvert;i++) { + for(j=0; j<3; j++) { + gzread(gzf, &wrf, sizeof( wrf )); + vverts[i].co[j] = wrf; + } + //if(i<20) fprintf(stderr, "GZ_VELload %d = %f,%f,%f \n",i,vverts[i].co[0],vverts[i].co[1],vverts[i].co[2]); // DEBUG + } + + gzclose(gzf); +} + + +/* ***************************** fluidsim derived mesh ***************************** */ + +/* check which file to load, and replace old mesh of the object with it */ +/* this replacement is undone at the end of mesh_calc_modifiers */ +void loadFluidsimMesh(Object *srcob, int useRenderParams) +{ + Mesh *mesh = NULL; + float *bbStart = NULL, *bbSize = NULL; + float lastBB[3]; + int displaymode = 0; + int curFrame = G.scene->r.cfra - 1 /*G.scene->r.sfra*/; /* start with 0 at start frame */ + char targetDir[FILE_MAXFILE+FILE_MAXDIR], targetFile[FILE_MAXFILE+FILE_MAXDIR]; + char debugStrBuffer[256]; + //snprintf(debugStrBuffer,256,"loadFluidsimMesh call (obid '%s', rp %d)\n", srcob->id.name, useRenderParams); // debug + + if((!srcob)||(!srcob->fluidsimSettings)) { + snprintf(debugStrBuffer,256,"DEBUG - Invalid loadFluidsimMesh call, rp %d, dm %d)\n", useRenderParams, displaymode); // debug + elbeemDebugOut(debugStrBuffer); // debug + return; + } + // make sure the original mesh data pointer is stored + if(!srcob->fluidsimSettings->orgMesh) { + srcob->fluidsimSettings->orgMesh = srcob->data; + } + + // free old mesh, if there is one (todo, check if it's still valid?) + if(srcob->fluidsimSettings->meshSurface) { + Mesh *freeFsMesh = srcob->fluidsimSettings->meshSurface; + + // similar to free_mesh(...) , but no things like unlink... + CustomData_free(&freeFsMesh->vdata, freeFsMesh->totvert); + CustomData_free(&freeFsMesh->edata, freeFsMesh->totedge); + CustomData_free(&freeFsMesh->fdata, freeFsMesh->totface); + MEM_freeN(freeFsMesh); + + if(srcob->data == srcob->fluidsimSettings->meshSurface) + srcob->data = srcob->fluidsimSettings->orgMesh; + srcob->fluidsimSettings->meshSurface = NULL; + + if(srcob->fluidsimSettings->meshSurfNormals) MEM_freeN(srcob->fluidsimSettings->meshSurfNormals); + srcob->fluidsimSettings->meshSurfNormals = NULL; + } + + // init bounding box + bbStart = srcob->fluidsimSettings->bbStart; + bbSize = srcob->fluidsimSettings->bbSize; + lastBB[0] = bbSize[0]; // TEST + lastBB[1] = bbSize[1]; + lastBB[2] = bbSize[2]; + fluidsimGetAxisAlignedBB(srcob->fluidsimSettings->orgMesh, srcob->obmat, bbStart, bbSize, &srcob->fluidsimSettings->meshBB); + // check free fsmesh... TODO + + if(!useRenderParams) { + displaymode = srcob->fluidsimSettings->guiDisplayMode; + } else { + displaymode = srcob->fluidsimSettings->renderDisplayMode; + } + + snprintf(debugStrBuffer,256,"loadFluidsimMesh call (obid '%s', rp %d, dm %d), curFra=%d, sFra=%d #=%d \n", + srcob->id.name, useRenderParams, displaymode, G.scene->r.cfra, G.scene->r.sfra, curFrame ); // debug + elbeemDebugOut(debugStrBuffer); // debug + + strncpy(targetDir, srcob->fluidsimSettings->surfdataPath, FILE_MAXDIR); + // use preview or final mesh? + if(displaymode==1) { + // just display original object + srcob->data = srcob->fluidsimSettings->orgMesh; + return; + } else if(displaymode==2) { + strcat(targetDir,"fluidsurface_preview_#"); + } else { // 3 + strcat(targetDir,"fluidsurface_final_#"); + } + BLI_convertstringcode(targetDir, G.sce, curFrame); // fixed #frame-no + strcpy(targetFile,targetDir); + strcat(targetFile, ".bobj.gz"); + + snprintf(debugStrBuffer,256,"loadFluidsimMesh call (obid '%s', rp %d, dm %d) '%s' \n", srcob->id.name, useRenderParams, displaymode, targetFile); // debug + elbeemDebugOut(debugStrBuffer); // debug + + if(displaymode!=2) { // dont add bounding box for final + mesh = readBobjgz(targetFile, srcob->fluidsimSettings->orgMesh ,NULL,NULL); + } else { + mesh = readBobjgz(targetFile, srcob->fluidsimSettings->orgMesh, bbSize,bbSize ); + } + if(!mesh) { + // switch, abort background rendering when fluidsim mesh is missing + const char *strEnvName2 = "BLENDER_ELBEEMBOBJABORT"; // from blendercall.cpp + if(G.background==1) { + if(getenv(strEnvName2)) { + int elevel = atoi(getenv(strEnvName2)); + if(elevel>0) { + printf("Env. var %s set, fluid sim mesh '%s' not found, aborting render...\n",strEnvName2, targetFile); + exit(1); + } + } + } + + // display org. object upon failure + srcob->data = srcob->fluidsimSettings->orgMesh; + return; + } + + if((mesh)&&(mesh->totvert>0)) { + make_edges(mesh, 0); // 0 = make all edges draw + } + srcob->fluidsimSettings->meshSurface = mesh; + srcob->data = mesh; + srcob->fluidsimSettings->meshSurfNormals = MEM_dupallocN(mesh->mvert); + + // load vertex velocities, if they exist... + // TODO? use generate flag as loading flag as well? + // warning, needs original .bobj.gz mesh loading filename + if(displaymode==3) { + readVelgz(targetFile, srcob); + } else { + // no data for preview, only clear... + int i,j; + for(i=0; itotvert;i++) { for(j=0; j<3; j++) { srcob->fluidsimSettings->meshSurfNormals[i].co[j] = 0.; }} + } + + //fprintf(stderr,"LOADFLM DEBXHCH fs=%d 3:%d,%d,%d \n", (int)mesh, ((Mesh *)(srcob->fluidsimSettings->meshSurface))->mvert[3].no[0], ((Mesh *)(srcob->fluidsimSettings->meshSurface))->mvert[3].no[1], ((Mesh *)(srcob->fluidsimSettings->meshSurface))->mvert[3].no[2]); + return; +} + +/* helper function */ +/* init axis aligned BB for mesh object */ +void fluidsimGetAxisAlignedBB(struct Mesh *mesh, float obmat[][4], + /*RET*/ float start[3], /*RET*/ float size[3], /*RET*/ struct Mesh **bbmesh ) +{ + float bbsx=0.0, bbsy=0.0, bbsz=0.0; + float bbex=1.0, bbey=1.0, bbez=1.0; + int i; + float vec[3]; + + VECCOPY(vec, mesh->mvert[0].co); + Mat4MulVecfl(obmat, vec); + bbsx = vec[0]; bbsy = vec[1]; bbsz = vec[2]; + bbex = vec[0]; bbey = vec[1]; bbez = vec[2]; + + for(i=1; itotvert;i++) { + VECCOPY(vec, mesh->mvert[i].co); + Mat4MulVecfl(obmat, vec); + + if(vec[0] < bbsx){ bbsx= vec[0]; } + if(vec[1] < bbsy){ bbsy= vec[1]; } + if(vec[2] < bbsz){ bbsz= vec[2]; } + if(vec[0] > bbex){ bbex= vec[0]; } + if(vec[1] > bbey){ bbey= vec[1]; } + if(vec[2] > bbez){ bbez= vec[2]; } + } + + // return values... + if(start) { + start[0] = bbsx; + start[1] = bbsy; + start[2] = bbsz; + } + if(size) { + size[0] = bbex-bbsx; + size[1] = bbey-bbsy; + size[2] = bbez-bbsz; + } + + // init bounding box mesh? + if(bbmesh) { + int i,j; + Mesh *newmesh = NULL; + if(!(*bbmesh)) { newmesh = MEM_callocN(sizeof(Mesh), "fluidsimGetAxisAlignedBB_meshbb"); } + else { newmesh = *bbmesh; } + + newmesh->totvert = 8; + if(!newmesh->mvert) + newmesh->mvert = CustomData_add_layer(&newmesh->vdata, CD_MVERT, CD_CALLOC, NULL, newmesh->totvert); + for(i=0; i<8; i++) { + for(j=0; j<3; j++) newmesh->mvert[i].co[j] = start[j]; + } + + newmesh->totface = 6; + if(!newmesh->mface) + newmesh->mface = CustomData_add_layer(&newmesh->fdata, CD_MFACE, CD_CALLOC, NULL, newmesh->totface); + + *bbmesh = newmesh; + } +} + +#else // DISABLE_ELBEEM + +/* dummy for mesh_calc_modifiers */ +void loadFluidsimMesh(Object *srcob, int useRenderParams) { +} + +#endif // DISABLE_ELBEEM + diff --git a/source/blender/blenkernel/intern/Makefile b/source/blender/blenkernel/intern/Makefile new file mode 100644 index 00000000000..89b91ed2a8f --- /dev/null +++ b/source/blender/blenkernel/intern/Makefile @@ -0,0 +1,109 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = blenkernel +DIR = $(OCGDIR)/blender/$(LIBNAME) + +include nan_compile.mk + +CFLAGS += $(LEVEL_1_C_WARNINGS) + +# OpenGL and Python +CPPFLAGS += -I$(OPENGL_HEADERS) +CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) + +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include +# Reference to the types in makesdna and imbuf +CPPFLAGS += -I../../makesdna +CPPFLAGS += -I../../imbuf +# This mod uses the BLI and BLO module +CPPFLAGS += -I../../blenlib +CPPFLAGS += -I../../blenloader +CPPFLAGS += -I../../python +# also avi is used +CPPFLAGS += -I../../avi +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include + +# we still refer to /include a bit... +CPPFLAGS += -I../../include + +# to include the render stuff: +CPPFLAGS += -I../../render/extern/include + +# for image stamping +CPPFLAGS += -I$(NAN_BMFONT)/include +# for sound +#CPPFLAGS += -I../../../kernel/gen_system +CPPFLAGS += $(NAN_SDLCFLAGS) + +CPPFLAGS += -I$(NAN_IKSOLVER)/include +CPPFLAGS += -I$(NAN_DECIMATION)/include +CPPFLAGS += -I$(NAN_ELBEEM)/include + +# path to zlib +CPPFLAGS += -I$(NAN_ZLIB)/include + +#path to nodes +CPPFLAGS += -I../../nodes + +# path to our own external headerfiles +CPPFLAGS += -I.. + +ifeq ($(WITH_FREETYPE2), true) + CPPFLAGS += -DWITH_FREETYPE2 + CPPFLAGS += -I$(NAN_FREETYPE)/include + CPPFLAGS += -I$(NAN_FREETYPE)/include/freetype2 +endif + +ifeq ($(WITH_VERSE), true) + CPPFLAGS += -DWITH_VERSE + CPPFLAGS += -I$(NAN_VERSE)/include +endif + +ifeq ($(WITH_FFMPEG),true) + CPPFLAGS += -DWITH_FFMPEG + CPPFLAGS += $(NAN_FFMPEGCFLAGS) +endif + +ifeq ($(WITH_OPENEXR), true) + CPPFLAGS += -DWITH_OPENEXR +endif + +ifeq ($(WITH_DDS), true) + CPPFLAGS += -DWITH_DDS +endif + +ifeq ($(WITH_QUICKTIME), true) + CPPFLAGS += -I../../quicktime + CPPFLAGS += -DWITH_QUICKTIME +endif diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c new file mode 100644 index 00000000000..d202178fc0a --- /dev/null +++ b/source/blender/blenkernel/intern/action.c @@ -0,0 +1,1373 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Full recode, Ton Roosendaal, Crete 2005 + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include /* for NULL */ + +#include "MEM_guardedalloc.h" + +#include "DNA_action_types.h" +#include "DNA_armature_types.h" +#include "DNA_constraint_types.h" +#include "DNA_curve_types.h" +#include "DNA_ipo_types.h" +#include "DNA_key_types.h" +#include "DNA_nla_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_action.h" +#include "BKE_anim.h" +#include "BKE_armature.h" +#include "BKE_blender.h" +#include "BKE_constraint.h" +#include "BKE_displist.h" +#include "BKE_global.h" +#include "BKE_ipo.h" +#include "BKE_key.h" +#include "BKE_lattice.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_object.h" +#include "BKE_utildefines.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" + +#include "nla.h" + +/* *********************** NOTE ON POSE AND ACTION ********************** + + - Pose is the local (object level) component of armature. The current + object pose is saved in files, and (will be) is presorted for dependency + - Actions have fewer (or other) channels, and write data to a Pose + - Currently ob->pose data is controlled in where_is_pose only. The (recalc) + event system takes care of calling that + - The NLA system (here too) uses Poses as interpolation format for Actions + - Therefore we assume poses to be static, and duplicates of poses have channels in + same order, for quick interpolation reasons + + ****************************** (ton) ************************************ */ + +/* ***************** Library data level operations on action ************** */ + +static void make_local_action_channels(bAction *act) +{ + bActionChannel *chan; + bConstraintChannel *conchan; + + for (chan=act->chanbase.first; chan; chan=chan->next) { + if(chan->ipo) { + if(chan->ipo->id.us==1) { + chan->ipo->id.lib= NULL; + chan->ipo->id.flag= LIB_LOCAL; + new_id(0, (ID *)chan->ipo, 0); + } + else { + chan->ipo= copy_ipo(chan->ipo); + } + } + for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) { + if(conchan->ipo) { + if(conchan->ipo->id.us==1) { + conchan->ipo->id.lib= NULL; + conchan->ipo->id.flag= LIB_LOCAL; + new_id(0, (ID *)conchan->ipo, 0); + } + else { + conchan->ipo= copy_ipo(conchan->ipo); + } + } + } + } +} + +void make_local_action(bAction *act) +{ + Object *ob; + bAction *actn; + int local=0, lib=0; + + if(act->id.lib==0) return; + if(act->id.us==1) { + act->id.lib= 0; + act->id.flag= LIB_LOCAL; + make_local_action_channels(act); + new_id(0, (ID *)act, 0); + return; + } + + ob= G.main->object.first; + while(ob) { + if(ob->action==act) { + if(ob->id.lib) lib= 1; + else local= 1; + } + ob= ob->id.next; + } + + if(local && lib==0) { + act->id.lib= 0; + act->id.flag= LIB_LOCAL; + make_local_action_channels(act); + new_id(0, (ID *)act, 0); + } + else if(local && lib) { + actn= copy_action(act); + actn->id.us= 0; + + ob= G.main->object.first; + while(ob) { + if(ob->action==act) { + + if(ob->id.lib==0) { + ob->action = actn; + actn->id.us++; + act->id.us--; + } + } + ob= ob->id.next; + } + } +} + + +void free_action (bAction *act) +{ + bActionChannel *chan; + + /* Free channels */ + for (chan=act->chanbase.first; chan; chan=chan->next) { + if (chan->ipo) + chan->ipo->id.us--; + free_constraint_channels(&chan->constraintChannels); + } + + if (act->chanbase.first) + BLI_freelistN(&act->chanbase); +} + +bAction *copy_action (bAction *src) +{ + bAction *dst = NULL; + bActionChannel *dchan, *schan; + + if (!src) return NULL; + + dst= copy_libblock(src); + duplicatelist(&(dst->chanbase), &(src->chanbase)); + + for (dchan=dst->chanbase.first, schan=src->chanbase.first; dchan; dchan=dchan->next, schan=schan->next){ + dchan->ipo = copy_ipo(dchan->ipo); + copy_constraint_channels(&dchan->constraintChannels, &schan->constraintChannels); + } + dst->id.flag |= LIB_FAKEUSER; + dst->id.us++; + return dst; +} + + + +/* ************************ Pose channels *************** */ + +/* usually used within a loop, so we got a N^2 slowdown */ +bPoseChannel *get_pose_channel(const bPose *pose, const char *name) +{ + bPoseChannel *chan; + + if(pose==NULL) return NULL; + + for (chan=pose->chanbase.first; chan; chan=chan->next) { + if(chan->name[0] == name[0]) + if (!strcmp (chan->name, name)) + return chan; + } + + return NULL; +} + +/* Use with care, not on Armature poses but for temporal ones */ +/* (currently used for action constraints and in rebuild_pose) */ +bPoseChannel *verify_pose_channel(bPose* pose, const char* name) +{ + bPoseChannel *chan; + + if (!pose) { + return NULL; + } + + /* See if this channel exists */ + for (chan=pose->chanbase.first; chan; chan=chan->next) { + if (!strcmp (name, chan->name)) + return chan; + } + + /* If not, create it and add it */ + chan = MEM_callocN(sizeof(bPoseChannel), "verifyPoseChannel"); + + strncpy (chan->name, name, 31); + /* init vars to prevent math errors */ + chan->quat[0] = 1.0F; + chan->size[0] = chan->size[1] = chan->size[2] = 1.0F; + + chan->limitmin[0]= chan->limitmin[1]= chan->limitmin[2]= -180.0f; + chan->limitmax[0]= chan->limitmax[1]= chan->limitmax[2]= 180.0f; + chan->stiffness[0]= chan->stiffness[1]= chan->stiffness[2]= 0.0f; + + Mat4One(chan->constinv); + + BLI_addtail (&pose->chanbase, chan); + + return chan; +} + + +/* dst should be freed already, makes entire duplicate */ +void copy_pose(bPose **dst, bPose *src, int copycon) +{ + bPose *outPose; + bPoseChannel *pchan; + ListBase listb; + + if (!src){ + *dst=NULL; + return; + } + + outPose= MEM_callocN(sizeof(bPose), "pose"); + + duplicatelist (&outPose->chanbase, &src->chanbase); + + if (copycon) { + for (pchan=outPose->chanbase.first; pchan; pchan=pchan->next) { + copy_constraints(&listb, &pchan->constraints); // copy_constraints NULLs listb + pchan->constraints= listb; + pchan->path= NULL; + } + } + + *dst=outPose; +} + +void free_pose_channels(bPose *pose) +{ + bPoseChannel *pchan; + + if (pose->chanbase.first){ + for (pchan = pose->chanbase.first; pchan; pchan=pchan->next){ + if(pchan->path) + MEM_freeN(pchan->path); + free_constraints(&pchan->constraints); + } + BLI_freelistN (&pose->chanbase); + } +} + +static void copy_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *chan) +{ + bConstraint *pcon, *con; + + VECCOPY(pchan->loc, chan->loc); + VECCOPY(pchan->size, chan->size); + QUATCOPY(pchan->quat, chan->quat); + pchan->flag= chan->flag; + + con= chan->constraints.first; + for(pcon= pchan->constraints.first; pcon; pcon= pcon->next) + pcon->enforce= con->enforce; +} + +/* checks for IK constraint, can do more constraints flags later */ +/* pose should be entirely OK */ +void update_pose_constraint_flags(bPose *pose) +{ + bPoseChannel *pchan, *parchan; + bConstraint *con; + + /* clear */ + for (pchan = pose->chanbase.first; pchan; pchan=pchan->next) { + pchan->constflag= 0; + } + /* detect */ + for (pchan = pose->chanbase.first; pchan; pchan=pchan->next) { + for(con= pchan->constraints.first; con; con= con->next) { + if(con->type==CONSTRAINT_TYPE_KINEMATIC) { + bKinematicConstraint *data = (bKinematicConstraint*)con->data; + + pchan->constflag |= PCHAN_HAS_IK; + + if(data->tar==NULL || (data->tar->type==OB_ARMATURE && data->subtarget[0]==0)) + pchan->constflag |= PCHAN_HAS_TARGET; + + /* negative rootbone = recalc rootbone index. used in do_versions */ + if(data->rootbone<0) { + data->rootbone= 0; + + if(data->flag & CONSTRAINT_IK_TIP) parchan= pchan; + else parchan= pchan->parent; + + while(parchan) { + data->rootbone++; + if((parchan->bone->flag & BONE_CONNECTED)==0) + break; + parchan= parchan->parent; + } + } + } + else pchan->constflag |= PCHAN_HAS_CONST; + } + } +} + +/* Clears all BONE_UNKEYED flags for every pose channel in every pose + * This should only be called on frame changing, when it is acceptable to + * do this. Otherwise, these flags should not get cleared as poses may get lost. + */ +void framechange_poses_clear_unkeyed(void) +{ + Object *ob; + bPose *pose; + bPoseChannel *pchan; + + /* This needs to be done for each object that has a pose */ + // TODO: proxies may/may not be correctly handled here... (this needs checking) + for (ob= G.main->object.first; ob; ob= ob->id.next) { + /* we only need to do this on objects with a pose */ + if ( (pose= ob->pose) ) { + for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) { + if (pchan->bone) + pchan->bone->flag &= ~BONE_UNKEYED; + } + } + } +} + +/* ************************ END Pose channels *************** */ + +/* ************************ Action channels *************** */ + + +bActionChannel *get_action_channel(bAction *act, const char *name) +{ + bActionChannel *chan; + + if (!act || !name) + return NULL; + + for (chan = act->chanbase.first; chan; chan=chan->next){ + if (!strcmp (chan->name, name)) + return chan; + } + + return NULL; +} + +/* returns existing channel, or adds new one. In latter case it doesnt activate it, context is required for that*/ +bActionChannel *verify_action_channel(bAction *act, const char *name) +{ + bActionChannel *chan; + + chan= get_action_channel(act, name); + if(chan==NULL) { + if (!chan) { + chan = MEM_callocN (sizeof(bActionChannel), "actionChannel"); + strncpy (chan->name, name, 31); + BLI_addtail (&act->chanbase, chan); + } + } + return chan; +} + +/* ************** time ****************** */ + +static bActionStrip *get_active_strip(Object *ob) +{ + bActionStrip *strip; + + if(ob->action==NULL) + return NULL; + + for (strip=ob->nlastrips.first; strip; strip=strip->next) + if(strip->flag & ACTSTRIP_ACTIVE) + break; + + if(strip && strip->act==ob->action) + return strip; + return NULL; +} + +/* non clipped mapping of strip */ +static float get_actionstrip_frame(bActionStrip *strip, float cframe, int invert) +{ + float length, actlength, repeat; + + if (strip->flag & ACTSTRIP_USESTRIDE) + repeat= 1.0f; + else + repeat= strip->repeat; + + length = strip->end-strip->start; + if(length==0.0f) + length= 1.0f; + actlength = strip->actend-strip->actstart; + + + + if(invert) + return length*(cframe - strip->actstart)/(repeat*actlength) + strip->start; + else + return repeat*actlength*(cframe - strip->start)/length + strip->actstart; +} + +/* if the conditions match, it converts current time to strip time */ +float get_action_frame(Object *ob, float cframe) +{ + bActionStrip *strip= get_active_strip(ob); + + if(strip) + return get_actionstrip_frame(strip, cframe, 0); + return cframe; +} + +/* inverted, strip time to current time */ +float get_action_frame_inv(Object *ob, float cframe) +{ + bActionStrip *strip= get_active_strip(ob); + + if(strip) + return get_actionstrip_frame(strip, cframe, 1); + return cframe; +} + + +/* ************************ Blending with NLA *************** */ + +static void blend_pose_strides(bPose *dst, bPose *src, float srcweight, short mode) +{ + float dstweight; + + switch (mode){ + case ACTSTRIPMODE_BLEND: + dstweight = 1.0F - srcweight; + break; + case ACTSTRIPMODE_ADD: + dstweight = 1.0F; + break; + default : + dstweight = 1.0F; + } + + VecLerpf(dst->stride_offset, dst->stride_offset, src->stride_offset, srcweight); +} + + +/* + +bone matching diagram, strips A and B + + .------------------------. + | A | + '------------------------' + . . b2 + . .-------------v----------. + . | B . | + . '------------------------' + . . . + . . . +offset: . 0 . A-B . A-b2+B + . . . + +*/ + + +static void blend_pose_offset_bone(bActionStrip *strip, bPose *dst, bPose *src, float srcweight, short mode) +{ + /* matching offset bones */ + /* take dst offset, and put src on on that location */ + + if(strip->offs_bone[0]==0) + return; + + /* are we also blending with matching bones? */ + if(strip->prev && strip->start>=strip->prev->start) { + bPoseChannel *dpchan= get_pose_channel(dst, strip->offs_bone); + if(dpchan) { + bPoseChannel *spchan= get_pose_channel(src, strip->offs_bone); + if(spchan) { + float vec[3]; + + /* dst->ctime has the internal strip->prev action time */ + /* map this time to nla time */ + + float ctime= get_actionstrip_frame(strip, src->ctime, 1); + + if( ctime > strip->prev->end) { + bActionChannel *achan; + + /* add src to dest, minus the position of src on strip->prev->end */ + + ctime= get_actionstrip_frame(strip, strip->prev->end, 0); + + achan= get_action_channel(strip->act, strip->offs_bone); + if(achan && achan->ipo) { + bPoseChannel pchan; + /* Evaluates and sets the internal ipo value */ + calc_ipo(achan->ipo, ctime); + /* This call also sets the pchan flags */ + execute_action_ipo(achan, &pchan); + + /* store offset that moves src to location of pchan */ + VecSubf(vec, dpchan->loc, pchan.loc); + + Mat4Mul3Vecfl(dpchan->bone->arm_mat, vec); + } + } + else { + /* store offset that moves src to location of dst */ + + VecSubf(vec, dpchan->loc, spchan->loc); + Mat4Mul3Vecfl(dpchan->bone->arm_mat, vec); + } + + /* if blending, we only add with factor scrweight */ + VecMulf(vec, srcweight); + + VecAddf(dst->cyclic_offset, dst->cyclic_offset, vec); + } + } + } + + VecAddf(dst->cyclic_offset, dst->cyclic_offset, src->cyclic_offset); +} + + +/* Only allowed for Poses with identical channels */ +void blend_poses(bPose *dst, bPose *src, float srcweight, short mode) +{ + bPoseChannel *dchan; + const bPoseChannel *schan; + bConstraint *dcon, *scon; + float dquat[4], squat[4]; + float dstweight; + int i; + + switch (mode){ + case ACTSTRIPMODE_BLEND: + dstweight = 1.0F - srcweight; + break; + case ACTSTRIPMODE_ADD: + dstweight = 1.0F; + break; + default : + dstweight = 1.0F; + } + + schan= src->chanbase.first; + for (dchan = dst->chanbase.first; dchan; dchan=dchan->next, schan= schan->next){ + if (schan->flag & (POSE_ROT|POSE_LOC|POSE_SIZE)) { + /* replaced quat->matrix->quat conversion with decent quaternion interpol (ton) */ + + /* Do the transformation blend */ + if (schan->flag & POSE_ROT) { + QUATCOPY(dquat, dchan->quat); + QUATCOPY(squat, schan->quat); + if(mode==ACTSTRIPMODE_BLEND) + QuatInterpol(dchan->quat, dquat, squat, srcweight); + else + QuatAdd(dchan->quat, dquat, squat, srcweight); + + NormalQuat (dchan->quat); + } + + for (i=0; i<3; i++){ + if (schan->flag & POSE_LOC) + dchan->loc[i] = (dchan->loc[i]*dstweight) + (schan->loc[i]*srcweight); + if (schan->flag & POSE_SIZE) + dchan->size[i] = 1.0f + ((dchan->size[i]-1.0f)*dstweight) + ((schan->size[i]-1.0f)*srcweight); + } + dchan->flag |= schan->flag; + } + for(dcon= dchan->constraints.first, scon= schan->constraints.first; dcon && scon; dcon= dcon->next, scon= scon->next) { + /* no 'add' option for constraint blending */ + dcon->enforce= dcon->enforce*(1.0f-srcweight) + scon->enforce*srcweight; + } + } + + /* this pose is now in src time */ + dst->ctime= src->ctime; +} + + +void calc_action_range(const bAction *act, float *start, float *end, int incl_hidden) +{ + const bActionChannel *chan; + const bConstraintChannel *conchan; + const IpoCurve *icu; + float min=999999999.0f, max=-999999999.0; + int foundvert=0; + + if(act) { + for (chan=act->chanbase.first; chan; chan=chan->next) { + if(incl_hidden || (chan->flag & ACHAN_HIDDEN)==0) { + if(chan->ipo) { + for (icu=chan->ipo->curve.first; icu; icu=icu->next) { + if(icu->totvert) { + min= MIN2 (min, icu->bezt[0].vec[1][0]); + max= MAX2 (max, icu->bezt[icu->totvert-1].vec[1][0]); + foundvert=1; + } + } + } + for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) { + if(conchan->ipo) { + for (icu=conchan->ipo->curve.first; icu; icu=icu->next) { + if(icu->totvert) { + min= MIN2 (min, icu->bezt[0].vec[1][0]); + max= MAX2 (max, icu->bezt[icu->totvert-1].vec[1][0]); + foundvert=1; + } + } + } + } + } + } + } + if (foundvert) { + if(min==max) max+= 1.0f; + *start= min; + *end= max; + } + else { + *start= 0.0f; + *end= 1.0f; + } +} + +/* Copy the data from the action-pose (src) into the pose */ +/* both args are assumed to be valid */ +/* exported to game engine */ +void extract_pose_from_pose(bPose *pose, const bPose *src) +{ + const bPoseChannel *schan; + bPoseChannel *pchan= pose->chanbase.first; + + for (schan=src->chanbase.first; schan; schan=schan->next, pchan= pchan->next) { + copy_pose_channel_data(pchan, schan); + } +} + +/* Pose should exist, can have any number of channels too (used for constraint) */ +void extract_pose_from_action(bPose *pose, bAction *act, float ctime) +{ + bActionChannel *achan; + bPoseChannel *pchan; + Ipo *ipo; + + if (!act) + return; + if (!pose) + return; + + /* Copy the data from the action into the pose */ + for (pchan= pose->chanbase.first; pchan; pchan=pchan->next) { + /* skip this pose channel if it has been tagged as having unkeyed poses */ + if ((pchan->bone) && (pchan->bone->flag & BONE_UNKEYED)) + continue; + + /* get action channel and clear pchan-transform flags */ + achan= get_action_channel(act, pchan->name); + pchan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE); + + if (achan) { + ipo = achan->ipo; + if (ipo) { + /* Evaluates and sets the internal ipo value */ + calc_ipo(ipo, ctime); + /* This call also sets the pchan flags */ + execute_action_ipo(achan, pchan); + } + /* 0 = do all ipos, not only drivers */ + do_constraint_channels(&pchan->constraints, &achan->constraintChannels, ctime, 0); + } + } + + pose->ctime= ctime; /* used for cyclic offset matching */ +} + +/* for do_all_pose_actions, clears the pose. Now also exported for proxy and tools */ +void rest_pose(bPose *pose) +{ + bPoseChannel *pchan; + int i; + + if (!pose) + return; + + memset(pose->stride_offset, 0, sizeof(pose->stride_offset)); + memset(pose->cyclic_offset, 0, sizeof(pose->cyclic_offset)); + + for (pchan=pose->chanbase.first; pchan; pchan= pchan->next){ + for (i=0; i<3; i++) { + pchan->loc[i]= 0.0f; + pchan->quat[i+1]= 0.0f; + pchan->size[i]= 1.0f; + } + pchan->quat[0]= 1.0f; + + pchan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE); + } +} + +/* both poses should be in sync */ +void copy_pose_result(bPose *to, bPose *from) +{ + bPoseChannel *pchanto, *pchanfrom; + + if(to==NULL || from==NULL) { + printf("pose result copy error\n"); // debug temp + return; + } + + for(pchanfrom= from->chanbase.first; pchanfrom; pchanfrom= pchanfrom->next) { + pchanto= get_pose_channel(to, pchanfrom->name); + if(pchanto) { + Mat4CpyMat4(pchanto->pose_mat, pchanfrom->pose_mat); + Mat4CpyMat4(pchanto->chan_mat, pchanfrom->chan_mat); + /* used for local constraints */ + VECCOPY(pchanto->loc, pchanfrom->loc); + QUATCOPY(pchanto->quat, pchanfrom->quat); + VECCOPY(pchanto->size, pchanfrom->size); + + VECCOPY(pchanto->pose_head, pchanfrom->pose_head); + VECCOPY(pchanto->pose_tail, pchanfrom->pose_tail); + pchanto->flag= pchanfrom->flag; + } + } +} + +/* ********** NLA with non-poses works with ipo channels ********** */ + +typedef struct NlaIpoChannel { + struct NlaIpoChannel *next, *prev; + float val; + void *poin; + int type; +} NlaIpoChannel; + +static void extract_ipochannels_from_action(ListBase *lb, ID *id, bAction *act, char *name, float ctime) +{ + bActionChannel *achan= get_action_channel(act, name); + IpoCurve *icu; + NlaIpoChannel *nic; + + if(achan==NULL) return; + + if(achan->ipo) { + calc_ipo(achan->ipo, ctime); + + for(icu= achan->ipo->curve.first; icu; icu= icu->next) { + /* skip IPO_BITS, is for layers and cannot be blended */ + if(icu->vartype != IPO_BITS) { + nic= MEM_callocN(sizeof(NlaIpoChannel), "NlaIpoChannel"); + BLI_addtail(lb, nic); + nic->val= icu->curval; + nic->poin= get_ipo_poin(id, icu, &nic->type); + } + } + } + + /* constraint channels only for objects */ + if(GS(id->name)==ID_OB) { + Object *ob= (Object *)id; + bConstraint *con; + bConstraintChannel *conchan; + + for (con=ob->constraints.first; con; con=con->next) { + conchan = get_constraint_channel(&achan->constraintChannels, con->name); + + if(conchan && conchan->ipo) { + calc_ipo(conchan->ipo, ctime); + + icu= conchan->ipo->curve.first; // only one ipo now + if(icu) { + nic= MEM_callocN(sizeof(NlaIpoChannel), "NlaIpoChannel constr"); + BLI_addtail(lb, nic); + nic->val= icu->curval; + nic->poin= &con->enforce; + nic->type= IPO_FLOAT; + } + } + } + } +} + +static NlaIpoChannel *find_nla_ipochannel(ListBase *lb, void *poin) +{ + NlaIpoChannel *nic; + + if(poin) { + for(nic= lb->first; nic; nic= nic->next) { + if(nic->poin==poin) + return nic; + } + } + return NULL; +} + + +static void blend_ipochannels(ListBase *dst, ListBase *src, float srcweight, int mode) +{ + NlaIpoChannel *snic, *dnic, *next; + float dstweight; + + switch (mode){ + case ACTSTRIPMODE_BLEND: + dstweight = 1.0F - srcweight; + break; + case ACTSTRIPMODE_ADD: + dstweight = 1.0F; + break; + default : + dstweight = 1.0F; + } + + for(snic= src->first; snic; snic= next) { + next= snic->next; + + dnic= find_nla_ipochannel(dst, snic->poin); + if(dnic==NULL) { + /* remove from src list, and insert in dest */ + BLI_remlink(src, snic); + BLI_addtail(dst, snic); + } + else { + /* we do the blend */ + dnic->val= dstweight*dnic->val + srcweight*snic->val; + } + } +} + +static void execute_ipochannels(ListBase *lb) +{ + NlaIpoChannel *nic; + + for(nic= lb->first; nic; nic= nic->next) { + if(nic->poin) { + write_ipo_poin(nic->poin, nic->type, nic->val); + } + } +} + +/* nla timing */ + +/* this now only used for repeating cycles, to enable fields and blur. */ +/* the whole time control in blender needs serious thinking... */ +static float nla_time(float cfra, float unit) +{ + extern float bluroffs; // bad construct, borrowed from object.c for now + extern float fieldoffs; + + /* motion blur & fields */ + cfra+= unit*(bluroffs+fieldoffs); + + /* global time */ + cfra*= G.scene->r.framelen; + + + /* decide later... */ +// if(no_speed_curve==0) if(ob && ob->ipo) cfra= calc_ipo_time(ob->ipo, cfra); + + return cfra; +} + +/* added "sizecorr" here, to allow armatures to be scaled and still have striding. + Only works for uniform scaling. In general I'd advise against scaling armatures ever though! (ton) +*/ +static float stridechannel_frame(Object *ob, float sizecorr, bActionStrip *strip, Path *path, float pathdist, float *stride_offset) +{ + bAction *act= strip->act; + char *name= strip->stridechannel; + bActionChannel *achan= get_action_channel(act, name); + int stride_axis= strip->stride_axis; + + if(achan && achan->ipo) { + IpoCurve *icu= NULL; + float minx=0.0f, maxx=0.0f, miny=0.0f, maxy=0.0f; + int foundvert= 0; + + if(stride_axis==0) stride_axis= AC_LOC_X; + else if(stride_axis==1) stride_axis= AC_LOC_Y; + else stride_axis= AC_LOC_Z; + + /* calculate the min/max */ + for (icu=achan->ipo->curve.first; icu; icu=icu->next) { + if(icu->adrcode==stride_axis) { + if(icu->totvert>1) { + foundvert= 1; + minx= icu->bezt[0].vec[1][0]; + maxx= icu->bezt[icu->totvert-1].vec[1][0]; + + miny= icu->bezt[0].vec[1][1]; + maxy= icu->bezt[icu->totvert-1].vec[1][1]; + } + break; + } + } + + if(foundvert && miny!=maxy) { + float stridelen= sizecorr*fabs(maxy-miny), striptime; + float actiondist, pdist, pdistNewNormalized, offs; + float vec1[4], vec2[4], dir[3]; + + /* internal cycling, actoffs is in frames */ + offs= stridelen*strip->actoffs/(maxx-minx); + + /* amount path moves object */ + pdist = (float)fmod (pathdist+offs, stridelen); + striptime= pdist/stridelen; + + /* amount stride bone moves */ + actiondist= sizecorr*eval_icu(icu, minx + striptime*(maxx-minx)) - miny; + + pdist = fabs(actiondist) - pdist; + pdistNewNormalized = (pathdist+pdist)/path->totdist; + + /* now we need to go pdist further (or less) on cu path */ + where_on_path(ob, (pathdist)/path->totdist, vec1, dir); /* vec needs size 4 */ + if (pdistNewNormalized <= 1) { + // search for correction in positive path-direction + where_on_path(ob, pdistNewNormalized, vec2, dir); /* vec needs size 4 */ + VecSubf(stride_offset, vec2, vec1); + } + else { + // we reached the end of the path, search backwards instead + where_on_path(ob, (pathdist-pdist)/path->totdist, vec2, dir); /* vec needs size 4 */ + VecSubf(stride_offset, vec1, vec2); + } + Mat4Mul3Vecfl(ob->obmat, stride_offset); + return striptime; + } + } + return 0.0f; +} + +static void cyclic_offs_bone(Object *ob, bPose *pose, bActionStrip *strip, float time) +{ + /* only called when strip has cyclic, so >= 1.0f works... */ + if(time >= 1.0f) { + bActionChannel *achan= get_action_channel(strip->act, strip->offs_bone); + + if(achan && achan->ipo) { + IpoCurve *icu= NULL; + Bone *bone; + float min[3]={0.0f, 0.0f, 0.0f}, max[3]={0.0f, 0.0f, 0.0f}; + int index=0, foundvert= 0; + + /* calculate the min/max */ + for (icu=achan->ipo->curve.first; icu; icu=icu->next) { + if(icu->totvert>1) { + + if(icu->adrcode==AC_LOC_X) + index= 0; + else if(icu->adrcode==AC_LOC_Y) + index= 1; + else if(icu->adrcode==AC_LOC_Z) + index= 2; + else + continue; + + foundvert= 1; + min[index]= icu->bezt[0].vec[1][1]; + max[index]= icu->bezt[icu->totvert-1].vec[1][1]; + } + } + if(foundvert) { + /* bring it into armature space */ + VecSubf(min, max, min); + bone= get_named_bone(ob->data, strip->offs_bone); /* weak */ + if(bone) { + Mat4Mul3Vecfl(bone->arm_mat, min); + + /* dominant motion, cyclic_offset was cleared in rest_pose */ + if (strip->flag & (ACTSTRIP_CYCLIC_USEX | ACTSTRIP_CYCLIC_USEY | ACTSTRIP_CYCLIC_USEZ)) { + if (strip->flag & ACTSTRIP_CYCLIC_USEX) pose->cyclic_offset[0]= time*min[0]; + if (strip->flag & ACTSTRIP_CYCLIC_USEY) pose->cyclic_offset[1]= time*min[1]; + if (strip->flag & ACTSTRIP_CYCLIC_USEZ) pose->cyclic_offset[2]= time*min[2]; + } else { + if( fabs(min[0]) >= fabs(min[1]) && fabs(min[0]) >= fabs(min[2])) + pose->cyclic_offset[0]= time*min[0]; + else if( fabs(min[1]) >= fabs(min[0]) && fabs(min[1]) >= fabs(min[2])) + pose->cyclic_offset[1]= time*min[1]; + else + pose->cyclic_offset[2]= time*min[2]; + } + } + } + } + } +} + +/* simple case for now; only the curve path with constraint value > 0.5 */ +/* blending we might do later... */ +static Object *get_parent_path(Object *ob) +{ + bConstraint *con; + + if(ob->parent && ob->parent->type==OB_CURVE) + return ob->parent; + + for (con = ob->constraints.first; con; con=con->next) { + if(con->type==CONSTRAINT_TYPE_FOLLOWPATH) { + if(con->enforce>0.5f) { + bFollowPathConstraint *data= con->data; + return data->tar; + } + } + } + return NULL; +} + +/* ************** do the action ************ */ + +/* For the calculation of the effects of an action at the given frame on an object + * This is currently only used for the action constraint + */ +void what_does_obaction (Object *ob, bAction *act, float cframe) +{ + ListBase tchanbase= {NULL, NULL}; + + clear_workob(); + Mat4CpyMat4(workob.obmat, ob->obmat); + Mat4CpyMat4(workob.parentinv, ob->parentinv); + Mat4CpyMat4(workob.constinv, ob->constinv); + workob.parent= ob->parent; + workob.track= ob->track; + + workob.trackflag= ob->trackflag; + workob.upflag= ob->upflag; + + workob.partype= ob->partype; + workob.par1= ob->par1; + workob.par2= ob->par2; + workob.par3= ob->par3; + + workob.constraints.first = ob->constraints.first; + workob.constraints.last = ob->constraints.last; + + strcpy(workob.parsubstr, ob->parsubstr); + + /* extract_ipochannels_from_action needs id's! */ + workob.action= act; + + extract_ipochannels_from_action(&tchanbase, &ob->id, act, "Object", bsystem_time(&workob, cframe, 0.0)); + + if (tchanbase.first) { + execute_ipochannels(&tchanbase); + BLI_freelistN(&tchanbase); + } +} + +/* ----- nla, etc. --------- */ + +static void do_nla(Object *ob, int blocktype) +{ + bPose *tpose= NULL; + Key *key= NULL; + ListBase tchanbase={NULL, NULL}, chanbase={NULL, NULL}; + bActionStrip *strip, *striplast=NULL, *stripfirst=NULL; + float striptime, frametime, length, actlength; + float blendfac, stripframe; + float scene_cfra= frame_to_float(G.scene->r.cfra); + int doit, dostride; + + if(blocktype==ID_AR) { + copy_pose(&tpose, ob->pose, 1); + rest_pose(ob->pose); // potentially destroying current not-keyed pose + } + else { + key= ob_get_key(ob); + } + + /* check on extend to left or right, when no strip is hit by 'cfra' */ + for (strip=ob->nlastrips.first; strip; strip=strip->next) { + /* escape loop on a hit */ + if( scene_cfra >= strip->start && scene_cfra <= strip->end + 0.1f) /* note 0.1 comes back below */ + break; + if(scene_cfra < strip->start) { + if(stripfirst==NULL) + stripfirst= strip; + else if(stripfirst->start > strip->start) + stripfirst= strip; + } + else if(scene_cfra > strip->end) { + if(striplast==NULL) + striplast= strip; + else if(striplast->end < strip->end) + striplast= strip; + } + } + if(strip==NULL) { /* extend */ + if(striplast) + scene_cfra= striplast->end; + else if(stripfirst) + scene_cfra= stripfirst->start; + } + + /* and now go over all strips */ + for (strip=ob->nlastrips.first; strip; strip=strip->next){ + doit=dostride= 0; + + if (strip->act && !(strip->flag & ACTSTRIP_MUTE)) { /* so theres an action */ + + /* Determine if the current frame is within the strip's range */ + length = strip->end-strip->start; + actlength = strip->actend-strip->actstart; + striptime = (scene_cfra-(strip->start)) / length; + stripframe = (scene_cfra-(strip->start)) ; + + if (striptime>=0.0){ + + if(blocktype==ID_AR) + rest_pose(tpose); + + /* To handle repeat, we add 0.1 frame extra to make sure the last frame is included */ + if (striptime < 1.0f + 0.1f/length) { + + /* Handle path */ + if ((strip->flag & ACTSTRIP_USESTRIDE) && (blocktype==ID_AR) && (ob->ipoflag & OB_DISABLE_PATH)==0){ + Object *parent= get_parent_path(ob); + + if (parent) { + Curve *cu = parent->data; + float ctime, pdist; + + if (cu->flag & CU_PATH){ + /* Ensure we have a valid path */ + if(cu->path==NULL || cu->path->data==NULL) makeDispListCurveTypes(parent, 0); + if(cu->path) { + + /* Find the position on the path */ + ctime= bsystem_time(ob, scene_cfra, 0.0); + + if(calc_ipo_spec(cu->ipo, CU_SPEED, &ctime)==0) { + /* correct for actions not starting on zero */ + ctime= (ctime - strip->actstart)/cu->pathlen; + CLAMP(ctime, 0.0, 1.0); + } + pdist = ctime*cu->path->totdist; + + if(tpose && strip->stridechannel[0]) { + striptime= stridechannel_frame(parent, ob->size[0], strip, cu->path, pdist, tpose->stride_offset); + } + else { + if (strip->stridelen) { + striptime = pdist / strip->stridelen; + striptime = (float)fmod (striptime+strip->actoffs, 1.0); + } + else + striptime = 0; + } + + frametime = (striptime * actlength) + strip->actstart; + frametime= bsystem_time(ob, frametime, 0.0); + + if(blocktype==ID_AR) { + extract_pose_from_action (tpose, strip->act, frametime); + } + else if(blocktype==ID_OB) { + extract_ipochannels_from_action(&tchanbase, &ob->id, strip->act, "Object", frametime); + if(key) + extract_ipochannels_from_action(&tchanbase, &key->id, strip->act, "Shape", frametime); + } + doit=dostride= 1; + } + } + } + } + /* To handle repeat, we add 0.1 frame extra to make sure the last frame is included */ + else { + + /* Mod to repeat */ + if(strip->repeat!=1.0f) { + float cycle= striptime*strip->repeat; + + striptime = (float)fmod (cycle, 1.0f + 0.1f/length); + cycle-= striptime; + + if(blocktype==ID_AR) + cyclic_offs_bone(ob, tpose, strip, cycle); + } + + frametime = (striptime * actlength) + strip->actstart; + frametime= nla_time(frametime, (float)strip->repeat); + + if(blocktype==ID_AR) { + extract_pose_from_action (tpose, strip->act, frametime); + } + else if(blocktype==ID_OB) { + extract_ipochannels_from_action(&tchanbase, &ob->id, strip->act, "Object", frametime); + if(key) + extract_ipochannels_from_action(&tchanbase, &key->id, strip->act, "Shape", frametime); + } + + doit=1; + } + } + /* Handle extend */ + else { + if (strip->flag & ACTSTRIP_HOLDLASTFRAME){ + /* we want the strip to hold on the exact fraction of the repeat value */ + + frametime = actlength * (strip->repeat-(int)strip->repeat); + if(frametime<=0.000001f) frametime= actlength; /* rounding errors... */ + frametime= bsystem_time(ob, frametime+strip->actstart, 0.0); + + if(blocktype==ID_AR) + extract_pose_from_action (tpose, strip->act, frametime); + else if(blocktype==ID_OB) { + extract_ipochannels_from_action(&tchanbase, &ob->id, strip->act, "Object", frametime); + if(key) + extract_ipochannels_from_action(&tchanbase, &key->id, strip->act, "Shape", frametime); + } + + /* handle cycle hold */ + if(strip->repeat!=1.0f) { + if(blocktype==ID_AR) + cyclic_offs_bone(ob, tpose, strip, strip->repeat-1.0f); + } + + doit=1; + } + } + + /* Handle blendin & blendout */ + if (doit){ + /* Handle blendin */ + + if (strip->blendin>0.0 && stripframe<=strip->blendin && scene_cfra>=strip->start){ + blendfac = stripframe/strip->blendin; + } + else if (strip->blendout>0.0 && stripframe>=(length-strip->blendout) && scene_cfra<=strip->end){ + blendfac = (length-stripframe)/(strip->blendout); + } + else + blendfac = 1; + + if(blocktype==ID_AR) {/* Blend this pose with the accumulated pose */ + /* offset bone, for matching cycles */ + blend_pose_offset_bone (strip, ob->pose, tpose, blendfac, strip->mode); + + blend_poses (ob->pose, tpose, blendfac, strip->mode); + if(dostride) + blend_pose_strides (ob->pose, tpose, blendfac, strip->mode); + } + else { + blend_ipochannels(&chanbase, &tchanbase, blendfac, strip->mode); + BLI_freelistN(&tchanbase); + } + } + } + } + } + + if(blocktype==ID_OB) { + execute_ipochannels(&chanbase); + } + else if(blocktype==ID_AR) { + /* apply stride offset to object */ + VecAddf(ob->obmat[3], ob->obmat[3], ob->pose->stride_offset); + } + + /* free */ + if (tpose){ + free_pose_channels(tpose); + MEM_freeN(tpose); + } + if(chanbase.first) + BLI_freelistN(&chanbase); +} + +void do_all_pose_actions(Object *ob) +{ + /* only to have safe calls from editor */ + if(ob==NULL) return; + if(ob->type!=OB_ARMATURE || ob->pose==NULL) return; + + if(ob->pose->flag & POSE_LOCKED) { /* no actions to execute while transform */ + if(ob->pose->flag & POSE_DO_UNLOCK) + ob->pose->flag &= ~(POSE_LOCKED|POSE_DO_UNLOCK); + } + else if(ob->action && ((ob->nlaflag & OB_NLA_OVERRIDE)==0 || ob->nlastrips.first==NULL) ) { + float cframe= (float) G.scene->r.cfra; + + cframe= get_action_frame(ob, cframe); + + extract_pose_from_action (ob->pose, ob->action, bsystem_time(ob, cframe, 0.0)); + } + else if(ob->nlastrips.first) { + do_nla(ob, ID_AR); + } + + /* clear POSE_DO_UNLOCK flags that might have slipped through (just in case) */ + ob->pose->flag &= ~POSE_DO_UNLOCK; +} + +/* called from where_is_object */ +void do_all_object_actions(Object *ob) +{ + if(ob==NULL) return; + if(ob->dup_group) return; /* prevent conflicts, might add smarter check later */ + + /* Do local action */ + if(ob->action && ((ob->nlaflag & OB_NLA_OVERRIDE)==0 || ob->nlastrips.first==NULL) ) { + ListBase tchanbase= {NULL, NULL}; + Key *key= ob_get_key(ob); + float cframe= (float) G.scene->r.cfra; + + cframe= get_action_frame(ob, cframe); + + extract_ipochannels_from_action(&tchanbase, &ob->id, ob->action, "Object", bsystem_time(ob, cframe, 0.0)); + if(key) + extract_ipochannels_from_action(&tchanbase, &key->id, ob->action, "Shape", bsystem_time(ob, cframe, 0.0)); + + if(tchanbase.first) { + execute_ipochannels(&tchanbase); + BLI_freelistN(&tchanbase); + } + } + else if(ob->nlastrips.first) { + do_nla(ob, ID_OB); + } +} diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c new file mode 100644 index 00000000000..32ea2b3ed2c --- /dev/null +++ b/source/blender/blenkernel/intern/anim.c @@ -0,0 +1,844 @@ +/** anim.c + * + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include + +#include "MEM_guardedalloc.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "DNA_listBase.h" + +#include "DNA_curve_types.h" +#include "DNA_effect_types.h" +#include "DNA_group_types.h" +#include "DNA_key_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_view3d_types.h" +#include "DNA_vfont_types.h" + +#include "BKE_anim.h" +#include "BKE_DerivedMesh.h" +#include "BKE_displist.h" +#include "BKE_effect.h" +#include "BKE_font.h" +#include "BKE_group.h" +#include "BKE_global.h" +#include "BKE_ipo.h" +#include "BKE_key.h" +#include "BKE_main.h" +#include "BKE_object.h" +#include "BKE_utildefines.h" + +#include "BKE_bad_level_calls.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +void free_path(Path *path) +{ + if(path->data) MEM_freeN(path->data); + MEM_freeN(path); +} + + +void calc_curvepath(Object *ob) +{ + BevList *bl; + BevPoint *bevp, *bevpn, *bevpfirst, *bevplast, *tempbevp; + Curve *cu; + Nurb *nu; + Path *path; + float *fp, *dist, *maxdist, x, y, z; + float fac, d=0, fac1, fac2; + int a, tot, cycl=0; + float *ft; + + /* in a path vertices are with equal differences: path->len = number of verts */ + /* NOW WITH BEVELCURVE!!! */ + + if(ob==NULL || ob->type != OB_CURVE) return; + cu= ob->data; + if(ob==G.obedit) nu= editNurb.first; + else nu= cu->nurb.first; + + if(cu->path) free_path(cu->path); + cu->path= NULL; + + bl= cu->bev.first; + if(bl==NULL) return; + + cu->path=path= MEM_callocN(sizeof(Path), "path"); + + /* if POLY: last vertice != first vertice */ + cycl= (bl->poly!= -1); + + if(cycl) tot= bl->nr; + else tot= bl->nr-1; + + path->len= tot+1; + /* exception: vector handle paths and polygon paths should be subdivided at least a factor resolu */ + if(path->lenresolu*nu->pntsu) path->len= nu->resolu*nu->pntsu; + + dist= (float *)MEM_mallocN((tot+1)*4, "calcpathdist"); + + /* all lengths in *dist */ + bevp= bevpfirst= (BevPoint *)(bl+1); + fp= dist; + *fp= 0; + for(a=0; ax - bevp->x; + y= bevpfirst->y - bevp->y; + z= bevpfirst->z - bevp->z; + } + else { + tempbevp = bevp+1; + x= (tempbevp)->x - bevp->x; + y= (tempbevp)->y - bevp->y; + z= (tempbevp)->z - bevp->z; + } + *fp= *(fp-1)+ (float)sqrt(x*x+y*y+z*z); + + bevp++; + } + + path->totdist= *fp; + + /* the path verts in path->data */ + /* now also with TILT value */ + ft= path->data = (float *)MEM_callocN(16*path->len, "pathdata"); + + bevp= bevpfirst; + bevpn= bevp+1; + bevplast= bevpfirst + (bl->nr-1); + fp= dist+1; + maxdist= dist+tot; + fac= 1.0f/((float)path->len-1.0f); + fac = fac * path->totdist; + + for(a=0; alen; a++) { + + d= ((float)a)*fac; + + /* we're looking for location (distance) 'd' in the array */ + while((d>= *fp) && fpbevplast) { + if(cycl) bevpn= bevpfirst; + else bevpn= bevplast; + } + } + + fac1= *(fp)- *(fp-1); + fac2= *(fp)-d; + fac1= fac2/fac1; + fac2= 1.0f-fac1; + + ft[0]= fac1*bevp->x+ fac2*(bevpn)->x; + ft[1]= fac1*bevp->y+ fac2*(bevpn)->y; + ft[2]= fac1*bevp->z+ fac2*(bevpn)->z; + ft[3]= fac1*bevp->alfa+ fac2*(bevpn)->alfa; + + ft+= 4; + + } + + MEM_freeN(dist); +} + +int interval_test(int min, int max, int p1, int cycl) +{ + + if(cycl) { + if( p1 < min) + p1= ((p1 -min) % (max-min+1)) + max+1; + else if(p1 > max) + p1= ((p1 -min) % (max-min+1)) + min; + } + else { + if(p1 < min) p1= min; + else if(p1 > max) p1= max; + } + return p1; +} + +/* warning, *vec needs FOUR items! */ +/* ctime is normalized range <0-1> */ +int where_on_path(Object *ob, float ctime, float *vec, float *dir) /* returns OK */ +{ + Curve *cu; + Nurb *nu; + BevList *bl; + Path *path; + float *fp, *p0, *p1, *p2, *p3, fac; + float data[4]; + int cycl=0, s0, s1, s2, s3; + + if(ob==NULL || ob->type != OB_CURVE) return 0; + cu= ob->data; + if(cu->path==NULL || cu->path->data==NULL) { + printf("no path!\n"); + } + path= cu->path; + fp= path->data; + + /* test for cyclic */ + bl= cu->bev.first; + if(bl && bl->poly> -1) cycl= 1; + + ctime *= (path->len-1); + + s1= (int)floor(ctime); + fac= (float)(s1+1)-ctime; + + /* path->len is corected for cyclic */ + s0= interval_test(0, path->len-1-cycl, s1-1, cycl); + s1= interval_test(0, path->len-1-cycl, s1, cycl); + s2= interval_test(0, path->len-1-cycl, s1+1, cycl); + s3= interval_test(0, path->len-1-cycl, s1+2, cycl); + + p0= fp + 4*s0; + p1= fp + 4*s1; + p2= fp + 4*s2; + p3= fp + 4*s3; + + /* note, commented out for follow constraint */ + //if(cu->flag & CU_FOLLOW) { + + set_afgeleide_four_ipo(1.0f-fac, data, KEY_BSPLINE); + + dir[0]= data[0]*p0[0] + data[1]*p1[0] + data[2]*p2[0] + data[3]*p3[0] ; + dir[1]= data[0]*p0[1] + data[1]*p1[1] + data[2]*p2[1] + data[3]*p3[1] ; + dir[2]= data[0]*p0[2] + data[1]*p1[2] + data[2]*p2[2] + data[3]*p3[2] ; + + /* make compatible with vectoquat */ + dir[0]= -dir[0]; + dir[1]= -dir[1]; + dir[2]= -dir[2]; + //} + + nu= cu->nurb.first; + + /* make sure that first and last frame are included in the vectors here */ + if((nu->type & 7)==CU_POLY) set_four_ipo(1.0f-fac, data, KEY_LINEAR); + else if((nu->type & 7)==CU_BEZIER) set_four_ipo(1.0f-fac, data, KEY_LINEAR); + else if(s0==s1 || p2==p3) set_four_ipo(1.0f-fac, data, KEY_CARDINAL); + else set_four_ipo(1.0f-fac, data, KEY_BSPLINE); + + vec[0]= data[0]*p0[0] + data[1]*p1[0] + data[2]*p2[0] + data[3]*p3[0] ; + vec[1]= data[0]*p0[1] + data[1]*p1[1] + data[2]*p2[1] + data[3]*p3[1] ; + vec[2]= data[0]*p0[2] + data[1]*p1[2] + data[2]*p2[2] + data[3]*p3[2] ; + + vec[3]= data[0]*p0[3] + data[1]*p1[3] + data[2]*p2[3] + data[3]*p3[3] ; + + return 1; +} + +/* ****************** DUPLICATOR ************** */ + +static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[][4], int lay, int index) +{ + DupliObject *dob= MEM_callocN(sizeof(DupliObject), "dupliobject"); + + BLI_addtail(lb, dob); + dob->ob= ob; + Mat4CpyMat4(dob->mat, mat); + Mat4CpyMat4(dob->omat, ob->obmat); + dob->origlay= ob->lay; + dob->index= index; + ob->lay= lay; + + /* allowing duplicators for particle systems... a bit silly still */ + { + PartEff *paf= give_parteff(ob); + if(paf) { + Mat4Invert(ob->imat, ob->obmat); + Mat4CpyMat4(paf->imat, ob->imat); + } + } + return dob; +} + +static void group_duplilist(ListBase *lb, Object *ob, int level) +{ + DupliObject *dob; + Group *group; + GroupObject *go; + float mat[4][4]; + + if(ob->dup_group==NULL) return; + group= ob->dup_group; + + /* simple preventing of too deep nested groups */ + if(level>4) return; + + /* handles animated groups, and */ + /* we need to check update for objects that are not in scene... */ + group_handle_recalc_and_update(ob, group); + + for(go= group->gobject.first; go; go= go->next) { + /* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */ + if(go->ob!=ob) { + Mat4MulMat4(mat, go->ob->obmat, ob->obmat); + dob= new_dupli_object(lb, go->ob, mat, ob->lay, 0); + dob->no_draw= (dob->origlay & group->layer)==0; + + if(go->ob->dup_group && (go->ob->transflag & OB_DUPLIGROUP)) { + Mat4CpyMat4(dob->ob->obmat, dob->mat); + group_duplilist(lb, go->ob, level+1); + Mat4CpyMat4(dob->ob->obmat, dob->omat); + } + } + } +} + +static void frames_duplilist(ListBase *lb, Object *ob) +{ + extern int enable_cu_speed; /* object.c */ + Object copyob; + int cfrao, ok; + + cfrao= G.scene->r.cfra; + if(ob->parent==NULL && ob->track==NULL && ob->ipo==NULL && ob->constraints.first==NULL) return; + + if(ob->transflag & OB_DUPLINOSPEED) enable_cu_speed= 0; + copyob= *ob; /* store transform info */ + + for(G.scene->r.cfra= ob->dupsta; G.scene->r.cfra<=ob->dupend; G.scene->r.cfra++) { + + ok= 1; + if(ob->dupoff) { + ok= G.scene->r.cfra - ob->dupsta; + ok= ok % (ob->dupon+ob->dupoff); + if(ok < ob->dupon) ok= 1; + else ok= 0; + } + if(ok) { + do_ob_ipo(ob); + where_is_object_time(ob, (float)G.scene->r.cfra); + new_dupli_object(lb, ob, ob->obmat, ob->lay, G.scene->r.cfra); + } + } + + *ob= copyob; /* restore transform info */ + G.scene->r.cfra= cfrao; + enable_cu_speed= 1; +} + +struct vertexDupliData { + ListBase *lb; + float pmat[4][4]; + Object *ob, *par; +}; + +static void vertex_dupli__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s) +{ + struct vertexDupliData *vdd= userData; + float vec[3], *q2, mat[3][3], tmat[4][4], obmat[4][4]; + + VECCOPY(vec, co); + Mat4MulVecfl(vdd->pmat, vec); + VecSubf(vec, vec, vdd->pmat[3]); + VecAddf(vec, vec, vdd->ob->obmat[3]); + + Mat4CpyMat4(obmat, vdd->ob->obmat); + VECCOPY(obmat[3], vec); + + if(vdd->par->transflag & OB_DUPLIROT) { + if(no_f) { + vec[0]= -no_f[0]; vec[1]= -no_f[1]; vec[2]= -no_f[2]; + } + else if(no_s) { + vec[0]= -no_s[0]; vec[1]= -no_s[1]; vec[2]= -no_s[2]; + } + + q2= vectoquat(vec, vdd->ob->trackflag, vdd->ob->upflag); + + QuatToMat3(q2, mat); + Mat4CpyMat4(tmat, obmat); + Mat4MulMat43(obmat, tmat, mat); + } + new_dupli_object(vdd->lb, vdd->ob, obmat, vdd->par->lay, index); +} + +static void vertex_duplilist(ListBase *lb, Scene *sce, Object *par) +{ + Object *ob; + Base *base; + float vec[3], no[3], pmat[4][4]; + int lay, totvert, a; + DerivedMesh *dm; + + Mat4CpyMat4(pmat, par->obmat); + + lay= G.scene->lay; + + if(par==G.obedit) + dm= editmesh_get_derived_cage(CD_MASK_BAREMESH); + else + dm = mesh_get_derived_deform(par, CD_MASK_BAREMESH); + + totvert = dm->getNumVerts(dm); + + base= sce->base.first; + while(base) { + + if(base->object->type>0 && (lay & base->lay) && G.obedit!=base->object) { + ob= base->object->parent; + while(ob) { + if(ob==par) { + struct vertexDupliData vdd; + + ob= base->object; + vdd.lb= lb; + vdd.ob= ob; + vdd.par= par; + Mat4CpyMat4(vdd.pmat, pmat); + + /* mballs have a different dupli handling */ + if(ob->type!=OB_MBALL) ob->flag |= OB_DONE; /* doesnt render */ + + if(par==G.obedit) { + dm->foreachMappedVert(dm, vertex_dupli__mapFunc, (void*) &vdd); + } + else { + for(a=0; agetVertCo(dm, a, vec); + dm->getVertNo(dm, a, no); + + vertex_dupli__mapFunc(&vdd, a, vec, no, NULL); + } + } + + break; + } + ob= ob->parent; + } + } + base= base->next; + } + + dm->release(dm); +} + +static void face_duplilist(ListBase *lb, Scene *sce, Object *par) +{ + Object *ob; + Base *base; + DerivedMesh *dm; + MFace *mface; + MVert *mvert; + float pmat[4][4], imat[3][3]; + int lay, totface, a; + + Mat4CpyMat4(pmat, par->obmat); + + lay= G.scene->lay; + + if(par==G.obedit) { + int totvert; + dm= editmesh_get_derived_cage(CD_MASK_BAREMESH); + + totface= dm->getNumFaces(dm); + mface= MEM_mallocN(sizeof(MFace)*totface, "mface temp"); + dm->copyFaceArray(dm, mface); + totvert= dm->getNumVerts(dm); + mvert= MEM_mallocN(sizeof(MVert)*totvert, "mvert temp"); + dm->copyVertArray(dm, mvert); + } + else { + dm = mesh_get_derived_deform(par, CD_MASK_BAREMESH); + + totface= dm->getNumFaces(dm); + mface= dm->getFaceArray(dm); + mvert= dm->getVertArray(dm); + } + + + for(base= sce->base.first; base; base= base->next) { + + if(base->object->type>0 && (lay & base->lay) && G.obedit!=base->object) { + ob= base->object->parent; + while(ob) { + if(ob==par) { + + ob= base->object; + Mat3CpyMat4(imat, ob->parentinv); + + /* mballs have a different dupli handling */ + if(ob->type!=OB_MBALL) ob->flag |= OB_DONE; /* doesnt render */ + + for(a=0; aobmat[3]); + + Mat4CpyMat4(obmat, ob->obmat); + VECCOPY(obmat[3], cent); + + /* rotation */ + triatoquat(v1, v2, v3, quat); + QuatToMat3(quat, mat); + + /* scale */ + if(par->transflag & OB_DUPLIFACES_SCALE) { + float size= v4?AreaQ3Dfl(v1, v2, v3, v4):AreaT3Dfl(v1, v2, v3); + size= sqrt(size); + Mat3MulFloat(mat[0], size); + } + + Mat3CpyMat3(mat3, mat); + Mat3MulMat3(mat, imat, mat3); + + Mat4CpyMat4(tmat, obmat); + Mat4MulMat43(obmat, tmat, mat); + + new_dupli_object(lb, ob, obmat, lay, a); + + } + + break; + } + ob= ob->parent; + } + } + } + + if(par==G.obedit) { + MEM_freeN(mface); + MEM_freeN(mvert); + } + + dm->release(dm); +} + + + +static void particle_duplilist(ListBase *lb, Scene *sce, Object *par, PartEff *paf) +{ + Object *ob, copyob; + Base *base; + Particle *pa; + float ctime, vec1[3]; + float vec[3], tmat[4][4], mat[3][3]; + float *q2; + int lay, a, counter; /* counter is used to find in render the indexed object */ + + pa= paf->keys; + if(pa==NULL || (G.rendering && paf->disp!=100)) { + build_particle_system(par); + pa= paf->keys; + if(pa==NULL) return; + } + + ctime= bsystem_time(par, (float)G.scene->r.cfra, 0.0); + + lay= G.scene->lay; + + for(base= sce->base.first; base; base= base->next) { + if(base->object->type>0 && (base->lay & lay) && G.obedit!=base->object) { + ob= base->object->parent; + while(ob) { + if(ob==par) { + + ob= base->object; + /* temp copy, to have ipos etc to work OK */ + copyob= *ob; + + /* don't want parent animation to apply on past object positions */ + if(!(paf->flag & PAF_STATIC)) + ob->parent= NULL; + + for(a=0, pa= paf->keys, counter=0; atotpart; a++, pa+=paf->totkey, counter++) { + + if(paf->flag & PAF_STATIC) { + float mtime; + + where_is_particle(paf, pa, pa->time, vec1); + mtime= pa->time+pa->lifetime; + + for(ctime= pa->time; ctimestaticstep, counter++) { + + /* make sure hair grows until the end.. */ + if(ctime>pa->time+pa->lifetime) ctime= pa->time+pa->lifetime; + + /* to give ipos in object correct offset */ + where_is_object_time(ob, ctime-pa->time); + + where_is_particle(paf, pa, ctime, vec); // makes sure there's always a vec + Mat4MulVecfl(par->obmat, vec); + + if(paf->stype==PAF_VECT) { + where_is_particle(paf, pa, ctime+1.0, vec1); // makes sure there's always a vec + Mat4MulVecfl(par->obmat, vec1); + + VecSubf(vec1, vec1, vec); + q2= vectoquat(vec1, ob->trackflag, ob->upflag); + + QuatToMat3(q2, mat); + Mat4CpyMat4(tmat, ob->obmat); + Mat4MulMat43(ob->obmat, tmat, mat); + } + + VECCOPY(ob->obmat[3], vec); + /* put object back in original state, so it cam be restored OK */ + Mat4CpyMat4(tmat, ob->obmat); + Mat4CpyMat4(ob->obmat, copyob.obmat); + new_dupli_object(lb, ob, tmat, par->lay, counter); + } + } + else { // non static particles + + if((paf->flag & PAF_UNBORN)==0 && ctime < pa->time) continue; + if((paf->flag & PAF_DIED)==0 && ctime > pa->time+pa->lifetime) continue; + + //if(ctime < pa->time+pa->lifetime) { + + /* to give ipos in object correct offset, ob->parent is NULLed */ + where_is_object_time(ob, ctime-pa->time); + + where_is_particle(paf, pa, ctime, vec); + if(paf->stype==PAF_VECT) { + + /* if particle died, we use previous position */ + if(ctime > pa->time+pa->lifetime) { + where_is_particle(paf, pa, pa->time+pa->lifetime-1.0f, vec1); + VecSubf(vec1, vec, vec1); + } + else { + where_is_particle(paf, pa, ctime+1.0f, vec1); + VecSubf(vec1, vec1, vec); + } + q2= vectoquat(vec1, ob->trackflag, ob->upflag); + + QuatToMat3(q2, mat); + Mat4CpyMat4(tmat, ob->obmat); + Mat4MulMat43(ob->obmat, tmat, mat); + } + + VECCOPY(ob->obmat[3], vec); + + /* put object back in original state, so it can be restored OK */ + Mat4CpyMat4(tmat, ob->obmat); + Mat4CpyMat4(ob->obmat, copyob.obmat); + new_dupli_object(lb, ob, tmat, par->lay, counter); + } + } + /* temp copy, to have ipos etc to work OK */ + *ob= copyob; + + break; + } + ob= ob->parent; + } + } + } + + if(G.rendering && paf->disp!=100) { + MEM_freeN(paf->keys); + paf->keys= NULL; + } + + +} + +static Object *find_family_object(Object **obar, char *family, char ch) +{ + Object *ob; + int flen; + + if( obar[ch] ) return obar[ch]; + + flen= strlen(family); + + ob= G.main->object.first; + while(ob) { + if( ob->id.name[flen+2]==ch ) { + if( strncmp(ob->id.name+2, family, flen)==0 ) break; + } + ob= ob->id.next; + } + + obar[ch]= ob; + + return ob; +} + + +static void font_duplilist(ListBase *lb, Object *par) +{ + Object *ob, *obar[256]; + Curve *cu; + struct chartrans *ct, *chartransdata; + float vec[3], obmat[4][4], pmat[4][4], fsize, xof, yof; + int slen, a; + + Mat4CpyMat4(pmat, par->obmat); + + /* in par the family name is stored, use this to find the other objects */ + + chartransdata= text_to_curve(par, FO_DUPLI); + if(chartransdata==0) return; + + memset(obar, 0, 256*sizeof(void *)); + + cu= par->data; + slen= strlen(cu->str); + fsize= cu->fsize; + xof= cu->xof; + yof= cu->yof; + + ct= chartransdata; + + for(a=0; afamily, cu->str[a]); + if(ob) { + vec[0]= fsize*(ct->xof - xof); + vec[1]= fsize*(ct->yof - yof); + vec[2]= 0.0; + + Mat4MulVecfl(pmat, vec); + + Mat4CpyMat4(obmat, par->obmat); + VECCOPY(obmat[3], vec); + + new_dupli_object(lb, ob, obmat, par->lay, a); + } + + } + + MEM_freeN(chartransdata); +} + +/* ***************************** */ + +/* note; group dupli's already set transform matrix. see note in group_duplilist() */ +ListBase *object_duplilist(Scene *sce, Object *ob) +{ + ListBase *duplilist= MEM_mallocN(sizeof(ListBase), "duplilist"); + duplilist->first= duplilist->last= NULL; + + if(ob->transflag & OB_DUPLI) { + if(ob->transflag & OB_DUPLIVERTS) { + if(ob->type==OB_MESH) { + PartEff *paf; + if( (paf=give_parteff(ob)) ) + particle_duplilist(duplilist, sce, ob, paf); + else + vertex_duplilist(duplilist, sce, ob); + } + else if(ob->type==OB_FONT) { + font_duplilist(duplilist, ob); + } + } + else if(ob->transflag & OB_DUPLIFACES) { + if(ob->type==OB_MESH) + face_duplilist(duplilist, sce, ob); + } + else if(ob->transflag & OB_DUPLIFRAMES) + frames_duplilist(duplilist, ob); + else if(ob->transflag & OB_DUPLIGROUP) { + DupliObject *dob; + + group_duplilist(duplilist, ob, 0); /* now recursive */ + + /* make copy already, because in group dupli's deform displists can be makde, requiring parent matrices */ + for(dob= duplilist->first; dob; dob= dob->next) + Mat4CpyMat4(dob->ob->obmat, dob->mat); + } + + } + + return duplilist; +} + +void free_object_duplilist(ListBase *lb) +{ + DupliObject *dob; + + for(dob= lb->first; dob; dob= dob->next) { + dob->ob->lay= dob->origlay; + Mat4CpyMat4(dob->ob->obmat, dob->omat); + } + + BLI_freelistN(lb); + MEM_freeN(lb); +} + +int count_duplilist(Object *ob) +{ + if(ob->transflag & OB_DUPLI) { + if(ob->transflag & OB_DUPLIVERTS) { + if(ob->type==OB_MESH) { + if(ob->transflag & OB_DUPLIVERTS) { + PartEff *paf; + if( (paf=give_parteff(ob)) ) { + return paf->totpart; + } + else { + Mesh *me= ob->data; + return me->totvert; + } + } + } + } + else if(ob->transflag & OB_DUPLIFRAMES) { + int tot= ob->dupend - ob->dupsta; + tot/= (ob->dupon+ob->dupoff); + return tot*ob->dupon; + } + } + return 1; +} diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c new file mode 100644 index 00000000000..40f4ae7298e --- /dev/null +++ b/source/blender/blenkernel/intern/armature.c @@ -0,0 +1,2130 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Full recode, Ton Roosendaal, Crete 2005 + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include +#include +#include +#include +#include "MEM_guardedalloc.h" + +#include "nla.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" + +#include "DNA_armature_types.h" +#include "DNA_action_types.h" +#include "DNA_constraint_types.h" +#include "DNA_mesh_types.h" +#include "DNA_lattice_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_nla_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_view3d_types.h" + +#include "BKE_armature.h" +#include "BKE_action.h" +#include "BKE_blender.h" +#include "BKE_constraint.h" +#include "BKE_curve.h" +#include "BKE_deform.h" +#include "BKE_depsgraph.h" +#include "BKE_DerivedMesh.h" +#include "BKE_displist.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_lattice.h" +#include "BKE_main.h" +#include "BKE_object.h" +#include "BKE_object.h" +#include "BKE_utildefines.h" + +#include "BIF_editdeform.h" + +#include "IK_solver.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +/* **************** Generic Functions, data level *************** */ + +bArmature *get_armature(Object *ob) +{ + if(ob==NULL) return NULL; + if(ob->type==OB_ARMATURE) return ob->data; + else return NULL; +} + +bArmature *add_armature(char *name) +{ + bArmature *arm; + + arm= alloc_libblock (&G.main->armature, ID_AR, name); + arm->deformflag = ARM_DEF_VGROUP|ARM_DEF_ENVELOPE; + arm->layer= 1; + return arm; +} + + +void free_boneChildren(Bone *bone) +{ + Bone *child; + + if (bone) { + + child=bone->childbase.first; + if (child){ + while (child){ + free_boneChildren (child); + child=child->next; + } + BLI_freelistN (&bone->childbase); + } + } +} + +void free_bones (bArmature *arm) +{ + Bone *bone; + /* Free children (if any) */ + bone= arm->bonebase.first; + if (bone) { + while (bone){ + free_boneChildren (bone); + bone=bone->next; + } + } + + + BLI_freelistN(&arm->bonebase); +} + +void free_armature(bArmature *arm) +{ + if (arm) { + /* unlink_armature(arm);*/ + free_bones(arm); + } +} + +void make_local_armature(bArmature *arm) +{ + int local=0, lib=0; + Object *ob; + bArmature *newArm; + + if (arm->id.lib==0) + return; + if (arm->id.us==1) { + arm->id.lib= 0; + arm->id.flag= LIB_LOCAL; + new_id(0, (ID*)arm, 0); + return; + } + + if(local && lib==0) { + arm->id.lib= 0; + arm->id.flag= LIB_LOCAL; + new_id(0, (ID *)arm, 0); + } + else if(local && lib) { + newArm= copy_armature(arm); + newArm->id.us= 0; + + ob= G.main->object.first; + while(ob) { + if(ob->data==arm) { + + if(ob->id.lib==0) { + ob->data= newArm; + newArm->id.us++; + arm->id.us--; + } + } + ob= ob->id.next; + } + } +} + +static void copy_bonechildren (Bone* newBone, Bone* oldBone) +{ + Bone *curBone, *newChildBone; + + /* Copy this bone's list*/ + duplicatelist (&newBone->childbase, &oldBone->childbase); + + /* For each child in the list, update it's children*/ + newChildBone=newBone->childbase.first; + for (curBone=oldBone->childbase.first;curBone;curBone=curBone->next){ + newChildBone->parent=newBone; + copy_bonechildren(newChildBone,curBone); + newChildBone=newChildBone->next; + } +} + +bArmature *copy_armature(bArmature *arm) +{ + bArmature *newArm; + Bone *oldBone, *newBone; + + newArm= copy_libblock (arm); + duplicatelist(&newArm->bonebase, &arm->bonebase); + + /* Duplicate the childrens' lists*/ + newBone=newArm->bonebase.first; + for (oldBone=arm->bonebase.first;oldBone;oldBone=oldBone->next){ + newBone->parent=NULL; + copy_bonechildren (newBone, oldBone); + newBone=newBone->next; + }; + + return newArm; +} + +static Bone *get_named_bone_bonechildren (Bone *bone, const char *name) +{ + Bone *curBone, *rbone; + + if (!strcmp (bone->name, name)) + return bone; + + for (curBone=bone->childbase.first; curBone; curBone=curBone->next){ + rbone=get_named_bone_bonechildren (curBone, name); + if (rbone) + return rbone; + } + + return NULL; +} + + +Bone *get_named_bone (bArmature *arm, const char *name) +/* + Walk the list until the bone is found + */ +{ + Bone *bone=NULL, *curBone; + + if (!arm) return NULL; + + for (curBone=arm->bonebase.first; curBone; curBone=curBone->next){ + bone = get_named_bone_bonechildren (curBone, name); + if (bone) + return bone; + } + + return bone; +} + + +#define IS_SEPARATOR(a) (a=='.' || a==' ' || a=='-' || a=='_') + +/* finds the best possible flipped name. For renaming; check for unique names afterwards */ +/* if strip_number: removes number extensions */ +void bone_flip_name (char *name, int strip_number) +{ + int len; + char prefix[128]={""}; /* The part before the facing */ + char suffix[128]={""}; /* The part after the facing */ + char replace[128]={""}; /* The replacement string */ + char number[128]={""}; /* The number extension string */ + char *index=NULL; + + len= strlen(name); + if(len<3) return; // we don't do names like .R or .L + + /* We first check the case with a .### extension, let's find the last period */ + if(isdigit(name[len-1])) { + index= strrchr(name, '.'); // last occurrance + if (index && isdigit(index[1]) ) { // doesnt handle case bone.1abc2 correct..., whatever! + if(strip_number==0) + strcpy(number, index); + *index= 0; + len= strlen(name); + } + } + + strcpy (prefix, name); + + /* first case; separator . - _ with extensions r R l L */ + if( IS_SEPARATOR(name[len-2]) ) { + switch(name[len-1]) { + case 'l': + prefix[len-1]= 0; + strcpy(replace, "r"); + break; + case 'r': + prefix[len-1]= 0; + strcpy(replace, "l"); + break; + case 'L': + prefix[len-1]= 0; + strcpy(replace, "R"); + break; + case 'R': + prefix[len-1]= 0; + strcpy(replace, "L"); + break; + } + } + /* case; beginning with r R l L , with separator after it */ + else if( IS_SEPARATOR(name[1]) ) { + switch(name[0]) { + case 'l': + strcpy(replace, "r"); + strcpy(suffix, name+1); + prefix[0]= 0; + break; + case 'r': + strcpy(replace, "l"); + strcpy(suffix, name+1); + prefix[0]= 0; + break; + case 'L': + strcpy(replace, "R"); + strcpy(suffix, name+1); + prefix[0]= 0; + break; + case 'R': + strcpy(replace, "L"); + strcpy(suffix, name+1); + prefix[0]= 0; + break; + } + } + else if(len > 5) { + /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */ + index = BLI_strcasestr(prefix, "right"); + if (index==prefix || index==prefix+len-5) { + if(index[0]=='r') + strcpy (replace, "left"); + else { + if(index[1]=='I') + strcpy (replace, "LEFT"); + else + strcpy (replace, "Left"); + } + *index= 0; + strcpy (suffix, index+5); + } + else { + index = BLI_strcasestr(prefix, "left"); + if (index==prefix || index==prefix+len-4) { + if(index[0]=='l') + strcpy (replace, "right"); + else { + if(index[1]=='E') + strcpy (replace, "RIGHT"); + else + strcpy (replace, "Right"); + } + *index= 0; + strcpy (suffix, index+4); + } + } + } + + sprintf (name, "%s%s%s%s", prefix, replace, suffix, number); +} + + +/* ************* B-Bone support ******************* */ + +#define MAX_BBONE_SUBDIV 32 + +/* data has MAX_BBONE_SUBDIV+1 interpolated points, will become desired amount with equal distances */ +static void equalize_bezier(float *data, int desired) +{ + float *fp, totdist, ddist, dist, fac1, fac2; + float pdist[MAX_BBONE_SUBDIV+1]; + float temp[MAX_BBONE_SUBDIV+1][4]; + int a, nr; + + pdist[0]= 0.0f; + for(a=0, fp= data; a= pdist[nr]) && nrsegments elements */ +/* this calculation is done within unit bone space */ +Mat4 *b_bone_spline_setup(bPoseChannel *pchan, int rest) +{ + static Mat4 bbone_array[MAX_BBONE_SUBDIV]; + static Mat4 bbone_rest_array[MAX_BBONE_SUBDIV]; + Mat4 *result_array= (rest)? bbone_rest_array: bbone_array; + bPoseChannel *next, *prev; + Bone *bone= pchan->bone; + float h1[3], h2[3], scale[3], length, hlength1, hlength2, roll1=0.0f, roll2; + float mat3[3][3], imat[4][4], posemat[4][4], scalemat[4][4], iscalemat[4][4]; + float data[MAX_BBONE_SUBDIV+1][4], *fp; + int a, doscale= 0; + + length= bone->length; + + if(!rest) { + /* check if we need to take non-uniform bone scaling into account */ + scale[0]= VecLength(pchan->pose_mat[0]); + scale[1]= VecLength(pchan->pose_mat[1]); + scale[2]= VecLength(pchan->pose_mat[2]); + + if(fabs(scale[0] - scale[1]) > 1e-6f || fabs(scale[1] - scale[2]) > 1e-6f) { + Mat4One(scalemat); + scalemat[0][0]= scale[0]; + scalemat[1][1]= scale[1]; + scalemat[2][2]= scale[2]; + Mat4Invert(iscalemat, scalemat); + + length *= scale[1]; + doscale = 1; + } + } + + hlength1= bone->ease1*length*0.390464f; // 0.5*sqrt(2)*kappa, the handle length for near-perfect circles + hlength2= bone->ease2*length*0.390464f; + + /* evaluate next and prev bones */ + if(bone->flag & BONE_CONNECTED) + prev= pchan->parent; + else + prev= NULL; + + next= pchan->child; + + /* find the handle points, since this is inside bone space, the + first point = (0,0,0) + last point = (0, length, 0) */ + + if(rest) { + Mat4Invert(imat, pchan->bone->arm_mat); + } + else if(doscale) { + Mat4CpyMat4(posemat, pchan->pose_mat); + Mat4Ortho(posemat); + Mat4Invert(imat, posemat); + } + else + Mat4Invert(imat, pchan->pose_mat); + + if(prev) { + float difmat[4][4], result[3][3], imat3[3][3]; + + /* transform previous point inside this bone space */ + if(rest) + VECCOPY(h1, prev->bone->arm_head) + else + VECCOPY(h1, prev->pose_head) + Mat4MulVecfl(imat, h1); + + if(prev->bone->segments>1) { + /* if previous bone is B-bone too, use average handle direction */ + h1[1]-= length; + roll1= 0.0f; + } + + Normalize(h1); + VecMulf(h1, -hlength1); + + if(prev->bone->segments==1) { + /* find the previous roll to interpolate */ + if(rest) + Mat4MulMat4(difmat, prev->bone->arm_mat, imat); + else + Mat4MulMat4(difmat, prev->pose_mat, imat); + Mat3CpyMat4(result, difmat); // the desired rotation at beginning of next bone + + vec_roll_to_mat3(h1, 0.0f, mat3); // the result of vec_roll without roll + + Mat3Inv(imat3, mat3); + Mat3MulMat3(mat3, result, imat3); // the matrix transforming vec_roll to desired roll + + roll1= atan2(mat3[2][0], mat3[2][2]); + } + } + else { + h1[0]= 0.0f; h1[1]= hlength1; h1[2]= 0.0f; + roll1= 0.0f; + } + if(next) { + float difmat[4][4], result[3][3], imat3[3][3]; + + /* transform next point inside this bone space */ + if(rest) + VECCOPY(h2, next->bone->arm_tail) + else + VECCOPY(h2, next->pose_tail) + Mat4MulVecfl(imat, h2); + /* if next bone is B-bone too, use average handle direction */ + if(next->bone->segments>1); + else h2[1]-= length; + Normalize(h2); + + /* find the next roll to interpolate as well */ + if(rest) + Mat4MulMat4(difmat, next->bone->arm_mat, imat); + else + Mat4MulMat4(difmat, next->pose_mat, imat); + Mat3CpyMat4(result, difmat); // the desired rotation at beginning of next bone + + vec_roll_to_mat3(h2, 0.0f, mat3); // the result of vec_roll without roll + + Mat3Inv(imat3, mat3); + Mat3MulMat3(mat3, imat3, result); // the matrix transforming vec_roll to desired roll + + roll2= atan2(mat3[2][0], mat3[2][2]); + + /* and only now negate handle */ + VecMulf(h2, -hlength2); + } + else { + h2[0]= 0.0f; h2[1]= -hlength2; h2[2]= 0.0f; + roll2= 0.0; + } + + /* make curve */ + if(bone->segments > MAX_BBONE_SUBDIV) + bone->segments= MAX_BBONE_SUBDIV; + + forward_diff_bezier(0.0, h1[0], h2[0], 0.0, data[0], MAX_BBONE_SUBDIV, 4); + forward_diff_bezier(0.0, h1[1], length + h2[1], length, data[0]+1, MAX_BBONE_SUBDIV, 4); + forward_diff_bezier(0.0, h1[2], h2[2], 0.0, data[0]+2, MAX_BBONE_SUBDIV, 4); + forward_diff_bezier(roll1, roll1 + 0.390464f*(roll2-roll1), roll2 - 0.390464f*(roll2-roll1), roll2, data[0]+3, MAX_BBONE_SUBDIV, 4); + + equalize_bezier(data[0], bone->segments); // note: does stride 4! + + /* make transformation matrices for the segments for drawing */ + for(a=0, fp= data[0]; asegments; a++, fp+=4) { + VecSubf(h1, fp+4, fp); + vec_roll_to_mat3(h1, fp[3], mat3); // fp[3] is roll + + Mat4CpyMat3(result_array[a].mat, mat3); + VECCOPY(result_array[a].mat[3], fp); + + if(doscale) { + /* correct for scaling when this matrix is used in scaled space */ + Mat4MulSerie(result_array[a].mat, iscalemat, result_array[a].mat, + scalemat, NULL, NULL, NULL, NULL, NULL); + } + } + + return result_array; +} + +/* ************ Armature Deform ******************* */ + +static void pchan_b_bone_defmats(bPoseChannel *pchan, int use_quaternion, int rest_def) +{ + Bone *bone= pchan->bone; + Mat4 *b_bone= b_bone_spline_setup(pchan, 0); + Mat4 *b_bone_rest= (rest_def)? NULL: b_bone_spline_setup(pchan, 1); + Mat4 *b_bone_mats; + DualQuat *b_bone_dual_quats= NULL; + float tmat[4][4]; + int a; + + /* allocate b_bone matrices and dual quats */ + b_bone_mats= MEM_mallocN((1+bone->segments)*sizeof(Mat4), "BBone defmats"); + pchan->b_bone_mats= b_bone_mats; + + if(use_quaternion) { + b_bone_dual_quats= MEM_mallocN((bone->segments)*sizeof(DualQuat), "BBone dqs"); + pchan->b_bone_dual_quats= b_bone_dual_quats; + } + + /* first matrix is the inverse arm_mat, to bring points in local bone space + for finding out which segment it belongs to */ + Mat4Invert(b_bone_mats[0].mat, bone->arm_mat); + + /* then we make the b_bone_mats: + - first transform to local bone space + - translate over the curve to the bbone mat space + - transform with b_bone matrix + - transform back into global space */ + Mat4One(tmat); + + for(a=0; asegments; a++) { + if(b_bone_rest) + Mat4Invert(tmat, b_bone_rest[a].mat); + else + tmat[3][1] = -a*(bone->length/(float)bone->segments); + + Mat4MulSerie(b_bone_mats[a+1].mat, pchan->chan_mat, bone->arm_mat, + b_bone[a].mat, tmat, b_bone_mats[0].mat, NULL, NULL, NULL); + + if(use_quaternion) + Mat4ToDQuat(bone->arm_mat, b_bone_mats[a+1].mat, &b_bone_dual_quats[a]); + } +} + +static void b_bone_deform(bPoseChannel *pchan, Bone *bone, float *co, DualQuat *dq, float defmat[][3]) +{ + Mat4 *b_bone= pchan->b_bone_mats; + float (*mat)[4]= b_bone[0].mat; + float segment, y; + int a; + + /* need to transform co back to bonespace, only need y */ + y= mat[0][1]*co[0] + mat[1][1]*co[1] + mat[2][1]*co[2] + mat[3][1]; + + /* now calculate which of the b_bones are deforming this */ + segment= bone->length/((float)bone->segments); + a= (int)(y/segment); + + /* note; by clamping it extends deform at endpoints, goes best with + straight joints in restpos. */ + CLAMP(a, 0, bone->segments-1); + + if(dq) { + DQuatCpyDQuat(dq, &((DualQuat*)pchan->b_bone_dual_quats)[a]); + } + else { + Mat4MulVecfl(b_bone[a+1].mat, co); + + if(defmat) + Mat3CpyMat4(defmat, b_bone[a+1].mat); + } +} + +/* using vec with dist to bone b1 - b2 */ +float distfactor_to_bone (float vec[3], float b1[3], float b2[3], float rad1, float rad2, float rdist) +{ + float dist=0.0f; + float bdelta[3]; + float pdelta[3]; + float hsqr, a, l, rad; + + VecSubf (bdelta, b2, b1); + l = Normalize (bdelta); + + VecSubf (pdelta, vec, b1); + + a = bdelta[0]*pdelta[0] + bdelta[1]*pdelta[1] + bdelta[2]*pdelta[2]; + hsqr = ((pdelta[0]*pdelta[0]) + (pdelta[1]*pdelta[1]) + (pdelta[2]*pdelta[2])); + + if (a < 0.0F){ + /* If we're past the end of the bone, do a spherical field attenuation thing */ + dist= ((b1[0]-vec[0])*(b1[0]-vec[0]) +(b1[1]-vec[1])*(b1[1]-vec[1]) +(b1[2]-vec[2])*(b1[2]-vec[2])) ; + rad= rad1; + } + else if (a > l){ + /* If we're past the end of the bone, do a spherical field attenuation thing */ + dist= ((b2[0]-vec[0])*(b2[0]-vec[0]) +(b2[1]-vec[1])*(b2[1]-vec[1]) +(b2[2]-vec[2])*(b2[2]-vec[2])) ; + rad= rad2; + } + else { + dist= (hsqr - (a*a)); + + if(l!=0.0f) { + rad= a/l; + rad= rad*rad2 + (1.0-rad)*rad1; + } + else rad= rad1; + } + + a= rad*rad; + if(dist < a) + return 1.0f; + else { + l= rad+rdist; + l*= l; + if(rdist==0.0f || dist >= l) + return 0.0f; + else { + a= sqrt(dist)-rad; + return 1.0-( a*a )/( rdist*rdist ); + } + } +} + +static void pchan_deform_mat_add(bPoseChannel *pchan, float weight, float bbonemat[][3], float mat[][3]) +{ + float wmat[3][3]; + + if(pchan->bone->segments>1) + Mat3CpyMat3(wmat, bbonemat); + else + Mat3CpyMat4(wmat, pchan->chan_mat); + + Mat3MulFloat((float*)wmat, weight); + Mat3AddMat3(mat, mat, wmat); +} + +static float dist_bone_deform(bPoseChannel *pchan, float *vec, DualQuat *dq, float mat[][3], float *co) +{ + Bone *bone= pchan->bone; + float fac, contrib=0.0; + float cop[3], bbonemat[3][3]; + DualQuat bbonedq; + + if(bone==NULL) return 0.0f; + + VECCOPY (cop, co); + + fac= distfactor_to_bone(cop, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist); + + if (fac>0.0) { + + fac*=bone->weight; + contrib= fac; + if(contrib>0.0) { + if(vec) { + if(bone->segments>1) + // applies on cop and bbonemat + b_bone_deform(pchan, bone, cop, NULL, (mat)?bbonemat:NULL); + else + Mat4MulVecfl(pchan->chan_mat, cop); + + // Make this a delta from the base position + VecSubf (cop, cop, co); + cop[0]*=fac; cop[1]*=fac; cop[2]*=fac; + VecAddf (vec, vec, cop); + + if(mat) + pchan_deform_mat_add(pchan, fac, bbonemat, mat); + } + else { + if(bone->segments>1) { + b_bone_deform(pchan, bone, cop, &bbonedq, NULL); + DQuatAddWeighted(dq, &bbonedq, fac); + } + else + DQuatAddWeighted(dq, pchan->dual_quat, fac); + } + } + } + + return contrib; +} + +static void pchan_bone_deform(bPoseChannel *pchan, float weight, float *vec, DualQuat *dq, float mat[][3], float *co, float *contrib) +{ + float cop[3], bbonemat[3][3]; + DualQuat bbonedq; + + if (!weight) + return; + + VECCOPY(cop, co); + + if(vec) { + if(pchan->bone->segments>1) + // applies on cop and bbonemat + b_bone_deform(pchan, pchan->bone, cop, NULL, (mat)?bbonemat:NULL); + else + Mat4MulVecfl(pchan->chan_mat, cop); + + vec[0]+=(cop[0]-co[0])*weight; + vec[1]+=(cop[1]-co[1])*weight; + vec[2]+=(cop[2]-co[2])*weight; + + if(mat) + pchan_deform_mat_add(pchan, weight, bbonemat, mat); + } + else { + if(pchan->bone->segments>1) { + b_bone_deform(pchan, pchan->bone, cop, &bbonedq, NULL); + DQuatAddWeighted(dq, &bbonedq, weight); + } + else + DQuatAddWeighted(dq, pchan->dual_quat, weight); + } + + (*contrib)+=weight; +} + +void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, + float (*vertexCos)[3], float (*defMats)[3][3], + int numVerts, int deformflag, const char *defgrp_name) +{ + bPoseChannel *pchan, **defnrToPC = NULL; + MDeformVert *dverts = NULL; + bDeformGroup *dg; + DualQuat *dualquats= NULL; + float obinv[4][4], premat[4][4], postmat[4][4]; + int use_envelope = deformflag & ARM_DEF_ENVELOPE; + int use_quaternion = deformflag & ARM_DEF_QUATERNION; + int bbone_rest_def = deformflag & ARM_DEF_B_BONE_REST; + int numGroups = 0; /* safety for vertexgroup index overflow */ + int i, target_totvert = 0; /* safety for vertexgroup overflow */ + int use_dverts = 0; + int armature_def_nr = -1; + int totchan; + + if(armOb == G.obedit) return; + + Mat4Invert(obinv, target->obmat); + Mat4CpyMat4(premat, target->obmat); + Mat4MulMat4(postmat, armOb->obmat, obinv); + Mat4Invert(premat, postmat); + + /* bone defmats are already in the channels, chan_mat */ + + /* initialize B_bone matrices and dual quaternions */ + if(use_quaternion) { + totchan= BLI_countlist(&armOb->pose->chanbase); + dualquats= MEM_callocN(sizeof(DualQuat)*totchan, "dualquats"); + } + + totchan= 0; + for(pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next) { + if(!(pchan->bone->flag & BONE_NO_DEFORM)) { + if(pchan->bone->segments > 1) + pchan_b_bone_defmats(pchan, use_quaternion, bbone_rest_def); + + if(use_quaternion) { + pchan->dual_quat= &dualquats[totchan++]; + Mat4ToDQuat(pchan->bone->arm_mat, pchan->chan_mat, pchan->dual_quat); + } + } + } + + /* get the def_nr for the overall armature vertex group if present */ + for(i = 0, dg = target->defbase.first; dg; i++, dg = dg->next) + if(defgrp_name && strcmp(defgrp_name, dg->name) == 0) + armature_def_nr = i; + + /* get a vertex-deform-index to posechannel array */ + if(deformflag & ARM_DEF_VGROUP) { + if(ELEM(target->type, OB_MESH, OB_LATTICE)) { + numGroups = BLI_countlist(&target->defbase); + + if(target->type==OB_MESH) { + Mesh *me= target->data; + dverts = me->dvert; + target_totvert = me->totvert; + } + else { + Lattice *lt= target->data; + dverts = lt->dvert; + if(dverts) + target_totvert = lt->pntsu*lt->pntsv*lt->pntsw; + } + /* if we have a DerivedMesh, only use dverts if it has them */ + if(dm) + if(dm->getVertData(dm, 0, CD_MDEFORMVERT)) + use_dverts = 1; + else use_dverts = 0; + else if(dverts) use_dverts = 1; + + if(use_dverts) { + defnrToPC = MEM_callocN(sizeof(*defnrToPC) * numGroups, + "defnrToBone"); + for(i = 0, dg = target->defbase.first; dg; + i++, dg = dg->next) { + defnrToPC[i] = get_pose_channel(armOb->pose, dg->name); + /* exclude non-deforming bones */ + if(defnrToPC[i]) { + if(defnrToPC[i]->bone->flag & BONE_NO_DEFORM) + defnrToPC[i]= NULL; + } + } + } + } + } + + for(i = 0; i < numVerts; i++) { + MDeformVert *dvert; + DualQuat sumdq, *dq = NULL; + float *co = vertexCos[i], dco[3]; + float sumvec[3], summat[3][3]; + float *vec = NULL, (*smat)[3] = NULL; + float contrib = 0.0f; + float armature_weight = 1.0f; /* default to 1 if no overall def group */ + int j; + + if(use_quaternion) { + memset(&sumdq, 0, sizeof(DualQuat)); + dq= &sumdq; + } + else { + sumvec[0] = sumvec[1] = sumvec[2] = 0.0f; + vec= sumvec; + + if(defMats) { + Mat3Clr((float*)summat); + smat = summat; + } + } + + if(use_dverts || armature_def_nr >= 0) { + if(dm) dvert = dm->getVertData(dm, i, CD_MDEFORMVERT); + else if(dverts && i < target_totvert) dvert = dverts + i; + else dvert = NULL; + } else + dvert = NULL; + + if(armature_def_nr >= 0 && dvert) { + armature_weight = 0.0f; /* a def group was given, so default to 0 */ + for(j = 0; j < dvert->totweight; j++) { + if(dvert->dw[j].def_nr == armature_def_nr) { + armature_weight = dvert->dw[j].weight; + break; + } + } + } + + /* check if there's any point in calculating for this vert */ + if(armature_weight == 0.0f) continue; + + /* Apply the object's matrix */ + Mat4MulVecfl(premat, co); + + if(use_dverts && dvert && dvert->totweight) { // use weight groups ? + int deformed = 0; + + for(j = 0; j < dvert->totweight; j++){ + int index = dvert->dw[j].def_nr; + pchan = index < numGroups?defnrToPC[index]:NULL; + if(pchan) { + float weight = dvert->dw[j].weight; + Bone *bone = pchan->bone; + + deformed = 1; + + if(bone && bone->flag & BONE_MULT_VG_ENV) { + weight *= distfactor_to_bone(co, bone->arm_head, + bone->arm_tail, + bone->rad_head, + bone->rad_tail, + bone->dist); + } + pchan_bone_deform(pchan, weight, vec, dq, smat, co, &contrib); + } + } + /* if there are vertexgroups but not groups with bones + * (like for softbody groups) + */ + if(deformed == 0 && use_envelope) { + for(pchan = armOb->pose->chanbase.first; pchan; + pchan = pchan->next) { + if(!(pchan->bone->flag & BONE_NO_DEFORM)) + contrib += dist_bone_deform(pchan, vec, dq, smat, co); + } + } + } + else if(use_envelope) { + for(pchan = armOb->pose->chanbase.first; pchan; + pchan = pchan->next) { + if(!(pchan->bone->flag & BONE_NO_DEFORM)) + contrib += dist_bone_deform(pchan, vec, dq, smat, co); + } + } + + /* actually should be EPSILON? weight values and contrib can be like 10e-39 small */ + if(contrib > 0.0001f) { + if(use_quaternion) { + DQuatNormalize(dq, contrib, armature_weight); + + if(armature_weight != 1.0f) { + VECCOPY(dco, co); + DQuatMulVecfl(dq, dco, (defMats)? summat: NULL); + VecSubf(dco, dco, co); + VecMulf(dco, armature_weight); + VecAddf(co, co, dco); + } + else + DQuatMulVecfl(dq, co, (defMats)? summat: NULL); + + smat = summat; + } + else { + VecMulf(vec, armature_weight/contrib); + VecAddf(co, vec, co); + } + + if(defMats) { + float pre[3][3], post[3][3], tmpmat[3][3]; + + Mat3CpyMat4(pre, premat); + Mat3CpyMat4(post, postmat); + Mat3CpyMat3(tmpmat, defMats[i]); + + if(!use_quaternion) /* quaternion already is scale corrected */ + Mat3MulFloat((float*)smat, armature_weight/contrib); + + Mat3MulSerie(defMats[i], tmpmat, pre, smat, post, + NULL, NULL, NULL, NULL); + } + } + + /* always, check above code */ + Mat4MulVecfl(postmat, co); + } + + if(dualquats) MEM_freeN(dualquats); + if(defnrToPC) MEM_freeN(defnrToPC); + + /* free B_bone matrices */ + for(pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next) { + if(pchan->b_bone_mats) { + MEM_freeN(pchan->b_bone_mats); + pchan->b_bone_mats = NULL; + } + if(pchan->b_bone_dual_quats) { + MEM_freeN(pchan->b_bone_dual_quats); + pchan->b_bone_dual_quats = NULL; + } + + pchan->dual_quat = NULL; + } +} + +/* ************ END Armature Deform ******************* */ + +void get_objectspace_bone_matrix (struct Bone* bone, float M_accumulatedMatrix[][4], int root, int posed) +{ + Mat4CpyMat4(M_accumulatedMatrix, bone->arm_mat); +} + +/* **************** Space to Space API ****************** */ + +/* Convert World-Space Matrix to Pose-Space Matrix */ +void armature_mat_world_to_pose(Object *ob, float inmat[][4], float outmat[][4]) +{ + float obmat[4][4]; + + /* prevent crashes */ + if (ob==NULL) return; + + /* get inverse of (armature) object's matrix */ + Mat4Invert(obmat, ob->obmat); + + /* multiply given matrix by object's-inverse to find pose-space matrix */ + Mat4MulMat4(outmat, obmat, inmat); +} + +/* Convert Wolrd-Space Location to Pose-Space Location + * NOTE: this cannot be used to convert to pose-space location of the supplied + * pose-channel into its local space (i.e. 'visual'-keyframing) + */ +void armature_loc_world_to_pose(Object *ob, float *inloc, float *outloc) +{ + float xLocMat[4][4]; + float nLocMat[4][4]; + + /* build matrix for location */ + Mat4One(xLocMat); + VECCOPY(xLocMat[3], inloc); + + /* get bone-space cursor matrix and extract location */ + armature_mat_world_to_pose(ob, xLocMat, nLocMat); + VECCOPY(outloc, nLocMat[3]); +} + +/* Convert Pose-Space Matrix to Bone-Space Matrix + * NOTE: this cannot be used to convert to pose-space transforms of the supplied + * pose-channel into its local space (i.e. 'visual'-keyframing) + */ +void armature_mat_pose_to_bone(bPoseChannel *pchan, float inmat[][4], float outmat[][4]) +{ + float pc_trans[4][4], inv_trans[4][4]; + float pc_posemat[4][4], inv_posemat[4][4]; + + /* paranoia: prevent crashes with no pose-channel supplied */ + if (pchan==NULL) return; + + /* get the inverse matrix of the pchan's transforms */ + LocQuatSizeToMat4(pc_trans, pchan->loc, pchan->quat, pchan->size); + Mat4Invert(inv_trans, pc_trans); + + /* Remove the pchan's transforms from it's pose_mat. + * This should leave behind the effects of restpose + + * parenting + constraints + */ + Mat4MulMat4(pc_posemat, inv_trans, pchan->pose_mat); + + /* get the inverse of the leftovers so that we can remove + * that component from the supplied matrix + */ + Mat4Invert(inv_posemat, pc_posemat); + + /* get the new matrix */ + Mat4MulMat4(outmat, inmat, inv_posemat); +} + +/* Convert Pose-Space Location to Bone-Space Location + * NOTE: this cannot be used to convert to pose-space location of the supplied + * pose-channel into its local space (i.e. 'visual'-keyframing) + */ +void armature_loc_pose_to_bone(bPoseChannel *pchan, float *inloc, float *outloc) +{ + float xLocMat[4][4]; + float nLocMat[4][4]; + + /* build matrix for location */ + Mat4One(xLocMat); + VECCOPY(xLocMat[3], inloc); + + /* get bone-space cursor matrix and extract location */ + armature_mat_pose_to_bone(pchan, xLocMat, nLocMat); + VECCOPY(outloc, nLocMat[3]); +} + +/* Remove rest-position effects from pose-transform for obtaining + * 'visual' transformation of pose-channel. + * (used by the Visual-Keyframing stuff) + */ +void armature_mat_pose_to_delta(float delta_mat[][4], float pose_mat[][4], float arm_mat[][4]) +{ + float imat[4][4]; + + Mat4Invert(imat, arm_mat); + Mat4MulMat4(delta_mat, pose_mat, imat); +} + + +/* **************** The new & simple (but OK!) armature evaluation ********* */ + +/* ****************** And how it works! **************************************** + + This is the bone transformation trick; they're hierarchical so each bone(b) + is in the coord system of bone(b-1): + + arm_mat(b)= arm_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b) + + -> yoffs is just the y axis translation in parent's coord system + -> d_root is the translation of the bone root, also in parent's coord system + + pose_mat(b)= pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b) * chan_mat(b) + + we then - in init deform - store the deform in chan_mat, such that: + + pose_mat(b)= arm_mat(b) * chan_mat(b) + + *************************************************************************** */ +/* Computes vector and roll based on a rotation. "mat" must + contain only a rotation, and no scaling. */ +void mat3_to_vec_roll(float mat[][3], float *vec, float *roll) +{ + if (vec) + VecCopyf(vec, mat[1]); + + if (roll) { + float vecmat[3][3], vecmatinv[3][3], rollmat[3][3]; + + vec_roll_to_mat3(mat[1], 0.0f, vecmat); + Mat3Inv(vecmatinv, vecmat); + Mat3MulMat3(rollmat, vecmatinv, mat); + + *roll= atan2(rollmat[2][0], rollmat[2][2]); + } +} + +/* Calculates the rest matrix of a bone based + On its vector and a roll around that vector */ +void vec_roll_to_mat3(float *vec, float roll, float mat[][3]) +{ + float nor[3], axis[3], target[3]={0,1,0}; + float theta; + float rMatrix[3][3], bMatrix[3][3]; + + VECCOPY (nor, vec); + Normalize (nor); + + /* Find Axis & Amount for bone matrix*/ + Crossf (axis,target,nor); + + if (Inpf(axis,axis) > 0.0000000000001) { + /* if nor is *not* a multiple of target ... */ + Normalize (axis); + + theta= NormalizedVecAngle2(target, nor); + + /* Make Bone matrix*/ + VecRotToMat3(axis, theta, bMatrix); + } + else { + /* if nor is a multiple of target ... */ + float updown; + + /* point same direction, or opposite? */ + updown = ( Inpf (target,nor) > 0 ) ? 1.0 : -1.0; + + /* I think this should work ... */ + bMatrix[0][0]=updown; bMatrix[0][1]=0.0; bMatrix[0][2]=0.0; + bMatrix[1][0]=0.0; bMatrix[1][1]=updown; bMatrix[1][2]=0.0; + bMatrix[2][0]=0.0; bMatrix[2][1]=0.0; bMatrix[2][2]=1.0; + } + + /* Make Roll matrix*/ + VecRotToMat3(nor, roll, rMatrix); + + /* Combine and output result*/ + Mat3MulMat3 (mat, rMatrix, bMatrix); +} + + +/* recursive part, calculates restposition of entire tree of children */ +/* used by exiting editmode too */ +void where_is_armature_bone(Bone *bone, Bone *prevbone) +{ + float vec[3]; + + /* Bone Space */ + VecSubf (vec, bone->tail, bone->head); + vec_roll_to_mat3(vec, bone->roll, bone->bone_mat); + + bone->length= VecLenf(bone->head, bone->tail); + + /* this is called on old file reading too... */ + if(bone->xwidth==0.0) { + bone->xwidth= 0.1f; + bone->zwidth= 0.1f; + bone->segments= 1; + } + + if(prevbone) { + float offs_bone[4][4]; // yoffs(b-1) + root(b) + bonemat(b) + + /* bone transform itself */ + Mat4CpyMat3(offs_bone, bone->bone_mat); + + /* The bone's root offset (is in the parent's coordinate system) */ + VECCOPY(offs_bone[3], bone->head); + + /* Get the length translation of parent (length along y axis) */ + offs_bone[3][1]+= prevbone->length; + + /* Compose the matrix for this bone */ + Mat4MulMat4(bone->arm_mat, offs_bone, prevbone->arm_mat); + } + else { + Mat4CpyMat3(bone->arm_mat, bone->bone_mat); + VECCOPY(bone->arm_mat[3], bone->head); + } + + /* head */ + VECCOPY(bone->arm_head, bone->arm_mat[3]); + /* tail is in current local coord system */ + VECCOPY(vec, bone->arm_mat[1]); + VecMulf(vec, bone->length); + VecAddf(bone->arm_tail, bone->arm_head, vec); + + /* and the kiddies */ + prevbone= bone; + for(bone= bone->childbase.first; bone; bone= bone->next) { + where_is_armature_bone(bone, prevbone); + } +} + +/* updates vectors and matrices on rest-position level, only needed + after editing armature itself, now only on reading file */ +void where_is_armature (bArmature *arm) +{ + Bone *bone; + + /* hierarchical from root to children */ + for(bone= arm->bonebase.first; bone; bone= bone->next) { + where_is_armature_bone(bone, NULL); + } +} + +/* if bone layer is protected, copy the data from from->pose */ +static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected) +{ + bPose *pose= ob->pose, *frompose= from->pose; + bPoseChannel *pchan, *pchanp, pchanw; + bConstraint *con; + + if(frompose==NULL) return; + + /* exception, armature local layer should be proxied too */ + if(pose->proxy_layer) + ((bArmature *)ob->data)->layer= pose->proxy_layer; + + /* clear all transformation values from library */ + rest_pose(frompose); + + pchan= pose->chanbase.first; + for(; pchan; pchan= pchan->next) { + if(pchan->bone->layer & layer_protected) { + pchanp= get_pose_channel(frompose, pchan->name); + + /* copy posechannel to temp, but restore important pointers */ + pchanw= *pchanp; + pchanw.prev= pchan->prev; + pchanw.next= pchan->next; + pchanw.parent= pchan->parent; + pchanw.child= pchan->child; + pchanw.path= NULL; + + /* constraints, set target ob pointer to own object */ + copy_constraints(&pchanw.constraints, &pchanp->constraints); + + for (con= pchanw.constraints.first; con; con= con->next) { + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + ListBase targets = {NULL, NULL}; + bConstraintTarget *ct; + + if (cti && cti->get_constraint_targets) { + cti->get_constraint_targets(con, &targets); + + for (ct= targets.first; ct; ct= ct->next) { + if (ct->tar == from) + ct->tar = ob; + } + + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(con, &targets, 0); + } + } + + /* free stuff from current channel */ + if (pchan->path) MEM_freeN(pchan->path); + free_constraints(&pchan->constraints); + + /* the final copy */ + *pchan= pchanw; + } + } +} + +static int rebuild_pose_bone(bPose *pose, Bone *bone, bPoseChannel *parchan, int counter) +{ + bPoseChannel *pchan = verify_pose_channel (pose, bone->name); // verify checks and/or adds + + pchan->bone= bone; + pchan->parent= parchan; + + counter++; + + for(bone= bone->childbase.first; bone; bone= bone->next) { + counter= rebuild_pose_bone(pose, bone, pchan, counter); + /* for quick detecting of next bone in chain, only b-bone uses it now */ + if(bone->flag & BONE_CONNECTED) + pchan->child= get_pose_channel(pose, bone->name); + } + + return counter; +} + +/* only after leave editmode, duplicating, validating older files, library syncing */ +/* NOTE: pose->flag is set for it */ +void armature_rebuild_pose(Object *ob, bArmature *arm) +{ + Bone *bone; + bPose *pose; + bPoseChannel *pchan, *next; + int counter=0; + + /* only done here */ + if(ob->pose==NULL) ob->pose= MEM_callocN(sizeof(bPose), "new pose"); + pose= ob->pose; + + /* clear */ + for(pchan= pose->chanbase.first; pchan; pchan= pchan->next) { + pchan->bone= NULL; + pchan->child= NULL; + } + + /* first step, check if all channels are there */ + for(bone= arm->bonebase.first; bone; bone= bone->next) { + counter= rebuild_pose_bone(pose, bone, NULL, counter); + } + + /* and a check for garbage */ + for(pchan= pose->chanbase.first; pchan; pchan= next) { + next= pchan->next; + if(pchan->bone==NULL) { + if(pchan->path) + MEM_freeN(pchan->path); + free_constraints(&pchan->constraints); + BLI_freelinkN(&pose->chanbase, pchan); + } + } + // printf("rebuild pose %s, %d bones\n", ob->id.name, counter); + + /* synchronize protected layers with proxy */ + if(ob->proxy) + pose_proxy_synchronize(ob, ob->proxy, arm->layer_protected); + + update_pose_constraint_flags(ob->pose); // for IK detection for example + + /* the sorting */ + if(counter>1) + DAG_pose_sort(ob); + + ob->pose->flag &= ~POSE_RECALC; +} + + +/* ********************** THE IK SOLVER ******************* */ + + + +/* allocates PoseTree, and links that to root bone/channel */ +/* Note: detecting the IK chain is duplicate code... in drawarmature.c and in transform_conversions.c */ +static void initialize_posetree(struct Object *ob, bPoseChannel *pchan_tip) +{ + bPoseChannel *curchan, *pchan_root=NULL, *chanlist[256], **oldchan; + PoseTree *tree; + PoseTarget *target; + bConstraint *con; + bKinematicConstraint *data; + int a, segcount= 0, size, newsize, *oldparent, parent; + + /* find IK constraint, and validate it */ + for(con= pchan_tip->constraints.first; con; con= con->next) { + if(con->type==CONSTRAINT_TYPE_KINEMATIC) break; + } + if(con==NULL) return; + + data=(bKinematicConstraint*)con->data; + + /* two types of targets */ + if(data->flag & CONSTRAINT_IK_AUTO); + else { + if(con->flag & CONSTRAINT_DISABLE) return; /* checked in editconstraint.c */ + if(con->enforce == 0.0f) return; + if(data->tar==NULL) return; + if(data->tar->type==OB_ARMATURE && data->subtarget[0]==0) return; + } + + /* exclude tip from chain? */ + if(!(data->flag & CONSTRAINT_IK_TIP)) + pchan_tip= pchan_tip->parent; + + /* Find the chain's root & count the segments needed */ + for (curchan = pchan_tip; curchan; curchan=curchan->parent){ + pchan_root = curchan; + + curchan->flag |= POSE_CHAIN; // don't forget to clear this + chanlist[segcount]=curchan; + segcount++; + + if(segcount==data->rootbone || segcount>255) break; // 255 is weak + } + if (!segcount) return; + + /* setup the chain data */ + + /* we make tree-IK, unless all existing targets are in this chain */ + for(tree= pchan_root->iktree.first; tree; tree= tree->next) { + for(target= tree->targets.first; target; target= target->next) { + curchan= tree->pchan[target->tip]; + if(curchan->flag & POSE_CHAIN) + curchan->flag &= ~POSE_CHAIN; + else + break; + } + if(target) break; + } + + /* create a target */ + target= MEM_callocN(sizeof(PoseTarget), "posetarget"); + target->con= con; + pchan_tip->flag &= ~POSE_CHAIN; + + if(tree==NULL) { + /* make new tree */ + tree= MEM_callocN(sizeof(PoseTree), "posetree"); + + tree->iterations= data->iterations; + tree->totchannel= segcount; + tree->stretch = (data->flag & CONSTRAINT_IK_STRETCH); + + tree->pchan= MEM_callocN(segcount*sizeof(void*), "ik tree pchan"); + tree->parent= MEM_callocN(segcount*sizeof(int), "ik tree parent"); + for(a=0; apchan[a]= chanlist[segcount-a-1]; + tree->parent[a]= a-1; + } + target->tip= segcount-1; + + /* AND! link the tree to the root */ + BLI_addtail(&pchan_root->iktree, tree); + } + else { + tree->iterations= MAX2(data->iterations, tree->iterations); + tree->stretch= tree->stretch && !(data->flag & CONSTRAINT_IK_STRETCH); + + /* skip common pose channels and add remaining*/ + size= MIN2(segcount, tree->totchannel); + for(a=0; apchan[a]==chanlist[segcount-a-1]; a++); + parent= a-1; + + segcount= segcount-a; + target->tip= tree->totchannel + segcount - 1; + + if (segcount > 0) { + /* resize array */ + newsize= tree->totchannel + segcount; + oldchan= tree->pchan; + oldparent= tree->parent; + + tree->pchan= MEM_callocN(newsize*sizeof(void*), "ik tree pchan"); + tree->parent= MEM_callocN(newsize*sizeof(int), "ik tree parent"); + memcpy(tree->pchan, oldchan, sizeof(void*)*tree->totchannel); + memcpy(tree->parent, oldparent, sizeof(int)*tree->totchannel); + MEM_freeN(oldchan); + MEM_freeN(oldparent); + + /* add new pose channels at the end, in reverse order */ + for(a=0; apchan[tree->totchannel+a]= chanlist[segcount-a-1]; + tree->parent[tree->totchannel+a]= tree->totchannel+a-1; + } + tree->parent[tree->totchannel]= parent; + + tree->totchannel= newsize; + } + + /* move tree to end of list, for correct evaluation order */ + BLI_remlink(&pchan_root->iktree, tree); + BLI_addtail(&pchan_root->iktree, tree); + } + + /* add target to the tree */ + BLI_addtail(&tree->targets, target); +} + +/* called from within the core where_is_pose loop, all animsystems and constraints +were executed & assigned. Now as last we do an IK pass */ +static void execute_posetree(Object *ob, PoseTree *tree) +{ + float R_parmat[3][3]; + float iR_parmat[3][3]; + float R_bonemat[3][3]; + float goalrot[3][3], goalpos[3]; + float rootmat[4][4], imat[4][4]; + float goal[4][4], goalinv[4][4]; + float irest_basis[3][3], full_basis[3][3]; + float end_pose[4][4], world_pose[4][4]; + float length, basis[3][3], rest_basis[3][3], start[3], *ikstretch=NULL; + int a, flag, hasstretch=0; + bPoseChannel *pchan; + IK_Segment *seg, *parent, **iktree, *iktarget; + IK_Solver *solver; + PoseTarget *target; + bKinematicConstraint *data, *poleangledata=NULL; + Bone *bone; + + if (tree->totchannel == 0) + return; + + iktree= MEM_mallocN(sizeof(void*)*tree->totchannel, "ik tree"); + + for(a=0; atotchannel; a++) { + pchan= tree->pchan[a]; + bone= pchan->bone; + + /* set DoF flag */ + flag= 0; + if((pchan->ikflag & BONE_IK_NO_XDOF) == 0) + flag |= IK_XDOF; + if((pchan->ikflag & BONE_IK_NO_YDOF) == 0) + flag |= IK_YDOF; + if((pchan->ikflag & BONE_IK_NO_ZDOF) == 0) + flag |= IK_ZDOF; + + if(tree->stretch && (pchan->ikstretch > 0.0)) { + flag |= IK_TRANS_YDOF; + hasstretch = 1; + } + + seg= iktree[a]= IK_CreateSegment(flag); + + /* find parent */ + if(a == 0) + parent= NULL; + else + parent= iktree[tree->parent[a]]; + + IK_SetParent(seg, parent); + + /* get the matrix that transforms from prevbone into this bone */ + Mat3CpyMat4(R_bonemat, pchan->pose_mat); + + /* gather transformations for this IK segment */ + + if (pchan->parent) + Mat3CpyMat4(R_parmat, pchan->parent->pose_mat); + else + Mat3One(R_parmat); + + /* bone offset */ + if (pchan->parent && (a > 0)) + VecSubf(start, pchan->pose_head, pchan->parent->pose_tail); + else + /* only root bone (a = 0) has no parent */ + start[0]= start[1]= start[2]= 0.0f; + + /* change length based on bone size */ + length= bone->length*VecLength(R_bonemat[1]); + + /* compute rest basis and its inverse */ + Mat3CpyMat3(rest_basis, bone->bone_mat); + Mat3CpyMat3(irest_basis, bone->bone_mat); + Mat3Transp(irest_basis); + + /* compute basis with rest_basis removed */ + Mat3Inv(iR_parmat, R_parmat); + Mat3MulMat3(full_basis, iR_parmat, R_bonemat); + Mat3MulMat3(basis, irest_basis, full_basis); + + /* basis must be pure rotation */ + Mat3Ortho(basis); + + /* transform offset into local bone space */ + Mat3Ortho(iR_parmat); + Mat3MulVecfl(iR_parmat, start); + + IK_SetTransform(seg, start, rest_basis, basis, length); + + if (pchan->ikflag & BONE_IK_XLIMIT) + IK_SetLimit(seg, IK_X, pchan->limitmin[0], pchan->limitmax[0]); + if (pchan->ikflag & BONE_IK_YLIMIT) + IK_SetLimit(seg, IK_Y, pchan->limitmin[1], pchan->limitmax[1]); + if (pchan->ikflag & BONE_IK_ZLIMIT) + IK_SetLimit(seg, IK_Z, pchan->limitmin[2], pchan->limitmax[2]); + + IK_SetStiffness(seg, IK_X, pchan->stiffness[0]); + IK_SetStiffness(seg, IK_Y, pchan->stiffness[1]); + IK_SetStiffness(seg, IK_Z, pchan->stiffness[2]); + + if(tree->stretch && (pchan->ikstretch > 0.0)) { + float ikstretch = pchan->ikstretch*pchan->ikstretch; + IK_SetStiffness(seg, IK_TRANS_Y, MIN2(1.0-ikstretch, 0.999)); + IK_SetLimit(seg, IK_TRANS_Y, 0.001, 1e10); + } + } + + solver= IK_CreateSolver(iktree[0]); + + /* set solver goals */ + + /* first set the goal inverse transform, assuming the root of tree was done ok! */ + pchan= tree->pchan[0]; + if (pchan->parent) + /* transform goal by parent mat, so this rotation is not part of the + segment's basis. otherwise rotation limits do not work on the + local transform of the segment itself. */ + Mat4CpyMat4(rootmat, pchan->parent->pose_mat); + else + Mat4One(rootmat); + VECCOPY(rootmat[3], pchan->pose_head); + + Mat4MulMat4 (imat, rootmat, ob->obmat); + Mat4Invert (goalinv, imat); + + for (target=tree->targets.first; target; target=target->next) { + float polepos[3]; + int poleconstrain= 0; + + data= (bKinematicConstraint*)target->con->data; + + /* 1.0=ctime, we pass on object for auto-ik (owner-type here is object, even though + * strictly speaking, it is a posechannel) + */ + get_constraint_target_matrix(target->con, 0, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0); + + /* and set and transform goal */ + Mat4MulMat4(goal, rootmat, goalinv); + + VECCOPY(goalpos, goal[3]); + Mat3CpyMat4(goalrot, goal); + + /* same for pole vector target */ + if(data->poletar) { + get_constraint_target_matrix(target->con, 1, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0); + + if(data->flag & CONSTRAINT_IK_SETANGLE) { + /* don't solve IK when we are setting the pole angle */ + break; + } + else { + Mat4MulMat4(goal, rootmat, goalinv); + VECCOPY(polepos, goal[3]); + poleconstrain= 1; + + if(data->flag & CONSTRAINT_IK_GETANGLE) { + poleangledata= data; + data->flag &= ~CONSTRAINT_IK_GETANGLE; + } + } + } + + /* do we need blending? */ + if (target->con->enforce!=1.0) { + float q1[4], q2[4], q[4]; + float fac= target->con->enforce; + float mfac= 1.0-fac; + + pchan= tree->pchan[target->tip]; + + /* end effector in world space */ + Mat4CpyMat4(end_pose, pchan->pose_mat); + VECCOPY(end_pose[3], pchan->pose_tail); + Mat4MulSerie(world_pose, goalinv, ob->obmat, end_pose, 0, 0, 0, 0, 0); + + /* blend position */ + goalpos[0]= fac*goalpos[0] + mfac*world_pose[3][0]; + goalpos[1]= fac*goalpos[1] + mfac*world_pose[3][1]; + goalpos[2]= fac*goalpos[2] + mfac*world_pose[3][2]; + + /* blend rotation */ + Mat3ToQuat(goalrot, q1); + Mat4ToQuat(world_pose, q2); + QuatInterpol(q, q1, q2, mfac); + QuatToMat3(q, goalrot); + } + + iktarget= iktree[target->tip]; + + if(data->weight != 0.0) { + if(poleconstrain) + IK_SolverSetPoleVectorConstraint(solver, iktarget, goalpos, + polepos, data->poleangle*M_PI/180, (poleangledata == data)); + IK_SolverAddGoal(solver, iktarget, goalpos, data->weight); + } + if((data->flag & CONSTRAINT_IK_ROT) && (data->orientweight != 0.0)) + if((data->flag & CONSTRAINT_IK_AUTO)==0) + IK_SolverAddGoalOrientation(solver, iktarget, goalrot, + data->orientweight); + } + + /* solve */ + IK_Solve(solver, 0.0f, tree->iterations); + + if(poleangledata) + poleangledata->poleangle= IK_SolverGetPoleAngle(solver)*180/M_PI; + + IK_FreeSolver(solver); + + /* gather basis changes */ + tree->basis_change= MEM_mallocN(sizeof(float[3][3])*tree->totchannel, "ik basis change"); + if(hasstretch) + ikstretch= MEM_mallocN(sizeof(float)*tree->totchannel, "ik stretch"); + + for(a=0; atotchannel; a++) { + IK_GetBasisChange(iktree[a], tree->basis_change[a]); + + if(hasstretch) { + /* have to compensate for scaling received from parent */ + float parentstretch, stretch; + + pchan= tree->pchan[a]; + parentstretch= (tree->parent[a] >= 0)? ikstretch[tree->parent[a]]: 1.0; + + if(tree->stretch && (pchan->ikstretch > 0.0)) { + float trans[3], length; + + IK_GetTranslationChange(iktree[a], trans); + length= pchan->bone->length*VecLength(pchan->pose_mat[1]); + + ikstretch[a]= (length == 0.0)? 1.0: (trans[1]+length)/length; + } + else + ikstretch[a] = 1.0; + + stretch= (parentstretch == 0.0)? 1.0: ikstretch[a]/parentstretch; + + VecMulf(tree->basis_change[a][0], stretch); + VecMulf(tree->basis_change[a][1], stretch); + VecMulf(tree->basis_change[a][2], stretch); + + } + + IK_FreeSegment(iktree[a]); + } + + MEM_freeN(iktree); + if(ikstretch) MEM_freeN(ikstretch); +} + +void free_posetree(PoseTree *tree) +{ + BLI_freelistN(&tree->targets); + if(tree->pchan) MEM_freeN(tree->pchan); + if(tree->parent) MEM_freeN(tree->parent); + if(tree->basis_change) MEM_freeN(tree->basis_change); + MEM_freeN(tree); +} + +/* ********************** THE POSE SOLVER ******************* */ + + +/* loc/rot/size to mat4 */ +/* used in constraint.c too */ +void chan_calc_mat(bPoseChannel *chan) +{ + float smat[3][3]; + float rmat[3][3]; + float tmat[3][3]; + + SizeToMat3(chan->size, smat); + + NormalQuat(chan->quat); + + QuatToMat3(chan->quat, rmat); + + Mat3MulMat3(tmat, rmat, smat); + + Mat4CpyMat3(chan->chan_mat, tmat); + + /* prevent action channels breaking chains */ + /* need to check for bone here, CONSTRAINT_TYPE_ACTION uses this call */ + if (chan->bone==NULL || !(chan->bone->flag & BONE_CONNECTED)) { + VECCOPY(chan->chan_mat[3], chan->loc); + } + +} + +/* transform from bone(b) to bone(b+1), store in chan_mat */ +static void make_dmats(bPoseChannel *pchan) +{ + if (pchan->parent) { + float iR_parmat[4][4]; + Mat4Invert(iR_parmat, pchan->parent->pose_mat); + Mat4MulMat4(pchan->chan_mat, pchan->pose_mat, iR_parmat); // delta mat + } + else Mat4CpyMat4(pchan->chan_mat, pchan->pose_mat); +} + +/* applies IK matrix to pchan, IK is done separated */ +/* formula: pose_mat(b) = pose_mat(b-1) * diffmat(b-1, b) * ik_mat(b) */ +/* to make this work, the diffmats have to be precalculated! Stored in chan_mat */ +static void where_is_ik_bone(bPoseChannel *pchan, float ik_mat[][3]) // nr = to detect if this is first bone +{ + float vec[3], ikmat[4][4]; + + Mat4CpyMat3(ikmat, ik_mat); + + if (pchan->parent) + Mat4MulSerie(pchan->pose_mat, pchan->parent->pose_mat, pchan->chan_mat, ikmat, NULL, NULL, NULL, NULL, NULL); + else + Mat4MulMat4(pchan->pose_mat, ikmat, pchan->chan_mat); + + /* calculate head */ + VECCOPY(pchan->pose_head, pchan->pose_mat[3]); + /* calculate tail */ + VECCOPY(vec, pchan->pose_mat[1]); + VecMulf(vec, pchan->bone->length); + VecAddf(pchan->pose_tail, pchan->pose_head, vec); + + pchan->flag |= POSE_DONE; +} + +/* NLA strip modifiers */ +static void do_strip_modifiers(Object *armob, Bone *bone, bPoseChannel *pchan) +{ + bActionModifier *amod; + bActionStrip *strip; + float scene_cfra= G.scene->r.cfra; + + for (strip=armob->nlastrips.first; strip; strip=strip->next) { + if(scene_cfra>=strip->start && scene_cfra<=strip->end) { + + /* temporal solution to prevent 2 strips accumulating */ + if(scene_cfra==strip->end && strip->next && strip->next->start==scene_cfra) + continue; + + for(amod= strip->modifiers.first; amod; amod= amod->next) { + switch (amod->type) { + case ACTSTRIP_MOD_DEFORM: + { + /* validate first */ + if(amod->ob && amod->ob->type==OB_CURVE && amod->channel[0]) { + + if( strcmp(pchan->name, amod->channel)==0 ) { + float mat4[4][4], mat3[3][3]; + + curve_deform_vector(amod->ob, armob, bone->arm_mat[3], pchan->pose_mat[3], mat3, amod->no_rot_axis); + Mat4CpyMat4(mat4, pchan->pose_mat); + Mat4MulMat34(pchan->pose_mat, mat3, mat4); + + } + } + } + break; + case ACTSTRIP_MOD_NOISE: + { + if( strcmp(pchan->name, amod->channel)==0 ) { + float nor[3], loc[3], ofs; + float eul[3], size[3], eulo[3], sizeo[3]; + + /* calculate turbulance */ + ofs = amod->turbul / 200.0f; + + /* make a copy of starting conditions */ + VECCOPY(loc, pchan->pose_mat[3]); + Mat4ToEul(pchan->pose_mat, eul); + Mat4ToSize(pchan->pose_mat, size); + VECCOPY(eulo, eul); + VECCOPY(sizeo, size); + + /* apply noise to each set of channels */ + if (amod->channels & 4) { + /* for scaling */ + nor[0] = BLI_gNoise(amod->noisesize, size[0]+ofs, size[1], size[2], 0, 0) - ofs; + nor[1] = BLI_gNoise(amod->noisesize, size[0], size[1]+ofs, size[2], 0, 0) - ofs; + nor[2] = BLI_gNoise(amod->noisesize, size[0], size[1], size[2]+ofs, 0, 0) - ofs; + VecAddf(size, size, nor); + + if (sizeo[0] != 0) + VecMulf(pchan->pose_mat[0], size[0] / sizeo[0]); + if (sizeo[1] != 0) + VecMulf(pchan->pose_mat[1], size[1] / sizeo[1]); + if (sizeo[2] != 0) + VecMulf(pchan->pose_mat[2], size[2] / sizeo[2]); + } + if (amod->channels & 2) { + /* for rotation */ + nor[0] = BLI_gNoise(amod->noisesize, eul[0]+ofs, eul[1], eul[2], 0, 0) - ofs; + nor[1] = BLI_gNoise(amod->noisesize, eul[0], eul[1]+ofs, eul[2], 0, 0) - ofs; + nor[2] = BLI_gNoise(amod->noisesize, eul[0], eul[1], eul[2]+ofs, 0, 0) - ofs; + + compatible_eul(nor, eulo); + VecAddf(eul, eul, nor); + compatible_eul(eul, eulo); + + LocEulSizeToMat4(pchan->pose_mat, loc, eul, size); + } + if (amod->channels & 1) { + /* for location */ + nor[0] = BLI_gNoise(amod->noisesize, loc[0]+ofs, loc[1], loc[2], 0, 0) - ofs; + nor[1] = BLI_gNoise(amod->noisesize, loc[0], loc[1]+ofs, loc[2], 0, 0) - ofs; + nor[2] = BLI_gNoise(amod->noisesize, loc[0], loc[1], loc[2]+ofs, 0, 0) - ofs; + + VecAddf(pchan->pose_mat[3], loc, nor); + } + } + } + break; + } + } + } + } +} + + +/* The main armature solver, does all constraints excluding IK */ +/* pchan is validated, as having bone and parent pointer */ +static void where_is_pose_bone(Object *ob, bPoseChannel *pchan, float ctime) +{ + Bone *bone, *parbone; + bPoseChannel *parchan; + float vec[3]; + + /* set up variables for quicker access below */ + bone= pchan->bone; + parbone= bone->parent; + parchan= pchan->parent; + + /* this gives a chan_mat with actions (ipos) results */ + chan_calc_mat(pchan); + + /* construct the posemat based on PoseChannels, that we do before applying constraints */ + /* pose_mat(b)= pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b) * chan_mat(b) */ + + if(parchan) { + float offs_bone[4][4]; // yoffs(b-1) + root(b) + bonemat(b) + + /* bone transform itself */ + Mat4CpyMat3(offs_bone, bone->bone_mat); + + /* The bone's root offset (is in the parent's coordinate system) */ + VECCOPY(offs_bone[3], bone->head); + + /* Get the length translation of parent (length along y axis) */ + offs_bone[3][1]+= parbone->length; + + /* Compose the matrix for this bone */ + if(bone->flag & BONE_HINGE) { // uses restposition rotation, but actual position + float tmat[4][4]; + + /* the rotation of the parent restposition */ + Mat4CpyMat4(tmat, parbone->arm_mat); + + /* the location of actual parent transform */ + VECCOPY(tmat[3], offs_bone[3]); + offs_bone[3][0]= offs_bone[3][1]= offs_bone[3][2]= 0.0f; + Mat4MulVecfl(parchan->pose_mat, tmat[3]); + + Mat4MulSerie(pchan->pose_mat, tmat, offs_bone, pchan->chan_mat, NULL, NULL, NULL, NULL, NULL); + } + else + Mat4MulSerie(pchan->pose_mat, parchan->pose_mat, offs_bone, pchan->chan_mat, NULL, NULL, NULL, NULL, NULL); + } + else { + Mat4MulMat4(pchan->pose_mat, pchan->chan_mat, bone->arm_mat); + /* only rootbones get the cyclic offset */ + VecAddf(pchan->pose_mat[3], pchan->pose_mat[3], ob->pose->cyclic_offset); + } + + /* do NLA strip modifiers - i.e. curve follow */ + do_strip_modifiers(ob, bone, pchan); + + /* Do constraints */ + if (pchan->constraints.first) { + bConstraintOb *cob; + + /* make a copy of location of PoseChannel for later */ + VECCOPY(vec, pchan->pose_mat[3]); + + /* prepare PoseChannel for Constraint solving + * - makes a copy of matrix, and creates temporary struct to use + */ + cob= constraints_make_evalob(ob, pchan, CONSTRAINT_OBTYPE_BONE); + + /* Solve PoseChannel's Constraints */ + solve_constraints(&pchan->constraints, cob, ctime); // ctime doesnt alter objects + + /* cleanup after Constraint Solving + * - applies matrix back to pchan, and frees temporary struct used + */ + constraints_clear_evalob(cob); + + /* prevent constraints breaking a chain */ + if(pchan->bone->flag & BONE_CONNECTED) { + VECCOPY(pchan->pose_mat[3], vec); + } + } + + /* calculate head */ + VECCOPY(pchan->pose_head, pchan->pose_mat[3]); + /* calculate tail */ + VECCOPY(vec, pchan->pose_mat[1]); + VecMulf(vec, bone->length); + VecAddf(pchan->pose_tail, pchan->pose_head, vec); +} + +/* This only reads anim data from channels, and writes to channels */ +/* This is the only function adding poses */ +void where_is_pose (Object *ob) +{ + bArmature *arm; + Bone *bone; + bPoseChannel *pchan; + float imat[4][4]; + float ctime= bsystem_time(ob, (float)G.scene->r.cfra, 0.0); /* not accurate... */ + + arm = get_armature(ob); + + if(arm==NULL) return; + if(ob->pose==NULL || (ob->pose->flag & POSE_RECALC)) + armature_rebuild_pose(ob, arm); + + /* In restposition we read the data from the bones */ + if(ob==G.obedit || (arm->flag & ARM_RESTPOS)) { + + for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { + bone= pchan->bone; + if(bone) { + Mat4CpyMat4(pchan->pose_mat, bone->arm_mat); + VECCOPY(pchan->pose_head, bone->arm_head); + VECCOPY(pchan->pose_tail, bone->arm_tail); + } + } + } + else { + Mat4Invert(ob->imat, ob->obmat); // imat is needed + + /* 1. construct the PoseTrees, clear flags */ + for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { + pchan->flag &= ~(POSE_DONE|POSE_CHAIN); + if(pchan->constflag & PCHAN_HAS_IK) // flag is set on editing constraints + initialize_posetree(ob, pchan); // will attach it to root! + } + + /* 2. the main loop, channels are already hierarchical sorted from root to children */ + for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { + + /* 3. if we find an IK root, we handle it separated */ + if(pchan->iktree.first) { + while(pchan->iktree.first) { + PoseTree *tree= pchan->iktree.first; + int a; + + /* 4. walk over the tree for regular solving */ + for(a=0; atotchannel; a++) { + if(!(tree->pchan[a]->flag & POSE_DONE)) // successive trees can set the flag + where_is_pose_bone(ob, tree->pchan[a], ctime); + } + /* 5. execute the IK solver */ + execute_posetree(ob, tree); + + /* 6. apply the differences to the channels, + we need to calculate the original differences first */ + for(a=0; atotchannel; a++) + make_dmats(tree->pchan[a]); + + for(a=0; atotchannel; a++) + /* sets POSE_DONE */ + where_is_ik_bone(tree->pchan[a], tree->basis_change[a]); + + /* 7. and free */ + BLI_remlink(&pchan->iktree, tree); + free_posetree(tree); + } + } + else if(!(pchan->flag & POSE_DONE)) { + where_is_pose_bone(ob, pchan, ctime); + } + } + } + + /* calculating deform matrices */ + for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { + if(pchan->bone) { + Mat4Invert(imat, pchan->bone->arm_mat); + Mat4MulMat4(pchan->chan_mat, imat, pchan->pose_mat); + } + } +} diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c new file mode 100644 index 00000000000..9d86b86a47f --- /dev/null +++ b/source/blender/blenkernel/intern/blender.c @@ -0,0 +1,735 @@ +/* blender.c jan 94 MIXED MODEL + * + * common help functions and data + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef WIN32 + #include // for read close + #include // for MAXPATHLEN +#else + #include // for open close read +#endif + +#include +#include +#include +#include // for open + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" +#include "DNA_sdna_types.h" +#include "DNA_userdef_types.h" +#include "DNA_object_types.h" +#include "DNA_curve_types.h" +#include "DNA_scene_types.h" + +#include "BLI_blenlib.h" +#include "BLI_dynstr.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "DNA_mesh_types.h" +#include "DNA_screen_types.h" + +#include "BKE_blender.h" +#include "BKE_curve.h" +#include "BKE_depsgraph.h" +#include "BKE_displist.h" +#include "BKE_font.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_node.h" +#include "BKE_object.h" +#include "BKE_scene.h" +#include "BKE_sound.h" + +#include "BLI_editVert.h" + +#include "BLO_undofile.h" +#include "BLO_readfile.h" +#include "BLO_writefile.h" + +#include "BKE_bad_level_calls.h" // for freeAllRad editNurb free_editMesh free_editText free_editArmature +#include "BKE_utildefines.h" // O_BINARY FALSE +#include "BIF_mainqueue.h" // mainqenter for onload script +#include "mydevice.h" +#include "nla.h" +#include "blendef.h" + +Global G; +UserDef U; + +char versionstr[48]= ""; + +/* ************************************************ */ +/* pushpop facility: to store data temporally, FIFO! */ + +ListBase ppmain={0, 0}; + +typedef struct PushPop { + struct PushPop *next, *prev; + void *data; + int len; +} PushPop; + +void pushdata(void *data, int len) +{ + PushPop *pp; + + pp= MEM_mallocN(sizeof(PushPop), "pushpop"); + BLI_addtail(&ppmain, pp); + pp->data= MEM_mallocN(len, "pushpop"); + pp->len= len; + memcpy(pp->data, data, len); +} + +void popfirst(void *data) +{ + PushPop *pp; + + pp= ppmain.first; + if(pp) { + memcpy(data, pp->data, pp->len); + BLI_remlink(&ppmain, pp); + MEM_freeN(pp->data); + MEM_freeN(pp); + } + else printf("error in popfirst\n"); +} + +void poplast(void *data) +{ + PushPop *pp; + + pp= ppmain.last; + if(pp) { + memcpy(data, pp->data, pp->len); + BLI_remlink(&ppmain, pp); + MEM_freeN(pp->data); + MEM_freeN(pp); + } + else printf("error in poplast\n"); +} + +void free_pushpop() +{ + PushPop *pp; + + pp= ppmain.first; + while(pp) { + BLI_remlink(&ppmain, pp); + MEM_freeN(pp->data); + MEM_freeN(pp); + } +} + +void pushpop_test() +{ + if(ppmain.first) printf("pushpop not empty\n"); + free_pushpop(); +} + + + +/* ********** free ********** */ + +void free_blender(void) +{ + /* samples are in a global list..., also sets G.main->sound->sample NULL */ + sound_free_all_samples(); + + free_main(G.main); + G.main= NULL; + + IMB_freeImBufdata(); /* imbuf lib */ + + free_nodesystem(); +} + +void duplicatelist(ListBase *list1, ListBase *list2) /* copy from 2 to 1 */ +{ + struct Link *link1, *link2; + + list1->first= list1->last= 0; + + link2= list2->first; + while(link2) { + + link1= MEM_dupallocN(link2); + BLI_addtail(list1, link1); + + link2= link2->next; + } +} + +static EditMesh theEditMesh; + +void initglobals(void) +{ + memset(&G, 0, sizeof(Global)); + + memset(&theEditMesh, 0, sizeof(theEditMesh)); + G.editMesh = &theEditMesh; + + U.savetime= 1; + + G.main= MEM_callocN(sizeof(Main), "initglobals"); + + strcpy(G.ima, "//"); + + G.version= BLENDER_VERSION; + + G.order= 1; + G.order= (((char*)&G.order)[0])?L_ENDIAN:B_ENDIAN; + + if(BLENDER_SUBVERSION) + sprintf(versionstr, "www.blender.org %d.%d", G.version, BLENDER_SUBVERSION); + else + sprintf(versionstr, "www.blender.org %d", G.version); + +#ifdef _WIN32 // FULLSCREEN + G.windowstate = G_WINDOWSTATE_USERDEF; +#endif + + clear_workob(); /* object.c */ + + G.charstart = 0x0000; + G.charmin = 0x0000; + G.charmax = 0xffff; +} + +/***/ + +static void clear_global(void) +{ + extern short winqueue_break; /* screen.c */ + + freeAllRad(); + fastshade_free_render(); /* lamps hang otherwise */ + free_main(G.main); /* free all lib data */ + + /* force all queues to be left */ + winqueue_break= 1; + + if (G.obedit) { + freeNurblist(&editNurb); + free_editMesh(G.editMesh); + free_editText(); + free_editArmature(); + } + + G.curscreen= NULL; + G.scene= NULL; + G.main= NULL; + + G.obedit= NULL; + G.saction= NULL; + G.buts= NULL; + G.v2d= NULL; + G.vd= NULL; + G.soops= NULL; + G.sima= NULL; + G.sipo= NULL; + + free_vertexpaint(); + + G.f &= ~(G_WEIGHTPAINT + G_VERTEXPAINT + G_FACESELECT); +} + +/* make sure path names are correct for OS */ +static void clean_paths(Main *main) +{ + Image *image= main->image.first; + bSound *sound= main->sound.first; + Scene *scene= main->scene.first; + Editing *ed; + Sequence *seq; + Strip *strip; + + while(image) { + BLI_clean(image->name); + image= image->id.next; + } + + while(sound) { + BLI_clean(sound->name); + sound= sound->id.next; + } + + while(scene) { + ed= scene->ed; + if(ed) { + seq= ed->seqbasep->first; + while(seq) { + if(seq->plugin) { + BLI_clean(seq->plugin->name); + } + strip= seq->strip; + while(strip) { + BLI_clean(strip->dir); + strip= strip->next; + } + seq= seq->next; + } + } + BLI_clean(scene->r.backbuf); + BLI_clean(scene->r.pic); + BLI_clean(scene->r.ftype); + + scene= scene->id.next; + } +} + +static void setup_app_data(BlendFileData *bfd, char *filename) +{ + Object *ob; + bScreen *curscreen= NULL; + Scene *curscene= NULL; + char mode; + + /* 'u' = undo save, 'n' = no UI load */ + if(bfd->main->screen.first==NULL) mode= 'u'; + else if(G.fileflags & G_FILE_NO_UI) mode= 'n'; + else mode= 0; + + clean_paths(bfd->main); + + /* no load screens? */ + if(mode) { + /* comes from readfile.c */ + extern void lib_link_screen_restore(Main *, Scene *); + + SWAP(ListBase, G.main->screen, bfd->main->screen); + + /* we re-use current screen */ + curscreen= G.curscreen; + /* but use new Scene pointer */ + curscene= bfd->curscene; + if(curscene==NULL) curscene= bfd->main->scene.first; + /* and we enforce curscene to be in current screen */ + curscreen->scene= curscene; + + /* clear_global will free G.main, here we can still restore pointers */ + lib_link_screen_restore(bfd->main, curscene); + } + + clear_global(); /* free Main database */ + + if(mode!='u') G.save_over = 1; + + G.main= bfd->main; + if (bfd->user) { + + /* only here free userdef themes... */ + BLI_freelistN(&U.themes); + + U= *bfd->user; + MEM_freeN(bfd->user); + + } + + /* samples is a global list... */ + sound_free_all_samples(); + + /* case G_FILE_NO_UI or no screens in file */ + if(mode) { + G.curscreen= curscreen; + G.scene= curscene; + } + else { + G.winpos= bfd->winpos; + G.displaymode= bfd->displaymode; + G.fileflags= bfd->fileflags; + G.curscreen= bfd->curscreen; + G.scene= G.curscreen->scene; + } + /* this can happen when active scene was lib-linked, and doesnt exist anymore */ + if(G.scene==NULL) { + G.scene= G.main->scene.first; + G.curscreen->scene= G.scene; + } + + /* special cases, override loaded flags: */ + if (G.f & G_DEBUG) bfd->globalf |= G_DEBUG; + else bfd->globalf &= ~G_DEBUG; + if (!(G.f & G_DOSCRIPTLINKS)) bfd->globalf &= ~G_DOSCRIPTLINKS; + + G.f= bfd->globalf; + + if (!G.background) { + setscreen(G.curscreen); + } + + /* baseflags, groups, make depsgraph, etc */ + set_scene_bg(G.scene); + + /* last stage of do_versions actually, that sets recalc flags for recalc poses */ + for(ob= G.main->object.first; ob; ob= ob->id.next) { + if(ob->type==OB_ARMATURE) + if(ob->recalc) object_handle_update(ob); + } + + /* now tag update flags, to ensure deformers get calculated on redraw */ + DAG_scene_update_flags(G.scene, G.scene->lay); + + if (G.f & G_DOSCRIPTLINKS) { + /* there's an onload scriptlink to execute in screenmain */ + mainqenter(ONLOAD_SCRIPT, 1); + } + if (G.sce != filename) /* these are the same at times, should never copy to the same location */ + strcpy(G.sce, filename); + + strcpy(G.main->name, filename); /* is guaranteed current file */ + + MEM_freeN(bfd); +} + +static void handle_subversion_warning(Main *main) +{ + if(main->minversionfile > BLENDER_VERSION || + (main->minversionfile == BLENDER_VERSION && + main->minsubversionfile > BLENDER_SUBVERSION)) { + + char str[128]; + + sprintf(str, "File written by newer Blender binary: %d.%d , expect loss of data!", main->minversionfile, main->minsubversionfile); + error(str); + } + +} + +/* returns: + 0: no load file + 1: OK + 2: OK, and with new user settings +*/ + +int BKE_read_file(char *dir, void *type_r) +{ + BlendReadError bre; + BlendFileData *bfd; + int retval= 1; + + if (!G.background) + waitcursor(1); + + bfd= BLO_read_from_file(dir, &bre); + if (bfd) { + if(bfd->user) retval= 2; + if (type_r) + *((BlenFileType*)type_r)= bfd->type; + + setup_app_data(bfd, dir); + + handle_subversion_warning(G.main); + } + else { + error("Loading %s failed: %s", dir, BLO_bre_as_string(bre)); + } + + if (!G.background) + waitcursor(0); + + return (bfd?retval:0); +} + +int BKE_read_file_from_memory(char* filebuf, int filelength, void *type_r) +{ + BlendReadError bre; + BlendFileData *bfd; + + if (!G.background) + waitcursor(1); + + bfd= BLO_read_from_memory(filebuf, filelength, &bre); + if (bfd) { + if (type_r) + *((BlenFileType*)type_r)= bfd->type; + + setup_app_data(bfd, ""); + } else { + error("Loading failed: %s", BLO_bre_as_string(bre)); + } + + if (!G.background) + waitcursor(0); + + return (bfd?1:0); +} + +/* memfile is the undo buffer */ +int BKE_read_file_from_memfile(MemFile *memfile) +{ + BlendReadError bre; + BlendFileData *bfd; + + if (!G.background) + waitcursor(1); + + bfd= BLO_read_from_memfile(G.sce, memfile, &bre); + if (bfd) { + setup_app_data(bfd, ""); + } else { + error("Loading failed: %s", BLO_bre_as_string(bre)); + } + + if (!G.background) + waitcursor(0); + + return (bfd?1:0); +} + + +/* ***************** GLOBAL UNDO *************** */ + +#define UNDO_DISK 0 + +#define MAXUNDONAME 64 +typedef struct UndoElem { + struct UndoElem *next, *prev; + char str[FILE_MAXDIR+FILE_MAXFILE]; + char name[MAXUNDONAME]; + MemFile memfile; +} UndoElem; + +static ListBase undobase={NULL, NULL}; +static UndoElem *curundo= NULL; + + +static int read_undosave(UndoElem *uel) +{ + char scestr[FILE_MAXDIR+FILE_MAXFILE]; + int success=0, fileflags; + + strcpy(scestr, G.sce); /* temporal store */ + fileflags= G.fileflags; + G.fileflags |= G_FILE_NO_UI; + + if(UNDO_DISK) + success= BKE_read_file(uel->str, NULL); + else + success= BKE_read_file_from_memfile(&uel->memfile); + + /* restore */ + strcpy(G.sce, scestr); + G.fileflags= fileflags; + + return success; +} + +/* name can be a dynamic string */ +void BKE_write_undo(char *name) +{ + int nr, success; + UndoElem *uel; + + if( (U.uiflag & USER_GLOBALUNDO)==0) return; + if( U.undosteps==0) return; + + /* remove all undos after (also when curundo==NULL) */ + while(undobase.last != curundo) { + uel= undobase.last; + BLI_remlink(&undobase, uel); + BLO_free_memfile(&uel->memfile); + MEM_freeN(uel); + } + + /* make new */ + curundo= uel= MEM_callocN(sizeof(UndoElem), "undo file"); + strncpy(uel->name, name, MAXUNDONAME-1); + BLI_addtail(&undobase, uel); + + /* and limit amount to the maximum */ + nr= 0; + uel= undobase.last; + while(uel) { + nr++; + if(nr==U.undosteps) break; + uel= uel->prev; + } + if(uel) { + while(undobase.first!=uel) { + UndoElem *first= undobase.first; + BLI_remlink(&undobase, first); + /* the merge is because of compression */ + BLO_merge_memfile(&first->memfile, &first->next->memfile); + MEM_freeN(first); + } + } + + + /* disk save version */ + if(UNDO_DISK) { + static int counter= 0; + char *err, tstr[FILE_MAXDIR+FILE_MAXFILE]; + char numstr[32]; + + /* calculate current filename */ + counter++; + counter= counter % U.undosteps; + + sprintf(numstr, "%d.blend", counter); + BLI_make_file_string("/", tstr, U.tempdir, numstr); + + success= BLO_write_file(tstr, G.fileflags, &err); + + strcpy(curundo->str, tstr); + } + else { + MemFile *prevfile=NULL; + char *err; + + if(curundo->prev) prevfile= &(curundo->prev->memfile); + + success= BLO_write_file_mem(prevfile, &curundo->memfile, G.fileflags, &err); + + } +} + +/* 1= an undo, -1 is a redo. we have to make sure 'curundo' remains at current situation */ +void BKE_undo_step(int step) +{ + + if(step==0) { + read_undosave(curundo); + } + else if(step==1) { + /* curundo should never be NULL, after restart or load file it should call undo_save */ + if(curundo==NULL || curundo->prev==NULL) error("No undo available"); + else { + if(G.f & G_DEBUG) printf("undo %s\n", curundo->name); + curundo= curundo->prev; + read_undosave(curundo); + } + } + else { + + /* curundo has to remain current situation! */ + + if(curundo==NULL || curundo->next==NULL) error("No redo available"); + else { + read_undosave(curundo->next); + curundo= curundo->next; + if(G.f & G_DEBUG) printf("redo %s\n", curundo->name); + } + } +} + +void BKE_reset_undo(void) +{ + UndoElem *uel; + + uel= undobase.first; + while(uel) { + BLO_free_memfile(&uel->memfile); + uel= uel->next; + } + + BLI_freelistN(&undobase); + curundo= NULL; +} + +/* based on index nr it does a restore */ +void BKE_undo_number(int nr) +{ + UndoElem *uel; + int a=1; + + for(uel= undobase.first; uel; uel= uel->next, a++) { + if(a==nr) break; + } + curundo= uel; + BKE_undo_step(0); +} + +char *BKE_undo_menu_string(void) +{ + UndoElem *uel; + DynStr *ds= BLI_dynstr_new(); + char *menu; + + BLI_dynstr_append(ds, "Global Undo History %t"); + + for(uel= undobase.first; uel; uel= uel->next) { + BLI_dynstr_append(ds, "|"); + BLI_dynstr_append(ds, uel->name); + } + + menu= BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + + return menu; +} + + /* saves quit.blend */ +void BKE_undo_save_quit(void) +{ + UndoElem *uel; + MemFileChunk *chunk; + int file; + char str[FILE_MAXDIR+FILE_MAXFILE]; + + if( (U.uiflag & USER_GLOBALUNDO)==0) return; + + uel= curundo; + if(uel==NULL) { + printf("No undo buffer to save recovery file\n"); + return; + } + + /* no undo state to save */ + if(undobase.first==undobase.last) return; + + BLI_make_file_string("/", str, U.tempdir, "quit.blend"); + + file = open(str,O_BINARY+O_WRONLY+O_CREAT+O_TRUNC, 0666); + if(file == -1) { + printf("Unable to save %s\n", str); + return; + } + + chunk= uel->memfile.chunks.first; + while(chunk) { + if( write(file, chunk->buf, chunk->size) != chunk->size) break; + chunk= chunk->next; + } + + close(file); + + if(chunk) printf("Unable to save %s\n", str); + else printf("Saved session recovery to %s\n", str); +} + diff --git a/source/blender/blenkernel/intern/bmfont.c b/source/blender/blenkernel/intern/bmfont.c new file mode 100644 index 00000000000..6ea08b5cfbb --- /dev/null +++ b/source/blender/blenkernel/intern/bmfont.c @@ -0,0 +1,297 @@ +/** + * bmfont.c + * + * 04-10-2000 frank + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + */ + +/** + * Two external functions: + * + * void detectBitmapFont(ImBuf *ibuf) + * detects if an image buffer contains a bitmap font. It makes the + * specific bitmap data which is stored in the bitmap invisible to blender. + * + * void matrixGlyph(ImBuf * ibuf, unsigned short unicode, *float x 7) + * returns all the information about the character (unicode) in the floats + * + * Room for improvement: + * add kerning data in the bitmap + * all calculations in matrixGlyph() are static and could be done during + * initialization + */ + +#include + +#include "MEM_guardedalloc.h" +#include "BLI_blenlib.h" +#include "BKE_global.h" +#include "IMB_imbuf_types.h" + +#include "BKE_bmfont.h" +#include "BKE_bmfont_types.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +void printfGlyph(bmGlyph * glyph) +{ + printf("unicode: %d '%c'\n", glyph->unicode, glyph->unicode); + printf(" locx: %4d locy: %4d\n", glyph->locx, glyph->locy); + printf(" sizex: %3d sizey: %3d\n", glyph->sizex, glyph->sizey); + printf(" ofsx: %3d ofsy: %3d\n", glyph->ofsx, glyph->ofsy); + printf(" advan: %3d reser: %3d\n", glyph->advance, glyph->reserved); +} + +#define MAX2(x,y) ( (x)>(y) ? (x) : (y) ) +#define MAX3(x,y,z) MAX2( MAX2((x),(y)) , (z) ) + +void calcAlpha(ImBuf * ibuf) +{ + int i; + char * rect; + + if (ibuf) { + rect = (char *) ibuf->rect; + for (i = ibuf->x * ibuf->y ; i > 0 ; i--) { + rect[3] = MAX3(rect[0], rect[1], rect[2]); + rect += 4; + } + } +} + +void readBitmapFontVersion0(ImBuf * ibuf, unsigned char * rect, int step) +{ + int glyphcount, bytes, i, index, linelength, ysize; + unsigned char * buffer; + bmFont * bmfont; + + linelength = ibuf->x * step; + + glyphcount = (rect[6 * step] << 8) | rect[7 * step]; + bytes = ((glyphcount - 1) * sizeof(bmGlyph)) + sizeof(bmFont); + + ysize = (bytes + (ibuf->x - 1)) / ibuf->x; + + if (ysize < ibuf->y) { + // we're first going to copy all data into a liniar buffer. + // step can be 4 or 1 bytes, and the data is not sequential because + // the bitmap was flipped vertically. + + buffer = MEM_mallocN(bytes, "readBitmapFontVersion0:buffer"); + + index = 0; + for (i = 0; i < bytes; i++) { + buffer[i] = rect[index]; + index += step; + if (index >= linelength) { + // we've read one line, no skip to the line *before* that + rect -= linelength; + index -= linelength; + } + } + + // we're now going to endian convert the data + + bmfont = MEM_mallocN(bytes, "readBitmapFontVersion0:bmfont"); + index = 0; + + // first read the header + bmfont->magic[0] = buffer[index++]; + bmfont->magic[1] = buffer[index++]; + bmfont->magic[2] = buffer[index++]; + bmfont->magic[3] = buffer[index++]; + bmfont->version = (buffer[index] << 8) | buffer[index + 1]; index += 2; + bmfont->glyphcount = (buffer[index] << 8) | buffer[index + 1]; index += 2; + bmfont->xsize = (buffer[index] << 8) | buffer[index + 1]; index += 2; + bmfont->ysize = (buffer[index] << 8) | buffer[index + 1]; index += 2; + + for (i = 0; i < bmfont->glyphcount; i++) { + bmfont->glyphs[i].unicode = (buffer[index] << 8) | buffer[index + 1]; index += 2; + bmfont->glyphs[i].locx = (buffer[index] << 8) | buffer[index + 1]; index += 2; + bmfont->glyphs[i].locy = (buffer[index] << 8) | buffer[index + 1]; index += 2; + bmfont->glyphs[i].ofsx = buffer[index++]; + bmfont->glyphs[i].ofsy = buffer[index++]; + bmfont->glyphs[i].sizex = buffer[index++]; + bmfont->glyphs[i].sizey = buffer[index++]; + bmfont->glyphs[i].advance = buffer[index++]; + bmfont->glyphs[i].reserved = buffer[index++]; + if (G.f & G_DEBUG) { + printfGlyph(&bmfont->glyphs[i]); + } + } + + MEM_freeN(buffer); + + if (G.f & G_DEBUG) { + printf("Oldy = %d Newy = %d\n", ibuf->y, ibuf->y - ysize); + printf("glyphcount = %d\n", glyphcount); + printf("bytes = %d\n", bytes); + } + + // we've read the data from the image. Now we're going + // to crop the image vertically so only the bitmap data + // remains visible + + ibuf->y -= ysize; + ibuf->userdata = bmfont; + ibuf->userflags |= IB_BITMAPFONT; + + if (ibuf->depth < 32) { + // we're going to fake alpha here: + calcAlpha(ibuf); + } + } else { + printf("readBitmapFontVersion0: corrupted bitmapfont\n"); + } +} + +void detectBitmapFont(ImBuf *ibuf) +{ + unsigned char * rect; + unsigned short version; + long i; + + if (ibuf != NULL) { + // bitmap must have an x size that is a power of two + if (is_power_of_two(ibuf->x)) { + rect = (unsigned char *) (ibuf->rect + (ibuf->x * (ibuf->y - 1))); + // printf ("starts with: %s %c %c %c %c\n", rect, rect[0], rect[1], rect[2], rect[3]); + if (rect[0] == 'B' && rect[1] == 'F' && rect[2] == 'N' && rect[3] == 'T') { + // printf("found 8bit font !\n"); + // round y size down + // do the 8 bit font stuff. (not yet) + } else { + // we try all 4 possible combinations + for (i = 0; i < 4; i++) { + if (rect[0] == 'B' && rect[4] == 'F' && rect[8] == 'N' && rect[12] == 'T') { + // printf("found 24bit font !\n"); + // We're going to parse the file: + + version = (rect[16] << 8) | rect[20]; + + if (version == 0) { + readBitmapFontVersion0(ibuf, rect, 4); + } else { + printf("detectBitmapFont :Unsupported version %d\n", version); + } + + // on succes ibuf->userdata points to the bitmapfont + if (ibuf->userdata) { + break; + } + } + rect++; + } + } + } + } +} + +int locateGlyph(bmFont *bmfont, unsigned short unicode) +{ + int min, max, current = 0; + + if (bmfont) { + min = 0; + max = bmfont->glyphcount; + while (1) { + // look halfway for glyph + current = (min + max) >> 1; + + if (bmfont->glyphs[current].unicode == unicode) { + break; + } else if (bmfont->glyphs[current].unicode < unicode) { + // have to move up + min = current; + } else { + // have to move down + max = current; + } + + if (max - min <= 1) { + // unable to locate glyph + current = 0; + break; + } + } + } + + return(current); +} + +void matrixGlyph(ImBuf * ibuf, unsigned short unicode, + float *centerx, float *centery, + float *sizex, float *sizey, + float *transx, float *transy, + float *movex, float *movey, + float *advance) +{ + int index; + bmFont *bmfont; + + *centerx = *centery = 0.0; + *sizex = *sizey = 1.0; + *transx = *transy = 0.0; + *movex = *movey = 0.0; + *advance = 1.0; + + if (ibuf) { + bmfont = ibuf->userdata; + if (bmfont && (ibuf->userflags & IB_BITMAPFONT)) { + index = locateGlyph(bmfont, unicode); + if (index) { + + *sizex = (bmfont->glyphs[index].sizex) / (float) (bmfont->glyphs[0].sizex); + *sizey = (bmfont->glyphs[index].sizey) / (float) (bmfont->glyphs[0].sizey); + + *transx = bmfont->glyphs[index].locx / (float) ibuf->x; + *transy = (ibuf->y - bmfont->glyphs[index].locy) / (float) ibuf->y; + + *centerx = bmfont->glyphs[0].locx / (float) ibuf->x; + *centery = (ibuf->y - bmfont->glyphs[0].locy) / (float) ibuf->y; + + // 2.0 units is the default size of an object + + *movey = 1.0f - *sizey + 2.0f * (bmfont->glyphs[index].ofsy - bmfont->glyphs[0].ofsy) / (float) bmfont->glyphs[0].sizey; + *movex = *sizex - 1.0f + 2.0f * (bmfont->glyphs[index].ofsx - bmfont->glyphs[0].ofsx) / (float) bmfont->glyphs[0].sizex; + + *advance = 2.0f * bmfont->glyphs[index].advance / (float) bmfont->glyphs[0].advance; + + // printfGlyph(&bmfont->glyphs[index]); + // printf("%c %d %0.5f %0.5f %0.5f %0.5f %0.5f \n", unicode, index, *sizex, *sizey, *transx, *transy, *advance); + } + } + } +} diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c new file mode 100644 index 00000000000..ca2f7b114d5 --- /dev/null +++ b/source/blender/blenkernel/intern/brush.c @@ -0,0 +1,882 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_brush_types.h" +#include "DNA_image_types.h" +#include "DNA_texture_types.h" +#include "DNA_scene_types.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" + +#include "BKE_brush.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_texture.h" +#include "BKE_utildefines.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "RE_render_ext.h" /* externtex */ + +/* Datablock add/copy/free/make_local */ + +Brush *add_brush(char *name) +{ + Brush *brush; + + brush= alloc_libblock(&G.main->brush, ID_BR, name); + + brush->rgb[0]= 1.0f; + brush->rgb[1]= 1.0f; + brush->rgb[2]= 1.0f; + brush->alpha= 0.2f; + brush->size= 25; + brush->spacing= 10.0f; + brush->rate= 0.1f; + brush->innerradius= 0.5f; + brush->clone.alpha= 0.5; + + /* enable fake user by default */ + brush_toggle_fake_user(brush); + + return brush; +} + +Brush *copy_brush(Brush *brush) +{ + Brush *brushn; + MTex *mtex; + int a; + + brushn= copy_libblock(brush); + + for(a=0; amtex[a]; + if(mtex) { + brushn->mtex[a]= MEM_dupallocN(mtex); + if(mtex->tex) id_us_plus((ID*)mtex->tex); + } + } + + /* enable fake user by default */ + if (!(brushn->id.flag & LIB_FAKEUSER)) + brush_toggle_fake_user(brushn); + + return brushn; +} + +/* not brush itself */ +void free_brush(Brush *brush) +{ + MTex *mtex; + int a; + + for(a=0; amtex[a]; + if(mtex) { + if(mtex->tex) mtex->tex->id.us--; + MEM_freeN(mtex); + } + } +} + +void make_local_brush(Brush *brush) +{ + /* - only lib users: do nothing + * - only local users: set flag + * - mixed: make copy + */ + + Brush *brushn; + Scene *scene; + int local= 0, lib= 0; + + if(brush->id.lib==0) return; + + if(brush->clone.image) { + /* special case: ima always local immediately */ + brush->clone.image->id.lib= 0; + brush->clone.image->id.flag= LIB_LOCAL; + new_id(0, (ID *)brush->clone.image, 0); + } + + for(scene= G.main->scene.first; scene; scene=scene->id.next) + if(scene->toolsettings->imapaint.brush==brush) { + if(scene->id.lib) lib= 1; + else local= 1; + } + + if(local && lib==0) { + brush->id.lib= 0; + brush->id.flag= LIB_LOCAL; + new_id(0, (ID *)brush, 0); + + /* enable fake user by default */ + if (!(brush->id.flag & LIB_FAKEUSER)) + brush_toggle_fake_user(brush); + } + else if(local && lib) { + brushn= copy_brush(brush); + brushn->id.us= 1; /* only keep fake user */ + brushn->id.flag |= LIB_FAKEUSER; + + for(scene= G.main->scene.first; scene; scene=scene->id.next) + if(scene->toolsettings->imapaint.brush==brush) + if(scene->id.lib==0) { + scene->toolsettings->imapaint.brush= brushn; + brushn->id.us++; + brush->id.us--; + } + } +} + +/* Library Operations */ + +int brush_set_nr(Brush **current_brush, int nr) +{ + ID *idtest, *id; + + id= (ID*)(*current_brush); + idtest= (ID*)BLI_findlink(&G.main->brush, nr-1); + + if(idtest==0) { /* new brush */ + if(id) idtest= (ID *)copy_brush((Brush *)id); + else idtest= (ID *)add_brush("Brush"); + idtest->us--; + } + if(idtest!=id) { + brush_delete(current_brush); + *current_brush= (Brush *)idtest; + id_us_plus(idtest); + + return 1; + } + + return 0; +} + +int brush_delete(Brush **current_brush) +{ + if (*current_brush) { + (*current_brush)->id.us--; + *current_brush= NULL; + + return 1; + } + + return 0; +} + +void brush_toggle_fake_user(Brush *brush) +{ + ID *id= (ID*)brush; + if(id) { + if(id->flag & LIB_FAKEUSER) { + id->flag -= LIB_FAKEUSER; + id->us--; + } else { + id->flag |= LIB_FAKEUSER; + id_us_plus(id); + } + } +} + +int brush_texture_set_nr(Brush *brush, int nr) +{ + ID *idtest, *id=NULL; + + if(brush->mtex[brush->texact]) + id= (ID *)brush->mtex[brush->texact]->tex; + + idtest= (ID*)BLI_findlink(&G.main->tex, nr-1); + if(idtest==0) { /* new tex */ + if(id) idtest= (ID *)copy_texture((Tex *)id); + else idtest= (ID *)add_texture("Tex"); + idtest->us--; + } + if(idtest!=id) { + brush_texture_delete(brush); + + if(brush->mtex[brush->texact]==NULL) { + brush->mtex[brush->texact]= add_mtex(); + brush->mtex[brush->texact]->r = 1.0f; + brush->mtex[brush->texact]->g = 1.0f; + brush->mtex[brush->texact]->b = 1.0f; + } + brush->mtex[brush->texact]->tex= (Tex*)idtest; + id_us_plus(idtest); + + return 1; + } + + return 0; +} + +int brush_texture_delete(Brush *brush) +{ + if(brush->mtex[brush->texact]) { + if(brush->mtex[brush->texact]->tex) + brush->mtex[brush->texact]->tex->id.us--; + MEM_freeN(brush->mtex[brush->texact]); + brush->mtex[brush->texact]= NULL; + + return 1; + } + + return 0; +} + +int brush_clone_image_set_nr(Brush *brush, int nr) +{ + if(brush && nr > 0) { + Image *ima= (Image*)BLI_findlink(&G.main->image, nr-1); + + if(ima) { + brush_clone_image_delete(brush); + brush->clone.image= ima; + id_us_plus(&ima->id); + brush->clone.offset[0]= brush->clone.offset[1]= 0.0f; + + return 1; + } + } + + return 0; +} + +int brush_clone_image_delete(Brush *brush) +{ + if (brush && brush->clone.image) { + brush->clone.image->id.us--; + brush->clone.image= NULL; + return 1; + } + + return 0; +} + +void brush_check_exists(Brush **brush) +{ + if(*brush==NULL) + brush_set_nr(brush, 1); +} + +/* Brush Sampling */ + +/*static float taylor_approx_cos(float f) +{ + f = f*f; + f = 1.0f - f/2.0f + f*f/24.0f; + return f; +}*/ + +float brush_sample_falloff(Brush *brush, float dist) +{ + float a, outer, inner; + + outer = brush->size >> 1; + inner = outer*brush->innerradius; + + if (dist <= inner) { + return brush->alpha; + } + else if ((dist < outer) && (inner < outer)) { + a = sqrt((dist - inner)/(outer - inner)); + return (1 - a)*brush->alpha; + + /* formula used by sculpt, with taylor approx + a = 0.5f*(taylor_approx_cos(3.0f*(dist - inner)/(outer - inner)) + 1.0f); + return a*brush->alpha; */ + } + else + return 0.0f; +} + +void brush_sample_tex(Brush *brush, float *xy, float *rgba) +{ + MTex *mtex= brush->mtex[brush->texact]; + + if (mtex && mtex->tex) { + float co[3], tin, tr, tg, tb, ta; + int hasrgb; + + co[0]= xy[0]/(brush->size >> 1); + co[1]= xy[1]/(brush->size >> 1); + co[2]= 0.0f; + + hasrgb= externtex(mtex, co, &tin, &tr, &tg, &tb, &ta); + + if (hasrgb) { + rgba[0]= tr; + rgba[1]= tg; + rgba[2]= tb; + rgba[3]= ta; + } + else { + rgba[0]= tin; + rgba[1]= tin; + rgba[2]= tin; + rgba[3]= 1.0f; + } + } + else if (rgba) + rgba[0]= rgba[1]= rgba[2]= rgba[3]= 1.0f; +} + +#define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.0f*val)) + +void brush_imbuf_new(Brush *brush, short flt, short texfall, int size, ImBuf **outbuf) +{ + ImBuf *ibuf; + float xy[2], dist, rgba[4], *dstf; + int x, y, rowbytes, xoff, yoff, imbflag; + char *dst, crgb[3]; + + imbflag= (flt)? IB_rectfloat: IB_rect; + xoff = -size/2.0f + 0.5f; + yoff = -size/2.0f + 0.5f; + rowbytes= size*4; + + if (*outbuf) + ibuf= *outbuf; + else + ibuf= IMB_allocImBuf(size, size, 32, imbflag, 0); + + if (flt) { + for (y=0; y < ibuf->y; y++) { + dstf = ibuf->rect_float + y*rowbytes; + + for (x=0; x < ibuf->x; x++, dstf+=4) { + xy[0] = x + xoff; + xy[1] = y + yoff; + + if (texfall == 0) { + dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]); + + VECCOPY(dstf, brush->rgb); + dstf[3]= brush_sample_falloff(brush, dist); + } + else if (texfall == 1) { + brush_sample_tex(brush, xy, dstf); + } + else { + dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]); + + brush_sample_tex(brush, xy, rgba); + + dstf[0] = rgba[0]*brush->rgb[0]; + dstf[1] = rgba[1]*brush->rgb[1]; + dstf[2] = rgba[2]*brush->rgb[2]; + dstf[3] = rgba[3]*brush_sample_falloff(brush, dist); + } + } + } + } + else { + crgb[0]= FTOCHAR(brush->rgb[0]); + crgb[1]= FTOCHAR(brush->rgb[1]); + crgb[2]= FTOCHAR(brush->rgb[2]); + + for (y=0; y < ibuf->y; y++) { + dst = (char*)ibuf->rect + y*rowbytes; + + for (x=0; x < ibuf->x; x++, dst+=4) { + xy[0] = x + xoff; + xy[1] = y + yoff; + + if (texfall == 0) { + dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]); + + dst[0]= crgb[0]; + dst[1]= crgb[1]; + dst[2]= crgb[2]; + dst[3]= FTOCHAR(brush_sample_falloff(brush, dist)); + } + else if (texfall == 1) { + brush_sample_tex(brush, xy, rgba); + dst[0]= FTOCHAR(rgba[0]); + dst[1]= FTOCHAR(rgba[1]); + dst[2]= FTOCHAR(rgba[2]); + dst[3]= FTOCHAR(rgba[3]); + } + else { + dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]); + + brush_sample_tex(brush, xy, rgba); + dst[0] = FTOCHAR(rgba[0]*brush->rgb[0]); + dst[1] = FTOCHAR(rgba[1]*brush->rgb[1]); + dst[2] = FTOCHAR(rgba[2]*brush->rgb[2]); + dst[3] = FTOCHAR(rgba[3]*brush_sample_falloff(brush, dist)); + } + } + } + } + + *outbuf= ibuf; +} + +/* Brush Painting */ + +typedef struct BrushPainterCache { + short enabled; + + int size; /* size override, if 0 uses brush->size */ + short flt; /* need float imbuf? */ + short texonly; /* no alpha, color or fallof, only texture in imbuf */ + + int lastsize; + float lastalpha; + float lastinnerradius; + + ImBuf *ibuf; + ImBuf *texibuf; + ImBuf *maskibuf; +} BrushPainterCache; + +struct BrushPainter { + Brush *brush; + + float lastmousepos[2]; /* mouse position of last paint call */ + + float accumdistance; /* accumulated distance of brush since last paint op */ + float lastpaintpos[2]; /* position of last paint op */ + float startpaintpos[2]; /* position of first paint */ + + double accumtime; /* accumulated time since last paint op (airbrush) */ + double lasttime; /* time of last update */ + + float lastpressure; + + short firsttouch; /* first paint op */ + + float startsize; + float startalpha; + float startinnerradius; + float startspacing; + + BrushPainterCache cache; +}; + +BrushPainter *brush_painter_new(Brush *brush) +{ + BrushPainter *painter= MEM_callocN(sizeof(BrushPainter), "BrushPainter"); + + painter->brush= brush; + painter->firsttouch= 1; + painter->cache.lastsize= -1; /* force ibuf create in refresh */ + + painter->startsize = brush->size; + painter->startalpha = brush->alpha; + painter->startinnerradius = brush->innerradius; + painter->startspacing = brush->spacing; + + return painter; +} + +void brush_painter_require_imbuf(BrushPainter *painter, short flt, short texonly, int size) +{ + if ((painter->cache.flt != flt) || (painter->cache.size != size) || + ((painter->cache.texonly != texonly) && texonly)) { + if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf); + if (painter->cache.maskibuf) IMB_freeImBuf(painter->cache.maskibuf); + painter->cache.ibuf= painter->cache.maskibuf= NULL; + painter->cache.lastsize= -1; /* force ibuf create in refresh */ + } + + if (painter->cache.flt != flt) { + if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf); + painter->cache.texibuf= NULL; + painter->cache.lastsize= -1; /* force ibuf create in refresh */ + } + + painter->cache.size= size; + painter->cache.flt= flt; + painter->cache.texonly= texonly; + painter->cache.enabled= 1; +} + +void brush_painter_free(BrushPainter *painter) +{ + Brush *brush = painter->brush; + + brush->size = painter->startsize; + brush->alpha = painter->startalpha; + brush->innerradius = painter->startinnerradius; + brush->spacing = painter->startspacing; + + if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf); + if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf); + if (painter->cache.maskibuf) IMB_freeImBuf(painter->cache.maskibuf); + MEM_freeN(painter); +} + +static void brush_painter_do_partial(BrushPainter *painter, ImBuf *oldtexibuf, int x, int y, int w, int h, int xt, int yt, float *pos) +{ + Brush *brush= painter->brush; + ImBuf *ibuf, *maskibuf, *texibuf; + float *bf, *mf, *tf, *otf=NULL, xoff, yoff, xy[2], rgba[4]; + char *b, *m, *t, *ot= NULL; + int dotexold, origx= x, origy= y; + + xoff = -brush->size/2.0f + 0.5f; + yoff = -brush->size/2.0f + 0.5f; + xoff += (int)pos[0] - (int)painter->startpaintpos[0]; + yoff += (int)pos[1] - (int)painter->startpaintpos[1]; + + ibuf = painter->cache.ibuf; + texibuf = painter->cache.texibuf; + maskibuf = painter->cache.maskibuf; + + dotexold = (oldtexibuf != NULL); + + if (painter->cache.flt) { + for (; y < h; y++) { + bf = ibuf->rect_float + (y*ibuf->x + origx)*4; + tf = texibuf->rect_float + (y*texibuf->x + origx)*4; + mf = maskibuf->rect_float + (y*maskibuf->x + origx)*4; + + if (dotexold) + otf = oldtexibuf->rect_float + ((y - origy + yt)*oldtexibuf->x + xt)*4; + + for (x=origx; x < w; x++, bf+=4, mf+=4, tf+=4) { + if (dotexold) { + VECCOPY(tf, otf); + tf[3] = otf[3]; + otf += 4; + } + else { + xy[0] = x + xoff; + xy[1] = y + yoff; + + brush_sample_tex(brush, xy, tf); + } + + bf[0] = tf[0]*mf[0]; + bf[1] = tf[1]*mf[1]; + bf[2] = tf[2]*mf[2]; + bf[3] = tf[3]*mf[3]; + } + } + } + else { + for (; y < h; y++) { + b = (char*)ibuf->rect + (y*ibuf->x + origx)*4; + t = (char*)texibuf->rect + (y*texibuf->x + origx)*4; + m = (char*)maskibuf->rect + (y*maskibuf->x + origx)*4; + + if (dotexold) + ot = (char*)oldtexibuf->rect + ((y - origy + yt)*oldtexibuf->x + xt)*4; + + for (x=origx; x < w; x++, b+=4, m+=4, t+=4) { + if (dotexold) { + t[0] = ot[0]; + t[1] = ot[1]; + t[2] = ot[2]; + t[3] = ot[3]; + ot += 4; + } + else { + xy[0] = x + xoff; + xy[1] = y + yoff; + + brush_sample_tex(brush, xy, rgba); + t[0]= FTOCHAR(rgba[0]); + t[1]= FTOCHAR(rgba[1]); + t[2]= FTOCHAR(rgba[2]); + t[3]= FTOCHAR(rgba[3]); + } + + b[0] = t[0]*m[0]/255; + b[1] = t[1]*m[1]/255; + b[2] = t[2]*m[2]/255; + b[3] = t[3]*m[3]/255; + } + } + } +} + +void brush_painter_fixed_tex_partial_update(BrushPainter *painter, float *pos) +{ + Brush *brush= painter->brush; + BrushPainterCache *cache= &painter->cache; + ImBuf *oldtexibuf, *ibuf; + int imbflag, destx, desty, srcx, srcy, w, h, x1, y1, x2, y2; + + imbflag= (cache->flt)? IB_rectfloat: IB_rect; + if (!cache->ibuf) + cache->ibuf= IMB_allocImBuf(brush->size, brush->size, 32, imbflag, 0); + ibuf= cache->ibuf; + + oldtexibuf= cache->texibuf; + cache->texibuf= IMB_allocImBuf(brush->size, brush->size, 32, imbflag, 0); + + if (oldtexibuf) { + srcx= srcy= 0; + destx= (int)painter->lastpaintpos[0] - (int)pos[0]; + desty= (int)painter->lastpaintpos[1] - (int)pos[1]; + w= oldtexibuf->x; + h= oldtexibuf->y; + + IMB_rectclip(cache->texibuf, oldtexibuf, &destx, &desty, &srcx, &srcy, &w, &h); + } + else { + srcx= srcy= 0; + destx= desty= 0; + w= h= 0; + } + + x1= destx; + y1= desty; + x2= destx+w; + y2= desty+h; + + /* blend existing texture in new position */ + if ((x1 < x2) && (y1 < y2)) + brush_painter_do_partial(painter, oldtexibuf, x1, y1, x2, y2, srcx, srcy, pos); + + if (oldtexibuf) + IMB_freeImBuf(oldtexibuf); + + /* sample texture in new areas */ + if ((0 < x1) && (0 < ibuf->y)) + brush_painter_do_partial(painter, NULL, 0, 0, x1, ibuf->y, 0, 0, pos); + if ((x2 < ibuf->x) && (0 < ibuf->y)) + brush_painter_do_partial(painter, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0, pos); + if ((x1 < x2) && (0 < y1)) + brush_painter_do_partial(painter, NULL, x1, 0, x2, y1, 0, 0, pos); + if ((x1 < x2) && (y2 < ibuf->y)) + brush_painter_do_partial(painter, NULL, x1, y2, x2, ibuf->y, 0, 0, pos); +} + +static void brush_painter_refresh_cache(BrushPainter *painter, float *pos) +{ + Brush *brush= painter->brush; + BrushPainterCache *cache= &painter->cache; + MTex *mtex= brush->mtex[brush->texact]; + int size; + short flt; + + if ((brush->size != cache->lastsize) || (brush->alpha != cache->lastalpha) + || (brush->innerradius != cache->lastinnerradius)) { + if (cache->ibuf) { + IMB_freeImBuf(cache->ibuf); + cache->ibuf= NULL; + } + if (cache->maskibuf) { + IMB_freeImBuf(cache->maskibuf); + cache->maskibuf= NULL; + } + + flt= cache->flt; + size= (cache->size)? cache->size: brush->size; + + if (!(mtex && mtex->tex) || (mtex->tex->type==0)) { + brush_imbuf_new(brush, flt, 0, size, &cache->ibuf); + } + else if (brush->flag & BRUSH_FIXED_TEX) { + brush_imbuf_new(brush, flt, 0, size, &cache->maskibuf); + brush_painter_fixed_tex_partial_update(painter, pos); + } + else + brush_imbuf_new(brush, flt, 2, size, &cache->ibuf); + + cache->lastsize= brush->size; + cache->lastalpha= brush->alpha; + cache->lastinnerradius= brush->innerradius; + } + else if ((brush->flag & BRUSH_FIXED_TEX) && mtex && mtex->tex) { + int dx = (int)painter->lastpaintpos[0] - (int)pos[0]; + int dy = (int)painter->lastpaintpos[1] - (int)pos[1]; + + if ((dx != 0) || (dy != 0)) + brush_painter_fixed_tex_partial_update(painter, pos); + } +} + +void brush_painter_break_stroke(BrushPainter *painter) +{ + painter->firsttouch= 1; +} + +static void brush_apply_pressure(BrushPainter *painter, Brush *brush, float pressure) +{ + if (brush->flag & BRUSH_ALPHA_PRESSURE) + brush->alpha = MAX2(0.0, painter->startalpha*pressure); + if (brush->flag & BRUSH_SIZE_PRESSURE) + brush->size = MAX2(1.0, painter->startsize*pressure); + if (brush->flag & BRUSH_RAD_PRESSURE) + brush->innerradius = MAX2(0.0, painter->startinnerradius*pressure); + if (brush->flag & BRUSH_SPACING_PRESSURE) + brush->spacing = MAX2(1.0, painter->startspacing*(1.5f-pressure)); +} + +int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, double time, float pressure, void *user) +{ + Brush *brush= painter->brush; + int totpaintops= 0; + + if (pressure == 0.0f) + pressure = 1.0f; /* zero pressure == not using tablet */ + + if (painter->firsttouch) { + /* paint exactly once on first touch */ + painter->startpaintpos[0]= pos[0]; + painter->startpaintpos[1]= pos[1]; + + brush_apply_pressure(painter, brush, pressure); + if (painter->cache.enabled) + brush_painter_refresh_cache(painter, pos); + totpaintops += func(user, painter->cache.ibuf, pos, pos); + + painter->lasttime= time; + painter->firsttouch= 0; + painter->lastpaintpos[0]= pos[0]; + painter->lastpaintpos[1]= pos[1]; + } +#if 0 + else if (painter->brush->flag & BRUSH_AIRBRUSH) { + float spacing, step, paintpos[2], dmousepos[2], len; + double starttime, curtime= time; + + /* compute brush spacing adapted to brush size */ + spacing= brush->rate; //brush->size*brush->spacing*0.01f; + + /* setup starting time, direction vector and accumulated time */ + starttime= painter->accumtime; + Vec2Subf(dmousepos, pos, painter->lastmousepos); + len= Normalize2(dmousepos); + painter->accumtime += curtime - painter->lasttime; + + /* do paint op over unpainted time distance */ + while (painter->accumtime >= spacing) { + step= (spacing - starttime)*len; + paintpos[0]= painter->lastmousepos[0] + dmousepos[0]*step; + paintpos[1]= painter->lastmousepos[1] + dmousepos[1]*step; + + if (painter->cache.enabled) + brush_painter_refresh_cache(painter); + totpaintops += func(user, painter->cache.ibuf, + painter->lastpaintpos, paintpos); + + painter->lastpaintpos[0]= paintpos[0]; + painter->lastpaintpos[1]= paintpos[1]; + painter->accumtime -= spacing; + starttime -= spacing; + } + + painter->lasttime= curtime; + } +#endif + else { + float startdistance, spacing, step, paintpos[2], dmousepos[2]; + float t, len, press; + + /* compute brush spacing adapted to brush size, spacing may depend + on pressure, so update it */ + brush_apply_pressure(painter, brush, painter->lastpressure); + spacing= MAX2(1.0f, brush->size)*brush->spacing*0.01f; + + /* setup starting distance, direction vector and accumulated distance */ + startdistance= painter->accumdistance; + Vec2Subf(dmousepos, pos, painter->lastmousepos); + len= Normalize2(dmousepos); + painter->accumdistance += len; + + /* do paint op over unpainted distance */ + while ((len > 0.0f) && (painter->accumdistance >= spacing)) { + step= spacing - startdistance; + paintpos[0]= painter->lastmousepos[0] + dmousepos[0]*step; + paintpos[1]= painter->lastmousepos[1] + dmousepos[1]*step; + + t = step/len; + press= (1.0f-t)*painter->lastpressure + t*pressure; + brush_apply_pressure(painter, brush, press); + spacing= MAX2(1.0f, brush->size)*brush->spacing*0.01f; + + if (painter->cache.enabled) + brush_painter_refresh_cache(painter, paintpos); + + totpaintops += + func(user, painter->cache.ibuf, painter->lastpaintpos, paintpos); + + painter->lastpaintpos[0]= paintpos[0]; + painter->lastpaintpos[1]= paintpos[1]; + painter->accumdistance -= spacing; + startdistance -= spacing; + } + + /* do airbrush paint ops, based on the number of paint ops left over + from regular painting. this is a temporary solution until we have + accurate time stamps for mouse move events */ + if (brush->flag & BRUSH_AIRBRUSH) { + double curtime= time; + double painttime= brush->rate*totpaintops; + + painter->accumtime += curtime - painter->lasttime; + if (painter->accumtime <= painttime) + painter->accumtime= 0.0; + else + painter->accumtime -= painttime; + + while (painter->accumtime >= brush->rate) { + brush_apply_pressure(painter, brush, pressure); + if (painter->cache.enabled) + brush_painter_refresh_cache(painter, paintpos); + totpaintops += + func(user, painter->cache.ibuf, painter->lastmousepos, pos); + painter->accumtime -= brush->rate; + } + + painter->lasttime= curtime; + } + } + + painter->lastmousepos[0]= pos[0]; + painter->lastmousepos[1]= pos[1]; + painter->lastpressure= pressure; + + brush->alpha = painter->startalpha; + brush->size = painter->startsize; + brush->innerradius = painter->startinnerradius; + brush->spacing = painter->startspacing; + + return totpaintops; +} + + diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c new file mode 100644 index 00000000000..2d5f5f091c3 --- /dev/null +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -0,0 +1,1130 @@ +/* +* $Id$ +* +* ***** BEGIN GPL LICENSE BLOCK ***** +* +* 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. +* +* The Original Code is Copyright (C) 2006 Blender Foundation. +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): Ben Batt +* +* ***** END GPL LICENSE BLOCK ***** +* +* Implementation of CDDerivedMesh. +* +* BKE_cdderivedmesh.h contains the function prototypes for this file. +* +*/ + +/* TODO maybe BIF_gl.h should include string.h? */ +#include +#include "BIF_gl.h" + +#include "BKE_cdderivedmesh.h" +#include "BKE_customdata.h" +#include "BKE_DerivedMesh.h" +#include "BKE_displist.h" +#include "BKE_global.h" +#include "BKE_mesh.h" +#include "BKE_utildefines.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" +#include "BLI_edgehash.h" +#include "BLI_editVert.h" +#include "BLI_ghash.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "MEM_guardedalloc.h" + +#include +#include + +typedef struct { + DerivedMesh dm; + + /* these point to data in the DerivedMesh custom data layers, + they are only here for efficiency and convenience **/ + MVert *mvert; + MEdge *medge; + MFace *mface; +} CDDerivedMesh; + +/**************** DerivedMesh interface functions ****************/ +static int cdDM_getNumVerts(DerivedMesh *dm) +{ + return dm->numVertData; +} + +static int cdDM_getNumEdges(DerivedMesh *dm) +{ + return dm->numEdgeData; +} + +static int cdDM_getNumFaces(DerivedMesh *dm) +{ + return dm->numFaceData; +} + +static void cdDM_getVert(DerivedMesh *dm, int index, MVert *vert_r) +{ + CDDerivedMesh *cddm = (CDDerivedMesh *)dm; + *vert_r = cddm->mvert[index]; +} + +static void cdDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r) +{ + CDDerivedMesh *cddm = (CDDerivedMesh *)dm; + *edge_r = cddm->medge[index]; +} + +static void cdDM_getFace(DerivedMesh *dm, int index, MFace *face_r) +{ + CDDerivedMesh *cddm = (CDDerivedMesh *)dm; + *face_r = cddm->mface[index]; +} + +static void cdDM_copyVertArray(DerivedMesh *dm, MVert *vert_r) +{ + CDDerivedMesh *cddm = (CDDerivedMesh *)dm; + memcpy(vert_r, cddm->mvert, sizeof(*vert_r) * dm->numVertData); +} + +static void cdDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r) +{ + CDDerivedMesh *cddm = (CDDerivedMesh *)dm; + memcpy(edge_r, cddm->medge, sizeof(*edge_r) * dm->numEdgeData); +} + +void cdDM_copyFaceArray(DerivedMesh *dm, MFace *face_r) +{ + CDDerivedMesh *cddm = (CDDerivedMesh *)dm; + memcpy(face_r, cddm->mface, sizeof(*face_r) * dm->numFaceData); +} + +static void cdDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3]) +{ + CDDerivedMesh *cddm = (CDDerivedMesh*) dm; + int i; + + if (dm->numVertData) { + for (i=0; inumVertData; i++) { + DO_MINMAX(cddm->mvert[i].co, min_r, max_r); + } + } else { + min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0; + } +} + +static void cdDM_getVertCo(DerivedMesh *dm, int index, float co_r[3]) +{ + CDDerivedMesh *cddm = (CDDerivedMesh*) dm; + + VECCOPY(co_r, cddm->mvert[index].co); +} + +static void cdDM_getVertCos(DerivedMesh *dm, float (*cos_r)[3]) +{ + MVert *mv = CDDM_get_verts(dm); + int i; + + for(i = 0; i < dm->numVertData; i++, mv++) + VECCOPY(cos_r[i], mv->co); +} + +static void cdDM_getVertNo(DerivedMesh *dm, int index, float no_r[3]) +{ + CDDerivedMesh *cddm = (CDDerivedMesh*) dm; + short *no = cddm->mvert[index].no; + + no_r[0] = no[0]/32767.f; + no_r[1] = no[1]/32767.f; + no_r[2] = no[2]/32767.f; +} + +static void cdDM_drawVerts(DerivedMesh *dm) +{ + CDDerivedMesh *cddm = (CDDerivedMesh*) dm; + MVert *mv = cddm->mvert; + int i; + + glBegin(GL_POINTS); + for(i = 0; i < dm->numVertData; i++, mv++) + glVertex3fv(mv->co); + glEnd(); +} + +static void cdDM_drawUVEdges(DerivedMesh *dm) +{ + CDDerivedMesh *cddm = (CDDerivedMesh*) dm; + MFace *mf = cddm->mface; + MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE); + int i; + + if(mf) { + glBegin(GL_LINES); + for(i = 0; i < dm->numFaceData; i++, mf++, tf++) { + if(!(mf->flag&ME_HIDE)) { + glVertex2fv(tf->uv[0]); + glVertex2fv(tf->uv[1]); + + glVertex2fv(tf->uv[1]); + glVertex2fv(tf->uv[2]); + + if(!mf->v4) { + glVertex2fv(tf->uv[2]); + glVertex2fv(tf->uv[0]); + } else { + glVertex2fv(tf->uv[2]); + glVertex2fv(tf->uv[3]); + + glVertex2fv(tf->uv[3]); + glVertex2fv(tf->uv[0]); + } + } + } + glEnd(); + } +} + +static void cdDM_drawEdges(DerivedMesh *dm, int drawLooseEdges) +{ + CDDerivedMesh *cddm = (CDDerivedMesh*) dm; + MVert *mvert = cddm->mvert; + MEdge *medge = cddm->medge; + int i; + + glBegin(GL_LINES); + for(i = 0; i < dm->numEdgeData; i++, medge++) { + if((medge->flag&ME_EDGEDRAW) + && (drawLooseEdges || !(medge->flag&ME_LOOSEEDGE))) { + glVertex3fv(mvert[medge->v1].co); + glVertex3fv(mvert[medge->v2].co); + } + } + glEnd(); +} + +static void cdDM_drawLooseEdges(DerivedMesh *dm) +{ + CDDerivedMesh *cddm = (CDDerivedMesh*) dm; + MVert *mvert = cddm->mvert; + MEdge *medge = cddm->medge; + int i; + + glBegin(GL_LINES); + for(i = 0; i < dm->numEdgeData; i++, medge++) { + if(medge->flag&ME_LOOSEEDGE) { + glVertex3fv(mvert[medge->v1].co); + glVertex3fv(mvert[medge->v2].co); + } + } + glEnd(); +} + +static void cdDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int)) +{ + CDDerivedMesh *cddm = (CDDerivedMesh*) dm; + MVert *mvert = cddm->mvert; + MFace *mface = cddm->mface; + float *nors= dm->getFaceDataArray(dm, CD_NORMAL); + int a, glmode = -1, shademodel = -1, matnr = -1, drawCurrentMat = 1; + +#define PASSVERT(index) { \ + if(shademodel == GL_SMOOTH) { \ + short *no = mvert[index].no; \ + glNormal3sv(no); \ + } \ + glVertex3fv(mvert[index].co); \ +} + + glBegin(glmode = GL_QUADS); + for(a = 0; a < dm->numFaceData; a++, mface++) { + int new_glmode, new_matnr, new_shademodel; + + new_glmode = mface->v4?GL_QUADS:GL_TRIANGLES; + new_matnr = mface->mat_nr + 1; + new_shademodel = (mface->flag & ME_SMOOTH)?GL_SMOOTH:GL_FLAT; + + if(new_glmode != glmode || new_matnr != matnr + || new_shademodel != shademodel) { + glEnd(); + + drawCurrentMat = setMaterial(matnr = new_matnr); + + glShadeModel(shademodel = new_shademodel); + glBegin(glmode = new_glmode); + } + + if(drawCurrentMat) { + if(shademodel == GL_FLAT) { + if (nors) { + glNormal3fv(nors); + } + else { + /* TODO make this better (cache facenormals as layer?) */ + float nor[3]; + if(mface->v4) { + CalcNormFloat4(mvert[mface->v1].co, mvert[mface->v2].co, + mvert[mface->v3].co, mvert[mface->v4].co, + nor); + } else { + CalcNormFloat(mvert[mface->v1].co, mvert[mface->v2].co, + mvert[mface->v3].co, nor); + } + glNormal3fv(nor); + } + } + + PASSVERT(mface->v1); + PASSVERT(mface->v2); + PASSVERT(mface->v3); + if(mface->v4) { + PASSVERT(mface->v4); + } + } + + if(nors) nors += 3; + } + glEnd(); + + glShadeModel(GL_FLAT); +#undef PASSVERT +} + +static void cdDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned char *col1, unsigned char *col2) +{ + CDDerivedMesh *cddm = (CDDerivedMesh*) dm; + int a, glmode; + unsigned char *cp1, *cp2; + MVert *mvert = cddm->mvert; + MFace *mface = cddm->mface; + + cp1 = col1; + if(col2) { + cp2 = col2; + } else { + cp2 = NULL; + useTwoSided = 0; + } + + /* there's a conflict here... twosided colors versus culling...? */ + /* defined by history, only texture faces have culling option */ + /* we need that as mesh option builtin, next to double sided lighting */ + if(col1 && col2) + glEnable(GL_CULL_FACE); + + glShadeModel(GL_SMOOTH); + glBegin(glmode = GL_QUADS); + for(a = 0; a < dm->numFaceData; a++, mface++, cp1 += 16) { + int new_glmode = mface->v4?GL_QUADS:GL_TRIANGLES; + + if(new_glmode != glmode) { + glEnd(); + glBegin(glmode = new_glmode); + } + + glColor3ub(cp1[0], cp1[1], cp1[2]); + glVertex3fv(mvert[mface->v1].co); + glColor3ub(cp1[4], cp1[5], cp1[6]); + glVertex3fv(mvert[mface->v2].co); + glColor3ub(cp1[8], cp1[9], cp1[10]); + glVertex3fv(mvert[mface->v3].co); + if(mface->v4) { + glColor3ub(cp1[12], cp1[13], cp1[14]); + glVertex3fv(mvert[mface->v4].co); + } + + if(useTwoSided) { + glColor3ub(cp2[8], cp2[9], cp2[10]); + glVertex3fv(mvert[mface->v3].co ); + glColor3ub(cp2[4], cp2[5], cp2[6]); + glVertex3fv(mvert[mface->v2].co ); + glColor3ub(cp2[0], cp2[1], cp2[2]); + glVertex3fv(mvert[mface->v1].co ); + if(mface->v4) { + glColor3ub(cp2[12], cp2[13], cp2[14]); + glVertex3fv(mvert[mface->v4].co ); + } + } + if(col2) cp2 += 16; + } + glEnd(); + + glShadeModel(GL_FLAT); + glDisable(GL_CULL_FACE); +} + +static void cdDM_drawFacesTex_common(DerivedMesh *dm, + int (*drawParams)(MTFace *tface, MCol *mcol, int matnr), + int (*drawParamsMapped)(void *userData, int index), + void *userData) +{ + CDDerivedMesh *cddm = (CDDerivedMesh*) dm; + MVert *mv = cddm->mvert; + MFace *mf = cddm->mface; + MCol *mcol = dm->getFaceDataArray(dm, CD_MCOL); + float *nors= dm->getFaceDataArray(dm, CD_NORMAL); + MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE); + int i, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX); + + for(i = 0; i < dm->numFaceData; i++, mf++) { + MVert *mvert; + int flag; + unsigned char *cp = NULL; + + if(drawParams) { + flag = drawParams(tf? &tf[i]: NULL, mcol? &mcol[i*4]: NULL, mf->mat_nr); + } + else { + if(index) { + orig = *index++; + if(orig == ORIGINDEX_NONE) { if(nors) nors += 3; continue; } + if(drawParamsMapped) flag = drawParamsMapped(userData, orig); + else { if(nors) nors += 3; continue; } + } + else + if(drawParamsMapped) flag = drawParamsMapped(userData, i); + else { if(nors) nors += 3; continue; } + } + + if(flag != 0) { /* if the flag is 0 it means the face is hidden or invisible */ + if (flag==1 && mcol) + cp= (unsigned char*) &mcol[i*4]; + + if(!(mf->flag&ME_SMOOTH)) { + if (nors) { + glNormal3fv(nors); + } + else { + /* TODO make this better (cache facenormals as layer?) */ + float nor[3]; + if(mf->v4) { + CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co, + mv[mf->v3].co, mv[mf->v4].co, + nor); + } else { + CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co, + mv[mf->v3].co, nor); + } + glNormal3fv(nor); + } + } + + glBegin(mf->v4?GL_QUADS:GL_TRIANGLES); + if(tf) glTexCoord2fv(tf[i].uv[0]); + if(cp) glColor3ub(cp[3], cp[2], cp[1]); + mvert = &mv[mf->v1]; + if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no); + glVertex3fv(mvert->co); + + if(tf) glTexCoord2fv(tf[i].uv[1]); + if(cp) glColor3ub(cp[7], cp[6], cp[5]); + mvert = &mv[mf->v2]; + if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no); + glVertex3fv(mvert->co); + + if(tf) glTexCoord2fv(tf[i].uv[2]); + if(cp) glColor3ub(cp[11], cp[10], cp[9]); + mvert = &mv[mf->v3]; + if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no); + glVertex3fv(mvert->co); + + if(mf->v4) { + if(tf) glTexCoord2fv(tf[i].uv[3]); + if(cp) glColor3ub(cp[15], cp[14], cp[13]); + mvert = &mv[mf->v4]; + if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no); + glVertex3fv(mvert->co); + } + glEnd(); + } + + if(nors) nors += 3; + } +} + +static void cdDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr)) +{ + cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL); +} + +static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors) +{ + CDDerivedMesh *cddm = (CDDerivedMesh*) dm; + MVert *mv = cddm->mvert; + MFace *mf = cddm->mface; + MCol *mc = DM_get_face_data_layer(dm, CD_MCOL); + float *nors= dm->getFaceDataArray(dm, CD_NORMAL); + int i, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX); + + for(i = 0; i < dm->numFaceData; i++, mf++) { + int drawSmooth = (mf->flag & ME_SMOOTH); + + if(index) { + orig = *index++; + if(setDrawOptions && orig == ORIGINDEX_NONE) + { if(nors) nors += 3; continue; } + } + else + orig = i; + + if(!setDrawOptions || setDrawOptions(userData, orig, &drawSmooth)) { + unsigned char *cp = NULL; + + if(useColors && mc) + cp = (unsigned char *)&mc[i * 4]; + + glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT); + glBegin(mf->v4?GL_QUADS:GL_TRIANGLES); + + if (!drawSmooth) { + if (nors) { + glNormal3fv(nors); + } + else { + /* TODO make this better (cache facenormals as layer?) */ + float nor[3]; + if(mf->v4) { + CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co, + mv[mf->v3].co, mv[mf->v4].co, + nor); + } else { + CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co, + mv[mf->v3].co, nor); + } + glNormal3fv(nor); + } + + if(cp) glColor3ub(cp[3], cp[2], cp[1]); + glVertex3fv(mv[mf->v1].co); + if(cp) glColor3ub(cp[7], cp[6], cp[5]); + glVertex3fv(mv[mf->v2].co); + if(cp) glColor3ub(cp[11], cp[10], cp[9]); + glVertex3fv(mv[mf->v3].co); + if(mf->v4) { + if(cp) glColor3ub(cp[15], cp[14], cp[13]); + glVertex3fv(mv[mf->v4].co); + } + } else { + if(cp) glColor3ub(cp[3], cp[2], cp[1]); + glNormal3sv(mv[mf->v1].no); + glVertex3fv(mv[mf->v1].co); + if(cp) glColor3ub(cp[7], cp[6], cp[5]); + glNormal3sv(mv[mf->v2].no); + glVertex3fv(mv[mf->v2].co); + if(cp) glColor3ub(cp[11], cp[10], cp[9]); + glNormal3sv(mv[mf->v3].no); + glVertex3fv(mv[mf->v3].co); + if(mf->v4) { + if(cp) glColor3ub(cp[15], cp[14], cp[13]); + glNormal3sv(mv[mf->v4].no); + glVertex3fv(mv[mf->v4].co); + } + } + + glEnd(); + } + + if (nors) nors += 3; + } +} + +static void cdDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) +{ + cdDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData); +} + +static void cdDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) +{ + CDDerivedMesh *cddm = (CDDerivedMesh*) dm; + MVert *vert = cddm->mvert; + MEdge *edge = cddm->medge; + int i, orig, *index = DM_get_edge_data_layer(dm, CD_ORIGINDEX); + + glBegin(GL_LINES); + for(i = 0; i < dm->numEdgeData; i++, edge++) { + if(index) { + orig = *index++; + if(setDrawOptions && orig == ORIGINDEX_NONE) continue; + } + else + orig = i; + + if(!setDrawOptions || setDrawOptions(userData, orig)) { + glVertex3fv(vert[edge->v1].co); + glVertex3fv(vert[edge->v2].co); + } + } + glEnd(); +} + +static void cdDM_foreachMappedVert( + DerivedMesh *dm, + void (*func)(void *userData, int index, float *co, + float *no_f, short *no_s), + void *userData) +{ + MVert *mv = CDDM_get_verts(dm); + int i, orig, *index = DM_get_vert_data_layer(dm, CD_ORIGINDEX); + + for(i = 0; i < dm->numVertData; i++, mv++) { + if(index) { + orig = *index++; + if(orig == ORIGINDEX_NONE) continue; + func(userData, orig, mv->co, NULL, mv->no); + } + else + func(userData, i, mv->co, NULL, mv->no); + } +} + +static void cdDM_foreachMappedEdge( + DerivedMesh *dm, + void (*func)(void *userData, int index, + float *v0co, float *v1co), + void *userData) +{ + CDDerivedMesh *cddm = (CDDerivedMesh*) dm; + MVert *mv = cddm->mvert; + MEdge *med = cddm->medge; + int i, orig, *index = DM_get_edge_data_layer(dm, CD_ORIGINDEX); + + for(i = 0; i < dm->numEdgeData; i++, med++) { + if (index) { + orig = *index++; + if(orig == ORIGINDEX_NONE) continue; + func(userData, orig, mv[med->v1].co, mv[med->v2].co); + } + else + func(userData, i, mv[med->v1].co, mv[med->v2].co); + } +} + +static void cdDM_foreachMappedFaceCenter( + DerivedMesh *dm, + void (*func)(void *userData, int index, + float *cent, float *no), + void *userData) +{ + CDDerivedMesh *cddm = (CDDerivedMesh*)dm; + MVert *mv = cddm->mvert; + MFace *mf = cddm->mface; + int i, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX); + + for(i = 0; i < dm->numFaceData; i++, mf++) { + float cent[3]; + float no[3]; + + if (index) { + orig = *index++; + if(orig == ORIGINDEX_NONE) continue; + } + else + orig = i; + + VECCOPY(cent, mv[mf->v1].co); + VecAddf(cent, cent, mv[mf->v2].co); + VecAddf(cent, cent, mv[mf->v3].co); + + if (mf->v4) { + CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co, + mv[mf->v3].co, mv[mf->v4].co, no); + VecAddf(cent, cent, mv[mf->v4].co); + VecMulf(cent, 0.25f); + } else { + CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co, + mv[mf->v3].co, no); + VecMulf(cent, 0.33333333333f); + } + + func(userData, orig, cent, no); + } +} + +static void cdDM_release(DerivedMesh *dm) +{ + CDDerivedMesh *cddm = (CDDerivedMesh*)dm; + + if (DM_release(dm)) + MEM_freeN(cddm); +} + +/**************** CDDM interface functions ****************/ +static CDDerivedMesh *cdDM_create(const char *desc) +{ + CDDerivedMesh *cddm; + DerivedMesh *dm; + + cddm = MEM_callocN(sizeof(*cddm), desc); + dm = &cddm->dm; + + dm->getMinMax = cdDM_getMinMax; + + dm->getNumVerts = cdDM_getNumVerts; + dm->getNumFaces = cdDM_getNumFaces; + dm->getNumEdges = cdDM_getNumEdges; + + dm->getVert = cdDM_getVert; + dm->getEdge = cdDM_getEdge; + dm->getFace = cdDM_getFace; + dm->copyVertArray = cdDM_copyVertArray; + dm->copyEdgeArray = cdDM_copyEdgeArray; + dm->copyFaceArray = cdDM_copyFaceArray; + dm->getVertData = DM_get_vert_data; + dm->getEdgeData = DM_get_edge_data; + dm->getFaceData = DM_get_face_data; + dm->getVertDataArray = DM_get_vert_data_layer; + dm->getEdgeDataArray = DM_get_edge_data_layer; + dm->getFaceDataArray = DM_get_face_data_layer; + + dm->getVertCos = cdDM_getVertCos; + dm->getVertCo = cdDM_getVertCo; + dm->getVertNo = cdDM_getVertNo; + + dm->drawVerts = cdDM_drawVerts; + + dm->drawUVEdges = cdDM_drawUVEdges; + dm->drawEdges = cdDM_drawEdges; + dm->drawLooseEdges = cdDM_drawLooseEdges; + dm->drawMappedEdges = cdDM_drawMappedEdges; + + dm->drawFacesSolid = cdDM_drawFacesSolid; + dm->drawFacesColored = cdDM_drawFacesColored; + dm->drawFacesTex = cdDM_drawFacesTex; + dm->drawMappedFaces = cdDM_drawMappedFaces; + dm->drawMappedFacesTex = cdDM_drawMappedFacesTex; + + dm->foreachMappedVert = cdDM_foreachMappedVert; + dm->foreachMappedEdge = cdDM_foreachMappedEdge; + dm->foreachMappedFaceCenter = cdDM_foreachMappedFaceCenter; + + dm->release = cdDM_release; + + return cddm; +} + +DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces) +{ + CDDerivedMesh *cddm = cdDM_create("CDDM_new dm"); + DerivedMesh *dm = &cddm->dm; + + DM_init(dm, numVerts, numEdges, numFaces); + + CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts); + CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges); + CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numFaces); + + cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT); + cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE); + cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE); + + return dm; +} + +DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob) +{ + CDDerivedMesh *cddm = cdDM_create("CDDM_from_mesh dm"); + DerivedMesh *dm = &cddm->dm; + int i, *index; + + /* this does a referenced copy, the only new layers being ORIGINDEX */ + + DM_init(dm, mesh->totvert, mesh->totedge, mesh->totface); + + CustomData_merge(&mesh->vdata, &dm->vertData, CD_MASK_MESH, CD_REFERENCE, + mesh->totvert); + CustomData_merge(&mesh->edata, &dm->edgeData, CD_MASK_MESH, CD_REFERENCE, + mesh->totedge); + CustomData_merge(&mesh->fdata, &dm->faceData, CD_MASK_MESH, CD_REFERENCE, + mesh->totface); + + cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT); + cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE); + cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE); + + index = CustomData_get_layer(&dm->vertData, CD_ORIGINDEX); + for(i = 0; i < mesh->totvert; ++i, ++index) + *index = i; + + index = CustomData_get_layer(&dm->edgeData, CD_ORIGINDEX); + for(i = 0; i < mesh->totedge; ++i, ++index) + *index = i; + + index = CustomData_get_layer(&dm->faceData, CD_ORIGINDEX); + for(i = 0; i < mesh->totface; ++i, ++index) + *index = i; + + /* works in conjunction with hack during modifier calc, where active mcol + layer with weight paint colors is temporarily added */ + if ((G.f & G_WEIGHTPAINT) && + (ob && ob==(G.scene->basact?G.scene->basact->object:NULL))) + CustomData_duplicate_referenced_layer(&dm->faceData, CD_MCOL); + + return dm; +} + +DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *me) +{ + DerivedMesh *dm = CDDM_new(BLI_countlist(&em->verts), + BLI_countlist(&em->edges), + BLI_countlist(&em->faces)); + CDDerivedMesh *cddm = (CDDerivedMesh*)dm; + EditVert *eve; + EditEdge *eed; + EditFace *efa; + MVert *mvert = cddm->mvert; + MEdge *medge = cddm->medge; + MFace *mface = cddm->mface; + int i, *index; + + CustomData_merge(&em->vdata, &dm->vertData, CD_MASK_DERIVEDMESH, + CD_CALLOC, dm->numVertData); + /* CustomData_merge(&em->edata, &dm->edgeData, CD_MASK_DERIVEDMESH, + CD_CALLOC, dm->numEdgeData); */ + CustomData_merge(&em->fdata, &dm->faceData, CD_MASK_DERIVEDMESH, + CD_CALLOC, dm->numFaceData); + + /* set eve->hash to vert index */ + for(i = 0, eve = em->verts.first; eve; eve = eve->next, ++i) + eve->tmp.l = i; + + /* Need to be able to mark loose edges */ + for(eed = em->edges.first; eed; eed = eed->next) { + eed->f2 = 0; + } + for(efa = em->faces.first; efa; efa = efa->next) { + efa->e1->f2 = 1; + efa->e2->f2 = 1; + efa->e3->f2 = 1; + if(efa->e4) efa->e4->f2 = 1; + } + + index = dm->getVertDataArray(dm, CD_ORIGINDEX); + for(i = 0, eve = em->verts.first; i < dm->numVertData; + i++, eve = eve->next, index++) { + MVert *mv = &mvert[i]; + + VECCOPY(mv->co, eve->co); + + mv->no[0] = eve->no[0] * 32767.0; + mv->no[1] = eve->no[1] * 32767.0; + mv->no[2] = eve->no[2] * 32767.0; + + mv->mat_nr = 0; + mv->flag = 0; + + *index = i; + + CustomData_from_em_block(&em->vdata, &dm->vertData, eve->data, i); + } + + index = dm->getEdgeDataArray(dm, CD_ORIGINDEX); + for(i = 0, eed = em->edges.first; i < dm->numEdgeData; + i++, eed = eed->next, index++) { + MEdge *med = &medge[i]; + + med->v1 = eed->v1->tmp.l; + med->v2 = eed->v2->tmp.l; + med->crease = (unsigned char) (eed->crease * 255.0f); + med->flag = ME_EDGEDRAW|ME_EDGERENDER; + + if(eed->seam) med->flag |= ME_SEAM; + if(eed->sharp) med->flag |= ME_SHARP; + if(!eed->f2) med->flag |= ME_LOOSEEDGE; + + *index = i; + + /* CustomData_from_em_block(&em->edata, &dm->edgeData, eed->data, i); */ + } + + index = dm->getFaceDataArray(dm, CD_ORIGINDEX); + for(i = 0, efa = em->faces.first; i < dm->numFaceData; + i++, efa = efa->next, index++) { + MFace *mf = &mface[i]; + + mf->v1 = efa->v1->tmp.l; + mf->v2 = efa->v2->tmp.l; + mf->v3 = efa->v3->tmp.l; + mf->v4 = efa->v4 ? efa->v4->tmp.l : 0; + mf->mat_nr = efa->mat_nr; + mf->flag = efa->flag; + + *index = i; + + CustomData_from_em_block(&em->fdata, &dm->faceData, efa->data, i); + test_index_face(mf, &dm->faceData, i, efa->v4?4:3); + } + + return dm; +} + +DerivedMesh *CDDM_copy(DerivedMesh *source) +{ + CDDerivedMesh *cddm = cdDM_create("CDDM_copy cddm"); + DerivedMesh *dm = &cddm->dm; + int numVerts = source->numVertData; + int numEdges = source->numEdgeData; + int numFaces = source->numFaceData; + + /* this initializes dm, and copies all non mvert/medge/mface layers */ + DM_from_template(dm, source, numVerts, numEdges, numFaces); + + CustomData_copy_data(&source->vertData, &dm->vertData, 0, 0, numVerts); + CustomData_copy_data(&source->edgeData, &dm->edgeData, 0, 0, numEdges); + CustomData_copy_data(&source->faceData, &dm->faceData, 0, 0, numFaces); + + /* now add mvert/medge/mface layers */ + cddm->mvert = source->dupVertArray(source); + cddm->medge = source->dupEdgeArray(source); + cddm->mface = source->dupFaceArray(source); + + CustomData_add_layer(&dm->vertData, CD_MVERT, CD_ASSIGN, cddm->mvert, numVerts); + CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_ASSIGN, cddm->medge, numEdges); + CustomData_add_layer(&dm->faceData, CD_MFACE, CD_ASSIGN, cddm->mface, numFaces); + + return dm; +} + +DerivedMesh *CDDM_from_template(DerivedMesh *source, + int numVerts, int numEdges, int numFaces) +{ + CDDerivedMesh *cddm = cdDM_create("CDDM_from_template dest"); + DerivedMesh *dm = &cddm->dm; + + /* this does a copy of all non mvert/medge/mface layers */ + DM_from_template(dm, source, numVerts, numEdges, numFaces); + + /* now add mvert/medge/mface layers */ + CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts); + CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges); + CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numFaces); + + cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT); + cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE); + cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE); + + return dm; +} + +void CDDM_apply_vert_coords(DerivedMesh *dm, float (*vertCoords)[3]) +{ + CDDerivedMesh *cddm = (CDDerivedMesh*)dm; + MVert *vert; + int i; + + /* this will just return the pointer if it wasn't a referenced layer */ + vert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT); + cddm->mvert = vert; + + for(i = 0; i < dm->numVertData; ++i, ++vert) + VECCOPY(vert->co, vertCoords[i]); +} + +void CDDM_apply_vert_normals(DerivedMesh *dm, short (*vertNormals)[3]) +{ + CDDerivedMesh *cddm = (CDDerivedMesh*)dm; + MVert *vert; + int i; + + /* this will just return the pointer if it wasn't a referenced layer */ + vert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT); + cddm->mvert = vert; + + for(i = 0; i < dm->numVertData; ++i, ++vert) + VECCOPY(vert->no, vertNormals[i]); +} + +/* adapted from mesh_calc_normals */ +void CDDM_calc_normals(DerivedMesh *dm) +{ + CDDerivedMesh *cddm = (CDDerivedMesh*)dm; + float (*temp_nors)[3]; + float (*face_nors)[3]; + int i; + int numVerts = dm->numVertData; + int numFaces = dm->numFaceData; + MFace *mf; + MVert *mv; + + if(numVerts == 0) return; + + temp_nors = MEM_callocN(numVerts * sizeof(*temp_nors), + "CDDM_calc_normals temp_nors"); + + /* we don't want to overwrite any referenced layers */ + mv = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT); + cddm->mvert = mv; + + /* make a face normal layer if not present */ + face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL); + if(!face_nors) + face_nors = CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_CALLOC, + NULL, dm->numFaceData); + + /* calculate face normals and add to vertex normals */ + mf = CDDM_get_faces(dm); + for(i = 0; i < numFaces; i++, mf++) { + float *f_no = face_nors[i]; + + if(mf->v4) + CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co, + mv[mf->v3].co, mv[mf->v4].co, f_no); + else + CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co, + mv[mf->v3].co, f_no); + + VecAddf(temp_nors[mf->v1], temp_nors[mf->v1], f_no); + VecAddf(temp_nors[mf->v2], temp_nors[mf->v2], f_no); + VecAddf(temp_nors[mf->v3], temp_nors[mf->v3], f_no); + if(mf->v4) + VecAddf(temp_nors[mf->v4], temp_nors[mf->v4], f_no); + } + + /* normalize vertex normals and assign */ + for(i = 0; i < numVerts; i++, mv++) { + float *no = temp_nors[i]; + + if (Normalize(no) == 0.0) { + VECCOPY(no, mv->co); + Normalize(no); + } + + mv->no[0] = (short)(no[0] * 32767.0); + mv->no[1] = (short)(no[1] * 32767.0); + mv->no[2] = (short)(no[2] * 32767.0); + } + + MEM_freeN(temp_nors); +} + +void CDDM_calc_edges(DerivedMesh *dm) +{ + CDDerivedMesh *cddm = (CDDerivedMesh*)dm; + CustomData edgeData; + EdgeHashIterator *ehi; + MFace *mf = cddm->mface; + MEdge *med; + EdgeHash *eh = BLI_edgehash_new(); + int i, *index, numEdges, maxFaces = dm->numFaceData; + + for (i = 0; i < maxFaces; i++, mf++) { + if (!BLI_edgehash_haskey(eh, mf->v1, mf->v2)) + BLI_edgehash_insert(eh, mf->v1, mf->v2, NULL); + if (!BLI_edgehash_haskey(eh, mf->v2, mf->v3)) + BLI_edgehash_insert(eh, mf->v2, mf->v3, NULL); + + if (mf->v4) { + if (!BLI_edgehash_haskey(eh, mf->v3, mf->v4)) + BLI_edgehash_insert(eh, mf->v3, mf->v4, NULL); + if (!BLI_edgehash_haskey(eh, mf->v4, mf->v1)) + BLI_edgehash_insert(eh, mf->v4, mf->v1, NULL); + } else { + if (!BLI_edgehash_haskey(eh, mf->v3, mf->v1)) + BLI_edgehash_insert(eh, mf->v3, mf->v1, NULL); + } + } + + numEdges = BLI_edgehash_size(eh); + + /* write new edges into a temporary CustomData */ + memset(&edgeData, 0, sizeof(edgeData)); + CustomData_add_layer(&edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges); + CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges); + + ehi = BLI_edgehashIterator_new(eh); + med = CustomData_get_layer(&edgeData, CD_MEDGE); + index = CustomData_get_layer(&edgeData, CD_ORIGINDEX); + for(i = 0; !BLI_edgehashIterator_isDone(ehi); + BLI_edgehashIterator_step(ehi), ++i, ++med, ++index) { + BLI_edgehashIterator_getKey(ehi, (int*)&med->v1, (int*)&med->v2); + + med->flag = ME_EDGEDRAW|ME_EDGERENDER; + *index = ORIGINDEX_NONE; + } + BLI_edgehashIterator_free(ehi); + + /* free old CustomData and assign new one */ + CustomData_free(&dm->edgeData, dm->numVertData); + dm->edgeData = edgeData; + dm->numEdgeData = numEdges; + + cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE); + + BLI_edgehash_free(eh, NULL); +} + +void CDDM_lower_num_verts(DerivedMesh *dm, int numVerts) +{ + if (numVerts < dm->numVertData) + CustomData_free_elem(&dm->vertData, numVerts, dm->numVertData-numVerts); + + dm->numVertData = numVerts; +} + +void CDDM_lower_num_edges(DerivedMesh *dm, int numEdges) +{ + if (numEdges < dm->numEdgeData) + CustomData_free_elem(&dm->edgeData, numEdges, dm->numEdgeData-numEdges); + + dm->numEdgeData = numEdges; +} + +void CDDM_lower_num_faces(DerivedMesh *dm, int numFaces) +{ + if (numFaces < dm->numFaceData) + CustomData_free_elem(&dm->faceData, numFaces, dm->numFaceData-numFaces); + + dm->numFaceData = numFaces; +} + +MVert *CDDM_get_vert(DerivedMesh *dm, int index) +{ + return &((CDDerivedMesh*)dm)->mvert[index]; +} + +MEdge *CDDM_get_edge(DerivedMesh *dm, int index) +{ + return &((CDDerivedMesh*)dm)->medge[index]; +} + +MFace *CDDM_get_face(DerivedMesh *dm, int index) +{ + return &((CDDerivedMesh*)dm)->mface[index]; +} + +MVert *CDDM_get_verts(DerivedMesh *dm) +{ + return ((CDDerivedMesh*)dm)->mvert; +} + +MEdge *CDDM_get_edges(DerivedMesh *dm) +{ + return ((CDDerivedMesh*)dm)->medge; +} + +MFace *CDDM_get_faces(DerivedMesh *dm) +{ + return ((CDDerivedMesh*)dm)->mface; +} + diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c new file mode 100644 index 00000000000..83b014cdd63 --- /dev/null +++ b/source/blender/blenkernel/intern/colortools.c @@ -0,0 +1,719 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_color_types.h" +#include "DNA_curve_types.h" +#include "DNA_image_types.h" +#include "DNA_texture_types.h" + +#include "BKE_colortools.h" +#include "BKE_curve.h" +#include "BKE_global.h" +#include "BKE_ipo.h" +#include "BKE_image.h" +#include "BKE_main.h" +#include "BKE_utildefines.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_threads.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +/* ********************************* color curve ********************* */ + +/* ***************** operations on full struct ************* */ + +CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, float maxy) +{ + CurveMapping *cumap; + int a; + float clipminx, clipminy, clipmaxx, clipmaxy; + + cumap= MEM_callocN(sizeof(CurveMapping), "new curvemap"); + cumap->flag= CUMA_DO_CLIP; + if(tot==4) cumap->cur= 3; /* rhms, hack for 'col' curve? */ + + clipminx = MIN2(minx, maxx); + clipminy = MIN2(miny, maxy); + clipmaxx = MAX2(minx, maxx); + clipmaxy = MAX2(miny, maxy); + + BLI_init_rctf(&cumap->curr, clipminx, clipmaxx, clipminy, clipmaxy); + cumap->clipr= cumap->curr; + + cumap->white[0]= cumap->white[1]= cumap->white[2]= 1.0f; + cumap->bwmul[0]= cumap->bwmul[1]= cumap->bwmul[2]= 1.0f; + + for(a=0; acm[a].flag= CUMA_EXTEND_EXTRAPOLATE; + cumap->cm[a].totpoint= 2; + cumap->cm[a].curve= MEM_callocN(2*sizeof(CurveMapPoint), "curve points"); + + cumap->cm[a].curve[0].x= minx; + cumap->cm[a].curve[0].y= miny; + cumap->cm[a].curve[1].x= maxx; + cumap->cm[a].curve[1].y= maxy; + } + return cumap; +} + +void curvemapping_free(CurveMapping *cumap) +{ + int a; + + if(cumap) { + for(a=0; acm[a].curve) MEM_freeN(cumap->cm[a].curve); + if(cumap->cm[a].table) MEM_freeN(cumap->cm[a].table); + } + MEM_freeN(cumap); + } +} + +CurveMapping *curvemapping_copy(CurveMapping *cumap) +{ + int a; + + if(cumap) { + CurveMapping *cumapn= MEM_dupallocN(cumap); + for(a=0; acm[a].curve) + cumapn->cm[a].curve= MEM_dupallocN(cumap->cm[a].curve); + if(cumap->cm[a].table) + cumapn->cm[a].table= MEM_dupallocN(cumap->cm[a].table); + } + return cumapn; + } + return NULL; +} + +void curvemapping_set_black_white(CurveMapping *cumap, float *black, float *white) +{ + int a; + + if(white) + VECCOPY(cumap->white, white); + if(black) + VECCOPY(cumap->black, black); + + for(a=0; a<3; a++) { + if(cumap->white[a]==cumap->black[a]) + cumap->bwmul[a]= 0.0f; + else + cumap->bwmul[a]= 1.0f/(cumap->white[a] - cumap->black[a]); + } +} + +/* ***************** operations on single curve ************* */ +/* ********** NOTE: requires curvemapping_changed() call after ******** */ + +/* removes with flag set */ +void curvemap_remove(CurveMap *cuma, int flag) +{ + CurveMapPoint *cmp= MEM_mallocN((cuma->totpoint)*sizeof(CurveMapPoint), "curve points"); + int a, b, removed=0; + + /* well, lets keep the two outer points! */ + cmp[0]= cuma->curve[0]; + for(a=1, b=1; atotpoint-1; a++) { + if(!(cuma->curve[a].flag & flag)) { + cmp[b]= cuma->curve[a]; + b++; + } + else removed++; + } + cmp[b]= cuma->curve[a]; + + MEM_freeN(cuma->curve); + cuma->curve= cmp; + cuma->totpoint -= removed; +} + +void curvemap_insert(CurveMap *cuma, float x, float y) +{ + CurveMapPoint *cmp= MEM_callocN((cuma->totpoint+1)*sizeof(CurveMapPoint), "curve points"); + int a; + + memcpy(cmp, cuma->curve, (cuma->totpoint)*sizeof(CurveMapPoint)); + MEM_freeN(cuma->curve); + cuma->curve= cmp; + + cuma->curve[cuma->totpoint].x= x; + cuma->curve[cuma->totpoint].y= y; + cuma->curve[cuma->totpoint].flag = CUMA_SELECT; + for(a=0; atotpoint; a++, cmp++) + cmp->flag= 0; + cuma->totpoint++; +} + +void curvemap_reset(CurveMap *cuma, rctf *clipr) +{ + cuma->totpoint= 2; + + cuma->curve[0].x= clipr->xmin; + cuma->curve[0].y= clipr->ymin; + cuma->curve[0].flag= 0; + cuma->curve[1].x= clipr->xmax; + cuma->curve[1].y= clipr->ymax; + cuma->curve[1].flag= 0; + + if(cuma->table) { + MEM_freeN(cuma->table); + cuma->table= NULL; + } +} + +/* if type==1: vector, else auto */ +void curvemap_sethandle(CurveMap *cuma, int type) +{ + int a; + + for(a=0; atotpoint; a++) { + if(cuma->curve[a].flag & CUMA_SELECT) { + if(type) cuma->curve[a].flag |= CUMA_VECTOR; + else cuma->curve[a].flag &= ~CUMA_VECTOR; + } + } +} + +/* *********************** Making the tables and display ************** */ + +/* reduced copy of garbled calchandleNurb() code in curve.c */ +static void calchandle_curvemap(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode) +{ + float *p1,*p2,*p3,pt[3]; + float dx1,dy1, dx,dy, vx,vy, len,len1,len2; + + if(bezt->h1==0 && bezt->h2==0) return; + + p2= bezt->vec[1]; + + if(prev==NULL) { + p3= next->vec[1]; + pt[0]= 2*p2[0]- p3[0]; + pt[1]= 2*p2[1]- p3[1]; + p1= pt; + } + else p1= prev->vec[1]; + + if(next==NULL) { + p1= prev->vec[1]; + pt[0]= 2*p2[0]- p1[0]; + pt[1]= 2*p2[1]- p1[1]; + p3= pt; + } + else p3= next->vec[1]; + + dx= p2[0]- p1[0]; + dy= p2[1]- p1[1]; + + len1= (float)sqrt(dx*dx+dy*dy); + + dx1= p3[0]- p2[0]; + dy1= p3[1]- p2[1]; + + len2= (float)sqrt(dx1*dx1+dy1*dy1); + + if(len1==0.0f) len1=1.0f; + if(len2==0.0f) len2=1.0f; + + if(bezt->h1==HD_AUTO || bezt->h2==HD_AUTO) { /* auto */ + vx= dx1/len2 + dx/len1; + vy= dy1/len2 + dy/len1; + + len= 2.5614f*(float)sqrt(vx*vx + vy*vy); + if(len!=0.0f) { + + if(bezt->h1==HD_AUTO) { + len1/=len; + *(p2-3)= *p2-vx*len1; + *(p2-2)= *(p2+1)-vy*len1; + } + if(bezt->h2==HD_AUTO) { + len2/=len; + *(p2+3)= *p2+vx*len2; + *(p2+4)= *(p2+1)+vy*len2; + } + } + } + + if(bezt->h1==HD_VECT) { /* vector */ + dx/=3.0; + dy/=3.0; + *(p2-3)= *p2-dx; + *(p2-2)= *(p2+1)-dy; + } + if(bezt->h2==HD_VECT) { + dx1/=3.0; + dy1/=3.0; + *(p2+3)= *p2+dx1; + *(p2+4)= *(p2+1)+dy1; + } +} + +/* in X, out Y. + X is presumed to be outside first or last */ +static float curvemap_calc_extend(CurveMap *cuma, float x, float *first, float *last) +{ + if(x <= first[0]) { + if((cuma->flag & CUMA_EXTEND_EXTRAPOLATE)==0) { + /* no extrapolate */ + return first[1]; + } + else { + if(cuma->ext_in[0]==0.0f) + return first[1] + cuma->ext_in[1]*10000.0f; + else + return first[1] + cuma->ext_in[1]*(x - first[0])/cuma->ext_in[0]; + } + } + else if(x >= last[0]) { + if((cuma->flag & CUMA_EXTEND_EXTRAPOLATE)==0) { + /* no extrapolate */ + return last[1]; + } + else { + if(cuma->ext_out[0]==0.0f) + return last[1] - cuma->ext_out[1]*10000.0f; + else + return last[1] + cuma->ext_out[1]*(x - last[0])/cuma->ext_out[0]; + } + } + return 0.0f; +} + +/* only creates a table for a single channel in CurveMapping */ +static void curvemap_make_table(CurveMap *cuma, rctf *clipr) +{ + CurveMapPoint *cmp= cuma->curve; + BezTriple *bezt; + float *fp, *allpoints, *lastpoint, curf, range; + int a, totpoint; + + if(cuma->curve==NULL) return; + + /* default rect also is table range */ + cuma->mintable= clipr->xmin; + cuma->maxtable= clipr->xmax; + + /* hrmf... we now rely on blender ipo beziers, these are more advanced */ + bezt= MEM_callocN(cuma->totpoint*sizeof(BezTriple), "beztarr"); + + for(a=0; atotpoint; a++) { + cuma->mintable= MIN2(cuma->mintable, cmp[a].x); + cuma->maxtable= MAX2(cuma->maxtable, cmp[a].x); + bezt[a].vec[1][0]= cmp[a].x; + bezt[a].vec[1][1]= cmp[a].y; + if(cmp[a].flag & CUMA_VECTOR) + bezt[a].h1= bezt[a].h2= HD_VECT; + else + bezt[a].h1= bezt[a].h2= HD_AUTO; + } + + for(a=0; atotpoint; a++) { + if(a==0) + calchandle_curvemap(bezt, NULL, bezt+1, 0); + else if(a==cuma->totpoint-1) + calchandle_curvemap(bezt+a, bezt+a-1, NULL, 0); + else + calchandle_curvemap(bezt+a, bezt+a-1, bezt+a+1, 0); + } + + /* first and last handle need correction, instead of pointing to center of next/prev, + we let it point to the closest handle */ + if(cuma->totpoint>2) { + float hlen, nlen, vec[3]; + + if(bezt[0].h2==HD_AUTO) { + + hlen= VecLenf(bezt[0].vec[1], bezt[0].vec[2]); /* original handle length */ + /* clip handle point */ + VECCOPY(vec, bezt[1].vec[0]); + if(vec[0] < bezt[0].vec[1][0]) + vec[0]= bezt[0].vec[1][0]; + + VecSubf(vec, vec, bezt[0].vec[1]); + nlen= VecLength(vec); + if(nlen>FLT_EPSILON) { + VecMulf(vec, hlen/nlen); + VecAddf(bezt[0].vec[2], vec, bezt[0].vec[1]); + VecSubf(bezt[0].vec[0], bezt[0].vec[1], vec); + } + } + a= cuma->totpoint-1; + if(bezt[a].h2==HD_AUTO) { + + hlen= VecLenf(bezt[a].vec[1], bezt[a].vec[0]); /* original handle length */ + /* clip handle point */ + VECCOPY(vec, bezt[a-1].vec[2]); + if(vec[0] > bezt[a].vec[1][0]) + vec[0]= bezt[a].vec[1][0]; + + VecSubf(vec, vec, bezt[a].vec[1]); + nlen= VecLength(vec); + if(nlen>FLT_EPSILON) { + VecMulf(vec, hlen/nlen); + VecAddf(bezt[a].vec[0], vec, bezt[a].vec[1]); + VecSubf(bezt[a].vec[2], bezt[a].vec[1], vec); + } + } + } + /* make the bezier curve */ + if(cuma->table) + MEM_freeN(cuma->table); + totpoint= (cuma->totpoint-1)*CM_RESOL; + fp= allpoints= MEM_callocN(totpoint*2*sizeof(float), "table"); + + for(a=0; atotpoint-1; a++, fp += 2*CM_RESOL) { + correct_bezpart(bezt[a].vec[1], bezt[a].vec[2], bezt[a+1].vec[0], bezt[a+1].vec[1]); + forward_diff_bezier(bezt[a].vec[1][0], bezt[a].vec[2][0], bezt[a+1].vec[0][0], bezt[a+1].vec[1][0], fp, CM_RESOL-1, 2); + forward_diff_bezier(bezt[a].vec[1][1], bezt[a].vec[2][1], bezt[a+1].vec[0][1], bezt[a+1].vec[1][1], fp+1, CM_RESOL-1, 2); + } + + /* store first and last handle for extrapolation, unit length */ + cuma->ext_in[0]= bezt[0].vec[0][0] - bezt[0].vec[1][0]; + cuma->ext_in[1]= bezt[0].vec[0][1] - bezt[0].vec[1][1]; + range= sqrt(cuma->ext_in[0]*cuma->ext_in[0] + cuma->ext_in[1]*cuma->ext_in[1]); + cuma->ext_in[0]/= range; + cuma->ext_in[1]/= range; + + a= cuma->totpoint-1; + cuma->ext_out[0]= bezt[a].vec[1][0] - bezt[a].vec[2][0]; + cuma->ext_out[1]= bezt[a].vec[1][1] - bezt[a].vec[2][1]; + range= sqrt(cuma->ext_out[0]*cuma->ext_out[0] + cuma->ext_out[1]*cuma->ext_out[1]); + cuma->ext_out[0]/= range; + cuma->ext_out[1]/= range; + + /* cleanup */ + MEM_freeN(bezt); + + range= CM_TABLEDIV*(cuma->maxtable - cuma->mintable); + cuma->range= 1.0f/range; + + /* now make a table with CM_TABLE equal x distances */ + fp= allpoints; + lastpoint= allpoints + 2*(totpoint-1); + cmp= MEM_callocN((CM_TABLE+1)*sizeof(CurveMapPoint), "dist table"); + + for(a=0; a<=CM_TABLE; a++) { + curf= cuma->mintable + range*(float)a; + cmp[a].x= curf; + + /* get the first x coordinate larger than curf */ + while(curf >= fp[0] && fp!=lastpoint) { + fp+=2; + } + if(fp==allpoints || (curf >= fp[0] && fp==lastpoint)) + cmp[a].y= curvemap_calc_extend(cuma, curf, allpoints, lastpoint); + else { + float fac1= fp[0] - fp[-2]; + float fac2= fp[0] - curf; + if(fac1 > FLT_EPSILON) + fac1= fac2/fac1; + else + fac1= 0.0f; + cmp[a].y= fac1*fp[-1] + (1.0f-fac1)*fp[1]; + } + } + + MEM_freeN(allpoints); + cuma->table= cmp; +} + +/* call when you do images etc, needs restore too. also verifies tables */ +/* it uses a flag to prevent premul or free to happen twice */ +void curvemapping_premultiply(CurveMapping *cumap, int restore) +{ + int a; + + if(restore) { + if(cumap->flag & CUMA_PREMULLED) { + for(a=0; a<3; a++) { + MEM_freeN(cumap->cm[a].table); + cumap->cm[a].table= cumap->cm[a].premultable; + cumap->cm[a].premultable= NULL; + } + + cumap->flag &= ~CUMA_PREMULLED; + } + } + else { + if((cumap->flag & CUMA_PREMULLED)==0) { + /* verify and copy */ + for(a=0; a<3; a++) { + if(cumap->cm[a].table==NULL) + curvemap_make_table(cumap->cm+a, &cumap->clipr); + cumap->cm[a].premultable= cumap->cm[a].table; + cumap->cm[a].table= MEM_mallocN((CM_TABLE+1)*sizeof(CurveMapPoint), "premul table"); + memcpy(cumap->cm[a].table, cumap->cm[a].premultable, (CM_TABLE+1)*sizeof(CurveMapPoint)); + } + + if(cumap->cm[3].table==NULL) + curvemap_make_table(cumap->cm+3, &cumap->clipr); + + /* premul */ + for(a=0; a<3; a++) { + int b; + for(b=0; b<=CM_TABLE; b++) { + cumap->cm[a].table[b].y= curvemap_evaluateF(cumap->cm+3, cumap->cm[a].table[b].y); + } + } + + cumap->flag |= CUMA_PREMULLED; + } + } +} + +static int sort_curvepoints(const void *a1, const void *a2) +{ + const struct CurveMapPoint *x1=a1, *x2=a2; + + if( x1->x > x2->x ) return 1; + else if( x1->x < x2->x) return -1; + return 0; +} + +/* ************************ more CurveMapping calls *************** */ + +/* note; only does current curvemap! */ +void curvemapping_changed(CurveMapping *cumap, int rem_doubles) +{ + CurveMap *cuma= cumap->cm+cumap->cur; + CurveMapPoint *cmp= cuma->curve; + rctf *clipr= &cumap->clipr; + float thresh= 0.01f*(clipr->xmax - clipr->xmin); + float dx= 0.0f, dy= 0.0f; + int a; + + /* clamp with clip */ + if(cumap->flag & CUMA_DO_CLIP) { + for(a=0; atotpoint; a++) { + if(cmp[a].flag & CUMA_SELECT) { + if(cmp[a].x < clipr->xmin) + dx= MIN2(dx, cmp[a].x - clipr->xmin); + else if(cmp[a].x > clipr->xmax) + dx= MAX2(dx, cmp[a].x - clipr->xmax); + if(cmp[a].y < clipr->ymin) + dy= MIN2(dy, cmp[a].y - clipr->ymin); + else if(cmp[a].y > clipr->ymax) + dy= MAX2(dy, cmp[a].y - clipr->ymax); + } + } + for(a=0; atotpoint; a++) { + if(cmp[a].flag & CUMA_SELECT) { + cmp[a].x -= dx; + cmp[a].y -= dy; + } + } + } + + + qsort(cmp, cuma->totpoint, sizeof(CurveMapPoint), sort_curvepoints); + + /* remove doubles, threshold set on 1% of default range */ + if(rem_doubles && cuma->totpoint>2) { + for(a=0; atotpoint-1; a++) { + dx= cmp[a].x - cmp[a+1].x; + dy= cmp[a].y - cmp[a+1].y; + if( sqrt(dx*dx + dy*dy) < thresh ) { + if(a==0) { + cmp[a+1].flag|= 2; + if(cmp[a+1].flag & CUMA_SELECT) + cmp[a].flag |= CUMA_SELECT; + } + else { + cmp[a].flag|= 2; + if(cmp[a].flag & CUMA_SELECT) + cmp[a+1].flag |= CUMA_SELECT; + } + break; /* we assume 1 deletion per edit is ok */ + } + } + if(a != cuma->totpoint-1) + curvemap_remove(cuma, 2); + } + curvemap_make_table(cuma, clipr); +} + +/* table should be verified */ +float curvemap_evaluateF(CurveMap *cuma, float value) +{ + float fi; + int i; + + /* index in table */ + fi= (value-cuma->mintable)*cuma->range; + i= (int)fi; + + if(fi<0.0f || fi>cuma->range) + return curvemap_calc_extend(cuma, value, &cuma->table[0].x, &cuma->table[CM_TABLE].x); + else { + if(i<0) return cuma->table[0].y; + if(i>=CM_TABLE) return cuma->table[CM_TABLE].y; + + fi= fi-(float)i; + return (1.0f-fi)*cuma->table[i].y + (fi)*cuma->table[i+1].y; + } +} + +/* works with curve 'cur' */ +float curvemapping_evaluateF(CurveMapping *cumap, int cur, float value) +{ + CurveMap *cuma= cumap->cm+cur; + + /* allocate or bail out */ + if(cuma->table==NULL) { + curvemap_make_table(cuma, &cumap->clipr); + if(cuma->table==NULL) + return value; + } + return curvemap_evaluateF(cuma, value); +} + +/* vector case */ +void curvemapping_evaluate3F(CurveMapping *cumap, float *vecout, const float *vecin) +{ + vecout[0]= curvemapping_evaluateF(cumap, 0, vecin[0]); + vecout[1]= curvemapping_evaluateF(cumap, 1, vecin[1]); + vecout[2]= curvemapping_evaluateF(cumap, 2, vecin[2]); +} + +/* RGB case, no black/white points, no premult */ +void curvemapping_evaluateRGBF(CurveMapping *cumap, float *vecout, const float *vecin) +{ + vecout[0]= curvemapping_evaluateF(cumap, 0, curvemapping_evaluateF(cumap, 3, vecin[0])); + vecout[1]= curvemapping_evaluateF(cumap, 1, curvemapping_evaluateF(cumap, 3, vecin[1])); + vecout[2]= curvemapping_evaluateF(cumap, 2, curvemapping_evaluateF(cumap, 3, vecin[2])); +} + + +/* RGB with black/white points and premult. tables are checked */ +void curvemapping_evaluate_premulRGBF(CurveMapping *cumap, float *vecout, const float *vecin) +{ + float fac; + + fac= (vecin[0] - cumap->black[0])*cumap->bwmul[0]; + vecout[0]= curvemap_evaluateF(cumap->cm, fac); + + fac= (vecin[1] - cumap->black[1])*cumap->bwmul[1]; + vecout[1]= curvemap_evaluateF(cumap->cm+1, fac); + + fac= (vecin[2] - cumap->black[2])*cumap->bwmul[2]; + vecout[2]= curvemap_evaluateF(cumap->cm+2, fac); +} + +#define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.0f*val)) + +void curvemapping_do_ibuf(CurveMapping *cumap, ImBuf *ibuf) +{ + int pixel; + + if(ibuf==NULL) + return; + if(ibuf->rect_float==NULL) + IMB_float_from_rect(ibuf); + else if(ibuf->rect==NULL) + imb_addrectImBuf(ibuf); + + curvemapping_premultiply(cumap, 0); + + if(ibuf->rect_float && ibuf->rect) { + float *pixf= ibuf->rect_float; + float col[3]; + int stride= 4; + char *pixc= (char *)ibuf->rect; + + if(ibuf->channels) + stride= ibuf->channels; + + for(pixel= ibuf->x*ibuf->y; pixel>0; pixel--, pixf+=stride, pixc+=4) { + if(stride<3) { + col[0]= curvemap_evaluateF(cumap->cm, *pixf); + pixc[1]= pixc[2]= pixc[3]= pixc[0]= FTOCHAR(col[0]); + } + else { + curvemapping_evaluate_premulRGBF(cumap, col, pixf); + pixc[0]= FTOCHAR(col[0]); + pixc[1]= FTOCHAR(col[1]); + pixc[2]= FTOCHAR(col[2]); + if(stride>3) + pixc[3]= FTOCHAR(pixf[3]); + else + pixc[3]= 255; + } + } + } + + curvemapping_premultiply(cumap, 1); +} + +int curvemapping_RGBA_does_something(CurveMapping *cumap) +{ + int a; + + if(cumap->black[0]!=0.0f) return 1; + if(cumap->black[1]!=0.0f) return 1; + if(cumap->black[2]!=0.0f) return 1; + if(cumap->white[0]!=1.0f) return 1; + if(cumap->white[1]!=1.0f) return 1; + if(cumap->white[2]!=1.0f) return 1; + + for(a=0; acm[a].curve) { + if(cumap->cm[a].totpoint!=2) return 1; + + if(cumap->cm[a].curve[0].x != 0.0f) return 1; + if(cumap->cm[a].curve[0].y != 0.0f) return 1; + if(cumap->cm[a].curve[1].x != 1.0f) return 1; + if(cumap->cm[a].curve[1].y != 1.0f) return 1; + } + } + return 0; +} + +void curvemapping_initialize(CurveMapping *cumap) +{ + int a; + + if(cumap==NULL) return; + + for(a=0; acm[a].table==NULL) + curvemap_make_table(cumap->cm+a, &cumap->clipr); + } +} diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c new file mode 100644 index 00000000000..f50cb2c6be0 --- /dev/null +++ b/source/blender/blenkernel/intern/constraint.c @@ -0,0 +1,3422 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): 2007, Joshua Leung, major recode + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include +#include + +#include "MEM_guardedalloc.h" +#include "nla.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "DNA_armature_types.h" +#include "DNA_constraint_types.h" +#include "DNA_object_types.h" +#include "DNA_action_types.h" +#include "DNA_curve_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_lattice_types.h" +#include "DNA_scene_types.h" +#include "DNA_text_types.h" + +#include "BKE_utildefines.h" +#include "BKE_action.h" +#include "BKE_anim.h" /* for the curve calculation part */ +#include "BKE_armature.h" +#include "BKE_blender.h" +#include "BKE_constraint.h" +#include "BKE_displist.h" +#include "BKE_deform.h" +#include "BKE_DerivedMesh.h" /* for geometry targets */ +#include "BKE_cdderivedmesh.h" /* for geometry targets */ +#include "BKE_object.h" +#include "BKE_ipo.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_idprop.h" + + +#include "BPY_extern.h" + +#include "blendef.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + + +/* ******************* Constraint Channels ********************** */ +/* Constraint Channels exist in one of two places: + * - Under Action Channels in an Action (act->chanbase->achan->constraintChannels) + * - Under Object without object-level action yet (ob->constraintChannels) + * + * The main purpose that constraint channels serve is to act as a link + * between an IPO-block which + */ + +/* ------------ Data Management ----------- */ + +/* Free constraint channels, and reduce the number of users of the related ipo-blocks */ +void free_constraint_channels (ListBase *chanbase) +{ + bConstraintChannel *chan; + + for (chan=chanbase->first; chan; chan=chan->next) { + if (chan->ipo) { + chan->ipo->id.us--; + } + } + + BLI_freelistN(chanbase); +} + +/* Make a copy of the constraint channels from dst to src, and also give the + * new constraint channels their own copy of the original's IPO. + */ +void copy_constraint_channels (ListBase *dst, ListBase *src) +{ + bConstraintChannel *dchan, *schan; + + dst->first = dst->last = NULL; + duplicatelist(dst, src); + + for (dchan=dst->first, schan=src->first; dchan; dchan=dchan->next, schan=schan->next) { + dchan->ipo = copy_ipo(schan->ipo); + } +} + +/* Make a copy of the constraint channels from dst to src, but make the + * new constraint channels use the same IPO-data as their twin. + */ +void clone_constraint_channels (ListBase *dst, ListBase *src) +{ + bConstraintChannel *dchan, *schan; + + dst->first = dst->last = NULL; + duplicatelist(dst, src); + + for (dchan=dst->first, schan=src->first; dchan; dchan=dchan->next, schan=schan->next) { + id_us_plus((ID *)dchan->ipo); + } +} + +/* ------------- Constraint Channel Tools ------------ */ + +/* Find the constraint channel with a given name */ +bConstraintChannel *get_constraint_channel (ListBase *list, const char name[]) +{ + bConstraintChannel *chan; + + for (chan = list->first; chan; chan=chan->next) { + if (!strcmp(name, chan->name)) { + return chan; + } + } + + return NULL; +} + +/* Find or create a new constraint channel */ +bConstraintChannel *verify_constraint_channel (ListBase *list, const char name[]) +{ + bConstraintChannel *chan; + + chan= get_constraint_channel(list, name); + + if (chan == NULL) { + chan= MEM_callocN(sizeof(bConstraintChannel), "new constraint channel"); + BLI_addtail(list, chan); + strcpy(chan->name, name); + } + + return chan; +} + +/* --------- Constraint Channel Evaluation/Execution --------- */ + +/* IPO-system call: calculate IPO-block for constraint channels, and flush that + * info onto the corresponding constraint. + */ +void do_constraint_channels (ListBase *conbase, ListBase *chanbase, float ctime, short onlydrivers) +{ + bConstraint *con; + bConstraintChannel *chan; + IpoCurve *icu= NULL; + + /* for each Constraint, calculate its Influence from the corresponding ConstraintChannel */ + for (con=conbase->first; con; con=con->next) { + chan = get_constraint_channel(chanbase, con->name); + + if (chan && chan->ipo) { + calc_ipo(chan->ipo, ctime); + + for (icu=chan->ipo->curve.first; icu; icu=icu->next) { + if (!onlydrivers || icu->driver) { + switch (icu->adrcode) { + case CO_ENFORCE: + { + /* Influence is clamped to 0.0f -> 1.0f range */ + con->enforce = CLAMPIS(icu->curval, 0.0f, 1.0f); + } + break; + } + } + } + } + } +} + +/* ************************ Constraints - General Utilities *************************** */ +/* These functions here don't act on any specific constraints, and are therefore should/will + * not require any of the special function-pointers afforded by the relevant constraint + * type-info structs. + */ + +/* -------------- Naming -------------- */ + +/* Find the first available, non-duplicate name for a given constraint */ +void unique_constraint_name (bConstraint *con, ListBase *list) +{ + bConstraint *curcon; + char tempname[64]; + int number = 1, exists = 0; + char *dot; + + /* See if we are given an empty string */ + if (con->name[0] == '\0') { + /* give it default name first */ + strcpy(con->name, "Const"); + } + + /* See if we even need to do this */ + for (curcon = list->first; curcon; curcon=curcon->next) { + if (curcon != con) { + if (!strcmp(curcon->name, con->name)) { + exists = 1; + break; + } + } + } + + if (exists == 0) + return; + + /* Strip off the suffix */ + dot = strchr(con->name, '.'); + if (dot) + *dot=0; + + for (number = 1; number <= 999; number++) { + sprintf(tempname, "%s.%03d", con->name, number); + + exists = 0; + for (curcon=list->first; curcon; curcon=curcon->next) { + if (con != curcon) { + if (strcmp(curcon->name, tempname)==0) { + exists = 1; + break; + } + } + } + if (exists == 0) { + strcpy(con->name, tempname); + return; + } + } +} + +/* ----------------- Evaluation Loop Preparation --------------- */ + +/* package an object/bone for use in constraint evaluation */ +/* This function MEM_calloc's a bConstraintOb struct, that will need to be freed after evaluation */ +bConstraintOb *constraints_make_evalob (Object *ob, void *subdata, short datatype) +{ + bConstraintOb *cob; + + /* create regardless of whether we have any data! */ + cob= MEM_callocN(sizeof(bConstraintOb), "bConstraintOb"); + + /* based on type of available data */ + switch (datatype) { + case CONSTRAINT_OBTYPE_OBJECT: + { + /* disregard subdata... calloc should set other values right */ + if (ob) { + cob->ob = ob; + cob->type = datatype; + Mat4CpyMat4(cob->matrix, ob->obmat); + } + else + Mat4One(cob->matrix); + + Mat4CpyMat4(cob->startmat, cob->matrix); + } + break; + case CONSTRAINT_OBTYPE_BONE: + { + /* only set if we have valid bone, otherwise default */ + if (ob && subdata) { + cob->ob = ob; + cob->pchan = (bPoseChannel *)subdata; + cob->type = datatype; + + /* matrix in world-space */ + Mat4MulMat4(cob->matrix, cob->pchan->pose_mat, ob->obmat); + } + else + Mat4One(cob->matrix); + + Mat4CpyMat4(cob->startmat, cob->matrix); + } + break; + + default: /* other types not yet handled */ + Mat4One(cob->matrix); + Mat4One(cob->startmat); + break; + } + + return cob; +} + +/* cleanup after constraint evaluation */ +void constraints_clear_evalob (bConstraintOb *cob) +{ + float delta[4][4], imat[4][4]; + + /* prevent crashes */ + if (cob == NULL) + return; + + /* calculate delta of constraints evaluation */ + Mat4Invert(imat, cob->startmat); + Mat4MulMat4(delta, cob->matrix, imat); + + /* copy matrices back to source */ + switch (cob->type) { + case CONSTRAINT_OBTYPE_OBJECT: + { + /* cob->ob might not exist! */ + if (cob->ob) { + /* copy new ob-matrix back to owner */ + Mat4CpyMat4(cob->ob->obmat, cob->matrix); + + /* copy inverse of delta back to owner */ + Mat4Invert(cob->ob->constinv, delta); + } + } + break; + case CONSTRAINT_OBTYPE_BONE: + { + /* cob->ob or cob->pchan might not exist */ + if (cob->ob && cob->pchan) { + /* copy new pose-matrix back to owner */ + Mat4MulMat4(cob->pchan->pose_mat, cob->matrix, cob->ob->imat); + + /* copy inverse of delta back to owner */ + Mat4Invert(cob->pchan->constinv, delta); + } + } + break; + } + + /* free tempolary struct */ + MEM_freeN(cob); +} + +/* -------------- Space-Conversion API -------------- */ + +/* This function is responsible for the correct transformations/conversions + * of a matrix from one space to another for constraint evaluation. + * For now, this is only implemented for Objects and PoseChannels. + */ +void constraint_mat_convertspace (Object *ob, bPoseChannel *pchan, float mat[][4], short from, short to) +{ + float tempmat[4][4]; + float diff_mat[4][4]; + float imat[4][4]; + + /* prevent crashes in these unlikely events */ + if (ob==NULL || mat==NULL) return; + /* optimise trick - check if need to do anything */ + if (from == to) return; + + /* are we dealing with pose-channels or objects */ + if (pchan) { + /* pose channels */ + switch (from) { + case CONSTRAINT_SPACE_WORLD: /* ---------- FROM WORLDSPACE ---------- */ + { + /* world to pose */ + if (to==CONSTRAINT_SPACE_POSE || to==CONSTRAINT_SPACE_LOCAL || to==CONSTRAINT_SPACE_PARLOCAL) { + Mat4Invert(imat, ob->obmat); + Mat4CpyMat4(tempmat, mat); + Mat4MulMat4(mat, tempmat, imat); + } + + /* pose to local */ + if (to == CONSTRAINT_SPACE_LOCAL) { + /* call self with slightly different values */ + constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to); + } + /* pose to local + parent */ + else if (to == CONSTRAINT_SPACE_PARLOCAL) { + /* call self with slightly different values */ + constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to); + } + } + break; + case CONSTRAINT_SPACE_POSE: /* ---------- FROM POSESPACE ---------- */ + { + /* pose to world */ + if (to == CONSTRAINT_SPACE_WORLD) { + Mat4CpyMat4(tempmat, mat); + Mat4MulMat4(mat, tempmat, ob->obmat); + } + /* pose to local */ + else if (to == CONSTRAINT_SPACE_LOCAL) { + if (pchan->bone) { + if (pchan->parent) { + float offs_bone[4][4]; + + /* construct offs_bone the same way it is done in armature.c */ + Mat4CpyMat3(offs_bone, pchan->bone->bone_mat); + VECCOPY(offs_bone[3], pchan->bone->head); + offs_bone[3][1]+= pchan->bone->parent->length; + + if (pchan->bone->flag & BONE_HINGE) { + /* pose_mat = par_pose-space_location * chan_mat */ + float tmat[4][4]; + + /* the rotation of the parent restposition */ + Mat4CpyMat4(tmat, pchan->bone->parent->arm_mat); + + /* the location of actual parent transform */ + VECCOPY(tmat[3], offs_bone[3]); + offs_bone[3][0]= offs_bone[3][1]= offs_bone[3][2]= 0.0f; + Mat4MulVecfl(pchan->parent->pose_mat, tmat[3]); + + Mat4MulMat4(diff_mat, offs_bone, tmat); + Mat4Invert(imat, diff_mat); + } + else { + /* pose_mat = par_pose_mat * bone_mat * chan_mat */ + Mat4MulMat4(diff_mat, offs_bone, pchan->parent->pose_mat); + Mat4Invert(imat, diff_mat); + } + } + else { + /* pose_mat = chan_mat * arm_mat */ + Mat4Invert(imat, pchan->bone->arm_mat); + } + + Mat4CpyMat4(tempmat, mat); + Mat4MulMat4(mat, tempmat, imat); + } + } + /* pose to local with parent */ + else if (to == CONSTRAINT_SPACE_PARLOCAL) { + if (pchan->bone) { + Mat4Invert(imat, pchan->bone->arm_mat); + Mat4CpyMat4(tempmat, mat); + Mat4MulMat4(mat, tempmat, imat); + } + } + } + break; + case CONSTRAINT_SPACE_LOCAL: /* ------------ FROM LOCALSPACE --------- */ + { + /* local to pose */ + if (to==CONSTRAINT_SPACE_POSE || to==CONSTRAINT_SPACE_WORLD) { + /* do inverse procedure that was done for pose to local */ + if (pchan->bone) { + /* we need the posespace_matrix = local_matrix + (parent_posespace_matrix + restpos) */ + if (pchan->parent) { + float offs_bone[4][4]; + + /* construct offs_bone the same way it is done in armature.c */ + Mat4CpyMat3(offs_bone, pchan->bone->bone_mat); + VECCOPY(offs_bone[3], pchan->bone->head); + offs_bone[3][1]+= pchan->bone->parent->length; + + if (pchan->bone->flag & BONE_HINGE) { + /* pose_mat = par_pose-space_location * chan_mat */ + float tmat[4][4]; + + /* the rotation of the parent restposition */ + Mat4CpyMat4(tmat, pchan->bone->parent->arm_mat); + + /* the location of actual parent transform */ + VECCOPY(tmat[3], offs_bone[3]); + offs_bone[3][0]= offs_bone[3][1]= offs_bone[3][2]= 0.0f; + Mat4MulVecfl(pchan->parent->pose_mat, tmat[3]); + + Mat4MulMat4(diff_mat, offs_bone, tmat); + Mat4CpyMat4(tempmat, mat); + Mat4MulMat4(mat, tempmat, diff_mat); + } + else { + /* pose_mat = par_pose_mat * bone_mat * chan_mat */ + Mat4MulMat4(diff_mat, offs_bone, pchan->parent->pose_mat); + Mat4CpyMat4(tempmat, mat); + Mat4MulMat4(mat, tempmat, diff_mat); + } + } + else { + Mat4CpyMat4(diff_mat, pchan->bone->arm_mat); + + Mat4CpyMat4(tempmat, mat); + Mat4MulMat4(mat, tempmat, diff_mat); + } + } + } + /* local to world */ + if (to == CONSTRAINT_SPACE_WORLD) { + /* call self with slightly different values */ + constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to); + } + } + break; + case CONSTRAINT_SPACE_PARLOCAL: /* -------------- FROM LOCAL WITH PARENT ---------- */ + { + /* local to pose */ + if (to==CONSTRAINT_SPACE_POSE || to==CONSTRAINT_SPACE_WORLD) { + if (pchan->bone) { + Mat4CpyMat4(diff_mat, pchan->bone->arm_mat); + Mat4CpyMat4(tempmat, mat); + Mat4MulMat4(mat, diff_mat, tempmat); + } + } + /* local to world */ + if (to == CONSTRAINT_SPACE_WORLD) { + /* call self with slightly different values */ + constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to); + } + } + break; + } + } + else { + /* objects */ + if (from==CONSTRAINT_SPACE_WORLD && to==CONSTRAINT_SPACE_LOCAL) { + /* check if object has a parent - otherwise this won't work */ + if (ob->parent) { + /* 'subtract' parent's effects from owner */ + Mat4MulMat4(diff_mat, ob->parentinv, ob->parent->obmat); + Mat4Invert(imat, diff_mat); + Mat4CpyMat4(tempmat, mat); + Mat4MulMat4(mat, tempmat, imat); + } + } + else if (from==CONSTRAINT_SPACE_LOCAL && to==CONSTRAINT_SPACE_WORLD) { + /* check that object has a parent - otherwise this won't work */ + if (ob->parent) { + /* 'add' parent's effect back to owner */ + Mat4CpyMat4(tempmat, mat); + Mat4MulMat4(diff_mat, ob->parentinv, ob->parent->obmat); + Mat4MulMat4(mat, tempmat, diff_mat); + } + } + } +} + +/* ------------ General Target Matrix Tools ---------- */ + +/* function that sets the given matrix based on given vertex group in mesh */ +static void contarget_get_mesh_mat (Object *ob, char *substring, float mat[][4]) +{ + DerivedMesh *dm; + float vec[3] = {0.0f, 0.0f, 0.0f}, tvec[3]; + float normal[3] = {0.0f, 0.0f, 0.0f}, plane[3]; + float imat[3][3], tmat[3][3]; + int dgroup; + + /* initialize target matrix using target matrix */ + Mat4CpyMat4(mat, ob->obmat); + + /* get index of vertex group */ + dgroup = get_named_vertexgroup_num(ob, substring); + if (dgroup < 0) return; + + /* get DerivedMesh */ + if (G.obedit && G.editMesh) { + /* we are in editmode, so get a special derived mesh */ + dm = CDDM_from_editmesh(G.editMesh, ob->data); + } + else { + /* when not in EditMode, this should exist */ + dm = (DerivedMesh *)ob->derivedFinal; + } + + /* only continue if there's a valid DerivedMesh */ + if (dm) { + MDeformVert *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); + int *index = (int *)dm->getVertDataArray(dm, CD_ORIGINDEX); + int numVerts = dm->getNumVerts(dm); + int i, j, count = 0; + float co[3], nor[3]; + + /* check that dvert and index are valid pointers (just in case) */ + if (dvert && index) { + /* get the average of all verts with that are in the vertex-group */ + for (i = 0; i < numVerts; i++, index++) { + for (j = 0; j < dvert[i].totweight; j++) { + /* does this vertex belong to nominated vertex group? */ + if (dvert[i].dw[j].def_nr == dgroup) { + dm->getVertCo(dm, i, co); + dm->getVertNo(dm, i, nor); + VecAddf(vec, vec, co); + VecAddf(normal, normal, nor); + count++; + break; + } + + } + } + + + /* calculate averages of normal and coordinates */ + if (count > 0) { + VecMulf(vec, 1.0f / count); + VecMulf(normal, 1.0f / count); + } + + + /* derive the rotation from the average normal: + * - code taken from transform_manipulator.c, + * calc_manipulator_stats, V3D_MANIP_NORMAL case + */ + /* we need the transpose of the inverse for a normal... */ + Mat3CpyMat4(imat, ob->obmat); + + Mat3Inv(tmat, imat); + Mat3Transp(tmat); + Mat3MulVecfl(tmat, normal); + + Normalize(normal); + VECCOPY(plane, tmat[1]); + + VECCOPY(tmat[2], normal); + Crossf(tmat[0], normal, plane); + Crossf(tmat[1], tmat[2], tmat[0]); + + Mat4CpyMat3(mat, tmat); + Mat4Ortho(mat); + + + /* apply the average coordinate as the new location */ + VecMat4MulVecfl(tvec, ob->obmat, vec); + VECCOPY(mat[3], tvec); + } + } + + /* free temporary DerivedMesh created (in EditMode case) */ + if (G.editMesh) { + if (dm) dm->release(dm); + } +} + +/* function that sets the given matrix based on given vertex group in lattice */ +static void contarget_get_lattice_mat (Object *ob, char *substring, float mat[][4]) +{ + Lattice *lt= (Lattice *)ob->data; + + DispList *dl = find_displist(&ob->disp, DL_VERTS); + float *co = dl?dl->verts:NULL; + BPoint *bp = lt->def; + + MDeformVert *dvert = lt->dvert; + int tot_verts= lt->pntsu*lt->pntsv*lt->pntsw; + float vec[3]= {0.0f, 0.0f, 0.0f}, tvec[3]; + int dgroup=0, grouped=0; + int i, n; + + /* initialize target matrix using target matrix */ + Mat4CpyMat4(mat, ob->obmat); + + /* get index of vertex group */ + dgroup = get_named_vertexgroup_num(ob, substring); + if (dgroup < 0) return; + if (dvert == NULL) return; + + /* 1. Loop through control-points checking if in nominated vertex-group. + * 2. If it is, add it to vec to find the average point. + */ + for (i=0; i < tot_verts; i++, dvert++) { + for (n= 0; n < dvert->totweight; n++) { + /* found match - vert is in vgroup */ + if (dvert->dw[n].def_nr == dgroup) { + /* copy coordinates of point to temporary vector, then add to find average */ + if (co) + memcpy(tvec, co, 3*sizeof(float)); + else + memcpy(tvec, bp->vec, 3*sizeof(float)); + + VecAddf(vec, vec, tvec); + grouped++; + + break; + } + } + + /* advance pointer to coordinate data */ + if (co) co+= 3; + else bp++; + } + + /* find average location, then multiply by ob->obmat to find world-space location */ + if (grouped) + VecMulf(vec, 1.0f / grouped); + VecMat4MulVecfl(tvec, ob->obmat, vec); + + /* copy new location to matrix */ + VECCOPY(mat[3], tvec); +} + +/* generic function to get the appropriate matrix for most target cases */ +/* The cases where the target can be object data have not been implemented */ +static void constraint_target_to_mat4 (Object *ob, char *substring, float mat[][4], short from, short to) +{ + /* Case OBJECT */ + if (!strlen(substring)) { + Mat4CpyMat4(mat, ob->obmat); + constraint_mat_convertspace(ob, NULL, mat, from, to); + } + /* Case VERTEXGROUP */ + /* Current method just takes the average location of all the points in the + * VertexGroup, and uses that as the location value of the targets. Where + * possible, the orientation will also be calculated, by calculating an + * 'average' vertex normal, and deriving the rotaation from that. + * + * NOTE: EditMode is not currently supported, and will most likely remain that + * way as constraints can only really affect things on object/bone level. + */ + else if (ob->type == OB_MESH) { + contarget_get_mesh_mat(ob, substring, mat); + constraint_mat_convertspace(ob, NULL, mat, from, to); + } + else if (ob->type == OB_LATTICE) { + contarget_get_lattice_mat(ob, substring, mat); + constraint_mat_convertspace(ob, NULL, mat, from, to); + } + /* Case BONE */ + else { + bPoseChannel *pchan; + + pchan = get_pose_channel(ob->pose, substring); + if (pchan) { + /* Multiply the PoseSpace accumulation/final matrix for this + * PoseChannel by the Armature Object's Matrix to get a worldspace + * matrix. + */ + Mat4MulMat4(mat, pchan->pose_mat, ob->obmat); + } + else + Mat4CpyMat4(mat, ob->obmat); + + /* convert matrix space as required */ + constraint_mat_convertspace(ob, pchan, mat, from, to); + } +} + +/* ************************* Specific Constraints ***************************** */ +/* Each constraint defines a set of functions, which will be called at the appropriate + * times. In addition to this, each constraint should have a type-info struct, where + * its functions are attached for use. + */ + +/* Template for type-info data: + * - make a copy of this when creating new constraints, and just change the functions + * pointed to as necessary + * - although the naming of functions doesn't matter, it would help for code + * readability, to follow the same naming convention as is presented here + * - any functions that a constraint doesn't need to define, don't define + * for such cases, just use NULL + * - these should be defined after all the functions have been defined, so that + * forward-definitions/prototypes don't need to be used! + * - keep this copy #if-def'd so that future constraints can get based off this + */ +#if 0 +static bConstraintTypeInfo CTI_CONSTRNAME = { + CONSTRAINT_TYPE_CONSTRNAME, /* type */ + sizeof(bConstrNameConstraint), /* size */ + "ConstrName", /* name */ + "bConstrNameConstraint", /* struct name */ + constrname_free, /* free data */ + constrname_relink, /* relink data */ + constrname_copy, /* copy data */ + constrname_new_data, /* new data */ + constrname_get_tars, /* get constraint targets */ + constrname_flush_tars, /* flush constraint targets */ + constrname_get_tarmat, /* get target matrix */ + constrname_evaluate /* evaluate */ +}; +#endif + +/* This function should be used for the get_target_matrix member of all + * constraints that are not picky about what happens to their target matrix. + */ +static void default_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime) +{ + if (VALID_CONS_TARGET(ct)) + constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space); + else if (ct) + Mat4One(ct->matrix); +} + +/* This following macro should be used for all standard single-target *_get_tars functions + * to save typing and reduce maintainance woes. + * (Hopefully all compilers will be happy with the lines with just a space on them. Those are + * really just to help this code easier to read) + */ +#define SINGLETARGET_GET_TARS(con, datatar, datasubtarget, ct, list) \ + { \ + ct= MEM_callocN(sizeof(bConstraintTarget), "tempConstraintTarget"); \ + \ + ct->tar= datatar; \ + strcpy(ct->subtarget, datasubtarget); \ + ct->space= con->tarspace; \ + ct->flag= CONSTRAINT_TAR_TEMP; \ + \ + if (ct->tar) { \ + if ((ct->tar->type==OB_ARMATURE) && (ct->subtarget[0])) ct->type = CONSTRAINT_OBTYPE_BONE; \ + else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) ct->type = CONSTRAINT_OBTYPE_VERT; \ + else ct->type = CONSTRAINT_OBTYPE_OBJECT; \ + } \ + \ + BLI_addtail(list, ct); \ + } + +/* This following macro should be used for all standard single-target *_get_tars functions + * to save typing and reduce maintainance woes. It does not do the subtarget related operations + * (Hopefully all compilers will be happy with the lines with just a space on them. Those are + * really just to help this code easier to read) + */ +#define SINGLETARGETNS_GET_TARS(con, datatar, ct, list) \ + { \ + ct= MEM_callocN(sizeof(bConstraintTarget), "tempConstraintTarget"); \ + \ + ct->tar= datatar; \ + ct->space= con->tarspace; \ + ct->flag= CONSTRAINT_TAR_TEMP; \ + \ + if (ct->tar) ct->type = CONSTRAINT_OBTYPE_OBJECT; \ + \ + BLI_addtail(list, ct); \ + } + +/* This following macro should be used for all standard single-target *_flush_tars functions + * to save typing and reduce maintainance woes. + * (Hopefully all compilers will be happy with the lines with just a space on them. Those are + * really just to help this code easier to read) + */ +#define SINGLETARGET_FLUSH_TARS(con, datatar, datasubtarget, ct, list, nocopy) \ + { \ + if (ct) { \ + if (nocopy == 0) { \ + datatar= ct->tar; \ + strcpy(datasubtarget, ct->subtarget); \ + con->tarspace= ct->space; \ + } \ + \ + BLI_freelinkN(list, ct); \ + } \ + } + +/* This following macro should be used for all standard single-target *_flush_tars functions + * to save typing and reduce maintainance woes. It does not do the subtarget related operations + * (Hopefully all compilers will be happy with the lines with just a space on them. Those are + * really just to help this code easier to read) + */ +#define SINGLETARGETNS_FLUSH_TARS(con, datatar, ct, list, nocopy) \ + { \ + if (ct) { \ + if (nocopy == 0) { \ + datatar= ct->tar; \ + con->tarspace= ct->space; \ + } \ + \ + BLI_freelinkN(list, ct); \ + } \ + } + +/* --------- ChildOf Constraint ------------ */ + +static void childof_new_data (void *cdata) +{ + bChildOfConstraint *data= (bChildOfConstraint *)cdata; + + data->flag = (CHILDOF_LOCX | CHILDOF_LOCY | CHILDOF_LOCZ | + CHILDOF_ROTX |CHILDOF_ROTY | CHILDOF_ROTZ | + CHILDOF_SIZEX | CHILDOF_SIZEY | CHILDOF_SIZEZ); + Mat4One(data->invmat); +} + +static void childof_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bChildOfConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + } +} + +static void childof_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bChildOfConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy) + } +} + +static void childof_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bChildOfConstraint *data= con->data; + bConstraintTarget *ct= targets->first; + + /* only evaluate if there is a target */ + if (VALID_CONS_TARGET(ct)) { + float parmat[4][4], invmat[4][4], tempmat[4][4]; + float loc[3], eul[3], size[3]; + float loco[3], eulo[3], sizo[3]; + + /* get offset (parent-inverse) matrix */ + Mat4CpyMat4(invmat, data->invmat); + + /* extract components of both matrices */ + VECCOPY(loc, ct->matrix[3]); + Mat4ToEul(ct->matrix, eul); + Mat4ToSize(ct->matrix, size); + + VECCOPY(loco, invmat[3]); + Mat4ToEul(invmat, eulo); + Mat4ToSize(invmat, sizo); + + /* disable channels not enabled */ + if (!(data->flag & CHILDOF_LOCX)) loc[0]= loco[0]= 0.0f; + if (!(data->flag & CHILDOF_LOCY)) loc[1]= loco[1]= 0.0f; + if (!(data->flag & CHILDOF_LOCZ)) loc[2]= loco[2]= 0.0f; + if (!(data->flag & CHILDOF_ROTX)) eul[0]= eulo[0]= 0.0f; + if (!(data->flag & CHILDOF_ROTY)) eul[1]= eulo[1]= 0.0f; + if (!(data->flag & CHILDOF_ROTZ)) eul[2]= eulo[2]= 0.0f; + if (!(data->flag & CHILDOF_SIZEX)) size[0]= sizo[0]= 1.0f; + if (!(data->flag & CHILDOF_SIZEY)) size[1]= sizo[1]= 1.0f; + if (!(data->flag & CHILDOF_SIZEZ)) size[2]= sizo[2]= 1.0f; + + /* make new target mat and offset mat */ + LocEulSizeToMat4(ct->matrix, loc, eul, size); + LocEulSizeToMat4(invmat, loco, eulo, sizo); + + /* multiply target (parent matrix) by offset (parent inverse) to get + * the effect of the parent that will be exherted on the owner + */ + Mat4MulMat4(parmat, invmat, ct->matrix); + + /* now multiply the parent matrix by the owner matrix to get the + * the effect of this constraint (i.e. owner is 'parented' to parent) + */ + Mat4CpyMat4(tempmat, cob->matrix); + Mat4MulMat4(cob->matrix, tempmat, parmat); + } +} + +static bConstraintTypeInfo CTI_CHILDOF = { + CONSTRAINT_TYPE_CHILDOF, /* type */ + sizeof(bChildOfConstraint), /* size */ + "ChildOf", /* name */ + "bChildOfConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + childof_new_data, /* new data */ + childof_get_tars, /* get constraint targets */ + childof_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get a target matrix */ + childof_evaluate /* evaluate */ +}; + +/* -------- TrackTo Constraint ------- */ + +static void trackto_new_data (void *cdata) +{ + bTrackToConstraint *data= (bTrackToConstraint *)cdata; + + data->reserved1 = TRACK_Y; + data->reserved2 = UP_Z; +} + +static void trackto_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bTrackToConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + } +} + +static void trackto_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bTrackToConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy) + } +} + + +static int basis_cross (int n, int m) +{ + switch (n-m) { + case 1: + case -2: + return 1; + + case -1: + case 2: + return -1; + + default: + return 0; + } +} + +static void vectomat (float *vec, float *target_up, short axis, short upflag, short flags, float m[][3]) +{ + float n[3]; + float u[3]; /* vector specifying the up axis */ + float proj[3]; + float right[3]; + float neg = -1; + int right_index; + + VecCopyf(n, vec); + if (Normalize(n) == 0.0) { + n[0] = 0.0; + n[1] = 0.0; + n[2] = 1.0; + } + if (axis > 2) axis -= 3; + else VecMulf(n,-1); + + /* n specifies the transformation of the track axis */ + if (flags & TARGET_Z_UP) { + /* target Z axis is the global up axis */ + u[0] = target_up[0]; + u[1] = target_up[1]; + u[2] = target_up[2]; + } + else { + /* world Z axis is the global up axis */ + u[0] = 0; + u[1] = 0; + u[2] = 1; + } + + /* project the up vector onto the plane specified by n */ + Projf(proj, u, n); /* first u onto n... */ + VecSubf(proj, u, proj); /* then onto the plane */ + /* proj specifies the transformation of the up axis */ + + if (Normalize(proj) == 0.0) { /* degenerate projection */ + proj[0] = 0.0; + proj[1] = 1.0; + proj[2] = 0.0; + } + + /* Normalized cross product of n and proj specifies transformation of the right axis */ + Crossf(right, proj, n); + Normalize(right); + + if (axis != upflag) { + right_index = 3 - axis - upflag; + neg = (float)basis_cross(axis, upflag); + + /* account for up direction, track direction */ + m[right_index][0] = neg * right[0]; + m[right_index][1] = neg * right[1]; + m[right_index][2] = neg * right[2]; + + m[upflag][0] = proj[0]; + m[upflag][1] = proj[1]; + m[upflag][2] = proj[2]; + + m[axis][0] = n[0]; + m[axis][1] = n[1]; + m[axis][2] = n[2]; + } + /* identity matrix - don't do anything if the two axes are the same */ + else { + m[0][0]= m[1][1]= m[2][2]= 1.0; + m[0][1]= m[0][2]= m[0][3]= 0.0; + m[1][0]= m[1][2]= m[1][3]= 0.0; + m[2][0]= m[2][1]= m[2][3]= 0.0; + } +} + + +static void trackto_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bTrackToConstraint *data= con->data; + bConstraintTarget *ct= targets->first; + + if (VALID_CONS_TARGET(ct)) { + float size[3], vec[3]; + float totmat[3][3]; + float tmat[4][4]; + + /* Get size property, since ob->size is only the object's own relative size, not its global one */ + Mat4ToSize(cob->matrix, size); + + /* Clear the object's rotation */ + cob->matrix[0][0]=size[0]; + cob->matrix[0][1]=0; + cob->matrix[0][2]=0; + cob->matrix[1][0]=0; + cob->matrix[1][1]=size[1]; + cob->matrix[1][2]=0; + cob->matrix[2][0]=0; + cob->matrix[2][1]=0; + cob->matrix[2][2]=size[2]; + + /* targetmat[2] instead of ownermat[2] is passed to vectomat + * for backwards compatability it seems... (Aligorith) + */ + VecSubf(vec, cob->matrix[3], ct->matrix[3]); + vectomat(vec, ct->matrix[2], + (short)data->reserved1, (short)data->reserved2, + data->flags, totmat); + + Mat4CpyMat4(tmat, cob->matrix); + Mat4MulMat34(cob->matrix, totmat, tmat); + } +} + +static bConstraintTypeInfo CTI_TRACKTO = { + CONSTRAINT_TYPE_TRACKTO, /* type */ + sizeof(bTrackToConstraint), /* size */ + "TrackTo", /* name */ + "bTrackToConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + trackto_new_data, /* new data */ + trackto_get_tars, /* get constraint targets */ + trackto_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get target matrix */ + trackto_evaluate /* evaluate */ +}; + +/* --------- Inverse-Kinemetics --------- */ + +static void kinematic_new_data (void *cdata) +{ + bKinematicConstraint *data= (bKinematicConstraint *)cdata; + + data->weight= (float)1.0; + data->orientweight= (float)1.0; + data->iterations = 500; + data->flag= CONSTRAINT_IK_TIP|CONSTRAINT_IK_STRETCH|CONSTRAINT_IK_POS; +} + +static void kinematic_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bKinematicConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + SINGLETARGET_GET_TARS(con, data->poletar, data->polesubtarget, ct, list) + } +} + +static void kinematic_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bKinematicConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy) + ct= ct->next; + SINGLETARGET_FLUSH_TARS(con, data->poletar, data->polesubtarget, ct, list, nocopy) + } +} + +static void kinematic_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime) +{ + bKinematicConstraint *data= con->data; + + if (VALID_CONS_TARGET(ct)) + constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space); + else if (ct) { + if (data->flag & CONSTRAINT_IK_AUTO) { + Object *ob= cob->ob; + + if (ob == NULL) { + Mat4One(ct->matrix); + } + else { + float vec[3]; + /* move grabtarget into world space */ + VECCOPY(vec, data->grabtarget); + Mat4MulVecfl(ob->obmat, vec); + Mat4CpyMat4(ct->matrix, ob->obmat); + VECCOPY(ct->matrix[3], vec); + } + } + else + Mat4One(ct->matrix); + } +} + +static bConstraintTypeInfo CTI_KINEMATIC = { + CONSTRAINT_TYPE_KINEMATIC, /* type */ + sizeof(bKinematicConstraint), /* size */ + "IK", /* name */ + "bKinematicConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + kinematic_new_data, /* new data */ + kinematic_get_tars, /* get constraint targets */ + kinematic_flush_tars, /* flush constraint targets */ + kinematic_get_tarmat, /* get target matrix */ + NULL /* evaluate - solved as separate loop */ +}; + +/* -------- Follow-Path Constraint ---------- */ + +static void followpath_new_data (void *cdata) +{ + bFollowPathConstraint *data= (bFollowPathConstraint *)cdata; + + data->trackflag = TRACK_Y; + data->upflag = UP_Z; + data->offset = 0; + data->followflag = 0; +} + +static void followpath_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bFollowPathConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints without subtargets */ + SINGLETARGETNS_GET_TARS(con, data->tar, ct, list) + } +} + +static void followpath_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bFollowPathConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, nocopy) + } +} + +static void followpath_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime) +{ + bFollowPathConstraint *data= con->data; + + if (VALID_CONS_TARGET(ct)) { + Curve *cu= ct->tar->data; + float q[4], vec[4], dir[3], *quat, x1; + float totmat[4][4]; + float curvetime; + + Mat4One(totmat); + Mat4One(ct->matrix); + + /* note: when creating constraints that follow path, the curve gets the CU_PATH set now, + * currently for paths to work it needs to go through the bevlist/displist system (ton) + */ + + /* only happens on reload file, but violates depsgraph still... fix! */ + if (cu->path==NULL || cu->path->data==NULL) + makeDispListCurveTypes(ct->tar, 0); + + if (cu->path && cu->path->data) { + curvetime= bsystem_time(ct->tar, (float)ctime, 0.0) - data->offset; + + if (calc_ipo_spec(cu->ipo, CU_SPEED, &curvetime)==0) { + curvetime /= cu->pathlen; + CLAMP(curvetime, 0.0, 1.0); + } + + if ( where_on_path(ct->tar, curvetime, vec, dir) ) { + if (data->followflag) { + quat= vectoquat(dir, (short) data->trackflag, (short) data->upflag); + + Normalize(dir); + q[0]= (float)cos(0.5*vec[3]); + x1= (float)sin(0.5*vec[3]); + q[1]= -x1*dir[0]; + q[2]= -x1*dir[1]; + q[3]= -x1*dir[2]; + QuatMul(quat, q, quat); + + QuatToMat4(quat, totmat); + } + VECCOPY(totmat[3], vec); + + Mat4MulSerie(ct->matrix, ct->tar->obmat, totmat, NULL, NULL, NULL, NULL, NULL, NULL); + } + } + } + else if (ct) + Mat4One(ct->matrix); +} + +static void followpath_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bConstraintTarget *ct= targets->first; + + /* only evaluate if there is a target */ + if (VALID_CONS_TARGET(ct)) { + float obmat[4][4]; + float size[3], obsize[3]; + + /* get Object local transform (loc/rot/size) to determine transformation from path */ + //object_to_mat4(ob, obmat); + Mat4CpyMat4(obmat, cob->matrix); // FIXME!!! + + /* get scaling of object before applying constraint */ + Mat4ToSize(cob->matrix, size); + + /* apply targetmat - containing location on path, and rotation */ + Mat4MulSerie(cob->matrix, ct->matrix, obmat, NULL, NULL, NULL, NULL, NULL, NULL); + + /* un-apply scaling caused by path */ + Mat4ToSize(cob->matrix, obsize); + if (obsize[0]) + VecMulf(cob->matrix[0], size[0] / obsize[0]); + if (obsize[1]) + VecMulf(cob->matrix[1], size[1] / obsize[1]); + if (obsize[2]) + VecMulf(cob->matrix[2], size[2] / obsize[2]); + } +} + +static bConstraintTypeInfo CTI_FOLLOWPATH = { + CONSTRAINT_TYPE_FOLLOWPATH, /* type */ + sizeof(bFollowPathConstraint), /* size */ + "Follow Path", /* name */ + "bFollowPathConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + followpath_new_data, /* new data */ + followpath_get_tars, /* get constraint targets */ + followpath_flush_tars, /* flush constraint targets */ + followpath_get_tarmat, /* get target matrix */ + followpath_evaluate /* evaluate */ +}; + +/* --------- Limit Location --------- */ + + +static void loclimit_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bLocLimitConstraint *data = con->data; + + if (data->flag & LIMIT_XMIN) { + if (cob->matrix[3][0] < data->xmin) + cob->matrix[3][0] = data->xmin; + } + if (data->flag & LIMIT_XMAX) { + if (cob->matrix[3][0] > data->xmax) + cob->matrix[3][0] = data->xmax; + } + if (data->flag & LIMIT_YMIN) { + if (cob->matrix[3][1] < data->ymin) + cob->matrix[3][1] = data->ymin; + } + if (data->flag & LIMIT_YMAX) { + if (cob->matrix[3][1] > data->ymax) + cob->matrix[3][1] = data->ymax; + } + if (data->flag & LIMIT_ZMIN) { + if (cob->matrix[3][2] < data->zmin) + cob->matrix[3][2] = data->zmin; + } + if (data->flag & LIMIT_ZMAX) { + if (cob->matrix[3][2] > data->zmax) + cob->matrix[3][2] = data->zmax; + } +} + +static bConstraintTypeInfo CTI_LOCLIMIT = { + CONSTRAINT_TYPE_LOCLIMIT, /* type */ + sizeof(bLocLimitConstraint), /* size */ + "Limit Location", /* name */ + "bLocLimitConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + NULL, /* new data */ + NULL, /* get constraint targets */ + NULL, /* flush constraint targets */ + NULL, /* get target matrix */ + loclimit_evaluate /* evaluate */ +}; + +/* -------- Limit Rotation --------- */ + +static void rotlimit_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bRotLimitConstraint *data = con->data; + float loc[3]; + float eul[3]; + float size[3]; + + VECCOPY(loc, cob->matrix[3]); + Mat4ToSize(cob->matrix, size); + + Mat4ToEul(cob->matrix, eul); + + /* eulers: radians to degrees! */ + eul[0] = (eul[0] / M_PI * 180); + eul[1] = (eul[1] / M_PI * 180); + eul[2] = (eul[2] / M_PI * 180); + + /* limiting of euler values... */ + if (data->flag & LIMIT_XROT) { + if (eul[0] < data->xmin) + eul[0] = data->xmin; + + if (eul[0] > data->xmax) + eul[0] = data->xmax; + } + if (data->flag & LIMIT_YROT) { + if (eul[1] < data->ymin) + eul[1] = data->ymin; + + if (eul[1] > data->ymax) + eul[1] = data->ymax; + } + if (data->flag & LIMIT_ZROT) { + if (eul[2] < data->zmin) + eul[2] = data->zmin; + + if (eul[2] > data->zmax) + eul[2] = data->zmax; + } + + /* eulers: degrees to radians ! */ + eul[0] = (eul[0] / 180 * M_PI); + eul[1] = (eul[1] / 180 * M_PI); + eul[2] = (eul[2] / 180 * M_PI); + + LocEulSizeToMat4(cob->matrix, loc, eul, size); +} + +static bConstraintTypeInfo CTI_ROTLIMIT = { + CONSTRAINT_TYPE_ROTLIMIT, /* type */ + sizeof(bRotLimitConstraint), /* size */ + "Limit Rotation", /* name */ + "bRotLimitConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + NULL, /* new data */ + NULL, /* get constraint targets */ + NULL, /* flush constraint targets */ + NULL, /* get target matrix */ + rotlimit_evaluate /* evaluate */ +}; + +/* --------- Limit Scaling --------- */ + + +static void sizelimit_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bSizeLimitConstraint *data = con->data; + float obsize[3], size[3]; + + Mat4ToSize(cob->matrix, size); + Mat4ToSize(cob->matrix, obsize); + + if (data->flag & LIMIT_XMIN) { + if (size[0] < data->xmin) + size[0] = data->xmin; + } + if (data->flag & LIMIT_XMAX) { + if (size[0] > data->xmax) + size[0] = data->xmax; + } + if (data->flag & LIMIT_YMIN) { + if (size[1] < data->ymin) + size[1] = data->ymin; + } + if (data->flag & LIMIT_YMAX) { + if (size[1] > data->ymax) + size[1] = data->ymax; + } + if (data->flag & LIMIT_ZMIN) { + if (size[2] < data->zmin) + size[2] = data->zmin; + } + if (data->flag & LIMIT_ZMAX) { + if (size[2] > data->zmax) + size[2] = data->zmax; + } + + if (obsize[0]) + VecMulf(cob->matrix[0], size[0]/obsize[0]); + if (obsize[1]) + VecMulf(cob->matrix[1], size[1]/obsize[1]); + if (obsize[2]) + VecMulf(cob->matrix[2], size[2]/obsize[2]); +} + +static bConstraintTypeInfo CTI_SIZELIMIT = { + CONSTRAINT_TYPE_SIZELIMIT, /* type */ + sizeof(bSizeLimitConstraint), /* size */ + "Limit Scaling", /* name */ + "bSizeLimitConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + NULL, /* new data */ + NULL, /* get constraint targets */ + NULL, /* flush constraint targets */ + NULL, /* get target matrix */ + sizelimit_evaluate /* evaluate */ +}; + +/* ----------- Copy Location ------------- */ + +static void loclike_new_data (void *cdata) +{ + bLocateLikeConstraint *data= (bLocateLikeConstraint *)cdata; + + data->flag = LOCLIKE_X|LOCLIKE_Y|LOCLIKE_Z; +} + +static void loclike_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bLocateLikeConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + } +} + +static void loclike_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bLocateLikeConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy) + } +} + +static void loclike_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime) +{ + bLocateLikeConstraint *data = con->data; + + if (VALID_CONS_TARGET(ct)) { + if (ct->tar->type==OB_ARMATURE && strlen(ct->subtarget)) { + /* Pose-Channels for the CopyLoc target are handled specially, so that + * we can support using the bone-tip as an option. + */ + bPoseChannel *pchan; + float tmat[4][4]; + + pchan = get_pose_channel(ct->tar->pose, ct->subtarget); + if (pchan) { + Mat4CpyMat4(tmat, pchan->pose_mat); + + if (data->flag & LOCLIKE_TIP) { + VECCOPY(tmat[3], pchan->pose_tail); + } + + Mat4MulMat4(ct->matrix, tmat, ct->tar->obmat); + } + else + Mat4CpyMat4(ct->matrix, ct->tar->obmat); + + /* convert matrix space as required */ + constraint_mat_convertspace(ct->tar, pchan, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space); + } + else { + /* get target matrix as is done normally for other constraints */ + constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space); + } + } + else if (ct) + Mat4One(ct->matrix); +} + +static void loclike_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bLocateLikeConstraint *data= con->data; + bConstraintTarget *ct= targets->first; + + if (VALID_CONS_TARGET(ct)) { + float offset[3] = {0.0f, 0.0f, 0.0f}; + + if (data->flag & LOCLIKE_OFFSET) + VECCOPY(offset, cob->matrix[3]); + + if (data->flag & LOCLIKE_X) { + cob->matrix[3][0] = ct->matrix[3][0]; + + if (data->flag & LOCLIKE_X_INVERT) cob->matrix[3][0] *= -1; + cob->matrix[3][0] += offset[0]; + } + if (data->flag & LOCLIKE_Y) { + cob->matrix[3][1] = ct->matrix[3][1]; + + if (data->flag & LOCLIKE_Y_INVERT) cob->matrix[3][1] *= -1; + cob->matrix[3][1] += offset[1]; + } + if (data->flag & LOCLIKE_Z) { + cob->matrix[3][2] = ct->matrix[3][2]; + + if (data->flag & LOCLIKE_Z_INVERT) cob->matrix[3][2] *= -1; + cob->matrix[3][2] += offset[2]; + } + } +} + +static bConstraintTypeInfo CTI_LOCLIKE = { + CONSTRAINT_TYPE_LOCLIKE, /* type */ + sizeof(bLocateLikeConstraint), /* size */ + "Copy Location", /* name */ + "bLocateLikeConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + loclike_new_data, /* new data */ + loclike_get_tars, /* get constraint targets */ + loclike_flush_tars, /* flush constraint targets */ + loclike_get_tarmat, /* get target matrix */ + loclike_evaluate /* evaluate */ +}; + +/* ----------- Copy Rotation ------------- */ + +static void rotlike_new_data (void *cdata) +{ + bRotateLikeConstraint *data= (bRotateLikeConstraint *)cdata; + + data->flag = ROTLIKE_X|ROTLIKE_Y|ROTLIKE_Z; +} + +static void rotlike_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bRotateLikeConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + } +} + +static void rotlike_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bRotateLikeConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy) + } +} + +static void rotlike_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bRotateLikeConstraint *data= con->data; + bConstraintTarget *ct= targets->first; + + if (VALID_CONS_TARGET(ct)) { + float loc[3]; + float eul[3], obeul[3]; + float size[3]; + + VECCOPY(loc, cob->matrix[3]); + Mat4ToSize(cob->matrix, size); + + Mat4ToEul(ct->matrix, eul); + Mat4ToEul(cob->matrix, obeul); + + if ((data->flag & ROTLIKE_X)==0) + eul[0] = obeul[0]; + else { + if (data->flag & ROTLIKE_OFFSET) + euler_rot(eul, obeul[0], 'x'); + + if (data->flag & ROTLIKE_X_INVERT) + eul[0] *= -1; + } + + if ((data->flag & ROTLIKE_Y)==0) + eul[1] = obeul[1]; + else { + if (data->flag & ROTLIKE_OFFSET) + euler_rot(eul, obeul[1], 'y'); + + if (data->flag & ROTLIKE_Y_INVERT) + eul[1] *= -1; + } + + if ((data->flag & ROTLIKE_Z)==0) + eul[2] = obeul[2]; + else { + if (data->flag & ROTLIKE_OFFSET) + euler_rot(eul, obeul[2], 'z'); + + if (data->flag & ROTLIKE_Z_INVERT) + eul[2] *= -1; + } + + compatible_eul(eul, obeul); + LocEulSizeToMat4(cob->matrix, loc, eul, size); + } +} + +static bConstraintTypeInfo CTI_ROTLIKE = { + CONSTRAINT_TYPE_ROTLIKE, /* type */ + sizeof(bRotateLikeConstraint), /* size */ + "Copy Rotation", /* name */ + "bRotateLikeConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + rotlike_new_data, /* new data */ + rotlike_get_tars, /* get constraint targets */ + rotlike_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get target matrix */ + rotlike_evaluate /* evaluate */ +}; + +/* ---------- Copy Scaling ---------- */ + +static void sizelike_new_data (void *cdata) +{ + bSizeLikeConstraint *data= (bSizeLikeConstraint *)cdata; + + data->flag = SIZELIKE_X|SIZELIKE_Y|SIZELIKE_Z; +} + +static void sizelike_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bSizeLikeConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + } +} + +static void sizelike_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bSizeLikeConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy) + } +} + +static void sizelike_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bSizeLikeConstraint *data= con->data; + bConstraintTarget *ct= targets->first; + + if (VALID_CONS_TARGET(ct)) { + float obsize[3], size[3]; + + Mat4ToSize(ct->matrix, size); + Mat4ToSize(cob->matrix, obsize); + + if ((data->flag & SIZELIKE_X) && (obsize[0] != 0)) { + if (data->flag & SIZELIKE_OFFSET) { + size[0] += (obsize[0] - 1.0f); + VecMulf(cob->matrix[0], size[0] / obsize[0]); + } + else + VecMulf(cob->matrix[0], size[0] / obsize[0]); + } + if ((data->flag & SIZELIKE_Y) && (obsize[1] != 0)) { + if (data->flag & SIZELIKE_OFFSET) { + size[1] += (obsize[1] - 1.0f); + VecMulf(cob->matrix[1], size[1] / obsize[1]); + } + else + VecMulf(cob->matrix[1], size[1] / obsize[1]); + } + if ((data->flag & SIZELIKE_Z) && (obsize[2] != 0)) { + if (data->flag & SIZELIKE_OFFSET) { + size[2] += (obsize[2] - 1.0f); + VecMulf(cob->matrix[2], size[2] / obsize[2]); + } + else + VecMulf(cob->matrix[2], size[2] / obsize[2]); + } + } +} + +static bConstraintTypeInfo CTI_SIZELIKE = { + CONSTRAINT_TYPE_SIZELIKE, /* type */ + sizeof(bSizeLikeConstraint), /* size */ + "Copy Scale", /* name */ + "bSizeLikeConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + sizelike_new_data, /* new data */ + sizelike_get_tars, /* get constraint targets */ + sizelike_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get target matrix */ + sizelike_evaluate /* evaluate */ +}; + +/* ----------- Python Constraint -------------- */ + +static void pycon_free (bConstraint *con) +{ + bPythonConstraint *data= con->data; + + /* id-properties */ + IDP_FreeProperty(data->prop); + MEM_freeN(data->prop); + + /* multiple targets */ + BLI_freelistN(&data->targets); +} + +static void pycon_relink (bConstraint *con) +{ + bPythonConstraint *data= con->data; + + ID_NEW(data->text); +} + +static void pycon_copy (bConstraint *con, bConstraint *srccon) +{ + bPythonConstraint *pycon = (bPythonConstraint *)con->data; + bPythonConstraint *opycon = (bPythonConstraint *)srccon->data; + + pycon->prop = IDP_CopyProperty(opycon->prop); + duplicatelist(&pycon->targets, &opycon->targets); +} + +static void pycon_new_data (void *cdata) +{ + bPythonConstraint *data= (bPythonConstraint *)cdata; + + /* everything should be set correctly by calloc, except for the prop->type constant.*/ + data->prop = MEM_callocN(sizeof(IDProperty), "PyConstraintProps"); + data->prop->type = IDP_GROUP; +} + +static void pycon_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bPythonConstraint *data= con->data; + + list->first = data->targets.first; + list->last = data->targets.last; + } +} + +/* Whether this approach is maintained remains to be seen (aligorith) */ +static void pycon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime) +{ + bPythonConstraint *data= con->data; + + if (VALID_CONS_TARGET(ct)) { + /* special exception for curves - depsgraph issues */ + if (ct->tar->type == OB_CURVE) { + Curve *cu= ct->tar->data; + + /* this check is to make sure curve objects get updated on file load correctly.*/ + if (cu->path==NULL || cu->path->data==NULL) /* only happens on reload file, but violates depsgraph still... fix! */ + makeDispListCurveTypes(ct->tar, 0); + } + + /* firstly calculate the matrix the normal way, then let the py-function override + * this matrix if it needs to do so + */ + constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space); + BPY_pyconstraint_target(data, ct); + } + else if (ct) + Mat4One(ct->matrix); +} + +static void pycon_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bPythonConstraint *data= con->data; + +/* currently removed, until I this can be re-implemented for multiple targets */ +#if 0 + /* Firstly, run the 'driver' function which has direct access to the objects involved + * Technically, this is potentially dangerous as users may abuse this and cause dependency-problems, + * but it also allows certain 'clever' rigging hacks to work. + */ + BPY_pyconstraint_driver(data, cob, targets); +#endif + + /* Now, run the actual 'constraint' function, which should only access the matrices */ + BPY_pyconstraint_eval(data, cob, targets); +} + +static bConstraintTypeInfo CTI_PYTHON = { + CONSTRAINT_TYPE_PYTHON, /* type */ + sizeof(bPythonConstraint), /* size */ + "Script", /* name */ + "bPythonConstraint", /* struct name */ + pycon_free, /* free data */ + pycon_relink, /* relink data */ + pycon_copy, /* copy data */ + pycon_new_data, /* new data */ + pycon_get_tars, /* get constraint targets */ + NULL, /* flush constraint targets */ + pycon_get_tarmat, /* get target matrix */ + pycon_evaluate /* evaluate */ +}; + +/* -------- Action Constraint ----------- */ + +static void actcon_relink (bConstraint *con) +{ + bActionConstraint *data= con->data; + ID_NEW(data->act); +} + +static void actcon_new_data (void *cdata) +{ + bActionConstraint *data= (bActionConstraint *)cdata; + + /* set type to 20 (Loc X), as 0 is Rot X for backwards compatability */ + data->type = 20; +} + +static void actcon_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bActionConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + } +} + +static void actcon_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bActionConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy) + } +} + +static void actcon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime) +{ + extern void chan_calc_mat(bPoseChannel *chan); + bActionConstraint *data = con->data; + + if (VALID_CONS_TARGET(ct)) { + float tempmat[4][4], vec[3]; + float s, t; + short axis; + + /* initialise return matrix */ + Mat4One(ct->matrix); + + /* get the transform matrix of the target */ + constraint_target_to_mat4(ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space); + + /* determine where in transform range target is */ + /* data->type is mapped as follows for backwards compatability: + * 00,01,02 - rotation (it used to be like this) + * 10,11,12 - scaling + * 20,21,22 - location + */ + if (data->type < 10) { + /* extract rotation (is in whatever space target should be in) */ + Mat4ToEul(tempmat, vec); + vec[0] *= (float)(180.0/M_PI); + vec[1] *= (float)(180.0/M_PI); + vec[2] *= (float)(180.0/M_PI); + axis= data->type; + } + else if (data->type < 20) { + /* extract scaling (is in whatever space target should be in) */ + Mat4ToSize(tempmat, vec); + axis= data->type - 10; + } + else { + /* extract location */ + VECCOPY(vec, tempmat[3]); + axis= data->type - 20; + } + + /* Target defines the animation */ + s = (vec[axis]-data->min) / (data->max-data->min); + CLAMP(s, 0, 1); + t = ( s * (data->end-data->start)) + data->start; + + /* Get the appropriate information from the action */ + if (cob->type == CONSTRAINT_OBTYPE_BONE) { + bPose *pose; + bPoseChannel *pchan, *tchan; + + /* make a temporary pose and evaluate using that */ + pose = MEM_callocN(sizeof(bPose), "pose"); + + pchan = cob->pchan; + tchan= verify_pose_channel(pose, pchan->name); + extract_pose_from_action(pose, data->act, t); + + chan_calc_mat(tchan); + + Mat4CpyMat4(ct->matrix, tchan->chan_mat); + + /* Clean up */ + free_pose_channels(pose); + MEM_freeN(pose); + } + else if (cob->type == CONSTRAINT_OBTYPE_OBJECT) { + /* evaluate using workob */ + what_does_obaction(cob->ob, data->act, t); + object_to_mat4(&workob, ct->matrix); + } + else { + /* behaviour undefined... */ + puts("Error: unknown owner type for Action Constraint"); + } + } +} + +static void actcon_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bConstraintTarget *ct= targets->first; + + if (VALID_CONS_TARGET(ct)) { + float temp[4][4]; + + /* Nice and simple... we just need to multiply the matrices, as the get_target_matrix + * function has already taken care of everything else. + */ + Mat4CpyMat4(temp, cob->matrix); + Mat4MulMat4(cob->matrix, ct->matrix, temp); + } +} + +static bConstraintTypeInfo CTI_ACTION = { + CONSTRAINT_TYPE_ACTION, /* type */ + sizeof(bActionConstraint), /* size */ + "Action", /* name */ + "bActionConstraint", /* struct name */ + NULL, /* free data */ + actcon_relink, /* relink data */ + NULL, /* copy data */ + actcon_new_data, /* new data */ + actcon_get_tars, /* get constraint targets */ + actcon_flush_tars, /* flush constraint targets */ + actcon_get_tarmat, /* get target matrix */ + actcon_evaluate /* evaluate */ +}; + +/* --------- Locked Track ---------- */ + +static void locktrack_new_data (void *cdata) +{ + bLockTrackConstraint *data= (bLockTrackConstraint *)cdata; + + data->trackflag = TRACK_Y; + data->lockflag = LOCK_Z; +} + +static void locktrack_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bLockTrackConstraint *data= con->data; + bConstraintTarget *ct; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + } +} + +static void locktrack_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bLockTrackConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy) + } +} + +static void locktrack_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bLockTrackConstraint *data= con->data; + bConstraintTarget *ct= targets->first; + + if (VALID_CONS_TARGET(ct)) { + float vec[3],vec2[3]; + float totmat[3][3]; + float tmpmat[3][3]; + float invmat[3][3]; + float tmat[4][4]; + float mdet; + + /* Vector object -> target */ + VecSubf(vec, ct->matrix[3], cob->matrix[3]); + switch (data->lockflag){ + case LOCK_X: /* LOCK X */ + { + switch (data->trackflag) { + case TRACK_Y: /* LOCK X TRACK Y */ + { + /* Projection of Vector on the plane */ + Projf(vec2, vec, cob->matrix[0]); + VecSubf(totmat[1], vec, vec2); + Normalize(totmat[1]); + + /* the x axis is fixed */ + totmat[0][0] = cob->matrix[0][0]; + totmat[0][1] = cob->matrix[0][1]; + totmat[0][2] = cob->matrix[0][2]; + Normalize(totmat[0]); + + /* the z axis gets mapped onto a third orthogonal vector */ + Crossf(totmat[2], totmat[0], totmat[1]); + } + break; + case TRACK_Z: /* LOCK X TRACK Z */ + { + /* Projection of Vector on the plane */ + Projf(vec2, vec, cob->matrix[0]); + VecSubf(totmat[2], vec, vec2); + Normalize(totmat[2]); + + /* the x axis is fixed */ + totmat[0][0] = cob->matrix[0][0]; + totmat[0][1] = cob->matrix[0][1]; + totmat[0][2] = cob->matrix[0][2]; + Normalize(totmat[0]); + + /* the z axis gets mapped onto a third orthogonal vector */ + Crossf(totmat[1], totmat[2], totmat[0]); + } + break; + case TRACK_nY: /* LOCK X TRACK -Y */ + { + /* Projection of Vector on the plane */ + Projf(vec2, vec, cob->matrix[0]); + VecSubf(totmat[1], vec, vec2); + Normalize(totmat[1]); + VecMulf(totmat[1],-1); + + /* the x axis is fixed */ + totmat[0][0] = cob->matrix[0][0]; + totmat[0][1] = cob->matrix[0][1]; + totmat[0][2] = cob->matrix[0][2]; + Normalize(totmat[0]); + + /* the z axis gets mapped onto a third orthogonal vector */ + Crossf(totmat[2], totmat[0], totmat[1]); + } + break; + case TRACK_nZ: /* LOCK X TRACK -Z */ + { + /* Projection of Vector on the plane */ + Projf(vec2, vec, cob->matrix[0]); + VecSubf(totmat[2], vec, vec2); + Normalize(totmat[2]); + VecMulf(totmat[2],-1); + + /* the x axis is fixed */ + totmat[0][0] = cob->matrix[0][0]; + totmat[0][1] = cob->matrix[0][1]; + totmat[0][2] = cob->matrix[0][2]; + Normalize(totmat[0]); + + /* the z axis gets mapped onto a third orthogonal vector */ + Crossf(totmat[1], totmat[2], totmat[0]); + } + break; + default: + { + totmat[0][0] = 1;totmat[0][1] = 0;totmat[0][2] = 0; + totmat[1][0] = 0;totmat[1][1] = 1;totmat[1][2] = 0; + totmat[2][0] = 0;totmat[2][1] = 0;totmat[2][2] = 1; + } + break; + } + } + break; + case LOCK_Y: /* LOCK Y */ + { + switch (data->trackflag) { + case TRACK_X: /* LOCK Y TRACK X */ + { + /* Projection of Vector on the plane */ + Projf(vec2, vec, cob->matrix[1]); + VecSubf(totmat[0], vec, vec2); + Normalize(totmat[0]); + + /* the y axis is fixed */ + totmat[1][0] = cob->matrix[1][0]; + totmat[1][1] = cob->matrix[1][1]; + totmat[1][2] = cob->matrix[1][2]; + Normalize(totmat[1]); + + /* the z axis gets mapped onto a third orthogonal vector */ + Crossf(totmat[2], totmat[0], totmat[1]); + } + break; + case TRACK_Z: /* LOCK Y TRACK Z */ + { + /* Projection of Vector on the plane */ + Projf(vec2, vec, cob->matrix[1]); + VecSubf(totmat[2], vec, vec2); + Normalize(totmat[2]); + + /* the y axis is fixed */ + totmat[1][0] = cob->matrix[1][0]; + totmat[1][1] = cob->matrix[1][1]; + totmat[1][2] = cob->matrix[1][2]; + Normalize(totmat[1]); + + /* the z axis gets mapped onto a third orthogonal vector */ + Crossf(totmat[0], totmat[1], totmat[2]); + } + break; + case TRACK_nX: /* LOCK Y TRACK -X */ + { + /* Projection of Vector on the plane */ + Projf(vec2, vec, cob->matrix[1]); + VecSubf(totmat[0], vec, vec2); + Normalize(totmat[0]); + VecMulf(totmat[0],-1); + + /* the y axis is fixed */ + totmat[1][0] = cob->matrix[1][0]; + totmat[1][1] = cob->matrix[1][1]; + totmat[1][2] = cob->matrix[1][2]; + Normalize(totmat[1]); + + /* the z axis gets mapped onto a third orthogonal vector */ + Crossf(totmat[2], totmat[0], totmat[1]); + } + break; + case TRACK_nZ: /* LOCK Y TRACK -Z */ + { + /* Projection of Vector on the plane */ + Projf(vec2, vec, cob->matrix[1]); + VecSubf(totmat[2], vec, vec2); + Normalize(totmat[2]); + VecMulf(totmat[2],-1); + + /* the y axis is fixed */ + totmat[1][0] = cob->matrix[1][0]; + totmat[1][1] = cob->matrix[1][1]; + totmat[1][2] = cob->matrix[1][2]; + Normalize(totmat[1]); + + /* the z axis gets mapped onto a third orthogonal vector */ + Crossf(totmat[0], totmat[1], totmat[2]); + } + break; + default: + { + totmat[0][0] = 1;totmat[0][1] = 0;totmat[0][2] = 0; + totmat[1][0] = 0;totmat[1][1] = 1;totmat[1][2] = 0; + totmat[2][0] = 0;totmat[2][1] = 0;totmat[2][2] = 1; + } + break; + } + } + break; + case LOCK_Z: /* LOCK Z */ + { + switch (data->trackflag) { + case TRACK_X: /* LOCK Z TRACK X */ + { + /* Projection of Vector on the plane */ + Projf(vec2, vec, cob->matrix[2]); + VecSubf(totmat[0], vec, vec2); + Normalize(totmat[0]); + + /* the z axis is fixed */ + totmat[2][0] = cob->matrix[2][0]; + totmat[2][1] = cob->matrix[2][1]; + totmat[2][2] = cob->matrix[2][2]; + Normalize(totmat[2]); + + /* the x axis gets mapped onto a third orthogonal vector */ + Crossf(totmat[1], totmat[2], totmat[0]); + } + break; + case TRACK_Y: /* LOCK Z TRACK Y */ + { + /* Projection of Vector on the plane */ + Projf(vec2, vec, cob->matrix[2]); + VecSubf(totmat[1], vec, vec2); + Normalize(totmat[1]); + + /* the z axis is fixed */ + totmat[2][0] = cob->matrix[2][0]; + totmat[2][1] = cob->matrix[2][1]; + totmat[2][2] = cob->matrix[2][2]; + Normalize(totmat[2]); + + /* the x axis gets mapped onto a third orthogonal vector */ + Crossf(totmat[0], totmat[1], totmat[2]); + } + break; + case TRACK_nX: /* LOCK Z TRACK -X */ + { + /* Projection of Vector on the plane */ + Projf(vec2, vec, cob->matrix[2]); + VecSubf(totmat[0], vec, vec2); + Normalize(totmat[0]); + VecMulf(totmat[0],-1); + + /* the z axis is fixed */ + totmat[2][0] = cob->matrix[2][0]; + totmat[2][1] = cob->matrix[2][1]; + totmat[2][2] = cob->matrix[2][2]; + Normalize(totmat[2]); + + /* the x axis gets mapped onto a third orthogonal vector */ + Crossf(totmat[1], totmat[2], totmat[0]); + } + break; + case TRACK_nY: /* LOCK Z TRACK -Y */ + { + /* Projection of Vector on the plane */ + Projf(vec2, vec, cob->matrix[2]); + VecSubf(totmat[1], vec, vec2); + Normalize(totmat[1]); + VecMulf(totmat[1],-1); + + /* the z axis is fixed */ + totmat[2][0] = cob->matrix[2][0]; + totmat[2][1] = cob->matrix[2][1]; + totmat[2][2] = cob->matrix[2][2]; + Normalize(totmat[2]); + + /* the x axis gets mapped onto a third orthogonal vector */ + Crossf(totmat[0], totmat[1], totmat[2]); + } + break; + default: + { + totmat[0][0] = 1;totmat[0][1] = 0;totmat[0][2] = 0; + totmat[1][0] = 0;totmat[1][1] = 1;totmat[1][2] = 0; + totmat[2][0] = 0;totmat[2][1] = 0;totmat[2][2] = 1; + } + break; + } + } + break; + default: + { + totmat[0][0] = 1;totmat[0][1] = 0;totmat[0][2] = 0; + totmat[1][0] = 0;totmat[1][1] = 1;totmat[1][2] = 0; + totmat[2][0] = 0;totmat[2][1] = 0;totmat[2][2] = 1; + } + break; + } + /* Block to keep matrix heading */ + tmpmat[0][0] = cob->matrix[0][0];tmpmat[0][1] = cob->matrix[0][1];tmpmat[0][2] = cob->matrix[0][2]; + tmpmat[1][0] = cob->matrix[1][0];tmpmat[1][1] = cob->matrix[1][1];tmpmat[1][2] = cob->matrix[1][2]; + tmpmat[2][0] = cob->matrix[2][0];tmpmat[2][1] = cob->matrix[2][1];tmpmat[2][2] = cob->matrix[2][2]; + Normalize(tmpmat[0]); + Normalize(tmpmat[1]); + Normalize(tmpmat[2]); + Mat3Inv(invmat, tmpmat); + Mat3MulMat3(tmpmat, totmat, invmat); + totmat[0][0] = tmpmat[0][0];totmat[0][1] = tmpmat[0][1];totmat[0][2] = tmpmat[0][2]; + totmat[1][0] = tmpmat[1][0];totmat[1][1] = tmpmat[1][1];totmat[1][2] = tmpmat[1][2]; + totmat[2][0] = tmpmat[2][0];totmat[2][1] = tmpmat[2][1];totmat[2][2] = tmpmat[2][2]; + + Mat4CpyMat4(tmat, cob->matrix); + + mdet = Det3x3( totmat[0][0],totmat[0][1],totmat[0][2], + totmat[1][0],totmat[1][1],totmat[1][2], + totmat[2][0],totmat[2][1],totmat[2][2]); + if (mdet==0) { + totmat[0][0] = 1;totmat[0][1] = 0;totmat[0][2] = 0; + totmat[1][0] = 0;totmat[1][1] = 1;totmat[1][2] = 0; + totmat[2][0] = 0;totmat[2][1] = 0;totmat[2][2] = 1; + } + + /* apply out transformaton to the object */ + Mat4MulMat34(cob->matrix, totmat, tmat); + } +} + +static bConstraintTypeInfo CTI_LOCKTRACK = { + CONSTRAINT_TYPE_LOCKTRACK, /* type */ + sizeof(bLockTrackConstraint), /* size */ + "Locked Track", /* name */ + "bLockTrackConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + locktrack_new_data, /* new data */ + locktrack_get_tars, /* get constraint targets */ + locktrack_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get target matrix */ + locktrack_evaluate /* evaluate */ +}; + +/* ---------- Stretch To ------------ */ + +static void stretchto_new_data (void *cdata) +{ + bStretchToConstraint *data= (bStretchToConstraint *)cdata; + + data->volmode = 0; + data->plane = 0; + data->orglength = 0.0; + data->bulge = 1.0; +} + +static void stretchto_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bStretchToConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + } +} + +static void stretchto_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bStretchToConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy) + } +} + +static void stretchto_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bStretchToConstraint *data= con->data; + bConstraintTarget *ct= targets->first; + + /* only evaluate if there is a target */ + if (VALID_CONS_TARGET(ct)) { + float size[3], scale[3], vec[3], xx[3], zz[3], orth[3]; + float totmat[3][3]; + float tmat[4][4]; + float dist; + + /* store scaling before destroying obmat */ + Mat4ToSize(cob->matrix, size); + + /* store X orientation before destroying obmat */ + xx[0] = cob->matrix[0][0]; + xx[1] = cob->matrix[0][1]; + xx[2] = cob->matrix[0][2]; + Normalize(xx); + + /* store Z orientation before destroying obmat */ + zz[0] = cob->matrix[2][0]; + zz[1] = cob->matrix[2][1]; + zz[2] = cob->matrix[2][2]; + Normalize(zz); + + VecSubf(vec, cob->matrix[3], ct->matrix[3]); + vec[0] /= size[0]; + vec[1] /= size[1]; + vec[2] /= size[2]; + + dist = Normalize(vec); + //dist = VecLenf( ob->obmat[3], targetmat[3]); + + /* data->orglength==0 occurs on first run, and after 'R' button is clicked */ + if (data->orglength == 0) + data->orglength = dist; + if (data->bulge == 0) + data->bulge = 1.0; + + scale[1] = dist/data->orglength; + switch (data->volmode) { + /* volume preserving scaling */ + case VOLUME_XZ : + scale[0] = 1.0f - (float)sqrt(data->bulge) + (float)sqrt(data->bulge*(data->orglength/dist)); + scale[2] = scale[0]; + break; + case VOLUME_X: + scale[0] = 1.0f + data->bulge * (data->orglength /dist - 1); + scale[2] = 1.0; + break; + case VOLUME_Z: + scale[0] = 1.0; + scale[2] = 1.0f + data->bulge * (data->orglength /dist - 1); + break; + /* don't care for volume */ + case NO_VOLUME: + scale[0] = 1.0; + scale[2] = 1.0; + break; + default: /* should not happen, but in case*/ + return; + } /* switch (data->volmode) */ + + /* Clear the object's rotation and scale */ + cob->matrix[0][0]=size[0]*scale[0]; + cob->matrix[0][1]=0; + cob->matrix[0][2]=0; + cob->matrix[1][0]=0; + cob->matrix[1][1]=size[1]*scale[1]; + cob->matrix[1][2]=0; + cob->matrix[2][0]=0; + cob->matrix[2][1]=0; + cob->matrix[2][2]=size[2]*scale[2]; + + VecSubf(vec, cob->matrix[3], ct->matrix[3]); + Normalize(vec); + + /* new Y aligns object target connection*/ + totmat[1][0] = -vec[0]; + totmat[1][1] = -vec[1]; + totmat[1][2] = -vec[2]; + switch (data->plane) { + case PLANE_X: + /* build new Z vector */ + /* othogonal to "new Y" "old X! plane */ + Crossf(orth, vec, xx); + Normalize(orth); + + /* new Z*/ + totmat[2][0] = orth[0]; + totmat[2][1] = orth[1]; + totmat[2][2] = orth[2]; + + /* we decided to keep X plane*/ + Crossf(xx, orth, vec); + Normalize(xx); + totmat[0][0] = xx[0]; + totmat[0][1] = xx[1]; + totmat[0][2] = xx[2]; + break; + case PLANE_Z: + /* build new X vector */ + /* othogonal to "new Y" "old Z! plane */ + Crossf(orth, vec, zz); + Normalize(orth); + + /* new X */ + totmat[0][0] = -orth[0]; + totmat[0][1] = -orth[1]; + totmat[0][2] = -orth[2]; + + /* we decided to keep Z */ + Crossf(zz, orth, vec); + Normalize(zz); + totmat[2][0] = zz[0]; + totmat[2][1] = zz[1]; + totmat[2][2] = zz[2]; + break; + } /* switch (data->plane) */ + + Mat4CpyMat4(tmat, cob->matrix); + Mat4MulMat34(cob->matrix, totmat, tmat); + } +} + +static bConstraintTypeInfo CTI_STRETCHTO = { + CONSTRAINT_TYPE_STRETCHTO, /* type */ + sizeof(bStretchToConstraint), /* size */ + "Stretch To", /* name */ + "bStretchToConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + stretchto_new_data, /* new data */ + stretchto_get_tars, /* get constraint targets */ + stretchto_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get target matrix */ + stretchto_evaluate /* evaluate */ +}; + +/* ---------- Floor ------------ */ + +static void minmax_new_data (void *cdata) +{ + bMinMaxConstraint *data= (bMinMaxConstraint *)cdata; + + data->minmaxflag = TRACK_Z; + data->offset = 0.0f; + data->cache[0] = data->cache[1] = data->cache[2] = 0.0f; + data->flag = 0; +} + +static void minmax_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bMinMaxConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + } +} + +static void minmax_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bMinMaxConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy) + } +} + +static void minmax_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bMinMaxConstraint *data= con->data; + bConstraintTarget *ct= targets->first; + + /* only evaluate if there is a target */ + if (VALID_CONS_TARGET(ct)) { + float obmat[4][4], imat[4][4], tarmat[4][4], tmat[4][4]; + float val1, val2; + int index; + + Mat4CpyMat4(obmat, cob->matrix); + Mat4CpyMat4(tarmat, ct->matrix); + + if (data->flag & MINMAX_USEROT) { + /* take rotation of target into account by doing the transaction in target's localspace */ + Mat4Invert(imat, tarmat); + Mat4MulMat4(tmat, obmat, imat); + Mat4CpyMat4(obmat, tmat); + Mat4One(tarmat); + } + + switch (data->minmaxflag) { + case TRACK_Z: + val1 = tarmat[3][2]; + val2 = obmat[3][2]-data->offset; + index = 2; + break; + case TRACK_Y: + val1 = tarmat[3][1]; + val2 = obmat[3][1]-data->offset; + index = 1; + break; + case TRACK_X: + val1 = tarmat[3][0]; + val2 = obmat[3][0]-data->offset; + index = 0; + break; + case TRACK_nZ: + val2 = tarmat[3][2]; + val1 = obmat[3][2]-data->offset; + index = 2; + break; + case TRACK_nY: + val2 = tarmat[3][1]; + val1 = obmat[3][1]-data->offset; + index = 1; + break; + case TRACK_nX: + val2 = tarmat[3][0]; + val1 = obmat[3][0]-data->offset; + index = 0; + break; + default: + return; + } + + if (val1 > val2) { + obmat[3][index] = tarmat[3][index] + data->offset; + if (data->flag & MINMAX_STICKY) { + if (data->flag & MINMAX_STUCK) { + VECCOPY(obmat[3], data->cache); + } + else { + VECCOPY(data->cache, obmat[3]); + data->flag |= MINMAX_STUCK; + } + } + if (data->flag & MINMAX_USEROT) { + /* get out of localspace */ + Mat4MulMat4(tmat, obmat, ct->matrix); + Mat4CpyMat4(cob->matrix, tmat); + } + else { + VECCOPY(cob->matrix[3], obmat[3]); + } + } + else { + data->flag &= ~MINMAX_STUCK; + } + } +} + +static bConstraintTypeInfo CTI_MINMAX = { + CONSTRAINT_TYPE_MINMAX, /* type */ + sizeof(bMinMaxConstraint), /* size */ + "Floor", /* name */ + "bMinMaxConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + minmax_new_data, /* new data */ + minmax_get_tars, /* get constraint targets */ + minmax_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get target matrix */ + minmax_evaluate /* evaluate */ +}; + +/* ------- RigidBody Joint ---------- */ + +static void rbj_new_data (void *cdata) +{ + bRigidBodyJointConstraint *data= (bRigidBodyJointConstraint *)cdata; + + // removed code which set target of this constraint + data->type=1; +} + +static void rbj_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bRigidBodyJointConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints without subtargets */ + SINGLETARGETNS_GET_TARS(con, data->tar, ct, list) + } +} + +static void rbj_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bRigidBodyJointConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, nocopy) + } +} + +static bConstraintTypeInfo CTI_RIGIDBODYJOINT = { + CONSTRAINT_TYPE_RIGIDBODYJOINT, /* type */ + sizeof(bRigidBodyJointConstraint), /* size */ + "RigidBody Joint", /* name */ + "bRigidBodyJointConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + rbj_new_data, /* new data */ + rbj_get_tars, /* get constraint targets */ + rbj_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get target matrix */ + NULL /* evaluate - this is not solved here... is just an interface for game-engine */ +}; + +/* -------- Clamp To ---------- */ + +static void clampto_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bClampToConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints without subtargets */ + SINGLETARGETNS_GET_TARS(con, data->tar, ct, list) + } +} + +static void clampto_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bClampToConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, nocopy) + } +} + +static void clampto_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime) +{ + if (VALID_CONS_TARGET(ct)) { + Curve *cu= ct->tar->data; + + /* note: when creating constraints that follow path, the curve gets the CU_PATH set now, + * currently for paths to work it needs to go through the bevlist/displist system (ton) + */ + + /* only happens on reload file, but violates depsgraph still... fix! */ + if (cu->path==NULL || cu->path->data==NULL) + makeDispListCurveTypes(ct->tar, 0); + } + + /* technically, this isn't really needed for evaluation, but we don't know what else + * might end up calling this... + */ + if (ct) + Mat4One(ct->matrix); +} + +static void clampto_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bClampToConstraint *data= con->data; + bConstraintTarget *ct= targets->first; + + /* only evaluate if there is a target and it is a curve */ + if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_CURVE)) { + Curve *cu= data->tar->data; + float obmat[4][4], targetMatrix[4][4], ownLoc[3]; + float curveMin[3], curveMax[3]; + + Mat4CpyMat4(obmat, cob->matrix); + Mat4One(targetMatrix); + VECCOPY(ownLoc, obmat[3]); + + INIT_MINMAX(curveMin, curveMax) + minmax_object(ct->tar, curveMin, curveMax); + + /* get targetmatrix */ + if (cu->path && cu->path->data) { + float vec[4], dir[3], totmat[4][4]; + float curvetime; + short clamp_axis; + + /* find best position on curve */ + /* 1. determine which axis to sample on? */ + if (data->flag == CLAMPTO_AUTO) { + float size[3]; + VecSubf(size, curveMax, curveMin); + + /* find axis along which the bounding box has the greatest + * extent. Otherwise, default to the x-axis, as that is quite + * frequently used. + */ + if ((size[2]>size[0]) && (size[2]>size[1])) + clamp_axis= CLAMPTO_Z - 1; + else if ((size[1]>size[0]) && (size[1]>size[2])) + clamp_axis= CLAMPTO_Y - 1; + else + clamp_axis = CLAMPTO_X - 1; + } + else + clamp_axis= data->flag - 1; + + /* 2. determine position relative to curve on a 0-1 scale based on bounding box */ + if (data->flag2 & CLAMPTO_CYCLIC) { + /* cyclic, so offset within relative bounding box is used */ + float len= (curveMax[clamp_axis] - curveMin[clamp_axis]); + float offset; + + /* find bounding-box range where target is located */ + if (ownLoc[clamp_axis] < curveMin[clamp_axis]) { + /* bounding-box range is before */ + offset= curveMin[clamp_axis]; + + while (ownLoc[clamp_axis] < offset) + offset -= len; + + /* now, we calculate as per normal, except using offset instead of curveMin[clamp_axis] */ + curvetime = (ownLoc[clamp_axis] - offset) / (len); + } + else if (ownLoc[clamp_axis] > curveMax[clamp_axis]) { + /* bounding-box range is after */ + offset= curveMax[clamp_axis]; + + while (ownLoc[clamp_axis] > offset) { + if ((offset + len) > ownLoc[clamp_axis]) + break; + else + offset += len; + } + + /* now, we calculate as per normal, except using offset instead of curveMax[clamp_axis] */ + curvetime = (ownLoc[clamp_axis] - offset) / (len); + } + else { + /* as the location falls within bounds, just calculate */ + curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / (len); + } + } + else { + /* no cyclic, so position is clamped to within the bounding box */ + if (ownLoc[clamp_axis] <= curveMin[clamp_axis]) + curvetime = 0.0; + else if (ownLoc[clamp_axis] >= curveMax[clamp_axis]) + curvetime = 1.0; + else + curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / (curveMax[clamp_axis] - curveMin[clamp_axis]); + } + + /* 3. position on curve */ + if (where_on_path(ct->tar, curvetime, vec, dir) ) { + Mat4One(totmat); + VECCOPY(totmat[3], vec); + + Mat4MulSerie(targetMatrix, ct->tar->obmat, totmat, NULL, NULL, NULL, NULL, NULL, NULL); + } + } + + /* obtain final object position */ + VECCOPY(cob->matrix[3], targetMatrix[3]); + } +} + +static bConstraintTypeInfo CTI_CLAMPTO = { + CONSTRAINT_TYPE_CLAMPTO, /* type */ + sizeof(bClampToConstraint), /* size */ + "Clamp To", /* name */ + "bClampToConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + NULL, /* new data */ + clampto_get_tars, /* get constraint targets */ + clampto_flush_tars, /* flush constraint targets */ + clampto_get_tarmat, /* get target matrix */ + clampto_evaluate /* evaluate */ +}; + +/* ---------- Transform Constraint ----------- */ + +static void transform_new_data (void *cdata) +{ + bTransformConstraint *data= (bTransformConstraint *)cdata; + + data->map[0]= 0; + data->map[1]= 1; + data->map[2]= 2; +} + +static void transform_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bTransformConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + } +} + +static void transform_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bTransformConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy) + } +} + +static void transform_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bTransformConstraint *data= con->data; + bConstraintTarget *ct= targets->first; + + /* only evaluate if there is a target */ + if (VALID_CONS_TARGET(ct)) { + float loc[3], eul[3], size[3]; + float dvec[3], sval[3]; + short i; + + /* obtain target effect */ + switch (data->from) { + case 2: /* scale */ + Mat4ToSize(ct->matrix, dvec); + break; + case 1: /* rotation */ + Mat4ToEul(ct->matrix, dvec); + break; + default: /* location */ + VecCopyf(dvec, ct->matrix[3]); + break; + } + + /* extract components of owner's matrix */ + VECCOPY(loc, cob->matrix[3]); + Mat4ToEul(cob->matrix, eul); + Mat4ToSize(cob->matrix, size); + + /* determine where in range current transforms lie */ + if (data->expo) { + for (i=0; i<3; i++) { + if (data->from_max[i] - data->from_min[i]) + sval[i]= (dvec[i] - data->from_min[i]) / (data->from_max[i] - data->from_min[i]); + else + sval[i]= 0.0f; + } + } + else { + /* clamp transforms out of range */ + for (i=0; i<3; i++) { + CLAMP(dvec[i], data->from_min[i], data->from_max[i]); + if (data->from_max[i] - data->from_min[i]) + sval[i]= (dvec[i] - data->from_min[i]) / (data->from_max[i] - data->from_min[i]); + else + sval[i]= 0.0f; + } + } + + /* convert radian<->degree */ + if (data->from==1 && data->to==0) { + /* from radians to degrees */ + for (i=0; i<3; i++) + sval[i] = sval[i] / M_PI * 180; + } + else if (data->from==0 && data->to==1) { + /* from degrees to radians */ + for (i=0; i<3; i++) + sval[i] = sval[i] / 180 * M_PI; + } + + /* apply transforms */ + switch (data->to) { + case 2: /* scaling */ + for (i=0; i<3; i++) + size[i]= data->to_min[i] + (sval[data->map[i]] * (data->to_max[i] - data->to_min[i])); + break; + case 1: /* rotation */ + for (i=0; i<3; i++) { + float tmin, tmax; + + /* convert destination min/max ranges from degrees to radians */ + tmin= data->to_min[i] / M_PI * 180; + tmax= data->to_max[i] / M_PI * 180; + + eul[i]= tmin + (sval[data->map[i]] * (tmax - tmin)); + } + break; + default: /* location */ + /* get new location */ + for (i=0; i<3; i++) + loc[i]= (data->to_min[i] + (sval[data->map[i]] * (data->to_max[i] - data->to_min[i]))); + + /* add original location back on (so that it can still be moved) */ + VecAddf(loc, cob->matrix[3], loc); + break; + } + + /* apply to matrix */ + LocEulSizeToMat4(cob->matrix, loc, eul, size); + } +} + +static bConstraintTypeInfo CTI_TRANSFORM = { + CONSTRAINT_TYPE_TRANSFORM, /* type */ + sizeof(bTransformConstraint), /* size */ + "Transform", /* name */ + "bTransformConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + transform_new_data, /* new data */ + transform_get_tars, /* get constraint targets */ + transform_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get a target matrix */ + transform_evaluate /* evaluate */ +}; + +/* ************************* Constraints Type-Info *************************** */ +/* All of the constraints api functions use bConstraintTypeInfo structs to carry out + * and operations that involve constraint specifc code. + */ + +/* These globals only ever get directly accessed in this file */ +static bConstraintTypeInfo *constraintsTypeInfo[NUM_CONSTRAINT_TYPES]; +static short CTI_INIT= 1; /* when non-zero, the list needs to be updated */ + +/* This function only gets called when CTI_INIT is non-zero */ +static void constraints_init_typeinfo () { + constraintsTypeInfo[0]= NULL; /* 'Null' Constraint */ + constraintsTypeInfo[1]= &CTI_CHILDOF; /* ChildOf Constraint */ + constraintsTypeInfo[2]= &CTI_TRACKTO; /* TrackTo Constraint */ + constraintsTypeInfo[3]= &CTI_KINEMATIC; /* IK Constraint */ + constraintsTypeInfo[4]= &CTI_FOLLOWPATH; /* Follow-Path Constraint */ + constraintsTypeInfo[5]= &CTI_ROTLIMIT; /* Limit Rotation Constraint */ + constraintsTypeInfo[6]= &CTI_LOCLIMIT; /* Limit Location Constraint */ + constraintsTypeInfo[7]= &CTI_SIZELIMIT; /* Limit Scaling Constraint */ + constraintsTypeInfo[8]= &CTI_ROTLIKE; /* Copy Rotation Constraint */ + constraintsTypeInfo[9]= &CTI_LOCLIKE; /* Copy Location Constraint */ + constraintsTypeInfo[10]= &CTI_SIZELIKE; /* Copy Scaling Constraint */ + constraintsTypeInfo[11]= &CTI_PYTHON; /* Python/Script Constraint */ + constraintsTypeInfo[12]= &CTI_ACTION; /* Action Constraint */ + constraintsTypeInfo[13]= &CTI_LOCKTRACK; /* Locked-Track Constraint */ + constraintsTypeInfo[14]= NULL; /* 'Distance Limit' Constraint */ + constraintsTypeInfo[15]= &CTI_STRETCHTO; /* StretchTo Constaint */ + constraintsTypeInfo[16]= &CTI_MINMAX; /* Floor Constraint */ + constraintsTypeInfo[17]= &CTI_RIGIDBODYJOINT; /* RigidBody Constraint */ + constraintsTypeInfo[18]= &CTI_CLAMPTO; /* ClampTo Constraint */ + constraintsTypeInfo[19]= &CTI_TRANSFORM; /* Transformation Constraint */ +} + +/* This function should be used for getting the appropriate type-info when only + * a constraint type is known + */ +bConstraintTypeInfo *get_constraint_typeinfo (int type) +{ + /* initialise the type-info list? */ + if (CTI_INIT) { + constraints_init_typeinfo(); + CTI_INIT = 0; + } + + /* only return for valid types */ + if ( (type >= CONSTRAINT_TYPE_NULL) && + (type <= NUM_CONSTRAINT_TYPES ) ) + { + /* there shouldn't be any segfaults here... */ + return constraintsTypeInfo[type]; + } + else { + printf("No valid constraint type-info data available. Type = %i \n", type); + } + + return NULL; +} + +/* This function should always be used to get the appropriate type-info, as it + * has checks which prevent segfaults in some weird cases. + */ +bConstraintTypeInfo *constraint_get_typeinfo (bConstraint *con) +{ + /* only return typeinfo for valid constraints */ + if (con) + return get_constraint_typeinfo(con->type); + else + return NULL; +} + +/* ************************* General Constraints API ************************** */ +/* The functions here are called by various parts of Blender. Very few (should be none if possible) + * constraint-specific code should occur here. + */ + +/* ---------- Data Management ------- */ + +/* Free data of a specific constraint if it has any info */ +void free_constraint_data (bConstraint *con) +{ + if (con->data) { + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + + /* perform any special freeing constraint may have */ + if (cti && cti->free_data) + cti->free_data(con); + + /* free constraint data now */ + MEM_freeN(con->data); + } +} + +/* Free all constraints from a constraint-stack */ +void free_constraints (ListBase *conlist) +{ + bConstraint *con; + + /* Free constraint data and also any extra data */ + for (con= conlist->first; con; con= con->next) { + free_constraint_data(con); + } + + /* Free the whole list */ + BLI_freelistN(conlist); +} + +/* Reassign links that constraints have to other data (called during file loading?) */ +void relink_constraints (ListBase *conlist) +{ + bConstraint *con; + bConstraintTarget *ct; + + for (con= conlist->first; con; con= con->next) { + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + + if (cti) { + /* relink any targets */ + if (cti->get_constraint_targets) { + ListBase targets = {NULL, NULL}; + + cti->get_constraint_targets(con, &targets); + for (ct= targets.first; ct; ct= ct->next) { + ID_NEW(ct->tar); + } + + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(con, &targets, 0); + } + + /* relink any other special data */ + if (cti->relink_data) + cti->relink_data(con); + } + } +} + +/* duplicate all of the constraints in a constraint stack */ +void copy_constraints (ListBase *dst, ListBase *src) +{ + bConstraint *con, *srccon; + + dst->first= dst->last= NULL; + duplicatelist(dst, src); + + for (con=dst->first, srccon=src->first; con; srccon=srccon->next, con=con->next) { + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + + /* make a new copy of the constraint's data */ + con->data = MEM_dupallocN(con->data); + + /* only do specific constraints if required */ + if (cti && cti->copy_data) + cti->copy_data(con, srccon); + } +} + +/* -------- Target-Matrix Stuff ------- */ + +/* This function is a relic from the prior implementations of the constraints system, when all + * constraints either had one or no targets. It used to be called during the main constraint solving + * loop, but is now only used for the remaining cases for a few constraints. + * + * None of the actual calculations of the matricies should be done here! Also, this function is + * not to be used by any new constraints, particularly any that have multiple targets. + */ +void get_constraint_target_matrix (bConstraint *con, int n, short ownertype, void *ownerdata, float mat[][4], float ctime) +{ + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + ListBase targets = {NULL, NULL}; + bConstraintOb *cob; + bConstraintTarget *ct; + + if (cti && cti->get_constraint_targets) { + /* make 'constraint-ob' */ + cob= MEM_callocN(sizeof(bConstraintOb), "tempConstraintOb"); + cob->type= ownertype; + switch (ownertype) { + case CONSTRAINT_OBTYPE_OBJECT: /* it is usually this case */ + { + cob->ob= (Object *)ownerdata; + cob->pchan= NULL; + if (cob->ob) { + Mat4CpyMat4(cob->matrix, cob->ob->obmat); + Mat4CpyMat4(cob->startmat, cob->matrix); + } + else { + Mat4One(cob->matrix); + Mat4One(cob->startmat); + } + } + break; + case CONSTRAINT_OBTYPE_BONE: /* this may occur in some cases */ + { + cob->ob= NULL; /* this might not work at all :/ */ + cob->pchan= (bPoseChannel *)ownerdata; + if (cob->pchan) { + Mat4CpyMat4(cob->matrix, cob->pchan->pose_mat); + Mat4CpyMat4(cob->startmat, cob->matrix); + } + else { + Mat4One(cob->matrix); + Mat4One(cob->startmat); + } + } + break; + } + + /* get targets - we only need the first one though (and there should only be one) */ + cti->get_constraint_targets(con, &targets); + + /* only calculate the target matrix on the first target */ + ct= (bConstraintTarget *)targets.first; + while(ct && n-- > 0) + ct= ct->next; + + if (ct) { + if (cti->get_target_matrix) + cti->get_target_matrix(con, cob, ct, ctime); + Mat4CpyMat4(mat, ct->matrix); + } + + /* free targets + 'constraint-ob' */ + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(con, &targets, 1); + MEM_freeN(cob); + } + else { + /* invalid constraint - perhaps... */ + Mat4One(mat); + } +} + +/* ---------- Evaluation ----------- */ + +/* This function is called whenever constraints need to be evaluated. Currently, all + * constraints that can be evaluated are everytime this gets run. + * + * constraints_make_evalob and constraints_clear_evalob should be called before and + * after running this function, to sort out cob + */ +void solve_constraints (ListBase *conlist, bConstraintOb *cob, float ctime) +{ + bConstraint *con; + float solution[4][4], delta[4][4]; + float oldmat[4][4], imat[4][4]; + float enf; + + /* check that there is a valid constraint object to evaluate */ + if (cob == NULL) + return; + + /* loop over available constraints, solving and blending them */ + for (con= conlist->first; con; con= con->next) { + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + ListBase targets = {NULL, NULL}; + + /* these we can skip completely (invalid constraints...) */ + if (cti == NULL) continue; + if (con->flag & CONSTRAINT_DISABLE) continue; + /* these constraints can't be evaluated anyway */ + if (cti->evaluate_constraint == NULL) continue; + /* influence == 0 should be ignored */ + if (con->enforce == 0.0f) continue; + + /* influence of constraint + * - value should have been set from IPO's/Constraint Channels already + */ + enf = con->enforce; + + /* move owner matrix into right space */ + constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace); + Mat4CpyMat4(oldmat, cob->matrix); + + /* prepare targets for constraint solving */ + if (cti->get_constraint_targets) { + bConstraintTarget *ct; + + /* get targets + * - constraints should use ct->matrix, not directly accessing values + * - ct->matrix members have not yet been calculated here! + */ + cti->get_constraint_targets(con, &targets); + + /* set matrices + * - calculate if possible, otherwise just initialise as identity matrix + */ + if (cti->get_target_matrix) { + for (ct= targets.first; ct; ct= ct->next) + cti->get_target_matrix(con, cob, ct, ctime); + } + else { + for (ct= targets.first; ct; ct= ct->next) + Mat4One(ct->matrix); + } + } + + /* Solve the constraint */ + cti->evaluate_constraint(con, cob, &targets); + + /* clear targets after use + * - this should free temp targets but no data should be copied back + * as constraints may have done some nasty things to it... + */ + if (cti->flush_constraint_targets) { + cti->flush_constraint_targets(con, &targets, 1); + } + + /* Interpolate the enforcement, to blend result of constraint into final owner transform */ + /* 1. Remove effects of original matrix from constraint solution ==> delta */ + Mat4Invert(imat, oldmat); + Mat4CpyMat4(solution, cob->matrix); + Mat4MulMat4(delta, solution, imat); + + /* 2. If constraint influence is not full strength, then interpolate + * identity_matrix --> delta_matrix to get the effect the constraint actually exerts + */ + if (enf < 1.0) { + float identity[4][4]; + Mat4One(identity); + Mat4BlendMat4(delta, identity, delta, enf); + } + + /* 3. Now multiply the delta by the matrix in use before the evaluation */ + Mat4MulMat4(cob->matrix, delta, oldmat); + + /* move owner back into worldspace for next constraint/other business */ + if ((con->flag & CONSTRAINT_SPACEONCE) == 0) + constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, con->ownspace, CONSTRAINT_SPACE_WORLD); + } +} diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c new file mode 100644 index 00000000000..ece0a7f1d6c --- /dev/null +++ b/source/blender/blenkernel/intern/curve.c @@ -0,0 +1,2595 @@ + +/* curve.c + * + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include // floor +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_guardedalloc.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "DNA_object_types.h" +#include "DNA_curve_types.h" +#include "DNA_material_types.h" + +/* for dereferencing pointers */ +#include "DNA_ID.h" +#include "DNA_vfont_types.h" +#include "DNA_key_types.h" +#include "DNA_ipo_types.h" + +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_utildefines.h" // VECCOPY +#include "BKE_object.h" +#include "BKE_mesh.h" +#include "BKE_curve.h" +#include "BKE_displist.h" +#include "BKE_ipo.h" +#include "BKE_anim.h" +#include "BKE_library.h" +#include "BKE_key.h" + + +/* globals */ + +extern ListBase editNurb; /* editcurve.c */ + +/* local */ +int cu_isectLL(float *v1, float *v2, float *v3, float *v4, + short cox, short coy, + float *labda, float *mu, float *vec); + +void unlink_curve(Curve *cu) +{ + int a; + + for(a=0; atotcol; a++) { + if(cu->mat[a]) cu->mat[a]->id.us--; + cu->mat[a]= 0; + } + if(cu->vfont) cu->vfont->id.us--; + cu->vfont= 0; + if(cu->key) cu->key->id.us--; + cu->key= 0; + if(cu->ipo) cu->ipo->id.us--; + cu->ipo= 0; +} + + +/* niet curve zelf vrijgeven */ +void free_curve(Curve *cu) +{ + + freeNurblist(&cu->nurb); + BLI_freelistN(&cu->bev); + freedisplist(&cu->disp); + + unlink_curve(cu); + + if(cu->mat) MEM_freeN(cu->mat); + if(cu->str) MEM_freeN(cu->str); + if(cu->strinfo) MEM_freeN(cu->strinfo); + if(cu->bb) MEM_freeN(cu->bb); + if(cu->path) free_path(cu->path); + if(cu->tb) MEM_freeN(cu->tb); +} + +Curve *add_curve(char *name, int type) +{ + Curve *cu; + + cu= alloc_libblock(&G.main->curve, ID_CU, name); + + cu->size[0]= cu->size[1]= cu->size[2]= 1.0; + cu->flag= CU_FRONT+CU_BACK; + cu->pathlen= 100; + cu->resolu= cu->resolv= 12; + cu->width= 1.0; + cu->wordspace = 1.0; + cu->spacing= cu->linedist= 1.0; + cu->fsize= 1.0; + cu->ulheight = 0.05; + cu->texflag= CU_AUTOSPACE; + + cu->bb= unit_boundbox(); + + return cu; +} + +Curve *copy_curve(Curve *cu) +{ + Curve *cun; + int a; + + cun= copy_libblock(cu); + cun->nurb.first= cun->nurb.last= 0; + duplicateNurblist( &(cun->nurb), &(cu->nurb)); + + cun->mat= MEM_dupallocN(cu->mat); + for(a=0; atotcol; a++) { + id_us_plus((ID *)cun->mat[a]); + } + + cun->str= MEM_dupallocN(cu->str); + cun->strinfo= MEM_dupallocN(cu->strinfo); + cun->tb= MEM_dupallocN(cu->tb); + cun->bb= MEM_dupallocN(cu->bb); + + cun->key= copy_key(cu->key); + if(cun->key) cun->key->from= (ID *)cun; + + cun->disp.first= cun->disp.last= 0; + cun->bev.first= cun->bev.last= 0; + cun->path= 0; + + /* single user ipo too */ + if(cun->ipo) cun->ipo= copy_ipo(cun->ipo); + + id_us_plus((ID *)cun->vfont); + id_us_plus((ID *)cun->vfontb); + id_us_plus((ID *)cun->vfonti); + id_us_plus((ID *)cun->vfontbi); + + return cun; +} + +void make_local_curve(Curve *cu) +{ + Object *ob = 0; + Curve *cun; + int local=0, lib=0; + + /* - when there are only lib users: don't do + * - when there are only local users: set flag + * - mixed: do a copy + */ + + if(cu->id.lib==0) return; + + if(cu->vfont) cu->vfont->id.lib= 0; + + if(cu->id.us==1) { + cu->id.lib= 0; + cu->id.flag= LIB_LOCAL; + new_id(0, (ID *)cu, 0); + return; + } + + ob= G.main->object.first; + while(ob) { + if(ob->data==cu) { + if(ob->id.lib) lib= 1; + else local= 1; + } + ob= ob->id.next; + } + + if(local && lib==0) { + cu->id.lib= 0; + cu->id.flag= LIB_LOCAL; + new_id(0, (ID *)cu, 0); + } + else if(local && lib) { + cun= copy_curve(cu); + cun->id.us= 0; + + ob= G.main->object.first; + while(ob) { + if(ob->data==cu) { + + if(ob->id.lib==0) { + ob->data= cun; + cun->id.us++; + cu->id.us--; + } + } + ob= ob->id.next; + } + } +} + +short curve_type(Curve *cu) +{ + Nurb *nu; + if(cu->vfont) { + return OB_FONT; + } + for (nu= cu->nurb.first; nu; nu= nu->next) { + if(nu->pntsv>1) { + return OB_SURF; + } + } + + return OB_CURVE; +} + +void test_curve_type(Object *ob) +{ + ob->type = curve_type(ob->data); +} + +void tex_space_curve(Curve *cu) +{ + DispList *dl; + BoundBox *bb; + float *data, min[3], max[3], loc[3], size[3]; + int tot, doit= 0; + + if(cu->bb==NULL) cu->bb= MEM_callocN(sizeof(BoundBox), "boundbox"); + bb= cu->bb; + + INIT_MINMAX(min, max); + + dl= cu->disp.first; + while(dl) { + + if(dl->type==DL_INDEX3 || dl->type==DL_INDEX3) tot= dl->nr; + else tot= dl->nr*dl->parts; + + if(tot) doit= 1; + data= dl->verts; + while(tot--) { + DO_MINMAX(data, min, max); + data+= 3; + } + dl= dl->next; + } + + if(!doit) { + min[0] = min[1] = min[2] = -1.0f; + max[0] = max[1] = max[2] = 1.0f; + } + + loc[0]= (min[0]+max[0])/2.0f; + loc[1]= (min[1]+max[1])/2.0f; + loc[2]= (min[2]+max[2])/2.0f; + + size[0]= (max[0]-min[0])/2.0f; + size[1]= (max[1]-min[1])/2.0f; + size[2]= (max[2]-min[2])/2.0f; + + boundbox_set_from_min_max(bb, min, max); + + if(cu->texflag & CU_AUTOSPACE) { + VECCOPY(cu->loc, loc); + VECCOPY(cu->size, size); + cu->rot[0]= cu->rot[1]= cu->rot[2]= 0.0; + + if(cu->size[0]==0.0) cu->size[0]= 1.0; + else if(cu->size[0]>0.0 && cu->size[0]<0.00001) cu->size[0]= 0.00001; + else if(cu->size[0]<0.0 && cu->size[0]> -0.00001) cu->size[0]= -0.00001; + + if(cu->size[1]==0.0) cu->size[1]= 1.0; + else if(cu->size[1]>0.0 && cu->size[1]<0.00001) cu->size[1]= 0.00001; + else if(cu->size[1]<0.0 && cu->size[1]> -0.00001) cu->size[1]= -0.00001; + + if(cu->size[2]==0.0) cu->size[2]= 1.0; + else if(cu->size[2]>0.0 && cu->size[2]<0.00001) cu->size[2]= 0.00001; + else if(cu->size[2]<0.0 && cu->size[2]> -0.00001) cu->size[2]= -0.00001; + + } +} + + +int count_curveverts(ListBase *nurb) +{ + Nurb *nu; + int tot=0; + + nu= nurb->first; + while(nu) { + if(nu->bezt) tot+= 3*nu->pntsu; + else if(nu->bp) tot+= nu->pntsu*nu->pntsv; + + nu= nu->next; + } + return tot; +} + +int count_curveverts_without_handles(ListBase *nurb) +{ + Nurb *nu; + int tot=0; + + nu= nurb->first; + while(nu) { + if(nu->bezt) tot+= nu->pntsu; + else if(nu->bp) tot+= nu->pntsu*nu->pntsv; + + nu= nu->next; + } + return tot; +} + +/* **************** NURBS ROUTINES ******************** */ + +void freeNurb(Nurb *nu) +{ + + if(nu==0) return; + + if(nu->bezt) MEM_freeN(nu->bezt); + nu->bezt= 0; + if(nu->bp) MEM_freeN(nu->bp); + nu->bp= 0; + if(nu->knotsu) MEM_freeN(nu->knotsu); + nu->knotsu= 0; + if(nu->knotsv) MEM_freeN(nu->knotsv); + nu->knotsv= 0; + /* if(nu->trim.first) freeNurblist(&(nu->trim)); */ + + MEM_freeN(nu); + +} + + +void freeNurblist(ListBase *lb) +{ + Nurb *nu, *next; + + if(lb==0) return; + + nu= lb->first; + while(nu) { + next= nu->next; + freeNurb(nu); + nu= next; + } + lb->first= lb->last= 0; +} + +Nurb *duplicateNurb(Nurb *nu) +{ + Nurb *newnu; + int len; + + newnu= (Nurb*)MEM_mallocN(sizeof(Nurb),"duplicateNurb"); + if(newnu==0) return 0; + memcpy(newnu, nu, sizeof(Nurb)); + + if(nu->bezt) { + newnu->bezt= + (BezTriple*)MEM_mallocN((nu->pntsu)* sizeof(BezTriple),"duplicateNurb2"); + memcpy(newnu->bezt, nu->bezt, nu->pntsu*sizeof(BezTriple)); + } + else { + len= nu->pntsu*nu->pntsv; + newnu->bp= + (BPoint*)MEM_mallocN((len)* sizeof(BPoint),"duplicateNurb3"); + memcpy(newnu->bp, nu->bp, len*sizeof(BPoint)); + + newnu->knotsu=newnu->knotsv= 0; + + if(nu->knotsu) { + len= KNOTSU(nu); + if(len) { + newnu->knotsu= MEM_mallocN(len*sizeof(float), "duplicateNurb4"); + memcpy(newnu->knotsu, nu->knotsu, sizeof(float)*len); + } + } + if(nu->pntsv>1 && nu->knotsv) { + len= KNOTSV(nu); + if(len) { + newnu->knotsv= MEM_mallocN(len*sizeof(float), "duplicateNurb5"); + memcpy(newnu->knotsv, nu->knotsv, sizeof(float)*len); + } + } + } + return newnu; +} + +void duplicateNurblist(ListBase *lb1, ListBase *lb2) +{ + Nurb *nu, *nun; + + freeNurblist(lb1); + + nu= lb2->first; + while(nu) { + nun= duplicateNurb(nu); + BLI_addtail(lb1, nun); + + nu= nu->next; + } +} + +void test2DNurb(Nurb *nu) +{ + BezTriple *bezt; + BPoint *bp; + int a; + + if( nu->type== CU_BEZIER+CU_2D ) { + a= nu->pntsu; + bezt= nu->bezt; + while(a--) { + bezt->vec[0][2]= 0.0; + bezt->vec[1][2]= 0.0; + bezt->vec[2][2]= 0.0; + bezt++; + } + } + else if(nu->type & CU_2D) { + a= nu->pntsu*nu->pntsv; + bp= nu->bp; + while(a--) { + bp->vec[2]= 0.0; + bp++; + } + } +} + +void minmaxNurb(Nurb *nu, float *min, float *max) +{ + BezTriple *bezt; + BPoint *bp; + int a; + + if( (nu->type & 7)==CU_BEZIER ) { + a= nu->pntsu; + bezt= nu->bezt; + while(a--) { + DO_MINMAX(bezt->vec[0], min, max); + DO_MINMAX(bezt->vec[1], min, max); + DO_MINMAX(bezt->vec[2], min, max); + bezt++; + } + } + else { + a= nu->pntsu*nu->pntsv; + bp= nu->bp; + while(a--) { + DO_MINMAX(bp->vec, min, max); + bp++; + } + } + +} + +/* ~~~~~~~~~~~~~~~~~~~~Non Uniform Rational B Spline calculations ~~~~~~~~~~~ */ + + +static void calcknots(float *knots, short aantal, short order, short type) +/* knots: number of pnts NOT corrected for cyclic */ +/* type; 0: uniform, 1: endpoints, 2: bezier */ +{ + float k; + int a, t; + + t = aantal+order; + if(type==0) { + + for(a=0;a=order && a<=aantal) k+= 1.0; + } + } + else if(type==2) { + if(order==4) { + k= 0.34; + for(a=0;a=order && a<=aantal) k+= (0.5); + knots[a]= (float)floor(k); + } + } + } +} + +static void makecyclicknots(float *knots, short pnts, short order) +/* pnts, order: number of pnts NOT corrected for cyclic */ +{ + int a, b, order2, c; + + if(knots==0) return; + order2=order-1; + + /* do first long rows (order -1), remove identical knots at endpoints */ + if(order>2) { + b= pnts+order2; + for(a=1; atype & 7)==CU_NURBS ) { + if(uv & 1) { + if(nu->knotsu) MEM_freeN(nu->knotsu); + if(nu->pntsu>1) { + nu->knotsu= MEM_callocN(4+sizeof(float)*KNOTSU(nu), "makeknots"); + calcknots(nu->knotsu, nu->pntsu, nu->orderu, type); + if(nu->flagu & 1) makecyclicknots(nu->knotsu, nu->pntsu, nu->orderu); + } + else nu->knotsu= 0; + } + if(uv & 2) { + if(nu->knotsv) MEM_freeN(nu->knotsv); + if(nu->pntsv>1) { + nu->knotsv= MEM_callocN(4+sizeof(float)*KNOTSV(nu), "makeknots"); + calcknots(nu->knotsv, nu->pntsv, nu->orderv, type); + if(nu->flagv & 1) makecyclicknots(nu->knotsv, nu->pntsv, nu->orderv); + } + else nu->knotsv= 0; + } + } +} + +static void basisNurb(float t, short order, short pnts, float *knots, float *basis, int *start, int *end) +{ + float d, e; + int i, i1 = 0, i2 = 0 ,j, orderpluspnts, opp2, o2; + + orderpluspnts= order+pnts; + opp2 = orderpluspnts-1; + + /* this is for float inaccuracy */ + if(t < knots[0]) t= knots[0]; + else if(t > knots[opp2]) t= knots[opp2]; + + /* this part is order '1' */ + o2 = order + 1; + for(i=0;i= knots[i] && t<=knots[i+1]) { + basis[i]= 1.0; + i1= i-o2; + if(i1<0) i1= 0; + i2= i; + i++; + while(i= orderpluspnts) i2= opp2-j; + + for(i= i1; i<=i2; i++) { + if(basis[i]!=0.0) + d= ((t-knots[i])*basis[i]) / (knots[i+j-1]-knots[i]); + else + d= 0.0; + + if(basis[i+1]!=0.0) + e= ((knots[i+j]-t)*basis[i+1]) / (knots[i+j]-knots[i+1]); + else + e= 0.0; + + basis[i]= d+e; + } + } + + *start= 1000; + *end= 0; + + for(i=i1; i<=i2; i++) { + if(basis[i]>0.0) { + *end= i; + if(*start==1000) *start= i; + } + } +} + + +void makeNurbfaces(Nurb *nu, float *data, int rowstride) +/* data has to be 3*4*resolu*resolv in size, and zero-ed */ +{ + BPoint *bp; + float *basisu, *basis, *basisv, *sum, *fp, *in; + float u, v, ustart, uend, ustep, vstart, vend, vstep, sumdiv; + int i, j, iofs, jofs, cycl, len, resolu, resolv; + int istart, iend, jsta, jen, *jstart, *jend, ratcomp; + + if(nu->knotsu==0 || nu->knotsv==0) return; + if(nu->orderu>nu->pntsu) return; + if(nu->orderv>nu->pntsv) return; + if(data==0) return; + + /* allocate and initialize */ + len= nu->pntsu*nu->pntsv; + if(len==0) return; + + + + sum= (float *)MEM_callocN(sizeof(float)*len, "makeNurbfaces1"); + + resolu= nu->resolu; + resolv= nu->resolv; + len= resolu*resolv; + if(len==0) { + MEM_freeN(sum); + return; + } + + bp= nu->bp; + i= nu->pntsu*nu->pntsv; + ratcomp=0; + while(i--) { + if(bp->vec[3]!=1.0) { + ratcomp= 1; + break; + } + bp++; + } + + fp= nu->knotsu; + ustart= fp[nu->orderu-1]; + if(nu->flagu & 1) uend= fp[nu->pntsu+nu->orderu-1]; + else uend= fp[nu->pntsu]; + ustep= (uend-ustart)/(resolu-1+(nu->flagu & 1)); + basisu= (float *)MEM_mallocN(sizeof(float)*KNOTSU(nu), "makeNurbfaces3"); + + fp= nu->knotsv; + vstart= fp[nu->orderv-1]; + + if(nu->flagv & 1) vend= fp[nu->pntsv+nu->orderv-1]; + else vend= fp[nu->pntsv]; + vstep= (vend-vstart)/(resolv-1+(nu->flagv & 1)); + len= KNOTSV(nu); + basisv= (float *)MEM_mallocN(sizeof(float)*len*resolv, "makeNurbfaces3"); + jstart= (int *)MEM_mallocN(sizeof(float)*resolv, "makeNurbfaces4"); + jend= (int *)MEM_mallocN(sizeof(float)*resolv, "makeNurbfaces5"); + + /* precalculation of basisv and jstart,jend */ + if(nu->flagv & 1) cycl= nu->orderv-1; + else cycl= 0; + v= vstart; + basis= basisv; + while(resolv--) { + basisNurb(v, nu->orderv, (short)(nu->pntsv+cycl), nu->knotsv, basis, jstart+resolv, jend+resolv); + basis+= KNOTSV(nu); + v+= vstep; + } + + if(nu->flagu & 1) cycl= nu->orderu-1; + else cycl= 0; + in= data; + u= ustart; + while(resolu--) { + + basisNurb(u, nu->orderu, (short)(nu->pntsu+cycl), nu->knotsu, basisu, &istart, &iend); + + basis= basisv; + resolv= nu->resolv; + while(resolv--) { + + jsta= jstart[resolv]; + jen= jend[resolv]; + + /* calculate sum */ + sumdiv= 0.0; + fp= sum; + + for(j= jsta; j<=jen; j++) { + + if(j>=nu->pntsv) jofs= (j - nu->pntsv); + else jofs= j; + bp= nu->bp+ nu->pntsu*jofs+istart-1; + + for(i= istart; i<=iend; i++, fp++) { + + if(i>= nu->pntsu) { + iofs= i- nu->pntsu; + bp= nu->bp+ nu->pntsu*jofs+iofs; + } + else bp++; + + if(ratcomp) { + *fp= basisu[i]*basis[j]*bp->vec[3]; + sumdiv+= *fp; + } + else *fp= basisu[i]*basis[j]; + } + } + + if(ratcomp) { + fp= sum; + for(j= jsta; j<=jen; j++) { + for(i= istart; i<=iend; i++, fp++) { + *fp/= sumdiv; + } + } + } + + /* one! (1.0) real point now */ + fp= sum; + for(j= jsta; j<=jen; j++) { + + if(j>=nu->pntsv) jofs= (j - nu->pntsv); + else jofs= j; + bp= nu->bp+ nu->pntsu*jofs+istart-1; + + for(i= istart; i<=iend; i++, fp++) { + + if(i>= nu->pntsu) { + iofs= i- nu->pntsu; + bp= nu->bp+ nu->pntsu*jofs+iofs; + } + else bp++; + + if(*fp!=0.0) { + in[0]+= (*fp) * bp->vec[0]; + in[1]+= (*fp) * bp->vec[1]; + in[2]+= (*fp) * bp->vec[2]; + } + } + } + + in+=3; + basis+= KNOTSV(nu); + } + u+= ustep; + if (rowstride!=0) in = (float*) (((unsigned char*) in) + (rowstride - 3*nu->resolv*sizeof(*in))); + } + + /* free */ + MEM_freeN(sum); + MEM_freeN(basisu); + MEM_freeN(basisv); + MEM_freeN(jstart); + MEM_freeN(jend); +} + +void makeNurbcurve(Nurb *nu, float *data, int resolu, int dim) +/* data has to be dim*4*pntsu*resolu in size and zero-ed */ +{ + BPoint *bp; + float u, ustart, uend, ustep, sumdiv; + float *basisu, *sum, *fp, *in; + int i, len, istart, iend, cycl; + + if(nu->knotsu==0) return; + if(nu->orderu>nu->pntsu) return; + if(data==0) return; + + /* allocate and initialize */ + len= nu->pntsu; + if(len==0) return; + sum= (float *)MEM_callocN(sizeof(float)*len, "makeNurbcurve1"); + + resolu*= nu->pntsu; + if(resolu==0) { + MEM_freeN(sum); + return; + } + + fp= nu->knotsu; + ustart= fp[nu->orderu-1]; + if(nu->flagu & 1) uend= fp[nu->pntsu+nu->orderu-1]; + else uend= fp[nu->pntsu]; + ustep= (uend-ustart)/(resolu-1+(nu->flagu & 1)); + basisu= (float *)MEM_mallocN(sizeof(float)*KNOTSU(nu), "makeNurbcurve3"); + + if(nu->flagu & 1) cycl= nu->orderu-1; + else cycl= 0; + + in= data; + u= ustart; + while(resolu--) { + + basisNurb(u, nu->orderu, (short)(nu->pntsu+cycl), nu->knotsu, basisu, &istart, &iend); + /* calc sum */ + sumdiv= 0.0; + fp= sum; + bp= nu->bp+ istart-1; + for(i= istart; i<=iend; i++, fp++) { + + if(i>=nu->pntsu) bp= nu->bp+(i - nu->pntsu); + else bp++; + + *fp= basisu[i]*bp->vec[3]; + sumdiv+= *fp; + } + if(sumdiv!=0.0) if(sumdiv<0.999 || sumdiv>1.001) { + /* is normalizing needed? */ + fp= sum; + for(i= istart; i<=iend; i++, fp++) { + *fp/= sumdiv; + } + } + + /* one! (1.0) real point */ + fp= sum; + bp= nu->bp+ istart-1; + for(i= istart; i<=iend; i++, fp++) { + + if(i>=nu->pntsu) bp= nu->bp+(i - nu->pntsu); + else bp++; + + if(*fp!=0.0) { + + in[0]+= (*fp) * bp->vec[0]; + in[1]+= (*fp) * bp->vec[1]; + if(dim>=3) { + in[2]+= (*fp) * bp->vec[2]; + if(dim==4) in[3]+= (*fp) * bp->alfa; + } + } + } + + in+= dim; + + u+= ustep; + } + + /* free */ + MEM_freeN(sum); + MEM_freeN(basisu); +} + +/* forward differencing method for bezier curve */ +void forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride) +{ + float rt0,rt1,rt2,rt3,f; + int a; + + f= (float)it; + rt0= q0; + rt1= 3.0f*(q1-q0)/f; + f*= f; + rt2= 3.0f*(q0-2.0f*q1+q2)/f; + f*= it; + rt3= (q3-q0+3.0f*(q1-q2))/f; + + q0= rt0; + q1= rt1+rt2+rt3; + q2= 2*rt2+6*rt3; + q3= 6*rt3; + + for(a=0; a<=it; a++) { + *p= q0; + p+= stride; + q0+= q1; + q1+= q2; + q2+= q3; + } +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +float *make_orco_surf(Object *ob) +{ + Curve *cu= ob->data; + Nurb *nu; + int a, b, tot=0; + int sizeu, sizev; + float *data, *orco; + + /* first calculate the size of the datablock */ + nu= cu->nurb.first; + while(nu) { + /* as we want to avoid the seam in a cyclic nurbs + texture wrapping, reserve extra orco data space to save these extra needed + vertex based UV coordinates for the meridian vertices. + Vertices on the 0/2pi boundary are not duplicated inside the displist but later in + the renderface/vert construction. + + See also convertblender.c: init_render_surf() + */ + + sizeu = nu->resolu; + sizev = nu->resolv; + if (nu->flagu & CU_CYCLIC) sizeu++; + if (nu->flagv & CU_CYCLIC) sizev++; + if(nu->pntsv>1) tot+= sizeu * sizev; + + nu= nu->next; + } + /* makeNurbfaces wants zeros */ + data= orco= MEM_callocN(3*sizeof(float)*tot, "make_orco"); + + nu= cu->nurb.first; + while(nu) { + if(nu->pntsv>1) { + sizeu = nu->resolu; + sizev = nu->resolv; + if (nu->flagu & CU_CYCLIC) sizeu++; + if (nu->flagv & CU_CYCLIC) sizev++; + + if(cu->flag & CU_UV_ORCO) { + for(b=0; b< sizeu; b++) { + for(a=0; a< sizev; a++) { + + if(sizev <2) data[0]= 0.0f; + else data[0]= -1.0f + 2.0f*((float)a)/(sizev - 1); + + if(sizeu <2) data[1]= 0.0f; + else data[1]= -1.0f + 2.0f*((float)b)/(sizeu - 1); + + data[2]= 0.0; + + data+= 3; + } + } + } + else { + float *_tdata= MEM_callocN(nu->resolu*nu->resolv*3*sizeof(float), "temp data"); + float *tdata= _tdata; + + makeNurbfaces(nu, tdata, 0); + + for(b=0; bflagu & CU_CYCLIC)) + use_b= 0; + + for(a=0; aflagv & CU_CYCLIC)) + use_a= 0; + + tdata = _tdata + 3 * (use_b * nu->resolv + use_a); + + data[0]= (tdata[0]-cu->loc[0])/cu->size[0]; + data[1]= (tdata[1]-cu->loc[1])/cu->size[1]; + data[2]= (tdata[2]-cu->loc[2])/cu->size[2]; + data+= 3; + } + } + + MEM_freeN(_tdata); + } + } + nu= nu->next; + } + + return orco; +} + + + /* NOTE: This routine is tied to the order of vertex + * built by displist and as passed to the renderer. + */ +float *make_orco_curve(Object *ob) +{ + Curve *cu = ob->data; + DispList *dl; + int u, v, numVerts; + float *fp, *orco; + int remakeDisp = 0; + + if (!(cu->flag&CU_UV_ORCO) && cu->key && cu->key->refkey) { + cp_cu_key(cu, cu->key->refkey, 0, count_curveverts(&cu->nurb)); + makeDispListCurveTypes(ob, 1); + remakeDisp = 1; + } + + /* Assumes displist has been built */ + + numVerts = 0; + for (dl=cu->disp.first; dl; dl=dl->next) { + if (dl->type==DL_INDEX3) { + numVerts += dl->nr; + } else if (dl->type==DL_SURF) { + /* convertblender.c uses the Surface code for creating renderfaces when cyclic U only (closed circle beveling) */ + if (dl->flag & DL_CYCL_U) { + if (dl->flag & DL_CYCL_V) + numVerts += (dl->parts+1)*(dl->nr+1); + else + numVerts += dl->parts*(dl->nr+1); + } + else + numVerts += dl->parts*dl->nr; + } + } + + fp= orco= MEM_mallocN(3*sizeof(float)*numVerts, "cu_orco"); + for (dl=cu->disp.first; dl; dl=dl->next) { + if (dl->type==DL_INDEX3) { + for (u=0; unr; u++, fp+=3) { + if (cu->flag & CU_UV_ORCO) { + fp[0]= 2.0f*u/(dl->nr-1) - 1.0f; + fp[1]= 0.0; + fp[2]= 0.0; + } else { + VECCOPY(fp, &dl->verts[u*3]); + + fp[0]= (fp[0]-cu->loc[0])/cu->size[0]; + fp[1]= (fp[1]-cu->loc[1])/cu->size[1]; + fp[2]= (fp[2]-cu->loc[2])/cu->size[2]; + } + } + } else if (dl->type==DL_SURF) { + int sizeu= dl->nr, sizev= dl->parts; + + /* exception as handled in convertblender.c too */ + if (dl->flag & DL_CYCL_U) { + sizeu++; + if (dl->flag & DL_CYCL_V) + sizev++; + } + + for (u=0; uflag & CU_UV_ORCO) { + fp[0]= 2.0f*u/(dl->parts-1) - 1.0f; + fp[1]= 2.0f*v/(dl->nr-1) - 1.0f; + fp[2]= 0.0; + } else { + int realv= v % dl->nr; + + VECCOPY(fp, &dl->verts[(dl->nr*u + realv)*3]); + + fp[0]= (fp[0]-cu->loc[0])/cu->size[0]; + fp[1]= (fp[1]-cu->loc[1])/cu->size[1]; + fp[2]= (fp[2]-cu->loc[2])/cu->size[2]; + } + } + } + } + } + + if (remakeDisp) { + makeDispListCurveTypes(ob, 0); + } + + return orco; +} + + +/* ***************** BEVEL ****************** */ + +void makebevelcurve(Object *ob, ListBase *disp) +{ + DispList *dl, *dlnew; + Curve *bevcu, *cu; + float *fp, facx, facy, angle, dangle; + int nr, a; + + cu= ob->data; + disp->first = disp->last = NULL; + + /* if a font object is being edited, then do nothing */ + if( ob == G.obedit && ob->type == OB_FONT ) return; + + if(cu->bevobj && cu->bevobj!=ob) { + if(cu->bevobj->type==OB_CURVE) { + bevcu= cu->bevobj->data; + if(bevcu->ext1==0.0 && bevcu->ext2==0.0) { + facx= cu->bevobj->size[0]; + facy= cu->bevobj->size[1]; + + dl= bevcu->disp.first; + if(dl==0) { + makeDispListCurveTypes(cu->bevobj, 0); + dl= bevcu->disp.first; + } + while(dl) { + if ELEM(dl->type, DL_POLY, DL_SEGM) { + dlnew= MEM_mallocN(sizeof(DispList), "makebevelcurve1"); + *dlnew= *dl; + dlnew->verts= MEM_mallocN(3*sizeof(float)*dl->parts*dl->nr, "makebevelcurve1"); + memcpy(dlnew->verts, dl->verts, 3*sizeof(float)*dl->parts*dl->nr); + + if(dlnew->type==DL_SEGM) dlnew->flag |= (DL_FRONT_CURVE|DL_BACK_CURVE); + + BLI_addtail(disp, dlnew); + fp= dlnew->verts; + nr= dlnew->parts*dlnew->nr; + while(nr--) { + fp[2]= fp[1]*facy; + fp[1]= -fp[0]*facx; + fp[0]= 0.0; + fp+= 3; + } + } + dl= dl->next; + } + } + } + } + else if(cu->ext1==0.0 && cu->ext2==0.0) { + ; + } + else if(cu->ext2==0.0) { + dl= MEM_callocN(sizeof(DispList), "makebevelcurve2"); + dl->verts= MEM_mallocN(2*3*sizeof(float), "makebevelcurve2"); + BLI_addtail(disp, dl); + dl->type= DL_SEGM; + dl->parts= 1; + dl->flag= DL_FRONT_CURVE|DL_BACK_CURVE; + dl->nr= 2; + + fp= dl->verts; + fp[0]= fp[1]= 0.0; + fp[2]= -cu->ext1; + fp[3]= fp[4]= 0.0; + fp[5]= cu->ext1; + } + else if( (cu->flag & (CU_FRONT|CU_BACK))==0 && cu->ext1==0.0f) { // we make a full round bevel in that case + + nr= 4+ 2*cu->bevresol; + + dl= MEM_callocN(sizeof(DispList), "makebevelcurve p1"); + dl->verts= MEM_mallocN(nr*3*sizeof(float), "makebevelcurve p1"); + BLI_addtail(disp, dl); + dl->type= DL_POLY; + dl->parts= 1; + dl->flag= DL_BACK_CURVE; + dl->nr= nr; + + /* a circle */ + fp= dl->verts; + dangle= (2.0f*M_PI/(nr)); + angle= -(nr-1)*dangle; + + for(a=0; aext2)); + fp[2]= (float)(sin(angle)*(cu->ext2)) - cu->ext1; + angle+= dangle; + fp+= 3; + } + } + else { + short dnr; + + /* bevel now in three parts, for proper vertex normals */ + /* part 1 */ + dnr= nr= 2+ cu->bevresol; + if( (cu->flag & (CU_FRONT|CU_BACK))==0) + nr= 3+ 2*cu->bevresol; + + dl= MEM_callocN(sizeof(DispList), "makebevelcurve p1"); + dl->verts= MEM_mallocN(nr*3*sizeof(float), "makebevelcurve p1"); + BLI_addtail(disp, dl); + dl->type= DL_SEGM; + dl->parts= 1; + dl->flag= DL_BACK_CURVE; + dl->nr= nr; + + /* half a circle */ + fp= dl->verts; + dangle= (0.5*M_PI/(dnr-1)); + angle= -(nr-1)*dangle; + + for(a=0; aext2)); + fp[2]= (float)(sin(angle)*(cu->ext2)) - cu->ext1; + angle+= dangle; + fp+= 3; + } + + /* part 2, sidefaces */ + if(cu->ext1!=0.0) { + nr= 2; + + dl= MEM_callocN(sizeof(DispList), "makebevelcurve p2"); + dl->verts= MEM_callocN(nr*3*sizeof(float), "makebevelcurve p2"); + BLI_addtail(disp, dl); + dl->type= DL_SEGM; + dl->parts= 1; + dl->nr= nr; + + fp= dl->verts; + fp[1]= cu->ext2; + fp[2]= -cu->ext1; + fp[4]= cu->ext2; + fp[5]= cu->ext1; + + if( (cu->flag & (CU_FRONT|CU_BACK))==0) { + dl= MEM_dupallocN(dl); + dl->verts= MEM_dupallocN(dl->verts); + BLI_addtail(disp, dl); + + fp= dl->verts; + fp[1]= -fp[1]; + fp[2]= -fp[2]; + fp[4]= -fp[4]; + fp[5]= -fp[5]; + } + } + + /* part 3 */ + dnr= nr= 2+ cu->bevresol; + if( (cu->flag & (CU_FRONT|CU_BACK))==0) + nr= 3+ 2*cu->bevresol; + + dl= MEM_callocN(sizeof(DispList), "makebevelcurve p3"); + dl->verts= MEM_mallocN(nr*3*sizeof(float), "makebevelcurve p3"); + BLI_addtail(disp, dl); + dl->type= DL_SEGM; + dl->flag= DL_FRONT_CURVE; + dl->parts= 1; + dl->nr= nr; + + /* half a circle */ + fp= dl->verts; + angle= 0.0; + dangle= (0.5*M_PI/(dnr-1)); + + for(a=0; aext2)); + fp[2]= (float)(sin(angle)*(cu->ext2)) + cu->ext1; + angle+= dangle; + fp+= 3; + } + } +} + +int cu_isectLL(float *v1, float *v2, float *v3, float *v4, short cox, short coy, float *labda, float *mu, float *vec) +{ + /* return: + -1: colliniar + 0: no intersection of segments + 1: exact intersection of segments + 2: cross-intersection of segments + */ + float deler; + + deler= (v1[cox]-v2[cox])*(v3[coy]-v4[coy])-(v3[cox]-v4[cox])*(v1[coy]-v2[coy]); + if(deler==0.0) return -1; + + *labda= (v1[coy]-v3[coy])*(v3[cox]-v4[cox])-(v1[cox]-v3[cox])*(v3[coy]-v4[coy]); + *labda= -(*labda/deler); + + deler= v3[coy]-v4[coy]; + if(deler==0) { + deler=v3[cox]-v4[cox]; + *mu= -(*labda*(v2[cox]-v1[cox])+v1[cox]-v3[cox])/deler; + } else { + *mu= -(*labda*(v2[coy]-v1[coy])+v1[coy]-v3[coy])/deler; + } + vec[cox]= *labda*(v2[cox]-v1[cox])+v1[cox]; + vec[coy]= *labda*(v2[coy]-v1[coy])+v1[coy]; + + if(*labda>=0.0 && *labda<=1.0 && *mu>=0.0 && *mu<=1.0) { + if(*labda==0.0 || *labda==1.0 || *mu==0.0 || *mu==1.0) return 1; + return 2; + } + return 0; +} + + +static short bevelinside(BevList *bl1,BevList *bl2) +{ + /* is bl2 INSIDE bl1 ? with left-right method and "labda's" */ + /* returns '1' if correct hole */ + BevPoint *bevp, *prevbevp; + float min,max,vec[3],hvec1[3],hvec2[3],lab,mu; + int nr, links=0,rechts=0,mode; + + /* take first vertex of possible hole */ + + bevp= (BevPoint *)(bl2+1); + hvec1[0]= bevp->x; + hvec1[1]= bevp->y; + hvec1[2]= 0.0; + VECCOPY(hvec2,hvec1); + hvec2[0]+=1000; + + /* test it with all edges of potential surounding poly */ + /* count number of transitions left-right */ + + bevp= (BevPoint *)(bl1+1); + nr= bl1->nr; + prevbevp= bevp+(nr-1); + + while(nr--) { + min= prevbevp->y; + max= bevp->y; + if(maxy; + } + if(min!=max) { + if(min<=hvec1[1] && max>=hvec1[1]) { + /* there's a transition, calc intersection point */ + mode= cu_isectLL(&(prevbevp->x),&(bevp->x),hvec1,hvec2,0,1,&lab,&mu,vec); + /* if lab==0.0 or lab==1.0 then the edge intersects exactly a transition + only allow for one situation: we choose lab= 1.0 + */ + if(mode>=0 && lab!=0.0) { + if(vec[0]left > x2->left ) return 1; + else if( x1->left < x2->left) return -1; + return 0; +} + +/* this function cannot be replaced with atan2, but why? */ + +static void calc_bevel_sin_cos(float x1, float y1, float x2, float y2, float *sina, float *cosa) +{ + float t01, t02, x3, y3; + + t01= (float)sqrt(x1*x1+y1*y1); + t02= (float)sqrt(x2*x2+y2*y2); + if(t01==0.0) t01= 1.0; + if(t02==0.0) t02= 1.0; + + x1/=t01; + y1/=t01; + x2/=t02; + y2/=t02; + + t02= x1*x2+y1*y2; + if(fabs(t02)>=1.0) t02= .5*M_PI; + else t02= (saacos(t02))/2.0f; + + t02= (float)sin(t02); + if(t02==0.0) t02= 1.0; + + x3= x1-x2; + y3= y1-y2; + if(x3==0 && y3==0) { + x3= y1; + y3= -x1; + } else { + t01= (float)sqrt(x3*x3+y3*y3); + x3/=t01; + y3/=t01; + } + + *sina= -y3/t02; + *cosa= x3/t02; + +} + +static void alfa_bezpart(BezTriple *prevbezt, BezTriple *bezt, Nurb *nu, float *data_a, int resolu) +{ + BezTriple *pprev, *next, *last; + float fac, dfac, t[4]; + int a; + + last= nu->bezt+(nu->pntsu-1); + + /* returns a point */ + if(prevbezt==nu->bezt) { + if(nu->flagu & 1) pprev= last; + else pprev= prevbezt; + } + else pprev= prevbezt-1; + + /* next point */ + if(bezt==last) { + if(nu->flagu & 1) next= nu->bezt; + else next= bezt; + } + else next= bezt+1; + + fac= 0.0; + dfac= 1.0f/(float)resolu; + + for(a=0; atilt_interp); + + data_a[a]= t[0]*pprev->alfa + t[1]*prevbezt->alfa + t[2]*bezt->alfa + t[3]*next->alfa; + } +} + +void makeBevelList(Object *ob) +{ + /* + - convert all curves to polys, with indication of resol and flags for double-vertices + - possibly; do a smart vertice removal (in case Nurb) + - separate in individual blicks with BoundBox + - AutoHole detection + */ + Curve *cu; + Nurb *nu; + BezTriple *bezt, *prevbezt; + BPoint *bp; + BevList *bl, *blnew, *blnext; + BevPoint *bevp, *bevp2, *bevp1 = NULL, *bevp0; + float *data, *data_a, *v1, *v2, min, inp, x1, x2, y1, y2, vec[3]; + struct bevelsort *sortdata, *sd, *sd1; + int a, b, len, nr, poly, resolu; + + /* this function needs an object, because of tflag and upflag */ + cu= ob->data; + + /* STEP 1: MAKE POLYS */ + + BLI_freelistN(&(cu->bev)); + if(ob==G.obedit && ob->type!=OB_FONT) nu= editNurb.first; + else nu= cu->nurb.first; + + while(nu) { + if(nu->pntsu>1) { + if(G.rendering && cu->resolu_ren!=0) + resolu= cu->resolu_ren; + else + resolu= nu->resolu; + + if((nu->type & 7)==CU_POLY) { + + len= nu->pntsu; + bl= MEM_callocN(sizeof(BevList)+len*sizeof(BevPoint), "makeBevelList"); + BLI_addtail(&(cu->bev), bl); + + if(nu->flagu & 1) bl->poly= 0; + else bl->poly= -1; + bl->nr= len; + bl->flag= 0; + bevp= (BevPoint *)(bl+1); + bp= nu->bp; + + while(len--) { + bevp->x= bp->vec[0]; + bevp->y= bp->vec[1]; + bevp->z= bp->vec[2]; + bevp->alfa= bp->alfa; + bevp->f1= 1; + bevp++; + bp++; + } + } + else if((nu->type & 7)==CU_BEZIER) { + + len= resolu*(nu->pntsu+ (nu->flagu & 1) -1)+1; /* in case last point is not cyclic */ + bl= MEM_callocN(sizeof(BevList)+len*sizeof(BevPoint), "makeBevelList"); + BLI_addtail(&(cu->bev), bl); + + if(nu->flagu & 1) bl->poly= 0; + else bl->poly= -1; + bevp= (BevPoint *)(bl+1); + + a= nu->pntsu-1; + bezt= nu->bezt; + if(nu->flagu & 1) { + a++; + prevbezt= nu->bezt+(nu->pntsu-1); + } + else { + prevbezt= bezt; + bezt++; + } + + data= MEM_mallocN(3*sizeof(float)*(resolu+1), "makeBevelList2"); + data_a= MEM_callocN(sizeof(float)*(resolu+1), "data_a"); + + while(a--) { + if(prevbezt->h2==HD_VECT && bezt->h1==HD_VECT) { + + bevp->x= prevbezt->vec[1][0]; + bevp->y= prevbezt->vec[1][1]; + bevp->z= prevbezt->vec[1][2]; + bevp->alfa= prevbezt->alfa; + bevp->f1= 1; + bevp->f2= 0; + bevp++; + bl->nr++; + bl->flag= 1; + } + else { + v1= prevbezt->vec[1]; + v2= bezt->vec[0]; + + /* always do all three, to prevent data hanging around */ + forward_diff_bezier(v1[0], v1[3], v2[0], v2[3], data, resolu, 3); + forward_diff_bezier(v1[1], v1[4], v2[1], v2[4], data+1, resolu, 3); + forward_diff_bezier(v1[2], v1[5], v2[2], v2[5], data+2, resolu, 3); + + if((nu->type & CU_2D)==0) { + if(cu->flag & CU_3D) { + alfa_bezpart(prevbezt, bezt, nu, data_a, resolu); + } + } + + + /* indicate with handlecodes double points */ + if(prevbezt->h1==prevbezt->h2) { + if(prevbezt->h1==0 || prevbezt->h1==HD_VECT) bevp->f1= 1; + } + else { + if(prevbezt->h1==0 || prevbezt->h1==HD_VECT) bevp->f1= 1; + else if(prevbezt->h2==0 || prevbezt->h2==HD_VECT) bevp->f1= 1; + } + + v1= data; + v2= data_a; + nr= resolu; + + while(nr--) { + bevp->x= v1[0]; + bevp->y= v1[1]; + bevp->z= v1[2]; + bevp->alfa= v2[0]; + bevp++; + v1+=3; + v2++; + } + bl->nr+= resolu; + + } + prevbezt= bezt; + bezt++; + } + + MEM_freeN(data); + MEM_freeN(data_a); + + if((nu->flagu & 1)==0) { /* not cyclic: endpoint */ + bevp->x= prevbezt->vec[1][0]; + bevp->y= prevbezt->vec[1][1]; + bevp->z= prevbezt->vec[1][2]; + bevp->alfa= prevbezt->alfa; + bl->nr++; + } + + } + else if((nu->type & 7)==CU_NURBS) { + if(nu->pntsv==1) { + len= resolu*nu->pntsu; + bl= MEM_mallocN(sizeof(BevList)+len*sizeof(BevPoint), "makeBevelList3"); + BLI_addtail(&(cu->bev), bl); + bl->nr= len; + bl->flag= 0; + if(nu->flagu & 1) bl->poly= 0; + else bl->poly= -1; + bevp= (BevPoint *)(bl+1); + + data= MEM_callocN(4*sizeof(float)*len, "makeBevelList4"); /* has to be zero-ed */ + makeNurbcurve(nu, data, resolu, 4); + + v1= data; + while(len--) { + bevp->x= v1[0]; + bevp->y= v1[1]; + bevp->z= v1[2]; + bevp->alfa= v1[3]; + + bevp->f1= bevp->f2= 0; + bevp++; + v1+=4; + } + MEM_freeN(data); + } + } + } + nu= nu->next; + } + + /* STEP 2: DOUBLE POINTS AND AUTOMATIC RESOLUTION, REDUCE DATABLOCKS */ + bl= cu->bev.first; + while(bl) { + nr= bl->nr; + bevp1= (BevPoint *)(bl+1); + bevp0= bevp1+(nr-1); + nr--; + while(nr--) { + if( fabs(bevp0->x-bevp1->x)<0.00001 ) { + if( fabs(bevp0->y-bevp1->y)<0.00001 ) { + if( fabs(bevp0->z-bevp1->z)<0.00001 ) { + bevp0->f2= 1; + bl->flag++; + } + } + } + bevp0= bevp1; + bevp1++; + } + bl= bl->next; + } + bl= cu->bev.first; + while(bl) { + blnext= bl->next; + if(bl->flag) { + nr= bl->nr- bl->flag+1; /* +1 because vectorbezier sets flag too */ + blnew= MEM_mallocN(sizeof(BevList)+nr*sizeof(BevPoint), "makeBevelList"); + memcpy(blnew, bl, sizeof(BevList)); + blnew->nr= 0; + BLI_remlink(&(cu->bev), bl); + BLI_insertlinkbefore(&(cu->bev),blnext,blnew); /* to make sure bevlijst is tuned with nurblist */ + bevp0= (BevPoint *)(bl+1); + bevp1= (BevPoint *)(blnew+1); + nr= bl->nr; + while(nr--) { + if(bevp0->f2==0) { + memcpy(bevp1, bevp0, sizeof(BevPoint)); + bevp1++; + blnew->nr++; + } + bevp0++; + } + MEM_freeN(bl); + blnew->flag= 0; + } + bl= blnext; + } + + /* STEP 3: COUNT POLYS TELLEN AND AUTOHOLE */ + bl= cu->bev.first; + poly= 0; + while(bl) { + if(bl->poly>=0) { + poly++; + bl->poly= poly; + bl->gat= 0; /* 'gat' is dutch for hole */ + } + bl= bl->next; + } + + + /* find extreme left points, also test (turning) direction */ + if(poly>0) { + sd= sortdata= MEM_mallocN(sizeof(struct bevelsort)*poly, "makeBevelList5"); + bl= cu->bev.first; + while(bl) { + if(bl->poly>0) { + + min= 300000.0; + bevp= (BevPoint *)(bl+1); + nr= bl->nr; + while(nr--) { + if(min>bevp->x) { + min= bevp->x; + bevp1= bevp; + } + bevp++; + } + sd->bl= bl; + sd->left= min; + + bevp= (BevPoint *)(bl+1); + if(bevp1== bevp) bevp0= bevp+ (bl->nr-1); + else bevp0= bevp1-1; + bevp= bevp+ (bl->nr-1); + if(bevp1== bevp) bevp2= (BevPoint *)(bl+1); + else bevp2= bevp1+1; + + inp= (bevp1->x- bevp0->x)*(bevp0->y- bevp2->y) + +(bevp0->y- bevp1->y)*(bevp0->x- bevp2->x); + + if(inp>0.0) sd->dir= 1; + else sd->dir= 0; + + sd++; + } + + bl= bl->next; + } + qsort(sortdata,poly,sizeof(struct bevelsort), vergxcobev); + + sd= sortdata+1; + for(a=1; abl; /* is bl a hole? */ + sd1= sortdata+ (a-1); + for(b=a-1; b>=0; b--, sd1--) { /* all polys to the left */ + if(bevelinside(sd1->bl, bl)) { + bl->gat= 1- sd1->bl->gat; + break; + } + } + } + + /* turning direction */ + if((cu->flag & CU_3D)==0) { + sd= sortdata; + for(a=0; abl->gat==sd->dir) { + bl= sd->bl; + bevp1= (BevPoint *)(bl+1); + bevp2= bevp1+ (bl->nr-1); + nr= bl->nr/2; + while(nr--) { + SWAP(BevPoint, *bevp1, *bevp2); + bevp1++; + bevp2--; + } + } + } + } + MEM_freeN(sortdata); + } + + /* STEP 4: COSINES */ + bl= cu->bev.first; + while(bl) { + + if(bl->nr==2) { /* 2 pnt, treat separate */ + bevp2= (BevPoint *)(bl+1); + bevp1= bevp2+1; + + x1= bevp1->x- bevp2->x; + y1= bevp1->y- bevp2->y; + + calc_bevel_sin_cos(x1, y1, -x1, -y1, &(bevp1->sina), &(bevp1->cosa)); + bevp2->sina= bevp1->sina; + bevp2->cosa= bevp1->cosa; + + if(cu->flag & CU_3D) { /* 3D */ + float *quat, q[4]; + + vec[0]= bevp1->x - bevp2->x; + vec[1]= bevp1->y - bevp2->y; + vec[2]= bevp1->z - bevp2->z; + + quat= vectoquat(vec, 5, 1); + + Normalize(vec); + q[0]= (float)cos(0.5*bevp1->alfa); + x1= (float)sin(0.5*bevp1->alfa); + q[1]= x1*vec[0]; + q[2]= x1*vec[1]; + q[3]= x1*vec[2]; + QuatMul(quat, q, quat); + + QuatToMat3(quat, bevp1->mat); + Mat3CpyMat3(bevp2->mat, bevp1->mat); + } + + } + else if(bl->nr>2) { + bevp2= (BevPoint *)(bl+1); + bevp1= bevp2+(bl->nr-1); + bevp0= bevp1-1; + + + nr= bl->nr; + + while(nr--) { + + if(cu->flag & CU_3D) { /* 3D */ + float *quat, q[4]; + + vec[0]= bevp2->x - bevp0->x; + vec[1]= bevp2->y - bevp0->y; + vec[2]= bevp2->z - bevp0->z; + + Normalize(vec); + + quat= vectoquat(vec, 5, 1); + + q[0]= (float)cos(0.5*bevp1->alfa); + x1= (float)sin(0.5*bevp1->alfa); + q[1]= x1*vec[0]; + q[2]= x1*vec[1]; + q[3]= x1*vec[2]; + QuatMul(quat, q, quat); + + QuatToMat3(quat, bevp1->mat); + } + + x1= bevp1->x- bevp0->x; + x2= bevp1->x- bevp2->x; + y1= bevp1->y- bevp0->y; + y2= bevp1->y- bevp2->y; + + calc_bevel_sin_cos(x1, y1, x2, y2, &(bevp1->sina), &(bevp1->cosa)); + + + bevp0= bevp1; + bevp1= bevp2; + bevp2++; + } + /* correct non-cyclic cases */ + if(bl->poly== -1) { + if(bl->nr>2) { + bevp= (BevPoint *)(bl+1); + bevp1= bevp+1; + bevp->sina= bevp1->sina; + bevp->cosa= bevp1->cosa; + Mat3CpyMat3(bevp->mat, bevp1->mat); + bevp= (BevPoint *)(bl+1); + bevp+= (bl->nr-1); + bevp1= bevp-1; + bevp->sina= bevp1->sina; + bevp->cosa= bevp1->cosa; + Mat3CpyMat3(bevp->mat, bevp1->mat); + } + } + } + bl= bl->next; + } +} + +/* calculates a bevel width (radius) for a particular subdivided curve part, + * based on the radius value of the surrounding CVs */ +float calc_curve_subdiv_radius(Curve *cu, Nurb *nu, int cursubdiv) +{ + BezTriple *bezt, *beztfirst, *beztlast, *beztnext, *beztprev; + BPoint *bp, *bpfirst, *bplast; + int resolu; + float prevrad=0.0, nextrad=0.0, rad=0.0, ratio=0.0; + int vectseg=0, subdivs=0; + + if((nu==NULL) || (nu->pntsu<=1)) return 1.0; + bezt= nu->bezt; + bp = nu->bp; + + if(G.rendering && cu->resolu_ren!=0) resolu= cu->resolu_ren; + else resolu= nu->resolu; + + if(((nu->type & 7)==CU_BEZIER) && (bezt != NULL)) { + beztfirst = nu->bezt; + beztlast = nu->bezt + (nu->pntsu - 1); + + /* loop through the CVs to end up with a pointer to the CV before the subdiv in question, and a ratio + * of how far that subdiv is between this CV and the next */ + while(bezt<=beztlast) { + beztnext = bezt+1; + beztprev = bezt-1; + vectseg=0; + + if (subdivs==cursubdiv) { + ratio= 0.0; + break; + } + + /* check to see if we're looking at a vector segment (no subdivisions) */ + if (nu->flagu & CU_CYCLIC) { + if (bezt == beztfirst) { + if ((beztlast->h2==HD_VECT) && (bezt->h1==HD_VECT)) vectseg = 1; + } else { + if ((beztprev->h2==HD_VECT) && (bezt->h1==HD_VECT)) vectseg = 1; + } + } else if ((bezt->h2==HD_VECT) && (beztnext->h1==HD_VECT)) vectseg = 1; + + + if (vectseg==0) { + /* if it's NOT a vector segment, check to see if the subdiv falls within the segment */ + subdivs += resolu; + + if (cursubdiv < subdivs) { + ratio = 1.0 - ((subdivs - cursubdiv)/(float)resolu); + break; + } + } else { + /* must be a vector segment.. loop again! */ + subdivs += 1; + } + + bezt++; + } + + /* Now we have a nice bezt pointer to the CV that we want. But cyclic messes it up, so must correct for that.. + * (cyclic goes last-> first -> first+1 -> first+2 -> ...) */ + if (nu->flagu & CU_CYCLIC) { + if (bezt == beztfirst) bezt = beztlast; + else bezt--; + } + + /* find the radii at the bounding CVs and interpolate between them based on ratio */ + rad = prevrad = bezt->radius; + + if ((bezt == beztlast) && (nu->flagu & CU_CYCLIC)) { /* loop around */ + bezt= beztfirst; + } else if (bezt != beztlast) { + bezt++; + } + nextrad = bezt->radius; + + } + else if( ( ((nu->type & 7)==CU_NURBS) || ((nu->type & 7)==CU_POLY)) && (bp != NULL)) { + /* follows similar algo as for bezt above */ + bpfirst = nu->bp; + bplast = nu->bp + (nu->pntsu - 1); + + if ((nu->type & 7)==CU_POLY) resolu=1; + + while(bp<=bplast) { + if (subdivs==cursubdiv) { + ratio= 0.0; + break; + } + + subdivs += resolu; + + if (cursubdiv < subdivs) { + ratio = 1.0 - ((subdivs - cursubdiv)/(float)resolu); + break; + } + + bp++; + } + + if ( ((nu->type & 7)==CU_NURBS) && (nu->flagu & CU_CYCLIC)) { + if (bp == bplast) bp = bpfirst; + else bp++; + } + + rad = prevrad = bp->radius; + + if ((bp == bplast) && (nu->flagu & CU_CYCLIC)) { /* loop around */ + bp= bpfirst; + } else if (bp != bplast) { + bp++; + } + nextrad = bp->radius; + + } + + + if (nextrad != prevrad) { + /* smooth interpolation */ + rad = prevrad + (nextrad-prevrad)*(3.0f*ratio*ratio - 2.0f*ratio*ratio*ratio); + } + + if (rad > 0.0) + return rad; + else + return 1.0; +} + +/* ****************** HANDLES ************** */ + +/* + * handlecodes: + * 1: nothing, 1:auto, 2:vector, 3:aligned + */ + +/* mode: is not zero when IpoCurve, is 2 when forced horizontal for autohandles */ +void calchandleNurb(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode) +{ + float *p1,*p2,*p3, pt[3]; + float dx1,dy1,dz1,dx,dy,dz,vx,vy,vz,len,len1,len2; + + if(bezt->h1==0 && bezt->h2==0) return; + + p2= bezt->vec[1]; + + if(prev==0) { + p3= next->vec[1]; + pt[0]= 2*p2[0]- p3[0]; + pt[1]= 2*p2[1]- p3[1]; + pt[2]= 2*p2[2]- p3[2]; + p1= pt; + } + else p1= prev->vec[1]; + + if(next==0) { + pt[0]= 2*p2[0]- p1[0]; + pt[1]= 2*p2[1]- p1[1]; + pt[2]= 2*p2[2]- p1[2]; + p3= pt; + } + else p3= next->vec[1]; + + dx= p2[0]- p1[0]; + dy= p2[1]- p1[1]; + dz= p2[2]- p1[2]; + + if(mode) len1= dx; + else len1= (float)sqrt(dx*dx+dy*dy+dz*dz); + + dx1= p3[0]- p2[0]; + dy1= p3[1]- p2[1]; + dz1= p3[2]- p2[2]; + + if(mode) len2= dx1; + else len2= (float)sqrt(dx1*dx1+dy1*dy1+dz1*dz1); + + if(len1==0.0f) len1=1.0f; + if(len2==0.0f) len2=1.0f; + + + if(bezt->h1==HD_AUTO || bezt->h2==HD_AUTO) { /* auto */ + vx= dx1/len2 + dx/len1; + vy= dy1/len2 + dy/len1; + vz= dz1/len2 + dz/len1; + len= 2.5614f*(float)sqrt(vx*vx + vy*vy + vz*vz); + if(len!=0.0f) { + int leftviolate=0, rightviolate=0; /* for mode==2 */ + + if(len1>5.0f*len2) len1= 5.0f*len2; + if(len2>5.0f*len1) len2= 5.0f*len1; + + if(bezt->h1==HD_AUTO) { + len1/=len; + *(p2-3)= *p2-vx*len1; + *(p2-2)= *(p2+1)-vy*len1; + *(p2-1)= *(p2+2)-vz*len1; + + if(mode==2 && next && prev) { // keep horizontal if extrema + float ydiff1= prev->vec[1][1] - bezt->vec[1][1]; + float ydiff2= next->vec[1][1] - bezt->vec[1][1]; + if( (ydiff1<=0.0 && ydiff2<=0.0) || (ydiff1>=0.0 && ydiff2>=0.0) ) { + bezt->vec[0][1]= bezt->vec[1][1]; + } + else { // handles should not be beyond y coord of two others + if(ydiff1<=0.0) { + if(prev->vec[1][1] > bezt->vec[0][1]) { + bezt->vec[0][1]= prev->vec[1][1]; + leftviolate= 1; + } + } + else { + if(prev->vec[1][1] < bezt->vec[0][1]) { + bezt->vec[0][1]= prev->vec[1][1]; + leftviolate= 1; + } + } + } + } + } + if(bezt->h2==HD_AUTO) { + len2/=len; + *(p2+3)= *p2+vx*len2; + *(p2+4)= *(p2+1)+vy*len2; + *(p2+5)= *(p2+2)+vz*len2; + + if(mode==2 && next && prev) { // keep horizontal if extrema + float ydiff1= prev->vec[1][1] - bezt->vec[1][1]; + float ydiff2= next->vec[1][1] - bezt->vec[1][1]; + if( (ydiff1<=0.0 && ydiff2<=0.0) || (ydiff1>=0.0 && ydiff2>=0.0) ) { + bezt->vec[2][1]= bezt->vec[1][1]; + } + else { // handles should not be beyond y coord of two others + if(ydiff1<=0.0) { + if(next->vec[1][1] < bezt->vec[2][1]) { + bezt->vec[2][1]= next->vec[1][1]; + rightviolate= 1; + } + } + else { + if(next->vec[1][1] > bezt->vec[2][1]) { + bezt->vec[2][1]= next->vec[1][1]; + rightviolate= 1; + } + } + } + } + } + if(leftviolate || rightviolate) { /* align left handle */ + float h1[3], h2[3]; + + VecSubf(h1, p2-3, p2); + VecSubf(h2, p2, p2+3); + len1= Normalize(h1); + len2= Normalize(h2); + + vz= INPR(h1, h2); + + if(leftviolate) { + *(p2+3)= *(p2) - vz*len2*h1[0]; + *(p2+4)= *(p2+1) - vz*len2*h1[1]; + *(p2+5)= *(p2+2) - vz*len2*h1[2]; + } + else { + *(p2-3)= *(p2) + vz*len1*h2[0]; + *(p2-2)= *(p2+1) + vz*len1*h2[1]; + *(p2-1)= *(p2+2) + vz*len1*h2[2]; + } + } + + } + } + + if(bezt->h1==HD_VECT) { /* vector */ + dx/=3.0; + dy/=3.0; + dz/=3.0; + *(p2-3)= *p2-dx; + *(p2-2)= *(p2+1)-dy; + *(p2-1)= *(p2+2)-dz; + } + if(bezt->h2==HD_VECT) { + dx1/=3.0; + dy1/=3.0; + dz1/=3.0; + *(p2+3)= *p2+dx1; + *(p2+4)= *(p2+1)+dy1; + *(p2+5)= *(p2+2)+dz1; + } + + len2= VecLenf(p2, p2+3); + len1= VecLenf(p2, p2-3); + if(len1==0.0) len1=1.0; + if(len2==0.0) len2=1.0; + + if(bezt->f1 & 1) { /* order of calculation */ + if(bezt->h2==HD_ALIGN) { /* aligned */ + len= len2/len1; + p2[3]= p2[0]+len*(p2[0]-p2[-3]); + p2[4]= p2[1]+len*(p2[1]-p2[-2]); + p2[5]= p2[2]+len*(p2[2]-p2[-1]); + } + if(bezt->h1==HD_ALIGN) { + len= len1/len2; + p2[-3]= p2[0]+len*(p2[0]-p2[3]); + p2[-2]= p2[1]+len*(p2[1]-p2[4]); + p2[-1]= p2[2]+len*(p2[2]-p2[5]); + } + } + else { + if(bezt->h1==HD_ALIGN) { + len= len1/len2; + p2[-3]= p2[0]+len*(p2[0]-p2[3]); + p2[-2]= p2[1]+len*(p2[1]-p2[4]); + p2[-1]= p2[2]+len*(p2[2]-p2[5]); + } + if(bezt->h2==HD_ALIGN) { /* aligned */ + len= len2/len1; + p2[3]= p2[0]+len*(p2[0]-p2[-3]); + p2[4]= p2[1]+len*(p2[1]-p2[-2]); + p2[5]= p2[2]+len*(p2[2]-p2[-1]); + } + } +} + +void calchandlesNurb(Nurb *nu) /* first, if needed, set handle flags */ +{ + BezTriple *bezt, *prev, *next; + short a; + + if((nu->type & 7)!=CU_BEZIER) return; + if(nu->pntsu<2) return; + + a= nu->pntsu; + bezt= nu->bezt; + if(nu->flagu & 1) prev= bezt+(a-1); + else prev= 0; + next= bezt+1; + + while(a--) { + calchandleNurb(bezt, prev, next, 0); + prev= bezt; + if(a==1) { + if(nu->flagu & 1) next= nu->bezt; + else next= 0; + } + else next++; + + bezt++; + } +} + + +void testhandlesNurb(Nurb *nu) +{ + /* use when something has changed with handles. + it treats all BezTriples with the following rules: + PHASE 1: do types have to be altered? + Auto handles: become aligned when selection status is NOT(000 || 111) + Vector handles: become 'nothing' when (one half selected AND other not) + PHASE 2: recalculate handles + */ + BezTriple *bezt; + short flag, a; + + if((nu->type & 7)!=CU_BEZIER) return; + + bezt= nu->bezt; + a= nu->pntsu; + while(a--) { + flag= 0; + if(bezt->f1 & 1) flag++; + if(bezt->f2 & 1) flag += 2; + if(bezt->f3 & 1) flag += 4; + + if( !(flag==0 || flag==7) ) { + if(bezt->h1==HD_AUTO) { /* auto */ + bezt->h1= HD_ALIGN; + } + if(bezt->h2==HD_AUTO) { /* auto */ + bezt->h2= HD_ALIGN; + } + + if(bezt->h1==HD_VECT) { /* vector */ + if(flag < 4) bezt->h1= 0; + } + if(bezt->h2==HD_VECT) { /* vector */ + if( flag > 3) bezt->h2= 0; + } + } + bezt++; + } + + calchandlesNurb(nu); +} + +void autocalchandlesNurb(Nurb *nu, int flag) +{ + /* checks handle coordinates and calculates type */ + + BezTriple *bezt2, *bezt1, *bezt0; + int i, align, leftsmall, rightsmall; + + if(nu==0 || nu->bezt==0) return; + + bezt2 = nu->bezt; + bezt1 = bezt2 + (nu->pntsu-1); + bezt0 = bezt1 - 1; + i = nu->pntsu; + + while(i--) { + + align= leftsmall= rightsmall= 0; + + /* left handle: */ + if(flag==0 || (bezt1->f1 & flag) ) { + bezt1->h1= 0; + /* distance too short: vectorhandle */ + if( VecLenf( bezt1->vec[1], bezt0->vec[1] ) < 0.0001) { + bezt1->h1= HD_VECT; + leftsmall= 1; + } + else { + /* aligned handle? */ + if(DistVL2Dfl(bezt1->vec[1], bezt1->vec[0], bezt1->vec[2]) < 0.0001) { + align= 1; + bezt1->h1= HD_ALIGN; + } + /* or vector handle? */ + if(DistVL2Dfl(bezt1->vec[0], bezt1->vec[1], bezt0->vec[1]) < 0.0001) + bezt1->h1= HD_VECT; + + } + } + /* right handle: */ + if(flag==0 || (bezt1->f3 & flag) ) { + bezt1->h2= 0; + /* distance too short: vectorhandle */ + if( VecLenf( bezt1->vec[1], bezt2->vec[1] ) < 0.0001) { + bezt1->h2= HD_VECT; + rightsmall= 1; + } + else { + /* aligned handle? */ + if(align) bezt1->h2= HD_ALIGN; + + /* or vector handle? */ + if(DistVL2Dfl(bezt1->vec[2], bezt1->vec[1], bezt2->vec[1]) < 0.0001) + bezt1->h2= HD_VECT; + + } + } + if(leftsmall && bezt1->h2==HD_ALIGN) bezt1->h2= 0; + if(rightsmall && bezt1->h1==HD_ALIGN) bezt1->h1= 0; + + /* undesired combination: */ + if(bezt1->h1==HD_ALIGN && bezt1->h2==HD_VECT) bezt1->h1= 0; + if(bezt1->h2==HD_ALIGN && bezt1->h1==HD_VECT) bezt1->h2= 0; + + bezt0= bezt1; + bezt1= bezt2; + bezt2++; + } + + calchandlesNurb(nu); +} + +void autocalchandlesNurb_all(int flag) +{ + Nurb *nu; + + nu= editNurb.first; + while(nu) { + autocalchandlesNurb(nu, flag); + nu= nu->next; + } +} + +void sethandlesNurb(short code) +{ + /* code==1: set autohandle */ + /* code==2: set vectorhandle */ + /* code==3 (HD_ALIGN) it toggle, vectorhandles become HD_FREE */ + /* code==4: sets icu flag to become IPO_AUTO_HORIZ, horizontal extremes on auto-handles */ + Nurb *nu; + BezTriple *bezt; + short a, ok=0; + + if(code==1 || code==2) { + nu= editNurb.first; + while(nu) { + if( (nu->type & 7)==1) { + bezt= nu->bezt; + a= nu->pntsu; + while(a--) { + if(bezt->f1 || bezt->f3) { + if(bezt->f1) bezt->h1= code; + if(bezt->f3) bezt->h2= code; + if(bezt->h1!=bezt->h2) { + if ELEM(bezt->h1, HD_ALIGN, HD_AUTO) bezt->h1= HD_FREE; + if ELEM(bezt->h2, HD_ALIGN, HD_AUTO) bezt->h2= HD_FREE; + } + } + bezt++; + } + calchandlesNurb(nu); + } + nu= nu->next; + } + } + else { + /* there is 1 handle not FREE: FREE it all, else make ALIGNED */ + + nu= editNurb.first; + while(nu) { + if( (nu->type & 7)==1) { + bezt= nu->bezt; + a= nu->pntsu; + while(a--) { + if(bezt->f1 && bezt->h1) ok= 1; + if(bezt->f3 && bezt->h2) ok= 1; + if(ok) break; + bezt++; + } + } + nu= nu->next; + } + if(ok) ok= HD_FREE; + else ok= HD_ALIGN; + + nu= editNurb.first; + while(nu) { + if( (nu->type & 7)==1) { + bezt= nu->bezt; + a= nu->pntsu; + while(a--) { + if(bezt->f1) bezt->h1= ok; + if(bezt->f3 ) bezt->h2= ok; + + bezt++; + } + calchandlesNurb(nu); + } + nu= nu->next; + } + } +} + +static void swapdata(void *adr1, void *adr2, int len) +{ + + if(len<=0) return; + + if(len<65) { + char adr[64]; + + memcpy(adr, adr1, len); + memcpy(adr1, adr2, len); + memcpy(adr2, adr, len); + } + else { + char *adr; + + adr= (char *)MEM_mallocN(len, "curve swap"); + memcpy(adr, adr1, len); + memcpy(adr1, adr2, len); + memcpy(adr2, adr, len); + MEM_freeN(adr); + } +} + +void switchdirectionNurb(Nurb *nu) +{ + BezTriple *bezt1, *bezt2; + BPoint *bp1, *bp2; + float *fp1, *fp2, *tempf; + int a, b; + + if(nu->pntsu==1 && nu->pntsv==1) return; + + if((nu->type & 7)==CU_BEZIER) { + a= nu->pntsu; + bezt1= nu->bezt; + bezt2= bezt1+(a-1); + if(a & 1) a+= 1; /* if odd, also swap middle content */ + a/= 2; + while(a>0) { + if(bezt1!=bezt2) SWAP(BezTriple, *bezt1, *bezt2); + + swapdata(bezt1->vec[0], bezt1->vec[2], 12); + if(bezt1!=bezt2) swapdata(bezt2->vec[0], bezt2->vec[2], 12); + + SWAP(char, bezt1->h1, bezt1->h2); + SWAP(short, bezt1->f1, bezt1->f3); + + if(bezt1!=bezt2) { + SWAP(char, bezt2->h1, bezt2->h2); + SWAP(short, bezt2->f1, bezt2->f3); + bezt1->alfa= -bezt1->alfa; + bezt2->alfa= -bezt2->alfa; + } + a--; + bezt1++; + bezt2--; + } + } + else if(nu->pntsv==1) { + a= nu->pntsu; + bp1= nu->bp; + bp2= bp1+(a-1); + a/= 2; + while(bp1!=bp2 && a>0) { + SWAP(BPoint, *bp1, *bp2); + a--; + bp1->alfa= -bp1->alfa; + bp2->alfa= -bp2->alfa; + bp1++; + bp2--; + } + if((nu->type & 7)==CU_NURBS) { + /* inverse knots */ + a= KNOTSU(nu); + fp1= nu->knotsu; + fp2= fp1+(a-1); + a/= 2; + while(fp1!=fp2 && a>0) { + SWAP(float, *fp1, *fp2); + a--; + fp1++; + fp2--; + } + /* and make in increasing order again */ + a= KNOTSU(nu); + fp1= nu->knotsu; + fp2=tempf= MEM_mallocN(sizeof(float)*a, "switchdirect"); + while(a--) { + fp2[0]= fabs(fp1[1]-fp1[0]); + fp1++; + fp2++; + } + + a= KNOTSU(nu)-1; + fp1= nu->knotsu; + fp2= tempf; + fp1[0]= 0.0; + fp1++; + while(a--) { + fp1[0]= fp1[-1]+fp2[0]; + fp1++; + fp2++; + } + MEM_freeN(tempf); + } + } + else { + + for(b=0; bpntsv; b++) { + + bp1= nu->bp+b*nu->pntsu; + a= nu->pntsu; + bp2= bp1+(a-1); + a/= 2; + + while(bp1!=bp2 && a>0) { + SWAP(BPoint, *bp1, *bp2); + a--; + bp1++; + bp2--; + } + } + } +} + + +float (*curve_getVertexCos(Curve *cu, ListBase *lb, int *numVerts_r))[3] +{ + int i, numVerts = *numVerts_r = count_curveverts(lb); + float *co, (*cos)[3] = MEM_mallocN(sizeof(*cos)*numVerts, "cu_vcos"); + Nurb *nu; + + co = cos[0]; + for (nu=lb->first; nu; nu=nu->next) { + if ((nu->type & 7)==CU_BEZIER) { + BezTriple *bezt = nu->bezt; + + for (i=0; ipntsu; i++,bezt++) { + VECCOPY(co, bezt->vec[0]); co+=3; + VECCOPY(co, bezt->vec[1]); co+=3; + VECCOPY(co, bezt->vec[2]); co+=3; + } + } else { + BPoint *bp = nu->bp; + + for (i=0; ipntsu*nu->pntsv; i++,bp++) { + VECCOPY(co, bp->vec); co+=3; + } + } + } + + return cos; +} + +void curve_applyVertexCos(Curve *cu, ListBase *lb, float (*vertexCos)[3]) +{ + float *co = vertexCos[0]; + Nurb *nu; + int i; + + for (nu=lb->first; nu; nu=nu->next) { + if ((nu->type & 7)==CU_BEZIER) { + BezTriple *bezt = nu->bezt; + + for (i=0; ipntsu; i++,bezt++) { + VECCOPY(bezt->vec[0], co); co+=3; + VECCOPY(bezt->vec[1], co); co+=3; + VECCOPY(bezt->vec[2], co); co+=3; + } + } else { + BPoint *bp = nu->bp; + + for (i=0; ipntsu*nu->pntsv; i++,bp++) { + VECCOPY(bp->vec, co); co+=3; + } + } + } +} diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c new file mode 100644 index 00000000000..466ba9f4201 --- /dev/null +++ b/source/blender/blenkernel/intern/customdata.c @@ -0,0 +1,1482 @@ +/* +* $Id$ +* +* ***** BEGIN GPL LICENSE BLOCK ***** +* +* 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. +* +* The Original Code is Copyright (C) 2006 Blender Foundation. +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): Ben Batt +* +* ***** END GPL LICENSE BLOCK ***** +* +* Implementation of CustomData. +* +* BKE_customdata.h contains the function prototypes for this file. +* +*/ + +#include "BKE_customdata.h" + +#include "BLI_blenlib.h" +#include "BLI_linklist.h" + +#include "DNA_customdata_types.h" +#include "DNA_listBase.h" +#include "DNA_meshdata_types.h" + +#include "MEM_guardedalloc.h" + +#include + +/* number of layers to add when growing a CustomData object */ +#define CUSTOMDATA_GROW 5 + +/********************* Layer type information **********************/ +typedef struct LayerTypeInfo { + int size; /* the memory size of one element of this layer's data */ + char *structname; /* name of the struct used, for file writing */ + int structnum; /* number of structs per element, for file writing */ + char *defaultname; /* default layer name */ + + /* a function to copy count elements of this layer's data + * (deep copy if appropriate) + * if NULL, memcpy is used + */ + void (*copy)(const void *source, void *dest, int count); + + /* a function to free any dynamically allocated components of this + * layer's data (note the data pointer itself should not be freed) + * size should be the size of one element of this layer's data (e.g. + * LayerTypeInfo.size) + */ + void (*free)(void *data, int count, int size); + + /* a function to interpolate between count source elements of this + * layer's data and store the result in dest + * if weights == NULL or sub_weights == NULL, they should default to 1 + * + * weights gives the weight for each element in sources + * sub_weights gives the sub-element weights for each element in sources + * (there should be (sub element count)^2 weights per element) + * count gives the number of elements in sources + */ + void (*interp)(void **sources, float *weights, float *sub_weights, + int count, void *dest); + + /* a function to swap the data in corners of the element */ + void (*swap)(void *data, int *corner_indices); + + /* a function to set a layer's data to default values. if NULL, the + default is assumed to be all zeros */ + void (*set_default)(void *data, int count); +} LayerTypeInfo; + +static void layerCopy_mdeformvert(const void *source, void *dest, + int count) +{ + int i, size = sizeof(MDeformVert); + + memcpy(dest, source, count * size); + + for(i = 0; i < count; ++i) { + MDeformVert *dvert = (MDeformVert *)((char *)dest + i * size); + MDeformWeight *dw = MEM_callocN(dvert->totweight * sizeof(*dw), + "layerCopy_mdeformvert dw"); + + memcpy(dw, dvert->dw, dvert->totweight * sizeof(*dw)); + dvert->dw = dw; + } +} + +static void layerFree_mdeformvert(void *data, int count, int size) +{ + int i; + + for(i = 0; i < count; ++i) { + MDeformVert *dvert = (MDeformVert *)((char *)data + i * size); + + if(dvert->dw) { + MEM_freeN(dvert->dw); + dvert->dw = NULL; + dvert->totweight = 0; + } + } +} + +static void linklist_free_simple(void *link) +{ + MEM_freeN(link); +} + +static void layerInterp_mdeformvert(void **sources, float *weights, + float *sub_weights, int count, void *dest) +{ + MDeformVert *dvert = dest; + LinkNode *dest_dw = NULL; /* a list of lists of MDeformWeight pointers */ + LinkNode *node; + int i, j, totweight; + + if(count <= 0) return; + + /* build a list of unique def_nrs for dest */ + totweight = 0; + for(i = 0; i < count; ++i) { + MDeformVert *source = sources[i]; + float interp_weight = weights ? weights[i] : 1.0f; + + for(j = 0; j < source->totweight; ++j) { + MDeformWeight *dw = &source->dw[j]; + + for(node = dest_dw; node; node = node->next) { + MDeformWeight *tmp_dw = (MDeformWeight *)node->link; + + if(tmp_dw->def_nr == dw->def_nr) { + tmp_dw->weight += dw->weight * interp_weight; + break; + } + } + + /* if this def_nr is not in the list, add it */ + if(!node) { + MDeformWeight *tmp_dw = MEM_callocN(sizeof(*tmp_dw), + "layerInterp_mdeformvert tmp_dw"); + tmp_dw->def_nr = dw->def_nr; + tmp_dw->weight = dw->weight * interp_weight; + BLI_linklist_prepend(&dest_dw, tmp_dw); + totweight++; + } + } + } + + /* now we know how many unique deform weights there are, so realloc */ + if(dvert->dw) MEM_freeN(dvert->dw); + + if(totweight) { + dvert->dw = MEM_callocN(sizeof(*dvert->dw) * totweight, + "layerInterp_mdeformvert dvert->dw"); + dvert->totweight = totweight; + + for(i = 0, node = dest_dw; node; node = node->next, ++i) + dvert->dw[i] = *((MDeformWeight *)node->link); + } + else + memset(dvert, 0, sizeof(*dvert)); + + BLI_linklist_free(dest_dw, linklist_free_simple); +} + + +static void layerInterp_msticky(void **sources, float *weights, + float *sub_weights, int count, void *dest) +{ + float co[2], w; + MSticky *mst; + int i; + + co[0] = co[1] = 0.0f; + for(i = 0; i < count; i++) { + w = weights ? weights[i] : 1.0f; + mst = (MSticky*)sources[i]; + + co[0] += w*mst->co[0]; + co[1] += w*mst->co[1]; + } + + mst = (MSticky*)dest; + mst->co[0] = co[0]; + mst->co[1] = co[1]; +} + + +static void layerCopy_tface(const void *source, void *dest, int count) +{ + const MTFace *source_tf = (const MTFace*)source; + MTFace *dest_tf = (MTFace*)dest; + int i; + + for(i = 0; i < count; ++i) + dest_tf[i] = source_tf[i]; +} + +static void layerInterp_tface(void **sources, float *weights, + float *sub_weights, int count, void *dest) +{ + MTFace *tf = dest; + int i, j, k; + float uv[4][2]; + float *sub_weight; + + if(count <= 0) return; + + memset(uv, 0, sizeof(uv)); + + sub_weight = sub_weights; + for(i = 0; i < count; ++i) { + float weight = weights ? weights[i] : 1; + MTFace *src = sources[i]; + + for(j = 0; j < 4; ++j) { + if(sub_weights) { + for(k = 0; k < 4; ++k, ++sub_weight) { + float w = (*sub_weight) * weight; + float *tmp_uv = src->uv[k]; + + uv[j][0] += tmp_uv[0] * w; + uv[j][1] += tmp_uv[1] * w; + } + } else { + uv[j][0] += src->uv[j][0] * weight; + uv[j][1] += src->uv[j][1] * weight; + } + } + } + + *tf = *(MTFace *)sources[0]; + for(j = 0; j < 4; ++j) { + tf->uv[j][0] = uv[j][0]; + tf->uv[j][1] = uv[j][1]; + } +} + +static void layerSwap_tface(void *data, int *corner_indices) +{ + MTFace *tf = data; + float uv[4][2]; + int j; + + for(j = 0; j < 4; ++j) { + uv[j][0] = tf->uv[corner_indices[j]][0]; + uv[j][1] = tf->uv[corner_indices[j]][1]; + } + + memcpy(tf->uv, uv, sizeof(tf->uv)); +} + +static void layerDefault_tface(void *data, int count) +{ + static MTFace default_tf = {{{0, 1}, {0, 0}, {1, 0}, {1, 1}}, NULL, + 0, 0, TF_DYNAMIC, 0, 0}; + MTFace *tf = (MTFace*)data; + int i; + + for(i = 0; i < count; i++) + tf[i] = default_tf; +} + +static void layerInterp_mcol(void **sources, float *weights, + float *sub_weights, int count, void *dest) +{ + MCol *mc = dest; + int i, j, k; + struct { + float a; + float r; + float g; + float b; + } col[4]; + float *sub_weight; + + if(count <= 0) return; + + memset(col, 0, sizeof(col)); + + sub_weight = sub_weights; + for(i = 0; i < count; ++i) { + float weight = weights ? weights[i] : 1; + + for(j = 0; j < 4; ++j) { + if(sub_weights) { + MCol *src = sources[i]; + for(k = 0; k < 4; ++k, ++sub_weight, ++src) { + col[j].a += src->a * (*sub_weight) * weight; + col[j].r += src->r * (*sub_weight) * weight; + col[j].g += src->g * (*sub_weight) * weight; + col[j].b += src->b * (*sub_weight) * weight; + } + } else { + MCol *src = sources[i]; + col[j].a += src[j].a * weight; + col[j].r += src[j].r * weight; + col[j].g += src[j].g * weight; + col[j].b += src[j].b * weight; + } + } + } + + for(j = 0; j < 4; ++j) { + mc[j].a = (int)col[j].a; + mc[j].r = (int)col[j].r; + mc[j].g = (int)col[j].g; + mc[j].b = (int)col[j].b; + } +} + +static void layerSwap_mcol(void *data, int *corner_indices) +{ + MCol *mcol = data; + MCol col[4]; + int j; + + for(j = 0; j < 4; ++j) + col[j] = mcol[corner_indices[j]]; + + memcpy(mcol, col, sizeof(col)); +} + +static void layerDefault_mcol(void *data, int count) +{ + static MCol default_mcol = {255, 255, 255, 255}; + MCol *mcol = (MCol*)data; + int i; + + for(i = 0; i < 4*count; i++) + mcol[i] = default_mcol; +} + +const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { + {sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(MSticky), "MSticky", 1, NULL, NULL, NULL, layerInterp_msticky, NULL, + NULL}, + {sizeof(MDeformVert), "MDeformVert", 1, NULL, layerCopy_mdeformvert, + layerFree_mdeformvert, layerInterp_mdeformvert, NULL, NULL}, + {sizeof(MEdge), "MEdge", 1, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(MFace), "MFace", 1, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(MTFace), "MTFace", 1, "UVTex", layerCopy_tface, NULL, + layerInterp_tface, layerSwap_tface, layerDefault_tface}, + /* 4 MCol structs per face */ + {sizeof(MCol)*4, "MCol", 4, "Col", NULL, NULL, layerInterp_mcol, + layerSwap_mcol, layerDefault_mcol}, + {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, + /* 3 floats per normal vector */ + {sizeof(float)*3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(MFloatProperty), "MFloatProperty",1,"Float",NULL,NULL,NULL,NULL}, + {sizeof(MIntProperty), "MIntProperty",1,"Int",NULL,NULL,NULL,NULL}, + {sizeof(MStringProperty), "MStringProperty",1,"String",NULL,NULL,NULL,NULL}, +}; + +const char *LAYERTYPENAMES[CD_NUMTYPES] = { + "CDMVert", "CDMSticky", "CDMDeformVert", "CDMEdge", "CDMFace", "CDMTFace", + "CDMCol", "CDOrigIndex", "CDNormal", "CDFlags","CDMFloatProperty","CDMIntProperty","CDMStringProperty"}; + +const CustomDataMask CD_MASK_BAREMESH = + CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE; +const CustomDataMask CD_MASK_MESH = + CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE | + CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | CD_MASK_MCOL | + CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR; +const CustomDataMask CD_MASK_EDITMESH = + CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | + CD_MASK_MCOL|CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR; +const CustomDataMask CD_MASK_DERIVEDMESH = + CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | + CD_MASK_MCOL | CD_MASK_ORIGINDEX| + CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR; + +static const LayerTypeInfo *layerType_getInfo(int type) +{ + if(type < 0 || type >= CD_NUMTYPES) return NULL; + + return &LAYERTYPEINFO[type]; +} + +static const char *layerType_getName(int type) +{ + if(type < 0 || type >= CD_NUMTYPES) return NULL; + + return LAYERTYPENAMES[type]; +} + +/********************* CustomData functions *********************/ +static void customData_update_offsets(CustomData *data); + +static CustomDataLayer *customData_add_layer__internal(CustomData *data, + int type, int alloctype, void *layerdata, int totelem, const char *name); + +void CustomData_merge(const struct CustomData *source, struct CustomData *dest, + CustomDataMask mask, int alloctype, int totelem) +{ + const LayerTypeInfo *typeInfo; + CustomDataLayer *layer, *newlayer; + int i, type, number = 0, lasttype = -1, lastactive = 0, lastrender = 0; + + for(i = 0; i < source->totlayer; ++i) { + layer = &source->layers[i]; + typeInfo = layerType_getInfo(layer->type); + + type = layer->type; + + if (type != lasttype) { + number = 0; + lastactive = layer->active; + lastrender = layer->active_rnd; + lasttype = type; + } + else + number++; + + if(layer->flag & CD_FLAG_NOCOPY) continue; + else if(!(mask & (1 << type))) continue; + else if(number < CustomData_number_of_layers(dest, type)) continue; + + if((alloctype == CD_ASSIGN) && (layer->flag & CD_FLAG_NOFREE)) + newlayer = customData_add_layer__internal(dest, type, CD_REFERENCE, + layer->data, totelem, layer->name); + else + newlayer = customData_add_layer__internal(dest, type, alloctype, + layer->data, totelem, layer->name); + + if(newlayer) { + newlayer->active = lastactive; + newlayer->active_rnd = lastrender; + } + } +} + +void CustomData_copy(const struct CustomData *source, struct CustomData *dest, + CustomDataMask mask, int alloctype, int totelem) +{ + memset(dest, 0, sizeof(*dest)); + + CustomData_merge(source, dest, mask, alloctype, totelem); +} + +static void customData_free_layer__internal(CustomDataLayer *layer, int totelem) +{ + const LayerTypeInfo *typeInfo; + + if(!(layer->flag & CD_FLAG_NOFREE) && layer->data) { + typeInfo = layerType_getInfo(layer->type); + + if(typeInfo->free) + typeInfo->free(layer->data, totelem, typeInfo->size); + + if(layer->data) + MEM_freeN(layer->data); + } +} + +void CustomData_free(CustomData *data, int totelem) +{ + int i; + + for(i = 0; i < data->totlayer; ++i) + customData_free_layer__internal(&data->layers[i], totelem); + + if(data->layers) + MEM_freeN(data->layers); + + memset(data, 0, sizeof(*data)); +} + +static void customData_update_offsets(CustomData *data) +{ + const LayerTypeInfo *typeInfo; + int i, offset = 0; + + for(i = 0; i < data->totlayer; ++i) { + typeInfo = layerType_getInfo(data->layers[i].type); + + data->layers[i].offset = offset; + offset += typeInfo->size; + } + + data->totsize = offset; +} + +int CustomData_get_layer_index(const CustomData *data, int type) +{ + int i; + + for(i=0; i < data->totlayer; ++i) + if(data->layers[i].type == type) + return i; + + return -1; +} + +int CustomData_get_named_layer_index(const CustomData *data, int type, char *name) +{ + int i; + + for(i=0; i < data->totlayer; ++i) + if(data->layers[i].type == type && strcmp(data->layers[i].name, name)==0) + return i; + + return -1; +} + +int CustomData_get_active_layer_index(const CustomData *data, int type) +{ + int i; + + for(i=0; i < data->totlayer; ++i) + if(data->layers[i].type == type) + return i + data->layers[i].active; + + return -1; +} + +int CustomData_get_render_layer_index(const CustomData *data, int type) +{ + int i; + + for(i=0; i < data->totlayer; ++i) + if(data->layers[i].type == type) + return i + data->layers[i].active_rnd; + + return -1; +} + +int CustomData_get_active_layer(const CustomData *data, int type) +{ + int i; + + for(i=0; i < data->totlayer; ++i) + if(data->layers[i].type == type) + return data->layers[i].active; + + return -1; +} + +int CustomData_get_render_layer(const CustomData *data, int type) +{ + int i; + + for(i=0; i < data->totlayer; ++i) + if(data->layers[i].type == type) + return data->layers[i].active_rnd; + + return -1; +} + + +void CustomData_set_layer_active(CustomData *data, int type, int n) +{ + int i; + + for(i=0; i < data->totlayer; ++i) + if(data->layers[i].type == type) + data->layers[i].active = n; +} + +void CustomData_set_layer_render(CustomData *data, int type, int n) +{ + int i; + + for(i=0; i < data->totlayer; ++i) + if(data->layers[i].type == type) + data->layers[i].active_rnd = n; +} + +/* for using with an index from CustomData_get_active_layer_index and CustomData_get_render_layer_index */ +void CustomData_set_layer_active_index(CustomData *data, int type, int n) +{ + int i; + + for(i=0; i < data->totlayer; ++i) + if(data->layers[i].type == type) + data->layers[i].active = n-i; +} + +void CustomData_set_layer_render_index(CustomData *data, int type, int n) +{ + int i; + + for(i=0; i < data->totlayer; ++i) + if(data->layers[i].type == type) + data->layers[i].active_rnd = n-i; +} + + +void CustomData_set_layer_flag(struct CustomData *data, int type, int flag) +{ + int i; + + for(i=0; i < data->totlayer; ++i) + if(data->layers[i].type == type) + data->layers[i].flag |= flag; +} + +static int customData_resize(CustomData *data, int amount) +{ + CustomDataLayer *tmp = MEM_callocN(sizeof(*tmp)*(data->maxlayer + amount), + "CustomData->layers"); + if(!tmp) return 0; + + data->maxlayer += amount; + if (data->layers) { + memcpy(tmp, data->layers, sizeof(*tmp) * data->totlayer); + MEM_freeN(data->layers); + } + data->layers = tmp; + + return 1; +} + +static CustomDataLayer *customData_add_layer__internal(CustomData *data, + int type, int alloctype, void *layerdata, int totelem, const char *name) +{ + const LayerTypeInfo *typeInfo= layerType_getInfo(type); + int size = typeInfo->size * totelem, flag = 0, index = data->totlayer; + void *newlayerdata; + + if (!typeInfo->defaultname && CustomData_has_layer(data, type)) + return &data->layers[CustomData_get_layer_index(data, type)]; + + if((alloctype == CD_ASSIGN) || (alloctype == CD_REFERENCE)) { + newlayerdata = layerdata; + } + else { + newlayerdata = MEM_callocN(size, layerType_getName(type)); + if(!newlayerdata) + return NULL; + } + + if (alloctype == CD_DUPLICATE) { + if(typeInfo->copy) + typeInfo->copy(layerdata, newlayerdata, totelem); + else + memcpy(newlayerdata, layerdata, size); + } + else if (alloctype == CD_DEFAULT) { + if(typeInfo->set_default) + typeInfo->set_default((char*)newlayerdata, totelem); + } + else if (alloctype == CD_REFERENCE) + flag |= CD_FLAG_NOFREE; + + if(index >= data->maxlayer) { + if(!customData_resize(data, CUSTOMDATA_GROW)) { + if(newlayerdata != layerdata) + MEM_freeN(newlayerdata); + return NULL; + } + } + + data->totlayer++; + + /* keep layers ordered by type */ + for( ; index > 0 && data->layers[index - 1].type > type; --index) + data->layers[index] = data->layers[index - 1]; + + data->layers[index].type = type; + data->layers[index].flag = flag; + data->layers[index].data = newlayerdata; + + if(name) { + strcpy(data->layers[index].name, name); + CustomData_set_layer_unique_name(data, index); + } + else + data->layers[index].name[0] = '\0'; + + if(index > 0 && data->layers[index-1].type == type) { + data->layers[index].active = data->layers[index-1].active; + data->layers[index].active_rnd = data->layers[index-1].active_rnd; + } else { + data->layers[index].active = 0; + data->layers[index].active_rnd = 0; + } + + customData_update_offsets(data); + + return &data->layers[index]; +} + +void *CustomData_add_layer(CustomData *data, int type, int alloctype, + void *layerdata, int totelem) +{ + CustomDataLayer *layer; + const LayerTypeInfo *typeInfo= layerType_getInfo(type); + + layer = customData_add_layer__internal(data, type, alloctype, layerdata, + totelem, typeInfo->defaultname); + + if(layer) + return layer->data; + + return NULL; +} + +/*same as above but accepts a name*/ +void *CustomData_add_layer_named(CustomData *data, int type, int alloctype, + void *layerdata, int totelem, char *name) +{ + CustomDataLayer *layer; + + layer = customData_add_layer__internal(data, type, alloctype, layerdata, + totelem, name); + + if(layer) + return layer->data; + + return NULL; +} + + +int CustomData_free_layer(CustomData *data, int type, int totelem, int index) +{ + int i; + CustomDataLayer *layer; + + if (index < 0) return 0; + + layer = &data->layers[index]; + + customData_free_layer__internal(&data->layers[index], totelem); + + for (i=index+1; i < data->totlayer; ++i) + data->layers[i-1] = data->layers[i]; + + data->totlayer--; + + /* if layer was last of type in array, set new active layer */ + if ((index >= data->totlayer) || (data->layers[index].type != type)) { + i = CustomData_get_layer_index(data, type); + + if (i >= 0) + for (; i < data->totlayer && data->layers[i].type == type; i++) { + data->layers[i].active--; + data->layers[i].active_rnd--; + } + } + + if (data->totlayer <= data->maxlayer-CUSTOMDATA_GROW) + customData_resize(data, -CUSTOMDATA_GROW); + + customData_update_offsets(data); + + return 1; +} + +int CustomData_free_layer_active(CustomData *data, int type, int totelem) +{ + int index = 0; + index = CustomData_get_active_layer_index(data, type); + if (index < 0) return 0; + return CustomData_free_layer(data, type, totelem, index); +} + + +void CustomData_free_layers(CustomData *data, int type, int totelem) +{ + while (CustomData_has_layer(data, type)) + CustomData_free_layer_active(data, type, totelem); +} + +int CustomData_has_layer(const CustomData *data, int type) +{ + return (CustomData_get_layer_index(data, type) != -1); +} + +int CustomData_number_of_layers(const CustomData *data, int type) +{ + int i, number = 0; + + for(i = 0; i < data->totlayer; i++) + if(data->layers[i].type == type) + number++; + + return number; +} + +void *CustomData_duplicate_referenced_layer(struct CustomData *data, int type) +{ + CustomDataLayer *layer; + int layer_index; + + /* get the layer index of the first layer of type */ + layer_index = CustomData_get_active_layer_index(data, type); + if(layer_index < 0) return NULL; + + layer = &data->layers[layer_index]; + + if (layer->flag & CD_FLAG_NOFREE) { + layer->data = MEM_dupallocN(layer->data); + layer->flag &= ~CD_FLAG_NOFREE; + } + + return layer->data; +} + +void *CustomData_duplicate_referenced_layer_named(struct CustomData *data, + int type, char *name) +{ + CustomDataLayer *layer; + int layer_index; + + /* get the layer index of the desired layer */ + layer_index = CustomData_get_named_layer_index(data, type, name); + if(layer_index < 0) return NULL; + + layer = &data->layers[layer_index]; + + if (layer->flag & CD_FLAG_NOFREE) { + layer->data = MEM_dupallocN(layer->data); + layer->flag &= ~CD_FLAG_NOFREE; + } + + return layer->data; +} + +void CustomData_free_temporary(CustomData *data, int totelem) +{ + CustomDataLayer *layer; + int i, j; + + for(i = 0, j = 0; i < data->totlayer; ++i) { + layer = &data->layers[i]; + + if (i != j) + data->layers[j] = data->layers[i]; + + if ((layer->flag & CD_FLAG_TEMPORARY) == CD_FLAG_TEMPORARY) + customData_free_layer__internal(layer, totelem); + else + j++; + } + + data->totlayer = j; + + if(data->totlayer <= data->maxlayer-CUSTOMDATA_GROW) + customData_resize(data, -CUSTOMDATA_GROW); + + customData_update_offsets(data); +} + +void CustomData_set_only_copy(const struct CustomData *data, + CustomDataMask mask) +{ + int i; + + for(i = 0; i < data->totlayer; ++i) + if(!(mask & (1 << data->layers[i].type))) + data->layers[i].flag |= CD_FLAG_NOCOPY; +} + +void CustomData_copy_data(const CustomData *source, CustomData *dest, + int source_index, int dest_index, int count) +{ + const LayerTypeInfo *typeInfo; + int src_i, dest_i; + int src_offset; + int dest_offset; + + /* copies a layer at a time */ + dest_i = 0; + for(src_i = 0; src_i < source->totlayer; ++src_i) { + + /* find the first dest layer with type >= the source type + * (this should work because layers are ordered by type) + */ + while(dest_i < dest->totlayer + && dest->layers[dest_i].type < source->layers[src_i].type) + ++dest_i; + + /* if there are no more dest layers, we're done */ + if(dest_i >= dest->totlayer) return; + + /* if we found a matching layer, copy the data */ + if(dest->layers[dest_i].type == source->layers[src_i].type) { + char *src_data = source->layers[src_i].data; + char *dest_data = dest->layers[dest_i].data; + + typeInfo = layerType_getInfo(source->layers[src_i].type); + + src_offset = source_index * typeInfo->size; + dest_offset = dest_index * typeInfo->size; + + if(typeInfo->copy) + typeInfo->copy(src_data + src_offset, + dest_data + dest_offset, + count); + else + memcpy(dest_data + dest_offset, + src_data + src_offset, + count * typeInfo->size); + + /* if there are multiple source & dest layers of the same type, + * we don't want to copy all source layers to the same dest, so + * increment dest_i + */ + ++dest_i; + } + } +} + +void CustomData_free_elem(CustomData *data, int index, int count) +{ + int i; + const LayerTypeInfo *typeInfo; + + for(i = 0; i < data->totlayer; ++i) { + if(!(data->layers[i].flag & CD_FLAG_NOFREE)) { + typeInfo = layerType_getInfo(data->layers[i].type); + + if(typeInfo->free) { + int offset = typeInfo->size * index; + + typeInfo->free((char *)data->layers[i].data + offset, + count, typeInfo->size); + } + } + } +} + +#define SOURCE_BUF_SIZE 100 + +void CustomData_interp(const CustomData *source, CustomData *dest, + int *src_indices, float *weights, float *sub_weights, + int count, int dest_index) +{ + int src_i, dest_i; + int dest_offset; + int j; + void *source_buf[SOURCE_BUF_SIZE]; + void **sources = source_buf; + + /* slow fallback in case we're interpolating a ridiculous number of + * elements + */ + if(count > SOURCE_BUF_SIZE) + sources = MEM_callocN(sizeof(*sources) * count, + "CustomData_interp sources"); + + /* interpolates a layer at a time */ + dest_i = 0; + for(src_i = 0; src_i < source->totlayer; ++src_i) { + const LayerTypeInfo *typeInfo= layerType_getInfo(source->layers[src_i].type); + if(!typeInfo->interp) continue; + + /* find the first dest layer with type >= the source type + * (this should work because layers are ordered by type) + */ + while(dest_i < dest->totlayer + && dest->layers[dest_i].type < source->layers[src_i].type) + ++dest_i; + + /* if there are no more dest layers, we're done */ + if(dest_i >= dest->totlayer) return; + + /* if we found a matching layer, copy the data */ + if(dest->layers[dest_i].type == source->layers[src_i].type) { + void *src_data = source->layers[src_i].data; + + for(j = 0; j < count; ++j) + sources[j] = (char *)src_data + + typeInfo->size * src_indices[j]; + + dest_offset = dest_index * typeInfo->size; + + typeInfo->interp(sources, weights, sub_weights, count, + (char *)dest->layers[dest_i].data + dest_offset); + + /* if there are multiple source & dest layers of the same type, + * we don't want to copy all source layers to the same dest, so + * increment dest_i + */ + ++dest_i; + } + } + + if(count > SOURCE_BUF_SIZE) MEM_freeN(sources); +} + +void CustomData_swap(struct CustomData *data, int index, int *corner_indices) +{ + const LayerTypeInfo *typeInfo; + int i; + + for(i = 0; i < data->totlayer; ++i) { + typeInfo = layerType_getInfo(data->layers[i].type); + + if(typeInfo->swap) { + int offset = typeInfo->size * index; + + typeInfo->swap((char *)data->layers[i].data + offset, corner_indices); + } + } +} + +void *CustomData_get(const CustomData *data, int index, int type) +{ + int offset; + int layer_index; + + /* get the layer index of the active layer of type */ + layer_index = CustomData_get_active_layer_index(data, type); + if(layer_index < 0) return NULL; + + /* get the offset of the desired element */ + offset = layerType_getInfo(type)->size * index; + + return (char *)data->layers[layer_index].data + offset; +} + +void *CustomData_get_layer(const CustomData *data, int type) +{ + /* get the layer index of the active layer of type */ + int layer_index = CustomData_get_active_layer_index(data, type); + if(layer_index < 0) return NULL; + + return data->layers[layer_index].data; +} + +void *CustomData_get_layer_n(const CustomData *data, int type, int n) +{ + /* get the layer index of the active layer of type */ + int layer_index = CustomData_get_layer_index(data, type); + if(layer_index < 0) return NULL; + + return data->layers[layer_index+n].data; +} + +void *CustomData_get_layer_named(const struct CustomData *data, int type, + char *name) +{ + int layer_index = CustomData_get_named_layer_index(data, type, name); + if(layer_index < 0) return NULL; + + return data->layers[layer_index].data; +} + +void *CustomData_set_layer(const CustomData *data, int type, void *ptr) +{ + /* get the layer index of the first layer of type */ + int layer_index = CustomData_get_active_layer_index(data, type); + + if(layer_index < 0) return NULL; + + data->layers[layer_index].data = ptr; + + return ptr; +} + +void *CustomData_set_layer_n(const struct CustomData *data, int type, int n, void *ptr) +{ + /* get the layer index of the first layer of type */ + int layer_index = CustomData_get_layer_index(data, type); + if(layer_index < 0) return NULL; + + data->layers[layer_index+n].data = ptr; + + return ptr; +} + +void CustomData_set(const CustomData *data, int index, int type, void *source) +{ + void *dest = CustomData_get(data, index, type); + const LayerTypeInfo *typeInfo = layerType_getInfo(type); + + if(!dest) return; + + if(typeInfo->copy) + typeInfo->copy(source, dest, 1); + else + memcpy(dest, source, typeInfo->size); +} + +/* EditMesh functions */ + +void CustomData_em_free_block(CustomData *data, void **block) +{ + const LayerTypeInfo *typeInfo; + int i; + + if(!*block) return; + + for(i = 0; i < data->totlayer; ++i) { + if(!(data->layers[i].flag & CD_FLAG_NOFREE)) { + typeInfo = layerType_getInfo(data->layers[i].type); + + if(typeInfo->free) { + int offset = data->layers[i].offset; + typeInfo->free((char*)*block + offset, 1, typeInfo->size); + } + } + } + + MEM_freeN(*block); + *block = NULL; +} + +static void CustomData_em_alloc_block(CustomData *data, void **block) +{ + /* TODO: optimize free/alloc */ + + if (*block) + CustomData_em_free_block(data, block); + + if (data->totsize > 0) + *block = MEM_callocN(data->totsize, "CustomData EM block"); + else + *block = NULL; +} + +void CustomData_em_copy_data(const CustomData *source, CustomData *dest, + void *src_block, void **dest_block) +{ + const LayerTypeInfo *typeInfo; + int dest_i, src_i; + + if (!*dest_block) + CustomData_em_alloc_block(dest, dest_block); + + /* copies a layer at a time */ + dest_i = 0; + for(src_i = 0; src_i < source->totlayer; ++src_i) { + + /* find the first dest layer with type >= the source type + * (this should work because layers are ordered by type) + */ + while(dest_i < dest->totlayer + && dest->layers[dest_i].type < source->layers[src_i].type) + ++dest_i; + + /* if there are no more dest layers, we're done */ + if(dest_i >= dest->totlayer) return; + + /* if we found a matching layer, copy the data */ + if(dest->layers[dest_i].type == source->layers[src_i].type) { + char *src_data = (char*)src_block + source->layers[src_i].offset; + char *dest_data = (char*)*dest_block + dest->layers[dest_i].offset; + + typeInfo = layerType_getInfo(source->layers[src_i].type); + + if(typeInfo->copy) + typeInfo->copy(src_data, dest_data, 1); + else + memcpy(dest_data, src_data, typeInfo->size); + + /* if there are multiple source & dest layers of the same type, + * we don't want to copy all source layers to the same dest, so + * increment dest_i + */ + ++dest_i; + } + } +} + +void *CustomData_em_get(const CustomData *data, void *block, int type) +{ + int layer_index; + + /* get the layer index of the first layer of type */ + layer_index = CustomData_get_active_layer_index(data, type); + if(layer_index < 0) return NULL; + + return (char *)block + data->layers[layer_index].offset; +} + +void *CustomData_em_get_n(const CustomData *data, void *block, int type, int n) +{ + int layer_index; + + /* get the layer index of the first layer of type */ + layer_index = CustomData_get_active_layer_index(data, type); + if(layer_index < 0) return NULL; + + return (char *)block + data->layers[layer_index+n].offset; +} + +void CustomData_em_set(CustomData *data, void *block, int type, void *source) +{ + void *dest = CustomData_em_get(data, block, type); + const LayerTypeInfo *typeInfo = layerType_getInfo(type); + + if(!dest) return; + + if(typeInfo->copy) + typeInfo->copy(source, dest, 1); + else + memcpy(dest, source, typeInfo->size); +} + +void CustomData_em_set_n(CustomData *data, void *block, int type, int n, void *source) +{ + void *dest = CustomData_em_get_n(data, block, type, n); + const LayerTypeInfo *typeInfo = layerType_getInfo(type); + + if(!dest) return; + + if(typeInfo->copy) + typeInfo->copy(source, dest, 1); + else + memcpy(dest, source, typeInfo->size); +} + +void CustomData_em_interp(CustomData *data, void **src_blocks, float *weights, + float *sub_weights, int count, void *dest_block) +{ + int i, j; + void *source_buf[SOURCE_BUF_SIZE]; + void **sources = source_buf; + + /* slow fallback in case we're interpolating a ridiculous number of + * elements + */ + if(count > SOURCE_BUF_SIZE) + sources = MEM_callocN(sizeof(*sources) * count, + "CustomData_interp sources"); + + /* interpolates a layer at a time */ + for(i = 0; i < data->totlayer; ++i) { + CustomDataLayer *layer = &data->layers[i]; + const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); + + if(typeInfo->interp) { + for(j = 0; j < count; ++j) + sources[j] = (char *)src_blocks[j] + layer->offset; + + typeInfo->interp(sources, weights, sub_weights, count, + (char *)dest_block + layer->offset); + } + } + + if(count > SOURCE_BUF_SIZE) MEM_freeN(sources); +} + +void CustomData_em_set_default(CustomData *data, void **block) +{ + const LayerTypeInfo *typeInfo; + int i; + + if (!*block) + CustomData_em_alloc_block(data, block); + + for(i = 0; i < data->totlayer; ++i) { + int offset = data->layers[i].offset; + + typeInfo = layerType_getInfo(data->layers[i].type); + + if(typeInfo->set_default) + typeInfo->set_default((char*)*block + offset, 1); + } +} + +void CustomData_to_em_block(const CustomData *source, CustomData *dest, + int src_index, void **dest_block) +{ + const LayerTypeInfo *typeInfo; + int dest_i, src_i, src_offset; + + if (!*dest_block) + CustomData_em_alloc_block(dest, dest_block); + + /* copies a layer at a time */ + dest_i = 0; + for(src_i = 0; src_i < source->totlayer; ++src_i) { + + /* find the first dest layer with type >= the source type + * (this should work because layers are ordered by type) + */ + while(dest_i < dest->totlayer + && dest->layers[dest_i].type < source->layers[src_i].type) + ++dest_i; + + /* if there are no more dest layers, we're done */ + if(dest_i >= dest->totlayer) return; + + /* if we found a matching layer, copy the data */ + if(dest->layers[dest_i].type == source->layers[src_i].type) { + int offset = dest->layers[dest_i].offset; + char *src_data = source->layers[src_i].data; + char *dest_data = (char*)*dest_block + offset; + + typeInfo = layerType_getInfo(dest->layers[dest_i].type); + src_offset = src_index * typeInfo->size; + + if(typeInfo->copy) + typeInfo->copy(src_data + src_offset, dest_data, 1); + else + memcpy(dest_data, src_data + src_offset, typeInfo->size); + + /* if there are multiple source & dest layers of the same type, + * we don't want to copy all source layers to the same dest, so + * increment dest_i + */ + ++dest_i; + } + } +} + +void CustomData_from_em_block(const CustomData *source, CustomData *dest, + void *src_block, int dest_index) +{ + const LayerTypeInfo *typeInfo; + int dest_i, src_i, dest_offset; + + /* copies a layer at a time */ + dest_i = 0; + for(src_i = 0; src_i < source->totlayer; ++src_i) { + + /* find the first dest layer with type >= the source type + * (this should work because layers are ordered by type) + */ + while(dest_i < dest->totlayer + && dest->layers[dest_i].type < source->layers[src_i].type) + ++dest_i; + + /* if there are no more dest layers, we're done */ + if(dest_i >= dest->totlayer) return; + + /* if we found a matching layer, copy the data */ + if(dest->layers[dest_i].type == source->layers[src_i].type) { + int offset = source->layers[src_i].offset; + char *src_data = (char*)src_block + offset; + char *dest_data = dest->layers[dest_i].data; + + typeInfo = layerType_getInfo(dest->layers[dest_i].type); + dest_offset = dest_index * typeInfo->size; + + if(typeInfo->copy) + typeInfo->copy(src_data, dest_data + dest_offset, 1); + else + memcpy(dest_data + dest_offset, src_data, typeInfo->size); + + /* if there are multiple source & dest layers of the same type, + * we don't want to copy all source layers to the same dest, so + * increment dest_i + */ + ++dest_i; + } + } + +} + +void CustomData_file_write_info(int type, char **structname, int *structnum) +{ + const LayerTypeInfo *typeInfo = layerType_getInfo(type); + + *structname = typeInfo->structname; + *structnum = typeInfo->structnum; +} + +int CustomData_sizeof(int type) +{ + const LayerTypeInfo *typeInfo = layerType_getInfo(type); + + return typeInfo->size; +} + +const char *CustomData_layertype_name(int type) +{ + return layerType_getName(type); +} + +static int CustomData_is_property_layer(int type) +{ + if((type == CD_PROP_FLT) || (type == CD_PROP_INT) || (type == CD_PROP_STR)) + return 1; + return 0; +} + +void CustomData_set_layer_unique_name(CustomData *data, int index) +{ + char tempname[64]; + int number, i, type; + char *dot, *name; + CustomDataLayer *layer, *nlayer= &data->layers[index]; + const LayerTypeInfo *typeInfo= layerType_getInfo(nlayer->type); + + if (!typeInfo->defaultname) + return; + + type = nlayer->type; + name = nlayer->name; + + if (name[0] == '\0') + BLI_strncpy(nlayer->name, typeInfo->defaultname, sizeof(nlayer->name)); + + /* see if there is a duplicate */ + for(i=0; itotlayer; i++) { + layer = &data->layers[i]; + + if(CustomData_is_property_layer(type)){ + if(i!=index && CustomData_is_property_layer(layer->type) && + strcmp(layer->name, name)==0) + break; + + } + else{ + if(i!=index && layer->type==type && strcmp(layer->name, name)==0) + break; + } + } + + if(i == data->totlayer) + return; + + /* strip off the suffix */ + dot = strchr(nlayer->name, '.'); + if(dot) *dot=0; + + for(number=1; number <=999; number++) { + sprintf(tempname, "%s.%03d", nlayer->name, number); + + for(i=0; itotlayer; i++) { + layer = &data->layers[i]; + + if(CustomData_is_property_layer(type)){ + if(i!=index && CustomData_is_property_layer(layer->type) && + strcmp(layer->name, tempname)==0) + + break; + } + else{ + if(i!=index && layer->type==type && strcmp(layer->name, tempname)==0) + break; + } + } + + if(i == data->totlayer) { + BLI_strncpy(nlayer->name, tempname, sizeof(nlayer->name)); + return; + } + } +} + +int CustomData_verify_versions(struct CustomData *data, int index) +{ + const LayerTypeInfo *typeInfo; + CustomDataLayer *layer = &data->layers[index]; + int i, keeplayer = 1; + + if (layer->type >= CD_NUMTYPES) { + keeplayer = 0; /* unknown layer type from future version */ + } + else { + typeInfo = layerType_getInfo(layer->type); + + if (!typeInfo->defaultname && (index > 0) && + data->layers[index-1].type == layer->type) + keeplayer = 0; /* multiple layers of which we only support one */ + } + + if (!keeplayer) { + for (i=index+1; i < data->totlayer; ++i) + data->layers[i-1] = data->layers[i]; + data->totlayer--; + } + + return keeplayer; +} + diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c new file mode 100644 index 00000000000..9356ba14071 --- /dev/null +++ b/source/blender/blenkernel/intern/deform.c @@ -0,0 +1,225 @@ +/* deform.c June 2001 + * + * support for deformation groups + * + * Reevan McKay + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_curve_types.h" +#include "DNA_effect_types.h" +#include "DNA_lattice_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force.h" +#include "DNA_scene_types.h" + +#include "BKE_curve.h" +#include "BKE_deform.h" +#include "BKE_displist.h" +#include "BKE_effect.h" +#include "BKE_global.h" +#include "BKE_key.h" +#include "BKE_lattice.h" +#include "BKE_object.h" +#include "BKE_softbody.h" +#include "BKE_utildefines.h" +#include "BKE_mesh.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + + +void copy_defgroups (ListBase *outbase, ListBase *inbase) +{ + bDeformGroup *defgroup, *defgroupn; + + outbase->first= outbase->last= 0; + + for (defgroup = inbase->first; defgroup; defgroup=defgroup->next){ + defgroupn= copy_defgroup(defgroup); + BLI_addtail(outbase, defgroupn); + } +} + +bDeformGroup *copy_defgroup (bDeformGroup *ingroup) +{ + bDeformGroup *outgroup; + + if (!ingroup) + return NULL; + + outgroup=MEM_callocN(sizeof(bDeformGroup), "copy deformGroup"); + + /* For now, just copy everything over. */ + memcpy (outgroup, ingroup, sizeof(bDeformGroup)); + + outgroup->next=outgroup->prev=NULL; + + return outgroup; +} + +bDeformGroup *get_named_vertexgroup (Object *ob, char *name) +{ + /* return a pointer to the deform group with this name + * or return NULL otherwise. + */ + bDeformGroup *curdef; + + for (curdef = ob->defbase.first; curdef; curdef=curdef->next) { + if (!strcmp(curdef->name, name)) { + return curdef; + } + } + return NULL; +} + +int get_named_vertexgroup_num (Object *ob, char *name) +{ + /* Return the location of the named deform group within the list of + * deform groups. This function is a combination of get_defgroup_num and + * get_named_vertexgroup. The other two could be called instead, but that + * require looping over the vertexgroups twice. + */ + bDeformGroup *curdef; + int def_nr; + + for (curdef=ob->defbase.first, def_nr=0; curdef; curdef=curdef->next, def_nr++) { + if (!strcmp(curdef->name, name)) + return def_nr; + } + + return -1; +} + +int get_defgroup_num (Object *ob, bDeformGroup *dg) +{ + /* Fetch the location of this deform group + * within the linked list of deform groups. + * (this number is stored in the deform + * weights of the deform verts to link them + * to this deform group). + */ + + bDeformGroup *eg; + int def_nr; + + eg = ob->defbase.first; + def_nr = 0; + + /* loop through all deform groups */ + while (eg != NULL) { + + /* if the current deform group is + * the one we are after, return + * def_nr + */ + if (eg == dg) { + break; + } + ++def_nr; + eg = eg->next; + } + + /* if there was no deform group found then + * return -1 (should set up a nice symbolic + * constant for this) + */ + if (eg == NULL) return -1; + + return def_nr; + +} + +void unique_vertexgroup_name (bDeformGroup *dg, Object *ob) +{ + bDeformGroup *curdef; + int number; + int exists = 0; + char tempname[64]; + char *dot; + + if (!ob) + return; + + /* See if we are given an empty string */ + if (dg->name[0] == '\0') { + /* give it default name first */ + strcpy (dg->name, "Group"); + } + + /* See if we even need to do this */ + for (curdef = ob->defbase.first; curdef; curdef=curdef->next) { + if (dg!=curdef) { + if (!strcmp(curdef->name, dg->name)) { + exists = 1; + break; + } + } + } + + if (!exists) + return; + + /* Strip off the suffix */ + dot=strchr(dg->name, '.'); + if (dot) + *dot=0; + + for (number = 1; number <=999; number++) { + sprintf (tempname, "%s.%03d", dg->name, number); + + exists = 0; + for (curdef=ob->defbase.first; curdef; curdef=curdef->next) { + if (dg!=curdef) { + if (!strcmp (curdef->name, tempname)) { + exists = 1; + break; + } + } + } + if (!exists) { + BLI_strncpy (dg->name, tempname, 32); + return; + } + } +} diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c new file mode 100644 index 00000000000..11ec8670ed1 --- /dev/null +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -0,0 +1,2236 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include +#include + +#ifdef _WIN32 +#include "BLI_winstuff.h" +#endif + +//#include "BMF_Api.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "DNA_action_types.h" +#include "DNA_armature_types.h" +#include "DNA_curve_types.h" +#include "DNA_camera_types.h" +#include "DNA_ID.h" +#include "DNA_effect_types.h" +#include "DNA_group_types.h" +#include "DNA_lattice_types.h" +#include "DNA_key_types.h" +#include "DNA_mesh_types.h" +#include "DNA_modifier_types.h" +#include "DNA_nla_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force.h" +#include "DNA_object_fluidsim.h" +#include "DNA_oops_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_view2d_types.h" +#include "DNA_view3d_types.h" + +#include "BKE_action.h" +#include "BKE_effect.h" +#include "BKE_global.h" +#include "BKE_group.h" +#include "BKE_key.h" +#include "BKE_main.h" +#include "BKE_mball.h" +#include "BKE_modifier.h" +#include "BKE_object.h" +#include "BKE_scene.h" +#include "BKE_utildefines.h" + +#include "MEM_guardedalloc.h" +#include "blendef.h" + +#include "BPY_extern.h" + + #include "depsgraph_private.h" + +/* Queue and stack operations for dag traversal + * + * the queue store a list of freenodes to avoid successives alloc/dealloc + */ + +DagNodeQueue * queue_create (int slots) +{ + DagNodeQueue * queue; + DagNodeQueueElem * elem; + int i; + + queue = MEM_mallocN(sizeof(DagNodeQueue),"DAG queue"); + queue->freenodes = MEM_mallocN(sizeof(DagNodeQueue),"DAG queue"); + queue->count = 0; + queue->maxlevel = 0; + queue->first = queue->last = NULL; + elem = MEM_mallocN(sizeof(DagNodeQueueElem),"DAG queue elem3"); + elem->node = NULL; + elem->next = NULL; + queue->freenodes->first = queue->freenodes->last = elem; + + for (i = 1; i node = NULL; + elem->next = NULL; + queue->freenodes->last->next = elem; + queue->freenodes->last = elem; + } + queue->freenodes->count = slots; + return queue; +} + +void queue_raz(DagNodeQueue *queue) +{ + DagNodeQueueElem * elem; + + elem = queue->first; + if (queue->freenodes->last) + queue->freenodes->last->next = elem; + else + queue->freenodes->first = queue->freenodes->last = elem; + + elem->node = NULL; + queue->freenodes->count++; + while (elem->next) { + elem = elem->next; + elem->node = NULL; + queue->freenodes->count++; + } + queue->freenodes->last = elem; + queue->count = 0; +} + +void queue_delete(DagNodeQueue *queue) +{ + DagNodeQueueElem * elem; + DagNodeQueueElem * temp; + + elem = queue->first; + while (elem) { + temp = elem; + elem = elem->next; + MEM_freeN(temp); + } + + elem = queue->freenodes->first; + while (elem) { + temp = elem; + elem = elem->next; + MEM_freeN(temp); + } + + MEM_freeN(queue->freenodes); + MEM_freeN(queue); +} + +/* insert in queue, remove in front */ +void push_queue(DagNodeQueue *queue, DagNode *node) +{ + DagNodeQueueElem * elem; + int i; + + if (node == NULL) { + fprintf(stderr,"pushing null node \n"); + return; + } + /*fprintf(stderr,"BFS push : %s %d\n",((ID *) node->ob)->name, queue->count);*/ + + elem = queue->freenodes->first; + if (elem != NULL) { + queue->freenodes->first = elem->next; + if ( queue->freenodes->last == elem) { + queue->freenodes->last = NULL; + queue->freenodes->first = NULL; + } + queue->freenodes->count--; + } else { /* alllocating more */ + elem = MEM_mallocN(sizeof(DagNodeQueueElem),"DAG queue elem1"); + elem->node = NULL; + elem->next = NULL; + queue->freenodes->first = queue->freenodes->last = elem; + + for (i = 1; i node = NULL; + elem->next = NULL; + queue->freenodes->last->next = elem; + queue->freenodes->last = elem; + } + queue->freenodes->count = DAGQUEUEALLOC; + + elem = queue->freenodes->first; + queue->freenodes->first = elem->next; + } + elem->next = NULL; + elem->node = node; + if (queue->last != NULL) + queue->last->next = elem; + queue->last = elem; + if (queue->first == NULL) { + queue->first = elem; + } + queue->count++; +} + + +/* insert in front, remove in front */ +void push_stack(DagNodeQueue *queue, DagNode *node) +{ + DagNodeQueueElem * elem; + int i; + + elem = queue->freenodes->first; + if (elem != NULL) { + queue->freenodes->first = elem->next; + if ( queue->freenodes->last == elem) { + queue->freenodes->last = NULL; + queue->freenodes->first = NULL; + } + queue->freenodes->count--; + } else { /* alllocating more */ + elem = MEM_mallocN(sizeof(DagNodeQueueElem),"DAG queue elem1"); + elem->node = NULL; + elem->next = NULL; + queue->freenodes->first = queue->freenodes->last = elem; + + for (i = 1; i node = NULL; + elem->next = NULL; + queue->freenodes->last->next = elem; + queue->freenodes->last = elem; + } + queue->freenodes->count = DAGQUEUEALLOC; + + elem = queue->freenodes->first; + queue->freenodes->first = elem->next; + } + elem->next = queue->first; + elem->node = node; + queue->first = elem; + if (queue->last == NULL) + queue->last = elem; + queue->count++; +} + + +DagNode * pop_queue(DagNodeQueue *queue) +{ + DagNodeQueueElem * elem; + DagNode *node; + + elem = queue->first; + if (elem) { + queue->first = elem->next; + if (queue->last == elem) { + queue->last=NULL; + queue->first=NULL; + } + queue->count--; + if (queue->freenodes->last) + queue->freenodes->last->next=elem; + queue->freenodes->last=elem; + if (queue->freenodes->first == NULL) + queue->freenodes->first=elem; + node = elem->node; + elem->node = NULL; + elem->next = NULL; + queue->freenodes->count++; + return node; + } else { + fprintf(stderr,"return null \n"); + return NULL; + } +} + +void *pop_ob_queue(struct DagNodeQueue *queue) { + return(pop_queue(queue)->ob); +} + +DagNode * get_top_node_queue(DagNodeQueue *queue) +{ + return queue->first->node; +} + +int queue_count(struct DagNodeQueue *queue){ + return queue->count; +} + + +DagForest * dag_init() +{ + DagForest *forest; + /* use callocN to init all zero */ + forest = MEM_callocN(sizeof(DagForest),"DAG root"); + return forest; +} + +static void dag_add_driver_relation(Ipo *ipo, DagForest *dag, DagNode *node, int isdata) +{ + IpoCurve *icu; + DagNode *node1; + + for(icu= ipo->curve.first; icu; icu= icu->next) { + if(icu->driver) { + + if (icu->driver->type == IPO_DRIVER_TYPE_PYTHON) { + + if ((icu->driver->flag & IPO_DRIVER_FLAG_INVALID) || (icu->driver->name[0] == '\0')) + continue; /* empty or invalid expression */ + else { + /* now we need refs to all objects mentioned in this + * pydriver expression, to call 'dag_add_relation' + * for each of them */ + Object **obarray = BPY_pydriver_get_objects(icu->driver); + if (obarray) { + Object *ob, **oba = obarray; + + while (*oba) { + ob = *oba; + node1 = dag_get_node(dag, ob); + if (ob->type == OB_ARMATURE) + dag_add_relation(dag, node1, node, isdata?DAG_RL_DATA_DATA:DAG_RL_DATA_OB); + else + dag_add_relation(dag, node1, node, isdata?DAG_RL_OB_DATA:DAG_RL_OB_OB); + oba++; + } + + MEM_freeN(obarray); + } + } + } + else if (icu->driver->ob) { + node1 = dag_get_node(dag, icu->driver->ob); + if(icu->driver->blocktype==ID_AR) + dag_add_relation(dag, node1, node, isdata?DAG_RL_DATA_DATA:DAG_RL_DATA_OB); + else + dag_add_relation(dag, node1, node, isdata?DAG_RL_OB_DATA:DAG_RL_OB_OB); + } + } + } +} + +static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int mask) +{ + bConstraint *con; + bConstraintChannel *conchan; + DagNode * node; + DagNode * node2; + DagNode * node3; + Key *key; + int addtoroot= 1; + + node = dag_get_node(dag, ob); + + if ((ob->data) && (mask&DAG_RL_DATA)) { + node2 = dag_get_node(dag,ob->data); + dag_add_relation(dag,node,node2,DAG_RL_DATA); + node2->first_ancestor = ob; + node2->ancestor_count += 1; + } + + if (ob->type == OB_ARMATURE) { + if (ob->pose){ + bPoseChannel *pchan; + bConstraint *con; + + for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) { + for (con = pchan->constraints.first; con; con=con->next) { + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + ListBase targets = {NULL, NULL}; + bConstraintTarget *ct; + + if (cti && cti->get_constraint_targets) { + cti->get_constraint_targets(con, &targets); + + for (ct= targets.first; ct; ct= ct->next) { + if (ct->tar && ct->tar != ob) { + // fprintf(stderr,"armature %s target :%s \n", ob->id.name, target->id.name); + node3 = dag_get_node(dag, ct->tar); + + if (ct->subtarget[0]) + dag_add_relation(dag,node3,node, DAG_RL_OB_DATA|DAG_RL_DATA_DATA); + else if(ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO)) + dag_add_relation(dag,node3,node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA); + else + dag_add_relation(dag,node3,node, DAG_RL_OB_DATA); + } + } + + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(con, &targets, 1); + } + + } + } + } + } + + /* driver dependencies, nla modifiers */ + if(ob->ipo) + dag_add_driver_relation(ob->ipo, dag, node, 0); + + key= ob_get_key(ob); + if(key && key->ipo) + dag_add_driver_relation(key->ipo, dag, node, 1); + + for (conchan=ob->constraintChannels.first; conchan; conchan=conchan->next) + if(conchan->ipo) + dag_add_driver_relation(conchan->ipo, dag, node, 0); + + if(ob->action) { + bActionChannel *chan; + for (chan = ob->action->chanbase.first; chan; chan=chan->next){ + if(chan->ipo) + dag_add_driver_relation(chan->ipo, dag, node, 1); + for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) + if(conchan->ipo) + dag_add_driver_relation(conchan->ipo, dag, node, 1); + } + } + if(ob->nlastrips.first) { + bActionStrip *strip; + bActionChannel *chan; + for(strip= ob->nlastrips.first; strip; strip= strip->next) { + if(strip->act && strip->act!=ob->action) + for (chan = strip->act->chanbase.first; chan; chan=chan->next) + if(chan->ipo) + dag_add_driver_relation(chan->ipo, dag, node, 1); + if(strip->modifiers.first) { + bActionModifier *amod; + for(amod= strip->modifiers.first; amod; amod= amod->next) { + if(amod->ob) { + node2 = dag_get_node(dag, amod->ob); + dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA); + } + } + } + } + } + if (ob->modifiers.first) { + ModifierData *md; + + for(md=ob->modifiers.first; md; md=md->next) { + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + if (mti->updateDepgraph) mti->updateDepgraph(md, dag, ob, node); + } + } + if (ob->parent) { + node2 = dag_get_node(dag,ob->parent); + + switch(ob->partype) { + case PARSKEL: + dag_add_relation(dag,node2,node,DAG_RL_DATA_DATA|DAG_RL_OB_OB); + break; + case PARVERT1: case PARVERT3: case PARBONE: + dag_add_relation(dag,node2,node,DAG_RL_DATA_OB|DAG_RL_OB_OB); + break; + default: + if(ob->parent->type==OB_LATTICE) + dag_add_relation(dag,node2,node,DAG_RL_DATA_DATA|DAG_RL_OB_OB); + else if(ob->parent->type==OB_CURVE) { + Curve *cu= ob->parent->data; + if(cu->flag & CU_PATH) + dag_add_relation(dag,node2,node,DAG_RL_DATA_OB|DAG_RL_OB_OB); + else + dag_add_relation(dag,node2,node,DAG_RL_OB_OB); + } + else + dag_add_relation(dag,node2,node,DAG_RL_OB_OB); + } + /* exception case: parent is duplivert */ + if(ob->type==OB_MBALL && (ob->parent->transflag & OB_DUPLIVERTS)) { + dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_OB); + } + + addtoroot = 0; + } + if (ob->track) { + node2 = dag_get_node(dag,ob->track); + dag_add_relation(dag,node2,node,DAG_RL_OB_OB); + addtoroot = 0; + } + if (ob->proxy) { + node2 = dag_get_node(dag, ob->proxy); + dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA|DAG_RL_OB_OB); + /* inverted relation, so addtoroot shouldn't be set to zero */ + } + if (ob->type==OB_CAMERA) { + Camera *cam = (Camera *)ob->data; + if (cam->dof_ob) { + node2 = dag_get_node(dag, cam->dof_ob); + dag_add_relation(dag,node2,node,DAG_RL_OB_OB); + } + } + if (ob->transflag & OB_DUPLI) { + if((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) { + GroupObject *go; + for(go= ob->dup_group->gobject.first; go; go= go->next) { + if(go->ob) { + node2 = dag_get_node(dag, go->ob); + /* node2 changes node1, this keeps animations updated in groups?? not logical? */ + dag_add_relation(dag, node2, node, DAG_RL_OB_OB); + } + } + } + } + + /* softbody collision */ + if((ob->type==OB_MESH) || (ob->type==OB_CURVE) || (ob->type==OB_LATTICE)) { + Base *base; + if(modifiers_isSoftbodyEnabled(ob)){ + // would be nice to have a list of colliders here + // so for now walk all objects in scene check 'same layer rule' + for(base = G.scene->base.first; base; base= base->next) { + if( (base->lay & ob->lay) && base->object->pd) { + Object *ob1= base->object; + if((ob1->pd->deflect) && (ob1 != ob)) { + node2 = dag_get_node(dag, ob1); + dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA); + } + } + } + } + } + + if (ob->type==OB_MBALL) { + Object *mom= find_basis_mball(ob); + if(mom!=ob) { + node2 = dag_get_node(dag, mom); + dag_add_relation(dag,node,node2,DAG_RL_DATA_DATA|DAG_RL_OB_DATA); // mom depends on children! + } + } + else if (ob->type==OB_CURVE) { + Curve *cu= ob->data; + if(cu->bevobj) { + node2 = dag_get_node(dag, cu->bevobj); + dag_add_relation(dag,node2,node,DAG_RL_DATA_DATA|DAG_RL_OB_DATA); + } + if(cu->taperobj) { + node2 = dag_get_node(dag, cu->taperobj); + dag_add_relation(dag,node2,node,DAG_RL_DATA_DATA|DAG_RL_OB_DATA); + } + if(cu->ipo) + dag_add_driver_relation(cu->ipo, dag, node, 1); + + } + else if(ob->type==OB_FONT) { + Curve *cu= ob->data; + if(cu->textoncurve) { + node2 = dag_get_node(dag, cu->textoncurve); + dag_add_relation(dag,node2,node,DAG_RL_DATA_DATA|DAG_RL_OB_DATA); + } + } + else if(ob->type==OB_MESH) { + PartEff *paf= give_parteff(ob); + if(paf) { + ListBase *listb; + pEffectorCache *ec; + + /* ob location depends on itself */ + if((paf->flag & PAF_STATIC)==0) + dag_add_relation(dag, node, node, DAG_RL_OB_DATA); + + listb= pdInitEffectors(ob, paf->group); /* note, makes copy... */ + if(listb) { + for(ec= listb->first; ec; ec= ec->next) { + Object *ob1= ec->ob; + PartDeflect *pd= ob1->pd; + + if(pd->forcefield) { + node2 = dag_get_node(dag, ob1); + if(pd->forcefield==PFIELD_GUIDE) + dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA); + else + dag_add_relation(dag, node2, node, DAG_RL_OB_DATA); + } + } + + pdEndEffectors(listb); /* restores copy... */ + } + } + } + + for (con = ob->constraints.first; con; con=con->next) { + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + ListBase targets = {NULL, NULL}; + bConstraintTarget *ct; + + if (cti && cti->get_constraint_targets) { + cti->get_constraint_targets(con, &targets); + + for (ct= targets.first; ct; ct= ct->next) { + Object *obt; + + if (ct->tar) + obt= ct->tar; + else + continue; + + node2 = dag_get_node(dag, obt); + if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO)) + dag_add_relation(dag, node2, node, DAG_RL_DATA_OB|DAG_RL_OB_OB); + else { + if (ELEM3(obt->type, OB_ARMATURE, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) + dag_add_relation(dag, node2, node, DAG_RL_DATA_OB|DAG_RL_OB_OB); + else + dag_add_relation(dag, node2, node, DAG_RL_OB_OB); + } + addtoroot = 0; + } + + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(con, &targets, 1); + } + } + + if (addtoroot == 1 ) + dag_add_relation(dag,scenenode,node,DAG_RL_SCENE); +} + +struct DagForest *build_dag(struct Scene *sce, short mask) +{ + Base *base; + Object *ob; + Group *group; + GroupObject *go; + DagNode *node; + DagNode *scenenode; + DagForest *dag; + DagAdjList *itA; + + dag = sce->theDag; + sce->dagisvalid=1; + if ( dag) + free_forest( dag ); + else { + dag = dag_init(); + sce->theDag = dag; + } + + /* add base node for scene. scene is always the first node in DAG */ + scenenode = dag_add_node(dag, sce); + + /* add current scene objects */ + for(base = sce->base.first; base; base= base->next) { + ob= base->object; + + build_dag_object(dag, scenenode, ob, mask); + if(ob->proxy) + build_dag_object(dag, scenenode, ob->proxy, mask); + + /* handled in next loop */ + if(ob->dup_group) + ob->dup_group->id.flag |= LIB_DOIT; + } + + /* add groups used in current scene objects */ + for(group= G.main->group.first; group; group= group->id.next) { + if(group->id.flag & LIB_DOIT) { + for(go= group->gobject.first; go; go= go->next) { + build_dag_object(dag, scenenode, go->ob, mask); + } + group->id.flag &= ~LIB_DOIT; + } + } + + /* Now all relations were built, but we need to solve 1 exceptional case; + When objects have multiple "parents" (for example parent + constraint working on same object) + the relation type has to be synced. One of the parents can change, and should give same event to child */ + + /* nodes were callocced, so we can use node->color for temporal storage */ + for(node = sce->theDag->DagNode.first; node; node= node->next) { + if(node->type==ID_OB) { + for(itA = node->child; itA; itA= itA->next) { + if(itA->node->type==ID_OB) { + itA->node->color |= itA->type; + } + } + } + } + /* now set relations equal, so that when only one parent changes, the correct recalcs are found */ + for(node = sce->theDag->DagNode.first; node; node= node->next) { + if(node->type==ID_OB) { + for(itA = node->child; itA; itA= itA->next) { + if(itA->node->type==ID_OB) { + itA->type |= itA->node->color; + } + } + } + } + + // cycle detection and solving + // solve_cycles(dag); + + return dag; +} + + +void free_forest(DagForest *Dag) +{ /* remove all nodes and deps */ + DagNode *tempN; + DagAdjList *tempA; + DagAdjList *itA; + DagNode *itN = Dag->DagNode.first; + + while (itN) { + itA = itN->child; + while (itA) { + tempA = itA; + itA = itA->next; + MEM_freeN(tempA); + } + + itA = itN->parent; + while (itA) { + tempA = itA; + itA = itA->next; + MEM_freeN(tempA); + } + + tempN = itN; + itN = itN->next; + MEM_freeN(tempN); + } + Dag->DagNode.first = NULL; + Dag->DagNode.last = NULL; + Dag->numNodes = 0; + +} + +DagNode * dag_find_node (DagForest *forest,void * fob) +{ + DagNode *node = forest->DagNode.first; + + while (node) { + if (node->ob == fob) + return node; + node = node->next; + } + return NULL; +} + +static int ugly_hack_sorry= 1; // prevent type check + +/* no checking of existance, use dag_find_node first or dag_get_node */ +DagNode * dag_add_node (DagForest *forest, void * fob) +{ + DagNode *node; + + node = MEM_callocN(sizeof(DagNode),"DAG node"); + if (node) { + node->ob = fob; + node->color = DAG_WHITE; + + if(ugly_hack_sorry) node->type = GS(((ID *) fob)->name); // sorry, done for pose sorting + if (forest->numNodes) { + ((DagNode *) forest->DagNode.last)->next = node; + forest->DagNode.last = node; + forest->numNodes++; + } else { + forest->DagNode.last = node; + forest->DagNode.first = node; + forest->numNodes = 1; + } + } + return node; +} + +DagNode * dag_get_node (DagForest *forest,void * fob) +{ + DagNode *node; + + node = dag_find_node (forest, fob); + if (!node) + node = dag_add_node(forest, fob); + return node; +} + + + +DagNode * dag_get_sub_node (DagForest *forest,void * fob) +{ + DagNode *node; + DagAdjList *mainchild, *prev=NULL; + + mainchild = ((DagNode *) forest->DagNode.first)->child; + /* remove from first node (scene) adj list if present */ + while (mainchild) { + if (mainchild->node == fob) { + if (prev) { + prev->next = mainchild->next; + MEM_freeN(mainchild); + break; + } else { + ((DagNode *) forest->DagNode.first)->child = mainchild->next; + MEM_freeN(mainchild); + break; + } + } + prev = mainchild; + mainchild = mainchild->next; + } + node = dag_find_node (forest, fob); + if (!node) + node = dag_add_node(forest, fob); + return node; +} + +void dag_add_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel) +{ + DagAdjList *itA = fob1->child; + + while (itA) { /* search if relation exist already */ + if (itA->node == fob2) { + itA->type |= rel; + itA->count += 1; + return; + } + itA = itA->next; + } + /* create new relation and insert at head. MALLOC alert! */ + itA = MEM_mallocN(sizeof(DagAdjList),"DAG adj list"); + itA->node = fob2; + itA->type = rel; + itA->count = 1; + itA->next = fob1->child; + fob1->child = itA; +} + +static void dag_add_parent_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel) +{ + DagAdjList *itA = fob2->parent; + + while (itA) { /* search if relation exist already */ + if (itA->node == fob1) { + itA->type |= rel; + itA->count += 1; + return; + } + itA = itA->next; + } + /* create new relation and insert at head. MALLOC alert! */ + itA = MEM_mallocN(sizeof(DagAdjList),"DAG adj list"); + itA->node = fob1; + itA->type = rel; + itA->count = 1; + itA->next = fob2->parent; + fob2->parent = itA; +} + + +/* + * MainDAG is the DAG of all objects in current scene + * used only for drawing there is one also in each scene + */ +static DagForest * MainDag = NULL; + +DagForest *getMainDag(void) +{ + return MainDag; +} + + +void setMainDag(DagForest *dag) +{ + MainDag = dag; +} + + +/* + * note for BFS/DFS + * in theory we should sweep the whole array + * but in our case the first node is the scene + * and is linked to every other object + * + * for general case we will need to add outer loop + */ + +/* + * ToDo : change pos kludge + */ + +/* adjust levels for drawing in oops space */ +void graph_bfs(void) +{ + DagNode *node; + DagNodeQueue *nqueue; + int pos[50]; + int i; + DagAdjList *itA; + int minheight; + + /* fprintf(stderr,"starting BFS \n ------------\n"); */ + nqueue = queue_create(DAGQUEUEALLOC); + for ( i=0; i<50; i++) + pos[i] = 0; + + /* Init + * dagnode.first is alway the root (scene) + */ + node = MainDag->DagNode.first; + while(node) { + node->color = DAG_WHITE; + node->BFS_dist = 9999; + node->k = 0; + node = node->next; + } + + node = MainDag->DagNode.first; + if (node->color == DAG_WHITE) { + node->color = DAG_GRAY; + node->BFS_dist = 1; + push_queue(nqueue,node); + while(nqueue->count) { + node = pop_queue(nqueue); + + minheight = pos[node->BFS_dist]; + itA = node->child; + while(itA != NULL) { + if((itA->node->color == DAG_WHITE) ) { + itA->node->color = DAG_GRAY; + itA->node->BFS_dist = node->BFS_dist + 1; + itA->node->k = (float) minheight; + push_queue(nqueue,itA->node); + } + + else { + fprintf(stderr,"bfs not dag tree edge color :%i \n",itA->node->color); + } + + + itA = itA->next; + } + if (pos[node->BFS_dist] > node->k ) { + pos[node->BFS_dist] += 1; + node->k = (float) pos[node->BFS_dist]; + } else { + pos[node->BFS_dist] = (int) node->k +1; + } + set_node_xy(node, node->BFS_dist*DEPSX*2, pos[node->BFS_dist]*DEPSY*2); + node->color = DAG_BLACK; + /* + fprintf(stderr,"BFS node : %20s %i %5.0f %5.0f\n",((ID *) node->ob)->name,node->BFS_dist, node->x, node->y); + */ + } + } + queue_delete(nqueue); +} + +int pre_and_post_BFS(DagForest *dag, short mask, graph_action_func pre_func, graph_action_func post_func, void **data) { + DagNode *node; + + node = dag->DagNode.first; + return pre_and_post_source_BFS(dag, mask, node, pre_func, post_func, data); +} + + +int pre_and_post_source_BFS(DagForest *dag, short mask, DagNode *source, graph_action_func pre_func, graph_action_func post_func, void **data) +{ + DagNode *node; + DagNodeQueue *nqueue; + DagAdjList *itA; + int retval = 0; + /* fprintf(stderr,"starting BFS \n ------------\n"); */ + + /* Init + * dagnode.first is alway the root (scene) + */ + node = dag->DagNode.first; + nqueue = queue_create(DAGQUEUEALLOC); + while(node) { + node->color = DAG_WHITE; + node->BFS_dist = 9999; + node = node->next; + } + + node = source; + if (node->color == DAG_WHITE) { + node->color = DAG_GRAY; + node->BFS_dist = 1; + pre_func(node->ob,data); + + while(nqueue->count) { + node = pop_queue(nqueue); + + itA = node->child; + while(itA != NULL) { + if((itA->node->color == DAG_WHITE) && (itA->type & mask)) { + itA->node->color = DAG_GRAY; + itA->node->BFS_dist = node->BFS_dist + 1; + push_queue(nqueue,itA->node); + pre_func(node->ob,data); + } + + else { // back or cross edge + retval = 1; + } + itA = itA->next; + } + post_func(node->ob,data); + node->color = DAG_BLACK; + /* + fprintf(stderr,"BFS node : %20s %i %5.0f %5.0f\n",((ID *) node->ob)->name,node->BFS_dist, node->x, node->y); + */ + } + } + queue_delete(nqueue); + return retval; +} + +/* non recursive version of DFS, return queue -- outer loop present to catch odd cases (first level cycles)*/ +DagNodeQueue * graph_dfs(void) +{ + DagNode *node; + DagNodeQueue *nqueue; + DagNodeQueue *retqueue; + int pos[50]; + int i; + DagAdjList *itA; + int time; + int skip = 0; + int minheight; + int maxpos=0; + int is_cycle = 0; + /* + *fprintf(stderr,"starting DFS \n ------------\n"); + */ + nqueue = queue_create(DAGQUEUEALLOC); + retqueue = queue_create(MainDag->numNodes); + for ( i=0; i<50; i++) + pos[i] = 0; + + /* Init + * dagnode.first is alway the root (scene) + */ + node = MainDag->DagNode.first; + while(node) { + node->color = DAG_WHITE; + node->DFS_dist = 9999; + node->DFS_dvtm = node->DFS_fntm = 9999; + node->k = 0; + node = node->next; + } + + time = 1; + + node = MainDag->DagNode.first; + + do { + if (node->color == DAG_WHITE) { + node->color = DAG_GRAY; + node->DFS_dist = 1; + node->DFS_dvtm = time; + time++; + push_stack(nqueue,node); + + while(nqueue->count) { + //graph_print_queue(nqueue); + + skip = 0; + node = get_top_node_queue(nqueue); + + minheight = pos[node->DFS_dist]; + + itA = node->child; + while(itA != NULL) { + if((itA->node->color == DAG_WHITE) ) { + itA->node->DFS_dvtm = time; + itA->node->color = DAG_GRAY; + + time++; + itA->node->DFS_dist = node->DFS_dist + 1; + itA->node->k = (float) minheight; + push_stack(nqueue,itA->node); + skip = 1; + break; + } else { + if (itA->node->color == DAG_GRAY) { // back edge + fprintf(stderr,"dfs back edge :%15s %15s \n",((ID *) node->ob)->name, ((ID *) itA->node->ob)->name); + is_cycle = 1; + } else if (itA->node->color == DAG_BLACK) { + ; + /* already processed node but we may want later to change distance either to shorter to longer. + * DFS_dist is the first encounter + */ + /*if (node->DFS_dist >= itA->node->DFS_dist) + itA->node->DFS_dist = node->DFS_dist + 1; + + fprintf(stderr,"dfs forward or cross edge :%15s %i-%i %15s %i-%i \n", + ((ID *) node->ob)->name, + node->DFS_dvtm, + node->DFS_fntm, + ((ID *) itA->node->ob)->name, + itA->node->DFS_dvtm, + itA->node->DFS_fntm); + */ + } else + fprintf(stderr,"dfs unknown edge \n"); + } + itA = itA->next; + } + + if (!skip) { + node = pop_queue(nqueue); + node->color = DAG_BLACK; + + node->DFS_fntm = time; + time++; + if (node->DFS_dist > maxpos) + maxpos = node->DFS_dist; + if (pos[node->DFS_dist] > node->k ) { + pos[node->DFS_dist] += 1; + node->k = (float) pos[node->DFS_dist]; + } else { + pos[node->DFS_dist] = (int) node->k +1; + } + set_node_xy(node, node->DFS_dist*DEPSX*2, pos[node->DFS_dist]*DEPSY*2); + + /* + fprintf(stderr,"DFS node : %20s %i %i %i %i\n",((ID *) node->ob)->name,node->BFS_dist, node->DFS_dist, node->DFS_dvtm, node->DFS_fntm ); + */ + push_stack(retqueue,node); + + } + } + } + node = node->next; + } while (node); +// fprintf(stderr,"i size : %i \n", maxpos); + + queue_delete(nqueue); + return(retqueue); +} + +/* unused */ +int pre_and_post_DFS(DagForest *dag, short mask, graph_action_func pre_func, graph_action_func post_func, void **data) { + DagNode *node; + + node = dag->DagNode.first; + return pre_and_post_source_DFS(dag, mask, node, pre_func, post_func, data); +} + +int pre_and_post_source_DFS(DagForest *dag, short mask, DagNode *source, graph_action_func pre_func, graph_action_func post_func, void **data) +{ + DagNode *node; + DagNodeQueue *nqueue; + DagAdjList *itA; + int time; + int skip = 0; + int retval = 0; + /* + *fprintf(stderr,"starting DFS \n ------------\n"); + */ + nqueue = queue_create(DAGQUEUEALLOC); + + /* Init + * dagnode.first is alway the root (scene) + */ + node = dag->DagNode.first; + while(node) { + node->color = DAG_WHITE; + node->DFS_dist = 9999; + node->DFS_dvtm = node->DFS_fntm = 9999; + node->k = 0; + node = node->next; + } + + time = 1; + + node = source; + do { + if (node->color == DAG_WHITE) { + node->color = DAG_GRAY; + node->DFS_dist = 1; + node->DFS_dvtm = time; + time++; + push_stack(nqueue,node); + pre_func(node->ob,data); + + while(nqueue->count) { + skip = 0; + node = get_top_node_queue(nqueue); + + itA = node->child; + while(itA != NULL) { + if((itA->node->color == DAG_WHITE) && (itA->type & mask) ) { + itA->node->DFS_dvtm = time; + itA->node->color = DAG_GRAY; + + time++; + itA->node->DFS_dist = node->DFS_dist + 1; + push_stack(nqueue,itA->node); + pre_func(node->ob,data); + + skip = 1; + break; + } else { + if (itA->node->color == DAG_GRAY) {// back edge + retval = 1; + } +// else if (itA->node->color == DAG_BLACK) { // cross or forward +// ; + } + itA = itA->next; + } + + if (!skip) { + node = pop_queue(nqueue); + node->color = DAG_BLACK; + + node->DFS_fntm = time; + time++; + post_func(node->ob,data); + } + } + } + node = node->next; + } while (node); + queue_delete(nqueue); + return(retval); +} + + +// used to get the obs owning a datablock +struct DagNodeQueue *get_obparents(struct DagForest *dag, void *ob) +{ + DagNode * node, *node1; + DagNodeQueue *nqueue; + DagAdjList *itA; + + node = dag_find_node(dag,ob); + if(node==NULL) { + return NULL; + } + else if (node->ancestor_count == 1) { // simple case + nqueue = queue_create(1); + push_queue(nqueue,node); + } else { // need to go over the whole dag for adj list + nqueue = queue_create(node->ancestor_count); + + node1 = dag->DagNode.first; + do { + if (node1->DFS_fntm > node->DFS_fntm) { // a parent is finished after child. must check adj list + itA = node->child; + while(itA != NULL) { + if ((itA->node == node) && (itA->type == DAG_RL_DATA)) { + push_queue(nqueue,node); + } + itA = itA->next; + } + } + node1 = node1->next; + } while (node1); + } + return nqueue; +} + +struct DagNodeQueue *get_first_ancestors(struct DagForest *dag, void *ob) +{ + DagNode * node, *node1; + DagNodeQueue *nqueue; + DagAdjList *itA; + + node = dag_find_node(dag,ob); + + // need to go over the whole dag for adj list + nqueue = queue_create(node->ancestor_count); + + node1 = dag->DagNode.first; + do { + if (node1->DFS_fntm > node->DFS_fntm) { + itA = node->child; + while(itA != NULL) { + if (itA->node == node) { + push_queue(nqueue,node); + } + itA = itA->next; + } + } + node1 = node1->next; + } while (node1); + + return nqueue; +} + +// standard DFS list +struct DagNodeQueue *get_all_childs(struct DagForest *dag, void *ob) +{ + DagNode *node; + DagNodeQueue *nqueue; + DagNodeQueue *retqueue; + DagAdjList *itA; + int time; + int skip = 0; + + nqueue = queue_create(DAGQUEUEALLOC); + retqueue = queue_create(dag->numNodes); // was MainDag... why? (ton) + + node = dag->DagNode.first; + while(node) { + node->color = DAG_WHITE; + node = node->next; + } + + time = 1; + + node = dag_find_node(dag, ob); // could be done in loop above (ton) + if(node) { // can be null for newly added objects + + node->color = DAG_GRAY; + time++; + push_stack(nqueue,node); + + while(nqueue->count) { + + skip = 0; + node = get_top_node_queue(nqueue); + + itA = node->child; + while(itA != NULL) { + if((itA->node->color == DAG_WHITE) ) { + itA->node->DFS_dvtm = time; + itA->node->color = DAG_GRAY; + + time++; + push_stack(nqueue,itA->node); + skip = 1; + break; + } + itA = itA->next; + } + + if (!skip) { + node = pop_queue(nqueue); + node->color = DAG_BLACK; + + time++; + push_stack(retqueue,node); + } + } + } + queue_delete(nqueue); + return(retqueue); +} + +/* unused */ +short are_obs_related(struct DagForest *dag, void *ob1, void *ob2) { + DagNode * node; + DagAdjList *itA; + + node = dag_find_node(dag, ob1); + + itA = node->child; + while(itA != NULL) { + if((itA->node->ob == ob2) ) { + return itA->node->type; + } + itA = itA->next; + } + return DAG_NO_RELATION; +} + +int is_acyclic( DagForest *dag) { + return dag->is_acyclic; +} + +void set_node_xy(DagNode *node, float x, float y) +{ + node->x = x; + node->y = y; +} + + +/* debug test functions */ + +void graph_print_queue(DagNodeQueue *nqueue) +{ + DagNodeQueueElem *queueElem; + + queueElem = nqueue->first; + while(queueElem) { + fprintf(stderr,"** %s %i %i-%i ",((ID *) queueElem->node->ob)->name,queueElem->node->color,queueElem->node->DFS_dvtm,queueElem->node->DFS_fntm); + queueElem = queueElem->next; + } + fprintf(stderr,"\n"); +} + +void graph_print_queue_dist(DagNodeQueue *nqueue) +{ + DagNodeQueueElem *queueElem; + int max, count; + + queueElem = nqueue->first; + max = queueElem->node->DFS_fntm; + count = 0; + while(queueElem) { + fprintf(stderr,"** %25s %2.2i-%2.2i ",((ID *) queueElem->node->ob)->name,queueElem->node->DFS_dvtm,queueElem->node->DFS_fntm); + while (count < queueElem->node->DFS_dvtm-1) { fputc(' ',stderr); count++;} + fputc('|',stderr); + while (count < queueElem->node->DFS_fntm-2) { fputc('-',stderr); count++;} + fputc('|',stderr); + fputc('\n',stderr); + count = 0; + queueElem = queueElem->next; + } + fprintf(stderr,"\n"); +} + +void graph_print_adj_list(void) +{ + DagNode *node; + DagAdjList *itA; + + node = (getMainDag())->DagNode.first; + while(node) { + fprintf(stderr,"node : %s col: %i",((ID *) node->ob)->name, node->color); + itA = node->child; + while (itA) { + fprintf(stderr,"-- %s ",((ID *) itA->node->ob)->name); + + itA = itA->next; + } + fprintf(stderr,"\n"); + node = node->next; + } +} + +/* ************************ API *********************** */ + +/* groups with objects in this scene need to be put in the right order as well */ +static void scene_sort_groups(Scene *sce) +{ + Base *base; + Group *group; + GroupObject *go; + Object *ob; + + /* test; are group objects all in this scene? */ + for(ob= G.main->object.first; ob; ob= ob->id.next) { + ob->id.flag &= ~LIB_DOIT; + ob->id.newid= NULL; /* newid abuse for GroupObject */ + } + for(base = sce->base.first; base; base= base->next) + base->object->id.flag |= LIB_DOIT; + + for(group= G.main->group.first; group; group= group->id.next) { + for(go= group->gobject.first; go; go= go->next) { + if((go->ob->id.flag & LIB_DOIT)==0) + break; + } + /* this group is entirely in this scene */ + if(go==NULL) { + ListBase listb= {NULL, NULL}; + + for(go= group->gobject.first; go; go= go->next) + go->ob->id.newid= (ID *)go; + + /* in order of sorted bases we reinsert group objects */ + for(base = sce->base.first; base; base= base->next) { + + if(base->object->id.newid) { + go= (GroupObject *)base->object->id.newid; + base->object->id.newid= NULL; + BLI_remlink( &group->gobject, go); + BLI_addtail( &listb, go); + } + } + /* copy the newly sorted listbase */ + group->gobject= listb; + } + } +} + +/* sort the base list on dependency order */ +void DAG_scene_sort(struct Scene *sce) +{ + DagNode *node; + DagNodeQueue *nqueue; + DagAdjList *itA; + int time; + int skip = 0; + ListBase tempbase; + Base *base; + + tempbase.first= tempbase.last= NULL; + + build_dag(sce, DAG_RL_ALL_BUT_DATA); + + nqueue = queue_create(DAGQUEUEALLOC); + + for(node = sce->theDag->DagNode.first; node; node= node->next) { + node->color = DAG_WHITE; + } + + time = 1; + + node = sce->theDag->DagNode.first; + + node->color = DAG_GRAY; + time++; + push_stack(nqueue,node); + + while(nqueue->count) { + + skip = 0; + node = get_top_node_queue(nqueue); + + itA = node->child; + while(itA != NULL) { + if((itA->node->color == DAG_WHITE) ) { + itA->node->DFS_dvtm = time; + itA->node->color = DAG_GRAY; + + time++; + push_stack(nqueue,itA->node); + skip = 1; + break; + } + itA = itA->next; + } + + if (!skip) { + if (node) { + node = pop_queue(nqueue); + if (node->ob == sce) // we are done + break ; + node->color = DAG_BLACK; + + time++; + base = sce->base.first; + while (base && base->object != node->ob) + base = base->next; + if(base) { + BLI_remlink(&sce->base,base); + BLI_addhead(&tempbase,base); + } + } + } + } + + // temporal correction for circular dependancies + base = sce->base.first; + while (base) { + BLI_remlink(&sce->base,base); + BLI_addhead(&tempbase,base); + //if(G.f & G_DEBUG) + printf("cyclic %s\n", base->object->id.name); + base = sce->base.first; + } + + sce->base = tempbase; + queue_delete(nqueue); + + /* all groups with objects in this scene gets resorted too */ + scene_sort_groups(sce); + + if(G.f & G_DEBUG) { + printf("\nordered\n"); + for(base = sce->base.first; base; base= base->next) { + printf(" %s\n", base->object->id.name); + } + } + /* temporal...? */ + sce->recalc |= SCE_PRV_CHANGED; /* test for 3d preview */ +} + +/* node was checked to have lasttime != curtime and is if type ID_OB */ +static void flush_update_node(DagNode *node, unsigned int layer, int curtime) +{ + DagAdjList *itA; + Object *ob, *obc; + int oldflag, changed=0; + unsigned int all_layer; + + node->lasttime= curtime; + + ob= node->ob; + if(ob && (ob->recalc & OB_RECALC)) { + all_layer= ob->lay; + /* got an object node that changes, now check relations */ + for(itA = node->child; itA; itA= itA->next) { + all_layer |= itA->lay; + /* the relationship is visible */ + if(itA->lay & layer) { + if(itA->node->type==ID_OB) { + obc= itA->node->ob; + oldflag= obc->recalc; + + /* got a ob->obc relation, now check if flag needs flush */ + if(ob->recalc & OB_RECALC_OB) { + if(itA->type & DAG_RL_OB_OB) { + //printf("ob %s changes ob %s\n", ob->id.name, obc->id.name); + obc->recalc |= OB_RECALC_OB; + } + if(itA->type & DAG_RL_OB_DATA) { + //printf("ob %s changes obdata %s\n", ob->id.name, obc->id.name); + obc->recalc |= OB_RECALC_DATA; + } + } + if(ob->recalc & OB_RECALC_DATA) { + if(itA->type & DAG_RL_DATA_OB) { + //printf("obdata %s changes ob %s\n", ob->id.name, obc->id.name); + obc->recalc |= OB_RECALC_OB; + } + if(itA->type & DAG_RL_DATA_DATA) { + //printf("obdata %s changes obdata %s\n", ob->id.name, obc->id.name); + obc->recalc |= OB_RECALC_DATA; + } + } + if(oldflag!=obc->recalc) changed= 1; + } + } + } + /* even nicer, we can clear recalc flags... */ + if((all_layer & layer)==0) { + /* but existing displaylists or derivedmesh should be freed */ + if(ob->recalc & OB_RECALC_DATA) + object_free_display(ob); + + ob->recalc &= ~OB_RECALC; + } + } + + /* check case where child changes and parent forcing obdata to change */ + /* should be done regardless if this ob has recalc set */ + /* could merge this in with loop above...? (ton) */ + for(itA = node->child; itA; itA= itA->next) { + /* the relationship is visible */ + if(itA->lay & layer) { + if(itA->node->type==ID_OB) { + obc= itA->node->ob; + /* child moves */ + if((obc->recalc & OB_RECALC)==OB_RECALC_OB) { + /* parent has deforming info */ + if(itA->type & (DAG_RL_OB_DATA|DAG_RL_DATA_DATA)) { + // printf("parent %s changes ob %s\n", ob->id.name, obc->id.name); + obc->recalc |= OB_RECALC_DATA; + } + } + } + } + } + + /* we only go deeper if node not checked or something changed */ + for(itA = node->child; itA; itA= itA->next) { + if(changed || itA->node->lasttime!=curtime) + flush_update_node(itA->node, layer, curtime); + } + +} + +/* node was checked to have lasttime != curtime , and is of type ID_OB */ +static unsigned int flush_layer_node(DagNode *node, int curtime) +{ + DagAdjList *itA; + + node->lasttime= curtime; + node->lay= ((Object *)node->ob)->lay; + + for(itA = node->child; itA; itA= itA->next) { + if(itA->node->type==ID_OB) { + if(itA->node->lasttime!=curtime) { + itA->lay= flush_layer_node(itA->node, curtime); // lay is only set once for each relation + //printf("layer %d for relation %s to %s\n", itA->lay, ((Object *)node->ob)->id.name, ((Object *)itA->node->ob)->id.name); + } + else itA->lay= itA->node->lay; + + node->lay |= itA->lay; + } + } + + return node->lay; +} + +/* flushes all recalc flags in objects down the dependency tree */ +void DAG_scene_flush_update(Scene *sce, unsigned int lay) +{ + DagNode *firstnode; + DagAdjList *itA; + int lasttime; + + if(sce->theDag==NULL) { + printf("DAG zero... not allowed to happen!\n"); + DAG_scene_sort(sce); + } + + firstnode= sce->theDag->DagNode.first; // always scene node + + /* first we flush the layer flags */ + sce->theDag->time++; // so we know which nodes were accessed + lasttime= sce->theDag->time; + for(itA = firstnode->child; itA; itA= itA->next) { + if(itA->node->lasttime!=lasttime && itA->node->type==ID_OB) + flush_layer_node(itA->node, lasttime); + } + + /* then we use the relationships + layer info to flush update events */ + sce->theDag->time++; // so we know which nodes were accessed + lasttime= sce->theDag->time; + for(itA = firstnode->child; itA; itA= itA->next) { + if(itA->node->lasttime!=lasttime && itA->node->type==ID_OB) + flush_update_node(itA->node, lay, lasttime); + } +} + +static int object_modifiers_use_time(Object *ob) +{ + ModifierData *md; + + for (md=ob->modifiers.first; md; md=md->next) + if (modifier_dependsOnTime(md)) + return 1; + + return 0; +} + +static int exists_channel(Object *ob, char *name) +{ + bActionStrip *strip; + + if(ob->action) + if(get_action_channel(ob->action, name)) + return 1; + + for (strip=ob->nlastrips.first; strip; strip=strip->next) + if(get_action_channel(strip->act, name)) + return 1; + return 0; +} + +static void dag_object_time_update_flags(Object *ob) +{ + + if(ob->ipo) ob->recalc |= OB_RECALC_OB; + else if(ob->constraints.first) { + bConstraint *con; + for (con = ob->constraints.first; con; con=con->next) { + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + ListBase targets = {NULL, NULL}; + bConstraintTarget *ct; + + if (cti && cti->get_constraint_targets) { + cti->get_constraint_targets(con, &targets); + + for (ct= targets.first; ct; ct= ct->next) { + if (ct->tar) { + ob->recalc |= OB_RECALC_OB; + break; + } + } + + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(con, &targets, 1); + } + } + } + else if(ob->scriptlink.totscript) ob->recalc |= OB_RECALC_OB; + else if(ob->parent) { + /* motion path or bone child */ + if(ob->parent->type==OB_CURVE || ob->parent->type==OB_ARMATURE) ob->recalc |= OB_RECALC_OB; + } + + if(ob->action || ob->nlastrips.first) { + /* since actions now are mixed, we set the recalcs on the safe side */ + ob->recalc |= OB_RECALC_OB; + if(ob->type==OB_ARMATURE) + ob->recalc |= OB_RECALC_DATA; + else if(exists_channel(ob, "Shape")) + ob->recalc |= OB_RECALC_DATA; + else if(ob->dup_group) { + bActionStrip *strip; + /* this case is for groups with nla, whilst nla target has no action or nla */ + for(strip= ob->nlastrips.first; strip; strip= strip->next) { + if(strip->object) + strip->object->recalc |= OB_RECALC; + } + } + } + else if(modifiers_isSoftbodyEnabled(ob)) ob->recalc |= OB_RECALC_DATA; + else if(object_modifiers_use_time(ob)) ob->recalc |= OB_RECALC_DATA; + else { + Mesh *me; + Curve *cu; + Lattice *lt; + + switch(ob->type) { + case OB_MESH: + me= ob->data; + if(me->key) { + if(!(ob->shapeflag & OB_SHAPE_LOCK)) { + ob->recalc |= OB_RECALC_DATA; + ob->shapeflag &= ~OB_SHAPE_TEMPLOCK; + } + } + else if(ob->effect.first) { + Effect *eff= ob->effect.first; + PartEff *paf= give_parteff(ob); + + if(eff->type==EFF_WAVE) + ob->recalc |= OB_RECALC_DATA; + else if(paf && paf->keys==NULL) + ob->recalc |= OB_RECALC_DATA; + } + if((ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) && (ob->fluidsimSettings)) { + // fluidsimSettings might not be initialized during load... + if(ob->fluidsimSettings->type & (OB_FLUIDSIM_DOMAIN|OB_FLUIDSIM_PARTICLE)) { + ob->recalc |= OB_RECALC_DATA; // NT FSPARTICLE + } + } + break; + case OB_CURVE: + case OB_SURF: + cu= ob->data; + if(cu->key) { + if(!(ob->shapeflag & OB_SHAPE_LOCK)) { + ob->recalc |= OB_RECALC_DATA; + ob->shapeflag &= ~OB_SHAPE_TEMPLOCK; + } + } + break; + case OB_FONT: + cu= ob->data; + if(cu->nurb.first==NULL && cu->str && cu->vfont) + ob->recalc |= OB_RECALC_DATA; + break; + case OB_LATTICE: + lt= ob->data; + if(lt->key) { + if(!(ob->shapeflag & OB_SHAPE_LOCK)) { + ob->recalc |= OB_RECALC_DATA; + ob->shapeflag &= ~OB_SHAPE_TEMPLOCK; + } + } + break; + case OB_MBALL: + if(ob->transflag & OB_DUPLI) ob->recalc |= OB_RECALC_DATA; + break; + } + } +} + +/* flag all objects that need recalc, for changes in time for example */ +void DAG_scene_update_flags(Scene *scene, unsigned int lay) +{ + Base *base; + Object *ob; + Group *group; + GroupObject *go; + Scene *sce; + + /* set ob flags where animated systems are */ + for(SETLOOPER(scene, base)) { + ob= base->object; + + /* now if DagNode were part of base, the node->lay could be checked... */ + /* we do all now, since the scene_flush checks layers and clears recalc flags even */ + dag_object_time_update_flags(ob); + + /* handled in next loop */ + if(ob->dup_group) + ob->dup_group->id.flag |= LIB_DOIT; + } + + /* we do groups each once */ + for(group= G.main->group.first; group; group= group->id.next) { + if(group->id.flag & LIB_DOIT) { + for(go= group->gobject.first; go; go= go->next) { + dag_object_time_update_flags(go->ob); + } + } + } + + for(sce= scene; sce; sce= sce->set) + DAG_scene_flush_update(sce, lay); + + /* test: set time flag, to disable baked systems to update */ + for(SETLOOPER(scene, base)) { + ob= base->object; + if(ob->recalc) + ob->recalc |= OB_RECALC_TIME; + } + + /* hrmf... an exception to look at once, for invisible camera object we do it over */ + if(scene->camera) + dag_object_time_update_flags(scene->camera); + + /* and store the info in groupobject */ + for(group= G.main->group.first; group; group= group->id.next) { + if(group->id.flag & LIB_DOIT) { + for(go= group->gobject.first; go; go= go->next) { + go->recalc= go->ob->recalc; + // printf("ob %s recalc %d\n", go->ob->id.name, go->recalc); + } + group->id.flag &= ~LIB_DOIT; + } + } + +} + +/* for depgraph updating, all layers visible in a screen */ +/* this is a copy from editscreen.c... I need to think over a more proper solution for this */ +/* probably the DAG_object_flush_update() should give layer too? */ +/* or some kind of dag context... (DAG_set_layer) */ +static unsigned int dag_screen_view3d_layers(void) +{ + ScrArea *sa; + int layer= 0; + + for(sa= G.curscreen->areabase.first; sa; sa= sa->next) { + if(sa->spacetype==SPACE_VIEW3D) + layer |= ((View3D *)sa->spacedata.first)->lay; + } + return layer; +} + + +/* flag this object and all its relations to recalc */ +/* if you need to do more objects, tag object yourself and + use DAG_scene_flush_update() in end */ +void DAG_object_flush_update(Scene *sce, Object *ob, short flag) +{ + + if(ob==NULL || sce->theDag==NULL) return; + ob->recalc |= flag; + + /* all users of this ob->data should be checked */ + /* BUT! displists for curves are still only on cu */ + if(flag & OB_RECALC_DATA) { + if(ob->type!=OB_CURVE && ob->type!=OB_SURF) { + ID *id= ob->data; + if(id && id->us>1) { + /* except when there's a key and shapes are locked */ + if(ob_get_key(ob) && (ob->shapeflag & (OB_SHAPE_LOCK|OB_SHAPE_TEMPLOCK))); + else { + Object *obt; + for (obt=G.main->object.first; obt; obt= obt->id.next) { + if (obt->data==ob->data) { + obt->recalc |= OB_RECALC_DATA; + } + } + } + } + } + } + + if(G.curscreen) + DAG_scene_flush_update(sce, dag_screen_view3d_layers()); + else + DAG_scene_flush_update(sce, sce->lay); +} + +/* recursively descends tree, each node only checked once */ +/* node is checked to be of type object */ +static int parent_check_node(DagNode *node, int curtime) +{ + DagAdjList *itA; + + node->lasttime= curtime; + + if(node->color==DAG_GRAY) + return DAG_GRAY; + + for(itA = node->child; itA; itA= itA->next) { + if(itA->node->type==ID_OB) { + + if(itA->node->color==DAG_GRAY) + return DAG_GRAY; + + /* descend if not done */ + if(itA->node->lasttime!=curtime) { + itA->node->color= parent_check_node(itA->node, curtime); + + if(itA->node->color==DAG_GRAY) + return DAG_GRAY; + } + } + } + + return DAG_WHITE; +} + +/* all nodes that influence this object get tagged, for calculating the exact + position of this object at a given timeframe */ +void DAG_object_update_flags(Scene *sce, Object *ob, unsigned int lay) +{ + DagNode *node; + DagAdjList *itA; + + /* tag nodes unchecked */ + for(node = sce->theDag->DagNode.first; node; node= node->next) + node->color = DAG_WHITE; + + node= dag_find_node(sce->theDag, ob); + + /* object not in scene? then handle group exception. needs to be dagged once too */ + if(node==NULL) { + Group *group= find_group(ob); + if(group) { + GroupObject *go; + /* primitive; tag all... this call helps building groups for particles */ + for(go= group->gobject.first; go; go= go->next) + go->ob->recalc= OB_RECALC; + } + } + else { + + node->color = DAG_GRAY; + + sce->theDag->time++; + node= sce->theDag->DagNode.first; + for(itA = node->child; itA; itA= itA->next) { + if(itA->node->type==ID_OB && itA->node->lasttime!=sce->theDag->time) + itA->node->color= parent_check_node(itA->node, sce->theDag->time); + } + + /* set recalcs and flushes */ + DAG_scene_update_flags(sce, lay); + + /* now we clear recalcs, unless color is set */ + for(node = sce->theDag->DagNode.first; node; node= node->next) { + if(node->type==ID_OB && node->color==DAG_WHITE) { + Object *ob= node->ob; + ob->recalc= 0; + } + } + } +} + +/* ******************* DAG FOR ARMATURE POSE ***************** */ + +static int node_recurs_level(DagNode *node, int level) +{ + DagAdjList *itA; + + node->color= DAG_BLACK; /* done */ + level++; + + for(itA= node->parent; itA; itA= itA->next) { + if(itA->node->color==DAG_WHITE) + itA->node->ancestor_count= node_recurs_level(itA->node, level); + } + + return level; +} + +static void pose_check_cycle(DagForest *dag) +{ + DagNode *node; + DagAdjList *itA; + + /* tag nodes unchecked */ + for(node = dag->DagNode.first; node; node= node->next) + node->color= DAG_WHITE; + + for(node = dag->DagNode.first; node; node= node->next) { + if(node->color==DAG_WHITE) { + node->ancestor_count= node_recurs_level(node, 0); + } + } + + /* check relations, and print errors */ + for(node = dag->DagNode.first; node; node= node->next) { + for(itA= node->parent; itA; itA= itA->next) { + if(itA->node->ancestor_count > node->ancestor_count) { + bPoseChannel *pchan= (bPoseChannel *)node->ob; + bPoseChannel *parchan= (bPoseChannel *)itA->node->ob; + + if(pchan && parchan) + if(pchan->parent!=parchan) + printf("Cycle in %s to %s\n", pchan->name, parchan->name); + } + } + } +} + +/* we assume its an armature with pose */ +void DAG_pose_sort(Object *ob) +{ + bPose *pose= ob->pose; + bPoseChannel *pchan; + bConstraint *con; + DagNode *node; + DagNode *node2, *node3; + DagNode *rootnode; + DagForest *dag; + DagNodeQueue *nqueue; + DagAdjList *itA; + ListBase tempbase; + int skip = 0; + + dag = dag_init(); + ugly_hack_sorry= 0; // no ID structs + + rootnode = dag_add_node(dag, NULL); // node->ob becomes NULL + + /* we add the hierarchy and the constraints */ + for(pchan = pose->chanbase.first; pchan; pchan= pchan->next) { + int addtoroot = 1; + + node = dag_get_node(dag, pchan); + + if(pchan->parent) { + node2 = dag_get_node(dag, pchan->parent); + dag_add_relation(dag, node2, node, 0); + dag_add_parent_relation(dag, node2, node, 0); + addtoroot = 0; + } + for (con = pchan->constraints.first; con; con=con->next) { + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + ListBase targets = {NULL, NULL}; + bConstraintTarget *ct; + + if (cti && cti->get_constraint_targets) { + cti->get_constraint_targets(con, &targets); + + for (ct= targets.first; ct; ct= ct->next) { + if (ct->tar==ob && ct->subtarget[0]) { + bPoseChannel *target= get_pose_channel(ob->pose, ct->subtarget); + if (target) { + node2= dag_get_node(dag, target); + dag_add_relation(dag, node2, node, 0); + dag_add_parent_relation(dag, node2, node, 0); + + if (con->type==CONSTRAINT_TYPE_KINEMATIC) { + bKinematicConstraint *data = (bKinematicConstraint *)con->data; + bPoseChannel *parchan; + int segcount= 0; + + /* exclude tip from chain? */ + if(!(data->flag & CONSTRAINT_IK_TIP)) + parchan= pchan->parent; + else + parchan= pchan; + + /* Walk to the chain's root */ + while (parchan) { + node3= dag_get_node(dag, parchan); + dag_add_relation(dag, node2, node3, 0); + dag_add_parent_relation(dag, node2, node3, 0); + + segcount++; + if (segcount==data->rootbone || segcount>255) break; // 255 is weak + parchan= parchan->parent; + } + } + } + } + } + + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(con, &targets, 1); + } + } + if (addtoroot == 1 ) { + dag_add_relation(dag, rootnode, node, 0); + dag_add_parent_relation(dag, rootnode, node, 0); + } + } + + pose_check_cycle(dag); + + /* now we try to sort... */ + tempbase.first= tempbase.last= NULL; + + nqueue = queue_create(DAGQUEUEALLOC); + + /* tag nodes unchecked */ + for(node = dag->DagNode.first; node; node= node->next) + node->color = DAG_WHITE; + + node = dag->DagNode.first; + + node->color = DAG_GRAY; + push_stack(nqueue, node); + + while(nqueue->count) { + + skip = 0; + node = get_top_node_queue(nqueue); + + itA = node->child; + while(itA != NULL) { + if((itA->node->color == DAG_WHITE) ) { + itA->node->color = DAG_GRAY; + push_stack(nqueue,itA->node); + skip = 1; + break; + } + itA = itA->next; + } + + if (!skip) { + if (node) { + node = pop_queue(nqueue); + if (node->ob == NULL) // we are done + break ; + node->color = DAG_BLACK; + + /* put node in new list */ + BLI_remlink(&pose->chanbase, node->ob); + BLI_addhead(&tempbase, node->ob); + } + } + } + + // temporal correction for circular dependancies + while(pose->chanbase.first) { + pchan= pose->chanbase.first; + BLI_remlink(&pose->chanbase, pchan); + BLI_addhead(&tempbase, pchan); + + printf("cyclic %s\n", pchan->name); + } + + pose->chanbase = tempbase; + queue_delete(nqueue); + +// printf("\nordered\n"); +// for(pchan = pose->chanbase.first; pchan; pchan= pchan->next) { +// printf(" %s\n", pchan->name); +// } + + free_forest( dag ); + MEM_freeN( dag ); + + ugly_hack_sorry= 1; +} + + + diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c new file mode 100644 index 00000000000..30a4c8c3433 --- /dev/null +++ b/source/blender/blenkernel/intern/displist.c @@ -0,0 +1,1589 @@ +/* displist.c + * + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "IMB_imbuf_types.h" + +#include "DNA_texture_types.h" +#include "DNA_meta_types.h" +#include "DNA_curve_types.h" +#include "DNA_effect_types.h" +#include "DNA_listBase.h" +#include "DNA_lamp_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_scene_types.h" +#include "DNA_image_types.h" +#include "DNA_material_types.h" +#include "DNA_view3d_types.h" +#include "DNA_lattice_types.h" +#include "DNA_key_types.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_editVert.h" +#include "BLI_edgehash.h" + +#include "BKE_bad_level_calls.h" +#include "BKE_utildefines.h" +#include "BKE_global.h" +#include "BKE_displist.h" +#include "BKE_deform.h" +#include "BKE_DerivedMesh.h" +#include "BKE_object.h" +#include "BKE_world.h" +#include "BKE_mesh.h" +#include "BKE_effect.h" +#include "BKE_mball.h" +#include "BKE_material.h" +#include "BKE_curve.h" +#include "BKE_key.h" +#include "BKE_anim.h" +#include "BKE_screen.h" +#include "BKE_texture.h" +#include "BKE_library.h" +#include "BKE_font.h" +#include "BKE_lattice.h" +#include "BKE_scene.h" +#include "BKE_subsurf.h" +#include "BKE_modifier.h" +#include "BKE_customdata.h" + +#include "RE_pipeline.h" +#include "RE_shader_ext.h" + + +static void boundbox_displist(Object *ob); + +void free_disp_elem(DispList *dl) +{ + if(dl) { + if(dl->verts) MEM_freeN(dl->verts); + if(dl->nors) MEM_freeN(dl->nors); + if(dl->index) MEM_freeN(dl->index); + if(dl->col1) MEM_freeN(dl->col1); + if(dl->col2) MEM_freeN(dl->col2); + if(dl->bevelSplitFlag) MEM_freeN(dl->bevelSplitFlag); + MEM_freeN(dl); + } +} + +void freedisplist(ListBase *lb) +{ + DispList *dl; + + dl= lb->first; + while(dl) { + BLI_remlink(lb, dl); + free_disp_elem(dl); + dl= lb->first; + } +} + +DispList *find_displist_create(ListBase *lb, int type) +{ + DispList *dl; + + dl= lb->first; + while(dl) { + if(dl->type==type) return dl; + dl= dl->next; + } + + dl= MEM_callocN(sizeof(DispList), "find_disp"); + dl->type= type; + BLI_addtail(lb, dl); + + return dl; +} + +DispList *find_displist(ListBase *lb, int type) +{ + DispList *dl; + + dl= lb->first; + while(dl) { + if(dl->type==type) return dl; + dl= dl->next; + } + + return 0; +} + +int displist_has_faces(ListBase *lb) +{ + DispList *dl; + + dl= lb->first; + while(dl) { + if ELEM3(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF) + return 1; + dl= dl->next; + } + return 0; +} + +void copy_displist(ListBase *lbn, ListBase *lb) +{ + DispList *dln, *dl; + + lbn->first= lbn->last= 0; + + dl= lb->first; + while(dl) { + + dln= MEM_dupallocN(dl); + BLI_addtail(lbn, dln); + dln->verts= MEM_dupallocN(dl->verts); + dln->nors= MEM_dupallocN(dl->nors); + dln->index= MEM_dupallocN(dl->index); + dln->col1= MEM_dupallocN(dl->col1); + dln->col2= MEM_dupallocN(dl->col2); + + dl= dl->next; + } +} + +void addnormalsDispList(Object *ob, ListBase *lb) +{ + DispList *dl = NULL; + float *vdata, *ndata, nor[3]; + float *v1, *v2, *v3, *v4; + float *n1, *n2, *n3, *n4; + int a, b, p1, p2, p3, p4; + + + dl= lb->first; + + while(dl) { + if(dl->type==DL_INDEX3) { + if(dl->nors==NULL) { + dl->nors= MEM_callocN(sizeof(float)*3, "dlnors"); + if(dl->verts[2]<0.0) dl->nors[2]= -1.0; + else dl->nors[2]= 1.0; + } + } + else if(dl->type==DL_SURF) { + if(dl->nors==NULL) { + dl->nors= MEM_callocN(sizeof(float)*3*dl->nr*dl->parts, "dlnors"); + + vdata= dl->verts; + ndata= dl->nors; + + for(a=0; aparts; a++) { + + DL_SURFINDEX(dl->flag & DL_CYCL_U, dl->flag & DL_CYCL_V, dl->nr, dl->parts); + + v1= vdata+ 3*p1; + n1= ndata+ 3*p1; + v2= vdata+ 3*p2; + n2= ndata+ 3*p2; + v3= vdata+ 3*p3; + n3= ndata+ 3*p3; + v4= vdata+ 3*p4; + n4= ndata+ 3*p4; + + for(; bnr; b++) { + + CalcNormFloat4(v1, v3, v4, v2, nor); + + VecAddf(n1, n1, nor); + VecAddf(n2, n2, nor); + VecAddf(n3, n3, nor); + VecAddf(n4, n4, nor); + + v2= v1; v1+= 3; + v4= v3; v3+= 3; + n2= n1; n1+= 3; + n4= n3; n3+= 3; + } + } + a= dl->parts*dl->nr; + v1= ndata; + while(a--) { + Normalize(v1); + v1+= 3; + } + } + } + dl= dl->next; + } +} + +void count_displist(ListBase *lb, int *totvert, int *totface) +{ + DispList *dl; + + dl= lb->first; + while(dl) { + + switch(dl->type) { + case DL_SURF: + *totvert+= dl->nr*dl->parts; + *totface+= (dl->nr-1)*(dl->parts-1); + break; + case DL_INDEX3: + case DL_INDEX4: + *totvert+= dl->nr; + *totface+= dl->parts; + break; + case DL_POLY: + case DL_SEGM: + *totvert+= dl->nr*dl->parts; + } + + dl= dl->next; + } +} + + +/* ***************************** shade displist. note colors now are in rgb(a) order ******************** */ + +/* create default shade input... save cpu cycles with ugly global */ +/* XXXX bad code warning: local ShadeInput initialize... */ +static ShadeInput shi; +static void init_fastshade_shadeinput(void) +{ + memset(&shi, 0, sizeof(ShadeInput)); + shi.lay= G.scene->lay; + shi.view[2]= -1.0f; + shi.passflag= SCE_PASS_COMBINED; + shi.combinedflag= -1; +} + +static Render *fastshade_get_render(void) +{ + Render *re= RE_GetRender("_Shade View_"); + if(re==NULL) { + re= RE_NewRender("_Shade View_"); + + RE_Database_Baking(re, G.scene, 0); /* 0= no faces */ + } + return re; +} + +/* called on file reading */ +void fastshade_free_render(void) +{ + Render *re= RE_GetRender("_Shade View_"); + + if(re) { + RE_Database_Free(re); + RE_FreeRender(re); + } +} + +static int fastshade_customdata_layer_num(int n, int active) +{ + /* make the active layer the first */ + if (n == active) return 0; + else if (n < active) return n+1; + else return n; +} + +static void fastshade_customdata(CustomData *fdata, int a, int j, Material *ma) +{ + CustomDataLayer *layer; + MTFace *mtface; + int index, n, needuv= ma->texco & TEXCO_UV; + char *vertcol; + + shi.totuv= 0; + shi.totcol= 0; + + for(index=0; indextotlayer; index++) { + layer= &fdata->layers[index]; + + if(needuv && layer->type == CD_MTFACE && shi.totuv < MAX_MTFACE) { + n= fastshade_customdata_layer_num(shi.totuv, layer->active_rnd); + mtface= &((MTFace*)layer->data)[a]; + + shi.uv[shi.totuv].uv[0]= 2.0f*mtface->uv[j][0]-1.0f; + shi.uv[shi.totuv].uv[1]= 2.0f*mtface->uv[j][1]-1.0f; + shi.uv[shi.totuv].uv[2]= 1.0f; + + shi.uv[shi.totuv].name= layer->name; + shi.totuv++; + } + else if(layer->type == CD_MCOL && shi.totcol < MAX_MCOL) { + n= fastshade_customdata_layer_num(shi.totcol, layer->active_rnd); + vertcol= (char*)&((MCol*)layer->data)[a*4 + j]; + + shi.col[shi.totcol].col[0]= ((float)vertcol[3])/255.0f; + shi.col[shi.totcol].col[1]= ((float)vertcol[2])/255.0f; + shi.col[shi.totcol].col[2]= ((float)vertcol[1])/255.0f; + + shi.col[shi.totcol].name= layer->name; + shi.totcol++; + } + } + + if(needuv && shi.totuv == 0) + VECCOPY(shi.uv[0].uv, shi.lo); + + if(shi.totcol) + VECCOPY(shi.vcol, shi.col[0].col); +} + +static void fastshade(float *co, float *nor, float *orco, Material *ma, char *col1, char *col2) +{ + ShadeResult shr; + int a; + + VECCOPY(shi.co, co); + shi.vn[0]= -nor[0]; + shi.vn[1]= -nor[1]; + shi.vn[2]= -nor[2]; + VECCOPY(shi.vno, shi.vn); + VECCOPY(shi.facenor, shi.vn); + + if(ma->texco) { + VECCOPY(shi.lo, orco); + + if(ma->texco & TEXCO_GLOB) { + VECCOPY(shi.gl, shi.lo); + } + if(ma->texco & TEXCO_WINDOW) { + VECCOPY(shi.winco, shi.lo); + } + if(ma->texco & TEXCO_STICKY) { + VECCOPY(shi.sticky, shi.lo); + } + if(ma->texco & TEXCO_OBJECT) { + VECCOPY(shi.co, shi.lo); + } + if(ma->texco & TEXCO_NORM) { + VECCOPY(shi.orn, shi.vn); + } + if(ma->texco & TEXCO_REFL) { + float inp= 2.0*(shi.vn[2]); + shi.ref[0]= (inp*shi.vn[0]); + shi.ref[1]= (inp*shi.vn[1]); + shi.ref[2]= (-1.0+inp*shi.vn[2]); + } + } + + shi.mat= ma; /* set each time... node shaders change it */ + RE_shade_external(NULL, &shi, &shr); + + a= 256.0f*(shr.combined[0]); + col1[0]= CLAMPIS(a, 0, 255); + a= 256.0f*(shr.combined[1]); + col1[1]= CLAMPIS(a, 0, 255); + a= 256.0f*(shr.combined[2]); + col1[2]= CLAMPIS(a, 0, 255); + + if(col2) { + shi.vn[0]= -shi.vn[0]; + shi.vn[1]= -shi.vn[1]; + shi.vn[2]= -shi.vn[2]; + + shi.mat= ma; /* set each time... node shaders change it */ + RE_shade_external(NULL, &shi, &shr); + + a= 256.0f*(shr.combined[0]); + col2[0]= CLAMPIS(a, 0, 255); + a= 256.0f*(shr.combined[1]); + col2[1]= CLAMPIS(a, 0, 255); + a= 256.0f*(shr.combined[2]); + col2[2]= CLAMPIS(a, 0, 255); + } +} + +static void init_fastshade_for_ob(Render *re, Object *ob, int *need_orco_r, float mat[4][4], float imat[3][3]) +{ + float tmat[4][4]; + float amb[3]= {0.0f, 0.0f, 0.0f}; + int a; + + /* initialize globals in render */ + RE_shade_external(re, NULL, NULL); + + /* initialize global here */ + init_fastshade_shadeinput(); + + RE_DataBase_GetView(re, tmat); + Mat4MulMat4(mat, ob->obmat, tmat); + + Mat4Invert(tmat, mat); + Mat3CpyMat4(imat, tmat); + if(ob->transflag & OB_NEG_SCALE) Mat3MulFloat((float *)imat, -1.0); + + if (need_orco_r) *need_orco_r= 0; + for(a=0; atotcol; a++) { + Material *ma= give_current_material(ob, a+1); + if(ma) { + init_render_material(ma, 0, amb); + + if(ma->texco & TEXCO_ORCO) { + if (need_orco_r) *need_orco_r= 1; + } + } + } +} + +static void end_fastshade_for_ob(Object *ob) +{ + int a; + + for(a=0; atotcol; a++) { + Material *ma= give_current_material(ob, a+1); + if(ma) + end_render_material(ma); + } +} + + +static void mesh_create_shadedColors(Render *re, Object *ob, int onlyForMesh, unsigned int **col1_r, unsigned int **col2_r) +{ + Mesh *me= ob->data; + DerivedMesh *dm; + MVert *mvert; + MFace *mface; + unsigned int *col1, *col2; + float *orco, *vnors, *nors, imat[3][3], mat[4][4], vec[3]; + int a, i, need_orco, totface, totvert; + CustomDataMask dataMask = CD_MASK_BAREMESH | CD_MASK_MCOL + | CD_MASK_MTFACE | CD_MASK_NORMAL; + + init_fastshade_for_ob(re, ob, &need_orco, mat, imat); + + orco = (need_orco)? mesh_create_orco(ob): NULL; + + if (onlyForMesh) + dm = mesh_get_derived_deform(ob, dataMask); + else + dm = mesh_get_derived_final(ob, dataMask); + + mvert = dm->getVertArray(dm); + mface = dm->getFaceArray(dm); + nors = dm->getFaceDataArray(dm, CD_NORMAL); + totvert = dm->getNumVerts(dm); + totface = dm->getNumFaces(dm); + + if (onlyForMesh) { + col1 = *col1_r; + col2 = NULL; + } else { + *col1_r = col1 = MEM_mallocN(sizeof(*col1)*totface*4, "col1"); + + if (col2_r && (me->flag & ME_TWOSIDED)) + col2 = MEM_mallocN(sizeof(*col2)*totface*4, "col2"); + else + col2 = NULL; + + if (col2_r) *col2_r = col2; + } + + /* vertexnormals */ + vnors= MEM_mallocN(totvert*3*sizeof(float), "vnors disp"); + for (a=0; ano[0]; + float yn= mv->no[1]; + float zn= mv->no[2]; + + /* transpose ! */ + vn[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn; + vn[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn; + vn[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn; + Normalize(vn); + } + + for (i=0; imat_nr+1); + int j, vidx[4], nverts= mf->v4?4:3; + unsigned char *col1base= (unsigned char*) &col1[i*4]; + unsigned char *col2base= (unsigned char*) (col2?&col2[i*4]:NULL); + float nor[3], n1[3]; + + if(ma==NULL) ma= &defmaterial; + + vidx[0]= mf->v1; + vidx[1]= mf->v2; + vidx[2]= mf->v3; + vidx[3]= mf->v4; + + if (nors) { + VECCOPY(nor, &nors[i*3]); + } else { + if (mf->v4) + CalcNormFloat4(mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co, mvert[mf->v4].co, nor); + else + CalcNormFloat(mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co, nor); + } + + n1[0]= imat[0][0]*nor[0]+imat[0][1]*nor[1]+imat[0][2]*nor[2]; + n1[1]= imat[1][0]*nor[0]+imat[1][1]*nor[1]+imat[1][2]*nor[2]; + n1[2]= imat[2][0]*nor[0]+imat[2][1]*nor[1]+imat[2][2]*nor[2]; + Normalize(n1); + + for (j=0; jflag & ME_SMOOTH)?&vnors[3*vidx[j]]:n1; + + VECCOPY(vec, mv->co); + Mat4MulVecfl(mat, vec); + vec[0]+= 0.001*vn[0]; + vec[1]+= 0.001*vn[1]; + vec[2]+= 0.001*vn[2]; + + fastshade_customdata(&dm->faceData, i, j, ma); + fastshade(vec, vn, orco?&orco[vidx[j]*3]:mv->co, ma, col1, col2); + } + } + MEM_freeN(vnors); + + if (orco) + MEM_freeN(orco); + + dm->release(dm); + + end_fastshade_for_ob(ob); +} + +void shadeMeshMCol(Object *ob, Mesh *me) +{ + int a; + char *cp; + unsigned int *mcol= (unsigned int*)me->mcol; + + Render *re= fastshade_get_render(); + mesh_create_shadedColors(re, ob, 1, &mcol, NULL); + me->mcol= (MCol*)mcol; + + /* swap bytes */ + for(cp= (char *)me->mcol, a= 4*me->totface; a>0; a--, cp+=4) { + SWAP(char, cp[0], cp[3]); + SWAP(char, cp[1], cp[2]); + } +} + +/* has base pointer, to check for layer */ +/* called from drawobject.c */ +void shadeDispList(Base *base) +{ + Object *ob= base->object; + DispList *dl, *dlob; + Material *ma = NULL; + Curve *cu; + Render *re; + float imat[3][3], mat[4][4], vec[3]; + float *fp, *nor, n1[3]; + unsigned int *col1; + int a, need_orco; + + re= fastshade_get_render(); + + dl = find_displist(&ob->disp, DL_VERTCOL); + if (dl) { + BLI_remlink(&ob->disp, dl); + free_disp_elem(dl); + } + + if(ob->type==OB_MESH) { + dl= MEM_callocN(sizeof(DispList), "displistshade"); + dl->type= DL_VERTCOL; + + mesh_create_shadedColors(re, ob, 0, &dl->col1, &dl->col2); + + /* add dl to ob->disp after mesh_create_shadedColors, because it + might indirectly free ob->disp */ + BLI_addtail(&ob->disp, dl); + } + else { + + init_fastshade_for_ob(re, ob, &need_orco, mat, imat); + + if ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT) { + + /* now we need the normals */ + cu= ob->data; + dl= cu->disp.first; + + while(dl) { + dlob= MEM_callocN(sizeof(DispList), "displistshade"); + BLI_addtail(&ob->disp, dlob); + dlob->type= DL_VERTCOL; + dlob->parts= dl->parts; + dlob->nr= dl->nr; + + if(dl->type==DL_INDEX3) { + col1= dlob->col1= MEM_mallocN(sizeof(int)*dl->nr, "col1"); + } + else { + col1= dlob->col1= MEM_mallocN(sizeof(int)*dl->parts*dl->nr, "col1"); + } + + + ma= give_current_material(ob, dl->col+1); + if(ma==NULL) ma= &defmaterial; + + if(dl->type==DL_INDEX3) { + if(dl->nors) { + /* there's just one normal */ + n1[0]= imat[0][0]*dl->nors[0]+imat[0][1]*dl->nors[1]+imat[0][2]*dl->nors[2]; + n1[1]= imat[1][0]*dl->nors[0]+imat[1][1]*dl->nors[1]+imat[1][2]*dl->nors[2]; + n1[2]= imat[2][0]*dl->nors[0]+imat[2][1]*dl->nors[1]+imat[2][2]*dl->nors[2]; + Normalize(n1); + + fp= dl->verts; + + a= dl->nr; + while(a--) { + VECCOPY(vec, fp); + Mat4MulVecfl(mat, vec); + + fastshade(vec, n1, fp, ma, (char *)col1, NULL); + + fp+= 3; col1++; + } + } + } + else if(dl->type==DL_SURF) { + if(dl->nors) { + a= dl->nr*dl->parts; + fp= dl->verts; + nor= dl->nors; + + while(a--) { + VECCOPY(vec, fp); + Mat4MulVecfl(mat, vec); + + n1[0]= imat[0][0]*nor[0]+imat[0][1]*nor[1]+imat[0][2]*nor[2]; + n1[1]= imat[1][0]*nor[0]+imat[1][1]*nor[1]+imat[1][2]*nor[2]; + n1[2]= imat[2][0]*nor[0]+imat[2][1]*nor[1]+imat[2][2]*nor[2]; + Normalize(n1); + + fastshade(vec, n1, fp, ma, (char *)col1, NULL); + + fp+= 3; nor+= 3; col1++; + } + } + } + dl= dl->next; + } + } + else if(ob->type==OB_MBALL) { + /* there are normals already */ + dl= ob->disp.first; + + while(dl) { + + if(dl->type==DL_INDEX4) { + if(dl->nors) { + + if(dl->col1) MEM_freeN(dl->col1); + col1= dl->col1= MEM_mallocN(sizeof(int)*dl->nr, "col1"); + + ma= give_current_material(ob, dl->col+1); + if(ma==NULL) ma= &defmaterial; + + fp= dl->verts; + nor= dl->nors; + + a= dl->nr; + while(a--) { + VECCOPY(vec, fp); + Mat4MulVecfl(mat, vec); + + /* transpose ! */ + n1[0]= imat[0][0]*nor[0]+imat[0][1]*nor[1]+imat[0][2]*nor[2]; + n1[1]= imat[1][0]*nor[0]+imat[1][1]*nor[1]+imat[1][2]*nor[2]; + n1[2]= imat[2][0]*nor[0]+imat[2][1]*nor[1]+imat[2][2]*nor[2]; + Normalize(n1); + + fastshade(vec, n1, fp, ma, (char *)col1, NULL); + + fp+= 3; col1++; nor+= 3; + } + } + } + dl= dl->next; + } + } + + end_fastshade_for_ob(ob); + } +} + +/* frees render and shade part of displists */ +/* note: dont do a shade again, until a redraw happens */ +void reshadeall_displist(void) +{ + Base *base; + Object *ob; + + fastshade_free_render(); + + for(base= G.scene->base.first; base; base= base->next) { + ob= base->object; + freedisplist(&ob->disp); + if(base->lay & G.scene->lay) { + /* Metaballs have standard displist at the Object */ + if(ob->type==OB_MBALL) shadeDispList(base); + } + } +} + +/* ****************** make displists ********************* */ + +static void curve_to_displist(Curve *cu, ListBase *nubase, ListBase *dispbase) +{ + Nurb *nu; + DispList *dl; + BezTriple *bezt, *prevbezt; + BPoint *bp; + float *data, *v1, *v2; + int a, len, resolu; + + nu= nubase->first; + while(nu) { + if(nu->hide==0) { + + if(G.rendering && cu->resolu_ren!=0) + resolu= cu->resolu_ren; + else + resolu= nu->resolu; + + if(nu->pntsu<2); + else if((nu->type & 7)==CU_BEZIER) { + + /* count */ + len= 0; + a= nu->pntsu-1; + if(nu->flagu & CU_CYCLIC) a++; + + prevbezt= nu->bezt; + bezt= prevbezt+1; + while(a--) { + if(a==0 && (nu->flagu & CU_CYCLIC)) bezt= nu->bezt; + + if(prevbezt->h2==HD_VECT && bezt->h1==HD_VECT) len++; + else len+= resolu; + + if(a==0 && (nu->flagu & CU_CYCLIC)==0) len++; + + prevbezt= bezt; + bezt++; + } + + dl= MEM_callocN(sizeof(DispList), "makeDispListbez"); + /* len+1 because of 'forward_diff_bezier' function */ + dl->verts= MEM_callocN( (len+1)*3*sizeof(float), "dlverts"); + BLI_addtail(dispbase, dl); + dl->parts= 1; + dl->nr= len; + dl->col= nu->mat_nr; + dl->charidx= nu->charidx; + + data= dl->verts; + + if(nu->flagu & 1) { + dl->type= DL_POLY; + a= nu->pntsu; + } + else { + dl->type= DL_SEGM; + a= nu->pntsu-1; + } + + prevbezt= nu->bezt; + bezt= prevbezt+1; + + while(a--) { + if(a==0 && dl->type== DL_POLY) bezt= nu->bezt; + + if(prevbezt->h2==HD_VECT && bezt->h1==HD_VECT) { + VECCOPY(data, prevbezt->vec[1]); + data+= 3; + } + else { + v1= prevbezt->vec[1]; + v2= bezt->vec[0]; + forward_diff_bezier(v1[0], v1[3], v2[0], v2[3], data, resolu, 3); + forward_diff_bezier(v1[1], v1[4], v2[1], v2[4], data+1, resolu, 3); + forward_diff_bezier(v1[2], v1[5], v2[2], v2[5], data+2, resolu, 3); + data+= 3*resolu; + } + + if(a==0 && dl->type==DL_SEGM) { + VECCOPY(data, bezt->vec[1]); + } + + prevbezt= bezt; + bezt++; + } + } + else if((nu->type & 7)==CU_NURBS) { + len= nu->pntsu*resolu; + dl= MEM_callocN(sizeof(DispList), "makeDispListsurf"); + dl->verts= MEM_callocN(len*3*sizeof(float), "dlverts"); + BLI_addtail(dispbase, dl); + dl->parts= 1; + dl->nr= len; + dl->col= nu->mat_nr; + dl->charidx = nu->charidx; + + data= dl->verts; + if(nu->flagu & 1) dl->type= DL_POLY; + else dl->type= DL_SEGM; + makeNurbcurve(nu, data, resolu, 3); + } + else if((nu->type & 7)==CU_POLY) { + len= nu->pntsu; + dl= MEM_callocN(sizeof(DispList), "makeDispListpoly"); + dl->verts= MEM_callocN(len*3*sizeof(float), "dlverts"); + BLI_addtail(dispbase, dl); + dl->parts= 1; + dl->nr= len; + dl->col= nu->mat_nr; + dl->charidx = nu->charidx; + + data= dl->verts; + if(nu->flagu & 1) dl->type= DL_POLY; + else dl->type= DL_SEGM; + + a= len; + bp= nu->bp; + while(a--) { + VECCOPY(data, bp->vec); + bp++; + data+= 3; + } + } + } + nu= nu->next; + } +} + + +void filldisplist(ListBase *dispbase, ListBase *to) +{ + EditVert *eve, *v1, *vlast; + EditFace *efa; + DispList *dlnew=0, *dl; + float *f1; + int colnr=0, charidx=0, cont=1, tot, a, *index; + long totvert; + + if(dispbase==0) return; + if(dispbase->first==0) return; + + while(cont) { + cont= 0; + totvert=0; + + dl= dispbase->first; + while(dl) { + + if(dl->type==DL_POLY) { + if(charidxcharidx) cont= 1; + else if(charidx==dl->charidx) { + + colnr= dl->col; + charidx= dl->charidx; + + /* make editverts and edges */ + f1= dl->verts; + a= dl->nr; + eve= v1= 0; + + while(a--) { + vlast= eve; + + eve= BLI_addfillvert(f1); + totvert++; + + if(vlast==0) v1= eve; + else { + BLI_addfilledge(vlast, eve); + } + f1+=3; + } + + if(eve!=0 && v1!=0) { + BLI_addfilledge(eve, v1); + } + } + } + dl= dl->next; + } + + if(totvert && BLI_edgefill(0, (G.obedit && G.obedit->actcol)?(G.obedit->actcol-1):0)) { + + /* count faces */ + tot= 0; + efa= fillfacebase.first; + while(efa) { + tot++; + efa= efa->next; + } + + if(tot) { + dlnew= MEM_callocN(sizeof(DispList), "filldisplist"); + dlnew->type= DL_INDEX3; + dlnew->col= colnr; + dlnew->nr= totvert; + dlnew->parts= tot; + + dlnew->index= MEM_mallocN(tot*3*sizeof(int), "dlindex"); + dlnew->verts= MEM_mallocN(totvert*3*sizeof(float), "dlverts"); + + /* vert data */ + f1= dlnew->verts; + totvert= 0; + eve= fillvertbase.first; + while(eve) { + VECCOPY(f1, eve->co); + f1+= 3; + + /* index number */ + eve->tmp.l = totvert; + totvert++; + + eve= eve->next; + } + + /* index data */ + efa= fillfacebase.first; + index= dlnew->index; + while(efa) { + index[0]= (long)efa->v1->tmp.l; + index[1]= (long)efa->v2->tmp.l; + index[2]= (long)efa->v3->tmp.l; + + index+= 3; + efa= efa->next; + } + } + + BLI_addhead(to, dlnew); + + } + BLI_end_edgefill(); + + charidx++; + } + + /* do not free polys, needed for wireframe display */ + +} + +static void bevels_to_filledpoly(Curve *cu, ListBase *dispbase) +{ + ListBase front, back; + DispList *dl, *dlnew; + float *fp, *fp1; + int a, dpoly; + + front.first= front.last= back.first= back.last= 0; + + dl= dispbase->first; + while(dl) { + if(dl->type==DL_SURF) { + if( (dl->flag & DL_CYCL_V) && (dl->flag & DL_CYCL_U)==0 ) { + if( (cu->flag & CU_BACK) && (dl->flag & DL_BACK_CURVE) ) { + dlnew= MEM_callocN(sizeof(DispList), "filldisp"); + BLI_addtail(&front, dlnew); + dlnew->verts= fp1= MEM_mallocN(sizeof(float)*3*dl->parts, "filldisp1"); + dlnew->nr= dl->parts; + dlnew->parts= 1; + dlnew->type= DL_POLY; + dlnew->col= dl->col; + dlnew->charidx = dl->charidx; + + fp= dl->verts; + dpoly= 3*dl->nr; + + a= dl->parts; + while(a--) { + VECCOPY(fp1, fp); + fp1+= 3; + fp+= dpoly; + } + } + if( (cu->flag & CU_FRONT) && (dl->flag & DL_FRONT_CURVE) ) { + dlnew= MEM_callocN(sizeof(DispList), "filldisp"); + BLI_addtail(&back, dlnew); + dlnew->verts= fp1= MEM_mallocN(sizeof(float)*3*dl->parts, "filldisp1"); + dlnew->nr= dl->parts; + dlnew->parts= 1; + dlnew->type= DL_POLY; + dlnew->col= dl->col; + dlnew->charidx= dl->charidx; + + fp= dl->verts+3*(dl->nr-1); + dpoly= 3*dl->nr; + + a= dl->parts; + while(a--) { + VECCOPY(fp1, fp); + fp1+= 3; + fp+= dpoly; + } + } + } + } + dl= dl->next; + } + + filldisplist(&front, dispbase); + filldisplist(&back, dispbase); + + freedisplist(&front); + freedisplist(&back); + + filldisplist(dispbase, dispbase); + +} + +void curve_to_filledpoly(Curve *cu, ListBase *nurb, ListBase *dispbase) +{ + if(cu->flag & CU_3D) return; + + if(dispbase->first && ((DispList*) dispbase->first)->type==DL_SURF) { + bevels_to_filledpoly(cu, dispbase); + } + else { + filldisplist(dispbase, dispbase); + } +} + +/* taper rules: + - only 1 curve + - first point left, last point right + - based on subdivided points in original curve, not on points in taper curve (still) +*/ +static float calc_taper(Object *taperobj, int cur, int tot) +{ + Curve *cu; + DispList *dl; + + if(taperobj==NULL) return 1.0; + + cu= taperobj->data; + dl= cu->disp.first; + if(dl==NULL) { + makeDispListCurveTypes(taperobj, 0); + dl= cu->disp.first; + } + if(dl) { + float fac= ((float)cur)/(float)(tot-1); + float minx, dx, *fp; + int a; + + /* horizontal size */ + minx= dl->verts[0]; + dx= dl->verts[3*(dl->nr-1)] - minx; + if(dx>0.0) { + + fp= dl->verts; + for(a=0; anr; a++, fp+=3) { + if( (fp[0]-minx)/dx >= fac) { + /* interpolate with prev */ + if(a>0) { + float fac1= (fp[-3]-minx)/dx; + float fac2= (fp[0]-minx)/dx; + if(fac1!=fac2) + return fp[1]*(fac1-fac)/(fac1-fac2) + fp[-2]*(fac-fac2)/(fac1-fac2); + } + return fp[1]; + } + } + return fp[-2]; // last y coord + } + } + + return 1.0; +} + +void makeDispListMBall(Object *ob) +{ + if(!ob || ob->type!=OB_MBALL) return; + + freedisplist(&(ob->disp)); + + if(ob->type==OB_MBALL) { + if(ob==find_basis_mball(ob)) { + metaball_polygonize(ob); + tex_space_mball(ob); + + object_deform_mball(ob); + } + } + + boundbox_displist(ob); +} + +static ModifierData *curve_get_tesselate_point(Object *ob, int forRender, int editmode) +{ + ModifierData *md = modifiers_getVirtualModifierList(ob); + ModifierData *preTesselatePoint; + int required_mode; + + if(forRender) required_mode = eModifierMode_Render; + else required_mode = eModifierMode_Realtime; + + if(editmode) required_mode |= eModifierMode_Editmode; + + preTesselatePoint = NULL; + for (; md; md=md->next) { + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + if ((md->mode & required_mode) != required_mode) continue; + if (mti->isDisabled && mti->isDisabled(md)) continue; + + if (md->type==eModifierType_Hook || md->type==eModifierType_Softbody) { + preTesselatePoint = md; + } + } + + return preTesselatePoint; +} + +void curve_calc_modifiers_pre(Object *ob, ListBase *nurb, int forRender, float (**originalVerts_r)[3], float (**deformedVerts_r)[3], int *numVerts_r) +{ + int editmode = (!forRender && ob==G.obedit); + ModifierData *md = modifiers_getVirtualModifierList(ob); + ModifierData *preTesselatePoint = curve_get_tesselate_point(ob, forRender, editmode); + int numVerts = 0; + float (*originalVerts)[3] = NULL; + float (*deformedVerts)[3] = NULL; + int required_mode; + + if(forRender) required_mode = eModifierMode_Render; + else required_mode = eModifierMode_Realtime; + + if(editmode) required_mode |= eModifierMode_Editmode; + + if(ob!=G.obedit && do_ob_key(ob)) { + deformedVerts = curve_getVertexCos(ob->data, nurb, &numVerts); + originalVerts = MEM_dupallocN(deformedVerts); + } + + if (preTesselatePoint) { + for (; md; md=md->next) { + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + if ((md->mode & required_mode) != required_mode) continue; + if (mti->isDisabled && mti->isDisabled(md)) continue; + if (mti->type!=eModifierTypeType_OnlyDeform) continue; + + if (!deformedVerts) { + deformedVerts = curve_getVertexCos(ob->data, nurb, &numVerts); + originalVerts = MEM_dupallocN(deformedVerts); + } + + mti->deformVerts(md, ob, NULL, deformedVerts, numVerts); + + if (md==preTesselatePoint) + break; + } + } + + if (deformedVerts) { + curve_applyVertexCos(ob->data, nurb, deformedVerts); + } + + *originalVerts_r = originalVerts; + *deformedVerts_r = deformedVerts; + *numVerts_r = numVerts; +} + +void curve_calc_modifiers_post(Object *ob, ListBase *nurb, ListBase *dispbase, int forRender, float (*originalVerts)[3], float (*deformedVerts)[3]) +{ + int editmode = (!forRender && ob==G.obedit); + ModifierData *md = modifiers_getVirtualModifierList(ob); + ModifierData *preTesselatePoint = curve_get_tesselate_point(ob, forRender, editmode); + DispList *dl; + int required_mode; + + if(forRender) required_mode = eModifierMode_Render; + else required_mode = eModifierMode_Realtime; + + if(editmode) required_mode |= eModifierMode_Editmode; + + if (preTesselatePoint) { + md = preTesselatePoint->next; + } + + for (; md; md=md->next) { + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + if ((md->mode & required_mode) != required_mode) continue; + if (mti->isDisabled && mti->isDisabled(md)) continue; + if (mti->type!=eModifierTypeType_OnlyDeform) continue; + + for (dl=dispbase->first; dl; dl=dl->next) { + mti->deformVerts(md, ob, NULL, (float(*)[3]) dl->verts, (dl->type==DL_INDEX3)?dl->nr:dl->parts*dl->nr); + } + } + + if (deformedVerts) { + curve_applyVertexCos(ob->data, nurb, originalVerts); + MEM_freeN(originalVerts); + MEM_freeN(deformedVerts); + } +} + +static void displist_surf_indices(DispList *dl) +{ + int a, b, p1, p2, p3, p4; + int *index; + + dl->totindex= 0; + + index=dl->index= MEM_mallocN( 4*sizeof(int)*(dl->parts+1)*(dl->nr+1), "index array nurbs"); + + for(a=0; aparts; a++) { + + DL_SURFINDEX(dl->flag & DL_CYCL_U, dl->flag & DL_CYCL_V, dl->nr, dl->parts); + + for(; bnr; b++, index+=4) { + index[0]= p1; + index[1]= p2; + index[2]= p4; + index[3]= p3; + + dl->totindex++; + + p2= p1; p1++; + p4= p3; p3++; + + } + } + +} + +void makeDispListSurf(Object *ob, ListBase *dispbase, int forRender) +{ + ListBase *nubase; + Nurb *nu; + Curve *cu = ob->data; + DispList *dl; + float *data; + int len; + int numVerts; + float (*originalVerts)[3]; + float (*deformedVerts)[3]; + + if(!forRender && ob==G.obedit) { + nubase= &editNurb; + } + else { + nubase= &cu->nurb; + } + + curve_calc_modifiers_pre(ob, nubase, forRender, &originalVerts, &deformedVerts, &numVerts); + + for (nu=nubase->first; nu; nu=nu->next) { + if(forRender || nu->hide==0) { + if(nu->pntsv==1) { + len= nu->pntsu*nu->resolu; + + dl= MEM_callocN(sizeof(DispList), "makeDispListsurf"); + dl->verts= MEM_callocN(len*3*sizeof(float), "dlverts"); + + BLI_addtail(dispbase, dl); + dl->parts= 1; + dl->nr= len; + dl->col= nu->mat_nr; + dl->charidx= nu->charidx; + dl->rt= nu->flag; + + data= dl->verts; + if(nu->flagu & 1) dl->type= DL_POLY; + else dl->type= DL_SEGM; + + makeNurbcurve(nu, data, nu->resolu, 3); + } + else { + len= nu->resolu*nu->resolv; + + dl= MEM_callocN(sizeof(DispList), "makeDispListsurf"); + dl->verts= MEM_callocN(len*3*sizeof(float), "dlverts"); + BLI_addtail(dispbase, dl); + + dl->col= nu->mat_nr; + dl->charidx= nu->charidx; + dl->rt= nu->flag; + + data= dl->verts; + dl->type= DL_SURF; + + dl->parts= nu->resolu; /* in reverse, because makeNurbfaces works that way */ + dl->nr= nu->resolv; + if(nu->flagv & CU_CYCLIC) dl->flag|= DL_CYCL_U; /* reverse too! */ + if(nu->flagu & CU_CYCLIC) dl->flag|= DL_CYCL_V; + + makeNurbfaces(nu, data, 0); + + /* gl array drawing: using indices */ + displist_surf_indices(dl); + } + } + } + + if (!forRender) { + tex_space_curve(cu); + } + + curve_calc_modifiers_post(ob, nubase, dispbase, forRender, originalVerts, deformedVerts); +} + +void makeDispListCurveTypes(Object *ob, int forOrco) +{ + Curve *cu = ob->data; + ListBase *dispbase; + + /* we do allow duplis... this is only displist on curve level */ + if(!ELEM3(ob->type, OB_SURF, OB_CURVE, OB_FONT)) return; + + freedisplist(&(ob->disp)); + dispbase= &(cu->disp); + freedisplist(dispbase); + + if(ob->type==OB_SURF) { + makeDispListSurf(ob, dispbase, 0); + } + else if ELEM(ob->type, OB_CURVE, OB_FONT) { + ListBase dlbev; + float (*originalVerts)[3]; + float (*deformedVerts)[3]; + int obedit= (G.obedit && G.obedit->data==ob->data && G.obedit->type==OB_CURVE); + ListBase *nubase = obedit?&editNurb:&cu->nurb; + int numVerts; + + BLI_freelistN(&(cu->bev)); + + if(cu->path) free_path(cu->path); + cu->path= NULL; + + if(ob->type==OB_FONT) text_to_curve(ob, 0); + + if(!forOrco) curve_calc_modifiers_pre(ob, nubase, 0, &originalVerts, &deformedVerts, &numVerts); + + makeBevelList(ob); + + /* If curve has no bevel will return nothing */ + makebevelcurve(ob, &dlbev); + + /* no bevel or extrude, and no width correction? */ + if (!dlbev.first && cu->width==1.0f) { + curve_to_displist(cu, nubase, dispbase); + } else { + float widfac= cu->width-1.0; + BevList *bl= cu->bev.first; + Nurb *nu= nubase->first; + + for (; bl && nu; bl=bl->next,nu=nu->next) { + DispList *dl; + float *fp1, *data; + BevPoint *bevp; + int a,b; + + /* exception handling; curve without bevel or extrude, with width correction */ + if(dlbev.first==NULL) { + dl= MEM_callocN(sizeof(DispList), "makeDispListbev"); + dl->verts= MEM_callocN(3*sizeof(float)*bl->nr, "dlverts"); + BLI_addtail(dispbase, dl); + + if(bl->poly!= -1) dl->type= DL_POLY; + else dl->type= DL_SEGM; + + if(dl->type==DL_SEGM) dl->flag = (DL_FRONT_CURVE|DL_BACK_CURVE); + + dl->parts= 1; + dl->nr= bl->nr; + dl->col= nu->mat_nr; + dl->charidx= nu->charidx; + dl->rt= nu->flag; + + a= dl->nr; + bevp= (BevPoint *)(bl+1); + data= dl->verts; + while(a--) { + data[0]= bevp->x+widfac*bevp->sina; + data[1]= bevp->y+widfac*bevp->cosa; + data[2]= bevp->z; + bevp++; + data+=3; + } + } + else { + DispList *dlb; + + for (dlb=dlbev.first; dlb; dlb=dlb->next) { + + /* for each part of the bevel use a separate displblock */ + dl= MEM_callocN(sizeof(DispList), "makeDispListbev1"); + dl->verts= data= MEM_callocN(3*sizeof(float)*dlb->nr*bl->nr, "dlverts"); + BLI_addtail(dispbase, dl); + + dl->type= DL_SURF; + + dl->flag= dlb->flag & (DL_FRONT_CURVE|DL_BACK_CURVE); + if(dlb->type==DL_POLY) dl->flag |= DL_CYCL_U; + if(bl->poly>=0) dl->flag |= DL_CYCL_V; + + dl->parts= bl->nr; + dl->nr= dlb->nr; + dl->col= nu->mat_nr; + dl->charidx= nu->charidx; + dl->rt= nu->flag; + dl->bevelSplitFlag= MEM_callocN(sizeof(*dl->col2)*((bl->nr+0x1F)>>5), "col2"); + bevp= (BevPoint *)(bl+1); + + /* for each point of poly make a bevel piece */ + bevp= (BevPoint *)(bl+1); + for(a=0; anr; a++,bevp++) { + float fac=1.0; + if (cu->taperobj==NULL) { + if ( (cu->bevobj!=NULL) || !((cu->flag & CU_FRONT) || (cu->flag & CU_BACK)) ) + fac = calc_curve_subdiv_radius(cu, nu, a); + } else { + fac = calc_taper(cu->taperobj, a, bl->nr); + } + + if (bevp->f1) { + dl->bevelSplitFlag[a>>5] |= 1<<(a&0x1F); + } + + /* rotate bevel piece and write in data */ + fp1= dlb->verts; + for (b=0; bnr; b++,fp1+=3,data+=3) { + if(cu->flag & CU_3D) { + float vec[3]; + + vec[0]= fp1[1]+widfac; + vec[1]= fp1[2]; + vec[2]= 0.0; + + Mat3MulVecfl(bevp->mat, vec); + + data[0]= bevp->x+ fac*vec[0]; + data[1]= bevp->y+ fac*vec[1]; + data[2]= bevp->z+ fac*vec[2]; + } + else { + data[0]= bevp->x+ fac*(widfac+fp1[1])*bevp->sina; + data[1]= bevp->y+ fac*(widfac+fp1[1])*bevp->cosa; + data[2]= bevp->z+ fac*fp1[2]; + } + } + } + + /* gl array drawing: using indices */ + displist_surf_indices(dl); + } + } + + } + freedisplist(&dlbev); + } + + curve_to_filledpoly(cu, nubase, dispbase); + + if(cu->flag & CU_PATH) calc_curvepath(ob); + + if(!forOrco) curve_calc_modifiers_post(ob, nubase, &cu->disp, 0, originalVerts, deformedVerts); + tex_space_curve(cu); + } + + boundbox_displist(ob); +} + +void imagestodisplist(void) +{ + /* removed */ +} + +/* this is confusing, there's also min_max_object, appplying the obmat... */ +static void boundbox_displist(Object *ob) +{ + BoundBox *bb=0; + float min[3], max[3]; + DispList *dl; + float *vert; + int a, tot=0; + + INIT_MINMAX(min, max); + + if(ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { + Curve *cu= ob->data; + int doit= 0; + + if(cu->bb==0) cu->bb= MEM_callocN(sizeof(BoundBox), "boundbox"); + bb= cu->bb; + + dl= cu->disp.first; + + while (dl) { + if(dl->type==DL_INDEX3) tot= dl->nr; + else tot= dl->nr*dl->parts; + + vert= dl->verts; + for(a=0; anext; + } + + if(!doit) { + min[0] = min[1] = min[2] = -1.0f; + max[0] = max[1] = max[2] = 1.0f; + } + + } + + if(bb) { + boundbox_set_from_min_max(bb, min, max); + } +} + diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c new file mode 100644 index 00000000000..07fe8bbee31 --- /dev/null +++ b/source/blender/blenkernel/intern/effect.c @@ -0,0 +1,2110 @@ +/* effect.c + * + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_curve_types.h" +#include "DNA_effect_types.h" +#include "DNA_group_types.h" +#include "DNA_ipo_types.h" +#include "DNA_key_types.h" +#include "DNA_lattice_types.h" +#include "DNA_listBase.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_material_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force.h" +#include "DNA_texture_types.h" +#include "DNA_scene_types.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" +#include "BLI_jitter.h" +#include "BLI_rand.h" + +#include "BKE_action.h" +#include "BKE_anim.h" /* needed for where_on_path */ +#include "BKE_armature.h" +#include "BKE_bad_level_calls.h" +#include "BKE_blender.h" +#include "BKE_constraint.h" +#include "BKE_deform.h" +#include "BKE_depsgraph.h" +#include "BKE_displist.h" +#include "BKE_DerivedMesh.h" +#include "BKE_effect.h" +#include "BKE_global.h" +#include "BKE_group.h" +#include "BKE_ipo.h" +#include "BKE_key.h" +#include "BKE_lattice.h" +#include "BKE_mesh.h" +#include "BKE_material.h" +#include "BKE_main.h" +#include "BKE_modifier.h" +#include "BKE_object.h" +#include "BKE_scene.h" +#include "BKE_screen.h" +#include "BKE_utildefines.h" + +#include "PIL_time.h" +#include "RE_render_ext.h" + +/* fluid sim particle import */ +#ifndef DISABLE_ELBEEM +#include "DNA_object_fluidsim.h" +#include "LBM_fluidsim.h" +#include "elbeem.h" +#include +#include +#endif // DISABLE_ELBEEM + +/* temporal struct, used for reading return of mesh_get_mapped_verts_nors() */ +typedef struct VeNoCo { + float co[3], no[3]; +} VeNoCo; + +Effect *add_effect(int type) +{ + Effect *eff=0; + PartEff *paf; + int a; + + switch(type) { + case EFF_PARTICLE: + paf= MEM_callocN(sizeof(PartEff), "neweff"); + eff= (Effect *)paf; + + paf->sta= 1.0; + paf->end= 100.0; + paf->lifetime= 50.0; + for(a=0; alife[a]= 50.0; + paf->child[a]= 4; + paf->mat[a]= 1; + } + + paf->totpart= 1000; + paf->totkey= 8; + paf->staticstep= 5; + paf->defvec[2]= 1.0f; + paf->nabla= 0.05f; + paf->disp = 100; + paf->speedtex = 8; + paf->omat = 1; + paf->flag= PAF_FACE; + + break; + } + + eff->type= eff->buttype= type; + eff->flag |= SELECT; + + return eff; +} + +void free_effect(Effect *eff) +{ + PartEff *paf; + + if(eff->type==EFF_PARTICLE) { + paf= (PartEff *)eff; + if(paf->keys) MEM_freeN(paf->keys); + } + MEM_freeN(eff); +} + + +void free_effects(ListBase *lb) +{ + Effect *eff; + + eff= lb->first; + while(eff) { + BLI_remlink(lb, eff); + free_effect(eff); + eff= lb->first; + } +} + +Effect *copy_effect(Effect *eff) +{ + Effect *effn; + + effn= MEM_dupallocN(eff); + if(effn->type==EFF_PARTICLE) ((PartEff *)effn)->keys= 0; + + return effn; +} + +void copy_act_effect(Object *ob) +{ + /* return a copy of the active effect */ + Effect *effn, *eff; + + eff= ob->effect.first; + while(eff) { + if(eff->flag & SELECT) { + + effn= copy_effect(eff); + BLI_addtail(&ob->effect, effn); + + eff->flag &= ~SELECT; + return; + + } + eff= eff->next; + } + + /* when it comes here: add new effect */ + eff= add_effect(EFF_PARTICLE); + BLI_addtail(&ob->effect, eff); + +} + +void copy_effects(ListBase *lbn, ListBase *lb) +{ + Effect *eff, *effn; + + lbn->first= lbn->last= 0; + + eff= lb->first; + while(eff) { + effn= copy_effect(eff); + BLI_addtail(lbn, effn); + + eff= eff->next; + } + +} + +void deselectall_eff(Object *ob) +{ + Effect *eff= ob->effect.first; + + while(eff) { + eff->flag &= ~SELECT; + eff= eff->next; + } +} + +/* ***************** PARTICLES ***************** */ + +static Particle *new_particle(PartEff *paf) +{ + static Particle *pa; + static int cur; + + /* we agree: when paf->keys==0: alloc */ + if(paf->keys==NULL) { + pa= paf->keys= MEM_callocN( paf->totkey*paf->totpart*sizeof(Particle), "particlekeys" ); + cur= 0; + } + else { + if(cur && curtotpart) pa+=paf->totkey; + cur++; + } + return pa; +} + +PartEff *give_parteff(Object *ob) +{ + PartEff *paf; + + paf= ob->effect.first; + while(paf) { + if(paf->type==EFF_PARTICLE) return paf; + paf= paf->next; + } + return 0; +} + +void where_is_particle(PartEff *paf, Particle *pa, float ctime, float *vec) +{ + Particle *p[4]; + float dt, t[4]; + int a; + + if(paf->totkey==1 || ctime < pa->time) { + VECCOPY(vec, pa->co); + return; + } + + /* first find the first particlekey */ + a= (int)((paf->totkey-1)*(ctime-pa->time)/pa->lifetime); + if(a>=paf->totkey) a= paf->totkey-1; + else if(a<0) a= 0; + + pa+= a; + + if(a>0) p[0]= pa-1; else p[0]= pa; + p[1]= pa; + + if(a+1totkey) p[2]= pa+1; else p[2]= pa; + if(a+2totkey) p[3]= pa+2; else p[3]= p[2]; + + if(p[1]==p[2] || p[2]->time == p[1]->time) dt= 0.0; + else dt= (ctime-p[1]->time)/(p[2]->time - p[1]->time); + + if(paf->flag & PAF_BSPLINE) set_four_ipo(dt, t, KEY_BSPLINE); + else set_four_ipo(dt, t, KEY_CARDINAL); + + vec[0]= t[0]*p[0]->co[0] + t[1]*p[1]->co[0] + t[2]*p[2]->co[0] + t[3]*p[3]->co[0]; + vec[1]= t[0]*p[0]->co[1] + t[1]*p[1]->co[1] + t[2]*p[2]->co[1] + t[3]*p[3]->co[1]; + vec[2]= t[0]*p[0]->co[2] + t[1]*p[1]->co[2] + t[2]*p[2]->co[2] + t[3]*p[3]->co[2]; + +} + +static void particle_tex(MTex *mtex, PartEff *paf, float *co, float *no) +{ + float tin, tr, tg, tb, ta; + float old; + + externtex(mtex, co, &tin, &tr, &tg, &tb, &ta); + + if(paf->texmap==PAF_TEXINT) { + tin*= paf->texfac; + no[0]+= tin*paf->defvec[0]; + no[1]+= tin*paf->defvec[1]; + no[2]+= tin*paf->defvec[2]; + } + else if(paf->texmap==PAF_TEXRGB) { + no[0]+= (tr-0.5f)*paf->texfac; + no[1]+= (tg-0.5f)*paf->texfac; + no[2]+= (tb-0.5f)*paf->texfac; + } + else { /* PAF_TEXGRAD */ + + old= tin; + co[0]+= paf->nabla; + externtex(mtex, co, &tin, &tr, &tg, &tb, &ta); + no[0]+= (old-tin)*paf->texfac; + + co[0]-= paf->nabla; + co[1]+= paf->nabla; + externtex(mtex, co, &tin, &tr, &tg, &tb, &ta); + no[1]+= (old-tin)*paf->texfac; + + co[1]-= paf->nabla; + co[2]+= paf->nabla; + externtex(mtex, co, &tin, &tr, &tg, &tb, &ta); + no[2]+= (old-tin)*paf->texfac; + + } +} + +/* -------------------------- Effectors ------------------ */ + +static void add_to_effectorcache(ListBase *lb, Object *ob, Object *obsrc) +{ + pEffectorCache *ec; + PartDeflect *pd= ob->pd; + + if(pd->forcefield == PFIELD_GUIDE) { + if(ob->type==OB_CURVE && obsrc->type==OB_MESH) { /* guides only do mesh particles */ + Curve *cu= ob->data; + if(cu->flag & CU_PATH) { + if(cu->path==NULL || cu->path->data==NULL) + makeDispListCurveTypes(ob, 0); + if(cu->path && cu->path->data) { + ec= MEM_callocN(sizeof(pEffectorCache), "effector cache"); + ec->ob= ob; + BLI_addtail(lb, ec); + } + } + } + } + else if(pd->forcefield) { + ec= MEM_callocN(sizeof(pEffectorCache), "effector cache"); + ec->ob= ob; + BLI_addtail(lb, ec); + } +} + +/* returns ListBase handle with objects taking part in the effecting */ +ListBase *pdInitEffectors(Object *obsrc, Group *group) +{ + static ListBase listb={NULL, NULL}; + pEffectorCache *ec; + Base *base; + unsigned int layer= obsrc->lay; + + if(group) { + GroupObject *go; + + for(go= group->gobject.first; go; go= go->next) { + if( (go->ob->lay & layer) && go->ob->pd && go->ob!=obsrc) { + add_to_effectorcache(&listb, go->ob, obsrc); + } + } + } + else { + for(base = G.scene->base.first; base; base= base->next) { + if( (base->lay & layer) && base->object->pd && base->object!=obsrc) { + add_to_effectorcache(&listb, base->object, obsrc); + } + } + } + + /* make a full copy */ + for(ec= listb.first; ec; ec= ec->next) { + ec->obcopy= *(ec->ob); + } + + if(listb.first) + return &listb; + + return NULL; +} + +void pdEndEffectors(ListBase *lb) +{ + if(lb) { + pEffectorCache *ec; + /* restore full copy */ + for(ec= lb->first; ec; ec= ec->next) + *(ec->ob)= ec->obcopy; + + BLI_freelistN(lb); + } +} + +/* local for this c file, only for guides now */ +static void precalc_effectors(Object *ob, PartEff *paf, Particle *pa, ListBase *lb) +{ + pEffectorCache *ec; + + for(ec= lb->first; ec; ec= ec->next) { + PartDeflect *pd= ec->ob->pd; + + ec->oldspeed[0]= ec->oldspeed[1]= ec->oldspeed[2]= 0.0f; + + if(pd->forcefield==PFIELD_GUIDE && ec->ob->type==OB_CURVE) { + float vec[4], dir[3]; + + if(!(paf->flag & PAF_STATIC)) + where_is_object_time(ec->ob, pa->time); + + /* scale corrects speed vector to curve size */ + if(paf->totkey>1) ec->scale= (paf->totkey-1)/pa->lifetime; + else ec->scale= 1.0f; + + /* time_scale is for random life */ + if(pa->lifetime>paf->lifetime) + ec->time_scale= paf->lifetime/pa->lifetime; + else + ec->time_scale= pa->lifetime/paf->lifetime; + + /* distance of first path point to particle origin */ + where_on_path(ec->ob, 0.0f, vec, dir); + VECCOPY(ec->oldloc, vec); /* store local coord for differences */ + Mat4MulVecfl(ec->ob->obmat, vec); + + /* for static we need to move to global space */ + if(paf->flag & PAF_STATIC) { + VECCOPY(dir, pa->co); + Mat4MulVecfl(ob->obmat, dir); + ec->guide_dist= VecLenf(vec, dir); + } + else + ec->guide_dist= VecLenf(vec, pa->co); + } + } +} + + +/* -------- pdDoEffectors() -------- + generic force/speed system, now used for particles and softbodies + lb = listbase with objects that take part in effecting + opco = global coord, as input + force = force accumulator + speed = actual current speed which can be altered + cur_time = "external" time in frames, is constant for static particles + loc_time = "local" time in frames, range <0-1> for the lifetime of particle + par_layer = layer the caller is in + flags = only used for softbody wind now + guide = old speed of particle + +*/ +void pdDoEffectors(ListBase *lb, float *opco, float *force, float *speed, float cur_time, float loc_time, unsigned int flags) +{ +/* + Modifies the force on a particle according to its + relation with the effector object + Different kind of effectors include: + Forcefields: Gravity-like attractor + (force power is related to the inverse of distance to the power of a falloff value) + Vortex fields: swirling effectors + (particles rotate around Z-axis of the object. otherwise, same relation as) + (Forcefields, but this is not done through a force/acceleration) + Guide: particles on a path + (particles are guided along a curve bezier or old nurbs) + (is independent of other effectors) +*/ + Object *ob; + pEffectorCache *ec; + PartDeflect *pd; + float vect_to_vert[3]; + float f_force, force_vec[3]; + float *obloc; + float distance, force_val, ffall_val; + float guidecollect[3], guidedist= 0.0f; + int cur_frame; + + guidecollect[0]= guidecollect[1]= guidecollect[2]=0.0f; + + /* Cycle through collected objects, get total of (1/(gravity_strength * dist^gravity_power)) */ + /* Check for min distance here? (yes would be cool to add that, ton) */ + + for(ec = lb->first; ec; ec= ec->next) { + /* object effectors were fully checked to be OK to evaluate! */ + ob= ec->ob; + pd= ob->pd; + + /* Get IPO force strength and fall off values here */ + if (has_ipo_code(ob->ipo, OB_PD_FSTR)) + force_val = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, cur_time); + else + force_val = pd->f_strength; + + if (has_ipo_code(ob->ipo, OB_PD_FFALL)) + ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, cur_time); + else + ffall_val = pd->f_power; + + /* Need to set r.cfra for paths (investigate, ton) (uses ob->ctime now, ton) */ + if(ob->ctime!=cur_time) { + cur_frame = G.scene->r.cfra; + G.scene->r.cfra = (int)cur_time; + where_is_object_time(ob, cur_time); + G.scene->r.cfra = cur_frame; + } + + /* use center of object for distance calculus */ + obloc= ob->obmat[3]; + VECSUB(vect_to_vert, obloc, opco); + distance = VecLength(vect_to_vert); + + if((pd->flag & PFIELD_USEMAX) && distance>pd->maxdist && pd->forcefield != PFIELD_GUIDE) + ; /* don't do anything */ + else if(pd->forcefield == PFIELD_WIND) { + VECCOPY(force_vec, ob->obmat[2]); + + /* wind works harder perpendicular to normal, would be nice for softbody later (ton) */ + + /* Limit minimum distance to vertex so that */ + /* the force is not too big */ + if (distance < 0.001) distance = 0.001f; + f_force = (force_val)*(1/(1000 * (float)pow((double)distance, (double)ffall_val))); + /* this option for softbody only */ + if(flags && PE_WIND_AS_SPEED){ + speed[0] -= (force_vec[0] * f_force ); + speed[1] -= (force_vec[1] * f_force ); + speed[2] -= (force_vec[2] * f_force ); + } + else{ + force[0] += force_vec[0]*f_force; + force[1] += force_vec[1]*f_force; + force[2] += force_vec[2]*f_force; + } + } + else if(pd->forcefield == PFIELD_FORCE) { + + /* only use center of object */ + obloc= ob->obmat[3]; + + /* Now calculate the gravitational force */ + VECSUB(vect_to_vert, obloc, opco); + distance = VecLength(vect_to_vert); + + /* Limit minimum distance to vertex so that */ + /* the force is not too big */ + if (distance < 0.001) distance = 0.001f; + f_force = (force_val)*(1.0/(1000.0 * (float)pow((double)distance, (double)ffall_val))); + force[0] += (vect_to_vert[0] * f_force ); + force[1] += (vect_to_vert[1] * f_force ); + force[2] += (vect_to_vert[2] * f_force ); + } + else if(pd->forcefield == PFIELD_VORTEX) { + float vortexvec[3]; + + /* only use center of object */ + obloc= ob->obmat[3]; + + /* Now calculate the vortex force */ + VECSUB(vect_to_vert, obloc, opco); + distance = VecLength(vect_to_vert); + + Crossf(force_vec, ob->obmat[2], vect_to_vert); + Normalize(force_vec); + + /* Limit minimum distance to vertex so that */ + /* the force is not too big */ + if (distance < 0.001) distance = 0.001f; + f_force = (force_val)*(1.0/(100.0 * (float)pow((double)distance, (double)ffall_val))); + vortexvec[0]= -(force_vec[0] * f_force ); + vortexvec[1]= -(force_vec[1] * f_force ); + vortexvec[2]= -(force_vec[2] * f_force ); + + /* this option for softbody only */ + if(flags &&PE_WIND_AS_SPEED) { + speed[0]+= vortexvec[0]; + speed[1]+= vortexvec[1]; + speed[2]+= vortexvec[2]; + } + else { + /* since vortex alters the speed, we have to correct for the previous vortex result */ + speed[0]+= vortexvec[0] - ec->oldspeed[0]; + speed[1]+= vortexvec[1] - ec->oldspeed[1]; + speed[2]+= vortexvec[2] - ec->oldspeed[2]; + + VECCOPY(ec->oldspeed, vortexvec); + } + } + else if(pd->forcefield == PFIELD_GUIDE) { + float guidevec[4], guidedir[3]; + float mindist= force_val; /* force_val is actually mindist in the UI */ + + distance= ec->guide_dist; + + /* WARNING: bails out with continue here */ + if((pd->flag & PFIELD_USEMAX) && distance>pd->maxdist) continue; + + /* calculate contribution factor for this guide */ + if(distance<=mindist) f_force= 1.0f; + else if(pd->flag & PFIELD_USEMAX) { + if(distance>pd->maxdist || mindist>=pd->maxdist) f_force= 0.0f; + else { + f_force= 1.0f - (distance-mindist)/(pd->maxdist - mindist); + if(ffall_val!=0.0f) + f_force = (float)pow(f_force, ffall_val+1.0); + } + } + else { + f_force= 1.0f/(1.0f + distance-mindist); + if(ffall_val!=0.0f) + f_force = (float)pow(f_force, ffall_val+1.0); + } + + /* now derive path point from loc_time */ + if(pd->flag & PFIELD_GUIDE_PATH_ADD) + where_on_path(ob, f_force*loc_time*ec->time_scale, guidevec, guidedir); + else + where_on_path(ob, loc_time*ec->time_scale, guidevec, guidedir); + + VECSUB(guidedir, guidevec, ec->oldloc); + VECCOPY(ec->oldloc, guidevec); + + Mat4Mul3Vecfl(ob->obmat, guidedir); + VecMulf(guidedir, ec->scale); /* correction for lifetime and speed */ + + /* we subtract the speed we gave it previous step */ + VECCOPY(guidevec, guidedir); + VECSUB(guidedir, guidedir, ec->oldspeed); + VECCOPY(ec->oldspeed, guidevec); + + /* if it fully contributes, we stop */ + if(f_force==1.0) { + VECCOPY(guidecollect, guidedir); + guidedist= 1.0f; + break; + } + else if(guidedist<1.0f) { + VecMulf(guidedir, f_force); + VECADD(guidecollect, guidecollect, guidedir); + guidedist += f_force; + } + } + } + + /* all guides are accumulated here */ + if(guidedist!=0.0f) { + if(guidedist!=1.0f) VecMulf(guidecollect, 1.0f/guidedist); + VECADD(speed, speed, guidecollect); + } +} + +static void cache_object_vertices(Object *ob) +{ + Mesh *me; + MVert *mvert; + float *fp; + int a; + + me= ob->data; + if(me->totvert==0) return; + + fp= ob->sumohandle= MEM_mallocN(3*sizeof(float)*me->totvert, "cache particles"); + mvert= me->mvert; + a= me->totvert; + while(a--) { + VECCOPY(fp, mvert->co); + Mat4MulVecfl(ob->obmat, fp); + mvert++; + fp+= 3; + } +} + +static int pdDoDeflection(RNG *rng, float opco[3], float npco[3], float opno[3], + float npno[3], float life, float force[3], int def_depth, + float cur_time, unsigned int par_layer, int *last_object, + int *last_face, int *same_face) +{ + /* Particle deflection code */ + /* The code is in two sections: the first part checks whether a particle has */ + /* intersected a face of a deflector mesh, given its old and new co-ords, opco and npco */ + /* and which face it hit first */ + /* The second part calculates the new co-ordinates given that collision and updates */ + /* the new co-ordinates accordingly */ + Base *base; + Object *ob, *deflection_object = NULL; + Mesh *def_mesh; + MFace *mface, *deflection_face = NULL; + float *v1, *v2, *v3, *v4, *vcache=NULL; + float nv1[3], nv2[3], nv3[3], nv4[3], edge1[3], edge2[3]; + float dv1[3] = {0}, dv2[3] = {0}, dv3[3] = {0}; + float vect_to_int[3], refl_vel[3]; + float d_intersect_co[3], d_intersect_vect[3], d_nvect[3], d_i_co_above[3]; + float forcec[3]; + float k_point3, dist_to_plane; + float first_dist, ref_plane_mag; + float dk_plane=0, dk_point1=0; + float icalctop, icalcbot, n_mag; + float mag_iv, x_m,y_m,z_m; + float damping, perm_thresh; + float perm_val, rdamp_val; + int a, deflected=0, deflected_now=0; + float t,t2, min_t; + float mat[3][3], obloc[3] = {0}; + int cur_frame; + float time_before, time_after; + float force_mag_norm; + int d_object=0, d_face=0, ds_object=0, ds_face=0; + + first_dist = 200000; + min_t = 200000; + + /* The first part of the code, finding the first intersected face*/ + base= G.scene->base.first; + while (base) { + /*Only proceed for mesh object in same layer */ + if(base->object->type==OB_MESH && (base->lay & par_layer)) { + ob= base->object; + /* only with deflecting set */ + if(ob->pd && ob->pd->deflect) { + def_mesh= ob->data; + + d_object = d_object + 1; + + d_face = d_face + 1; + mface= def_mesh->mface; + a = def_mesh->totface; + + + if(ob->parent==NULL && ob->ipo==NULL) { // static + if(ob->sumohandle==NULL) cache_object_vertices(ob); + vcache= ob->sumohandle; + } + else { + /*Find out where the object is at this time*/ + cur_frame = G.scene->r.cfra; + G.scene->r.cfra = (int)cur_time; + where_is_object_time(ob, cur_time); + G.scene->r.cfra = cur_frame; + + /*Pass the values from ob->obmat to mat*/ + /*and the location values to obloc */ + Mat3CpyMat4(mat,ob->obmat); + obloc[0] = ob->obmat[3][0]; + obloc[1] = ob->obmat[3][1]; + obloc[2] = ob->obmat[3][2]; + vcache= NULL; + + } + + while (a--) { + + if(vcache) { + v1= vcache+ 3*(mface->v1); + VECCOPY(nv1, v1); + v1= vcache+ 3*(mface->v2); + VECCOPY(nv2, v1); + v1= vcache+ 3*(mface->v3); + VECCOPY(nv3, v1); + v1= vcache+ 3*(mface->v4); + VECCOPY(nv4, v1); + } + else { + /* Calculate the global co-ordinates of the vertices*/ + v1= (def_mesh->mvert+(mface->v1))->co; + v2= (def_mesh->mvert+(mface->v2))->co; + v3= (def_mesh->mvert+(mface->v3))->co; + v4= (def_mesh->mvert+(mface->v4))->co; + + VECCOPY(nv1, v1); + VECCOPY(nv2, v2); + VECCOPY(nv3, v3); + VECCOPY(nv4, v4); + + /*Apply the objects deformation matrix*/ + Mat3MulVecfl(mat, nv1); + Mat3MulVecfl(mat, nv2); + Mat3MulVecfl(mat, nv3); + Mat3MulVecfl(mat, nv4); + + VECADD(nv1, nv1, obloc); + VECADD(nv2, nv2, obloc); + VECADD(nv3, nv3, obloc); + VECADD(nv4, nv4, obloc); + } + + deflected_now = 0; + + + +// t= 0.5; // this is labda of line, can use it optimize quad intersection +// sorry but no .. see below (BM) + if( LineIntersectsTriangle(opco, npco, nv1, nv2, nv3, &t) ) { + if (t < min_t) { + deflected = 1; + deflected_now = 1; + } + } +// else if (mface->v4 && (t>=0.0 && t<=1.0)) { +// no, you can't skip testing the other triangle +// it might give a smaller t on (close to) the edge .. this is numerics not esoteric maths :) +// note: the 2 triangles don't need to share a plane ! (BM) + if (mface->v4) { + if( LineIntersectsTriangle(opco, npco, nv1, nv3, nv4, &t2) ) { + if (t2 < min_t) { + deflected = 1; + deflected_now = 2; + } + } + } + + if ((deflected_now > 0) && ((t < min_t) ||(t2 < min_t))) { + min_t = t; + ds_object = d_object; + ds_face = d_face; + deflection_object = ob; + deflection_face = mface; + if (deflected_now==1) { + min_t = t; + VECCOPY(dv1, nv1); + VECCOPY(dv2, nv2); + VECCOPY(dv3, nv3); + } + else { + min_t = t2; + VECCOPY(dv1, nv1); + VECCOPY(dv2, nv3); + VECCOPY(dv3, nv4); + } + } + mface++; + } + } + } + base = base->next; + } + + + /* Here's the point to do the permeability calculation */ + /* Set deflected to 0 if a random number is below the value */ + /* Get the permeability IPO here*/ + if (deflected) { + + if (has_ipo_code(deflection_object->ipo, OB_PD_PERM)) + perm_val = IPO_GetFloatValue(deflection_object->ipo, OB_PD_PERM, cur_time); + else + perm_val = deflection_object->pd->pdef_perm; + + perm_thresh = rng_getFloat(rng) - perm_val; + if (perm_thresh < 0 ) { + deflected = 0; + } + } + + /* Now for the second part of the deflection code - work out the new speed */ + /* and position of the particle if a collision occurred */ + if (deflected) { + VECSUB(edge1, dv1, dv2); + VECSUB(edge2, dv3, dv2); + Crossf(d_nvect, edge2, edge1); + n_mag = Normalize(d_nvect); + dk_plane = INPR(d_nvect, nv1); + dk_point1 = INPR(d_nvect,opco); + + VECSUB(d_intersect_vect, npco, opco); + + d_intersect_co[0] = opco[0] + (min_t * (npco[0] - opco[0])); + d_intersect_co[1] = opco[1] + (min_t * (npco[1] - opco[1])); + d_intersect_co[2] = opco[2] + (min_t * (npco[2] - opco[2])); + + d_i_co_above[0] = (d_intersect_co[0] + (0.001f * d_nvect[0])); + d_i_co_above[1] = (d_intersect_co[1] + (0.001f * d_nvect[1])); + d_i_co_above[2] = (d_intersect_co[2] + (0.001f * d_nvect[2])); + mag_iv = Normalize(d_intersect_vect); + VECCOPY(npco, d_intersect_co); + + VECSUB(vect_to_int, opco, d_intersect_co); + first_dist = Normalize(vect_to_int); + + /* Work out the lengths of time before and after collision*/ + time_before = (life*(first_dist / (mag_iv))); + time_after = (life*((mag_iv - first_dist) / (mag_iv))); + + /* We have to recalculate what the speed would have been at the */ + /* point of collision, not the key frame time */ + npno[0]= opno[0] + time_before*force[0]; + npno[1]= opno[1] + time_before*force[1]; + npno[2]= opno[2] + time_before*force[2]; + + + /* Reflect the speed vector in the face */ + x_m = (2 * npno[0] * d_nvect[0]); + y_m = (2 * npno[1] * d_nvect[1]); + z_m = (2 * npno[2] * d_nvect[2]); + refl_vel[0] = npno[0] - (d_nvect[0] * (x_m + y_m + z_m)); + refl_vel[1] = npno[1] - (d_nvect[1] * (x_m + y_m + z_m)); + refl_vel[2] = npno[2] - (d_nvect[2] * (x_m + y_m + z_m)); + + /*A random variation in the damping factor........ */ + /*Get the IPO values for damping here*/ + + if (has_ipo_code(deflection_object->ipo, OB_PD_SDAMP)) + damping = IPO_GetFloatValue(deflection_object->ipo, OB_PD_SDAMP, cur_time); + else + damping = deflection_object->pd->pdef_damp; + + if (has_ipo_code(deflection_object->ipo, OB_PD_RDAMP)) + rdamp_val = IPO_GetFloatValue(deflection_object->ipo, OB_PD_RDAMP, cur_time); + else + rdamp_val = deflection_object->pd->pdef_rdamp; + + damping = damping + ((1.0f - damping) * rng_getFloat(rng) *rdamp_val); + damping = damping * damping; + ref_plane_mag = INPR(refl_vel,d_nvect); + + if (damping > 0.999) damping = 0.999f; + + /* Now add in the damping force - only damp in the direction of */ + /* the faces normal vector */ + npno[0] = (refl_vel[0] - (d_nvect[0] * ref_plane_mag * damping)); + npno[1] = (refl_vel[1] - (d_nvect[1] * ref_plane_mag * damping)); + npno[2] = (refl_vel[2] - (d_nvect[2] * ref_plane_mag * damping)); + + /* Now reset opno */ + VECCOPY(opno,npno); + VECCOPY(forcec, force); + + /* If the particle has bounced more than four times on the same */ + /* face within this cycle (depth > 4, same face > 4 ) */ + /* Then set the force to be only that component of the force */ + /* in the same direction as the face normal */ + /* i.e. subtract the component of the force in the direction */ + /* of the face normal from the actual force */ + if ((ds_object == *last_object) && (ds_face == *last_face)) { + /* Increment same_face */ + *same_face = *same_face + 1; + if ((*same_face > 3) && (def_depth > 3)) { + force_mag_norm = INPR(forcec, d_nvect); + forcec[0] = forcec[0] - (d_nvect[0] * force_mag_norm); + forcec[1] = forcec[1] - (d_nvect[1] * force_mag_norm); + forcec[2] = forcec[2] - (d_nvect[2] * force_mag_norm); + } + } + else *same_face = 1; + + *last_object = ds_object; + *last_face = ds_face; + + /* We have the particles speed at the point of collision */ + /* Now we want the particles speed at the current key frame */ + + npno[0]= npno[0] + time_after*forcec[0]; + npno[1]= npno[1] + time_after*forcec[1]; + npno[2]= npno[2] + time_after*forcec[2]; + + /* Now we have to recalculate pa->co for the remainder*/ + /* of the time since the intersect*/ + npco[0]= npco[0] + time_after*npno[0]; + npco[1]= npco[1] + time_after*npno[1]; + npco[2]= npco[2] + time_after*npno[2]; + + /* And set the old co-ordinates back to the point just above the intersection */ + VECCOPY(opco, d_i_co_above); + + /* Finally update the time */ + life = time_after; + cur_time += time_before; + + /* The particle may have fallen through the face again by now!!*/ + /* So check if the particle has changed sides of the plane compared*/ + /* the co-ordinates at the last keyframe*/ + /* But only do this as a last resort, if we've got to the end of the */ + /* number of collisions allowed */ + if (def_depth==9) { + k_point3 = INPR(d_nvect,npco); + if (((dk_plane > k_point3) && (dk_plane < dk_point1))||((dk_plane < k_point3) && (dk_plane > dk_point1))) { + + /* Yup, the pesky particle may have fallen through a hole!!! */ + /* So we'll cheat a bit and move the particle along the normal vector */ + /* until it's just the other side of the plane */ + icalctop = (dk_plane - d_nvect[0]*npco[0] - d_nvect[1]*npco[1] - d_nvect[2]*npco[2]); + icalcbot = (d_nvect[0]*d_nvect[0] + d_nvect[1]*d_nvect[1] + d_nvect[2]*d_nvect[2]); + dist_to_plane = icalctop / icalcbot; + + /* Now just increase the distance a little to place */ + /* the point the other side of the plane */ + dist_to_plane *= 1.1f; + npco[0]= npco[0] + (dist_to_plane * d_nvect[0]); + npco[1]= npco[1] + (dist_to_plane * d_nvect[1]); + npco[2]= npco[2] + (dist_to_plane * d_nvect[2]); + + } + } + } + return deflected; +} + +/* + rng= random number generator + ob = object that spawns the particles + depth = for fireworks + nr = index nr of current particle + paf = the particle system + part = current particle + force = force vector + deform = flag to indicate lattice deform + */ +static void make_particle_keys(RNG *rng, Object *ob, int depth, int nr, PartEff *paf, Particle *part, float *force, int deform, MTex *mtex, ListBase *effectorbase) +{ + Particle *pa, *opa = NULL; + float damp, deltalife, life; + float cur_time, maxspeed= paf->maxlen/(float)paf->totkey; + float opco[3], opno[3], npco[3], npno[3], new_force[3], new_speed[3]; + int b, rt1, rt2, deflected, deflection, finish_defs, def_count; + int last_ob, last_fc, same_fc; + + damp= 1.0f-paf->damp; + pa= part; + + /* start speed: random */ + if(paf->randfac!=0.0) { + pa->no[0]+= paf->randfac*(rng_getFloat(rng) - 0.5f); + pa->no[1]+= paf->randfac*(rng_getFloat(rng) - 0.5f); + pa->no[2]+= paf->randfac*(rng_getFloat(rng) - 0.5f); + } + + /* start speed: texture */ + if(mtex && paf->texfac!=0.0) { + particle_tex(mtex, paf, pa->co, pa->no); + } + + /* effectors here? */ + if(effectorbase) + precalc_effectors(ob, paf, pa, effectorbase); + + if(paf->totkey>1) deltalife= pa->lifetime/(paf->totkey-1); + else deltalife= pa->lifetime; + + /* longer lifetime results in longer distance covered */ + VecMulf(pa->no, deltalife); + + opa= pa; + pa++; + + for(b=1; btotkey; b++) { + + /* new time */ + pa->time= opa->time+deltalife; + cur_time = pa->time; + + /* set initial variables */ + VECCOPY(opco, opa->co); + VECCOPY(new_force, force); + VECCOPY(new_speed, opa->no); + VecMulf(new_speed, 1.0f/deltalife); + //new_speed[0] = new_speed[1] = new_speed[2] = 0.0f; + + /* handle differences between static (local coords, fixed frame) and dynamic */ + if(effectorbase) { + float loc_time= ((float)b)/(float)(paf->totkey-1); + + if(paf->flag & PAF_STATIC) { + float opco1[3], new_force1[3]; + + /* move co and force to global coords */ + VECCOPY(opco1, opco); + Mat4MulVecfl(ob->obmat, opco1); + VECCOPY(new_force1, new_force); + Mat4Mul3Vecfl(ob->obmat, new_force1); + Mat4Mul3Vecfl(ob->obmat, new_speed); + + cur_time = G.scene->r.cfra; + + /* force fields */ + pdDoEffectors(effectorbase, opco1, new_force1, new_speed, cur_time, loc_time, 0); + + /* move co, force and newspeed back to local */ + VECCOPY(opco, opco1); + Mat4MulVecfl(ob->imat, opco); + VECCOPY(new_force, new_force1); + Mat4Mul3Vecfl(ob->imat, new_force); + Mat4Mul3Vecfl(ob->imat, new_speed); + } + else { + /* force fields */ + pdDoEffectors(effectorbase, opco, new_force, new_speed, cur_time, loc_time, 0); + } + } + + /* new speed */ + pa->no[0]= deltalife * (new_speed[0] + new_force[0]); + pa->no[1]= deltalife * (new_speed[1] + new_force[1]); + pa->no[2]= deltalife * (new_speed[2] + new_force[2]); + + /* speed limitor */ + if((paf->flag & PAF_STATIC) && maxspeed!=0.0f) { + float len= VecLength(pa->no); + if(len > maxspeed) + VecMulf(pa->no, maxspeed/len); + } + + /* new location */ + pa->co[0]= opa->co[0] + pa->no[0]; + pa->co[1]= opa->co[1] + pa->no[1]; + pa->co[2]= opa->co[2] + pa->no[2]; + + /* Particle deflection code */ + if((paf->flag & PAF_STATIC)==0) { + deflection = 0; + finish_defs = 1; + def_count = 0; + + VECCOPY(opno, opa->no); + VECCOPY(npco, pa->co); + VECCOPY(npno, pa->no); + + life = deltalife; + cur_time -= deltalife; + + last_ob = -1; + last_fc = -1; + same_fc = 0; + + /* First call the particle deflection check for the particle moving */ + /* between the old co-ordinates and the new co-ordinates */ + /* If a deflection occurs, call the code again, this time between the */ + /* intersection point and the updated new co-ordinates */ + /* Bail out if we've done the calculation 10 times - this seems ok */ + /* for most scenes I've tested */ + while (finish_defs) { + deflected = pdDoDeflection(rng, opco, npco, opno, npno, life, new_force, + def_count, cur_time, ob->lay, + &last_ob, &last_fc, &same_fc); + if (deflected) { + def_count = def_count + 1; + deflection = 1; + if (def_count==10) finish_defs = 0; + } + else { + finish_defs = 0; + } + } + + /* Only update the particle positions and speed if we had a deflection */ + if (deflection) { + pa->co[0] = npco[0]; + pa->co[1] = npco[1]; + pa->co[2] = npco[2]; + pa->no[0] = npno[0]; + pa->no[1] = npno[1]; + pa->no[2] = npno[2]; + } + } + + /* speed: texture */ + if(mtex && paf->texfac!=0.0) { + particle_tex(mtex, paf, pa->co, pa->no); + } + if(damp!=1.0) { + pa->no[0]*= damp; + pa->no[1]*= damp; + pa->no[2]*= damp; + } + + opa= pa; + pa++; + /* opa is used later on too! */ + } + + if(deform) { + /* deform all keys */ + pa= part; + b= paf->totkey; + while(b--) { + calc_latt_deform(pa->co, 1.0f); + pa++; + } + } + + /* the big multiplication */ + if(depthmult[depth]!=0.0) { + + /* new 'child' emerges from an average 'mult' part from + the particles */ + damp = (float)nr; + rt1= (int)(damp*paf->mult[depth]); + rt2= (int)((damp+1.0)*paf->mult[depth]); + if(rt1!=rt2) { + + for(b=0; bchild[depth]; b++) { + pa= new_particle(paf); + *pa= *opa; + pa->lifetime= paf->life[depth]; + if(paf->randlife!=0.0) { + pa->lifetime*= 1.0f + paf->randlife*(rng_getFloat(rng) - 0.5f); + } + pa->mat_nr= paf->mat[depth]; + + make_particle_keys(rng, ob, depth+1, b, paf, pa, force, deform, mtex, effectorbase); + } + } + } +} + +static void init_mv_jit(float *jit, int num, int seed2) +{ + RNG *rng; + float *jit2, x, rad1, rad2, rad3; + int i, num2; + + if(num==0) return; + + rad1= (float)(1.0/sqrt((float)num)); + rad2= (float)(1.0/((float)num)); + rad3= (float)sqrt((float)num)/((float)num); + + rng = rng_new(31415926 + num + seed2); + x= 0; + num2 = 2 * num; + for(i=0; iseed); + int i, tot; + + if(paf->flag & PAF_TRAND) + tot= partnr; + else + tot= JIT_RAND; /* arbitrary... allows JIT_RAND times more particles in a face for jittered distro */ + + trands= MEM_callocN(2+2*tot*sizeof(float), "trands"); + for(i=0; iflag & PAF_TRAND)==0) { + jitlevel= paf->userjit; + + if(jitlevel == 0) { + jitlevel= partnr/subnr; + if(paf->flag & PAF_EDISTR) jitlevel*= 2; /* looks better in general, not very scietific */ + if(jitlevel<3) jitlevel= 3; + if(jitlevel>100) jitlevel= 100; + } + + jit= MEM_callocN(2+ jitlevel*2*sizeof(float), "jit"); + init_mv_jit(jit, jitlevel, paf->seed); + BLI_array_randomize(jit, 2*sizeof(float), jitlevel, paf->seed); /* for custom jit or even distribution */ + } + return; + } + + if(paf->flag & PAF_TRAND) { + u= trands[2*partnr]; + v= trands[2*partnr+1]; + } + else { + /* jittered distribution gets fixed random offset */ + if(subnr>=jitlevel) { + int jitrand= (subnr/jitlevel) % JIT_RAND; + + subnr %= jitlevel; + u= jit[2*subnr] + trands[2*jitrand]; + v= jit[2*subnr+1] + trands[2*jitrand+1]; + if(u > 1.0f) u-= 1.0f; + if(v > 1.0f) v-= 1.0f; + } + else { + u= jit[2*subnr]; + v= jit[2*subnr+1]; + } + } + + v1= (noco+(mface->v1))->co; + v2= (noco+(mface->v2))->co; + v3= (noco+(mface->v3))->co; + n1= (noco+(mface->v1))->no; + n2= (noco+(mface->v2))->no; + n3= (noco+(mface->v3))->no; + + if(mface->v4) { + float uv= u*v; + float muv= (1.0f-u)*(v); + float umv= (u)*(1.0f-v); + float mumv= (1.0f-u)*(1.0f-v); + + v4= (noco+(mface->v4))->co; + n4= (noco+(mface->v4))->no; + + co[0]= mumv*v1[0] + muv*v2[0] + uv*v3[0] + umv*v4[0]; + co[1]= mumv*v1[1] + muv*v2[1] + uv*v3[1] + umv*v4[1]; + co[2]= mumv*v1[2] + muv*v2[2] + uv*v3[2] + umv*v4[2]; + + no[0]= mumv*n1[0] + muv*n2[0] + uv*n3[0] + umv*n4[0]; + no[1]= mumv*n1[1] + muv*n2[1] + uv*n3[1] + umv*n4[1]; + no[2]= mumv*n1[2] + muv*n2[2] + uv*n3[2] + umv*n4[2]; + } + else { + /* mirror triangle uv coordinates when on other side */ + if(u + v > 1.0f) { + u= 1.0f-u; + v= 1.0f-v; + } + co[0]= v1[0] + u*(v3[0]-v1[0]) + v*(v2[0]-v1[0]); + co[1]= v1[1] + u*(v3[1]-v1[1]) + v*(v2[1]-v1[1]); + co[2]= v1[2] + u*(v3[2]-v1[2]) + v*(v2[2]-v1[2]); + + no[0]= n1[0] + u*(n3[0]-n1[0]) + v*(n2[0]-n1[0]); + no[1]= n1[1] + u*(n3[1]-n1[1]) + v*(n2[1]-n1[1]); + no[2]= n1[2] + u*(n3[2]-n1[2]) + v*(n2[2]-n1[2]); + } +} + + +/* Gets a MDeformVert's weight in group (0 if not in group) */ +/* note; this call could be in mesh.c or deform.c, but OK... it's in armature.c too! (ton) */ +static float vert_weight(MDeformVert *dvert, int group) +{ + MDeformWeight *dw; + int i; + + if(dvert) { + dw= dvert->dw; + for(i= dvert->totweight; i>0; i--, dw++) { + if(dw->def_nr == group) return dw->weight; + if(i==1) break; /*otherwise dw will point to somewhere it shouldn't*/ + } + } + return 0.0; +} + +/* Gets a faces average weight in a group, helper for below, face and weights are always set */ +static float face_weight(MFace *face, float *weights) +{ + float tweight; + + tweight = weights[face->v1] + weights[face->v2] + weights[face->v3]; + + if(face->v4) { + tweight += weights[face->v4]; + tweight /= 4.0; + } + else { + tweight /= 3.0; + } + + return tweight; +} + +/* helper function for build_particle_system() */ +static void make_weight_tables(PartEff *paf, Mesh *me, int totpart, VeNoCo *vertlist, int totvert, MFace *facelist, int totface, float **vweights, float **fweights) +{ + MFace *mface; + float *foweights=NULL, *voweights=NULL; + float totvweight=0.0f, totfweight=0.0f; + int a; + + if((paf->flag & PAF_FACE)==0) totface= 0; + + /* collect emitting vertices & faces if vert groups used */ + if(paf->vertgroup && me->dvert) { + + /* allocate weights array for all vertices, also for lookup of faces later on. note it's a malloc */ + *vweights= voweights= MEM_mallocN( totvert*sizeof(float), "pafvoweights" ); + totvweight= 0.0f; + for(a=0; advert+a, paf->vertgroup-1); + totvweight+= voweights[a]; + } + + if(totface) { + /* allocate weights array for faces, note it's a malloc */ + *fweights= foweights= MEM_mallocN(totface*sizeof(float), "paffoweights" ); + for(a=0, mface=facelist; aflag & PAF_EDISTR)) { + float maxfarea= 0.0f, curfarea; + + /* two cases for area distro, second case we already have group weights */ + if(foweights==NULL) { + /* allocate weights array for faces, note it's a malloc */ + *fweights= foweights= MEM_mallocN(totface*sizeof(float), "paffoweights" ); + + for(a=0, mface=facelist; av4) + curfarea= AreaQ3Dfl(vertlist[mface->v1].co, vertlist[mface->v2].co, vertlist[mface->v3].co, vertlist[mface->v4].co); + else + curfarea= AreaT3Dfl(vertlist[mface->v1].co, vertlist[mface->v2].co, vertlist[mface->v3].co); + if(curfarea>maxfarea) + maxfarea = curfarea; + foweights[a]= curfarea; + } + } + else { + for(a=0, mface=facelist; av4) + curfarea= AreaQ3Dfl(vertlist[mface->v1].co, vertlist[mface->v2].co, vertlist[mface->v3].co, vertlist[mface->v4].co); + else + curfarea= AreaT3Dfl(vertlist[mface->v1].co, vertlist[mface->v2].co, vertlist[mface->v3].co); + if(curfarea>maxfarea) + maxfarea = curfarea; + foweights[a]*= curfarea; + } + } + } + + /* normalize weights for max face area, calculate tot */ + if(maxfarea!=0.0f) { + maxfarea= 1.0f/maxfarea; + for(a=0; a< totface; a++) { + if(foweights[a]!=0.0) { + foweights[a] *= maxfarea; + totfweight+= foweights[a]; + } + } + } + } + else if(foweights) { + /* only add totfweight value */ + for(a=0; a< totface; a++) { + if(foweights[a]!=0.0) { + totfweight+= foweights[a]; + } + } + } + + /* if weight arrays, we turn these arrays into the amount of particles */ + if(totvert && voweights) { + float mult= (float)totpart/totvweight; + + for(a=0; a< totvert; a++) { + if(voweights[a]!=0.0) + voweights[a] *= mult; + } + } + + if(totface && foweights) { + float mult= (float)totpart/totfweight; + + for(a=0; a< totface; a++) { + if(foweights[a]!=0.0) + foweights[a] *= mult; + } + } +} + +/* helper function for build_particle_system() */ +static void make_length_tables(PartEff *paf, Mesh *me, int totvert, MFace *facelist, int totface, float **vlengths, float **flengths) +{ + MFace *mface; + float *folengths=NULL, *volengths=NULL; + int a; + + if((paf->flag & PAF_FACE)==0) totface= 0; + + /* collect emitting vertices & faces if vert groups used */ + if(paf->vertgroup_v && me->dvert) { + + /* allocate lengths array for all vertices, also for lookup of faces later on. note it's a malloc */ + *vlengths= volengths= MEM_mallocN( totvert*sizeof(float), "pafvolengths" ); + for(a=0; advert+a, paf->vertgroup_v-1); + } + + if(totface) { + /* allocate lengths array for faces, note it's a malloc */ + *flengths= folengths= MEM_mallocN(totface*sizeof(float), "paffolengths" ); + for(a=0, mface=facelist; aid.idnew! */ +/* error: this function changes ob->recalc of other objects... */ +static pMatrixCache *cache_object_matrices(Object *ob, int start, int end) +{ + pMatrixCache *mcache, *mc; + Group *group= NULL; + Object *obcopy; + Base *base; + float framelenold, cfrao, sfo; + + /* object can be linked in group... stupid exception */ + if(NULL==object_in_scene(ob, G.scene)) + group= find_group(ob); + + mcache= mc= MEM_mallocN( (end-start+1)*sizeof(pMatrixCache), "ob matrix cache"); + + framelenold= G.scene->r.framelen; + G.scene->r.framelen= 1.0f; + cfrao= G.scene->r.cfra; + sfo= ob->sf; + ob->sf= 0.0f; + + /* clear storage, copy recalc tag (bad loop) */ + for(obcopy= G.main->object.first; obcopy; obcopy= obcopy->id.next) { + obcopy->id.newid= NULL; + obcopy->recalco= obcopy->recalc; + obcopy->recalc= 0; + } + + /* all objects get tagged recalc that influence this object (does group too) */ + /* note that recalco has the real recalc tags, set by callers of this function */ + ob->recalc |= OB_RECALC_OB; /* make sure a recalc gets flushed */ + DAG_object_update_flags(G.scene, ob, -1); + + for(G.scene->r.cfra= start; G.scene->r.cfra<=end; G.scene->r.cfra++, mc++) { + + if(group) { + GroupObject *go; + + for(go= group->gobject.first; go; go= go->next) { + if(go->ob->recalc) { + where_is_object(go->ob); + + do_ob_key(go->ob); + if(go->ob->type==OB_ARMATURE) { + do_all_pose_actions(go->ob); // only does this object actions + where_is_pose(go->ob); + } + } + } + } + else { + for(base= G.scene->base.first; base; base= base->next) { + if(base->object->recalc) { + if(base->object->id.newid==NULL) + base->object->id.newid= MEM_dupallocN(base->object); + + where_is_object(base->object); + + do_ob_key(base->object); + if(base->object->type==OB_ARMATURE) { + do_all_pose_actions(base->object); // only does this object actions + where_is_pose(base->object); + } + } + } + } + Mat4CpyMat4(mc->obmat, ob->obmat); + Mat4Invert(ob->imat, ob->obmat); + Mat3CpyMat4(mc->imat, ob->imat); + Mat3Transp(mc->imat); + } + + /* restore */ + G.scene->r.cfra= cfrao; + G.scene->r.framelen= framelenold; + ob->sf= sfo; + + if(group) { + GroupObject *go; + + for(go= group->gobject.first; go; go= go->next) { + if(go->ob->recalc) { + where_is_object(go->ob); + + do_ob_key(go->ob); + if(go->ob->type==OB_ARMATURE) { + do_all_pose_actions(go->ob); // only does this object actions + where_is_pose(go->ob); + } + } + } + } + else { + for(base= G.scene->base.first; base; base= base->next) { + if(base->object->recalc) { + + if(base->object->id.newid) { + obcopy= (Object *)base->object->id.newid; + *(base->object) = *(obcopy); + MEM_freeN(obcopy); + base->object->id.newid= NULL; + } + + do_ob_key(base->object); + if(base->object->type==OB_ARMATURE) { + do_all_pose_actions(base->object); // only does this object actions + where_is_pose(base->object); + } + } + } + } + + /* copy recalc tag (bad loop) */ + for(obcopy= G.main->object.first; obcopy; obcopy= obcopy->id.next) + obcopy->recalc= obcopy->recalco; + + return mcache; +} + +/* for fluidsim win32 debug messages */ +#if defined(WIN32) && (!(defined snprintf)) +#define snprintf _snprintf +#endif + +/* main particle building function + one day particles should become dynamic (realtime) with the current method as a 'bake' (ton) */ +void build_particle_system(Object *ob) +{ + RNG *rng; + PartEff *paf; + Particle *pa; + Mesh *me; + Base *base; + MTex *mtexmove=0, *mtextime=0; + Material *ma; + MFace *facelist= NULL; + pMatrixCache *mcache=NULL, *mcnow, *mcprev; + ListBase *effectorbase; + VeNoCo *vertexcosnos; + double startseconds= PIL_check_seconds_timer(); + float ftime, dtime, force[3], vec[3], fac, co[3], no[3]; + float *voweights= NULL, *foweights= NULL, maxw=1.0f; + float *volengths= NULL, *folengths= NULL; + int deform=0, a, totpart, paf_sta, paf_end; + int waitcursor_set= 0, totvert, totface, curface, curvert; +#ifndef DISABLE_ELBEEM + int readMask, activeParts, fileParts; +#endif + + /* return conditions */ + if(ob->type!=OB_MESH) return; + me= ob->data; + + paf= give_parteff(ob); + if(paf==NULL) return; + + if(G.rendering==0 && paf->disp==0) return; + + if(paf->keys) MEM_freeN(paf->keys); /* free as early as possible, for returns */ + paf->keys= NULL; + + //printf("build particles\n"); + + /* fluid sim particle import handling, actual loading of particles from file */ + #ifndef DISABLE_ELBEEM + if( (1) && (ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) && // broken, disabled for now! + (ob->fluidsimSettings) && + (ob->fluidsimSettings->type == OB_FLUIDSIM_PARTICLE)) { + char *suffix = "fluidsurface_particles_#"; + char *suffix2 = ".gz"; + char filename[256]; + char debugStrBuffer[256]; + int curFrame = G.scene->r.cfra -1; // warning - sync with derived mesh fsmesh loading + int j, numFileParts; + gzFile gzf; + float vel[3]; + + if(ob==G.obedit) { // off... + paf->totpart = 0; // 1 or 0? + return; + } + + // ok, start loading + strcpy(filename, ob->fluidsimSettings->surfdataPath); + strcat(filename, suffix); + BLI_convertstringcode(filename, G.sce, curFrame); // fixed #frame-no + strcat(filename, suffix2); + + gzf = gzopen(filename, "rb"); + if (!gzf) { + snprintf(debugStrBuffer,256,"readFsPartData::error - Unable to open file for reading '%s' \n", filename); + //elbeemDebugOut(debugStrBuffer); + paf->totpart = 0; + return; + } + + gzread(gzf, &totpart, sizeof(totpart)); + numFileParts = totpart; + totpart = (G.rendering)?totpart:(paf->disp*totpart)/100; + paf->totpart= totpart; + paf->totkey= 1; + /* initialize particles */ + new_particle(paf); + ftime = 0.0; // unused... + + // set up reading mask + readMask = ob->fluidsimSettings->typeFlags; + activeParts=0; + fileParts=0; + + for(a=0; atime= ftime; + pa->lifetime= ftime + 10000.; // add large number to make sure they are displayed, G.scene->r.efra +1.0; + pa->co[0] = 0.0; + pa->co[1] = + pa->co[2] = 1.0*(float)a / (float)totpart; + pa->no[0] = pa->no[1] = pa->no[2] = 0.0; + pa->mat_nr= paf->omat; + gzread(gzf, &convertSize, sizeof( float )); + // convert range of 1.0-10.0 to shorts 1000-10000) + shsize = (short)(convertSize*1000.0); + pa->rt = shsize; + + for(j=0; j<3; j++) { + float wrf; + gzread(gzf, &wrf, sizeof( wrf )); + pa->co[j] = wrf; + //fprintf(stderr,"Rj%d ",j); + } + for(j=0; j<3; j++) { + float wrf; + gzread(gzf, &wrf, sizeof( wrf )); + vel[j] = wrf; + } + //if(a<25) fprintf(stderr,"FSPARTICLE debug set %s , a%d = %f,%f,%f , life=%f \n", filename, a, pa->co[0],pa->co[1],pa->co[2], pa->lifetime ); + } else { + // skip... + for(j=0; j<2*3+1; j++) { + float wrf; gzread(gzf, &wrf, sizeof( wrf )); + } + } + fileParts++; + } + gzclose( gzf ); + + totpart = paf->totpart = activeParts; + snprintf(debugStrBuffer,256,"readFsPartData::done - particles:%d, active:%d, file:%d, mask:%d \n", paf->totpart,activeParts,fileParts,readMask); + elbeemDebugOut(debugStrBuffer); + return; + } // fluid sim particles done + #endif // DISABLE_ELBEEM + + if(paf->end < paf->sta) return; + + if( (paf->flag & PAF_OFACE) && (paf->flag & PAF_FACE)==0) return; + + if(me->totvert==0) return; + + if(ob==G.obedit) return; + totpart= (G.rendering)?paf->totpart:(paf->disp*paf->totpart)/100; + if(totpart==0) return; + + /* No returns after this line! */ + + /* material */ + ma= give_current_material(ob, paf->omat); + if(ma) { + if(paf->speedtex) + mtexmove= ma->mtex[paf->speedtex-1]; + mtextime= ma->mtex[paf->timetex-1]; + } + + disable_speed_curve(1); /* check this... */ + + /* initialize particles */ + new_particle(paf); + + /* reset deflector cache, sumohandle is free, but its still sorta abuse... (ton) */ + for(base= G.scene->base.first; base; base= base->next) + base->object->sumohandle= NULL; + + /* all object positions from start to end */ + paf_sta= (int)floor(paf->sta); + paf_end= (int)ceil(paf->end); + if((paf->flag & PAF_STATIC)==0) + mcache= cache_object_matrices(ob, paf_sta, paf_end); + + /* mult generations? */ + for(a=0; amult[a]!=0.0) { + /* interesting formula! this way after 'x' generations the total is paf->totpart */ + totpart= (int)(totpart / (1.0+paf->mult[a]*paf->child[a])); + } + else break; + } + + /* for static particles, calculate system on current frame (? ton) */ + if(ma) do_mat_ipo(ma); + + /* matrix invert for static too */ + Mat4Invert(ob->imat, ob->obmat); + Mat4CpyMat4(paf->imat, ob->imat); /* used for duplicators */ + + /* new random generator */ + rng = rng_new(paf->seed); + + /* otherwise it goes way too fast */ + force[0]= paf->force[0]*0.05f; + force[1]= paf->force[1]*0.05f; + force[2]= paf->force[2]*0.05f; + + if( paf->flag & PAF_STATIC ) deform= 0; + else { + Object *parlatt= modifiers_isDeformedByLattice(ob); + if(parlatt) { + deform= 1; + init_latt_deform(parlatt, 0); + } + } + + /* get the effectors */ + effectorbase= pdInitEffectors(ob, paf->group); + + /* init geometry, return is 6 x float * me->totvert in size */ + vertexcosnos= (VeNoCo *)mesh_get_mapped_verts_nors(ob); + facelist= me->mface; + totvert= me->totvert; + totface= me->totface; + + /* if vertexweights or even distribution, it makes weight tables, also checks where it emits from */ + make_weight_tables(paf, me, totpart, vertexcosnos, totvert, facelist, totface, &voweights, &foweights); + + /* vertexweights can define lengths too */ + make_length_tables(paf, me, totvert, facelist, totface, &volengths, &folengths); + + /* now define where to emit from, if there are face weights we skip vertices */ + if(paf->flag & PAF_OFACE) totvert= 0; + if((paf->flag & PAF_FACE)==0) totface= 0; + if(foweights) totvert= 0; + + /* initialize give_mesh_particle_coord */ + if(totface) + give_mesh_particle_coord(paf, vertexcosnos, facelist, totpart, totface, NULL, NULL); + + /* correction for face timing when using weighted average */ + if(totface && foweights) { + maxw= (paf->end-paf->sta)/foweights[0]; + } + else if(totvert && voweights) { + maxw= (paf->end-paf->sta)/voweights[0]; + } + + /* for loop below */ + if (paf->flag & PAF_STATIC) { + ftime = G.scene->r.cfra; + dtime= 0.0f; + } else { + ftime= paf->sta; + dtime= (paf->end - paf->sta)/(float)totpart; + } + + curface= curvert= 0; + for(a=0; a 0.5) { + waitcursor(1); + waitcursor_set= 1; + } + } + + pa= new_particle(paf); + pa->time= ftime; + + /* get coordinates from faces, only when vertices set to zero */ + if(totvert==0 && totface) { + int curjit; + + /* use weight table, we have to do faces in order to be able to use jitter table... */ + if(foweights) { + + if(foweights[curface] < 1.0f) { + float remainder= 0.0f; + + while(remainder + foweights[curface] < 1.0f && curfaceend-paf->sta)/foweights[curface]; + } + + if(foweights[curface]==0.0f) + break; /* WARN skips here out of particle generating */ + else { + if(foweights[curface] >= 1.0f) /* note the >= here, this because of the < 1.0f above, it otherwise will stick to 1 face forever */ + foweights[curface] -= 1.0f; + + curjit= (int) foweights[curface]; + give_mesh_particle_coord(paf, vertexcosnos, facelist+curface, a, curjit, co, no); + + /* time correction to make particles appear evenly, maxw does interframe (0-1) */ + pa->time= paf->sta + maxw*foweights[curface]; + } + } + else { + curface= a % totface; + curjit= a/totface; + give_mesh_particle_coord(paf, vertexcosnos, facelist+curface, a, curjit, co, no); + } + } + /* get coordinates from vertices */ + if(totvert) { + /* use weight table */ + if(voweights) { + + if(voweights[curvert] < 1.0f) { + float remainder= 0.0f; + + while(remainder + voweights[curvert] < 1.0f && curvertend-paf->sta)/voweights[curvert]; + } + + if(voweights[curvert]==0.0f) + break; /* WARN skips here out of particle generating */ + else { + if(voweights[curvert] > 1.0f) + voweights[curvert] -= 1.0f; + + /* time correction to make particles appear evenly */ + pa->time= paf->sta + maxw*voweights[curvert]; + } + } + else { + curvert= a % totvert; + if(a >= totvert && totface) + totvert= 0; + } + + VECCOPY(co, vertexcosnos[curvert].co); + VECCOPY(no, vertexcosnos[curvert].no); + } + + VECCOPY(pa->co, co); + + /* dynamic options */ + if((paf->flag & PAF_STATIC)==0) { + int cur; + + /* particle retiming with texture */ + if(mtextime && (paf->flag2 & PAF_TEXTIME)) { + float tin, tr, tg, tb, ta, orco[3]; + + /* calculate normalized orco */ + orco[0] = (co[0]-me->loc[0])/me->size[0]; + orco[1] = (co[1]-me->loc[1])/me->size[1]; + orco[2] = (co[2]-me->loc[2])/me->size[2]; + externtex(mtextime, orco, &tin, &tr, &tg, &tb, &ta); + + if(paf->flag2neg & PAF_TEXTIME) + pa->time = paf->sta + (paf->end - paf->sta)*tin; + else + pa->time = paf->sta + (paf->end - paf->sta)*(1.0f-tin); + } + + /* set ob at correct time, we use cached matrices */ + cur= (int)floor(pa->time) + 1 ; /* + 1 has a reason: (obmat/prevobmat) otherwise comet-tails start too late */ + + if(cur <= paf_end) mcnow= mcache + cur - paf_sta; + else mcnow= mcache + paf_end - paf_sta; + + if(cur > paf_sta) mcprev= mcnow-1; + else mcprev= mcache; + + /* move to global space */ + Mat4MulVecfl(mcnow->obmat, pa->co); + + VECCOPY(vec, co); + Mat4MulVecfl(mcprev->obmat, vec); + + /* first start speed: object */ + VECSUB(pa->no, pa->co, vec); + + VecMulf(pa->no, paf->obfac); + + /* calculate the correct inter-frame */ + fac= (pa->time- (float)floor(pa->time)); + pa->co[0]= fac*pa->co[0] + (1.0f-fac)*vec[0]; + pa->co[1]= fac*pa->co[1] + (1.0f-fac)*vec[1]; + pa->co[2]= fac*pa->co[2] + (1.0f-fac)*vec[2]; + + /* start speed: normal */ + if(paf->normfac!=0.0) { + /* imat is transpose ! */ + VECCOPY(vec, no); + Mat3MulVecfl(mcnow->imat, vec); + + Normalize(vec); + VecMulf(vec, paf->normfac); + VECADD(pa->no, pa->no, vec); + } + } + else { + if(paf->normfac!=0.0) { + VECCOPY(pa->no, no); + Normalize(pa->no); + VecMulf(pa->no, paf->normfac); + } + } + + pa->lifetime= paf->lifetime; + if(paf->randlife!=0.0) { + pa->lifetime*= 1.0f + paf->randlife*(rng_getFloat(rng) - 0.5f); + } + pa->mat_nr= paf->omat; + + if(folengths) + pa->lifetime*= folengths[curface]; + + make_particle_keys(rng, ob, 0, a, paf, pa, force, deform, mtexmove, effectorbase); + } + + /* free stuff */ + give_mesh_particle_coord(NULL, NULL, NULL, 0, 0, NULL, NULL); + MEM_freeN(vertexcosnos); + if(voweights) MEM_freeN(voweights); + if(foweights) MEM_freeN(foweights); + if(volengths) MEM_freeN(volengths); + if(folengths) MEM_freeN(folengths); + if(mcache) MEM_freeN(mcache); + rng_free(rng); + + if(deform) end_latt_deform(); + + if(effectorbase) + pdEndEffectors(effectorbase); + + /* reset deflector cache */ + for(base= G.scene->base.first; base; base= base->next) { + if(base->object->sumohandle) { + + MEM_freeN(base->object->sumohandle); + base->object->sumohandle= NULL; + } + } + + disable_speed_curve(0); + + if(waitcursor_set) waitcursor(0); +} + diff --git a/source/blender/blenkernel/intern/exotic.c b/source/blender/blenkernel/intern/exotic.c new file mode 100644 index 00000000000..0f1f8c6078a --- /dev/null +++ b/source/blender/blenkernel/intern/exotic.c @@ -0,0 +1,4943 @@ +/* exotic.c + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): + * - Martin DeMello + * Added dxf_read_arc, dxf_read_ellipse and dxf_read_lwpolyline + * Copyright (C) 2004 by Etheract Software Labs + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + * eigen videoscape formaat: + * + * + * lamp: + * 3DG2 + aantal_lampen + + type + spsi spbl + r, g, b, energy + locx, locy, locz + vecx, vecy, vecz + + + curve / nurbs: + 3DG3 + 5 of 11 (curve of surf) + aantal_nurbs + extr1 extr2 + + mat[0][0] mat[0][1] mat[0][2] mat[0][3] + mat[1][0] mat[1][1] mat[1][2] mat[1][3] + ... + + type + pntsu, pntsv + resolu, resolv + orderu, orderv + flagu, flagv + + (als type==nurb) x y z w + x y z w + ... + (als type==bez) xyz xyz xyz h1 h2 h3 + xyz xyz xyz h1 h2 h3 + ... + * + * + */ + + +#include /* isdigit, isspace */ +#include +#include +#include +#include +#include + +#ifndef WIN32 +#include +#else +#include +#endif + +#include "MEM_guardedalloc.h" + +#include "DNA_object_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_material_types.h" +#include "DNA_lamp_types.h" +#include "DNA_curve_types.h" +#include "DNA_image_types.h" +#include "DNA_camera_types.h" +#include "DNA_scene_types.h" +#include "DNA_view3d_types.h" +#include "DNA_userdef_types.h" + +#include "BKE_bad_level_calls.h" +#include "BKE_utildefines.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_editVert.h" + +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_mesh.h" +#include "BKE_library.h" +#include "BKE_global.h" +#include "BKE_object.h" +#include "BKE_material.h" +#include "BKE_exotic.h" +/* #include "BKE_error.h" */ +#include "BKE_screen.h" +#include "BKE_displist.h" +#include "BKE_DerivedMesh.h" +#include "BKE_curve.h" +#include "BKE_customdata.h" + +#include "BPY_extern.h" + +#include "blendef.h" + +#include "zlib.h" + +static int is_dxf(char *str); +static void dxf_read(char *filename); +static int is_stl(char *str); + +static int is_stl_ascii(char *str) +{ + FILE *fpSTL; + char buffer[1000]; + int numread, i; + + fpSTL = fopen(str, "rb"); + if ( (numread = fread( (void *) buffer, sizeof(char), 1000, fpSTL)) <= 0 ) + { fclose(fpSTL); return 0; } + + for (i=0; i < numread; ++i) { + /* if bit 8 is set we assume binary */ + if (buffer[i] & 0x80) + { fclose(fpSTL); return 0; } + } + + buffer[5] = '\0'; + if ( !(strstr(buffer, "solid")) && !(strstr(buffer, "SOLID")) ) + { fclose(fpSTL); return 0; } + + fclose(fpSTL); + + return 1; +} + +static int is_stl(char *str) +{ + int i; + i = strlen(str) - 3; + if ( (str[i] !='s') && (str[i] !='S')) + return 0; + i++; + if ( (str[i] !='t') && (str[i] !='T')) + return 0; + i++; + if ( (str[i] !='l') && (str[i] !='L')) + return 0; + + return 1; +} + +#define READSTLVERT { \ + if (fread(mvert->co, sizeof(float), 3, fpSTL) != 3) { \ + char error_msg[255]; \ + MEM_freeN(vertdata); \ + MEM_freeN(facedata); \ + fclose(fpSTL); \ + sprintf(error_msg, "Problems reading face %d!", i); \ + error(error_msg); \ + return; \ + } \ + else { \ + if (G.order==B_ENDIAN) { \ + SWITCH_INT(mvert->co[0]); \ + SWITCH_INT(mvert->co[1]); \ + SWITCH_INT(mvert->co[2]); \ + } \ + } \ +} + +static void simple_vertex_normal_blend(short *no, short *ble) +{ + if(no[0]==0 && no[1]==0 && no[2]==0) { + VECCOPY(no, ble); + } + else { + no[0]= (2*no[0] + ble[0])/3; + no[1]= (2*no[1] + ble[1])/3; + no[2]= (2*no[2] + ble[2])/3; + } +} + +static void mesh_add_normals_flags(Mesh *me) +{ + MVert *v1, *v2, *v3, *v4; + MFace *mface; + float nor[3]; + int a; + short sno[3]; + + mface= me->mface; + for(a=0; atotface; a++, mface++) { + v1= me->mvert+mface->v1; + v2= me->mvert+mface->v2; + v3= me->mvert+mface->v3; + v4= me->mvert+mface->v4; + + CalcNormFloat(v1->co, v2->co, v3->co, nor); + sno[0]= 32767.0*nor[0]; + sno[1]= 32767.0*nor[1]; + sno[2]= 32767.0*nor[2]; + + simple_vertex_normal_blend(v1->no, sno); + simple_vertex_normal_blend(v2->no, sno); + simple_vertex_normal_blend(v3->no, sno); + if(mface->v4) { + simple_vertex_normal_blend(v4->no, sno); + } + mface->edcode= ME_V1V2|ME_V2V3; + } +} + +static void read_stl_mesh_binary(char *str) +{ + FILE *fpSTL; + Object *ob; + Mesh *me; + MVert *mvert, *vertdata; + MFace *mface, *facedata; + unsigned int numfacets = 0, i, j, vertnum; + unsigned int maxmeshsize, nummesh, lastmeshsize; + unsigned int totvert, totface; + + fpSTL= fopen(str, "rb"); + if(fpSTL==NULL) { + error("Can't read file"); + return; + } + + fseek(fpSTL, 80, SEEK_SET); + fread(&numfacets, 4*sizeof(char), 1, fpSTL); + if (G.order==B_ENDIAN) { + SWITCH_INT(numfacets); + } + + maxmeshsize = MESH_MAX_VERTS/3; + + nummesh = (numfacets / maxmeshsize) + 1; + lastmeshsize = numfacets % maxmeshsize; + + if (numfacets) { + for (j=0; j < nummesh; ++j) { + /* new object */ + if (j == nummesh-1) { + totface = lastmeshsize; + } + else { + totface = maxmeshsize; + } + totvert = 3 * totface; + + vertdata = MEM_callocN(totvert*sizeof(MVert), "mverts"); + facedata = MEM_callocN(totface*sizeof(MFace), "mface"); + + vertnum = 0; + mvert= vertdata; + mface = facedata; + for (i=0; i < totface; i++) { + fseek(fpSTL, 12, SEEK_CUR); /* skip the face normal */ + READSTLVERT; + mvert++; + READSTLVERT; + mvert++; + READSTLVERT; + mvert++; + + mface->v1 = vertnum++; + mface->v2 = vertnum++; + mface->v3 = vertnum++; + mface++; + + fseek(fpSTL, 2, SEEK_CUR); + } + + ob= add_object(OB_MESH); + me= ob->data; + me->totvert = totvert; + me->totface = totface; + me->mvert = CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, + vertdata, totvert); + me->mface = CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, + facedata, totface); + + mesh_add_normals_flags(me); + make_edges(me, 0); + } + waitcursor(1); + } + fclose(fpSTL); + +} +#undef READSTLVERT + +#define STLALLOCERROR { \ + char error_msg[255]; \ + fclose(fpSTL); \ + sprintf(error_msg, "Can't allocate storage for %d faces!", \ + numtenthousand * 10000); \ + error(error_msg); \ + return; \ +} + +#define STLBAILOUT(message) { \ + char error_msg[255]; \ + fclose(fpSTL); \ + free(vertdata); \ + sprintf(error_msg, "Line %d: %s", linenum, message); \ + error(message); \ + return; \ +} + +#define STLREADLINE { \ + if (!fgets(buffer, 2048, fpSTL)) STLBAILOUT("Can't read line!"); \ + linenum++; \ +} + +#define STLREADVERT { \ + STLREADLINE; \ + if ( !(cp = strstr(buffer, "vertex")) && \ + !(cp = strstr(buffer, "VERTEX")) ) STLBAILOUT("Bad vertex!"); \ + vp = vertdata + 3 * totvert; \ + if (sscanf(cp + 6, "%f %f %f", vp, vp+1, vp+2) != 3) \ + STLBAILOUT("Bad vertex!"); \ + ++totvert; \ +} +static void read_stl_mesh_ascii(char *str) +{ + FILE *fpSTL; + char buffer[2048], *cp; + Object *ob; + Mesh *me; + MVert *mvert; + MFace *mface; + float *vertdata, *vp; + unsigned int numtenthousand, linenum; + unsigned int i, vertnum; + unsigned int totvert, totface; + + /* ASCII stl sucks ... we don't really know how many faces there + are until the file is done, so lets allocate faces 10000 at a time */ + + fpSTL= fopen(str, "r"); + if(fpSTL==NULL) { + error("Can't read file"); + return; + } + + /* we'll use the standard malloc/realloc for now ... + * lets allocate enough storage to hold 10000 triangles, + * i.e. 30000 verts, i.e., 90000 floats. + */ + numtenthousand = 1; + vertdata = malloc(numtenthousand*3*30000*sizeof(float)); // uses realloc! + if (!vertdata) STLALLOCERROR; + + linenum = 1; + /* Get rid of the first line */ + STLREADLINE; + + totvert = 0; + totface = 0; + while(1) { + /* Read in the next line */ + STLREADLINE; + + /* lets check if this is the end of the file */ + if ( strstr(buffer, "endsolid") || strstr(buffer, "ENDSOLID") ) + break; + + /* Well, guess that wasn't the end, so lets make + * sure we have enough storage for some more faces + */ + if ( (totface) && ( (totface % 10000) == 0 ) ) { + ++numtenthousand; + vertdata = realloc(vertdata, + numtenthousand*3*30000*sizeof(float)); + if (!vertdata) STLALLOCERROR; + } + + /* Don't read normal, but check line for proper syntax anyway + */ + if ( !(cp = strstr(buffer, "facet")) && + !(cp = strstr(buffer, "FACET")) ) STLBAILOUT("Bad normal line!"); + if ( !(strstr(cp+5, "normal")) && + !(strstr(cp+5, "NORMAL")) ) STLBAILOUT("Bad normal line!"); + + /* Read in what should be the outer loop line + */ + STLREADLINE; + if ( !(cp = strstr(buffer, "outer")) && + !(cp = strstr(buffer, "OUTER")) ) STLBAILOUT("Bad outer loop!"); + if ( !(strstr(cp+5, "loop")) && + !(strstr(cp+5, "LOOP")) ) STLBAILOUT("Bad outer loop!"); + + /* Read in the face */ + STLREADVERT; + STLREADVERT; + STLREADVERT; + + /* Read in what should be the endloop line + */ + STLREADLINE; + if ( !strstr(buffer, "endloop") && !strstr(buffer, "ENDLOOP") ) + STLBAILOUT("Bad endloop!"); + + /* Read in what should be the endfacet line + */ + STLREADLINE; + if ( !strstr(buffer, "endfacet") && !strstr(buffer, "ENDFACET") ) + STLBAILOUT("Bad endfacet!"); + + /* Made it this far? Increment face count */ + ++totface; + } + fclose(fpSTL); + + /* OK, lets create our mesh */ + ob = add_object(OB_MESH); + me = ob->data; + + me->totface = totface; + me->totvert = totvert; + me->mvert = CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, + NULL, totvert); + me->mface = CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, + NULL, totface); + + /* Copy vert coords and create topology */ + mvert = me->mvert; + mface = me->mface; + vertnum = 0; + for (i=0; i < totface; ++i) { + memcpy(mvert->co, vertdata+3*vertnum, 3*sizeof(float) ); + mface->v1 = vertnum; + mvert++; + vertnum++; + + memcpy(mvert->co, vertdata+3*vertnum, 3*sizeof(float) ); + mface->v2 = vertnum; + mvert++; + vertnum++; + + memcpy(mvert->co, vertdata+3*vertnum, 3*sizeof(float) ); + mface->v3 = vertnum; + mvert++; + vertnum++; + + mface++; + } + free(vertdata); + + mesh_add_normals_flags(me); + make_edges(me, 0); + + waitcursor(1); +} + +#undef STLALLOCERROR +#undef STLBAILOUT +#undef STLREADLINE +#undef STLREADVERT + +static void read_videoscape_mesh(char *str) +{ + Object *ob; + Mesh *me; + MVert *mvert; + MFace *mface; + Material *ma; + FILE *fp; + float *vertdata, *vd, min[3], max[3], cent[3], ftemp; + unsigned int color[32], col; + int totcol, a, b, verts, tottria=0, totquad=0, totedge=0, poly, nr0, nr, first; + int end; + char s[50]; + + fp= fopen(str, "rb"); + if(fp==NULL) { + error("Can't read file"); + return; + } + + fscanf(fp, "%40s", s); + + fscanf(fp, "%d\n", &verts); + if(verts<=0) { + fclose(fp); + error("Read error"); + return; + } + + if(verts>MESH_MAX_VERTS) { + error("too many vertices"); + fclose(fp); + return; + } + + INIT_MINMAX(min, max); + vd= vertdata= MEM_mallocN(sizeof(float)*3*verts, "videoscapelezer"); + + for(a=0; a0) { + end= fscanf(fp,"%d", &poly); + if(end<=0) break; + + if(poly==3) tottria++; + else if(poly==4) totquad++; + else totedge+= poly; + + for(a=0;a=totcol && totcol<32) { + color[totcol]= col; + totcol++; + } + } + + /* new object */ + ob= add_object(OB_MESH); + me= ob->data; + me->totvert= verts; + me->totface= totedge+tottria+totquad; + + me->mvert= CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, + NULL, me->totvert); + me->mface= CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, + NULL, me->totface); + + /* colors */ + if(totcol) { + ob->mat= MEM_callocN(sizeof(void *)*totcol, "ob->mat"); + me->mat= MEM_callocN(sizeof(void *)*totcol, "me->mat"); + me->totcol= totcol; + ob->totcol= (unsigned char) me->totcol; + ob->actcol= 1; + } + + /* materials */ + for(a=0; amat.first; + while(ma) { + if(ma->mtex[0]==0) { + col= rgb_to_cpack(ma->r, ma->g, ma->b); + if(color[a]==col) { + me->mat[a]= ma; + ma->id.us++; + break; + } + } + ma= ma->id.next; + } + if(ma==0) { + ma= add_material("ext"); + me->mat[a]= ma; + cpack_to_rgb(color[a], cent, cent+1, cent+2); + ma->r= cent[0]; + ma->g= cent[1]; + ma->b= cent[2]; + automatname(ma); + } + } + + /* verts */ + + cent[0]= (min[0]+max[0])/2.0f; + cent[1]= (min[1]+max[1])/2.0f; + cent[2]= (min[2]+max[2])/2.0f; + VECCOPY(ob->loc, cent); + + a= me->totvert; + vd= vertdata; + mvert= me->mvert; + while(a--) { + VecSubf(mvert->co, vd, cent); + mvert++; + vd+= 3; + } + + /* faces */ + if(me->totface) { + rewind(fp); + + fscanf(fp, "%40s", s); + fscanf(fp, "%d\n", &verts); + /* fake read */ + for(a=0;atotface; + mface= me->mface; + while(a--) { + end= fscanf(fp,"%d", &poly); + if(end<=0) break; + + if(poly==3 || poly==4) { + fscanf(fp,"%d", &nr); + mface->v1= MIN2(nr, me->totvert-1); + fscanf(fp,"%d", &nr); + mface->v2= MIN2(nr, me->totvert-1); + fscanf(fp,"%d", &nr); + mface->v3= MIN2(nr, me->totvert-1); + if(poly==4) { + if( fscanf(fp,"%d", &nr) <=0 ) break; + mface->v4= MIN2(nr, me->totvert-1); + } + + test_index_face(mface, NULL, 0, poly); + + mface++; + } + else { + if( fscanf(fp,"%d", &nr0) <=0) break; + first= nr0; + for(b=1; btotvert-1); + mface->v1= nr; + mface->v2= nr0; + nr0= nr; + mface++; + a--; + } + mface->v1= first; + mface->v2= nr; + mface++; + if(end<=0) break; + } + end= fscanf(fp,"%i", &col); + col &= 0xF0F0F0; + if(end<=0) break; + + for(b=0; bmat_nr= b; + break; + } + } + } + } + + fclose(fp); + MEM_freeN(vertdata); + + mesh_add_normals_flags(me); + make_edges(me, 0); + + waitcursor(1); +} + +static void read_radiogour(char *str) +{ + Object *ob; + Mesh *me; + MVert *mvert; + MFace *mface; + FILE *fp; + float *vertdata, *vd, min[3], max[3], cent[3], ftemp; + unsigned int *colv, *colf, *colvertdata; + int itemp, a, b, verts, tottria=0, totquad=0, totedge=0, poly, nr0, nr, first; + int end; + char s[50]; + + fp= fopen(str, "rb"); + if(fp==NULL) { + error("Can't read file"); + return; + } + + fscanf(fp, "%40s", s); + + fscanf(fp, "%d\n", &verts); + if(verts<=0) { + fclose(fp); + error("Read error"); + return; + } + + if(verts>MESH_MAX_VERTS) { + error("too many vertices"); + fclose(fp); + return; + } + + INIT_MINMAX(min, max); + vd= vertdata= MEM_mallocN(sizeof(float)*3*verts, "videoscapelezer"); + colv= colvertdata= MEM_mallocN(verts*sizeof(float), "coldata"); + + for(a=0; a0) { + end= fscanf(fp,"%d", &poly); + if(end<=0) break; + + if(poly==3) tottria++; + else if(poly==4) totquad++; + else totedge+= poly; + + for(a=0;aMESH_MAX_VERTS) { + printf(" var1: %d, var2: %d, var3: %d \n", totedge, tottria, totquad); + error("too many faces"); + MEM_freeN(vertdata); + MEM_freeN(colvertdata); + fclose(fp); + return; + } + + /* new object */ + ob= add_object(OB_MESH); + me= ob->data; + me->totvert= verts; + me->totface= totedge+tottria+totquad; + me->flag= 0; + + me->mvert= CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, + NULL, me->totvert); + me->mface= CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, + NULL, me->totface); + + /* verts */ + + cent[0]= (min[0]+max[0])/2.0f; + cent[1]= (min[1]+max[1])/2.0f; + cent[2]= (min[2]+max[2])/2.0f; + VECCOPY(ob->loc, cent); + + a= me->totvert; + vd= vertdata; + mvert= me->mvert; + while(a--) { + VecSubf(mvert->co, vd, cent); + mvert++; + vd+= 3; + } + + /* faces */ + if(me->totface) { + rewind(fp); + + fscanf(fp, "%40s", s); + fscanf(fp, "%d\n", &verts); + for(a=0;atotface; + mface= me->mface; + while(a--) { + end= fscanf(fp,"%d", &poly); + if(end<=0) break; + + if(poly==3 || poly==4) { + fscanf(fp,"%d", &nr); + mface->v1= MIN2(nr, me->totvert-1); + fscanf(fp,"%d", &nr); + mface->v2= MIN2(nr, me->totvert-1); + fscanf(fp,"%d", &nr); + mface->v3= MIN2(nr, me->totvert-1); + if(poly==4) { + if( fscanf(fp,"%d", &nr) <=0 ) break; + mface->v4= MIN2(nr, me->totvert-1); + } + + test_index_face(mface, NULL, 0, poly); + + mface++; + } + else { + if( fscanf(fp,"%d", &nr0) <=0) break; + first= nr0; + for(b=1; btotvert-1); + mface->v1= nr; + mface->v2= nr0; + nr0= nr; + mface++; + a--; + } + mface->v1= first; + mface->v2= nr; + mface->flag= ME_SMOOTH; + + mface++; + if(end<=0) break; + } + } + + /* mcol is 4 colors per face */ + me->mcol= MEM_mallocN(4*sizeof(int)*me->totface, "mcol"); + colf= (unsigned int *)me->mcol; + + a= me->totface; + mface= me->mface; + while(a--) { + + colf[0]= colvertdata[mface->v1]; + colf[1]= colvertdata[mface->v2]; + colf[2]= colvertdata[mface->v3]; + colf[3]= colvertdata[mface->v4]; + + colf+= 4; + mface++; + } + + MEM_freeN(colvertdata); + } + + fclose(fp); + MEM_freeN(vertdata); + + mesh_add_normals_flags(me); + make_edges(me, 0); + + waitcursor(1); +} + + +static void read_videoscape_lamp(char *str) +{ + Object *ob; + Lamp *la; + FILE *fp; + float vec[3], *q1; + int tot, val; + char s[50]; + + fp= fopen(str, "rb"); + if(fp==NULL) { + error("Can't read file"); + return; + } + + fscanf(fp, "%40s", s); + fscanf(fp, "%d\n", &tot); + + while(tot--) { + ob= add_object(OB_LAMP); + la= ob->data; + + fscanf(fp, "%d\n", &val); + la->type= val; + if(la->type==1) la->type= LA_SPOT; + else if(la->type==2) la->type= LA_SUN; + + fscanf(fp, "%f %f\n", &la->spotsize, &la->spotblend); + + fscanf(fp, "%f %f %f %f\n", &la->r, &la->g, &la->b, &la->energy); + + fscanf(fp, "%f %f %f\n", ob->loc, ob->loc+1, ob->loc+2); + val= fscanf(fp, "%f %f %f\n", vec, vec+1, vec+2); + q1= vectoquat(vec, 5, 2); + QuatToEul(q1, ob->rot); + + if(val<=0) break; + + } + fclose(fp); +} + +static void read_videoscape_nurbs(char *str) +{ + Object *ob; + Curve *cu; + Nurb *nu; + BezTriple *bezt; + BPoint *bp; + FILE *fp; + float tmat[4][4], omat[3][3], imat[3][3], mat[3][3]; + int a, tot, type, val; + char s[50]; + + fp= fopen(str, "rb"); + if(fp==NULL) { + error("Can't read file"); + return; + } + + fscanf(fp, "%40s", s); + fscanf(fp, "%d\n", &type); + + if(type==5) ob= add_object(OB_SURF); + else ob= add_object(OB_CURVE); + cu= ob->data; + + fscanf(fp, "%d\n", &tot); + fscanf(fp, "%d %d\n", &type, &val); + + cu->ext1= 0.002f*type; + cu->ext2= 0.002f*val; + + for(a=0; a<4; a++) fscanf(fp, "%e %e %e %e\n", tmat[a], tmat[a]+1, tmat[a]+2, tmat[a]+3); + + VECCOPY(ob->loc, tmat[3]); + + Mat3CpyMat4(omat, tmat); + Mat3ToEul(omat, ob->rot); + EulToMat3(ob->rot, mat); + Mat3Inv(imat, mat); + Mat3MulMat3((float ( * )[3])tmat, imat, omat); + + while(tot--) { + nu= (Nurb*)MEM_callocN(sizeof(Nurb),"nu from exotic"); + BLI_addtail(&cu->nurb, nu); + + fscanf(fp, "%d\n", &type); + nu->type= type; + + fscanf(fp, "%d %d\n", &type, &val); + nu->pntsu= type; nu->pntsv= val; + fscanf(fp, "%d %d\n", &type, &val); + nu->resolu= type; nu->resolv= val; + fscanf(fp, "%d %d\n", &type, &val); + nu->orderu= type; nu->orderv= val; + fscanf(fp, "%d %d\n", &type, &val); + nu->flagu= type; nu->flagv= val; + + if( (nu->type & 7)==CU_BEZIER) { + a= nu->pntsu; + nu->bezt= bezt= MEM_callocN(a*sizeof(BezTriple), "bezt from exotic"); + while(a--) { + fscanf(fp, "%f %f %f ", bezt->vec[0], bezt->vec[0]+1, bezt->vec[0]+2); + Mat4MulVecfl(tmat, bezt->vec[0]); + fscanf(fp, "%f %f %f ", bezt->vec[1], bezt->vec[1]+1, bezt->vec[1]+2); + Mat4MulVecfl(tmat, bezt->vec[1]); + fscanf(fp, "%f %f %f ", bezt->vec[2], bezt->vec[2]+1, bezt->vec[2]+2); + Mat4MulVecfl(tmat, bezt->vec[2]); + fscanf(fp, "%d %d\n", &type, &val); + bezt->h1= type; + bezt->h2= val; + bezt++; + } + } + else { + a= nu->pntsu*nu->pntsv; + if(a) { + nu->bp= bp= MEM_callocN(a*sizeof(BPoint), "bp from exotic"); + while(a--) { + fscanf(fp, "%f %f %f %f\n", bp->vec, bp->vec+1, bp->vec+2, bp->vec+3); + Mat4MulVecfl(tmat, bp->vec); + bp++; + } + + val= KNOTSU(nu); + nu->knotsu= MEM_mallocN(sizeof(float)*val, "knots"); + for(a=0; aknotsu+a); + + if(nu->pntsv>1) { + val= KNOTSV(nu); + nu->knotsv= MEM_mallocN(sizeof(float)*val, "knots"); + for(a=0; aknotsv+a); + } + } + else { + BLI_remlink(&cu->nurb, nu); + MEM_freeN(nu); + } + } + } + fclose(fp); +} + +static void read_videoscape(char *str) +{ + int file, type; + unsigned int val; + unsigned short numlen; + char name[FILE_MAXDIR+FILE_MAXFILE], head[FILE_MAXDIR+FILE_MAXFILE], tail[FILE_MAXFILE]; + + strcpy(name, str); + + while( TRUE ) { + file= open(name, O_BINARY|O_RDONLY); + if(file<=0) break; + else { + read(file, &type, 4); + close(file); + + if(type==DDG1) read_videoscape_mesh(name); + else if(type==DDG2) read_videoscape_lamp(name); + else if(type==DDG3) read_videoscape_nurbs(name); + } + + val = BLI_stringdec(name, head, tail, &numlen); + BLI_stringenc(name, head, tail, numlen, val + 1); + + } +} + + +/* ***************** INVENTOR ******************* */ + + +#define IV_MAXSTACK 3000000 +#define IV_MAXFIELD 10 +#define IV_MAXCOL 16 + +static float *iv_data_stack; +static float ivcolors[IV_MAXCOL][3]; +static Object *ivsurf; +static ListBase ivbase; + +struct IvNode { + struct IvNode *next, *prev; + char *nodename; + char *fieldname[IV_MAXFIELD]; + int datalen[IV_MAXFIELD]; + float *data[IV_MAXFIELD]; +}; + +static int iv_curcol=0; + +static int iv_colornumber(struct IvNode *iv) +{ + float *fp, fr = 0.0, fg = 0.0, fb = 0.0; + int a; + char *cp; + + /* search back to last material */ + while(iv) { + if( strcmp(iv->nodename, "Material")==0) { + fp= iv->data[0]; + if(fp==0) fp= iv->data[1]; + if(fp) { + fr= fp[0]; + fg= fp[1]; + fb= fp[2]; + } + break; + } + else if( strcmp(iv->nodename, "BaseColor")==0) { + fp= iv->data[0]; + fr= fp[0]; + fg= fp[1]; + fb= fp[2]; + break; + } + else if( strcmp(iv->nodename, "PackedColor")==0) { + cp= (char *)iv->data[0]; + fr= cp[3]/255.0f; + fg= cp[2]/255.0f; + fb= cp[1]/255.0f; + break; + } + iv= iv->prev; + + } + if(iv==0) return 0; + if(iv->datalen[0]<3) return 0; + + for(a=0; a=IV_MAXCOL) a= IV_MAXCOL-1; + iv_curcol= a+1; + ivcolors[a][0]= fr; + ivcolors[a][1]= fg; + ivcolors[a][2]= fb; + + return iv_curcol; +} + +static int iv_finddata(struct IvNode *iv, char *field, int fieldnr) +{ + /* search for "field", count data size and make datablock. return skipdata */ + float *fp; + int len, stackcount, skipdata=0; + char *cpa, terminator, str[64]; + long i; + + len= strlen(field); + + cpa= iv->nodename+1; + while( *cpa != '}' ) { + + if( *cpa == *field ) { + if( strncmp(cpa, field, len)==0 ) { + iv->fieldname[fieldnr]= cpa; + + /* read until first character */ + cpa+= len; + skipdata+= len; + *cpa= 0; + cpa++; + skipdata++; + + while( *cpa==32 || *cpa==13 || *cpa==10 || *cpa==9) cpa++; + if( *cpa=='[' ) { + terminator= ']'; + cpa++; + skipdata++; + } + else terminator= 13; + + stackcount= 0; + fp= iv_data_stack; + + while( *cpa!=terminator && *cpa != '}' ) { + + /* in fact, isdigit should include the dot and minus */ + if( (isdigit(*cpa) || *cpa=='.' || *cpa=='-') && (isspace(cpa[-1]) || cpa[-1]==0 || cpa[-1]==',') ) { + if(cpa[1]=='x') { + memcpy(str, cpa, 16); + str[16]= 0; + + sscanf(str, "%x", (int *)fp); + } + else { + /* atof doesn't stop after the first float + * in a long string at Windows... so we copy + * the float to a new string then atof... */ + char *cpa_temp = strpbrk(cpa, ", \n"); + i = cpa_temp - cpa; + + if (i>63) *fp= 0.0; + else { + memcpy(str, cpa, i); + str[i]=0; + + *fp= (float) atof(str); + } + } + + stackcount++; + if(stackcount>=IV_MAXSTACK) { + printf("stackoverflow in IV read\n"); + break; + } + fp++; + } + cpa++; + skipdata++; + } + + iv->datalen[fieldnr]= stackcount; + if(stackcount) { + iv->data[fieldnr]= MEM_mallocN(sizeof(float)*stackcount, "iv_finddata"); + memcpy(iv->data[fieldnr], iv_data_stack, sizeof(float)*stackcount); + } + else iv->data[fieldnr]= 0; + + return skipdata; + } + } + cpa++; + skipdata++; + } + + return skipdata; +} + +static void read_iv_index(float *data, float *baseadr, float *index, int nr, int coordtype) +{ + /* write in data: baseadr with offset index (and number nr) */ + float *fp; + int ofs; + + while(nr--) { + ofs= (int) *index; + fp= baseadr+coordtype*ofs; + VECCOPY(data, fp); + data+= 3; + index++; + } +} + + + +static void read_inventor(char *str, struct ListBase *listb) +{ + struct IvNode *iv, *ivp, *ivn; + char *maindata, *md, *cpa; + float *index, *data, *fp; + int file, filelen, count, lll, face, nr = 0; + int skipdata, ok, a, b, tot, first, colnr, coordtype, polytype, *idata; + struct DispList *dl; + + ivbase.first= ivbase.last= 0; + iv_curcol= 0; + ivsurf= 0; + + file= open(str, O_BINARY|O_RDONLY); + if(file== -1) { + error("Can't read file\n"); + return; + } + + filelen= BLI_filesize(file); + if(filelen < 1) { + close(file); + return; + } + + maindata= MEM_mallocN(filelen, "leesInventor"); + read(file, maindata, filelen); + close(file); + + iv_data_stack= MEM_mallocN(sizeof(float)*IV_MAXSTACK, "ivstack"); + + /* preprocess: remove comments */ + md= maindata+20; + count= 20; + while(count=filelen) break; + } + } + md++; + count++; + } + + + /* now time to collect: which are the nodes and fields? */ + md= maindata; + count= 0; + while(count32 && *cpa<128) cpa--; + cpa++; + *md= 0; + + ok= 0; + skipdata= 0; + iv= MEM_callocN(sizeof(struct IvNode), "leesInventor"); + iv->nodename= cpa; + + if(strcmp(cpa, "Coordinate3")==0 || strcmp(cpa, "Coordinate4")==0) { + skipdata= iv_finddata(iv, "point", 0); + ok= 1; + } + else if(strcmp(cpa, "VertexProperty")==0) { + skipdata= iv_finddata(iv, "vertex", 0); + ok= 1; + } + else if(strcmp(cpa, "IndexedLineSet")==0) { + skipdata= iv_finddata(iv, "coordIndex", 0); + ok= 1; + } + else if(strcmp(cpa, "IndexedTriangleMesh")==0) { + skipdata= iv_finddata(iv, "coordIndex", 0); + ok= 1; + } + else if(strcmp(cpa, "IndexedFaceSet")==0) { + skipdata= iv_finddata(iv, "coordIndex", 0); + ok= 1; + } + else if(strcmp(cpa, "FaceSet")==0) { + skipdata= iv_finddata(iv, "numVertices", 0); + ok= 1; + } + else if(strcmp(cpa, "Material")==0) { + iv_finddata(iv, "diffuseColor", 0); + iv_finddata(iv, "ambientColor", 1); + ok= 1; + } + else if(strcmp(cpa, "BaseColor")==0) { + iv_finddata(iv, "rgb", 0); + ok= 1; + } + else if(strcmp(cpa, "PackedColor")==0) { + iv_finddata(iv, "rgba", 0); + ok= 1; + } + else if(strcmp(cpa, "QuadMesh")==0) { + iv_finddata(iv, "verticesPerColumn", 0); + iv_finddata(iv, "verticesPerRow", 1); + + ok= 1; + } + else if(strcmp(cpa, "IndexedTriangleStripSet")==0) { + skipdata= iv_finddata(iv, "coordIndex", 0); + ok= 1; + } + else if(strcmp(cpa, "TriangleStripSet")==0) { + skipdata= iv_finddata(iv, "numVertices", 0); + ok= 1; + } + else if(strcmp(cpa, "IndexedNurbsSurface")==0 || strcmp(cpa, "NurbsSurface")==0) { + iv_finddata(iv, "numUControlPoints", 0); + iv_finddata(iv, "numVControlPoints", 1); + iv_finddata(iv, "uKnotVector", 2); + iv_finddata(iv, "vKnotVector", 3); + ok= 1; + } + else { + /* to the end */ + while( *md != '}') { + md++; + count++; + if(countnext; + + if( strncmp(iv->nodename, "Indexed", 7)==0) { + /* seek back: same name? */ + + ivp= iv->prev; + while(ivp) { + if(strcmp(iv->nodename, ivp->nodename)==0) break; + + if(strcmp(ivp->nodename, "Coordinate3")==0 || + strcmp(ivp->nodename, "Coordinate4")==0 || + strcmp(ivp->nodename, "VertexProperty")==0) { + ivp= 0; + break; + } + ivp= ivp->prev; + } + + if(ivp) { + /* add iv to ivp */ + + tot= iv->datalen[0] + ivp->datalen[0]; + if(tot) { + data= MEM_mallocN(tot*sizeof(float), "samenvoeg iv"); + memcpy(data, ivp->data[0], sizeof(float)*ivp->datalen[0]); + memcpy(data+ivp->datalen[0], iv->data[0], sizeof(float)*iv->datalen[0]); + + ivp->datalen[0]+= iv->datalen[0]; + MEM_freeN(ivp->data[0]); + ivp->data[0]= data; + + BLI_remlink(&ivbase, iv); + MEM_freeN(iv->data[0]); + MEM_freeN(iv); + } + } + } + + iv= ivn; + } + + + /* convert Nodes to DispLists */ + iv= ivbase.first; + while(iv) { + + /* printf(" Node: %s\n", iv->nodename); */ + /* if(iv->fieldname[0]) printf(" Field: %s len %d\n", iv->fieldname[0], iv->datalen[0]); */ + coordtype= 3; + + if( strcmp(iv->nodename, "IndexedLineSet")==0 ) { + + colnr= iv_colornumber(iv); + + /* seek back to data */ + ivp= iv; + while(ivp->prev) { + ivp= ivp->prev; + if( strcmp(ivp->nodename, "Coordinate3")==0 ) { + coordtype= 3; + break; + } + if( strcmp(ivp->nodename, "Coordinate4")==0 ) { + coordtype= 4; + break; + } + } + if(ivp) { + + /* count the nr of lines */ + tot= 0; + index= iv->data[0]; + lll = iv->datalen[0]-1; + for(a=0; atype= DL_SEGM; + dl->nr= 2; + dl->parts= tot/2; + dl->col= colnr; + data= (float *)(dl+1); + + index= iv->data[0]; + for(a=0; adata[0], index, 2, coordtype); + data+= 6; + } + index++; + } + } + } + else if( strcmp(iv->nodename, "FaceSet")==0 ) { + + colnr= iv_colornumber(iv); + + /* seek back to data */ + ivp= iv; + while(ivp->prev) { + ivp= ivp->prev; + if( strcmp(ivp->nodename, "Coordinate3")==0 ) { + coordtype= 3; + break; + } + if( strcmp(ivp->nodename, "Coordinate4")==0 ) { + coordtype= 4; + break; + } + } + + if(ivp) { + /* count triangles */ + tot= 0; + + index= iv->data[0]; + polytype= (int) index[0]; + + for(a=0; adatalen[0]; a++) { + if(index[0]== polytype) tot++; /* one kind? */ + index++; + } + + + tot*= polytype; /* nr of vertices */ + dl= MEM_callocN(sizeof(struct DispList)+tot*3*sizeof(float), "leesInventor4"); + BLI_addtail(listb, dl); + dl->type= DL_POLY; + dl->nr= polytype; + dl->parts= tot/polytype; + dl->col= colnr; + data= (float *)(dl+1); + + index= ivp->data[0]; + first= 1; + for(a=0; adatalen[0]; a++) { + + VECCOPY(data, index); + data+= 3; + index+= 3; + + VECCOPY(data, index); + data+= 3; + index+= 3; + + VECCOPY(data, index); + data+= 3; + index+= 3; + + if(polytype==4) { + VECCOPY(data, index); + data+= 3; + index+= 3; + } + } + } + } + else if( strcmp(iv->nodename, "TriangleStripSet")==0 ) { + + colnr= iv_colornumber(iv); + + /* seek back to data */ + ivp= iv; + while(ivp->prev) { + ivp= ivp->prev; + if( strcmp(ivp->nodename, "Coordinate3")==0 ) { + coordtype= 3; + break; + } + if( strcmp(ivp->nodename, "Coordinate4")==0 ) { + coordtype= 4; + break; + } + } + + if(ivp) { + /* count triangles */ + tot= 0; + face= 0; + + index= iv->data[0]; /* strip size */ + + for(a=0; adatalen[0]; a++) { + tot+= (int) index[0]; + face+= ((int) index[0]) - 2; + index++; + } + + dl= MEM_callocN(sizeof(struct DispList), "leesInventor4"); + dl->verts= MEM_callocN( tot*3*sizeof(float), "dl verts"); + dl->index= MEM_callocN( face*3*sizeof(int), "dl index"); + + dl->type= DL_INDEX3; + dl->nr= tot; + dl->parts= face; + + BLI_addtail(listb, dl); + dl->col= colnr; + + index= iv->data[0]; /* strip size */ + fp= ivp->data[0]; /* vertices */ + data= dl->verts; + idata= dl->index; + first= 0; + + for(a=0; adatalen[0]; a++) { + + /* vertices */ + for(b=0; bnodename, "IndexedFaceSet")==0 ) { + + colnr= iv_colornumber(iv); + + /* seek back to data */ + ivp= iv; + while(ivp->prev) { + ivp= ivp->prev; + if( strcmp(ivp->nodename, "Coordinate3")==0 ) { + coordtype= 3; + break; + } + if( strcmp(ivp->nodename, "Coordinate4")==0 ) { + coordtype= 4; + break; + } + } + if(ivp) { + + /* count triangles */ + face= 0; + index= iv->data[0]; + lll = iv->datalen[0]-2; + for(a=0; adatalen[0]/coordtype; + + if(tot) { + dl= MEM_callocN(sizeof(struct DispList), "leesInventor5"); + BLI_addtail(listb, dl); + dl->type= DL_INDEX3; + dl->nr= tot; + dl->parts= face; + dl->col= colnr; + + dl->verts= MEM_callocN( tot*3*sizeof(float), "dl verts"); + dl->index= MEM_callocN(sizeof(int)*3*face, "dl index"); + + /* vertices */ + fp= ivp->data[0]; + data= dl->verts; + for(b=tot; b>0; b--) { + VECCOPY(data, fp); + data+= 3; + fp+= coordtype; + } + + /* indices */ + index= iv->data[0]; + idata= dl->index; + first= 1; + lll=iv->datalen[0]-2; + for(a=0; anodename, "IndexedTriangleMesh")==0 || + strcmp(iv->nodename, "IndexedTriangleStripSet")==0 ) { + + colnr= iv_colornumber(iv); + + /* seek back to data */ + ivp= iv; + while(ivp->prev) { + ivp= ivp->prev; + if( strcmp(ivp->nodename, "Coordinate3")==0 ) { + coordtype= 3; + break; + } + if( strcmp(ivp->nodename, "Coordinate4")==0 ) { + coordtype= 4; + break; + } + } + if(ivp) { + + /* count triangles */ + face= 0; + index= iv->data[0]; + lll=iv->datalen[0]-2; + for(a=0; adatalen[0]/coordtype; + + dl= MEM_callocN(sizeof(struct DispList), "leesInventor6"); + BLI_addtail(listb, dl); + dl->type= DL_INDEX3; + dl->nr= tot; + dl->parts= face; + dl->col= colnr; + + dl->verts= MEM_callocN( tot*3*sizeof(float), "dl verts"); + dl->index= MEM_callocN(sizeof(int)*3*face, "dl index"); + + /* vertices */ + fp= ivp->data[0]; + data= dl->verts; + for(b=tot; b>0; b--) { + VECCOPY(data, fp); + data+= 3; + fp+= coordtype; + } + + /* indices */ + index= iv->data[0]; + idata= dl->index; + + lll=iv->datalen[0]-2; + for(a=lll; a>0; a--) { + + if(index[0]!= -1 && index[1]!= -1 && index[2]!= -1) { + idata[0]= (int) index[0]; + idata[1]= (int) index[1]; + idata[2]= (int) index[2]; + idata+= 3; + } + index++; + } + } + } + else if( strcmp(iv->nodename, "QuadMesh")==0 ) { + + colnr= iv_colornumber(iv); + + /* seek back to data */ + ivp= iv; + while(ivp->prev) { + ivp= ivp->prev; + if( strcmp(ivp->nodename, "Coordinate3")==0 ) { + coordtype= 3; + break; + } + if( strcmp(ivp->nodename, "VertexProperty")==0 ) { + coordtype= 3; + break; + } + if( strcmp(ivp->nodename, "Coordinate4")==0 ) { + coordtype= 4; + break; + } + } + + if(ivp) { + tot= (int) (floor(*(iv->data[0])+0.5) * floor(*(iv->data[1])+0.5)); + + if(tot>0) { + dl= MEM_callocN(sizeof(struct DispList)+tot*3*sizeof(float), "leesInventor8"); + BLI_addtail(listb, dl); + dl->type= DL_SURF; + dl->parts= (int) floor(*(iv->data[0])+0.5); + dl->nr= (int) floor(*(iv->data[1])+0.5); + dl->col= colnr; + data= (float *)(dl+1); + memcpy(data, ivp->data[0], tot*3*sizeof(float)); + } + } + } + else if(strcmp(iv->nodename, "IndexedNurbsSurface")==0 || strcmp(iv->nodename, "NurbsSurface")==0) { + + colnr= iv_colornumber(iv); + + /* sek back to data */ + ivp= iv; + while(ivp->prev) { + ivp= ivp->prev; + if( strcmp(ivp->nodename, "Coordinate3")==0 ) { + coordtype= 3; + break; + } + if( strcmp(ivp->nodename, "Coordinate4")==0 ) { + coordtype= 4; + break; + } + } + if(ivp) { + a= (int) *(iv->data[0]); + b= (int) *(iv->data[1]); + + tot= a*b; + + if( (a>=4 || b>=4) && tot>6) { + Object *ob; + Curve *cu; + Nurb *nu; + BPoint *bp; + + if(ivsurf==0) { + ob= add_object(OB_SURF); + ivsurf= ob; + } + else ob= ivsurf; + cu= ob->data; + nu = (Nurb*) MEM_callocN(sizeof(Nurb),"addNurbprim") ; + BLI_addtail(&cu->nurb, nu); + nu->type= CU_NURBS; + + nu->pntsu= a; + nu->pntsv= b; + nu->resolu= 2*a; + nu->resolv= 2*b; + + nu->flagu= 0; + nu->flagv= 0; + + nu->bp = bp = + (BPoint*)MEM_callocN(tot * sizeof(BPoint), "addNurbprim3"); + a= tot; + data= ivp->data[0]; + while(a--) { + VECCOPY(bp->vec, data); + if(coordtype==4) { + bp->vec[3]= data[3]; + VecMulf(bp->vec, 1.0f/data[3]); + } + else bp->vec[3]= 1.0; + data+= coordtype; + bp++; + } + + /* iv->datalen[2] / [3] is number of knots */ + nu->orderu= iv->datalen[2] - nu->pntsu; + nu->orderv= iv->datalen[3] - nu->pntsv; + + nu->knotsu= MEM_mallocN( sizeof(float)*(iv->datalen[2]), "knots"); + memcpy(nu->knotsu, iv->data[2], sizeof(float)*(iv->datalen[2])); + nu->knotsv= MEM_mallocN( sizeof(float)*(iv->datalen[3]), "knots"); + memcpy(nu->knotsv, iv->data[3], sizeof(float)*(iv->datalen[3])); + + switchdirectionNurb(nu); + + } + else { + dl= MEM_callocN(sizeof(struct DispList)+tot*3*sizeof(float), "leesInventor3"); + BLI_addtail(listb, dl); + dl->type= DL_SURF; + dl->nr= (int) *(iv->data[0]); + dl->parts= (int) *(iv->data[1]); + dl->col= colnr; + data= (float *)(dl+1); + + a= tot; + fp= ivp->data[0]; + while(a--) { + VECCOPY(data, fp); + fp+= coordtype; + data+= 3; + } + } + } + } + iv= iv->next; + } + + /* free */ + iv= ivbase.first; + while(iv) { + for(a=0; adata[a]) MEM_freeN(iv->data[a]); + } + iv= iv->next; + } + + BLI_freelistN(&ivbase); + MEM_freeN(maindata); + MEM_freeN(iv_data_stack); + +} + +/* ************************************************************ */ + +static void displist_to_mesh(DispList *dlfirst) +{ + Object *ob; + Mesh *me; + Material *ma; + DispList *dl; + MVert *mvert; + MFace *mface; + float *data, vec[3], min[3], max[3]; + int a, b, startve, *idata, totedge=0, tottria=0, totquad=0, totvert=0, totface, totcol=0, colnr; + int p1, p2, p3, p4; + unsigned int maxvertidx; + + /* count first */ + INIT_MINMAX(min, max); + + dl= dlfirst; + while(dl) { + + /* PATCH 1 (polyfill) can't be done, there's no listbase here. do that first! */ + /* PATCH 2 */ + if(dl->type==DL_SEGM && dl->nr>2) { + data= (float *)(dl+1); + if(data[0]==data[3*(dl->nr-1)]) { + if(data[1]==data[3*(dl->nr-1)+1]) { + if(data[2]==data[3*(dl->nr-1)+2]) { + dl->type= DL_POLY; + dl->nr--; + } + } + } + } + + /* colors */ + if(dl->col > totcol) totcol= dl->col; + + /* size and count */ + if(dl->type==DL_SURF) { + a= dl->nr; + b= dl->parts; + if(dl->flag & DL_CYCL_U) a++; + if(dl->flag & DL_CYCL_V) b++; + + totquad+= a*b; + + totvert+= dl->nr*dl->parts; + + data= (float *)(dl+1); + for(a= dl->nr*dl->parts; a>0; a--) { + DO_MINMAX(data, min, max); + data+= 3; + } + } + else if(dl->type==DL_POLY) { + if(dl->nr==3 || dl->nr==4) { + if(dl->nr==3) tottria+= dl->parts; + else totquad+= dl->parts; + + totvert+= dl->nr*dl->parts; + + data= (float *)(dl+1); + for(a= dl->nr*dl->parts; a>0; a--) { + DO_MINMAX(data, min, max); + data+= 3; + } + } + else if(dl->nr>4) { + + tottria+= dl->nr*dl->parts; + totvert+= dl->nr*dl->parts; + + data= (float *)(dl+1); + for(a= dl->nr*dl->parts; a>0; a--) { + DO_MINMAX(data, min, max); + data+= 3; + } + + } + } + else if(dl->type==DL_INDEX3) { + tottria+= dl->parts; + totvert+= dl->nr; + + data= dl->verts; + for(a= dl->nr; a>0; a--) { + DO_MINMAX(data, min, max); + data+= 3; + } + } + else if(dl->type==DL_SEGM) { + + tottria+= (dl->nr-1)*dl->parts; + totvert+= dl->nr*dl->parts; + + data= (float *)(dl+1); + for(a= dl->nr*dl->parts; a>0; a--) { + DO_MINMAX(data, min, max); + data+= 3; + } + } + + dl= dl->next; + } + + if(totvert==0) { + return; + } + + if(totcol>16) { + error("Found more than 16 different colors"); + totcol= 16; + } + + vec[0]= (min[0]+max[0])/2; + vec[1]= (min[1]+max[1])/2; + vec[2]= (min[2]+max[2])/2; + + ob= add_object(OB_MESH); + VECCOPY(ob->loc, vec); + where_is_object(ob); + + me= ob->data; + + /* colors */ + if(totcol) { + ob->mat= MEM_callocN(sizeof(void *)*totcol, "ob->mat"); + me->mat= MEM_callocN(sizeof(void *)*totcol, "me->mat"); + me->totcol= totcol; + ob->totcol= (unsigned char) me->totcol; + ob->actcol= 1; + } + + /* materials */ + for(a=0; amat.first; + while(ma) { + if(ma->mtex[0]==0) { + if(ivcolors[a][0]==ma->r && ivcolors[a][1]==ma->g && ivcolors[a][2]==ma->b) { + me->mat[a]= ma; + ma->id.us++; + break; + } + } + ma= ma->id.next; + } + if(ma==0) { + ma= add_material("ext"); + me->mat[a]= ma; + ma->r= ivcolors[a][0]; + ma->g= ivcolors[a][1]; + ma->b= ivcolors[a][2]; + automatname(ma); + } + } + + totface= totquad+tottria+totedge; + + printf("Import: %d vertices %d faces\n", totvert, totface); + + me->totvert= totvert; + me->totface= totface; + me->mvert= CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, + NULL, me->totvert); + me->mface= CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, + NULL, me->totface); + maxvertidx= totvert-1; + + mvert= me->mvert; + mface= me->mface; + + startve= 0; + + dl= dlfirst; + while(dl) { + + colnr= (dl->col>15 ? 15: dl->col); + if(colnr) colnr--; + + if(dl->type==DL_SURF) { + data= (float *)(dl+1); + + for(a=dl->parts*dl->nr; a>0; a--) { + mvert->co[0]= data[0] -vec[0]; + mvert->co[1]= data[1] -vec[1]; + mvert->co[2]= data[2] -vec[2]; + + data+=3; + mvert++; + } + + for(a=0; aparts; a++) { + + DL_SURFINDEX(dl->flag & DL_CYCL_U, dl->flag & DL_CYCL_V, dl->nr, dl->parts); + p1+= startve; + p2+= startve; + p3+= startve; + p4+= startve; + + for(; bnr; b++) { + + mface->v1= p1; + mface->v2= p2; + mface->v3= p4; + mface->v4= p3; + + mface->mat_nr= colnr; + test_index_face(mface, NULL, 0, 4); + + mface++; + + p4= p3; + p3++; + p2= p1; + p1++; + } + } + + startve += dl->parts*dl->nr; + + } + else if(dl->type==DL_POLY) { + + if(dl->nr==3 || dl->nr==4) { + data= (float *)(dl+1); + + for(a=dl->parts*dl->nr; a>0; a--) { + mvert->co[0]= data[0] -vec[0]; + mvert->co[1]= data[1] -vec[1]; + mvert->co[2]= data[2] -vec[2]; + data+=3; + mvert++; + } + + for(a=0; aparts; a++) { + if(dl->nr==3) { + mface->v1= startve+a*dl->nr; + mface->v2= startve+a*dl->nr+1; + mface->v3= startve+a*dl->nr+2; + mface->mat_nr= colnr; + test_index_face(mface, NULL, 0, 3); + mface++; + } + else { + mface->v1= startve+a*dl->nr; + mface->v2= startve+a*dl->nr+1; + mface->v3= startve+a*dl->nr+2; + mface->v4= startve+a*dl->nr+3; + mface->mat_nr= colnr; + test_index_face(mface, NULL, 0, 4); + mface++; + } + } + startve += dl->parts*dl->nr; + } + else if(dl->nr>4) { + data= (float *)(dl+1); + + for(a=dl->parts*dl->nr; a>0; a--) { + mvert->co[0]= data[0] -vec[0]; + mvert->co[1]= data[1] -vec[1]; + mvert->co[2]= data[2] -vec[2]; + + data+=3; + mvert++; + } + + for(b=0; bparts; b++) { + for(a=0; anr; a++) { + mface->v1= startve+a; + + if(a==dl->nr-1) mface->v2= startve; + else mface->v2= startve+a+1; + + mface->mat_nr= colnr; + + mface++; + } + startve += dl->nr; + } + } + } + else if(dl->type==DL_INDEX3) { + data= dl->verts; + + for(a=dl->nr; a>0; a--) { + mvert->co[0]= data[0] -vec[0]; + mvert->co[1]= data[1] -vec[1]; + mvert->co[2]= data[2] -vec[2]; + data+=3; + mvert++; + } + + idata= dl->index; + for(b=dl->parts; b>0; b--) { + mface->v1= startve+idata[0]; + mface->v2= startve+idata[1]; + mface->v3= startve+idata[2]; + mface->mat_nr= colnr; + + if (mface->v1>maxvertidx) mface->v1= maxvertidx; + if (mface->v2>maxvertidx) mface->v2= maxvertidx; + if (mface->v3>maxvertidx) mface->v3= maxvertidx; + + test_index_face(mface, NULL, 0, 3); + mface++; + idata+= 3; + } + startve += dl->nr; + } + else if(dl->type==DL_SEGM) { + data= (float *)(dl+1); + + for(a=dl->parts*dl->nr; a>0; a--) { + mvert->co[0]= data[0] -vec[0]; + mvert->co[1]= data[1] -vec[1]; + mvert->co[2]= data[2] -vec[2]; + data+=3; + mvert++; + } + + for(b=0; bparts; b++) { + for(a=0; anr-1; a++) { + mface->v1= startve+a; + mface->v2= startve+a+1; + mface->mat_nr= colnr; + mface++; + } + startve += dl->nr; + } + } + dl= dl->next; + } + + mesh_add_normals_flags(me); + make_edges(me, 0); +} + +static void displist_to_objects(ListBase *lbase) +{ + DispList *dl, *first, *prev, *next; + ListBase tempbase; + int maxaantal, curcol, totvert=0, vert; + + /* irst this: is still active */ + if(ivsurf) { + where_is_object(ivsurf); + docenter_new(); + } + + dl= lbase->first; + while(dl) { + next= dl->next; + + /* PATCH 1: polyfill */ + if(dl->type==DL_POLY && dl->nr>4) { + /* solution: put them together in separate listbase */ + ; + } + /* PATCH 2: poly's of 2 points */ + if(dl->type==DL_POLY && dl->nr==2) dl->type= DL_SEGM; + + dl= next; + } + + /* count vertices */ + + dl= lbase->first; + while(dl) { + + if(dl->type==DL_SURF) totvert+= dl->nr*dl->parts; + else if(dl->type==DL_POLY) { + if(dl->nr==3 || dl->nr==4) totvert+= dl->nr*dl->parts; + else if(dl->nr>4) totvert+= dl->nr*dl->parts; + } + else if(dl->type==DL_INDEX3) totvert+= dl->nr; + else if(dl->type==DL_SEGM) totvert+= dl->nr*dl->parts; + + dl= dl->next; + } + + if(totvert==0) { + + if(ivsurf==0) error("Found no data"); + if(lbase->first) BLI_freelistN(lbase); + + return; + } + + maxaantal= 32000; + + if(totvert>maxaantal) { + + /* try to put colors together */ + curcol= 0; + tempbase.first= tempbase.last= 0; + + while(lbase->first) { + dl= lbase->first; + while(dl) { + next= dl->next; + if(dl->col==curcol) { + BLI_remlink(lbase, dl); + BLI_addtail(&tempbase, dl); + dl->col= 0; + } + + dl= next; + } + + /* in tempbase are all 'curcol' */ + totvert= 0; + dl= first= tempbase.first; + while(dl) { + vert= 0; + + if(dl->type==DL_SURF) vert= dl->nr*dl->parts; + else if(dl->type==DL_POLY) { + if(dl->nr==3 || dl->nr==4) vert= dl->nr*dl->parts; + else if(dl->nr>4) vert= dl->nr*dl->parts; + } + else if(dl->type==DL_INDEX3) totvert+= dl->nr; + else if(dl->type==DL_SEGM) vert= dl->nr*dl->parts; + + totvert+= vert; + if(totvert > maxaantal || dl->next==0) { + if(dl->next==0) { + displist_to_mesh(first); + } + else if(dl->prev) { + prev= dl->prev; + prev->next= 0; + displist_to_mesh(first); + prev->next= dl; + first= dl; + totvert= 0; + } + } + + dl= dl->next; + } + + freedisplist(&tempbase); + + curcol++; + } + } + else displist_to_mesh(lbase->first); + + freedisplist(lbase); + +} + +int BKE_read_exotic(char *name) +{ + ListBase lbase={0, 0}; + int len; + gzFile gzfile; + char str[32]; + int *s0 = (int*) str; + int retval = 0; + + // make sure we're not trying to read a directory.... + + len= strlen(name); + if (name[len-1] !='/' && name[len-1] != '\\') { + gzfile = gzopen(name,"rb"); + + if (NULL == gzfile ) { + error("Can't open file: %s", name); + retval= -1; + } else { + gzread(gzfile, str, 31); + gzclose(gzfile); + + if ((*s0 != FORM) && (strncmp(str, "BLEN", 4) != 0) && !BLI_testextensie(name,".blend.gz")) { + + waitcursor(1); + + if(*s0==GOUR) { + if(G.obedit) { + error("Unable to perform function in EditMode"); + } else { + read_radiogour(name); + retval = 1; + } + } + else if ELEM4(*s0, DDG1, DDG2, DDG3, DDG4) { + if(G.obedit) { + error("Unable to perform function in EditMode"); + } else { + read_videoscape(name); + retval = 1; + } + } + else if(strncmp(str, "#Inventor V1.0", 14)==0) { + if( strncmp(str+15, "ascii", 5)==0) { + read_inventor(name, &lbase); + displist_to_objects(&lbase); + retval = 1; + } else { + error("Can only read Inventor 1.0 ascii"); + } + } + else if((strncmp(str, "#VRML V1.0 asc", 14)==0)) { + read_inventor(name, &lbase); + displist_to_objects(&lbase); + retval = 1; + } + else if(is_dxf(name)) { + dxf_read(name); + retval = 1; + } + else if(is_stl(name)) { + if (is_stl_ascii(name)) + read_stl_mesh_ascii(name); + else + read_stl_mesh_binary(name); + retval = 1; + } + // TODO: this should not be in the kernel... + else { // unknown format, call Python importloader + if (BPY_call_importloader(name)) { + retval = 1; + } else { + error("Unknown file type or error, check console"); + } + + } + waitcursor(0); + } + } + } + + return (retval); +} + + +/* ************************ WRITE ************************** */ + + +char temp_dir[160]= {0, 0}; + +static void write_vert_stl(Object *ob, MVert *verts, int index, FILE *fpSTL) +{ + float vert[3]; + + VECCOPY(vert, verts[(index)].co); + Mat4MulVecfl(ob->obmat, vert); + + if (G.order==B_ENDIAN) { + SWITCH_INT(vert[0]); + SWITCH_INT(vert[1]); + SWITCH_INT(vert[2]); + } + + fwrite(vert, sizeof(float), 3, fpSTL); +} + +static int write_derivedmesh_stl(FILE *fpSTL, Object *ob, DerivedMesh *dm) +{ + MVert *mvert = dm->getVertArray(dm); + MFace *mface = dm->getFaceArray(dm); + int i, numfacets = 0, totface = dm->getNumFaces(dm); + float zero[3] = {0.0f, 0.0f, 0.0f}; + + for (i=0; iv1, fpSTL); + write_vert_stl(ob, mvert, mface->v2, fpSTL); + write_vert_stl(ob, mvert, mface->v3, fpSTL); + fprintf(fpSTL, " "); + numfacets++; + + if(mface->v4) { /* quad = 2 tri's */ + fwrite(zero, sizeof(float), 3, fpSTL); + write_vert_stl(ob, mvert, mface->v1, fpSTL); + write_vert_stl(ob, mvert, mface->v3, fpSTL); + write_vert_stl(ob, mvert, mface->v4, fpSTL); + fprintf(fpSTL, " "); + numfacets++; + } + } + + return numfacets; +} + +static int write_object_stl(FILE *fpSTL, Object *ob, Mesh *me) +{ + int numfacets = 0; + DerivedMesh *dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH); + + numfacets += write_derivedmesh_stl(fpSTL, ob, dm); + + dm->release(dm); + + return numfacets; +} + +void write_stl(char *str) +{ + Object *ob; + Mesh *me; + Base *base; + FILE *fpSTL; + int numfacets = 0; + + if(BLI_testextensie(str,".blend")) str[ strlen(str)-6]= 0; + if(BLI_testextensie(str,".ble")) str[ strlen(str)-4]= 0; + if(BLI_testextensie(str,".stl")==0) strcat(str, ".stl"); + + if (!during_script()) { + if (BLI_exists(str)) + if(saveover(str)==0) + return; + } + + fpSTL= fopen(str, "wb"); + + if(fpSTL==NULL) { + if (!during_script()) error("Can't write file"); + return; + } + strcpy(temp_dir, str); + + waitcursor(1); + + /* The header part of the STL */ + /* First 80 characters are a title or whatever you want. + Lets make the first 32 of those spam and the rest the filename. + Those first 80 characters will be followed by 4 bytes + which will be overwritten later with an integer holding + how many facets are written (we set them to ' ' for now). + */ + fprintf(fpSTL, "Binary STL output from Blender: %-48.48s ", str); + + /* Write all selected mesh objects */ + base= G.scene->base.first; + while(base) { + if (base->flag & SELECT) { + ob = base->object; + if (ob->type == OB_MESH) { + me = ob->data; + if (me) + numfacets += write_object_stl(fpSTL, ob, me); + } + } + base= base->next; + } + + /* time to write the number of facets in the 4 bytes + starting at byte 81 + */ + fseek(fpSTL, 80, SEEK_SET); + + if (G.order==B_ENDIAN) { + SWITCH_INT(numfacets); + } + fwrite(&numfacets, 4*sizeof(char), 1, fpSTL); + + fclose(fpSTL); + + waitcursor(0); +} + +static void write_videoscape_mesh(Object *ob, char *str) +{ + EditMesh *em = G.editMesh; + Mesh *me; + Material *ma; + MFace *mface; + FILE *fp; + EditVert *eve; + EditFace *evl; + unsigned int kleur[32]; + float co[3]; + int a; + long tot; + char *cp; + + if(ob && ob->type==OB_MESH); + else { + return; + } + + kleur[0]= 0x00C0C0C0; + + cp= (char *)kleur; + for(a=0; atotcol; a++, cp+=4) { + + ma= give_current_material(ob, a+1); + if(ma) { + cp[0]= (unsigned char) (255.0*ma->emit); + cp[1]= (unsigned char) (255.0*ma->b); + cp[2]= (unsigned char) (255.0*ma->g); + cp[3]= (unsigned char) (255.0*ma->r); + if(G.order==L_ENDIAN) SWITCH_INT(kleur[a]); + } + else kleur[a]= 0x00C0C0C0; + + if(a>30) break; + } + + fp= fopen(str, "wb"); + if(fp==NULL) return; + + fprintf(fp,"3DG1\n"); + + if(G.obedit) { + + fprintf(fp, "%d\n", G.totvert); + + tot= 0; + eve= em->verts.first; + while(eve) { + VECCOPY(co, eve->co); + Mat4MulVecfl(ob->obmat, co); + fprintf(fp, "%f %f %f\n", co[0], co[1], co[2] ); + eve->tmp.l = tot; + tot++; + eve= eve->next; + } + evl= em->faces.first; + while(evl) { + + if(evl->v4==0) { + fprintf(fp, "3 %ld %ld %ld 0x%x\n", + evl->v1->tmp.l, + evl->v2->tmp.l, + evl->v3->tmp.l, + kleur[evl->mat_nr]); + } + else { + fprintf(fp, "4 %ld %ld %ld %ld 0x%x\n", + evl->v1->tmp.l, + evl->v2->tmp.l, + evl->v3->tmp.l, + evl->v4->tmp.l, + kleur[evl->mat_nr]); + } + evl= evl->next; + } + } + else { + DerivedMesh *dm = mesh_get_derived_deform(ob, CD_MASK_BAREMESH); + + me= ob->data; + + fprintf(fp, "%d\n", me->totvert); + + mface= me->mface; + for(a=0; atotvert; a++) { + dm->getVertCo(dm, a, co); + Mat4MulVecfl(ob->obmat, co); + fprintf(fp, "%f %f %f\n", co[0], co[1], co[2] ); + } + for(a=0; atotface; a++, mface++) { + if(mface->v4==0) { + fprintf(fp, "3 %d %d %d 0x%x\n", mface->v1, mface->v2, mface->v3, kleur[mface->mat_nr]); + } + else { + fprintf(fp, "4 %d %d %d %d 0x%x\n", mface->v1, mface->v2, mface->v3, mface->v4, kleur[mface->mat_nr]); + } + } + + dm->release(dm); + } + + fclose(fp); + +} + + +void write_videoscape(char *str) +{ + Base *base; + int file, val, lampdone=0; + unsigned short numlen; + char head[FILE_MAXFILE], tail[FILE_MAXFILE]; + + if(BLI_testextensie(str,".trace")) str[ strlen(str)-6]= 0; + if(BLI_testextensie(str,".blend")) str[ strlen(str)-6]= 0; + if(BLI_testextensie(str,".ble")) str[ strlen(str)-4]= 0; + if(BLI_testextensie(str,".obj")==0) strcat(str, ".obj"); + + file= open(str,O_BINARY|O_RDONLY); + close(file); + if(file>-1) if(!during_script() && saveover(str)==0) return; + + strcpy(temp_dir, str); + + base= G.scene->base.first; + while(base) { + if((base->flag & SELECT) && (base->lay & G.scene->lay)) { + if(base->object->type==OB_MESH) { + write_videoscape_mesh(base->object, str); + val = BLI_stringdec(str, head, tail, &numlen); + BLI_stringenc(str, head, tail, numlen, val + 1); + } + else if(base->object->type==OB_CURVE || base->object->type==OB_SURF) { + /* write_videoscape_nurbs(base->object, str); */ + /* val = stringdec(str, head, tail, &numlen); */ + /* stringenc(str, head, tail, numlen, val + 1); */ + } + else if(lampdone==0 && base->object->type==OB_LAMP) { + /* lampdone= 1; */ + /* write_videoscape_lamps(str); */ + /* val = stringdec(str, head, tail, &numlen); */ + /* stringenc(str, head, tail, numlen, val + 1); */ + } + } + base= base->next; + } + + + /* remove when higher numbers exist */ + while(remove(str)==0) { + + val = BLI_stringdec(str, head, tail, &numlen); + BLI_stringenc(str, head, tail, numlen, val + 1); + } +} + +/* ******************************* WRITE VRML ***************************** */ + +static void replace_chars(char *str1, char *str2) +{ + int a= strlen(str2); + + str1[a]= 0; + while(a--) { + if(str2[a]=='.' || str2[a]==' ') str1[a]= '_'; + else str1[a]= str2[a]; + } +} + + +static void write_material_vrml(FILE *fp, Material *ma) +{ + char str[32]; + + replace_chars(str, ma->id.name+2); + + fprintf(fp, "\tDEF %s\n", str); + fprintf(fp, "\tMaterial {\n"); + + fprintf(fp, "\t\tdiffuseColor %f %f %f\n", ma->r, ma->g, ma->b); + fprintf(fp, "\t\tspecularColor %f %f %f\n", ma->specr, ma->specg, ma->specb); + fprintf(fp, "\t\tshininess %f \n", ((float)ma->har)/100.0); + fprintf(fp, "\t\ttransparency %f \n", 1.0-ma->alpha); + + fprintf(fp, "\t}\n"); + +} + +unsigned int *mcol_to_vcol(Mesh *me) +{ + MFace *mface; + unsigned int *mcol, *mcoln, *mcolmain; + int a; + + if(me->totface==0 || me->mcol==0) return 0; + + mcoln= mcolmain= MEM_mallocN(sizeof(int)*me->totvert, "mcoln"); + mcol = (unsigned int *)me->mcol; + mface= me->mface; + + for(a=me->totface; a>0; a--, mface++) { + mcoln[mface->v1]= mcol[0]; + mcoln[mface->v2]= mcol[1]; + mcoln[mface->v3]= mcol[2]; + if(mface->v4) mcoln[mface->v4]= mcol[3]; + + mcol+= 4; + } + + return mcolmain; +} + +void mcol_to_rgba(unsigned int col, float *r, float *g, float *b, float *a) +{ + char *cp; + + cp = (char *)&col; + + *r= cp[3]; + *r /= 255.0; + + *g= cp[2]; + *g /= 255.0; + + *b= cp[1]; + *b /= 255.0; + + *a= cp[0]; + *a /= 255.0; +} + +static void write_mesh_vrml(FILE *fp, Mesh *me) +{ + Material *ma; + MVert *mvert; + MFace *mface; + MTFace *tface; + Image *ima; + int a, b, totcol, texind; + char str[32]; + + replace_chars(str, me->id.name+2); + + fprintf(fp, "\tDEF %s\n", str); + fprintf(fp, "\tSeparator {\n"); + + if(me->mtface) { + ima= ((MTFace *)me->mtface)->tpage; + if(ima) { + fprintf(fp, "\t\tTexture2 {\n"); + fprintf(fp, "\t\t\tfilename %s\n", ima->name); + fprintf(fp, "\t\t\twrapS REPEAT \n"); + fprintf(fp, "\t\t\twrapT REPEAT \n"); + fprintf(fp, "\t\t}\n"); + } + } + + if(me->mcol) { + unsigned int *mcol, *mcolmain; + float r, g, b, cola; + + fprintf(fp, "\t\tMaterial {\n"); + fprintf(fp, "\t\t\tdiffuseColor [\n"); + + a= me->totvert; + mcol= mcolmain= mcol_to_vcol(me); + if(mcol) { + while(a--) { + mcol_to_rgba(*mcol, &r, &g, &b, &cola); + fprintf(fp, "\t\t\t\t %f %f %f,\n", r, g, b); + mcol++; + } + MEM_freeN(mcolmain); + } + fprintf(fp, "\t\t\t]\n"); + fprintf(fp, "\t\t}\n"); + + fprintf(fp, "\t\tMaterialBinding { value PER_VERTEX_INDEXED }\n"); + } + + + fprintf(fp, "\t\tCoordinate3 {\n"); + fprintf(fp, "\t\t\tpoint [\n"); + + a= me->totvert; + mvert= me->mvert; + while(a--) { + fprintf(fp, "\t\t\t\t %f %f %f,\n", mvert->co[0], mvert->co[1], mvert->co[2]); + mvert++; + } + fprintf(fp, "\t\t\t]\n"); + fprintf(fp, "\t\t}\n"); + + + totcol= me->totcol; + if(totcol==0) totcol= 1; + texind= 0; // index for uv coords + + for(b=0; bmcol==0) { + if(me->mat) { + ma= me->mat[b]; + if(ma) { + replace_chars(str, ma->id.name+2); + + fprintf(fp, "\t\tUSE %s\n\n", str); + } + } + } + + if(me->mtface) { + fprintf(fp, "\t\tTextureCoordinate2 {\n"); + fprintf(fp, "\t\t\tpoint [\n"); + + a= me->totface; + mface= me->mface; + tface= me->mtface; + while(a--) { + if(mface->mat_nr==b) { + fprintf(fp, "\t\t\t\t %f %f,\n", tface->uv[0][0], tface->uv[0][1]); + fprintf(fp, "\t\t\t\t %f %f,\n", tface->uv[1][0], tface->uv[1][1]); + fprintf(fp, "\t\t\t\t %f %f,\n", tface->uv[2][0], tface->uv[2][1]); + if(mface->v4) fprintf(fp, "\t\t\t\t %f %f,\n", tface->uv[3][0], tface->uv[3][1]); + } + mface++; + tface++; + } + fprintf(fp, "\t\t\t]\n"); + fprintf(fp, "\t\t}\n"); + } + + fprintf(fp, "\t\tIndexedFaceSet {\n"); + fprintf(fp, "\t\t\tcoordIndex [\n"); + + a= me->totface; + mface= me->mface; + while(a--) { + if(mface->mat_nr==b) { + if(mface->v4) fprintf(fp, "\t\t\t\t %d, %d, %d, %d, -1,\n", mface->v1, mface->v2, mface->v3, mface->v4); + else fprintf(fp, "\t\t\t\t %d, %d, %d, -1,\n", mface->v1, mface->v2, mface->v3); + } + mface++; + } + fprintf(fp, "\t\t\t]\n"); + + if(me->mtface) { + fprintf(fp, "\t\t\ttextureCoordIndex [\n"); + + a= me->totface; + mface= me->mface; + while(a--) { + if(mface->mat_nr==b) { + if(mface->v4) { + fprintf(fp, "\t\t\t\t %d, %d, %d, %d, -1,\n", texind, texind+1, texind+2, texind+3); + texind+= 4; + } + else { + fprintf(fp, "\t\t\t\t %d, %d, %d, -1,\n", texind, texind+1, texind+2); + texind+= 3; + } + } + mface++; + } + fprintf(fp, "\t\t\t]\n"); + } + fprintf(fp, "\t\t}\n"); + } + + fprintf(fp, "\t}\n"); +} + +static void write_camera_vrml(FILE *fp, Object *ob) +{ + Camera *cam; + + if(ob==0) return; + Mat4Invert(ob->imat, ob->obmat); + + fprintf(fp, "\tMatrixTransform {\n"); + + fprintf(fp, "\tmatrix \n"); + + fprintf(fp, "\t\t%f %f %f %f\n", ob->imat[0][0], ob->imat[0][1], ob->imat[0][2], ob->imat[0][3]); + fprintf(fp, "\t\t%f %f %f %f\n", ob->imat[1][0], ob->imat[1][1], ob->imat[1][2], ob->imat[1][3]); + fprintf(fp, "\t\t%f %f %f %f\n", ob->imat[2][0], ob->imat[2][1], ob->imat[2][2], ob->imat[2][3]); + fprintf(fp, "\t\t%f %f %f %f\n", ob->imat[3][0], ob->imat[3][1], ob->imat[3][2], ob->imat[3][3]); + + fprintf(fp, "\t}\n"); + + cam= ob->data; + + fprintf(fp, "\tPerspectiveCamera {\n"); + fprintf(fp, "\t\tfocalDistance %f\n", cam->lens/10.0); + + fprintf(fp, "\t}\n"); + +} + +static void write_object_vrml(FILE *fp, Object *ob) +{ + ID *id; + char str[32]; + + fprintf(fp, "\tSeparator {\n"); + fprintf(fp, "\t\tMatrixTransform {\n"); + + fprintf(fp, "\t\tmatrix \n"); + + fprintf(fp, "\t\t\t%f %f %f %f\n", ob->obmat[0][0], ob->obmat[0][1], ob->obmat[0][2], ob->obmat[0][3]); + fprintf(fp, "\t\t\t%f %f %f %f\n", ob->obmat[1][0], ob->obmat[1][1], ob->obmat[1][2], ob->obmat[1][3]); + fprintf(fp, "\t\t\t%f %f %f %f\n", ob->obmat[2][0], ob->obmat[2][1], ob->obmat[2][2], ob->obmat[2][3]); + fprintf(fp, "\t\t\t%f %f %f %f\n", ob->obmat[3][0], ob->obmat[3][1], ob->obmat[3][2], ob->obmat[3][3]); + + fprintf(fp, "\t\t}\n"); + + id= ob->data; + + replace_chars(str, id->name+2); + + fprintf(fp, "\t\tUSE %s\n", str); + fprintf(fp, "\t}\n"); +} + + +void write_vrml(char *str) +{ + Mesh *me; + Material *ma; + Base *base; + FILE *fp; + + if(BLI_testextensie(str,".blend")) str[ strlen(str)-6]= 0; + if(BLI_testextensie(str,".ble")) str[ strlen(str)-4]= 0; + if(BLI_testextensie(str,".wrl")==0) strcat(str, ".wrl"); + + if(!during_script() && saveover(str)==0) return; + + fp= fopen(str, "w"); + + if(fp==NULL && !during_script()) { + error("Can't write file"); + return; + } + strcpy(temp_dir, str); + + waitcursor(1); + + /* FIRST: write all the datablocks */ + + fprintf(fp, "#VRML V1.0 ascii\n\n# Blender V%d\n\n# 'Switch' is used as a hack, to ensure it is not part of the drawing\n\n", G.version); + fprintf(fp, "Separator {\n"); + fprintf(fp, "Switch {\n"); + + ma= G.main->mat.first; + while(ma) { + if(ma->id.us) { + write_material_vrml(fp, ma); + } + ma= ma->id.next; + } + + /* only write meshes we're using in this scene */ + flag_listbase_ids(&G.main->mesh, LIB_DOIT, 0); + + for(base= G.scene->base.first; base; base= base->next) + if(base->object->type== OB_MESH) + ((ID *)base->object->data)->flag |= LIB_DOIT; + + me= G.main->mesh.first; + while(me) { + if(me->id.flag & LIB_DOIT) { /* is the mesh used in this scene ? */ + write_mesh_vrml(fp, me); + } + me= me->id.next; + } + + /* THEN:Hidden Objects */ + fprintf(fp, "\n\t# Hidden Objects, in invisible layers\n\n"); + base= G.scene->base.first; + while(base) { + if(base->object->type== OB_MESH) { + if( (base->lay & G.scene->lay)==0 ) { + write_object_vrml(fp, base->object); + } + } + base= base->next; + } + + fprintf(fp, "}\n"); + fprintf(fp, "\n# Visible Objects\n\n"); + fprintf(fp, "Separator {\n"); + + /* The camera */ + + write_camera_vrml(fp, G.scene->camera); + + /* THEN:The Objects */ + + base= G.scene->base.first; + while(base) { + if(base->object->type== OB_MESH) { + if(base->lay & G.scene->lay) { + write_object_vrml(fp, base->object); + } + } + base= base->next; + } + + fprintf(fp, "}\n"); + fprintf(fp, "}\n"); + + fclose(fp); + + waitcursor(0); +} + + +/* ******************************* WRITE DXF ***************************** */ + +#define write_group(id,data) fprintf(fp, "%d\n%s\n", id, data) + +/* A completely wacky function to try and make good +indexed (AutoCAD index) values out of straight rgb +ones... crazy */ + +static int rgb_to_dxf_col (float rf, float gf, float bf) +{ + int r= (int) (rf*255.0f); + int g= (int) (gf*255.0f); + int b= (int) (bf*255.0f); + float h,s,v; + int ret; + + /* Grayscale value */ + if (((int)r/10)==((int)g/10) && ((int)g/10)==((int)b/10)) ret= 250+((int)r/51); + /* A nice chroma value */ + else { + rgb_to_hsv (rf,gf,bf,&h,&s,&v); + + ret= (int) (10.0f + (h*239.0f)); + CLAMP(ret,10,249); + + /* If its whitish make the index odd */ + if (s<.5 || v>.5) if(ret%2) ret++; + } + + return ret; +} + +/* And its completely wacky complement */ + +static void dxf_col_to_rgb (int cid, float *rf, float *gf, float *bf) +{ + float h, s, v; + + /* Grayscale values */ + if (cid>=250 && cid <= 255) { + *rf= *gf= *bf= (float) ((cid-250)*51)/255; + CLAMP(*rf, 0.0, 1.0); + CLAMP(*gf, 0.0, 1.0); + CLAMP(*bf, 0.0, 1.0); + + /* Pure values */ + } else if (cid<10) { + switch (cid) { + case 1: + *rf=1.0; + *gf=0.0; + *bf=0.0; + break; + case 2: + *rf=1.0; + *gf=1.0; + *bf=0.0; + break; + case 3: + *gf=1.0; + *rf=0.0; + *bf=0.0; + break; + case 4: + *rf=0.0; + *gf=1.0; + *bf=1.0; + break; + case 5: + *rf=0.0; + *gf=0.0; + *bf=1.0; + break; + case 6: + *rf=1.0; + *gf=0.0; + *bf=1.0; + break; + case 7: + default: + *rf= *gf= *bf= 1.0; + break; + } + } else { + /* Get chroma values */ + + h= (float) (cid-10)/239; + CLAMP(h, 0.0, 1.0); + + /* If its odd make it a bit whitish */ + if (cid%2) { s=.75; v= 0.25; + } else { s= 0.25; v= 0.75;} + + hsv_to_rgb (h, s, v, rf, gf, bf); + } +} + +static void write_mesh_dxf(FILE *fp, Mesh *me) +{ + Material *ma; + MVert *mvert; + MFace *mface; + int a; + char str[32]; + + replace_chars(str, me->id.name+2); + + write_group(0, "BLOCK"); + + write_group(2, str); /* The name */ + + write_group(8, "Meshes"); /* DXF Layer */ + write_group(70, "64"); /* DXF block flags */ + + write_group(10, "0.0"); /* X of base */ + write_group(20, "0.0"); /* Y of base */ + write_group(30, "0.0"); /* Z of base */ + + write_group(3, str); /* The name (again) */ + + write_group(0, "POLYLINE"); /* Start the mesh */ + write_group(66, "1"); /* Vertices follow flag */ + write_group(8,"Meshes"); /* DXF Layer */ + + if (me->totcol) { + ma= me->mat[0]; + if(ma) { + sprintf(str,"%d",rgb_to_dxf_col(ma->r,ma->g,ma->b)); + write_group(62, str); /* Color index */ + } + } + + write_group(70, "64"); /* Polymesh mesh flag */ + + fprintf(fp, "71\n%d\n", me->totvert); /* Total vertices */ + fprintf(fp, "72\n%d\n", me->totface); /* Total faces */ + + /* Write the vertices */ + a= me->totvert; + mvert= me->mvert; + while(a--) { + write_group(0, "VERTEX"); /* Start a new vertex */ + write_group(8, "Meshes"); /* DXF Layer */ + fprintf (fp, "10\n%f\n", mvert->co[0]); /* X cord */ + fprintf (fp, "20\n%f\n", mvert->co[1]); /* Y cord */ + fprintf (fp, "30\n%f\n", mvert->co[2]); /* Z cord */ + write_group(70, "192"); /* Polymesh vertex flag */ + + mvert++; + } + + /* Write the face entries */ + a= me->totface; + mface= me->mface; + while(a--) { + write_group(0, "VERTEX"); /* Start a new face */ + write_group(8, "Meshes"); + + /* Write a face color */ + if (me->totcol) { + ma= me->mat[mface->mat_nr]; + if(ma) { + sprintf(str,"%d",rgb_to_dxf_col(ma->r,ma->g,ma->b)); + write_group(62, str); /* Color index */ + } + } + else write_group(62, "254"); /* Color Index */ + + /* Not sure what this really corresponds too */ + write_group(10, "0.0"); /* X of base */ + write_group(20, "0.0"); /* Y of base */ + write_group(30, "0.0"); /* Z of base */ + + write_group(70, "128"); /* Polymesh face flag */ + + if(mface->v4) { + fprintf (fp, "71\n%d\n", mface->v1+1); + fprintf (fp, "72\n%d\n", mface->v2+1); + fprintf (fp, "73\n%d\n", mface->v3+1); + fprintf (fp, "74\n%d\n", mface->v4+1); + } else { + fprintf (fp, "71\n%d\n", mface->v1+1); + fprintf (fp, "72\n%d\n", mface->v2+1); + fprintf (fp, "73\n%d\n", mface->v3+1); + } + mface++; + } + + write_group(0, "SEQEND"); + + write_group(0, "ENDBLK"); +} + +static void write_object_dxf(FILE *fp, Object *ob, int layer) +{ + ID *id; + char str[32]; + + id= ob->data; + + write_group(0, "INSERT"); /* Start an insert group */ + + sprintf(str, "%d", layer); + write_group(8, str); + + replace_chars(str, id->name+2); + write_group(2, str); + + fprintf (fp, "10\n%f\n", ob->loc[0]); /* X of base */ + fprintf (fp, "20\n%f\n", ob->loc[1]); /* Y of base */ + fprintf (fp, "30\n%f\n", ob->loc[2]); /* Z of base */ + + fprintf (fp, "41\n%f\n", ob->size[0]); /* X scale */ + fprintf (fp, "42\n%f\n", ob->size[1]); /* Y scale */ + fprintf (fp, "43\n%f\n", ob->size[2]); /* Z scale */ + + fprintf (fp, "50\n%f\n", (float) ob->rot[2]*180/M_PI); /* Can only write the Z rot */ +} + +void write_dxf(char *str) +{ + Mesh *me; + Base *base; + FILE *fp; + + if(BLI_testextensie(str,".blend")) str[ strlen(str)-6]= 0; + if(BLI_testextensie(str,".ble")) str[ strlen(str)-4]= 0; + if(BLI_testextensie(str,".dxf")==0) strcat(str, ".dxf"); + + if (!during_script()) { + if (BLI_exists(str)) + if(saveover(str)==0) + return; + } + + fp= fopen(str, "w"); + + if(fp==NULL && !during_script()) { + error("Can't write file"); + return; + } + strcpy(temp_dir, str); + + waitcursor(1); + + /* The header part of the DXF */ + + write_group(0, "SECTION"); + write_group(2, "HEADER"); + write_group(0, "ENDSEC"); + + /* The blocks part of the DXF */ + + write_group(0, "SECTION"); + write_group(2, "BLOCKS"); + + + /* only write meshes we're using in this scene */ + flag_listbase_ids(&G.main->mesh, LIB_DOIT, 0); + + for(base= G.scene->base.first; base; base= base->next) + if(base->object->type== OB_MESH) + ((ID *)base->object->data)->flag |= LIB_DOIT; + + /* Write all the meshes */ + me= G.main->mesh.first; + while(me) { + if(me->id.flag & LIB_DOIT) { /* is the mesh used in this scene ? */ + write_mesh_dxf(fp, me); + } + me= me->id.next; + } + + write_group(0, "ENDSEC"); + + /* The entities part of the DXF */ + + write_group(0, "SECTION"); + write_group(2, "ENTITIES"); + + /* Write all the mesh objects */ + base= G.scene->base.first; + while(base) { + if(base->object->type== OB_MESH) { + write_object_dxf(fp, base->object, base->lay); + } + base= base->next; + } + + write_group(0, "ENDSEC"); + + /* Thats all */ + + write_group(0, "EOF"); + fclose(fp); + + waitcursor(0); +} + + +static int dxf_line= 0; +static FILE *dxf_fp= NULL; + +/* exotic.c(2863) : note C6311: c:/Program Files/Microsoft Visual + * Studio/VC98/include\ctype.h(268) : see previous definition of + * 'iswspace' */ +#define ton_iswspace(c) (c==' '||c=='\n'||c=='\t') + +static void clean_wspace (char *str) +{ + char *from, *to; + char t; + + from= str; + to=str; + + while (*from!=0) { + t= *from; + *to= t; + + if(!ton_iswspace(*from)) to++; + from++; + } + *to=0; +} + +static int all_wspace(char *str) +{ + while(*str != 0) { + if (!ton_iswspace(*str)) return 0; + str++; + } + + return 1; +} + +static int all_digits(char *str) +{ + while(*str != 0) { + if (!isdigit(*str)) return 0; + str++; + } + + return 1; +} + +static int dxf_get_layer_col(char *layer) +{ + return 1; +} + +static int dxf_get_layer_num(char *layer) +{ + int ret = 0; + + if (all_digits(layer) && atoi(layer)<(1<<20)) ret= atoi(layer); + if (ret == 0) ret = G.scene->lay; + + return ret; +} + +static void dos_clean(char *str) +{ + while (*str) { + if (*str == 0x0d) { + *str='\n'; + *(++str)= 0; + break; + } + str++; + } +} + +static void myfgets(char *str, int len, FILE *fp) +{ + char c; + + while(len>0 && (c=getc(dxf_fp)) ) { + *str= c; + str++; + len--; + /* three types of enters, \n \r and \r\n */ + if(c == '\n') break; + if(c=='\r') { + c= getc(dxf_fp); // read the linefeed from stream + if(c != 10) ungetc(c, dxf_fp); // put back, if it's not one... + break; + } + } +} + +static int read_groupf(char *str) +{ + short c; + int ret=-1; + char tmp[256]; + + strcpy(str, " "); + + while ((c=getc(dxf_fp)) && ton_iswspace(c)); + ungetc(c, dxf_fp); + if (c==EOF) return -1; + + myfgets(tmp, 255, dxf_fp); + + dos_clean(tmp); + + if(sscanf(tmp, "%d\n", &ret)!=1) return -2; + + myfgets(tmp, 255, dxf_fp); + + dos_clean(tmp); + + if (!all_wspace(tmp)) { + if (sscanf(tmp, "%s\n", str)!=1) return -2; + } + + clean_wspace(str); + dxf_line+=2; + + return ret; +} + +#define id_test(id) if(id<0) {char errmsg[128];fclose(dxf_fp); if(id==-1) sprintf(errmsg, "Error inputting dxf, near line %d", dxf_line); else if(id==-2) sprintf(errmsg, "Error reading dxf, near line %d", dxf_line);error(errmsg); return;} + +#define read_group(id,str) {id= read_groupf(str); id_test(id);} + +#define group_is(idtst,str) (id==idtst&&strcmp(val,str)==0) +#define group_isnt(idtst,str) (id!=idtst||strcmp(val,str)!=0) +#define id_check(idtst,str) if(group_isnt(idtst,str)) { fclose(dxf_fp); error("Error parsing dxf, near line %d", dxf_line); return;} + +static int id; +static char val[256]; + +static short error_exit=0; +static short hasbumped=0; + +static int is_dxf(char *str) +{ + dxf_line=0; + + dxf_fp= fopen(str, "r"); + if (dxf_fp==NULL) return 0; + + id= read_groupf(val); + if ((id==0 && strcmp(val, "SECTION")==0)||id==999) return 1; + + fclose(dxf_fp); + + return 0; +} + +/* NOTES ON THE READER */ +/* + -- + It turns out that most DXF writers like (LOVE) to + write meshes as a long string of 3DFACE entities. + This means the natural way to read a DXF file + (every entity corresponds to an object) is completely + unusable, reading in 10,000 faces each as an + object just doesn't cut it. Thus the 3DFACE + entry reader holds state, and only finalizes to + an object when a) the layer name changes, b) the + entry type changes, c) we are done reading. + + PS... I decided to do the same thing with LINES, + apparently the same thing happens sometimes as + well. + + PPS... I decided to do the same thing with everything. + Now it is all really nasty and should be rewritten. + -- + + Added circular and elliptical arcs and lwpolylines. + These are all self-contained and have the size known + in advance, and so I haven't used the held state. -- martin +*/ + +static void dxf_add_mat (Object *ob, Mesh *me, float color[3], char *layer) +{ + Material *ma; + + if (!me) return; + + if(ob) ob->mat= MEM_callocN(sizeof(void *)*1, "ob->mat"); + if(ob) ob->actcol= 1; + + me->totcol= 1; + me->mat= MEM_callocN(sizeof(void *)*1, "me->mat"); + + if (color[0]<0) { + if (strlen(layer)) dxf_col_to_rgb(dxf_get_layer_col(layer), &color[0], &color[1], &color[2]); + color[0]= color[1]= color[2]= 0.8f; + } + + ma= G.main->mat.first; + while(ma) { + if(ma->mtex[0]==0) { + if(color[0]==ma->r && color[1]==ma->g && color[2]==ma->b) { + me->mat[0]= ma; + ma->id.us++; + break; + } + } + ma= ma->id.next; + } + if(ma==0) { + ma= add_material("ext"); + me->mat[0]= ma; + ma->r= color[0]; + ma->g= color[1]; + ma->b= color[2]; + automatname(ma); + } +} + + /* General DXF vars */ +static float cent[3]={0.0, 0.0, 0.0}; +static char layname[32]=""; +static char entname[32]=""; +static float color[3]={-1.0, -1.0, -1.0}; +static float *vcenter; +static float zerovec[3]= {0.0, 0.0, 0.0}; + +#define reset_vars cent[0]= cent[1]= cent[2]=0.0; strcpy(layname, ""); color[0]= color[1]= color[2]= -1.0 + + +static void dxf_get_mesh(Mesh** m, Object** o, int noob) +{ + Mesh *me = NULL; + Object *ob; + + if (!noob) { + *o = add_object(OB_MESH); + ob = *o; + + if (strlen(entname)) new_id(&G.main->object, (ID *)ob, entname); + else if (strlen(layname)) new_id(&G.main->object, (ID *)ob, layname); + + if (strlen(layname)) ob->lay= dxf_get_layer_num(layname); + else ob->lay= G.scene->lay; + // not nice i know... but add_object() sets active base, which needs layer setting too (ton) + G.scene->basact->lay= ob->lay; + + *m = ob->data; + me= *m; + + vcenter= ob->loc; + } + else { + *o = NULL; + *m = add_mesh("Mesh"); G.totmesh++; + + me = *m; + ob = *o; + + ((ID *)me)->us=0; + + if (strlen(entname)) new_id(&G.main->mesh, (ID *)me, entname); + else if (strlen(layname)) new_id(&G.main->mesh, (ID *)me, layname); + + vcenter = zerovec; + } + me->totvert=0; + me->totface=0; + me->mvert= CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, 0); + me->mface= CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, 0); +} + +static void dxf_read_point(int noob) { + /* Blender vars */ + Object *ob; + Mesh *me; + MVert *mvert; + + reset_vars; + + read_group(id, val); + while(id!=0) { + if (id==8) { + BLI_strncpy(layname, val, sizeof(layname)); + } else if (id==10) { + cent[0]= (float) atof(val); + } else if (id==20) { + cent[1]= (float) atof(val); + } else if (id==30) { + cent[2]= (float) atof(val); + } else if (id==60) { + /* short invisible= atoi(val); */ + } else if (id==62) { + int colorid= atoi(val); + + CLAMP(colorid, 1, 255); + dxf_col_to_rgb(colorid, &color[0], &color[1], &color[2]); + } + read_group(id, val); + } + + dxf_get_mesh(&me, &ob, noob); + me->totvert= 1; + me->mvert= MEM_callocN(me->totvert*sizeof(MVert), "mverts"); + CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert); + + dxf_add_mat (ob, me, color, layname); + + mvert= me->mvert; + mvert->co[0]= mvert->co[1]= mvert->co[2]= 0; + + if (ob) VECCOPY(ob->loc, cent); + + hasbumped=1; +} + + /* Line state vars */ +static Object *linehold=NULL; +static Mesh *linemhold=NULL; + +static char oldllay[32]; +static short lwasline=0; /* last was face 3d? */ + +static void dxf_close_line(void) +{ + linemhold=NULL; + if (linehold==NULL) return; + + linehold=NULL; +} + +static void dxf_read_line(int noob) { + /* Entity specific vars */ + float epoint[3]={0.0, 0.0, 0.0}; + short vspace=0; /* Whether or not coords are relative */ + + /* Blender vars */ + Object *ob; + Mesh *me; + MVert *mvert, *vtmp; + MFace *mface, *ftmp; + + reset_vars; + + read_group(id, val); + while(id!=0) { + if (id==8) { + BLI_strncpy(layname, val, sizeof(layname)); + } else if (id==10) { + cent[0]= (float) atof(val); + } else if (id==20) { + cent[1]= (float) atof(val); + } else if (id==30) { + cent[2]= (float) atof(val); + } else if (id==11) { + epoint[0]= (float) atof(val); + } else if (id==21) { + epoint[1]= (float) atof(val); + } else if (id==31) { + epoint[2]= (float) atof(val); + } else if (id==60) { + /* short invisible= atoi(val); */ + } else if (id==62) { + int colorid= atoi(val); + + CLAMP(colorid, 1, 255); + dxf_col_to_rgb(colorid, &color[0], &color[1], &color[2]); + } else if (id==67) { + vspace= atoi(val); + } + read_group(id, val); + } + + /* Check to see if we need to make a new object */ + + if(!lwasline || strcmp(layname, oldllay)!=0) + dxf_close_line(); + if(linemhold != NULL && linemhold->totvert>MESH_MAX_VERTS) + dxf_close_line(); + + if (linemhold==NULL) { + dxf_get_mesh(&me, &ob, noob); + + if(ob) VECCOPY(ob->loc, cent); + + dxf_add_mat (ob, me, color, layname); + + linehold= ob; + linemhold= me; + } else { + ob= linehold; + me= linemhold; + } + + me->totvert+= 2; + me->totface++; + + vtmp= MEM_callocN(me->totvert*sizeof(MVert), "mverts"); + ftmp= MEM_callocN(me->totface*sizeof(MFace), "mface"); + + if(me->mvert) { + memcpy(vtmp, me->mvert, (me->totvert-2)*sizeof(MVert)); + MEM_freeN(me->mvert); + } + me->mvert= CustomData_set_layer(&me->vdata, CD_MVERT, vtmp); + vtmp=NULL; + + if(me->mface) { + memcpy(ftmp, me->mface, (me->totface-1)*sizeof(MFace)); + MEM_freeN(me->mface); + } + me->mface= CustomData_set_layer(&me->fdata, CD_MFACE, ftmp); + ftmp=NULL; + + mvert= &me->mvert[(me->totvert-2)]; + + VecSubf(mvert->co, cent, vcenter); + mvert++; + if (vspace) { VECCOPY(mvert->co, epoint); + } else VecSubf(mvert->co, epoint, vcenter); + + mface= &(((MFace*)me->mface)[me->totface-1]); + mface->v1= me->totvert-2; + mface->v2= me->totvert-1; + mface->mat_nr= 0; + + hasbumped=1; +} + + /* 2D Polyline state vars */ +static Object *p2dhold=NULL; +static Mesh *p2dmhold=NULL; +static char oldplay[32]; +static short lwasp2d=0; + +static void dxf_close_2dpoly(void) +{ + p2dmhold= NULL; + if (p2dhold==NULL) return; + + p2dhold=NULL; +} + +static void dxf_read_ellipse(int noob) +{ + + /* + * The Parameter option of the ELLIPSE command uses the following equation to define an elliptical arc. + * + * p(u)=c+a*cos(u)+b*sin(u) + * + * The variables a, b, c are determined when you select the endpoints for the + * first axis and the distance for the second axis. a is the negative of 1/2 + * of the major axis length, b is the negative of 1/2 the minor axis length, + * and c is the center point (2-D) of the ellipse. + * + * Because this is actually a vector equation and the variable c is actually + * a point with X and Y values, it really should be written as: + * + * p(u)=(Cx+a*cos(u))*i+(Cy+b*sin(u))*j + * + * where + * + * Cx is the X value of the point c + * Cy is the Y value of the point c + * a is -(1/2 of the major axis length) + * b is -(1/2 of the minor axis length) + * i and j represent unit vectors in the X and Y directions + * + * http://astronomy.swin.edu.au/~pbourke/geomformats/dxf2000/ellipse_command39s_parameter_option_dxf_06.htm + * (reproduced with permission) + * + * NOTE: The start and end angles ('parameters') are in radians, whereas those for the circular arc are + * in degrees. The 'sense' of u appears to be determined by the extrusion direction (see more detailed comment + * in the code) + * + * TODO: The code is specific to ellipses in the x-y plane right now. + * + */ + + /* Entity specific vars */ + float epoint[3]={0.0, 0.0, 0.0}; + float center[3]={0.0, 0.0, 0.0}; + float extrusion[3]={0.0, 0.0, 1.0}; + float axis_endpoint[3] = {0.0, 0.0, 0.0}; /* major axis endpoint */ + short vspace=0; /* Whether or not coords are relative */ + float a, b, x, y, z; + float phid = 0.0f, phi = 0.0f, theta = 0.0f; + float start_angle = 0.0f; + float end_angle = 2*M_PI; + float axis_ratio = 1.0f; + float temp; + int v, tot; + int isArc=0; + /* Blender vars */ + Object *ob; + Mesh *me; + MVert *mvert; + MFace *mface; + + reset_vars; + read_group(id, val); + while(id!=0) { + if (id==8) { + BLI_strncpy(layname, val, sizeof(layname)); + } else if (id==10) { + center[0]= (float) atof(val); + } else if (id==20) { + center[1]= (float) atof(val); + } else if (id==30) { + center[2]= (float) atof(val); + } else if (id==11) { + axis_endpoint[0]= (float) atof(val); + } else if (id==21) { + axis_endpoint[1]= (float) atof(val); + } else if (id==31) { + axis_endpoint[2]= (float) atof(val); + } else if (id==40) { + axis_ratio = (float) atof(val); + } else if (id==41) { + printf("dxf: start = %f", atof(val) * 180/M_PI); + start_angle = -atof(val) + M_PI_2; + } else if (id==42) { + printf("dxf: end = %f", atof(val) * 180/M_PI); + end_angle = -atof(val) + M_PI_2; + } else if (id==62) { + int colorid= atoi(val); + CLAMP(colorid, 1, 255); + dxf_col_to_rgb(colorid, &color[0], &color[1], &color[2]); + } else if (id==67) { + vspace= atoi(val); + } else if (id==100) { + isArc = 1; + } else if (id==210) { + extrusion[0] = atof(val); + } else if (id==220) { + extrusion[1] = atof(val); + } else if (id==230) { + extrusion[2] = atof(val); + } + read_group(id, val); + } + + if(!lwasline || strcmp(layname, oldllay)!=0) dxf_close_line(); + if(linemhold != NULL && linemhold->totvert>MESH_MAX_VERTS) + dxf_close_line(); + + /* The 'extrusion direction' seems akin to a face normal, + * insofar as it determines the direction of increasing phi. + * This is again x-y plane specific; it should be fixed at + * some point. */ + + if (extrusion[2] < 0) { + temp = start_angle; + start_angle = M_PI - end_angle; + end_angle = M_PI - temp; + } + + if(end_angle > start_angle) + end_angle -= 2 * M_PI; + + phi = start_angle; + + x = axis_endpoint[0]; + y = axis_endpoint[1]; + z = axis_endpoint[2]; + a = sqrt(x*x + y*y + z*z); + b = a * axis_ratio; + + theta = atan2(y, x); + + x = a * sin(phi); + y = b * cos(phi); + +#ifndef DEBUG_CENTER + epoint[0] = center[0] + x*cos(theta) - y*sin(theta); + epoint[1] = center[1] + x*sin(theta) + y*cos(theta); + epoint[2] = center[2]; + + + cent[0]= epoint[0]; + cent[1]= epoint[1]; + cent[2]= epoint[2]; +#else + cent[0]= center[0]; + cent[1]= center[1]; + cent[2]= center[2]; +#endif + + dxf_get_mesh(&me, &ob, noob); + strcpy(oldllay, layname); + if(ob) VECCOPY(ob->loc, cent); + dxf_add_mat (ob, me, color, layname); + + tot = 32; /* # of line segments to divide the arc into */ + + phid = (end_angle - start_angle)/tot; + + me->totvert += tot+1; + me->totface += tot+1; + + me->mvert = (MVert*) MEM_callocN(me->totvert*sizeof(MVert), "mverts"); + me->mface = (MFace*) MEM_callocN(me->totface*sizeof(MVert), "mface"); + + CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert); + CustomData_set_layer(&me->fdata, CD_MFACE, me->mface); + + printf("vertex and face buffers allocated\n"); + + for(v = 0; v <= tot; v++) { + + x = a * sin(phi); + y = b * cos(phi); + epoint[0] = center[0] + x*cos(theta) - y*sin(theta); + epoint[1] = center[1] + x*sin(theta) + y*cos(theta); + epoint[2] = center[2]; + + mvert= &me->mvert[v]; + + if (vspace) { + VECCOPY(mvert->co, epoint); + } else { + VecSubf(mvert->co, epoint, vcenter); + } + + if (v > 0) { + mface= &(((MFace*)me->mface)[v-1]); + mface->v1 = v-1; + mface->v2 = v; + mface->mat_nr = 0; + } + + hasbumped = 1; + + VECCOPY(cent, epoint); + phi+=phid; + } +} + +static void dxf_read_arc(int noob) +{ + /* Entity specific vars */ + float epoint[3]={0.0, 0.0, 0.0}; + float center[3]={0.0, 0.0, 0.0}; + float extrusion[3]={0.0, 0.0, 1.0}; + short vspace=0; /* Whether or not coords are relative */ + float dia = 0.0f; + float phid = 0.0f, phi = 0.0f; + float start_angle = 0.0f; + float end_angle = 2*M_PI; + float temp; + int v, tot = 32; + int isArc=0; + /* Blender vars */ + Object *ob; + Mesh *me; + MVert *mvert; + MFace *mface; + + reset_vars; + read_group(id, val); + while(id!=0) { + if (id==8) { + BLI_strncpy(layname, val, sizeof(layname)); + } else if (id==10) { + center[0]= (float) atof(val); + } else if (id==20) { + center[1]= (float) atof(val); + } else if (id==30) { + center[2]= (float) atof(val); + } else if (id==40) { + dia = (float) atof(val); + } else if (id==62) { + int colorid= atoi(val); + + CLAMP(colorid, 1, 255); + dxf_col_to_rgb(colorid, &color[0], &color[1], &color[2]); + } else if (id==67) { + vspace= atoi(val); + } else if (id==100) { + isArc = 1; + } else if (id==50) { + start_angle = (90 - atoi(val)) * M_PI/180.0; + } else if (id==51) { + end_angle = (90 - atoi(val)) * M_PI/180.0; + } else if (id==210) { + extrusion[0] = atof(val); + } else if (id==220) { + extrusion[1] = atof(val); + } else if (id==230) { + extrusion[2] = atof(val); + } + read_group(id, val); + } + + if(!lwasline || strcmp(layname, oldllay)!=0) dxf_close_line(); + if(linemhold != NULL && linemhold->totvert>MESH_MAX_VERTS) + dxf_close_line(); + + /* Same xy-plane-specific extrusion direction code as in read_ellipse + * (read_arc and read_ellipse should ideally be rewritten to share code) + */ + + if (extrusion[2] < 0) { + temp = start_angle; + start_angle = M_PI - end_angle; + end_angle = M_PI - temp; + } + + phi = start_angle; + if(end_angle > start_angle) + end_angle -= 2 * M_PI; + + cent[0]= center[0]+dia*sin(phi); + cent[1]= center[1]+dia*cos(phi); + cent[2]= center[2]; + + dxf_get_mesh(&me, &ob, noob); + strcpy(oldllay, layname); + if(ob) VECCOPY(ob->loc, cent); + dxf_add_mat (ob, me, color, layname); + + tot = 32; /* # of line segments to divide the arc into */ + phid = (end_angle - start_angle)/tot; /* fix so that arcs have the same 'resolution' as circles? */ + + me->totvert += tot+1; + me->totface += tot+1; + + me->mvert = (MVert*) MEM_callocN(me->totvert*sizeof(MVert), "mverts"); + me->mface = (MFace*) MEM_callocN(me->totface*sizeof(MVert), "mface"); + + CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert); + CustomData_set_layer(&me->fdata, CD_MFACE, me->mface); + + for(v = 0; v <= tot; v++) { + + epoint[0]= center[0]+dia*sin(phi); + epoint[1]= center[1]+dia*cos(phi); + epoint[2]= center[2]; + + mvert= &me->mvert[v]; + + if (vspace) { + VECCOPY(mvert->co, epoint); + } else { + VecSubf(mvert->co, epoint, vcenter); + } + + if (v > 0) { + mface= &(((MFace*)me->mface)[v-1]); + mface->v1 = v-1; + mface->v2 = v; + mface->mat_nr = 0; + } + + hasbumped=1; + + VECCOPY(cent, epoint); + phi+=phid; + } +} + +static void dxf_read_polyline(int noob) { + /* Entity specific vars */ + short vspace=0; /* Whether or not coords are relative */ + int flag=0; + int vflags=0; + int vids[4]; + int nverts; + + /* Blender vars */ + Object *ob; + Mesh *me; + float vert[3]; + + MVert *mvert, *vtmp; + MFace *mface, *ftmp; + + reset_vars; + + read_group(id, val); + while(id!=0) { + if (id==8) { + BLI_strncpy(layname, val, sizeof(layname)); + } else if (id==10) { + cent[0]= (float) atof(val); + } else if (id==20) { + cent[1]= (float) atof(val); + } else if (id==30) { + cent[2]= (float) atof(val); + } else if (id==60) { + /* short invisible= atoi(val); */ + } else if (id==62) { + int colorid= atoi(val); + + CLAMP(colorid, 1, 255); + dxf_col_to_rgb(colorid, &color[0], &color[1], &color[2]); + } else if (id==67) { + vspace= atoi(val); + } else if (id==70) { + flag= atoi(val); + } + read_group(id, val); + } + + if (flag & 9) { // 1= closed curve, 8= 3d curve + if(!lwasp2d || strcmp(layname, oldplay)!=0) dxf_close_2dpoly(); + if(p2dmhold != NULL && p2dmhold->totvert>MESH_MAX_VERTS) + dxf_close_2dpoly(); + + if (p2dmhold==NULL) { + dxf_get_mesh(&me, &ob, noob); + + strcpy(oldplay, layname); + + if(ob) VECCOPY(ob->loc, cent); + + dxf_add_mat (ob, me, color, layname); + + p2dhold= ob; + p2dmhold= me; + } + else { + ob= p2dhold; + me= p2dmhold; + } + + nverts=0; + while (group_is(0, "VERTEX")) { + read_group(id, val); + while(id!=0) { + if (id==10) { + vert[0]= (float) atof(val); + } else if (id==20) { + vert[1]= (float) atof(val); + } else if (id==30) { + vert[2]= (float) atof(val); + } + read_group(id, val); + } + nverts++; + me->totvert++; + + vtmp= MEM_callocN(me->totvert*sizeof(MVert), "mverts"); + + if (me->mvert) { + memcpy (vtmp, me->mvert, (me->totvert-1)*sizeof(MVert)); + MEM_freeN(me->mvert); + } + me->mvert= CustomData_set_layer(&me->vdata, CD_MVERT, vtmp); + vtmp= NULL; + + mvert= &me->mvert[me->totvert-1]; + + if (vspace) { VECCOPY(mvert->co, vert); + } else VecSubf(mvert->co, vert, vcenter); + } + + /* make edges */ + if(nverts>1) { + int a, oldtotface; + + oldtotface= me->totface; + me->totface+= nverts-1; + + ftmp= MEM_callocN(me->totface*sizeof(MFace), "mface"); + + if(me->mface) { + memcpy(ftmp, me->mface, oldtotface*sizeof(MFace)); + MEM_freeN(me->mface); + } + me->mface= CustomData_set_layer(&me->fdata, CD_MFACE, ftmp); + ftmp=NULL; + + mface= me->mface; + mface+= oldtotface; + + for(a=1; av1= (me->totvert-nverts)+a-1; + mface->v2= (me->totvert-nverts)+a; + mface->mat_nr= 0; + } + } + + lwasp2d=1; + } + else if (flag&64) { + dxf_get_mesh(&me, &ob, noob); + + if(ob) VECCOPY(ob->loc, cent); + + dxf_add_mat (ob, me, color, layname); + + while (group_is(0, "VERTEX")) { + vflags= 0; + vids[0]= vids[1]= vids[2]= vids[3]= 0; + + vflags=0; + read_group(id, val); + while(id!=0) { + if(id==8) { + ; /* Layer def, skip */ + } else if (id==10) { + vert[0]= (float) atof(val); + } else if (id==20) { + vert[1]= (float) atof(val); + } else if (id==30) { + vert[2]= (float) atof(val); + } else if (id==70) { + vflags= atoi(val); + } else if (id==71) { + vids[0]= abs(atoi(val)); + } else if (id==72) { + vids[1]= abs(atoi(val)); + } else if (id==73) { + vids[2]= abs(atoi(val)); + } else if (id==74) { + vids[3]= abs(atoi(val)); + } + read_group(id, val); + } + + if (vflags & 128 && vflags & 64) { + me->totvert++; + + /* If we are nearing the limit scan to the next entry */ + if(me->totvert > MESH_MAX_VERTS) + while(group_isnt(0, "SEQEND")) read_group(id, val); + + vtmp= MEM_callocN(me->totvert*sizeof(MVert), "mverts"); + + if(me->mvert) { + memcpy(vtmp, me->mvert, (me->totvert-1)*sizeof(MVert)); + MEM_freeN(me->mvert); + } + me->mvert= CustomData_set_layer(&me->vdata, CD_MVERT, vtmp); + vtmp=NULL; + + mvert= &me->mvert[(me->totvert-1)]; + + if (vspace) { VECCOPY(mvert->co, vert); + } else VecSubf(mvert->co, vert, vcenter); + + } else if (vflags & 128) { + if(vids[2]==0) { + error("(PL) Error parsing dxf, not enough vertices near line %d", dxf_line); + + error_exit=1; + fclose(dxf_fp); + return; + } + + me->totface++; + + ftmp= MEM_callocN(me->totface*sizeof(MFace), "mfaces"); + + if(me->mface) { + memcpy(ftmp, me->mface, (me->totface-1)*sizeof(MFace)); + MEM_freeN(me->mface); + } + me->mface= CustomData_set_layer(&me->fdata, CD_MFACE, ftmp); + ftmp=NULL; + + mface= &(((MFace*)me->mface)[me->totface-1]); + mface->v1= vids[0]-1; + mface->v2= vids[1]-1; + mface->v3= vids[2]-1; + + if(vids[3] && vids[3]!=vids[0]) { + mface->v4= vids[3]-1; + test_index_face(mface, NULL, 0, 4); + } + else test_index_face(mface, NULL, 0, 3); + + mface->mat_nr= 0; + + } else { + error("Error parsing dxf, unknown polyline information near %d", dxf_line); + + error_exit=1; + fclose(dxf_fp); + return; + } + + } + } +} + +static void dxf_read_lwpolyline(int noob) { + /* Entity specific vars */ + short vspace=0; /* Whether or not coords are relative */ + int flag=0; + int nverts=0; + int v; + + /* Blender vars */ + Object *ob; + Mesh *me; + float vert[3]; + + MVert *mvert; + MFace *mface; + + reset_vars; + + id = -1; + + /* block structure is + * {...} + * 90 => nverts + * 70 => flags + * nverts.times { 10 => x, 20 => y } + */ + while(id!=70) { + read_group(id, val); + if (id==8) { + BLI_strncpy(layname, val, sizeof(layname)); + } else if (id==38) { + vert[2]= (float) atof(val); + } else if (id==60) { + /* short invisible= atoi(val); */ + } else if (id==62) { + int colorid= atoi(val); + + CLAMP(colorid, 1, 255); + dxf_col_to_rgb(colorid, &color[0], &color[1], &color[2]); + } else if (id==67) { + vspace= atoi(val); + } else if (id==70) { + flag= atoi(val); + } else if (id==90) { + nverts= atoi(val); + } + } + printf("nverts %d\n", nverts); + if (nverts == 0) + return; + + dxf_get_mesh(&me, &ob, noob); + strcpy(oldllay, layname); + if(ob) VECCOPY(ob->loc, cent); + dxf_add_mat (ob, me, color, layname); + + me->totvert += nverts; + me->totface += nverts; + + me->mvert = (MVert*) MEM_callocN(me->totvert*sizeof(MVert), "mverts"); + me->mface = (MFace*) MEM_callocN(me->totface*sizeof(MVert), "mface"); + + CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert); + CustomData_set_layer(&me->fdata, CD_MFACE, me->mface); + + for (v = 0; v < nverts; v++) { + read_group(id,val); + if (id == 10) { + vert[0]= (float) atof(val); + } else { + error("Error parsing dxf, expected (10, ) at line %d", dxf_line); + } + + read_group(id,val); + if (id == 20) { + vert[1]= (float) atof(val); + } else { + error("Error parsing dxf, expected (20, ) at line %d", dxf_line); + } + + mvert = &me->mvert[v]; + + if (vspace) { + VECCOPY(mvert->co, vert); + } else { + VecSubf(mvert->co, vert, vcenter); + } + + if (v > 0) { + mface= &(((MFace*)me->mface)[v-1]); + mface->v1 = v-1; + mface->v2 = v; + mface->mat_nr = 0; + } + } + + /* flag & 1 -> closed polyline + * TODO: give the polyline actual 2D faces if it is closed */ + + if (flag&1) { + if(me->mface) { + mface= &(((MFace*)me->mface)[nverts - 1]); + mface->v1 = nverts-1; + mface->v2 = 0; + mface->mat_nr = 0; + } + } +} + + + /* 3D Face state vars */ +static Object *f3dhold=NULL; +static Mesh *f3dmhold=NULL; +static char oldflay[32]; +static short lwasf3d=0; /* last was face 3d? */ + +/* how can this function do anything useful (ton)? */ +static void dxf_close_3dface(void) +{ + f3dmhold= NULL; + if (f3dhold==NULL) return; + + f3dhold=NULL; +} + +static void dxf_read_3dface(int noob) +{ + /* Entity specific vars */ + float vert2[3]={0.0, 0.0, 0.0}; + float vert3[3]={0.0, 0.0, 0.0}; + float vert4[3]={0.0, 0.0, 0.0}; + short vspace=0; + + int nverts=0; + + /* Blender vars */ + Object *ob; + Mesh *me; + MVert *mvert, *vtmp; + MFace *mface, *ftmp; + + reset_vars; + + read_group(id, val); + while(id!=0) { + if (id==8) { + BLI_strncpy(layname, val, sizeof(layname)); + + /* First vert/origin */ + } else if (id==10) { + cent[0]= (float) atof(val); + if (nverts<1)nverts++; + } else if (id==20) { + cent[1]= (float) atof(val); + if (nverts<1)nverts++; + } else if (id==30) { + cent[2]= (float) atof(val); + if (nverts<1)nverts++; + + /* Second vert */ + } else if (id==11) { + vert2[0]= (float) atof(val); + if (nverts<2)nverts++; + } else if (id==21) { + vert2[1]= (float) atof(val); + if (nverts<2)nverts++; + } else if (id==31) { + vert2[2]= (float) atof(val); + if (nverts<2)nverts++; + + /* Third vert */ + } else if (id==12) { + vert3[0]= (float) atof(val); + if (nverts<3)nverts++; + } else if (id==22) { + vert3[1]= (float) atof(val); + if (nverts<3)nverts++; + } else if (id==32) { + vert3[2]= (float) atof(val); + if (nverts<3)nverts++; + + /* Fourth vert */ + } else if (id==13) { + vert4[0]= (float) atof(val); + if (nverts<4)nverts++; + } else if (id==23) { + vert4[1]= (float) atof(val); + if (nverts<4)nverts++; + } else if (id==33) { + vert4[2]= (float) atof(val); + if (nverts<4)nverts++; + + /* Other */ + } else if (id==60) { + /* short invisible= atoi(val); */ + } else if (id==62) { + int colorid= atoi(val); + + CLAMP(colorid, 1, 255); + dxf_col_to_rgb(colorid, &color[0], &color[1], &color[2]); + } else if (id==67) { + vspace= atoi(val); + } + read_group(id, val); + } + + /* Check to see if we need to make a new object */ + + if(!lwasf3d || strcmp(layname, oldflay)!=0) dxf_close_3dface(); + if(f3dmhold != NULL && f3dmhold->totvert>MESH_MAX_VERTS) + dxf_close_3dface(); + + if(nverts<3) { + error("(3DF) Error parsing dxf, not enough vertices near line %d", dxf_line); + + error_exit=1; + fclose(dxf_fp); + return; + } + + if (f3dmhold==NULL) { + dxf_get_mesh(&me, &ob, noob); + + strcpy(oldflay, layname); + + if(ob) VECCOPY(ob->loc, cent); + + dxf_add_mat (ob, me, color, layname); + + f3dhold= ob; + f3dmhold= me; + } else { + ob= f3dhold; + me= f3dmhold; + } + + me->totvert+= nverts; + me->totface++; + + vtmp= MEM_callocN(me->totvert*sizeof(MVert), "mverts"); + ftmp= MEM_callocN(me->totface*sizeof(MFace), "mface"); + + if(me->mvert) { + memcpy(vtmp, me->mvert, (me->totvert-nverts)*sizeof(MVert)); + MEM_freeN(me->mvert); + } + me->mvert= CustomData_set_layer(&me->vdata, CD_MVERT, vtmp); + vtmp=NULL; + + if(me->mface) { + memcpy(ftmp, me->mface, (me->totface-1)*sizeof(MFace)); + MEM_freeN(me->mface); + } + me->mface= CustomData_set_layer(&me->fdata, CD_MFACE, ftmp); + ftmp=NULL; + + mvert= &me->mvert[(me->totvert-nverts)]; + VecSubf(mvert->co, cent, vcenter); + + mvert++; + if (vspace) { VECCOPY(mvert->co, vert2); + } else VecSubf(mvert->co, vert2, vcenter); + + mvert++; + if (vspace) { VECCOPY(mvert->co, vert3); + } else VecSubf(mvert->co, vert3, vcenter); + + if (nverts==4) { + mvert++; + if (vspace) { VECCOPY(mvert->co, vert4); + } else VecSubf(mvert->co, vert4, vcenter); + } + + mface= &(((MFace*)me->mface)[me->totface-1]); + mface->v1= (me->totvert-nverts)+0; + mface->v2= (me->totvert-nverts)+1; + mface->v3= (me->totvert-nverts)+2; + + if (nverts==4) + mface->v4= (me->totvert-nverts)+3; + + mface->mat_nr= 0; + + test_index_face(mface, NULL, 0, nverts); + + hasbumped=1; +} + +static void dxf_read(char *filename) +{ + Mesh *lastMe = G.main->mesh.last; + + /* clear ugly global variables, that can hang because on error the code + below returns... tsk (ton) */ + dxf_line=0; + dxf_close_3dface(); + dxf_close_2dpoly(); + dxf_close_line(); + + dxf_fp= fopen(filename, "r"); + if (dxf_fp==NULL) return; + + while (1) { + read_group(id, val); + if (group_is(0, "EOF")) break; + + if (id==999) continue; + id_check(0, "SECTION"); + + read_group(id, val); + if (group_is(2, "HEADER")) { + } else if (group_is(2, "TABLES")) { + } else if (group_is(2, "OBJECTS")) { + } else if (group_is(2, "CLASSES")) { + } else if (group_is(2, "BLOCKS")) { + while(1) { + read_group(id, val); + if (group_is(0, "BLOCK")) { + while(group_isnt(0, "ENDBLK")) { + read_group(id, val); + + if(id==2) { + BLI_strncpy(entname, val, sizeof(entname)); + } else if (id==3) { + /* Now the object def should follow */ + if(strlen(entname)==0) { + error("Error parsing dxf, no mesh name near %d", dxf_line); + fclose(dxf_fp); + return; + } + + /* Now the object def should follow */ + while(group_isnt(0, "ENDBLK")) { + read_group(id, val); + + if(group_is(0, "POLYLINE")) { + dxf_read_polyline(1); + if(error_exit) return; + lwasf3d=0; + lwasline=0; + + while(group_isnt(0, "SEQEND")) read_group(id, val); + + } else if(group_is(0, "LWPOLYLINE")) { + dxf_read_lwpolyline(1); + if(error_exit) return; + lwasf3d=0; + lwasline=0; + + while(group_isnt(0, "SEQEND")) read_group(id, val); + } else if(group_is(0, "ATTRIB")) { + while(group_isnt(0, "SEQEND")) read_group(id, val); + lwasf3d=0; + lwasp2d=0; + lwasline=0; + } else if(group_is(0, "POINT")) { + dxf_read_point(1); + if(error_exit) return; + lwasf3d=0; + lwasp2d=0; + lwasline=0; + } else if(group_is(0, "LINE")) { + dxf_read_line(1); + if(error_exit) return; + lwasline=1; + lwasp2d=0; + lwasf3d=0; + } else if(group_is(0, "3DFACE")) { + dxf_read_3dface(1); + if(error_exit) return; + lwasf3d=1; + lwasp2d=0; + lwasline=0; + } else if (group_is(0, "CIRCLE")) { + dxf_read_arc(1); + } else if (group_is(0, "ELLIPSE")) { + dxf_read_ellipse(1); + } else if (group_is(0, "ENDBLK")) { + break; + } + } + } else if (group_is(0, "ENDBLK")) { + break; + } + } + while(id!=0) read_group(id, val); + + } else if(group_is(0, "ENDSEC")) { + break; + } + } + } else if (group_is(2, "ENTITIES")) { + while(group_isnt(0, "ENDSEC")) { + char obname[32]=""; + char layname[32]=""; + float cent[3]={0.0, 0.0, 0.0}; + float obsize[3]={1.0, 1.0, 1.0}; + float obrot[3]={0.0, 0.0, 0.0}; + + if(!hasbumped) read_group(id, val); + hasbumped=0; + if (group_is(0, "INSERT")) { + Base *base; + Object *ob; + void *obdata; + + read_group(id, val); + + while(id!=0) { + if(id==2) { + BLI_strncpy(obname, val, sizeof(obname)); + } else if (id==8) { + BLI_strncpy(layname, val, sizeof(layname)); + } else if (id==10) { + cent[0]= (float) atof(val); + } else if (id==20) { + cent[1]= (float) atof(val); + } else if (id==30) { + cent[2]= (float) atof(val); + } else if (id==41) { + obsize[0]= (float) atof(val); + } else if (id==42) { + obsize[1]= (float) atof(val); + } else if (id==43) { + obsize[2]= (float) atof(val); + } else if (id==50) { + obrot[2]= (float) (atof(val)*M_PI/180.0); + } else if (id==60) { + /* short invisible= atoi(val); */ + } + + read_group(id, val); + + } + + if(strlen(obname)==0) { + error("Error parsing dxf, no object name near %d", dxf_line); + fclose(dxf_fp); + return; + } + + obdata= find_id("ME", obname); + + if (obdata) { + ob= alloc_libblock(&G.main->object, ID_OB, obname); + + ob->type= OB_MESH; + + ob->dt= OB_SHADED; + if(U.flag & USER_MAT_ON_OB) ob->colbits= -1; + + ob->trackflag= OB_POSY; + ob->upflag= OB_POSZ; + + ob->ipoflag = OB_OFFS_OB+OB_OFFS_PARENT; + + ob->dupon= 1; ob->dupoff= 0; + ob->dupsta= 1; ob->dupend= 100; + ob->recalc= OB_RECALC; /* needed because of weird way of adding libdata directly */ + + G.totobj++; + + ob->data= obdata; + ((ID*)ob->data)->us++; + + VECCOPY(ob->loc, cent); + VECCOPY(ob->size, obsize); + VECCOPY(ob->rot, obrot); + + ob->mat= MEM_callocN(sizeof(void *)*1, "ob->mat"); + ob->totcol= (unsigned char) ((Mesh*)ob->data)->totcol; + ob->actcol= 1; + + /* note: materials are either linked to mesh or object, if both then + you have to increase user counts. below line is not needed. + I leave it commented out here as warning (ton) */ + //for (i=0; itotcol; i++) ob->mat[i]= ((Mesh*)ob->data)->mat[i]; + + if (strlen(layname)) ob->lay= dxf_get_layer_num(layname); + else ob->lay= G.scene->lay; + + /* link to scene */ + base= MEM_callocN( sizeof(Base), "add_base"); + BLI_addhead(&G.scene->base, base); + + base->lay= ob->lay; + + base->object= ob; + } + + hasbumped=1; + + lwasf3d=0; + lwasp2d=0; + lwasline=0; + } else if(group_is(0, "POLYLINE")) { + dxf_read_polyline(0); + if(error_exit) return; + lwasf3d=0; + lwasline=0; + + while(group_isnt(0, "SEQEND")) read_group(id, val); + + } else if(group_is(0, "LWPOLYLINE")) { + dxf_read_lwpolyline(0); + if(error_exit) return; + lwasf3d=0; + lwasline=0; + //while(group_isnt(0, "SEQEND")) read_group(id, val); + + } else if(group_is(0, "ATTRIB")) { + while(group_isnt(0, "SEQEND")) read_group(id, val); + lwasf3d=0; + lwasp2d=0; + lwasline=0; + } else if(group_is(0, "POINT")) { + dxf_read_point(0); + if(error_exit) return; + lwasf3d=0; + lwasp2d=0; + lwasline=0; + } else if(group_is(0, "LINE")) { + dxf_read_line(0); + if(error_exit) return; + lwasline=1; + lwasp2d=0; + lwasf3d=0; + } else if(group_is(0, "3DFACE")) { + dxf_read_3dface(0); + if(error_exit) return; + lwasline=0; + lwasp2d=0; + lwasf3d=1; + } else if (group_is(0, "CIRCLE") || group_is(0, "ARC")) { + dxf_read_arc(0); + } else if (group_is(0, "ELLIPSE")) { + dxf_read_ellipse(0); + } else if(group_is(0, "ENDSEC")) { + break; + } + } + } + + while(group_isnt(0, "ENDSEC")) read_group(id, val); + } + id_check(0, "EOF"); + + fclose (dxf_fp); + + /* Close any remaining state held stuff */ + dxf_close_3dface(); + dxf_close_2dpoly(); + dxf_close_line(); + + if (lastMe) { + lastMe = lastMe->id.next; + } else { + lastMe = G.main->mesh.first; + } + for (; lastMe; lastMe=lastMe->id.next) { + mesh_add_normals_flags(lastMe); + make_edges(lastMe, 0); + } +} diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c new file mode 100644 index 00000000000..fc11b3d234d --- /dev/null +++ b/source/blender/blenkernel/intern/font.c @@ -0,0 +1,1189 @@ +/* font.c + * + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_guardedalloc.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" +#include "BLI_vfontdata.h" + +#include "DNA_packedFile_types.h" +#include "DNA_curve_types.h" +#include "DNA_object_types.h" +#include "DNA_view3d_types.h" +#include "DNA_vfont_types.h" +#include "DNA_scene_types.h" + +#include "BKE_utildefines.h" +#include "BKE_bad_level_calls.h" + +#include "BKE_packedFile.h" + +#include "BKE_library.h" +#include "BKE_font.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_screen.h" +#include "BKE_anim.h" +#include "BKE_curve.h" +#include "BKE_displist.h" + +#define callocstructN(x,y,name) (x*)MEM_callocN((y)* sizeof(x),name) + +struct SelBox *selboxes= NULL; + +/* UTF-8 <-> wchar transformations */ +void +chtoutf8(unsigned long c, char *o) +{ + // Variables and initialization +/* memset(o, 0, 16); */ + + // Create the utf-8 string + if (c < 0x80) + { + o[0] = (char) c; + } + else if (c < 0x800) + { + o[0] = (0xC0 | (c>>6)); + o[1] = (0x80 | (c & 0x3f)); + } + else if (c < 0x10000) + { + o[0] = (0xe0 | (c >> 12)); + o[1] = (0x80 | (c >>6 & 0x3f)); + o[2] = (0x80 | (c & 0x3f)); + } + else if (c < 0x200000) + { + o[0] = (0xf0 | (c>>18)); + o[1] = (0x80 | (c >>12 & 0x3f)); + o[2] = (0x80 | (c >> 6 & 0x3f)); + o[3] = (0x80 | (c & 0x3f)); + } +} + +void +wcs2utf8s(char *dst, wchar_t *src) +{ + char ch[5]; + + while(*src) + { + memset(ch, 0, 5); + chtoutf8(*src++, ch); + strcat(dst, ch); + } +} + +int +wcsleninu8(wchar_t *src) +{ + char ch[16]; + int len = 0; + + while(*src) + { + memset(ch, 0, 16); + chtoutf8(*src++, ch); + len = len + strlen(ch); + } + + return len; +} + +int +utf8slen(char *src) +{ + int size = 0, index = 0; + unsigned char c; + + c = src[index++]; + while(c) + { + if((c & 0x80) == 0) + { + index += 0; + } + else if((c & 0xe0) == 0xe0) + { + index += 2; + } + else + { + index += 1; + } + size += 1; + c = src[index++]; + } + + return size; +} + +int utf8towchar_(wchar_t *w, char *c) +{ + int len=0; + if(w==NULL || c==NULL) return(0); + //printf("%s\n",c); + while(*c) + { + if(*c & 0x80) + { + if(*c & 0x40) + { + if(*c & 0x20) + { + if(*c & 0x10) + { + *w=(c[0] & 0x0f)<<18 | (c[1]&0x1f)<<12 | (c[2]&0x3f)<<6 | (c[3]&0x7f); + c++; + } + else + *w=(c[0] & 0x1f)<<12 | (c[1]&0x3f)<<6 | (c[2]&0x7f); + c++; + } + else + *w=(((c[0] &0x3f)<<6) | (c[1]&0x7f)); + c++; + } + else + *w=(c[0] & 0x7f); + } + else + *w=(c[0] & 0x7f); + c++; + w++; + len++; + } + return len; +} + +/* The vfont code */ +void free_vfont(struct VFont *vf) +{ + if (vf == 0) return; + + if (vf->data) { + while(vf->data->characters.first) + { + VChar *che = vf->data->characters.first; + + while (che->nurbsbase.first) { + Nurb *nu = che->nurbsbase.first; + if (nu->bezt) MEM_freeN(nu->bezt); + BLI_freelinkN(&che->nurbsbase, nu); + } + + BLI_freelinkN(&vf->data->characters, che); + } + + MEM_freeN(vf->data); + vf->data = NULL; + } + + if (vf->packedfile) { + freePackedFile(vf->packedfile); + vf->packedfile = NULL; + } +} + +static void *builtin_font_data= NULL; +static int builtin_font_size= 0; + +void BKE_font_register_builtin(void *mem, int size) +{ + builtin_font_data= mem; + builtin_font_size= size; +} + +static PackedFile *get_builtin_packedfile(void) +{ + if (!builtin_font_data) { + printf("Internal error, builtin font not loaded\n"); + + return NULL; + } else { + void *mem= MEM_mallocN(builtin_font_size, "vfd_builtin"); + + memcpy(mem, builtin_font_data, builtin_font_size); + + return newPackedFileMemory(mem, builtin_font_size); + } +} + +static VFontData *vfont_get_data(VFont *vfont) +{ + struct TmpFont *tmpfnt = NULL; + PackedFile *tpf; + + if(vfont==NULL) return NULL; + + // Try finding the font from font list + tmpfnt = G.ttfdata.first; + + while(tmpfnt) + { + if(tmpfnt->vfont == vfont) + break; + tmpfnt = tmpfnt->next; + } + + // And then set the data + if (!vfont->data) { + PackedFile *pf; + + if (BLI_streq(vfont->name, "")) { + pf= get_builtin_packedfile(); + } else { + if (vfont->packedfile) { + pf= vfont->packedfile; + + // We need to copy a tmp font to memory unless it is already there + if(!tmpfnt) + { + tpf= MEM_callocN(sizeof(*tpf), "PackedFile"); + tpf->data= MEM_mallocN(pf->size, "packFile"); + tpf->size= pf->size; + memcpy(tpf->data, pf->data, pf->size); + + // Add temporary packed file to globals + tmpfnt= (struct TmpFont *) MEM_callocN(sizeof(struct TmpFont), "temp_font"); + tmpfnt->pf= tpf; + tmpfnt->vfont= vfont; + BLI_addtail(&G.ttfdata, tmpfnt); + } + } else { + pf= newPackedFile(vfont->name); + + if(!tmpfnt) + { + tpf= newPackedFile(vfont->name); + + // Add temporary packed file to globals + tmpfnt= (struct TmpFont *) MEM_callocN(sizeof(struct TmpFont), "temp_font"); + tmpfnt->pf= tpf; + tmpfnt->vfont= vfont; + BLI_addtail(&G.ttfdata, tmpfnt); + } + } + if(!pf) { + printf("Font file doesn't exist: %s\n", vfont->name); + + strcpy(vfont->name, ""); + pf= get_builtin_packedfile(); + } + } + + if (pf) { +#ifdef WITH_FREETYPE2 + vfont->data= BLI_vfontdata_from_freetypefont(pf); +#else + vfont->data= BLI_vfontdata_from_psfont(pf); +#endif + if (pf != vfont->packedfile) { + freePackedFile(pf); + } + } + } + + return vfont->data; +} + +VFont *load_vfont(char *name) +{ + char filename[FILE_MAXFILE]; + VFont *vfont= NULL; + PackedFile *pf; + PackedFile *tpf = NULL; + int is_builtin; + struct TmpFont *tmpfnt; + + if (BLI_streq(name, "")) { + strcpy(filename, name); + + pf= get_builtin_packedfile(); + is_builtin= 1; + } else { + char dir[FILE_MAXDIR]; + + strcpy(dir, name); + BLI_splitdirstring(dir, filename); + + pf= newPackedFile(name); + tpf= newPackedFile(name); + + is_builtin= 0; + } + + if (pf) { + VFontData *vfd; + + waitcursor(1); + +#ifdef WITH_FREETYPE2 + vfd= BLI_vfontdata_from_freetypefont(pf); +#else + vfd= BLI_vfontdata_from_psfont(pf); +#endif + + if (vfd) { + vfont = alloc_libblock(&G.main->vfont, ID_VF, filename); + vfont->data = vfd; + + BLI_strncpy(vfont->name, name, sizeof(vfont->name)); + + // if autopack is on store the packedfile in de font structure + if (!is_builtin && (G.fileflags & G_AUTOPACK)) { + vfont->packedfile = pf; + } + + // Do not add to temporary listbase + if(strcmp(filename, "")) + { + tmpfnt= (struct TmpFont *) MEM_callocN(sizeof(struct TmpFont), "temp_font"); + tmpfnt->pf= tpf; + tmpfnt->vfont= vfont; + BLI_addtail(&G.ttfdata, tmpfnt); + } + } + + // Free the packed file + if (!vfont || vfont->packedfile != pf) { + freePackedFile(pf); + } + + waitcursor(0); + } + + return vfont; +} + +static VFont *which_vfont(Curve *cu, CharInfo *info) +{ + switch(info->flag & CU_STYLE) { + case CU_BOLD: + if (cu->vfontb) return(cu->vfontb); else return(cu->vfont); + case CU_ITALIC: + if (cu->vfonti) return(cu->vfonti); else return(cu->vfont); + case (CU_BOLD|CU_ITALIC): + if (cu->vfontbi) return(cu->vfontbi); else return(cu->vfont); + default: + return(cu->vfont); + } +} + +static void build_underline(Curve *cu, float x1, float y1, float x2, float y2, int charidx, short mat_nr) +{ + Nurb *nu2; + BPoint *bp; + + nu2 =(Nurb*) MEM_callocN(sizeof(Nurb),"underline_nurb"); + if (nu2 == NULL) return; + nu2->resolu= cu->resolu; + nu2->bezt = NULL; + nu2->knotsu = nu2->knotsv = 0; + nu2->flag= 0; + nu2->charidx = charidx+1000; + if (mat_nr > 0) nu2->mat_nr= mat_nr-1; + nu2->pntsu = 4; + nu2->pntsv = 1; + nu2->orderu = 4; + nu2->orderv = 1; + nu2->flagu = CU_CYCLIC; + + bp = (BPoint*)MEM_callocN(4 * sizeof(BPoint),"underline_bp"); + if (bp == 0){ + MEM_freeN(nu2); + return; + } + nu2->bp = bp; + + nu2->bp[0].vec[0] = x1; + nu2->bp[0].vec[1] = y1; + nu2->bp[0].vec[2] = 0; + nu2->bp[0].vec[3] = 1.0; + nu2->bp[1].vec[0] = x2; + nu2->bp[1].vec[1] = y1; + nu2->bp[1].vec[2] = 0; + nu2->bp[1].vec[3] = 1.0; + nu2->bp[2].vec[0] = x2; + nu2->bp[2].vec[1] = y2; + nu2->bp[2].vec[2] = 0; + nu2->bp[2].vec[3] = 1.0; + nu2->bp[3].vec[0] = x1; + nu2->bp[3].vec[1] = y2; + nu2->bp[3].vec[2] = 0; + nu2->bp[3].vec[3] = 1.0; + + nu2->type = CU_2D; + BLI_addtail(&(cu->nurb), nu2); + +} + +static void buildchar(Curve *cu, unsigned long character, CharInfo *info, float ofsx, float ofsy, float rot, int charidx) +{ + BezTriple *bezt1, *bezt2; + Nurb *nu1 = NULL, *nu2 = NULL; + float *fp, fsize, shear, x, si, co; + VFontData *vfd = NULL; + VChar *che = NULL; + int i, sel=0; + + vfd= vfont_get_data(which_vfont(cu, info)); + if (!vfd) return; + + if (cu->selend < cu->selstart) { + if ((charidx >= (cu->selend)) && (charidx <= (cu->selstart-2))) + sel= 1; + } + else { + if ((charidx >= (cu->selstart-1)) && (charidx <= (cu->selend-1))) + sel= 1; + } + + /* make a copy at distance ofsx,ofsy with shear*/ + fsize= cu->fsize; + shear= cu->shear; + si= (float)sin(rot); + co= (float)cos(rot); + + // Find the correct character from the font + che = vfd->characters.first; + while(che) + { + if(che->index == character) + break; + che = che->next; + } + + // Select the glyph data + if(che) + nu1 = che->nurbsbase.first; + + // Create the character + while(nu1) + { + bezt1 = nu1->bezt; + if (bezt1){ + nu2 =(Nurb*) MEM_mallocN(sizeof(Nurb),"duplichar_nurb"); + if (nu2 == 0) break; + memcpy(nu2, nu1, sizeof(struct Nurb)); + nu2->resolu= cu->resolu; + nu2->bp = 0; + nu2->knotsu = nu2->knotsv = 0; + nu2->flag= CU_SMOOTH; + nu2->charidx = charidx; + if (info->mat_nr) { + nu2->mat_nr= info->mat_nr-1; + } + else { + nu2->mat_nr= 0; + } + /* nu2->trim.first = 0; */ + /* nu2->trim.last = 0; */ + i = nu2->pntsu; + + bezt2 = (BezTriple*)MEM_mallocN(i * sizeof(BezTriple),"duplichar_bezt2"); + if (bezt2 == 0){ + MEM_freeN(nu2); + break; + } + memcpy(bezt2, bezt1, i * sizeof(struct BezTriple)); + nu2->bezt = bezt2; + + if (shear != 0.0) { + bezt2 = nu2->bezt; + + for (i= nu2->pntsu; i > 0; i--) { + bezt2->vec[0][0] += shear * bezt2->vec[0][1]; + bezt2->vec[1][0] += shear * bezt2->vec[1][1]; + bezt2->vec[2][0] += shear * bezt2->vec[2][1]; + bezt2++; + } + } + if(rot!=0.0) { + bezt2= nu2->bezt; + for (i=nu2->pntsu; i > 0; i--) { + fp= bezt2->vec[0]; + + x= fp[0]; + fp[0]= co*x + si*fp[1]; + fp[1]= -si*x + co*fp[1]; + x= fp[3]; + fp[3]= co*x + si*fp[4]; + fp[4]= -si*x + co*fp[4]; + x= fp[6]; + fp[6]= co*x + si*fp[7]; + fp[7]= -si*x + co*fp[7]; + + bezt2++; + } + } + bezt2 = nu2->bezt; + + for (i= nu2->pntsu; i > 0; i--) { + fp= bezt2->vec[0]; + + fp[0]= (fp[0]+ofsx)*fsize; + fp[1]= (fp[1]+ofsy)*fsize; + fp[3]= (fp[3]+ofsx)*fsize; + fp[4]= (fp[4]+ofsy)*fsize; + fp[6]= (fp[6]+ofsx)*fsize; + fp[7]= (fp[7]+ofsy)*fsize; + bezt2++; + } + + BLI_addtail(&(cu->nurb), nu2); + } + + nu1 = nu1->next; + } +} + +int getselection(int *start, int *end) +{ + Curve *cu; + + if (G.obedit==NULL || G.obedit->type != OB_FONT) return 0; + + cu= G.obedit->data; + + if (cu->selstart == 0) return 0; + if (cu->selstart <= cu->selend) { + *start = cu->selstart-1; + *end = cu->selend-1; + return 1; + } + else { + *start = cu->selend; + *end = cu->selstart-2; + return -1; + } +} + +struct chartrans *text_to_curve(Object *ob, int mode) +{ + VFont *vfont, *oldvfont; + VFontData *vfd= NULL; + Curve *cu, *cucu; + struct chartrans *chartransdata=NULL, *ct; + float distfac, tabfac, ctime, dtime, tvec[4], vec[4], rotvec[3], minx, maxx, miny, maxy; + float cmat[3][3], timeofs, si, co, sizefac; + float *f, maxlen=0, xof, yof, xtrax, linedist, *linedata, *linedata2, *linedata3, *linedata4; + int i, slen, oldflag, j; + short cnr=0, lnr=0, wsnr= 0; + wchar_t *mem, *tmp, ascii; + int outta; + float vecyo[3], curofs; + CharInfo *info; + float wsfac; + float ulwidth, uloverlap; + TextBox *tb; + int curbox; + int selstart, selend; + SelBox *sb= NULL; /* to please gcc */ + VChar *che; + float twidth; + int utf8len; + + /* renark: do calculations including the trailing '\0' of a string + because the cursor can be at that location */ + + if(ob->type!=OB_FONT) return 0; + + // Set font data + cu= (Curve *) ob->data; + vfont= cu->vfont; + + if(cu->str == 0) return 0; + if(vfont == 0) return 0; + + // Create unicode string + utf8len = utf8slen(cu->str); + tmp = mem = MEM_callocN(((utf8len + 1) * sizeof(wchar_t)), "convertedmem"); + + utf8towchar_(mem, cu->str); + + // Count the wchar_t string length + slen = wcslen(mem); + + if (cu->ulheight == 0.0) cu->ulheight = 0.05; + if (cu->strinfo==NULL) { /* old file */ + cu->strinfo = MEM_callocN((slen+1) * sizeof(CharInfo), "strinfo compat"); + } + if (cu->tb==NULL) { + cu->tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "TextBox compat"); + } + + vfd= vfont_get_data(vfont); + + /* The VFont Data can not be found */ + if(!vfd) + { + if(mem) + MEM_freeN(mem); + return 0; + } + + /* calc offset and rotation of each char */ + ct = chartransdata = + (struct chartrans*)MEM_callocN((slen+1)* sizeof(struct chartrans),"buildtext"); + + /* We assume the worst case: 1 character per line (is freed at end anyway) */ + + linedata= MEM_mallocN(sizeof(float)*(slen+2),"buildtext2"); + linedata2= MEM_mallocN(sizeof(float)*(slen+2),"buildtext3"); + linedata3= MEM_callocN(sizeof(float)*(slen+2),"buildtext4"); + linedata4= MEM_callocN(sizeof(float)*(slen+2),"buildtext5"); + + linedist= cu->linedist; + + xof= cu->xof + (cu->tb[0].x/cu->fsize); + yof= cu->yof + (cu->tb[0].y/cu->fsize); + + xtrax= 0.5f*cu->spacing-0.5f; + + oldvfont = NULL; + + for (i=0; istrinfo[i].flag &= ~CU_WRAP; + + if (selboxes) MEM_freeN(selboxes); + selboxes = NULL; + if (getselection(&selstart, &selend)) + selboxes = MEM_callocN((selend-selstart+1)*sizeof(SelBox), "font selboxes"); + + tb = &(cu->tb[0]); + curbox= 0; + for (i = 0 ; i<=slen ; i++) { + makebreak: + // Characters in the list + che = vfd->characters.first; + ascii = mem[i]; + info = &(cu->strinfo[i]); + vfont = which_vfont(cu, info); + + if(vfont==NULL) break; + + // Find the character + while(che) + { + if(che->index == ascii) + break; + che = che->next; + } + +#ifdef WITH_FREETYPE2 + // The character wasn't in the current curve base so load it + // But if the font is then do not try loading since whole font is in the memory already + if(che == NULL && strcmp(vfont->name, "")) + { + BLI_vfontchar_from_freetypefont(vfont, ascii); + } + + // Try getting the character again from the list + che = vfd->characters.first; + while(che) + { + if(che->index == ascii) + break; + che = che->next; + } +#endif + + /* No VFont found */ + if (vfont==0) + { + if(mem) + MEM_freeN(mem); + MEM_freeN(chartransdata); + return 0; + } + + if (vfont != oldvfont) { + vfd= vfont_get_data(vfont); + oldvfont = vfont; + } + + /* VFont Data for VFont couldn't be found */ + if (!vfd) + { + if(mem) + MEM_freeN(mem); + MEM_freeN(chartransdata); + return 0; + } + + // The character wasn't found, propably ascii = 0, then the width shall be 0 as well + if(!che) + { + twidth = 0; + } + else + { + twidth = che->width; + } + + // Calculate positions + if((tb->w != 0.0) && (ct->dobreak==0) && ((xof-(tb->x/cu->fsize)+twidth)*cu->fsize) > tb->w) { + // fprintf(stderr, "linewidth exceeded: %c%c%c...\n", mem[i], mem[i+1], mem[i+2]); + for (j=i; j && (mem[j] != '\n') && (mem[j] != '\r') && (chartransdata[j].dobreak==0); j--) { + if (mem[j]==' ' || mem[j]=='-') { + ct -= (i-(j-1)); + cnr -= (i-(j-1)); + if (mem[j] == ' ') wsnr--; + if (mem[j] == '-') wsnr++; + i = j-1; + xof = ct->xof; + ct[1].dobreak = 1; + cu->strinfo[i+1].flag |= CU_WRAP; + goto makebreak; + } + if (chartransdata[j].dobreak) { + // fprintf(stderr, "word too long: %c%c%c...\n", mem[j], mem[j+1], mem[j+2]); + ct->dobreak= 1; + cu->strinfo[i+1].flag |= CU_WRAP; + ct -= 1; + cnr -= 1; + i--; + xof = ct->xof; + goto makebreak; + } + } + } + if(ascii== '\n' || ascii== '\r' || ascii==0 || ct->dobreak) { + ct->xof= xof; + ct->yof= yof; + ct->linenr= lnr; + ct->charnr= cnr; + + yof-= linedist; + + maxlen= MAX2(maxlen, (xof-tb->x/cu->fsize)); + linedata[lnr]= xof-tb->x/cu->fsize; + linedata2[lnr]= cnr; + linedata3[lnr]= tb->w/cu->fsize; + linedata4[lnr]= wsnr; + + if ( (tb->h != 0.0) && + ((-(yof-(tb->y/cu->fsize))) > ((tb->h/cu->fsize)-(linedist*cu->fsize))) && + (cu->totbox > (curbox+1)) ) { + maxlen= 0; + tb++; + curbox++; + yof= cu->yof + tb->y/cu->fsize; + } + + if(ascii == '\n' || ascii == '\r') + xof = cu->xof; + else + xof= cu->xof + (tb->x/cu->fsize); + + xof= cu->xof + (tb->x/cu->fsize); + lnr++; + cnr= 0; + wsnr= 0; + } + else if(ascii==9) { /* TAB */ + ct->xof= xof; + ct->yof= yof; + ct->linenr= lnr; + ct->charnr= cnr++; + + tabfac= (xof-cu->xof+0.01f); + tabfac= (float)(2.0*ceil(tabfac/2.0)); + xof= cu->xof+tabfac; + } + else { + ct->xof= xof; + ct->yof= yof; + ct->linenr= lnr; + ct->charnr= cnr++; + + if (selboxes && (i>=selstart) && (i<=selend)) { + sb = &(selboxes[i-selstart]); + sb->y = yof*cu->fsize-linedist*cu->fsize*0.1; + sb->h = linedist*cu->fsize; + sb->w = xof*cu->fsize; + } + + if (ascii==32) { + wsfac = cu->wordspace; + wsnr++; + } else wsfac = 1.0; + // Set the width of the character + if(!che) + { + twidth = 0; + } + else + { + twidth = che->width; + } + xof += (twidth*wsfac*(1.0+(info->kern/40.0)) ) + xtrax; + + if (selboxes && (i>=selstart) && (i<=selend)) sb->w = (xof*cu->fsize) - sb->w; + } + ct++; + } + + + + cu->lines= 1; + ct= chartransdata; + tmp = mem; + for (i= 0; i<=slen; i++, tmp++, ct++) { + ascii = *tmp; + if(ascii== '\n' || ascii== '\r' || ct->dobreak) cu->lines++; + } + + // linedata is now: width of line + // linedata2 is now: number of characters + // linedata3 is now: maxlen of that line + // linedata4 is now: number of whitespaces of line + + if(cu->spacemode!=CU_LEFT) { + ct= chartransdata; + + if(cu->spacemode==CU_RIGHT) { + for(i=0;ixof+= linedata[ct->linenr]; + ct++; + } + } else if(cu->spacemode==CU_MIDDLE) { + for(i=0;ixof+= linedata[ct->linenr]; + ct++; + } + } else if((cu->spacemode==CU_FLUSH) && + (cu->tb[0].w != 0.0)) { + for(i=0;i1) + linedata[i]= (linedata3[i]-linedata[i])/(linedata2[i]-1); + for (i=0; i<=slen; i++) { + for (j=i; (mem[j]) && (mem[j]!='\n') && + (mem[j]!='\r') && (chartransdata[j].dobreak==0) && (jxof+= ct->charnr*linedata[ct->linenr]; +// } + ct++; + } + } else if((cu->spacemode==CU_JUSTIFY) && + (cu->tb[0].w != 0.0)) { + curofs= 0; + for (i=0; i<=slen; i++) { + for (j=i; (mem[j]) && (mem[j]!='\n') && + (mem[j]!='\r') && (chartransdata[j].dobreak==0) && (jlinenr]-linedata[ct->linenr])/linedata4[ct->linenr]; + ct->xof+= curofs; + } + if (mem[i]=='\n' || mem[i]=='\r' || chartransdata[i].dobreak) curofs= 0; + ct++; + } + } + } + + /* TEXT ON CURVE */ + if(cu->textoncurve) { + cucu= cu->textoncurve->data; + + oldflag= cucu->flag; + cucu->flag |= (CU_PATH+CU_FOLLOW); + + if(cucu->path==NULL) makeDispListCurveTypes(cu->textoncurve, 0); + if(cucu->path) { + float imat[4][4], imat3[3][3]; + Mat4Invert(imat, ob->obmat); + Mat3CpyMat4(imat3, imat); + + Mat3CpyMat4(cmat, cu->textoncurve->obmat); + Mat3MulMat3(cmat, cmat, imat3); + sizefac= Normalize(cmat[0])/cu->fsize; + + minx=miny= 1.0e20f; + maxx=maxy= -1.0e20f; + ct= chartransdata; + for (i=0; i<=slen; i++, ct++) { + if(minx>ct->xof) minx= ct->xof; + if(maxxxof) maxx= ct->xof; + if(miny>ct->yof) miny= ct->yof; + if(maxyyof) maxy= ct->yof; + } + + /* we put the x-coordinaat exact at the curve, the y is rotated */ + + /* length correction */ + distfac= sizefac*cucu->path->totdist/(maxx-minx); + timeofs= 0.0; + + if(distfac > 1.0) { + /* path longer than text: spacemode involves */ + distfac= 1.0f/distfac; + + if(cu->spacemode==CU_RIGHT) { + timeofs= 1.0f-distfac; + } + else if(cu->spacemode==CU_MIDDLE) { + timeofs= (1.0f-distfac)/2.0f; + } + else if(cu->spacemode==CU_FLUSH) distfac= 1.0f; + + } + else distfac= 1.0; + + distfac/= (maxx-minx); + + timeofs+= distfac*cu->xof; /* not cyclic */ + + ct= chartransdata; + for (i=0; i<=slen; i++, ct++) { + + /* rotate around center character */ + ascii = mem[i]; + + // Find the character + che = vfd->characters.first; + while(che) + { + if(che->index == ascii) + break; + che = che->next; + } + + if(che) + { + twidth = che->width; + } + else + { + twidth = 0; + } + + dtime= distfac*0.35f*twidth; /* why not 0.5? */ + dtime= distfac*0.5f*twidth; /* why not 0.5? */ + + ctime= timeofs + distfac*( ct->xof - minx); + CLAMP(ctime, 0.0, 1.0); + + /* calc the right loc AND the right rot separately */ + /* vec, tvec need 4 items */ + where_on_path(cu->textoncurve, ctime, vec, tvec); + where_on_path(cu->textoncurve, ctime+dtime, tvec, rotvec); + + VecMulf(vec, sizefac); + + ct->rot= (float)(M_PI-atan2(rotvec[1], rotvec[0])); + + si= (float)sin(ct->rot); + co= (float)cos(ct->rot); + + yof= ct->yof; + + ct->xof= vec[0] + si*yof; + ct->yof= vec[1] + co*yof; + + } + cucu->flag= oldflag; + } + } + + if (selboxes) { + ct= chartransdata; + for (i=0; i<=selend; i++, ct++) { + if (i>=selstart) { + selboxes[i-selstart].x = ct->xof*cu->fsize; + selboxes[i-selstart].y = ct->yof*cu->fsize; + } + } + } + + if(mode==FO_CURSUP || mode==FO_CURSDOWN || mode==FO_PAGEUP || mode==FO_PAGEDOWN) { + /* 2: curs up + 3: curs down */ + ct= chartransdata+cu->pos; + + if((mode==FO_CURSUP || mode==FO_PAGEUP) && ct->linenr==0); + else if((mode==FO_CURSDOWN || mode==FO_PAGEDOWN) && ct->linenr==lnr); + else { + switch(mode) { + case FO_CURSUP: lnr= ct->linenr-1; break; + case FO_CURSDOWN: lnr= ct->linenr+1; break; + case FO_PAGEUP: lnr= ct->linenr-10; break; + case FO_PAGEDOWN: lnr= ct->linenr+10; break; + } + cnr= ct->charnr; + /* seek for char with lnr en cnr */ + cu->pos= 0; + ct= chartransdata; + for (i= 0; ilinenr==lnr) { + if(ct->charnr==cnr) break; + if( (ct+1)->charnr==0) break; + } + else if(ct->linenr>lnr) break; + cu->pos++; + ct++; + } + } + } + + /* cursor first */ + if(ob==G.obedit) { + ct= chartransdata+cu->pos; + si= (float)sin(ct->rot); + co= (float)cos(ct->rot); + + f= G.textcurs[0]; + + f[0]= cu->fsize*(-0.1f*co + ct->xof); + f[1]= cu->fsize*(0.1f*si + ct->yof); + + f[2]= cu->fsize*(0.1f*co + ct->xof); + f[3]= cu->fsize*(-0.1f*si + ct->yof); + + f[4]= cu->fsize*( 0.1f*co + 0.8f*si + ct->xof); + f[5]= cu->fsize*(-0.1f*si + 0.8f*co + ct->yof); + + f[6]= cu->fsize*(-0.1f*co + 0.8f*si + ct->xof); + f[7]= cu->fsize*( 0.1f*si + 0.8f*co + ct->yof); + + } + + MEM_freeN(linedata); + MEM_freeN(linedata2); + MEM_freeN(linedata3); + MEM_freeN(linedata4); + + if (mode == FO_SELCHANGE) { + MEM_freeN(chartransdata); + MEM_freeN(mem); + return NULL; + } + + if(mode==0) { + /* make nurbdata */ + unsigned long cha; + + freeNurblist(&cu->nurb); + + ct= chartransdata; + if (cu->sepchar==0) { + for (i= 0; istrinfo[i]); + if (info->mat_nr > (ob->totcol)) { + /* printf("Error: Illegal material index (%d) in text object, setting to 0\n", info->mat_nr); */ + info->mat_nr = 0; + } + // We do not want to see any character for \n or \r + if(cha != '\n' && cha != '\r') + buildchar(cu, cha, info, ct->xof, ct->yof, ct->rot, i); + if ((info->flag & CU_UNDERLINE) && (cu->textoncurve == NULL) && (cha != '\n') && (cha != '\r')) { + uloverlap = 0; + if ( (i<(slen-1)) && (mem[i+1] != '\n') && (mem[i+1] != '\r') && + ((mem[i+1] != ' ') || (cu->strinfo[i+1].flag & CU_UNDERLINE)) && ((cu->strinfo[i+1].flag & CU_WRAP)==0) + ) { + uloverlap = xtrax + 0.1; + } + // Find the character, the characters has to be in the memory already + // since character checking has been done earlier already. + che = vfd->characters.first; + while(che) + { + if(che->index == cha) + break; + che = che->next; + } + + if(!che) twidth =0; else twidth=che->width; + ulwidth = cu->fsize * ((twidth* (1.0+(info->kern/40.0)))+uloverlap); + build_underline(cu, ct->xof*cu->fsize, ct->yof*cu->fsize + (cu->ulpos-0.05)*cu->fsize, + ct->xof*cu->fsize + ulwidth, + ct->yof*cu->fsize + (cu->ulpos-0.05)*cu->fsize - cu->ulheight*cu->fsize, + i, info->mat_nr); + } + ct++; + } + } + else { + outta = 0; + for (i= 0; (istrinfo[i]); + if (cu->sepchar == (i+1)) { + mem[0] = ascii; + mem[1] = 0; + cu->strinfo[0]= *info; + cu->pos = 1; + cu->len = 1; + vecyo[0] = ct->xof; + vecyo[1] = ct->yof; + vecyo[2] = 0; + Mat4MulVecfl(ob->obmat, vecyo); + VECCOPY(ob->loc, vecyo); + outta = 1; + cu->sepchar = 0; + } + ct++; + } + } + } + + if(mode==FO_DUPLI) { + MEM_freeN(mem); + return chartransdata; + } + + if(mem) + MEM_freeN(mem); + + MEM_freeN(chartransdata); + return 0; +} + + diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c new file mode 100644 index 00000000000..201d93220f9 --- /dev/null +++ b/source/blender/blenkernel/intern/group.c @@ -0,0 +1,327 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_action_types.h" +#include "DNA_effect_types.h" +#include "DNA_group_types.h" +#include "DNA_ID.h" +#include "DNA_ipo_types.h" +#include "DNA_material_types.h" +#include "DNA_object_types.h" +#include "DNA_nla_types.h" +#include "DNA_scene_types.h" + +#include "BLI_blenlib.h" + +#include "BKE_global.h" +#include "BKE_group.h" +#include "BKE_ipo.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_object.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +void free_group_object(GroupObject *go) +{ + MEM_freeN(go); +} + + +void free_group(Group *group) +{ + /* don't free group itself */ + GroupObject *go; + + while(group->gobject.first) { + go= group->gobject.first; + BLI_remlink(&group->gobject, go); + free_group_object(go); + } +} + +void unlink_group(Group *group) +{ + Material *ma; + Object *ob; + + for(ma= G.main->mat.first; ma; ma= ma->id.next) { + if(ma->group==group) + ma->group= NULL; + } + for(ob= G.main->object.first; ob; ob= ob->id.next) { + bActionStrip *strip; + PartEff *paf; + + if(ob->dup_group==group) { + ob->dup_group= NULL; + + /* duplicator strips use a group object, we remove it */ + for(strip= ob->nlastrips.first; strip; strip= strip->next) { + if(strip->object) + strip->object= NULL; + } + } + for(paf= ob->effect.first; paf; paf= paf->next) { + if(paf->type==EFF_PARTICLE) { + if(paf->group) + paf->group= NULL; + } + } + } + group->id.us= 0; +} + +Group *add_group(char *name) +{ + Group *group; + + group = alloc_libblock(&G.main->group, ID_GR, name); + group->layer= (1<<20)-1; + return group; +} + +/* external */ +void add_to_group(Group *group, Object *ob) +{ + GroupObject *go; + + if(group==NULL || ob==NULL) return; + + /* check if the object has been added already */ + for(go= group->gobject.first; go; go= go->next) { + if(go->ob==ob) return; + } + + go= MEM_callocN(sizeof(GroupObject), "groupobject"); + BLI_addtail( &group->gobject, go); + + go->ob= ob; + +} + +/* also used for ob==NULL */ +void rem_from_group(Group *group, Object *ob) +{ + GroupObject *go, *gon; + + if(group==NULL) return; + + go= group->gobject.first; + while(go) { + gon= go->next; + if(go->ob==ob) { + BLI_remlink(&group->gobject, go); + free_group_object(go); + } + go= gon; + } +} + +int object_in_group(Object *ob, Group *group) +{ + GroupObject *go; + + if(group==NULL || ob==NULL) return 0; + + for(go= group->gobject.first; go; go= go->next) { + if(go->ob==ob) + return 1; + } + return 0; +} + +Group *find_group(Object *ob) +{ + Group *group= G.main->group.first; + + while(group) { + if(object_in_group(ob, group)) + return group; + group= group->id.next; + } + return NULL; +} + +void group_tag_recalc(Group *group) +{ + GroupObject *go; + + if(group==NULL) return; + + for(go= group->gobject.first; go; go= go->next) { + if(go->ob) + go->ob->recalc= go->recalc; + } +} + +/* only replaces object strips or action when parent nla instructs it */ +/* keep checking nla.c though, in case internal structure of strip changes */ +static void group_replaces_nla(Object *parent, Object *target, char mode) +{ + static ListBase nlastrips={NULL, NULL}; + static bAction *action= NULL; + static int done= 0; + bActionStrip *strip, *nstrip; + + if(mode=='s') { + + for(strip= parent->nlastrips.first; strip; strip= strip->next) { + if(strip->object==target) { + if(done==0) { + /* clear nla & action from object */ + nlastrips= target->nlastrips; + target->nlastrips.first= target->nlastrips.last= NULL; + action= target->action; + target->action= NULL; + target->nlaflag |= OB_NLA_OVERRIDE; + done= 1; + } + nstrip= MEM_dupallocN(strip); + BLI_addtail(&target->nlastrips, nstrip); + } + } + } + else if(mode=='e') { + if(done) { + BLI_freelistN(&target->nlastrips); + target->nlastrips= nlastrips; + target->action= action; + + nlastrips.first= nlastrips.last= NULL; /* not needed, but yah... :) */ + action= NULL; + done= 0; + } + } +} + + +/* puts all group members in local timing system, after this call +you can draw everything, leaves tags in objects to signal it needs further updating */ + +/* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */ +void group_handle_recalc_and_update(Object *parent, Group *group) +{ + GroupObject *go; + + /* if animated group... */ + if(parent->sf != 0.0f || parent->nlastrips.first) { + int cfrao; + + /* switch to local time */ + cfrao= G.scene->r.cfra; + G.scene->r.cfra -= (int)parent->sf; + + /* we need a DAG per group... */ + for(go= group->gobject.first; go; go= go->next) { + if(go->ob && go->recalc) { + go->ob->recalc= go->recalc; + + group_replaces_nla(parent, go->ob, 's'); + object_handle_update(go->ob); + group_replaces_nla(parent, go->ob, 'e'); + + /* leave recalc tags in case group members are in normal scene */ + go->ob->recalc= go->recalc; + } + } + + /* restore */ + G.scene->r.cfra= cfrao; + } + else { + /* only do existing tags, as set by regular depsgraph */ + for(go= group->gobject.first; go; go= go->next) { + if(go->ob) { + if(go->ob->recalc) { + object_handle_update(go->ob); + } + } + } + } +} + +Object *group_get_member_with_action(Group *group, bAction *act) +{ + GroupObject *go; + + if(group==NULL || act==NULL) return NULL; + + for(go= group->gobject.first; go; go= go->next) { + if(go->ob) { + if(go->ob->action==act) + return go->ob; + if(go->ob->nlastrips.first) { + bActionStrip *strip; + + for(strip= go->ob->nlastrips.first; strip; strip= strip->next) { + if(strip->act==act) + return go->ob; + } + } + } + } + return NULL; +} + +/* if group has NLA, we try to map the used objects in NLA to group members */ +/* this assuming that object has received a new group link */ +void group_relink_nla_objects(Object *ob) +{ + Group *group; + GroupObject *go; + bActionStrip *strip; + + if(ob==NULL || ob->dup_group==NULL) return; + group= ob->dup_group; + + for(strip= ob->nlastrips.first; strip; strip= strip->next) { + if(strip->object) { + for(go= group->gobject.first; go; go= go->next) { + if(go->ob) { + if(strcmp(go->ob->id.name, strip->object->id.name)==0) + break; + } + } + if(go) + strip->object= go->ob; + else + strip->object= NULL; + } + + } +} + diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c new file mode 100644 index 00000000000..f144d2badd1 --- /dev/null +++ b/source/blender/blenkernel/intern/icons.c @@ -0,0 +1,302 @@ +/** +* $Id$ +* +* ***** BEGIN GPL LICENSE BLOCK ***** +* +* 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. +* +* The Original Code is Copyright (C) 2006-2007 Blender Foundation. +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): none yet. +* +* ***** END GPL LICENSE BLOCK ***** +* +*/ + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_guardedalloc.h" + +#include "DNA_ID.h" +#include "DNA_image_types.h" +#include "DNA_lamp_types.h" +#include "DNA_material_types.h" +#include "DNA_texture_types.h" +#include "DNA_world_types.h" + +#include "BLI_ghash.h" + +#include "BKE_icons.h" + +#define GS(a) (*((short *)(a))) + +/* GLOBALS */ + +static GHash* gIcons = NULL; + +static int gNextIconId = 1; + +static int gFirstIconId = 1; + + +static void icon_free(void *val) +{ + Icon* icon = val; + + if (icon) + { + if (icon->drawinfo_free) { + icon->drawinfo_free(icon->drawinfo); + } + else if (icon->drawinfo) { + MEM_freeN(icon->drawinfo); + } + MEM_freeN(icon); + } +} + +/* create an id for a new icon and make sure that ids from deleted icons get reused + after the integer number range is used up */ +static int get_next_free_id() +{ + int startId = gFirstIconId; + + /* if we haven't used up the int number range, we just return the next int */ + if (gNextIconId>=gFirstIconId) + return gNextIconId++; + + /* now we try to find the smallest icon id not stored in the gIcons hash */ + while (BLI_ghash_lookup(gIcons, (void *)startId) && startId>=gFirstIconId) + startId++; + + /* if we found a suitable one that isnt used yet, return it */ + if (startId>=gFirstIconId) + return startId; + + /* fail */ + return 0; +} + +void BKE_icons_init(int first_dyn_id) +{ + gNextIconId = first_dyn_id; + gFirstIconId = first_dyn_id; + + if (!gIcons) + gIcons = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp); +} + +void BKE_icons_free() +{ + if(gIcons) + BLI_ghash_free(gIcons, 0, icon_free); + gIcons = NULL; +} + +struct PreviewImage* BKE_previewimg_create() +{ + PreviewImage* prv_img = NULL; + int i; + + prv_img = MEM_callocN(sizeof(PreviewImage), "img_prv"); + + for (i=0; ichanged[i] = 1; + } + return prv_img; +} + +void BKE_previewimg_free(PreviewImage **prv) +{ + if(prv && (*prv)) { + int i; + + for (i=0; irect[i]) { + MEM_freeN((*prv)->rect[i]); + (*prv)->rect[i] = NULL; + } + } + MEM_freeN((*prv)); + *prv = NULL; + } +} + +struct PreviewImage* BKE_previewimg_copy(PreviewImage *prv) +{ + PreviewImage* prv_img = NULL; + int i; + + if (prv) { + prv_img = MEM_dupallocN(prv); + for (i=0; i < PREVIEW_MIPMAPS; ++i) { + if (prv->rect[i]) { + prv_img->rect[i] = MEM_dupallocN(prv->rect[i]); + } else { + prv_img->rect[i] = NULL; + } + } + } + return prv_img; +} + +void BKE_previewimg_free_id(ID *id) +{ + if (GS(id->name) == ID_MA) { + Material *mat = (Material*)id; + BKE_previewimg_free(&mat->preview); + } else if (GS(id->name) == ID_TE) { + Tex *tex = (Tex*)id; + BKE_previewimg_free(&tex->preview); + } else if (GS(id->name) == ID_WO) { + World *wo = (World*)id; + BKE_previewimg_free(&wo->preview); + } else if (GS(id->name) == ID_LA) { + Lamp *la = (Lamp*)id; + BKE_previewimg_free(&la->preview); + } else if (GS(id->name) == ID_IM) { + Image *img = (Image*)id; + BKE_previewimg_free(&img->preview); + } +} + +PreviewImage* BKE_previewimg_get(ID *id) +{ + PreviewImage* prv_img = NULL; + + if (GS(id->name) == ID_MA) { + Material *mat = (Material*)id; + if (!mat->preview) mat->preview = BKE_previewimg_create(); + prv_img = mat->preview; + } else if (GS(id->name) == ID_TE) { + Tex *tex = (Tex*)id; + if (!tex->preview) tex->preview = BKE_previewimg_create(); + prv_img = tex->preview; + } else if (GS(id->name) == ID_WO) { + World *wo = (World*)id; + if (!wo->preview) wo->preview = BKE_previewimg_create(); + prv_img = wo->preview; + } else if (GS(id->name) == ID_LA) { + Lamp *la = (Lamp*)id; + if (!la->preview) la->preview = BKE_previewimg_create(); + prv_img = la->preview; + } else if (GS(id->name) == ID_IM) { + Image *img = (Image*)id; + if (!img->preview) img->preview = BKE_previewimg_create(); + prv_img = img->preview; + } + + return prv_img; +} + +void BKE_icon_changed(int id) +{ + Icon* icon = 0; + + if (!id) return; + + icon = BLI_ghash_lookup(gIcons, (void *)id); + + if (icon) + { + PreviewImage *prv = BKE_previewimg_get((ID*)icon->obj); + + /* all previews changed */ + if (prv) { + int i; + for (i=0; ichanged[i] = 1; + } + } + } +} + +int BKE_icon_getid(struct ID* id) +{ + Icon* new_icon = 0; + + if (!id) + return 0; + + if (id->icon_id) + return id->icon_id; + + id->icon_id = get_next_free_id(); + + if (!id->icon_id){ + printf("BKE_icon_getid: Internal error - not enough IDs\n"); + return 0; + } + + new_icon = MEM_callocN(sizeof(Icon), "texicon"); + + new_icon->obj = id; + new_icon->type = GS(id->name); + + /* next two lines make sure image gets created */ + new_icon->drawinfo = 0; + new_icon->drawinfo_free = 0; + + BLI_ghash_insert(gIcons, (void *)id->icon_id, new_icon); + + return id->icon_id; +} + +Icon* BKE_icon_get(int icon_id) +{ + Icon* icon = 0; + + icon = BLI_ghash_lookup(gIcons, (void*)icon_id); + + if (!icon) { + printf("BKE_icon_get: Internal error, no icon for icon ID: %d\n", icon_id); + return 0; + } + + return icon; +} + +void BKE_icon_set(int icon_id, struct Icon* icon) +{ + Icon* old_icon = 0; + + old_icon = BLI_ghash_lookup(gIcons, (void*)icon_id); + + if (old_icon) + { + printf("BKE_icon_set: Internal error, icon already set: %d\n", icon_id); + return; + } + + BLI_ghash_insert(gIcons, (void *)icon_id, icon); +} + +void BKE_icon_delete(struct ID* id) +{ + + if (!id->icon_id) return; /* no icon defined for library object */ + + BLI_ghash_remove(gIcons, (void*)id->icon_id, 0, icon_free); + id->icon_id = 0; +} diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c new file mode 100644 index 00000000000..bf2a3aae11a --- /dev/null +++ b/source/blender/blenkernel/intern/idprop.c @@ -0,0 +1,443 @@ +/** + * $Id: idprop.c + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Joseph Eagar + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "DNA_listBase.h" +#include "DNA_ID.h" + +#include "BKE_idprop.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_utildefines.h" + +#include "BLI_blenlib.h" + +#include "MEM_guardedalloc.h" + +#include +#include +#include + +#define BSTR_EQ(a, b) (*(a) == *(b) && !strcmp(a, b)) + +/* IDPropertyTemplate is a union in DNA_ID.h */ + +/*local size table.*/ +static char idp_size_table[] = { + 1, /*strings*/ + sizeof(int), + sizeof(float), + sizeof(float)*3, /*Vector type, deprecated*/ + sizeof(float)*16, /*Matrix type, deprecated*/ + 0, /*arrays don't have a fixed size*/ + sizeof(ListBase), /*Group type*/ + sizeof(void*) +}; + + +/* ----------- Array Type ----------- */ + +/*this function works for strings too!*/ +void IDP_ResizeArray(IDProperty *prop, int newlen) +{ + void *newarr; + int newsize=newlen; + + /*first check if the array buffer size has room*/ + /*if newlen is 200 chars less then totallen, reallocate anyway*/ + if (newlen <= prop->totallen && prop->totallen - newlen < 200) { + prop->len = newlen; + return; + } + + /* - Note: This code comes from python, here's the corrusponding comment. - */ + /* This over-allocates proportional to the list size, making room + * for additional growth. The over-allocation is mild, but is + * enough to give linear-time amortized behavior over a long + * sequence of appends() in the presence of a poorly-performing + * system realloc(). + * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... + */ + newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize; + + newarr = MEM_callocN(idp_size_table[prop->type]*newsize, "idproperty array resized"); + /*newlen is bigger*/ + if (newlen >= prop->len) memcpy(newarr, prop->data.pointer, prop->len*idp_size_table[prop->type]); + /*newlen is smaller*/ + else memcpy(newarr, prop->data.pointer, newlen*prop->len*idp_size_table[prop->type]); + + MEM_freeN(prop->data.pointer); + prop->data.pointer = newarr; + prop->len = newlen; + prop->totallen = newsize; +} + + void IDP_FreeArray(IDProperty *prop) +{ + if (prop->data.pointer) + MEM_freeN(prop->data.pointer); +} + + + static IDProperty *idp_generic_copy(IDProperty *prop) + { + IDProperty *newp = MEM_callocN(sizeof(IDProperty), "IDProperty array dup"); + + strncpy(newp->name, prop->name, MAX_IDPROP_NAME); + newp->type = prop->type; + newp->flag = prop->flag; + newp->data.val = prop->data.val; + + return newp; + } + +IDProperty *IDP_CopyArray(IDProperty *prop) +{ + IDProperty *newp = idp_generic_copy(prop); + + if (prop->data.pointer) newp->data.pointer = MEM_dupallocN(prop->data.pointer); + newp->len = prop->len; + newp->subtype = prop->subtype; + newp->totallen = prop->totallen; + + return newp; +} + +/*taken from readfile.c*/ +#define SWITCH_LONGINT(a) { \ + char s_i, *p_i; \ + p_i= (char *)&(a); \ + s_i=p_i[0]; p_i[0]=p_i[7]; p_i[7]=s_i; \ + s_i=p_i[1]; p_i[1]=p_i[6]; p_i[6]=s_i; \ + s_i=p_i[2]; p_i[2]=p_i[5]; p_i[5]=s_i; \ + s_i=p_i[3]; p_i[3]=p_i[4]; p_i[4]=s_i; } + + + +/* ---------- String Type ------------ */ +IDProperty *IDP_CopyString(IDProperty *prop) +{ + IDProperty *newp = idp_generic_copy(prop); + + if (prop->data.pointer) newp->data.pointer = MEM_dupallocN(prop->data.pointer); + newp->len = prop->len; + newp->subtype = prop->subtype; + newp->totallen = prop->totallen; + + return newp; +} + + +void IDP_AssignString(IDProperty *prop, char *st) +{ + int stlen; + + stlen = strlen(st); + + IDP_ResizeArray(prop, stlen+1); /*make room for null byte :) */ + strcpy(prop->data.pointer, st); +} + +void IDP_ConcatStringC(IDProperty *prop, char *st) +{ + int newlen; + + newlen = prop->len + strlen(st); + /*we have to remember that prop->len includes the null byte for strings. + so there's no need to add +1 to the resize function.*/ + IDP_ResizeArray(prop, newlen); + strcat(prop->data.pointer, st); +} + +void IDP_ConcatString(IDProperty *str1, IDProperty *append) +{ + int newlen; + + /*since ->len for strings includes the NULL byte, we have to subtract one or + we'll get an extra null byte after each concatination operation.*/ + newlen = str1->len + append->len - 1; + IDP_ResizeArray(str1, newlen); + strcat(str1->data.pointer, append->data.pointer); +} + +void IDP_FreeString(IDProperty *prop) +{ + MEM_freeN(prop->data.pointer); +} + + +/*-------- ID Type, not in use yet -------*/ + +void IDP_LinkID(IDProperty *prop, ID *id) +{ + if (prop->data.pointer) ((ID*)prop->data.pointer)->us--; + prop->data.pointer = id; + id_us_plus(id); +} + +void IDP_UnlinkID(IDProperty *prop) +{ + ((ID*)prop->data.pointer)->us--; +} + +/*-------- Group Functions -------*/ + +/*checks if a property with the same name as prop exists, and if so replaces it.*/ +IDProperty *IDP_CopyGroup(IDProperty *prop) +{ + IDProperty *newp = idp_generic_copy(prop), *link; + + for (link=prop->data.group.first; link; link=link->next) { + BLI_addtail(&newp->data.group, IDP_CopyProperty(link)); + } + + return newp; +} + +void IDP_ReplaceInGroup(IDProperty *group, IDProperty *prop) +{ + IDProperty *loop; + for (loop=group->data.group.first; loop; loop=loop->next) { + if (BSTR_EQ(loop->name, prop->name)) { + if (loop->next) BLI_insertlinkbefore(&group->data.group, loop->next, prop); + else BLI_addtail(&group->data.group, prop); + BLI_remlink(&group->data.group, loop); + IDP_FreeProperty(loop); + MEM_freeN(loop); + group->len++; + return; + } + } + + group->len++; + BLI_addtail(&group->data.group, prop); +} + +/*returns 0 if an id property with the same name exists and it failed, + or 1 if it succeeded in adding to the group.*/ +int IDP_AddToGroup(IDProperty *group, IDProperty *prop) +{ + IDProperty *loop; + for (loop=group->data.group.first; loop; loop=loop->next) { + if (BSTR_EQ(loop->name, prop->name)) return 0; + } + + group->len++; + BLI_addtail(&group->data.group, prop); + + return 1; +} + +int IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew) +{ + IDProperty *loop; + for (loop=group->data.group.first; loop; loop=loop->next) { + if (BSTR_EQ(loop->name, pnew->name)) return 0; + } + + group->len++; + + BLI_insertlink(&group->data.group, previous, pnew); + return 1; +} + +void IDP_RemFromGroup(IDProperty *group, IDProperty *prop) +{ + group->len--; + BLI_remlink(&group->data.group, prop); +} + +IDProperty *IDP_GetPropertyFromGroup(IDProperty *prop, char *name) +{ + IDProperty *loop; + for (loop=prop->data.group.first; loop; loop=loop->next) { + if (strcmp(loop->name, name)==0) return loop; + } + return NULL; +} + +typedef struct IDPIter { + void *next; + IDProperty *parent; +} IDPIter; + +void *IDP_GetGroupIterator(IDProperty *prop) +{ + IDPIter *iter = MEM_callocN(sizeof(IDPIter), "IDPIter"); + iter->next = prop->data.group.first; + iter->parent = prop; + return (void*) iter; +} + +IDProperty *IDP_GroupIterNext(void *vself) +{ + IDPIter *self = (IDPIter*) vself; + Link *next = (Link*) self->next; + if (self->next == NULL) { + MEM_freeN(self); + return NULL; + } + + self->next = next->next; + return (void*) next; +} + +void IDP_FreeIterBeforeEnd(void *vself) +{ + MEM_freeN(vself); +} + +/*Ok, the way things work, Groups free the ID Property structs of their children. + This is because all ID Property freeing functions free only direct data (not the ID Property + struct itself), but for Groups the child properties *are* considered + direct data.*/ +void IDP_FreeGroup(IDProperty *prop) +{ + IDProperty *loop, *next; + for (loop=prop->data.group.first; loop; loop=next) + { + next = loop->next; + BLI_remlink(&prop->data.group, loop); + IDP_FreeProperty(loop); + MEM_freeN(loop); + } +} + + +/*-------- Main Functions --------*/ +IDProperty *IDP_CopyProperty(IDProperty *prop) +{ + switch (prop->type) { + case IDP_GROUP: return IDP_CopyGroup(prop); + case IDP_STRING: return IDP_CopyString(prop); + case IDP_ARRAY: return IDP_CopyArray(prop); + default: return idp_generic_copy(prop); + } +} + +IDProperty *IDP_GetProperties(ID *id, int create_if_needed) +{ + if (id->properties) return id->properties; + else { + if (create_if_needed) { + id->properties = MEM_callocN(sizeof(IDProperty), "IDProperty"); + id->properties->type = IDP_GROUP; + } + return id->properties; + } +} + +IDProperty *IDP_New(int type, IDPropertyTemplate val, char *name) +{ + IDProperty *prop=NULL; + + switch (type) { + case IDP_INT: + prop = MEM_callocN(sizeof(IDProperty), "IDProperty int"); + prop->data.val = val.i; + break; + case IDP_FLOAT: + prop = MEM_callocN(sizeof(IDProperty), "IDProperty float"); + *(float*)&prop->data.val = val.f; + break; + case IDP_ARRAY: + { + /*for now, we only support float and int arrays*/ + if (val.array.type == IDP_FLOAT || val.array.type == IDP_INT) { + prop = MEM_callocN(sizeof(IDProperty), "IDProperty array"); + prop->len = prop->totallen = val.array.len; + prop->subtype = val.array.type; + prop->data.pointer = MEM_callocN(idp_size_table[val.array.type]*val.array.len, "id property array"); + break; + } else { + return NULL; + } + } + case IDP_STRING: + { + char *st = val.str; + int stlen; + + prop = MEM_callocN(sizeof(IDProperty), "IDProperty string"); + if (st == NULL) { + prop->data.pointer = MEM_callocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1"); + prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS; + prop->len = 1; /*NULL string, has len of 1 to account for null byte.*/ + } else { + stlen = strlen(st) + 1; + prop->data.pointer = MEM_callocN(stlen, "id property string 2"); + prop->len = prop->totallen = stlen; + strcpy(prop->data.pointer, st); + } + break; + } + case IDP_GROUP: + { + prop = MEM_callocN(sizeof(IDProperty), "IDProperty group"); + /* heh I think all needed values are set properly by calloc anyway :) */ + break; + } + default: + { + prop = MEM_callocN(sizeof(IDProperty), "IDProperty array"); + break; + } + } + + prop->type = type; + strncpy(prop->name, name, MAX_IDPROP_NAME); + return prop; +} + +/*NOTE: this will free all child properties of list arrays and groups! + Also, note that this does NOT unlink anything! Plus it doesn't free + the actual IDProperty struct either.*/ +void IDP_FreeProperty(IDProperty *prop) +{ + switch (prop->type) { + case IDP_ARRAY: + IDP_FreeArray(prop); + break; + case IDP_STRING: + IDP_FreeString(prop); + break; + case IDP_GROUP: + IDP_FreeGroup(prop); + break; + } +} + +/*Unlinks any IDProperty<->ID linkage that might be going on.*/ +void IDP_UnlinkProperty(IDProperty *prop) +{ + switch (prop->type) { + case IDP_ID: + IDP_UnlinkID(prop); + } +} diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c new file mode 100644 index 00000000000..17a4dfd3db9 --- /dev/null +++ b/source/blender/blenkernel/intern/image.c @@ -0,0 +1,1805 @@ +/* image.c + * + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation, 2006 + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include +#include +#include +#include +#ifndef WIN32 +#include +#else +#include +#endif + +#include + +#include "MEM_guardedalloc.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#ifdef WITH_OPENEXR +#include "intern/openexr/openexr_multi.h" +#endif + +#include "DNA_image_types.h" +#include "DNA_packedFile_types.h" +#include "DNA_scene_types.h" +#include "DNA_camera_types.h" +#include "DNA_texture_types.h" +#include "DNA_userdef_types.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" +#include "BLI_threads.h" + +#include "BKE_bmfont.h" +#include "BKE_global.h" +#include "BKE_icons.h" +#include "BKE_image.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_packedFile.h" +#include "BKE_scene.h" +#include "BKE_texture.h" +#include "BKE_utildefines.h" + +#include "PIL_time.h" + +#include "RE_pipeline.h" + +/* bad level; call to free_realtime_image */ +#include "BKE_bad_level_calls.h" + +/* for stamp drawing to an image */ +#include "BMF_Api.h" + +#include "blendef.h" +#include "BSE_time.h" + +/* max int, to indicate we don't store sequences in ibuf */ +#define IMA_NO_INDEX 0x7FEFEFEF + +/* quick lookup: supports 1 million frames, thousand passes */ +#define IMA_MAKE_INDEX(frame, index) ((frame)<<10)+index +#define IMA_INDEX_FRAME(index) (index>>10) + +/* ******** IMAGE PROCESSING ************* */ + +/* used by sequencer */ +void converttopremul(struct ImBuf *ibuf) +{ + int x, y, val; + char *cp; + + if(ibuf==0) return; + if(ibuf->depth==24) { /* put alpha at 255 */ + + cp= (char *)(ibuf->rect); + for(y=0; yy; y++) { + for(x=0; xx; x++, cp+=4) { + cp[3]= 255; + } + } + return; + } + + cp= (char *)(ibuf->rect); + for(y=0; yy; y++) { + for(x=0; xx; x++, cp+=4) { + if(cp[3]==0) { + cp[0]= cp[1]= cp[2]= 0; + } + else if(cp[3]!=255) { + val= cp[3]; + cp[0]= (cp[0]*val)>>8; + cp[1]= (cp[1]*val)>>8; + cp[2]= (cp[2]*val)>>8; + } + } + } +} + +static void de_interlace_ng(struct ImBuf *ibuf) /* neogeo fields */ +{ + struct ImBuf * tbuf1, * tbuf2; + + if (ibuf == 0) return; + if (ibuf->flags & IB_fields) return; + ibuf->flags |= IB_fields; + + if (ibuf->rect) { + /* make copies */ + tbuf1 = IMB_allocImBuf(ibuf->x, (short)(ibuf->y >> 1), (unsigned char)32, (int)IB_rect, (unsigned char)0); + tbuf2 = IMB_allocImBuf(ibuf->x, (short)(ibuf->y >> 1), (unsigned char)32, (int)IB_rect, (unsigned char)0); + + ibuf->x *= 2; + + IMB_rectcpy(tbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y); + IMB_rectcpy(tbuf2, ibuf, 0, 0, tbuf2->x, 0, ibuf->x, ibuf->y); + + ibuf->x /= 2; + IMB_rectcpy(ibuf, tbuf1, 0, 0, 0, 0, tbuf1->x, tbuf1->y); + IMB_rectcpy(ibuf, tbuf2, 0, tbuf2->y, 0, 0, tbuf2->x, tbuf2->y); + + IMB_freeImBuf(tbuf1); + IMB_freeImBuf(tbuf2); + } + ibuf->y /= 2; +} + +static void de_interlace_st(struct ImBuf *ibuf) /* standard fields */ +{ + struct ImBuf * tbuf1, * tbuf2; + + if (ibuf == 0) return; + if (ibuf->flags & IB_fields) return; + ibuf->flags |= IB_fields; + + if (ibuf->rect) { + /* make copies */ + tbuf1 = IMB_allocImBuf(ibuf->x, (short)(ibuf->y >> 1), (unsigned char)32, IB_rect, 0); + tbuf2 = IMB_allocImBuf(ibuf->x, (short)(ibuf->y >> 1), (unsigned char)32, IB_rect, 0); + + ibuf->x *= 2; + + IMB_rectcpy(tbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y); + IMB_rectcpy(tbuf2, ibuf, 0, 0, tbuf2->x, 0, ibuf->x, ibuf->y); + + ibuf->x /= 2; + IMB_rectcpy(ibuf, tbuf2, 0, 0, 0, 0, tbuf2->x, tbuf2->y); + IMB_rectcpy(ibuf, tbuf1, 0, tbuf2->y, 0, 0, tbuf1->x, tbuf1->y); + + IMB_freeImBuf(tbuf1); + IMB_freeImBuf(tbuf2); + } + ibuf->y /= 2; +} + +void image_de_interlace(Image *ima, int odd) +{ + ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); + if(ibuf) { + if(odd) + de_interlace_st(ibuf); + else + de_interlace_ng(ibuf); + } +} + +/* ***************** ALLOC & FREE, DATA MANAGING *************** */ + +static void image_free_buffers(Image *ima) +{ + ImBuf *ibuf; + + while((ibuf = ima->ibufs.first)) { + BLI_remlink(&ima->ibufs, ibuf); + + if (ibuf->userdata) { + MEM_freeN(ibuf->userdata); + ibuf->userdata = NULL; + } + IMB_freeImBuf(ibuf); + } + + if(ima->anim) IMB_free_anim(ima->anim); + ima->anim= NULL; + + if(ima->rr) { + RE_FreeRenderResult(ima->rr); + ima->rr= NULL; + } + + free_realtime_image(ima); + + ima->ok= IMA_OK; +} + +/* called by library too, do not free ima itself */ +void free_image(Image *ima) +{ + + image_free_buffers(ima); + if (ima->packedfile) { + freePackedFile(ima->packedfile); + ima->packedfile = NULL; + } + BKE_icon_delete(&ima->id); + ima->id.icon_id = 0; + if (ima->preview) { + BKE_previewimg_free(&ima->preview); + } + +} + +/* only image block itself */ +static Image *image_alloc(const char *name, short source, short type) +{ + Image *ima; + + ima= alloc_libblock(&G.main->image, ID_IM, name); + if(ima) { + ima->ok= IMA_OK; + + ima->xrep= ima->yrep= 1; + ima->aspx= ima->aspy= 1.0; + ima->gen_x= 256; ima->gen_y= 256; + ima->gen_type= 1; /* no defines yet? */ + + ima->source= source; + ima->type= type; + } + return ima; +} + +/* get the ibuf from an image cache, local use here only */ +static ImBuf *image_get_ibuf(Image *ima, int index, int frame) +{ + if(index==IMA_NO_INDEX) + return ima->ibufs.first; + else { + ImBuf *ibuf; + + index= IMA_MAKE_INDEX(frame, index); + for(ibuf= ima->ibufs.first; ibuf; ibuf= ibuf->next) + if(ibuf->index==index) + return ibuf; + return NULL; + } +} + +/* no ima->ibuf anymore, but listbase */ +static void image_remove_ibuf(Image *ima, ImBuf *ibuf) +{ + if(ibuf) { + BLI_remlink(&ima->ibufs, ibuf); + IMB_freeImBuf(ibuf); + } +} + + +/* no ima->ibuf anymore, but listbase */ +static void image_assign_ibuf(Image *ima, ImBuf *ibuf, int index, int frame) +{ + if(ibuf) { + ImBuf *link; + + if(index!=IMA_NO_INDEX) + index= IMA_MAKE_INDEX(frame, index); + + /* insert based on index */ + for(link= ima->ibufs.first; link; link= link->next) + if(link->index>=index) + break; + /* now we don't want copies? */ + if(link && ibuf->index==link->index) { + ImBuf *prev= ibuf->prev; + image_remove_ibuf(ima, link); + link= prev; + } + + /* this function accepts link==NULL */ + BLI_insertlinkbefore(&ima->ibufs, link, ibuf); + + ibuf->index= index; + } + +} + +/* checks if image was already loaded, then returns same image */ +/* otherwise creates new. */ +/* does not load ibuf itself */ +Image *BKE_add_image_file(const char *name) +{ + Image *ima; + int file, len; + const char *libname; + char str[FILE_MAX], strtest[FILE_MAX]; + + /* escape when name is directory */ + len= strlen(name); + if(len) { + if(name[len-1]=='/' || name[len-1]=='\\') + return NULL; + } + + BLI_strncpy(str, name, sizeof(str)); + BLI_convertstringcode(str, G.sce, G.scene->r.cfra); + + /* exists? */ + file= open(str, O_BINARY|O_RDONLY); + if(file== -1) return NULL; + close(file); + + /* first search an identical image */ + for(ima= G.main->image.first; ima; ima= ima->id.next) { + if(ima->source!=IMA_SRC_VIEWER) { + BLI_strncpy(strtest, ima->name, sizeof(ima->name)); + BLI_convertstringcode(strtest, G.sce, G.scene->r.cfra); + + if( strcmp(strtest, str)==0 ) { + if(ima->anim==NULL || ima->id.us==0) { + BLI_strncpy(ima->name, name, sizeof(ima->name)); /* for stringcode */ + ima->id.us++; /* officially should not, it doesn't link here! */ + if(ima->ok==0) + ima->ok= IMA_OK; + /* RETURN! */ + return ima; + } + } + } + } + /* add new image */ + + /* create a short library name */ + len= strlen(name); + + while (len > 0 && name[len - 1] != '/' && name[len - 1] != '\\') len--; + libname= name+len; + + ima= image_alloc(libname, IMA_SRC_FILE, IMA_TYPE_IMAGE); + BLI_strncpy(ima->name, name, sizeof(ima->name)); + + /* do a wild guess! */ + if(BLI_testextensie(name, ".avi") || BLI_testextensie(name, ".mov") + || BLI_testextensie(name, ".mpg") || BLI_testextensie(name, ".mp4")) + ima->source= IMA_SRC_MOVIE; + + return ima; +} + +static ImBuf *add_ibuf_size(int width, int height, char *name, short uvtestgrid, float color[4]) +{ + ImBuf *ibuf; + float h=0.0, hoffs=0.0, hue=0.0, s=0.9, v=0.9, r, g, b; + unsigned char *rect; + int x, y; + int checkerwidth=21, dark=1; + + ibuf= IMB_allocImBuf(width, height, 24, IB_rect, 0); + strcpy(ibuf->name, "Untitled"); + ibuf->userflags |= IB_BITMAPDIRTY; + + rect= (unsigned char*)ibuf->rect; + + if (uvtestgrid) { + /* these two passes could be combined into one, but it's more readable and + * easy to tweak like this, speed isn't really that much of an issue in this situation... */ + + /* checkers */ + for(y=0; yy; y++) { + dark = pow(-1, floor(y / checkerwidth)); + + for(x=0; xx; x++, rect+=4) { + if (x % checkerwidth == 0) dark *= -1; + + if (dark > 0) { + rect[0] = rect[1] = rect[2] = 64; + rect[3] = 255; + } else { + rect[0] = rect[1] = rect[2] = 150; + rect[3] = 255; + } + } + } + + /* 2nd pass, colored + */ + rect= (unsigned char*)ibuf->rect; + + for(y=0; yy; y++) { + hoffs = 0.125 * floor(y / checkerwidth); + + for(x=0; xx; x++, rect+=4) { + h = 0.125 * floor(x / checkerwidth); + + if ((fabs((x % checkerwidth) - (checkerwidth / 2)) < 4) && + (fabs((y % checkerwidth) - (checkerwidth / 2)) < 4)) { + + if ((fabs((x % checkerwidth) - (checkerwidth / 2)) < 1) || + (fabs((y % checkerwidth) - (checkerwidth / 2)) < 1)) { + + hue = fmod(fabs(h-hoffs), 1.0); + hsv_to_rgb(hue, s, v, &r, &g, &b); + + rect[0]= (char)(r * 255.0); + rect[1]= (char)(g * 255.0); + rect[2]= (char)(b * 255.0); + rect[3]= 255; + } + } + + } + } + } else { /* blank image */ + for(y=0; yy; y++) { + for(x=0; xx; x++, rect+=4) { + rect[0]= (char)(color[0] * 255.0); + rect[1]= (char)(color[1] * 255.0); + rect[2]= (char)(color[2] * 255.0); + rect[3]= (char)(color[3] * 255.0); + } + } + } + return ibuf; +} + +/* adds new image block, creates ImBuf and initializes color */ +Image *BKE_add_image_size(int width, int height, char *name, short uvtestgrid, float color[4]) +{ + Image *ima; + + /* on save, type is changed to FILE in editsima.c */ + ima= image_alloc(name, IMA_SRC_GENERATED, IMA_TYPE_UV_TEST); + + if (ima) { + ImBuf *ibuf; + + BLI_strncpy(ima->name, name, FILE_MAX); + ima->gen_x= width; + ima->gen_y= height; + ima->gen_type= uvtestgrid; + + ibuf= add_ibuf_size(width, height, name, uvtestgrid, color); + image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); + + ima->ok= IMA_OK_LOADED; + } + + return ima; +} + +/* packs rect from memory as PNG */ +void BKE_image_memorypack(Image *ima) +{ + ImBuf *ibuf= image_get_ibuf(ima, IMA_NO_INDEX, 0); + + if(ibuf==NULL) + return; + if (ima->packedfile) { + freePackedFile(ima->packedfile); + ima->packedfile = NULL; + } + + ibuf->ftype= PNG; + ibuf->depth= 32; + + IMB_saveiff(ibuf, ibuf->name, IB_rect | IB_mem); + if(ibuf->encodedbuffer==NULL) { + printf("memory save for pack error\n"); + } + else { + PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile"); + + pf->data = ibuf->encodedbuffer; + pf->size = ibuf->encodedsize; + ima->packedfile= pf; + ibuf->encodedbuffer= NULL; + ibuf->encodedsize= 0; + ibuf->userflags &= ~IB_BITMAPDIRTY; + + if(ima->source==IMA_SRC_GENERATED) { + ima->source= IMA_SRC_FILE; + ima->type= IMA_TYPE_IMAGE; + } + } +} + +void tag_image_time(Image *ima) +{ + if (ima) + ima->lastused = (int)PIL_check_seconds_timer(); +} + +void tag_all_images_time() +{ + Image *ima; + int ctime = (int)PIL_check_seconds_timer(); + + ima= G.main->image.first; + while(ima) { + if(ima->bindcode || ima->repbind || ima->ibufs.first) { + ima->lastused = ctime; + } + } +} + +void free_old_images() +{ + Image *ima; + static int lasttime = 0; + int ctime = (int)PIL_check_seconds_timer(); + + /* + Run garbage collector once for every collecting period of time + if textimeout is 0, that's the option to NOT run the collector + */ + if (U.textimeout == 0 || ctime % U.texcollectrate || ctime == lasttime) + return; + + lasttime = ctime; + + ima= G.main->image.first; + while(ima) { + if((ima->flag & IMA_NOCOLLECT)==0 && ctime - ima->lastused > U.textimeout) { + /* + If it's in GL memory, deallocate and set time tag to current time + This gives textures a "second chance" to be used before dying. + */ + if(ima->bindcode || ima->repbind) { + free_realtime_image(ima); + ima->lastused = ctime; + } + /* Otherwise, just kill the buffers */ + else if (ima->ibufs.first) { + image_free_buffers(ima); + } + } + ima = ima->id.next; + } +} + +void BKE_image_free_all_textures(void) +{ + Tex *tex; + Image *ima; + unsigned int totsize= 0; + + for(ima= G.main->image.first; ima; ima= ima->id.next) + ima->id.flag &= ~LIB_DOIT; + + for(tex= G.main->tex.first; tex; tex= tex->id.next) + if(tex->ima) + tex->ima->id.flag |= LIB_DOIT; + + for(ima= G.main->image.first; ima; ima= ima->id.next) { + if(ima->ibufs.first && (ima->id.flag & LIB_DOIT)) { + ImBuf *ibuf; + for(ibuf= ima->ibufs.first; ibuf; ibuf= ibuf->next) { + if(ibuf->mipmap[0]) + totsize+= 1.33*ibuf->x*ibuf->y*4; + else + totsize+= ibuf->x*ibuf->y*4; + } + image_free_buffers(ima); + } + } + /* printf("freed total %d MB\n", totsize/(1024*1024)); */ +} + +/* except_frame is weak, only works for seqs without offset... */ +void BKE_image_free_anim_ibufs(Image *ima, int except_frame) +{ + ImBuf *ibuf, *nbuf; + + for(ibuf= ima->ibufs.first; ibuf; ibuf= nbuf) { + nbuf= ibuf->next; + if(ibuf->userflags & IB_BITMAPDIRTY) + continue; + if(ibuf->index==IMA_NO_INDEX) + continue; + if(except_frame!=IMA_INDEX_FRAME(ibuf->index)) { + BLI_remlink(&ima->ibufs, ibuf); + + if (ibuf->userdata) { + MEM_freeN(ibuf->userdata); + ibuf->userdata = NULL; + } + IMB_freeImBuf(ibuf); + } + } +} + +void BKE_image_all_free_anim_ibufs(int cfra) +{ + Image *ima; + + for(ima= G.main->image.first; ima; ima= ima->id.next) + if(ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) + BKE_image_free_anim_ibufs(ima, cfra); +} + + +/* *********** READ AND WRITE ************** */ + +int BKE_imtype_to_ftype(int imtype) +{ + if(imtype==0) + return TGA; + else if(imtype== R_IRIS) + return IMAGIC; + else if (imtype==R_RADHDR) + return RADHDR; + else if (imtype==R_PNG) + return PNG; +#ifdef WITH_DDS + else if (imtype==R_DDS) + return DDS; +#endif + else if (imtype==R_BMP) + return BMP; + else if (imtype==R_TIFF) + return TIF; + else if (imtype==R_OPENEXR || imtype==R_MULTILAYER) + return OPENEXR; + else if (imtype==R_CINEON) + return CINEON; + else if (imtype==R_DPX) + return DPX; + else if (imtype==R_TARGA) + return TGA; + else if(imtype==R_RAWTGA) + return RAWTGA; + else if(imtype==R_HAMX) + return AN_hamx; + else + return JPG|90; +} + +int BKE_ftype_to_imtype(int ftype) +{ + if(ftype==0) + return TGA; + else if(ftype == IMAGIC) + return R_IRIS; + else if (ftype & RADHDR) + return R_RADHDR; + else if (ftype & PNG) + return R_PNG; +#ifdef WITH_DDS + else if (ftype & DDS) + return R_DDS; +#endif + else if (ftype & BMP) + return R_BMP; + else if (ftype & TIF) + return R_TIFF; + else if (ftype & OPENEXR) + return R_OPENEXR; + else if (ftype & CINEON) + return R_CINEON; + else if (ftype & DPX) + return R_DPX; + else if (ftype & TGA) + return R_TARGA; + else if(ftype & RAWTGA) + return R_RAWTGA; + else if(ftype == AN_hamx) + return R_HAMX; + else + return R_JPEG90; +} + + +int BKE_imtype_is_movie(int imtype) +{ + switch(imtype) { + case R_MOVIE: + case R_AVIRAW: + case R_AVIJPEG: + case R_AVICODEC: + case R_QUICKTIME: + case R_FFMPEG: + case R_FRAMESERVER: + return 1; + } + return 0; +} + +void BKE_add_image_extension(char *string, int imtype) +{ + char *extension=""; + + if(G.scene->r.imtype== R_IRIS) { + if(!BLI_testextensie(string, ".rgb")) + extension= ".rgb"; + } + else if(imtype==R_IRIZ) { + if(!BLI_testextensie(string, ".rgb")) + extension= ".rgb"; + } + else if(imtype==R_RADHDR) { + if(!BLI_testextensie(string, ".hdr")) + extension= ".hdr"; + } + else if(imtype==R_PNG) { + if(!BLI_testextensie(string, ".png")) + extension= ".png"; + } +#ifdef WITH_DDS + else if(imtype==R_DDS) { + if(!BLI_testextensie(string, ".dds")) + extension= ".dds"; + } +#endif + else if(imtype==R_RAWTGA) { + if(!BLI_testextensie(string, ".tga")) + extension= ".tga"; + } + else if(ELEM5(imtype, R_MOVIE, R_AVICODEC, R_AVIRAW, R_AVIJPEG, R_JPEG90)) { + if(!BLI_testextensie(string, ".jpg")) + extension= ".jpg"; + } + else if(imtype==R_BMP) { + if(!BLI_testextensie(string, ".bmp")) + extension= ".bmp"; + } + else if(G.have_libtiff && (imtype==R_TIFF)) { + if(!BLI_testextensie(string, ".tif")) + extension= ".tif"; + } +#ifdef WITH_OPENEXR + else if( ELEM(imtype, R_OPENEXR, R_MULTILAYER)) { + if(!BLI_testextensie(string, ".exr")) + extension= ".exr"; + } +#endif + else if(imtype==R_CINEON){ + if (!BLI_testextensie(string, ".cin")) + extension= ".cin"; + } + else if(imtype==R_DPX){ + if (!BLI_testextensie(string, ".dpx")) + extension= ".dpx"; + } + else { /* targa default */ + if(!BLI_testextensie(string, ".tga")) + extension= ".tga"; + } + + strcat(string, extension); +} + +/* could allow access externally */ +typedef struct StampData { + char file[512]; + char note[512]; + char date[512]; + char marker[512]; + char time[512]; + char frame[512]; + char camera[512]; + char scene[512]; +} StampData; + +static void stampdata(StampData *stamp_data, int do_prefix) +{ + char text[256]; + +#ifndef WIN32 + struct tm *tl; + time_t t; +#else + char sdate[9]; +#endif /* WIN32 */ + + if (do_prefix) sprintf(stamp_data->file, "File %s", G.sce); + else sprintf(stamp_data->file, "%s", G.sce); + + if (G.scene->r.stamp & R_STAMP_NOTE) { + if (do_prefix) sprintf(stamp_data->note, "Note %s", G.scene->r.stamp_udata); + else sprintf(stamp_data->note, "%s", G.scene->r.stamp_udata); + } else { + stamp_data->note[0] = '\0'; + } + + if (G.scene->r.stamp & R_STAMP_DATE) { +#ifdef WIN32 + _strdate (sdate); + sprintf (text, "%s", sdate); +#else + t = time (NULL); + tl = localtime (&t); + sprintf (text, "%04d-%02d-%02d", tl->tm_year+1900, tl->tm_mon+1, tl->tm_mday); +#endif /* WIN32 */ + if (do_prefix) sprintf(stamp_data->date, "Date %s", text); + else sprintf(stamp_data->date, "%s", text); + } else { + stamp_data->date[0] = '\0'; + } + + if (G.scene->r.stamp & R_STAMP_MARKER) { + TimeMarker *marker = get_frame_marker(CFRA); + + if (marker) strcpy(text, marker->name); + else strcpy(text, ""); + + if (do_prefix) sprintf(stamp_data->marker, "Marker %s", text); + else sprintf(stamp_data->marker, "%s", text); + } else { + stamp_data->marker[0] = '\0'; + } + + if (G.scene->r.stamp & R_STAMP_TIME) { + int h, m, s, f; + h= m= s= f= 0; + f = (int)(G.scene->r.cfra % G.scene->r.frs_sec); + s = (int)(G.scene->r.cfra / G.scene->r.frs_sec); + + if (s) { + m = (int)(s / 60); + s %= 60; + + if (m) { + h = (int)(m / 60); + m %= 60; + } + } + + if (G.scene->r.frs_sec < 100) + sprintf (text, "%02d:%02d:%02d.%02d", h, m, s, f); + else + sprintf (text, "%02d:%02d:%02d.%03d", h, m, s, f); + + if (do_prefix) sprintf(stamp_data->time, "Time %s", text); + else sprintf(stamp_data->time, "%s", text); + } else { + stamp_data->time[0] = '\0'; + } + + if (G.scene->r.stamp & R_STAMP_FRAME) { + char format[32]; + if (do_prefix) sprintf(format, "Frame %%0%di\n", 1 + (int) log10(G.scene->r.efra)); + else sprintf(format, "%%0%di\n", 1 + (int) log10(G.scene->r.efra)); + sprintf (stamp_data->frame, format, G.scene->r.cfra); + } else { + stamp_data->frame[0] = '\0'; + } + + if (G.scene->r.stamp & R_STAMP_CAMERA) { + if (do_prefix) sprintf(stamp_data->camera, "Camera %s", ((Camera *) G.scene->camera)->id.name+2); + else sprintf(stamp_data->camera, "%s", ((Camera *) G.scene->camera)->id.name+2); + } else { + stamp_data->camera[0] = '\0'; + } + + if (G.scene->r.stamp & R_STAMP_SCENE) { + if (do_prefix) sprintf(stamp_data->scene, "Scene %s", G.scene->id.name+2); + else sprintf(stamp_data->scene, "%s", G.scene->id.name+2); + } else { + stamp_data->scene[0] = '\0'; + } +} + +void BKE_stamp_buf(unsigned char *rect, float *rectf, int width, int height) +{ + struct StampData stamp_data; + + int x=1,y=1; + int font_height; + int text_width; + int text_pad; + struct BMF_Font *font; + + if (!rect && !rectf) + return; + + stampdata(&stamp_data, 1); + + switch (G.scene->r.stamp_font_id) { + case 1: /* tiny */ + font = BMF_GetFont(BMF_kHelveticaBold8); + break; + case 2: /* small */ + font = BMF_GetFont(BMF_kHelveticaBold10); + break; + case 3: /* medium */ + font = BMF_GetFont(BMF_kScreen12); + break; + case 0: /* large - default */ + font = BMF_GetFont(BMF_kScreen15); + break; + case 4: /* huge */ + font = BMF_GetFont(BMF_kHelveticaBold14); + break; + default: + font = NULL; + break; + } + + font_height = BMF_GetFontHeight(font); + /* All texts get halfspace+1 pixel on each side and 1 pix + above and below as padding against their backing rectangles */ + text_pad = BMF_GetStringWidth(font, " "); + + + if (stamp_data.file[0]) { + /* Top left corner */ + x = 1; /* Inits for everyone, text position, so 1 for padding, not 0 */ + y = height - font_height - 1; /* Also inits for everyone, notice padding pixel */ + text_width = BMF_GetStringWidth(font, stamp_data.file); + buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); + BMF_DrawStringBuf(font, stamp_data.file, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height); + y -= font_height+2; /* Top and bottom 1 pix padding each */ + } + + /* Top left corner, below File */ + if (stamp_data.note[0]) { + text_width = BMF_GetStringWidth(font, stamp_data.note); + buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); + BMF_DrawStringBuf(font, stamp_data.note, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height); + y -= font_height+2; /* Top and bottom 1 pix padding each */ + } + + /* Top left corner, below File (or Note) */ + if (stamp_data.date[0]) { + text_width = BMF_GetStringWidth(font, stamp_data.date); + buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); + BMF_DrawStringBuf(font, stamp_data.date, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height); + } + + /* Bottom left corner, leaving space for timing */ + if (stamp_data.marker[0]) { + x = 1; + y = font_height+2+1; /* 2 for padding in TIME|FRAME fields below and 1 for padding in this one */ + text_width = BMF_GetStringWidth(font, stamp_data.marker); + buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); + BMF_DrawStringBuf(font, stamp_data.marker, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height); + } + + /* Left bottom corner */ + if (stamp_data.time[0]) { + x = 1; + y = 1; + text_width = BMF_GetStringWidth(font, stamp_data.time); + buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); + BMF_DrawStringBuf(font, stamp_data.time, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height); + x += text_width+text_pad+2; /* Both sides have 1 pix additional padding each */ + } + + if (stamp_data.frame[0]) { + text_width = BMF_GetStringWidth(font, stamp_data.frame); + /* Left bottom corner (after SMPTE if exists) */ + if (!stamp_data.time[0]) x = 1; + y = 1; + buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); + BMF_DrawStringBuf(font, stamp_data.frame, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height); + } + + if (stamp_data.camera[0]) { + text_width = BMF_GetStringWidth(font, stamp_data.camera); + /* Center of bottom edge */ + x = (width/2) - (BMF_GetStringWidth(font, stamp_data.camera)/2); + y = 1; + buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); + BMF_DrawStringBuf(font, stamp_data.camera, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height); + } + + if (stamp_data.scene[0]) { + text_width = BMF_GetStringWidth(font, stamp_data.scene); + /* Bottom right corner */ + x = width - (text_width+1+text_pad); + y = 1; + buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); + BMF_DrawStringBuf(font, stamp_data.scene, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height); + } +} + + +void BKE_stamp_info(struct ImBuf *ibuf) +{ + struct StampData stamp_data; + + if (!ibuf) return; + + /* fill all the data values, no prefix */ + stampdata(&stamp_data, 0); + + if (stamp_data.file[0]) IMB_imginfo_change_field (ibuf, "File", stamp_data.file); + if (stamp_data.note[0]) IMB_imginfo_change_field (ibuf, "Note", stamp_data.note); + if (stamp_data.date[0]) IMB_imginfo_change_field (ibuf, "Date", stamp_data.date); + if (stamp_data.marker[0]) IMB_imginfo_change_field (ibuf, "Marker", stamp_data.marker); + if (stamp_data.time[0]) IMB_imginfo_change_field (ibuf, "Time", stamp_data.time); + if (stamp_data.frame[0]) IMB_imginfo_change_field (ibuf, "Frame", stamp_data.frame); + if (stamp_data.camera[0]) IMB_imginfo_change_field (ibuf, "Camera", stamp_data.camera); + if (stamp_data.scene[0]) IMB_imginfo_change_field (ibuf, "Scene", stamp_data.scene); +} + +int BKE_write_ibuf(ImBuf *ibuf, char *name, int imtype, int subimtype, int quality) +{ + int ok; + + if(imtype==0); + else if(imtype== R_IRIS) + ibuf->ftype= IMAGIC; + else if ((imtype==R_RADHDR)) { + ibuf->ftype= RADHDR; + } + else if ((imtype==R_PNG)) { + ibuf->ftype= PNG; + } +#ifdef WITH_DDS + else if ((imtype==R_DDS)) { + ibuf->ftype= DDS; + } +#endif + else if ((imtype==R_BMP)) { + ibuf->ftype= BMP; + } + else if ((G.have_libtiff) && (imtype==R_TIFF)) { + ibuf->ftype= TIF; + } +#ifdef WITH_OPENEXR + else if (imtype==R_OPENEXR || imtype==R_MULTILAYER) { + ibuf->ftype= OPENEXR; + if(subimtype & R_OPENEXR_HALF) + ibuf->ftype |= OPENEXR_HALF; + ibuf->ftype |= (quality & OPENEXR_COMPRESS); + + if(!(subimtype & R_OPENEXR_ZBUF)) + ibuf->zbuf_float = NULL; /* signal for exr saving */ + + } +#endif + else if (imtype==R_CINEON) { + ibuf->ftype = CINEON; + } + else if (imtype==R_DPX) { + ibuf->ftype = DPX; + } + else if (imtype==R_TARGA) { + ibuf->ftype= TGA; + } + else if(imtype==R_RAWTGA) { + ibuf->ftype= RAWTGA; + } + else if(imtype==R_HAMX) { + ibuf->ftype= AN_hamx; + } + else { + /* R_JPEG90, R_MOVIE, etc. default we save jpegs */ + if(quality < 10) quality= 90; + ibuf->ftype= JPG|quality; + if(ibuf->depth==32) ibuf->depth= 24; /* unsupported feature only confuses other s/w */ + } + + BLI_make_existing_file(name); + + if(G.scene->r.scemode & R_STAMP_INFO) + BKE_stamp_info(ibuf); + + ok = IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat); + if (ok == 0) { + perror(name); + } + + return(ok); +} + + +void BKE_makepicstring(char *string, char *base, int frame, int imtype) +{ + short i, len, digits= 4; /* digits in G.scene? */ + char num[10]; + + if (string==NULL) return; + + BLI_strncpy(string, base, FILE_MAX - 10); /* weak assumption */ + BLI_convertstringcode(string, G.sce, frame); + + len= strlen(string); + + i= digits - sprintf(num, "%d", frame); + for(; i>0; i--){ + string[len]= '0'; + len++; + } + string[len]= 0; + strcat(string, num); + + if(G.scene->r.scemode & R_EXTENSION) + BKE_add_image_extension(string, imtype); + +} + +/* used by sequencer too */ +struct anim *openanim(char *name, int flags) +{ + struct anim *anim; + struct ImBuf *ibuf; + + anim = IMB_open_anim(name, flags); + if (anim == NULL) return(0); + + ibuf = IMB_anim_absolute(anim, 0); + if (ibuf == NULL) { + printf("not an anim; %s\n", name); + IMB_free_anim(anim); + return(0); + } + IMB_freeImBuf(ibuf); + + return(anim); +} + +/* ************************* New Image API *************** */ + + +/* Notes about Image storage +- packedfile + -> written in .blend +- filename + -> written in .blend +- movie + -> comes from packedfile or filename +- renderresult + -> comes from packedfile or filename +- listbase + -> ibufs from exrhandle +- flipbook array + -> ibufs come from movie, temporary renderresult or sequence +- ibuf + -> comes from packedfile or filename or generated + +*/ + + +/* forces existance of 1 Image for renderout or nodes, returns Image */ +/* name is only for default, when making new one */ +Image *BKE_image_verify_viewer(int type, const char *name) +{ + Image *ima; + + for(ima=G.main->image.first; ima; ima= ima->id.next) + if(ima->source==IMA_SRC_VIEWER) + if(ima->type==type) + break; + + if(ima==NULL) + ima= image_alloc(name, IMA_SRC_VIEWER, type); + + /* happens on reload, imagewindow cannot be image user when hidden*/ + if(ima->id.us==0) + id_us_plus(&ima->id); + + return ima; +} + +void BKE_image_assign_ibuf(Image *ima, ImBuf *ibuf) +{ + image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); +} + +void BKE_image_signal(Image *ima, ImageUser *iuser, int signal) +{ + if(ima==NULL) + return; + + switch(signal) { + case IMA_SIGNAL_FREE: + image_free_buffers(ima); + if(iuser) + iuser->ok= 1; + break; + case IMA_SIGNAL_SRC_CHANGE: + if(ima->type==IMA_TYPE_MULTILAYER) + image_free_buffers(ima); + else if(ima->source==IMA_SRC_GENERATED) { + if(ima->gen_x==0 || ima->gen_y==0) { + ImBuf *ibuf= image_get_ibuf(ima, IMA_NO_INDEX, 0); + if(ibuf) { + ima->gen_x= ibuf->x; + ima->gen_y= ibuf->y; + } + } + } + ima->ok= 1; + if(iuser) + iuser->ok= 1; + break; + + case IMA_SIGNAL_RELOAD: + /* try to repack file */ + if(ima->packedfile) { + PackedFile *pf; + pf = newPackedFile(ima->name); + if (pf) { + freePackedFile(ima->packedfile); + ima->packedfile = pf; + image_free_buffers(ima); + } else { + printf("ERROR: Image not available. Keeping packed image\n"); + } + } + else + image_free_buffers(ima); + + if(iuser) + iuser->ok= 1; + + break; + case IMA_SIGNAL_USER_NEW_IMAGE: + if(iuser) { + iuser->ok= 1; + if(ima->source==IMA_SRC_FILE || ima->source==IMA_SRC_SEQUENCE) { + if(ima->type==IMA_TYPE_MULTILAYER) { + iuser->multi_index= 0; + iuser->layer= iuser->pass= 0; + } + } + } + break; + } +} + +/* if layer or pass changes, we need an index for the imbufs list */ +/* note it is called for rendered results, but it doesnt use the index! */ +/* and because rendered results use fake layer/passes, don't correct for wrong indices here */ +RenderPass *BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser) +{ + RenderLayer *rl; + RenderPass *rpass= NULL; + + if(rr==NULL) + return NULL; + + if(iuser) { + short index= 0, rl_index= 0, rp_index; + + for(rl= rr->layers.first; rl; rl= rl->next, rl_index++) { + rp_index= 0; + for(rpass= rl->passes.first; rpass; rpass= rpass->next, index++, rp_index++) + if(iuser->layer==rl_index && iuser->pass==rp_index) + break; + if(rpass) + break; + } + + if(rpass) + iuser->multi_index= index; + else + iuser->multi_index= 0; + } + if(rpass==NULL) { + rl= rr->layers.first; + if(rl) + rpass= rl->passes.first; + } + + return rpass; +} + +RenderResult *BKE_image_get_renderresult(Image *ima) +{ + if(ima->rr) + return ima->rr; + if(ima->type==IMA_TYPE_R_RESULT) + return RE_GetResult(RE_GetRender(G.scene->id.name)); + return NULL; +} + +/* after imbuf load, openexr type can return with a exrhandle open */ +/* in that case we have to build a render-result */ +static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr) +{ + + ima->rr= RE_MultilayerConvert(ibuf->userdata, ibuf->x, ibuf->y); + +#ifdef WITH_OPENEXR + IMB_exr_close(ibuf->userdata); +#endif + + ibuf->userdata= NULL; + if(ima->rr) + ima->rr->framenr= framenr; +} + +/* common stuff to do with images after loading */ +static void image_initialize_after_load(Image *ima, ImBuf *ibuf) +{ + + + /* preview is NULL when it has never been used as an icon before */ + if(G.background==0 && ima->preview==NULL) + BKE_icon_changed(BKE_icon_getid(&ima->id)); + + /* stringcodes also in ibuf, ibuf->name is used to retrieve original (buttons) */ + BLI_strncpy(ibuf->name, ima->name, FILE_MAX); + + /* fields */ + if (ima->flag & IMA_FIELDS) { + if(ima->flag & IMA_STD_FIELD) de_interlace_st(ibuf); + else de_interlace_ng(ibuf); + } + /* timer */ + ima->lastused = clock() / CLOCKS_PER_SEC; + + ima->ok= IMA_OK_LOADED; + +} + +static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame) +{ + struct ImBuf *ibuf; + unsigned short numlen; + char name[FILE_MAX], head[FILE_MAX], tail[FILE_MAX]; + + ima->lastframe= frame; + + BLI_stringdec(ima->name, head, tail, &numlen); + BLI_stringenc(ima->name, head, tail, numlen, frame); + BLI_strncpy(name, ima->name, sizeof(name)); + + if(ima->id.lib) + BLI_convertstringcode(name, ima->id.lib->filename, frame); + else + BLI_convertstringcode(name, G.sce, frame); + + /* read ibuf */ + ibuf = IMB_loadiffname(name, IB_rect|IB_multilayer); + if(G.f & G_DEBUG) printf("loaded %s\n", name); + + if (ibuf) { +#ifdef WITH_OPENEXR + /* handle multilayer case, don't assign ibuf. will be handled in BKE_image_get_ibuf */ + if (ibuf->ftype==OPENEXR && ibuf->userdata) { + image_create_multilayer(ima, ibuf, frame); + ima->type= IMA_TYPE_MULTILAYER; + IMB_freeImBuf(ibuf); + ibuf= NULL; + } + else { + image_assign_ibuf(ima, ibuf, 0, frame); + image_initialize_after_load(ima, ibuf); + } +#else + image_assign_ibuf(ima, ibuf, 0, frame); + image_initialize_after_load(ima, ibuf); +#endif + } + else + ima->ok= 0; + + if(iuser) + iuser->ok= ima->ok; + + return ibuf; +} + +static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int frame) +{ + struct ImBuf *ibuf= NULL; + + /* either we load from RenderResult, or we have to load a new one */ + + /* check for new RenderResult */ + if(ima->rr==NULL || frame!=ima->rr->framenr) { + /* copy to survive not found multilayer image */ + RenderResult *oldrr= ima->rr; + + ima->rr= NULL; + ibuf = image_load_sequence_file(ima, iuser, frame); + + if(ibuf) { /* actually an error */ + ima->type= IMA_TYPE_IMAGE; + printf("error, multi is normal image\n"); + } + // printf("loaded new result %p\n", ima->rr); + /* free result if new one found */ + if(ima->rr) { + // if(oldrr) printf("freed previous result %p\n", oldrr); + if(oldrr) RE_FreeRenderResult(oldrr); + } + else + ima->rr= oldrr; + + } + if(ima->rr) { + RenderPass *rpass= BKE_image_multilayer_index(ima->rr, iuser); + + if(rpass) { + // printf("load from pass %s\n", rpass->name); + /* since we free render results, we copy the rect */ + ibuf= IMB_allocImBuf(ima->rr->rectx, ima->rr->recty, 32, 0, 0); + ibuf->rect_float= MEM_dupallocN(rpass->rect); + ibuf->flags |= IB_rectfloat; + ibuf->mall= IB_rectfloat; + ibuf->channels= rpass->channels; + + image_assign_ibuf(ima, ibuf, iuser->multi_index, frame); + image_initialize_after_load(ima, ibuf); + + } + // else printf("pass not found\n"); + } + else + ima->ok= 0; + + if(iuser) + iuser->ok= ima->ok; + + return ibuf; +} + + +static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame) +{ + struct ImBuf *ibuf= NULL; + + ima->lastframe= frame; + + if(ima->anim==NULL) { + char str[FILE_MAX]; + + BLI_strncpy(str, ima->name, FILE_MAX); + if(ima->id.lib) + BLI_convertstringcode(str, ima->id.lib->filename, 0); + else + BLI_convertstringcode(str, G.sce, 0); + + ima->anim = openanim(str, IB_cmap | IB_rect); + + /* let's initialize this user */ + if(ima->anim && iuser && iuser->frames==0) + iuser->frames= IMB_anim_get_duration(ima->anim); + } + + if(ima->anim) { + int dur = IMB_anim_get_duration(ima->anim); + int fra= frame-1; + + if(fra<0) fra = 0; + if(fra>(dur-1)) fra= dur-1; + ibuf = IMB_anim_absolute(ima->anim, fra); + + if(ibuf) { + image_assign_ibuf(ima, ibuf, 0, frame); + image_initialize_after_load(ima, ibuf); + } + else + ima->ok= 0; + } + else + ima->ok= 0; + + if(iuser) + iuser->ok= ima->ok; + + return ibuf; +} + +/* cfra used for # code, Image can only have this # for all its users */ +static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra) +{ + struct ImBuf *ibuf; + char str[FILE_MAX]; + + /* always ensure clean ima */ + image_free_buffers(ima); + + /* is there a PackedFile with this image ? */ + if (ima->packedfile) { + ibuf = IMB_ibImageFromMemory((int *) ima->packedfile->data, ima->packedfile->size, IB_rect|IB_multilayer); + } + else { + + /* get the right string */ + BLI_strncpy(str, ima->name, sizeof(str)); + if(ima->id.lib) + BLI_convertstringcode(str, ima->id.lib->filename, cfra); + else + BLI_convertstringcode(str, G.sce, cfra); + + /* read ibuf */ + ibuf = IMB_loadiffname(str, IB_rect|IB_multilayer|IB_imginfo); + } + + if (ibuf) { + /* handle multilayer case, don't assign ibuf. will be handled in BKE_image_get_ibuf */ + if (ibuf->ftype==OPENEXR && ibuf->userdata) { + image_create_multilayer(ima, ibuf, cfra); + ima->type= IMA_TYPE_MULTILAYER; + IMB_freeImBuf(ibuf); + ibuf= NULL; + } + else { + image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); + image_initialize_after_load(ima, ibuf); + + /* check if the image is a font image... */ + detectBitmapFont(ibuf); + + /* make packed file for autopack */ + if ((ima->packedfile == NULL) && (G.fileflags & G_AUTOPACK)) + ima->packedfile = newPackedFile(str); + } + } + else + ima->ok= 0; + + if(iuser) + iuser->ok= ima->ok; + + return ibuf; +} + +static ImBuf *image_get_ibuf_multilayer(Image *ima, ImageUser *iuser) +{ + ImBuf *ibuf= NULL; + + if(ima->rr==NULL) { + ibuf = image_load_image_file(ima, iuser, 0); + if(ibuf) { /* actually an error */ + ima->type= IMA_TYPE_IMAGE; + return ibuf; + } + } + if(ima->rr) { + RenderPass *rpass= BKE_image_multilayer_index(ima->rr, iuser); + + if(rpass) { + ibuf= IMB_allocImBuf(ima->rr->rectx, ima->rr->recty, 32, 0, 0); + + image_assign_ibuf(ima, ibuf, iuser?iuser->multi_index:IMA_NO_INDEX, 0); + image_initialize_after_load(ima, ibuf); + + ibuf->rect_float= rpass->rect; + ibuf->flags |= IB_rectfloat; + ibuf->channels= rpass->channels; + } + } + + if(ibuf==NULL) + ima->ok= 0; + if(iuser) + iuser->ok= ima->ok; + + return ibuf; +} + + +/* showing RGBA result itself (from compo/sequence) or + like exr, using layers etc */ +static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser) +{ + RenderResult *rr= RE_GetResult(RE_GetRender(G.scene->id.name)); + + if(rr && iuser) { + RenderResult rres; + float *rectf; + unsigned int *rect; + int channels= 4, layer= iuser->layer; + + /* this gives active layer, composite or seqence result */ + RE_GetResultImage(RE_GetRender(G.scene->id.name), &rres); + rect= (unsigned int *)rres.rect32; + rectf= rres.rectf; + + /* get compo/seq result by default */ + if(rr->rectf && layer==0); + else if(rr->layers.first) { + RenderLayer *rl= BLI_findlink(&rr->layers, iuser->layer-(rr->rectf?1:0)); + if(rl) { + /* there's no combined pass, is in renderlayer itself */ + if(iuser->pass==0) { + rectf= rl->rectf; + } + else { + RenderPass *rpass= BLI_findlink(&rl->passes, iuser->pass-1); + if(rpass) { + channels= rpass->channels; + rectf= rpass->rect; + } + } + } + } + + if(rectf || rect) { + ImBuf *ibuf= image_get_ibuf(ima, IMA_NO_INDEX, 0); + + /* make ibuf if needed, and initialize it */ + if(ibuf==NULL) { + ibuf= IMB_allocImBuf(rr->rectx, rr->recty, 32, 0, 0); + image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); + } + ibuf->x= rr->rectx; + ibuf->y= rr->recty; + + if(ibuf->rect_float!=rectf || rect) /* ensure correct redraw */ + imb_freerectImBuf(ibuf); + if(rect) + ibuf->rect= rect; + + ibuf->rect_float= rectf; + ibuf->flags |= IB_rectfloat; + ibuf->channels= channels; + + ima->ok= IMA_OK_LOADED; + return ibuf; + } + } + + return NULL; +} + +/* Checks optional ImageUser and verifies/creates ImBuf. */ +/* returns ibuf */ +ImBuf *BKE_image_get_ibuf(Image *ima, ImageUser *iuser) +{ + ImBuf *ibuf= NULL; + float color[] = {0, 0, 0, 1}; + + /* quick reject tests */ + if(ima==NULL) + return NULL; + if(iuser) { + if(iuser->ok==0) + return NULL; + } + else if(ima->ok==0) + return NULL; + + BLI_lock_thread(LOCK_IMAGE); + + /* handle image source and types */ + if(ima->source==IMA_SRC_MOVIE) { + /* source is from single file, use flipbook to store ibuf */ + int frame= iuser?iuser->framenr:ima->lastframe; + + ibuf= image_get_ibuf(ima, 0, frame); + if(ibuf==NULL) + ibuf= image_load_movie_file(ima, iuser, frame); + } + else if(ima->source==IMA_SRC_SEQUENCE) { + + if(ima->type==IMA_TYPE_IMAGE) { + /* regular files, ibufs in flipbook, allows saving */ + int frame= iuser?iuser->framenr:ima->lastframe; + + ibuf= image_get_ibuf(ima, 0, frame); + if(ibuf==NULL) + ibuf= image_load_sequence_file(ima, iuser, frame); + else + BLI_strncpy(ima->name, ibuf->name, sizeof(ima->name)); + } + /* no else; on load the ima type can change */ + if(ima->type==IMA_TYPE_MULTILAYER) { + /* only 1 layer/pass stored in imbufs, no exrhandle anim storage, no saving */ + int frame= iuser?iuser->framenr:ima->lastframe; + int index= iuser?iuser->multi_index:IMA_NO_INDEX; + + ibuf= image_get_ibuf(ima, index, frame); + if(G.rt) printf("seq multi fra %d id %d ibuf %p %s\n", frame, index, ibuf, ima->id.name); + if(ibuf==NULL) + ibuf= image_load_sequence_multilayer(ima, iuser, frame); + else + BLI_strncpy(ima->name, ibuf->name, sizeof(ima->name)); + } + + } + else if(ima->source==IMA_SRC_FILE) { + + if(ima->type==IMA_TYPE_IMAGE) { + ibuf= image_get_ibuf(ima, IMA_NO_INDEX, 0); + if(ibuf==NULL) + ibuf= image_load_image_file(ima, iuser, G.scene->r.cfra); /* cfra only for '#', this global is OK */ + } + /* no else; on load the ima type can change */ + if(ima->type==IMA_TYPE_MULTILAYER) { + /* keeps render result, stores ibufs in listbase, allows saving */ + ibuf= image_get_ibuf(ima, iuser?iuser->multi_index:IMA_NO_INDEX, 0); + if(ibuf==NULL) + ibuf= image_get_ibuf_multilayer(ima, iuser); + } + + } + else if(ima->source == IMA_SRC_GENERATED) { + /* generated is: ibuf is allocated dynamically */ + ibuf= image_get_ibuf(ima, IMA_NO_INDEX, 0); + + if(ibuf==NULL) { + if(ima->type==IMA_TYPE_VERSE) { + /* todo */ + } + else { /* always fall back to IMA_TYPE_UV_TEST */ + /* UV testgrid or black or solid etc */ + if(ima->gen_x==0) ima->gen_x= 256; + if(ima->gen_y==0) ima->gen_y= 256; + ibuf= add_ibuf_size(ima->gen_x, ima->gen_y, ima->name, ima->gen_type, color); + image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); + ima->ok= IMA_OK_LOADED; + } + } + } + else if(ima->source == IMA_SRC_VIEWER) { + if(ima->type==IMA_TYPE_R_RESULT) { + /* always verify entirely */ + ibuf= image_get_render_result(ima, iuser); + } + else if(ima->type==IMA_TYPE_COMPOSITE) { + int frame= iuser?iuser->framenr:0; + + /* Composite Viewer, all handled in compositor */ + ibuf= image_get_ibuf(ima, 0, frame); + if(ibuf==NULL) { + /* fake ibuf, will be filled in compositor */ + ibuf= IMB_allocImBuf(256, 256, 32, IB_rect, 0); + image_assign_ibuf(ima, ibuf, 0, frame); + } + } + } + + if(G.rendering==0) + tag_image_time(ima); + + BLI_unlock_thread(LOCK_IMAGE); + + return ibuf; +} + + +void BKE_image_user_calc_imanr(ImageUser *iuser, int cfra, int fieldnr) +{ + int imanr, len; + + /* here (+fie_ima/2-1) makes sure that division happens correctly */ + len= (iuser->fie_ima*iuser->frames)/2; + + if(len==0) { + iuser->framenr= 0; + } + else { + cfra= cfra - iuser->sfra+1; + + /* cyclic */ + if(iuser->cycl) { + cfra= ( (cfra) % len ); + if(cfra < 0) cfra+= len; + if(cfra==0) cfra= len; + } + + if(cfra<1) cfra= 1; + else if(cfra>len) cfra= len; + + /* convert current frame to current field */ + cfra= 2*(cfra); + if(fieldnr) cfra++; + + /* transform to images space */ + imanr= (cfra+iuser->fie_ima-2)/iuser->fie_ima; + if(imanr>iuser->frames) imanr= iuser->frames; + imanr+= iuser->offset; + + if(iuser->cycl) { + imanr= ( (imanr) % len ); + while(imanr < 0) imanr+= len; + if(imanr==0) imanr= len; + } + + /* allows image users to handle redraws */ + if(iuser->flag & IMA_ANIM_ALWAYS) + if(imanr!=iuser->framenr) + iuser->flag |= IMA_ANIM_REFRESHED; + + iuser->framenr= imanr; + if(iuser->ok==0) iuser->ok= 1; + } +} + diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c new file mode 100644 index 00000000000..107633eda64 --- /dev/null +++ b/source/blender/blenkernel/intern/ipo.c @@ -0,0 +1,2432 @@ +/* ipo.c + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_guardedalloc.h" + +#include "DNA_action_types.h" +#include "DNA_armature_types.h" +#include "DNA_curve_types.h" +#include "DNA_camera_types.h" +#include "DNA_lamp_types.h" +#include "DNA_ipo_types.h" +#include "DNA_key_types.h" +#include "DNA_material_types.h" +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force.h" +#include "DNA_sequence_types.h" +#include "DNA_scene_types.h" +#include "DNA_sound_types.h" +#include "DNA_texture_types.h" +#include "DNA_view3d_types.h" +#include "DNA_world_types.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "BKE_bad_level_calls.h" +#include "BKE_utildefines.h" + +#include "BKE_action.h" +#include "BKE_blender.h" +#include "BKE_curve.h" +#include "BKE_constraint.h" +#include "BKE_global.h" +#include "BKE_ipo.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_mesh.h" +#include "BKE_object.h" +#include "BPY_extern.h" /* for BPY_pydriver_eval() */ + +#define SMALL -1.0e-10 + +/* This array concept was meant to make sure that defines such as OB_LOC_X + don't have to be enumerated, also for backward compatibility, future changes, + and to enable it all can be accessed with a for-next loop. +*/ + +int co_ar[CO_TOTIPO]= { + CO_ENFORCE +}; + +int ob_ar[OB_TOTIPO]= { + OB_LOC_X, OB_LOC_Y, OB_LOC_Z, OB_DLOC_X, OB_DLOC_Y, OB_DLOC_Z, + OB_ROT_X, OB_ROT_Y, OB_ROT_Z, OB_DROT_X, OB_DROT_Y, OB_DROT_Z, + OB_SIZE_X, OB_SIZE_Y, OB_SIZE_Z, OB_DSIZE_X, OB_DSIZE_Y, OB_DSIZE_Z, + OB_LAY, OB_TIME, OB_COL_R, OB_COL_G, OB_COL_B, OB_COL_A, + OB_PD_FSTR, OB_PD_FFALL, OB_PD_SDAMP, OB_PD_RDAMP, OB_PD_PERM +}; + +int ac_ar[AC_TOTIPO]= { + AC_LOC_X, AC_LOC_Y, AC_LOC_Z, + AC_QUAT_W, AC_QUAT_X, AC_QUAT_Y, AC_QUAT_Z, + AC_SIZE_X, AC_SIZE_Y, AC_SIZE_Z +}; + +int ma_ar[MA_TOTIPO]= { + MA_COL_R, MA_COL_G, MA_COL_B, + MA_SPEC_R, MA_SPEC_G, MA_SPEC_B, + MA_MIR_R, MA_MIR_G, MA_MIR_B, + MA_REF, MA_ALPHA, MA_EMIT, MA_AMB, + MA_SPEC, MA_HARD, MA_SPTR, MA_IOR, + MA_MODE, MA_HASIZE, MA_TRANSLU, MA_RAYM, + MA_FRESMIR, MA_FRESMIRI, MA_FRESTRA, MA_FRESTRAI, MA_ADD, + + MA_MAP1+MAP_OFS_X, MA_MAP1+MAP_OFS_Y, MA_MAP1+MAP_OFS_Z, + MA_MAP1+MAP_SIZE_X, MA_MAP1+MAP_SIZE_Y, MA_MAP1+MAP_SIZE_Z, + MA_MAP1+MAP_R, MA_MAP1+MAP_G, MA_MAP1+MAP_B, + MA_MAP1+MAP_DVAR, MA_MAP1+MAP_COLF, MA_MAP1+MAP_NORF, MA_MAP1+MAP_VARF, MA_MAP1+MAP_DISP +}; + +int te_ar[TE_TOTIPO] ={ + + TE_NSIZE, TE_NDEPTH, TE_NTYPE, TE_TURB, + + TE_VNW1, TE_VNW2, TE_VNW3, TE_VNW4, + TE_VNMEXP, TE_VN_COLT, TE_VN_DISTM, + + TE_ISCA, TE_DISTA, + + TE_MG_TYP, TE_MGH, TE_MG_LAC, TE_MG_OCT, TE_MG_OFF, TE_MG_GAIN, + + TE_N_BAS1, TE_N_BAS2, + + TE_COL_R, TE_COL_G, TE_COL_B, TE_BRIGHT, TE_CONTRA +}; + +int seq_ar[SEQ_TOTIPO]= { + SEQ_FAC1 +}; + +int cu_ar[CU_TOTIPO]= { + CU_SPEED +}; + +int wo_ar[WO_TOTIPO]= { + WO_HOR_R, WO_HOR_G, WO_HOR_B, WO_ZEN_R, WO_ZEN_G, WO_ZEN_B, + WO_EXPOS, WO_MISI, WO_MISTDI, WO_MISTSTA, WO_MISTHI, + WO_STAR_R, WO_STAR_G, WO_STAR_B, WO_STARDIST, WO_STARSIZE, + + MA_MAP1+MAP_OFS_X, MA_MAP1+MAP_OFS_Y, MA_MAP1+MAP_OFS_Z, + MA_MAP1+MAP_SIZE_X, MA_MAP1+MAP_SIZE_Y, MA_MAP1+MAP_SIZE_Z, + MA_MAP1+MAP_R, MA_MAP1+MAP_G, MA_MAP1+MAP_B, + MA_MAP1+MAP_DVAR, MA_MAP1+MAP_COLF, MA_MAP1+MAP_NORF, MA_MAP1+MAP_VARF +}; + +int la_ar[LA_TOTIPO]= { + LA_ENERGY, LA_COL_R, LA_COL_G, LA_COL_B, + LA_DIST, LA_SPOTSI, LA_SPOTBL, + LA_QUAD1, LA_QUAD2, LA_HALOINT, + + MA_MAP1+MAP_OFS_X, MA_MAP1+MAP_OFS_Y, MA_MAP1+MAP_OFS_Z, + MA_MAP1+MAP_SIZE_X, MA_MAP1+MAP_SIZE_Y, MA_MAP1+MAP_SIZE_Z, + MA_MAP1+MAP_R, MA_MAP1+MAP_G, MA_MAP1+MAP_B, + MA_MAP1+MAP_DVAR, MA_MAP1+MAP_COLF +}; + +/* yafray: aperture & focal distance curves added */ +/* qdn: FDIST now available to Blender as well for defocus node */ +int cam_ar[CAM_TOTIPO]= { + CAM_LENS, CAM_STA, CAM_END, CAM_YF_APERT, CAM_YF_FDIST, CAM_SHIFT_X, CAM_SHIFT_Y +}; + +int snd_ar[SND_TOTIPO]= { + SND_VOLUME, SND_PITCH, SND_PANNING, SND_ATTEN +}; + +int fluidsim_ar[FLUIDSIM_TOTIPO]= { + FLUIDSIM_VISC, FLUIDSIM_TIME, + FLUIDSIM_GRAV_X , FLUIDSIM_GRAV_Y , FLUIDSIM_GRAV_Z , + FLUIDSIM_VEL_X , FLUIDSIM_VEL_Y , FLUIDSIM_VEL_Z , + FLUIDSIM_ACTIVE +}; + + + +float frame_to_float(int cfra) /* see also bsystem_time in object.c */ +{ + extern float bluroffs; /* bad stuff borrowed from object.c */ + extern float fieldoffs; + float ctime; + + ctime= (float)cfra; + ctime+= bluroffs+fieldoffs; + ctime*= G.scene->r.framelen; + + return ctime; +} + +/* includes ipo curve itself */ +void free_ipo_curve(IpoCurve *icu) +{ + if(icu->bezt) MEM_freeN(icu->bezt); + if(icu->bp) MEM_freeN(icu->bp); + if(icu->driver) MEM_freeN(icu->driver); + MEM_freeN(icu); +} + +/* do not free ipo itself */ +void free_ipo(Ipo *ipo) +{ + IpoCurve *icu; + + while( (icu= ipo->curve.first) ) { + BLI_remlink(&ipo->curve, icu); + free_ipo_curve(icu); + } +} + +/* on adding new ipos, or for empty views */ +void ipo_default_v2d_cur(int blocktype, rctf *cur) +{ + if(blocktype==ID_CA) { + cur->xmin= G.scene->r.sfra; + cur->xmax= G.scene->r.efra; + cur->ymin= 0.0; + cur->ymax= 100.0; + } + else if ELEM5(blocktype, ID_MA, ID_CU, ID_WO, ID_LA, ID_CO) { + cur->xmin= (float)G.scene->r.sfra-0.1; + cur->xmax= G.scene->r.efra; + cur->ymin= (float)-0.1; + cur->ymax= (float)+1.1; + } + else if(blocktype==ID_TE) { + cur->xmin= (float)G.scene->r.sfra-0.1; + cur->xmax= G.scene->r.efra; + cur->ymin= (float)-0.1; + cur->ymax= (float)+1.1; + } + else if(blocktype==ID_SEQ) { + cur->xmin= -5.0; + cur->xmax= 105.0; + cur->ymin= (float)-0.1; + cur->ymax= (float)+1.1; + } + else if(blocktype==ID_KE) { + cur->xmin= (float)G.scene->r.sfra-0.1; + cur->xmax= G.scene->r.efra; + cur->ymin= (float)-0.1; + cur->ymax= (float)+2.1; + } + else { /* ID_OB and everything else */ + cur->xmin= G.scene->r.sfra; + cur->xmax= G.scene->r.efra; + cur->ymin= -5.0; + cur->ymax= +5.0; + } +} + + +Ipo *add_ipo(char *name, int idcode) +{ + Ipo *ipo; + + ipo= alloc_libblock(&G.main->ipo, ID_IP, name); + ipo->blocktype= idcode; + ipo_default_v2d_cur(idcode, &ipo->cur); + + return ipo; +} + +Ipo *copy_ipo(Ipo *ipo) +{ + Ipo *ipon; + IpoCurve *icu; + + if(ipo==NULL) return 0; + + ipon= copy_libblock(ipo); + + duplicatelist(&(ipon->curve), &(ipo->curve)); + + for(icu= ipo->curve.first; icu; icu= icu->next) { + icu->bezt= MEM_dupallocN(icu->bezt); + if(icu->driver) icu->driver= MEM_dupallocN(icu->driver); + } + + return ipon; +} + +/* uses id->newid to match pointers with other copied data */ +void ipo_idnew(Ipo *ipo) +{ + if(ipo) { + IpoCurve *icu; + + for(icu= ipo->curve.first; icu; icu= icu->next) { + if(icu->driver) { + ID_NEW(icu->driver->ob); + } + } + } +} + +void make_local_obipo(Ipo *ipo) +{ + Object *ob; + Ipo *ipon; + int local=0, lib=0; + + /* - only lib users: do nothing + * - only local users: set flag + * - mixed: make copy + */ + + ob= G.main->object.first; + while(ob) { + if(ob->ipo==ipo) { + if(ob->id.lib) lib= 1; + else local= 1; + } + ob= ob->id.next; + } + + if(local && lib==0) { + ipo->id.lib= 0; + ipo->id.flag= LIB_LOCAL; + new_id(0, (ID *)ipo, 0); + } + else if(local && lib) { + ipon= copy_ipo(ipo); + ipon->id.us= 0; + + ob= G.main->object.first; + while(ob) { + if(ob->ipo==ipo) { + + if(ob->id.lib==NULL) { + ob->ipo= ipon; + ipon->id.us++; + ipo->id.us--; + } + } + ob= ob->id.next; + } + } +} + +void make_local_matipo(Ipo *ipo) +{ + Material *ma; + Ipo *ipon; + int local=0, lib=0; + + /* - only lib users: do nothing + * - only local users: set flag + * - mixed: make copy + */ + + ma= G.main->mat.first; + while(ma) { + if(ma->ipo==ipo) { + if(ma->id.lib) lib= 1; + else local= 1; + } + ma= ma->id.next; + } + + if(local && lib==0) { + ipo->id.lib= 0; + ipo->id.flag= LIB_LOCAL; + new_id(0, (ID *)ipo, 0); + } + else if(local && lib) { + ipon= copy_ipo(ipo); + ipon->id.us= 0; + + ma= G.main->mat.first; + while(ma) { + if(ma->ipo==ipo) { + + if(ma->id.lib==NULL) { + ma->ipo= ipon; + ipon->id.us++; + ipo->id.us--; + } + } + ma= ma->id.next; + } + } +} + +void make_local_keyipo(Ipo *ipo) +{ + Key *key; + Ipo *ipon; + int local=0, lib=0; + + /* - only lib users: do nothing + * - only local users: set flag + * - mixed: make copy + */ + + key= G.main->key.first; + while(key) { + if(key->ipo==ipo) { + if(key->id.lib) lib= 1; + else local= 1; + } + key= key->id.next; + } + + if(local && lib==0) { + ipo->id.lib= 0; + ipo->id.flag= LIB_LOCAL; + new_id(0, (ID *)ipo, 0); + } + else if(local && lib) { + ipon= copy_ipo(ipo); + ipon->id.us= 0; + + key= G.main->key.first; + while(key) { + if(key->ipo==ipo) { + + if(key->id.lib==NULL) { + key->ipo= ipon; + ipon->id.us++; + ipo->id.us--; + } + } + key= key->id.next; + } + } +} + + +void make_local_ipo(Ipo *ipo) +{ + + if(ipo->id.lib==NULL) return; + if(ipo->id.us==1) { + ipo->id.lib= 0; + ipo->id.flag= LIB_LOCAL; + new_id(0, (ID *)ipo, 0); + return; + } + + if(ipo->blocktype==ID_OB) make_local_obipo(ipo); + else if(ipo->blocktype==ID_MA) make_local_matipo(ipo); + else if(ipo->blocktype==ID_KE) make_local_keyipo(ipo); + +} + +IpoCurve *find_ipocurve(Ipo *ipo, int adrcode) +{ + if(ipo) { + IpoCurve *icu; + for(icu= ipo->curve.first; icu; icu= icu->next) { + if(icu->adrcode==adrcode) return icu; + } + } + return NULL; +} + +void calchandles_ipocurve(IpoCurve *icu) +{ + BezTriple *bezt, *prev, *next; + int a; + + a= icu->totvert; + + /* IPO_CONST doesn't have handles */ + if(a<2 || icu->ipo==IPO_CONST) return; + + bezt= icu->bezt; + prev= 0; + next= bezt+1; + + while(a--) { + + if(bezt->vec[0][0]>bezt->vec[1][0]) bezt->vec[0][0]= bezt->vec[1][0]; + if(bezt->vec[2][0]vec[1][0]) bezt->vec[2][0]= bezt->vec[1][0]; + + if(icu->flag & IPO_AUTO_HORIZ) + calchandleNurb(bezt, prev, next, 2); /* 2==special autohandle && keep extrema horizontal */ + else + calchandleNurb(bezt, prev, next, 1); /* 1==special autohandle */ + + prev= bezt; + if(a==1) { + next= 0; + } + else next++; + + /* for automatic ease in and out */ + if(bezt->h1==HD_AUTO && bezt->h2==HD_AUTO) { + if(a==0 || a==icu->totvert-1) { + if(icu->extrap==IPO_HORIZ) { + bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1]; + } + } + } + + bezt++; + } +} + +void testhandles_ipocurve(IpoCurve *icu) +{ + /* use when something has changed with handles. + it treats all BezTriples with the following rules: + PHASE 1: do types have to be altered? + Auto handles: become aligned when selection status is NOT(000 || 111) + Vector handles: become 'nothing' when (one half selected AND other not) + PHASE 2: recalculate handles + */ + BezTriple *bezt; + int flag, a; + + bezt= icu->bezt; + if(bezt==NULL) return; + + a= icu->totvert; + while(a--) { + flag= 0; + if(bezt->f1 & 1) flag++; + if(bezt->f2 & 1) flag += 2; + if(bezt->f3 & 1) flag += 4; + + if( !(flag==0 || flag==7) ) { + if(bezt->h1==HD_AUTO) { /* auto */ + bezt->h1= HD_ALIGN; + } + if(bezt->h2==HD_AUTO) { /* auto */ + bezt->h2= HD_ALIGN; + } + + if(bezt->h1==HD_VECT) { /* vector */ + if(flag < 4) bezt->h1= 0; + } + if(bezt->h2==HD_VECT) { /* vector */ + if( flag > 3) bezt->h2= 0; + } + } + bezt++; + } + + calchandles_ipocurve(icu); +} + + +void sort_time_ipocurve(IpoCurve *icu) +{ + BezTriple *bezt; + int a, ok= 1; + + while(ok) { + ok= 0; + + if(icu->bezt) { + bezt= icu->bezt; + a= icu->totvert; + while(a--) { + if(a>0) { + if( bezt->vec[1][0] > (bezt+1)->vec[1][0]) { + SWAP(BezTriple, *bezt, *(bezt+1)); + ok= 1; + } + } + if(bezt->vec[0][0]>bezt->vec[1][0] && bezt->vec[2][0]vec[1][0]) { + SWAP(float, bezt->vec[0][0], bezt->vec[2][0]); + SWAP(float, bezt->vec[0][1], bezt->vec[2][1]); + } + else { + if(bezt->vec[0][0]>bezt->vec[1][0]) bezt->vec[0][0]= bezt->vec[1][0]; + if(bezt->vec[2][0]vec[1][0]) bezt->vec[2][0]= bezt->vec[1][0]; + } + bezt++; + } + } + else { + + } + } +} + +int test_time_ipocurve(IpoCurve *icu) +{ + BezTriple *bezt; + int a; + + if(icu->bezt) { + bezt= icu->bezt; + a= icu->totvert-1; + while(a--) { + if( bezt->vec[1][0] > (bezt+1)->vec[1][0]) { + return 1; + } + bezt++; + } + } + else { + + } + + return 0; +} + +void correct_bezpart(float *v1, float *v2, float *v3, float *v4) +{ + /* the total length of the handles is not allowed to be more + * than the horizontal distance between (v1-v4) + * this to prevent curve loops + */ + float h1[2], h2[2], len1, len2, len, fac; + + h1[0]= v1[0]-v2[0]; + h1[1]= v1[1]-v2[1]; + h2[0]= v4[0]-v3[0]; + h2[1]= v4[1]-v3[1]; + + len= v4[0]- v1[0]; + len1= (float)fabs(h1[0]); + len2= (float)fabs(h2[0]); + + if(len1+len2==0.0) return; + if(len1+len2 > len) { + fac= len/(len1+len2); + + v2[0]= (v1[0]-fac*h1[0]); + v2[1]= (v1[1]-fac*h1[1]); + + v3[0]= (v4[0]-fac*h2[0]); + v3[1]= (v4[1]-fac*h2[1]); + + } +} + +/* *********************** ARITH *********************** */ + +int findzero(float x, float q0, float q1, float q2, float q3, float *o) +{ + double c0, c1, c2, c3, a, b, c, p, q, d, t, phi; + int nr= 0; + + c0= q0-x; + c1= 3*(q1-q0); + c2= 3*(q0-2*q1+q2); + c3= q3-q0+3*(q1-q2); + + if(c3!=0.0) { + a= c2/c3; + b= c1/c3; + c= c0/c3; + a= a/3; + + p= b/3-a*a; + q= (2*a*a*a-a*b+c)/2; + d= q*q+p*p*p; + + if(d>0.0) { + t= sqrt(d); + o[0]= (float)(Sqrt3d(-q+t)+Sqrt3d(-q-t)-a); + if(o[0]>= SMALL && o[0]<=1.000001) return 1; + else return 0; + } + else if(d==0.0) { + t= Sqrt3d(-q); + o[0]= (float)(2*t-a); + if(o[0]>=SMALL && o[0]<=1.000001) nr++; + o[nr]= (float)(-t-a); + if(o[nr]>=SMALL && o[nr]<=1.000001) return nr+1; + else return nr; + } + else { + phi= acos(-q/sqrt(-(p*p*p))); + t= sqrt(-p); + p= cos(phi/3); + q= sqrt(3-3*p*p); + o[0]= (float)(2*t*p-a); + if(o[0]>=SMALL && o[0]<=1.000001) nr++; + o[nr]= (float)(-t*(p+q)-a); + if(o[nr]>=SMALL && o[nr]<=1.000001) nr++; + o[nr]= (float)(-t*(p-q)-a); + if(o[nr]>=SMALL && o[nr]<=1.000001) return nr+1; + else return nr; + } + } + else { + a=c2; + b=c1; + c=c0; + + if(a!=0.0) { + p=b*b-4*a*c; + if(p>0) { + p= sqrt(p); + o[0]= (float)((-b-p)/(2*a)); + if(o[0]>=SMALL && o[0]<=1.000001) nr++; + o[nr]= (float)((-b+p)/(2*a)); + if(o[nr]>=SMALL && o[nr]<=1.000001) return nr+1; + else return nr; + } + else if(p==0) { + o[0]= (float)(-b/(2*a)); + if(o[0]>=SMALL && o[0]<=1.000001) return 1; + else return 0; + } + } + else if(b!=0.0) { + o[0]= (float)(-c/b); + if(o[0]>=SMALL && o[0]<=1.000001) return 1; + else return 0; + } + else if(c==0.0) { + o[0]= 0.0; + return 1; + } + return 0; + } +} + +void berekeny(float f1, float f2, float f3, float f4, float *o, int b) +{ + float t, c0, c1, c2, c3; + int a; + + c0= f1; + c1= 3.0f*(f2 - f1); + c2= 3.0f*(f1 - 2.0f*f2 + f3); + c3= f4 - f1 + 3.0f*(f2-f3); + + for(a=0; apose_mat); + + if (pchan->parent) { + + if(flag & TFM_WITHOUT_BONE) { + float par_mat[3][3]; + Mat3CpyMat4(par_mat, pchan->parent->pose_mat); + Mat3MulMat3(diff_mat, par_mat, pchan->bone->bone_mat); + } + else + Mat3CpyMat4(diff_mat, pchan->parent->pose_mat); + + Mat3Inv(ipar_mat, diff_mat); + } + else { + if(flag & TFM_WITHOUT_BONE) + Mat3Inv(ipar_mat, pchan->bone->bone_mat); + else + Mat3One(ipar_mat); + } + + Mat3MulMat3(diff_mat, ipar_mat, pose_mat); + + if(quat) + Mat3ToQuat(diff_mat, quat); + if(eul) + Mat3ToEul(diff_mat, eul); + if(size) + Mat3ToSize(diff_mat, size); +} + +/* has to return a float value */ +static float eval_driver(IpoDriver *driver, float ipotime) +{ + + if(driver->type == IPO_DRIVER_TYPE_PYTHON) { + /* check for empty or invalid expression */ + if ((driver->name[0] == '\0') || + (driver->flag & IPO_DRIVER_FLAG_INVALID)) + return 0.0f; + /* this evals the expression and returns its result: + * (on errors it reports, then returns 0.0f) */ + return BPY_pydriver_eval(driver); + } + else { + Object *ob= driver->ob; + + if(ob==NULL) return 0.0f; + if(ob->proxy_from) + ob= ob->proxy_from; + + if(driver->blocktype==ID_OB) { + /* depsgraph failure; ob ipos are calculated in where_is_object, this might get called too late */ + if(ob->ipo && ob->ctime!=ipotime) { + calc_ipo_spec(ob->ipo, driver->adrcode, &ipotime); + return ipotime; + } + + switch(driver->adrcode) { + case OB_LOC_X: + return ob->loc[0]; + case OB_LOC_Y: + return ob->loc[1]; + case OB_LOC_Z: + return ob->loc[2]; + case OB_ROT_X: + return ob->rot[0]/(M_PI_2/9.0); + case OB_ROT_Y: + return ob->rot[1]/(M_PI_2/9.0); + case OB_ROT_Z: + return ob->rot[2]/(M_PI_2/9.0); + case OB_SIZE_X: + return ob->size[0]; + case OB_SIZE_Y: + return ob->size[1]; + case OB_SIZE_Z: + return ob->size[2]; + } + } + else { /* ID_AR */ + bPoseChannel *pchan= get_pose_channel(ob->pose, driver->name); + if(pchan && pchan->bone) { + + /* rotation difference is not a simple driver (i.e. value drives value), but the angle between 2 bones is driving stuff... which is useful */ + if(driver->adrcode==OB_ROT_DIFF) { + bPoseChannel *pchan2= get_pose_channel(ob->pose, driver->name+DRIVER_NAME_OFFS); + if(pchan2 && pchan2->bone) { + float q1[4], q2[4], quat[4], angle; + + Mat4ToQuat(pchan->pose_mat, q1); + Mat4ToQuat(pchan2->pose_mat, q2); + // posechannel_get_local_transform(pchan , q1, NULL, NULL, 0); + // posechannel_get_local_transform(pchan2, q2, NULL, NULL, 0); + + QuatInv(q1); + QuatMul(quat, q1, q2); + angle = 2.0f * (saacos(quat[0])); + angle= ABS(angle); + + return angle>M_PI?2.0f*M_PI-angle:angle; + } + } + else { + float eul[3], size[3]; + + posechannel_get_local_transform(pchan, NULL, eul, size, TFM_WITHOUT_BONE); + + switch(driver->adrcode) { + case OB_LOC_X: + return pchan->loc[0]; + case OB_LOC_Y: + return pchan->loc[1]; + case OB_LOC_Z: + return pchan->loc[2]; + case OB_ROT_X: + return eul[0]/(M_PI_2/9.0); + case OB_ROT_Y: + return eul[1]/(M_PI_2/9.0); + case OB_ROT_Z: + return eul[2]/(M_PI_2/9.0); + case OB_SIZE_X: + return size[0]; + case OB_SIZE_Y: + return size[1]; + case OB_SIZE_Z: + return size[2]; + } + } + } + } + } + return 0.0f; +} + +float eval_icu(IpoCurve *icu, float ipotime) +{ + BezTriple *bezt, *prevbezt; + float v1[2], v2[2], v3[2], v4[2], opl[32], dx, fac; + float cycdx, cycdy, ofs, cycyofs, cvalue = 0.0; + int a, b; + + cycyofs= 0.0; + + if(icu->driver) { + /* ipotime now serves as input for the curve */ + ipotime= cvalue= eval_driver(icu->driver, ipotime); + } + if(icu->bezt) { + prevbezt= icu->bezt; + bezt= prevbezt+1; + a= icu->totvert-1; + + /* cyclic? */ + if(icu->extrap & IPO_CYCL) { + ofs= icu->bezt->vec[1][0]; + cycdx= (icu->bezt+icu->totvert-1)->vec[1][0] - ofs; + cycdy= (icu->bezt+icu->totvert-1)->vec[1][1] - icu->bezt->vec[1][1]; + if(cycdx!=0.0) { + + if(icu->extrap & IPO_DIR) { + cycyofs= (float)floor((ipotime-ofs)/cycdx); + cycyofs*= cycdy; + } + + ipotime= (float)(fmod(ipotime-ofs, cycdx)+ofs); + if(ipotimevec[1][0]>=ipotime) { + if( (icu->extrap & IPO_DIR) && icu->ipo!=IPO_CONST) { + dx= prevbezt->vec[1][0]-ipotime; + fac= prevbezt->vec[1][0]-prevbezt->vec[0][0]; + if(fac!=0.0) { + fac= (prevbezt->vec[1][1]-prevbezt->vec[0][1])/fac; + cvalue= prevbezt->vec[1][1]-fac*dx; + } + else cvalue= prevbezt->vec[1][1]; + } + else cvalue= prevbezt->vec[1][1]; + + cvalue+= cycyofs; + } + else if( (prevbezt+a)->vec[1][0]<=ipotime) { + if( (icu->extrap & IPO_DIR) && icu->ipo!=IPO_CONST) { + prevbezt+= a; + dx= ipotime-prevbezt->vec[1][0]; + fac= prevbezt->vec[2][0]-prevbezt->vec[1][0]; + + if(fac!=0) { + fac= (prevbezt->vec[2][1]-prevbezt->vec[1][1])/fac; + cvalue= prevbezt->vec[1][1]+fac*dx; + } + else cvalue= prevbezt->vec[1][1]; + } + else cvalue= (prevbezt+a)->vec[1][1]; + + cvalue+= cycyofs; + } + else { + while(a--) { + if(prevbezt->vec[1][0]<=ipotime && bezt->vec[1][0]>=ipotime) { + if(icu->ipo==IPO_CONST) { + cvalue= prevbezt->vec[1][1]+cycyofs; + } + else if(icu->ipo==IPO_LIN) { + fac= bezt->vec[1][0]-prevbezt->vec[1][0]; + if(fac==0) cvalue= cycyofs+prevbezt->vec[1][1]; + else { + fac= (ipotime-prevbezt->vec[1][0])/fac; + cvalue= cycyofs+prevbezt->vec[1][1]+ fac*(bezt->vec[1][1]-prevbezt->vec[1][1]); + } + } + else { + v1[0]= prevbezt->vec[1][0]; + v1[1]= prevbezt->vec[1][1]; + v2[0]= prevbezt->vec[2][0]; + v2[1]= prevbezt->vec[2][1]; + + v3[0]= bezt->vec[0][0]; + v3[1]= bezt->vec[0][1]; + v4[0]= bezt->vec[1][0]; + v4[1]= bezt->vec[1][1]; + + correct_bezpart(v1, v2, v3, v4); + + b= findzero(ipotime, v1[0], v2[0], v3[0], v4[0], opl); + if(b) { + berekeny(v1[1], v2[1], v3[1], v4[1], opl, 1); + cvalue= opl[0]+cycyofs; + break; + } + } + } + prevbezt= bezt; + bezt++; + } + } + } + + if(icu->ymin < icu->ymax) { + if(cvalue < icu->ymin) cvalue= icu->ymin; + else if(cvalue > icu->ymax) cvalue= icu->ymax; + } + + return cvalue; +} + +void calc_icu(IpoCurve *icu, float ctime) +{ + icu->curval= eval_icu(icu, ctime); +} + +float calc_ipo_time(Ipo *ipo, float ctime) +{ + + if(ipo && ipo->blocktype==ID_OB) { + IpoCurve *icu= ipo->curve.first; + + while(icu) { + if (icu->adrcode==OB_TIME) { + calc_icu(icu, ctime); + return 10.0f*icu->curval; + } + icu= icu->next; + } + } + + return ctime; +} + +void calc_ipo(Ipo *ipo, float ctime) +{ + IpoCurve *icu; + + if(ipo==NULL) return; + if(ipo->muteipo) return; + + for(icu= ipo->curve.first; icu; icu= icu->next) { + if(icu->driver || (icu->flag & IPO_LOCK)==0) { + if((icu->flag & IPO_MUTE)==0) + calc_icu(icu, ctime); + } + } +} + +/* ************************************** */ +/* DO THE IPO! */ +/* ************************************** */ + +void write_ipo_poin(void *poin, int type, float val) +{ + + switch(type) { + case IPO_FLOAT: + *( (float *)poin)= val; + break; + case IPO_FLOAT_DEGR: + *( (float *)poin)= (float)(val*M_PI_2/9.0); + break; + case IPO_INT: + case IPO_INT_BIT: + case IPO_LONG: + *( (int *)poin)= (int)val; + break; + case IPO_SHORT: + case IPO_SHORT_BIT: + *( (short *)poin)= (short)val; + break; + case IPO_CHAR: + case IPO_CHAR_BIT: + *( (char *)poin)= (char)val; + break; + } +} + +float read_ipo_poin(void *poin, int type) +{ + float val = 0.0; + + switch(type) { + case IPO_FLOAT: + val= *( (float *)poin); + break; + case IPO_FLOAT_DEGR: + val= *( (float *)poin); + val = (float)(val/(M_PI_2/9.0)); + break; + case IPO_INT: + case IPO_INT_BIT: + case IPO_LONG: + val= (float)(*( (int *)poin)); + break; + case IPO_SHORT: + case IPO_SHORT_BIT: + val= *( (short *)poin); + break; + case IPO_CHAR: + case IPO_CHAR_BIT: + val= *( (char *)poin); + break; + } + return val; +} + +static void *give_tex_poin(Tex *tex, int adrcode, int *type ) +{ + void *poin=0; + + switch(adrcode) { + case TE_NSIZE: + poin= &(tex->noisesize); break; + case TE_TURB: + poin= &(tex->turbul); break; + case TE_NDEPTH: + poin= &(tex->noisedepth); *type= IPO_SHORT; break; + case TE_NTYPE: + poin= &(tex->noisetype); *type= IPO_SHORT; break; + case TE_VNW1: + poin= &(tex->vn_w1); break; + case TE_VNW2: + poin= &(tex->vn_w2); break; + case TE_VNW3: + poin= &(tex->vn_w3); break; + case TE_VNW4: + poin= &(tex->vn_w4); break; + case TE_VNMEXP: + poin= &(tex->vn_mexp); break; + case TE_ISCA: + poin= &(tex->ns_outscale); break; + case TE_DISTA: + poin= &(tex->dist_amount); break; + case TE_VN_COLT: + poin= &(tex->vn_coltype); *type= IPO_SHORT; break; + case TE_VN_DISTM: + poin= &(tex->vn_distm); *type= IPO_SHORT; break; + case TE_MG_TYP: + poin= &(tex->stype); *type= IPO_SHORT; break; + case TE_MGH: + poin= &(tex->mg_H); break; + case TE_MG_LAC: + poin= &(tex->mg_lacunarity); break; + case TE_MG_OCT: + poin= &(tex->mg_octaves); break; + case TE_MG_OFF: + poin= &(tex->mg_offset); break; + case TE_MG_GAIN: + poin= &(tex->mg_gain); break; + case TE_N_BAS1: + poin= &(tex->noisebasis); *type= IPO_SHORT; break; + case TE_N_BAS2: + poin= &(tex->noisebasis2); *type= IPO_SHORT; break; + case TE_COL_R: + poin= &(tex->rfac); break; + case TE_COL_G: + poin= &(tex->gfac); break; + case TE_COL_B: + poin= &(tex->bfac); break; + case TE_BRIGHT: + poin= &(tex->bright); break; + case TE_CONTRA: + poin= &(tex->contrast); break; + + } + + return poin; +} + +void *give_mtex_poin(MTex *mtex, int adrcode ) +{ + void *poin=0; + + switch(adrcode) { + case MAP_OFS_X: + poin= &(mtex->ofs[0]); break; + case MAP_OFS_Y: + poin= &(mtex->ofs[1]); break; + case MAP_OFS_Z: + poin= &(mtex->ofs[2]); break; + case MAP_SIZE_X: + poin= &(mtex->size[0]); break; + case MAP_SIZE_Y: + poin= &(mtex->size[1]); break; + case MAP_SIZE_Z: + poin= &(mtex->size[2]); break; + case MAP_R: + poin= &(mtex->r); break; + case MAP_G: + poin= &(mtex->g); break; + case MAP_B: + poin= &(mtex->b); break; + case MAP_DVAR: + poin= &(mtex->def_var); break; + case MAP_COLF: + poin= &(mtex->colfac); break; + case MAP_NORF: + poin= &(mtex->norfac); break; + case MAP_VARF: + poin= &(mtex->varfac); break; + case MAP_DISP: + poin= &(mtex->dispfac); break; + } + + return poin; +} + +/* GS reads the memory pointed at in a specific ordering. There are, + * however two definitions for it. I have jotted them down here, both, + * but I think the first one is actually used. The thing is that + * big-endian systems might read this the wrong way round. OTOH, we + * constructed the IDs that are read out with this macro explicitly as + * well. I expect we'll sort it out soon... */ + +/* from blendef: */ +#define GS(a) (*((short *)(a))) + +/* from misc_util: flip the bytes from x */ +/* #define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1]) */ + +void *get_ipo_poin(ID *id, IpoCurve *icu, int *type) +{ + void *poin= NULL; + Object *ob; + Material *ma; + MTex *mtex; + Tex *tex; + Lamp *la; + Sequence *seq; + World *wo; + + *type= IPO_FLOAT; + + if( GS(id->name)==ID_OB) { + + ob= (Object *)id; + + switch(icu->adrcode) { + case OB_LOC_X: + poin= &(ob->loc[0]); break; + case OB_LOC_Y: + poin= &(ob->loc[1]); break; + case OB_LOC_Z: + poin= &(ob->loc[2]); break; + case OB_DLOC_X: + poin= &(ob->dloc[0]); break; + case OB_DLOC_Y: + poin= &(ob->dloc[1]); break; + case OB_DLOC_Z: + poin= &(ob->dloc[2]); break; + + case OB_ROT_X: + poin= &(ob->rot[0]); *type= IPO_FLOAT_DEGR; break; + case OB_ROT_Y: + poin= &(ob->rot[1]); *type= IPO_FLOAT_DEGR; break; + case OB_ROT_Z: + poin= &(ob->rot[2]); *type= IPO_FLOAT_DEGR; break; + case OB_DROT_X: + poin= &(ob->drot[0]); *type= IPO_FLOAT_DEGR; break; + case OB_DROT_Y: + poin= &(ob->drot[1]); *type= IPO_FLOAT_DEGR; break; + case OB_DROT_Z: + poin= &(ob->drot[2]); *type= IPO_FLOAT_DEGR; break; + + case OB_SIZE_X: + poin= &(ob->size[0]); break; + case OB_SIZE_Y: + poin= &(ob->size[1]); break; + case OB_SIZE_Z: + poin= &(ob->size[2]); break; + case OB_DSIZE_X: + poin= &(ob->dsize[0]); break; + case OB_DSIZE_Y: + poin= &(ob->dsize[1]); break; + case OB_DSIZE_Z: + poin= &(ob->dsize[2]); break; + + case OB_LAY: + poin= &(ob->lay); *type= IPO_INT_BIT; break; + + case OB_COL_R: + poin= &(ob->col[0]); + break; + case OB_COL_G: + poin= &(ob->col[1]); + break; + case OB_COL_B: + poin= &(ob->col[2]); + break; + case OB_COL_A: + poin= &(ob->col[3]); + break; + case OB_PD_FSTR: + if(ob->pd) poin= &(ob->pd->f_strength); + break; + case OB_PD_FFALL: + if(ob->pd) poin= &(ob->pd->f_power); + break; + case OB_PD_SDAMP: + if(ob->pd) poin= &(ob->pd->pdef_damp); + break; + case OB_PD_RDAMP: + if(ob->pd) poin= &(ob->pd->pdef_rdamp); + break; + case OB_PD_PERM: + if(ob->pd) poin= &(ob->pd->pdef_perm); + break; + } + } + else if( GS(id->name)==ID_MA) { + + ma= (Material *)id; + + switch(icu->adrcode) { + case MA_COL_R: + poin= &(ma->r); break; + case MA_COL_G: + poin= &(ma->g); break; + case MA_COL_B: + poin= &(ma->b); break; + case MA_SPEC_R: + poin= &(ma->specr); break; + case MA_SPEC_G: + poin= &(ma->specg); break; + case MA_SPEC_B: + poin= &(ma->specb); break; + case MA_MIR_R: + poin= &(ma->mirr); break; + case MA_MIR_G: + poin= &(ma->mirg); break; + case MA_MIR_B: + poin= &(ma->mirb); break; + case MA_REF: + poin= &(ma->ref); break; + case MA_ALPHA: + poin= &(ma->alpha); break; + case MA_EMIT: + poin= &(ma->emit); break; + case MA_AMB: + poin= &(ma->amb); break; + case MA_SPEC: + poin= &(ma->spec); break; + case MA_HARD: + poin= &(ma->har); *type= IPO_SHORT; break; + case MA_SPTR: + poin= &(ma->spectra); break; + case MA_IOR: + poin= &(ma->ang); break; + case MA_MODE: + poin= &(ma->mode); *type= IPO_INT_BIT; break; + case MA_HASIZE: + poin= &(ma->hasize); break; + case MA_TRANSLU: + poin= &(ma->translucency); break; + case MA_RAYM: + poin= &(ma->ray_mirror); break; + case MA_FRESMIR: + poin= &(ma->fresnel_mir); break; + case MA_FRESMIRI: + poin= &(ma->fresnel_mir_i); break; + case MA_FRESTRA: + poin= &(ma->fresnel_tra); break; + case MA_FRESTRAI: + poin= &(ma->fresnel_tra_i); break; + case MA_ADD: + poin= &(ma->add); break; + } + + if(poin==NULL) { + mtex= 0; + if(icu->adrcode & MA_MAP1) mtex= ma->mtex[0]; + else if(icu->adrcode & MA_MAP2) mtex= ma->mtex[1]; + else if(icu->adrcode & MA_MAP3) mtex= ma->mtex[2]; + else if(icu->adrcode & MA_MAP4) mtex= ma->mtex[3]; + else if(icu->adrcode & MA_MAP5) mtex= ma->mtex[4]; + else if(icu->adrcode & MA_MAP6) mtex= ma->mtex[5]; + else if(icu->adrcode & MA_MAP7) mtex= ma->mtex[6]; + else if(icu->adrcode & MA_MAP8) mtex= ma->mtex[7]; + else if(icu->adrcode & MA_MAP9) mtex= ma->mtex[8]; + else if(icu->adrcode & MA_MAP10) mtex= ma->mtex[9]; + + if(mtex) { + poin= give_mtex_poin(mtex, icu->adrcode & (MA_MAP1-1) ); + } + } + } + else if( GS(id->name)==ID_TE) { + tex= (Tex *)id; + + if(tex) poin= give_tex_poin(tex, icu->adrcode, type); + } + else if( GS(id->name)==ID_SEQ) { + seq= (Sequence *)id; + + switch(icu->adrcode) { + case SEQ_FAC1: + poin= &(seq->facf0); break; + } + } + else if( GS(id->name)==ID_CU) { + + poin= &(icu->curval); + + } + else if( GS(id->name)==ID_KE) { + KeyBlock *kb= ((Key *)id)->block.first; + + for(; kb; kb= kb->next) + if(kb->adrcode==icu->adrcode) + break; + if(kb) + poin= &(kb->curval); + + } + else if(GS(id->name)==ID_WO) { + + wo= (World *)id; + + switch(icu->adrcode) { + case WO_HOR_R: + poin= &(wo->horr); break; + case WO_HOR_G: + poin= &(wo->horg); break; + case WO_HOR_B: + poin= &(wo->horb); break; + case WO_ZEN_R: + poin= &(wo->zenr); break; + case WO_ZEN_G: + poin= &(wo->zeng); break; + case WO_ZEN_B: + poin= &(wo->zenb); break; + + case WO_EXPOS: + poin= &(wo->exposure); break; + + case WO_MISI: + poin= &(wo->misi); break; + case WO_MISTDI: + poin= &(wo->mistdist); break; + case WO_MISTSTA: + poin= &(wo->miststa); break; + case WO_MISTHI: + poin= &(wo->misthi); break; + + case WO_STAR_R: + poin= &(wo->starr); break; + case WO_STAR_G: + poin= &(wo->starg); break; + case WO_STAR_B: + poin= &(wo->starb); break; + + case WO_STARDIST: + poin= &(wo->stardist); break; + case WO_STARSIZE: + poin= &(wo->starsize); break; + } + + if(poin==NULL) { + mtex= 0; + if(icu->adrcode & MA_MAP1) mtex= wo->mtex[0]; + else if(icu->adrcode & MA_MAP2) mtex= wo->mtex[1]; + else if(icu->adrcode & MA_MAP3) mtex= wo->mtex[2]; + else if(icu->adrcode & MA_MAP4) mtex= wo->mtex[3]; + else if(icu->adrcode & MA_MAP5) mtex= wo->mtex[4]; + else if(icu->adrcode & MA_MAP6) mtex= wo->mtex[5]; + else if(icu->adrcode & MA_MAP7) mtex= wo->mtex[6]; + else if(icu->adrcode & MA_MAP8) mtex= wo->mtex[7]; + else if(icu->adrcode & MA_MAP9) mtex= wo->mtex[8]; + else if(icu->adrcode & MA_MAP10) mtex= wo->mtex[9]; + + if(mtex) { + poin= give_mtex_poin(mtex, icu->adrcode & (MA_MAP1-1) ); + } + } + } + else if( GS(id->name)==ID_LA) { + + la= (Lamp *)id; + + switch(icu->adrcode) { + case LA_ENERGY: + poin= &(la->energy); break; + case LA_COL_R: + poin= &(la->r); break; + case LA_COL_G: + poin= &(la->g); break; + case LA_COL_B: + poin= &(la->b); break; + case LA_DIST: + poin= &(la->dist); break; + case LA_SPOTSI: + poin= &(la->spotsize); break; + case LA_SPOTBL: + poin= &(la->spotblend); break; + case LA_QUAD1: + poin= &(la->att1); break; + case LA_QUAD2: + poin= &(la->att2); break; + case LA_HALOINT: + poin= &(la->haint); break; + } + + if(poin==NULL) { + mtex= 0; + if(icu->adrcode & MA_MAP1) mtex= la->mtex[0]; + else if(icu->adrcode & MA_MAP2) mtex= la->mtex[1]; + else if(icu->adrcode & MA_MAP3) mtex= la->mtex[2]; + else if(icu->adrcode & MA_MAP4) mtex= la->mtex[3]; + else if(icu->adrcode & MA_MAP5) mtex= la->mtex[4]; + else if(icu->adrcode & MA_MAP6) mtex= la->mtex[5]; + else if(icu->adrcode & MA_MAP7) mtex= la->mtex[6]; + else if(icu->adrcode & MA_MAP8) mtex= la->mtex[7]; + else if(icu->adrcode & MA_MAP9) mtex= la->mtex[8]; + else if(icu->adrcode & MA_MAP10) mtex= la->mtex[9]; + + if(mtex) { + poin= give_mtex_poin(mtex, icu->adrcode & (MA_MAP1-1) ); + } + } + } + else if(GS(id->name)==ID_CA) { + Camera *ca= (Camera *)id; + + /* yafray: aperture & focal distance params */ + switch(icu->adrcode) { + case CAM_LENS: + if(ca->type==CAM_ORTHO) + poin= &(ca->ortho_scale); + else + poin= &(ca->lens); + break; + case CAM_STA: + poin= &(ca->clipsta); break; + case CAM_END: + poin= &(ca->clipend); break; + case CAM_YF_APERT: + poin= &(ca->YF_aperture); break; + case CAM_YF_FDIST: + poin= &(ca->YF_dofdist); break; + case CAM_SHIFT_X: + poin= &(ca->shiftx); break; + case CAM_SHIFT_Y: + poin= &(ca->shifty); break; + } + } + else if(GS(id->name)==ID_SO) { + bSound *snd= (bSound *)id; + + switch(icu->adrcode) { + case SND_VOLUME: + poin= &(snd->volume); break; + case SND_PITCH: + poin= &(snd->pitch); break; + case SND_PANNING: + poin= &(snd->panning); break; + case SND_ATTEN: + poin= &(snd->attenuation); break; + } + } + + return poin; +} + +void set_icu_vars(IpoCurve *icu) +{ + /* defaults. 0.0 for y-extents makes these ignored */ + icu->ymin= icu->ymax= 0.0; + icu->ipo= IPO_BEZ; + + if(icu->blocktype==ID_OB) { + + if(icu->adrcode==OB_LAY) { + icu->ipo= IPO_CONST; + icu->vartype= IPO_BITS; + } + + } + else if(icu->blocktype==ID_MA) { + + if(icu->adrcode < MA_MAP1) { + switch(icu->adrcode) { + case MA_HASIZE: + icu->ymax= 10000.0; break; + case MA_HARD: + icu->ymax= 511.0; break; + case MA_SPEC: + icu->ymax= 2.0; break; + case MA_MODE: + icu->ipo= IPO_CONST; + icu->vartype= IPO_BITS; break; + case MA_RAYM: + icu->ymax= 1.0; break; + case MA_TRANSLU: + icu->ymax= 1.0; break; + case MA_IOR: + icu->ymin= 1.0; + icu->ymax= 3.0; break; + case MA_FRESMIR: + icu->ymax= 5.0; break; + case MA_FRESMIRI: + icu->ymin= 1.0; + icu->ymax= 5.0; break; + case MA_FRESTRA: + icu->ymax= 5.0; break; + case MA_FRESTRAI: + icu->ymin= 1.0; + icu->ymax= 5.0; break; + case MA_ADD: + icu->ymax= 1.0; break; + default: + icu->ymax= 1.0; break; + } + } + else { + switch(icu->adrcode & (MA_MAP1-1)) { + case MAP_OFS_X: + case MAP_OFS_Y: + case MAP_OFS_Z: + case MAP_SIZE_X: + case MAP_SIZE_Y: + case MAP_SIZE_Z: + icu->ymax= 1000.0; + icu->ymin= -1000.0; + + break; + case MAP_R: + case MAP_G: + case MAP_B: + case MAP_DVAR: + case MAP_COLF: + case MAP_VARF: + case MAP_DISP: + icu->ymax= 1.0; + break; + case MAP_NORF: + icu->ymax= 25.0; + break; + } + } + } + else if(icu->blocktype==ID_TE) { + switch(icu->adrcode & (MA_MAP1-1)) { + case TE_NSIZE: + icu->ymin= 0.0001; + icu->ymax= 2.0; break; + case TE_NDEPTH: + icu->vartype= IPO_SHORT; + icu->ipo= IPO_CONST; + icu->ymax= 6.0; break; + case TE_NTYPE: + icu->vartype= IPO_SHORT; + icu->ipo= IPO_CONST; + icu->ymax= 1.0; break; + case TE_TURB: + icu->ymax= 200.0; break; + case TE_VNW1: + case TE_VNW2: + case TE_VNW3: + case TE_VNW4: + icu->ymax= 2.0; + icu->ymin= -2.0; break; + case TE_VNMEXP: + icu->ymax= 10.0; + icu->ymin= 0.01; break; + case TE_VN_DISTM: + icu->vartype= IPO_SHORT; + icu->ipo= IPO_CONST; + icu->ymax= 6.0; break; + case TE_VN_COLT: + icu->vartype= IPO_SHORT; + icu->ipo= IPO_CONST; + icu->ymax= 3.0; break; + case TE_ISCA: + icu->ymax= 10.0; + icu->ymin= 0.01; break; + case TE_DISTA: + icu->ymax= 10.0; break; + case TE_MG_TYP: + icu->vartype= IPO_SHORT; + icu->ipo= IPO_CONST; + icu->ymax= 6.0; break; + case TE_MGH: + icu->ymin= 0.0001; + icu->ymax= 2.0; break; + case TE_MG_LAC: + case TE_MG_OFF: + case TE_MG_GAIN: + icu->ymax= 6.0; break; + case TE_MG_OCT: + icu->ymax= 8.0; break; + case TE_N_BAS1: + case TE_N_BAS2: + icu->vartype= IPO_SHORT; + icu->ipo= IPO_CONST; + icu->ymax= 8.0; break; + case TE_COL_R: + icu->ymax= 0.0; break; + case TE_COL_G: + icu->ymax= 2.0; break; + case TE_COL_B: + icu->ymax= 2.0; break; + case TE_BRIGHT: + icu->ymax= 2.0; break; + case TE_CONTRA: + icu->ymax= 5.0; break; + + } + } + else if(icu->blocktype==ID_SEQ) { + + icu->ymax= 1.0; + + } + else if(icu->blocktype==ID_CU) { + + icu->ymax= 1.0; + + } + else if(icu->blocktype==ID_WO) { + + if(icu->adrcode < MA_MAP1) { + switch(icu->adrcode) { + case WO_EXPOS: + icu->ymax= 5.0; break; + case WO_MISTDI: + case WO_MISTSTA: + case WO_MISTHI: + case WO_STARDIST: + case WO_STARSIZE: + break; + + default: + icu->ymax= 1.0; + break; + } + } + else { + switch(icu->adrcode & (MA_MAP1-1)) { + case MAP_OFS_X: + case MAP_OFS_Y: + case MAP_OFS_Z: + case MAP_SIZE_X: + case MAP_SIZE_Y: + case MAP_SIZE_Z: + icu->ymax= 100.0; + icu->ymin= -100.0; + + break; + case MAP_R: + case MAP_G: + case MAP_B: + case MAP_DVAR: + case MAP_COLF: + case MAP_NORF: + case MAP_VARF: + case MAP_DISP: + icu->ymax= 1.0; + } + } + } + else if(icu->blocktype==ID_LA) { + if(icu->adrcode < MA_MAP1) { + switch(icu->adrcode) { + case LA_ENERGY: + case LA_DIST: + break; + + case LA_COL_R: + case LA_COL_G: + case LA_COL_B: + case LA_SPOTBL: + case LA_QUAD1: + case LA_QUAD2: + icu->ymax= 1.0; break; + case LA_SPOTSI: + icu->ymax= 180.0; break; + case LA_HALOINT: + icu->ymax= 5.0; break; + } + } + else { + switch(icu->adrcode & (MA_MAP1-1)) { + case MAP_OFS_X: + case MAP_OFS_Y: + case MAP_OFS_Z: + case MAP_SIZE_X: + case MAP_SIZE_Y: + case MAP_SIZE_Z: + icu->ymax= 100.0; + icu->ymin= -100.0; + break; + case MAP_R: + case MAP_G: + case MAP_B: + case MAP_DVAR: + case MAP_COLF: + case MAP_NORF: + case MAP_VARF: + case MAP_DISP: + icu->ymax= 1.0; + } + } + } + else if(icu->blocktype==ID_CA) { + + /* yafray: aperture & focal distance params */ + switch(icu->adrcode) { + case CAM_LENS: + icu->ymin= 5.0; + icu->ymax= 1000.0; + break; + case CAM_STA: + icu->ymin= 0.001f; + break; + case CAM_END: + icu->ymin= 0.1f; + break; + case CAM_YF_APERT: + icu->ymin = 0.0; + icu->ymax = 2.0; + break; + case CAM_YF_FDIST: + icu->ymin = 0.0; + icu->ymax = 5000.0; + break; + + case CAM_SHIFT_X: + case CAM_SHIFT_Y: + icu->ymin= -2.0f; + icu->ymax= 2.0f; + break; + } + } + else if(icu->blocktype==ID_SO) { + + switch(icu->adrcode) { + case SND_VOLUME: + icu->ymin= 0.0; + icu->ymax= 1.0; + break; + case SND_PITCH: + icu->ymin= -12.0; + icu->ymin= 12.0; + break; + case SND_PANNING: + icu->ymin= 0.0; + icu->ymax= 1.0; + break; + case SND_ATTEN: + icu->ymin= 0.0; + icu->ymin= 1.0; + break; + } + } + else if(icu->blocktype==ID_CO) { + icu->ymin= 0.0; + icu->ymax= 1.0f; + } + + /* by default, slider limits will be icu->ymin and icu->ymax */ + icu->slide_min= icu->ymin; + icu->slide_max= icu->ymax; +} + +/* not for actions or constraints! */ +void execute_ipo(ID *id, Ipo *ipo) +{ + IpoCurve *icu; + void *poin; + int type; + + if(ipo==NULL) return; + + for(icu= ipo->curve.first; icu; icu= icu->next) { + poin= get_ipo_poin(id, icu, &type); + if(poin) write_ipo_poin(poin, type, icu->curval); + } +} + +void *get_pchan_ipo_poin(bPoseChannel *pchan, int adrcode) +{ + void *poin= NULL; + + switch (adrcode) { + case AC_QUAT_W: + poin= &(pchan->quat[0]); + pchan->flag |= POSE_ROT; + break; + case AC_QUAT_X: + poin= &(pchan->quat[1]); + pchan->flag |= POSE_ROT; + break; + case AC_QUAT_Y: + poin= &(pchan->quat[2]); + pchan->flag |= POSE_ROT; + break; + case AC_QUAT_Z: + poin= &(pchan->quat[3]); + pchan->flag |= POSE_ROT; + break; + case AC_LOC_X: + poin= &(pchan->loc[0]); + pchan->flag |= POSE_LOC; + break; + case AC_LOC_Y: + poin= &(pchan->loc[1]); + pchan->flag |= POSE_LOC; + break; + case AC_LOC_Z: + poin= &(pchan->loc[2]); + pchan->flag |= POSE_LOC; + break; + case AC_SIZE_X: + poin= &(pchan->size[0]); + pchan->flag |= POSE_SIZE; + break; + case AC_SIZE_Y: + poin= &(pchan->size[1]); + pchan->flag |= POSE_SIZE; + break; + case AC_SIZE_Z: + poin= &(pchan->size[2]); + pchan->flag |= POSE_SIZE; + break; + } + return poin; +} + +void execute_action_ipo(bActionChannel *achan, bPoseChannel *pchan) +{ + + if(achan && achan->ipo) { + IpoCurve *icu; + for(icu= achan->ipo->curve.first; icu; icu= icu->next) { + void *poin= get_pchan_ipo_poin(pchan, icu->adrcode); + if(poin) { + write_ipo_poin(poin, IPO_FLOAT, icu->curval); + //printf("execute_action_ipo wrote_ipo_poin: %f\n", icu->curval); + //printf("%s has poin %p value %f\n", achan->name, poin, icu->curval); + } + } + } +} + +/* exception: it does calc for objects... + * now find out why this routine was used anyway! + */ +void do_ipo_nocalc(Ipo *ipo) +{ + Object *ob; + Material *ma; + Tex *tex; + World *wo; + Lamp *la; + Camera *ca; + bSound *snd; + + if(ipo==NULL) return; + + switch(ipo->blocktype) { + case ID_OB: + ob= G.main->object.first; + while(ob) { + if(ob->ipo==ipo) { + do_ob_ipo(ob); + /* execute_ipo((ID *)ob, ipo); */ + } + ob= ob->id.next; + } + break; + case ID_MA: + ma= G.main->mat.first; + while(ma) { + if(ma->ipo==ipo) execute_ipo((ID *)ma, ipo); + ma= ma->id.next; + } + break; + case ID_TE: + tex= G.main->tex.first; + while(tex) { + if(tex->ipo==ipo) execute_ipo((ID *)tex, ipo); + tex=tex->id.next; + } + break; + case ID_WO: + wo= G.main->world.first; + while(wo) { + if(wo->ipo==ipo) execute_ipo((ID *)wo, ipo); + wo= wo->id.next; + } + break; + case ID_LA: + la= G.main->lamp.first; + while(la) { + if(la->ipo==ipo) execute_ipo((ID *)la, ipo); + la= la->id.next; + } + break; + case ID_CA: + ca= G.main->camera.first; + while(ca) { + if(ca->ipo==ipo) execute_ipo((ID *)ca, ipo); + ca= ca->id.next; + } + break; + case ID_SO: + snd= G.main->sound.first; + while(snd) { + if(snd->ipo==ipo) execute_ipo((ID *)snd, ipo); + snd= snd->id.next; + } + break; + } +} + +void do_ipo(Ipo *ipo) +{ + if(ipo) { + float ctime= frame_to_float(G.scene->r.cfra); + calc_ipo(ipo, ctime); + + do_ipo_nocalc(ipo); + } +} + + + +void do_mat_ipo(Material *ma) +{ + float ctime; + + if(ma==NULL || ma->ipo==NULL) return; + + ctime= frame_to_float(G.scene->r.cfra); + /* if(ob->ipoflag & OB_OFFS_OB) ctime-= ob->sf; */ + + calc_ipo(ma->ipo, ctime); + + execute_ipo((ID *)ma, ma->ipo); +} + +void do_ob_ipo(Object *ob) +{ + float ctime; + unsigned int lay; + + if(ob->ipo==NULL) return; + + /* do not set ob->ctime here: for example when parent in invisible layer */ + + ctime= bsystem_time(ob, (float) G.scene->r.cfra, 0.0); + + calc_ipo(ob->ipo, ctime); + + /* Patch: remember localview */ + lay= ob->lay & 0xFF000000; + + execute_ipo((ID *)ob, ob->ipo); + + ob->lay |= lay; + if(ob->id.name[2]=='S' && ob->id.name[3]=='C' && ob->id.name[4]=='E') { + if(strcmp(G.scene->id.name+2, ob->id.name+6)==0) { + G.scene->lay= ob->lay; + copy_view3d_lock(0); + /* no redraw here! creates too many calls */ + } + } +} + +void do_ob_ipodrivers(Object *ob, Ipo *ipo, float ctime) +{ + IpoCurve *icu; + void *poin; + int type; + + for(icu= ipo->curve.first; icu; icu= icu->next) { + if(icu->driver) { + icu->curval= eval_icu(icu, ctime); + poin= get_ipo_poin((ID *)ob, icu, &type); + if(poin) write_ipo_poin(poin, type, icu->curval); + } + } +} + +void do_seq_ipo(Sequence *seq) +{ + float ctime, div; + + /* seq_ipo has an exception: calc both fields immediately */ + + if(seq->ipo) { + if((seq->flag & SEQ_IPO_FRAME_LOCKED) != 0) { + ctime = frame_to_float(G.scene->r.cfra); + div = 1.0; + } else { + ctime= frame_to_float(G.scene->r.cfra + - seq->startdisp); + div= (seq->enddisp - seq->startdisp)/100.0f; + if(div==0.0) return; + } + + /* 2nd field */ + calc_ipo(seq->ipo, (ctime+0.5f)/div); + execute_ipo((ID *)seq, seq->ipo); + seq->facf1= seq->facf0; + + /* 1st field */ + calc_ipo(seq->ipo, ctime/div); + execute_ipo((ID *)seq, seq->ipo); + + } + else seq->facf1= seq->facf0= 1.0f; +} + +int has_ipo_code(Ipo *ipo, int code) +{ + IpoCurve *icu; + + if(ipo==NULL) return 0; + + for(icu= ipo->curve.first; icu; icu= icu->next) { + if(icu->adrcode==code) return 1; + } + return 0; +} + +void do_all_data_ipos() +{ + Material *ma; + Tex *tex; + World *wo; + Ipo *ipo; + Lamp *la; + Key *key; + Camera *ca; + bSound *snd; + Sequence *seq; + Editing *ed; + Base *base; + float ctime; + + ctime= frame_to_float(G.scene->r.cfra); + + /* this exception cannot be depgraphed yet... what todo with objects in other layers?... */ + for(base= G.scene->base.first; base; base= base->next) { + /* only update layer when an ipo */ + if( has_ipo_code(base->object->ipo, OB_LAY) ) { + do_ob_ipo(base->object); + base->lay= base->object->lay; + } + } + + /* layers for the set...*/ + if(G.scene->set) { + for(base= G.scene->set->base.first; base; base= base->next) { + if( has_ipo_code(base->object->ipo, OB_LAY) ) { + do_ob_ipo(base->object); + base->lay= base->object->lay; + } + } + } + + + ipo= G.main->ipo.first; + while(ipo) { + if(ipo->id.us && ipo->blocktype!=ID_OB) { + calc_ipo(ipo, ctime); + } + ipo= ipo->id.next; + } + + for(tex= G.main->tex.first; tex; tex= tex->id.next) { + if(tex->ipo) execute_ipo((ID *)tex, tex->ipo); + } + + for(ma= G.main->mat.first; ma; ma= ma->id.next) { + if(ma->ipo) execute_ipo((ID *)ma, ma->ipo); + } + + for(wo= G.main->world.first; wo; wo= wo->id.next) { + if(wo->ipo) execute_ipo((ID *)wo, wo->ipo); + } + + for(key= G.main->key.first; key; key= key->id.next) { + if(key->ipo) execute_ipo((ID *)key, key->ipo); + } + + la= G.main->lamp.first; + while(la) { + if(la->ipo) execute_ipo((ID *)la, la->ipo); + la= la->id.next; + } + + ca= G.main->camera.first; + while(ca) { + if(ca->ipo) execute_ipo((ID *)ca, ca->ipo); + ca= ca->id.next; + } + + snd= G.main->sound.first; + while(snd) { + if(snd->ipo) execute_ipo((ID *)snd, snd->ipo); + snd= snd->id.next; + } + + /* process FAC Ipos used as volume envelopes */ + ed= G.scene->ed; + if (ed) { + seq= ed->seqbasep->first; + while(seq) { + if ((seq->type == SEQ_RAM_SOUND + || seq->type == SEQ_HD_SOUND) && (seq->ipo) && + (seq->startdisp<=G.scene->r.cfra+2) && + (seq->enddisp>G.scene->r.cfra)) + do_seq_ipo(seq); + seq= seq->next; + } + } + +} + + +int calc_ipo_spec(Ipo *ipo, int adrcode, float *ctime) +{ + IpoCurve *icu; + + if(ipo==NULL) return 0; + + for(icu= ipo->curve.first; icu; icu= icu->next) { + if(icu->adrcode == adrcode) { + if(icu->flag & IPO_LOCK); + else calc_icu(icu, *ctime); + + *ctime= icu->curval; + return 1; + } + } + + return 0; +} + + +/* ************************** */ + +void clear_delta_obipo(Ipo *ipo) +{ + Object *ob; + + if(ipo==NULL) return; + + ob= G.main->object.first; + while(ob) { + if(ob->id.lib==NULL) { + if(ob->ipo==ipo) { + memset(&ob->dloc, 0, 12); + memset(&ob->drot, 0, 12); + memset(&ob->dsize, 0, 12); + } + } + ob= ob->id.next; + } +} + +void add_to_cfra_elem(ListBase *lb, BezTriple *bezt) +{ + CfraElem *ce, *cen; + + ce= lb->first; + while(ce) { + + if( ce->cfra==bezt->vec[1][0] ) { + /* do because of double keys */ + if(bezt->f2 & 1) ce->sel= bezt->f2; + return; + } + else if(ce->cfra > bezt->vec[1][0]) break; + + ce= ce->next; + } + + cen= MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem"); + if(ce) BLI_insertlinkbefore(lb, ce, cen); + else BLI_addtail(lb, cen); + + cen->cfra= bezt->vec[1][0]; + cen->sel= bezt->f2; +} + + + +void make_cfra_list(Ipo *ipo, ListBase *elems) +{ + IpoCurve *icu; + BezTriple *bezt; + int a; + + if(ipo->blocktype==ID_OB) { + for(icu= ipo->curve.first; icu; icu= icu->next) { + if(icu->flag & IPO_VISIBLE) { + switch(icu->adrcode) { + case OB_DLOC_X: + case OB_DLOC_Y: + case OB_DLOC_Z: + case OB_DROT_X: + case OB_DROT_Y: + case OB_DROT_Z: + case OB_DSIZE_X: + case OB_DSIZE_Y: + case OB_DSIZE_Z: + + case OB_LOC_X: + case OB_LOC_Y: + case OB_LOC_Z: + case OB_ROT_X: + case OB_ROT_Y: + case OB_ROT_Z: + case OB_SIZE_X: + case OB_SIZE_Y: + case OB_SIZE_Z: + case OB_PD_FSTR: + case OB_PD_FFALL: + case OB_PD_SDAMP: + case OB_PD_RDAMP: + case OB_PD_PERM: + bezt= icu->bezt; + if(bezt) { + a= icu->totvert; + while(a--) { + add_to_cfra_elem(elems, bezt); + bezt++; + } + } + break; + } + } + } + } + else if(ipo->blocktype==ID_AC) { + for(icu= ipo->curve.first; icu; icu= icu->next) { + if(icu->flag & IPO_VISIBLE) { + switch(icu->adrcode) { + case AC_LOC_X: + case AC_LOC_Y: + case AC_LOC_Z: + case AC_SIZE_X: + case AC_SIZE_Y: + case AC_SIZE_Z: + case AC_QUAT_W: + case AC_QUAT_X: + case AC_QUAT_Y: + case AC_QUAT_Z: + bezt= icu->bezt; + if(bezt) { + a= icu->totvert; + while(a--) { + add_to_cfra_elem(elems, bezt); + bezt++; + } + } + break; + } + } + } + } + else { + for(icu= ipo->curve.first; icu; icu= icu->next) { + if(icu->flag & IPO_VISIBLE) { + bezt= icu->bezt; + if(bezt) { + a= icu->totvert; + while(a--) { + add_to_cfra_elem(elems, bezt); + bezt++; + } + } + } + } + } + + /* what's the point of this little block of code? */ +#if 0 + if(ipo->showkey==0) { + /* deselect all keys */ + ce= elems->first; + while(ce) { + ce->sel= 0; + ce= ce->next; + } + } +#endif +} + +/* *********************** INTERFACE FOR KETSJI ********** */ + + +int IPO_GetChannels(Ipo *ipo, IPO_Channel *channels) +{ + /* channels is max 32 items, allocated by calling function */ + + IpoCurve *icu; + int total=0; + + if(ipo==NULL) return 0; + + for(icu= ipo->curve.first; icu; icu= icu->next) { + channels[total]= icu->adrcode; + total++; + if(total>31) break; + } + + return total; +} + + + +/* Get the float value for channel 'channel' at time 'ctime' */ + +float IPO_GetFloatValue(Ipo *ipo, IPO_Channel channel, float ctime) +{ + if(ipo==NULL) return 0; + + calc_ipo_spec(ipo, channel, &ctime); + + if (OB_ROT_X <= channel && channel <= OB_DROT_Z) { + ctime *= (float)(M_PI_2/9.0); + } + + return ctime; +} diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c new file mode 100644 index 00000000000..8da3ea0b994 --- /dev/null +++ b/source/blender/blenkernel/intern/key.c @@ -0,0 +1,1408 @@ + +/* key.c + * + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_curve_types.h" +#include "DNA_ipo_types.h" +#include "DNA_key_types.h" +#include "DNA_lattice_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_action.h" +#include "BKE_bad_level_calls.h" +#include "BKE_blender.h" +#include "BKE_curve.h" +#include "BKE_global.h" +#include "BKE_ipo.h" +#include "BKE_key.h" +#include "BKE_lattice.h" +#include "BKE_library.h" +#include "BKE_mesh.h" +#include "BKE_main.h" +#include "BKE_object.h" +#include "BKE_utildefines.h" + +#include "BLI_blenlib.h" + +#include "blendef.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define KEY_BPOINT 1 +#define KEY_BEZTRIPLE 2 + +int slurph_opt= 1; + + +void free_key(Key *key) +{ + KeyBlock *kb; + + if(key->ipo) key->ipo->id.us--; + + + while( (kb= key->block.first) ) { + + if(kb->data) MEM_freeN(kb->data); + + BLI_remlink(&key->block, kb); + MEM_freeN(kb); + } + +} + +/* GS reads the memory pointed at in a specific ordering. There are, + * however two definitions for it. I have jotted them down here, both, + * but I think the first one is actually used. The thing is that + * big-endian systems might read this the wrong way round. OTOH, we + * constructed the IDs that are read out with this macro explicitly as + * well. I expect we'll sort it out soon... */ + +/* from blendef: */ +#define GS(a) (*((short *)(a))) + +/* from misc_util: flip the bytes from x */ +/* #define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1]) */ + +Key *add_key(ID *id) /* common function */ +{ + Key *key; + char *el; + + key= alloc_libblock(&G.main->key, ID_KE, "Key"); + + key->type= KEY_NORMAL; + key->from= id; + + if( GS(id->name)==ID_ME) { + el= key->elemstr; + + el[0]= 3; + el[1]= IPO_FLOAT; + el[2]= 0; + + key->elemsize= 12; + } + else if( GS(id->name)==ID_LT) { + el= key->elemstr; + + el[0]= 3; + el[1]= IPO_FLOAT; + el[2]= 0; + + key->elemsize= 12; + } + else if( GS(id->name)==ID_CU) { + el= key->elemstr; + + el[0]= 4; + el[1]= IPO_BPOINT; + el[2]= 0; + + key->elemsize= 16; + } + + return key; +} + +Key *copy_key(Key *key) +{ + Key *keyn; + KeyBlock *kbn, *kb; + + if(key==0) return 0; + + keyn= copy_libblock(key); + + keyn->ipo= copy_ipo(key->ipo); + + duplicatelist(&keyn->block, &key->block); + + kb= key->block.first; + kbn= keyn->block.first; + while(kbn) { + + if(kbn->data) kbn->data= MEM_dupallocN(kbn->data); + if( kb==key->refkey ) keyn->refkey= kbn; + + kbn= kbn->next; + kb= kb->next; + } + + return keyn; +} + +void make_local_key(Key *key) +{ + + /* - only lib users: do nothing + * - only local users: set flag + * - mixed: make copy + */ + if(key==0) return; + + key->id.lib= 0; + new_id(0, (ID *)key, 0); + make_local_ipo(key->ipo); +} + +/* + * Sort shape keys and Ipo curves after a change. This assumes that at most + * one key was moved, which is a valid assumption for the places it's + * currently being called. + */ + +void sort_keys(Key *key) +{ + KeyBlock *kb; + short i, adrcode; + IpoCurve *icu = NULL; + KeyBlock *kb2; + + /* locate the key which is out of position */ + for( kb= key->block.first; kb; kb= kb->next ) + if( kb->next && kb->pos > kb->next->pos ) + break; + + /* if we find a key, move it */ + if( kb ) { + kb = kb->next; /* next key is the out-of-order one */ + BLI_remlink(&key->block, kb); + + /* find the right location and insert before */ + for( kb2=key->block.first; kb2; kb2= kb2->next ) { + if( kb2->pos > kb->pos ) { + BLI_insertlink(&key->block, kb2->prev, kb); + break; + } + } + + /* if more than one Ipo curve, see if this key had a curve */ + + if(key->ipo && key->ipo->curve.first != key->ipo->curve.last ) { + for(icu= key->ipo->curve.first; icu; icu= icu->next) { + /* if we find the curve, remove it and reinsert in the + right place */ + if(icu->adrcode==kb->adrcode) { + IpoCurve *icu2; + BLI_remlink(&key->ipo->curve, icu); + for(icu2= key->ipo->curve.first; icu2; icu2= icu2->next) { + if(icu2->adrcode >= kb2->adrcode) { + BLI_insertlink(&key->ipo->curve, icu2->prev, icu); + break; + } + } + break; + } + } + } + + /* kb points at the moved key, icu at the moved ipo (if it exists). + * go back now and renumber adrcodes */ + + /* first new code */ + adrcode = kb2->adrcode; + for( i = kb->adrcode - adrcode; i >= 0; --i, ++adrcode ) { + /* if the next ipo curve matches the current key, renumber it */ + if(icu && icu->adrcode == kb->adrcode ) { + icu->adrcode = adrcode; + icu = icu->next; + } + /* renumber the shape key */ + kb->adrcode = adrcode; + kb = kb->next; + } + } + + /* new rule; first key is refkey, this to match drawing channels... */ + key->refkey= key->block.first; +} + +/**************** do the key ****************/ + + +void set_four_ipo(float d, float *data, int type) +{ + float d2, d3, fc; + + if(type==KEY_LINEAR) { + data[0]= 0.0f; + data[1]= 1.0f-d; + data[2]= d; + data[3]= 0.0f; + } + else { + d2= d*d; + d3= d2*d; + + if(type==KEY_CARDINAL) { + + fc= 0.71f; + + data[0]= -fc*d3 +2.0f*fc*d2 -fc*d; + data[1]= (2.0f-fc)*d3 +(fc-3.0f)*d2 +1.0f; + data[2]= (fc-2.0f)*d3 +(3.0f-2.0f*fc)*d2 +fc*d; + data[3]= fc*d3 -fc*d2; + } + else if(type==KEY_BSPLINE) { + + data[0]= -0.1666f*d3 +0.5f*d2 -0.5f*d +0.16666f; + data[1]= 0.5f*d3 -d2 +0.6666f; + data[2]= -0.5f*d3 +0.5f*d2 +0.5f*d +0.1666f; + data[3]= 0.1666f*d3 ; + } + } +} + +void set_afgeleide_four_ipo(float d, float *data, int type) +{ + float d2, fc; + + if(type==KEY_LINEAR) { + + } + else { + d2= d*d; + + if(type==KEY_CARDINAL) { + + fc= 0.71f; + + data[0]= -3.0f*fc*d2 +4.0f*fc*d -fc; + data[1]= 3.0f*(2.0f-fc)*d2 +2.0f*(fc-3.0f)*d; + data[2]= 3.0f*(fc-2.0f)*d2 +2.0f*(3.0f-2.0f*fc)*d +fc; + data[3]= 3.0f*fc*d2 -2.0f*fc*d; + } + else if(type==KEY_BSPLINE) { + + data[0]= -0.1666f*3.0f*d2 +d -0.5f; + data[1]= 1.5f*d2 -2.0f*d; + data[2]= -1.5f*d2 +d +0.5f; + data[3]= 0.1666f*3.0f*d2 ; + } + } +} + +static int setkeys(float fac, ListBase *lb, KeyBlock *k[], float *t, int cycl) +{ + /* return 1 means k[2] is the position, return 0 means interpolate */ + KeyBlock *k1, *firstkey; + float d, dpos, ofs=0, lastpos, temp, fval[4]; + short bsplinetype; + + firstkey= lb->first; + k1= lb->last; + lastpos= k1->pos; + dpos= lastpos - firstkey->pos; + + if(fac < firstkey->pos) fac= firstkey->pos; + else if(fac > k1->pos) fac= k1->pos; + + k1=k[0]=k[1]=k[2]=k[3]= firstkey; + t[0]=t[1]=t[2]=t[3]= k1->pos; + + /* if(fac<0.0 || fac>1.0) return 1; */ + + if(k1->next==0) return 1; + + if(cycl) { /* pre-sort */ + k[2]= k1->next; + k[3]= k[2]->next; + if(k[3]==0) k[3]=k1; + while(k1) { + if(k1->next==0) k[0]=k1; + k1=k1->next; + } + k1= k[1]; + t[0]= k[0]->pos; + t[1]+= dpos; + t[2]= k[2]->pos + dpos; + t[3]= k[3]->pos + dpos; + fac+= dpos; + ofs= dpos; + if(k[3]==k[1]) { + t[3]+= dpos; + ofs= 2.0f*dpos; + } + if(facnext; + t[2]= k[2]->pos; + k[3]= k[2]->next; + if(k[3]==0) k[3]= k[2]; + t[3]= k[3]->pos; + k1= k[3]; + } + + while( t[2]next==0) { + if(cycl) { + k1= firstkey; + ofs+= dpos; + } + else if(t[2]==t[3]) break; + } + else k1= k1->next; + + t[0]= t[1]; + k[0]= k[1]; + t[1]= t[2]; + k[1]= k[2]; + t[2]= t[3]; + k[2]= k[3]; + t[3]= k1->pos+ofs; + k[3]= k1; + + if(ofs>2.1+lastpos) break; + } + + bsplinetype= 0; + if(k[1]->type==KEY_BSPLINE || k[2]->type==KEY_BSPLINE) bsplinetype= 1; + + + if(cycl==0) { + if(bsplinetype==0) { /* B spline doesn't go through the control points */ + if(fac<=t[1]) { /* fac for 1st key */ + t[2]= t[1]; + k[2]= k[1]; + return 1; + } + if(fac>=t[2] ) { /* fac after 2nd key */ + return 1; + } + } + else if(fac>t[2]) { /* last key */ + fac= t[2]; + k[3]= k[2]; + t[3]= t[2]; + } + } + + d= t[2]-t[1]; + if(d==0.0) { + if(bsplinetype==0) { + return 1; /* both keys equal */ + } + } + else d= (fac-t[1])/d; + + /* interpolation */ + + set_four_ipo(d, t, k[1]->type); + + if(k[1]->type != k[2]->type) { + set_four_ipo(d, fval, k[2]->type); + + temp= 1.0f-d; + t[0]= temp*t[0]+ d*fval[0]; + t[1]= temp*t[1]+ d*fval[1]; + t[2]= temp*t[2]+ d*fval[2]; + t[3]= temp*t[3]+ d*fval[3]; + } + + return 0; + +} + +static void flerp(int aantal, float *in, float *f0, float *f1, float *f2, float *f3, float *t) +{ + int a; + + for(a=0; afrom==NULL) return; + + if( GS(key->from->name)==ID_ME ) { + ofs[0]= sizeof(MVert); + ofs[1]= 0; + poinsize= ofs[0]; + } + else if( GS(key->from->name)==ID_LT ) { + ofs[0]= sizeof(BPoint); + ofs[1]= 0; + poinsize= ofs[0]; + } + else if( GS(key->from->name)==ID_CU ) { + if(mode==KEY_BPOINT) ofs[0]= sizeof(BPoint); + else ofs[0]= sizeof(BezTriple); + + ofs[1]= 0; + poinsize= ofs[0]; + } + + + if(end>tot) end= tot; + + k1= k->data; + kref= key->refkey->data; + + if(tot != k->totelem) { + ktot= 0.0; + flagflo= 1; + if(k->totelem) { + kd= k->totelem/(float)tot; + } + else return; + } + + /* this exception is needed for slurphing */ + if(start!=0) { + + poin+= poinsize*start; + + if(flagflo) { + ktot+= start*kd; + a= (int)floor(ktot); + if(a) { + ktot-= a; + k1+= a*key->elemsize; + } + } + else k1+= start*key->elemsize; + } + + if(mode==KEY_BEZTRIPLE) { + elemstr[0]= 1; + elemstr[1]= IPO_BEZTRIPLE; + elemstr[2]= 0; + } + + /* just do it here, not above! */ + elemsize= key->elemsize; + if(mode==KEY_BEZTRIPLE) elemsize*= 3; + + for(a=start; aelemstr; + if(mode==KEY_BEZTRIPLE) cp= elemstr; + + ofsp= ofs; + + while( cp[0] ) { + + switch(cp[1]) { + case IPO_FLOAT: + + if(weights) { + memcpy(poin, kref, 4*cp[0]); + if(*weights!=0.0f) + rel_flerp(cp[0], (float *)poin, (float *)kref, (float *)k1, *weights); + weights++; + } + else + memcpy(poin, k1, 4*cp[0]); + + poin+= ofsp[0]; + + break; + case IPO_BPOINT: + memcpy(poin, k1, 3*4); + memcpy(poin+16, k1+12, 4); + + poin+= ofsp[0]; + + break; + case IPO_BEZTRIPLE: + memcpy(poin, k1, 4*12); + poin+= ofsp[0]; + + break; + } + + cp+= 2; ofsp++; + } + + /* are we going to be nasty? */ + if(flagflo) { + ktot+= kd; + while(ktot>=1.0) { + ktot-= 1.0; + k1+= elemsize; + kref+= elemsize; + } + } + else { + k1+= elemsize; + kref+= elemsize; + } + + if(mode==KEY_BEZTRIPLE) a+=2; + } +} + +void cp_cu_key(Curve *cu, KeyBlock *kb, int start, int end) +{ + Nurb *nu; + int a, step = 0, tot, a1, a2; + char *poin; + + tot= count_curveverts(&cu->nurb); + nu= cu->nurb.first; + a= 0; + while(nu) { + if(nu->bp) { + + step= nu->pntsu*nu->pntsv; + + /* exception because keys prefer to work with complete blocks */ + poin= (char *)nu->bp->vec; + poin -= a*sizeof(BPoint); + + a1= MAX2(a, start); + a2= MIN2(a+step, end); + + if(a1key, kb, NULL, KEY_BPOINT); + } + else if(nu->bezt) { + + step= 3*nu->pntsu; + + poin= (char *)nu->bezt->vec; + poin -= a*sizeof(BezTriple); + + a1= MAX2(a, start); + a2= MIN2(a+step, end); + + if(a1key, kb, NULL, KEY_BEZTRIPLE); + + } + a+= step; + nu=nu->next; + } +} + + +static void do_rel_key(int start, int end, int tot, char *basispoin, Key *key, int mode) +{ + KeyBlock *kb; + int *ofsp, ofs[3], elemsize, b; + char *cp, *poin, *reffrom, *from, elemstr[8]; + + if(key->from==NULL) return; + + if( GS(key->from->name)==ID_ME ) { + ofs[0]= sizeof(MVert); + ofs[1]= 0; + } + else if( GS(key->from->name)==ID_LT ) { + ofs[0]= sizeof(BPoint); + ofs[1]= 0; + } + else if( GS(key->from->name)==ID_CU ) { + if(mode==KEY_BPOINT) ofs[0]= sizeof(BPoint); + else ofs[0]= sizeof(BezTriple); + + ofs[1]= 0; + } + + if(end>tot) end= tot; + + /* in case of beztriple */ + elemstr[0]= 1; /* nr of ipofloats */ + elemstr[1]= IPO_BEZTRIPLE; + elemstr[2]= 0; + + /* just here, not above! */ + elemsize= key->elemsize; + if(mode==KEY_BEZTRIPLE) elemsize*= 3; + + /* step 1 init */ + cp_key(start, end, tot, basispoin, key, key->refkey, NULL, mode); + + /* step 2: do it */ + + kb= key->block.first; + while(kb) { + + if(kb!=key->refkey) { + float icuval= kb->curval; + + /* only with value, and no difference allowed */ + if(icuval!=0.0f && kb->totelem==tot) { + float weight, *weights= kb->weights; + + poin= basispoin; + reffrom= key->refkey->data; + from= kb->data; + + poin+= start*ofs[0]; + reffrom+= key->elemsize*start; // key elemsize yes! + from+= key->elemsize*start; + + for(b=start; belemstr; + if(mode==KEY_BEZTRIPLE) cp= elemstr; + + ofsp= ofs; + + while( cp[0] ) { /* cp[0]==amount */ + + switch(cp[1]) { + case IPO_FLOAT: + rel_flerp(cp[0], (float *)poin, (float *)reffrom, (float *)from, weight); + + break; + case IPO_BPOINT: + rel_flerp(3, (float *)poin, (float *)reffrom, (float *)from, icuval); + rel_flerp(1, (float *)(poin+16), (float *)(reffrom+16), (float *)(from+16), icuval); + + break; + case IPO_BEZTRIPLE: + rel_flerp(9, (float *)poin, (float *)reffrom, (float *)from, icuval); + + break; + } + + poin+= ofsp[0]; + + cp+= 2; + ofsp++; + } + + reffrom+= elemsize; + from+= elemsize; + + if(mode==KEY_BEZTRIPLE) b+= 2; + if(weights) weights++; + } + } + } + kb= kb->next; + } +} + + +static void do_key(int start, int end, int tot, char *poin, Key *key, KeyBlock **k, float *t, int mode) +{ + float k1tot = 0.0, k2tot = 0.0, k3tot = 0.0, k4tot = 0.0; + float k1d = 0.0, k2d = 0.0, k3d = 0.0, k4d = 0.0; + int a, ofs[32], *ofsp; + int flagdo= 15, flagflo=0, elemsize, poinsize=0; + char *k1, *k2, *k3, *k4; + char *cp, elemstr[8];; + + if(key->from==0) return; + + if( GS(key->from->name)==ID_ME ) { + ofs[0]= sizeof(MVert); + ofs[1]= 0; + poinsize= ofs[0]; + } + else if( GS(key->from->name)==ID_LT ) { + ofs[0]= sizeof(BPoint); + ofs[1]= 0; + poinsize= ofs[0]; + } + else if( GS(key->from->name)==ID_CU ) { + if(mode==KEY_BPOINT) ofs[0]= sizeof(BPoint); + else ofs[0]= sizeof(BezTriple); + + ofs[1]= 0; + poinsize= ofs[0]; + } + + if(end>tot) end= tot; + + k1= k[0]->data; + k2= k[1]->data; + k3= k[2]->data; + k4= k[3]->data; + + /* test for more or less points (per key!) */ + if(tot != k[0]->totelem) { + k1tot= 0.0; + flagflo |= 1; + if(k[0]->totelem) { + k1d= k[0]->totelem/(float)tot; + } + else flagdo -= 1; + } + if(tot != k[1]->totelem) { + k2tot= 0.0; + flagflo |= 2; + if(k[0]->totelem) { + k2d= k[1]->totelem/(float)tot; + } + else flagdo -= 2; + } + if(tot != k[2]->totelem) { + k3tot= 0.0; + flagflo |= 4; + if(k[0]->totelem) { + k3d= k[2]->totelem/(float)tot; + } + else flagdo -= 4; + } + if(tot != k[3]->totelem) { + k4tot= 0.0; + flagflo |= 8; + if(k[0]->totelem) { + k4d= k[3]->totelem/(float)tot; + } + else flagdo -= 8; + } + + /* this exception needed for slurphing */ + if(start!=0) { + + poin+= poinsize*start; + + if(flagdo & 1) { + if(flagflo & 1) { + k1tot+= start*k1d; + a= (int)floor(k1tot); + if(a) { + k1tot-= a; + k1+= a*key->elemsize; + } + } + else k1+= start*key->elemsize; + } + if(flagdo & 2) { + if(flagflo & 2) { + k2tot+= start*k2d; + a= (int)floor(k2tot); + if(a) { + k2tot-= a; + k2+= a*key->elemsize; + } + } + else k2+= start*key->elemsize; + } + if(flagdo & 4) { + if(flagflo & 4) { + k3tot+= start*k3d; + a= (int)floor(k3tot); + if(a) { + k3tot-= a; + k3+= a*key->elemsize; + } + } + else k3+= start*key->elemsize; + } + if(flagdo & 8) { + if(flagflo & 8) { + k4tot+= start*k4d; + a= (int)floor(k4tot); + if(a) { + k4tot-= a; + k4+= a*key->elemsize; + } + } + else k4+= start*key->elemsize; + } + + } + + /* in case of beztriple */ + elemstr[0]= 1; /* nr of ipofloats */ + elemstr[1]= IPO_BEZTRIPLE; + elemstr[2]= 0; + + /* only here, not above! */ + elemsize= key->elemsize; + if(mode==KEY_BEZTRIPLE) elemsize*= 3; + + for(a=start; aelemstr; + if(mode==KEY_BEZTRIPLE) cp= elemstr; + + ofsp= ofs; + + while( cp[0] ) { /* cp[0]==amount */ + + switch(cp[1]) { + case IPO_FLOAT: + flerp(cp[0], (float *)poin, (float *)k1, (float *)k2, (float *)k3, (float *)k4, t); + poin+= ofsp[0]; + + break; + case IPO_BPOINT: + flerp(3, (float *)poin, (float *)k1, (float *)k2, (float *)k3, (float *)k4, t); + flerp(1, (float *)(poin+16), (float *)(k1+12), (float *)(k2+12), (float *)(k3+12), (float *)(k4+12), t); + + poin+= ofsp[0]; + + break; + case IPO_BEZTRIPLE: + flerp(9, (void *)poin, (void *)k1, (void *)k2, (void *)k3, (void *)k4, t); + flerp(1, (float *)(poin+36), (float *)(k1+36), (float *)(k2+36), (float *)(k3+36), (float *)(k4+36), t); + poin+= ofsp[0]; + + break; + } + + + cp+= 2; + ofsp++; + } + /* lets do it the difficult way: when keys have a different size */ + if(flagdo & 1) { + if(flagflo & 1) { + k1tot+= k1d; + while(k1tot>=1.0) { + k1tot-= 1.0; + k1+= elemsize; + } + } + else k1+= elemsize; + } + if(flagdo & 2) { + if(flagflo & 2) { + k2tot+= k2d; + while(k2tot>=1.0) { + k2tot-= 1.0; + k2+= elemsize; + } + } + else k2+= elemsize; + } + if(flagdo & 4) { + if(flagflo & 4) { + k3tot+= k3d; + while(k3tot>=1.0) { + k3tot-= 1.0; + k3+= elemsize; + } + } + else k3+= elemsize; + } + if(flagdo & 8) { + if(flagflo & 8) { + k4tot+= k4d; + while(k4tot>=1.0) { + k4tot-= 1.0; + k4+= elemsize; + } + } + else k4+= elemsize; + } + + if(mode==KEY_BEZTRIPLE) a+= 2; + } +} + +static float *get_weights_array(Object *ob, char *vgroup) +{ + bDeformGroup *curdef; + MDeformVert *dvert= NULL; + int totvert= 0, index= 0; + + /* no vgroup string set? */ + if(vgroup[0]==0) return NULL; + + /* gather dvert and totvert */ + if(ob->type==OB_MESH) { + Mesh *me= ob->data; + dvert= me->dvert; + totvert= me->totvert; + } + else if(ob->type==OB_LATTICE) { + Lattice *lt= ob->data; + dvert= lt->dvert; + totvert= lt->pntsu*lt->pntsv*lt->pntsw; + } + + if(dvert==NULL) return NULL; + + /* find the group (weak loop-in-loop) */ + for (curdef = ob->defbase.first; curdef; curdef=curdef->next, index++) + if (!strcmp(curdef->name, vgroup)) + break; + + if(curdef) { + float *weights; + int i, j; + + weights= MEM_callocN(totvert*sizeof(float), "weights"); + + for (i=0; i < totvert; i++, dvert++) { + for(j=0; jtotweight; j++) { + if (dvert->dw[j].def_nr == index) { + weights[i]= dvert->dw[j].weight; + break; + } + } + } + return weights; + } + return NULL; +} + +static int do_mesh_key(Object *ob, Mesh *me) +{ + KeyBlock *k[4]; + float cfra, ctime, t[4], delta, loc[3], size[3]; + int a, flag = 0, step; + + if(me->totvert==0) return 0; + if(me->key==NULL) return 0; + if(me->key->block.first==NULL) return 0; + + /* prevent python from screwing this up? anyhoo, the from pointer could be dropped */ + me->key->from= (ID *)me; + + if(me->key->slurph && me->key->type!=KEY_RELATIVE ) { + delta= me->key->slurph; + delta/= me->totvert; + + step= 1; + if(me->totvert>100 && slurph_opt) { + step= me->totvert/50; + delta*= step; + /* in do_key and cp_key the case a>tot is handled */ + } + + cfra= G.scene->r.cfra; + + for(a=0; atotvert; a+=step, cfra+= delta) { + + ctime= bsystem_time(0, cfra, 0.0); + if(calc_ipo_spec(me->key->ipo, KEY_SPEED, &ctime)==0) { + ctime /= 100.0; + CLAMP(ctime, 0.0, 1.0); + } + + flag= setkeys(ctime, &me->key->block, k, t, 0); + if(flag==0) { + + do_key(a, a+step, me->totvert, (char *)me->mvert->co, me->key, k, t, 0); + } + else { + cp_key(a, a+step, me->totvert, (char *)me->mvert->co, me->key, k[2], NULL, 0); + } + } + + if(flag && k[2]==me->key->refkey) tex_space_mesh(me); + else boundbox_mesh(me, loc, size); + } + else { + + if(me->key->type==KEY_RELATIVE) { + KeyBlock *kb; + + for(kb= me->key->block.first; kb; kb= kb->next) + kb->weights= get_weights_array(ob, kb->vgroup); + + do_rel_key(0, me->totvert, me->totvert, (char *)me->mvert->co, me->key, 0); + + for(kb= me->key->block.first; kb; kb= kb->next) { + if(kb->weights) MEM_freeN(kb->weights); + kb->weights= NULL; + } + } + else { + ctime= bsystem_time(ob, G.scene->r.cfra, 0.0); + + if(calc_ipo_spec(me->key->ipo, KEY_SPEED, &ctime)==0) { + ctime /= 100.0; + CLAMP(ctime, 0.0, 1.0); + } + + flag= setkeys(ctime, &me->key->block, k, t, 0); + if(flag==0) { + do_key(0, me->totvert, me->totvert, (char *)me->mvert->co, me->key, k, t, 0); + } + else { + cp_key(0, me->totvert, me->totvert, (char *)me->mvert->co, me->key, k[2], NULL, 0); + } + + if(flag && k[2]==me->key->refkey) tex_space_mesh(me); + else boundbox_mesh(me, loc, size); + } + } + return 1; +} + +static void do_cu_key(Curve *cu, KeyBlock **k, float *t) +{ + Nurb *nu; + int a, step = 0, tot; + char *poin; + + tot= count_curveverts(&cu->nurb); + nu= cu->nurb.first; + a= 0; + + while(nu) { + if(nu->bp) { + + step= nu->pntsu*nu->pntsv; + + /* exception because keys prefer to work with complete blocks */ + poin= (char *)nu->bp->vec; + poin -= a*sizeof(BPoint); + + do_key(a, a+step, tot, poin, cu->key, k, t, KEY_BPOINT); + } + else if(nu->bezt) { + + step= 3*nu->pntsu; + + poin= (char *)nu->bezt->vec; + poin -= a*sizeof(BezTriple); + + do_key(a, a+step, tot, poin, cu->key, k, t, KEY_BEZTRIPLE); + + } + a+= step; + nu=nu->next; + } +} + +static void do_rel_cu_key(Curve *cu, float ctime) +{ + Nurb *nu; + int a, step = 0, tot; + char *poin; + + tot= count_curveverts(&cu->nurb); + nu= cu->nurb.first; + a= 0; + while(nu) { + if(nu->bp) { + + step= nu->pntsu*nu->pntsv; + + /* exception because keys prefer to work with complete blocks */ + poin= (char *)nu->bp->vec; + poin -= a*sizeof(BPoint); + + do_rel_key(a, a+step, tot, poin, cu->key, KEY_BPOINT); + } + else if(nu->bezt) { + + step= 3*nu->pntsu; + + poin= (char *)nu->bezt->vec; + poin -= a*sizeof(BezTriple); + + do_rel_key(a, a+step, tot, poin, cu->key, KEY_BEZTRIPLE); + } + a+= step; + + nu=nu->next; + } +} + +static int do_curve_key(Curve *cu) +{ + KeyBlock *k[4]; + float cfra, ctime, t[4], delta; + int a, flag = 0, step = 0, tot; + + tot= count_curveverts(&cu->nurb); + + if(tot==0) return 0; + if(cu->key==NULL) return 0; + if(cu->key->block.first==NULL) return 0; + + if(cu->key->slurph) { + delta= cu->key->slurph; + delta/= tot; + + step= 1; + if(tot>100 && slurph_opt) { + step= tot/50; + delta*= step; + /* in do_key and cp_key the case a>tot has been handled */ + } + + cfra= G.scene->r.cfra; + + for(a=0; akey->ipo, KEY_SPEED, &ctime)==0) { + ctime /= 100.0; + CLAMP(ctime, 0.0, 1.0); + } + + flag= setkeys(ctime, &cu->key->block, k, t, 0); + if(flag==0) { + + /* do_key(a, a+step, tot, (char *)cu->mvert->co, cu->key, k, t, 0); */ + } + else { + /* cp_key(a, a+step, tot, (char *)cu->mvert->co, cu->key, k[2],0); */ + } + } + + if(flag && k[2]==cu->key->refkey) tex_space_curve(cu); + + + } + else { + + ctime= bsystem_time(NULL, (float)G.scene->r.cfra, 0.0); + + if(cu->key->type==KEY_RELATIVE) { + do_rel_cu_key(cu, ctime); + } + else { + if(calc_ipo_spec(cu->key->ipo, KEY_SPEED, &ctime)==0) { + ctime /= 100.0; + CLAMP(ctime, 0.0, 1.0); + } + + flag= setkeys(ctime, &cu->key->block, k, t, 0); + + if(flag==0) do_cu_key(cu, k, t); + else cp_cu_key(cu, k[2], 0, tot); + + if(flag && k[2]==cu->key->refkey) tex_space_curve(cu); + } + } + + return 1; +} + +static int do_latt_key(Object *ob, Lattice *lt) +{ + KeyBlock *k[4]; + float delta, cfra, ctime, t[4]; + int a, tot, flag; + + if(lt->key==NULL) return 0; + if(lt->key->block.first==NULL) return 0; + + tot= lt->pntsu*lt->pntsv*lt->pntsw; + + if(lt->key->slurph) { + delta= lt->key->slurph; + delta/= (float)tot; + + cfra= G.scene->r.cfra; + + for(a=0; akey->ipo, KEY_SPEED, &ctime)==0) { + ctime /= 100.0; + CLAMP(ctime, 0.0, 1.0); + } + + flag= setkeys(ctime, <->key->block, k, t, 0); + if(flag==0) { + + do_key(a, a+1, tot, (char *)lt->def->vec, lt->key, k, t, 0); + } + else { + cp_key(a, a+1, tot, (char *)lt->def->vec, lt->key, k[2], NULL, 0); + } + } + } + else { + ctime= bsystem_time(NULL, (float)G.scene->r.cfra, 0.0); + + if(lt->key->type==KEY_RELATIVE) { + KeyBlock *kb; + + for(kb= lt->key->block.first; kb; kb= kb->next) + kb->weights= get_weights_array(ob, kb->vgroup); + + do_rel_key(0, tot, tot, (char *)lt->def->vec, lt->key, 0); + + for(kb= lt->key->block.first; kb; kb= kb->next) { + if(kb->weights) MEM_freeN(kb->weights); + kb->weights= NULL; + } + } + else { + if(calc_ipo_spec(lt->key->ipo, KEY_SPEED, &ctime)==0) { + ctime /= 100.0; + CLAMP(ctime, 0.0, 1.0); + } + + flag= setkeys(ctime, <->key->block, k, t, 0); + if(flag==0) { + do_key(0, tot, tot, (char *)lt->def->vec, lt->key, k, t, 0); + } + else { + cp_key(0, tot, tot, (char *)lt->def->vec, lt->key, k[2], NULL, 0); + } + } + } + + if(lt->flag & LT_OUTSIDE) outside_lattice(lt); + + return 1; +} + +/* returns 1 when key applied */ +int do_ob_key(Object *ob) +{ + Key *key= ob_get_key(ob); + + if(key==NULL) + return 0; + + if(ob->shapeflag & (OB_SHAPE_LOCK|OB_SHAPE_TEMPLOCK)) { + KeyBlock *kb= BLI_findlink(&key->block, ob->shapenr-1); + + if(kb==NULL) { + kb= key->block.first; + ob->shapenr= 1; + } + + if(ob->type==OB_MESH) { + Mesh *me= ob->data; + float *weights= get_weights_array(ob, kb->vgroup); + + cp_key(0, me->totvert, me->totvert, (char *)me->mvert->co, key, kb, weights, 0); + + if(weights) MEM_freeN(weights); + } + else if(ob->type==OB_LATTICE) { + Lattice *lt= ob->data; + float *weights= get_weights_array(ob, kb->vgroup); + int tot= lt->pntsu*lt->pntsv*lt->pntsw; + + cp_key(0, tot, tot, (char *)lt->def->vec, key, kb, weights, 0); + + if(weights) MEM_freeN(weights); + } + else if ELEM(ob->type, OB_CURVE, OB_SURF) { + Curve *cu= ob->data; + int tot= count_curveverts(&cu->nurb); + + cp_cu_key(cu, kb, 0, tot); + } + return 1; + } + else { + if(ob->ipoflag & OB_ACTION_KEY) + do_all_object_actions(ob); + else { + calc_ipo(key->ipo, bsystem_time(ob, G.scene->r.cfra, 0.0)); + execute_ipo((ID *)key, key->ipo); + } + + if(ob->type==OB_MESH) return do_mesh_key(ob, ob->data); + else if(ob->type==OB_CURVE) return do_curve_key( ob->data); + else if(ob->type==OB_SURF) return do_curve_key( ob->data); + else if(ob->type==OB_LATTICE) return do_latt_key(ob, ob->data); + } + + return 0; +} + +Key *ob_get_key(Object *ob) +{ + if(ob==NULL) return NULL; + + if(ob->type==OB_MESH) { + Mesh *me= ob->data; + return me->key; + } + else if ELEM(ob->type, OB_CURVE, OB_SURF) { + Curve *cu= ob->data; + return cu->key; + } + else if(ob->type==OB_LATTICE) { + Lattice *lt= ob->data; + return lt->key; + } + return NULL; +} + +/* only the active keyblock */ +KeyBlock *ob_get_keyblock(Object *ob) +{ + Key *key= ob_get_key(ob); + + if (key) { + KeyBlock *kb= BLI_findlink(&key->block, ob->shapenr-1); + return kb; + } + + return NULL; +} + +/* get the appropriate KeyBlock given an index */ +KeyBlock *key_get_keyblock(Key *key, int index) +{ + KeyBlock *kb; + int i; + + if (key) { + kb= key->block.first; + + for (i= 1; i < key->totkey; i++) { + kb= kb->next; + + if (index==i) + return kb; + } + } + + return NULL; +} diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c new file mode 100644 index 00000000000..64c081c27a6 --- /dev/null +++ b/source/blender/blenkernel/intern/lattice.c @@ -0,0 +1,915 @@ +/** + * lattice.c + * + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "DNA_armature_types.h" +#include "DNA_ipo_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_lattice_types.h" +#include "DNA_curve_types.h" +#include "DNA_key_types.h" + +#include "BKE_anim.h" +#include "BKE_armature.h" +#include "BKE_curve.h" +#include "BKE_cdderivedmesh.h" +#include "BKE_DerivedMesh.h" +#include "BKE_deform.h" +#include "BKE_displist.h" +#include "BKE_global.h" +#include "BKE_ipo.h" +#include "BKE_key.h" +#include "BKE_lattice.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_mesh.h" +#include "BKE_modifier.h" +#include "BKE_object.h" +#include "BKE_screen.h" +#include "BKE_utildefines.h" + +#include "BIF_editdeform.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "blendef.h" + +Lattice *editLatt=0; +static Lattice *deformLatt=0; + +static float *latticedata=0, latmat[4][4]; + +void calc_lat_fudu(int flag, int res, float *fu, float *du) +{ + if(res==1) { + *fu= 0.0; + *du= 0.0; + } + else if(flag & LT_GRID) { + *fu= -0.5f*(res-1); + *du= 1.0f; + } + else { + *fu= -1.0f; + *du= 2.0f/(res-1); + } +} + +void resizelattice(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb) +{ + BPoint *bp; + int i, u, v, w; + float fu, fv, fw, uc, vc, wc, du=0.0, dv=0.0, dw=0.0; + float *co, (*vertexCos)[3] = NULL; + + /* vertex weight groups are just freed all for now */ + if(lt->dvert) { + free_dverts(lt->dvert, lt->pntsu*lt->pntsv*lt->pntsw); + lt->dvert= NULL; + } + + while(uNew*vNew*wNew > 32000) { + if( uNew>=vNew && uNew>=wNew) uNew--; + else if( vNew>=uNew && vNew>=wNew) vNew--; + else wNew--; + } + + vertexCos = MEM_mallocN(sizeof(*vertexCos)*uNew*vNew*wNew, "tmp_vcos"); + + calc_lat_fudu(lt->flag, uNew, &fu, &du); + calc_lat_fudu(lt->flag, vNew, &fv, &dv); + calc_lat_fudu(lt->flag, wNew, &fw, &dw); + + /* If old size is different then resolution changed in interface, + * try to do clever reinit of points. Pretty simply idea, we just + * deform new verts by old lattice, but scaling them to match old + * size first. + */ + if (ltOb) { + if (uNew!=1 && lt->pntsu!=1) { + fu = lt->fu; + du = (lt->pntsu-1)*lt->du/(uNew-1); + } + + if (vNew!=1 && lt->pntsv!=1) { + fv = lt->fv; + dv = (lt->pntsv-1)*lt->dv/(vNew-1); + } + + if (wNew!=1 && lt->pntsw!=1) { + fw = lt->fw; + dw = (lt->pntsw-1)*lt->dw/(wNew-1); + } + } + + co = vertexCos[0]; + for(w=0,wc=fw; wtypeu, typev = lt->typev, typew = lt->typew; + + /* works best if we force to linear type (endpoints match) */ + lt->typeu = lt->typev = lt->typew = KEY_LINEAR; + + /* prevent using deformed locations */ + freedisplist(<Ob->disp); + + Mat4CpyMat4(mat, ltOb->obmat); + Mat4One(ltOb->obmat); + lattice_deform_verts(ltOb, NULL, NULL, vertexCos, uNew*vNew*wNew, NULL); + Mat4CpyMat4(ltOb->obmat, mat); + + lt->typeu = typeu; + lt->typev = typev; + lt->typew = typew; + } + + lt->fu = fu; + lt->fv = fv; + lt->fw = fw; + lt->du = du; + lt->dv = dv; + lt->dw = dw; + + lt->pntsu = uNew; + lt->pntsv = vNew; + lt->pntsw = wNew; + + MEM_freeN(lt->def); + lt->def= MEM_callocN(lt->pntsu*lt->pntsv*lt->pntsw*sizeof(BPoint), "lattice bp"); + + bp= lt->def; + + for (i=0; ipntsu*lt->pntsv*lt->pntsw; i++,bp++) { + VECCOPY(bp->vec, vertexCos[i]); + } + + MEM_freeN(vertexCos); +} + +Lattice *add_lattice(char *name) +{ + Lattice *lt; + + lt= alloc_libblock(&G.main->latt, ID_LT, name); + + lt->flag= LT_GRID; + + lt->typeu= lt->typev= lt->typew= KEY_BSPLINE; + + lt->def= MEM_callocN(sizeof(BPoint), "lattvert"); /* temporary */ + resizelattice(lt, 2, 2, 2, NULL); /* creates a uniform lattice */ + + return lt; +} + +Lattice *copy_lattice(Lattice *lt) +{ + Lattice *ltn; + + ltn= copy_libblock(lt); + ltn->def= MEM_dupallocN(lt->def); + + id_us_plus((ID *)ltn->ipo); + + ltn->key= copy_key(ltn->key); + if(ltn->key) ltn->key->from= (ID *)ltn; + + if(lt->dvert) { + int tot= lt->pntsu*lt->pntsv*lt->pntsw; + ltn->dvert = MEM_mallocN (sizeof (MDeformVert)*tot, "Lattice MDeformVert"); + copy_dverts(ltn->dvert, lt->dvert, tot); + } + + return ltn; +} + +void free_lattice(Lattice *lt) +{ + if(lt->def) MEM_freeN(lt->def); + if(lt->dvert) free_dverts(lt->dvert, lt->pntsu*lt->pntsv*lt->pntsw); +} + + +void make_local_lattice(Lattice *lt) +{ + Object *ob; + Lattice *ltn; + int local=0, lib=0; + + /* - only lib users: do nothing + * - only local users: set flag + * - mixed: make copy + */ + + if(lt->id.lib==0) return; + if(lt->id.us==1) { + lt->id.lib= 0; + lt->id.flag= LIB_LOCAL; + new_id(0, (ID *)lt, 0); + return; + } + + ob= G.main->object.first; + while(ob) { + if(ob->data==lt) { + if(ob->id.lib) lib= 1; + else local= 1; + } + ob= ob->id.next; + } + + if(local && lib==0) { + lt->id.lib= 0; + lt->id.flag= LIB_LOCAL; + new_id(0, (ID *)lt, 0); + } + else if(local && lib) { + ltn= copy_lattice(lt); + ltn->id.us= 0; + + ob= G.main->object.first; + while(ob) { + if(ob->data==lt) { + + if(ob->id.lib==0) { + ob->data= ltn; + ltn->id.us++; + lt->id.us--; + } + } + ob= ob->id.next; + } + } +} + +void init_latt_deform(Object *oblatt, Object *ob) +{ + /* we make an array with all differences */ + Lattice *lt = deformLatt = (oblatt==G.obedit)?editLatt:oblatt->data; + BPoint *bp = lt->def; + DispList *dl = find_displist(&oblatt->disp, DL_VERTS); + float *co = dl?dl->verts:NULL; + float *fp, imat[4][4]; + float fu, fv, fw; + int u, v, w; + + fp= latticedata= MEM_mallocN(sizeof(float)*3*deformLatt->pntsu*deformLatt->pntsv*deformLatt->pntsw, "latticedata"); + + /* for example with a particle system: ob==0 */ + if(ob==0) { + /* in deformspace, calc matrix */ + Mat4Invert(latmat, oblatt->obmat); + + /* back: put in deform array */ + Mat4Invert(imat, latmat); + } + else { + /* in deformspace, calc matrix */ + Mat4Invert(imat, oblatt->obmat); + Mat4MulMat4(latmat, ob->obmat, imat); + + /* back: put in deform array */ + Mat4Invert(imat, latmat); + } + + for(w=0,fw=lt->fw; wpntsw; w++,fw+=lt->dw) { + for(v=0,fv=lt->fv; vpntsv; v++, fv+=lt->dv) { + for(u=0,fu=lt->fu; upntsu; u++, bp++, co+=3, fp+=3, fu+=lt->du) { + if (dl) { + fp[0] = co[0] - fu; + fp[1] = co[1] - fv; + fp[2] = co[2] - fw; + } else { + fp[0] = bp->vec[0] - fu; + fp[1] = bp->vec[1] - fv; + fp[2] = bp->vec[2] - fw; + } + + Mat4Mul3Vecfl(imat, fp); + } + } + } +} + +void calc_latt_deform(float *co, float weight) +{ + Lattice *lt; + float u, v, w, tu[4], tv[4], tw[4]; + float *fpw, *fpv, *fpu, vec[3]; + int ui, vi, wi, uu, vv, ww; + + if(latticedata==0) return; + + lt= deformLatt; /* just for shorter notation! */ + + /* co is in local coords, treat with latmat */ + + VECCOPY(vec, co); + Mat4MulVecfl(latmat, vec); + + /* u v w coords */ + + if(lt->pntsu>1) { + u= (vec[0]-lt->fu)/lt->du; + ui= (int)floor(u); + u -= ui; + set_four_ipo(u, tu, lt->typeu); + } + else { + tu[0]= tu[2]= tu[3]= 0.0; tu[1]= 1.0; + ui= 0; + } + + if(lt->pntsv>1) { + v= (vec[1]-lt->fv)/lt->dv; + vi= (int)floor(v); + v -= vi; + set_four_ipo(v, tv, lt->typev); + } + else { + tv[0]= tv[2]= tv[3]= 0.0; tv[1]= 1.0; + vi= 0; + } + + if(lt->pntsw>1) { + w= (vec[2]-lt->fw)/lt->dw; + wi= (int)floor(w); + w -= wi; + set_four_ipo(w, tw, lt->typew); + } + else { + tw[0]= tw[2]= tw[3]= 0.0; tw[1]= 1.0; + wi= 0; + } + + for(ww= wi-1; ww<=wi+2; ww++) { + w= tw[ww-wi+1]; + + if(w!=0.0) { + if(ww>0) { + if(wwpntsw) fpw= latticedata + 3*ww*lt->pntsu*lt->pntsv; + else fpw= latticedata + 3*(lt->pntsw-1)*lt->pntsu*lt->pntsv; + } + else fpw= latticedata; + + for(vv= vi-1; vv<=vi+2; vv++) { + v= w*tv[vv-vi+1]; + + if(v!=0.0) { + if(vv>0) { + if(vvpntsv) fpv= fpw + 3*vv*lt->pntsu; + else fpv= fpw + 3*(lt->pntsv-1)*lt->pntsu; + } + else fpv= fpw; + + for(uu= ui-1; uu<=ui+2; uu++) { + u= weight*v*tu[uu-ui+1]; + + if(u!=0.0) { + if(uu>0) { + if(uupntsu) fpu= fpv + 3*uu; + else fpu= fpv + 3*(lt->pntsu-1); + } + else fpu= fpv; + + co[0]+= u*fpu[0]; + co[1]+= u*fpu[1]; + co[2]+= u*fpu[2]; + } + } + } + } + } + } +} + +void end_latt_deform() +{ + + MEM_freeN(latticedata); + latticedata= 0; +} + + /* calculations is in local space of deformed object + so we store in latmat transform from path coord inside object + */ +typedef struct { + float dmin[3], dmax[3], dsize, dloc[3]; + float curvespace[4][4], objectspace[4][4], objectspace3[3][3]; + int no_rot_axis; +} CurveDeform; + +static void init_curve_deform(Object *par, Object *ob, CurveDeform *cd, int dloc) +{ + Mat4Invert(ob->imat, ob->obmat); + Mat4MulMat4(cd->objectspace, par->obmat, ob->imat); + Mat4Invert(cd->curvespace, cd->objectspace); + Mat3CpyMat4(cd->objectspace3, cd->objectspace); + + // offset vector for 'no smear' + if(dloc) { + Mat4Invert(par->imat, par->obmat); + VecMat4MulVecfl(cd->dloc, par->imat, ob->obmat[3]); + } + else cd->dloc[0]=cd->dloc[1]=cd->dloc[2]= 0.0f; + + cd->no_rot_axis= 0; +} + +/* this makes sure we can extend for non-cyclic. *vec needs 4 items! */ +static int where_on_path_deform(Object *ob, float ctime, float *vec, float *dir) /* returns OK */ +{ + Curve *cu= ob->data; + BevList *bl; + float ctime1; + int cycl=0; + + /* test for cyclic */ + bl= cu->bev.first; + if(bl && bl->poly> -1) cycl= 1; + + if(cycl==0) { + ctime1= CLAMPIS(ctime, 0.0, 1.0); + } + else ctime1= ctime; + + /* vec needs 4 items */ + if(where_on_path(ob, ctime1, vec, dir)) { + + if(cycl==0) { + Path *path= cu->path; + float dvec[3]; + + if(ctime < 0.0) { + VecSubf(dvec, path->data+4, path->data); + VecMulf(dvec, ctime*(float)path->len); + VECADD(vec, vec, dvec); + } + else if(ctime > 1.0) { + VecSubf(dvec, path->data+4*path->len-4, path->data+4*path->len-8); + VecMulf(dvec, (ctime-1.0)*(float)path->len); + VECADD(vec, vec, dvec); + } + } + return 1; + } + return 0; +} + + /* for each point, rotate & translate to curve */ + /* use path, since it has constant distances */ + /* co: local coord, result local too */ + /* returns quaternion for rotation, using cd->no_rot_axis */ + /* axis is using another define!!! */ +static float *calc_curve_deform(Object *par, float *co, short axis, CurveDeform *cd) +{ + Curve *cu= par->data; + float fac, loc[4], dir[3], cent[3]; + short upflag, index; + + if(axis==MOD_CURVE_POSX || axis==MOD_CURVE_NEGX) { + upflag= OB_POSZ; + cent[0]= 0.0; + cent[1]= co[1]; + cent[2]= co[2]; + index= 0; + } + else if(axis==MOD_CURVE_POSY || axis==MOD_CURVE_NEGY) { + upflag= OB_POSZ; + cent[0]= co[0]; + cent[1]= 0.0; + cent[2]= co[2]; + index= 1; + } + else { + upflag= OB_POSY; + cent[0]= co[0]; + cent[1]= co[1]; + cent[2]= 0.0; + index= 2; + } + /* to be sure, mostly after file load */ + if(cu->path==NULL) { + makeDispListCurveTypes(par, 0); + if(cu->path==NULL) return NULL; // happens on append... + } + + /* options */ + if(ELEM3(axis, OB_NEGX, OB_NEGY, OB_NEGZ)) { + if(cu->flag & CU_STRETCH) + fac= (-co[index]-cd->dmax[index])/(cd->dmax[index] - cd->dmin[index]); + else + fac= (cd->dloc[index])/(cu->path->totdist) - (co[index]-cd->dmax[index])/(cu->path->totdist); + } + else { + if(cu->flag & CU_STRETCH) + fac= (co[index]-cd->dmin[index])/(cd->dmax[index] - cd->dmin[index]); + else + fac= (cd->dloc[index])/(cu->path->totdist) + (co[index]-cd->dmin[index])/(cu->path->totdist); + } + + /* we want the ipo to work on the default 100 frame range, because there's no + actual time involved in path position */ + if(cu->ipo) { + fac*= 100.0f; + if(calc_ipo_spec(cu->ipo, CU_SPEED, &fac)==0) + fac/= 100.0; + } + + if( where_on_path_deform(par, fac, loc, dir)) { /* returns OK */ + float q[4], mat[3][3]; + float *quat; + + if(cd->no_rot_axis) /* set by caller */ + dir[cd->no_rot_axis-1]= 0.0f; + + /* -1 for compatibility with old track defines */ + quat= vectoquat(dir, axis-1, upflag); /* gives static quat */ + + /* the tilt */ + if(loc[3]!=0.0) { + Normalize(dir); + q[0]= (float)cos(0.5*loc[3]); + fac= (float)sin(0.5*loc[3]); + q[1]= -fac*dir[0]; + q[2]= -fac*dir[1]; + q[3]= -fac*dir[2]; + QuatMul(quat, q, quat); + } + QuatToMat3(quat, mat); + + /* local rotation */ + Mat3MulVecfl(mat, cent); + + /* translation */ + VECADD(co, cent, loc); + + return quat; + } + return NULL; +} + +void curve_deform_verts(Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], int numVerts, char *vgroup, short defaxis) +{ + Curve *cu = cuOb->data; + int a, flag = cu->flag; + CurveDeform cd; + int use_vgroups; + + cu->flag |= (CU_PATH|CU_FOLLOW); // needed for path & bevlist + + init_curve_deform(cuOb, target, &cd, (cu->flag & CU_STRETCH)==0); + + /* check whether to use vertex groups (only possible if target is a Mesh) + * we want either a Mesh with no derived data, or derived data with + * deformverts + */ + if(target && target->type==OB_MESH) { + /* if there's derived data without deformverts, don't use vgroups */ + if(dm && !dm->getVertData(dm, 0, CD_MDEFORMVERT)) + use_vgroups = 0; + else + use_vgroups = 1; + } else + use_vgroups = 0; + + if(vgroup && vgroup[0] && use_vgroups) { + bDeformGroup *curdef; + Mesh *me= target->data; + int index; + + /* find the group (weak loop-in-loop) */ + for(index = 0, curdef = target->defbase.first; curdef; + curdef = curdef->next, index++) + if (!strcmp(curdef->name, vgroup)) + break; + + if(curdef && (me->dvert || dm)) { + MDeformVert *dvert = me->dvert; + float vec[3]; + int j; + + INIT_MINMAX(cd.dmin, cd.dmax); + + for(a = 0; a < numVerts; a++, dvert++) { + if(dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT); + + for(j = 0; j < dvert->totweight; j++) { + if(dvert->dw[j].def_nr == index) { + Mat4MulVecfl(cd.curvespace, vertexCos[a]); + DO_MINMAX(vertexCos[a], cd.dmin, cd.dmax); + break; + } + } + } + + dvert = me->dvert; + for(a = 0; a < numVerts; a++, dvert++) { + if(dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT); + + for(j = 0; j < dvert->totweight; j++) { + if(dvert->dw[j].def_nr == index) { + VECCOPY(vec, vertexCos[a]); + calc_curve_deform(cuOb, vec, defaxis, &cd); + VecLerpf(vertexCos[a], vertexCos[a], vec, + dvert->dw[j].weight); + Mat4MulVecfl(cd.objectspace, vertexCos[a]); + break; + } + } + } + } + } else { + INIT_MINMAX(cd.dmin, cd.dmax); + + for(a = 0; a < numVerts; a++) { + Mat4MulVecfl(cd.curvespace, vertexCos[a]); + DO_MINMAX(vertexCos[a], cd.dmin, cd.dmax); + } + + for(a = 0; a < numVerts; a++) { + calc_curve_deform(cuOb, vertexCos[a], defaxis, &cd); + Mat4MulVecfl(cd.objectspace, vertexCos[a]); + } + } + cu->flag = flag; +} + +/* input vec and orco = local coord in armature space */ +/* orco is original not-animated or deformed reference point */ +/* result written in vec and mat */ +void curve_deform_vector(Object *cuOb, Object *target, float *orco, float *vec, float mat[][3], int no_rot_axis) +{ + CurveDeform cd; + float *quat; + + init_curve_deform(cuOb, target, &cd, 0); /* 0 no dloc */ + cd.no_rot_axis= no_rot_axis; /* option to only rotate for XY, for example */ + + VECCOPY(cd.dmin, orco); + VECCOPY(cd.dmax, orco); + + Mat4MulVecfl(cd.curvespace, vec); + + quat= calc_curve_deform(cuOb, vec, target->trackflag+1, &cd); + if(quat) { + float qmat[3][3]; + + QuatToMat3(quat, qmat); + Mat3MulMat3(mat, qmat, cd.objectspace3); + } + else + Mat3One(mat); + + Mat4MulVecfl(cd.objectspace, vec); + +} + +void lattice_deform_verts(Object *laOb, Object *target, DerivedMesh *dm, + float (*vertexCos)[3], int numVerts, char *vgroup) +{ + int a; + int use_vgroups; + + init_latt_deform(laOb, target); + + /* check whether to use vertex groups (only possible if target is a Mesh) + * we want either a Mesh with no derived data, or derived data with + * deformverts + */ + if(target && target->type==OB_MESH) { + /* if there's derived data without deformverts, don't use vgroups */ + if(dm && !dm->getVertData(dm, 0, CD_MDEFORMVERT)) + use_vgroups = 0; + else + use_vgroups = 1; + } else + use_vgroups = 0; + + if(vgroup && vgroup[0] && use_vgroups) { + bDeformGroup *curdef; + Mesh *me = target->data; + int index = 0; + + /* find the group (weak loop-in-loop) */ + for(curdef = target->defbase.first; curdef; + curdef = curdef->next, index++) + if(!strcmp(curdef->name, vgroup)) break; + + if(curdef && (me->dvert || dm)) { + MDeformVert *dvert = me->dvert; + int j; + + for(a = 0; a < numVerts; a++, dvert++) { + if(dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT); + for(j = 0; j < dvert->totweight; j++) { + if (dvert->dw[j].def_nr == index) { + calc_latt_deform(vertexCos[a], dvert->dw[j].weight); + } + } + } + } + } else { + for(a = 0; a < numVerts; a++) { + calc_latt_deform(vertexCos[a], 1.0f); + } + } + end_latt_deform(); +} + +int object_deform_mball(Object *ob) +{ + if(ob->parent && ob->parent->type==OB_LATTICE && ob->partype==PARSKEL) { + DispList *dl; + + for (dl=ob->disp.first; dl; dl=dl->next) { + lattice_deform_verts(ob->parent, ob, NULL, + (float(*)[3]) dl->verts, dl->nr, NULL); + } + + return 1; + } else { + return 0; + } +} + +static BPoint *latt_bp(Lattice *lt, int u, int v, int w) +{ + return lt->def+ u + v*lt->pntsu + w*lt->pntsu*lt->pntsv; +} + +void outside_lattice(Lattice *lt) +{ + BPoint *bp, *bp1, *bp2; + int u, v, w; + float fac1, du=0.0, dv=0.0, dw=0.0; + + bp= lt->def; + + if(lt->pntsu>1) du= 1.0f/((float)lt->pntsu-1); + if(lt->pntsv>1) dv= 1.0f/((float)lt->pntsv-1); + if(lt->pntsw>1) dw= 1.0f/((float)lt->pntsw-1); + + for(w=0; wpntsw; w++) { + + for(v=0; vpntsv; v++) { + + for(u=0; upntsu; u++, bp++) { + if(u==0 || v==0 || w==0 || u==lt->pntsu-1 || v==lt->pntsv-1 || w==lt->pntsw-1); + else { + + bp->hide= 1; + bp->f1 &= ~SELECT; + + /* u extrema */ + bp1= latt_bp(lt, 0, v, w); + bp2= latt_bp(lt, lt->pntsu-1, v, w); + + fac1= du*u; + bp->vec[0]= (1.0f-fac1)*bp1->vec[0] + fac1*bp2->vec[0]; + bp->vec[1]= (1.0f-fac1)*bp1->vec[1] + fac1*bp2->vec[1]; + bp->vec[2]= (1.0f-fac1)*bp1->vec[2] + fac1*bp2->vec[2]; + + /* v extrema */ + bp1= latt_bp(lt, u, 0, w); + bp2= latt_bp(lt, u, lt->pntsv-1, w); + + fac1= dv*v; + bp->vec[0]+= (1.0f-fac1)*bp1->vec[0] + fac1*bp2->vec[0]; + bp->vec[1]+= (1.0f-fac1)*bp1->vec[1] + fac1*bp2->vec[1]; + bp->vec[2]+= (1.0f-fac1)*bp1->vec[2] + fac1*bp2->vec[2]; + + /* w extrema */ + bp1= latt_bp(lt, u, v, 0); + bp2= latt_bp(lt, u, v, lt->pntsw-1); + + fac1= dw*w; + bp->vec[0]+= (1.0f-fac1)*bp1->vec[0] + fac1*bp2->vec[0]; + bp->vec[1]+= (1.0f-fac1)*bp1->vec[1] + fac1*bp2->vec[1]; + bp->vec[2]+= (1.0f-fac1)*bp1->vec[2] + fac1*bp2->vec[2]; + + VecMulf(bp->vec, 0.3333333f); + + } + } + + } + + } + +} + +float (*lattice_getVertexCos(struct Object *ob, int *numVerts_r))[3] +{ + Lattice *lt = (G.obedit==ob)?editLatt:ob->data; + int i, numVerts = *numVerts_r = lt->pntsu*lt->pntsv*lt->pntsw; + float (*vertexCos)[3] = MEM_mallocN(sizeof(*vertexCos)*numVerts,"lt_vcos"); + + for (i=0; idef[i].vec); + } + + return vertexCos; +} + +void lattice_applyVertexCos(struct Object *ob, float (*vertexCos)[3]) +{ + Lattice *lt = ob->data; + int i, numVerts = lt->pntsu*lt->pntsv*lt->pntsw; + + for (i=0; idef[i].vec, vertexCos[i]); + } +} + +void lattice_calc_modifiers(Object *ob) +{ + float (*vertexCos)[3] = NULL; + ModifierData *md = modifiers_getVirtualModifierList(ob); + int numVerts, editmode = G.obedit==ob; + + freedisplist(&ob->disp); + + if (!editmode) { + do_ob_key(ob); + } + + for (; md; md=md->next) { + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + if (!(md->mode&eModifierMode_Realtime)) continue; + if (editmode && !(md->mode&eModifierMode_Editmode)) continue; + if (mti->isDisabled && mti->isDisabled(md)) continue; + if (mti->type!=eModifierTypeType_OnlyDeform) continue; + + if (!vertexCos) vertexCos = lattice_getVertexCos(ob, &numVerts); + mti->deformVerts(md, ob, NULL, vertexCos, numVerts); + } + + if (vertexCos) { + DispList *dl = MEM_callocN(sizeof(*dl), "lt_dl"); + dl->type = DL_VERTS; + dl->parts = 1; + dl->nr = numVerts; + dl->verts = (float*) vertexCos; + + BLI_addtail(&ob->disp, dl); + } +} diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c new file mode 100644 index 00000000000..28a6aad7b4d --- /dev/null +++ b/source/blender/blenkernel/intern/library.c @@ -0,0 +1,1098 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + * Contains management of ID's and libraries + * allocate and free of all library data + * + */ + + +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_guardedalloc.h" + +/* all types are needed here, in order to do memory operations */ +#include "DNA_ID.h" +#include "DNA_listBase.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_mesh_types.h" +#include "DNA_lattice_types.h" +#include "DNA_curve_types.h" +#include "DNA_meta_types.h" +#include "DNA_material_types.h" +#include "DNA_texture_types.h" +#include "DNA_image_types.h" +#include "DNA_wave_types.h" +#include "DNA_lamp_types.h" +#include "DNA_camera_types.h" +#include "DNA_ipo_types.h" +#include "DNA_key_types.h" +#include "DNA_world_types.h" +#include "DNA_screen_types.h" +#include "DNA_vfont_types.h" +#include "DNA_text_types.h" +#include "DNA_sound_types.h" +#include "DNA_group_types.h" +#include "DNA_armature_types.h" +#include "DNA_action_types.h" +#include "DNA_userdef_types.h" +#include "DNA_node_types.h" +#include "DNA_nla_types.h" +#include "DNA_effect_types.h" +#include "DNA_brush_types.h" + +#include "BLI_blenlib.h" +#include "BLI_dynstr.h" + +#include "BKE_bad_level_calls.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_global.h" +#include "BKE_sound.h" +#include "BKE_object.h" +#include "BKE_screen.h" +#include "BKE_script.h" +#include "BKE_mesh.h" +#include "BKE_material.h" +#include "BKE_curve.h" +#include "BKE_mball.h" +#include "BKE_text.h" +#include "BKE_texture.h" +#include "BKE_scene.h" +#include "BKE_icons.h" +#include "BKE_image.h" +#include "BKE_ipo.h" +#include "BKE_key.h" +#include "BKE_world.h" +#include "BKE_font.h" +#include "BKE_group.h" +#include "BKE_lattice.h" +#include "BKE_armature.h" +#include "BKE_action.h" +#include "BKE_node.h" +#include "BKE_effect.h" +#include "BKE_brush.h" +#include "BKE_idprop.h" + +#include "BPI_script.h" + +#define MAX_IDPUP 60 /* was 24 */ + +/* ************* general ************************ */ + +void id_lib_extern(ID *id) +{ + if(id) { + if(id->flag & LIB_INDIRECT) { + id->flag -= LIB_INDIRECT; + id->flag |= LIB_EXTERN; + } + } +} + +void id_us_plus(ID *id) +{ + if(id) { + id->us++; + if(id->flag & LIB_INDIRECT) { + id->flag -= LIB_INDIRECT; + id->flag |= LIB_EXTERN; + } + } +} + +ListBase *wich_libbase(Main *mainlib, short type) +{ + switch( type ) { + case ID_SCE: + return &(mainlib->scene); + case ID_LI: + return &(mainlib->library); + case ID_OB: + return &(mainlib->object); + case ID_ME: + return &(mainlib->mesh); + case ID_CU: + return &(mainlib->curve); + case ID_MB: + return &(mainlib->mball); + case ID_MA: + return &(mainlib->mat); + case ID_TE: + return &(mainlib->tex); + case ID_IM: + return &(mainlib->image); + case ID_WV: + return &(mainlib->wave); + case ID_LT: + return &(mainlib->latt); + case ID_LA: + return &(mainlib->lamp); + case ID_CA: + return &(mainlib->camera); + case ID_IP: + return &(mainlib->ipo); + case ID_KE: + return &(mainlib->key); + case ID_WO: + return &(mainlib->world); + case ID_SCR: + return &(mainlib->screen); + case ID_VF: + return &(mainlib->vfont); + case ID_TXT: + return &(mainlib->text); + case ID_SCRIPT: + return &(mainlib->script); + case ID_SO: + return &(mainlib->sound); + case ID_GR: + return &(mainlib->group); + case ID_AR: + return &(mainlib->armature); + case ID_AC: + return &(mainlib->action); + case ID_NT: + return &(mainlib->nodetree); + case ID_BR: + return &(mainlib->brush); + } + return 0; +} + +/* Flag all ids in listbase */ +void flag_listbase_ids(ListBase *lb, short flag, short value) +{ + ID *id; + if (value) { + for(id= lb->first; id; id= id->next) id->flag |= flag; + } else { + flag = ~flag; + for(id= lb->first; id; id= id->next) id->flag &= flag; + } +} + +/* Flag all ids in listbase */ +void flag_all_listbases_ids(short flag, short value) +{ + ListBase *lbarray[MAX_LIBARRAY]; + int a; + a= set_listbasepointers(G.main, lbarray); + while(a--) flag_listbase_ids(lbarray[a], flag, value); +} + + +/* note: MAX_LIBARRAY define should match this code */ +int set_listbasepointers(Main *main, ListBase **lb) +{ + /* BACKWARDS! also watch order of free-ing! (mesh<->mat) */ + + lb[0]= &(main->ipo); + lb[1]= &(main->key); + lb[2]= &(main->image); + lb[3]= &(main->tex); + lb[4]= &(main->mat); + lb[5]= &(main->vfont); + + /* Important!: When adding a new object type, + * the specific data should be inserted here + */ + + lb[6]= &(main->armature); + lb[7]= &(main->action); + + lb[8]= &(main->mesh); + lb[9]= &(main->curve); + lb[10]= &(main->mball); + + lb[11]= &(main->wave); + lb[12]= &(main->latt); + lb[13]= &(main->lamp); + lb[14]= &(main->camera); + + lb[15]= &(main->text); + lb[16]= &(main->sound); + lb[17]= &(main->group); + lb[18]= &(main->nodetree); + lb[19]= &(main->brush); + lb[20]= &(main->script); + + lb[21]= &(main->world); + lb[22]= &(main->screen); + lb[23]= &(main->object); + lb[24]= &(main->scene); + lb[25]= &(main->library); + + lb[26]= NULL; + + return 26; +} + +/* *********** ALLOC AND FREE ***************** + +free_libblock(ListBase *lb, ID *id ) + provide a list-basis and datablock, but only ID is read + +void *alloc_libblock(ListBase *lb, type, name) + inserts in list and returns a new ID + + ***************************** */ + +static ID *alloc_libblock_notest(short type) +{ + ID *id= NULL; + + switch( type ) { + case ID_SCE: + id= MEM_callocN(sizeof(Scene), "scene"); + break; + case ID_LI: + id= MEM_callocN(sizeof(Library), "library"); + break; + case ID_OB: + id= MEM_callocN(sizeof(Object), "object"); + break; + case ID_ME: + id= MEM_callocN(sizeof(Mesh), "mesh"); + break; + case ID_CU: + id= MEM_callocN(sizeof(Curve), "curve"); + break; + case ID_MB: + id= MEM_callocN(sizeof(MetaBall), "mball"); + break; + case ID_MA: + id= MEM_callocN(sizeof(Material), "mat"); + break; + case ID_TE: + id= MEM_callocN(sizeof(Tex), "tex"); + break; + case ID_IM: + id= MEM_callocN(sizeof(Image), "image"); + break; + case ID_WV: + id= MEM_callocN(sizeof(Wave), "wave"); + break; + case ID_LT: + id= MEM_callocN(sizeof(Lattice), "latt"); + break; + case ID_LA: + id= MEM_callocN(sizeof(Lamp), "lamp"); + break; + case ID_CA: + id= MEM_callocN(sizeof(Camera), "camera"); + break; + case ID_IP: + id= MEM_callocN(sizeof(Ipo), "ipo"); + break; + case ID_KE: + id= MEM_callocN(sizeof(Key), "key"); + break; + case ID_WO: + id= MEM_callocN(sizeof(World), "world"); + break; + case ID_SCR: + id= MEM_callocN(sizeof(bScreen), "screen"); + break; + case ID_VF: + id= MEM_callocN(sizeof(VFont), "vfont"); + break; + case ID_TXT: + id= MEM_callocN(sizeof(Text), "text"); + break; + case ID_SCRIPT: + id= MEM_callocN(sizeof(Script), "script"); + break; + case ID_SO: + id= MEM_callocN(sizeof(bSound), "sound"); + break; + case ID_GR: + id= MEM_callocN(sizeof(Group), "group"); + break; + case ID_AR: + id = MEM_callocN(sizeof(bArmature), "armature"); + break; + case ID_AC: + id = MEM_callocN(sizeof(bAction), "action"); + break; + case ID_NT: + id = MEM_callocN(sizeof(bNodeTree), "nodetree"); + break; + case ID_BR: + id = MEM_callocN(sizeof(Brush), "brush"); + break; + } + return id; +} + +/* used everywhere in blenkernel and text.c */ +void *alloc_libblock(ListBase *lb, short type, const char *name) +{ + ID *id= NULL; + + id= alloc_libblock_notest(type); + if(id) { + BLI_addtail(lb, id); + id->us= 1; + id->icon_id = 0; + *( (short *)id->name )= type; + new_id(lb, id, name); + /* alphabetic insterion: is in new_id */ + } + return id; +} + +/* GS reads the memory pointed at in a specific ordering. + only use this definition, makes little and big endian systems + work fine, in conjunction with MAKE_ID */ + +/* from blendef: */ +#define GS(a) (*((short *)(a))) + +/* used everywhere in blenkernel and text.c */ +void *copy_libblock(void *rt) +{ + ID *idn, *id; + ListBase *lb; + char *cp, *cpn; + int idn_len; + + id= rt; + + lb= wich_libbase(G.main, GS(id->name)); + idn= alloc_libblock(lb, GS(id->name), id->name+2); + + idn_len= MEM_allocN_len(idn); + if(idn_len - sizeof(ID) > 0) { + cp= (char *)id; + cpn= (char *)idn; + memcpy(cpn+sizeof(ID), cp+sizeof(ID), idn_len - sizeof(ID)); + } + + id->newid= idn; + idn->flag |= LIB_NEW; + if (id->properties) idn->properties = IDP_CopyProperty(id->properties); + + return idn; +} + +static void free_library(Library *lib) +{ + /* no freeing needed for libraries yet */ +} + +/* used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c */ +void free_libblock(ListBase *lb, void *idv) +{ + ID *id= idv; + + switch( GS(id->name) ) { /* GetShort from util.h */ + case ID_SCE: + free_scene((Scene *)id); + break; + case ID_LI: + free_library((Library *)id); + break; + case ID_OB: + free_object((Object *)id); + break; + case ID_ME: + free_mesh((Mesh *)id); + break; + case ID_CU: + free_curve((Curve *)id); + break; + case ID_MB: + free_mball((MetaBall *)id); + break; + case ID_MA: + free_material((Material *)id); + break; + case ID_TE: + free_texture((Tex *)id); + break; + case ID_IM: + free_image((Image *)id); + break; + case ID_WV: + /* free_wave(id); */ + break; + case ID_LT: + free_lattice((Lattice *)id); + break; + case ID_LA: + free_lamp((Lamp *)id); + break; + case ID_CA: + free_camera((Camera*) id); + break; + case ID_IP: + free_ipo((Ipo *)id); + break; + case ID_KE: + free_key((Key *)id); + break; + case ID_WO: + free_world((World *)id); + break; + case ID_SCR: + free_screen((bScreen *)id); + break; + case ID_VF: + free_vfont((VFont *)id); + break; + case ID_TXT: + free_text((Text *)id); + break; + case ID_SCRIPT: + free_script((Script *)id); + break; + case ID_SO: + sound_free_sound((bSound *)id); + break; + case ID_GR: + free_group((Group *)id); + break; + case ID_AR: + free_armature((bArmature *)id); + break; + case ID_AC: + free_action((bAction *)id); + break; + case ID_NT: + ntreeFreeTree((bNodeTree *)id); + break; + case ID_BR: + free_brush((Brush *)id); + break; + } + + if (id->properties) { + IDP_FreeProperty(id->properties); + MEM_freeN(id->properties); + } + BLI_remlink(lb, id); + MEM_freeN(id); + +} + +void free_libblock_us(ListBase *lb, void *idv) /* test users */ +{ + ID *id= idv; + + id->us--; + + if(id->us<0) { + if(id->lib) printf("ERROR block %s %s users %d\n", id->lib->name, id->name, id->us); + else printf("ERROR block %s users %d\n", id->name, id->us); + } + if(id->us==0) { + if( GS(id->name)==ID_OB ) unlink_object((Object *)id); + + free_libblock(lb, id); + } +} + + +void free_main(Main *mainvar) +{ + /* also call when reading a file, erase all, etc */ + ListBase *lbarray[MAX_LIBARRAY]; + int a; + + a= set_listbasepointers(mainvar, lbarray); + while(a--) { + ListBase *lb= lbarray[a]; + ID *id; + + while ( (id= lb->first) ) { + free_libblock(lb, id); + } + } + + MEM_freeN(mainvar); +} + +/* ***************** ID ************************ */ + + +ID *find_id(char *type, char *name) /* type: "OB" or "MA" etc */ +{ + ID *id; + ListBase *lb; + + lb= wich_libbase(G.main, GS(type)); + + id= lb->first; + while(id) { + if(id->name[2]==name[0] && strcmp(id->name+2, name)==0 ) + return id; + id= id->next; + } + return 0; +} + +static void get_flags_for_id(ID *id, char *buf) +{ + int isfake= id->flag & LIB_FAKEUSER; + int isnode=0; + /* Writeout the flags for the entry, note there + * is a small hack that writes 5 spaces instead + * of 4 if no flags are displayed... this makes + * things usually line up ok - better would be + * to have that explicit, oh well - zr + */ + + if(GS(id->name)==ID_MA) + isnode= ((Material *)id)->use_nodes; + + if (id->us<0) + sprintf(buf, "-1W "); + else if (!id->lib && !isfake && id->us && !isnode) + sprintf(buf, " "); + else if(isnode) + sprintf(buf, "%c%cN%c ", id->lib?'L':' ', isfake?'F':' ', (id->us==0)?'O':' '); + else + sprintf(buf, "%c%c%c ", id->lib?'L':' ', isfake?'F':' ', (id->us==0)?'O':' '); +} + +#define IDPUP_NO_VIEWER 1 + +static void IDnames_to_dyn_pupstring(DynStr *pupds, ListBase *lb, ID *link, short *nr, int hideflag) +{ + int i, nids= BLI_countlist(lb); + + if (nr) *nr= -1; + + if (nr && nids>MAX_IDPUP) { + BLI_dynstr_append(pupds, "DataBrowse %x-2"); + *nr= -2; + } else { + ID *id; + + for (i=0, id= lb->first; id; id= id->next, i++) { + char buf[32]; + + if (nr && id==link) *nr= i+1; + + if (U.uiflag & USER_HIDE_DOT && id->name[2]=='.') + continue; + if (hideflag & IDPUP_NO_VIEWER) + if (GS(id->name)==ID_IM) + if ( ((Image *)id)->source==IMA_SRC_VIEWER ) + continue; + + get_flags_for_id(id, buf); + + BLI_dynstr_append(pupds, buf); + BLI_dynstr_append(pupds, id->name+2); + sprintf(buf, "%%x%d", i+1); + BLI_dynstr_append(pupds, buf); + + /* icon */ + switch(GS(id->name)) + { + case ID_MA: /* fall through */ + case ID_TE: /* fall through */ + case ID_IM: /* fall through */ + case ID_WO: /* fall through */ + case ID_LA: /* fall through */ + sprintf(buf, "%%i%d", BKE_icon_getid(id) ); + BLI_dynstr_append(pupds, buf); + break; + default: + break; + } + + if(id->next) + BLI_dynstr_append(pupds, "|"); + } + } +} + + /* Silly routine, the only difference between the one + * above is that it only adds items with a matching + * blocktype... this should be unified somehow... - zr + */ +static void IPOnames_to_dyn_pupstring(DynStr *pupds, ListBase *lb, ID *link, short *nr, int blocktype) +{ + ID *id; + int i, nids; + + for (id= lb->first, nids= 0; id; id= id->next) { + Ipo *ipo= (Ipo*) id; + + if (ipo->blocktype==blocktype) + nids++; + } + + if (nids>MAX_IDPUP) { + BLI_dynstr_append(pupds, "DataBrowse %x-2"); + } else { + for (i=0, id= lb->first; id; id= id->next) { + Ipo *ipo= (Ipo*) id; + + if (ipo->blocktype==blocktype) { + char buf[32]; + + if (id==link) + *nr= i+1; + + if (U.uiflag & USER_HIDE_DOT && id->name[2]=='.') + continue; + + get_flags_for_id(id, buf); + + BLI_dynstr_append(pupds, buf); + BLI_dynstr_append(pupds, id->name+2); + sprintf(buf, "%%x%d", i+1); + BLI_dynstr_append(pupds, buf); + + if(id->next) + BLI_dynstr_append(pupds, "|"); + + i++; + } + } + } +} + +/* used by headerbuttons.c buttons.c editobject.c editseq.c */ +/* if nr==NULL no MAX_IDPUP, this for non-header browsing */ +void IDnames_to_pupstring(char **str, char *title, char *extraops, ListBase *lb, ID *link, short *nr) +{ + DynStr *pupds= BLI_dynstr_new(); + + if (title) { + BLI_dynstr_append(pupds, title); + BLI_dynstr_append(pupds, "%t|"); + } + + if (extraops) { + BLI_dynstr_append(pupds, extraops); + if (BLI_dynstr_get_len(pupds)) + BLI_dynstr_append(pupds, "|"); + } + + IDnames_to_dyn_pupstring(pupds, lb, link, nr, 0); + + *str= BLI_dynstr_get_cstring(pupds); + BLI_dynstr_free(pupds); +} + +/* skips viewer images */ +void IMAnames_to_pupstring(char **str, char *title, char *extraops, ListBase *lb, ID *link, short *nr) +{ + DynStr *pupds= BLI_dynstr_new(); + + if (title) { + BLI_dynstr_append(pupds, title); + BLI_dynstr_append(pupds, "%t|"); + } + + if (extraops) { + BLI_dynstr_append(pupds, extraops); + if (BLI_dynstr_get_len(pupds)) + BLI_dynstr_append(pupds, "|"); + } + + IDnames_to_dyn_pupstring(pupds, lb, link, nr, IDPUP_NO_VIEWER); + + *str= BLI_dynstr_get_cstring(pupds); + BLI_dynstr_free(pupds); +} + + +/* only used by headerbuttons.c */ +void IPOnames_to_pupstring(char **str, char *title, char *extraops, ListBase *lb, ID *link, short *nr, int blocktype) +{ + DynStr *pupds= BLI_dynstr_new(); + + if (title) { + BLI_dynstr_append(pupds, title); + BLI_dynstr_append(pupds, "%t|"); + } + + if (extraops) { + BLI_dynstr_append(pupds, extraops); + if (BLI_dynstr_get_len(pupds)) + BLI_dynstr_append(pupds, "|"); + } + + IPOnames_to_dyn_pupstring(pupds, lb, link, nr, blocktype); + + *str= BLI_dynstr_get_cstring(pupds); + BLI_dynstr_free(pupds); +} + +/* used by buttons.c library.c mball.c */ +void splitIDname(char *name, char *left, int *nr) +{ + int a; + + *nr= 0; + strncpy(left, name, 21); + + a= strlen(name); + if(a>1 && name[a-1]=='.') return; + + while(a--) { + if( name[a]=='.' ) { + left[a]= 0; + *nr= atol(name+a+1); + return; + } + if( isdigit(name[a])==0 ) break; + + left[a]= 0; + } + strcpy(left, name); +} + +static void sort_alpha_id(ListBase *lb, ID *id) +{ + ID *idtest; + + /* insert alphabetically */ + if(lb->first!=lb->last) { + BLI_remlink(lb, id); + + idtest= lb->first; + while(idtest) { + if(BLI_strcasecmp(idtest->name, id->name)>0 || idtest->lib) { + BLI_insertlinkbefore(lb, idtest, id); + break; + } + idtest= idtest->next; + } + /* as last */ + if(idtest==0) { + BLI_addtail(lb, id); + } + } + +} + +/* + * Check to see if an ID name is already used, and find a new one if so. + * Return 1 if created a new name (returned in name). + * + * Normally the ID that's being check is already in the ListBase, so ID *id + * points at the new entry. The Python Library module needs to know what + * the name of a datablock will be before it is appended; in this case ID *id + * id is NULL; + */ + +int check_for_dupid(ListBase *lb, ID *id, char *name) +{ + ID *idtest; + int nr= 0, nrtest, a; + const int maxtest=32; + char left[32], leftest[32], in_use[32]; + + /* make sure input name is terminated properly */ + if( strlen(name) > 21 ) name[21]= 0; + + while (1) { + + /* phase 1: id already exists? */ + for( idtest = lb->first; idtest; idtest = idtest->next ) { + /* if idtest is not a lib */ + if( id != idtest && idtest->lib == NULL ) { + /* do not test alphabetic! */ + /* optimized */ + if( idtest->name[2] == name[0] ) { + if(strcmp(name, idtest->name+2)==0) break; + } + } + } + + /* if there is no double, done */ + if( idtest == NULL ) return 0; + + /* we have a dup; need to make a new name */ + /* quick check so we can reuse one of first 32 ids if vacant */ + memset(in_use, 0, maxtest); + + /* get name portion, number portion ("name.number") */ + splitIDname( name, left, &nr); + + /* if new name will be too long, truncate it */ + if(nr>999 && strlen(left)>16) left[16]= 0; + else if(strlen(left)>17) left[17]= 0; + + for( idtest = lb->first; idtest; idtest = idtest->next ) { + if( id != idtest && idtest->lib == NULL ) { + splitIDname(idtest->name+2, leftest, &nrtest); + /* if base names match... */ + /* optimized */ + if( *left == *leftest && strcmp(left, leftest)==0 ) { + if(nrtest < maxtest) + in_use[nrtest]= 1; /* mark as used */ + if(nr <= nrtest) + nr= nrtest+1; /* track largest unused */ + } + } + } + + /* decide which value of nr to use */ + for(a=0; a=nr) break; /* stop when we've check up to biggest */ + if( in_use[a]==0 ) { /* found an unused value */ + nr = a; + break; + } + } + + /* if non-numbered name was not in use, reuse it */ + if(nr==0) strcpy( name, left ); + else { + if(nr > 999 && strlen(left) > 16) { + /* this would overflow name buffer */ + left[16] = 0; + strcpy( name, left ); + continue; + } + /* this format specifier is from hell... */ + sprintf(name, "%s.%.3d", left, nr); + } + return 1; + } +} + +/* + * Only for local blocks: external en indirect blocks already have a + * unique ID. + * + * return 1: created a new name + */ + +int new_id(ListBase *lb, ID *id, const char *tname) +{ + int result; + char name[22]; + + /* if library, don't rename */ + if(id->lib) return 0; + + /* if no libdata given, look up based on ID */ + if(lb==NULL) lb= wich_libbase(G.main, GS(id->name)); + + if(tname==0) { /* if no name given, use name of current ID */ + strncpy(name, id->name+2, 21); + result= strlen(id->name+2); + } + else { /* else make a copy (tname args can be const) */ + strncpy(name, tname, 21); + result= strlen(tname); + } + + /* if result > 21, strncpy don't put the final '\0' to name. */ + if( result > 21 ) name[21]= 0; + + result = check_for_dupid( lb, id, name ); + strcpy( id->name+2, name ); + + /* This was in 2.43 and previous releases + * however all data in blender should be sorted, not just duplicate names + * sorting should not hurt, but noting just incause it alters the way other + * functions work, so sort every time */ + /* if( result ) + sort_alpha_id(lb, id);*/ + + sort_alpha_id(lb, id); + + return result; +} + +/* next to indirect usage in read/writefile also in editobject.c scene.c */ +void clear_id_newpoins() +{ + ListBase *lbarray[MAX_LIBARRAY]; + ID *id; + int a; + + a= set_listbasepointers(G.main, lbarray); + while(a--) { + id= lbarray[a]->first; + while(id) { + id->newid= 0; + id->flag &= ~LIB_NEW; + id= id->next; + } + } +} + +/* only for library fixes */ +static void image_fix_relative_path(Image *ima) +{ + if(ima->id.lib==NULL) return; + if(strncmp(ima->name, "//", 2)==0) { + BLI_convertstringcode(ima->name, ima->id.lib->filename, 0); + BLI_makestringcode(G.sce, ima->name); + } +} + +#define LIBTAG(a) if(a && a->id.lib) {a->id.flag &=~LIB_INDIRECT; a->id.flag |= LIB_EXTERN;} + +static void lib_indirect_test_id(ID *id) +{ + + if(id->lib) + return; + + if(GS(id->name)==ID_OB) { + Object *ob= (Object *)id; + bActionStrip *strip; + Mesh *me; + PartEff *paf; + int a; + + for (strip=ob->nlastrips.first; strip; strip=strip->next){ + LIBTAG(strip->object); + LIBTAG(strip->act); + LIBTAG(strip->ipo); + } + + for(a=0; atotcol; a++) { + LIBTAG(ob->mat[a]); + } + + paf = give_parteff(ob); + if (paf) + LIBTAG(paf->group); + + LIBTAG(ob->dup_group); + LIBTAG(ob->proxy); + + me= ob->data; + LIBTAG(me); + } +} + + +/* if lib!=NULL, only all from lib local */ +void all_local(Library *lib, int untagged_only) +{ + ListBase *lbarray[MAX_LIBARRAY], tempbase={0, 0}; + ID *id, *idn; + int a; + + a= set_listbasepointers(G.main, lbarray); + while(a--) { + id= lbarray[a]->first; + + while(id) { + id->newid= NULL; + idn= id->next; /* id is possibly being inserted again */ + + /* The check on the second line (LIB_APPEND_TAG) is done so its + * possible to tag data you dont want to be made local, used for + * appending data, so any libdata alredy linked wont become local + * (very nasty to discover all your links are lost after appending) + * */ + if(id->flag & (LIB_EXTERN|LIB_INDIRECT|LIB_NEW) && + (untagged_only==0 || !(id->flag & LIB_APPEND_TAG))) + { + if(lib==NULL || id->lib==lib) { + id->flag &= ~(LIB_EXTERN|LIB_INDIRECT|LIB_NEW); + + if(id->lib) { + /* relative file patch */ + if(GS(id->name)==ID_IM) + image_fix_relative_path((Image *)id); + + id->lib= NULL; + new_id(lbarray[a], id, 0); /* new_id only does it with double names */ + sort_alpha_id(lbarray[a], id); + } + } + } + id= idn; + } + + /* patch2: make it aphabetically */ + while( (id=tempbase.first) ) { + BLI_remlink(&tempbase, id); + BLI_addtail(lbarray[a], id); + new_id(lbarray[a], id, 0); + } + } + + /* patch 3: make sure library data isn't indirect falsely... */ + a= set_listbasepointers(G.main, lbarray); + while(a--) { + for(id= lbarray[a]->first; id; id=id->next) + lib_indirect_test_id(id); + } +} + + +void test_idbutton(char *name) +{ + /* called from buttons: when name already exists: call new_id */ + ListBase *lb; + ID *idtest; + + + lb= wich_libbase(G.main, GS(name-2) ); + if(lb==0) return; + + /* search for id */ + idtest= lb->first; + while(idtest) { + if( strcmp(idtest->name+2, name)==0) break; + idtest= idtest->next; + } + + if(idtest) if( new_id(lb, idtest, name)==0 ) sort_alpha_id(lb, idtest); +} + +void rename_id(ID *id, char *name) +{ + ListBase *lb; + + strncpy(id->name+2, name, 21); + lb= wich_libbase(G.main, GS(id->name) ); + + new_id(lb, id, name); +} + diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c new file mode 100644 index 00000000000..49d3021090e --- /dev/null +++ b/source/blender/blenkernel/intern/material.c @@ -0,0 +1,1110 @@ + +/* material.c + * + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_curve_types.h" +#include "DNA_material_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meta_types.h" +#include "DNA_node_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_texture_types.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "BKE_bad_level_calls.h" +#include "BKE_blender.h" +#include "BKE_displist.h" +#include "BKE_global.h" +#include "BKE_icons.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_material.h" +#include "BKE_mesh.h" +#include "BKE_node.h" +#include "BKE_utildefines.h" + +#include "BPY_extern.h" + +/* used in UI and render */ +Material defmaterial; + +/* called on startup, creator.c */ +void init_def_material(void) +{ + init_material(&defmaterial); +} + +/* not material itself */ +void free_material(Material *ma) +{ + MTex *mtex; + int a; + + BPY_free_scriptlink(&ma->scriptlink); + + for(a=0; amtex[a]; + if(mtex && mtex->tex) mtex->tex->id.us--; + if(mtex) MEM_freeN(mtex); + } + + if(ma->ramp_col) MEM_freeN(ma->ramp_col); + if(ma->ramp_spec) MEM_freeN(ma->ramp_spec); + + BKE_previewimg_free(&ma->preview); + BKE_icon_delete((struct ID*)ma); + ma->id.icon_id = 0; + + /* is no lib link block, but material extension */ + if(ma->nodetree) { + ntreeFreeTree(ma->nodetree); + MEM_freeN(ma->nodetree); + } +} + +void init_material(Material *ma) +{ + ma->r= ma->g= ma->b= ma->ref= 0.8; + ma->specr= ma->specg= ma->specb= 1.0; + ma->mirr= ma->mirg= ma->mirb= 1.0; + ma->spectra= 1.0; + ma->amb= 0.5; + ma->alpha= 1.0; + ma->spec= ma->hasize= 0.5; + ma->har= 50; + ma->starc= ma->ringc= 4; + ma->linec= 12; + ma->flarec= 1; + ma->flaresize= ma->subsize= 1.0; + ma->flareboost= 1; + ma->seed2= 6; + ma->friction= 0.5; + ma->refrac= 4.0; + ma->roughness= 0.5; + ma->param[0]= 0.5; + ma->param[1]= 0.1; + ma->param[2]= 0.5; + ma->param[3]= 0.1; + ma->rms= 0.1; + ma->darkness= 1.0; + + ma->strand_sta= ma->strand_end= 1.0f; + + ma->ang= 1.0; + ma->ray_depth= 2; + ma->ray_depth_tra= 2; + ma->fresnel_mir= 0.0; + ma->fresnel_tra= 0.0; + ma->fresnel_tra_i= 1.25; + ma->fresnel_mir_i= 1.25; + ma->tx_limit= 0.0; + ma->tx_falloff= 1.0; + ma->shad_alpha= 1.0f; + + ma->gloss_mir = ma->gloss_tra= 1.0; + ma->samp_gloss_mir = ma->samp_gloss_tra= 18; + ma->adapt_thresh_mir = ma->adapt_thresh_tra = 0.005; + ma->dist_mir = 0.0; + ma->fadeto_mir = MA_RAYMIR_FADETOSKY; + + ma->rampfac_col= 1.0; + ma->rampfac_spec= 1.0; + ma->pr_lamp= 3; /* two lamps, is bits */ + ma->pr_type= MA_SPHERE; + + ma->sss_radius[0]= 1.0f; + ma->sss_radius[1]= 1.0f; + ma->sss_radius[2]= 1.0f; + ma->sss_col[0]= 0.8f; + ma->sss_col[1]= 0.8f; + ma->sss_col[2]= 0.8f; + ma->sss_error= 0.05f; + ma->sss_scale= 0.1f; + ma->sss_ior= 1.3f; + ma->sss_colfac= 1.0f; + ma->sss_texfac= 0.0f; + ma->sss_front= 1.0f; + ma->sss_back= 1.0f; + + ma->mode= MA_TRACEBLE|MA_SHADBUF|MA_SHADOW|MA_RADIO|MA_RAYBIAS|MA_TANGENT_STR; + + ma->preview = NULL; +} + +Material *add_material(char *name) +{ + Material *ma; + + ma= alloc_libblock(&G.main->mat, ID_MA, name); + + init_material(ma); + + return ma; +} + +Material *copy_material(Material *ma) +{ + Material *man; + int a; + + man= copy_libblock(ma); + + id_us_plus((ID *)man->ipo); + id_us_plus((ID *)man->group); + + + for(a=0; amtex[a]) { + man->mtex[a]= MEM_mallocN(sizeof(MTex), "copymaterial"); + memcpy(man->mtex[a], ma->mtex[a], sizeof(MTex)); + id_us_plus((ID *)man->mtex[a]->tex); + } + } + + BPY_copy_scriptlink(&ma->scriptlink); + + if(ma->ramp_col) man->ramp_col= MEM_dupallocN(ma->ramp_col); + if(ma->ramp_spec) man->ramp_spec= MEM_dupallocN(ma->ramp_spec); + + if (ma->preview) man->preview = BKE_previewimg_copy(ma->preview); + + if(ma->nodetree) { + man->nodetree= ntreeCopyTree(ma->nodetree, 0); /* 0 == full new tree */ + } + + return man; +} + +void make_local_material(Material *ma) +{ + Object *ob; + Mesh *me; + Curve *cu; + MetaBall *mb; + Material *man; + int a, local=0, lib=0; + + /* - only lib users: do nothing + * - only local users: set flag + * - mixed: make copy + */ + + if(ma->id.lib==0) return; + if(ma->id.us==1) { + ma->id.lib= 0; + ma->id.flag= LIB_LOCAL; + new_id(0, (ID *)ma, 0); + for(a=0; amtex[a]) id_lib_extern((ID *)ma->mtex[a]->tex); + } + + return; + } + + /* test objects */ + ob= G.main->object.first; + while(ob) { + if(ob->mat) { + for(a=0; atotcol; a++) { + if(ob->mat[a]==ma) { + if(ob->id.lib) lib= 1; + else local= 1; + } + } + } + ob= ob->id.next; + } + /* test meshes */ + me= G.main->mesh.first; + while(me) { + if(me->mat) { + for(a=0; atotcol; a++) { + if(me->mat[a]==ma) { + if(me->id.lib) lib= 1; + else local= 1; + } + } + } + me= me->id.next; + } + /* test curves */ + cu= G.main->curve.first; + while(cu) { + if(cu->mat) { + for(a=0; atotcol; a++) { + if(cu->mat[a]==ma) { + if(cu->id.lib) lib= 1; + else local= 1; + } + } + } + cu= cu->id.next; + } + /* test mballs */ + mb= G.main->mball.first; + while(mb) { + if(mb->mat) { + for(a=0; atotcol; a++) { + if(mb->mat[a]==ma) { + if(mb->id.lib) lib= 1; + else local= 1; + } + } + } + mb= mb->id.next; + } + + if(local && lib==0) { + ma->id.lib= 0; + ma->id.flag= LIB_LOCAL; + + for(a=0; amtex[a]) id_lib_extern((ID *)ma->mtex[a]->tex); + } + + new_id(0, (ID *)ma, 0); + } + else if(local && lib) { + + man= copy_material(ma); + man->id.us= 0; + + /* do objects */ + ob= G.main->object.first; + while(ob) { + if(ob->mat) { + for(a=0; atotcol; a++) { + if(ob->mat[a]==ma) { + if(ob->id.lib==0) { + ob->mat[a]= man; + man->id.us++; + ma->id.us--; + } + } + } + } + ob= ob->id.next; + } + /* do meshes */ + me= G.main->mesh.first; + while(me) { + if(me->mat) { + for(a=0; atotcol; a++) { + if(me->mat[a]==ma) { + if(me->id.lib==0) { + me->mat[a]= man; + man->id.us++; + ma->id.us--; + } + } + } + } + me= me->id.next; + } + /* do curves */ + cu= G.main->curve.first; + while(cu) { + if(cu->mat) { + for(a=0; atotcol; a++) { + if(cu->mat[a]==ma) { + if(cu->id.lib==0) { + cu->mat[a]= man; + man->id.us++; + ma->id.us--; + } + } + } + } + cu= cu->id.next; + } + /* do mballs */ + mb= G.main->mball.first; + while(mb) { + if(mb->mat) { + for(a=0; atotcol; a++) { + if(mb->mat[a]==ma) { + if(mb->id.lib==0) { + mb->mat[a]= man; + man->id.us++; + ma->id.us--; + } + } + } + } + mb= mb->id.next; + } + } +} + +Material ***give_matarar(Object *ob) +{ + Mesh *me; + Curve *cu; + MetaBall *mb; + + if(ob->type==OB_MESH) { + me= ob->data; + return &(me->mat); + } + else if ELEM3(ob->type, OB_CURVE, OB_FONT, OB_SURF) { + cu= ob->data; + return &(cu->mat); + } + else if(ob->type==OB_MBALL) { + mb= ob->data; + return &(mb->mat); + } + return NULL; +} + +short *give_totcolp(Object *ob) +{ + Mesh *me; + Curve *cu; + MetaBall *mb; + + if(ob->type==OB_MESH) { + me= ob->data; + return &(me->totcol); + } + else if ELEM3(ob->type, OB_CURVE, OB_FONT, OB_SURF) { + cu= ob->data; + return &(cu->totcol); + } + else if(ob->type==OB_MBALL) { + mb= ob->data; + return &(mb->totcol); + } + return NULL; +} + +Material *give_current_material(Object *ob, int act) +{ + Material ***matarar, *ma; + short *totcolp; + + if(ob==NULL) return NULL; + + /* if object cannot have material, totcolp==NULL */ + totcolp= give_totcolp(ob); + if(totcolp==NULL || ob->totcol==0) return NULL; + + if(act>ob->totcol) act= ob->totcol; + else if(act<=0) act= 1; + + if( BTST(ob->colbits, act-1) ) { /* in object */ + ma= ob->mat[act-1]; + } + else { /* in data */ + + /* check for inconsistancy */ + if(*totcolp < ob->totcol) + ob->totcol= *totcolp; + if(act>ob->totcol) act= ob->totcol; + + matarar= give_matarar(ob); + + if(matarar && *matarar) ma= (*matarar)[act-1]; + else ma= 0; + + } + + return ma; +} + +ID *material_from(Object *ob, int act) +{ + + if(ob==0) return 0; + + if(ob->totcol==0) return ob->data; + if(act==0) act= 1; + + if( BTST(ob->colbits, act-1) ) return (ID *)ob; + else return ob->data; +} + +/* GS reads the memory pointed at in a specific ordering. There are, + * however two definitions for it. I have jotted them down here, both, + * but I think the first one is actually used. The thing is that + * big-endian systems might read this the wrong way round. OTOH, we + * constructed the IDs that are read out with this macro explicitly as + * well. I expect we'll sort it out soon... */ + +/* from blendef: */ +#define GS(a) (*((short *)(a))) + +/* from misc_util: flip the bytes from x */ +/* #define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1]) */ + +void test_object_materials(ID *id) +{ + /* make the ob mat-array same size as 'ob->data' mat-array */ + Object *ob; + Mesh *me; + Curve *cu; + MetaBall *mb; + Material **newmatar; + int totcol=0; + + if(id==0) return; + + if( GS(id->name)==ID_ME ) { + me= (Mesh *)id; + totcol= me->totcol; + } + else if( GS(id->name)==ID_CU ) { + cu= (Curve *)id; + totcol= cu->totcol; + } + else if( GS(id->name)==ID_MB ) { + mb= (MetaBall *)id; + totcol= mb->totcol; + } + else return; + + ob= G.main->object.first; + while(ob) { + + if(ob->data==id) { + + if(totcol==0) { + if(ob->totcol) { + MEM_freeN(ob->mat); + ob->mat= 0; + } + } + else if(ob->totcoltotcol) { + memcpy(newmatar, ob->mat, sizeof(void *)*ob->totcol); + MEM_freeN(ob->mat); + } + ob->mat= newmatar; + } + ob->totcol= totcol; + if(ob->totcol && ob->actcol==0) ob->actcol= 1; + if(ob->actcol>ob->totcol) ob->actcol= ob->totcol; + } + ob= ob->id.next; + } +} + + +void assign_material(Object *ob, Material *ma, int act) +{ + Material *mao, **matar, ***matarar; + short *totcolp; + + if(act>MAXMAT) return; + if(act<1) act= 1; + + /* test arraylens */ + + totcolp= give_totcolp(ob); + matarar= give_matarar(ob); + + if(totcolp==0 || matarar==0) return; + + if( act > *totcolp) { + matar= MEM_callocN(sizeof(void *)*act, "matarray1"); + if( *totcolp) { + memcpy(matar, *matarar, sizeof(void *)*( *totcolp )); + MEM_freeN(*matarar); + } + *matarar= matar; + *totcolp= act; + } + + if(act > ob->totcol) { + matar= MEM_callocN(sizeof(void *)*act, "matarray2"); + if( ob->totcol) { + memcpy(matar, ob->mat, sizeof(void *)*( ob->totcol )); + MEM_freeN(ob->mat); + } + ob->mat= matar; + ob->totcol= act; + } + + /* do it */ + + if( BTST(ob->colbits, act-1) ) { /* in object */ + mao= ob->mat[act-1]; + if(mao) mao->id.us--; + ob->mat[act-1]= ma; + } + else { /* in data */ + mao= (*matarar)[act-1]; + if(mao) mao->id.us--; + (*matarar)[act-1]= ma; + } + id_us_plus((ID *)ma); + test_object_materials(ob->data); +} + +void new_material_to_objectdata(Object *ob) +{ + Material *ma; + + if(ob==0) return; + if(ob->totcol>=MAXMAT) return; + + ma= give_current_material(ob, ob->actcol); + if(ma==NULL) + ma= add_material("Material"); + else + ma= copy_material(ma); + + ma->id.us= 0; /* eeh... */ + + if(ob->actcol) { + if( BTST(ob->colbits, ob->actcol-1) ) { + ob->colbits= BSET(ob->colbits, ob->totcol); + } + } + + assign_material(ob, ma, ob->totcol+1); + ob->actcol= ob->totcol; +} + +static void do_init_render_material(Material *ma, int r_mode, float *amb) +{ + MTex *mtex; + int a, needuv=0; + + if(ma->flarec==0) ma->flarec= 1; + + /* add all texcoflags from mtex */ + ma->texco= 0; + ma->mapto= 0; + for(a=0; aseptex & (1<mtex[a]; + if(mtex && mtex->tex && mtex->tex->type) { + + ma->texco |= mtex->texco; + ma->mapto |= mtex->mapto; + if(r_mode & R_OSA) { + if ELEM3(mtex->tex->type, TEX_IMAGE, TEX_PLUGIN, TEX_ENVMAP) ma->texco |= TEXCO_OSA; + } + + if(ma->texco & (TEXCO_ORCO|TEXCO_REFL|TEXCO_NORM|TEXCO_STRAND|TEXCO_STRESS)) needuv= 1; + else if(ma->texco & (TEXCO_GLOB|TEXCO_UV|TEXCO_OBJECT|TEXCO_SPEED)) needuv= 1; + else if(ma->texco & (TEXCO_LAVECTOR|TEXCO_VIEW|TEXCO_STICKY)) needuv= 1; + } + } + + if(r_mode & R_RADIO) + if(ma->mode & MA_RADIO) needuv= 1; + + if(ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP|MA_FACETEXTURE)) { + needuv= 1; + if(r_mode & R_OSA) ma->texco |= TEXCO_OSA; /* for texfaces */ + } + if(needuv) ma->texco |= NEED_UV; + + /* since the raytracer doesnt recalc O structs for each ray, we have to preset them all */ + if(r_mode & R_RAYTRACE) { + if(ma->mode & (MA_RAYMIRROR|MA_RAYTRANSP|MA_SHADOW_TRA)) { + ma->texco |= NEED_UV|TEXCO_ORCO|TEXCO_REFL|TEXCO_NORM; + if(r_mode & R_OSA) ma->texco |= TEXCO_OSA; + } + } + + if(amb) { + ma->ambr= ma->amb*amb[0]; + ma->ambg= ma->amb*amb[1]; + ma->ambb= ma->amb*amb[2]; + } + /* will become or-ed result of all node modes */ + ma->mode_l= ma->mode; + ma->mode_l &= ~MA_SHLESS; +} + +static void init_render_nodetree(bNodeTree *ntree, Material *basemat, int r_mode, float *amb) +{ + bNode *node; + + for(node=ntree->nodes.first; node; node= node->next) { + if(node->id) { + if(GS(node->id->name)==ID_MA) { + Material *ma= (Material *)node->id; + if(ma!=basemat) { + do_init_render_material(ma, r_mode, amb); + basemat->texco |= ma->texco; + basemat->mode_l |= ma->mode_l; + } + } + else if(node->type==NODE_GROUP) + init_render_nodetree((bNodeTree *)node->id, basemat, r_mode, amb); + } + } + /* parses the geom+tex nodes */ + ntreeShaderGetTexcoMode(ntree, r_mode, &basemat->texco, &basemat->mode_l); +} + +void init_render_material(Material *mat, int r_mode, float *amb) +{ + + do_init_render_material(mat, r_mode, amb); + + if(mat->nodetree && mat->use_nodes) { + init_render_nodetree(mat->nodetree, mat, r_mode, amb); + + ntreeBeginExecTree(mat->nodetree); /* has internal flag to detect it only does it once */ + } +} + +void init_render_materials(int r_mode, float *amb) +{ + Material *ma; + + /* two steps, first initialize, then or the flags for layers */ + for(ma= G.main->mat.first; ma; ma= ma->id.next) { + /* is_used flag comes back in convertblender.c */ + ma->flag &= ~MA_IS_USED; + if(ma->id.us) + init_render_material(ma, r_mode, amb); + } + + do_init_render_material(&defmaterial, r_mode, amb); +} + +/* only needed for nodes now */ +void end_render_material(Material *mat) +{ + if(mat && mat->nodetree && mat->use_nodes) + ntreeEndExecTree(mat->nodetree); /* has internal flag to detect it only does it once */ +} + +void end_render_materials(void) +{ + Material *ma; + for(ma= G.main->mat.first; ma; ma= ma->id.next) + if(ma->id.us) + end_render_material(ma); +} + +static int material_in_nodetree(bNodeTree *ntree, Material *mat) +{ + bNode *node; + + for(node=ntree->nodes.first; node; node= node->next) { + if(node->id && GS(node->id->name)==ID_MA) { + if(node->id==(ID*)mat) + return 1; + } + else if(node->type==NODE_GROUP) + if(material_in_nodetree((bNodeTree*)node->id, mat)) + return 1; + } + + return 0; +} + +int material_in_material(Material *parmat, Material *mat) +{ + if(parmat==mat) + return 1; + else if(parmat->nodetree && parmat->use_nodes) + return material_in_nodetree(parmat->nodetree, mat); + else + return 0; +} + +/* ****************** */ + +char colname_array[125][20]= { +"Black","DarkRed","HalfRed","Red","Red", +"DarkGreen","DarkOlive","Brown","Chocolate","OrangeRed", +"HalfGreen","GreenOlive","DryOlive","Goldenrod","DarkOrange", +"LightGreen","Chartreuse","YellowGreen","Yellow","Gold", +"Green","LawnGreen","GreenYellow","LightOlive","Yellow", +"DarkBlue","DarkPurple","HotPink","VioletPink","RedPink", +"SlateGray","DarkGrey","PalePurple","IndianRed","Tomato", +"SeaGreen","PaleGreen","GreenKhaki","LightBrown","LightSalmon", +"SpringGreen","PaleGreen","MediumOlive","YellowBrown","LightGold", +"LightGreen","LightGreen","LightGreen","GreenYellow","PaleYellow", +"HalfBlue","DarkSky","HalfMagenta","VioletRed","DeepPink", +"SteelBlue","SkyBlue","Orchid","LightHotPink","HotPink", +"SeaGreen","SlateGray","MediumGrey","Burlywood","LightPink", +"SpringGreen","Aquamarine","PaleGreen","Khaki","PaleOrange", +"SpringGreen","SeaGreen","PaleGreen","PaleWhite","YellowWhite", +"LightBlue","Purple","MediumOrchid","Magenta","Magenta", +"RoyalBlue","SlateBlue","MediumOrchid","Orchid","Magenta", +"DeepSkyBlue","LightSteelBlue","LightSkyBlue","Violet","LightPink", +"Cyan","DarkTurquoise","SkyBlue","Grey","Snow", +"Mint","Mint","Aquamarine","MintCream","Ivory", +"Blue","Blue","DarkMagenta","DarkOrchid","Magenta", +"SkyBlue","RoyalBlue","LightSlateBlue","MediumOrchid","Magenta", +"DodgerBlue","SteelBlue","MediumPurple","PalePurple","Plum", +"DeepSkyBlue","PaleBlue","LightSkyBlue","PalePurple","Thistle", +"Cyan","ColdBlue","PaleTurquoise","GhostWhite","White" +}; + +void automatname(Material *ma) +{ + int nr, r, g, b; + float ref; + + if(ma==0) return; + if(ma->mode & MA_SHLESS) ref= 1.0; + else ref= ma->ref; + + r= (int)(4.99*(ref*ma->r)); + g= (int)(4.99*(ref*ma->g)); + b= (int)(4.99*(ref*ma->b)); + nr= r + 5*g + 25*b; + if(nr>124) nr= 124; + new_id(&G.main->mat, (ID *)ma, colname_array[nr]); + +} + + +void delete_material_index() +{ + Material *mao, ***matarar; + Object *ob, *obt; + Curve *cu; + Nurb *nu; + short *totcolp; + int a, actcol; + + if(G.obedit) { + error("Unable to perform function in EditMode"); + return; + } + ob= ((G.scene->basact)? (G.scene->basact->object) : 0) ; + if(ob==0 || ob->totcol==0) return; + + /* take a mesh/curve/mball as starting point, remove 1 index, + * AND with all objects that share the ob->data + * + * after that check indices in mesh/curve/mball!!! + */ + + totcolp= give_totcolp(ob); + matarar= give_matarar(ob); + + /* we delete the actcol */ + if(ob->totcol) { + mao= (*matarar)[ob->actcol-1]; + if(mao) mao->id.us--; + } + + for(a=ob->actcol; atotcol; a++) { + (*matarar)[a-1]= (*matarar)[a]; + } + (*totcolp)--; + + if(*totcolp==0) { + MEM_freeN(*matarar); + *matarar= 0; + } + + actcol= ob->actcol; + obt= G.main->object.first; + while(obt) { + + if(obt->data==ob->data) { + + /* WATCH IT: do not use actcol from ob or from obt (can become zero) */ + mao= obt->mat[actcol-1]; + if(mao) mao->id.us--; + + for(a=actcol; atotcol; a++) obt->mat[a-1]= obt->mat[a]; + obt->totcol--; + if(obt->actcol > obt->totcol) obt->actcol= obt->totcol; + + if(obt->totcol==0) { + MEM_freeN(obt->mat); + obt->mat= 0; + } + } + obt= obt->id.next; + } + + /* check indices from mesh */ + + if(ob->type==OB_MESH) { + Mesh *me= get_mesh(ob); + mesh_delete_material_index(me, actcol-1); + freedisplist(&ob->disp); + } + else if ELEM(ob->type, OB_CURVE, OB_SURF) { + cu= ob->data; + nu= cu->nurb.first; + + while(nu) { + if(nu->mat_nr && nu->mat_nr>=actcol-1) { + nu->mat_nr--; + if (ob->type == OB_CURVE) nu->charidx--; + } + nu= nu->next; + } + freedisplist(&ob->disp); + } +} + + +/* r g b = current value, col = new value, fac==0 is no change */ +/* if g==NULL, it only does r channel */ +void ramp_blend(int type, float *r, float *g, float *b, float fac, float *col) +{ + float tmp, facm= 1.0-fac; + + switch (type) { + case MA_RAMP_BLEND: + *r = facm*(*r) + fac*col[0]; + if(g) { + *g = facm*(*g) + fac*col[1]; + *b = facm*(*b) + fac*col[2]; + } + break; + case MA_RAMP_ADD: + *r += fac*col[0]; + if(g) { + *g += fac*col[1]; + *b += fac*col[2]; + } + break; + case MA_RAMP_MULT: + *r *= (facm + fac*col[0]); + if(g) { + *g *= (facm + fac*col[1]); + *b *= (facm + fac*col[2]); + } + break; + case MA_RAMP_SCREEN: + *r = 1.0 - (facm + fac*(1.0 - col[0])) * (1.0 - *r); + if(g) { + *g = 1.0 - (facm + fac*(1.0 - col[1])) * (1.0 - *g); + *b = 1.0 - (facm + fac*(1.0 - col[2])) * (1.0 - *b); + } + break; + case MA_RAMP_OVERLAY: + if(*r < 0.5f) + *r *= (facm + 2.0f*fac*col[0]); + else + *r = 1.0 - (facm + 2.0f*fac*(1.0 - col[0])) * (1.0 - *r); + if(g) { + if(*g < 0.5f) + *g *= (facm + 2.0f*fac*col[1]); + else + *g = 1.0 - (facm + 2.0f*fac*(1.0 - col[1])) * (1.0 - *g); + if(*b < 0.5f) + *b *= (facm + 2.0f*fac*col[2]); + else + *b = 1.0 - (facm + 2.0f*fac*(1.0 - col[2])) * (1.0 - *b); + } + break; + case MA_RAMP_SUB: + *r -= fac*col[0]; + if(g) { + *g -= fac*col[1]; + *b -= fac*col[2]; + } + break; + case MA_RAMP_DIV: + if(col[0]!=0.0) + *r = facm*(*r) + fac*(*r)/col[0]; + if(g) { + if(col[1]!=0.0) + *g = facm*(*g) + fac*(*g)/col[1]; + if(col[2]!=0.0) + *b = facm*(*b) + fac*(*b)/col[2]; + } + break; + case MA_RAMP_DIFF: + *r = facm*(*r) + fac*fabs(*r-col[0]); + if(g) { + *g = facm*(*g) + fac*fabs(*g-col[1]); + *b = facm*(*b) + fac*fabs(*b-col[2]); + } + break; + case MA_RAMP_DARK: + tmp= fac*col[0]; + if(tmp < *r) *r= tmp; + if(g) { + tmp= fac*col[1]; + if(tmp < *g) *g= tmp; + tmp= fac*col[2]; + if(tmp < *b) *b= tmp; + } + break; + case MA_RAMP_LIGHT: + tmp= fac*col[0]; + if(tmp > *r) *r= tmp; + if(g) { + tmp= fac*col[1]; + if(tmp > *g) *g= tmp; + tmp= fac*col[2]; + if(tmp > *b) *b= tmp; + } + break; + case MA_RAMP_DODGE: + + + if(*r !=0.0){ + tmp = 1.0 - fac*col[0]; + if(tmp <= 0.0) + *r = 1.0; + else if ((tmp = (*r) / tmp)> 1.0) + *r = 1.0; + else + *r = tmp; + } + if(g) { + if(*g !=0.0){ + tmp = 1.0 - fac*col[1]; + if(tmp <= 0.0 ) + *g = 1.0; + else if ((tmp = (*g) / tmp) > 1.0 ) + *g = 1.0; + else + *g = tmp; + } + if(*b !=0.0){ + tmp = 1.0 - fac*col[2]; + if(tmp <= 0.0) + *b = 1.0; + else if ((tmp = (*b) / tmp) > 1.0 ) + *b = 1.0; + else + *b = tmp; + } + + } + break; + case MA_RAMP_BURN: + + tmp = facm + fac*col[0]; + + if(tmp <= 0.0) + *r = 0.0; + else if (( tmp = (1.0 - (1.0 - (*r)) / tmp )) < 0.0) + *r = 0.0; + else if (tmp > 1.0) + *r=1.0; + else + *r = tmp; + + if(g) { + tmp = facm + fac*col[1]; + if(tmp <= 0.0) + *g = 0.0; + else if (( tmp = (1.0 - (1.0 - (*g)) / tmp )) < 0.0 ) + *g = 0.0; + else if(tmp >1.0) + *g=1.0; + else + *g = tmp; + + tmp = facm + fac*col[2]; + if(tmp <= 0.0) + *b = 0.0; + else if (( tmp = (1.0 - (1.0 - (*b)) / tmp )) < 0.0 ) + *b = 0.0; + else if(tmp >1.0) + *b= 1.0; + else + *b = tmp; + } + break; + case MA_RAMP_HUE: + if(g){ + float rH,rS,rV; + float colH,colS,colV; + float tmpr,tmpg,tmpb; + rgb_to_hsv(col[0],col[1],col[2],&colH,&colS,&colV); + if(colS!=0 ){ + rgb_to_hsv(*r,*g,*b,&rH,&rS,&rV); + hsv_to_rgb( colH , rS, rV, &tmpr, &tmpg, &tmpb); + *r = facm*(*r) + fac*tmpr; + *g = facm*(*g) + fac*tmpg; + *b = facm*(*b) + fac*tmpb; + } + } + break; + case MA_RAMP_SAT: + if(g){ + float rH,rS,rV; + float colH,colS,colV; + rgb_to_hsv(*r,*g,*b,&rH,&rS,&rV); + if(rS!=0){ + rgb_to_hsv(col[0],col[1],col[2],&colH,&colS,&colV); + hsv_to_rgb( rH, (facm*rS +fac*colS), rV, r, g, b); + } + } + break; + case MA_RAMP_VAL: + if(g){ + float rH,rS,rV; + float colH,colS,colV; + rgb_to_hsv(*r,*g,*b,&rH,&rS,&rV); + rgb_to_hsv(col[0],col[1],col[2],&colH,&colS,&colV); + hsv_to_rgb( rH, rS, (facm*rV +fac*colV), r, g, b); + } + break; + case MA_RAMP_COLOR: + if(g){ + float rH,rS,rV; + float colH,colS,colV; + float tmpr,tmpg,tmpb; + rgb_to_hsv(col[0],col[1],col[2],&colH,&colS,&colV); + if(colS!=0){ + rgb_to_hsv(*r,*g,*b,&rH,&rS,&rV); + hsv_to_rgb( colH, colS, rV, &tmpr, &tmpg, &tmpb); + *r = facm*(*r) + fac*tmpr; + *g = facm*(*g) + fac*tmpg; + *b = facm*(*b) + fac*tmpb; + } + } + break; + } + +} + + diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c new file mode 100644 index 00000000000..e731f0fdfe0 --- /dev/null +++ b/source/blender/blenkernel/intern/mball.c @@ -0,0 +1,2088 @@ +/** mball.c + * + * MetaBalls are created from a single Object (with a name without number in it), + * here the DispList and BoundBox also is located. + * All objects with the same name (but with a number in it) are added to this. + * + * texture coordinates are patched within the displist + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Jiri Hnidek . + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include +#include +#include +#include +#include +#include "MEM_guardedalloc.h" + +#include "DNA_material_types.h" +#include "DNA_object_types.h" +#include "DNA_meta_types.h" +#include "DNA_scene_types.h" + + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "BKE_utildefines.h" +#include "BKE_bad_level_calls.h" + +#include "BKE_global.h" +#include "BKE_main.h" + +/* #include "BKE_object.h" */ +#include "BKE_scene.h" +#include "BKE_blender.h" +#include "BKE_library.h" +#include "BKE_displist.h" +#include "BKE_mball.h" +#include "BKE_object.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +/* Global variables */ + +float thresh= 0.6f; +int totelem=0; +MetaElem **mainb; +octal_tree *metaball_tree = NULL; +/* Functions */ + +void unlink_mball(MetaBall *mb) +{ + int a; + + for(a=0; atotcol; a++) { + if(mb->mat[a]) mb->mat[a]->id.us--; + mb->mat[a]= 0; + } +} + + +/* do not free mball itself */ +void free_mball(MetaBall *mb) +{ + unlink_mball(mb); + + if(mb->mat) MEM_freeN(mb->mat); + if(mb->bb) MEM_freeN(mb->bb); + BLI_freelistN(&mb->elems); + if(mb->disp.first) freedisplist(&mb->disp); +} + +MetaBall *add_mball(char *name) +{ + MetaBall *mb; + + mb= alloc_libblock(&G.main->mball, ID_MB, name); + + mb->size[0]= mb->size[1]= mb->size[2]= 1.0; + mb->texflag= MB_AUTOSPACE; + + mb->wiresize= 0.4f; + mb->rendersize= 0.2f; + mb->thresh= 0.6f; + + return mb; +} + +MetaBall *copy_mball(MetaBall *mb) +{ + MetaBall *mbn; + int a; + + mbn= copy_libblock(mb); + + duplicatelist(&mbn->elems, &mb->elems); + + mbn->mat= MEM_dupallocN(mb->mat); + for(a=0; atotcol; a++) { + id_us_plus((ID *)mbn->mat[a]); + } + mbn->bb= MEM_dupallocN(mb->bb); + + return mbn; +} + +void make_local_mball(MetaBall *mb) +{ + Object *ob; + MetaBall *mbn; + int local=0, lib=0; + + /* - only lib users: do nothing + * - only local users: set flag + * - mixed: make copy + */ + + if(mb->id.lib==0) return; + if(mb->id.us==1) { + mb->id.lib= 0; + mb->id.flag= LIB_LOCAL; + return; + } + + ob= G.main->object.first; + while(ob) { + if(ob->data==mb) { + if(ob->id.lib) lib= 1; + else local= 1; + } + ob= ob->id.next; + } + + if(local && lib==0) { + mb->id.lib= 0; + mb->id.flag= LIB_LOCAL; + } + else if(local && lib) { + mbn= copy_mball(mb); + mbn->id.us= 0; + + ob= G.main->object.first; + while(ob) { + if(ob->data==mb) { + + if(ob->id.lib==0) { + ob->data= mbn; + mbn->id.us++; + mb->id.us--; + } + } + ob= ob->id.next; + } + } +} +/** Compute bounding box of all MetaElems/MetaBalls. + * + * Bounding box is computed from polygonized surface. Object *ob is + * basic MetaBall (usaualy with name Meta). All other MetaBalls (whith + * names Meta.001, Meta.002, etc) are included in this Bounding Box. + */ +void tex_space_mball(Object *ob) +{ + DispList *dl; + BoundBox *bb; + float *data, min[3], max[3], loc[3], size[3]; + int tot, doit=0; + + if(ob->bb==0) ob->bb= MEM_callocN(sizeof(BoundBox), "mb boundbox"); + bb= ob->bb; + + /* Weird one, this. */ +/* INIT_MINMAX(min, max); */ + (min)[0]= (min)[1]= (min)[2]= 1.0e30f; + (max)[0]= (max)[1]= (max)[2]= -1.0e30f; + + dl= ob->disp.first; + while(dl) { + tot= dl->nr; + if(tot) doit= 1; + data= dl->verts; + while(tot--) { + /* Also weird... but longer. From utildefines. */ + DO_MINMAX(data, min, max); + data+= 3; + } + dl= dl->next; + } + + if(!doit) { + min[0] = min[1] = min[2] = -1.0f; + max[0] = max[1] = max[2] = 1.0f; + } + + loc[0]= (min[0]+max[0])/2.0f; + loc[1]= (min[1]+max[1])/2.0f; + loc[2]= (min[2]+max[2])/2.0f; + + size[0]= (max[0]-min[0])/2.0f; + size[1]= (max[1]-min[1])/2.0f; + size[2]= (max[2]-min[2])/2.0f; + + boundbox_set_from_min_max(bb, min, max); +} + +void make_orco_mball(Object *ob) +{ + BoundBox *bb; + DispList *dl; + float *data; + float loc[3], size[3]; + int a; + + /* restore size and loc */ + bb= ob->bb; + loc[0]= (bb->vec[0][0]+bb->vec[4][0])/2.0f; + size[0]= bb->vec[4][0]-loc[0]; + loc[1]= (bb->vec[0][1]+bb->vec[2][1])/2.0f; + size[1]= bb->vec[2][1]-loc[1]; + loc[2]= (bb->vec[0][2]+bb->vec[1][2])/2.0f; + size[2]= bb->vec[1][2]-loc[2]; + + dl= ob->disp.first; + data= dl->verts; + a= dl->nr; + while(a--) { + data[0]= (data[0]-loc[0])/size[0]; + data[1]= (data[1]-loc[1])/size[1]; + data[2]= (data[2]-loc[2])/size[2]; + + data+= 3; + } +} +/** \brief Test, if Object *ob is basic MetaBall. + * + * It test last character of Object ID name. If last character + * is digit it return 0, else it return 1. + */ +int is_basis_mball(Object *ob) +{ + int len; + + /* just a quick test */ + len= strlen(ob->id.name); + if( isdigit(ob->id.name[len-1]) ) return 0; + return 1; +} + +/** \brief This function finds basic MetaBall. + * + * Basic MetaBall doesn't include any number at the end of + * its name. All MetaBalls with same base of name can be + * blended. MetaBalls with different basic name can't be + * blended. + */ +Object *find_basis_mball(Object *basis) +{ + Base *base; + Object *ob,*bob= basis; + MetaElem *ml=NULL; + int basisnr, obnr; + char basisname[32], obname[32]; + + splitIDname(basis->id.name+2, basisname, &basisnr); + totelem= 0; + + next_object(0, 0, 0); + while(next_object(1, &base, &ob)) { + + if (ob->type==OB_MBALL) { + if(ob==bob){ + /* if bob object is in edit mode, then dynamic list of all MetaElems + * is stored in editelems */ + if(ob==G.obedit) ml= editelems.first; + /* keep track of linked data too! */ + else if(G.obedit && G.obedit->data==ob->data) ml= editelems.first; + /* if bob object is in object mode */ + else ml= ((MetaBall*)ob->data)->elems.first; + } + else{ + splitIDname(ob->id.name+2, obname, &obnr); + + /* object ob has to be in same "group" ... it means, that it has to have + * same base of its name */ + if(strcmp(obname, basisname)==0){ + /* if object is in edit mode, then dynamic list of all MetaElems + * is stored in editelems */ + if(ob==G.obedit) ml= editelems.first; + /* keep track of linked data too! */ + else if(bob==G.obedit && bob->data==ob->data) ml= editelems.first; + /* object is in object mode */ + else ml= ((MetaBall*)ob->data)->elems.first; + + if(obnrflag & OB_FROMDUPLI)){ + basis= ob; + basisnr= obnr; + } + } + } + } + + while(ml){ + if(!(ml->flag & MB_HIDE)) totelem++; + ml= ml->next; + } + } + } + + return basis; +} + + +/* ******************** ARITH ************************* */ + +/* BASED AT CODE (but mostly rewritten) : + * C code from the article + * "An Implicit Surface Polygonizer" + * by Jules Bloomenthal, jbloom@beauty.gmu.edu + * in "Graphics Gems IV", Academic Press, 1994 + + * Authored by Jules Bloomenthal, Xerox PARC. + * Copyright (c) Xerox Corporation, 1991. All rights reserved. + * Permission is granted to reproduce, use and distribute this code for + * any and all purposes, provided that this notice appears in all copies. */ + +#define RES 12 /* # converge iterations */ + +#define L 0 /* left direction: -x, -i */ +#define R 1 /* right direction: +x, +i */ +#define B 2 /* bottom direction: -y, -j */ +#define T 3 /* top direction: +y, +j */ +#define N 4 /* near direction: -z, -k */ +#define F 5 /* far direction: +z, +k */ +#define LBN 0 /* left bottom near corner */ +#define LBF 1 /* left bottom far corner */ +#define LTN 2 /* left top near corner */ +#define LTF 3 /* left top far corner */ +#define RBN 4 /* right bottom near corner */ +#define RBF 5 /* right bottom far corner */ +#define RTN 6 /* right top near corner */ +#define RTF 7 /* right top far corner */ + +/* the LBN corner of cube (i, j, k), corresponds with location + * (start.x+(i-0.5)*size, start.y+(j-0.5)*size, start.z+(k-0.5)*size) */ + +#define HASHBIT (5) +#define HASHSIZE (size_t)(1<<(3*HASHBIT)) /*! < hash table size (32768) */ + +#define HASH(i,j,k) ((((( (i) & 31)<<5) | ( (j) & 31))<<5 ) | ( (k) & 31) ) + +#define MB_BIT(i, bit) (((i)>>(bit))&1) +#define FLIP(i,bit) ((i)^1<<(bit)) /* flip the given bit of i */ + + +/* **************** POLYGONIZATION ************************ */ + +void calc_mballco(MetaElem *ml, float *vec) +{ + if(ml->mat) { + Mat4MulVecfl((float ( * )[4])ml->mat, vec); + } +} + +float densfunc(MetaElem *ball, float x, float y, float z) +{ + float dist2 = 0.0, dx, dy, dz; + float vec[3]; + + vec[0]= x; + vec[1]= y; + vec[2]= z; + Mat4MulVecfl((float ( * )[4])ball->imat, vec); + dx= vec[0]; + dy= vec[1]; + dz= vec[2]; + + if(ball->type==MB_BALL) { + } + else if(ball->type==MB_TUBEX) { + if( dx > ball->len) dx-= ball->len; + else if(dx< -ball->len) dx+= ball->len; + else dx= 0.0; + } + else if(ball->type==MB_TUBEY) { + if( dy > ball->len) dy-= ball->len; + else if(dy< -ball->len) dy+= ball->len; + else dy= 0.0; + } + else if(ball->type==MB_TUBEZ) { + if( dz > ball->len) dz-= ball->len; + else if(dz< -ball->len) dz+= ball->len; + else dz= 0.0; + } + else if(ball->type==MB_TUBE) { + if( dx > ball->expx) dx-= ball->expx; + else if(dx< -ball->expx) dx+= ball->expx; + else dx= 0.0; + } + else if(ball->type==MB_PLANE) { + if( dx > ball->expx) dx-= ball->expx; + else if(dx< -ball->expx) dx+= ball->expx; + else dx= 0.0; + if( dy > ball->expy) dy-= ball->expy; + else if(dy< -ball->expy) dy+= ball->expy; + else dy= 0.0; + } + else if(ball->type==MB_ELIPSOID) { + dx *= 1/ball->expx; + dy *= 1/ball->expy; + dz *= 1/ball->expz; + } + else if(ball->type==MB_CUBE) { + if( dx > ball->expx) dx-= ball->expx; + else if(dx< -ball->expx) dx+= ball->expx; + else dx= 0.0; + if( dy > ball->expy) dy-= ball->expy; + else if(dy< -ball->expy) dy+= ball->expy; + else dy= 0.0; + if( dz > ball->expz) dz-= ball->expz; + else if(dz< -ball->expz) dz+= ball->expz; + else dz= 0.0; + } + + dist2= (dx*dx + dy*dy + dz*dz); + + if(ball->flag & MB_NEGATIVE) { + dist2= 1.0f-(dist2/ball->rad2); + if(dist2 < 0.0) return 0.5f; + + return 0.5f-ball->s*dist2*dist2*dist2; + } + else { + dist2= 1.0f-(dist2/ball->rad2); + if(dist2 < 0.0) return -0.5f; + + return ball->s*dist2*dist2*dist2 -0.5f; + } +} + +octal_node* find_metaball_octal_node(octal_node *node, float x, float y, float z, short depth) +{ + if(!depth) return node; + + if(z < node->z){ + if(y < node->y){ + if(x < node->x){ + if(node->nodes[0]) + return find_metaball_octal_node(node->nodes[0],x,y,z,depth--); + else + return node; + } + else{ + if(node->nodes[1]) + return find_metaball_octal_node(node->nodes[1],x,y,z,depth--); + else + return node; + } + } + else{ + if(x < node->x){ + if(node->nodes[3]) + return find_metaball_octal_node(node->nodes[3],x,y,z,depth--); + else + return node; + } + else{ + if(node->nodes[2]) + return find_metaball_octal_node(node->nodes[2],x,y,z,depth--); + else + return node; + } + } + } + else{ + if(y < node->y){ + if(x < node->x){ + if(node->nodes[4]) + return find_metaball_octal_node(node->nodes[4],x,y,z,depth--); + else + return node; + } + else{ + if(node->nodes[5]) + return find_metaball_octal_node(node->nodes[5],x,y,z,depth--); + else + return node; + } + } + else{ + if(x < node->x){ + if(node->nodes[7]) + return find_metaball_octal_node(node->nodes[7],x,y,z,depth--); + else + return node; + } + else{ + if(node->nodes[6]) + return find_metaball_octal_node(node->nodes[6],x,y,z,depth--); + else + return node; + } + } + } + + return node; +} + +float metaball(float x, float y, float z) +/* float x, y, z; */ +{ + struct octal_node *node; + struct ml_pointer *ml_p; + float dens=0; + int a; + + if(totelem > 1){ + node= find_metaball_octal_node(metaball_tree->first, x, y, z, metaball_tree->depth); + if(node){ + ml_p= node->elems.first; + + while(ml_p){ + dens+=densfunc(ml_p->ml, x, y, z); + ml_p= ml_p->next; + } + + dens+= -0.5*(metaball_tree->pos - node->pos); + dens+= 0.5*(metaball_tree->neg - node->neg); + } + else{ + for(a=0; a10000 || size==0) { + printf("incorrect use of new_pgn_element\n"); + } + else if(size== -1) { + cur= lb.first; + while(cur) { + MEM_freeN(cur->data); + cur= cur->next; + } + BLI_freelistN(&lb); + + return NULL; + } + + size= 4*( (size+3)/4 ); + + if(cur) { + if(size+offs < blocksize) { + adr= (void *) (cur->data+offs); + offs+= size; + return adr; + } + } + + cur= MEM_callocN( sizeof(struct pgn_elements), "newpgn"); + cur->data= MEM_callocN(blocksize, "newpgn"); + BLI_addtail(&lb, cur); + + offs= size; + return cur->data; +} + +void freepolygonize(PROCESS *p) +{ + MEM_freeN(p->corners); + MEM_freeN(p->edges); + MEM_freeN(p->centers); + + new_pgn_element(-1); + + if(p->vertices.ptr) MEM_freeN(p->vertices.ptr); +} + +/**** Cubical Polygonization (optional) ****/ + +#define LB 0 /* left bottom edge */ +#define LT 1 /* left top edge */ +#define LN 2 /* left near edge */ +#define LF 3 /* left far edge */ +#define RB 4 /* right bottom edge */ +#define RT 5 /* right top edge */ +#define RN 6 /* right near edge */ +#define RF 7 /* right far edge */ +#define BN 8 /* bottom near edge */ +#define BF 9 /* bottom far edge */ +#define TN 10 /* top near edge */ +#define TF 11 /* top far edge */ + +static INTLISTS *cubetable[256]; + +/* edge: LB, LT, LN, LF, RB, RT, RN, RF, BN, BF, TN, TF */ +static int corner1[12] = { + LBN,LTN,LBN,LBF,RBN,RTN,RBN,RBF,LBN,LBF,LTN,LTF}; +static int corner2[12] = { + LBF,LTF,LTN,LTF,RBF,RTF,RTN,RTF,RBN,RBF,RTN,RTF}; +static int leftface[12] = { + B, L, L, F, R, T, N, R, N, B, T, F}; +/* face on left when going corner1 to corner2 */ +static int rightface[12] = { + L, T, N, L, B, R, R, F, B, F, N, T}; +/* face on right when going corner1 to corner2 */ + + +/* docube: triangulate the cube directly, without decomposition */ + +void docube(CUBE *cube, PROCESS *p, MetaBall *mb) +{ + INTLISTS *polys; + CORNER *c1, *c2; + int i, index = 0, count, indexar[8]; + + for (i = 0; i < 8; i++) if (cube->corners[i]->value > 0.0) index += (1<next) { + INTLIST *edges; + + count = 0; + + for (edges = polys->list; edges; edges = edges->next) { + c1 = cube->corners[corner1[edges->i]]; + c2 = cube->corners[corner2[edges->i]]; + + indexar[count] = vertid(c1, c2, p, mb); + count++; + } + if(count>2) { + switch(count) { + case 3: + accum_mballfaces(indexar[2], indexar[1], indexar[0], 0); + break; + case 4: + if(indexar[0]==0) accum_mballfaces(indexar[0], indexar[3], indexar[2], indexar[1]); + else accum_mballfaces(indexar[3], indexar[2], indexar[1], indexar[0]); + break; + case 5: + if(indexar[0]==0) accum_mballfaces(indexar[0], indexar[3], indexar[2], indexar[1]); + else accum_mballfaces(indexar[3], indexar[2], indexar[1], indexar[0]); + + accum_mballfaces(indexar[4], indexar[3], indexar[0], 0); + break; + case 6: + if(indexar[0]==0) { + accum_mballfaces(indexar[0], indexar[3], indexar[2], indexar[1]); + accum_mballfaces(indexar[0], indexar[5], indexar[4], indexar[3]); + } + else { + accum_mballfaces(indexar[3], indexar[2], indexar[1], indexar[0]); + accum_mballfaces(indexar[5], indexar[4], indexar[3], indexar[0]); + } + break; + case 7: + if(indexar[0]==0) { + accum_mballfaces(indexar[0], indexar[3], indexar[2], indexar[1]); + accum_mballfaces(indexar[0], indexar[5], indexar[4], indexar[3]); + } + else { + accum_mballfaces(indexar[3], indexar[2], indexar[1], indexar[0]); + accum_mballfaces(indexar[5], indexar[4], indexar[3], indexar[0]); + } + + accum_mballfaces(indexar[6], indexar[5], indexar[0], 0); + + break; + } + } + } +} + + +/* testface: given cube at lattice (i, j, k), and four corners of face, + * if surface crosses face, compute other four corners of adjacent cube + * and add new cube to cube stack */ + +void testface(int i, int j, int k, CUBE* old, int bit, int c1, int c2, int c3, int c4, PROCESS *p) +{ + CUBE newc; + CUBES *oldcubes = p->cubes; + CORNER *corn1, *corn2, *corn3, *corn4; + int n, pos; + + corn1= old->corners[c1]; + corn2= old->corners[c2]; + corn3= old->corners[c3]; + corn4= old->corners[c4]; + + pos = corn1->value > 0.0 ? 1 : 0; + + /* test if no surface crossing */ + if( (corn2->value > 0) == pos && (corn3->value > 0) == pos && (corn4->value > 0) == pos) return; + /* test if cube out of bounds */ + /*if ( abs(i) > p->bounds || abs(j) > p->bounds || abs(k) > p->bounds) return;*/ + /* test if already visited (always as last) */ + if (setcenter(p->centers, i, j, k)) return; + + + /* create new cube and add cube to top of stack: */ + p->cubes = (CUBES *) new_pgn_element(sizeof(CUBES)); + p->cubes->next = oldcubes; + + newc.i = i; + newc.j = j; + newc.k = k; + for (n = 0; n < 8; n++) newc.corners[n] = NULL; + + newc.corners[FLIP(c1, bit)] = corn1; + newc.corners[FLIP(c2, bit)] = corn2; + newc.corners[FLIP(c3, bit)] = corn3; + newc.corners[FLIP(c4, bit)] = corn4; + + if(newc.corners[0]==0) newc.corners[0] = setcorner(p, i, j, k); + if(newc.corners[1]==0) newc.corners[1] = setcorner(p, i, j, k+1); + if(newc.corners[2]==0) newc.corners[2] = setcorner(p, i, j+1, k); + if(newc.corners[3]==0) newc.corners[3] = setcorner(p, i, j+1, k+1); + if(newc.corners[4]==0) newc.corners[4] = setcorner(p, i+1, j, k); + if(newc.corners[5]==0) newc.corners[5] = setcorner(p, i+1, j, k+1); + if(newc.corners[6]==0) newc.corners[6] = setcorner(p, i+1, j+1, k); + if(newc.corners[7]==0) newc.corners[7] = setcorner(p, i+1, j+1, k+1); + + p->cubes->cube= newc; +} + +/* setcorner: return corner with the given lattice location + set (and cache) its function value */ + +CORNER *setcorner (PROCESS* p, int i, int j, int k) +{ + /* for speed, do corner value caching here */ + CORNER *c; + int index; + + /* does corner exist? */ + index = HASH(i, j, k); + c = p->corners[index]; + + for (; c != NULL; c = c->next) { + if (c->i == i && c->j == j && c->k == k) { + return c; + } + } + + c = (CORNER *) new_pgn_element(sizeof(CORNER)); + + c->i = i; + c->x = p->start.x+((float)i-0.5f)*p->size; + c->j = j; + c->y = p->start.y+((float)j-0.5f)*p->size; + c->k = k; + c->z = p->start.z+((float)k-0.5f)*p->size; + c->value = p->function(c->x, c->y, c->z); + + c->next = p->corners[index]; + p->corners[index] = c; + + return c; +} + + +/* nextcwedge: return next clockwise edge from given edge around given face */ + +int nextcwedge (int edge, int face) +{ + switch (edge) { + case LB: + return (face == L)? LF : BN; + case LT: + return (face == L)? LN : TF; + case LN: + return (face == L)? LB : TN; + case LF: + return (face == L)? LT : BF; + case RB: + return (face == R)? RN : BF; + case RT: + return (face == R)? RF : TN; + case RN: + return (face == R)? RT : BN; + case RF: + return (face == R)? RB : TF; + case BN: + return (face == B)? RB : LN; + case BF: + return (face == B)? LB : RF; + case TN: + return (face == T)? LT : RN; + case TF: + return (face == T)? RT : LF; + } + return 0; +} + + +/* otherface: return face adjoining edge that is not the given face */ + +int otherface (int edge, int face) +{ + int other = leftface[edge]; + return face == other? rightface[edge] : other; +} + + +/* makecubetable: create the 256 entry table for cubical polygonization */ + +void makecubetable (void) +{ + static int isdone= 0; + int i, e, c, done[12], pos[8]; + + if(isdone) return; + isdone= 1; + + for (i = 0; i < 256; i++) { + for (e = 0; e < 12; e++) done[e] = 0; + for (c = 0; c < 8; c++) pos[c] = MB_BIT(i, c); + for (e = 0; e < 12; e++) + if (!done[e] && (pos[corner1[e]] != pos[corner2[e]])) { + INTLIST *ints = 0; + INTLISTS *lists = (INTLISTS *) MEM_callocN(sizeof(INTLISTS), "mball_intlist"); + int start = e, edge = e; + + /* get face that is to right of edge from pos to neg corner: */ + int face = pos[corner1[e]]? rightface[e] : leftface[e]; + + while (1) { + edge = nextcwedge(edge, face); + done[edge] = 1; + if (pos[corner1[edge]] != pos[corner2[edge]]) { + INTLIST *tmp = ints; + + ints = (INTLIST *) MEM_callocN(sizeof(INTLIST), "mball_intlist"); + ints->i = edge; + ints->next = tmp; /* add edge to head of list */ + + if (edge == start) break; + face = otherface(edge, face); + } + } + lists->list = ints; /* add ints to head of table entry */ + lists->next = cubetable[i]; + cubetable[i] = lists; + } + } +} + +void BKE_freecubetable(void) +{ + int i; + INTLISTS *lists, *nlists; + INTLIST *ints, *nints; + + for (i = 0; i < 256; i++) { + lists= cubetable[i]; + while(lists) { + nlists= lists->next; + + ints= lists->list; + while(ints) { + nints= ints->next; + MEM_freeN(ints); + ints= nints; + } + + MEM_freeN(lists); + lists= nlists; + } + cubetable[i]= 0; + } +} + +/**** Storage ****/ + +/* setcenter: set (i,j,k) entry of table[] + * return 1 if already set; otherwise, set and return 0 */ + +int setcenter(CENTERLIST *table[], int i, int j, int k) +{ + int index; + CENTERLIST *newc, *l, *q; + + index= HASH(i, j, k); + q= table[index]; + + for (l = q; l != NULL; l = l->next) { + if (l->i == i && l->j == j && l->k == k) return 1; + } + + newc = (CENTERLIST *) new_pgn_element(sizeof(CENTERLIST)); + newc->i = i; + newc->j = j; + newc->k = k; + newc->next = q; + table[index] = newc; + + return 0; +} + + +/* setedge: set vertex id for edge */ + +void setedge (EDGELIST *table[], + int i1, int j1, + int k1, int i2, + int j2, int k2, + int vid) +{ + unsigned int index; + EDGELIST *newe; + + if (i1>i2 || (i1==i2 && (j1>j2 || (j1==j2 && k1>k2)))) { + int t=i1; + i1=i2; + i2=t; + t=j1; + j1=j2; + j2=t; + t=k1; + k1=k2; + k2=t; + } + index = HASH(i1, j1, k1) + HASH(i2, j2, k2); + newe = (EDGELIST *) new_pgn_element(sizeof(EDGELIST)); + newe->i1 = i1; + newe->j1 = j1; + newe->k1 = k1; + newe->i2 = i2; + newe->j2 = j2; + newe->k2 = k2; + newe->vid = vid; + newe->next = table[index]; + table[index] = newe; +} + + +/* getedge: return vertex id for edge; return -1 if not set */ + +int getedge (EDGELIST *table[], + int i1, int j1, int k1, + int i2, int j2, int k2) +{ + EDGELIST *q; + + if (i1>i2 || (i1==i2 && (j1>j2 || (j1==j2 && k1>k2)))) { + int t=i1; + i1=i2; + i2=t; + t=j1; + j1=j2; + j2=t; + t=k1; + k1=k2; + k2=t; + } + q = table[HASH(i1, j1, k1)+HASH(i2, j2, k2)]; + for (; q != NULL; q = q->next) + if (q->i1 == i1 && q->j1 == j1 && q->k1 == k1 && + q->i2 == i2 && q->j2 == j2 && q->k2 == k2) + return q->vid; + return -1; +} + + +/**** Vertices ****/ + +#undef R + + + +/* vertid: return index for vertex on edge: + * c1->value and c2->value are presumed of different sign + * return saved index if any; else compute vertex and save */ + +/* addtovertices: add v to sequence of vertices */ + +void addtovertices (VERTICES *vertices, VERTEX v) +{ + if (vertices->count == vertices->max) { + int i; + VERTEX *newv; + vertices->max = vertices->count == 0 ? 10 : 2*vertices->count; + newv = (VERTEX *) MEM_callocN(vertices->max * sizeof(VERTEX), "addtovertices"); + + for (i = 0; i < vertices->count; i++) newv[i] = vertices->ptr[i]; + + if (vertices->ptr != NULL) MEM_freeN(vertices->ptr); + vertices->ptr = newv; + } + vertices->ptr[vertices->count++] = v; +} + +/* vnormal: compute unit length surface normal at point */ + +void vnormal (MB_POINT *point, PROCESS *p, MB_POINT *v) +{ + float delta= 0.2f*p->delta; + float f = p->function(point->x, point->y, point->z); + + v->x = p->function(point->x+delta, point->y, point->z)-f; + v->y = p->function(point->x, point->y+delta, point->z)-f; + v->z = p->function(point->x, point->y, point->z+delta)-f; + f = (float)sqrt(v->x*v->x + v->y*v->y + v->z*v->z); + + if (f != 0.0) { + v->x /= f; + v->y /= f; + v->z /= f; + } + + if(FALSE) { + MB_POINT temp; + + delta*= 2.0; + + f = p->function(point->x, point->y, point->z); + + temp.x = p->function(point->x+delta, point->y, point->z)-f; + temp.y = p->function(point->x, point->y+delta, point->z)-f; + temp.z = p->function(point->x, point->y, point->z+delta)-f; + f = (float)sqrt(temp.x*temp.x + temp.y*temp.y + temp.z*temp.z); + + if (f != 0.0) { + temp.x /= f; + temp.y /= f; + temp.z /= f; + + v->x+= temp.x; + v->y+= temp.y; + v->z+= temp.z; + + f = (float)sqrt(v->x*v->x + v->y*v->y + v->z*v->z); + + if (f != 0.0) { + v->x /= f; + v->y /= f; + v->z /= f; + } + } + } + +} + + +int vertid (CORNER *c1, CORNER *c2, PROCESS *p, MetaBall *mb) +{ + VERTEX v; + MB_POINT a, b; + int vid = getedge(p->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k); + + if (vid != -1) return vid; /* previously computed */ + a.x = c1->x; + a.y = c1->y; + a.z = c1->z; + b.x = c2->x; + b.y = c2->y; + b.z = c2->z; + + converge(&a, &b, c1->value, c2->value, p->function, &v.position, mb, 1); /* position */ + vnormal(&v.position, p, &v.normal); + + addtovertices(&p->vertices, v); /* save vertex */ + vid = p->vertices.count-1; + setedge(p->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k, vid); + + return vid; +} + + + + +/* converge: from two points of differing sign, converge to zero crossing */ +/* watch it: p1 and p2 are used to calculate */ +void converge (MB_POINT *p1, MB_POINT *p2, float v1, float v2, + float (*function)(float, float, float), MB_POINT *p, MetaBall *mb, int f) +{ + int i = 0; + MB_POINT pos, neg; + float positive = 0.0f, negative = 0.0f; + float dx = 0.0f ,dy = 0.0f ,dz = 0.0f; + + if (v1 < 0) { + pos= *p2; + neg= *p1; + positive = v2; + negative = v1; + } + else { + pos= *p1; + neg= *p2; + positive = v1; + negative = v2; + } + + dx = pos.x - neg.x; + dy = pos.y - neg.y; + dz = pos.z - neg.z; + +/* Aproximation by linear interpolation is faster then binary subdivision, + * but it results sometimes (mb->thresh < 0.2) into the strange results */ + if((mb->thresh >0.2) && (f==1)){ + if((dy == 0.0f) && (dz == 0.0f)){ + p->x = neg.x - negative*dx/(positive-negative); + p->y = neg.y; + p->z = neg.z; + return; + } + if((dx == 0.0f) && (dz == 0.0f)){ + p->x = neg.x; + p->y = neg.y - negative*dy/(positive-negative); + p->z = neg.z; + return; + } + if((dx == 0.0f) && (dy == 0.0f)){ + p->x = neg.x; + p->y = neg.y; + p->z = neg.z - negative*dz/(positive-negative); + return; + } + } + + if((dy == 0.0f) && (dz == 0.0f)){ + p->y = neg.y; + p->z = neg.z; + while (1) { + p->x = 0.5f*(pos.x + neg.x); + if (i++ == RES) return; + if ((function(p->x,p->y,p->z)) > 0.0) pos.x = p->x; else neg.x = p->x; + } + } + + if((dx == 0.0f) && (dz == 0.0f)){ + p->x = neg.x; + p->z = neg.z; + while (1) { + p->y = 0.5f*(pos.y + neg.y); + if (i++ == RES) return; + if ((function(p->x,p->y,p->z)) > 0.0) pos.y = p->y; else neg.y = p->y; + } + } + + if((dx == 0.0f) && (dy == 0.0f)){ + p->x = neg.x; + p->y = neg.y; + while (1) { + p->z = 0.5f*(pos.z + neg.z); + if (i++ == RES) return; + if ((function(p->x,p->y,p->z)) > 0.0) pos.z = p->z; else neg.z = p->z; + } + } + + /* This is necessary to find start point */ + while (1) { + p->x = 0.5f*(pos.x + neg.x); + p->y = 0.5f*(pos.y + neg.y); + p->z = 0.5f*(pos.z + neg.z); + + if (i++ == RES) return; + + if ((function(p->x, p->y, p->z)) > 0.0){ + pos.x = p->x; + pos.y = p->y; + pos.z = p->z; + } + else{ + neg.x = p->x; + neg.y = p->y; + neg.z = p->z; + } + } +} + +/* ************************************** */ +void add_cube(PROCESS *mbproc, int i, int j, int k, int count) +{ + CUBES *ncube; + int n; + int a, b, c; + + /* hmmm, not only one, but eight cube will be added on the stack + * ... */ + for(a=i-1; acenters, a, b, c)==0 ) { + /* push cube on stack: */ + ncube= (CUBES *) new_pgn_element(sizeof(CUBES)); + ncube->next= mbproc->cubes; + mbproc->cubes= ncube; + + ncube->cube.i= a; + ncube->cube.j= b; + ncube->cube.k= c; + + /* set corners of initial cube: */ + for (n = 0; n < 8; n++) + ncube->cube.corners[n] = setcorner(mbproc, a+MB_BIT(n,2), b+MB_BIT(n,1), c+MB_BIT(n,0)); + } + } +} + + +void find_first_points(PROCESS *mbproc, MetaBall *mb, int a) +{ + MB_POINT IN, in, OUT, out; /*point;*/ + MetaElem *ml; + int i, j, k, c_i, c_j, c_k; + int index[3]={1,0,-1}; + float f =0.0f; + float in_v, out_v; + + ml = mainb[a]; + + f = 1-(mb->thresh/ml->s); + + /* Skip, when Stiffness of MetaElement is too small ... MetaElement can't be + * visible alone ... but still can influence others MetaElements :-) */ + if(f > 0.0) { + OUT.x = IN.x = in.x= 0.0; + OUT.y = IN.y = in.y= 0.0; + OUT.z = IN.z = in.z= 0.0; + + calc_mballco(ml, (float *)&in); + in_v = mbproc->function(in.x, in.y, in.z); + + for(i=0;i<3;i++){ + switch (ml->type) { + case MB_BALL: + OUT.x = out.x= IN.x + index[i]*ml->rad; + break; + case MB_TUBE: + case MB_PLANE: + case MB_ELIPSOID: + case MB_CUBE: + OUT.x = out.x= IN.x + index[i]*(ml->expx + ml->rad); + break; + } + + for(j=0;j<3;j++) { + switch (ml->type) { + case MB_BALL: + OUT.y = out.y= IN.y + index[j]*ml->rad; + break; + case MB_TUBE: + case MB_PLANE: + case MB_ELIPSOID: + case MB_CUBE: + OUT.y = out.y= IN.y + index[j]*(ml->expy + ml->rad); + break; + } + + for(k=0;k<3;k++) { + out.x = OUT.x; + out.y = OUT.y; + switch (ml->type) { + case MB_BALL: + case MB_TUBE: + case MB_PLANE: + out.z= IN.z + index[k]*ml->rad; + break; + case MB_ELIPSOID: + case MB_CUBE: + out.z= IN.z + index[k]*(ml->expz + ml->rad); + break; + } + + calc_mballco(ml, (float *)&out); + + out_v = mbproc->function(out.x, out.y, out.z); + + /* find "first point" on Implicit Surface of MetaElemnt ml */ + converge(&in, &out, in_v, out_v, mbproc->function, &mbproc->start, mb, 0); + + /* indexes of CUBE, which includes "first point" */ + c_i= (int)floor(mbproc->start.x/mbproc->size ); + c_j= (int)floor(mbproc->start.y/mbproc->size ); + c_k= (int)floor(mbproc->start.z/mbproc->size ); + + mbproc->start.x= mbproc->start.y= mbproc->start.z= 0.0; + + /* add CUBE (with indexes c_i, c_j, c_k) to the stack, + * this cube includes found point of Implicit Surface */ + if (ml->flag & MB_NEGATIVE) + add_cube(mbproc, c_i, c_j, c_k, 2); + else + add_cube(mbproc, c_i, c_j, c_k, 1); + + + } + } + } + } +} + +void polygonize(PROCESS *mbproc, MetaBall *mb) +{ + CUBE c; + int a; + + mbproc->vertices.count = mbproc->vertices.max = 0; + mbproc->vertices.ptr = NULL; + + /* allocate hash tables and build cube polygon table: */ + mbproc->centers = MEM_callocN(HASHSIZE * sizeof(CENTERLIST *), "mbproc->centers"); + mbproc->corners = MEM_callocN(HASHSIZE * sizeof(CORNER *), "mbproc->corners"); + mbproc->edges = MEM_callocN(2*HASHSIZE * sizeof(EDGELIST *), "mbproc->edges"); + makecubetable(); + + for(a=0; acubes != NULL) { /* process active cubes till none left */ + c = mbproc->cubes->cube; + + /* polygonize the cube directly: */ + docube(&c, mbproc, mb); + + /* pop current cube from stack */ + mbproc->cubes = mbproc->cubes->next; + + /* test six face directions, maybe add to stack: */ + testface(c.i-1, c.j, c.k, &c, 2, LBN, LBF, LTN, LTF, mbproc); + testface(c.i+1, c.j, c.k, &c, 2, RBN, RBF, RTN, RTF, mbproc); + testface(c.i, c.j-1, c.k, &c, 1, LBN, LBF, RBN, RBF, mbproc); + testface(c.i, c.j+1, c.k, &c, 1, LTN, LTF, RTN, RTF, mbproc); + testface(c.i, c.j, c.k-1, &c, 0, LBN, LTN, RBN, RTN, mbproc); + testface(c.i, c.j, c.k+1, &c, 0, LBF, LTF, RBF, RTF, mbproc); + } +} + +float init_meta(Object *ob) /* return totsize */ +{ + Base *base; + Object *bob; + MetaBall *mb; + MetaElem *ml; + float size, totsize, (*mat)[4] = NULL, (*imat)[4] = NULL, obinv[4][4], obmat[4][4], vec[3]; + float temp1[4][4], temp2[4][4], temp3[4][4]; //max=0.0; + int a, obnr, zero_size=0; + char obname[32]; + + Mat4CpyMat4(obmat, ob->obmat); /* to cope with duplicators from next_object */ + Mat4Invert(obinv, ob->obmat); + a= 0; + + splitIDname(ob->id.name+2, obname, &obnr); + + /* make main array */ + + next_object(0, 0, 0); + while(next_object(1, &base, &bob)) { + + if(bob->type==OB_MBALL) { + zero_size= 0; + ml= NULL; + + if(bob==ob && (base->flag & OB_FROMDUPLI)==0) { + mat= imat= 0; + mb= ob->data; + + if(ob==G.obedit) ml= editelems.first; + else if(G.obedit && G.obedit->type==OB_MBALL && G.obedit->data==mb) ml= editelems.first; + else ml= mb->elems.first; + } + else { + char name[32]; + int nr; + + splitIDname(bob->id.name+2, name, &nr); + if( strcmp(obname, name)==0 ) { + mb= bob->data; + if(G.obedit && G.obedit->type==OB_MBALL && G.obedit->data==mb) + ml= editelems.first; + else ml= mb->elems.first; + } + } + + /* when metaball object hase zero scale, then MetaElem ot this MetaBall + * will not be put to mainb array */ + if(bob->size[0]==0.0 || bob->size[1]==0.0 || bob->size[2]==0.0) { + zero_size= 1; + } + else if(bob->parent) { + struct Object *pob=bob->parent; + while(pob) { + if(pob->size[0]==0.0 || pob->size[1]==0.0 || pob->size[2]==0.0) { + zero_size= 1; + break; + } + pob= pob->parent; + } + } + + if (zero_size) { + unsigned int ml_count=0; + while(ml) { + ml_count++; + ml= ml->next; + } + totelem -= ml_count; + } + else { + while(ml) { + if(!(ml->flag & MB_HIDE)) { + int i; + float max_x, max_y, max_z, min_x, min_y, min_z; + + max_x = max_y = max_z = -3.4e38; + min_x = min_y = min_z = 3.4e38; + + /* too big stiffness seems only ugly due to linear interpolation + * no need to have possibility for too big stiffness */ + if(ml->s > 10.0) ml->s = 10.0; + + /* Rotation of MetaElem is stored in quat */ + QuatToMat4(ml->quat, temp3); + + /* Translation of MetaElem */ + Mat4One(temp2); + temp2[3][0]= ml->x; + temp2[3][1]= ml->y; + temp2[3][2]= ml->z; + + Mat4MulMat4(temp1, temp3, temp2); + + /* make a copy because of duplicates */ + mainb[a]= new_pgn_element(sizeof(MetaElem)); + *(mainb[a])= *ml; + mainb[a]->bb = new_pgn_element(sizeof(BoundBox)); + + mat= new_pgn_element(4*4*sizeof(float)); + imat= new_pgn_element(4*4*sizeof(float)); + + /* mat is the matrix to transform from mball into the basis-mball */ + Mat4Invert(obinv, obmat); + Mat4MulMat4(temp2, bob->obmat, obinv); + /* MetaBall transformation */ + Mat4MulMat4(mat, temp1, temp2); + + Mat4Invert(imat,mat); + + mainb[a]->rad2= ml->rad*ml->rad; + + mainb[a]->mat= (float*) mat; + mainb[a]->imat= (float*) imat; + + /* untransformed Bounding Box of MetaElem */ + /* 0 */ + mainb[a]->bb->vec[0][0]= -ml->expx; + mainb[a]->bb->vec[0][1]= -ml->expy; + mainb[a]->bb->vec[0][2]= -ml->expz; + /* 1 */ + mainb[a]->bb->vec[1][0]= ml->expx; + mainb[a]->bb->vec[1][1]= -ml->expy; + mainb[a]->bb->vec[1][2]= -ml->expz; + /* 2 */ + mainb[a]->bb->vec[2][0]= ml->expx; + mainb[a]->bb->vec[2][1]= ml->expy; + mainb[a]->bb->vec[2][2]= -ml->expz; + /* 3 */ + mainb[a]->bb->vec[3][0]= -ml->expx; + mainb[a]->bb->vec[3][1]= ml->expy; + mainb[a]->bb->vec[3][2]= -ml->expz; + /* 4 */ + mainb[a]->bb->vec[4][0]= -ml->expx; + mainb[a]->bb->vec[4][1]= -ml->expy; + mainb[a]->bb->vec[4][2]= ml->expz; + /* 5 */ + mainb[a]->bb->vec[5][0]= ml->expx; + mainb[a]->bb->vec[5][1]= -ml->expy; + mainb[a]->bb->vec[5][2]= ml->expz; + /* 6 */ + mainb[a]->bb->vec[6][0]= ml->expx; + mainb[a]->bb->vec[6][1]= ml->expy; + mainb[a]->bb->vec[6][2]= ml->expz; + /* 7 */ + mainb[a]->bb->vec[7][0]= -ml->expx; + mainb[a]->bb->vec[7][1]= ml->expy; + mainb[a]->bb->vec[7][2]= ml->expz; + + /* transformation of Metalem bb */ + for(i=0; i<8; i++) + Mat4MulVecfl((float ( * )[4])mat, mainb[a]->bb->vec[i]); + + /* find max and min of transformed bb */ + for(i=0; i<8; i++){ + /* find maximums */ + if(mainb[a]->bb->vec[i][0] > max_x) max_x = mainb[a]->bb->vec[i][0]; + if(mainb[a]->bb->vec[i][1] > max_y) max_y = mainb[a]->bb->vec[i][1]; + if(mainb[a]->bb->vec[i][2] > max_z) max_z = mainb[a]->bb->vec[i][2]; + /* find minimums */ + if(mainb[a]->bb->vec[i][0] < min_x) min_x = mainb[a]->bb->vec[i][0]; + if(mainb[a]->bb->vec[i][1] < min_y) min_y = mainb[a]->bb->vec[i][1]; + if(mainb[a]->bb->vec[i][2] < min_z) min_z = mainb[a]->bb->vec[i][2]; + } + + /* create "new" bb, only point 0 and 6, which are + * neccesary for octal tree filling */ + mainb[a]->bb->vec[0][0] = min_x - ml->rad; + mainb[a]->bb->vec[0][1] = min_y - ml->rad; + mainb[a]->bb->vec[0][2] = min_z - ml->rad; + + mainb[a]->bb->vec[6][0] = max_x + ml->rad; + mainb[a]->bb->vec[6][1] = max_y + ml->rad; + mainb[a]->bb->vec[6][2] = max_z + ml->rad; + + a++; + } + ml= ml->next; + } + } + } + } + + + /* totsize (= 'manhattan' radius) */ + totsize= 0.0; + for(a=0; ax + mainb[a]->rad + mainb[a]->expx; + vec[1]= mainb[a]->y + mainb[a]->rad + mainb[a]->expy; + vec[2]= mainb[a]->z + mainb[a]->rad + mainb[a]->expz; + + calc_mballco(mainb[a], vec); + + size= (float)fabs( vec[0] ); + if( size > totsize ) totsize= size; + size= (float)fabs( vec[1] ); + if( size > totsize ) totsize= size; + size= (float)fabs( vec[2] ); + if( size > totsize ) totsize= size; + + vec[0]= mainb[a]->x - mainb[a]->rad; + vec[1]= mainb[a]->y - mainb[a]->rad; + vec[2]= mainb[a]->z - mainb[a]->rad; + + calc_mballco(mainb[a], vec); + + size= (float)fabs( vec[0] ); + if( size > totsize ) totsize= size; + size= (float)fabs( vec[1] ); + if( size > totsize ) totsize= size; + size= (float)fabs( vec[2] ); + if( size > totsize ) totsize= size; + } + + for(a=0; aml= ml; + BLI_addtail(&(node->nodes[i]->elems), ml_p); + node->count++; + + if(ml->flag & MB_NEGATIVE) { + node->nodes[i]->neg++; + } + else{ + node->nodes[i]->pos++; + } +} + +/* Node is subdivided as is ilustrated on the following figure: + * + * +------+------+ + * / / /| + * +------+------+ | + * / / /| + + * +------+------+ |/| + * | | | + | + * | | |/| + + * +------+------+ |/ + * | | | + + * | | |/ + * +------+------+ + * + */ +void subdivide_metaball_octal_node(octal_node *node, float *size, short depth) +{ + MetaElem *ml; + ml_pointer *ml_p; + float x,y,z; + int a,i; + + if(depth==0) return; + + /* create new nodes */ + for(a=0;a<8;a++){ + node->nodes[a]= MEM_mallocN(sizeof(octal_node),"octal_node"); + for(i=0;i<8;i++) + node->nodes[a]->nodes[i]= NULL; + node->nodes[a]->parent= node; + node->nodes[a]->elems.first= NULL; + node->nodes[a]->elems.last= NULL; + node->nodes[a]->count= 0; + node->nodes[a]->neg= 0; + node->nodes[a]->pos= 0; + } + + size[0]/=2; size[1]/=2; size[2]/=2; + + /* center of node */ + node->x= x= node->x_min + size[0]; + node->y= y= node->y_min + size[1]; + node->z= z= node->z_min + size[2]; + + /* setting up of border points of new nodes */ + node->nodes[0]->x_min= node->x_min; + node->nodes[0]->y_min= node->y_min; + node->nodes[0]->z_min= node->z_min; + + node->nodes[1]->x_min= x; + node->nodes[1]->y_min= node->y_min; + node->nodes[1]->z_min= node->z_min; + + node->nodes[2]->x_min= x; + node->nodes[2]->y_min= y; + node->nodes[2]->z_min= node->z_min; + + node->nodes[3]->x_min= node->x_min; + node->nodes[3]->y_min= y; + node->nodes[3]->z_min= node->z_min; + + node->nodes[4]->x_min= node->x_min; + node->nodes[4]->y_min= node->y_min; + node->nodes[4]->z_min= z; + + node->nodes[5]->x_min= x; + node->nodes[5]->y_min= node->y_min; + node->nodes[5]->z_min= z; + + node->nodes[6]->x_min= x; + node->nodes[6]->y_min= y; + node->nodes[6]->z_min= z; + + node->nodes[7]->x_min= node->x_min; + node->nodes[7]->y_min= y; + node->nodes[7]->z_min= z; + + ml_p= node->elems.first; + + /* setting up references of MetaElems for new nodes */ + while(ml_p){ + ml= ml_p->ml; + if(ml->bb->vec[0][2] < z){ + if(ml->bb->vec[0][1] < y){ + /* vec[0][0] lies in first octant */ + if(ml->bb->vec[0][0] < x){ + /* ml belongs to the (0)1st node */ + fill_metaball_octal_node(node, ml, 0); + + /* ml belongs to the (3)4th node */ + if(ml->bb->vec[6][1] >= y){ + fill_metaball_octal_node(node, ml, 3); + + /* ml belongs to the (7)8th node */ + if(ml->bb->vec[6][2] >= z){ + fill_metaball_octal_node(node, ml, 7); + } + } + + /* ml belongs to the (1)2nd node */ + if(ml->bb->vec[6][0] >= x){ + fill_metaball_octal_node(node, ml, 1); + + /* ml belongs to the (5)6th node */ + if(ml->bb->vec[6][2] >= z){ + fill_metaball_octal_node(node, ml, 5); + } + } + + /* ml belongs to the (2)3th node */ + if((ml->bb->vec[6][0] >= x) && (ml->bb->vec[6][1] >= y)){ + fill_metaball_octal_node(node, ml, 2); + + /* ml belong to the (6)7th node */ + if(ml->bb->vec[6][2] >= z){ + fill_metaball_octal_node(node, ml, 6); + } + + } + + /* ml belongs to the (4)5th node too */ + if(ml->bb->vec[6][2] >= z){ + fill_metaball_octal_node(node, ml, 4); + } + + + + } + /* vec[0][0] is in the (1)second octant */ + else{ + /* ml belong to the (1)2nd node */ + fill_metaball_octal_node(node, ml, 1); + + /* ml belongs to the (2)3th node */ + if(ml->bb->vec[6][1] >= y){ + fill_metaball_octal_node(node, ml, 2); + + /* ml belongs to the (6)7th node */ + if(ml->bb->vec[6][2] >= z){ + fill_metaball_octal_node(node, ml, 6); + } + + } + + /* ml belongs to the (5)6th node */ + if(ml->bb->vec[6][2] >= z){ + fill_metaball_octal_node(node, ml, 5); + } + } + } + else{ + /* vec[0][0] is in the (3)4th octant */ + if(ml->bb->vec[0][0] < x){ + /* ml belongs to the (3)4nd node */ + fill_metaball_octal_node(node, ml, 3); + + /* ml belongs to the (7)8th node */ + if(ml->bb->vec[6][2] >= z){ + fill_metaball_octal_node(node, ml, 7); + } + + + /* ml belongs to the (2)3th node */ + if(ml->bb->vec[6][0] >= x){ + fill_metaball_octal_node(node, ml, 2); + + /* ml belongs to the (6)7th node */ + if(ml->bb->vec[6][2] >= z){ + fill_metaball_octal_node(node, ml, 6); + } + } + } + + } + + /* vec[0][0] is in the (2)3th octant */ + if((ml->bb->vec[0][0] >= x) && (ml->bb->vec[0][1] >= y)){ + /* ml belongs to the (2)3th node */ + fill_metaball_octal_node(node, ml, 2); + + /* ml belongs to the (6)7th node */ + if(ml->bb->vec[6][2] >= z){ + fill_metaball_octal_node(node, ml, 6); + } + } + } + else{ + if(ml->bb->vec[0][1] < y){ + /* vec[0][0] lies in (4)5th octant */ + if(ml->bb->vec[0][0] < x){ + /* ml belongs to the (4)5th node */ + fill_metaball_octal_node(node, ml, 4); + + if(ml->bb->vec[6][0] >= x){ + fill_metaball_octal_node(node, ml, 5); + } + + if(ml->bb->vec[6][1] >= y){ + fill_metaball_octal_node(node, ml, 7); + } + + if((ml->bb->vec[6][0] >= x) && (ml->bb->vec[6][1] >= y)){ + fill_metaball_octal_node(node, ml, 6); + } + } + /* vec[0][0] lies in (5)6th octant */ + else{ + fill_metaball_octal_node(node, ml, 5); + + if(ml->bb->vec[6][1] >= y){ + fill_metaball_octal_node(node, ml, 6); + } + } + } + else{ + /* vec[0][0] lies in (7)8th octant */ + if(ml->bb->vec[0][0] < x){ + fill_metaball_octal_node(node, ml, 7); + + if(ml->bb->vec[6][0] >= x){ + fill_metaball_octal_node(node, ml, 6); + } + } + + } + + /* vec[0][0] lies in (6)7th octant */ + if((ml->bb->vec[0][0] >= x) && (ml->bb->vec[0][1] >= y)){ + fill_metaball_octal_node(node, ml, 6); + } + } + ml_p= ml_p->next; + } + + /* free references of MetaElems for curent node (it is not needed anymore) */ + BLI_freelistN(&node->elems); + + depth--; + + if(depth>0){ + for(a=0;a<8;a++){ + if(node->nodes[a]->count > 0) /* if node is not empty, then it is subdivided */ + subdivide_metaball_octal_node(node->nodes[a], size, depth); + } + } +} + +/* free all octal nodes recursively */ +void free_metaball_octal_node(octal_node *node) +{ + int a; + for(a=0;a<8;a++){ + if(node->nodes[a]!=NULL) free_metaball_octal_node(node->nodes[a]); + } + BLI_freelistN(&node->elems); + MEM_freeN(node); +} + +/* If scene include more then one MetaElem, then octree is used */ +void init_metaball_octal_tree(int depth) +{ + struct octal_node *node; + ml_pointer *ml_p; + float size[3]; + int a; + + metaball_tree= MEM_mallocN(sizeof(octal_tree), "metaball_octal_tree"); + metaball_tree->first= node= MEM_mallocN(sizeof(octal_node), "metaball_octal_node"); + /* maximal depth of octree */ + metaball_tree->depth= depth; + + metaball_tree->neg= node->neg=0; + metaball_tree->pos= node->pos=0; + + node->elems.first= NULL; + node->elems.last= NULL; + node->count=0; + + for(a=0;a<8;a++) + node->nodes[a]=NULL; + + node->x_min= node->y_min= node->z_min= FLT_MAX; + node->x_max= node->y_max= node->z_max= -FLT_MAX; + + /* size of octal tree scene */ + for(a=0;abb->vec[0][0] < node->x_min) node->x_min= mainb[a]->bb->vec[0][0]; + if(mainb[a]->bb->vec[0][1] < node->y_min) node->y_min= mainb[a]->bb->vec[0][1]; + if(mainb[a]->bb->vec[0][2] < node->z_min) node->z_min= mainb[a]->bb->vec[0][2]; + + if(mainb[a]->bb->vec[6][0] > node->x_max) node->x_max= mainb[a]->bb->vec[6][0]; + if(mainb[a]->bb->vec[6][1] > node->y_max) node->y_max= mainb[a]->bb->vec[6][1]; + if(mainb[a]->bb->vec[6][2] > node->z_max) node->z_max= mainb[a]->bb->vec[6][2]; + + ml_p= MEM_mallocN(sizeof(ml_pointer), "ml_pointer"); + ml_p->ml= mainb[a]; + BLI_addtail(&node->elems, ml_p); + + if(mainb[a]->flag & MB_NEGATIVE) { + /* number of negative MetaElem in scene */ + metaball_tree->neg++; + } + else{ + /* number of positive MetaElem in scene */ + metaball_tree->pos++; + } + } + + /* size of first node */ + size[0]= node->x_max - node->x_min; + size[1]= node->y_max - node->y_min; + size[2]= node->z_max - node->z_min; + + /* first node is subdivided recursively */ + subdivide_metaball_octal_node(node, size, metaball_tree->depth); +} + +void metaball_polygonize(Object *ob) +{ + PROCESS mbproc; + MetaBall *mb; + DispList *dl; + int a, nr_cubes; + float *ve, *no, totsize, width; + + mb= ob->data; + + if(totelem==0) return; + if(!(G.rendering) && (mb->flag==MB_UPDATE_NEVER)) return; + if(G.moving && mb->flag==MB_UPDATE_FAST) return; + + freedisplist(&ob->disp); + curindex= totindex= 0; + indices= 0; + thresh= mb->thresh; + + /* total number of MetaElems (totelem) is precomputed in find_basis_mball() function */ + mainb= MEM_mallocN(sizeof(void *)*totelem, "mainb"); + + /* initialize all mainb (MetaElems) */ + totsize= init_meta(ob); + + if(metaball_tree){ + free_metaball_octal_node(metaball_tree->first); + MEM_freeN(metaball_tree); + metaball_tree= NULL; + } + + /* if scene includes more then one MetaElem, then octal tree optimalisation is used */ + if((totelem > 1) && (totelem <= 64)) init_metaball_octal_tree(1); + if((totelem > 64) && (totelem <= 128)) init_metaball_octal_tree(2); + if((totelem > 128) && (totelem <= 512)) init_metaball_octal_tree(3); + if((totelem > 512) && (totelem <= 1024)) init_metaball_octal_tree(4); + if(totelem > 1024) init_metaball_octal_tree(5); + + /* don't polygonize metaballs with too high resolution (base mball to small) */ + if(metaball_tree) { + if(ob->size[0]<=0.0001f*(metaball_tree->first->x_max - metaball_tree->first->x_min) || + ob->size[1]<=0.0001f*(metaball_tree->first->y_max - metaball_tree->first->y_min) || + ob->size[2]<=0.0001f*(metaball_tree->first->z_max - metaball_tree->first->z_min)) + { + MEM_freeN(mainb); + return; + } + } + + /* width is size per polygonize cube */ + if(G.rendering) width= mb->rendersize; + else { + width= mb->wiresize; + if(G.moving && mb->flag==MB_UPDATE_HALFRES) width*= 2; + } + /* nr_cubes is just for safety, minimum is totsize */ + nr_cubes= (int)(0.5+totsize/width); + + /* init process */ + mbproc.function = metaball; + mbproc.size = width; + mbproc.bounds = nr_cubes; + mbproc.cubes= 0; + mbproc.delta = width/(float)(RES*RES); + + polygonize(&mbproc, mb); + + MEM_freeN(mainb); + + /* free octal tree */ + if(totelem > 1){ + free_metaball_octal_node(metaball_tree->first); + MEM_freeN(metaball_tree); + metaball_tree= NULL; + } + + if(curindex) { + + dl= MEM_callocN(sizeof(DispList), "mbaldisp"); + BLI_addtail(&ob->disp, dl); + dl->type= DL_INDEX4; + dl->nr= mbproc.vertices.count; + dl->parts= curindex; + + dl->index= indices; + indices= 0; + + a= mbproc.vertices.count; + dl->verts= ve= MEM_mallocN(sizeof(float)*3*a, "mballverts"); + dl->nors= no= MEM_mallocN(sizeof(float)*3*a, "mballnors"); + + for(a=0; a +#endif + +#include +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_ID.h" +#include "DNA_curve_types.h" +#include "DNA_material_types.h" +#include "DNA_object_types.h" +#include "DNA_image_types.h" +#include "DNA_key_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_ipo_types.h" + +#include "BDR_sculptmode.h" + +#include "BKE_customdata.h" +#include "BKE_depsgraph.h" +#include "BKE_main.h" +#include "BKE_DerivedMesh.h" +#include "BKE_global.h" +#include "BKE_mesh.h" +#include "BKE_subsurf.h" +#include "BKE_displist.h" +#include "BKE_library.h" +#include "BKE_material.h" +#include "BKE_key.h" +/* these 2 are only used by conversion functions */ +#include "BKE_curve.h" +/* -- */ +#include "BKE_object.h" +#include "BKE_utildefines.h" +#include "BKE_bad_level_calls.h" + +#ifdef WITH_VERSE +#include "BKE_verse.h" +#endif + +#include "BLI_blenlib.h" +#include "BLI_editVert.h" +#include "BLI_arithb.h" + +#include "multires.h" + +int update_realtime_texture(MTFace *tface, double time) +{ + Image *ima; + int inc = 0; + float diff; + int newframe; + + ima = tface->tpage; + + if (!ima) + return 0; + + if (ima->lastupdate<0) + ima->lastupdate = 0; + + if (ima->lastupdate>time) + ima->lastupdate=(float)time; + + if(ima->tpageflag & IMA_TWINANIM) { + if(ima->twend >= ima->xrep*ima->yrep) ima->twend= ima->xrep*ima->yrep-1; + + /* check: is the bindcode not in the array? Then free. (still to do) */ + + diff = (float)(time-ima->lastupdate); + + inc = (int)(diff*(float)ima->animspeed); + + ima->lastupdate+=((float)inc/(float)ima->animspeed); + + newframe = ima->lastframe+inc; + + if (newframe > (int)ima->twend) + newframe = (int)ima->twsta-1 + (newframe-ima->twend)%(ima->twend-ima->twsta); + + ima->lastframe = newframe; + } + return inc; +} + +void mesh_update_customdata_pointers(Mesh *me) +{ + me->mvert = CustomData_get_layer(&me->vdata, CD_MVERT); + me->dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT); + me->msticky = CustomData_get_layer(&me->vdata, CD_MSTICKY); + + me->medge = CustomData_get_layer(&me->edata, CD_MEDGE); + + me->mface = CustomData_get_layer(&me->fdata, CD_MFACE); + me->mcol = CustomData_get_layer(&me->fdata, CD_MCOL); + me->mtface = CustomData_get_layer(&me->fdata, CD_MTFACE); +} + +/* Note: unlinking is called when me->id.us is 0, question remains how + * much unlinking of Library data in Mesh should be done... probably + * we need a more generic method, like the expand() functions in + * readfile.c */ + +void unlink_mesh(Mesh *me) +{ + int a; + + if(me==0) return; + + for(a=0; atotcol; a++) { + if(me->mat[a]) me->mat[a]->id.us--; + me->mat[a]= 0; + } + + if(me->key) { + me->key->id.us--; + if (me->key->id.us == 0 && me->key->ipo ) + me->key->ipo->id.us--; + } + me->key= 0; + + if(me->texcomesh) me->texcomesh= 0; +} + + +/* do not free mesh itself */ +void free_mesh(Mesh *me) +{ + unlink_mesh(me); + + if(me->pv) { + if(me->pv->vert_map) MEM_freeN(me->pv->vert_map); + if(me->pv->edge_map) MEM_freeN(me->pv->edge_map); + if(me->pv->old_faces) MEM_freeN(me->pv->old_faces); + if(me->pv->old_edges) MEM_freeN(me->pv->old_edges); + me->totvert= me->pv->totvert; + me->totedge= me->pv->totedge; + me->totface= me->pv->totface; + MEM_freeN(me->pv); + } + + CustomData_free(&me->vdata, me->totvert); + CustomData_free(&me->edata, me->totedge); + CustomData_free(&me->fdata, me->totface); + + if(me->mat) MEM_freeN(me->mat); + + if(me->bb) MEM_freeN(me->bb); + if(me->mselect) MEM_freeN(me->mselect); + + if(me->mr) multires_free(me->mr); +} + +void copy_dverts(MDeformVert *dst, MDeformVert *src, int copycount) +{ + /* Assumes dst is already set up */ + int i; + + if (!src || !dst) + return; + + memcpy (dst, src, copycount * sizeof(MDeformVert)); + + for (i=0; imesh, ID_ME, name); + + me->size[0]= me->size[1]= me->size[2]= 1.0; + me->smoothresh= 30; + me->texflag= AUTOSPACE; + me->flag= ME_TWOSIDED; + me->bb= unit_boundbox(); + +#ifdef WITH_VERSE + me->vnode = NULL; +#endif + + return me; +} + +Mesh *copy_mesh(Mesh *me) +{ + Mesh *men; + MTFace *tface; + int a, i; + + men= copy_libblock(me); + + men->mat= MEM_dupallocN(me->mat); + for(a=0; atotcol; a++) { + id_us_plus((ID *)men->mat[a]); + } + id_us_plus((ID *)men->texcomesh); + + CustomData_copy(&me->vdata, &men->vdata, CD_MASK_MESH, CD_DUPLICATE, men->totvert); + CustomData_copy(&me->edata, &men->edata, CD_MASK_MESH, CD_DUPLICATE, men->totedge); + CustomData_copy(&me->fdata, &men->fdata, CD_MASK_MESH, CD_DUPLICATE, men->totface); + mesh_update_customdata_pointers(men); + + /* ensure indirect linked data becomes lib-extern */ + for(i=0; ifdata.totlayer; i++) { + if(me->fdata.layers[i].type == CD_MTFACE) { + tface= (MTFace*)me->fdata.layers[i].data; + + for(a=0; atotface; a++, tface++) + if(tface->tpage) + id_lib_extern((ID*)tface->tpage); + } + } + + if(me->mr) + men->mr= multires_copy(me->mr); + + men->mselect= NULL; + + men->bb= MEM_dupallocN(men->bb); + + men->key= copy_key(me->key); + if(men->key) men->key->from= (ID *)men; + +#ifdef WITH_VERSE + men->vnode = NULL; +#endif + + return men; +} + +void make_local_tface(Mesh *me) +{ + MTFace *tface; + Image *ima; + int a, i; + + for(i=0; ifdata.totlayer; i++) { + if(me->fdata.layers[i].type == CD_MTFACE) { + tface= (MTFace*)me->fdata.layers[i].data; + + for(a=0; atotface; a++, tface++) { + /* special case: ima always local immediately */ + if(tface->tpage) { + ima= tface->tpage; + if(ima->id.lib) { + ima->id.lib= 0; + ima->id.flag= LIB_LOCAL; + new_id(0, (ID *)ima, 0); + } + } + } + } + } +} + +void make_local_mesh(Mesh *me) +{ + Object *ob; + Mesh *men; + int local=0, lib=0; + + /* - only lib users: do nothing + * - only local users: set flag + * - mixed: make copy + */ + + if(me->id.lib==0) return; + if(me->id.us==1) { + me->id.lib= 0; + me->id.flag= LIB_LOCAL; + new_id(0, (ID *)me, 0); + + if(me->mtface) make_local_tface(me); + + return; + } + + ob= G.main->object.first; + while(ob) { + if( me==get_mesh(ob) ) { + if(ob->id.lib) lib= 1; + else local= 1; + } + ob= ob->id.next; + } + + if(local && lib==0) { + me->id.lib= 0; + me->id.flag= LIB_LOCAL; + new_id(0, (ID *)me, 0); + + if(me->mtface) make_local_tface(me); + + } + else if(local && lib) { + men= copy_mesh(me); + men->id.us= 0; + + ob= G.main->object.first; + while(ob) { + if( me==get_mesh(ob) ) { + if(ob->id.lib==0) { + set_mesh(ob, men); + } + } + ob= ob->id.next; + } + } +} + +void boundbox_mesh(Mesh *me, float *loc, float *size) +{ + MVert *mvert; + BoundBox *bb; + float min[3], max[3]; + float mloc[3], msize[3]; + int a; + + if(me->bb==0) me->bb= MEM_callocN(sizeof(BoundBox), "boundbox"); + bb= me->bb; + + INIT_MINMAX(min, max); + + if (!loc) loc= mloc; + if (!size) size= msize; + + mvert= me->mvert; + for(a=0; atotvert; a++, mvert++) { + DO_MINMAX(mvert->co, min, max); + } + + if(!me->totvert) { + min[0] = min[1] = min[2] = -1.0f; + max[0] = max[1] = max[2] = 1.0f; + } + + loc[0]= (min[0]+max[0])/2.0f; + loc[1]= (min[1]+max[1])/2.0f; + loc[2]= (min[2]+max[2])/2.0f; + + size[0]= (max[0]-min[0])/2.0f; + size[1]= (max[1]-min[1])/2.0f; + size[2]= (max[2]-min[2])/2.0f; + + boundbox_set_from_min_max(bb, min, max); +} + +void tex_space_mesh(Mesh *me) +{ + KeyBlock *kb; + float *fp, loc[3], size[3], min[3], max[3]; + int a; + + boundbox_mesh(me, loc, size); + + if(me->texflag & AUTOSPACE) { + if(me->key) { + kb= me->key->refkey; + if (kb) { + + INIT_MINMAX(min, max); + + fp= kb->data; + for(a=0; atotelem; a++, fp+=3) { + DO_MINMAX(fp, min, max); + } + if(kb->totelem) { + loc[0]= (min[0]+max[0])/2.0f; loc[1]= (min[1]+max[1])/2.0f; loc[2]= (min[2]+max[2])/2.0f; + size[0]= (max[0]-min[0])/2.0f; size[1]= (max[1]-min[1])/2.0f; size[2]= (max[2]-min[2])/2.0f; + } + else { + loc[0]= loc[1]= loc[2]= 0.0; + size[0]= size[1]= size[2]= 0.0; + } + + } + } + + for (a=0; a<3; a++) { + if(size[a]==0.0) size[a]= 1.0; + else if(size[a]>0.0 && size[a]<0.00001) size[a]= 0.00001; + else if(size[a]<0.0 && size[a]> -0.00001) size[a]= -0.00001; + } + + VECCOPY(me->loc, loc); + VECCOPY(me->size, size); + me->rot[0]= me->rot[1]= me->rot[2]= 0.0; + } +} + +BoundBox *mesh_get_bb(Mesh *me) +{ + if (!me->bb) { + tex_space_mesh(me); + } + + return me->bb; +} + +void mesh_get_texspace(Mesh *me, float *loc_r, float *rot_r, float *size_r) +{ + if (!me->bb) { + tex_space_mesh(me); + } + + if (loc_r) VECCOPY(loc_r, me->loc); + if (rot_r) VECCOPY(rot_r, me->rot); + if (size_r) VECCOPY(size_r, me->size); +} + +static float *make_orco_mesh_internal(Object *ob, int render) +{ + Mesh *me = ob->data; + float (*orcoData)[3]; + int a, totvert; + float loc[3], size[3]; + DerivedMesh *dm; + float (*vcos)[3] = NULL; + + /* Get appropriate vertex coordinates */ + + if(me->key && me->texcomesh==0 && me->key->refkey) { + vcos= mesh_getRefKeyCos(me, &totvert); + } + else { + MultiresLevel *lvl = NULL; + MVert *mvert = NULL; + + if(me->mr) { + lvl = multires_level_n(me->mr, me->mr->pinlvl); + vcos = MEM_callocN(sizeof(*vcos)*lvl->totvert, "orco mr mesh"); + mvert = me->mr->verts; + totvert = lvl->totvert; + } + else { + Mesh *tme = me->texcomesh?me->texcomesh:me; + vcos = MEM_callocN(sizeof(*vcos)*me->totvert, "orco mesh"); + mvert = tme->mvert; + totvert = MIN2(tme->totvert, me->totvert); + } + + for(a=0; aco[0]; + vcos[a][1]= mvert->co[1]; + vcos[a][2]= mvert->co[2]; + } + } + + /* Apply orco-changing modifiers */ + + if (render) { + dm = mesh_create_derived_no_deform_render(ob, vcos, CD_MASK_BAREMESH); + } else { + dm = mesh_create_derived_no_deform(ob, vcos, CD_MASK_BAREMESH); + } + totvert = dm->getNumVerts(dm); + + orcoData = MEM_mallocN(sizeof(*orcoData)*totvert, "orcoData"); + dm->getVertCos(dm, orcoData); + dm->release(dm); + MEM_freeN(vcos); + + mesh_get_texspace(me->texcomesh?me->texcomesh:me, loc, NULL, size); + + for(a=0; av4) check for quads work */ +void test_index_face(MFace *mface, CustomData *fdata, int mfindex, int nr) +{ + /* first test if the face is legal */ + if(mface->v3 && mface->v3==mface->v4) { + mface->v4= 0; + nr--; + } + if(mface->v2 && mface->v2==mface->v3) { + mface->v3= mface->v4; + mface->v4= 0; + nr--; + } + if(mface->v1==mface->v2) { + mface->v2= mface->v3; + mface->v3= mface->v4; + mface->v4= 0; + nr--; + } + + /* prevent a zero at wrong index location */ + if(nr==3) { + if(mface->v3==0) { + static int corner_indices[4] = {1, 2, 0, 3}; + + SWAP(int, mface->v1, mface->v2); + SWAP(int, mface->v2, mface->v3); + + if(fdata) + CustomData_swap(fdata, mfindex, corner_indices); + } + } + else if(nr==4) { + if(mface->v3==0 || mface->v4==0) { + static int corner_indices[4] = {2, 3, 0, 1}; + + SWAP(int, mface->v1, mface->v3); + SWAP(int, mface->v2, mface->v4); + + if(fdata) + CustomData_swap(fdata, mfindex, corner_indices); + } + } +} + +Mesh *get_mesh(Object *ob) +{ + + if(ob==0) return 0; + if(ob->type==OB_MESH) return ob->data; + else return 0; +} + +void set_mesh(Object *ob, Mesh *me) +{ + Mesh *old=0; + + if(ob==0) return; + + if(ob->type==OB_MESH) { + old= ob->data; + old->id.us--; + ob->data= me; + id_us_plus((ID *)me); + } + + test_object_materials((ID *)me); +} + +/* ************** make edges in a Mesh, for outside of editmode */ + +struct edgesort { + int v1, v2; + short is_loose, is_draw; +}; + +/* edges have to be added with lowest index first for sorting */ +static void to_edgesort(struct edgesort *ed, int v1, int v2, short is_loose, short is_draw) +{ + if(v1v1= v1; ed->v2= v2; + } + else { + ed->v1= v2; ed->v2= v1; + } + ed->is_loose= is_loose; + ed->is_draw= is_draw; +} + +static int vergedgesort(const void *v1, const void *v2) +{ + const struct edgesort *x1=v1, *x2=v2; + + if( x1->v1 > x2->v1) return 1; + else if( x1->v1 < x2->v1) return -1; + else if( x1->v2 > x2->v2) return 1; + else if( x1->v2 < x2->v2) return -1; + + return 0; +} + +void make_edges(Mesh *me, int old) +{ + MFace *mface; + MEdge *medge; + struct edgesort *edsort, *ed; + int a, totedge=0, final=0; + + /* we put all edges in array, sort them, and detect doubles that way */ + + for(a= me->totface, mface= me->mface; a>0; a--, mface++) { + if(mface->v4) totedge+=4; + else if(mface->v3) totedge+=3; + else totedge+=1; + } + + if(totedge==0) { + /* flag that mesh has edges */ + me->medge = MEM_callocN(0, "make mesh edges"); + me->totedge = 0; + return; + } + + ed= edsort= MEM_mallocN(totedge*sizeof(struct edgesort), "edgesort"); + + for(a= me->totface, mface= me->mface; a>0; a--, mface++) { + to_edgesort(ed++, mface->v1, mface->v2, !mface->v3, mface->edcode & ME_V1V2); + if(mface->v4) { + to_edgesort(ed++, mface->v2, mface->v3, 0, mface->edcode & ME_V2V3); + to_edgesort(ed++, mface->v3, mface->v4, 0, mface->edcode & ME_V3V4); + to_edgesort(ed++, mface->v4, mface->v1, 0, mface->edcode & ME_V4V1); + } + else if(mface->v3) { + to_edgesort(ed++, mface->v2, mface->v3, 0, mface->edcode & ME_V2V3); + to_edgesort(ed++, mface->v3, mface->v1, 0, mface->edcode & ME_V3V1); + } + } + + qsort(edsort, totedge, sizeof(struct edgesort), vergedgesort); + + /* count final amount */ + for(a=totedge, ed=edsort; a>1; a--, ed++) { + /* edge is unique when it differs from next edge, or is last */ + if(ed->v1 != (ed+1)->v1 || ed->v2 != (ed+1)->v2) final++; + } + final++; + + + medge= CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, NULL, final); + me->medge= medge; + me->totedge= final; + + for(a=totedge, ed=edsort; a>1; a--, ed++) { + /* edge is unique when it differs from next edge, or is last */ + if(ed->v1 != (ed+1)->v1 || ed->v2 != (ed+1)->v2) { + medge->v1= ed->v1; + medge->v2= ed->v2; + if(old==0 || ed->is_draw) medge->flag= ME_EDGEDRAW|ME_EDGERENDER; + if(ed->is_loose) medge->flag|= ME_LOOSEEDGE; + medge++; + } + else { + /* equal edge, we merge the drawflag */ + (ed+1)->is_draw |= ed->is_draw; + } + } + /* last edge */ + medge->v1= ed->v1; + medge->v2= ed->v2; + medge->flag= ME_EDGEDRAW; + if(ed->is_loose) medge->flag|= ME_LOOSEEDGE; + medge->flag |= ME_EDGERENDER; + + MEM_freeN(edsort); + + mesh_strip_loose_faces(me); +} + +void mesh_strip_loose_faces(Mesh *me) +{ + int a,b; + + for (a=b=0; atotface; a++) { + if (me->mface[a].v3) { + if (a!=b) { + memcpy(&me->mface[b],&me->mface[a],sizeof(me->mface[b])); + CustomData_copy_data(&me->fdata, &me->fdata, a, b, 1); + CustomData_free_elem(&me->fdata, a, 1); + } + b++; + } + } + me->totface = b; +} + + +void mball_to_mesh(ListBase *lb, Mesh *me) +{ + DispList *dl; + MVert *mvert; + MFace *mface; + float *nors, *verts; + int a, *index; + + dl= lb->first; + if(dl==0) return; + + if(dl->type==DL_INDEX4) { + me->flag= ME_NOPUNOFLIP; + me->totvert= dl->nr; + me->totface= dl->parts; + + mvert= CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, dl->nr); + mface= CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, dl->parts); + me->mvert= mvert; + me->mface= mface; + + a= dl->nr; + nors= dl->nors; + verts= dl->verts; + while(a--) { + VECCOPY(mvert->co, verts); + mvert->no[0]= (short int)(nors[0]*32767.0); + mvert->no[1]= (short int)(nors[1]*32767.0); + mvert->no[2]= (short int)(nors[2]*32767.0); + mvert++; + nors+= 3; + verts+= 3; + } + + a= dl->parts; + index= dl->index; + while(a--) { + mface->v1= index[0]; + mface->v2= index[1]; + mface->v3= index[2]; + mface->v4= index[3]; + mface->flag= ME_SMOOTH; + + if(mface->v3==mface->v4) + mface->v4= 0; + + mface++; + index+= 4; + } + + make_edges(me, 0); // all edges + } +} + +/* this may fail replacing ob->data, be sure to check ob->type */ +void nurbs_to_mesh(Object *ob) +{ + Object *ob1; + DispList *dl; + Mesh *me; + Curve *cu; + MVert *mvert; + MFace *mface; + float *data; + int a, b, ofs, vertcount, startvert, totvert=0, totvlak=0; + int p1, p2, p3, p4, *index; + + cu= ob->data; + + /* count */ + dl= cu->disp.first; + while(dl) { + if(dl->type==DL_SEGM) { + totvert+= dl->parts*dl->nr; + totvlak+= dl->parts*(dl->nr-1); + } + else if(dl->type==DL_POLY) { + /* cyclic polys are filled. except when 3D */ + if(cu->flag & CU_3D) { + totvert+= dl->parts*dl->nr; + totvlak+= dl->parts*dl->nr; + } + } + else if(dl->type==DL_SURF) { + totvert+= dl->parts*dl->nr; + totvlak+= (dl->parts-1+((dl->flag & DL_CYCL_V)==2))*(dl->nr-1+(dl->flag & DL_CYCL_U)); + } + else if(dl->type==DL_INDEX3) { + totvert+= dl->nr; + totvlak+= dl->parts; + } + dl= dl->next; + } + if(totvert==0) { + /* error("can't convert"); */ + /* Make Sure you check ob->data is a curve */ + return; + } + + /* make mesh */ + me= add_mesh("Mesh"); + me->totvert= totvert; + me->totface= totvlak; + + me->totcol= cu->totcol; + me->mat= cu->mat; + cu->mat= 0; + cu->totcol= 0; + + mvert= CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert); + mface= CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, me->totface); + me->mvert= mvert; + me->mface= mface; + + /* verts and faces */ + vertcount= 0; + + dl= cu->disp.first; + while(dl) { + if(dl->type==DL_SEGM) { + startvert= vertcount; + a= dl->parts*dl->nr; + data= dl->verts; + while(a--) { + VECCOPY(mvert->co, data); + data+=3; + vertcount++; + mvert++; + } + + for(a=0; aparts; a++) { + ofs= a*dl->nr; + for(b=1; bnr; b++) { + mface->v1= startvert+ofs+b-1; + mface->v2= startvert+ofs+b; + mface++; + } + } + + } + else if(dl->type==DL_POLY) { + /* 3d polys are not filled */ + if(cu->flag & CU_3D) { + startvert= vertcount; + a= dl->parts*dl->nr; + data= dl->verts; + while(a--) { + VECCOPY(mvert->co, data); + data+=3; + vertcount++; + mvert++; + } + + for(a=0; aparts; a++) { + ofs= a*dl->nr; + for(b=0; bnr; b++) { + mface->v1= startvert+ofs+b; + if(b==dl->nr-1) mface->v2= startvert+ofs; + else mface->v2= startvert+ofs+b+1; + mface++; + } + } + } + } + else if(dl->type==DL_INDEX3) { + startvert= vertcount; + a= dl->nr; + data= dl->verts; + while(a--) { + VECCOPY(mvert->co, data); + data+=3; + vertcount++; + mvert++; + } + + a= dl->parts; + index= dl->index; + while(a--) { + mface->v1= startvert+index[0]; + mface->v2= startvert+index[2]; + mface->v3= startvert+index[1]; + mface->v4= 0; + test_index_face(mface, NULL, 0, 3); + + mface++; + index+= 3; + } + + + } + else if(dl->type==DL_SURF) { + startvert= vertcount; + a= dl->parts*dl->nr; + data= dl->verts; + while(a--) { + VECCOPY(mvert->co, data); + data+=3; + vertcount++; + mvert++; + } + + for(a=0; aparts; a++) { + + if( (dl->flag & DL_CYCL_V)==0 && a==dl->parts-1) break; + + if(dl->flag & DL_CYCL_U) { /* p2 -> p1 -> */ + p1= startvert+ dl->nr*a; /* p4 -> p3 -> */ + p2= p1+ dl->nr-1; /* -----> next row */ + p3= p1+ dl->nr; + p4= p2+ dl->nr; + b= 0; + } + else { + p2= startvert+ dl->nr*a; + p1= p2+1; + p4= p2+ dl->nr; + p3= p1+ dl->nr; + b= 1; + } + if( (dl->flag & DL_CYCL_V) && a==dl->parts-1) { + p3-= dl->parts*dl->nr; + p4-= dl->parts*dl->nr; + } + + for(; bnr; b++) { + mface->v1= p1; + mface->v2= p3; + mface->v3= p4; + mface->v4= p2; + mface->mat_nr= (unsigned char)dl->col; + test_index_face(mface, NULL, 0, 4); + mface++; + + p4= p3; + p3++; + p2= p1; + p1++; + } + } + + } + + dl= dl->next; + } + + make_edges(me, 0); // all edges + mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); + + if(ob->data) { + free_libblock(&G.main->curve, ob->data); + } + ob->data= me; + ob->type= OB_MESH; + + /* other users */ + ob1= G.main->object.first; + while(ob1) { + if(ob1->data==cu) { + ob1->type= OB_MESH; + + ob1->data= ob->data; + id_us_plus((ID *)ob->data); + } + ob1= ob1->id.next; + } + +} + +void mesh_delete_material_index(Mesh *me, int index) { + int i; + + for (i=0; itotface; i++) { + MFace *mf = &((MFace*) me->mface)[i]; + if (mf->mat_nr && mf->mat_nr>=index) + mf->mat_nr--; + } +} + +void mesh_set_smooth_flag(Object *meshOb, int enableSmooth) { + Mesh *me = meshOb->data; + int i; + + for (i=0; itotface; i++) { + MFace *mf = &((MFace*) me->mface)[i]; + + if (enableSmooth) { + mf->flag |= ME_SMOOTH; + } else { + mf->flag &= ~ME_SMOOTH; + } + } + + DAG_object_flush_update(G.scene, meshOb, OB_RECALC_DATA); +} + +void mesh_calc_normals(MVert *mverts, int numVerts, MFace *mfaces, int numFaces, float **faceNors_r) +{ + float (*tnorms)[3]= MEM_callocN(numVerts*sizeof(*tnorms), "tnorms"); + float *fnors= MEM_mallocN(sizeof(*fnors)*3*numFaces, "meshnormals"); + int i; + + for (i=0; iv4) + CalcNormFloat4(mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co, mverts[mf->v4].co, f_no); + else + CalcNormFloat(mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co, f_no); + + VecAddf(tnorms[mf->v1], tnorms[mf->v1], f_no); + VecAddf(tnorms[mf->v2], tnorms[mf->v2], f_no); + VecAddf(tnorms[mf->v3], tnorms[mf->v3], f_no); + if (mf->v4) + VecAddf(tnorms[mf->v4], tnorms[mf->v4], f_no); + } + for (i=0; ico); + Normalize(no); + } + + mv->no[0]= (short)(no[0]*32767.0); + mv->no[1]= (short)(no[1]*32767.0); + mv->no[2]= (short)(no[2]*32767.0); + } + + MEM_freeN(tnorms); + + if (faceNors_r) { + *faceNors_r = fnors; + } else { + MEM_freeN(fnors); + } +} + +float (*mesh_getVertexCos(Mesh *me, int *numVerts_r))[3] +{ +#ifdef WITH_VERSE + if(me->vnode) { + struct VLayer *vlayer; + struct VerseVert *vvert; + unsigned int i, numVerts; + float (*cos)[3]; + + vlayer = find_verse_layer_type((VGeomData*)((VNode*)me->vnode)->data, VERTEX_LAYER); + + vvert = vlayer->dl.lb.first; + numVerts = vlayer->dl.da.count; + cos = MEM_mallocN(sizeof(*cos)*numVerts, "verse_vertexcos"); + + for(i=0; inext, i++) { + VECCOPY(cos[i], vvert->co); + } + + return cos; + } + else { +#endif + int i, numVerts = me->totvert; + float (*cos)[3] = MEM_mallocN(sizeof(*cos)*numVerts, "vertexcos1"); + + if (numVerts_r) *numVerts_r = numVerts; + for (i=0; imvert[i].co); + + return cos; +#ifdef WITH_VERSE + } +#endif +} + +float (*mesh_getRefKeyCos(Mesh *me, int *numVerts_r))[3] +{ + KeyBlock *kb; + float (*cos)[3] = NULL; + int totvert; + + if(me->key && me->key->refkey) { + if(numVerts_r) *numVerts_r= me->totvert; + cos= MEM_mallocN(sizeof(*cos)*me->totvert, "vertexcos1"); + + kb= me->key->refkey; + totvert= MIN2(kb->totelem, me->totvert); + + memcpy(cos, kb->data, sizeof(*cos)*totvert); + } + + return cos; +} + +UvVertMap *make_uv_vert_map(struct MFace *mface, struct MTFace *tface, unsigned int totface, unsigned int totvert, int selected, float *limit) +{ + UvVertMap *vmap; + UvMapVert *buf; + MFace *mf; + MTFace *tf; + unsigned int a; + int i, totuv, nverts; + + totuv = 0; + + /* generate UvMapVert array */ + mf= mface; + tf= tface; + for(a=0; aflag & ME_HIDE) && (mf->flag & ME_FACE_SEL))) + totuv += (mf->v4)? 4: 3; + + if(totuv==0) + return NULL; + + vmap= (UvVertMap*)MEM_mallocN(sizeof(*vmap), "UvVertMap"); + if (!vmap) + return NULL; + + vmap->vert= (UvMapVert**)MEM_callocN(sizeof(*vmap->vert)*totvert, "UvMapVert*"); + buf= vmap->buf= (UvMapVert*)MEM_mallocN(sizeof(*vmap->buf)*totuv, "UvMapVert"); + + if (!vmap->vert || !vmap->buf) { + free_uv_vert_map(vmap); + return NULL; + } + + mf= mface; + tf= tface; + for(a=0; aflag & ME_HIDE) && (mf->flag & ME_FACE_SEL))) { + nverts= (mf->v4)? 4: 3; + + for(i=0; itfindex= i; + buf->f= a; + buf->separate = 0; + buf->next= vmap->vert[*(&mf->v1 + i)]; + vmap->vert[*(&mf->v1 + i)]= buf; + buf++; + } + } + } + + /* sort individual uvs for each vert */ + tf= tface; + for(a=0; avert[a]; + UvMapVert *iterv, *v, *lastv, *next; + float *uv, *uv2, uvdiff[2]; + + while(vlist) { + v= vlist; + vlist= vlist->next; + v->next= newvlist; + newvlist= v; + + uv= (tf+v->f)->uv[v->tfindex]; + lastv= NULL; + iterv= vlist; + + while(iterv) { + next= iterv->next; + + uv2= (tf+iterv->f)->uv[iterv->tfindex]; + Vec2Subf(uvdiff, uv2, uv); + + + if(fabs(uv[0]-uv2[0]) < limit[0] && fabs(uv[1]-uv2[1]) < limit[1]) { + if(lastv) lastv->next= next; + else vlist= next; + iterv->next= newvlist; + newvlist= iterv; + } + else + lastv=iterv; + + iterv= next; + } + + newvlist->separate = 1; + } + + vmap->vert[a]= newvlist; + } + + return vmap; +} + +UvMapVert *get_uv_map_vert(UvVertMap *vmap, unsigned int v) +{ + return vmap->vert[v]; +} + +void free_uv_vert_map(UvVertMap *vmap) +{ + if (vmap) { + if (vmap->vert) MEM_freeN(vmap->vert); + if (vmap->buf) MEM_freeN(vmap->buf); + MEM_freeN(vmap); + } +} + diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c new file mode 100644 index 00000000000..743926ed91b --- /dev/null +++ b/source/blender/blenkernel/intern/modifier.c @@ -0,0 +1,5765 @@ +/* +* $Id$ +* +* ***** BEGIN GPL LICENSE BLOCK ***** +* +* 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. +* +* The Original Code is Copyright (C) 2005 by the Blender Foundation. +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): Daniel Dunbar +* Ton Roosendaal, +* Ben Batt, +* Brecht Van Lommel, +* Campbell Barton +* +* ***** END GPL LICENSE BLOCK ***** +* +* Modifier stack implementation. +* +* BKE_modifier.h contains the function prototypes for this file. +* +*/ + +#include "string.h" +#include "stdarg.h" +#include "math.h" +#include "float.h" + +#include "BLI_blenlib.h" +#include "BLI_rand.h" +#include "BLI_arithb.h" +#include "BLI_linklist.h" +#include "BLI_edgehash.h" +#include "BLI_ghash.h" +#include "BLI_memarena.h" + +#include "MEM_guardedalloc.h" + +#include "DNA_armature_types.h" +#include "DNA_effect_types.h" +#include "DNA_material_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force.h" +#include "DNA_scene_types.h" +#include "DNA_texture_types.h" +#include "DNA_curve_types.h" +#include "DNA_camera_types.h" + +#include "BLI_editVert.h" + +#include "MTC_matrixops.h" +#include "MTC_vectorops.h" + +#include "BKE_main.h" +#include "BKE_anim.h" +#include "BKE_bad_level_calls.h" +#include "BKE_customdata.h" +#include "BKE_global.h" +#include "BKE_utildefines.h" +#include "BKE_cdderivedmesh.h" +#include "BKE_DerivedMesh.h" +#include "BKE_booleanops.h" +#include "BKE_displist.h" +#include "BKE_modifier.h" +#include "BKE_lattice.h" +#include "BKE_subsurf.h" +#include "BKE_object.h" +#include "BKE_mesh.h" +#include "BKE_softbody.h" +#include "BKE_material.h" +#include "depsgraph_private.h" + +#include "LOD_DependKludge.h" +#include "LOD_decimation.h" + +#include "CCGSubSurf.h" + +#include "RE_shader_ext.h" + +/***/ + +static int noneModifier_isDisabled(ModifierData *md) +{ + return 1; +} + +/* Curve */ + +static void curveModifier_initData(ModifierData *md) +{ + CurveModifierData *cmd = (CurveModifierData*) md; + + cmd->defaxis = MOD_CURVE_POSX; +} + +static void curveModifier_copyData(ModifierData *md, ModifierData *target) +{ + CurveModifierData *cmd = (CurveModifierData*) md; + CurveModifierData *tcmd = (CurveModifierData*) target; + + tcmd->defaxis = cmd->defaxis; + tcmd->object = cmd->object; + strncpy(tcmd->name, cmd->name, 32); +} + +CustomDataMask curveModifier_requiredDataMask(ModifierData *md) +{ + CurveModifierData *cmd = (CurveModifierData *)md; + CustomDataMask dataMask = 0; + + /* ask for vertexgroups if we need them */ + if(cmd->name[0]) dataMask |= (1 << CD_MDEFORMVERT); + + return dataMask; +} + +static int curveModifier_isDisabled(ModifierData *md) +{ + CurveModifierData *cmd = (CurveModifierData*) md; + + return !cmd->object; +} + +static void curveModifier_foreachObjectLink( + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) +{ + CurveModifierData *cmd = (CurveModifierData*) md; + + walk(userData, ob, &cmd->object); +} + +static void curveModifier_updateDepgraph( + ModifierData *md, DagForest *forest, + Object *ob, DagNode *obNode) +{ + CurveModifierData *cmd = (CurveModifierData*) md; + + if (cmd->object) { + DagNode *curNode = dag_get_node(forest, cmd->object); + + dag_add_relation(forest, curNode, obNode, + DAG_RL_DATA_DATA | DAG_RL_OB_DATA); + } +} + +static void curveModifier_deformVerts( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) +{ + CurveModifierData *cmd = (CurveModifierData*) md; + + curve_deform_verts(cmd->object, ob, derivedData, vertexCos, numVerts, + cmd->name, cmd->defaxis); +} + +static void curveModifier_deformVertsEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) +{ + DerivedMesh *dm = derivedData; + + if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data); + + curveModifier_deformVerts(md, ob, dm, vertexCos, numVerts); + + if(!derivedData) dm->release(dm); +} + +/* Lattice */ + +static void latticeModifier_copyData(ModifierData *md, ModifierData *target) +{ + LatticeModifierData *lmd = (LatticeModifierData*) md; + LatticeModifierData *tlmd = (LatticeModifierData*) target; + + tlmd->object = lmd->object; + strncpy(tlmd->name, lmd->name, 32); +} + +CustomDataMask latticeModifier_requiredDataMask(ModifierData *md) +{ + LatticeModifierData *lmd = (LatticeModifierData *)md; + CustomDataMask dataMask = 0; + + /* ask for vertexgroups if we need them */ + if(lmd->name[0]) dataMask |= (1 << CD_MDEFORMVERT); + + return dataMask; +} + +static int latticeModifier_isDisabled(ModifierData *md) +{ + LatticeModifierData *lmd = (LatticeModifierData*) md; + + return !lmd->object; +} + +static void latticeModifier_foreachObjectLink( + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) +{ + LatticeModifierData *lmd = (LatticeModifierData*) md; + + walk(userData, ob, &lmd->object); +} + +static void latticeModifier_updateDepgraph(ModifierData *md, DagForest *forest, + Object *ob, DagNode *obNode) +{ + LatticeModifierData *lmd = (LatticeModifierData*) md; + + if(lmd->object) { + DagNode *latNode = dag_get_node(forest, lmd->object); + + dag_add_relation(forest, latNode, obNode, + DAG_RL_DATA_DATA | DAG_RL_OB_DATA); + } +} + +static void latticeModifier_deformVerts( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) +{ + LatticeModifierData *lmd = (LatticeModifierData*) md; + + lattice_deform_verts(lmd->object, ob, derivedData, + vertexCos, numVerts, lmd->name); +} + +static void latticeModifier_deformVertsEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) +{ + DerivedMesh *dm = derivedData; + + if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data); + + latticeModifier_deformVerts(md, ob, dm, vertexCos, numVerts); + + if(!derivedData) dm->release(dm); +} + +/* Subsurf */ + +static void subsurfModifier_initData(ModifierData *md) +{ + SubsurfModifierData *smd = (SubsurfModifierData*) md; + + smd->levels = 1; + smd->renderLevels = 2; + smd->flags |= eSubsurfModifierFlag_SubsurfUv; +} + +static void subsurfModifier_copyData(ModifierData *md, ModifierData *target) +{ + SubsurfModifierData *smd = (SubsurfModifierData*) md; + SubsurfModifierData *tsmd = (SubsurfModifierData*) target; + + tsmd->flags = smd->flags; + tsmd->levels = smd->levels; + tsmd->renderLevels = smd->renderLevels; + tsmd->subdivType = smd->subdivType; +} + +static void subsurfModifier_freeData(ModifierData *md) +{ + SubsurfModifierData *smd = (SubsurfModifierData*) md; + + if(smd->mCache) { + ccgSubSurf_free(smd->mCache); + } + if(smd->emCache) { + ccgSubSurf_free(smd->emCache); + } +} + +static DerivedMesh *subsurfModifier_applyModifier( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) +{ + SubsurfModifierData *smd = (SubsurfModifierData*) md; + DerivedMesh *result; + + result = subsurf_make_derived_from_derived(derivedData, smd, + useRenderParams, NULL, + isFinalCalc, 0); + + return result; +} + +static DerivedMesh *subsurfModifier_applyModifierEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData) +{ + SubsurfModifierData *smd = (SubsurfModifierData*) md; + DerivedMesh *result; + + result = subsurf_make_derived_from_derived(derivedData, smd, 0, + NULL, 0, 1); + + return result; +} + +/* Build */ + +static void buildModifier_initData(ModifierData *md) +{ + BuildModifierData *bmd = (BuildModifierData*) md; + + bmd->start = 1.0; + bmd->length = 100.0; +} + +static void buildModifier_copyData(ModifierData *md, ModifierData *target) +{ + BuildModifierData *bmd = (BuildModifierData*) md; + BuildModifierData *tbmd = (BuildModifierData*) target; + + tbmd->start = bmd->start; + tbmd->length = bmd->length; + tbmd->randomize = bmd->randomize; + tbmd->seed = bmd->seed; +} + +static int buildModifier_dependsOnTime(ModifierData *md) +{ + return 1; +} + +static DerivedMesh *buildModifier_applyModifier(ModifierData *md, Object *ob, + DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) +{ + DerivedMesh *dm = derivedData; + DerivedMesh *result; + BuildModifierData *bmd = (BuildModifierData*) md; + int i; + int numFaces, numEdges; + int maxVerts, maxEdges, maxFaces; + int *vertMap, *edgeMap, *faceMap; + float frac; + GHashIterator *hashIter; + /* maps vert indices in old mesh to indices in new mesh */ + GHash *vertHash = BLI_ghash_new(BLI_ghashutil_inthash, + BLI_ghashutil_intcmp); + /* maps edge indices in new mesh to indices in old mesh */ + GHash *edgeHash = BLI_ghash_new(BLI_ghashutil_inthash, + BLI_ghashutil_intcmp); + + maxVerts = dm->getNumVerts(dm); + vertMap = MEM_callocN(sizeof(*vertMap) * maxVerts, + "build modifier vertMap"); + for(i = 0; i < maxVerts; ++i) vertMap[i] = i; + + maxEdges = dm->getNumEdges(dm); + edgeMap = MEM_callocN(sizeof(*edgeMap) * maxEdges, + "build modifier edgeMap"); + for(i = 0; i < maxEdges; ++i) edgeMap[i] = i; + + maxFaces = dm->getNumFaces(dm); + faceMap = MEM_callocN(sizeof(*faceMap) * maxFaces, + "build modifier faceMap"); + for(i = 0; i < maxFaces; ++i) faceMap[i] = i; + + if (ob) { + frac = bsystem_time(ob, (float)G.scene->r.cfra, + bmd->start - 1.0f) / bmd->length; + } else { + frac = G.scene->r.cfra - bmd->start / bmd->length; + } + CLAMP(frac, 0.0, 1.0); + + numFaces = dm->getNumFaces(dm) * frac; + numEdges = dm->getNumEdges(dm) * frac; + + /* if there's at least one face, build based on faces */ + if(numFaces) { + int maxEdges; + + if(bmd->randomize) + BLI_array_randomize(faceMap, sizeof(*faceMap), + maxFaces, bmd->seed); + + /* get the set of all vert indices that will be in the final mesh, + * mapped to the new indices + */ + for(i = 0; i < numFaces; ++i) { + MFace mf; + dm->getFace(dm, faceMap[i], &mf); + + if(!BLI_ghash_haskey(vertHash, (void *)mf.v1)) + BLI_ghash_insert(vertHash, (void *)mf.v1, + (void *)BLI_ghash_size(vertHash)); + if(!BLI_ghash_haskey(vertHash, (void *)mf.v2)) + BLI_ghash_insert(vertHash, (void *)mf.v2, + (void *)BLI_ghash_size(vertHash)); + if(!BLI_ghash_haskey(vertHash, (void *)mf.v3)) + BLI_ghash_insert(vertHash, (void *)mf.v3, + (void *)BLI_ghash_size(vertHash)); + if(mf.v4 && !BLI_ghash_haskey(vertHash, (void *)mf.v4)) + BLI_ghash_insert(vertHash, (void *)mf.v4, + (void *)BLI_ghash_size(vertHash)); + } + + /* get the set of edges that will be in the new mesh (i.e. all edges + * that have both verts in the new mesh) + */ + maxEdges = dm->getNumEdges(dm); + for(i = 0; i < maxEdges; ++i) { + MEdge me; + dm->getEdge(dm, i, &me); + + if(BLI_ghash_haskey(vertHash, (void *)me.v1) + && BLI_ghash_haskey(vertHash, (void *)me.v2)) + BLI_ghash_insert(edgeHash, + (void *)BLI_ghash_size(edgeHash), (void *)i); + } + } else if(numEdges) { + if(bmd->randomize) + BLI_array_randomize(edgeMap, sizeof(*edgeMap), + maxEdges, bmd->seed); + + /* get the set of all vert indices that will be in the final mesh, + * mapped to the new indices + */ + for(i = 0; i < numEdges; ++i) { + MEdge me; + dm->getEdge(dm, edgeMap[i], &me); + + if(!BLI_ghash_haskey(vertHash, (void *)me.v1)) + BLI_ghash_insert(vertHash, (void *)me.v1, + (void *)BLI_ghash_size(vertHash)); + if(!BLI_ghash_haskey(vertHash, (void *)me.v2)) + BLI_ghash_insert(vertHash, (void *)me.v2, + (void *)BLI_ghash_size(vertHash)); + } + + /* get the set of edges that will be in the new mesh + */ + for(i = 0; i < numEdges; ++i) { + MEdge me; + dm->getEdge(dm, edgeMap[i], &me); + + BLI_ghash_insert(edgeHash, (void *)BLI_ghash_size(edgeHash), + (void *)edgeMap[i]); + } + } else { + int numVerts = dm->getNumVerts(dm) * frac; + + if(bmd->randomize) + BLI_array_randomize(vertMap, sizeof(*vertMap), + maxVerts, bmd->seed); + + /* get the set of all vert indices that will be in the final mesh, + * mapped to the new indices + */ + for(i = 0; i < numVerts; ++i) + BLI_ghash_insert(vertHash, (void *)vertMap[i], (void *)i); + } + + /* now we know the number of verts, edges and faces, we can create + * the mesh + */ + result = CDDM_from_template(dm, BLI_ghash_size(vertHash), + BLI_ghash_size(edgeHash), numFaces); + + /* copy the vertices across */ + for(hashIter = BLI_ghashIterator_new(vertHash); + !BLI_ghashIterator_isDone(hashIter); + BLI_ghashIterator_step(hashIter)) { + MVert source; + MVert *dest; + int oldIndex = (int)BLI_ghashIterator_getKey(hashIter); + int newIndex = (int)BLI_ghashIterator_getValue(hashIter); + + dm->getVert(dm, oldIndex, &source); + dest = CDDM_get_vert(result, newIndex); + + DM_copy_vert_data(dm, result, oldIndex, newIndex, 1); + *dest = source; + } + BLI_ghashIterator_free(hashIter); + + /* copy the edges across, remapping indices */ + for(i = 0; i < BLI_ghash_size(edgeHash); ++i) { + MEdge source; + MEdge *dest; + int oldIndex = (int)BLI_ghash_lookup(edgeHash, (void *)i); + + dm->getEdge(dm, oldIndex, &source); + dest = CDDM_get_edge(result, i); + + source.v1 = (int)BLI_ghash_lookup(vertHash, (void *)source.v1); + source.v2 = (int)BLI_ghash_lookup(vertHash, (void *)source.v2); + + DM_copy_edge_data(dm, result, oldIndex, i, 1); + *dest = source; + } + + /* copy the faces across, remapping indices */ + for(i = 0; i < numFaces; ++i) { + MFace source; + MFace *dest; + int orig_v4; + + dm->getFace(dm, faceMap[i], &source); + dest = CDDM_get_face(result, i); + + orig_v4 = source.v4; + + source.v1 = (int)BLI_ghash_lookup(vertHash, (void *)source.v1); + source.v2 = (int)BLI_ghash_lookup(vertHash, (void *)source.v2); + source.v3 = (int)BLI_ghash_lookup(vertHash, (void *)source.v3); + if(source.v4) + source.v4 = (int)BLI_ghash_lookup(vertHash, (void *)source.v4); + + DM_copy_face_data(dm, result, faceMap[i], i, 1); + *dest = source; + + test_index_face(dest, &result->faceData, i, (orig_v4 ? 4 : 3)); + } + + CDDM_calc_normals(result); + + BLI_ghash_free(vertHash, NULL, NULL); + BLI_ghash_free(edgeHash, NULL, NULL); + + MEM_freeN(vertMap); + MEM_freeN(edgeMap); + MEM_freeN(faceMap); + + return result; +} + +/* Array */ +/* Array modifier: duplicates the object multiple times along an axis +*/ + +static void arrayModifier_initData(ModifierData *md) +{ + ArrayModifierData *amd = (ArrayModifierData*) md; + + /* default to 2 duplicates distributed along the x-axis by an + offset of 1 object-width + */ + amd->start_cap = amd->end_cap = amd->curve_ob = amd->offset_ob = NULL; + amd->count = 2; + amd->offset[0] = amd->offset[1] = amd->offset[2] = 0; + amd->scale[0] = 1; + amd->scale[1] = amd->scale[2] = 0; + amd->length = 0; + amd->merge_dist = 0.01; + amd->fit_type = MOD_ARR_FIXEDCOUNT; + amd->offset_type = MOD_ARR_OFF_RELATIVE; + amd->flags = 0; +} + +static void arrayModifier_copyData(ModifierData *md, ModifierData *target) +{ + ArrayModifierData *amd = (ArrayModifierData*) md; + ArrayModifierData *tamd = (ArrayModifierData*) target; + + tamd->start_cap = amd->start_cap; + tamd->end_cap = amd->end_cap; + tamd->curve_ob = amd->curve_ob; + tamd->offset_ob = amd->offset_ob; + tamd->count = amd->count; + VECCOPY(tamd->offset, amd->offset); + VECCOPY(tamd->scale, amd->scale); + tamd->length = amd->length; + tamd->merge_dist = amd->merge_dist; + tamd->fit_type = amd->fit_type; + tamd->offset_type = amd->offset_type; + tamd->flags = amd->flags; +} + +static void arrayModifier_foreachObjectLink( + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) +{ + ArrayModifierData *amd = (ArrayModifierData*) md; + + walk(userData, ob, &amd->start_cap); + walk(userData, ob, &amd->end_cap); + walk(userData, ob, &amd->curve_ob); + walk(userData, ob, &amd->offset_ob); +} + +static void arrayModifier_updateDepgraph(ModifierData *md, DagForest *forest, + Object *ob, DagNode *obNode) +{ + ArrayModifierData *amd = (ArrayModifierData*) md; + + if (amd->start_cap) { + DagNode *curNode = dag_get_node(forest, amd->start_cap); + + dag_add_relation(forest, curNode, obNode, + DAG_RL_DATA_DATA | DAG_RL_OB_DATA); + } + if (amd->end_cap) { + DagNode *curNode = dag_get_node(forest, amd->end_cap); + + dag_add_relation(forest, curNode, obNode, + DAG_RL_DATA_DATA | DAG_RL_OB_DATA); + } + if (amd->curve_ob) { + DagNode *curNode = dag_get_node(forest, amd->curve_ob); + + dag_add_relation(forest, curNode, obNode, + DAG_RL_DATA_DATA | DAG_RL_OB_DATA); + } + if (amd->offset_ob) { + DagNode *curNode = dag_get_node(forest, amd->offset_ob); + + dag_add_relation(forest, curNode, obNode, + DAG_RL_DATA_DATA | DAG_RL_OB_DATA); + } +} + +float vertarray_size(MVert *mvert, int numVerts, int axis) +{ + int i; + float min_co, max_co; + + /* if there are no vertices, width is 0 */ + if(numVerts == 0) return 0; + + /* find the minimum and maximum coordinates on the desired axis */ + min_co = max_co = mvert->co[axis]; + ++mvert; + for(i = 1; i < numVerts; ++i, ++mvert) { + if(mvert->co[axis] < min_co) min_co = mvert->co[axis]; + if(mvert->co[axis] > max_co) max_co = mvert->co[axis]; + } + + return max_co - min_co; +} + +typedef struct IndexMapEntry { + /* the new vert index that this old vert index maps to */ + int new; + /* -1 if this vert isn't merged, otherwise the old vert index it + * should be replaced with + */ + int merge; + /* 1 if this vert's first copy is merged with the last copy of its + * merge target, otherwise 0 + */ + short merge_final; +} IndexMapEntry; + +/* indexMap - an array of IndexMap entries + * oldIndex - the old index to map + * copyNum - the copy number to map to (original = 0, first copy = 1, etc.) + */ +static int calc_mapping(IndexMapEntry *indexMap, int oldIndex, int copyNum) +{ + if(indexMap[oldIndex].merge < 0) { + /* vert wasn't merged, so use copy of this vert */ + return indexMap[oldIndex].new + copyNum; + } else if(indexMap[oldIndex].merge == oldIndex) { + /* vert was merged with itself */ + return indexMap[oldIndex].new; + } else { + /* vert was merged with another vert */ + /* follow the chain of merges to the end, or until we've passed + * a number of vertices equal to the copy number + */ + if(copyNum <= 0) + return indexMap[oldIndex].new; + else + return calc_mapping(indexMap, indexMap[oldIndex].merge, + copyNum - 1); + } +} + +static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, + Object *ob, DerivedMesh *dm, + int initFlags) +{ + int i, j; + /* offset matrix */ + float offset[4][4]; + float final_offset[4][4]; + float tmp_mat[4][4]; + float length = amd->length; + int count = amd->count; + int numVerts, numEdges, numFaces; + int maxVerts, maxEdges, maxFaces; + int finalVerts, finalEdges, finalFaces; + DerivedMesh *result, *start_cap = NULL, *end_cap = NULL; + MVert *mvert, *src_mvert; + MEdge *medge; + MFace *mface; + + IndexMapEntry *indexMap; + + EdgeHash *edges; + + /* need to avoid infinite recursion here */ + if(amd->start_cap && amd->start_cap != ob) + start_cap = mesh_get_derived_final(amd->start_cap, CD_MASK_MESH); + if(amd->end_cap && amd->end_cap != ob) + end_cap = mesh_get_derived_final(amd->end_cap, CD_MASK_MESH); + + MTC_Mat4One(offset); + + indexMap = MEM_callocN(sizeof(*indexMap) * dm->getNumVerts(dm), + "indexmap"); + + src_mvert = dm->getVertArray(dm); + + maxVerts = dm->getNumVerts(dm); + + if(amd->offset_type & MOD_ARR_OFF_CONST) + VecAddf(offset[3], offset[3], amd->offset); + if(amd->offset_type & MOD_ARR_OFF_RELATIVE) { + for(j = 0; j < 3; j++) + offset[3][j] += amd->scale[j] * vertarray_size(src_mvert, + maxVerts, j); + } + + if((amd->offset_type & MOD_ARR_OFF_OBJ) && (amd->offset_ob)) { + float obinv[4][4]; + float result_mat[4][4]; + + if(ob) + MTC_Mat4Invert(obinv, ob->obmat); + else + MTC_Mat4One(obinv); + + MTC_Mat4MulSerie(result_mat, offset, + obinv, amd->offset_ob->obmat, + NULL, NULL, NULL, NULL, NULL); + MTC_Mat4CpyMat4(offset, result_mat); + } + + if(amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob) { + Curve *cu = amd->curve_ob->data; + if(cu) { + if(!cu->path) { + cu->flag |= CU_PATH; // needed for path & bevlist + makeDispListCurveTypes(amd->curve_ob, 0); + } + if(cu->path) + length = cu->path->totdist; + } + } + + /* calculate the maximum number of copies which will fit within the + prescribed length */ + if(amd->fit_type == MOD_ARR_FITLENGTH + || amd->fit_type == MOD_ARR_FITCURVE) { + float dist = sqrt(MTC_dot3Float(offset[3], offset[3])); + + if(dist > FLT_EPSILON) + /* this gives length = first copy start to last copy end + add a tiny offset for floating point rounding errors */ + count = (length + FLT_EPSILON) / dist; + else + /* if the offset has no translation, just make one copy */ + count = 1; + } + + if(count < 1) + count = 1; + + /* allocate memory for count duplicates (including original) plus + * start and end caps + */ + finalVerts = dm->getNumVerts(dm) * count; + finalEdges = dm->getNumEdges(dm) * count; + finalFaces = dm->getNumFaces(dm) * count; + if(start_cap) { + finalVerts += start_cap->getNumVerts(start_cap); + finalEdges += start_cap->getNumEdges(start_cap); + finalFaces += start_cap->getNumFaces(start_cap); + } + if(end_cap) { + finalVerts += end_cap->getNumVerts(end_cap); + finalEdges += end_cap->getNumEdges(end_cap); + finalFaces += end_cap->getNumFaces(end_cap); + } + result = CDDM_from_template(dm, finalVerts, finalEdges, finalFaces); + + /* calculate the offset matrix of the final copy (for merging) */ + MTC_Mat4One(final_offset); + + for(j=0; j < count - 1; j++) { + MTC_Mat4MulMat4(tmp_mat, final_offset, offset); + MTC_Mat4CpyMat4(final_offset, tmp_mat); + } + + numVerts = numEdges = numFaces = 0; + mvert = CDDM_get_verts(result); + + for (i = 0; i < maxVerts; i++) { + MVert *inMV; + MVert *mv = &mvert[numVerts]; + MVert *mv2; + float co[3]; + + inMV = &src_mvert[i]; + + DM_copy_vert_data(dm, result, i, numVerts, 1); + *mv = *inMV; + numVerts++; + + indexMap[i].new = numVerts - 1; + indexMap[i].merge = -1; /* default to no merge */ + indexMap[i].merge_final = 0; /* default to no merge */ + + VECCOPY(co, mv->co); + + /* Attempts to merge verts from one duplicate with verts from the + * next duplicate which are closer than amd->merge_dist. + * Only the first such vert pair is merged. + * If verts are merged in the first duplicate pair, they are merged + * in all pairs. + */ + if((count > 1) && (amd->flags & MOD_ARR_MERGE)) { + float tmp_co[3]; + VECCOPY(tmp_co, mv->co); + MTC_Mat4MulVecfl(offset, tmp_co); + + for(j = 0; j < maxVerts; j++) { + inMV = &src_mvert[j]; + /* if this vert is within merge limit, merge */ + if(VecLenCompare(tmp_co, inMV->co, amd->merge_dist)) { + indexMap[i].merge = j; + + /* test for merging with final copy of merge target */ + if(amd->flags & MOD_ARR_MERGEFINAL) { + VECCOPY(tmp_co, inMV->co); + inMV = &src_mvert[i]; + MTC_Mat4MulVecfl(final_offset, tmp_co); + if(VecLenCompare(tmp_co, inMV->co, amd->merge_dist)) + indexMap[i].merge_final = 1; + } + break; + } + } + } + + /* if no merging, generate copies of this vert */ + if(indexMap[i].merge < 0) { + for(j=0; j < count - 1; j++) { + mv2 = &mvert[numVerts]; + + DM_copy_vert_data(result, result, numVerts - 1, numVerts, 1); + *mv2 = *mv; + numVerts++; + + MTC_Mat4MulVecfl(offset, co); + VECCOPY(mv2->co, co); + } + } else if(indexMap[i].merge != i && indexMap[i].merge_final) { + /* if this vert is not merging with itself, and it is merging + * with the final copy of its merge target, remove the first copy + */ + numVerts--; + DM_free_vert_data(result, numVerts, 1); + } + } + + /* make a hashtable so we can avoid duplicate edges from merging */ + edges = BLI_edgehash_new(); + + maxEdges = dm->getNumEdges(dm); + medge = CDDM_get_edges(result); + for(i = 0; i < maxEdges; i++) { + MEdge inMED; + MEdge med; + MEdge *med2; + int vert1, vert2; + + dm->getEdge(dm, i, &inMED); + + med = inMED; + med.v1 = indexMap[inMED.v1].new; + med.v2 = indexMap[inMED.v2].new; + + /* if vertices are to be merged with the final copies of their + * merge targets, calculate that final copy + */ + if(indexMap[inMED.v1].merge_final) { + med.v1 = calc_mapping(indexMap, indexMap[inMED.v1].merge, + count - 1); + } + if(indexMap[inMED.v2].merge_final) { + med.v2 = calc_mapping(indexMap, indexMap[inMED.v2].merge, + count - 1); + } + + if (initFlags) { + med.flag |= ME_EDGEDRAW | ME_EDGERENDER; + } + + if(!BLI_edgehash_haskey(edges, med.v1, med.v2)) { + DM_copy_edge_data(dm, result, i, numEdges, 1); + medge[numEdges] = med; + numEdges++; + + BLI_edgehash_insert(edges, med.v1, med.v2, NULL); + } + + for(j = 1; j < count; j++) + { + vert1 = calc_mapping(indexMap, inMED.v1, j); + vert2 = calc_mapping(indexMap, inMED.v2, j); + /* avoid duplicate edges */ + if(!BLI_edgehash_haskey(edges, vert1, vert2)) { + med2 = &medge[numEdges]; + + DM_copy_edge_data(dm, result, i, numEdges, 1); + *med2 = med; + numEdges++; + + med2->v1 = vert1; + med2->v2 = vert2; + + BLI_edgehash_insert(edges, med2->v1, med2->v2, NULL); + } + } + } + + maxFaces = dm->getNumFaces(dm); + mface = CDDM_get_faces(result); + for (i=0; i < maxFaces; i++) { + MFace inMF; + MFace *mf = &mface[numFaces]; + + dm->getFace(dm, i, &inMF); + + DM_copy_face_data(dm, result, i, numFaces, 1); + *mf = inMF; + + mf->v1 = indexMap[inMF.v1].new; + mf->v2 = indexMap[inMF.v2].new; + mf->v3 = indexMap[inMF.v3].new; + if(inMF.v4) + mf->v4 = indexMap[inMF.v4].new; + + /* if vertices are to be merged with the final copies of their + * merge targets, calculate that final copy + */ + if(indexMap[inMF.v1].merge_final) + mf->v1 = calc_mapping(indexMap, indexMap[inMF.v1].merge, count-1); + if(indexMap[inMF.v2].merge_final) + mf->v2 = calc_mapping(indexMap, indexMap[inMF.v2].merge, count-1); + if(indexMap[inMF.v3].merge_final) + mf->v3 = calc_mapping(indexMap, indexMap[inMF.v3].merge, count-1); + if(inMF.v4 && indexMap[inMF.v4].merge_final) + mf->v4 = calc_mapping(indexMap, indexMap[inMF.v4].merge, count-1); + + test_index_face(mf, &result->faceData, numFaces, inMF.v4?4:3); + numFaces++; + + /* if the face has fewer than 3 vertices, don't create it */ + if(mf->v3 == 0) { + numFaces--; + DM_free_face_data(result, numFaces, 1); + } + + for(j = 1; j < count; j++) + { + MFace *mf2 = &mface[numFaces]; + + DM_copy_face_data(dm, result, i, numFaces, 1); + *mf2 = *mf; + + mf2->v1 = calc_mapping(indexMap, inMF.v1, j); + mf2->v2 = calc_mapping(indexMap, inMF.v2, j); + mf2->v3 = calc_mapping(indexMap, inMF.v3, j); + if (inMF.v4) + mf2->v4 = calc_mapping(indexMap, inMF.v4, j); + + test_index_face(mf2, &result->faceData, numFaces, inMF.v4?4:3); + numFaces++; + + /* if the face has fewer than 3 vertices, don't create it */ + if(mf2->v3 == 0) { + numFaces--; + DM_free_face_data(result, numFaces, 1); + } + } + } + + /* add start and end caps */ + if(start_cap) { + float startoffset[4][4]; + MVert *cap_mvert; + MEdge *cap_medge; + MFace *cap_mface; + int *origindex; + int *vert_map; + int capVerts, capEdges, capFaces; + + capVerts = start_cap->getNumVerts(start_cap); + capEdges = start_cap->getNumEdges(start_cap); + capFaces = start_cap->getNumFaces(start_cap); + cap_mvert = start_cap->getVertArray(start_cap); + cap_medge = start_cap->getEdgeArray(start_cap); + cap_mface = start_cap->getFaceArray(start_cap); + + Mat4Invert(startoffset, offset); + + vert_map = MEM_callocN(sizeof(*vert_map) * capVerts, + "arrayModifier_doArray vert_map"); + + origindex = result->getVertDataArray(result, CD_ORIGINDEX); + for(i = 0; i < capVerts; i++) { + MVert *mv = &cap_mvert[i]; + short merged = 0; + + if(amd->flags & MOD_ARR_MERGE) { + float tmp_co[3]; + MVert *in_mv; + int j; + + VECCOPY(tmp_co, mv->co); + Mat4MulVecfl(startoffset, tmp_co); + + for(j = 0; j < maxVerts; j++) { + in_mv = &src_mvert[j]; + /* if this vert is within merge limit, merge */ + if(VecLenCompare(tmp_co, in_mv->co, amd->merge_dist)) { + vert_map[i] = calc_mapping(indexMap, j, 0); + merged = 1; + break; + } + } + } + + if(!merged) { + DM_copy_vert_data(start_cap, result, i, numVerts, 1); + mvert[numVerts] = *mv; + Mat4MulVecfl(startoffset, mvert[numVerts].co); + origindex[numVerts] = ORIGINDEX_NONE; + + vert_map[i] = numVerts; + + numVerts++; + } + } + origindex = result->getEdgeDataArray(result, CD_ORIGINDEX); + for(i = 0; i < capEdges; i++) { + int v1, v2; + + v1 = vert_map[cap_medge[i].v1]; + v2 = vert_map[cap_medge[i].v2]; + + if(!BLI_edgehash_haskey(edges, v1, v2)) { + DM_copy_edge_data(start_cap, result, i, numEdges, 1); + medge[numEdges] = cap_medge[i]; + medge[numEdges].v1 = v1; + medge[numEdges].v2 = v2; + origindex[numEdges] = ORIGINDEX_NONE; + + numEdges++; + } + } + origindex = result->getFaceDataArray(result, CD_ORIGINDEX); + for(i = 0; i < capFaces; i++) { + DM_copy_face_data(start_cap, result, i, numFaces, 1); + mface[numFaces] = cap_mface[i]; + mface[numFaces].v1 = vert_map[mface[numFaces].v1]; + mface[numFaces].v2 = vert_map[mface[numFaces].v2]; + mface[numFaces].v3 = vert_map[mface[numFaces].v3]; + if(mface[numFaces].v4) + mface[numFaces].v4 = vert_map[mface[numFaces].v4]; + origindex[numFaces] = ORIGINDEX_NONE; + + numFaces++; + } + + MEM_freeN(vert_map); + start_cap->release(start_cap); + } + + if(end_cap) { + float endoffset[4][4]; + MVert *cap_mvert; + MEdge *cap_medge; + MFace *cap_mface; + int *origindex; + int *vert_map; + int capVerts, capEdges, capFaces; + + capVerts = end_cap->getNumVerts(end_cap); + capEdges = end_cap->getNumEdges(end_cap); + capFaces = end_cap->getNumFaces(end_cap); + cap_mvert = end_cap->getVertArray(end_cap); + cap_medge = end_cap->getEdgeArray(end_cap); + cap_mface = end_cap->getFaceArray(end_cap); + + Mat4MulMat4(endoffset, final_offset, offset); + + vert_map = MEM_callocN(sizeof(*vert_map) * capVerts, + "arrayModifier_doArray vert_map"); + + origindex = result->getVertDataArray(result, CD_ORIGINDEX); + for(i = 0; i < capVerts; i++) { + MVert *mv = &cap_mvert[i]; + short merged = 0; + + if(amd->flags & MOD_ARR_MERGE) { + float tmp_co[3]; + MVert *in_mv; + int j; + + VECCOPY(tmp_co, mv->co); + Mat4MulVecfl(offset, tmp_co); + + for(j = 0; j < maxVerts; j++) { + in_mv = &src_mvert[j]; + /* if this vert is within merge limit, merge */ + if(VecLenCompare(tmp_co, in_mv->co, amd->merge_dist)) { + vert_map[i] = calc_mapping(indexMap, j, count - 1); + merged = 1; + break; + } + } + } + + if(!merged) { + DM_copy_vert_data(end_cap, result, i, numVerts, 1); + mvert[numVerts] = *mv; + Mat4MulVecfl(endoffset, mvert[numVerts].co); + origindex[numVerts] = ORIGINDEX_NONE; + + vert_map[i] = numVerts; + + numVerts++; + } + } + origindex = result->getEdgeDataArray(result, CD_ORIGINDEX); + for(i = 0; i < capEdges; i++) { + int v1, v2; + + v1 = vert_map[cap_medge[i].v1]; + v2 = vert_map[cap_medge[i].v2]; + + if(!BLI_edgehash_haskey(edges, v1, v2)) { + DM_copy_edge_data(end_cap, result, i, numEdges, 1); + medge[numEdges] = cap_medge[i]; + medge[numEdges].v1 = v1; + medge[numEdges].v2 = v2; + origindex[numEdges] = ORIGINDEX_NONE; + + numEdges++; + } + } + origindex = result->getFaceDataArray(result, CD_ORIGINDEX); + for(i = 0; i < capFaces; i++) { + DM_copy_face_data(end_cap, result, i, numFaces, 1); + mface[numFaces] = cap_mface[i]; + mface[numFaces].v1 = vert_map[mface[numFaces].v1]; + mface[numFaces].v2 = vert_map[mface[numFaces].v2]; + mface[numFaces].v3 = vert_map[mface[numFaces].v3]; + if(mface[numFaces].v4) + mface[numFaces].v4 = vert_map[mface[numFaces].v4]; + origindex[numFaces] = ORIGINDEX_NONE; + + numFaces++; + } + + MEM_freeN(vert_map); + end_cap->release(end_cap); + } + + BLI_edgehash_free(edges, NULL); + MEM_freeN(indexMap); + + CDDM_lower_num_verts(result, numVerts); + CDDM_lower_num_edges(result, numEdges); + CDDM_lower_num_faces(result, numFaces); + + return result; +} + +static DerivedMesh *arrayModifier_applyModifier( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) +{ + DerivedMesh *result; + ArrayModifierData *amd = (ArrayModifierData*) md; + + result = arrayModifier_doArray(amd, ob, derivedData, 0); + + CDDM_calc_normals(result); + + return result; +} + +static DerivedMesh *arrayModifier_applyModifierEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData) +{ + return arrayModifier_applyModifier(md, ob, derivedData, 0, 1); +} + +/* Mirror */ + +static void mirrorModifier_initData(ModifierData *md) +{ + MirrorModifierData *mmd = (MirrorModifierData*) md; + + mmd->flag |= MOD_MIR_AXIS_X; + mmd->tolerance = 0.001; +} + +static void mirrorModifier_copyData(ModifierData *md, ModifierData *target) +{ + MirrorModifierData *mmd = (MirrorModifierData*) md; + MirrorModifierData *tmmd = (MirrorModifierData*) target; + + tmmd->axis = mmd->axis; + tmmd->flag = mmd->flag; + tmmd->tolerance = mmd->tolerance; +} + +static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, + DerivedMesh *dm, + int initFlags, + int axis) +{ + int i; + float tolerance = mmd->tolerance; + DerivedMesh *result; + int numVerts, numEdges, numFaces; + int maxVerts = dm->getNumVerts(dm); + int maxEdges = dm->getNumEdges(dm); + int maxFaces = dm->getNumFaces(dm); + int (*indexMap)[2]; + + numVerts = numEdges = numFaces = 0; + + indexMap = MEM_mallocN(sizeof(*indexMap) * maxVerts, "indexmap"); + + result = CDDM_from_template(dm, maxVerts * 2, maxEdges * 2, maxFaces * 2); + + for(i = 0; i < maxVerts; i++) { + MVert inMV; + MVert *mv = CDDM_get_vert(result, numVerts); + int isShared; + + dm->getVert(dm, i, &inMV); + isShared = ABS(inMV.co[axis])<=tolerance; + + /* Because the topology result (# of vertices) must be the same if + * the mesh data is overridden by vertex cos, have to calc sharedness + * based on original coordinates. This is why we test before copy. + */ + DM_copy_vert_data(dm, result, i, numVerts, 1); + *mv = inMV; + numVerts++; + + indexMap[i][0] = numVerts - 1; + indexMap[i][1] = !isShared; + + if(isShared) { + mv->co[axis] = 0; + mv->flag |= ME_VERT_MERGED; + } else { + MVert *mv2 = CDDM_get_vert(result, numVerts); + + DM_copy_vert_data(dm, result, i, numVerts, 1); + *mv2 = *mv; + numVerts++; + + mv2->co[axis] = -mv2->co[axis]; + } + } + + for(i = 0; i < maxEdges; i++) { + MEdge inMED; + MEdge *med = CDDM_get_edge(result, numEdges); + + dm->getEdge(dm, i, &inMED); + + DM_copy_edge_data(dm, result, i, numEdges, 1); + *med = inMED; + numEdges++; + + med->v1 = indexMap[inMED.v1][0]; + med->v2 = indexMap[inMED.v2][0]; + if(initFlags) + med->flag |= ME_EDGEDRAW | ME_EDGERENDER; + + if(indexMap[inMED.v1][1] || indexMap[inMED.v2][1]) { + MEdge *med2 = CDDM_get_edge(result, numEdges); + + DM_copy_edge_data(dm, result, i, numEdges, 1); + *med2 = *med; + numEdges++; + + med2->v1 += indexMap[inMED.v1][1]; + med2->v2 += indexMap[inMED.v2][1]; + } + } + + for(i = 0; i < maxFaces; i++) { + MFace inMF; + MFace *mf = CDDM_get_face(result, numFaces); + + dm->getFace(dm, i, &inMF); + + DM_copy_face_data(dm, result, i, numFaces, 1); + *mf = inMF; + numFaces++; + + mf->v1 = indexMap[inMF.v1][0]; + mf->v2 = indexMap[inMF.v2][0]; + mf->v3 = indexMap[inMF.v3][0]; + mf->v4 = indexMap[inMF.v4][0]; + + if(indexMap[inMF.v1][1] + || indexMap[inMF.v2][1] + || indexMap[inMF.v3][1] + || (mf->v4 && indexMap[inMF.v4][1])) { + MFace *mf2 = CDDM_get_face(result, numFaces); + static int corner_indices[4] = {2, 1, 0, 3}; + + DM_copy_face_data(dm, result, i, numFaces, 1); + *mf2 = *mf; + + mf2->v1 += indexMap[inMF.v1][1]; + mf2->v2 += indexMap[inMF.v2][1]; + mf2->v3 += indexMap[inMF.v3][1]; + if(inMF.v4) mf2->v4 += indexMap[inMF.v4][1]; + + /* mirror UVs if enabled */ + if(mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V)) { + MTFace *tf = result->getFaceData(result, numFaces, CD_MTFACE); + if(tf) { + int j; + for(j = 0; j < 4; ++j) { + if(mmd->flag & MOD_MIR_MIRROR_U) + tf->uv[j][0] = 1.0f - tf->uv[j][0]; + if(mmd->flag & MOD_MIR_MIRROR_V) + tf->uv[j][1] = 1.0f - tf->uv[j][1]; + } + } + } + + /* Flip face normal */ + SWAP(int, mf2->v1, mf2->v3); + DM_swap_face_data(result, numFaces, corner_indices); + + test_index_face(mf2, &result->faceData, numFaces, inMF.v4?4:3); + numFaces++; + } + } + + MEM_freeN(indexMap); + + CDDM_lower_num_verts(result, numVerts); + CDDM_lower_num_edges(result, numEdges); + CDDM_lower_num_faces(result, numFaces); + + return result; +} + +static DerivedMesh *mirrorModifier__doMirror(MirrorModifierData *mmd, + DerivedMesh *dm, + int initFlags) +{ + DerivedMesh *result = dm; + + /* check which axes have been toggled and mirror accordingly */ + if(mmd->flag & MOD_MIR_AXIS_X) { + result = doMirrorOnAxis(mmd, result, initFlags, 0); + } + if(mmd->flag & MOD_MIR_AXIS_Y) { + DerivedMesh *tmp = result; + result = doMirrorOnAxis(mmd, result, initFlags, 1); + if(tmp != dm) tmp->release(tmp); /* free intermediate results */ + } + if(mmd->flag & MOD_MIR_AXIS_Z) { + DerivedMesh *tmp = result; + result = doMirrorOnAxis(mmd, result, initFlags, 2); + if(tmp != dm) tmp->release(tmp); /* free intermediate results */ + } + + return result; +} + +static DerivedMesh *mirrorModifier_applyModifier( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) +{ + DerivedMesh *result; + MirrorModifierData *mmd = (MirrorModifierData*) md; + + result = mirrorModifier__doMirror(mmd, derivedData, 0); + + CDDM_calc_normals(result); + + return result; +} + +static DerivedMesh *mirrorModifier_applyModifierEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData) +{ + return mirrorModifier_applyModifier(md, ob, derivedData, 0, 1); +} + +/* EdgeSplit */ +/* EdgeSplit modifier: Splits edges in the mesh according to sharpness flag + * or edge angle (can be used to achieve autosmoothing) +*/ +#if 0 +#define EDGESPLIT_DEBUG_3 +#define EDGESPLIT_DEBUG_2 +#define EDGESPLIT_DEBUG_1 +#define EDGESPLIT_DEBUG_0 +#endif + +static void edgesplitModifier_initData(ModifierData *md) +{ + EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md; + + /* default to 30-degree split angle, sharpness from both angle & flag + */ + emd->split_angle = 30; + emd->flags = MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG; +} + +static void edgesplitModifier_copyData(ModifierData *md, ModifierData *target) +{ + EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md; + EdgeSplitModifierData *temd = (EdgeSplitModifierData*) target; + + temd->split_angle = emd->split_angle; + temd->flags = emd->flags; +} + +/* Mesh data for edgesplit operation */ +typedef struct SmoothVert { + LinkNode *faces; /* all faces which use this vert */ + int oldIndex; /* the index of the original DerivedMesh vert */ + int newIndex; /* the index of the new DerivedMesh vert */ +} SmoothVert; + +#define SMOOTHEDGE_NUM_VERTS 2 + +typedef struct SmoothEdge { + SmoothVert *verts[SMOOTHEDGE_NUM_VERTS]; /* the verts used by this edge */ + LinkNode *faces; /* all faces which use this edge */ + int oldIndex; /* the index of the original DerivedMesh edge */ + int newIndex; /* the index of the new DerivedMesh edge */ + short flag; /* the flags from the original DerivedMesh edge */ +} SmoothEdge; + +#define SMOOTHFACE_MAX_EDGES 4 + +typedef struct SmoothFace { + SmoothEdge *edges[SMOOTHFACE_MAX_EDGES]; /* nonexistent edges == NULL */ + int flip[SMOOTHFACE_MAX_EDGES]; /* 1 = flip edge dir, 0 = don't flip */ + float normal[3]; /* the normal of this face */ + int oldIndex; /* the index of the original DerivedMesh face */ + int newIndex; /* the index of the new DerivedMesh face */ +} SmoothFace; + +typedef struct SmoothMesh { + SmoothVert *verts; + SmoothEdge *edges; + SmoothFace *faces; + int num_verts, num_edges, num_faces; + int max_verts, max_edges, max_faces; + DerivedMesh *dm; + float threshold; /* the cosine of the smoothing angle */ + int flags; +} SmoothMesh; + +static SmoothVert *smoothvert_copy(SmoothVert *vert, SmoothMesh *mesh) +{ + SmoothVert *copy = &mesh->verts[mesh->num_verts]; + + if(mesh->num_verts >= mesh->max_verts) { + printf("Attempted to add a SmoothMesh vert beyond end of array\n"); + return NULL; + } + + *copy = *vert; + copy->faces = NULL; + copy->newIndex = mesh->num_verts; + ++mesh->num_verts; + +#ifdef EDGESPLIT_DEBUG_2 + printf("copied vert %4d to vert %4d\n", vert->newIndex, copy->newIndex); +#endif + return copy; +} + +static SmoothEdge *smoothedge_copy(SmoothEdge *edge, SmoothMesh *mesh) +{ + SmoothEdge *copy = &mesh->edges[mesh->num_edges]; + + if(mesh->num_edges >= mesh->max_edges) { + printf("Attempted to add a SmoothMesh edge beyond end of array\n"); + return NULL; + } + + *copy = *edge; + copy->faces = NULL; + copy->newIndex = mesh->num_edges; + ++mesh->num_edges; + +#ifdef EDGESPLIT_DEBUG_2 + printf("copied edge %4d to edge %4d\n", edge->newIndex, copy->newIndex); +#endif + return copy; +} + +static int smoothedge_has_vert(SmoothEdge *edge, SmoothVert *vert) +{ + int i; + for(i = 0; i < SMOOTHEDGE_NUM_VERTS; i++) + if(edge->verts[i] == vert) return 1; + + return 0; +} + +static SmoothMesh *smoothmesh_new(int num_verts, int num_edges, int num_faces, + int max_verts, int max_edges, int max_faces) +{ + SmoothMesh *mesh = MEM_callocN(sizeof(*mesh), "smoothmesh"); + mesh->verts = MEM_callocN(sizeof(*mesh->verts) * max_verts, + "SmoothMesh.verts"); + mesh->edges = MEM_callocN(sizeof(*mesh->edges) * max_edges, + "SmoothMesh.edges"); + mesh->faces = MEM_callocN(sizeof(*mesh->faces) * max_faces, + "SmoothMesh.faces"); + + mesh->num_verts = num_verts; + mesh->num_edges = num_edges; + mesh->num_faces = num_faces; + + mesh->max_verts = max_verts; + mesh->max_edges = max_edges; + mesh->max_faces = max_faces; + + return mesh; +} + +static void smoothmesh_free(SmoothMesh *mesh) +{ + int i; + + for(i = 0; i < mesh->num_verts; ++i) + BLI_linklist_free(mesh->verts[i].faces, NULL); + + for(i = 0; i < mesh->num_edges; ++i) + BLI_linklist_free(mesh->edges[i].faces, NULL); + + MEM_freeN(mesh->verts); + MEM_freeN(mesh->edges); + MEM_freeN(mesh->faces); + MEM_freeN(mesh); +} + +static void smoothmesh_resize_verts(SmoothMesh *mesh, int max_verts) +{ + int i; + SmoothVert *tmp; + + if(max_verts <= mesh->max_verts) return; + + tmp = MEM_callocN(sizeof(*tmp) * max_verts, "SmoothMesh.verts"); + + memcpy(tmp, mesh->verts, sizeof(*tmp) * mesh->num_verts); + + /* remap vert pointers in edges */ + for(i = 0; i < mesh->num_edges; ++i) { + int j; + SmoothEdge *edge = &mesh->edges[i]; + + for(j = 0; j < SMOOTHEDGE_NUM_VERTS; ++j) + /* pointer arithmetic to get vert array index */ + edge->verts[j] = &tmp[edge->verts[j] - mesh->verts]; + } + + MEM_freeN(mesh->verts); + mesh->verts = tmp; + mesh->max_verts = max_verts; +} + +static void smoothmesh_resize_edges(SmoothMesh *mesh, int max_edges) +{ + int i; + SmoothEdge *tmp; + + if(max_edges <= mesh->max_edges) return; + + tmp = MEM_callocN(sizeof(*tmp) * max_edges, "SmoothMesh.edges"); + + memcpy(tmp, mesh->edges, sizeof(*tmp) * mesh->num_edges); + + /* remap edge pointers in faces */ + for(i = 0; i < mesh->num_faces; ++i) { + int j; + SmoothFace *face = &mesh->faces[i]; + + for(j = 0; j < SMOOTHFACE_MAX_EDGES; ++j) + if(face->edges[j]) + /* pointer arithmetic to get edge array index */ + face->edges[j] = &tmp[face->edges[j] - mesh->edges]; + } + + MEM_freeN(mesh->edges); + mesh->edges = tmp; + mesh->max_edges = max_edges; +} + +#ifdef EDGESPLIT_DEBUG_0 +static void smoothmesh_print(SmoothMesh *mesh) +{ + int i, j; + DerivedMesh *dm = mesh->dm; + + printf("--- SmoothMesh ---\n"); + printf("--- Vertices ---\n"); + for(i = 0; i < mesh->num_verts; i++) { + SmoothVert *vert = &mesh->verts[i]; + LinkNode *node; + MVert mv; + + dm->getVert(dm, vert->oldIndex, &mv); + + printf("%3d: ind={%3d, %3d}, pos={% 5.1f, % 5.1f, % 5.1f}", + i, vert->oldIndex, vert->newIndex, + mv.co[0], mv.co[1], mv.co[2]); + printf(", faces={"); + for(node = vert->faces; node != NULL; node = node->next) { + printf(" %d", ((SmoothFace *)node->link)->newIndex); + } + printf("}\n"); + } + + printf("\n--- Edges ---\n"); + for(i = 0; i < mesh->num_edges; i++) { + SmoothEdge *edge = &mesh->edges[i]; + LinkNode *node; + + printf("%4d: indices={%4d, %4d}, verts={%4d, %4d}", + i, + edge->oldIndex, edge->newIndex, + edge->verts[0]->newIndex, edge->verts[1]->newIndex); + if(edge->verts[0] == edge->verts[1]) printf(" <- DUPLICATE VERTEX"); + printf(", faces={"); + for(node = edge->faces; node != NULL; node = node->next) { + printf(" %d", ((SmoothFace *)node->link)->newIndex); + } + printf("}\n"); + } + + printf("\n--- Faces ---\n"); + for(i = 0; i < mesh->num_faces; i++) { + SmoothFace *face = &mesh->faces[i]; + + printf("%4d: indices={%4d, %4d}, edges={", i, + face->oldIndex, face->newIndex); + for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) { + if(face->flip[j]) + printf(" -%-2d", face->edges[j]->newIndex); + else + printf(" %-2d", face->edges[j]->newIndex); + } + printf("}, verts={"); + for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) { + printf(" %d", face->edges[j]->verts[face->flip[j]]->newIndex); + } + printf("}\n"); + } +} +#endif + +static SmoothMesh *smoothmesh_from_derivedmesh(DerivedMesh *dm) +{ + SmoothMesh *mesh; + EdgeHash *edges = BLI_edgehash_new(); + int i; + int totvert, totedge, totface; + + totvert = dm->getNumVerts(dm); + totedge = dm->getNumEdges(dm); + totface = dm->getNumFaces(dm); + + mesh = smoothmesh_new(totvert, totedge, totface, + totvert, totedge, totface); + + mesh->dm = dm; + + for(i = 0; i < totvert; i++) { + SmoothVert *vert = &mesh->verts[i]; + + vert->oldIndex = vert->newIndex = i; + } + + for(i = 0; i < totedge; i++) { + SmoothEdge *edge = &mesh->edges[i]; + MEdge med; + + dm->getEdge(dm, i, &med); + edge->verts[0] = &mesh->verts[med.v1]; + edge->verts[1] = &mesh->verts[med.v2]; + edge->oldIndex = edge->newIndex = i; + edge->flag = med.flag; + + BLI_edgehash_insert(edges, med.v1, med.v2, edge); + } + + for(i = 0; i < totface; i++) { + SmoothFace *face = &mesh->faces[i]; + MFace mf; + MVert v1, v2, v3; + int j; + + dm->getFace(dm, i, &mf); + + dm->getVert(dm, mf.v1, &v1); + dm->getVert(dm, mf.v2, &v2); + dm->getVert(dm, mf.v3, &v3); + face->edges[0] = BLI_edgehash_lookup(edges, mf.v1, mf.v2); + if(face->edges[0]->verts[1]->oldIndex == mf.v1) face->flip[0] = 1; + face->edges[1] = BLI_edgehash_lookup(edges, mf.v2, mf.v3); + if(face->edges[1]->verts[1]->oldIndex == mf.v2) face->flip[1] = 1; + if(mf.v4) { + MVert v4; + dm->getVert(dm, mf.v4, &v4); + face->edges[2] = BLI_edgehash_lookup(edges, mf.v3, mf.v4); + if(face->edges[2]->verts[1]->oldIndex == mf.v3) face->flip[2] = 1; + face->edges[3] = BLI_edgehash_lookup(edges, mf.v4, mf.v1); + if(face->edges[3]->verts[1]->oldIndex == mf.v4) face->flip[3] = 1; + CalcNormFloat4(v1.co, v2.co, v3.co, v4.co, face->normal); + } else { + face->edges[2] = BLI_edgehash_lookup(edges, mf.v3, mf.v1); + if(face->edges[2]->verts[1]->oldIndex == mf.v3) face->flip[2] = 1; + face->edges[3] = NULL; + CalcNormFloat(v1.co, v2.co, v3.co, face->normal); + } + + for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) { + SmoothEdge *edge = face->edges[j]; + BLI_linklist_prepend(&edge->faces, face); + BLI_linklist_prepend(&edge->verts[face->flip[j]]->faces, face); + } + + face->oldIndex = face->newIndex = i; + } + + BLI_edgehash_free(edges, NULL); + + return mesh; +} + +static DerivedMesh *CDDM_from_smoothmesh(SmoothMesh *mesh) +{ + DerivedMesh *result = CDDM_from_template(mesh->dm, + mesh->num_verts, + mesh->num_edges, + mesh->num_faces); + MVert *new_verts = CDDM_get_verts(result); + MEdge *new_edges = CDDM_get_edges(result); + MFace *new_faces = CDDM_get_faces(result); + int i; + + for(i = 0; i < mesh->num_verts; ++i) { + SmoothVert *vert = &mesh->verts[i]; + MVert *newMV = &new_verts[vert->newIndex]; + + DM_copy_vert_data(mesh->dm, result, + vert->oldIndex, vert->newIndex, 1); + mesh->dm->getVert(mesh->dm, vert->oldIndex, newMV); + } + + for(i = 0; i < mesh->num_edges; ++i) { + SmoothEdge *edge = &mesh->edges[i]; + MEdge *newME = &new_edges[edge->newIndex]; + + DM_copy_edge_data(mesh->dm, result, + edge->oldIndex, edge->newIndex, 1); + mesh->dm->getEdge(mesh->dm, edge->oldIndex, newME); + newME->v1 = edge->verts[0]->newIndex; + newME->v2 = edge->verts[1]->newIndex; + } + + for(i = 0; i < mesh->num_faces; ++i) { + SmoothFace *face = &mesh->faces[i]; + MFace *newMF = &new_faces[face->newIndex]; + + DM_copy_face_data(mesh->dm, result, + face->oldIndex, face->newIndex, 1); + mesh->dm->getFace(mesh->dm, face->oldIndex, newMF); + + newMF->v1 = face->edges[0]->verts[face->flip[0]]->newIndex; + newMF->v2 = face->edges[1]->verts[face->flip[1]]->newIndex; + newMF->v3 = face->edges[2]->verts[face->flip[2]]->newIndex; + + if(face->edges[3]) { + newMF->v4 = face->edges[3]->verts[face->flip[3]]->newIndex; + } else { + newMF->v4 = 0; + } + } + + return result; +} + +/* returns the other vert in the given edge + */ +static SmoothVert *other_vert(SmoothEdge *edge, SmoothVert *vert) +{ + if(edge->verts[0] == vert) return edge->verts[1]; + else return edge->verts[0]; +} + +/* returns the other edge in the given face that uses the given vert + * returns NULL if no other edge in the given face uses the given vert + * (this should never happen) + */ +static SmoothEdge *other_edge(SmoothFace *face, SmoothVert *vert, + SmoothEdge *edge) +{ + int i,j; + for(i = 0; i < SMOOTHFACE_MAX_EDGES && face->edges[i]; i++) { + SmoothEdge *tmp_edge = face->edges[i]; + if(tmp_edge == edge) continue; + + for(j = 0; j < SMOOTHEDGE_NUM_VERTS; j++) + if(tmp_edge->verts[j] == vert) return tmp_edge; + } + + /* if we get to here, something's wrong (there should always be 2 edges + * which use the same vert in a face) + */ + return NULL; +} + +/* returns a face attached to the given edge which is not the given face. + * returns NULL if no other faces use this edge. + */ +static SmoothFace *other_face(SmoothEdge *edge, SmoothFace *face) +{ + LinkNode *node; + + for(node = edge->faces; node != NULL; node = node->next) + if(node->link != face) return node->link; + + return NULL; +} + +#if 0 +/* copies source list to target, overwriting target (target is not freed) + * nodes in the copy will be in the same order as in source + */ +static void linklist_copy(LinkNode **target, LinkNode *source) +{ + LinkNode *node = NULL; + *target = NULL; + + for(; source; source = source->next) { + if(node) { + node->next = MEM_mallocN(sizeof(*node->next), "nlink_copy"); + node = node->next; + } else { + node = *target = MEM_mallocN(sizeof(**target), "nlink_copy"); + } + node->link = source->link; + node->next = NULL; + } +} +#endif + +/* appends source to target if it's not already in target */ +static void linklist_append_unique(LinkNode **target, void *source) +{ + LinkNode *node; + LinkNode *prev = NULL; + + /* check if source value is already in the list */ + for(node = *target; node; prev = node, node = node->next) + if(node->link == source) return; + + node = MEM_mallocN(sizeof(*node), "nlink"); + node->next = NULL; + node->link = source; + + if(prev) prev->next = node; + else *target = node; +} + +/* appends elements of source which aren't already in target to target */ +static void linklist_append_list_unique(LinkNode **target, LinkNode *source) +{ + for(; source; source = source->next) + linklist_append_unique(target, source->link); +} + +#if 0 /* this is no longer used, it should possibly be removed */ +/* prepends prepend to list - doesn't copy nodes, just joins the lists */ +static void linklist_prepend_linklist(LinkNode **list, LinkNode *prepend) +{ + if(prepend) { + LinkNode *node = prepend; + while(node->next) node = node->next; + + node->next = *list; + *list = prepend; + } +} +#endif + +/* returns 1 if the linked list contains the given pointer, 0 otherwise + */ +static int linklist_contains(LinkNode *list, void *ptr) +{ + LinkNode *node; + + for(node = list; node; node = node->next) + if(node->link == ptr) return 1; + + return 0; +} + +/* returns 1 if the first linked list is a subset of the second (comparing + * pointer values), 0 if not + */ +static int linklist_subset(LinkNode *list1, LinkNode *list2) +{ + for(; list1; list1 = list1->next) + if(!linklist_contains(list2, list1->link)) + return 0; + + return 1; +} + +#if 0 +/* empties the linked list + * frees pointers with freefunc if freefunc is not NULL + */ +static void linklist_empty(LinkNode **list, LinkNodeFreeFP freefunc) +{ + BLI_linklist_free(*list, freefunc); + *list = NULL; +} +#endif + +/* removes the first instance of value from the linked list + * frees the pointer with freefunc if freefunc is not NULL + */ +static void linklist_remove_first(LinkNode **list, void *value, + LinkNodeFreeFP freefunc) +{ + LinkNode *node = *list; + LinkNode *prev = NULL; + + while(node && node->link != value) { + prev = node; + node = node->next; + } + + if(node) { + if(prev) + prev->next = node->next; + else + *list = node->next; + + if(freefunc) + freefunc(node->link); + + MEM_freeN(node); + } +} + +/* removes all elements in source from target */ +static void linklist_remove_list(LinkNode **target, LinkNode *source, + LinkNodeFreeFP freefunc) +{ + for(; source; source = source->next) + linklist_remove_first(target, source->link, freefunc); +} + +#ifdef EDGESPLIT_DEBUG_0 +static void print_ptr(void *ptr) +{ + printf("%p\n", ptr); +} + +static void print_edge(void *ptr) +{ + SmoothEdge *edge = ptr; + printf(" %4d", edge->newIndex); +} + +static void print_face(void *ptr) +{ + SmoothFace *face = ptr; + printf(" %4d", face->newIndex); +} +#endif + +typedef struct ReplaceData { + void *find; + void *replace; +} ReplaceData; + +static void edge_replace_vert(void *ptr, void *userdata) +{ + SmoothEdge *edge = ptr; + SmoothVert *find = ((ReplaceData *)userdata)->find; + SmoothVert *replace = ((ReplaceData *)userdata)->replace; + int i; + +#ifdef EDGESPLIT_DEBUG_3 + printf("replacing vert %4d with %4d in edge %4d", + find->newIndex, replace->newIndex, edge->newIndex); + printf(": {%4d, %4d}", edge->verts[0]->newIndex, edge->verts[1]->newIndex); +#endif + + for(i = 0; i < SMOOTHEDGE_NUM_VERTS; i++) { + if(edge->verts[i] == find) { + linklist_append_list_unique(&replace->faces, edge->faces); + linklist_remove_list(&find->faces, edge->faces, NULL); + + edge->verts[i] = replace; + } + } + +#ifdef EDGESPLIT_DEBUG_3 + printf(" -> {%4d, %4d}\n", edge->verts[0]->newIndex, edge->verts[1]->newIndex); +#endif +} + +static void face_replace_vert(void *ptr, void *userdata) +{ + SmoothFace *face = ptr; + int i; + + for(i = 0; i < SMOOTHFACE_MAX_EDGES && face->edges[i]; i++) + edge_replace_vert(face->edges[i], userdata); +} + +static void face_replace_edge(void *ptr, void *userdata) +{ + SmoothFace *face = ptr; + SmoothEdge *find = ((ReplaceData *)userdata)->find; + SmoothEdge *replace = ((ReplaceData *)userdata)->replace; + int i; + +#ifdef EDGESPLIT_DEBUG_3 + printf("replacing edge %4d with %4d in face %4d", + find->newIndex, replace->newIndex, face->newIndex); + if(face->edges[3]) + printf(": {%2d %2d %2d %2d}", + face->edges[0]->newIndex, face->edges[1]->newIndex, + face->edges[2]->newIndex, face->edges[3]->newIndex); + else + printf(": {%2d %2d %2d}", + face->edges[0]->newIndex, face->edges[1]->newIndex, + face->edges[2]->newIndex); +#endif + + for(i = 0; i < SMOOTHFACE_MAX_EDGES && face->edges[i]; i++) { + if(face->edges[i] == find) { + linklist_remove_first(&face->edges[i]->faces, face, NULL); + BLI_linklist_prepend(&replace->faces, face); + face->edges[i] = replace; + } + } + +#ifdef EDGESPLIT_DEBUG_3 + if(face->edges[3]) + printf(" -> {%2d %2d %2d %2d}\n", + face->edges[0]->newIndex, face->edges[1]->newIndex, + face->edges[2]->newIndex, face->edges[3]->newIndex); + else + printf(" -> {%2d %2d %2d}\n", + face->edges[0]->newIndex, face->edges[1]->newIndex, + face->edges[2]->newIndex); +#endif +} + +static int edge_is_loose(SmoothEdge *edge) +{ + return !(edge->faces && edge->faces->next); +} + +static int edge_is_sharp(SmoothEdge *edge, int flags, + float threshold) +{ +#ifdef EDGESPLIT_DEBUG_1 + printf("edge %d: ", edge->newIndex); +#endif + if(edge->flag & ME_SHARP) { + /* edge can only be sharp if it has at least 2 faces */ + if(!edge_is_loose(edge)) { +#ifdef EDGESPLIT_DEBUG_1 + printf("sharp\n"); +#endif + return 1; + } else { + /* edge is loose, so it can't be sharp */ + edge->flag &= ~ME_SHARP; + } + } + +#ifdef EDGESPLIT_DEBUG_1 + printf("not sharp\n"); +#endif + return 0; +} + +/* finds another sharp edge which uses vert, by traversing faces around the + * vert until it does one of the following: + * - hits a loose edge (the edge is returned) + * - hits a sharp edge (the edge is returned) + * - returns to the start edge (NULL is returned) + */ +static SmoothEdge *find_other_sharp_edge(SmoothVert *vert, SmoothEdge *edge, + LinkNode **visited_faces, float threshold, int flags) +{ + SmoothFace *face = NULL; + SmoothEdge *edge2 = NULL; + /* holds the edges we've seen so we can avoid looping indefinitely */ + LinkNode *visited_edges = NULL; +#ifdef EDGESPLIT_DEBUG_1 + printf("=== START === find_other_sharp_edge(edge = %4d, vert = %4d)\n", + edge->newIndex, vert->newIndex); +#endif + + /* get a face on which to start */ + if(edge->faces) face = edge->faces->link; + else return NULL; + + /* record this edge as visited */ + BLI_linklist_prepend(&visited_edges, edge); + + /* get the next edge */ + edge2 = other_edge(face, vert, edge); + + /* record this face as visited */ + if(visited_faces) + BLI_linklist_prepend(visited_faces, face); + + /* search until we hit a loose edge or a sharp edge or an edge we've + * seen before + */ + while(face && !edge_is_sharp(edge2, flags, threshold) + && !linklist_contains(visited_edges, edge2)) { +#ifdef EDGESPLIT_DEBUG_3 + printf("current face %4d; current edge %4d\n", face->newIndex, + edge2->newIndex); +#endif + /* get the next face */ + face = other_face(edge2, face); + + /* if face == NULL, edge2 is a loose edge */ + if(face) { + /* record this face as visited */ + if(visited_faces) + BLI_linklist_prepend(visited_faces, face); + + /* record this edge as visited */ + BLI_linklist_prepend(&visited_edges, edge2); + + /* get the next edge */ + edge2 = other_edge(face, vert, edge2); +#ifdef EDGESPLIT_DEBUG_3 + printf("next face %4d; next edge %4d\n", + face->newIndex, edge2->newIndex); + } else { + printf("loose edge: %4d\n", edge2->newIndex); +#endif + } + } + + /* either we came back to the start edge or we found a sharp/loose edge */ + if(linklist_contains(visited_edges, edge2)) + /* we came back to the start edge */ + edge2 = NULL; + + BLI_linklist_free(visited_edges, NULL); + +#ifdef EDGESPLIT_DEBUG_1 + printf("=== END === find_other_sharp_edge(edge = %4d, vert = %4d), " + "returning edge %d\n", + edge->newIndex, vert->newIndex, edge2 ? edge2->newIndex : -1); +#endif + return edge2; +} + +static void split_single_vert(SmoothVert *vert, SmoothFace *face, + SmoothMesh *mesh) +{ + SmoothVert *copy_vert; + ReplaceData repdata; + + copy_vert = smoothvert_copy(vert, mesh); + + repdata.find = vert; + repdata.replace = copy_vert; + face_replace_vert(face, &repdata); +} + +static void split_edge(SmoothEdge *edge, SmoothVert *vert, SmoothMesh *mesh); + +static void propagate_split(SmoothEdge *edge, SmoothVert *vert, + SmoothMesh *mesh) +{ + SmoothEdge *edge2; + LinkNode *visited_faces = NULL; +#ifdef EDGESPLIT_DEBUG_1 + printf("=== START === propagate_split(edge = %4d, vert = %4d)\n", + edge->newIndex, vert->newIndex); +#endif + + edge2 = find_other_sharp_edge(vert, edge, &visited_faces, + mesh->threshold, mesh->flags); + + if(!edge2) { + /* didn't find a sharp or loose edge, so we've hit a dead end */ + } else if(!edge_is_loose(edge2)) { + /* edge2 is not loose, so it must be sharp */ + if(edge_is_loose(edge)) { + /* edge is loose, so we can split edge2 at this vert */ + split_edge(edge2, vert, mesh); + } else if(edge_is_sharp(edge, mesh->flags, mesh->threshold)) { + /* both edges are sharp, so we can split the pair at vert */ + split_edge(edge, vert, mesh); + } else { + /* edge is not sharp, so try to split edge2 at its other vert */ + split_edge(edge2, other_vert(edge2, vert), mesh); + } + } else { /* edge2 is loose */ + if(edge_is_loose(edge)) { + SmoothVert *vert2; + ReplaceData repdata; + + /* can't split edge, what should we do with vert? */ + if(linklist_subset(vert->faces, visited_faces)) { + /* vert has only one fan of faces attached; don't split it */ + } else { + /* vert has more than one fan of faces attached; split it */ + vert2 = smoothvert_copy(vert, mesh); + + /* replace vert with its copy in visited_faces */ + repdata.find = vert; + repdata.replace = vert2; + BLI_linklist_apply(visited_faces, face_replace_vert, &repdata); + } + } else { + /* edge is not loose, so it must be sharp; split it */ + split_edge(edge, vert, mesh); + } + } + + BLI_linklist_free(visited_faces, NULL); +#ifdef EDGESPLIT_DEBUG_1 + printf("=== END === propagate_split(edge = %4d, vert = %4d)\n", + edge->newIndex, vert->newIndex); +#endif +} + +static void split_edge(SmoothEdge *edge, SmoothVert *vert, SmoothMesh *mesh) +{ + SmoothEdge *edge2; + SmoothVert *vert2; + ReplaceData repdata; + /* the list of faces traversed while looking for a sharp edge */ + LinkNode *visited_faces = NULL; +#ifdef EDGESPLIT_DEBUG_1 + printf("=== START === split_edge(edge = %4d, vert = %4d)\n", + edge->newIndex, vert->newIndex); +#endif + + edge2 = find_other_sharp_edge(vert, edge, &visited_faces, + mesh->threshold, mesh->flags); + + if(!edge2) { + /* didn't find a sharp or loose edge, so try the other vert */ + vert2 = other_vert(edge, vert); + propagate_split(edge, vert2, mesh); + } else if(!edge_is_loose(edge2)) { + /* edge2 is not loose, so it must be sharp */ + SmoothEdge *copy_edge = smoothedge_copy(edge, mesh); + SmoothEdge *copy_edge2 = smoothedge_copy(edge2, mesh); + SmoothVert *vert2; + + /* replace edge with its copy in visited_faces */ + repdata.find = edge; + repdata.replace = copy_edge; + BLI_linklist_apply(visited_faces, face_replace_edge, &repdata); + + /* replace edge2 with its copy in visited_faces */ + repdata.find = edge2; + repdata.replace = copy_edge2; + BLI_linklist_apply(visited_faces, face_replace_edge, &repdata); + + vert2 = smoothvert_copy(vert, mesh); + + /* replace vert with its copy in visited_faces (must be done after + * edge replacement so edges have correct vertices) + */ + repdata.find = vert; + repdata.replace = vert2; + BLI_linklist_apply(visited_faces, face_replace_vert, &repdata); + + /* all copying and replacing is done; the mesh should be consistent. + * now propagate the split to the vertices at either end + */ + propagate_split(copy_edge, other_vert(copy_edge, vert2), mesh); + propagate_split(copy_edge2, other_vert(copy_edge2, vert2), mesh); + + if(smoothedge_has_vert(edge, vert)) + propagate_split(edge, vert, mesh); + } else { + /* edge2 is loose */ + SmoothEdge *copy_edge = smoothedge_copy(edge, mesh); + SmoothVert *vert2; + + /* replace edge with its copy in visited_faces */ + repdata.find = edge; + repdata.replace = copy_edge; + BLI_linklist_apply(visited_faces, face_replace_edge, &repdata); + + vert2 = smoothvert_copy(vert, mesh); + + /* replace vert with its copy in visited_faces (must be done after + * edge replacement so edges have correct vertices) + */ + repdata.find = vert; + repdata.replace = vert2; + BLI_linklist_apply(visited_faces, face_replace_vert, &repdata); + + /* copying and replacing is done; the mesh should be consistent. + * now propagate the split to the vertex at the other end + */ + propagate_split(copy_edge, other_vert(copy_edge, vert2), mesh); + + if(smoothedge_has_vert(edge, vert)) + propagate_split(edge, vert, mesh); + } + + BLI_linklist_free(visited_faces, NULL); +#ifdef EDGESPLIT_DEBUG_1 + printf("=== END === split_edge(edge = %4d, vert = %4d)\n", + edge->newIndex, vert->newIndex); +#endif +} + +static void tag_and_count_extra_edges(SmoothMesh *mesh, float split_angle, + int flags, int *extra_edges) +{ + /* if normal1 dot normal2 < threshold, angle is greater, so split */ + /* FIXME not sure if this always works */ + /* 0.00001 added for floating-point rounding */ + float threshold = cos((split_angle + 0.00001) * M_PI / 180.0); + int i; + + *extra_edges = 0; + + /* loop through edges, counting potential new ones */ + for(i = 0; i < mesh->num_edges; i++) { + SmoothEdge *edge = &mesh->edges[i]; + int sharp = 0; + + /* treat all non-manifold edges (3 or more faces) as sharp */ + if(edge->faces && edge->faces->next && edge->faces->next->next) { + LinkNode *node; + + /* this edge is sharp */ + sharp = 1; + + /* add an extra edge for every face beyond the first */ + *extra_edges += 2; + for(node = edge->faces->next->next->next; node; node = node->next) + (*extra_edges)++; + } else if((flags & (MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG)) + && !edge_is_loose(edge)) { + /* (the edge can only be sharp if we're checking angle or flag, + * and it has at least 2 faces) */ + + /* if we're checking the sharp flag and it's set, good */ + if((flags & MOD_EDGESPLIT_FROMFLAG) && (edge->flag & ME_SHARP)) { + /* this edge is sharp */ + sharp = 1; + + (*extra_edges)++; + } else if(flags & MOD_EDGESPLIT_FROMANGLE) { + /* we know the edge has 2 faces, so check the angle */ + SmoothFace *face1 = edge->faces->link; + SmoothFace *face2 = edge->faces->next->link; + float edge_angle_cos = MTC_dot3Float(face1->normal, + face2->normal); + + if(edge_angle_cos < threshold) { + /* this edge is sharp */ + sharp = 1; + + (*extra_edges)++; + } + } + } + + /* set/clear sharp flag appropriately */ + if(sharp) edge->flag |= ME_SHARP; + else edge->flag &= ~ME_SHARP; + } +} + +static void split_sharp_edges(SmoothMesh *mesh, float split_angle, int flags) +{ + int i; + /* if normal1 dot normal2 < threshold, angle is greater, so split */ + /* FIXME not sure if this always works */ + /* 0.00001 added for floating-point rounding */ + mesh->threshold = cos((split_angle + 0.00001) * M_PI / 180.0); + mesh->flags = flags; + + /* loop through edges, splitting sharp ones */ + /* can't use an iterator here, because we'll be adding edges */ + for(i = 0; i < mesh->num_edges; i++) { + SmoothEdge *edge = &mesh->edges[i]; + + if(edge_is_sharp(edge, flags, mesh->threshold)) + split_edge(edge, edge->verts[0], mesh); + } + +} + +static int count_bridge_verts(SmoothMesh *mesh) +{ + int i, j, count = 0; + + for(i = 0; i < mesh->num_faces; i++) { + SmoothFace *face = &mesh->faces[i]; + + for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) { + SmoothEdge *edge = face->edges[j]; + SmoothEdge *next_edge; + SmoothVert *vert = edge->verts[1 - face->flip[j]]; + int next = (j + 1) % SMOOTHFACE_MAX_EDGES; + + /* wrap next around if at last edge */ + if(!face->edges[next]) next = 0; + + next_edge = face->edges[next]; + + /* if there are other faces sharing this vertex but not + * these edges, the vertex will be split, so count it + */ + /* vert has to have at least one face (this one), so faces != 0 */ + if(!edge->faces->next && !next_edge->faces->next + && vert->faces->next) { + count++; + } + } + } + + /* each bridge vert will be counted once per face that uses it, + * so count is too high, but it's ok for now + */ + return count; +} + +static void split_bridge_verts(SmoothMesh *mesh) +{ + int i,j; + + for(i = 0; i < mesh->num_faces; i++) { + SmoothFace *face = &mesh->faces[i]; + + for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) { + SmoothEdge *edge = face->edges[j]; + SmoothEdge *next_edge; + SmoothVert *vert = edge->verts[1 - face->flip[j]]; + int next = (j + 1) % SMOOTHFACE_MAX_EDGES; + + /* wrap next around if at last edge */ + if(!face->edges[next]) next = 0; + + next_edge = face->edges[next]; + + /* if there are other faces sharing this vertex but not + * these edges, split the vertex + */ + /* vert has to have at least one face (this one), so faces != 0 */ + if(!edge->faces->next && !next_edge->faces->next + && vert->faces->next) + /* FIXME this needs to find all faces that share edges with + * this one and split off together + */ + split_single_vert(vert, face, mesh); + } + } +} + +static DerivedMesh *edgesplitModifier_do(EdgeSplitModifierData *emd, + Object *ob, DerivedMesh *dm) +{ + SmoothMesh *mesh; + DerivedMesh *result; + int max_verts, max_edges; + + if(!(emd->flags & (MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG))) + return dm; + + /* 1. make smoothmesh with initial number of elements */ + mesh = smoothmesh_from_derivedmesh(dm); + + /* 2. count max number of elements to add */ + tag_and_count_extra_edges(mesh, emd->split_angle, emd->flags, &max_edges); + max_verts = max_edges * 2 + mesh->max_verts; + max_verts += count_bridge_verts(mesh); + max_edges += mesh->max_edges; + + /* 3. reallocate smoothmesh arrays & copy elements across */ + /* 4. remap copied elements' pointers to point into the new arrays */ + smoothmesh_resize_verts(mesh, max_verts); + smoothmesh_resize_edges(mesh, max_edges); + +#ifdef EDGESPLIT_DEBUG_1 + printf("********** Pre-split **********\n"); + smoothmesh_print(mesh); +#endif + + split_sharp_edges(mesh, emd->split_angle, emd->flags); +#ifdef EDGESPLIT_DEBUG_1 + printf("********** Post-edge-split **********\n"); + smoothmesh_print(mesh); +#endif + + split_bridge_verts(mesh); + +#ifdef EDGESPLIT_DEBUG_1 + printf("********** Post-vert-split **********\n"); + smoothmesh_print(mesh); +#endif + +#ifdef EDGESPLIT_DEBUG_0 + printf("Edgesplit: Estimated %d verts & %d edges, " + "found %d verts & %d edges\n", max_verts, max_edges, + mesh->num_verts, mesh->num_edges); +#endif + + result = CDDM_from_smoothmesh(mesh); + smoothmesh_free(mesh); + + return result; +} + +static DerivedMesh *edgesplitModifier_applyModifier( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) +{ + DerivedMesh *result; + EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md; + + result = edgesplitModifier_do(emd, ob, derivedData); + + CDDM_calc_normals(result); + + return result; +} + +static DerivedMesh *edgesplitModifier_applyModifierEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData) +{ + return edgesplitModifier_applyModifier(md, ob, derivedData, 0, 1); +} + +/* Displace */ + +static void displaceModifier_initData(ModifierData *md) +{ + DisplaceModifierData *dmd = (DisplaceModifierData*) md; + + dmd->texture = NULL; + dmd->strength = 1; + dmd->direction = MOD_DISP_DIR_NOR; + dmd->midlevel = 0.5; +} + +static void displaceModifier_copyData(ModifierData *md, ModifierData *target) +{ + DisplaceModifierData *dmd = (DisplaceModifierData*) md; + DisplaceModifierData *tdmd = (DisplaceModifierData*) target; + + tdmd->texture = dmd->texture; + tdmd->strength = dmd->strength; + tdmd->direction = dmd->direction; + strncpy(tdmd->defgrp_name, dmd->defgrp_name, 32); + tdmd->midlevel = dmd->midlevel; + tdmd->texmapping = dmd->texmapping; + tdmd->map_object = dmd->map_object; + strncpy(tdmd->uvlayer_name, dmd->uvlayer_name, 32); +} + +CustomDataMask displaceModifier_requiredDataMask(ModifierData *md) +{ + DisplaceModifierData *dmd = (DisplaceModifierData *)md; + CustomDataMask dataMask = 0; + + /* ask for vertexgroups if we need them */ + if(dmd->defgrp_name[0]) dataMask |= (1 << CD_MDEFORMVERT); + + /* ask for UV coordinates if we need them */ + if(dmd->texmapping == MOD_DISP_MAP_UV) dataMask |= (1 << CD_MTFACE); + + return dataMask; +} + +static void displaceModifier_foreachObjectLink(ModifierData *md, Object *ob, + ObjectWalkFunc walk, void *userData) +{ + DisplaceModifierData *dmd = (DisplaceModifierData*) md; + + walk(userData, ob, &dmd->map_object); +} + +static void displaceModifier_foreachIDLink(ModifierData *md, Object *ob, + IDWalkFunc walk, void *userData) +{ + DisplaceModifierData *dmd = (DisplaceModifierData*) md; + + walk(userData, ob, (ID **)&dmd->texture); + + displaceModifier_foreachObjectLink(md, ob, (ObjectWalkFunc) walk, userData); +} + +static int displaceModifier_isDisabled(ModifierData *md) +{ + DisplaceModifierData *dmd = (DisplaceModifierData*) md; + + return !dmd->texture; +} + +static void displaceModifier_updateDepgraph( + ModifierData *md, DagForest *forest, + Object *ob, DagNode *obNode) +{ + DisplaceModifierData *dmd = (DisplaceModifierData*) md; + + if(dmd->map_object) { + DagNode *curNode = dag_get_node(forest, dmd->map_object); + + dag_add_relation(forest, curNode, obNode, + DAG_RL_DATA_DATA | DAG_RL_OB_DATA); + } +} + +static void validate_layer_name(const CustomData *data, int type, char *name) +{ + int index = -1; + + /* if a layer name was given, try to find that layer */ + if(name[0]) + index = CustomData_get_named_layer_index(data, CD_MTFACE, name); + + if(index < 0) { + /* either no layer was specified, or the layer we want has been + * deleted, so assign the active layer to name + */ + index = CustomData_get_active_layer_index(data, CD_MTFACE); + strcpy(name, data->layers[index].name); + } +} + +static void get_texture_coords(DisplaceModifierData *dmd, Object *ob, + DerivedMesh *dm, + float (*co)[3], float (*texco)[3], + int numVerts) +{ + int i; + int texmapping = dmd->texmapping; + + if(texmapping == MOD_DISP_MAP_OBJECT) { + if(dmd->map_object) + Mat4Invert(dmd->map_object->imat, dmd->map_object->obmat); + else /* if there is no map object, default to local */ + texmapping = MOD_DISP_MAP_LOCAL; + } + + /* UVs need special handling, since they come from faces */ + if(texmapping == MOD_DISP_MAP_UV) { + if(dm->getFaceDataArray(dm, CD_MTFACE)) { + MFace *mface = dm->getFaceArray(dm); + MFace *mf; + char *done = MEM_callocN(sizeof(*done) * numVerts, + "get_texture_coords done"); + int numFaces = dm->getNumFaces(dm); + MTFace *tf; + + validate_layer_name(&dm->faceData, CD_MTFACE, dmd->uvlayer_name); + + tf = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, + dmd->uvlayer_name); + + /* verts are given the UV from the first face that uses them */ + for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tf) { + if(!done[mf->v1]) { + texco[mf->v1][0] = tf->uv[0][0]; + texco[mf->v1][1] = tf->uv[0][1]; + texco[mf->v1][2] = 0; + done[mf->v1] = 1; + } + if(!done[mf->v2]) { + texco[mf->v2][0] = tf->uv[1][0]; + texco[mf->v2][1] = tf->uv[1][1]; + texco[mf->v2][2] = 0; + done[mf->v2] = 1; + } + if(!done[mf->v3]) { + texco[mf->v3][0] = tf->uv[2][0]; + texco[mf->v3][1] = tf->uv[2][1]; + texco[mf->v3][2] = 0; + done[mf->v3] = 1; + } + if(!done[mf->v4]) { + texco[mf->v4][0] = tf->uv[3][0]; + texco[mf->v4][1] = tf->uv[3][1]; + texco[mf->v4][2] = 0; + done[mf->v4] = 1; + } + } + + /* remap UVs from [0, 1] to [-1, 1] */ + for(i = 0; i < numVerts; ++i) { + texco[i][0] = texco[i][0] * 2 - 1; + texco[i][1] = texco[i][1] * 2 - 1; + } + + MEM_freeN(done); + return; + } else /* if there are no UVs, default to local */ + texmapping = MOD_DISP_MAP_LOCAL; + } + + for(i = 0; i < numVerts; ++i, ++co, ++texco) { + switch(texmapping) { + case MOD_DISP_MAP_LOCAL: + VECCOPY(*texco, *co); + break; + case MOD_DISP_MAP_GLOBAL: + VECCOPY(*texco, *co); + Mat4MulVecfl(ob->obmat, *texco); + break; + case MOD_DISP_MAP_OBJECT: + VECCOPY(*texco, *co); + Mat4MulVecfl(ob->obmat, *texco); + Mat4MulVecfl(dmd->map_object->imat, *texco); + break; + } + } +} + +static void get_texture_value(Tex *texture, float *tex_co, TexResult *texres) +{ + int result_type; + + result_type = multitex_ext(texture, tex_co, NULL, + NULL, 1, texres); + + /* if the texture gave an RGB value, we assume it didn't give a valid + * intensity, so calculate one (formula from do_material_tex). + * if the texture didn't give an RGB value, copy the intensity across + */ + if(result_type & TEX_RGB) + texres->tin = (0.35 * texres->tr + 0.45 * texres->tg + + 0.2 * texres->tb); + else + texres->tr = texres->tg = texres->tb = texres->tin; +} + +/* dm must be a CDDerivedMesh */ +static void displaceModifier_do( + DisplaceModifierData *dmd, Object *ob, + DerivedMesh *dm, float (*vertexCos)[3], int numVerts) +{ + int i; + MVert *mvert; + MDeformVert *dvert = NULL; + int defgrp_index; + float (*tex_co)[3]; + + if(!dmd->texture) return; + + defgrp_index = -1; + + if(dmd->defgrp_name[0]) { + bDeformGroup *def; + for(i = 0, def = ob->defbase.first; def; def = def->next, i++) { + if(!strcmp(def->name, dmd->defgrp_name)) { + defgrp_index = i; + break; + } + } + } + + mvert = CDDM_get_verts(dm); + if(defgrp_index >= 0) + dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); + + tex_co = MEM_callocN(sizeof(*tex_co) * numVerts, + "displaceModifier_do tex_co"); + get_texture_coords(dmd, ob, dm, vertexCos, tex_co, numVerts); + + for(i = 0; i < numVerts; ++i) { + TexResult texres; + float delta = 0, strength = dmd->strength; + MDeformWeight *def_weight = NULL; + + if(dvert) { + int j; + for(j = 0; j < dvert[i].totweight; ++j) { + if(dvert[i].dw[j].def_nr == defgrp_index) { + def_weight = &dvert[i].dw[j]; + break; + } + } + if(!def_weight) continue; + } + + texres.nor = NULL; + get_texture_value(dmd->texture, tex_co[i], &texres); + + delta = texres.tin - dmd->midlevel; + + if(def_weight) strength *= def_weight->weight; + + delta *= strength; + + switch(dmd->direction) { + case MOD_DISP_DIR_X: + vertexCos[i][0] += delta; + break; + case MOD_DISP_DIR_Y: + vertexCos[i][1] += delta; + break; + case MOD_DISP_DIR_Z: + vertexCos[i][2] += delta; + break; + case MOD_DISP_DIR_RGB_XYZ: + vertexCos[i][0] += (texres.tr - dmd->midlevel) * strength; + vertexCos[i][1] += (texres.tg - dmd->midlevel) * strength; + vertexCos[i][2] += (texres.tb - dmd->midlevel) * strength; + break; + case MOD_DISP_DIR_NOR: + vertexCos[i][0] += delta * mvert[i].no[0] / 32767.0f; + vertexCos[i][1] += delta * mvert[i].no[1] / 32767.0f; + vertexCos[i][2] += delta * mvert[i].no[2] / 32767.0f; + break; + } + } + + MEM_freeN(tex_co); +} + +static void displaceModifier_deformVerts( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) +{ + DerivedMesh *dm; + + if(derivedData) dm = CDDM_copy(derivedData); + else if(ob->type==OB_MESH) dm = CDDM_from_mesh(ob->data, ob); + else return; + + CDDM_apply_vert_coords(dm, vertexCos); + CDDM_calc_normals(dm); + + displaceModifier_do((DisplaceModifierData *)md, ob, dm, + vertexCos, numVerts); + + dm->release(dm); +} + +static void displaceModifier_deformVertsEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) +{ + DerivedMesh *dm; + + if(derivedData) dm = CDDM_copy(derivedData); + else dm = CDDM_from_editmesh(editData, ob->data); + + CDDM_apply_vert_coords(dm, vertexCos); + CDDM_calc_normals(dm); + + displaceModifier_do((DisplaceModifierData *)md, ob, dm, + vertexCos, numVerts); + + dm->release(dm); +} + +/* UVProject */ +/* UV Project modifier: Generates UVs projected from an object +*/ + +static void uvprojectModifier_initData(ModifierData *md) +{ + UVProjectModifierData *umd = (UVProjectModifierData*) md; + int i; + + for(i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i) + umd->projectors[i] = NULL; + umd->image = NULL; + umd->flags = 0; + umd->num_projectors = 1; + umd->aspectx = umd->aspecty = 1.0f; +} + +static void uvprojectModifier_copyData(ModifierData *md, ModifierData *target) +{ + UVProjectModifierData *umd = (UVProjectModifierData*) md; + UVProjectModifierData *tumd = (UVProjectModifierData*) target; + int i; + + for(i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i) + tumd->projectors[i] = umd->projectors[i]; + tumd->image = umd->image; + tumd->flags = umd->flags; + tumd->num_projectors = umd->num_projectors; + tumd->aspectx = umd->aspectx; + tumd->aspecty = umd->aspecty; +} + +CustomDataMask uvprojectModifier_requiredDataMask(ModifierData *md) +{ + CustomDataMask dataMask = 0; + + /* ask for UV coordinates */ + dataMask |= (1 << CD_MTFACE); + + return dataMask; +} + +static void uvprojectModifier_foreachObjectLink(ModifierData *md, Object *ob, + ObjectWalkFunc walk, void *userData) +{ + UVProjectModifierData *umd = (UVProjectModifierData*) md; + int i; + + for(i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i) + walk(userData, ob, &umd->projectors[i]); +} + +static void uvprojectModifier_foreachIDLink(ModifierData *md, Object *ob, + IDWalkFunc walk, void *userData) +{ + UVProjectModifierData *umd = (UVProjectModifierData*) md; + + walk(userData, ob, (ID **)&umd->image); + + uvprojectModifier_foreachObjectLink(md, ob, (ObjectWalkFunc)walk, + userData); +} + +static void uvprojectModifier_updateDepgraph(ModifierData *md, + DagForest *forest, Object *ob, DagNode *obNode) +{ + UVProjectModifierData *umd = (UVProjectModifierData*) md; + int i; + + for(i = 0; i < umd->num_projectors; ++i) { + if(umd->projectors[i]) { + DagNode *curNode = dag_get_node(forest, umd->projectors[i]); + + dag_add_relation(forest, curNode, obNode, + DAG_RL_DATA_DATA | DAG_RL_OB_DATA); + } + } +} + +typedef struct Projector { + Object *ob; /* object this projector is derived from */ + float projmat[4][4]; /* projection matrix */ + float normal[3]; /* projector normal in world space */ +} Projector; + +static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd, + Object *ob, DerivedMesh *dm) +{ + float (*coords)[3], (*co)[3]; + MTFace *tface; + int i, numVerts, numFaces; + Image *image = umd->image; + MFace *mface, *mf; + int override_image = ((umd->flags & MOD_UVPROJECT_OVERRIDEIMAGE) != 0); + Projector projectors[MOD_UVPROJECT_MAXPROJECTORS]; + int num_projectors = 0; + float aspect; + + if(umd->aspecty != 0) aspect = umd->aspectx / umd->aspecty; + else aspect = 1.0f; + + for(i = 0; i < umd->num_projectors; ++i) + if(umd->projectors[i]) + projectors[num_projectors++].ob = umd->projectors[i]; + + if(num_projectors == 0) return dm; + + /* make sure there are UV layers available */ + if(!dm->getFaceDataArray(dm, CD_MTFACE)) return dm; + + /* make sure we're using an existing layer */ + validate_layer_name(&dm->faceData, CD_MTFACE, umd->uvlayer_name); + + /* make sure we are not modifying the original UV layer */ + tface = CustomData_duplicate_referenced_layer_named(&dm->faceData, + CD_MTFACE, + umd->uvlayer_name); + + numVerts = dm->getNumVerts(dm); + + coords = MEM_callocN(sizeof(*coords) * numVerts, + "uvprojectModifier_do coords"); + dm->getVertCos(dm, coords); + + /* convert coords to world space */ + for(i = 0, co = coords; i < numVerts; ++i, ++co) + Mat4MulVecfl(ob->obmat, *co); + + /* calculate a projection matrix and normal for each projector */ + for(i = 0; i < num_projectors; ++i) { + float tmpmat[4][4]; + float offsetmat[4][4]; + + /* calculate projection matrix */ + Mat4Invert(projectors[i].projmat, projectors[i].ob->obmat); + + if(projectors[i].ob->type == OB_CAMERA) { + Camera *cam = (Camera *)projectors[i].ob->data; + if(cam->type == CAM_PERSP) { + float perspmat[4][4]; + float xmax; + float xmin; + float ymax; + float ymin; + float pixsize = cam->clipsta * 32.0 / cam->lens; + + if(aspect > 1.0f) { + xmax = 0.5f * pixsize; + ymax = xmax / aspect; + } else { + ymax = 0.5f * pixsize; + xmax = ymax * aspect; + } + xmin = -xmax; + ymin = -ymax; + + i_window(xmin, xmax, ymin, ymax, + cam->clipsta, cam->clipend, perspmat); + Mat4MulMat4(tmpmat, projectors[i].projmat, perspmat); + } else if(cam->type == CAM_ORTHO) { + float orthomat[4][4]; + float xmax; + float xmin; + float ymax; + float ymin; + + if(aspect > 1.0f) { + xmax = 0.5f * cam->ortho_scale; + ymax = xmax / aspect; + } else { + ymax = 0.5f * cam->ortho_scale; + xmax = ymax * aspect; + } + xmin = -xmax; + ymin = -ymax; + + i_ortho(xmin, xmax, ymin, ymax, + cam->clipsta, cam->clipend, orthomat); + Mat4MulMat4(tmpmat, projectors[i].projmat, orthomat); + } + } else { + Mat4CpyMat4(tmpmat, projectors[i].projmat); + } + + Mat4One(offsetmat); + Mat4MulFloat3(offsetmat[0], 0.5); + offsetmat[3][0] = offsetmat[3][1] = offsetmat[3][2] = 0.5; + Mat4MulMat4(projectors[i].projmat, tmpmat, offsetmat); + + /* calculate worldspace projector normal (for best projector test) */ + projectors[i].normal[0] = 0; + projectors[i].normal[1] = 0; + projectors[i].normal[2] = 1; + Mat4Mul3Vecfl(projectors[i].ob->obmat, projectors[i].normal); + } + + /* if only one projector, project coords to UVs */ + if(num_projectors == 1) + for(i = 0, co = coords; i < numVerts; ++i, ++co) + Mat4MulVec3Project(projectors[0].projmat, *co); + + mface = dm->getFaceArray(dm); + numFaces = dm->getNumFaces(dm); + + /* apply coords as UVs, and apply image if tfaces are new */ + for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tface) { + if(override_image || !image || tface->tpage == image) { + if(num_projectors == 1) { + /* apply transformed coords as UVs */ + tface->uv[0][0] = coords[mf->v1][0]; + tface->uv[0][1] = coords[mf->v1][1]; + tface->uv[1][0] = coords[mf->v2][0]; + tface->uv[1][1] = coords[mf->v2][1]; + tface->uv[2][0] = coords[mf->v3][0]; + tface->uv[2][1] = coords[mf->v3][1]; + if(mf->v4) { + tface->uv[3][0] = coords[mf->v4][0]; + tface->uv[3][1] = coords[mf->v4][1]; + } + } else { + /* multiple projectors, select the closest to face normal + * direction + */ + float co1[3], co2[3], co3[3], co4[3]; + float face_no[3]; + int j; + Projector *best_projector; + float best_dot; + + VECCOPY(co1, coords[mf->v1]); + VECCOPY(co2, coords[mf->v2]); + VECCOPY(co3, coords[mf->v3]); + + /* get the untransformed face normal */ + if(mf->v4) { + VECCOPY(co4, coords[mf->v4]); + CalcNormFloat4(co1, co2, co3, co4, face_no); + } else { + CalcNormFloat(co1, co2, co3, face_no); + } + + /* find the projector which the face points at most directly + * (projector normal with largest dot product is best) + */ + best_dot = MTC_dot3Float(projectors[0].normal, face_no); + best_projector = &projectors[0]; + + for(j = 1; j < num_projectors; ++j) { + float tmp_dot = MTC_dot3Float(projectors[j].normal, + face_no); + if(tmp_dot > best_dot) { + best_dot = tmp_dot; + best_projector = &projectors[j]; + } + } + + Mat4MulVec3Project(best_projector->projmat, co1); + Mat4MulVec3Project(best_projector->projmat, co2); + Mat4MulVec3Project(best_projector->projmat, co3); + if(mf->v4) + Mat4MulVec3Project(best_projector->projmat, co4); + + /* apply transformed coords as UVs */ + tface->uv[0][0] = co1[0]; + tface->uv[0][1] = co1[1]; + tface->uv[1][0] = co2[0]; + tface->uv[1][1] = co2[1]; + tface->uv[2][0] = co3[0]; + tface->uv[2][1] = co3[1]; + if(mf->v4) { + tface->uv[3][0] = co4[0]; + tface->uv[3][1] = co4[1]; + } + } + } + + if(override_image) { + tface->mode = TF_TEX; + tface->tpage = image; + } + } + + MEM_freeN(coords); + + return dm; +} + +static DerivedMesh *uvprojectModifier_applyModifier( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) +{ + DerivedMesh *result; + UVProjectModifierData *umd = (UVProjectModifierData*) md; + + result = uvprojectModifier_do(umd, ob, derivedData); + + return result; +} + +static DerivedMesh *uvprojectModifier_applyModifierEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData) +{ + return uvprojectModifier_applyModifier(md, ob, derivedData, 0, 1); +} + +/* Decimate */ + +static void decimateModifier_initData(ModifierData *md) +{ + DecimateModifierData *dmd = (DecimateModifierData*) md; + + dmd->percent = 1.0; +} + +static void decimateModifier_copyData(ModifierData *md, ModifierData *target) +{ + DecimateModifierData *dmd = (DecimateModifierData*) md; + DecimateModifierData *tdmd = (DecimateModifierData*) target; + + tdmd->percent = dmd->percent; +} + +static DerivedMesh *decimateModifier_applyModifier( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) +{ + DecimateModifierData *dmd = (DecimateModifierData*) md; + DerivedMesh *dm = derivedData, *result = NULL; + MVert *mvert; + MFace *mface; + LOD_Decimation_Info lod; + int totvert, totface; + int a, numTris; + + mvert = dm->getVertArray(dm); + mface = dm->getFaceArray(dm); + totvert = dm->getNumVerts(dm); + totface = dm->getNumFaces(dm); + + numTris = 0; + for (a=0; av4) numTris++; + } + + if(numTris<3) { + modifier_setError(md, + "There must be more than 3 input faces (triangles)."); + goto exit; + } + + lod.vertex_buffer= MEM_mallocN(3*sizeof(float)*totvert, "vertices"); + lod.vertex_normal_buffer= MEM_mallocN(3*sizeof(float)*totvert, "normals"); + lod.triangle_index_buffer= MEM_mallocN(3*sizeof(int)*numTris, "trias"); + lod.vertex_num= totvert; + lod.face_num= numTris; + + for(a=0; aco); + + vbNo[0] = mv->no[0]/32767.0f; + vbNo[1] = mv->no[1]/32767.0f; + vbNo[2] = mv->no[2]/32767.0f; + } + + numTris = 0; + for(a=0; av1; + tri[1]= mf->v2; + tri[2]= mf->v3; + + if(mf->v4) { + tri = &lod.triangle_index_buffer[3*numTris++]; + tri[0]= mf->v1; + tri[1]= mf->v3; + tri[2]= mf->v4; + } + } + + dmd->faceCount = 0; + if(LOD_LoadMesh(&lod) ) { + if( LOD_PreprocessMesh(&lod) ) { + /* we assume the decim_faces tells how much to reduce */ + + while(lod.face_num > numTris*dmd->percent) { + if( LOD_CollapseEdge(&lod)==0) break; + } + + if(lod.vertex_num>2) { + result = CDDM_new(lod.vertex_num, 0, lod.face_num); + dmd->faceCount = lod.face_num; + } + else + result = CDDM_new(lod.vertex_num, 0, 0); + + mvert = CDDM_get_verts(result); + for(a=0; aco, vbCo); + } + + if(lod.vertex_num>2) { + mface = CDDM_get_faces(result); + for(a=0; av1 = tri[0]; + mf->v2 = tri[1]; + mf->v3 = tri[2]; + test_index_face(mf, NULL, 0, 3); + } + } + + CDDM_calc_edges(result); + CDDM_calc_normals(result); + } + else + modifier_setError(md, "Out of memory."); + + LOD_FreeDecimationData(&lod); + } + else + modifier_setError(md, "Non-manifold mesh as input."); + + MEM_freeN(lod.vertex_buffer); + MEM_freeN(lod.vertex_normal_buffer); + MEM_freeN(lod.triangle_index_buffer); + +exit: + return result; +} + +/* Smooth */ + +static void smoothModifier_initData(ModifierData *md) +{ + SmoothModifierData *smd = (SmoothModifierData*) md; + + smd->fac = 0.5f; + smd->repeat = 1; + smd->flag = MOD_SMOOTH_X | MOD_SMOOTH_Y | MOD_SMOOTH_Z; + smd->defgrp_name[0] = '\0'; +} + +static void smoothModifier_copyData(ModifierData *md, ModifierData *target) +{ + SmoothModifierData *smd = (SmoothModifierData*) md; + SmoothModifierData *tsmd = (SmoothModifierData*) target; + + tsmd->fac = smd->fac; + tsmd->repeat = smd->repeat; + tsmd->flag = smd->flag; + strncpy(tsmd->defgrp_name, smd->defgrp_name, 32); +} + +int smoothModifier_isDisabled(ModifierData *md) +{ + SmoothModifierData *smd = (SmoothModifierData*) md; + short flag; + + flag = smd->flag & (MOD_SMOOTH_X|MOD_SMOOTH_Y|MOD_SMOOTH_Z); + + /* disable if modifier is off for X, Y and Z or if factor is 0 */ + if((smd->fac == 0.0f) || flag == 0) return 1; + + return 0; +} + +CustomDataMask smoothModifier_requiredDataMask(ModifierData *md) +{ + SmoothModifierData *smd = (SmoothModifierData *)md; + CustomDataMask dataMask = 0; + + /* ask for vertexgroups if we need them */ + if(smd->defgrp_name[0]) dataMask |= (1 << CD_MDEFORMVERT); + + return dataMask; +} + +static void smoothModifier_do( + SmoothModifierData *smd, Object *ob, DerivedMesh *dm, + float (*vertexCos)[3], int numVerts) +{ + MDeformVert *dvert = NULL; + MEdge *medges = NULL; + + int i, j, numDMEdges, defgrp_index; + unsigned char *uctmp; + float *ftmp, fac, facm; + + ftmp = (float*)MEM_callocN(3*sizeof(float)*numVerts, + "smoothmodifier_f"); + if (!ftmp) return; + uctmp = (unsigned char*)MEM_callocN(sizeof(unsigned char)*numVerts, + "smoothmodifier_uc"); + if (!uctmp) { + if (ftmp) MEM_freeN(ftmp); + return; + } + + fac = smd->fac; + facm = 1 - fac; + + medges = CDDM_get_edges(dm); + numDMEdges = dm->getNumEdges(dm); + + defgrp_index = -1; + + if (smd->defgrp_name[0]) { + bDeformGroup *def; + + for (i = 0, def = ob->defbase.first; def; def = def->next, i++) { + if (!strcmp(def->name, smd->defgrp_name)) { + defgrp_index = i; + break; + } + } + } + + if (defgrp_index >= 0) + dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); + + /* NOTICE: this can be optimized a little bit by moving the + * if (dvert) out of the loop, if needed */ + for (j = 0; j < smd->repeat; j++) { + for (i = 0; i < numDMEdges; i++) { + float fvec[3]; + float *v1, *v2; + unsigned int idx1, idx2; + + idx1 = medges[i].v1; + idx2 = medges[i].v2; + + v1 = vertexCos[idx1]; + v2 = vertexCos[idx2]; + + fvec[0] = (v1[0] + v2[0]) / 2.0; + fvec[1] = (v1[1] + v2[1]) / 2.0; + fvec[2] = (v1[2] + v2[2]) / 2.0; + + v1 = &ftmp[idx1*3]; + v2 = &ftmp[idx2*3]; + + if (uctmp[idx1] < 255) { + uctmp[idx1]++; + VecAddf(v1, v1, fvec); + } + if (uctmp[idx2] < 255) { + uctmp[idx2]++; + VecAddf(v2, v2, fvec); + } + } + + if (dvert) { + for (i = 0; i < numVerts; i++) { + MDeformWeight *dw = NULL; + float f, fm, facw, *fp, *v; + int k; + short flag = smd->flag; + + v = vertexCos[i]; + fp = &ftmp[i*3]; + + for (k = 0; k < dvert[i].totweight; ++k) { + if(dvert[i].dw[k].def_nr == defgrp_index) { + dw = &dvert[i].dw[k]; + break; + } + } + if (!dw) continue; + + f = fac * dw->weight; + fm = 1.0f - f; + + /* fp is the sum of uctmp[i] verts, so must be averaged */ + facw = 0.0f; + if (uctmp[i]) + facw = f / (float)uctmp[i]; + + if (flag & MOD_SMOOTH_X) + v[0] = fm * v[0] + facw * fp[0]; + if (flag & MOD_SMOOTH_Y) + v[1] = fm * v[1] + facw * fp[1]; + if (flag & MOD_SMOOTH_Z) + v[2] = fm * v[2] + facw * fp[2]; + } + } + else { /* no vertex group */ + for (i = 0; i < numVerts; i++) { + float facw, *fp, *v; + short flag = smd->flag; + + v = vertexCos[i]; + fp = &ftmp[i*3]; + + /* fp is the sum of uctmp[i] verts, so must be averaged */ + facw = 0.0f; + if (uctmp[i]) + facw = fac / (float)uctmp[i]; + + if (flag & MOD_SMOOTH_X) + v[0] = facm * v[0] + facw * fp[0]; + if (flag & MOD_SMOOTH_Y) + v[1] = facm * v[1] + facw * fp[1]; + if (flag & MOD_SMOOTH_Z) + v[2] = facm * v[2] + facw * fp[2]; + } + + } + + memset(ftmp, 0, 3*sizeof(float)*numVerts); + memset(uctmp, 0, sizeof(unsigned char)*numVerts); + } + + MEM_freeN(ftmp); + MEM_freeN(uctmp); +} + +static void smoothModifier_deformVerts( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) +{ + DerivedMesh *dm; + + if(derivedData) dm = CDDM_copy(derivedData); + else dm = CDDM_from_mesh(ob->data, ob); + + CDDM_apply_vert_coords(dm, vertexCos); + CDDM_calc_normals(dm); + + smoothModifier_do((SmoothModifierData *)md, ob, dm, + vertexCos, numVerts); + + dm->release(dm); +} + +static void smoothModifier_deformVertsEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) +{ + DerivedMesh *dm; + + if(derivedData) dm = CDDM_copy(derivedData); + else dm = CDDM_from_editmesh(editData, ob->data); + + CDDM_apply_vert_coords(dm, vertexCos); + CDDM_calc_normals(dm); + + smoothModifier_do((SmoothModifierData *)md, ob, dm, + vertexCos, numVerts); + + dm->release(dm); +} + +/* Cast */ + +static void castModifier_initData(ModifierData *md) +{ + CastModifierData *cmd = (CastModifierData*) md; + + cmd->fac = 0.5f; + cmd->radius = 0.0f; + cmd->size = 0.0f; + cmd->flag = MOD_CAST_X | MOD_CAST_Y | MOD_CAST_Z + | MOD_CAST_SIZE_FROM_RADIUS; + cmd->type = MOD_CAST_TYPE_SPHERE; + cmd->defgrp_name[0] = '\0'; + cmd->object = NULL; +} + + +static void castModifier_copyData(ModifierData *md, ModifierData *target) +{ + CastModifierData *cmd = (CastModifierData*) md; + CastModifierData *tcmd = (CastModifierData*) target; + + tcmd->fac = cmd->fac; + tcmd->radius = cmd->radius; + tcmd->size = cmd->size; + tcmd->flag = cmd->flag; + tcmd->type = cmd->type; + tcmd->object = cmd->object; + strncpy(tcmd->defgrp_name, cmd->defgrp_name, 32); +} + +int castModifier_isDisabled(ModifierData *md) +{ + CastModifierData *cmd = (CastModifierData*) md; + short flag; + + flag = cmd->flag & (MOD_CAST_X|MOD_CAST_Y|MOD_CAST_Z); + + if((cmd->fac == 0.0f) || flag == 0) return 1; + + return 0; +} + +CustomDataMask castModifier_requiredDataMask(ModifierData *md) +{ + CastModifierData *cmd = (CastModifierData *)md; + CustomDataMask dataMask = 0; + + /* ask for vertexgroups if we need them */ + if(cmd->defgrp_name[0]) dataMask |= (1 << CD_MDEFORMVERT); + + return dataMask; +} + +static void castModifier_foreachObjectLink( + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) +{ + CastModifierData *cmd = (CastModifierData*) md; + + walk (userData, ob, &cmd->object); +} + +static void castModifier_updateDepgraph( + ModifierData *md, DagForest *forest, Object *ob, + DagNode *obNode) +{ + CastModifierData *cmd = (CastModifierData*) md; + + if (cmd->object) { + DagNode *curNode = dag_get_node(forest, cmd->object); + + dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA); + } +} + +static void castModifier_sphere_do( + CastModifierData *cmd, Object *ob, DerivedMesh *dm, + float (*vertexCos)[3], int numVerts) +{ + MDeformVert *dvert = NULL; + + Object *ctrl_ob = NULL; + + int i, defgrp_index = -1; + int has_radius = 0; + short flag, type; + float fac, facm, len = 0.0f; + float vec[3], center[3] = {0.0f, 0.0f, 0.0f}; + float mat[4][4], imat[4][4]; + + fac = cmd->fac; + facm = 1.0f - fac; + + flag = cmd->flag; + type = cmd->type; /* projection type: sphere or cylinder */ + + if (type == MOD_CAST_TYPE_CYLINDER) + flag &= ~MOD_CAST_Z; + + ctrl_ob = cmd->object; + + /* spherify's center is {0, 0, 0} (the ob's own center in its local + * space), by default, but if the user defined a control object, + * we use its location, transformed to ob's local space */ + if (ctrl_ob) { + if(flag & MOD_CAST_USE_OB_TRANSFORM) { + Mat4Invert(ctrl_ob->imat, ctrl_ob->obmat); + Mat4MulMat4(mat, ob->obmat, ctrl_ob->imat); + Mat4Invert(imat, mat); + } + + Mat4Invert(ob->imat, ob->obmat); + VECCOPY(center, ctrl_ob->obmat[3]); + Mat4MulVecfl(ob->imat, center); + } + + /* now we check which options the user wants */ + + /* 1) (flag was checked in the "if (ctrl_ob)" block above) */ + /* 2) cmd->radius > 0.0f: only the vertices within this radius from + * the center of the effect should be deformed */ + if (cmd->radius > FLT_EPSILON) has_radius = 1; + + /* 3) if we were given a vertex group name, + * only those vertices should be affected */ + if (cmd->defgrp_name[0]) { + bDeformGroup *def; + + for (i = 0, def = ob->defbase.first; def; def = def->next, i++) { + if (!strcmp(def->name, cmd->defgrp_name)) { + defgrp_index = i; + break; + } + } + } + + if ((ob->type == OB_MESH) && dm && defgrp_index >= 0) + dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); + + if(flag & MOD_CAST_SIZE_FROM_RADIUS) { + len = cmd->radius; + } + else { + len = cmd->size; + } + + if(len <= 0) { + for (i = 0; i < numVerts; i++) { + len += VecLenf(center, vertexCos[i]); + } + len /= numVerts; + + if (len == 0.0f) len = 10.0f; + } + + /* ready to apply the effect, one vertex at a time; + * tiny optimization: the code is separated (with parts repeated) + * in two possible cases: + * with or w/o a vgroup. With lots of if's in the code below, + * further optimizations are possible, if needed */ + if (dvert) { /* with a vgroup */ + float fac_orig = fac; + for (i = 0; i < numVerts; i++) { + MDeformWeight *dw = NULL; + int j; + float tmp_co[3]; + + VECCOPY(tmp_co, vertexCos[i]); + if(ctrl_ob) { + if(flag & MOD_CAST_USE_OB_TRANSFORM) { + Mat4MulVecfl(mat, tmp_co); + } else { + VecSubf(tmp_co, tmp_co, center); + } + } + + VECCOPY(vec, tmp_co); + + if (type == MOD_CAST_TYPE_CYLINDER) + vec[2] = 0.0f; + + if (has_radius) { + if (VecLength(vec) > cmd->radius) continue; + } + + for (j = 0; j < dvert[i].totweight; ++j) { + if(dvert[i].dw[j].def_nr == defgrp_index) { + dw = &dvert[i].dw[j]; + break; + } + } + if (!dw) continue; + + fac = fac_orig * dw->weight; + facm = 1.0f - fac; + + Normalize(vec); + + if (flag & MOD_CAST_X) + tmp_co[0] = fac*vec[0]*len + facm*tmp_co[0]; + if (flag & MOD_CAST_Y) + tmp_co[1] = fac*vec[1]*len + facm*tmp_co[1]; + if (flag & MOD_CAST_Z) + tmp_co[2] = fac*vec[2]*len + facm*tmp_co[2]; + + if(ctrl_ob) { + if(flag & MOD_CAST_USE_OB_TRANSFORM) { + Mat4MulVecfl(imat, tmp_co); + } else { + VecAddf(tmp_co, tmp_co, center); + } + } + + VECCOPY(vertexCos[i], tmp_co); + } + return; + } + + /* no vgroup */ + for (i = 0; i < numVerts; i++) { + float tmp_co[3]; + + VECCOPY(tmp_co, vertexCos[i]); + if(ctrl_ob) { + if(flag & MOD_CAST_USE_OB_TRANSFORM) { + Mat4MulVecfl(mat, tmp_co); + } else { + VecSubf(tmp_co, tmp_co, center); + } + } + + VECCOPY(vec, tmp_co); + + if (type == MOD_CAST_TYPE_CYLINDER) + vec[2] = 0.0f; + + if (has_radius) { + if (VecLength(vec) > cmd->radius) continue; + } + + Normalize(vec); + + if (flag & MOD_CAST_X) + tmp_co[0] = fac*vec[0]*len + facm*tmp_co[0]; + if (flag & MOD_CAST_Y) + tmp_co[1] = fac*vec[1]*len + facm*tmp_co[1]; + if (flag & MOD_CAST_Z) + tmp_co[2] = fac*vec[2]*len + facm*tmp_co[2]; + + if(ctrl_ob) { + if(flag & MOD_CAST_USE_OB_TRANSFORM) { + Mat4MulVecfl(imat, tmp_co); + } else { + VecAddf(tmp_co, tmp_co, center); + } + } + + VECCOPY(vertexCos[i], tmp_co); + } +} + +static void castModifier_cuboid_do( + CastModifierData *cmd, Object *ob, DerivedMesh *dm, + float (*vertexCos)[3], int numVerts) +{ + MDeformVert *dvert = NULL; + Object *ctrl_ob = NULL; + + int i, defgrp_index = -1; + int has_radius = 0; + short flag; + float fac, facm; + float min[3], max[3], bb[8][3]; + float center[3] = {0.0f, 0.0f, 0.0f}; + float mat[4][4], imat[4][4]; + + fac = cmd->fac; + facm = 1.0f - fac; + + flag = cmd->flag; + + ctrl_ob = cmd->object; + + /* now we check which options the user wants */ + + /* 1) (flag was checked in the "if (ctrl_ob)" block above) */ + /* 2) cmd->radius > 0.0f: only the vertices within this radius from + * the center of the effect should be deformed */ + if (cmd->radius > FLT_EPSILON) has_radius = 1; + + /* 3) if we were given a vertex group name, + * only those vertices should be affected */ + if (cmd->defgrp_name[0]) { + bDeformGroup *def; + + for (i = 0, def = ob->defbase.first; def; def = def->next, i++) { + if (!strcmp(def->name, cmd->defgrp_name)) { + defgrp_index = i; + break; + } + } + } + + if ((ob->type == OB_MESH) && dm && defgrp_index >= 0) + dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); + + if (ctrl_ob) { + if(flag & MOD_CAST_USE_OB_TRANSFORM) { + Mat4Invert(ctrl_ob->imat, ctrl_ob->obmat); + Mat4MulMat4(mat, ob->obmat, ctrl_ob->imat); + Mat4Invert(imat, mat); + } + + Mat4Invert(ob->imat, ob->obmat); + VECCOPY(center, ctrl_ob->obmat[3]); + Mat4MulVecfl(ob->imat, center); + } + + if((flag & MOD_CAST_SIZE_FROM_RADIUS) && has_radius) { + for(i = 0; i < 3; i++) { + min[i] = -cmd->radius; + max[i] = cmd->radius; + } + } else if(!(flag & MOD_CAST_SIZE_FROM_RADIUS) && cmd->size > 0) { + for(i = 0; i < 3; i++) { + min[i] = -cmd->size; + max[i] = cmd->size; + } + } else { + /* get bound box */ + /* We can't use the object's bound box because other modifiers + * may have changed the vertex data. */ + INIT_MINMAX(min, max); + + /* Cast's center is the ob's own center in its local space, + * by default, but if the user defined a control object, we use + * its location, transformed to ob's local space. */ + if (ctrl_ob) { + float vec[3]; + + /* let the center of the ctrl_ob be part of the bound box: */ + DO_MINMAX(center, min, max); + + for (i = 0; i < numVerts; i++) { + VecSubf(vec, vertexCos[i], center); + DO_MINMAX(vec, min, max); + } + } + else { + for (i = 0; i < numVerts; i++) { + DO_MINMAX(vertexCos[i], min, max); + } + } + + /* we want a symmetric bound box around the origin */ + if (fabs(min[0]) > fabs(max[0])) max[0] = fabs(min[0]); + if (fabs(min[1]) > fabs(max[1])) max[1] = fabs(min[1]); + if (fabs(min[2]) > fabs(max[2])) max[2] = fabs(min[2]); + min[0] = -max[0]; + min[1] = -max[1]; + min[2] = -max[2]; + } + + /* building our custom bounding box */ + bb[0][0] = bb[2][0] = bb[4][0] = bb[6][0] = min[0]; + bb[1][0] = bb[3][0] = bb[5][0] = bb[7][0] = max[0]; + bb[0][1] = bb[1][1] = bb[4][1] = bb[5][1] = min[1]; + bb[2][1] = bb[3][1] = bb[6][1] = bb[7][1] = max[1]; + bb[0][2] = bb[1][2] = bb[2][2] = bb[3][2] = min[2]; + bb[4][2] = bb[5][2] = bb[6][2] = bb[7][2] = max[2]; + + /* ready to apply the effect, one vertex at a time; + * tiny optimization: the code is separated (with parts repeated) + * in two possible cases: + * with or w/o a vgroup. With lots of if's in the code below, + * further optimizations are possible, if needed */ + if (dvert) { /* with a vgroup */ + float fac_orig = fac; + for (i = 0; i < numVerts; i++) { + MDeformWeight *dw = NULL; + int j, octant, coord; + float d[3], dmax, apex[3], fbb; + float tmp_co[3]; + + VECCOPY(tmp_co, vertexCos[i]); + if(ctrl_ob) { + if(flag & MOD_CAST_USE_OB_TRANSFORM) { + Mat4MulVecfl(mat, tmp_co); + } else { + VecSubf(tmp_co, tmp_co, center); + } + } + + if (has_radius) { + if (fabs(tmp_co[0]) > cmd->radius || + fabs(tmp_co[1]) > cmd->radius || + fabs(tmp_co[2]) > cmd->radius) continue; + } + + for (j = 0; j < dvert[i].totweight; ++j) { + if(dvert[i].dw[j].def_nr == defgrp_index) { + dw = &dvert[i].dw[j]; + break; + } + } + if (!dw) continue; + + fac = fac_orig * dw->weight; + facm = 1.0f - fac; + + /* The algo used to project the vertices to their + * bounding box (bb) is pretty simple: + * for each vertex v: + * 1) find in which octant v is in; + * 2) find which outer "wall" of that octant is closer to v; + * 3) calculate factor (var fbb) to project v to that wall; + * 4) project. */ + + /* find in which octant this vertex is in */ + octant = 0; + if (tmp_co[0] > 0.0f) octant += 1; + if (tmp_co[1] > 0.0f) octant += 2; + if (tmp_co[2] > 0.0f) octant += 4; + + /* apex is the bb's vertex at the chosen octant */ + VecCopyf(apex, bb[octant]); + + /* find which bb plane is closest to this vertex ... */ + d[0] = tmp_co[0] / apex[0]; + d[1] = tmp_co[1] / apex[1]; + d[2] = tmp_co[2] / apex[2]; + + /* ... (the closest has the higher (closer to 1) d value) */ + dmax = d[0]; + coord = 0; + if (d[1] > dmax) { + dmax = d[1]; + coord = 1; + } + if (d[2] > dmax) { + /* dmax = d[2]; */ /* commented, we don't need it */ + coord = 2; + } + + /* ok, now we know which coordinate of the vertex to use */ + + if (fabs(tmp_co[coord]) < FLT_EPSILON) /* avoid division by zero */ + continue; + + /* finally, this is the factor we wanted, to project the vertex + * to its bounding box (bb) */ + fbb = apex[coord] / tmp_co[coord]; + + /* calculate the new vertex position */ + if (flag & MOD_CAST_X) + tmp_co[0] = facm * tmp_co[0] + fac * tmp_co[0] * fbb; + if (flag & MOD_CAST_Y) + tmp_co[1] = facm * tmp_co[1] + fac * tmp_co[1] * fbb; + if (flag & MOD_CAST_Z) + tmp_co[2] = facm * tmp_co[2] + fac * tmp_co[2] * fbb; + + if(ctrl_ob) { + if(flag & MOD_CAST_USE_OB_TRANSFORM) { + Mat4MulVecfl(imat, tmp_co); + } else { + VecAddf(tmp_co, tmp_co, center); + } + } + + VECCOPY(vertexCos[i], tmp_co); + } + return; + } + + /* no vgroup (check previous case for comments about the code) */ + for (i = 0; i < numVerts; i++) { + int octant, coord; + float d[3], dmax, fbb, apex[3]; + float tmp_co[3]; + + VECCOPY(tmp_co, vertexCos[i]); + if(ctrl_ob) { + if(flag & MOD_CAST_USE_OB_TRANSFORM) { + Mat4MulVecfl(mat, tmp_co); + } else { + VecSubf(tmp_co, tmp_co, center); + } + } + + if (has_radius) { + if (fabs(tmp_co[0]) > cmd->radius || + fabs(tmp_co[1]) > cmd->radius || + fabs(tmp_co[2]) > cmd->radius) continue; + } + + octant = 0; + if (tmp_co[0] > 0.0f) octant += 1; + if (tmp_co[1] > 0.0f) octant += 2; + if (tmp_co[2] > 0.0f) octant += 4; + + VecCopyf(apex, bb[octant]); + + d[0] = tmp_co[0] / apex[0]; + d[1] = tmp_co[1] / apex[1]; + d[2] = tmp_co[2] / apex[2]; + + dmax = d[0]; + coord = 0; + if (d[1] > dmax) { + dmax = d[1]; + coord = 1; + } + if (d[2] > dmax) { + /* dmax = d[2]; */ /* commented, we don't need it */ + coord = 2; + } + + if (fabs(tmp_co[coord]) < FLT_EPSILON) + continue; + + fbb = apex[coord] / tmp_co[coord]; + + if (flag & MOD_CAST_X) + tmp_co[0] = facm * tmp_co[0] + fac * tmp_co[0] * fbb; + if (flag & MOD_CAST_Y) + tmp_co[1] = facm * tmp_co[1] + fac * tmp_co[1] * fbb; + if (flag & MOD_CAST_Z) + tmp_co[2] = facm * tmp_co[2] + fac * tmp_co[2] * fbb; + + if(ctrl_ob) { + if(flag & MOD_CAST_USE_OB_TRANSFORM) { + Mat4MulVecfl(imat, tmp_co); + } else { + VecAddf(tmp_co, tmp_co, center); + } + } + + VECCOPY(vertexCos[i], tmp_co); + } +} + +static void castModifier_deformVerts( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) +{ + DerivedMesh *dm = derivedData; + CastModifierData *cmd = (CastModifierData *)md; + + if (!dm && ob->type == OB_MESH) + dm = CDDM_from_mesh(ob->data, ob); + + if (cmd->type == MOD_CAST_TYPE_CUBOID) { + castModifier_cuboid_do(cmd, ob, dm, vertexCos, numVerts); + } else { /* MOD_CAST_TYPE_SPHERE or MOD_CAST_TYPE_CYLINDER */ + castModifier_sphere_do(cmd, ob, dm, vertexCos, numVerts); + } + + if (!derivedData && dm) dm->release(dm); +} + +static void castModifier_deformVertsEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) +{ + DerivedMesh *dm = derivedData; + CastModifierData *cmd = (CastModifierData *)md; + + if (!dm && ob->type == OB_MESH) + dm = CDDM_from_editmesh(editData, ob->data); + + if (cmd->type == MOD_CAST_TYPE_CUBOID) { + castModifier_cuboid_do(cmd, ob, dm, vertexCos, numVerts); + } else { /* MOD_CAST_TYPE_SPHERE or MOD_CAST_TYPE_CYLINDER */ + castModifier_sphere_do(cmd, ob, dm, vertexCos, numVerts); + } + + if (!derivedData && dm) dm->release(dm); +} + +/* Wave */ + +static void waveModifier_initData(ModifierData *md) +{ + WaveModifierData *wmd = (WaveModifierData*) md; // whadya know, moved here from Iraq + + wmd->flag |= (MOD_WAVE_X | MOD_WAVE_Y | MOD_WAVE_CYCL + | MOD_WAVE_NORM_X | MOD_WAVE_NORM_Y | MOD_WAVE_NORM_Z); + + wmd->objectcenter = NULL; + wmd->texture = NULL; + wmd->map_object = NULL; + wmd->height= 0.5f; + wmd->width= 1.5f; + wmd->speed= 0.5f; + wmd->narrow= 1.5f; + wmd->lifetime= 0.0f; + wmd->damp= 10.0f; + wmd->texmapping = MOD_WAV_MAP_LOCAL; + wmd->defgrp_name[0] = 0; +} + +static void waveModifier_copyData(ModifierData *md, ModifierData *target) +{ + WaveModifierData *wmd = (WaveModifierData*) md; + WaveModifierData *twmd = (WaveModifierData*) target; + + twmd->damp = wmd->damp; + twmd->flag = wmd->flag; + twmd->height = wmd->height; + twmd->lifetime = wmd->lifetime; + twmd->narrow = wmd->narrow; + twmd->speed = wmd->speed; + twmd->startx = wmd->startx; + twmd->starty = wmd->starty; + twmd->timeoffs = wmd->timeoffs; + twmd->width = wmd->width; + twmd->objectcenter = wmd->objectcenter; + twmd->texture = wmd->texture; + twmd->map_object = wmd->map_object; + twmd->texmapping = wmd->texmapping; + strncpy(twmd->defgrp_name, wmd->defgrp_name, 32); +} + +static int waveModifier_dependsOnTime(ModifierData *md) +{ + return 1; +} + +static void waveModifier_foreachObjectLink( + ModifierData *md, Object *ob, + ObjectWalkFunc walk, void *userData) +{ + WaveModifierData *wmd = (WaveModifierData*) md; + + walk(userData, ob, &wmd->objectcenter); + walk(userData, ob, &wmd->map_object); +} + +static void waveModifier_foreachIDLink(ModifierData *md, Object *ob, + IDWalkFunc walk, void *userData) +{ + WaveModifierData *wmd = (WaveModifierData*) md; + + walk(userData, ob, (ID **)&wmd->texture); + + waveModifier_foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); +} + +static void waveModifier_updateDepgraph( + ModifierData *md, DagForest *forest, Object *ob, + DagNode *obNode) +{ + WaveModifierData *wmd = (WaveModifierData*) md; + + if(wmd->objectcenter) { + DagNode *curNode = dag_get_node(forest, wmd->objectcenter); + + dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA); + } + + if(wmd->map_object) { + DagNode *curNode = dag_get_node(forest, wmd->map_object); + + dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA); + } +} + +CustomDataMask waveModifier_requiredDataMask(ModifierData *md) +{ + WaveModifierData *wmd = (WaveModifierData *)md; + CustomDataMask dataMask = 0; + + + /* ask for UV coordinates if we need them */ + if(wmd->texture && wmd->texmapping == MOD_WAV_MAP_UV) + dataMask |= (1 << CD_MTFACE); + + /* ask for vertexgroups if we need them */ + if(wmd->defgrp_name[0]) + dataMask |= (1 << CD_MDEFORMVERT); + + return dataMask; +} + +static void wavemod_get_texture_coords(WaveModifierData *wmd, Object *ob, + DerivedMesh *dm, + float (*co)[3], float (*texco)[3], + int numVerts) +{ + int i; + int texmapping = wmd->texmapping; + + if(texmapping == MOD_WAV_MAP_OBJECT) { + if(wmd->map_object) + Mat4Invert(wmd->map_object->imat, wmd->map_object->obmat); + else /* if there is no map object, default to local */ + texmapping = MOD_WAV_MAP_LOCAL; + } + + /* UVs need special handling, since they come from faces */ + if(texmapping == MOD_WAV_MAP_UV) { + if(dm->getFaceDataArray(dm, CD_MTFACE)) { + MFace *mface = dm->getFaceArray(dm); + MFace *mf; + char *done = MEM_callocN(sizeof(*done) * numVerts, + "get_texture_coords done"); + int numFaces = dm->getNumFaces(dm); + MTFace *tf; + + validate_layer_name(&dm->faceData, CD_MTFACE, wmd->uvlayer_name); + + tf = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, + wmd->uvlayer_name); + + /* verts are given the UV from the first face that uses them */ + for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tf) { + if(!done[mf->v1]) { + texco[mf->v1][0] = tf->uv[0][0]; + texco[mf->v1][1] = tf->uv[0][1]; + texco[mf->v1][2] = 0; + done[mf->v1] = 1; + } + if(!done[mf->v2]) { + texco[mf->v2][0] = tf->uv[1][0]; + texco[mf->v2][1] = tf->uv[1][1]; + texco[mf->v2][2] = 0; + done[mf->v2] = 1; + } + if(!done[mf->v3]) { + texco[mf->v3][0] = tf->uv[2][0]; + texco[mf->v3][1] = tf->uv[2][1]; + texco[mf->v3][2] = 0; + done[mf->v3] = 1; + } + if(!done[mf->v4]) { + texco[mf->v4][0] = tf->uv[3][0]; + texco[mf->v4][1] = tf->uv[3][1]; + texco[mf->v4][2] = 0; + done[mf->v4] = 1; + } + } + + /* remap UVs from [0, 1] to [-1, 1] */ + for(i = 0; i < numVerts; ++i) { + texco[i][0] = texco[i][0] * 2 - 1; + texco[i][1] = texco[i][1] * 2 - 1; + } + + MEM_freeN(done); + return; + } else /* if there are no UVs, default to local */ + texmapping = MOD_WAV_MAP_LOCAL; + } + + for(i = 0; i < numVerts; ++i, ++co, ++texco) { + switch(texmapping) { + case MOD_WAV_MAP_LOCAL: + VECCOPY(*texco, *co); + break; + case MOD_WAV_MAP_GLOBAL: + VECCOPY(*texco, *co); + Mat4MulVecfl(ob->obmat, *texco); + break; + case MOD_WAV_MAP_OBJECT: + VECCOPY(*texco, *co); + Mat4MulVecfl(ob->obmat, *texco); + Mat4MulVecfl(wmd->map_object->imat, *texco); + break; + } + } +} + +static void waveModifier_do( + WaveModifierData *md, Object *ob, DerivedMesh *dm, + float (*vertexCos)[3], int numVerts) +{ + WaveModifierData *wmd = (WaveModifierData*) md; + MVert *mvert = NULL; + MDeformVert *dvert = NULL; + int defgrp_index; + float ctime = bsystem_time(ob, (float)G.scene->r.cfra, 0.0); + float minfac = + (float)(1.0 / exp(wmd->width * wmd->narrow * wmd->width * wmd->narrow)); + float lifefac = wmd->height; + float (*tex_co)[3] = NULL; + + if(wmd->flag & MOD_WAVE_NORM && ob->type == OB_MESH) + mvert = dm->getVertArray(dm); + + if(wmd->objectcenter){ + float mat[4][4]; + /* get the control object's location in local coordinates */ + Mat4Invert(ob->imat, ob->obmat); + Mat4MulMat4(mat, wmd->objectcenter->obmat, ob->imat); + + wmd->startx = mat[3][0]; + wmd->starty = mat[3][1]; + } + + /* get the index of the deform group */ + defgrp_index = -1; + + if(wmd->defgrp_name[0]) { + int i; + bDeformGroup *def; + for(i = 0, def = ob->defbase.first; def; def = def->next, i++) { + if(!strcmp(def->name, wmd->defgrp_name)) { + defgrp_index = i; + break; + } + } + } + + if(defgrp_index >= 0){ + dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); + } + + if(wmd->damp == 0) wmd->damp = 10.0f; + + if(wmd->lifetime != 0.0) { + float x = ctime - wmd->timeoffs; + + if(x > wmd->lifetime) { + lifefac = x - wmd->lifetime; + + if(lifefac > wmd->damp) lifefac = 0.0; + else lifefac = + (float)(wmd->height * (1.0 - sqrt(lifefac / wmd->damp))); + } + } + + if(wmd->texture) { + tex_co = MEM_mallocN(sizeof(*tex_co) * numVerts, + "waveModifier_do tex_co"); + wavemod_get_texture_coords(wmd, ob, dm, vertexCos, tex_co, numVerts); + } + + if(lifefac != 0.0) { + int i; + + for(i = 0; i < numVerts; i++) { + float *co = vertexCos[i]; + float x = co[0] - wmd->startx; + float y = co[1] - wmd->starty; + float amplit= 0.0f; + TexResult texres; + MDeformWeight *def_weight = NULL; + + /* get weights */ + if(dvert) { + int j; + for(j = 0; j < dvert[i].totweight; ++j) { + if(dvert[i].dw[j].def_nr == defgrp_index) { + def_weight = &dvert[i].dw[j]; + break; + } + } + + /* if this vert isn't in the vgroup, don't deform it */ + if(!def_weight) continue; + } + + if(wmd->texture) { + texres.nor = NULL; + get_texture_value(wmd->texture, tex_co[i], &texres); + } + + + if(wmd->flag & MOD_WAVE_X) { + if(wmd->flag & MOD_WAVE_Y) amplit = (float)sqrt(x*x + y*y); + else amplit = x; + } + else if(wmd->flag & MOD_WAVE_Y) + amplit= y; + + /* this way it makes nice circles */ + amplit -= (ctime - wmd->timeoffs) * wmd->speed; + + if(wmd->flag & MOD_WAVE_CYCL) { + amplit = (float)fmod(amplit - wmd->width, 2.0 * wmd->width) + + wmd->width; + } + + /* GAUSSIAN */ + if(amplit > -wmd->width && amplit < wmd->width) { + amplit = amplit * wmd->narrow; + amplit = (float)(1.0 / exp(amplit * amplit) - minfac); + if(wmd->texture) + amplit = amplit * texres.tin; + + if(def_weight) + amplit = amplit * def_weight->weight; + + if(mvert) { + /* move along normals */ + if(wmd->flag & MOD_WAVE_NORM_X) { + co[0] += (lifefac * amplit) * mvert[i].no[0] / 32767.0f; + } + if(wmd->flag & MOD_WAVE_NORM_Y) { + co[1] += (lifefac * amplit) * mvert[i].no[1] / 32767.0f; + } + if(wmd->flag & MOD_WAVE_NORM_Z) { + co[2] += (lifefac * amplit) * mvert[i].no[2] / 32767.0f; + } + } + else { + /* move along local z axis */ + co[2] += lifefac * amplit; + } + } + } + } + + if(wmd->texture) MEM_freeN(tex_co); +} + +static void waveModifier_deformVerts( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) +{ + DerivedMesh *dm; + WaveModifierData *wmd = (WaveModifierData *)md; + + if(!wmd->texture && !wmd->defgrp_name[0] && !(wmd->flag & MOD_WAVE_NORM)) + dm = derivedData; + else if(derivedData) dm = derivedData; + else if(ob->type == OB_MESH) dm = CDDM_from_mesh(ob->data, ob); + else return; + + if(wmd->flag & MOD_WAVE_NORM) { + CDDM_apply_vert_coords(dm, vertexCos); + CDDM_calc_normals(dm); + } + + waveModifier_do(wmd, ob, dm, vertexCos, numVerts); + + if(dm != derivedData) dm->release(dm); +} + +static void waveModifier_deformVertsEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) +{ + DerivedMesh *dm; + WaveModifierData *wmd = (WaveModifierData *)md; + + if(!wmd->texture && !wmd->defgrp_name[0] && !(wmd->flag & MOD_WAVE_NORM)) + dm = derivedData; + else if(derivedData) dm = derivedData; + else dm = CDDM_from_editmesh(editData, ob->data); + + if(wmd->flag & MOD_WAVE_NORM) { + CDDM_apply_vert_coords(dm, vertexCos); + CDDM_calc_normals(dm); + } + + waveModifier_do(wmd, ob, dm, vertexCos, numVerts); + + if(dm != derivedData) dm->release(dm); +} + +/* Armature */ + +static void armatureModifier_initData(ModifierData *md) +{ + ArmatureModifierData *amd = (ArmatureModifierData*) md; + + amd->deformflag = ARM_DEF_ENVELOPE | ARM_DEF_VGROUP; +} + +static void armatureModifier_copyData(ModifierData *md, ModifierData *target) +{ + ArmatureModifierData *amd = (ArmatureModifierData*) md; + ArmatureModifierData *tamd = (ArmatureModifierData*) target; + + tamd->object = amd->object; + tamd->deformflag = amd->deformflag; + strncpy(tamd->defgrp_name, amd->defgrp_name, 32); +} + +CustomDataMask armatureModifier_requiredDataMask(ModifierData *md) +{ + CustomDataMask dataMask = 0; + + /* ask for vertexgroups */ + dataMask |= (1 << CD_MDEFORMVERT); + + return dataMask; +} + +static int armatureModifier_isDisabled(ModifierData *md) +{ + ArmatureModifierData *amd = (ArmatureModifierData*) md; + + return !amd->object; +} + +static void armatureModifier_foreachObjectLink( + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) +{ + ArmatureModifierData *amd = (ArmatureModifierData*) md; + + walk(userData, ob, &amd->object); +} + +static void armatureModifier_updateDepgraph( + ModifierData *md, DagForest *forest, Object *ob, + DagNode *obNode) +{ + ArmatureModifierData *amd = (ArmatureModifierData*) md; + + if (amd->object) { + DagNode *curNode = dag_get_node(forest, amd->object); + + dag_add_relation(forest, curNode, obNode, + DAG_RL_DATA_DATA | DAG_RL_OB_DATA); + } +} + +static void armatureModifier_deformVerts( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) +{ + ArmatureModifierData *amd = (ArmatureModifierData*) md; + + armature_deform_verts(amd->object, ob, derivedData, vertexCos, NULL, + numVerts, amd->deformflag, amd->defgrp_name); +} + +static void armatureModifier_deformVertsEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) +{ + ArmatureModifierData *amd = (ArmatureModifierData*) md; + DerivedMesh *dm = derivedData; + + if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data); + + armature_deform_verts(amd->object, ob, dm, vertexCos, NULL, numVerts, + amd->deformflag, amd->defgrp_name); + + if(!derivedData) dm->release(dm); +} + +static void armatureModifier_deformMatricesEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], + float (*defMats)[3][3], int numVerts) +{ + ArmatureModifierData *amd = (ArmatureModifierData*) md; + DerivedMesh *dm = derivedData; + + if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data); + + armature_deform_verts(amd->object, ob, dm, vertexCos, defMats, numVerts, + amd->deformflag, amd->defgrp_name); + + if(!derivedData) dm->release(dm); +} + +/* Hook */ + +static void hookModifier_initData(ModifierData *md) +{ + HookModifierData *hmd = (HookModifierData*) md; + + hmd->force= 1.0; +} + +static void hookModifier_copyData(ModifierData *md, ModifierData *target) +{ + HookModifierData *hmd = (HookModifierData*) md; + HookModifierData *thmd = (HookModifierData*) target; + + VECCOPY(thmd->cent, hmd->cent); + thmd->falloff = hmd->falloff; + thmd->force = hmd->force; + thmd->object = hmd->object; + thmd->totindex = hmd->totindex; + thmd->indexar = MEM_dupallocN(hmd->indexar); + memcpy(thmd->parentinv, hmd->parentinv, sizeof(hmd->parentinv)); + strncpy(thmd->name, hmd->name, 32); +} + +CustomDataMask hookModifier_requiredDataMask(ModifierData *md) +{ + HookModifierData *hmd = (HookModifierData *)md; + CustomDataMask dataMask = 0; + + /* ask for vertexgroups if we need them */ + if(!hmd->indexar && hmd->name[0]) dataMask |= (1 << CD_MDEFORMVERT); + + return dataMask; +} + +static void hookModifier_freeData(ModifierData *md) +{ + HookModifierData *hmd = (HookModifierData*) md; + + if (hmd->indexar) MEM_freeN(hmd->indexar); +} + +static int hookModifier_isDisabled(ModifierData *md) +{ + HookModifierData *hmd = (HookModifierData*) md; + + return !hmd->object; +} + +static void hookModifier_foreachObjectLink( + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) +{ + HookModifierData *hmd = (HookModifierData*) md; + + walk(userData, ob, &hmd->object); +} + +static void hookModifier_updateDepgraph(ModifierData *md, DagForest *forest, + Object *ob, DagNode *obNode) +{ + HookModifierData *hmd = (HookModifierData*) md; + + if (hmd->object) { + DagNode *curNode = dag_get_node(forest, hmd->object); + + dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA); + } +} + +static void hookModifier_deformVerts( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) +{ + HookModifierData *hmd = (HookModifierData*) md; + float vec[3], mat[4][4]; + int i; + DerivedMesh *dm = derivedData; + + Mat4Invert(ob->imat, ob->obmat); + Mat4MulSerie(mat, ob->imat, hmd->object->obmat, hmd->parentinv, + NULL, NULL, NULL, NULL, NULL); + + /* vertex indices? */ + if(hmd->indexar) { + for(i = 0; i < hmd->totindex; i++) { + int index = hmd->indexar[i]; + + /* This should always be true and I don't generally like + * "paranoid" style code like this, but old files can have + * indices that are out of range because old blender did + * not correct them on exit editmode. - zr + */ + if(index < numVerts) { + float *co = vertexCos[index]; + float fac = hmd->force; + + /* if DerivedMesh is present and has original index data, + * use it + */ + if(dm && dm->getVertData(dm, 0, CD_ORIGINDEX)) { + int j; + int orig_index; + for(j = 0; j < numVerts; ++j) { + fac = hmd->force; + orig_index = *(int *)dm->getVertData(dm, j, + CD_ORIGINDEX); + if(orig_index == index) { + co = vertexCos[j]; + if(hmd->falloff != 0.0) { + float len = VecLenf(co, hmd->cent); + if(len > hmd->falloff) fac = 0.0; + else if(len > 0.0) + fac *= sqrt(1.0 - len / hmd->falloff); + } + + if(fac != 0.0) { + VecMat4MulVecfl(vec, mat, co); + VecLerpf(co, co, vec, fac); + } + } + } + } else { + if(hmd->falloff != 0.0) { + float len = VecLenf(co, hmd->cent); + if(len > hmd->falloff) fac = 0.0; + else if(len > 0.0) + fac *= sqrt(1.0 - len / hmd->falloff); + } + + if(fac != 0.0) { + VecMat4MulVecfl(vec, mat, co); + VecLerpf(co, co, vec, fac); + } + } + } + } + } else { /* vertex group hook */ + bDeformGroup *curdef; + Mesh *me = ob->data; + int index = 0; + int use_dverts; + int maxVerts = 0; + + /* find the group (weak loop-in-loop) */ + for(curdef = ob->defbase.first; curdef; curdef = curdef->next, index++) + if(!strcmp(curdef->name, hmd->name)) break; + + if(dm) + if(dm->getVertData(dm, 0, CD_MDEFORMVERT)) { + use_dverts = 1; + maxVerts = dm->getNumVerts(dm); + } else use_dverts = 0; + else if(me->dvert) { + use_dverts = 1; + maxVerts = me->totvert; + } else use_dverts = 0; + + if(curdef && use_dverts) { + MDeformVert *dvert = me->dvert; + int i, j; + + for(i = 0; i < maxVerts; i++, dvert++) { + if(dm) dvert = dm->getVertData(dm, i, CD_MDEFORMVERT); + for(j = 0; j < dvert->totweight; j++) { + if(dvert->dw[j].def_nr == index) { + float fac = hmd->force*dvert->dw[j].weight; + float *co = vertexCos[i]; + + if(hmd->falloff != 0.0) { + float len = VecLenf(co, hmd->cent); + if(len > hmd->falloff) fac = 0.0; + else if(len > 0.0) + fac *= sqrt(1.0 - len / hmd->falloff); + } + + VecMat4MulVecfl(vec, mat, co); + VecLerpf(co, co, vec, fac); + } + } + } + } + } +} + +static void hookModifier_deformVertsEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) +{ + DerivedMesh *dm = derivedData; + + if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data); + + hookModifier_deformVerts(md, ob, derivedData, vertexCos, numVerts); + + if(!derivedData) dm->release(dm); +} + +/* Softbody */ + +static void softbodyModifier_deformVerts( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) +{ + sbObjectStep(ob, (float)G.scene->r.cfra, vertexCos, numVerts); +} + +/* Boolean */ + +static void booleanModifier_copyData(ModifierData *md, ModifierData *target) +{ + BooleanModifierData *bmd = (BooleanModifierData*) md; + BooleanModifierData *tbmd = (BooleanModifierData*) target; + + tbmd->object = bmd->object; + tbmd->operation = bmd->operation; +} + +static int booleanModifier_isDisabled(ModifierData *md) +{ + BooleanModifierData *bmd = (BooleanModifierData*) md; + + return !bmd->object; +} + +static void booleanModifier_foreachObjectLink( + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) +{ + BooleanModifierData *bmd = (BooleanModifierData*) md; + + walk(userData, ob, &bmd->object); +} + +static void booleanModifier_updateDepgraph( + ModifierData *md, DagForest *forest, Object *ob, + DagNode *obNode) +{ + BooleanModifierData *bmd = (BooleanModifierData*) md; + + if(bmd->object) { + DagNode *curNode = dag_get_node(forest, bmd->object); + + dag_add_relation(forest, curNode, obNode, + DAG_RL_DATA_DATA | DAG_RL_OB_DATA); + } +} + +static DerivedMesh *booleanModifier_applyModifier( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) +{ + // XXX doesn't handle derived data + BooleanModifierData *bmd = (BooleanModifierData*) md; + + /* we do a quick sanity check */ + if(((Mesh *)ob->data)->totface > 3 + && bmd->object && ((Mesh *)bmd->object->data)->totface > 3) { + DerivedMesh *result = NewBooleanDerivedMesh(bmd->object, ob, + 1 + bmd->operation); + + /* if new mesh returned, return it; otherwise there was + * an error, so delete the modifier object */ + if(result) + return result; + else + bmd->object = NULL; + } + + return derivedData; +} + +/* MeshDeform */ + +static void meshdeformModifier_initData(ModifierData *md) +{ + MeshDeformModifierData *mmd = (MeshDeformModifierData*) md; + + mmd->gridsize= 5; +} + +static void meshdeformModifier_freeData(ModifierData *md) +{ + MeshDeformModifierData *mmd = (MeshDeformModifierData*) md; + + if (mmd->bindweights) MEM_freeN(mmd->bindweights); + if (mmd->bindcos) MEM_freeN(mmd->bindcos); +} + +static void meshdeformModifier_copyData(ModifierData *md, ModifierData *target) +{ + MeshDeformModifierData *mmd = (MeshDeformModifierData*) md; + MeshDeformModifierData *tmmd = (MeshDeformModifierData*) target; + + tmmd->gridsize = mmd->gridsize; + tmmd->object = mmd->object; +} + +CustomDataMask meshdeformModifier_requiredDataMask(ModifierData *md) +{ + MeshDeformModifierData *mmd = (MeshDeformModifierData *)md; + CustomDataMask dataMask = 0; + + /* ask for vertexgroups if we need them */ + if(mmd->defgrp_name[0]) dataMask |= (1 << CD_MDEFORMVERT); + + return dataMask; +} + +static int meshdeformModifier_isDisabled(ModifierData *md) +{ + MeshDeformModifierData *mmd = (MeshDeformModifierData*) md; + + return !mmd->object; +} + +static void meshdeformModifier_foreachObjectLink( + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) +{ + MeshDeformModifierData *mmd = (MeshDeformModifierData*) md; + + walk(userData, ob, &mmd->object); +} + +static void meshdeformModifier_updateDepgraph( + ModifierData *md, DagForest *forest, Object *ob, + DagNode *obNode) +{ + MeshDeformModifierData *mmd = (MeshDeformModifierData*) md; + + if (mmd->object) { + DagNode *curNode = dag_get_node(forest, mmd->object); + + dag_add_relation(forest, curNode, obNode, + DAG_RL_DATA_DATA|DAG_RL_OB_DATA|DAG_RL_DATA_OB|DAG_RL_OB_OB); + } +} + +static void meshdeformModifier_do( + ModifierData *md, Object *ob, DerivedMesh *dm, + float (*vertexCos)[3], int numVerts) +{ + MeshDeformModifierData *mmd = (MeshDeformModifierData*) md; + float imat[4][4], cagemat[4][4], icagemat[4][4], icmat[3][3]; + float weight, totweight, fac, co[3], *weights, (*dco)[3], (*bindcos)[3]; + int a, b, totvert, totcagevert, defgrp_index; + DerivedMesh *tmpdm, *cagedm; + MDeformVert *dvert = NULL; + MDeformWeight *dw; + MVert *cagemvert; + + if(!mmd->object || (!mmd->bindweights && !mmd->needbind)) + return; + + /* get cage derivedmesh */ + if(mmd->object == G.obedit) { + tmpdm= editmesh_get_derived_cage_and_final(&cagedm, 0); + if(tmpdm) + tmpdm->release(tmpdm); + } + else + cagedm= mesh_get_derived_final(mmd->object, CD_MASK_BAREMESH); + + /* TODO: this could give inifinite loop for circular dependency */ + if(!cagedm) + return; + + /* compute matrices to go in and out of cage object space */ + Mat4Invert(imat, mmd->object->obmat); + Mat4MulMat4(cagemat, ob->obmat, imat); + Mat4Invert(icagemat, cagemat); + Mat3CpyMat4(icmat, icagemat); + + /* bind weights if needed */ + if(!mmd->bindweights) + harmonic_coordinates_bind(mmd, vertexCos, numVerts, cagemat); + + /* verify we have compatible weights */ + totvert= numVerts; + totcagevert= cagedm->getNumVerts(cagedm); + + if(mmd->totvert!=totvert || mmd->totcagevert!=totcagevert || !mmd->bindweights) { + cagedm->release(cagedm); + return; + } + + /* setup deformation data */ + cagemvert= cagedm->getVertArray(cagedm); + weights= mmd->bindweights; + bindcos= (float(*)[3])mmd->bindcos; + + dco= MEM_callocN(sizeof(*dco)*totcagevert, "MDefDco"); + for(a=0; aobject->obmat, co); + VECSUB(dco[a], co, bindcos[a]); + } + + defgrp_index = -1; + + if(mmd->defgrp_name[0]) { + bDeformGroup *def; + + for(a=0, def=ob->defbase.first; def; def=def->next, a++) { + if(!strcmp(def->name, mmd->defgrp_name)) { + defgrp_index= a; + break; + } + } + + if (defgrp_index >= 0) + dvert= dm->getVertDataArray(dm, CD_MDEFORMVERT); + } + + /* do deformation */ + fac= 1.0f; + + for(b=0; bflag & MOD_MDEF_INVERT_VGROUP) { + if(!dw) fac= 1.0f; + else if(dw->weight == 1.0f) continue; + else fac=1.0f-dw->weight; + } + else { + if(!dw) continue; + else fac= dw->weight; + } + } + + totweight= 0.0f; + co[0]= co[1]= co[2]= 0.0f; + + for(a=0; a 0.0f) { + VecMulf(co, fac/totweight); + Mat3MulVecfl(icmat, co); + VECADD(vertexCos[b], vertexCos[b], co); + } + } + + /* release cage derivedmesh */ + MEM_freeN(dco); + cagedm->release(cagedm); +} + +static void meshdeformModifier_deformVerts( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) +{ + DerivedMesh *dm; + + if(!derivedData && ob->type==OB_MESH) + dm= CDDM_from_mesh(ob->data, ob); + else + dm= derivedData; + + meshdeformModifier_do(md, ob, dm, vertexCos, numVerts); + + if(dm != derivedData) + dm->release(dm); +} + +static void meshdeformModifier_deformVertsEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) +{ + DerivedMesh *dm; + + if(!derivedData && ob->type == OB_MESH) + dm = CDDM_from_editmesh(editData, ob->data); + else + dm = derivedData; + + meshdeformModifier_do(md, ob, dm, vertexCos, numVerts); + + if(dm != derivedData) + dm->release(dm); +} + +/***/ + +static ModifierTypeInfo typeArr[NUM_MODIFIER_TYPES]; +static int typeArrInit = 1; + +ModifierTypeInfo *modifierType_getInfo(ModifierType type) +{ + if (typeArrInit) { + ModifierTypeInfo *mti; + + memset(typeArr, 0, sizeof(typeArr)); + + /* Initialize and return the appropriate type info structure, + * assumes that modifier has: + * name == typeName, + * structName == typeName + 'ModifierData' + */ +#define INIT_TYPE(typeName) \ + (strcpy(typeArr[eModifierType_##typeName].name, #typeName), \ + strcpy(typeArr[eModifierType_##typeName].structName, \ + #typeName "ModifierData"), \ + typeArr[eModifierType_##typeName].structSize = \ + sizeof(typeName##ModifierData), \ + &typeArr[eModifierType_##typeName]) + + mti = &typeArr[eModifierType_None]; + strcpy(mti->name, "None"); + strcpy(mti->structName, "ModifierData"); + mti->structSize = sizeof(ModifierData); + mti->type = eModifierType_None; + mti->flags = eModifierTypeFlag_AcceptsMesh + | eModifierTypeFlag_AcceptsCVs; + mti->isDisabled = noneModifier_isDisabled; + + mti = INIT_TYPE(Curve); + mti->type = eModifierTypeType_OnlyDeform; + mti->flags = eModifierTypeFlag_AcceptsCVs + | eModifierTypeFlag_SupportsEditmode; + mti->initData = curveModifier_initData; + mti->copyData = curveModifier_copyData; + mti->requiredDataMask = curveModifier_requiredDataMask; + mti->isDisabled = curveModifier_isDisabled; + mti->foreachObjectLink = curveModifier_foreachObjectLink; + mti->updateDepgraph = curveModifier_updateDepgraph; + mti->deformVerts = curveModifier_deformVerts; + mti->deformVertsEM = curveModifier_deformVertsEM; + + mti = INIT_TYPE(Lattice); + mti->type = eModifierTypeType_OnlyDeform; + mti->flags = eModifierTypeFlag_AcceptsCVs + | eModifierTypeFlag_SupportsEditmode; + mti->copyData = latticeModifier_copyData; + mti->requiredDataMask = latticeModifier_requiredDataMask; + mti->isDisabled = latticeModifier_isDisabled; + mti->foreachObjectLink = latticeModifier_foreachObjectLink; + mti->updateDepgraph = latticeModifier_updateDepgraph; + mti->deformVerts = latticeModifier_deformVerts; + mti->deformVertsEM = latticeModifier_deformVertsEM; + + mti = INIT_TYPE(Subsurf); + mti->type = eModifierTypeType_Constructive; + mti->flags = eModifierTypeFlag_AcceptsMesh + | eModifierTypeFlag_SupportsMapping + | eModifierTypeFlag_SupportsEditmode + | eModifierTypeFlag_EnableInEditmode; + mti->initData = subsurfModifier_initData; + mti->copyData = subsurfModifier_copyData; + mti->freeData = subsurfModifier_freeData; + mti->applyModifier = subsurfModifier_applyModifier; + mti->applyModifierEM = subsurfModifier_applyModifierEM; + + mti = INIT_TYPE(Build); + mti->type = eModifierTypeType_Nonconstructive; + mti->flags = eModifierTypeFlag_AcceptsMesh; + mti->initData = buildModifier_initData; + mti->copyData = buildModifier_copyData; + mti->dependsOnTime = buildModifier_dependsOnTime; + mti->applyModifier = buildModifier_applyModifier; + + mti = INIT_TYPE(Array); + mti->type = eModifierTypeType_Constructive; + mti->flags = eModifierTypeFlag_AcceptsMesh + | eModifierTypeFlag_SupportsMapping + | eModifierTypeFlag_SupportsEditmode + | eModifierTypeFlag_EnableInEditmode; + mti->initData = arrayModifier_initData; + mti->copyData = arrayModifier_copyData; + mti->foreachObjectLink = arrayModifier_foreachObjectLink; + mti->updateDepgraph = arrayModifier_updateDepgraph; + mti->applyModifier = arrayModifier_applyModifier; + mti->applyModifierEM = arrayModifier_applyModifierEM; + + mti = INIT_TYPE(Mirror); + mti->type = eModifierTypeType_Constructive; + mti->flags = eModifierTypeFlag_AcceptsMesh + | eModifierTypeFlag_SupportsMapping + | eModifierTypeFlag_SupportsEditmode + | eModifierTypeFlag_EnableInEditmode; + mti->initData = mirrorModifier_initData; + mti->copyData = mirrorModifier_copyData; + mti->applyModifier = mirrorModifier_applyModifier; + mti->applyModifierEM = mirrorModifier_applyModifierEM; + + mti = INIT_TYPE(EdgeSplit); + mti->type = eModifierTypeType_Constructive; + mti->flags = eModifierTypeFlag_AcceptsMesh + | eModifierTypeFlag_SupportsMapping + | eModifierTypeFlag_SupportsEditmode + | eModifierTypeFlag_EnableInEditmode; + mti->initData = edgesplitModifier_initData; + mti->copyData = edgesplitModifier_copyData; + mti->applyModifier = edgesplitModifier_applyModifier; + mti->applyModifierEM = edgesplitModifier_applyModifierEM; + + mti = INIT_TYPE(Displace); + mti->type = eModifierTypeType_OnlyDeform; + mti->flags = eModifierTypeFlag_AcceptsMesh|eModifierTypeFlag_SupportsEditmode; + mti->initData = displaceModifier_initData; + mti->copyData = displaceModifier_copyData; + mti->requiredDataMask = displaceModifier_requiredDataMask; + mti->foreachObjectLink = displaceModifier_foreachObjectLink; + mti->foreachIDLink = displaceModifier_foreachIDLink; + mti->updateDepgraph = displaceModifier_updateDepgraph; + mti->isDisabled = displaceModifier_isDisabled; + mti->deformVerts = displaceModifier_deformVerts; + mti->deformVertsEM = displaceModifier_deformVertsEM; + + mti = INIT_TYPE(UVProject); + mti->type = eModifierTypeType_Nonconstructive; + mti->flags = eModifierTypeFlag_AcceptsMesh + | eModifierTypeFlag_SupportsMapping + | eModifierTypeFlag_SupportsEditmode + | eModifierTypeFlag_EnableInEditmode; + mti->initData = uvprojectModifier_initData; + mti->copyData = uvprojectModifier_copyData; + mti->requiredDataMask = uvprojectModifier_requiredDataMask; + mti->foreachObjectLink = uvprojectModifier_foreachObjectLink; + mti->foreachIDLink = uvprojectModifier_foreachIDLink; + mti->updateDepgraph = uvprojectModifier_updateDepgraph; + mti->applyModifier = uvprojectModifier_applyModifier; + mti->applyModifierEM = uvprojectModifier_applyModifierEM; + + mti = INIT_TYPE(Decimate); + mti->type = eModifierTypeType_Nonconstructive; + mti->flags = eModifierTypeFlag_AcceptsMesh; + mti->initData = decimateModifier_initData; + mti->copyData = decimateModifier_copyData; + mti->applyModifier = decimateModifier_applyModifier; + + mti = INIT_TYPE(Smooth); + mti->type = eModifierTypeType_OnlyDeform; + mti->flags = eModifierTypeFlag_AcceptsMesh + | eModifierTypeFlag_SupportsEditmode; + mti->initData = smoothModifier_initData; + mti->copyData = smoothModifier_copyData; + mti->requiredDataMask = smoothModifier_requiredDataMask; + mti->deformVerts = smoothModifier_deformVerts; + mti->deformVertsEM = smoothModifier_deformVertsEM; + + mti = INIT_TYPE(Cast); + mti->type = eModifierTypeType_OnlyDeform; + mti->flags = eModifierTypeFlag_AcceptsCVs + | eModifierTypeFlag_SupportsEditmode; + mti->initData = castModifier_initData; + mti->copyData = castModifier_copyData; + mti->requiredDataMask = castModifier_requiredDataMask; + mti->foreachObjectLink = castModifier_foreachObjectLink; + mti->updateDepgraph = castModifier_updateDepgraph; + mti->deformVerts = castModifier_deformVerts; + mti->deformVertsEM = castModifier_deformVertsEM; + + mti = INIT_TYPE(Wave); + mti->type = eModifierTypeType_OnlyDeform; + mti->flags = eModifierTypeFlag_AcceptsCVs + | eModifierTypeFlag_SupportsEditmode; + mti->initData = waveModifier_initData; + mti->copyData = waveModifier_copyData; + mti->dependsOnTime = waveModifier_dependsOnTime; + mti->requiredDataMask = waveModifier_requiredDataMask; + mti->foreachObjectLink = waveModifier_foreachObjectLink; + mti->foreachIDLink = waveModifier_foreachIDLink; + mti->updateDepgraph = waveModifier_updateDepgraph; + mti->deformVerts = waveModifier_deformVerts; + mti->deformVertsEM = waveModifier_deformVertsEM; + + mti = INIT_TYPE(Armature); + mti->type = eModifierTypeType_OnlyDeform; + mti->flags = eModifierTypeFlag_AcceptsCVs + | eModifierTypeFlag_SupportsEditmode; + mti->initData = armatureModifier_initData; + mti->copyData = armatureModifier_copyData; + mti->requiredDataMask = armatureModifier_requiredDataMask; + mti->isDisabled = armatureModifier_isDisabled; + mti->foreachObjectLink = armatureModifier_foreachObjectLink; + mti->updateDepgraph = armatureModifier_updateDepgraph; + mti->deformVerts = armatureModifier_deformVerts; + mti->deformVertsEM = armatureModifier_deformVertsEM; + mti->deformMatricesEM = armatureModifier_deformMatricesEM; + + mti = INIT_TYPE(Hook); + mti->type = eModifierTypeType_OnlyDeform; + mti->flags = eModifierTypeFlag_AcceptsCVs + | eModifierTypeFlag_SupportsEditmode; + mti->initData = hookModifier_initData; + mti->copyData = hookModifier_copyData; + mti->requiredDataMask = hookModifier_requiredDataMask; + mti->freeData = hookModifier_freeData; + mti->isDisabled = hookModifier_isDisabled; + mti->foreachObjectLink = hookModifier_foreachObjectLink; + mti->updateDepgraph = hookModifier_updateDepgraph; + mti->deformVerts = hookModifier_deformVerts; + mti->deformVertsEM = hookModifier_deformVertsEM; + + mti = INIT_TYPE(Softbody); + mti->type = eModifierTypeType_OnlyDeform; + mti->flags = eModifierTypeFlag_AcceptsCVs + | eModifierTypeFlag_RequiresOriginalData; + mti->deformVerts = softbodyModifier_deformVerts; + + mti = INIT_TYPE(Boolean); + mti->type = eModifierTypeType_Nonconstructive; + mti->flags = eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_RequiresOriginalData; + mti->copyData = booleanModifier_copyData; + mti->isDisabled = booleanModifier_isDisabled; + mti->applyModifier = booleanModifier_applyModifier; + mti->foreachObjectLink = booleanModifier_foreachObjectLink; + mti->updateDepgraph = booleanModifier_updateDepgraph; + + mti = INIT_TYPE(MeshDeform); + mti->type = eModifierTypeType_OnlyDeform; + mti->flags = eModifierTypeFlag_AcceptsCVs + | eModifierTypeFlag_SupportsEditmode; + mti->initData = meshdeformModifier_initData; + mti->freeData = meshdeformModifier_freeData; + mti->copyData = meshdeformModifier_copyData; + mti->requiredDataMask = meshdeformModifier_requiredDataMask; + mti->isDisabled = meshdeformModifier_isDisabled; + mti->foreachObjectLink = meshdeformModifier_foreachObjectLink; + mti->updateDepgraph = meshdeformModifier_updateDepgraph; + mti->deformVerts = meshdeformModifier_deformVerts; + mti->deformVertsEM = meshdeformModifier_deformVertsEM; + + typeArrInit = 0; +#undef INIT_TYPE + } + + if (type>=0 && typestructSize, mti->structName); + + strcpy(md->name, mti->name); + + md->type = type; + md->mode = eModifierMode_Realtime + | eModifierMode_Render | eModifierMode_Expanded; + + if (mti->flags & eModifierTypeFlag_EnableInEditmode) + md->mode |= eModifierMode_Editmode; + + if (mti->initData) mti->initData(md); + + return md; +} + +void modifier_free(ModifierData *md) +{ + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + if (mti->freeData) mti->freeData(md); + if (md->error) MEM_freeN(md->error); + + MEM_freeN(md); +} + +int modifier_dependsOnTime(ModifierData *md) +{ + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + return mti->dependsOnTime && mti->dependsOnTime(md); +} + +int modifier_supportsMapping(ModifierData *md) +{ + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + return ( (mti->flags & eModifierTypeFlag_SupportsEditmode) && + ( (mti->type==eModifierTypeType_OnlyDeform || + (mti->flags & eModifierTypeFlag_SupportsMapping))) ); +} + +ModifierData *modifiers_findByType(Object *ob, ModifierType type) +{ + ModifierData *md = ob->modifiers.first; + + for (; md; md=md->next) + if (md->type==type) + break; + + return md; +} + +void modifiers_clearErrors(Object *ob) +{ + ModifierData *md = ob->modifiers.first; + int qRedraw = 0; + + for (; md; md=md->next) { + if (md->error) { + MEM_freeN(md->error); + md->error = NULL; + + qRedraw = 1; + } + } + + if (qRedraw) allqueue(REDRAWBUTSEDIT, 0); +} + +void modifiers_foreachObjectLink(Object *ob, ObjectWalkFunc walk, + void *userData) +{ + ModifierData *md = ob->modifiers.first; + + for (; md; md=md->next) { + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + if (mti->foreachObjectLink) + mti->foreachObjectLink(md, ob, walk, userData); + } +} + +void modifiers_foreachIDLink(Object *ob, IDWalkFunc walk, void *userData) +{ + ModifierData *md = ob->modifiers.first; + + for (; md; md=md->next) { + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + if(mti->foreachIDLink) mti->foreachIDLink(md, ob, walk, userData); + else if(mti->foreachObjectLink) { + /* each Object can masquerade as an ID, so this should be OK */ + ObjectWalkFunc fp = (ObjectWalkFunc)walk; + mti->foreachObjectLink(md, ob, fp, userData); + } + } +} + +void modifier_copyData(ModifierData *md, ModifierData *target) +{ + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + target->mode = md->mode; + + if (mti->copyData) + mti->copyData(md, target); +} + +int modifier_couldBeCage(ModifierData *md) +{ + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + return ( (md->mode & eModifierMode_Realtime) && + (md->mode & eModifierMode_Editmode) && + (!mti->isDisabled || !mti->isDisabled(md)) && + modifier_supportsMapping(md)); +} + +void modifier_setError(ModifierData *md, char *format, ...) +{ + char buffer[2048]; + va_list ap; + + va_start(ap, format); + vsprintf(buffer, format, ap); + va_end(ap); + + if (md->error) + MEM_freeN(md->error); + + md->error = BLI_strdup(buffer); + + allqueue(REDRAWBUTSEDIT, 0); +} + +/* used for buttons, to find out if the 'draw deformed in editmode' option is + * there + * + * also used in transform_conversion.c, to detect CrazySpace [tm] (2nd arg + * then is NULL) + */ +int modifiers_getCageIndex(Object *ob, int *lastPossibleCageIndex_r) +{ + ModifierData *md = ob->modifiers.first; + int i, cageIndex = -1; + + /* Find the last modifier acting on the cage. */ + for (i=0; md; i++,md=md->next) { + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + if (!(md->mode & eModifierMode_Realtime)) continue; + if (!(md->mode & eModifierMode_Editmode)) continue; + if (mti->isDisabled && mti->isDisabled(md)) continue; + if (!(mti->flags & eModifierTypeFlag_SupportsEditmode)) continue; + if (md->mode & eModifierMode_DisableTemporary) continue; + + if (!modifier_supportsMapping(md)) + break; + + if (lastPossibleCageIndex_r) *lastPossibleCageIndex_r = i; + if (md->mode & eModifierMode_OnCage) + cageIndex = i; + } + + return cageIndex; +} + + +int modifiers_isSoftbodyEnabled(Object *ob) +{ + ModifierData *md = modifiers_findByType(ob, eModifierType_Softbody); + + return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)); +} + +LinkNode *modifiers_calcDataMasks(ModifierData *md, CustomDataMask dataMask) +{ + LinkNode *dataMasks = NULL; + LinkNode *curr, *prev; + + /* build a list of modifier data requirements in reverse order */ + for(; md; md = md->next) { + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + CustomDataMask mask = 0; + + if(mti->requiredDataMask) mask = mti->requiredDataMask(md); + + BLI_linklist_prepend(&dataMasks, (void *)mask); + } + + /* build the list of required data masks - each mask in the list must + * include all elements of the masks that follow it + * + * note the list is currently in reverse order, so "masks that follow it" + * actually means "masks that precede it" at the moment + */ + for(curr = dataMasks, prev = NULL; curr; prev = curr, curr = curr->next) { + if(prev) { + CustomDataMask prev_mask = (CustomDataMask)prev->link; + CustomDataMask curr_mask = (CustomDataMask)curr->link; + + curr->link = (void *)(curr_mask | prev_mask); + } else { + CustomDataMask curr_mask = (CustomDataMask)curr->link; + + curr->link = (void *)(curr_mask | dataMask); + } + } + + /* reverse the list so it's in the correct order */ + BLI_linklist_reverse(&dataMasks); + + return dataMasks; +} + +ModifierData *modifiers_getVirtualModifierList(Object *ob) +{ + /* Kinda hacky, but should be fine since we are never + * reentrant and avoid free hassles. + */ + static ArmatureModifierData amd; + static CurveModifierData cmd; + static LatticeModifierData lmd; + static int init = 1; + + if (init) { + ModifierData *md; + + md = modifier_new(eModifierType_Armature); + amd = *((ArmatureModifierData*) md); + modifier_free(md); + + md = modifier_new(eModifierType_Curve); + cmd = *((CurveModifierData*) md); + modifier_free(md); + + md = modifier_new(eModifierType_Lattice); + lmd = *((LatticeModifierData*) md); + modifier_free(md); + + amd.modifier.mode |= eModifierMode_Virtual; + cmd.modifier.mode |= eModifierMode_Virtual; + lmd.modifier.mode |= eModifierMode_Virtual; + + init = 0; + } + + if (ob->parent) { + if(ob->parent->type==OB_ARMATURE && ob->partype==PARSKEL) { + amd.object = ob->parent; + amd.modifier.next = ob->modifiers.first; + amd.deformflag= ((bArmature *)(ob->parent->data))->deformflag; + return &amd.modifier; + } else if(ob->parent->type==OB_CURVE && ob->partype==PARSKEL) { + cmd.object = ob->parent; + cmd.defaxis = ob->trackflag + 1; + cmd.modifier.next = ob->modifiers.first; + return &cmd.modifier; + } else if(ob->parent->type==OB_LATTICE && ob->partype==PARSKEL) { + lmd.object = ob->parent; + lmd.modifier.next = ob->modifiers.first; + return &lmd.modifier; + } + } + + return ob->modifiers.first; +} +/* Takes an object and returns its first selected armature, else just its + * armature + * This should work for multiple armatures per object + */ +Object *modifiers_isDeformedByArmature(Object *ob) +{ + ModifierData *md = modifiers_getVirtualModifierList(ob); + ArmatureModifierData *amd= NULL; + + /* return the first selected armature, this lets us use multiple armatures + */ + for (; md; md=md->next) { + if (md->type==eModifierType_Armature) { + amd = (ArmatureModifierData*) md; + if (amd->object && (amd->object->flag & SELECT)) + return amd->object; + } + } + + if (amd) /* if were still here then return the last armature */ + return amd->object; + + return NULL; +} + +/* Takes an object and returns its first selected lattice, else just its +* armature +* This should work for multiple armatures per object +*/ +Object *modifiers_isDeformedByLattice(Object *ob) +{ + ModifierData *md = modifiers_getVirtualModifierList(ob); + LatticeModifierData *lmd= NULL; + + /* return the first selected armature, this lets us use multiple armatures + */ + for (; md; md=md->next) { + if (md->type==eModifierType_Lattice) { + lmd = (LatticeModifierData*) md; + if (lmd->object && (lmd->object->flag & SELECT)) + return lmd->object; + } + } + + if (lmd) /* if were still here then return the last lattice */ + return lmd->object; + + return NULL; +} + + + +int modifiers_usesArmature(Object *ob, bArmature *arm) +{ + ModifierData *md = modifiers_getVirtualModifierList(ob); + + for (; md; md=md->next) { + if (md->type==eModifierType_Armature) { + ArmatureModifierData *amd = (ArmatureModifierData*) md; + if (amd->object && amd->object->data==arm) + return 1; + } + } + + return 0; +} + +int modifier_isDeformer(ModifierData *md) +{ + if (md->type==eModifierType_Armature) + return 1; + if (md->type==eModifierType_Curve) + return 1; + if (md->type==eModifierType_Lattice) + return 1; + + return 0; +} + +int modifiers_isDeformed(Object *ob) +{ + ModifierData *md = modifiers_getVirtualModifierList(ob); + + for (; md; md=md->next) { + if(ob==G.obedit && (md->mode & eModifierMode_Editmode)==0); + else if(modifier_isDeformer(md)) + return 1; + } + return 0; +} + diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c new file mode 100644 index 00000000000..961ea21d088 --- /dev/null +++ b/source/blender/blenkernel/intern/nla.c @@ -0,0 +1,190 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" + +#include "DNA_space_types.h" +#include "DNA_nla_types.h" +#include "DNA_action_types.h" +#include "DNA_ID.h" +#include "DNA_ipo_types.h" +#include "DNA_object_types.h" + +#include "BKE_nla.h" +#include "BKE_action.h" +#include "BKE_blender.h" +#include "BKE_library.h" +#include "BKE_object.h" /* for convert_action_to_strip(ob) */ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +/* NOTE: in group.c the strips get copied for group-nla override, this assumes + that strips are one single block, without additional data to be copied */ + +void copy_actionstrip (bActionStrip **dst, bActionStrip **src){ + bActionStrip *dstrip; + bActionStrip *sstrip = *src; + + if (!*src){ + *dst=NULL; + return; + } + + *dst = MEM_dupallocN(sstrip); + + dstrip = *dst; + if (dstrip->act) + dstrip->act->id.us++; + + if (dstrip->ipo) + dstrip->ipo->id.us++; + + if (dstrip->modifiers.first) { + duplicatelist (&dstrip->modifiers, &sstrip->modifiers); + } + +} + +void copy_nlastrips (ListBase *dst, ListBase *src) +{ + bActionStrip *strip; + + dst->first=dst->last=NULL; + + duplicatelist (dst, src); + + /* Update specific data */ + if (!dst->first) + return; + + for (strip = dst->first; strip; strip=strip->next){ + if (strip->act) + strip->act->id.us++; + if (strip->ipo) + strip->ipo->id.us++; + if (strip->modifiers.first) { + ListBase listb; + duplicatelist (&listb, &strip->modifiers); + strip->modifiers= listb; + } + } +} + +/* from editnla, for convert_action_to_strip -- no UI code so should be ok here.. */ +void find_stridechannel(Object *ob, bActionStrip *strip) +{ + if(ob && ob->pose) { + bPoseChannel *pchan; + for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) + if(pchan->flag & POSE_STRIDE) + break; + if(pchan) + BLI_strncpy(strip->stridechannel, pchan->name, 32); + else + strip->stridechannel[0]= 0; + } +} + +//called by convert_nla / bpy api with an object with the action to be converted to a new strip +bActionStrip *convert_action_to_strip (Object *ob) +{ + bActionStrip *nstrip; + + /* Make new actionstrip */ + nstrip = MEM_callocN(sizeof(bActionStrip), "bActionStrip"); + + /* Link the action to the nstrip */ + nstrip->act = ob->action; + id_us_plus(&nstrip->act->id); + calc_action_range(nstrip->act, &nstrip->actstart, &nstrip->actend, 1); + nstrip->start = nstrip->actstart; + nstrip->end = nstrip->actend; + nstrip->flag = ACTSTRIP_SELECT|ACTSTRIP_LOCK_ACTION; + + find_stridechannel(ob, nstrip); + //set_active_strip(ob, nstrip); /* is in editnla as does UI calls */ + + nstrip->repeat = 1.0; + + if(ob->nlastrips.first == NULL) + ob->nlaflag |= OB_NLA_OVERRIDE; + + BLI_addtail(&ob->nlastrips, nstrip); + return nstrip; /* is created, malloced etc. here so is safe to just return the pointer? + this is needed for setting this active in UI, and probably useful for API too */ + +} + + +/* not strip itself! */ +void free_actionstrip(bActionStrip* strip) +{ + if (!strip) + return; + + if (strip->act){ + strip->act->id.us--; + strip->act = NULL; + } + if (strip->ipo){ + strip->ipo->id.us--; + strip->ipo = NULL; + } + if (strip->modifiers.first) { + BLI_freelistN(&strip->modifiers); + } + +} + +void free_nlastrips (ListBase *nlalist) +{ + bActionStrip *strip; + + if (!nlalist->first) + return; + + /* Do any specific freeing */ + for (strip=nlalist->first; strip; strip=strip->next) + { + free_actionstrip (strip); + }; + + /* Free the whole list */ + BLI_freelistN(nlalist); +} diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c new file mode 100644 index 00000000000..651115b7180 --- /dev/null +++ b/source/blender/blenkernel/intern/node.c @@ -0,0 +1,2414 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include +#include + +#include "DNA_ID.h" +#include "DNA_image_types.h" +#include "DNA_node_types.h" +#include "DNA_material_types.h" +#include "DNA_scene_types.h" + +#include "BKE_blender.h" +#include "BKE_colortools.h" +#include "BKE_global.h" +#include "BKE_image.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_node.h" +#include "BKE_texture.h" +#include "BKE_utildefines.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" +#include "BLI_rand.h" +#include "BLI_threads.h" + +#include "PIL_time.h" + +#include "MEM_guardedalloc.h" +#include "IMB_imbuf.h" + +#include "RE_pipeline.h" +#include "RE_shader_ext.h" /* <- TexResult */ +#include "RE_render_ext.h" /* <- ibuf_sample() */ + +#include "CMP_node.h" +#include "SHD_node.h" + +/* not very important, but the stack solver likes to know a maximum */ +#define MAX_SOCKET 64 + +static ListBase empty_list = {NULL, NULL}; +ListBase node_all_composit = {NULL, NULL}; +ListBase node_all_shaders = {NULL, NULL}; + +/* ************** Type stuff ********** */ + +static bNodeType *node_get_type(bNodeTree *ntree, int type, bNodeTree *ngroup) +{ + if(type==NODE_GROUP) { + if(ngroup && GS(ngroup->id.name)==ID_NT) { + return ngroup->owntype; + } + return NULL; + } + else { + bNodeType *ntype = ntree->alltypes.first; + for(; ntype; ntype= ntype->next) + if(ntype->type==type) + return ntype; + + return NULL; + } +} + +void ntreeInitTypes(bNodeTree *ntree) +{ + bNode *node, *next; + + if(ntree->type==NTREE_SHADER) + ntree->alltypes= node_all_shaders; + else if(ntree->type==NTREE_COMPOSIT) + ntree->alltypes= node_all_composit; + else { + ntree->alltypes= empty_list; + printf("Error: no type definitions for nodes\n"); + } + + for(node= ntree->nodes.first; node; node= next) { + next= node->next; + node->typeinfo= node_get_type(ntree, node->type, (bNodeTree *)node->id); + if(node->typeinfo==NULL) { + printf("Error: Node type %s doesn't exist anymore, removed\n", node->name); + nodeFreeNode(ntree, node); + } + } + + ntree->init |= NTREE_TYPE_INIT; +} + +/* only used internal... we depend on type definitions! */ +static bNodeSocket *node_add_socket_type(ListBase *lb, bNodeSocketType *stype) +{ + bNodeSocket *sock= MEM_callocN(sizeof(bNodeSocket), "sock"); + + BLI_strncpy(sock->name, stype->name, NODE_MAXSTR); + if(stype->limit==0) sock->limit= 0xFFF; + else sock->limit= stype->limit; + sock->type= stype->type; + + sock->to_index= stype->own_index; + sock->tosock= stype->internsock; + + sock->ns.vec[0]= stype->val1; + sock->ns.vec[1]= stype->val2; + sock->ns.vec[2]= stype->val3; + sock->ns.vec[3]= stype->val4; + sock->ns.min= stype->min; + sock->ns.max= stype->max; + + if(lb) + BLI_addtail(lb, sock); + + return sock; +} + +static void node_rem_socket(bNodeTree *ntree, ListBase *lb, bNodeSocket *sock) +{ + bNodeLink *link, *next; + + for(link= ntree->links.first; link; link= next) { + next= link->next; + if(link->fromsock==sock || link->tosock==sock) { + nodeRemLink(ntree, link); + } + } + + BLI_remlink(lb, sock); + MEM_freeN(sock); +} + +static bNodeSocket *verify_socket(ListBase *lb, bNodeSocketType *stype) +{ + bNodeSocket *sock; + + for(sock= lb->first; sock; sock= sock->next) { + /* both indices are zero for non-groups, otherwise it's a unique index */ + if(sock->to_index==stype->own_index) + if(strncmp(sock->name, stype->name, NODE_MAXSTR)==0) + break; + } + if(sock) { + sock->type= stype->type; /* in future, read this from tydefs! */ + if(stype->limit==0) sock->limit= 0xFFF; + else sock->limit= stype->limit; + sock->ns.min= stype->min; + sock->ns.max= stype->max; + sock->tosock= stype->internsock; + + BLI_remlink(lb, sock); + + return sock; + } + else { + return node_add_socket_type(NULL, stype); + } +} + +static void verify_socket_list(bNodeTree *ntree, ListBase *lb, bNodeSocketType *stype_first) +{ + bNodeSocketType *stype; + + /* no inputs anymore? */ + if(stype_first==NULL) { + while(lb->first) + node_rem_socket(ntree, lb, lb->first); + } + else { + /* step by step compare */ + stype= stype_first; + while(stype->type != -1) { + stype->sock= verify_socket(lb, stype); + stype++; + } + /* leftovers are removed */ + while(lb->first) + node_rem_socket(ntree, lb, lb->first); + /* and we put back the verified sockets */ + stype= stype_first; + while(stype->type != -1) { + BLI_addtail(lb, stype->sock); + stype++; + } + } +} + +void nodeVerifyType(bNodeTree *ntree, bNode *node) +{ + bNodeType *ntype= node->typeinfo; + + if(ntype) { + /* might add some other verify stuff here */ + + verify_socket_list(ntree, &node->inputs, ntype->inputs); + verify_socket_list(ntree, &node->outputs, ntype->outputs); + } +} + +void ntreeVerifyTypes(bNodeTree *ntree) +{ + bNode *node; + + /* if((ntree->init & NTREE_TYPE_INIT)==0) */ + ntreeInitTypes(ntree); + + /* check inputs and outputs, and remove or insert them */ + for(node= ntree->nodes.first; node; node= node->next) + nodeVerifyType(ntree, node); + +} + +/* ************** Group stuff ********** */ + +bNodeType node_group_typeinfo= { + /* next,prev */ NULL, NULL, + /* type code */ NODE_GROUP, + /* name */ "Group", + /* width+range */ 120, 60, 200, + /* class+opts */ NODE_CLASS_GROUP, NODE_OPTIONS, + /* input sock */ NULL, + /* output sock */ NULL, + /* storage */ "", + /* execfunc */ NULL, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; + +/* tag internal sockets */ +static void group_tag_internal_sockets(bNodeTree *ngroup) +{ + bNode *node; + bNodeSocket *sock; + bNodeLink *link; + + /* clear intern tag, but check already for hidden sockets */ + for(node= ngroup->nodes.first; node; node= node->next) { + for(sock= node->inputs.first; sock; sock= sock->next) + sock->intern= sock->flag & SOCK_HIDDEN; + for(sock= node->outputs.first; sock; sock= sock->next) + sock->intern= sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL); + } + /* set tag */ + for(link= ngroup->links.first; link; link= link->next) { + link->fromsock->intern= 1; + link->tosock->intern= 1; + } + + /* remove link pointer to external links (only happens on create group) */ + for(node= ngroup->nodes.first; node; node= node->next) { + for(sock= node->inputs.first; sock; sock= sock->next) + if(sock->intern==0) + sock->link= NULL; + } + + /* set all intern sockets to own_index zero, makes sure that later use won't mixup */ + for(node= ngroup->nodes.first; node; node= node->next) { + for(sock= node->inputs.first; sock; sock= sock->next) + if(sock->intern) + sock->own_index= 0; + for(sock= node->outputs.first; sock; sock= sock->next) + if(sock->intern) + sock->own_index= 0; + } +} + +/* after editing group, new sockets are zero */ +/* this routine ensures unique identifiers for zero sockets that are exposed */ +static void group_verify_own_indices(bNodeTree *ngroup) +{ + bNode *node; + bNodeSocket *sock; + + for(node= ngroup->nodes.first; node; node= node->next) { + for(sock= node->inputs.first; sock; sock= sock->next) + if(sock->own_index==0 && sock->intern==0) + sock->own_index= ++(ngroup->cur_index); + for(sock= node->outputs.first; sock; sock= sock->next) + if(sock->own_index==0 && sock->intern==0) + sock->own_index= ++(ngroup->cur_index); + } + //printf("internal index %d\n", ngroup->cur_index); +} + + +/* nodetrees can be used as groups, so we need typeinfo structs generated */ +void ntreeMakeOwnType(bNodeTree *ngroup) +{ + bNode *node; + bNodeSocket *sock; + int totin= 0, totout=0, a; + + /* tags socket when internal linked */ + group_tag_internal_sockets(ngroup); + + /* ensure all sockets have own unique id */ + group_verify_own_indices(ngroup); + + /* counting stats */ + for(node= ngroup->nodes.first; node; node= node->next) { + if(node->type==NODE_GROUP) + break; + for(sock= node->inputs.first; sock; sock= sock->next) + if(sock->intern==0) + totin++; + for(sock= node->outputs.first; sock; sock= sock->next) + if(sock->intern==0) + totout++; + } + /* debug: nodetrees in nodetrees not handled yet */ + if(node) { + printf("group in group, not supported yet\n"); + return; + } + + /* free own type struct */ + if(ngroup->owntype) { + if(ngroup->owntype->inputs) + MEM_freeN(ngroup->owntype->inputs); + if(ngroup->owntype->outputs) + MEM_freeN(ngroup->owntype->outputs); + MEM_freeN(ngroup->owntype); + } + + /* make own type struct */ + ngroup->owntype= MEM_callocN(sizeof(bNodeType), "group type"); + *ngroup->owntype= node_group_typeinfo; /* copy data, for init */ + + /* input type arrays */ + if(totin) { + bNodeSocketType *stype; + bNodeSocketType *inputs= MEM_callocN(sizeof(bNodeSocketType)*(totin+1), "bNodeSocketType"); + a= 0; + + for(node= ngroup->nodes.first; node; node= node->next) { + /* nodes are presumed fully verified, stype and socket list are in sync */ + stype= node->typeinfo->inputs; + for(sock= node->inputs.first; sock; sock= sock->next, stype++) { + if(sock->intern==0) { + /* debug only print */ + if(stype==NULL || stype->type==-1) printf("group verification error %s\n", ngroup->id.name); + + inputs[a]= *stype; + inputs[a].own_index= sock->own_index; + inputs[a].internsock= sock; + a++; + } + } + } + inputs[a].type= -1; /* terminator code */ + ngroup->owntype->inputs= inputs; + } + + /* output type arrays */ + if(totout) { + bNodeSocketType *stype; + bNodeSocketType *outputs= MEM_callocN(sizeof(bNodeSocketType)*(totout+1), "bNodeSocketType"); + a= 0; + + for(node= ngroup->nodes.first; node; node= node->next) { + /* nodes are presumed fully verified, stype and socket list are in sync */ + stype= node->typeinfo->outputs; + for(sock= node->outputs.first; sock; sock= sock->next, stype++) { + if(sock->intern==0) { + /* debug only print */ + if(stype==NULL || stype->type==-1) printf("group verification error %s\n", ngroup->id.name); + + outputs[a]= *stype; + outputs[a].own_index= sock->own_index; + outputs[a].internsock= sock; + a++; + } + } + } + outputs[a].type= -1; /* terminator code */ + ngroup->owntype->outputs= outputs; + } + + /* voila, the nodetree has the full definition for generating group-node instances! */ +} + + +static bNodeSocket *groupnode_find_tosock(bNode *gnode, int index) +{ + bNodeSocket *sock; + + for(sock= gnode->inputs.first; sock; sock= sock->next) + if(sock->to_index==index) + return sock; + return NULL; +} + +static bNodeSocket *groupnode_find_fromsock(bNode *gnode, int index) +{ + bNodeSocket *sock; + + for(sock= gnode->outputs.first; sock; sock= sock->next) + if(sock->to_index==index) + return sock; + return NULL; +} + +bNode *nodeMakeGroupFromSelected(bNodeTree *ntree) +{ + bNodeLink *link, *linkn; + bNode *node, *gnode, *nextn; + bNodeSocket *sock; + bNodeTree *ngroup; + float min[2], max[2]; + int totnode=0; + + INIT_MINMAX2(min, max); + + /* is there something to group? also do some clearing */ + for(node= ntree->nodes.first; node; node= node->next) { + if(node->flag & NODE_SELECT) { + /* no groups in groups */ + if(node->type==NODE_GROUP) + return NULL; + DO_MINMAX2( (&node->locx), min, max); + totnode++; + } + node->done= 0; + } + if(totnode==0) return NULL; + + /* check if all connections are OK, no unselected node has both + inputs and outputs to a selection */ + for(link= ntree->links.first; link; link= link->next) { + if(link->fromnode->flag & NODE_SELECT) + link->tonode->done |= 1; + if(link->tonode->flag & NODE_SELECT) + link->fromnode->done |= 2; + } + + for(node= ntree->nodes.first; node; node= node->next) { + if((node->flag & NODE_SELECT)==0) + if(node->done==3) + break; + } + if(node) + return NULL; + + /* OK! new nodetree */ + ngroup= alloc_libblock(&G.main->nodetree, ID_NT, "NodeGroup"); + ngroup->type= ntree->type; + ngroup->alltypes= ntree->alltypes; + + /* move nodes over */ + for(node= ntree->nodes.first; node; node= nextn) { + nextn= node->next; + if(node->flag & NODE_SELECT) { + BLI_remlink(&ntree->nodes, node); + BLI_addtail(&ngroup->nodes, node); + node->locx-= 0.5f*(min[0]+max[0]); + node->locy-= 0.5f*(min[1]+max[1]); + } + } + + /* move links over */ + for(link= ntree->links.first; link; link= linkn) { + linkn= link->next; + if(link->fromnode->flag & link->tonode->flag & NODE_SELECT) { + BLI_remlink(&ntree->links, link); + BLI_addtail(&ngroup->links, link); + } + } + + /* now we can make own group typeinfo */ + ntreeMakeOwnType(ngroup); + + /* make group node */ + gnode= nodeAddNodeType(ntree, NODE_GROUP, ngroup); + gnode->locx= 0.5f*(min[0]+max[0]); + gnode->locy= 0.5f*(min[1]+max[1]); + + /* relink external sockets */ + for(link= ntree->links.first; link; link= linkn) { + linkn= link->next; + + if(link->tonode->flag & NODE_SELECT) { + link->tonode= gnode; + sock= groupnode_find_tosock(gnode, link->tosock->own_index); + if(sock==NULL) { + nodeRemLink(ntree, link); + printf("Removed link, cannot mix internal and external sockets in group\n"); + } + else link->tosock= sock; + } + else if(link->fromnode->flag & NODE_SELECT) { + link->fromnode= gnode; + sock= groupnode_find_fromsock(gnode, link->fromsock->own_index); + if(sock==NULL) { + nodeRemLink(ntree, link); + printf("Removed link, cannot mix internal and external sockets in group\n"); + } + else link->fromsock= sock; + } + } + + /* initialize variables of unused input sockets */ + for(node= ngroup->nodes.first; node; node= node->next) { + for(sock= node->inputs.first; sock; sock= sock->next) { + if(sock->intern==0) { + bNodeSocket *nsock= groupnode_find_tosock(gnode, sock->own_index); + if(nsock) { + QUATCOPY(nsock->ns.vec, sock->ns.vec); + } + } + } + } + return gnode; +} + +/* note: ungroup: group_indices zero! */ + +/* here's a nasty little one, need to check users... */ +/* should become callbackable... */ +void nodeVerifyGroup(bNodeTree *ngroup) +{ + + /* group changed, so we rebuild the type definition */ + ntreeMakeOwnType(ngroup); + + if(ngroup->type==NTREE_SHADER) { + Material *ma; + for(ma= G.main->mat.first; ma; ma= ma->id.next) { + if(ma->nodetree) { + bNode *node; + + /* find if group is in tree */ + for(node= ma->nodetree->nodes.first; node; node= node->next) + if(node->id == (ID *)ngroup) + break; + + if(node) { + /* set all type pointers OK */ + ntreeInitTypes(ma->nodetree); + + for(node= ma->nodetree->nodes.first; node; node= node->next) + if(node->id == (ID *)ngroup) + nodeVerifyType(ma->nodetree, node); + } + } + } + } + else if(ngroup->type==NTREE_COMPOSIT) { + Scene *sce; + for(sce= G.main->scene.first; sce; sce= sce->id.next) { + if(sce->nodetree) { + bNode *node; + + /* find if group is in tree */ + for(node= sce->nodetree->nodes.first; node; node= node->next) + if(node->id == (ID *)ngroup) + break; + + if(node) { + /* set all type pointers OK */ + ntreeInitTypes(sce->nodetree); + + for(node= sce->nodetree->nodes.first; node; node= node->next) + if(node->id == (ID *)ngroup) + nodeVerifyType(sce->nodetree, node); + } + } + } + } +} + +/* also to check all users of groups. Now only used in editor for hide/unhide */ +/* should become callbackable? */ +void nodeGroupSocketUseFlags(bNodeTree *ngroup) +{ + bNode *node; + bNodeSocket *sock; + + /* clear flags */ + for(node= ngroup->nodes.first; node; node= node->next) { + for(sock= node->inputs.first; sock; sock= sock->next) + sock->flag &= ~SOCK_IN_USE; + for(sock= node->outputs.first; sock; sock= sock->next) + sock->flag &= ~SOCK_IN_USE; + } + + /* tag all thats in use */ + if(ngroup->type==NTREE_SHADER) { + Material *ma; + for(ma= G.main->mat.first; ma; ma= ma->id.next) { + if(ma->nodetree) { + for(node= ma->nodetree->nodes.first; node; node= node->next) { + if(node->id==(ID *)ngroup) { + for(sock= node->inputs.first; sock; sock= sock->next) + if(sock->link) + if(sock->tosock) + sock->tosock->flag |= SOCK_IN_USE; + for(sock= node->outputs.first; sock; sock= sock->next) + if(nodeCountSocketLinks(ma->nodetree, sock)) + if(sock->tosock) + sock->tosock->flag |= SOCK_IN_USE; + } + } + } + } + } + else if(ngroup->type==NTREE_COMPOSIT) { + Scene *sce; + for(sce= G.main->scene.first; sce; sce= sce->id.next) { + if(sce->nodetree) { + for(node= sce->nodetree->nodes.first; node; node= node->next) { + if(node->id==(ID *)ngroup) { + for(sock= node->inputs.first; sock; sock= sock->next) + if(sock->link) + if(sock->tosock) + sock->tosock->flag |= SOCK_IN_USE; + for(sock= node->outputs.first; sock; sock= sock->next) + if(nodeCountSocketLinks(sce->nodetree, sock)) + if(sock->tosock) + sock->tosock->flag |= SOCK_IN_USE; + } + } + } + } + } +} + +static void find_node_with_socket(bNodeTree *ntree, bNodeSocket *sock, bNode **nodep, int *sockindex) +{ + bNode *node; + bNodeSocket *tsock; + int index= 0; + + for(node= ntree->nodes.first; node; node= node->next) { + for(index=0, tsock= node->inputs.first; tsock; tsock= tsock->next, index++) + if(tsock==sock) + break; + if(tsock) + break; + for(index=0, tsock= node->outputs.first; tsock; tsock= tsock->next, index++) + if(tsock==sock) + break; + if(tsock) + break; + } + if(node) { + *nodep= node; + *sockindex= index; + } + else { + *nodep= NULL; + } +} + +/* returns 1 if its OK */ +int nodeGroupUnGroup(bNodeTree *ntree, bNode *gnode) +{ + bNodeLink *link, *linkn; + bNode *node, *nextn; + bNodeTree *ngroup, *wgroup; + int index; + + ngroup= (bNodeTree *)gnode->id; + if(ngroup==NULL) return 0; + + /* clear new pointers, set in copytree */ + for(node= ntree->nodes.first; node; node= node->next) + node->new_node= NULL; + + wgroup= ntreeCopyTree(ngroup, 0); + + /* add the nodes into the ntree */ + for(node= wgroup->nodes.first; node; node= nextn) { + nextn= node->next; + BLI_remlink(&wgroup->nodes, node); + BLI_addtail(&ntree->nodes, node); + node->locx+= gnode->locx; + node->locy+= gnode->locy; + node->flag |= NODE_SELECT; + } + /* and the internal links */ + for(link= wgroup->links.first; link; link= linkn) { + linkn= link->next; + BLI_remlink(&wgroup->links, link); + BLI_addtail(&ntree->links, link); + } + + /* restore links to and from the gnode */ + for(link= ntree->links.first; link; link= link->next) { + if(link->tonode==gnode) { + /* link->tosock->tosock is on the node we look for */ + find_node_with_socket(ngroup, link->tosock->tosock, &nextn, &index); + if(nextn==NULL) printf("wrong stuff!\n"); + else if(nextn->new_node==NULL) printf("wrong stuff too!\n"); + else { + link->tonode= nextn->new_node; + link->tosock= BLI_findlink(&link->tonode->inputs, index); + } + } + else if(link->fromnode==gnode) { + /* link->fromsock->tosock is on the node we look for */ + find_node_with_socket(ngroup, link->fromsock->tosock, &nextn, &index); + if(nextn==NULL) printf("1 wrong stuff!\n"); + else if(nextn->new_node==NULL) printf("1 wrong stuff too!\n"); + else { + link->fromnode= nextn->new_node; + link->fromsock= BLI_findlink(&link->fromnode->outputs, index); + } + } + } + + /* remove the gnode & work tree */ + free_libblock(&G.main->nodetree, wgroup); + + nodeFreeNode(ntree, gnode); + + /* solve order goes fine, but the level tags not... doing it twice works for now. solve this once */ + ntreeSolveOrder(ntree); + ntreeSolveOrder(ntree); + + return 1; +} + +/* ************** Add stuff ********** */ + +bNode *nodeAddNodeType(bNodeTree *ntree, int type, bNodeTree *ngroup) +{ + bNode *node; + bNodeType *ntype= node_get_type(ntree, type, ngroup); + bNodeSocketType *stype; + + node= MEM_callocN(sizeof(bNode), "new node"); + BLI_addtail(&ntree->nodes, node); + node->typeinfo= ntype; + + if(ngroup) + BLI_strncpy(node->name, ngroup->id.name+2, NODE_MAXSTR); + else + BLI_strncpy(node->name, ntype->name, NODE_MAXSTR); + node->type= ntype->type; + node->flag= NODE_SELECT|ntype->flag; + node->width= ntype->width; + node->miniwidth= 42.0f; /* small value only, allows print of first chars */ + + if(type==NODE_GROUP) + node->id= (ID *)ngroup; + + if(ntype->inputs) { + stype= ntype->inputs; + while(stype->type != -1) { + node_add_socket_type(&node->inputs, stype); + stype++; + } + } + if(ntype->outputs) { + stype= ntype->outputs; + while(stype->type != -1) { + node_add_socket_type(&node->outputs, stype); + stype++; + } + } + + /* need init handler later? */ + /* got it-bob*/ + if(ntype->initfunc!=NULL) + ntype->initfunc(node); + + return node; +} + +/* keep socket listorder identical, for copying links */ +/* ntree is the target tree */ +bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node) +{ + bNode *nnode= MEM_callocN(sizeof(bNode), "dupli node"); + bNodeSocket *sock; + + *nnode= *node; + BLI_addtail(&ntree->nodes, nnode); + + duplicatelist(&nnode->inputs, &node->inputs); + for(sock= nnode->inputs.first; sock; sock= sock->next) + sock->own_index= 0; + + duplicatelist(&nnode->outputs, &node->outputs); + for(sock= nnode->outputs.first; sock; sock= sock->next) { + sock->own_index= 0; + sock->stack_index= 0; + sock->ns.data= NULL; + } + + if(nnode->id) + nnode->id->us++; + + if(node->typeinfo->copystoragefunc) + node->typeinfo->copystoragefunc(node, nnode); + + node->new_node= nnode; + nnode->new_node= NULL; + nnode->preview= NULL; + + return nnode; +} + +bNodeLink *nodeAddLink(bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, bNode *tonode, bNodeSocket *tosock) +{ + bNodeLink *link= MEM_callocN(sizeof(bNodeLink), "link"); + + BLI_addtail(&ntree->links, link); + link->fromnode= fromnode; + link->fromsock= fromsock; + link->tonode= tonode; + link->tosock= tosock; + + return link; +} + +void nodeRemLink(bNodeTree *ntree, bNodeLink *link) +{ + BLI_remlink(&ntree->links, link); + if(link->tosock) + link->tosock->link= NULL; + MEM_freeN(link); +} + + +bNodeTree *ntreeAddTree(int type) +{ + bNodeTree *ntree= MEM_callocN(sizeof(bNodeTree), "new node tree"); + ntree->type= type; + ntree->alltypes.first = NULL; + ntree->alltypes.last = NULL; + + ntreeInitTypes(ntree); + return ntree; +} + +bNodeTree *ntreeCopyTree(bNodeTree *ntree, int internal_select) +{ + bNodeTree *newtree; + bNode *node, *nnode, *last; + bNodeLink *link, *nlink; + bNodeSocket *sock; + int a; + + if(ntree==NULL) return NULL; + + if(internal_select==0) { + /* is ntree part of library? */ + for(newtree=G.main->nodetree.first; newtree; newtree= newtree->id.next) + if(newtree==ntree) break; + if(newtree) + newtree= copy_libblock(ntree); + else + newtree= MEM_dupallocN(ntree); + newtree->nodes.first= newtree->nodes.last= NULL; + newtree->links.first= newtree->links.last= NULL; + } + else + newtree= ntree; + + last= ntree->nodes.last; + for(node= ntree->nodes.first; node; node= node->next) { + + node->new_node= NULL; + if(internal_select==0 || (node->flag & NODE_SELECT)) { + nnode= nodeCopyNode(newtree, node); /* sets node->new */ + if(internal_select) { + node->flag &= ~NODE_SELECT; + nnode->flag |= NODE_SELECT; + } + node->flag &= ~NODE_ACTIVE; + } + if(node==last) break; + } + + /* check for copying links */ + for(link= ntree->links.first; link; link= link->next) { + if(link->fromnode->new_node && link->tonode->new_node) { + nlink= nodeAddLink(newtree, link->fromnode->new_node, NULL, link->tonode->new_node, NULL); + /* sockets were copied in order */ + for(a=0, sock= link->fromnode->outputs.first; sock; sock= sock->next, a++) { + if(sock==link->fromsock) + break; + } + nlink->fromsock= BLI_findlink(&link->fromnode->new_node->outputs, a); + + for(a=0, sock= link->tonode->inputs.first; sock; sock= sock->next, a++) { + if(sock==link->tosock) + break; + } + nlink->tosock= BLI_findlink(&link->tonode->new_node->inputs, a); + } + } + + /* own type definition for group usage */ + if(internal_select==0) { + if(ntree->owntype) { + newtree->owntype= MEM_dupallocN(ntree->owntype); + if(ntree->owntype->inputs) + newtree->owntype->inputs= MEM_dupallocN(ntree->owntype->inputs); + if(ntree->owntype->outputs) + newtree->owntype->outputs= MEM_dupallocN(ntree->owntype->outputs); + } + } + /* weird this is required... there seem to be link pointers wrong still? */ + /* anyhoo, doing this solves crashes on copying entire tree (copy scene) and delete nodes */ + ntreeSolveOrder(newtree); + + return newtree; +} + +/* ************** Free stuff ********** */ + +/* goes over entire tree */ +static void node_unlink_node(bNodeTree *ntree, bNode *node) +{ + bNodeLink *link, *next; + bNodeSocket *sock; + ListBase *lb; + + for(link= ntree->links.first; link; link= next) { + next= link->next; + + if(link->fromnode==node) { + lb= &node->outputs; + NodeTagChanged(ntree, link->tonode); + } + else if(link->tonode==node) + lb= &node->inputs; + else + lb= NULL; + + if(lb) { + for(sock= lb->first; sock; sock= sock->next) { + if(link->fromsock==sock || link->tosock==sock) + break; + } + if(sock) { + nodeRemLink(ntree, link); + } + } + } +} + +static void composit_free_node_cache(bNode *node) +{ + bNodeSocket *sock; + + for(sock= node->outputs.first; sock; sock= sock->next) { + if(sock->ns.data) { + free_compbuf(sock->ns.data); + sock->ns.data= NULL; + } + } +} + +void nodeFreeNode(bNodeTree *ntree, bNode *node) +{ + node_unlink_node(ntree, node); + BLI_remlink(&ntree->nodes, node); + + /* since it is called while free database, node->id is undefined */ + + if(ntree->type==NTREE_COMPOSIT) + composit_free_node_cache(node); + BLI_freelistN(&node->inputs); + BLI_freelistN(&node->outputs); + + if(node->preview) { + if(node->preview->rect) + MEM_freeN(node->preview->rect); + MEM_freeN(node->preview); + } + if(node->typeinfo && node->typeinfo->freestoragefunc) { + node->typeinfo->freestoragefunc(node); + } + MEM_freeN(node); +} + +/* do not free ntree itself here, free_libblock calls this function too */ +void ntreeFreeTree(bNodeTree *ntree) +{ + bNode *node, *next; + + if(ntree==NULL) return; + + ntreeEndExecTree(ntree); /* checks for if it is still initialized */ + + BLI_freelistN(&ntree->links); /* do first, then unlink_node goes fast */ + + for(node= ntree->nodes.first; node; node= next) { + next= node->next; + nodeFreeNode(ntree, node); + } + + if(ntree->owntype) { + if(ntree->owntype->inputs) + MEM_freeN(ntree->owntype->inputs); + if(ntree->owntype->outputs) + MEM_freeN(ntree->owntype->outputs); + MEM_freeN(ntree->owntype); + } +} + +void ntreeFreeCache(bNodeTree *ntree) +{ + bNode *node; + + if(ntree==NULL) return; + + if(ntree->type==NTREE_COMPOSIT) + for(node= ntree->nodes.first; node; node= node->next) + composit_free_node_cache(node); + +} + +void ntreeMakeLocal(bNodeTree *ntree) +{ + int local=0, lib=0; + + /* - only lib users: do nothing + * - only local users: set flag + * - mixed: make copy + */ + + if(ntree->id.lib==NULL) return; + if(ntree->id.us==1) { + ntree->id.lib= 0; + ntree->id.flag= LIB_LOCAL; + new_id(0, (ID *)ntree, 0); + return; + } + + /* now check users of groups... again typedepending, callback... */ + if(ntree->type==NTREE_SHADER) { + Material *ma; + for(ma= G.main->mat.first; ma; ma= ma->id.next) { + if(ma->nodetree) { + bNode *node; + + /* find if group is in tree */ + for(node= ma->nodetree->nodes.first; node; node= node->next) { + if(node->id == (ID *)ntree) { + if(ma->id.lib) lib= 1; + else local= 1; + } + } + } + } + } + else if(ntree->type==NTREE_COMPOSIT) { + Scene *sce; + for(sce= G.main->scene.first; sce; sce= sce->id.next) { + if(sce->nodetree) { + bNode *node; + + /* find if group is in tree */ + for(node= sce->nodetree->nodes.first; node; node= node->next) { + if(node->id == (ID *)ntree) { + if(sce->id.lib) lib= 1; + else local= 1; + } + } + } + } + } + + /* if all users are local, we simply make tree local */ + if(local && lib==0) { + ntree->id.lib= NULL; + ntree->id.flag= LIB_LOCAL; + new_id(0, (ID *)ntree, 0); + } + else if(local && lib) { + /* this is the mixed case, we copy the tree and assign it to local users */ + bNodeTree *newtree= ntreeCopyTree(ntree, 0); + + newtree->id.us= 0; + + if(ntree->type==NTREE_SHADER) { + Material *ma; + for(ma= G.main->mat.first; ma; ma= ma->id.next) { + if(ma->nodetree) { + bNode *node; + + /* find if group is in tree */ + for(node= ma->nodetree->nodes.first; node; node= node->next) { + if(node->id == (ID *)ntree) { + if(ma->id.lib==NULL) { + node->id= &newtree->id; + newtree->id.us++; + ntree->id.us--; + } + } + } + } + } + } + else if(ntree->type==NTREE_COMPOSIT) { + Scene *sce; + for(sce= G.main->scene.first; sce; sce= sce->id.next) { + if(sce->nodetree) { + bNode *node; + + /* find if group is in tree */ + for(node= sce->nodetree->nodes.first; node; node= node->next) { + if(node->id == (ID *)ntree) { + if(sce->id.lib==NULL) { + node->id= &newtree->id; + newtree->id.us++; + ntree->id.us--; + } + } + } + } + } + } + } +} + + +/* ************ find stuff *************** */ + +static int ntreeHasType(bNodeTree *ntree, int type) +{ + bNode *node; + + if(ntree) + for(node= ntree->nodes.first; node; node= node->next) + if(node->type == type) + return 1; + return 0; +} + +bNodeLink *nodeFindLink(bNodeTree *ntree, bNodeSocket *from, bNodeSocket *to) +{ + bNodeLink *link; + + for(link= ntree->links.first; link; link= link->next) { + if(link->fromsock==from && link->tosock==to) + return link; + if(link->fromsock==to && link->tosock==from) /* hrms? */ + return link; + } + return NULL; +} + +int nodeCountSocketLinks(bNodeTree *ntree, bNodeSocket *sock) +{ + bNodeLink *link; + int tot= 0; + + for(link= ntree->links.first; link; link= link->next) { + if(link->fromsock==sock || link->tosock==sock) + tot++; + } + return tot; +} + +bNode *nodeGetActive(bNodeTree *ntree) +{ + bNode *node; + + if(ntree==NULL) return NULL; + + for(node= ntree->nodes.first; node; node= node->next) + if(node->flag & NODE_ACTIVE) + break; + return node; +} + +/* two active flags, ID nodes have special flag for buttons display */ +bNode *nodeGetActiveID(bNodeTree *ntree, short idtype) +{ + bNode *node; + + if(ntree==NULL) return NULL; + + for(node= ntree->nodes.first; node; node= node->next) + if(node->id && GS(node->id->name)==idtype) + if(node->flag & NODE_ACTIVE_ID) + break; + return node; +} + +/* two active flags, ID nodes have special flag for buttons display */ +void nodeClearActiveID(bNodeTree *ntree, short idtype) +{ + bNode *node; + + if(ntree==NULL) return; + + for(node= ntree->nodes.first; node; node= node->next) + if(node->id && GS(node->id->name)==idtype) + node->flag &= ~NODE_ACTIVE_ID; +} + +/* two active flags, ID nodes have special flag for buttons display */ +void nodeSetActive(bNodeTree *ntree, bNode *node) +{ + bNode *tnode; + + /* make sure only one node is active, and only one per ID type */ + for(tnode= ntree->nodes.first; tnode; tnode= tnode->next) { + tnode->flag &= ~NODE_ACTIVE; + + if(node->id && tnode->id) { + if(GS(node->id->name) == GS(tnode->id->name)) + tnode->flag &= ~NODE_ACTIVE_ID; + } + } + + node->flag |= NODE_ACTIVE; + if(node->id) + node->flag |= NODE_ACTIVE_ID; +} + +/* use flags are not persistant yet, groups might need different tagging, so we do it each time + when we need to get this info */ +void ntreeSocketUseFlags(bNodeTree *ntree) +{ + bNode *node; + bNodeSocket *sock; + bNodeLink *link; + + /* clear flags */ + for(node= ntree->nodes.first; node; node= node->next) { + for(sock= node->inputs.first; sock; sock= sock->next) + sock->flag &= ~SOCK_IN_USE; + for(sock= node->outputs.first; sock; sock= sock->next) + sock->flag &= ~SOCK_IN_USE; + } + + /* tag all thats in use */ + for(link= ntree->links.first; link; link= link->next) { + link->fromsock->flag |= SOCK_IN_USE; + link->tosock->flag |= SOCK_IN_USE; + } +} + +/* ************** dependency stuff *********** */ + +/* node is guaranteed to be not checked before */ +static int node_recurs_check(bNode *node, bNode ***nsort, int level) +{ + bNode *fromnode; + bNodeSocket *sock; + int has_inputlinks= 0; + + node->done= 1; + level++; + + for(sock= node->inputs.first; sock; sock= sock->next) { + if(sock->link) { + has_inputlinks= 1; + fromnode= sock->link->fromnode; + if(fromnode->done==0) { + fromnode->level= node_recurs_check(fromnode, nsort, level); + } + } + } +// printf("node sort %s level %d\n", node->name, level); + **nsort= node; + (*nsort)++; + + if(has_inputlinks) + return level; + else + return 0xFFF; +} + +void ntreeSolveOrder(bNodeTree *ntree) +{ + bNode *node, **nodesort, **nsort; + bNodeSocket *sock; + bNodeLink *link; + int a, totnode=0; + + /* the solve-order is called on each tree change, so we should be sure no exec can be running */ + ntreeEndExecTree(ntree); + + /* set links pointers the input sockets, to find dependencies */ + /* first clear data */ + for(node= ntree->nodes.first; node; node= node->next) { + node->done= 0; + totnode++; + for(sock= node->inputs.first; sock; sock= sock->next) + sock->link= NULL; + } + if(totnode==0) + return; + + for(link= ntree->links.first; link; link= link->next) { + link->tosock->link= link; + } + + nsort= nodesort= MEM_callocN(totnode*sizeof(void *), "sorted node array"); + + /* recursive check */ + for(node= ntree->nodes.first; node; node= node->next) { + if(node->done==0) { + node->level= node_recurs_check(node, &nsort, 0); + } + } + + /* re-insert nodes in order, first a paranoia check */ + for(a=0; anodes.first= ntree->nodes.last= NULL; + for(a=0; anodes, nodesort[a]); + } + + MEM_freeN(nodesort); + + /* find the active outputs, might become tree type dependant handler */ + for(node= ntree->nodes.first; node; node= node->next) { + if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) { + bNode *tnode; + int output= 0; + + /* we need a check for which output node should be tagged like this, below an exception */ + if(node->type==CMP_NODE_OUTPUT_FILE) + continue; + + /* there is more types having output class, each one is checked */ + for(tnode= ntree->nodes.first; tnode; tnode= tnode->next) { + if(tnode->typeinfo->nclass==NODE_CLASS_OUTPUT) { + if(tnode->type==node->type) { + if(tnode->flag & NODE_DO_OUTPUT) { + output++; + if(output>1) + tnode->flag &= ~NODE_DO_OUTPUT; + } + } + } + } + if(output==0) + node->flag |= NODE_DO_OUTPUT; + } + } + + /* here we could recursively set which nodes have to be done, + might be different for editor or for "real" use... */ +} + +/* should be callback! */ +void NodeTagChanged(bNodeTree *ntree, bNode *node) +{ + if(ntree->type==NTREE_COMPOSIT) { + bNodeSocket *sock; + + for(sock= node->outputs.first; sock; sock= sock->next) { + if(sock->ns.data) { + free_compbuf(sock->ns.data); + sock->ns.data= NULL; + + //if(node->preview && node->preview->rect) { + // MEM_freeN(node->preview->rect); + // node->preview->rect= NULL; + //} + + } + } + node->need_exec= 1; + } +} + +void NodeTagIDChanged(bNodeTree *ntree, ID *id) +{ + if(id==NULL) + return; + + if(ntree->type==NTREE_COMPOSIT) { + bNode *node; + + for(node= ntree->nodes.first; node; node= node->next) + if(node->id==id) + NodeTagChanged(ntree, node); + } +} + + +/* *************** preview *********** */ + +/* if node->preview, then we assume the rect to exist */ + +static void nodeInitPreview(bNode *node, int xsize, int ysize) +{ + + if(node->preview==NULL) { + node->preview= MEM_callocN(sizeof(bNodePreview), "node preview"); +// printf("added preview %s\n", node->name); + } + + /* node previews can get added with variable size this way */ + if(xsize==0 || ysize==0) + return; + + /* sanity checks & initialize */ + if(node->preview->rect) { + if(node->preview->xsize!=xsize && node->preview->ysize!=ysize) { + MEM_freeN(node->preview->rect); + node->preview->rect= NULL; + } + } + + if(node->preview->rect==NULL) { + node->preview->rect= MEM_callocN(4*xsize + xsize*ysize*sizeof(float)*4, "node preview rect"); + node->preview->xsize= xsize; + node->preview->ysize= ysize; + } +} + +void ntreeInitPreview(bNodeTree *ntree, int xsize, int ysize) +{ + bNode *node; + + if(ntree==NULL) + return; + + for(node= ntree->nodes.first; node; node= node->next) { + if(node->typeinfo->flag & NODE_PREVIEW) /* hrms, check for closed nodes? */ + nodeInitPreview(node, xsize, ysize); + if(node->type==NODE_GROUP && (node->flag & NODE_GROUP_EDIT)) + ntreeInitPreview((bNodeTree *)node->id, xsize, ysize); + } +} + +static void nodeClearPreview(bNode *node) +{ + if(node->preview && node->preview->rect) + memset(node->preview->rect, 0, MEM_allocN_len(node->preview->rect)); +} + +/* use it to enforce clear */ +void ntreeClearPreview(bNodeTree *ntree) +{ + bNode *node; + + if(ntree==NULL) + return; + + for(node= ntree->nodes.first; node; node= node->next) { + if(node->typeinfo->flag & NODE_PREVIEW) + nodeClearPreview(node); + if(node->type==NODE_GROUP && (node->flag & NODE_GROUP_EDIT)) + ntreeClearPreview((bNodeTree *)node->id); + } +} + +/* hack warning! this function is only used for shader previews, and + since it gets called multiple times per pixel for Ztransp we only + add the color once. Preview gets cleared before it starts render though */ +void nodeAddToPreview(bNode *node, float *col, int x, int y) +{ + bNodePreview *preview= node->preview; + if(preview) { + if(x>=0 && y>=0) { + if(xxsize && yysize) { + float *tar= preview->rect+ 4*((preview->xsize*y) + x); + if(tar[0]==0.0f) { + QUATCOPY(tar, col); + } + } + //else printf("prv out bound x y %d %d\n", x, y); + } + //else printf("prv out bound x y %d %d\n", x, y); + } +} + + + +/* ******************* executing ************* */ + +/* see notes at ntreeBeginExecTree */ +static void group_node_get_stack(bNode *node, bNodeStack *stack, bNodeStack **in, bNodeStack **out, bNodeStack **gin, bNodeStack **gout) +{ + bNodeSocket *sock; + + /* build pointer stack */ + for(sock= node->inputs.first; sock; sock= sock->next) { + if(sock->intern) { + /* yep, intern can have link or is hidden socket */ + if(sock->link) + *(in++)= stack + sock->link->fromsock->stack_index; + else + *(in++)= &sock->ns; + } + else + *(in++)= gin[sock->stack_index_ext]; + } + + for(sock= node->outputs.first; sock; sock= sock->next) { + if(sock->intern) + *(out++)= stack + sock->stack_index; + else + *(out++)= gout[sock->stack_index_ext]; + } +} + +static void node_group_execute(bNodeStack *stack, void *data, bNode *gnode, bNodeStack **in, bNodeStack **out) +{ + bNode *node; + bNodeTree *ntree= (bNodeTree *)gnode->id; + bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */ + bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */ + + if(ntree==NULL) return; + + stack+= gnode->stack_index; + + for(node= ntree->nodes.first; node; node= node->next) { + if(node->typeinfo->execfunc) { + group_node_get_stack(node, stack, nsin, nsout, in, out); + + /* for groups, only execute outputs for edited group */ + if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) { + if(gnode->flag & NODE_GROUP_EDIT) + if(node->flag & NODE_DO_OUTPUT) + node->typeinfo->execfunc(data, node, nsin, nsout); + } + else + node->typeinfo->execfunc(data, node, nsin, nsout); + } + } + + /* free internal group output nodes */ + if(ntree->type==NTREE_COMPOSIT) { + for(node= ntree->nodes.first; node; node= node->next) { + if(node->typeinfo->execfunc) { + bNodeSocket *sock; + + for(sock= node->outputs.first; sock; sock= sock->next) { + if(sock->intern) { + bNodeStack *ns= stack + sock->stack_index; + if(ns->data) { + free_compbuf(ns->data); + ns->data= NULL; + } + } + } + } + } + } +} + +/* recursively called for groups */ +/* we set all trees on own local indices, but put a total counter + in the groups, so each instance of a group has own stack */ +static int ntree_begin_exec_tree(bNodeTree *ntree) +{ + bNode *node; + bNodeSocket *sock; + int index= 0, index_in= 0, index_out= 0; + + if((ntree->init & NTREE_TYPE_INIT)==0) + ntreeInitTypes(ntree); + + /* create indices for stack, check preview */ + for(node= ntree->nodes.first; node; node= node->next) { + + for(sock= node->inputs.first; sock; sock= sock->next) { + if(sock->intern==0) + sock->stack_index_ext= index_in++; + } + + for(sock= node->outputs.first; sock; sock= sock->next) { + sock->stack_index= index++; + if(sock->intern==0) + sock->stack_index_ext= index_out++; + } + + if(node->type==NODE_GROUP) { + if(node->id) { + node->stack_index= index; + index+= ntree_begin_exec_tree((bNodeTree *)node->id); + } + } + } + + return index; +} + +/* copy socket compbufs to stack, initialize usage of curve nodes */ +static void composit_begin_exec(bNodeTree *ntree, int is_group) +{ + bNode *node; + bNodeSocket *sock; + + for(node= ntree->nodes.first; node; node= node->next) { + + /* initialize needed for groups */ + node->exec= 0; + + if(is_group==0) { + for(sock= node->outputs.first; sock; sock= sock->next) { + bNodeStack *ns= ntree->stack[0] + sock->stack_index; + + if(sock->ns.data) { + ns->data= sock->ns.data; + sock->ns.data= NULL; + } + } + } + /* cannot initialize them while using in threads */ + if(ELEM3(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB)) { + curvemapping_initialize(node->storage); + if(node->type==CMP_NODE_CURVE_RGB) + curvemapping_premultiply(node->storage, 0); + } + if(node->type==NODE_GROUP) + composit_begin_exec((bNodeTree *)node->id, 1); + + } +} + +/* copy stack compbufs to sockets */ +static void composit_end_exec(bNodeTree *ntree, int is_group) +{ + extern void print_compbuf(char *str, struct CompBuf *cbuf); + bNode *node; + bNodeStack *ns; + int a; + + for(node= ntree->nodes.first; node; node= node->next) { + if(is_group==0) { + bNodeSocket *sock; + + for(sock= node->outputs.first; sock; sock= sock->next) { + ns= ntree->stack[0] + sock->stack_index; + if(ns->data) { + sock->ns.data= ns->data; + ns->data= NULL; + } + } + } + if(node->type==CMP_NODE_CURVE_RGB) + curvemapping_premultiply(node->storage, 1); + + if(node->type==NODE_GROUP) + composit_end_exec((bNodeTree *)node->id, 1); + + node->need_exec= 0; + } + + if(is_group==0) { + /* internally, group buffers are not stored */ + for(ns= ntree->stack[0], a=0; astacksize; a++, ns++) { + if(ns->data) { + printf("freed leftover buffer from stack\n"); + free_compbuf(ns->data); + } + } + } +} + +static void group_tag_used_outputs(bNode *gnode, bNodeStack *stack) +{ + bNodeTree *ntree= (bNodeTree *)gnode->id; + bNode *node; + + stack+= gnode->stack_index; + + for(node= ntree->nodes.first; node; node= node->next) { + if(node->typeinfo->execfunc) { + bNodeSocket *sock; + + for(sock= node->inputs.first; sock; sock= sock->next) { + if(sock->intern) { + if(sock->link) { + bNodeStack *ns= stack + sock->link->fromsock->stack_index; + ns->hasoutput= 1; + ns->sockettype= sock->link->fromsock->type; + } + else + sock->ns.sockettype= sock->type; + } + } + } + } +} + +/* stack indices make sure all nodes only write in allocated data, for making it thread safe */ +/* only root tree gets the stack, to enable instances to have own stack entries */ +/* only two threads now! */ +/* per tree (and per group) unique indices are created */ +/* the index_ext we need to be able to map from groups to the group-node own stack */ + +void ntreeBeginExecTree(bNodeTree *ntree) +{ + /* let's make it sure */ + if(ntree->init & NTREE_EXEC_INIT) + return; + + /* allocate the stack pointer array */ + ntree->stack= MEM_callocN(BLENDER_MAX_THREADS*sizeof(void *), "stack array"); + + /* goes recursive over all groups */ + ntree->stacksize= ntree_begin_exec_tree(ntree); + + if(ntree->stacksize) { + bNode *node; + bNodeStack *ns; + int a; + + /* allocate the base stack */ + ns=ntree->stack[0]= MEM_callocN(ntree->stacksize*sizeof(bNodeStack), "node stack"); + + /* tag inputs, the get_stack() gives own socket stackdata if not in use */ + for(a=0; astacksize; a++, ns++) ns->hasinput= 1; + + /* tag used outputs, so we know when we can skip operations */ + for(node= ntree->nodes.first; node; node= node->next) { + bNodeSocket *sock; + for(sock= node->inputs.first; sock; sock= sock->next) { + if(sock->link) { + ns= ntree->stack[0] + sock->link->fromsock->stack_index; + ns->hasoutput= 1; + ns->sockettype= sock->link->fromsock->type; + } + else + sock->ns.sockettype= sock->type; + } + if(node->type==NODE_GROUP && node->id) + group_tag_used_outputs(node, ntree->stack[0]); + } + + /* composite does 1 node per thread, so no multiple stacks needed */ + if(ntree->type==NTREE_COMPOSIT) + composit_begin_exec(ntree, 0); + else { + for(a=1; astack[a]= MEM_dupallocN(ntree->stack[0]); + } + } + + ntree->init |= NTREE_EXEC_INIT; +} + +void ntreeEndExecTree(bNodeTree *ntree) +{ + + if(ntree->init & NTREE_EXEC_INIT) { + int a; + + /* another callback candidate! */ + if(ntree->type==NTREE_COMPOSIT) + composit_end_exec(ntree, 0); + + if(ntree->stack) { + for(a=0; astack[a]) + MEM_freeN(ntree->stack[a]); + + MEM_freeN(ntree->stack); + ntree->stack= NULL; + } + + ntree->init &= ~NTREE_EXEC_INIT; + } +} + +static void node_get_stack(bNode *node, bNodeStack *stack, bNodeStack **in, bNodeStack **out) +{ + bNodeSocket *sock; + + /* build pointer stack */ + for(sock= node->inputs.first; sock; sock= sock->next) { + if(sock->link) + *(in++)= stack + sock->link->fromsock->stack_index; + else + *(in++)= &sock->ns; + } + + for(sock= node->outputs.first; sock; sock= sock->next) { + *(out++)= stack + sock->stack_index; + } +} + +/* nodes are presorted, so exec is in order of list */ +void ntreeExecTree(bNodeTree *ntree, void *callerdata, int thread) +{ + bNode *node; + bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */ + bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */ + bNodeStack *stack; + + /* only when initialized */ + if((ntree->init & NTREE_EXEC_INIT)==0) + ntreeBeginExecTree(ntree); + + stack= ntree->stack[thread]; + + for(node= ntree->nodes.first; node; node= node->next) { + if(node->typeinfo->execfunc) { + node_get_stack(node, stack, nsin, nsout); + node->typeinfo->execfunc(callerdata, node, nsin, nsout); + } + else if(node->type==NODE_GROUP && node->id) { + node_get_stack(node, stack, nsin, nsout); + node_group_execute(stack, callerdata, node, nsin, nsout); + } + } +} + + +/* ***************************** threaded version for execute composite nodes ************* */ + +/* not changing info, for thread callback */ +typedef struct ThreadData { + bNodeStack *stack; + RenderData *rd; +} ThreadData; + +static void *exec_composite_node(void *node_v) +{ + bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */ + bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */ + bNode *node= node_v; + ThreadData *thd= (ThreadData *)node->new_node; /* abuse */ + + node_get_stack(node, thd->stack, nsin, nsout); + + if(node->typeinfo->execfunc) { + node->typeinfo->execfunc(thd->rd, node, nsin, nsout); + } + else if(node->type==NODE_GROUP && node->id) { + node_group_execute(thd->stack, thd->rd, node, nsin, nsout); + } + + node->exec |= NODE_READY; + return 0; +} + +/* these are nodes without input, only giving values */ +/* or nodes with only value inputs */ +static int node_only_value(bNode *node) +{ + bNodeSocket *sock; + + if(ELEM3(node->type, CMP_NODE_TIME, CMP_NODE_VALUE, CMP_NODE_RGB)) + return 1; + + /* doing this for all node types goes wrong. memory free errors */ + if(node->inputs.first && node->type==CMP_NODE_MAP_VALUE) { + int retval= 1; + for(sock= node->inputs.first; sock; sock= sock->next) { + if(sock->link) + retval &= node_only_value(sock->link->fromnode); + } + return retval; + } + return 0; +} + +/* return total of executable nodes, for timecursor */ +/* only compositor uses it */ +static int setExecutableNodes(bNodeTree *ntree, ThreadData *thd) +{ + bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */ + bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */ + bNode *node; + bNodeSocket *sock; + int totnode= 0, group_edit= 0; + + /* note; do not add a dependency sort here, the stack was created already */ + + /* if we are in group edit, viewer nodes get skipped when group has viewer */ + for(node= ntree->nodes.first; node; node= node->next) + if(node->type==NODE_GROUP && (node->flag & NODE_GROUP_EDIT)) + if(ntreeHasType((bNodeTree *)node->id, CMP_NODE_VIEWER)) + group_edit= 1; + + for(node= ntree->nodes.first; node; node= node->next) { + int a; + + node_get_stack(node, thd->stack, nsin, nsout); + + /* test the outputs */ + /* skip value-only nodes (should be in type!) */ + if(!node_only_value(node)) { + for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) { + if(nsout[a]->data==NULL && nsout[a]->hasoutput) { + node->need_exec= 1; + break; + } + } + } + + /* test the inputs */ + for(a=0, sock= node->inputs.first; sock; sock= sock->next, a++) { + /* skip viewer nodes in bg render or group edit */ + if( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER) && (G.background || group_edit)) + node->need_exec= 0; + /* is sock in use? */ + else if(sock->link) { + bNodeLink *link= sock->link; + /* this is the test for a cyclic case */ + if(link->fromnode->level >= link->tonode->level && link->tonode->level!=0xFFF) { + if(link->fromnode->need_exec) { + node->need_exec= 1; + break; + } + } + else { + node->need_exec= 0; + printf("Node %s skipped, cyclic dependency\n", node->name); + } + } + } + + if(node->need_exec) { + + /* free output buffers */ + for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) { + if(nsout[a]->data) { + free_compbuf(nsout[a]->data); + nsout[a]->data= NULL; + } + } + totnode++; + /* printf("node needs exec %s\n", node->name); */ + + /* tag for getExecutableNode() */ + node->exec= 0; + } + else { + /* tag for getExecutableNode() */ + node->exec= NODE_READY|NODE_FINISHED; + + } + } + + /* last step: set the stack values for only-value nodes */ + /* just does all now, compared to a full buffer exec this is nothing */ + if(totnode) { + for(node= ntree->nodes.first; node; node= node->next) { + if(node->need_exec==0 && node_only_value(node)) { + if(node->typeinfo->execfunc) { + node_get_stack(node, thd->stack, nsin, nsout); + node->typeinfo->execfunc(thd->rd, node, nsin, nsout); + } + } + } + } + + return totnode; +} + +/* while executing tree, free buffers from nodes that are not needed anymore */ +static void freeExecutableNode(bNodeTree *ntree) +{ + /* node outputs can be freed when: + - not a render result or image node + - when node outputs go to nodes all being set NODE_FINISHED + */ + bNode *node; + bNodeSocket *sock; + + /* set exec flag for finished nodes that might need freed */ + for(node= ntree->nodes.first; node; node= node->next) { + if(node->type!=CMP_NODE_R_LAYERS) + if(node->exec & NODE_FINISHED) + node->exec |= NODE_FREEBUFS; + } + /* clear this flag for input links that are not done yet */ + for(node= ntree->nodes.first; node; node= node->next) { + if((node->exec & NODE_FINISHED)==0) { + for(sock= node->inputs.first; sock; sock= sock->next) + if(sock->link) + sock->link->fromnode->exec &= ~NODE_FREEBUFS; + } + } + /* now we can free buffers */ + for(node= ntree->nodes.first; node; node= node->next) { + if(node->exec & NODE_FREEBUFS) { + for(sock= node->outputs.first; sock; sock= sock->next) { + bNodeStack *ns= ntree->stack[0] + sock->stack_index; + if(ns->data) { + free_compbuf(ns->data); + ns->data= NULL; + // printf("freed buf node %s \n", node->name); + } + } + } + } +} + +static bNode *getExecutableNode(bNodeTree *ntree) +{ + bNode *node; + bNodeSocket *sock; + + for(node= ntree->nodes.first; node; node= node->next) { + if(node->exec==0) { + + /* input sockets should be ready */ + for(sock= node->inputs.first; sock; sock= sock->next) { + if(sock->link) + if((sock->link->fromnode->exec & NODE_READY)==0) + break; + } + if(sock==NULL) + return node; + } + } + return NULL; +} + + +/* optimized tree execute test for compositing */ +void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview) +{ + bNode *node; + ListBase threads; + ThreadData thdata; + int totnode, rendering= 1; + + if(ntree==NULL) return; + + if(do_preview) + ntreeInitPreview(ntree, 0, 0); + + ntreeBeginExecTree(ntree); + + /* prevent unlucky accidents */ + if(G.background) + rd->scemode &= ~R_COMP_CROP; + + /* setup callerdata for thread callback */ + thdata.rd= rd; + thdata.stack= ntree->stack[0]; + + /* fixed seed, for example noise texture */ + BLI_srandom(rd->cfra); + + /* sets need_exec tags in nodes */ + totnode= setExecutableNodes(ntree, &thdata); + + BLI_init_threads(&threads, exec_composite_node, rd->threads); + + while(rendering) { + + if(BLI_available_threads(&threads)) { + node= getExecutableNode(ntree); + if(node) { + + if(ntree->timecursor) + ntree->timecursor(totnode); + if(ntree->stats_draw) { + char str[64]; + sprintf(str, "Compositing %d %s", totnode, node->name); + ntree->stats_draw(str); + } + totnode--; + + node->new_node = (bNode *)&thdata; + node->exec= NODE_PROCESSING; + BLI_insert_thread(&threads, node); + } + else + PIL_sleep_ms(50); + } + else + PIL_sleep_ms(50); + + rendering= 0; + /* test for ESC */ + if(ntree->test_break && ntree->test_break()) { + for(node= ntree->nodes.first; node; node= node->next) + node->exec |= NODE_READY; + } + + /* check for ready ones, and if we need to continue */ + for(node= ntree->nodes.first; node; node= node->next) { + if(node->exec & NODE_READY) { + if((node->exec & NODE_FINISHED)==0) { + BLI_remove_thread(&threads, node); /* this waits for running thread to finish btw */ + node->exec |= NODE_FINISHED; + + /* freeing unused buffers */ + if(rd->scemode & R_COMP_FREE) + freeExecutableNode(ntree); + } + } + else rendering= 1; + } + } + + + BLI_end_threads(&threads); + + ntreeEndExecTree(ntree); +} + + +/* **************** call to switch lamploop for material node ************ */ + +void (*node_shader_lamp_loop)(struct ShadeInput *, struct ShadeResult *); + +void set_node_shader_lamp_loop(void (*lamp_loop_func)(ShadeInput *, ShadeResult *)) +{ + node_shader_lamp_loop= lamp_loop_func; +} + +/* clumsy checking... should do dynamic outputs once */ +static void force_hidden_passes(bNode *node, int passflag) +{ + bNodeSocket *sock; + + for(sock= node->outputs.first; sock; sock= sock->next) + sock->flag &= ~SOCK_UNAVAIL; + + sock= BLI_findlink(&node->outputs, RRES_OUT_Z); + if(!(passflag & SCE_PASS_Z)) sock->flag |= SOCK_UNAVAIL; + sock= BLI_findlink(&node->outputs, RRES_OUT_NORMAL); + if(!(passflag & SCE_PASS_NORMAL)) sock->flag |= SOCK_UNAVAIL; + sock= BLI_findlink(&node->outputs, RRES_OUT_VEC); + if(!(passflag & SCE_PASS_VECTOR)) sock->flag |= SOCK_UNAVAIL; + sock= BLI_findlink(&node->outputs, RRES_OUT_UV); + if(!(passflag & SCE_PASS_UV)) sock->flag |= SOCK_UNAVAIL; + sock= BLI_findlink(&node->outputs, RRES_OUT_RGBA); + if(!(passflag & SCE_PASS_RGBA)) sock->flag |= SOCK_UNAVAIL; + sock= BLI_findlink(&node->outputs, RRES_OUT_DIFF); + if(!(passflag & SCE_PASS_DIFFUSE)) sock->flag |= SOCK_UNAVAIL; + sock= BLI_findlink(&node->outputs, RRES_OUT_SPEC); + if(!(passflag & SCE_PASS_SPEC)) sock->flag |= SOCK_UNAVAIL; + sock= BLI_findlink(&node->outputs, RRES_OUT_SHADOW); + if(!(passflag & SCE_PASS_SHADOW)) sock->flag |= SOCK_UNAVAIL; + sock= BLI_findlink(&node->outputs, RRES_OUT_AO); + if(!(passflag & SCE_PASS_AO)) sock->flag |= SOCK_UNAVAIL; + sock= BLI_findlink(&node->outputs, RRES_OUT_REFLECT); + if(!(passflag & SCE_PASS_REFLECT)) sock->flag |= SOCK_UNAVAIL; + sock= BLI_findlink(&node->outputs, RRES_OUT_REFRACT); + if(!(passflag & SCE_PASS_REFRACT)) sock->flag |= SOCK_UNAVAIL; + sock= BLI_findlink(&node->outputs, RRES_OUT_RADIO); + if(!(passflag & SCE_PASS_RADIO)) sock->flag |= SOCK_UNAVAIL; + sock= BLI_findlink(&node->outputs, RRES_OUT_INDEXOB); + if(!(passflag & SCE_PASS_INDEXOB)) sock->flag |= SOCK_UNAVAIL; + +} + +/* based on rules, force sockets hidden always */ +void ntreeCompositForceHidden(bNodeTree *ntree) +{ + bNode *node; + + if(ntree==NULL) return; + + for(node= ntree->nodes.first; node; node= node->next) { + if( node->type==CMP_NODE_R_LAYERS) { + Scene *sce= node->id?(Scene *)node->id:G.scene; /* G.scene is WEAK! */ + SceneRenderLayer *srl= BLI_findlink(&sce->r.layers, node->custom1); + if(srl) + force_hidden_passes(node, srl->passflag); + } + else if( node->type==CMP_NODE_IMAGE) { + Image *ima= (Image *)node->id; + if(ima) { + if(ima->rr) { + ImageUser *iuser= node->storage; + RenderLayer *rl= BLI_findlink(&ima->rr->layers, iuser->layer); + if(rl) + force_hidden_passes(node, rl->passflag); + else + force_hidden_passes(node, 0); + } + else if(ima->type!=IMA_TYPE_MULTILAYER) { /* if ->rr not yet read we keep inputs */ + force_hidden_passes(node, RRES_OUT_Z); + } + else + force_hidden_passes(node, 0); + } + else + force_hidden_passes(node, 0); + } + } + +} + +/* called from render pipeline, to tag render input and output */ +/* need to do all scenes, to prevent errors when you re-render 1 scene */ +void ntreeCompositTagRender(Scene *curscene) +{ + Scene *sce; + + for(sce= G.main->scene.first; sce; sce= sce->id.next) { + if(sce->nodetree) { + bNode *node; + + for(node= sce->nodetree->nodes.first; node; node= node->next) { + if(node->id==(ID *)curscene || node->type==CMP_NODE_COMPOSITE) + NodeTagChanged(sce->nodetree, node); + } + } + } +} + +/* tags nodes that have animation capabilities */ +int ntreeCompositTagAnimated(bNodeTree *ntree) +{ + bNode *node; + int tagged= 0; + + if(ntree==NULL) return 0; + + for(node= ntree->nodes.first; node; node= node->next) { + if(node->type==CMP_NODE_IMAGE) { + Image *ima= (Image *)node->id; + if(ima && ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) { + NodeTagChanged(ntree, node); + tagged= 1; + } + } + else if(node->type==CMP_NODE_TIME) { + NodeTagChanged(ntree, node); + tagged= 1; + } + else if(node->type==CMP_NODE_R_LAYERS) { + NodeTagChanged(ntree, node); + tagged= 1; + } + else if(node->type==NODE_GROUP) { + if( ntreeCompositTagAnimated((bNodeTree *)node->id) ) { + NodeTagChanged(ntree, node); + } + } + } + + return tagged; +} + + +/* called from image window preview */ +void ntreeCompositTagGenerators(bNodeTree *ntree) +{ + bNode *node; + + if(ntree==NULL) return; + + for(node= ntree->nodes.first; node; node= node->next) { + if( ELEM(node->type, CMP_NODE_R_LAYERS, CMP_NODE_IMAGE)) + NodeTagChanged(ntree, node); + } +} + +/* ************* node definition init ********** */ + +static bNodeType *is_nodetype_registered(ListBase *typelist, int type) +{ + bNodeType *ntype= typelist->first; + + for(;ntype; ntype= ntype->next ) + if(ntype->type==type) + return ntype; + + return NULL; +} + +/* type can be from a static array, we make copy for duplicate types (like group) */ +void nodeRegisterType(ListBase *typelist, const bNodeType *ntype) +{ + bNodeType *found= is_nodetype_registered(typelist, ntype->type); + + if(found==NULL) { + bNodeType *ntypen= MEM_mallocN(sizeof(bNodeType), "node type"); + *ntypen= *ntype; + BLI_addtail(typelist, ntypen); + } +} + +static void registerCompositNodes(ListBase *ntypelist) +{ + nodeRegisterType(ntypelist, &node_group_typeinfo); + nodeRegisterType(ntypelist, &cmp_node_rlayers); + nodeRegisterType(ntypelist, &cmp_node_image); + nodeRegisterType(ntypelist, &cmp_node_texture); + nodeRegisterType(ntypelist, &cmp_node_value); + nodeRegisterType(ntypelist, &cmp_node_rgb); + nodeRegisterType(ntypelist, &cmp_node_curve_time); + + nodeRegisterType(ntypelist, &cmp_node_composite); + nodeRegisterType(ntypelist, &cmp_node_viewer); + nodeRegisterType(ntypelist, &cmp_node_splitviewer); + nodeRegisterType(ntypelist, &cmp_node_output_file); + + nodeRegisterType(ntypelist, &cmp_node_curve_rgb); + nodeRegisterType(ntypelist, &cmp_node_mix_rgb); + nodeRegisterType(ntypelist, &cmp_node_hue_sat); + nodeRegisterType(ntypelist, &cmp_node_brightcontrast); + nodeRegisterType(ntypelist, &cmp_node_gamma); + nodeRegisterType(ntypelist, &cmp_node_invert); + nodeRegisterType(ntypelist, &cmp_node_alphaover); + nodeRegisterType(ntypelist, &cmp_node_zcombine); + + nodeRegisterType(ntypelist, &cmp_node_normal); + nodeRegisterType(ntypelist, &cmp_node_curve_vec); + nodeRegisterType(ntypelist, &cmp_node_map_value); + nodeRegisterType(ntypelist, &cmp_node_normalize); + + nodeRegisterType(ntypelist, &cmp_node_filter); + nodeRegisterType(ntypelist, &cmp_node_blur); + nodeRegisterType(ntypelist, &cmp_node_vecblur); + nodeRegisterType(ntypelist, &cmp_node_dilateerode); + nodeRegisterType(ntypelist, &cmp_node_defocus); + + nodeRegisterType(ntypelist, &cmp_node_valtorgb); + nodeRegisterType(ntypelist, &cmp_node_rgbtobw); + nodeRegisterType(ntypelist, &cmp_node_setalpha); + nodeRegisterType(ntypelist, &cmp_node_idmask); + nodeRegisterType(ntypelist, &cmp_node_math); + nodeRegisterType(ntypelist, &cmp_node_seprgba); + nodeRegisterType(ntypelist, &cmp_node_combrgba); + nodeRegisterType(ntypelist, &cmp_node_sephsva); + nodeRegisterType(ntypelist, &cmp_node_combhsva); + nodeRegisterType(ntypelist, &cmp_node_sepyuva); + nodeRegisterType(ntypelist, &cmp_node_combyuva); + nodeRegisterType(ntypelist, &cmp_node_sepycca); + nodeRegisterType(ntypelist, &cmp_node_combycca); + + nodeRegisterType(ntypelist, &cmp_node_diff_matte); + nodeRegisterType(ntypelist, &cmp_node_chroma); + nodeRegisterType(ntypelist, &cmp_node_channel_matte); + nodeRegisterType(ntypelist, &cmp_node_color_spill); + nodeRegisterType(ntypelist, &cmp_node_luma_matte); + + nodeRegisterType(ntypelist, &cmp_node_translate); + nodeRegisterType(ntypelist, &cmp_node_rotate); + nodeRegisterType(ntypelist, &cmp_node_scale); + nodeRegisterType(ntypelist, &cmp_node_flip); + nodeRegisterType(ntypelist, &cmp_node_crop); + nodeRegisterType(ntypelist, &cmp_node_displace); + nodeRegisterType(ntypelist, &cmp_node_mapuv); + + nodeRegisterType(ntypelist, &cmp_node_glare); + nodeRegisterType(ntypelist, &cmp_node_tonemap); + nodeRegisterType(ntypelist, &cmp_node_lensdist); +} + +static void registerShaderNodes(ListBase *ntypelist) +{ + nodeRegisterType(ntypelist, &node_group_typeinfo); + nodeRegisterType(ntypelist, &sh_node_output); + nodeRegisterType(ntypelist, &sh_node_mix_rgb); + nodeRegisterType(ntypelist, &sh_node_valtorgb); + nodeRegisterType(ntypelist, &sh_node_rgbtobw); + nodeRegisterType(ntypelist, &sh_node_normal); + nodeRegisterType(ntypelist, &sh_node_geom); + nodeRegisterType(ntypelist, &sh_node_mapping); + nodeRegisterType(ntypelist, &sh_node_curve_vec); + nodeRegisterType(ntypelist, &sh_node_curve_rgb); + nodeRegisterType(ntypelist, &sh_node_math); + nodeRegisterType(ntypelist, &sh_node_vect_math); + nodeRegisterType(ntypelist, &sh_node_squeeze); + nodeRegisterType(ntypelist, &sh_node_camera); + nodeRegisterType(ntypelist, &sh_node_material); + nodeRegisterType(ntypelist, &sh_node_material_ext); + nodeRegisterType(ntypelist, &sh_node_value); + nodeRegisterType(ntypelist, &sh_node_rgb); + nodeRegisterType(ntypelist, &sh_node_texture); + nodeRegisterType(ntypelist, &sh_node_invert); + nodeRegisterType(ntypelist, &sh_node_seprgb); + nodeRegisterType(ntypelist, &sh_node_combrgb); + nodeRegisterType(ntypelist, &sh_node_hue_sat); +} + +void init_nodesystem(void) +{ + registerCompositNodes(&node_all_composit); + registerShaderNodes(&node_all_shaders); +} + +void free_nodesystem(void) +{ + BLI_freelistN(&node_all_composit); + BLI_freelistN(&node_all_shaders); +} + + diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c new file mode 100644 index 00000000000..7d707813c65 --- /dev/null +++ b/source/blender/blenkernel/intern/object.c @@ -0,0 +1,2080 @@ +/* object.c + * + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_guardedalloc.h" + +#include "DNA_action_types.h" +#include "DNA_armature_types.h" +#include "DNA_camera_types.h" +#include "DNA_constraint_types.h" +#include "DNA_curve_types.h" +#include "DNA_group_types.h" +#include "DNA_ipo_types.h" +#include "DNA_lamp_types.h" +#include "DNA_lattice_types.h" +#include "DNA_material_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_nla_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force.h" +#include "DNA_object_fluidsim.h" +#include "DNA_oops_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_texture_types.h" +#include "DNA_userdef_types.h" +#include "DNA_view3d_types.h" +#include "DNA_world_types.h" + +#include "BKE_armature.h" +#include "BKE_action.h" +#include "BKE_colortools.h" +#include "BKE_deform.h" +#include "BKE_DerivedMesh.h" +#include "BKE_nla.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_editVert.h" + +#include "BKE_utildefines.h" +#include "BKE_bad_level_calls.h" + +#include "BKE_main.h" +#include "BKE_global.h" + +#include "BKE_anim.h" +#include "BKE_blender.h" +#include "BKE_constraint.h" +#include "BKE_curve.h" +#include "BKE_displist.h" +#include "BKE_effect.h" +#include "BKE_group.h" +#include "BKE_icons.h" +#include "BKE_ipo.h" +#include "BKE_key.h" +#include "BKE_lattice.h" +#include "BKE_library.h" +#include "BKE_mesh.h" +#include "BKE_mball.h" +#include "BKE_modifier.h" +#include "BKE_object.h" +#include "BKE_property.h" +#include "BKE_sca.h" +#include "BKE_scene.h" +#include "BKE_screen.h" +#include "BKE_softbody.h" + +#include "LBM_fluidsim.h" + +#include "BPY_extern.h" + +/* Local function protos */ +static void solve_parenting (Object *ob, Object *par, float obmat[][4], float slowmat[][4], int simul); + +float originmat[3][3]; /* after where_is_object(), can be used in other functions (bad!) */ +Object workob; + +void clear_workob(void) +{ + memset(&workob, 0, sizeof(Object)); + + workob.size[0]= workob.size[1]= workob.size[2]= 1.0; + +} + +void copy_baseflags() +{ + Base *base= G.scene->base.first; + + while(base) { + base->object->flag= base->flag; + base= base->next; + } +} + +void copy_objectflags() +{ + Base *base= G.scene->base.first; + + while(base) { + base->flag= base->object->flag; + base= base->next; + } +} + +void update_base_layer(Object *ob) +{ + Base *base= G.scene->base.first; + + while (base) { + if (base->object == ob) base->lay= ob->lay; + base= base->next; + } +} + +void object_free_modifiers(Object *ob) +{ + while (ob->modifiers.first) { + ModifierData *md = ob->modifiers.first; + + BLI_remlink(&ob->modifiers, md); + + modifier_free(md); + } +} + +/* here we will collect all local displist stuff */ +/* also (ab)used in depsgraph */ +void object_free_display(Object *ob) +{ + if(ob->derivedDeform) { + ob->derivedDeform->needsFree = 1; + ob->derivedDeform->release(ob->derivedDeform); + ob->derivedDeform= NULL; + } + if(ob->derivedFinal) { + ob->derivedFinal->needsFree = 1; + ob->derivedFinal->release(ob->derivedFinal); + ob->derivedFinal= NULL; + } + + freedisplist(&ob->disp); +} + +/* do not free object itself */ +void free_object(Object *ob) +{ + int a; + + object_free_display(ob); + + /* disconnect specific data */ + if(ob->data) { + ID *id= ob->data; + id->us--; + if(id->us==0) { + if(ob->type==OB_MESH) unlink_mesh(ob->data); + else if(ob->type==OB_CURVE) unlink_curve(ob->data); + else if(ob->type==OB_MBALL) unlink_mball(ob->data); + } + ob->data= 0; + } + + for(a=0; atotcol; a++) { + if(ob->mat[a]) ob->mat[a]->id.us--; + } + if(ob->mat) MEM_freeN(ob->mat); + ob->mat= 0; + if(ob->bb) MEM_freeN(ob->bb); + ob->bb= 0; + if(ob->path) free_path(ob->path); + ob->path= 0; + if(ob->ipo) ob->ipo->id.us--; + if(ob->action) ob->action->id.us--; + if(ob->dup_group) ob->dup_group->id.us--; + if(ob->defbase.first) + BLI_freelistN(&ob->defbase); + if(ob->pose) { + free_pose_channels(ob->pose); + MEM_freeN(ob->pose); + } + free_effects(&ob->effect); + free_properties(&ob->prop); + object_free_modifiers(ob); + + free_sensors(&ob->sensors); + free_controllers(&ob->controllers); + free_actuators(&ob->actuators); + + free_constraints(&ob->constraints); + free_constraint_channels(&ob->constraintChannels); + free_nlastrips(&ob->nlastrips); + + BPY_free_scriptlink(&ob->scriptlink); + + if(ob->pd) MEM_freeN(ob->pd); + if(ob->soft) sbFree(ob->soft); + if(ob->fluidsimSettings) fluidsimSettingsFree(ob->fluidsimSettings); +} + +static void unlink_object__unlinkModifierLinks(void *userData, Object *ob, Object **obpoin) +{ + Object *unlinkOb = userData; + + if (*obpoin==unlinkOb) { + *obpoin = NULL; + ob->recalc |= OB_RECALC; + } +} +void unlink_object(Object *ob) +{ + Object *obt; + Material *mat; + World *wrld; + bScreen *sc; + Scene *sce; + Curve *cu; + Tex *tex; + Ipo *ipo; + Group *group; + Camera *camera; + bConstraint *con; + bActionStrip *strip; + int a; + + unlink_controllers(&ob->controllers); + unlink_actuators(&ob->actuators); + + /* check all objects: parents en bevels and fields, also from libraries */ + obt= G.main->object.first; + while(obt) { + if(obt->proxy==ob) + obt->proxy= NULL; + if(obt->proxy_from==ob) { + obt->proxy_from= NULL; + obt->recalc |= OB_RECALC_OB; + } + if(obt->proxy_group==ob) + obt->proxy_group= NULL; + + if(obt->parent==ob) { + obt->parent= NULL; + obt->recalc |= OB_RECALC; + } + + if(obt->track==ob) { + obt->track= NULL; + obt->recalc |= OB_RECALC_OB; + } + + modifiers_foreachObjectLink(obt, unlink_object__unlinkModifierLinks, ob); + + if ELEM(obt->type, OB_CURVE, OB_FONT) { + cu= obt->data; + + if(cu->bevobj==ob) { + cu->bevobj= NULL; + obt->recalc |= OB_RECALC; + } + if(cu->taperobj==ob) { + cu->taperobj= NULL; + obt->recalc |= OB_RECALC; + } + if(cu->textoncurve==ob) { + cu->textoncurve= NULL; + obt->recalc |= OB_RECALC; + } + } + else if(obt->type==OB_ARMATURE && obt->pose) { + bPoseChannel *pchan; + for(pchan= obt->pose->chanbase.first; pchan; pchan= pchan->next) { + for (con = pchan->constraints.first; con; con=con->next) { + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + ListBase targets = {NULL, NULL}; + bConstraintTarget *ct; + + if (cti && cti->get_constraint_targets) { + cti->get_constraint_targets(con, &targets); + + for (ct= targets.first; ct; ct= ct->next) { + if (ct->tar == ob) { + ct->tar = NULL; + strcpy(ct->subtarget, ""); + obt->recalc |= OB_RECALC_DATA; + } + } + + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(con, &targets, 0); + } + } + if(pchan->custom==ob) + pchan->custom= NULL; + } + } + + sca_remove_ob_poin(obt, ob); + + for (con = obt->constraints.first; con; con=con->next) { + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + ListBase targets = {NULL, NULL}; + bConstraintTarget *ct; + + if (cti && cti->get_constraint_targets) { + cti->get_constraint_targets(con, &targets); + + for (ct= targets.first; ct; ct= ct->next) { + if (ct->tar == ob) { + ct->tar = NULL; + strcpy(ct->subtarget, ""); + obt->recalc |= OB_RECALC_DATA; + } + } + + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(con, &targets, 0); + } + } + + /* object is deflector or field */ + if(ob->pd) { + if(give_parteff(obt)) + obt->recalc |= OB_RECALC_DATA; + else if(obt->soft) + obt->recalc |= OB_RECALC_DATA; + } + + /* strips */ + for(strip= obt->nlastrips.first; strip; strip= strip->next) { + if(strip->object==ob) + strip->object= NULL; + + if(strip->modifiers.first) { + bActionModifier *amod; + for(amod= strip->modifiers.first; amod; amod= amod->next) + if(amod->ob==ob) + amod->ob= NULL; + } + } + + obt= obt->id.next; + } + + /* materials */ + mat= G.main->mat.first; + while(mat) { + + for(a=0; amtex[a] && ob==mat->mtex[a]->object) { + /* actually, test for lib here... to do */ + mat->mtex[a]->object= NULL; + } + } + + mat= mat->id.next; + } + + /* textures */ + tex= G.main->tex.first; + while(tex) { + if(tex->env) { + if(tex->env->object == ob) tex->env->object= NULL; + } + tex= tex->id.next; + } + + /* mballs */ + if(ob->type==OB_MBALL) { + obt= find_basis_mball(ob); + if(obt) freedisplist(&obt->disp); + } + + /* worlds */ + wrld= G.main->world.first; + while(wrld) { + if(wrld->id.lib==NULL) { + for(a=0; amtex[a] && ob==wrld->mtex[a]->object) + wrld->mtex[a]->object= NULL; + } + } + + wrld= wrld->id.next; + } + + /* scenes */ + sce= G.main->scene.first; + while(sce) { + if(sce->id.lib==NULL) { + if(sce->camera==ob) sce->camera= NULL; + } + sce= sce->id.next; + } + /* ipos */ + ipo= G.main->ipo.first; + while(ipo) { + if(ipo->id.lib==NULL) { + IpoCurve *icu; + for(icu= ipo->curve.first; icu; icu= icu->next) { + if(icu->driver && icu->driver->ob==ob) + icu->driver->ob= NULL; + } + } + ipo= ipo->id.next; + } + + /* screens */ + sc= G.main->screen.first; + while(sc) { + ScrArea *sa= sc->areabase.first; + while(sa) { + SpaceLink *sl; + + for (sl= sa->spacedata.first; sl; sl= sl->next) { + if(sl->spacetype==SPACE_VIEW3D) { + View3D *v3d= (View3D*) sl; + + if(v3d->camera==ob) { + v3d->camera= NULL; + if(v3d->persp>1) v3d->persp= 1; + } + if(v3d->localvd && v3d->localvd->camera==ob ) { + v3d->localvd->camera= NULL; + if(v3d->localvd->persp>1) v3d->localvd->persp= 1; + } + } + else if(sl->spacetype==SPACE_IPO) { + SpaceIpo *sipo= (SpaceIpo *)sl; + if(sipo->from == (ID *)ob) sipo->from= NULL; + } + else if(sl->spacetype==SPACE_OOPS) { + SpaceOops *so= (SpaceOops *)sl; + Oops *oops; + + oops= so->oops.first; + while(oops) { + if(oops->id==(ID *)ob) oops->id= NULL; + oops= oops->next; + } + if(so->treestore) { + TreeStoreElem *tselem= so->treestore->data; + int a; + for(a=0; atreestore->usedelem; a++, tselem++) { + if(tselem->id==(ID *)ob) tselem->id= NULL; + } + } + so->lockpoin= NULL; + } + } + + sa= sa->next; + } + sc= sc->id.next; + } + + /* groups */ + group= G.main->group.first; + while(group) { + rem_from_group(group, ob); + group= group->id.next; + } + + /* cameras */ + camera= G.main->camera.first; + while(camera) { + if (camera->dof_ob==ob) { + camera->dof_ob = NULL; + } + camera= camera->id.next; + } +} + +int exist_object(Object *obtest) +{ + Object *ob; + + if(obtest==NULL) return 0; + + ob= G.main->object.first; + while(ob) { + if(ob==obtest) return 1; + ob= ob->id.next; + } + return 0; +} + +void *add_camera(char *name) +{ + Camera *cam; + + cam= alloc_libblock(&G.main->camera, ID_CA, name); + + cam->lens= 35.0f; + cam->angle= 49.14f; + cam->clipsta= 0.1f; + cam->clipend= 100.0f; + cam->drawsize= 0.5f; + cam->ortho_scale= 6.0; + cam->flag |= CAM_SHOWTITLESAFE; + cam->passepartalpha = 0.2f; + + return cam; +} + +Camera *copy_camera(Camera *cam) +{ + Camera *camn; + + camn= copy_libblock(cam); + id_us_plus((ID *)camn->ipo); + + BPY_copy_scriptlink(&camn->scriptlink); + + return camn; +} + + + +void make_local_camera(Camera *cam) +{ + Object *ob; + Camera *camn; + int local=0, lib=0; + + /* - only lib users: do nothing + * - only local users: set flag + * - mixed: make copy + */ + + if(cam->id.lib==0) return; + if(cam->id.us==1) { + cam->id.lib= 0; + cam->id.flag= LIB_LOCAL; + new_id(0, (ID *)cam, 0); + return; + } + + ob= G.main->object.first; + while(ob) { + if(ob->data==cam) { + if(ob->id.lib) lib= 1; + else local= 1; + } + ob= ob->id.next; + } + + if(local && lib==0) { + cam->id.lib= 0; + cam->id.flag= LIB_LOCAL; + new_id(0, (ID *)cam, 0); + } + else if(local && lib) { + camn= copy_camera(cam); + camn->id.us= 0; + + ob= G.main->object.first; + while(ob) { + if(ob->data==cam) { + + if(ob->id.lib==0) { + ob->data= camn; + camn->id.us++; + cam->id.us--; + } + } + ob= ob->id.next; + } + } +} + +/* get the camera's dof value, takes the dof object into account */ +float dof_camera(Object *ob) +{ + Camera *cam = (Camera *)ob->data; + if (ob->type != OB_CAMERA) + return 0.0; + if (cam->dof_ob) { + /* too simple, better to return the distance on the view axis only + * return VecLenf(ob->obmat[3], cam->dof_ob->obmat[3]); */ + + float mat[4][4]; + Mat4Invert(ob->imat, ob->obmat); + Mat4MulMat4(mat, cam->dof_ob->obmat, ob->imat); + return fabs(mat[3][2]); + } + return cam->YF_dofdist; +} + +void *add_lamp(char *name) +{ + Lamp *la; + + la= alloc_libblock(&G.main->lamp, ID_LA, name); + + la->r= la->g= la->b= la->k= 1.0; + la->haint= la->energy= 1.0; + la->dist= 20.0; + la->spotsize= 45.0; + la->spotblend= 0.15; + la->att2= 1.0; + la->mode= LA_SHAD_BUF; + la->bufsize= 512; + la->clipsta= 0.5; + la->clipend= 40.0; + la->shadspotsize= 45.0; + la->samp= 3; + la->bias= 1.0; + la->soft= 3.0; + la->ray_samp= la->ray_sampy= la->ray_sampz= 1; + la->area_size=la->area_sizey=la->area_sizez= 1.0; + la->buffers= 1; + la->buftype= LA_SHADBUF_HALFWAY; + la->ray_samp_method = LA_SAMP_HALTON; + la->adapt_thresh = 0.001; + la->preview=NULL; + la->falloff_type = LA_FALLOFF_INVLINEAR; + la->curfalloff = curvemapping_add(1, 0.0f, 1.0f, 1.0f, 0.0f); + curvemapping_initialize(la->curfalloff); + return la; +} + +Lamp *copy_lamp(Lamp *la) +{ + Lamp *lan; + int a; + + lan= copy_libblock(la); + + for(a=0; amtex[a]) { + lan->mtex[a]= MEM_mallocN(sizeof(MTex), "copylamptex"); + memcpy(lan->mtex[a], la->mtex[a], sizeof(MTex)); + id_us_plus((ID *)lan->mtex[a]->tex); + } + } + + lan->curfalloff = curvemapping_copy(la->curfalloff); + + id_us_plus((ID *)lan->ipo); + + if (la->preview) lan->preview = BKE_previewimg_copy(la->preview); + + BPY_copy_scriptlink(&la->scriptlink); + + return lan; +} + +void make_local_lamp(Lamp *la) +{ + Object *ob; + Lamp *lan; + int local=0, lib=0; + + /* - only lib users: do nothing + * - only local users: set flag + * - mixed: make copy + */ + + if(la->id.lib==0) return; + if(la->id.us==1) { + la->id.lib= 0; + la->id.flag= LIB_LOCAL; + new_id(0, (ID *)la, 0); + return; + } + + ob= G.main->object.first; + while(ob) { + if(ob->data==la) { + if(ob->id.lib) lib= 1; + else local= 1; + } + ob= ob->id.next; + } + + if(local && lib==0) { + la->id.lib= 0; + la->id.flag= LIB_LOCAL; + new_id(0, (ID *)la, 0); + } + else if(local && lib) { + lan= copy_lamp(la); + lan->id.us= 0; + + ob= G.main->object.first; + while(ob) { + if(ob->data==la) { + + if(ob->id.lib==0) { + ob->data= lan; + lan->id.us++; + la->id.us--; + } + } + ob= ob->id.next; + } + } +} + +void free_camera(Camera *ca) +{ + BPY_free_scriptlink(&ca->scriptlink); +} + +void free_lamp(Lamp *la) +{ + MTex *mtex; + int a; + + /* scriptlinks */ + + BPY_free_scriptlink(&la->scriptlink); + + for(a=0; amtex[a]; + if(mtex && mtex->tex) mtex->tex->id.us--; + if(mtex) MEM_freeN(mtex); + } + la->ipo= 0; + + curvemapping_free(la->curfalloff); + + BKE_previewimg_free(&la->preview); + BKE_icon_delete(&la->id); + la->id.icon_id = 0; +} + +void *add_wave() +{ + return 0; +} + + +/* *************************************************** */ + +static void *add_obdata_from_type(int type) +{ + switch (type) { + case OB_MESH: G.totmesh++; return add_mesh("Mesh"); + case OB_CURVE: G.totcurve++; return add_curve("Curve", OB_CURVE); + case OB_SURF: G.totcurve++; return add_curve("Surf", OB_SURF); + case OB_FONT: return add_curve("Text", OB_FONT); + case OB_MBALL: return add_mball("Meta"); + case OB_CAMERA: return add_camera("Camera"); + case OB_LAMP: G.totlamp++; return add_lamp("Lamp"); + case OB_LATTICE: return add_lattice("Lattice"); + case OB_WAVE: return add_wave(); + case OB_ARMATURE: return add_armature("Armature"); + case OB_EMPTY: return NULL; + default: + printf("add_obdata_from_type: Internal error, bad type: %d\n", type); + return NULL; + } +} + +static char *get_obdata_defname(int type) +{ + switch (type) { + case OB_MESH: return "Mesh"; + case OB_CURVE: return "Curve"; + case OB_SURF: return "Surf"; + case OB_FONT: return "Font"; + case OB_MBALL: return "Mball"; + case OB_CAMERA: return "Camera"; + case OB_LAMP: return "Lamp"; + case OB_LATTICE: return "Lattice"; + case OB_WAVE: return "Wave"; + case OB_ARMATURE: return "Armature"; + case OB_EMPTY: return "Empty"; + default: + printf("get_obdata_defname: Internal error, bad type: %d\n", type); + return "Empty"; + } +} + +/* more general add: creates minimum required data, but without vertices etc. */ +Object *add_only_object(int type, char *name) +{ + Object *ob; + + ob= alloc_libblock(&G.main->object, ID_OB, name); + G.totobj++; + + /* default object vars */ + ob->type= type; + /* ob->transflag= OB_QUAT; */ + + QuatOne(ob->quat); + QuatOne(ob->dquat); + + ob->col[0]= ob->col[1]= ob->col[2]= 0.0; + ob->col[3]= 1.0; + + ob->loc[0]= ob->loc[1]= ob->loc[2]= 0.0; + ob->rot[0]= ob->rot[1]= ob->rot[2]= 0.0; + ob->size[0]= ob->size[1]= ob->size[2]= 1.0; + + Mat4One(ob->constinv); + Mat4One(ob->parentinv); + Mat4One(ob->obmat); + ob->dt= OB_SHADED; + if(U.flag & USER_MAT_ON_OB) ob->colbits= -1; + ob->empty_drawtype= OB_ARROWS; + ob->empty_drawsize= 1.0; + + if(type==OB_CAMERA || type==OB_LAMP) { + ob->trackflag= OB_NEGZ; + ob->upflag= OB_POSY; + } + else { + ob->trackflag= OB_POSY; + ob->upflag= OB_POSZ; + } + ob->ipoflag = OB_OFFS_OB+OB_OFFS_PARENT; + ob->ipowin= ID_OB; /* the ipowin shown */ + ob->dupon= 1; ob->dupoff= 0; + ob->dupsta= 1; ob->dupend= 100; + + /* Game engine defaults*/ + ob->mass= ob->inertia= 1.0f; + ob->formfactor= 0.4f; + ob->damping= 0.04f; + ob->rdamping= 0.1f; + ob->anisotropicFriction[0] = 1.0f; + ob->anisotropicFriction[1] = 1.0f; + ob->anisotropicFriction[2] = 1.0f; + ob->gameflag= OB_PROP; + + /* NT fluid sim defaults */ + ob->fluidsimFlag = 0; + ob->fluidsimSettings = NULL; + + return ob; +} + +/* general add: to G.scene, with layer from area and default name */ +/* creates minimum required data, but without vertices etc. */ +Object *add_object(int type) +{ + Object *ob; + Base *base; + char name[32]; + + strcpy(name, get_obdata_defname(type)); + ob = add_only_object(type, name); + + ob->data= add_obdata_from_type(type); + + ob->lay= G.scene->lay; + + base= scene_add_base(G.scene, ob); + scene_select_base(G.scene, base); + ob->recalc |= OB_RECALC; + + return ob; +} + +void base_init_from_view3d(Base *base, View3D *v3d) +{ + Object *ob= base->object; + + if (!v3d) { + /* no 3d view, this wont happen often */ + base->lay = 1; + VECCOPY(ob->loc, G.scene->cursor); + + /* return now because v3d->viewquat isnt available */ + return; + } else if (v3d->localview) { + base->lay= ob->lay= v3d->layact + v3d->lay; + VECCOPY(ob->loc, v3d->cursor); + } else { + base->lay= ob->lay= v3d->layact; + VECCOPY(ob->loc, G.scene->cursor); + } + + if (U.flag & USER_ADD_VIEWALIGNED) { + v3d->viewquat[0]= -v3d->viewquat[0]; + if (ob->transflag & OB_QUAT) { + QUATCOPY(ob->quat, v3d->viewquat); + } else { + QuatToEul(v3d->viewquat, ob->rot); + } + v3d->viewquat[0]= -v3d->viewquat[0]; + } +} + +SoftBody *copy_softbody(SoftBody *sb) +{ + SoftBody *sbn; + + if (sb==NULL) return(NULL); + + sbn= MEM_dupallocN(sb); + sbn->totspring= sbn->totpoint= 0; + sbn->bpoint= NULL; + sbn->bspring= NULL; + sbn->ctime= 0.0f; + + sbn->keys= NULL; + sbn->totkey= sbn->totpointkey= 0; + + sbn->scratch= NULL; + return sbn; +} + +static void copy_object_pose(Object *obn, Object *ob) +{ + bPoseChannel *chan; + + copy_pose(&obn->pose, ob->pose, 1); + + for (chan = obn->pose->chanbase.first; chan; chan=chan->next){ + bConstraint *con; + + chan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE); + + for (con= chan->constraints.first; con; con= con->next) { + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + ListBase targets = {NULL, NULL}; + bConstraintTarget *ct; + + if (cti && cti->get_constraint_targets) { + cti->get_constraint_targets(con, &targets); + + for (ct= targets.first; ct; ct= ct->next) { + if (ct->tar == ob) + ct->tar = obn; + } + + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(con, &targets, 0); + } + } + } +} + +Object *copy_object(Object *ob) +{ + Object *obn; + ModifierData *md; + int a; + + obn= copy_libblock(ob); + + if(ob->totcol) { + obn->mat= MEM_dupallocN(ob->mat); + } + + if(ob->bb) obn->bb= MEM_dupallocN(ob->bb); + obn->path= NULL; + obn->flag &= ~OB_FROMGROUP; + + copy_effects(&obn->effect, &ob->effect); + obn->modifiers.first = obn->modifiers.last= NULL; + + for (md=ob->modifiers.first; md; md=md->next) { + ModifierData *nmd = modifier_new(md->type); + modifier_copyData(md, nmd); + BLI_addtail(&obn->modifiers, nmd); + } + + BPY_copy_scriptlink(&ob->scriptlink); + + copy_properties(&obn->prop, &ob->prop); + copy_sensors(&obn->sensors, &ob->sensors); + copy_controllers(&obn->controllers, &ob->controllers); + copy_actuators(&obn->actuators, &ob->actuators); + + if(ob->pose) { + copy_object_pose(obn, ob); + /* backwards compat... non-armatures can get poses in older files? */ + if(ob->type==OB_ARMATURE) + armature_rebuild_pose(obn, obn->data); + } + copy_defgroups(&obn->defbase, &ob->defbase); + copy_nlastrips(&obn->nlastrips, &ob->nlastrips); + copy_constraints (&obn->constraints, &ob->constraints); + + clone_constraint_channels (&obn->constraintChannels, &ob->constraintChannels); + + /* increase user numbers */ + id_us_plus((ID *)obn->data); + id_us_plus((ID *)obn->ipo); + id_us_plus((ID *)obn->action); + id_us_plus((ID *)obn->dup_group); + + for(a=0; atotcol; a++) id_us_plus((ID *)obn->mat[a]); + + obn->disp.first= obn->disp.last= NULL; + + if(ob->pd) obn->pd= MEM_dupallocN(ob->pd); + obn->soft= copy_softbody(ob->soft); + + /* NT copy fluid sim setting memory */ + if(obn->fluidsimSettings) { + obn->fluidsimSettings = fluidsimSettingsCopy(ob->fluidsimSettings); + /* copying might fail... */ + if(obn->fluidsimSettings) { + obn->fluidsimSettings->orgMesh = (Mesh *)obn->data; + } + } + + obn->derivedDeform = NULL; + obn->derivedFinal = NULL; + +#ifdef WITH_VERSE + obn->vnode = NULL; +#endif + + + return obn; +} + +void expand_local_object(Object *ob) +{ + bActionStrip *strip; + int a; + + id_lib_extern((ID *)ob->action); + id_lib_extern((ID *)ob->ipo); + id_lib_extern((ID *)ob->data); + + for(a=0; atotcol; a++) { + id_lib_extern((ID *)ob->mat[a]); + } + for (strip=ob->nlastrips.first; strip; strip=strip->next) { + id_lib_extern((ID *)strip->act); + } + +} + +void make_local_object(Object *ob) +{ + Object *obn; + Scene *sce; + Base *base; + int local=0, lib=0; + + /* - only lib users: do nothing + * - only local users: set flag + * - mixed: make copy + */ + + if(ob->id.lib==NULL) return; + + ob->proxy= ob->proxy_from= NULL; + + if(ob->id.us==1) { + ob->id.lib= NULL; + ob->id.flag= LIB_LOCAL; + new_id(0, (ID *)ob, 0); + + } + else { + sce= G.main->scene.first; + while(sce) { + base= sce->base.first; + while(base) { + if(base->object==ob) { + if(sce->id.lib) lib++; + else local++; + break; + } + base= base->next; + } + sce= sce->id.next; + } + + if(local && lib==0) { + ob->id.lib= 0; + ob->id.flag= LIB_LOCAL; + new_id(0, (ID *)ob, 0); + } + else if(local && lib) { + obn= copy_object(ob); + obn->id.us= 0; + + sce= G.main->scene.first; + while(sce) { + if(sce->id.lib==0) { + base= sce->base.first; + while(base) { + if(base->object==ob) { + base->object= obn; + obn->id.us++; + ob->id.us--; + } + base= base->next; + } + } + sce= sce->id.next; + } + } + } + + expand_local_object(ob); +} + +/* *************** PROXY **************** */ + +/* proxy rule: lib_object->proxy_from == the one we borrow from, set temporally while object_update */ +/* local_object->proxy == pointer to library object, saved in files and read */ +/* local_object->proxy_group == pointer to group dupli-object, saved in files and read */ + +void object_make_proxy(Object *ob, Object *target, Object *gob) +{ + /* paranoia checks */ + if(ob->id.lib || target->id.lib==NULL) { + printf("cannot make proxy\n"); + return; + } + + ob->proxy= target; + ob->proxy_group= gob; + id_lib_extern(&target->id); + + ob->recalc= target->recalc= OB_RECALC; + + /* copy transform */ + if(gob) { + VECCOPY(ob->loc, gob->loc); + VECCOPY(ob->rot, gob->rot); + VECCOPY(ob->size, gob->size); + } + else { + VECCOPY(ob->loc, target->loc); + VECCOPY(ob->rot, target->rot); + VECCOPY(ob->size, target->size); + } + + ob->parent= target->parent; /* libdata */ + Mat4CpyMat4(ob->parentinv, target->parentinv); + ob->ipo= target->ipo; /* libdata */ + + /* skip constraints, constraintchannels, nla? */ + + ob->type= target->type; + ob->data= target->data; + id_us_plus((ID *)ob->data); /* ensures lib data becomes LIB_EXTERN */ + + /* type conversions */ + if(target->type == OB_ARMATURE) { + copy_object_pose(ob, target); /* data copy, object pointers in constraints */ + rest_pose(ob->pose); /* clear all transforms in channels */ + armature_rebuild_pose(ob, ob->data); /* set all internal links */ + } +} + + +/* *************** CALC ****************** */ + +/* there is also a timing calculation in drawobject() */ + +float bluroffs= 0.0f, fieldoffs= 0.0f; +int no_speed_curve= 0; + +/* ugly calls from render */ +void set_mblur_offs(float blur) +{ + bluroffs= blur; +} + +void set_field_offs(float field) +{ + fieldoffs= field; +} + +void disable_speed_curve(int val) +{ + no_speed_curve= val; +} + +/* ob can be NULL */ +float bsystem_time(Object *ob, float cfra, float ofs) +{ + /* returns float ( see frame_to_float in ipo.c) */ + + /* bluroffs and fieldoffs are ugly globals that are set by render */ + cfra+= bluroffs+fieldoffs; + + /* global time */ + cfra*= G.scene->r.framelen; + + if (ob) { + if (no_speed_curve==0 && ob->ipo) + cfra= calc_ipo_time(ob->ipo, cfra); + + /* ofset frames */ + if ((ob->ipoflag & OB_OFFS_PARENT) && (ob->partype & PARSLOW)==0) + cfra-= ob->sf; + } + + cfra-= ofs; + + return cfra; +} + +void object_to_mat3(Object *ob, float mat[][3]) /* no parent */ +{ + float smat[3][3], vec[3]; + float rmat[3][3]; + float q1[4]; + + /* size */ + if(ob->ipo) { + vec[0]= ob->size[0]+ob->dsize[0]; + vec[1]= ob->size[1]+ob->dsize[1]; + vec[2]= ob->size[2]+ob->dsize[2]; + SizeToMat3(vec, smat); + } + else { + SizeToMat3(ob->size, smat); + } + + /* rot */ + if(ob->transflag & OB_QUAT) { + if(ob->ipo) { + QuatMul(q1, ob->quat, ob->dquat); + QuatToMat3(q1, rmat); + } + else { + QuatToMat3(ob->quat, rmat); + } + } + else { + if(ob->ipo) { + vec[0]= ob->rot[0]+ob->drot[0]; + vec[1]= ob->rot[1]+ob->drot[1]; + vec[2]= ob->rot[2]+ob->drot[2]; + EulToMat3(vec, rmat); + } + else { + EulToMat3(ob->rot, rmat); + } + } + Mat3MulMat3(mat, rmat, smat); +} + +void object_to_mat4(Object *ob, float mat[][4]) +{ + float tmat[3][3]; + + object_to_mat3(ob, tmat); + + Mat4CpyMat3(mat, tmat); + + VECCOPY(mat[3], ob->loc); + if(ob->ipo) { + mat[3][0]+= ob->dloc[0]; + mat[3][1]+= ob->dloc[1]; + mat[3][2]+= ob->dloc[2]; + } +} + +int enable_cu_speed= 1; + +static void ob_parcurve(Object *ob, Object *par, float mat[][4]) +{ + Curve *cu; + float q[4], vec[4], dir[3], *quat, x1, ctime; + float timeoffs= 0.0; + + Mat4One(mat); + + cu= par->data; + if(cu->path==NULL || cu->path->data==NULL) /* only happens on reload file, but violates depsgraph still... fix! */ + makeDispListCurveTypes(par, 0); + if(cu->path==NULL) return; + + /* exception, timeoffset is regarded as distance offset */ + if(cu->flag & CU_OFFS_PATHDIST) { + SWAP(float, timeoffs, ob->sf); + } + + /* catch exceptions: feature for nla stride editing */ + if(ob->ipoflag & OB_DISABLE_PATH) { + ctime= 0.0f; + } + /* catch exceptions: curve paths used as a duplicator */ + else if(enable_cu_speed) { + ctime= bsystem_time(ob, (float)G.scene->r.cfra, 0.0); + + if(calc_ipo_spec(cu->ipo, CU_SPEED, &ctime)==0) { + ctime /= cu->pathlen; + CLAMP(ctime, 0.0, 1.0); + } + } + else { + ctime= G.scene->r.cfra - ob->sf; + ctime /= cu->pathlen; + + CLAMP(ctime, 0.0, 1.0); + } + + /* time calculus is correct, now apply distance offset */ + if(cu->flag & CU_OFFS_PATHDIST) { + ctime += timeoffs/cu->path->totdist; + + /* restore */ + SWAP(float, timeoffs, ob->sf); + } + + + /* vec: 4 items! */ + if( where_on_path(par, ctime, vec, dir) ) { + + if(cu->flag & CU_FOLLOW) { + quat= vectoquat(dir, ob->trackflag, ob->upflag); + + /* the tilt */ + Normalize(dir); + q[0]= (float)cos(0.5*vec[3]); + x1= (float)sin(0.5*vec[3]); + q[1]= -x1*dir[0]; + q[2]= -x1*dir[1]; + q[3]= -x1*dir[2]; + QuatMul(quat, q, quat); + + QuatToMat4(quat, mat); + } + + VECCOPY(mat[3], vec); + + } +} + +static void ob_parbone(Object *ob, Object *par, float mat[][4]) +{ + bPoseChannel *pchan; + bArmature *arm; + float vec[3]; + + arm=get_armature(par); + if (!arm) { + Mat4One(mat); + return; + } + + /* Make sure the bone is still valid */ + pchan= get_pose_channel(par->pose, ob->parsubstr); + if (!pchan){ + printf ("Object %s with Bone parent: bone %s doesn't exist\n", ob->id.name+2, ob->parsubstr); + Mat4One(mat); + return; + } + + /* get bone transform */ + Mat4CpyMat4(mat, pchan->pose_mat); + + /* but for backwards compatibility, the child has to move to the tail */ + VECCOPY(vec, mat[1]); + VecMulf(vec, pchan->bone->length); + VecAddf(mat[3], mat[3], vec); +} + +static void give_parvert(Object *par, int nr, float *vec) +{ + int a, count; + + vec[0]=vec[1]=vec[2]= 0.0f; + + if(par->type==OB_MESH) { + if(G.obedit && (par->data==G.obedit->data)) { + EditMesh *em = G.editMesh; + EditVert *eve; + + for(eve= em->verts.first; eve; eve= eve->next) { + if(eve->keyindex==nr) { + memcpy(vec, eve->co, 12); + break; + } + } + } + else { + DerivedMesh *dm = par->derivedFinal; + + if(dm) { + int i, count = 0, numVerts = dm->getNumVerts(dm); + int *index = (int *)dm->getVertDataArray(dm, CD_ORIGINDEX); + float co[3]; + + /* get the average of all verts with (original index == nr) */ + for(i = 0; i < numVerts; ++i, ++index) { + if(*index == nr) { + dm->getVertCo(dm, i, co); + VecAddf(vec, vec, co); + count++; + } + } + + if(count > 0) { + VecMulf(vec, 1.0f / count); + } else { + dm->getVertCo(dm, 0, vec); + } + } + } + } + else if ELEM(par->type, OB_CURVE, OB_SURF) { + Nurb *nu; + Curve *cu; + BPoint *bp; + BezTriple *bezt; + + cu= par->data; + nu= cu->nurb.first; + if(par==G.obedit) nu= editNurb.first; + + count= 0; + while(nu) { + if((nu->type & 7)==CU_BEZIER) { + bezt= nu->bezt; + a= nu->pntsu; + while(a--) { + if(count==nr) { + VECCOPY(vec, bezt->vec[1]); + break; + } + count++; + bezt++; + } + } + else { + bp= nu->bp; + a= nu->pntsu*nu->pntsv; + while(a--) { + if(count==nr) { + memcpy(vec, bp->vec, 12); + break; + } + count++; + bp++; + } + } + nu= nu->next; + } + + } + else if(par->type==OB_LATTICE) { + Lattice *latt= par->data; + BPoint *bp; + DispList *dl = find_displist(&par->disp, DL_VERTS); + float *co = dl?dl->verts:NULL; + + if(par==G.obedit) latt= editLatt; + + a= latt->pntsu*latt->pntsv*latt->pntsw; + count= 0; + bp= latt->def; + while(a--) { + if(count==nr) { + if(co) + memcpy(vec, co, 3*sizeof(float)); + else + memcpy(vec, bp->vec, 3*sizeof(float)); + break; + } + count++; + if(co) co+= 3; + else bp++; + } + } +} + +static void ob_parvert3(Object *ob, Object *par, float mat[][4]) +{ + float cmat[3][3], v1[3], v2[3], v3[3], q[4]; + + /* in local ob space */ + Mat4One(mat); + + if ELEM4(par->type, OB_MESH, OB_SURF, OB_CURVE, OB_LATTICE) { + + give_parvert(par, ob->par1, v1); + give_parvert(par, ob->par2, v2); + give_parvert(par, ob->par3, v3); + + triatoquat(v1, v2, v3, q); + QuatToMat3(q, cmat); + Mat4CpyMat3(mat, cmat); + + if(ob->type==OB_CURVE) { + VECCOPY(mat[3], v1); + } + else { + VecAddf(mat[3], v1, v2); + VecAddf(mat[3], mat[3], v3); + VecMulf(mat[3], 0.3333333f); + } + } +} + +static int no_parent_ipo=0; +void set_no_parent_ipo(int val) +{ + no_parent_ipo= val; +} + +static int during_script_flag=0; +void disable_where_script(short on) +{ + during_script_flag= on; +} + +int during_script(void) { + return during_script_flag; +} + +static int during_scriptlink_flag=0; +void disable_where_scriptlink(short on) +{ + during_scriptlink_flag= on; +} + +int during_scriptlink(void) { + return during_scriptlink_flag; +} + +void where_is_object_time(Object *ob, float ctime) +{ + float *fp1, *fp2, slowmat[4][4] = MAT4_UNITY; + float stime, fac1, fac2, vec[3]; + int a; + int pop; + + /* new version: correct parent+vertexparent and track+parent */ + /* this one only calculates direct attached parent and track */ + /* is faster, but should keep track of timeoffs */ + + if(ob==NULL) return; + + /* this is needed to be able to grab objects with ipos, otherwise it always freezes them */ + stime= bsystem_time(ob, ctime, 0.0); + if(stime != ob->ctime) { + + ob->ctime= stime; + + if(ob->ipo) { + calc_ipo(ob->ipo, stime); + execute_ipo((ID *)ob, ob->ipo); + } + else + do_all_object_actions(ob); + + /* do constraint ipos ..., note it needs stime (0 = all ipos) */ + do_constraint_channels(&ob->constraints, &ob->constraintChannels, stime, 0); + } + else { + /* but, the drivers have to be done */ + if(ob->ipo) do_ob_ipodrivers(ob, ob->ipo, stime); + /* do constraint ipos ..., note it needs stime (1 = only drivers ipos) */ + do_constraint_channels(&ob->constraints, &ob->constraintChannels, stime, 1); + } + + if(ob->parent) { + Object *par= ob->parent; + + if(ob->ipoflag & OB_OFFS_PARENT) ctime-= ob->sf; + + /* hurms, code below conflicts with depgraph... (ton) */ + /* and even worse, it gives bad effects for NLA stride too (try ctime != par->ctime, with MBlur) */ + pop= 0; + if(no_parent_ipo==0 && stime != par->ctime) { + + // only for ipo systems? + pushdata(par, sizeof(Object)); + pop= 1; + + if(par->proxy_from); // was a copied matrix, no where_is! bad... + else where_is_object_time(par, ctime); + } + + solve_parenting(ob, par, ob->obmat, slowmat, 0); + + if(pop) { + poplast(par); + } + + if(ob->partype & PARSLOW) { + // include framerate + + fac1= (1.0f/(1.0f+ fabs(ob->sf))); + if(fac1>=1.0) return; + fac2= 1.0f-fac1; + + fp1= ob->obmat[0]; + fp2= slowmat[0]; + for(a=0; a<16; a++, fp1++, fp2++) { + fp1[0]= fac1*fp1[0] + fac2*fp2[0]; + } + } + + } + else { + object_to_mat4(ob, ob->obmat); + } + + /* Handle tracking */ + if(ob->track) { + if( ctime != ob->track->ctime) where_is_object_time(ob->track, ctime); + solve_tracking (ob, ob->track->obmat); + + } + + /* solve constraints */ + if (ob->constraints.first) { + bConstraintOb *cob; + + cob= constraints_make_evalob(ob, NULL, CONSTRAINT_OBTYPE_OBJECT); + + /* constraints need ctime, not stime. Some call where_is_object_time and bsystem_time */ + solve_constraints (&ob->constraints, cob, ctime); + + constraints_clear_evalob(cob); + } + + if(ob->scriptlink.totscript && !during_script()) { + if (G.f & G_DOSCRIPTLINKS) BPY_do_pyscript((ID *)ob, SCRIPT_REDRAW); + } + + /* set negative scale flag in object */ + Crossf(vec, ob->obmat[0], ob->obmat[1]); + if( Inpf(vec, ob->obmat[2]) < 0.0 ) ob->transflag |= OB_NEG_SCALE; + else ob->transflag &= ~OB_NEG_SCALE; +} + +static void solve_parenting (Object *ob, Object *par, float obmat[][4], float slowmat[][4], int simul) +{ + float totmat[4][4]; + float tmat[4][4]; + float locmat[4][4]; + float vec[3]; + int ok; + + object_to_mat4(ob, locmat); + + if(ob->partype & PARSLOW) Mat4CpyMat4(slowmat, obmat); + + + switch(ob->partype & PARTYPE) { + case PAROBJECT: + ok= 0; + if(par->type==OB_CURVE) { + if( ((Curve *)par->data)->flag & CU_PATH ) { + ob_parcurve(ob, par, tmat); + ok= 1; + } + } + + if(ok) Mat4MulSerie(totmat, par->obmat, tmat, + NULL, NULL, NULL, NULL, NULL, NULL); + else Mat4CpyMat4(totmat, par->obmat); + + break; + case PARBONE: + ob_parbone(ob, par, tmat); + Mat4MulSerie(totmat, par->obmat, tmat, + NULL, NULL, NULL, NULL, NULL, NULL); + break; + + case PARVERT1: + Mat4One(totmat); + if (simul){ + VECCOPY(totmat[3], par->obmat[3]); + } + else{ + give_parvert(par, ob->par1, vec); + VecMat4MulVecfl(totmat[3], par->obmat, vec); + } + break; + case PARVERT3: + ob_parvert3(ob, par, tmat); + + Mat4MulSerie(totmat, par->obmat, tmat, + NULL, NULL, NULL, NULL, NULL, NULL); + break; + + case PARSKEL: + Mat4CpyMat4(totmat, par->obmat); + break; + } + + // total + Mat4MulSerie(tmat, totmat, ob->parentinv, + NULL, NULL, NULL, NULL, NULL, NULL); + Mat4MulSerie(obmat, tmat, locmat, + NULL, NULL, NULL, NULL, NULL, NULL); + + if (simul) { + + } + else{ + // external usable originmat + Mat3CpyMat4(originmat, tmat); + + // origin, voor help line + if( (ob->partype & 15)==PARSKEL ) { + VECCOPY(ob->orig, par->obmat[3]); + } + else { + VECCOPY(ob->orig, totmat[3]); + } + } + +} +void solve_tracking (Object *ob, float targetmat[][4]) +{ + float *quat; + float vec[3]; + float totmat[3][3]; + float tmat[4][4]; + + VecSubf(vec, ob->obmat[3], targetmat[3]); + quat= vectoquat(vec, ob->trackflag, ob->upflag); + QuatToMat3(quat, totmat); + + if(ob->parent && (ob->transflag & OB_POWERTRACK)) { + /* 'temporal' : clear parent info */ + object_to_mat4(ob, tmat); + tmat[0][3]= ob->obmat[0][3]; + tmat[1][3]= ob->obmat[1][3]; + tmat[2][3]= ob->obmat[2][3]; + tmat[3][0]= ob->obmat[3][0]; + tmat[3][1]= ob->obmat[3][1]; + tmat[3][2]= ob->obmat[3][2]; + tmat[3][3]= ob->obmat[3][3]; + } + else Mat4CpyMat4(tmat, ob->obmat); + + Mat4MulMat34(ob->obmat, totmat, tmat); + +} + +void where_is_object(Object *ob) +{ + where_is_object_time(ob, (float)G.scene->r.cfra); +} + + +void where_is_object_simul(Object *ob) +/* was written for the old game engine (until 2.04) */ +/* It seems that this function is only called +for a lamp that is the child of another object */ +{ + Object *par; + Ipo *ipo; + float *fp1, *fp2; + float slowmat[4][4]; + float fac1, fac2; + int a; + + /* NO TIMEOFFS */ + + /* no ipo! (because of dloc and realtime-ipos) */ + ipo= ob->ipo; + ob->ipo= NULL; + + if(ob->parent) { + par= ob->parent; + + solve_parenting(ob, par, ob->obmat, slowmat, 1); + + if(ob->partype & PARSLOW) { + + fac1= (float)(1.0/(1.0+ fabs(ob->sf))); + fac2= 1.0f-fac1; + fp1= ob->obmat[0]; + fp2= slowmat[0]; + for(a=0; a<16; a++, fp1++, fp2++) { + fp1[0]= fac1*fp1[0] + fac2*fp2[0]; + } + } + + } + else { + object_to_mat4(ob, ob->obmat); + } + + if(ob->track) + solve_tracking(ob, ob->track->obmat); + + /* solve constraints */ + if (ob->constraints.first) { + bConstraintOb *cob; + + cob= constraints_make_evalob(ob, NULL, CONSTRAINT_OBTYPE_OBJECT); + solve_constraints (&ob->constraints, cob, G.scene->r.cfra); + constraints_clear_evalob(cob); + } + + /* WATCH IT!!! */ + ob->ipo= ipo; +} + +/* for calculation of the inverse parent transform, only used for editor */ +void what_does_parent(Object *ob) +{ + clear_workob(); + Mat4One(workob.obmat); + Mat4One(workob.parentinv); + Mat4One(workob.constinv); + workob.parent= ob->parent; + workob.track= ob->track; + + workob.trackflag= ob->trackflag; + workob.upflag= ob->upflag; + + workob.partype= ob->partype; + workob.par1= ob->par1; + workob.par2= ob->par2; + workob.par3= ob->par3; + + workob.constraints.first = ob->constraints.first; + workob.constraints.last = ob->constraints.last; + + strcpy(workob.parsubstr, ob->parsubstr); + + where_is_object(&workob); +} + +BoundBox *unit_boundbox() +{ + BoundBox *bb; + float min[3] = {-1,-1,-1}, max[3] = {-1,-1,-1}; + + bb= MEM_mallocN(sizeof(BoundBox), "bb"); + boundbox_set_from_min_max(bb, min, max); + + return bb; +} + +void boundbox_set_from_min_max(BoundBox *bb, float min[3], float max[3]) +{ + bb->vec[0][0]=bb->vec[1][0]=bb->vec[2][0]=bb->vec[3][0]= min[0]; + bb->vec[4][0]=bb->vec[5][0]=bb->vec[6][0]=bb->vec[7][0]= max[0]; + + bb->vec[0][1]=bb->vec[1][1]=bb->vec[4][1]=bb->vec[5][1]= min[1]; + bb->vec[2][1]=bb->vec[3][1]=bb->vec[6][1]=bb->vec[7][1]= max[1]; + + bb->vec[0][2]=bb->vec[3][2]=bb->vec[4][2]=bb->vec[7][2]= min[2]; + bb->vec[1][2]=bb->vec[2][2]=bb->vec[5][2]=bb->vec[6][2]= max[2]; +} + +BoundBox *object_get_boundbox(Object *ob) +{ + BoundBox *bb= NULL; + + if(ob->type==OB_MESH) { + bb = mesh_get_bb(ob->data); + } + else if ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT) { + bb= ( (Curve *)ob->data )->bb; + } + else if(ob->type==OB_MBALL) { + bb= ob->bb; + } + return bb; +} + +/* used to temporally disable/enable boundbox */ +void object_boundbox_flag(Object *ob, int flag, int set) +{ + BoundBox *bb= object_get_boundbox(ob); + if(bb) { + if(set) bb->flag |= flag; + else bb->flag &= ~flag; + } +} + +void minmax_object(Object *ob, float *min, float *max) +{ + BoundBox bb; + Mesh *me; + Curve *cu; + float vec[3]; + int a; + + switch(ob->type) { + + case OB_CURVE: + case OB_FONT: + case OB_SURF: + cu= ob->data; + + if(cu->bb==NULL) tex_space_curve(cu); + bb= *(cu->bb); + + for(a=0; a<8; a++) { + Mat4MulVecfl(ob->obmat, bb.vec[a]); + DO_MINMAX(bb.vec[a], min, max); + } + break; + case OB_ARMATURE: + if(ob->pose) { + bPoseChannel *pchan; + for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { + VECCOPY(vec, pchan->pose_head); + Mat4MulVecfl(ob->obmat, vec); + DO_MINMAX(vec, min, max); + VECCOPY(vec, pchan->pose_tail); + Mat4MulVecfl(ob->obmat, vec); + DO_MINMAX(vec, min, max); + } + break; + } + /* no break, get_mesh will give NULL and it passes on to default */ + case OB_MESH: + me= get_mesh(ob); + + if(me) { + bb = *mesh_get_bb(me); + + for(a=0; a<8; a++) { + Mat4MulVecfl(ob->obmat, bb.vec[a]); + DO_MINMAX(bb.vec[a], min, max); + } + } + if(min[0] < max[0] ) break; + + /* else here no break!!!, mesh can be zero sized */ + + default: + DO_MINMAX(ob->obmat[3], min, max); + + VECCOPY(vec, ob->obmat[3]); + VecAddf(vec, vec, ob->size); + DO_MINMAX(vec, min, max); + + VECCOPY(vec, ob->obmat[3]); + VecSubf(vec, vec, ob->size); + DO_MINMAX(vec, min, max); + break; + } +} + +/* TODO - use dupli objects bounding boxes */ +void minmax_object_duplis(Object *ob, float *min, float *max) +{ + if ((ob->transflag & OB_DUPLI)==0) { + return; + } else { + ListBase *lb; + DupliObject *dob; + + lb= object_duplilist(G.scene, ob); + for(dob= lb->first; dob; dob= dob->next) { + if(dob->no_draw); + else { + /* should really use bound box of dup object */ + DO_MINMAX(dob->mat[3], min, max); + } + } + free_object_duplilist(lb); /* does restore */ + } +} + + +/* proxy rule: lib_object->proxy_from == the one we borrow from, only set temporal and cleared here */ +/* local_object->proxy == pointer to library object, saved in files and read */ + +/* function below is polluted with proxy exceptions, cleanup will follow! */ + +/* the main object update call, for object matrix, constraints, keys and displist (modifiers) */ +/* requires flags to be set! */ +void object_handle_update(Object *ob) +{ + if(ob->recalc & OB_RECALC) { + + if(ob->recalc & OB_RECALC_OB) { + + // printf("recalcob %s\n", ob->id.name+2); + + /* handle proxy copy for target */ + if(ob->id.lib && ob->proxy_from) { + // printf("ob proxy copy, lib ob %s proxy %s\n", ob->id.name, ob->proxy_from->id.name); + if(ob->proxy_from->proxy_group) {/* transform proxy into group space */ + Object *obg= ob->proxy_from->proxy_group; + Mat4Invert(obg->imat, obg->obmat); + Mat4MulMat4(ob->obmat, ob->proxy_from->obmat, obg->imat); + } + else + Mat4CpyMat4(ob->obmat, ob->proxy_from->obmat); + } + else + where_is_object(ob); + } + + if(ob->recalc & OB_RECALC_DATA) { + + // printf("recalcdata %s\n", ob->id.name+2); + + /* includes all keys and modifiers */ + if(ob->type==OB_MESH) { + makeDerivedMesh(ob, get_viewedit_datamask()); + } + else if(ob->type==OB_MBALL) { + makeDispListMBall(ob); + } + else if(ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { + makeDispListCurveTypes(ob, 0); + } + else if(ob->type==OB_LATTICE) { + lattice_calc_modifiers(ob); + } + else if(ob->type==OB_ARMATURE) { + /* this happens for reading old files and to match library armatures with poses */ + if(ob->pose==NULL || (ob->pose->flag & POSE_RECALC)) + armature_rebuild_pose(ob, ob->data); + + if(ob->id.lib && ob->proxy_from) { + copy_pose_result(ob->pose, ob->proxy_from->pose); + // printf("pose proxy copy, lib ob %s proxy %s\n", ob->id.name, ob->proxy_from->id.name); + } + else { + do_all_pose_actions(ob); + where_is_pose(ob); + } + } + } + + /* the no-group proxy case, we call update */ + if(ob->proxy && ob->proxy_group==NULL) { + /* set pointer in library proxy target, for copying, but restore it */ + ob->proxy->proxy_from= ob; + // printf("call update, lib ob %s proxy %s\n", ob->proxy->id.name, ob->id.name); + object_handle_update(ob->proxy); + } + + ob->recalc &= ~OB_RECALC; + } + + /* the case when this is a group proxy, object_update is called in group.c */ + if(ob->proxy) { + ob->proxy->proxy_from= ob; + // printf("set proxy pointer for later group stuff %s\n", ob->id.name); + } +} diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c new file mode 100644 index 00000000000..bd33fafe23c --- /dev/null +++ b/source/blender/blenkernel/intern/packedFile.c @@ -0,0 +1,614 @@ +/** + * blenkernel/packedFile.c - (cleaned up mar-01 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifndef WIN32 +#include +#else +#include +#endif +#include +#include "MEM_guardedalloc.h" + +#include "DNA_image_types.h" +#include "DNA_sound_types.h" +#include "DNA_vfont_types.h" +#include "DNA_packedFile_types.h" +#include "DNA_scene_types.h" + +#include "BLI_blenlib.h" + +#include "BKE_utildefines.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_screen.h" +#include "BKE_sound.h" +#include "BKE_image.h" +#include "BKE_font.h" +#include "BKE_packedFile.h" +#include "BKE_bad_level_calls.h" /* <- waitcursor */ + +int seekPackedFile(PackedFile * pf, int offset, int whence) +{ + int oldseek = -1, seek = 0; + + if (pf) { + oldseek = pf->seek; + switch(whence) { + case SEEK_CUR: + seek = oldseek + offset; + break; + case SEEK_END: + seek = pf->size + offset; + break; + case SEEK_SET: + seek = offset; + break; + default: + oldseek = -1; + } + if (seek < 0) { + seek = 0; + } else if (seek > pf->size) { + seek = pf->size; + } + pf->seek = seek; + } + + return(oldseek); +} + +void rewindPackedFile(PackedFile * pf) +{ + seekPackedFile(pf, 0, SEEK_SET); +} + +int readPackedFile(PackedFile * pf, void * data, int size) +{ + if ((pf != NULL) && (size >= 0) && (data != NULL)) { + if (size + pf->seek > pf->size) { + size = pf->size - pf->seek; + } + + if (size > 0) { + memcpy(data, ((char *) pf->data) + pf->seek, size); + } else { + size = 0; + } + + pf->seek += size; + } else { + size = -1; + } + + return(size); +} + +int countPackedFiles() +{ + int count = 0; + Image *ima; + VFont *vf; + bSample *sample; + + // let's check if there are packed files... + ima = G.main->image.first; + while (ima) { + if (ima->packedfile) { + count++; + } + ima= ima->id.next; + } + + vf = G.main->vfont.first; + while (vf) { + if (vf->packedfile) { + count++; + } + vf = vf->id.next; + } + + sample = samples->first; + while (sample) { + if (sample->packedfile) { + count++; + } + sample = sample->id.next; + } + + return(count); +} + +void freePackedFile(PackedFile * pf) +{ + if (pf) { + MEM_freeN(pf->data); + MEM_freeN(pf); + } else { + printf("freePackedFile: Trying to free a NULL pointer\n"); + } +} + +PackedFile * newPackedFileMemory(void *mem, int memlen) +{ + PackedFile * pf = MEM_callocN(sizeof(*pf), "PackedFile"); + pf->data = mem; + pf->size = memlen; + + return pf; +} + +PackedFile * newPackedFile(char * filename) +{ + PackedFile * pf = NULL; + int file, filelen; + char name[FILE_MAXDIR+FILE_MAXFILE]; + void * data; + + waitcursor(1); + + // convert relative filenames to absolute filenames + + strcpy(name, filename); + BLI_convertstringcode(name, G.sce, G.scene->r.cfra); + + // open the file + // and create a PackedFile structure + + file= open(name, O_BINARY|O_RDONLY); + if (file <= 0) { + // error("Can't open file: %s", name); + } else { + filelen = BLI_filesize(file); + + if (filelen == 0) { + // MEM_mallocN complains about MEM_mallocN(0, "bla"); + // we don't care.... + data = MEM_mallocN(1, "packFile"); + } else { + data = MEM_mallocN(filelen, "packFile"); + } + if (read(file, data, filelen) == filelen) { + pf = newPackedFileMemory(data, filelen); + } + + close(file); + } + + waitcursor(0); + + return (pf); +} + +void packAll() +{ + Image *ima; + VFont *vf; + bSample *sample; + + ima = G.main->image.first; + while (ima) { + if (ima->packedfile == NULL) { + ima->packedfile = newPackedFile(ima->name); + } + ima= ima->id.next; + } + + vf = G.main->vfont.first; + while (vf) { + if (vf->packedfile == NULL) { + vf->packedfile = newPackedFile(vf->name); + } + vf = vf->id.next; + } + + + sample = samples->first; + while (sample) { + if (sample->packedfile == NULL) { + sound_set_packedfile(sample, newPackedFile(sample->name)); + } + sample = sample->id.next; + } +} + + +/* + +// attempt to create a function that generates an unique filename +// this will work when all funtions in fileops.c understand relative filenames... + +char * find_new_name(char * name) +{ + char tempname[FILE_MAXDIR + FILE_MAXFILE]; + char * newname; + + if (fop_exists(name)) { + for (number = 1; number <= 999; number++) { + sprintf(tempname, "%s.%03d", name, number); + if (! fop_exists(tempname)) { + break; + } + } + } + + newname = mallocN(strlen(tempname) + 1, "find_new_name"); + strcpy(newname, tempname); + + return(newname); +} + +*/ + +int writePackedFile(char * filename, PackedFile *pf, int guimode) +{ + int file, number, remove_tmp = FALSE; + int ret_value = RET_OK; + char name[FILE_MAXDIR + FILE_MAXFILE]; + char tempname[FILE_MAXDIR + FILE_MAXFILE]; +/* void * data; */ + + if (guimode) waitcursor(1); + + strcpy(name, filename); + BLI_convertstringcode(name, G.sce, G.scene->r.cfra); + + if (BLI_exists(name)) { + for (number = 1; number <= 999; number++) { + sprintf(tempname, "%s.%03d_", name, number); + if (! BLI_exists(tempname)) { + if (BLI_copy_fileops(name, tempname) == RET_OK) { + remove_tmp = TRUE; + } + break; + } + } + } + + // make sure the path to the file exists... + BLI_make_existing_file(name); + + file = open(name, O_BINARY + O_WRONLY + O_CREAT + O_TRUNC, 0666); + if (file >= 0) { + if (write(file, pf->data, pf->size) != pf->size) { + if(guimode) error("Error writing file: %s", name); + ret_value = RET_ERROR; + } + close(file); + } else { + if(guimode) error("Error creating file: %s", name); + ret_value = RET_ERROR; + } + + if (remove_tmp) { + if (ret_value == RET_ERROR) { + if (BLI_rename(tempname, name) == RET_ERROR) { + if(guimode) error("Error restoring tempfile. Check files: '%s' '%s'", tempname, name); + } + } else { + if (BLI_delete(tempname, 0, 0) == RET_ERROR) { + if(guimode) error("Error deleting '%s' (ignored)"); + } + } + } + + if(guimode) waitcursor(0); + + return (ret_value); +} + +/* + +This function compares a packed file to a 'real' file. +It returns an integer indicating if: + +PF_EQUAL - the packed file and original file are identical +PF_DIFFERENT - the packed file and original file differ +PF_NOFILE - the original file doens't exist + +*/ + +int checkPackedFile(char * filename, PackedFile * pf) +{ + struct stat st; + int ret_val, i, len, file; + char buf[4096]; + char name[FILE_MAXDIR + FILE_MAXFILE]; + + strcpy(name, filename); + BLI_convertstringcode(name, G.sce, G.scene->r.cfra); + + if (stat(name, &st)) { + ret_val = PF_NOFILE; + } else if (st.st_size != pf->size) { + ret_val = PF_DIFFERS; + } else { + // we'll have to compare the two... + + file = open(name, O_BINARY | O_RDONLY); + if (file < 0) { + ret_val = PF_NOFILE; + } else { + ret_val = PF_EQUAL; + + for (i = 0; i < pf->size; i += sizeof(buf)) { + len = pf->size - i; + if (len > sizeof(buf)) { + len = sizeof(buf); + } + + if (read(file, buf, len) != len) { + // read error ... + ret_val = PF_DIFFERS; + break; + } else { + if (memcmp(buf, ((char *)pf->data) + i, len)) { + ret_val = PF_DIFFERS; + break; + } + } + } + } + } + + return(ret_val); +} + +/* + +unpackFile() looks at the existing files (abs_name, local_name) and a packed file. +If how == PF_ASK it offers the user a couple of options what to do with the packed file. + +It returns a char * to the existing file name / new file name or NULL when +there was an error or when the user desides to cancel the operation. + +*/ + +char *unpackFile(char * abs_name, char * local_name, PackedFile * pf, int how) +{ + char menu[6 * (FILE_MAXDIR + FILE_MAXFILE + 100)]; + char line[FILE_MAXDIR + FILE_MAXFILE + 100]; + char * newname = NULL, * temp = NULL; + + // char newabs[FILE_MAXDIR + FILE_MAXFILE]; + // char newlocal[FILE_MAXDIR + FILE_MAXFILE]; + + if (pf != NULL) { + if (how == PF_ASK) { + sprintf(menu, "UnPack file%%t|Remove Pack %%x%d", PF_REMOVE); + + if (strcmp(abs_name, local_name)) { + switch (checkPackedFile(local_name, pf)) { + case PF_NOFILE: + sprintf(line, "|Create %s%%x%d", local_name, PF_WRITE_LOCAL); + strcat(menu, line); + break; + case PF_EQUAL: + sprintf(line, "|Use %s (identical)%%x%d", local_name, PF_USE_LOCAL); + strcat(menu, line); + break; + case PF_DIFFERS: + sprintf(line, "|Use %s (differs)%%x%d", local_name, PF_USE_LOCAL); + strcat(menu, line); + sprintf(line, "|Overwrite %s%%x%d", local_name, PF_WRITE_LOCAL); + strcat(menu, line); + break; + } + // sprintf(line, "|%%x%d", PF_INVALID); + // strcat(menu, line); + } + + switch (checkPackedFile(abs_name, pf)) { + case PF_NOFILE: + sprintf(line, "|Create %s%%x%d", abs_name, PF_WRITE_ORIGINAL); + strcat(menu, line); + break; + case PF_EQUAL: + sprintf(line, "|Use %s (identical)%%x%d", abs_name, PF_USE_ORIGINAL); + strcat(menu, line); + break; + case PF_DIFFERS: + sprintf(line, "|Use %s (differs)%%x%d", abs_name, PF_USE_ORIGINAL); + strcat(menu, line); + sprintf(line, "|Overwrite %s%%x%d", abs_name, PF_WRITE_ORIGINAL); + strcat(menu, line); + break; + } + + how = pupmenu(menu); + } + + switch (how) { + case -1: + case PF_KEEP: + break; + case PF_REMOVE: + temp= abs_name; + break; + case PF_USE_LOCAL: + // if file exists use it + if (BLI_exists(local_name)) { + temp = local_name; + break; + } + // else fall through and create it + case PF_WRITE_LOCAL: + if (writePackedFile(local_name, pf, 1) == RET_OK) { + temp = local_name; + } + break; + case PF_USE_ORIGINAL: + // if file exists use it + if (BLI_exists(abs_name)) { + temp = abs_name; + break; + } + // else fall through and create it + case PF_WRITE_ORIGINAL: + if (writePackedFile(abs_name, pf, 1) == RET_OK) { + temp = abs_name; + } + break; + default: + printf("unpackFile: unknown return_value %d\n", how); + break; + } + + if (temp) { + newname = MEM_mallocN(strlen(temp) + 1, "unpack_file newname"); + strcpy(newname, temp); + } + } + + return (newname); +} + + +int unpackVFont(VFont * vfont, int how) +{ + char localname[FILE_MAXDIR + FILE_MAXFILE], fi[FILE_MAXFILE]; + char * newname; + int ret_value = RET_ERROR; + + if (vfont != NULL) { + strcpy(localname, vfont->name); + BLI_splitdirstring(localname, fi); + + sprintf(localname, "//fonts/%s", fi); + + newname = unpackFile(vfont->name, localname, vfont->packedfile, how); + if (newname != NULL) { + ret_value = RET_OK; + freePackedFile(vfont->packedfile); + vfont->packedfile = 0; + strcpy(vfont->name, newname); + MEM_freeN(newname); + } + } + + return (ret_value); +} + +int unpackSample(bSample *sample, int how) +{ + char localname[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX]; + char * newname; + int ret_value = RET_ERROR; + PackedFile *pf; + + if (sample != NULL) { + strcpy(localname, sample->name); + BLI_splitdirstring(localname, fi); + sprintf(localname, "//samples/%s", fi); + + newname = unpackFile(sample->name, localname, sample->packedfile, how); + if (newname != NULL) { + strcpy(sample->name, newname); + MEM_freeN(newname); + + pf = sample->packedfile; + // because samples and sounds can point to the + // same packedfile we have to check them all + sound_set_packedfile(sample, NULL); + freePackedFile(pf); + + ret_value = RET_OK; + } + } + + return(ret_value); +} + +int unpackImage(Image * ima, int how) +{ + char localname[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX]; + char * newname; + int ret_value = RET_ERROR; + + if (ima != NULL) { + strcpy(localname, ima->name); + BLI_splitdirstring(localname, fi); + sprintf(localname, "//textures/%s", fi); + + newname = unpackFile(ima->name, localname, ima->packedfile, how); + if (newname != NULL) { + ret_value = RET_OK; + freePackedFile(ima->packedfile); + ima->packedfile = NULL; + strcpy(ima->name, newname); + MEM_freeN(newname); + BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD); + } + } + + return(ret_value); +} + +void unpackAll(int how) +{ + Image *ima; + VFont *vf; + bSample *sample; + + ima = G.main->image.first; + while (ima) { + if (ima->packedfile) { + unpackImage(ima, how); + } + ima= ima->id.next; + } + + vf = G.main->vfont.first; + while (vf) { + if (vf->packedfile) { + unpackVFont(vf, how); + } + vf = vf->id.next; + } + + sample = samples->first; + while (sample) { + if (sample->packedfile) { + unpackSample(sample, how); + } + sample = sample->id.next; + } +} diff --git a/source/blender/blenkernel/intern/property.c b/source/blender/blenkernel/intern/property.c new file mode 100644 index 00000000000..a60c03c4840 --- /dev/null +++ b/source/blender/blenkernel/intern/property.c @@ -0,0 +1,269 @@ + +/* property.c june 2000 + * + * ton roosendaal + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_guardedalloc.h" + +#include "DNA_property_types.h" +#include "DNA_object_types.h" +#include "DNA_listBase.h" + + +#include "BLI_blenlib.h" +#include "BKE_bad_level_calls.h" +#include "BKE_property.h" + +void free_property(bProperty *prop) +{ + + if(prop->poin && prop->poin != &prop->data) MEM_freeN(prop->poin); + MEM_freeN(prop); + +} + +void free_properties(ListBase *lb) +{ + bProperty *prop; + + while( (prop= lb->first) ) { + BLI_remlink(lb, prop); + free_property(prop); + } +} + +bProperty *copy_property(bProperty *prop) +{ + bProperty *propn; + + propn= MEM_dupallocN(prop); + if(prop->poin && prop->poin != &prop->data) { + propn->poin= MEM_dupallocN(prop->poin); + } + else propn->poin= &propn->data; + + return propn; +} + +void copy_properties(ListBase *lbn, ListBase *lbo) +{ + bProperty *prop, *propn; + + lbn->first= lbn->last= 0; + prop= lbo->first; + while(prop) { + propn= copy_property(prop); + BLI_addtail(lbn, propn); + prop= prop->next; + } + + +} + +void init_property(bProperty *prop) +{ + /* also use when property changes type */ + + if(prop->poin && prop->poin != &prop->data) MEM_freeN(prop->poin); + prop->poin= 0; + + prop->otype= prop->type; + prop->data= 0; + + switch(prop->type) { + case PROP_BOOL: + prop->poin= &prop->data; + break; + case PROP_INT: + prop->poin= &prop->data; + break; + case PROP_FLOAT: + prop->poin= &prop->data; + break; + case PROP_STRING: + prop->poin= MEM_callocN(MAX_PROPSTRING, "property string"); + break; + case PROP_TIME: + prop->poin= &prop->data; + break; + } +} + + +bProperty *new_property(int type) +{ + bProperty *prop; + + prop= MEM_callocN(sizeof(bProperty), "property"); + prop->type= type; + + init_property(prop); + + strcpy(prop->name, "prop"); + + return prop; +} + +bProperty *get_property(Object *ob, char *name) +{ + bProperty *prop; + + prop= ob->prop.first; + while(prop) { + if( strcmp(prop->name, name)==0 ) return prop; + prop= prop->next; + } + return NULL; +} + +/* negative: prop is smaller + * positive: prop is larger + */ +int compare_property(bProperty *prop, char *str) +{ +// extern int Gdfra; /* sector.c */ + float fvalue, ftest; + + switch(prop->type) { + case PROP_BOOL: + if(BLI_strcasecmp(str, "true")==0) { + if(prop->data==1) return 0; + else return 1; + } + else if(BLI_strcasecmp(str, "false")==0) { + if(prop->data==0) return 0; + else return 1; + } + /* no break, do prop_int too! */ + + case PROP_INT: + return prop->data - atoi(str); + + case PROP_FLOAT: + case PROP_TIME: + // WARNING: untested for PROP_TIME + // function isn't used currently + fvalue= *((float *)&prop->data); + ftest= (float)atof(str); + if( fvalue > ftest) return 1; + else if( fvalue < ftest) return -1; + return 0; + + case PROP_STRING: + return strcmp(prop->poin, str); + } + + return 0; +} + +void set_property(bProperty *prop, char *str) +{ +// extern int Gdfra; /* sector.c */ + + switch(prop->type) { + case PROP_BOOL: + if(BLI_strcasecmp(str, "true")==0) prop->data= 1; + else if(BLI_strcasecmp(str, "false")==0) prop->data= 0; + else prop->data= (atoi(str)!=0); + break; + case PROP_INT: + prop->data= atoi(str); + break; + case PROP_FLOAT: + case PROP_TIME: + *((float *)&prop->data)= (float)atof(str); + break; + case PROP_STRING: + strcpy(prop->poin, str); + break; + } + +} + +void add_property(bProperty *prop, char *str) +{ +// extern int Gdfra; /* sector.c */ + + switch(prop->type) { + case PROP_BOOL: + case PROP_INT: + prop->data+= atoi(str); + break; + case PROP_FLOAT: + case PROP_TIME: + *((float *)&prop->data)+= (float)atof(str); + break; + case PROP_STRING: + /* strcpy(prop->poin, str); */ + break; + } +} + +/* reads value of property, sets it in chars in str */ +void set_property_valstr(bProperty *prop, char *str) +{ +// extern int Gdfra; /* sector.c */ + + if(str == NULL) return; + + switch(prop->type) { + case PROP_BOOL: + case PROP_INT: + sprintf(str, "%d", prop->data); + break; + case PROP_FLOAT: + case PROP_TIME: + sprintf(str, "%f", *((float *)&prop->data)); + break; + case PROP_STRING: + BLI_strncpy(str, prop->poin, MAX_PROPSTRING); + break; + } +} + +void cp_property(bProperty *prop1, bProperty *prop2) +{ + char str[128]; + + set_property_valstr(prop2, str); + + set_property(prop1, str); +} diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c new file mode 100644 index 00000000000..e772a3bcdb4 --- /dev/null +++ b/source/blender/blenkernel/intern/sca.c @@ -0,0 +1,638 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * these all are linked to objects (listbase) + * all data is 'direct data', not Blender lib data. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include "MEM_guardedalloc.h" + +#include "nla.h" /* For __NLA: Important, do not remove */ +#include "DNA_text_types.h" +#include "DNA_controller_types.h" +#include "DNA_sensor_types.h" +#include "DNA_actuator_types.h" +#include "DNA_object_types.h" + +#include "BLI_blenlib.h" +#include "BKE_bad_level_calls.h" +#include "BKE_utildefines.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_blender.h" +#include "BKE_sca.h" + +void free_text_controllers(Text *txt) +{ + Object *ob; + bController *cont; + + ob= G.main->object.first; + while(ob) { + cont= ob->controllers.first; + while(cont) { + if(cont->type==CONT_PYTHON) { + bPythonCont *pc; + + pc= cont->data; + if(pc->text==txt) pc->text= NULL; + } + cont= cont->next; + } + ob= ob->id.next; + } +} + + +/* ******************* SENSORS ************************ */ + +void free_sensor(bSensor *sens) +{ + if(sens->links) MEM_freeN(sens->links); + if(sens->data) MEM_freeN(sens->data); + MEM_freeN(sens); + +} + +void free_sensors(ListBase *lb) +{ + bSensor *sens; + + while((sens= lb->first)) { + BLI_remlink(lb, sens); + free_sensor(sens); + } +} + +bSensor *copy_sensor(bSensor *sens) +{ + bSensor *sensn; + + sensn= MEM_dupallocN(sens); + sensn->flag |= SENS_NEW; + if(sens->data) { + sensn->data= MEM_dupallocN(sens->data); + } + + if(sens->links) sensn->links= MEM_dupallocN(sens->links); + + return sensn; +} + +void copy_sensors(ListBase *lbn, ListBase *lbo) +{ + bSensor *sens, *sensn; + + lbn->first= lbn->last= 0; + sens= lbo->first; + while(sens) { + sensn= copy_sensor(sens); + BLI_addtail(lbn, sensn); + sens= sens->next; + } +} + +void init_sensor(bSensor *sens) +{ + /* also use when sensor changes type */ + bNearSensor *ns; + bMouseSensor *ms; + + if(sens->data) MEM_freeN(sens->data); + sens->data= NULL; + sens->pulse = 0; + + switch(sens->type) { + case SENS_ALWAYS: + sens->pulse = 1; + break; + case SENS_TOUCH: + sens->data= MEM_callocN(sizeof(bTouchSensor), "touchsens"); + break; + case SENS_NEAR: + ns=sens->data= MEM_callocN(sizeof(bNearSensor), "nearsens"); + ns->dist= 1.0; + ns->resetdist= 2.0; + break; + case SENS_KEYBOARD: + sens->data= MEM_callocN(sizeof(bKeyboardSensor), "keysens"); + break; + case SENS_PROPERTY: + sens->data= MEM_callocN(sizeof(bPropertySensor), "propsens"); + break; + case SENS_MOUSE: + ms=sens->data= MEM_callocN(sizeof(bMouseSensor), "mousesens"); + ms->type= LEFTMOUSE; + break; + case SENS_COLLISION: + sens->data= MEM_callocN(sizeof(bCollisionSensor), "colsens"); + break; + case SENS_RADAR: + sens->data= MEM_callocN(sizeof(bRadarSensor), "radarsens"); + break; + case SENS_RANDOM: + sens->data= MEM_callocN(sizeof(bRandomSensor), "randomsens"); + break; + case SENS_RAY: + sens->data= MEM_callocN(sizeof(bRaySensor), "raysens"); + break; + case SENS_MESSAGE: + sens->data= MEM_callocN(sizeof(bMessageSensor), "messagesens"); + break; + case SENS_JOYSTICK: + sens->data= MEM_callocN(sizeof(bJoystickSensor), "joysticksens"); + break; + default: + ; /* this is very severe... I cannot make any memory for this */ + /* logic brick... */ + } +} + +bSensor *new_sensor(int type) +{ + bSensor *sens; + + sens= MEM_callocN(sizeof(bSensor), "Sensor"); + sens->type= type; + sens->flag= SENS_SHOW; + + init_sensor(sens); + + strcpy(sens->name, "sensor"); + make_unique_prop_names(sens->name); + + return sens; +} + +/* ******************* CONTROLLERS ************************ */ + +void unlink_controller(bController *cont) +{ + bSensor *sens; + Object *ob; + int a, removed; + + /* check for controller pointers in sensors */ + ob= G.main->object.first; + while(ob) { + sens= ob->sensors.first; + while(sens) { + removed= 0; + for(a=0; atotlinks; a++) { + if(removed) (sens->links)[a-1] = (sens->links)[a]; + else if((sens->links)[a] == cont) removed= 1; + } + if(removed) { + sens->totlinks--; + + if(sens->totlinks==0) { + MEM_freeN(sens->links); + sens->links= NULL; + } + } + sens= sens->next; + } + ob= ob->id.next; + } +} + +void unlink_controllers(ListBase *lb) +{ + bController *cont; + + for (cont= lb->first; cont; cont= cont->next) + unlink_controller(cont); +} + +void free_controller(bController *cont) +{ + if(cont->links) MEM_freeN(cont->links); + + /* the controller itself */ + if(cont->data) MEM_freeN(cont->data); + MEM_freeN(cont); + +} + +void free_controllers(ListBase *lb) +{ + bController *cont; + + while((cont= lb->first)) { + BLI_remlink(lb, cont); + if(cont->slinks) MEM_freeN(cont->slinks); + free_controller(cont); + } +} + +bController *copy_controller(bController *cont) +{ + bController *contn; + + cont->mynew=contn= MEM_dupallocN(cont); + contn->flag |= CONT_NEW; + if(cont->data) { + contn->data= MEM_dupallocN(cont->data); + } + + if(cont->links) contn->links= MEM_dupallocN(cont->links); + contn->slinks= NULL; + contn->totslinks= 0; + + return contn; +} + +void copy_controllers(ListBase *lbn, ListBase *lbo) +{ + bController *cont, *contn; + + lbn->first= lbn->last= 0; + cont= lbo->first; + while(cont) { + contn= copy_controller(cont); + BLI_addtail(lbn, contn); + cont= cont->next; + } +} + +void init_controller(bController *cont) +{ + /* also use when controller changes type, leave actuators... */ + + if(cont->data) MEM_freeN(cont->data); + cont->data= 0; + + switch(cont->type) { + case CONT_EXPRESSION: + cont->data= MEM_callocN(sizeof(bExpressionCont), "expcont"); + break; + case CONT_PYTHON: + cont->data= MEM_callocN(sizeof(bPythonCont), "pycont"); + break; + } +} + +bController *new_controller(int type) +{ + bController *cont; + + cont= MEM_callocN(sizeof(bController), "Controller"); + cont->type= type; + cont->flag= CONT_SHOW; + + init_controller(cont); + + strcpy(cont->name, "cont"); + make_unique_prop_names(cont->name); + + return cont; +} + +/* ******************* ACTUATORS ************************ */ + +void unlink_actuator(bActuator *act) +{ + bController *cont; + Object *ob; + int a, removed; + + /* check for actuator pointers in controllers */ + ob= G.main->object.first; + while(ob) { + cont= ob->controllers.first; + while(cont) { + removed= 0; + for(a=0; atotlinks; a++) { + if(removed) (cont->links)[a-1] = (cont->links)[a]; + else if((cont->links)[a] == act) removed= 1; + } + if(removed) { + cont->totlinks--; + + if(cont->totlinks==0) { + MEM_freeN(cont->links); + cont->links= NULL; + } + } + cont= cont->next; + } + ob= ob->id.next; + } +} + +void unlink_actuators(ListBase *lb) +{ + bActuator *act; + + for (act= lb->first; act; act= act->next) + unlink_actuator(act); +} + +void free_actuator(bActuator *act) +{ + if(act->data) MEM_freeN(act->data); + MEM_freeN(act); +} + +void free_actuators(ListBase *lb) +{ + bActuator *act; + + while((act= lb->first)) { + BLI_remlink(lb, act); + free_actuator(act); + } +} + +bActuator *copy_actuator(bActuator *act) +{ + bActuator *actn; + + act->mynew=actn= MEM_dupallocN(act); + actn->flag |= ACT_NEW; + if(act->data) { + actn->data= MEM_dupallocN(act->data); + } + + return actn; +} + +void copy_actuators(ListBase *lbn, ListBase *lbo) +{ + bActuator *act, *actn; + + lbn->first= lbn->last= 0; + act= lbo->first; + while(act) { + actn= copy_actuator(act); + BLI_addtail(lbn, actn); + act= act->next; + } +} + +void init_actuator(bActuator *act) +{ + /* also use when actuator changes type */ + bObjectActuator *oa; + + if(act->data) MEM_freeN(act->data); + act->data= 0; + + switch(act->type) { +#ifdef __NLA + case ACT_ACTION: + act->data= MEM_callocN(sizeof(bActionActuator), "actionact"); + break; +#endif + case ACT_SOUND: + act->data= MEM_callocN(sizeof(bSoundActuator), "soundact"); + break; + case ACT_CD: + act->data= MEM_callocN(sizeof(bCDActuator), "cdact"); + break; + case ACT_OBJECT: + act->data= MEM_callocN(sizeof(bObjectActuator), "objectact"); + oa= act->data; + oa->flag= 15; + break; + case ACT_IPO: + act->data= MEM_callocN(sizeof(bIpoActuator), "ipoact"); + break; + case ACT_PROPERTY: + act->data= MEM_callocN(sizeof(bPropertyActuator), "propact"); + break; + case ACT_CAMERA: + act->data= MEM_callocN(sizeof(bCameraActuator), "camact"); + break; + case ACT_EDIT_OBJECT: + act->data= MEM_callocN(sizeof(bEditObjectActuator), "editobact"); + break; + case ACT_CONSTRAINT: + act->data= MEM_callocN(sizeof(bConstraintActuator), "cons act"); + break; + case ACT_SCENE: + act->data= MEM_callocN(sizeof(bSceneActuator), "scene act"); + break; + case ACT_GROUP: + act->data= MEM_callocN(sizeof(bGroupActuator), "group act"); + break; + case ACT_RANDOM: + act->data= MEM_callocN(sizeof(bRandomActuator), "random act"); + break; + case ACT_MESSAGE: + act->data= MEM_callocN(sizeof(bMessageActuator), "message act"); + break; + case ACT_GAME: + act->data= MEM_callocN(sizeof(bGameActuator), "game act"); + break; + case ACT_VISIBILITY: + act->data= MEM_callocN(sizeof(bVisibilityActuator), "visibility act"); + break; + default: + ; /* this is very severe... I cannot make any memory for this */ + /* logic brick... */ + } +} + +bActuator *new_actuator(int type) +{ + bActuator *act; + + act= MEM_callocN(sizeof(bActuator), "Actuator"); + act->type= type; + act->flag= ACT_SHOW; + + init_actuator(act); + + strcpy(act->name, "act"); + make_unique_prop_names(act->name); + + return act; +} + +/* ******************** GENERAL ******************* */ + +void clear_sca_new_poins_ob(Object *ob) +{ + bSensor *sens; + bController *cont; + bActuator *act; + + sens= ob->sensors.first; + while(sens) { + sens->flag &= ~SENS_NEW; + sens= sens->next; + } + cont= ob->controllers.first; + while(cont) { + cont->mynew= NULL; + cont->flag &= ~CONT_NEW; + cont= cont->next; + } + act= ob->actuators.first; + while(act) { + act->mynew= NULL; + act->flag &= ~ACT_NEW; + act= act->next; + } +} + +void clear_sca_new_poins() +{ + Object *ob; + + ob= G.main->object.first; + while(ob) { + clear_sca_new_poins_ob(ob); + ob= ob->id.next; + } +} + +void set_sca_new_poins_ob(Object *ob) +{ + bSensor *sens; + bController *cont; + bActuator *act; + int a; + + sens= ob->sensors.first; + while(sens) { + if(sens->flag & SENS_NEW) { + for(a=0; atotlinks; a++) { + if(sens->links[a] && sens->links[a]->mynew) + sens->links[a]= sens->links[a]->mynew; + } + } + sens= sens->next; + } + + cont= ob->controllers.first; + while(cont) { + if(cont->flag & CONT_NEW) { + for(a=0; atotlinks; a++) { + if( cont->links[a] && cont->links[a]->mynew) + cont->links[a]= cont->links[a]->mynew; + } + } + cont= cont->next; + } + + + act= ob->actuators.first; + while(act) { + if(act->flag & ACT_NEW) { + if(act->type==ACT_EDIT_OBJECT) { + bEditObjectActuator *eoa= act->data; + ID_NEW(eoa->ob); + } + else if(act->type==ACT_SCENE) { + bSceneActuator *sca= act->data; + ID_NEW(sca->camera); + } + else if(act->type==ACT_CAMERA) { + bCameraActuator *ca= act->data; + ID_NEW(ca->ob); + } + else if(act->type==ACT_SCENE) { + bSceneActuator *sca= act->data; + ID_NEW(sca->camera); + } + } + act= act->next; + } +} + + +void set_sca_new_poins() +{ + Object *ob; + + ob= G.main->object.first; + while(ob) { + set_sca_new_poins_ob(ob); + ob= ob->id.next; + } +} + +void sca_remove_ob_poin(Object *obt, Object *ob) +{ + bSensor *sens; + bMessageSensor *ms; + bActuator *act; + bCameraActuator *ca; + bSceneActuator *sa; + bEditObjectActuator *eoa; + bPropertyActuator *pa; + bMessageActuator *ma; + + sens= obt->sensors.first; + while(sens) { + switch(sens->type) { + case SENS_MESSAGE: + ms= sens->data; + if(ms->fromObject==ob) ms->fromObject= NULL; + } + sens= sens->next; + } + + act= obt->actuators.first; + while(act) { + switch(act->type) { + case ACT_CAMERA: + ca= act->data; + if(ca->ob==ob) ca->ob= NULL; + break; + case ACT_PROPERTY: + pa= act->data; + if(pa->ob==ob) pa->ob= NULL; + break; + case ACT_SCENE: + sa= act->data; + if(sa->camera==ob) sa->camera= NULL; + break; + case ACT_EDIT_OBJECT: + eoa= act->data; + if(eoa->ob==ob) eoa->ob= NULL; + break; + case ACT_MESSAGE: + ma= act->data; + if(ma->toObject==ob) ma->toObject= NULL; + break; + + } + act= act->next; + } +} diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c new file mode 100644 index 00000000000..88de43fa85d --- /dev/null +++ b/source/blender/blenkernel/intern/scene.c @@ -0,0 +1,564 @@ +/* scene.c + * + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifndef WIN32 +#include +#else +#include +#endif +#include "MEM_guardedalloc.h" + +#include "DNA_armature_types.h" +#include "DNA_constraint_types.h" +#include "DNA_curve_types.h" +#include "DNA_group_types.h" +#include "DNA_lamp_types.h" +#include "DNA_material_types.h" +#include "DNA_meta_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_scriptlink_types.h" +#include "DNA_texture_types.h" +#include "DNA_userdef_types.h" + +#include "BKE_action.h" +#include "BKE_anim.h" +#include "BKE_armature.h" +#include "BKE_bad_level_calls.h" +#include "BKE_constraint.h" +#include "BKE_depsgraph.h" +#include "BKE_global.h" +#include "BKE_group.h" +#include "BKE_ipo.h" +#include "BKE_image.h" +#include "BKE_key.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_node.h" +#include "BKE_object.h" +#include "BKE_scene.h" +#include "BKE_world.h" +#include "BKE_utildefines.h" + +#include "BIF_previewrender.h" +#include "BDR_sculptmode.h" + +#include "BPY_extern.h" +#include "BLI_arithb.h" +#include "BLI_blenlib.h" + +#include "nla.h" + +#ifdef WIN32 +#else +#include +#endif + +void free_avicodecdata(AviCodecData *acd) +{ + if (acd) { + if (acd->lpFormat){ + MEM_freeN(acd->lpFormat); + acd->lpFormat = NULL; + acd->cbFormat = 0; + } + if (acd->lpParms){ + MEM_freeN(acd->lpParms); + acd->lpParms = NULL; + acd->cbParms = 0; + } + } +} + +void free_qtcodecdata(QuicktimeCodecData *qcd) +{ + if (qcd) { + if (qcd->cdParms){ + MEM_freeN(qcd->cdParms); + qcd->cdParms = NULL; + qcd->cdSize = 0; + } + } +} + +/* copy_scene moved to src/header_info.c... should be back */ + +/* do not free scene itself */ +void free_scene(Scene *sce) +{ + Base *base; + + base= sce->base.first; + while(base) { + base->object->id.us--; + base= base->next; + } + /* do not free objects! */ + + BLI_freelistN(&sce->base); + free_editing(sce->ed); + if(sce->radio) MEM_freeN(sce->radio); + sce->radio= 0; + + BPY_free_scriptlink(&sce->scriptlink); + if (sce->r.avicodecdata) { + free_avicodecdata(sce->r.avicodecdata); + MEM_freeN(sce->r.avicodecdata); + sce->r.avicodecdata = NULL; + } + if (sce->r.qtcodecdata) { + free_qtcodecdata(sce->r.qtcodecdata); + MEM_freeN(sce->r.qtcodecdata); + sce->r.qtcodecdata = NULL; + } + + BLI_freelistN(&sce->markers); + BLI_freelistN(&sce->r.layers); + + if(sce->toolsettings){ + MEM_freeN(sce->toolsettings); + sce->toolsettings = NULL; + } + + if (sce->theDag) { + free_forest(sce->theDag); + MEM_freeN(sce->theDag); + } + + if(sce->nodetree) { + ntreeFreeTree(sce->nodetree); + MEM_freeN(sce->nodetree); + } + + sculptmode_free_all(sce); +} + +Scene *add_scene(char *name) +{ + Scene *sce; + + sce= alloc_libblock(&G.main->scene, ID_SCE, name); + sce->lay= 1; + sce->selectmode= SCE_SELECT_VERTEX; + sce->editbutsize= 0.1; + + sce->r.mode= R_GAMMA; + sce->r.cfra= 1; + sce->r.sfra= 1; + sce->r.efra= 250; + sce->r.xsch= 320; + sce->r.ysch= 256; + sce->r.xasp= 1; + sce->r.yasp= 1; + sce->r.xparts= 4; + sce->r.yparts= 4; + sce->r.size= 100; + sce->r.planes= 24; + sce->r.quality= 90; + sce->r.framapto= 100; + sce->r.images= 100; + sce->r.framelen= 1.0; + sce->r.frs_sec= 25; + sce->r.frs_sec_base= 1; + sce->r.ocres = 128; + + sce->r.bake_mode= 1; /* prevent to include render stuff here */ + sce->r.bake_filter= 2; + sce->r.bake_osa= 5; + sce->r.bake_flag= R_BAKE_CLEAR; + + sce->r.xplay= 640; + sce->r.yplay= 480; + sce->r.freqplay= 60; + sce->r.depth= 32; + + sce->r.threads= 1; + + sce->r.stereomode = 1; // no stereo + + sce->toolsettings = MEM_callocN(sizeof(struct ToolSettings),"Tool Settings Struct"); + sce->toolsettings->cornertype=1; + sce->toolsettings->degr = 90; + sce->toolsettings->step = 9; + sce->toolsettings->turn = 1; + sce->toolsettings->extr_offs = 1; + sce->toolsettings->doublimit = 0.001; + sce->toolsettings->segments = 32; + sce->toolsettings->rings = 32; + sce->toolsettings->vertices = 32; + sce->toolsettings->editbutflag = 1; + sce->toolsettings->uvcalc_radius = 1.0f; + sce->toolsettings->uvcalc_cubesize = 1.0f; + sce->toolsettings->uvcalc_mapdir = 1; + sce->toolsettings->uvcalc_mapalign = 1; + sce->toolsettings->unwrapper = 1; + sce->toolsettings->select_thresh= 0.01f; + sce->toolsettings->jointrilimit = 0.8f; + + sce->jumpframe = 10; + sce->audio.mixrate = 44100; + + strcpy(sce->r.backbuf, "//backbuf"); + strcpy(sce->r.pic, U.renderdir); + strcpy(sce->r.ftype, "//ftype"); + + BLI_init_rctf(&sce->r.safety, 0.1f, 0.9f, 0.1f, 0.9f); + sce->r.osa= 8; + + sculptmode_init(sce); + + /* note; in header_info.c the scene copy happens..., if you add more to renderdata it has to be checked there */ + scene_add_render_layer(sce); + + return sce; +} + +Base *object_in_scene(Object *ob, Scene *sce) +{ + Base *base; + + base= sce->base.first; + while(base) { + if(base->object == ob) return base; + base= base->next; + } + return NULL; +} + +void set_scene_bg(Scene *sce) +{ + Base *base; + Object *ob; + Group *group; + GroupObject *go; + int flag; + + G.scene= sce; + + /* check for cyclic sets, for reading old files but also for definite security (py?) */ + scene_check_setscene(G.scene); + + /* deselect objects (for dataselect) */ + for(ob= G.main->object.first; ob; ob= ob->id.next) + ob->flag &= ~(SELECT|OB_FROMGROUP); + + /* group flags again */ + for(group= G.main->group.first; group; group= group->id.next) { + go= group->gobject.first; + while(go) { + if(go->ob) go->ob->flag |= OB_FROMGROUP; + go= go->next; + } + } + + /* sort baselist */ + DAG_scene_sort(sce); + + /* ensure dags are built for sets */ + for(sce= sce->set; sce; sce= sce->set) + if(sce->theDag==NULL) + DAG_scene_sort(sce); + + /* copy layers and flags from bases to objects */ + for(base= G.scene->base.first; base; base= base->next) { + ob= base->object; + ob->lay= base->lay; + + /* group patch... */ + base->flag &= ~(OB_FROMGROUP); + flag= ob->flag & (OB_FROMGROUP); + base->flag |= flag; + + /* not too nice... for recovering objects with lost data */ + if(ob->pose==NULL) base->flag &= ~OB_POSEMODE; + ob->flag= base->flag; + + ob->ctime= -1234567.0; /* force ipo to be calculated later */ + } + /* no full animation update, this to enable render code to work (render code calls own animation updates) */ + + /* do we need FRAMECHANGED in set_scene? */ +// if (G.f & G_DOSCRIPTLINKS) BPY_do_all_scripts(SCRIPT_FRAMECHANGED); +} + +/* called from creator.c */ +void set_scene_name(char *name) +{ + Scene *sce; + + for (sce= G.main->scene.first; sce; sce= sce->id.next) { + if (BLI_streq(name, sce->id.name+2)) { + set_scene_bg(sce); + return; + } + } + + error("Can't find scene: %s", name); +} + +/* used by metaballs + * doesnt return the original duplicated object, only dupli's + */ +int next_object(int val, Base **base, Object **ob) +{ + static ListBase *duplilist= NULL; + static DupliObject *dupob; + static int fase; + int run_again=1; + + /* init */ + if(val==0) { + fase= F_START; + dupob= NULL; + } + else { + + /* run_again is set when a duplilist has been ended */ + while(run_again) { + run_again= 0; + + /* the first base */ + if(fase==F_START) { + *base= G.scene->base.first; + if(*base) { + *ob= (*base)->object; + fase= F_SCENE; + } + else { + /* exception: empty scene */ + if(G.scene->set && G.scene->set->base.first) { + *base= G.scene->set->base.first; + *ob= (*base)->object; + fase= F_SET; + } + } + } + else { + if(*base && fase!=F_DUPLI) { + *base= (*base)->next; + if(*base) *ob= (*base)->object; + else { + if(fase==F_SCENE) { + /* scene is finished, now do the set */ + if(G.scene->set && G.scene->set->base.first) { + *base= G.scene->set->base.first; + *ob= (*base)->object; + fase= F_SET; + } + } + } + } + } + + if(*base == NULL) fase= F_START; + else { + if(fase!=F_DUPLI) { + if( (*base)->object->transflag & OB_DUPLI) { + /* groups cannot be duplicated for mballs yet, + this enters eternal loop because of + makeDispListMBall getting called inside of group_duplilist */ + if((*base)->object->dup_group == NULL) { + duplilist= object_duplilist(G.scene, (*base)->object); + + dupob= duplilist->first; + } + } + } + /* handle dupli's */ + if(dupob) { + + Mat4CpyMat4(dupob->ob->obmat, dupob->mat); + + (*base)->flag |= OB_FROMDUPLI; + *ob= dupob->ob; + fase= F_DUPLI; + + dupob= dupob->next; + } + else if(fase==F_DUPLI) { + fase= F_SCENE; + (*base)->flag &= ~OB_FROMDUPLI; + + for(dupob= duplilist->first; dupob; dupob= dupob->next) { + Mat4CpyMat4(dupob->ob->obmat, dupob->omat); + } + + free_object_duplilist(duplilist); + duplilist= NULL; + run_again= 1; + } + } + } + } + + return fase; +} + +Object *scene_find_camera(Scene *sc) +{ + Base *base; + + for (base= sc->base.first; base; base= base->next) + if (base->object->type==OB_CAMERA) + return base->object; + + return NULL; +} + + +Base *scene_add_base(Scene *sce, Object *ob) +{ + Base *b= MEM_callocN(sizeof(*b), "scene_add_base"); + BLI_addhead(&sce->base, b); + + b->object= ob; + b->flag= ob->flag; + b->lay= ob->lay; + + return b; +} + +void scene_deselect_all(Scene *sce) +{ + Base *b; + + for (b= sce->base.first; b; b= b->next) { + b->flag&= ~SELECT; + b->object->flag= b->flag; + } +} + +void scene_select_base(Scene *sce, Base *selbase) +{ + scene_deselect_all(sce); + + selbase->flag |= SELECT; + selbase->object->flag= selbase->flag; + + sce->basact= selbase; +} + +/* checks for cycle, returns 1 if it's all OK */ +int scene_check_setscene(Scene *sce) +{ + Scene *scene; + + if(sce->set==NULL) return 1; + + /* LIB_DOIT is the free flag to tag library data */ + for(scene= G.main->scene.first; scene; scene= scene->id.next) + scene->id.flag &= ~LIB_DOIT; + + scene= sce; + while(scene->set) { + scene->id.flag |= LIB_DOIT; + /* when set has flag set, we got a cycle */ + if(scene->set->id.flag & LIB_DOIT) + break; + scene= scene->set; + } + + if(scene->set) { + /* the tested scene gets zero'ed, that's typically current scene */ + sce->set= NULL; + return 0; + } + return 1; +} + +static void scene_update(Scene *sce, unsigned int lay) +{ + Base *base; + Object *ob; + + if(sce->theDag==NULL) + DAG_scene_sort(sce); + + DAG_scene_update_flags(sce, lay); // only stuff that moves or needs display still + + for(base= sce->base.first; base; base= base->next) { + ob= base->object; + + object_handle_update(ob); // bke_object.h + + /* only update layer when an ipo */ + if(ob->ipo && has_ipo_code(ob->ipo, OB_LAY) ) { + base->lay= ob->lay; + } + } +} + +/* applies changes right away, does all sets too */ +void scene_update_for_newframe(Scene *sce, unsigned int lay) +{ + Scene *scene= sce; + + /* clears all BONE_UNKEYED flags for every pose's pchans */ + framechange_poses_clear_unkeyed(); + + /* object ipos are calculated in where_is_object */ + do_all_data_ipos(); + + if (G.f & G_DOSCRIPTLINKS) BPY_do_all_scripts(SCRIPT_FRAMECHANGED); + + /* sets first, we allow per definition current scene to have dependencies on sets */ + for(sce= sce->set; sce; sce= sce->set) + scene_update(sce, lay); + + scene_update(scene, lay); +} + +/* return default layer, also used to patch old files */ +void scene_add_render_layer(Scene *sce) +{ + SceneRenderLayer *srl; + int tot= 1 + BLI_countlist(&sce->r.layers); + + srl= MEM_callocN(sizeof(SceneRenderLayer), "new render layer"); + sprintf(srl->name, "%d RenderLayer", tot); + BLI_addtail(&sce->r.layers, srl); + + /* note, this is also in render, pipeline.c, to make layer when scenedata doesnt have it */ + srl->lay= (1<<20) -1; + srl->layflag= 0x7FFF; /* solid ztra halo edge strand */ + srl->passflag= SCE_PASS_COMBINED|SCE_PASS_Z; +} + diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c new file mode 100644 index 00000000000..5e8735147c3 --- /dev/null +++ b/source/blender/blenkernel/intern/screen.c @@ -0,0 +1,57 @@ + +/* screen.c + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include +#include + +#include "DNA_screen_types.h" +#include "BKE_bad_level_calls.h" +#include "BLI_blenlib.h" + +#include "BKE_screen.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +/* don't free screen itself */ +void free_screen(bScreen *sc) +{ + unlink_screen(sc); + + BLI_freelistN(&sc->vertbase); + BLI_freelistN(&sc->edgebase); + BLI_freelistN(&sc->areabase); +} diff --git a/source/blender/blenkernel/intern/script.c b/source/blender/blenkernel/intern/script.c new file mode 100644 index 00000000000..b99c2c51441 --- /dev/null +++ b/source/blender/blenkernel/intern/script.c @@ -0,0 +1,71 @@ +/* blenkernel/script.c + * + * + * $Id$ + * + * Function(s) related to struct script management. + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BKE_script.h" +#include "BPI_script.h" + +#include "MEM_guardedalloc.h" +#include "BKE_bad_level_calls.h" /* for BPY_clear_script */ + +/* +#include "BLI_blenlib.h" +#include "BKE_utildefines.h" +#include "BKE_library.h" +#include "BKE_global.h" +#include "BKE_main.h" + +#include "BPY_extern.h" // Blender Python library + +#ifdef HAVE_CONFIG_H +#include +#endif +*/ + +/* XXX this function and so also the file should not be needed anymore, + * since we have to force clearing all Python related data before freeing + * Blender's library. Still testing, will decide later (Willian). */ +void free_script (Script *script) +{ + if (!script) return; + + if (script->py_globaldict || script->py_button || + script->py_event || script->py_draw) + { + BPY_clear_script(script); + } + + return; +} diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c new file mode 100644 index 00000000000..19dcee676cb --- /dev/null +++ b/source/blender/blenkernel/intern/softbody.c @@ -0,0 +1,3420 @@ +/* softbody.c + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* +****** +variables on the UI for now + + float mediafrict; friction to env + float nodemass; softbody mass of *vertex* + float grav; softbody amount of gravitaion to apply + + float goalspring; softbody goal springs + float goalfrict; softbody goal springs friction + float mingoal; quick limits for goal + float maxgoal; + + float inspring; softbody inner springs + float infrict; softbody inner springs friction + +***** +*/ + + +#include +#include +#include + +#include "MEM_guardedalloc.h" + +/* types */ +#include "DNA_curve_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force.h" /* here is the softbody struct */ +#include "DNA_key_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_lattice_types.h" +#include "DNA_scene_types.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_ghash.h" +#include "BKE_curve.h" +#include "BKE_effect.h" +#include "BKE_global.h" +#include "BKE_key.h" +#include "BKE_object.h" +#include "BKE_softbody.h" +#include "BKE_utildefines.h" +#include "BKE_DerivedMesh.h" + +#include "BIF_editdeform.h" +#include "BIF_graphics.h" +#include "PIL_time.h" + +/* callbacks for errors and interrupts and some goo */ +static int (*SB_localInterruptCallBack)(void) = NULL; + + +/* ********** soft body engine ******* */ + + + +typedef struct BodyPoint { + float origS[3], origE[3], origT[3], pos[3], vec[3], force[3]; + float goal; + float prevpos[3], prevvec[3], prevdx[3], prevdv[3]; /* used for Heun integration */ + int nofsprings; int *springs; + float choke; + float colball; + short flag; + char octantflag; +} BodyPoint; + +typedef struct BodySpring { + int v1, v2; + float len, strength, cf; + float ext_force[3]; /* edges colliding and sailing */ + short order; + short flag; +} BodySpring; + +typedef struct BodyFace { + int v1, v2, v3 ,v4; + float ext_force[3]; /* edges colliding and sailing */ + short flag; +} BodyFace; + + +/*private scratch pad for caching and other data only needed when alive*/ +typedef struct SBScratch { + GHash *colliderhash; + short needstobuildcollider; + short flag; + BodyFace *bodyface; + int totface; + float aabbmin[3],aabbmax[3]; +}SBScratch; + +#define SOFTGOALSNAP 0.999f +/* if bp-> goal is above make it a *forced follow original* and skip all ODE stuff for this bp + removes *unnecessary* stiffnes from ODE system +*/ +#define HEUNWARNLIMIT 1 /* 500 would be fine i think for detecting severe *stiff* stuff */ + + +#define BSF_INTERSECT 1 /* edge intersects collider face */ +#define SBF_DOFUZZY 1 /* edge intersects collider face */ +#define BFF_INTERSECT 1 /* edge intersects collider face */ + + +float SoftHeunTol = 1.0f; /* humm .. this should be calculated from sb parameters and sizes */ + +/* local prototypes */ +static void free_softbody_intern(SoftBody *sb); +/* aye this belongs to arith.c */ +static void Vec3PlusStVec(float *v, float s, float *v1); + +/*+++ frame based timing +++*/ + +/*physical unit of force is [kg * m / sec^2]*/ + +static float sb_grav_force_scale(Object *ob) +/* since unit of g is [m/sec^2] and F = mass * g we rescale unit mass of node to 1 gramm + put it to a function here, so we can add user options later without touching simulation code +*/ +{ + return (0.001f); +} + +static float sb_fric_force_scale(Object *ob) +/* rescaling unit of drag [1 / sec] to somehow reasonable + put it to a function here, so we can add user options later without touching simulation code +*/ +{ + return (0.01f); +} + +static float sb_time_scale(Object *ob) +/* defining the frames to *real* time relation */ +{ + SoftBody *sb= ob->soft; /* is supposed to be there */ + if (sb){ + return(sb->physics_speed); + /*hrms .. this could be IPO as well :) + estimated range [0.001 sluggish slug - 100.0 very fast (i hope ODE solver can handle that)] + 1 approx = a unit 1 pendulum at g = 9.8 [earth conditions] has period 65 frames + theory would give a 50 frames period .. so there must be something inaccurate .. looking for that (BM) + */ + } + return (1.0f); + /* + this would be frames/sec independant timing assuming 25 fps is default + but does not work very well with NLA + return (25.0f/G.scene->r.frs_sec) + */ +} +/*--- frame based timing ---*/ + +/*+++ collider caching and dicing +++*/ + +/******************** +for each target object/face the axis aligned bounding box (AABB) is stored +faces paralell to global axes +so only simple "value" in [min,max] ckecks are used +float operations still +*/ + +/* just an ID here to reduce the prob for killing objects +** ob->sumohandle points to we should not kill :) +*/ +const int CCD_SAVETY = 190561; + +typedef struct ccdf_minmax{ +float minx,miny,minz,maxx,maxy,maxz; +}ccdf_minmax; + + + +typedef struct ccd_Mesh { + int totvert, totface; + MVert *mvert; + MVert *mprevvert; + MFace *mface; + int savety; + ccdf_minmax *mima; + /* Axis Aligned Bounding Box AABB */ + float bbmin[3]; + float bbmax[3]; +}ccd_Mesh; + + + + +ccd_Mesh *ccd_mesh_make(Object *ob, DerivedMesh *dm) +{ + ccd_Mesh *pccd_M = NULL; + ccdf_minmax *mima =NULL; + MFace *mface=NULL; + float v[3],hull; + int i; + + /* first some paranoia checks */ + if (!dm) return NULL; + if (!dm->getNumVerts(dm) || !dm->getNumFaces(dm)) return NULL; + + pccd_M = MEM_mallocN(sizeof(ccd_Mesh),"ccd_Mesh"); + pccd_M->totvert = dm->getNumVerts(dm); + pccd_M->totface = dm->getNumFaces(dm); + pccd_M->savety = CCD_SAVETY; + pccd_M->bbmin[0]=pccd_M->bbmin[1]=pccd_M->bbmin[2]=1e30f; + pccd_M->bbmax[0]=pccd_M->bbmax[1]=pccd_M->bbmax[2]=-1e30f; + pccd_M->mprevvert=NULL; + + + /* blow it up with forcefield ranges */ + hull = MAX2(ob->pd->pdef_sbift,ob->pd->pdef_sboft); + + /* alloc and copy verts*/ + pccd_M->mvert = dm->dupVertArray(dm); + /* ah yeah, put the verices to global coords once */ + /* and determine the ortho BB on the fly */ + for(i=0; i < pccd_M->totvert; i++){ + Mat4MulVecfl(ob->obmat, pccd_M->mvert[i].co); + + /* evaluate limits */ + VECCOPY(v,pccd_M->mvert[i].co); + pccd_M->bbmin[0] = MIN2(pccd_M->bbmin[0],v[0]-hull); + pccd_M->bbmin[1] = MIN2(pccd_M->bbmin[1],v[1]-hull); + pccd_M->bbmin[2] = MIN2(pccd_M->bbmin[2],v[2]-hull); + + pccd_M->bbmax[0] = MAX2(pccd_M->bbmax[0],v[0]+hull); + pccd_M->bbmax[1] = MAX2(pccd_M->bbmax[1],v[1]+hull); + pccd_M->bbmax[2] = MAX2(pccd_M->bbmax[2],v[2]+hull); + + } + /* alloc and copy faces*/ + pccd_M->mface = dm->dupFaceArray(dm); + + /* OBBs for idea1 */ + pccd_M->mima = MEM_mallocN(sizeof(ccdf_minmax)*pccd_M->totface,"ccd_Mesh_Faces_mima"); + mima = pccd_M->mima; + mface = pccd_M->mface; + + + /* anyhoo we need to walk the list of faces and find OBB they live in */ + for(i=0; i < pccd_M->totface; i++){ + mima->minx=mima->miny=mima->minz=1e30f; + mima->maxx=mima->maxy=mima->maxz=-1e30f; + + VECCOPY(v,pccd_M->mvert[mface->v1].co); + mima->minx = MIN2(mima->minx,v[0]-hull); + mima->miny = MIN2(mima->miny,v[1]-hull); + mima->minz = MIN2(mima->minz,v[2]-hull); + mima->maxx = MAX2(mima->maxx,v[0]+hull); + mima->maxy = MAX2(mima->maxy,v[1]+hull); + mima->maxz = MAX2(mima->maxz,v[2]+hull); + + VECCOPY(v,pccd_M->mvert[mface->v2].co); + mima->minx = MIN2(mima->minx,v[0]-hull); + mima->miny = MIN2(mima->miny,v[1]-hull); + mima->minz = MIN2(mima->minz,v[2]-hull); + mima->maxx = MAX2(mima->maxx,v[0]+hull); + mima->maxy = MAX2(mima->maxy,v[1]+hull); + mima->maxz = MAX2(mima->maxz,v[2]+hull); + + VECCOPY(v,pccd_M->mvert[mface->v3].co); + mima->minx = MIN2(mima->minx,v[0]-hull); + mima->miny = MIN2(mima->miny,v[1]-hull); + mima->minz = MIN2(mima->minz,v[2]-hull); + mima->maxx = MAX2(mima->maxx,v[0]+hull); + mima->maxy = MAX2(mima->maxy,v[1]+hull); + mima->maxz = MAX2(mima->maxz,v[2]+hull); + + if(mface->v4){ + VECCOPY(v,pccd_M->mvert[mface->v4].co); + mima->minx = MIN2(mima->minx,v[0]-hull); + mima->miny = MIN2(mima->miny,v[1]-hull); + mima->minz = MIN2(mima->minz,v[2]-hull); + mima->maxx = MAX2(mima->maxx,v[0]+hull); + mima->maxy = MAX2(mima->maxy,v[1]+hull); + mima->maxz = MAX2(mima->maxz,v[2]+hull); + } + + + mima++; + mface++; + + } + return pccd_M; +} +void ccd_mesh_update(Object *ob,ccd_Mesh *pccd_M, DerivedMesh *dm) +{ + ccdf_minmax *mima =NULL; + MFace *mface=NULL; + float v[3],hull; + int i; + + /* first some paranoia checks */ + if (!dm) return ; + if (!dm->getNumVerts(dm) || !dm->getNumFaces(dm)) return ; + + if ((pccd_M->totvert != dm->getNumVerts(dm)) || + (pccd_M->totface != dm->getNumFaces(dm))) return; + + pccd_M->bbmin[0]=pccd_M->bbmin[1]=pccd_M->bbmin[2]=1e30f; + pccd_M->bbmax[0]=pccd_M->bbmax[1]=pccd_M->bbmax[2]=-1e30f; + + + /* blow it up with forcefield ranges */ + hull = MAX2(ob->pd->pdef_sbift,ob->pd->pdef_sboft); + + /* rotate current to previous */ + if(pccd_M->mprevvert) MEM_freeN(pccd_M->mprevvert); + pccd_M->mprevvert = pccd_M->mvert; + /* alloc and copy verts*/ + pccd_M->mvert = dm->dupVertArray(dm); + /* ah yeah, put the verices to global coords once */ + /* and determine the ortho BB on the fly */ + for(i=0; i < pccd_M->totvert; i++){ + Mat4MulVecfl(ob->obmat, pccd_M->mvert[i].co); + + /* evaluate limits */ + VECCOPY(v,pccd_M->mvert[i].co); + pccd_M->bbmin[0] = MIN2(pccd_M->bbmin[0],v[0]-hull); + pccd_M->bbmin[1] = MIN2(pccd_M->bbmin[1],v[1]-hull); + pccd_M->bbmin[2] = MIN2(pccd_M->bbmin[2],v[2]-hull); + + pccd_M->bbmax[0] = MAX2(pccd_M->bbmax[0],v[0]+hull); + pccd_M->bbmax[1] = MAX2(pccd_M->bbmax[1],v[1]+hull); + pccd_M->bbmax[2] = MAX2(pccd_M->bbmax[2],v[2]+hull); + + /* evaluate limits */ + VECCOPY(v,pccd_M->mprevvert[i].co); + pccd_M->bbmin[0] = MIN2(pccd_M->bbmin[0],v[0]-hull); + pccd_M->bbmin[1] = MIN2(pccd_M->bbmin[1],v[1]-hull); + pccd_M->bbmin[2] = MIN2(pccd_M->bbmin[2],v[2]-hull); + + pccd_M->bbmax[0] = MAX2(pccd_M->bbmax[0],v[0]+hull); + pccd_M->bbmax[1] = MAX2(pccd_M->bbmax[1],v[1]+hull); + pccd_M->bbmax[2] = MAX2(pccd_M->bbmax[2],v[2]+hull); + + } + + mima = pccd_M->mima; + mface = pccd_M->mface; + + + /* anyhoo we need to walk the list of faces and find OBB they live in */ + for(i=0; i < pccd_M->totface; i++){ + mima->minx=mima->miny=mima->minz=1e30f; + mima->maxx=mima->maxy=mima->maxz=-1e30f; + + VECCOPY(v,pccd_M->mvert[mface->v1].co); + mima->minx = MIN2(mima->minx,v[0]-hull); + mima->miny = MIN2(mima->miny,v[1]-hull); + mima->minz = MIN2(mima->minz,v[2]-hull); + mima->maxx = MAX2(mima->maxx,v[0]+hull); + mima->maxy = MAX2(mima->maxy,v[1]+hull); + mima->maxz = MAX2(mima->maxz,v[2]+hull); + + VECCOPY(v,pccd_M->mvert[mface->v2].co); + mima->minx = MIN2(mima->minx,v[0]-hull); + mima->miny = MIN2(mima->miny,v[1]-hull); + mima->minz = MIN2(mima->minz,v[2]-hull); + mima->maxx = MAX2(mima->maxx,v[0]+hull); + mima->maxy = MAX2(mima->maxy,v[1]+hull); + mima->maxz = MAX2(mima->maxz,v[2]+hull); + + VECCOPY(v,pccd_M->mvert[mface->v3].co); + mima->minx = MIN2(mima->minx,v[0]-hull); + mima->miny = MIN2(mima->miny,v[1]-hull); + mima->minz = MIN2(mima->minz,v[2]-hull); + mima->maxx = MAX2(mima->maxx,v[0]+hull); + mima->maxy = MAX2(mima->maxy,v[1]+hull); + mima->maxz = MAX2(mima->maxz,v[2]+hull); + + if(mface->v4){ + VECCOPY(v,pccd_M->mvert[mface->v4].co); + mima->minx = MIN2(mima->minx,v[0]-hull); + mima->miny = MIN2(mima->miny,v[1]-hull); + mima->minz = MIN2(mima->minz,v[2]-hull); + mima->maxx = MAX2(mima->maxx,v[0]+hull); + mima->maxy = MAX2(mima->maxy,v[1]+hull); + mima->maxz = MAX2(mima->maxz,v[2]+hull); + } + + + VECCOPY(v,pccd_M->mprevvert[mface->v1].co); + mima->minx = MIN2(mima->minx,v[0]-hull); + mima->miny = MIN2(mima->miny,v[1]-hull); + mima->minz = MIN2(mima->minz,v[2]-hull); + mima->maxx = MAX2(mima->maxx,v[0]+hull); + mima->maxy = MAX2(mima->maxy,v[1]+hull); + mima->maxz = MAX2(mima->maxz,v[2]+hull); + + VECCOPY(v,pccd_M->mprevvert[mface->v2].co); + mima->minx = MIN2(mima->minx,v[0]-hull); + mima->miny = MIN2(mima->miny,v[1]-hull); + mima->minz = MIN2(mima->minz,v[2]-hull); + mima->maxx = MAX2(mima->maxx,v[0]+hull); + mima->maxy = MAX2(mima->maxy,v[1]+hull); + mima->maxz = MAX2(mima->maxz,v[2]+hull); + + VECCOPY(v,pccd_M->mprevvert[mface->v3].co); + mima->minx = MIN2(mima->minx,v[0]-hull); + mima->miny = MIN2(mima->miny,v[1]-hull); + mima->minz = MIN2(mima->minz,v[2]-hull); + mima->maxx = MAX2(mima->maxx,v[0]+hull); + mima->maxy = MAX2(mima->maxy,v[1]+hull); + mima->maxz = MAX2(mima->maxz,v[2]+hull); + + if(mface->v4){ + VECCOPY(v,pccd_M->mprevvert[mface->v4].co); + mima->minx = MIN2(mima->minx,v[0]-hull); + mima->miny = MIN2(mima->miny,v[1]-hull); + mima->minz = MIN2(mima->minz,v[2]-hull); + mima->maxx = MAX2(mima->maxx,v[0]+hull); + mima->maxy = MAX2(mima->maxy,v[1]+hull); + mima->maxz = MAX2(mima->maxz,v[2]+hull); + } + + + mima++; + mface++; + + } + return ; +} + +void ccd_mesh_free(ccd_Mesh *ccdm) +{ + if(ccdm && (ccdm->savety == CCD_SAVETY )){ /*make sure we're not nuking objects we don't know*/ + MEM_freeN(ccdm->mface); + MEM_freeN(ccdm->mvert); + if (ccdm->mprevvert) MEM_freeN(ccdm->mprevvert); + MEM_freeN(ccdm->mima); + MEM_freeN(ccdm); + ccdm = NULL; + } +} + +void ccd_build_deflector_hache(Object *vertexowner,GHash *hash) +{ + Base *base; + Object *ob; + base= G.scene->base.first; + base= G.scene->base.first; + if (!hash) return; + while (base) { + /*Only proceed for mesh object in same layer */ + if(base->object->type==OB_MESH && (base->lay & vertexowner->lay)) { + ob= base->object; + if((vertexowner) && (ob == vertexowner)){ + /* if vertexowner is given we don't want to check collision with owner object */ + base = base->next; + continue; + } + + /*+++ only with deflecting set */ + if(ob->pd && ob->pd->deflect && BLI_ghash_lookup(hash, ob) == 0) { + DerivedMesh *dm= NULL; + + if(ob->softflag & OB_SB_COLLFINAL) { /* so maybe someone wants overkill to collide with subsurfed */ + dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH); + } else { + dm = mesh_get_derived_deform(ob, CD_MASK_BAREMESH); + } + + if(dm){ + ccd_Mesh *ccdmesh = ccd_mesh_make(ob, dm); + BLI_ghash_insert(hash, ob, ccdmesh); + + /* we did copy & modify all we need so give 'em away again */ + dm->release(dm); + + } + }/*--- only with deflecting set */ + + }/* mesh && layer*/ + base = base->next; + } /* while (base) */ +} + +void ccd_update_deflector_hache(Object *vertexowner,GHash *hash) +{ + Base *base; + Object *ob; + base= G.scene->base.first; + base= G.scene->base.first; + if ((!hash) || (!vertexowner)) return; + while (base) { + /*Only proceed for mesh object in same layer */ + if(base->object->type==OB_MESH && (base->lay & vertexowner->lay)) { + ob= base->object; + if(ob == vertexowner){ + /* if vertexowner is given we don't want to check collision with owner object */ + base = base->next; + continue; + } + + /*+++ only with deflecting set */ + if(ob->pd && ob->pd->deflect) { + DerivedMesh *dm= NULL; + + if(ob->softflag & OB_SB_COLLFINAL) { /* so maybe someone wants overkill to collide with subsurfed */ + dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH); + } else { + dm = mesh_get_derived_deform(ob, CD_MASK_BAREMESH); + } + if(dm){ + ccd_Mesh *ccdmesh = BLI_ghash_lookup(hash,ob); + if (ccdmesh) + ccd_mesh_update(ob,ccdmesh,dm); + + /* we did copy & modify all we need so give 'em away again */ + dm->release(dm); + } + }/*--- only with deflecting set */ + + }/* mesh && layer*/ + base = base->next; + } /* while (base) */ +} + + + + +/*--- collider caching and dicing ---*/ + + +static int count_mesh_quads(Mesh *me) +{ + int a,result = 0; + MFace *mface= me->mface; + + if(mface) { + for(a=me->totface; a>0; a--, mface++) { + if(mface->v4) result++; + } + } + return result; +} + +static void add_mesh_quad_diag_springs(Object *ob) +{ + Mesh *me= ob->data; + MFace *mface= me->mface; + BodyPoint *bp; + BodySpring *bs, *bs_new; + int a ; + + if (ob->soft){ + int nofquads; + + nofquads = count_mesh_quads(me); + if (nofquads) { + /* resize spring-array to hold additional quad springs */ + bs_new= MEM_callocN( (ob->soft->totspring + nofquads *2 )*sizeof(BodySpring), "bodyspring"); + memcpy(bs_new,ob->soft->bspring,(ob->soft->totspring )*sizeof(BodySpring)); + + if(ob->soft->bspring) + MEM_freeN(ob->soft->bspring); /* do this before reassigning the pointer or have a 1st class memory leak */ + ob->soft->bspring = bs_new; + + /* fill the tail */ + a = 0; + bs = bs_new+ob->soft->totspring; + bp= ob->soft->bpoint; + if(mface ) { + for(a=me->totface; a>0; a--, mface++) { + if(mface->v4) { + bs->v1= mface->v1; + bs->v2= mface->v3; + bs->strength= 1.0; + bs->order =2; + bs++; + bs->v1= mface->v2; + bs->v2= mface->v4; + bs->strength= 1.0; + bs->order =2; + bs++; + + } + } + } + + /* now we can announce new springs */ + ob->soft->totspring += nofquads *2; + } + } +} + +static void add_2nd_order_roller(Object *ob,float stiffness,int *counter, int addsprings) +{ + /*assume we have a softbody*/ + SoftBody *sb= ob->soft; /* is supposed to be there */ + BodyPoint *bp,*bpo; + BodySpring *bs,*bs2,*bs3= NULL; + int a,b,c,notthis= 0,v0; + if (!sb->bspring){return;} /* we are 2nd order here so 1rst should have been build :) */ + /* first run counting second run adding */ + *counter = 0; + if (addsprings) bs3 = ob->soft->bspring+ob->soft->totspring; + for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { + /*scan for neighborhood*/ + bpo = NULL; + v0 = (sb->totpoint-a); + for(b=bp->nofsprings;b>0;b--){ + bs = sb->bspring + bp->springs[b-1]; + /*nasty thing here that springs have two ends + so here we have to make sure we examine the other */ + if (( v0 == bs->v1) ){ + bpo =sb->bpoint+bs->v2; + notthis = bs->v2; + } + else { + if (( v0 == bs->v2) ){ + bpo =sb->bpoint+bs->v1; + notthis = bs->v1; + } + else {printf("oops we should not get here - add_2nd_order_springs");} + } + if (bpo){/* so now we have a 2nd order humpdidump */ + for(c=bpo->nofsprings;c>0;c--){ + bs2 = sb->bspring + bpo->springs[c-1]; + if ((bs2->v1 != notthis) && (bs2->v1 > v0)){ + (*counter)++;/*hit */ + if (addsprings){ + bs3->v1= v0; + bs3->v2= bs2->v1; + bs3->strength= stiffness; + bs3->order=2; + bs3++; + } + } + if ((bs2->v2 !=notthis)&&(bs2->v2 > v0)){ + (*counter)++;/*hit */ + if (addsprings){ + bs3->v1= v0; + bs3->v2= bs2->v2; + bs3->strength= stiffness; + bs3->order=2; + bs3++; + } + + } + } + + } + + } + /*scan for neighborhood done*/ + } +} + + +static void add_2nd_order_springs(Object *ob,float stiffness) +{ + int counter = 0; + BodySpring *bs_new; + + add_2nd_order_roller(ob,stiffness,&counter,0); /* counting */ + if (counter) { + /* resize spring-array to hold additional springs */ + bs_new= MEM_callocN( (ob->soft->totspring + counter )*sizeof(BodySpring), "bodyspring"); + memcpy(bs_new,ob->soft->bspring,(ob->soft->totspring )*sizeof(BodySpring)); + + if(ob->soft->bspring) + MEM_freeN(ob->soft->bspring); + ob->soft->bspring = bs_new; + + add_2nd_order_roller(ob,stiffness,&counter,1); /* adding */ + ob->soft->totspring +=counter ; + } +} + +static void add_bp_springlist(BodyPoint *bp,int springID) +{ + int *newlist; + + if (bp->springs == NULL) { + bp->springs = MEM_callocN( sizeof(int), "bpsprings"); + bp->springs[0] = springID; + bp->nofsprings = 1; + } + else { + bp->nofsprings++; + newlist = MEM_callocN(bp->nofsprings * sizeof(int), "bpsprings"); + memcpy(newlist,bp->springs,(bp->nofsprings-1)* sizeof(int)); + MEM_freeN(bp->springs); + bp->springs = newlist; + bp->springs[bp->nofsprings-1] = springID; + } +} + +/* do this once when sb is build +it is O(N^2) so scanning for springs every iteration is too expensive +*/ +static void build_bps_springlist(Object *ob) +{ + SoftBody *sb= ob->soft; /* is supposed to be there */ + BodyPoint *bp; + BodySpring *bs; + int a,b; + + if (sb==NULL) return; /* paranoya check */ + + for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { + /* throw away old list */ + if (bp->springs) { + MEM_freeN(bp->springs); + bp->springs=NULL; + } + /* scan for attached inner springs */ + for(b=sb->totspring, bs= sb->bspring; b>0; b--, bs++) { + if (( (sb->totpoint-a) == bs->v1) ){ + add_bp_springlist(bp,sb->totspring -b); + } + if (( (sb->totpoint-a) == bs->v2) ){ + add_bp_springlist(bp,sb->totspring -b); + } + }/*for springs*/ + }/*for bp*/ +} + +static void calculate_collision_balls(Object *ob) +{ + SoftBody *sb= ob->soft; /* is supposed to be there */ + BodyPoint *bp; + BodySpring *bs; + int a,b,akku_count; + float min,max,akku; + + if (sb==NULL) return; /* paranoya check */ + + for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { + bp->colball=0; + akku =0.0f; + akku_count=0; + min = 1e22f; + max = -1e22f; + /* first estimation based on attached */ + for(b=bp->nofsprings;b>0;b--){ + bs = sb->bspring + bp->springs[b-1]; + if (bs->order == 1){ + akku += bs->len; + akku_count++, + min = MIN2(bs->len,min); + max = MAX2(bs->len,max); + } + } + + if (akku_count > 0) { + if (sb->sbc_mode == 0){ + bp->colball=sb->colball; + } + if (sb->sbc_mode == 1){ + bp->colball = akku/(float)akku_count*sb->colball; + } + if (sb->colball == 2){ + bp->colball=min*sb->colball; + } + if (sb->colball == 3){ + bp->colball=max*sb->colball; + } + if (sb->colball == 4){ + bp->colball = (min + max)/2.0f*sb->colball; + } + } + else bp->colball=0; + }/*for bp*/ +} + + +char set_octant_flags(float *ce, float *pos, float ball) +{ + float x,y,z; + char res = 0; + int a; + + for (a=0;a<7;a++){ + switch(a){ + case 0: x=pos[0]; y=pos[1]; z=pos[2]; break; + case 1: x=pos[0]+ball; y=pos[1]; z=pos[2]; break; + case 2: x=pos[0]-ball; y=pos[1]; z=pos[2]; break; + case 3: x=pos[0]; y=pos[1]+ball; z=pos[2]; break; + case 4: x=pos[0]; y=pos[1]-ball; z=pos[2]; break; + case 5: x=pos[0]; y=pos[1]; z=pos[2]+ball; break; + case 6: x=pos[0]; y=pos[1]; z=pos[2]-ball; break; + } + + x=pos[0]; y=pos[1]; z=pos[2]; + + if (x > ce[0]){ + if (y > ce[1]){ + if (z > ce[2]) res|= 1; + else res|= 2; + } + else{ + if (z > ce[2]) res|= 4; + else res|= 8; + } + } + + else{ + if (y > ce[1]){ + if (z > ce[2]) res|= 16; + else res|= 32; + } + else{ + if (z > ce[2]) res|= 64; + else res|= 128; + } + } + } + return res; +} + +/* creates new softbody if didn't exist yet, makes new points and springs arrays */ +static void renew_softbody(Object *ob, int totpoint, int totspring) +{ + SoftBody *sb; + int i; + + if(ob->soft==NULL) ob->soft= sbNew(); + else free_softbody_intern(ob->soft); + sb= ob->soft; + + if(totpoint) { + sb->totpoint= totpoint; + sb->totspring= totspring; + + sb->bpoint= MEM_mallocN( totpoint*sizeof(BodyPoint), "bodypoint"); + if(totspring) + sb->bspring= MEM_mallocN( totspring*sizeof(BodySpring), "bodyspring"); + + /* initialise BodyPoint array */ + for (i=0; ibpoint[i]; + + if(ob->softflag & OB_SB_GOAL) { + bp->goal= ob->soft->defgoal; + } + else { + bp->goal= 0.0f; + /* so this will definily be below SOFTGOALSNAP */ + } + + bp->nofsprings= 0; + bp->springs= NULL; + bp->choke = 0.0f; + bp->colball = 0.0f; + bp->flag = 0; + + } + } +} + +static void free_softbody_baked(SoftBody *sb) +{ + SBVertex *key; + int k; + + for(k=0; ktotkey; k++) { + key= *(sb->keys + k); + if(key) MEM_freeN(key); + } + if(sb->keys) MEM_freeN(sb->keys); + + sb->keys= NULL; + sb->totkey= 0; + +} +static void free_scratch(SoftBody *sb) +{ + if(sb->scratch){ + /* todo make sure everything is cleaned up nicly */ + if (sb->scratch->colliderhash){ + BLI_ghash_free(sb->scratch->colliderhash, NULL, + (GHashValFreeFP) ccd_mesh_free); /*this hoepfully will free all caches*/ + sb->scratch->colliderhash = NULL; + } + if (sb->scratch->bodyface){ + MEM_freeN(sb->scratch->bodyface); + } + MEM_freeN(sb->scratch); + sb->scratch = NULL; + } + +} + +/* only frees internal data */ +static void free_softbody_intern(SoftBody *sb) +{ + if(sb) { + int a; + BodyPoint *bp; + + if(sb->bpoint){ + for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { + /* free spring list */ + if (bp->springs != NULL) { + MEM_freeN(bp->springs); + } + } + MEM_freeN(sb->bpoint); + } + + if(sb->bspring) MEM_freeN(sb->bspring); + + sb->totpoint= sb->totspring= 0; + sb->bpoint= NULL; + sb->bspring= NULL; + + free_scratch(sb); + free_softbody_baked(sb); + } +} + + +/* ************ dynamics ********** */ + +/* the most general (micro physics correct) way to do collision +** (only needs the current particle position) +** +** it actually checks if the particle intrudes a short range force field generated +** by the faces of the target object and returns a force to drive the particel out +** the strenght of the field grows exponetially if the particle is on the 'wrong' side of the face +** 'wrong' side : projection to the face normal is negative (all referred to a vertex in the face) +** +** flaw of this: 'fast' particles as well as 'fast' colliding faces +** give a 'tunnel' effect such that the particle passes through the force field +** without ever 'seeing' it +** this is fully compliant to heisenberg: h >= fuzzy(location) * fuzzy(time) +** besides our h is way larger than in QM because forces propagate way slower here +** we have to deal with fuzzy(time) in the range of 1/25 seconds (typical frame rate) +** yup collision targets are not known here any better +** and 1/25 second is looong compared to real collision events +** Q: why not use 'simple' collision here like bouncing back a particle +** --> reverting is velocity on the face normal +** A: because our particles are not alone here +** and need to tell their neighbours exactly what happens via spring forces +** unless sbObjectStep( .. ) is called on sub frame timing level +** BTW that also questions the use of a 'implicit' solvers on softbodies +** since that would only valid for 'slow' moving collision targets and dito particles +*/ + +/* aye this belongs to arith.c */ +static void Vec3PlusStVec(float *v, float s, float *v1) +{ + v[0] += s*v1[0]; + v[1] += s*v1[1]; + v[2] += s*v1[2]; +} + +/* +++ dependancy information functions*/ +static int are_there_deflectors(unsigned int layer) +{ + Base *base; + + for(base = G.scene->base.first; base; base= base->next) { + if( (base->lay & layer) && base->object->pd) { + if(base->object->pd->deflect) + return 1; + } + } + return 0; +} + +static int query_external_colliders(Object *me) +{ + return(are_there_deflectors(me->lay)); +} + +#if 0 +static int query_external_forces(Object *me) +{ +/* silly but true: we need to create effector cache to see if anything is in it */ + ListBase *ec = pdInitEffectors(me,NULL); + int result = 0; + if (ec){ + result = 1; + pdEndEffectors(ec); /* sorry ec, yes i'm an idiot, but i needed to know if you were there */ + } + return result; +} + +/* +any of that external objects may have an IPO or something alike .. +so unless we can ask them if they are moving we have to assume they do +*/ +static int query_external_time(Object *me) +{ + if (query_external_colliders(me)) return 1; + if (query_external_forces(me)) return 1; + return 0; +} +static int query_internal_time(Object *me) +{ + if (me->softflag & OB_SB_GOAL) return 1; + return 0; +} +#endif +/* --- dependancy information functions*/ + +/* +++ the aabb "force" section*/ +int sb_detect_aabb_collisionCached( float force[3], unsigned int par_layer,struct Object *vertexowner,float time) +{ + Object *ob; + SoftBody *sb=vertexowner->soft; + GHash *hash; + GHashIterator *ihash; + float aabbmin[3],aabbmax[3]; + int a, deflected=0; + + if ((sb == NULL) || (sb->scratch ==NULL)) return 0; + VECCOPY(aabbmin,sb->scratch->aabbmin); + VECCOPY(aabbmax,sb->scratch->aabbmax); + + hash = vertexowner->soft->scratch->colliderhash; + ihash = BLI_ghashIterator_new(hash); + while (!BLI_ghashIterator_isDone(ihash) ) { + + ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash); + ob = BLI_ghashIterator_getKey (ihash); + /* only with deflecting set */ + if(ob->pd && ob->pd->deflect) { + MFace *mface= NULL; + MVert *mvert= NULL; + MVert *mprevvert= NULL; + ccdf_minmax *mima= NULL; + if(ccdm){ + mface= ccdm->mface; + mvert= ccdm->mvert; + mprevvert= ccdm->mprevvert; + mima= ccdm->mima; + a = ccdm->totface; + + if ((aabbmax[0] < ccdm->bbmin[0]) || + (aabbmax[1] < ccdm->bbmin[1]) || + (aabbmax[2] < ccdm->bbmin[2]) || + (aabbmin[0] > ccdm->bbmax[0]) || + (aabbmin[1] > ccdm->bbmax[1]) || + (aabbmin[2] > ccdm->bbmax[2]) ) { + /* boxes dont intersect */ + BLI_ghashIterator_step(ihash); + continue; + } + + /* so now we have the 2 boxes overlapping */ + /* forces actually not used */ + deflected = 2; + + } + else{ + /*aye that should be cached*/ + printf("missing cache error \n"); + BLI_ghashIterator_step(ihash); + continue; + } + } /* if(ob->pd && ob->pd->deflect) */ + BLI_ghashIterator_step(ihash); + } /* while () */ + BLI_ghashIterator_free(ihash); + return deflected; +} +/* --- the aabb section*/ + + +/* +++ the face external section*/ + +int sb_detect_face_collisionCached(float face_v1[3],float face_v2[3],float face_v3[3],float *damp, + float force[3], unsigned int par_layer,struct Object *vertexowner,float time) +{ + Object *ob; + GHash *hash; + GHashIterator *ihash; + float nv1[3], nv2[3], nv3[3], nv4[3], edge1[3], edge2[3], d_nvect[3], aabbmin[3],aabbmax[3]; + float t; + int a, deflected=0; + + aabbmin[0] = MIN3(face_v1[0],face_v2[0],face_v3[0]); + aabbmin[1] = MIN3(face_v1[1],face_v2[1],face_v3[1]); + aabbmin[2] = MIN3(face_v1[2],face_v2[2],face_v3[2]); + aabbmax[0] = MAX3(face_v1[0],face_v2[0],face_v3[0]); + aabbmax[1] = MAX3(face_v1[1],face_v2[1],face_v3[1]); + aabbmax[2] = MAX3(face_v1[2],face_v2[2],face_v3[2]); + + hash = vertexowner->soft->scratch->colliderhash; + ihash = BLI_ghashIterator_new(hash); + while (!BLI_ghashIterator_isDone(ihash) ) { + + ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash); + ob = BLI_ghashIterator_getKey (ihash); + /* only with deflecting set */ + if(ob->pd && ob->pd->deflect) { + MFace *mface= NULL; + MVert *mvert= NULL; + MVert *mprevvert= NULL; + ccdf_minmax *mima= NULL; + if(ccdm){ + mface= ccdm->mface; + mvert= ccdm->mvert; + mprevvert= ccdm->mprevvert; + mima= ccdm->mima; + a = ccdm->totface; + + if ((aabbmax[0] < ccdm->bbmin[0]) || + (aabbmax[1] < ccdm->bbmin[1]) || + (aabbmax[2] < ccdm->bbmin[2]) || + (aabbmin[0] > ccdm->bbmax[0]) || + (aabbmin[1] > ccdm->bbmax[1]) || + (aabbmin[2] > ccdm->bbmax[2]) ) { + /* boxes dont intersect */ + BLI_ghashIterator_step(ihash); + continue; + } + + } + else{ + /*aye that should be cached*/ + printf("missing cache error \n"); + BLI_ghashIterator_step(ihash); + continue; + } + + + /* use mesh*/ + while (a--) { + if ( + (aabbmax[0] < mima->minx) || + (aabbmin[0] > mima->maxx) || + (aabbmax[1] < mima->miny) || + (aabbmin[1] > mima->maxy) || + (aabbmax[2] < mima->minz) || + (aabbmin[2] > mima->maxz) + ) { + mface++; + mima++; + continue; + } + + + if (mvert){ + + VECCOPY(nv1,mvert[mface->v1].co); + VECCOPY(nv2,mvert[mface->v2].co); + VECCOPY(nv3,mvert[mface->v3].co); + if (mface->v4){ + VECCOPY(nv4,mvert[mface->v4].co); + } + if (mprevvert){ + VecMulf(nv1,time); + Vec3PlusStVec(nv1,(1.0f-time),mprevvert[mface->v1].co); + + VecMulf(nv2,time); + Vec3PlusStVec(nv2,(1.0f-time),mprevvert[mface->v2].co); + + VecMulf(nv3,time); + Vec3PlusStVec(nv3,(1.0f-time),mprevvert[mface->v3].co); + + if (mface->v4){ + VecMulf(nv4,time); + Vec3PlusStVec(nv4,(1.0f-time),mprevvert[mface->v4].co); + } + } + } + + /* switch origin to be nv2*/ + VECSUB(edge1, nv1, nv2); + VECSUB(edge2, nv3, nv2); + Crossf(d_nvect, edge2, edge1); + Normalize(d_nvect); + if ( + LineIntersectsTriangle(nv1, nv2, face_v1, face_v2, face_v3, &t) || + LineIntersectsTriangle(nv2, nv3, face_v1, face_v2, face_v3, &t) || + LineIntersectsTriangle(nv3, nv1, face_v1, face_v2, face_v3, &t) ){ + Vec3PlusStVec(force,-1.0f,d_nvect); + *damp=ob->pd->pdef_sbdamp; + deflected = 2; + } + if (mface->v4){ /* quad */ + /* switch origin to be nv4 */ + VECSUB(edge1, nv3, nv4); + VECSUB(edge2, nv1, nv4); + Crossf(d_nvect, edge2, edge1); + Normalize(d_nvect); + if ( + LineIntersectsTriangle(nv1, nv3, face_v1, face_v2, face_v3, &t) || + LineIntersectsTriangle(nv3, nv4, face_v1, face_v2, face_v3, &t) || + LineIntersectsTriangle(nv4, nv1, face_v1, face_v2, face_v3, &t) ){ + Vec3PlusStVec(force,-1.0f,d_nvect); + *damp=ob->pd->pdef_sbdamp; + deflected = 2; + } + } + mface++; + mima++; + }/* while a */ + } /* if(ob->pd && ob->pd->deflect) */ + BLI_ghashIterator_step(ihash); + } /* while () */ + BLI_ghashIterator_free(ihash); + return deflected; +} + + + +void scan_for_ext_face_forces(Object *ob,float timenow) +{ + SoftBody *sb = ob->soft; + BodyFace *bf; + int a; + float damp; + float tune = -10.0f; + float feedback[3]; + + if (sb && sb->scratch->totface){ + + + bf = sb->scratch->bodyface; + for(a=0; ascratch->totface; a++, bf++) { + bf->ext_force[0]=bf->ext_force[1]=bf->ext_force[2]=0.0f; + feedback[0]=feedback[1]=feedback[2]=0.0f; + bf->flag &= ~BFF_INTERSECT; + + if (sb_detect_face_collisionCached(sb->bpoint[bf->v1].pos,sb->bpoint[bf->v2].pos, sb->bpoint[bf->v3].pos, + &damp, feedback, ob->lay ,ob , timenow)){ + Vec3PlusStVec(bf->ext_force,tune,feedback); + bf->flag |= BFF_INTERSECT; + } + + feedback[0]=feedback[1]=feedback[2]=0.0f; + if ((bf->v4) && (sb_detect_face_collisionCached(sb->bpoint[bf->v1].pos,sb->bpoint[bf->v3].pos, sb->bpoint[bf->v4].pos, + &damp, feedback, ob->lay ,ob , timenow))){ + Vec3PlusStVec(bf->ext_force,tune,feedback); + bf->flag |= BFF_INTERSECT; + } + } + + + + bf = sb->scratch->bodyface; + for(a=0; ascratch->totface; a++, bf++) { + if ( bf->flag & BFF_INTERSECT) + { + VECADD(sb->bpoint[bf->v1].force,sb->bpoint[bf->v1].force,bf->ext_force); + VECADD(sb->bpoint[bf->v2].force,sb->bpoint[bf->v2].force,bf->ext_force); + VECADD(sb->bpoint[bf->v3].force,sb->bpoint[bf->v3].force,bf->ext_force); + if (bf->v4){ + VECADD(sb->bpoint[bf->v4].force,sb->bpoint[bf->v4].force,bf->ext_force); + } + + } + + } + + + + + } +} + +/* --- the face external section*/ + + +/* +++ the spring external section*/ + +int sb_detect_edge_collisionCached(float edge_v1[3],float edge_v2[3],float *damp, + float force[3], unsigned int par_layer,struct Object *vertexowner,float time) +{ + Object *ob; + GHash *hash; + GHashIterator *ihash; + float nv1[3], nv2[3], nv3[3], nv4[3], edge1[3], edge2[3], d_nvect[3], aabbmin[3],aabbmax[3]; + float t,el; + int a, deflected=0; + + aabbmin[0] = MIN2(edge_v1[0],edge_v2[0]); + aabbmin[1] = MIN2(edge_v1[1],edge_v2[1]); + aabbmin[2] = MIN2(edge_v1[2],edge_v2[2]); + aabbmax[0] = MAX2(edge_v1[0],edge_v2[0]); + aabbmax[1] = MAX2(edge_v1[1],edge_v2[1]); + aabbmax[2] = MAX2(edge_v1[2],edge_v2[2]); + + el = VecLenf(edge_v1,edge_v2); + + hash = vertexowner->soft->scratch->colliderhash; + ihash = BLI_ghashIterator_new(hash); + while (!BLI_ghashIterator_isDone(ihash) ) { + + ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash); + ob = BLI_ghashIterator_getKey (ihash); + /* only with deflecting set */ + if(ob->pd && ob->pd->deflect) { + MFace *mface= NULL; + MVert *mvert= NULL; + MVert *mprevvert= NULL; + ccdf_minmax *mima= NULL; + if(ccdm){ + mface= ccdm->mface; + mvert= ccdm->mvert; + mprevvert= ccdm->mprevvert; + mima= ccdm->mima; + a = ccdm->totface; + + if ((aabbmax[0] < ccdm->bbmin[0]) || + (aabbmax[1] < ccdm->bbmin[1]) || + (aabbmax[2] < ccdm->bbmin[2]) || + (aabbmin[0] > ccdm->bbmax[0]) || + (aabbmin[1] > ccdm->bbmax[1]) || + (aabbmin[2] > ccdm->bbmax[2]) ) { + /* boxes dont intersect */ + BLI_ghashIterator_step(ihash); + continue; + } + + } + else{ + /*aye that should be cached*/ + printf("missing cache error \n"); + BLI_ghashIterator_step(ihash); + continue; + } + + + /* use mesh*/ + while (a--) { + if ( + (aabbmax[0] < mima->minx) || + (aabbmin[0] > mima->maxx) || + (aabbmax[1] < mima->miny) || + (aabbmin[1] > mima->maxy) || + (aabbmax[2] < mima->minz) || + (aabbmin[2] > mima->maxz) + ) { + mface++; + mima++; + continue; + } + + + if (mvert){ + + VECCOPY(nv1,mvert[mface->v1].co); + VECCOPY(nv2,mvert[mface->v2].co); + VECCOPY(nv3,mvert[mface->v3].co); + if (mface->v4){ + VECCOPY(nv4,mvert[mface->v4].co); + } + if (mprevvert){ + VecMulf(nv1,time); + Vec3PlusStVec(nv1,(1.0f-time),mprevvert[mface->v1].co); + + VecMulf(nv2,time); + Vec3PlusStVec(nv2,(1.0f-time),mprevvert[mface->v2].co); + + VecMulf(nv3,time); + Vec3PlusStVec(nv3,(1.0f-time),mprevvert[mface->v3].co); + + if (mface->v4){ + VecMulf(nv4,time); + Vec3PlusStVec(nv4,(1.0f-time),mprevvert[mface->v4].co); + } + } + } + + /* switch origin to be nv2*/ + VECSUB(edge1, nv1, nv2); + VECSUB(edge2, nv3, nv2); + + Crossf(d_nvect, edge2, edge1); + Normalize(d_nvect); + if ( LineIntersectsTriangle(edge_v1, edge_v2, nv1, nv2, nv3, &t)){ + float v1[3],v2[3]; + float intrusiondepth,i1,i2; + VECSUB(v1, edge_v1, nv2); + VECSUB(v2, edge_v2, nv2); + i1 = Inpf(v1,d_nvect); + i2 = Inpf(v2,d_nvect); + intrusiondepth = -MIN2(i1,i2)/el; + Vec3PlusStVec(force,intrusiondepth,d_nvect); + *damp=ob->pd->pdef_sbdamp; + deflected = 2; + } + if (mface->v4){ /* quad */ + /* switch origin to be nv4 */ + VECSUB(edge1, nv3, nv4); + VECSUB(edge2, nv1, nv4); + + Crossf(d_nvect, edge2, edge1); + Normalize(d_nvect); + if (LineIntersectsTriangle( edge_v1, edge_v2,nv1, nv3, nv4, &t)){ + float v1[3],v2[3]; + float intrusiondepth,i1,i2; + VECSUB(v1, edge_v1, nv4); + VECSUB(v2, edge_v2, nv4); + i1 = Inpf(v1,d_nvect); + i2 = Inpf(v2,d_nvect); + intrusiondepth = -MIN2(i1,i2)/el; + + + Vec3PlusStVec(force,intrusiondepth,d_nvect); + *damp=ob->pd->pdef_sbdamp; + deflected = 2; + } + } + mface++; + mima++; + }/* while a */ + } /* if(ob->pd && ob->pd->deflect) */ + BLI_ghashIterator_step(ihash); + } /* while () */ + BLI_ghashIterator_free(ihash); + return deflected; +} + + +void scan_for_ext_spring_forces(Object *ob,float timenow) +{ + SoftBody *sb = ob->soft; + ListBase *do_effector; + int a; + float damp; + float feedback[3]; + do_effector= pdInitEffectors(ob,NULL); + + if (sb && sb->totspring){ + for(a=0; atotspring; a++) { + BodySpring *bs = &sb->bspring[a]; + bs->ext_force[0]=bs->ext_force[1]=bs->ext_force[2]=0.0f; + feedback[0]=feedback[1]=feedback[2]=0.0f; + bs->flag &= ~BSF_INTERSECT; + + if (bs->order ==1){ + /* +++ springs colliding */ + if (ob->softflag & OB_SB_EDGECOLL){ + if ( sb_detect_edge_collisionCached (sb->bpoint[bs->v1].pos , sb->bpoint[bs->v2].pos, + &damp,feedback,ob->lay,ob,timenow)){ + VecAddf(bs->ext_force,bs->ext_force,feedback); + bs->flag |= BSF_INTERSECT; + //bs->cf=damp; + bs->cf=sb->choke*0.01f; + + } + } + /* ---- springs colliding */ + + /* +++ springs seeing wind ... n stuff depending on their orientation*/ + /* note we don't use sb->mediafrict but use sb->aeroedge for magnitude of effect*/ + if(sb->aeroedge){ + float vel[3],sp[3],pr[3],force[3]; + float f,windfactor = 250.0f; + /*see if we have wind*/ + if(do_effector) { + float speed[3]={0.0f,0.0f,0.0f}; + float pos[3]; + VecMidf(pos, sb->bpoint[bs->v1].pos , sb->bpoint[bs->v2].pos); + VecMidf(vel, sb->bpoint[bs->v1].vec , sb->bpoint[bs->v2].vec); + pdDoEffectors(do_effector, pos, force, speed, (float)G.scene->r.cfra, 0.0f, PE_WIND_AS_SPEED); + VecMulf(speed,windfactor); + VecAddf(vel,vel,speed); + } + /* media in rest */ + else{ + VECADD(vel, sb->bpoint[bs->v1].vec , sb->bpoint[bs->v2].vec); + } + f = Normalize(vel); + f = -0.0001f*f*f*sb->aeroedge; + /* todo add a nice angle dependant function */ + /* look up one at bergman scheafer */ + + VECSUB(sp, sb->bpoint[bs->v1].pos , sb->bpoint[bs->v2].pos); + Projf(pr,vel,sp); + VECSUB(vel,vel,pr); + Normalize(vel); + Vec3PlusStVec(bs->ext_force,f,vel); + } + /* --- springs seeing wind */ + } + } + } + if(do_effector) + pdEndEffectors(do_effector); +} +/* --- the spring external section*/ + +int choose_winner(float*w, float* pos,float*a,float*b,float*c,float*ca,float*cb,float*cc) +{ + float mindist,cp; + int winner =1; + mindist = ABS(Inpf(pos,a)); + + cp = ABS(Inpf(pos,b)); + if ( mindist < cp ){ + mindist = cp; + winner =2; + } + + cp = ABS(Inpf(pos,c)); + if (mindist < cp ){ + mindist = cp; + winner =3; + } + switch (winner){ + case 1: VECCOPY(w,ca); break; + case 2: VECCOPY(w,cb); break; + case 3: VECCOPY(w,cc); + } + return(winner); +} + + + +int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3], float *damp, + float force[3], unsigned int par_layer,struct Object *vertexowner, + float time,float vel[3], float *intrusion) +{ + Object *ob= NULL; + GHash *hash; + GHashIterator *ihash; + float nv1[3], nv2[3], nv3[3], nv4[3], edge1[3], edge2[3],d_nvect[3], dv1[3],ve[3],avel[3], + vv1[3], vv2[3], vv3[3], vv4[3], coledge[3], mindistedge = 1000.0f, + outerforceaccu[3],innerforceaccu[3], + facedist,n_mag,force_mag_norm,minx,miny,minz,maxx,maxy,maxz, + innerfacethickness = -0.5f, outerfacethickness = 0.2f, + ee = 5.0f, ff = 0.1f, fa=1; + int a, deflected=0, cavel=0,ci=0; +/* init */ + *intrusion = 0.0f; + hash = vertexowner->soft->scratch->colliderhash; + ihash = BLI_ghashIterator_new(hash); + outerforceaccu[0]=outerforceaccu[1]=outerforceaccu[2]=0.0f; + innerforceaccu[0]=innerforceaccu[1]=innerforceaccu[2]=0.0f; +/* go */ + while (!BLI_ghashIterator_isDone(ihash) ) { + + ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash); + ob = BLI_ghashIterator_getKey (ihash); + /* only with deflecting set */ + if(ob->pd && ob->pd->deflect) { + MFace *mface= NULL; + MVert *mvert= NULL; + MVert *mprevvert= NULL; + ccdf_minmax *mima= NULL; + + if(ccdm){ + mface= ccdm->mface; + mvert= ccdm->mvert; + mprevvert= ccdm->mprevvert; + mima= ccdm->mima; + a = ccdm->totface; + + minx =ccdm->bbmin[0]; + miny =ccdm->bbmin[1]; + minz =ccdm->bbmin[2]; + + maxx =ccdm->bbmax[0]; + maxy =ccdm->bbmax[1]; + maxz =ccdm->bbmax[2]; + + if ((opco[0] < minx) || + (opco[1] < miny) || + (opco[2] < minz) || + (opco[0] > maxx) || + (opco[1] > maxy) || + (opco[2] > maxz) ) { + /* outside the padded boundbox --> collision object is too far away */ + BLI_ghashIterator_step(ihash); + continue; + } + } + else{ + /*aye that should be cached*/ + printf("missing cache error \n"); + BLI_ghashIterator_step(ihash); + continue; + } + + /* do object level stuff */ + /* need to have user control for that since it depends on model scale */ + innerfacethickness =-ob->pd->pdef_sbift; + outerfacethickness =ob->pd->pdef_sboft; + fa = (ff*outerfacethickness-outerfacethickness); + fa *= fa; + fa = 1.0f/fa; + avel[0]=avel[1]=avel[2]=0.0f; + /* use mesh*/ + while (a--) { + if ( + (opco[0] < mima->minx) || + (opco[0] > mima->maxx) || + (opco[1] < mima->miny) || + (opco[1] > mima->maxy) || + (opco[2] < mima->minz) || + (opco[2] > mima->maxz) + ) { + mface++; + mima++; + continue; + } + + if (mvert){ + + VECCOPY(nv1,mvert[mface->v1].co); + VECCOPY(nv2,mvert[mface->v2].co); + VECCOPY(nv3,mvert[mface->v3].co); + if (mface->v4){ + VECCOPY(nv4,mvert[mface->v4].co); + } + + if (mprevvert){ + /* grab the average speed of the collider vertices + before we spoil nvX + humm could be done once a SB steps but then we' need to store that too + since the AABB reduced propabitlty to get here drasticallly + it might be a nice tradeof CPU <--> memory + */ + VECSUB(vv1,nv1,mprevvert[mface->v1].co); + VECSUB(vv2,nv2,mprevvert[mface->v2].co); + VECSUB(vv3,nv3,mprevvert[mface->v3].co); + if (mface->v4){ + VECSUB(vv4,nv4,mprevvert[mface->v4].co); + } + + VecMulf(nv1,time); + Vec3PlusStVec(nv1,(1.0f-time),mprevvert[mface->v1].co); + + VecMulf(nv2,time); + Vec3PlusStVec(nv2,(1.0f-time),mprevvert[mface->v2].co); + + VecMulf(nv3,time); + Vec3PlusStVec(nv3,(1.0f-time),mprevvert[mface->v3].co); + + if (mface->v4){ + VecMulf(nv4,time); + Vec3PlusStVec(nv4,(1.0f-time),mprevvert[mface->v4].co); + } + } + } + + /* switch origin to be nv2*/ + VECSUB(edge1, nv1, nv2); + VECSUB(edge2, nv3, nv2); + VECSUB(dv1,opco,nv2); /* abuse dv1 to have vertex in question at *origin* of triangle */ + + Crossf(d_nvect, edge2, edge1); + n_mag = Normalize(d_nvect); + facedist = Inpf(dv1,d_nvect); + // so rules are + // + + if ((facedist > innerfacethickness) && (facedist < outerfacethickness)){ + if (point_in_tri_prism(opco, nv1, nv2, nv3) ){ + force_mag_norm =(float)exp(-ee*facedist); + if (facedist > outerfacethickness*ff) + force_mag_norm =(float)force_mag_norm*fa*(facedist - outerfacethickness)*(facedist - outerfacethickness); + *damp=ob->pd->pdef_sbdamp; + if (facedist > 0.0f){ + *damp *= (1.0f - facedist/outerfacethickness); + Vec3PlusStVec(outerforceaccu,force_mag_norm,d_nvect); + deflected = 3; + + } + else { + Vec3PlusStVec(innerforceaccu,force_mag_norm,d_nvect); + if (deflected < 2) deflected = 2; + } + if ((mprevvert) && (*damp > 0.0f)){ + choose_winner(ve,opco,nv1,nv2,nv3,vv1,vv2,vv3); + VECADD(avel,avel,ve); + cavel ++; + } + *intrusion += facedist; + ci++; + } + } + if (mface->v4){ /* quad */ + /* switch origin to be nv4 */ + VECSUB(edge1, nv3, nv4); + VECSUB(edge2, nv1, nv4); + VECSUB(dv1,opco,nv4); /* abuse dv1 to have vertex in question at *origin* of triangle */ + + Crossf(d_nvect, edge2, edge1); + n_mag = Normalize(d_nvect); + facedist = Inpf(dv1,d_nvect); + + if ((facedist > innerfacethickness) && (facedist < outerfacethickness)){ + if (point_in_tri_prism(opco, nv1, nv3, nv4) ){ + force_mag_norm =(float)exp(-ee*facedist); + if (facedist > outerfacethickness*ff) + force_mag_norm =(float)force_mag_norm*fa*(facedist - outerfacethickness)*(facedist - outerfacethickness); + *damp=ob->pd->pdef_sbdamp; + if (facedist > 0.0f){ + *damp *= (1.0f - facedist/outerfacethickness); + Vec3PlusStVec(outerforceaccu,force_mag_norm,d_nvect); + deflected = 3; + + } + else { + Vec3PlusStVec(innerforceaccu,force_mag_norm,d_nvect); + if (deflected < 2) deflected = 2; + } + + if ((mprevvert) && (*damp > 0.0f)){ + choose_winner(ve,opco,nv1,nv3,nv4,vv1,vv3,vv4); + VECADD(avel,avel,ve); + cavel ++; + } + *intrusion += facedist; + ci++; + } + + } + if ((deflected < 2)&& (G.rt != 444)) // we did not hit a face until now + { // see if 'outer' hits an edge + float dist; + + PclosestVL3Dfl(ve, opco, nv1, nv2); + VECSUB(ve,opco,ve); + dist = Normalize(ve); + if ((dist < outerfacethickness)&&(dist < mindistedge )){ + VECCOPY(coledge,ve); + mindistedge = dist, + deflected=1; + } + + PclosestVL3Dfl(ve, opco, nv2, nv3); + VECSUB(ve,opco,ve); + dist = Normalize(ve); + if ((dist < outerfacethickness)&&(dist < mindistedge )){ + VECCOPY(coledge,ve); + mindistedge = dist, + deflected=1; + } + + PclosestVL3Dfl(ve, opco, nv3, nv1); + VECSUB(ve,opco,ve); + dist = Normalize(ve); + if ((dist < outerfacethickness)&&(dist < mindistedge )){ + VECCOPY(coledge,ve); + mindistedge = dist, + deflected=1; + } + if (mface->v4){ /* quad */ + PclosestVL3Dfl(ve, opco, nv3, nv4); + VECSUB(ve,opco,ve); + dist = Normalize(ve); + if ((dist < outerfacethickness)&&(dist < mindistedge )){ + VECCOPY(coledge,ve); + mindistedge = dist, + deflected=1; + } + + PclosestVL3Dfl(ve, opco, nv1, nv4); + VECSUB(ve,opco,ve); + dist = Normalize(ve); + if ((dist < outerfacethickness)&&(dist < mindistedge )){ + VECCOPY(coledge,ve); + mindistedge = dist, + deflected=1; + } + + } + + + } + } + mface++; + mima++; + }/* while a */ + } /* if(ob->pd && ob->pd->deflect) */ + BLI_ghashIterator_step(ihash); + } /* while () */ + + if (deflected == 1){ // no face but 'outer' edge cylinder sees vert + force_mag_norm =(float)exp(-ee*mindistedge); + if (mindistedge > outerfacethickness*ff) + force_mag_norm =(float)force_mag_norm*fa*(mindistedge - outerfacethickness)*(mindistedge - outerfacethickness); + Vec3PlusStVec(force,force_mag_norm,coledge); + *damp=ob->pd->pdef_sbdamp; + if (mindistedge > 0.0f){ + *damp *= (1.0f - mindistedge/outerfacethickness); + } + + } + if (deflected == 2){ // face inner detected + VECADD(force,force,innerforceaccu); + } + if (deflected == 3){ // face outer detected + VECADD(force,force,outerforceaccu); + } + + BLI_ghashIterator_free(ihash); + if (cavel) VecMulf(avel,1.0f/(float)cavel); + VECCOPY(vel,avel); + if (ci) *intrusion /= ci; + if (deflected){ + VECCOPY(facenormal,force); + Normalize(facenormal); + } + return deflected; +} + +/* not complete yet .. + try to find a pos resolving all inside collisions +*/ +#if 0 //mute it for now +int sb_detect_vertex_collisionCachedEx(float opco[3], float facenormal[3], float *damp, + float force[3], unsigned int par_layer,struct Object *vertexowner, + float time,float vel[3], float *intrusion) +{ + Object *ob; + GHash *hash; + GHashIterator *ihash; + float nv1[3], nv2[3], nv3[3], nv4[3], edge1[3], edge2[3],d_nvect[3], dv1[3],ve[3],avel[3], + vv1[3], vv2[3], vv3[3], vv4[3], + facedist,n_mag,force_mag_norm,minx,miny,minz,maxx,maxy,maxz, + innerfacethickness,outerfacethickness, + closestinside, + ee = 5.0f, ff = 0.1f, fa; + int a, deflected=0, cavel=0; +/* init */ + *intrusion = 0.0f; + hash = vertexowner->soft->scratch->colliderhash; + ihash = BLI_ghashIterator_new(hash); +/* go */ + while (!BLI_ghashIterator_isDone(ihash) ) { + + ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash); + ob = BLI_ghashIterator_getKey (ihash); + /* only with deflecting set */ + if(ob->pd && ob->pd->deflect) { + MFace *mface= NULL; + MVert *mvert= NULL; + MVert *mprevvert= NULL; + ccdf_minmax *mima= NULL; + + if(ccdm){ + mface= ccdm->mface; + mvert= ccdm->mvert; + mprevvert= ccdm->mprevvert; + mima= ccdm->mima; + a = ccdm->totface; + + minx =ccdm->bbmin[0]; + miny =ccdm->bbmin[1]; + minz =ccdm->bbmin[2]; + + maxx =ccdm->bbmax[0]; + maxy =ccdm->bbmax[1]; + maxz =ccdm->bbmax[2]; + + if ((opco[0] < minx) || + (opco[1] < miny) || + (opco[2] < minz) || + (opco[0] > maxx) || + (opco[1] > maxy) || + (opco[2] > maxz) ) { + /* outside the padded boundbox --> collision object is too far away */ + BLI_ghashIterator_step(ihash); + continue; + } + } + else{ + /*aye that should be cached*/ + printf("missing cache error \n"); + BLI_ghashIterator_step(ihash); + continue; + } + + /* do object level stuff */ + /* need to have user control for that since it depends on model scale */ + innerfacethickness =-ob->pd->pdef_sbift; + outerfacethickness =ob->pd->pdef_sboft; + closestinside = innerfacethickness; + fa = (ff*outerfacethickness-outerfacethickness); + fa *= fa; + fa = 1.0f/fa; + avel[0]=avel[1]=avel[2]=0.0f; + /* use mesh*/ + while (a--) { + if ( + (opco[0] < mima->minx) || + (opco[0] > mima->maxx) || + (opco[1] < mima->miny) || + (opco[1] > mima->maxy) || + (opco[2] < mima->minz) || + (opco[2] > mima->maxz) + ) { + mface++; + mima++; + continue; + } + + if (mvert){ + + VECCOPY(nv1,mvert[mface->v1].co); + VECCOPY(nv2,mvert[mface->v2].co); + VECCOPY(nv3,mvert[mface->v3].co); + if (mface->v4){ + VECCOPY(nv4,mvert[mface->v4].co); + } + + if (mprevvert){ + /* grab the average speed of the collider vertices + before we spoil nvX + humm could be done once a SB steps but then we' need to store that too + since the AABB reduced propabitlty to get here drasticallly + it might be a nice tradeof CPU <--> memory + */ + VECSUB(vv1,nv1,mprevvert[mface->v1].co); + VECSUB(vv2,nv2,mprevvert[mface->v2].co); + VECSUB(vv3,nv3,mprevvert[mface->v3].co); + if (mface->v4){ + VECSUB(vv4,nv4,mprevvert[mface->v4].co); + } + + VecMulf(nv1,time); + Vec3PlusStVec(nv1,(1.0f-time),mprevvert[mface->v1].co); + + VecMulf(nv2,time); + Vec3PlusStVec(nv2,(1.0f-time),mprevvert[mface->v2].co); + + VecMulf(nv3,time); + Vec3PlusStVec(nv3,(1.0f-time),mprevvert[mface->v3].co); + + if (mface->v4){ + VecMulf(nv4,time); + Vec3PlusStVec(nv4,(1.0f-time),mprevvert[mface->v4].co); + } + } + } + + /* switch origin to be nv2*/ + VECSUB(edge1, nv1, nv2); + VECSUB(edge2, nv3, nv2); + VECSUB(dv1,opco,nv2); /* abuse dv1 to have vertex in question at *origin* of triangle */ + + Crossf(d_nvect, edge2, edge1); + n_mag = Normalize(d_nvect); + facedist = Inpf(dv1,d_nvect); + + if ((facedist > closestinside) && (facedist < outerfacethickness)){ +// if ((facedist > innerfacethickness) && (facedist < outerfacethickness)){ + if (point_in_tri_prism(opco, nv1, nv2, nv3) ){ + force_mag_norm =(float)exp(-ee*facedist); + if (facedist > outerfacethickness*ff) + force_mag_norm =(float)force_mag_norm*fa*(facedist - outerfacethickness)*(facedist - outerfacethickness); + *damp=ob->pd->pdef_sbdamp; + + if (facedist > 0.0f){ + *damp *= (1.0f - facedist/outerfacethickness); + Vec3PlusStVec(force,force_mag_norm,d_nvect); + if (deflected < 2){ + deflected = 1; + if ((mprevvert) && (*damp > 0.0f)){ + choose_winner(ve,opco,nv1,nv2,nv3,vv1,vv2,vv3); + VECADD(avel,avel,ve); + cavel ++; + } + } + + } + else{ + Vec3PlusStVec(force,force_mag_norm,d_nvect); + VECCOPY(facenormal,d_nvect); + if ((mprevvert) && (*damp > 0.0f)){ + choose_winner(avel,opco,nv1,nv2,nv3,vv1,vv2,vv3); + cavel = 1; + deflected = 2; + closestinside = facedist; + } + } + *intrusion = facedist; + } + } + if (mface->v4){ /* quad */ + /* switch origin to be nv4 */ + VECSUB(edge1, nv3, nv4); + VECSUB(edge2, nv1, nv4); + VECSUB(dv1,opco,nv4); /* abuse dv1 to have vertex in question at *origin* of triangle */ + + Crossf(d_nvect, edge2, edge1); + n_mag = Normalize(d_nvect); + facedist = Inpf(dv1,d_nvect); + + if ((facedist > innerfacethickness) && (facedist < outerfacethickness)){ + if (point_in_tri_prism(opco, nv1, nv3, nv4) ){ + force_mag_norm =(float)exp(-ee*facedist); + if (facedist > outerfacethickness*ff) + force_mag_norm =(float)force_mag_norm*fa*(facedist - outerfacethickness)*(facedist - outerfacethickness); + Vec3PlusStVec(force,force_mag_norm,d_nvect); + *damp=ob->pd->pdef_sbdamp; + + if (facedist > 0.0f){ + *damp *= (1.0f - facedist/outerfacethickness); + Vec3PlusStVec(force,force_mag_norm,d_nvect); + if (deflected < 2){ + deflected = 1; + if ((mprevvert) && (*damp > 0.0f)){ + choose_winner(ve,opco,nv1,nv3,nv4,vv1,vv3,vv4); + VECADD(avel,avel,ve); + cavel ++; + } + } + + } + else{ + Vec3PlusStVec(force,force_mag_norm,d_nvect); + VECCOPY(facenormal,d_nvect); + if ((mprevvert) && (*damp > 0.0f)){ + choose_winner(avel,opco,nv1,nv3,nv4,vv1,vv3,vv4); + cavel = 1; + deflected = 2; + closestinside = facedist; + } + } + + + + *intrusion = facedist; + } + + } + } + mface++; + mima++; + }/* while a */ + } /* if(ob->pd && ob->pd->deflect) */ + BLI_ghashIterator_step(ihash); + } /* while () */ + BLI_ghashIterator_free(ihash); + if (cavel) VecMulf(avel,1.0f/(float)cavel); + VECCOPY(vel,avel); + + /* we did stay "outside" but have some close to contact forces + just to be complete fake a face normal + */ + if (deflected ==1){ + VECCOPY(facenormal,force); + Normalize(facenormal); + } + else{ + facenormal[0] = facenormal[1] = facenormal[2] = 0.0f; + } + return deflected; +} +#endif + + + +/* sandbox to plug in various deflection algos */ +static int sb_deflect_face(Object *ob,float *actpos,float *facenormal,float *force,float *cf,float time,float *vel,float *intrusion) +{ + float s_actpos[3]; + int deflected; + VECCOPY(s_actpos,actpos); + deflected= sb_detect_vertex_collisionCached(s_actpos, facenormal, cf, force , ob->lay, ob,time,vel,intrusion); + //deflected= sb_detect_vertex_collisionCachedEx(s_actpos, facenormal, cf, force , ob->lay, ob,time,vel,intrusion); + return(deflected); +} + + +static void softbody_calc_forces(Object *ob, float forcetime, float timenow) +{ +/* rule we never alter free variables :bp->vec bp->pos in here ! + * this will ruin adaptive stepsize AKA heun! (BM) + */ + SoftBody *sb= ob->soft; /* is supposed to be there */ + BodyPoint *bp; + BodyPoint *bproot; + BodySpring *bs; + ListBase *do_effector; + float iks, ks, kd, gravity, actspringlen, forcefactor, sd[3]; + float fieldfactor = 1000.0f, windfactor = 250.0f; + float tune = sb->ballstiff; + int a, b, do_deflector,do_selfcollision,do_springcollision,do_aero; + + + gravity = sb->grav * sb_grav_force_scale(ob); + + /* check conditions for various options */ + do_deflector= query_external_colliders(ob); + do_effector= pdInitEffectors(ob,NULL); + do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF)); + do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL); + do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES)); + + iks = 1.0f/(1.0f-sb->inspring)-1.0f ;/* inner spring constants function */ + bproot= sb->bpoint; /* need this for proper spring addressing */ + + + + if (do_springcollision || do_aero) scan_for_ext_spring_forces(ob,timenow); + if (do_deflector) { + float defforce[3]; + do_deflector = sb_detect_aabb_collisionCached(defforce,ob->lay,ob,timenow); + } + + if (do_selfcollision ){ + float ce[3]; + VecMidf(ce,sb->scratch->aabbmax,sb->scratch->aabbmin); + for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { + bp->octantflag = set_octant_flags(ce,bp->pos,bp->colball); + } + } + + for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { + /* clear forces accumulator */ + bp->force[0]= bp->force[1]= bp->force[2]= 0.0; + + /* naive ball self collision */ + /* needs to be done if goal snaps or not */ + if(do_selfcollision){ + int attached; + BodyPoint *obp; + int c,b; + float velcenter[3],dvel[3],def[3]; + float distance; + float compare; + + for(c=sb->totpoint, obp= sb->bpoint; c>=a; c--, obp++) { + + if ((bp->octantflag & obp->octantflag) == 0) continue; + + compare = (obp->colball + bp->colball); + VecSubf(def, bp->pos, obp->pos); + + /* rather check the AABBoxes before ever calulating the real distance */ + /* mathematically it is completly nuts, but performace is pretty much (3) times faster */ + if ((ABS(def[0]) > compare) || (ABS(def[1]) > compare) || (ABS(def[2]) > compare)) continue; + + distance = Normalize(def); + if (distance < compare ){ + /* exclude body points attached with a spring */ + attached = 0; + for(b=obp->nofsprings;b>0;b--){ + bs = sb->bspring + obp->springs[b-1]; + if (( sb->totpoint-a == bs->v2) || ( sb->totpoint-a == bs->v1)){ + attached=1; + continue;} + } + if (!attached){ + float f = tune/(distance) + tune/(compare*compare)*distance - 2.0f*tune/compare ; + + VecMidf(velcenter, bp->vec, obp->vec); + VecSubf(dvel,velcenter,bp->vec); + VecMulf(dvel,sb->nodemass); + + Vec3PlusStVec(bp->force,sb->balldamp,dvel); + Vec3PlusStVec(bp->force,f*(1.0f-sb->balldamp),def); + /* exploit force(a,b) == -force(b,a) part2/2 */ + VecSubf(dvel,velcenter,obp->vec); + VecMulf(dvel,sb->nodemass); + + Vec3PlusStVec(obp->force,sb->balldamp,dvel); + Vec3PlusStVec(obp->force,-f*(1.0f-sb->balldamp),def); + + } + } + } + } + /* naive ball self collision done */ + + if(bp->goal < SOFTGOALSNAP){ /* ommit this bp when it snaps */ + float auxvect[3]; + float velgoal[3]; + float absvel =0, projvel= 0; + + /* do goal stuff */ + if(ob->softflag & OB_SB_GOAL) { + /* true elastic goal */ + VecSubf(auxvect,bp->origT,bp->pos); + ks = 1.0f/(1.0f- bp->goal*sb->goalspring)-1.0f ; + bp->force[0]+= ks*(auxvect[0]); + bp->force[1]+= ks*(auxvect[1]); + bp->force[2]+= ks*(auxvect[2]); + /* calulate damping forces generated by goals*/ + VecSubf(velgoal,bp->origS, bp->origE); + kd = sb->goalfrict * sb_fric_force_scale(ob) ; + + if (forcetime > 0.0 ) { /* make sure friction does not become rocket motor on time reversal */ + bp->force[0]-= kd * (velgoal[0] + bp->vec[0]); + bp->force[1]-= kd * (velgoal[1] + bp->vec[1]); + bp->force[2]-= kd * (velgoal[2] + bp->vec[2]); + } + else { + bp->force[0]-= kd * (velgoal[0] - bp->vec[0]); + bp->force[1]-= kd * (velgoal[1] - bp->vec[1]); + bp->force[2]-= kd * (velgoal[2] - bp->vec[2]); + } + } + /* done goal stuff */ + + + /* gravitation */ + bp->force[2]-= gravity*sb->nodemass; /* individual mass of node here */ + + + /* particle field & vortex */ + if(do_effector) { + float force[3]= {0.0f, 0.0f, 0.0f}; + float speed[3]= {0.0f, 0.0f, 0.0f}; + float eval_sb_fric_force_scale = sb_fric_force_scale(ob); /* just for calling function once */ + + pdDoEffectors(do_effector, bp->pos, force, speed, (float)G.scene->r.cfra, 0.0f, PE_WIND_AS_SPEED); + + /* apply forcefield*/ + VecMulf(force,fieldfactor* eval_sb_fric_force_scale); + VECADD(bp->force, bp->force, force); + + /* BP friction in moving media */ + kd= sb->mediafrict* eval_sb_fric_force_scale; + bp->force[0] -= kd * (bp->vec[0] + windfactor*speed[0]/eval_sb_fric_force_scale); + bp->force[1] -= kd * (bp->vec[1] + windfactor*speed[1]/eval_sb_fric_force_scale); + bp->force[2] -= kd * (bp->vec[2] + windfactor*speed[2]/eval_sb_fric_force_scale); + /* now we'll have nice centrifugal effect for vortex */ + + } + else { + /* BP friction in media (not) moving*/ + kd= sb->mediafrict* sb_fric_force_scale(ob); + /* assume it to be proportional to actual velocity */ + bp->force[0]-= bp->vec[0]*kd; + bp->force[1]-= bp->vec[1]*kd; + bp->force[2]-= bp->vec[2]*kd; + /* friction in media done */ + } + /* +++cached collision targets */ + bp->choke = 0.0f; + bp->flag &= ~SBF_DOFUZZY; + if(do_deflector) { + float cfforce[3],defforce[3] ={0.0f,0.0f,0.0f}, vel[3] = {0.0f,0.0f,0.0f}, facenormal[3], cf = 1.0f,intrusion; + kd = 1.0f; + + if (sb_deflect_face(ob,bp->pos,facenormal,defforce,&cf,timenow,vel,&intrusion)){ + if (intrusion < 0.0f){ + /*bjornmose: uugh.. what an evil hack + violation of the 'don't touch bp->pos in here' rule + but works nice, like this--> + we predict the solution beeing out of the collider + in heun step No1 and leave the heun step No2 adapt to it + so we kind of introduced a implicit solver for this case + */ + Vec3PlusStVec(bp->pos,-intrusion,facenormal); + + sb->scratch->flag |= SBF_DOFUZZY; + bp->flag |= SBF_DOFUZZY; + bp->choke = sb->choke*0.01f; + } + else{ + VECSUB(cfforce,bp->vec,vel); + Vec3PlusStVec(bp->force,-cf*50.0f,cfforce); + } + + Vec3PlusStVec(bp->force,kd,defforce); + } + + } + /* ---cached collision targets */ + + /* +++springs */ + if(ob->softflag & OB_SB_EDGES) { + if (sb->bspring){ /* spring list exists at all ? */ + for(b=bp->nofsprings;b>0;b--){ + bs = sb->bspring + bp->springs[b-1]; + if (do_springcollision || do_aero){ + VecAddf(bp->force,bp->force,bs->ext_force); + if (bs->flag & BSF_INTERSECT) + bp->choke = bs->cf; + + } + + if (( (sb->totpoint-a) == bs->v1) ){ + actspringlen= VecLenf( (bproot+bs->v2)->pos, bp->pos); + VecSubf(sd,(bproot+bs->v2)->pos, bp->pos); + Normalize(sd); + + /* friction stuff V1 */ + VecSubf(velgoal,bp->vec,(bproot+bs->v2)->vec); + kd = sb->infrict * sb_fric_force_scale(ob); + absvel = Normalize(velgoal); + projvel = ABS(Inpf(sd,velgoal)); + kd *= absvel * projvel; + Vec3PlusStVec(bp->force,-kd,velgoal); + + if(bs->len > 0.0f) /* check for degenerated springs */ + forcefactor = (bs->len - actspringlen)/bs->len * iks; + else + forcefactor = actspringlen * iks; + forcefactor *= bs->strength; + + Vec3PlusStVec(bp->force,-forcefactor,sd); + + } + + if (( (sb->totpoint-a) == bs->v2) ){ + actspringlen= VecLenf( (bproot+bs->v1)->pos, bp->pos); + VecSubf(sd,bp->pos,(bproot+bs->v1)->pos); + Normalize(sd); + + /* friction stuff V2 */ + VecSubf(velgoal,bp->vec,(bproot+bs->v1)->vec); + kd = sb->infrict * sb_fric_force_scale(ob); + absvel = Normalize(velgoal); + projvel = ABS(Inpf(sd,velgoal)); + kd *= absvel * projvel; + Vec3PlusStVec(bp->force,-kd,velgoal); + + if(bs->len > 0.0) + forcefactor = (bs->len - actspringlen)/bs->len * iks; + else + forcefactor = actspringlen * iks; + forcefactor *= bs->strength; + Vec3PlusStVec(bp->force,+forcefactor,sd); + } + }/* loop springs */ + }/* existing spring list */ + }/*any edges*/ + /* ---springs */ + }/*omit on snap */ + }/*loop all bp's*/ + + + /* finally add forces caused by face collision */ + if (ob->softflag & OB_SB_FACECOLL) scan_for_ext_face_forces(ob,timenow); + /* cleanup */ + if(do_effector) pdEndEffectors(do_effector); +} + + + +static void softbody_apply_forces(Object *ob, float forcetime, int mode, float *err) +{ + /* time evolution */ + /* actually does an explicit euler step mode == 0 */ + /* or heun ~ 2nd order runge-kutta steps, mode 1,2 */ + SoftBody *sb= ob->soft; /* is supposed to be there */ + BodyPoint *bp; + float dx[3],dv[3],aabbmin[3],aabbmax[3],cm[3]={0.0f,0.0f,0.0f}; + float timeovermass; + float maxerrpos= 0.0f,maxerrvel = 0.0f; + int a,fuzzy=0; + + forcetime *= sb_time_scale(ob); + + aabbmin[0]=aabbmin[1]=aabbmin[2] = 1e20f; + aabbmax[0]=aabbmax[1]=aabbmax[2] = -1e20f; + + /* claim a minimum mass for vertex */ + if (sb->nodemass > 0.009999f) timeovermass = forcetime/sb->nodemass; + else timeovermass = forcetime/0.009999f; + + for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { + if(bp->goal < SOFTGOALSNAP){ + + /* so here is (v)' = a(cceleration) = sum(F_springs)/m + gravitation + some friction forces + more forces*/ + /* the ( ... )' operator denotes derivate respective time */ + /* the euler step for velocity then becomes */ + /* v(t + dt) = v(t) + a(t) * dt */ + bp->force[0]*= timeovermass; /* individual mass of node here */ + bp->force[1]*= timeovermass; + bp->force[2]*= timeovermass; + /* some nasty if's to have heun in here too */ + VECCOPY(dv,bp->force); + + if (mode == 1){ + VECCOPY(bp->prevvec, bp->vec); + VECCOPY(bp->prevdv, dv); + } + + if (mode ==2){ + /* be optimistic and execute step */ + bp->vec[0] = bp->prevvec[0] + 0.5f * (dv[0] + bp->prevdv[0]); + bp->vec[1] = bp->prevvec[1] + 0.5f * (dv[1] + bp->prevdv[1]); + bp->vec[2] = bp->prevvec[2] + 0.5f * (dv[2] + bp->prevdv[2]); + /* compare euler to heun to estimate error for step sizing */ + maxerrvel = MAX2(maxerrvel,ABS(dv[0] - bp->prevdv[0])); + maxerrvel = MAX2(maxerrvel,ABS(dv[1] - bp->prevdv[1])); + maxerrvel = MAX2(maxerrvel,ABS(dv[2] - bp->prevdv[2])); + } + else {VECADD(bp->vec, bp->vec, bp->force);} + + /* so here is (x)'= v(elocity) */ + /* the euler step for location then becomes */ + /* x(t + dt) = x(t) + v(t) * dt */ + + VECCOPY(dx,bp->vec); + dx[0]*=forcetime; + dx[1]*=forcetime; + dx[2]*=forcetime; + /* again some nasty if's to have heun in here too */ + if (mode ==1){ + VECCOPY(bp->prevpos,bp->pos); + VECCOPY(bp->prevdx ,dx); + } + + if (mode ==2){ + bp->pos[0] = bp->prevpos[0] + 0.5f * ( dx[0] + bp->prevdx[0]); + bp->pos[1] = bp->prevpos[1] + 0.5f * ( dx[1] + bp->prevdx[1]); + bp->pos[2] = bp->prevpos[2] + 0.5f* ( dx[2] + bp->prevdx[2]); + maxerrpos = MAX2(maxerrpos,ABS(dx[0] - bp->prevdx[0])); + maxerrpos = MAX2(maxerrpos,ABS(dx[1] - bp->prevdx[1])); + maxerrpos = MAX2(maxerrpos,ABS(dx[2] - bp->prevdx[2])); + +/* bp->choke is set when we need to pull a vertex or edge out of the collider. + the collider object signals to get out by pushing hard. on the other hand + we don't want to end up in deep space so we add some + to balance that out */ + if (bp->choke > 0.0f){ + bp->vec[0] = bp->vec[0]*(1.0f - bp->choke); + bp->vec[1] = bp->vec[1]*(1.0f - bp->choke); + bp->vec[2] = bp->vec[2]*(1.0f - bp->choke); + } + + } + else { VECADD(bp->pos, bp->pos, dx);} + }/*snap*/ + /* so while we are looping BPs anyway do statistics on the fly */ + aabbmin[0] = MIN2(aabbmin[0],bp->pos[0]); + aabbmin[1] = MIN2(aabbmin[1],bp->pos[1]); + aabbmin[2] = MIN2(aabbmin[2],bp->pos[2]); + aabbmax[0] = MAX2(aabbmax[0],bp->pos[0]); + aabbmax[1] = MAX2(aabbmax[1],bp->pos[1]); + aabbmax[2] = MAX2(aabbmax[2],bp->pos[2]); + if (bp->flag & SBF_DOFUZZY) fuzzy =1; + } /*for*/ + + if (sb->totpoint) VecMulf(cm,1.0f/sb->totpoint); + if (sb->scratch){ + VECCOPY(sb->scratch->aabbmin,aabbmin); + VECCOPY(sb->scratch->aabbmax,aabbmax); + } + + if (err){ /* so step size will be controlled by biggest difference in slope */ + if (sb->solverflags & SBSO_OLDERR) + *err = MAX2(maxerrpos,maxerrvel); + else + *err = maxerrpos; + //printf("EP %f EV %f \n",maxerrpos,maxerrvel); + if (fuzzy){ + *err /= sb->fuzzyness; + } + } +} + +/* used by heun when it overshoots */ +static void softbody_restore_prev_step(Object *ob) +{ + SoftBody *sb= ob->soft; /* is supposed to be there*/ + BodyPoint *bp; + int a; + + for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { + VECCOPY(bp->vec, bp->prevvec); + VECCOPY(bp->pos, bp->prevpos); + } +} + +/* care for bodypoints taken out of the 'ordinary' solver step +** because they are screwed to goal by bolts +** they just need to move along with the goal in time +** we need to adjust them on sub frame timing in solver +** so now when frame is done .. put 'em to the position at the end of frame +*/ +static void softbody_apply_goalsnap(Object *ob) +{ + SoftBody *sb= ob->soft; /* is supposed to be there */ + BodyPoint *bp; + int a; + + for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { + if (bp->goal >= SOFTGOALSNAP){ + VECCOPY(bp->prevpos,bp->pos); + VECCOPY(bp->pos,bp->origT); + } + } +} + +/* expects full initialized softbody */ +static void interpolate_exciter(Object *ob, int timescale, int time) +{ + SoftBody *sb= ob->soft; + BodyPoint *bp; + float f; + int a; + + f = (float)time/(float)timescale; + + for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { + bp->origT[0] = bp->origS[0] + f*(bp->origE[0] - bp->origS[0]); + bp->origT[1] = bp->origS[1] + f*(bp->origE[1] - bp->origS[1]); + bp->origT[2] = bp->origS[2] + f*(bp->origE[2] - bp->origS[2]); + if (bp->goal >= SOFTGOALSNAP){ + bp->vec[0] = bp->origE[0] - bp->origS[0]; + bp->vec[1] = bp->origE[1] - bp->origS[1]; + bp->vec[2] = bp->origE[2] - bp->origS[2]; + } + } + +} + + +/* ************ convertors ********** */ + +/* for each object type we need; + - xxxx_to_softbody(Object *ob) : a full (new) copy, creates SB geometry +*/ + +static void get_scalar_from_vertexgroup(Object *ob, int vertID, short groupindex, float *target) +/* result 0 on success, else indicates error number +-- kind of *inverse* result defintion, +-- but this way we can signal error condition to caller +-- and yes this function must not be here but in a *vertex group module* +*/ +{ + MDeformVert *dv= NULL; + int i; + + /* spot the vert in deform vert list at mesh */ + if(ob->type==OB_MESH) { + Mesh *me= ob->data; + if (me->dvert) + dv = me->dvert + vertID; + } + else if(ob->type==OB_LATTICE) { /* not yet supported in softbody btw */ + Lattice *lt= ob->data; + if (lt->dvert) + dv = lt->dvert + vertID; + } + if(dv) { + /* Lets see if this vert is in the weight group */ + for (i=0; itotweight; i++){ + if (dv->dw[i].def_nr == groupindex){ + *target= dv->dw[i].weight; /* got it ! */ + break; + } + } + } +} + +/* Resetting a Mesh SB object's springs */ +/* Spring lenght are caculted from'raw' mesh vertices that are NOT altered by modifier stack. */ +static void springs_from_mesh(Object *ob) +{ + SoftBody *sb; + Mesh *me= ob->data; + BodyPoint *bp; + int a; + float scale =1.0f; + + sb= ob->soft; + if (me && sb) + { + /* using bp->origS as a container for spring calcualtions here + ** will be overwritten sbObjectStep() to receive + ** actual modifier stack positions + */ + if(me->totvert) { + bp= ob->soft->bpoint; + for(a=0; atotvert; a++, bp++) { + VECCOPY(bp->origS, me->mvert[a].co); + Mat4MulVecfl(ob->obmat, bp->origS); + } + + } + /* recalculate spring length for meshes here */ + /* special hidden feature! shrink to fit */ + if (G.rt > 500){ + scale = (G.rt - 500) / 100.0f; + } + for(a=0; atotspring; a++) { + BodySpring *bs = &sb->bspring[a]; + bs->len= scale*VecLenf(sb->bpoint[bs->v1].origS, sb->bpoint[bs->v2].origS); + } + } +} + + +/* makes totally fresh start situation */ +static void mesh_to_softbody(Object *ob) +{ + SoftBody *sb; + Mesh *me= ob->data; + MEdge *medge= me->medge; + BodyPoint *bp; + BodySpring *bs; + float goalfac; + int a, totedge; + if (ob->softflag & OB_SB_EDGES) totedge= me->totedge; + else totedge= 0; + + /* renew ends with ob->soft with points and edges, also checks & makes ob->soft */ + renew_softbody(ob, me->totvert, totedge); + + /* we always make body points */ + sb= ob->soft; + bp= sb->bpoint; + goalfac= ABS(sb->maxgoal - sb->mingoal); + + for(a=0; atotvert; a++, bp++) { + /* get scalar values needed *per vertex* from vertex group functions, + so we can *paint* them nicly .. + they are normalized [0.0..1.0] so may be we need amplitude for scale + which can be done by caller but still .. i'd like it to go this way + */ + + if((ob->softflag & OB_SB_GOAL) && sb->vertgroup) { + get_scalar_from_vertexgroup(ob, a,(short) (sb->vertgroup-1), &bp->goal); + /* do this always, regardless successfull read from vertex group */ + bp->goal= sb->mingoal + bp->goal*goalfac; + } + /* a little ad hoc changing the goal control to be less *sharp* */ + bp->goal = (float)pow(bp->goal, 4.0f); + + /* to proove the concept + this would enable per vertex *mass painting* + strcpy(name,"SOFTMASS"); + error = get_scalar_from_named_vertexgroup(ob,name, a,&temp); + if (!error) bp->mass = temp * ob->rangeofmass; + */ + } + + /* but we only optionally add body edge springs */ + if (ob->softflag & OB_SB_EDGES) { + if(medge) { + bs= sb->bspring; + for(a=me->totedge; a>0; a--, medge++, bs++) { + bs->v1= medge->v1; + bs->v2= medge->v2; + bs->strength= 1.0; + bs->order=1; + } + + + /* insert *diagonal* springs in quads if desired */ + if (ob->softflag & OB_SB_QUADS) { + add_mesh_quad_diag_springs(ob); + } + + build_bps_springlist(ob); /* scan for springs attached to bodypoints ONCE */ + /* insert *other second order* springs if desired */ + if (sb->secondspring > 0.0000001f) { + add_2nd_order_springs(ob,sb->secondspring); /* exploits the the first run of build_bps_springlist(ob);*/ + build_bps_springlist(ob); /* yes we need to do it again*/ + } + springs_from_mesh(ob); /* write the 'rest'-lenght of the springs */ + if (ob->softflag & OB_SB_SELF) {calculate_collision_balls(ob);} + + } + + } + +} + +static void mesh_faces_to_scratch(Object *ob) +{ + SoftBody *sb= ob->soft; + Mesh *me= ob->data; + MFace *mface; + BodyFace *bodyface; + int a; + /* alloc and copy faces*/ + + bodyface = sb->scratch->bodyface = MEM_mallocN(sizeof(BodyFace)*me->totface,"SB_body_Faces"); + //memcpy(sb->scratch->mface,me->mface,sizeof(MFace)*me->totface); + mface = me->mface; + for(a=0; atotface; a++, mface++, bodyface++) { + bodyface->v1 = mface->v1; + bodyface->v2 = mface->v2; + bodyface->v3 = mface->v3; + bodyface->v4 = mface->v4; + bodyface->ext_force[0] = bodyface->ext_force[1] = bodyface->ext_force[2] = 0.0f; + bodyface->flag =0; + } + sb->scratch->totface = me->totface; +} + +/* +helper function to get proper spring length +when object is rescaled +*/ +float globallen(float *v1,float *v2,Object *ob) +{ + float p1[3],p2[3]; + VECCOPY(p1,v1); + Mat4MulVecfl(ob->obmat, p1); + VECCOPY(p2,v2); + Mat4MulVecfl(ob->obmat, p2); + return VecLenf(p1,p2); +} + +static void makelatticesprings(Lattice *lt, BodySpring *bs, int dostiff,Object *ob) +{ + BPoint *bp=lt->def, *bpu; + int u, v, w, dv, dw, bpc=0, bpuc; + + dv= lt->pntsu; + dw= dv*lt->pntsv; + + for(w=0; wpntsw; w++) { + + for(v=0; vpntsv; v++) { + + for(u=0, bpuc=0, bpu=NULL; upntsu; u++, bp++, bpc++) { + + if(w) { + bs->v1 = bpc; + bs->v2 = bpc-dw; + bs->strength= 1.0; + bs->order=1; + bs->len= globallen((bp-dw)->vec, bp->vec,ob); + bs++; + } + if(v) { + bs->v1 = bpc; + bs->v2 = bpc-dv; + bs->strength= 1.0; + bs->order=1; + bs->len= globallen((bp-dv)->vec, bp->vec,ob); + bs++; + } + if(u) { + bs->v1 = bpuc; + bs->v2 = bpc; + bs->strength= 1.0; + bs->order=1; + bs->len= globallen((bpu)->vec, bp->vec,ob); + bs++; + } + + if (dostiff) { + + if(w){ + if( v && u ) { + bs->v1 = bpc; + bs->v2 = bpc-dw-dv-1; + bs->strength= 1.0; + bs->order=2; + bs->len= globallen((bp-dw-dv-1)->vec, bp->vec,ob); + bs++; + } + if( (v < lt->pntsv-1) && (u) ) { + bs->v1 = bpc; + bs->v2 = bpc-dw+dv-1; + bs->strength= 1.0; + bs->order=2; + bs->len= globallen((bp-dw+dv-1)->vec, bp->vec,ob); + bs++; + } + } + + if(w < lt->pntsw -1){ + if( v && u ) { + bs->v1 = bpc; + bs->v2 = bpc+dw-dv-1; + bs->strength= 1.0; + bs->order=2; + bs->len= globallen((bp+dw-dv-1)->vec, bp->vec,ob); + bs++; + } + if( (v < lt->pntsv-1) && (u) ) { + bs->v1 = bpc; + bs->v2 = bpc+dw+dv-1; + bs->strength= 1.0; + bs->order=2; + bs->len= globallen((bp+dw+dv-1)->vec, bp->vec,ob); + bs++; + } + } + } + bpu = bp; + bpuc = bpc; + } + } + } +} + + +/* makes totally fresh start situation */ +static void lattice_to_softbody(Object *ob) +{ + Lattice *lt= ob->data; + SoftBody *sb; + int totvert, totspring = 0; + + totvert= lt->pntsu*lt->pntsv*lt->pntsw; + + if (ob->softflag & OB_SB_EDGES){ + totspring = ((lt->pntsu -1) * lt->pntsv + + (lt->pntsv -1) * lt->pntsu) * lt->pntsw + +lt->pntsu*lt->pntsv*(lt->pntsw -1); + if (ob->softflag & OB_SB_QUADS){ + totspring += 4*(lt->pntsu -1) * (lt->pntsv -1) * (lt->pntsw-1); + } + } + + + /* renew ends with ob->soft with points and edges, also checks & makes ob->soft */ + renew_softbody(ob, totvert, totspring); + sb= ob->soft; /* can be created in renew_softbody() */ + + /* weights from bpoints, same code used as for mesh vertices */ + if((ob->softflag & OB_SB_GOAL) && sb->vertgroup) { + BodyPoint *bp= sb->bpoint; + BPoint *bpnt= lt->def; + float goalfac= ABS(sb->maxgoal - sb->mingoal); + int a; + + for(a=0; agoal= sb->mingoal + bpnt->weight*goalfac; + /* a little ad hoc changing the goal control to be less *sharp* */ + bp->goal = (float)pow(bp->goal, 4.0f); + } + } + + /* create some helper edges to enable SB lattice to be usefull at all */ + if (ob->softflag & OB_SB_EDGES){ + makelatticesprings(lt,ob->soft->bspring,ob->softflag & OB_SB_QUADS,ob); + build_bps_springlist(ob); /* link bps to springs */ + } +} + +/* makes totally fresh start situation */ +static void curve_surf_to_softbody(Object *ob) +{ + Curve *cu= ob->data; + SoftBody *sb; + BodyPoint *bp; + BodySpring *bs; + Nurb *nu; + BezTriple *bezt; + BPoint *bpnt; + float goalfac; + int a, curindex=0; + int totvert, totspring = 0, setgoal=0; + + totvert= count_curveverts(&cu->nurb); + + if (ob->softflag & OB_SB_EDGES){ + if(ob->type==OB_CURVE) { + totspring= totvert - BLI_countlist(&cu->nurb); + } + } + + /* renew ends with ob->soft with points and edges, also checks & makes ob->soft */ + renew_softbody(ob, totvert, totspring); + sb= ob->soft; /* can be created in renew_softbody() */ + + /* set vars now */ + goalfac= ABS(sb->maxgoal - sb->mingoal); + bp= sb->bpoint; + bs= sb->bspring; + + /* weights from bpoints, same code used as for mesh vertices */ + if((ob->softflag & OB_SB_GOAL) && sb->vertgroup) + setgoal= 1; + + for(nu= cu->nurb.first; nu; nu= nu->next) { + if(nu->bezt) { + for(bezt=nu->bezt, a=0; apntsu; a++, bezt++, bp+=3, curindex+=3) { + if(setgoal) { + bp->goal= sb->mingoal + bezt->weight*goalfac; + /* a little ad hoc changing the goal control to be less *sharp* */ + bp->goal = (float)pow(bp->goal, 4.0f); + + /* all three triples */ + (bp+1)->goal= bp->goal; + (bp+2)->goal= bp->goal; + } + + if(totspring) { + if(a>0) { + bs->v1= curindex-1; + bs->v2= curindex; + bs->strength= 1.0; + bs->order=1; + bs->len= globallen( (bezt-1)->vec[2], bezt->vec[0], ob ); + bs++; + } + bs->v1= curindex; + bs->v2= curindex+1; + bs->strength= 1.0; + bs->order=1; + bs->len= globallen( bezt->vec[0], bezt->vec[1], ob ); + bs++; + + bs->v1= curindex+1; + bs->v2= curindex+2; + bs->strength= 1.0; + bs->order=1; + bs->len= globallen( bezt->vec[1], bezt->vec[2], ob ); + bs++; + } + } + } + else { + for(bpnt=nu->bp, a=0; apntsu*nu->pntsv; a++, bpnt++, bp++, curindex++) { + if(setgoal) { + bp->goal= sb->mingoal + bpnt->weight*goalfac; + /* a little ad hoc changing the goal control to be less *sharp* */ + bp->goal = (float)pow(bp->goal, 4.0f); + } + if(totspring && a>0) { + bs->v1= curindex-1; + bs->v2= curindex; + bs->strength= 1.0; + bs->order=1; + bs->len= globallen( (bpnt-1)->vec, bpnt->vec , ob ); + bs++; + } + } + } + } + + if(totspring) + { + build_bps_springlist(ob); /* link bps to springs */ + if (ob->softflag & OB_SB_SELF) {calculate_collision_balls(ob);} + } +} + + +/* copies softbody result back in object */ +static void softbody_to_object(Object *ob, float (*vertexCos)[3], int numVerts, int local) +{ + BodyPoint *bp= ob->soft->bpoint; + int a; + + /* inverse matrix is not uptodate... */ + Mat4Invert(ob->imat, ob->obmat); + + for(a=0; apos); + if(local==0) + Mat4MulVecfl(ob->imat, vertexCos[a]); /* softbody is in global coords, baked optionally not */ + } +} + +/* return 1 if succesfully baked and applied step */ +static int softbody_baked_step(Object *ob, float framenr, float (*vertexCos)[3], int numVerts) +{ + SoftBody *sb= ob->soft; + SBVertex *key0, *key1, *key2, *key3; + BodyPoint *bp; + float data[4], sfra, efra, cfra, dfra, fac; /* start, end, current, delta */ + int ofs1, a; + + /* precondition check */ + if(sb==NULL || sb->keys==NULL || sb->totkey==0) return 0; + /* so we got keys, but no bodypoints... even without simul we need it for the bake */ + if(sb->bpoint==NULL) sb->bpoint= MEM_callocN( sb->totpoint*sizeof(BodyPoint), "bodypoint"); + + /* convert cfra time to system time */ + sfra= (float)sb->sfra; + cfra= bsystem_time(ob, framenr, 0.0); + efra= (float)sb->efra; + dfra= (float)sb->interval; + + /* offset in keys array */ + ofs1= (int)floor( (cfra-sfra)/dfra ); + + if(ofs1 < 0) { + key0=key1=key2=key3= *sb->keys; + } + else if(ofs1 >= sb->totkey-1) { + key0=key1=key2=key3= *(sb->keys+sb->totkey-1); + } + else { + key1= *(sb->keys+ofs1); + key2= *(sb->keys+ofs1+1); + + if(ofs1>0) key0= *(sb->keys+ofs1-1); + else key0= key1; + + if(ofs1totkey-2) key3= *(sb->keys+ofs1+2); + else key3= key2; + } + + sb->ctime= cfra; /* needed? */ + + /* timing */ + fac= ((cfra-sfra)/dfra) - (float)ofs1; + CLAMP(fac, 0.0, 1.0); + set_four_ipo(fac, data, KEY_BSPLINE); + if (key0&&key1&&key2&&key3) // may be null because we SHIFT_ESCAPED + for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++, key0++, key1++, key2++, key3++) { + bp->pos[0]= data[0]*key0->vec[0] + data[1]*key1->vec[0] + data[2]*key2->vec[0] + data[3]*key3->vec[0]; + bp->pos[1]= data[0]*key0->vec[1] + data[1]*key1->vec[1] + data[2]*key2->vec[1] + data[3]*key3->vec[1]; + bp->pos[2]= data[0]*key0->vec[2] + data[1]*key1->vec[2] + data[2]*key2->vec[2] + data[3]*key3->vec[2]; + } + + softbody_to_object(ob, vertexCos, numVerts, sb->local); + + return 1; +} + +/* only gets called after succesfully doing softbody_step */ +/* already checked for OB_SB_BAKE flag */ +static void softbody_baked_add(Object *ob, float framenr) +{ + SoftBody *sb= ob->soft; + SBVertex *key; + BodyPoint *bp; + float sfra, efra, cfra, dfra, fac1; /* start, end, current, delta */ + int ofs1, a; + + /* convert cfra time to system time */ + sfra= (float)sb->sfra; + fac1= ob->sf; ob->sf= 0.0f; /* disable startframe */ + cfra= bsystem_time(ob, framenr, 0.0); + ob->sf= fac1; + efra= (float)sb->efra; + dfra= (float)sb->interval; + + if(sb->totkey==0) { + if(sb->sfra >= sb->efra) return; /* safety, UI or py setting allows */ + if(sb->interval<1) sb->interval= 1; /* just be sure */ + + sb->totkey= 1 + (int)(ceil( (efra-sfra)/dfra ) ); + sb->keys= MEM_callocN( sizeof(void *)*sb->totkey, "sb keys"); + } + + /* inverse matrix might not be uptodate... */ + Mat4Invert(ob->imat, ob->obmat); + + /* now find out if we have to store a key */ + + /* offset in keys array */ + if(cfra>=(efra)) { + ofs1= sb->totkey-1; + fac1= 0.0; + } + else { + ofs1= (int)floor( (cfra-sfra)/dfra ); + fac1= ((cfra-sfra)/dfra) - (float)ofs1; + } + if( fac1 < 1.0/dfra ) { + + key= *(sb->keys+ofs1); + if(key == NULL) { + *(sb->keys+ofs1)= key= MEM_mallocN(sb->totpoint*sizeof(SBVertex), "softbody key"); + + for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++, key++) { + VECCOPY(key->vec, bp->pos); + if(sb->local) + Mat4MulVecfl(ob->imat, key->vec); + } + } + } +} +/* +++ ************ maintaining scratch *************** */ +void sb_new_scratch(SoftBody *sb) +{ + if (!sb) return; + sb->scratch = MEM_callocN(sizeof(SBScratch), "SBScratch"); + sb->scratch->colliderhash = BLI_ghash_new(BLI_ghashutil_ptrhash,BLI_ghashutil_ptrcmp); + sb->scratch->bodyface = NULL; + sb->scratch->totface = 0; + sb->scratch->aabbmax[0]=sb->scratch->aabbmax[1]=sb->scratch->aabbmax[2] = 1.0e30f; + sb->scratch->aabbmin[0]=sb->scratch->aabbmin[1]=sb->scratch->aabbmin[2] = -1.0e30f; + +} +/* --- ************ maintaining scratch *************** */ + +/* ************ Object level, exported functions *************** */ + +/* allocates and initializes general main data */ +SoftBody *sbNew(void) +{ + SoftBody *sb; + + sb= MEM_callocN(sizeof(SoftBody), "softbody"); + + sb->mediafrict= 0.5f; + sb->nodemass= 1.0f; + sb->grav= 9.8f; + sb->physics_speed= 1.0f; + sb->rklimit= 0.1f; + + sb->goalspring= 0.5f; + sb->goalfrict= 0.0f; + sb->mingoal= 0.0f; + sb->maxgoal= 1.0f; + sb->defgoal= 0.7f; + + sb->inspring= 0.5f; + sb->infrict= 0.5f; + + sb->interval= 10; + sb->sfra= G.scene->r.sfra; + sb->efra= G.scene->r.efra; + + sb->colball = 0.49f; + sb->balldamp = 0.50f; + sb->ballstiff= 1.0f; + sb->sbc_mode = 1; + + + sb->minloops = 10; + + sb->choke = 3; + sb_new_scratch(sb); + return sb; +} + +/* frees all */ +void sbFree(SoftBody *sb) +{ + free_softbody_intern(sb); + MEM_freeN(sb); +} + + +/* makes totally fresh start situation */ +void sbObjectToSoftbody(Object *ob) +{ + ob->softflag |= OB_SB_REDO; + + free_softbody_intern(ob->soft); +} + +static int object_has_edges(Object *ob) +{ + if(ob->type==OB_MESH) { + return ((Mesh*) ob->data)->totedge; + } + else if(ob->type==OB_LATTICE) { + return 1; + } + else { + return 0; + } +} + +/* SB global visible functions */ +void sbSetInterruptCallBack(int (*f)(void)) +{ + SB_localInterruptCallBack = f; +} + + +/* simulates one step. framenr is in frames */ +void sbObjectStep(Object *ob, float framenr, float (*vertexCos)[3], int numVerts) +{ + SoftBody *sb; + BodyPoint *bp; + int a; + float dtime,ctime,forcetime,err; + + /* baking works with global time */ + if(!(ob->softflag & OB_SB_BAKEDO) ) + if(softbody_baked_step(ob, framenr, vertexCos, numVerts) ) return; + + + /* This part only sets goals and springs, based on original mesh/curve/lattice data. + Copying coordinates happens in next chunk by setting softbody flag OB_SB_RESET */ + /* remake softbody if: */ + if( (ob->softflag & OB_SB_REDO) || /* signal after weightpainting */ + (ob->soft==NULL) || /* just to be nice we allow full init */ + (ob->soft->bpoint==NULL) || /* after reading new file, or acceptable as signal to refresh */ + (numVerts!=ob->soft->totpoint) || /* should never happen, just to be safe */ + ((ob->softflag & OB_SB_EDGES) && !ob->soft->bspring && object_has_edges(ob))) /* happens when in UI edges was set */ + { + switch(ob->type) { + case OB_MESH: + mesh_to_softbody(ob); + break; + case OB_LATTICE: + lattice_to_softbody(ob); + break; + case OB_CURVE: + case OB_SURF: + curve_surf_to_softbody(ob); + break; + default: + renew_softbody(ob, numVerts, 0); + break; + } + + /* still need to update to correct vertex locations, happens on next step */ + ob->softflag |= OB_SB_RESET; + ob->softflag &= ~OB_SB_REDO; + } + + sb= ob->soft; + + /* still no points? go away */ + if(sb->totpoint==0) return; + + + /* checking time: */ + + ctime= bsystem_time(ob, framenr, 0.0); + + if (ob->softflag&OB_SB_RESET) { + dtime = 0.0; + } else { + dtime= ctime - sb->ctime; + } + + /* the simulator */ + + /* update the vertex locations */ + if (dtime!=0.0) { + for(a=0,bp=sb->bpoint; aorigS, bp->origE); + /* copy the position of the goals at desired end time */ + VECCOPY(bp->origE, vertexCos[a]); + /* vertexCos came from local world, go global */ + Mat4MulVecfl(ob->obmat, bp->origE); + /* just to be save give bp->origT a defined value + will be calulated in interpolate_exciter()*/ + VECCOPY(bp->origT, bp->origE); + } + } + + if((ob->softflag&OB_SB_RESET) || /* got a reset signal */ + (dtime<0.0) || /* back in time */ + (dtime>=9.9*G.scene->r.framelen) /* too far forward in time --> goals won't be accurate enough */ + ) + { + for(a=0,bp=sb->bpoint; apos, vertexCos[a]); + Mat4MulVecfl(ob->obmat, bp->pos); /* yep, sofbody is global coords*/ + VECCOPY(bp->origS, bp->pos); + VECCOPY(bp->origE, bp->pos); + VECCOPY(bp->origT, bp->pos); + bp->vec[0]= bp->vec[1]= bp->vec[2]= 0.0f; + + /* the bp->prev*'s are for rolling back from a canceled try to propagate in time + adaptive step size algo in a nutshell: + 1. set sheduled time step to new dtime + 2. try to advance the sheduled time step, beeing optimistic execute it + 3. check for success + 3.a we 're fine continue, may be we can increase sheduled time again ?? if so, do so! + 3.b we did exceed error limit --> roll back, shorten the sheduled time and try again at 2. + 4. check if we did reach dtime + 4.a nope we need to do some more at 2. + 4.b yup we're done + */ + + VECCOPY(bp->prevpos, bp->pos); + VECCOPY(bp->prevvec, bp->vec); + VECCOPY(bp->prevdx, bp->vec); + VECCOPY(bp->prevdv, bp->vec); + } + /* make a nice clean scratch struc */ + free_scratch(sb); /* clear if any */ + sb_new_scratch(sb); /* make a new */ + sb->scratch->needstobuildcollider=1; + + + /* copy some info to scratch */ + switch(ob->type) { + case OB_MESH: + if (ob->softflag & OB_SB_FACECOLL) mesh_faces_to_scratch(ob); + break; + case OB_LATTICE: + break; + case OB_CURVE: + case OB_SURF: + break; + default: + break; + } + + + + ob->softflag &= ~OB_SB_RESET; + } + else if(dtime>0.0) { + double sct,sst=PIL_check_seconds_timer(); + ccd_update_deflector_hache(ob,sb->scratch->colliderhash); + + + if(sb->scratch->needstobuildcollider){ + if (query_external_colliders(ob)){ + ccd_build_deflector_hache(ob,sb->scratch->colliderhash); + } + sb->scratch->needstobuildcollider=0; + } + + + if (TRUE) { /* */ + /* special case of 2nd order Runge-Kutta type AKA Heun */ + float forcetimemax = 1.0f; + float forcetimemin = 0.001f; + float timedone =0.0; /* how far did we get without violating error condition */ + /* loops = counter for emergency brake + * we don't want to lock up the system if physics fail + */ + int loops =0 ; + SoftHeunTol = sb->rklimit; /* humm .. this should be calculated from sb parameters and sizes */ + if (sb->minloops > 0) forcetimemax = 1.0f / sb->minloops; + + if (sb->maxloops > 0) forcetimemin = 1.0f / sb->maxloops; + + + //forcetime = dtime; /* hope for integrating in one step */ + forcetime =forcetimemax; /* hope for integrating in one step */ + while ( (ABS(timedone) < ABS(dtime)) && (loops < 2000) ) + { + /* set goals in time */ + interpolate_exciter(ob,200,(int)(200.0*(timedone/dtime))); + + sb->scratch->flag &= ~SBF_DOFUZZY; + /* do predictive euler step */ + softbody_calc_forces(ob, forcetime,timedone/dtime); + softbody_apply_forces(ob, forcetime, 1, NULL); + + + /* crop new slope values to do averaged slope step */ + softbody_calc_forces(ob, forcetime,timedone/dtime); + softbody_apply_forces(ob, forcetime, 2, &err); + + softbody_apply_goalsnap(ob); + + if (err > SoftHeunTol) { /* error needs to be scaled to some quantity */ + + if (forcetime > forcetimemin){ + forcetime = MAX2(forcetime / 2.0f,forcetimemin); + softbody_restore_prev_step(ob); + //printf("down,"); + } + else { + timedone += forcetime; + } + } + else { + float newtime = forcetime * 1.1f; /* hope for 1.1 times better conditions in next step */ + + if (sb->scratch->flag & SBF_DOFUZZY){ + //if (err > SoftHeunTol/(2.0f*sb->fuzzyness)) { /* stay with this stepsize unless err really small */ + newtime = forcetime; + //} + } + else { + if (err > SoftHeunTol/2.0f) { /* stay with this stepsize unless err really small */ + newtime = forcetime; + } + } + timedone += forcetime; + newtime=MIN2(forcetimemax,MAX2(newtime,forcetimemin)); + //if (newtime > forcetime) printf("up,"); + if (forcetime > 0.0) + forcetime = MIN2(dtime - timedone,newtime); + else + forcetime = MAX2(dtime - timedone,newtime); + } + loops++; + if(sb->solverflags & SBSO_MONITOR ){ + sct=PIL_check_seconds_timer(); + if (sct-sst > 0.5f) printf("%3.0f%% \r",100.0f*timedone); + } + if (SB_localInterruptCallBack && SB_localInterruptCallBack()) break; + + } + /* move snapped to final position */ + interpolate_exciter(ob, 2, 2); + softbody_apply_goalsnap(ob); + + // if(G.f & G_DEBUG){ + if(sb->solverflags & SBSO_MONITOR ){ + if (loops > HEUNWARNLIMIT) /* monitor high loop counts */ + printf("\r needed %d steps/frame ",loops); + } + + } + else{ + /* do brute force explicit euler */ + /* removed but left this branch for better integrators / solvers (BM) */ + /* yah! Nicholas Guttenberg (NichG) here is the place to plug in */ + } + if(sb->solverflags & SBSO_MONITOR ){ + sct=PIL_check_seconds_timer(); + if (sct-sst > 0.5f) printf(" solver time %f %s \r",sct-sst,ob->id.name); + } + } + + softbody_to_object(ob, vertexCos, numVerts, 0); + sb->ctime= ctime; + + + if(ob->softflag & OB_SB_BAKEDO) softbody_baked_add(ob, framenr); +} + diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c new file mode 100644 index 00000000000..3b14cb8adac --- /dev/null +++ b/source/blender/blenkernel/intern/sound.c @@ -0,0 +1,138 @@ +/** + * sound.c (mar-2001 nzc) + * + * $Id$ + */ + +#include +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" + +#include "DNA_scene_types.h" +#include "DNA_sound_types.h" +#include "DNA_packedFile_types.h" + +#include "BKE_utildefines.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_sound.h" +#include "BKE_packedFile.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +ListBase _samples = {0,0}, *samples = &_samples; + +void sound_free_sound(bSound *sound) +{ + /* when sounds have been loaded, but not played, the packedfile was not copied + to sample block and not freed otherwise */ + if(sound->sample==NULL) { + if (sound->newpackedfile) { + freePackedFile(sound->newpackedfile); + sound->newpackedfile = NULL; + } + } + if (sound->stream) free(sound->stream); +} + +void sound_free_sample(bSample *sample) +{ + if (sample) { + if (sample->data != &sample->fakedata[0] && sample->data != NULL) { + MEM_freeN(sample->data); + sample->data = &sample->fakedata[0]; + } + + if (sample->packedfile) { + freePackedFile(sample->packedfile); //FIXME: crashes sometimes + sample->packedfile = NULL; + } + + if (sample->alindex != SAMPLE_INVALID) { +// AUD_free_sample(sample->snd_sample); + sample->alindex = SAMPLE_INVALID; + } + + sample->type = SAMPLE_INVALID; + } +} + +/* this is called after file reading or undos */ +void sound_free_all_samples(void) +{ + bSample *sample; + bSound *sound; + + /* ensure no sample pointers exist, and check packedfile */ + for(sound= G.main->sound.first; sound; sound= sound->id.next) { + if(sound->sample && sound->sample->packedfile==sound->newpackedfile) + sound->newpackedfile= NULL; + sound->sample= NULL; + } + + /* now free samples */ + for(sample= samples->first; sample; sample= sample->id.next) + sound_free_sample(sample); + BLI_freelistN(samples); + +} + +void sound_set_packedfile(bSample *sample, PackedFile *pf) +{ + bSound *sound; + + if (sample) { + sample->packedfile = pf; + sound = G.main->sound.first; + while (sound) { + if (sound->sample == sample) { + sound->newpackedfile = pf; + if (pf == NULL) { + strcpy(sound->name, sample->name); + } + } + sound = sound->id.next; + } + } +} + +PackedFile* sound_find_packedfile(bSound *sound) +{ + bSound *search; + PackedFile *pf = NULL; + char soundname[FILE_MAXDIR + FILE_MAXFILE], searchname[FILE_MAXDIR + FILE_MAXFILE]; + + // convert sound->name to abolute filename + strcpy(soundname, sound->name); + BLI_convertstringcode(soundname, G.sce, G.scene->r.cfra); + + search = G.main->sound.first; + while (search) { + if (search->sample && search->sample->packedfile) { + strcpy(searchname, search->sample->name); + BLI_convertstringcode(searchname, G.sce, G.scene->r.cfra); + + if (BLI_streq(searchname, soundname)) { + pf = search->sample->packedfile; + break; + } + } + + if (search->newpackedfile) { + strcpy(searchname, search->name); + BLI_convertstringcode(searchname, G.sce, G.scene->r.cfra); + if (BLI_streq(searchname, soundname)) { + pf = search->newpackedfile; + break; + } + } + search = search->id.next; + } + + return (pf); +} diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c new file mode 100644 index 00000000000..0b1563beced --- /dev/null +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -0,0 +1,2540 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" + +#include "BKE_bad_level_calls.h" +#include "BKE_cdderivedmesh.h" +#include "BKE_customdata.h" +#include "BKE_utildefines.h" +#include "BKE_global.h" +#include "BKE_mesh.h" +#include "BKE_subsurf.h" +#include "BKE_displist.h" +#include "BKE_DerivedMesh.h" + +#include "BLI_blenlib.h" +#include "BLI_editVert.h" +#include "BLI_arithb.h" +#include "BLI_linklist.h" +#include "BLI_memarena.h" +#include "BLI_edgehash.h" + +#include "BIF_gl.h" + +#include "CCGSubSurf.h" + +typedef struct _VertData { + float co[3]; + float no[3]; +} VertData; + +struct CCGDerivedMesh { + DerivedMesh dm; + + CCGSubSurf *ss; + int drawInteriorEdges, useSubsurfUv; + + struct {int startVert; CCGVert *vert;} *vertMap; + struct {int startVert; int startEdge; CCGEdge *edge;} *edgeMap; + struct {int startVert; int startEdge; + int startFace; CCGFace *face;} *faceMap; +}; + +typedef struct CCGDerivedMesh CCGDerivedMesh; + +static int ccgDM_getVertMapIndex(CCGDerivedMesh *ccgdm, CCGSubSurf *ss, CCGVert *v); +static int ccgDM_getEdgeMapIndex(CCGDerivedMesh *ccgdm, CCGSubSurf *ss, CCGEdge *e); +static int ccgDM_getFaceMapIndex(CCGDerivedMesh *ccgdm, CCGSubSurf *ss, CCGFace *f); + +/// + +static void *arena_alloc(CCGAllocatorHDL a, int numBytes) { + return BLI_memarena_alloc(a, numBytes); +} +static void *arena_realloc(CCGAllocatorHDL a, void *ptr, int newSize, int oldSize) { + void *p2 = BLI_memarena_alloc(a, newSize); + if (ptr) { + memcpy(p2, ptr, oldSize); + } + return p2; +} +static void arena_free(CCGAllocatorHDL a, void *ptr) { +} +static void arena_release(CCGAllocatorHDL a) { + BLI_memarena_free(a); +} + +static CCGSubSurf *_getSubSurf(CCGSubSurf *prevSS, int subdivLevels, int useAging, int useArena, int useFlatSubdiv) { + CCGMeshIFC ifc; + CCGSubSurf *ccgSS; + + /* subdivLevels==0 is not allowed */ + subdivLevels = MAX2(subdivLevels, 1); + + if (prevSS) { + int oldUseAging; + + useAging = !!useAging; + ccgSubSurf_getUseAgeCounts(prevSS, &oldUseAging, NULL, NULL, NULL); + + if (oldUseAging!=useAging) { + ccgSubSurf_free(prevSS); + } else { + ccgSubSurf_setSubdivisionLevels(prevSS, subdivLevels); + + return prevSS; + } + } + + if (useAging) { + ifc.vertUserSize = ifc.edgeUserSize = ifc.faceUserSize = 12; + } else { + ifc.vertUserSize = ifc.edgeUserSize = ifc.faceUserSize = 8; + } + ifc.vertDataSize = sizeof(VertData); + + if (useArena) { + CCGAllocatorIFC allocatorIFC; + CCGAllocatorHDL allocator = BLI_memarena_new((1<<16)); + + allocatorIFC.alloc = arena_alloc; + allocatorIFC.realloc = arena_realloc; + allocatorIFC.free = arena_free; + allocatorIFC.release = arena_release; + + ccgSS = ccgSubSurf_new(&ifc, subdivLevels, &allocatorIFC, allocator); + } else { + ccgSS = ccgSubSurf_new(&ifc, subdivLevels, NULL, NULL); + } + + if (useAging) { + ccgSubSurf_setUseAgeCounts(ccgSS, 1, 8, 8, 8); + } + + ccgSubSurf_setCalcVertexNormals(ccgSS, 1, BLI_STRUCT_OFFSET(VertData, no)); + + return ccgSS; +} + +static int getEdgeIndex(CCGSubSurf *ss, CCGEdge *e, int x, int edgeSize) { + CCGVert *v0 = ccgSubSurf_getEdgeVert0(ss, e); + CCGVert *v1 = ccgSubSurf_getEdgeVert1(ss, e); + int v0idx = *((int*) ccgSubSurf_getVertUserData(ss, v0)); + int v1idx = *((int*) ccgSubSurf_getVertUserData(ss, v1)); + int edgeBase = *((int*) ccgSubSurf_getEdgeUserData(ss, e)); + + if (x==0) { + return v0idx; + } else if (x==edgeSize-1) { + return v1idx; + } else { + return edgeBase + x-1; + } +} +static int getFaceIndex(CCGSubSurf *ss, CCGFace *f, int S, int x, int y, int edgeSize, int gridSize) { + int faceBase = *((int*) ccgSubSurf_getFaceUserData(ss, f)); + int numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + + if (x==gridSize-1 && y==gridSize-1) { + CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S); + return *((int*) ccgSubSurf_getVertUserData(ss, v)); + } else if (x==gridSize-1) { + CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S); + CCGEdge *e = ccgSubSurf_getFaceEdge(ss, f, S); + int edgeBase = *((int*) ccgSubSurf_getEdgeUserData(ss, e)); + if (v==ccgSubSurf_getEdgeVert0(ss, e)) { + return edgeBase + (gridSize-1-y)-1; + } else { + return edgeBase + (edgeSize-2-1)-((gridSize-1-y)-1); + } + } else if (y==gridSize-1) { + CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S); + CCGEdge *e = ccgSubSurf_getFaceEdge(ss, f, (S+numVerts-1)%numVerts); + int edgeBase = *((int*) ccgSubSurf_getEdgeUserData(ss, e)); + if (v==ccgSubSurf_getEdgeVert0(ss, e)) { + return edgeBase + (gridSize-1-x)-1; + } else { + return edgeBase + (edgeSize-2-1)-((gridSize-1-x)-1); + } + } else if (x==0 && y==0) { + return faceBase; + } else if (x==0) { + S = (S+numVerts-1)%numVerts; + return faceBase + 1 + (gridSize-2)*S + (y-1); + } else if (y==0) { + return faceBase + 1 + (gridSize-2)*S + (x-1); + } else { + return faceBase + 1 + (gridSize-2)*numVerts + S*(gridSize-2)*(gridSize-2) + (y-1)*(gridSize-2) + (x-1); + } +} + +static void get_face_uv_map_vert(UvVertMap *vmap, struct MFace *mf, int fi, CCGVertHDL *fverts) { + unsigned int *fv = &mf->v1; + UvMapVert *v, *nv; + int j, nverts= mf->v4? 4: 3; + + for (j=0; jnext) { + if (v->separate) + nv= v; + if (v->f == fi) + break; + } + + fverts[j]= (CCGVertHDL)(nv->f*4 + nv->tfindex); + } +} + +static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, MTFace *tface) { + MFace *mface = dm->getFaceArray(dm); + MVert *mvert = dm->getVertArray(dm); + int totvert = dm->getNumVerts(dm); + int totface = dm->getNumFaces(dm); + int i, j, seam; + UvMapVert *v; + UvVertMap *vmap; + float limit[2]; + CCGVertHDL fverts[4]; + EdgeHash *ehash; + float creaseFactor = (float)ccgSubSurf_getSubdivisionLevels(ss); + + limit[0]= limit[1]= 0.0001f; + vmap= make_uv_vert_map(mface, tface, totface, totvert, 0, limit); + if (!vmap) + return 0; + + ccgSubSurf_initFullSync(ss); + + /* create vertices */ + for (i=0; inext; v; v=v->next) + if (v->separate) + break; + + seam = (v != NULL) || ((mvert+i)->flag & ME_VERT_MERGED); + + for (v=get_uv_map_vert(vmap, i); v; v=v->next) { + if (v->separate) { + CCGVert *ssv; + CCGVertHDL vhdl = (CCGVertHDL)(v->f*4 + v->tfindex); + float uv[3]; + + uv[0]= (tface+v->f)->uv[v->tfindex][0]; + uv[1]= (tface+v->f)->uv[v->tfindex][1]; + uv[2]= 0.0f; + + ccgSubSurf_syncVert(ss, vhdl, uv, seam, &ssv); + } + } + } + + /* create edges */ + ehash = BLI_edgehash_new(); + + for (i=0; iv4? 4: 3; + CCGFace *origf= ccgSubSurf_getFace(origss, (CCGFaceHDL)i); + unsigned int *fv = &mf->v1; + + get_face_uv_map_vert(vmap, mf, i, fverts); + + for (j=0; jflag&mv1->flag) & ME_VERT_MERGED) + crease = creaseFactor; + else + crease = ccgSubSurf_getEdgeCrease(origss, orige); + + ccgSubSurf_syncEdge(ss, ehdl, fverts[j], fverts[(j+1)%nverts], crease, &e); + BLI_edgehash_insert(ehash, v0, v1, NULL); + } + } + } + + BLI_edgehash_free(ehash, NULL); + + /* create faces */ + for (i=0; iv4? 4: 3; + CCGFace *f; + + get_face_uv_map_vert(vmap, mf, i, fverts); + ccgSubSurf_syncFace(ss, (CCGFaceHDL)i, nverts, fverts, &f); + } + + free_uv_vert_map(vmap); + ccgSubSurf_processSync(ss); + + return 1; +} + +static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result, int n) +{ + CCGSubSurf *uvss; + CCGFace **faceMap; + MTFace *tf; + CCGFaceIterator *fi; + int index, gridSize, gridFaces, edgeSize, totface, x, y, S; + MTFace *dmtface = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, n); + MTFace *tface = CustomData_get_layer_n(&result->faceData, CD_MTFACE, n); + + if(!dmtface || !tface) + return; + + /* create a CCGSubsurf from uv's */ + uvss = _getSubSurf(NULL, ccgSubSurf_getSubdivisionLevels(ss), 0, 1, 0); + + if(!ss_sync_from_uv(uvss, ss, dm, dmtface)) { + ccgSubSurf_free(uvss); + return; + } + + /* get some info from CCGSubsurf */ + totface = ccgSubSurf_getNumFaces(uvss); + edgeSize = ccgSubSurf_getEdgeSize(uvss); + gridSize = ccgSubSurf_getGridSize(uvss); + gridFaces = gridSize - 1; + + /* make a map from original faces to CCGFaces */ + faceMap = MEM_mallocN(totface*sizeof(*faceMap), "facemapuv"); + + fi = ccgSubSurf_getFaceIterator(uvss); + for(; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { + CCGFace *f = ccgFaceIterator_getCurrent(fi); + faceMap[(int) ccgSubSurf_getFaceFaceHandle(uvss, f)] = f; + } + ccgFaceIterator_free(fi); + + /* load coordinates from uvss into tface */ + tf= tface; + + for(index = 0; index < totface; index++) { + CCGFace *f = faceMap[index]; + int numVerts = ccgSubSurf_getFaceNumVerts(uvss, f); + + for (S=0; Suv[0][0] = a[0]; tf->uv[0][1] = a[1]; + tf->uv[1][0] = d[0]; tf->uv[1][1] = d[1]; + tf->uv[2][0] = c[0]; tf->uv[2][1] = c[1]; + tf->uv[3][0] = b[0]; tf->uv[3][1] = b[1]; + + tf++; + } + } + } + } + + ccgSubSurf_free(uvss); + MEM_freeN(faceMap); +} + +#if 0 +static unsigned int ss_getEdgeFlags(CCGSubSurf *ss, CCGEdge *e, int ssFromEditmesh, DispListMesh *dlm, MEdge *medge, MTFace *tface) +{ + unsigned int flags = 0; + int N = ccgSubSurf_getEdgeNumFaces(ss, e); + + if (!N) flags |= ME_LOOSEEDGE; + + if (ssFromEditmesh) { + EditEdge *eed = ccgSubSurf_getEdgeEdgeHandle(ss, e); + + flags |= ME_EDGEDRAW|ME_EDGERENDER; + if (eed->seam) { + flags |= ME_SEAM; + } + } else { + if (edgeIdx!=-1) { + MEdge *origMed = &medge[edgeIdx]; + + if (dlm) { + flags |= origMed->flag&~ME_EDGE_STEPINDEX; + } else { + flags |= (origMed->flag&ME_SEAM)|ME_EDGEDRAW|ME_EDGERENDER; + } + } + } + + return flags; +} +#endif + +/* face weighting */ +static void calc_ss_weights(int gridFaces, + FaceVertWeight **qweight, FaceVertWeight **tweight) +{ + FaceVertWeight *qw, *tw; + int x, y, j; + int numWeights = gridFaces * gridFaces; + + *tweight = MEM_mallocN(sizeof(**tweight) * numWeights, "ssTriWeight"); + *qweight = MEM_mallocN(sizeof(**qweight) * numWeights, "ssQuadWeight"); + + qw = *qweight; + tw = *tweight; + + for (y = 0; y < gridFaces; y++) { + for (x = 0; x < gridFaces; x++) { + for (j = 0; j < 4; j++) { + int fx = x + (j == 2 || j == 3); + int fy = y + (j == 1 || j == 2); + float x_v = (float) fx / gridFaces; + float y_v = (float) fy / gridFaces; + float tx_v = (1.0f - x_v), ty_v = (1.0f - y_v); + float center = (1.0f / 3.0f) * tx_v * ty_v; + + (*tw)[j][0] = center + 0.5f * tx_v * y_v; + (*tw)[j][2] = center + 0.5f * x_v * ty_v; + (*tw)[j][1] = 1.0f - (*tw)[j][0] - (*tw)[j][2]; + (*tw)[j][3] = 0.0f; + + tx_v *= 0.5f; + ty_v *= 0.5f; + + (*qw)[j][3] = tx_v * ty_v; + (*qw)[j][0] = (*qw)[j][3] + tx_v * y_v; + (*qw)[j][2] = (*qw)[j][3] + x_v * ty_v; + (*qw)[j][1] = 1.0f - (*qw)[j][0] - (*qw)[j][2] - (*qw)[j][3]; + + } + tw++; + qw++; + } + } +} + +DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, + int drawInteriorEdges, int useSubsurfUv, + DerivedMesh *dm) +{ + DerivedMesh *result; + int edgeSize = ccgSubSurf_getEdgeSize(ss); + int gridSize = ccgSubSurf_getGridSize(ss); + int gridFaces = gridSize - 1; + int edgeBase, faceBase; + int i, j, k, S, x, y, index; + int vertBase = 0; + CCGVertIterator *vi; + CCGEdgeIterator *ei; + CCGFaceIterator *fi; + CCGFace **faceMap2; + CCGEdge **edgeMap2; + CCGVert **vertMap2; + int totvert, totedge, totface; + MVert *mvert; + MEdge *med; + MFace *mf; + int *origIndex; + FaceVertWeight *qweight, *tweight; + + calc_ss_weights(gridFaces, &qweight, &tweight); + + /* vert map */ + totvert = ccgSubSurf_getNumVerts(ss); + vertMap2 = MEM_mallocN(totvert*sizeof(*vertMap2), "vertmap"); + vi = ccgSubSurf_getVertIterator(ss); + for(; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) { + CCGVert *v = ccgVertIterator_getCurrent(vi); + + vertMap2[(int) ccgSubSurf_getVertVertHandle(ss, v)] = v; + } + ccgVertIterator_free(vi); + + totedge = ccgSubSurf_getNumEdges(ss); + edgeMap2 = MEM_mallocN(totedge*sizeof(*edgeMap2), "edgemap"); + ei = ccgSubSurf_getEdgeIterator(ss); + for(; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) { + CCGEdge *e = ccgEdgeIterator_getCurrent(ei); + + edgeMap2[(int) ccgSubSurf_getEdgeEdgeHandle(ss, e)] = e; + } + + totface = ccgSubSurf_getNumFaces(ss); + faceMap2 = MEM_mallocN(totface*sizeof(*faceMap2), "facemap"); + fi = ccgSubSurf_getFaceIterator(ss); + for(; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { + CCGFace *f = ccgFaceIterator_getCurrent(fi); + + faceMap2[(int) ccgSubSurf_getFaceFaceHandle(ss, f)] = f; + } + ccgFaceIterator_free(fi); + + if(dm) { + result = CDDM_from_template(dm, ccgSubSurf_getNumFinalVerts(ss), + ccgSubSurf_getNumFinalEdges(ss), + ccgSubSurf_getNumFinalFaces(ss)); + } else { + result = CDDM_new(ccgSubSurf_getNumFinalVerts(ss), + ccgSubSurf_getNumFinalEdges(ss), + ccgSubSurf_getNumFinalFaces(ss)); + } + + // load verts + faceBase = i = 0; + mvert = CDDM_get_verts(result); + origIndex = result->getVertData(result, 0, CD_ORIGINDEX); + + for(index = 0; index < totface; index++) { + CCGFace *f = faceMap2[index]; + int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + FaceVertWeight *weight = (numVerts == 4) ? qweight : tweight; + int vertIdx[4]; + + for(S = 0; S < numVerts; S++) { + CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S); + + vertIdx[S] = (int)ccgSubSurf_getVertVertHandle(ss, v); + } + + DM_interp_vert_data(dm, result, vertIdx, weight[0][0], numVerts, i); + VecCopyf(mvert->co, ccgSubSurf_getFaceCenterData(ss, f)); + *origIndex = ORIGINDEX_NONE; + ++mvert; + ++origIndex; + i++; + + for(S = 0; S < numVerts; S++) { + int prevS = (S - 1 + numVerts) % numVerts; + int nextS = (S + 1) % numVerts; + int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3; + for(x = 1; x < gridFaces; x++) { + float w[4]; + w[prevS] = weight[x][0][0]; + w[S] = weight[x][0][1]; + w[nextS] = weight[x][0][2]; + w[otherS] = weight[x][0][3]; + DM_interp_vert_data(dm, result, vertIdx, w, numVerts, i); + VecCopyf(mvert->co, + ccgSubSurf_getFaceGridEdgeData(ss, f, S, x)); + *origIndex = ORIGINDEX_NONE; + ++mvert; + ++origIndex; + i++; + } + } + + for(S = 0; S < numVerts; S++) { + int prevS = (S - 1 + numVerts) % numVerts; + int nextS = (S + 1) % numVerts; + int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3; + for(y = 1; y < gridFaces; y++) { + for(x = 1; x < gridFaces; x++) { + float w[4]; + w[prevS] = weight[y * gridFaces + x][0][0]; + w[S] = weight[y * gridFaces + x][0][1]; + w[nextS] = weight[y * gridFaces + x][0][2]; + w[otherS] = weight[y * gridFaces + x][0][3]; + DM_interp_vert_data(dm, result, vertIdx, w, numVerts, i); + VecCopyf(mvert->co, + ccgSubSurf_getFaceGridData(ss, f, S, x, y)); + *origIndex = ORIGINDEX_NONE; + ++mvert; + ++origIndex; + i++; + } + } + } + + *((int*)ccgSubSurf_getFaceUserData(ss, f)) = faceBase; + faceBase += 1 + numVerts * ((gridSize-2) + (gridSize-2) * (gridSize-2)); + } + + edgeBase = i; + for(index = 0; index < totedge; index++) { + CCGEdge *e = edgeMap2[index]; + int x; + int vertIdx[2]; + + CCGVert *v; + v = ccgSubSurf_getEdgeVert0(ss, e); + vertIdx[0] = (int)ccgSubSurf_getVertVertHandle(ss, v); + v = ccgSubSurf_getEdgeVert1(ss, e); + vertIdx[1] = (int)ccgSubSurf_getVertVertHandle(ss, v); + + for(x = 1; x < edgeSize - 1; x++) { + float w[2]; + w[1] = (float) x / (edgeSize - 1); + w[0] = 1 - w[1]; + DM_interp_vert_data(dm, result, vertIdx, w, 2, i); + VecCopyf(mvert->co, ccgSubSurf_getEdgeData(ss, e, x)); + *origIndex = ORIGINDEX_NONE; + ++mvert; + ++origIndex; + i++; + } + + *((int*)ccgSubSurf_getEdgeUserData(ss, e)) = edgeBase; + edgeBase += edgeSize-2; + } + + vertBase = i; + for(index = 0; index < totvert; index++) { + CCGVert *v = vertMap2[index]; + int vertIdx; + + vertIdx = (int)ccgSubSurf_getVertVertHandle(ss, v); + + DM_copy_vert_data(dm, result, vertIdx, i, 1); + VecCopyf(mvert->co, ccgSubSurf_getVertData(ss, v)); + + *((int*)ccgSubSurf_getVertUserData(ss, v)) = i; + *origIndex = ccgDM_getVertMapIndex(NULL, ss, v); + ++mvert; + ++origIndex; + i++; + } + + // load edges + i = 0; + med = CDDM_get_edges(result); + origIndex = result->getEdgeData(result, 0, CD_ORIGINDEX); + + for(index = 0; index < totface; index++) { + CCGFace *f = faceMap2[index]; + int numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + + for(k = 0; k < numVerts; k++) { + for(x = 0; x < gridFaces; x++) { + if(drawInteriorEdges) med->flag = ME_EDGEDRAW | ME_EDGERENDER; + med->v1 = getFaceIndex(ss, f, k, x, 0, edgeSize, gridSize); + med->v2 = getFaceIndex(ss, f, k, x+1, 0, edgeSize, gridSize); + *origIndex = ORIGINDEX_NONE; + ++med; + ++origIndex; + i++; + } + + for(x = 1; x < gridFaces; x++) { + for(y = 0; y < gridFaces; y++) { + if(drawInteriorEdges) + med->flag = ME_EDGEDRAW | ME_EDGERENDER; + med->v1 = getFaceIndex(ss, f, k, x, y, edgeSize, gridSize); + med->v2 = getFaceIndex(ss, f, k, x, y + 1, + edgeSize, gridSize); + *origIndex = ORIGINDEX_NONE; + ++med; + ++origIndex; + i++; + + if(drawInteriorEdges) + med->flag = ME_EDGEDRAW | ME_EDGERENDER; + med->v1 = getFaceIndex(ss, f, k, y, x, edgeSize, gridSize); + med->v2 = getFaceIndex(ss, f, k, y + 1, x, + edgeSize, gridSize); + *origIndex = ORIGINDEX_NONE; + ++med; + ++origIndex; + i++; + } + } + } + } + + for(index = 0; index < totedge; index++) { + CCGEdge *e = edgeMap2[index]; + unsigned int flags = 0; + int edgeIdx = (int)ccgSubSurf_getEdgeEdgeHandle(ss, e); + + if(!ccgSubSurf_getEdgeNumFaces(ss, e)) flags |= ME_LOOSEEDGE; + + + if(edgeIdx != -1 && dm) { + MEdge origMed; + dm->getEdge(dm, edgeIdx, &origMed); + + flags |= origMed.flag; + } + + for(x = 0; x < edgeSize - 1; x++) { + med->v1 = getEdgeIndex(ss, e, x, edgeSize); + med->v2 = getEdgeIndex(ss, e, x + 1, edgeSize); + med->flag = flags; + *origIndex = ccgDM_getEdgeMapIndex(NULL, ss, e); + ++med; + ++origIndex; + i++; + } + } + + // load faces + i = 0; + mf = CDDM_get_faces(result); + origIndex = result->getFaceData(result, 0, CD_ORIGINDEX); + + for(index = 0; index < totface; index++) { + CCGFace *f = faceMap2[index]; + int numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + int mat_nr; + int flag; + int mapIndex = ccgDM_getFaceMapIndex(NULL, ss, f); + int faceIdx = (int)ccgSubSurf_getFaceFaceHandle(ss, f); + + if(!ssFromEditmesh) { + MFace origMFace; + dm->getFace(dm, faceIdx, &origMFace); + + mat_nr = origMFace.mat_nr; + flag = origMFace.flag; + } else { + EditFace *ef = ccgSubSurf_getFaceFaceHandle(ss, f); + mat_nr = ef->mat_nr; + flag = ef->flag; + } + + for(S = 0; S < numVerts; S++) { + FaceVertWeight *weight = (numVerts == 4) ? qweight : tweight; + + for(y = 0; y < gridFaces; y++) { + for(x = 0; x < gridFaces; x++) { + mf->v1 = getFaceIndex(ss, f, S, x + 0, y + 0, + edgeSize, gridSize); + mf->v2 = getFaceIndex(ss, f, S, x + 0, y + 1, + edgeSize, gridSize); + mf->v3 = getFaceIndex(ss, f, S, x + 1, y + 1, + edgeSize, gridSize); + mf->v4 = getFaceIndex(ss, f, S, x + 1, y + 0, + edgeSize, gridSize); + mf->mat_nr = mat_nr; + mf->flag = flag; + + if(dm) { + int prevS = (S - 1 + numVerts) % numVerts; + int nextS = (S + 1) % numVerts; + int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3; + FaceVertWeight w; + + for(j = 0; j < 4; ++j) { + w[j][prevS] = (*weight)[j][0]; + w[j][S] = (*weight)[j][1]; + w[j][nextS] = (*weight)[j][2]; + w[j][otherS] = (*weight)[j][3]; + } + + DM_interp_face_data(dm, result, &faceIdx, NULL, + &w, 1, i); + weight++; + } + + *origIndex = mapIndex; + ++mf; + ++origIndex; + i++; + } + } + } + } + + MEM_freeN(faceMap2); + MEM_freeN(edgeMap2); + MEM_freeN(vertMap2); + + MEM_freeN(tweight); + MEM_freeN(qweight); + + if(useSubsurfUv) { + CustomData *fdata = &result->faceData; + CustomData *dmfdata = &dm->faceData; + int numlayer = CustomData_number_of_layers(fdata, CD_MTFACE); + int dmnumlayer = CustomData_number_of_layers(dmfdata, CD_MTFACE); + + for (i=0; igetNumVerts(dm); + int totedge = dm->getNumEdges(dm); + int totface = dm->getNumFaces(dm); + int i; + int *index; + MVert *mvert = dm->getVertArray(dm); + MEdge *medge = dm->getEdgeArray(dm); + MFace *mface = dm->getFaceArray(dm); + MVert *mv; + MEdge *me; + MFace *mf; + + ccgSubSurf_initFullSync(ss); + + mv = mvert; + index = (int *)dm->getVertDataArray(dm, CD_ORIGINDEX); + for(i = 0; i < totvert; i++, mv++, index++) { + CCGVert *v; + + if(vertexCos) { + ccgSubSurf_syncVert(ss, (CCGVertHDL)i, vertexCos[i], 0, &v); + } else { + ccgSubSurf_syncVert(ss, (CCGVertHDL)i, mv->co, 0, &v); + } + + ((int*)ccgSubSurf_getVertUserData(ss, v))[1] = *index; + } + + me = medge; + index = (int *)dm->getEdgeDataArray(dm, CD_ORIGINDEX); + for(i = 0; i < totedge; i++, me++, index++) { + CCGEdge *e; + float crease; + + crease = useFlatSubdiv ? creaseFactor : + me->crease * creaseFactor / 255.0f; + + ccgSubSurf_syncEdge(ss, (CCGEdgeHDL)i, (CCGVertHDL)me->v1, + (CCGVertHDL)me->v2, crease, &e); + + ((int*)ccgSubSurf_getEdgeUserData(ss, e))[1] = *index; + } + + mf = mface; + index = (int *)dm->getFaceDataArray(dm, CD_ORIGINDEX); + for (i = 0; i < totface; i++, mf++, index++) { + CCGFace *f; + + fVerts[0] = (CCGVertHDL) mf->v1; + fVerts[1] = (CCGVertHDL) mf->v2; + fVerts[2] = (CCGVertHDL) mf->v3; + fVerts[3] = (CCGVertHDL) mf->v4; + + // this is very bad, means mesh is internally consistent. + // it is not really possible to continue without modifying + // other parts of code significantly to handle missing faces. + // since this really shouldn't even be possible we just bail. + if(ccgSubSurf_syncFace(ss, (CCGFaceHDL)i, fVerts[3] ? 4 : 3, + fVerts, &f) == eCCGError_InvalidValue) { + static int hasGivenError = 0; + + if(!hasGivenError) { + error("Unrecoverable error in SubSurf calculation," + " mesh is inconsistent."); + + hasGivenError = 1; + } + + return; + } + + ((int*)ccgSubSurf_getFaceUserData(ss, f))[1] = *index; + } + + ccgSubSurf_processSync(ss); +} + +/***/ + +static int ccgDM_getVertMapIndex(CCGDerivedMesh *ccgdm, CCGSubSurf *ss, CCGVert *v) { + return ((int*) ccgSubSurf_getVertUserData(ss, v))[1]; +} + +static int ccgDM_getEdgeMapIndex(CCGDerivedMesh *ccgdm, CCGSubSurf *ss, CCGEdge *e) { + return ((int*) ccgSubSurf_getEdgeUserData(ss, e))[1]; +} + +static int ccgDM_getFaceMapIndex(CCGDerivedMesh *ccgdm, CCGSubSurf *ss, CCGFace *f) { + return ((int*) ccgSubSurf_getFaceUserData(ss, f))[1]; +} + +static void ccgDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3]) { + CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; + CCGSubSurf *ss = ccgdm->ss; + CCGVertIterator *vi = ccgSubSurf_getVertIterator(ss); + CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss); + CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss); + int i, edgeSize = ccgSubSurf_getEdgeSize(ss); + int gridSize = ccgSubSurf_getGridSize(ss); + + if (!ccgSubSurf_getNumVerts(ss)) + min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0; + + for (; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) { + CCGVert *v = ccgVertIterator_getCurrent(vi); + float *co = ccgSubSurf_getVertData(ss, v); + + DO_MINMAX(co, min_r, max_r); + } + + for (; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) { + CCGEdge *e = ccgEdgeIterator_getCurrent(ei); + VertData *edgeData = ccgSubSurf_getEdgeDataArray(ss, e); + + for (i=0; iss); +} +static int ccgDM_getNumEdges(DerivedMesh *dm) { + CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; + + return ccgSubSurf_getNumFinalEdges(ccgdm->ss); +} +static int ccgDM_getNumFaces(DerivedMesh *dm) { + CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; + + return ccgSubSurf_getNumFinalFaces(ccgdm->ss); +} + +static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv) +{ + CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; + CCGSubSurf *ss = ccgdm->ss; + int i; + + memset(mv, 0, sizeof(*mv)); + + if(vertNum < ccgdm->edgeMap[0].startVert) { + /* this vert comes from face data */ + int lastface = ccgSubSurf_getNumFaces(ss) - 1; + CCGFace *f; + int x, y, grid, numVerts; + int offset; + int gridSize = ccgSubSurf_getGridSize(ss); + int gridSideVerts; + int gridInternalVerts; + int gridSideEnd; + int gridInternalEnd; + + i = 0; + while(i < lastface && vertNum >= ccgdm->faceMap[i + 1].startVert) + ++i; + + f = ccgdm->faceMap[i].face; + numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + + gridSideVerts = gridSize - 2; + gridInternalVerts = gridSideVerts * gridSideVerts; + + gridSideEnd = 1 + numVerts * gridSideVerts; + gridInternalEnd = gridSideEnd + numVerts * gridInternalVerts; + + offset = vertNum - ccgdm->faceMap[i].startVert; + if(offset < 1) { + VecCopyf(mv->co, ccgSubSurf_getFaceCenterData(ss, f)); + } else if(offset < gridSideEnd) { + offset -= 1; + grid = offset / gridSideVerts; + x = offset % gridSideVerts + 1; + VecCopyf(mv->co, ccgSubSurf_getFaceGridEdgeData(ss, f, grid, x)); + } else if(offset < gridInternalEnd) { + offset -= gridSideEnd; + grid = offset / gridInternalVerts; + offset %= gridInternalVerts; + y = offset / gridSideVerts + 1; + x = offset % gridSideVerts + 1; + VecCopyf(mv->co, ccgSubSurf_getFaceGridData(ss, f, grid, x, y)); + } + } else if(vertNum < ccgdm->vertMap[0].startVert) { + /* this vert comes from edge data */ + CCGEdge *e; + int lastedge = ccgSubSurf_getNumEdges(ss) - 1; + int x; + + i = 0; + while(i < lastedge && vertNum >= ccgdm->edgeMap[i + 1].startVert) + ++i; + + e = ccgdm->edgeMap[i].edge; + + x = vertNum - ccgdm->edgeMap[i].startVert + 1; + VecCopyf(mv->co, ccgSubSurf_getEdgeData(ss, e, x)); + } else { + /* this vert comes from vert data */ + CCGVert *v; + i = vertNum - ccgdm->vertMap[0].startVert; + + v = ccgdm->vertMap[i].vert; + VecCopyf(mv->co, ccgSubSurf_getVertData(ss, v)); + } +} + +static void ccgDM_getFinalEdge(DerivedMesh *dm, int edgeNum, MEdge *med) +{ + CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; + CCGSubSurf *ss = ccgdm->ss; + int i; + + memset(med, 0, sizeof(*med)); + + if(edgeNum < ccgdm->edgeMap[0].startEdge) { + /* this edge comes from face data */ + int lastface = ccgSubSurf_getNumFaces(ss) - 1; + CCGFace *f; + int x, y, grid, numVerts; + int offset; + int gridSize = ccgSubSurf_getGridSize(ss); + int edgeSize = ccgSubSurf_getEdgeSize(ss); + int gridSideEdges; + int gridInternalEdges; + + i = 0; + while(i < lastface && edgeNum >= ccgdm->faceMap[i + 1].startEdge) + ++i; + + f = ccgdm->faceMap[i].face; + numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + + gridSideEdges = gridSize - 1; + gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2; + + offset = edgeNum - ccgdm->faceMap[i].startEdge; + grid = offset / (gridSideEdges + gridInternalEdges); + offset %= (gridSideEdges + gridInternalEdges); + + if(offset < gridSideEdges) { + x = offset; + med->v1 = getFaceIndex(ss, f, grid, x, 0, edgeSize, gridSize); + med->v2 = getFaceIndex(ss, f, grid, x+1, 0, edgeSize, gridSize); + } else { + offset -= gridSideEdges; + x = (offset / 2) / gridSideEdges + 1; + y = (offset / 2) % gridSideEdges; + if(offset % 2 == 0) { + med->v1 = getFaceIndex(ss, f, grid, x, y, edgeSize, gridSize); + med->v2 = getFaceIndex(ss, f, grid, x, y+1, edgeSize, gridSize); + } else { + med->v1 = getFaceIndex(ss, f, grid, y, x, edgeSize, gridSize); + med->v2 = getFaceIndex(ss, f, grid, y+1, x, edgeSize, gridSize); + } + } + } else { + /* this vert comes from edge data */ + CCGEdge *e; + int edgeSize = ccgSubSurf_getEdgeSize(ss); + int x, *edgeFlag; + unsigned int flags = 0; + + i = (edgeNum - ccgdm->edgeMap[0].startEdge) / (edgeSize - 1); + + e = ccgdm->edgeMap[i].edge; + + if(!ccgSubSurf_getEdgeNumFaces(ss, e)) flags |= ME_LOOSEEDGE; + + x = edgeNum - ccgdm->edgeMap[i].startEdge; + + med->v1 = getEdgeIndex(ss, e, x, edgeSize); + med->v2 = getEdgeIndex(ss, e, x+1, edgeSize); + + edgeFlag = dm->getEdgeData(dm, edgeNum, CD_FLAGS); + if(edgeFlag) + flags |= (*edgeFlag & (ME_SEAM | ME_SHARP)) + | ME_EDGEDRAW | ME_EDGERENDER; + else + flags |= ME_EDGEDRAW | ME_EDGERENDER; + + med->flag = flags; + } +} + +static void ccgDM_getFinalFace(DerivedMesh *dm, int faceNum, MFace *mf) +{ + CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; + CCGSubSurf *ss = ccgdm->ss; + int gridSize = ccgSubSurf_getGridSize(ss); + int edgeSize = ccgSubSurf_getEdgeSize(ss); + int gridSideEdges = gridSize - 1; + int gridFaces = gridSideEdges * gridSideEdges; + int i; + CCGFace *f; + int numVerts; + int offset; + int grid; + int x, y; + int lastface = ccgSubSurf_getNumFaces(ss) - 1; + char *faceFlags = dm->getFaceDataArray(dm, CD_FLAGS); + + memset(mf, 0, sizeof(*mf)); + + i = 0; + while(i < lastface && faceNum >= ccgdm->faceMap[i + 1].startFace) + ++i; + + f = ccgdm->faceMap[i].face; + numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + + offset = faceNum - ccgdm->faceMap[i].startFace; + grid = offset / gridFaces; + offset %= gridFaces; + y = offset / gridSideEdges; + x = offset % gridSideEdges; + + mf->v1 = getFaceIndex(ss, f, grid, x+0, y+0, edgeSize, gridSize); + mf->v2 = getFaceIndex(ss, f, grid, x+0, y+1, edgeSize, gridSize); + mf->v3 = getFaceIndex(ss, f, grid, x+1, y+1, edgeSize, gridSize); + mf->v4 = getFaceIndex(ss, f, grid, x+1, y+0, edgeSize, gridSize); + + if(faceFlags) mf->flag = faceFlags[i*4]; + else mf->flag = ME_SMOOTH; +} + +static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert) +{ + CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; + CCGSubSurf *ss = ccgdm->ss; + int index; + int totvert, totedge, totface; + int gridSize = ccgSubSurf_getGridSize(ss); + int edgeSize = ccgSubSurf_getEdgeSize(ss); + int i = 0; + + totface = ccgSubSurf_getNumFaces(ss); + for(index = 0; index < totface; index++) { + CCGFace *f = ccgdm->faceMap[index].face; + int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + + VecCopyf(mvert[i++].co, ccgSubSurf_getFaceCenterData(ss, f)); + + for(S = 0; S < numVerts; S++) { + for(x = 1; x < gridSize - 1; x++) { + VecCopyf(mvert[i++].co, + ccgSubSurf_getFaceGridEdgeData(ss, f, S, x)); + } + } + + for(S = 0; S < numVerts; S++) { + for(y = 1; y < gridSize - 1; y++) { + for(x = 1; x < gridSize - 1; x++) { + VecCopyf(mvert[i++].co, + ccgSubSurf_getFaceGridData(ss, f, S, x, y)); + } + } + } + } + + totedge = ccgSubSurf_getNumEdges(ss); + for(index = 0; index < totedge; index++) { + CCGEdge *e = ccgdm->edgeMap[index].edge; + int x; + + for(x = 1; x < edgeSize - 1; x++) { + VecCopyf(mvert[i++].co, ccgSubSurf_getEdgeData(ss, e, x)); + } + } + + totvert = ccgSubSurf_getNumVerts(ss); + for(index = 0; index < totvert; index++) { + CCGVert *v = ccgdm->vertMap[index].vert; + + VecCopyf(mvert[i].co, ccgSubSurf_getVertData(ss, v)); + + i++; + } +} + +static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge) +{ + CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; + CCGSubSurf *ss = ccgdm->ss; + int index; + int totedge, totface; + int gridSize = ccgSubSurf_getGridSize(ss); + int edgeSize = ccgSubSurf_getEdgeSize(ss); + int i = 0; + int *edgeFlags = dm->getEdgeDataArray(dm, CD_FLAGS); + + totface = ccgSubSurf_getNumFaces(ss); + for(index = 0; index < totface; index++) { + CCGFace *f = ccgdm->faceMap[index].face; + int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + + for(S = 0; S < numVerts; S++) { + for(x = 0; x < gridSize - 1; x++) { + MEdge *med = &medge[i]; + + if(ccgdm->drawInteriorEdges) + med->flag = ME_EDGEDRAW | ME_EDGERENDER; + med->v1 = getFaceIndex(ss, f, S, x, 0, edgeSize, gridSize); + med->v2 = getFaceIndex(ss, f, S, x + 1, 0, edgeSize, gridSize); + i++; + } + + for(x = 1; x < gridSize - 1; x++) { + for(y = 0; y < gridSize - 1; y++) { + MEdge *med; + + med = &medge[i]; + if(ccgdm->drawInteriorEdges) + med->flag = ME_EDGEDRAW | ME_EDGERENDER; + med->v1 = getFaceIndex(ss, f, S, x, y, + edgeSize, gridSize); + med->v2 = getFaceIndex(ss, f, S, x, y + 1, + edgeSize, gridSize); + i++; + + med = &medge[i]; + if(ccgdm->drawInteriorEdges) + med->flag = ME_EDGEDRAW | ME_EDGERENDER; + med->v1 = getFaceIndex(ss, f, S, y, x, + edgeSize, gridSize); + med->v2 = getFaceIndex(ss, f, S, y + 1, x, + edgeSize, gridSize); + i++; + } + } + } + } + + totedge = ccgSubSurf_getNumEdges(ss); + for(index = 0; index < totedge; index++) { + CCGEdge *e = ccgdm->edgeMap[index].edge; + unsigned int flags = 0; + int x; + int edgeIdx = (int)ccgSubSurf_getEdgeEdgeHandle(ss, e); + + if(!ccgSubSurf_getEdgeNumFaces(ss, e)) flags |= ME_LOOSEEDGE; + + if(edgeFlags) { + if(edgeIdx != -1) { + flags |= (edgeFlags[i] & (ME_SEAM | ME_SHARP)) + | ME_EDGEDRAW | ME_EDGERENDER; + } + } else { + flags |= ME_EDGEDRAW | ME_EDGERENDER; + } + + for(x = 0; x < edgeSize - 1; x++) { + MEdge *med = &medge[i]; + med->v1 = getEdgeIndex(ss, e, x, edgeSize); + med->v2 = getEdgeIndex(ss, e, x + 1, edgeSize); + med->flag = flags; + i++; + } + } +} + +static void ccgDM_copyFinalFaceArray(DerivedMesh *dm, MFace *mface) +{ + CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; + CCGSubSurf *ss = ccgdm->ss; + int index; + int totface; + int gridSize = ccgSubSurf_getGridSize(ss); + int edgeSize = ccgSubSurf_getEdgeSize(ss); + int i = 0; + char *faceFlags = dm->getFaceDataArray(dm, CD_FLAGS); + + totface = ccgSubSurf_getNumFaces(ss); + for(index = 0; index < totface; index++) { + CCGFace *f = ccgdm->faceMap[index].face; + int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + int mat_nr = 0; + int flag = ME_SMOOTH; /* assume face is smooth by default */ + + for(S = 0; S < numVerts; S++) { + for(y = 0; y < gridSize - 1; y++) { + for(x = 0; x < gridSize - 1; x++) { + MFace *mf = &mface[i]; + mf->v1 = getFaceIndex(ss, f, S, x + 0, y + 0, + edgeSize, gridSize); + mf->v2 = getFaceIndex(ss, f, S, x + 0, y + 1, + edgeSize, gridSize); + mf->v3 = getFaceIndex(ss, f, S, x + 1, y + 1, + edgeSize, gridSize); + mf->v4 = getFaceIndex(ss, f, S, x + 1, y + 0, + edgeSize, gridSize); + mf->mat_nr = mat_nr; + if(faceFlags) mf->flag = faceFlags[index*4]; + else mf->flag = flag; + + i++; + } + } + } + } +} + +static void ccgdm_getVertCos(DerivedMesh *dm, float (*cos)[3]) { + CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; + CCGSubSurf *ss = ccgdm->ss; + int edgeSize = ccgSubSurf_getEdgeSize(ss); + int gridSize = ccgSubSurf_getGridSize(ss); + int i; + CCGVertIterator *vi; + CCGEdgeIterator *ei; + CCGFaceIterator *fi; + CCGFace **faceMap2; + CCGEdge **edgeMap2; + CCGVert **vertMap2; + int index, totvert, totedge, totface; + + totvert = ccgSubSurf_getNumVerts(ss); + vertMap2 = MEM_mallocN(totvert*sizeof(*vertMap2), "vertmap"); + vi = ccgSubSurf_getVertIterator(ss); + for (; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) { + CCGVert *v = ccgVertIterator_getCurrent(vi); + + vertMap2[(int) ccgSubSurf_getVertVertHandle(ss, v)] = v; + } + ccgVertIterator_free(vi); + + totedge = ccgSubSurf_getNumEdges(ss); + edgeMap2 = MEM_mallocN(totedge*sizeof(*edgeMap2), "edgemap"); + ei = ccgSubSurf_getEdgeIterator(ss); + for (i=0; !ccgEdgeIterator_isStopped(ei); i++,ccgEdgeIterator_next(ei)) { + CCGEdge *e = ccgEdgeIterator_getCurrent(ei); + + edgeMap2[(int) ccgSubSurf_getEdgeEdgeHandle(ss, e)] = e; + } + + totface = ccgSubSurf_getNumFaces(ss); + faceMap2 = MEM_mallocN(totface*sizeof(*faceMap2), "facemap"); + fi = ccgSubSurf_getFaceIterator(ss); + for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { + CCGFace *f = ccgFaceIterator_getCurrent(fi); + + faceMap2[(int) ccgSubSurf_getFaceFaceHandle(ss, f)] = f; + } + ccgFaceIterator_free(fi); + + i = 0; + for (index=0; indexss); + + for (; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) { + CCGVert *v = ccgVertIterator_getCurrent(vi); + VertData *vd = ccgSubSurf_getVertData(ccgdm->ss, v); + int index = ccgDM_getVertMapIndex(ccgdm, ccgdm->ss, v); + + if (index!=-1) + func(userData, index, vd->co, vd->no, NULL); + } + + ccgVertIterator_free(vi); +} +static void ccgDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData) { + CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; + CCGSubSurf *ss = ccgdm->ss; + CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss); + int i, edgeSize = ccgSubSurf_getEdgeSize(ss); + + for (; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) { + CCGEdge *e = ccgEdgeIterator_getCurrent(ei); + VertData *edgeData = ccgSubSurf_getEdgeDataArray(ss, e); + int index = ccgDM_getEdgeMapIndex(ccgdm, ss, e); + + if (index!=-1) { + for (i=0; iss; + int edgeSize = ccgSubSurf_getEdgeSize(ss); + int gridSize = ccgSubSurf_getGridSize(ss); + CCGVertIterator *vi; + CCGEdgeIterator *ei; + CCGFaceIterator *fi; + + glBegin(GL_POINTS); + vi = ccgSubSurf_getVertIterator(ss); + for (; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) { + CCGVert *v = ccgVertIterator_getCurrent(vi); + glVertex3fv(ccgSubSurf_getVertData(ss, v)); + } + ccgVertIterator_free(vi); + + ei = ccgSubSurf_getEdgeIterator(ss); + for (; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) { + CCGEdge *e = ccgEdgeIterator_getCurrent(ei); + int x; + + for (x=1; xss; + CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss); + CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss); + int i, edgeSize = ccgSubSurf_getEdgeSize(ss); + int gridSize = ccgSubSurf_getGridSize(ss); + int useAging; + + ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL); + + for (; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) { + CCGEdge *e = ccgEdgeIterator_getCurrent(ei); + VertData *edgeData = ccgSubSurf_getEdgeDataArray(ss, e); + + if (!drawLooseEdges && !ccgSubSurf_getEdgeNumFaces(ss, e)) + continue; + + if (useAging && !(G.f&G_BACKBUFSEL)) { + int ageCol = 255-ccgSubSurf_getEdgeAge(ss, e)*4; + glColor3ub(0, ageCol>0?ageCol:0, 0); + } + + glBegin(GL_LINE_STRIP); + for (i=0; idrawInteriorEdges) { + for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { + CCGFace *f = ccgFaceIterator_getCurrent(fi); + int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + + for (S=0; Sss; + CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss); + int i, edgeSize = ccgSubSurf_getEdgeSize(ss); + + for (; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) { + CCGEdge *e = ccgEdgeIterator_getCurrent(ei); + VertData *edgeData = ccgSubSurf_getEdgeDataArray(ss, e); + + if (!ccgSubSurf_getEdgeNumFaces(ss, e)) { + glBegin(GL_LINE_STRIP); + for (i=0; iss; + CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss); + int gridSize = ccgSubSurf_getGridSize(ss); + char *faceFlags = DM_get_face_data_layer(dm, CD_FLAGS); + + for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { + CCGFace *f = ccgFaceIterator_getCurrent(fi); + int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + int index = (int) ccgSubSurf_getFaceFaceHandle(ss, f); + int drawSmooth, mat_nr; + + if(faceFlags) { + drawSmooth = (faceFlags[index*4] & ME_SMOOTH); + mat_nr= faceFlags[index*4 + 1]; + } + else { + drawSmooth = 1; + mat_nr= 0; + } + + if (!setMaterial(mat_nr+1)) + continue; + + glShadeModel(drawSmooth? GL_SMOOTH: GL_FLAT); + for (S=0; Sno); + glVertex3fv(a->co); + glNormal3fv(b->no); + glVertex3fv(b->co); + } + glEnd(); + } + } else { + glBegin(GL_QUADS); + for (y=0; yss; + CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss); + int gridSize = ccgSubSurf_getGridSize(ss); + unsigned char *cp1, *cp2; + int useTwoSide=1; + + cp1= col1; + if(col2) { + cp2= col2; + } else { + cp2= NULL; + useTwoSide= 0; + } + + glShadeModel(GL_SMOOTH); + if(col1 && col2) + glEnable(GL_CULL_FACE); + + glBegin(GL_QUADS); + for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { + CCGFace *f = ccgFaceIterator_getCurrent(fi); + int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + + for (S=0; Sss; + MCol *mcol = DM_get_face_data_layer(dm, CD_MCOL); + MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE); + char *faceFlags = DM_get_face_data_layer(dm, CD_FLAGS); + int i, totface, flag, gridSize = ccgSubSurf_getGridSize(ss); + int gridFaces = gridSize - 1; + + totface = ccgSubSurf_getNumFaces(ss); + for(i = 0; i < totface; i++) { + CCGFace *f = ccgdm->faceMap[i].face; + int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + int drawSmooth, index = ccgDM_getFaceMapIndex(ccgdm, ss, f); + int origIndex = (int)ccgSubSurf_getFaceFaceHandle(ss, f); + unsigned char *cp= NULL; + int mat_nr; + + if(faceFlags) { + drawSmooth = (faceFlags[origIndex*4] & ME_SMOOTH); + mat_nr= faceFlags[origIndex*4 + 1]; + } + else { + drawSmooth = 1; + mat_nr= 0; + } + + if(drawParams) + flag = drawParams(tf, mcol, mat_nr); + else + flag= (drawParamsMapped)? drawParamsMapped(userData, index): 1; + + if (flag == 0) { /* flag 0 == the face is hidden or invisible */ + if(tf) tf += gridFaces*gridFaces*numVerts; + if(mcol) mcol += gridFaces*gridFaces*numVerts*4; + continue; + } + + /* flag 1 == use vertex colors */ + if(mcol) { + if(flag==1) cp= (unsigned char*)mcol; + mcol += gridFaces*gridFaces*numVerts*4; + } + + for (S=0; Suv[0]); + if(cp) glColor3ub(cp[3], cp[2], cp[1]); + glNormal3fv(a->no); + glVertex3fv(a->co); + + if(tf) glTexCoord2fv(tf->uv[1]); + if(cp) glColor3ub(cp[7], cp[6], cp[5]); + glNormal3fv(b->no); + glVertex3fv(b->co); + + if(x != gridFaces-1) { + if(tf) tf++; + if(cp) cp += 16; + } + } + + a = &faceGridData[(y+0)*gridSize + x]; + b = &faceGridData[(y+1)*gridSize + x]; + + if(tf) glTexCoord2fv(tf->uv[3]); + if(cp) glColor3ub(cp[15], cp[14], cp[13]); + glNormal3fv(a->no); + glVertex3fv(a->co); + + if(tf) glTexCoord2fv(tf->uv[2]); + if(cp) glColor3ub(cp[11], cp[10], cp[9]); + glNormal3fv(b->no); + glVertex3fv(b->co); + + if(tf) tf++; + if(cp) cp += 16; + + glEnd(); + } + } else { + glShadeModel(GL_FLAT); + glBegin(GL_QUADS); + for (y=0; yuv[1]); + if(cp) glColor3ub(cp[7], cp[6], cp[5]); + glVertex3fv(d); + + if(tf) glTexCoord2fv(tf->uv[2]); + if(cp) glColor3ub(cp[11], cp[10], cp[9]); + glVertex3fv(c); + + if(tf) glTexCoord2fv(tf->uv[3]); + if(cp) glColor3ub(cp[15], cp[14], cp[13]); + glVertex3fv(b); + + if(tf) glTexCoord2fv(tf->uv[0]); + if(cp) glColor3ub(cp[3], cp[2], cp[1]); + glVertex3fv(a); + + if(tf) tf++; + if(cp) cp += 16; + } + } + glEnd(); + } + } + } +} + +static void ccgDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr)) +{ + ccgDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL); +} + +static void ccgDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) +{ + ccgDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData); +} + +static void ccgDM_drawUVEdges(DerivedMesh *dm) +{ + + MFace *mf = dm->getFaceArray(dm); + MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE); + int i; + + if (tf) { + glBegin(GL_LINES); + for(i = 0; i < dm->numFaceData; i++, mf++, tf++) { + if(!(mf->flag&ME_HIDE)) { + glVertex2fv(tf->uv[0]); + glVertex2fv(tf->uv[1]); + + glVertex2fv(tf->uv[1]); + glVertex2fv(tf->uv[2]); + + if(!mf->v4) { + glVertex2fv(tf->uv[2]); + glVertex2fv(tf->uv[0]); + } else { + glVertex2fv(tf->uv[2]); + glVertex2fv(tf->uv[3]); + + glVertex2fv(tf->uv[3]); + glVertex2fv(tf->uv[0]); + } + } + } + glEnd(); + } +} + +static void ccgDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors) { + GLubyte act_face_stipple[32*32/8] = DM_FACE_STIPPLE; + CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; + CCGSubSurf *ss = ccgdm->ss; + CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss); + int i, gridSize = ccgSubSurf_getGridSize(ss); + char *faceFlags = dm->getFaceDataArray(dm, CD_FLAGS); + + for (i=0; !ccgFaceIterator_isStopped(fi); i++,ccgFaceIterator_next(fi)) { + CCGFace *f = ccgFaceIterator_getCurrent(fi); + int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + int drawSmooth, index = ccgDM_getFaceMapIndex(ccgdm, ss, f); + int origIndex; + + origIndex = (int)ccgSubSurf_getFaceFaceHandle(ss, f); + + if(faceFlags) drawSmooth = (faceFlags[origIndex*4] & ME_SMOOTH); + else drawSmooth = 1; + + if (index!=-1) { + int draw; + draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, index, &drawSmooth); + + if (draw) { + if (draw==2) { + glEnable(GL_POLYGON_STIPPLE); + glPolygonStipple(act_face_stipple); + } + + for (S=0; Sno); + glVertex3fv(a->co); + glNormal3fv(b->no); + glVertex3fv(b->co); + } + glEnd(); + } + } else { + glShadeModel(GL_FLAT); + glBegin(GL_QUADS); + for (y=0; yss; + CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss); + int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss); + + ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL); + + for (; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) { + CCGEdge *e = ccgEdgeIterator_getCurrent(ei); + VertData *edgeData = ccgSubSurf_getEdgeDataArray(ss, e); + int index = ccgDM_getEdgeMapIndex(ccgdm, ss, e); + + glBegin(GL_LINE_STRIP); + if (index!=-1 && (!setDrawOptions || setDrawOptions(userData, index))) { + if (useAging && !(G.f&G_BACKBUFSEL)) { + int ageCol = 255-ccgSubSurf_getEdgeAge(ss, e)*4; + glColor3ub(0, ageCol>0?ageCol:0, 0); + } + + for (i=0; iss; + CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss); + int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss); + + ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL); + + for (; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) { + CCGEdge *e = ccgEdgeIterator_getCurrent(ei); + VertData *edgeData = ccgSubSurf_getEdgeDataArray(ss, e); + int index = ccgDM_getEdgeMapIndex(ccgdm, ss, e); + + glBegin(GL_LINE_STRIP); + if (index!=-1 && (!setDrawOptions || setDrawOptions(userData, index))) { + for (i=0; i0?ageCol:0, 0); + } + + glVertex3fv(edgeData[i].co); + } + } + glEnd(); + } + + ccgEdgeIterator_free(ei); +} +static void ccgDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData) { + CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; + CCGSubSurf *ss = ccgdm->ss; + CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss); + + for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { + CCGFace *f = ccgFaceIterator_getCurrent(fi); + int index = ccgDM_getFaceMapIndex(ccgdm, ss, f); + + if (index!=-1) { + /* Face center data normal isn't updated atm. */ + VertData *vd = ccgSubSurf_getFaceGridData(ss, f, 0, 0, 0); + + func(userData, index, vd->co, vd->no); + } + } + + ccgFaceIterator_free(fi); +} + +static void ccgDM_release(DerivedMesh *dm) { + CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; + + if (DM_release(dm)) { + MEM_freeN(ccgdm->vertMap); + MEM_freeN(ccgdm->edgeMap); + MEM_freeN(ccgdm->faceMap); + MEM_freeN(ccgdm); + } +} + +static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, + int drawInteriorEdges, + int useSubsurfUv, + DerivedMesh *dm) +{ + CCGDerivedMesh *ccgdm = MEM_callocN(sizeof(*ccgdm), "ccgdm"); + CCGVertIterator *vi; + CCGEdgeIterator *ei; + CCGFaceIterator *fi; + int index, totvert, totedge, totface; + int i; + int vertNum, edgeNum, faceNum; + int *vertOrigIndex, *edgeOrigIndex, *faceOrigIndex; + int *edgeFlags; + char *faceFlags; + int edgeSize; + int gridSize; + int gridFaces; + int gridSideVerts; + int gridInternalVerts; + int gridSideEdges; + int gridInternalEdges; + MVert *mvert = NULL; + MEdge *medge = NULL; + MFace *mface = NULL; + FaceVertWeight *qweight, *tweight; + + DM_from_template(&ccgdm->dm, dm, ccgSubSurf_getNumFinalVerts(ss), + ccgSubSurf_getNumFinalEdges(ss), + ccgSubSurf_getNumFinalFaces(ss)); + DM_add_face_layer(&ccgdm->dm, CD_FLAGS, CD_CALLOC, NULL); + DM_add_edge_layer(&ccgdm->dm, CD_FLAGS, CD_CALLOC, NULL); + + CustomData_set_layer_flag(&ccgdm->dm.faceData, CD_FLAGS, CD_FLAG_NOCOPY); + CustomData_set_layer_flag(&ccgdm->dm.edgeData, CD_FLAGS, CD_FLAG_NOCOPY); + + ccgdm->dm.getMinMax = ccgDM_getMinMax; + ccgdm->dm.getNumVerts = ccgDM_getNumVerts; + ccgdm->dm.getNumFaces = ccgDM_getNumFaces; + + ccgdm->dm.getNumEdges = ccgDM_getNumEdges; + ccgdm->dm.getVert = ccgDM_getFinalVert; + ccgdm->dm.getEdge = ccgDM_getFinalEdge; + ccgdm->dm.getFace = ccgDM_getFinalFace; + ccgdm->dm.copyVertArray = ccgDM_copyFinalVertArray; + ccgdm->dm.copyEdgeArray = ccgDM_copyFinalEdgeArray; + ccgdm->dm.copyFaceArray = ccgDM_copyFinalFaceArray; + ccgdm->dm.getVertData = DM_get_vert_data; + ccgdm->dm.getEdgeData = DM_get_edge_data; + ccgdm->dm.getFaceData = DM_get_face_data; + ccgdm->dm.getVertDataArray = DM_get_vert_data_layer; + ccgdm->dm.getEdgeDataArray = DM_get_edge_data_layer; + ccgdm->dm.getFaceDataArray = DM_get_face_data_layer; + + ccgdm->dm.getVertCos = ccgdm_getVertCos; + ccgdm->dm.foreachMappedVert = ccgDM_foreachMappedVert; + ccgdm->dm.foreachMappedEdge = ccgDM_foreachMappedEdge; + ccgdm->dm.foreachMappedFaceCenter = ccgDM_foreachMappedFaceCenter; + + ccgdm->dm.drawVerts = ccgDM_drawVerts; + ccgdm->dm.drawEdges = ccgDM_drawEdges; + ccgdm->dm.drawLooseEdges = ccgDM_drawLooseEdges; + ccgdm->dm.drawFacesSolid = ccgDM_drawFacesSolid; + ccgdm->dm.drawFacesColored = ccgDM_drawFacesColored; + ccgdm->dm.drawFacesTex = ccgDM_drawFacesTex; + ccgdm->dm.drawMappedFaces = ccgDM_drawMappedFaces; + ccgdm->dm.drawMappedFacesTex = ccgDM_drawMappedFacesTex; + ccgdm->dm.drawUVEdges = ccgDM_drawUVEdges; + + ccgdm->dm.drawMappedEdgesInterp = ccgDM_drawMappedEdgesInterp; + ccgdm->dm.drawMappedEdges = ccgDM_drawMappedEdges; + + ccgdm->dm.release = ccgDM_release; + + ccgdm->ss = ss; + ccgdm->drawInteriorEdges = drawInteriorEdges; + ccgdm->useSubsurfUv = useSubsurfUv; + + totvert = ccgSubSurf_getNumVerts(ss); + ccgdm->vertMap = MEM_mallocN(totvert * sizeof(*ccgdm->vertMap), "vertMap"); + vi = ccgSubSurf_getVertIterator(ss); + for(; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) { + CCGVert *v = ccgVertIterator_getCurrent(vi); + + ccgdm->vertMap[(int) ccgSubSurf_getVertVertHandle(ss, v)].vert = v; + } + ccgVertIterator_free(vi); + + totedge = ccgSubSurf_getNumEdges(ss); + ccgdm->edgeMap = MEM_mallocN(totedge * sizeof(*ccgdm->edgeMap), "edgeMap"); + ei = ccgSubSurf_getEdgeIterator(ss); + for(; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) { + CCGEdge *e = ccgEdgeIterator_getCurrent(ei); + + ccgdm->edgeMap[(int) ccgSubSurf_getEdgeEdgeHandle(ss, e)].edge = e; + } + + totface = ccgSubSurf_getNumFaces(ss); + ccgdm->faceMap = MEM_mallocN(totface * sizeof(*ccgdm->faceMap), "faceMap"); + fi = ccgSubSurf_getFaceIterator(ss); + for(; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { + CCGFace *f = ccgFaceIterator_getCurrent(fi); + + ccgdm->faceMap[(int) ccgSubSurf_getFaceFaceHandle(ss, f)].face = f; + } + ccgFaceIterator_free(fi); + + edgeSize = ccgSubSurf_getEdgeSize(ss); + gridSize = ccgSubSurf_getGridSize(ss); + gridFaces = gridSize - 1; + gridSideVerts = gridSize - 2; + gridInternalVerts = gridSideVerts * gridSideVerts; + gridSideEdges = gridSize - 1; + gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2; + + calc_ss_weights(gridFaces, &qweight, &tweight); + + vertNum = 0; + edgeNum = 0; + faceNum = 0; + + mvert = dm->getVertArray(dm); + medge = dm->getEdgeArray(dm); + mface = dm->getFaceArray(dm); + + vertOrigIndex = DM_get_vert_data_layer(&ccgdm->dm, CD_ORIGINDEX); + edgeOrigIndex = DM_get_edge_data_layer(&ccgdm->dm, CD_ORIGINDEX); + faceOrigIndex = DM_get_face_data_layer(&ccgdm->dm, CD_ORIGINDEX); + + faceFlags = DM_get_face_data_layer(&ccgdm->dm, CD_FLAGS); + + for(index = 0; index < totface; ++index) { + CCGFace *f = ccgdm->faceMap[index].face; + int numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + int numFinalEdges = numVerts * (gridSideEdges + gridInternalEdges); + int mapIndex = ccgDM_getFaceMapIndex(ccgdm, ss, f); + int origIndex = (int)ccgSubSurf_getFaceFaceHandle(ss, f); + FaceVertWeight *weight = (numVerts == 4) ? qweight : tweight; + int S, x, y; + int vertIdx[4]; + + ccgdm->faceMap[index].startVert = vertNum; + ccgdm->faceMap[index].startEdge = edgeNum; + ccgdm->faceMap[index].startFace = faceNum; + + /* set the face base vert */ + *((int*)ccgSubSurf_getFaceUserData(ss, f)) = vertNum; + + for(S = 0; S < numVerts; S++) { + CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S); + + vertIdx[S] = (int)ccgSubSurf_getVertVertHandle(ss, v); + } + + DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, weight[0][0], + numVerts, vertNum); + *vertOrigIndex = ORIGINDEX_NONE; + ++vertOrigIndex; + ++vertNum; + + for(S = 0; S < numVerts; S++) { + int prevS = (S - 1 + numVerts) % numVerts; + int nextS = (S + 1) % numVerts; + int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3; + for(x = 1; x < gridFaces; x++) { + float w[4]; + w[prevS] = weight[x][0][0]; + w[S] = weight[x][0][1]; + w[nextS] = weight[x][0][2]; + w[otherS] = weight[x][0][3]; + DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, w, + numVerts, vertNum); + *vertOrigIndex = ORIGINDEX_NONE; + ++vertOrigIndex; + ++vertNum; + } + } + + for(S = 0; S < numVerts; S++) { + int prevS = (S - 1 + numVerts) % numVerts; + int nextS = (S + 1) % numVerts; + int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3; + for(y = 1; y < gridFaces; y++) { + for(x = 1; x < gridFaces; x++) { + float w[4]; + w[prevS] = weight[y * gridFaces + x][0][0]; + w[S] = weight[y * gridFaces + x][0][1]; + w[nextS] = weight[y * gridFaces + x][0][2]; + w[otherS] = weight[y * gridFaces + x][0][3]; + DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, w, + numVerts, vertNum); + *vertOrigIndex = ORIGINDEX_NONE; + ++vertOrigIndex; + ++vertNum; + } + } + } + + for(i = 0; i < numFinalEdges; ++i) + *(int *)DM_get_edge_data(&ccgdm->dm, edgeNum + i, + CD_ORIGINDEX) = ORIGINDEX_NONE; + + for(S = 0; S < numVerts; S++) { + int prevS = (S - 1 + numVerts) % numVerts; + int nextS = (S + 1) % numVerts; + int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3; + + weight = (numVerts == 4) ? qweight : tweight; + + for(y = 0; y < gridFaces; y++) { + for(x = 0; x < gridFaces; x++) { + FaceVertWeight w; + int j; + + for(j = 0; j < 4; ++j) { + w[j][prevS] = (*weight)[j][0]; + w[j][S] = (*weight)[j][1]; + w[j][nextS] = (*weight)[j][2]; + w[j][otherS] = (*weight)[j][3]; + } + + DM_interp_face_data(dm, &ccgdm->dm, &origIndex, NULL, + &w, 1, faceNum); + weight++; + + *faceOrigIndex = mapIndex; + + ++faceOrigIndex; + ++faceNum; + } + } + } + + faceFlags[index*4] = mface[origIndex].flag; + faceFlags[index*4 + 1] = mface[origIndex].mat_nr; + + edgeNum += numFinalEdges; + } + + if(useSubsurfUv) { + CustomData *fdata = &ccgdm->dm.faceData; + CustomData *dmfdata = &dm->faceData; + int numlayer = CustomData_number_of_layers(fdata, CD_MTFACE); + int dmnumlayer = CustomData_number_of_layers(dmfdata, CD_MTFACE); + + for (i=0; idm, i); + } + + edgeFlags = DM_get_edge_data_layer(&ccgdm->dm, CD_FLAGS); + + for(index = 0; index < totedge; ++index) { + CCGEdge *e = ccgdm->edgeMap[index].edge; + int numFinalEdges = edgeSize - 1; + int mapIndex = ccgDM_getEdgeMapIndex(ccgdm, ss, e); + int x; + int vertIdx[2]; + int edgeIdx = (int)ccgSubSurf_getEdgeEdgeHandle(ss, e); + + CCGVert *v; + v = ccgSubSurf_getEdgeVert0(ss, e); + vertIdx[0] = (int)ccgSubSurf_getVertVertHandle(ss, v); + v = ccgSubSurf_getEdgeVert1(ss, e); + vertIdx[1] = (int)ccgSubSurf_getVertVertHandle(ss, v); + + ccgdm->edgeMap[index].startVert = vertNum; + ccgdm->edgeMap[index].startEdge = edgeNum; + + /* set the edge base vert */ + *((int*)ccgSubSurf_getEdgeUserData(ss, e)) = vertNum; + + for(x = 1; x < edgeSize - 1; x++) { + float w[2]; + w[1] = (float) x / (edgeSize - 1); + w[0] = 1 - w[1]; + DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, w, 2, vertNum); + *vertOrigIndex = ORIGINDEX_NONE; + ++vertOrigIndex; + ++vertNum; + } + + for(i = 0; i < numFinalEdges; ++i) { + if(edgeIdx >= 0 && edgeFlags) + edgeFlags[edgeNum + i] = medge[edgeIdx].flag; + + *(int *)DM_get_edge_data(&ccgdm->dm, edgeNum + i, + CD_ORIGINDEX) = mapIndex; + } + + edgeNum += numFinalEdges; + } + + for(index = 0; index < totvert; ++index) { + CCGVert *v = ccgdm->vertMap[index].vert; + int mapIndex = ccgDM_getVertMapIndex(ccgdm, ccgdm->ss, v); + int vertIdx; + + vertIdx = (int)ccgSubSurf_getVertVertHandle(ss, v); + + ccgdm->vertMap[index].startVert = vertNum; + + /* set the vert base vert */ + *((int*) ccgSubSurf_getVertUserData(ss, v)) = vertNum; + + DM_copy_vert_data(dm, &ccgdm->dm, vertIdx, vertNum, 1); + + *vertOrigIndex = mapIndex; + ++vertOrigIndex; + ++vertNum; + } + + MEM_freeN(qweight); + MEM_freeN(tweight); + + return ccgdm; +} + +/***/ + +struct DerivedMesh *subsurf_make_derived_from_derived( + struct DerivedMesh *dm, + struct SubsurfModifierData *smd, + int useRenderParams, float (*vertCos)[3], + int isFinalCalc, int editMode) +{ + int useSimple = smd->subdivType == ME_SIMPLE_SUBSURF; + int useAging = smd->flags & eSubsurfModifierFlag_DebugIncr; + int useSubsurfUv = smd->flags & eSubsurfModifierFlag_SubsurfUv; + int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges); + DerivedMesh *result; + + if(editMode) { + smd->emCache = _getSubSurf(smd->emCache, smd->levels, useAging, 0, + useSimple); + ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple); + + return (DerivedMesh *)getCCGDerivedMesh(smd->emCache, + drawInteriorEdges, + useSubsurfUv, dm); + } else if(useRenderParams) { + /* Do not use cache in render mode. */ + CCGSubSurf *ss = _getSubSurf(NULL, smd->renderLevels, 0, 1, useSimple); + + ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple); + + result = ss_to_cdderivedmesh(ss, 0, drawInteriorEdges, + useSubsurfUv, dm); + + ccgSubSurf_free(ss); + + return result; + } else { + int useIncremental = (smd->flags & eSubsurfModifierFlag_Incremental); + int useAging = smd->flags & eSubsurfModifierFlag_DebugIncr; + CCGSubSurf *ss; + + /* It is quite possible there is a much better place to do this. It + * depends a bit on how rigourously we expect this function to never + * be called in editmode. In semi-theory we could share a single + * cache, but the handles used inside and outside editmode are not + * the same so we would need some way of converting them. Its probably + * not worth the effort. But then why am I even writing this long + * comment that no one will read? Hmmm. - zr + */ + if(smd->emCache) { + ccgSubSurf_free(smd->emCache); + smd->emCache = NULL; + } + + if(useIncremental && isFinalCalc) { + smd->mCache = ss = _getSubSurf(smd->mCache, smd->levels, + useAging, 0, useSimple); + + ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple); + + + return ss_to_cdderivedmesh(ss, 0, drawInteriorEdges, + useSubsurfUv, dm); + + /*return (DerivedMesh *)getCCGDerivedMesh(smd->mCache, + drawInteriorEdges, + useSubsurfUv, dm);*/ + } else { + if (smd->mCache && isFinalCalc) { + ccgSubSurf_free(smd->mCache); + smd->mCache = NULL; + } + + ss = _getSubSurf(NULL, smd->levels, 0, 1, useSimple); + ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple); + + /*smd->mCache = ss; + result = (DerivedMesh *)getCCGDerivedMesh(smd->mCache, + drawInteriorEdges, + useSubsurfUv, dm);*/ + + result = ss_to_cdderivedmesh(ss, 0, drawInteriorEdges, + useSubsurfUv, dm); + + ccgSubSurf_free(ss); + + return result; + } + } +} + +void subsurf_calculate_limit_positions(Mesh *me, float (*positions_r)[3]) +{ + /* Finds the subsurf limit positions for the verts in a mesh + * and puts them in an array of floats. Please note that the + * calculated vert positions is incorrect for the verts + * on the boundary of the mesh. + */ + CCGSubSurf *ss = _getSubSurf(NULL, 1, 0, 1, 0); + float edge_sum[3], face_sum[3]; + CCGVertIterator *vi; + DerivedMesh *dm = CDDM_from_mesh(me, NULL); + + ss_sync_from_derivedmesh(ss, dm, NULL, 0); + + vi = ccgSubSurf_getVertIterator(ss); + for (; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) { + CCGVert *v = ccgVertIterator_getCurrent(vi); + int idx = (int) ccgSubSurf_getVertVertHandle(ss, v); + int N = ccgSubSurf_getVertNumEdges(ss, v); + int numFaces = ccgSubSurf_getVertNumFaces(ss, v); + float *co; + int i; + + edge_sum[0]= edge_sum[1]= edge_sum[2]= 0.0; + face_sum[0]= face_sum[1]= face_sum[2]= 0.0; + + for (i=0; irelease(dm); +} + diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c new file mode 100644 index 00000000000..ea0dabe1e81 --- /dev/null +++ b/source/blender/blenkernel/intern/text.c @@ -0,0 +1,2393 @@ +/* text.c + * + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include /* strstr */ + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" + +#include "DNA_scene_types.h" +#include "DNA_text_types.h" + +#include "BKE_bad_level_calls.h" +#include "BKE_utildefines.h" +#include "BKE_text.h" +#include "BKE_library.h" +#include "BKE_global.h" +#include "BKE_main.h" + +#include "BPY_extern.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +/***************/ /* + +How Texts should work +-- +A text should relate to a file as follows - +(Text *)->name should be the place where the + file will or has been saved. + +(Text *)->flags has the following bits + TXT_ISDIRTY - should always be set if the file in mem. differs from + the file on disk, or if there is no file on disk. + TXT_ISTMP - should always be set if the (Text *)->name file has not + been written before, and attempts to save should result + in "Save over?" + TXT_ISMEM - should always be set if the Text has not been mapped to + a file, in which case (Text *)->name may be NULL or garbage. + TXT_ISEXT - should always be set if the Text is not to be written into + the .blend + TXT_ISSCRIPT - should be set if the user has designated the text + as a script. (NEW: this was unused, but now it is needed by + space handler script links (see header_view3d.c, for example) + +->>> see also: /makesdna/DNA_text_types.h + +Display +-- +The st->top determines at what line the top of the text is displayed. +If the user moves the cursor the st containing that cursor should +be popped ... other st's retain their own top location. + +*/ /***************/ + + +/****************/ /* + Undo + +Undo/Redo works by storing +events in a queue, and a pointer +to the current position in the +queue... + +Events are stored using an +arbitrary op-code system +to keep track of +a) the two cursors (normal and selected) +b) input (visible and control (ie backspace)) + +input data is stored as its +ASCII value, the opcodes are +then selected to not conflict. + +opcodes with data in between are +written at the beginning and end +of the data to allow undo and redo +to simply check the code at the current +undo position + +*/ /***************/ + +/***/ + +static void txt_pop_first(Text *text); +static void txt_pop_last(Text *text); +static void txt_undo_add_op(Text *text, int op); +static void txt_undo_add_block(Text *text, int op, char *buf); +static void txt_delete_line(Text *text, TextLine *line); + +/***/ + +static char *txt_cut_buffer= NULL; +static unsigned char undoing; + +/* allow to switch off undoing externally */ +void txt_set_undostate(int u) +{ + undoing = u; +} + +int txt_get_undostate(void) +{ + return undoing; +} + +void free_text(Text *text) +{ + TextLine *tmp; + + for (tmp= text->lines.first; tmp; tmp= tmp->next) { + MEM_freeN(tmp->line); + if (tmp->format) + MEM_freeN(tmp->format); + } + + BLI_freelistN(&text->lines); + + if(text->name) MEM_freeN(text->name); + MEM_freeN(text->undo_buf); + if (text->compiled) BPY_free_compiled_text(text); +} + +Text *add_empty_text(char *name) +{ + Text *ta; + TextLine *tmp; + + ta= alloc_libblock(&G.main->text, ID_TXT, name); + ta->id.us= 1; + + ta->name= NULL; + + ta->undo_pos= -1; + ta->undo_len= TXT_INIT_UNDO; + ta->undo_buf= MEM_mallocN(ta->undo_len, "undo buf"); + + ta->nlines=1; + ta->flags= TXT_ISDIRTY | TXT_ISTMP | TXT_ISMEM; + + ta->lines.first= ta->lines.last= NULL; + + tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline"); + tmp->line= (char*) MEM_mallocN(1, "textline_string"); + tmp->format= (char*) MEM_mallocN(2, "Syntax_format"); + + tmp->line[0]=0; + tmp->len= 0; + + tmp->next= NULL; + tmp->prev= NULL; + + BLI_addhead(&ta->lines, tmp); + + ta->curl= ta->lines.first; + ta->curc= 0; + ta->sell= ta->lines.first; + ta->selc= 0; + + return ta; +} + +// this function removes any control characters from +// a textline + +static void cleanup_textline(TextLine * tl) +{ + int i; + + for (i = 0; i < tl->len; i++ ) { + if (tl->line[i] < ' ' && tl->line[i] != '\t') { + memmove(tl->line + i, tl->line + i + 1, tl->len - i); + tl->len--; + i--; + } + } +} + +int reopen_text(Text *text) +{ + FILE *fp; + int i, llen, len; + unsigned char *buffer; + TextLine *tmp; + char sdir[FILE_MAXDIR]; + char sfile[FILE_MAXFILE]; + char str[FILE_MAXDIR+FILE_MAXFILE]; + + if (!text || !text->name) return 0; + + BLI_strncpy(str, text->name, FILE_MAXDIR+FILE_MAXFILE); + BLI_convertstringcode(str, G.sce, G.scene->r.cfra); + BLI_split_dirfile(str, sdir, sfile); + + fp= fopen(str, "r"); + if(fp==NULL) return 0; + + /* free memory: */ + + for (tmp= text->lines.first; tmp; tmp= tmp->next) { + MEM_freeN(tmp->line); + if (tmp->format) MEM_freeN(tmp->format); + } + + BLI_freelistN(&text->lines); + + text->lines.first= text->lines.last= NULL; + text->curl= text->sell= NULL; + + /* clear undo buffer */ + MEM_freeN(text->undo_buf); + text->undo_pos= -1; + text->undo_len= TXT_INIT_UNDO; + text->undo_buf= MEM_mallocN(text->undo_len, "undo buf"); + + text->flags= TXT_ISDIRTY | TXT_ISTMP; + + fseek(fp, 0L, SEEK_END); + len= ftell(fp); + fseek(fp, 0L, SEEK_SET); + + text->undo_pos= -1; + + buffer= MEM_mallocN(len, "text_buffer"); + // under windows fread can return less then len bytes because + // of CR stripping + len = fread(buffer, 1, len, fp); + + fclose(fp); + + text->nlines=0; + i=0; + llen=0; + for(i=0; iline= (char*) MEM_mallocN(llen+1, "textline_string"); + tmp->format= (char*) MEM_mallocN(llen+2, "Syntax_format"); + + if(llen) memcpy(tmp->line, &buffer[i-llen], llen); + tmp->line[llen]=0; + tmp->len= llen; + + cleanup_textline(tmp); + + BLI_addtail(&text->lines, tmp); + text->nlines++; + + llen=0; + continue; + } + llen++; + } + + if (llen!=0 || text->nlines==0) { + tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline"); + tmp->line= (char*) MEM_mallocN(llen+1, "textline_string"); + tmp->format= (char*) MEM_mallocN(llen+2, "Syntax_format"); + + if(llen) memcpy(tmp->line, &buffer[i-llen], llen); + + tmp->line[llen]=0; + tmp->len= llen; + + cleanup_textline(tmp); + + BLI_addtail(&text->lines, tmp); + text->nlines++; + } + + text->curl= text->sell= text->lines.first; + text->curc= text->selc= 0; + + MEM_freeN(buffer); + return 1; +} + +Text *add_text(char *file) +{ + FILE *fp; + int i, llen, len; + unsigned char *buffer; + TextLine *tmp; + Text *ta; + char sdir[FILE_MAXDIR]; + char sfile[FILE_MAXFILE]; + char str[FILE_MAXDIR+FILE_MAXFILE]; + + BLI_strncpy(str, file, FILE_MAXDIR+FILE_MAXFILE); + if (G.scene) /* can be NULL (bg mode) */ + BLI_convertstringcode(str, G.sce, G.scene->r.cfra); + BLI_split_dirfile(str, sdir, sfile); + + fp= fopen(str, "r"); + if(fp==NULL) return NULL; + + ta= alloc_libblock(&G.main->text, ID_TXT, sfile); + ta->id.us= 1; + + ta->lines.first= ta->lines.last= NULL; + ta->curl= ta->sell= NULL; + +/* ta->flags= TXT_ISTMP | TXT_ISEXT; */ + ta->flags= TXT_ISTMP; + + fseek(fp, 0L, SEEK_END); + len= ftell(fp); + fseek(fp, 0L, SEEK_SET); + + ta->name= MEM_mallocN(strlen(file)+1, "text_name"); + strcpy(ta->name, file); + + ta->undo_pos= -1; + ta->undo_len= TXT_INIT_UNDO; + ta->undo_buf= MEM_mallocN(ta->undo_len, "undo buf"); + + buffer= MEM_mallocN(len, "text_buffer"); + // under windows fread can return less then len bytes because + // of CR stripping + len = fread(buffer, 1, len, fp); + + fclose(fp); + + ta->nlines=0; + i=0; + llen=0; + for(i=0; iline= (char*) MEM_mallocN(llen+1, "textline_string"); + tmp->format= (char*) MEM_mallocN(llen+2, "Syntax_format"); + + if(llen) memcpy(tmp->line, &buffer[i-llen], llen); + tmp->line[llen]=0; + tmp->len= llen; + + cleanup_textline(tmp); + + BLI_addtail(&ta->lines, tmp); + ta->nlines++; + + llen=0; + continue; + } + llen++; + } + + if (llen!=0 || ta->nlines==0) { + tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline"); + tmp->line= (char*) MEM_mallocN(llen+1, "textline_string"); + tmp->format= (char*) MEM_mallocN(llen+2, "Syntax_format"); + + if(llen) memcpy(tmp->line, &buffer[i-llen], llen); + + tmp->line[llen]=0; + tmp->len= llen; + + cleanup_textline(tmp); + + BLI_addtail(&ta->lines, tmp); + ta->nlines++; + } + + ta->curl= ta->sell= ta->lines.first; + ta->curc= ta->selc= 0; + + MEM_freeN(buffer); + + return ta; +} + +Text *copy_text(Text *ta) +{ + Text *tan; + TextLine *line, *tmp; + + tan= copy_libblock(ta); + + tan->name= MEM_mallocN(strlen(ta->name)+1, "text_name"); + strcpy(tan->name, ta->name); + + tan->flags = ta->flags | TXT_ISDIRTY | TXT_ISTMP; + + tan->lines.first= tan->lines.last= NULL; + tan->curl= tan->sell= NULL; + + tan->nlines= ta->nlines; + + line= ta->lines.first; + /* Walk down, reconstructing */ + while (line) { + tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline"); + tmp->line= MEM_mallocN(line->len+1, "textline_string"); + tmp->format= MEM_mallocN(line->len+2, "Syntax_format"); + + strcpy(tmp->line, line->line); + + tmp->len= line->len; + + BLI_addtail(&tan->lines, tmp); + + line= line->next; + } + + tan->curl= tan->sell= tan->lines.first; + tan->curc= tan->selc= 0; + + return tan; +} + +/*****************************/ +/* Editing utility functions */ +/*****************************/ + +static void make_new_line (TextLine *line, char *newline, char *newformat) +{ + if (line->line) MEM_freeN(line->line); + if (line->format) MEM_freeN(line->format); + + line->line= newline; + line->len= strlen(newline); + line->format= newformat; +} + +static TextLine *txt_new_line(char *str) +{ + TextLine *tmp; + + if(!str) str= ""; + + tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline"); + tmp->line= MEM_mallocN(strlen(str)+1, "textline_string"); + tmp->format= MEM_mallocN(strlen(str)+2, "Syntax_format"); + + strcpy(tmp->line, str); + + tmp->len= strlen(str); + tmp->next= tmp->prev= NULL; + + return tmp; +} + +static TextLine *txt_new_linen(char *str, int n) +{ + TextLine *tmp; + + if(!str) str= ""; + + tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline"); + tmp->line= MEM_mallocN(n+1, "textline_string"); + tmp->format= MEM_mallocN(n+2, "Syntax_format"); + + BLI_strncpy(tmp->line, str, n+1); + + tmp->len= strlen(tmp->line); + tmp->next= tmp->prev= NULL; + + return tmp; +} + +void txt_clean_text (Text *text) +{ + TextLine **top, **bot; + + if (!text) return; + + if (!text->lines.first) { + if (text->lines.last) text->lines.first= text->lines.last; + else text->lines.first= text->lines.last= txt_new_line(NULL); + } + + if (!text->lines.last) text->lines.last= text->lines.first; + + top= (TextLine **) &text->lines.first; + bot= (TextLine **) &text->lines.last; + + while ((*top)->prev) *top= (*top)->prev; + while ((*bot)->next) *bot= (*bot)->next; + + if(!text->curl) { + if(text->sell) text->curl= text->sell; + else text->curl= text->lines.first; + text->curc= 0; + } + + if(!text->sell) { + text->sell= text->curl; + text->selc= 0; + } +} + +int txt_get_span (TextLine *from, TextLine *to) +{ + int ret=0; + TextLine *tmp= from; + + if (!to || !from) return 0; + if (from==to) return 0; + + /* Look forwards */ + while (tmp) { + if (tmp == to) return ret; + ret++; + tmp= tmp->next; + } + + /* Look backwards */ + if (!tmp) { + tmp= from; + ret=0; + while(tmp) { + if (tmp == to) break; + ret--; + tmp= tmp->prev; + } + if(!tmp) ret=0; + } + + return ret; +} + +static void txt_make_dirty (Text *text) +{ + text->flags |= TXT_ISDIRTY; + if (text->compiled) BPY_free_compiled_text(text); +} + +/****************************/ +/* Cursor utility functions */ +/****************************/ + +static void txt_curs_cur (Text *text, TextLine ***linep, int **charp) +{ + *linep= &text->curl; *charp= &text->curc; +} + +static void txt_curs_sel (Text *text, TextLine ***linep, int **charp) +{ + *linep= &text->sell; *charp= &text->selc; +} + +static void txt_curs_first (Text *text, TextLine **linep, int *charp) +{ + if (text->curl==text->sell) { + *linep= text->curl; + if (text->curcselc) *charp= text->curc; + else *charp= text->selc; + } else if (txt_get_span(text->lines.first, text->curl)lines.first, text->sell)) { + *linep= text->curl; + *charp= text->curc; + } else { + *linep= text->sell; + *charp= text->selc; + } +} + +/****************************/ +/* Cursor movement functions */ +/****************************/ + +void txt_move_up(Text *text, short sel) +{ + TextLine **linep; + int *charp, old; + + if (!text) return; + if(sel) txt_curs_sel(text, &linep, &charp); + else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); } + if (!*linep) return; + old= *charp; + + if((*linep)->prev) { + *linep= (*linep)->prev; + if (*charp > (*linep)->len) { + *charp= (*linep)->len; + if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, (*linep)->next), old, txt_get_span(text->lines.first, *linep), (unsigned short) *charp); + } else { + if(!undoing) txt_undo_add_op(text, sel?UNDO_SUP:UNDO_CUP); + } + } else { + *charp= 0; + if(!undoing) txt_undo_add_op(text, sel?UNDO_SUP:UNDO_CUP); + } + + if(!sel) txt_pop_sel(text); +} + +void txt_move_down(Text *text, short sel) +{ + TextLine **linep; + int *charp, old; + + if (!text) return; + if(sel) txt_curs_sel(text, &linep, &charp); + else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); } + if (!*linep) return; + old= *charp; + + if((*linep)->next) { + *linep= (*linep)->next; + if (*charp > (*linep)->len) { + *charp= (*linep)->len; + if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, (*linep)->prev), old, txt_get_span(text->lines.first, *linep), (unsigned short)*charp); + } else + if(!undoing) txt_undo_add_op(text, sel?UNDO_SDOWN:UNDO_CDOWN); + } else { + *charp= (*linep)->len; + if(!undoing) txt_undo_add_op(text, sel?UNDO_SDOWN:UNDO_CDOWN); + } + + if(!sel) txt_pop_sel(text); +} + +void txt_move_left(Text *text, short sel) +{ + TextLine **linep; + int *charp, oundoing= undoing; + + if (!text) return; + if(sel) txt_curs_sel(text, &linep, &charp); + else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); } + if (!*linep) return; + + undoing= 1; + if (*charp== 0) { + if ((*linep)->prev) { + txt_move_up(text, sel); + *charp= (*linep)->len; + } + } else { + (*charp)--; + } + undoing= oundoing; + if(!undoing) txt_undo_add_op(text, sel?UNDO_SLEFT:UNDO_CLEFT); + + if(!sel) txt_pop_sel(text); +} + +void txt_move_right(Text *text, short sel) +{ + TextLine **linep; + int *charp, oundoing= undoing; + + if (!text) return; + if(sel) txt_curs_sel(text, &linep, &charp); + else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); } + if (!*linep) return; + + undoing= 1; + if (*charp== (*linep)->len) { + if ((*linep)->next) { + txt_move_down(text, sel); + *charp= 0; + } + } else { + (*charp)++; + } + undoing= oundoing; + if(!undoing) txt_undo_add_op(text, sel?UNDO_SRIGHT:UNDO_CRIGHT); + + if(!sel) txt_pop_sel(text); +} + +void txt_move_bol (Text *text, short sel) +{ + TextLine **linep; + int *charp, old; + + if (!text) return; + if(sel) txt_curs_sel(text, &linep, &charp); + else txt_curs_cur(text, &linep, &charp); + if (!*linep) return; + old= *charp; + + *charp= 0; + + if(!sel) txt_pop_sel(text); + if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, *linep), old, txt_get_span(text->lines.first, *linep), (unsigned short)*charp); +} + +void txt_move_eol (Text *text, short sel) +{ + TextLine **linep; + int *charp, old; + + if (!text) return; + if(sel) txt_curs_sel(text, &linep, &charp); + else txt_curs_cur(text, &linep, &charp); + if (!*linep) return; + old= *charp; + + *charp= (*linep)->len; + + if(!sel) txt_pop_sel(text); + if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, *linep), old, txt_get_span(text->lines.first, *linep), (unsigned short)*charp); +} + +void txt_move_bof (Text *text, short sel) +{ + TextLine **linep; + int *charp, old; + + if (!text) return; + if(sel) txt_curs_sel(text, &linep, &charp); + else txt_curs_cur(text, &linep, &charp); + if (!*linep) return; + old= *charp; + + *linep= text->lines.first; + *charp= 0; + + if(!sel) txt_pop_sel(text); + if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, *linep), old, txt_get_span(text->lines.first, *linep), (unsigned short)*charp); +} + +void txt_move_eof (Text *text, short sel) +{ + TextLine **linep; + int *charp, old; + + if (!text) return; + if(sel) txt_curs_sel(text, &linep, &charp); + else txt_curs_cur(text, &linep, &charp); + if (!*linep) return; + old= *charp; + + *linep= text->lines.last; + *charp= (*linep)->len; + + if(!sel) txt_pop_sel(text); + if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, *linep), old, txt_get_span(text->lines.first, *linep), (unsigned short)*charp); +} + +void txt_move_toline (Text *text, unsigned int line, short sel) +{ + TextLine **linep, *oldl; + int *charp, oldc; + unsigned int i; + + if (!text) return; + if(sel) txt_curs_sel(text, &linep, &charp); + else txt_curs_cur(text, &linep, &charp); + if (!*linep) return; + oldc= *charp; + oldl= *linep; + + *linep= text->lines.first; + for (i=0; inext) *linep= (*linep)->next; + else break; + } + *charp= 0; + + if(!sel) txt_pop_sel(text); + if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, oldl), oldc, txt_get_span(text->lines.first, *linep), (unsigned short)*charp); +} + +/****************************/ +/* Text selection functions */ +/****************************/ + +static void txt_curs_swap (Text *text) +{ + TextLine *tmpl; + int tmpc; + + tmpl= text->curl; + text->curl= text->sell; + text->sell= tmpl; + + tmpc= text->curc; + text->curc= text->selc; + text->selc= tmpc; + + if(!undoing) txt_undo_add_op(text, UNDO_SWAP); +} + +static void txt_pop_first (Text *text) +{ + + if (txt_get_span(text->curl, text->sell)<0 || + (text->curl==text->sell && text->curc>text->selc)) { + txt_curs_swap(text); + } + + if(!undoing) txt_undo_add_toop(text, UNDO_STO, + txt_get_span(text->lines.first, text->sell), + text->selc, + txt_get_span(text->lines.first, text->curl), + text->curc); + + txt_pop_sel(text); +} + +static void txt_pop_last (Text *text) +{ + if (txt_get_span(text->curl, text->sell)>0 || + (text->curl==text->sell && text->curcselc)) { + txt_curs_swap(text); + } + + if(!undoing) txt_undo_add_toop(text, UNDO_STO, + txt_get_span(text->lines.first, text->sell), + text->selc, + txt_get_span(text->lines.first, text->curl), + text->curc); + + txt_pop_sel(text); +} + +/* never used: CVS 1.19 */ +/* static void txt_pop_selr (Text *text) */ + +void txt_pop_sel (Text *text) +{ + text->sell= text->curl; + text->selc= text->curc; +} + +void txt_order_cursors(Text *text) +{ + if (!text) return; + if (!text->curl) return; + if (!text->sell) return; + + /* Flip so text->curl is before text->sell */ + if (txt_get_span(text->curl, text->sell)<0 || + (text->curl==text->sell && text->curc>text->selc)) + txt_curs_swap(text); +} + +int txt_has_sel(Text *text) +{ + return ((text->curl!=text->sell) || (text->curc!=text->selc)); +} + +static void txt_delete_sel (Text *text) +{ + TextLine *tmpl; + char *buf, *format; + + if (!text) return; + if (!text->curl) return; + if (!text->sell) return; + + if (!txt_has_sel(text)) return; + + txt_order_cursors(text); + + if(!undoing) { + buf= txt_sel_to_buf(text); + txt_undo_add_block(text, UNDO_DBLOCK, buf); + MEM_freeN(buf); + } + + buf= MEM_mallocN(text->curc+(text->sell->len - text->selc)+1, "textline_string"); + format= MEM_mallocN(text->curc+(text->sell->len - text->selc)+2, "Syntax_format"); + + strncpy(buf, text->curl->line, text->curc); + strcpy(buf+text->curc, text->sell->line + text->selc); + buf[text->curc+(text->sell->len - text->selc)]=0; + + make_new_line(text->curl, buf, format); + + tmpl= text->sell; + while (tmpl != text->curl) { + tmpl= tmpl->prev; + if (!tmpl) break; + + txt_delete_line(text, tmpl->next); + } + + text->sell= text->curl; + text->selc= text->curc; +} + +void txt_sel_all (Text *text) +{ + if (!text) return; + + text->curl= text->lines.first; + text->curc= 0; + + text->sell= text->lines.last; + text->selc= text->sell->len; +} + +void txt_sel_line (Text *text) +{ + if (!text) return; + if (!text->curl) return; + + text->curc= 0; + text->sell= text->curl; + text->selc= text->sell->len; +} + +/***************************/ +/* Cut and paste functions */ +/***************************/ + +void txt_print_cutbuffer (void) +{ + printf ("Cut buffer\n--\n%s\n--\n", txt_cut_buffer); +} + +char *txt_to_buf (Text *text) +{ + int length; + TextLine *tmp, *linef, *linel; + int charf, charl; + char *buf; + + if (!text) return NULL; + if (!text->curl) return NULL; + if (!text->sell) return NULL; + + linef= text->lines.first; + charf= 0; + + linel= text->lines.last; + charl= linel->len; + + if (linef == text->lines.last) { + length= charl-charf; + + buf= MEM_mallocN(length+2, "text buffer"); + + BLI_strncpy(buf, linef->line + charf, length+1); + buf[length]=0; + } else { + length= linef->len - charf; + length+= charl; + length+= 2; /* For the 2 '\n' */ + + tmp= linef->next; + while (tmp && tmp!= linel) { + length+= tmp->len+1; + tmp= tmp->next; + } + + buf= MEM_mallocN(length+1, "cut buffer"); + + strncpy(buf, linef->line + charf, linef->len-charf); + length= linef->len - charf; + + buf[length++]='\n'; + + tmp= linef->next; + while (tmp && tmp!=linel) { + strncpy(buf+length, tmp->line, tmp->len); + length+= tmp->len; + + buf[length++]='\n'; + + tmp= tmp->next; + } + strncpy(buf+length, linel->line, charl); + length+= charl; + + /* python compiler wants an empty end line */ + buf[length++]='\n'; + buf[length]=0; + } + + return buf; +} + +int txt_find_string(Text *text, char *findstr) +{ + TextLine *tl, *startl; + char *s= NULL; + + if (!text || !text->curl || !text->sell) return 0; + + txt_order_cursors(text); + + tl= startl= text->sell; + + s= strstr(&tl->line[text->selc], findstr); + while (!s) { + tl= tl->next; + if (!tl) + tl= text->lines.first; + + s= strstr(tl->line, findstr); + if (tl==startl) + break; + } + + if (s) { + text->curl= text->sell= tl; + text->curc= (int) (s-tl->line); + text->selc= text->curc + strlen(findstr); + + return 1; + } else + return 0; +} + +void txt_cut_sel (Text *text) +{ + txt_copy_sel(text); + + txt_delete_sel(text); + txt_make_dirty(text); +} + +char *txt_sel_to_buf (Text *text) +{ + char *buf; + int length=0; + TextLine *tmp, *linef, *linel; + int charf, charl; + + if (!text) return NULL; + if (!text->curl) return NULL; + if (!text->sell) return NULL; + + if (text->curl==text->sell) { + linef= linel= text->curl; + + if (text->curc < text->selc) { + charf= text->curc; + charl= text->selc; + } else{ + charf= text->selc; + charl= text->curc; + } + } else if (txt_get_span(text->curl, text->sell)<0) { + linef= text->sell; + linel= text->curl; + + charf= text->selc; + charl= text->curc; + } else { + linef= text->curl; + linel= text->sell; + + charf= text->curc; + charl= text->selc; + } + + if (linef == linel) { + length= charl-charf; + + buf= MEM_mallocN(length+1, "sel buffer"); + + BLI_strncpy(buf, linef->line + charf, length+1); + } else { + length+= linef->len - charf; + length+= charl; + length++; /* For the '\n' */ + + tmp= linef->next; + while (tmp && tmp!= linel) { + length+= tmp->len+1; + tmp= tmp->next; + } + + buf= MEM_mallocN(length+1, "sel buffer"); + + strncpy(buf, linef->line+ charf, linef->len-charf); + length= linef->len-charf; + + buf[length++]='\n'; + + tmp= linef->next; + while (tmp && tmp!=linel) { + strncpy(buf+length, tmp->line, tmp->len); + length+= tmp->len; + + buf[length++]='\n'; + + tmp= tmp->next; + } + strncpy(buf+length, linel->line, charl); + length+= charl; + + buf[length]=0; + } + + return buf; +} + +void txt_copy_sel (Text *text) +{ + int length=0; + TextLine *tmp, *linef, *linel; + int charf, charl; + + if (!text) return; + if (!text->curl) return; + if (!text->sell) return; + + if (!txt_has_sel(text)) return; + + if (txt_cut_buffer) MEM_freeN(txt_cut_buffer); + txt_cut_buffer= NULL; + + if (text->curl==text->sell) { + linef= linel= text->curl; + + if (text->curc < text->selc) { + charf= text->curc; + charl= text->selc; + } else{ + charf= text->selc; + charl= text->curc; + } + } else if (txt_get_span(text->curl, text->sell)<0) { + linef= text->sell; + linel= text->curl; + + charf= text->selc; + charl= text->curc; + } else { + linef= text->curl; + linel= text->sell; + + charf= text->curc; + charl= text->selc; + } + + if (linef == linel) { + length= charl-charf; + + txt_cut_buffer= MEM_mallocN(length+1, "cut buffera"); + + BLI_strncpy(txt_cut_buffer, linef->line + charf, length+1); + } else { + length+= linef->len - charf; + length+= charl; + length++; /* For the '\n' */ + + tmp= linef->next; + while (tmp && tmp!= linel) { + length+= tmp->len+1; + tmp= tmp->next; + } + + txt_cut_buffer= MEM_mallocN(length+1, "cut bufferb"); + + strncpy(txt_cut_buffer, linef->line+ charf, linef->len-charf); + length= linef->len-charf; + + txt_cut_buffer[length++]='\n'; + + tmp= linef->next; + while (tmp && tmp!=linel) { + strncpy(txt_cut_buffer+length, tmp->line, tmp->len); + length+= tmp->len; + + txt_cut_buffer[length++]='\n'; + + tmp= tmp->next; + } + strncpy(txt_cut_buffer+length, linel->line, charl); + length+= charl; + + txt_cut_buffer[length]=0; + } +} + +void txt_insert_buf(Text *text, char *in_buffer) +{ + int i=0, l=0, j, u, len; + TextLine *add; + + if (!text) return; + if (!in_buffer) return; + + txt_delete_sel(text); + + if(!undoing) txt_undo_add_block (text, UNDO_IBLOCK, in_buffer); + + u= undoing; + undoing= 1; + + /* Read the first line (or as close as possible */ + while (in_buffer[i] && in_buffer[i]!='\n') { + txt_add_char(text, in_buffer[i]); + i++; + } + + if (in_buffer[i]=='\n') txt_split_curline(text); + else { undoing = u; return; } + i++; + + /* Read as many full lines as we can */ + len= strlen(in_buffer); + + while (ilines, text->curl, add); + i++; + } else { + for (j= i-l; jundo_pos+x >= text->undo_len) { \ + if(text->undo_len*2 > TXT_MAX_UNDO) { \ + error("Undo limit reached, buffer cleared\n"); \ + MEM_freeN(text->undo_buf); \ + text->undo_len= TXT_INIT_UNDO; \ + text->undo_buf= MEM_mallocN(text->undo_len, "undo buf"); \ + text->undo_pos=-1; \ + return; \ + } else { \ + void *tmp= text->undo_buf; \ + text->undo_buf= MEM_callocN(text->undo_len*2, "undo buf"); \ + memcpy(text->undo_buf, tmp, text->undo_len); \ + text->undo_len*=2; \ + MEM_freeN(tmp); \ + } \ + } + +static void dump_buffer(Text *text) +{ + int i= 0; + + while (i++undo_pos) printf("%d: %d %c\n", i, text->undo_buf[i], text->undo_buf[i]); +} + +void txt_print_undo(Text *text) +{ + int i= 0; + int op; + char *ops; + int linep, charp; + + dump_buffer(text); + + printf ("---< Undo Buffer >---\n"); + + printf ("UndoPosition is %d\n", text->undo_pos); + + while (i<=text->undo_pos) { + op= text->undo_buf[i]; + + if (op==UNDO_CLEFT) { + ops= "Cursor left"; + } else if (op==UNDO_CRIGHT) { + ops= "Cursor right"; + } else if (op==UNDO_CUP) { + ops= "Cursor up"; + } else if (op==UNDO_CDOWN) { + ops= "Cursor down"; + } else if (op==UNDO_SLEFT) { + ops= "Selection left"; + } else if (op==UNDO_SRIGHT) { + ops= "Selection right"; + } else if (op==UNDO_SUP) { + ops= "Selection up"; + } else if (op==UNDO_SDOWN) { + ops= "Selection down"; + } else if (op==UNDO_STO) { + ops= "Selection "; + } else if (op==UNDO_CTO) { + ops= "Cursor "; + } else if (op==UNDO_INSERT) { + ops= "Insert"; + } else if (op==UNDO_BS) { + ops= "Backspace"; + } else if (op==UNDO_DEL) { + ops= "Delete"; + } else if (op==UNDO_SWAP) { + ops= "Cursor swap"; + } else if (op==UNDO_DBLOCK) { + ops= "Delete text block"; + } else if (op==UNDO_IBLOCK) { + ops= "Insert text block"; + } else if (op==UNDO_INDENT) { + ops= "Indent "; + } else if (op==UNDO_UNINDENT) { + ops= "Unindent "; + } else if (op==UNDO_COMMENT) { + ops= "Comment "; + } else if (op==UNDO_UNCOMMENT) { + ops= "Uncomment "; + } else { + ops= "Unknown"; + } + + printf ("Op (%o) at %d = %s", op, i, ops); + if (op==UNDO_INSERT || op==UNDO_BS || op==UNDO_DEL) { + i++; + printf (" - Char is %c", text->undo_buf[i]); + i++; + } else if (op==UNDO_STO || op==UNDO_CTO) { + i++; + + charp= text->undo_buf[i]; i++; + charp= charp+(text->undo_buf[i]<<8); i++; + + linep= text->undo_buf[i]; i++; + linep= linep+(text->undo_buf[i]<<8); i++; + linep= linep+(text->undo_buf[i]<<16); i++; + linep= linep+(text->undo_buf[i]<<24); i++; + + printf ("to <%d, %d> ", linep, charp); + + charp= text->undo_buf[i]; i++; + charp= charp+(text->undo_buf[i]<<8); i++; + + linep= text->undo_buf[i]; i++; + linep= linep+(text->undo_buf[i]<<8); i++; + linep= linep+(text->undo_buf[i]<<16); i++; + linep= linep+(text->undo_buf[i]<<24); i++; + + printf ("from <%d, %d>", linep, charp); + } else if (op==UNDO_DBLOCK || op==UNDO_IBLOCK) { + i++; + + linep= text->undo_buf[i]; i++; + linep= linep+(text->undo_buf[i]<<8); i++; + linep= linep+(text->undo_buf[i]<<16); i++; + linep= linep+(text->undo_buf[i]<<24); i++; + + printf (" (length %d) <", linep); + + while (linep>0) { + putchar(text->undo_buf[i]); + linep--; i++; + } + + linep= text->undo_buf[i]; i++; + linep= linep+(text->undo_buf[i]<<8); i++; + linep= linep+(text->undo_buf[i]<<16); i++; + linep= linep+(text->undo_buf[i]<<24); i++; + printf ("> (%d)", linep); + } else if (op==UNDO_INDENT || op==UNDO_UNINDENT) { + i++; + + charp= text->undo_buf[i]; i++; + charp= charp+(text->undo_buf[i]<<8); i++; + + linep= text->undo_buf[i]; i++; + linep= linep+(text->undo_buf[i]<<8); i++; + linep= linep+(text->undo_buf[i]<<16); i++; + linep= linep+(text->undo_buf[i]<<24); i++; + + printf ("to <%d, %d> ", linep, charp); + + charp= text->undo_buf[i]; i++; + charp= charp+(text->undo_buf[i]<<8); i++; + + linep= text->undo_buf[i]; i++; + linep= linep+(text->undo_buf[i]<<8); i++; + linep= linep+(text->undo_buf[i]<<16); i++; + linep= linep+(text->undo_buf[i]<<24); i++; + + printf ("from <%d, %d>", linep, charp); + } + + printf (" %d\n", i); + i++; + } +} + +static void txt_undo_add_op(Text *text, int op) +{ + MAX_UNDO_TEST(2); + + text->undo_pos++; + text->undo_buf[text->undo_pos]= op; + text->undo_buf[text->undo_pos+1]= 0; +} + +static void txt_undo_add_block(Text *text, int op, char *buf) +{ + int length; + + length= strlen(buf); + + MAX_UNDO_TEST(length+11); + + text->undo_pos++; + text->undo_buf[text->undo_pos]= op; + + text->undo_pos++; + text->undo_buf[text->undo_pos]= (length)&0xff; + text->undo_pos++; + text->undo_buf[text->undo_pos]= (length>>8)&0xff; + text->undo_pos++; + text->undo_buf[text->undo_pos]= (length>>16)&0xff; + text->undo_pos++; + text->undo_buf[text->undo_pos]= (length>>24)&0xff; + + text->undo_pos++; + strncpy(text->undo_buf+text->undo_pos, buf, length); + text->undo_pos+=length; + + text->undo_buf[text->undo_pos]= (length)&0xff; + text->undo_pos++; + text->undo_buf[text->undo_pos]= (length>>8)&0xff; + text->undo_pos++; + text->undo_buf[text->undo_pos]= (length>>16)&0xff; + text->undo_pos++; + text->undo_buf[text->undo_pos]= (length>>24)&0xff; + + text->undo_pos++; + text->undo_buf[text->undo_pos]= op; + + text->undo_buf[text->undo_pos+1]= 0; +} + +void txt_undo_add_toop(Text *text, int op, unsigned int froml, unsigned short fromc, unsigned int tol, unsigned short toc) +{ + MAX_UNDO_TEST(15); + + if (froml==tol && fromc==toc) return; + + text->undo_pos++; + text->undo_buf[text->undo_pos]= op; + + text->undo_pos++; + text->undo_buf[text->undo_pos]= (fromc)&0xff; + text->undo_pos++; + text->undo_buf[text->undo_pos]= (fromc>>8)&0xff; + + text->undo_pos++; + text->undo_buf[text->undo_pos]= (froml)&0xff; + text->undo_pos++; + text->undo_buf[text->undo_pos]= (froml>>8)&0xff; + text->undo_pos++; + text->undo_buf[text->undo_pos]= (froml>>16)&0xff; + text->undo_pos++; + text->undo_buf[text->undo_pos]= (froml>>24)&0xff; + + text->undo_pos++; + text->undo_buf[text->undo_pos]= (toc)&0xff; + text->undo_pos++; + text->undo_buf[text->undo_pos]= (toc>>8)&0xff; + + text->undo_pos++; + text->undo_buf[text->undo_pos]= (tol)&0xff; + text->undo_pos++; + text->undo_buf[text->undo_pos]= (tol>>8)&0xff; + text->undo_pos++; + text->undo_buf[text->undo_pos]= (tol>>16)&0xff; + text->undo_pos++; + text->undo_buf[text->undo_pos]= (tol>>24)&0xff; + + text->undo_pos++; + text->undo_buf[text->undo_pos]= op; + + text->undo_buf[text->undo_pos+1]= 0; +} + +static void txt_undo_add_charop(Text *text, int op, char c) +{ + MAX_UNDO_TEST(4); + + text->undo_pos++; + text->undo_buf[text->undo_pos]= op; + text->undo_pos++; + text->undo_buf[text->undo_pos]= c; + text->undo_pos++; + text->undo_buf[text->undo_pos]= op; + text->undo_buf[text->undo_pos+1]= 0; +} + +void txt_do_undo(Text *text) +{ + int op= text->undo_buf[text->undo_pos]; + unsigned int linep, i; + unsigned short charp; + TextLine *holdl; + int holdc, holdln; + char *buf; + + if (text->undo_pos<0) { + return; + } + + text->undo_pos--; + + undoing= 1; + + switch(op) { + case UNDO_CLEFT: + txt_move_right(text, 0); + break; + + case UNDO_CRIGHT: + txt_move_left(text, 0); + break; + + case UNDO_CUP: + txt_move_down(text, 0); + break; + + case UNDO_CDOWN: + txt_move_up(text, 0); + break; + + case UNDO_SLEFT: + txt_move_right(text, 1); + break; + + case UNDO_SRIGHT: + txt_move_left(text, 1); + break; + + case UNDO_SUP: + txt_move_down(text, 1); + break; + + case UNDO_SDOWN: + txt_move_up(text, 1); + break; + + case UNDO_CTO: + case UNDO_STO: + text->undo_pos--; + text->undo_pos--; + text->undo_pos--; + text->undo_pos--; + + text->undo_pos--; + text->undo_pos--; + + linep= text->undo_buf[text->undo_pos]; text->undo_pos--; + linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; + linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; + linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; + + charp= text->undo_buf[text->undo_pos]; text->undo_pos--; + charp= (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; + + if (op==UNDO_CTO) { + txt_move_toline(text, linep, 0); + text->curc= charp; + txt_pop_sel(text); + } else { + txt_move_toline(text, linep, 1); + text->selc= charp; + } + + text->undo_pos--; + break; + + case UNDO_INSERT: + txt_backspace_char(text); + text->undo_pos--; + text->undo_pos--; + break; + + case UNDO_BS: + txt_add_char(text, text->undo_buf[text->undo_pos]); + text->undo_pos--; + text->undo_pos--; + break; + + case UNDO_DEL: + txt_add_char(text, text->undo_buf[text->undo_pos]); + txt_move_left(text, 0); + text->undo_pos--; + text->undo_pos--; + break; + + case UNDO_SWAP: + txt_curs_swap(text); + txt_do_undo(text); /* swaps should appear transparent */ + break; + + case UNDO_DBLOCK: + linep= text->undo_buf[text->undo_pos]; text->undo_pos--; + linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; + linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; + linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; + + buf= MEM_mallocN(linep+1, "dblock buffer"); + for (i=0; i < linep; i++){ + buf[(linep-1)-i]= text->undo_buf[text->undo_pos]; + text->undo_pos--; + } + buf[i]= 0; + + txt_curs_first(text, &holdl, &holdc); + holdln= txt_get_span(text->lines.first, holdl); + + txt_insert_buf(text, buf); + MEM_freeN(buf); + + text->curl= text->lines.first; + while (holdln>0) { + if(text->curl->next) + text->curl= text->curl->next; + + holdln--; + } + text->curc= holdc; + + linep= text->undo_buf[text->undo_pos]; text->undo_pos--; + linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; + linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; + linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; + + text->undo_pos--; + + break; + + case UNDO_IBLOCK: + linep= text->undo_buf[text->undo_pos]; text->undo_pos--; + linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; + linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; + linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; + + txt_delete_sel(text); + while (linep>0) { + txt_backspace_char(text); + text->undo_pos--; + linep--; + } + + text->undo_pos--; + text->undo_pos--; + text->undo_pos--; + text->undo_pos--; + + text->undo_pos--; + + break; + case UNDO_INDENT: + case UNDO_UNINDENT: + case UNDO_COMMENT: + case UNDO_UNCOMMENT: + linep= text->undo_buf[text->undo_pos]; text->undo_pos--; + linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; + linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; + linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; + //linep is now the end line of the selection + + charp = text->undo_buf[text->undo_pos]; text->undo_pos--; + charp = (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; + //charp is the last char selected or text->line->len + //set the selcetion for this now + text->selc = charp; + text->sell = text->lines.first; + for (i= 0; i < linep; i++) { + text->sell = text->sell->next; + } + + linep= text->undo_buf[text->undo_pos]; text->undo_pos--; + linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; + linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; + linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; + //first line to be selected + + charp = text->undo_buf[text->undo_pos]; text->undo_pos--; + charp = (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; + //first postion to be selected + text->curc = charp; + text->curl = text->lines.first; + for (i = 0; i < linep; i++) { + text->curl = text->curl->next; + } + + + if (op==UNDO_INDENT) { + unindent(text); + } else if (op== UNDO_UNINDENT) { + indent(text); + } else if (op == UNDO_COMMENT) { + uncomment(text); + } else if (op == UNDO_UNCOMMENT) { + comment(text); + } + + text->undo_pos--; + break; + default: + error("Undo buffer error - resetting"); + text->undo_pos= -1; + + break; + } + + undoing= 0; +} + +void txt_do_redo(Text *text) +{ + char op; + unsigned int linep, i; + unsigned short charp; + char *buf; + + text->undo_pos++; + op= text->undo_buf[text->undo_pos]; + + if (!op) { + text->undo_pos--; + return; + } + + undoing= 1; + + switch(op) { + case UNDO_CLEFT: + txt_move_left(text, 0); + break; + + case UNDO_CRIGHT: + txt_move_right(text, 0); + break; + + case UNDO_CUP: + txt_move_up(text, 0); + break; + + case UNDO_CDOWN: + txt_move_down(text, 0); + break; + + case UNDO_SLEFT: + txt_move_left(text, 1); + break; + + case UNDO_SRIGHT: + txt_move_right(text, 1); + break; + + case UNDO_SUP: + txt_move_up(text, 1); + break; + + case UNDO_SDOWN: + txt_move_down(text, 1); + break; + + case UNDO_INSERT: + text->undo_pos++; + txt_add_char(text, text->undo_buf[text->undo_pos]); + text->undo_pos++; + break; + + case UNDO_BS: + text->undo_pos++; + txt_backspace_char(text); + text->undo_pos++; + break; + + case UNDO_DEL: + text->undo_pos++; + txt_delete_char(text); + text->undo_pos++; + break; + + case UNDO_SWAP: + txt_curs_swap(text); + txt_do_undo(text); /* swaps should appear transparent a*/ + break; + + case UNDO_CTO: + case UNDO_STO: + text->undo_pos++; + text->undo_pos++; + + text->undo_pos++; + text->undo_pos++; + text->undo_pos++; + text->undo_pos++; + + text->undo_pos++; + + charp= text->undo_buf[text->undo_pos]; + text->undo_pos++; + charp= charp+(text->undo_buf[text->undo_pos]<<8); + + text->undo_pos++; + linep= text->undo_buf[text->undo_pos]; text->undo_pos++; + linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++; + linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++; + linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++; + + if (op==UNDO_CTO) { + txt_move_toline(text, linep, 0); + text->curc= charp; + txt_pop_sel(text); + } else { + txt_move_toline(text, linep, 1); + text->selc= charp; + } + + break; + + case UNDO_DBLOCK: + text->undo_pos++; + linep= text->undo_buf[text->undo_pos]; text->undo_pos++; + linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++; + linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++; + linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++; + + txt_delete_sel(text); + text->undo_pos+=linep; + + text->undo_pos++; + text->undo_pos++; + text->undo_pos++; + text->undo_pos++; + + break; + + case UNDO_IBLOCK: + text->undo_pos++; + linep= text->undo_buf[text->undo_pos]; text->undo_pos++; + linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++; + linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++; + linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++; + + buf= MEM_mallocN(linep+1, "iblock buffer"); + memcpy (buf, &text->undo_buf[text->undo_pos], linep); + text->undo_pos+= linep; + buf[linep]= 0; + + txt_insert_buf(text, buf); + MEM_freeN(buf); + + linep= text->undo_buf[text->undo_pos]; text->undo_pos++; + linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++; + linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++; + linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++; + + break; + case UNDO_INDENT: + case UNDO_UNINDENT: + case UNDO_COMMENT: + case UNDO_UNCOMMENT: + text->undo_pos++; + charp = text->undo_buf[text->undo_pos]; text->undo_pos++; + charp = charp+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++; + //charp is the first char selected or 0 + + linep= text->undo_buf[text->undo_pos]; text->undo_pos++; + linep = linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++; + linep = linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++; + linep = linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++; + //linep is now the first line of the selection + //set the selcetion for this now + text->curc = charp; + text->curl = text->lines.first; + for (i= 0; i < linep; i++) { + text->curl = text->curl->next; + } + + charp = text->undo_buf[text->undo_pos]; text->undo_pos++; + charp = charp+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++; + //last postion to be selected + linep= text->undo_buf[text->undo_pos]; text->undo_pos++; + linep = linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++; + linep = linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++; + linep = linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++; + //Last line to be selected + + text->selc = charp; + text->sell = text->lines.first; + for (i = 0; i < linep; i++) { + text->sell = text->sell->next; + } + + if (op==UNDO_INDENT) { + indent(text); + } else if (op== UNDO_UNINDENT) { + unindent(text); + } else if (op == UNDO_COMMENT) { + comment(text); + } else if (op == UNDO_UNCOMMENT) { + uncomment(text); + } + break; + default: + error("Undo buffer error - resetting"); + text->undo_pos= -1; + + break; + } + + undoing= 0; +} + +/**************************/ +/* Line editing functions */ +/**************************/ + +void txt_split_curline (Text *text) +{ + TextLine *ins; + char *left, *right, *fleft, *fright; + + if (!text) return; + if (!text->curl) return; + + txt_delete_sel(text); + + /* Make the two half strings */ + + left= MEM_mallocN(text->curc+1, "textline_string"); + fleft= MEM_mallocN(text->curc+2, "Syntax_format"); + if (text->curc) memcpy(left, text->curl->line, text->curc); + left[text->curc]=0; + + right= MEM_mallocN(text->curl->len - text->curc+1, "textline_string"); + fright= MEM_mallocN(text->curl->len - text->curc+2, "Syntax_format"); + if (text->curl->len - text->curc) memcpy(right, text->curl->line+text->curc, text->curl->len-text->curc); + right[text->curl->len - text->curc]=0; + + MEM_freeN(text->curl->line); + if (text->curl->format) MEM_freeN(text->curl->format); + + /* Make the new TextLine */ + + ins= MEM_mallocN(sizeof(TextLine), "textline"); + ins->line= left; + ins->format= fleft; + ins->len= text->curc; + + text->curl->line= right; + text->curl->format= fright; + text->curl->len= text->curl->len - text->curc; + + BLI_insertlinkbefore(&text->lines, text->curl, ins); + + text->curc=0; + + txt_make_dirty(text); + txt_clean_text(text); + + txt_pop_sel(text); + if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, '\n'); +} + +static void txt_delete_line (Text *text, TextLine *line) +{ + if (!text) return; + if (!text->curl) return; + + BLI_remlink (&text->lines, line); + + if (line->line) MEM_freeN(line->line); + if (line->format) MEM_freeN(line->format); + + MEM_freeN(line); + + txt_make_dirty(text); + txt_clean_text(text); +} + +static void txt_combine_lines (Text *text, TextLine *linea, TextLine *lineb) +{ + char *tmp, *format; + + if (!text) return; + + if(!linea || !lineb) return; + + tmp= MEM_mallocN(linea->len+lineb->len+1, "textline_string"); + format= MEM_mallocN(linea->len+lineb->len+1, "Syntax_format"); + + strcpy(tmp, linea->line); + strcat(tmp, lineb->line); + + make_new_line(linea, tmp, format); + + txt_delete_line(text, lineb); + + txt_make_dirty(text); + txt_clean_text(text); +} + +void txt_delete_char (Text *text) +{ + char c='\n'; + + if (!text) return; + if (!text->curl) return; + + if (txt_has_sel(text)) { /* deleting a selection */ + txt_delete_sel(text); + } + else if (text->curc== text->curl->len) { /* Appending two lines */ + if (text->curl->next) { + txt_combine_lines(text, text->curl, text->curl->next); + txt_pop_sel(text); + } + } else { /* Just deleting a char */ + int i= text->curc; + + c= text->curl->line[i]; + while(i< text->curl->len) { + text->curl->line[i]= text->curl->line[i+1]; + i++; + } + text->curl->len--; + + txt_pop_sel(text); + } + + txt_make_dirty(text); + txt_clean_text(text); + + if(!undoing) txt_undo_add_charop(text, UNDO_DEL, c); +} + +void txt_backspace_char (Text *text) +{ + char c='\n'; + + if (!text) return; + if (!text->curl) return; + + if (txt_has_sel(text)) { /* deleting a selection */ + txt_delete_sel(text); + } + else if (text->curc==0) { /* Appending two lines */ + if (text->curl->prev) { + text->curl= text->curl->prev; + text->curc= text->curl->len; + + txt_combine_lines(text, text->curl, text->curl->next); + txt_pop_sel(text); + } + } + else { /* Just backspacing a char */ + int i= text->curc-1; + + c= text->curl->line[i]; + while(i< text->curl->len) { + text->curl->line[i]= text->curl->line[i+1]; + i++; + } + text->curl->len--; + text->curc--; + + txt_pop_sel(text); + } + + txt_make_dirty(text); + txt_clean_text(text); + + if(!undoing) txt_undo_add_charop(text, UNDO_BS, c); +} + +int txt_add_char (Text *text, char add) +{ + int len; + char *tmp, *format; + + if (!text) return 0; + if (!text->curl) return 0; + + if (add=='\n') { + txt_split_curline(text); + return 1; + } + + txt_delete_sel(text); + + tmp= MEM_mallocN(text->curl->len+2, "textline_string"); + format= MEM_mallocN(text->curl->len+4, "Syntax_format"); + + if(text->curc) memcpy(tmp, text->curl->line, text->curc); + tmp[text->curc]= add; + + len= text->curl->len - text->curc; + if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len); + tmp[text->curl->len+1]=0; + make_new_line(text->curl, tmp, format); + + text->curc++; + + txt_pop_sel(text); + + txt_make_dirty(text); + txt_clean_text(text); + + if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, add); + return 1; +} + +void indent(Text *text) +{ + int len, num; + char *tmp, *format; + char add = '\t'; + + if (!text) return; + if (!text->curl) return; + if (!text->sell) return; + + num = 0; + while (TRUE) + { + tmp= MEM_mallocN(text->curl->len+2, "textline_string"); + format= MEM_mallocN(text->curl->len+3, "Syntax_format"); + + text->curc = 0; + if(text->curc) memcpy(tmp, text->curl->line, text->curc); + tmp[text->curc]= add; + + len= text->curl->len - text->curc; + if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len); + tmp[text->curl->len+1]=0; + + make_new_line(text->curl, tmp, format); + + text->curc++; + + txt_make_dirty(text); + txt_clean_text(text); + + if(text->curl == text->sell) + { + text->selc = text->sell->len; + break; + } else { + text->curl = text->curl->next; + num++; + } + } + text->curc = 0; + while( num > 0 ) + { + text->curl = text->curl->prev; + num--; + } + + if(!undoing) + { + txt_undo_add_toop(text, UNDO_INDENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc); + } +} + +void unindent(Text *text) +{ + int num = 0; + char remove = '\t'; + + if (!text) return; + if (!text->curl) return; + if (!text->sell) return; + + while(TRUE) + { + int i = 0; + + if (text->curl->line[i] == remove) + { + while(i< text->curl->len) { + text->curl->line[i]= text->curl->line[i+1]; + i++; + } + text->curl->len--; + } + + + txt_make_dirty(text); + txt_clean_text(text); + + if(text->curl == text->sell) + { + text->selc = text->sell->len; + break; + } else { + text->curl = text->curl->next; + num++; + } + + } + text->curc = 0; + while( num > 0 ) + { + text->curl = text->curl->prev; + num--; + } + + if(!undoing) + { + txt_undo_add_toop(text, UNDO_UNINDENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc); + } +} + +void comment(Text *text) +{ + int len, num; + char *tmp, *format; + char add = '#'; + + if (!text) return; + if (!text->curl) return; + if (!text->sell) return;// Need to change this need to check if only one line is selected ot more then one + + num = 0; + while (TRUE) + { + tmp= MEM_mallocN(text->curl->len+2, "textline_string"); + format = MEM_mallocN(text->curl->len+3, "Syntax_format"); + + text->curc = 0; + if(text->curc) memcpy(tmp, text->curl->line, text->curc); + tmp[text->curc]= add; + + len= text->curl->len - text->curc; + if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len); + tmp[text->curl->len+1]=0; + + make_new_line(text->curl, tmp, format); + + text->curc++; + + txt_make_dirty(text); + txt_clean_text(text); + + if(text->curl == text->sell) + { + text->selc = text->sell->len; + break; + } else { + text->curl = text->curl->next; + num++; + } + } + text->curc = 0; + while( num > 0 ) + { + text->curl = text->curl->prev; + num--; + } + + if(!undoing) + { + txt_undo_add_toop(text, UNDO_COMMENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc); + } +} + +void uncomment(Text *text) +{ + int num = 0; + char remove = '#'; + + if (!text) return; + if (!text->curl) return; + if (!text->sell) return; + + while(TRUE) + { + int i = 0; + + if (text->curl->line[i] == remove) + { + while(i< text->curl->len) { + text->curl->line[i]= text->curl->line[i+1]; + i++; + } + text->curl->len--; + } + + + txt_make_dirty(text); + txt_clean_text(text); + + if(text->curl == text->sell) + { + text->selc = text->sell->len; + break; + } else { + text->curl = text->curl->next; + num++; + } + + } + text->curc = 0; + while( num > 0 ) + { + text->curl = text->curl->prev; + num--; + } + + if(!undoing) + { + txt_undo_add_toop(text, UNDO_UNCOMMENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc); + } +} + +int setcurr_tab (Text *text) +{ + int i = 0; + int test = 0; + char *word = ":"; + char *comm = "#"; + char back_words[3][7] = {"return", "break", "pass"}; + if (!text) return 0; + if (!text->curl) return 0; + + while (text->curl->line[i] == '\t') + { + //we only count thos tabs that are before any text or before the curs; + if (i == text->curc) + { + return i; + } else { + i++; + } + } + if(strstr(text->curl->line, word)) + { + //if we find a : then add a tab but not if it is in a comment + if(strcspn(text->curl->line, word) < strcspn(text->curl->line, comm)) + { + i++; + + } + } + + while(test < 3) + { + //if there are these 3 key words then remove a tab because we are done with the block + if(strstr(text->curl->line, back_words[test]) && i > 0) + { + if(strcspn(text->curl->line, back_words[test]) < strcspn(text->curl->line, comm)) + { + i--; + } + } + test++; + } + return i; +} + diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c new file mode 100644 index 00000000000..a53db265c52 --- /dev/null +++ b/source/blender/blenkernel/intern/texture.c @@ -0,0 +1,820 @@ +/* texture.c + * + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "PIL_dynlib.h" + +#include "MTC_matrixops.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_rand.h" + +#include "DNA_texture_types.h" +#include "DNA_key_types.h" +#include "DNA_object_types.h" +#include "DNA_lamp_types.h" +#include "DNA_material_types.h" +#include "DNA_image_types.h" +#include "DNA_world_types.h" +#include "DNA_brush_types.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "BKE_plugin_types.h" + +#include "BKE_bad_level_calls.h" +#include "BKE_utildefines.h" + +#include "BKE_global.h" +#include "BKE_main.h" + +#include "BKE_library.h" +#include "BKE_image.h" +#include "BKE_material.h" +#include "BKE_texture.h" +#include "BKE_key.h" +#include "BKE_icons.h" +#include "BKE_ipo.h" +#include "BKE_brush.h" + + +/* ------------------------------------------------------------------------- */ + +/* All support for plugin textures: */ +int test_dlerr(const char *name, const char *symbol) +{ + char *err; + + err= PIL_dynlib_get_error_as_string(NULL); + if(err) { + printf("var1: %s, var2: %s, var3: %s\n", name, symbol, err); + return 1; + } + + return 0; +} + +/* ------------------------------------------------------------------------- */ + +void open_plugin_tex(PluginTex *pit) +{ + int (*version)(void); + + /* init all the happy variables */ + pit->doit= 0; + pit->pname= 0; + pit->stnames= 0; + pit->varstr= 0; + pit->result= 0; + pit->cfra= 0; + pit->version= 0; + + /* clear the error list */ + PIL_dynlib_get_error_as_string(NULL); + + /* no PIL_dynlib_close! multiple opened plugins... */ + /* if(pit->handle) PIL_dynlib_close(pit->handle); */ + /* pit->handle= 0; */ + + /* open the needed object */ + pit->handle= PIL_dynlib_open(pit->name); + if(test_dlerr(pit->name, pit->name)) return; + + if (pit->handle != 0) { + /* find the address of the version function */ + version= (int (*)(void)) PIL_dynlib_find_symbol(pit->handle, "plugin_tex_getversion"); + if (test_dlerr(pit->name, "plugin_tex_getversion")) return; + + if (version != 0) { + pit->version= version(); + if (pit->version>=2 && pit->version<=5) { + int (*info_func)(PluginInfo *); + PluginInfo *info= (PluginInfo*) MEM_mallocN(sizeof(PluginInfo), "plugin_info"); + + info_func= (int (*)(PluginInfo *))PIL_dynlib_find_symbol(pit->handle, "plugin_getinfo"); + if (!test_dlerr(pit->name, "plugin_getinfo")) { + info->instance_init = NULL; + + info_func(info); + + pit->doit= (int(*)(void)) info->tex_doit; + pit->callback= (void(*)(unsigned short)) info->callback; + pit->stypes= info->stypes; + pit->vars= info->nvars; + pit->pname= info->name; + pit->stnames= info->snames; + pit->varstr= info->varstr; + pit->result= info->result; + pit->cfra= info->cfra; + pit->instance_init = info->instance_init; + if (info->init) info->init(); + } + MEM_freeN(info); + } else { + printf ("Plugin returned unrecognized version number\n"); + return; + } + } + } +} + +/* ------------------------------------------------------------------------- */ + +/* very badlevel define to bypass linking with BIF_interface.h */ +#define INT 96 +#define FLO 128 + +PluginTex *add_plugin_tex(char *str) +{ + PluginTex *pit; + VarStruct *varstr; + int a; + + pit= MEM_callocN(sizeof(PluginTex), "plugintex"); + + strcpy(pit->name, str); + open_plugin_tex(pit); + + if(pit->doit==0) { + if(pit->handle==0) error("no plugin: %s", str); + else error("in plugin: %s", str); + MEM_freeN(pit); + return NULL; + } + + varstr= pit->varstr; + for(a=0; avars; a++, varstr++) { + if( (varstr->type & FLO)==FLO) + pit->data[a]= varstr->def; + else if( (varstr->type & INT)==INT) + *((int *)(pit->data+a))= (int) varstr->def; + } + + if (pit->instance_init) + pit->instance_init((void *) pit->data); + + return pit; +} + +/* ------------------------------------------------------------------------- */ + +void free_plugin_tex(PluginTex *pit) +{ + if(pit==0) return; + + /* no PIL_dynlib_close: same plugin can be opened multiple times, 1 handle */ + MEM_freeN(pit); +} + +/* ****************** Mapping ******************* */ + +TexMapping *add_mapping(void) +{ + TexMapping *texmap= MEM_callocN(sizeof(TexMapping), "Tex map"); + + texmap->size[0]= texmap->size[1]= texmap->size[2]= 1.0f; + texmap->max[0]= texmap->max[1]= texmap->max[2]= 1.0f; + Mat4One(texmap->mat); + + return texmap; +} + +void init_mapping(TexMapping *texmap) +{ + float eul[3], smat[3][3], rmat[3][3], mat[3][3]; + + SizeToMat3(texmap->size, smat); + + eul[0]= (M_PI/180.0f)*texmap->rot[0]; + eul[1]= (M_PI/180.0f)*texmap->rot[1]; + eul[2]= (M_PI/180.0f)*texmap->rot[2]; + EulToMat3(eul, rmat); + + Mat3MulMat3(mat, rmat, smat); + + Mat4CpyMat3(texmap->mat, mat); + VECCOPY(texmap->mat[3], texmap->loc); + +} + +/* ****************** COLORBAND ******************* */ + +void init_colorband(ColorBand *coba, int rangetype) +{ + int a; + + coba->data[0].pos= 0.0; + coba->data[1].pos= 1.0; + + if(rangetype==0) { + coba->data[0].r= 0.0; + coba->data[0].g= 0.0; + coba->data[0].b= 0.0; + coba->data[0].a= 0.0; + + coba->data[1].r= 0.0; + coba->data[1].g= 1.0; + coba->data[1].b= 1.0; + coba->data[1].a= 1.0; + } + else { + coba->data[0].r= 0.0; + coba->data[0].g= 0.0; + coba->data[0].b= 0.0; + coba->data[0].a= 1.0; + + coba->data[1].r= 1.0; + coba->data[1].g= 1.0; + coba->data[1].b= 1.0; + coba->data[1].a= 1.0; + } + + for(a=2; adata[a].r= 0.5; + coba->data[a].g= 0.5; + coba->data[a].b= 0.5; + coba->data[a].a= 1.0; + coba->data[a].pos= 0.5; + } + + coba->tot= 2; + +} + +ColorBand *add_colorband(int rangetype) +{ + ColorBand *coba; + + coba= MEM_callocN( sizeof(ColorBand), "colorband"); + init_colorband(coba, rangetype); + + return coba; +} + +/* ------------------------------------------------------------------------- */ + +int do_colorband(ColorBand *coba, float in, float out[4]) +{ + CBData *cbd1, *cbd2, *cbd0, *cbd3; + float fac, mfac, t[4]; + int a; + + if(coba==NULL || coba->tot==0) return 0; + + cbd1= coba->data; + if(coba->tot==1) { + out[0]= cbd1->r; + out[1]= cbd1->g; + out[2]= cbd1->b; + out[3]= cbd1->a; + } + else { + if(in <= cbd1->pos && coba->ipotype<2) { + out[0]= cbd1->r; + out[1]= cbd1->g; + out[2]= cbd1->b; + out[3]= cbd1->a; + } + else { + CBData left, right; + + /* we're looking for first pos > in */ + for(a=0; atot; a++, cbd1++) if(cbd1->pos > in) break; + + if(a==coba->tot) { + cbd2= cbd1-1; + right= *cbd2; + right.pos= 1.0f; + cbd1= &right; + } + else if(a==0) { + left= *cbd1; + left.pos= 0.0f; + cbd2= &left; + } + else cbd2= cbd1-1; + + if(in >= cbd1->pos && coba->ipotype<2) { + out[0]= cbd1->r; + out[1]= cbd1->g; + out[2]= cbd1->b; + out[3]= cbd1->a; + } + else { + + if(cbd2->pos!=cbd1->pos) + fac= (in-cbd1->pos)/(cbd2->pos-cbd1->pos); + else + fac= 0.0f; + + if(coba->ipotype>=2) { + /* ipo from right to left: 3 2 1 0 */ + + if(a>=coba->tot-1) cbd0= cbd1; + else cbd0= cbd1+1; + if(a<2) cbd3= cbd2; + else cbd3= cbd2-1; + + CLAMP(fac, 0.0f, 1.0f); + + if(coba->ipotype==3) + set_four_ipo(fac, t, KEY_CARDINAL); + else + set_four_ipo(fac, t, KEY_BSPLINE); + + out[0]= t[3]*cbd3->r +t[2]*cbd2->r +t[1]*cbd1->r +t[0]*cbd0->r; + out[1]= t[3]*cbd3->g +t[2]*cbd2->g +t[1]*cbd1->g +t[0]*cbd0->g; + out[2]= t[3]*cbd3->b +t[2]*cbd2->b +t[1]*cbd1->b +t[0]*cbd0->b; + out[3]= t[3]*cbd3->a +t[2]*cbd2->a +t[1]*cbd1->a +t[0]*cbd0->a; + CLAMP(out[0], 0.0, 1.0); + CLAMP(out[1], 0.0, 1.0); + CLAMP(out[2], 0.0, 1.0); + CLAMP(out[3], 0.0, 1.0); + } + else { + + if(coba->ipotype==1) { /* EASE */ + mfac= fac*fac; + fac= 3.0f*mfac-2.0f*mfac*fac; + } + mfac= 1.0f-fac; + + out[0]= mfac*cbd1->r + fac*cbd2->r; + out[1]= mfac*cbd1->g + fac*cbd2->g; + out[2]= mfac*cbd1->b + fac*cbd2->b; + out[3]= mfac*cbd1->a + fac*cbd2->a; + } + } + } + } + return 1; /* OK */ +} + +/* ******************* TEX ************************ */ + +void free_texture(Tex *tex) +{ + free_plugin_tex(tex->plugin); + if(tex->coba) MEM_freeN(tex->coba); + if(tex->env) BKE_free_envmap(tex->env); + BKE_previewimg_free(&tex->preview); + BKE_icon_delete((struct ID*)tex); + tex->id.icon_id = 0; +} + +/* ------------------------------------------------------------------------- */ + +void default_tex(Tex *tex) +{ + PluginTex *pit; + VarStruct *varstr; + int a; + + tex->stype= 0; + tex->flag= TEX_CHECKER_ODD; + tex->imaflag= TEX_INTERPOL+TEX_MIPMAP; + tex->extend= TEX_REPEAT; + tex->cropxmin= tex->cropymin= 0.0; + tex->cropxmax= tex->cropymax= 1.0; + tex->xrepeat= tex->yrepeat= 1; + tex->fie_ima= 2; + tex->sfra= 1; + tex->frames= 0; + tex->offset= 0; + tex->noisesize= 0.25; + tex->noisedepth= 2; + tex->turbul= 5.0; + tex->nabla= 0.025; // also in do_versions + tex->bright= 1.0; + tex->contrast= tex->filtersize= 1.0; + tex->rfac= 1.0; + tex->gfac= 1.0; + tex->bfac= 1.0; + /* newnoise: init. */ + tex->noisebasis = 0; + tex->noisebasis2 = 0; + /* musgrave */ + tex->mg_H = 1.0; + tex->mg_lacunarity = 2.0; + tex->mg_octaves = 2.0; + tex->mg_offset = 1.0; + tex->mg_gain = 1.0; + tex->ns_outscale = 1.0; + /* distnoise */ + tex->dist_amount = 1.0; + /* voronoi */ + tex->vn_w1 = 1.0; + tex->vn_w2 = tex->vn_w3 = tex->vn_w4 = 0.0; + tex->vn_mexp = 2.5; + tex->vn_distm = 0; + tex->vn_coltype = 0; + + if (tex->env) { + tex->env->stype=ENV_STATIC; + tex->env->clipsta=0.1; + tex->env->clipend=100; + tex->env->cuberes=100; + tex->env->depth=0; + } + + pit = tex->plugin; + if (pit) { + varstr= pit->varstr; + if(varstr) { + for(a=0; avars; a++, varstr++) { + pit->data[a] = varstr->def; + } + } + } + + tex->iuser.fie_ima= 2; + tex->iuser.ok= 1; + tex->iuser.frames= 100; + + tex->preview = NULL; +} + +/* ------------------------------------------------------------------------- */ + +Tex *add_texture(char *name) +{ + Tex *tex; + + tex= alloc_libblock(&G.main->tex, ID_TE, name); + + default_tex(tex); + + return tex; +} + +/* ------------------------------------------------------------------------- */ + +void default_mtex(MTex *mtex) +{ + mtex->texco= TEXCO_ORCO; + mtex->mapto= MAP_COL; + mtex->object= 0; + mtex->projx= PROJ_X; + mtex->projy= PROJ_Y; + mtex->projz= PROJ_Z; + mtex->mapping= MTEX_FLAT; + mtex->ofs[0]= 0.0; + mtex->ofs[1]= 0.0; + mtex->ofs[2]= 0.0; + mtex->size[0]= 1.0; + mtex->size[1]= 1.0; + mtex->size[2]= 1.0; + mtex->tex= 0; + mtex->texflag= 0; + mtex->colormodel= 0; + mtex->r= 1.0; + mtex->g= 0.0; + mtex->b= 1.0; + mtex->k= 1.0; + mtex->def_var= 1.0; + mtex->blendtype= MTEX_BLEND; + mtex->colfac= 1.0; + mtex->norfac= 0.5; + mtex->varfac= 1.0; + mtex->dispfac=0.2; +} + + +/* ------------------------------------------------------------------------- */ + +MTex *add_mtex() +{ + MTex *mtex; + + mtex= MEM_callocN(sizeof(MTex), "add_mtex"); + + default_mtex(mtex); + + return mtex; +} + +/* ------------------------------------------------------------------------- */ + +Tex *copy_texture(Tex *tex) +{ + Tex *texn; + + texn= copy_libblock(tex); + if(texn->type==TEX_IMAGE) id_us_plus((ID *)texn->ima); + else texn->ima= 0; + + if(texn->plugin) { + texn->plugin= MEM_dupallocN(texn->plugin); + open_plugin_tex(texn->plugin); + } + + if(texn->coba) texn->coba= MEM_dupallocN(texn->coba); + if(texn->env) texn->env= BKE_copy_envmap(texn->env); + + if(tex->preview) texn->preview = BKE_previewimg_copy(tex->preview); + + return texn; +} + +/* ------------------------------------------------------------------------- */ + +void make_local_texture(Tex *tex) +{ + Tex *texn; + Material *ma; + World *wrld; + Lamp *la; + Brush *br; + int a, local=0, lib=0; + + /* - only lib users: do nothing + * - only local users: set flag + * - mixed: make copy + */ + + if(tex->id.lib==0) return; + + /* special case: ima always local immediately */ + if(tex->ima) { + tex->ima->id.lib= 0; + tex->ima->id.flag= LIB_LOCAL; + new_id(0, (ID *)tex->ima, 0); + } + + if(tex->id.us==1) { + tex->id.lib= 0; + tex->id.flag= LIB_LOCAL; + new_id(0, (ID *)tex, 0); + + return; + } + + ma= G.main->mat.first; + while(ma) { + for(a=0; amtex[a] && ma->mtex[a]->tex==tex) { + if(ma->id.lib) lib= 1; + else local= 1; + } + } + ma= ma->id.next; + } + la= G.main->lamp.first; + while(la) { + for(a=0; amtex[a] && la->mtex[a]->tex==tex) { + if(la->id.lib) lib= 1; + else local= 1; + } + } + la= la->id.next; + } + wrld= G.main->world.first; + while(wrld) { + for(a=0; amtex[a] && wrld->mtex[a]->tex==tex) { + if(wrld->id.lib) lib= 1; + else local= 1; + } + } + wrld= wrld->id.next; + } + br= G.main->brush.first; + while(br) { + for(a=0; amtex[a] && br->mtex[a]->tex==tex) { + if(br->id.lib) lib= 1; + else local= 1; + } + } + br= br->id.next; + } + + if(local && lib==0) { + tex->id.lib= 0; + tex->id.flag= LIB_LOCAL; + new_id(0, (ID *)tex, 0); + } + else if(local && lib) { + texn= copy_texture(tex); + texn->id.us= 0; + + ma= G.main->mat.first; + while(ma) { + for(a=0; amtex[a] && ma->mtex[a]->tex==tex) { + if(ma->id.lib==0) { + ma->mtex[a]->tex= texn; + texn->id.us++; + tex->id.us--; + } + } + } + ma= ma->id.next; + } + la= G.main->lamp.first; + while(la) { + for(a=0; amtex[a] && la->mtex[a]->tex==tex) { + if(la->id.lib==0) { + la->mtex[a]->tex= texn; + texn->id.us++; + tex->id.us--; + } + } + } + la= la->id.next; + } + wrld= G.main->world.first; + while(wrld) { + for(a=0; amtex[a] && wrld->mtex[a]->tex==tex) { + if(wrld->id.lib==0) { + wrld->mtex[a]->tex= texn; + texn->id.us++; + tex->id.us--; + } + } + } + wrld= wrld->id.next; + } + br= G.main->brush.first; + while(br) { + for(a=0; amtex[a] && br->mtex[a]->tex==tex) { + if(br->id.lib==0) { + br->mtex[a]->tex= texn; + texn->id.us++; + tex->id.us--; + } + } + } + br= br->id.next; + } + } +} + +/* ------------------------------------------------------------------------- */ + +void autotexname(Tex *tex) +{ +/* extern char texstr[20][12]; *//* buttons.c, already in bad lev calls*/ + Image *ima; + char di[FILE_MAXDIR], fi[FILE_MAXFILE]; + + if(tex) { + if(tex->type==TEX_IMAGE) { + ima= tex->ima; + if(ima) { + strcpy(di, ima->name); + BLI_splitdirstring(di, fi); + strcpy(di, "I."); + strcat(di, fi); + new_id(&G.main->tex, (ID *)tex, di); + } + else new_id(&G.main->tex, (ID *)tex, texstr[tex->type]); + } + else if(tex->type==TEX_PLUGIN && tex->plugin) new_id(&G.main->tex, (ID *)tex, tex->plugin->pname); + else new_id(&G.main->tex, (ID *)tex, texstr[tex->type]); + } +} + +/* ------------------------------------------------------------------------- */ + +Tex *give_current_texture(Object *ob, int act) +{ + Material ***matarar, *ma; + Lamp *la = 0; + MTex *mtex = 0; + Tex *tex = 0; + + if(ob==0) return 0; + if(ob->totcol==0) return 0; + + if(ob->type==OB_LAMP) { + la=(Lamp *)ob->data; + if(la) { + mtex= la->mtex[(int)(la->texact)]; + if(mtex) tex= mtex->tex; + } + else tex= 0; + } else { + if(act>ob->totcol) act= ob->totcol; + else if(act==0) act= 1; + + if( BTST(ob->colbits, act-1) ) { /* in object */ + ma= ob->mat[act-1]; + } + else { /* in data */ + matarar= give_matarar(ob); + + if(matarar && *matarar) ma= (*matarar)[act-1]; + else ma= 0; + + } + if(ma) { + mtex= ma->mtex[(int)(ma->texact)]; + if(mtex) tex= mtex->tex; + } + else tex= 0; + } + + return tex; +} + + +/* ------------------------------------------------------------------------- */ + +EnvMap *BKE_add_envmap(void) +{ + EnvMap *env; + + env= MEM_callocN(sizeof(EnvMap), "envmap"); + env->type= ENV_CUBE; + env->stype= ENV_STATIC; + env->clipsta= 0.1; + env->clipend= 100.0; + env->cuberes= 100; + + return env; +} + +/* ------------------------------------------------------------------------- */ + +EnvMap *BKE_copy_envmap(EnvMap *env) +{ + EnvMap *envn; + int a; + + envn= MEM_dupallocN(env); + envn->ok= 0; + for(a=0; a<6; a++) envn->cube[a]= NULL; + if(envn->ima) id_us_plus((ID *)envn->ima); + + return envn; +} + +/* ------------------------------------------------------------------------- */ + +void BKE_free_envmapdata(EnvMap *env) +{ + unsigned int part; + + for(part=0; part<6; part++) { + if(env->cube[part]) + IMB_freeImBuf(env->cube[part]); + env->cube[part]= NULL; + } + env->ok= 0; +} + +/* ------------------------------------------------------------------------- */ + +void BKE_free_envmap(EnvMap *env) +{ + + BKE_free_envmapdata(env); + MEM_freeN(env); + +} + +/* ------------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/verse_bitmap_node.c b/source/blender/blenkernel/intern/verse_bitmap_node.c new file mode 100644 index 00000000000..5f2c48b5221 --- /dev/null +++ b/source/blender/blenkernel/intern/verse_bitmap_node.c @@ -0,0 +1,451 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributor(s): Jiri Hnidek. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef WITH_VERSE + +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" + +#include "BLI_dynamiclist.h" +#include "BLI_blenlib.h" + +#include "BIF_verse.h" + +#include "BKE_verse.h" + +#include "verse.h" + +/* function prototypes of static functions */ +static void cb_b_dimension_set(void *user_data, VNodeID node_id, uint16 width, uint16 height, uint16 depth); +static void cb_b_layer_create(void *user_data, VNodeID node_id, VLayerID layer_id, const char *name, VNBLayerType type); +static void cb_b_layer_destroy(void *user_data, VNodeID node_id, VLayerID layer_id); +static void cb_b_tile_set(void *user_data, VNodeID node_id, VLayerID layer_id, uint16 tile_x, uint16 tile_y, uint16 z, VNBLayerType type, const VNBTile *tile); + +static void change_layer_dimension( + VBitmapLayer *vblayer, + unsigned int old_width, + unsigned int old_height, + unsigned int t_old_width, + unsigned int t_old_height); +static void *alloc_verse_bitmap_layer_data(struct VBitmapLayer *vblayer); + +/* + * resize/crop verse bitmap layer + */ +static void change_layer_dimension( + VBitmapLayer *vblayer, + unsigned int old_width, + unsigned int old_height, + unsigned int t_old_width, + unsigned int t_old_height) +{ + struct VNode *vnode = vblayer->vnode; + unsigned int t_width = ((VBitmapData*)(vnode->data))->t_width; + unsigned int width = ((VBitmapData*)(vnode->data))->width; + unsigned int height = ((VBitmapData*)(vnode->data))->height; + unsigned int x, y, i, j; + + i = j = 0; + + /* "copy" old data to new data */ + if(vblayer->type==VN_B_LAYER_UINT8) { + unsigned char *data = (unsigned char*)vblayer->data; + /* allocate new verse bitmap layer data */ + unsigned char *new_data = (unsigned char*)alloc_verse_bitmap_layer_data(vblayer); + for(y=0; ydata); + vblayer->data = new_data; + } +} + +/* + * free data stored in verse bitmap layer + */ +void free_bitmap_layer_data(VBitmapLayer *vblayer) +{ + struct VerseSession *session = vblayer->vnode->session; + + /* free name of bitmap layer */ + MEM_freeN(vblayer->name); + + /* unsubscribe from verse bitmap layer */ + if(session->flag & VERSE_CONNECTED) + verse_send_b_layer_unsubscribe(vblayer->vnode->id, vblayer->id); + + /* free image data of bitmap layer */ + if(vblayer->data) MEM_freeN(vblayer->data); +} + +/* + * allocate data of verse bitmap layer + */ +static void *alloc_verse_bitmap_layer_data(VBitmapLayer *vblayer) +{ + struct VNode *vnode = vblayer->vnode; + unsigned int t_width = ((VBitmapData*)(vnode->data))->t_width; + unsigned int t_height = ((VBitmapData*)(vnode->data))->t_height; + unsigned int size; + void *data; + + size = t_width*t_height; + + /* allocation of own data stored in verse bitmap layer */ + switch (vblayer->type) { + case VN_B_LAYER_UINT1: + data = (void*)MEM_mallocN(sizeof(unsigned char)*size, "VBLayer data uint1"); + break; + case VN_B_LAYER_UINT8: + data = (void*)MEM_mallocN(sizeof(unsigned char)*size, "VBLayer data uint8"); + break; + case VN_B_LAYER_UINT16: + data = (void*)MEM_mallocN(sizeof(unsigned int)*size, "VBLayer data uint16"); + break; + case VN_B_LAYER_REAL32: + data = (void*)MEM_mallocN(sizeof(float)*size, "VBLayer data float16"); + break; + case VN_B_LAYER_REAL64: + data = (void*)MEM_mallocN(sizeof(double)*size, "VBLayer data float32"); + break; + default: + data = NULL; + break; + } + + return data; +} + +/* + * create verse bitmap layer + */ +VBitmapLayer *create_bitmap_layer( + VNode *vnode, + VLayerID layer_id, + const char *name, + VNBLayerType type) +{ + struct VBitmapLayer *vblayer; + unsigned int width = ((VBitmapData*)(vnode->data))->width; + unsigned int height = ((VBitmapData*)(vnode->data))->height; + + /* allocate memory for own verse bitmap layer */ + vblayer = (VBitmapLayer*)MEM_mallocN(sizeof(VBitmapLayer), "Verse Bitmap Layer"); + + /* verse bitmap layer will include pointer at parent verse node and own id */ + vblayer->vnode = vnode; + vblayer->id = layer_id; + + /* name of verse layer */ + vblayer->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "Verse Bitmap Layer name"); + vblayer->name[0] = '\0'; + strcpy(vblayer->name, name); + + /* type of data stored in verse bitmap layer */ + vblayer->type = type; + + /* we can allocate memory for layer data, when we know dimmension of layers; when + * we don't know it, then we will allocate this data when we will receive dimmension */ + if(width==0 || height==0) + vblayer->data = NULL; + else + vblayer->data = alloc_verse_bitmap_layer_data(vblayer); + + vblayer->flag = 0; + + return vblayer; +} + +/* + * free data of bitmap node + */ +void free_bitmap_node_data(VNode *vnode) +{ + if(vnode->data) { + struct VBitmapLayer *vblayer = (VBitmapLayer*)((VBitmapData*)(vnode->data))->layers.lb.first; + + /* free all VerseLayer data */ + while(vblayer) { + free_bitmap_layer_data(vblayer); + vblayer = vblayer->next; + } + + /* free all VerseLayers */ + BLI_dlist_destroy(&(((VGeomData*)vnode->data)->layers)); + } +} + +/* + * create data of bitmap node + */ +VBitmapData *create_bitmap_data() +{ + struct VBitmapData *vbitmap; + + vbitmap = (VBitmapData*)MEM_mallocN(sizeof(VBitmapData), "Verse Bitmap Data"); + + BLI_dlist_init(&(vbitmap->layers)); + vbitmap->queue.first = vbitmap->queue.last = NULL; + + vbitmap->width = 0; + vbitmap->height = 0; + vbitmap->depth = 0; + + vbitmap->image = NULL; + + vbitmap->post_bitmap_dimension_set = post_bitmap_dimension_set; + vbitmap->post_bitmap_layer_create = post_bitmap_layer_create; + vbitmap->post_bitmap_layer_destroy = post_bitmap_layer_destroy; + vbitmap->post_bitmap_tile_set = post_bitmap_tile_set; + + return vbitmap; +} + +/* + * callback function, dimension of image was changed, it is neccessary to + * crop all layers + */ +static void cb_b_dimension_set( + void *user_data, + VNodeID node_id, + uint16 width, + uint16 height, + uint16 depth) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VBitmapLayer *vblayer; + unsigned int old_width, old_height, t_old_width, t_old_height; + + if(!session) return; + + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + if(!vnode) return; + +#ifdef VERSE_DEBUG_PRINT + printf("\t cb_b_dimension_set()\n"); +#endif + + /* backup old width and height */ + old_width = ((VBitmapData*)(vnode->data))->width; + old_height = ((VBitmapData*)(vnode->data))->height; + t_old_width = ((VBitmapData*)(vnode->data))->t_width; + t_old_height = ((VBitmapData*)(vnode->data))->t_height; + + /* set up new dimension of layers */ + ((VBitmapData*)(vnode->data))->width = width; + ((VBitmapData*)(vnode->data))->height = height; + ((VBitmapData*)(vnode->data))->depth = depth; + + /* we cache t_width because tiles aren't one pixel width */ + if((width % VN_B_TILE_SIZE)!=0) + ((VBitmapData*)(vnode->data))->t_width = (width/VN_B_TILE_SIZE + 1)*VN_B_TILE_SIZE; + else + ((VBitmapData*)(vnode->data))->t_width = width; + + /* we cache t_height because tiles aren't one pixel height */ + if((height % VN_B_TILE_SIZE)!=0) + ((VBitmapData*)(vnode->data))->t_height = (height/VN_B_TILE_SIZE + 1)*VN_B_TILE_SIZE; + else + ((VBitmapData*)(vnode->data))->t_height = height; + + /* crop resize all layers */ + vblayer = ((VBitmapData*)vnode->data)->layers.lb.first; + + while(vblayer) { + /* when this callback function received after cb_b_layer_create, + * then we have to allocate memory for verse bitmap layer data */ + if(!vblayer->data) vblayer->data = alloc_verse_bitmap_layer_data(vblayer); + /* crop/resize all verse bitmap layers */ + else change_layer_dimension(vblayer, old_width, old_height, t_old_width, t_old_height); + + vblayer = vblayer->next; + } + + /* post callback function */ + ((VBitmapData*)(vnode->data))->post_bitmap_dimension_set(vnode); +} + +/* + * callback function, new layer channel of image was created + */ +static void cb_b_layer_create( + void *user_data, + VNodeID node_id, + VLayerID layer_id, + const char *name, + VNBLayerType type) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VBitmapLayer *vblayer; + + if(!session) return; + + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + if(!vnode) return; + +#ifdef VERSE_DEBUG_PRINT + printf("\t cb_b_layer_create()\n"); +#endif + + /* when no layer exists, then new layer will be created */ + vblayer = create_bitmap_layer(vnode, layer_id, name, type); + + /* add verse bitmap layer to list of layers */ + BLI_dlist_add_item_index(&((VBitmapData*)vnode->data)->layers, vblayer, layer_id); + + /* post callback function */ + ((VBitmapData*)(vnode->data))->post_bitmap_layer_create(vblayer); + +} + +/* + * callback function, existing layer of image was destroyed + */ +static void cb_b_layer_destroy( + void *user_data, + VNodeID node_id, + VLayerID layer_id) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VBitmapLayer *vblayer; + + if(!session) return; + + /* find node of this layer*/ + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + if(!vnode) return; + + vblayer = (VBitmapLayer*)BLI_dlist_find_link(&(((VBitmapData*)vnode->data)->layers), layer_id); + if(!vblayer) return; + +#ifdef VERSE_DEBUG_PRINT + printf("\t cb_b_layer_destroy()\n"); +#endif + + /* remove verse bitmap layer from list of layers */ + BLI_dlist_rem_item(&(((VBitmapData*)vnode->data)->layers), layer_id); + + /* post callback function */ + ((VBitmapData*)(vnode->data))->post_bitmap_layer_destroy(vblayer); + + /* free data of verse bitmap layer */ + free_bitmap_layer_data(vblayer); + + /* free verse bitmap layer */ + MEM_freeN(vblayer); +} + +/* + * callback function, small part (8x8 pixels) was changed + */ +static void cb_b_tile_set( + void *user_data, + VNodeID node_id, + VLayerID layer_id, + uint16 tile_x, + uint16 tile_y, + uint16 z, + VNBLayerType type, + const VNBTile *tile) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VBitmapLayer *vblayer; + unsigned int x, y, xs, ys, width, height, t_height, t_width, i, j; + + if(!session) return; + + /* try to find verse node in dynamic list nodes */ + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + if(!vnode) return; + + /* try to find verse bitmap layer in list of layers */ + vblayer = (VBitmapLayer*)BLI_dlist_find_link(&(((VBitmapData*)vnode->data)->layers), layer_id); + if(!vblayer) return; + + /* we have to have allocated memory for bitmap layer */ + if(!vblayer->data) return; + + width = ((VBitmapData*)vnode->data)->width; + height = ((VBitmapData*)vnode->data)->height; + + /* width of verse image including all tiles */ + t_height = ((VBitmapData*)vnode->data)->t_height; + /* height of verse image including all tiles */ + t_width = ((VBitmapData*)vnode->data)->t_width; + +#ifdef VERSE_DEBUG_PRINT + printf("\t cb_b_tile_set()\n"); +#endif + + xs = tile_x*VN_B_TILE_SIZE; + ys = tile_y*VN_B_TILE_SIZE; + + /* initial position in one dimension vblayer->data (y_start*width + x_start) */ + i = ys*t_width + xs; + /* intial position in one dimension tile array */ + j = 0; + + if(type==VN_B_LAYER_UINT8) { + unsigned char *data = (unsigned char*)vblayer->data; + for(y=ys; yvuint8[j]; + } + + /* post callback function */ + ((VBitmapData*)(vnode->data))->post_bitmap_tile_set(vblayer, xs, ys); +} + +/* + * set up all callbacks functions for image nodes + */ +void set_bitmap_callbacks(void) +{ + /* dimension (size) of bitmap was set up or changes (image will be croped) */ + verse_callback_set(verse_send_b_dimensions_set, cb_b_dimension_set, NULL); + + /* new layer (chanell) of image was added or created */ + verse_callback_set(verse_send_b_layer_create, cb_b_layer_create, NULL); + + /* existing layer was destroyed */ + verse_callback_set(verse_send_b_layer_destroy, cb_b_layer_destroy, NULL); + + /* some tile (small part 8x8 pixels of image was changed) */ + verse_callback_set(verse_send_b_tile_set, cb_b_tile_set, NULL); +} + +#endif + diff --git a/source/blender/blenkernel/intern/verse_geometry_node.c b/source/blender/blenkernel/intern/verse_geometry_node.c new file mode 100644 index 00000000000..613d4eadbec --- /dev/null +++ b/source/blender/blenkernel/intern/verse_geometry_node.c @@ -0,0 +1,2101 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributor(s): Jiri Hnidek. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef WITH_VERSE + +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" + +#include "BLI_dynamiclist.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "BKE_verse.h" +#include "BKE_utildefines.h" + +#include "BIF_verse.h" + +#include "verse.h" + +/* function prototypes of static functions */ + +/* test functions for callback functions */ +static char test_polygon_set_corner_uint32(uint32 v0, uint32 v1, uint32 v2, uint32 v3); + +/* callback functions */ +static void cb_g_layer_create(void *user_data, VNodeID node_id, VLayerID layer_id, const char *name, VNGLayerType type, uint32 def_integer, real64 def_real); +static void cb_g_layer_destroy(void *user_data, VNodeID node_id, VLayerID layer_id); +static void cb_g_vertex_set_xyz_real32(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real32 x, real32 y, real32 z); +static void cb_g_polygon_set_corner_uint32(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3); +static void cb_g_vertex_delete_real32(void *user_data, VNodeID node_id, uint32 vertex_id); +static void cb_g_polygon_delete(void *user_data, VNodeID node_id, uint32 polygon_id); +static void cb_g_crease_set_edge(void *user_data, VNodeID node_id, const char *layer, uint32 def_crease); +static void cb_g_crease_set_vertex(void *user_data, VNodeID node_id, const char *layer, uint32 def_crease); + +/* other static functions */ + +static void free_unneeded_verseverts_of_verseface(struct VNode *vnode, struct VerseFace *vface); +static void free_verse_vertex(struct VLayer *vlayer, struct VerseVert *vvert); +static void free_verse_face(struct VLayer *vlayer, struct VerseFace *vface); +static void free_verse_layer_data(struct VNode *vnode, struct VLayer *vlayer); + +static void send_verse_face(struct VerseFace *vface); + +static VerseVert* find_verse_vert_in_queue(struct VLayer *vlayer, VNodeID node_id, uint32 vertex_id, real32 x, real32 y, real32 z); +static VerseFace* find_verse_face_in_queue(struct VLayer *vlayer, VNodeID node_id, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3); + +static unsigned short test_incoming_verseface(struct VGeomData *geom, struct VerseFace *vface); +static void find_unsent_faces(struct VNode *vnode, struct VerseVert *vvert); +static void find_vlayer_orphans(struct VNode *vnode, struct VerseVert *vvert); +static void move_face_orphan_to_dlist(struct VNode *vnode, struct VLayer *vlayer, struct VerseFace *vface); +static void increase_verse_verts_references(struct VerseFace *vface); +static void recalculate_verseface_normals(struct VNode *vnode); + +/* verse edge functions */ +static VerseEdge* find_verse_edge(struct VNode *vnode, uint32 v0, uint32 v1); +static void insert_verse_edgehash(struct VNode *vnode, struct VerseEdge *vedge); +static void remove_verse_edgehash(struct VNode *vnode, struct VerseEdge *vedge); +static void remove_verse_edge(struct VNode *vnode, uint32 v0, uint32 v1); +static void add_verse_edge(struct VNode *vnode, uint32 v0, uint32 v1); +static void update_edgehash_of_deleted_verseface(struct VNode *vnode, struct VerseFace *vface); +static void update_edgehash_of_changed_verseface(struct VNode *vnode, struct VerseFace *vface, uint32 v0, uint32 v1, uint32 v2, uint32 v3); +static void update_edgehash_of_new_verseface(struct VNode *vnode, uint32 v0, uint32 v1, uint32 v2, uint32 v3); + +/* + * recalcute normals of all VerseFaces + */ +static void recalculate_verseface_normals(VNode *vnode) +{ + struct VLayer *vert_layer, *face_layer; + struct VerseFace *vface; + struct VerseVert *vvert; + + if(vnode->type != V_NT_GEOMETRY) return; + + vert_layer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); + face_layer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); + + vvert = vert_layer->dl.lb.first; + while(vvert) { + vvert->no[0] = vvert->no[1] = vvert->no[2] = 0.0; + vvert = vvert->next; + } + + vface = face_layer->dl.lb.first; + while(vface) { + /* calculate face normals */ + if(vface->vvert3) { + CalcNormFloat4(vface->vvert0->co, vface->vvert1->co, + vface->vvert2->co, vface->vvert3->co, vface->no); + VecAddf(vface->vvert3->no, vface->vvert3->no, vface->no); + } + else + CalcNormFloat(vface->vvert0->co, vface->vvert1->co, + vface->vvert2->co, vface->no); + + /* calculate vertex normals ... it is averadge of all face normals using the vertex */ + VecAddf(vface->vvert0->no, vface->vvert0->no, vface->no); + VecAddf(vface->vvert1->no, vface->vvert1->no, vface->no); + VecAddf(vface->vvert2->no, vface->vvert2->no, vface->no); + + vface = vface->next; + } + + /* we have to normalize all vertex normals */ + vvert = vert_layer->dl.lb.first; + while(vvert) { + Normalize(vvert->no); + vvert = vvert->next; + } +} + +/* + * add created item to the queue and send it if possible + */ +void add_item_to_send_queue(ListBase *lb, void *item, short type) +{ + struct VNode *vnode; + struct VLayer *vlayer; + struct VerseVert *vvert; + struct VerseFace *vface; + + /* this prevent from adding duplicated faces */ + if(type==VERSE_FACE) { + struct Link *link = (Link*)lb->first; + while(link) { + if(link==item) { + if(((VerseFace*)item)->flag & FACE_SENT) { +/* printf("\tverse face %d marked as OBSOLETE\n", ((VerseFace*)item)->id);*/ + ((VerseFace*)item)->flag |= FACE_OBSOLETE; + } + return; + } + link = link->next; + } + } + + /* add item to sending queue (two way dynamic list) */ + BLI_addtail(lb, item); + + /* send item, when it is possible */ + switch (type) { + case VERSE_NODE: /* only first node in queue can be sent */ + if(lb->first==lb->last) + send_verse_node((VNode*)item); + break; + case VERSE_LINK: /* both object between have to exist */ + if(((VLink*)item)->flag & LINK_SEND_READY) + send_verse_link((VLink*)item); + break; + case VERSE_LAYER: + if(((VLayer*)item)->vnode->flag & NODE_RECEIVED) + send_verse_layer((VLayer*)item); + break; + case VERSE_VERT: + if(((VerseVert*)item)->vlayer->flag & LAYER_RECEIVED) + send_verse_vertex((VerseVert*)item); + break; + case VERSE_FACE: /* all vertexes of face have to be received */ + if(((VerseFace*)item)->flag & FACE_SEND_READY) + send_verse_face((VerseFace*)item); + break; + case VERSE_TAG: + send_verse_tag((VTag*)item); + break; + case VERSE_TAG_GROUP: + send_verse_taggroup((VTagGroup*)item); + break; + case VERSE_VERT_UINT32: /* parent item has to exist */ + vnode = (((uint32_item*)item)->vlayer)->vnode; + vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 0 ); + vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), ((uint32_item*)item)->id ); + if(vvert != NULL) + send_verse_vert_uint32((uint32_item*)item, type); + break; + case VERSE_VERT_REAL32: /* parent item has to exist */ + vnode = (((real32_item*)item)->vlayer)->vnode; + vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 0 ); + vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), ((real32_item*)item)->id ); + if( vvert != NULL) + send_verse_vert_real32((real32_item*)item, type); + break; + case VERSE_VERT_VEC_REAL32: /* parent item has to exist */ + vnode = (((vec_real32_item*)item)->vlayer)->vnode; + vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 0 ); + vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), ((vec_real32_item*)item)->id ); + if(vvert != NULL) + send_verse_vert_vec_real32((vec_real32_item*)item, type); + break; + case VERSE_FACE_UINT8: /* parent item has to exist */ + vnode = (((uint8_item*)item)->vlayer)->vnode; + vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 ); + vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((uint8_item*)item)->id ); + if(vface != NULL) + send_verse_face_uint8((uint8_item*)item, type); + break; + case VERSE_FACE_UINT32: /* parent item has to exist */ + vnode = (((uint32_item*)item)->vlayer)->vnode; + vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 ); + vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((uint32_item*)item)->id ); + if(vface != NULL) + send_verse_face_uint32((uint32_item*)item, type); + break; + case VERSE_FACE_REAL32: /* parent item has to exist */ + vnode = (((real32_item*)item)->vlayer)->vnode; + vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 ); + vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((real32_item*)item)->id ); + if(vface != NULL) + send_verse_face_real32((real32_item*)item, type); + break; + case VERSE_FACE_QUAT_UINT32: /* parent item has to exist */ + vnode = (((quat_uint32_item*)item)->vlayer)->vnode; + vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 ); + vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((quat_uint32_item*)item)->id ); + if(vface != NULL) + send_verse_face_corner_quat_uint32((quat_uint32_item*)item, type); + break; + case VERSE_FACE_QUAT_REAL32: /* parent item has to exist */ + vnode = (((quat_real32_item*)item)->vlayer)->vnode; + vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 ); + vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((quat_real32_item*)item)->id ); + if(vface != NULL) + send_verse_face_corner_quat_real32((quat_real32_item*)item, type); + break; + } +} + +/* + * return VerseLayer with certain content (vertexes, polygons, in the + * future: weight, red color, etc.) + */ +VLayer* find_verse_layer_type(VGeomData *geom, short content) +{ + struct VLayer *vlayer = NULL; + + switch(content) { + case VERTEX_LAYER: + /* VERTEX_LAYER equals 0 and vertex layer is + * always in 1st layer */ + vlayer = geom->layers.da.items[VERTEX_LAYER]; + break; + case POLYGON_LAYER: + /* POLYGON_LAYER equals 1 and vertex layer is + * always in 2nd layer */ + vlayer = geom->layers.da.items[POLYGON_LAYER]; + break; + } + + return vlayer; +} + +/* + * increase references of VerseVerts of new VerseFace + */ +static void increase_verse_verts_references(VerseFace *vface) +{ + if(vface->vvert0) vface->vvert0->counter++; + if(vface->vvert1) vface->vvert1->counter++; + if(vface->vvert2) vface->vvert2->counter++; + if(vface->vvert3) vface->vvert3->counter++; +} + +/* + * move VerseFace from list of orphans to dlist of VerseFaces (if VerseFace was only changed + * then this VerseFace is only removed from list of orphans) + */ +static void move_face_orphan_to_dlist(VNode *vnode, VLayer *vlayer, VerseFace *vface) +{ + /* remove vface from list of orphans */ + BLI_remlink(&(vlayer->orphans), vface); + /* increase references of all vertexes beying part of this face*/ + increase_verse_verts_references(vface); + + if(vface->flag & FACE_RECEIVED) { + /* set up vface flag */ + vface->flag &= ~FACE_RECEIVED; + /* move vface to dynamic list of faces */ + BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, vface->id); + /* recalculate all vertex and faces normals */ + recalculate_verseface_normals(vnode); + /* post create action (change local data) */ + ((VGeomData*)vnode->data)->post_polygon_create(vface); + } + else if(vface->flag & FACE_CHANGED) { + /* set up vface flag */ + vface->flag &= ~FACE_CHANGED; + /* move vface to dynamic list of faces */ + BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, vface->id); + /* recalculate all vertex and faces normals */ + recalculate_verseface_normals(vnode); + /* post create action (change local data) */ + ((VGeomData*)vnode->data)->post_polygon_set_corner(vface); + } +} + +/* + * find all VerseFaces waiting in queue, which needs id of new VerseVert + */ +static void find_unsent_faces(VNode *vnode, VerseVert *vvert) +{ + VLayer *vlayer; + VerseFace *vface, *next_vface; + + vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); + + if(vlayer) { + vface = vlayer->queue.first; + while(vface) { + next_vface = vface->next; + if(vface->vvert0==vvert) { + vface->v0 = vvert->id; + vface->counter--; + } + else if(vface->vvert1==vvert) { + vface->v1 = vvert->id; + vface->counter--; + } + else if(vface->vvert2==vvert) { + vface->v2 = vvert->id; + vface->counter--; + } + else if(vface->vvert3==vvert){ + vface->v3 = vvert->id; + vface->counter--; + } + + if(vface->counter<1 && !(vface->flag & FACE_SENT)) + send_verse_face(vface); + + vface = next_vface; + } + } +} + +/* + * find all VerseFace orphans, which needs incoming VerseVert + */ +static void find_vlayer_orphans(VNode *vnode, VerseVert *vvert) +{ + VLayer *vlayer; + VerseFace *vface, *next_vface; + unsigned int vertex_id = vvert->id; + + vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); + + if(vlayer) { + vface = vlayer->orphans.first; + while(vface){ + next_vface = vface->next; + if(vface->v0 == vertex_id) { + vface->vvert0 = vvert; + vface->counter--; + } + else if(vface->v1 == vertex_id) { + vface->vvert1 = vvert; + vface->counter--; + } + else if(vface->v2 == vertex_id) { + vface->vvert2 = vvert; + vface->counter--; + } + else if(vface->v3 == vertex_id) { + vface->vvert3 = vvert; + vface->counter--; + } + if(vface->counter<1) { + /* moving VerseFace orphan to dlist */ + move_face_orphan_to_dlist(vnode, vlayer, vface); + } + vface = next_vface; + } + } +} + +/* + * return number of VerseVerts missing to incoming VerseFace, set up pointers + * at VerseVerts + */ +static unsigned short test_incoming_verseface(VGeomData *geom, VerseFace *vface) +{ + struct VLayer *vert_layer; + struct VerseVert *vvert; + int counter=0; + + vert_layer = find_verse_layer_type(geom, VERTEX_LAYER); + + if(vface->v0 != -1){ + vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v0); + if(vvert==NULL) counter++; + else vface->vvert0 = vvert; + } + if(vface->v1 != -1){ + vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v1); + if(vvert==NULL) counter++; + else vface->vvert1 = vvert; + } + if(vface->v2 != -1){ + vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v2); + if(vvert==NULL) counter++; + else vface->vvert2 = vvert; + } + if(vface->v3 != -1){ + vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v3); + if(vvert==NULL) counter++; + else vface->vvert3 = vvert; + } + + return counter; +} + +/* + * try to find changed VerseFace in sending queue + */ +static VerseFace* find_changed_verse_face_in_queue(VLayer *vlayer, uint32 polygon_id) +{ + struct VerseFace *vface = vlayer->queue.first; + + while(vface){ + if(vface->id == polygon_id && vface->flag & FACE_CHANGED) { + return vface; + } + vface = vface->next; + } + return NULL; +} + +/* + * try to find VerseFace in queue + */ +static VerseFace* find_verse_face_in_queue( + VLayer *vlayer, + VNodeID node_id, + uint32 polygon_id, + uint32 v0, + uint32 v1, + uint32 v2, + uint32 v3) +{ + struct VerseFace *vface = vlayer->queue.first; + + while(vface){ + if((vface->v0==v0) && (vface->v1==v1) && (vface->v2==v2) && (vface->v3==v3)){ + vface->id = polygon_id; + vface->vlayer = vlayer; + return vface; + } + vface = vface->next; + } + return NULL; +} + +/* + * try to find VerseVert in queue + */ +static VerseVert* find_verse_vert_in_queue( + VLayer *vlayer, + VNodeID node_id, + uint32 vertex_id, + real32 x, + real32 y, + real32 z) +{ + struct VerseVert *vvert = vlayer->queue.first; + + while(vvert){ + if((vvert->vlayer->vnode->id == node_id) && (vvert->co[0] == x) && (vvert->co[1] == y) && (vvert->co[2] == z)) + { + vvert->id = vertex_id; + vvert->vlayer = vlayer; + + return vvert; + } + vvert = vvert->next; + } + + return NULL; +} + + +/* + * send quat of float values to verse server (4x32 bits) + */ +void send_verse_face_corner_quat_real32(quat_real32_item *item, short type) +{ + verse_send_g_polygon_set_corner_real32( + item->vlayer->vnode->id, + item->vlayer->id, + item->id, + item->value[0], + item->value[1], + item->value[2], + item->value[3]); +} + +/* + * send quat of unsigned int values to verse server (4x32 bits) + */ +void send_verse_face_corner_quat_uint32(quat_uint32_item *item, short type) +{ + verse_send_g_polygon_set_corner_uint32( + item->vlayer->vnode->id, + item->vlayer->id, + item->id, + item->value[0], + item->value[1], + item->value[2], + item->value[3]); +} + +/* + * send float value (32 bits) to verse server + */ +void send_verse_face_real32(real32_item *item, short type) +{ + verse_send_g_polygon_set_face_real32( + item->vlayer->vnode->id, + item->vlayer->id, + item->id, + item->value); +} + +/* + * send unsigned integer (32 bits) to verse server + */ +void send_verse_face_uint32(uint32_item *item, short type) +{ + verse_send_g_polygon_set_face_uint32( + item->vlayer->vnode->id, + item->vlayer->id, + item->id, + item->value); +} + +/* + * send unsigned char (8 bits) to verse server + */ +void send_verse_face_uint8(uint8_item *item, short type) +{ + verse_send_g_polygon_set_face_uint8( + item->vlayer->vnode->id, + item->vlayer->id, + item->id, + item->value); +} + +/* + * send vector of float values to verse server (3x32 bits) + */ +void send_verse_vert_vec_real32(vec_real32_item *item, short type) +{ + verse_send_g_vertex_set_xyz_real32( + item->vlayer->vnode->id, + item->vlayer->id, + item->id, + item->value[0], + item->value[1], + item->value[2]); +} + +/* + * send float value (32 bits) to verse server + */ +void send_verse_vert_real32(real32_item *item, short type) +{ + verse_send_g_vertex_set_real32( + item->vlayer->vnode->id, + item->vlayer->id, + item->id, + item->value); +} + +/* + * send unsigned integer (32 bits) to verse server + */ +void send_verse_vert_uint32(uint32_item *item, short type) +{ + verse_send_g_vertex_set_uint32( + item->vlayer->vnode->id, + item->vlayer->id, + item->id, + item->value); +} + +/* + * send delete command to verse server + */ +void send_verse_vertex_delete(VerseVert *vvert) +{ + verse_session_set(vvert->vlayer->vnode->session->vsession); + + vvert->flag |= VERT_OBSOLETE; + + verse_send_g_vertex_delete_real32(vvert->vlayer->vnode->id, vvert->id); +} + +/* + * send VerseLayer to verse server + */ +void send_verse_layer(VLayer *vlayer) +{ + verse_session_set(vlayer->vnode->session->vsession); + + verse_send_g_layer_create( + vlayer->vnode->id, + vlayer->id, + vlayer->name, + vlayer->type, + vlayer->def_int, + vlayer->def_real); +} + +/* + * send VerseVert to verse server + */ +void send_verse_vertex(VerseVert *vvert) +{ + /* new vertex position will not be sent, when vertex was deleted */ + if(vvert->flag & VERT_OBSOLETE) return; + + verse_session_set(vvert->vlayer->vnode->session->vsession); + + verse_send_g_vertex_set_xyz_real32( + vvert->vlayer->vnode->id, + vvert->vlayer->id, + vvert->id, + vvert->co[0], + vvert->co[2], + -vvert->co[1]); +} + +/* + * send delete command to verse server + */ +void send_verse_face_delete(VerseFace *vface) +{ + verse_session_set(vface->vlayer->vnode->session->vsession); + + vface->flag |= FACE_DELETED; + + verse_send_g_polygon_delete(vface->vlayer->vnode->id, vface->id); +} + +/* + * send VerseFace to verse server + */ +static void send_verse_face(VerseFace *vface) +{ + verse_session_set(vface->vlayer->vnode->session->vsession); + + vface->flag |= FACE_SENT; + + if(vface->v3 != -1) { + verse_send_g_polygon_set_corner_uint32( + vface->vlayer->vnode->id, + vface->vlayer->id, + vface->id, + vface->v0, + vface->v3, /* verse use clock-wise winding */ + vface->v2, + vface->v1); /* verse use clock-wise winding */ + } + else { + verse_send_g_polygon_set_corner_uint32( + vface->vlayer->vnode->id, + vface->vlayer->id, + vface->id, + vface->v0, + vface->v2, /* verse use clock-wise winding */ + vface->v1, /* verse use clock-wise winding */ + vface->v3); + } +} + +/* + * free VerseVert + */ +static void free_verse_vertex(VLayer *vlayer, VerseVert *vvert) +{ + /* free VerseVert */ + BLI_freelinkN(&(vlayer->orphans), vvert); +} + +/* + * free VerseFace (and blender face) + */ +static void free_verse_face(VLayer *vlayer, VerseFace *vface) +{ + /* free VerseFace */ + BLI_dlist_free_item(&(vlayer->dl), (unsigned int)vface->id); +} + +/* + * free VerseLayer data + */ +static void free_verse_layer_data(VNode *vnode, VLayer *vlayer) +{ + struct VerseFace *vface; + struct VerseVert *vvert; + + /* set up EditVert->vvert and EditFace->vface pointers to NULL */ + switch(vlayer->content) { + case VERTEX_LAYER: + vvert = (VerseVert*)vlayer->dl.lb.first; + while(vvert) { + ((VGeomData*)vnode->data)->post_vertex_free_constraint(vvert); + vvert = vvert->next; + } + break; + case POLYGON_LAYER: + vface = (VerseFace*)vlayer->dl.lb.first; + while(vface) { + ((VGeomData*)vnode->data)->post_polygon_free_constraint(vface); + vface = vface->next; + } + break; + default: + break; + } + /* free Verse Layer name */ + MEM_freeN(vlayer->name); + /* destroy VerseLayer data (vertexes, polygons, etc.) */ + BLI_dlist_destroy(&(vlayer->dl)); + /* free unsent data */ + BLI_freelistN(&(vlayer->queue)); + /* free orphans */ + BLI_freelistN(&(vlayer->orphans)); +} + +/* + * free all unneeded VerseVerts waiting for deleting + */ +static void free_unneeded_verseverts_of_verseface(VNode *vnode, VerseFace *vface) +{ + struct VLayer *vert_vlayer; + + /* find layer containing vertexes */ + vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); + + /* free all "deleted" VerseVert waiting for deleting this VerseFace */ + + if((vface->vvert0->counter < 1) && (vface->vvert0->flag & VERT_DELETED)) { + ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert0); + free_verse_vertex(vert_vlayer, vface->vvert0); + vface->vvert0 = NULL; + } + if((vface->vvert1->counter < 1) && (vface->vvert1->flag & VERT_DELETED)) { + ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert1); + free_verse_vertex(vert_vlayer, vface->vvert1); + vface->vvert1 = NULL; + } + if((vface->vvert2->counter < 1) && (vface->vvert2->flag & VERT_DELETED)) { + ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert2); + free_verse_vertex(vert_vlayer, vface->vvert2); + vface->vvert2 = NULL; + } + if((vface->vvert3) && (vface->vvert3->counter < 1) && (vface->vvert3->flag & VERT_DELETED)) { + ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert3); + free_verse_vertex(vert_vlayer, vface->vvert3); + vface->vvert3 = NULL; + } +} + +/* + * This function create VerseVert and returns pointer on this vertex + */ +VerseVert* create_verse_vertex( + VLayer *vlayer, + uint32 vertex_id, + real32 x, + real32 y, + real32 z) +{ + struct VerseVert *vvert; + + vvert = (VerseVert*)MEM_mallocN(sizeof(VerseVert), "VerseVert"); + + /* set up pointer on parent node */ + vvert->vlayer = vlayer; + vvert->id = vertex_id; + /* position */ + vvert->co[0] = x; + vvert->co[1] = y; + vvert->co[2] = z; + /* normal */ + vvert->no[0] = vvert->no[1] = vvert->no[2] = 0.0; + /* blender internals */ + vvert->flag = 0; + vvert->counter = 0; + vvert->vertex = NULL; + + /* increase layer counter of vertexes */ + vlayer->counter++; + + return vvert; +} + +/* + * this function creates fake VerseEdge and returns pointer at this edge + */ +VerseEdge *create_verse_edge(uint32 v0, uint32 v1) +{ + struct VerseEdge *vedge; + + vedge = (VerseEdge*)MEM_mallocN(sizeof(VerseEdge), "VerseEdge"); + + vedge->v0 = v0; + vedge->v1 = v1; + vedge->counter = 0; + + return vedge; +} + +/* + * this function will create new VerseFace and will return pointer on such Face + */ +VerseFace* create_verse_face( + VLayer *vlayer, + uint32 polygon_id, + uint32 v0, + uint32 v1, + uint32 v2, + uint32 v3) +{ + struct VerseFace *vface; + + vface = (VerseFace*)MEM_mallocN(sizeof(VerseFace), "VerseFace"); + + /* verse data */ + vface->vlayer = vlayer; + vface->id = polygon_id; + + vface->vvert0 = NULL; + vface->vvert1 = NULL; + vface->vvert2 = NULL; + vface->vvert3 = NULL; + + vface->v0 = v0; + vface->v1 = v1; + vface->v2 = v2; + vface->v3 = v3; + + /* blender data */ + vface->face = NULL; + vface->flag = 0; + vface->counter = 4; + + /* increase layer counter of faces */ + vlayer->counter++; + + return vface; +} + +/* + * create and return VerseLayer + */ +VLayer *create_verse_layer( + VNode *vnode, + VLayerID layer_id, + const char *name, + VNGLayerType type, + uint32 def_integer, + real64 def_real) +{ + struct VLayer *vlayer; + + /* add layer to the DynamicList */ + vlayer = (VLayer*)MEM_mallocN(sizeof(VLayer), "VerseLayer"); + + /* store all relevant info to the vlayer and set up vlayer */ + vlayer->vnode = vnode; + vlayer->id = layer_id; + vlayer->name = (char*)MEM_mallocN(sizeof(char)*(sizeof(name)+1),"Verse Layer name"); + strcpy(vlayer->name, name); + vlayer->type = type; + vlayer->def_int = def_integer; + vlayer->def_real = def_real; + + if((type == VN_G_LAYER_VERTEX_XYZ) && (layer_id == 0)) + vlayer->content = VERTEX_LAYER; + else if((type == VN_G_LAYER_POLYGON_CORNER_UINT32) && (layer_id == 1)) + vlayer->content = POLYGON_LAYER; + else + vlayer->content = -1; + + /* initialize DynamicList in the vlayer (vertexes, polygons, etc.)*/ + BLI_dlist_init(&(vlayer->dl)); + /* initialization of queue of layer */ + vlayer->queue.first = vlayer->queue.last = NULL; + /* initialization of list of orphans */ + vlayer->orphans.first = vlayer->orphans.last = NULL; + /* initialize number of sent items (vertexes, faces, etc) */ + vlayer->counter = 0; + /* initialize flag */ + vlayer->flag = 0; + + /* set up methods */ + vlayer->post_layer_create = post_layer_create; + vlayer->post_layer_destroy = post_layer_destroy; + + return vlayer; +} + +/* + * create geometry data + */ +VGeomData *create_geometry_data(void) +{ + struct VGeomData *geom; + + geom = (VGeomData*)MEM_mallocN(sizeof(VGeomData), "VerseGeometryData"); + BLI_dlist_init(&(geom->layers)); + geom->vlink = NULL; + geom->queue.first = geom->queue.last = NULL; + geom->mesh = NULL; + geom->editmesh = NULL; + + /* initialize list of fake verse edges and initialize verse edge hash */ + geom->edges.first = geom->edges.last = NULL; + geom->hash = MEM_callocN(VEDHASHSIZE*sizeof(HashVerseEdge), "verse hashedge tab"); + + /* set up methods */ + geom->post_vertex_create = post_vertex_create; + geom->post_vertex_set_xyz = post_vertex_set_xyz; + geom->post_vertex_delete = post_vertex_delete; + geom->post_vertex_free_constraint = post_vertex_free_constraint; + geom->post_polygon_create = post_polygon_create; + geom->post_polygon_set_corner = post_polygon_set_corner; + geom->post_polygon_delete = post_polygon_delete; + geom->post_polygon_free_constraint = post_polygon_free_constraint; + geom->post_geometry_free_constraint = post_geometry_free_constraint; + geom->post_polygon_set_uint8 = post_polygon_set_uint8; + + return geom; +} + +/* Create item containing 4 floats */ +static quat_real32_item *create_quat_real32_item( + VLayer *vlayer, + uint32 item_id, + real32 v0, + real32 v1, + real32 v2, + real32 v3) +{ + struct quat_real32_item *item; + + item = (quat_real32_item*)MEM_mallocN(sizeof(quat_real32_item), "quat_real32_item"); + + item->vlayer = vlayer; + item->id = item_id; + item->value[0] = v0; + item->value[1] = v1; + item->value[2] = v2; + item->value[3] = v3; + + return item; +} + +/* Create item containing 1 float */ +static real32_item *create_real32_item(VLayer *vlayer, uint32 item_id, real32 value) +{ + struct real32_item *item; + + item = (real32_item*)MEM_mallocN(sizeof(real32_item), "real32_item"); + + item->vlayer = vlayer; + item->id = item_id; + item->value = value; + + return item; +} + +/* Create item containing 1 integer */ +static uint32_item *create_uint32_item(VLayer *vlayer, uint32 item_id, uint32 value) +{ + struct uint32_item *item; + + item = (uint32_item*)MEM_mallocN(sizeof(uint32_item), "uint32_item"); + + item->vlayer = vlayer; + item->id = item_id; + item->value = value; + + return item; +} + +/* Create item containing 1 byte */ +static uint8_item *create_uint8_item(VLayer *vlayer, uint32 item_id, uint8 value) +{ + struct uint8_item *item; + + item = (uint8_item*)MEM_mallocN(sizeof(uint8_item), "uint8_item"); + + item->vlayer = vlayer; + item->id = item_id; + item->value = value; + + return item; +} + +/* + * callback function: vertex crease was set + */ +static void cb_g_crease_set_vertex( + void *user_data, + VNodeID node_id, + const char *layer, + uint32 def_crease) +{ +} + +/* + * we have to test corretness of incoming data from verse server + * no two vertexes can have the same index + */ +static char test_polygon_set_corner_uint32( + uint32 v0, + uint32 v1, + uint32 v2, + uint32 v3) +{ + if((v0==v1) || (v0==v2) || (v0==v3) || (v1==v2) || (v1==v3) || (v2==v3)) + return 0; + else + return 1; +} + +/* + * try to find verse layer in sending queue of verse geometry node + */ +static VLayer *find_vlayer_in_sending_queue(VNode *vnode, VLayerID layer_id) +{ + struct VLayer *vlayer; + + /* try to find verse layyer in sending queue */ + vlayer = ((VGeomData*)vnode->data)->queue.first; + while(vlayer) { + if(vlayer->id==layer_id) return vlayer; + vlayer = vlayer->next; + } + + return NULL; +} + +/* + * this function will find edge in hash table, hash function isn't too optimal (it needs + * lot of memory for every verse node), but it works without any bug + */ +static VerseEdge* find_verse_edge(VNode *vnode, uint32 v0, uint32 v1) +{ + struct HashVerseEdge *hve; + + if(((VGeomData*)vnode->data)->hash==NULL) + ((VGeomData*)vnode->data)->hash = MEM_callocN(VEDHASHSIZE*sizeof(HashVerseEdge), "verse hashedge tab"); + + hve = ((VGeomData*)vnode->data)->hash + VEDHASH(v0, v1);; + while(hve) { + /* edge v0---v1 is the same edge as v1---v0 */ + if(hve->vedge && ((hve->vedge->v0==v0 && hve->vedge->v1==v1) || (hve->vedge->v0==v1 && hve->vedge->v1==v0))) return hve->vedge; + hve = hve->next; + } + + return NULL; +} + +/* + * insert hash of verse edge to hash table + */ +static void insert_verse_edgehash(VNode *vnode, VerseEdge *vedge) +{ + struct HashVerseEdge *first, *hve; + + if(((VGeomData*)vnode->data)->hash==NULL) + ((VGeomData*)vnode->data)->hash = MEM_callocN(VEDHASHSIZE*sizeof(HashVerseEdge), "verse hashedge tab"); + + first = ((VGeomData*)vnode->data)->hash + VEDHASH(vedge->v0, vedge->v1); + + if(first->vedge==NULL) { + first->vedge = vedge; + } + else { + hve = &(vedge->hash); + hve->vedge = vedge; + hve->next = first->next; + first->next = hve; + } +} + +/* + * remove hash of verse edge from hash table + */ +static void remove_verse_edgehash(VNode *vnode, VerseEdge *vedge) +{ + struct HashVerseEdge *first, *hve, *prev; + + hve = first = ((VGeomData*)vnode->data)->hash + VEDHASH(vedge->v0, vedge->v1); + + while(hve) { + if(hve->vedge == vedge) { + if(hve==first) { + if(first->next) { + hve = first->next; + first->vedge = hve->vedge; + first->next = hve->next; + } + else { + hve->vedge = NULL; + } + } + else { + prev->next = hve->next; + } + return; + } + prev = hve; + hve = hve->next; + } +} + +/* + * this function will try to remove existing fake verse edge, when this verse + * edge is still used by some faces, then counter will be only decremented + */ +static void remove_verse_edge(VNode *vnode, uint32 v0, uint32 v1) +{ + struct VerseEdge *vedge; + + vedge = find_verse_edge(vnode, v0, v1); + if(vedge) { + vedge->counter--; + if(vedge->counter==0) { + remove_verse_edgehash(vnode, vedge); + BLI_freelinkN(&(((VGeomData*)vnode->data)->edges), vedge); + } + } + else { + printf("error: remove_verse_edge %d, %d\n", v0, v1); + } +} + +/* + * this function will try to add new fake verse edge, when no such edge exist, + * when such edge exist, then only counter of edge will be incremented + */ +static void add_verse_edge(VNode *vnode, uint32 v0, uint32 v1) +{ + struct VerseEdge *vedge; + + vedge = find_verse_edge(vnode, v0, v1); + if(!vedge) { + if(v0!=v1) { + vedge = create_verse_edge(v0, v1); + BLI_addtail(&(((VGeomData*)vnode->data)->edges), vedge); + insert_verse_edgehash(vnode, vedge); + } + else { + printf("error:add_verse_edge: %d, %d\n", v0, v1); + return; + } + } + vedge->counter++; +} + +/* + * verse face was deleted ... update edge hash + */ +static void update_edgehash_of_deleted_verseface(VNode *vnode, VerseFace *vface) +{ + uint32 v0, v1, v2, v3; /* verse vertex indexes of deleted verse face */ + + v0 = vface->vvert0->id; + v1 = vface->vvert1->id; + v2 = vface->vvert2->id; + v3 = vface->vvert3 ? vface->vvert3->id : -1; + + remove_verse_edge(vnode, v0, v1); + remove_verse_edge(vnode, v1, v2); + if(v3!=-1) { + remove_verse_edge(vnode, v2, v3); + remove_verse_edge(vnode, v3, v0); + } + else { + remove_verse_edge(vnode, v2, v0); + } +} + +/* + * existing verse face was changed ... update edge hash + */ +static void update_edgehash_of_changed_verseface( + VNode *vnode, + VerseFace *vface, + uint32 v0, + uint32 v1, + uint32 v2, + uint32 v3) +{ + uint32 ov0, ov1, ov2, ov3; /* old indexes at verse vertexes*/ + + ov0 = vface->vvert0->id; + ov1 = vface->vvert1->id; + ov2 = vface->vvert2->id; + ov3 = vface->vvert3 ? vface->vvert3->id : -1; + + /* 1st edge */ + if(v0!=ov0 || v1!=ov1) { + remove_verse_edge(vnode, ov0, ov1); + add_verse_edge(vnode, v0, v1); + } + + /* 2nd edge */ + if(v1!=ov1 || v2!=ov2) { + remove_verse_edge(vnode, ov1, ov2); + add_verse_edge(vnode, v1, v2); + } + + /* 3rd edge */ + if(v2!=ov2 || v3!=ov3 || v0!=ov0) { + if(ov3!=-1) { + remove_verse_edge(vnode, ov2, ov3); + if(v3!=-1) { + add_verse_edge(vnode, v2, v3); /* new 3rd edge (quat->quat) */ + } + else { + remove_verse_edge(vnode, ov3, ov0); /* old edge v3,v0 of quat have to be removed */ + add_verse_edge(vnode, v2, v0); /* new 3rd edge (quat->triangle) */ + } + } + else { + remove_verse_edge(vnode, ov2, ov0); + if(v3!=-1) { + add_verse_edge(vnode, v2, v3); /* new 3rd edge (triangle->quat) */ + } + else { + add_verse_edge(vnode, v2, v0); /* new 3rd edge (triangle->triangle) */ + } + } + } + + /* 4th edge */ + if(v3!=-1 && (v3!=ov3 || v0!=ov0)) { + remove_verse_edge(vnode, ov3, ov0); + add_verse_edge(vnode, v3, v0); + } +} + +/* + * new verse face was created ... update list of edges and edge has + */ +static void update_edgehash_of_new_verseface( + VNode *vnode, + uint32 v0, + uint32 v1, + uint32 v2, + uint32 v3) +{ + /* when edge already exists, then only its counter is incremented, + * look at commentary of add_verse_edge() function */ + add_verse_edge(vnode, v0, v1); + add_verse_edge(vnode, v1, v2); + if(v3!=-1) { + add_verse_edge(vnode, v2, v3); + add_verse_edge(vnode, v3, v0); + } + else { + add_verse_edge(vnode, v2, v0); + } +} + +/* + * callback function: edge crease was set + */ +static void cb_g_crease_set_edge( + void *user_data, + VNodeID node_id, + const char *layer, + uint32 def_crease) +{ +} + +/* + * callback function: float value for polygon was set up + */ +static void cb_g_polygon_set_face_real32( + void *user_def, + VNodeID node_id, + VLayerID layer_id, + uint32 polygon_id, + real32 value) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VLayer *vlayer; + struct real32_item *item; + + if(!session) return; + + /* find needed node (we can be sure, that it is geometry node) */ + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + + /* find layer containing uint_8 data */ + vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id); + + /* try to find item*/ + item = BLI_dlist_find_link(&(vlayer->dl), polygon_id); + + if(item) { + item->value = value; + } + else { + item = create_real32_item(vlayer, polygon_id, value); + BLI_dlist_add_item_index(&(vlayer->dl), item, item->id); + } +} + +/* + * callback function: int values for polygon was set up + */ +static void cb_g_polygon_set_face_uint32( + void *user_def, + VNodeID node_id, + VLayerID layer_id, + uint32 polygon_id, + uint32 value) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VLayer *vlayer; + struct uint32_item *item; + + if(!session) return; + + /* find needed node (we can be sure, that it is geometry node) */ + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + + /* find layer containing uint_8 data */ + vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id); + + /* try to find item*/ + item = BLI_dlist_find_link(&(vlayer->dl), polygon_id); + + if(item) { + item->value = value; + } + else { + item = create_uint32_item(vlayer, polygon_id, value); + BLI_dlist_add_item_index(&(vlayer->dl), item, item->id); + } +} + +/* + * callback function: uint8 value for polygon was set up + */ +static void cb_g_polygon_set_face_uint8( + void *user_def, + VNodeID node_id, + VLayerID layer_id, + uint32 polygon_id, + uint8 value) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VLayer *vlayer; + struct uint8_item *item; + + if(!session) return; + + /* find needed node (we can be sure, that it is geometry node) */ + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + + /* find layer containing uint_8 data */ + vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id); + + /* try to find item*/ + item = BLI_dlist_find_link(&(vlayer->dl), polygon_id); + + if(item) { + item->value = value; + } + else { + item = create_uint8_item(vlayer, polygon_id, value); + BLI_dlist_add_item_index(&(vlayer->dl), item, item->id); + } +} + +/* + * callback function: float value for polygon corner was set up + */ +static void cb_g_polygon_set_corner_real32( + void *user_def, + VNodeID node_id, + VLayerID layer_id, + uint32 polygon_id, + real32 v0, + real32 v1, + real32 v2, + real32 v3) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VLayer *vlayer; + struct quat_real32_item *item; + + if(!session) return; + + /* find needed node (we can be sure, that it is geometry node) */ + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + + /* find layer containing uint_8 data */ + vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id); + + /* try to find item*/ + item = BLI_dlist_find_link(&(vlayer->dl), polygon_id); + + if(item) { + item->value[0] = v0; + item->value[1] = v1; + item->value[2] = v2; + item->value[3] = v3; + } + else { + item = create_quat_real32_item(vlayer, polygon_id, v0, v1, v2, v3); + BLI_dlist_add_item_index(&(vlayer->dl), item, item->id); + } +} + +/* + * callback function: polygon is deleted + */ +static void cb_g_polygon_delete( + void *user_data, + VNodeID node_id, + uint32 polygon_id) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + VNode *vnode; + VLayer *vlayer; + VerseFace *vface; + + if(!session) return; + + /* find needed node (we can be sure, that it is geometry node) */ + vnode = BLI_dlist_find_link(&(session->nodes), node_id); + + /* find layer containing faces */ + vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); + + /* find wanted VerseFace */ + vface = BLI_dlist_find_link(&(vlayer->dl), polygon_id); + + if(!vface) return; + + /* update edge hash */ + update_edgehash_of_deleted_verseface(vnode, vface); + + ((VGeomData*)vnode->data)->post_polygon_delete(vface); + + /* decrease references at coresponding VerseVertexes */ + vface->vvert0->counter--; + vface->vvert1->counter--; + vface->vvert2->counter--; + if(vface->vvert3) vface->vvert3->counter--; + + /* delete unneeded VerseVertexes */ + free_unneeded_verseverts_of_verseface(vnode, vface); + + free_verse_face(vlayer, vface); +} + +/* + * callback function: new polygon (face) created or existing polygon was changed + */ +static void cb_g_polygon_set_corner_uint32( + void *user_data, + VNodeID node_id, + VLayerID layer_id, + uint32 polygon_id, + uint32 v0, + uint32 v1, + uint32 v2, + uint32 v3) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VLayer *vlayer; + struct VerseFace *vface=NULL; + + if(!session) return; + + /* try to find VerseNode */ + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + if(!vnode) return; + + /* try to find VerseLayer */ + vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id); + if(!vlayer) return; + + /* we have to test coretness of incoming data */ + if(!test_polygon_set_corner_uint32(v0, v1, v2, v3)) return; + + /* Blender uses different order of vertexes */ + if(v3!=-1) { /* quat swap */ + unsigned int v; v = v1; v1 = v3; v3 = v; + } + else { /* triangle swap */ + unsigned int v; v = v1; v1 = v2; v2 = v; + } + + /* try to find VerseFace */ + vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), (unsigned int)polygon_id); + + /* try to find modified VerseFace */ + if(!vface) { + vface = find_changed_verse_face_in_queue(vlayer, polygon_id); + if(vface) { + BLI_remlink(&(vlayer->queue), (void*)vface); + BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, (unsigned int)polygon_id); + } + } + + if(!vface) { + /* try to find VerseFace in list of VerseVaces created by me and set up polygon and + * layer ids */ + vface = find_verse_face_in_queue(vlayer, node_id, polygon_id, v0, v1, v2, v3); + + /* update edge hash */ + update_edgehash_of_new_verseface(vnode, v0, v1, v2, v3); + + if(vface){ + /* I creeated this face ... remove VerseFace from queue */ + BLI_remlink(&(vlayer->queue), (void*)vface); + } + else { + /* some other client created this face*/ + vface = create_verse_face(vlayer, polygon_id, v0, v1, v2, v3); + } + + vface->flag &= ~FACE_SENT; + + /* return number of missing verse vertexes */ + vface->counter = test_incoming_verseface((VGeomData*)vnode->data, vface); + + if(vface->counter < 1) { + /* when VerseFace received all needed VerseFaces, then it is moved + * to list of VerseFaces */ + BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, (unsigned int)polygon_id); + increase_verse_verts_references(vface); + recalculate_verseface_normals(vnode); + ((VGeomData*)vnode->data)->post_polygon_create(vface); + } + else { + /* when all needed VerseVertexes weren't received, then VerseFace is moved to + * the list of orphans waiting on needed vertexes */ + vface->flag |= FACE_RECEIVED; + BLI_addtail(&(vlayer->orphans), (void*)vface); + } + } + else { + VLayer *vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); + /* VerseVertexes of existing VerseFace were changed (VerseFace will use some different + * VerseVertexes or it will use them in different order) */ + + /* update fake verse edges */ + update_edgehash_of_changed_verseface(vnode, vface, v0, v1, v2, v3); + + /* initialize count of unreceived vertexes needed for this face */ + vface->counter = 4; + + /* 1st corner */ + if(vface->vvert0->id != v0) { + /* decrease references of obsolete vertexes*/ + vface->vvert0->counter--; + /* delete this vertex, when it isn't used by any face and it was marked as deleted */ + if((vface->vvert0->counter < 1) && (vface->vvert0->flag & VERT_DELETED)) { + ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert0); + free_verse_vertex(vert_vlayer, vface->vvert0); + } + /* try to set up new pointer at verse vertex */ + vface->v0 = v0; + vface->vvert0 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v0); + if(vface->vvert0) { + /* increase references at new vertex */ + vface->vvert0->counter++; + /* decrease count of needed vertex to receive */ + vface->counter--; + } + + } + else + /* this corner wasn't changed */ + vface->counter--; + + /* 2nd corner */ + if(vface->vvert1->id != v1) { + vface->vvert1->counter--; + if((vface->vvert1->counter < 1) && (vface->vvert1->flag & VERT_DELETED)) { + ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert1); + free_verse_vertex(vert_vlayer, vface->vvert1); + } + vface->v1 = v1; + vface->vvert1 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v1); + if(vface->vvert1) { + vface->vvert1->counter++; + vface->counter--; + } + } + else + vface->counter--; + + /* 3rd corner */ + if(vface->vvert2->id != v2) { + vface->vvert2->counter--; + if((vface->vvert2->counter < 1) && (vface->vvert2->flag & VERT_DELETED)) { + ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert2); + free_verse_vertex(vert_vlayer, vface->vvert2); + } + vface->v2 = v2; + vface->vvert2 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v2); + if(vface->vvert2) { + vface->vvert2->counter++; + vface->counter--; + } + } + else + vface->counter--; + + /* 4th corner */ + if(vface->vvert3) { + if(vface->vvert3->id != v3) { + vface->vvert3->counter--; + if((vface->vvert3->counter < 1) && (vface->vvert3->flag & VERT_DELETED)) { + ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert3); + free_verse_vertex(vert_vlayer, vface->vvert3); + } + vface->v3 = v3; + if(v3 != -1) { + vface->vvert3 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v3); + if(vface->vvert3) { + vface->vvert3->counter++; + vface->counter--; + } + } + else { + /* this is some special case, this face hase now only 3 corners + * quat -> triangle */ + vface->vvert3 = NULL; + vface->counter--; + } + } + } + else if(v3 != -1) + /* this is some special case, 4th corner of this polygon was created + * triangle -> quat */ + vface->v3 = v3; + vface->vvert3 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v3); + if(vface->vvert3) { + vface->vvert3->counter++; + vface->counter--; + } + else { + vface->v3 = -1; + vface->counter--; + } + + vface->flag &= ~FACE_SENT; + vface->flag |= FACE_CHANGED; + + if(vface->counter<1) { + vface->flag &= ~FACE_CHANGED; + recalculate_verseface_normals(vnode); + ((VGeomData*)vnode->data)->post_polygon_set_corner(vface); + } + else { + /* when all needed VerseVertexes weren't received, then VerseFace is added to + * the list of orphans waiting on needed vertexes */ + BLI_dlist_rem_item(&(vlayer->dl), vface->id); + BLI_addtail(&(vlayer->orphans), (void*)vface); + } + } +} + +/* + * callback function: float value was set up for VerseVert with vertex_id + */ +static void cb_g_vertex_set_real32( + void *user_def, + VNodeID node_id, + VLayerID layer_id, + uint32 vertex_id, + real32 value) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VLayer *vlayer; + struct real32_item *item; + + if(!session) return; + + /* find needed node (we can be sure, that it is geometry node) */ + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + + /* find layer containing uint_8 data */ + vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id); + + /* try to find item*/ + item = BLI_dlist_find_link(&(vlayer->dl), vertex_id); + + if(item) { + item->value = value; + } + else { + item = create_real32_item(vlayer, vertex_id, value); + BLI_dlist_add_item_index(&(vlayer->dl), item, item->id); + } +} + +/* + * callback function: int value was set up for VerseVert with vertex_id + */ +static void cb_g_vertex_set_uint32( + void *user_def, + VNodeID node_id, + VLayerID layer_id, + uint32 vertex_id, + uint32 value) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VLayer *vlayer; + struct uint32_item *item; + + if(!session) return; + + /* find needed node (we can be sure, that it is geometry node) */ + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + + /* find layer containing uint_8 data */ + vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id); + + /* try to find item*/ + item = BLI_dlist_find_link(&(vlayer->dl), vertex_id); + + if(item) { + item->value = value; + } + else { + item = create_uint32_item(vlayer, vertex_id, value); + BLI_dlist_add_item_index(&(vlayer->dl), item, item->id); + } +} + +/* + * callback function: polygon was deleted + */ +static void cb_g_vertex_delete_real32( + void *user_data, + VNodeID node_id, + uint32 vertex_id) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + VNode *vnode=NULL; + VLayer *vert_vlayer=NULL; + VerseVert *vvert=NULL; + + if(!session) return; + + vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + + vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); + + vvert = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vertex_id); + + if(!vvert) return; + + if(vvert->counter < 1) { + ((VGeomData*)vnode->data)->post_vertex_delete(vvert); + BLI_dlist_free_item(&(vert_vlayer->dl), (unsigned int)vertex_id); + } + else { + /* some VerseFace(s) still need VerseVert, remove verse vert from + * list verse vertexes and put it to list of orphans */ + vvert->flag |= VERT_DELETED; + BLI_dlist_rem_item(&(vert_vlayer->dl), (unsigned int)vertex_id); + BLI_addtail(&(vert_vlayer->orphans), vvert); + } +} + +/* + * callback function: position of one vertex was changed or new vertex was created + */ +static void cb_g_vertex_set_xyz_real32( + void *user_data, + VNodeID node_id, + VLayerID layer_id, + uint32 vertex_id, + real32 x, + real32 y, + real32 z) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode = NULL; + struct VLayer *vlayer = NULL; + struct VerseVert *vvert = NULL; + real32 tmp; + + if(!session) return; + + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + if(!vnode)return; + + vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id); + if(!vlayer) return; + + /* switch axis orientation */ + tmp = y; + y = -z; + z = tmp; + + if(vlayer->id == 0) { + /* try to pick up verse vert from DynamicList */ + vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), (unsigned int)vertex_id); + + if(vvert) { + if(vvert->flag & VERT_OBSOLETE) return; + + if (vvert->flag & VERT_LOCKED) { + /* this application changed position of this vertex */ + if((vvert->co[0]==x) && (vvert->co[1]==y) && (vvert->co[2]==z)) { + /* unlock vertex position */ + vvert->flag &= ~VERT_LOCKED; + /* call post_vertex_set_xyz only, when position of vertex is + * obsolete ... the new vertex position will be sent to + * verse server */ + if (vvert->flag & VERT_POS_OBSOLETE) { + ((VGeomData*)vnode->data)->post_vertex_set_xyz(vvert); + } + } + } + else { + /* somebody else changed position of this vertex*/ + if((vvert->co[0]!=x) || (vvert->co[1]!=y) || (vvert->co[2]!=z)) { + vvert->co[0] = x; + vvert->co[1] = y; + vvert->co[2] = z; + recalculate_verseface_normals(vnode); + ((VGeomData*)vnode->data)->post_vertex_set_xyz(vvert); + } + } + } + else { + /* create new verse vert */ + + /* test if we are authors of this vertex :-) */ + vvert = find_verse_vert_in_queue(vlayer, node_id, vertex_id, x, y, z); + + if(vvert) { + /* remove vert from queue */ + BLI_remlink(&(vlayer->queue), (void*)vvert); + /* add vvert to the dynamic list */ + BLI_dlist_add_item_index(&(vlayer->dl), (void*)vvert, (unsigned int)vertex_id); + /* set VerseVert flags */ + vvert->flag |= VERT_RECEIVED; + if(!(vvert->flag & VERT_POS_OBSOLETE)) + vvert->flag &= ~VERT_LOCKED; + /* find VerseFaces orphans */ + find_vlayer_orphans(vnode, vvert); + /* find unsent VerseFaces */ + find_unsent_faces(vnode, vvert); + } + else { + /* create new VerseVert */ + vvert = create_verse_vertex(vlayer, vertex_id, x, y, z); + /* add VerseVert to list of VerseVerts */ + BLI_dlist_add_item_index(&(vlayer->dl), (void*)vvert, (unsigned int)vertex_id); + /* set VerseVert flags */ + vvert->flag |= VERT_RECEIVED; + /* find VerseFaces orphans */ + find_vlayer_orphans(vnode, vvert); + } + + ((VGeomData*)vnode->data)->post_vertex_create(vvert); + } + } +} + +/* + * callback function for destroyng of verse layer + */ +static void cb_g_layer_destroy( + void *user_data, + VNodeID node_id, + VLayerID layer_id) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VLayer *vlayer; + + if(!session) return; + + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), node_id); + if(!vnode) return; + + vlayer = (VLayer*) BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), layer_id); + + if(vlayer){ + /* free VerseLayer data */ + free_verse_layer_data(vnode, vlayer); + /* remove VerseLayer from list of verse layers */ + BLI_dlist_rem_item(&(((VGeomData*)vnode->data)->layers), layer_id); + /* do client dependent actions */ + vlayer->post_layer_destroy(vlayer); + /* free vlayer itself */ + MEM_freeN(vlayer); + } + +} + +/* + * callback function: new layer was created + */ +static void cb_g_layer_create( + void *user_data, + VNodeID node_id, + VLayerID layer_id, + const char *name, + VNGLayerType type, + uint32 def_integer, + real64 def_real) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode=NULL; + struct VLayer *vlayer=NULL; + + if(!session) return; + + /* find node of this layer*/ + vnode = BLI_dlist_find_link(&(session->nodes), node_id); + if(!vnode) return; + + /* when we created this layer, then subscribe to this layer */ + if(vnode->owner_id == VN_OWNER_MINE || session->flag & VERSE_AUTOSUBSCRIBE) + verse_send_g_layer_subscribe(node_id, layer_id, 0); + + /* try to find */ + if(vnode->owner_id == VN_OWNER_MINE) + vlayer = find_vlayer_in_sending_queue(vnode, layer_id); + + if(vlayer) { + /* remove vlayer form sending queue add verse layer to list of verse layers */ + BLI_remlink(&((VGeomData*)vnode->data)->queue, vlayer); + BLI_dlist_add_item_index(&((VGeomData*)vnode->data)->layers, (void*)vlayer, (unsigned int)vlayer->id); + /* send all not sent vertexes to verse server + * other items waiting in sending queue will be automaticaly sent to verse server, + * when verse vertexes will be received from verse server */ + if((vlayer->type == VN_G_LAYER_VERTEX_XYZ) && (layer_id==0)) { + struct VerseVert *vvert = (VerseVert*)vlayer->queue.first; + while(vvert) { + send_verse_vertex(vvert); + vvert = vvert->next; + } + } + } + else { + /* create new VerseLayer */ + vlayer = create_verse_layer(vnode, layer_id, name, type, def_integer, def_real); + /* add layer to the list of VerseLayers */ + BLI_dlist_add_item_index(&(((VGeomData*)vnode->data)->layers), (void*)vlayer, (unsigned int)layer_id); + } + + vlayer->flag |= LAYER_RECEIVED; + + /* post callback function */ + vlayer->post_layer_create(vlayer); +} + +/* + * this function will send destroy commands for all VerseVertexes and + * VerseFaces to verse server, but it will not send destroy commands + * for VerseLayers or geometry node, it can be used in other functions + * (undo, destroy geom node, some edit mesh commands, ... ), parameter of + * this function has to be geometry verse node + */ +void destroy_geometry(VNode *vnode) +{ + struct VLayer *vert_vlayer, *face_vlayer; + struct VerseFace *vface; + struct VerseVert *vvert; + + if(vnode->type != V_NT_GEOMETRY) return; + + face_vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); + vface = face_vlayer->dl.lb.first; + + while(vface) { + send_verse_face_delete(vface); + vface = vface->next; + } + + vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); + vvert = vert_vlayer->dl.lb.first; + + while(vvert) { + send_verse_vertex_delete(vvert); + vvert = vvert->next; + } + + /* own destruction of local verse date will be executed, when client will + * receive apropriate callback commands from verse server */ +} + +/* + * free VGeomData + */ +void free_geom_data(VNode *vnode) +{ + struct VerseSession *session = vnode->session; + struct VLayer *vlayer; + + if(vnode->data){ + vlayer = (VLayer*)((VGeomData*)vnode->data)->layers.lb.first; + while(vlayer){ + /* unsubscribe from layer */ + if(session->flag & VERSE_CONNECTED) + verse_send_g_layer_unsubscribe(vnode->id, vlayer->id); + /* free VerseLayer data */ + free_verse_layer_data(vnode, vlayer); + /* next layer */ + vlayer = vlayer->next; + } + /* free constraint between vnode and mesh */ + ((VGeomData*)vnode->data)->post_geometry_free_constraint(vnode); + /* free all VerseLayers */ + BLI_dlist_destroy(&(((VGeomData*)vnode->data)->layers)); + /* free fake verse edges */ + BLI_freelistN(&((VGeomData*)vnode->data)->edges); + /* free edge hash */ + MEM_freeN(((VGeomData*)vnode->data)->hash); + } +} + +void set_geometry_callbacks(void) +{ + /* new layer created */ + verse_callback_set(verse_send_g_layer_create, cb_g_layer_create, NULL); + /* layer was destroyed */ + verse_callback_set(verse_send_g_layer_destroy, cb_g_layer_destroy, NULL); + + /* position of vertex was changed */ + verse_callback_set(verse_send_g_vertex_set_xyz_real32, cb_g_vertex_set_xyz_real32, NULL); + /* vertex was deleted */ + verse_callback_set(verse_send_g_vertex_delete_real32, cb_g_vertex_delete_real32, NULL); + + /* callback functions for values being associated with vertexes */ + verse_callback_set(verse_send_g_vertex_set_uint32, cb_g_vertex_set_uint32, NULL); + verse_callback_set(verse_send_g_vertex_set_real32, cb_g_vertex_set_real32, NULL); + + /* new polygon was created / vertex(es) of polygon was set */ + verse_callback_set(verse_send_g_polygon_set_corner_uint32, cb_g_polygon_set_corner_uint32, NULL); + /* polygon was deleted */ + verse_callback_set(verse_send_g_polygon_delete, cb_g_polygon_delete, NULL); + + /* callback functions for values being associated with polygon corners */ + verse_callback_set(verse_send_g_polygon_set_corner_real32, cb_g_polygon_set_corner_real32, NULL); + /* callback functions for values being associated with faces */ + verse_callback_set(verse_send_g_polygon_set_face_uint8, cb_g_polygon_set_face_uint8, NULL); + verse_callback_set(verse_send_g_polygon_set_face_uint32, cb_g_polygon_set_face_uint32, NULL); + verse_callback_set(verse_send_g_polygon_set_face_real32, cb_g_polygon_set_face_real32, NULL); + + /* crease of vertex was set */ + verse_callback_set(verse_send_g_crease_set_vertex, cb_g_crease_set_vertex, NULL); + /* crease of edge was set */ + verse_callback_set(verse_send_g_crease_set_edge, cb_g_crease_set_edge, NULL); +} + +#endif diff --git a/source/blender/blenkernel/intern/verse_method.c b/source/blender/blenkernel/intern/verse_method.c new file mode 100644 index 00000000000..89b5282acfd --- /dev/null +++ b/source/blender/blenkernel/intern/verse_method.c @@ -0,0 +1,523 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributor(s): Nathan Letwory. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef WITH_VERSE + +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" +#include "DNA_userdef_types.h" +#include "DNA_text_types.h" + +#include "BLI_dynamiclist.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "BIF_verse.h" + +#include "BKE_bad_level_calls.h" +#include "BKE_library.h" +#include "BKE_text.h" +#include "BKE_verse.h" +#include "BKE_global.h" +#include "BKE_main.h" + +#include "verse.h" + +/* helper struct for creating method descriptions */ +typedef struct VMethodInfo { + const char *name; + uint8 param_count; + const VNOParamType param_type[4]; + const char *param_name[4]; + uint16 id; +} VMethodInfo; + +#ifdef VERSECHAT +/* array with methods for verse chat */ +static VMethodInfo vmethod_info[] = { + { "join", 1, { VN_O_METHOD_PTYPE_STRING }, { "channel"}}, + { "leave", 1, { VN_O_METHOD_PTYPE_STRING }, { "channel"}}, + { "hear", 3, { VN_O_METHOD_PTYPE_STRING, VN_O_METHOD_PTYPE_STRING, VN_O_METHOD_PTYPE_STRING }, { "channel", "from", "msg"}} +}; +#endif + +/* lookup a method group based on its name */ +struct VMethodGroup *lookup_vmethodgroup_name(ListBase *lb, const char *name) { + struct VMethodGroup *vmg; + + for(vmg= lb->first; vmg; vmg= vmg->next) + if(strcmp(vmg->name,name)==0) break; + + return vmg; +} + +/* lookup a method group based on its group_id */ +struct VMethodGroup *lookup_vmethodgroup(ListBase *lb, uint16 group_id) { + struct VMethodGroup *vmg; + + for(vmg= lb->first; vmg; vmg= vmg->next) + if(vmg->group_id==group_id) break; + + return vmg; +} + +/* lookup a method based on its name */ +struct VMethod *lookup_vmethod_name(ListBase *lb, const char *name) { + struct VMethod *vm; + for(vm= lb->first; vm; vm= vm->next) + if(strcmp(vm->name,name)==0) break; + + return vm; +} + +/* lookup a method based on its method_id */ +struct VMethod *lookup_vmethod(ListBase *lb, uint8 method_id) { + struct VMethod *vm; + for(vm= lb->first; vm; vm= vm->next) + if(vm->id==method_id) break; + + return vm; +} + +#ifdef VERSECHAT +/* + * send say command + */ +void send_say(const char *chan, const char *utter) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VMethodGroup *vmg; + struct VMethod *vm; + VNOPackedParams *utterpack; + VNOParam args[2]; + + vnode= (VNode *)(session->nodes.lb.first); + + for( ; vnode; vnode= vnode->next) { + if(strcmp(vnode->name, "tawksrv")==0) { + vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk"); + if(!vmg) break; + vm= lookup_vmethod_name(&(vmg->methods), "say"); + if(!vm) break; + args[0].vstring= (char *)chan; + args[1].vstring= (char *)utter; + if((utterpack= verse_method_call_pack(vm->param_count, vm->param_type, args))!=NULL) { + verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, utterpack); + } + break; + } + + } +} + +/* + * send logout command + */ +void send_logout(VNode *vnode) +{ + struct VMethodGroup *vmg; + struct VMethod *vm; + VNOPackedParams *pack; + + vnode->chat_flag = CHAT_LOGGED; + vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk"); + if(!vmg) return; + vm= lookup_vmethod_name(&(vmg->methods), "logout"); + if(!vm) return; + + if((pack= verse_method_call_pack(vm->param_count, vm->param_type, NULL))!=NULL) { + verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, pack); + } + vnode->chat_flag = CHAT_NOTLOGGED; +} + +/* + * send join command + */ +void send_join(VNode *vnode, const char *chan) +{ + struct VMethodGroup *vmg; + struct VMethod *vm; + VNOPackedParams *join; + VNOParam channel[1]; + + vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk"); + if(!vmg) return; + vm= lookup_vmethod_name(&(vmg->methods), "join"); + if(!vm) return; + + channel[0].vstring= (char *)chan; + if((join= verse_method_call_pack(vm->param_count, vm->param_type, channel))!=NULL) { + verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, join); + } +} + +/* + * send leave command + */ +void send_leave(VNode *vnode, const char *chan) +{ + struct VMethodGroup *vmg; + struct VMethod *vm; + VNOPackedParams *leave; + VNOParam channel[1]; + + vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk"); + if(!vmg) return; + vm= lookup_vmethod_name(&(vmg->methods), "leave"); + if(!vm) return; + + channel[0].vstring= (char *)chan; + if((leave= verse_method_call_pack(vm->param_count, vm->param_type, channel))!=NULL) { + verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, leave); + } +} + +/* + * send login command + */ +void send_login(VNode *vnode) +{ + struct VMethodGroup *vmg; + struct VMethod *vm; + VNOPackedParams *login; + VNOParam param[1]; + + vnode->chat_flag = CHAT_LOGGED; + vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk"); + if(!vmg) return; + vm= lookup_vmethod_name(&(vmg->methods), "login"); + if(!vm) return; + + param[0].vstring= U.verseuser; + + if((login= verse_method_call_pack(vm->param_count, vm->param_type, param))!=NULL) { + verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, login); + } + vnode->chat_flag = CHAT_LOGGED; + + vnode= lookup_vnode(vnode->session, vnode->session->avatar); + vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk-client"); + if(!vmg) + verse_send_o_method_group_create(vnode->session->avatar, ~0, "tawk-client"); +} +#endif + +/* + * Free a VMethod + */ +void free_verse_method(VMethod *vm) { + if(!vm) return; + + MEM_freeN(vm->param_type); +} + +/* + * Free methods for VMethodGroup + */ +void free_verse_methodgroup(VMethodGroup *vmg) +{ + struct VMethod *vm, *tmpvm; + + if(!vmg) return; + + vm= vmg->methods.first; + while(vm) { + tmpvm=vm->next; + free_verse_method(vm); + vm= tmpvm; + } + BLI_freelistN(&(vmg->methods)); +} + +/* callback for method group creation */ +static void cb_o_method_group_create( + void *user_data, + VNodeID node_id, + uint16 group_id, + const char *name) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VMethodGroup *vmg; + + if(!session) return; + + vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + + vmg = lookup_vmethodgroup(&(vnode->methodgroups), group_id); + + /* create method group holder in node node_id */ + if(!vmg) { + vmg= MEM_mallocN(sizeof(VMethodGroup), "VMethodGroup"); + vmg->group_id = group_id; + vmg->methods.first = vmg->methods.last = NULL; + BLI_addtail(&(vnode->methodgroups), vmg); + printf("new method group with name %s (group_id %d) for node %u created\n", name, group_id, node_id); + } + + /* this ensures name of an existing group gets updated, in case it is changed */ + BLI_strncpy(vmg->name, (char *)name, 16); + + /* subscribe to method group */ + verse_send_o_method_group_subscribe(node_id, group_id); + +#ifdef VERSECHAT + /* if this is our own method group, register our methods */ + if(node_id==session->avatar) { + verse_send_o_method_create(node_id, group_id, (uint8)~0u, vmethod_info[0].name, + vmethod_info[0].param_count, + (VNOParamType *)vmethod_info[0].param_type, + (const char **)vmethod_info[0].param_name); + b_verse_update(); + verse_send_o_method_create(node_id, group_id, (uint8)~0u, vmethod_info[1].name, + vmethod_info[1].param_count, + (VNOParamType *)vmethod_info[1].param_type, + (const char **)vmethod_info[1].param_name); + b_verse_update(); + verse_send_o_method_create(node_id, group_id, (uint8)~0u, vmethod_info[2].name, + vmethod_info[2].param_count, + (VNOParamType *)vmethod_info[2].param_type, + (const char **)vmethod_info[2].param_name); + b_verse_update(); + } +#endif +} + +/* callback for method group destruction */ +static void cb_o_method_group_destroy( + void *user_data, + VNodeID node_id, + uint16 group_id, + const char *name) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VMethodGroup *vmg; + struct VMethod *vm; + + printf("method group %d destroyed\n", group_id); + + if(!session) return; + + vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + for(vmg= vnode->methodgroups.first; vmg; vmg= vmg->next) + if(vmg->group_id==group_id) break; + + if(!vmg) return; /* method group doesn't exist? */ + + vmg->group_id = 0; + vmg->name[0] = '\0'; + vm= vmg->methods.first; + while(vm) { + /* free vm */ + + } + + /* TODO: unsubscribe from method group */ + BLI_remlink(&(vnode->methodgroups),vmg); + MEM_freeN(vmg); +} + +/* callback for method creation */ +static void cb_o_method_create( + void *user_data, + VNodeID node_id, + uint16 group_id, + uint16 method_id, + const char *name, + uint8 param_count, + const VNOParamType *param_type, + const char *param_name[]) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VMethodGroup *vmg; + struct VMethod *vm; + unsigned int size; + unsigned int i; + char *put; + + if(!session) return; + + vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + + vmg= lookup_vmethodgroup((&vnode->methodgroups), group_id); + + if(!vmg) return; + + vm= lookup_vmethod((&vmg->methods), method_id); + + if(!vm) { + vm= MEM_mallocN(sizeof(VMethod), "VMethod"); + vm->id= method_id; + vm->param_count= param_count; + size= param_count* (sizeof(*vm->param_type) + sizeof(*vm->param_name)); + for(i= 0; i param_type= MEM_mallocN(size, "param_type and param_name"); + memcpy(vm->param_type, param_type, sizeof(VNOParamType)*param_count); + vm->param_name= (char **)(vm->param_type + param_count); + put= (char *)(vm->param_name + param_count); + for(i= 0; i < param_count; i++) { + vm->param_name[i]= put; + strcpy(put, param_name[i]); + put += strlen(param_name[i]) + 1; + } + + BLI_addtail(&(vmg->methods), vm); +#ifdef VERSECHAT + if(strcmp(vmethod_info[0].name, name)==0) { + vmethod_info[0].id = method_id; + } +#endif + printf("method %s in group %d of node %u created\n", name, group_id, node_id); + } + + BLI_strncpy(vm->name, (char *)name, 500); +} + +/* callback for method destruction */ +static void cb_o_method_destroy( + void *user_data, + VNodeID node_id, + uint16 group_id, + uint16 method_id, + const char *name, + uint8 param_count, + const VNOParamType *param_type, + const char *param_name[]) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VMethodGroup *vmg; + struct VMethod *vm; + + if(!session) return; + + vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + for(vmg= vnode->methodgroups.first; vmg; vmg= vmg->next) + if(vmg->group_id==group_id) break; + + if(!vmg) return; /* method group doesn't exist? */ + + for(vm= vmg->methods.first; vm; vm= vm->next) + if(vm->id==method_id) break; + + if(!vm) return; + + BLI_remlink(&(vmg->methods), vm); + MEM_freeN(vm->param_type); + MEM_freeN(vm); +} + +/* callback for method calls */ +static void cb_o_method_call(void *user_data, VNodeID node_id, uint8 group_id, uint8 method_id, VNodeID sender, VNOPackedParams *params) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VMethodGroup *vmg; + struct VMethod *vm; + Text *text; + int method_idx= -1; + + VNOParam arg[3]; + + if(!session) return; + + if(session->avatar!=node_id) return; + + vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + vmg= lookup_vmethodgroup(&(vnode->methodgroups), group_id); + if(!vmg) return; + + vm= lookup_vmethod(&(vmg->methods), method_id); + if(!vm) return; +#ifdef VERSECHAT + if(strcmp(vm->name, "join")==0) method_idx=0; + if(strcmp(vm->name, "leave")==0) method_idx=1; + if(strcmp(vm->name, "hear")==0) method_idx=2; + if(method_idx>-1) + verse_method_call_unpack(params, vmethod_info[method_idx].param_count, vmethod_info[method_idx].param_type, arg); + + switch(method_idx) { + case 0: + printf("Joining channel %s\n",arg[0].vstring); + text=add_empty_text(); + text->flags |= TXT_ISCHAT; + rename_id(&(text->id), arg[0].vstring); + break; + case 1: + printf("Leaving channel %s\n",arg[0].vstring); + break; + case 2: + { + ListBase lb = G.main->text; + ID *id= (ID *)lb.first; + char showstr[1024]; + showstr[0]='\0'; + text = NULL; + sprintf(showstr, "%s: %s\n", arg[1].vstring, arg[2].vstring); + for(; id; id= id->next) { + if(strcmp(id->name+2, arg[0].vstring)==0 && strcmp(arg[0].vstring, "#server")!=0) { + text = (Text *)id; + break; + } + } + if(text) { + txt_insert_buf(text, showstr); + txt_move_eof(text, 0); + allqueue(REDRAWCHAT, 0); + } else { + printf("%s> %s: %s\n",arg[0].vstring, arg[1].vstring, arg[2].vstring); + } + } + break; + } +#endif +} + +void set_method_callbacks(void) +{ + /* create and destroy method groups */ + verse_callback_set(verse_send_o_method_group_create, cb_o_method_group_create, NULL); + verse_callback_set(verse_send_o_method_group_destroy, cb_o_method_group_destroy, NULL); + + /* create and destroy methods */ + verse_callback_set(verse_send_o_method_create, cb_o_method_create, NULL); + verse_callback_set(verse_send_o_method_destroy, cb_o_method_destroy, NULL); + + /* call methods */ + verse_callback_set(verse_send_o_method_call, cb_o_method_call, NULL); +} + +#endif diff --git a/source/blender/blenkernel/intern/verse_node.c b/source/blender/blenkernel/intern/verse_node.c new file mode 100644 index 00000000000..fd5a25598d3 --- /dev/null +++ b/source/blender/blenkernel/intern/verse_node.c @@ -0,0 +1,750 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributor(s): Jiri Hnidek. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef WITH_VERSE + +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" +#include "DNA_userdef_types.h" + +#include "BLI_dynamiclist.h" +#include "BLI_blenlib.h" + +#include "BIF_verse.h" + +#include "BKE_verse.h" + +#include "verse.h" + +/* function prototypes of static functions */ + /* for tags */ +static void free_verse_tag_data(struct VTag *vtag); +static struct VTag *find_tag_in_queue(struct VTagGroup *vtaggroup, const char *name); +static struct VTag *create_verse_tag(struct VTagGroup *vtaggroup, uint16 tag_id, const char *name, VNTagType type, const VNTag *tag); + /* for verse tag groups */ +static void free_verse_taggroup_data(struct VTagGroup *taggroup); +static struct VTagGroup *find_taggroup_in_queue(struct VNode *vnode, const char *name); +static struct VTagGroup *create_verse_taggroup(VNode *vnode, uint16 group_id, const char *name); + /* for verse nodes */ +static void move_verse_node_to_dlist(struct VerseSession *session, VNodeID vnode_id); + /* function prototypes of node callback functions */ +static void cb_tag_destroy(void *user_data, VNodeID node_id, uint16 group_id, uint16 tag_id); +static void cb_tag_create(void *user_data, VNodeID node_id, uint16 group_id, uint16 tag_id, const char *name, VNTagType type, const VNTag *tag); +static void cb_tag_group_destroy(void *user_data, VNodeID node_id, uint16 group_id); +static void cb_tag_group_create(void *user_data, VNodeID node_id, uint16 group_id, const char *name); +static void cb_node_name_set(void *user_data, VNodeID node_id, const char *name); +static void cb_node_destroy(void *user_data, VNodeID node_id); +static void cb_node_create(void *user_data, VNodeID node_id, uint8 type, VNodeID owner_id); + +/* + * send new tag to verse server + */ +void send_verse_tag(VTag *vtag) +{ + verse_send_tag_create(vtag->vtaggroup->vnode->id, + vtag->vtaggroup->id, + vtag->id, + vtag->name, + vtag->type, + vtag->tag); +} + +/* + * free tag data + */ +static void free_verse_tag_data(VTag *vtag) +{ + /* free name of verse tag */ + MEM_freeN(vtag->name); + /* free value of tag */ + MEM_freeN(vtag->tag); +} + +/* + * try to find tag in sending queue ... if tag will be found, then + * this function will removed tag from queue and will return pointer + * at this tag + */ +static VTag *find_tag_in_queue(VTagGroup *vtaggroup, const char *name) +{ + struct VTag *vtag; + + vtag = vtaggroup->queue.first; + + while(vtag) { + if(strcmp(vtag->name, name)==0) { + BLI_remlink(&(vtaggroup->queue), vtag); + break; + } + vtag = vtag->next; + } + + return vtag; +} + +/* + * create new verse tag + */ +static VTag *create_verse_tag( + VTagGroup *vtaggroup, + uint16 tag_id, + const char *name, + VNTagType type, + const VNTag *tag) +{ + struct VTag *vtag; + + vtag = (VTag*)MEM_mallocN(sizeof(VTag), "VTag"); + + vtag->vtaggroup = vtaggroup; + vtag->id = tag_id; + vtag->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "VTag name"); + strcpy(vtag->name, name); + vtag->type = type; + + vtag->tag = (VNTag*)MEM_mallocN(sizeof(VNTag), "VNTag"); + *vtag->tag = *tag; + + vtag->value = NULL; + + return vtag; +} + +/* + * send taggroup to verse server + */ +void send_verse_taggroup(VTagGroup *vtaggroup) +{ + verse_send_tag_group_create( + vtaggroup->vnode->id, + vtaggroup->id, + vtaggroup->name); +} + +/* + * free taggroup data + */ +static void free_verse_taggroup_data(VTagGroup *taggroup) +{ + struct VerseSession *session = taggroup->vnode->session; + struct VTag *vtag; + + vtag = taggroup->tags.lb.first; + + while(vtag) { + free_verse_tag_data(vtag); + vtag = vtag->next; + } + + /* unsubscribe from taggroup */ + if(session->flag & VERSE_CONNECTED) + verse_send_tag_group_unsubscribe(taggroup->vnode->id, taggroup->id); + + BLI_dlist_destroy(&(taggroup->tags)); + MEM_freeN(taggroup->name); +} + +/* + * move taggroup from queue to dynamic list with access array, + * set up taggroup id and return pointer at this taggroup + */ +static VTagGroup *find_taggroup_in_queue(VNode *vnode, const char *name) +{ + struct VTagGroup *vtaggroup; + + vtaggroup = vnode->queue.first; + + while(vtaggroup) { + if(strcmp(vtaggroup->name, name)==0) { + BLI_remlink(&(vnode->queue), vtaggroup); + break; + } + vtaggroup = vtaggroup->next; + } + + return vtaggroup; +} + +/* + * create new verse group of tags + */ +static VTagGroup *create_verse_taggroup(VNode *vnode, uint16 group_id, const char *name) +{ + struct VTagGroup *taggroup; + + taggroup = (VTagGroup*)MEM_mallocN(sizeof(VTagGroup), "VTagGroup"); + + taggroup->vnode = vnode; + taggroup->id = group_id; + taggroup->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "VTagGroup name"); + strcpy(taggroup->name, name); + + BLI_dlist_init(&(taggroup->tags)); + taggroup->queue.first = taggroup->queue.last = NULL; + + taggroup->post_tag_change = post_tag_change; + taggroup->post_taggroup_create = post_taggroup_create; + + return taggroup; +} + +/* + * move first VerseNode waiting in sending queue to dynamic list of VerseNodes + * (it usually happens, when "our" VerseNode was received from verse server) + */ +static void move_verse_node_to_dlist(VerseSession *session, VNodeID vnode_id) +{ + VNode *vnode; + + vnode = session->queue.first; + + if(vnode) { + BLI_remlink(&(session->queue), vnode); + BLI_dlist_add_item_index(&(session->nodes), (void*)vnode, vnode_id); + } +} + +/* + * send VerseNode to verse server + */ +void send_verse_node(VNode *vnode) +{ + verse_send_node_create( + vnode->id, + vnode->type, + vnode->session->avatar); +} + +/* + * free Verse Node data + */ +void free_verse_node_data(VNode *vnode) +{ + struct VerseSession *session = vnode->session; + struct VTagGroup *vtaggroup; + + /* free node data (object, geometry, etc.) */ + switch(vnode->type){ + case V_NT_OBJECT: + free_object_data(vnode); + break; + case V_NT_GEOMETRY: + free_geom_data(vnode); + break; + case V_NT_BITMAP: + free_bitmap_node_data(vnode); + break; + default: + break; + } + + /* free all tag groups in dynamic list with access array */ + vtaggroup = vnode->taggroups.lb.first; + while(vtaggroup) { + free_verse_taggroup_data(vtaggroup); + vtaggroup = vtaggroup->next; + } + BLI_dlist_destroy(&(vnode->taggroups)); + + /* free all tag groups still waiting in queue */ + vtaggroup = vnode->queue.first; + while(vtaggroup) { + free_verse_taggroup_data(vtaggroup); + vtaggroup = vtaggroup->next; + } + BLI_freelistN(&(vnode->queue)); + + /* unsubscribe from node */ + if(session->flag & VERSE_CONNECTED) + verse_send_node_unsubscribe(vnode->id); + + /* free node name */ + MEM_freeN(vnode->name); + vnode->name = NULL; + + /* free node data */ + MEM_freeN(vnode->data); + vnode->data = NULL; + +} + +/* + * free VerseNode + */ +void free_verse_node(VNode *vnode) +{ + free_verse_node_data(vnode); + + BLI_dlist_free_item(&(vnode->session->nodes), vnode->id); +} + +/* + * Find a Verse Node from session + */ +VNode* lookup_vnode(VerseSession *session, VNodeID node_id) +{ + struct VNode *vnode; + vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + + return vnode; +} + +/* + * create new Verse Node + */ +VNode* create_verse_node(VerseSession *session, VNodeID node_id, uint8 type, VNodeID owner_id) +{ + struct VNode *vnode; + + vnode = (VNode*)MEM_mallocN(sizeof(VNode), "VerseNode"); + + vnode->session = session; + vnode->id = node_id; + vnode->owner_id = owner_id; + vnode->name = NULL; + vnode->type = type; + + BLI_dlist_init(&(vnode->taggroups)); + vnode->queue.first = vnode->queue.last = NULL; + vnode->methodgroups.first = vnode->methodgroups.last = NULL; + + vnode->data = NULL; + + vnode->counter = 0; + + vnode->flag = 0; +#ifdef VERSECHAT + vnode->chat_flag = CHAT_NOTLOGGED; +#endif + + vnode->post_node_create = post_node_create; + vnode->post_node_destroy = post_node_destroy; + vnode->post_node_name_set = post_node_name_set; + + return vnode; +} + +/* + * callback function: tag was destroyed + */ +static void cb_tag_destroy( + void *user_data, + VNodeID node_id, + uint16 group_id, + uint16 tag_id) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VTagGroup *vtaggroup; + struct VTag *vtag; + + if(!session) return; + + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + if(!vnode) return; + + /* try to find tag group in list of tag groups */ + vtaggroup = BLI_dlist_find_link(&(vnode->taggroups), group_id); + + if(!vtaggroup) return; + + /* try to find verse tag in dynamic list of tags in tag group */ + vtag = (VTag*)BLI_dlist_find_link(&(vtaggroup->tags), tag_id); + + if(vtag) { + free_verse_tag_data(vtag); + BLI_dlist_free_item(&(vtaggroup->tags), vtag->id); + } +} + +/* + * callback function: new tag was created + */ +static void cb_tag_create( + void *user_data, + VNodeID node_id, + uint16 group_id, + uint16 tag_id, + const char *name, + VNTagType type, + const VNTag *tag) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VTagGroup *vtaggroup; + struct VTag *vtag; + + if(!session) return; + + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + if(!vnode) return; + + /* try to find tag group in list of tag groups */ + vtaggroup = BLI_dlist_find_link(&(vnode->taggroups), group_id); + + if(!vtaggroup) return; + + /* try to find verse tag in dynamic list of tags in tag group */ + vtag = (VTag*)BLI_dlist_find_link(&(vtaggroup->tags), tag_id); + + if(!vtag) { + /* we will try to find vtag in sending queue */ + vtag = find_tag_in_queue(vtaggroup, name); + + /* when we didn't create this tag, then we will have to create one */ + if(!vtag) vtag = create_verse_tag(vtaggroup, tag_id, name, type, tag); + else vtag->id = tag_id; + + /* add tag to the list of tags in tag group */ + BLI_dlist_add_item_index(&(vtaggroup->tags), vtag, tag_id); + + /* post change/create method */ + vtaggroup->post_tag_change(vtag); + } + else { + /* this tag exists, then we will propably change value of this tag */ + if((vtag->type != type) || (strcmp(vtag->name, name)!=0)) { + /* changes of type or name are not allowed and such + * stupid changes will be returned back */ + send_verse_tag(vtag); + } + else { + /* post change/create method */ + vtaggroup->post_tag_change(vtag); + } + } +} + +/* + * callback function: tag group was destroyed + */ +static void cb_tag_group_destroy( + void *user_data, + VNodeID node_id, + uint16 group_id) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VTagGroup *vtaggroup; + + if(!session) return; + + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + if(!vnode) return; + + vtaggroup = BLI_dlist_find_link(&(vnode->taggroups), group_id); + + if(vtaggroup) { + free_verse_taggroup_data(vtaggroup); + BLI_dlist_free_item(&(vnode->taggroups), vtaggroup->id); + } +} + +/* + * callback function: new tag group was created + */ +static void cb_tag_group_create( + void *user_data, + VNodeID node_id, + uint16 group_id, + const char *name) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VTagGroup *vtaggroup; + + if(!session) return; + + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + if(!vnode) return; + + /* name of taggroup has to begin with string "blender:" */ + if(strncmp("blender:", name, 8)) return; + + /* try to find tag group in list of tag groups */ + vtaggroup = BLI_dlist_find_link(&(vnode->taggroups), group_id); + + if(!vtaggroup) { + /* subscribe to tag group (when new tag will be created, then blender will + * receive command about it) */ + verse_send_tag_group_subscribe(vnode->id, group_id); + verse_callback_update(0); + + /* try to find taggroup in waiting queue */ + vtaggroup = find_taggroup_in_queue(vnode, name); + + /* if no taggroup exist, then new has to be created */ + if(!vtaggroup) vtaggroup = create_verse_taggroup(vnode, group_id, name); + else vtaggroup->id = group_id; + + /* add tag group to dynamic list with access array */ + BLI_dlist_add_item_index(&(vnode->taggroups), (void*)vtaggroup, (unsigned int)group_id); + + /* post create method */ + vtaggroup->post_taggroup_create(vtaggroup); + } + else { + /* this taggroup exist and somebody try to change its name */ + if(strcmp(vtaggroup->name, name)!=0) { + /* blender doesn't allow such stupid and dangerous things */ + send_verse_taggroup(vtaggroup); + } + } +} + +/* + * callback function: change name of node + */ +static void cb_node_name_set( + void *user_data, + VNodeID node_id, + const char *name) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + + if(!session) return; + + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + if(vnode && name) { + if(!vnode->name) { + vnode->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "VerseNode name"); + } + else if(strlen(name) > strlen(vnode->name)) { + MEM_freeN(vnode->name); + vnode->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "VerseNode name"); + } + strcpy(vnode->name, name); + + vnode->post_node_name_set(vnode); + } +} + +/* + * callback function for deleting node + */ +static void cb_node_destroy( + void *user_data, + VNodeID node_id) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + + if(!session) return; + + vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + + if(vnode) { + /* remove VerseNode from dynamic list */ + BLI_dlist_rem_item(&(session->nodes), (unsigned int)node_id); + /* do post destroy operations */ + vnode->post_node_destroy(vnode); + /* free verse data */ + free_verse_node_data(vnode); + /* free VerseNode */ + MEM_freeN(vnode); + }; +} + + +/* + * callback function for new created node + */ +static void cb_node_create( + void *user_data, + VNodeID node_id, + uint8 type, + VNodeID owner_id) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode = NULL; + + if(!session) return; + + /* subscribe to node */ + if((type==V_NT_OBJECT) || (type==V_NT_GEOMETRY) || (type==V_NT_BITMAP)) + verse_send_node_subscribe(node_id); + else + return; + + switch(type){ + case V_NT_OBJECT : + if(owner_id==VN_OWNER_MINE) { + struct VLink *vlink; + /* collect VerseNode from VerseNode queue */ + move_verse_node_to_dlist(session, node_id); + /* send next VerseNode waiting in queue */ + if(session->queue.first) send_verse_node(session->queue.first); + /* get received VerseNode from list of VerseNodes */ + vnode = BLI_dlist_find_link(&(session->nodes), node_id); + /* set up ID */ + vnode->id = node_id; + /* set up flags */ + vnode->flag |= NODE_RECEIVED; + /* find unsent link pointing at this VerseNode */ + vlink = find_unsent_child_vlink(session, vnode); + /* send VerseLink */ + if(vlink) send_verse_link(vlink); + /* send name of object node */ + verse_send_node_name_set(node_id, vnode->name); + /* subscribe to changes of object node transformations */ + verse_send_o_transform_subscribe(node_id, 0); + /* send object transformation matrix */ + send_verse_object_position(vnode); + send_verse_object_rotation(vnode); + send_verse_object_scale(vnode); + } + else { + /* create new VerseNode */ + vnode = create_verse_node(session, node_id, type, owner_id); + /* add VerseNode to list of nodes */ + BLI_dlist_add_item_index(&(session->nodes), (void*)vnode, (unsigned int)node_id); + /* set up flags */ + vnode->flag |= NODE_RECEIVED; + /* create object data */ + vnode->data = create_object_data(); + /* set up avatar's name */ + if(node_id == session->avatar) { + verse_send_node_name_set(node_id, U.verseuser); + } + else if(session->flag & VERSE_AUTOSUBSCRIBE) { + /* subscribe to changes of object node transformations */ + verse_send_o_transform_subscribe(node_id, 0); + } + } + break; + case V_NT_GEOMETRY : + if(owner_id==VN_OWNER_MINE){ + struct VLink *vlink; + struct VLayer *vlayer; + /* collect VerseNode from VerseNode queue */ + move_verse_node_to_dlist(session, node_id); + /* send next VerseNode waiting in queue */ + if(session->queue.first) send_verse_node(session->queue.first); + /* get received VerseNode from list of VerseNodes */ + vnode = BLI_dlist_find_link(&(session->nodes), node_id); + /* set up ID */ + vnode->id = node_id; + /* set up flags */ + vnode->flag |= NODE_RECEIVED; + /* find unsent link pointing at this VerseNode */ + vlink = find_unsent_parent_vlink(session, vnode); + /* send VerseLink */ + if(vlink) send_verse_link(vlink); + /* send name of geometry node */ + verse_send_node_name_set(node_id, vnode->name); + /* send all not sent layer to verse server */ + vlayer = (VLayer*)((VGeomData*)vnode->data)->queue.first; + if(vlayer) { + while(vlayer) { + send_verse_layer(vlayer); + vlayer = vlayer->next; + } + } + else { + /* send two verse layers to verse server */ +/* verse_send_g_layer_create(node_id, 0, "vertex", VN_G_LAYER_VERTEX_XYZ, 0, 0); + verse_send_g_layer_create(node_id, 1, "polygon", VN_G_LAYER_POLYGON_CORNER_UINT32, 0, 0);*/ + } + } + else { + /* create new VerseNode*/ + vnode = create_verse_node(session, node_id, type, owner_id); + /* add VerseNode to dlist of nodes */ + BLI_dlist_add_item_index(&(session->nodes), (void*)vnode, (unsigned int)node_id); + /* set up flags */ + vnode->flag |= NODE_RECEIVED; + /* create geometry data */ + vnode->data = (void*)create_geometry_data(); + } + break; + case V_NT_BITMAP : + if(owner_id==VN_OWNER_MINE) { + /* collect VerseNode from VerseNode queue */ + move_verse_node_to_dlist(session, node_id); + /* send next VerseNode waiting in queue */ + if(session->queue.first) send_verse_node(session->queue.first); + /* get received VerseNode from list of VerseNodes */ + vnode = BLI_dlist_find_link(&(session->nodes), node_id); + /* set up ID */ + vnode->id = node_id; + /* set up flags */ + vnode->flag |= NODE_RECEIVED; + /* send name of object node */ + verse_send_node_name_set(node_id, vnode->name); + /* send dimension of image to verse server */ + verse_send_b_dimensions_set(node_id, + ((VBitmapData*)vnode->data)->width, + ((VBitmapData*)vnode->data)->height, + ((VBitmapData*)vnode->data)->depth); + } + else { + /* create new VerseNode*/ + vnode = create_verse_node(session, node_id, type, owner_id); + /* add VerseNode to dlist of nodes */ + BLI_dlist_add_item_index(&(session->nodes), (void*)vnode, (unsigned int)node_id); + /* set up flags */ + vnode->flag |= NODE_RECEIVED; + /* create bitmap data */ + vnode->data = (void*)create_bitmap_data(); + } + break; + default: + vnode = NULL; + break; + } + + if(vnode) vnode->post_node_create(vnode); +} + +/* + * set up all callbacks for verse nodes + */ +void set_node_callbacks(void) +{ + /* new node created */ + verse_callback_set(verse_send_node_create, cb_node_create, NULL); + /* node was deleted */ + verse_callback_set(verse_send_node_destroy, cb_node_destroy, NULL); + /* name of node was set */ + verse_callback_set(verse_send_node_name_set, cb_node_name_set, NULL); + + /* new tag group was created */ + verse_callback_set(verse_send_tag_group_create, cb_tag_group_create, NULL); + /* tag group was destroy */ + verse_callback_set(verse_send_tag_group_destroy, cb_tag_group_destroy, NULL); + + /* new tag was created */ + verse_callback_set(verse_send_tag_create, cb_tag_create, NULL); + /* tag was destroy */ + verse_callback_set(verse_send_tag_destroy, cb_tag_destroy, NULL); +} + +#endif diff --git a/source/blender/blenkernel/intern/verse_object_node.c b/source/blender/blenkernel/intern/verse_object_node.c new file mode 100644 index 00000000000..d8be38cd00f --- /dev/null +++ b/source/blender/blenkernel/intern/verse_object_node.c @@ -0,0 +1,620 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributor(s): Jiri Hnidek. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef WITH_VERSE + +#include +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" +#include "DNA_userdef_types.h" + +#include "BLI_dynamiclist.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "BIF_verse.h" + +#include "BKE_verse.h" +#include "BKE_utildefines.h" + +#include "verse.h" + +/* function prototypes of static functions */ + +/* callback functions */ +static void cb_o_transform_pos_real32(void *user_data, VNodeID node_id, uint32 time_s, uint32 time_f, const real32 *pos, const real32 *speed, const real32 *accelerate, const real32 *drag_normal, real32 drag); +static void cb_o_transform_rot_real32(void *user_data, VNodeID node_id, uint32 time_s, uint32 time_f, const VNQuat32 *temp, const VNQuat32 *speed, const VNQuat32 *accelerate, const VNQuat32 *drag_normal, real32 drag); +static void cb_o_transform_scale_real32(void *user_data, VNodeID node_id, real32 scale_x, real32 scale_y, real32 scale_z); +static void cb_o_link_set(void *user_data, VNodeID node_id, uint16 link_id, VNodeID link, const char *label, uint32 target_id); +static void cb_o_link_destroy(void *user_data, VNodeID node_id,uint16 link_id); + +/* other functions */ +static void set_target_node_link_pointer(struct VNode *vnode, struct VLink *vlink); +static void free_verse_link_data(struct VLink *vlink); + +/* + * find noy sent VerseLink in queue + */ +VLink *find_unsent_child_vlink(VerseSession *session, VNode *vnode) +{ + struct VLink *vlink; + + if(vnode->type!=V_NT_OBJECT) return NULL; + + vlink = ((VObjectData*)vnode->data)->queue.first; + while(vlink) { + if(vlink->target->id != -1) { + printf("\t vlink found, vnode target id %d\n", vlink->target->id); + return vlink; + } + vlink = vlink->next; + } + return NULL; +} + +/* + * find unsent VerseLink "pointing at this VerseNode" + */ +VLink *find_unsent_parent_vlink(VerseSession *session, VNode *vnode) +{ + struct VNode *tmp; + struct VLink *vlink; + + tmp = session->nodes.lb.first; + + while(tmp) { + if(tmp->type==V_NT_OBJECT) { + vlink = ((VObjectData*)tmp->data)->queue.first; + while(vlink) { + if(vlink->target == vnode) + return vlink; + vlink = vlink->next; + } + } + tmp = tmp->next; + } + return NULL; +} + +/* + * send object position to verse server + */ +void send_verse_object_position(VNode *vnode) +{ + float tmp; + + ((VObjectData*)vnode->data)->flag &= ~POS_SEND_READY; + + /* we have to do rotation around x axis (+pi/2) to be + compatible with other verse applications */ + tmp = -((VObjectData*)vnode->data)->pos[1]; + ((VObjectData*)vnode->data)->pos[1] = ((VObjectData*)vnode->data)->pos[2]; + ((VObjectData*)vnode->data)->pos[2] = tmp; + + verse_send_o_transform_pos_real32( + vnode->id, /* node id */ + 0, /* time_s ... no interpolation */ + 0, /* time_f ... no interpolation */ + ((VObjectData*)vnode->data)->pos, + NULL, /* speed ... no interpolation */ + NULL, /* accelerate ... no interpolation */ + NULL, /* drag normal ... no interpolation */ + 0.0); /* drag ... no interpolation */ +} + +/* + * send object rotation to verse server + */ +void send_verse_object_rotation(VNode *vnode) +{ + VNQuat32 quat; + float q[4] = {cos(-M_PI/4), -sin(-M_PI/4), 0, 0}, v[4], tmp[4]; + + /* inverse transformation to transformation in function cb_o_transform_rot_real32 */ + QuatMul(v, ((VObjectData*)vnode->data)->quat, q); + q[1]= sin(-M_PI/4); + QuatMul(tmp, q, v); + + quat.x = tmp[1]; + quat.y = tmp[2]; + quat.z = tmp[3]; + quat.w = tmp[0]; + + ((VObjectData*)vnode->data)->flag &= ~ROT_SEND_READY; + + verse_send_o_transform_rot_real32( + vnode->id, /* node id */ + 0, /* time_s ... no interpolation */ + 0, /* time_f ... no interpolation */ + &quat, + NULL, /* speed ... no interpolation */ + NULL, /* accelerate ... no interpolation */ + NULL, /* drag normal ... no interpolation */ + 0.0); /* drag ... no interpolation */ +} + +/* + * send object rotation to verse server + */ +void send_verse_object_scale(VNode *vnode) +{ + float tmp; + + ((VObjectData*)vnode->data)->flag &= ~SCALE_SEND_READY; + + /* we have to do rotation around x axis (+pi/2) to be + compatible with other verse applications */ + tmp = ((VObjectData*)vnode->data)->scale[1]; + ((VObjectData*)vnode->data)->scale[1] = ((VObjectData*)vnode->data)->scale[2]; + ((VObjectData*)vnode->data)->scale[2] = tmp; + + verse_send_o_transform_scale_real32( + vnode->id, + ((VObjectData*)vnode->data)->scale[0], + ((VObjectData*)vnode->data)->scale[1], + ((VObjectData*)vnode->data)->scale[2]); +} + +/* + * send VerseLink to verse server + */ +void send_verse_link(VLink *vlink) +{ + verse_session_set(vlink->session->vsession); + + verse_send_o_link_set( + vlink->source->id, + vlink->id, + vlink->target->id, + vlink->label, + vlink->target_id); +} + +/* + * set up pointer at VerseLink of target node (geometry node, material node, etc.) + */ +static void set_target_node_link_pointer(VNode *vnode, VLink *vlink) +{ + switch (vnode->type) { + case V_NT_GEOMETRY: + ((VGeomData*)vnode->data)->vlink = vlink; + break; + default: + break; + } +} + +/* + * free VerseLink and it's label + */ +static void free_verse_link_data(VLink *vlink) +{ + MEM_freeN(vlink->label); +} + +/* + * create new VerseLink + */ +VLink *create_verse_link( + VerseSession *session, + VNode *source, + VNode *target, + uint16 link_id, + uint32 target_id, + const char *label) +{ + struct VLink *vlink; + + vlink = (VLink*)MEM_mallocN(sizeof(VLink), "VerseLink"); + vlink->session = session; + vlink->source = source; + vlink->target = target; + vlink->id = link_id; + vlink->target_id = target_id; + + set_target_node_link_pointer(target, vlink); + + vlink->label = (char*)MEM_mallocN(sizeof(char)*(strlen(label)+1), "VerseLink label"); + vlink->label[0] = '\0'; + strcat(vlink->label, label); + + vlink->flag = 0; + + vlink->post_link_set = post_link_set; + vlink->post_link_destroy = post_link_destroy; + + return vlink; +} + +/* + * free ObjectData (links, links in queue and lables of links) + */ +void free_object_data(VNode *vnode) +{ + struct VerseSession *session = vnode->session; + struct VObjectData *obj = (VObjectData*)vnode->data; + struct VLink *vlink; + struct VMethodGroup *vmg; + + if(!obj) return; + + /* free all labels of links in dlist */ + vlink = obj->links.lb.first; + while(vlink){ + free_verse_link_data(vlink); + vlink = vlink->next; + } + + /* free all labels of links waiting in queue */ + vlink = obj->queue.first; + while(vlink){ + free_verse_link_data(vlink); + vlink = vlink->next; + } + /* free dynamic list and sendig queue of links */ + BLI_dlist_destroy(&(obj->links)); + BLI_freelistN(&(obj->queue)); + + /* free method groups and their methods */ + for(vmg = vnode->methodgroups.first; vmg; vmg= vmg->next) { + free_verse_methodgroup(vmg); + } + BLI_freelistN(&(vnode->methodgroups)); + + /* free constraint between VerseNode and Object */ + obj->post_object_free_constraint(vnode); + + /* unsubscribe from receiving changes of transformation matrix */ + if(session->flag & VERSE_CONNECTED) + verse_send_o_transform_unsubscribe(vnode->id, 0); +} + +/* + * create new object data + */ +VObjectData *create_object_data(void) +{ + VObjectData *obj; + + obj = (VObjectData*)MEM_mallocN(sizeof(VObjectData), "VerseObjectData"); + obj->object = NULL; + BLI_dlist_init(&(obj->links)); + obj->queue.first = obj->queue.last = NULL; + obj->flag = 0; + + /* transformation matrix */ + obj->pos[0] = obj->pos[1] = obj->pos[2] = 0.0; + obj->quat[0] = obj->quat[1] = obj->quat[2] = 0.0; obj->quat[3] = 1; + obj->scale[0] = obj->scale[1] = obj->scale[2] = 1.0; + + /* transformation flags */ + obj->flag |= POS_SEND_READY; + obj->flag |= ROT_SEND_READY; + obj->flag |= SCALE_SEND_READY; + + /* set up pointers at post callback functions */ +/* obj->post_transform = post_transform;*/ + obj->post_transform_pos = post_transform_pos; + obj->post_transform_rot = post_transform_rot; + obj->post_transform_scale = post_transform_scale; + obj->post_object_free_constraint = post_object_free_constraint; + + return obj; +} + +/* + * callback function: + */ +static void cb_o_transform_pos_real32( + void *user_data, + VNodeID node_id, + uint32 time_s, + uint32 time_f, + const real32 *pos, + const real32 *speed, + const real32 *accelerate, + const real32 *drag_normal, + real32 drag) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + float vec[3], dt, tmp; + + if(!session) return; + + vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + + ((VObjectData*)vnode->data)->flag |= POS_SEND_READY; + + /* verse server sends automaticaly some stupid default values ... + * we have to ignore these values, when we created this object node */ + if( (vnode->owner_id==VN_OWNER_MINE) && !(((VObjectData*)vnode->data)->flag & POS_RECEIVE_READY) ) { + ((VObjectData*)vnode->data)->flag |= POS_RECEIVE_READY; + return; + } + + dt = time_s + time_f/(0xffff); + + if(pos) { + vec[0] = pos[0]; + vec[1] = pos[1]; + vec[2] = pos[2]; + } + else { + vec[0] = 0.0f; + vec[1] = 0.0f; + vec[2] = 0.0f; + } + + if(speed) { + vec[0] += speed[0]*dt; + vec[1] += speed[1]*dt; + vec[2] += speed[2]*dt; + } + + if(accelerate) { + vec[0] += accelerate[0]*dt*dt/2; + vec[1] += accelerate[1]*dt*dt/2; + vec[2] += accelerate[2]*dt*dt/2; + } + + /* we have to do rotation around x axis (+pi/2) to be + compatible with other verse applications */ + tmp = vec[1]; + vec[1] = -vec[2]; + vec[2] = tmp; + + if( (((VObjectData*)vnode->data)->pos[0] != vec[0]) || + (((VObjectData*)vnode->data)->pos[1] != vec[1]) || + (((VObjectData*)vnode->data)->pos[2] != vec[2])) + { + ((VObjectData*)vnode->data)->pos[0] = vec[0]; + ((VObjectData*)vnode->data)->pos[1] = vec[1]; + ((VObjectData*)vnode->data)->pos[2] = vec[2]; + + ((VObjectData*)vnode->data)->post_transform_pos(vnode); + } +} + +/* + * callback function: + */ +static void cb_o_transform_rot_real32( + void *user_data, + VNodeID node_id, + uint32 time_s, + uint32 time_f, + const VNQuat32 *quat, + const VNQuat32 *speed, + const VNQuat32 *accelerate, + const VNQuat32 *drag_normal, + real32 drag) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + float temp[4]={0, 0, 0, 0}, v[4], dt; /* temporary quaternions */ + float q[4]={cos(M_PI/4), -sin(M_PI/4), 0, 0}; /* conjugate quaternion (represents rotation + around x-axis +90 degrees) */ + + if(!session) return; + + vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + + ((VObjectData*)vnode->data)->flag |= ROT_SEND_READY; + + /* verse server sends automaticaly some stupid default values ... + * we have to ignore these values, when we created this object node */ + if( (vnode->owner_id==VN_OWNER_MINE) && !(((VObjectData*)vnode->data)->flag & ROT_RECEIVE_READY) ) { + ((VObjectData*)vnode->data)->flag |= ROT_RECEIVE_READY; + return; + } + + dt = time_s + time_f/(0xffff); + + if(quat) { + temp[1] = quat->x; + temp[2] = quat->y; + temp[3] = quat->z; + temp[0] = quat->w; + } + + if(speed) { + temp[1] += speed->x*dt; + temp[2] += speed->y*dt; + temp[3] += speed->z*dt; + temp[0] += speed->w*dt; + } + + if(accelerate) { + temp[1] += accelerate->x*dt*dt/2; + temp[2] += accelerate->y*dt*dt/2; + temp[3] += accelerate->z*dt*dt/2; + temp[0] += accelerate->w*dt*dt/2; + } + + /* following matematical operation transform rotation: + * + * v' = quaternion * v * conjugate_quaternion + * + *, where v is original representation of rotation */ + + QuatMul(v, temp, q); + q[1]= sin(M_PI/4); /* normal quaternion */ + QuatMul(temp, q, v); + + if( (((VObjectData*)vnode->data)->quat[0] != temp[0]) || + (((VObjectData*)vnode->data)->quat[1] != temp[1]) || + (((VObjectData*)vnode->data)->quat[2] != temp[2]) || + (((VObjectData*)vnode->data)->quat[3] != temp[3])) + { + QUATCOPY(((VObjectData*)vnode->data)->quat, temp); + + ((VObjectData*)vnode->data)->post_transform_rot(vnode); + } +} + +/* + * callback function: + */ +static void cb_o_transform_scale_real32( + void *user_data, + VNodeID node_id, + real32 scale_x, + real32 scale_y, + real32 scale_z) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + real32 tmp; + + if(!session) return; + + vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + + ((VObjectData*)vnode->data)->flag |= SCALE_SEND_READY; + + /* verse server sends automaticaly some stupid default values ... + * we have to ignore these values, when we created this object node */ + if( (vnode->owner_id==VN_OWNER_MINE) && !(((VObjectData*)vnode->data)->flag & SCALE_RECEIVE_READY) ) { + ((VObjectData*)vnode->data)->flag |= SCALE_RECEIVE_READY; + return; + } + + /* flip axis (verse spec) */ + tmp = scale_y; + scale_y = scale_z; + scale_z = tmp; + + /* z and y axis are flipped here too */ + if( (((VObjectData*)vnode->data)->scale[0] != scale_x) || + (((VObjectData*)vnode->data)->scale[1] != scale_y) || + (((VObjectData*)vnode->data)->scale[2] != scale_z)) + { + ((VObjectData*)vnode->data)->scale[0] = scale_x; + ((VObjectData*)vnode->data)->scale[1] = scale_y; + ((VObjectData*)vnode->data)->scale[2] = scale_z; + + ((VObjectData*)vnode->data)->post_transform_scale(vnode); + } +} + +/* + * callback function: link between object node and some other node was created + */ +static void cb_o_link_set( + void *user_data, + VNodeID node_id, + uint16 link_id, + VNodeID link, + const char *label, + uint32 target_id) +{ + struct VLink *vlink; + struct VNode *source; + struct VNode *target; + + struct VerseSession *session = (VerseSession*)current_verse_session(); + + if(!session) return; + + source = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + target = BLI_dlist_find_link(&(session->nodes), (unsigned int)link); + + if(!(source && target)) return; + + vlink = ((VObjectData*)source->data)->queue.first; + + if(vlink && (vlink->source==source) && (vlink->target==target)) { + /* remove VerseLink from sending queue */ + BLI_remlink(&(((VObjectData*)source->data)->queue), vlink); + /* add VerseLink to dynamic list of VerseLinks */ + BLI_dlist_add_item_index(&(((VObjectData*)source->data)->links), vlink, (unsigned int)link_id); + /* send next link from sending queue */ + if(((VObjectData*)source->data)->queue.first) + send_verse_link(((VObjectData*)source->data)->queue.first); + /* set up VerseLink variables */ + vlink->flag = 0; + vlink->id = link_id; + vlink->target_id = target_id; + } + else { + /* create new VerseLink */ + vlink = create_verse_link(session, source, target, link_id, target_id, label); + /* add VerseLink to dynamic list of VerseLinks */ + BLI_dlist_add_item_index(&(((VObjectData*)source->data)->links), vlink, (unsigned int)link_id); + } + + target->counter++; + + vlink->post_link_set(vlink); +} + +/* + * callback function: destroy link between two VerseNodes + */ +static void cb_o_link_destroy( + void *user_data, + VNodeID node_id, + uint16 link_id) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VLink *vlink; + + if(!session) return; + + vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + + vlink = BLI_dlist_find_link(&(((VObjectData*)vnode->data)->links), link_id); + + if(vlink) { + vlink->target->counter--; + free_verse_link_data(vlink); + BLI_dlist_free_item(&(((VObjectData*)vnode->data)->links), link_id); + } + + vlink->post_link_destroy(vlink); +} + +void set_object_callbacks(void) +{ + /* position of object was changed */ + verse_callback_set(verse_send_o_transform_pos_real32, cb_o_transform_pos_real32, NULL); + /* rotation of object was changed */ + verse_callback_set(verse_send_o_transform_rot_real32, cb_o_transform_rot_real32, NULL); + /* size of object was changed */ + verse_callback_set(verse_send_o_transform_scale_real32, cb_o_transform_scale_real32, NULL); + /* new link between nodes was created */ + verse_callback_set(verse_send_o_link_set, cb_o_link_set, NULL); + /* link between nodes was destroyed */ + verse_callback_set(verse_send_o_link_destroy, cb_o_link_destroy, NULL); +} + +#endif diff --git a/source/blender/blenkernel/intern/verse_session.c b/source/blender/blenkernel/intern/verse_session.c new file mode 100644 index 00000000000..1226fffd929 --- /dev/null +++ b/source/blender/blenkernel/intern/verse_session.c @@ -0,0 +1,480 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributor(s): Jiri Hnidek. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef WITH_VERSE + +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" /* temp */ +#include "DNA_listBase.h" +#include "DNA_screen_types.h" +#include "DNA_userdef_types.h" + +#include "BLI_dynamiclist.h" +#include "BLI_blenlib.h" + +#include "BIF_screen.h" +#include "BIF_verse.h" + +#include "BKE_global.h" +#include "BKE_verse.h" + +struct ListBase session_list={NULL, NULL}; +struct ListBase server_list={NULL, NULL}; + +static int cb_ping_registered = 0; + +/* list of static function prototypes */ +static void cb_connect_terminate(const char *address, const char *bye); +static void cb_connect_accept(void *user_data, uint32 avatar, void *address, void *connection, const uint8 *host_id); +static void set_all_callbacks(void); +static void free_verse_session_data(struct VerseSession *session); +static void add_verse_server(VMSServer *server); +static void check_connection_state(struct VerseServer *server); + +static void check_connection_state(struct VerseServer *server) +{ + struct VerseSession *session; + session = session_list.first; + while(session) { + if(strcmp(server->ip,session->address)==0) { + server->flag = session->flag; + return; + } + session = session->next; + } +} +/* + * add verse server to server_list. Prevents duplicate + * entries + */ +static void add_verse_server(VMSServer *server) +{ + struct VerseServer *iter, *niter; + VerseServer *newserver; + const char *name = verse_ms_field_value(server, "DE"); + iter = server_list.first; + + while(iter) { + niter = iter->next; + if(strcmp(iter->ip, server->ip)==0) { + return; + } + iter = niter; + } + + newserver = (VerseServer *)MEM_mallocN(sizeof(VerseServer), "VerseServer"); + newserver->ip = (char *)MEM_mallocN(sizeof(char)*(strlen(server->ip)+1), "VerseServer ip"); + strcpy(newserver->ip, server->ip); + + if(name) { + newserver->name = (char *)MEM_mallocN(sizeof(char)*(strlen(name)+strlen(newserver->ip)+4), "VerseServer name"); + strcpy(newserver->name, name); + strcat(newserver->name, " ("); + strcat(newserver->name, newserver->ip); + strcat(newserver->name, ")"); + } + + newserver->flag = 0; + check_connection_state(newserver); + + printf("Adding new verse server: %s at %s\n", newserver->name, newserver->ip); + + BLI_addtail(&server_list, newserver); + post_server_add(); +} + +/* + * callback function for ping + */ +static void cb_ping(void *user, const char *address, const char *message) +{ + VMSServer **servers = verse_ms_list_parse(message); + if(servers != NULL) + { + int i; + + for(i = 0; servers[i] != NULL; i++) + add_verse_server(servers[i]); + + free(servers); + } +} + +/* + * callback function for connection terminated + */ +static void cb_connect_terminate(const char *address, const char *bye) +{ + VerseSession *session = (VerseSession*)current_verse_session(); + + if(!session) return; + + /* remove session from list of session */ + BLI_remlink(&session_list, session); + /* do post connect operations */ + session->post_connect_terminated(session); + /* free session data */ + free_verse_session_data(session); + /* free session */ + MEM_freeN(session); +} + +/* + * callback function for accepted connection to verse server + */ +static void cb_connect_accept( + void *user_data, + uint32 avatar, + void *address, + void *connection, + const uint8 *host_id) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VerseServer *server = server_list.first; + uint32 i, mask=0; + + if(!session) return; + + session->flag |= VERSE_CONNECTED; + session->flag &= ~VERSE_CONNECTING; + + while(server) { + if(strcmp(session->address, server->ip)==0) { + server->flag |= VERSE_CONNECTED; + server->flag &= ~VERSE_CONNECTING; + server->session = session; + break; + } + server = server->next; + } + + printf("\tBlender is connected to verse server: %s\n", (char*)address); + printf("\tVerseSession->counter: %d\n", session->counter); + + session->avatar = avatar; + + session->post_connect_accept(session); + + for(i = 0; i < V_NT_NUM_TYPES; i++) + mask = mask | (1 << i); + verse_send_node_index_subscribe(mask); + verse_send_node_subscribe(session->avatar); /* subscribe to avatar node, as well */ + + /* create our own method group and method */ + /*verse_send_o_method_group_create(session->avatar, ~0, "tawk-client");*/ +} + +/* + * set up all callbacks for sessions + */ +void set_verse_session_callbacks(void) +{ + /* connection */ + verse_callback_set(verse_send_connect_accept, cb_connect_accept, NULL); + /* connection was terminated */ + verse_callback_set(verse_send_connect_terminate, cb_connect_terminate, NULL); + +} + +/* + * set all callbacks used in Blender + */ +static void set_all_callbacks(void) +{ + /* set up all callbacks for sessions */ + set_verse_session_callbacks(); + + /* set up callbacks for nodes */ + set_node_callbacks(); + + /* set up all callbacks for object nodes */ + set_object_callbacks(); + + /* set up all callbacks for geometry nodes */ + set_geometry_callbacks(); + + /* set up all callbacks for bitmap nodes */ + set_bitmap_callbacks(); + + /* set up all callbacks for method groups and methods */ + set_method_callbacks(); +} + +/* + * this function sends and receive all packets for all sessions + */ +void b_verse_update(void) +{ + VerseSession *session, *next_session; + + session = session_list.first; + while(session){ + next_session = session->next; + verse_session_set(session->vsession); + if((session->flag & VERSE_CONNECTED) || (session->flag & VERSE_CONNECTING)) { + verse_callback_update(10); + session->post_connect_update(session); + } + session = next_session; + } + if(cb_ping_registered>0) { + verse_callback_update(10); + } +} + +/* + * returns VerseSession coresponding to vsession pointer + */ +VerseSession *versesession_from_vsession(VSession *vsession) +{ + struct VerseSession *session; + + session = session_list.first; + + while(session) { + if(session->vsession==vsession) return session; + session = session->next; + } + + return session; +} + +/* + * returns pointer at current VerseSession + */ +VerseSession *current_verse_session(void) +{ + struct VerseSession *session; + VSession vsession = verse_session_get(); + + session = session_list.first; + + while(session){ + if(session->vsession == vsession) + return session; + session = session->next; + } + + printf("error: non-existing SESSION occured!\n"); + return NULL; +} + +/* + * free VerseSession + */ +static void free_verse_session_data(VerseSession *session) +{ + struct VNode *vnode; + + /* free data of all nodes */ + vnode = session->nodes.lb.first; + while(vnode){ + free_verse_node_data(vnode); + vnode = vnode->next; + } + + /* free data of nodes waiting in queue */ + vnode = session->queue.first; + while(vnode){ + free_verse_node_data(vnode); + vnode = vnode->next; + } + + /* free all VerseNodes */ + BLI_dlist_destroy(&(session->nodes)); + /* free all VerseNodes waiting in queque */ + BLI_freelistN(&(session->queue)); + + /* free name of verse host for this session */ + MEM_freeN(session->address); +} + +/* + * free VerseSession + */ +void free_verse_session(VerseSession *session) +{ + /* remove session from session list*/ + BLI_remlink(&session_list, session); + /* do post terminated operations */ + session->post_connect_terminated(session); + /* free session data (nodes, layers) */ + free_verse_session_data(session); + /* free session */ + MEM_freeN(session); +} + +/* + * create new verse session and return coresponding data structure + */ +VerseSession *create_verse_session( + const char *name, + const char *pass, + const char *address, + uint8 *expected_key) +{ + struct VerseSession *session; + VSession *vsession; + + vsession = verse_send_connect(name, pass, address, expected_key); + + if(!vsession) return NULL; + + session = (VerseSession*)MEM_mallocN(sizeof(VerseSession), "VerseSession"); + + session->flag = VERSE_CONNECTING; + + session->vsession = vsession; + session->avatar = -1; + + session->address = (char*)MEM_mallocN(sizeof(char)*(strlen(address)+1),"session adress name"); + strcpy(session->address, address); + + session->connection = NULL; + session->host_id = NULL; + session->counter = 0; + + /* initialize dynamic list of nodes and node queue */ + BLI_dlist_init(&(session->nodes)); + session->queue.first = session->queue.last = NULL; + + /* set up all client dependent functions */ + session->post_connect_accept = post_connect_accept; + session->post_connect_terminated = post_connect_terminated; + session->post_connect_update = post_connect_update; + + post_server_add(); + + return session; +} + +/* + * end verse session and free all session data + */ +void end_verse_session(VerseSession *session) +{ + /* send terminate command to verse server */ + verse_send_connect_terminate(session->address, "blender: bye bye"); + /* update callbacks */ + verse_callback_update(1000); + /* send destroy session command to verse server */ + verse_session_destroy(session->vsession); + /* set up flag of verse session */ + session->flag &= ~VERSE_CONNECTED; + /* do post connect operations */ + session->post_connect_terminated(session); + /* free structure of verse session */ + free_verse_session(session); +} + +void free_all_servers(void) +{ + VerseServer *server, *nextserver; + + server = server_list.first; + + while(server) { + nextserver = server->next; + BLI_remlink(&server_list, server); + MEM_freeN(server->name); + MEM_freeN(server->ip); + MEM_freeN(server); + server = nextserver; + } + + BLI_freelistN(&server_list); +} + +/* + * end connection to all verse hosts (servers) ... free all VerseSessions + * free all VerseServers + */ +void end_all_verse_sessions(void) +{ + VerseSession *session,*nextsession; + + session = session_list.first; + + while(session) { + nextsession= session->next; + end_verse_session(session); + /* end next session */ + session = nextsession; + } + + BLI_freelistN(&session_list); + + free_all_servers(); +} + +/* + * do a get from ms + */ +void b_verse_ms_get(void) +{ + if(cb_ping_registered==0) { + /* handle ping messages (for master server) */ + verse_callback_set(verse_send_ping, cb_ping, NULL); + add_screenhandler(G.curscreen, SCREEN_HANDLER_VERSE, 1); + cb_ping_registered++; + } + free_all_servers(); + + verse_ms_get_send(U.versemaster, VERSE_MS_FIELD_DESCRIPTION, NULL); + verse_callback_update(10); +} + +/* + * connect to verse host, set up all callbacks, create session + */ +void b_verse_connect(char *address) +{ + VerseSession *session = NULL; + + /* if no session was created before, then set up all callbacks */ + if((session_list.first==NULL) && (session_list.last==NULL)) + set_all_callbacks(); + + /* create new session */ + if(address) + session = create_verse_session("Blender", "pass", address, NULL); + + if(session) { + /* add new session to the list of sessions */ + BLI_addtail(&session_list, session); + + /* add verse handler if this is first session */ + if(session_list.first == session_list.last) + add_screenhandler(G.curscreen, SCREEN_HANDLER_VERSE, 1); + + } +} + +#endif diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c new file mode 100644 index 00000000000..625ca57dbf3 --- /dev/null +++ b/source/blender/blenkernel/intern/world.c @@ -0,0 +1,187 @@ + +/* world.c + * + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include +#include "MEM_guardedalloc.h" + +#include "DNA_world_types.h" +#include "DNA_texture_types.h" +#include "DNA_scriptlink_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_camera_types.h" + + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "BKE_bad_level_calls.h" +#include "BKE_utildefines.h" + +#include "BKE_library.h" +#include "BKE_world.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_icons.h" + +#include "BPY_extern.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +void free_world(World *wrld) +{ + MTex *mtex; + int a; + + BPY_free_scriptlink(&wrld->scriptlink); + + for(a=0; amtex[a]; + if(mtex && mtex->tex) mtex->tex->id.us--; + if(mtex) MEM_freeN(mtex); + } + BKE_previewimg_free(&wrld->preview); + + wrld->ipo= 0; + BKE_icon_delete((struct ID*)wrld); + wrld->id.icon_id = 0; +} + + +World *add_world(char *name) +{ + World *wrld; + + wrld= alloc_libblock(&G.main->world, ID_WO, name); + + wrld->horb= 0.6f; + wrld->skytype= WO_SKYBLEND; + wrld->stardist= 15.0f; + wrld->starsize= 2.0f; + wrld->gravity= 9.8f; + + wrld->exp= 0.0f; + wrld->exposure=wrld->range= 1.0f; + + wrld->aodist= 5.0; + wrld->aosamp= 5; + wrld->aoenergy= 1.0; + wrld->aobias= 0.05; + wrld->ao_samp_method = WO_AOSAMP_HAMMERSLEY; + + + wrld->physicsEngine= WOPHY_BULLET;//WOPHY_SUMO; Bullet by default + wrld->preview = NULL; + + return wrld; +} + +World *copy_world(World *wrld) +{ + World *wrldn; + int a; + + wrldn= copy_libblock(wrld); + + for(a=0; amtex[a]) { + wrldn->mtex[a]= MEM_mallocN(sizeof(MTex), "copymaterial"); + memcpy(wrldn->mtex[a], wrld->mtex[a], sizeof(MTex)); + id_us_plus((ID *)wrldn->mtex[a]->tex); + } + } + + if (wrld->preview) wrldn->preview = BKE_previewimg_copy(wrld->preview); + + BPY_copy_scriptlink(&wrld->scriptlink); + + id_us_plus((ID *)wrldn->ipo); + + return wrldn; +} + +void make_local_world(World *wrld) +{ + Scene *sce; + World *wrldn; + int local=0, lib=0; + + /* - only lib users: do nothing + * - only local users: set flag + * - mixed: make copy + */ + + if(wrld->id.lib==0) return; + if(wrld->id.us==1) { + wrld->id.lib= 0; + wrld->id.flag= LIB_LOCAL; + new_id(0, (ID *)wrld, 0); + return; + } + + sce= G.main->scene.first; + while(sce) { + if(sce->world==wrld) { + if(sce->id.lib) lib= 1; + else local= 1; + } + sce= sce->id.next; + } + + if(local && lib==0) { + wrld->id.lib= 0; + wrld->id.flag= LIB_LOCAL; + new_id(0, (ID *)wrld, 0); + } + else if(local && lib) { + wrldn= copy_world(wrld); + wrldn->id.us= 0; + + sce= G.main->scene.first; + while(sce) { + if(sce->world==wrld) { + if(sce->id.lib==0) { + sce->world= wrldn; + wrldn->id.us++; + wrld->id.us--; + } + } + sce= sce->id.next; + } + } +} diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c new file mode 100644 index 00000000000..bd6859973b1 --- /dev/null +++ b/source/blender/blenkernel/intern/writeavi.c @@ -0,0 +1,223 @@ +/** + * Functions for writing avi-format files. + * Added interface for generic movie support (ton) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Robert Wenzlaff + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + */ + +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_scene_types.h" + +#include "BLI_blenlib.h" + +#include "BKE_global.h" +#include "BKE_writeavi.h" +#include "AVI_avi.h" + + +/* ********************** general blender movie support ***************************** */ + +#ifdef WITH_QUICKTIME +#include "quicktime_export.h" +#endif + +#if defined(_WIN32) && !defined(FREE_WINDOWS) +#include "BIF_writeavicodec.h" +#endif + +#ifdef WITH_FFMPEG +#include "BKE_writeffmpeg.h" +#endif + +#include "BKE_writeframeserver.h" + +bMovieHandle *BKE_get_movie_handle(int imtype) +{ + static bMovieHandle mh; + + /* set the default handle, as builtin */ + mh.start_movie= start_avi; + mh.append_movie= append_avi; + mh.end_movie= end_avi; + mh.get_next_frame = 0; + + /* do the platform specific handles */ +#ifdef __sgi + if (imtype == R_MOVIE) { + + } +#endif +#if defined(_WIN32) && !defined(FREE_WINDOWS) + if (imtype == R_AVICODEC) { + mh.start_movie= start_avi_codec; + mh.append_movie= append_avi_codec; + mh.end_movie= end_avi_codec; + } +#endif +#ifdef WITH_QUICKTIME + if (imtype == R_QUICKTIME) { + mh.start_movie= start_qt; + mh.append_movie= append_qt; + mh.end_movie= end_qt; + } +#endif +#ifdef WITH_FFMPEG + if (imtype == R_FFMPEG) { + mh.start_movie = start_ffmpeg; + mh.append_movie = append_ffmpeg; + mh.end_movie = end_ffmpeg; + } +#endif + if (imtype == R_FRAMESERVER) { + mh.start_movie = start_frameserver; + mh.append_movie = append_frameserver; + mh.end_movie = end_frameserver; + mh.get_next_frame = frameserver_loop; + } + + return &mh; +} + +/* ****************************************************************** */ + + +static AviMovie *avi=NULL; +static int sframe; + +void makeavistring (RenderData *rd, char *string) +{ + char txt[64]; + + if (string==0) return; + + strcpy(string, rd->pic); + BLI_convertstringcode(string, G.sce, rd->cfra); + + BLI_make_existing_file(string); + + if (BLI_strcasecmp(string + strlen(string) - 4, ".avi")) { + sprintf(txt, "%04d_%04d.avi", (rd->sfra) , (rd->efra) ); + strcat(string, txt); + } +} + +void start_avi(RenderData *rd, int rectx, int recty) +{ + int x, y; + char name[256]; + AviFormat format; + int quality; + double framerate; + + makeavistring(rd, name); + + sframe = (rd->sfra); + x = rectx; + y = recty; + + quality= rd->quality; + framerate= (double) rd->frs_sec / (double) rd->frs_sec_base; + + avi = MEM_mallocN (sizeof(AviMovie), "avimovie"); + + /* RPW 11-21-2002 + if (rd->imtype != AVI_FORMAT_MJPEG) format = AVI_FORMAT_AVI_RGB; + */ + if (rd->imtype != R_AVIJPEG ) format = AVI_FORMAT_AVI_RGB; + else format = AVI_FORMAT_MJPEG; + + if (AVI_open_compress (name, avi, 1, format) != AVI_ERROR_NONE) { + printf("cannot open or start AVI movie file"); + MEM_freeN (avi); + avi = NULL; + return; + } + + AVI_set_compress_option (avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_WIDTH, &x); + AVI_set_compress_option (avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_HEIGHT, &y); + AVI_set_compress_option (avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_QUALITY, &quality); + AVI_set_compress_option (avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_FRAMERATE, &framerate); + + avi->interlace= 0; + avi->odd_fields= 0; +/* avi->interlace= rd->mode & R_FIELDS; */ +/* avi->odd_fields= (rd->mode & R_ODDFIELD)?1:0; */ + + printf("Created avi: %s\n", name); +} + +void append_avi(int frame, int *pixels, int rectx, int recty) +{ + unsigned int *rt1, *rt2, *rectot; + int x, y; + char *cp, rt; + + if (avi == NULL) { + G.afbreek = 1; + return; + } + + /* note that libavi free's the buffer... stupid interface - zr */ + rectot= MEM_mallocN(rectx*recty*sizeof(int), "rectot"); + rt1= rectot; + rt2= (unsigned int*)pixels + (recty-1)*rectx; + /* flip y and convert to abgr */ + for (y=0; y < recty; y++, rt1+= rectx, rt2-= rectx) { + memcpy (rt1, rt2, rectx*sizeof(int)); + + cp= (char *)rt1; + for(x= rectx; x>0; x--) { + rt= cp[0]; + cp[0]= cp[3]; + cp[3]= rt; + rt= cp[1]; + cp[1]= cp[2]; + cp[2]= rt; + cp+= 4; + } + } + + AVI_write_frame (avi, (frame-sframe), AVI_FORMAT_RGB32, rectot, rectx*recty*4); +// printf ("added frame %3d (frame %3d in avi): ", frame, frame-sframe); +} + +void end_avi(void) +{ + if (avi == NULL) return; + + AVI_close_compress (avi); + MEM_freeN (avi); + avi= NULL; +} diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c new file mode 100644 index 00000000000..cbaf1f8c605 --- /dev/null +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -0,0 +1,827 @@ +/* + * ffmpeg-write support + * + * Partial Copyright (c) 2006 Peter Schlaile + * + * 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. + * + */ + + +#ifdef WITH_FFMPEG +#include +#include + +#if defined(_WIN32) && defined(_DEBUG) && !defined(__MINGW32__) && !defined(__CYGWIN__) +/* This does not seem necessary or present on MSVC 8, but may be needed in earlier versions? */ +#if _MSC_VER < 1400 +#include +#endif +#endif + +#include + +#include +#include +#include +#include + +#if LIBAVFORMAT_VERSION_INT < (49 << 16) +#define FFMPEG_OLD_FRAME_RATE 1 +#else +#define FFMPEG_CODEC_IS_POINTER 1 +#define FFMPEG_CODEC_TIME_BASE 1 +#endif + +#if defined(WIN32) && (!(defined snprintf)) +#define snprintf _snprintf +#endif + +#include "BKE_writeffmpeg.h" + +#include "MEM_guardedalloc.h" +#include "BLI_blenlib.h" + +#include "BKE_bad_level_calls.h" +#include "BKE_global.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "BSE_seqaudio.h" + +#include "DNA_scene_types.h" +#include "blendef.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +extern void do_init_ffmpeg(); +void makeffmpegstring(char* string); + +static int ffmpeg_type = 0; +static int ffmpeg_codec = CODEC_ID_MPEG4; +static int ffmpeg_audio_codec = CODEC_ID_MP2; +static int ffmpeg_video_bitrate = 1150; +static int ffmpeg_audio_bitrate = 128; +static int ffmpeg_gop_size = 12; +static int ffmpeg_multiplex_audio = 1; +static int ffmpeg_autosplit = 0; +static int ffmpeg_autosplit_count = 0; + +static AVFormatContext* outfile = 0; +static AVStream* video_stream = 0; +static AVStream* audio_stream = 0; +static AVFrame* current_frame = 0; +static struct SwsContext *img_convert_ctx = 0; + +static uint8_t* video_buffer = 0; +static int video_buffersize = 0; + +static uint8_t* audio_input_buffer = 0; +static int audio_input_frame_size = 0; +static uint8_t* audio_output_buffer = 0; +static int audio_outbuf_size = 0; + +static RenderData *ffmpeg_renderdata = 0; + +#define FFMPEG_AUTOSPLIT_SIZE 2000000000 + +/* Delete a picture buffer */ + +static void delete_picture(AVFrame* f) +{ + if (f) { + if (f->data[0]) MEM_freeN(f->data[0]); + av_free(f); + } +} + +#ifdef FFMPEG_CODEC_IS_POINTER +static AVCodecContext* get_codec_from_stream(AVStream* stream) +{ + return stream->codec; +} +#else +static AVCodecContext* get_codec_from_stream(AVStream* stream) +{ + return &stream->codec; +} +#endif + +static int write_audio_frame(void) +{ + AVCodecContext* c = NULL; + AVPacket pkt; + + c = get_codec_from_stream(audio_stream); + + audiostream_fill(audio_input_buffer, + audio_input_frame_size + * sizeof(short) * c->channels); + + av_init_packet(&pkt); + + pkt.size = avcodec_encode_audio(c, audio_output_buffer, + audio_outbuf_size, + (short*) audio_input_buffer); + pkt.data = audio_output_buffer; +#ifdef FFMPEG_CODEC_TIME_BASE + pkt.pts = av_rescale_q(c->coded_frame->pts, + c->time_base, audio_stream->time_base); +#else + pkt.pts = c->coded_frame->pts; +#endif + fprintf(stderr, "Audio Frame PTS: %lld\n", pkt.pts); + + pkt.stream_index = audio_stream->index; + pkt.flags |= PKT_FLAG_KEY; + if (av_interleaved_write_frame(outfile, &pkt) != 0) { + error("Error writing audio packet"); + return -1; + } + return 0; +} + +/* Allocate a temporary frame */ +static AVFrame* alloc_picture(int pix_fmt, int width, int height) +{ + AVFrame* f; + uint8_t* buf; + int size; + + /* allocate space for the struct */ + f = avcodec_alloc_frame(); + if (!f) return NULL; + size = avpicture_get_size(pix_fmt, width, height); + /* allocate the actual picture buffer */ + buf = MEM_mallocN(size, "AVFrame buffer"); + if (!buf) { + free(f); + return NULL; + } + avpicture_fill((AVPicture*)f, buf, pix_fmt, width, height); + return f; +} + +/* Get the correct file extensions for the requested format, + first is always desired guess_format parameter */ +static const char** get_file_extensions(int format) +{ + switch(format) { + case FFMPEG_DV: { + static const char * rv[] = { ".dv", NULL }; + return rv; + } + case FFMPEG_MPEG1: { + static const char * rv[] = { ".mpg", ".mpeg", NULL }; + return rv; + } + case FFMPEG_MPEG2: { + static const char * rv[] = { ".dvd", ".vob", ".mpg", ".mpeg", + NULL }; + return rv; + } + case FFMPEG_MPEG4: { + static const char * rv[] = { ".mp4", ".mpg", ".mpeg", NULL }; + return rv; + } + case FFMPEG_AVI: { + static const char * rv[] = { ".avi", NULL }; + return rv; + } + case FFMPEG_MOV: { + static const char * rv[] = { ".mov", NULL }; + return rv; + } + case FFMPEG_H264: { + /* FIXME: avi for now... */ + static const char * rv[] = { ".avi", NULL }; + return rv; + } + + case FFMPEG_XVID: { + /* FIXME: avi for now... */ + static const char * rv[] = { ".avi", NULL }; + return rv; + } + default: + return NULL; + } +} + +/* Write a frame to the output file */ +static void write_video_frame(AVFrame* frame) +{ + int outsize = 0; + int ret; + AVCodecContext* c = get_codec_from_stream(video_stream); +#ifdef FFMPEG_CODEC_TIME_BASE + frame->pts = G.scene->r.cfra - G.scene->r.sfra; +#endif + + outsize = avcodec_encode_video(c, video_buffer, video_buffersize, + frame); + if (outsize != 0) { + AVPacket packet; + av_init_packet(&packet); + +#ifdef FFMPEG_CODEC_TIME_BASE + packet.pts = av_rescale_q(c->coded_frame->pts, + c->time_base, + video_stream->time_base); +#else + packet.pts = c->coded_frame->pts; +#endif + fprintf(stderr, "Video Frame PTS: %lld\n", packet.pts); + if (c->coded_frame->key_frame) + packet.flags |= PKT_FLAG_KEY; + packet.stream_index = video_stream->index; + packet.data = video_buffer; + packet.size = outsize; + ret = av_interleaved_write_frame(outfile, &packet); + } else ret = 0; + if (ret != 0) { + G.afbreek = 1; + error("Error writing frame"); + } +} + +/* read and encode a frame of audio from the buffer */ +static AVFrame* generate_video_frame(uint8_t* pixels) +{ + uint8_t* rendered_frame; + + AVCodecContext* c = get_codec_from_stream(video_stream); + int width = c->width; + int height = c->height; + AVFrame* rgb_frame; + + if (c->pix_fmt != PIX_FMT_RGBA32) { + rgb_frame = alloc_picture(PIX_FMT_RGBA32, width, height); + if (!rgb_frame) { + G.afbreek=1; + error("Couldn't allocate temporary frame"); + return NULL; + } + } else { + rgb_frame = current_frame; + } + + rendered_frame = pixels; + + /* Do RGBA-conversion and flipping in one step depending + on CPU-Endianess */ + + if (G.order == L_ENDIAN) { + int y; + for (y = 0; y < height; y++) { + uint8_t* target = rgb_frame->data[0] + + width * 4 * (height - y - 1); + uint8_t* src = rendered_frame + width * 4 * y; + uint8_t* end = src + width * 4; + while (src != end) { + target[3] = src[3]; + target[2] = src[0]; + target[1] = src[1]; + target[0] = src[2]; + + target += 4; + src += 4; + } + } + } else { + int y; + for (y = 0; y < height; y++) { + uint8_t* target = rgb_frame->data[0] + + width * 4 * (height - y - 1); + uint8_t* src = rendered_frame + width * 4 * y; + uint8_t* end = src + width * 4; + while (src != end) { + target[3] = src[2]; + target[2] = src[1]; + target[1] = src[0]; + target[0] = src[3]; + + target += 4; + src += 4; + } + } + } + + if (c->pix_fmt != PIX_FMT_RGBA32) { + sws_scale(img_convert_ctx, rgb_frame->data, + rgb_frame->linesize, 0, c->height, + current_frame->data, current_frame->linesize); + delete_picture(rgb_frame); + } + return current_frame; +} + +/* prepare a video stream for the output file */ + +static AVStream* alloc_video_stream(int codec_id, AVFormatContext* of, + int rectx, int recty) +{ + AVStream* st; + AVCodecContext* c; + AVCodec* codec; + st = av_new_stream(of, 0); + if (!st) return NULL; + + /* Set up the codec context */ + + c = get_codec_from_stream(st); + c->codec_id = codec_id; + c->codec_type = CODEC_TYPE_VIDEO; + + + /* Get some values from the current render settings */ + + c->width = rectx; + c->height = recty; + +#ifdef FFMPEG_CODEC_TIME_BASE + /* FIXME: Really bad hack (tm) for NTSC support */ + if (ffmpeg_type == FFMPEG_DV && G.scene->r.frs_sec != 25) { + c->time_base.den = 2997; + c->time_base.num = 100; + } else if ((double) ((int) G.scene->r.frs_sec_base) == + G.scene->r.frs_sec_base) { + c->time_base.den = G.scene->r.frs_sec; + c->time_base.num = (int) G.scene->r.frs_sec_base; + } else { + c->time_base.den = G.scene->r.frs_sec * 100000; + c->time_base.num = ((double) G.scene->r.frs_sec_base) * 100000; + } +#else + /* FIXME: Really bad hack (tm) for NTSC support */ + if (ffmpeg_type == FFMPEG_DV && G.scene->r.frs_sec != 25) { + c->frame_rate = 2997; + c->frame_rate_base = 100; + } else if ((double) ((int) G.scene->r.frs_sec_base) == + G.scene->r.frs_sec_base) { + c->frame_rate = G.scene->r.frs_sec; + c->frame_rate_base = G.scene->r.frs_sec_base; + } else { + c->frame_rate = G.scene->r.frs_sec * 100000; + c->frame_rate_base = ((double) G.scene->r.frs_sec_base)*100000; + } +#endif + + c->gop_size = ffmpeg_gop_size; + c->bit_rate = ffmpeg_video_bitrate*1000; + c->rc_max_rate = G.scene->r.ffcodecdata.rc_max_rate*1000; + c->rc_min_rate = G.scene->r.ffcodecdata.rc_min_rate*1000; + c->rc_buffer_size = G.scene->r.ffcodecdata.rc_buffer_size * 1024; + c->rc_initial_buffer_occupancy + = G.scene->r.ffcodecdata.rc_buffer_size*3/4; + c->rc_buffer_aggressivity = 1.0; + c->me_method = ME_EPZS; + + codec = avcodec_find_encoder(c->codec_id); + if (!codec) return NULL; + + /* Be sure to use the correct pixel format(e.g. RGB, YUV) */ + + if (codec->pix_fmts) { + c->pix_fmt = codec->pix_fmts[0]; + } else { + /* makes HuffYUV happy ... */ + c->pix_fmt = PIX_FMT_YUV422P; + } + + if (codec_id == CODEC_ID_XVID) { + /* arghhhh ... */ + c->pix_fmt = PIX_FMT_YUV420P; + } + + if (!strcmp(of->oformat->name, "mp4") || + !strcmp(of->oformat->name, "mov") || + !strcmp(of->oformat->name, "3gp")) { + fprintf(stderr, "Using global header\n"); + c->flags |= CODEC_FLAG_GLOBAL_HEADER; + } + + /* Determine whether we are encoding interlaced material or not */ + if (G.scene->r.mode & (1 << 6)) { + fprintf(stderr, "Encoding interlaced video\n"); + c->flags |= CODEC_FLAG_INTERLACED_DCT; + c->flags |= CODEC_FLAG_INTERLACED_ME; + } + c->sample_aspect_ratio.num = G.scene->r.xasp; + c->sample_aspect_ratio.den = G.scene->r.yasp; + + if (avcodec_open(c, codec) < 0) { + error("Couldn't initialize codec"); + return NULL; + } + + video_buffersize = 2000000; + video_buffer = (uint8_t*)MEM_mallocN(video_buffersize, + "FFMPEG video buffer"); + + current_frame = alloc_picture(c->pix_fmt, c->width, c->height); + + img_convert_ctx = sws_getContext(c->width, c->height, + PIX_FMT_RGBA32, + c->width, c->height, + c->pix_fmt, + SWS_BICUBIC, + NULL, NULL, NULL); + return st; +} + +/* Prepare an audio stream for the output file */ + +static AVStream* alloc_audio_stream(int codec_id, AVFormatContext* of) +{ + AVStream* st; + AVCodecContext* c; + AVCodec* codec; + + st = av_new_stream(of, 1); + if (!st) return NULL; + + c = get_codec_from_stream(st); + c->codec_id = codec_id; + c->codec_type = CODEC_TYPE_AUDIO; + + c->sample_rate = G.scene->audio.mixrate; + c->bit_rate = ffmpeg_audio_bitrate*1000; + c->channels = 2; + codec = avcodec_find_encoder(c->codec_id); + if (!codec) { + error("Couldn't find a valid audio codec"); + return NULL; + } + if (avcodec_open(c, codec) < 0) { + error("Couldn't initialize audio codec"); + return NULL; + } + + /* FIXME: Should be user configurable */ + if (ffmpeg_type == FFMPEG_DV) { + /* this is a hack around the poor ffmpeg dv multiplexer. */ + /* only fixes PAL for now + (NTSC is a lot more complicated here...)! */ + audio_outbuf_size = 7680; + } else { + audio_outbuf_size = 10000; + } + audio_output_buffer = (uint8_t*)MEM_mallocN( + audio_outbuf_size, "FFMPEG audio encoder input buffer"); + + /* ugly hack for PCM codecs */ + + if (c->frame_size <= 1) { + audio_input_frame_size = audio_outbuf_size / c->channels; + switch(c->codec_id) { + case CODEC_ID_PCM_S16LE: + case CODEC_ID_PCM_S16BE: + case CODEC_ID_PCM_U16LE: + case CODEC_ID_PCM_U16BE: + audio_input_frame_size >>= 1; + break; + default: + break; + } + } else { + audio_input_frame_size = c->frame_size; + } + + audio_input_buffer = (uint8_t*)MEM_mallocN( + audio_input_frame_size * sizeof(short) * c->channels, + "FFMPEG audio encoder output buffer"); + + return st; +} +/* essential functions -- start, append, end */ + +void start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty) +{ + /* Handle to the output file */ + AVFormatContext* of; + AVOutputFormat* fmt; + char name[256]; + const char ** exts; + + ffmpeg_type = rd->ffcodecdata.type; + ffmpeg_codec = rd->ffcodecdata.codec; + ffmpeg_audio_codec = rd->ffcodecdata.audio_codec; + ffmpeg_video_bitrate = rd->ffcodecdata.video_bitrate; + ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate; + ffmpeg_gop_size = rd->ffcodecdata.gop_size; + ffmpeg_multiplex_audio = rd->ffcodecdata.flags + & FFMPEG_MULTIPLEX_AUDIO; + ffmpeg_autosplit = rd->ffcodecdata.flags + & FFMPEG_AUTOSPLIT_OUTPUT; + + do_init_ffmpeg(); + + /* Determine the correct filename */ + makeffmpegstring(name); + fprintf(stderr, "Starting output to %s(ffmpeg)...\n" + " Using type=%d, codec=%d, audio_codec=%d,\n" + " video_bitrate=%d, audio_bitrate=%d,\n" + " gop_size=%d, multiplex=%d, autosplit=%d\n" + " render width=%d, render height=%d\n", + name, ffmpeg_type, ffmpeg_codec, ffmpeg_audio_codec, + ffmpeg_video_bitrate, ffmpeg_audio_bitrate, + ffmpeg_gop_size, ffmpeg_multiplex_audio, + ffmpeg_autosplit, rectx, recty); + + exts = get_file_extensions(ffmpeg_type); + if (!exts) { + G.afbreek = 1; /* Abort render */ + error("No valid formats found"); + return; + } + fmt = guess_format(NULL, exts[0], NULL); + if (!fmt) { + G.afbreek = 1; /* Abort render */ + error("No valid formats found"); + return; + } + + of = av_alloc_format_context(); + if (!of) { + G.afbreek = 1; + error("Error opening output file"); + return; + } + + of->oformat = fmt; + of->packet_size= G.scene->r.ffcodecdata.mux_packet_size; + if (ffmpeg_multiplex_audio) { + of->mux_rate = G.scene->r.ffcodecdata.mux_rate; + } else { + of->mux_rate = 0; + } + + of->preload = (int)(0.5*AV_TIME_BASE); + of->max_delay = (int)(0.7*AV_TIME_BASE); + + snprintf(of->filename, sizeof(of->filename), "%s", name); + /* set the codec to the user's selection */ + switch(ffmpeg_type) { + case FFMPEG_AVI: + case FFMPEG_MOV: + fmt->video_codec = ffmpeg_codec; + break; + case FFMPEG_DV: + fmt->video_codec = CODEC_ID_DVVIDEO; + break; + case FFMPEG_MPEG1: + fmt->video_codec = CODEC_ID_MPEG1VIDEO; + break; + case FFMPEG_MPEG2: + fmt->video_codec = CODEC_ID_MPEG2VIDEO; + break; + case FFMPEG_H264: + fmt->video_codec = CODEC_ID_H264; + break; + case FFMPEG_XVID: + fmt->video_codec = CODEC_ID_XVID; + break; + case FFMPEG_MPEG4: + default: + fmt->video_codec = CODEC_ID_MPEG4; + break; + } + if (fmt->video_codec == CODEC_ID_DVVIDEO) { + if (rectx != 720) { + G.afbreek = 1; + error("Render width has to be 720 pixels for DV!"); + return; + } + if (G.scene->r.frs_sec != 25 && recty != 480) { + G.afbreek = 1; + error("Render height has to be 480 pixels " + "for DV-NTSC!"); + return; + + } + if (G.scene->r.frs_sec == 25 && recty != 576) { + G.afbreek = 1; + error("Render height has to be 576 pixels " + "for DV-PAL!"); + return; + } + } + if (ffmpeg_type == FFMPEG_DV) { + fmt->audio_codec = CODEC_ID_PCM_S16LE; + if (ffmpeg_multiplex_audio + && G.scene->audio.mixrate != 48000) { + G.afbreek = 1; + error("FFMPEG only supports 48khz / stereo " + "audio for DV!"); + return; + } + } + + video_stream = alloc_video_stream(fmt->video_codec, of, rectx, recty); + if (!video_stream) { + G.afbreek = 1; + error("Error initializing video stream"); + return; + } + + if (ffmpeg_multiplex_audio) { + audio_stream = alloc_audio_stream(fmt->audio_codec, of); + if (!audio_stream) { + G.afbreek = 1; + error("Error initializing audio stream"); + return; + } + audiostream_play(SFRA, 0, 1); + } + if (av_set_parameters(of, NULL) < 0) { + G.afbreek = 1; + error("Error setting output parameters"); + return; + } + if (!(fmt->flags & AVFMT_NOFILE)) { + if (url_fopen(&of->pb, name, URL_WRONLY) < 0) { + G.afbreek = 1; + error("Could not open file for writing"); + return; + } + } + + av_write_header(of); + outfile = of; + dump_format(of, 0, name, 1); +} + +/* ********************************************************************** + * public interface + ********************************************************************** */ + +/* Get the output filename-- similar to the other output formats */ +void makeffmpegstring(char* string) { + + char txt[FILE_MAXDIR+FILE_MAXFILE]; + char autosplit[20]; + + const char ** exts = get_file_extensions(G.scene->r.ffcodecdata.type); + const char ** fe = exts; + + if (!string || !exts) return; + + strcpy(string, G.scene->r.pic); + BLI_convertstringcode(string, G.sce, G.scene->r.cfra); + + BLI_make_existing_file(string); + + autosplit[0] = 0; + + if ((G.scene->r.ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT) != 0) { + sprintf(autosplit, "_%03d", ffmpeg_autosplit_count); + } + + while (*fe) { + if (BLI_strcasecmp(string + strlen(string) - strlen(*fe), + *fe) == 0) { + break; + } + fe++; + } + + if (!*fe) { + strcat(string, autosplit); + sprintf(txt, "%04d_%04d%s", (G.scene->r.sfra), + (G.scene->r.efra), *exts); + strcat(string, txt); + } else { + *(string + strlen(string) - strlen(*fe)) = 0; + strcat(string, autosplit); + strcat(string, *fe); + } +} + + +void start_ffmpeg(RenderData *rd, int rectx, int recty) +{ + ffmpeg_autosplit_count = 0; + + ffmpeg_renderdata = rd; + + start_ffmpeg_impl(rd, rectx, recty); +} + +void end_ffmpeg(void); + +static void write_audio_frames() +{ + int finished = 0; + + while (ffmpeg_multiplex_audio && !finished) { + double a_pts = ((double)audio_stream->pts.val + * audio_stream->time_base.num + / audio_stream->time_base.den); + double v_pts = ((double)video_stream->pts.val + * video_stream->time_base.num + / video_stream->time_base.den); + + if (a_pts < v_pts) { + write_audio_frame(); + } else { + finished = 1; + } + } +} + +void append_ffmpeg(int frame, int *pixels, int rectx, int recty) +{ + fprintf(stderr, "Writing frame %i, " + "render width=%d, render height=%d\n", frame, + rectx, recty); + + write_audio_frames(); + write_video_frame(generate_video_frame((unsigned char*) pixels)); + + if (ffmpeg_autosplit) { + if (url_ftell(&outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) { + end_ffmpeg(); + ffmpeg_autosplit_count++; + start_ffmpeg_impl(ffmpeg_renderdata, + rectx, recty); + } + } +} + + +void end_ffmpeg(void) +{ + int i; + + fprintf(stderr, "Closing ffmpeg...\n"); + + if (audio_stream) { + write_audio_frames(); + } + + if (outfile) { + av_write_trailer(outfile); + } + + /* Close the video codec */ + + if (video_stream && get_codec_from_stream(video_stream)) { + avcodec_close(get_codec_from_stream(video_stream)); + video_stream = 0; + } + + + /* Close the output file */ + if (outfile) { + for (i = 0; i < outfile->nb_streams; i++) { + if (&outfile->streams[i]) { + av_freep(&outfile->streams[i]); + } + } + } + /* free the temp buffer */ + if (current_frame) { + delete_picture(current_frame); + current_frame = 0; + } + if (outfile && outfile->oformat) { + if (!(outfile->oformat->flags & AVFMT_NOFILE)) { + url_fclose(&outfile->pb); + } + } + if (outfile) { + av_free(outfile); + outfile = 0; + } + if (video_buffer) { + MEM_freeN(video_buffer); + video_buffer = 0; + } + if (audio_output_buffer) { + MEM_freeN(audio_output_buffer); + audio_output_buffer = 0; + } + if (audio_input_buffer) { + MEM_freeN(audio_input_buffer); + audio_input_buffer = 0; + } + + if (img_convert_ctx) { + sws_freeContext(img_convert_ctx); + img_convert_ctx = 0; + } +} +#endif + diff --git a/source/blender/blenkernel/intern/writeframeserver.c b/source/blender/blenkernel/intern/writeframeserver.c new file mode 100644 index 00000000000..6b38d7deadb --- /dev/null +++ b/source/blender/blenkernel/intern/writeframeserver.c @@ -0,0 +1,381 @@ +/* + * Frameserver + * Makes Blender accessible from TMPGenc directly using VFAPI (you can + * use firefox too ;-) + * + * Copyright (c) 2006 Peter Schlaile + * + * 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. + * + */ + + +#include +#include + +#if defined(_WIN32) +#include +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include + +#include "MEM_guardedalloc.h" +#include "BLI_blenlib.h" +#include "DNA_userdef_types.h" + +#include "BKE_bad_level_calls.h" +#include "BKE_global.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "DNA_scene_types.h" +#include "blendef.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +static int sock; +static int connsock; +static int write_ppm; +static int render_width; +static int render_height; + + +#if defined(_WIN32) +static int startup_socket_system() +{ + WSADATA wsa; + return (WSAStartup(MAKEWORD(2,0),&wsa) == 0); +} + +static void shutdown_socket_system() +{ + WSACleanup(); +} +static int select_was_interrupted_by_signal() +{ + return (WSAGetLastError() == WSAEINTR); +} +#else +static int startup_socket_system() +{ + return 1; +} + +static void shutdown_socket_system() +{ +} + +static int select_was_interrupted_by_signal() +{ + return (errno == EINTR); +} + +static int closesocket(int fd) +{ + return close(fd); +} +#endif + +void start_frameserver(RenderData *rd, int rectx, int recty) +{ + struct sockaddr_in addr; + int arg = 1; + + if (!startup_socket_system()) { + G.afbreek = 1; + error("Can't startup socket system"); + return; + } + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + shutdown_socket_system(); + G.afbreek = 1; /* Abort render */ + error("Can't open socket"); + return; + } + + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, + (char*) &arg, sizeof(arg)); + + addr.sin_family = AF_INET; + addr.sin_port = htons(U.frameserverport); + addr.sin_addr.s_addr = INADDR_ANY; + + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + shutdown_socket_system(); + G.afbreek = 1; /* Abort render */ + error("Can't bind to socket"); + return; + } + + if (listen(sock, SOMAXCONN) < 0) { + shutdown_socket_system(); + G.afbreek = 1; /* Abort render */ + error("Can't establish listen backlog"); + return; + } + connsock = -1; + + render_width = rectx; + render_height = recty; +} + +static char index_page[] += +"HTTP/1.1 200 OK\n" +"Content-Type: text/html\n\n" +"Blender Frameserver\n" +"\n"; + +static char good_bye[] += "HTTP/1.1 200 OK\n" +"Content-Type: text/html\n\n" +"Blender Frameserver\n" +"
\n"
+"Render stopped. Goodbye
"; + +static int safe_write(char * s, int tosend) +{ + int total = tosend; + do { + int got = send(connsock, s, tosend, 0); + if (got < 0) { + return got; + } + tosend -= got; + s += got; + } while (tosend > 0); + + return total; +} + +static int safe_puts(char * s) +{ + return safe_write(s, strlen(s)); +} + +static int handle_request(char * req) +{ + char * p; + char * path; + int pathlen; + + if (memcmp(req, "GET ", 4) != 0) { + return -1; + } + + p = req + 4; + path = p; + + while (*p != ' ' && *p) p++; + + *p = 0; + + if (strcmp(path, "/index.html") == 0 + || strcmp(path, "/") == 0) { + safe_puts(index_page); + return -1; + } + + write_ppm = 0; + pathlen = strlen(path); + + if (pathlen > 12 && memcmp(path, "/images/ppm/", 12) == 0) { + write_ppm = 1; + return atoi(path + 12); + } + if (strcmp(path, "/info.txt") == 0) { + char buf[4096]; + + sprintf(buf, + "HTTP/1.1 200 OK\n" + "Content-Type: text/html\n\n" + "start %d\n" + "end %d\n" + "width %d\n" + "height %d\n" + "rate %d\n" + "ratescale %d\n", + G.scene->r.sfra, + G.scene->r.efra, + render_width, + render_height, + G.scene->r.frs_sec, + 1 + ); + + safe_puts(buf); + return -1; + } + if (strcmp(path, "/close.txt") == 0) { + safe_puts(good_bye); + G.afbreek = 1; /* Abort render */ + return -1; + } + return -1; +} + +int frameserver_loop() +{ + fd_set readfds; + struct timeval tv; + struct sockaddr_in addr; + int len, rval; + unsigned int socklen; + char buf[4096]; + + if (connsock != -1) { + closesocket(connsock); + connsock = -1; + } + + tv.tv_sec = 1; + tv.tv_usec = 0; + + FD_ZERO(&readfds); + FD_SET(sock, &readfds); + + rval = select(sock + 1, &readfds, NULL, NULL, &tv); + if (rval < 0) { + return -1; + } + + if (rval == 0) { /* nothing to be done */ + return -1; + } + + socklen = sizeof(addr); + + if ((connsock = accept(sock, (struct sockaddr *)&addr, &socklen)) < 0) { + return -1; + } + + FD_ZERO(&readfds); + FD_SET(connsock, &readfds); + + for (;;) { + /* give 10 seconds for telnet testing... */ + tv.tv_sec = 10; + tv.tv_usec = 0; + + rval = select(connsock + 1, &readfds, NULL, NULL, &tv); + if (rval > 0) { + break; + } else if (rval == 0) { + return -1; + } else if (rval < 0) { + if (!select_was_interrupted_by_signal()) { + return -1; + } + } + } + + len = recv(connsock, buf, 4095, 0); + + if (len < 0) { + return -1; + } + + buf[len] = 0; + + return handle_request(buf); +} + +static void serve_ppm(int *pixels, int rectx, int recty) +{ + unsigned char* rendered_frame; + unsigned char* row = (unsigned char*) malloc(render_width * 3); + int y; + char header[1024]; + + sprintf(header, + "HTTP/1.1 200 OK\n" + "Content-Type: image/ppm\n" + "Connection: close\n\n" + "P6\n" + "# Creator: blender frameserver v0.0.1\n" + "%d %d\n" + "255\n", + rectx, recty); + + safe_puts(header); + + rendered_frame = (unsigned char *)pixels; + + for (y = recty - 1; y >= 0; y--) { + unsigned char* target = row; + unsigned char* src = rendered_frame + rectx * 4 * y; + unsigned char* end = src + rectx * 4; + while (src != end) { + target[2] = src[2]; + target[1] = src[1]; + target[0] = src[0]; + + target += 3; + src += 4; + } + safe_write((char*)row, 3 * rectx); + } + free(row); + closesocket(connsock); + connsock = -1; +} + +void append_frameserver(int frame, int *pixels, int rectx, int recty) +{ + fprintf(stderr, "Serving frame: %d\n", frame); + if (write_ppm) { + serve_ppm(pixels, rectx, recty); + } + if (connsock != -1) { + closesocket(connsock); + connsock = -1; + } +} + +void end_frameserver() +{ + if (connsock != -1) { + closesocket(connsock); + connsock = -1; + } + closesocket(sock); + shutdown_socket_system(); +} + diff --git a/source/blender/blenlib/BLI_arithb.h b/source/blender/blenlib/BLI_arithb.h new file mode 100644 index 00000000000..d5e7447ff66 --- /dev/null +++ b/source/blender/blenlib/BLI_arithb.h @@ -0,0 +1,385 @@ +#undef TEST_ACTIVE +//#define ACTIVE 1 +/** + * blenlib/BLI_arithb.h mar 2001 Nzc + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * */ + +#ifndef BLI_ARITHB_H +#define BLI_ARITHB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif +#ifndef M_PI_2 +#define M_PI_2 1.57079632679489661923 +#endif +#ifndef M_SQRT2 +#define M_SQRT2 1.41421356237309504880 +#endif +#ifndef M_SQRT1_2 +#define M_SQRT1_2 0.70710678118654752440 +#endif + +#define MAT4_UNITY {{ 1.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, 1.0}} + +#define MAT3_UNITY {{ 1.0, 0.0, 0.0},\ + { 0.0, 1.0, 0.0},\ + { 0.0, 0.0, 1.0}} + + +void CalcCent3f(float *cent, float *v1, float *v2, float *v3); +void CalcCent4f(float *cent, float *v1, float *v2, float *v3, float *v4); + +void Crossf(float *c, float *a, float *b); +void Projf(float *c, float *v1, float *v2); + +float Inpf(float *v1, float *v2); +float Inp2f(float *v1, float *v2); + +float Normalize(float *n); +float Normalize2(float *n); + +float Sqrt3f(float f); +double Sqrt3d(double d); + +float saacos(float fac); +float saasin(float fac); +float sasqrt(float fac); + +int FloatCompare(float *v1, float *v2, float limit); +float FloatLerpf(float target, float origin, float fac); + +float CalcNormFloat(float *v1, float *v2, float *v3, float *n); +float CalcNormFloat4(float *v1, float *v2, float *v3, float *v4, float *n); + +void CalcNormLong(int *v1, int *v2, int *v3, float *n); +/* CalcNormShort: is ook uitprodukt - (translates as 'is also out/cross product') */ +void CalcNormShort(short *v1, short *v2, short *v3, float *n); + + +/** + * @section Euler conversion routines + */ + +void EulToMat3(float *eul, float mat[][3]); +void EulToMat4(float *eul, float mat[][4]); + +void Mat3ToEul(float tmat[][3], float *eul); +void Mat4ToEul(float tmat[][4],float *eul); + +void EulToQuat(float *eul, float *quat); + +void compatible_eul(float *eul, float *oldrot); + +void Mat3ToCompatibleEul(float mat[][3], float *eul, float *oldrot); + + +/** + * @section Quaternion arithmetic routines + */ + +void QuatToEul(float *quat, float *eul); +void QuatOne(float *); +void QuatMul(float *, float *, float *); +void QuatMulVecf(float *q, float *v); + +void NormalQuat(float *); +void VecRotToQuat(float *vec, float phi, float *quat); + +void QuatSub(float *q, float *q1, float *q2); +void QuatConj(float *q); +void QuatInv(float *q); +void QuatMulf(float *q, float f); +float QuatDot(float *q1, float *q2); +void QuatCopy(float *q1, float *q2); + +void printquat(char *str, float q[4]); + +void QuatInterpol(float *result, float *quat1, float *quat2, float t); +void QuatAdd(float *result, float *quat1, float *quat2, float t); + + +/** + * @section matrix multiplication and copying routines + */ + +void Mat3MulFloat(float *m, float f); +void Mat4MulFloat(float *m, float f); +void Mat4MulFloat3(float *m, float f); + +void Mat3Transp(float mat[][3]); +void Mat4Transp(float mat[][4]); + +int Mat4Invert(float inverse[][4], float mat[][4]); +void Mat4InvertSimp(float inverse[][4], float mat[][4]); +void Mat4Inv(float *m1, float *m2); +void Mat4InvGG(float out[][4], float in[][4]); +void Mat3Inv(float m1[][3], float m2[][3]); + +void Mat3CpyMat4(float m1[][3],float m2[][4]); +void Mat4CpyMat3(float m1[][4], float m2[][3]); + +void Mat4BlendMat4(float out[][4], float dst[][4], float src[][4], float srcweight); + +float Det2x2(float a,float b,float c, float d); + +float Det3x3( + float a1, float a2, float a3, + float b1, float b2, float b3, + float c1, float c2, float c3 +); + +float Det4x4(float m[][4]); + +void Mat3Adj(float m1[][3], float m[][3]); +void Mat4Adj(float out[][4], float in[][4]); + +void Mat4MulMat4(float m1[][4], float m2[][4], float m3[][4]); +void subMat4MulMat4(float *m1, float *m2, float *m3); +#ifndef TEST_ACTIVE +void Mat3MulMat3(float m1[][3], float m3[][3], float m2[][3]); +#else +void Mat3MulMat3(float *m1, float *m3, float *m2); +#endif +void Mat4MulMat34(float (*m1)[4], float (*m3)[3], float (*m2)[4]); +void Mat4CpyMat4(float m1[][4], float m2[][4]); +void Mat4SwapMat4(float *m1, float *m2); +void Mat3CpyMat3(float m1[][3], float m2[][3]); + +void Mat3MulSerie(float answ[][3], + float m1[][3], float m2[][3], float m3[][3], + float m4[][3], float m5[][3], float m6[][3], + float m7[][3], float m8[][3] +); + +void Mat4MulSerie(float answ[][4], float m1[][4], + float m2[][4], float m3[][4], float m4[][4], + float m5[][4], float m6[][4], float m7[][4], + float m8[][4] +); + +void Mat4Clr(float *m); +void Mat3Clr(float *m); + +void Mat3One(float m[][3]); +void Mat4One(float m[][4]); + +void Mat3Ortho(float mat[][3]); +void Mat4Ortho(float mat[][4]); + +void VecMat4MulVecfl(float *in, float mat[][4], float *vec); +void Mat4MulMat43(float (*m1)[4], float (*m3)[4], float (*m2)[3]); +void Mat3IsMat3MulMat4(float m1[][3], float m2[][3], float m3[][4]); + +void Mat4MulVec(float mat[][4],int *vec); +void Mat4MulVecfl(float mat[][4], float *vec); +void Mat4Mul3Vecfl(float mat[][4], float *vec); +void Mat4MulVec3Project(float mat[][4],float *vec); +void Mat4MulVec4fl(float mat[][4], float *vec); +void Mat3MulVec(float mat[][3],int *vec); +void Mat3MulVecfl(float mat[][3], float *vec); +void Mat3MulVecd(float mat[][3], double *vec); +void Mat3TransMulVecfl(float mat[][3], float *vec); + +void Mat3AddMat3(float m1[][3], float m2[][3], float m3[][3]); +void Mat4AddMat4(float m1[][4], float m2[][4], float m3[][4]); + +void VecUpMat3old(float *vec, float mat[][3], short axis); +void VecUpMat3(float *vec, float mat[][3], short axis); +void VecRotToMat3(float *vec, float phi, float mat[][3]); +void VecRotToMat4(float *vec, float phi, float mat[][4]); + +void VecCopyf(float *v1, float *v2); +int VecLen(int *v1, int *v2); +float VecLenf(float *v1, float *v2); +float VecLength(float *v); +void VecMulf(float *v1, float f); + +int VecLenCompare(float *v1, float *v2, float limit); +int VecCompare(float *v1, float *v2, float limit); +int VecEqual(float *v1, float *v2); + +void printvecf(char *str,float v[3]); +void printvec4f(char *str, float v[4]); + +void VecAddf(float *v, float *v1, float *v2); +void VecSubf(float *v, float *v1, float *v2); +void VecLerpf(float *target, float *a, float *b, float t); +void VecMidf(float *v, float *v1, float *v2); + +void VecOrthoBasisf(float *v, float *v1, float *v2); + +float Vec2Lenf(float *v1, float *v2); +void Vec2Mulf(float *v1, float f); +void Vec2Addf(float *v, float *v1, float *v2); +void Vec2Subf(float *v, float *v1, float *v2); +void Vec2Copyf(float *v1, float *v2); + +float *vectoquat(float *vec, short axis, short upflag); + +float VecAngle2(float *v1, float *v2); +float VecAngle3(float *v1, float *v2, float *v3); +float NormalizedVecAngle2(float *v1, float *v2); + +void euler_rot(float *beul, float ang, char axis); + + +float DistVL2Dfl(float *v1, float *v2, float *v3); +float PdistVL2Dfl(float *v1, float *v2, float *v3); +float PdistVL3Dfl(float *v1, float *v2, float *v3); +void PclosestVL3Dfl(float *closest, float *v1, float *v2, float *v3); +float AreaF2Dfl(float *v1, float *v2, float *v3); +float AreaQ3Dfl(float *v1, float *v2, float *v3, float *v4); +float AreaT3Dfl(float *v1, float *v2, float *v3); +float AreaPoly3Dfl(int nr, float *verts, float *normal); + +/* intersect Line-Line + return: + -1: colliniar + 0: no intersection of segments + 1: exact intersection of segments + 2: cross-intersection of segments +*/ +extern short IsectLL2Df(float *v1, float *v2, float *v3, float *v4); +extern short IsectLL2Ds(short *v1, short *v2, short *v3, short *v4); + +/* interpolation weights of point in a triangle or quad, v4 may be NULL */ +void InterpWeightsQ3Dfl(float *v1, float *v2, float *v3, float *v4, float *co, float *w); +/* interpolation weights of point in a polygon with >= 3 vertices */ +void MeanValueWeights(float v[][3], int n, float *co, float *w); + +void i_lookat( + float vx, float vy, + float vz, float px, + float py, float pz, + float twist, float mat[][4] +); + +void i_window( + float left, float right, + float bottom, float top, + float nearClip, float farClip, + float mat[][4] +); + +void hsv_to_rgb(float h, float s, float v, float *r, float *g, float *b); +void hex_to_rgb(char *hexcol, float *r, float *g, float *b); +void rgb_to_yuv(float r, float g, float b, float *ly, float *lu, float *lv); +void yuv_to_rgb(float y, float u, float v, float *lr, float *lg, float *lb); +void ycc_to_rgb(float y, float cb, float cr, float *lr, float *lg, float *lb); +void rgb_to_ycc(float r, float g, float b, float *ly, float *lcb, float *lcr); +void rgb_to_hsv(float r, float g, float b, float *lh, float *ls, float *lv); +unsigned int hsv_to_cpack(float h, float s, float v); +unsigned int rgb_to_cpack(float r, float g, float b); +void cpack_to_rgb(unsigned int col, float *r, float *g, float *b); +void MinMaxRGB(short c[]); + + + +void VecStar(float mat[][3],float *vec); + +short EenheidsMat(float mat[][3]); + +void QuatToMat3(float *q, float m[][3]); +void QuatToMat4(float *q, float m[][4]); + +void Mat3ToQuat_is_ok(float wmat[][3], float *q); + +void i_ortho(float left, float right, float bottom, float top, float nearClip, float farClip, float matrix[][4]); +void i_polarview(float dist, float azimuth, float incidence, float twist, float Vm[][4]); +void i_translate(float Tx, float Ty, float Tz, float mat[][4]); +void i_multmatrix(float icand[][4], float Vm[][4]); +void i_rotate(float angle, char axis, float mat[][4]); + + + + + +void MinMax3(float *min, float *max, float *vec); +void SizeToMat3(float *size, float mat[][3]); +void SizeToMat4(float *size, float mat[][4]); + +float Mat3ToScalef(float mat[][3]); +float Mat4ToScalef(float mat[][4]); + +void printmatrix3(char *str, float m[][3]); +void printmatrix4(char *str, float m[][4]); + +/* uit Sig.Proc.85 pag 253 */ +void Mat3ToQuat(float wmat[][3], float *q); +void Mat4ToQuat(float m[][4], float *q); + +void Mat3ToSize(float mat[][3], float *size); +void Mat4ToSize(float mat[][4], float *size); + +void triatoquat(float *v1, float *v2, float *v3, float *quat); + +void LocEulSizeToMat4(float mat[][4], float loc[3], float eul[3], float size[3]); +void LocQuatSizeToMat4(float mat[][4], float loc[3], float quat[4], float size[3]); + +void tubemap(float x, float y, float z, float *u, float *v); +void spheremap(float x, float y, float z, float *u, float *v); + +int LineIntersectsTriangle(float p1[3], float p2[3], float v0[3], float v1[3], float v2[3], float *lambda); +int point_in_tri_prism(float p[3], float v1[3], float v2[3], float v3[3]); + +float lambda_cp_line_ex(float p[3], float l1[3], float l2[3], float cp[3]); + +typedef struct DualQuat { + float quat[4]; + float trans[4]; + + float scale[4][4]; + float scale_weight; +} DualQuat; + +void Mat4ToDQuat(float basemat[][4], float mat[][4], DualQuat *dq); +void DQuatToMat4(DualQuat *dq, float mat[][4]); +void DQuatAddWeighted(DualQuat *dqsum, DualQuat *dq, float weight); +void DQuatNormalize(DualQuat *dq, float totweight, float factor); +void DQuatMulVecfl(DualQuat *dq, float *co, float mat[][3]); +void DQuatCpyDQuat(DualQuat *dq1, DualQuat *dq2); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/source/blender/blenlib/BLI_blenlib.h b/source/blender/blenlib/BLI_blenlib.h new file mode 100644 index 00000000000..57248fb1d68 --- /dev/null +++ b/source/blender/blenlib/BLI_blenlib.h @@ -0,0 +1,406 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + * @mainpage BLI - Blender LIbrary external interface + * + * @section about About the BLI module + * + * This is the external interface of the Blender Library. If you find + * a call to a BLI function that is not prototyped here, please add a + * prototype here. The library offers mathematical operations (mainly + * vector and matrix calculus), an abstraction layer for file i/o, + * functions for calculating Perlin noise, scanfilling services for + * triangles, and a system for guarded memory + * allocation/deallocation. There is also a patch to make MS Windows + * behave more or less Posix-compliant. + * + * @section issues Known issues with BLI + * + * - blenlib is written in C. + * - The posix-compliancy may move to a separate lib that deals with + * platform dependencies. (There are other platform-dependent + * fixes as well.) + * - The file i/o has some redundant code. It should be cleaned. + * - arithb.c is a very messy matrix library. We need a better + * solution. + * - vectorops.c is close to superfluous. It may disappear in the + * near future. + * + * @section dependencies Dependencies + * + * - The blenlib uses type defines from makesdna/, and functions from + * standard libraries. + * + * $Id$ +*/ + +#ifndef BLI_BLENLIB_H +#define BLI_BLENLIB_H + +/* braindamage for the masses... needed + because fillfacebase and fillvertbase are used outside */ +#include "DNA_listBase.h" + +#include + +extern ListBase fillfacebase; +extern ListBase fillvertbase; +/** + * @attention Defined in scanfill.c + */ +extern ListBase filledgebase; +extern int totblock; + +struct chardesc; +struct direntry; +struct rctf; +struct rcti; +struct EditVert; +struct PackedFile; +struct LinkNode; +struct DynamicList; + +#ifdef __cplusplus +extern "C" { +#endif + +/* BLI_util.h */ +char *BLI_gethome(void); +void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file); +void BLI_make_exist(char *dir); +void BLI_make_existing_file(char *name); +void BLI_split_dirfile(const char *string, char *dir, char *file); +void BLI_join_dirfile(char *string, const char *dir, const char *file); +int BLI_testextensie(const char *str, const char *ext); +void addlisttolist(ListBase *list1, ListBase *list2); +void BLI_insertlink(struct ListBase *listbase, void *vprevlink, void *vnewlink); +void *BLI_findlink(struct ListBase *listbase, int number); +int BLI_findindex(struct ListBase *listbase, void *vlink); +void BLI_freelistN(struct ListBase *listbase); +void BLI_addtail(struct ListBase *listbase, void *vlink); +void BLI_remlink(struct ListBase *listbase, void *vlink); +void BLI_newname(char * name, int add); +int BLI_stringdec(char *string, char *kop, char *start, unsigned short *numlen); +void BLI_stringenc(char *string, char *kop, char *start, unsigned short numlen, int pic); +void BLI_addhead(struct ListBase *listbase, void *vlink); +void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink); +void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink); +void BLI_sortlist(struct ListBase *listbase, int (*cmp)(void *, void *)); +void BLI_freelist(struct ListBase *listbase); +int BLI_countlist(struct ListBase *listbase); +void BLI_freelinkN(ListBase *listbase, void *vlink); +void BLI_splitdirstring(char *di,char *fi); + +struct DynamicList *BLI_dlist_from_listbase(struct ListBase *lb); +struct ListBase *BLI_listbase_from_dlist(struct DynamicList *dlist, struct ListBase *lb); +void * BLI_dlist_find_link(struct DynamicList *dlist, unsigned int index); +unsigned int BLI_count_items(struct DynamicList *dlist); +void BLI_dlist_free_item(struct DynamicList *dlist, unsigned int index); +void BLI_dlist_rem_item(struct DynamicList *dlist, unsigned int index); +void * BLI_dlist_add_item_index(struct DynamicList *dlist, void *item, unsigned int index); +void BLI_dlist_destroy(struct DynamicList *dlist); +void BLI_dlist_init(struct DynamicList *dlist); +void BLI_dlist_reinit(struct DynamicList *dlist); + + /** + * dir can be any input, like from buttons, and this function + * converts it to a regular full path. + * Also removes garbage from directory paths, like /../ or double slashes etc + */ +void BLI_cleanup_dir(const char *relabase, char *dir); + + /** + * Blender's path code replacement function. + * Bases @a path strings leading with "//" by the + * directory @a basepath, and replaces instances of + * '#' with the @a framenum. Results are written + * back into @a path. + * + * @a path The path to convert + * @a basepath The directory to base relative paths with. + * @a framenum The framenumber to replace the frame code with. + * @retval Returns true if the path was relative (started with "//"). + */ +int BLI_convertstringcode(char *path, const char *basepath, int framenum); + +void BLI_makestringcode(const char *relfile, char *file); + + /** + * Change every @a from in @a string into @a to. The + * result will be in @a string + * + * @a string The string to work on + * @a from The character to replace + * @a to The character to replace with + */ +void BLI_char_switch(char *string, char from, char to); + + /** + * Makes sure @a path has platform-specific slashes. + * + * @a path The path to 'clean' + */ +void BLI_clean(char *path); + /** + * Duplicates the cstring @a str into a newly mallocN'd + * string and returns it. + * + * @param str The string to be duplicated + * @retval Returns the duplicated string + */ +char *BLI_strdup(const char *str); + + /** + * Duplicates the first @a len bytes of cstring @a str + * into a newly mallocN'd string and returns it. @a str + * is assumed to be at least len bytes long. + * + * @param str The string to be duplicated + * @param len The number of bytes to duplicate + * @retval Returns the duplicated string + */ +char *BLI_strdupn(const char *str, int len); + + /** + * Like strncpy but ensures dst is always + * '\0' terminated. + * + * @param dst Destination for copy + * @param src Source string to copy + * @param maxncpy Maximum number of characters to copy (generally + * the size of dst) + * @retval Returns dst + */ +char *BLI_strncpy(char *dst, const char *src, int maxncpy); + + /* + * Replacement for snprintf + */ +int BLI_snprintf(char *buffer, size_t count, const char *format, ...); + + /** + * Compare two strings + * + * @retval True if the strings are equal, false otherwise. + */ +int BLI_streq(char *a, char *b); + + /** + * Compare two strings without regard to case. + * + * @retval True if the strings are equal, false otherwise. + */ +int BLI_strcaseeq(char *a, char *b); + +/* in util.c */ +#ifdef WITH_ICONV +void BLI_string_to_utf8(char *original, char *utf_8, char *code); +#endif + + /** + * Read a file as ASCII lines. An empty list is + * returned if the file cannot be opened or read. + * + * @attention The returned list should be free'd with + * BLI_free_file_lines. + * + * @param name The name of the file to read. + * @retval A list of strings representing the file lines. + */ +struct LinkNode *BLI_read_file_as_lines(char *name); + + /** + * Free the list returned by BLI_read_file_as_lines. + */ +void BLI_free_file_lines(struct LinkNode *lines); + + /** + * Checks if name is a fully qualified filename to an executable. + * If not it searches $PATH for the file. On Windows it also + * adds the correct extension (.com .exe etc) from + * $PATHEXT if necessary. Also on Windows it translates + * the name to its 8.3 version to prevent problems with + * spaces and stuff. Final result is returned in fullname. + * + * @param fullname The full path and full name of the executable + * @param name The name of the executable (usually argv[0]) to be checked + */ +void BLI_where_am_i(char *fullname, char *name); + + /** + * determines the full path to the application bundle on OS X + * + * @return path to application bundle + */ +#ifdef __APPLE__ +char* BLI_getbundle(void); +#endif + +#ifdef WIN32 +int BLI_getInstallationDir(char *str); +#endif + +/* BLI_storage.h */ +int BLI_filesize(int file); +double BLI_diskfree(char *dir); +char *BLI_getwdN(char *dir); +void BLI_hide_dot_files(int set); +unsigned int BLI_getdir(char *dirname, struct direntry **filelist); + +/** + * @attention Do not confuse with BLI_exists + */ +int BLI_exist(char *name); + +/* BLI_fileops.h */ +void BLI_recurdir_fileops(char *dirname); +int BLI_link(char *file, char *to); +int BLI_backup(char *file, char *from, char *to); +int BLI_is_writable(char *filename); + +/** + * @attention Do not confuse with BLI_exist + */ +int BLI_exists(char *file); +int BLI_copy_fileops(char *file, char *to); +int BLI_rename(char *from, char *to); +int BLI_gzip(char *from, char *to); +int BLI_delete(char *file, int dir, int recursive); +int BLI_move(char *file, char *to); +int BLI_touch(char *file); +char *BLI_last_slash(char *string); + +/* BLI_rct.c */ +/** + * Determine if a rect is empty. An empty + * rect is one with a zero (or negative) + * width or height. + * + * @return True if @a rect is empty. + */ +int BLI_rcti_is_empty(struct rcti *rect); +void BLI_init_rctf(struct rctf *rect, float xmin, float xmax, float ymin, float ymax); +void BLI_init_rcti(struct rcti *rect, int xmin, int xmax, int ymin, int ymax); +void BLI_translate_rctf(struct rctf *rect, float x, float y); +void BLI_translate_rcti(struct rcti *rect, int x, int y); +int BLI_in_rcti(struct rcti *rect, int x, int y); +int BLI_in_rctf(struct rctf *rect, float x, float y); +int BLI_isect_rctf(struct rctf *src1, struct rctf *src2, struct rctf *dest); +int BLI_isect_rcti(struct rcti *src1, struct rcti *src2, struct rcti *dest); +void BLI_union_rctf(struct rctf *rcta, struct rctf *rctb); + +/* scanfill.c: used in displist only... */ +struct EditVert *BLI_addfillvert(float *vec); +struct EditEdge *BLI_addfilledge(struct EditVert *v1, struct EditVert *v2); +int BLI_edgefill(int mode, int mat_nr); +void BLI_end_edgefill(void); + +/* noise.h: */ +float BLI_hnoise(float noisesize, float x, float y, float z); +float BLI_hnoisep(float noisesize, float x, float y, float z); +float BLI_turbulence(float noisesize, float x, float y, float z, int nr); +float BLI_turbulence1(float noisesize, float x, float y, float z, int nr); +/* newnoise: generic noise & turbulence functions to replace the above BLI_hnoise/p & BLI_turbulence/1. + * This is done so different noise basis functions can be used */ +float BLI_gNoise(float noisesize, float x, float y, float z, int hard, int noisebasis); +float BLI_gTurbulence(float noisesize, float x, float y, float z, int oct, int hard, int noisebasis); +/* newnoise: musgrave functions */ +float mg_fBm(float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis); +float mg_MultiFractal(float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis); +float mg_VLNoise(float x, float y, float z, float distortion, int nbas1, int nbas2); +float mg_HeteroTerrain(float x, float y, float z, float H, float lacunarity, float octaves, float offset, int noisebasis); +float mg_HybridMultiFractal(float x, float y, float z, float H, float lacunarity, float octaves, float offset, float gain, int noisebasis); +float mg_RidgedMultiFractal(float x, float y, float z, float H, float lacunarity, float octaves, float offset, float gain, int noisebasis); +/* newnoise: voronoi */ +void voronoi(float x, float y, float z, float* da, float* pa, float me, int dtype); +/* newnoise: cellNoise & cellNoiseV (for vector/point/color) */ +float cellNoise(float x, float y, float z); +void cellNoiseV(float x, float y, float z, float *ca); + +/* These callbacks are needed to make the lib finction properly */ + +/** + * Set a function taking a char* as argument to flag errors. If the + * callback is not set, the error is discarded. + * @param f The function to use as callback + * @attention used in creator.c + */ +void BLI_setErrorCallBack(void (*f)(char*)); + +/** + * Set a function to be able to interrupt the execution of processing + * in this module. If the function returns true, the execution will + * terminate gracefully. If the callback is not set, interruption is + * not possible. + * @param f The function to use as callback + * @attention used in creator.c + */ +void BLI_setInterruptCallBack(int (*f)(void)); + +char *BLI_strcasestr(const char *s, const char *find); +int BLI_strcasecmp(const char *s1, const char *s2); +int BLI_strncasecmp(const char *s1, const char *s2, int n); +void BLI_timestr(double time, char *str); + +/** + * Trick to address 32 GB with an int (only for malloced pointers) + */ +int BLI_int_from_pointer(void *poin); +void *BLI_pointer_from_int(int val); + + +#define PRNTSUB(type,arg) printf(#arg ": %" #type " ", arg) + +#ifndef PRINT +#define PRINT(t,v) {PRNTSUB(t,v); printf("\n");} +#define PRINT2(t1,v1,t2,v2) {PRNTSUB(t1,v1); PRNTSUB(t2,v2); printf("\n");} +#define PRINT3(t1,v1,t2,v2,t3,v3) {PRNTSUB(t1,v1); PRNTSUB(t2,v2); PRNTSUB(t3,v3); printf("\n");} +#define PRINT4(t1,v1,t2,v2,t3,v3,t4,v4) {PRNTSUB(t1,v1); PRNTSUB(t2,v2); PRNTSUB(t3,v3); PRNTSUB(t4,v4); printf("\n");} +#endif + +/** + * @param array The array in question + * @retval The number of elements in the array. + */ +#define BLI_ARRAY_NELEMS(array) (sizeof((array))/sizeof((array)[0])) + +/** + * @param strct The structure of interest + * @param member The name of a member field of @a strct + * @retval The offset in bytes of @a member within @a strct + */ +#define BLI_STRUCT_OFFSET(strct, member) ((int) &((strct*) 0)->member) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/blender/blenlib/BLI_boxpack2d.h b/source/blender/blenlib/BLI_boxpack2d.h new file mode 100644 index 00000000000..b5cf9cd81e9 --- /dev/null +++ b/source/blender/blenlib/BLI_boxpack2d.h @@ -0,0 +1,69 @@ +/** + * + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + * The old math stuff from Ton. These will slowly phase out in favour + * of MTC calls. (or even MoTO :) ) + * */ + +/* Box Packer */ + +/* verts, internal use only */ +typedef struct boxVert { + float x; + float y; + short free; + + struct boxPack *trb; /* top right box */ + struct boxPack *blb; /* bottom left box */ + struct boxPack *brb; /* bottom right box */ + struct boxPack *tlb; /* top left box */ + + /* Store last intersecting boxes here + * speedup intersection testing */ + struct boxPack *isect_cache[4]; + + int index; +} boxVert; + +typedef struct boxPack { + float x; + float y; + float w; + float h; + int index; + + /* Verts this box uses + * (BL,TR,TL,BR) / 0,1,2,3 */ + boxVert *v[4]; +} boxPack; + +void boxPack2D(boxPack *boxarray, int len, float *tot_width, float *tot_height); + diff --git a/source/blender/blenlib/BLI_dynamiclist.h b/source/blender/blenlib/BLI_dynamiclist.h new file mode 100644 index 00000000000..89e27743054 --- /dev/null +++ b/source/blender/blenlib/BLI_dynamiclist.h @@ -0,0 +1,58 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributor(s): Jiri Hnidek. + * + * Documentation of Two way dynamic list with access array can be found at: + * + * http://wiki.blender.org/bin/view.pl/Blenderwiki/DynamicListWithAccessArray + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef B_DYNAMIC_LIST_H +#define B_DYNAMIC_LIST_H + +#define PAGE_SIZE 4 + +struct ListBase; + +/* + * Access array using realloc + */ +typedef struct DynamicArray{ + unsigned int count; /* count of items in list */ + unsigned int max_item_index; /* max available index */ + unsigned int last_item_index; /* max used index */ + void **items; /* dynamicaly allocated array of pointers + pointing at items in list */ +} DynamicArray; + +/* + * Two way dynamic list with access array + */ +typedef struct DynamicList { + struct DynamicArray da; /* access array */ + struct ListBase lb; /* two way linked dynamic list */ +} DynamicList; + +#endif diff --git a/source/blender/blenlib/BLI_dynstr.h b/source/blender/blenlib/BLI_dynstr.h new file mode 100644 index 00000000000..7e8cc140964 --- /dev/null +++ b/source/blender/blenlib/BLI_dynstr.h @@ -0,0 +1,90 @@ +/** + * @file BLI_dynstr.h + * + * A dynamically sized string ADT. + * This ADT is designed purely for dynamic string creation + * through appending, not for general usage, the intent is + * to build up dynamic strings using a DynStr object, then + * convert it to a c-string and work with that. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BLI_DYNSTR_H +#define BLI_DYNSTR_H + +struct DynStr; + + /** The abstract DynStr type */ +typedef struct DynStr DynStr; + + /** + * Create a new DynStr. + * + * @return Pointer to a new DynStr. + */ +DynStr* BLI_dynstr_new (void); + + /** + * Append a c-string to a DynStr. + * + * @param ds The DynStr to append to. + * @param cstr The c-string to append. + */ +void BLI_dynstr_append (DynStr *ds, char *cstr); + + /** + * Find the length of a DynStr. + * + * @param ds The DynStr of interest. + * @return The length of @a ds. + */ +int BLI_dynstr_get_len (DynStr *ds); + + /** + * Get a DynStr's contents as a c-string. + * The returned c-string should be free'd + * using BLI_freeN. + * + * @param ds The DynStr of interest. + * @return The contents of @a ds as a c-string. + */ +char* BLI_dynstr_get_cstring (DynStr *ds); + + /** + * Free the DynStr + * + * @param ds The DynStr to free. + */ +void BLI_dynstr_free (DynStr *ds); + +#endif + diff --git a/source/blender/blenlib/BLI_edgehash.h b/source/blender/blenlib/BLI_edgehash.h new file mode 100644 index 00000000000..6b7eaedea2f --- /dev/null +++ b/source/blender/blenlib/BLI_edgehash.h @@ -0,0 +1,99 @@ +/** + * A general unordered 2-int pair hash table ADT + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: none of this file. + * + * Contributor(s): Daniel Dunbar + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BLI_EDGEHASH_H +#define BLI_EDGEHASH_H + +struct EdgeHash; +struct EdgeHashIterator; +typedef struct EdgeHash EdgeHash; +typedef struct EdgeHashIterator EdgeHashIterator; + +typedef void (*EdgeHashFreeFP)(void *key); + +EdgeHash* BLI_edgehash_new (void); +void BLI_edgehash_free (EdgeHash *eh, EdgeHashFreeFP valfreefp); + + /* Insert edge (v0,v1) into hash with given value, does + * not check for duplicates. + */ +void BLI_edgehash_insert (EdgeHash *eh, int v0, int v1, void *val); + + /* Return value for given edge (v0,v1), or NULL if + * if key does not exist in hash. (If need exists + * to differentiate between key-value being NULL and + * lack of key then see BLI_edgehash_lookup_p(). + */ +void* BLI_edgehash_lookup (EdgeHash *eh, int v0, int v1); + + /* Return pointer to value for given edge (v0,v1), + * or NULL if key does not exist in hash. + */ +void** BLI_edgehash_lookup_p (EdgeHash *eh, int v0, int v1); + + /* Return boolean true/false if edge (v0,v1) in hash. */ +int BLI_edgehash_haskey (EdgeHash *eh, int v0, int v1); + + /* Return number of keys in hash. */ +int BLI_edgehash_size (EdgeHash *eh); + + /* Remove all edges from hash. */ +void BLI_edgehash_clear (EdgeHash *eh, EdgeHashFreeFP valfreefp); + +/***/ + + /** + * Create a new EdgeHashIterator. The hash table must not be mutated + * while the iterator is in use, and the iterator will step exactly + * BLI_edgehash_size(gh) times before becoming done. + */ +EdgeHashIterator* BLI_edgehashIterator_new (EdgeHash *eh); + + /* Free an EdgeHashIterator. */ +void BLI_edgehashIterator_free (EdgeHashIterator *ehi); + + /* Retrieve the key from an iterator. */ +void BLI_edgehashIterator_getKey (EdgeHashIterator *ehi, int *v0_r, int *v1_r); + + /* Retrieve the value from an iterator. */ +void* BLI_edgehashIterator_getValue (EdgeHashIterator *ehi); + + /* Steps the iterator to the next index. */ +void BLI_edgehashIterator_step (EdgeHashIterator *ehi); + + /* Determine if an iterator is done. */ +int BLI_edgehashIterator_isDone (EdgeHashIterator *ehi); + +#endif + diff --git a/source/blender/blenlib/BLI_editVert.h b/source/blender/blenlib/BLI_editVert.h new file mode 100644 index 00000000000..795f6781894 --- /dev/null +++ b/source/blender/blenlib/BLI_editVert.h @@ -0,0 +1,190 @@ +/** + * blenlib/BLI_editVert.h mar 2001 Nzc + * + * Some editing types needed in the lib (unfortunately) for + * scanfill.c + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BLI_EDITVERT_H +#define BLI_EDITVERT_H + +#include "DNA_customdata_types.h" +#include "DNA_mesh_types.h" + +struct DerivedMesh; +struct RetopoPaintData; + +/* note; changing this also might affect the undo copy in editmesh.c */ +typedef struct EditVert +{ + struct EditVert *next, *prev; + union { + /* some lean storage for temporary usage + * in editmesh routines + */ + struct EditVert *v; + struct EditEdge *e; + struct EditFace *f; + void *p; + long l; + float fp; + } tmp; + float no[3]; /*vertex normal */ + float co[3]; /*vertex location */ + short xs, ys; /* used to store a screenspace 2d projection of the verts */ + + /* f stores selection eg. if (eve->f & SELECT) {... + h for hidden. if (!eve->h) {... + f1 and f2 can be used for temp data, clear them first*/ + unsigned char f, h, f1, f2; + short fast; /* only 0 or 1, for editmesh_fastmalloc, do not store temp data here! */ + int hash; + int keyindex; /* original index #, for restoring key information */ +/*#ifdef WITH_VERSE*/ + void *vvert; +/*#endif*/ + + void *data; /* custom vertex data */ +} EditVert; + +struct EditEdge; + +typedef struct HashEdge { + struct EditEdge *eed; + struct HashEdge *next; +} HashEdge; + +/* note; changing this also might affect the undo copy in editmesh.c */ +typedef struct EditEdge +{ + struct EditEdge *next, *prev; + struct EditVert *v1, *v2; + union { + /* some lean storage for temporary usage + * in editmesh routines + */ + struct EditVert *v; + struct EditEdge *e; + struct EditFace *f; + void *p; + long l; + float fp; + } tmp; + short f1, f2; /* short, f1 is (ab)used in subdiv */ + unsigned char f, h, dir, seam, sharp; + float crease; + short fast; /* only 0 or 1, for editmesh_fastmalloc */ + short fgoni; /* index for fgon, for search */ + HashEdge hash; + void *data; /*custom edge data*/ +} EditEdge; + +/* note; changing this also might affect the undo copy in editmesh.c */ +typedef struct EditFace +{ + struct EditFace *next, *prev; + struct EditVert *v1, *v2, *v3, *v4; + struct EditEdge *e1, *e2, *e3, *e4; + union { + /* some lean storage for temporary usage + * in editmesh routines + */ + struct EditVert *v; + struct EditEdge *e; + struct EditFace *f; + void *p; + long l; + float fp; + } tmp; + float n[3], cent[3]; + unsigned char mat_nr, flag; + unsigned char f, f1, h; + unsigned char fast; /* only 0 or 1, for editmesh_fastmalloc */ + unsigned char fgonf; /* flag for fgon options */ +/*#ifdef WITH_VERSE*/ + void *vface; +/*#endif*/ + void *data; /* custom face data */ +} EditFace; + + +/*selection types*/ +#define EDITVERT 0 +#define EDITEDGE 1 +#define EDITFACE 2 + +typedef struct EditSelection +{ + struct EditSelection *next, *prev; + short type; + void *data; +} EditSelection; + + +typedef struct EditMesh +{ + ListBase verts, edges, faces; + ListBase selected; /*EditSelections. Used to store the order in which things are selected.*/ + HashEdge *hashedgetab; + + /* this is for the editmesh_fastmalloc */ + EditVert *allverts, *curvert; + EditEdge *alledges, *curedge; + EditFace *allfaces, *curface; + /* DerivedMesh caches... note that derived cage can be equivalent + * to derived final, care should be taken on release. + */ + + /* used for keeping track of the last clicked on face - so the space image + * when using the last selected face - (EditSelection) the space image flickered too much + * + * never access this directly, use EM_set_actFace and EM_get_actFace */ + EditFace *act_face; + + struct DerivedMesh *derivedCage, *derivedFinal; + /* the custom data layer mask that was last used to calculate + * derivedCage and derivedFinal + */ + int lastDataMask; + + struct RetopoPaintData *retopo_paint_data; + + CustomData vdata, edata, fdata; + +#ifdef WITH_VERSE + void *vnode; +#endif +} EditMesh; + +#endif + diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h new file mode 100644 index 00000000000..ce5be5fc311 --- /dev/null +++ b/source/blender/blenlib/BLI_ghash.h @@ -0,0 +1,118 @@ +/** + * A general (pointer -> pointer) hash table ADT + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BLI_GHASH_H +#define BLI_GHASH_H + +struct GHash; +typedef struct GHash GHash; +typedef struct GHashIterator GHashIterator; + +typedef unsigned int (*GHashHashFP) (void *key); +typedef int (*GHashCmpFP) (void *a, void *b); +typedef void (*GHashKeyFreeFP) (void *key); +typedef void (*GHashValFreeFP) (void *val); + +GHash* BLI_ghash_new (GHashHashFP hashfp, GHashCmpFP cmpfp); +void BLI_ghash_free (GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp); + +void BLI_ghash_insert (GHash *gh, void *key, void *val); +int BLI_ghash_remove (GHash *gh, void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp); +void* BLI_ghash_lookup (GHash *gh, void *key); +int BLI_ghash_haskey (GHash *gh, void *key); + +int BLI_ghash_size (GHash *gh); + +/* *** */ + + /** + * Create a new GHashIterator. The hash table must not be mutated + * while the iterator is in use, and the iterator will step exactly + * BLI_ghash_size(gh) times before becoming done. + * + * @param gh The GHash to iterate over. + * @return Pointer to a new DynStr. + */ +GHashIterator* BLI_ghashIterator_new (GHash *gh); + /** + * Free a GHashIterator. + * + * @param ghi The iterator to free. + */ +void BLI_ghashIterator_free (GHashIterator *ghi); + + /** + * Retrieve the key from an iterator. + * + * @param ghi The iterator. + * @return The key at the current index, or NULL if the + * iterator is done. + */ +void* BLI_ghashIterator_getKey (GHashIterator *ghi); + /** + * Retrieve the value from an iterator. + * + * @param ghi The iterator. + * @return The value at the current index, or NULL if the + * iterator is done. + */ +void* BLI_ghashIterator_getValue (GHashIterator *ghi); + /** + * Steps the iterator to the next index. + * + * @param ghi The iterator. + */ +void BLI_ghashIterator_step (GHashIterator *ghi); + /** + * Determine if an iterator is done (has reached the end of + * the hash table). + * + * @param ghi The iterator. + * @return True if done, False otherwise. + */ +int BLI_ghashIterator_isDone (GHashIterator *ghi); + +/* *** */ + +unsigned int BLI_ghashutil_ptrhash (void *key); +int BLI_ghashutil_ptrcmp (void *a, void *b); + +unsigned int BLI_ghashutil_strhash (void *key); +int BLI_ghashutil_strcmp (void *a, void *b); + +unsigned int BLI_ghashutil_inthash (void *ptr); +int BLI_ghashutil_intcmp(void *a, void *b); + +#endif + diff --git a/source/blender/blenlib/BLI_gsqueue.h b/source/blender/blenlib/BLI_gsqueue.h new file mode 100644 index 00000000000..5180d3d8bbc --- /dev/null +++ b/source/blender/blenlib/BLI_gsqueue.h @@ -0,0 +1,96 @@ +/* + * A generic structure queue (a queue for fixed length + * (generally small) structures. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BLI_GSQUEUE_H +#define BLI_GSQUEUE_H + +typedef struct _GSQueue GSQueue; + + /** + * Create a new GSQueue. + * + * @param elem_size The size of the structures in the queue. + * @retval The new queue + */ +GSQueue* BLI_gsqueue_new (int elem_size); + + /** + * Query if the queue is empty + */ +int BLI_gsqueue_is_empty(GSQueue *gq); + + /** + * Access the item at the head of the queue + * without removing it. + * + * @param item_r A pointer to an appropriatly + * sized structure (the size passed to BLI_gsqueue_new) + */ +void BLI_gsqueue_peek (GSQueue *gq, void *item_r); + + /** + * Access the item at the head of the queue + * and remove it. + * + * @param item_r A pointer to an appropriatly + * sized structure (the size passed to BLI_gsqueue_new). + * Can be NULL if desired. + */ +void BLI_gsqueue_pop (GSQueue *gq, void *item_r); + + /** + * Push an element onto the tail of the queue. + * + * @param item A pointer to an appropriatly + * sized structure (the size passed to BLI_gsqueue_new). + */ +void BLI_gsqueue_push (GSQueue *gq, void *item); + + /** + * Push an element back onto the head of the queue (so + * it would be returned from the next call to BLI_gsqueue_pop). + * + * @param item A pointer to an appropriatly + * sized structure (the size passed to BLI_gsqueue_new). + */ +void BLI_gsqueue_pushback (GSQueue *gq, void *item); + + /** + * Free the queue + */ +void BLI_gsqueue_free (GSQueue *gq); + +#endif /* BLI_GSQUEUE_H */ + diff --git a/source/blender/blenlib/BLI_heap.h b/source/blender/blenlib/BLI_heap.h new file mode 100644 index 00000000000..8ebb6ad269f --- /dev/null +++ b/source/blender/blenlib/BLI_heap.h @@ -0,0 +1,74 @@ +/** + * A heap / priority queue ADT + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: none of this file. + * + * Contributor(s): Brecht Van Lommel + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BLI_HEAP_H +#define BLI_HEAP_H + +struct Heap; +struct HeapNode; +typedef struct Heap Heap; +typedef struct HeapNode HeapNode; + +typedef void (*HeapFreeFP)(void *ptr); + +/* Creates a new heap. BLI_memarena is used for allocating nodes. Removed nodes + are recycled, so memory usage will not shrink. */ +Heap* BLI_heap_new (void); +void BLI_heap_free (Heap *heap, HeapFreeFP ptrfreefp); + +/* Insert heap node with a value (often a 'cost') and pointer into the heap, + duplicate values are allowed. */ +HeapNode* BLI_heap_insert (Heap *heap, float value, void *ptr); + +/* Remove a heap node. */ +void BLI_heap_remove (Heap *heap, HeapNode *node); + +/* Return 0 if the heap is empty, 1 otherwise. */ +int BLI_heap_empty (Heap *heap); + +/* Return the size of the heap. */ +int BLI_heap_size (Heap *heap); + +/* Return the top node of the heap. This is the node with the lowest value. */ +HeapNode* BLI_heap_top (Heap *heap); + +/* Pop the top node off the heap and return it's pointer. */ +void* BLI_heap_popmin (Heap *heap); + +/* Return the value or pointer of a heap node. */ +float BLI_heap_node_value (HeapNode *heap); +void* BLI_heap_node_ptr (HeapNode *heap); + +#endif + diff --git a/source/blender/blenlib/BLI_jitter.h b/source/blender/blenlib/BLI_jitter.h new file mode 100644 index 00000000000..1cd4880d0b7 --- /dev/null +++ b/source/blender/blenlib/BLI_jitter.h @@ -0,0 +1,40 @@ +/* + * jitter.h + * + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BLI_JITTER_H +#define BLI_JITTER_H + +extern void BLI_initjit(float *jitarr, int num); +extern void BLI_jitterate1(float *jit1, float *jit2, int num, float rad1); +extern void BLI_jitterate2(float *jit1, float *jit2, int num, float rad2); + +#endif + diff --git a/source/blender/blenlib/BLI_linklist.h b/source/blender/blenlib/BLI_linklist.h new file mode 100644 index 00000000000..9982047ec9e --- /dev/null +++ b/source/blender/blenlib/BLI_linklist.h @@ -0,0 +1,62 @@ +/* + * Routines for working with singly linked lists + * of 'links' - pointers to other data. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BLI_LINKLIST_H +#define BLI_LINKLIST_H + +struct MemArena; + +typedef void (*LinkNodeFreeFP)(void *link); +typedef void (*LinkNodeApplyFP)(void *link, void *userdata); + +struct LinkNode; +typedef struct LinkNode { + struct LinkNode *next; + void *link; +} LinkNode; + +int BLI_linklist_length (struct LinkNode *list); + +void BLI_linklist_reverse (struct LinkNode **listp); + +void BLI_linklist_prepend (struct LinkNode **listp, void *ptr); +void BLI_linklist_append (struct LinkNode **listp, void *ptr); +void BLI_linklist_prepend_arena (struct LinkNode **listp, void *ptr, struct MemArena *ma); + +void BLI_linklist_free (struct LinkNode *list, LinkNodeFreeFP freefunc); +void BLI_linklist_apply (struct LinkNode *list, LinkNodeApplyFP applyfunc, void *userdata); + +#endif + diff --git a/source/blender/blenlib/BLI_memarena.h b/source/blender/blenlib/BLI_memarena.h new file mode 100644 index 00000000000..420995e3b11 --- /dev/null +++ b/source/blender/blenlib/BLI_memarena.h @@ -0,0 +1,61 @@ +/* + * Memory arena ADT + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + * Memory arena's are commonly used when the program + * needs to quickly allocate lots of little bits of + * data, which are all freed at the same moment. + * + */ + +#ifndef BLI_MEMARENA_H +#define BLI_MEMARENA_H + + /* A reasonable standard buffer size, big + * enough to not cause much internal fragmentation, + * small enough not to waste resources + */ +#define BLI_MEMARENA_STD_BUFSIZE (1<<14) + +struct MemArena; +typedef struct MemArena MemArena; + + +struct MemArena* BLI_memarena_new (int bufsize); +void BLI_memarena_free (struct MemArena *ma); + +void BLI_memarena_use_calloc (struct MemArena *ma); + +void* BLI_memarena_alloc (struct MemArena *ma, int size); + +#endif + diff --git a/source/blender/blenlib/BLI_rand.h b/source/blender/blenlib/BLI_rand.h new file mode 100644 index 00000000000..da2ecb79651 --- /dev/null +++ b/source/blender/blenlib/BLI_rand.h @@ -0,0 +1,99 @@ +/** + * @file BLI_rand.h + * + * Random number functions. + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BLI_RAND_H +#define BLI_RAND_H + + /* RNG is just an abstract random number generator + * type that avoids using globals, otherwise identical + * to BLI_rand functions below. + */ +struct RNG; +typedef struct RNG RNG; + +struct RNG* rng_new (unsigned int seed); +void rng_free (struct RNG* rng); + +void rng_seed (struct RNG* rng, unsigned int seed); +int rng_getInt (struct RNG* rng); +double rng_getDouble (struct RNG* rng); +float rng_getFloat (struct RNG* rng); +void rng_shuffleArray(struct RNG *rng, void *data, int elemSize, int numElems); + + /** Seed the random number generator */ +void BLI_srand (unsigned int seed); + + /** Better seed for the random number generator, using noise.c hash[] */ +void BLI_srandom (unsigned int seed); + + /** Return a pseudo-random number N where 0<=N<(2^31) */ +int BLI_rand (void); + + /** Return a pseudo-random number N where 0.0<=N<1.0 */ +double BLI_drand (void); + + /** Return a pseudo-random number N where 0.0f<=N<1.0f */ +float BLI_frand (void); + + /** Fills a block of memory starting at @a addr + * and extending @a len bytes with pseudo-random + * contents. This routine does not use nor modify + * the state of the BLI random number generator. + */ +void BLI_fillrand (void *addr, int len); + + /** Shuffle an array randomly using the given seed. + * contents. This routine does not use nor modify + * the state of the BLI random number generator. + */ +void BLI_array_randomize (void *data, int elemSize, int numElems, unsigned int seed); + + + /** Better seed for the random number generator, using noise.c hash[] */ + /** Allows up to 16 threads to address */ +void BLI_thread_srandom (int thread, unsigned int seed); + + /** Return a pseudo-random number N where 0<=N<(2^31) */ + /** Allows up to 16 threads to address */ +int BLI_thread_rand (int thread); + + /** Return a pseudo-random number N where 0.0f<=N<1.0f */ + /** Allows up to 16 threads to address */ +float BLI_thread_frand (int thread); + + + +#endif + diff --git a/source/blender/blenlib/BLI_storage_types.h b/source/blender/blenlib/BLI_storage_types.h new file mode 100644 index 00000000000..ebce33852a1 --- /dev/null +++ b/source/blender/blenlib/BLI_storage_types.h @@ -0,0 +1,83 @@ +/** + * blenlib/BLI_storage_types.h + * + * Some types for dealing with directories + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BLI_STORAGE_TYPES_H +#define BLI_STORAGE_TYPES_H + +#include + +#define HDRSIZE 512 +#define NAMSIZE 200 + +struct header{ + char name[NAMSIZE]; + unsigned int size; + unsigned int chksum; + char fill[HDRSIZE-NAMSIZE-2*sizeof(unsigned int)]; +}; + +#if defined(WIN32) && !defined(FREE_WINDOWS) +typedef unsigned int mode_t; +#endif + +struct ImBuf; + +struct direntry{ + char *string; + mode_t type; + char *relname; + struct stat s; + unsigned int flags; + char size[16]; + char mode1[4]; + char mode2[4]; + char mode3[4]; + char owner[16]; + char time[8]; + char date[16]; + char extra[16]; + void *poin; + int nr; + struct ImBuf *image; +}; + +struct dirlink +{ + struct dirlink *next,*prev; + char *name; +}; + +#endif /* BLI_STORAGE_TYPES_H */ + diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h new file mode 100644 index 00000000000..60ecce3f9d8 --- /dev/null +++ b/source/blender/blenlib/BLI_threads.h @@ -0,0 +1,54 @@ +/* + * + * $Id: + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BLI_THREADS_H +#define BLI_THREADS_H + +/* one custom lock available now. can be extended */ +#define LOCK_IMAGE 0 +#define LOCK_CUSTOM1 1 + +/* for tables, button in UI, etc */ +#define BLENDER_MAX_THREADS 8 + +struct ListBase; + +void BLI_init_threads (struct ListBase *threadbase, void *(*do_thread)(void *), int tot); +int BLI_available_threads(struct ListBase *threadbase); +int BLI_available_thread_index(struct ListBase *threadbase); +void BLI_insert_thread (struct ListBase *threadbase, void *callerdata); +void BLI_remove_thread (struct ListBase *threadbase, void *callerdata); +void BLI_end_threads (struct ListBase *threadbase); + +void BLI_lock_thread (int type); +void BLI_unlock_thread (int type); + +#endif + diff --git a/source/blender/blenlib/BLI_vfontdata.h b/source/blender/blenlib/BLI_vfontdata.h new file mode 100644 index 00000000000..ce800111afb --- /dev/null +++ b/source/blender/blenlib/BLI_vfontdata.h @@ -0,0 +1,103 @@ +/** + * @file BLI_vfontdata.h + * + * A structure to represent vector fonts, + * and to load them from PostScript fonts. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BLI_VFONTDATA_H +#define BLI_VFONTDATA_H + +#include "DNA_listBase.h" + +struct PackedFile; +struct VFont; + +#define MAX_VF_CHARS 256 + +typedef struct VFontData { + ListBase characters; + // ListBase nurbsbase[MAX_VF_CHARS]; + // float resol[MAX_VF_CHARS]; + // float width[MAX_VF_CHARS]; + // float *points[MAX_VF_CHARS]; + char name[128]; +} VFontData; + +typedef struct VChar { + struct VChar *next, *prev; + ListBase nurbsbase; + unsigned long index; + float resol; + float width; + float *points; +} VChar; + +struct TmpFont +{ + struct TmpFont *next, *prev; + struct PackedFile *pf; + struct VFont *vfont; +}; + + +/** + * Construct a new VFontData structure from + * PostScript font data in a PackedFile. + * + * @param pf The font data. + * @retval A new VFontData structure, or NULL + * if unable to load. + */ + VFontData* +BLI_vfontdata_from_psfont( + struct PackedFile *pf); + +/** + * Construct a new VFontData structure from + * Freetype font data in a PackedFile. + * + * @param pf The font data. + * @retval A new VFontData structure, or NULL + * if unable to load. + */ + VFontData* +BLI_vfontdata_from_freetypefont( + struct PackedFile *pf); + + int +BLI_vfontchar_from_freetypefont( + struct VFont *vfont, unsigned long character); + +#endif + diff --git a/source/blender/blenlib/BLI_winstuff.h b/source/blender/blenlib/BLI_winstuff.h new file mode 100644 index 00000000000..0f39d37c31f --- /dev/null +++ b/source/blender/blenlib/BLI_winstuff.h @@ -0,0 +1,119 @@ +/** + * Compatibility-like things for windows. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#pragma warning(once: 4761 4305 4244 4018) + +#define WIN32_LEAN_AND_MEAN + +#ifndef WIN32_SKIP_HKEY_PROTECTION +#define HKEY WIN32_HKEY // prevent competing definitions +#include +#undef HKEY +#else +#include +#endif + +#undef near +#undef far +#undef rad +#undef rad1 +#undef rad2 +#undef rad3 +#undef vec +#undef rect +#undef rct1 +#undef rct2 + +#define near clipsta +#define far clipend + +#undef small + +#ifndef __WINSTUFF_H__ +#define __WINSTUFF_H__ + + // These definitions are also in arithb for simplicity + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif +#ifndef M_PI_2 +#define M_PI_2 1.57079632679489661923 +#endif +#ifndef M_SQRT2 +#define M_SQRT2 1.41421356237309504880 +#endif +#ifndef M_SQRT1_2 +#define M_SQRT1_2 0.70710678118654752440 +#endif + +#define MAXPATHLEN MAX_PATH + +#ifndef S_ISREG +#define S_ISREG(x) ((x&S_IFMT) == S_IFREG) +#endif +#ifndef S_ISDIR +#define S_ISDIR(x) ((x&S_IFMT) == S_IFDIR) +#endif + +#ifndef FREE_WINDOWS +typedef unsigned int mode_t; +#endif + +struct dirent { + int d_ino; + int d_off; + unsigned short d_reclen; + char *d_name; +}; + +typedef struct _DIR { + HANDLE handle; + WIN32_FIND_DATA data; + char path[MAX_PATH]; + long dd_loc; + long dd_size; + char dd_buf[4096]; + void *dd_direct; + + struct dirent direntry; +} DIR; + +void RegisterBlendExtension(char * str); +DIR *opendir (const char *path); +struct dirent *readdir(DIR *dp); +int closedir (DIR *dp); +void get_default_root(char* root); + +#endif /* __WINSTUFF_H__ */ + diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt new file mode 100644 index 00000000000..4812cad033d --- /dev/null +++ b/source/blender/blenlib/CMakeLists.txt @@ -0,0 +1,56 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +FILE(GLOB SRC intern/*.c) + +SET(INC + . ../makesdna ../blenkernel ../../../intern/guardedalloc ../include + ${FREETYPE_INC} + ${SDL_INC} + ${ZLIB_INC} +) + +IF(WITH_VERSE) + ADD_DEFINITIONS(-DWITH_VERSE) + SET(INC ${INC} ${VERSE_INC}) +ENDIF(WITH_VERSE) + +IF(WITH_INTERNATIONAL) + ADD_DEFINITIONS(-DWITH_FREETYPE2) +ENDIF(WITH_INTERNATIONAL) + +IF(WIN32) + SET(INC ${INC} ${PTHREADS_INC}) +ENDIF(WIN32) + +BLENDERLIB(bf_blenlib "${SRC}" "${INC}") +#if env['OURPLATFORM'] == 'linux2': +# cflags='-pthread' +# +#env.BlenderLib ( 'bf_blenlib', sources, Split(incs), Split(defs), libtype=['core','player'], priority = [85,195], compileflags =cflags ) diff --git a/source/blender/blenlib/MTC_matrixops.h b/source/blender/blenlib/MTC_matrixops.h new file mode 100644 index 00000000000..27b5bb1ca95 --- /dev/null +++ b/source/blender/blenlib/MTC_matrixops.h @@ -0,0 +1,165 @@ +/* + * matrixops.h + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef MATRIXOPS_H +#define MATRIXOPS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------------------------------------------------------------- */ +/* need rewriting: */ +/** + * copy the left upp3 3 by 3 of m2 to m1 + */ +void MTC_Mat3CpyMat4(float m1[][3], float m2[][4]); + +/* ------------------------------------------------------------------------- */ +/* operations based on 4 by 4 matrices */ + +/** + * Copy m1 to m2 + */ +void MTC_Mat4CpyMat4(float m1[][4], float m2[][4]); + +/** + * Multiply all matrices after the first, leave the result in the + * first argument + */ +void MTC_Mat4MulSerie(float answ[][4], + float m1[][4], float m2[][4], float m3[][4], + float m4[][4], float m5[][4], float m6[][4], + float m7[][4], float m8[][4]); + +/** + * m1 = m2 matprod m3 + */ +void MTC_Mat4MulMat4(float m1[][4], float m2[][4], float m3[][4]); + +/** + * Do vec^t prod mat, result in vec. Ignore vec[3] (vec is a + * float[3]) + */ +void MTC_Mat4MulVecfl(float mat[][4], float *vec); + +/** + * Invert mat, result in inverse. Always returns 1 + */ +int MTC_Mat4Invert(float inverse[][4], float mat[][4]); + +/** + * Make the set of mat orthonormal (mat should already be orthogonal)? + * (doesn't appear to normalize properly?) + */ +void MTC_Mat4Ortho(float mat[][4]); + +/** + * vec = mat prod vec, result in vec, ignore fourth component entirely + * (4th component is _not_ accessed!!! vec is 3d) + */ +void MTC_Mat4Mul3Vecfl(float mat[][4], float *vec); + +/** + * vec = mat prod vec, result in vec + */ +void MTC_Mat4MulVec4fl(float mat[][4], float *vec); + +/** + * Set to the 4-D unity matrix + */ +void MTC_Mat4One(float m[][4]); + +/** + * Swap matrices m1 and m2 + */ +void MTC_Mat4SwapMat4(float m1[][4], float m2[][4]); + +/** + * Copy m2 to the top-left 3x3 of m1, don't touch the remaining elements. + */ +void MTC_Mat4CpyMat3nc(float m1[][4], float m2[][3]); + +/** + * m1 = m2 * m3, but only the top-left 3x3 + */ +void MTC_Mat4MulMat33(float m1[][3], float m2[][4], float m3[][3]); + +/* ------------------------------------------------------------------------- */ +/* Operations based on 3 by 3 matrices */ +/** + * Do vec^t prod mat, result in vec.(vex is 3d) + */ +void MTC_Mat3MulVecfl(float mat[][3], float *vec); + +/** + * Copy m1 to m2 + */ +void MTC_Mat3CpyMat3(float m1[][3], float m2[][3]); + +/** + * m1 = m2 prod m3 + */ +void MTC_Mat3MulMat3(float m1[][3], float m3[][3], float m2[][3]); + +/** + * vec = vec prod mat + */ +void MTC_Mat3MulVecd(float mat[][3], double *vec); + +/** + * Guess: invert matrix + * result goes to m1 + */ +void MTC_Mat3Inv(float m1[][3], float m2[][3]); + +/** + * Sort of a determinant matrix? Doesn't seem very adjoint to me... + * result goes to m1 + */ +void MTC_Mat3Adj(float m1[][3], float m[][3]); + +/** + * Set to the 3D unity matrix + */ +void MTC_Mat3One(float m[][3]); + +/* ------------------------------------------------------------------------- */ + +#ifdef __cplusplus +} +#endif + +#endif /* MATRIXOPS_H */ + diff --git a/source/blender/blenlib/MTC_vectorops.h b/source/blender/blenlib/MTC_vectorops.h new file mode 100644 index 00000000000..64b2c312eb4 --- /dev/null +++ b/source/blender/blenlib/MTC_vectorops.h @@ -0,0 +1,61 @@ +/* + * vectorops.h + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef VECTOROPS_H +#define VECTOROPS_H + +/* ------------------------------------------------------------------------- */ + +void MTC_diff3Int(int v1[3], int v2[3], int v3[3]); +void MTC_cross3Int(int v1[3], int v2[3], int v3[3]); +int MTC_dot3Int(int v1[3], int v2[3]); + +void MTC_diff3Float(float v1[3], float v2[3], float v3[3]); +void MTC_cross3Float(float v1[3], float v2[3], float v3[3]); +float MTC_dot3Float(float v1[3], float v2[3]); +void MTC_cp3Float(float v1[3], float v2[3]); +/** + * Copy vector with a minus sign (so a = -b) + */ +void MTC_cp3FloatInv(float v1[3], float v2[3]); + +void MTC_swapInt(int *i1, int *i2); + +void MTC_diff3DFF(double v1[3], float v2[3], float v3[3]); +void MTC_cross3Double(double v1[3], double v2[3], double v3[3]); +float MTC_normalize3DF(float n[3]); + +/* ------------------------------------------------------------------------- */ +#endif /* VECTOROPS_H */ + diff --git a/source/blender/blenlib/Makefile b/source/blender/blenlib/Makefile new file mode 100644 index 00000000000..12ee8c5ad8c --- /dev/null +++ b/source/blender/blenlib/Makefile @@ -0,0 +1,37 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# Bounces make to subdirectories. + +SOURCEDIR = source/blender/blenlib +DIRS = intern + +include nan_subdirs.mk diff --git a/source/blender/blenlib/PIL_dynlib.h b/source/blender/blenlib/PIL_dynlib.h new file mode 100644 index 00000000000..26e1b2f9ac4 --- /dev/null +++ b/source/blender/blenlib/PIL_dynlib.h @@ -0,0 +1,55 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef __PIL_DYNLIB_H__ +#define __PIL_DYNLIB_H__ + +typedef struct PILdynlib PILdynlib; + + PILdynlib* +PIL_dynlib_open( + char *name); + + void* +PIL_dynlib_find_symbol( + PILdynlib* lib, + char *symname); + + char* +PIL_dynlib_get_error_as_string( + PILdynlib* lib); + + void +PIL_dynlib_close( + PILdynlib* lib); + +#endif /* __PIL_DYNLIB_H__ */ + diff --git a/source/blender/blenlib/PIL_time.h b/source/blender/blenlib/PIL_time.h new file mode 100644 index 00000000000..190a116d658 --- /dev/null +++ b/source/blender/blenlib/PIL_time.h @@ -0,0 +1,62 @@ +/** + * @file PIL_time.h + * + * Platform independant time functions. + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef PIL_TIME_H +#define PIL_TIME_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern + /** Return an indication of time, expressed as + * seconds since some fixed point. Successive calls + * are guarenteed to generate values greator than or + * equal to the last call. + */ +double PIL_check_seconds_timer (void); + + /** + * Platform-independant sleep function. + * @param ms Number of milliseconds to sleep + */ +void PIL_sleep_ms (int ms); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/source/blender/blenlib/SConscript b/source/blender/blenlib/SConscript new file mode 100644 index 00000000000..e11934d968e --- /dev/null +++ b/source/blender/blenlib/SConscript @@ -0,0 +1,26 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.c') + +cflags='' +incs = '. ../makesdna ../blenkernel #/intern/guardedalloc ../include' +incs += ' ' + env['BF_FREETYPE_INC'] +incs += ' ' + env['BF_ZLIB_INC'] +incs += ' ' + env['BF_SDL_INC'] +defs = '' + +if env['WITH_BF_INTERNATIONAL'] == 1: + defs = 'WITH_FREETYPE2' + +if env['WITH_BF_VERSE']: + defs += ' WITH_VERSE' + incs += ' ' + env['BF_VERSE_INCLUDE'] + +if env['OURPLATFORM'] == 'linux2': + cflags='-pthread' + +if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw'): + incs += ' ' + env['BF_PTHREADS_INC'] + +env.BlenderLib ( 'bf_blenlib', sources, Split(incs), Split(defs), libtype=['core','player'], priority = [85,195], compileflags =cflags ) diff --git a/source/blender/blenlib/intern/BLI_callbacks.h b/source/blender/blenlib/intern/BLI_callbacks.h new file mode 100644 index 00000000000..1f854764a59 --- /dev/null +++ b/source/blender/blenlib/intern/BLI_callbacks.h @@ -0,0 +1,44 @@ +/** + * blenlib/BLI_editVert.h mar 2001 Nzc + * + * These callbacks are needed in the lib + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BLI_CALLBACKS_H +#define BLI_CALLBACKS_H + +// This is blenlib internal only +void callLocalErrorCallBack(char* msg); + +#endif + diff --git a/source/blender/blenlib/intern/BLI_dynstr.c b/source/blender/blenlib/intern/BLI_dynstr.c new file mode 100644 index 00000000000..8bde670eef5 --- /dev/null +++ b/source/blender/blenlib/intern/BLI_dynstr.c @@ -0,0 +1,118 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * Dynamically sized string ADT + */ + +#include +#include + +#include "MEM_guardedalloc.h" +#include "BLI_blenlib.h" +#include "BLI_dynstr.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +/***/ + +typedef struct DynStrElem DynStrElem; +struct DynStrElem { + DynStrElem *next; + + char *str; +}; + +struct DynStr { + DynStrElem *elems, *last; + int curlen; +}; + +/***/ + +DynStr *BLI_dynstr_new(void) { + DynStr *ds= MEM_mallocN(sizeof(*ds), "DynStr"); + ds->elems= ds->last= NULL; + ds->curlen= 0; + + return ds; +} + +void BLI_dynstr_append(DynStr *ds, char *cstr) { + DynStrElem *dse= malloc(sizeof(*dse)); + int cstrlen= strlen(cstr); + + dse->str= malloc(cstrlen+1); + memcpy(dse->str, cstr, cstrlen+1); + dse->next= NULL; + + if (!ds->last) + ds->last= ds->elems= dse; + else + ds->last= ds->last->next= dse; + + ds->curlen+= cstrlen; +} + +int BLI_dynstr_get_len(DynStr *ds) { + return ds->curlen; +} + +char *BLI_dynstr_get_cstring(DynStr *ds) { + char *s, *rets= MEM_mallocN(ds->curlen+1, "dynstr_cstring"); + DynStrElem *dse; + + for (s= rets, dse= ds->elems; dse; dse= dse->next) { + int slen= strlen(dse->str); + + memcpy(s, dse->str, slen); + + s+= slen; + } + rets[ds->curlen]= '\0'; + + return rets; +} + +void BLI_dynstr_free(DynStr *ds) { + DynStrElem *dse; + + for (dse= ds->elems; dse; ) { + DynStrElem *n= dse->next; + + free(dse->str); + free(dse); + + dse= n; + } + + MEM_freeN(ds); +} diff --git a/source/blender/blenlib/intern/BLI_fileops.h b/source/blender/blenlib/intern/BLI_fileops.h new file mode 100644 index 00000000000..622706a32e9 --- /dev/null +++ b/source/blender/blenlib/intern/BLI_fileops.h @@ -0,0 +1,50 @@ +/** + * blenlib/BLI_listBase.h mar 2001 Nzc + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + * More low-level fileops from Daniel Dunbar. Two functions were also + * defined in storage.c. These are the old fop_ prefixes. There is + * definitely some redundancy here! + * */ + +#ifndef BLI_FILEOPS_H +#define BLI_FILEOPS_H + +char *first_slash(char *string); + +/* only for the sane unix world: direct calls to system functions :( */ +#ifndef WIN32 +void BLI_setCmdCallBack(int (*f)(char*)); +#endif + +#endif + diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c new file mode 100644 index 00000000000..5846bbda40e --- /dev/null +++ b/source/blender/blenlib/intern/BLI_ghash.c @@ -0,0 +1,295 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * A general (pointer -> pointer) hash table ADT + */ + +#include +#include + +#include "MEM_guardedalloc.h" +#include "BLI_ghash.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +/***/ + +static unsigned int hashsizes[]= { + 1, 3, 5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209, + 16411, 32771, 65537, 131101, 262147, 524309, 1048583, 2097169, + 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, + 268435459 +}; + +/***/ + +typedef struct Entry Entry; +struct Entry { + Entry *next; + + void *key, *val; +}; + +struct GHash { + GHashHashFP hashfp; + GHashCmpFP cmpfp; + + Entry **buckets; + int nbuckets, nentries, cursize; +}; + +/***/ + +GHash *BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp) { + GHash *gh= MEM_mallocN(sizeof(*gh), "GHash"); + gh->hashfp= hashfp; + gh->cmpfp= cmpfp; + + gh->cursize= 0; + gh->nentries= 0; + gh->nbuckets= hashsizes[gh->cursize]; + + gh->buckets= malloc(gh->nbuckets*sizeof(*gh->buckets)); + memset(gh->buckets, 0, gh->nbuckets*sizeof(*gh->buckets)); + + return gh; +} + +void BLI_ghash_insert(GHash *gh, void *key, void *val) { + unsigned int hash= gh->hashfp(key)%gh->nbuckets; + Entry *e= malloc(sizeof(*e)); + + e->key= key; + e->val= val; + e->next= gh->buckets[hash]; + gh->buckets[hash]= e; + + if (++gh->nentries>gh->nbuckets*3) { + Entry *e, **old= gh->buckets; + int i, nold= gh->nbuckets; + + gh->nbuckets= hashsizes[++gh->cursize]; + gh->buckets= malloc(gh->nbuckets*sizeof(*gh->buckets)); + memset(gh->buckets, 0, gh->nbuckets*sizeof(*gh->buckets)); + + for (i=0; inext; + + hash= gh->hashfp(e->key)%gh->nbuckets; + e->next= gh->buckets[hash]; + gh->buckets[hash]= e; + + e= n; + } + } + + free(old); + } +} + +void* BLI_ghash_lookup(GHash *gh, void *key) { + unsigned int hash= gh->hashfp(key)%gh->nbuckets; + Entry *e; + + for (e= gh->buckets[hash]; e; e= e->next) + if (gh->cmpfp(key, e->key)==0) + return e->val; + + return NULL; +} + +int BLI_ghash_remove (GHash *gh, void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp) +{ + unsigned int hash= gh->hashfp(key)%gh->nbuckets; + Entry *e; + Entry *p = 0; + + for (e= gh->buckets[hash]; e; e= e->next) { + if (gh->cmpfp(key, e->key)==0) { + Entry *n= e->next; + + if (keyfreefp) keyfreefp(e->key); + if (valfreefp) valfreefp(e->val); + free(e); + + + e= n; + if (p) + p->next = n; + else + gh->buckets[hash] = n; + + --gh->nentries; + return 1; + } + p = e; + } + + return 0; +} + +int BLI_ghash_haskey(GHash *gh, void *key) { + unsigned int hash= gh->hashfp(key)%gh->nbuckets; + Entry *e; + + for (e= gh->buckets[hash]; e; e= e->next) + if (gh->cmpfp(key, e->key)==0) + return 1; + + return 0; +} + +int BLI_ghash_size(GHash *gh) { + return gh->nentries; +} + +void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp) { + int i; + + for (i=0; inbuckets; i++) { + Entry *e; + + for (e= gh->buckets[i]; e; ) { + Entry *n= e->next; + + if (keyfreefp) keyfreefp(e->key); + if (valfreefp) valfreefp(e->val); + free(e); + + e= n; + } + } + + free(gh->buckets); + gh->buckets = 0; + gh->nentries = 0; + gh->nbuckets = 0; + MEM_freeN(gh); +} + +/***/ + +struct GHashIterator { + GHash *gh; + int curBucket; + Entry *curEntry; +}; + +GHashIterator *BLI_ghashIterator_new(GHash *gh) { + GHashIterator *ghi= malloc(sizeof(*ghi)); + ghi->gh= gh; + ghi->curEntry= NULL; + ghi->curBucket= -1; + while (!ghi->curEntry) { + ghi->curBucket++; + if (ghi->curBucket==ghi->gh->nbuckets) + break; + ghi->curEntry= ghi->gh->buckets[ghi->curBucket]; + } + return ghi; +} +void BLI_ghashIterator_free(GHashIterator *ghi) { + free(ghi); +} + +void *BLI_ghashIterator_getKey(GHashIterator *ghi) { + return ghi->curEntry?ghi->curEntry->key:NULL; +} +void *BLI_ghashIterator_getValue(GHashIterator *ghi) { + return ghi->curEntry?ghi->curEntry->val:NULL; +} + +void BLI_ghashIterator_step(GHashIterator *ghi) { + if (ghi->curEntry) { + ghi->curEntry= ghi->curEntry->next; + while (!ghi->curEntry) { + ghi->curBucket++; + if (ghi->curBucket==ghi->gh->nbuckets) + break; + ghi->curEntry= ghi->gh->buckets[ghi->curBucket]; + } + } +} +int BLI_ghashIterator_isDone(GHashIterator *ghi) { + return !ghi->curEntry; +} + +/***/ + +unsigned int BLI_ghashutil_ptrhash(void *key) { + return (unsigned int) key; +} +int BLI_ghashutil_ptrcmp(void *a, void *b) { + if (a==b) + return 0; + else + return (a> 5); + key += (key << 3); + key ^= (key >> 13); + key += ~(key << 9); + key ^= (key >> 17); + + return (unsigned int)(key & 0xffffffff); +} + +int BLI_ghashutil_intcmp(void *a, void *b) { + if (a==b) + return 0; + else + return (a +#include + +#include "MEM_guardedalloc.h" +#include "BLI_memarena.h" +#include "BLI_heap.h" + +/***/ + +struct HeapNode { + void *ptr; + float value; + int index; +}; + +struct Heap { + unsigned int size; + unsigned int bufsize; + MemArena *arena; + HeapNode *freenodes; + HeapNode *nodes; + HeapNode **tree; +}; + +#define SWAP(type, a, b) \ + { type sw_ap; sw_ap=(a); (a)=(b); (b)=sw_ap; } +#define HEAP_PARENT(i) ((i-1)>>1) +#define HEAP_LEFT(i) ((i<<1)+1) +#define HEAP_RIGHT(i) ((i<<1)+2) +#define HEAP_COMPARE(a, b) (a->value < b->value) +#define HEAP_EQUALS(a, b) (a->value == b->value) +#define HEAP_SWAP(heap, i, j) \ + { SWAP(int, heap->tree[i]->index, heap->tree[j]->index); \ + SWAP(HeapNode*, heap->tree[i], heap->tree[j]); } + +/***/ + +Heap *BLI_heap_new() +{ + Heap *heap = (Heap*)MEM_callocN(sizeof(Heap), "BLIHeap"); + heap->bufsize = 1; + heap->tree = (HeapNode**)MEM_mallocN(sizeof(HeapNode*), "BLIHeapTree"); + heap->arena = BLI_memarena_new(1<<16); + + return heap; +} + +void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) +{ + int i; + + if (ptrfreefp) + for (i = 0; i < heap->size; i++) + ptrfreefp(heap->tree[i]->ptr); + + MEM_freeN(heap->tree); + BLI_memarena_free(heap->arena); + MEM_freeN(heap); +} + +static void BLI_heap_down(Heap *heap, int i) +{ + while (1) { + int size = heap->size, smallest; + int l = HEAP_LEFT(i); + int r = HEAP_RIGHT(i); + + smallest = ((l < size) && HEAP_COMPARE(heap->tree[l], heap->tree[i]))? l: i; + + if ((r < size) && HEAP_COMPARE(heap->tree[r], heap->tree[smallest])) + smallest = r; + + if (smallest == i) + break; + + HEAP_SWAP(heap, i, smallest); + i = smallest; + } +} + +static void BLI_heap_up(Heap *heap, int i) +{ + while (i > 0) { + int p = HEAP_PARENT(i); + + if (HEAP_COMPARE(heap->tree[p], heap->tree[i])) + break; + + HEAP_SWAP(heap, p, i); + i = p; + } +} + +HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr) +{ + HeapNode *node; + + if ((heap->size + 1) > heap->bufsize) { + int newsize = heap->bufsize*2; + HeapNode **newtree; + + newtree = (HeapNode**)MEM_mallocN(newsize*sizeof(*newtree), "BLIHeapTree"); + memcpy(newtree, heap->tree, sizeof(HeapNode*)*heap->size); + MEM_freeN(heap->tree); + + heap->tree = newtree; + heap->bufsize = newsize; + } + + if (heap->freenodes) { + node = heap->freenodes; + heap->freenodes = (HeapNode*)(((HeapNode*)heap->freenodes)->ptr); + } + else + node = (HeapNode*)BLI_memarena_alloc(heap->arena, sizeof *node); + + node->value = value; + node->ptr = ptr; + node->index = heap->size; + + heap->tree[node->index] = node; + + heap->size++; + + BLI_heap_up(heap, heap->size-1); + + return node; +} + +int BLI_heap_empty(Heap *heap) +{ + return (heap->size == 0); +} + +int BLI_heap_size(Heap *heap) +{ + return heap->size; +} + +HeapNode *BLI_heap_top(Heap *heap) +{ + return heap->tree[0]; +} + +void *BLI_heap_popmin(Heap *heap) +{ + void *ptr = heap->tree[0]->ptr; + + heap->tree[0]->ptr = heap->freenodes; + heap->freenodes = heap->tree[0]; + + if (heap->size == 1) + heap->size--; + else { + HEAP_SWAP(heap, 0, heap->size-1); + heap->size--; + + BLI_heap_down(heap, 0); + } + + return ptr; +} + +void BLI_heap_remove(Heap *heap, HeapNode *node) +{ + int i = node->index; + + while (i > 0) { + int p = HEAP_PARENT(i); + + HEAP_SWAP(heap, p, i); + i = p; + } + + BLI_heap_popmin(heap); +} + +float BLI_heap_node_value(HeapNode *node) +{ + return node->value; +} + +void *BLI_heap_node_ptr(HeapNode *node) +{ + return node->ptr; +} + diff --git a/source/blender/blenlib/intern/BLI_linklist.c b/source/blender/blenlib/intern/BLI_linklist.c new file mode 100644 index 00000000000..6bb828a44bf --- /dev/null +++ b/source/blender/blenlib/intern/BLI_linklist.c @@ -0,0 +1,119 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * Support for linked lists. + */ + +#include "MEM_guardedalloc.h" +#include "BLI_blenlib.h" +#include "BLI_linklist.h" +#include "BLI_memarena.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +int BLI_linklist_length(LinkNode *list) { + if (0) { + return list?(1+BLI_linklist_length(list->next)):0; + } else { + int len; + + for (len=0; list; list= list->next) + len++; + + return len; + } +} + +void BLI_linklist_reverse(LinkNode **listp) { + LinkNode *rhead= NULL, *cur= *listp; + + while (cur) { + LinkNode *next= cur->next; + + cur->next= rhead; + rhead= cur; + + cur= next; + } + + *listp= rhead; +} + +void BLI_linklist_prepend(LinkNode **listp, void *ptr) { + LinkNode *nlink= MEM_mallocN(sizeof(*nlink), "nlink"); + nlink->link= ptr; + + nlink->next= *listp; + *listp= nlink; +} + +void BLI_linklist_append(LinkNode **listp, void *ptr) { + LinkNode *nlink= MEM_mallocN(sizeof(*nlink), "nlink"); + LinkNode *node = *listp; + + nlink->link = ptr; + nlink->next = NULL; + + if(node == NULL){ + *listp = nlink; + } else { + while(node->next != NULL){ + node = node->next; + } + node->next = nlink; + } +} + +void BLI_linklist_prepend_arena(LinkNode **listp, void *ptr, MemArena *ma) { + LinkNode *nlink= BLI_memarena_alloc(ma, sizeof(*nlink)); + nlink->link= ptr; + + nlink->next= *listp; + *listp= nlink; +} + +void BLI_linklist_free(LinkNode *list, LinkNodeFreeFP freefunc) { + while (list) { + LinkNode *next= list->next; + + if (freefunc) + freefunc(list->link); + MEM_freeN(list); + + list= next; + } +} + +void BLI_linklist_apply(LinkNode *list, LinkNodeApplyFP applyfunc, void *userdata) { + for (; list; list= list->next) + applyfunc(list->link, userdata); +} diff --git a/source/blender/blenlib/intern/BLI_memarena.c b/source/blender/blenlib/intern/BLI_memarena.c new file mode 100644 index 00000000000..c42ff3610fd --- /dev/null +++ b/source/blender/blenlib/intern/BLI_memarena.c @@ -0,0 +1,96 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * Efficient memory allocation for lots of similar small chunks. + */ + +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_memarena.h" +#include "BLI_linklist.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +struct MemArena { + unsigned char *curbuf; + int bufsize, cursize; + + int use_calloc; + + LinkNode *bufs; +}; + +MemArena *BLI_memarena_new(int bufsize) { + MemArena *ma= MEM_callocN(sizeof(*ma), "memarena"); + ma->bufsize= bufsize; + + return ma; +} + +void BLI_memarena_use_calloc(MemArena *ma) { + ma->use_calloc= 1; +} + +void BLI_memarena_free(MemArena *ma) { + BLI_linklist_free(ma->bufs, (void(*)(void*)) MEM_freeN); + MEM_freeN(ma); +} + + /* amt must be power of two */ +#define PADUP(num, amt) ((num+(amt-1))&~(amt-1)) + +void *BLI_memarena_alloc(MemArena *ma, int size) { + void *ptr; + + /* ensure proper alignment by rounding + * size up to multiple of 8 */ + size= PADUP(size, 8); + + if (size>ma->cursize) { + ma->cursize= (size>ma->bufsize)?size:ma->bufsize; + if(ma->use_calloc) + ma->curbuf= MEM_callocN(ma->cursize, "memarena calloc"); + else + ma->curbuf= MEM_mallocN(ma->cursize, "memarena malloc"); + + BLI_linklist_prepend(&ma->bufs, ma->curbuf); + } + + ptr= ma->curbuf; + ma->curbuf+= size; + ma->cursize-= size; + + return ptr; +} diff --git a/source/blender/blenlib/intern/BLI_scanfill.h b/source/blender/blenlib/intern/BLI_scanfill.h new file mode 100644 index 00000000000..cc02d76ad69 --- /dev/null +++ b/source/blender/blenlib/intern/BLI_scanfill.h @@ -0,0 +1,41 @@ +/** + * blenlib/BLI_scanfill.h mar 2001 Nzc + * + * Filling meshes. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BLI_SCANFILL_H +#define BLI_SCANFILL_H + +#endif + diff --git a/source/blender/blenlib/intern/BLI_storage.h b/source/blender/blenlib/intern/BLI_storage.h new file mode 100644 index 00000000000..5e9c377c410 --- /dev/null +++ b/source/blender/blenlib/intern/BLI_storage.h @@ -0,0 +1,41 @@ +/* $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BLI_STORAGE_H +#define BLI_STORAGE_H + +#include "BLI_storage_types.h" + +void BLI_adddirstrings(void); +void BLI_builddir(char *dirname, char *relname); +int BLI_compare(struct direntry *entry1, struct direntry *entry2); + +#endif /* BLI_STORAGE_H */ + diff --git a/source/blender/blenlib/intern/BLI_util.h b/source/blender/blenlib/intern/BLI_util.h new file mode 100644 index 00000000000..b033c89a0c9 --- /dev/null +++ b/source/blender/blenlib/intern/BLI_util.h @@ -0,0 +1,45 @@ +/** + * blenlib/BLI_storage_types.h + * + * Some types for dealing with directories + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BLI_UTIL_H +#define BLI_UTIL_H + +#define mallocstructN(x,y,name) (x*)MEM_mallocN((y)* sizeof(x),name) +#define callocstructN(x,y,name) (x*)MEM_callocN((y)* sizeof(x),name) + +struct ListBase; + +#endif + diff --git a/source/blender/blenlib/intern/Makefile b/source/blender/blenlib/intern/Makefile new file mode 100644 index 00000000000..68148a1eb37 --- /dev/null +++ b/source/blender/blenlib/intern/Makefile @@ -0,0 +1,61 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = blenlib +DIR = $(OCGDIR)/blender/$(LIBNAME) + +include nan_compile.mk + +# CPPFLAGS += $(LEVEL_2_CPP_WARNINGS) + +# path to SDNA types +CPPFLAGS += -I../../makesdna +# path to our own external headerfiles +CPPFLAGS += -I.. +# path to the guarded memory allocator +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include +# path to freetype font stuff +CPPFLAGS += -I$(NAN_FREETYPE)/include +CPPFLAGS += -I$(NAN_FREETYPE)/include/freetype2 +# path to blenkernel +CPPFLAGS += -I$(SRCHOME)/blender/blenkernel +CPPFLAGS += -I../../include/ +# path to zlib +CPPFLAGS += -I$(NAN_ZLIB)/include + +ifdef NAN_PTHREADS + CPPFLAGS += -I$(NAN_PTHREADS)/include +endif +ifeq ($(WITH_FREETYPE2), true) + CPPFLAGS += -DWITH_FREETYPE2 +endif diff --git a/source/blender/blenlib/intern/arithb.c b/source/blender/blenlib/intern/arithb.c new file mode 100644 index 00000000000..721df3a1a0c --- /dev/null +++ b/source/blender/blenlib/intern/arithb.c @@ -0,0 +1,3672 @@ +/* arithb.c + * + * simple math for blender code + * + * sort of cleaned up mar-01 nzc + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* ************************ FUNKTIES **************************** */ + +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(__sun__) || defined( __sun ) || defined (__sparc) || defined (__sparc__) +#include +#endif + +#if !defined(__sgi) && !defined(WIN32) +#include +#include +#endif + +#include +#include "BLI_arithb.h" + +/* A few small defines. Keep'em local! */ +#define SMALL_NUMBER 1.e-8 +#define ABS(x) ((x) < 0 ? -(x) : (x)) +#define SWAP(type, a, b) { type sw_ap; sw_ap=(a); (a)=(b); (b)=sw_ap; } + + +#if defined(WIN32) || defined(__APPLE__) +#include +#define M_PI 3.14159265358979323846 +#define M_SQRT2 1.41421356237309504880 + +#endif /* defined(WIN32) || defined(__APPLE__) */ + + +float saacos(float fac) +{ + if(fac<= -1.0f) return (float)M_PI; + else if(fac>=1.0f) return 0.0; + else return (float)acos(fac); +} + +float saasin(float fac) +{ + if(fac<= -1.0f) return (float)-M_PI/2.0f; + else if(fac>=1.0f) return (float)M_PI/2.0f; + else return (float)asin(fac); +} + +float sasqrt(float fac) +{ + if(fac<=0.0) return 0.0; + return (float)sqrt(fac); +} + +float Normalize(float *n) +{ + float d; + + d= n[0]*n[0]+n[1]*n[1]+n[2]*n[2]; + /* A larger value causes normalize errors in a scaled down models with camera xtreme close */ + if(d>1.0e-35F) { + d= (float)sqrt(d); + + n[0]/=d; + n[1]/=d; + n[2]/=d; + } else { + n[0]=n[1]=n[2]= 0.0; + d= 0.0; + } + return d; +} + +void Crossf(float *c, float *a, float *b) +{ + c[0] = a[1] * b[2] - a[2] * b[1]; + c[1] = a[2] * b[0] - a[0] * b[2]; + c[2] = a[0] * b[1] - a[1] * b[0]; +} + +/* Inpf returns the dot product, also called the scalar product and inner product */ +float Inpf( float *v1, float *v2) +{ + return v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]; +} + +/* Project v1 on v2 */ +void Projf(float *c, float *v1, float *v2) +{ + float mul; + mul = Inpf(v1, v2) / Inpf(v2, v2); + + c[0] = mul * v2[0]; + c[1] = mul * v2[1]; + c[2] = mul * v2[2]; +} + +void Mat3Transp(float mat[][3]) +{ + float t; + + t = mat[0][1] ; + mat[0][1] = mat[1][0] ; + mat[1][0] = t; + t = mat[0][2] ; + mat[0][2] = mat[2][0] ; + mat[2][0] = t; + t = mat[1][2] ; + mat[1][2] = mat[2][1] ; + mat[2][1] = t; +} + +void Mat4Transp(float mat[][4]) +{ + float t; + + t = mat[0][1] ; + mat[0][1] = mat[1][0] ; + mat[1][0] = t; + t = mat[0][2] ; + mat[0][2] = mat[2][0] ; + mat[2][0] = t; + t = mat[0][3] ; + mat[0][3] = mat[3][0] ; + mat[3][0] = t; + + t = mat[1][2] ; + mat[1][2] = mat[2][1] ; + mat[2][1] = t; + t = mat[1][3] ; + mat[1][3] = mat[3][1] ; + mat[3][1] = t; + + t = mat[2][3] ; + mat[2][3] = mat[3][2] ; + mat[3][2] = t; +} + + +/* + * invertmat - + * computes the inverse of mat and puts it in inverse. Returns + * TRUE on success (i.e. can always find a pivot) and FALSE on failure. + * Uses Gaussian Elimination with partial (maximal column) pivoting. + * + * Mark Segal - 1992 + */ + +int Mat4Invert(float inverse[][4], float mat[][4]) +{ + int i, j, k; + double temp; + float tempmat[4][4]; + float max; + int maxj; + + /* Set inverse to identity */ + for (i=0; i<4; i++) + for (j=0; j<4; j++) + inverse[i][j] = 0; + for (i=0; i<4; i++) + inverse[i][i] = 1; + + /* Copy original matrix so we don't mess it up */ + for(i = 0; i < 4; i++) + for(j = 0; j <4; j++) + tempmat[i][j] = mat[i][j]; + + for(i = 0; i < 4; i++) { + /* Look for row with max pivot */ + max = ABS(tempmat[i][i]); + maxj = i; + for(j = i + 1; j < 4; j++) { + if(ABS(tempmat[j][i]) > max) { + max = ABS(tempmat[j][i]); + maxj = j; + } + } + /* Swap rows if necessary */ + if (maxj != i) { + for( k = 0; k < 4; k++) { + SWAP(float, tempmat[i][k], tempmat[maxj][k]); + SWAP(float, inverse[i][k], inverse[maxj][k]); + } + } + + temp = tempmat[i][i]; + if (temp == 0) + return 0; /* No non-zero pivot */ + for(k = 0; k < 4; k++) { + tempmat[i][k] = (float)(tempmat[i][k]/temp); + inverse[i][k] = (float)(inverse[i][k]/temp); + } + for(j = 0; j < 4; j++) { + if(j != i) { + temp = tempmat[j][i]; + for(k = 0; k < 4; k++) { + tempmat[j][k] -= (float)(tempmat[i][k]*temp); + inverse[j][k] -= (float)(inverse[i][k]*temp); + } + } + } + } + return 1; +} +#ifdef TEST_ACTIVE +void Mat4InvertSimp(float inverse[][4], float mat[][4]) +{ + /* only for Matrices that have a rotation */ + /* based at GG IV pag 205 */ + float scale; + + scale= mat[0][0]*mat[0][0] + mat[1][0]*mat[1][0] + mat[2][0]*mat[2][0]; + if(scale==0.0) return; + + scale= 1.0/scale; + + /* transpose and scale */ + inverse[0][0]= scale*mat[0][0]; + inverse[1][0]= scale*mat[0][1]; + inverse[2][0]= scale*mat[0][2]; + inverse[0][1]= scale*mat[1][0]; + inverse[1][1]= scale*mat[1][1]; + inverse[2][1]= scale*mat[1][2]; + inverse[0][2]= scale*mat[2][0]; + inverse[1][2]= scale*mat[2][1]; + inverse[2][2]= scale*mat[2][2]; + + inverse[3][0]= -(inverse[0][0]*mat[3][0] + inverse[1][0]*mat[3][1] + inverse[2][0]*mat[3][2]); + inverse[3][1]= -(inverse[0][1]*mat[3][0] + inverse[1][1]*mat[3][1] + inverse[2][1]*mat[3][2]); + inverse[3][2]= -(inverse[0][2]*mat[3][0] + inverse[1][2]*mat[3][1] + inverse[2][2]*mat[3][2]); + + inverse[0][3]= inverse[1][3]= inverse[2][3]= 0.0; + inverse[3][3]= 1.0; +} +#endif +/* struct Matrix4; */ + +#ifdef TEST_ACTIVE +/* this seems to be unused.. */ + +void Mat4Inv(float *m1, float *m2) +{ + +/* This gets me into trouble: */ + float mat1[3][3], mat2[3][3]; + +/* void Mat3Inv(); */ +/* void Mat3CpyMat4(); */ +/* void Mat4CpyMat3(); */ + + Mat3CpyMat4((float*)mat2,m2); + Mat3Inv((float*)mat1, (float*) mat2); + Mat4CpyMat3(m1, mat1); + +} +#endif + + +float Det2x2(float a,float b,float c,float d) +{ + + return a*d - b*c; +} + + + +float Det3x3(float a1, float a2, float a3, + float b1, float b2, float b3, + float c1, float c2, float c3 ) +{ + float ans; + + ans = a1 * Det2x2( b2, b3, c2, c3 ) + - b1 * Det2x2( a2, a3, c2, c3 ) + + c1 * Det2x2( a2, a3, b2, b3 ); + + return ans; +} + +float Det4x4(float m[][4]) +{ + float ans; + float a1,a2,a3,a4,b1,b2,b3,b4,c1,c2,c3,c4,d1,d2,d3,d4; + + a1= m[0][0]; + b1= m[0][1]; + c1= m[0][2]; + d1= m[0][3]; + + a2= m[1][0]; + b2= m[1][1]; + c2= m[1][2]; + d2= m[1][3]; + + a3= m[2][0]; + b3= m[2][1]; + c3= m[2][2]; + d3= m[2][3]; + + a4= m[3][0]; + b4= m[3][1]; + c4= m[3][2]; + d4= m[3][3]; + + ans = a1 * Det3x3( b2, b3, b4, c2, c3, c4, d2, d3, d4) + - b1 * Det3x3( a2, a3, a4, c2, c3, c4, d2, d3, d4) + + c1 * Det3x3( a2, a3, a4, b2, b3, b4, d2, d3, d4) + - d1 * Det3x3( a2, a3, a4, b2, b3, b4, c2, c3, c4); + + return ans; +} + + +void Mat4Adj(float out[][4], float in[][4]) /* out = ADJ(in) */ +{ + float a1, a2, a3, a4, b1, b2, b3, b4; + float c1, c2, c3, c4, d1, d2, d3, d4; + + a1= in[0][0]; + b1= in[0][1]; + c1= in[0][2]; + d1= in[0][3]; + + a2= in[1][0]; + b2= in[1][1]; + c2= in[1][2]; + d2= in[1][3]; + + a3= in[2][0]; + b3= in[2][1]; + c3= in[2][2]; + d3= in[2][3]; + + a4= in[3][0]; + b4= in[3][1]; + c4= in[3][2]; + d4= in[3][3]; + + + out[0][0] = Det3x3( b2, b3, b4, c2, c3, c4, d2, d3, d4); + out[1][0] = - Det3x3( a2, a3, a4, c2, c3, c4, d2, d3, d4); + out[2][0] = Det3x3( a2, a3, a4, b2, b3, b4, d2, d3, d4); + out[3][0] = - Det3x3( a2, a3, a4, b2, b3, b4, c2, c3, c4); + + out[0][1] = - Det3x3( b1, b3, b4, c1, c3, c4, d1, d3, d4); + out[1][1] = Det3x3( a1, a3, a4, c1, c3, c4, d1, d3, d4); + out[2][1] = - Det3x3( a1, a3, a4, b1, b3, b4, d1, d3, d4); + out[3][1] = Det3x3( a1, a3, a4, b1, b3, b4, c1, c3, c4); + + out[0][2] = Det3x3( b1, b2, b4, c1, c2, c4, d1, d2, d4); + out[1][2] = - Det3x3( a1, a2, a4, c1, c2, c4, d1, d2, d4); + out[2][2] = Det3x3( a1, a2, a4, b1, b2, b4, d1, d2, d4); + out[3][2] = - Det3x3( a1, a2, a4, b1, b2, b4, c1, c2, c4); + + out[0][3] = - Det3x3( b1, b2, b3, c1, c2, c3, d1, d2, d3); + out[1][3] = Det3x3( a1, a2, a3, c1, c2, c3, d1, d2, d3); + out[2][3] = - Det3x3( a1, a2, a3, b1, b2, b3, d1, d2, d3); + out[3][3] = Det3x3( a1, a2, a3, b1, b2, b3, c1, c2, c3); +} + +void Mat4InvGG(float out[][4], float in[][4]) /* from Graphic Gems I, out= INV(in) */ +{ + int i, j; + float det; + + /* calculate the adjoint matrix */ + + Mat4Adj(out,in); + + det = Det4x4(out); + + if ( fabs( det ) < SMALL_NUMBER) { + return; + } + + /* scale the adjoint matrix to get the inverse */ + + for (i=0; i<4; i++) + for(j=0; j<4; j++) + out[i][j] = out[i][j] / det; + + /* the last factor is not always 1. For that reason an extra division should be implemented? */ +} + + +void Mat3Inv(float m1[][3], float m2[][3]) +{ + short a,b; + float det; + + /* calc adjoint */ + Mat3Adj(m1,m2); + + /* then determinant old matrix! */ + det= m2[0][0]* (m2[1][1]*m2[2][2] - m2[1][2]*m2[2][1]) + -m2[1][0]* (m2[0][1]*m2[2][2] - m2[0][2]*m2[2][1]) + +m2[2][0]* (m2[0][1]*m2[1][2] - m2[0][2]*m2[1][1]); + + if(det==0) det=1; + det= 1/det; + for(a=0;a<3;a++) { + for(b=0;b<3;b++) { + m1[a][b]*=det; + } + } +} + +void Mat3Adj(float m1[][3], float m[][3]) +{ + m1[0][0]=m[1][1]*m[2][2]-m[1][2]*m[2][1]; + m1[0][1]= -m[0][1]*m[2][2]+m[0][2]*m[2][1]; + m1[0][2]=m[0][1]*m[1][2]-m[0][2]*m[1][1]; + + m1[1][0]= -m[1][0]*m[2][2]+m[1][2]*m[2][0]; + m1[1][1]=m[0][0]*m[2][2]-m[0][2]*m[2][0]; + m1[1][2]= -m[0][0]*m[1][2]+m[0][2]*m[1][0]; + + m1[2][0]=m[1][0]*m[2][1]-m[1][1]*m[2][0]; + m1[2][1]= -m[0][0]*m[2][1]+m[0][1]*m[2][0]; + m1[2][2]=m[0][0]*m[1][1]-m[0][1]*m[1][0]; +} + +void Mat4MulMat4(float m1[][4], float m2[][4], float m3[][4]) +{ + /* matrix product: m1[j][k] = m2[j][i].m3[i][k] */ + + m1[0][0] = m2[0][0]*m3[0][0] + m2[0][1]*m3[1][0] + m2[0][2]*m3[2][0] + m2[0][3]*m3[3][0]; + m1[0][1] = m2[0][0]*m3[0][1] + m2[0][1]*m3[1][1] + m2[0][2]*m3[2][1] + m2[0][3]*m3[3][1]; + m1[0][2] = m2[0][0]*m3[0][2] + m2[0][1]*m3[1][2] + m2[0][2]*m3[2][2] + m2[0][3]*m3[3][2]; + m1[0][3] = m2[0][0]*m3[0][3] + m2[0][1]*m3[1][3] + m2[0][2]*m3[2][3] + m2[0][3]*m3[3][3]; + + m1[1][0] = m2[1][0]*m3[0][0] + m2[1][1]*m3[1][0] + m2[1][2]*m3[2][0] + m2[1][3]*m3[3][0]; + m1[1][1] = m2[1][0]*m3[0][1] + m2[1][1]*m3[1][1] + m2[1][2]*m3[2][1] + m2[1][3]*m3[3][1]; + m1[1][2] = m2[1][0]*m3[0][2] + m2[1][1]*m3[1][2] + m2[1][2]*m3[2][2] + m2[1][3]*m3[3][2]; + m1[1][3] = m2[1][0]*m3[0][3] + m2[1][1]*m3[1][3] + m2[1][2]*m3[2][3] + m2[1][3]*m3[3][3]; + + m1[2][0] = m2[2][0]*m3[0][0] + m2[2][1]*m3[1][0] + m2[2][2]*m3[2][0] + m2[2][3]*m3[3][0]; + m1[2][1] = m2[2][0]*m3[0][1] + m2[2][1]*m3[1][1] + m2[2][2]*m3[2][1] + m2[2][3]*m3[3][1]; + m1[2][2] = m2[2][0]*m3[0][2] + m2[2][1]*m3[1][2] + m2[2][2]*m3[2][2] + m2[2][3]*m3[3][2]; + m1[2][3] = m2[2][0]*m3[0][3] + m2[2][1]*m3[1][3] + m2[2][2]*m3[2][3] + m2[2][3]*m3[3][3]; + + m1[3][0] = m2[3][0]*m3[0][0] + m2[3][1]*m3[1][0] + m2[3][2]*m3[2][0] + m2[3][3]*m3[3][0]; + m1[3][1] = m2[3][0]*m3[0][1] + m2[3][1]*m3[1][1] + m2[3][2]*m3[2][1] + m2[3][3]*m3[3][1]; + m1[3][2] = m2[3][0]*m3[0][2] + m2[3][1]*m3[1][2] + m2[3][2]*m3[2][2] + m2[3][3]*m3[3][2]; + m1[3][3] = m2[3][0]*m3[0][3] + m2[3][1]*m3[1][3] + m2[3][2]*m3[2][3] + m2[3][3]*m3[3][3]; + +} +#ifdef TEST_ACTIVE +void subMat4MulMat4(float *m1, float *m2, float *m3) +{ + + m1[0]= m2[0]*m3[0] + m2[1]*m3[4] + m2[2]*m3[8]; + m1[1]= m2[0]*m3[1] + m2[1]*m3[5] + m2[2]*m3[9]; + m1[2]= m2[0]*m3[2] + m2[1]*m3[6] + m2[2]*m3[10]; + m1[3]= m2[0]*m3[3] + m2[1]*m3[7] + m2[2]*m3[11] + m2[3]; + m1+=4; + m2+=4; + m1[0]= m2[0]*m3[0] + m2[1]*m3[4] + m2[2]*m3[8]; + m1[1]= m2[0]*m3[1] + m2[1]*m3[5] + m2[2]*m3[9]; + m1[2]= m2[0]*m3[2] + m2[1]*m3[6] + m2[2]*m3[10]; + m1[3]= m2[0]*m3[3] + m2[1]*m3[7] + m2[2]*m3[11] + m2[3]; + m1+=4; + m2+=4; + m1[0]= m2[0]*m3[0] + m2[1]*m3[4] + m2[2]*m3[8]; + m1[1]= m2[0]*m3[1] + m2[1]*m3[5] + m2[2]*m3[9]; + m1[2]= m2[0]*m3[2] + m2[1]*m3[6] + m2[2]*m3[10]; + m1[3]= m2[0]*m3[3] + m2[1]*m3[7] + m2[2]*m3[11] + m2[3]; +} +#endif + +#ifndef TEST_ACTIVE +void Mat3MulMat3(float m1[][3], float m3[][3], float m2[][3]) +#else +void Mat3MulMat3(float *m1, float *m3, float *m2) +#endif +{ + /* m1[i][j] = m2[i][k]*m3[k][j], args are flipped! */ +#ifndef TEST_ACTIVE + m1[0][0]= m2[0][0]*m3[0][0] + m2[0][1]*m3[1][0] + m2[0][2]*m3[2][0]; + m1[0][1]= m2[0][0]*m3[0][1] + m2[0][1]*m3[1][1] + m2[0][2]*m3[2][1]; + m1[0][2]= m2[0][0]*m3[0][2] + m2[0][1]*m3[1][2] + m2[0][2]*m3[2][2]; + + m1[1][0]= m2[1][0]*m3[0][0] + m2[1][1]*m3[1][0] + m2[1][2]*m3[2][0]; + m1[1][1]= m2[1][0]*m3[0][1] + m2[1][1]*m3[1][1] + m2[1][2]*m3[2][1]; + m1[1][2]= m2[1][0]*m3[0][2] + m2[1][1]*m3[1][2] + m2[1][2]*m3[2][2]; + + m1[2][0]= m2[2][0]*m3[0][0] + m2[2][1]*m3[1][0] + m2[2][2]*m3[2][0]; + m1[2][1]= m2[2][0]*m3[0][1] + m2[2][1]*m3[1][1] + m2[2][2]*m3[2][1]; + m1[2][2]= m2[2][0]*m3[0][2] + m2[2][1]*m3[1][2] + m2[2][2]*m3[2][2]; +#else + m1[0]= m2[0]*m3[0] + m2[1]*m3[3] + m2[2]*m3[6]; + m1[1]= m2[0]*m3[1] + m2[1]*m3[4] + m2[2]*m3[7]; + m1[2]= m2[0]*m3[2] + m2[1]*m3[5] + m2[2]*m3[8]; + m1+=3; + m2+=3; + m1[0]= m2[0]*m3[0] + m2[1]*m3[3] + m2[2]*m3[6]; + m1[1]= m2[0]*m3[1] + m2[1]*m3[4] + m2[2]*m3[7]; + m1[2]= m2[0]*m3[2] + m2[1]*m3[5] + m2[2]*m3[8]; + m1+=3; + m2+=3; + m1[0]= m2[0]*m3[0] + m2[1]*m3[3] + m2[2]*m3[6]; + m1[1]= m2[0]*m3[1] + m2[1]*m3[4] + m2[2]*m3[7]; + m1[2]= m2[0]*m3[2] + m2[1]*m3[5] + m2[2]*m3[8]; +#endif +} /* end of void Mat3MulMat3(float m1[][3], float m3[][3], float m2[][3]) */ + +void Mat4MulMat43(float (*m1)[4], float (*m3)[4], float (*m2)[3]) +{ + m1[0][0]= m2[0][0]*m3[0][0] + m2[0][1]*m3[1][0] + m2[0][2]*m3[2][0]; + m1[0][1]= m2[0][0]*m3[0][1] + m2[0][1]*m3[1][1] + m2[0][2]*m3[2][1]; + m1[0][2]= m2[0][0]*m3[0][2] + m2[0][1]*m3[1][2] + m2[0][2]*m3[2][2]; + m1[1][0]= m2[1][0]*m3[0][0] + m2[1][1]*m3[1][0] + m2[1][2]*m3[2][0]; + m1[1][1]= m2[1][0]*m3[0][1] + m2[1][1]*m3[1][1] + m2[1][2]*m3[2][1]; + m1[1][2]= m2[1][0]*m3[0][2] + m2[1][1]*m3[1][2] + m2[1][2]*m3[2][2]; + m1[2][0]= m2[2][0]*m3[0][0] + m2[2][1]*m3[1][0] + m2[2][2]*m3[2][0]; + m1[2][1]= m2[2][0]*m3[0][1] + m2[2][1]*m3[1][1] + m2[2][2]*m3[2][1]; + m1[2][2]= m2[2][0]*m3[0][2] + m2[2][1]*m3[1][2] + m2[2][2]*m3[2][2]; +} +/* m1 = m2 * m3, ignore the elements on the 4th row/column of m3*/ +void Mat3IsMat3MulMat4(float m1[][3], float m2[][3], float m3[][4]) +{ + /* m1[i][j] = m2[i][k] * m3[k][j] */ + m1[0][0] = m2[0][0] * m3[0][0] + m2[0][1] * m3[1][0] +m2[0][2] * m3[2][0]; + m1[0][1] = m2[0][0] * m3[0][1] + m2[0][1] * m3[1][1] +m2[0][2] * m3[2][1]; + m1[0][2] = m2[0][0] * m3[0][2] + m2[0][1] * m3[1][2] +m2[0][2] * m3[2][2]; + + m1[1][0] = m2[1][0] * m3[0][0] + m2[1][1] * m3[1][0] +m2[1][2] * m3[2][0]; + m1[1][1] = m2[1][0] * m3[0][1] + m2[1][1] * m3[1][1] +m2[1][2] * m3[2][1]; + m1[1][2] = m2[1][0] * m3[0][2] + m2[1][1] * m3[1][2] +m2[1][2] * m3[2][2]; + + m1[2][0] = m2[2][0] * m3[0][0] + m2[2][1] * m3[1][0] +m2[2][2] * m3[2][0]; + m1[2][1] = m2[2][0] * m3[0][1] + m2[2][1] * m3[1][1] +m2[2][2] * m3[2][1]; + m1[2][2] = m2[2][0] * m3[0][2] + m2[2][1] * m3[1][2] +m2[2][2] * m3[2][2]; +} + + + +void Mat4MulMat34(float (*m1)[4], float (*m3)[3], float (*m2)[4]) +{ + m1[0][0]= m2[0][0]*m3[0][0] + m2[0][1]*m3[1][0] + m2[0][2]*m3[2][0]; + m1[0][1]= m2[0][0]*m3[0][1] + m2[0][1]*m3[1][1] + m2[0][2]*m3[2][1]; + m1[0][2]= m2[0][0]*m3[0][2] + m2[0][1]*m3[1][2] + m2[0][2]*m3[2][2]; + m1[1][0]= m2[1][0]*m3[0][0] + m2[1][1]*m3[1][0] + m2[1][2]*m3[2][0]; + m1[1][1]= m2[1][0]*m3[0][1] + m2[1][1]*m3[1][1] + m2[1][2]*m3[2][1]; + m1[1][2]= m2[1][0]*m3[0][2] + m2[1][1]*m3[1][2] + m2[1][2]*m3[2][2]; + m1[2][0]= m2[2][0]*m3[0][0] + m2[2][1]*m3[1][0] + m2[2][2]*m3[2][0]; + m1[2][1]= m2[2][0]*m3[0][1] + m2[2][1]*m3[1][1] + m2[2][2]*m3[2][1]; + m1[2][2]= m2[2][0]*m3[0][2] + m2[2][1]*m3[1][2] + m2[2][2]*m3[2][2]; +} + +void Mat4CpyMat4(float m1[][4], float m2[][4]) +{ + memcpy(m1, m2, 4*4*sizeof(float)); +} + +void Mat4SwapMat4(float *m1, float *m2) +{ + float t; + int i; + + for(i=0;i<16;i++) { + t= *m1; + *m1= *m2; + *m2= t; + m1++; + m2++; + } +} + +typedef float Mat3Row[3]; +typedef float Mat4Row[4]; + +#ifdef TEST_ACTIVE +void Mat3CpyMat4(float *m1p, float *m2p) +#else +void Mat3CpyMat4(float m1[][3], float m2[][4]) +#endif +{ +#ifdef TEST_ACTIVE + int i, j; + Mat3Row *m1= (Mat3Row *)m1p; + Mat4Row *m2= (Mat4Row *)m2p; + for ( i = 0; i++; i < 3) { + for (j = 0; j++; j < 3) { + m1p[3*i + j] = m2p[4*i + j]; + } + } +#endif + m1[0][0]= m2[0][0]; + m1[0][1]= m2[0][1]; + m1[0][2]= m2[0][2]; + + m1[1][0]= m2[1][0]; + m1[1][1]= m2[1][1]; + m1[1][2]= m2[1][2]; + + m1[2][0]= m2[2][0]; + m1[2][1]= m2[2][1]; + m1[2][2]= m2[2][2]; +} + +/* Butched. See .h for comment */ +/* void Mat4CpyMat3(float m1[][4], float m2[][3]) */ +#ifdef TEST_ACTIVE +void Mat4CpyMat3(float* m1, float *m2) +{ + int i; + for (i = 0; i < 3; i++) { + m1[(4*i)] = m2[(3*i)]; + m1[(4*i) + 1]= m2[(3*i) + 1]; + m1[(4*i) + 2]= m2[(3*i) + 2]; + m1[(4*i) + 3]= 0.0; + i++; + } + + m1[12]=m1[13]= m1[14]= 0.0; + m1[15]= 1.0; +} +#else + +void Mat4CpyMat3(float m1[][4], float m2[][3]) /* no clear */ +{ + m1[0][0]= m2[0][0]; + m1[0][1]= m2[0][1]; + m1[0][2]= m2[0][2]; + + m1[1][0]= m2[1][0]; + m1[1][1]= m2[1][1]; + m1[1][2]= m2[1][2]; + + m1[2][0]= m2[2][0]; + m1[2][1]= m2[2][1]; + m1[2][2]= m2[2][2]; + + /* Reevan's Bugfix */ + m1[0][3]=0.0F; + m1[1][3]=0.0F; + m1[2][3]=0.0F; + + m1[3][0]=0.0F; + m1[3][1]=0.0F; + m1[3][2]=0.0F; + m1[3][3]=1.0F; + + +} +#endif + +void Mat3CpyMat3(float m1[][3], float m2[][3]) +{ + /* destination comes first: */ + memcpy(&m1[0], &m2[0], 9*sizeof(float)); +} + +void Mat3MulSerie(float answ[][3], + float m1[][3], float m2[][3], float m3[][3], + float m4[][3], float m5[][3], float m6[][3], + float m7[][3], float m8[][3]) +{ + float temp[3][3]; + + if(m1==0 || m2==0) return; + + + Mat3MulMat3(answ, m2, m1); + if(m3) { + Mat3MulMat3(temp, m3, answ); + if(m4) { + Mat3MulMat3(answ, m4, temp); + if(m5) { + Mat3MulMat3(temp, m5, answ); + if(m6) { + Mat3MulMat3(answ, m6, temp); + if(m7) { + Mat3MulMat3(temp, m7, answ); + if(m8) { + Mat3MulMat3(answ, m8, temp); + } + else Mat3CpyMat3(answ, temp); + } + } + else Mat3CpyMat3(answ, temp); + } + } + else Mat3CpyMat3(answ, temp); + } +} + +void Mat4MulSerie(float answ[][4], float m1[][4], + float m2[][4], float m3[][4], float m4[][4], + float m5[][4], float m6[][4], float m7[][4], + float m8[][4]) +{ + float temp[4][4]; + + if(m1==0 || m2==0) return; + + Mat4MulMat4(answ, m2, m1); + if(m3) { + Mat4MulMat4(temp, m3, answ); + if(m4) { + Mat4MulMat4(answ, m4, temp); + if(m5) { + Mat4MulMat4(temp, m5, answ); + if(m6) { + Mat4MulMat4(answ, m6, temp); + if(m7) { + Mat4MulMat4(temp, m7, answ); + if(m8) { + Mat4MulMat4(answ, m8, temp); + } + else Mat4CpyMat4(answ, temp); + } + } + else Mat4CpyMat4(answ, temp); + } + } + else Mat4CpyMat4(answ, temp); + } +} + +void Mat4BlendMat4(float out[][4], float dst[][4], float src[][4], float srcweight) +{ + float squat[4], dquat[4], fquat[4]; + float ssize[3], dsize[3], fsize[4]; + float sloc[3], dloc[3], floc[3]; + + Mat4ToQuat(dst, dquat); + Mat4ToSize(dst, dsize); + VecCopyf(dloc, dst[3]); + + Mat4ToQuat(src, squat); + Mat4ToSize(src, ssize); + VecCopyf(sloc, src[3]); + + /* do blending */ + VecLerpf(floc, dloc, sloc, srcweight); + QuatInterpol(fquat, dquat, squat, srcweight); + VecLerpf(fsize, dsize, ssize, srcweight); + + /* compose new matrix */ + LocQuatSizeToMat4(out, floc, fquat, fsize); +} + +void Mat4Clr(float *m) +{ + memset(m, 0, 4*4*sizeof(float)); +} + +void Mat3Clr(float *m) +{ + memset(m, 0, 3*3*sizeof(float)); +} + +void Mat4One(float m[][4]) +{ + + m[0][0]= m[1][1]= m[2][2]= m[3][3]= 1.0; + m[0][1]= m[0][2]= m[0][3]= 0.0; + m[1][0]= m[1][2]= m[1][3]= 0.0; + m[2][0]= m[2][1]= m[2][3]= 0.0; + m[3][0]= m[3][1]= m[3][2]= 0.0; +} + +void Mat3One(float m[][3]) +{ + + m[0][0]= m[1][1]= m[2][2]= 1.0; + m[0][1]= m[0][2]= 0.0; + m[1][0]= m[1][2]= 0.0; + m[2][0]= m[2][1]= 0.0; +} + +void Mat4MulVec( float mat[][4], int *vec) +{ + int x,y; + + x=vec[0]; + y=vec[1]; + vec[0]=(int)(x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2] + mat[3][0]); + vec[1]=(int)(x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2] + mat[3][1]); + vec[2]=(int)(x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2] + mat[3][2]); +} + +void Mat4MulVecfl( float mat[][4], float *vec) +{ + float x,y; + + x=vec[0]; + y=vec[1]; + vec[0]=x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2] + mat[3][0]; + vec[1]=x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2] + mat[3][1]; + vec[2]=x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2] + mat[3][2]; +} + +void VecMat4MulVecfl(float *in, float mat[][4], float *vec) +{ + float x,y; + + x=vec[0]; + y=vec[1]; + in[0]= x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2] + mat[3][0]; + in[1]= x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2] + mat[3][1]; + in[2]= x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2] + mat[3][2]; +} + +void Mat4Mul3Vecfl( float mat[][4], float *vec) +{ + float x,y; + + x= vec[0]; + y= vec[1]; + vec[0]= x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2]; + vec[1]= x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2]; + vec[2]= x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2]; +} + +void Mat4MulVec3Project(float mat[][4], float *vec) +{ + float w; + + w = vec[0]*mat[0][3] + vec[1]*mat[1][3] + vec[2]*mat[2][3] + mat[3][3]; + Mat4MulVecfl(mat, vec); + + vec[0] /= w; + vec[1] /= w; + vec[2] /= w; +} + +void Mat4MulVec4fl( float mat[][4], float *vec) +{ + float x,y,z; + + x=vec[0]; + y=vec[1]; + z= vec[2]; + vec[0]=x*mat[0][0] + y*mat[1][0] + z*mat[2][0] + mat[3][0]*vec[3]; + vec[1]=x*mat[0][1] + y*mat[1][1] + z*mat[2][1] + mat[3][1]*vec[3]; + vec[2]=x*mat[0][2] + y*mat[1][2] + z*mat[2][2] + mat[3][2]*vec[3]; + vec[3]=x*mat[0][3] + y*mat[1][3] + z*mat[2][3] + mat[3][3]*vec[3]; +} + +void Mat3MulVec( float mat[][3], int *vec) +{ + int x,y; + + x=vec[0]; + y=vec[1]; + vec[0]= (int)(x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2]); + vec[1]= (int)(x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2]); + vec[2]= (int)(x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2]); +} + +void Mat3MulVecfl( float mat[][3], float *vec) +{ + float x,y; + + x=vec[0]; + y=vec[1]; + vec[0]= x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2]; + vec[1]= x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2]; + vec[2]= x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2]; +} + +void Mat3MulVecd( float mat[][3], double *vec) +{ + double x,y; + + x=vec[0]; + y=vec[1]; + vec[0]= x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2]; + vec[1]= x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2]; + vec[2]= x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2]; +} + +void Mat3TransMulVecfl( float mat[][3], float *vec) +{ + float x,y; + + x=vec[0]; + y=vec[1]; + vec[0]= x*mat[0][0] + y*mat[0][1] + mat[0][2]*vec[2]; + vec[1]= x*mat[1][0] + y*mat[1][1] + mat[1][2]*vec[2]; + vec[2]= x*mat[2][0] + y*mat[2][1] + mat[2][2]*vec[2]; +} + +void Mat3MulFloat(float *m, float f) +{ + int i; + + for(i=0;i<9;i++) m[i]*=f; +} + +void Mat4MulFloat(float *m, float f) +{ + int i; + + for(i=0;i<16;i++) m[i]*=f; /* count to 12: without vector component */ +} + + +void Mat4MulFloat3(float *m, float f) /* only scale component */ +{ + int i,j; + + for(i=0; i<3; i++) { + for(j=0; j<3; j++) { + + m[4*i+j] *= f; + } + } +} + +void Mat3AddMat3(float m1[][3], float m2[][3], float m3[][3]) +{ + int i, j; + + for(i=0;i<3;i++) + for(j=0;j<3;j++) + m1[i][j]= m2[i][j] + m3[i][j]; +} + +void Mat4AddMat4(float m1[][4], float m2[][4], float m3[][4]) +{ + int i, j; + + for(i=0;i<4;i++) + for(j=0;j<4;j++) + m1[i][j]= m2[i][j] + m3[i][j]; +} + +void VecStar(float mat[][3], float *vec) +{ + + mat[0][0]= mat[1][1]= mat[2][2]= 0.0; + mat[0][1]= -vec[2]; + mat[0][2]= vec[1]; + mat[1][0]= vec[2]; + mat[1][2]= -vec[0]; + mat[2][0]= -vec[1]; + mat[2][1]= vec[0]; + +} +#ifdef TEST_ACTIVE +short EenheidsMat(float mat[][3]) +{ + + if(mat[0][0]==1.0 && mat[0][1]==0.0 && mat[0][2]==0.0) + if(mat[1][0]==0.0 && mat[1][1]==1.0 && mat[1][2]==0.0) + if(mat[2][0]==0.0 && mat[2][1]==0.0 && mat[2][2]==1.0) + return 1; + return 0; +} +#endif + +int FloatCompare( float *v1, float *v2, float limit) +{ + + if( fabs(v1[0]-v2[0])FLT_EPSILON) { + s= sqrt( tr); + q[0]= (float)s; + s*= 4.0; + q[1]= (float)((mat[1][2]-mat[2][1])/s); + q[2]= (float)((mat[2][0]-mat[0][2])/s); + q[3]= (float)((mat[0][1]-mat[1][0])/s); + } + else { + q[0]= 0.0f; + s= -0.5*(mat[1][1]+mat[2][2]); + + if(s>FLT_EPSILON) { + s= sqrt(s); + q[1]= (float)s; + q[2]= (float)(mat[0][1]/(2*s)); + q[3]= (float)(mat[0][2]/(2*s)); + } + else { + q[1]= 0.0f; + s= 0.5*(1.0-mat[2][2]); + + if(s>FLT_EPSILON) { + s= sqrt(s); + q[2]= (float)s; + q[3]= (float)(mat[1][2]/(2*s)); + } + else { + q[2]= 0.0f; + q[3]= 1.0f; + } + } + } + NormalQuat(q); +} + +void Mat3ToQuat_is_ok( float wmat[][3], float *q) +{ + float mat[3][3], matr[3][3], matn[3][3], q1[4], q2[4], angle, si, co, nor[3]; + + /* work on a copy */ + Mat3CpyMat3(mat, wmat); + Mat3Ortho(mat); + + /* rotate z-axis of matrix to z-axis */ + + nor[0] = mat[2][1]; /* cross product with (0,0,1) */ + nor[1] = -mat[2][0]; + nor[2] = 0.0; + Normalize(nor); + + co= mat[2][2]; + angle= 0.5f*saacos(co); + + co= (float)cos(angle); + si= (float)sin(angle); + q1[0]= co; + q1[1]= -nor[0]*si; /* negative here, but why? */ + q1[2]= -nor[1]*si; + q1[3]= -nor[2]*si; + + /* rotate back x-axis from mat, using inverse q1 */ + QuatToMat3(q1, matr); + Mat3Inv(matn, matr); + Mat3MulVecfl(matn, mat[0]); + + /* and align x-axes */ + angle= (float)(0.5*atan2(mat[0][1], mat[0][0])); + + co= (float)cos(angle); + si= (float)sin(angle); + q2[0]= co; + q2[1]= 0.0f; + q2[2]= 0.0f; + q2[3]= si; + + QuatMul(q, q1, q2); +} + + +void Mat4ToQuat( float m[][4], float *q) +{ + float mat[3][3]; + + Mat3CpyMat4(mat, m); + Mat3ToQuat(mat, q); + +} + +void QuatOne(float *q) +{ + q[0]= q[2]= q[3]= 0.0; + q[1]= 1.0; +} + +void NormalQuat(float *q) +{ + float len; + + len= (float)sqrt(q[0]*q[0]+q[1]*q[1]+q[2]*q[2]+q[3]*q[3]); + if(len!=0.0) { + q[0]/= len; + q[1]/= len; + q[2]/= len; + q[3]/= len; + } else { + q[1]= 1.0f; + q[0]= q[2]= q[3]= 0.0f; + } +} + +float *vectoquat( float *vec, short axis, short upflag) +{ + static float q1[4]; + float q2[4], nor[3], *fp, mat[3][3], angle, si, co, x2, y2, z2, len1; + + /* first rotate to axis */ + if(axis>2) { + x2= vec[0] ; y2= vec[1] ; z2= vec[2]; + axis-= 3; + } + else { + x2= -vec[0] ; y2= -vec[1] ; z2= -vec[2]; + } + + q1[0]=1.0; + q1[1]=q1[2]=q1[3]= 0.0; + + len1= (float)sqrt(x2*x2+y2*y2+z2*z2); + if(len1 == 0.0) return(q1); + + /* nasty! I need a good routine for this... + * problem is a rotation of an Y axis to the negative Y-axis for example. + */ + + if(axis==0) { /* x-axis */ + nor[0]= 0.0; + nor[1]= -z2; + nor[2]= y2; + + if( fabs(y2)+fabs(z2)<0.0001 ) { + nor[1]= 1.0; + } + + co= x2; + } + else if(axis==1) { /* y-axis */ + nor[0]= z2; + nor[1]= 0.0; + nor[2]= -x2; + + if( fabs(x2)+fabs(z2)<0.0001 ) { + nor[2]= 1.0; + } + + co= y2; + } + else { /* z-axis */ + nor[0]= -y2; + nor[1]= x2; + nor[2]= 0.0; + + if( fabs(x2)+fabs(y2)<0.0001 ) { + nor[0]= 1.0; + } + + co= z2; + } + co/= len1; + + Normalize(nor); + + angle= 0.5f*saacos(co); + si= (float)sin(angle); + q1[0]= (float)cos(angle); + q1[1]= nor[0]*si; + q1[2]= nor[1]*si; + q1[3]= nor[2]*si; + + if(axis!=upflag) { + QuatToMat3(q1, mat); + + fp= mat[2]; + if(axis==0) { + if(upflag==1) angle= (float)(0.5*atan2(fp[2], fp[1])); + else angle= (float)(-0.5*atan2(fp[1], fp[2])); + } + else if(axis==1) { + if(upflag==0) angle= (float)(-0.5*atan2(fp[2], fp[0])); + else angle= (float)(0.5*atan2(fp[0], fp[2])); + } + else { + if(upflag==0) angle= (float)(0.5*atan2(-fp[1], -fp[0])); + else angle= (float)(-0.5*atan2(-fp[0], -fp[1])); + } + + co= (float)cos(angle); + si= (float)(sin(angle)/len1); + q2[0]= co; + q2[1]= x2*si; + q2[2]= y2*si; + q2[3]= z2*si; + + QuatMul(q1,q2,q1); + } + + return(q1); +} + +void VecUpMat3old( float *vec, float mat[][3], short axis) +{ + float inp, up[3]; + short cox = 0, coy = 0, coz = 0; + + /* using different up's is not useful, infact there is no real 'up'! + */ + + up[0]= 0.0; + up[1]= 0.0; + up[2]= 1.0; + + if(axis==0) { + cox= 0; coy= 1; coz= 2; /* Y up Z tr */ + } + if(axis==1) { + cox= 1; coy= 2; coz= 0; /* Z up X tr */ + } + if(axis==2) { + cox= 2; coy= 0; coz= 1; /* X up Y tr */ + } + if(axis==3) { + cox= 0; coy= 2; coz= 1; /* */ + } + if(axis==4) { + cox= 1; coy= 0; coz= 2; /* */ + } + if(axis==5) { + cox= 2; coy= 1; coz= 0; /* Y up X tr */ + } + + mat[coz][0]= vec[0]; + mat[coz][1]= vec[1]; + mat[coz][2]= vec[2]; + Normalize((float *)mat[coz]); + + inp= mat[coz][0]*up[0] + mat[coz][1]*up[1] + mat[coz][2]*up[2]; + mat[coy][0]= up[0] - inp*mat[coz][0]; + mat[coy][1]= up[1] - inp*mat[coz][1]; + mat[coy][2]= up[2] - inp*mat[coz][2]; + + Normalize((float *)mat[coy]); + + Crossf(mat[cox], mat[coy], mat[coz]); + +} + +void VecUpMat3(float *vec, float mat[][3], short axis) +{ + float inp; + short cox = 0, coy = 0, coz = 0; + + /* using different up's is not useful, infact there is no real 'up'! + */ + + if(axis==0) { + cox= 0; coy= 1; coz= 2; /* Y up Z tr */ + } + if(axis==1) { + cox= 1; coy= 2; coz= 0; /* Z up X tr */ + } + if(axis==2) { + cox= 2; coy= 0; coz= 1; /* X up Y tr */ + } + if(axis==3) { + cox= 0; coy= 1; coz= 2; /* Y op -Z tr */ + vec[0]= -vec[0]; + vec[1]= -vec[1]; + vec[2]= -vec[2]; + } + if(axis==4) { + cox= 1; coy= 0; coz= 2; /* */ + } + if(axis==5) { + cox= 2; coy= 1; coz= 0; /* Y up X tr */ + } + + mat[coz][0]= vec[0]; + mat[coz][1]= vec[1]; + mat[coz][2]= vec[2]; + Normalize((float *)mat[coz]); + + inp= mat[coz][2]; + mat[coy][0]= - inp*mat[coz][0]; + mat[coy][1]= - inp*mat[coz][1]; + mat[coy][2]= 1.0f - inp*mat[coz][2]; + + Normalize((float *)mat[coy]); + + Crossf(mat[cox], mat[coy], mat[coz]); + +} + +/* A & M Watt, Advanced animation and rendering techniques, 1992 ACM press */ +void QuatInterpolW(float *, float *, float *, float ); + +void QuatInterpolW(float *result, float *quat1, float *quat2, float t) +{ + float omega, cosom, sinom, sc1, sc2; + + cosom = quat1[0]*quat2[0] + quat1[1]*quat2[1] + quat1[2]*quat2[2] + quat1[3]*quat2[3] ; + + /* rotate around shortest angle */ + if ((1.0 + cosom) > 0.0001) { + + if ((1.0 - cosom) > 0.0001) { + omega = acos(cosom); + sinom = sin(omega); + sc1 = sin((1.0 - t) * omega) / sinom; + sc2 = sin(t * omega) / sinom; + } + else { + sc1 = 1.0 - t; + sc2 = t; + } + result[0] = sc1*quat1[0] + sc2*quat2[0]; + result[1] = sc1*quat1[1] + sc2*quat2[1]; + result[2] = sc1*quat1[2] + sc2*quat2[2]; + result[3] = sc1*quat1[3] + sc2*quat2[3]; + } + else { + result[0] = quat2[3]; + result[1] = -quat2[2]; + result[2] = quat2[1]; + result[3] = -quat2[0]; + + sc1 = sin((1.0 - t)*M_PI_2); + sc2 = sin(t*M_PI_2); + + result[0] = sc1*quat1[0] + sc2*result[0]; + result[1] = sc1*quat1[1] + sc2*result[1]; + result[2] = sc1*quat1[2] + sc2*result[2]; + result[3] = sc1*quat1[3] + sc2*result[3]; + } +} + +void QuatInterpol(float *result, float *quat1, float *quat2, float t) +{ + float quat[4], omega, cosom, sinom, sc1, sc2; + + cosom = quat1[0]*quat2[0] + quat1[1]*quat2[1] + quat1[2]*quat2[2] + quat1[3]*quat2[3] ; + + /* rotate around shortest angle */ + if (cosom < 0.0) { + cosom = -cosom; + quat[0]= -quat1[0]; + quat[1]= -quat1[1]; + quat[2]= -quat1[2]; + quat[3]= -quat1[3]; + } + else { + quat[0]= quat1[0]; + quat[1]= quat1[1]; + quat[2]= quat1[2]; + quat[3]= quat1[3]; + } + + if ((1.0 - cosom) > 0.0001) { + omega = acos(cosom); + sinom = sin(omega); + sc1 = sin((1 - t) * omega) / sinom; + sc2 = sin(t * omega) / sinom; + } else { + sc1= 1.0 - t; + sc2= t; + } + + result[0] = sc1 * quat[0] + sc2 * quat2[0]; + result[1] = sc1 * quat[1] + sc2 * quat2[1]; + result[2] = sc1 * quat[2] + sc2 * quat2[2]; + result[3] = sc1 * quat[3] + sc2 * quat2[3]; +} + +void QuatAdd(float *result, float *quat1, float *quat2, float t) +{ + result[0]= quat1[0] + t*quat2[0]; + result[1]= quat1[1] + t*quat2[1]; + result[2]= quat1[2] + t*quat2[2]; + result[3]= quat1[3] + t*quat2[3]; +} + +void QuatCopy(float *q1, float *q2) +{ + q1[0]= q2[0]; + q1[1]= q2[1]; + q1[2]= q2[2]; + q1[3]= q2[3]; +} + +/* **************** DUAL QUATERNIONS ************** */ + +/* + Conversion routines between (regular quaternion, translation) and + dual quaternion. + + Version 1.0.0, February 7th, 2007 + + Copyright (C) 2006-2007 University of Dublin, Trinity College, All Rights + Reserved + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author(s) 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. + + Author: Ladislav Kavan, kavanl@cs.tcd.ie + + Changes for Blender: + - renaming, style changes and optimizations + - added support for scaling +*/ + +void Mat4ToDQuat(float basemat[][4], float mat[][4], DualQuat *dq) +{ + float *t, *q, dscale[3], scale[3], basequat[4]; + float baseRS[4][4], baseinv[4][4], baseR[4][4], baseRinv[4][4]; + float R[4][4], S[4][4]; + + /* split scaling and rotation, there is probably a faster way to do + this, it's done like this now to correctly get negative scaling */ + Mat4MulMat4(baseRS, basemat, mat); + Mat4ToSize(baseRS, scale); + + VecCopyf(dscale, scale); + dscale[0] -= 1.0f; dscale[1] -= 1.0f; dscale[2] -= 1.0f; + + if((Det4x4(mat) < 0.0f) || VecLength(dscale) > 1e-4) { + /* extract R and S */ + Mat4ToQuat(baseRS, basequat); + QuatToMat4(basequat, baseR); + VecCopyf(baseR[3], baseRS[3]); + + Mat4Invert(baseinv, basemat); + Mat4MulMat4(R, baseinv, baseR); + + Mat4Invert(baseRinv, baseR); + Mat4MulMat4(S, baseRS, baseRinv); + + /* set scaling part */ + Mat4MulSerie(dq->scale, basemat, S, baseinv, 0, 0, 0, 0, 0); + dq->scale_weight= 1.0f; + } + else { + /* matrix does not contain scaling */ + Mat4CpyMat4(R, mat); + dq->scale_weight= 0.0f; + } + + /* non-dual part */ + Mat4ToQuat(R, dq->quat); + + /* dual part */ + t= R[3]; + q= dq->quat; + dq->trans[0]= -0.5f*( t[0]*q[1] + t[1]*q[2] + t[2]*q[3]); + dq->trans[1]= 0.5f*( t[0]*q[0] + t[1]*q[3] - t[2]*q[2]); + dq->trans[2]= 0.5f*(-t[0]*q[3] + t[1]*q[0] + t[2]*q[1]); + dq->trans[3]= 0.5f*( t[0]*q[2] - t[1]*q[1] + t[2]*q[0]); +} + +void DQuatToMat4(DualQuat *dq, float mat[][4]) +{ + float len, *t, q0[4]; + + /* regular quaternion */ + QuatCopy(q0, dq->quat); + + /* normalize */ + len= sqrt(QuatDot(q0, q0)); + if(len != 0.0f) + QuatMulf(q0, 1.0f/len); + + /* rotation */ + QuatToMat4(q0, mat); + + /* translation */ + t= dq->trans; + mat[3][0]= 2.0*(-t[0]*q0[1] + t[1]*q0[0] - t[2]*q0[3] + t[3]*q0[2]); + mat[3][1]= 2.0*(-t[0]*q0[2] + t[1]*q0[3] + t[2]*q0[0] - t[3]*q0[1]); + mat[3][2]= 2.0*(-t[0]*q0[3] - t[1]*q0[2] + t[2]*q0[1] + t[3]*q0[0]); + + /* note: this does not handle scaling */ +} + +void DQuatAddWeighted(DualQuat *dqsum, DualQuat *dq, float weight) +{ + /* make sure we interpolate quats in the right direction */ + if (QuatDot(dq->quat, dqsum->quat) < 0) + weight = -weight; + + /* interpolate rotation and translation */ + dqsum->quat[0] += weight*dq->quat[0]; + dqsum->quat[1] += weight*dq->quat[1]; + dqsum->quat[2] += weight*dq->quat[2]; + dqsum->quat[3] += weight*dq->quat[3]; + + dqsum->trans[0] += weight*dq->trans[0]; + dqsum->trans[1] += weight*dq->trans[1]; + dqsum->trans[2] += weight*dq->trans[2]; + dqsum->trans[3] += weight*dq->trans[3]; + + /* interpolate scale - but only if needed */ + if (dq->scale_weight) { + float wmat[4][4]; + + Mat4CpyMat4(wmat, dq->scale); + Mat4MulFloat((float*)wmat, weight); + Mat4AddMat4(dqsum->scale, dqsum->scale, wmat); + dqsum->scale_weight += weight; + } +} + +void DQuatNormalize(DualQuat *dq, float totweight, float factor) +{ + float scale= factor/totweight; + + QuatMulf(dq->quat, scale); + QuatMulf(dq->trans, scale); + + if(dq->scale_weight) { + float addweight= totweight - dq->scale_weight; + + if(addweight) { + dq->scale[0][0] += addweight; + dq->scale[1][1] += addweight; + dq->scale[2][2] += addweight; + dq->scale[3][3] += addweight; + } + + Mat4MulFloat((float*)dq->scale, scale); + dq->scale_weight= 1.0f; + } +} + +void DQuatMulVecfl(DualQuat *dq, float *co, float mat[][3]) +{ + float M[3][3], t[3], scalemat[3][3], len2; + float w= dq->quat[0], x= dq->quat[1], y= dq->quat[2], z= dq->quat[3]; + float t0= dq->trans[0], t1= dq->trans[1], t2= dq->trans[2], t3= dq->trans[3]; + + /* rotation matrix */ + M[0][0]= w*w + x*x - y*y - z*z; + M[1][0]= 2*(x*y - w*z); + M[2][0]= 2*(x*z + w*y); + + M[0][1]= 2*(x*y + w*z); + M[1][1]= w*w + y*y - x*x - z*z; + M[2][1]= 2*(y*z - w*x); + + M[0][2]= 2*(x*z - w*y); + M[1][2]= 2*(y*z + w*x); + M[2][2]= w*w + z*z - x*x - y*y; + + len2= QuatDot(dq->quat, dq->quat); + if(len2 > 0.0f) + len2= 1.0f/len2; + + /* translation */ + t[0]= 2*(-t0*x + w*t1 - t2*z + y*t3); + t[1]= 2*(-t0*y + t1*z - x*t3 + w*t2); + t[2]= 2*(-t0*z + x*t2 + w*t3 - t1*y); + + /* apply scaling */ + if(dq->scale_weight) + Mat4MulVecfl(dq->scale, co); + + /* apply rotation and translation */ + Mat3MulVecfl(M, co); + co[0]= (co[0] + t[0])*len2; + co[1]= (co[1] + t[1])*len2; + co[2]= (co[2] + t[2])*len2; + + /* compute crazyspace correction mat */ + if(mat) { + if(dq->scale_weight) { + Mat3CpyMat4(scalemat, dq->scale); + Mat3MulMat3(mat, M, scalemat); + } + else + Mat3CpyMat3(mat, M); + Mat3MulFloat((float*)mat, len2); + } +} + +void DQuatCpyDQuat(DualQuat *dq1, DualQuat *dq2) +{ + memcpy(dq1, dq2, sizeof(DualQuat)); +} + +/* **************** VIEW / PROJECTION ******************************** */ + + +void i_ortho( + float left, float right, + float bottom, float top, + float nearClip, float farClip, + float matrix[][4] +){ + float Xdelta, Ydelta, Zdelta; + + Xdelta = right - left; + Ydelta = top - bottom; + Zdelta = farClip - nearClip; + if (Xdelta == 0.0 || Ydelta == 0.0 || Zdelta == 0.0) { + return; + } + Mat4One(matrix); + matrix[0][0] = 2.0f/Xdelta; + matrix[3][0] = -(right + left)/Xdelta; + matrix[1][1] = 2.0f/Ydelta; + matrix[3][1] = -(top + bottom)/Ydelta; + matrix[2][2] = -2.0f/Zdelta; /* note: negate Z */ + matrix[3][2] = -(farClip + nearClip)/Zdelta; +} + +void i_window( + float left, float right, + float bottom, float top, + float nearClip, float farClip, + float mat[][4] +){ + float Xdelta, Ydelta, Zdelta; + + Xdelta = right - left; + Ydelta = top - bottom; + Zdelta = farClip - nearClip; + + if (Xdelta == 0.0 || Ydelta == 0.0 || Zdelta == 0.0) { + return; + } + mat[0][0] = nearClip * 2.0f/Xdelta; + mat[1][1] = nearClip * 2.0f/Ydelta; + mat[2][0] = (right + left)/Xdelta; /* note: negate Z */ + mat[2][1] = (top + bottom)/Ydelta; + mat[2][2] = -(farClip + nearClip)/Zdelta; + mat[2][3] = -1.0f; + mat[3][2] = (-2.0f * nearClip * farClip)/Zdelta; + mat[0][1] = mat[0][2] = mat[0][3] = + mat[1][0] = mat[1][2] = mat[1][3] = + mat[3][0] = mat[3][1] = mat[3][3] = 0.0; + +} + +void i_translate(float Tx, float Ty, float Tz, float mat[][4]) +{ + mat[3][0] += (Tx*mat[0][0] + Ty*mat[1][0] + Tz*mat[2][0]); + mat[3][1] += (Tx*mat[0][1] + Ty*mat[1][1] + Tz*mat[2][1]); + mat[3][2] += (Tx*mat[0][2] + Ty*mat[1][2] + Tz*mat[2][2]); +} + +void i_multmatrix( float icand[][4], float Vm[][4]) +{ + int row, col; + float temp[4][4]; + + for(row=0 ; row<4 ; row++) + for(col=0 ; col<4 ; col++) + temp[row][col] = icand[row][0] * Vm[0][col] + + icand[row][1] * Vm[1][col] + + icand[row][2] * Vm[2][col] + + icand[row][3] * Vm[3][col]; + Mat4CpyMat4(Vm, temp); +} + +void i_rotate(float angle, char axis, float mat[][4]) +{ + int col; + float temp[4]; + float cosine, sine; + + for(col=0; col<4 ; col++) /* init temp to zero matrix */ + temp[col] = 0; + + angle = (float)(angle*(3.1415926535/180.0)); + cosine = (float)cos(angle); + sine = (float)sin(angle); + switch(axis){ + case 'x': + case 'X': + for(col=0 ; col<4 ; col++) + temp[col] = cosine*mat[1][col] + sine*mat[2][col]; + for(col=0 ; col<4 ; col++) { + mat[2][col] = - sine*mat[1][col] + cosine*mat[2][col]; + mat[1][col] = temp[col]; + } + break; + + case 'y': + case 'Y': + for(col=0 ; col<4 ; col++) + temp[col] = cosine*mat[0][col] - sine*mat[2][col]; + for(col=0 ; col<4 ; col++) { + mat[2][col] = sine*mat[0][col] + cosine*mat[2][col]; + mat[0][col] = temp[col]; + } + break; + + case 'z': + case 'Z': + for(col=0 ; col<4 ; col++) + temp[col] = cosine*mat[0][col] + sine*mat[1][col]; + for(col=0 ; col<4 ; col++) { + mat[1][col] = - sine*mat[0][col] + cosine*mat[1][col]; + mat[0][col] = temp[col]; + } + break; + } +} + +void i_polarview(float dist, float azimuth, float incidence, float twist, float Vm[][4]) +{ + + Mat4One(Vm); + + i_translate(0.0, 0.0, -dist, Vm); + i_rotate(-twist,'z', Vm); + i_rotate(-incidence,'x', Vm); + i_rotate(-azimuth,'z', Vm); +} + +void i_lookat(float vx, float vy, float vz, float px, float py, float pz, float twist, float mat[][4]) +{ + float sine, cosine, hyp, hyp1, dx, dy, dz; + float mat1[4][4]; + + Mat4One(mat); + Mat4One(mat1); + + i_rotate(-twist,'z', mat); + + dx = px - vx; + dy = py - vy; + dz = pz - vz; + hyp = dx * dx + dz * dz; /* hyp squared */ + hyp1 = (float)sqrt(dy*dy + hyp); + hyp = (float)sqrt(hyp); /* the real hyp */ + + if (hyp1 != 0.0) { /* rotate X */ + sine = -dy / hyp1; + cosine = hyp /hyp1; + } else { + sine = 0; + cosine = 1.0f; + } + mat1[1][1] = cosine; + mat1[1][2] = sine; + mat1[2][1] = -sine; + mat1[2][2] = cosine; + + i_multmatrix(mat1, mat); + + mat1[1][1] = mat1[2][2] = 1.0f; /* be careful here to reinit */ + mat1[1][2] = mat1[2][1] = 0.0; /* those modified by the last */ + + /* paragraph */ + if (hyp != 0.0f) { /* rotate Y */ + sine = dx / hyp; + cosine = -dz / hyp; + } else { + sine = 0; + cosine = 1.0f; + } + mat1[0][0] = cosine; + mat1[0][2] = -sine; + mat1[2][0] = sine; + mat1[2][2] = cosine; + + i_multmatrix(mat1, mat); + i_translate(-vx,-vy,-vz, mat); /* translate viewpoint to origin */ +} + + + + + +/* ************************************************ */ + +void Mat3Ortho(float mat[][3]) +{ + Normalize(mat[0]); + Normalize(mat[1]); + Normalize(mat[2]); +} + +void Mat4Ortho(float mat[][4]) +{ + float len; + + len= Normalize(mat[0]); + if(len!=0.0) mat[0][3]/= len; + len= Normalize(mat[1]); + if(len!=0.0) mat[1][3]/= len; + len= Normalize(mat[2]); + if(len!=0.0) mat[2][3]/= len; +} + +void VecCopyf(float *v1, float *v2) +{ + v1[0]= v2[0]; + v1[1]= v2[1]; + v1[2]= v2[2]; +} + +int VecLen( int *v1, int *v2) +{ + float x,y,z; + + x=(float)(v1[0]-v2[0]); + y=(float)(v1[1]-v2[1]); + z=(float)(v1[2]-v2[2]); + return (int)floor(sqrt(x*x+y*y+z*z)); +} + +float VecLenf( float *v1, float *v2) +{ + float x,y,z; + + x=v1[0]-v2[0]; + y=v1[1]-v2[1]; + z=v1[2]-v2[2]; + return (float)sqrt(x*x+y*y+z*z); +} + +float VecLength(float *v) +{ + return (float) sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); +} + +void VecAddf(float *v, float *v1, float *v2) +{ + v[0]= v1[0]+ v2[0]; + v[1]= v1[1]+ v2[1]; + v[2]= v1[2]+ v2[2]; +} + +void VecSubf(float *v, float *v1, float *v2) +{ + v[0]= v1[0]- v2[0]; + v[1]= v1[1]- v2[1]; + v[2]= v1[2]- v2[2]; +} + +void VecLerpf(float *target, float *a, float *b, float t) +{ + float s = 1.0f-t; + + target[0]= s*a[0] + t*b[0]; + target[1]= s*a[1] + t*b[1]; + target[2]= s*a[2] + t*b[2]; +} + +void VecMidf(float *v, float *v1, float *v2) +{ + v[0]= 0.5f*(v1[0]+ v2[0]); + v[1]= 0.5f*(v1[1]+ v2[1]); + v[2]= 0.5f*(v1[2]+ v2[2]); +} + +void VecMulf(float *v1, float f) +{ + + v1[0]*= f; + v1[1]*= f; + v1[2]*= f; +} + +void VecOrthoBasisf(float *v, float *v1, float *v2) +{ + if (v[0] == 0.0f && v[1] == 0.0f) + { + // degenerate case + v1[0] = 0.0f; v1[1] = 1.0f; v1[2] = 0.0f; + if (v[2] > 0.0f) { + v2[0] = 1.0f; v2[1] = v2[2] = 0.0f; + } + else { + v2[0] = -1.0f; v2[1] = v2[2] = 0.0f; + } + } + else + { + float f = 1.0f/sqrt(v[0]*v[0] + v[1]*v[1]); + v1[0] = v[1]*f; + v1[1] = -v[0]*f; + v1[2] = 0.0f; + + Crossf(v2, v, v1); + } +} + +int VecLenCompare(float *v1, float *v2, float limit) +{ + float x,y,z; + + x=v1[0]-v2[0]; + y=v1[1]-v2[1]; + z=v1[2]-v2[2]; + + return ((x*x + y*y + z*z) < (limit*limit)); +} + +int VecCompare( float *v1, float *v2, float limit) +{ + if( fabs(v1[0]-v2[0])=1.0) { + pt[0]= v3[0]; + pt[1]= v3[1]; + } + else { + pt[0]= labda*rc[0]+v2[0]; + pt[1]= labda*rc[1]+v2[1]; + } + + rc[0]= pt[0]-v1[0]; + rc[1]= pt[1]-v1[1]; + return (float)sqrt(rc[0]*rc[0]+ rc[1]*rc[1]); +} + +float AreaF2Dfl( float *v1, float *v2, float *v3) +{ + return (float)(0.5*fabs( (v1[0]-v2[0])*(v2[1]-v3[1]) + (v1[1]-v2[1])*(v3[0]-v2[0]) )); +} + + +float AreaQ3Dfl( float *v1, float *v2, float *v3, float *v4) /* only convex Quadrilaterals */ +{ + float len, vec1[3], vec2[3], n[3]; + + VecSubf(vec1, v2, v1); + VecSubf(vec2, v4, v1); + Crossf(n, vec1, vec2); + len= Normalize(n); + + VecSubf(vec1, v4, v3); + VecSubf(vec2, v2, v3); + Crossf(n, vec1, vec2); + len+= Normalize(n); + + return (len/2.0f); +} + +float AreaT3Dfl( float *v1, float *v2, float *v3) /* Triangles */ +{ + float len, vec1[3], vec2[3], n[3]; + + VecSubf(vec1, v3, v2); + VecSubf(vec2, v1, v2); + Crossf(n, vec1, vec2); + len= Normalize(n); + + return (len/2.0f); +} + +#define MAX2(x,y) ( (x)>(y) ? (x) : (y) ) +#define MAX3(x,y,z) MAX2( MAX2((x),(y)) , (z) ) + + +float AreaPoly3Dfl(int nr, float *verts, float *normal) +{ + float x, y, z, area, max; + float *cur, *prev; + int a, px=0, py=1; + + /* first: find dominant axis: 0==X, 1==Y, 2==Z */ + x= (float)fabs(normal[0]); + y= (float)fabs(normal[1]); + z= (float)fabs(normal[2]); + max = MAX3(x, y, z); + if(max==y) py=2; + else if(max==x) { + px=1; + py= 2; + } + + /* The Trapezium Area Rule */ + prev= verts+3*(nr-1); + cur= verts; + area= 0; + for(a=0; a=0.0 && labda<=1.0 && mu>=0.0 && mu<=1.0) { + if(labda==0.0 || labda==1.0 || mu==0.0 || mu==1.0) return 1; + return 2; + } + return 0; +} + +/* intersect Line-Line, floats */ +short IsectLL2Df(float *v1, float *v2, float *v3, float *v4) +{ + /* return: + -1: colliniar +0: no intersection of segments +1: exact intersection of segments +2: cross-intersection of segments + */ + float div, labda, mu; + + div= (v2[0]-v1[0])*(v4[1]-v3[1])-(v2[1]-v1[1])*(v4[0]-v3[0]); + if(div==0.0) return -1; + + labda= ((float)(v1[1]-v3[1])*(v4[0]-v3[0])-(v1[0]-v3[0])*(v4[1]-v3[1]))/div; + + mu= ((float)(v1[1]-v3[1])*(v2[0]-v1[0])-(v1[0]-v3[0])*(v2[1]-v1[1]))/div; + + if(labda>=0.0 && labda<=1.0 && mu>=0.0 && mu<=1.0) { + if(labda==0.0 || labda==1.0 || mu==0.0 || mu==1.0) return 1; + return 2; + } + return 0; +} + +void MinMax3(float *min, float *max, float *vec) +{ + if(min[0]>vec[0]) min[0]= vec[0]; + if(min[1]>vec[1]) min[1]= vec[1]; + if(min[2]>vec[2]) min[2]= vec[2]; + + if(max[0]=xn && zn>=yn) {i= 0; j= 1;} + else if(yn>=xn && yn>=zn) {i= 0; j= 2;} + else {i= 1; j= 2;} + + a1= TriSignedArea(v2, v3, co, i, j); + a2= TriSignedArea(v3, v1, co, i, j); + a3= TriSignedArea(v1, v2, co, i, j); + + asum= a1 + a2 + a3; + + if (fabs(asum) < FLT_EPSILON) { + /* zero area triangle */ + w[0]= w[1]= w[2]= 1.0f/3.0f; + return 1; + } + + asum= 1.0f/asum; + w[0]= a1*asum; + w[1]= a2*asum; + w[2]= a3*asum; + + return 0; +} + +void InterpWeightsQ3Dfl(float *v1, float *v2, float *v3, float *v4, float *co, float *w) +{ + float w2[3]; + + w[0]= w[1]= w[2]= w[3]= 0.0f; + + /* first check for exact match */ + if(VecEqual(co, v1)) + w[0]= 1.0f; + else if(VecEqual(co, v2)) + w[1]= 1.0f; + else if(VecEqual(co, v3)) + w[2]= 1.0f; + else if(v4 && VecEqual(co, v4)) + w[3]= 1.0f; + else { + /* otherwise compute barycentric interpolation weights */ + float n1[3], n2[3], n[3]; + int degenerate; + + VecSubf(n1, v1, v3); + if (v4) { + VecSubf(n2, v2, v4); + } + else { + VecSubf(n2, v2, v3); + } + Crossf(n, n1, n2); + + /* OpenGL seems to split this way, so we do too */ + if (v4) { + degenerate= BarycentricWeights(v1, v2, v4, co, n, w); + SWAP(float, w[2], w[3]); + + if(degenerate || (w[0] < 0.0f)) { + /* if w[1] is negative, co is on the other side of the v1-v3 edge, + so we interpolate using the other triangle */ + degenerate= BarycentricWeights(v2, v3, v4, co, n, w2); + + if(!degenerate) { + w[0]= 0.0f; + w[1]= w2[0]; + w[2]= w2[1]; + w[3]= w2[2]; + } + } + } + else + BarycentricWeights(v1, v2, v3, co, n, w); + } +} + +/* Mean value weights - smooth interpolation weights for polygons with + * more than 3 vertices */ +static float MeanValueHalfTan(float *v1, float *v2, float *v3) +{ + float d2[3], d3[3], cross[3], area, dot, len; + + VecSubf(d2, v2, v1); + VecSubf(d3, v3, v1); + Crossf(cross, d2, d3); + + area= VecLength(cross); + dot= Inpf(d2, d3); + len= VecLength(d2)*VecLength(d3); + + if(area == 0.0f) + return 0.0f; + else + return (len - dot)/area; +} + +void MeanValueWeights(float v[][3], int n, float *co, float *w) +{ + float totweight, t1, t2, len, *vmid, *vprev, *vnext; + int i; + + totweight= 0.0f; + + for(i=0; i 16.0*FLT_EPSILON) { + + eul1[0] = (float)atan2(mat[1][2], mat[2][2]); + eul1[1] = (float)atan2(-mat[0][2], cy); + eul1[2] = (float)atan2(mat[0][1], mat[0][0]); + + eul2[0] = (float)atan2(-mat[1][2], -mat[2][2]); + eul2[1] = (float)atan2(-mat[0][2], -cy); + eul2[2] = (float)atan2(-mat[0][1], -mat[0][0]); + + } else { + eul1[0] = (float)atan2(-mat[2][1], mat[1][1]); + eul1[1] = (float)atan2(-mat[0][2], cy); + eul1[2] = 0.0f; + + VecCopyf(eul2, eul1); + } +} + +void Mat3ToEul(float tmat[][3], float *eul) +{ + float eul1[3], eul2[3]; + + mat3_to_eul2(tmat, eul1, eul2); + + /* return best, which is just the one with lowest values it in */ + if( fabs(eul1[0])+fabs(eul1[1])+fabs(eul1[2]) > fabs(eul2[0])+fabs(eul2[1])+fabs(eul2[2])) { + VecCopyf(eul, eul2); + } + else { + VecCopyf(eul, eul1); + } +} + +void Mat4ToEul(float tmat[][4], float *eul) +{ + float tempMat[3][3]; + + Mat3CpyMat4 (tempMat, tmat); + Mat3Ortho(tempMat); + Mat3ToEul(tempMat, eul); +} + +void QuatToEul( float *quat, float *eul) +{ + float mat[3][3]; + + QuatToMat3(quat, mat); + Mat3ToEul(mat, eul); +} + + +void EulToQuat( float *eul, float *quat) +{ + float ti, tj, th, ci, cj, ch, si, sj, sh, cc, cs, sc, ss; + + ti = eul[0]*0.5f; tj = eul[1]*0.5f; th = eul[2]*0.5f; + ci = (float)cos(ti); cj = (float)cos(tj); ch = (float)cos(th); + si = (float)sin(ti); sj = (float)sin(tj); sh = (float)sin(th); + cc = ci*ch; cs = ci*sh; sc = si*ch; ss = si*sh; + + quat[0] = cj*cc + sj*ss; + quat[1] = cj*sc - sj*cs; + quat[2] = cj*ss + sj*cc; + quat[3] = cj*cs - sj*sc; +} + +void VecRotToMat3( float *vec, float phi, float mat[][3]) +{ + /* rotation of phi radials around vec */ + float vx, vx2, vy, vy2, vz, vz2, co, si; + + vx= vec[0]; + vy= vec[1]; + vz= vec[2]; + vx2= vx*vx; + vy2= vy*vy; + vz2= vz*vz; + co= (float)cos(phi); + si= (float)sin(phi); + + mat[0][0]= vx2+co*(1.0f-vx2); + mat[0][1]= vx*vy*(1.0f-co)+vz*si; + mat[0][2]= vz*vx*(1.0f-co)-vy*si; + mat[1][0]= vx*vy*(1.0f-co)-vz*si; + mat[1][1]= vy2+co*(1.0f-vy2); + mat[1][2]= vy*vz*(1.0f-co)+vx*si; + mat[2][0]= vz*vx*(1.0f-co)+vy*si; + mat[2][1]= vy*vz*(1.0f-co)-vx*si; + mat[2][2]= vz2+co*(1.0f-vz2); + +} + +void VecRotToMat4( float *vec, float phi, float mat[][4]) +{ + float tmat[3][3]; + + VecRotToMat3(vec, phi, tmat); + Mat4One(mat); + Mat4CpyMat3(mat, tmat); +} + +void VecRotToQuat( float *vec, float phi, float *quat) +{ + /* rotation of phi radials around vec */ + float si; + + quat[1]= vec[0]; + quat[2]= vec[1]; + quat[3]= vec[2]; + + if( Normalize(quat+1) == 0.0) { + QuatOne(quat); + } + else { + quat[0]= (float)cos( phi/2.0 ); + si= (float)sin( phi/2.0 ); + quat[1] *= si; + quat[2] *= si; + quat[3] *= si; + } +} + +/* Return the angle in degrees between vecs 1-2 and 2-3 in degrees + If v1 is a shoulder, v2 is the elbow and v3 is the hand, + this would return the angle at the elbow */ +float VecAngle3(float *v1, float *v2, float *v3) +{ + float vec1[3], vec2[3]; + + VecSubf(vec1, v2, v1); + VecSubf(vec2, v2, v3); + Normalize(vec1); + Normalize(vec2); + + return NormalizedVecAngle2(vec1, vec2) * 180.0/M_PI; +} + +/* Return the shortest angle in degrees between the 2 vectors */ +float VecAngle2(float *v1, float *v2) +{ + float vec1[3], vec2[3]; + + VecCopyf(vec1, v1); + VecCopyf(vec2, v2); + Normalize(vec1); + Normalize(vec2); + + return NormalizedVecAngle2(vec1, vec2)* 180.0/M_PI; +} + +float NormalizedVecAngle2(float *v1, float *v2) +{ + /* this is the same as acos(Inpf(v1, v2)), but more accurate */ + if (Inpf(v1, v2) < 0.0f) { + float vec[3]; + + vec[0]= -v2[0]; + vec[1]= -v2[1]; + vec[2]= -v2[2]; + + return (float)M_PI - 2.0f*saasin(VecLenf(vec, v1)/2.0f); + } + else + return 2.0f*saasin(VecLenf(v2, v1)/2.0); +} + +void euler_rot(float *beul, float ang, char axis) +{ + float eul[3], mat1[3][3], mat2[3][3], totmat[3][3]; + + eul[0]= eul[1]= eul[2]= 0.0; + if(axis=='x') eul[0]= ang; + else if(axis=='y') eul[1]= ang; + else eul[2]= ang; + + EulToMat3(eul, mat1); + EulToMat3(beul, mat2); + + Mat3MulMat3(totmat, mat2, mat1); + + Mat3ToEul(totmat, beul); + +} + +/* exported to transform.c */ +void compatible_eul(float *eul, float *oldrot) +{ + float dx, dy, dz; + + /* correct differences of about 360 degrees first */ + + dx= eul[0] - oldrot[0]; + dy= eul[1] - oldrot[1]; + dz= eul[2] - oldrot[2]; + + while( fabs(dx) > 5.1) { + if(dx > 0.0) eul[0] -= 2.0*M_PI; else eul[0]+= 2.0*M_PI; + dx= eul[0] - oldrot[0]; + } + while( fabs(dy) > 5.1) { + if(dy > 0.0) eul[1] -= 2.0*M_PI; else eul[1]+= 2.0*M_PI; + dy= eul[1] - oldrot[1]; + } + while( fabs(dz) > 5.1 ) { + if(dz > 0.0) eul[2] -= 2.0*M_PI; else eul[2]+= 2.0*M_PI; + dz= eul[2] - oldrot[2]; + } + + /* is 1 of the axis rotations larger than 180 degrees and the other small? NO ELSE IF!! */ + if( fabs(dx) > 3.2 && fabs(dy)<1.6 && fabs(dz)<1.6 ) { + if(dx > 0.0) eul[0] -= 2.0*M_PI; else eul[0]+= 2.0*M_PI; + } + if( fabs(dy) > 3.2 && fabs(dz)<1.6 && fabs(dx)<1.6 ) { + if(dy > 0.0) eul[1] -= 2.0*M_PI; else eul[1]+= 2.0*M_PI; + } + if( fabs(dz) > 3.2 && fabs(dx)<1.6 && fabs(dy)<1.6 ) { + if(dz > 0.0) eul[2] -= 2.0*M_PI; else eul[2]+= 2.0*M_PI; + } + + /* the method below was there from ancient days... but why! probably because the code sucks :) + */ +#if 0 + /* calc again */ + dx= eul[0] - oldrot[0]; + dy= eul[1] - oldrot[1]; + dz= eul[2] - oldrot[2]; + + /* special case, tested for x-z */ + + if( (fabs(dx) > 3.1 && fabs(dz) > 1.5 ) || ( fabs(dx) > 1.5 && fabs(dz) > 3.1 ) ) { + if(dx > 0.0) eul[0] -= M_PI; else eul[0]+= M_PI; + if(eul[1] > 0.0) eul[1]= M_PI - eul[1]; else eul[1]= -M_PI - eul[1]; + if(dz > 0.0) eul[2] -= M_PI; else eul[2]+= M_PI; + + } + else if( (fabs(dx) > 3.1 && fabs(dy) > 1.5 ) || ( fabs(dx) > 1.5 && fabs(dy) > 3.1 ) ) { + if(dx > 0.0) eul[0] -= M_PI; else eul[0]+= M_PI; + if(dy > 0.0) eul[1] -= M_PI; else eul[1]+= M_PI; + if(eul[2] > 0.0) eul[2]= M_PI - eul[2]; else eul[2]= -M_PI - eul[2]; + } + else if( (fabs(dy) > 3.1 && fabs(dz) > 1.5 ) || ( fabs(dy) > 1.5 && fabs(dz) > 3.1 ) ) { + if(eul[0] > 0.0) eul[0]= M_PI - eul[0]; else eul[0]= -M_PI - eul[0]; + if(dy > 0.0) eul[1] -= M_PI; else eul[1]+= M_PI; + if(dz > 0.0) eul[2] -= M_PI; else eul[2]+= M_PI; + } +#endif +} + +/* uses 2 methods to retrieve eulers, and picks the closest */ +void Mat3ToCompatibleEul(float mat[][3], float *eul, float *oldrot) +{ + float eul1[3], eul2[3]; + float d1, d2; + + mat3_to_eul2(mat, eul1, eul2); + + compatible_eul(eul1, oldrot); + compatible_eul(eul2, oldrot); + + d1= fabs(eul1[0]-oldrot[0]) + fabs(eul1[1]-oldrot[1]) + fabs(eul1[2]-oldrot[2]); + d2= fabs(eul2[0]-oldrot[0]) + fabs(eul2[1]-oldrot[1]) + fabs(eul2[2]-oldrot[2]); + + /* return best, which is just the one with lowest difference */ + if( d1 > d2) { + VecCopyf(eul, eul2); + } + else { + VecCopyf(eul, eul1); + } + +} + +/* ******************************************** */ + +void SizeToMat3( float *size, float mat[][3]) +{ + mat[0][0]= size[0]; + mat[0][1]= 0.0; + mat[0][2]= 0.0; + mat[1][1]= size[1]; + mat[1][0]= 0.0; + mat[1][2]= 0.0; + mat[2][2]= size[2]; + mat[2][1]= 0.0; + mat[2][0]= 0.0; +} + +void SizeToMat4( float *size, float mat[][4]) +{ + float tmat[3][3]; + + SizeToMat3(size, tmat); + Mat4One(mat); + Mat4CpyMat3(mat, tmat); +} + +void Mat3ToSize( float mat[][3], float *size) +{ + size[0]= VecLength(mat[0]); + size[1]= VecLength(mat[1]); + size[2]= VecLength(mat[2]); +} + +void Mat4ToSize( float mat[][4], float *size) +{ + size[0]= VecLength(mat[0]); + size[1]= VecLength(mat[1]); + size[2]= VecLength(mat[2]); +} + +/* this gets the average scale of a matrix, only use when your scaling + * data that has no idea of scale axis, examples are bone-envelope-radius + * and curve radius */ +float Mat3ToScalef(float mat[][3]) +{ + /* unit length vector */ + float unit_vec[3] = {0.577350269189626, 0.577350269189626, 0.577350269189626}; + Mat3MulVecfl(mat, unit_vec); + return VecLength(unit_vec); +} + +float Mat4ToScalef(float mat[][4]) +{ + float tmat[3][3]; + Mat3CpyMat4(tmat, mat); + return Mat3ToScalef(tmat); +} + + +/* ************* SPECIALS ******************* */ + +void triatoquat( float *v1, float *v2, float *v3, float *quat) +{ + /* imaginary x-axis, y-axis triangle is being rotated */ + float vec[3], q1[4], q2[4], n[3], si, co, angle, mat[3][3], imat[3][3]; + + /* move z-axis to face-normal */ + CalcNormFloat(v1, v2, v3, vec); + + n[0]= vec[1]; + n[1]= -vec[0]; + n[2]= 0.0; + Normalize(n); + + if(n[0]==0.0 && n[1]==0.0) n[0]= 1.0; + + angle= -0.5f*saacos(vec[2]); + co= (float)cos(angle); + si= (float)sin(angle); + q1[0]= co; + q1[1]= n[0]*si; + q1[2]= n[1]*si; + q1[3]= 0.0f; + + /* rotate back line v1-v2 */ + QuatToMat3(q1, mat); + Mat3Inv(imat, mat); + VecSubf(vec, v2, v1); + Mat3MulVecfl(imat, vec); + + /* what angle has this line with x-axis? */ + vec[2]= 0.0; + Normalize(vec); + + angle= (float)(0.5*atan2(vec[1], vec[0])); + co= (float)cos(angle); + si= (float)sin(angle); + q2[0]= co; + q2[1]= 0.0f; + q2[2]= 0.0f; + q2[3]= si; + + QuatMul(quat, q1, q2); +} + +void MinMaxRGB(short c[]) +{ + if(c[0]>255) c[0]=255; + else if(c[0]<0) c[0]=0; + if(c[1]>255) c[1]=255; + else if(c[1]<0) c[1]=0; + if(c[2]>255) c[2]=255; + else if(c[2]<0) c[2]=0; +} + +float Vec2Lenf(float *v1, float *v2) +{ + float x, y; + + x = v1[0]-v2[0]; + y = v1[1]-v2[1]; + return (float)sqrt(x*x+y*y); +} + +void Vec2Mulf(float *v1, float f) +{ + v1[0]*= f; + v1[1]*= f; +} + +void Vec2Addf(float *v, float *v1, float *v2) +{ + v[0]= v1[0]+ v2[0]; + v[1]= v1[1]+ v2[1]; +} + +void Vec2Subf(float *v, float *v1, float *v2) +{ + v[0]= v1[0]- v2[0]; + v[1]= v1[1]- v2[1]; +} + +void Vec2Copyf(float *v1, float *v2) +{ + v1[0]= v2[0]; + v1[1]= v2[1]; +} + +float Inp2f(float *v1, float *v2) +{ + return v1[0]*v2[0]+v1[1]*v2[1]; +} + +float Normalize2(float *n) +{ + float d; + + d= n[0]*n[0]+n[1]*n[1]; + + if(d>1.0e-35F) { + d= (float)sqrt(d); + + n[0]/=d; + n[1]/=d; + } else { + n[0]=n[1]= 0.0; + d= 0.0; + } + return d; +} + +void hsv_to_rgb(float h, float s, float v, float *r, float *g, float *b) +{ + int i; + float f, p, q, t; + + h *= 360.0f; + + if(s==0.0) { + *r = v; + *g = v; + *b = v; + } + else { + if(h==360) h = 0; + + h /= 60; + i = (int)floor(h); + f = h - i; + p = v*(1.0f-s); + q = v*(1.0f-(s*f)); + t = v*(1.0f-(s*(1.0f-f))); + + switch (i) { + case 0 : + *r = v; + *g = t; + *b = p; + break; + case 1 : + *r = q; + *g = v; + *b = p; + break; + case 2 : + *r = p; + *g = v; + *b = t; + break; + case 3 : + *r = p; + *g = q; + *b = v; + break; + case 4 : + *r = t; + *g = p; + *b = v; + break; + case 5 : + *r = v; + *g = p; + *b = q; + break; + } + } +} + +void rgb_to_yuv(float r, float g, float b, float *ly, float *lu, float *lv) +{ + float y, u, v; + y= 0.299*r + 0.587*g + 0.114*b; + u=-0.147*r - 0.289*g + 0.436*b; + v= 0.615*r - 0.515*g - 0.100*b; + + *ly=y; + *lu=u; + *lv=v; +} + +void yuv_to_rgb(float y, float u, float v, float *lr, float *lg, float *lb) +{ + float r, g, b; + r=y+1.140*v; + g=y-0.394*u - 0.581*v; + b=y+2.032*u; + + *lr=r; + *lg=g; + *lb=b; +} + +void rgb_to_ycc(float r, float g, float b, float *ly, float *lcb, float *lcr) +{ + float sr,sg, sb; + float y, cr, cb; + + sr=255.0*r; + sg=255.0*g; + sb=255.0*b; + + + y=(0.257*sr)+(0.504*sg)+(0.098*sb)+16.0; + cb=(-0.148*sr)-(0.291*sg)+(0.439*sb)+128.0; + cr=(0.439*sr)-(0.368*sg)-(0.071*sb)+128.0; + + *ly=y; + *lcb=cb; + *lcr=cr; +} + +void ycc_to_rgb(float y, float cb, float cr, float *lr, float *lg, float *lb) +{ + float r,g,b; + + r=1.164*(y-16)+1.596*(cr-128); + g=1.164*(y-16)-0.813*(cr-128)-0.392*(cb-128); + b=1.164*(y-16)+2.017*(cb-128); + + *lr=r/255.0; + *lg=g/255.0; + *lb=b/255.0; +} + +void hex_to_rgb(char *hexcol, float *r, float *g, float *b) +{ + unsigned int ri, gi, bi; + + if (hexcol[0] == '#') hexcol++; + + if (sscanf(hexcol, "%02x%02x%02x", &ri, &gi, &bi)) { + *r = ri / 255.0; + *g = gi / 255.0; + *b = bi / 255.0; + } +} + +void rgb_to_hsv(float r, float g, float b, float *lh, float *ls, float *lv) +{ + float h, s, v; + float cmax, cmin, cdelta; + float rc, gc, bc; + + cmax = r; + cmin = r; + cmax = (g>cmax ? g:cmax); + cmin = (gcmax ? b:cmax); + cmin = (b255) ir= 255; + ig= (int)floor(255.0*g); + if(ig<0) ig= 0; else if(ig>255) ig= 255; + ib= (int)floor(255.0*b); + if(ib<0) ib= 0; else if(ib>255) ib= 255; + + return (ir+ (ig*256) + (ib*256*256)); +} + +void cpack_to_rgb(unsigned int col, float *r, float *g, float *b) +{ + + *r= (float)((col)&0xFF); + *r /= 255.0f; + + *g= (float)(((col)>>8)&0xFF); + *g /= 255.0f; + + *b= (float)(((col)>>16)&0xFF); + *b /= 255.0f; +} + + +/* *************** PROJECTIONS ******************* */ + +void tubemap(float x, float y, float z, float *u, float *v) +{ + float len; + + *v = (z + 1.0) / 2.0; + + len= sqrt(x*x+y*y); + if(len>0) { + *u = (1.0 - (atan2(x/len,y/len) / M_PI)) / 2.0; + } +} + +/* ------------------------------------------------------------------------- */ + +void spheremap(float x, float y, float z, float *u, float *v) +{ + float len; + + len= sqrt(x*x+y*y+z*z); + if(len>0.0) { + + if(x==0.0 && y==0.0) *u= 0.0; /* othwise domain error */ + else *u = (1.0 - atan2(x,y)/M_PI )/2.0; + + z/=len; + *v = 1.0- saacos(z)/M_PI; + } +} + +/* ------------------------------------------------------------------------- */ + +/* ***************** m1 = m2 ***************** */ +void cpy_m3_m3(float m1[][3], float m2[][3]) +{ + memcpy(m1[0], m2[0], 9*sizeof(float)); +} + +/* ***************** m1 = m2 ***************** */ +void cpy_m4_m4(float m1[][4], float m2[][4]) +{ + memcpy(m1[0], m2[0], 16*sizeof(float)); +} + +/* ***************** identity matrix ***************** */ +void ident_m4(float m[][4]) +{ + + m[0][0]= m[1][1]= m[2][2]= m[3][3]= 1.0; + m[0][1]= m[0][2]= m[0][3]= 0.0; + m[1][0]= m[1][2]= m[1][3]= 0.0; + m[2][0]= m[2][1]= m[2][3]= 0.0; + m[3][0]= m[3][1]= m[3][2]= 0.0; +} + + +/* ***************** m1 = m2 (pre) * m3 (post) ***************** */ +void mul_m3_m3m3(float m1[][3], float m2[][3], float m3[][3]) +{ + float m[3][3]; + + m[0][0]= m2[0][0]*m3[0][0] + m2[1][0]*m3[0][1] + m2[2][0]*m3[0][2]; + m[0][1]= m2[0][1]*m3[0][0] + m2[1][1]*m3[0][1] + m2[2][1]*m3[0][2]; + m[0][2]= m2[0][2]*m3[0][0] + m2[1][2]*m3[0][1] + m2[2][2]*m3[0][2]; + + m[1][0]= m2[0][0]*m3[1][0] + m2[1][0]*m3[1][1] + m2[2][0]*m3[1][2]; + m[1][1]= m2[0][1]*m3[1][0] + m2[1][1]*m3[1][1] + m2[2][1]*m3[1][2]; + m[1][2]= m2[0][2]*m3[1][0] + m2[1][2]*m3[1][1] + m2[2][2]*m3[1][2]; + + m[2][0]= m2[0][0]*m3[2][0] + m2[1][0]*m3[2][1] + m2[2][0]*m3[2][2]; + m[2][1]= m2[0][1]*m3[2][0] + m2[1][1]*m3[2][1] + m2[2][1]*m3[2][2]; + m[2][2]= m2[0][2]*m3[2][0] + m2[1][2]*m3[2][1] + m2[2][2]*m3[2][2]; + + cpy_m3_m3(m1, m2); +} + +/* ***************** m1 = m2 (pre) * m3 (post) ***************** */ +void mul_m4_m4m4(float m1[][4], float m2[][4], float m3[][4]) +{ + float m[4][4]; + + m[0][0]= m2[0][0]*m3[0][0] + m2[1][0]*m3[0][1] + m2[2][0]*m3[0][2] + m2[3][0]*m3[0][3]; + m[0][1]= m2[0][1]*m3[0][0] + m2[1][1]*m3[0][1] + m2[2][1]*m3[0][2] + m2[3][1]*m3[0][3]; + m[0][2]= m2[0][2]*m3[0][0] + m2[1][2]*m3[0][1] + m2[2][2]*m3[0][2] + m2[3][2]*m3[0][3]; + m[0][3]= m2[0][3]*m3[0][0] + m2[1][3]*m3[0][1] + m2[2][3]*m3[0][2] + m2[3][3]*m3[0][3]; + + m[1][0]= m2[0][0]*m3[1][0] + m2[1][0]*m3[1][1] + m2[2][0]*m3[1][2] + m2[3][0]*m3[1][3]; + m[1][1]= m2[0][1]*m3[1][0] + m2[1][1]*m3[1][1] + m2[2][1]*m3[1][2] + m2[3][1]*m3[1][3]; + m[1][2]= m2[0][2]*m3[1][0] + m2[1][2]*m3[1][1] + m2[2][2]*m3[1][2] + m2[3][2]*m3[1][3]; + m[1][3]= m2[0][3]*m3[1][0] + m2[1][3]*m3[1][1] + m2[2][3]*m3[1][2] + m2[3][3]*m3[1][3]; + + m[2][0]= m2[0][0]*m3[2][0] + m2[1][0]*m3[2][1] + m2[2][0]*m3[2][2] + m2[3][0]*m3[2][3]; + m[2][1]= m2[0][1]*m3[2][0] + m2[1][1]*m3[2][1] + m2[2][1]*m3[2][2] + m2[3][1]*m3[2][3]; + m[2][2]= m2[0][2]*m3[2][0] + m2[1][2]*m3[2][1] + m2[2][2]*m3[2][2] + m2[3][2]*m3[2][3]; + m[2][3]= m2[0][3]*m3[2][0] + m2[1][3]*m3[2][1] + m2[2][3]*m3[2][2] + m2[3][3]*m3[2][3]; + + m[3][0]= m2[0][0]*m3[3][0] + m2[1][0]*m3[3][1] + m2[2][0]*m3[3][2] + m2[3][0]*m3[3][3]; + m[3][1]= m2[0][1]*m3[3][0] + m2[1][1]*m3[3][1] + m2[2][1]*m3[3][2] + m2[3][1]*m3[3][3]; + m[3][2]= m2[0][2]*m3[3][0] + m2[1][2]*m3[3][1] + m2[2][2]*m3[3][2] + m2[3][2]*m3[3][3]; + m[3][3]= m2[0][3]*m3[3][0] + m2[1][3]*m3[3][1] + m2[2][3]*m3[3][2] + m2[3][3]*m3[3][3]; + + cpy_m4_m4(m1, m2); +} + +/* ***************** m1 = inverse(m2) ***************** */ +void inv_m3_m3(float m1[][3], float m2[][3]) +{ + short a,b; + float det; + + /* calc adjoint */ + Mat3Adj(m1, m2); + + /* then determinant old matrix! */ + det= m2[0][0]* (m2[1][1]*m2[2][2] - m2[1][2]*m2[2][1]) + -m2[1][0]* (m2[0][1]*m2[2][2] - m2[0][2]*m2[2][1]) + +m2[2][0]* (m2[0][1]*m2[1][2] - m2[0][2]*m2[1][1]); + + if(det==0.0f) det=1.0f; + det= 1.0f/det; + for(a=0;a<3;a++) { + for(b=0;b<3;b++) { + m1[a][b]*=det; + } + } +} + +/* ***************** m1 = inverse(m2) ***************** */ +int inv_m4_m4(float inverse[][4], float mat[][4]) +{ + int i, j, k; + double temp; + float tempmat[4][4]; + float max; + int maxj; + + /* Set inverse to identity */ + ident_m4(inverse); + + /* Copy original matrix so we don't mess it up */ + cpy_m4_m4(tempmat, mat); + + for(i = 0; i < 4; i++) { + /* Look for row with max pivot */ + max = ABS(tempmat[i][i]); + maxj = i; + for(j = i + 1; j < 4; j++) { + if(ABS(tempmat[j][i]) > max) { + max = ABS(tempmat[j][i]); + maxj = j; + } + } + /* Swap rows if necessary */ + if (maxj != i) { + for( k = 0; k < 4; k++) { + SWAP(float, tempmat[i][k], tempmat[maxj][k]); + SWAP(float, inverse[i][k], inverse[maxj][k]); + } + } + + temp = tempmat[i][i]; + if (temp == 0) + return 0; /* No non-zero pivot */ + for(k = 0; k < 4; k++) { + tempmat[i][k] = (float)(tempmat[i][k]/temp); + inverse[i][k] = (float)(inverse[i][k]/temp); + } + for(j = 0; j < 4; j++) { + if(j != i) { + temp = tempmat[j][i]; + for(k = 0; k < 4; k++) { + tempmat[j][k] -= (float)(tempmat[i][k]*temp); + inverse[j][k] -= (float)(inverse[i][k]*temp); + } + } + } + } + return 1; +} + +/* ***************** v1 = v2 * mat ***************** */ +void mul_v3_v3m4(float *v1, float *v2, float mat[][4]) +{ + float x, y; + + x= v2[0]; /* work with a copy, v1 can be same as v2 */ + y= v2[1]; + v1[0]= x*mat[0][0] + y*mat[1][0] + mat[2][0]*v2[2] + mat[3][0]; + v1[1]= x*mat[0][1] + y*mat[1][1] + mat[2][1]*v2[2] + mat[3][1]; + v1[2]= x*mat[0][2] + y*mat[1][2] + mat[2][2]*v2[2] + mat[3][2]; + +} + +/* moved from effect.c + test if the line starting at p1 ending at p2 intersects the triangle v0..v2 + return non zero if it does +*/ +int LineIntersectsTriangle(float p1[3], float p2[3], float v0[3], float v1[3], float v2[3], float *lambda) +{ + + float p[3], s[3], d[3], e1[3], e2[3], q[3]; + float a, f, u, v; + + VecSubf(e1, v1, v0); + VecSubf(e2, v2, v0); + VecSubf(d, p2, p1); + + Crossf(p, d, e2); + a = Inpf(e1, p); + if ((a > -0.000001) && (a < 0.000001)) return 0; + f = 1.0f/a; + + VecSubf(s, p1, v0); + + Crossf(q, s, e1); + *lambda = f * Inpf(e2, q); + if ((*lambda < 0.0)||(*lambda > 1.0)) return 0; + + u = f * Inpf(s, p); + if ((u < 0.0)||(u > 1.0)) return 0; + + v = f * Inpf(d, q); + if ((v < 0.0)||((u + v) > 1.0)) return 0; + + return 1; +} + + +/* +find closest point to p on line through l1,l2 +and return lambda, where (0 <= lambda <= 1) when cp is in the line segement l1,l2 +*/ +float lambda_cp_line_ex(float p[3], float l1[3], float l2[3], float cp[3]) +{ + float h[3],u[3],lambda; + VecSubf(u, l2, l1); + VecSubf(h, p, l1); + lambda =Inpf(u,h)/Inpf(u,u); + cp[0] = l1[0] + u[0] * lambda; + cp[1] = l1[1] + u[1] * lambda; + cp[2] = l1[2] + u[2] * lambda; + return lambda; +} +/* little sister we only need to know lambda */ +float lambda_cp_line(float p[3], float l1[3], float l2[3]) +{ + float h[3],u[3]; + VecSubf(u, l2, l1); + VecSubf(h, p, l1); + return(Inpf(u,h)/Inpf(u,u)); +} + + + +int point_in_slice(float p[3], float v1[3], float l1[3], float l2[3]) +{ +/* +what is a slice ? +some maths: +a line including l1,l2 and a point not on the line +define a subset of R3 delimeted by planes parallel to the line and orthogonal +to the (point --> line) distance vector,one plane on the line one on the point, +the room inside usually is rather small compared to R3 though still infinte +useful for restricting (speeding up) searches +e.g. all points of triangular prism are within the intersection of 3 'slices' +onother trivial case : cube +but see a 'spat' which is a deformed cube with paired parallel planes needs only 3 slices too +*/ + float h,rp[3],cp[3],q[3]; + + lambda_cp_line_ex(v1,l1,l2,cp); + VecSubf(q,cp,v1); + + VecSubf(rp,p,v1); + h=Inpf(q,rp)/Inpf(q,q); + if (h < 0.0f || h > 1.0f) return 0; + return 1; +} + +/*adult sister defining the slice planes by the origin and the normal +NOTE |normal| may not be 1 but defining the thickness of the slice*/ +int point_in_slice_as(float p[3],float origin[3],float normal[3]) +{ + float h,rp[3]; + VecSubf(rp,p,origin); + h=Inpf(normal,rp)/Inpf(normal,normal); + if (h < 0.0f || h > 1.0f) return 0; + return 1; +} + +/*mama (knowing the squared lenght of the normal)*/ +int point_in_slice_m(float p[3],float origin[3],float normal[3],float lns) +{ + float h,rp[3]; + VecSubf(rp,p,origin); + h=Inpf(normal,rp)/lns; + if (h < 0.0f || h > 1.0f) return 0; + return 1; +} + + +int point_in_tri_prism(float p[3], float v1[3], float v2[3], float v3[3]) +{ + if(!point_in_slice(p,v1,v2,v3)) return 0; + if(!point_in_slice(p,v2,v3,v1)) return 0; + if(!point_in_slice(p,v3,v1,v2)) return 0; + return 1; +} + +/* point closest to v1 on line v2-v3 in 3D */ +void PclosestVL3Dfl(float *closest, float *v1, float *v2, float *v3) +{ + float lambda, cp[3]; + + lambda= lambda_cp_line_ex(v1, v2, v3, cp); + + if(lambda <= 0.0f) + VecCopyf(closest, v2); + else if(lambda >= 1.0f) + VecCopyf(closest, v3); + else + VecCopyf(closest, cp); +} + +/* distance v1 to line-piece v2-v3 in 3D */ +float PdistVL3Dfl(float *v1, float *v2, float *v3) +{ + float closest[3]; + + PclosestVL3Dfl(closest, v1, v2, v3); + + return VecLenf(closest, v1); +} + +/********************************************************/ + +/* make a 4x4 matrix out of 3 transform components */ +/* matrices are made in the order: scale * rot * loc */ +void LocEulSizeToMat4(float mat[][4], float loc[3], float eul[3], float size[3]) +{ + float rmat[3][3], smat[3][3], tmat[3][3]; + + /* initialise new matrix */ + Mat4One(mat); + + /* make rotation + scaling part */ + EulToMat3(eul, rmat); + SizeToMat3(size, smat); + Mat3MulMat3(tmat, rmat, smat); + + /* copy rot/scale part to output matrix*/ + Mat4CpyMat3(mat, tmat); + + /* copy location to matrix */ + mat[3][0] = loc[0]; + mat[3][1] = loc[1]; + mat[3][2] = loc[2]; +} + +/* make a 4x4 matrix out of 3 transform components */ +/* matrices are made in the order: scale * rot * loc */ +void LocQuatSizeToMat4(float mat[][4], float loc[3], float quat[4], float size[3]) +{ + float rmat[3][3], smat[3][3], tmat[3][3]; + + /* initialise new matrix */ + Mat4One(mat); + + /* make rotation + scaling part */ + QuatToMat3(quat, rmat); + SizeToMat3(size, smat); + Mat3MulMat3(tmat, rmat, smat); + + /* copy rot/scale part to output matrix*/ + Mat4CpyMat3(mat, tmat); + + /* copy location to matrix */ + mat[3][0] = loc[0]; + mat[3][1] = loc[1]; + mat[3][2] = loc[2]; +} diff --git a/source/blender/blenlib/intern/boxpack2d.c b/source/blender/blenlib/intern/boxpack2d.c new file mode 100644 index 00000000000..42092bc54c3 --- /dev/null +++ b/source/blender/blenlib/intern/boxpack2d.c @@ -0,0 +1,416 @@ +/* + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Campbell barton + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include + +#include "BKE_utildefines.h" +#include "MEM_guardedalloc.h" +#include "BLI_boxpack2d.h" + +/* BoxPacker ported from Python by Campbell Barton + * + * The defined Below are for internal use only */ + +/* free vert flags */ +#define eul 0.0000001 +#define BLF 1 +#define TRF 2 +#define TLF 4 +#define BRF 8 +#define BL 0 +#define TR 1 +#define TL 2 +#define BR 3 + +#define BOXLEFT(b) b->v[BL]->x +#define BOXRIGHT(b) b->v[TR]->x +#define BOXBOTTOM(b) b->v[BL]->y +#define BOXTOP(b) b->v[TR]->y +#define BOXAREA(b) (b->w * b->h) + +#define UPDATE_V34X(b) b->v[TL]->x = b->v[BL]->x;\ + b->v[BR]->x = b->v[TR]->x +#define UPDATE_V34Y(b) b->v[TL]->y = b->v[TR]->y;\ + b->v[BR]->y = b->v[BL]->y +#define UPDATE_V34(b) UPDATE_V34X(b); UPDATE_V34Y(b) + +#define SET_BOXLEFT(b, f) b->v[TR]->x = f + b->w;\ + b->v[BL]->x = f;\ + UPDATE_V34X(b) +#define SET_BOXRIGHT(b, f) b->v[BL]->x = f - b->w;\ + b->v[TR]->x = f;\ + UPDATE_V34X(b) +#define SET_BOXBOTTOM(b, f) b->v[TR]->y = f + b->h;\ + b->v[BL]->y = f;\ + UPDATE_V34Y(b) +#define SET_BOXTOP(b, f) b->v[BL]->y = f - b->h;\ + b->v[TR]->y = f;\ + UPDATE_V34Y(b) +#define BOXINTERSECT(b1, b2)\ + (!( BOXLEFT(b1)+eul>=BOXRIGHT(b2) ||\ + BOXBOTTOM(b1)+eul>=BOXTOP(b2) ||\ + BOXRIGHT(b1)-eul<=BOXLEFT(b2) ||\ + BOXTOP(b1)-eul<=BOXBOTTOM(b2) )) + +/* #define BOXDEBUG(b)\ + * printf("\tBox Debug i %i, w:%.3f h:%.3f x:%.3f y:%.3f\n",\ + * b->index, b->w, b->h, b->x, b->y) */ + +/* qsort function - sort largest to smallest */ +static int box_areasort(const void *p1, const void *p2) +{ + const boxPack *b1=p1, *b2=p2; + float a1, a2; + + a1 = BOXAREA(b1); + a2 = BOXAREA(b2); + + if ( a1 < a2 ) return 1; + else if ( a1 > a2 ) return -1; + return 0; +} + +/* qsort vertex sorting function + * sorts from lower left to top right It uses the current box's width and height + * as offsets when sorting, this has the result of not placing boxes outside + * the bounds of the existing backed area where possible + * */ +static float box_width; +static float box_height; +static boxVert *vertarray; + +static int vertex_sort(const void *p1, const void *p2) +{ + boxVert *v1, *v2; + float a1, a2; + + v1 = vertarray + ((int *) p1)[0]; + v2 = vertarray + ((int *) p2)[0]; + + a1 = MAX2(v1->x+box_width, v1->y+box_height); + a2 = MAX2(v2->x+box_width, v2->y+box_height); + + /* sort largest to smallest */ + if ( a1 > a2 ) return 1; + else if ( a1 < a2 ) return -1; + return 0; +} +/* Main boxpacking function accessed from other functions + * This sets boxes x,y to positive values, sorting from 0,0 outwards. + * There is no limit to the space boxes may take, only that they will be packed + * tightly into the lower left hand corner (0,0) + * + * boxarray - a pre allocated array of boxes. + * only the 'box->x' and 'box->y' are set, 'box->w' and 'box->h' are used, + * 'box->index' is not used at all, the only reason its there + * is that the box array is sorted by area and programs need to be able + * to have some way of writing the boxes back to the original data. + * len - the number of boxes in teh array. + * tot_width and tot_height are set so you can normalize the data. + * */ +void boxPack2D(boxPack *boxarray, int len, float *tot_width, float *tot_height) +{ + boxVert *vert; /* the current vert */ + int box_index, verts_pack_len, i, j, k, isect; + int quad_flags[4]= {BLF,TRF,TLF,BRF}; /* use for looping */ + boxPack *box, *box_test; /*current box and another for intersection tests*/ + int *vertex_pack_indicies; /*an array of indicies used for sorting verts*/ + + if (!len) { + *tot_width = 0.0; + *tot_height = 0.0; + return; + } + + /* Sort boxes, biggest first */ + qsort(boxarray, len, sizeof(boxPack), box_areasort); + + /* add verts to the boxes, these are only used internally */ + vert = vertarray = MEM_mallocN( len*4*sizeof(boxVert), "boxPack verts"); + vertex_pack_indicies = MEM_mallocN( len*3*sizeof(int), "boxPack indicies"); + + for (box=boxarray, box_index=0, i=0; box_index < len; box_index++, box++) { + + vert->blb = vert->brb = vert->tlb =\ + vert->isect_cache[0] = vert->isect_cache[1] =\ + vert->isect_cache[2] = vert->isect_cache[3] = NULL; + vert->free = 15 &~ TRF; + vert->trb = box; + vert->index = i; i++; + box->v[BL] = vert; vert++; + + vert->trb= vert->brb = vert->tlb =\ + vert->isect_cache[0] = vert->isect_cache[1] =\ + vert->isect_cache[2] = vert->isect_cache[3] = NULL; + vert->free = 15 &~ BLF; + vert->blb = box; + vert->index = i; i++; + box->v[TR] = vert; vert++; + + vert->trb = vert->blb = vert->tlb =\ + vert->isect_cache[0] = vert->isect_cache[1] =\ + vert->isect_cache[2] = vert->isect_cache[3] = NULL; + vert->free = 15 &~ BRF; + vert->brb = box; + vert->index = i; i++; + box->v[TL] = vert; vert++; + + vert->trb = vert->blb = vert->brb =\ + vert->isect_cache[0] = vert->isect_cache[1] =\ + vert->isect_cache[2] = vert->isect_cache[3] = NULL; + vert->free = 15 &~ TLF; + vert->tlb = box; + vert->index = i; i++; + box->v[BR] = vert; vert++; + } + vert = NULL; + + + /* Pack the First box! + * then enter the main boxpacking loop */ + + box = boxarray; /* get the first box */ + /* First time, no boxes packed */ + box->v[BL]->free = 0; /* Cant use any if these */ + box->v[BR]->free &= ~(BLF|BRF); + box->v[TL]->free &= ~(BLF|TLF); + + *tot_width = box->w; + *tot_height = box->h; + + /* This sets all the vertex locations */ + SET_BOXLEFT(box, 0.0); + SET_BOXBOTTOM(box, 0.0); + box->x = box->y = 0.0; + + for (i=0; i<3; i++) + vertex_pack_indicies[i] = box->v[i+1]->index; + verts_pack_len = 3; + box++; /* next box, needed for the loop below */ + /* ...done packing the first box */ + + /* Main boxpacking loop */ + for (box_index=1; box_index < len; box_index++, box++) { + + /* Sort the verts, these constants are used in sorting */ + box_width = box->w; + box_height = box->h; + + qsort(vertex_pack_indicies, verts_pack_len, sizeof(int), vertex_sort); + + /* Pack the box in with the others */ + /* sort the verts */ + isect = 1; + + for (i=0; ifree, verts_pack_len, vert->x, vert->y); */ + + /* This vert has a free quaderent + * Test if we can place the box here + * vert->free & quad_flags[j] - Checks + * */ + + for (j=0; (j<4) && isect; j++) { + if (vert->free & quad_flags[j]) { + switch (j) { + case BL: + SET_BOXRIGHT(box, vert->x); + SET_BOXTOP(box, vert->y); + break; + case TR: + SET_BOXLEFT(box, vert->x); + SET_BOXBOTTOM(box, vert->y); + break; + case TL: + SET_BOXRIGHT(box, vert->x); + SET_BOXBOTTOM(box, vert->y); + break; + case BR: + SET_BOXLEFT(box, vert->x); + SET_BOXTOP(box, vert->y); + break; + } + + /* Now we need to check that the box intersects + * with any other boxes + * Assume no intersection... */ + isect = 0; + + if (/* Constrain boxes to positive X/Y values */ + BOXLEFT(box)<0.0 || BOXBOTTOM(box) < 0.0 || + /* check for last intersected */ + ( vert->isect_cache[j] && + BOXINTERSECT(box, vert->isect_cache[j]) ) + ) { + /* Here we check that the last intersected + * box will intersect with this one using + * isect_cache that can store a pointer to a + * box for each quaderent + * big speedup */ + isect = 1; + } else { + /* do a full saech for colliding box + * this is realy slow, some spacialy divided + * datastructure would be better */ + for (box_test=boxarray; box_test != box; box_test++) { + if BOXINTERSECT(box, box_test) { + /* Store the last intersecting here as cache + * for faster checking next time around */ + vert->isect_cache[j] = box_test; + isect = 1; + break; + } + } + } + + if (!isect) { + + /* maintain the total width and height */ + (*tot_width) = MAX2(BOXRIGHT(box), (*tot_width)); + (*tot_height) = MAX2(BOXTOP(box), (*tot_height)); + + /* Place the box */ + vert->free &= ~quad_flags[j]; + + switch (j) { + case TR: + box->v[BL]= vert; + vert->trb = box; + break; + case TL: + box->v[BR]= vert; + vert->tlb = box; + break; + case BR: + box->v[TL]= vert; + vert->brb = box; + break; + case BL: + box->v[TR]= vert; + vert->blb = box; + break; + } + + /* Mask free flags for verts that are + * on the bottom or side so we dont get + * boxes outside the given rectangle ares + * + * We can do an else/if here because only the first + * box can be at the very bottom left corner */ + if (BOXLEFT(box) <= 0) { + box->v[TL]->free &= ~(TLF|BLF); + box->v[BL]->free &= ~(TLF|BLF); + } else if (BOXBOTTOM(box) <= 0) { + box->v[BL]->free &= ~(BRF|BLF); + box->v[BR]->free &= ~(BRF|BLF); + } + + /* The following block of code does a logical + * check with 2 adjacent boxes, its possible to + * flag verts on one or both of the boxes + * as being used by checking the width or + * height of both boxes */ + if (vert->tlb && vert->trb && + (box == vert->tlb || box == vert->trb)) { + if (vert->tlb->h > vert->trb->h) { + vert->trb->v[TL]->free &= ~(TLF|BLF); + } else if (vert->tlb->h < vert->trb->h) { + vert->tlb->v[TR]->free &= ~(TRF|BRF); + } else { /*same*/ + vert->tlb->v[TR]->free &= ~BLF; + vert->trb->v[TL]->free &= ~BRF; + } + } else if (vert->blb && vert->brb && + (box == vert->blb || box == vert->brb)) { + if (vert->blb->h > vert->brb->h) { + vert->brb->v[BL]->free &= ~(TLF|BLF); + } else if (vert->blb->h < vert->brb->h) { + vert->blb->v[BR]->free &= ~(TRF|BRF); + } else { /*same*/ + vert->blb->v[BR]->free &= ~TRF; + vert->brb->v[BL]->free &= ~TLF; + } + } + /* Horizontal */ + if (vert->tlb && vert->blb && + (box == vert->tlb || box == vert->blb) ) { + if (vert->tlb->w > vert->blb->w) { + vert->blb->v[TL]->free &= ~(TLF|TRF); + } else if (vert->tlb->w < vert->blb->w) { + vert->tlb->v[BL]->free &= ~(BLF|BRF); + } else { /*same*/ + vert->blb->v[TL]->free &= ~TRF; + vert->tlb->v[BL]->free &= ~BRF; + } + } else if ( vert->trb && vert->brb && + (box == vert->trb || box == vert->brb) ) { + if (vert->trb->w > vert->brb->w) { + vert->brb->v[TR]->free &= ~(TRF|TRF); + } else if (vert->trb->w < vert->brb->w) { + vert->trb->v[BR]->free &= ~(BLF|BRF); + } else { /*same*/ + vert->brb->v[TR]->free &= ~TLF; + vert->trb->v[BR]->free &= ~BLF; + } + } + /* End logical check */ + + + for (k=0; k<4; k++) { + if (box->v[k] != vert) { + vertex_pack_indicies[verts_pack_len] = + box->v[k]->index; + verts_pack_len++; + } + } + /* The Box verts are only used interially + * Update the box x and y since thats what external + * functions will see */ + box->x = BOXLEFT(box); + box->y = BOXBOTTOM(box); + } + } + } + } + } + + /* free all the verts, not realy needed because they shouldebt be + * touched anymore but accessing the pointers woud crash blender */ + for (box_index=0; box_index < len; box_index++) { + box = boxarray+box_index; + box->v[0] = box->v[1] = box->v[2] = box->v[3] = NULL; + } + MEM_freeN(vertex_pack_indicies); + MEM_freeN(vertarray); +} + diff --git a/source/blender/blenlib/intern/dynlib.c b/source/blender/blenlib/intern/dynlib.c new file mode 100644 index 00000000000..c455ba664ce --- /dev/null +++ b/source/blender/blenlib/intern/dynlib.c @@ -0,0 +1,343 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file, with exception of below: + * + * Contributor(s): Peter O'Gorman + * The functions osxdlopen() and osxerror() + * are Copyright (c) 2002 Peter O'Gorman + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include +#include + +#include "../PIL_dynlib.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if !defined(CHAR_MAX) +#define CHAR_MAX 255 +#endif + +/* + * XXX, should use mallocN so we can see + * handle's not being released. fixme zr + */ + +#ifdef WIN32 + +#include + +struct PILdynlib { + void *handle; +}; + +PILdynlib *PIL_dynlib_open(char *name) { + void *handle= LoadLibrary(name); + + if (handle) { + PILdynlib *lib= malloc(sizeof(*lib)); + lib->handle= handle; + + return lib; + } else { + return NULL; + } +} + +void *PIL_dynlib_find_symbol(PILdynlib* lib, char *symname) { + return GetProcAddress(lib->handle, symname); +} + +char *PIL_dynlib_get_error_as_string(PILdynlib* lib) { + int err; + + /* if lib is NULL reset the last error code */ + if (!lib) { + SetLastError(ERROR_SUCCESS); + return NULL; + } + + err= GetLastError(); + if (err) { + static char buf[1024]; + + if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + err, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + buf, + sizeof(buf), + NULL)) + return buf; + } + + return NULL; +} + +void PIL_dynlib_close(PILdynlib *lib) { + FreeLibrary(lib->handle); + + free(lib); +} + +#else +#ifdef __APPLE__ /* MacOS X */ + +#include +#include +#include + +#define ERR_STR_LEN 256 + +struct PILdynlib { + void *handle; +}; + +static char *osxerror(int setget, const char *str, ...) +{ + static char errstr[ERR_STR_LEN]; + static int err_filled = 0; + char *retval; + NSLinkEditErrors ler; + int lerno; + const char *dylderrstr; + const char *file; + va_list arg; + if (setget <= 0) + { + va_start(arg, str); + strncpy(errstr, "dlsimple: ", ERR_STR_LEN); + vsnprintf(errstr + 10, ERR_STR_LEN - 10, str, arg); + va_end(arg); + /* We prefer to use the dyld error string if setget is 0 */ + if (setget == 0) { + NSLinkEditError(&ler, &lerno, &file, &dylderrstr); +// printf("dyld: %s\n",dylderrstr); + if (dylderrstr && strlen(dylderrstr)) + strncpy(errstr,dylderrstr,ERR_STR_LEN); + } + err_filled = 1; + retval = NULL; + } + else + { + if (!err_filled) + retval = NULL; + else + retval = errstr; + err_filled = 0; + } + return retval; +} + +static void *osxdlopen(const char *path, int mode) +{ + void *module = 0; + NSObjectFileImage ofi = 0; + NSObjectFileImageReturnCode ofirc; + static int (*make_private_module_public) (NSModule module) = 0; + unsigned int flags = NSLINKMODULE_OPTION_RETURN_ON_ERROR | NSLINKMODULE_OPTION_PRIVATE; + + /* If we got no path, the app wants the global namespace, use -1 as the marker + in this case */ + if (!path) + return (void *)-1; + + /* Create the object file image, works for things linked with the -bundle arg to ld */ + ofirc = NSCreateObjectFileImageFromFile(path, &ofi); + switch (ofirc) + { + case NSObjectFileImageSuccess: + /* It was okay, so use NSLinkModule to link in the image */ + if (!(mode & RTLD_LAZY)) flags += NSLINKMODULE_OPTION_BINDNOW; + module = NSLinkModule(ofi, path,flags); + /* Don't forget to destroy the object file image, unless you like leaks */ + NSDestroyObjectFileImage(ofi); + /* If the mode was global, then change the module, this avoids + multiply defined symbol errors to first load private then make + global. Silly, isn't it. */ + if ((mode & RTLD_GLOBAL)) + { + if (!make_private_module_public) + { + _dyld_func_lookup("__dyld_NSMakePrivateModulePublic", + (unsigned long *)&make_private_module_public); + } + make_private_module_public(module); + } + break; + case NSObjectFileImageInappropriateFile: + /* It may have been a dynamic library rather than a bundle, try to load it */ + module = (void *)NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR); + break; + case NSObjectFileImageFailure: + osxerror(0,"Object file setup failure : \"%s\"", path); + return 0; + case NSObjectFileImageArch: + osxerror(0,"No object for this architecture : \"%s\"", path); + return 0; + case NSObjectFileImageFormat: + osxerror(0,"Bad object file format : \"%s\"", path); + return 0; + case NSObjectFileImageAccess: + osxerror(0,"Can't read object file : \"%s\"", path); + return 0; + } + if (!module) + osxerror(0, "Can not open \"%s\"", path); + return module; +} + +PILdynlib *PIL_dynlib_open(char *name) { + void *handle= osxdlopen(name, RTLD_LAZY); + + if (handle) { + PILdynlib *lib= malloc(sizeof(*lib)); + lib->handle= handle; + + return lib; + } else { + return NULL; + } +} + +void *PIL_dynlib_find_symbol(PILdynlib* lib, char *symname) +{ + int sym_len = strlen(symname); + void *value = NULL; + char *malloc_sym = NULL; + NSSymbol *nssym = 0; + malloc_sym = malloc(sym_len + 2); + if (malloc_sym) + { + sprintf(malloc_sym, "_%s", symname); + /* If the lib->handle is -1, if is the app global context */ + if (lib->handle == (void *)-1) + { + /* Global context, use NSLookupAndBindSymbol */ + if (NSIsSymbolNameDefined(malloc_sym)) + { + nssym = NSLookupAndBindSymbol(malloc_sym); + } + } + /* Now see if the lib->handle is a struch mach_header* or not, use NSLookupSymbol in image + for libraries, and NSLookupSymbolInModule for bundles */ + else + { + /* Check for both possible magic numbers depending on x86/ppc byte order */ + if ((((struct mach_header *)lib->handle)->magic == MH_MAGIC) || + (((struct mach_header *)lib->handle)->magic == MH_CIGAM)) + { + if (NSIsSymbolNameDefinedInImage((struct mach_header *)lib->handle, malloc_sym)) + { + nssym = NSLookupSymbolInImage((struct mach_header *)lib->handle, + malloc_sym, + NSLOOKUPSYMBOLINIMAGE_OPTION_BIND + | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); + } + + } + else + { + nssym = NSLookupSymbolInModule(lib->handle, malloc_sym); + } + } + if (!nssym) + { + osxerror(0, "symname \"%s\" Not found", symname); + } + value = NSAddressOfSymbol(nssym); + free(malloc_sym); + } + else + { + osxerror(-1, "Unable to allocate memory"); + } + return value; +} + +char *PIL_dynlib_get_error_as_string(PILdynlib* lib) +{ + return osxerror(1, (char *)NULL); +} + +void PIL_dynlib_close(PILdynlib *lib) +{ + if ((((struct mach_header *)lib->handle)->magic == MH_MAGIC) || + (((struct mach_header *)lib->handle)->magic == MH_CIGAM)) + { + osxerror(-1, "Can't remove dynamic libraries on darwin"); + } + if (!NSUnLinkModule(lib->handle, 0)) + { + osxerror(0, "unable to unlink module %s", NSNameOfModule(lib->handle)); + } + + free(lib); +} + +#else /* Unix */ + +#include + +struct PILdynlib { + void *handle; +}; + +PILdynlib *PIL_dynlib_open(char *name) { + void *handle= dlopen(name, RTLD_LAZY); + + if (handle) { + PILdynlib *lib= malloc(sizeof(*lib)); + lib->handle= handle; + + return lib; + } else { + return NULL; + } +} + +void *PIL_dynlib_find_symbol(PILdynlib* lib, char *symname) { + return dlsym(lib->handle, symname); +} + +char *PIL_dynlib_get_error_as_string(PILdynlib* lib) { + return dlerror(); +} + +void PIL_dynlib_close(PILdynlib *lib) { + dlclose(lib->handle); + + free(lib); +} + +#endif +#endif diff --git a/source/blender/blenlib/intern/edgehash.c b/source/blender/blenlib/intern/edgehash.c new file mode 100644 index 00000000000..8fae0f63746 --- /dev/null +++ b/source/blender/blenlib/intern/edgehash.c @@ -0,0 +1,220 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: none of this file. + * + * Contributor(s): Daniel Dunbar + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * A general (pointer -> pointer) hash table ADT + */ + +#include +#include + +#include "MEM_guardedalloc.h" +#include "BLI_edgehash.h" + +/***/ + +static unsigned int hashsizes[]= { + 1, 3, 5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209, + 16411, 32771, 65537, 131101, 262147, 524309, 1048583, 2097169, + 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, + 268435459 +}; + +#define EDGEHASH(v0,v1) ((v0*39)^(v1*31)) + +/***/ + +typedef struct Entry Entry; +struct Entry { + Entry *next; + int v0, v1; + void *val; +}; + +struct EdgeHash { + Entry **buckets; + int nbuckets, nentries, cursize; +}; + +/***/ + +EdgeHash *BLI_edgehash_new(void) { + EdgeHash *eh= MEM_mallocN(sizeof(*eh), "EdgeHash"); + eh->cursize= 0; + eh->nentries= 0; + eh->nbuckets= hashsizes[eh->cursize]; + + eh->buckets= malloc(eh->nbuckets*sizeof(*eh->buckets)); + memset(eh->buckets, 0, eh->nbuckets*sizeof(*eh->buckets)); + + return eh; +} + +void BLI_edgehash_insert(EdgeHash *eh, int v0, int v1, void *val) { + unsigned int hash; + Entry *e= malloc(sizeof(*e)); + + if (v1nbuckets; + + e->v0 = v0; + e->v1 = v1; + e->val = val; + e->next= eh->buckets[hash]; + eh->buckets[hash]= e; + + if (++eh->nentries>eh->nbuckets*3) { + Entry *e, **old= eh->buckets; + int i, nold= eh->nbuckets; + + eh->nbuckets= hashsizes[++eh->cursize]; + eh->buckets= malloc(eh->nbuckets*sizeof(*eh->buckets)); + memset(eh->buckets, 0, eh->nbuckets*sizeof(*eh->buckets)); + + for (i=0; inext; + + hash= EDGEHASH(e->v0,e->v1)%eh->nbuckets; + e->next= eh->buckets[hash]; + eh->buckets[hash]= e; + + e= n; + } + } + + free(old); + } +} + +void** BLI_edgehash_lookup_p(EdgeHash *eh, int v0, int v1) { + unsigned int hash; + Entry *e; + + if (v1nbuckets; + for (e= eh->buckets[hash]; e; e= e->next) + if (v0==e->v0 && v1==e->v1) + return &e->val; + + return NULL; +} + +void* BLI_edgehash_lookup(EdgeHash *eh, int v0, int v1) { + void **value_p = BLI_edgehash_lookup_p(eh,v0,v1); + + return value_p?*value_p:NULL; +} + +int BLI_edgehash_haskey(EdgeHash *eh, int v0, int v1) { + return BLI_edgehash_lookup_p(eh, v0, v1)!=NULL; +} + +int BLI_edgehash_size(EdgeHash *eh) { + return eh->nentries; +} + +void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP valfreefp) { + int i; + + for (i=0; inbuckets; i++) { + Entry *e; + + for (e= eh->buckets[i]; e; ) { + Entry *n= e->next; + + if (valfreefp) valfreefp(e->val); + free(e); + + e= n; + } + eh->buckets[i]= NULL; + } + + eh->nentries= 0; +} + +void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP valfreefp) { + BLI_edgehash_clear(eh, valfreefp); + + free(eh->buckets); + MEM_freeN(eh); +} + + +/***/ + +struct EdgeHashIterator { + EdgeHash *eh; + int curBucket; + Entry *curEntry; +}; + +EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh) { + EdgeHashIterator *ehi= malloc(sizeof(*ehi)); + ehi->eh= eh; + ehi->curEntry= NULL; + ehi->curBucket= -1; + while (!ehi->curEntry) { + ehi->curBucket++; + if (ehi->curBucket==ehi->eh->nbuckets) + break; + ehi->curEntry= ehi->eh->buckets[ehi->curBucket]; + } + return ehi; +} +void BLI_edgehashIterator_free(EdgeHashIterator *ehi) { + free(ehi); +} + +void BLI_edgehashIterator_getKey(EdgeHashIterator *ehi, int *v0_r, int *v1_r) { + if (ehi->curEntry) { + *v0_r = ehi->curEntry->v0; + *v1_r = ehi->curEntry->v1; + } +} +void *BLI_edgehashIterator_getValue(EdgeHashIterator *ehi) { + return ehi->curEntry?ehi->curEntry->val:NULL; +} + +void BLI_edgehashIterator_step(EdgeHashIterator *ehi) { + if (ehi->curEntry) { + ehi->curEntry= ehi->curEntry->next; + while (!ehi->curEntry) { + ehi->curBucket++; + if (ehi->curBucket==ehi->eh->nbuckets) + break; + ehi->curEntry= ehi->eh->buckets[ehi->curBucket]; + } + } +} +int BLI_edgehashIterator_isDone(EdgeHashIterator *ehi) { + return !ehi->curEntry; +} + diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c new file mode 100644 index 00000000000..fcea30982bd --- /dev/null +++ b/source/blender/blenlib/intern/fileops.c @@ -0,0 +1,364 @@ +/* + * blenlib/fileops.h + * + * cleaned up (a bit) mar-01 nzc + * + * More low-level file things. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "zlib.h" + +#ifdef WIN32 +#include "BLI_winstuff.h" +#include +#else +#include +#endif + +#include "BLI_blenlib.h" +#include "BLI_storage.h" +#include "BLI_fileops.h" +#include "BLI_callbacks.h" + +#include +#include +#include + +#include "BKE_utildefines.h" +#include + +/* implementations: */ +char *first_slash(char *string) { + char *ffslash, *fbslash; + + ffslash= strchr(string, '/'); + fbslash= strchr(string, '\\'); + + if (!ffslash) return fbslash; + else if (!fbslash) return ffslash; + + if ((long)ffslash < (long)fbslash) return ffslash; + else return fbslash; +} + +char *BLI_last_slash(char *string) { + char *lfslash, *lbslash; + + lfslash= strrchr(string, '/'); + lbslash= strrchr(string, '\\'); + + if (!lfslash) return lbslash; + else if (!lbslash) return lfslash; + + if ((long)lfslash < (long)lbslash) return lbslash; + else return lfslash; +} + +/* gzip the file in from and write it to "to". + return -1 if zlib fails, -2 if the originating file does not exist + note: will remove the "from" file + */ +int BLI_gzip(char *from, char *to) { + char buffer[10240]; + int file; + int readsize = 0; + + gzFile gzfile = gzopen(to,"wb"); + if (NULL == gzfile) return -1; + + file = open(from,O_BINARY|O_RDONLY); + + if ( -1 == file ) return -2; + + while ( 1 ) + { + readsize = read(file, buffer, 10240); + + if (readsize <= 0) break; + + gzwrite(gzfile,buffer,readsize); + } + + gzclose(gzfile); + close(file); + + remove(from); + + return 0; +} + +/* return 1 when file can be written */ +int BLI_is_writable(char *filename) +{ + int file; + + file = open(filename, O_BINARY | O_RDWR | O_CREAT | O_TRUNC, 0666); + + if (file < 0) + return 0; + else { + close(file); + return 1; + } +} + +#ifdef WIN32 + +static char str[MAXPATHLEN+12]; + +int BLI_delete(char *file, int dir, int recursive) { + int err; + + if (recursive) { + callLocalErrorCallBack("Recursive delete is unsupported on Windows"); + err= 1; + } else if (dir) { + err= !RemoveDirectory(file); + if (err) printf ("Unable to remove directory"); + } else { + err= !DeleteFile(file); + if (err) callLocalErrorCallBack("Unable to delete file"); + } + + return err; +} + +int BLI_touch(char *file) { + callLocalErrorCallBack("Touching files is unsupported on Windows"); + + return 1; +} + +int BLI_move(char *file, char *to) { + int err; + + // windows doesn't support moveing to a directory + // it has to be 'mv filename filename' and not + // 'mv filename destdir' + + strcpy(str, to); + // points 'to' to a directory ? + if (BLI_last_slash(str) == (str + strlen(str) - 1)) { + if (BLI_last_slash(file) != NULL) { + strcat(str, BLI_last_slash(file) + 1); + } + } + + err= !MoveFile(file, str); + if (err) { + callLocalErrorCallBack("Unable to move file"); + printf(" Move from '%s' to '%s' failed\n", file, str); + } + + return err; +} + + +int BLI_copy_fileops(char *file, char *to) { + int err; + + // windows doesn't support copying to a directory + // it has to be 'cp filename filename' and not + // 'cp filename destdir' + + strcpy(str, to); + // points 'to' to a directory ? + if (BLI_last_slash(str) == (str + strlen(str) - 1)) { + if (BLI_last_slash(file) != NULL) { + strcat(str, BLI_last_slash(file) + 1); + } + } + + err= !CopyFile(file,str,FALSE); + + if (err) { + callLocalErrorCallBack("Unable to copy file!"); + printf(" Copy from '%s' to '%s' failed\n", file, str); + } + + return err; +} + +int BLI_link(char *file, char *to) { + callLocalErrorCallBack("Linking files is unsupported on Windows"); + + return 1; +} + +int BLI_backup(char *file, char *from, char *to) { + callLocalErrorCallBack("Backing up files is unsupported on Windows"); + + return 1; +} + +int BLI_exists(char *file) { + return (GetFileAttributes(file) != 0xFFFFFFFF); +} + +void BLI_recurdir_fileops(char *dirname) { + char *lslash; + char tmp[MAXPATHLEN]; + + // First remove possible slash at the end of the dirname. + // This routine otherwise tries to create + // blah1/blah2/ (with slash) after creating + // blah1/blah2 (without slash) + + strcpy(tmp, dirname); + lslash= BLI_last_slash(tmp); + + if (lslash == tmp + strlen(tmp) - 1) { + *lslash = 0; + } + + if (BLI_exists(tmp)) return; + + lslash= BLI_last_slash(tmp); + if (lslash) { + /* Split about the last slash and recurse */ + *lslash = 0; + BLI_recurdir_fileops(tmp); + } + + if(dirname[0]) /* patch, this recursive loop tries to create a nameless directory */ + if (!CreateDirectory(dirname, NULL)) + callLocalErrorCallBack("Unable to create directory\n"); +} + +int BLI_rename(char *from, char *to) { + if (!BLI_exists(from)) return 0; + + if (BLI_exists(to)) + if(BLI_delete(to, 0, 0)) return 1; + + return rename(from, to); +} + +#else /* The sane UNIX world */ + +/* + * but the sane UNIX world is tied to the interface, and the system + * timer, and... We implement a callback mechanism. The system will + * have to initialise the callback before the functions will work! + * */ +static char str[MAXPATHLEN+12]; + +int BLI_delete(char *file, int dir, int recursive) +{ + if(strchr(file, '"')) { + printf("Error: not deleted file %s because of quote!\n", file); + } + else { + if (recursive) sprintf(str, "/bin/rm -rf \"%s\"", file); + else if (dir) sprintf(str, "/bin/rmdir \"%s\"", file); + else sprintf(str, "/bin/rm -f \"%s\"", file); + + return system(str); + } + return -1; +} + +int BLI_touch(char *file) +{ + + if( BLI_exists("/bin/touch") ) + sprintf(str, "/bin/touch %s", file); + else + sprintf(str, "/usr/bin/touch %s", file); + + return system(str); +} + +int BLI_move(char *file, char *to) { + sprintf(str, "/bin/mv -f \"%s\" \"%s\"", file, to); + + return system(str); +} + +int BLI_copy_fileops(char *file, char *to) { + sprintf(str, "/bin/cp -rf \"%s\" \"%s\"", file, to); + + return system(str); +} + +int BLI_link(char *file, char *to) { + sprintf(str, "/bin/ln -f \"%s\" \"%s\"", file, to); + + return system(str); +} + +int BLI_backup(char *file, char *from, char *to) { + sprintf(str, "/bin/su root -c 'cd %s; /bin/tar cf - \"%s\" | (/bin/cd %s; /bin/tar xf -)'", from, file, to); + + return system(str); +} + +int BLI_exists(char *file) { + return BLI_exist(file); +} + +void BLI_recurdir_fileops(char *dirname) { + char *lslash; + char tmp[MAXPATHLEN]; + + if (BLI_exists(dirname)) return; + + strcpy(tmp, dirname); + + lslash= BLI_last_slash(tmp); + if (lslash) { + /* Split about the last slash and recurse */ + *lslash = 0; + BLI_recurdir_fileops(tmp); + } + + mkdir(dirname, 0777); +} + +int BLI_rename(char *from, char *to) { + if (!BLI_exists(from)) return 0; + + if (BLI_exists(to)) if(BLI_delete(to, 0, 0)) return 1; + + return rename(from, to); +} + +#endif diff --git a/source/blender/blenlib/intern/freetypefont.c b/source/blender/blenlib/intern/freetypefont.c new file mode 100644 index 00000000000..7fbd4bac485 --- /dev/null +++ b/source/blender/blenlib/intern/freetypefont.c @@ -0,0 +1,634 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is written by Rob Haarsma (phase) + * All rights reserved. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + * This code parses the Freetype font outline data to chains of Blender's beziertriples. + * Additional information can be found at the bottom of this file. + * + * Code that uses exotic character maps is present but commented out. + */ + +#ifdef WITH_FREETYPE2 + +#ifdef WIN32 +#pragma warning (disable:4244) +#endif + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H +#include FT_BBOX_H +#include FT_SIZES_H +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_vfontdata.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "BIF_toolbox.h" + +#include "BKE_global.h" +#include "BKE_utildefines.h" + +#include "DNA_vfont_types.h" +#include "DNA_packedFile_types.h" +#include "DNA_curve_types.h" + +#define myMIN_ASCII 32 +#define myMAX_ASCII 255 + +/* local variables */ +static FT_Library library; +static FT_Error err; + + +void freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd) +{ + // Blender + struct Nurb *nu; + struct VChar *che; + struct BezTriple *bezt; + + // Freetype2 + FT_GlyphSlot glyph; + FT_UInt glyph_index; + FT_Outline ftoutline; + float scale, height; + float dx, dy; + int j,k,l,m=0; + + // adjust font size + height= ((double) face->bbox.yMax - (double) face->bbox.yMin); + if(height != 0.0) + scale = 1.0 / height; + else + scale = 1.0 / 1000.0; + + // + // Generate the character 3D data + // + // Get the FT Glyph index and load the Glyph + glyph_index= FT_Get_Char_Index(face, charcode); + err= FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP); + + // If loading succeeded, convert the FT glyph to the internal format + if(!err) + { + int *npoints; + int *onpoints; + + // First we create entry for the new character to the character list + che= (VChar *) MEM_callocN(sizeof(struct VChar), "objfnt_char"); + BLI_addtail(&vfd->characters, che); + + // Take some data for modifying purposes + glyph= face->glyph; + ftoutline= glyph->outline; + + // Set the width and character code + che->index= charcode; + che->width= glyph->advance.x * scale; + + // Start converting the FT data + npoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"endpoints") ; + onpoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"onpoints") ; + + // calculate total points of each contour + for(j = 0; j < ftoutline.n_contours; j++) { + if(j == 0) + npoints[j] = ftoutline.contours[j] + 1; + else + npoints[j] = ftoutline.contours[j] - ftoutline.contours[j - 1]; + } + + // get number of on-curve points for beziertriples (including conic virtual on-points) + for(j = 0; j < ftoutline.n_contours; j++) { + l = 0; + for(k = 0; k < npoints[j]; k++) { + if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k; + if(ftoutline.tags[l] == FT_Curve_Tag_On) + onpoints[j]++; + + if(k < npoints[j] - 1 ) + if( ftoutline.tags[l] == FT_Curve_Tag_Conic && + ftoutline.tags[l+1] == FT_Curve_Tag_Conic) + onpoints[j]++; + } + } + + //contour loop, bezier & conic styles merged + for(j = 0; j < ftoutline.n_contours; j++) { + // add new curve + nu = (Nurb*)MEM_callocN(sizeof(struct Nurb),"objfnt_nurb"); + bezt = (BezTriple*)MEM_callocN((onpoints[j])* sizeof(BezTriple),"objfnt_bezt") ; + BLI_addtail(&che->nurbsbase, nu); + + nu->type= CU_BEZIER+CU_2D; + nu->pntsu = onpoints[j]; + nu->resolu= 8; + nu->flagu= 1; + nu->bezt = bezt; + + //individual curve loop, start-end + for(k = 0; k < npoints[j]; k++) { + if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k; + if(k == 0) m = l; + + //virtual conic on-curve points + if(k < npoints[j] - 1 ) + { + if( ftoutline.tags[l] == FT_Curve_Tag_Conic && ftoutline.tags[l+1] == FT_Curve_Tag_Conic) { + dx = (ftoutline.points[l].x + ftoutline.points[l+1].x)* scale / 2.0; + dy = (ftoutline.points[l].y + ftoutline.points[l+1].y)* scale / 2.0; + + //left handle + bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x)* scale) / 3.0; + bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y)* scale) / 3.0; + + //midpoint (virtual on-curve point) + bezt->vec[1][0] = dx; + bezt->vec[1][1] = dy; + + //right handle + bezt->vec[2][0] = (dx + (2 * ftoutline.points[l+1].x)* scale) / 3.0; + bezt->vec[2][1] = (dy + (2 * ftoutline.points[l+1].y)* scale) / 3.0; + + bezt->h1= bezt->h2= HD_ALIGN; + bezt++; + } + } + + //on-curve points + if(ftoutline.tags[l] == FT_Curve_Tag_On) { + //left handle + if(k > 0) { + if(ftoutline.tags[l - 1] == FT_Curve_Tag_Cubic) { + bezt->vec[0][0] = ftoutline.points[l-1].x* scale; + bezt->vec[0][1] = ftoutline.points[l-1].y* scale; + bezt->h1= HD_FREE; + } else if(ftoutline.tags[l - 1] == FT_Curve_Tag_Conic) { + bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l - 1].x))* scale / 3.0; + bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y))* scale / 3.0; + bezt->h1= HD_FREE; + } else { + bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l-1].x)* scale / 3.0; + bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l-1].y)* scale / 3.0; + bezt->h1= HD_VECT; + } + } else { //first point on curve + if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Cubic) { + bezt->vec[0][0] = ftoutline.points[ftoutline.contours[j]].x * scale; + bezt->vec[0][1] = ftoutline.points[ftoutline.contours[j]].y * scale; + bezt->h1= HD_FREE; + } else if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Conic) { + bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[ftoutline.contours[j]].x))* scale / 3.0 ; + bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y))* scale / 3.0 ; + bezt->h1= HD_FREE; + } else { + bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[ftoutline.contours[j]].x)* scale / 3.0; + bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y)* scale / 3.0; + bezt->h1= HD_VECT; + } + } + + //midpoint (on-curve point) + bezt->vec[1][0] = ftoutline.points[l].x* scale; + bezt->vec[1][1] = ftoutline.points[l].y* scale; + + //right handle + if(k < (npoints[j] - 1)) { + if(ftoutline.tags[l+1] == FT_Curve_Tag_Cubic) { + bezt->vec[2][0] = ftoutline.points[l+1].x* scale; + bezt->vec[2][1] = ftoutline.points[l+1].y* scale; + bezt->h2= HD_FREE; + } else if(ftoutline.tags[l+1] == FT_Curve_Tag_Conic) { + bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l+1].x))* scale / 3.0; + bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l+1].y))* scale / 3.0; + bezt->h2= HD_FREE; + } else { + bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l+1].x)* scale / 3.0; + bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l+1].y)* scale / 3.0; + bezt->h2= HD_VECT; + } + } else { //last point on curve + if(ftoutline.tags[m] == FT_Curve_Tag_Cubic) { + bezt->vec[2][0] = ftoutline.points[m].x* scale; + bezt->vec[2][1] = ftoutline.points[m].y* scale; + bezt->h2= HD_FREE; + } else if(ftoutline.tags[m] == FT_Curve_Tag_Conic) { + bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[m].x))* scale / 3.0 ; + bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y))* scale / 3.0 ; + bezt->h2= HD_FREE; + } else { + bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[m].x)* scale / 3.0; + bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[m].y)* scale / 3.0; + bezt->h2= HD_VECT; + } + } + + // get the handles that are aligned, tricky... + // DistVL2Dfl, check if the three beztriple points are on one line + // VecLenf, see if there's a distance between the three points + // VecLenf again, to check the angle between the handles + // finally, check if one of them is a vector handle + if((DistVL2Dfl(bezt->vec[0],bezt->vec[1],bezt->vec[2]) < 0.001) && + (VecLenf(bezt->vec[0], bezt->vec[1]) > 0.0001) && + (VecLenf(bezt->vec[1], bezt->vec[2]) > 0.0001) && + (VecLenf(bezt->vec[0], bezt->vec[2]) > 0.0002) && + (VecLenf(bezt->vec[0], bezt->vec[2]) > MAX2(VecLenf(bezt->vec[0], bezt->vec[1]), VecLenf(bezt->vec[1], bezt->vec[2]))) && + bezt->h1 != HD_VECT && bezt->h2 != HD_VECT) + { + bezt->h1= bezt->h2= HD_ALIGN; + } + bezt++; + } + } + } + if(npoints) MEM_freeN(npoints); + if(onpoints) MEM_freeN(onpoints); + } +} + +int objchr_to_ftvfontdata(VFont *vfont, FT_ULong charcode) +{ + // Freetype2 + FT_Face face; + struct TmpFont *tf; + + // Find the correct FreeType font + tf= G.ttfdata.first; + while(tf) + { + if(tf->vfont == vfont) + break; + tf= tf->next; + } + + // What, no font found. Something strange here + if(!tf) return FALSE; + + // Load the font to memory + if(tf->pf) + { + err= FT_New_Memory_Face( library, + tf->pf->data, + tf->pf->size, + 0, + &face); + } + else + err= TRUE; + + // Read the char + freetypechar_to_vchar(face, charcode, vfont->data); + + // And everything went ok + return TRUE; +} + + +static VFontData *objfnt_to_ftvfontdata(PackedFile * pf) +{ + // Variables + FT_Face face; + FT_ULong charcode = 0, lcode; + FT_UInt glyph_index; + const char *fontname; + VFontData *vfd; + +/* + FT_CharMap found = 0; + FT_CharMap charmap; + FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT; + FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS; + int n; +*/ + + // load the freetype font + err = FT_New_Memory_Face( library, + pf->data, + pf->size, + 0, + &face ); + + if(err) return NULL; +/* + for ( n = 0; n < face->num_charmaps; n++ ) + { + charmap = face->charmaps[n]; + if ( charmap->platform_id == my_platform_id && + charmap->encoding_id == my_encoding_id ) + { + found = charmap; + break; + } + } + + if ( !found ) { return NULL; } + + // now, select the charmap for the face object + err = FT_Set_Charmap( face, found ); + if ( err ) { return NULL; } +*/ + + // allocate blender font + vfd= MEM_callocN(sizeof(*vfd), "FTVFontData"); + + // get the name + fontname = FT_Get_Postscript_Name(face); + strcpy(vfd->name, (fontname == NULL) ? "Fontname not available" : fontname); + + // Extract the first 256 character from TTF + lcode= charcode= FT_Get_First_Char(face, &glyph_index); + + // No charmap found from the ttf so we need to figure it out + if(glyph_index == 0) + { + FT_CharMap found = 0; + FT_CharMap charmap; + int n; + + for ( n = 0; n < face->num_charmaps; n++ ) + { + charmap = face->charmaps[n]; + if (charmap->encoding == FT_ENCODING_APPLE_ROMAN) + { + found = charmap; + break; + } + } + + err = FT_Set_Charmap( face, found ); + + if( err ) + return NULL; + + lcode= charcode= FT_Get_First_Char(face, &glyph_index); + } + + // Load characters + while(charcode < 256) + { + // Generate the font data + freetypechar_to_vchar(face, charcode, vfd); + + // Next glyph + charcode = FT_Get_Next_Char(face, charcode, &glyph_index); + + // Check that we won't start infinite loop + if(charcode <= lcode) + break; + lcode = charcode; + } + + err = FT_Set_Charmap( face, (FT_CharMap) FT_ENCODING_UNICODE ); + + return vfd; +} + + +static int check_freetypefont(PackedFile * pf) +{ + FT_Face face; + FT_GlyphSlot glyph; + FT_UInt glyph_index; +/* + FT_CharMap charmap; + FT_CharMap found; + FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT; + FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS; + int n; +*/ + int success = 0; + + err = FT_New_Memory_Face( library, + pf->data, + pf->size, + 0, + &face ); + if(err) { + success = 0; + error("This is not a valid font"); + } + else { +/* + for ( n = 0; n < face->num_charmaps; n++ ) + { + charmap = face->charmaps[n]; + if ( charmap->platform_id == my_platform_id && + charmap->encoding_id == my_encoding_id ) + { + found = charmap; + break; + } + } + + if ( !found ) { return 0; } + + // now, select the charmap for the face object + err = FT_Set_Charmap( face, found ); + if ( err ) { return 0; } +*/ + glyph_index = FT_Get_Char_Index( face, 'A' ); + err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP); + if(err) success = 0; + else { + glyph = face->glyph; + if (glyph->format == ft_glyph_format_outline ) { + success = 1; + } else { + error("Selected Font has no outline data"); + success = 0; + } + } + } + + return success; +} + + +VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf) +{ + VFontData *vfd= NULL; + int success = 0; + + //init Freetype + err = FT_Init_FreeType( &library); + if(err) { + error("Failed to load the Freetype font library"); + return 0; + } + + success = check_freetypefont(pf); + + if (success) { + vfd= objfnt_to_ftvfontdata(pf); + } + + //free Freetype + FT_Done_FreeType( library); + + return vfd; +} + +int BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character) +{ + int success = FALSE; + + if(!vfont) return FALSE; + + // Init Freetype + err = FT_Init_FreeType(&library); + if(err) { + error("Failed to load the Freetype font library"); + return 0; + } + + // Load the character + success = objchr_to_ftvfontdata(vfont, character); + if(success == FALSE) return FALSE; + + // Free Freetype + FT_Done_FreeType(library); + + // Ahh everything ok + return TRUE; +} + +#endif // WITH_FREETYPE2 + + + +#if 0 + +// Freetype2 Outline struct + +typedef struct FT_Outline_ + { + short n_contours; /* number of contours in glyph */ + short n_points; /* number of points in the glyph */ + + FT_Vector* points; /* the outline's points */ + char* tags; /* the points flags */ + short* contours; /* the contour end points */ + + int flags; /* outline masks */ + + } FT_Outline; + +#endif + +/***//* +from: http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-1 + +Vectorial representation of Freetype glyphs + +The source format of outlines is a collection of closed paths called "contours". Each contour is +made of a series of line segments and bezier arcs. Depending on the file format, these can be +second-order or third-order polynomials. The former are also called quadratic or conic arcs, and +they come from the TrueType format. The latter are called cubic arcs and mostly come from the +Type1 format. + +Each arc is described through a series of start, end and control points. Each point of the outline +has a specific tag which indicates wether it is used to describe a line segment or an arc. + + +The following rules are applied to decompose the contour's points into segments and arcs : + +# two successive "on" points indicate a line segment joining them. + +# one conic "off" point amidst two "on" points indicates a conic bezier arc, the "off" point being + the control point, and the "on" ones the start and end points. + +# Two successive cubic "off" points amidst two "on" points indicate a cubic bezier arc. There must + be exactly two cubic control points and two on points for each cubic arc (using a single cubic + "off" point between two "on" points is forbidden, for example). + +# finally, two successive conic "off" points forces the rasterizer to create (during the scan-line + conversion process exclusively) a virtual "on" point amidst them, at their exact middle. This + greatly facilitates the definition of successive conic bezier arcs. Moreover, it's the way + outlines are described in the TrueType specification. + +Note that it is possible to mix conic and cubic arcs in a single contour, even though no current +font driver produces such outlines. + + * # on + * off + __---__ + #-__ _-- -_ + --__ _- - + --__ # \ + --__ # + -# + Two "on" points + Two "on" points and one "conic" point + between them + + + + * + # __ Two "on" points with two "conic" + \ - - points between them. The point + \ / \ marked '0' is the middle of the + - 0 \ "off" points, and is a 'virtual' + -_ _- # "on" point where the curve passes. + -- It does not appear in the point + list. + * + + + + + * # on + * * off + __---__ + _-- -_ + _- - + # \ + # + + Two "on" points + and two "cubic" point + between them + + +Each glyph's original outline points are located on a grid of indivisible units. The points are stored +in the font file as 16-bit integer grid coordinates, with the grid origin's being at (0,0); they thus +range from -16384 to 16383. + +Convert conic to bezier arcs: +Conic P0 P1 P2 +Bezier B0 B1 B2 B3 +B0=P0 +B1=(P0+2*P1)/3 +B2=(P2+2*P1)/3 +B3=P2 + +*//****/ diff --git a/source/blender/blenlib/intern/gsqueue.c b/source/blender/blenlib/intern/gsqueue.c new file mode 100644 index 00000000000..e52c573eec7 --- /dev/null +++ b/source/blender/blenlib/intern/gsqueue.c @@ -0,0 +1,122 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#include + +#include "MEM_guardedalloc.h" +#include "BLI_gsqueue.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +typedef struct _GSQueueElem GSQueueElem; +struct _GSQueueElem { + GSQueueElem *next; +}; + +struct _GSQueue { + GSQueueElem *head; + GSQueueElem *tail; + int elem_size; +}; + +GSQueue *BLI_gsqueue_new(int elem_size) +{ + GSQueue *gq= MEM_mallocN(sizeof(*gq), "gqueue_new"); + gq->head= gq->tail= NULL; + gq->elem_size= elem_size; + + return gq; +} + +int BLI_gsqueue_is_empty(GSQueue *gq) +{ + return (gq->head==NULL); +} + +void BLI_gsqueue_peek(GSQueue *gq, void *item_r) +{ + memcpy(item_r, &gq->head[1], gq->elem_size); +} +void BLI_gsqueue_pop(GSQueue *gq, void *item_r) +{ + GSQueueElem *elem= gq->head; + if (elem==gq->tail) { + gq->head= gq->tail= NULL; + } else { + gq->head= gq->head->next; + } + + if (item_r) memcpy(item_r, &elem[1], gq->elem_size); + MEM_freeN(elem); +} +void BLI_gsqueue_push(GSQueue *gq, void *item) +{ + GSQueueElem *elem; + + /* compare: prevent events added double in row */ + if (!BLI_gsqueue_is_empty(gq)) { + if(0==memcmp(item, &gq->head[1], gq->elem_size)) + return; + } + elem= MEM_mallocN(sizeof(*elem)+gq->elem_size, "gqueue_push"); + memcpy(&elem[1], item, gq->elem_size); + elem->next= NULL; + + if (BLI_gsqueue_is_empty(gq)) { + gq->tail= gq->head= elem; + } else { + gq->tail= gq->tail->next= elem; + } +} +void BLI_gsqueue_pushback(GSQueue *gq, void *item) +{ + GSQueueElem *elem= MEM_mallocN(sizeof(*elem)+gq->elem_size, "gqueue_push"); + memcpy(&elem[1], item, gq->elem_size); + elem->next= gq->head; + + if (BLI_gsqueue_is_empty(gq)) { + gq->head= gq->tail= elem; + } else { + gq->head= elem; + } +} + +void BLI_gsqueue_free(GSQueue *gq) +{ + while (gq->head) { + BLI_gsqueue_pop(gq, NULL); + } + MEM_freeN(gq); +} + + diff --git a/source/blender/blenlib/intern/jitter.c b/source/blender/blenlib/intern/jitter.c new file mode 100644 index 00000000000..fd658765802 --- /dev/null +++ b/source/blender/blenlib/intern/jitter.c @@ -0,0 +1,178 @@ +/** + * Jitter offset table + * + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include +#include +#include +#include "MEM_guardedalloc.h" + +#include "BLI_arithb.h" +#include "BLI_rand.h" +#include "BLI_jitter.h" + + +void BLI_jitterate1(float *jit1, float *jit2, int num, float rad1) +{ + int i , j , k; + float vecx, vecy, dvecx, dvecy, x, y, len; + + for (i = 2*num-2; i>=0 ; i-=2) { + dvecx = dvecy = 0.0; + x = jit1[i]; + y = jit1[i+1]; + for (j = 2*num-2; j>=0 ; j-=2) { + if (i != j){ + vecx = jit1[j] - x - 1.0; + vecy = jit1[j+1] - y - 1.0; + for (k = 3; k>0 ; k--){ + if( fabs(vecx)0 && len0 && len0 && len= 0 ; i-=2){ + dvecx = dvecy = 0.0; + x = jit1[i]; + y = jit1[i+1]; + for (j =2*num -2; j>= 0 ; j-=2){ + if (i != j){ + vecx = jit1[j] - x - 1.0; + vecy = jit1[j+1] - y - 1.0; + + if( fabs(vecx) +#include "MTC_matrixops.h" +#include "MTC_vectorops.h" +/* ------------------------------------------------------------------------- */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(__sun__) || defined( __sun ) || defined (__sparc) || defined (__sparc__) +#include +#endif + +#define ABS(x) ((x) < 0 ? -(x) : (x)) +#define SWAP(type, a, b) { type sw_ap; sw_ap=(a); (a)=(b); (b)=sw_ap; } + +void MTC_Mat4CpyMat4(float m1[][4], float m2[][4]) +{ + memcpy(m1, m2, 4*4*sizeof(float)); +} + +/* ------------------------------------------------------------------------- */ + +void MTC_Mat4MulSerie(float answ[][4], + float m1[][4], float m2[][4], float m3[][4], + float m4[][4], float m5[][4], float m6[][4], + float m7[][4], float m8[][4]) +{ + float temp[4][4]; + + if(m1==0 || m2==0) return; + + MTC_Mat4MulMat4(answ, m2, m1); + if(m3) { + MTC_Mat4MulMat4(temp, m3, answ); + if(m4) { + MTC_Mat4MulMat4(answ, m4, temp); + if(m5) { + MTC_Mat4MulMat4(temp, m5, answ); + if(m6) { + MTC_Mat4MulMat4(answ, m6, temp); + if(m7) { + MTC_Mat4MulMat4(temp, m7, answ); + if(m8) { + MTC_Mat4MulMat4(answ, m8, temp); + } + else MTC_Mat4CpyMat4(answ, temp); + } + } + else MTC_Mat4CpyMat4(answ, temp); + } + } + else MTC_Mat4CpyMat4(answ, temp); + } +} + +/* ------------------------------------------------------------------------- */ +void MTC_Mat4MulMat4(float m1[][4], float m2[][4], float m3[][4]) +{ + /* matrix product: c[j][k] = a[j][i].b[i][k] */ + + m1[0][0] = m2[0][0]*m3[0][0] + m2[0][1]*m3[1][0] + m2[0][2]*m3[2][0] + m2[0][3]*m3[3][0]; + m1[0][1] = m2[0][0]*m3[0][1] + m2[0][1]*m3[1][1] + m2[0][2]*m3[2][1] + m2[0][3]*m3[3][1]; + m1[0][2] = m2[0][0]*m3[0][2] + m2[0][1]*m3[1][2] + m2[0][2]*m3[2][2] + m2[0][3]*m3[3][2]; + m1[0][3] = m2[0][0]*m3[0][3] + m2[0][1]*m3[1][3] + m2[0][2]*m3[2][3] + m2[0][3]*m3[3][3]; + + m1[1][0] = m2[1][0]*m3[0][0] + m2[1][1]*m3[1][0] + m2[1][2]*m3[2][0] + m2[1][3]*m3[3][0]; + m1[1][1] = m2[1][0]*m3[0][1] + m2[1][1]*m3[1][1] + m2[1][2]*m3[2][1] + m2[1][3]*m3[3][1]; + m1[1][2] = m2[1][0]*m3[0][2] + m2[1][1]*m3[1][2] + m2[1][2]*m3[2][2] + m2[1][3]*m3[3][2]; + m1[1][3] = m2[1][0]*m3[0][3] + m2[1][1]*m3[1][3] + m2[1][2]*m3[2][3] + m2[1][3]*m3[3][3]; + + m1[2][0] = m2[2][0]*m3[0][0] + m2[2][1]*m3[1][0] + m2[2][2]*m3[2][0] + m2[2][3]*m3[3][0]; + m1[2][1] = m2[2][0]*m3[0][1] + m2[2][1]*m3[1][1] + m2[2][2]*m3[2][1] + m2[2][3]*m3[3][1]; + m1[2][2] = m2[2][0]*m3[0][2] + m2[2][1]*m3[1][2] + m2[2][2]*m3[2][2] + m2[2][3]*m3[3][2]; + m1[2][3] = m2[2][0]*m3[0][3] + m2[2][1]*m3[1][3] + m2[2][2]*m3[2][3] + m2[2][3]*m3[3][3]; + + m1[3][0] = m2[3][0]*m3[0][0] + m2[3][1]*m3[1][0] + m2[3][2]*m3[2][0] + m2[3][3]*m3[3][0]; + m1[3][1] = m2[3][0]*m3[0][1] + m2[3][1]*m3[1][1] + m2[3][2]*m3[2][1] + m2[3][3]*m3[3][1]; + m1[3][2] = m2[3][0]*m3[0][2] + m2[3][1]*m3[1][2] + m2[3][2]*m3[2][2] + m2[3][3]*m3[3][2]; + m1[3][3] = m2[3][0]*m3[0][3] + m2[3][1]*m3[1][3] + m2[3][2]*m3[2][3] + m2[3][3]*m3[3][3]; + +} +/* ------------------------------------------------------------------------- */ + +void MTC_Mat4MulVecfl(float mat[][4], float *vec) +{ + float x,y; + + x=vec[0]; + y=vec[1]; + vec[0]=x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2] + mat[3][0]; + vec[1]=x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2] + mat[3][1]; + vec[2]=x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2] + mat[3][2]; +} + +/* ------------------------------------------------------------------------- */ +void MTC_Mat3MulVecfl(float mat[][3], float *vec) +{ + float x,y; + + x=vec[0]; + y=vec[1]; + vec[0]= x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2]; + vec[1]= x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2]; + vec[2]= x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2]; +} + +/* ------------------------------------------------------------------------- */ + +int MTC_Mat4Invert(float inverse[][4], float mat[][4]) +{ + int i, j, k; + double temp; + float tempmat[4][4]; + float max; + int maxj; + + /* Set inverse to identity */ + for (i=0; i<4; i++) + for (j=0; j<4; j++) + inverse[i][j] = 0; + for (i=0; i<4; i++) + inverse[i][i] = 1; + + /* Copy original matrix so we don't mess it up */ + for(i = 0; i < 4; i++) + for(j = 0; j <4; j++) + tempmat[i][j] = mat[i][j]; + + for(i = 0; i < 4; i++) { + /* Look for row with max pivot */ + max = ABS(tempmat[i][i]); + maxj = i; + for(j = i + 1; j < 4; j++) { + if(ABS(tempmat[j][i]) > max) { + max = ABS(tempmat[j][i]); + maxj = j; + } + } + /* Swap rows if necessary */ + if (maxj != i) { + for( k = 0; k < 4; k++) { + SWAP(float, tempmat[i][k], tempmat[maxj][k]); + SWAP(float, inverse[i][k], inverse[maxj][k]); + } + } + + temp = tempmat[i][i]; + if (temp == 0) + return 0; /* No non-zero pivot */ + for(k = 0; k < 4; k++) { + tempmat[i][k] /= temp; + inverse[i][k] /= temp; + } + for(j = 0; j < 4; j++) { + if(j != i) { + temp = tempmat[j][i]; + for(k = 0; k < 4; k++) { + tempmat[j][k] -= tempmat[i][k]*temp; + inverse[j][k] -= inverse[i][k]*temp; + } + } + } + } + return 1; +} + +/* ------------------------------------------------------------------------- */ +void MTC_Mat3CpyMat4(float m1[][3], float m2[][4]) +{ + + m1[0][0]= m2[0][0]; + m1[0][1]= m2[0][1]; + m1[0][2]= m2[0][2]; + + m1[1][0]= m2[1][0]; + m1[1][1]= m2[1][1]; + m1[1][2]= m2[1][2]; + + m1[2][0]= m2[2][0]; + m1[2][1]= m2[2][1]; + m1[2][2]= m2[2][2]; +} + +/* ------------------------------------------------------------------------- */ + +void MTC_Mat3CpyMat3(float m1[][3], float m2[][3]) +{ + memcpy(m1, m2, 3*3*sizeof(float)); +} + +/* ------------------------------------------------------------------------- */ +/* void Mat3MulMat3(float m1[][3], float m3[][3], float m2[][3]) */ +void MTC_Mat3MulMat3(float m1[][3], float m3[][3], float m2[][3]) +{ + /* be careful about this rewrite... */ + /* m1[i][j] = m2[i][k]*m3[k][j], args are flipped! */ + m1[0][0]= m2[0][0]*m3[0][0] + m2[0][1]*m3[1][0] + m2[0][2]*m3[2][0]; + m1[0][1]= m2[0][0]*m3[0][1] + m2[0][1]*m3[1][1] + m2[0][2]*m3[2][1]; + m1[0][2]= m2[0][0]*m3[0][2] + m2[0][1]*m3[1][2] + m2[0][2]*m3[2][2]; + + m1[1][0]= m2[1][0]*m3[0][0] + m2[1][1]*m3[1][0] + m2[1][2]*m3[2][0]; + m1[1][1]= m2[1][0]*m3[0][1] + m2[1][1]*m3[1][1] + m2[1][2]*m3[2][1]; + m1[1][2]= m2[1][0]*m3[0][2] + m2[1][1]*m3[1][2] + m2[1][2]*m3[2][2]; + + m1[2][0]= m2[2][0]*m3[0][0] + m2[2][1]*m3[1][0] + m2[2][2]*m3[2][0]; + m1[2][1]= m2[2][0]*m3[0][1] + m2[2][1]*m3[1][1] + m2[2][2]*m3[2][1]; + m1[2][2]= m2[2][0]*m3[0][2] + m2[2][1]*m3[1][2] + m2[2][2]*m3[2][2]; + +/* m1[0]= m2[0]*m3[0] + m2[1]*m3[3] + m2[2]*m3[6]; */ +/* m1[1]= m2[0]*m3[1] + m2[1]*m3[4] + m2[2]*m3[7]; */ +/* m1[2]= m2[0]*m3[2] + m2[1]*m3[5] + m2[2]*m3[8]; */ +/* m1+=3; */ +/* m2+=3; */ +/* m1[0]= m2[0]*m3[0] + m2[1]*m3[3] + m2[2]*m3[6]; */ +/* m1[1]= m2[0]*m3[1] + m2[1]*m3[4] + m2[2]*m3[7]; */ +/* m1[2]= m2[0]*m3[2] + m2[1]*m3[5] + m2[2]*m3[8]; */ +/* m1+=3; */ +/* m2+=3; */ +/* m1[0]= m2[0]*m3[0] + m2[1]*m3[3] + m2[2]*m3[6]; */ +/* m1[1]= m2[0]*m3[1] + m2[1]*m3[4] + m2[2]*m3[7]; */ +/* m1[2]= m2[0]*m3[2] + m2[1]*m3[5] + m2[2]*m3[8]; */ +} /* end of void Mat3MulMat3(float m1[][3], float m3[][3], float m2[][3]) */ + +/* ------------------------------------------------------------------------- */ + +void MTC_Mat4Ortho(float mat[][4]) +{ + float len; + + len= MTC_normalize3DF(mat[0]); + if(len!=0.0) mat[0][3]/= len; + len= MTC_normalize3DF(mat[1]); + if(len!=0.0) mat[1][3]/= len; + len= MTC_normalize3DF(mat[2]); + if(len!=0.0) mat[2][3]/= len; +} + +/* ------------------------------------------------------------------------- */ + +void MTC_Mat4Mul3Vecfl(float mat[][4], float *vec) +{ + float x,y; + /* vec = mat^T dot vec !!! or vec a row, then vec = vec dot mat*/ + + x= vec[0]; + y= vec[1]; + vec[0]= x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2]; + vec[1]= x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2]; + vec[2]= x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2]; +} + +/* ------------------------------------------------------------------------- */ + +void MTC_Mat4One(float m[][4]) +{ + + m[0][0]= m[1][1]= m[2][2]= m[3][3]= 1.0; + m[0][1]= m[0][2]= m[0][3]= 0.0; + m[1][0]= m[1][2]= m[1][3]= 0.0; + m[2][0]= m[2][1]= m[2][3]= 0.0; + m[3][0]= m[3][1]= m[3][2]= 0.0; +} + + +/* ------------------------------------------------------------------------- */ +/* Result is a 3-vector!*/ +void MTC_Mat3MulVecd(float mat[][3], double *vec) +{ + double x,y; + + /* vec = mat^T dot vec !!! or vec a row, then vec = vec dot mat*/ + x=vec[0]; + y=vec[1]; + vec[0]= x * mat[0][0] + y * mat[1][0] + mat[2][0] * vec[2]; + vec[1]= x * mat[0][1] + y * mat[1][1] + mat[2][1] * vec[2]; + vec[2]= x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2]; +} + +/* ------------------------------------------------------------------------- */ + +void MTC_Mat3Inv(float m1[][3], float m2[][3]) +{ + short a,b; + float det; + + /* first adjoint */ + MTC_Mat3Adj(m1,m2); + + /* then determinant old mat! */ + det= m2[0][0]* (m2[1][1]*m2[2][2] - m2[1][2]*m2[2][1]) + -m2[1][0]* (m2[0][1]*m2[2][2] - m2[0][2]*m2[2][1]) + +m2[2][0]* (m2[0][1]*m2[1][2] - m2[0][2]*m2[1][1]); + + if(det==0) det=1; + det= 1/det; + for(a=0;a<3;a++) { + for(b=0;b<3;b++) { + m1[a][b]*=det; + } + } +} + +/* ------------------------------------------------------------------------- */ + +void MTC_Mat3Adj(float m1[][3], float m[][3]) +{ + m1[0][0]=m[1][1]*m[2][2]-m[1][2]*m[2][1]; + m1[0][1]= -m[0][1]*m[2][2]+m[0][2]*m[2][1]; + m1[0][2]=m[0][1]*m[1][2]-m[0][2]*m[1][1]; + + m1[1][0]= -m[1][0]*m[2][2]+m[1][2]*m[2][0]; + m1[1][1]=m[0][0]*m[2][2]-m[0][2]*m[2][0]; + m1[1][2]= -m[0][0]*m[1][2]+m[0][2]*m[1][0]; + + m1[2][0]=m[1][0]*m[2][1]-m[1][1]*m[2][0]; + m1[2][1]= -m[0][0]*m[2][1]+m[0][1]*m[2][0]; + m1[2][2]=m[0][0]*m[1][1]-m[0][1]*m[1][0]; +} + +/* ------------------------------------------------------------------------- */ + +void MTC_Mat3One(float m[][3]) +{ + + m[0][0]= m[1][1]= m[2][2]= 1.0; + m[0][1]= m[0][2]= 0.0; + m[1][0]= m[1][2]= 0.0; + m[2][0]= m[2][1]= 0.0; +} + +/* ------------------------------------------------------------------------- */ + +void MTC_Mat4SwapMat4(float m1[][4], float m2[][4]) +{ + float t; + int i, j; + + for(i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + t = m1[i][j]; + m1[i][j] = m2[i][j]; + m2[i][j] = t; + } + } +} + +/* ------------------------------------------------------------------------- */ + +void MTC_Mat4MulVec4fl(float mat[][4], float *vec) +{ + float x,y,z; + + x = vec[0]; + y = vec[1]; + z = vec[2]; + vec[0] = x*mat[0][0] + y*mat[1][0] + z*mat[2][0] + mat[3][0]*vec[3]; + vec[1] = x*mat[0][1] + y*mat[1][1] + z*mat[2][1] + mat[3][1]*vec[3]; + vec[2] = x*mat[0][2] + y*mat[1][2] + z*mat[2][2] + mat[3][2]*vec[3]; + vec[3] = x*mat[0][3] + y*mat[1][3] + z*mat[2][3] + mat[3][3]*vec[3]; +} + +/* ------------------------------------------------------------------------- */ + +void MTC_Mat4CpyMat3nc(float m1[][4], float m2[][3]) /* no clear */ +{ + m1[0][0]= m2[0][0]; + m1[0][1]= m2[0][1]; + m1[0][2]= m2[0][2]; + + m1[1][0]= m2[1][0]; + m1[1][1]= m2[1][1]; + m1[1][2]= m2[1][2]; + + m1[2][0]= m2[2][0]; + m1[2][1]= m2[2][1]; + m1[2][2]= m2[2][2]; +} + +/* ------------------------------------------------------------------------- */ + +void MTC_Mat4MulMat33(float m1[][3], float m2[][4], float m3[][3]) +{ + /* m1_i_j = m2_i_k * m3_k_j ? */ + + m1[0][0] = m2[0][0]*m3[0][0] + m2[0][1]*m3[1][0] + m2[0][2]*m3[2][0]; + m1[0][1] = m2[0][0]*m3[0][1] + m2[0][1]*m3[1][1] + m2[0][2]*m3[2][1]; + m1[0][2] = m2[0][0]*m3[0][2] + m2[0][1]*m3[1][2] + m2[0][2]*m3[2][2]; + + m1[1][0] = m2[1][0]*m3[0][0] + m2[1][1]*m3[1][0] + m2[1][2]*m3[2][0]; + m1[1][1] = m2[1][0]*m3[0][1] + m2[1][1]*m3[1][1] + m2[1][2]*m3[2][1]; + m1[1][2] = m2[1][0]*m3[0][2] + m2[1][1]*m3[1][2] + m2[1][2]*m3[2][2]; + + m1[2][0] = m2[2][0]*m3[0][0] + m2[2][1]*m3[1][0] + m2[2][2]*m3[2][0]; + m1[2][1] = m2[2][0]*m3[0][1] + m2[2][1]*m3[1][1] + m2[2][2]*m3[2][1]; + m1[2][2] = m2[2][0]*m3[0][2] + m2[2][1]*m3[1][2] + m2[2][2]*m3[2][2]; + +} + +/* ------------------------------------------------------------------------- */ + +/* eof */ diff --git a/source/blender/blenlib/intern/noise.c b/source/blender/blenlib/intern/noise.c new file mode 100644 index 00000000000..4fa2d1fdd48 --- /dev/null +++ b/source/blender/blenlib/intern/noise.c @@ -0,0 +1,1392 @@ +/* + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + */ + +#ifdef _WIN32 +#pragma warning (disable : 4244) // "conversion from double to float" +#pragma warning (disable : 4305) // "truncation from const double to float" +#endif + +#include +#include "BLI_blenlib.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +/* local */ +float noise3_perlin(float vec[3]); +float turbulence_perlin(float *point, float lofreq, float hifreq); +float turbulencep(float noisesize, float x, float y, float z, int nr); + +#define HASHVEC(x,y,z) hashvectf+3*hash[ (hash[ (hash[(z) & 255]+(y)) & 255]+(x)) & 255] + +/* needed for voronoi */ +#define HASHPNT(x,y,z) hashpntf+3*hash[ (hash[ (hash[(z) & 255]+(y)) & 255]+(x)) & 255] +static float hashpntf[768] = {0.536902, 0.020915, 0.501445, 0.216316, 0.517036, 0.822466, 0.965315, +0.377313, 0.678764, 0.744545, 0.097731, 0.396357, 0.247202, 0.520897, +0.613396, 0.542124, 0.146813, 0.255489, 0.810868, 0.638641, 0.980742, +0.292316, 0.357948, 0.114382, 0.861377, 0.629634, 0.722530, 0.714103, +0.048549, 0.075668, 0.564920, 0.162026, 0.054466, 0.411738, 0.156897, +0.887657, 0.599368, 0.074249, 0.170277, 0.225799, 0.393154, 0.301348, +0.057434, 0.293849, 0.442745, 0.150002, 0.398732, 0.184582, 0.915200, +0.630984, 0.974040, 0.117228, 0.795520, 0.763238, 0.158982, 0.616211, +0.250825, 0.906539, 0.316874, 0.676205, 0.234720, 0.667673, 0.792225, +0.273671, 0.119363, 0.199131, 0.856716, 0.828554, 0.900718, 0.705960, +0.635923, 0.989433, 0.027261, 0.283507, 0.113426, 0.388115, 0.900176, +0.637741, 0.438802, 0.715490, 0.043692, 0.202640, 0.378325, 0.450325, +0.471832, 0.147803, 0.906899, 0.524178, 0.784981, 0.051483, 0.893369, +0.596895, 0.275635, 0.391483, 0.844673, 0.103061, 0.257322, 0.708390, +0.504091, 0.199517, 0.660339, 0.376071, 0.038880, 0.531293, 0.216116, +0.138672, 0.907737, 0.807994, 0.659582, 0.915264, 0.449075, 0.627128, +0.480173, 0.380942, 0.018843, 0.211808, 0.569701, 0.082294, 0.689488, +0.573060, 0.593859, 0.216080, 0.373159, 0.108117, 0.595539, 0.021768, +0.380297, 0.948125, 0.377833, 0.319699, 0.315249, 0.972805, 0.792270, +0.445396, 0.845323, 0.372186, 0.096147, 0.689405, 0.423958, 0.055675, +0.117940, 0.328456, 0.605808, 0.631768, 0.372170, 0.213723, 0.032700, +0.447257, 0.440661, 0.728488, 0.299853, 0.148599, 0.649212, 0.498381, +0.049921, 0.496112, 0.607142, 0.562595, 0.990246, 0.739659, 0.108633, +0.978156, 0.209814, 0.258436, 0.876021, 0.309260, 0.600673, 0.713597, +0.576967, 0.641402, 0.853930, 0.029173, 0.418111, 0.581593, 0.008394, +0.589904, 0.661574, 0.979326, 0.275724, 0.111109, 0.440472, 0.120839, +0.521602, 0.648308, 0.284575, 0.204501, 0.153286, 0.822444, 0.300786, +0.303906, 0.364717, 0.209038, 0.916831, 0.900245, 0.600685, 0.890002, +0.581660, 0.431154, 0.705569, 0.551250, 0.417075, 0.403749, 0.696652, +0.292652, 0.911372, 0.690922, 0.323718, 0.036773, 0.258976, 0.274265, +0.225076, 0.628965, 0.351644, 0.065158, 0.080340, 0.467271, 0.130643, +0.385914, 0.919315, 0.253821, 0.966163, 0.017439, 0.392610, 0.478792, +0.978185, 0.072691, 0.982009, 0.097987, 0.731533, 0.401233, 0.107570, +0.349587, 0.479122, 0.700598, 0.481751, 0.788429, 0.706864, 0.120086, +0.562691, 0.981797, 0.001223, 0.192120, 0.451543, 0.173092, 0.108960, +0.549594, 0.587892, 0.657534, 0.396365, 0.125153, 0.666420, 0.385823, +0.890916, 0.436729, 0.128114, 0.369598, 0.759096, 0.044677, 0.904752, +0.088052, 0.621148, 0.005047, 0.452331, 0.162032, 0.494238, 0.523349, +0.741829, 0.698450, 0.452316, 0.563487, 0.819776, 0.492160, 0.004210, +0.647158, 0.551475, 0.362995, 0.177937, 0.814722, 0.727729, 0.867126, +0.997157, 0.108149, 0.085726, 0.796024, 0.665075, 0.362462, 0.323124, +0.043718, 0.042357, 0.315030, 0.328954, 0.870845, 0.683186, 0.467922, +0.514894, 0.809971, 0.631979, 0.176571, 0.366320, 0.850621, 0.505555, +0.749551, 0.750830, 0.401714, 0.481216, 0.438393, 0.508832, 0.867971, +0.654581, 0.058204, 0.566454, 0.084124, 0.548539, 0.902690, 0.779571, +0.562058, 0.048082, 0.863109, 0.079290, 0.713559, 0.783496, 0.265266, +0.672089, 0.786939, 0.143048, 0.086196, 0.876129, 0.408708, 0.229312, +0.629995, 0.206665, 0.207308, 0.710079, 0.341704, 0.264921, 0.028748, +0.629222, 0.470173, 0.726228, 0.125243, 0.328249, 0.794187, 0.741340, +0.489895, 0.189396, 0.724654, 0.092841, 0.039809, 0.860126, 0.247701, +0.655331, 0.964121, 0.672536, 0.044522, 0.690567, 0.837238, 0.631520, +0.953734, 0.352484, 0.289026, 0.034152, 0.852575, 0.098454, 0.795529, +0.452181, 0.826159, 0.186993, 0.820725, 0.440328, 0.922137, 0.704592, +0.915437, 0.738183, 0.733461, 0.193798, 0.929213, 0.161390, 0.318547, +0.888751, 0.430968, 0.740837, 0.193544, 0.872253, 0.563074, 0.274598, +0.347805, 0.666176, 0.449831, 0.800991, 0.588727, 0.052296, 0.714761, +0.420620, 0.570325, 0.057550, 0.210888, 0.407312, 0.662848, 0.924382, +0.895958, 0.775198, 0.688605, 0.025721, 0.301913, 0.791408, 0.500602, +0.831984, 0.828509, 0.642093, 0.494174, 0.525880, 0.446365, 0.440063, +0.763114, 0.630358, 0.223943, 0.333806, 0.906033, 0.498306, 0.241278, +0.427640, 0.772683, 0.198082, 0.225379, 0.503894, 0.436599, 0.016503, +0.803725, 0.189878, 0.291095, 0.499114, 0.151573, 0.079031, 0.904618, +0.708535, 0.273900, 0.067419, 0.317124, 0.936499, 0.716511, 0.543845, +0.939909, 0.826574, 0.715090, 0.154864, 0.750150, 0.845808, 0.648108, +0.556564, 0.644757, 0.140873, 0.799167, 0.632989, 0.444245, 0.471978, +0.435910, 0.359793, 0.216241, 0.007633, 0.337236, 0.857863, 0.380247, +0.092517, 0.799973, 0.919000, 0.296798, 0.096989, 0.854831, 0.165369, +0.568475, 0.216855, 0.020457, 0.835511, 0.538039, 0.999742, 0.620226, +0.244053, 0.060399, 0.323007, 0.294874, 0.988899, 0.384919, 0.735655, +0.773428, 0.549776, 0.292882, 0.660611, 0.593507, 0.621118, 0.175269, +0.682119, 0.794493, 0.868197, 0.632150, 0.807823, 0.509656, 0.482035, +0.001780, 0.259126, 0.358002, 0.280263, 0.192985, 0.290367, 0.208111, +0.917633, 0.114422, 0.925491, 0.981110, 0.255570, 0.974862, 0.016629, +0.552599, 0.575741, 0.612978, 0.615965, 0.803615, 0.772334, 0.089745, +0.838812, 0.634542, 0.113709, 0.755832, 0.577589, 0.667489, 0.529834, +0.325660, 0.817597, 0.316557, 0.335093, 0.737363, 0.260951, 0.737073, +0.049540, 0.735541, 0.988891, 0.299116, 0.147695, 0.417271, 0.940811, +0.524160, 0.857968, 0.176403, 0.244835, 0.485759, 0.033353, 0.280319, +0.750688, 0.755809, 0.924208, 0.095956, 0.962504, 0.275584, 0.173715, +0.942716, 0.706721, 0.078464, 0.576716, 0.804667, 0.559249, 0.900611, +0.646904, 0.432111, 0.927885, 0.383277, 0.269973, 0.114244, 0.574867, +0.150703, 0.241855, 0.272871, 0.199950, 0.079719, 0.868566, 0.962833, +0.789122, 0.320025, 0.905554, 0.234876, 0.991356, 0.061913, 0.732911, +0.785960, 0.874074, 0.069035, 0.658632, 0.309901, 0.023676, 0.791603, +0.764661, 0.661278, 0.319583, 0.829650, 0.117091, 0.903124, 0.982098, +0.161631, 0.193576, 0.670428, 0.857390, 0.003760, 0.572578, 0.222162, +0.114551, 0.420118, 0.530404, 0.470682, 0.525527, 0.764281, 0.040596, +0.443275, 0.501124, 0.816161, 0.417467, 0.332172, 0.447565, 0.614591, +0.559246, 0.805295, 0.226342, 0.155065, 0.714630, 0.160925, 0.760001, +0.453456, 0.093869, 0.406092, 0.264801, 0.720370, 0.743388, 0.373269, +0.403098, 0.911923, 0.897249, 0.147038, 0.753037, 0.516093, 0.739257, +0.175018, 0.045768, 0.735857, 0.801330, 0.927708, 0.240977, 0.591870, +0.921831, 0.540733, 0.149100, 0.423152, 0.806876, 0.397081, 0.061100, +0.811630, 0.044899, 0.460915, 0.961202, 0.822098, 0.971524, 0.867608, +0.773604, 0.226616, 0.686286, 0.926972, 0.411613, 0.267873, 0.081937, +0.226124, 0.295664, 0.374594, 0.533240, 0.237876, 0.669629, 0.599083, +0.513081, 0.878719, 0.201577, 0.721296, 0.495038, 0.079760, 0.965959, +0.233090, 0.052496, 0.714748, 0.887844, 0.308724, 0.972885, 0.723337, +0.453089, 0.914474, 0.704063, 0.823198, 0.834769, 0.906561, 0.919600, +0.100601, 0.307564, 0.901977, 0.468879, 0.265376, 0.885188, 0.683875, +0.868623, 0.081032, 0.466835, 0.199087, 0.663437, 0.812241, 0.311337, +0.821361, 0.356628, 0.898054, 0.160781, 0.222539, 0.714889, 0.490287, +0.984915, 0.951755, 0.964097, 0.641795, 0.815472, 0.852732, 0.862074, +0.051108, 0.440139, 0.323207, 0.517171, 0.562984, 0.115295, 0.743103, +0.977914, 0.337596, 0.440694, 0.535879, 0.959427, 0.351427, 0.704361, +0.010826, 0.131162, 0.577080, 0.349572, 0.774892, 0.425796, 0.072697, +0.500001, 0.267322, 0.909654, 0.206176, 0.223987, 0.937698, 0.323423, +0.117501, 0.490308, 0.474372, 0.689943, 0.168671, 0.719417, 0.188928, +0.330464, 0.265273, 0.446271, 0.171933, 0.176133, 0.474616, 0.140182, +0.114246, 0.905043, 0.713870, 0.555261, 0.951333}; + +unsigned char hash[512]= { +0xA2,0xA0,0x19,0x3B,0xF8,0xEB,0xAA,0xEE,0xF3,0x1C,0x67,0x28,0x1D,0xED,0x0,0xDE,0x95,0x2E,0xDC,0x3F,0x3A,0x82,0x35,0x4D,0x6C,0xBA,0x36,0xD0,0xF6,0xC,0x79,0x32,0xD1,0x59,0xF4,0x8,0x8B,0x63,0x89,0x2F,0xB8,0xB4,0x97,0x83,0xF2,0x8F,0x18,0xC7,0x51,0x14,0x65,0x87,0x48,0x20,0x42,0xA8,0x80,0xB5,0x40,0x13,0xB2,0x22,0x7E,0x57, +0xBC,0x7F,0x6B,0x9D,0x86,0x4C,0xC8,0xDB,0x7C,0xD5,0x25,0x4E,0x5A,0x55,0x74,0x50,0xCD,0xB3,0x7A,0xBB,0xC3,0xCB,0xB6,0xE2,0xE4,0xEC,0xFD,0x98,0xB,0x96,0xD3,0x9E,0x5C,0xA1,0x64,0xF1,0x81,0x61,0xE1,0xC4,0x24,0x72,0x49,0x8C,0x90,0x4B,0x84,0x34,0x38,0xAB,0x78,0xCA,0x1F,0x1,0xD7,0x93,0x11,0xC1,0x58,0xA9,0x31,0xF9,0x44,0x6D, +0xBF,0x33,0x9C,0x5F,0x9,0x94,0xA3,0x85,0x6,0xC6,0x9A,0x1E,0x7B,0x46,0x15,0x30,0x27,0x2B,0x1B,0x71,0x3C,0x5B,0xD6,0x6F,0x62,0xAC,0x4F,0xC2,0xC0,0xE,0xB1,0x23,0xA7,0xDF,0x47,0xB0,0x77,0x69,0x5,0xE9,0xE6,0xE7,0x76,0x73,0xF,0xFE,0x6E,0x9B,0x56,0xEF,0x12,0xA5,0x37,0xFC,0xAE,0xD9,0x3,0x8E,0xDD,0x10,0xB9,0xCE,0xC9,0x8D, +0xDA,0x2A,0xBD,0x68,0x17,0x9F,0xBE,0xD4,0xA,0xCC,0xD2,0xE8,0x43,0x3D,0x70,0xB7,0x2,0x7D,0x99,0xD8,0xD,0x60,0x8A,0x4,0x2C,0x3E,0x92,0xE5,0xAF,0x53,0x7,0xE0,0x29,0xA6,0xC5,0xE3,0xF5,0xF7,0x4A,0x41,0x26,0x6A,0x16,0x5E,0x52,0x2D,0x21,0xAD,0xF0,0x91,0xFF,0xEA,0x54,0xFA,0x66,0x1A,0x45,0x39,0xCF,0x75,0xA4,0x88,0xFB,0x5D, +0xA2,0xA0,0x19,0x3B,0xF8,0xEB,0xAA,0xEE,0xF3,0x1C,0x67,0x28,0x1D,0xED,0x0,0xDE,0x95,0x2E,0xDC,0x3F,0x3A,0x82,0x35,0x4D,0x6C,0xBA,0x36,0xD0,0xF6,0xC,0x79,0x32,0xD1,0x59,0xF4,0x8,0x8B,0x63,0x89,0x2F,0xB8,0xB4,0x97,0x83,0xF2,0x8F,0x18,0xC7,0x51,0x14,0x65,0x87,0x48,0x20,0x42,0xA8,0x80,0xB5,0x40,0x13,0xB2,0x22,0x7E,0x57, +0xBC,0x7F,0x6B,0x9D,0x86,0x4C,0xC8,0xDB,0x7C,0xD5,0x25,0x4E,0x5A,0x55,0x74,0x50,0xCD,0xB3,0x7A,0xBB,0xC3,0xCB,0xB6,0xE2,0xE4,0xEC,0xFD,0x98,0xB,0x96,0xD3,0x9E,0x5C,0xA1,0x64,0xF1,0x81,0x61,0xE1,0xC4,0x24,0x72,0x49,0x8C,0x90,0x4B,0x84,0x34,0x38,0xAB,0x78,0xCA,0x1F,0x1,0xD7,0x93,0x11,0xC1,0x58,0xA9,0x31,0xF9,0x44,0x6D, +0xBF,0x33,0x9C,0x5F,0x9,0x94,0xA3,0x85,0x6,0xC6,0x9A,0x1E,0x7B,0x46,0x15,0x30,0x27,0x2B,0x1B,0x71,0x3C,0x5B,0xD6,0x6F,0x62,0xAC,0x4F,0xC2,0xC0,0xE,0xB1,0x23,0xA7,0xDF,0x47,0xB0,0x77,0x69,0x5,0xE9,0xE6,0xE7,0x76,0x73,0xF,0xFE,0x6E,0x9B,0x56,0xEF,0x12,0xA5,0x37,0xFC,0xAE,0xD9,0x3,0x8E,0xDD,0x10,0xB9,0xCE,0xC9,0x8D, +0xDA,0x2A,0xBD,0x68,0x17,0x9F,0xBE,0xD4,0xA,0xCC,0xD2,0xE8,0x43,0x3D,0x70,0xB7,0x2,0x7D,0x99,0xD8,0xD,0x60,0x8A,0x4,0x2C,0x3E,0x92,0xE5,0xAF,0x53,0x7,0xE0,0x29,0xA6,0xC5,0xE3,0xF5,0xF7,0x4A,0x41,0x26,0x6A,0x16,0x5E,0x52,0x2D,0x21,0xAD,0xF0,0x91,0xFF,0xEA,0x54,0xFA,0x66,0x1A,0x45,0x39,0xCF,0x75,0xA4,0x88,0xFB,0x5D, +}; + + +float hashvectf[768]= { +0.33783,0.715698,-0.611206,-0.944031,-0.326599,-0.045624,-0.101074,-0.416443,-0.903503,0.799286,0.49411,-0.341949,-0.854645,0.518036,0.033936,0.42514,-0.437866,-0.792114,-0.358948,0.597046,0.717377,-0.985413,0.144714,0.089294,-0.601776,-0.33728,-0.723907,-0.449921,0.594513,0.666382,0.208313,-0.10791, +0.972076,0.575317,0.060425,0.815643,0.293365,-0.875702,-0.383453,0.293762,0.465759,0.834686,-0.846008,-0.233398,-0.47934,-0.115814,0.143036,-0.98291,0.204681,-0.949036,-0.239532,0.946716,-0.263947,0.184326,-0.235596,0.573822,0.784332,0.203705,-0.372253,-0.905487,0.756989,-0.651031,0.055298,0.497803, +0.814697,-0.297363,-0.16214,0.063995,-0.98468,-0.329254,0.834381,0.441925,0.703827,-0.527039,-0.476227,0.956421,0.266113,0.119781,0.480133,0.482849,0.7323,-0.18631,0.961212,-0.203125,-0.748474,-0.656921,-0.090393,-0.085052,-0.165253,0.982544,-0.76947,0.628174,-0.115234,0.383148,0.537659,0.751068, +0.616486,-0.668488,-0.415924,-0.259979,-0.630005,0.73175,0.570953,-0.087952,0.816223,-0.458008,0.023254,0.888611,-0.196167,0.976563,-0.088287,-0.263885,-0.69812,-0.665527,0.437134,-0.892273,-0.112793,-0.621674,-0.230438,0.748566,0.232422,0.900574,-0.367249,0.22229,-0.796143,0.562744,-0.665497,-0.73764, +0.11377,0.670135,0.704803,0.232605,0.895599,0.429749,-0.114655,-0.11557,-0.474243,0.872742,0.621826,0.604004,-0.498444,-0.832214,0.012756,0.55426,-0.702484,0.705994,-0.089661,-0.692017,0.649292,0.315399,-0.175995,-0.977997,0.111877,0.096954,-0.04953,0.994019,0.635284,-0.606689,-0.477783,-0.261261, +-0.607422,-0.750153,0.983276,0.165436,0.075958,-0.29837,0.404083,-0.864655,-0.638672,0.507721,0.578156,0.388214,0.412079,0.824249,0.556183,-0.208832,0.804352,0.778442,0.562012,0.27951,-0.616577,0.781921,-0.091522,0.196289,0.051056,0.979187,-0.121216,0.207153,-0.970734,-0.173401,-0.384735,0.906555, +0.161499,-0.723236,-0.671387,0.178497,-0.006226,-0.983887,-0.126038,0.15799,0.97934,0.830475,-0.024811,0.556458,-0.510132,-0.76944,0.384247,0.81424,0.200104,-0.544891,-0.112549,-0.393311,-0.912445,0.56189,0.152222,-0.813049,0.198914,-0.254517,-0.946381,-0.41217,0.690979,-0.593811,-0.407257,0.324524, +0.853668,-0.690186,0.366119,-0.624115,-0.428345,0.844147,-0.322296,-0.21228,-0.297546,-0.930756,-0.273071,0.516113,0.811798,0.928314,0.371643,0.007233,0.785828,-0.479218,-0.390778,-0.704895,0.058929,0.706818,0.173248,0.203583,0.963562,0.422211,-0.904297,-0.062469,-0.363312,-0.182465,0.913605,0.254028, +-0.552307,-0.793945,-0.28891,-0.765747,-0.574554,0.058319,0.291382,0.954803,0.946136,-0.303925,0.111267,-0.078156,0.443695,-0.892731,0.182098,0.89389,0.409515,-0.680298,-0.213318,0.701141,0.062469,0.848389,-0.525635,-0.72879,-0.641846,0.238342,-0.88089,0.427673,0.202637,-0.532501,-0.21405,0.818878, +0.948975,-0.305084,0.07962,0.925446,0.374664,0.055817,0.820923,0.565491,0.079102,0.25882,0.099792,-0.960724,-0.294617,0.910522,0.289978,0.137115,0.320038,-0.937408,-0.908386,0.345276,-0.235718,-0.936218,0.138763,0.322754,0.366577,0.925934,-0.090637,0.309296,-0.686829,-0.657684,0.66983,0.024445, +0.742065,-0.917999,-0.059113,-0.392059,0.365509,0.462158,-0.807922,0.083374,0.996399,-0.014801,0.593842,0.253143,-0.763672,0.974976,-0.165466,0.148285,0.918976,0.137299,0.369537,0.294952,0.694977,0.655731,0.943085,0.152618,-0.295319,0.58783,-0.598236,0.544495,0.203796,0.678223,0.705994,-0.478821, +-0.661011,0.577667,0.719055,-0.1698,-0.673828,-0.132172,-0.965332,0.225006,-0.981873,-0.14502,0.121979,0.763458,0.579742,0.284546,-0.893188,0.079681,0.442474,-0.795776,-0.523804,0.303802,0.734955,0.67804,-0.007446,0.15506,0.986267,-0.056183,0.258026,0.571503,-0.778931,-0.681549,-0.702087,-0.206116, +-0.96286,-0.177185,0.203613,-0.470978,-0.515106,0.716095,-0.740326,0.57135,0.354095,-0.56012,-0.824982,-0.074982,-0.507874,0.753204,0.417969,-0.503113,0.038147,0.863342,0.594025,0.673553,-0.439758,-0.119873,-0.005524,-0.992737,0.098267,-0.213776,0.971893,-0.615631,0.643951,0.454163,0.896851,-0.441071, +0.032166,-0.555023,0.750763,-0.358093,0.398773,0.304688,0.864929,-0.722961,0.303589,0.620544,-0.63559,-0.621948,-0.457306,-0.293243,0.072327,0.953278,-0.491638,0.661041,-0.566772,-0.304199,-0.572083,-0.761688,0.908081,-0.398956,0.127014,-0.523621,-0.549683,-0.650848,-0.932922,-0.19986,0.299408,0.099426, +0.140869,0.984985,-0.020325,-0.999756,-0.002319,0.952667,0.280853,-0.11615,-0.971893,0.082581,0.220337,0.65921,0.705292,-0.260651,0.733063,-0.175537,0.657043,-0.555206,0.429504,-0.712189,0.400421,-0.89859,0.179352,0.750885,-0.19696,0.630341,0.785675,-0.569336,0.241821,-0.058899,-0.464111,0.883789, +0.129608,-0.94519,0.299622,-0.357819,0.907654,0.219238,-0.842133,-0.439117,-0.312927,-0.313477,0.84433,0.434479,-0.241211,0.053253,0.968994,0.063873,0.823273,0.563965,0.476288,0.862152,-0.172516,0.620941,-0.298126,0.724915,0.25238,-0.749359,-0.612122,-0.577545,0.386566,0.718994,-0.406342,-0.737976, +0.538696,0.04718,0.556305,0.82959,-0.802856,0.587463,0.101166,-0.707733,-0.705963,0.026428,0.374908,0.68457,0.625092,0.472137,0.208405,-0.856506,-0.703064,-0.581085,-0.409821,-0.417206,-0.736328,0.532623,-0.447876,-0.20285,-0.870728,0.086945,-0.990417,0.107086,0.183685,0.018341,-0.982788,0.560638, +-0.428864,0.708282,0.296722,-0.952576,-0.0672,0.135773,0.990265,0.030243,-0.068787,0.654724,0.752686,0.762604,-0.551758,0.337585,-0.819611,-0.407684,0.402466,-0.727844,-0.55072,-0.408539,-0.855774,-0.480011,0.19281,0.693176,-0.079285,0.716339,0.226013,0.650116,-0.725433,0.246704,0.953369,-0.173553, +-0.970398,-0.239227,-0.03244,0.136383,-0.394318,0.908752,0.813232,0.558167,0.164368,0.40451,0.549042,-0.731323,-0.380249,-0.566711,0.730865,0.022156,0.932739,0.359741,0.00824,0.996552,-0.082306,0.956635,-0.065338,-0.283722,-0.743561,0.008209,0.668579,-0.859589,-0.509674,0.035767,-0.852234,0.363678, +-0.375977,-0.201965,-0.970795,-0.12915,0.313477,0.947327,0.06546,-0.254028,-0.528259,0.81015,0.628052,0.601105,0.49411,-0.494385,0.868378,0.037933,0.275635,-0.086426,0.957336,-0.197937,0.468903,-0.860748,0.895599,0.399384,0.195801,0.560791,0.825012,-0.069214,0.304199,-0.849487,0.43103,0.096375, +0.93576,0.339111,-0.051422,0.408966,-0.911072,0.330444,0.942841,-0.042389,-0.452362,-0.786407,0.420563,0.134308,-0.933472,-0.332489,0.80191,-0.566711,-0.188934,-0.987946,-0.105988,0.112518,-0.24408,0.892242,-0.379791,-0.920502,0.229095,-0.316376,0.7789,0.325958,0.535706,-0.912872,0.185211,-0.36377, +-0.184784,0.565369,-0.803833,-0.018463,0.119537,0.992615,-0.259247,-0.935608,0.239532,-0.82373,-0.449127,-0.345947,-0.433105,0.659515,0.614349,-0.822754,0.378845,-0.423676,0.687195,-0.674835,-0.26889,-0.246582,-0.800842,0.545715,-0.729187,-0.207794,0.651978,0.653534,-0.610443,-0.447388,0.492584,-0.023346, +0.869934,0.609039,0.009094,-0.79306,0.962494,-0.271088,-0.00885,0.2659,-0.004913,0.963959,0.651245,0.553619,-0.518951,0.280548,-0.84314,0.458618,-0.175293,-0.983215,0.049805,0.035339,-0.979919,0.196045,-0.982941,0.164307,-0.082245,0.233734,-0.97226,-0.005005,-0.747253,-0.611328,0.260437,0.645599, +0.592773,0.481384,0.117706,-0.949524,-0.29068,-0.535004,-0.791901,-0.294312,-0.627167,-0.214447,0.748718,-0.047974,-0.813477,-0.57959,-0.175537,0.477264,-0.860992,0.738556,-0.414246,-0.53183,0.562561,-0.704071,0.433289,-0.754944,0.64801,-0.100586,0.114716,0.044525,-0.992371,0.966003,0.244873,-0.082764, +}; + +/**************************/ +/* IMPROVED PERLIN NOISE */ +/**************************/ + +#define lerp(t, a, b) ((a)+(t)*((b)-(a))) +#define npfade(t) ((t)*(t)*(t)*((t)*((t)*6-15)+10)) + +static float grad(int hash, float x, float y, float z) +{ + int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE + float u = h<8 ? x : y, // INTO 12 GRADIENT DIRECTIONS. + v = h<4 ? y : h==12||h==14 ? x : z; + return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v); +} + +/* instead of adding another permutation array, just use hash table defined above */ +static float newPerlin(float x, float y, float z) +{ + int A, AA, AB, B, BA, BB; + float u=floor(x), v=floor(y), w=floor(z); + int X=((int)u) & 255, Y=((int)v) & 255, Z=((int)w) & 255; // FIND UNIT CUBE THAT CONTAINS POINT + x -= u; // FIND RELATIVE X,Y,Z + y -= v; // OF POINT IN CUBE. + z -= w; + u = npfade(x); // COMPUTE FADE CURVES + v = npfade(y); // FOR EACH OF X,Y,Z. + w = npfade(z); + A = hash[X ]+Y; AA = hash[A]+Z; AB = hash[A+1]+Z; // HASH COORDINATES OF + B = hash[X+1]+Y; BA = hash[B]+Z; BB = hash[B+1]+Z; // THE 8 CUBE CORNERS, + return lerp(w, lerp(v, lerp(u, grad(hash[AA ], x , y , z ), // AND ADD + grad(hash[BA ], x-1, y , z )), // BLENDED + lerp(u, grad(hash[AB ], x , y-1, z ), // RESULTS + grad(hash[BB ], x-1, y-1, z ))),// FROM 8 + lerp(v, lerp(u, grad(hash[AA+1], x , y , z-1 ), // CORNERS + grad(hash[BA+1], x-1, y , z-1 )), // OF CUBE + lerp(u, grad(hash[AB+1], x , y-1, z-1 ), + grad(hash[BB+1], x-1, y-1, z-1 )))); +} + +/* for use with BLI_gNoise()/BLI_gTurbulence(), returns unsigned improved perlin noise */ +static float newPerlinU(float x, float y, float z) +{ + return (0.5+0.5*newPerlin(x, y, z)); +} + + +/**************************/ +/* END OF IMPROVED PERLIN */ +/**************************/ + +/* Was BLI_hnoise(), removed noisesize, so other functions can call it without scaling. */ +static float orgBlenderNoise(float x, float y, float z) +{ + register float cn1, cn2, cn3, cn4, cn5, cn6, i, *h; + float ox, oy, oz, jx, jy, jz; + float n= 0.5; + int ix, iy, iz, b00, b01, b10, b11, b20, b21; + + ox= (x- (ix= (int)floor(x)) ); + oy= (y- (iy= (int)floor(y)) ); + oz= (z- (iz= (int)floor(z)) ); + + jx= ox-1; + jy= oy-1; + jz= oz-1; + + cn1=ox*ox; cn2=oy*oy; cn3=oz*oz; + cn4=jx*jx; cn5=jy*jy; cn6=jz*jz; + + cn1= 1.0-3.0*cn1+2.0*cn1*ox; + cn2= 1.0-3.0*cn2+2.0*cn2*oy; + cn3= 1.0-3.0*cn3+2.0*cn3*oz; + cn4= 1.0-3.0*cn4-2.0*cn4*jx; + cn5= 1.0-3.0*cn5-2.0*cn5*jy; + cn6= 1.0-3.0*cn6-2.0*cn6*jz; + + b00= hash[ hash[ix & 255]+(iy & 255)]; + b10= hash[ hash[(ix+1) & 255]+(iy & 255)]; + b01= hash[ hash[ix & 255]+((iy+1) & 255)]; + b11= hash[ hash[(ix+1) & 255]+((iy+1) & 255)]; + + b20=iz & 255; b21= (iz+1) & 255; + + /* 0 */ + i= (cn1*cn2*cn3); + h=hashvectf+ 3*hash[b20+b00]; + n+= i*(h[0]*ox+h[1]*oy+h[2]*oz); + /* 1 */ + i= (cn1*cn2*cn6); + h=hashvectf+ 3*hash[b21+b00]; + n+= i*(h[0]*ox+h[1]*oy+h[2]*jz); + /* 2 */ + i= (cn1*cn5*cn3); + h=hashvectf+ 3*hash[b20+b01]; + n+= i*(h[0]*ox+h[1]*jy+h[2]*oz); + /* 3 */ + i= (cn1*cn5*cn6); + h=hashvectf+ 3*hash[b21+b01]; + n+= i*(h[0]*ox+h[1]*jy+h[2]*jz); + /* 4 */ + i= cn4*cn2*cn3; + h=hashvectf+ 3*hash[b20+b10]; + n+= i*(h[0]*jx+h[1]*oy+h[2]*oz); + /* 5 */ + i= cn4*cn2*cn6; + h=hashvectf+ 3*hash[b21+b10]; + n+= i*(h[0]*jx+h[1]*oy+h[2]*jz); + /* 6 */ + i= cn4*cn5*cn3; + h=hashvectf+ 3*hash[b20+b11]; + n+= i*(h[0]*jx+h[1]*jy+h[2]*oz); + /* 7 */ + i= (cn4*cn5*cn6); + h=hashvectf+ 3*hash[b21+b11]; + n+= i*(h[0]*jx+h[1]*jy+h[2]*jz); + + if(n<0.0) n=0.0; else if(n>1.0) n=1.0; + return n; +} + +/* as orgBlenderNoise(), returning signed noise */ +static float orgBlenderNoiseS(float x, float y, float z) +{ + return (2.0*orgBlenderNoise(x, y, z)-1.0); +} + +/* separated from orgBlenderNoise above, with scaling */ +float BLI_hnoise(float noisesize, float x, float y, float z) +{ + if(noisesize==0.0) return 0.0; + x= (1.0+x)/noisesize; + y= (1.0+y)/noisesize; + z= (1.0+z)/noisesize; + return orgBlenderNoise(x, y, z); +} + + +/* original turbulence functions */ +float BLI_turbulence(float noisesize, float x, float y, float z, int nr) +{ + float s, d= 0.5, div=1.0; + + s= BLI_hnoise(noisesize, x, y, z); + + while(nr>0) { + + s+= d*BLI_hnoise(noisesize*d, x, y, z); + div+= d; + d*= 0.5; + + nr--; + } + return s/div; +} + +float BLI_turbulence1(float noisesize, float x, float y, float z, int nr) +{ + float s, d= 0.5, div=1.0; + + s= fabs( (-1.0+2.0*BLI_hnoise(noisesize, x, y, z))); + + while(nr>0) { + + s+= fabs(d* (-1.0+2.0*BLI_hnoise(noisesize*d, x, y, z))); + div+= d; + d*= 0.5; + + nr--; + } + return s/div; +} + +/* ********************* FROM PERLIN HIMSELF: ******************** */ + +static char p[512+2]= { +0xA2,0xA0,0x19,0x3B,0xF8,0xEB,0xAA,0xEE,0xF3,0x1C,0x67,0x28,0x1D,0xED,0x0,0xDE,0x95,0x2E,0xDC,0x3F,0x3A,0x82,0x35,0x4D,0x6C,0xBA,0x36,0xD0,0xF6,0xC,0x79,0x32,0xD1,0x59,0xF4,0x8,0x8B,0x63,0x89,0x2F,0xB8,0xB4,0x97,0x83,0xF2,0x8F,0x18,0xC7,0x51,0x14,0x65,0x87,0x48,0x20,0x42,0xA8,0x80,0xB5,0x40,0x13,0xB2,0x22,0x7E,0x57, +0xBC,0x7F,0x6B,0x9D,0x86,0x4C,0xC8,0xDB,0x7C,0xD5,0x25,0x4E,0x5A,0x55,0x74,0x50,0xCD,0xB3,0x7A,0xBB,0xC3,0xCB,0xB6,0xE2,0xE4,0xEC,0xFD,0x98,0xB,0x96,0xD3,0x9E,0x5C,0xA1,0x64,0xF1,0x81,0x61,0xE1,0xC4,0x24,0x72,0x49,0x8C,0x90,0x4B,0x84,0x34,0x38,0xAB,0x78,0xCA,0x1F,0x1,0xD7,0x93,0x11,0xC1,0x58,0xA9,0x31,0xF9,0x44,0x6D, +0xBF,0x33,0x9C,0x5F,0x9,0x94,0xA3,0x85,0x6,0xC6,0x9A,0x1E,0x7B,0x46,0x15,0x30,0x27,0x2B,0x1B,0x71,0x3C,0x5B,0xD6,0x6F,0x62,0xAC,0x4F,0xC2,0xC0,0xE,0xB1,0x23,0xA7,0xDF,0x47,0xB0,0x77,0x69,0x5,0xE9,0xE6,0xE7,0x76,0x73,0xF,0xFE,0x6E,0x9B,0x56,0xEF,0x12,0xA5,0x37,0xFC,0xAE,0xD9,0x3,0x8E,0xDD,0x10,0xB9,0xCE,0xC9,0x8D, +0xDA,0x2A,0xBD,0x68,0x17,0x9F,0xBE,0xD4,0xA,0xCC,0xD2,0xE8,0x43,0x3D,0x70,0xB7,0x2,0x7D,0x99,0xD8,0xD,0x60,0x8A,0x4,0x2C,0x3E,0x92,0xE5,0xAF,0x53,0x7,0xE0,0x29,0xA6,0xC5,0xE3,0xF5,0xF7,0x4A,0x41,0x26,0x6A,0x16,0x5E,0x52,0x2D,0x21,0xAD,0xF0,0x91,0xFF,0xEA,0x54,0xFA,0x66,0x1A,0x45,0x39,0xCF,0x75,0xA4,0x88,0xFB,0x5D, +0xA2,0xA0,0x19,0x3B,0xF8,0xEB,0xAA,0xEE,0xF3,0x1C,0x67,0x28,0x1D,0xED,0x0,0xDE,0x95,0x2E,0xDC,0x3F,0x3A,0x82,0x35,0x4D,0x6C,0xBA,0x36,0xD0,0xF6,0xC,0x79,0x32,0xD1,0x59,0xF4,0x8,0x8B,0x63,0x89,0x2F,0xB8,0xB4,0x97,0x83,0xF2,0x8F,0x18,0xC7,0x51,0x14,0x65,0x87,0x48,0x20,0x42,0xA8,0x80,0xB5,0x40,0x13,0xB2,0x22,0x7E,0x57, +0xBC,0x7F,0x6B,0x9D,0x86,0x4C,0xC8,0xDB,0x7C,0xD5,0x25,0x4E,0x5A,0x55,0x74,0x50,0xCD,0xB3,0x7A,0xBB,0xC3,0xCB,0xB6,0xE2,0xE4,0xEC,0xFD,0x98,0xB,0x96,0xD3,0x9E,0x5C,0xA1,0x64,0xF1,0x81,0x61,0xE1,0xC4,0x24,0x72,0x49,0x8C,0x90,0x4B,0x84,0x34,0x38,0xAB,0x78,0xCA,0x1F,0x1,0xD7,0x93,0x11,0xC1,0x58,0xA9,0x31,0xF9,0x44,0x6D, +0xBF,0x33,0x9C,0x5F,0x9,0x94,0xA3,0x85,0x6,0xC6,0x9A,0x1E,0x7B,0x46,0x15,0x30,0x27,0x2B,0x1B,0x71,0x3C,0x5B,0xD6,0x6F,0x62,0xAC,0x4F,0xC2,0xC0,0xE,0xB1,0x23,0xA7,0xDF,0x47,0xB0,0x77,0x69,0x5,0xE9,0xE6,0xE7,0x76,0x73,0xF,0xFE,0x6E,0x9B,0x56,0xEF,0x12,0xA5,0x37,0xFC,0xAE,0xD9,0x3,0x8E,0xDD,0x10,0xB9,0xCE,0xC9,0x8D, +0xDA,0x2A,0xBD,0x68,0x17,0x9F,0xBE,0xD4,0xA,0xCC,0xD2,0xE8,0x43,0x3D,0x70,0xB7,0x2,0x7D,0x99,0xD8,0xD,0x60,0x8A,0x4,0x2C,0x3E,0x92,0xE5,0xAF,0x53,0x7,0xE0,0x29,0xA6,0xC5,0xE3,0xF5,0xF7,0x4A,0x41,0x26,0x6A,0x16,0x5E,0x52,0x2D,0x21,0xAD,0xF0,0x91,0xFF,0xEA,0x54,0xFA,0x66,0x1A,0x45,0x39,0xCF,0x75,0xA4,0x88,0xFB,0x5D, +0xA2,0xA0}; + + +float g[512+2][3]= { +0.33783,0.715698,-0.611206,-0.944031,-0.326599,-0.045624,-0.101074,-0.416443,-0.903503,0.799286,0.49411,-0.341949,-0.854645,0.518036,0.033936,0.42514,-0.437866,-0.792114,-0.358948,0.597046,0.717377,-0.985413,0.144714,0.089294,-0.601776,-0.33728,-0.723907,-0.449921,0.594513,0.666382,0.208313,-0.10791, +0.972076,0.575317,0.060425,0.815643,0.293365,-0.875702,-0.383453,0.293762,0.465759,0.834686,-0.846008,-0.233398,-0.47934,-0.115814,0.143036,-0.98291,0.204681,-0.949036,-0.239532,0.946716,-0.263947,0.184326,-0.235596,0.573822,0.784332,0.203705,-0.372253,-0.905487,0.756989,-0.651031,0.055298,0.497803, +0.814697,-0.297363,-0.16214,0.063995,-0.98468,-0.329254,0.834381,0.441925,0.703827,-0.527039,-0.476227,0.956421,0.266113,0.119781,0.480133,0.482849,0.7323,-0.18631,0.961212,-0.203125,-0.748474,-0.656921,-0.090393,-0.085052,-0.165253,0.982544,-0.76947,0.628174,-0.115234,0.383148,0.537659,0.751068, +0.616486,-0.668488,-0.415924,-0.259979,-0.630005,0.73175,0.570953,-0.087952,0.816223,-0.458008,0.023254,0.888611,-0.196167,0.976563,-0.088287,-0.263885,-0.69812,-0.665527,0.437134,-0.892273,-0.112793,-0.621674,-0.230438,0.748566,0.232422,0.900574,-0.367249,0.22229,-0.796143,0.562744,-0.665497,-0.73764, +0.11377,0.670135,0.704803,0.232605,0.895599,0.429749,-0.114655,-0.11557,-0.474243,0.872742,0.621826,0.604004,-0.498444,-0.832214,0.012756,0.55426,-0.702484,0.705994,-0.089661,-0.692017,0.649292,0.315399,-0.175995,-0.977997,0.111877,0.096954,-0.04953,0.994019,0.635284,-0.606689,-0.477783,-0.261261, +-0.607422,-0.750153,0.983276,0.165436,0.075958,-0.29837,0.404083,-0.864655,-0.638672,0.507721,0.578156,0.388214,0.412079,0.824249,0.556183,-0.208832,0.804352,0.778442,0.562012,0.27951,-0.616577,0.781921,-0.091522,0.196289,0.051056,0.979187,-0.121216,0.207153,-0.970734,-0.173401,-0.384735,0.906555, +0.161499,-0.723236,-0.671387,0.178497,-0.006226,-0.983887,-0.126038,0.15799,0.97934,0.830475,-0.024811,0.556458,-0.510132,-0.76944,0.384247,0.81424,0.200104,-0.544891,-0.112549,-0.393311,-0.912445,0.56189,0.152222,-0.813049,0.198914,-0.254517,-0.946381,-0.41217,0.690979,-0.593811,-0.407257,0.324524, +0.853668,-0.690186,0.366119,-0.624115,-0.428345,0.844147,-0.322296,-0.21228,-0.297546,-0.930756,-0.273071,0.516113,0.811798,0.928314,0.371643,0.007233,0.785828,-0.479218,-0.390778,-0.704895,0.058929,0.706818,0.173248,0.203583,0.963562,0.422211,-0.904297,-0.062469,-0.363312,-0.182465,0.913605,0.254028, +-0.552307,-0.793945,-0.28891,-0.765747,-0.574554,0.058319,0.291382,0.954803,0.946136,-0.303925,0.111267,-0.078156,0.443695,-0.892731,0.182098,0.89389,0.409515,-0.680298,-0.213318,0.701141,0.062469,0.848389,-0.525635,-0.72879,-0.641846,0.238342,-0.88089,0.427673,0.202637,-0.532501,-0.21405,0.818878, +0.948975,-0.305084,0.07962,0.925446,0.374664,0.055817,0.820923,0.565491,0.079102,0.25882,0.099792,-0.960724,-0.294617,0.910522,0.289978,0.137115,0.320038,-0.937408,-0.908386,0.345276,-0.235718,-0.936218,0.138763,0.322754,0.366577,0.925934,-0.090637,0.309296,-0.686829,-0.657684,0.66983,0.024445, +0.742065,-0.917999,-0.059113,-0.392059,0.365509,0.462158,-0.807922,0.083374,0.996399,-0.014801,0.593842,0.253143,-0.763672,0.974976,-0.165466,0.148285,0.918976,0.137299,0.369537,0.294952,0.694977,0.655731,0.943085,0.152618,-0.295319,0.58783,-0.598236,0.544495,0.203796,0.678223,0.705994,-0.478821, +-0.661011,0.577667,0.719055,-0.1698,-0.673828,-0.132172,-0.965332,0.225006,-0.981873,-0.14502,0.121979,0.763458,0.579742,0.284546,-0.893188,0.079681,0.442474,-0.795776,-0.523804,0.303802,0.734955,0.67804,-0.007446,0.15506,0.986267,-0.056183,0.258026,0.571503,-0.778931,-0.681549,-0.702087,-0.206116, +-0.96286,-0.177185,0.203613,-0.470978,-0.515106,0.716095,-0.740326,0.57135,0.354095,-0.56012,-0.824982,-0.074982,-0.507874,0.753204,0.417969,-0.503113,0.038147,0.863342,0.594025,0.673553,-0.439758,-0.119873,-0.005524,-0.992737,0.098267,-0.213776,0.971893,-0.615631,0.643951,0.454163,0.896851,-0.441071, +0.032166,-0.555023,0.750763,-0.358093,0.398773,0.304688,0.864929,-0.722961,0.303589,0.620544,-0.63559,-0.621948,-0.457306,-0.293243,0.072327,0.953278,-0.491638,0.661041,-0.566772,-0.304199,-0.572083,-0.761688,0.908081,-0.398956,0.127014,-0.523621,-0.549683,-0.650848,-0.932922,-0.19986,0.299408,0.099426, +0.140869,0.984985,-0.020325,-0.999756,-0.002319,0.952667,0.280853,-0.11615,-0.971893,0.082581,0.220337,0.65921,0.705292,-0.260651,0.733063,-0.175537,0.657043,-0.555206,0.429504,-0.712189,0.400421,-0.89859,0.179352,0.750885,-0.19696,0.630341,0.785675,-0.569336,0.241821,-0.058899,-0.464111,0.883789, +0.129608,-0.94519,0.299622,-0.357819,0.907654,0.219238,-0.842133,-0.439117,-0.312927,-0.313477,0.84433,0.434479,-0.241211,0.053253,0.968994,0.063873,0.823273,0.563965,0.476288,0.862152,-0.172516,0.620941,-0.298126,0.724915,0.25238,-0.749359,-0.612122,-0.577545,0.386566,0.718994,-0.406342,-0.737976, +0.538696,0.04718,0.556305,0.82959,-0.802856,0.587463,0.101166,-0.707733,-0.705963,0.026428,0.374908,0.68457,0.625092,0.472137,0.208405,-0.856506,-0.703064,-0.581085,-0.409821,-0.417206,-0.736328,0.532623,-0.447876,-0.20285,-0.870728,0.086945,-0.990417,0.107086,0.183685,0.018341,-0.982788,0.560638, +-0.428864,0.708282,0.296722,-0.952576,-0.0672,0.135773,0.990265,0.030243,-0.068787,0.654724,0.752686,0.762604,-0.551758,0.337585,-0.819611,-0.407684,0.402466,-0.727844,-0.55072,-0.408539,-0.855774,-0.480011,0.19281,0.693176,-0.079285,0.716339,0.226013,0.650116,-0.725433,0.246704,0.953369,-0.173553, +-0.970398,-0.239227,-0.03244,0.136383,-0.394318,0.908752,0.813232,0.558167,0.164368,0.40451,0.549042,-0.731323,-0.380249,-0.566711,0.730865,0.022156,0.932739,0.359741,0.00824,0.996552,-0.082306,0.956635,-0.065338,-0.283722,-0.743561,0.008209,0.668579,-0.859589,-0.509674,0.035767,-0.852234,0.363678, +-0.375977,-0.201965,-0.970795,-0.12915,0.313477,0.947327,0.06546,-0.254028,-0.528259,0.81015,0.628052,0.601105,0.49411,-0.494385,0.868378,0.037933,0.275635,-0.086426,0.957336,-0.197937,0.468903,-0.860748,0.895599,0.399384,0.195801,0.560791,0.825012,-0.069214,0.304199,-0.849487,0.43103,0.096375, +0.93576,0.339111,-0.051422,0.408966,-0.911072,0.330444,0.942841,-0.042389,-0.452362,-0.786407,0.420563,0.134308,-0.933472,-0.332489,0.80191,-0.566711,-0.188934,-0.987946,-0.105988,0.112518,-0.24408,0.892242,-0.379791,-0.920502,0.229095,-0.316376,0.7789,0.325958,0.535706,-0.912872,0.185211,-0.36377, +-0.184784,0.565369,-0.803833,-0.018463,0.119537,0.992615,-0.259247,-0.935608,0.239532,-0.82373,-0.449127,-0.345947,-0.433105,0.659515,0.614349,-0.822754,0.378845,-0.423676,0.687195,-0.674835,-0.26889,-0.246582,-0.800842,0.545715,-0.729187,-0.207794,0.651978,0.653534,-0.610443,-0.447388,0.492584,-0.023346, +0.869934,0.609039,0.009094,-0.79306,0.962494,-0.271088,-0.00885,0.2659,-0.004913,0.963959,0.651245,0.553619,-0.518951,0.280548,-0.84314,0.458618,-0.175293,-0.983215,0.049805,0.035339,-0.979919,0.196045,-0.982941,0.164307,-0.082245,0.233734,-0.97226,-0.005005,-0.747253,-0.611328,0.260437,0.645599, +0.592773,0.481384,0.117706,-0.949524,-0.29068,-0.535004,-0.791901,-0.294312,-0.627167,-0.214447,0.748718,-0.047974,-0.813477,-0.57959,-0.175537,0.477264,-0.860992,0.738556,-0.414246,-0.53183,0.562561,-0.704071,0.433289,-0.754944,0.64801,-0.100586,0.114716,0.044525,-0.992371,0.966003,0.244873,-0.082764, +0.33783,0.715698,-0.611206,-0.944031,-0.326599,-0.045624,-0.101074,-0.416443,-0.903503,0.799286,0.49411,-0.341949,-0.854645,0.518036,0.033936,0.42514,-0.437866,-0.792114,-0.358948,0.597046,0.717377,-0.985413,0.144714,0.089294,-0.601776,-0.33728,-0.723907,-0.449921,0.594513,0.666382,0.208313,-0.10791, +0.972076,0.575317,0.060425,0.815643,0.293365,-0.875702,-0.383453,0.293762,0.465759,0.834686,-0.846008,-0.233398,-0.47934,-0.115814,0.143036,-0.98291,0.204681,-0.949036,-0.239532,0.946716,-0.263947,0.184326,-0.235596,0.573822,0.784332,0.203705,-0.372253,-0.905487,0.756989,-0.651031,0.055298,0.497803, +0.814697,-0.297363,-0.16214,0.063995,-0.98468,-0.329254,0.834381,0.441925,0.703827,-0.527039,-0.476227,0.956421,0.266113,0.119781,0.480133,0.482849,0.7323,-0.18631,0.961212,-0.203125,-0.748474,-0.656921,-0.090393,-0.085052,-0.165253,0.982544,-0.76947,0.628174,-0.115234,0.383148,0.537659,0.751068, +0.616486,-0.668488,-0.415924,-0.259979,-0.630005,0.73175,0.570953,-0.087952,0.816223,-0.458008,0.023254,0.888611,-0.196167,0.976563,-0.088287,-0.263885,-0.69812,-0.665527,0.437134,-0.892273,-0.112793,-0.621674,-0.230438,0.748566,0.232422,0.900574,-0.367249,0.22229,-0.796143,0.562744,-0.665497,-0.73764, +0.11377,0.670135,0.704803,0.232605,0.895599,0.429749,-0.114655,-0.11557,-0.474243,0.872742,0.621826,0.604004,-0.498444,-0.832214,0.012756,0.55426,-0.702484,0.705994,-0.089661,-0.692017,0.649292,0.315399,-0.175995,-0.977997,0.111877,0.096954,-0.04953,0.994019,0.635284,-0.606689,-0.477783,-0.261261, +-0.607422,-0.750153,0.983276,0.165436,0.075958,-0.29837,0.404083,-0.864655,-0.638672,0.507721,0.578156,0.388214,0.412079,0.824249,0.556183,-0.208832,0.804352,0.778442,0.562012,0.27951,-0.616577,0.781921,-0.091522,0.196289,0.051056,0.979187,-0.121216,0.207153,-0.970734,-0.173401,-0.384735,0.906555, +0.161499,-0.723236,-0.671387,0.178497,-0.006226,-0.983887,-0.126038,0.15799,0.97934,0.830475,-0.024811,0.556458,-0.510132,-0.76944,0.384247,0.81424,0.200104,-0.544891,-0.112549,-0.393311,-0.912445,0.56189,0.152222,-0.813049,0.198914,-0.254517,-0.946381,-0.41217,0.690979,-0.593811,-0.407257,0.324524, +0.853668,-0.690186,0.366119,-0.624115,-0.428345,0.844147,-0.322296,-0.21228,-0.297546,-0.930756,-0.273071,0.516113,0.811798,0.928314,0.371643,0.007233,0.785828,-0.479218,-0.390778,-0.704895,0.058929,0.706818,0.173248,0.203583,0.963562,0.422211,-0.904297,-0.062469,-0.363312,-0.182465,0.913605,0.254028, +-0.552307,-0.793945,-0.28891,-0.765747,-0.574554,0.058319,0.291382,0.954803,0.946136,-0.303925,0.111267,-0.078156,0.443695,-0.892731,0.182098,0.89389,0.409515,-0.680298,-0.213318,0.701141,0.062469,0.848389,-0.525635,-0.72879,-0.641846,0.238342,-0.88089,0.427673,0.202637,-0.532501,-0.21405,0.818878, +0.948975,-0.305084,0.07962,0.925446,0.374664,0.055817,0.820923,0.565491,0.079102,0.25882,0.099792,-0.960724,-0.294617,0.910522,0.289978,0.137115,0.320038,-0.937408,-0.908386,0.345276,-0.235718,-0.936218,0.138763,0.322754,0.366577,0.925934,-0.090637,0.309296,-0.686829,-0.657684,0.66983,0.024445, +0.742065,-0.917999,-0.059113,-0.392059,0.365509,0.462158,-0.807922,0.083374,0.996399,-0.014801,0.593842,0.253143,-0.763672,0.974976,-0.165466,0.148285,0.918976,0.137299,0.369537,0.294952,0.694977,0.655731,0.943085,0.152618,-0.295319,0.58783,-0.598236,0.544495,0.203796,0.678223,0.705994,-0.478821, +-0.661011,0.577667,0.719055,-0.1698,-0.673828,-0.132172,-0.965332,0.225006,-0.981873,-0.14502,0.121979,0.763458,0.579742,0.284546,-0.893188,0.079681,0.442474,-0.795776,-0.523804,0.303802,0.734955,0.67804,-0.007446,0.15506,0.986267,-0.056183,0.258026,0.571503,-0.778931,-0.681549,-0.702087,-0.206116, +-0.96286,-0.177185,0.203613,-0.470978,-0.515106,0.716095,-0.740326,0.57135,0.354095,-0.56012,-0.824982,-0.074982,-0.507874,0.753204,0.417969,-0.503113,0.038147,0.863342,0.594025,0.673553,-0.439758,-0.119873,-0.005524,-0.992737,0.098267,-0.213776,0.971893,-0.615631,0.643951,0.454163,0.896851,-0.441071, +0.032166,-0.555023,0.750763,-0.358093,0.398773,0.304688,0.864929,-0.722961,0.303589,0.620544,-0.63559,-0.621948,-0.457306,-0.293243,0.072327,0.953278,-0.491638,0.661041,-0.566772,-0.304199,-0.572083,-0.761688,0.908081,-0.398956,0.127014,-0.523621,-0.549683,-0.650848,-0.932922,-0.19986,0.299408,0.099426, +0.140869,0.984985,-0.020325,-0.999756,-0.002319,0.952667,0.280853,-0.11615,-0.971893,0.082581,0.220337,0.65921,0.705292,-0.260651,0.733063,-0.175537,0.657043,-0.555206,0.429504,-0.712189,0.400421,-0.89859,0.179352,0.750885,-0.19696,0.630341,0.785675,-0.569336,0.241821,-0.058899,-0.464111,0.883789, +0.129608,-0.94519,0.299622,-0.357819,0.907654,0.219238,-0.842133,-0.439117,-0.312927,-0.313477,0.84433,0.434479,-0.241211,0.053253,0.968994,0.063873,0.823273,0.563965,0.476288,0.862152,-0.172516,0.620941,-0.298126,0.724915,0.25238,-0.749359,-0.612122,-0.577545,0.386566,0.718994,-0.406342,-0.737976, +0.538696,0.04718,0.556305,0.82959,-0.802856,0.587463,0.101166,-0.707733,-0.705963,0.026428,0.374908,0.68457,0.625092,0.472137,0.208405,-0.856506,-0.703064,-0.581085,-0.409821,-0.417206,-0.736328,0.532623,-0.447876,-0.20285,-0.870728,0.086945,-0.990417,0.107086,0.183685,0.018341,-0.982788,0.560638, +-0.428864,0.708282,0.296722,-0.952576,-0.0672,0.135773,0.990265,0.030243,-0.068787,0.654724,0.752686,0.762604,-0.551758,0.337585,-0.819611,-0.407684,0.402466,-0.727844,-0.55072,-0.408539,-0.855774,-0.480011,0.19281,0.693176,-0.079285,0.716339,0.226013,0.650116,-0.725433,0.246704,0.953369,-0.173553, +-0.970398,-0.239227,-0.03244,0.136383,-0.394318,0.908752,0.813232,0.558167,0.164368,0.40451,0.549042,-0.731323,-0.380249,-0.566711,0.730865,0.022156,0.932739,0.359741,0.00824,0.996552,-0.082306,0.956635,-0.065338,-0.283722,-0.743561,0.008209,0.668579,-0.859589,-0.509674,0.035767,-0.852234,0.363678, +-0.375977,-0.201965,-0.970795,-0.12915,0.313477,0.947327,0.06546,-0.254028,-0.528259,0.81015,0.628052,0.601105,0.49411,-0.494385,0.868378,0.037933,0.275635,-0.086426,0.957336,-0.197937,0.468903,-0.860748,0.895599,0.399384,0.195801,0.560791,0.825012,-0.069214,0.304199,-0.849487,0.43103,0.096375, +0.93576,0.339111,-0.051422,0.408966,-0.911072,0.330444,0.942841,-0.042389,-0.452362,-0.786407,0.420563,0.134308,-0.933472,-0.332489,0.80191,-0.566711,-0.188934,-0.987946,-0.105988,0.112518,-0.24408,0.892242,-0.379791,-0.920502,0.229095,-0.316376,0.7789,0.325958,0.535706,-0.912872,0.185211,-0.36377, +-0.184784,0.565369,-0.803833,-0.018463,0.119537,0.992615,-0.259247,-0.935608,0.239532,-0.82373,-0.449127,-0.345947,-0.433105,0.659515,0.614349,-0.822754,0.378845,-0.423676,0.687195,-0.674835,-0.26889,-0.246582,-0.800842,0.545715,-0.729187,-0.207794,0.651978,0.653534,-0.610443,-0.447388,0.492584,-0.023346, +0.869934,0.609039,0.009094,-0.79306,0.962494,-0.271088,-0.00885,0.2659,-0.004913,0.963959,0.651245,0.553619,-0.518951,0.280548,-0.84314,0.458618,-0.175293,-0.983215,0.049805,0.035339,-0.979919,0.196045,-0.982941,0.164307,-0.082245,0.233734,-0.97226,-0.005005,-0.747253,-0.611328,0.260437,0.645599, +0.592773,0.481384,0.117706,-0.949524,-0.29068,-0.535004,-0.791901,-0.294312,-0.627167,-0.214447,0.748718,-0.047974,-0.813477,-0.57959,-0.175537,0.477264,-0.860992,0.738556,-0.414246,-0.53183,0.562561,-0.704071,0.433289,-0.754944,0.64801,-0.100586,0.114716,0.044525,-0.992371,0.966003,0.244873,-0.082764, +0.33783,0.715698,-0.611206,-0.944031,-0.326599,-0.045624}; + + + +#define DOT(a,b) (a[0] * b[0] + a[1] * b[1] + a[2] * b[2]) + +#define setup(i,b0,b1,r0,r1) \ + t = vec[i] + 10000.; \ + b0 = ((int)t) & 255; \ + b1 = (b0+1) & 255; \ + r0 = t - (int)t; \ + r1 = r0 - 1.; + + +float noise3_perlin(float vec[3]) +{ + int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11; + float rx0, rx1, ry0, ry1, rz0, rz1, *q, sx, sy, sz, a, b, c, d, t, u, v; + register int i, j; + + + setup(0, bx0,bx1, rx0,rx1); + setup(1, by0,by1, ry0,ry1); + setup(2, bz0,bz1, rz0,rz1); + + i = p[ bx0 ]; + j = p[ bx1 ]; + + b00 = p[ i + by0 ]; + b10 = p[ j + by0 ]; + b01 = p[ i + by1 ]; + b11 = p[ j + by1 ]; + +#define at(rx,ry,rz) ( rx * q[0] + ry * q[1] + rz * q[2] ) + +#define surve(t) ( t * t * (3. - 2. * t) ) + +/* lerp moved to improved perlin above */ + + sx = surve(rx0); + sy = surve(ry0); + sz = surve(rz0); + + + q = g[ b00 + bz0 ] ; + u = at(rx0,ry0,rz0); + q = g[ b10 + bz0 ] ; + v = at(rx1,ry0,rz0); + a = lerp(sx, u, v); + + q = g[ b01 + bz0 ] ; + u = at(rx0,ry1,rz0); + q = g[ b11 + bz0 ] ; + v = at(rx1,ry1,rz0); + b = lerp(sx, u, v); + + c = lerp(sy, a, b); /* interpolate in y at lo x */ + + q = g[ b00 + bz1 ] ; + u = at(rx0,ry0,rz1); + q = g[ b10 + bz1 ] ; + v = at(rx1,ry0,rz1); + a = lerp(sx, u, v); + + q = g[ b01 + bz1 ] ; + u = at(rx0,ry1,rz1); + q = g[ b11 + bz1 ] ; + v = at(rx1,ry1,rz1); + b = lerp(sx, u, v); + + d = lerp(sy, a, b); /* interpolate in y at hi x */ + + return 1.5 * lerp(sz, c, d); /* interpolate in z */ +} + +float turbulence_perlin(float *point, float lofreq, float hifreq) +{ + float freq, t, p[3]; + + p[0] = point[0] + 123.456; + p[1] = point[1]; + p[2] = point[2]; + + t = 0; + for (freq = lofreq ; freq < hifreq ; freq *= 2.) { + t += fabs(noise3_perlin(p)) / freq; + p[0] *= 2.; + p[1] *= 2.; + p[2] *= 2.; + } + return t - 0.3; /* readjust to make mean value = 0.0 */ +} + +/* for use with BLI_gNoise/gTurbulence, returns signed noise */ +static float orgPerlinNoise(float x, float y, float z) +{ + float v[3]; + + v[0] = x; + v[1] = y; + v[2] = z; + return noise3_perlin(v); +} + +/* for use with BLI_gNoise/gTurbulence, returns unsigned noise */ +static float orgPerlinNoiseU(float x, float y, float z) +{ + float v[3]; + + v[0] = x; + v[1] = y; + v[2] = z; + return (0.5+0.5*noise3_perlin(v)); +} + +/* *************** CALL AS: *************** */ + +float BLI_hnoisep(float noisesize, float x, float y, float z) +{ + float vec[3]; + + vec[0]= x/noisesize; + vec[1]= y/noisesize; + vec[2]= z/noisesize; + + return noise3_perlin(vec); +} + +float turbulencep(float noisesize, float x, float y, float z, int nr) +{ + float vec[3]; + + vec[0]= x/noisesize; + vec[1]= y/noisesize; + vec[2]= z/noisesize; + nr++; + return turbulence_perlin(vec, 1.0, (float)(1<y)?x:y; + return ((z>t)?z:t); +} + +/* minkovsky preset exponent 0.5 */ +static float dist_MinkovskyH(float x, float y, float z, float e) +{ + float d = sqrt(fabs(x)) + sqrt(fabs(y)) + sqrt(fabs(z)); + return (d*d); +} + +/* minkovsky preset exponent 4 */ +static float dist_Minkovsky4(float x, float y, float z, float e) +{ + x *= x; + y *= y; + z *= z; + return sqrt(sqrt(x*x + y*y + z*z)); +} + +/* Minkovsky, general case, slow, maybe too slow to be useful */ +static float dist_Minkovsky(float x, float y, float z, float e) +{ + return pow(pow(fabs(x), e) + pow(fabs(y), e) + pow(fabs(z), e), 1.0/e); +} + + +/* Not 'pure' Worley, but the results are virtually the same. + Returns distances in da and point coords in pa */ +void voronoi(float x, float y, float z, float* da, float* pa, float me, int dtype) +{ + int xx, yy, zz, xi, yi, zi; + float xd, yd, zd, d, *p; + + float (*distfunc)(float, float, float, float); + switch (dtype) { + case 1: + distfunc = dist_Squared; + break; + case 2: + distfunc = dist_Manhattan; + break; + case 3: + distfunc = dist_Chebychev; + break; + case 4: + distfunc = dist_MinkovskyH; + break; + case 5: + distfunc = dist_Minkovsky4; + break; + case 6: + distfunc = dist_Minkovsky; + break; + case 0: + default: + distfunc = dist_Real; + } + + xi = (int)(floor(x)); + yi = (int)(floor(y)); + zi = (int)(floor(z)); + da[0] = da[1] = da[2] = da[3] = 1e10f; + for (xx=xi-1;xx<=xi+1;xx++) { + for (yy=yi-1;yy<=yi+1;yy++) { + for (zz=zi-1;zz<=zi+1;zz++) { + p = HASHPNT(xx, yy, zz); + xd = x - (p[0] + xx); + yd = y - (p[1] + yy); + zd = z - (p[2] + zz); + d = distfunc(xd, yd, zd, me); + if (d1.f) return 1.f; + return t; +} + + +/* Signed version of all 6 of the above, just 2x-1, not really correct though (range is potentially (0, sqrt(6)). + Used in the musgrave functions */ +static float voronoi_F1S(float x, float y, float z) +{ + float da[4], pa[12]; + voronoi(x, y, z, da, pa, 1, 0); + return (2.0*da[0]-1.0); +} + +static float voronoi_F2S(float x, float y, float z) +{ + float da[4], pa[12]; + voronoi(x, y, z, da, pa, 1, 0); + return (2.0*da[1]-1.0); +} + +static float voronoi_F3S(float x, float y, float z) +{ + float da[4], pa[12]; + voronoi(x, y, z, da, pa, 1, 0); + return (2.0*da[2]-1.0); +} + +static float voronoi_F4S(float x, float y, float z) +{ + float da[4], pa[12]; + voronoi(x, y, z, da, pa, 1, 0); + return (2.0*da[3]-1.0); +} + +static float voronoi_F1F2S(float x, float y, float z) +{ + float da[4], pa[12]; + voronoi(x, y, z, da, pa, 1, 0); + return (2.0*(da[1]-da[0])-1.0); +} + +/* Crackle type pattern, just a scale/clamp of F2-F1 */ +static float voronoi_CrS(float x, float y, float z) +{ + float t = 10*voronoi_F1F2(x, y, z); + if (t>1.f) return 1.f; + return (2.0*t-1.0); +} + + +/***************/ +/* voronoi end */ +/***************/ + +/*************/ +/* CELLNOISE */ +/*************/ + +/* returns unsigned cellnoise */ +static float cellNoiseU(float x, float y, float z) +{ + int xi = (int)(floor(x)); + int yi = (int)(floor(y)); + int zi = (int)(floor(z)); + unsigned int n = xi + yi*1301 + zi*314159; + n ^= (n<<13); + return ((float)(n*(n*n*15731 + 789221) + 1376312589) / 4294967296.0); +} + +/* idem, signed */ +float cellNoise(float x, float y, float z) +{ + return (2.0*cellNoiseU(x, y, z)-1.0); +} + +/* returns a vector/point/color in ca, using point hasharray directly */ +void cellNoiseV(float x, float y, float z, float *ca) +{ + int xi = (int)(floor(x)); + int yi = (int)(floor(y)); + int zi = (int)(floor(z)); + float *p = HASHPNT(xi, yi, zi); + ca[0] = p[0]; + ca[1] = p[1]; + ca[2] = p[2]; +} + + +/*****************/ +/* end cellnoise */ +/*****************/ + +/* newnoise: generic noise function for use with different noisebases */ +float BLI_gNoise(float noisesize, float x, float y, float z, int hard, int noisebasis) +{ + float (*noisefunc)(float, float, float); + + switch (noisebasis) { + case 1: + noisefunc = orgPerlinNoiseU; + break; + case 2: + noisefunc = newPerlinU; + break; + case 3: + noisefunc = voronoi_F1; + break; + case 4: + noisefunc = voronoi_F2; + break; + case 5: + noisefunc = voronoi_F3; + break; + case 6: + noisefunc = voronoi_F4; + break; + case 7: + noisefunc = voronoi_F1F2; + break; + case 8: + noisefunc = voronoi_Cr; + break; + case 14: + noisefunc = cellNoiseU; + break; + case 0: + default: { + noisefunc = orgBlenderNoise; + /* add one to make return value same as BLI_hnoise */ + x += 1; + y += 1; + z += 1; + } + } + + if (noisesize!=0.0) { + noisesize = 1.0/noisesize; + x *= noisesize; + y *= noisesize; + z *= noisesize; + } + + if (hard) return fabs(2.0*noisefunc(x, y, z)-1.0); + return noisefunc(x, y, z); +} + +/* newnoise: generic turbulence function for use with different noisebasis */ +float BLI_gTurbulence(float noisesize, float x, float y, float z, int oct, int hard, int noisebasis) +{ + float (*noisefunc)(float, float, float); + float sum, t, amp=1, fscale=1; + int i; + + switch (noisebasis) { + case 1: + noisefunc = orgPerlinNoiseU; + break; + case 2: + noisefunc = newPerlinU; + break; + case 3: + noisefunc = voronoi_F1; + break; + case 4: + noisefunc = voronoi_F2; + break; + case 5: + noisefunc = voronoi_F3; + break; + case 6: + noisefunc = voronoi_F4; + break; + case 7: + noisefunc = voronoi_F1F2; + break; + case 8: + noisefunc = voronoi_Cr; + break; + case 14: + noisefunc = cellNoiseU; + break; + case 0: + default: + noisefunc = orgBlenderNoise; + x += 1; + y += 1; + z += 1; + } + + if (noisesize!=0.0) { + noisesize = 1.0/noisesize; + x *= noisesize; + y *= noisesize; + z *= noisesize; + } + + sum = 0; + for (i=0;i<=oct;i++, amp*=0.5, fscale*=2) { + t = noisefunc(fscale*x, fscale*y, fscale*z); + if (hard) t = fabs(2.0*t-1.0); + sum += t * amp; + } + + sum *= ((float)(1<0.001) && (i<(int)octaves); i++) { + if (weight>1.0) weight=1.0; + signal = (noisefunc(x, y, z) + offset) * pwr; + pwr *= pwHL; + result += weight * signal; + weight *= gain * signal; + x *= lacunarity; + y *= lacunarity; + z *= lacunarity; + } + + rmd = octaves - floor(octaves); + if (rmd!=0.f) result += rmd * ((noisefunc(x, y, z) + offset) * pwr); + + return result; + +} /* HybridMultifractal() */ + + +/* Ridged multifractal terrain model. + * + * Some good parameter values to start with: + * + * H: 1.0 + * offset: 1.0 + * gain: 2.0 + */ +float mg_RidgedMultiFractal(float x, float y, float z, float H, float lacunarity, float octaves, float offset, float gain, int noisebasis) +{ + float result, signal, weight; + int i; + float pwHL = pow(lacunarity, -H); + float pwr = pwHL; /* starts with i=1 instead of 0 */ + + float (*noisefunc)(float, float, float); + switch (noisebasis) { + case 1: + noisefunc = orgPerlinNoise; + break; + case 2: + noisefunc = newPerlin; + break; + case 3: + noisefunc = voronoi_F1S; + break; + case 4: + noisefunc = voronoi_F2S; + break; + case 5: + noisefunc = voronoi_F3S; + break; + case 6: + noisefunc = voronoi_F4S; + break; + case 7: + noisefunc = voronoi_F1F2S; + break; + case 8: + noisefunc = voronoi_CrS; + break; + case 14: + noisefunc = cellNoise; + break; + case 0: + default: { + noisefunc = orgBlenderNoiseS; + } + } + + signal = offset - fabs(noisefunc(x, y, z)); + signal *= signal; + result = signal; + weight = 1.f; + + for( i=1; i<(int)octaves; i++ ) { + x *= lacunarity; + y *= lacunarity; + z *= lacunarity; + weight = signal * gain; + if (weight>1.0) weight=1.0; else if (weight<0.0) weight=0.0; + signal = offset - fabs(noisefunc(x, y, z)); + signal *= signal; + signal *= weight; + result += signal * pwr; + pwr *= pwHL; + } + + return result; +} /* RidgedMultifractal() */ + +/* "Variable Lacunarity Noise" + * A distorted variety of Perlin noise. + */ +float mg_VLNoise(float x, float y, float z, float distortion, int nbas1, int nbas2) +{ + float rv[3]; + float (*noisefunc1)(float, float, float); + float (*noisefunc2)(float, float, float); + + switch (nbas1) { + case 1: + noisefunc1 = orgPerlinNoise; + break; + case 2: + noisefunc1 = newPerlin; + break; + case 3: + noisefunc1 = voronoi_F1S; + break; + case 4: + noisefunc1 = voronoi_F2S; + break; + case 5: + noisefunc1 = voronoi_F3S; + break; + case 6: + noisefunc1 = voronoi_F4S; + break; + case 7: + noisefunc1 = voronoi_F1F2S; + break; + case 8: + noisefunc1 = voronoi_CrS; + break; + case 14: + noisefunc1 = cellNoise; + break; + case 0: + default: { + noisefunc1 = orgBlenderNoiseS; + } + } + + switch (nbas2) { + case 1: + noisefunc2 = orgPerlinNoise; + break; + case 2: + noisefunc2 = newPerlin; + break; + case 3: + noisefunc2 = voronoi_F1S; + break; + case 4: + noisefunc2 = voronoi_F2S; + break; + case 5: + noisefunc2 = voronoi_F3S; + break; + case 6: + noisefunc2 = voronoi_F4S; + break; + case 7: + noisefunc2 = voronoi_F1F2S; + break; + case 8: + noisefunc2 = voronoi_CrS; + break; + case 14: + noisefunc2 = cellNoise; + break; + case 0: + default: { + noisefunc2 = orgBlenderNoiseS; + } + } + + /* get a random vector and scale the randomization */ + rv[0] = noisefunc1(x+13.5, y+13.5, z+13.5) * distortion; + rv[1] = noisefunc1(x, y, z) * distortion; + rv[2] = noisefunc1(x-13.5, y-13.5, z-13.5) * distortion; + return noisefunc2(x+rv[0], y+rv[1], z+rv[2]); /* distorted-domain noise */ +} + +/****************/ +/* musgrave end */ +/****************/ diff --git a/source/blender/blenlib/intern/psfont.c b/source/blender/blenlib/intern/psfont.c new file mode 100644 index 00000000000..941bf4204a8 --- /dev/null +++ b/source/blender/blenlib/intern/psfont.c @@ -0,0 +1,2126 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * fromtype1 - Convert an Adobe type 1 font into .of or .sf format. + * Paul Haeberli - 1990 + */ + +#include +#include +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_vfontdata.h" +#include "BLI_blenlib.h" + +#include "DNA_packedFile_types.h" +#include "DNA_curve_types.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + + /* ObjFnt types */ + +typedef struct chardesc { + short movex, movey; /* advance */ + short llx, lly; /* bounding box */ + short urx, ury; + short *data; /* char data */ + long datalen; +} chardesc; + +typedef struct objfnt { + struct objfnt *freeaddr; /* if freeaddr != 0, objfnt is one chunck */ + short type; + short charmin, charmax; + short my_nchars; + short scale; + chardesc *my_chars; +} objfnt; + +#define OFMAGIC 0x93339333 + +#define TM_TYPE 1 +#define PO_TYPE 2 +#define SP_TYPE 3 + +/* ops for tmesh characters */ + +#define TM_BGNTMESH (1) +#define TM_SWAPTMESH (2) +#define TM_ENDBGNTMESH (3) +#define TM_RETENDTMESH (4) +#define TM_RET (5) + +/* ops for poly characters */ + +#define PO_BGNLOOP (1) +#define PO_ENDBGNLOOP (2) +#define PO_RETENDLOOP (3) +#define PO_RET (4) + +/* ops for spline characters */ + +#define SP_MOVETO (1) +#define SP_LINETO (2) +#define SP_CURVETO (3) +#define SP_CLOSEPATH (4) +#define SP_RETCLOSEPATH (5) +#define SP_RET (6) + + +#define MIN_ASCII ' ' +#define MAX_ASCII '~' +#define NASCII (256 - 32) + +#define NOBBOX (30000) + +typedef struct pschar { + char *name; + int code; + int prog; +} pschar; + + /***/ + +#define SKIP 4 +#define LINELEN 2048 +#define NOTHEX (100) +#define MC1 52845 +#define MC2 22719 +#define MAXSUBRS 4000 +#define MAXCHARS 4000 +#define MAXTRIES 30 + +/* some local thingies */ +static void rcurveto( int dx1, int dy1, int dx2, int dy2, int dx3, int dy3); +static void makeobjfont(int savesplines); +static void drawchar(int c); +static void runprog(void); +static int chartoindex(objfnt *fnt, int c); +static short STDtoISO(short c); +static char * newfgets(char * s, int n, PackedFile * pf); +static int readfontmatrix(PackedFile * pf, float mat[2][2]); +static char mdecrypt(char cipher); +static void decryptall(void); +static int decodetype1(PackedFile * pf, char *outname); +static void fakefopen(void); +static char *fakefread(int n); +static void setcharlist(void); +static void initpcstack(void); +static char *poppc(void); +static void initstack(void); +static void push(int val); +static int pop(void); +static void initretstack(void); +static void retpush(int val); +static int retpop(void); +static void subr1(void); +static void subr2(void); +static void subr0(void); +static void append_poly_offset(short ofsx, short ofsy, short * data); +static void append_spline_offset(short ofsx, short ofsy, short * data); +static void setwidth(int w, int x); +static void poly_beginchar(void); +static void poly_endchar(void); +static void poly_close(void); +static void poly_pnt(float x, float y); +static void spline_beginchar(void); +static void spline_endchar(void); +static void spline_close(void); +static void spline_line(float x0, float y0, float x1, float y1); +static void spline_curveto(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3); +static void savestart(int x, int y); +static void sbpoint( int x, int y); +static void rmoveto( int x, int y); +static void drawline(float x0, float y0, float x1, float y1, float dx0, float dy0, float dx1, float dy1); +static void rlineto( int x, int y); +static void closepath(void); +static void bezadapt( float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float beztol); +static void drawbez( float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3); +static int docommand(int cmd); + +/* some local vars */ +static int startx, starty; +static int curx, cury; +static int nextx, nexty; +static int delx, dely; +static int started; + + +/* postscript commands */ +#define HSTEM (1) +#define VSTEM (3) +#define VMOVETO (4) +#define RLINETO (5) +#define HLINETO (6) +#define VLINETO (7) +#define RRCURVETO (8) +#define CLOSEPATH (9) +#define CALLSUBR (10) +#define RETURN (11) +#define HSBW (13) +#define ENDCHAR (14) +#define RMOVETO (21) +#define HMOVETO (22) +#define VHCURVETO (30) +#define HVCURVETO (31) +#define DOTSECTION (256+0) +#define VSTEM3 (256+1) +#define HSTEM3 (256+2) +#define SEAC (256+6) +#define SBW (256+7) +#define DIV (256+12) +#define CALLOTHERSUBR (256+16) +#define POP (256+17) +#define SETCURRENTPOINT (256+33) +#define WHAT0 (0) + +static char oneline[LINELEN]; +static objfnt *fnt; + +static unsigned short int mr; + +static char *bindat; +static int datbytes; +static int firsted; +static short chardata[20000]; +static int nshorts; + +static int thecharwidth, thesidebearing; +static int npnts, nloops; +static int nvertpos; + +static int fakepos; +static int fakemax; + +static float beztol = 100.0; + +/* extern: from libfm */ + +static char *my_subrs[MAXSUBRS]; +static unsigned int my_sublen[MAXSUBRS]; +static char *my_chars[MAXCHARS]; +static unsigned int my_charlen[MAXCHARS]; +static char *my_charname[MAXCHARS]; +static int my_nsubrs, my_nchars; + +static short sidebearing[MAXCHARS]; +static char tok[LINELEN]; +static int sp_npnts, sp_nloops; + +/* + * interpreter globals + */ + + +static float mat[2][2]; +static char *pcstack[100]; +static char *pc; +static int pcsp; +static int coordpos; +static int coordsave[7][2]; +static int incusp; +static int retstack[1000]; +static int retsp; +static int stack[1000]; +static int sp; +static int savesplines = 1; + +static pschar ISOcharlist[NASCII] = { + "/space", 040, 0, + "/exclam", 041, 0, + "/quotedbl", 042, 0, + "/numbersign", 043, 0, + "/dollar", 044, 0, + "/percent", 045, 0, + "/ampersand", 046, 0, + "/quoteright", 047, 0, + + "/parenleft", 050, 0, + "/parenright", 051, 0, + "/asterisk", 052, 0, + "/plus", 053, 0, + "/comma", 054, 0, + "/hyphen", 055, 0, + "/period", 056, 0, + "/slash", 057, 0, + + "/zero", 060, 0, + "/one", 061, 0, + "/two", 062, 0, + "/three", 063, 0, + "/four", 064, 0, + "/five", 065, 0, + "/six", 066, 0, + "/seven", 067, 0, + + "/eight", 070, 0, + "/nine", 071, 0, + "/colon", 072, 0, + "/semicolon", 073, 0, + "/less", 074, 0, + "/equal", 075, 0, + "/greater", 076, 0, + "/question", 077, 0, + + "/at", 0100, 0, + "/A", 0101, 0, + "/B", 0102, 0, + "/C", 0103, 0, + "/D", 0104, 0, + "/E", 0105, 0, + "/F", 0106, 0, + "/G", 0107, 0, + + "/H", 0110, 0, + "/I", 0111, 0, + "/J", 0112, 0, + "/K", 0113, 0, + "/L", 0114, 0, + "/M", 0115, 0, + "/N", 0116, 0, + "/O", 0117, 0, + + "/P", 0120, 0, + "/Q", 0121, 0, + "/R", 0122, 0, + "/S", 0123, 0, + "/T", 0124, 0, + "/U", 0125, 0, + "/V", 0126, 0, + "/W", 0127, 0, + + "/X", 0130, 0, + "/Y", 0131, 0, + "/Z", 0132, 0, + "/bracketleft", 0133, 0, + "/backslash", 0134, 0, + "/bracketright", 0135, 0, + "/asciicircum", 0136, 0, + "/underscore", 0137, 0, + + "/quoteleft", 0140, 0, + "/a", 0141, 0, + "/b", 0142, 0, + "/c", 0143, 0, + "/d", 0144, 0, + "/e", 0145, 0, + "/f", 0146, 0, + "/g", 0147, 0, + + "/h", 0150, 0, + "/i", 0151, 0, + "/j", 0152, 0, + "/k", 0153, 0, + "/l", 0154, 0, + "/m", 0155, 0, + "/n", 0156, 0, + "/o", 0157, 0, + + "/p", 0160, 0, + "/q", 0161, 0, + "/r", 0162, 0, + "/s", 0163, 0, + "/t", 0164, 0, + "/u", 0165, 0, + "/v", 0166, 0, + "/w", 0167, 0, + + "/x", 0170, 0, + "/y", 0171, 0, + "/z", 0172, 0, + "/braceleft", 0173, 0, + "/bar", 0174, 0, + "/braceright", 0175, 0, + "/asciitilde", 0176, 0, + "/", 0177, 0, + + + /* nonstandard defs */ + + "/quotedblleft", 0200, 0, + "/quotedblright", 0201, 0, + "/quotedblbase", 0202, 0, + "/quotesinglbase", 0203, 0, + "/guilsinglleft", 0204, 0, + "/guilsinglright", 0205, 0, + "/endash", 0206, 0, + "/dagger", 0207, 0, + + "/daggerdbl", 0210, 0, + "/trademark", 0211, 0, + "/bullet", 0212, 0, + "/perthousand", 0213, 0, + "/Lslash", 0214, 0, + "/OE", 0215, 0, + "/lslash", 0216, 0, + "/oe", 0217, 0, + + /* endnonstandard defs */ + + "/dotlessi", 0220, 0, + "/grave", 0221, 0, + "/acute", 0222, 0, + "/circumflex", 0223, 0, + "/tilde", 0224, 0, + "/", 0225, 0, + "/breve", 0226, 0, + "/dotaccent", 0227, 0, + + "/", 0230, 0, + "/", 0231, 0, + "/ring", 0232, 0, + "/", 0233, 0, + "/", 0234, 0, + "/hungarumlaut", 0235, 0, + "/ogonek", 0236, 0, + "/caron", 0237, 0, + + "/", 0240, 0, + "/exclamdown", 0241, 0, + "/cent", 0242, 0, + "/sterling", 0243, 0, + "/florin", 0244, 0, + "/yen", 0245, 0, + "/brokenbar", 0246, 0, + "/section", 0247, 0, + + "/dieresis", 0250, 0, + "/copyright", 0251, 0, + "/ordfeminine", 0252, 0, + "/guillemotleft", 0253, 0, + "/logicalnot", 0254, 0, + "/hyphen", 0255, 0, + "/registered", 0256, 0, + "/macron", 0257, 0, + + "/degree", 0260, 0, + "/plusminus", 0261, 0, + "/twosuperior", 0262, 0, + "/threesuperior", 0263, 0, + "/acute", 0264, 0, + "/mu", 0265, 0, + "/paragraph", 0266, 0, + "/periodcentered", 0267, 0, + + "/cedilla", 0270, 0, + "/onesuperior", 0271, 0, + "/ordmasculine", 0272, 0, + "/guillemotright", 0273, 0, + "/onequarter", 0274, 0, + "/onehalf", 0275, 0, + "/threequarters", 0276, 0, + "/questiondown", 0277, 0, + + "/Agrave", 0300, 0, + "/Aacute", 0301, 0, + "/Acircumflex", 0302, 0, + "/Atilde", 0303, 0, + "/Adieresis", 0304, 0, + "/Aring", 0305, 0, + "/AE", 0306, 0, + "/Ccedilla", 0307, 0, + + "/Egrave", 0310, 0, + "/Eacute", 0311, 0, + "/Ecircumflex", 0312, 0, + "/Edieresis", 0313, 0, + "/Igrave", 0314, 0, + "/Iacute", 0315, 0, + "/Icircumflex", 0316, 0, + "/Idieresis", 0317, 0, + + "/Eth", 0320, 0, + "/Ntilde", 0321, 0, + "/Ograve", 0322, 0, + "/Oacute", 0323, 0, + "/Ocircumflex", 0324, 0, + "/Otilde", 0325, 0, + "/Odieresis", 0326, 0, + "/multiply", 0327, 0, + + "/Oslash", 0330, 0, + "/Ugrave", 0331, 0, + "/Uacute", 0332, 0, + "/Ucircumflex", 0333, 0, + "/Udieresis", 0334, 0, + "/Yacute", 0335, 0, + "/Thorn", 0336, 0, + "/germandbls", 0337, 0, + + "/agrave", 0340, 0, + "/aacute", 0341, 0, + "/acircumflex", 0342, 0, + "/atilde", 0343, 0, + "/adieresis", 0344, 0, + "/aring", 0345, 0, + "/ae", 0346, 0, + "/ccedilla", 0347, 0, + + "/egrave", 0350, 0, + "/eacute", 0351, 0, + "/ecircumflex", 0352, 0, + "/edieresis", 0353, 0, + "/igrave", 0354, 0, + "/iacute", 0355, 0, + "/icircumflex", 0356, 0, + "/idieresis", 0357, 0, + + "/eth", 0360, 0, + "/ntilde", 0361, 0, + "/ograve", 0362, 0, + "/oacute", 0363, 0, + "/ocircumflex", 0364, 0, + "/otilde", 0365, 0, + "/odieresis", 0366, 0, + "/divide", 0367, 0, + + "/oslash", 0370, 0, + "/ugrave", 0371, 0, + "/uacute", 0372, 0, + "/ucircumflex", 0373, 0, + "/udieresis", 0374, 0, + "/yacute", 0375, 0, + "/thorn", 0376, 0, + "/ydieresis", 0377, 0, +}; + + +static short STDvsISO [][2] = { + 0341, 0306, /* AE */ + 0351, 0330, /* Oslash */ + 0302, 0222, /* acute */ + 0361, 0346, /* ae */ + 0306, 0226, /* breve */ + 0317, 0237, /* caron */ + 0313, 0270, /* cedilla */ + 0303, 0223, /* circumflex */ + 0250, 0244, /* currency */ + 0310, 0250, /* dieresis */ + 0307, 0227, /* dotaccent */ + 0365, 0220, /* dotlessi */ + 0373, 0337, /* germandbls */ + 0301, 0221, /* grave */ + 0315, 0235, /* hungarumlaut */ + 0055, 0255, /* hyphen */ + 0305, 0257, /* macron */ + 0316, 0236, /* ogenek */ + 0343, 0252, /* ordfeminine */ + 0353, 0272, /* ordmasculine */ + 0371, 0370, /* oslash */ + 0264, 0267, /* periodcentered */ + 0312, 0232, /* ring */ + 0304, 0224, /* tilde */ +}; + +/* from objfont.c, rest is in lfm_s !!*/ + +/* START 5.2 */ + +static int chartoindex(objfnt *fnt, int c) +{ + if(ccharmin) + return -1; + if(c>fnt->charmax) + return -1; + return c-fnt->charmin; +} + + +static chardesc *getchardesc(objfnt *fnt, int c) +{ + int index; + + index = chartoindex(fnt,c); + if(index<0) + return 0; + return fnt->my_chars+index; +} + +static objfnt *newobjfnt(int type, int charmin, int charmax, int fscale) +{ + objfnt *fnt; + + fnt = (objfnt *)MEM_mallocN(sizeof(objfnt), "newobjfnt"); + fnt->freeaddr = 0; + fnt->type = type; + fnt->charmin = charmin; + fnt->charmax = charmax; + fnt->my_nchars = fnt->charmax-fnt->charmin+1; + fnt->scale = fscale; + fnt->my_chars = (chardesc *)MEM_mallocN(fnt->my_nchars*sizeof(chardesc), "newobjfnt2"); + memset(fnt->my_chars, 0, fnt->my_nchars*sizeof(chardesc)); + return fnt; +} + + +static void addchardata (objfnt * fnt, int c, short * data, int nshorts) +{ + int index; + chardesc *cd; + + index = chartoindex(fnt,c); + if(index<0) { + fprintf(stderr,"Addchardata bad poop\n"); + return; + } + cd = fnt->my_chars+index; + fnt->freeaddr = 0; + cd->datalen = nshorts*sizeof(short); + cd->data = (short *)MEM_mallocN(cd->datalen, "addchardata"); + memcpy(cd->data, data, cd->datalen); +} + +static void addcharmetrics(objfnt *fnt, int c, int movex, int movey) +{ + int index; + chardesc *cd; + + index = chartoindex(fnt,c); + if(index<0) { + fprintf(stderr,"Addcharmetrics bad poop\n"); + return; + } + cd = fnt->my_chars+index; + cd->movex = movex; + cd->movey = movey; +} + + +static void fakechar(objfnt *fnt, int c, int width) +{ + short chardata[1]; + + chardata[0] = PO_RET; + addchardata(fnt,c,chardata,1); + addcharmetrics(fnt,c,width,0); +} + + +static void freeobjfnt(objfnt * fnt) +{ + int i; + chardesc *cd; + + cd = fnt->my_chars; + for(i=0; imy_nchars; i++) { + if(cd->data) + MEM_freeN(cd->data); + cd++; + } + MEM_freeN(fnt->my_chars); + MEM_freeN(fnt); +} + + +/* END 5.2 */ + +static short STDtoISO(short c) +{ + short i = (sizeof(STDvsISO) / (2 * sizeof(short))) - 1; + + for (;i >= 0; i--){ + if (STDvsISO[i][0] == c) return (STDvsISO[i][1]); + } + return(c); +} + + +/* + * read the font matrix out of the font file + * + */ + +static char * newfgets(char * s, int n, PackedFile * pf){ + int c; + char * p; + + p = s; + while (n > 0){ + c = ((char *) pf->data)[pf->seek]; + pf->seek++; + if (pf->seek > pf->size){ + return (0); + } + if (c == 10 || c == 13){ + *p = 0; + return(s); + } + *p++ = c; + n--; + } + *p = 0; + return(s); +} + +static int readfontmatrix(PackedFile * pf, float mat[2][2]) +{ + char *cptr; + float a, b, c, d, e, f; + + pf->seek = 0; + + /* look for the FontMatrix def */ + while(1) { + if(!newfgets(oneline, LINELEN, pf)) { + fprintf(stderr,"fromtype1: no FontMatrix found\n"); + return(-1); + } + cptr = strchr(oneline,'/'); + if(cptr) { + if(strncmp(cptr,"/FontMatrix",11) == 0) { + cptr = strchr(cptr,'['); + if(!cptr) { + fprintf(stderr,"fromtype1: bad FontMatrix line\n"); + return(-1); + } + sscanf(cptr+1,"%f %f %f %f %f %f\n",&a,&b,&c,&d,&e,&f); + break; + } + } + } + + mat[0][0] = 1000.0*a; + mat[1][0] = 1000.0*b; + mat[0][1] = 1000.0*c; + mat[1][1] = 1000.0*d; + + return(0); +} + +/* + * Decryption support + * + * + */ +static void resetdecrypt(int n) +{ + mr = n; +} + + + +/* + * decryption subroutines + * + */ + +static char mdecrypt(char cipher) +{ + char plain; + + plain = (cipher^(mr>>8)); + mr = (cipher+mr)*MC1 + MC2; + return plain; +} + +static void decryptdata(char * cptr, int n) +{ + while(n--) { + *cptr = mdecrypt(*cptr); + cptr++; + } +} + +static int decryptprogram(char *buf, int len) +{ + int i; + + resetdecrypt(4330); + for(i=0; i='0' && i<='9') + hextab[i] = i-'0'; + else if(i>='a' && i<='f') + hextab[i] = 10+i-'a'; + else if(i>='A' && i<='F') + hextab[i] = 10+i-'A'; + else + hextab[i] = NOTHEX; + } + } + + pf->seek = 0; + + /* allocate buffers */ + totlen = pf->size; + hexdat = (char *)MEM_mallocN(totlen, "hexdat"); + bindat = (char *)MEM_mallocN(totlen, "bindat"); + + /* look for eexec part of file */ + while(1) { + if(!newfgets(oneline, LINELEN, pf)) { + fprintf(stderr,"fromtype1: no currentfile eexec found\n"); + return(-1); + } + oneline[16] = 0; + if(strcmp(oneline,"currentfile eexe") == 0) + break; + } + + /* initialize decryption variables */ + mr = 55665; + + /* first byte == 0 for binary data (???) */ + + c = ((char *) pf->data)[pf->seek]; + + if (hextab[c] != NOTHEX){ + /* read all the hex bytes into the hex buffer */ + hexbytes = 0; + while(newfgets(oneline, LINELEN, pf)) { + hptr = (char *)oneline; + while(*hptr) { + if(hextab[*hptr] != NOTHEX) + hexdat[hexbytes++] = *hptr; + hptr++; + } + } + + /* check number of hex bytes */ + if(hexbytes & 1) + hexbytes--; + datbytes = hexbytes/2; + + /* translate hex data to binary */ + hptr = hexdat; + bptr = bindat; + c = datbytes; + while(c--) { + *bptr++ = (hextab[hptr[0]]<<4)+hextab[hptr[1]]; + hptr += 2; + } + + /* decrypt the data */ + decryptdata(bindat,datbytes); + + } else { + datbytes = pf->size - pf->seek; + memcpy(bindat, ((char *) pf->data) + pf->seek, datbytes); + + if ((bindat[2] << (8 + bindat[3])) == 0x800){ + /* order data (remove 6 bytes headers) */ + i = datbytes; + hptr = bptr = bindat + 4; + hptr += 2; + + while (i > 0){ + if (i > 2046) c = 2046; + else c = i; + + memcpy(bptr, hptr, c); + bptr += 2046; + hptr += 2046 + 6; + i -= 2046 + 6; + datbytes -= 6; + } + + /* decrypt the data */ + decryptdata(bindat+4,datbytes); + } else{ + decryptdata(bindat+6,datbytes-6); + } + } + +#ifdef DEBUG + outf = fopen(outname,"wb"); + fwrite(bindat,datbytes,1,outf); + fclose(outf); +#endif + + MEM_freeN(hexdat); + + return 1; +} + +/* + * fake file reading funcs + * + * + */ + +static void fakefopen(void) +{ + fakepos = 0; + fakemax = datbytes; +} + + +static void fakegettoken(char *str) +{ + int c; + char *cptr; + char *start; + + start = (char *) str; + cptr = bindat+fakepos; + c = *cptr++; + fakepos++; + if(c != '\n') { + while(isspace(c)) { + c = *cptr++; + fakepos++; + } + while (fakeposfakemax) { + fprintf(stderr,"fromtype1: unexpected eof\n"); + strcpy(start, "end"); + } +} + +static int fakefgets(char *buf,int max) +{ + char *cptr; + + cptr = (char *)(bindat+fakepos); + while(max--) { + *buf++ = *cptr; + fakepos++; + if(*cptr == 10 || *cptr == 13) + return 1; + cptr++; + if(fakepos>fakemax) + return 0; + } + return 0; +} + +static char *fakefread(int n) +{ + fakepos += n; + return bindat+fakepos-n; +} + +static void applymat(float mat[][2], float *x, float *y) +{ + float tx, ty; + + tx = ((*x)*mat[0][0])+((*y)*mat[0][1]); + ty = ((*x)*mat[1][0])+((*y)*mat[1][1]); + *x = tx; + *y = ty; +} + +static void setcharlist(void) +{ + char *name, found; + int i, j; + + for(i=0; imy_nsubrs) { + fprintf(stderr,"bad Subr index %d\n",index); + /*exit(1);*/ + } + + /* get the number of bytes to read */ + fakegettoken(tok); + nread = atoi(tok); + fakegettoken(tok); + + /* read in the subroutine */ + my_sublen[index] = nread; + my_subrs[index] = fakefread(nread); + fakegettoken(tok); + } + + /* look for the CharStrings */ + while(1) { + fakegettoken(tok); + cptr = strchr(tok,'/'); + if(cptr && strcmp(cptr,"/CharStrings") == 0) + break; + } + + fakegettoken(tok); /* skip my_ncharscrings */ + fakegettoken(tok); /* skip dict */ + fakegettoken(tok); /* skip dup */ + fakegettoken(tok); /* skip begin */ + fakegettoken(tok); /* skip newline */ + + /* read the CharStrings one by one */ + my_nchars = 0; + for(i=0; i=7) { + fprintf(stderr,"subr2: bad poop\n"); + /*exit(1);*/ + } + coordsave[coordpos][0] = x; + coordsave[coordpos][1] = y; + coordpos++; +} + +static void subr0(void) +{ + int x0, y0; + int x1, y1; + int x2, y2; + int x3, y3; + int xpos, ypos, noise; + + ypos = pop(); + xpos = pop(); + noise = pop(); + if(coordpos!=7) { + fprintf(stderr,"subr0: bad poop\n"); + /*exit(1);*/ + } + x0 = coordsave[0][0]; + y0 = coordsave[0][1]; + + x1 = coordsave[1][0]+x0; + y1 = coordsave[1][1]+y0; + x2 = coordsave[2][0]; + y2 = coordsave[2][1]; + x3 = coordsave[3][0]; + y3 = coordsave[3][1]; + rcurveto(x1,y1,x1+x2,y1+y2,x1+x2+x3,y1+y2+y3); + x1 = coordsave[4][0]; + y1 = coordsave[4][1]; + x2 = coordsave[5][0]; + y2 = coordsave[5][1]; + x3 = coordsave[6][0]; + y3 = coordsave[6][1]; + rcurveto(x1,y1,x1+x2,y1+y2,x1+x2+x3,y1+y2+y3); + getpos(&x0,&y0); + retpush(y0); + retpush(x0); + incusp = 0; +} + +static void append_poly_offset(short ofsx, short ofsy, short * data) +{ + int nverts; + + if (data == 0) return; + + while(1) { + switch(chardata[nshorts++] = *data++) { + case PO_BGNLOOP: + nshorts --; /* for the first time */ + break; + case PO_RETENDLOOP: + case PO_RET: + return; + } + nverts = chardata[nshorts++] = *data++; + while(nverts--) { + chardata[nshorts++] = (*data++) + ofsx; + chardata[nshorts++] = (*data++) + ofsy; + } + } +} + + +static void append_spline_offset(short ofsx, short ofsy, short * data) +{ + int nverts = 0; + + if (data == 0) return; + + while(1) { + switch(chardata[nshorts++] = *data++) { + case SP_MOVETO: + case SP_LINETO: + nverts = 1; + break; + case SP_CURVETO: + nverts = 3; + break; + case SP_RETCLOSEPATH: + case SP_RET: + return; + } + + for (; nverts > 0; nverts--) { + chardata[nshorts++] = (*data++) + ofsx; + chardata[nshorts++] = (*data++) + ofsy; + } + } +} + + + +/* + * graphics follows + * + * + */ + + +/* poly output stuff */ + +static void setwidth(int w, int x) +{ + thecharwidth = w; + thesidebearing = x; +} + +static void poly_beginchar(void) +{ + npnts = 0; + nloops = 0; +} + +static void poly_endchar(void) +{ + if(nloops == 0) + chardata[nshorts++] = PO_RET; + else + chardata[nshorts++] = PO_RETENDLOOP; +} + +static void poly_close(void) +{ + chardata[nvertpos] = npnts; + npnts = 0; +} + +static void poly_pnt(float x, float y) +{ + int ix, iy; + + applymat(mat,&x,&y); + ix = floor(x); + iy = floor(y); + if(npnts == 0) { + if(nloops == 0) { + chardata[nshorts++] = PO_BGNLOOP; + nvertpos = nshorts++; + } else { + chardata[nshorts++] = PO_ENDBGNLOOP; + nvertpos = nshorts++; + } + nloops++; + } + chardata[nshorts++] = ix; + chardata[nshorts++] = iy; + npnts++; + +} + +/* spline output stuff */ + +static void spline_beginchar(void) +{ + sp_npnts = 0; + sp_nloops = 0; +} + +static void spline_endchar(void) +{ + if(sp_nloops == 0) + chardata[nshorts++] = SP_RET; + else + chardata[nshorts++] = SP_RETCLOSEPATH; +} + +static void spline_close(void) +{ + chardata[nshorts++] = SP_CLOSEPATH; + sp_npnts = 0; + sp_nloops = 0; +} + +static void spline_line(float x0, float y0, float x1, float y1) +{ + applymat(mat,&x0,&y0); + applymat(mat,&x1,&y1); + + if(sp_npnts == 0) { + chardata[nshorts++] = SP_MOVETO; + chardata[nshorts++] = floor(x0); + chardata[nshorts++] = floor(y0); + sp_npnts++; + sp_nloops++; + } + chardata[nshorts++] = SP_LINETO; + chardata[nshorts++] = floor(x1); + chardata[nshorts++] = floor(y1); + sp_npnts++; +} + +static void spline_curveto(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3) +{ + applymat(mat,&x0,&y0); + + applymat(mat,&x1,&y1); + applymat(mat,&x2,&y2); + applymat(mat,&x3,&y3); + if(sp_npnts == 0) { + chardata[nshorts++] = SP_MOVETO; + chardata[nshorts++] = floor(x0); + chardata[nshorts++] = floor(y0); + sp_npnts++; + sp_nloops++; + } + chardata[nshorts++] = SP_CURVETO; + chardata[nshorts++] = floor(x1); + chardata[nshorts++] = floor(y1); + chardata[nshorts++] = floor(x2); + chardata[nshorts++] = floor(y2); + chardata[nshorts++] = floor(x3); + chardata[nshorts++] = floor(y3); +} + +static void savestart(int x, int y) +{ + startx = x; + starty = y; + started = 1; +} + +static void sbpoint( int x, int y) +{ + curx = x; + cury = y; +} + +static void rmoveto( int x, int y) +{ + if(incusp) { + delx = x; + dely = y; + } else { + curx += x; + cury += y; + savestart(curx,cury); + } +} + +static void drawline(float x0, float y0, float x1, float y1, float dx0, float dy0, float dx1, float dy1) +{ + if(x0!=x1 || y0!=y1) + poly_pnt(x1,y1); +} + + +static void rlineto( int x, int y) +{ + float dx, dy; + + nextx = curx + x; + nexty = cury + y; + dx = nextx-curx; + dy = nexty-cury; + if (savesplines) spline_line( curx, cury, nextx, nexty); + else drawline( curx, cury, nextx, nexty,dx,dy,dx,dy); + curx = nextx; + cury = nexty; +} + +static void closepath(void) +{ + float dx, dy; + + if(started) { + dx = startx-curx; + dy = starty-cury; + if (savesplines) { + spline_close(); + } else { + drawline( curx, cury, startx, starty,dx,dy,dx,dy); + poly_close(); + } + started = 0; + } +} + +static void bezadapt( float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float beztol) +{ + float ax0,ay0,ax1,ay1,ax2,ay2,ax3,ay3; + float bx0,by0,bx1,by1,bx2,by2,bx3,by3; + float midx, midy; + float linx, liny, dx, dy, mag; + + midx = (x0+3*x1+3*x2+x3)/8.0; + midy = (y0+3*y1+3*y2+y3)/8.0; + linx = (x0+x3)/2.0; + liny = (y0+y3)/2.0; + dx = midx-linx; + dy = midy-liny; + mag = dx*dx+dy*dy; + if(mag<(beztol*beztol)) + drawline(x0,y0,x3,y3,x1-x0,y1-y0,x3-x2,y3-y2); + else { + ax0 = x0; + ay0 = y0; + ax1 = (x0+x1)/2; + ay1 = (y0+y1)/2; + ax2 = (x0+2*x1+x2)/4; + ay2 = (y0+2*y1+y2)/4; + ax3 = midx; + ay3 = midy; + bezadapt(ax0,ay0,ax1,ay1,ax2,ay2,ax3,ay3,beztol); + + bx0 = midx; + by0 = midy; + bx1 = (x1+2*x2+x3)/4; + by1 = (y1+2*y2+y3)/4; + bx2 = (x2+x3)/2; + by2 = (y2+y3)/2; + bx3 = x3; + by3 = y3; + bezadapt(bx0,by0,bx1,by1,bx2,by2,bx3,by3,beztol); + } +} + +static void drawbez( float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3) +{ + bezadapt(x0,y0,x1,y1,x2,y2,x3,y3,beztol); +} + + +static void rcurveto( int dx1, int dy1, int dx2, int dy2, int dx3, int dy3) +{ + int x0, y0; + int x1, y1; + int x2, y2; + int x3, y3; + + x0 = curx; + y0 = cury; + x1 = curx+dx1; + y1 = cury+dy1; + x2 = curx+dx2; + y2 = cury+dy2; + x3 = curx+dx3; + y3 = cury+dy3; + + if (savesplines) { + spline_curveto( x0, y0, x1, y1, x2, y2, x3, y3); + } else{ + drawbez( x0, y0, x1, y1, x2, y2, x3, y3); + } + curx = x3; + cury = y3; +} + +/* + * saveobjfont - + * save an object font. + * + */ + +/* generic routines */ + +static void makeobjfont(int savesplines) +{ + int i, c; + + if(savesplines) + fnt = newobjfnt(SP_TYPE, 32, 32+NASCII-1, 9840); + else + fnt = newobjfnt(PO_TYPE, 32, 32+NASCII-1, 9840); + + for(i=0; i=0) { + /*printf("decoding %s\n", ISOcharlist[i].name);*/ + + nshorts = 0; + drawchar(ISOcharlist[i].prog); + addchardata(fnt,c,chardata,nshorts); + addcharmetrics(fnt,c,thecharwidth,0); + sidebearing[c] = thesidebearing; + } else if(c == ' ') { + printf("faking space %d\n",i); + fakechar(fnt,' ',400); + } + } +} + +/* + * run the character program + * + * + */ + +static void drawchar(int c) +{ + if (savesplines) { + spline_beginchar(); + } else { + poly_beginchar(); + } + initstack(); + initpcstack(); + initretstack(); + pc = my_chars[c]; + runprog(); + if (savesplines){ + spline_endchar(); + } else { + poly_endchar(); + } +} + +static int docommand(int cmd) +{ + int x, y, w, c1, c2; + int dx1, dy1; + int dx2, dy2; + int dx3, dy3; + float fdx1, fdy1; + int i, sub, n; + char *subpc; + chardesc *cd; + short *ndata; + + switch(cmd) { + case WHAT0: + fprintf(stderr,"\nYUCK: WHAT0\n"); + break; + case HSTEM: + pop(); + pop(); + /*printf("hstem: %d %d\n", pop(), pop());*/ + break; + case VSTEM: + pop(); + pop(); + /*printf("vstem: %d %d\n", pop(), pop());*/ + break; + case VMOVETO: + y = pop(); + rmoveto(0,y); + break; + case RLINETO: + y = pop(); + x = pop(); + rlineto(x,y); + break; + case HLINETO: + x = pop(); + rlineto(x,0); + break; + case VLINETO: + y = pop(); + rlineto(0,y); + break; + case RRCURVETO: + dy3 = pop(); + dx3 = pop(); + dy2 = pop(); + dx2 = pop(); + dy1 = pop(); + dx1 = pop(); + rcurveto(dx1,dy1,dx1+dx2,dy1+dy2,dx1+dx2+dx3,dy1+dy2+dy3); + break; + case CLOSEPATH: + closepath(); + break; + case CALLSUBR: + sub = pop(); + subpc = my_subrs[sub]; + if(!subpc) { + fprintf(stderr,"\nYUCK no sub addr\n"); + } + pushpc(pc); + pc = subpc; + break; + case RETURN: + pc = poppc(); + break; + case HSBW: + w = pop(); + x = pop(); + setwidth(w, x); + sbpoint(x,0); + break; + case ENDCHAR: + closepath(); + break; + case RMOVETO: + y = pop(); + x = pop(); + rmoveto(x,y); + break; + case HMOVETO: + x = pop(); + rmoveto(x,0); + break; + case VHCURVETO: + dy3 = 0; + dx3 = pop(); + dy2 = pop(); + dx2 = pop(); + dy1 = pop(); + dx1 = 0; + rcurveto(dx1,dy1,dx1+dx2,dy1+dy2,dx1+dx2+dx3,dy1+dy2+dy3); + break; + case HVCURVETO: + dy3 = pop(); + dx3 = 0; + dy2 = pop(); + dx2 = pop(); + dy1 = 0; + dx1 = pop(); + rcurveto(dx1,dy1,dx1+dx2,dy1+dy2,dx1+dx2+dx3,dy1+dy2+dy3); + break; + case DOTSECTION: + break; + case VSTEM3: + /*printf("vstem3\n");*/ + pop(); + pop(); + pop(); + pop(); + pop(); + pop(); + break; + case HSTEM3: + /*printf("hstem3\n");*/ + pop(); + pop(); + pop(); + pop(); + pop(); + pop(); + break; + case SEAC: + if (0) { + printf("seac: %3d %3d %3d %3d %3d\n", pop(), pop(), pop(), pop(), pop()); + } else{ + c2 = STDtoISO(pop()); /* accent */ + c1 = STDtoISO(pop()); /* letter */ + + cd = getchardesc(fnt, c1); + if (cd) { + memcpy(chardata, cd->data, cd->datalen); + nshorts = cd->datalen / sizeof(short); + } + + cd = getchardesc(fnt, c2); + if (cd && cd->data && cd->datalen) { + ndata = cd->data; + + if (nshorts) { + if (savesplines) { + switch (chardata[nshorts - 1]){ + case SP_RET: + nshorts--; + break; + case SP_RETCLOSEPATH: + chardata[nshorts - 1] = SP_CLOSEPATH; + break; + } + } else { + switch (chardata[nshorts - 1]){ + case PO_RET: + printf("PO_RET in character disription ?\n"); + nshorts--; + break; + case PO_RETENDLOOP: + if (ndata[0] == PO_BGNLOOP) { + chardata[nshorts - 1] = PO_ENDBGNLOOP; + } else { + printf("new character doesn't start with PO_BGNLOOP ?\n"); + } + break; + } + } + } + + /* instead of the sidebearing[c1] maybe thesidebearing should be used */ + + dy1 = pop(); + dx1 = pop() + sidebearing[c1] - sidebearing[c2]; + pop(); + + fdx1 = dx1; + fdy1 = dy1; + applymat(mat, &fdx1, &fdy1); + dx1 = floor(fdx1); + dy1 = floor(fdy1); + + if (savesplines) { + append_spline_offset(dx1, dy1, ndata); + } else{ + append_poly_offset(dx1, dy1, ndata); + } + + /*printf("first: %d %d\n", cd->data[0], cd->data[1]);*/ + } + fflush(stdout); + } + break; + case SBW: + w = pop(); + y = pop(); + fprintf(stderr,"sbw: width: %d %d\n",w,y); + y = pop(); + x = pop(); + fprintf(stderr,"sbw: side: %d %d\n",x,y); + setwidth(w, x); + sbpoint(x,y); + break; + case DIV: + x = pop(); + y = pop(); + push(x/y); + break; + case CALLOTHERSUBR: + sub = pop(); + n = pop(); + if(sub == 0) + subr0(); + else if(sub == 1) + subr1(); + else if(sub == 2) + subr2(); + else { + for(i=0; i=0 && v<=31) { + if(v == 12) { + w = *pc++; + cmd = 256+w; + } else + cmd = v; + if(!docommand(cmd)) { + return; + } + } else if(v>=32 && v<=246) { + num = v-139; + push(num); + } else if(v>=247 && v<=250) { + w = *pc++; + num = (v-247)*256+w+108; + push(num); + } else if(v>=251 && v<=254) { + w = *pc++; + num = -(v-251)*256-w-108; + push(num); + } else if(v == 255) { + num = *pc++; + num <<= 8; + num |= *pc++; + num <<= 8; + num |= *pc++; + num <<= 8; + num |= *pc++; + push(num); + } + } +} + +/***/ + +static VFontData *objfnt_to_vfontdata(objfnt *fnt) +{ + VFontData *vfd; + chardesc *cd; + short *_data, *data; + int a, i, count, stop, ready, meet; + short first[2], last[2]; + struct Nurb *nu; + struct BezTriple *bezt, *bez2; + float scale, dx, dy; + struct VChar *che; + + if (!fnt || (fnt->type!=SP_TYPE)) { + return NULL; + } + + vfd= MEM_callocN(sizeof(*vfd), "VFontData"); + scale = 10.0/(float)fnt->scale; /* after IRIX 6.2, scaling went wrong */ + + for (i = 0; i < MAX_VF_CHARS; i++) { + cd = getchardesc(fnt, i); + if (cd && cd->data && cd->datalen) { + che = (VChar *) MEM_callocN(sizeof(VChar), "objfnt_char"); + BLI_addtail(&vfd->characters, che); + che->index = i; + che->width = scale * cd->movex; + + _data = data = cd->data; + + do{ + /* count first */ + _data = data; + count = 0; + ready = stop = 0; + + do{ + switch(*data++){ + case SP_MOVETO: + first[0] = data[0]; + first[1] = data[1]; + case SP_LINETO: + count++; + last[0] = data[0]; + last[1] = data[1]; + data += 2; + break; + case SP_CURVETO: + count++; + last[0] = data[4]; + last[1] = data[5]; + data += 6; + break; + case SP_RET: + case SP_RETCLOSEPATH: + stop = 1; + ready = 1; + break; + case SP_CLOSEPATH: + stop = 1; + break; + } + } while (!stop); + + if ((count>0) && last[0] == first[0] && last[1] == first[1]) meet = 1; + else meet = 0; + + /* is there more than 1 unique point ?*/ + + if (count - meet > 0) { + data = _data; + nu = (Nurb*)MEM_callocN(sizeof(struct Nurb),"objfnt_nurb"); + bezt = (BezTriple*)MEM_callocN((count)* sizeof(BezTriple),"objfnt_bezt") ; + if (nu != 0 && bezt != 0) { + BLI_addtail(&che->nurbsbase, nu); + nu->type= CU_BEZIER+CU_2D; + nu->pntsu = count; + nu->resolu= 8; + nu->flagu= 1; + nu->bezt = bezt; + stop = 0; + + /* read points */ + do { + switch(*data++){ + case SP_MOVETO: + bezt->vec[1][0] = scale * *data++; + bezt->vec[1][1] = scale * *data++; + + break; + case SP_LINETO: + bez2 = bezt++; + bezt->vec[1][0] = scale * *data++; + bezt->vec[1][1] = scale * *data++; + /* vector handles */ + bezt->h1= HD_VECT; + bez2->h2= HD_VECT; + dx = (bezt->vec[1][0] - bez2->vec[1][0]) / 3.0; + dy = (bezt->vec[1][1] - bez2->vec[1][1]) / 3.0; + bezt->vec[0][0] = bezt->vec[1][0] - dx; + bezt->vec[0][1] = bezt->vec[1][1] - dy; + bez2->vec[2][0] = bez2->vec[1][0] + dx; + bez2->vec[2][1] = bez2->vec[1][1] + dy; + break; + + case SP_CURVETO: + bezt->vec[2][0] = scale * *data++; + bezt->vec[2][1] = scale * *data++; + bezt->h2= HD_ALIGN; + bezt++; + bezt->vec[0][0] = scale * *data++; + bezt->vec[0][1] = scale * *data++; + bezt->vec[1][0] = scale * *data++; + bezt->vec[1][1] = scale * *data++; + bezt->h1= HD_ALIGN; + break; + + case SP_RET: + case SP_RETCLOSEPATH: + stop = 1; + ready = 1; + break; + case SP_CLOSEPATH: + stop = 1; + break; + } + } while (stop == 0); + + if (meet) { + /* copy handles */ + nu->bezt->vec[0][0] = bezt->vec[0][0]; + nu->bezt->vec[0][1] = bezt->vec[0][1]; + /* and forget last point */ + nu->pntsu--; + } + else { + /* vector handles */ + bez2 = nu->bezt; + dx = (bezt->vec[1][0] - bez2->vec[1][0]) / 3.0; + dy = (bezt->vec[1][1] - bez2->vec[1][1]) / 3.0; + bezt->vec[2][0] = bezt->vec[1][0] - dx; + bezt->vec[2][1] = bezt->vec[1][1] - dy; + bez2->vec[0][0] = bez2->vec[1][0] + dx; + bez2->vec[0][1] = bez2->vec[1][1] + dy; + bezt->h2= bez2->h1= HD_VECT; + } + + /* forbidden handle combinations */ + a= nu->pntsu; + bezt= nu->bezt; + while(a--) { + if(bezt->h1!=HD_ALIGN && bezt->h2==HD_ALIGN) bezt->h2= 0; + else if(bezt->h2!=HD_ALIGN && bezt->h1==HD_ALIGN) bezt->h1= 0; + bezt++; + } + + } + else { + if (nu) MEM_freeN(nu); + if (bezt) MEM_freeN(bezt); + } + } + _data = data; + } while (ready == 0); + } + } + + return vfd; +} + +VFontData *BLI_vfontdata_from_psfont(PackedFile *pf) +{ + objfnt *fnt= objfnt_from_psfont(pf); + VFontData *vfd= NULL; + + if (fnt) { + vfd= objfnt_to_vfontdata(fnt); + freeobjfnt(fnt); + } + + return vfd; +} diff --git a/source/blender/blenlib/intern/rand.c b/source/blender/blenlib/intern/rand.c new file mode 100644 index 00000000000..df01288aab8 --- /dev/null +++ b/source/blender/blenlib/intern/rand.c @@ -0,0 +1,192 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include + +#include "MEM_guardedalloc.h" + +#include "PIL_time.h" + +#include "BLI_threads.h" +#include "BLI_rand.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(WIN32) && !defined(FREE_WINDOWS) +typedef unsigned __int64 r_uint64; + +#define MULTIPLIER 0x5DEECE66Di64 +#define MASK 0x0000FFFFFFFFFFFFi64 +#else +typedef unsigned long long r_uint64; + +#define MULTIPLIER 0x5DEECE66Dll +#define MASK 0x0000FFFFFFFFFFFFll +#endif + +#define ADDEND 0xB + +#define LOWSEED 0x330E + +/***/ + +struct RNG { + r_uint64 X; +}; + +RNG *rng_new(unsigned int seed) +{ + RNG *rng = MEM_mallocN(sizeof(*rng), "rng"); + + rng_seed(rng, seed); + + return rng; +} + +void rng_free(RNG* rng) +{ + MEM_freeN(rng); +} + +void rng_seed(RNG *rng, unsigned int seed) { + rng->X= (((r_uint64) seed)<<16) | LOWSEED; +} + +int rng_getInt(RNG *rng) { + rng->X= (MULTIPLIER*rng->X + ADDEND)&MASK; + return (int) (rng->X>>17); +} + +double rng_getDouble(RNG *rng) { + return (double) rng_getInt(rng)/0x80000000; +} + +float rng_getFloat(RNG *rng) { + return (float) rng_getInt(rng)/0x80000000; +} + +void rng_shuffleArray(RNG *rng, void *data, int elemSize, int numElems) +{ + int i = numElems; + void *temp = malloc(elemSize); + + while (--i) { + int j = rng_getInt(rng)%numElems; + if(i!=j) { + void *iElem = (unsigned char*)data + i*elemSize; + void *jElem = (unsigned char*)data + j*elemSize; + memcpy(temp, iElem, elemSize); + memcpy(iElem, jElem, elemSize); + memcpy(jElem, temp, elemSize); + } + } + + free(temp); +} + +/***/ + +static RNG theBLI_rng = {0}; + +/* note, this one creates periodical patterns */ +void BLI_srand(unsigned int seed) { + rng_seed(&theBLI_rng, seed); +} + +/* using hash table to create better seed */ +void BLI_srandom(unsigned int seed) { + extern unsigned char hash[]; // noise.c + + rng_seed(&theBLI_rng, seed + hash[seed & 255]); + seed= rng_getInt(&theBLI_rng); + rng_seed(&theBLI_rng, seed + hash[seed & 255]); + seed= rng_getInt(&theBLI_rng); + rng_seed(&theBLI_rng, seed + hash[seed & 255]); +} + +int BLI_rand(void) { + return rng_getInt(&theBLI_rng); +} + +double BLI_drand(void) { + return rng_getDouble(&theBLI_rng); +} + +float BLI_frand(void) { + return rng_getFloat(&theBLI_rng); +} + +void BLI_fillrand(void *addr, int len) { + RNG rng; + unsigned char *p= addr; + + rng_seed(&rng, (unsigned int) (PIL_check_seconds_timer()*0x7FFFFFFF)); + while (len--) *p++= rng_getInt(&rng)&0xFF; +} + +void BLI_array_randomize(void *data, int elemSize, int numElems, unsigned int seed) +{ + RNG rng; + + rng_seed(&rng, seed); + rng_shuffleArray(&rng, data, elemSize, numElems); +} + +/* ********* for threaded random ************** */ + +static RNG rng_tab[BLENDER_MAX_THREADS]; + +void BLI_thread_srandom(int thread, unsigned int seed) +{ + extern unsigned char hash[]; // noise.c + + if(thread >= BLENDER_MAX_THREADS) + thread= 0; + + rng_seed(&rng_tab[thread], seed + hash[seed & 255]); + seed= rng_getInt(&rng_tab[thread]); + rng_seed(&rng_tab[thread], seed + hash[seed & 255]); + seed= rng_getInt(&rng_tab[thread]); + rng_seed(&rng_tab[thread], seed + hash[seed & 255]); +} + +int BLI_thread_rand(int thread) { + return rng_getInt(&rng_tab[thread]); +} + +float BLI_thread_frand(int thread) { + return rng_getFloat(&rng_tab[thread]); +} + diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c new file mode 100644 index 00000000000..60d96922544 --- /dev/null +++ b/source/blender/blenlib/intern/rct.c @@ -0,0 +1,171 @@ +/* + * + * rct.c + * + * april 95 + * + * $Id$ + * + * A minimalist lib for functions doing stuff with rectangle structs. + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + */ + +#include "DNA_vec_types.h" +#include "BLI_blenlib.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +int BLI_rcti_is_empty(rcti * rect) +{ + return ((rect->xmax<=rect->xmin) || + (rect->ymax<=rect->ymin)); +} + +int BLI_in_rcti(rcti * rect, int x, int y) +{ + + if(xxmin) return 0; + if(x>rect->xmax) return 0; + if(yymin) return 0; + if(y>rect->ymax) return 0; + return 1; +} + +int BLI_in_rctf(rctf *rect, float x, float y) +{ + + if(xxmin) return 0; + if(x>rect->xmax) return 0; + if(yymin) return 0; + if(y>rect->ymax) return 0; + return 1; +} + +void BLI_union_rctf(rctf *rct1, rctf *rct2) +{ + + if(rct1->xmin>rct2->xmin) rct1->xmin= rct2->xmin; + if(rct1->xmaxxmax) rct1->xmax= rct2->xmax; + if(rct1->ymin>rct2->ymin) rct1->ymin= rct2->ymin; + if(rct1->ymaxymax) rct1->ymax= rct2->ymax; +} + +void BLI_init_rctf(rctf *rect, float xmin, float xmax, float ymin, float ymax) +{ + rect->xmin= xmin; + rect->xmax= xmax; + rect->ymin= ymin; + rect->ymax= ymax; +} +void BLI_init_rcti(rcti *rect, int xmin, int xmax, int ymin, int ymax) +{ + rect->xmin= xmin; + rect->xmax= xmax; + rect->ymin= ymin; + rect->ymax= ymax; +} + +void BLI_translate_rcti(rcti *rect, int x, int y) +{ + rect->xmin += x; + rect->ymin += y; + rect->xmax += x; + rect->ymax += y; +} +void BLI_translate_rctf(rctf *rect, float x, float y) +{ + rect->xmin += x; + rect->ymin += y; + rect->xmax += x; + rect->ymax += y; +} + +int BLI_isect_rctf(rctf *src1, rctf *src2, rctf *dest) +{ + float xmin, xmax; + float ymin, ymax; + + xmin = (src1->xmin) > (src2->xmin) ? (src1->xmin) : (src2->xmin); + xmax = (src1->xmax) < (src2->xmax) ? (src1->xmax) : (src2->xmax); + ymin = (src1->ymin) > (src2->ymin) ? (src1->ymin) : (src2->ymin); + ymax = (src1->ymax) < (src2->ymax) ? (src1->ymax) : (src2->ymax); + + if(xmax>=xmin && ymax>=ymin) { + if(dest) { + dest->xmin = xmin; + dest->xmax = xmax; + dest->ymin = ymin; + dest->ymax = ymax; + } + return 1; + } + else { + if(dest) { + dest->xmin = 0; + dest->xmax = 0; + dest->ymin = 0; + dest->ymax = 0; + } + return 0; + } +} + +int BLI_isect_rcti(rcti *src1, rcti *src2, rcti *dest) +{ + int xmin, xmax; + int ymin, ymax; + + xmin = (src1->xmin) > (src2->xmin) ? (src1->xmin) : (src2->xmin); + xmax = (src1->xmax) < (src2->xmax) ? (src1->xmax) : (src2->xmax); + ymin = (src1->ymin) > (src2->ymin) ? (src1->ymin) : (src2->ymin); + ymax = (src1->ymax) < (src2->ymax) ? (src1->ymax) : (src2->ymax); + + if(xmax>=xmin && ymax>=ymin) { + if(dest) { + dest->xmin = xmin; + dest->xmax = xmax; + dest->ymin = ymin; + dest->ymax = ymax; + } + return 1; + } + else { + if(dest) { + dest->xmin = 0; + dest->xmax = 0; + dest->ymin = 0; + dest->ymax = 0; + } + return 0; + } +} diff --git a/source/blender/blenlib/intern/scanfill.c b/source/blender/blenlib/intern/scanfill.c new file mode 100644 index 00000000000..3c0770e5e07 --- /dev/null +++ b/source/blender/blenlib/intern/scanfill.c @@ -0,0 +1,1056 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * (uit traces) maart 95 + */ + +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" + +#include "BLI_util.h" +#include "DNA_listBase.h" +#include "DNA_mesh_types.h" +#include "BLI_editVert.h" +#include "BLI_arithb.h" +#include "BLI_scanfill.h" +#include "BLI_callbacks.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +/* callbacks for errors and interrupts and some goo */ +static void (*BLI_localErrorCallBack)(char*) = NULL; +static int (*BLI_localInterruptCallBack)(void) = NULL; + +void BLI_setErrorCallBack(void (*f)(char*)) +{ + BLI_localErrorCallBack = f; +} + +void BLI_setInterruptCallBack(int (*f)(void)) +{ + BLI_localInterruptCallBack = f; +} + +/* just flush the error to /dev/null if the error handler is missing */ +void callLocalErrorCallBack(char* msg) +{ + if (BLI_localErrorCallBack) { + BLI_localErrorCallBack(msg); + } +} + +#if 0 +/* ignore if the interrupt wasn't set */ +static int callLocalInterruptCallBack(void) +{ + if (BLI_localInterruptCallBack) { + return BLI_localInterruptCallBack(); + } else { + return 0; + } +} +#endif + +/* local types */ +typedef struct PolyFill { + int edges,verts; + float min[3],max[3]; + short f,nr; +} PolyFill; + +typedef struct ScFillVert { + EditVert *v1; + EditEdge *first,*last; + short f,f1; +} ScFillVert; + + +/* local funcs */ + +#define COMPLIMIT 0.00003 + +static ScFillVert *scdata; + +ListBase fillvertbase = {0,0}; +ListBase filledgebase = {0,0}; +ListBase fillfacebase = {0,0}; + +static short cox, coy; + +/* **** FUBCTIONS FOR QSORT *************************** */ + + +static int vergscdata(const void *a1, const void *a2) +{ + const ScFillVert *x1=a1,*x2=a2; + + if( x1->v1->co[coy] < x2->v1->co[coy] ) return 1; + else if( x1->v1->co[coy] > x2->v1->co[coy]) return -1; + else if( x1->v1->co[cox] > x2->v1->co[cox] ) return 1; + else if( x1->v1->co[cox] < x2->v1->co[cox]) return -1; + + return 0; +} + +static int vergpoly(const void *a1, const void *a2) +{ + const PolyFill *x1=a1, *x2=a2; + + if( x1->min[cox] > x2->min[cox] ) return 1; + else if( x1->min[cox] < x2->min[cox] ) return -1; + else if( x1->min[coy] > x2->min[coy] ) return 1; + else if( x1->min[coy] < x2->min[coy] ) return -1; + + return 0; +} + +/* ************* MEMORY MANAGEMENT ************* */ + +struct mem_elements { + struct mem_elements *next, *prev; + char *data; +}; + + +/* simple optimization for allocating thousands of small memory blocks + only to be used within loops, and not by one function at a time + free in the end, with argument '-1' +*/ + +static void *new_mem_element(int size) +{ + int blocksize= 16384; + static int offs= 0; /* the current free adress */ + static struct mem_elements *cur= 0; + static ListBase lb= {0, 0}; + void *adr; + + if(size>10000 || size==0) { + printf("incorrect use of new_mem_element\n"); + } + else if(size== -1) { + cur= lb.first; + while(cur) { + MEM_freeN(cur->data); + cur= cur->next; + } + BLI_freelistN(&lb); + + return NULL; + } + + size= 4*( (size+3)/4 ); + + if(cur) { + if(size+offs < blocksize) { + adr= (void *) (cur->data+offs); + offs+= size; + return adr; + } + } + + cur= MEM_callocN( sizeof(struct mem_elements), "newmem"); + cur->data= MEM_callocN(blocksize, "newmem"); + BLI_addtail(&lb, cur); + + offs= size; + return cur->data; +} + +void BLI_end_edgefill(void) +{ + new_mem_element(-1); + + fillvertbase.first= fillvertbase.last= 0; + filledgebase.first= filledgebase.last= 0; + fillfacebase.first= fillfacebase.last= 0; +} + +/* **** FILL ROUTINES *************************** */ + +EditVert *BLI_addfillvert(float *vec) +{ + EditVert *eve; + + eve= new_mem_element(sizeof(EditVert)); + BLI_addtail(&fillvertbase, eve); + + eve->co[0] = vec[0]; + eve->co[1] = vec[1]; + eve->co[2] = vec[2]; + + return eve; +} + +EditEdge *BLI_addfilledge(EditVert *v1, EditVert *v2) +{ + EditEdge *newed; + + newed= new_mem_element(sizeof(EditEdge)); + BLI_addtail(&filledgebase, newed); + + newed->v1= v1; + newed->v2= v2; + + return newed; +} + +static void addfillface(EditVert *v1, EditVert *v2, EditVert *v3, int mat_nr) +{ + /* does not make edges */ + EditFace *evl; + + evl= new_mem_element(sizeof(EditFace)); + BLI_addtail(&fillfacebase, evl); + + evl->v1= v1; + evl->v2= v2; + evl->v3= v3; + evl->f= 2; + evl->mat_nr= mat_nr; +} + +static int boundisect(PolyFill *pf2, PolyFill *pf1) +{ + /* has pf2 been touched (intersected) by pf1 ? with bounding box */ + /* test first if polys exist */ + + if(pf1->edges==0 || pf2->edges==0) return 0; + + if(pf2->max[cox] < pf1->min[cox] ) return 0; + if(pf2->max[coy] < pf1->min[coy] ) return 0; + + if(pf2->min[cox] > pf1->max[cox] ) return 0; + if(pf2->min[coy] > pf1->max[coy] ) return 0; + + /* join */ + if(pf2->max[cox]max[cox]) pf2->max[cox]= pf1->max[cox]; + if(pf2->max[coy]max[coy]) pf2->max[coy]= pf1->max[coy]; + + if(pf2->min[cox]>pf1->min[cox]) pf2->min[cox]= pf1->min[cox]; + if(pf2->min[coy]>pf1->min[coy]) pf2->min[coy]= pf1->min[coy]; + + return 1; +} + + +static void mergepolysSimp(PolyFill *pf1, PolyFill *pf2) /* add pf2 to pf1 */ +{ + EditVert *eve; + EditEdge *eed; + + /* replace old poly numbers */ + eve= fillvertbase.first; + while(eve) { + if(eve->xs== pf2->nr) eve->xs= pf1->nr; + eve= eve->next; + } + eed= filledgebase.first; + while(eed) { + if(eed->f1== pf2->nr) eed->f1= pf1->nr; + eed= eed->next; + } + + pf1->verts+= pf2->verts; + pf1->edges+= pf2->edges; + pf2->verts= pf2->edges= 0; + pf1->f= (pf1->f | pf2->f); +} + +static short testedgeside(float *v1, float *v2, float *v3) +/* is v3 to the right of v1-v2 ? With exception: v3==v1 || v3==v2 */ +{ + float inp; + + inp= (v2[cox]-v1[cox])*(v1[coy]-v3[coy]) + +(v1[coy]-v2[coy])*(v1[cox]-v3[cox]); + + if(inp<0.0) return 0; + else if(inp==0) { + if(v1[cox]==v3[cox] && v1[coy]==v3[coy]) return 0; + if(v2[cox]==v3[cox] && v2[coy]==v3[coy]) return 0; + } + return 1; +} + +static short addedgetoscanvert(ScFillVert *sc, EditEdge *eed) +{ + /* find first edge to the right of eed, and insert eed before that */ + EditEdge *ed; + float fac,fac1,x,y; + + if(sc->first==0) { + sc->first= sc->last= eed; + eed->prev= eed->next=0; + return 1; + } + + x= eed->v1->co[cox]; + y= eed->v1->co[coy]; + + fac1= eed->v2->co[coy]-y; + if(fac1==0.0) { + fac1= 1.0e10*(eed->v2->co[cox]-x); + + } + else fac1= (x-eed->v2->co[cox])/fac1; + + ed= sc->first; + while(ed) { + + if(ed->v2==eed->v2) return 0; + + fac= ed->v2->co[coy]-y; + if(fac==0.0) { + fac= 1.0e10*(ed->v2->co[cox]-x); + + } + else fac= (x-ed->v2->co[cox])/fac; + if(fac>fac1) break; + + ed= ed->next; + } + if(ed) BLI_insertlinkbefore((ListBase *)&(sc->first), ed, eed); + else BLI_addtail((ListBase *)&(sc->first),eed); + + return 1; +} + + +static ScFillVert *addedgetoscanlist(EditEdge *eed, int len) +{ + /* inserts edge at correct location in ScFillVert list */ + /* returns sc when edge already exists */ + ScFillVert *sc,scsearch; + EditVert *eve; + + /* which vert is left-top? */ + if(eed->v1->co[coy] == eed->v2->co[coy]) { + if(eed->v1->co[cox] > eed->v2->co[cox]) { + eve= eed->v1; + eed->v1= eed->v2; + eed->v2= eve; + } + } + else if(eed->v1->co[coy] < eed->v2->co[coy]) { + eve= eed->v1; + eed->v1= eed->v2; + eed->v2= eve; + } + /* find location in list */ + scsearch.v1= eed->v1; + sc= (ScFillVert *)bsearch(&scsearch,scdata,len, + sizeof(ScFillVert), vergscdata); + + if(sc==0) printf("Error in search edge: %p\n",eed); + else if(addedgetoscanvert(sc,eed)==0) return sc; + + return 0; +} + +static short boundinsideEV(EditEdge *eed, EditVert *eve) +/* is eve inside boundbox eed */ +{ + float minx,maxx,miny,maxy; + + if(eed->v1->co[cox]v2->co[cox]) { + minx= eed->v1->co[cox]; + maxx= eed->v2->co[cox]; + } else { + minx= eed->v2->co[cox]; + maxx= eed->v1->co[cox]; + } + if(eve->co[cox]>=minx && eve->co[cox]<=maxx) { + if(eed->v1->co[coy]v2->co[coy]) { + miny= eed->v1->co[coy]; + maxy= eed->v2->co[coy]; + } else { + miny= eed->v2->co[coy]; + maxy= eed->v1->co[coy]; + } + if(eve->co[coy]>=miny && eve->co[coy]<=maxy) return 1; + } + return 0; +} + + +static void testvertexnearedge(void) +{ + /* only vertices with ->h==1 are being tested for + being close to an edge, if true insert */ + + EditVert *eve; + EditEdge *eed,*ed1; + float dist,vec1[2],vec2[2],vec3[2]; + + eve= fillvertbase.first; + while(eve) { + if(eve->h==1) { + vec3[0]= eve->co[cox]; + vec3[1]= eve->co[coy]; + /* find the edge which has vertex eve */ + ed1= filledgebase.first; + while(ed1) { + if(ed1->v1==eve || ed1->v2==eve) break; + ed1= ed1->next; + } + if(ed1->v1==eve) { + ed1->v1= ed1->v2; + ed1->v2= eve; + } + eed= filledgebase.first; + while(eed) { + if(eve!=eed->v1 && eve!=eed->v2 && eve->xs==eed->f1) { + if(FloatCompare(eve->co,eed->v1->co, COMPLIMIT)) { + ed1->v2= eed->v1; + eed->v1->h++; + eve->h= 0; + break; + } + else if(FloatCompare(eve->co,eed->v2->co, COMPLIMIT)) { + ed1->v2= eed->v2; + eed->v2->h++; + eve->h= 0; + break; + } + else { + vec1[0]= eed->v1->co[cox]; + vec1[1]= eed->v1->co[coy]; + vec2[0]= eed->v2->co[cox]; + vec2[1]= eed->v2->co[coy]; + if(boundinsideEV(eed,eve)) { + dist= DistVL2Dfl(vec1,vec2,vec3); + if(distv1, eve); + + /* printf("fill: vertex near edge %x\n",eve); */ + ed1->f= ed1->h= 0; + ed1->f1= eed->f1; + eed->v1= eve; + eve->h= 3; + break; + } + } + } + } + eed= eed->next; + } + } + eve= eve->next; + } +} + +static void splitlist(ListBase *tempve, ListBase *temped, short nr) +{ + /* everything is in templist, write only poly nr to fillist */ + EditVert *eve,*nextve; + EditEdge *eed,*nexted; + + addlisttolist(tempve,&fillvertbase); + addlisttolist(temped,&filledgebase); + + eve= tempve->first; + while(eve) { + nextve= eve->next; + if(eve->xs==nr) { + BLI_remlink(tempve,eve); + BLI_addtail(&fillvertbase,eve); + } + eve= nextve; + } + eed= temped->first; + while(eed) { + nexted= eed->next; + if(eed->f1==nr) { + BLI_remlink(temped,eed); + BLI_addtail(&filledgebase,eed); + } + eed= nexted; + } +} + + +static void scanfill(PolyFill *pf, int mat_nr) +{ + ScFillVert *sc = NULL, *sc1; + EditVert *eve,*v1,*v2,*v3; + EditEdge *eed,*nexted,*ed1,*ed2,*ed3; + float miny = 0.0; + int a,b,verts, maxface, totface; + short nr, test, twoconnected=0; + + nr= pf->nr; + verts= pf->verts; + + /* PRINTS + eve= fillvertbase.first; + while(eve) { + printf("vert: %x co: %f %f\n",eve,eve->co[cox],eve->co[coy]); + eve= eve->next; + } + eed= filledgebase.first; + while(eed) { + printf("edge: %x verts: %x %x\n",eed,eed->v1,eed->v2); + eed= eed->next; + } */ + + /* STEP 0: remove zero sized edges */ + eed= filledgebase.first; + while(eed) { + if(eed->v1->co[cox]==eed->v2->co[cox]) { + if(eed->v1->co[coy]==eed->v2->co[coy]) { + if(eed->v1->f==255 && eed->v2->f!=255) { + eed->v2->f= 255; + eed->v2->tmp.v= eed->v1->tmp.v; + } + else if(eed->v2->f==255 && eed->v1->f!=255) { + eed->v1->f= 255; + eed->v1->tmp.v= eed->v2->tmp.v; + } + else if(eed->v2->f==255 && eed->v1->f==255) { + eed->v1->tmp.v= eed->v2->tmp.v; + } + else { + eed->v2->f= 255; + eed->v2->tmp.v = eed->v1->tmp.v; + } + } + } + eed= eed->next; + } + + /* STEP 1: make using FillVert and FillEdge lists a sorted + ScFillVert list + */ + sc= scdata= (ScFillVert *)MEM_callocN(pf->verts*sizeof(ScFillVert),"Scanfill1"); + eve= fillvertbase.first; + verts= 0; + while(eve) { + if(eve->xs==nr) { + if(eve->f!= 255) { + verts++; + eve->f= 0; /* flag for connectedges later on */ + sc->v1= eve; + sc++; + } + } + eve= eve->next; + } + + qsort(scdata, verts, sizeof(ScFillVert), vergscdata); + + sc= scdata; + eed= filledgebase.first; + while(eed) { + nexted= eed->next; + eed->f= 0; + BLI_remlink(&filledgebase,eed); +/* commented all of this out, this I have no idea for what it is for, probably from ancient past */ +/* it does crash blender, since it uses mixed original and new vertices (ton) */ +// if(eed->v1->f==255) { +// v1= eed->v1; +// while((eed->v1->f == 255) && (eed->v1->tmp.v != v1)) +// eed->v1 = eed->v1->tmp.v; +// } +// if(eed->v2->f==255) { +// v2= eed->v2; +// while((eed->v2->f == 255) && (eed->v2->tmp.v != v2)) +// eed->v2 = eed->v2->tmp.v; +// } + if(eed->v1!=eed->v2) addedgetoscanlist(eed,verts); + + eed= nexted; + } + /* + sc= scdata; + for(a=0;av1); + eed= sc->first; + while(eed) { + printf(" ed %x %x %x\n",eed,eed->v1,eed->v2); + eed= eed->next; + } + sc++; + }*/ + + + /* STEP 2: FILL LOOP */ + + if(pf->f==0) twoconnected= 1; + + /* (temporal) security: never much more faces than vertices */ + totface= 0; + maxface= 2*verts; /* 2*verts: based at a filled circle within a triangle */ + + sc= scdata; + for(a=0;av1); */ + ed1= sc->first; + while(ed1) { /* set connectflags */ + nexted= ed1->next; + if(ed1->v1->h==1 || ed1->v2->h==1) { + BLI_remlink((ListBase *)&(sc->first),ed1); + BLI_addtail(&filledgebase,ed1); + if(ed1->v1->h>1) ed1->v1->h--; + if(ed1->v2->h>1) ed1->v2->h--; + } + else ed1->v2->f= 1; + + ed1= nexted; + } + while(sc->first) { /* for as long there are edges */ + ed1= sc->first; + ed2= ed1->next; + + /* commented out... the ESC here delivers corrupted memory (and doesnt work during grab) */ + /* if(callLocalInterruptCallBack()) break; */ + if(totface>maxface) { + /* printf("Fill error: endless loop. Escaped at vert %d, tot: %d.\n", a, verts); */ + a= verts; + break; + } + if(ed2==0) { + sc->first=sc->last= 0; + /* printf("just 1 edge to vert\n"); */ + BLI_addtail(&filledgebase,ed1); + ed1->v2->f= 0; + ed1->v1->h--; + ed1->v2->h--; + } else { + /* test rest of vertices */ + v1= ed1->v2; + v2= ed1->v1; + v3= ed2->v2; + /* this happens with a serial of overlapping edges */ + if(v1==v2 || v2==v3) break; + /* printf("test verts %x %x %x\n",v1,v2,v3); */ + miny = ( (v1->co[coy])<(v3->co[coy]) ? (v1->co[coy]) : (v3->co[coy]) ); + /* miny= MIN2(v1->co[coy],v3->co[coy]); */ + sc1= sc+1; + test= 0; + + for(b=a+1;bv1->f==0) { + if(sc1->v1->co[coy] <= miny) break; + + if(testedgeside(v1->co,v2->co,sc1->v1->co)) + if(testedgeside(v2->co,v3->co,sc1->v1->co)) + if(testedgeside(v3->co,v1->co,sc1->v1->co)) { + /* point in triangle */ + + test= 1; + break; + } + } + sc1++; + } + if(test) { + /* make new edge, and start over */ + /* printf("add new edge %x %x and start again\n",v2,sc1->v1); */ + + ed3= BLI_addfilledge(v2, sc1->v1); + BLI_remlink(&filledgebase, ed3); + BLI_insertlinkbefore((ListBase *)&(sc->first), ed2, ed3); + ed3->v2->f= 1; + ed3->f= 2; + ed3->v1->h++; + ed3->v2->h++; + } + else { + /* new triangle */ + /* printf("add face %x %x %x\n",v1,v2,v3); */ + addfillface(v1, v2, v3, mat_nr); + totface++; + BLI_remlink((ListBase *)&(sc->first),ed1); + BLI_addtail(&filledgebase,ed1); + ed1->v2->f= 0; + ed1->v1->h--; + ed1->v2->h--; + /* ed2 can be removed when it's an old one */ + if(ed2->f==0 && twoconnected) { + BLI_remlink((ListBase *)&(sc->first),ed2); + BLI_addtail(&filledgebase,ed2); + ed2->v2->f= 0; + ed2->v1->h--; + ed2->v2->h--; + } + + /* new edge */ + ed3= BLI_addfilledge(v1, v3); + BLI_remlink(&filledgebase, ed3); + ed3->f= 2; + ed3->v1->h++; + ed3->v2->h++; + + /* printf("add new edge %x %x\n",v1,v3); */ + sc1= addedgetoscanlist(ed3, verts); + + if(sc1) { /* ed3 already exists: remove */ + /* printf("Edge exists\n"); */ + ed3->v1->h--; + ed3->v2->h--; + + if(twoconnected) ed3= sc1->first; + else ed3= 0; + while(ed3) { + if( (ed3->v1==v1 && ed3->v2==v3) || (ed3->v1==v3 && ed3->v2==v1) ) { + BLI_remlink((ListBase *)&(sc1->first),ed3); + BLI_addtail(&filledgebase,ed3); + ed3->v1->h--; + ed3->v2->h--; + break; + } + ed3= ed3->next; + } + } + + } + } + /* test for loose edges */ + ed1= sc->first; + while(ed1) { + nexted= ed1->next; + if(ed1->v1->h<2 || ed1->v2->h<2) { + BLI_remlink((ListBase *)&(sc->first),ed1); + BLI_addtail(&filledgebase,ed1); + if(ed1->v1->h>1) ed1->v1->h--; + if(ed1->v2->h>1) ed1->v2->h--; + } + + ed1= nexted; + } + } + sc++; + } + + MEM_freeN(scdata); +} + + + +int BLI_edgefill(int mode, int mat_nr) +{ + /* + - fill works with its own lists, so create that first (no faces!) + - for vertices, put in ->tmp.v the old pointer + - struct elements xs en ys are not used here: don't hide stuff in it + - edge flag ->f becomes 2 when it's a new edge + - mode: & 1 is check for crossings, then create edges (TO DO ) + */ + ListBase tempve, temped; + EditVert *eve; + EditEdge *eed,*nexted; + PolyFill *pflist,*pf; + float *minp, *maxp, *v1, *v2, norm[3], len; + short a,c,poly=0,ok=0,toggle=0; + + /* reset variables */ + eve= fillvertbase.first; + while(eve) { + eve->f= 0; + eve->xs= 0; + eve->h= 0; + eve= eve->next; + } + + /* first test vertices if they are in edges */ + /* including resetting of flags */ + eed= filledgebase.first; + while(eed) { + eed->f= eed->f1= eed->h= 0; + eed->v1->f= 1; + eed->v2->f= 1; + + eed= eed->next; + } + + eve= fillvertbase.first; + while(eve) { + if(eve->f & 1) { + ok=1; + break; + } + eve= eve->next; + } + + if(ok==0) return 0; + + /* NEW NEW! define projection: with 'best' normal */ + /* just use the first three different vertices */ + + /* THIS PART STILL IS PRETTY WEAK! (ton) */ + + eve= fillvertbase.last; + len= 0.0; + v1= eve->co; + v2= 0; + eve= fillvertbase.first; + while(eve) { + if(v2) { + if( FloatCompare(v2, eve->co, COMPLIMIT)==0) { + len= CalcNormFloat(v1, v2, eve->co, norm); + if(len != 0.0) break; + } + } + else if(FloatCompare(v1, eve->co, COMPLIMIT)==0) { + v2= eve->co; + } + eve= eve->next; + } + + if(len==0.0) return 0; /* no fill possible */ + + norm[0]= fabs(norm[0]); + norm[1]= fabs(norm[1]); + norm[2]= fabs(norm[2]); + + if(norm[2]>=norm[0] && norm[2]>=norm[1]) { + cox= 0; coy= 1; + } + else if(norm[1]>=norm[0] && norm[1]>=norm[2]) { + cox= 0; coy= 2; + } + else { + cox= 1; coy= 2; + } + + /* STEP 1: COUNT POLYS */ + eve= fillvertbase.first; + while(eve) { + /* get first vertex with no poly number */ + if(eve->xs==0) { + poly++; + /* now a sortof select connected */ + ok= 1; + eve->xs= poly; + + while(ok) { + + ok= 0; + toggle++; + if(toggle & 1) eed= filledgebase.first; + else eed= filledgebase.last; + + while(eed) { + if(eed->v1->xs==0 && eed->v2->xs==poly) { + eed->v1->xs= poly; + eed->f1= poly; + ok= 1; + } + else if(eed->v2->xs==0 && eed->v1->xs==poly) { + eed->v2->xs= poly; + eed->f1= poly; + ok= 1; + } + else if(eed->f1==0) { + if(eed->v1->xs==poly && eed->v2->xs==poly) { + eed->f1= poly; + ok= 1; + } + } + if(toggle & 1) eed= eed->next; + else eed= eed->prev; + } + } + } + eve= eve->next; + } + /* printf("amount of poly's: %d\n",poly); */ + + /* STEP 2: remove loose edges and strings of edges */ + eed= filledgebase.first; + while(eed) { + if(eed->v1->h++ >250) break; + if(eed->v2->h++ >250) break; + eed= eed->next; + } + if(eed) { + /* otherwise it's impossible to be sure you can clear vertices */ + callLocalErrorCallBack("No vertices with 250 edges allowed!"); + return 0; + } + + /* does it only for vertices with ->h==1 */ + testvertexnearedge(); + + ok= 1; + while(ok) { + ok= 0; + toggle++; + if(toggle & 1) eed= filledgebase.first; + else eed= filledgebase.last; + while(eed) { + if(toggle & 1) nexted= eed->next; + else nexted= eed->prev; + if(eed->v1->h==1) { + eed->v2->h--; + BLI_remlink(&fillvertbase,eed->v1); + BLI_remlink(&filledgebase,eed); + ok= 1; + } + else if(eed->v2->h==1) { + eed->v1->h--; + BLI_remlink(&fillvertbase,eed->v2); + BLI_remlink(&filledgebase,eed); + ok= 1; + } + eed= nexted; + } + } + if(filledgebase.first==0) { + /* printf("All edges removed\n"); */ + return 0; + } + + + /* CURRENT STATUS: + - eve->f :1= availalble in edges + - eve->xs :polynumber + - eve->h :amount of edges connected to vertex + - eve->tmp.v :store! original vertex number + + - eed->f : + - eed->f1 :poly number + */ + + + /* STEP 3: MAKE POLYFILL STRUCT */ + pflist= (PolyFill *)MEM_callocN(poly*sizeof(PolyFill),"edgefill"); + pf= pflist; + for(a=1;a<=poly;a++) { + pf->nr= a; + pf->min[0]=pf->min[1]=pf->min[2]= 1.0e20; + pf->max[0]=pf->max[1]=pf->max[2]= -1.0e20; + pf++; + } + eed= filledgebase.first; + while(eed) { + pflist[eed->f1-1].edges++; + eed= eed->next; + } + + eve= fillvertbase.first; + while(eve) { + pflist[eve->xs-1].verts++; + minp= pflist[eve->xs-1].min; + maxp= pflist[eve->xs-1].max; + + minp[cox]= (minp[cox])<(eve->co[cox]) ? (minp[cox]) : (eve->co[cox]); + minp[coy]= (minp[coy])<(eve->co[coy]) ? (minp[coy]) : (eve->co[coy]); + maxp[cox]= (maxp[cox])>(eve->co[cox]) ? (maxp[cox]) : (eve->co[cox]); + maxp[coy]= (maxp[coy])>(eve->co[coy]) ? (maxp[coy]) : (eve->co[coy]); + if(eve->h>2) pflist[eve->xs-1].f= 1; + + eve= eve->next; + } + + /* STEP 4: FIND HOLES OR BOUNDS, JOIN THEM + * ( bounds just to divide it in pieces for optimization, + * the edgefill itself has good auto-hole detection) + * WATCH IT: ONLY WORKS WITH SORTED POLYS!!! */ + + if(poly>1) { + short *polycache, *pc; + + /* so, sort first */ + qsort(pflist, poly, sizeof(PolyFill), vergpoly); + + /*pf= pflist; + for(a=1;a<=poly;a++) { + printf("poly:%d edges:%d verts:%d flag: %d\n",a,pf->edges,pf->verts,pf->f); + PRINT2(f, f, pf->min[0], pf->min[1]); + pf++; + }*/ + + polycache= pc= MEM_callocN(sizeof(short)*poly, "polycache"); + pf= pflist; + for(a=0; amax[cox] < (pflist+c)->min[cox]) break; */ + + } + while(pc!=polycache) { + pc--; + mergepolysSimp(pf, pflist+ *pc); + } + } + MEM_freeN(polycache); + } + + pf= pflist; + /* printf("after merge\n"); + for(a=1;a<=poly;a++) { + printf("poly:%d edges:%d verts:%d flag: %d\n",a,pf->edges,pf->verts,pf->f); + pf++; + } */ + + /* STEP 5: MAKE TRIANGLES */ + + tempve.first= fillvertbase.first; + tempve.last= fillvertbase.last; + temped.first= filledgebase.first; + temped.last= filledgebase.last; + fillvertbase.first=fillvertbase.last= 0; + filledgebase.first=filledgebase.last= 0; + + pf= pflist; + for(a=0;aedges>1) { + splitlist(&tempve,&temped,pf->nr); + scanfill(pf, mat_nr); + } + pf++; + } + addlisttolist(&fillvertbase,&tempve); + addlisttolist(&filledgebase,&temped); + + /* FREE */ + + MEM_freeN(pflist); + return 1; + +} diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c new file mode 100644 index 00000000000..1d46679cbf2 --- /dev/null +++ b/source/blender/blenlib/intern/storage.c @@ -0,0 +1,540 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * Reorganised mar-01 nzc + * Some really low-level file thingies. + */ + +#include +#include +#include + +#ifdef WIN32 +#include "BLI_winstuff.h" +#include +#include +#include +#endif + +#ifndef WIN32 +#include +#endif + +#include +#include + +#if !defined(linux) && (defined(__sgi) || defined(__sun__) || defined(__sun) || defined(__sparc) || defined(__sparc__)) +#include +#endif + +#if defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__NetBSD__) +#include +#include +#endif + +#if defined(linux) || defined(__CYGWIN32__) || defined(__hpux) +#include +#endif + +#ifdef __BeOS +struct statfs { + int f_bsize; + int f_bfree; +}; +#endif + +#ifdef __APPLE__ +/* For statfs */ +#include +#include +#endif /* __APPLE__ */ + + +#include +#if !defined(__BeOS) && !defined(WIN32) +#include /* tape comando's */ +#endif +#include /* strcpy etc.. */ + +#ifndef WIN32 +#include +#include /* */ +#include +#endif + +#if !defined(__FreeBSD__) && !defined(__APPLE__) +#include +#endif + +/* lib includes */ +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" +#include "BLI_blenlib.h" +#include "BLI_storage.h" +#include "BLI_storage_types.h" + +#include "BLI_util.h" +#include "BLI_linklist.h" + +#include "BKE_utildefines.h" + +/* vars: */ +static int totnum,actnum; +static struct direntry *files; + +static struct ListBase dirbase_={ + 0,0}; +static struct ListBase *dirbase = &dirbase_; + + +char *BLI_getwdN(char *dir) +{ + char *pwd; + + if (dir) { + pwd = getenv("PWD"); + if (pwd){ + strcpy(dir, pwd); + return(dir); + } + /* 160 is FILE_MAXDIR in filesel.c */ + return( getcwd(dir, 160) ); + } + return(0); +} + + +int BLI_compare(struct direntry *entry1, struct direntry *entry2) +{ + /* type is equal to stat.st_mode */ + + if (S_ISDIR(entry1->type)){ + if (S_ISDIR(entry2->type)==0) return (-1); + } else{ + if (S_ISDIR(entry2->type)) return (1); + } + if (S_ISREG(entry1->type)){ + if (S_ISREG(entry2->type)==0) return (-1); + } else{ + if (S_ISREG(entry2->type)) return (1); + } + if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1); + if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1); + + /* make sure "." and ".." are always first */ + if( strcmp(entry1->relname, ".")==0 ) return (-1); + if( strcmp(entry2->relname, ".")==0 ) return (1); + if( strcmp(entry1->relname, "..")==0 ) return (-1); + + return (BLI_strcasecmp(entry1->relname,entry2->relname)); +} + + +double BLI_diskfree(char *dir) +{ +#ifdef WIN32 + DWORD sectorspc, bytesps, freec, clusters; + char tmp[4]; + + tmp[0]='\\'; tmp[1]=0; /* Just a failsafe */ + if (dir[0]=='/' || dir[0]=='\\') { + tmp[0]='\\'; + tmp[1]=0; + } else if (dir[1]==':') { + tmp[0]=dir[0]; + tmp[1]=':'; + tmp[2]='\\'; + tmp[3]=0; + } + + GetDiskFreeSpace(tmp,§orspc, &bytesps, &freec, &clusters); + + return (double) (freec*bytesps*sectorspc); +#else + struct statfs disk; + char name[FILE_MAXDIR],*slash; + int len = strlen(dir); + + if (len >= FILE_MAXDIR) /* path too long */ + return -1; + + strcpy(name,dir); + + if(len){ + slash = strrchr(name,'/'); + if (slash) slash[1] = 0; + } else strcpy(name,"/"); + +#if defined (__FreeBSD__) || defined (linux) || defined (__OpenBSD__) || defined (__APPLE__) + if (statfs(name, &disk)) return(-1); +#endif +#ifdef __BeOS + return -1; +#endif +#if !defined(linux) && (defined (__sgi) || defined (__sun__) || defined (__sun) || defined(__sparc) || defined(__sparc__)) + + if (statfs(name, &disk, sizeof(struct statfs), 0)){ + /* printf("diskfree: Couldn't get information about %s.\n",dir); */ + return(-1); + } +#endif + + return ( ((double) disk.f_bsize) * ((double) disk.f_bfree)); +#endif +} + +static int hide_dot= 0; + +void BLI_hide_dot_files(int set) +{ + if(set) hide_dot= 1; + else hide_dot= 0; +} + +void BLI_builddir(char *dirname, char *relname) +{ + struct dirent *fname; + struct dirlink *dlink; + int rellen, newnum = 0, seen_ = 0, seen__ = 0; + char buf[256]; + DIR *dir; + + strcpy(buf,relname); + rellen=strlen(relname); + + if (rellen){ + buf[rellen]='/'; + rellen++; + } + + if (chdir(dirname) == -1){ + perror(dirname); + return; + } + + if ( (dir = (DIR *)opendir(".")) ){ + while ((fname = (struct dirent*) readdir(dir)) != NULL) { + + if(hide_dot && fname->d_name[0]=='.' && fname->d_name[1]!='.' && fname->d_name[1]!=0); + else { + + dlink = (struct dirlink *)malloc(sizeof(struct dirlink)); + if (dlink){ + strcpy(buf+rellen,fname->d_name); + + dlink->name = BLI_strdup(buf); + + if (dlink->name[0] == '.') { + if (dlink->name[1] == 0) seen_ = 1; + else if (dlink->name[1] == '.') { + if (dlink->name[2] == 0) seen__ = 1; + } + } + BLI_addhead(dirbase,dlink); + newnum++; + } + } + } + + if (newnum){ +#ifndef WIN32 + if (seen_ == 0) { /* Cachefs PATCH */ + dlink = (struct dirlink *)malloc(sizeof(struct dirlink)); + strcpy(buf+rellen,"./."); + dlink->name = BLI_strdup(buf); + BLI_addhead(dirbase,dlink); + newnum++; + } + if (seen__ == 0) { /* MAC PATCH */ + dlink = (struct dirlink *)malloc(sizeof(struct dirlink)); + strcpy(buf+rellen,"./.."); + dlink->name = BLI_strdup(buf); + BLI_addhead(dirbase,dlink); + newnum++; + } +#else // WIN32 + if (seen_ == 0) { /* should only happen for root paths like "C:\" */ + dlink = (struct dirlink *)malloc(sizeof(struct dirlink)); + strcpy(buf+rellen,"."); + dlink->name = BLI_strdup(buf); + BLI_addhead(dirbase,dlink); + newnum++; + } +#endif + + if (files) files=(struct direntry *)realloc(files,(totnum+newnum) * sizeof(struct direntry)); + else files=(struct direntry *)malloc(newnum * sizeof(struct direntry)); + + if (files){ + dlink = (struct dirlink *) dirbase->first; + while(dlink){ + memset(&files[actnum], 0 , sizeof(struct direntry)); + files[actnum].relname = dlink->name; + stat(dlink->name,&files[actnum].s); + files[actnum].type=files[actnum].s.st_mode; + files[actnum].flags = 0; + totnum++; + actnum++; + dlink = dlink->next; + } + } else{ + printf("Couldn't get memory for dir\n"); + exit(1); + } + + BLI_freelist(dirbase); + if (files) qsort(files, actnum, sizeof(struct direntry), (int (*)(const void *,const void*))BLI_compare); + } else { + printf("%s empty directory\n",dirname); + } + + closedir(dir); + } else { + printf("%s non-existant directory\n",dirname); + } +} + +void BLI_adddirstrings() +{ + char datum[100]; + char buf[250]; + char size[250]; + static char * types[8] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"}; + int num, mode; + int num1, num2, num3, num4; +#ifdef WIN32 + __int64 st_size; +#else + long long st_size; +#endif + + struct direntry * file; + struct tm *tm; + time_t zero= 0; + + file = &files[0]; + + for(num=0;nummode1, types[0]); + strcpy(file->mode2, types[0]); + strcpy(file->mode3, types[0]); +#else + mode = file->s.st_mode; + + strcpy(file->mode1, types[(mode & 0700) >> 6]); + strcpy(file->mode2, types[(mode & 0070) >> 3]); + strcpy(file->mode3, types[(mode & 0007)]); + + if (((mode & S_ISGID) == S_ISGID) && (file->mode2[2]=='-'))file->mode2[2]='l'; + + if (mode & (S_ISUID | S_ISGID)){ + if (file->mode1[2]=='x') file->mode1[2]='s'; + else file->mode1[2]='S'; + + if (file->mode2[2]=='x')file->mode2[2]='s'; + } + + if (mode & S_ISVTX){ + if (file->mode3[2] == 'x') file->mode3[2] = 't'; + else file->mode3[2] = 'T'; + } +#endif + +#ifdef WIN32 + strcpy(files[num].owner,"user"); +#else + { + struct passwd *pwuser; + pwuser = getpwuid(files[num].s.st_uid); + if ( pwuser ) { + strcpy(files[num].owner, pwuser->pw_name); + } else { + sprintf(files[num].owner, "%d", files[num].s.st_uid); + } + } +#endif + + tm= localtime(&files[num].s.st_mtime); + // prevent impossible dates in windows + if(tm==NULL) tm= localtime(&zero); + strftime(files[num].time, 8, "%H:%M", tm); + strftime(files[num].date, 16, "%d-%b-%y", tm); + + /* + * Seems st_size is signed 32-bit value in *nix and Windows. This + * will buy us some time until files get bigger than 4GB or until + * everyone starts using __USE_FILE_OFFSET64 or equivalent. + */ + st_size= (unsigned int)files[num].s.st_size; + + num1= st_size % 1000; + num2= st_size/1000; + num2= num2 % 1000; + num3= st_size/(1000*1000); + num3= num3 % 1000; + num4= st_size/(1000*1000*1000); + num4= num4 % 1000; + + if(num4) sprintf(files[num].size, "%3d %03d %03d %03d", num4, num3, num2, num1); + else if(num3) sprintf(files[num].size, "%7d %03d %03d", num3, num2, num1); + else if(num2) sprintf(files[num].size, "%11d %03d", num2, num1); + else if(num1) sprintf(files[num].size, "%15d", num1); + else sprintf(files[num].size, "0"); + + strftime(datum, 32, "%d-%b-%y %H:%M", tm); + + if (st_size < 1000) { + sprintf(size, "%10d", (int) st_size); + } else if (st_size < 1000 * 1000) { + sprintf(size, "%6d %03d", (int) (st_size / 1000), (int) (st_size % 1000)); + } else if (st_size < 100 * 1000 * 1000) { + sprintf(size, "%2d %03d %03d", (int) (st_size / (1000 * 1000)), (int) ((st_size / 1000) % 1000), (int) ( st_size % 1000)); + } else { + sprintf(size, "> %4.1f M", (double) (st_size / (1024.0 * 1024.0))); + sprintf(size, "%10d", (int) st_size); + } + + sprintf(buf,"%s %s %10s %s", files[num].date, files[num].time, size, + files[num].relname); + + sprintf(buf,"%s %s %s %7s %s %s %10s %s", file->mode1, file->mode2, file->mode3, files[num].owner, files[num].date, files[num].time, size, + files[num].relname); + + files[num].string=MEM_mallocN(strlen(buf)+1, "filestring"); + if (files[num].string){ + strcpy(files[num].string,buf); + } + + file++; + } +} + +unsigned int BLI_getdir(char *dirname, struct direntry **filelist) +{ + // reset global variables + // memory stored in files is free()'d in + // filesel.c:freefilelist() + + actnum = totnum = 0; + files = 0; + + BLI_builddir(dirname,""); + BLI_adddirstrings(); + + if (files) { + *(filelist) = files; + } else { + // keep blender happy. Blender stores this in a variable + // where 0 has special meaning..... + *(filelist) = files = malloc(sizeof(struct direntry)); + } + + return(actnum); +} + + +int BLI_filesize(int file) +{ + struct stat buf; + + if (file <= 0) return (-1); + fstat(file, &buf); + return (buf.st_size); +} + + + +int BLI_exist(char *name) +{ + struct stat st; +#ifdef WIN32 + /* in Windows stat doesn't recognize dir ending on a slash + To not break code where the ending slash is expected we + don't mess with the argument name directly here - elubie */ + char tmp[FILE_MAXDIR+FILE_MAXFILE]; + int len; + BLI_strncpy(tmp, name, FILE_MAXDIR+FILE_MAXFILE); + len = strlen(tmp); + if (len > 3 && ( tmp[len-1]=='\\' || tmp[len-1]=='/') ) tmp[len-1] = '\0'; + if (stat(tmp,&st)) return(0); +#else + if (stat(name,&st)) return(0); +#endif + return(st.st_mode); +} + +LinkNode *BLI_read_file_as_lines(char *name) +{ + FILE *fp= fopen(name, "r"); + LinkNode *lines= NULL; + char *buf; + int size; + + if (!fp) return NULL; + + fseek(fp, 0, SEEK_END); + size= ftell(fp); + fseek(fp, 0, SEEK_SET); + + buf= malloc(size); + if (buf) { + int i, last= 0; + + /* + * size = because on win32 reading + * all the bytes in the file will return + * less bytes because of crnl changes. + */ + size= fread(buf, 1, size, fp); + for (i=0; i<=size; i++) { + if (i==size || buf[i]=='\n') { + char *line= BLI_strdupn(&buf[last], i-last); + + BLI_linklist_prepend(&lines, line); + last= i+1; + } + } + + free(buf); + } + + fclose(fp); + + BLI_linklist_reverse(&lines); + return lines; +} + +void BLI_free_file_lines(LinkNode *lines) +{ + BLI_linklist_free(lines, (void(*)(void*)) MEM_freeN); +} diff --git a/source/blender/blenlib/intern/threads.c b/source/blender/blenlib/intern/threads.c new file mode 100644 index 00000000000..cb10185386a --- /dev/null +++ b/source/blender/blenlib/intern/threads.c @@ -0,0 +1,221 @@ +/** + * + * $Id: + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_threads.h" + + +/* ********** basic thread control API ************ + +Many thread cases have an X amount of jobs, and only an Y amount of +threads are useful (typically amount of cpus) + +This code can be used to start a maximum amount of 'thread slots', which +then can be filled in a loop with an idle timer. + +A sample loop can look like this (pseudo c); + + ListBase lb; + int maxthreads= 2; + int cont= 1; + + BLI_init_threads(&lb, do_something_func, maxthreads); + + while(cont) { + if(BLI_available_threads(&lb) && !(escape loop event)) { + // get new job (data pointer) + // tag job 'processed + BLI_insert_thread(&lb, job); + } + else PIL_sleep_ms(50); + + // find if a job is ready, this the do_something_func() should write in job somewhere + cont= 0; + for(go over all jobs) + if(job is ready) { + if(job was not removed) { + BLI_remove_thread(&lb, job); + } + } + else cont= 1; + } + // conditions to exit loop + if(if escape loop event) { + if(BLI_available_threadslots(&lb)==maxthreads) + break; + } + } + + BLI_end_threads(&lb); + + ************************************************ */ +static pthread_mutex_t _malloc_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t _image_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t _custom1_lock = PTHREAD_MUTEX_INITIALIZER; +static int thread_levels= 0; /* threads can be invoked inside threads */ + +/* just a max for security reasons */ +#define RE_MAX_THREAD 8 + +typedef struct ThreadSlot { + struct ThreadSlot *next, *prev; + void *(*do_thread)(void *); + void *callerdata; + pthread_t pthread; + int avail; +} ThreadSlot; + +static void BLI_lock_malloc_thread(void) +{ + pthread_mutex_lock(&_malloc_lock); +} + +static void BLI_unlock_malloc_thread(void) +{ + pthread_mutex_unlock(&_malloc_lock); +} + +void BLI_init_threads(ListBase *threadbase, void *(*do_thread)(void *), int tot) +{ + int a; + + if(threadbase==NULL) + return; + threadbase->first= threadbase->last= NULL; + + if(tot>RE_MAX_THREAD) tot= RE_MAX_THREAD; + else if(tot<1) tot= 1; + + for(a=0; ado_thread= do_thread; + tslot->avail= 1; + } + + MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread); + thread_levels++; +} + +/* amount of available threads */ +int BLI_available_threads(ListBase *threadbase) +{ + ThreadSlot *tslot; + int counter=0; + + for(tslot= threadbase->first; tslot; tslot= tslot->next) { + if(tslot->avail) + counter++; + } + return counter; +} + +/* returns thread number, for sample patterns or threadsafe tables */ +int BLI_available_thread_index(ListBase *threadbase) +{ + ThreadSlot *tslot; + int counter=0; + + for(tslot= threadbase->first; tslot; tslot= tslot->next, counter++) { + if(tslot->avail) + return counter; + } + return 0; +} + + +void BLI_insert_thread(ListBase *threadbase, void *callerdata) +{ + ThreadSlot *tslot; + + for(tslot= threadbase->first; tslot; tslot= tslot->next) { + if(tslot->avail) { + tslot->avail= 0; + tslot->callerdata= callerdata; + pthread_create(&tslot->pthread, NULL, tslot->do_thread, tslot->callerdata); + return; + } + } + printf("ERROR: could not insert thread slot\n"); +} + +void BLI_remove_thread(ListBase *threadbase, void *callerdata) +{ + ThreadSlot *tslot; + + for(tslot= threadbase->first; tslot; tslot= tslot->next) { + if(tslot->callerdata==callerdata) { + tslot->callerdata= NULL; + pthread_join(tslot->pthread, NULL); + tslot->avail= 1; + } + } +} + +void BLI_end_threads(ListBase *threadbase) +{ + ThreadSlot *tslot; + + for(tslot= threadbase->first; tslot; tslot= tslot->next) { + if(tslot->avail==0) { + pthread_join(tslot->pthread, NULL); + } + } + BLI_freelistN(threadbase); + + thread_levels--; + if(thread_levels==0) + MEM_set_lock_callback(NULL, NULL); +} + +void BLI_lock_thread(int type) +{ + if (type==LOCK_IMAGE) + pthread_mutex_lock(&_image_lock); + else if (type==LOCK_CUSTOM1) + pthread_mutex_lock(&_custom1_lock); +} + +void BLI_unlock_thread(int type) +{ + if (type==LOCK_IMAGE) + pthread_mutex_unlock(&_image_lock); + else if(type==LOCK_CUSTOM1) + pthread_mutex_unlock(&_custom1_lock); +} + +/* eof */ diff --git a/source/blender/blenlib/intern/time.c b/source/blender/blenlib/intern/time.c new file mode 100644 index 00000000000..47abca10b36 --- /dev/null +++ b/source/blender/blenlib/intern/time.c @@ -0,0 +1,105 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#include "PIL_time.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef WIN32 + +#include + +double PIL_check_seconds_timer(void) +{ + static int hasperfcounter= -1; /* -1==unknown */ + static double perffreq; + + if (hasperfcounter==-1) { + __int64 ifreq; + hasperfcounter= QueryPerformanceFrequency((LARGE_INTEGER*) &ifreq); + perffreq= (double) ifreq; + } + + if (hasperfcounter) { + __int64 count; + + QueryPerformanceCounter((LARGE_INTEGER*) &count); + + return count/perffreq; + } else { + static double accum= 0.0; + static int ltick= 0; + int ntick= GetTickCount(); + + if (ntick +#include + +double PIL_check_seconds_timer(void) +{ + struct timeval tv; + struct timezone tz; + + gettimeofday(&tv, &tz); + + return ((double) tv.tv_sec + tv.tv_usec/1000000.0); +} + +void PIL_sleep_ms(int ms) +{ + if (ms>=1000) { + sleep(ms/1000); + ms= (ms%1000); + } + + usleep(ms*1000); +} + +#endif diff --git a/source/blender/blenlib/intern/util.c b/source/blender/blenlib/intern/util.c new file mode 100644 index 00000000000..8e396eec09d --- /dev/null +++ b/source/blender/blenlib/intern/util.c @@ -0,0 +1,1691 @@ +/* util.c + * + * various string, file, list operations. + * + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + */ + +#include +#include +#include +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "DNA_listBase.h" +#include "BLI_storage.h" +#include "BLI_storage_types.h" +#include "BLI_dynamiclist.h" + +#include "BLI_util.h" +#include "BKE_utildefines.h" + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifndef WIN32 +#include +#else +#include +#endif + +#ifdef WIN32 +#include "BLI_winstuff.h" + +/* for duplicate_defgroup */ +#if !(defined vsnprintf) +#define vsnprintf _vsnprintf +#endif + +#endif + + +#ifndef WIN32 +#include +#endif + +#ifdef __APPLE__ +#include +#include +#endif + +/* local */ + +static int add_win32_extension(char *name); + +/* implementation */ + +/* Ripped this from blender.c */ +void addlisttolist(ListBase *list1, ListBase *list2) +{ + if (list2->first==0) return; + + if (list1->first==0) { + list1->first= list2->first; + list1->last= list2->last; + } + else { + ((Link *)list1->last)->next= list2->first; + ((Link *)list2->first)->prev= list1->last; + list1->last= list2->last; + } + list2->first= list2->last= 0; +} + +int BLI_stringdec(char *string, char *kop, char *start, unsigned short *numlen) +{ + unsigned short len, len2, nums = 0, nume = 0; + short i, found = 0; + + len2 = len = strlen(string); + + if (len > 6) { + if (BLI_strncasecmp(string + len - 6, ".blend", 6) == 0) len -= 6; + else if (BLI_strncasecmp(string + len - 6, ".trace", 6) == 0) len -= 6; + } + + if (len > 9) { + if (BLI_strncasecmp(string + len - 9, ".blend.gz", 9) == 0) len -= 9; + } + + if (len == len2) { + if (len > 4) { + /* handle .jf0 en .jf1 for jstreams */ + if (BLI_strncasecmp(string + len - 4, ".jf", 3) == 0) len -= 4; + else if (BLI_strncasecmp(string + len - 4, ".tga", 4) == 0) len -= 4; + else if (BLI_strncasecmp(string + len - 4, ".jpg", 4) == 0) len -= 4; + else if (BLI_strncasecmp(string + len - 4, ".png", 4) == 0) len -= 4; + else if (BLI_strncasecmp(string + len - 4, ".txt", 4) == 0) len -= 4; + else if (BLI_strncasecmp(string + len - 4, ".cyc", 4) == 0) len -= 4; + else if (BLI_strncasecmp(string + len - 4, ".enh", 4) == 0) len -= 4; + else if (BLI_strncasecmp(string + len - 4, ".rgb", 4) == 0) len -= 4; + else if (BLI_strncasecmp(string + len - 4, ".psx", 4) == 0) len -= 4; + else if (BLI_strncasecmp(string + len - 4, ".ble", 4) == 0) len -= 4; + else if (BLI_strncasecmp(string + len - 4, ".exr", 4) == 0) len -= 4; + } + } + + for (i = len - 1; i >= 0; i--) { + if (string[i] == '/') break; + if (isdigit(string[i])) { + if (found){ + nums = i; + } + else{ + nume = i; + nums = i; + found = 1; + } + } + else { + if (found) break; + } + } + if (found){ + if (start) strcpy(start,&string[nume+1]); + if (kop) { + strcpy(kop,string); + kop[nums]=0; + } + if (numlen) *numlen = nume-nums+1; + return ((int)atoi(&(string[nums]))); + } + if (start) strcpy(start, string + len); + if (kop) { + strncpy(kop, string, len); + kop[len] = 0; + } + if (numlen) *numlen=0; + return 0; +} + + +void BLI_stringenc(char *string, char *kop, char *start, unsigned short numlen, int pic) +{ + char numstr[10]=""; + unsigned short len,i; + + strcpy(string,kop); + + if (pic>0 || numlen==4) { + len= sprintf(numstr,"%d",pic); + + for(i=len;i 99 or from 10 -> 9 */ + if (add < 0 && digits < 4 && digits > 0) { + int i, exp; + exp = 1; + for (i = digits; i > 1; i--) exp *= 10; + if (pic >= exp && (pic + add) < exp) digits--; + } + + pic += add; + + if (digits==4 && pic<0) pic= 0; + BLI_stringenc(name, head, tail, digits, pic); +} + + +void BLI_addhead(ListBase *listbase, void *vlink) +{ + Link *link= vlink; + + if (link == NULL) return; + if (listbase == NULL) return; + + link->next = listbase->first; + link->prev = NULL; + + if (listbase->first) ((Link *)listbase->first)->prev = link; + if (listbase->last == NULL) listbase->last = link; + listbase->first = link; +} + + +void BLI_addtail(ListBase *listbase, void *vlink) +{ + Link *link= vlink; + + if (link == NULL) return; + if (listbase == NULL) return; + + link->next = NULL; + link->prev = listbase->last; + + if (listbase->last) ((Link *)listbase->last)->next = link; + if (listbase->first == 0) listbase->first = link; + listbase->last = link; +} + + +void BLI_remlink(ListBase *listbase, void *vlink) +{ + Link *link= vlink; + + if (link == NULL) return; + if (listbase == NULL) return; + + if (link->next) link->next->prev = link->prev; + if (link->prev) link->prev->next = link->next; + + if (listbase->last == link) listbase->last = link->prev; + if (listbase->first == link) listbase->first = link->next; +} + + +void BLI_freelinkN(ListBase *listbase, void *vlink) +{ + Link *link= vlink; + + if (link == NULL) return; + if (listbase == NULL) return; + + BLI_remlink(listbase,link); + MEM_freeN(link); +} + + +void BLI_insertlink(ListBase *listbase, void *vprevlink, void *vnewlink) +{ + Link *prevlink= vprevlink; + Link *newlink= vnewlink; + + /* newlink comes after prevlink */ + if (newlink == NULL) return; + if (listbase == NULL) return; + + /* empty list */ + if (listbase->first == NULL) { + + listbase->first= newlink; + listbase->last= newlink; + return; + } + + /* insert before first element */ + if (prevlink == NULL) { + newlink->next= listbase->first; + newlink->prev= 0; + newlink->next->prev= newlink; + listbase->first= newlink; + return; + } + + /* at end of list */ + if (listbase->last== prevlink) + listbase->last = newlink; + + newlink->next= prevlink->next; + prevlink->next= newlink; + if (newlink->next) newlink->next->prev= newlink; + newlink->prev= prevlink; +} + +/* This uses insertion sort, so NOT ok for large list */ +void BLI_sortlist(ListBase *listbase, int (*cmp)(void *, void *)) +{ + Link *current = NULL; + Link *previous = NULL; + Link *next = NULL; + + if (cmp == NULL) return; + if (listbase == NULL) return; + + if (listbase->first != listbase->last) + { + for( previous = listbase->first, current = previous->next; current; previous = current, current = next ) + { + next = current->next; + + BLI_remlink(listbase, current); + + while(previous && cmp(previous, current) == 1) + { + previous = previous->prev; + } + + if (previous == NULL) + { + BLI_addhead(listbase, current); + } + else + { + BLI_insertlinkafter(listbase, previous, current); + } + } + } +} + +void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink) +{ + Link *prevlink= vprevlink; + Link *newlink= vnewlink; + + /* newlink before nextlink */ + if (newlink == NULL) return; + if (listbase == NULL) return; + + /* empty list */ + if (listbase->first == NULL) { + listbase->first= newlink; + listbase->last= newlink; + return; + } + + /* insert at head of list */ + if (prevlink == NULL) { + newlink->prev = NULL; + newlink->next = listbase->first; + ((Link *)listbase->first)->prev = newlink; + listbase->first = newlink; + return; + } + + /* at end of list */ + if (listbase->last == prevlink) + listbase->last = newlink; + + newlink->next = prevlink->next; + newlink->prev = prevlink; + prevlink->next = newlink; + if (newlink->next) newlink->next->prev = newlink; +} + +void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink) +{ + Link *nextlink= vnextlink; + Link *newlink= vnewlink; + + /* newlink before nextlink */ + if (newlink == NULL) return; + if (listbase == NULL) return; + + /* empty list */ + if (listbase->first == NULL) { + listbase->first= newlink; + listbase->last= newlink; + return; + } + + /* insert at end of list */ + if (nextlink == NULL) { + newlink->prev= listbase->last; + newlink->next= 0; + ((Link *)listbase->last)->next= newlink; + listbase->last= newlink; + return; + } + + /* at beginning of list */ + if (listbase->first== nextlink) + listbase->first = newlink; + + newlink->next= nextlink; + newlink->prev= nextlink->prev; + nextlink->prev= newlink; + if (newlink->prev) newlink->prev->next= newlink; +} + + +void BLI_freelist(ListBase *listbase) +{ + Link *link, *next; + + if (listbase == NULL) + return; + + link= listbase->first; + while (link) { + next= link->next; + free(link); + link= next; + } + + listbase->first= NULL; + listbase->last= NULL; +} + +void BLI_freelistN(ListBase *listbase) +{ + Link *link, *next; + + if (listbase == NULL) return; + + link= listbase->first; + while (link) { + next= link->next; + MEM_freeN(link); + link= next; + } + + listbase->first= NULL; + listbase->last= NULL; +} + + +int BLI_countlist(ListBase *listbase) +{ + Link *link; + int count = 0; + + if (listbase) { + link = listbase->first; + while (link) { + count++; + link= link->next; + } + } + return count; +} + +void *BLI_findlink(ListBase *listbase, int number) +{ + Link *link = NULL; + + if (number >= 0) { + link = listbase->first; + while (link != NULL && number != 0) { + number--; + link = link->next; + } + } + + return link; +} + +int BLI_findindex(ListBase *listbase, void *vlink) +{ + Link *link= NULL; + int number= 0; + + if (listbase == NULL) return -1; + if (vlink == NULL) return -1; + + link= listbase->first; + while (link) { + if (link == vlink) + return number; + + number++; + link= link->next; + } + + return -1; +} + +/*=====================================================================================*/ +/* Methods for access array (realloc) */ +/*=====================================================================================*/ + +/* remove item with index */ +static void rem_array_item(struct DynamicArray *da, unsigned int index) +{ + da->items[index]=NULL; + da->count--; + if(index==da->last_item_index){ + while((!da->items[da->last_item_index]) && (da->last_item_index>0)){ + da->last_item_index--; + } + } +} + +/* add array (if needed, then realloc) */ +static void add_array_item(struct DynamicArray *da, void *item, unsigned int index) +{ + /* realloc of access array */ + if(da->max_item_index < index){ + unsigned int i, max = da->max_item_index; + void **nitems; + + do { + da->max_item_index += PAGE_SIZE; /* OS can allocate only PAGE_SIZE Bytes */ + } while(da->max_item_index<=index); + + nitems = (void**)MEM_mallocN(sizeof(void*)*(da->max_item_index+1), "dlist access array"); + for(i=0;i<=max;i++) + nitems[i] = da->items[i]; + + /* set rest pointers to the NULL */ + for(i=max+1; i<=da->max_item_index; i++) + nitems[i]=NULL; + + MEM_freeN(da->items); /* free old access array */ + da->items = nitems; + } + + da->items[index] = item; + da->count++; + if(index > da->last_item_index) da->last_item_index = index; +} + +/* free access array */ +static void destroy_array(DynamicArray *da) +{ + da->count=0; + da->last_item_index=0; + da->max_item_index=0; + MEM_freeN(da->items); + da->items = NULL; +} + +/* initialize dynamic array */ +static void init_array(DynamicArray *da) +{ + unsigned int i; + + da->count=0; + da->last_item_index=0; + da->max_item_index = PAGE_SIZE-1; + da->items = (void*)MEM_mallocN(sizeof(void*)*(da->max_item_index+1), "dlist access array"); + for(i=0; i<=da->max_item_index; i++) da->items[i]=NULL; +} + +/* reinitialize dynamic array */ +static void reinit_array(DynamicArray *da) +{ + destroy_array(da); + init_array(da); +} + +/*=====================================================================================*/ +/* Methods for two way dynamic list with access array */ +/*=====================================================================================*/ + +/* create new two way dynamic list with access array from two way dynamic list + * it doesn't copy any items to new array or something like this It is strongly + * recomended to use BLI_dlist_ methods for adding/removing items from dynamic list + * unless you can end with inconsistence system !!! */ +DynamicList *BLI_dlist_from_listbase(ListBase *lb) +{ + DynamicList *dlist; + Link *item; + int i=0, count; + + if(!lb) return NULL; + + count = BLI_countlist(lb); + + dlist = MEM_mallocN(sizeof(DynamicList), "temp dynamic list"); + /* ListBase stuff */ + dlist->lb.first = lb->first; + dlist->lb.last = lb->last; + /* access array stuff */ + dlist->da.count=count; + dlist->da.max_item_index = count-1; + dlist->da.last_item_index = count -1; + dlist->da.items = (void*)MEM_mallocN(sizeof(void*)*count, "temp dlist access array"); + + item = (Link*)lb->first; + while(item){ + dlist->da.items[i] = (void*)item; + item = item->next; + i++; + } + + /* to prevent you of using original ListBase :-) */ + lb->first = lb->last = NULL; + + return dlist; +} + +/* take out ListBase from DynamicList and destroy all temporary structures of DynamicList */ +ListBase *BLI_listbase_from_dlist(DynamicList *dlist, ListBase *lb) +{ + if(!dlist) return NULL; + + if(!lb) lb = (ListBase*)MEM_mallocN(sizeof(ListBase), "ListBase"); + + lb->first = dlist->lb.first; + lb->last = dlist->lb.last; + + /* free all items of access array */ + MEM_freeN(dlist->da.items); + /* free DynamicList*/ + MEM_freeN(dlist); + + return lb; +} + +/* return pointer at item from th dynamic list with access array */ +void *BLI_dlist_find_link(DynamicList *dlist, unsigned int index) +{ + if(!dlist || !dlist->da.items) return NULL; + + if((index <= dlist->da.last_item_index) && (index >= 0) && (dlist->da.count>0)){ + return dlist->da.items[index]; + } + else { + return NULL; + } +} + +/* return count of items in the dynamic list with access array */ +unsigned int BLI_count_items(DynamicList *dlist) +{ + if(!dlist) return 0; + + return dlist->da.count; +} + +/* free item from the dynamic list with access array */ +void BLI_dlist_free_item(DynamicList *dlist, unsigned int index) +{ + if(!dlist || !dlist->da.items) return; + + if((index <= dlist->da.last_item_index) && (dlist->da.items[index])){ + BLI_freelinkN(&(dlist->lb), dlist->da.items[index]); + rem_array_item(&(dlist->da), index); + } +} + +/* remove item from the dynamic list with access array */ +void BLI_dlist_rem_item(DynamicList *dlist, unsigned int index) +{ + if(!dlist || !dlist->da.items) return; + + if((index <= dlist->da.last_item_index) && (dlist->da.items[index])){ + BLI_remlink(&(dlist->lb), dlist->da.items[index]); + rem_array_item(&(dlist->da), index); + } +} + +/* add item to the dynamic list with access array (index) */ +void* BLI_dlist_add_item_index(DynamicList *dlist, void *item, unsigned int index) +{ + if(!dlist || !dlist->da.items) return NULL; + + if((index <= dlist->da.max_item_index) && (dlist->da.items[index])) { + /* you can't place item at used index */ + return NULL; + } + else { + add_array_item(&(dlist->da), item, index); + BLI_addtail(&(dlist->lb), item); + return item; + } +} + +/* destroy dynamic list with access array */ +void BLI_dlist_destroy(DynamicList *dlist) +{ + if(!dlist) return; + + BLI_freelistN(&(dlist->lb)); + destroy_array(&(dlist->da)); +} + +/* initialize dynamic list with access array */ +void BLI_dlist_init(DynamicList *dlist) +{ + if(!dlist) return; + + dlist->lb.first = NULL; + dlist->lb.last = NULL; + + init_array(&(dlist->da)); +} + +/* reinitialize dynamic list with acces array */ +void BLI_dlist_reinit(DynamicList *dlist) +{ + if(!dlist) return; + + BLI_freelistN(&(dlist->lb)); + reinit_array(&(dlist->da)); +} + +/*=====================================================================================*/ + +char *BLI_strdupn(const char *str, int len) { + char *n= MEM_mallocN(len+1, "strdup"); + memcpy(n, str, len); + n[len]= '\0'; + + return n; +} +char *BLI_strdup(const char *str) { + return BLI_strdupn(str, strlen(str)); +} + +char *BLI_strncpy(char *dst, const char *src, int maxncpy) { + int srclen= strlen(src); + int cpylen= (srclen>(maxncpy-1))?(maxncpy-1):srclen; + + memcpy(dst, src, cpylen); + dst[cpylen]= '\0'; + + return dst; +} + +int BLI_snprintf(char *buffer, size_t count, const char *format, ...) +{ + int n; + va_list arg; + + va_start(arg, format); + n = vsnprintf(buffer, count, format, arg); + + if (n != -1 && n < count) { + buffer[n] = '\0'; + } else { + buffer[count-1] = '\0'; + } + + va_end(arg); + return n; +} + +int BLI_streq(char *a, char *b) { + return (strcmp(a, b)==0); +} +int BLI_strcaseeq(char *a, char *b) { + return (BLI_strcasecmp(a, b)==0); +} + +/* ******************** string encoding ***************** */ + +/* This is quite an ugly function... its purpose is to + * take the dir name, make it absolute, and clean it up, replacing + * excess file entry stuff (like /tmp/../tmp/../) + * note that dir isn't protected for max string names... + */ + +void BLI_cleanup_dir(const char *relabase, char *dir) +{ + short a; + char *start, *eind; + + BLI_convertstringcode(dir, relabase, 0); + +#ifdef WIN32 + if(dir[0]=='.') { /* happens for example in FILE_MAIN */ + get_default_root(dir); + return; + } + + while ( (start = strstr(dir, "\\..\\")) ) { + eind = start + strlen("\\..\\") - 1; + a = start-dir-1; + while (a>0) { + if (dir[a] == '\\') break; + a--; + } + strcpy(dir+a,eind); + } + + while ( (start = strstr(dir,"\\.\\")) ){ + eind = start + strlen("\\.\\") - 1; + strcpy(start,eind); + } + + while ( (start = strstr(dir,"\\\\" )) ){ + eind = start + strlen("\\\\") - 1; + strcpy(start,eind); + } + + if((a = strlen(dir))){ /* remove the '\\' at the end */ + while(a>0 && dir[a-1] == '\\'){ + a--; + dir[a] = 0; + } + } + + strcat(dir, "\\"); +#else + if(dir[0]=='.') { /* happens, for example in FILE_MAIN */ + dir[0]= '/'; + dir[1]= 0; + return; + } + + while ( (start = strstr(dir, "/../")) ) { + eind = start + strlen("/../") - 1; + a = start-dir-1; + while (a>0) { + if (dir[a] == '/') break; + a--; + } + strcpy(dir+a,eind); + } + + while ( (start = strstr(dir,"/./")) ){ + eind = start + strlen("/./") - 1; + strcpy(start,eind); + } + + while ( (start = strstr(dir,"//" )) ){ + eind = start + strlen("//") - 1; + strcpy(start,eind); + } + + if( (a = strlen(dir)) ){ /* remove all '/' at the end */ + while(dir[a-1] == '/'){ + a--; + dir[a] = 0; + if (a<=0) break; + } + } + + strcat(dir, "/"); +#endif +} + + +void BLI_makestringcode(const char *relfile, char *file) +{ + char * p; + char * q; + char * lslash; + char temp[FILE_MAXDIR+FILE_MAXFILE]; + char res[FILE_MAXDIR+FILE_MAXFILE]; + + /* if file is already relative, bail out */ + if(file[0]=='/' && file[1]=='/') return; + + /* also bail out if relative path is not set */ + if (relfile[0] == 0) return; + +#ifdef WIN32 + if (strlen(relfile) > 2 && relfile[1] != ':') { + char* ptemp; + /* fix missing volume name in relative base, + can happen with old .Blog files */ + get_default_root(temp); + ptemp = &temp[2]; + if (relfile[0] != '\\' && relfile[0] != '/') { + ptemp++; + } + BLI_strncpy(ptemp, relfile, FILE_MAXDIR + FILE_MAXFILE-3); + } else { + BLI_strncpy(temp, relfile, FILE_MAXDIR + FILE_MAXFILE); + } + + if (strlen(file) > 2) { + if ( temp[1] == ':' && file[1] == ':' && temp[0] != file[0] ) + return; + } +#else + BLI_strncpy(temp, relfile, FILE_MAX); +#endif + + BLI_char_switch(temp, '\\', '/'); + BLI_char_switch(file, '\\', '/'); + + /* the last slash in the file indicates where the path part ends */ + lslash = BLI_last_slash(temp); + + if (lslash) + { + /* find the prefix of the filename that is equal for both filenames. + This is replaced by the two slashes at the beginning */ + p = temp; + q = file; + while (*p == *q) { + ++p; ++q; + } + /* we might have passed the slash when the beginning of a dir matches + so we rewind. Only check on the actual filename + */ + if (*q != '/') { + while ( (q >= file) && (*q != '/') ) { --q; --p; } + } + else if (*p != '/') { + while ( (p >= temp) && (*p != '/') ) { --p; --q; } + } + + strcpy(res, "//"); + + /* p now points to the slash that is at the beginning of the part + where the path is different from the relative path. + We count the number of directories we need to go up in the + hierarchy to arrive at the common 'prefix' of the path + */ + while (p && p < lslash) { + if (*p == '/') + strcat(res, "../"); + ++p; + } + + strcat(res, q+1); /* don't copy the slash at the beginning */ + +#ifdef WIN32 + BLI_char_switch(res+2, '/', '\\'); +#endif + strcpy(file, res); + } +} + +int BLI_convertstringcode(char *path, const char *basepath, int framenum) +{ + int len, wasrelative; + char tmp[FILE_MAXDIR+FILE_MAXFILE]; + char base[FILE_MAXDIR]; + char vol[3] = {'\0', '\0', '\0'}; + + BLI_strncpy(vol, path, 3); + wasrelative= (strncmp(vol, "//", 2)==0); + +#ifdef WIN32 + /* we are checking here if we have an absolute path that is not in the current + blend file as a lib main - we are basically checking for the case that a + UNIX root '/' is passed. + */ + if (!wasrelative && (vol[1] != ':' && (vol[0] == '\0' || vol[0] == '/' || vol[0] == '\\'))) { + char *p = path; + get_default_root(tmp); + // get rid of the slashes at the beginning of the path + while (*p == '\\' || *p == '/') { + p++; + } + strcat(tmp, p); + } + else { + strcpy(tmp, path); + } +#else + strcpy(tmp, path); +#endif + + strcpy(base, basepath); + + /* push slashes into unix mode - strings entering this part are + potentially messed up: having both back- and forward slashes. + Here we push into one conform direction, and at the end we + push them into the system specific dir. This ensures uniformity + of paths and solving some problems (and prevent potential future + ones) -jesterKing. */ + BLI_char_switch(tmp, '\\', '/'); + BLI_char_switch(base, '\\', '/'); + + if (tmp[0] == '/' && tmp[1] == '/') { + char *filepart= BLI_strdup(tmp+2); /* skip code */ + char *lslash= BLI_last_slash(base); + + if (lslash) { + int baselen= (int) (lslash-base) + 1; + + memcpy(tmp, base, baselen); + strcpy(tmp+baselen, filepart); + } else { + strcpy(tmp, filepart); + } + + MEM_freeN(filepart); + } + + len= strlen(tmp); + if(len && tmp[len-1]=='#') { + sprintf(tmp+len-1, "%04d", framenum); + } + + strcpy(path, tmp); +#ifdef WIN32 + /* skip first two chars, which in case of + absolute path will be drive:/blabla and + in case of relpath //blabla/. So relpath + // will be retained, rest will be nice and + shiny win32 backward slashes :) -jesterKing + */ + BLI_char_switch(path+2, '/', '\\'); +#endif + + return wasrelative; +} + +void BLI_splitdirstring(char *di, char *fi) +{ + char *lslash= BLI_last_slash(di); + + if (lslash) { + BLI_strncpy(fi, lslash+1, FILE_MAXFILE); + *(lslash+1)=0; + } else { + BLI_strncpy(fi, di, FILE_MAXFILE); + di[0]= 0; + } +} + +char *BLI_gethome(void) { + #ifdef __BeOS + return "/boot/home/"; /* BeOS 4.5: doubleclick at icon doesnt give home env */ + + #elif !defined(WIN32) + return getenv("HOME"); + + #else /* Windows */ + char * ret; + static char dir[512]; + + /* Check for %HOME% env var */ + + ret = getenv("HOME"); + if(ret) { + sprintf(dir, "%s\\.blender", ret); + if (BLI_exists(dir)) return dir; + } + + /* else, check install dir (path containing blender.exe) */ + + BLI_getInstallationDir(dir); + + if (BLI_exists(dir)) + { + strcat(dir,"\\.blender"); + if (BLI_exists(dir)) return(dir); + } + + + /* add user profile support for WIN 2K / NT */ + ret = getenv("USERPROFILE"); + if (ret) { + if (BLI_exists(ret)) { /* from fop, also below... */ + sprintf(dir, "%s\\Application Data\\Blender Foundation\\Blender", ret); + BLI_recurdir_fileops(dir); + if (BLI_exists(dir)) { + strcat(dir,"\\.blender"); + if(BLI_exists(dir)) return(dir); + } + } + } + + /* + Saving in the Windows dir is less than desirable. + Use as a last resort ONLY! (aphex) + */ + + ret = getenv("WINDOWS"); + if (ret) { + if(BLI_exists(ret)) return ret; + } + + ret = getenv("WINDIR"); + if (ret) { + if(BLI_exists(ret)) return ret; + } + + return "C:\\Temp"; /* sheesh! bad, bad, bad! (aphex) */ + #endif +} + +void BLI_clean(char *path) +{ + if(path==0) return; +#ifdef WIN32 + if(path && strlen(path)>2) { + BLI_char_switch(path+2, '/', '\\'); + } +#else + BLI_char_switch(path, '\\', '/'); +#endif +} + +void BLI_char_switch(char *string, char from, char to) +{ + if(string==0) return; + while (*string != 0) { + if (*string == from) *string = to; + string++; + } +} + +void BLI_make_exist(char *dir) { + int a; + + #ifdef WIN32 + BLI_char_switch(dir, '/', '\\'); + #else + BLI_char_switch(dir, '\\', '/'); + #endif + + a = strlen(dir); + +#ifdef WIN32 + while(BLI_exists(dir) == 0){ + a --; + while(dir[a] != '\\'){ + a--; + if (a <= 0) break; + } + if (a >= 0) dir[a+1] = 0; + else { + /* defaulting to drive (usually 'C:') of Windows installation */ + get_default_root(dir); + break; + } + } +#else + while(BLI_exist(dir) == 0){ + a --; + while(dir[a] != '/'){ + a--; + if (a <= 0) break; + } + if (a >= 0) dir[a+1] = 0; + else { + strcpy(dir,"/"); + break; + } + } +#endif +} + +void BLI_make_existing_file(char *name) +{ + char di[FILE_MAXDIR], fi[FILE_MAXFILE]; + + strcpy(di, name); + BLI_splitdirstring(di, fi); + + /* test exist */ + if (BLI_exists(di) == 0) { + BLI_recurdir_fileops(di); + } +} + + +void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file) +{ + int sl; + + if (!string || !dir || !file) return; /* We don't want any NULLs */ + + string[0]= 0; /* ton */ + + /* we first push all slashes into unix mode, just to make sure we don't get + any mess with slashes later on. -jesterKing */ + /* constant strings can be passed for those parameters - don't change them - elubie */ + /* + BLI_char_switch(relabase, '\\', '/'); + BLI_char_switch(dir, '\\', '/'); + BLI_char_switch(file, '\\', '/'); + */ + + /* Resolve relative references */ + if (relabase && dir[0] == '/' && dir[1] == '/') { + char *lslash; + + /* Get the file name, chop everything past the last slash (ie. the filename) */ + strcpy(string, relabase); + + lslash= (strrchr(string, '/')>strrchr(string, '\\'))?strrchr(string, '/'):strrchr(string, '\\'); + + if(lslash) *(lslash+1)= 0; + + dir+=2; /* Skip over the relative reference */ + } +#ifdef WIN32 + else { + if (strlen(dir) >= 2 && dir[1] == ':' ) { + BLI_strncpy(string, dir, 3); + dir += 2; + } + else { /* no drive specified */ + /* first option: get the drive from the relabase if it has one */ + if (relabase && strlen(relabase) >= 2 && relabase[1] == ':' ) { + BLI_strncpy(string, relabase, 3); + string[2] = '\\'; + string[3] = '\0'; + } + else { /* we're out of luck here, guessing the first valid drive, usually c:\ */ + get_default_root(string); + } + + /* ignore leading slashes */ + while (*dir == '/' || *dir == '\\') dir++; + } + } +#endif + + strcat(string, dir); + + /* Make sure string ends in one (and only one) slash */ + /* first trim all slashes from the end of the string */ + sl = strlen(string); + while (sl>0 && ( string[sl-1] == '/' || string[sl-1] == '\\') ) { + string[sl-1] = '\0'; + sl--; + } + /* since we've now removed all slashes, put back one slash at the end. */ + strcat(string, "/"); + + while (*file && (*file == '/' || *file == '\\')) /* Trim slashes from the front of file */ + file++; + + strcat (string, file); + + /* Push all slashes to the system preferred direction */ + BLI_clean(string); +} + +int BLI_testextensie(const char *str, const char *ext) +{ + short a, b; + int retval; + + a= strlen(str); + b= strlen(ext); + + if(a==0 || b==0 || b>=a) { + retval = 0; + } else if (BLI_strcasecmp(ext, str + a - b)) { + retval = 0; + } else { + retval = 1; + } + + return (retval); +} + + + +void BLI_split_dirfile(const char *string, char *dir, char *file) +{ + int a; +#ifdef WIN32 + int sl; + short is_relative = 0; +#endif + + dir[0]= 0; + file[0]= 0; + +#ifdef WIN32 + BLI_char_switch(string, '/', '\\'); /* make sure we have a valid path format */ + sl = strlen(string); + if (sl) { + int len; + if (string[0] == '/' || string[0] == '\\') { + BLI_strncpy(dir, string, FILE_MAXDIR); + if (sl > 1 && string[0] == '\\' && string[1] == '\\') is_relative = 1; + } else if (sl > 2 && string[1] == ':' && string[2] == '\\') { + BLI_strncpy(dir, string, FILE_MAXDIR); + } else { + BLI_getwdN(dir); + strcat(dir,"\\"); + strcat(dir,string); + BLI_strncpy(string,dir,FILE_MAXDIR+FILE_MAXFILE); + } + + // BLI_exist doesn't recognize a slashed dirname as a dir + // check if a trailing slash exists, and remove it. Do not do this + // when we are already at root. -jesterKing + a = strlen(dir); + if(a>=4 && dir[a-1]=='\\') dir[a-1] = 0; + + if (is_relative) { + printf("WARNING: BLI_split_dirfile needs absolute dir\n"); + } + else { + BLI_make_exist(dir); + } + + if (S_ISDIR(BLI_exist(dir))) { + + /* copy from end of string into file, to ensure filename itself isn't truncated + if string is too long. (aphex) */ + + len = FILE_MAXFILE - strlen(string); + + if (len < 0) + BLI_strncpy(file,string + abs(len),FILE_MAXFILE); + else + BLI_strncpy(file,string,FILE_MAXFILE); + + if (strrchr(string,'\\')) { + BLI_strncpy(file,strrchr(string,'\\')+1,FILE_MAXFILE); + } + + if ( (a = strlen(dir)) ) { + if (dir[a-1] != '\\') strcat(dir,"\\"); + } + } + else { + a = strlen(dir) - 1; + while(a>0 && dir[a] != '\\') a--; + dir[a + 1] = 0; + BLI_strncpy(file, string + strlen(dir),FILE_MAXFILE); + } + + } + else { + /* defaulting to first valid drive hoping it's not empty CD and DVD drives */ + get_default_root(dir); + file[0]=0; + } +#else + if (strlen(string)) { + if (string[0] == '/') { + strcpy(dir, string); + } else if (string[1] == ':' && string[2] == '\\') { + string+=2; + strcpy(dir, string); + } else { + BLI_getwdN(dir); + strcat(dir,"/"); + strcat(dir,string); + strcpy((char *)string,dir); + } + + BLI_make_exist(dir); + + if (S_ISDIR(BLI_exist(dir))) { + strcpy(file,string + strlen(dir)); + + if (strrchr(file,'/')) strcpy(file,strrchr(file,'/')+1); + + if ( (a = strlen(dir)) ) { + if (dir[a-1] != '/') strcat(dir,"/"); + } + } + else { + a = strlen(dir) - 1; + while(dir[a] != '/') a--; + dir[a + 1] = 0; + strcpy(file, string + strlen(dir)); + } + } + else { + BLI_getwdN(dir); + strcat(dir, "/"); + file[0] = 0; + } +#endif +} + +/* simple appending of filename to dir, does not check for valid path! */ +void BLI_join_dirfile(char *string, const char *dir, const char *file) +{ + int sl_dir = strlen(dir); + BLI_strncpy(string, dir, FILE_MAX); + if (sl_dir > FILE_MAX-1) sl_dir = FILE_MAX-1; +#ifdef WIN32 + string[sl_dir] = '\\'; +#else + string[sl_dir] = '/'; +#endif + sl_dir++; + if (sl_dir c2) { + return 1; + } else if (c1==0) { + break; + } + } + + return 0; +} + +int BLI_strncasecmp(const char *s1, const char *s2, int n) { + int i; + + for (i=0; ic2) { + return 1; + } else if (c1==0) { + break; + } + } + + return 0; +} + + +#ifdef WITH_ICONV +#include "iconv.h" +#include "localcharset.h" + +void BLI_string_to_utf8(char *original, char *utf_8, char *code) +{ + size_t inbytesleft=strlen(original); + size_t outbytesleft=512; + size_t rv=0; + iconv_t cd; + + if (NULL == code) { + code = locale_charset(); + } + cd=iconv_open("UTF-8", code); + + if (cd == (iconv_t)(-1)) { + printf("iconv_open Error"); + *utf_8='\0'; + return ; + } + rv=iconv(cd, &original, &inbytesleft, &utf_8, &outbytesleft); + if (rv == (size_t) -1) { + printf("iconv Error\n"); + return ; + } + *utf_8 = '\0'; + iconv_close(cd); +} +#endif // WITH_ICONV + +void BLI_timestr(double time, char *str) +{ + /* format 00:00:00.00 (hr:min:sec) string has to be 12 long */ + int hr= ((int) time) / (60*60); + int min= ( ((int) time) / 60 ) % 60; + int sec= ((int) (time)) % 60; + int hun= ((int) (time * 100.0)) % 100; + + if (hr) { + sprintf(str, "%.2d:%.2d:%.2d.%.2d",hr,min,sec,hun); + } else { + sprintf(str, "%.2d:%.2d.%.2d",min,sec,hun); + } + + str[11]=0; +} + +/* ************** 64 bits magic, trick to support up to 32 gig of address space *************** */ +/* only works for malloced pointers (8 aligned) */ + +#ifdef __LP64__ + +#if defined(WIN32) && !defined(FREE_WINDOWS) +#define PMASK 0x07FFFFFFFFi64 +#else +#define PMASK 0x07FFFFFFFFll +#endif + + +int BLI_int_from_pointer(void *poin) +{ + long lval= (long)poin; + + return (int)(lval>>3); +} + +void *BLI_pointer_from_int(int val) +{ + static int firsttime= 1; + static long basevalue= 0; + + if(firsttime) { + void *poin= malloc(10000); + basevalue= (long)poin; + basevalue &= ~PMASK; + printf("base: %d pointer %p\n", basevalue, poin); /* debug */ + firsttime= 0; + free(poin); + } + return (void *)(basevalue | (((long)val)<<3)); +} + +#else + +int BLI_int_from_pointer(void *poin) +{ + return (int)poin; +} +void *BLI_pointer_from_int(int val) +{ + return (void *)val; +} + +#endif + diff --git a/source/blender/blenlib/intern/vectorops.c b/source/blender/blenlib/intern/vectorops.c new file mode 100644 index 00000000000..8c4ad5414db --- /dev/null +++ b/source/blender/blenlib/intern/vectorops.c @@ -0,0 +1,169 @@ +/* + * + * Some vector operations. + * + * Always use + * - vector with x components : float x[3], int x[3], etc + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* ------------------------------------------------------------------------- */ +/* General format: op(a, b, c): a = b op c */ +/* Copying is done cp */ +/* ------------------------------------------------------------------------- */ + +#include "MTC_vectorops.h" +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +void MTC_diff3Int(int v1[3], int v2[3], int v3[3]) +{ + v1[0] = v2[0] - v3[0]; + v1[1] = v2[1] - v3[1]; + v1[2] = v2[2] - v3[2]; +} + +/* ------------------------------------------------------------------------- */ +void MTC_diff3Float(float v1[3], float v2[3], float v3[3]) +{ + v1[0] = v2[0] - v3[0]; + v1[1] = v2[1] - v3[1]; + v1[2] = v2[2] - v3[2]; +} + +/* ------------------------------------------------------------------------- */ + +void MTC_cross3Int(int v1[3], int v2[3], int v3[3]) +{ + v1[0] = v2[1]*v3[2] - v2[2]*v3[1]; + v1[1] = v2[2]*v3[0] - v2[0]*v3[2]; + v1[2] = v2[0]*v3[1] - v2[1]*v3[0]; +} + +/* ------------------------------------------------------------------------- */ + +void MTC_cross3Float(float v1[3], float v2[3], float v3[3]) +{ + v1[0] = v2[1]*v3[2] - v2[2]*v3[1]; + v1[1] = v2[2]*v3[0] - v2[0]*v3[2]; + v1[2] = v2[0]*v3[1] - v2[1]*v3[0]; +} +/* ------------------------------------------------------------------------- */ + +void MTC_cross3Double(double v1[3], double v2[3], double v3[3]) +{ + v1[0] = v2[1]*v3[2] - v2[2]*v3[1]; + v1[1] = v2[2]*v3[0] - v2[0]*v3[2]; + v1[2] = v2[0]*v3[1] - v2[1]*v3[0]; +} + +/* ------------------------------------------------------------------------- */ + +int MTC_dot3Int(int v1[3], int v2[3]) +{ + return (v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]); +} + +/* ------------------------------------------------------------------------- */ + +float MTC_dot3Float(float v1[3], float v2[3]) +{ + return (v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]); +} + +/* ------------------------------------------------------------------------- */ + +void MTC_cp3Float(float v1[3], float v2[3]) +{ + v2[0] = v1[0]; + v2[1] = v1[1]; + v2[2] = v1[2]; +} + +/* ------------------------------------------------------------------------- */ + +void MTC_cp3FloatInv(float v1[3], float v2[3]) +{ + v2[0] = -v1[0]; + v2[1] = -v1[1]; + v2[2] = -v1[2]; +} + +/* ------------------------------------------------------------------------- */ + +void MTC_swapInt(int *i1, int *i2) +{ + int swap; + swap = *i1; + *i1 = *i2; + *i2 = swap; +} + +/* ------------------------------------------------------------------------- */ + +void MTC_diff3DFF(double v1[3], float v2[3], float v3[3]) +{ + v1[0] = v2[0] - v3[0]; + v1[1] = v2[1] - v3[1]; + v1[2] = v2[2] - v3[2]; +} + +/* ------------------------------------------------------------------------- */ +float MTC_normalize3DF(float n[3]) +{ + float d; + + d= n[0]*n[0]+n[1]*n[1]+n[2]*n[2]; + /* FLT_EPSILON is too large! A larger value causes normalize errors in */ + /* a scaled down utah teapot */ + if(d>0.0000000000001) { + + /* d= sqrt(d); This _should_ be sqrt, but internally it's a double*/ + /* anyway. This is safe. */ + d = sqrt(d); + + n[0]/=d; + n[1]/=d; + n[2]/=d; + } else { + n[0]=n[1]=n[2]= 0.0; + d= 0.0; + } + return d; +} + +/* ------------------------------------------------------------------------- */ + +/* eof */ diff --git a/source/blender/blenlib/intern/winstuff.c b/source/blender/blenlib/intern/winstuff.c new file mode 100644 index 00000000000..1a3dfa79516 --- /dev/null +++ b/source/blender/blenlib/intern/winstuff.c @@ -0,0 +1,209 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * Windows-posix compatibility layer, windows-specific functions. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef WIN32 + +#include +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_util.h" +#define WIN32_SKIP_HKEY_PROTECTION // need to use HKEY +#include "BLI_winstuff.h" + +#include "BKE_utildefines.h" /* FILE_MAXDIR + FILE_MAXFILE */ + +int BLI_getInstallationDir( char * str ) { + char dir[FILE_MAXDIR]; + char file[FILE_MAXFILE]; + int a; + + GetModuleFileName(NULL,str,FILE_MAXDIR+FILE_MAXFILE); + BLI_split_dirfile(str,dir,file); /* shouldn't be relative */ + a = strlen(dir); + if(dir[a-1] == '\\') dir[a-1]=0; + + strcpy(str,dir); + + return 1; +} + + +void RegisterBlendExtension(char * str) { + LONG lresult; + HKEY hkey = 0; + DWORD dwd = 0; + char buffer[128]; + + lresult = RegCreateKeyEx(HKEY_CLASSES_ROOT, "blendfile\\shell\\open\\command", 0, + "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &dwd); + + if (lresult == ERROR_SUCCESS) { + sprintf(buffer, "\"%s\" \"%%1\"", str); + lresult = RegSetValueEx(hkey, NULL, 0, REG_SZ, buffer, strlen(buffer) + 1); + RegCloseKey(hkey); + } + + lresult = RegCreateKeyEx(HKEY_CLASSES_ROOT, "blendfile\\DefaultIcon", 0, + "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &dwd); + + if (lresult == ERROR_SUCCESS) { + sprintf(buffer, "\"%s\",1", str); + lresult = RegSetValueEx(hkey, NULL, 0, REG_SZ, buffer, strlen(buffer) + 1); + RegCloseKey(hkey); + } + + lresult = RegCreateKeyEx(HKEY_CLASSES_ROOT, ".blend", 0, + "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &dwd); + + if (lresult == ERROR_SUCCESS) { + sprintf(buffer, "%s", "blendfile"); + lresult = RegSetValueEx(hkey, NULL, 0, REG_SZ, buffer, strlen(buffer) + 1); + RegCloseKey(hkey); + } +} + +DIR *opendir (const char *path) { + if (GetFileAttributes(path) & FILE_ATTRIBUTE_DIRECTORY) { + DIR *newd= MEM_mallocN(sizeof(DIR), "opendir"); + + newd->handle = INVALID_HANDLE_VALUE; + sprintf(newd->path, "%s\\*",path); + + newd->direntry.d_ino= 0; + newd->direntry.d_off= 0; + newd->direntry.d_reclen= 0; + newd->direntry.d_name= NULL; + + return newd; + } else { + return NULL; + } +} + +struct dirent *readdir(DIR *dp) { + if (dp->direntry.d_name) { + MEM_freeN(dp->direntry.d_name); + dp->direntry.d_name= NULL; + } + + if (dp->handle==INVALID_HANDLE_VALUE) { + dp->handle= FindFirstFile(dp->path, &(dp->data)); + if (dp->handle==INVALID_HANDLE_VALUE) + return NULL; + + dp->direntry.d_name= BLI_strdup(dp->data.cFileName); + + return &dp->direntry; + } else if (FindNextFile (dp->handle, &(dp->data))) { + dp->direntry.d_name= BLI_strdup(dp->data.cFileName); + + return &dp->direntry; + } else { + return NULL; + } +} + +int closedir (DIR *dp) { + if (dp->direntry.d_name) MEM_freeN(dp->direntry.d_name); + if (dp->handle!=INVALID_HANDLE_VALUE) FindClose(dp->handle); + + MEM_freeN(dp); + + return 0; +} + +void get_default_root(char* root) { + char str[MAX_PATH+1]; + + /* the default drive to resolve a directory without a specified drive + should be the Windows installation drive, since this was what the OS + assumes. */ + if (GetWindowsDirectory(str,MAX_PATH+1)) { + root[0] = str[0]; + root[1] = ':'; + root[2] = '\\'; + root[3] = '\0'; + } else { + /* if GetWindowsDirectory fails, something has probably gone wrong, + we are trying the blender install dir though */ + if (GetModuleFileName(NULL,str,MAX_PATH+1)) { + printf("Error! Could not get the Windows Directory - Defaulting to Blender installation Dir!"); + root[0] = str[0]; + root[1] = ':'; + root[2] = '\\'; + root[3] = '\0'; + } else { + DWORD tmp; + int i; + int rc = 0; + /* now something has gone really wrong - still trying our best guess */ + printf("Error! Could not get the Windows Directory - Defaulting to first valid drive! Path might be invalid!"); + tmp= GetLogicalDrives(); + for (i=2; i < 26; i++) { + if ((tmp>>i) & 1) { + root[0] = 'a'+i; + root[1] = ':'; + root[2] = '\\'; + root[3] = '\0'; + if (GetFileAttributes(root) != 0xFFFFFFFF) { + rc = i; + break; + } + } + } + if (0 == rc) { + printf("ERROR in 'get_default_root': can't find a valid drive!"); + root[0] = 'C'; + root[1] = ':'; + root[2] = '\\'; + root[3] = '\0'; + } + } + } +} + +#else + +static void BLI_WINSTUFF_C_IS_EMPTY_FOR_UNIX(void) +{ + /*intentionally empty*/ +} + +#endif diff --git a/source/blender/blenloader/BLO_genfile.h b/source/blender/blenloader/BLO_genfile.h new file mode 100644 index 00000000000..6549bafe89b --- /dev/null +++ b/source/blender/blenloader/BLO_genfile.h @@ -0,0 +1,38 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * external genfile function prototypes + */ + +#ifndef BLO_GENFILE_H +#define BLO_GENFILE_H + +#endif + diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h new file mode 100644 index 00000000000..09edfe90d02 --- /dev/null +++ b/source/blender/blenloader/BLO_readfile.h @@ -0,0 +1,250 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * external readfile function prototypes + */ +#ifndef BLO_READFILE_H +#define BLO_READFILE_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct SpaceFile; +struct SpaceImaSel; +struct FileList; +struct LinkNode; +struct Main; +struct UserDef; +struct bScreen; +struct Scene; +struct MemFile; +struct direntry; + +typedef struct BlendHandle BlendHandle; + +typedef enum BlenFileType { + BLENFILETYPE_BLEND= 1, + BLENFILETYPE_PUB= 2, + BLENFILETYPE_RUNTIME= 3 +} BlenFileType; + +typedef enum { + BRE_NONE, + + BRE_UNABLE_TO_OPEN, + BRE_UNABLE_TO_READ, + + BRE_OUT_OF_MEMORY, + BRE_INTERNAL_ERROR, + + BRE_NOT_A_BLEND, + BRE_NOT_A_PUBFILE, + BRE_INCOMPLETE, + BRE_CORRUPT, + + BRE_TOO_NEW, + BRE_NOT_ALLOWED, + + BRE_NO_SCREEN, + BRE_NO_SCENE, + + BRE_INVALID +} BlendReadError; + +typedef struct BlendFileData { + struct Main* main; + struct UserDef* user; + + int winpos; + int fileflags; + int displaymode; + int globalf; + + struct bScreen* curscreen; + struct Scene* curscene; + + BlenFileType type; +} BlendFileData; + + /** + * Open a blender file from a pathname. The function + * returns NULL and sets the @a error_r argument if + * it cannot open the file. + * + * @param file The path of the file to open. + * @param error_r If the return value is NULL, an error + * code indicating the cause of the failure. + * @return The data of the file. + */ +BlendFileData* BLO_read_from_file (char *file, BlendReadError *error_r); + + /** + * Open a blender file from memory. The function + * returns NULL and sets the @a error_r argument if + * it cannot open the file. + * + * @param mem The file data. + * @param memsize The length of @a mem. + * @param error_r If the return value is NULL, an error + * code indicating the cause of the failure. + * @return The data of the file. + */ +BlendFileData* BLO_read_from_memory(void *mem, int memsize, BlendReadError *error_r); + +/** + * file name is current file, only for retrieving library data */ + +BlendFileData *BLO_read_from_memfile(const char *filename, struct MemFile *memfile, BlendReadError *error_r); + +/** + * Convert a BlendReadError to a human readable string. + * The string is static and does not need to be free'd. + * + * @param error The error to return a string for. + * @return A static human readable string representation + * of @a error. + */ + + char* +BLO_bre_as_string( + BlendReadError error); + +/** + * Free's a BlendFileData structure and _all_ the + * data associated with it (the userdef data, and + * the main libblock data). + * + * @param bfd The structure to free. + */ + void +BLO_blendfiledata_free( + BlendFileData *bfd); + +/** + * Convert an idcode into a name. + * + * @param code The code to convert. + * @return A static string representing the name of + * the code. + */ + char* +BLO_idcode_to_name( + int code); + +/** + * Convert a name into an idcode (ie. ID_SCE) + * + * @param name The name to convert. + * @return The code for the name, or 0 if invalid. + */ + int +BLO_idcode_from_name( + char *name); + +/** + * Open a blendhandle from a file path. + * + * @param file The file path to open. + * @return A handle on success, or NULL on failure. + */ + BlendHandle* +BLO_blendhandle_from_file( + char *file); + +/** + * Gets the names of all the datablocks in a file + * of a certain type (ie. All the scene names in + * a file). + * + * @param bh The blendhandle to access. + * @param ofblocktype The type of names to get. + * @return A BLI_linklist of strings. The string links + * should be freed with malloc. + */ + struct LinkNode* +BLO_blendhandle_get_datablock_names( + BlendHandle *bh, + int ofblocktype); + +/** + * Gets the previews of all the datablocks in a file + * of a certain type (ie. All the scene names in + * a file). + * + * @param bh The blendhandle to access. + * @param ofblocktype The type of names to get. + * @return A BLI_linklist of PreviewImage. The PreviewImage links + * should be freed with malloc. + */ + struct LinkNode* +BLO_blendhandle_get_previews( + BlendHandle *bh, + int ofblocktype); + +/** + * Gets the names of all the datablock groups in a + * file. (ie. file contains Scene, Mesh, and Lamp + * datablocks). + * + * @param bh The blendhandle to access. + * @return A BLI_linklist of strings. The string links + * should be freed with malloc. + */ + struct LinkNode* +BLO_blendhandle_get_linkable_groups( + BlendHandle *bh); + +/** + * Close and free a blendhandle. The handle + * becomes invalid after this call. + * + * @param bh The handle to close. + */ + void +BLO_blendhandle_close( + BlendHandle *bh); + + /***/ + +char *BLO_gethome(void); +int BLO_has_bfile_extension(char *str); +void BLO_library_append(struct SpaceFile *sfile, char *dir, int idcode); +void BLO_library_append_(BlendHandle **libfiledata, struct direntry* filelist, int totfile, char *dir, char* file, short flag, int idcode); +void BLO_script_library_append(BlendHandle *bh, char *dir, char *name, int idcode, short flag, struct Scene *scene); + +BlendFileData* blo_read_blendafterruntime(int file, int actualsize, BlendReadError *error_r); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/source/blender/blenloader/BLO_soundfile.h b/source/blender/blenloader/BLO_soundfile.h new file mode 100644 index 00000000000..3a8ff3fcb99 --- /dev/null +++ b/source/blender/blenloader/BLO_soundfile.h @@ -0,0 +1,44 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BLO_SOUNDFILE_H +#define BLO_SOUNDFILE_H + +#include "DNA_sound_types.h" +#include "DNA_packedFile_types.h" + +struct bSound; +struct PackedFile; + +//void sound_read_wav_data(bSound * sound, PackedFile * pf); + +#endif + diff --git a/source/blender/blenloader/BLO_sys_types.h b/source/blender/blenloader/BLO_sys_types.h new file mode 100644 index 00000000000..38dde20500e --- /dev/null +++ b/source/blender/blenloader/BLO_sys_types.h @@ -0,0 +1,102 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * A platform-independent definition of [u]intXX_t + * Plus the accompanying header include for htonl/ntohl + * + * This file includes to define [u]intXX_t types, where + * XX can be 8, 16, 32 or 64. Unfortunately, not all systems have this + * file. + * - Windows uses __intXX compiler-builtin types. These are signed, + * so we have to flip the signs. + * For these rogue platforms, we make the typedefs ourselves. + * + */ + +#ifndef BLO_SYS_TYPES_H +#define BLO_SYS_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef FREE_WINDOWS +typedef unsigned char uint8_t; +typedef unsigned int uint32_t; +#endif + +#if defined(_WIN32) && !defined(FREE_WINDOWS) + +/* The __intXX are built-in types of the visual complier! So we don't + * need to include anything else here. */ + +typedef signed __int8 int8_t; +typedef signed __int16 int16_t; +typedef signed __int32 int32_t; +typedef signed __int64 int64_t; + +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; + +#elif defined(__linux__) + + /* Linux-i386, Linux-Alpha, Linux-ppc */ +#include + +#elif defined (__APPLE__) + +#include + +#else + + /* FreeBSD, Irix, Solaris */ +#include + +#endif /* ifdef platform for types */ + +#ifdef _WIN32 +#define htonl(x) correctByteOrder(x) +#define ntohl(x) correctByteOrder(x) +#elif defined (__FreeBSD__) || defined (__OpenBSD__) +#include +#elif defined (__APPLE__) +#include +#else /* irix sun linux */ +#include +#endif /* ifdef platform for htonl/ntohl */ + +#ifdef __cplusplus +} +#endif + +#endif /* eof */ + diff --git a/source/blender/blenloader/BLO_undofile.h b/source/blender/blenloader/BLO_undofile.h new file mode 100644 index 00000000000..225b6bc15f5 --- /dev/null +++ b/source/blender/blenloader/BLO_undofile.h @@ -0,0 +1,58 @@ +/* + * $Id: + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * external writefile function prototypes + */ + +#ifndef BLO_UNDOFILE_H +#define BLO_UNDOFILE_H + +typedef struct { + void *next, *prev; + + char *buf; + unsigned int ident, size; + +} MemFileChunk; + +typedef struct MemFile { + ListBase chunks; + unsigned int size; +} MemFile; + +/* actually only used writefile.c */ +extern void add_memfilechunk(MemFile *compare, MemFile *current, char *buf, unsigned int size); + +/* exports */ +extern void BLO_free_memfile(MemFile *memfile); +extern void BLO_merge_memfile(MemFile *first, MemFile *second); + +#endif + diff --git a/source/blender/blenloader/BLO_writefile.h b/source/blender/blenloader/BLO_writefile.h new file mode 100644 index 00000000000..cfa2fd7b0f6 --- /dev/null +++ b/source/blender/blenloader/BLO_writefile.h @@ -0,0 +1,44 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * external writefile function prototypes + */ + +#ifndef BLO_WRITEFILE_H +#define BLO_WRITEFILE_H + +struct MemFile; + +extern int BLO_write_file(char *dir, int write_flags, char **error_r); +extern int BLO_write_file_mem(struct MemFile *compare, struct MemFile *current, int write_flags, char **error_r); +extern void BLO_write_runtime(char *file, char *exename); + +#endif + diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt new file mode 100644 index 00000000000..3e21c1dc318 --- /dev/null +++ b/source/blender/blenloader/CMakeLists.txt @@ -0,0 +1,46 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +FILE(GLOB SRC intern/*.c) + +SET(INC + . ../../../intern/guardedalloc ../blenlib ../blenkernel + ../makesdna ../readblenfile ../include + ../python ../../kernel/gen_messaging + ../render/extern/include + ${ZLIB_INC} +) + +IF(WITH_VERSE) + ADD_DEFINITIONS(-DWITH_VERSE) + SET(INC ${INC} ${VERSE_INC}) +ENDIF(WITH_VERSE) + +BLENDERLIB(bf_blenloader "${SRC}" "${INC}") +#env.BlenderLib ( 'bf_blenloader', sources, Split(incs), Split(defs), libtype=['core','player'], priority = [70, 30] ) diff --git a/source/blender/blenloader/Makefile b/source/blender/blenloader/Makefile new file mode 100644 index 00000000000..0d7cd16453e --- /dev/null +++ b/source/blender/blenloader/Makefile @@ -0,0 +1,37 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# Bounces make to subdirectories. + +SOURCEDIR = source/blender/blenloader +DIRS = intern + +include nan_subdirs.mk diff --git a/source/blender/blenloader/SConscript b/source/blender/blenloader/SConscript new file mode 100644 index 00000000000..fb36b15e3e7 --- /dev/null +++ b/source/blender/blenloader/SConscript @@ -0,0 +1,18 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.c') + +incs = '. #/intern/guardedalloc ../blenlib ../blenkernel' +incs += ' ../makesdna ../readblenfile ../include' +incs += ' ../python ../../kernel/gen_messaging' +incs += ' ../render/extern/include' + +incs += ' ' + env['BF_ZLIB_INC'] + +defs = '' +if env['WITH_BF_VERSE']: + defs += ' WITH_VERSE' + incs += ' ' + env['BF_VERSE_INCLUDE'] + +env.BlenderLib ( 'bf_blenloader', sources, Split(incs), Split(defs), libtype=['core','player'], priority = [70, 30] ) diff --git a/source/blender/blenloader/intern/Makefile b/source/blender/blenloader/intern/Makefile new file mode 100644 index 00000000000..4fcb0e8db47 --- /dev/null +++ b/source/blender/blenloader/intern/Makefile @@ -0,0 +1,76 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = blenloader +DIR = $(OCGDIR)/blender/$(LIBNAME) + +include nan_compile.mk + +# CFLAGS += $(LEVEL_2_C_WARNINGS) + +# OpenGL and Python +CPPFLAGS += $(OGL_CPPFLAGS) +CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) + +# zlib +ifeq ($(OS),$(findstring $(OS), "solaris windows")) + CPPFLAGS += -I$(NAN_ZLIB)/include +endif + +ifeq ($(WITH_VERSE), true) + CPPFLAGS += -DWITH_VERSE + CPPFLAGS += -I$(NAN_VERSE)/include +endif + +# streaming write function +CPPFLAGS += -I../../writestreamglue +CPPFLAGS += -I../../readstreamglue + +# initiate a streaming read pipe +CPPFLAGS += -I../../readblenfile + +# This mod uses the GEN, DNA, BLI and BKE modules +CPPFLAGS += -I../../../kernel/gen_messaging +CPPFLAGS += -I../../makesdna +CPPFLAGS += -I../../blenlib +# path to the guarded memory allocator +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include +CPPFLAGS += -I../../blenkernel +CPPFLAGS += -I../../render/extern/include/ +CPPFLAGS += -I../../python + +# we still refer to /include a bit... +CPPFLAGS += -I../../include + +# path to our own external headerfiles +CPPFLAGS += -I.. diff --git a/source/blender/blenloader/intern/genfile.c b/source/blender/blenloader/intern/genfile.c new file mode 100644 index 00000000000..b21185e84a0 --- /dev/null +++ b/source/blender/blenloader/intern/genfile.c @@ -0,0 +1,1102 @@ +/* genfile.c + * + * Functions for struct-dna, the genetic file dot c! + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * DNA handling + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifndef WIN32 +#include // for read close +#else +#include // for open close read +#endif + +#include // strncmp +#include // for printf +#include // for atoi +#include // for open O_RDONLY + +#include "MEM_guardedalloc.h" // for MEM_freeN MEM_mallocN MEM_callocN +#include "BLI_blenlib.h" // for BLI_filesize + +#include "BKE_utildefines.h" // for O_BINARY TRUE MIN2 + +#include "DNA_sdna_types.h" // for SDNA ;-) + +#include "BLO_writefile.h" +#include "BLO_genfile.h" + +#include "genfile.h" + +/* gcc 4.1 on mingw was complaining that __int64 was alredy defined +actually is saw the line below as typedef long long long long... +Anyhow, since its alredy defined, its safe to do an ifndef here- Cambpell*/ +#ifdef FREE_WINDOWS +#ifndef __int64 +typedef long long __int64; +#endif +#endif + +/* + * - please note: no builtin security to detect input of double structs + * - if you want a struct not to be in DNA file: add two hash marks above it (##) + +Structure DNA data is added to each blender file and to each executable, this to detect +in .blend files new veriables in structs, changed array sizes, etc. It's also used for +converting endian and pointer size (32-64 bits) +As an extra, Python uses a call to detect run-time the contents of a blender struct. + +Create a structDNA: only needed when one of the input include (.h) files change. +File Syntax: + SDNA (4 bytes) (magic number) + NAME (4 bytes) + (4 bytes) amount of names (int) + + + ... + ... + TYPE (4 bytes) + amount of types (int) + + + ... + ... + TLEN (4 bytes) + (short) the lengths of types + + ... + ... + STRC (4 bytes) + amount of structs (int) + ... + +!!Remember to read/write integer and short aligned!! + + While writing a file, the names of a struct is indicated with a type number, + to be found with: type= findstruct_nr(SDNA *, char *) + The value of 'type' corresponds with the the index within the structs array + + For the moment: the complete DNA file is included in a .blend file. For + the future we can think of smarter methods, like only included the used + structs. Only needed to keep a file short though... + +ALLOWED AND TESTED CHANGES IN STRUCTS: + - type change (a char to float will be divided by 255) + - location within a struct (everthing can be randomly mixed up) + - struct within struct (within struct etc), this is recursive + - adding new elements, will be default initialized zero + - remving elements + - change of array sizes + - change of a pointer type: when the name doesn't change the contents is copied + +NOT YET: + - array (vec[3]) to float struct (vec3f) + +DONE: + - endian compatibility + - pointer conversion (32-64 bits) + +IMPORTANT: + - do not use #defines in structs for array lenghts, this cannot be read by the dna functions + - do not use uint, but unsigned int instead, ushort and ulong are allowed + - only use a long in Blender if you want this to be the size of a pointer. so it is + 32 bits or 64 bits, dependant at the cpu architecture + - chars are always unsigned + - aligment of variables has to be done in such a way, that any system does + not create 'padding' (gaps) in structures. So make sure that: + - short: 2 aligned + - int: 4 aligned + - float: 4 aligned + - double: 8 aligned + - long: 8 aligned + - struct: 8 aligned + - the sdna functions have several error prints builtin, always check blender running from a console. + +*/ + +/* local */ +static int le_int(int temp); +static short le_short(short temp); + +/* ************************* ENDIAN STUFF ********************** */ + +static short le_short(short temp) +{ + short new; + char *rt=(char *)&temp, *rtn=(char *)&new; + + rtn[0]= rt[1]; + rtn[1]= rt[0]; + + return new; +} + + +static int le_int(int temp) +{ + int new; + char *rt=(char *)&temp, *rtn=(char *)&new; + + rtn[0]= rt[3]; + rtn[1]= rt[2]; + rtn[2]= rt[1]; + rtn[3]= rt[0]; + + return new; +} + + +/* ************************* MAKE DNA ********************** */ + +/* allowed duplicate code from makesdna.c */ +static int arraysize(char *astr, int len) +{ + int a, mul=1; + char str[100], *cp=0; + + memcpy(str, astr, len+1); + + for(a=0; adata); + MEM_freeN(sdna->names); + MEM_freeN(sdna->types); + MEM_freeN(sdna->structs); + + MEM_freeN(sdna); +} + +static int elementsize(struct SDNA *sdna, short type, short name) +/* call with numbers from struct-array */ +{ + int mul, namelen, len; + char *cp; + + cp= sdna->names[name]; + len= 0; + + namelen= strlen(cp); + /* is it a pointer or function pointer? */ + if(cp[0]=='*' || cp[1]=='*') { + /* has the naam an extra length? (array) */ + mul= 1; + if( cp[namelen-1]==']') mul= arraysize(cp, namelen); + + len= sdna->pointerlen*mul; + } + else if( sdna->typelens[type] ) { + /* has the naam an extra length? (array) */ + mul= 1; + if( cp[namelen-1]==']') mul= arraysize(cp, namelen); + + len= mul*sdna->typelens[type]; + + } + + return len; +} + +#if 0 +static void printstruct(struct SDNA *sdna, short strnr) +{ + /* is for debug */ + int b, nr; + short *sp; + + sp= sdna->structs[strnr]; + + printf("struct %s\n", sdna->types[ sp[0] ]); + nr= sp[1]; + sp+= 2; + + for(b=0; b< nr; b++, sp+= 2) { + printf(" %s %s\n", sdna->types[sp[0]], sdna->names[sp[1]]); + } +} +#endif + +static short *findstruct_name(struct SDNA *sdna, char *str) +{ + int a; + short *sp=0; + + + for(a=0; anr_structs; a++) { + + sp= sdna->structs[a]; + + if(strcmp( sdna->types[ sp[0] ], str )==0) return sp; + } + + return 0; +} + +int dna_findstruct_nr(struct SDNA *sdna, char *str) +{ + short *sp=0; + int a; + + if(sdna->lastfindnr_structs) { + sp= sdna->structs[sdna->lastfind]; + if(strcmp( sdna->types[ sp[0] ], str )==0) return sdna->lastfind; + } + + for(a=0; anr_structs; a++) { + + sp= sdna->structs[a]; + + if(strcmp( sdna->types[ sp[0] ], str )==0) { + sdna->lastfind= a; + return a; + } + } + + return -1; +} + +/* ************************* END DIV ********************** */ + +/* ************************* READ DNA ********************** */ + +static void init_structDNA(struct SDNA *sdna, int do_endian_swap) +/* in sdna->data the data, now we convert that to something understandable */ +{ + int *data, *verg; + long nr; + short *sp; + char str[8], *cp; + + verg= (int *)str; + data= (int *)sdna->data; + + strcpy(str, "SDNA"); + if( *data == *verg ) { + + data++; + + /* load names array */ + strcpy(str, "NAME"); + if( *data == *verg ) { + data++; + + if(do_endian_swap) sdna->nr_names= le_int(*data); + else sdna->nr_names= *data; + + data++; + sdna->names= MEM_callocN( sizeof(void *)*sdna->nr_names, "sdnanames"); + } + else { + printf("NAME error in SDNA file\n"); + return; + } + + nr= 0; + cp= (char *)data; + while(nrnr_names) { + sdna->names[nr]= cp; + while( *cp) cp++; + cp++; + nr++; + } + nr= (long)cp; /* prevent BUS error */ + nr= (nr+3) & ~3; + cp= (char *)nr; + + /* load type names array */ + data= (int *)cp; + strcpy(str, "TYPE"); + if( *data == *verg ) { + data++; + + if(do_endian_swap) sdna->nr_types= le_int(*data); + else sdna->nr_types= *data; + + data++; + sdna->types= MEM_callocN( sizeof(void *)*sdna->nr_types, "sdnatypes"); + } + else { + printf("TYPE error in SDNA file\n"); + return; + } + + nr= 0; + cp= (char *)data; + while(nrnr_types) { + sdna->types[nr]= cp; + + /* this is a patch, to change struct names without a confict with SDNA */ + /* be careful to use it, in this case for a system-struct (opengl/X) */ + + if( *cp == 'b') { + /* struct Screen was already used by X, 'bScreen' replaces the old IrisGL 'Screen' struct */ + if( strcmp("bScreen", cp)==0 ) sdna->types[nr]= cp+1; + } + + while( *cp) cp++; + cp++; + nr++; + } + nr= (long)cp; /* prevent BUS error */ + nr= (nr+3) & ~3; + cp= (char *)nr; + + /* load typelen array */ + data= (int *)cp; + strcpy(str, "TLEN"); + if( *data == *verg ) { + data++; + sp= (short *)data; + sdna->typelens= sp; + + if(do_endian_swap) { + short a, *spo= sp; + + a= sdna->nr_types; + while(a--) { + spo[0]= le_short(spo[0]); + spo++; + } + } + + sp+= sdna->nr_types; + } + else { + printf("TLEN error in SDNA file\n"); + return; + } + if(sdna->nr_types & 1) sp++; /* prevent BUS error */ + + /* load struct array */ + data= (int *)sp; + strcpy(str, "STRC"); + if( *data == *verg ) { + data++; + + if(do_endian_swap) sdna->nr_structs= le_int(*data); + else sdna->nr_structs= *data; + + data++; + sdna->structs= MEM_callocN( sizeof(void *)*sdna->nr_structs, "sdnastrcs"); + } + else { + printf("STRC error in SDNA file\n"); + return; + } + + nr= 0; + sp= (short *)data; + while(nrnr_structs) { + sdna->structs[nr]= sp; + + if(do_endian_swap) { + short a; + + sp[0]= le_short(sp[0]); + sp[1]= le_short(sp[1]); + + a= sp[1]; + sp+= 2; + while(a--) { + sp[0]= le_short(sp[0]); + sp[1]= le_short(sp[1]); + sp+= 2; + } + } + else { + sp+= 2*sp[1]+2; + } + + nr++; + } + + /* finally pointerlen: use struct ListBase to test it, never change the size of it! */ + sp= findstruct_name(sdna, "ListBase"); + /* weird; i have no memory of that... I think I used sizeof(void *) before... (ton) */ + + sdna->pointerlen= sdna->typelens[ sp[0] ]/2; + + if(sp[1]!=2 || (sdna->pointerlen!=4 && sdna->pointerlen!=8)) { + printf("ListBase struct error! Needs it to calculate pointerize.\n"); + exit(0); + /* well, at least sizeof(ListBase) is error proof! (ton) */ + } + + } +} + +struct SDNA *dna_sdna_from_data(void *data, int datalen, int do_endian_swap) +{ + struct SDNA *sdna= MEM_mallocN(sizeof(*sdna), "sdna"); + + sdna->lastfind= 0; + + sdna->datalen= datalen; + sdna->data= MEM_mallocN(datalen, "sdna_data"); + memcpy(sdna->data, data, datalen); + + init_structDNA(sdna, do_endian_swap); + + return sdna; +} + +/* ******************** END READ DNA ********************** */ + +/* ******************* HANDLE DNA ***************** */ + +static void recurs_test_compflags(struct SDNA *sdna, char *compflags, int structnr) +{ + int a, b, typenr, elems; + short *sp; + char *cp; + + /* check all structs, test if it's inside another struct */ + sp= sdna->structs[structnr]; + typenr= sp[0]; + + for(a=0; anr_structs; a++) { + if(a!=structnr && compflags[a]==1) { + sp= sdna->structs[a]; + elems= sp[1]; + sp+= 2; + for(b=0; bnames[ sp[1] ]; + if(cp[0]!= '*') { + compflags[a]= 2; + recurs_test_compflags(sdna, compflags, a); + } + } + } + } + } + +} + + /* Unsure of exact function - compares the sdna argument to + * newsdna and sets up the information necessary to convert + * data written with a dna of oldsdna to inmemory data with a + * structure defined by the newsdna sdna (I think). -zr + */ + +/* well, the function below is just a lookup table to speed + * up reading files. doh! -ton + */ + + +char *dna_get_structDNA_compareflags(struct SDNA *sdna, struct SDNA *newsdna) +{ + /* flag: 0: doesn't exist anymore (or not yet) + * 1: is equal + * 2: is different + */ + int a, b; + short *spold, *spcur; + char *str1, *str2; + char *compflags; + + if(sdna->nr_structs==0) { + printf("error: file without SDNA\n"); + return NULL; + } + + compflags= MEM_callocN(sdna->nr_structs, "compflags"); + + /* we check all structs in 'sdna' and compare them with + * the structs in 'newsdna' + */ + + for(a=0; anr_structs; a++) { + spold= sdna->structs[a]; + + /* search for type in cur */ + spcur= findstruct_name(newsdna, sdna->types[spold[0]]); + + if(spcur) { + compflags[a]= 2; + + /* compare length and amount of elems */ + if( spcur[1] == spold[1]) { + if( newsdna->typelens[spcur[0]] == sdna->typelens[spold[0]] ) { + + /* same length, same amount of elems, now per type and name */ + b= spold[1]; + spold+= 2; + spcur+= 2; + while(b > 0) { + str1= newsdna->types[spcur[0]]; + str2= sdna->types[spold[0]]; + if(strcmp(str1, str2)!=0) break; + + str1= newsdna->names[spcur[1]]; + str2= sdna->names[spold[1]]; + if(strcmp(str1, str2)!=0) break; + + /* same type and same name, now pointersize */ + if(str1[0]=='*') { + if(sdna->pointerlen!=newsdna->pointerlen) break; + } + + b--; + spold+= 2; + spcur+= 2; + } + if(b==0) compflags[a]= 1; + + } + } + + } + } + + /* first struct in util.h is struct Link, this is skipped in compflags (als # 0). + * was a bug, and this way dirty patched! Solve this later.... + */ + compflags[0]= 1; + + /* Because structs can be inside structs, we recursively + * set flags when a struct is altered + */ + for(a=0; anr_structs; a++) { + if(compflags[a]==2) recurs_test_compflags(sdna, compflags, a); + } + +/* + for(a=0; anr_structs; a++) { + if(compflags[a]==2) { + spold= sdna->structs[a]; + printf("changed: %s\n", sdna->types[ spold[0] ]); + } + } +*/ + + return compflags; +} + +static void cast_elem(char *ctype, char *otype, char *name, char *curdata, char *olddata) +{ + double val = 0.0; + int arrlen, curlen=1, oldlen=1, ctypenr, otypenr; + + arrlen= arraysize(name, strlen(name)); + + /* define otypenr */ + if(strcmp(otype, "char")==0) otypenr= 0; + else if((strcmp(otype, "uchar")==0)||(strcmp(otype, "unsigned char")==0)) otypenr= 1; + else if(strcmp(otype, "short")==0) otypenr= 2; + else if((strcmp(otype, "ushort")==0)||(strcmp(otype, "unsigned short")==0)) otypenr= 3; + else if(strcmp(otype, "int")==0) otypenr= 4; + else if(strcmp(otype, "long")==0) otypenr= 5; + else if((strcmp(otype, "ulong")==0)||(strcmp(otype, "unsigned long")==0)) otypenr= 6; + else if(strcmp(otype, "float")==0) otypenr= 7; + else if(strcmp(otype, "double")==0) otypenr= 8; + else return; + + /* define ctypenr */ + if(strcmp(ctype, "char")==0) ctypenr= 0; + else if((strcmp(ctype, "uchar")==0)||(strcmp(ctype, "unsigned char")==0)) ctypenr= 1; + else if(strcmp(ctype, "short")==0) ctypenr= 2; + else if((strcmp(ctype, "ushort")==0)||(strcmp(ctype, "unsigned short")==0)) ctypenr= 3; + else if(strcmp(ctype, "int")==0) ctypenr= 4; + else if(strcmp(ctype, "long")==0) ctypenr= 5; + else if((strcmp(ctype, "ulong")==0)||(strcmp(ctype, "unsigned long")==0)) ctypenr= 6; + else if(strcmp(ctype, "float")==0) ctypenr= 7; + else if(strcmp(ctype, "double")==0) ctypenr= 8; + else return; + + /* define lengths */ + if(otypenr < 2) oldlen= 1; + else if(otypenr < 4) oldlen= 2; + else if(otypenr < 8) oldlen= 4; + else oldlen= 8; + + if(ctypenr < 2) curlen= 1; + else if(ctypenr < 4) curlen= 2; + else if(ctypenr < 8) curlen= 4; + else curlen= 8; + + while(arrlen>0) { + switch(otypenr) { + case 0: + val= *olddata; break; + case 1: + val= *( (unsigned char *)olddata); break; + case 2: + val= *( (short *)olddata); break; + case 3: + val= *( (unsigned short *)olddata); break; + case 4: + val= *( (int *)olddata); break; + case 5: + val= *( (int *)olddata); break; + case 6: + val= *( (unsigned int *)olddata); break; + case 7: + val= *( (float *)olddata); break; + case 8: + val= *( (double *)olddata); break; + } + + switch(ctypenr) { + case 0: + *curdata= val; break; + case 1: + *( (unsigned char *)curdata)= val; break; + case 2: + *( (short *)curdata)= val; break; + case 3: + *( (unsigned short *)curdata)= val; break; + case 4: + *( (int *)curdata)= val; break; + case 5: + *( (int *)curdata)= val; break; + case 6: + *( (unsigned int *)curdata)= val; break; + case 7: + if(otypenr<2) val/= 255; + *( (float *)curdata)= val; break; + case 8: + if(otypenr<2) val/= 255; + *( (double *)curdata)= val; break; + } + + olddata+= oldlen; + curdata+= curlen; + arrlen--; + } +} + +static void cast_pointer(int curlen, int oldlen, char *name, char *curdata, char *olddata) +{ +#ifdef WIN32 + __int64 lval; +#else + long long lval; +#endif + int arrlen; + + arrlen= arraysize(name, strlen(name)); + + while(arrlen>0) { + + if(curlen==oldlen) { + memcpy(curdata, olddata, curlen); + } + else if(curlen==4 && oldlen==8) { +#ifdef WIN32 + lval= *( (__int64 *)olddata ); +#else + lval= *( (long long *)olddata ); +#endif + *((int *)curdata) = lval>>3; /* is of course gambling! */ + } + else if(curlen==8 && oldlen==4) { +#ifdef WIN32 + *( (__int64 *)curdata ) = *((int *)olddata); +#else + *( (long long *)curdata ) = *((int *)olddata); +#endif + } + else { + /* for debug */ + printf("errpr: illegal pointersize! \n"); + } + + olddata+= oldlen; + curdata+= curlen; + arrlen--; + + } +} + +static int elem_strcmp(char *name, char *oname) +{ + int a=0; + + /* strcmp without array part */ + + while(TRUE) { + if(name[a] != oname[a]) return 1; + if(name[a]=='[') break; + if(name[a]==0) break; + a++; + } + if(name[a] != oname[a]) return 1; + return 0; +} + +static char *find_elem(struct SDNA *sdna, char *type, char *name, short *old, char *olddata, short **sppo) +{ + int a, elemcount, len; + char *otype, *oname; + + /* without arraypart, so names can differ: return old namenr and type */ + + /* in old is the old struct */ + elemcount= old[1]; + old+= 2; + for(a=0; atypes[old[0]]; + oname= sdna->names[old[1]]; + + len= elementsize(sdna, old[0], old[1]); + + if( elem_strcmp(name, oname)==0 ) { /* naam equal */ + if( strcmp(type, otype)==0 ) { /* type equal */ + if(sppo) *sppo= old; + return olddata; + } + + return 0; + } + + olddata+= len; + } + return 0; +} + +static void reconstruct_elem(struct SDNA *newsdna, struct SDNA *oldsdna, char *type, char *name, char *curdata, short *old, char *olddata) +{ + /* rules: test for NAME: + - name equal: + - cast type + - name partially equal (array differs) + - type equal: memcpy + - types casten + (nzc 2-4-2001 I want the 'unsigned' bit to be parsed as well. Where + can I force this?) + */ + int a, elemcount, len, array, oldsize, cursize, mul; + char *otype, *oname, *cp; + + /* is 'name' an array? */ + cp= name; + array= 0; + while( *cp && *cp!='[') { + cp++; array++; + } + if( *cp!= '[' ) array= 0; + + /* in old is the old struct */ + elemcount= old[1]; + old+= 2; + for(a=0; atypes[old[0]]; + oname= oldsdna->names[old[1]]; + len= elementsize(oldsdna, old[0], old[1]); + + if( strcmp(name, oname)==0 ) { /* name equal */ + + if( name[0]=='*') { /* pointer afhandelen */ + cast_pointer(newsdna->pointerlen, oldsdna->pointerlen, name, curdata, olddata); + } + else if( strcmp(type, otype)==0 ) { /* type equal */ + memcpy(curdata, olddata, len); + } + else cast_elem(type, otype, name, curdata, olddata); + + return; + } + else if(array) { /* name is an array */ + + if(oname[array]=='[' && strncmp(name, oname, array)==0 ) { /* basis equal */ + + cursize= arraysize(name, strlen(name)); + oldsize= arraysize(oname, strlen(oname)); + + if( name[0]=='*') { /* handle pointer */ + if(cursize>oldsize) cast_pointer(newsdna->pointerlen, oldsdna->pointerlen, oname, curdata, olddata); + else cast_pointer(newsdna->pointerlen, oldsdna->pointerlen, name, curdata, olddata); + } + else if(name[0]=='*' || strcmp(type, otype)==0 ) { /* type equal */ + mul= len/oldsize; + mul*= MIN2(cursize, oldsize); + memcpy(curdata, olddata, mul); + } + else { + if(cursize>oldsize) cast_elem(type, otype, oname, curdata, olddata); + else cast_elem(type, otype, name, curdata, olddata); + } + return; + } + } + olddata+= len; + } +} + +static void reconstruct_struct(struct SDNA *newsdna, struct SDNA *oldsdna, char *compflags, int oldSDNAnr, char *data, int curSDNAnr, char *cur) +{ + /* Recursive! + * Per element from cur_struct, read data from old_struct. + * If element is a struct, call recursive. + */ + int a, elemcount, elen, eleno, mul, mulo, firststructtypenr; + short *spo, *spc, *sppo; + char *name, *nameo, *type, *cpo, *cpc; + + if(oldSDNAnr== -1) return; + if(curSDNAnr== -1) return; + + if( compflags[oldSDNAnr]==1 ) { /* if recursive: test for equal */ + + spo= oldsdna->structs[oldSDNAnr]; + elen= oldsdna->typelens[ spo[0] ]; + memcpy( cur, data, elen); + + return; + } + + firststructtypenr= *(newsdna->structs[0]); + + spo= oldsdna->structs[oldSDNAnr]; + spc= newsdna->structs[curSDNAnr]; + + elemcount= spc[1]; + + spc+= 2; + cpc= cur; + for(a=0; atypes[spc[0]]; + name= newsdna->names[spc[1]]; + + elen= elementsize(newsdna, spc[0], spc[1]); + + /* test: is type a struct? */ + if(spc[0]>=firststructtypenr && name[0]!='*') { + + /* where does the old struct data start (and is there an old one?) */ + cpo= find_elem(oldsdna, type, name, spo, data, &sppo); + + if(cpo) { + oldSDNAnr= dna_findstruct_nr(oldsdna, type); + curSDNAnr= dna_findstruct_nr(newsdna, type); + + /* array! */ + mul= arraysize(name, strlen(name)); + nameo= oldsdna->names[sppo[1]]; + mulo= arraysize(nameo, strlen(nameo)); + + eleno= elementsize(oldsdna, sppo[0], sppo[1]); + + elen/= mul; + eleno/= mulo; + + while(mul--) { + reconstruct_struct(newsdna, oldsdna, compflags, oldSDNAnr, cpo, curSDNAnr, cpc); + cpo+= eleno; + cpc+= elen; + + /* new struct array larger than old */ + mulo--; + if(mulo<=0) break; + } + } + else cpc+= elen; + } + else { + + reconstruct_elem(newsdna, oldsdna, type, name, cpc, spo, data); + cpc+= elen; + + } + } +} + +void dna_switch_endian_struct(struct SDNA *oldsdna, int oldSDNAnr, char *data) +{ + /* Recursive! + * If element is a struct, call recursive. + */ + int a, mul, elemcount, elen, elena, firststructtypenr; + short *spo, *spc, skip; + char *name, *type, *cpo, *cur, cval; + + if(oldSDNAnr== -1) return; + firststructtypenr= *(oldsdna->structs[0]); + + spo= spc= oldsdna->structs[oldSDNAnr]; + + elemcount= spo[1]; + + spc+= 2; + cur= data; + + for(a=0; atypes[spc[0]]; + name= oldsdna->names[spc[1]]; + + /* elementsize = including arraysize */ + elen= elementsize(oldsdna, spc[0], spc[1]); + + /* test: is type a struct? */ + if(spc[0]>=firststructtypenr && name[0]!='*') { + /* where does the old data start (is there one?) */ + cpo= find_elem(oldsdna, type, name, spo, data, 0); + if(cpo) { + oldSDNAnr= dna_findstruct_nr(oldsdna, type); + + mul= arraysize(name, strlen(name)); + elena= elen/mul; + + while(mul--) { + dna_switch_endian_struct(oldsdna, oldSDNAnr, cpo); + cpo += elena; + } + } + } + else { + + if( name[0]=='*' ) { + if(oldsdna->pointerlen==8) { + + mul= arraysize(name, strlen(name)); + cpo= cur; + while(mul--) { + cval= cpo[0]; cpo[0]= cpo[7]; cpo[7]= cval; + cval= cpo[1]; cpo[1]= cpo[6]; cpo[6]= cval; + cval= cpo[2]; cpo[2]= cpo[5]; cpo[5]= cval; + cval= cpo[3]; cpo[3]= cpo[4]; cpo[4]= cval; + + cpo+= 8; + } + + } + } + else { + + if( spc[0]==2 || spc[0]==3 ) { /* short-ushort */ + + /* exception: variable called blocktype/ipowin: derived from ID_ */ + skip= 0; + if(name[0]=='b' && name[1]=='l') { + if(strcmp(name, "blocktype")==0) skip= 1; + } + else if(name[0]=='i' && name[1]=='p') { + if(strcmp(name, "ipowin")==0) skip= 1; + } + + if(skip==0) { + mul= arraysize(name, strlen(name)); + cpo= cur; + while(mul--) { + cval= cpo[0]; + cpo[0]= cpo[1]; + cpo[1]= cval; + cpo+= 2; + } + } + } + else if(spc[0]>3 && spc[0]<8) { /* int-long-ulong-float */ + + mul= arraysize(name, strlen(name)); + cpo= cur; + while(mul--) { + cval= cpo[0]; + cpo[0]= cpo[3]; + cpo[3]= cval; + cval= cpo[1]; + cpo[1]= cpo[2]; + cpo[2]= cval; + cpo+= 4; + } + } + } + } + cur+= elen; + } +} + +void *dna_reconstruct(struct SDNA *newsdna, struct SDNA *oldsdna, char *compflags, int oldSDNAnr, int blocks, void *data) +{ + int a, curSDNAnr, curlen=0, oldlen; + short *spo, *spc; + char *cur, *type, *cpc, *cpo; + + /* oldSDNAnr == structnr, we're looking for the corresponding 'cur' number */ + spo= oldsdna->structs[oldSDNAnr]; + type= oldsdna->types[ spo[0] ]; + oldlen= oldsdna->typelens[ spo[0] ]; + curSDNAnr= dna_findstruct_nr(newsdna, type); + + /* init data and alloc */ + if(curSDNAnr >= 0) { + spc= newsdna->structs[curSDNAnr]; + curlen= newsdna->typelens[ spc[0] ]; + } + if(curlen==0) { + return NULL; + } + + cur= MEM_callocN( blocks*curlen, "reconstruct"); + cpc= cur; + cpo= data; + for(a=0; astructs[SDNAnr]; + char *cp= find_elem(sdna, vartype, name, spo, NULL, NULL); + return (int)((long)cp); +} + + + diff --git a/source/blender/blenloader/intern/genfile.h b/source/blender/blenloader/intern/genfile.h new file mode 100644 index 00000000000..f027c14ac7a --- /dev/null +++ b/source/blender/blenloader/intern/genfile.h @@ -0,0 +1,49 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * blenloader genfile private function prototypes + */ + +#ifndef GENFILE_H +#define GENFILE_H + +struct SDNA; + +int dna_findstruct_nr(struct SDNA *sdna, char *str); +char *dna_get_structDNA_compareflags(struct SDNA *sdna, struct SDNA *newsdna); +void dna_switch_endian_struct(struct SDNA *oldsdna, int oldSDNAnr, char *data); +void *dna_reconstruct(struct SDNA *newsdna, struct SDNA *oldsdna, char *compflags, int oldSDNAnr, int blocks, void *data); +int dna_elem_offset(struct SDNA *sdna, char *stype, char *vartype, char *name); + +struct SDNA *dna_sdna_from_data(void *data, int datalen, int do_endian_swap); +void dna_freestructDNA(struct SDNA *sdna); + +#endif + diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c new file mode 100644 index 00000000000..ef287428a19 --- /dev/null +++ b/source/blender/blenloader/intern/readblenentry.c @@ -0,0 +1,456 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * .blend file reading entry point + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_ghash.h" +#include "BLI_linklist.h" + +#include "DNA_sdna_types.h" +#include "DNA_space_types.h" +#include "DNA_userdef_types.h" +#include "DNA_ID.h" +#include "DNA_material_types.h" + +#include "BKE_utildefines.h" // for ENDB + +#include "BKE_main.h" +#include "BKE_global.h" +#include "BKE_library.h" // for free_main + +#include "BLO_readfile.h" +#include "BLO_undofile.h" + +#include "readfile.h" +#include "genfile.h" + +#include "BLO_readblenfile.h" + + /** + * IDType stuff, I plan to move this + * out into its own file + prefix, and + * make sure all IDType handling goes through + * these routines. + */ + +typedef struct { + unsigned short code; + char *name; + + int flags; +#define IDTYPE_FLAGS_ISLINKABLE (1<<0) +} IDType; + +static IDType idtypes[]= { + { ID_AC, "Action", IDTYPE_FLAGS_ISLINKABLE}, + { ID_AR, "Armature", IDTYPE_FLAGS_ISLINKABLE}, + { ID_BR, "Brush", IDTYPE_FLAGS_ISLINKABLE}, + { ID_CA, "Camera", IDTYPE_FLAGS_ISLINKABLE}, + { ID_CU, "Curve", IDTYPE_FLAGS_ISLINKABLE}, + { ID_GR, "Group", IDTYPE_FLAGS_ISLINKABLE}, + { ID_ID, "ID", 0}, + { ID_IM, "Image", IDTYPE_FLAGS_ISLINKABLE}, + { ID_IP, "Ipo", IDTYPE_FLAGS_ISLINKABLE}, + { ID_KE, "Key", 0}, + { ID_LA, "Lamp", IDTYPE_FLAGS_ISLINKABLE}, + { ID_LF, "Life", 0}, + { ID_LI, "Library", 0}, + { ID_LT, "Lattice", IDTYPE_FLAGS_ISLINKABLE}, + { ID_MA, "Material", IDTYPE_FLAGS_ISLINKABLE}, + { ID_MB, "Metaball", IDTYPE_FLAGS_ISLINKABLE}, + { ID_ME, "Mesh", IDTYPE_FLAGS_ISLINKABLE}, + { ID_NT, "NodeTree", IDTYPE_FLAGS_ISLINKABLE}, + { ID_OB, "Object", IDTYPE_FLAGS_ISLINKABLE}, + { ID_SCE, "Scene", IDTYPE_FLAGS_ISLINKABLE}, + { ID_SCR, "Screen", 0}, + { ID_SEQ, "Sequence", 0}, + { ID_SE, "Sector", 0}, + { ID_SO, "Sound", IDTYPE_FLAGS_ISLINKABLE}, + { ID_TE, "Texture", IDTYPE_FLAGS_ISLINKABLE}, + { ID_TXT, "Text", IDTYPE_FLAGS_ISLINKABLE}, + { ID_VF, "VFont", IDTYPE_FLAGS_ISLINKABLE}, + { ID_WO, "World", IDTYPE_FLAGS_ISLINKABLE}, + { ID_WV, "Wave", 0}, +}; +static int nidtypes= sizeof(idtypes)/sizeof(idtypes[0]); + +/* local prototypes --------------------- */ +void BLO_blendhandle_print_sizes(BlendHandle *, void *); + + +static IDType *idtype_from_name(char *str) +{ + int i= nidtypes; + + while (i--) + if (BLI_streq(str, idtypes[i].name)) + return &idtypes[i]; + + return NULL; +} +static IDType *idtype_from_code(int code) +{ + int i= nidtypes; + + while (i--) + if (code==idtypes[i].code) + return &idtypes[i]; + + return NULL; +} + +static int bheadcode_is_idcode(int code) +{ + return idtype_from_code(code)?1:0; +} + +static int idcode_is_linkable(int code) { + IDType *idt= idtype_from_code(code); + return idt?(idt->flags&IDTYPE_FLAGS_ISLINKABLE):0; +} + +char *BLO_idcode_to_name(int code) +{ + IDType *idt= idtype_from_code(code); + + return idt?idt->name:NULL; +} + +int BLO_idcode_from_name(char *name) +{ + IDType *idt= idtype_from_name(name); + + return idt?idt->code:0; +} + + /* Access routines used by filesel. */ + +BlendHandle *BLO_blendhandle_from_file(char *file) +{ + BlendReadError err; + + return (BlendHandle*) blo_openblenderfile(file, &err); +} + +void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp) +{ + FileData *fd= (FileData*) bh; + BHead *bhead; + + fprintf(fp, "[\n"); + for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) { + if (bhead->code==ENDB) + break; + else { + short *sp= fd->filesdna->structs[bhead->SDNAnr]; + char *name= fd->filesdna->types[ sp[0] ]; + char buf[4]; + + buf[0]= (bhead->code>>24)&0xFF; + buf[1]= (bhead->code>>16)&0xFF; + buf[2]= (bhead->code>>8)&0xFF; + buf[3]= (bhead->code>>0)&0xFF; + + buf[0]= buf[0]?buf[0]:' '; + buf[1]= buf[1]?buf[1]:' '; + buf[2]= buf[2]?buf[2]:' '; + buf[3]= buf[3]?buf[3]:' '; + + fprintf(fp, "['%.4s', '%s', %d, %ld ], \n", buf, name, bhead->nr, (long)bhead->len+sizeof(BHead)); + } + } + fprintf(fp, "]\n"); +} + +LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype) +{ + FileData *fd= (FileData*) bh; + LinkNode *names= NULL; + BHead *bhead; + + for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) { + if (bhead->code==ofblocktype) { + char *idname= bhead_id_name(fd, bhead); + + BLI_linklist_prepend(&names, strdup(idname+2)); + } else if (bhead->code==ENDB) + break; + } + + return names; +} + +LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype) +{ + FileData *fd= (FileData*) bh; + LinkNode *previews= NULL; + BHead *bhead; + int looking=0; + int npreviews = 0; + PreviewImage* prv = NULL; + PreviewImage* new_prv = NULL; + + for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) { + if (bhead->code==ofblocktype) { + ID *id= (ID*) (bhead+1); + if ( (GS(id->name) == ID_MA) || (GS(id->name) == ID_TE)) { + new_prv = MEM_callocN(sizeof(PreviewImage), "newpreview"); + BLI_linklist_prepend(&previews, new_prv); + looking = 1; + } + } else if (bhead->code==DATA) { + if (looking) { + if (bhead->SDNAnr == dna_findstruct_nr(fd->filesdna, "PreviewImage") ) { + prv = (PreviewImage*) (bhead+1); + npreviews = 0; + memcpy(new_prv, prv, sizeof(PreviewImage)); + if (prv->rect[0]) { + unsigned int *rect = NULL; + int rectlen = 0; + new_prv->rect[0] = MEM_callocN(new_prv->w[0]*new_prv->h[0]*sizeof(unsigned int), "prvrect"); + bhead= blo_nextbhead(fd, bhead); + rect = (unsigned int*)(bhead+1); + rectlen = new_prv->w[0]*new_prv->h[0]*sizeof(unsigned int); + memcpy(new_prv->rect[0], rect, bhead->len); + } else { + new_prv->rect[0] = NULL; + } + + if (prv->rect[1]) { + unsigned int *rect = NULL; + int rectlen = 0; + new_prv->rect[1] = MEM_callocN(new_prv->w[1]*new_prv->h[1]*sizeof(unsigned int), "prvrect"); + bhead= blo_nextbhead(fd, bhead); + rect = (unsigned int*)(bhead+1); + rectlen = new_prv->w[1]*new_prv->h[1]*sizeof(unsigned int); + memcpy(new_prv->rect[1], rect, bhead->len); + } else { + new_prv->rect[1] = NULL; + } + } + } + } else if (bhead->code==ENDB) { + break; + } else if (bhead->code==DATA) { + /* DATA blocks between IDBlock and Preview */ + } else { + looking = 0; + new_prv = NULL; + prv = NULL; + } + + } + + return previews; +} + +LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh) +{ + FileData *fd= (FileData*) bh; + GHash *gathered= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + LinkNode *names= NULL; + BHead *bhead; + + for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) { + if (bhead->code==ENDB) { + break; + } else if (bheadcode_is_idcode(bhead->code)) { + if (idcode_is_linkable(bhead->code)) { + char *str= BLO_idcode_to_name(bhead->code); + + if (!BLI_ghash_haskey(gathered, str)) { + BLI_linklist_prepend(&names, strdup(str)); + BLI_ghash_insert(gathered, str, NULL); + } + } + } + } + + BLI_ghash_free(gathered, NULL, NULL); + + return names; +} + +void BLO_blendhandle_close(BlendHandle *bh) { + FileData *fd= (FileData*) bh; + + blo_freefiledata(fd); +} + + /**********/ + +BlendFileData *BLO_read_from_file(char *file, BlendReadError *error_r) +{ + BlendFileData *bfd = NULL; + FileData *fd; + + fd = blo_openblenderfile(file, error_r); + if (fd) { + bfd= blo_read_file_internal(fd, error_r); + if (bfd) { + bfd->type= BLENFILETYPE_BLEND; + strncpy(bfd->main->name, file, sizeof(bfd->main->name)-1); + } + blo_freefiledata(fd); + } + + return bfd; +} + +BlendFileData *BLO_read_from_memory(void *mem, int memsize, BlendReadError *error_r) +{ + BlendFileData *bfd = NULL; + FileData *fd; + + fd = blo_openblendermemory(mem, memsize, error_r); + if (fd) { + bfd= blo_read_file_internal(fd, error_r); + if (bfd) { + bfd->type= BLENFILETYPE_BLEND; + strcpy(bfd->main->name, ""); + } + blo_freefiledata(fd); + } + + return bfd; +} + +BlendFileData *BLO_read_from_memfile(const char *filename, MemFile *memfile, BlendReadError *error_r) +{ + BlendFileData *bfd = NULL; + FileData *fd; + ListBase mainlist; + + fd = blo_openblendermemfile(memfile, error_r); + if (fd) { + strcpy(fd->filename, filename); + + /* separate libraries from G.main */ + blo_split_main(&mainlist, G.main); + /* add the library pointers in oldmap lookup */ + blo_add_library_pointer_map(&mainlist, fd); + + /* makes lookup of existing images in G.main */ + blo_make_image_pointer_map(fd); + + bfd= blo_read_file_internal(fd, error_r); + if (bfd) { + bfd->type= BLENFILETYPE_BLEND; + strcpy(bfd->main->name, ""); + } + + /* ensures relinked images are not freed */ + blo_end_image_pointer_map(fd); + + /* move libraries from G.main to new main */ + if(bfd && mainlist.first!=mainlist.last) { + + /* Library structs themselves */ + bfd->main->library= G.main->library; + G.main->library.first= G.main->library.last= NULL; + + /* add the Library mainlist to the new main */ + BLI_remlink(&mainlist, G.main); + BLI_addhead(&mainlist, bfd->main); + } + blo_join_main(&mainlist); + + blo_freefiledata(fd); + } + + return bfd; +} + +void BLO_blendfiledata_free(BlendFileData *bfd) +{ + if (bfd->main) { + free_main(bfd->main); + } + + if (bfd->user) { + MEM_freeN(bfd->user); + } + + MEM_freeN(bfd); +} + +char *BLO_bre_as_string(BlendReadError error) +{ + switch (error) { + case BRE_NONE: + return "No error"; + + case BRE_UNABLE_TO_OPEN: + return "Unable to open"; + case BRE_UNABLE_TO_READ: + return "Unable to read"; + + case BRE_OUT_OF_MEMORY: + return "Out of memory"; + case BRE_INTERNAL_ERROR: + return ""; + + case BRE_NOT_A_BLEND: + return "File is not a Blender file"; + case BRE_NOT_A_PUBFILE: + return "File is not a compressed, locked or signed Blender file"; + case BRE_INCOMPLETE: + return "File incomplete"; + case BRE_CORRUPT: + return "File corrupt"; + + case BRE_TOO_NEW: + return "File needs newer Blender version, please upgrade"; + case BRE_NOT_ALLOWED: + return "File is locked"; + + case BRE_NO_SCREEN: + return "File has no screen"; + case BRE_NO_SCENE: + return "File has no scene"; + + default: + case BRE_INVALID: + return ""; + } +} diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c new file mode 100644 index 00000000000..384a6d93480 --- /dev/null +++ b/source/blender/blenloader/intern/readfile.c @@ -0,0 +1,8134 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "zlib.h" + +#ifdef WIN32 +#include "winsock2.h" +#include "BLI_winstuff.h" +#endif + +#include // for printf fopen fwrite fclose sprintf FILE +#include // for getenv atoi +#include // for open +#include // for strrchr strncmp strstr +#include // for fabs + +#ifndef WIN32 + #include // for read close + #include // for MAXPATHLEN +#else + #include // for open close read +#endif + +#include "nla.h" + +#include "DNA_action_types.h" +#include "DNA_armature_types.h" +#include "DNA_ID.h" +#include "DNA_actuator_types.h" +#include "DNA_brush_types.h" +#include "DNA_camera_types.h" +#include "DNA_color_types.h" +#include "DNA_controller_types.h" +#include "DNA_constraint_types.h" +#include "DNA_curve_types.h" +#include "DNA_customdata_types.h" +#include "DNA_effect_types.h" +#include "DNA_fileglobal_types.h" +#include "DNA_group_types.h" +#include "DNA_ipo_types.h" +#include "DNA_image_types.h" +#include "DNA_key_types.h" +#include "DNA_lattice_types.h" +#include "DNA_lamp_types.h" +#include "DNA_meta_types.h" +#include "DNA_material_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_nla_types.h" +#include "DNA_node_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force.h" +#include "DNA_object_fluidsim.h" // NT +#include "DNA_oops_types.h" +#include "DNA_object_force.h" +#include "DNA_packedFile_types.h" +#include "DNA_property_types.h" +#include "DNA_text_types.h" +#include "DNA_view3d_types.h" +#include "DNA_screen_types.h" +#include "DNA_sensor_types.h" +#include "DNA_sdna_types.h" +#include "DNA_scene_types.h" +#include "DNA_sequence_types.h" +#include "DNA_sound_types.h" +#include "DNA_space_types.h" +#include "DNA_texture_types.h" +#include "DNA_userdef_types.h" +#include "DNA_vfont_types.h" +#include "DNA_world_types.h" + +#include "MEM_guardedalloc.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_storage_types.h" // for relname flags + +#include "BDR_sculptmode.h" + +#include "BKE_bad_level_calls.h" // for reopen_text build_seqar (from WHILE_SEQ) set_rects_butspace check_imasel_copy + +#include "BKE_action.h" +#include "BKE_armature.h" +#include "BKE_colortools.h" +#include "BKE_constraint.h" +#include "BKE_curve.h" +#include "BKE_customdata.h" +#include "BKE_deform.h" +#include "BKE_depsgraph.h" +#include "BKE_effect.h" // for give_parteff +#include "BKE_global.h" // for G +#include "BKE_group.h" +#include "BKE_image.h" +#include "BKE_lattice.h" +#include "BKE_library.h" // for wich_libbase +#include "BKE_main.h" // for Main +#include "BKE_mesh.h" // for ME_ defines (patching) +#include "BKE_modifier.h" +#include "BKE_node.h" // for tree type defines +#include "BKE_object.h" +#include "BKE_property.h" // for get_property +#include "BKE_sca.h" // for init_actuator +#include "BKE_scene.h" +#include "BKE_softbody.h" // sbNew() +#include "BKE_texture.h" // for open_plugin_tex +#include "BKE_utildefines.h" // SWITCH_INT DATA ENDB DNA1 O_BINARY GLOB USER TEST REND +#include "BKE_idprop.h" + +#include "BIF_butspace.h" // badlevel, for do_versions, patching event codes +#include "BIF_filelist.h" // badlevel too, where to move this? - elubie +#include "BIF_previewrender.h" // bedlelvel, for struct RenderInfo +#include "BLO_readfile.h" +#include "BLO_undofile.h" +#include "BLO_readblenfile.h" // streaming read pipe, for BLO_readblenfile BLO_readblenfilememory + +#include "multires.h" + +#include "readfile.h" + +#include "genfile.h" + +#include "mydevice.h" +#include "blendef.h" + +#include + +/* + Remark: still a weak point is the newadress() function, that doesnt solve reading from + multiple files at the same time + + (added remark: oh, i thought that was solved? will look at that... (ton) + +READ +- Existing Library (Main) push or free +- allocate new Main +- load file +- read SDNA +- for each LibBlock + - read LibBlock + - if a Library + - make a new Main + - attach ID's to it + - else + - read associated 'direct data' + - link direct data (internal and to LibBlock) +- read FileGlobal +- read USER data, only when indicated (file is ~/.B.blend) +- free file +- per Library (per Main) + - read file + - read SDNA + - find LibBlocks and attach IDs to Main + - if external LibBlock + - search all Main's + - or it's already read, + - or not read yet + - or make new Main + - per LibBlock + - read recursive + - read associated direct data + - link direct data (internal and to LibBlock) + - free file +- per Library with unread LibBlocks + - read file + - read SDNA + - per LibBlock + - read recursive + - read associated direct data + - link direct data (internal and to LibBlock) + - free file +- join all Mains +- link all LibBlocks and indirect pointers to libblocks +- initialize FileGlobal and copy pointers to Global +*/ + +/* also occurs in library.c */ +/* GS reads the memory pointed at in a specific ordering. There are, + * however two definitions for it. I have jotted them down here, both, + * but I think the first one is actually used. The thing is that + * big-endian systems might read this the wrong way round. OTOH, we + * constructed the IDs that are read out with this macro explicitly as + * well. I expect we'll sort it out soon... */ + +/* from blendef: */ +#define GS(a) (*((short *)(a))) + +/* from misc_util: flip the bytes from x */ +/* #define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1]) */ + +// only used here in readfile.c +#define SWITCH_LONGINT(a) { \ + char s_i, *p_i; \ + p_i= (char *)&(a); \ + s_i=p_i[0]; p_i[0]=p_i[7]; p_i[7]=s_i; \ + s_i=p_i[1]; p_i[1]=p_i[6]; p_i[6]=s_i; \ + s_i=p_i[2]; p_i[2]=p_i[5]; p_i[5]=s_i; \ + s_i=p_i[3]; p_i[3]=p_i[4]; p_i[4]=s_i; } + +/***/ + +typedef struct OldNew { + void *old, *newp; + int nr; +} OldNew; + +typedef struct OldNewMap { + OldNew *entries; + int nentries, entriessize; + int sorted; + int lasthit; +} OldNewMap; + + +/* local prototypes */ +static void *read_struct(FileData *fd, BHead *bh, char *blockname); + + +static OldNewMap *oldnewmap_new(void) +{ + OldNewMap *onm= MEM_callocN(sizeof(*onm), "OldNewMap"); + + onm->entriessize= 1024; + onm->entries= MEM_mallocN(sizeof(*onm->entries)*onm->entriessize, "OldNewMap.entries"); + + return onm; +} + +static int verg_oldnewmap(const void *v1, const void *v2) +{ + const struct OldNew *x1=v1, *x2=v2; + + if( x1->old > x2->old) return 1; + else if( x1->old < x2->old) return -1; + return 0; +} + + +static void oldnewmap_sort(FileData *fd) +{ + qsort(fd->libmap->entries, fd->libmap->nentries, sizeof(OldNew), verg_oldnewmap); + fd->libmap->sorted= 1; +} + +/* nr is zero for data, and ID code for libdata */ +static void oldnewmap_insert(OldNewMap *onm, void *oldaddr, void *newaddr, int nr) +{ + OldNew *entry; + + if(oldaddr==NULL || newaddr==NULL) return; + + if (onm->nentries==onm->entriessize) { + int osize= onm->entriessize; + OldNew *oentries= onm->entries; + + onm->entriessize*= 2; + onm->entries= MEM_mallocN(sizeof(*onm->entries)*onm->entriessize, "OldNewMap.entries"); + + memcpy(onm->entries, oentries, sizeof(*oentries)*osize); + MEM_freeN(oentries); + } + + entry= &onm->entries[onm->nentries++]; + entry->old= oldaddr; + entry->newp= newaddr; + entry->nr= nr; +} + +static void *oldnewmap_lookup_and_inc(OldNewMap *onm, void *addr) +{ + int i; + + if (onm->lasthitnentries-1) { + OldNew *entry= &onm->entries[++onm->lasthit]; + + if (entry->old==addr) { + entry->nr++; + return entry->newp; + } + } + + for (i=0; inentries; i++) { + OldNew *entry= &onm->entries[i]; + + if (entry->old==addr) { + onm->lasthit= i; + + entry->nr++; + return entry->newp; + } + } + + return NULL; +} + +/* for libdata, nr has ID code, no increment */ +static void *oldnewmap_liblookup(OldNewMap *onm, void *addr, void *lib) +{ + int i; + + if(addr==NULL) return NULL; + + /* lasthit works fine for non-libdata, linking there is done in same sequence as writing */ + if(onm->sorted) { + OldNew entry_s, *entry; + + entry_s.old= addr; + + entry= bsearch(&entry_s, onm->entries, onm->nentries, sizeof(OldNew), verg_oldnewmap); + if(entry) { + ID *id= entry->newp; + + if (id && (!lib || id->lib)) { + return entry->newp; + } + } + } + + for (i=0; inentries; i++) { + OldNew *entry= &onm->entries[i]; + + if (entry->old==addr) { + ID *id= entry->newp; + + if (id && (!lib || id->lib)) { + return entry->newp; + } + } + } + + return NULL; +} + +static void oldnewmap_free_unused(OldNewMap *onm) +{ + int i; + + for (i=0; inentries; i++) { + OldNew *entry= &onm->entries[i]; + if (entry->nr==0) { + MEM_freeN(entry->newp); + entry->newp= NULL; + } + } +} + +static void oldnewmap_clear(OldNewMap *onm) +{ + onm->nentries= 0; + onm->lasthit= 0; +} + +static void oldnewmap_free(OldNewMap *onm) +{ + MEM_freeN(onm->entries); + MEM_freeN(onm); +} + +/***/ + +static void read_libraries(FileData *basefd, ListBase *mainlist); + +/* ************ help functions ***************** */ + +static void add_main_to_main(Main *mainvar, Main *from) +{ + ListBase *lbarray[MAX_LIBARRAY], *fromarray[MAX_LIBARRAY]; + int a; + + a= set_listbasepointers(mainvar, lbarray); + a= set_listbasepointers(from, fromarray); + while(a--) { + addlisttolist(lbarray[a], fromarray[a]); + } +} + +void blo_join_main(ListBase *mainlist) +{ + Main *tojoin, *mainl; + + + mainl= mainlist->first; + while ((tojoin= mainl->next)) { + add_main_to_main(mainl, tojoin); + BLI_remlink(mainlist, tojoin); + MEM_freeN(tojoin); + } +} + +static void split_libdata(ListBase *lb, Main *first) +{ + ListBase *lbn; + ID *id, *idnext; + Main *mainvar; + + id= lb->first; + while(id) { + idnext= id->next; + if(id->lib) { + mainvar= first; + while(mainvar) { + if(mainvar->curlib==id->lib) { + lbn= wich_libbase(mainvar, GS(id->name)); + BLI_remlink(lb, id); + BLI_addtail(lbn, id); + break; + } + mainvar= mainvar->next; + } + if(mainvar==0) printf("error split_libdata\n"); + } + id= idnext; + } +} + +void blo_split_main(ListBase *mainlist, Main *main) +{ + ListBase *lbarray[MAX_LIBARRAY]; + Library *lib; + int i; + + mainlist->first= mainlist->last= main; + main->next= NULL; + + if(main->library.first==NULL) + return; + + for (lib= main->library.first; lib; lib= lib->id.next) { + Main *libmain= MEM_callocN(sizeof(Main), "libmain"); + libmain->curlib= lib; + BLI_addtail(mainlist, libmain); + } + + i= set_listbasepointers(main, lbarray); + while(i--) + split_libdata(lbarray[i], main->next); +} + +/* removes things like /blah/blah/../../blah/ etc, then writes in *name the full path */ +static void cleanup_path(const char *relabase, char *name) +{ + char filename[FILE_MAXFILE]; + + BLI_splitdirstring(name, filename); + BLI_cleanup_dir(relabase, name); + strcat(name, filename); +} + +static Main *blo_find_main(ListBase *mainlist, const char *name, const char *relabase) +{ + Main *m; + Library *lib; + char name1[FILE_MAXDIR+FILE_MAXFILE]; + + strncpy(name1, name, sizeof(name1)-1); + cleanup_path(relabase, name1); +// printf("blo_find_main: original in %s\n", name); +// printf("blo_find_main: converted to %s\n", name1); + + for (m= mainlist->first; m; m= m->next) { + char *libname= (m->curlib)?m->curlib->filename:m->name; + + if (BLI_streq(name1, libname)) { + if(G.f & G_DEBUG) printf("blo_find_main: found library %s\n", libname); + return m; + } + } + + m= MEM_callocN(sizeof(Main), "find_main"); + BLI_addtail(mainlist, m); + + lib= alloc_libblock(&m->library, ID_LI, "lib"); + strncpy(lib->name, name, sizeof(lib->name)-1); + BLI_strncpy(lib->filename, name1, sizeof(lib->filename)); + + m->curlib= lib; + + if(G.f & G_DEBUG) printf("blo_find_main: added new lib %s\n", name); + return m; +} + + +/* ************ FILE PARSING ****************** */ + +static void switch_endian_bh4(BHead4 *bhead) +{ + /* the ID_.. codes */ + if((bhead->code & 0xFFFF)==0) bhead->code >>=16; + + if (bhead->code != ENDB) { + SWITCH_INT(bhead->len); + SWITCH_INT(bhead->SDNAnr); + SWITCH_INT(bhead->nr); + } +} + +static void switch_endian_bh8(BHead8 *bhead) +{ + /* the ID_.. codes */ + if((bhead->code & 0xFFFF)==0) bhead->code >>=16; + + if (bhead->code != ENDB) { + SWITCH_INT(bhead->len); + SWITCH_INT(bhead->SDNAnr); + SWITCH_INT(bhead->nr); + } +} + +static void bh4_from_bh8(BHead *bhead, BHead8 *bhead8, int do_endian_swap) +{ + BHead4 *bhead4 = (BHead4 *) bhead; +#if defined(WIN32) && !defined(FREE_WINDOWS) + __int64 old; +#else + long long old; +#endif + + bhead4->code= bhead8->code; + bhead4->len= bhead8->len; + + if (bhead4->code != ENDB) { + + // why is this here ?? + if (do_endian_swap) { + SWITCH_LONGINT(bhead8->old); + } + + /* this patch is to avoid a long long being read from not-eight aligned positions + is necessary on any modern 64bit architecture) */ + memcpy(&old, &bhead8->old, 8); + bhead4->old = (int) (old >> 3); + + bhead4->SDNAnr= bhead8->SDNAnr; + bhead4->nr= bhead8->nr; + } +} + +static void bh8_from_bh4(BHead *bhead, BHead4 *bhead4) +{ + BHead8 *bhead8 = (BHead8 *) bhead; + + bhead8->code= bhead4->code; + bhead8->len= bhead4->len; + + if (bhead8->code != ENDB) { + bhead8->old= bhead4->old; + bhead8->SDNAnr= bhead4->SDNAnr; + bhead8->nr= bhead4->nr; + } +} + +static BHeadN *get_bhead(FileData *fd) +{ + BHead8 bhead8; + BHead4 bhead4; + BHead bhead; + BHeadN *new_bhead = 0; + int readsize; + + if (fd) { + if ( ! fd->eof) { + + // First read the bhead structure. + // Depending on the platform the file was written on this can + // be a big or little endian BHead4 or BHead8 structure. + + // As usual 'ENDB' (the last *partial* bhead of the file) + // needs some special handling. We don't want to EOF just yet. + + if (fd->flags & FD_FLAGS_FILE_POINTSIZE_IS_4) { + bhead4.code = DATA; + readsize = fd->read(fd, &bhead4, sizeof(bhead4)); + + if (readsize == sizeof(bhead4) || bhead4.code == ENDB) { + if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) { + switch_endian_bh4(&bhead4); + } + + if (fd->flags & FD_FLAGS_POINTSIZE_DIFFERS) { + bh8_from_bh4(&bhead, &bhead4); + } else { + memcpy(&bhead, &bhead4, sizeof(bhead)); + } + } else { + fd->eof = 1; + bhead.len= 0; + } + } else { + bhead8.code = DATA; + readsize = fd->read(fd, &bhead8, sizeof(bhead8)); + + if (readsize == sizeof(bhead8) || bhead8.code == ENDB) { + if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) { + switch_endian_bh8(&bhead8); + } + + if (fd->flags & FD_FLAGS_POINTSIZE_DIFFERS) { + bh4_from_bh8(&bhead, &bhead8, (fd->flags & FD_FLAGS_SWITCH_ENDIAN)); + } else { + memcpy(&bhead, &bhead8, sizeof(bhead)); + } + } else { + fd->eof = 1; + bhead.len= 0; + } + } + + /* make sure people are not trying to pass bad blend files */ + if (bhead.len < 0) fd->eof = 1; + + // bhead now contains the (converted) bhead structure. Now read + // the associated data and put everything in a BHeadN (creative naming !) + + if ( ! fd->eof) { + new_bhead = MEM_mallocN(sizeof(BHeadN) + bhead.len, "new_bhead"); + if (new_bhead) { + new_bhead->next = new_bhead->prev = 0; + new_bhead->bhead = bhead; + + readsize = fd->read(fd, new_bhead + 1, bhead.len); + + if (readsize != bhead.len) { + fd->eof = 1; + MEM_freeN(new_bhead); + new_bhead = 0; + } + } else { + fd->eof = 1; + } + } + } + } + + // We've read a new block. Now add it to the list + // of blocks. + + if (new_bhead) { + BLI_addtail(&fd->listbase, new_bhead); + } + + return(new_bhead); +} + +BHead *blo_firstbhead(FileData *fd) +{ + BHeadN *new_bhead; + BHead *bhead = 0; + + // Rewind the file + // Read in a new block if necessary + + new_bhead = fd->listbase.first; + if (new_bhead == 0) { + new_bhead = get_bhead(fd); + } + + if (new_bhead) { + bhead = &new_bhead->bhead; + } + + return(bhead); +} + +BHead *blo_prevbhead(FileData *fd, BHead *thisblock) +{ + BHeadN *bheadn= (BHeadN *) (((char *) thisblock) - (int) (&((BHeadN*)0)->bhead)); + BHeadN *prev= bheadn->prev; + + return prev?&prev->bhead:NULL; +} + +BHead *blo_nextbhead(FileData *fd, BHead *thisblock) +{ + BHeadN *new_bhead = 0; + BHead *bhead = 0; + + if (thisblock) { + // bhead is actually a sub part of BHeadN + // We calculate the BHeadN pointer from the BHead pointer below + new_bhead = (BHeadN *) (((char *) thisblock) - (int) (&((BHeadN*)0)->bhead)); + + // get the next BHeadN. If it doesn't exist we read in the next one + new_bhead = new_bhead->next; + if (new_bhead == 0) { + new_bhead = get_bhead(fd); + } + } + + if (new_bhead) { + // here we do the reverse: + // go from the BHeadN pointer to the BHead pointer + bhead = &new_bhead->bhead; + } + + return(bhead); +} + +#if 0 +static void get_blender_subversion(FileData *fd) +{ + BHead *bhead; + + for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) { + if (bhead->code==GLOB) { + FileGlobal *fg= read_struct(fd, bhead, "Global"); + fd->filesubversion= fg->subversion; + fd->fileminversion= fg->minversion; + fd->fileminsubversion= fg->minsubversion; + MEM_freeN(fg); + return; + } + else if (bhead->code==ENDB) + break; + } +} +#endif + +static void decode_blender_header(FileData *fd) +{ + char header[SIZEOFBLENDERHEADER], num[4]; + int readsize; + + // read in the header data + readsize = fd->read(fd, header, sizeof(header)); + + if (readsize == sizeof(header)) { + if(strncmp(header, "BLENDER", 7) == 0) { + int remove_this_endian_test= 1; + + fd->flags |= FD_FLAGS_FILE_OK; + + // what size are pointers in the file ? + if(header[7]=='_') { + fd->flags |= FD_FLAGS_FILE_POINTSIZE_IS_4; + if (sizeof(void *) != 4) { + fd->flags |= FD_FLAGS_POINTSIZE_DIFFERS; + } + } else { + if (sizeof(void *) != 8) { + fd->flags |= FD_FLAGS_POINTSIZE_DIFFERS; + } + } + + // is the file saved in a different endian + // than we need ? + if (((((char*)&remove_this_endian_test)[0]==1)?L_ENDIAN:B_ENDIAN) != ((header[8]=='v')?L_ENDIAN:B_ENDIAN)) { + fd->flags |= FD_FLAGS_SWITCH_ENDIAN; + } + + // get the version number + + memcpy(num, header+9, 3); + num[3] = 0; + fd->fileversion = atoi(num); + } + } +} + +static int read_file_dna(FileData *fd) +{ + BHead *bhead; + + for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) { + if (bhead->code==DNA1) { + int do_endian_swap= (fd->flags&FD_FLAGS_SWITCH_ENDIAN)?1:0; + + fd->filesdna= dna_sdna_from_data(&bhead[1], bhead->len, do_endian_swap); + if (fd->filesdna) { + + fd->compflags= dna_get_structDNA_compareflags(fd->filesdna, fd->memsdna); + /* used to retrieve ID names from (bhead+1) */ + fd->id_name_offs= dna_elem_offset(fd->filesdna, "ID", "char", "name[]"); + } + + return 1; + } else if (bhead->code==ENDB) + break; + } + + return 0; +} + +static int fd_read_from_file(FileData *filedata, void *buffer, int size) +{ + int readsize = read(filedata->filedes, buffer, size); + + if (readsize < 0) { + readsize = EOF; + } else { + filedata->seek += readsize; + } + + return (readsize); +} + +static int fd_read_gzip_from_file(FileData *filedata, void *buffer, int size) +{ + int readsize = gzread(filedata->gzfiledes, buffer, size); + + if (readsize < 0) { + readsize = EOF; + } else { + filedata->seek += readsize; + } + + return (readsize); +} + +static int fd_read_from_memory(FileData *filedata, void *buffer, int size) +{ + // don't read more bytes then there are available in the buffer + int readsize = MIN2(size, filedata->buffersize - filedata->seek); + + memcpy(buffer, filedata->buffer + filedata->seek, readsize); + filedata->seek += readsize; + + return (readsize); +} + +static int fd_read_from_memfile(FileData *filedata, void *buffer, int size) +{ + static unsigned int seek= 1<<30; /* the current position */ + static unsigned int offset= 0; /* size of previous chunks */ + static MemFileChunk *chunk=NULL; + + if(size==0) return 0; + + if(seek != (unsigned int)filedata->seek) { + chunk= filedata->memfile->chunks.first; + seek= 0; + + while(chunk) { + if(seek + chunk->size > (unsigned) filedata->seek) break; + seek+= chunk->size; + chunk= chunk->next; + } + offset= seek; + seek= filedata->seek; + } + + if(chunk) { + /* first check if it's on the end if current chunk */ + if( seek-offset == chunk->size) { + offset+= chunk->size; + chunk= chunk->next; + } + + /* debug, should never happen */ + if(chunk==NULL) { + printf("illegal read, chunk zero\n"); + return 0; + } + else if( (seek-offset)+size > chunk->size) { + size= chunk->size - (seek-offset); + printf("chunk too large, clipped to %d\n", size); + } + + memcpy(buffer, chunk->buf + (seek-offset), size); + filedata->seek += size; + seek+= size; + + return (size); + + } + return 0; +} + +static FileData *filedata_new(void) +{ + extern unsigned char DNAstr[]; /* DNA.c */ + extern int DNAlen; + FileData *fd = MEM_callocN(sizeof(FileData), "FileData"); + + fd->filedes = -1; + fd->gzfiledes = NULL; + + /* XXX, this doesn't need to be done all the time, + * but it keeps us reentrant, remove once we have + * a lib that provides a nice lock. - zr + */ + fd->memsdna = dna_sdna_from_data(DNAstr, DNAlen, 0); + + fd->datamap = oldnewmap_new(); + fd->globmap = oldnewmap_new(); + fd->libmap = oldnewmap_new(); + + return fd; +} + +static FileData *blo_decode_and_check(FileData *fd, BlendReadError *error_r) +{ + decode_blender_header(fd); + + if (fd->flags & FD_FLAGS_FILE_OK) { + if (!read_file_dna(fd)) { + *error_r = BRE_INCOMPLETE; + blo_freefiledata(fd); + fd= NULL; + } + } + else { + *error_r = BRE_NOT_A_BLEND; + blo_freefiledata(fd); + fd= NULL; + } + + return fd; +} + +/* cannot be called with relative paths anymore! */ +/* on each new library added, it now checks for the current FileData and expands relativeness */ +FileData *blo_openblenderfile(char *name, BlendReadError *error_r) +{ + gzFile gzfile; + + gzfile= gzopen(name, "rb"); + + if (NULL == gzfile) { + *error_r = BRE_UNABLE_TO_OPEN; + return NULL; + } else { + FileData *fd = filedata_new(); + fd->gzfiledes = gzfile; + BLI_strncpy(fd->filename, name, sizeof(fd->filename)); // now only in use by library append + fd->read = fd_read_gzip_from_file; + + return blo_decode_and_check(fd, error_r); + } +} + +FileData *blo_openblendermemory(void *mem, int memsize, BlendReadError *error_r) +{ + if (!mem || memsizebuffer= mem; + fd->buffersize= memsize; + fd->read= fd_read_from_memory; + fd->flags|= FD_FLAGS_NOT_MY_BUFFER; + + return blo_decode_and_check(fd, error_r); + } +} + +FileData *blo_openblendermemfile(MemFile *memfile, BlendReadError *error_r) +{ + if (!memfile) { + *error_r = BRE_UNABLE_TO_OPEN; + return NULL; + } else { + FileData *fd= filedata_new(); + fd->memfile= memfile; + + fd->read= fd_read_from_memfile; + fd->flags|= FD_FLAGS_NOT_MY_BUFFER; + + return blo_decode_and_check(fd, error_r); + } +} + + +void blo_freefiledata(FileData *fd) +{ + if (fd) { + + if (fd->filedes != -1) { + close(fd->filedes); + } + + if (fd->gzfiledes != NULL) + { + gzclose(fd->gzfiledes); + } + + if (fd->buffer && !(fd->flags & FD_FLAGS_NOT_MY_BUFFER)) { + MEM_freeN(fd->buffer); + fd->buffer = 0; + } + + // Free all BHeadN data blocks + BLI_freelistN(&fd->listbase); + + if (fd->memsdna) + dna_freestructDNA(fd->memsdna); + if (fd->filesdna) + dna_freestructDNA(fd->filesdna); + if (fd->compflags) + MEM_freeN(fd->compflags); + + if (fd->datamap) + oldnewmap_free(fd->datamap); + if (fd->globmap) + oldnewmap_free(fd->globmap); + if (fd->imamap) + oldnewmap_free(fd->imamap); + if (fd->libmap && !(fd->flags & FD_FLAGS_NOT_MY_LIBMAP)) + oldnewmap_free(fd->libmap); + + MEM_freeN(fd); + } +} + +/* ************ DIV ****************** */ + +int BLO_has_bfile_extension(char *str) +{ + return (BLI_testextensie(str, ".ble") || BLI_testextensie(str, ".blend")||BLI_testextensie(str, ".blend.gz")); +} + +/* ************** OLD POINTERS ******************* */ + +static void *newdataadr(FileData *fd, void *adr) /* only direct databocks */ +{ + return oldnewmap_lookup_and_inc(fd->datamap, adr); +} + +static void *newglobadr(FileData *fd, void *adr) /* direct datablocks with global linking */ +{ + return oldnewmap_lookup_and_inc(fd->globmap, adr); +} + +static void *newimaadr(FileData *fd, void *adr) /* used to restore image data after undo */ +{ + if(fd->imamap && adr) + return oldnewmap_lookup_and_inc(fd->imamap, adr); + return NULL; +} + + +static void *newlibadr(FileData *fd, void *lib, void *adr) /* only lib data */ +{ + return oldnewmap_liblookup(fd->libmap, adr, lib); +} + +static void *newlibadr_us(FileData *fd, void *lib, void *adr) /* increases user number */ +{ + ID *id= newlibadr(fd, lib, adr); + + if(id) + id->us++; + + return id; +} + +static void change_idid_adr_fd(FileData *fd, void *old, void *new) +{ + int i; + + for (i=0; ilibmap->nentries; i++) { + OldNew *entry= &fd->libmap->entries[i]; + + if (old==entry->newp && entry->nr==ID_ID) { + entry->newp= new; + if(new) entry->nr= GS( ((ID *)new)->name ); + break; + } + } +} + +static void change_idid_adr(ListBase *mainlist, FileData *basefd, void *old, void *new) +{ + Main *mainptr; + + for(mainptr= mainlist->first; mainptr; mainptr= mainptr->next) { + FileData *fd; + + if(mainptr->curlib) fd= mainptr->curlib->filedata; + else fd= basefd; + + if(fd) { + change_idid_adr_fd(fd, old, new); + } + } +} + +/* assumed; G.main still exists */ +void blo_make_image_pointer_map(FileData *fd) +{ + Image *ima= G.main->image.first; + Scene *sce= G.main->scene.first; + + fd->imamap= oldnewmap_new(); + + for(;ima; ima= ima->id.next) { + Link *ibuf= ima->ibufs.first; + for(; ibuf; ibuf= ibuf->next) + oldnewmap_insert(fd->imamap, ibuf, ibuf, 0); + } + for(; sce; sce= sce->id.next) { + if(sce->nodetree) { + bNode *node; + for(node= sce->nodetree->nodes.first; node; node= node->next) + oldnewmap_insert(fd->imamap, node->preview, node->preview, 0); + } + } +} + +/* set G.main image ibufs to zero if it has been restored */ +/* this works because freeing G.main only happens after this call */ +void blo_end_image_pointer_map(FileData *fd) +{ + OldNew *entry= fd->imamap->entries; + Image *ima= G.main->image.first; + Scene *sce= G.main->scene.first; + int i; + + /* used entries were restored, so we put them to zero */ + for (i=0; iimamap->nentries; i++, entry++) { + if (entry->nr>0) + entry->newp= NULL; + } + + for(;ima; ima= ima->id.next) { + Link *ibuf, *next; + + /* this mirrors direct_link_image */ + for(ibuf= ima->ibufs.first; ibuf; ibuf= next) { + next= ibuf->next; + if(NULL==newimaadr(fd, ibuf)) { /* so was restored */ + BLI_remlink(&ima->ibufs, ibuf); + ima->bindcode= 0; + } + } + } + for(; sce; sce= sce->id.next) { + if(sce->nodetree) { + bNode *node; + for(node= sce->nodetree->nodes.first; node; node= node->next) + node->preview= newimaadr(fd, node->preview); + } + } +} + +/* undo file support: add all library pointers in lookup */ +void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd) +{ + Main *ptr= mainlist->first; + ListBase *lbarray[MAX_LIBARRAY]; + + for(ptr= ptr->next; ptr; ptr= ptr->next) { + int i= set_listbasepointers(ptr, lbarray); + while(i--) { + ID *id; + for(id= lbarray[i]->first; id; id= id->next) + oldnewmap_insert(fd->libmap, id, id, GS(id->name)); + } + } +} + + +/* ********** END OLD POINTERS ****************** */ +/* ********** READ FILE ****************** */ + +static void switch_endian_structs(struct SDNA *filesdna, BHead *bhead) +{ + int blocksize, nblocks; + char *data; + + data= (char *)(bhead+1); + blocksize= filesdna->typelens[ filesdna->structs[bhead->SDNAnr][0] ]; + + nblocks= bhead->nr; + while(nblocks--) { + dna_switch_endian_struct(filesdna, bhead->SDNAnr, data); + + data+= blocksize; + } +} + +static void *read_struct(FileData *fd, BHead *bh, char *blockname) +{ + void *temp= NULL; + + if (bh->len) { + /* switch is based on file dna */ + if (bh->SDNAnr && (fd->flags & FD_FLAGS_SWITCH_ENDIAN)) + switch_endian_structs(fd->filesdna, bh); + + if (fd->compflags[bh->SDNAnr]) { /* flag==0: doesn't exist anymore */ + if(fd->compflags[bh->SDNAnr]==2) { + temp= dna_reconstruct(fd->memsdna, fd->filesdna, fd->compflags, bh->SDNAnr, bh->nr, (bh+1)); + } else { + temp= MEM_mallocN(bh->len, blockname); + memcpy(temp, (bh+1), bh->len); + } + } + } + + return temp; +} + +static void link_list(FileData *fd, ListBase *lb) /* only direct data */ +{ + Link *ln, *prev; + + if(lb->first==NULL) return; + + lb->first= newdataadr(fd, lb->first); + ln= lb->first; + prev= NULL; + while(ln) { + ln->next= newdataadr(fd, ln->next); + ln->prev= prev; + prev= ln; + ln= ln->next; + } + lb->last= prev; +} + +static void link_glob_list(FileData *fd, ListBase *lb) /* for glob data */ +{ + Link *ln, *prev; + void *poin; + + if(lb->first==0) return; + poin= newdataadr(fd, lb->first); + if(lb->first) { + oldnewmap_insert(fd->globmap, lb->first, poin, 0); + } + lb->first= poin; + + ln= lb->first; + prev= 0; + while(ln) { + poin= newdataadr(fd, ln->next); + if(ln->next) { + oldnewmap_insert(fd->globmap, ln->next, poin, 0); + } + ln->next= poin; + ln->prev= prev; + prev= ln; + ln= ln->next; + } + lb->last= prev; +} + +static void test_pointer_array(FileData *fd, void **mat) +{ +#if defined(WIN32) && !defined(FREE_WINDOWS) + __int64 *lpoin, *lmat; +#else + long long *lpoin, *lmat; +#endif + int len, *ipoin, *imat; + + /* manually convert the pointer array in + * the old dna format to a pointer array in + * the new dna format. + */ + if(*mat) { + len= MEM_allocN_len(*mat)/fd->filesdna->pointerlen; + + if(fd->filesdna->pointerlen==8 && fd->memsdna->pointerlen==4) { + ipoin=imat= MEM_mallocN( len*4, "newmatar"); + lpoin= *mat; + + while(len-- > 0) { + if((fd->flags & FD_FLAGS_SWITCH_ENDIAN)) + SWITCH_LONGINT(*lpoin); + *ipoin= (int) ((*lpoin) >> 3); + ipoin++; + lpoin++; + } + MEM_freeN(*mat); + *mat= imat; + } + + if(fd->filesdna->pointerlen==4 && fd->memsdna->pointerlen==8) { + lpoin=lmat= MEM_mallocN( len*8, "newmatar"); + ipoin= *mat; + + while(len-- > 0) { + *lpoin= *ipoin; + ipoin++; + lpoin++; + } + MEM_freeN(*mat); + *mat= lmat; + } + } +} + +/* ************ READ ID Properties *************** */ + +void IDP_DirectLinkProperty(IDProperty *prop, int switch_endian, void *fd); +void IDP_LibLinkProperty(IDProperty *prop, int switch_endian, void *fd); + +void IDP_DirectLinkArray(IDProperty *prop, int switch_endian, void *fd) +{ + int i; + + /*since we didn't save the extra buffer, set totallen to len.*/ + prop->totallen = prop->len; + prop->data.pointer = newdataadr(fd, prop->data.pointer); + + if (switch_endian) { + for (i=0; ilen; i++) { + SWITCH_INT(((int*)prop->data.pointer)[i]); + } + } +} + +void IDP_DirectLinkString(IDProperty *prop, int switch_endian, void *fd) +{ + /*since we didn't save the extra string buffer, set totallen to len.*/ + prop->totallen = prop->len; + prop->data.pointer = newdataadr(fd, prop->data.pointer); +} + +void IDP_DirectLinkGroup(IDProperty *prop, int switch_endian, void *fd) +{ + ListBase *lb = &prop->data.group; + IDProperty *loop; + + link_list(fd, lb); + + /*Link child id properties now*/ + for (loop=prop->data.group.first; loop; loop=loop->next) { + IDP_DirectLinkProperty(loop, switch_endian, fd); + } +} + +void IDP_DirectLinkProperty(IDProperty *prop, int switch_endian, void *fd) +{ + switch (prop->type) { + case IDP_GROUP: + IDP_DirectLinkGroup(prop, switch_endian, fd); + break; + case IDP_STRING: + IDP_DirectLinkString(prop, switch_endian, fd); + break; + case IDP_ARRAY: + IDP_DirectLinkArray(prop, switch_endian, fd); + break; + } +} + +/*stub function*/ +void IDP_LibLinkProperty(IDProperty *prop, int switch_endian, void *fd) +{ +} + +/* ************ READ Brush *************** */ +/* library brush linking after fileread */ +static void lib_link_brush(FileData *fd, Main *main) +{ + Brush *brush; + MTex *mtex; + int a; + + /* only link ID pointers */ + for(brush= main->brush.first; brush; brush= brush->id.next) { + if(brush->id.flag & LIB_NEEDLINK) { + brush->id.flag -= LIB_NEEDLINK; + + for(a=0; amtex[a]; + if(mtex) + mtex->tex= newlibadr_us(fd, brush->id.lib, mtex->tex); + } + } + } +} + +static void direct_link_brush(FileData *fd, Brush *brush) +{ + /* brush itself has been read */ + int a; + + for(a=0; amtex[a]= newdataadr(fd, brush->mtex[a]); +} + +/* ************ READ CurveMapping *************** */ + +/* cuma itself has been read! */ +static void direct_link_curvemapping(FileData *fd, CurveMapping *cumap) +{ + int a; + + /* flag seems to be able to hang? Maybe old files... not bad to clear anyway */ + cumap->flag &= ~CUMA_PREMULLED; + + for(a=0; acm[a].curve= newdataadr(fd, cumap->cm[a].curve); + cumap->cm[a].table= NULL; + } +} + +/* ************ READ NODE TREE *************** */ + +/* singe node tree (also used for material/scene trees), ntree is not NULL */ +static void lib_link_ntree(FileData *fd, ID *id, bNodeTree *ntree) +{ + bNode *node; + + for(node= ntree->nodes.first; node; node= node->next) + node->id= newlibadr_us(fd, id->lib, node->id); +} + +/* library ntree linking after fileread */ +static void lib_link_nodetree(FileData *fd, Main *main) +{ + bNodeTree *ntree; + + /* only link ID pointers */ + for(ntree= main->nodetree.first; ntree; ntree= ntree->id.next) { + if(ntree->id.flag & LIB_NEEDLINK) { + ntree->id.flag -= LIB_NEEDLINK; + lib_link_ntree(fd, &ntree->id, ntree); + } + } +} + +/* verify types for nodes and groups, all data has to be read */ +static void lib_verify_nodetree(Main *main) +{ + Scene *sce; + Material *ma; + bNodeTree *ntree; + + /* now create the own typeinfo structs an verify nodes */ + /* here we still assume no groups in groups */ + for(ntree= main->nodetree.first; ntree; ntree= ntree->id.next) { + ntreeVerifyTypes(ntree); /* internal nodes, no groups! */ + ntreeMakeOwnType(ntree); /* for group usage */ + } + + /* now verify all types in material trees, groups are set OK now */ + for(ma= main->mat.first; ma; ma= ma->id.next) { + if(ma->nodetree) + ntreeVerifyTypes(ma->nodetree); + } + /* and scene trees */ + for(sce= main->scene.first; sce; sce= sce->id.next) { + if(sce->nodetree) + ntreeVerifyTypes(sce->nodetree); + } +} + + + +/* ntree itself has been read! */ +static void direct_link_nodetree(FileData *fd, bNodeTree *ntree) +{ + /* note: writing and reading goes in sync, for speed */ + bNode *node; + bNodeSocket *sock; + bNodeLink *link; + + ntree->init= 0; /* to set callbacks and force setting types */ + ntree->owntype= NULL; + ntree->timecursor= NULL; + + link_list(fd, &ntree->nodes); + for(node= ntree->nodes.first; node; node= node->next) { + node->storage= newdataadr(fd, node->storage); + if(node->storage) { + + /* could be handlerized at some point */ + if(ntree->type==NTREE_SHADER && (node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB)) + direct_link_curvemapping(fd, node->storage); + else if(ntree->type==NTREE_COMPOSIT) { + if( ELEM3(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB)) + direct_link_curvemapping(fd, node->storage); + else if(ELEM3(node->type, CMP_NODE_IMAGE, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) + ((ImageUser *)node->storage)->ok= 1; + } + } + link_list(fd, &node->inputs); + link_list(fd, &node->outputs); + } + link_list(fd, &ntree->links); + + /* and we connect the rest */ + for(node= ntree->nodes.first; node; node= node->next) { + node->preview= newimaadr(fd, node->preview); + node->lasty= 0; + for(sock= node->inputs.first; sock; sock= sock->next) + sock->link= newdataadr(fd, sock->link); + for(sock= node->outputs.first; sock; sock= sock->next) + sock->ns.data= NULL; + } + for(link= ntree->links.first; link; link= link->next) { + link->fromnode= newdataadr(fd, link->fromnode); + link->tonode= newdataadr(fd, link->tonode); + link->fromsock= newdataadr(fd, link->fromsock); + link->tosock= newdataadr(fd, link->tosock); + } + + /* type verification is in lib-link */ +} + +/* ************ READ PACKEDFILE *************** */ + +static PackedFile *direct_link_packedfile(FileData *fd, PackedFile *oldpf) +{ + PackedFile *pf= newdataadr(fd, oldpf); + + if (pf) { + pf->data= newdataadr(fd, pf->data); + } + + return pf; +} + +/* ************ READ IMAGE PREVIEW *************** */ + +static PreviewImage *direct_link_preview_image(FileData *fd, PreviewImage *old_prv) +{ + PreviewImage *prv= newdataadr(fd, old_prv); + + if (prv) { + int i; + for (i=0; i < PREVIEW_MIPMAPS; ++i) { + if (prv->rect[i]) { + prv->rect[i] = newdataadr(fd, prv->rect[i]); + } + } + } + + return prv; +} + +/* ************ READ SCRIPTLINK *************** */ + +static void lib_link_scriptlink(FileData *fd, ID *id, ScriptLink *slink) +{ + int i; + + for(i=0; itotscript; i++) { + slink->scripts[i]= newlibadr(fd, id->lib, slink->scripts[i]); + } +} + +static void direct_link_scriptlink(FileData *fd, ScriptLink *slink) +{ + slink->scripts= newdataadr(fd, slink->scripts); + test_pointer_array(fd, (void **)&slink->scripts); + + slink->flag= newdataadr(fd, slink->flag); + + if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) { + int a; + + for(a=0; atotscript; a++) { + SWITCH_SHORT(slink->flag[a]); + } + } +} + +/* ************ READ ARMATURE ***************** */ + +static void lib_link_nlastrips(FileData *fd, ID *id, ListBase *striplist) +{ + bActionStrip *strip; + bActionModifier *amod; + + for (strip=striplist->first; strip; strip=strip->next){ + strip->object = newlibadr(fd, id->lib, strip->object); + strip->act = newlibadr_us(fd, id->lib, strip->act); + strip->ipo = newlibadr(fd, id->lib, strip->ipo); + for(amod= strip->modifiers.first; amod; amod= amod->next) + amod->ob= newlibadr(fd, id->lib, amod->ob); + } +} + +static void lib_link_constraint_channels(FileData *fd, ID *id, ListBase *chanbase) +{ + bConstraintChannel *chan; + + for (chan=chanbase->first; chan; chan=chan->next){ + chan->ipo = newlibadr_us(fd, id->lib, chan->ipo); + } +} + +static void lib_link_constraints(FileData *fd, ID *id, ListBase *conlist) +{ + bConstraint *con; + + for (con = conlist->first; con; con=con->next) { + /* patch for error introduced by changing constraints (dunno how) */ + /* if con->data type changes, dna cannot resolve the pointer! (ton) */ + if(con->data==NULL) { + con->type= CONSTRAINT_TYPE_NULL; + } + + switch (con->type) { + case CONSTRAINT_TYPE_PYTHON: + { + bPythonConstraint *data= (bPythonConstraint*)con->data; + bConstraintTarget *ct; + + for (ct= data->targets.first; ct; ct= ct->next) + ct->tar = newlibadr(fd, id->lib, ct->tar); + + data->text = newlibadr(fd, id->lib, data->text); + //IDP_LibLinkProperty(data->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + } + break; + case CONSTRAINT_TYPE_ACTION: + { + bActionConstraint *data; + data= ((bActionConstraint*)con->data); + data->tar = newlibadr(fd, id->lib, data->tar); + data->act = newlibadr(fd, id->lib, data->act); + } + break; + case CONSTRAINT_TYPE_LOCLIKE: + { + bLocateLikeConstraint *data; + data= ((bLocateLikeConstraint*)con->data); + data->tar = newlibadr(fd, id->lib, data->tar); + } + break; + case CONSTRAINT_TYPE_ROTLIKE: + { + bRotateLikeConstraint *data; + data= ((bRotateLikeConstraint*)con->data); + data->tar = newlibadr(fd, id->lib, data->tar); + } + break; + case CONSTRAINT_TYPE_SIZELIKE: + { + bSizeLikeConstraint *data; + data= ((bSizeLikeConstraint*)con->data); + data->tar = newlibadr(fd, id->lib, data->tar); + } + break; + case CONSTRAINT_TYPE_KINEMATIC: + { + bKinematicConstraint *data; + data = ((bKinematicConstraint*)con->data); + data->tar = newlibadr(fd, id->lib, data->tar); + data->poletar = newlibadr(fd, id->lib, data->poletar); + } + break; + case CONSTRAINT_TYPE_TRACKTO: + { + bTrackToConstraint *data; + data = ((bTrackToConstraint*)con->data); + data->tar = newlibadr(fd, id->lib, data->tar); + } + break; + case CONSTRAINT_TYPE_MINMAX: + { + bMinMaxConstraint *data; + data = ((bMinMaxConstraint*)con->data); + data->tar = newlibadr(fd, id->lib, data->tar); + } + break; + case CONSTRAINT_TYPE_LOCKTRACK: + { + bLockTrackConstraint *data; + data= ((bLockTrackConstraint*)con->data); + data->tar = newlibadr(fd, id->lib, data->tar); + } + break; + case CONSTRAINT_TYPE_FOLLOWPATH: + { + bFollowPathConstraint *data; + data= ((bFollowPathConstraint*)con->data); + data->tar = newlibadr(fd, id->lib, data->tar); + } + break; + case CONSTRAINT_TYPE_STRETCHTO: + { + bStretchToConstraint *data; + data= ((bStretchToConstraint*)con->data); + data->tar = newlibadr(fd, id->lib, data->tar); + } + break; + case CONSTRAINT_TYPE_RIGIDBODYJOINT: + { + bRigidBodyJointConstraint *data; + data= ((bRigidBodyJointConstraint*)con->data); + data->tar = newlibadr(fd, id->lib, data->tar); + } + break; + case CONSTRAINT_TYPE_CLAMPTO: + { + bClampToConstraint *data; + data= ((bClampToConstraint*)con->data); + data->tar = newlibadr(fd, id->lib, data->tar); + } + break; + case CONSTRAINT_TYPE_CHILDOF: + { + bChildOfConstraint *data; + data= ((bChildOfConstraint*)con->data); + data->tar = newlibadr(fd, id->lib, data->tar); + } + break; + case CONSTRAINT_TYPE_TRANSFORM: + { + bTransformConstraint *data; + data= ((bTransformConstraint*)con->data); + data->tar = newlibadr(fd, id->lib, data->tar); + } + break; + case CONSTRAINT_TYPE_NULL: + break; + } + } +} + +static void direct_link_constraints(FileData *fd, ListBase *lb) +{ + bConstraint *cons; + + link_list(fd, lb); + for (cons=lb->first; cons; cons=cons->next) { + cons->data = newdataadr(fd, cons->data); + if (cons->type == CONSTRAINT_TYPE_PYTHON) { + bPythonConstraint *data= cons->data; + link_list(fd, &data->targets); + data->prop = newdataadr(fd, data->prop); + IDP_DirectLinkProperty(data->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + } + } +} + +static void lib_link_pose(FileData *fd, Object *ob, bPose *pose) +{ + bPoseChannel *pchan; + bArmature *arm= ob->data; + int rebuild; + + if (!pose || !arm) + return; + + /* always rebuild to match proxy or lib changes */ + rebuild= ob->proxy || (ob->id.lib==NULL && arm->id.lib); + + for (pchan = pose->chanbase.first; pchan; pchan=pchan->next) { + lib_link_constraints(fd, (ID *)ob, &pchan->constraints); + + /* hurms... loop in a loop, but yah... later... (ton) */ + pchan->bone= get_named_bone(arm, pchan->name); + + pchan->custom= newlibadr(fd, arm->id.lib, pchan->custom); + if(pchan->bone==NULL) + rebuild= 1; + else if(ob->id.lib==NULL && arm->id.lib) { + /* local pose selection copied to armature, bit hackish */ + pchan->bone->flag &= ~(BONE_SELECTED|BONE_ACTIVE); + pchan->bone->flag |= pchan->selectflag; + } + } + + if(rebuild) { + ob->recalc= OB_RECALC; + pose->flag |= POSE_RECALC; + } +} + +static void lib_link_armature(FileData *fd, Main *main) +{ + bArmature *arm; + + arm= main->armature.first; + + while(arm) { + if(arm->id.flag & LIB_NEEDLINK) { + arm->id.flag -= LIB_NEEDLINK; + } + arm= arm->id.next; + } +} + +static void lib_link_action(FileData *fd, Main *main) +{ + bAction *act; + bActionChannel *chan; + + act= main->action.first; + while(act) { + if(act->id.flag & LIB_NEEDLINK) { + act->id.flag -= LIB_NEEDLINK; + + for (chan=act->chanbase.first; chan; chan=chan->next) { + chan->ipo= newlibadr_us(fd, act->id.lib, chan->ipo); + lib_link_constraint_channels(fd, &act->id, &chan->constraintChannels); + } + + } + act= act->id.next; + } +} + +static void direct_link_bones(FileData *fd, Bone* bone) +{ + Bone *child; + + bone->parent= newdataadr(fd, bone->parent); + + link_list(fd, &bone->childbase); + + for (child=bone->childbase.first; child; child=child->next) { + direct_link_bones(fd, child); + } +} + + +static void direct_link_action(FileData *fd, bAction *act) +{ + bActionChannel *achan; + + link_list(fd, &act->chanbase); + + for (achan = act->chanbase.first; achan; achan=achan->next) + link_list(fd, &achan->constraintChannels); + +} + +static void direct_link_armature(FileData *fd, bArmature *arm) +{ + Bone *bone; + + link_list(fd, &arm->bonebase); + + bone=arm->bonebase.first; + while (bone) { + direct_link_bones(fd, bone); + bone=bone->next; + } +} + +/* ************ READ CAMERA ***************** */ + +static void lib_link_camera(FileData *fd, Main *main) +{ + Camera *ca; + + ca= main->camera.first; + while(ca) { + if(ca->id.flag & LIB_NEEDLINK) { + + ca->ipo= newlibadr_us(fd, ca->id.lib, ca->ipo); + + ca->dof_ob= newlibadr_us(fd, ca->id.lib, ca->dof_ob); + + lib_link_scriptlink(fd, &ca->id, &ca->scriptlink); + + ca->id.flag -= LIB_NEEDLINK; + } + ca= ca->id.next; + } +} + +static void direct_link_camera(FileData *fd, Camera *ca) +{ + direct_link_scriptlink(fd, &ca->scriptlink); +} + + +/* ************ READ LAMP ***************** */ + +static void lib_link_lamp(FileData *fd, Main *main) +{ + Lamp *la; + MTex *mtex; + int a; + + la= main->lamp.first; + while(la) { + if(la->id.flag & LIB_NEEDLINK) { + + for(a=0; amtex[a]; + if(mtex) { + mtex->tex= newlibadr_us(fd, la->id.lib, mtex->tex); + mtex->object= newlibadr(fd, la->id.lib, mtex->object); + } + } + + la->ipo= newlibadr_us(fd, la->id.lib, la->ipo); + + lib_link_scriptlink(fd, &la->id, &la->scriptlink); + + la->id.flag -= LIB_NEEDLINK; + } + la= la->id.next; + } +} + +static void direct_link_lamp(FileData *fd, Lamp *la) +{ + int a; + + direct_link_scriptlink(fd, &la->scriptlink); + + for(a=0; amtex[a]= newdataadr(fd, la->mtex[a]); + } + + la->curfalloff= newdataadr(fd, la->curfalloff); + if(la->curfalloff) + direct_link_curvemapping(fd, la->curfalloff); + + la->preview = direct_link_preview_image(fd, la->preview); +} + +/* ************ READ keys ***************** */ + +static void lib_link_key(FileData *fd, Main *main) +{ + Key *key; + + key= main->key.first; + while(key) { + if(key->id.flag & LIB_NEEDLINK) { + + key->ipo= newlibadr_us(fd, key->id.lib, key->ipo); + key->from= newlibadr(fd, key->id.lib, key->from); + + key->id.flag -= LIB_NEEDLINK; + } + key= key->id.next; + } +} + +static void switch_endian_keyblock(Key *key, KeyBlock *kb) +{ + int elemsize, a, b; + char *data, *poin, *cp; + + elemsize= key->elemsize; + data= kb->data; + + for(a=0; atotelem; a++) { + + cp= key->elemstr; + poin= data; + + while( cp[0] ) { /* cp[0]==amount */ + + switch(cp[1]) { /* cp[1]= type */ + case IPO_FLOAT: + case IPO_BPOINT: + case IPO_BEZTRIPLE: + b= cp[0]; + while(b--) { + SWITCH_INT((*poin)); + poin+= 4; + } + break; + } + + cp+= 2; + + } + data+= elemsize; + } +} + +static void direct_link_key(FileData *fd, Key *key) +{ + KeyBlock *kb; + + link_list(fd, &(key->block)); + + key->refkey= newdataadr(fd, key->refkey); + + kb= key->block.first; + while(kb) { + + kb->data= newdataadr(fd, kb->data); + + if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) + switch_endian_keyblock(key, kb); + + kb= kb->next; + } +} + +/* ************ READ mball ***************** */ + +static void lib_link_mball(FileData *fd, Main *main) +{ + MetaBall *mb; + int a; + + mb= main->mball.first; + while(mb) { + if(mb->id.flag & LIB_NEEDLINK) { + + for(a=0; atotcol; a++) mb->mat[a]= newlibadr_us(fd, mb->id.lib, mb->mat[a]); + + mb->ipo= newlibadr_us(fd, mb->id.lib, mb->ipo); + + mb->id.flag -= LIB_NEEDLINK; + } + mb= mb->id.next; + } +} + +static void direct_link_mball(FileData *fd, MetaBall *mb) +{ + mb->mat= newdataadr(fd, mb->mat); + test_pointer_array(fd, (void **)&mb->mat); + + link_list(fd, &(mb->elems)); + + mb->disp.first= mb->disp.last= 0; + + mb->bb= 0; +} + +/* ************ READ WORLD ***************** */ + +static void lib_link_world(FileData *fd, Main *main) +{ + World *wrld; + MTex *mtex; + int a; + + wrld= main->world.first; + while(wrld) { + if(wrld->id.flag & LIB_NEEDLINK) { + + wrld->ipo= newlibadr_us(fd, wrld->id.lib, wrld->ipo); + + for(a=0; amtex[a]; + if(mtex) { + mtex->tex= newlibadr_us(fd, wrld->id.lib, mtex->tex); + mtex->object= newlibadr(fd, wrld->id.lib, mtex->object); + } + } + + lib_link_scriptlink(fd, &wrld->id, &wrld->scriptlink); + + wrld->id.flag -= LIB_NEEDLINK; + } + wrld= wrld->id.next; + } +} + +static void direct_link_world(FileData *fd, World *wrld) +{ + int a; + + direct_link_scriptlink(fd, &wrld->scriptlink); + + for(a=0; amtex[a]= newdataadr(fd, wrld->mtex[a]); + } + wrld->preview = direct_link_preview_image(fd, wrld->preview); +} + + +/* ************ READ IPO ***************** */ + +static void lib_link_ipo(FileData *fd, Main *main) +{ + Ipo *ipo; + + ipo= main->ipo.first; + while(ipo) { + if(ipo->id.flag & LIB_NEEDLINK) { + IpoCurve *icu; + for(icu= ipo->curve.first; icu; icu= icu->next) { + if(icu->driver) + icu->driver->ob= newlibadr(fd, ipo->id.lib, icu->driver->ob); + } + ipo->id.flag -= LIB_NEEDLINK; + } + ipo= ipo->id.next; + } +} + +static void direct_link_ipo(FileData *fd, Ipo *ipo) +{ + IpoCurve *icu; + + link_list(fd, &(ipo->curve)); + icu= ipo->curve.first; + while(icu) { + icu->bezt= newdataadr(fd, icu->bezt); + icu->bp= newdataadr(fd, icu->bp); + icu->driver= newdataadr(fd, icu->driver); + icu= icu->next; + } +} + +/* ************ READ VFONT ***************** */ + +static void lib_link_vfont(FileData *fd, Main *main) +{ + VFont *vf; + + vf= main->vfont.first; + while(vf) { + if(vf->id.flag & LIB_NEEDLINK) { + vf->id.flag -= LIB_NEEDLINK; + } + vf= vf->id.next; + } +} + +static void direct_link_vfont(FileData *fd, VFont *vf) +{ + vf->data= NULL; + vf->packedfile= direct_link_packedfile(fd, vf->packedfile); +} + +/* ************ READ TEXT ****************** */ + +static void lib_link_text(FileData *fd, Main *main) +{ + Text *text; + + text= main->text.first; + while(text) { + if(text->id.flag & LIB_NEEDLINK) { + text->id.flag -= LIB_NEEDLINK; + } + text= text->id.next; + } +} + +static void direct_link_text(FileData *fd, Text *text) +{ + TextLine *ln; + + text->name= newdataadr(fd, text->name); + + text->undo_pos= -1; + text->undo_len= TXT_INIT_UNDO; + text->undo_buf= MEM_mallocN(text->undo_len, "undo buf"); + + text->compiled= NULL; + +/* + if(text->flags & TXT_ISEXT) { + reopen_text(text); + } else { +*/ + + link_list(fd, &text->lines); + + text->curl= newdataadr(fd, text->curl); + text->sell= newdataadr(fd, text->sell); + + ln= text->lines.first; + while(ln) { + ln->line= newdataadr(fd, ln->line); + ln->format= NULL; + + if (ln->len != (int) strlen(ln->line)) { + printf("Error loading text, line lengths differ\n"); + ln->len = strlen(ln->line); + } + + ln= ln->next; + } + + text->flags = (text->flags|TXT_ISTMP) & ~TXT_ISEXT; + + text->id.us= 1; +} + +/* ************ READ IMAGE ***************** */ + +static void lib_link_image(FileData *fd, Main *main) +{ + Image *ima; + + ima= main->image.first; + while (ima) { + if(ima->id.flag & LIB_NEEDLINK) { + if (ima->id.properties) IDP_LibLinkProperty(ima->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + + ima->id.flag -= LIB_NEEDLINK; + } + ima= ima->id.next; + } +} + +static void link_ibuf_list(FileData *fd, ListBase *lb) +{ + Link *ln, *prev; + + if(lb->first==NULL) return; + + lb->first= newimaadr(fd, lb->first); + ln= lb->first; + prev= NULL; + while(ln) { + ln->next= newimaadr(fd, ln->next); + ln->prev= prev; + prev= ln; + ln= ln->next; + } + lb->last= prev; +} + +static void direct_link_image(FileData *fd, Image *ima) +{ + /* for undo system, pointers could be restored */ + if(fd->imamap) + link_ibuf_list(fd, &ima->ibufs); + else + ima->ibufs.first= ima->ibufs.last= NULL; + + /* if not restored, we keep the binded opengl index */ + if(ima->ibufs.first==NULL) + ima->bindcode= 0; + + ima->anim= NULL; + ima->rr= NULL; + ima->repbind= NULL; + + ima->packedfile = direct_link_packedfile(fd, ima->packedfile); + ima->preview = direct_link_preview_image(fd, ima->preview); + ima->ok= 1; +} + + +/* ************ READ CURVE ***************** */ + +static void lib_link_curve(FileData *fd, Main *main) +{ + Curve *cu; + int a; + + cu= main->curve.first; + while(cu) { + if(cu->id.flag & LIB_NEEDLINK) { + + for(a=0; atotcol; a++) cu->mat[a]= newlibadr_us(fd, cu->id.lib, cu->mat[a]); + + cu->bevobj= newlibadr(fd, cu->id.lib, cu->bevobj); + cu->taperobj= newlibadr(fd, cu->id.lib, cu->taperobj); + cu->textoncurve= newlibadr(fd, cu->id.lib, cu->textoncurve); + cu->vfont= newlibadr_us(fd, cu->id.lib, cu->vfont); + cu->vfontb= newlibadr_us(fd, cu->id.lib, cu->vfontb); + cu->vfonti= newlibadr_us(fd, cu->id.lib, cu->vfonti); + cu->vfontbi= newlibadr_us(fd, cu->id.lib, cu->vfontbi); + + cu->ipo= newlibadr_us(fd, cu->id.lib, cu->ipo); + cu->key= newlibadr_us(fd, cu->id.lib, cu->key); + + cu->id.flag -= LIB_NEEDLINK; + } + cu= cu->id.next; + } +} + + +static void switch_endian_knots(Nurb *nu) +{ + int len; + + if(nu->knotsu) { + len= KNOTSU(nu); + while(len--) { + SWITCH_INT(nu->knotsu[len]); + } + } + if(nu->knotsv) { + len= KNOTSV(nu); + while(len--) { + SWITCH_INT(nu->knotsv[len]); + } + } +} + +static void direct_link_curve(FileData *fd, Curve *cu) +{ + Nurb *nu; + TextBox *tb; + + cu->mat= newdataadr(fd, cu->mat); + test_pointer_array(fd, (void **)&cu->mat); + cu->str= newdataadr(fd, cu->str); + cu->strinfo= newdataadr(fd, cu->strinfo); + cu->tb= newdataadr(fd, cu->tb); + + if(cu->vfont==0) link_list(fd, &(cu->nurb)); + else { + cu->nurb.first=cu->nurb.last= 0; + + tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "TextBoxread"); + if (cu->tb) { + memcpy(tb, cu->tb, cu->totbox*sizeof(TextBox)); + MEM_freeN(cu->tb); + cu->tb= tb; + } else { + cu->totbox = 1; + cu->actbox = 1; + cu->tb = tb; + cu->tb[0].w = cu->linewidth; + } + if (cu->wordspace == 0.0) cu->wordspace = 1.0; + } + + cu->bev.first=cu->bev.last= 0; + cu->disp.first=cu->disp.last= 0; + cu->path= 0; + + nu= cu->nurb.first; + while(nu) { + nu->bezt= newdataadr(fd, nu->bezt); + nu->bp= newdataadr(fd, nu->bp); + nu->knotsu= newdataadr(fd, nu->knotsu); + nu->knotsv= newdataadr(fd, nu->knotsv); + if (cu->vfont==0) nu->charidx= nu->mat_nr; + + if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) { + switch_endian_knots(nu); + } + + nu= nu->next; + } + cu->bb= NULL; +} + +/* ************ READ TEX ***************** */ + +static void lib_link_texture(FileData *fd, Main *main) +{ + Tex *tex; + + tex= main->tex.first; + while(tex) { + if(tex->id.flag & LIB_NEEDLINK) { + + tex->ima= newlibadr_us(fd, tex->id.lib, tex->ima); + tex->ipo= newlibadr_us(fd, tex->id.lib, tex->ipo); + if(tex->env) tex->env->object= newlibadr(fd, tex->id.lib, tex->env->object); + + tex->id.flag -= LIB_NEEDLINK; + } + tex= tex->id.next; + } +} + +static void direct_link_texture(FileData *fd, Tex *tex) +{ + tex->plugin= newdataadr(fd, tex->plugin); + if(tex->plugin) { + tex->plugin->handle= 0; + open_plugin_tex(tex->plugin); + /* initialize data for this instance, if an initialization + * function exists. + */ + if (tex->plugin->instance_init) + tex->plugin->instance_init((void *) tex->plugin->data); + } + tex->coba= newdataadr(fd, tex->coba); + tex->env= newdataadr(fd, tex->env); + if(tex->env) { + tex->env->ima= NULL; + memset(tex->env->cube, 0, 6*sizeof(void *)); + tex->env->ok= 0; + } + tex->preview = direct_link_preview_image(fd, tex->preview); + + tex->iuser.ok= 1; +} + + + +/* ************ READ MATERIAL ***************** */ + +static void lib_link_material(FileData *fd, Main *main) +{ + Material *ma; + MTex *mtex; + int a; + + ma= main->mat.first; + while(ma) { + if(ma->id.flag & LIB_NEEDLINK) { + /*Link ID Properties -- and copy this comment EXACTLY for easy finding + of library blocks that implement this.*/ + if (ma->id.properties) IDP_LibLinkProperty(ma->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + + ma->ipo= newlibadr_us(fd, ma->id.lib, ma->ipo); + ma->group= newlibadr_us(fd, ma->id.lib, ma->group); + + for(a=0; amtex[a]; + if(mtex) { + mtex->tex= newlibadr_us(fd, ma->id.lib, mtex->tex); + mtex->object= newlibadr(fd, ma->id.lib, mtex->object); + } + } + lib_link_scriptlink(fd, &ma->id, &ma->scriptlink); + + if(ma->nodetree) + lib_link_ntree(fd, &ma->id, ma->nodetree); + + ma->id.flag -= LIB_NEEDLINK; + } + ma= ma->id.next; + } +} + +static void direct_link_material(FileData *fd, Material *ma) +{ + int a; + + for(a=0; amtex[a]= newdataadr(fd, ma->mtex[a]); + } + + ma->ramp_col= newdataadr(fd, ma->ramp_col); + ma->ramp_spec= newdataadr(fd, ma->ramp_spec); + + direct_link_scriptlink(fd, &ma->scriptlink); + + ma->nodetree= newdataadr(fd, ma->nodetree); + if(ma->nodetree) + direct_link_nodetree(fd, ma->nodetree); + + ma->preview = direct_link_preview_image(fd, ma->preview); +} + +/* ************ READ MESH ***************** */ + +static void lib_link_mtface(FileData *fd, Mesh *me, MTFace *mtface, int totface) +{ + MTFace *tf= mtface; + int i; + + for (i=0; itpage= newlibadr(fd, me->id.lib, tf->tpage); + if(tf->tpage && tf->tpage->id.us==0) + tf->tpage->id.us= 1; + } +} + +static void lib_link_customdata_mtface(FileData *fd, Mesh *me, CustomData *fdata, int totface) +{ + int i; + for(i=0; itotlayer; i++) { + CustomDataLayer *layer = &fdata->layers[i]; + + if(layer->type == CD_MTFACE) + lib_link_mtface(fd, me, layer->data, totface); + } + +} + +static void lib_link_mesh(FileData *fd, Main *main) +{ + Mesh *me; + + me= main->mesh.first; + while(me) { + if(me->id.flag & LIB_NEEDLINK) { + int i; + + /*Link ID Properties -- and copy this comment EXACTLY for easy finding + of library blocks that implement this.*/ + if (me->id.properties) IDP_LibLinkProperty(me->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + + /* this check added for python created meshes */ + if(me->mat) { + for(i=0; itotcol; i++) { + me->mat[i]= newlibadr_us(fd, me->id.lib, me->mat[i]); + } + } + else me->totcol= 0; + + me->ipo= newlibadr_us(fd, me->id.lib, me->ipo); + me->key= newlibadr_us(fd, me->id.lib, me->key); + me->texcomesh= newlibadr_us(fd, me->id.lib, me->texcomesh); + + lib_link_customdata_mtface(fd, me, &me->fdata, me->totface); + if(me->mr && me->mr->levels.first) + lib_link_customdata_mtface(fd, me, &me->mr->fdata, + ((MultiresLevel*)me->mr->levels.first)->totface); + + me->id.flag -= LIB_NEEDLINK; + } + me= me->id.next; + } +} + +static void direct_link_dverts(FileData *fd, int count, MDeformVert *mdverts) +{ + int i; + + if (!mdverts) + return; + + for (i=0; ilayers= newdataadr(fd, data->layers); + + while (i < data->totlayer) { + CustomDataLayer *layer = &data->layers[i]; + + if (CustomData_verify_versions(data, i)) { + layer->data = newdataadr(fd, layer->data); + i++; + } + } +} + +static void direct_link_mesh(FileData *fd, Mesh *mesh) +{ + mesh->mat= newdataadr(fd, mesh->mat); + test_pointer_array(fd, (void **)&mesh->mat); + + mesh->mvert= newdataadr(fd, mesh->mvert); + mesh->medge= newdataadr(fd, mesh->medge); + mesh->mface= newdataadr(fd, mesh->mface); + mesh->tface= newdataadr(fd, mesh->tface); + mesh->mtface= newdataadr(fd, mesh->mtface); + mesh->mcol= newdataadr(fd, mesh->mcol); + mesh->msticky= newdataadr(fd, mesh->msticky); + mesh->dvert= newdataadr(fd, mesh->dvert); + + /* Partial-mesh visibility (do this before using totvert, totface, or totedge!) */ + mesh->pv= newdataadr(fd, mesh->pv); + if(mesh->pv) { + mesh->pv->vert_map= newdataadr(fd, mesh->pv->vert_map); + mesh->pv->edge_map= newdataadr(fd, mesh->pv->edge_map); + mesh->pv->old_faces= newdataadr(fd, mesh->pv->old_faces); + mesh->pv->old_edges= newdataadr(fd, mesh->pv->old_edges); + } + + /* normally direct_link_dverts should be called in direct_link_customdata, + but for backwards compat in do_versions to work we do it here */ + direct_link_dverts(fd, mesh->pv ? mesh->pv->totvert : mesh->totvert, mesh->dvert); + + direct_link_customdata(fd, &mesh->vdata, mesh->pv ? mesh->pv->totvert : mesh->totvert); + direct_link_customdata(fd, &mesh->edata, mesh->pv ? mesh->pv->totedge : mesh->totedge); + direct_link_customdata(fd, &mesh->fdata, mesh->pv ? mesh->pv->totface : mesh->totface); + + mesh->bb= NULL; + mesh->mselect = NULL; + + /* Multires data */ + mesh->mr= newdataadr(fd, mesh->mr); + if(mesh->mr) { + MultiresLevel *lvl; + + link_list(fd, &mesh->mr->levels); + lvl= mesh->mr->levels.first; + + direct_link_customdata(fd, &mesh->mr->vdata, lvl->totvert); + direct_link_dverts(fd, lvl->totvert, CustomData_get(&mesh->mr->vdata, 0, CD_MDEFORMVERT)); + direct_link_customdata(fd, &mesh->mr->fdata, lvl->totface); + + if(mesh->mr->edge_flags) + mesh->mr->edge_flags= newdataadr(fd, mesh->mr->edge_flags); + if(mesh->mr->edge_creases) + mesh->mr->edge_creases= newdataadr(fd, mesh->mr->edge_creases); + + if(!mesh->mr->edge_flags) + mesh->mr->edge_flags= MEM_callocN(sizeof(short)*lvl->totedge, "Multires Edge Flags"); + if(!mesh->mr->edge_creases) + mesh->mr->edge_creases= MEM_callocN(sizeof(char)*lvl->totedge, "Multires Edge Creases"); + + mesh->mr->verts = newdataadr(fd, mesh->mr->verts); + + for(; lvl; lvl= lvl->next) { + lvl->verts= newdataadr(fd, lvl->verts); + lvl->faces= newdataadr(fd, lvl->faces); + lvl->edges= newdataadr(fd, lvl->edges); + lvl->colfaces= newdataadr(fd, lvl->colfaces); + lvl->edge_boundary_states= NULL; + lvl->vert_face_map = lvl->vert_edge_map = NULL; + lvl->map_mem= NULL; + } + } + + if((fd->flags & FD_FLAGS_SWITCH_ENDIAN) && mesh->tface) { + TFace *tf= mesh->tface; + int i; + + for (i=0; i< (mesh->pv ? mesh->pv->totface : mesh->totface); i++, tf++) { + SWITCH_INT(tf->col[0]); + SWITCH_INT(tf->col[1]); + SWITCH_INT(tf->col[2]); + SWITCH_INT(tf->col[3]); + } + } +} + +/* ************ READ LATTICE ***************** */ + +static void lib_link_latt(FileData *fd, Main *main) +{ + Lattice *lt; + + lt= main->latt.first; + while(lt) { + if(lt->id.flag & LIB_NEEDLINK) { + + lt->ipo= newlibadr_us(fd, lt->id.lib, lt->ipo); + lt->key= newlibadr_us(fd, lt->id.lib, lt->key); + + lt->id.flag -= LIB_NEEDLINK; + } + lt= lt->id.next; + } +} + +static void direct_link_latt(FileData *fd, Lattice *lt) +{ + lt->def= newdataadr(fd, lt->def); + + lt->dvert= newdataadr(fd, lt->dvert); + direct_link_dverts(fd, lt->pntsu*lt->pntsv*lt->pntsw, lt->dvert); +} + + +/* ************ READ OBJECT ***************** */ + +static void lib_link_modifiers__linkModifiers(void *userData, Object *ob, + ID **idpoin) +{ + FileData *fd = userData; + + *idpoin = newlibadr(fd, ob->id.lib, *idpoin); + /* hardcoded bad exception; non-object modifier data gets user count (texture, displace) */ + if(*idpoin && GS((*idpoin)->name)!=ID_OB) + (*idpoin)->us++; +} +static void lib_link_modifiers(FileData *fd, Object *ob) +{ + modifiers_foreachIDLink(ob, lib_link_modifiers__linkModifiers, fd); +} + +static void lib_link_object(FileData *fd, Main *main) +{ + Object *ob; + PartEff *paf; + bSensor *sens; + bController *cont; + bActuator *act; + void *poin; + int warn=0, a; + + ob= main->object.first; + while(ob) { + if(ob->id.flag & LIB_NEEDLINK) { + if (ob->id.properties) IDP_LibLinkProperty(ob->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + + ob->parent= newlibadr(fd, ob->id.lib, ob->parent); + ob->track= newlibadr(fd, ob->id.lib, ob->track); + ob->ipo= newlibadr_us(fd, ob->id.lib, ob->ipo); + ob->action = newlibadr_us(fd, ob->id.lib, ob->action); + ob->dup_group= newlibadr_us(fd, ob->id.lib, ob->dup_group); + + ob->proxy= newlibadr_us(fd, ob->id.lib, ob->proxy); + if(ob->proxy) { + /* paranoia check, actually a proxy_from pointer should never be written... */ + if(ob->proxy->id.lib==NULL) { + ob->proxy->proxy_from= NULL; + ob->proxy= NULL; + } + else { + /* this triggers object_update to always use a copy */ + ob->proxy->proxy_from= ob; + /* force proxy updates after load/undo, a bit weak */ + ob->recalc= ob->proxy->recalc= OB_RECALC; + } + } + ob->proxy_group= newlibadr(fd, ob->id.lib, ob->proxy_group); + + poin= ob->data; + ob->data= newlibadr_us(fd, ob->id.lib, ob->data); + + if(ob->data==NULL && poin!=NULL) { + ob->type= OB_EMPTY; + warn= 1; + if(ob->id.lib) printf("Can't find obdata of %s lib %s\n", ob->id.name+2, ob->id.lib->name); + else printf("Object %s lost data.", ob->id.name+2); + + if(ob->pose) { + free_pose_channels(ob->pose); + MEM_freeN(ob->pose); + ob->pose= NULL; + ob->flag &= ~OB_POSEMODE; + } + } + for(a=0; atotcol; a++) ob->mat[a]= newlibadr_us(fd, ob->id.lib, ob->mat[a]); + + ob->id.flag -= LIB_NEEDLINK; + /* if id.us==0 a new base will be created later on */ + + /* WARNING! Also check expand_object(), should reflect the stuff below. */ + lib_link_pose(fd, ob, ob->pose); + lib_link_constraints(fd, &ob->id, &ob->constraints); + lib_link_nlastrips(fd, &ob->id, &ob->nlastrips); + lib_link_constraint_channels(fd, &ob->id, &ob->constraintChannels); + + for(paf= ob->effect.first; paf; paf= paf->next) { + if(paf->type==EFF_PARTICLE) { + paf->group= newlibadr_us(fd, ob->id.lib, paf->group); + } + } + + sens= ob->sensors.first; + while(sens) { + if(ob->id.lib==NULL) { // done in expand_main + for(a=0; atotlinks; a++) { + sens->links[a]= newglobadr(fd, sens->links[a]); + } + } + if(sens->type==SENS_TOUCH) { + bTouchSensor *ts= sens->data; + ts->ma= newlibadr(fd, ob->id.lib, ts->ma); + } + else if(sens->type==SENS_MESSAGE) { + bMessageSensor *ms= sens->data; + ms->fromObject= + newlibadr(fd, ob->id.lib, ms->fromObject); + } + sens= sens->next; + } + + cont= ob->controllers.first; + while(cont) { + if(ob->id.lib==NULL) { // done in expand_main + for(a=0; atotlinks; a++) { + cont->links[a]= newglobadr(fd, cont->links[a]); + } + } + if(cont->type==CONT_PYTHON) { + bPythonCont *pc= cont->data; + pc->text= newlibadr(fd, ob->id.lib, pc->text); + } + cont->slinks= NULL; + cont->totslinks= 0; + + cont= cont->next; + } + + act= ob->actuators.first; + while(act) { + if(act->type==ACT_SOUND) { + bSoundActuator *sa= act->data; + sa->sound= newlibadr_us(fd, ob->id.lib, sa->sound); + } + else if(act->type==ACT_CD) { + /* bCDActuator *cda= act->data; */ + } + else if(act->type==ACT_GAME) { + /* bGameActuator *ga= act->data; */ + } + else if(act->type==ACT_CAMERA) { + bCameraActuator *ca= act->data; + ca->ob= newlibadr(fd, ob->id.lib, ca->ob); + } + /* leave this one, it's obsolete but necessary to read for conversion */ + else if(act->type==ACT_ADD_OBJECT) { + bAddObjectActuator *eoa= act->data; + if(eoa) eoa->ob= newlibadr(fd, ob->id.lib, eoa->ob); + } + else if(act->type==ACT_EDIT_OBJECT) { + bEditObjectActuator *eoa= act->data; + if(eoa==NULL) { + init_actuator(act); + } + else { + eoa->ob= newlibadr(fd, ob->id.lib, eoa->ob); + eoa->me= newlibadr(fd, ob->id.lib, eoa->me); + } + } + else if(act->type==ACT_SCENE) { + bSceneActuator *sa= act->data; + sa->camera= newlibadr(fd, ob->id.lib, sa->camera); + sa->scene= newlibadr(fd, ob->id.lib, sa->scene); + } + else if(act->type==ACT_ACTION) { + bActionActuator *aa= act->data; + aa->act= newlibadr(fd, ob->id.lib, aa->act); + } + else if(act->type==ACT_PROPERTY) { + bPropertyActuator *pa= act->data; + pa->ob= newlibadr(fd, ob->id.lib, pa->ob); + } + else if(act->type==ACT_MESSAGE) { + bMessageActuator *ma= act->data; + ma->toObject= newlibadr(fd, ob->id.lib, ma->toObject); + } + act= act->next; + } + + if(ob->fluidsimSettings) { + ob->fluidsimSettings->ipo = newlibadr_us(fd, ob->id.lib, ob->fluidsimSettings->ipo); + } + + lib_link_scriptlink(fd, &ob->id, &ob->scriptlink); + lib_link_modifiers(fd, ob); + } + ob= ob->id.next; + } + + if(warn) error("WARNING IN CONSOLE"); +} + + +static void direct_link_pose(FileData *fd, bPose *pose) { + + bPoseChannel *pchan; + + if (!pose) + return; + + link_list(fd, &pose->chanbase); + + for (pchan = pose->chanbase.first; pchan; pchan=pchan->next) { + pchan->bone= NULL; + pchan->parent= newdataadr(fd, pchan->parent); + pchan->child= newdataadr(fd, pchan->child); + direct_link_constraints(fd, &pchan->constraints); + pchan->iktree.first= pchan->iktree.last= NULL; + pchan->path= NULL; + } + +} + +static void direct_link_modifiers(FileData *fd, ListBase *lb) +{ + ModifierData *md; + + link_list(fd, lb); + + for (md=lb->first; md; md=md->next) { + md->error = NULL; + + /* if modifiers disappear, or for upward compatibility */ + if(NULL==modifierType_getInfo(md->type)) + md->type= eModifierType_None; + + if (md->type==eModifierType_Subsurf) { + SubsurfModifierData *smd = (SubsurfModifierData*) md; + + smd->emCache = smd->mCache = 0; + } else if (md->type==eModifierType_Hook) { + HookModifierData *hmd = (HookModifierData*) md; + + hmd->indexar= newdataadr(fd, hmd->indexar); + if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) { + int a; + for(a=0; atotindex; a++) { + SWITCH_INT(hmd->indexar[a]); + } + } + } + else if (md->type==eModifierType_MeshDeform) { + MeshDeformModifierData *mmd = (MeshDeformModifierData*) md; + + mmd->bindweights= newdataadr(fd, mmd->bindweights); + mmd->bindcos= newdataadr(fd, mmd->bindcos); + + if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) { + int a; + + for(a=0; atotcagevert*mmd->totvert; a++) + SWITCH_INT(mmd->bindweights[a]) + for(a=0; atotcagevert*3; a++) + SWITCH_INT(mmd->bindcos[a]) + } + } + } +} + +static void direct_link_nlastrips(FileData *fd, ListBase *strips) +{ + bActionStrip *strip; + + link_list(fd, strips); + + for(strip= strips->first; strip; strip= strip->next) + link_list(fd, &strip->modifiers); +} + +static void direct_link_object(FileData *fd, Object *ob) +{ + PartEff *paf; + bProperty *prop; + bSensor *sens; + bController *cont; + bActuator *act; + int a; + + /* weak weak... this was only meant as draw flag, now is used in give_base too */ + ob->flag &= ~OB_FROMGROUP; + + ob->disp.first=ob->disp.last= NULL; + + ob->pose= newdataadr(fd, ob->pose); + direct_link_pose(fd, ob->pose); + + link_list(fd, &ob->defbase); + direct_link_nlastrips(fd, &ob->nlastrips); + link_list(fd, &ob->constraintChannels); + + direct_link_scriptlink(fd, &ob->scriptlink); + + ob->mat= newdataadr(fd, ob->mat); + test_pointer_array(fd, (void **)&ob->mat); + + /* do it here, below old data gets converted */ + direct_link_modifiers(fd, &ob->modifiers); + + link_list(fd, &ob->effect); + paf= ob->effect.first; + while(paf) { + if(paf->type==EFF_PARTICLE) { + paf->keys= NULL; + } + if(paf->type==EFF_WAVE) { + WaveEff *wav = (WaveEff*) paf; + PartEff *next = paf->next; + WaveModifierData *wmd = (WaveModifierData*) modifier_new(eModifierType_Wave); + + wmd->damp = wav->damp; + wmd->flag = wav->flag; + wmd->height = wav->height; + wmd->lifetime = wav->lifetime; + wmd->narrow = wav->narrow; + wmd->speed = wav->speed; + wmd->startx = wav->startx; + wmd->starty = wav->startx; + wmd->timeoffs = wav->timeoffs; + wmd->width = wav->width; + + BLI_addtail(&ob->modifiers, wmd); + + BLI_remlink(&ob->effect, paf); + MEM_freeN(paf); + + paf = next; + continue; + } + if(paf->type==EFF_BUILD) { + BuildEff *baf = (BuildEff*) paf; + PartEff *next = paf->next; + BuildModifierData *bmd = (BuildModifierData*) modifier_new(eModifierType_Build); + + bmd->start = baf->sfra; + bmd->length = baf->len; + bmd->randomize = 0; + bmd->seed = 1; + + BLI_addtail(&ob->modifiers, bmd); + + BLI_remlink(&ob->effect, paf); + MEM_freeN(paf); + + paf = next; + continue; + } + paf= paf->next; + } + + ob->pd= newdataadr(fd, ob->pd); + ob->soft= newdataadr(fd, ob->soft); + if(ob->soft) { + SoftBody *sb= ob->soft; + + sb->bpoint= NULL; // init pointers so it gets rebuilt nicely + sb->bspring= NULL; + sb->scratch= NULL; + + + sb->keys= newdataadr(fd, sb->keys); + test_pointer_array(fd, (void **)&sb->keys); + if(sb->keys) { + for(a=0; atotkey; a++) { + sb->keys[a]= newdataadr(fd, sb->keys[a]); + } + } + } + ob->fluidsimSettings= newdataadr(fd, ob->fluidsimSettings); /* NT */ + if(ob->fluidsimSettings) { + // reinit mesh pointers + ob->fluidsimSettings->orgMesh = NULL; //ob->data; + ob->fluidsimSettings->meshSurface = NULL; + ob->fluidsimSettings->meshBB = NULL; + ob->fluidsimSettings->meshSurfNormals = NULL; + } + + link_list(fd, &ob->prop); + prop= ob->prop.first; + while(prop) { + prop->poin= newdataadr(fd, prop->poin); + if(prop->poin==0) prop->poin= &prop->data; + prop= prop->next; + } + + link_list(fd, &ob->sensors); + sens= ob->sensors.first; + while(sens) { + sens->data= newdataadr(fd, sens->data); + sens->links= newdataadr(fd, sens->links); + test_pointer_array(fd, (void **)&sens->links); + sens= sens->next; + } + + direct_link_constraints(fd, &ob->constraints); + + link_glob_list(fd, &ob->controllers); + cont= ob->controllers.first; + while(cont) { + cont->data= newdataadr(fd, cont->data); + cont->links= newdataadr(fd, cont->links); + test_pointer_array(fd, (void **)&cont->links); + cont= cont->next; + } + + link_glob_list(fd, &ob->actuators); + act= ob->actuators.first; + while(act) { + act->data= newdataadr(fd, act->data); + act= act->next; + } + + link_list(fd, &ob->hooks); + while (ob->hooks.first) { + ObHook *hook = ob->hooks.first; + HookModifierData *hmd = (HookModifierData*) modifier_new(eModifierType_Hook); + + hook->indexar= newdataadr(fd, hook->indexar); + if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) { + int a; + for(a=0; atotindex; a++) { + SWITCH_INT(hook->indexar[a]); + } + } + + /* Do conversion here because if we have loaded + * a hook we need to make sure it gets converted + * and free'd, regardless of version. + */ + VECCOPY(hmd->cent, hook->cent); + hmd->falloff = hook->falloff; + hmd->force = hook->force; + hmd->indexar = hook->indexar; + hmd->object = hook->parent; + memcpy(hmd->parentinv, hook->parentinv, sizeof(hmd->parentinv)); + hmd->totindex = hook->totindex; + + BLI_addhead(&ob->modifiers, hmd); + BLI_remlink(&ob->hooks, hook); + + MEM_freeN(hook); + } + + ob->bb= NULL; + ob->derivedDeform= NULL; + ob->derivedFinal= NULL; +} + +/* ************ READ SCENE ***************** */ + +static void lib_link_scene(FileData *fd, Main *main) +{ + Scene *sce; + Base *base, *next; + Editing *ed; + Sequence *seq; + SceneRenderLayer *srl; + int a; + + sce= main->scene.first; + while(sce) { + if(sce->id.flag & LIB_NEEDLINK) { + /*Link ID Properties -- and copy this comment EXACTLY for easy finding + of library blocks that implement this.*/ + if (sce->id.properties) IDP_LibLinkProperty(sce->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + + sce->camera= newlibadr(fd, sce->id.lib, sce->camera); + sce->world= newlibadr_us(fd, sce->id.lib, sce->world); + sce->set= newlibadr(fd, sce->id.lib, sce->set); + sce->ima= newlibadr_us(fd, sce->id.lib, sce->ima); + sce->toolsettings->imapaint.brush= + newlibadr_us(fd, sce->id.lib, sce->toolsettings->imapaint.brush); + + /* Sculptdata textures */ + for(a=0; asculptdata.mtex[a]; + if(mtex) + mtex->tex= newlibadr_us(fd, sce->id.lib, mtex->tex); + } + + for(base= sce->base.first; base; base= next) { + next= base->next; + + /* base->object= newlibadr_us(fd, sce->id.lib, base->object); */ + base->object= newlibadr_us(fd, sce->id.lib, base->object); + + /* when save during radiotool, needs cleared */ + base->flag &= ~OB_RADIO; + + if(base->object==NULL) { + printf("LIB ERROR: base removed\n"); + BLI_remlink(&sce->base, base); + if(base==sce->basact) sce->basact= 0; + MEM_freeN(base); + } + } + + ed= sce->ed; + if(ed) { + WHILE_SEQ(&ed->seqbase) { + if(seq->ipo) seq->ipo= newlibadr_us(fd, sce->id.lib, seq->ipo); + if(seq->scene) seq->scene= newlibadr(fd, sce->id.lib, seq->scene); + if(seq->sound) { + seq->sound= newlibadr(fd, sce->id.lib, seq->sound); + if (seq->sound) { + seq->sound->id.us++; + seq->sound->flags |= SOUND_FLAGS_SEQUENCE; + } + } + seq->anim= 0; + seq->hdaudio = 0; + } + END_SEQ + } + + lib_link_scriptlink(fd, &sce->id, &sce->scriptlink); + + if(sce->nodetree) + lib_link_ntree(fd, &sce->id, sce->nodetree); + + for(srl= sce->r.layers.first; srl; srl= srl->next) { + srl->mat_override= newlibadr_us(fd, sce->id.lib, srl->mat_override); + srl->light_override= newlibadr_us(fd, sce->id.lib, srl->light_override); + } + + sce->id.flag -= LIB_NEEDLINK; + } + + sce= sce->id.next; + } +} + +static void link_recurs_seq(FileData *fd, ListBase *lb) +{ + Sequence *seq; + + link_list(fd, lb); + seq= lb->first; + while(seq) { + if(seq->seqbase.first) link_recurs_seq(fd, &seq->seqbase); + seq= seq->next; + } +} + +static void direct_link_scene(FileData *fd, Scene *sce) +{ + Editing *ed; + Sequence *seq; + MetaStack *ms; + StripElem *se; + int a; + + sce->theDag = NULL; + sce->dagisvalid = 0; + /* set users to one by default, not in lib-link, this will increase it for compo nodes */ + sce->id.us= 1; + + link_list(fd, &(sce->base)); + + sce->basact= newdataadr(fd, sce->basact); + + sce->radio= newdataadr(fd, sce->radio); + + sce->toolsettings= newdataadr(fd, sce->toolsettings); + + sce->sculptdata.session= NULL; + /* SculptData textures */ + for(a=0; asculptdata.mtex[a]= newdataadr(fd,sce->sculptdata.mtex[a]); + + if(sce->ed) { + ListBase *old_seqbasep= &((Editing *)sce->ed)->seqbase; + + ed= sce->ed= newdataadr(fd, sce->ed); + + /* recursive link sequences, lb will be correctly initialized */ + link_recurs_seq(fd, &ed->seqbase); + + WHILE_SEQ(&ed->seqbase) { + seq->seq1= newdataadr(fd, seq->seq1); + seq->seq2= newdataadr(fd, seq->seq2); + seq->seq3= newdataadr(fd, seq->seq3); + /* a patch: after introduction of effects with 3 input strips */ + if(seq->seq3==0) seq->seq3= seq->seq2; + + seq->curelem= 0; + + seq->plugin= newdataadr(fd, seq->plugin); + seq->effectdata= newdataadr(fd, seq->effectdata); + + if (seq->type & SEQ_EFFECT) { + seq->flag |= SEQ_EFFECT_NOT_LOADED; + } + + seq->strip= newdataadr(fd, seq->strip); + if(seq->strip && seq->strip->done==0) { + seq->strip->done= 1; + + /* standard: strips from effects/metas are not written, but are mallocced */ + + if(seq->type==SEQ_IMAGE) { + seq->strip->stripdata= newdataadr(fd, seq->strip->stripdata); + se= seq->strip->stripdata; + if(se) { + for(a=0; astrip->len; a++, se++) { + se->ok= 1; + se->ibuf= 0; + } + } + } + else if(seq->type==SEQ_MOVIE) { + /* only first stripelem is in file */ + se= newdataadr(fd, seq->strip->stripdata); + + if(se) { + seq->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem"); + *seq->strip->stripdata= *se; + MEM_freeN(se); + + se= seq->strip->stripdata; + + for(a=0; astrip->len; a++, se++) { + se->ok= 1; + se->ibuf= 0; + se->nr= a + 1; + } + } + } + else if(seq->type==SEQ_RAM_SOUND + || seq->type == SEQ_HD_SOUND) { + /* only first stripelem is in file */ + se= newdataadr(fd, seq->strip->stripdata); + + if(se) { + seq->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem"); + *seq->strip->stripdata= *se; + MEM_freeN(se); + + se= seq->strip->stripdata; + + for(a=0; astrip->len; a++, se++) { + se->ok= 2; /* why? */ + se->ibuf= 0; + se->nr= a + 1; + } + } + } + else if(seq->len>0) + seq->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem"); + + } + } + END_SEQ + + /* link metastack, slight abuse of structs here, have to restore pointer to internal part in struct */ + { + Sequence temp; + char *poin; + long offset; + + offset= ((long)&(temp.seqbase)) - ((long)&temp); + + /* root pointer */ + if(ed->seqbasep == old_seqbasep) { + ed->seqbasep= &ed->seqbase; + } + else { + + poin= (char *)ed->seqbasep; + poin -= offset; + + poin= newdataadr(fd, poin); + if(poin) ed->seqbasep= (ListBase *)(poin+offset); + else ed->seqbasep= &ed->seqbase; + } + /* stack */ + link_list(fd, &(ed->metastack)); + + for(ms= ed->metastack.first; ms; ms= ms->next) { + ms->parseq= newdataadr(fd, ms->parseq); + + if(ms->oldbasep == old_seqbasep) + ms->oldbasep= &ed->seqbase; + else { + poin= (char *)ms->oldbasep; + poin -= offset; + poin= newdataadr(fd, poin); + if(poin) ms->oldbasep= (ListBase *)(poin+offset); + else ms->oldbasep= &ed->seqbase; + } + } + } + } + + direct_link_scriptlink(fd, &sce->scriptlink); + + sce->r.avicodecdata = newdataadr(fd, sce->r.avicodecdata); + if (sce->r.avicodecdata) { + sce->r.avicodecdata->lpFormat = newdataadr(fd, sce->r.avicodecdata->lpFormat); + sce->r.avicodecdata->lpParms = newdataadr(fd, sce->r.avicodecdata->lpParms); + } + + sce->r.qtcodecdata = newdataadr(fd, sce->r.qtcodecdata); + if (sce->r.qtcodecdata) { + sce->r.qtcodecdata->cdParms = newdataadr(fd, sce->r.qtcodecdata->cdParms); + } + + link_list(fd, &(sce->markers)); + link_list(fd, &(sce->r.layers)); + + sce->nodetree= newdataadr(fd, sce->nodetree); + if(sce->nodetree) + direct_link_nodetree(fd, sce->nodetree); + +} + +/* Nasty exception; IpoWindow stores a non-ID pointer in *from for sequence + strips... bad code warning! + + We work around it by retrieving the missing pointer from the corresponding + Sequence-structure. + + This is needed, to make Ipo-Pinning work for Sequence-Ipos... +*/ +static Sequence * find_sequence_from_ipo_helper(Main * main, Ipo * ipo) +{ + Editing *ed; + Sequence *seq = NULL; + + Scene * sce= main->scene.first; + while(sce) { + if(sce->ed) { + int found = 0; + + ed= sce->ed; + + WHILE_SEQ(&ed->seqbase) { + if (seq->ipo == ipo) { + found = 1; + break; + } + } + END_SEQ + if (found) { + break; + } + seq = NULL; + } + sce= sce->id.next; + } + if (seq) + return seq; + else + return NULL; +} + +static void lib_link_screen_sequence_ipos(Main *main) +{ + bScreen *sc; + ScrArea *sa; + + for(sc= main->screen.first; sc; sc= sc->id.next) { + for(sa= sc->areabase.first; sa; sa= sa->next) { + SpaceLink *sl; + for (sl= sa->spacedata.first; sl; sl= sl->next) { + if(sl->spacetype == SPACE_IPO) { + SpaceIpo *sipo= (SpaceIpo *)sl; + if(sipo->blocktype==ID_SEQ) { + sipo->from = (ID*) find_sequence_from_ipo_helper(main, sipo->ipo); + } + } + } + } + } +} + +/* ************ READ SCREEN ***************** */ + +/* note: file read without screens option G_FILE_NO_UI; + check lib pointers in call below */ +static void lib_link_screen(FileData *fd, Main *main) +{ + bScreen *sc; + ScrArea *sa; + + for(sc= main->screen.first; sc; sc= sc->id.next) { + if(sc->id.flag & LIB_NEEDLINK) { + sc->id.us= 1; + sc->scene= newlibadr(fd, sc->id.lib, sc->scene); + + sa= sc->areabase.first; + while(sa) { + SpaceLink *sl; + + sa->full= newlibadr(fd, sc->id.lib, sa->full); + + /* space handler scriptlinks */ + lib_link_scriptlink(fd, &sc->id, &sa->scriptlink); + + for (sl= sa->spacedata.first; sl; sl= sl->next) { + if(sl->spacetype==SPACE_VIEW3D) { + View3D *v3d= (View3D*) sl; + + v3d->camera= newlibadr(fd, sc->id.lib, v3d->camera); + v3d->ob_centre= newlibadr(fd, sc->id.lib, v3d->ob_centre); + + if(v3d->bgpic) { + v3d->bgpic->ima= newlibadr_us(fd, sc->id.lib, v3d->bgpic->ima); + } + if(v3d->localvd) { + v3d->localvd->camera= newlibadr(fd, sc->id.lib, v3d->localvd->camera); + } + v3d->depths= NULL; + v3d->ri= NULL; + } + else if(sl->spacetype==SPACE_IPO) { + SpaceIpo *sipo= (SpaceIpo *)sl; + sipo->editipo= 0; + + if(sipo->blocktype==ID_SEQ) sipo->from= NULL; // no libdata + else sipo->from= newlibadr(fd, sc->id.lib, sipo->from); + + sipo->ipokey.first= sipo->ipokey.last= 0; + sipo->ipo= newlibadr(fd, sc->id.lib, sipo->ipo); + } + else if(sl->spacetype==SPACE_BUTS) { + SpaceButs *sbuts= (SpaceButs *)sl; + sbuts->lockpoin= NULL; + sbuts->ri= NULL; + if(main->versionfile<132) set_rects_butspace(sbuts); + } + else if(sl->spacetype==SPACE_FILE) { + SpaceFile *sfile= (SpaceFile *)sl; + + sfile->filelist= NULL; + sfile->libfiledata= NULL; + sfile->returnfunc= NULL; + sfile->menup= NULL; + sfile->pupmenu= NULL; + } + else if(sl->spacetype==SPACE_IMASEL) { + SpaceImaSel *simasel= (SpaceImaSel *)sl; + + simasel->files = NULL; + simasel->returnfunc= NULL; + simasel->menup= NULL; + simasel->pupmenu= NULL; + simasel->img= NULL; + } + else if(sl->spacetype==SPACE_ACTION) { + SpaceAction *saction= (SpaceAction *)sl; + saction->action = newlibadr(fd, sc->id.lib, saction->action); + } + else if(sl->spacetype==SPACE_IMAGE) { + SpaceImage *sima= (SpaceImage *)sl; + + sima->image= newlibadr_us(fd, sc->id.lib, sima->image); + } + else if(sl->spacetype==SPACE_NLA){ + /* SpaceNla *snla= (SpaceNla *)sl; */ + } + else if(sl->spacetype==SPACE_TEXT) { + SpaceText *st= (SpaceText *)sl; + + st->text= newlibadr(fd, sc->id.lib, st->text); + + } + else if(sl->spacetype==SPACE_SCRIPT) { + SpaceScript *sc= (SpaceScript *)sl; + + sc->script = NULL; + } + else if(sl->spacetype==SPACE_OOPS) { + SpaceOops *so= (SpaceOops *)sl; + Oops *oops; + TreeStoreElem *tselem; + int a; + + oops= so->oops.first; + while(oops) { + oops->id= newlibadr(fd, NULL, oops->id); + oops= oops->next; + } + so->lockpoin= NULL; + so->tree.first= so->tree.last= NULL; + so->search_tse.id= newlibadr(fd, NULL, so->search_tse.id); + + if(so->treestore) { + tselem= so->treestore->data; + for(a=0; atreestore->usedelem; a++, tselem++) { + tselem->id= newlibadr(fd, NULL, tselem->id); + } + } + } + else if(sl->spacetype==SPACE_SOUND) { + SpaceSound *ssound= (SpaceSound *)sl; + + ssound->sound= newlibadr_us(fd, sc->id.lib, ssound->sound); + } + } + sa= sa->next; + } + sc->id.flag -= LIB_NEEDLINK; + } + } +} + +/* Only for undo files, or to restore a screen after reading without UI... */ +static void *restore_pointer_by_name(Main *mainp, ID *id, int user) +{ + + if(id) { + ListBase *lb= wich_libbase(mainp, GS(id->name)); + + if(lb) { // there's still risk of checking corrupt mem (freed Ids in oops) + ID *idn= lb->first; + char *name= id->name+2; + + while(idn) { + if(idn->name[2]==name[0] && strcmp(idn->name+2, name)==0) { + if(idn->lib==id->lib) { + if(user && idn->us==0) idn->us++; + break; + } + } + idn= idn->next; + } + return idn; + } + } + return NULL; +} + +/* called from kernel/blender.c */ +/* used to link a file (without UI) to the current UI */ +/* note that it assumes the old pointers in UI are still valid, so old Main is not freed */ +void lib_link_screen_restore(Main *newmain, Scene *curscene) +{ + bScreen *sc; + ScrArea *sa; + + for(sc= newmain->screen.first; sc; sc= sc->id.next) { + + sc->scene= curscene; + + sa= sc->areabase.first; + while(sa) { + SpaceLink *sl; + + if (sa->scriptlink.totscript) { + /* restore screen area script links */ + ScriptLink *slink = &sa->scriptlink; + int script_idx; + for (script_idx = 0; script_idx < slink->totscript; script_idx++) { + slink->scripts[script_idx] = restore_pointer_by_name(newmain, + (ID *)slink->scripts[script_idx], 1); + } + } + + for (sl= sa->spacedata.first; sl; sl= sl->next) { + if(sl->spacetype==SPACE_VIEW3D) { + View3D *v3d= (View3D*) sl; + + v3d->camera= restore_pointer_by_name(newmain, (ID *)v3d->camera, 1); + if(v3d->camera==NULL) + v3d->camera= sc->scene->camera; + v3d->ob_centre= restore_pointer_by_name(newmain, (ID *)v3d->ob_centre, 1); + + if(v3d->bgpic) { + v3d->bgpic->ima= restore_pointer_by_name(newmain, (ID *)v3d->bgpic->ima, 1); + } + if(v3d->localvd) { + Base *base; + + v3d->localvd->camera= sc->scene->camera; + + /* localview can become invalid during undo/redo steps, so we exit it when no could be found */ + for(base= sc->scene->base.first; base; base= base->next) { + if(base->lay & v3d->lay) break; + } + if(base==NULL) { + v3d->lay= v3d->localvd->lay; + v3d->layact= v3d->localvd->layact; + MEM_freeN(v3d->localvd); + v3d->localvd= NULL; + v3d->localview= 0; + } + } + else if(v3d->scenelock) v3d->lay= sc->scene->lay; + + /* not very nice, but could help */ + if((v3d->layact & v3d->lay)==0) v3d->layact= v3d->lay; + + } + else if(sl->spacetype==SPACE_IPO) { + SpaceIpo *sipo= (SpaceIpo *)sl; + + if(sipo->blocktype==ID_SEQ) sipo->from= NULL; // no libdata + else sipo->from= restore_pointer_by_name(newmain, (ID *)sipo->from, 0); + + // not free sipo->ipokey, creates dependency with src/ + sipo->ipo= restore_pointer_by_name(newmain, (ID *)sipo->ipo, 0); + if(sipo->editipo) MEM_freeN(sipo->editipo); + sipo->editipo= NULL; + } + else if(sl->spacetype==SPACE_BUTS) { + SpaceButs *sbuts= (SpaceButs *)sl; + sbuts->lockpoin= NULL; + if (sbuts->ri) sbuts->ri->curtile = 0; + } + else if(sl->spacetype==SPACE_FILE) { + SpaceFile *sfile= (SpaceFile *)sl; + if(sfile->libfiledata) + BLO_blendhandle_close(sfile->libfiledata); + sfile->libfiledata= 0; + } + else if(sl->spacetype==SPACE_IMASEL) { + SpaceImaSel *simasel= (SpaceImaSel *)sl; + if (simasel->files) { + BIF_filelist_freelib(simasel->files); + } + } + else if(sl->spacetype==SPACE_ACTION) { + SpaceAction *saction= (SpaceAction *)sl; + saction->action = restore_pointer_by_name(newmain, (ID *)saction->action, 1); + } + else if(sl->spacetype==SPACE_IMAGE) { + SpaceImage *sima= (SpaceImage *)sl; + + sima->image= restore_pointer_by_name(newmain, (ID *)sima->image, 1); + } + else if(sl->spacetype==SPACE_NLA){ + /* SpaceNla *snla= (SpaceNla *)sl; */ + } + else if(sl->spacetype==SPACE_TEXT) { + SpaceText *st= (SpaceText *)sl; + + st->text= restore_pointer_by_name(newmain, (ID *)st->text, 1); + if(st->text==NULL) st->text= newmain->text.first; + } + else if(sl->spacetype==SPACE_SCRIPT) { + SpaceScript *sc= (SpaceScript *)sl; + + sc->script = NULL; + } + else if(sl->spacetype==SPACE_OOPS) { + SpaceOops *so= (SpaceOops *)sl; + Oops *oops; + int a; + + oops= so->oops.first; + while(oops) { + oops->id= restore_pointer_by_name(newmain, (ID *)oops->id, 0); + oops= oops->next; + } + so->lockpoin= NULL; + so->search_tse.id= restore_pointer_by_name(newmain, so->search_tse.id, 0); + + if(so->treestore) { + TreeStore *ts= so->treestore; + TreeStoreElem *tselem=ts->data; + for(a=0; ausedelem; a++, tselem++) { + tselem->id= restore_pointer_by_name(newmain, tselem->id, 0); + } + } + } + else if(sl->spacetype==SPACE_SOUND) { + SpaceSound *ssound= (SpaceSound *)sl; + + ssound->sound= restore_pointer_by_name(newmain, (ID *)ssound->sound, 1); + } + else if(sl->spacetype==SPACE_NODE) { + SpaceNode *snode= (SpaceNode *)sl; + + snode->nodetree= snode->edittree= NULL; + snode->flag |= SNODE_DO_PREVIEW; + } + } + sa= sa->next; + } + } +} + +static void direct_link_screen(FileData *fd, bScreen *sc) +{ + ScrArea *sa; + ScrVert *sv; + ScrEdge *se; + Oops *oops; + int a; + + link_list(fd, &(sc->vertbase)); + link_list(fd, &(sc->edgebase)); + link_list(fd, &(sc->areabase)); + sc->winakt= 0; + + /* hacky patch... but people have been saving files with the verse-blender, + causing the handler to keep running for ever, with no means to disable it */ + for(a=0; ahandler[a]==SCREEN_HANDLER_VERSE) { + sc->handler[a]= 0; + break; + } + } + + /* edges */ + se= sc->edgebase.first; + while(se) { + se->v1= newdataadr(fd, se->v1); + se->v2= newdataadr(fd, se->v2); + if( (long)se->v1 > (long)se->v2) { + sv= se->v1; + se->v1= se->v2; + se->v2= sv; + } + + if(se->v1==NULL) { + printf("error reading screen... file corrupt\n"); + se->v1= se->v2; + } + se= se->next; + } + + /* areas */ + sa= sc->areabase.first; + while(sa) { + Panel *pa; + SpaceLink *sl; + + link_list(fd, &(sa->spacedata)); + link_list(fd, &(sa->panels)); + + /* accident can happen when read/save new file with older version */ + if(sa->spacedata.first==NULL && sa->spacetype>SPACE_NLA) + sa->spacetype= SPACE_EMPTY; + + for(pa= sa->panels.first; pa; pa=pa->next) { + pa->paneltab= newdataadr(fd, pa->paneltab); + pa->active= 0; + pa->sortcounter= 0; + } + + for (sl= sa->spacedata.first; sl; sl= sl->next) { + if (sl->spacetype==SPACE_VIEW3D) { + View3D *v3d= (View3D*) sl; + v3d->bgpic= newdataadr(fd, v3d->bgpic); + if(v3d->bgpic) + v3d->bgpic->iuser.ok= 1; + v3d->localvd= newdataadr(fd, v3d->localvd); + v3d->afterdraw.first= v3d->afterdraw.last= NULL; + v3d->clipbb= newdataadr(fd, v3d->clipbb); + v3d->retopo_view_data= NULL; + v3d->properties_storage= NULL; + } + else if (sl->spacetype==SPACE_OOPS) { + SpaceOops *soops= (SpaceOops*) sl; + + link_list(fd, &(soops->oops)); + oops= soops->oops.first; + while(oops) { + oops->link.first= oops->link.last= 0; + oops= oops->next; + } + + soops->treestore= newdataadr(fd, soops->treestore); + if(soops->treestore) { + soops->treestore->data= newdataadr(fd, soops->treestore->data); + /* we only saved what was used */ + soops->treestore->totelem= soops->treestore->usedelem; + soops->storeflag |= SO_TREESTORE_CLEANUP; // at first draw + } + } + else if(sl->spacetype==SPACE_IMAGE) { + SpaceImage *sima= (SpaceImage *)sl; + + sima->cumap= newdataadr(fd, sima->cumap); + if(sima->cumap) + direct_link_curvemapping(fd, sima->cumap); + sima->info_str= sima->info_spare= NULL; + sima->spare= NULL; + sima->iuser.ok= 1; + } + else if(sl->spacetype==SPACE_NODE) { + SpaceNode *snode= (SpaceNode *)sl; + snode->nodetree= snode->edittree= NULL; + snode->flag |= SNODE_DO_PREVIEW; + } + } + + sa->v1= newdataadr(fd, sa->v1); + sa->v2= newdataadr(fd, sa->v2); + sa->v3= newdataadr(fd, sa->v3); + sa->v4= newdataadr(fd, sa->v4); + + sa->win= sa->headwin= 0; + + sa->uiblocks.first= sa->uiblocks.last= NULL; + + /* space handler scriptlinks */ + direct_link_scriptlink(fd, &sa->scriptlink); + + sa= sa->next; + } +} + +/* ********** READ LIBRARY *************** */ + + +static void direct_link_library(FileData *fd, Library *lib, Main *main) +{ + Main *newmain; + + for(newmain= fd->mainlist.first; newmain; newmain= newmain->next) { + if(newmain->curlib) { + if(strcmp(newmain->curlib->filename, lib->filename)==0) { + printf("Fixed error in file; multiple instances of lib:\n %s\n", lib->filename); + + change_idid_adr(&fd->mainlist, fd, lib, newmain->curlib); +// change_idid_adr_fd(fd, lib, newmain->curlib); + + BLI_remlink(&main->library, lib); + MEM_freeN(lib); + + error("Library had multiple instances, save and reload!"); + return; + } + } + } + /* make sure we have full path in lib->filename */ + BLI_strncpy(lib->filename, lib->name, sizeof(lib->name)); + cleanup_path(fd->filename, lib->filename); + +// printf("direct_link_library: name %s\n", lib->name); +// printf("direct_link_library: filename %s\n", lib->filename); + + /* new main */ + newmain= MEM_callocN(sizeof(Main), "directlink"); + BLI_addtail(&fd->mainlist, newmain); + newmain->curlib= lib; + + lib->parent= NULL; +} + +static void lib_link_library(FileData *fd, Main *main) +{ + Library *lib; + + lib= main->library.first; + while(lib) { + lib->id.us= 1; + lib= lib->id.next; + } +} + +/* ************** READ SOUND ******************* */ + +static void direct_link_sound(FileData *fd, bSound *sound) +{ + sound->sample = NULL; + sound->snd_sound = NULL; + + sound->packedfile = direct_link_packedfile(fd, sound->packedfile); + sound->newpackedfile = direct_link_packedfile(fd, sound->newpackedfile); +} + +static void lib_link_sound(FileData *fd, Main *main) +{ + bSound *sound; + + sound= main->sound.first; + while(sound) { + if(sound->id.flag & LIB_NEEDLINK) { + sound->id.flag -= LIB_NEEDLINK; + sound->ipo= newlibadr_us(fd, sound->id.lib, sound->ipo); + sound->stream = 0; + } + sound= sound->id.next; + } +} +/* ***************** READ GROUP *************** */ + +static void direct_link_group(FileData *fd, Group *group) +{ + link_list(fd, &group->gobject); +} + +static void lib_link_group(FileData *fd, Main *main) +{ + Group *group= main->group.first; + GroupObject *go; + int add_us; + + while(group) { + if(group->id.flag & LIB_NEEDLINK) { + group->id.flag -= LIB_NEEDLINK; + + add_us= 0; + + go= group->gobject.first; + while(go) { + go->ob= newlibadr(fd, group->id.lib, go->ob); + if(go->ob) { + go->ob->flag |= OB_FROMGROUP; + /* if group has an object, it increments user... */ + add_us= 1; + if(go->ob->id.us==0) + go->ob->id.us= 1; + } + go= go->next; + } + if(add_us) group->id.us++; + rem_from_group(group, NULL); /* removes NULL entries */ + } + group= group->id.next; + } +} + +/* ************** GENERAL & MAIN ******************** */ + + +static char *dataname(short id_code) +{ + + switch( id_code ) { + case ID_OB: return "Data from OB"; + case ID_ME: return "Data from ME"; + case ID_IP: return "Data from IP"; + case ID_SCE: return "Data from SCE"; + case ID_MA: return "Data from MA"; + case ID_TE: return "Data from TE"; + case ID_CU: return "Data from CU"; + case ID_GR: return "Data from GR"; + case ID_AR: return "Data from AR"; + case ID_AC: return "Data from AC"; + case ID_LI: return "Data from LI"; + case ID_MB: return "Data from MB"; + case ID_IM: return "Data from IM"; + case ID_LT: return "Data from LT"; + case ID_LA: return "Data from LA"; + case ID_CA: return "Data from CA"; + case ID_KE: return "Data from KE"; + case ID_WO: return "Data from WO"; + case ID_SCR: return "Data from SCR"; + case ID_VF: return "Data from VF"; + case ID_TXT : return "Data from TXT"; + case ID_SO: return "Data from SO"; + case ID_NT: return "Data from NT"; + case ID_BR: return "Data from BR"; + } + return "Data from Lib Block"; + +} + +static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID **id_r) +{ + /* this routine reads a libblock and its direct data. Use link functions + * to connect it all + */ + + ID *id; + ListBase *lb; + char *allocname; + + /* read libblock */ + id = read_struct(fd, bhead, "lib block"); + if (id_r) + *id_r= id; + if (!id) + return blo_nextbhead(fd, bhead); + + oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code); /* for ID_ID check */ + + /* do after read_struct, for dna reconstruct */ + if(bhead->code==ID_ID) { + lb= wich_libbase(main, GS(id->name)); + } + else { + lb= wich_libbase(main, bhead->code); + } + + BLI_addtail(lb, id); + + /* clear first 8 bits */ + id->flag= (id->flag & 0xFF00) | flag | LIB_NEEDLINK; + id->lib= main->curlib; + if(id->flag & LIB_FAKEUSER) id->us= 1; + else id->us= 0; + id->icon_id = 0; + + /* this case cannot be direct_linked: it's just the ID part */ + if(bhead->code==ID_ID) { + return blo_nextbhead(fd, bhead); + } + + bhead = blo_nextbhead(fd, bhead); + + /* need a name for the mallocN, just for debugging and sane prints on leaks */ + allocname= dataname(GS(id->name)); + + /* read all data */ + while(bhead && bhead->code==DATA) { + void *data= read_struct(fd, bhead, allocname); + + if (data) { + oldnewmap_insert(fd->datamap, bhead->old, data, 0); + } + + bhead = blo_nextbhead(fd, bhead); + } + + /* init pointers direct data */ + switch( GS(id->name) ) { + case ID_SCR: + direct_link_screen(fd, (bScreen *)id); + break; + case ID_SCE: + direct_link_scene(fd, (Scene *)id); + break; + case ID_OB: + direct_link_object(fd, (Object *)id); + break; + case ID_ME: + direct_link_mesh(fd, (Mesh *)id); + break; + case ID_CU: + direct_link_curve(fd, (Curve *)id); + break; + case ID_MB: + direct_link_mball(fd, (MetaBall *)id); + break; + case ID_MA: + direct_link_material(fd, (Material *)id); + break; + case ID_TE: + direct_link_texture(fd, (Tex *)id); + break; + case ID_IM: + direct_link_image(fd, (Image *)id); + break; + case ID_LA: + direct_link_lamp(fd, (Lamp *)id); + break; + case ID_VF: + direct_link_vfont(fd, (VFont *)id); + break; + case ID_TXT: + direct_link_text(fd, (Text *)id); + break; + case ID_IP: + direct_link_ipo(fd, (Ipo *)id); + break; + case ID_KE: + direct_link_key(fd, (Key *)id); + break; + case ID_LT: + direct_link_latt(fd, (Lattice *)id); + break; + case ID_WO: + direct_link_world(fd, (World *)id); + break; + case ID_LI: + direct_link_library(fd, (Library *)id, main); + break; + case ID_CA: + direct_link_camera(fd, (Camera *)id); + break; + case ID_SO: + direct_link_sound(fd, (bSound *)id); + break; + case ID_GR: + direct_link_group(fd, (Group *)id); + break; + case ID_AR: + direct_link_armature(fd, (bArmature*)id); + break; + case ID_AC: + direct_link_action(fd, (bAction*)id); + break; + case ID_NT: + direct_link_nodetree(fd, (bNodeTree*)id); + break; + case ID_BR: + direct_link_brush(fd, (Brush*)id); + break; + } + + /*link direct data of ID properties*/ + if (id->properties) { + id->properties = newdataadr(fd, id->properties); + IDP_DirectLinkProperty(id->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + } + + oldnewmap_free_unused(fd->datamap); + oldnewmap_clear(fd->datamap); + + return (bhead); +} + +static void link_global(FileData *fd, BlendFileData *bfd, FileGlobal *fg) +{ + // this is nonsense... make it struct once (ton) + bfd->winpos= fg->winpos; + bfd->fileflags= fg->fileflags; + bfd->displaymode= fg->displaymode; + bfd->globalf= fg->globalf; + + bfd->curscreen= newlibadr(fd, 0, fg->curscreen); + bfd->curscene= newlibadr(fd, 0, fg->curscene); + // this happens in files older than 2.35 + if(bfd->curscene==NULL) { + if(bfd->curscreen) bfd->curscene= bfd->curscreen->scene; + } +} + +static void vcol_to_fcol(Mesh *me) +{ + MFace *mface; + unsigned int *mcol, *mcoln, *mcolmain; + int a; + + if(me->totface==0 || me->mcol==0) return; + + mcoln= mcolmain= MEM_mallocN(4*sizeof(int)*me->totface, "mcoln"); + mcol = (unsigned int *)me->mcol; + mface= me->mface; + for(a=me->totface; a>0; a--, mface++) { + mcoln[0]= mcol[mface->v1]; + mcoln[1]= mcol[mface->v2]; + mcoln[2]= mcol[mface->v3]; + mcoln[3]= mcol[mface->v4]; + mcoln+= 4; + } + + MEM_freeN(me->mcol); + me->mcol= (MCol *)mcolmain; +} + +static int map_223_keybd_code_to_224_keybd_code(int code) +{ + switch (code) { + case 312: return F12KEY; + case 159: return PADSLASHKEY; + case 161: return PAD0; + case 154: return PAD1; + case 150: return PAD2; + case 155: return PAD3; + case 151: return PAD4; + case 156: return PAD5; + case 152: return PAD6; + case 157: return PAD7; + case 153: return PAD8; + case 158: return PAD9; + default: return code; + } +} + +static void bone_version_238(ListBase *lb) +{ + Bone *bone; + + for(bone= lb->first; bone; bone= bone->next) { + if(bone->rad_tail==0.0f && bone->rad_head==0.0f) { + bone->rad_head= 0.25f*bone->length; + bone->rad_tail= 0.1f*bone->length; + + bone->dist-= bone->rad_head; + if(bone->dist<=0.0f) bone->dist= 0.0f; + } + bone_version_238(&bone->childbase); + } +} + +static void bone_version_239(ListBase *lb) +{ + Bone *bone; + + for(bone= lb->first; bone; bone= bone->next) { + if(bone->layer==0) + bone->layer= 1; + bone_version_239(&bone->childbase); + } +} + +static void ntree_version_241(bNodeTree *ntree) +{ + bNode *node; + + if(ntree->type==NTREE_COMPOSIT) { + for(node= ntree->nodes.first; node; node= node->next) { + if(node->type==CMP_NODE_BLUR) { + if(node->storage==NULL) { + NodeBlurData *nbd= MEM_callocN(sizeof(NodeBlurData), "node blur patch"); + nbd->sizex= node->custom1; + nbd->sizey= node->custom2; + nbd->filtertype= R_FILTER_QUAD; + node->storage= nbd; + } + } + else if(node->type==CMP_NODE_VECBLUR) { + if(node->storage==NULL) { + NodeBlurData *nbd= MEM_callocN(sizeof(NodeBlurData), "node blur patch"); + nbd->samples= node->custom1; + nbd->maxspeed= node->custom2; + nbd->fac= 1.0f; + node->storage= nbd; + } + } + } + } +} + +static void ntree_version_242(bNodeTree *ntree) +{ + bNode *node; + + if(ntree->type==NTREE_COMPOSIT) { + for(node= ntree->nodes.first; node; node= node->next) { + if(node->type==CMP_NODE_HUE_SAT) { + if(node->storage) { + NodeHueSat *nhs= node->storage; + if(nhs->val==0.0f) nhs->val= 1.0f; + } + } + } + } + else if(ntree->type==NTREE_SHADER) { + for(node= ntree->nodes.first; node; node= node->next) + if(node->type == SH_NODE_GEOMETRY && node->storage == NULL) + node->storage= MEM_callocN(sizeof(NodeGeometry), "NodeGeometry"); + } + +} + + +/* somehow, probably importing via python, keyblock adrcodes are not in order */ +static void sort_shape_fix(Main *main) +{ + Key *key; + KeyBlock *kb; + int sorted= 0; + + while(sorted==0) { + sorted= 1; + for(key= main->key.first; key; key= key->id.next) { + for(kb= key->block.first; kb; kb= kb->next) { + if(kb->next && kb->adrcode>kb->next->adrcode) { + KeyBlock *next= kb->next; + BLI_remlink(&key->block, kb); + BLI_insertlink(&key->block, next, kb); + kb= next; + sorted= 0; + } + } + } + if(sorted==0) printf("warning, shape keys were sorted incorrect, fixed it!\n"); + } +} + +static void customdata_version_242(Mesh *me) +{ + CustomDataLayer *layer; + MTFace *mtf; + MCol *mcol; + TFace *tf; + int a, mtfacen, mcoln; + + if (!me->vdata.totlayer) { + CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, me->mvert, me->totvert); + + if (me->msticky) + CustomData_add_layer(&me->vdata, CD_MSTICKY, CD_ASSIGN, me->msticky, me->totvert); + if (me->dvert) + CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_ASSIGN, me->dvert, me->totvert); + } + + if (!me->edata.totlayer) + CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, me->medge, me->totedge); + + if (!me->fdata.totlayer) { + CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, me->mface, me->totface); + + if (me->tface) { + if (me->mcol) + MEM_freeN(me->mcol); + + me->mcol= CustomData_add_layer(&me->fdata, CD_MCOL, CD_CALLOC, NULL, me->totface); + me->mtface= CustomData_add_layer(&me->fdata, CD_MTFACE, CD_CALLOC, NULL, me->totface); + + mtf= me->mtface; + mcol= me->mcol; + tf= me->tface; + + for (a=0; a < me->totface; a++, mtf++, tf++, mcol+=4) { + memcpy(mcol, tf->col, sizeof(tf->col)); + memcpy(mtf->uv, tf->uv, sizeof(tf->uv)); + + mtf->flag= tf->flag; + mtf->unwrap= tf->unwrap; + mtf->mode= tf->mode; + mtf->tile= tf->tile; + mtf->tpage= tf->tpage; + mtf->transp= tf->transp; + } + + MEM_freeN(me->tface); + me->tface= NULL; + } + else if (me->mcol) { + me->mcol= CustomData_add_layer(&me->fdata, CD_MCOL, CD_ASSIGN, me->mcol, me->totface); + } + } + + if (me->tface) { + MEM_freeN(me->tface); + me->tface= NULL; + } + + for (a=0, mtfacen=0, mcoln=0; a < me->fdata.totlayer; a++) { + layer= &me->fdata.layers[a]; + + if (layer->type == CD_MTFACE) { + if (layer->name[0] == 0) { + if (mtfacen == 0) strcpy(layer->name, "UVTex"); + else sprintf(layer->name, "UVTex.%.3d", mtfacen); + } + mtfacen++; + } + else if (layer->type == CD_MCOL) { + if (layer->name[0] == 0) { + if (mcoln == 0) strcpy(layer->name, "Col"); + else sprintf(layer->name, "Col.%.3d", mcoln); + } + mcoln++; + } + } + + mesh_update_customdata_pointers(me); +} + +/*only copy render texface layer from active*/ +static void customdata_version_243(Mesh *me) +{ + CustomDataLayer *layer; + int a; + + for (a=0; a < me->fdata.totlayer; a++) { + layer= &me->fdata.layers[a]; + layer->active_rnd = layer->active; + } +} + +/* struct NodeImageAnim moved to ImageUser, and we make it default available */ +static void do_version_ntree_242_2(bNodeTree *ntree) +{ + bNode *node; + + if(ntree->type==NTREE_COMPOSIT) { + for(node= ntree->nodes.first; node; node= node->next) { + if(ELEM3(node->type, CMP_NODE_IMAGE, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { + /* only image had storage */ + if(node->storage) { + NodeImageAnim *nia= node->storage; + ImageUser *iuser= MEM_callocN(sizeof(ImageUser), "ima user node"); + + iuser->frames= nia->frames; + iuser->sfra= nia->sfra; + iuser->offset= nia->nr-1; + iuser->cycl= nia->cyclic; + iuser->fie_ima= 2; + iuser->ok= 1; + + node->storage= iuser; + MEM_freeN(nia); + } + else { + ImageUser *iuser= node->storage= MEM_callocN(sizeof(ImageUser), "node image user"); + iuser->sfra= 1; + iuser->fie_ima= 2; + iuser->ok= 1; + } + } + } + } +} + +static void do_versions(FileData *fd, Library *lib, Main *main) +{ + /* WATCH IT!!!: pointers from libdata have not been converted */ + + if(G.f & G_DEBUG) + printf("read file %s\n Version %d sub %d\n", fd->filename, main->versionfile, main->subversionfile); + + if(main->versionfile == 100) { + /* tex->extend and tex->imageflag have changed: */ + Tex *tex = main->tex.first; + while(tex) { + if(tex->id.flag & LIB_NEEDLINK) { + + if(tex->extend==0) { + if(tex->xrepeat || tex->yrepeat) tex->extend= TEX_REPEAT; + else { + tex->extend= TEX_EXTEND; + tex->xrepeat= tex->yrepeat= 1; + } + } + + } + tex= tex->id.next; + } + } + if(main->versionfile <= 101) { + /* frame mapping */ + Scene *sce = main->scene.first; + while(sce) { + sce->r.framapto= 100; + sce->r.images= 100; + sce->r.framelen= 1.0; + sce= sce->id.next; + } + } + if(main->versionfile <= 102) { + /* init halo's at 1.0 */ + Material *ma = main->mat.first; + while(ma) { + ma->add= 1.0; + ma= ma->id.next; + } + } + if(main->versionfile <= 103) { + /* new variable in object: colbits */ + Object *ob = main->object.first; + int a; + while(ob) { + ob->colbits= 0; + if(ob->totcol) { + for(a=0; atotcol; a++) { + if(ob->mat[a]) ob->colbits |= (1<id.next; + } + } + if(main->versionfile <= 104) { + /* timeoffs moved */ + Object *ob = main->object.first; + while(ob) { + if(ob->transflag & 1) { + ob->transflag -= 1; + ob->ipoflag |= OB_OFFS_OB; + } + ob= ob->id.next; + } + } + if(main->versionfile <= 105) { + Object *ob = main->object.first; + while(ob) { + ob->dupon= 1; ob->dupoff= 0; + ob->dupsta= 1; ob->dupend= 100; + ob= ob->id.next; + } + } + if(main->versionfile <= 106) { + /* mcol changed */ + Mesh *me = main->mesh.first; + while(me) { + if(me->mcol) vcol_to_fcol(me); + me= me->id.next; + } + + } + if(main->versionfile <= 107) { + Object *ob; + Scene *sce = main->scene.first; + while(sce) { + sce->r.mode |= R_GAMMA; + sce= sce->id.next; + } + ob= main->object.first; + while(ob) { + ob->ipoflag |= OB_OFFS_PARENT; + if(ob->dt==0) ob->dt= OB_SOLID; + ob= ob->id.next; + } + + } + if(main->versionfile <= 109) { + /* new variable: gridlines */ + bScreen *sc = main->screen.first; + while(sc) { + ScrArea *sa= sc->areabase.first; + while(sa) { + SpaceLink *sl= sa->spacedata.first; + while (sl) { + if (sl->spacetype==SPACE_VIEW3D) { + View3D *v3d= (View3D*) sl; + + if (v3d->gridlines==0) v3d->gridlines= 20; + } + sl= sl->next; + } + sa= sa->next; + } + sc= sc->id.next; + } + } + if(main->versionfile <= 112) { + Mesh *me = main->mesh.first; + while(me) { + me->cubemapsize= 1.0; + me= me->id.next; + } + } + if(main->versionfile <= 113) { + Material *ma = main->mat.first; + while(ma) { + if(ma->flaresize==0.0) ma->flaresize= 1.0; + ma->subsize= 1.0; + ma->flareboost= 1.0; + ma= ma->id.next; + } + } + + if(main->versionfile <= 134) { + Tex *tex = main->tex.first; + while (tex) { + if ((tex->rfac == 0.0) && + (tex->gfac == 0.0) && + (tex->bfac == 0.0)) { + tex->rfac = 1.0; + tex->gfac = 1.0; + tex->bfac = 1.0; + tex->filtersize = 1.0; + } + tex = tex->id.next; + } + } + if(main->versionfile <= 140) { + /* r-g-b-fac in texure */ + Tex *tex = main->tex.first; + while (tex) { + if ((tex->rfac == 0.0) && + (tex->gfac == 0.0) && + (tex->bfac == 0.0)) { + tex->rfac = 1.0; + tex->gfac = 1.0; + tex->bfac = 1.0; + tex->filtersize = 1.0; + } + tex = tex->id.next; + } + } + if(main->versionfile <= 153) { + Scene *sce = main->scene.first; + while(sce) { + if(sce->r.blurfac==0.0) sce->r.blurfac= 1.0; + sce= sce->id.next; + } + } + if(main->versionfile <= 163) { + Scene *sce = main->scene.first; + while(sce) { + if(sce->r.frs_sec==0) sce->r.frs_sec= 25; + sce= sce->id.next; + } + } + if(main->versionfile <= 164) { + Mesh *me= main->mesh.first; + while(me) { + me->smoothresh= 30; + me= me->id.next; + } + } + if(main->versionfile <= 165) { + Mesh *me= main->mesh.first; + TFace *tface; + int nr; + char *cp; + + while(me) { + if(me->tface) { + nr= me->totface; + tface= me->tface; + while(nr--) { + cp= (char *)&tface->col[0]; + if(cp[1]>126) cp[1]= 255; else cp[1]*=2; + if(cp[2]>126) cp[2]= 255; else cp[2]*=2; + if(cp[3]>126) cp[3]= 255; else cp[3]*=2; + cp= (char *)&tface->col[1]; + if(cp[1]>126) cp[1]= 255; else cp[1]*=2; + if(cp[2]>126) cp[2]= 255; else cp[2]*=2; + if(cp[3]>126) cp[3]= 255; else cp[3]*=2; + cp= (char *)&tface->col[2]; + if(cp[1]>126) cp[1]= 255; else cp[1]*=2; + if(cp[2]>126) cp[2]= 255; else cp[2]*=2; + if(cp[3]>126) cp[3]= 255; else cp[3]*=2; + cp= (char *)&tface->col[3]; + if(cp[1]>126) cp[1]= 255; else cp[1]*=2; + if(cp[2]>126) cp[2]= 255; else cp[2]*=2; + if(cp[3]>126) cp[3]= 255; else cp[3]*=2; + + tface++; + } + } + me= me->id.next; + } + } + + if(main->versionfile <= 169) { + Mesh *me= main->mesh.first; + while(me) { + if(me->subdiv==0) me->subdiv= 1; + me= me->id.next; + } + } + + if(main->versionfile <= 169) { + bScreen *sc= main->screen.first; + while(sc) { + ScrArea *sa= sc->areabase.first; + while(sa) { + SpaceLink *sl= sa->spacedata.first; + while(sl) { + if(sl->spacetype==SPACE_IPO) { + SpaceIpo *sipo= (SpaceIpo*) sl; + sipo->v2d.max[0]= 15000.0; + } + sl= sl->next; + } + sa= sa->next; + } + sc= sc->id.next; + } + } + + if(main->versionfile <= 170) { + Object *ob = main->object.first; + PartEff *paf; + while (ob) { + paf = give_parteff(ob); + if (paf) { + if (paf->staticstep == 0) { + paf->staticstep= 5; + } + } + ob = ob->id.next; + } + } + + if(main->versionfile <= 171) { + bScreen *sc= main->screen.first; + while(sc) { + ScrArea *sa= sc->areabase.first; + while(sa) { + SpaceLink *sl= sa->spacedata.first; + while(sl) { + if(sl->spacetype==SPACE_TEXT) { + SpaceText *st= (SpaceText*) sl; + if(st->font_id>1) { + st->font_id= 0; + st->lheight= 13; + } + } + sl= sl->next; + } + sa= sa->next; + } + sc= sc->id.next; + } + } + + if(main->versionfile <= 173) { + int a, b; + Mesh *me= main->mesh.first; + while(me) { + if(me->tface) { + TFace *tface= me->tface; + for(a=0; atotface; a++, tface++) { + for(b=0; b<4; b++) { + tface->uv[b][0]/= 32767.0; + tface->uv[b][1]/= 32767.0; + } + } + } + me= me->id.next; + } + } + + if(main->versionfile <= 191) { + bScreen *sc= main->screen.first; + Object *ob= main->object.first; + Material *ma = main->mat.first; + + /* let faces have default add factor of 0.0 */ + while(ma) { + if (!(ma->mode & MA_HALO)) ma->add = 0.0; + ma = ma->id.next; + } + + while(ob) { + ob->mass= 1.0f; + ob->damping= 0.1f; + ob->quat[1]= 1.0f; + ob= ob->id.next; + } + + while(sc) { + ScrArea *sa= sc->areabase.first; + while(sa) { + SpaceLink *sl= sa->spacedata.first; + while(sl) { + if(sl->spacetype==SPACE_BUTS) { + SpaceButs *sbuts= (SpaceButs*) sl; + sbuts->scaflag= BUTS_SENS_LINK|BUTS_SENS_ACT|BUTS_CONT_ACT|BUTS_ACT_ACT|BUTS_ACT_LINK; + } + sl= sl->next; + } + sa= sa->next; + } + sc= sc->id.next; + } + } + + if(main->versionfile <= 193) { + Object *ob= main->object.first; + while(ob) { + ob->inertia= 1.0f; + ob->rdamping= 0.1f; + ob= ob->id.next; + } + } + + if(main->versionfile <= 196) { + Mesh *me= main->mesh.first; + int a, b; + while(me) { + if(me->tface) { + TFace *tface= me->tface; + for(a=0; atotface; a++, tface++) { + for(b=0; b<4; b++) { + tface->mode |= TF_DYNAMIC; + tface->mode &= ~TF_INVISIBLE; + } + } + } + me= me->id.next; + } + } + + if(main->versionfile <= 200) { + Object *ob= main->object.first; + while(ob) { + ob->scaflag = ob->gameflag & (64+128+256+512+1024+2048); + /* 64 is do_fh */ + ob->gameflag &= ~(128+256+512+1024+2048); + ob = ob->id.next; + } + } + + if(main->versionfile <= 201) { + /* add-object + end-object are joined to edit-object actuator */ + Object *ob = main->object.first; + bProperty *prop; + bActuator *act; + bIpoActuator *ia; + bEditObjectActuator *eoa; + bAddObjectActuator *aoa; + while (ob) { + act = ob->actuators.first; + while (act) { + if(act->type==ACT_IPO) { + ia= act->data; + prop= get_property(ob, ia->name); + if(prop) { + ia->type= ACT_IPO_FROM_PROP; + } + } + else if(act->type==ACT_ADD_OBJECT) { + aoa= act->data; + eoa= MEM_callocN(sizeof(bEditObjectActuator), "edit ob act"); + eoa->type= ACT_EDOB_ADD_OBJECT; + eoa->ob= aoa->ob; + eoa->time= aoa->time; + MEM_freeN(aoa); + act->data= eoa; + act->type= act->otype= ACT_EDIT_OBJECT; + } + else if(act->type==ACT_END_OBJECT) { + eoa= MEM_callocN(sizeof(bEditObjectActuator), "edit ob act"); + eoa->type= ACT_EDOB_END_OBJECT; + act->data= eoa; + act->type= act->otype= ACT_EDIT_OBJECT; + } + act= act->next; + } + ob = ob->id.next; + } + } + + if(main->versionfile <= 202) { + /* add-object and end-object are joined to edit-object + * actuator */ + Object *ob= main->object.first; + bActuator *act; + bObjectActuator *oa; + while(ob) { + act= ob->actuators.first; + while(act) { + if(act->type==ACT_OBJECT) { + oa= act->data; + oa->flag &= ~(ACT_TORQUE_LOCAL|ACT_DROT_LOCAL); /* this actuator didn't do local/glob rot before */ + } + act= act->next; + } + ob= ob->id.next; + } + } + + if(main->versionfile <= 204) { + /* patches for new physics */ + Object *ob= main->object.first; + bActuator *act; + bObjectActuator *oa; + bSound *sound; + while(ob) { + + /* please check this for demo20 files like + * original Egypt levels etc. converted + * rotation factor of 50 is not workable */ + act= ob->actuators.first; + while(act) { + if(act->type==ACT_OBJECT) { + oa= act->data; + + oa->forceloc[0]*= 25.0; + oa->forceloc[1]*= 25.0; + oa->forceloc[2]*= 25.0; + + oa->forcerot[0]*= 10.0; + oa->forcerot[1]*= 10.0; + oa->forcerot[2]*= 10.0; + } + act= act->next; + } + ob= ob->id.next; + } + + sound = main->sound.first; + while (sound) { + if (sound->volume < 0.01) { + sound->volume = 1.0; + } + sound = sound->id.next; + } + } + + if(main->versionfile <= 205) { + /* patches for new physics */ + Object *ob= main->object.first; + bActuator *act; + bSensor *sens; + bEditObjectActuator *oa; + bRaySensor *rs; + bCollisionSensor *cs; + while(ob) { + /* Set anisotropic friction off for old objects, + * values to 1.0. */ + ob->gameflag &= ~OB_ANISOTROPIC_FRICTION; + ob->anisotropicFriction[0] = 1.0; + ob->anisotropicFriction[1] = 1.0; + ob->anisotropicFriction[2] = 1.0; + + act= ob->actuators.first; + while(act) { + if(act->type==ACT_EDIT_OBJECT) { + /* Zero initial velocity for newly + * added objects */ + oa= act->data; + oa->linVelocity[0] = 0.0; + oa->linVelocity[1] = 0.0; + oa->linVelocity[2] = 0.0; + oa->localflag = 0; + } + act= act->next; + } + + sens= ob->sensors.first; + while (sens) { + /* Extra fields for radar sensors. */ + if(sens->type == SENS_RADAR) { + bRadarSensor *s = sens->data; + s->range = 10000.0; + } + + /* Pulsing: defaults for new sensors. */ + if(sens->type != SENS_ALWAYS) { + sens->pulse = 0; + sens->freq = 0; + } else { + sens->pulse = 1; + } + + /* Invert: off. */ + sens->invert = 0; + + /* Collision and ray: default = trigger + * on property. The material field can + * remain empty. */ + if(sens->type == SENS_COLLISION) { + cs = (bCollisionSensor*) sens->data; + cs->mode = 0; + } + if(sens->type == SENS_RAY) { + rs = (bRaySensor*) sens->data; + rs->mode = 0; + } + sens = sens->next; + } + ob= ob->id.next; + } + /* have to check the exact multiplier */ + } + + if(main->versionfile <= 211) { + /* Render setting: per scene, the applicable gamma value + * can be set. Default is 1.0, which means no + * correction. */ + bActuator *act; + bObjectActuator *oa; + Object *ob; + + /* added alpha in obcolor */ + ob= main->object.first; + while(ob) { + ob->col[3]= 1.0; + ob= ob->id.next; + } + + /* added alpha in obcolor */ + ob= main->object.first; + while(ob) { + act= ob->actuators.first; + while(act) { + if (act->type==ACT_OBJECT) { + /* multiply velocity with 50 in old files */ + oa= act->data; + if (fabs(oa->linearvelocity[0]) >= 0.01f) + oa->linearvelocity[0] *= 50.0; + if (fabs(oa->linearvelocity[1]) >= 0.01f) + oa->linearvelocity[1] *= 50.0; + if (fabs(oa->linearvelocity[2]) >= 0.01f) + oa->linearvelocity[2] *= 50.0; + if (fabs(oa->angularvelocity[0])>=0.01f) + oa->angularvelocity[0] *= 50.0; + if (fabs(oa->angularvelocity[1])>=0.01f) + oa->angularvelocity[1] *= 50.0; + if (fabs(oa->angularvelocity[2])>=0.01f) + oa->angularvelocity[2] *= 50.0; + } + act= act->next; + } + ob= ob->id.next; + } + } + + if(main->versionfile <= 212) { + + bSound* sound; + bProperty *prop; + Object *ob; + Mesh *me; + + sound = main->sound.first; + while (sound) + { + sound->max_gain = 1.0; + sound->min_gain = 0.0; + sound->distance = 1.0; + + if (sound->attenuation > 0.0) + sound->flags |= SOUND_FLAGS_3D; + else + sound->flags &= ~SOUND_FLAGS_3D; + + sound = sound->id.next; + } + + ob = main->object.first; + + while (ob) { + prop= ob->prop.first; + while(prop) { + if (prop->type == PROP_TIME) { + // convert old PROP_TIME values from int to float + *((float *)&prop->data) = (float) prop->data; + } + + prop= prop->next; + } + ob = ob->id.next; + } + + /* me->subdiv changed to reflect the actual reparametization + * better, and smeshes were removed - if it was a smesh make + * it a subsurf, and reset the subdiv level because subsurf + * takes a lot more work to calculate. + */ + for (me= main->mesh.first; me; me= me->id.next) { + if (me->flag&ME_SMESH) { + me->flag&= ~ME_SMESH; + me->flag|= ME_SUBSURF; + + me->subdiv= 1; + } else { + if (me->subdiv<2) + me->subdiv= 1; + else + me->subdiv--; + } + } + } + + if(main->versionfile <= 220) { + Object *ob; + Mesh *me; + + ob = main->object.first; + + /* adapt form factor in order to get the 'old' physics + * behaviour back...*/ + + while (ob) { + /* in future, distinguish between different + * object bounding shapes */ + ob->formfactor = 0.4f; + /* patch form factor , note that inertia equiv radius + * of a rotation symmetrical obj */ + if (ob->inertia != 1.0) { + ob->formfactor /= ob->inertia * ob->inertia; + } + ob = ob->id.next; + } + + /* Began using alpha component of vertex colors, but + * old file vertex colors are undefined, reset them + * to be fully opaque. -zr + */ + for (me= main->mesh.first; me; me= me->id.next) { + if (me->mcol) { + int i; + + for (i=0; itotface*4; i++) { + MCol *mcol= &me->mcol[i]; + mcol->a= 255; + } + } + if (me->tface) { + int i, j; + + for (i=0; itotface; i++) { + TFace *tf= &((TFace*) me->tface)[i]; + + for (j=0; j<4; j++) { + char *col= (char*) &tf->col[j]; + + col[0]= 255; + } + } + } + } + } + if(main->versionfile <= 221) { + Scene *sce= main->scene.first; + + // new variables for std-alone player and runtime + while(sce) { + + sce->r.xplay= 640; + sce->r.yplay= 480; + sce->r.freqplay= 60; + + sce= sce->id.next; + } + + } + if(main->versionfile <= 222) { + Scene *sce= main->scene.first; + + // new variables for std-alone player and runtime + while(sce) { + + sce->r.depth= 32; + + sce= sce->id.next; + } + } + + + if(main->versionfile <= 223) { + VFont *vf; + Image *ima; + Object *ob; + + for (vf= main->vfont.first; vf; vf= vf->id.next) { + if (BLI_streq(vf->name+strlen(vf->name)-6, ".Bfont")) { + strcpy(vf->name, ""); + } + } + + /* Old textures animate at 25 FPS */ + for (ima = main->image.first; ima; ima=ima->id.next){ + ima->animspeed = 25; + } + + /* Zr remapped some keyboard codes to be linear (stupid zr) */ + for (ob= main->object.first; ob; ob= ob->id.next) { + bSensor *sens; + + for (sens= ob->sensors.first; sens; sens= sens->next) { + if (sens->type==SENS_KEYBOARD) { + bKeyboardSensor *ks= sens->data; + + ks->key= map_223_keybd_code_to_224_keybd_code(ks->key); + ks->qual= map_223_keybd_code_to_224_keybd_code(ks->qual); + ks->qual2= map_223_keybd_code_to_224_keybd_code(ks->qual2); + } + } + } + } + if(main->versionfile <= 224) { + bSound* sound; + Scene *sce; + Mesh *me; + bScreen *sc; + + for (sound=main->sound.first; sound; sound=sound->id.next) { + if (sound->packedfile) { + if (sound->newpackedfile == NULL) { + sound->newpackedfile = sound->packedfile; + } + sound->packedfile = NULL; + } + } + /* Make sure that old subsurf meshes don't have zero subdivision level for rendering */ + for (me=main->mesh.first; me; me=me->id.next){ + if ((me->flag & ME_SUBSURF) && (me->subdivr==0)) + me->subdivr=me->subdiv; + } + + for (sce= main->scene.first; sce; sce= sce->id.next) { + sce->r.stereomode = 1; // no stereo + } + + /* some oldfile patch, moved from set_func_space */ + for (sc= main->screen.first; sc; sc= sc->id.next) { + ScrArea *sa; + + for (sa= sc->areabase.first; sa; sa= sa->next) { + SpaceLink *sl; + + for (sl= sa->spacedata.first; sl; sl= sl->next) { + if (sl->spacetype==SPACE_IPO) { + SpaceSeq *sseq= (SpaceSeq*) sl; + sseq->v2d.keeptot= 0; + } + } + } + } + + } + + + if(main->versionfile <= 225) { + World *wo; + /* Use Sumo for old games */ + for (wo = main->world.first; wo; wo= wo->id.next) { + wo->physicsEngine = 2; + } + } + + if(main->versionfile <= 227) { + Scene *sce; + Material *ma; + bScreen *sc; + Object *ob; + + /* As of now, this insures that the transition from the old Track system + to the new full constraint Track is painless for everyone. - theeth + */ + ob = main->object.first; + + while (ob) { + ListBase *list; + list = &ob->constraints; + + /* check for already existing TrackTo constraint + set their track and up flag correctly */ + + if (list){ + bConstraint *curcon; + for (curcon = list->first; curcon; curcon=curcon->next){ + if (curcon->type == CONSTRAINT_TYPE_TRACKTO){ + bTrackToConstraint *data = curcon->data; + data->reserved1 = ob->trackflag; + data->reserved2 = ob->upflag; + } + } + } + + if (ob->type == OB_ARMATURE) { + if (ob->pose){ + bConstraint *curcon; + bPoseChannel *pchan; + for (pchan = ob->pose->chanbase.first; + pchan; pchan=pchan->next){ + for (curcon = pchan->constraints.first; + curcon; curcon=curcon->next){ + if (curcon->type == CONSTRAINT_TYPE_TRACKTO){ + bTrackToConstraint *data = curcon->data; + data->reserved1 = ob->trackflag; + data->reserved2 = ob->upflag; + } + } + } + } + } + + /* Change Ob->Track in real TrackTo constraint */ + + if (ob->track){ + bConstraint *con; + bConstraintTypeInfo *cti; + bTrackToConstraint *data; + void *cdata; + + list = &ob->constraints; + if (list) + { + con = MEM_callocN(sizeof(bConstraint), "constraint"); + strcpy (con->name, "AutoTrack"); + unique_constraint_name(con, list); + con->flag |= CONSTRAINT_EXPAND; + con->enforce=1.0F; + con->type = CONSTRAINT_TYPE_TRACKTO; + + cti= get_constraint_typeinfo(CONSTRAINT_TYPE_TRACKTO); + cdata= MEM_callocN(cti->size, cti->structName); + cti->new_data(cdata); + data = (bTrackToConstraint *)cdata; + + data->tar = ob->track; + data->reserved1 = ob->trackflag; + data->reserved2 = ob->upflag; + con->data= (void*) data; + BLI_addtail(list, con); + } + ob->track = 0; + } + + ob = ob->id.next; + } + + + for (sce= main->scene.first; sce; sce= sce->id.next) { + sce->audio.mixrate = 44100; + sce->audio.flag |= AUDIO_SCRUB; + sce->r.mode |= R_ENVMAP; + } + // init new shader vars + for (ma= main->mat.first; ma; ma= ma->id.next) { + ma->refrac= 4.0f; + ma->roughness= 0.5f; + ma->param[0]= 0.5f; + ma->param[1]= 0.1f; + ma->param[2]= 0.1f; + ma->param[3]= 0.05f; + } + // patch for old wrong max view2d settings, allows zooming out more + for (sc= main->screen.first; sc; sc= sc->id.next) { + ScrArea *sa; + + for (sa= sc->areabase.first; sa; sa= sa->next) { + SpaceLink *sl; + + for (sl= sa->spacedata.first; sl; sl= sl->next) { + if (sl->spacetype==SPACE_ACTION) { + SpaceAction *sac= (SpaceAction *) sl; + sac->v2d.max[0]= 32000; + } + else if (sl->spacetype==SPACE_NLA) { + SpaceNla *sla= (SpaceNla *) sl; + sla->v2d.max[0]= 32000; + } + } + } + } + } + if(main->versionfile <= 228) { + Scene *sce; + bScreen *sc; + Object *ob; + + + /* As of now, this insures that the transition from the old Track system + to the new full constraint Track is painless for everyone.*/ + ob = main->object.first; + + while (ob) { + ListBase *list; + list = &ob->constraints; + + /* check for already existing TrackTo constraint + set their track and up flag correctly */ + + if (list){ + bConstraint *curcon; + for (curcon = list->first; curcon; curcon=curcon->next){ + if (curcon->type == CONSTRAINT_TYPE_TRACKTO){ + bTrackToConstraint *data = curcon->data; + data->reserved1 = ob->trackflag; + data->reserved2 = ob->upflag; + } + } + } + + if (ob->type == OB_ARMATURE) { + if (ob->pose){ + bConstraint *curcon; + bPoseChannel *pchan; + for (pchan = ob->pose->chanbase.first; + pchan; pchan=pchan->next){ + for (curcon = pchan->constraints.first; + curcon; curcon=curcon->next){ + if (curcon->type == CONSTRAINT_TYPE_TRACKTO){ + bTrackToConstraint *data = curcon->data; + data->reserved1 = ob->trackflag; + data->reserved2 = ob->upflag; + } + } + } + } + } + + ob = ob->id.next; + } + + for (sce= main->scene.first; sce; sce= sce->id.next) { + sce->r.mode |= R_ENVMAP; + } + + // convert old mainb values for new button panels + for (sc= main->screen.first; sc; sc= sc->id.next) { + ScrArea *sa; + + for (sa= sc->areabase.first; sa; sa= sa->next) { + SpaceLink *sl; + + for (sl= sa->spacedata.first; sl; sl= sl->next) { + if (sl->spacetype==SPACE_BUTS) { + SpaceButs *sbuts= (SpaceButs *) sl; + + sbuts->v2d.maxzoom= 1.2f; + sbuts->align= 1; /* horizontal default */ + + if(sbuts->mainb==BUTS_LAMP) { + sbuts->mainb= CONTEXT_SHADING; + sbuts->tab[CONTEXT_SHADING]= TAB_SHADING_LAMP; + } + else if(sbuts->mainb==BUTS_MAT) { + sbuts->mainb= CONTEXT_SHADING; + sbuts->tab[CONTEXT_SHADING]= TAB_SHADING_MAT; + } + else if(sbuts->mainb==BUTS_TEX) { + sbuts->mainb= CONTEXT_SHADING; + sbuts->tab[CONTEXT_SHADING]= TAB_SHADING_TEX; + } + else if(sbuts->mainb==BUTS_ANIM) { + sbuts->mainb= CONTEXT_OBJECT; + } + else if(sbuts->mainb==BUTS_WORLD) { + sbuts->mainb= CONTEXT_SCENE; + sbuts->tab[CONTEXT_SCENE]= TAB_SCENE_WORLD; + } + else if(sbuts->mainb==BUTS_RENDER) { + sbuts->mainb= CONTEXT_SCENE; + sbuts->tab[CONTEXT_SCENE]= TAB_SCENE_RENDER; + } + else if(sbuts->mainb==BUTS_GAME) { + sbuts->mainb= CONTEXT_LOGIC; + } + else if(sbuts->mainb==BUTS_FPAINT) { + sbuts->mainb= CONTEXT_EDITING; + } + else if(sbuts->mainb==BUTS_RADIO) { + sbuts->mainb= CONTEXT_SHADING; + sbuts->tab[CONTEXT_SHADING]= TAB_SHADING_RAD; + } + else if(sbuts->mainb==BUTS_CONSTRAINT) { + sbuts->mainb= CONTEXT_OBJECT; + } + else if(sbuts->mainb==BUTS_SCRIPT) { + sbuts->mainb= CONTEXT_OBJECT; + } + else if(sbuts->mainb==BUTS_EDIT) { + sbuts->mainb= CONTEXT_EDITING; + } + else sbuts->mainb= CONTEXT_SCENE; + } + } + } + } + } + /* ton: made this 230 instead of 229, + to be sure (tuho files) and this is a reliable check anyway + nevertheless, we might need to think over a fitness (initialize) + check apart from the do_versions() */ + + if(main->versionfile <= 230) { + bScreen *sc; + + // new variable blockscale, for panels in any area + for (sc= main->screen.first; sc; sc= sc->id.next) { + ScrArea *sa; + + for (sa= sc->areabase.first; sa; sa= sa->next) { + SpaceLink *sl; + + for (sl= sa->spacedata.first; sl; sl= sl->next) { + if(sl->blockscale==0.0) sl->blockscale= 0.7f; + /* added: 5x better zoom in for action */ + if(sl->spacetype==SPACE_ACTION) { + SpaceAction *sac= (SpaceAction *)sl; + sac->v2d.maxzoom= 50; + } + } + } + } + } + if(main->versionfile <= 231) { + /* new bit flags for showing/hiding grid floor and axes */ + bScreen *sc = main->screen.first; + while(sc) { + ScrArea *sa= sc->areabase.first; + while(sa) { + SpaceLink *sl= sa->spacedata.first; + while (sl) { + if (sl->spacetype==SPACE_VIEW3D) { + View3D *v3d= (View3D*) sl; + + if (v3d->gridflag==0) { + v3d->gridflag |= V3D_SHOW_X; + v3d->gridflag |= V3D_SHOW_Y; + v3d->gridflag |= V3D_SHOW_FLOOR; + v3d->gridflag &= ~V3D_SHOW_Z; + } + } + sl= sl->next; + } + sa= sa->next; + } + sc= sc->id.next; + } + } + if(main->versionfile <= 231) { + Material *ma= main->mat.first; + bScreen *sc = main->screen.first; + Scene *sce; + Lamp *la; + World *wrld; + + /* introduction of raytrace */ + while(ma) { + if(ma->fresnel_tra_i==0.0) ma->fresnel_tra_i= 1.25; + if(ma->fresnel_mir_i==0.0) ma->fresnel_mir_i= 1.25; + + ma->ang= 1.0; + ma->ray_depth= 2; + ma->ray_depth_tra= 2; + ma->fresnel_tra= 0.0; + ma->fresnel_mir= 0.0; + + ma= ma->id.next; + } + sce= main->scene.first; + while(sce) { + if(sce->r.gauss==0.0) sce->r.gauss= 1.0; + sce= sce->id.next; + } + la= main->lamp.first; + while(la) { + if(la->k==0.0) la->k= 1.0; + if(la->ray_samp==0) la->ray_samp= 1; + if(la->ray_sampy==0) la->ray_sampy= 1; + if(la->ray_sampz==0) la->ray_sampz= 1; + if(la->area_size==0.0) la->area_size= 1.0; + if(la->area_sizey==0.0) la->area_sizey= 1.0; + if(la->area_sizez==0.0) la->area_sizez= 1.0; + la= la->id.next; + } + wrld= main->world.first; + while(wrld) { + if(wrld->range==0.0) { + wrld->range= 1.0f/wrld->exposure; + } + wrld= wrld->id.next; + } + + /* new bit flags for showing/hiding grid floor and axes */ + + while(sc) { + ScrArea *sa= sc->areabase.first; + while(sa) { + SpaceLink *sl= sa->spacedata.first; + while (sl) { + if (sl->spacetype==SPACE_VIEW3D) { + View3D *v3d= (View3D*) sl; + + if (v3d->gridflag==0) { + v3d->gridflag |= V3D_SHOW_X; + v3d->gridflag |= V3D_SHOW_Y; + v3d->gridflag |= V3D_SHOW_FLOOR; + v3d->gridflag &= ~V3D_SHOW_Z; + } + } + sl= sl->next; + } + sa= sa->next; + } + sc= sc->id.next; + } + } + if(main->versionfile <= 232) { + Tex *tex= main->tex.first; + World *wrld= main->world.first; + bScreen *sc; + Scene *sce; + + while(tex) { + if((tex->flag & (TEX_CHECKER_ODD+TEX_CHECKER_EVEN))==0) { + tex->flag |= TEX_CHECKER_ODD; + } + /* copied from kernel texture.c */ + if(tex->ns_outscale==0.0) { + /* musgrave */ + tex->mg_H = 1.0f; + tex->mg_lacunarity = 2.0f; + tex->mg_octaves = 2.0f; + tex->mg_offset = 1.0f; + tex->mg_gain = 1.0f; + tex->ns_outscale = 1.0f; + /* distnoise */ + tex->dist_amount = 1.0f; + /* voronoi */ + tex->vn_w1 = 1.0f; + tex->vn_mexp = 2.5f; + } + tex= tex->id.next; + } + + while(wrld) { + if(wrld->aodist==0.0) { + wrld->aodist= 10.0f; + wrld->aobias= 0.05f; + } + if(wrld->aosamp==0.0) wrld->aosamp= 5; + if(wrld->aoenergy==0.0) wrld->aoenergy= 1.0; + wrld= wrld->id.next; + } + + + // new variable blockscale, for panels in any area, do again because new + // areas didnt initialize it to 0.7 yet + for (sc= main->screen.first; sc; sc= sc->id.next) { + ScrArea *sa; + for (sa= sc->areabase.first; sa; sa= sa->next) { + SpaceLink *sl; + for (sl= sa->spacedata.first; sl; sl= sl->next) { + if(sl->blockscale==0.0) sl->blockscale= 0.7f; + + /* added: 5x better zoom in for nla */ + if(sl->spacetype==SPACE_NLA) { + SpaceNla *snla= (SpaceNla *)sl; + snla->v2d.maxzoom= 50; + } + } + } + } + sce= main->scene.first; + while(sce) { + if(sce->r.ocres==0) sce->r.ocres= 64; + sce= sce->id.next; + } + + } + if(main->versionfile <= 233) { + bScreen *sc; + Material *ma= main->mat.first; + Object *ob= main->object.first; + + while(ma) { + if(ma->rampfac_col==0.0) ma->rampfac_col= 1.0; + if(ma->rampfac_spec==0.0) ma->rampfac_spec= 1.0; + if(ma->pr_lamp==0) ma->pr_lamp= 3; + ma= ma->id.next; + } + + /* this should have been done loooong before! */ + while(ob) { + if(ob->ipowin==0) ob->ipowin= ID_OB; + ob= ob->id.next; + } + + for (sc= main->screen.first; sc; sc= sc->id.next) { + ScrArea *sa; + for (sa= sc->areabase.first; sa; sa= sa->next) { + SpaceLink *sl; + for (sl= sa->spacedata.first; sl; sl= sl->next) { + if(sl->spacetype==SPACE_VIEW3D) { + View3D *v3d= (View3D *)sl; + v3d->flag |= V3D_SELECT_OUTLINE; + } + } + } + } + } + + + + + if(main->versionfile <= 234) { + Scene *sce; + World *wo; + bScreen *sc; + int set_zbuf_sel=0; + + // force sumo engine to be active + for (wo = main->world.first; wo; wo= wo->id.next) { + if(wo->physicsEngine==0) wo->physicsEngine = 2; + } + + for (sce= main->scene.first; sce; sce= sce->id.next) { + if(sce->selectmode==0) { + sce->selectmode= SCE_SELECT_VERTEX; + set_zbuf_sel= 1; + } + } + for (sc= main->screen.first; sc; sc= sc->id.next) { + ScrArea *sa; + for (sa= sc->areabase.first; sa; sa= sa->next) { + SpaceLink *sl; + for (sl= sa->spacedata.first; sl; sl= sl->next) { + if(sl->spacetype==SPACE_VIEW3D) { + View3D *v3d= (View3D *)sl; + if(set_zbuf_sel) v3d->flag |= V3D_ZBUF_SELECT; + } + else if(sl->spacetype==SPACE_TEXT) { + SpaceText *st= (SpaceText *)sl; + if(st->tabnumber==0) st->tabnumber= 2; + } + } + } + } + } + if(main->versionfile <= 235) { + Tex *tex= main->tex.first; + Scene *sce= main->scene.first; + Sequence *seq; + Editing *ed; + + while(tex) { + if(tex->nabla==0.0) tex->nabla= 0.025f; + tex= tex->id.next; + } + while(sce) { + ed= sce->ed; + if(ed) { + WHILE_SEQ(&ed->seqbase) { + if(seq->type==SEQ_IMAGE || seq->type==SEQ_MOVIE) seq->flag |= SEQ_MAKE_PREMUL; + } + END_SEQ + } + + sce= sce->id.next; + } + } + if(main->versionfile <= 236) { + Object *ob; + Scene *sce= main->scene.first; + Camera *cam= main->camera.first; + Material *ma; + bScreen *sc; + + while(sce) { + if(sce->editbutsize==0.0) sce->editbutsize= 0.1f; + + sce= sce->id.next; + } + while(cam) { + if(cam->ortho_scale==0.0) { + cam->ortho_scale= 256.0f/cam->lens; + if(cam->type==CAM_ORTHO) printf("NOTE: ortho render has changed, tweak new Camera 'scale' value.\n"); + } + cam= cam->id.next; + } + /* set manipulator type */ + /* force oops draw if depgraph was set*/ + /* set time line var */ + for (sc= main->screen.first; sc; sc= sc->id.next) { + ScrArea *sa; + for (sa= sc->areabase.first; sa; sa= sa->next) { + SpaceLink *sl; + for (sl= sa->spacedata.first; sl; sl= sl->next) { + if(sl->spacetype==SPACE_VIEW3D) { + View3D *v3d= (View3D *)sl; + if(v3d->twtype==0) v3d->twtype= V3D_MANIP_TRANSLATE; + } +#ifndef SHOWDEPGRAPH + else if(sl->spacetype==SPACE_OOPS) { + if ( ((SpaceOops *)sl)->type==SO_DEPSGRAPH) + ((SpaceOops *)sl)->type=SO_OOPS; + } +#endif + else if(sl->spacetype==SPACE_TIME) { + SpaceTime *stime= (SpaceTime *)sl; + if(stime->redraws==0) + stime->redraws= TIME_ALL_3D_WIN|TIME_ALL_ANIM_WIN; + } + } + } + } + // init new shader vars + for (ma= main->mat.first; ma; ma= ma->id.next) { + if(ma->darkness==0.0) { + ma->rms=0.1f; + ma->darkness=1.0f; + } + } + + /* softbody init new vars */ + for(ob= main->object.first; ob; ob= ob->id.next) { + if(ob->soft) { + if(ob->soft->defgoal==0.0) ob->soft->defgoal= 0.7f; + if(ob->soft->physics_speed==0.0) ob->soft->physics_speed= 1.0f; + + if(ob->soft->interval==0) { + ob->soft->interval= 2; + ob->soft->sfra= 1; + ob->soft->efra= 100; + } + } + if(ob->soft && ob->soft->vertgroup==0) { + bDeformGroup *locGroup = get_named_vertexgroup(ob, "SOFTGOAL"); + if(locGroup){ + /* retrieve index for that group */ + ob->soft->vertgroup = 1 + get_defgroup_num(ob, locGroup); + } + } + } + } + if(main->versionfile <= 237) { + bArmature *arm; + bConstraint *con; + Object *ob; + + // armature recode checks + for(arm= main->armature.first; arm; arm= arm->id.next) { + where_is_armature(arm); + } + for(ob= main->object.first; ob; ob= ob->id.next) { + if(ob->parent) { + Object *parent= newlibadr(fd, lib, ob->parent); + if (parent && parent->type==OB_LATTICE) + ob->partype = PARSKEL; + } + + // btw. armature_rebuild_pose is further only called on leave editmode + if(ob->type==OB_ARMATURE) { + if(ob->pose) + ob->pose->flag |= POSE_RECALC; + ob->recalc |= OB_RECALC; // cannot call stuff now (pointers!), done in setup_app_data + + /* new generic xray option */ + arm= newlibadr(fd, lib, ob->data); + if(arm->flag & ARM_DRAWXRAY) { + ob->dtx |= OB_DRAWXRAY; + } + } else if (ob->type==OB_MESH) { + Mesh *me = newlibadr(fd, lib, ob->data); + + if ((me->flag&ME_SUBSURF)) { + SubsurfModifierData *smd = (SubsurfModifierData*) modifier_new(eModifierType_Subsurf); + + smd->levels = MAX2(1, me->subdiv); + smd->renderLevels = MAX2(1, me->subdivr); + smd->subdivType = me->subsurftype; + + smd->modifier.mode = 0; + if (me->subdiv!=0) + smd->modifier.mode |= 1; + if (me->subdivr!=0) + smd->modifier.mode |= 2; + if (me->flag&ME_OPT_EDGES) + smd->flags |= eSubsurfModifierFlag_ControlEdges; + + BLI_addtail(&ob->modifiers, smd); + } + } + + // follow path constraint needs to set the 'path' option in curves... + for(con=ob->constraints.first; con; con= con->next) { + if(con->type==CONSTRAINT_TYPE_FOLLOWPATH) { + bFollowPathConstraint *data = con->data; + Object *obc= newlibadr(fd, lib, data->tar); + + if(obc && obc->type==OB_CURVE) { + Curve *cu= newlibadr(fd, lib, obc->data); + if(cu) cu->flag |= CU_PATH; + } + } + } + } + } + if(main->versionfile <= 238) { + Lattice *lt; + Object *ob; + bArmature *arm; + Mesh *me; + Key *key; + Scene *sce= main->scene.first; + + while(sce){ + if(sce->toolsettings == NULL){ + sce->toolsettings = MEM_callocN(sizeof(struct ToolSettings),"Tool Settings Struct"); + sce->toolsettings->cornertype=0; + sce->toolsettings->degr = 90; + sce->toolsettings->step = 9; + sce->toolsettings->turn = 1; + sce->toolsettings->extr_offs = 1; + sce->toolsettings->doublimit = 0.001f; + sce->toolsettings->segments = 32; + sce->toolsettings->rings = 32; + sce->toolsettings->vertices = 32; + sce->toolsettings->editbutflag =1; + } + sce= sce->id.next; + } + + for (lt=main->latt.first; lt; lt=lt->id.next) { + if (lt->fu==0.0 && lt->fv==0.0 && lt->fw==0.0) { + calc_lat_fudu(lt->flag, lt->pntsu, <->fu, <->du); + calc_lat_fudu(lt->flag, lt->pntsv, <->fv, <->dv); + calc_lat_fudu(lt->flag, lt->pntsw, <->fw, <->dw); + } + } + + for(ob=main->object.first; ob; ob= ob->id.next) { + ModifierData *md; + PartEff *paf; + + for (md=ob->modifiers.first; md; md=md->next) { + if (md->type==eModifierType_Subsurf) { + SubsurfModifierData *smd = (SubsurfModifierData*) md; + + smd->flags &= ~(eSubsurfModifierFlag_Incremental|eSubsurfModifierFlag_DebugIncr); + } + } + + if ((ob->softflag&OB_SB_ENABLE) && !modifiers_findByType(ob, eModifierType_Softbody)) { + if (ob->softflag&OB_SB_POSTDEF) { + md = ob->modifiers.first; + + while (md && modifierType_getInfo(md->type)->type==eModifierTypeType_OnlyDeform) { + md = md->next; + } + + BLI_insertlinkbefore(&ob->modifiers, md, modifier_new(eModifierType_Softbody)); + } else { + BLI_addhead(&ob->modifiers, modifier_new(eModifierType_Softbody)); + } + + ob->softflag &= ~OB_SB_ENABLE; + } + if(ob->pose) { + bPoseChannel *pchan; + bConstraint *con; + for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { + // note, pchan->bone is also lib-link stuff + if (pchan->limitmin[0] == 0.0f && pchan->limitmax[0] == 0.0f) { + pchan->limitmin[0]= pchan->limitmin[1]= pchan->limitmin[2]= -180.0f; + pchan->limitmax[0]= pchan->limitmax[1]= pchan->limitmax[2]= 180.0f; + + for(con= pchan->constraints.first; con; con= con->next) { + if(con->type == CONSTRAINT_TYPE_KINEMATIC) { + bKinematicConstraint *data = (bKinematicConstraint*)con->data; + data->weight = 1.0f; + data->orientweight = 1.0f; + data->flag &= ~CONSTRAINT_IK_ROT; + + /* enforce conversion from old IK_TOPARENT to rootbone index */ + data->rootbone= -1; + + /* update_pose_etc handles rootbone==-1 */ + ob->pose->flag |= POSE_RECALC; + } + } + } + } + } + + paf = give_parteff(ob); + if (paf) { + if(paf->disp == 0) + paf->disp = 100; + if(paf->speedtex == 0) + paf->speedtex = 8; + if(paf->omat == 0) + paf->omat = 1; + } + } + + for(arm=main->armature.first; arm; arm= arm->id.next) { + bone_version_238(&arm->bonebase); + arm->deformflag |= ARM_DEF_VGROUP; + } + + for(me=main->mesh.first; me; me= me->id.next) { + if (!me->medge) { + make_edges(me, 1); /* 1 = use mface->edcode */ + } else { + mesh_strip_loose_faces(me); + } + } + + for(key= main->key.first; key; key= key->id.next) { + KeyBlock *kb; + int index= 1; + + /* trick to find out if we already introduced adrcode */ + for(kb= key->block.first; kb; kb= kb->next) + if(kb->adrcode) break; + + if(kb==NULL) { + for(kb= key->block.first; kb; kb= kb->next) { + if(kb==key->refkey) { + if(kb->name[0]==0) + strcpy(kb->name, "Basis"); + } + else { + if(kb->name[0]==0) + sprintf(kb->name, "Key %d", index); + kb->adrcode= index++; + } + } + } + } + } + if(main->versionfile <= 239) { + bArmature *arm; + Object *ob; + Scene *sce= main->scene.first; + Camera *cam= main->camera.first; + Material *ma= main->mat.first; + int set_passepartout= 0; + + /* deformflag is local in modifier now */ + for(ob=main->object.first; ob; ob= ob->id.next) { + ModifierData *md; + + for (md=ob->modifiers.first; md; md=md->next) { + if (md->type==eModifierType_Armature) { + ArmatureModifierData *amd = (ArmatureModifierData*) md; + if(amd->object && amd->deformflag==0) { + Object *oba= newlibadr(fd, lib, amd->object); + bArmature *arm= newlibadr(fd, lib, oba->data); + amd->deformflag= arm->deformflag; + } + } + } + } + + /* updating stepsize for ghost drawing */ + for(arm= main->armature.first; arm; arm= arm->id.next) { + if (arm->ghostsize==0) arm->ghostsize=1; + bone_version_239(&arm->bonebase); + if(arm->layer==0) arm->layer= 1; + } + + for(;sce;sce= sce->id.next) { + /* make 'innervert' the default subdivide type, for backwards compat */ + sce->toolsettings->cornertype=1; + + if(sce->r.scemode & R_PASSEPARTOUT) { + set_passepartout= 1; + sce->r.scemode &= ~R_PASSEPARTOUT; + } + /* gauss is filter variable now */ + if(sce->r.mode & R_GAUSS) { + sce->r.filtertype= R_FILTER_GAUSS; + sce->r.mode &= ~R_GAUSS; + } + } + + for(;cam; cam= cam->id.next) { + if(set_passepartout) + cam->flag |= CAM_SHOWPASSEPARTOUT; + + /* make sure old cameras have title safe on */ + if (!(cam->flag & CAM_SHOWTITLESAFE)) + cam->flag |= CAM_SHOWTITLESAFE; + + /* set an appropriate camera passepartout alpha */ + if (!(cam->passepartalpha)) cam->passepartalpha = 0.2f; + } + + for(; ma; ma= ma->id.next) { + if(ma->strand_sta==0.0f) { + ma->strand_sta= ma->strand_end= 1.0f; + ma->mode |= MA_TANGENT_STR; + } + if(ma->mode & MA_TRACEBLE) ma->mode |= MA_SHADBUF; + } + } + + if(main->versionfile <= 241) { + Object *ob; + Tex *tex; + Scene *sce; + World *wo; + Lamp *la; + Material *ma; + bArmature *arm; + bNodeTree *ntree; + + for (wo = main->world.first; wo; wo= wo->id.next) { + /* Migrate to Bullet for games, except for the NaN versions */ + /* People can still explicitely choose for Sumo (after 2.42 is out) */ + if(main->versionfile > 225) + wo->physicsEngine = WOPHY_BULLET; + if(WO_AODIST == wo->aomode) + wo->aocolor= WO_AOPLAIN; + } + + /* updating layers still */ + for(arm= main->armature.first; arm; arm= arm->id.next) { + bone_version_239(&arm->bonebase); + if(arm->layer==0) arm->layer= 1; + } + for(sce= main->scene.first; sce; sce= sce->id.next) { + if(sce->jumpframe==0) sce->jumpframe= 10; + if(sce->audio.mixrate==0) sce->audio.mixrate= 44100; + + if(sce->r.xparts<2) sce->r.xparts= 4; + if(sce->r.yparts<2) sce->r.yparts= 4; + /* adds default layer */ + if(sce->r.layers.first==NULL) + scene_add_render_layer(sce); + else { + SceneRenderLayer *srl; + /* new layer flag for sky, was default for solid */ + for(srl= sce->r.layers.first; srl; srl= srl->next) { + if(srl->layflag & SCE_LAY_SOLID) + srl->layflag |= SCE_LAY_SKY; + srl->passflag &= (SCE_PASS_COMBINED|SCE_PASS_Z|SCE_PASS_NORMAL|SCE_PASS_VECTOR); + } + } + + /* node version changes */ + if(sce->nodetree) + ntree_version_241(sce->nodetree); + + /* uv calculation options moved to toolsettings */ + if (sce->toolsettings->uvcalc_radius == 0.0) { + sce->toolsettings->uvcalc_radius = 1.0f; + sce->toolsettings->uvcalc_cubesize = 1.0f; + sce->toolsettings->uvcalc_mapdir = 1; + sce->toolsettings->uvcalc_mapalign = 1; + sce->toolsettings->uvcalc_flag = 1; + sce->toolsettings->unwrapper = 1; + } + + if(sce->r.mode & R_PANORAMA) { + /* all these checks to ensure saved files with cvs version keep working... */ + if(sce->r.xsch < sce->r.ysch) { + Object *obc= newlibadr(fd, lib, sce->camera); + if(obc && obc->type==OB_CAMERA) { + Camera *cam= newlibadr(fd, lib, obc->data); + if(cam->lens>=10.0f) { + sce->r.xsch*= sce->r.xparts; + cam->lens*= (float)sce->r.ysch/(float)sce->r.xsch; + } + } + } + } + } + + for(ntree= main->nodetree.first; ntree; ntree= ntree->id.next) + ntree_version_241(ntree); + + for(la= main->lamp.first; la; la= la->id.next) + if(la->buffers==0) + la->buffers= 1; + + for(tex= main->tex.first; tex; tex= tex->id.next) { + if(tex->env && tex->env->viewscale==0.0f) + tex->env->viewscale= 1.0f; +// tex->imaflag |= TEX_GAUSS_MIP; + } + + /* for empty drawsize and drawtype */ + for(ob=main->object.first; ob; ob= ob->id.next) { + if(ob->empty_drawsize==0.0f) { + ob->empty_drawtype = OB_ARROWS; + ob->empty_drawsize = 1.0; + } + } + + for(ma= main->mat.first; ma; ma= ma->id.next) { + /* stucci returns intensity from now on */ + int a; + for(a=0; amtex[a] && ma->mtex[a]->tex) { + Tex *tex= newlibadr(fd, lib, ma->mtex[a]->tex); + if(tex && tex->type==TEX_STUCCI) + ma->mtex[a]->mapto &= ~(MAP_COL|MAP_SPEC|MAP_REF); + } + } + /* transmissivity defaults */ + if(ma->tx_falloff==0.0) ma->tx_falloff= 1.0; + } + + /* during 2.41 images with this name were used for viewer node output, lets fix that */ + if(main->versionfile == 241) { + Image *ima; + for(ima= main->image.first; ima; ima= ima->id.next) + if(strcmp(ima->name, "Compositor")==0) { + strcpy(ima->id.name+2, "Viewer Node"); + strcpy(ima->name, "Viewer Node"); + } + } + } + + if(main->versionfile <= 242) { + Scene *sce; + bScreen *sc; + Object *ob; + Curve *cu; + Material *ma; + Mesh *me; + Group *group; + Nurb *nu; + BezTriple *bezt; + BPoint *bp; + bNodeTree *ntree; + int a; + + for(sc= main->screen.first; sc; sc= sc->id.next) { + ScrArea *sa; + sa= sc->areabase.first; + while(sa) { + SpaceLink *sl; + + for (sl= sa->spacedata.first; sl; sl= sl->next) { + if(sl->spacetype==SPACE_VIEW3D) { + View3D *v3d= (View3D*) sl; + if (v3d->gridsubdiv == 0) + v3d->gridsubdiv = 10; + } + } + sa = sa->next; + } + } + + for(sce= main->scene.first; sce; sce= sce->id.next) { + if (sce->toolsettings->select_thresh == 0.0f) + sce->toolsettings->select_thresh= 0.01f; + if (sce->toolsettings->clean_thresh == 0.0f) + sce->toolsettings->clean_thresh = 0.1f; + + if (sce->r.threads==0) { + if (sce->r.mode & R_THREADS) + sce->r.threads= 2; + else + sce->r.threads= 1; + } + if(sce->nodetree) + ntree_version_242(sce->nodetree); + } + + for(ntree= main->nodetree.first; ntree; ntree= ntree->id.next) + ntree_version_242(ntree); + + /* add default radius values to old curve points */ + for(cu= main->curve.first; cu; cu= cu->id.next) { + for(nu= cu->nurb.first; nu; nu= nu->next) { + if (nu) { + if(nu->bezt) { + for(bezt=nu->bezt, a=0; apntsu; a++, bezt++) { + if (!bezt->radius) bezt->radius= 1.0; + } + } + else if(nu->bp) { + for(bp=nu->bp, a=0; apntsu*nu->pntsv; a++, bp++) { + if(!bp->radius) bp->radius= 1.0; + } + } + } + } + } + + for(ob = main->object.first; ob; ob= ob->id.next) { + ModifierData *md; + ListBase *list; + list = &ob->constraints; + + /* check for already existing MinMax (floor) constraint + and update the sticky flagging */ + + if (list){ + bConstraint *curcon; + for (curcon = list->first; curcon; curcon=curcon->next){ + switch (curcon->type) { + case CONSTRAINT_TYPE_MINMAX: + { + bMinMaxConstraint *data = curcon->data; + if (data->sticky==1) + data->flag |= MINMAX_STICKY; + else + data->flag &= ~MINMAX_STICKY; + } + break; + case CONSTRAINT_TYPE_ROTLIKE: + { + bRotateLikeConstraint *data = curcon->data; + + /* version patch from buttons_object.c */ + if(data->flag==0) + data->flag = ROTLIKE_X|ROTLIKE_Y|ROTLIKE_Z; + } + break; + } + } + } + + if (ob->type == OB_ARMATURE) { + if (ob->pose){ + bConstraint *curcon; + bPoseChannel *pchan; + for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next){ + for (curcon = pchan->constraints.first; curcon; curcon=curcon->next){ + switch (curcon->type) { + case CONSTRAINT_TYPE_MINMAX: + { + bMinMaxConstraint *data = curcon->data; + if (data->sticky==1) + data->flag |= MINMAX_STICKY; + else + data->flag &= ~MINMAX_STICKY; + } + break; + case CONSTRAINT_TYPE_KINEMATIC: + { + bKinematicConstraint *data = curcon->data; + if (!(data->flag & CONSTRAINT_IK_POS)) { + data->flag |= CONSTRAINT_IK_POS; + data->flag |= CONSTRAINT_IK_STRETCH; + } + } + break; + case CONSTRAINT_TYPE_ROTLIKE: + { + bRotateLikeConstraint *data = curcon->data; + + /* version patch from buttons_object.c */ + if(data->flag==0) + data->flag = ROTLIKE_X|ROTLIKE_Y|ROTLIKE_Z; + } + break; + } + } + } + } + } + + /* copy old object level track settings to curve modifers */ + for (md=ob->modifiers.first; md; md=md->next) { + if (md->type==eModifierType_Curve) { + CurveModifierData *cmd = (CurveModifierData*) md; + + if (cmd->defaxis == 0) cmd->defaxis = ob->trackflag+1; + } + } + + } + + for(ma = main->mat.first; ma; ma= ma->id.next) { + if(ma->shad_alpha==0.0f) + ma->shad_alpha= 1.0f; + if(ma->nodetree) + ntree_version_242(ma->nodetree); + } + + for(me=main->mesh.first; me; me=me->id.next) + customdata_version_242(me); + + for(group= main->group.first; group; group= group->id.next) + if(group->layer==0) + group->layer= (1<<20)-1; + + /* History fix (python?), shape key adrcode numbers have to be sorted */ + sort_shape_fix(main); + + /* now, subversion control! */ + if(main->subversionfile < 3) { + bScreen *sc; + Image *ima; + Tex *tex; + + /* Image refactor initialize */ + for(ima= main->image.first; ima; ima= ima->id.next) { + ima->source= IMA_SRC_FILE; + ima->type= IMA_TYPE_IMAGE; + + ima->gen_x= 256; ima->gen_y= 256; + ima->gen_type= 1; + + if(0==strncmp(ima->id.name+2, "Viewer Node", sizeof(ima->id.name+2))) { + ima->source= IMA_SRC_VIEWER; + ima->type= IMA_TYPE_COMPOSITE; + } + if(0==strncmp(ima->id.name+2, "Render Result", sizeof(ima->id.name+2))) { + ima->source= IMA_SRC_VIEWER; + ima->type= IMA_TYPE_R_RESULT; + } + + } + for(tex= main->tex.first; tex; tex= tex->id.next) { + if(tex->type==TEX_IMAGE && tex->ima) { + ima= newlibadr(fd, lib, tex->ima); + if(tex->imaflag & TEX_ANIM5_) + ima->source= IMA_SRC_MOVIE; + if(tex->imaflag & TEX_FIELDS_) + ima->flag |= IMA_FIELDS; + if(tex->imaflag & TEX_STD_FIELD_) + ima->flag |= IMA_STD_FIELD; + if(tex->imaflag & TEX_ANTIALI_) + ima->flag |= IMA_ANTIALI; + } + tex->iuser.frames= tex->frames; + tex->iuser.fie_ima= tex->fie_ima; + tex->iuser.offset= tex->offset; + tex->iuser.sfra= tex->sfra; + tex->iuser.cycl= (tex->imaflag & TEX_ANIMCYCLIC_)!=0; + } + for(sce= main->scene.first; sce; sce= sce->id.next) { + if(sce->nodetree) + do_version_ntree_242_2(sce->nodetree); + } + for(ntree= main->nodetree.first; ntree; ntree= ntree->id.next) + do_version_ntree_242_2(ntree); + for(ma = main->mat.first; ma; ma= ma->id.next) + if(ma->nodetree) + do_version_ntree_242_2(ma->nodetree); + + for(sc= main->screen.first; sc; sc= sc->id.next) { + ScrArea *sa; + for(sa= sc->areabase.first; sa; sa= sa->next) { + SpaceLink *sl; + for (sl= sa->spacedata.first; sl; sl= sl->next) { + if(sl->spacetype==SPACE_IMAGE) + ((SpaceImage *)sl)->iuser.fie_ima= 2; + else if(sl->spacetype==SPACE_VIEW3D) { + View3D *v3d= (View3D *)sl; + if(v3d->bgpic) + v3d->bgpic->iuser.fie_ima= 2; + } + } + } + } + } + + if(main->subversionfile < 4) { + for(sce= main->scene.first; sce; sce= sce->id.next) { + sce->r.bake_mode= 1; /* prevent to include render stuff here */ + sce->r.bake_filter= 2; + sce->r.bake_osa= 5; + sce->r.bake_flag= R_BAKE_CLEAR; + } + } + + if(main->subversionfile < 5) { + for(sce= main->scene.first; sce; sce= sce->id.next) { + /* improved triangle to quad conversion settings */ + if(sce->toolsettings->jointrilimit==0.0f) + sce->toolsettings->jointrilimit= 0.8f; + } + } + } + if(main->versionfile <= 243) { + Object *ob= main->object.first; + Camera *cam = main->camera.first; + Material *ma; + + for(; cam; cam= cam->id.next) { + cam->angle= 360.0f * atan(16.0f/cam->lens) / M_PI; + } + + for(ma=main->mat.first; ma; ma= ma->id.next) { + if(ma->sss_scale==0.0f) { + ma->sss_radius[0]= 1.0f; + ma->sss_radius[1]= 1.0f; + ma->sss_radius[2]= 1.0f; + ma->sss_col[0]= 0.8f; + ma->sss_col[1]= 0.8f; + ma->sss_col[2]= 0.8f; + ma->sss_error= 0.05f; + ma->sss_scale= 0.1f; + ma->sss_ior= 1.3f; + ma->sss_colfac= 1.0f; + ma->sss_texfac= 0.0f; + } + if(ma->sss_front==0 && ma->sss_back==0) { + ma->sss_front= 1.0f; + ma->sss_back= 1.0f; + } + if(ma->sss_col[0]==0 && ma->sss_col[1]==0 && ma->sss_col[2]==0) { + ma->sss_col[0]= ma->r; + ma->sss_col[1]= ma->g; + ma->sss_col[2]= ma->b; + } + } + + for(; ob; ob= ob->id.next) { + bDeformGroup *curdef; + + for(curdef= ob->defbase.first; curdef; curdef=curdef->next) { + /* replace an empty-string name with unique name */ + if (curdef->name[0] == '\0') { + unique_vertexgroup_name(curdef, ob); + } + } + + if(main->versionfile < 243 || main->subversionfile < 1) { + ModifierData *md; + + /* translate old mirror modifier axis values to new flags */ + for (md=ob->modifiers.first; md; md=md->next) { + if (md->type==eModifierType_Mirror) { + MirrorModifierData *mmd = (MirrorModifierData*) md; + + switch(mmd->axis) + { + case 0: + mmd->flag |= MOD_MIR_AXIS_X; + break; + case 1: + mmd->flag |= MOD_MIR_AXIS_Y; + break; + case 2: + mmd->flag |= MOD_MIR_AXIS_Z; + break; + } + + mmd->axis = 0; + } + } + } + } + + /* render layer added, this is not the active layer */ + if(main->versionfile <= 243 || main->subversionfile < 2) { + Mesh *me; + for(me=main->mesh.first; me; me=me->id.next) + customdata_version_243(me); + } + + } + + if(main->versionfile <= 244) { + Scene *sce; + bScreen *sc; + Lamp *la; + World *wrld; + + if(main->versionfile != 244 || main->subversionfile < 2) { + Mesh *me; + + for(sce= main->scene.first; sce; sce= sce->id.next) + sce->r.mode |= R_SSS; + + /* Copy over old per-level multires vertex data + into a single vertex array in struct Multires */ + + for(me = main->mesh.first; me; me=me->id.next) { + if(me->mr) { + MultiresLevel *lvl = me->mr->levels.last; + if(lvl) { + me->mr->verts = lvl->verts; + lvl->verts = NULL; + /* Don't need the other vert arrays */ + for(lvl = lvl->prev; lvl; lvl = lvl->prev) { + MEM_freeN(lvl->verts); + lvl->verts = NULL; + } + } + } + } + + /* correct older action editors - incorrect scrolling */ + for(sc= main->screen.first; sc; sc= sc->id.next) { + ScrArea *sa; + sa= sc->areabase.first; + while(sa) { + SpaceLink *sl; + + for (sl= sa->spacedata.first; sl; sl= sl->next) { + if(sl->spacetype==SPACE_ACTION) { + SpaceAction *saction= (SpaceAction*) sl; + + saction->v2d.tot.ymin= -1000.0; + saction->v2d.tot.ymax= 0.0; + + saction->v2d.cur.ymin= -75.0; + saction->v2d.cur.ymax= 5.0; + } + } + sa = sa->next; + } + } + } + if (main->versionfile != 244 || main->subversionfile < 3) { + /* constraints recode version patch used to be here. Moved to 245 now... */ + + + for(wrld=main->world.first; wrld; wrld= wrld->id.next) { + if (wrld->mode & WO_AMB_OCC) + wrld->ao_samp_method = WO_AOSAMP_CONSTANT; + else + wrld->ao_samp_method = WO_AOSAMP_HAMMERSLEY; + + wrld->ao_adapt_thresh = 0.005; + } + + for(la=main->lamp.first; la; la= la->id.next) { + if (la->type == LA_AREA) + la->ray_samp_method = LA_SAMP_CONSTANT; + else + la->ray_samp_method = LA_SAMP_HALTON; + + la->adapt_thresh = 0.001; + } + } + } + if(main->versionfile <= 245) { + bScreen *sc; + Object *ob; + Image *ima; + Lamp *la; + Material *ma; + + /* unless the file was created 2.44.3 but not 2.45, update the constraints */ + if ( !(main->versionfile==244 && main->subversionfile==3) && + ((main->versionfile<245) || (main->versionfile==245 && main->subversionfile==0)) ) + { + for (ob = main->object.first; ob; ob= ob->id.next) { + ListBase *list; + list = &ob->constraints; + + /* fix up constraints due to constraint recode changes (originally at 2.44.3) */ + if (list) { + bConstraint *curcon; + for (curcon = list->first; curcon; curcon=curcon->next) { + /* old CONSTRAINT_LOCAL check -> convert to CONSTRAINT_SPACE_LOCAL */ + if (curcon->flag & 0x20) { + curcon->ownspace = CONSTRAINT_SPACE_LOCAL; + curcon->tarspace = CONSTRAINT_SPACE_LOCAL; + } + + switch (curcon->type) { + case CONSTRAINT_TYPE_LOCLIMIT: + { + bLocLimitConstraint *data= (bLocLimitConstraint *)curcon->data; + + /* old limit without parent option for objects */ + if (data->flag2) + curcon->ownspace = CONSTRAINT_SPACE_LOCAL; + } + break; + case CONSTRAINT_TYPE_STRETCHTO: + { + bStretchToConstraint *data= (bStretchToConstraint *)curcon->data; + + /* force recalc of rest-length */ + data->orglength = 0; + } + break; + } + } + } + + /* correctly initialise constinv matrix */ + Mat4One(ob->constinv); + + if (ob->type == OB_ARMATURE) { + if (ob->pose) { + bConstraint *curcon; + bPoseChannel *pchan; + + for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) { + /* make sure constraints are all up to date */ + for (curcon = pchan->constraints.first; curcon; curcon=curcon->next) { + /* old CONSTRAINT_LOCAL check -> convert to CONSTRAINT_SPACE_LOCAL */ + if (curcon->flag & 0x20) { + curcon->ownspace = CONSTRAINT_SPACE_LOCAL; + curcon->tarspace = CONSTRAINT_SPACE_LOCAL; + } + + switch (curcon->type) { + case CONSTRAINT_TYPE_ACTION: + { + bActionConstraint *data= (bActionConstraint *)curcon->data; + + /* 'data->local' used to mean that target was in local-space */ + if (data->local) + curcon->tarspace = CONSTRAINT_SPACE_LOCAL; + } + break; + case CONSTRAINT_TYPE_STRETCHTO: + { + bStretchToConstraint *data= (bStretchToConstraint *)curcon->data; + + /* force recalc of rest-length */ + data->orglength = 0; + } + break; + } + } + + /* correctly initialise constinv matrix */ + Mat4One(pchan->constinv); + } + } + } + } + } + + /* fix all versions before 2.45 */ + if (main->versionfile != 245) { + + /* repair preview from 242 - 244*/ + for(ima= main->image.first; ima; ima= ima->id.next) { + ima->preview = NULL; + } + + /* repair imasel space - completely reworked */ + for(sc= main->screen.first; sc; sc= sc->id.next) { + ScrArea *sa; + sa= sc->areabase.first; + while(sa) { + SpaceLink *sl; + + for (sl= sa->spacedata.first; sl; sl= sl->next) { + if(sl->spacetype==SPACE_IMASEL) { + SpaceImaSel *simasel= (SpaceImaSel*) sl; + simasel->blockscale= 0.7; + /* view 2D */ + simasel->v2d.tot.xmin= -10.0; + simasel->v2d.tot.ymin= -10.0; + simasel->v2d.tot.xmax= (float)sa->winx + 10.0f; + simasel->v2d.tot.ymax= (float)sa->winy + 10.0f; + simasel->v2d.cur.xmin= 0.0; + simasel->v2d.cur.ymin= 0.0; + simasel->v2d.cur.xmax= (float)sa->winx; + simasel->v2d.cur.ymax= (float)sa->winy; + simasel->v2d.min[0]= 1.0; + simasel->v2d.min[1]= 1.0; + simasel->v2d.max[0]= 32000.0f; + simasel->v2d.max[1]= 32000.0f; + simasel->v2d.minzoom= 0.5f; + simasel->v2d.maxzoom= 1.21f; + simasel->v2d.scroll= 0; + simasel->v2d.keepaspect= 1; + simasel->v2d.keepzoom= 1; + simasel->v2d.keeptot= 0; + simasel->prv_h = 96; + simasel->prv_w = 96; + simasel->flag = 7; /* ??? elubie */ + strcpy (simasel->dir, U.textudir); /* TON */ + strcpy (simasel->file, ""); + + simasel->returnfunc = 0; + simasel->title[0] = 0; + } + } + sa = sa->next; + } + } + } + + if (main->versionfile != 245 || main->subversionfile < 1) { + for(la=main->lamp.first; la; la= la->id.next) { + if (la->mode & LA_QUAD) la->falloff_type = LA_FALLOFF_SLIDERS; + else la->falloff_type = LA_FALLOFF_INVLINEAR; + + if (la->curfalloff == NULL) { + la->curfalloff = curvemapping_add(1, 0.0f, 1.0f, 1.0f, 0.0f); + curvemapping_initialize(la->curfalloff); + } + } + } + + for(ma=main->mat.first; ma; ma= ma->id.next) { + if (ma->samp_gloss_mir == 0) { + ma->gloss_mir = ma->gloss_tra= 1.0; + ma->aniso_gloss_mir = 1.0; + ma->samp_gloss_mir = ma->samp_gloss_tra= 18; + ma->adapt_thresh_mir = ma->adapt_thresh_tra = 0.005; + ma->dist_mir = 0.0; + ma->fadeto_mir = MA_RAYMIR_FADETOSKY; + } + } + + } + + if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 2)) { + Image *ima; + + /* initialize 1:1 Aspect */ + for(ima= main->image.first; ima; ima= ima->id.next) { + ima->aspx = ima->aspy = 1.0f; + } + + } + + if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 4)) { + bArmature *arm; + ModifierData *md; + Object *ob; + + for(arm= main->armature.first; arm; arm= arm->id.next) + arm->deformflag |= ARM_DEF_B_BONE_REST; + + for(ob = main->object.first; ob; ob= ob->id.next) { + for(md=ob->modifiers.first; md; md=md->next) { + if(md->type==eModifierType_Armature) + ((ArmatureModifierData*)md)->deformflag |= ARM_DEF_B_BONE_REST; + } + } + } + + if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 5)) { + /* foreground color needs to be somthing other then black */ + Scene *sce; + for(sce= main->scene.first; sce; sce=sce->id.next) { + sce->r.fg_stamp[0] = sce->r.fg_stamp[1] = sce->r.fg_stamp[2] = 0.8; + sce->r.fg_stamp[3] = 1.0; /* dont use text alpha yet */ + sce->r.bg_stamp[3] = 0.25; /* make sure the background has full alpha */ + } + } + + + if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 6)) { + Scene *sce; + /* fix frs_sec_base */ + for(sce= main->scene.first; sce; sce= sce->id.next) { + if (sce->r.frs_sec_base == 0) { + sce->r.frs_sec_base = 1; + } + } + } + + if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 7)) { + Object *ob; + bPoseChannel *pchan; + bConstraint *con; + bConstraintTarget *ct; + + for(ob = main->object.first; ob; ob= ob->id.next) { + if(ob->pose) { + for(pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) { + for(con=pchan->constraints.first; con; con=con->next) { + if(con->type==CONSTRAINT_TYPE_PYTHON) { + bPythonConstraint *data= (bPythonConstraint *)con->data; + if (data->tar) { + /* version patching needs to be done */ + ct= MEM_callocN(sizeof(bConstraintTarget), "PyConTarget"); + + ct->tar = data->tar; + strcpy(ct->subtarget, data->subtarget); + ct->space = con->tarspace; + + BLI_addtail(&data->targets, ct); + data->tarnum++; + + /* clear old targets to avoid problems */ + data->tar = NULL; + strcpy(data->subtarget, ""); + } + } + } + } + } + + for(con=ob->constraints.first; con; con=con->next) { + if(con->type==CONSTRAINT_TYPE_PYTHON) { + bPythonConstraint *data= (bPythonConstraint *)con->data; + if (data->tar) { + /* version patching needs to be done */ + ct= MEM_callocN(sizeof(bConstraintTarget), "PyConTarget"); + + ct->tar = data->tar; + strcpy(ct->subtarget, data->subtarget); + ct->space = con->tarspace; + + BLI_addtail(&data->targets, ct); + data->tarnum++; + + /* clear old targets to avoid problems */ + data->tar = NULL; + strcpy(data->subtarget, ""); + } + } + } + } + } + + + /* WATCH IT!!!: pointers from libdata have not been converted yet here! */ + /* WATCH IT 2!: Userdef struct init has to be in src/usiblender.c! */ + + /* don't forget to set version number in blender.c! */ +} + +static void lib_link_all(FileData *fd, Main *main) +{ + oldnewmap_sort(fd); + + lib_link_screen(fd, main); + lib_link_scene(fd, main); + lib_link_object(fd, main); + lib_link_curve(fd, main); + lib_link_mball(fd, main); + lib_link_material(fd, main); + lib_link_texture(fd, main); + lib_link_image(fd, main); + lib_link_ipo(fd, main); + lib_link_key(fd, main); + lib_link_world(fd, main); + lib_link_lamp(fd, main); + lib_link_latt(fd, main); + lib_link_text(fd, main); + lib_link_camera(fd, main); + lib_link_sound(fd, main); + lib_link_group(fd, main); + lib_link_armature(fd, main); + lib_link_action(fd, main); + lib_link_vfont(fd, main); + lib_link_screen_sequence_ipos(main); + lib_link_nodetree(fd, main); /* has to be done after scene/materials, this will verify group nodes */ + lib_link_brush(fd, main); + + lib_link_mesh(fd, main); /* as last: tpage images with users at zero */ + + lib_link_library(fd, main); /* only init users */ +} + +static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead) +{ + Link *link; + + bfd->user= read_struct(fd, bhead, "user def"); + bfd->user->themes.first= bfd->user->themes.last= NULL; + + bhead = blo_nextbhead(fd, bhead); + + /* read all attached data */ + while(bhead && bhead->code==DATA) { + link= read_struct(fd, bhead, "user def data"); + BLI_addtail(&bfd->user->themes, link); + bhead = blo_nextbhead(fd, bhead); + } + + return bhead; +} + +BlendFileData *blo_read_file_internal(FileData *fd, BlendReadError *error_r) +{ + BHead *bhead= blo_firstbhead(fd); + BlendFileData *bfd; + FileGlobal *fg = (FileGlobal *)NULL; + + bfd= MEM_callocN(sizeof(BlendFileData), "blendfiledata"); + bfd->main= MEM_callocN(sizeof(Main), "main"); + BLI_addtail(&fd->mainlist, bfd->main); + + bfd->main->versionfile= fd->fileversion; + + while(bhead) { + switch(bhead->code) { + case GLOB: + case DATA: + case DNA1: + case TEST: + case REND: + if (bhead->code==GLOB) { + fg= read_struct(fd, bhead, "Global"); + /* set right away */ + bfd->main->subversionfile= fg->subversion; + bfd->main->minversionfile= fg->minversion; + bfd->main->minsubversionfile= fg->minsubversion; + } + bhead = blo_nextbhead(fd, bhead); + break; + case USER: + bhead= read_userdef(bfd, fd, bhead); + break; + case ENDB: + bhead = NULL; + break; + + case ID_LI: + bhead = read_libblock(fd, bfd->main, bhead, LIB_LOCAL, NULL); + break; + case ID_ID: + /* always adds to the most recently loaded + * ID_LI block, see direct_link_library. + * this is part of the file format definition. + */ + bhead = read_libblock(fd, fd->mainlist.last, bhead, LIB_READ+LIB_EXTERN, NULL); + break; + + default: + bhead = read_libblock(fd, bfd->main, bhead, LIB_LOCAL, NULL); + } + } + + /* do before read_libraries, but skip undo case */ +// if(fd->memfile==NULL) (the mesh shuffle hacks don't work yet? ton) + do_versions(fd, NULL, bfd->main); + + read_libraries(fd, &fd->mainlist); + + blo_join_main(&fd->mainlist); + + lib_link_all(fd, bfd->main); + lib_verify_nodetree(bfd->main); + + if(fg) + link_global(fd, bfd, fg); /* as last */ + + /* removed here: check for existance of curscreen/scene, moved to kernel setup_app */ + MEM_freeN(fg); + + return bfd; +} + +/* ************* APPEND LIBRARY ************** */ + +static BHead *find_previous_lib(FileData *fd, BHead *bhead) +{ + for (; bhead; bhead= blo_prevbhead(fd, bhead)) + if (bhead->code==ID_LI) + break; + + return bhead; +} + +static BHead *find_bhead(FileData *fd, void *old) +{ + BHead *bhead; + + if (!old) + return NULL; + + for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) + if (bhead->old==old) + return bhead; + + return NULL; +} + +char *bhead_id_name(FileData *fd, BHead *bhead) +{ + return ((char *)(bhead+1)) + fd->id_name_offs; +} + +static ID *is_yet_read(FileData *fd, Main *mainvar, BHead *bhead) +{ + ListBase *lb; + char *idname= bhead_id_name(fd, bhead); + + lb= wich_libbase(mainvar, GS(idname)); + + if(lb) { + ID *id= lb->first; + while(id) { + if( strcmp(id->name, idname)==0 ) + return id; + id= id->next; + } + } + return NULL; +} + +static void expand_doit(FileData *fd, Main *mainvar, void *old) +{ + BHead *bhead; + ID *id; + + bhead= find_bhead(fd, old); + if(bhead) { + /* from another library? */ + if(bhead->code==ID_ID) { + BHead *bheadlib= find_previous_lib(fd, bhead); + + if(bheadlib) { + Library *lib= read_struct(fd, bheadlib, "Library"); + Main *ptr= blo_find_main(&fd->mainlist, lib->name, fd->filename); + + id= is_yet_read(fd, ptr, bhead); + + if(id==NULL) { + read_libblock(fd, ptr, bhead, LIB_READ+LIB_INDIRECT, NULL); + if(G.f & G_DEBUG) printf("expand_doit: other lib %s\n", lib->name); + + /* for outliner dependency only */ + ptr->curlib->parent= mainvar->curlib; + } + else { + //oldnewmap_insert(fd->libmap, bhead->old, id, 1); + + change_idid_adr_fd(fd, bhead->old, id); + if(G.f & G_DEBUG) printf("expand_doit: already linked: %s lib: %s\n", id->name, lib->name); + } + + MEM_freeN(lib); + } + } + else { + id= is_yet_read(fd, mainvar, bhead); + if(id==NULL) { + read_libblock(fd, mainvar, bhead, LIB_TESTIND, NULL); + } + else { + /* this is actually only needed on UI call? when ID was already read before, and another append + happens which invokes same ID... in that case the lookup table needs this entry */ + oldnewmap_insert(fd->libmap, bhead->old, id, 1); + if(G.f & G_DEBUG) printf("expand: already read %s\n", id->name); + } + } + } +} + +static void expand_ipo(FileData *fd, Main *mainvar, Ipo *ipo) +{ + IpoCurve *icu; + for(icu= ipo->curve.first; icu; icu= icu->next) { + if(icu->driver) + expand_doit(fd, mainvar, icu->driver->ob); + } +} + +static void expand_group(FileData *fd, Main *mainvar, Group *group) +{ + GroupObject *go; + + for(go= group->gobject.first; go; go= go->next) { + expand_doit(fd, mainvar, go->ob); + } +} + +static void expand_key(FileData *fd, Main *mainvar, Key *key) +{ + expand_doit(fd, mainvar, key->ipo); +} + + +static void expand_texture(FileData *fd, Main *mainvar, Tex *tex) +{ + expand_doit(fd, mainvar, tex->ima); + expand_doit(fd, mainvar, tex->ipo); +} + +static void expand_brush(FileData *fd, Main *mainvar, Brush *brush) +{ + int a; + + for(a=0; amtex[a]) + expand_doit(fd, mainvar, brush->mtex[a]->tex); + expand_doit(fd, mainvar, brush->clone.image); +} + +static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree) +{ + bNode *node; + + for(node= ntree->nodes.first; node; node= node->next) + if(node->id && node->type!=CMP_NODE_R_LAYERS) + expand_doit(fd, mainvar, node->id); + +} + +static void expand_material(FileData *fd, Main *mainvar, Material *ma) +{ + int a; + + for(a=0; amtex[a]) { + expand_doit(fd, mainvar, ma->mtex[a]->tex); + expand_doit(fd, mainvar, ma->mtex[a]->object); + } + } + + expand_doit(fd, mainvar, ma->ipo); + + if(ma->nodetree) + expand_nodetree(fd, mainvar, ma->nodetree); +} + +static void expand_lamp(FileData *fd, Main *mainvar, Lamp *la) +{ + int a; + + for(a=0; amtex[a]) { + expand_doit(fd, mainvar, la->mtex[a]->tex); + expand_doit(fd, mainvar, la->mtex[a]->object); + } + } + expand_doit(fd, mainvar, la->ipo); +} + +static void expand_lattice(FileData *fd, Main *mainvar, Lattice *lt) +{ + expand_doit(fd, mainvar, lt->ipo); + expand_doit(fd, mainvar, lt->key); +} + + +static void expand_world(FileData *fd, Main *mainvar, World *wrld) +{ + int a; + + for(a=0; amtex[a]) { + expand_doit(fd, mainvar, wrld->mtex[a]->tex); + expand_doit(fd, mainvar, wrld->mtex[a]->object); + } + } + expand_doit(fd, mainvar, wrld->ipo); +} + + +static void expand_mball(FileData *fd, Main *mainvar, MetaBall *mb) +{ + int a; + + for(a=0; atotcol; a++) { + expand_doit(fd, mainvar, mb->mat[a]); + } +} + +static void expand_curve(FileData *fd, Main *mainvar, Curve *cu) +{ + int a; + + for(a=0; atotcol; a++) { + expand_doit(fd, mainvar, cu->mat[a]); + } + expand_doit(fd, mainvar, cu->vfont); + expand_doit(fd, mainvar, cu->vfontb); + expand_doit(fd, mainvar, cu->vfonti); + expand_doit(fd, mainvar, cu->vfontbi); + expand_doit(fd, mainvar, cu->key); + expand_doit(fd, mainvar, cu->ipo); + expand_doit(fd, mainvar, cu->bevobj); + expand_doit(fd, mainvar, cu->taperobj); + expand_doit(fd, mainvar, cu->textoncurve); +} + +static void expand_mesh(FileData *fd, Main *mainvar, Mesh *me) +{ + CustomDataLayer *layer; + MTFace *mtf; + TFace *tf; + int a, i; + + for(a=0; atotcol; a++) { + expand_doit(fd, mainvar, me->mat[a]); + } + + expand_doit(fd, mainvar, me->key); + expand_doit(fd, mainvar, me->texcomesh); + + if(me->tface) { + tf= me->tface; + for(i=0; itotface; i++, tf++) + if(tf->tpage) + expand_doit(fd, mainvar, tf->tpage); + } + + for(a=0; afdata.totlayer; a++) { + layer= &me->fdata.layers[a]; + + if(layer->type == CD_MTFACE) { + mtf= (MTFace*)layer->data; + for(i=0; itotface; i++, mtf++) + if(mtf->tpage) + expand_doit(fd, mainvar, mtf->tpage); + } + } +} + +static void expand_constraints(FileData *fd, Main *mainvar, ListBase *lb) +{ + bConstraint *curcon; + + for (curcon=lb->first; curcon; curcon=curcon->next) { + switch (curcon->type) { + case CONSTRAINT_TYPE_NULL: + break; + case CONSTRAINT_TYPE_PYTHON: + { + bPythonConstraint *data = (bPythonConstraint*)curcon->data; + bConstraintTarget *ct; + + for (ct= data->targets.first; ct; ct= ct->next) + expand_doit(fd, mainvar, ct->tar); + + expand_doit(fd, mainvar, data->text); + } + break; + case CONSTRAINT_TYPE_ACTION: + { + bActionConstraint *data = (bActionConstraint*)curcon->data; + expand_doit(fd, mainvar, data->tar); + expand_doit(fd, mainvar, data->act); + } + break; + case CONSTRAINT_TYPE_LOCLIKE: + { + bLocateLikeConstraint *data = (bLocateLikeConstraint*)curcon->data; + expand_doit(fd, mainvar, data->tar); + } + break; + case CONSTRAINT_TYPE_ROTLIKE: + { + bRotateLikeConstraint *data = (bRotateLikeConstraint*)curcon->data; + expand_doit(fd, mainvar, data->tar); + } + break; + case CONSTRAINT_TYPE_SIZELIKE: + { + bSizeLikeConstraint *data = (bSizeLikeConstraint*)curcon->data; + expand_doit(fd, mainvar, data->tar); + } + break; + case CONSTRAINT_TYPE_KINEMATIC: + { + bKinematicConstraint *data = (bKinematicConstraint*)curcon->data; + expand_doit(fd, mainvar, data->tar); + expand_doit(fd, mainvar, data->poletar); + } + break; + case CONSTRAINT_TYPE_TRACKTO: + { + bTrackToConstraint *data = (bTrackToConstraint*)curcon->data; + expand_doit(fd, mainvar, data->tar); + } + break; + case CONSTRAINT_TYPE_MINMAX: + { + bMinMaxConstraint *data = (bMinMaxConstraint*)curcon->data; + expand_doit(fd, mainvar, data->tar); + } + break; + case CONSTRAINT_TYPE_LOCKTRACK: + { + bLockTrackConstraint *data = (bLockTrackConstraint*)curcon->data; + expand_doit(fd, mainvar, data->tar); + } + break; + case CONSTRAINT_TYPE_FOLLOWPATH: + { + bFollowPathConstraint *data = (bFollowPathConstraint*)curcon->data; + expand_doit(fd, mainvar, data->tar); + } + break; + case CONSTRAINT_TYPE_STRETCHTO: + { + bStretchToConstraint *data = (bStretchToConstraint*)curcon->data; + expand_doit(fd, mainvar, data->tar); + } + break; + case CONSTRAINT_TYPE_RIGIDBODYJOINT: + { + bRigidBodyJointConstraint *data = (bRigidBodyJointConstraint*)curcon->data; + expand_doit(fd, mainvar, data->tar); + } + break; + case CONSTRAINT_TYPE_CLAMPTO: + { + bClampToConstraint *data = (bClampToConstraint*)curcon->data; + expand_doit(fd, mainvar, data->tar); + } + break; + case CONSTRAINT_TYPE_CHILDOF: + { + bChildOfConstraint *data = (bChildOfConstraint*)curcon->data; + expand_doit(fd, mainvar, data->tar); + } + break; + case CONSTRAINT_TYPE_TRANSFORM: + { + bTransformConstraint *data = (bTransformConstraint*)curcon->data; + expand_doit(fd, mainvar, data->tar); + } + break; + default: + break; + } + } +} + +static void expand_bones(FileData *fd, Main *mainvar, Bone *bone) +{ + Bone *curBone; + + for (curBone = bone->childbase.first; curBone; curBone=curBone->next) { + expand_bones(fd, mainvar, curBone); + } + +} + +static void expand_pose(FileData *fd, Main *mainvar, bPose *pose) +{ + bPoseChannel *chan; + + if (!pose) + return; + + for (chan = pose->chanbase.first; chan; chan=chan->next) { + expand_constraints(fd, mainvar, &chan->constraints); + expand_doit(fd, mainvar, chan->custom); + } +} + +static void expand_armature(FileData *fd, Main *mainvar, bArmature *arm) +{ + Bone *curBone; + + for (curBone = arm->bonebase.first; curBone; curBone=curBone->next) { + expand_bones(fd, mainvar, curBone); + } +} + +static void expand_constraint_channels(FileData *fd, Main *mainvar, ListBase *chanbase) +{ + bConstraintChannel *chan; + for (chan=chanbase->first; chan; chan=chan->next){ + expand_doit(fd, mainvar, chan->ipo); + } +} + +static void expand_action(FileData *fd, Main *mainvar, bAction *act) +{ + bActionChannel *chan; + for (chan=act->chanbase.first; chan; chan=chan->next) { + expand_doit(fd, mainvar, chan->ipo); + expand_constraint_channels(fd, mainvar, &chan->constraintChannels); + } +} + +static void expand_modifier(FileData *fd, Main *mainvar, ModifierData *md) +{ + if (md->type==eModifierType_Lattice) { + LatticeModifierData *lmd = (LatticeModifierData*) md; + + expand_doit(fd, mainvar, lmd->object); + } + else if (md->type==eModifierType_Curve) { + CurveModifierData *cmd = (CurveModifierData*) md; + + expand_doit(fd, mainvar, cmd->object); + } + else if (md->type==eModifierType_Array) { + ArrayModifierData *amd = (ArrayModifierData*) md; + + expand_doit(fd, mainvar, amd->curve_ob); + expand_doit(fd, mainvar, amd->offset_ob); + } +} + +static void expand_scriptlink(FileData *fd, Main *mainvar, ScriptLink *slink) +{ + int i; + + for(i=0; itotscript; i++) { + expand_doit(fd, mainvar, slink->scripts[i]); + } +} + +static void expand_object(FileData *fd, Main *mainvar, Object *ob) +{ + ModifierData *md; + bSensor *sens; + bController *cont; + bActuator *act; + bActionStrip *strip; + PartEff *paf; + int a; + + + expand_doit(fd, mainvar, ob->data); + expand_doit(fd, mainvar, ob->ipo); + expand_doit(fd, mainvar, ob->action); + + for (md=ob->modifiers.first; md; md=md->next) { + expand_modifier(fd, mainvar, md); + } + + expand_pose(fd, mainvar, ob->pose); + expand_constraints(fd, mainvar, &ob->constraints); + expand_constraint_channels(fd, mainvar, &ob->constraintChannels); + + for (strip=ob->nlastrips.first; strip; strip=strip->next){ + expand_doit(fd, mainvar, strip->object); + expand_doit(fd, mainvar, strip->act); + expand_doit(fd, mainvar, strip->ipo); + } + + for(a=0; atotcol; a++) { + expand_doit(fd, mainvar, ob->mat[a]); + } + + paf = give_parteff(ob); + if (paf && paf->group) + expand_doit(fd, mainvar, paf->group); + + if(ob->dup_group) + expand_doit(fd, mainvar, ob->dup_group); + + if(ob->proxy) + expand_doit(fd, mainvar, ob->proxy); + if(ob->proxy_group) + expand_doit(fd, mainvar, ob->proxy_group); + + sens= ob->sensors.first; + while(sens) { + for(a=0; atotlinks; a++) { + sens->links[a]= newglobadr(fd, sens->links[a]); + } + if(sens->type==SENS_TOUCH) { + bTouchSensor *ts= sens->data; + expand_doit(fd, mainvar, ts->ma); + } + else if(sens->type==SENS_MESSAGE) { + bMessageSensor *ms= sens->data; + expand_doit(fd, mainvar, ms->fromObject); + } + sens= sens->next; + } + + cont= ob->controllers.first; + while(cont) { + for(a=0; atotlinks; a++) { + cont->links[a]= newglobadr(fd, cont->links[a]); + } + if(cont->type==CONT_PYTHON) { + bPythonCont *pc= cont->data; + expand_doit(fd, mainvar, pc->text); + } + cont= cont->next; + } + + act= ob->actuators.first; + while(act) { + if(act->type==ACT_SOUND) { + bSoundActuator *sa= act->data; + expand_doit(fd, mainvar, sa->sound); + } + else if(act->type==ACT_CAMERA) { + bCameraActuator *ca= act->data; + expand_doit(fd, mainvar, ca->ob); + } + else if(act->type==ACT_EDIT_OBJECT) { + bEditObjectActuator *eoa= act->data; + if(eoa) { + expand_doit(fd, mainvar, eoa->ob); + expand_doit(fd, mainvar, eoa->me); + } + } + else if(act->type==ACT_SCENE) { + bSceneActuator *sa= act->data; + expand_doit(fd, mainvar, sa->camera); + expand_doit(fd, mainvar, sa->scene); + } + else if(act->type==ACT_ACTION) { + bActionActuator *aa= act->data; + expand_doit(fd, mainvar, aa->act); + } + else if(act->type==ACT_PROPERTY) { + bPropertyActuator *pa= act->data; + expand_doit(fd, mainvar, pa->ob); + } + else if(act->type==ACT_MESSAGE) { + bMessageActuator *ma= act->data; + expand_doit(fd, mainvar, ma->toObject); + } + act= act->next; + } + + expand_scriptlink(fd, mainvar, &ob->scriptlink); +} + +static void expand_scene(FileData *fd, Main *mainvar, Scene *sce) +{ + Base *base; + SceneRenderLayer *srl; + + for(base= sce->base.first; base; base= base->next) { + expand_doit(fd, mainvar, base->object); + } + expand_doit(fd, mainvar, sce->camera); + expand_doit(fd, mainvar, sce->world); + + if(sce->nodetree) + expand_nodetree(fd, mainvar, sce->nodetree); + + for(srl= sce->r.layers.first; srl; srl= srl->next) { + expand_doit(fd, mainvar, srl->mat_override); + expand_doit(fd, mainvar, srl->light_override); + } + +} + +static void expand_camera(FileData *fd, Main *mainvar, Camera *ca) +{ + expand_doit(fd, mainvar, ca->ipo); +} + +static void expand_sound(FileData *fd, Main *mainvar, bSound *snd) +{ + expand_doit(fd, mainvar, snd->ipo); +} + + +static void expand_main(FileData *fd, Main *mainvar) +{ + ListBase *lbarray[MAX_LIBARRAY]; + ID *id; + int a, doit= 1; + + if(fd==0) return; + + while(doit) { + doit= 0; + + a= set_listbasepointers(mainvar, lbarray); + while(a--) { + id= lbarray[a]->first; + + while(id) { + if(id->flag & LIB_TEST) { + + switch(GS(id->name)) { + + case ID_OB: + expand_object(fd, mainvar, (Object *)id); + break; + case ID_ME: + expand_mesh(fd, mainvar, (Mesh *)id); + break; + case ID_CU: + expand_curve(fd, mainvar, (Curve *)id); + break; + case ID_MB: + expand_mball(fd, mainvar, (MetaBall *)id); + break; + case ID_SCE: + expand_scene(fd, mainvar, (Scene *)id); + break; + case ID_MA: + expand_material(fd, mainvar, (Material *)id); + break; + case ID_TE: + expand_texture(fd, mainvar, (Tex *)id); + break; + case ID_WO: + expand_world(fd, mainvar, (World *)id); + break; + case ID_LT: + expand_lattice(fd, mainvar, (Lattice *)id); + break; + case ID_LA: + expand_lamp(fd, mainvar,(Lamp *)id); + break; + case ID_KE: + expand_key(fd, mainvar, (Key *)id); + break; + case ID_CA: + expand_camera(fd, mainvar, (Camera *)id); + break; + case ID_SO: + expand_sound(fd, mainvar, (bSound *)id); + break; + case ID_AR: + expand_armature(fd, mainvar, (bArmature *)id); + break; + case ID_AC: + expand_action(fd, mainvar, (bAction *)id); + break; + case ID_GR: + expand_group(fd, mainvar, (Group *)id); + break; + case ID_NT: + expand_nodetree(fd, mainvar, (bNodeTree *)id); + break; + case ID_BR: + expand_brush(fd, mainvar, (Brush *)id); + break; + case ID_IP: + expand_ipo(fd, mainvar, (Ipo *)id); + break; + } + + doit= 1; + id->flag -= LIB_TEST; + + } + id= id->next; + } + } + } +} + +static int object_in_any_scene(Object *ob) +{ + Scene *sce; + + for(sce= G.main->scene.first; sce; sce= sce->id.next) + if(object_in_scene(ob, sce)) + return 1; + return 0; +} + +/* when *lib set, it also does objects that were in the appended group */ +static void give_base_to_objects(Scene *sce, ListBase *lb, Library *lib) +{ + Object *ob; + Base *base; + + /* give all objects which are LIB_INDIRECT a base, or for a group when *lib has been set */ + for(ob= lb->first; ob; ob= ob->id.next) { + + if( ob->id.flag & LIB_INDIRECT ) { + int do_it= 0; + + if(ob->id.us==0) + do_it= 1; + else if(ob->id.us==1 && lib) + if(ob->id.lib==lib && (ob->flag & OB_FROMGROUP) && object_in_any_scene(ob)==0) + do_it= 1; + + if(do_it) { + base= MEM_callocN( sizeof(Base), "add_ext_base"); + BLI_addtail(&(sce->base), base); + base->lay= ob->lay; + base->object= ob; + base->flag= ob->flag; + ob->id.us= 1; + + ob->id.flag -= LIB_INDIRECT; + ob->id.flag |= LIB_EXTERN; + + } + } + } +} + + +static void append_named_part(FileData *fd, Main *mainvar, Scene *scene, char *name, int idcode, short flag) +{ + Object *ob; + Base *base; + BHead *bhead; + ID *id; + int endloop=0; + + bhead = blo_firstbhead(fd); + while(bhead && endloop==0) { + + if(bhead->code==ENDB) endloop= 1; + else if(bhead->code==idcode) { + char *idname= bhead_id_name(fd, bhead); + + if(strcmp(idname+2, name)==0) { + + id= is_yet_read(fd, mainvar, bhead); + if(id==NULL) { + read_libblock(fd, mainvar, bhead, LIB_TESTEXT, NULL); + } + else { + printf("append: already linked\n"); + oldnewmap_insert(fd->libmap, bhead->old, id, 1); + if(id->flag & LIB_INDIRECT) { + id->flag -= LIB_INDIRECT; + id->flag |= LIB_EXTERN; + } + } + + if(idcode==ID_OB) { /* loose object: give a base */ + base= MEM_callocN( sizeof(Base), "app_nam_part"); + BLI_addtail(&scene->base, base); + + if(id==NULL) ob= mainvar->object.last; + else ob= (Object *)id; + + /* this is bad code... G.vd nor G.scene should be used on this level... */ + if((flag & FILE_ACTIVELAY)) { + if(G.vd) ob->lay= G.vd->layact; + else ob->lay = G.scene->lay; + } + base->lay= ob->lay; + base->object= ob; + ob->id.us++; + + if(flag & FILE_AUTOSELECT) { + base->flag |= SELECT; + base->object->flag = base->flag; + /* do NOT make base active here! screws up GUI stuff, if you want it do it on src/ level */ + } + } + endloop= 1; + } + } + + bhead = blo_nextbhead(fd, bhead); + } +} + +static void append_id_part(FileData *fd, Main *mainvar, ID *id, ID **id_r) +{ + BHead *bhead; + + for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) { + if (bhead->code == GS(id->name)) { + + if (BLI_streq(id->name, bhead_id_name(fd, bhead))) { + id->flag &= ~LIB_READ; + id->flag |= LIB_TEST; +// printf("read lib block %s\n", id->name); + read_libblock(fd, mainvar, bhead, id->flag, id_r); + + break; + } + } else if (bhead->code==ENDB) + break; + } +} + +/* common routine to append/link something from a library */ + +static Library* library_append( Scene *scene, char* file, char *dir, int idcode, + int totsel, FileData *fd, struct direntry* filelist, int totfile, short flag) +{ + Main *mainl; + Library *curlib; + + /* make mains */ + blo_split_main(&fd->mainlist, G.main); + + /* which one do we need? */ + mainl = blo_find_main(&fd->mainlist, dir, G.sce); + + mainl->versionfile= fd->fileversion; /* needed for do_version */ + + curlib= mainl->curlib; + + if(totsel==0) { + append_named_part(fd, mainl, scene, file, idcode, flag); + } + else { + int a; + for(a=0; amainlist); + + if(flag & FILE_STRINGCODE) { + + /* use the full path, this could have been read by other library even */ + BLI_strncpy(mainl->curlib->name, mainl->curlib->filename, sizeof(mainl->curlib->name)); + + /* uses current .blend file as reference */ + BLI_makestringcode(G.sce, mainl->curlib->name); + } + + blo_join_main(&fd->mainlist); + G.main= fd->mainlist.first; + + lib_link_all(fd, G.main); + lib_verify_nodetree(G.main); + + /* give a base to loose objects. If group append, do it for objects too */ + if(idcode==ID_GR) + give_base_to_objects(scene, &(G.main->object), (flag & FILE_LINK)?NULL:curlib); + else + give_base_to_objects(scene, &(G.main->object), NULL); + + /* has been removed... erm, why? s..ton) */ + /* 20040907: looks like they are give base already in append_named_part(); -Nathan L */ + /* 20041208: put back. It only linked direct, not indirect objects (ton) */ + + /* patch to prevent switch_endian happens twice */ + if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) { + blo_freefiledata( fd ); + } + + return curlib; +} + +/* this is a version of BLO_library_append needed by the BPython API, so + * scripts can load data from .blend files -- see Blender.Library module.*/ +/* append to G.scene */ +/* this should probably be moved into the Python code anyway */ + +void BLO_script_library_append(BlendHandle *bh, char *dir, char *name, + int idcode, short flag, Scene *scene ) +{ + /* try to append the requested object */ + library_append( scene, name, dir, idcode, 0, (FileData *)bh, NULL, 0, flag ); + + /* do we need to do this? */ + DAG_scene_sort(G.scene); +} + +/* append to G.scene */ +/* dir is a full path */ +void BLO_library_append(SpaceFile *sfile, char *dir, int idcode) +{ + BLO_library_append_(&sfile->libfiledata, sfile->filelist, sfile->totfile, dir, sfile->file, sfile->flag, idcode); +} + +void BLO_library_append_(BlendHandle** libfiledata, struct direntry* filelist, int totfile, char *dir, char* file, short flag, int idcode) +{ + FileData *fd= (FileData*) (*libfiledata); + Library *curlib; + Base *centerbase; + Object *ob; + int a, totsel=0; + + /* are there files selected? */ + for(a=0; aflags & FD_FLAGS_SWITCH_ENDIAN) { + (*libfiledata)= 0; + } + + /* when not linking (appending)... */ + if((flag & FILE_LINK)==0) { + if(flag & FILE_ATCURSOR) { + float *curs, centerloc[3], vec[3], min[3], max[3]; + int count= 0; + + INIT_MINMAX(min, max); + + centerbase= (G.scene->base.first); + while(centerbase) { + if(centerbase->object->id.lib==curlib && centerbase->object->parent==NULL) { + VECCOPY(vec, centerbase->object->loc); + DO_MINMAX(vec, min, max); + count++; + } + centerbase= centerbase->next; + } + if(count) { + centerloc[0]= (min[0]+max[0])/2; + centerloc[1]= (min[1]+max[1])/2; + centerloc[2]= (min[2]+max[2])/2; + curs = G.scene->cursor; + VECSUB(centerloc,curs,centerloc); + + centerbase= (G.scene->base.first); + while(centerbase) { + if(centerbase->object->id.lib==curlib && centerbase->object->parent==NULL) { + ob= centerbase->object; + ob->loc[0] += centerloc[0]; + ob->loc[1] += centerloc[1]; + ob->loc[2] += centerloc[2]; + } + centerbase= centerbase->next; + } + } + } + } +} + +/* ************* READ LIBRARY ************** */ + +static int mainvar_count_libread_blocks(Main *mainvar) +{ + ListBase *lbarray[MAX_LIBARRAY]; + int a, tot= 0; + + a= set_listbasepointers(mainvar, lbarray); + while(a--) { + ID *id= lbarray[a]->first; + + for (id= lbarray[a]->first; id; id= id->next) + if (id->flag & LIB_READ) + tot++; + } + return tot; +} + +static void read_libraries(FileData *basefd, ListBase *mainlist) +{ + Main *mainl= mainlist->first; + Main *mainptr; + ListBase *lbarray[MAX_LIBARRAY]; + int a, doit= 1; + + while(doit) { + doit= 0; + + /* test 1: read libdata */ + mainptr= mainl->next; + while(mainptr) { + int tot= mainvar_count_libread_blocks(mainptr); + + // printf("found LIB_READ %s\n", mainptr->curlib->name); + if(tot) { + FileData *fd= mainptr->curlib->filedata; + + if(fd==NULL) { + BlendReadError err; + printf("read library: lib %s\n", mainptr->curlib->name); + fd= blo_openblenderfile(mainptr->curlib->filename, &err); + if (fd) { + if (fd->libmap) + oldnewmap_free(fd->libmap); + + fd->libmap = oldnewmap_new(); + + mainptr->curlib->filedata= fd; + mainptr->versionfile= fd->fileversion; + } + else mainptr->curlib->filedata= NULL; + + if (fd==NULL) + printf("ERROR: can't find lib %s \n", mainptr->curlib->filename); + } + if(fd) { + doit= 1; + a= set_listbasepointers(mainptr, lbarray); + while(a--) { + ID *id= lbarray[a]->first; + + while(id) { + ID *idn= id->next; + if(id->flag & LIB_READ) { + ID *realid= NULL; + BLI_remlink(lbarray[a], id); + + append_id_part(fd, mainptr, id, &realid); + if (!realid) + printf("LIB ERROR: can't find %s\n", id->name); + + change_idid_adr(mainlist, basefd, id, realid); + + MEM_freeN(id); + } + id= idn; + } + } + + expand_main(fd, mainptr); + + /* dang FileData... now new libraries need to be appended to original filedata, it is not a good replacement for the old global (ton) */ + while( fd->mainlist.first ) { + Main *mp= fd->mainlist.first; + BLI_remlink(&fd->mainlist, mp); + BLI_addtail(&basefd->mainlist, mp); + } + } + } + + mainptr= mainptr->next; + } + } + + /* test if there are unread libblocks */ + for(mainptr= mainl->next; mainptr; mainptr= mainptr->next) { + a= set_listbasepointers(mainptr, lbarray); + while(a--) { + ID *id= lbarray[a]->first; + while(id) { + ID *idn= id->next; + if(id->flag & LIB_READ) { + BLI_remlink(lbarray[a], id); + + printf("LIB ERROR: can't find %s\n", id->name); + change_idid_adr(mainlist, basefd, id, NULL); + + MEM_freeN(id); + } + id= idn; + } + } + } + + /* do versions, link, and free */ + for(mainptr= mainl->next; mainptr; mainptr= mainptr->next) { + /* some mains still have to be read, then + * versionfile is still zero! */ + if(mainptr->versionfile) { + if(mainptr->curlib->filedata) // can be zero... with shift+f1 append + do_versions(mainptr->curlib->filedata, mainptr->curlib, mainptr); + else + do_versions(basefd, NULL, mainptr); + } + + if(mainptr->curlib->filedata) + lib_link_all(mainptr->curlib->filedata, mainptr); + + if(mainptr->curlib->filedata) blo_freefiledata(mainptr->curlib->filedata); + mainptr->curlib->filedata= NULL; + + } +} + +/* reading runtime */ + +BlendFileData *blo_read_blendafterruntime(int file, int actualsize, BlendReadError *error_r) +{ + BlendFileData *bfd = NULL; + FileData *fd = filedata_new(); + fd->filedes = file; + fd->buffersize = actualsize; + fd->read = fd_read_from_file; + + fd = blo_decode_and_check(fd, error_r); + if (!fd) + return NULL; + + bfd= blo_read_file_internal(fd, error_r); + blo_freefiledata(fd); + + return bfd; +} diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h new file mode 100644 index 00000000000..79392023a56 --- /dev/null +++ b/source/blender/blenloader/intern/readfile.h @@ -0,0 +1,127 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * blenloader readfile private function prototypes + */ +#ifndef READFILE_H +#define READFILE_H + +#include "zlib.h" + +struct OldNewMap; +struct MemFile; + +typedef struct FileData { + // linked list of BHeadN's + ListBase listbase; + int flags; + int eof; + int buffersize; + int seek; + int (*read)(struct FileData *filedata, void *buffer, int size); + + // variables needed for reading from memory / stream + char *buffer; + // variables needed for reading from memfile (undo) + struct MemFile *memfile; + + // variables needed for reading from file + int filedes; + gzFile gzfiledes; + + // now only in use for library appending + char filename[FILE_MAXDIR+FILE_MAXFILE]; + + // variables needed for reading from stream + char headerdone; + int inbuffer; + + // general reading variables + struct SDNA *filesdna; + struct SDNA *memsdna; + char *compflags; + + int fileversion; + int id_name_offs; /* used to retrieve ID names from (bhead+1) */ + + struct OldNewMap *datamap; + struct OldNewMap *globmap; + struct OldNewMap *libmap; + struct OldNewMap *imamap; + + ListBase mainlist; + + /* ick ick, used to return + * data through streamglue. + */ + BlendFileData **bfd_r; + BlendReadError *error_r; +} FileData; + +typedef struct BHeadN { + struct BHeadN *next, *prev; + struct BHead bhead; +} BHeadN; + + +#define FD_FLAGS_SWITCH_ENDIAN (1<<0) +#define FD_FLAGS_FILE_POINTSIZE_IS_4 (1<<1) +#define FD_FLAGS_POINTSIZE_DIFFERS (1<<2) +#define FD_FLAGS_FILE_OK (1<<3) +#define FD_FLAGS_NOT_MY_BUFFER (1<<4) +#define FD_FLAGS_NOT_MY_LIBMAP (1<<5) + +#define SIZEOFBLENDERHEADER 12 + + /***/ +struct Main; +void blo_join_main(ListBase *mainlist); +void blo_split_main(ListBase *mainlist, struct Main *main); + +BlendFileData *blo_read_file_internal( FileData *fd, BlendReadError *error_r); + +FileData *blo_openblenderfile( char *name, BlendReadError *error_r); +FileData *blo_openblendermemory( void *buffer, int buffersize, BlendReadError *error_r); +FileData *blo_openblendermemfile(struct MemFile *memfile, BlendReadError *error_r); + +void blo_make_image_pointer_map(FileData *fd); +void blo_end_image_pointer_map(FileData *fd); +void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd); + +void blo_freefiledata( FileData *fd); + +BHead *blo_firstbhead(FileData *fd); +BHead *blo_nextbhead(FileData *fd, BHead *thisblock); +BHead *blo_prevbhead(FileData *fd, BHead *thisblock); + +char *bhead_id_name(FileData *fd, BHead *bhead); + +#endif + diff --git a/source/blender/blenloader/intern/undofile.c b/source/blender/blenloader/intern/undofile.c new file mode 100644 index 00000000000..c8c31f4f2ac --- /dev/null +++ b/source/blender/blenloader/intern/undofile.c @@ -0,0 +1,146 @@ +/** + * $Id: + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2004 Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * .blend file reading entry point + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" +#include "DNA_userdef_types.h" + +#include "BKE_utildefines.h" +#include "BKE_global.h" + +#include "BLO_undofile.h" + +#include "BLI_blenlib.h" +#include "BLI_linklist.h" + + + +/* **************** support for memory-write, for undo buffers *************** */ + +/* not memfile itself */ +void BLO_free_memfile(MemFile *memfile) +{ + MemFileChunk *chunk; + + while( (chunk = (memfile->chunks.first) ) ) { + if(chunk->ident==0) MEM_freeN(chunk->buf); + BLI_remlink(&memfile->chunks, chunk); + MEM_freeN(chunk); + } + memfile->size= 0; +} + +/* to keep list of memfiles consistant, 'first' is always first in list */ +/* result is that 'first' is being freed */ +void BLO_merge_memfile(MemFile *first, MemFile *second) +{ + MemFileChunk *fc, *sc; + + fc= first->chunks.first; + sc= second->chunks.first; + while (fc || sc) { + if(fc && sc) { + if(sc->ident) { + sc->ident= 0; + fc->ident= 1; + } + } + if(fc) fc= fc->next; + if(sc) sc= sc->next; + } + + BLO_free_memfile(first); +} + +static int my_memcmp(int *mem1, int *mem2, int len) +{ + register int a= len, *mema= mem1, *memb= mem2; + + while(a--) { + if( *mema != *memb) return 1; + mema++; + memb++; + } + return 0; +} + +void add_memfilechunk(MemFile *compare, MemFile *current, char *buf, unsigned int size) +{ + static MemFileChunk *compchunk=NULL; + MemFileChunk *curchunk; + + /* this function inits when compare != NULL or when current==NULL */ + if(compare) { + compchunk= compare->chunks.first; + return; + } + if(current==NULL) { + compchunk= NULL; + return; + } + + curchunk= MEM_mallocN(sizeof(MemFileChunk), "MemFileChunk"); + curchunk->size= size; + curchunk->buf= NULL; + curchunk->ident= 0; + BLI_addtail(¤t->chunks, curchunk); + + /* we compare compchunk with buf */ + if(compchunk) { + if(compchunk->size == curchunk->size) { + if( my_memcmp((int *)compchunk->buf, (int *)buf, size/4)==0) { + curchunk->buf= compchunk->buf; + curchunk->ident= 1; + } + } + compchunk= compchunk->next; + } + + /* not equal... */ + if(curchunk->buf==NULL) { + curchunk->buf= MEM_mallocN(size, "Chunk buffer"); + memcpy(curchunk->buf, buf, size); + current->size += size; + } +} + diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c new file mode 100644 index 00000000000..43907a30ac2 --- /dev/null +++ b/source/blender/blenloader/intern/writefile.c @@ -0,0 +1,2202 @@ +/* writefile.c + * + * .blend file writing + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* +FILEFORMAT: IFF-style structure (but not IFF compatible!) + +start file: + BLENDER_V100 12 bytes (versie 1.00) + V = big endian, v = little endian + _ = 4 byte pointer, - = 8 byte pointer + +datablocks: also see struct BHead + 4 chars + int, len data after BHead + void, old pointer + int + int, in case of array: amount of structs + data + ... + ... + +Almost all data in Blender are structures. Each struct saved +gets a BHead header. With BHead the struct can be linked again +and compared with StructDNA . + +WRITE + +Preferred writing order: (not really a must, but why would you do it random?) +Any case: direct data is ALWAYS after the lib block + +(Local file data) +- for each LibBlock + - write LibBlock + - write associated direct data +(External file data) +- per library + - write library block + - per LibBlock + - write the ID of LibBlock +- write FileGlobal (some global vars) +- write SDNA +- write USER if filename is ~/.B.blend +*/ + +/* for version 2.2+ +Important to know is that 'streaming' has been added to files, for Blender Publisher +*/ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "zlib.h" + +#ifndef WIN32 +#include +#else +#include "winsock2.h" +#include "BLI_winstuff.h" +#include +#include // for getpid +#endif + +#include +#include +#include +#include +#include + +#include "nla.h" // __NLA is defined + +#include "DNA_armature_types.h" +#include "DNA_action_types.h" +#include "DNA_actuator_types.h" +#include "DNA_brush_types.h" +#include "DNA_camera_types.h" +#include "DNA_color_types.h" +#include "DNA_constraint_types.h" +#include "DNA_controller_types.h" +#include "DNA_curve_types.h" +#include "DNA_customdata_types.h" +#include "DNA_effect_types.h" +#include "DNA_group_types.h" +#include "DNA_image_types.h" +#include "DNA_ipo_types.h" +#include "DNA_fileglobal_types.h" +#include "DNA_key_types.h" +#include "DNA_lattice_types.h" +#include "DNA_listBase.h" /* for Listbase, the type of samples, ...*/ +#include "DNA_lamp_types.h" +#include "DNA_meta_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_material_types.h" +#include "DNA_modifier_types.h" +#include "DNA_nla_types.h" +#include "DNA_node_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force.h" +#include "DNA_oops_types.h" +#include "DNA_packedFile_types.h" +#include "DNA_property_types.h" +#include "DNA_scene_types.h" +#include "DNA_sdna_types.h" +#include "DNA_sequence_types.h" +#include "DNA_sensor_types.h" +#include "DNA_space_types.h" +#include "DNA_screen_types.h" +#include "DNA_sound_types.h" +#include "DNA_texture_types.h" +#include "DNA_text_types.h" +#include "DNA_view3d_types.h" +#include "DNA_vfont_types.h" +#include "DNA_userdef_types.h" +#include "DNA_world_types.h" + +#include "MEM_guardedalloc.h" // MEM_freeN +#include "BLI_blenlib.h" +#include "BLI_linklist.h" + +#include "BKE_action.h" +#include "BKE_bad_level_calls.h" // build_seqar (from WHILE_SEQ) free_oops error +#include "BKE_blender.h" +#include "BKE_curve.h" +#include "BKE_customdata.h" +#include "BKE_constraint.h" +#include "BKE_global.h" // for G +#include "BKE_library.h" // for set_listbasepointers +#include "BKE_main.h" // G.main +#include "BKE_node.h" +#include "BKE_packedFile.h" // for packAll +#include "BKE_screen.h" // for waitcursor +#include "BKE_scene.h" // for do_seq +#include "BKE_sound.h" /* ... and for samples */ +#include "BKE_utildefines.h" // for defines +#include "BKE_modifier.h" +#include "BKE_idprop.h" +#ifdef WITH_VERSE +#include "BKE_verse.h" +#include "BIF_verse.h" +#endif + +#include "GEN_messaging.h" + +#include "BLO_writefile.h" +#include "BLO_readfile.h" +#include "BLO_undofile.h" + +#include "readfile.h" +#include "genfile.h" + +#include + +/* ********* my write, buffered writing with minimum 50k chunks ************ */ + +typedef struct { + struct SDNA *sdna; + + int file; + unsigned char *buf; + MemFile *compare, *current; + + int tot, count, error, memsize; +} WriteData; + +static WriteData *writedata_new(int file) +{ + extern unsigned char DNAstr[]; /* DNA.c */ + extern int DNAlen; + + WriteData *wd= MEM_callocN(sizeof(*wd), "writedata"); + + /* XXX, see note about this in readfile.c, remove + * once we have an xp lock - zr + */ + + if (wd == NULL) return NULL; + + wd->sdna= dna_sdna_from_data(DNAstr, DNAlen, 0); + + wd->file= file; + + wd->buf= MEM_mallocN(100000, "wd->buf"); + + return wd; +} + +static void writedata_do_write(WriteData *wd, void *mem, int memlen) +{ + if ((wd == NULL) || wd->error || (mem == NULL) || memlen < 1) return; + if (wd->error) return; + + /* memory based save */ + if(wd->current) { + add_memfilechunk(NULL, wd->current, mem, memlen); + } + else { + if (write(wd->file, mem, memlen) != memlen) + wd->error= 1; + + } +} + +static void writedata_free(WriteData *wd) +{ + dna_freestructDNA(wd->sdna); + + MEM_freeN(wd->buf); + MEM_freeN(wd); +} + +/***/ + +int mywfile; + +/** + * Low level WRITE(2) wrapper that buffers data + * @param adr Pointer to new chunk of data + * @param len Length of new chunk of data + * @warning Talks to other functions with global parameters + */ + +#define MYWRITE_FLUSH NULL + +static void mywrite( WriteData *wd, void *adr, int len) +{ + if (wd->error) return; + + if(adr==MYWRITE_FLUSH) { + if(wd->count) { + writedata_do_write(wd, wd->buf, wd->count); + wd->count= 0; + } + return; + } + + wd->tot+= len; + + if(len>50000) { + if(wd->count) { + writedata_do_write(wd, wd->buf, wd->count); + wd->count= 0; + } + writedata_do_write(wd, adr, len); + return; + } + if(len+wd->count>99999) { + writedata_do_write(wd, wd->buf, wd->count); + wd->count= 0; + } + memcpy(&wd->buf[wd->count], adr, len); + wd->count+= len; + +} + +/** + * BeGiN initializer for mywrite + * @param file File descriptor + * @param write_flags Write parameters + * @warning Talks to other functions with global parameters + */ +static WriteData *bgnwrite(int file, MemFile *compare, MemFile *current, int write_flags) +{ + WriteData *wd= writedata_new(file); + + if (wd == NULL) return NULL; + + wd->compare= compare; + wd->current= current; + /* this inits comparing */ + add_memfilechunk(compare, NULL, NULL, 0); + + return wd; +} + +/** + * END the mywrite wrapper + * @return 1 if write failed + * @return unknown global variable otherwise + * @warning Talks to other functions with global parameters + */ +static int endwrite(WriteData *wd) +{ + int err; + + if (wd->count) { + writedata_do_write(wd, wd->buf, wd->count); + wd->count= 0; + } + + err= wd->error; + writedata_free(wd); + + return err; +} + +/* ********** WRITE FILE ****************** */ + +static void writestruct(WriteData *wd, int filecode, char *structname, int nr, void *adr) +{ + BHead bh; + short *sp; + + if(adr==NULL || nr==0) return; + + /* init BHead */ + bh.code= filecode; + bh.old= adr; + bh.nr= nr; + + bh.SDNAnr= dna_findstruct_nr(wd->sdna, structname); + if(bh.SDNAnr== -1) { + printf("error: can't find SDNA code <%s>\n", structname); + return; + } + sp= wd->sdna->structs[bh.SDNAnr]; + + bh.len= nr*wd->sdna->typelens[sp[0]]; + + if(bh.len==0) return; + + mywrite(wd, &bh, sizeof(BHead)); + mywrite(wd, adr, bh.len); +} + +static void writedata(WriteData *wd, int filecode, int len, void *adr) /* do not use for structs */ +{ + BHead bh; + + if(adr==0) return; + if(len==0) return; + + len+= 3; + len-= ( len % 4); + + /* init BHead */ + bh.code= filecode; + bh.old= adr; + bh.nr= 1; + bh.SDNAnr= 0; + bh.len= len; + + mywrite(wd, &bh, sizeof(BHead)); + if(len) mywrite(wd, adr, len); +} + +/* *************** writing some direct data structs used in more code parts **************** */ +/*These functions are used by blender's .blend system for file saving/loading.*/ +void IDP_WriteProperty_OnlyData(IDProperty *prop, void *wd); +void IDP_WriteProperty(IDProperty *prop, void *wd); + +void IDP_WriteArray(IDProperty *prop, void *wd) +{ + /*REMEMBER to set totalen to len in the linking code!!*/ + if (prop->data.pointer) { + writedata(wd, DATA, MEM_allocN_len(prop->data.pointer), prop->data.pointer); + } +} + +void IDP_WriteString(IDProperty *prop, void *wd) +{ + /*REMEMBER to set totalen to len in the linking code!!*/ + writedata(wd, DATA, prop->len+1, prop->data.pointer); +} + +void IDP_WriteGroup(IDProperty *prop, void *wd) +{ + IDProperty *loop; + + for (loop=prop->data.group.first; loop; loop=loop->next) { + IDP_WriteProperty(loop, wd); + } +} + +/* Functions to read/write ID Properties */ +void IDP_WriteProperty_OnlyData(IDProperty *prop, void *wd) +{ + switch (prop->type) { + case IDP_GROUP: + IDP_WriteGroup(prop, wd); + break; + case IDP_STRING: + IDP_WriteString(prop, wd); + break; + case IDP_ARRAY: + IDP_WriteArray(prop, wd); + break; + } +} + +void IDP_WriteProperty(IDProperty *prop, void *wd) +{ + writestruct(wd, DATA, "IDProperty", 1, prop); + IDP_WriteProperty_OnlyData(prop, wd); +} + +static void write_curvemapping(WriteData *wd, CurveMapping *cumap) +{ + int a; + + writestruct(wd, DATA, "CurveMapping", 1, cumap); + for(a=0; acm[a].totpoint, cumap->cm[a].curve); +} + +/* this is only direct data, tree itself should have been written */ +static void write_nodetree(WriteData *wd, bNodeTree *ntree) +{ + bNode *node; + bNodeSocket *sock; + bNodeLink *link; + + /* for link_list() speed, we write per list */ + + for(node= ntree->nodes.first; node; node= node->next) + writestruct(wd, DATA, "bNode", 1, node); + + for(node= ntree->nodes.first; node; node= node->next) { + if(node->storage) { + /* could be handlerized at some point, now only 1 exception still */ + if(ntree->type==NTREE_SHADER && (node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB)) + write_curvemapping(wd, node->storage); + else if(ntree->type==NTREE_COMPOSIT && (node->type==CMP_NODE_TIME || node->type==CMP_NODE_CURVE_VEC || node->type==CMP_NODE_CURVE_RGB)) + write_curvemapping(wd, node->storage); + else + writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage); + } + for(sock= node->inputs.first; sock; sock= sock->next) + writestruct(wd, DATA, "bNodeSocket", 1, sock); + for(sock= node->outputs.first; sock; sock= sock->next) + writestruct(wd, DATA, "bNodeSocket", 1, sock); + } + + for(link= ntree->links.first; link; link= link->next) + writestruct(wd, DATA, "bNodeLink", 1, link); +} + +static void write_scriptlink(WriteData *wd, ScriptLink *slink) +{ + writedata(wd, DATA, sizeof(void *)*slink->totscript, slink->scripts); + writedata(wd, DATA, sizeof(short)*slink->totscript, slink->flag); +} + +static void write_renderinfo(WriteData *wd) /* for renderdeamon */ +{ + Scene *sce; + int data[8]; + + sce= G.main->scene.first; + while(sce) { + if(sce->id.lib==0 && ( sce==G.scene || (sce->r.scemode & R_BG_RENDER)) ) { + data[0]= sce->r.sfra; + data[1]= sce->r.efra; + + memset(data+2, 0, sizeof(int)*6); + strncpy((char *)(data+2), sce->id.name+2, 21); + + writedata(wd, REND, 32, data); + } + sce= sce->id.next; + } +} + +static void write_userdef(WriteData *wd) +{ + bTheme *btheme; + + writestruct(wd, USER, "UserDef", 1, &U); + + btheme= U.themes.first; + while(btheme) { + writestruct(wd, DATA, "bTheme", 1, btheme); + btheme= btheme->next; + } +} + +static void write_effects(WriteData *wd, ListBase *lb) +{ + Effect *eff; + + eff= lb->first; + while(eff) { + + switch(eff->type) { + case EFF_PARTICLE: + writestruct(wd, DATA, "PartEff", 1, eff); + break; + default: + writedata(wd, DATA, MEM_allocN_len(eff), eff); + } + + eff= eff->next; + } +} + +static void write_properties(WriteData *wd, ListBase *lb) +{ + bProperty *prop; + + prop= lb->first; + while(prop) { + writestruct(wd, DATA, "bProperty", 1, prop); + + if(prop->poin && prop->poin != &prop->data) + writedata(wd, DATA, MEM_allocN_len(prop->poin), prop->poin); + + prop= prop->next; + } +} + +static void write_sensors(WriteData *wd, ListBase *lb) +{ + bSensor *sens; + + sens= lb->first; + while(sens) { + writestruct(wd, DATA, "bSensor", 1, sens); + + writedata(wd, DATA, sizeof(void *)*sens->totlinks, sens->links); + + switch(sens->type) { + case SENS_NEAR: + writestruct(wd, DATA, "bNearSensor", 1, sens->data); + break; + case SENS_MOUSE: + writestruct(wd, DATA, "bMouseSensor", 1, sens->data); + break; + case SENS_TOUCH: + writestruct(wd, DATA, "bTouchSensor", 1, sens->data); + break; + case SENS_KEYBOARD: + writestruct(wd, DATA, "bKeyboardSensor", 1, sens->data); + break; + case SENS_PROPERTY: + writestruct(wd, DATA, "bPropertySensor", 1, sens->data); + break; + case SENS_COLLISION: + writestruct(wd, DATA, "bCollisionSensor", 1, sens->data); + break; + case SENS_RADAR: + writestruct(wd, DATA, "bRadarSensor", 1, sens->data); + break; + case SENS_RANDOM: + writestruct(wd, DATA, "bRandomSensor", 1, sens->data); + break; + case SENS_RAY: + writestruct(wd, DATA, "bRaySensor", 1, sens->data); + break; + case SENS_MESSAGE: + writestruct(wd, DATA, "bMessageSensor", 1, sens->data); + break; + case SENS_JOYSTICK: + writestruct(wd, DATA, "bJoystickSensor", 1, sens->data); + break; + default: + ; /* error: don't know how to write this file */ + } + + sens= sens->next; + } +} + +static void write_controllers(WriteData *wd, ListBase *lb) +{ + bController *cont; + + cont= lb->first; + while(cont) { + writestruct(wd, DATA, "bController", 1, cont); + + writedata(wd, DATA, sizeof(void *)*cont->totlinks, cont->links); + + switch(cont->type) { + case CONT_EXPRESSION: + writestruct(wd, DATA, "bExpressionCont", 1, cont->data); + break; + case CONT_PYTHON: + writestruct(wd, DATA, "bPythonCont", 1, cont->data); + break; + default: + ; /* error: don't know how to write this file */ + } + + cont= cont->next; + } +} + +static void write_actuators(WriteData *wd, ListBase *lb) +{ + bActuator *act; + + act= lb->first; + while(act) { + writestruct(wd, DATA, "bActuator", 1, act); + + switch(act->type) { + case ACT_ACTION: + writestruct(wd, DATA, "bActionActuator", 1, act->data); + break; + case ACT_SOUND: + writestruct(wd, DATA, "bSoundActuator", 1, act->data); + break; + case ACT_CD: + writestruct(wd, DATA, "bCDActuator", 1, act->data); + break; + case ACT_OBJECT: + writestruct(wd, DATA, "bObjectActuator", 1, act->data); + break; + case ACT_IPO: + writestruct(wd, DATA, "bIpoActuator", 1, act->data); + break; + case ACT_PROPERTY: + writestruct(wd, DATA, "bPropertyActuator", 1, act->data); + break; + case ACT_CAMERA: + writestruct(wd, DATA, "bCameraActuator", 1, act->data); + break; + case ACT_CONSTRAINT: + writestruct(wd, DATA, "bConstraintActuator", 1, act->data); + break; + case ACT_EDIT_OBJECT: + writestruct(wd, DATA, "bEditObjectActuator", 1, act->data); + break; + case ACT_SCENE: + writestruct(wd, DATA, "bSceneActuator", 1, act->data); + break; + case ACT_GROUP: + writestruct(wd, DATA, "bGroupActuator", 1, act->data); + break; + case ACT_RANDOM: + writestruct(wd, DATA, "bRandomActuator", 1, act->data); + break; + case ACT_MESSAGE: + writestruct(wd, DATA, "bMessageActuator", 1, act->data); + break; + case ACT_GAME: + writestruct(wd, DATA, "bGameActuator", 1, act->data); + break; + case ACT_VISIBILITY: + writestruct(wd, DATA, "bVisibilityActuator", 1, act->data); + break; + default: + ; /* error: don't know how to write this file */ + } + + act= act->next; + } +} + +static void write_nlastrips(WriteData *wd, ListBase *nlabase) +{ + bActionStrip *strip; + bActionModifier *amod; + + for (strip=nlabase->first; strip; strip=strip->next) + writestruct(wd, DATA, "bActionStrip", 1, strip); + for (strip=nlabase->first; strip; strip=strip->next) { + for(amod= strip->modifiers.first; amod; amod= amod->next) + writestruct(wd, DATA, "bActionModifier", 1, amod); + } +} + +static void write_constraints(WriteData *wd, ListBase *conlist) +{ + bConstraint *con; + + for (con=conlist->first; con; con=con->next) { + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + + /* Write the specific data */ + if (cti && con->data) { + /* firstly, just write the plain con->data struct */ + writestruct(wd, DATA, cti->structName, 1, con->data); + + /* do any constraint specific stuff */ + switch (con->type) { + case CONSTRAINT_TYPE_PYTHON: + { + bPythonConstraint *data = (bPythonConstraint *)con->data; + bConstraintTarget *ct; + + /* write targets */ + for (ct= data->targets.first; ct; ct= ct->next) + writestruct(wd, DATA, "bConstraintTarget", 1, ct); + + /* Write ID Properties -- and copy this comment EXACTLY for easy finding + of library blocks that implement this.*/ + IDP_WriteProperty(data->prop, wd); + } + break; + } + } + + /* Write the constraint */ + writestruct(wd, DATA, "bConstraint", 1, con); + } +} + +static void write_pose(WriteData *wd, bPose *pose) +{ + bPoseChannel *chan; + + /* Write each channel */ + if (!pose) + return; + + /* Write channels */ + for (chan=pose->chanbase.first; chan; chan=chan->next) { + write_constraints(wd, &chan->constraints); + + /* prevent crashes with autosave, when a bone duplicated in editmode has not yet been assigned to its posechannel */ + if (chan->bone) + chan->selectflag= chan->bone->flag & (BONE_SELECTED|BONE_ACTIVE); /* gets restored on read, for library armatures */ + + writestruct(wd, DATA, "bPoseChannel", 1, chan); + } + + /* Write this pose */ + writestruct(wd, DATA, "bPose", 1, pose); +} + +static void write_defgroups(WriteData *wd, ListBase *defbase) +{ + bDeformGroup *defgroup; + + for (defgroup=defbase->first; defgroup; defgroup=defgroup->next) + writestruct(wd, DATA, "bDeformGroup", 1, defgroup); +} + +static void write_constraint_channels(WriteData *wd, ListBase *chanbase) +{ + bConstraintChannel *chan; + + for (chan = chanbase->first; chan; chan=chan->next) + writestruct(wd, DATA, "bConstraintChannel", 1, chan); + +} + +static void write_modifiers(WriteData *wd, ListBase *modbase) +{ + ModifierData *md; + + if (modbase == NULL) return; + for (md=modbase->first; md; md= md->next) { + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + if (mti == NULL) return; + + writestruct(wd, DATA, mti->structName, 1, md); + + if (md->type==eModifierType_Hook) { + HookModifierData *hmd = (HookModifierData*) md; + + writedata(wd, DATA, sizeof(int)*hmd->totindex, hmd->indexar); + } + else if (md->type==eModifierType_MeshDeform) { + MeshDeformModifierData *mmd = (MeshDeformModifierData*) md; + + writedata(wd, DATA, sizeof(float)*mmd->totvert*mmd->totcagevert, + mmd->bindweights); + writedata(wd, DATA, sizeof(float)*3*mmd->totcagevert, + mmd->bindcos); + } + } +} + +static void write_objects(WriteData *wd, ListBase *idbase) +{ + Object *ob; + int a; + + ob= idbase->first; + while(ob) { + if(ob->id.us>0 || wd->current) { + /* write LibData */ +#ifdef WITH_VERSE + /* pointer at vnode stored in file have to be NULL */ + struct VNode *vnode = (VNode*)ob->vnode; + if(vnode) ob->vnode = NULL; +#endif + writestruct(wd, ID_OB, "Object", 1, ob); +#ifdef WITH_VERSE + if(vnode) ob->vnode = (void*)vnode; +#endif + + /*Write ID Properties -- and copy this comment EXACTLY for easy finding + of library blocks that implement this.*/ + if (ob->id.properties) IDP_WriteProperty(ob->id.properties, wd); + + /* direct data */ + writedata(wd, DATA, sizeof(void *)*ob->totcol, ob->mat); + write_effects(wd, &ob->effect); + write_properties(wd, &ob->prop); + write_sensors(wd, &ob->sensors); + write_controllers(wd, &ob->controllers); + write_actuators(wd, &ob->actuators); + write_scriptlink(wd, &ob->scriptlink); + write_pose(wd, ob->pose); + write_defgroups(wd, &ob->defbase); + write_constraints(wd, &ob->constraints); + write_constraint_channels(wd, &ob->constraintChannels); + write_nlastrips(wd, &ob->nlastrips); + + writestruct(wd, DATA, "PartDeflect", 1, ob->pd); + writestruct(wd, DATA, "SoftBody", 1, ob->soft); + if(ob->soft) { + SoftBody *sb= ob->soft; + if(sb->keys) { + writedata(wd, DATA, sizeof(void *)*sb->totkey, sb->keys); + for(a=0; atotkey; a++) { + writestruct(wd, DATA, "SBVertex", sb->totpoint, sb->keys[a]); + } + } + } + writestruct(wd, DATA, "FluidsimSettings", 1, ob->fluidsimSettings); // NT + + write_modifiers(wd, &ob->modifiers); + } + ob= ob->id.next; + } + + /* flush helps the compression for undo-save */ + mywrite(wd, MYWRITE_FLUSH, 0); +} + + +static void write_vfonts(WriteData *wd, ListBase *idbase) +{ + VFont *vf; + PackedFile * pf; + + vf= idbase->first; + while(vf) { + if(vf->id.us>0 || wd->current) { + /* write LibData */ + writestruct(wd, ID_VF, "VFont", 1, vf); + if (vf->id.properties) IDP_WriteProperty(vf->id.properties, wd); + + /* direct data */ + + if (vf->packedfile) { + pf = vf->packedfile; + writestruct(wd, DATA, "PackedFile", 1, pf); + writedata(wd, DATA, pf->size, pf->data); + } + } + + vf= vf->id.next; + } +} + +static void write_ipos(WriteData *wd, ListBase *idbase) +{ + Ipo *ipo; + IpoCurve *icu; + + ipo= idbase->first; + while(ipo) { + if(ipo->id.us>0 || wd->current) { + /* write LibData */ + writestruct(wd, ID_IP, "Ipo", 1, ipo); + if (ipo->id.properties) IDP_WriteProperty(ipo->id.properties, wd); + + /* direct data */ + icu= ipo->curve.first; + while(icu) { + writestruct(wd, DATA, "IpoCurve", 1, icu); + icu= icu->next; + } + + icu= ipo->curve.first; + while(icu) { + if(icu->bezt) writestruct(wd, DATA, "BezTriple", icu->totvert, icu->bezt); + if(icu->bp) writestruct(wd, DATA, "BPoint", icu->totvert, icu->bp); + if(icu->driver) writestruct(wd, DATA, "IpoDriver", 1, icu->driver); + icu= icu->next; + } + } + + ipo= ipo->id.next; + } + + /* flush helps the compression for undo-save */ + mywrite(wd, MYWRITE_FLUSH, 0); +} + +static void write_keys(WriteData *wd, ListBase *idbase) +{ + Key *key; + KeyBlock *kb; + + key= idbase->first; + while(key) { + if(key->id.us>0 || wd->current) { + /* write LibData */ + writestruct(wd, ID_KE, "Key", 1, key); + if (key->id.properties) IDP_WriteProperty(key->id.properties, wd); + + /* direct data */ + kb= key->block.first; + while(kb) { + writestruct(wd, DATA, "KeyBlock", 1, kb); + if(kb->data) writedata(wd, DATA, kb->totelem*key->elemsize, kb->data); + kb= kb->next; + } + } + + key= key->id.next; + } + /* flush helps the compression for undo-save */ + mywrite(wd, MYWRITE_FLUSH, 0); +} + +static void write_cameras(WriteData *wd, ListBase *idbase) +{ + Camera *cam; + + cam= idbase->first; + while(cam) { + if(cam->id.us>0 || wd->current) { + /* write LibData */ + writestruct(wd, ID_CA, "Camera", 1, cam); + if (cam->id.properties) IDP_WriteProperty(cam->id.properties, wd); + + /* direct data */ + write_scriptlink(wd, &cam->scriptlink); + } + + cam= cam->id.next; + } +} + +static void write_mballs(WriteData *wd, ListBase *idbase) +{ + MetaBall *mb; + MetaElem *ml; + + mb= idbase->first; + while(mb) { + if(mb->id.us>0 || wd->current) { + /* write LibData */ + writestruct(wd, ID_MB, "MetaBall", 1, mb); + if (mb->id.properties) IDP_WriteProperty(mb->id.properties, wd); + + /* direct data */ + writedata(wd, DATA, sizeof(void *)*mb->totcol, mb->mat); + + ml= mb->elems.first; + while(ml) { + writestruct(wd, DATA, "MetaElem", 1, ml); + ml= ml->next; + } + } + mb= mb->id.next; + } +} + +int amount_of_chars(char *str) +{ + // Since the data is saved as UTF-8 to the cu->str + // The cu->len is not same as the strlen(cu->str) + return strlen(str); +} + +static void write_curves(WriteData *wd, ListBase *idbase) +{ + Curve *cu; + Nurb *nu; + + cu= idbase->first; + while(cu) { + if(cu->id.us>0 || wd->current) { + /* write LibData */ + writestruct(wd, ID_CU, "Curve", 1, cu); + + /* direct data */ + writedata(wd, DATA, sizeof(void *)*cu->totcol, cu->mat); + if (cu->id.properties) IDP_WriteProperty(cu->id.properties, wd); + + if(cu->vfont) { + writedata(wd, DATA, amount_of_chars(cu->str)+1, cu->str); + writestruct(wd, DATA, "CharInfo", cu->len, cu->strinfo); + writestruct(wd, DATA, "TextBox", cu->totbox, cu->tb); + } + else { + /* is also the order of reading */ + nu= cu->nurb.first; + while(nu) { + writestruct(wd, DATA, "Nurb", 1, nu); + nu= nu->next; + } + nu= cu->nurb.first; + while(nu) { + if( (nu->type & 7)==CU_BEZIER) + writestruct(wd, DATA, "BezTriple", nu->pntsu, nu->bezt); + else { + writestruct(wd, DATA, "BPoint", nu->pntsu*nu->pntsv, nu->bp); + if(nu->knotsu) writedata(wd, DATA, KNOTSU(nu)*sizeof(float), nu->knotsu); + if(nu->knotsv) writedata(wd, DATA, KNOTSV(nu)*sizeof(float), nu->knotsv); + } + nu= nu->next; + } + } + } + cu= cu->id.next; + } + + /* flush helps the compression for undo-save */ + mywrite(wd, MYWRITE_FLUSH, 0); +} + +static void write_dverts(WriteData *wd, int count, MDeformVert *dvlist) +{ + if (dvlist) { + int i; + + /* Write the dvert list */ + writestruct(wd, DATA, "MDeformVert", count, dvlist); + + /* Write deformation data for each dvert */ + for (i=0; imaxlayer, data->layers); + + for (i=0; itotlayer; i++) { + CustomDataLayer *layer= &data->layers[i]; + char *structname; + int structnum, datasize; + + if (layer->type == CD_MDEFORMVERT) { + /* layer types that allocate own memory need special handling */ + write_dverts(wd, count, layer->data); + } + else { + CustomData_file_write_info(layer->type, &structname, &structnum); + if (structnum) { + /* when using partial visibility, the MEdge and MFace layers + are smaller than the original, so their type and count is + passed to make this work */ + if (layer->type != partial_type) datasize= structnum*count; + else datasize= structnum*partial_count; + + writestruct(wd, DATA, structname, datasize, layer->data); + } + else + printf("error: this CustomDataLayer must not be written to file\n"); + } + } +} + +static void write_meshs(WriteData *wd, ListBase *idbase) +{ + Mesh *mesh; + MultiresLevel *lvl; + + mesh= idbase->first; + while(mesh) { + if(mesh->id.us>0 || wd->current) { + /* write LibData */ +#ifdef WITH_VERSE + struct VNode *vnode = (VNode*)mesh->vnode; + if(vnode) { + /* mesh has to be created from verse geometry node*/ + create_meshdata_from_geom_node(mesh, vnode); + /* pointer at verse node can't be stored in file */ + mesh->vnode = NULL; + } +#endif + + writestruct(wd, ID_ME, "Mesh", 1, mesh); +#ifdef WITH_VERSE + if(vnode) mesh->vnode = (void*)vnode; +#endif + + /* direct data */ + if (mesh->id.properties) IDP_WriteProperty(mesh->id.properties, wd); + + writedata(wd, DATA, sizeof(void *)*mesh->totcol, mesh->mat); + + if(mesh->pv) { + write_customdata(wd, mesh->pv->totvert, &mesh->vdata, -1, 0); + write_customdata(wd, mesh->pv->totedge, &mesh->edata, + CD_MEDGE, mesh->totedge); + write_customdata(wd, mesh->pv->totface, &mesh->fdata, + CD_MFACE, mesh->totface); + } + else { + write_customdata(wd, mesh->totvert, &mesh->vdata, -1, 0); + write_customdata(wd, mesh->totedge, &mesh->edata, -1, 0); + write_customdata(wd, mesh->totface, &mesh->fdata, -1, 0); + } + + /* Multires data */ + writestruct(wd, DATA, "Multires", 1, mesh->mr); + if(mesh->mr) { + lvl= mesh->mr->levels.first; + if(lvl) { + write_customdata(wd, lvl->totvert, &mesh->mr->vdata, -1, 0); + write_customdata(wd, lvl->totface, &mesh->mr->fdata, -1, 0); + writedata(wd, DATA, sizeof(short)*lvl->totedge, mesh->mr->edge_flags); + writedata(wd, DATA, sizeof(char)*lvl->totedge, mesh->mr->edge_creases); + } + + for(; lvl; lvl= lvl->next) { + writestruct(wd, DATA, "MultiresLevel", 1, lvl); + writestruct(wd, DATA, "MultiresFace", lvl->totface, lvl->faces); + writestruct(wd, DATA, "MultiresEdge", lvl->totedge, lvl->edges); + writestruct(wd, DATA, "MultiresColFace", lvl->totface, lvl->colfaces); + } + + lvl= mesh->mr->levels.last; + if(lvl) + writestruct(wd, DATA, "MVert", lvl->totvert, mesh->mr->verts); + } + + /* PMV data */ + if(mesh->pv) { + writestruct(wd, DATA, "PartialVisibility", 1, mesh->pv); + writedata(wd, DATA, sizeof(unsigned int)*mesh->pv->totvert, mesh->pv->vert_map); + writedata(wd, DATA, sizeof(int)*mesh->pv->totedge, mesh->pv->edge_map); + writestruct(wd, DATA, "MFace", mesh->pv->totface, mesh->pv->old_faces); + writestruct(wd, DATA, "MEdge", mesh->pv->totedge, mesh->pv->old_edges); + } + } + mesh= mesh->id.next; + } +} + +static void write_lattices(WriteData *wd, ListBase *idbase) +{ + Lattice *lt; + + lt= idbase->first; + while(lt) { + if(lt->id.us>0 || wd->current) { + /* write LibData */ + writestruct(wd, ID_LT, "Lattice", 1, lt); + if (lt->id.properties) IDP_WriteProperty(lt->id.properties, wd); + + /* direct data */ + writestruct(wd, DATA, "BPoint", lt->pntsu*lt->pntsv*lt->pntsw, lt->def); + + write_dverts(wd, lt->pntsu*lt->pntsv*lt->pntsw, lt->dvert); + + } + lt= lt->id.next; + } +} + +static void write_previews(WriteData *wd, PreviewImage *prv) +{ + if (prv) { + short w = prv->w[1]; + short h = prv->h[1]; + unsigned int *rect = prv->rect[1]; + /* don't write out large previews if not requested */ + if (!(U.flag & USER_SAVE_PREVIEWS) ) { + prv->w[1] = 0; + prv->h[1] = 0; + prv->rect[1] = NULL; + } + writestruct(wd, DATA, "PreviewImage", 1, prv); + if (prv->rect[0]) writedata(wd, DATA, prv->w[0]*prv->h[0]*sizeof(unsigned int), prv->rect[0]); + if (prv->rect[1]) writedata(wd, DATA, prv->w[1]*prv->h[1]*sizeof(unsigned int), prv->rect[1]); + + /* restore preview, we still want to keep it in memory even if not saved to file */ + if (!(U.flag & USER_SAVE_PREVIEWS) ) { + prv->w[1] = w; + prv->h[1] = h; + prv->rect[1] = rect; + } + } +} + +static void write_images(WriteData *wd, ListBase *idbase) +{ + Image *ima; + PackedFile * pf; + + + ima= idbase->first; + while(ima) { + if(ima->id.us>0 || wd->current) { + /* write LibData */ + writestruct(wd, ID_IM, "Image", 1, ima); + if (ima->id.properties) IDP_WriteProperty(ima->id.properties, wd); + + if (ima->packedfile) { + pf = ima->packedfile; + writestruct(wd, DATA, "PackedFile", 1, pf); + writedata(wd, DATA, pf->size, pf->data); + } + + write_previews(wd, ima->preview); + + } + ima= ima->id.next; + } + /* flush helps the compression for undo-save */ + mywrite(wd, MYWRITE_FLUSH, 0); +} + +static void write_textures(WriteData *wd, ListBase *idbase) +{ + Tex *tex; + + tex= idbase->first; + while(tex) { + if(tex->id.us>0 || wd->current) { + /* write LibData */ + writestruct(wd, ID_TE, "Tex", 1, tex); + if (tex->id.properties) IDP_WriteProperty(tex->id.properties, wd); + + /* direct data */ + if(tex->plugin) writestruct(wd, DATA, "PluginTex", 1, tex->plugin); + if(tex->coba) writestruct(wd, DATA, "ColorBand", 1, tex->coba); + if(tex->env) writestruct(wd, DATA, "EnvMap", 1, tex->env); + + write_previews(wd, tex->preview); + } + tex= tex->id.next; + } + + /* flush helps the compression for undo-save */ + mywrite(wd, MYWRITE_FLUSH, 0); +} + +static void write_materials(WriteData *wd, ListBase *idbase) +{ + Material *ma; + int a; + + ma= idbase->first; + while(ma) { + if(ma->id.us>0 || wd->current) { + /* write LibData */ + writestruct(wd, ID_MA, "Material", 1, ma); + + /*Write ID Properties -- and copy this comment EXACTLY for easy finding + of library blocks that implement this.*/ + /*manually set head group property to IDP_GROUP, just in case it hadn't been + set yet :) */ + if (ma->id.properties) IDP_WriteProperty(ma->id.properties, wd); + + for(a=0; amtex[a]) writestruct(wd, DATA, "MTex", 1, ma->mtex[a]); + } + + if(ma->ramp_col) writestruct(wd, DATA, "ColorBand", 1, ma->ramp_col); + if(ma->ramp_spec) writestruct(wd, DATA, "ColorBand", 1, ma->ramp_spec); + + write_scriptlink(wd, &ma->scriptlink); + + /* nodetree is integral part of material, no libdata */ + if(ma->nodetree) { + writestruct(wd, DATA, "bNodeTree", 1, ma->nodetree); + write_nodetree(wd, ma->nodetree); + } + + write_previews(wd, ma->preview); + } + ma= ma->id.next; + } +} + +static void write_worlds(WriteData *wd, ListBase *idbase) +{ + World *wrld; + int a; + + wrld= idbase->first; + while(wrld) { + if(wrld->id.us>0 || wd->current) { + /* write LibData */ + writestruct(wd, ID_WO, "World", 1, wrld); + if (wrld->id.properties) IDP_WriteProperty(wrld->id.properties, wd); + + for(a=0; amtex[a]) writestruct(wd, DATA, "MTex", 1, wrld->mtex[a]); + } + + write_scriptlink(wd, &wrld->scriptlink); + + write_previews(wd, wrld->preview); + + } + wrld= wrld->id.next; + } +} + +static void write_lamps(WriteData *wd, ListBase *idbase) +{ + Lamp *la; + int a; + + la= idbase->first; + while(la) { + if(la->id.us>0 || wd->current) { + /* write LibData */ + writestruct(wd, ID_LA, "Lamp", 1, la); + if (la->id.properties) IDP_WriteProperty(la->id.properties, wd); + + /* direct data */ + for(a=0; amtex[a]) writestruct(wd, DATA, "MTex", 1, la->mtex[a]); + } + + if(la->curfalloff) + write_curvemapping(wd, la->curfalloff); + + write_scriptlink(wd, &la->scriptlink); + + write_previews(wd, la->preview); + + } + la= la->id.next; + } +} + + +static void write_scenes(WriteData *wd, ListBase *scebase) +{ + Scene *sce; + Base *base; + Editing *ed; + Sequence *seq; + MetaStack *ms; + Strip *strip; + TimeMarker *marker; + SceneRenderLayer *srl; + int a; + + sce= scebase->first; + while(sce) { + /* write LibData */ + writestruct(wd, ID_SCE, "Scene", 1, sce); + if (sce->id.properties) IDP_WriteProperty(sce->id.properties, wd); + + /* direct data */ + base= sce->base.first; + while(base) { + writestruct(wd, DATA, "Base", 1, base); + base= base->next; + } + + writestruct(wd, DATA, "Radio", 1, sce->radio); + writestruct(wd, DATA, "ToolSettings", 1, sce->toolsettings); + + for(a=0; asculptdata.mtex[a]); + + ed= sce->ed; + if(ed) { + writestruct(wd, DATA, "Editing", 1, ed); + + /* reset write flags too */ + WHILE_SEQ(&ed->seqbase) { + if(seq->strip) seq->strip->done= 0; + writestruct(wd, DATA, "Sequence", 1, seq); + } + END_SEQ + + WHILE_SEQ(&ed->seqbase) { + if(seq->strip && seq->strip->done==0) { + /* write strip with 'done' at 0 because readfile */ + + if(seq->plugin) writestruct(wd, DATA, "PluginSeq", 1, seq->plugin); + if(seq->effectdata) { + switch(seq->type){ + case SEQ_COLOR: + writestruct(wd, DATA, "SolidColorVars", 1, seq->effectdata); + break; + case SEQ_SPEED: + writestruct(wd, DATA, "SpeedControlVars", 1, seq->effectdata); + break; + case SEQ_WIPE: + writestruct(wd, DATA, "WipeVars", 1, seq->effectdata); + break; + case SEQ_GLOW: + writestruct(wd, DATA, "GlowVars", 1, seq->effectdata); + break; + case SEQ_TRANSFORM: + writestruct(wd, DATA, "TransformVars", 1, seq->effectdata); + break; + } + } + + strip= seq->strip; + writestruct(wd, DATA, "Strip", 1, strip); + + if(seq->type==SEQ_IMAGE) + writestruct(wd, DATA, "StripElem", strip->len, strip->stripdata); + else if(seq->type==SEQ_MOVIE || seq->type==SEQ_RAM_SOUND || seq->type == SEQ_HD_SOUND) + writestruct(wd, DATA, "StripElem", 1, strip->stripdata); + + strip->done= 1; + } + } + END_SEQ + + /* new; meta stack too, even when its nasty restore code */ + for(ms= ed->metastack.first; ms; ms= ms->next) { + writestruct(wd, DATA, "MetaStack", 1, ms); + } + } + + write_scriptlink(wd, &sce->scriptlink); + + if (sce->r.avicodecdata) { + writestruct(wd, DATA, "AviCodecData", 1, sce->r.avicodecdata); + if (sce->r.avicodecdata->lpFormat) writedata(wd, DATA, sce->r.avicodecdata->cbFormat, sce->r.avicodecdata->lpFormat); + if (sce->r.avicodecdata->lpParms) writedata(wd, DATA, sce->r.avicodecdata->cbParms, sce->r.avicodecdata->lpParms); + } + + if (sce->r.qtcodecdata) { + writestruct(wd, DATA, "QuicktimeCodecData", 1, sce->r.qtcodecdata); + if (sce->r.qtcodecdata->cdParms) writedata(wd, DATA, sce->r.qtcodecdata->cdSize, sce->r.qtcodecdata->cdParms); + } + + /* writing dynamic list of TimeMarkers to the blend file */ + for(marker= sce->markers.first; marker; marker= marker->next) + writestruct(wd, DATA, "TimeMarker", 1, marker); + + for(srl= sce->r.layers.first; srl; srl= srl->next) + writestruct(wd, DATA, "SceneRenderLayer", 1, srl); + + if(sce->nodetree) { + writestruct(wd, DATA, "bNodeTree", 1, sce->nodetree); + write_nodetree(wd, sce->nodetree); + } + + sce= sce->id.next; + } + /* flush helps the compression for undo-save */ + mywrite(wd, MYWRITE_FLUSH, 0); +} + +static void write_screens(WriteData *wd, ListBase *scrbase) +{ + bScreen *sc; + ScrArea *sa; + ScrVert *sv; + ScrEdge *se; + + sc= scrbase->first; + while(sc) { + /* write LibData */ + writestruct(wd, ID_SCR, "Screen", 1, sc); + if (sc->id.properties) IDP_WriteProperty(sc->id.properties, wd); + + /* direct data */ + sv= sc->vertbase.first; + while(sv) { + writestruct(wd, DATA, "ScrVert", 1, sv); + sv= sv->next; + } + + se= sc->edgebase.first; + while(se) { + writestruct(wd, DATA, "ScrEdge", 1, se); + se= se->next; + } + + sa= sc->areabase.first; + while(sa) { + SpaceLink *sl; + Panel *pa; + + writestruct(wd, DATA, "ScrArea", 1, sa); + + pa= sa->panels.first; + while(pa) { + writestruct(wd, DATA, "Panel", 1, pa); + pa= pa->next; + } + + /* space handler scriptlinks */ + write_scriptlink(wd, &sa->scriptlink); + + sl= sa->spacedata.first; + while(sl) { + if(sl->spacetype==SPACE_VIEW3D) { + View3D *v3d= (View3D*) sl; + writestruct(wd, DATA, "View3D", 1, v3d); + if(v3d->bgpic) writestruct(wd, DATA, "BGpic", 1, v3d->bgpic); + if(v3d->localvd) writestruct(wd, DATA, "View3D", 1, v3d->localvd); + if(v3d->clipbb) writestruct(wd, DATA, "BoundBox", 1, v3d->clipbb); + } + else if(sl->spacetype==SPACE_IPO) { + writestruct(wd, DATA, "SpaceIpo", 1, sl); + } + else if(sl->spacetype==SPACE_BUTS) { + writestruct(wd, DATA, "SpaceButs", 1, sl); + } + else if(sl->spacetype==SPACE_FILE) { + writestruct(wd, DATA, "SpaceFile", 1, sl); + } + else if(sl->spacetype==SPACE_SEQ) { + writestruct(wd, DATA, "SpaceSeq", 1, sl); + } + else if(sl->spacetype==SPACE_OOPS) { + SpaceOops *so= (SpaceOops *)sl; + Oops *oops; + + /* cleanup */ + oops= so->oops.first; + while(oops) { + Oops *oopsn= oops->next; + if(oops->id==0) { + BLI_remlink(&so->oops, oops); + free_oops(oops); + } + oops= oopsn; + } + + /* ater cleanup, because of listbase! */ + writestruct(wd, DATA, "SpaceOops", 1, so); + + oops= so->oops.first; + while(oops) { + writestruct(wd, DATA, "Oops", 1, oops); + oops= oops->next; + } + /* outliner */ + if(so->treestore) { + writestruct(wd, DATA, "TreeStore", 1, so->treestore); + if(so->treestore->data) + writestruct(wd, DATA, "TreeStoreElem", so->treestore->usedelem, so->treestore->data); + } + } + else if(sl->spacetype==SPACE_IMAGE) { + SpaceImage *sima= (SpaceImage *)sl; + + writestruct(wd, DATA, "SpaceImage", 1, sl); + if(sima->cumap) + write_curvemapping(wd, sima->cumap); + } + else if(sl->spacetype==SPACE_IMASEL) { + writestruct(wd, DATA, "SpaceImaSel", 1, sl); + } + else if(sl->spacetype==SPACE_TEXT) { + writestruct(wd, DATA, "SpaceText", 1, sl); + } + else if(sl->spacetype==SPACE_SCRIPT) { + SpaceScript *sc = (SpaceScript*)sl; + sc->but_refs = NULL; + writestruct(wd, DATA, "SpaceScript", 1, sl); + } + else if(sl->spacetype==SPACE_ACTION) { + writestruct(wd, DATA, "SpaceAction", 1, sl); + } + else if(sl->spacetype==SPACE_SOUND) { + writestruct(wd, DATA, "SpaceSound", 1, sl); + } + else if(sl->spacetype==SPACE_NLA){ + writestruct(wd, DATA, "SpaceNla", 1, sl); + } + else if(sl->spacetype==SPACE_TIME){ + writestruct(wd, DATA, "SpaceTime", 1, sl); + } + else if(sl->spacetype==SPACE_NODE){ + writestruct(wd, DATA, "SpaceNode", 1, sl); + } + sl= sl->next; + } + + sa= sa->next; + } + + sc= sc->id.next; + } +} + +static void write_libraries(WriteData *wd, Main *main) +{ + ListBase *lbarray[30]; + ID *id; + int a, tot, foundone; + + for(; main; main= main->next) { + + a=tot= set_listbasepointers(main, lbarray); + + /* test: is lib being used */ + foundone= 0; + while(tot--) { + for(id= lbarray[tot]->first; id; id= id->next) { + if(id->us>0 && (id->flag & LIB_EXTERN)) { + foundone= 1; + break; + } + } + if(foundone) break; + } + + if(foundone) { + writestruct(wd, ID_LI, "Library", 1, main->curlib); + + while(a--) { + for(id= lbarray[a]->first; id; id= id->next) { + if(id->us>0 && (id->flag & LIB_EXTERN)) { + writestruct(wd, ID_ID, "ID", 1, id); + } + } + } + } + } +} + +static void write_bone(WriteData *wd, Bone* bone) +{ + Bone* cbone; + + // PATCH for upward compatibility after 2.37+ armature recode + bone->size[0]= bone->size[1]= bone->size[2]= 1.0f; + + // Write this bone + writestruct(wd, DATA, "Bone", 1, bone); + + // Write Children + cbone= bone->childbase.first; + while(cbone) { + write_bone(wd, cbone); + cbone= cbone->next; + } +} + +static void write_armatures(WriteData *wd, ListBase *idbase) +{ + bArmature *arm; + Bone *bone; + + arm=idbase->first; + while (arm) { + if (arm->id.us>0 || wd->current) { + writestruct(wd, ID_AR, "bArmature", 1, arm); + if (arm->id.properties) IDP_WriteProperty(arm->id.properties, wd); + + /* Direct data */ + bone= arm->bonebase.first; + while(bone) { + write_bone(wd, bone); + bone=bone->next; + } + } + arm=arm->id.next; + } + + /* flush helps the compression for undo-save */ + mywrite(wd, MYWRITE_FLUSH, 0); +} + +static void write_actions(WriteData *wd, ListBase *idbase) +{ + bAction *act; + bActionChannel *chan; + + for(act=idbase->first; act; act= act->id.next) { + if (act->id.us>0 || wd->current) { + writestruct(wd, ID_AC, "bAction", 1, act); + if (act->id.properties) IDP_WriteProperty(act->id.properties, wd); + + for (chan=act->chanbase.first; chan; chan=chan->next) { + writestruct(wd, DATA, "bActionChannel", 1, chan); + write_constraint_channels(wd, &chan->constraintChannels); + } + } + } +} + +static void write_texts(WriteData *wd, ListBase *idbase) +{ + Text *text; + TextLine *tmp; + + text= idbase->first; + while(text) { + if ( (text->flags & TXT_ISMEM) && (text->flags & TXT_ISEXT)) text->flags &= ~TXT_ISEXT; + + /* write LibData */ + writestruct(wd, ID_TXT, "Text", 1, text); + if(text->name) writedata(wd, DATA, strlen(text->name)+1, text->name); + if (text->id.properties) IDP_WriteProperty(text->id.properties, wd); + + if(!(text->flags & TXT_ISEXT)) { + /* now write the text data, in two steps for optimization in the readfunction */ + tmp= text->lines.first; + while (tmp) { + writestruct(wd, DATA, "TextLine", 1, tmp); + tmp= tmp->next; + } + + tmp= text->lines.first; + while (tmp) { + writedata(wd, DATA, tmp->len+1, tmp->line); + tmp= tmp->next; + } + } + text= text->id.next; + } + + /* flush helps the compression for undo-save */ + mywrite(wd, MYWRITE_FLUSH, 0); +} + +static void write_sounds(WriteData *wd, ListBase *idbase) +{ + bSound *sound; + bSample *sample; + + PackedFile * pf; + + // set all samples to unsaved status + + sample = samples->first; + while (sample) { + sample->flags |= SAMPLE_NEEDS_SAVE; + sample = sample->id.next; + } + + sound= idbase->first; + while(sound) { + if(sound->id.us>0 || wd->current) { + // do we need to save the packedfile as well ? + sample = sound->sample; + if (sample) { + if (sample->flags & SAMPLE_NEEDS_SAVE) { + sound->newpackedfile = sample->packedfile; + sample->flags &= ~SAMPLE_NEEDS_SAVE; + } else { + sound->newpackedfile = NULL; + } + } + + /* write LibData */ + writestruct(wd, ID_SO, "bSound", 1, sound); + if (sound->id.properties) IDP_WriteProperty(sound->id.properties, wd); + + if (sound->newpackedfile) { + pf = sound->newpackedfile; + writestruct(wd, DATA, "PackedFile", 1, pf); + writedata(wd, DATA, pf->size, pf->data); + } + + if (sample) { + sound->newpackedfile = sample->packedfile; + } + } + sound= sound->id.next; + } + + /* flush helps the compression for undo-save */ + mywrite(wd, MYWRITE_FLUSH, 0); +} + +static void write_groups(WriteData *wd, ListBase *idbase) +{ + Group *group; + GroupObject *go; + + for(group= idbase->first; group; group= group->id.next) { + if(group->id.us>0 || wd->current) { + /* write LibData */ + writestruct(wd, ID_GR, "Group", 1, group); + if (group->id.properties) IDP_WriteProperty(group->id.properties, wd); + + go= group->gobject.first; + while(go) { + writestruct(wd, DATA, "GroupObject", 1, go); + go= go->next; + } + } + } +} + +static void write_nodetrees(WriteData *wd, ListBase *idbase) +{ + bNodeTree *ntree; + + for(ntree=idbase->first; ntree; ntree= ntree->id.next) { + if (ntree->id.us>0 || wd->current) { + writestruct(wd, ID_NT, "bNodeTree", 1, ntree); + write_nodetree(wd, ntree); + if (ntree->id.properties) IDP_WriteProperty(ntree->id.properties, wd); + } + } +} + +static void write_brushes(WriteData *wd, ListBase *idbase) +{ + Brush *brush; + int a; + + for(brush=idbase->first; brush; brush= brush->id.next) { + if(brush->id.us>0 || wd->current) { + writestruct(wd, ID_BR, "Brush", 1, brush); + if (brush->id.properties) IDP_WriteProperty(brush->id.properties, wd); + for(a=0; amtex[a]) + writestruct(wd, DATA, "MTex", 1, brush->mtex[a]); + } + } +} + +static void write_global(WriteData *wd) +{ + FileGlobal fg; + char subvstr[8]; + + fg.curscreen= G.curscreen; + fg.curscene= G.scene; + fg.displaymode= G.displaymode; + fg.winpos= G.winpos; + fg.fileflags= (G.fileflags & ~G_FILE_NO_UI); // prevent to save this, is not good convention, and feature with concerns... + fg.globalf= G.f; + + sprintf(subvstr, "%4d", BLENDER_SUBVERSION); + memcpy(fg.subvstr, subvstr, 4); + + fg.subversion= BLENDER_SUBVERSION; + fg.minversion= BLENDER_MINVERSION; + fg.minsubversion= BLENDER_MINSUBVERSION; + + writestruct(wd, GLOB, "FileGlobal", 1, &fg); +} + +/* if MemFile * there's filesave to memory */ +static int write_file_handle(int handle, MemFile *compare, MemFile *current, int write_user_block, int write_flags) +{ + BHead bhead; + ListBase mainlist; + char buf[16]; + WriteData *wd; + + blo_split_main(&mainlist, G.main); + + wd= bgnwrite(handle, compare, current, write_flags); + + sprintf(buf, "BLENDER%c%c%.3d", (sizeof(void*)==8)?'-':'_', (G.order==B_ENDIAN)?'V':'v', G.version); + mywrite(wd, buf, 12); + + write_renderinfo(wd); + write_global(wd); + + if(current==NULL) + write_screens (wd, &G.main->screen); /* no UI save in undo */ + write_scenes (wd, &G.main->scene); + write_curves (wd, &G.main->curve); + write_mballs (wd, &G.main->mball); + write_images (wd, &G.main->image); + write_cameras (wd, &G.main->camera); + write_lamps (wd, &G.main->lamp); + write_lattices (wd, &G.main->latt); + write_vfonts (wd, &G.main->vfont); + write_ipos (wd, &G.main->ipo); + write_keys (wd, &G.main->key); + write_worlds (wd, &G.main->world); + write_texts (wd, &G.main->text); + write_sounds (wd, &G.main->sound); + write_groups (wd, &G.main->group); + write_armatures(wd, &G.main->armature); + write_actions (wd, &G.main->action); + write_objects (wd, &G.main->object); + write_materials(wd, &G.main->mat); + write_textures (wd, &G.main->tex); + write_meshs (wd, &G.main->mesh); + write_nodetrees(wd, &G.main->nodetree); + write_brushes (wd, &G.main->brush); + if(current==NULL) + write_libraries(wd, G.main->next); /* no library save in undo */ + + if (write_user_block) { + write_userdef(wd); + } + + /* dna as last, because (to be implemented) test for which structs are written */ + writedata(wd, DNA1, wd->sdna->datalen, wd->sdna->data); + + /* end of file */ + memset(&bhead, 0, sizeof(BHead)); + bhead.code= ENDB; + mywrite(wd, &bhead, sizeof(BHead)); + + blo_join_main(&mainlist); + G.main= mainlist.first; + + return endwrite(wd); +} + +/* return: success (1) */ +int BLO_write_file(char *dir, int write_flags, char **error_r) +{ + char userfilename[FILE_MAXDIR+FILE_MAXFILE]; + char tempname[FILE_MAXDIR+FILE_MAXFILE]; + int file, err, write_user_block; + + sprintf(tempname, "%s@", dir); + + file = open(tempname,O_BINARY+O_WRONLY+O_CREAT+O_TRUNC, 0666); + if(file == -1) { + *error_r= "Unable to open"; + return 0; + } + + BLI_make_file_string(G.sce, userfilename, BLI_gethome(), ".B.blend"); + + write_user_block= BLI_streq(dir, userfilename); + + err= write_file_handle(file, NULL,NULL, write_user_block, write_flags); + close(file); + + if(!err) { + if(write_flags & G_FILE_COMPRESS) + { + // compressed files have the same ending as regular files... only from 2.4!!! + + int ret = BLI_gzip(tempname, dir); + + if(-1==ret) { + *error_r= "Failed opening .gz file"; + return 0; + } + if(-2==ret) { + *error_r= "Failed opening .blend file for compression"; + return 0; + } + } + else + if(BLI_rename(tempname, dir) < 0) { + *error_r= "Can't change old file. File saved with @"; + return 0; + } + + + } else { + *error_r= strerror(errno); + remove(tempname); + + return 0; + } + + return 1; +} + +/* return: success (1) */ +int BLO_write_file_mem(MemFile *compare, MemFile *current, int write_flags, char **error_r) +{ + int err; + + err= write_file_handle(0, compare, current, 0, write_flags); + + if(err==0) return 1; + return 0; +} + + + /* Runtime writing */ + +#ifdef WIN32 +#define PATHSEPERATOR "\\" +#else +#define PATHSEPERATOR "/" +#endif + +static char *get_install_dir(void) { + extern char bprogname[]; + char *tmpname = BLI_strdup(bprogname); + char *cut; + +#ifdef __APPLE__ + cut = strstr(tmpname, ".app"); + if (cut) cut[0] = 0; +#endif + + cut = BLI_last_slash(tmpname); + + if (cut) { + cut[0] = 0; + return tmpname; + } else { + MEM_freeN(tmpname); + return NULL; + } +} + +static char *get_runtime_path(char *exename) { + char *installpath= get_install_dir(); + + if (!installpath) { + return NULL; + } else { + char *path= MEM_mallocN(strlen(installpath)+strlen(PATHSEPERATOR)+strlen(exename)+1, "runtimepath"); + + if (path == NULL) { + MEM_freeN(installpath); + return NULL; + } + + strcpy(path, installpath); + strcat(path, PATHSEPERATOR); + strcat(path, exename); + + MEM_freeN(installpath); + + return path; + } +} + +#ifdef __APPLE__ + +static int recursive_copy_runtime(char *outname, char *exename, char **cause_r) +{ + char *cause = NULL, *runtime = get_runtime_path(exename); + char command[2 * (FILE_MAXDIR+FILE_MAXFILE) + 32]; + int progfd = -1; + + if (!runtime) { + cause= "Unable to find runtime"; + goto cleanup; + } + //printf("runtimepath %s\n", runtime); + + progfd= open(runtime, O_BINARY|O_RDONLY, 0); + if (progfd==-1) { + cause= "Unable to find runtime"; + goto cleanup; + } + + sprintf(command, "/bin/cp -R \"%s\" \"%s\"", runtime, outname); + //printf("command %s\n", command); + if (system(command) == -1) { + cause = "Couldn't copy runtime"; + } + +cleanup: + if (progfd!=-1) + close(progfd); + if (runtime) + MEM_freeN(runtime); + + if (cause) { + *cause_r= cause; + return 0; + } else + return 1; +} + +void BLO_write_runtime(char *file, char *exename) { + char gamename[FILE_MAXDIR+FILE_MAXFILE]; + int outfd = -1; + char *cause= NULL; + + // remove existing file / bundle + //printf("Delete file %s\n", file); + BLI_delete(file, 0, TRUE); + + if (!recursive_copy_runtime(file, exename, &cause)) + goto cleanup; + + strcpy(gamename, file); + strcat(gamename, "/Contents/Resources/game.blend"); + //printf("gamename %s\n", gamename); + outfd= open(gamename, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0777); + if (outfd != -1) { + + write_file_handle(outfd, NULL,NULL, 0, G.fileflags); + + if (write(outfd, " ", 1) != 1) { + cause= "Unable to write to output file"; + goto cleanup; + } + } else { + cause = "Unable to open blenderfile"; + } + +cleanup: + if (outfd!=-1) + close(outfd); + + if (cause) + error("Unable to make runtime: %s", cause); +} + +#else /* !__APPLE__ */ + +static int handle_append_runtime(int handle, char *exename, char **cause_r) { + char *cause= NULL, *runtime= get_runtime_path(exename); + unsigned char buf[1024]; + int count, progfd= -1; + + if (!runtime) { + cause= "Unable to find runtime"; + goto cleanup; + } + + progfd= open(runtime, O_BINARY|O_RDONLY, 0); + if (progfd==-1) { + cause= "Unable to find runtime"; + goto cleanup; + } + + while ((count= read(progfd, buf, sizeof(buf)))>0) { + if (write(handle, buf, count)!=count) { + cause= "Unable to write to output file"; + goto cleanup; + } + } + +cleanup: + if (progfd!=-1) + close(progfd); + if (runtime) + MEM_freeN(runtime); + + if (cause) { + *cause_r= cause; + return 0; + } else + return 1; +} + +static int handle_write_msb_int(int handle, int i) { + unsigned char buf[4]; + buf[0]= (i>>24)&0xFF; + buf[1]= (i>>16)&0xFF; + buf[2]= (i>>8)&0xFF; + buf[3]= (i>>0)&0xFF; + + return (write(handle, buf, 4)==4); +} + +void BLO_write_runtime(char *file, char *exename) { + int outfd= open(file, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0777); + char *cause= NULL; + int datastart; + + if (!outfd) { + cause= "Unable to open output file"; + goto cleanup; + } + if (!handle_append_runtime(outfd, exename, &cause)) + goto cleanup; + + datastart= lseek(outfd, 0, SEEK_CUR); + + write_file_handle(outfd, NULL,NULL, 0, G.fileflags); + + if (!handle_write_msb_int(outfd, datastart) || (write(outfd, "BRUNTIME", 8)!=8)) { + cause= "Unable to write to output file"; + goto cleanup; + } + +cleanup: + if (outfd!=-1) + close(outfd); + + if (cause) + error("Unable to make runtime: %s", cause); +} + +#endif /* !__APPLE__ */ diff --git a/source/blender/blenpluginapi/CMakeLists.txt b/source/blender/blenpluginapi/CMakeLists.txt new file mode 100644 index 00000000000..2afd3ebb121 --- /dev/null +++ b/source/blender/blenpluginapi/CMakeLists.txt @@ -0,0 +1,42 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +FILE(GLOB SRC intern/*.c) + +SET(INC + . .. ../../../intern/guardedalloc ../blenlib ../imbuf ../makesdna +) + +IF(WITH_QUICKTIME) + SET(INC ${INC} ${QUICKTIME_INC}) + ADD_DEFINITIONS(-DWITH_QUICKTIME) +ENDIF(WITH_QUICKTIME) + +BLENDERLIB(bf_blenpluginapi "${SRC}" "${INC}") +#env.BlenderLib ( libname = 'bf_blenpluginapi', sources = sources, includes = Split(incs), defines = defs, libtype=['core', 'player'], priority = [75, 35] ) diff --git a/source/blender/blenpluginapi/Makefile b/source/blender/blenpluginapi/Makefile new file mode 100644 index 00000000000..17c23c419a8 --- /dev/null +++ b/source/blender/blenpluginapi/Makefile @@ -0,0 +1,37 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# Bounces make to subdirectories. + +SOURCEDIR = source/blender/blenpluginapi +DIRS = intern + +include nan_subdirs.mk diff --git a/source/blender/blenpluginapi/SConscript b/source/blender/blenpluginapi/SConscript new file mode 100644 index 00000000000..d17a35e933e --- /dev/null +++ b/source/blender/blenpluginapi/SConscript @@ -0,0 +1,14 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.c') + +incs = '. .. #/intern/guardedalloc ../blenlib ../imbuf ../makesdna' + +defs = [] + +if env['WITH_BF_QUICKTIME'] == 1: + defs.append('WITH_QUICKTIME') + incs += ' ' + env['BF_QUICKTIME_INC'] + +env.BlenderLib ( libname = 'bf_blenpluginapi', sources = sources, includes = Split(incs), defines = defs, libtype=['core', 'player'], priority = [75, 35] ) diff --git a/source/blender/blenpluginapi/documentation.h b/source/blender/blenpluginapi/documentation.h new file mode 100644 index 00000000000..3bb9b33ee04 --- /dev/null +++ b/source/blender/blenpluginapi/documentation.h @@ -0,0 +1,72 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + * @mainpage plugin API - the access point for texture and sequence + * plugins + * + * @section about About the plugin API + * + * This API wraps functions that are used by texture and sequence + * plugins. They are explicitly wrapped in order to make the + * dependencies to the rest of the system clear. + * + * @section issues Known issues with the plugin API + * + * - It can be difficult at times to get access to the API functions + * linked into the final executable. On gcc, the -fpic and -shared + * flags take care of this. On Irix, -shared is needed, but you also + * need a reference to the function to get the handle. This has + * momentarily been taken care of by pluginapi_force_ref(). + * + * - Plugins need to define three functions that are needed for + * version bookkeeping and information. The plugin loading code + * explicitly checks for these functions. The nanes depend on whether + * it is a texture or sequence plugin. + * + * - The plugin loading occurs in sequence.c and texture.c. The + * following functions are involved: + * - open_plugin_seq() (used in readfile.c, editseq.c, sequence.c) + * - add_plugin_seq() (used in editseq.c, sequence.c) + * - free_plugin_seq() (used in editseq.c, sequence.c) + * - open_plugin_tex() (used in texture.c, readfile.c) + * - add_plugin_tex() (used in texture.c, buttons.c) + * - free_plugin_tex() (used in texture.c, buttons.c) + * - test_dlerr() (used in texture.c, sequence.c) + * Since the plugins are about to phase out, we will not sanitize this + * code. It will be removed as soon as the replacing system is in + * place. + * + * @section dependencies Dependencies + * + * The plugins wraps functions from IMB and BLI. In addition, they + * define some useful variables. + * */ + diff --git a/source/blender/blenpluginapi/externdef.h b/source/blender/blenpluginapi/externdef.h new file mode 100644 index 00000000000..7322841e608 --- /dev/null +++ b/source/blender/blenpluginapi/externdef.h @@ -0,0 +1,43 @@ +/* Copyright (c) 1999, Not a Number / NeoGeo b.v. + * + * All rights reserved. + * + * Contact: info@blender.org + * Information: http://www.blender.org + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#ifndef _EXTERNDEF_H +#define _EXTERNDEF_H + +#ifdef WIN32 + #ifdef PLUGIN_INTERN + #define LIBEXPORT __declspec(dllexport) + #else + #define LIBEXPORT extern __declspec(dllimport) + #endif +#elif !defined(WIN32) + #define LIBEXPORT extern +#endif + +#endif /* _EXTERNDEF_H */ diff --git a/source/blender/blenpluginapi/floatpatch.h b/source/blender/blenpluginapi/floatpatch.h new file mode 100644 index 00000000000..8e6fab8a363 --- /dev/null +++ b/source/blender/blenpluginapi/floatpatch.h @@ -0,0 +1,90 @@ +/* Copyright (c) 1999, Not a Number / NeoGeo b.v. + * $Id$ + * + * All rights reserved. + * + * Contact: info@blender.org + * Information: http://www.blender.org + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#ifndef FLOATPATCH_H +#define FLOATPATCH_H + +/* floating point libs differ at systems... with these defines it comilies at all! */ + +#ifdef MIPS1 +#else + +#define fabsf(a) fabs((double)(a)) + +#define facos acosf +#define acosf(a) acos((double)(a)) + +#define fasin asinf +#define asinf(a) asin((double)(a)) + +#define fatan atanf +#define atanf(a) atan((double)(a)) + +#define fatan2 atan2f +#define atan2f(a, b) atan2((double)(a), (double)(b)) + +#define fmodf(a, b) fmod((double)(a), (double)(b)) + +#define fcos cosf +#define cosf(a) cos((double)(a)) + +#define fsin sinf +#define sinf(a) sin((double)(a)) + +#define ftan tanf +#define tanf(a) tan((double)(a)) + +#define fexp expf +#define expf(a) exp((double)(a)) + +#define flog logf +#define logf(a) log((double)(a)) + +#define flog10 log10f +#define log10f(a) log10((double)(a)) + +#define fsqrt sqrtf +#define sqrtf(a) sqrt((double)(a)) + +#define fceil ceilf +#define ceilf(a) ceil((double)(a)) + +#define ffloor floorf +#define floorf(a) floor((double)(a)) + +#define fpow powf +#define powf(a, b) pow((double)(a), (double)(b)) + +/* #endif */ + +#endif + +#endif /* FLOATPATCH_H */ + diff --git a/source/blender/blenpluginapi/iff.h b/source/blender/blenpluginapi/iff.h new file mode 100644 index 00000000000..5eb52158a1a --- /dev/null +++ b/source/blender/blenpluginapi/iff.h @@ -0,0 +1,215 @@ +/* Copyright (c) 1999, Not a Number / NeoGeo b.v. + * $Id$ + * + * All rights reserved. + * + * Contact: info@blender.org + * Information: http://www.blender.org + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#ifndef IFF_H +#define IFF_H + +#include +#include "util.h" +#include "externdef.h" + +#define IB_rect (1 << 0) +#define IB_planes (1 << 1) +#define IB_cmap (1 << 2) +#define IB_test (1 << 7) + +#define IB_fields (1 << 11) +#define IB_yuv (1 << 12) +#define IB_zbuf (1 << 13) +#define IB_rgba (1 << 14) + +#define AMI (1 << 31) +#define PNG (1 << 30) +#define Anim (1 << 29) +#define TGA (1 << 28) +#define JPG (1 << 27) +#define BMP (1 << 26) +#ifdef WITH_QUICKTIME +#define QUICKTIME (1 << 25) +#endif +#define RADHDR (1<<24) + +#define RAWTGA (TGA | 1) + +#define JPG_STD (JPG | (0 << 8)) +#define JPG_VID (JPG | (1 << 8)) +#define JPG_JST (JPG | (2 << 8)) +#define JPG_MAX (JPG | (3 << 8)) +#define JPG_MSK (0xffffff00) + +#define AM_ham (0x0800 | AMI) +#define AM_hbrite (0x0080 | AMI) +#define AM_lace (0x0004 | AMI) +#define AM_hires (0x8000 | AMI) +#define AM_hblace (AM_hbrite | AM_lace) +#define AM_hilace (AM_hires | AM_lace) +#define AM_hamlace (AM_ham | AM_lace) + +#define RGB888 1 +#define RGB555 2 +#define DYUV 3 +#define CLUT8 4 +#define CLUT7 5 +#define CLUT4 6 +#define CLUT3 7 +#define RL7 8 +#define RL3 9 +#define MPLTE 10 + +#define DYUV1 0 +#define C233 1 +#define YUVX 2 +#define HAMX 3 +#define TANX 4 + +#define AN_c233 (Anim | C233) +#define AN_yuvx (Anim | YUVX) +#define AN_hamx (Anim | HAMX) +#define AN_tanx (Anim | TANX) + +#define IS_amiga(x) (x->ftype & AMI) +#define IS_ham(x) ((x->ftype & AM_ham) == AM_ham) +#define IS_hbrite(x) ((x->ftype & AM_hbrite) == AM_hbrite) + +#define IS_lace(x) ((x->ftype & AM_lace) == AM_lace) +#define IS_hires(x) ((x->ftype & AM_hires) == AM_hires) +#define IS_hblace(x) ((x->ftype & AM_hblace) == AM_hblace) +#define IS_hilace(x) ((x->ftype & AM_hilace) == AM_hilace) +#define IS_hamlace(x) ((x->ftype & AM_hamlace) == AM_hamlace) + +#define IS_anim(x) (x->ftype & Anim) +#define IS_hamx(x) (x->ftype == AN_hamx) +#define IS_tga(x) (x->ftype & TGA) +#define IS_png(x) (x->ftype & PNG) +#define IS_bmp(x) (x->ftype & BMP) +#define IS_radhdr(x) (x->ftype & RADHDR) +#define IS_tim(x) (x->ftype & TIM) +#define IS_tiff(x) (x->ftype & TIFF) +#define IS_openexr(x) (x->ftype & OPENEXR) + + +#define IMAGIC 0732 +#define IS_iris(x) (x->ftype == IMAGIC) + +#define IS_jpg(x) (x->ftype & JPG) +#define IS_stdjpg(x) ((x->ftype & JPG_MSK) == JPG_STD) +#define IS_vidjpg(x) ((x->ftype & JPG_MSK) == JPG_VID) +#define IS_jstjpg(x) ((x->ftype & JPG_MSK) == JPG_JST) +#define IS_maxjpg(x) ((x->ftype & JPG_MSK) == JPG_MAX) + +#define AN_INIT an_stringdec = stringdec; an_stringenc = stringenc; + +#define IB_MIPMAP_LEVELS 10 + +struct MEM_CacheLimiterHandle_s; + +typedef struct ImBuf { + struct ImBuf *next, *prev; /**< allow lists of ImBufs, for caches or flipbooks */ + short x, y; /**< width and Height of our image buffer */ + short skipx; /**< Width in ints to get to the next scanline */ + unsigned char depth; /**< Active amount of bits/bitplanes */ + unsigned char cbits; /**< Amount of active bits in cmap */ + unsigned short mincol; /**< smallest color in colormap */ + unsigned short maxcol; /**< Largest color in colormap */ + int type; /**< 0=abgr, 1=bitplanes */ + int ftype; /**< File type we are going to save as */ + unsigned int *cmap; /**< Color map data. */ + unsigned int *rect; /**< pixel values stored here */ + unsigned int **planes; /**< bitplanes */ + int flags; /**< Controls which components should exist. */ + int mall; /**< what is malloced internal, and can be freed */ + short xorig, yorig; /**< Cordinates of first pixel of an image used in some formats (example: targa) */ + char name[1023]; /**< The file name assocated with this image */ + char namenull; /**< Unused don't want to remove it thought messes things up */ + int userflags; /**< Used to set imbuf to Dirty and other stuff */ + int *zbuf; /**< z buffer data, original zbuffer */ + float *zbuf_float; /**< z buffer data, camera coordinates */ + void *userdata; + unsigned char *encodedbuffer; /**< Compressed image only used with png currently */ + unsigned int encodedsize; /**< Size of data written to encodedbuffer */ + unsigned int encodedbuffersize; /**< Size of encodedbuffer */ + + float *rect_float; /**< floating point Rect equivilant */ + int channels; /**< amount of channels in rect_float (0 = 4 channel default) */ + float dither; /**< random dither value, for conversion from float -> byte rect */ + + struct MEM_CacheLimiterHandle_s * c_handle; /**< handle for cache limiter */ + int refcounter; /**< Refcounter for multiple users */ + int index; /**< reference index for ImBuf lists */ + + struct ImBuf *mipmap[IB_MIPMAP_LEVELS]; /**< MipMap levels, a series of halved images */ +} ImBuf; + +LIBEXPORT struct ImBuf *allocImBuf(short,short,uchar,uint,uchar); +LIBEXPORT struct ImBuf *dupImBuf(struct ImBuf *); +LIBEXPORT void freeImBuf(struct ImBuf*); + +LIBEXPORT short converttocmap(struct ImBuf* ibuf); + +LIBEXPORT short saveiff(struct ImBuf *,char *,int); + +LIBEXPORT struct ImBuf *loadiffmem(int *,int); +LIBEXPORT struct ImBuf *loadifffile(int,int); +LIBEXPORT struct ImBuf *loadiffname(char *,int); +LIBEXPORT struct ImBuf *testiffname(char *,int); + +LIBEXPORT struct ImBuf *onehalf(struct ImBuf *); +LIBEXPORT struct ImBuf *onethird(struct ImBuf *); +LIBEXPORT struct ImBuf *halflace(struct ImBuf *); +LIBEXPORT struct ImBuf *half_x(struct ImBuf *); +LIBEXPORT struct ImBuf *half_y(struct ImBuf *); +LIBEXPORT struct ImBuf *double_x(struct ImBuf *); +LIBEXPORT struct ImBuf *double_y(struct ImBuf *); +LIBEXPORT struct ImBuf *double_fast_x(struct ImBuf *); +LIBEXPORT struct ImBuf *double_fast_y(struct ImBuf *); + +LIBEXPORT int ispic(char *); + +LIBEXPORT void dit2(struct ImBuf *, short, short); +LIBEXPORT void dit0(struct ImBuf *, short, short); + +LIBEXPORT struct ImBuf *scaleImBuf(struct ImBuf *, short, short); +LIBEXPORT struct ImBuf *scalefastImBuf(struct ImBuf *, short, short); +LIBEXPORT struct ImBuf *scalefieldImBuf(struct ImBuf *, short, short); +LIBEXPORT struct ImBuf *scalefastfieldImBuf(struct ImBuf *, short, short); + +LIBEXPORT void de_interlace(struct ImBuf *ib); +LIBEXPORT void interlace(struct ImBuf *ib); +LIBEXPORT void gamwarp(struct ImBuf *ibuf, double gamma); + +LIBEXPORT void IMB_rectcpy(struct ImBuf *dbuf, struct ImBuf *sbuf, + int destx, int desty, int srcx, int srcy, int width, int height); + +LIBEXPORT void IMB_rectfill(struct ImBuf *drect, float col[4]); +LIBEXPORT void IMB_rectfill_area(struct ImBuf *ibuf, float *col, int x1, int y1, int x2, int y2); +LIBEXPORT void buf_rectfill_area(unsigned char *rect, float *rectf, int width, int height, float *col, int x1, int y1, int x2, int y2); + +#endif /* IFF_H */ + diff --git a/source/blender/blenpluginapi/intern/Makefile b/source/blender/blenpluginapi/intern/Makefile new file mode 100644 index 00000000000..e493ea40aa5 --- /dev/null +++ b/source/blender/blenpluginapi/intern/Makefile @@ -0,0 +1,57 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = blenpluginapi +DIR = $(OCGDIR)/blender/$(LIBNAME) + +include nan_compile.mk + +ifeq ($(OS),$(findstring $(OS), "beos darwin freebsd linux openbsd solaris")) + CFLAGS += -shared +endif + +CFLAGS += $(LEVEL_1_C_WARNINGS) + +# path to our own external headerfiles. On win2k this needs to be +# longer, to avoid the util.h include problem +CPPFLAGS += -I.. +CPPFLAGS += -I../.. + +# also do dna +CPPFLAGS += -I../../makesdna +# path to blenlib +CPPFLAGS += -I../../blenlib +# path to imbuf +CPPFLAGS += -I../../imbuf +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include + diff --git a/source/blender/blenpluginapi/intern/pluginapi.c b/source/blender/blenpluginapi/intern/pluginapi.c new file mode 100644 index 00000000000..43c4727cea1 --- /dev/null +++ b/source/blender/blenpluginapi/intern/pluginapi.c @@ -0,0 +1,365 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * Wrappers for the plugin api. This api is up for removal. + */ + +/* There are four headers making up the plugin api: + * - floatpatch.h : Wraps math functions for mips platforms, no code + * required. + * - iff.h : Defines, macros and functions for dealing + * with image buffer things. + * - plugin.h : Wraps some plugin handling types, accesses noise + * functions. + * - util.h : Useful defines, memory management. + */ + +#define PLUGIN_INTERN /* This tells the LIBEXPORT macro to compile with + dll export set on windows */ + +#ifdef WIN32 +#include "blenpluginapi/util.h" +#else +#include "blenpluginapi/util.h" +#endif +#include "iff.h" +#include "plugin.h" +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" /* util and noise functions */ +#include "BLI_threads.h" /* For threadsfe guardedalloc malloc/calloc/free */ +#include "IMB_imbuf.h" /* image buffer stuff */ + +/* -------------------------------------------------------------------------- */ +/* stuff from util.h */ +/* -------------------------------------------------------------------------- */ + +LIBEXPORT void *mallocN(int len, char *str) +{ + return MEM_mallocN(len, str); +} + +LIBEXPORT void *callocN(int len, char *str) +{ + return MEM_callocN(len, str); +} + +LIBEXPORT short freeN(void *vmemh) +{ + return MEM_freeN(vmemh); +} + +/* these are not needed anymore, mallocN/callocN/freeN is now threadsafe */ +LIBEXPORT void *mallocT(int len, char *str) +{ + return MEM_mallocN(len, str); +} + +LIBEXPORT void *callocT(int len, char *str) +{ + return MEM_callocN(len, str); +} + +LIBEXPORT void freeT(void *vmemh) +{ + MEM_freeN(vmemh); + return; +} + + +/* -------------------------------------------------------------------------- */ +/* stuff from iff.h */ +/* -------------------------------------------------------------------------- */ + +LIBEXPORT struct ImBuf *allocImBuf(short x, + short y, + uchar d, + uint flags, + uchar bitmap) +{ + return IMB_allocImBuf(x, y, d, flags, bitmap); +} + + +LIBEXPORT struct ImBuf *dupImBuf(struct ImBuf *ib) +{ + return IMB_dupImBuf(ib); +} + +LIBEXPORT void freeImBuf(struct ImBuf* ib) +{ + IMB_freeImBuf(ib); +} + +LIBEXPORT short converttocmap(struct ImBuf* ibuf) +{ + return IMB_converttocmap(ibuf); +} + +LIBEXPORT short saveiff(struct ImBuf *ib, + char *c, + int i) +{ + return IMB_saveiff(ib, c, i); +} + +LIBEXPORT struct ImBuf *loadiffmem(int *mem,int flags) +{ + return IMB_loadiffmem(mem, flags); +} + +LIBEXPORT struct ImBuf *loadifffile(int a, + int b) +{ + return IMB_loadifffile(a, b); +} + +LIBEXPORT struct ImBuf *loadiffname(char *n, + int flags) +{ + return IMB_loadiffname(n, flags); +} + +LIBEXPORT struct ImBuf *testiffname(char *n, + int flags) +{ + return IMB_testiffname(n, flags); +} + +LIBEXPORT struct ImBuf *onehalf(struct ImBuf *ib) +{ + return IMB_onehalf(ib); +} + +LIBEXPORT struct ImBuf *onethird(struct ImBuf *ib) +{ + return IMB_onethird(ib); +} + +LIBEXPORT struct ImBuf *halflace(struct ImBuf *ib) +{ + return IMB_halflace(ib); +} + +LIBEXPORT struct ImBuf *half_x(struct ImBuf *ib) +{ + return IMB_half_x(ib); +} + +LIBEXPORT struct ImBuf *half_y(struct ImBuf *ib) +{ + return IMB_half_y(ib); +} + +LIBEXPORT struct ImBuf *double_x(struct ImBuf *ib) +{ + return IMB_double_x(ib); +} + +LIBEXPORT struct ImBuf *double_y(struct ImBuf *ib) +{ + return IMB_double_y(ib); +} + +LIBEXPORT struct ImBuf *double_fast_x(struct ImBuf *ib) +{ + return IMB_double_fast_x(ib); +} + +LIBEXPORT struct ImBuf *double_fast_y(struct ImBuf *ib) +{ + return IMB_double_fast_y(ib); +} + +LIBEXPORT int ispic(char * name) +{ + return IMB_ispic(name); +} + +LIBEXPORT void dit2(struct ImBuf *ib, + short a, + short b) +{ + IMB_dit2(ib, a, b); +} + +LIBEXPORT void dit0(struct ImBuf *ib, + short a, + short b) +{ + IMB_dit0(ib, a, b); +} + +/* still the same name */ +/* void (*ditherfunc)(struct ImBuf *, short, short){} */ + +LIBEXPORT struct ImBuf *scaleImBuf(struct ImBuf *ib, + short nx, + short ny) +{ + return IMB_scaleImBuf(ib, nx, ny); +} + +LIBEXPORT struct ImBuf *scalefastImBuf(struct ImBuf *ib, + short x, + short y) +{ + return IMB_scalefastImBuf(ib, x, y); +} + + +LIBEXPORT struct ImBuf *scalefieldImBuf(struct ImBuf *ib, + short x, + short y) +{ + return IMB_scalefieldImBuf(ib, x, y); +} + +LIBEXPORT struct ImBuf *scalefastfieldImBuf(struct ImBuf *ib, + short x, + short y) +{ + return IMB_scalefastfieldImBuf(ib, x, y); +} + + /* Extra ones that some NaN (read Ton) plugins use, + * even though they aren't in the header + */ + +LIBEXPORT void interlace(struct ImBuf *ibuf) +{ + IMB_interlace(ibuf); +} + +LIBEXPORT void gamwarp(struct ImBuf *ibuf, double gamma) +{ + IMB_gamwarp(ibuf,gamma); +} + +LIBEXPORT void de_interlace(struct ImBuf *ib) +{ + IMB_de_interlace(ib); +} + +/* -------------------------------------------------------------------------- */ +/* stuff from plugin.h */ +/* -------------------------------------------------------------------------- */ + +/* These three need to be defined in the plugion itself. The plugin + * loader looks for these functions to check whether it can use the + * plugin. For sequences, something similar exists. */ +/* int plugin_tex_getversion(void); */ +/* int plugin_seq_getversion(void); */ +/* void plugin_getinfo(PluginInfo *); */ + +LIBEXPORT float hnoise(float noisesize, + float x, + float y, + float z) +{ + return BLI_hnoise(noisesize, x, y, z); +} + +LIBEXPORT float hnoisep(float noisesize, + float x, + float y, + float z) +{ + return BLI_hnoisep(noisesize, x, y, z); +} + +LIBEXPORT float turbulence(float noisesize, + float x, + float y, + float z, + int depth) +{ + return BLI_turbulence(noisesize, x, y, z, depth); +} + +LIBEXPORT float turbulence1(float noisesize, + float x, + float y, + float z, + int depth) +{ + return BLI_turbulence1(noisesize, x, y, z, depth); +} + +/* -------------------------------------------------------------------------- */ + + /* Stupid hack - force the inclusion of all of the + * above functions in the binary by 'using' each one... + * Otherwise they will not be imported from the archive + * library on Unix. -zr + */ +int pluginapi_force_ref(void); + +int pluginapi_force_ref(void) +{ + return (int) mallocN + + (int) callocN + + (int) freeN + + (int) mallocT + + (int) callocT + + (int) freeT + + (int) allocImBuf + + (int) dupImBuf + + (int) freeImBuf + + (int) converttocmap + + (int) saveiff + + (int) loadiffmem + + (int) loadifffile + + (int) loadiffname + + (int) testiffname + + (int) onehalf + + (int) onethird + + (int) halflace + + (int) half_x + + (int) half_y + + (int) double_x + + (int) double_y + + (int) double_fast_x + + (int) double_fast_y + + (int) ispic + + (int) dit2 + + (int) dit0 + + (int) scaleImBuf + + (int) scalefastImBuf + + (int) scalefieldImBuf + + (int) scalefastfieldImBuf + + (int) hnoise + + (int) hnoisep + + (int) turbulence + + (int) turbulence1 + + (int) de_interlace + + (int) interlace + + (int) gamwarp; +} diff --git a/source/blender/blenpluginapi/plugin.DEF b/source/blender/blenpluginapi/plugin.DEF new file mode 100644 index 00000000000..ae2692c7cff --- /dev/null +++ b/source/blender/blenpluginapi/plugin.DEF @@ -0,0 +1,40 @@ +LIBRARY +EXPORTS +mallocN +callocN +freeN +mallocT +callocT +freeT +hnoise +hnoisep +turbulence +turbulence1 +allocImBuf +dupImBuf +freeImBuf +converttocmap +saveiff +loadiffmem +loadifffile +loadiffname +testiffname +onehalf +onethird +halflace +half_x +half_y +double_x +double_y +double_fast_x +double_fast_y +ispic +dit2 +dit0 +scaleImBuf +scalefastImBuf +scalefieldImBuf +scalefastfieldImBuf +de_interlace +interlace +gamwarp diff --git a/source/blender/blenpluginapi/plugin.h b/source/blender/blenpluginapi/plugin.h new file mode 100644 index 00000000000..1f6140130eb --- /dev/null +++ b/source/blender/blenpluginapi/plugin.h @@ -0,0 +1,103 @@ +/* Copyright (c) 1999, Not a Number / NeoGeo b.v. + * $Id$ + * + * All rights reserved. + * + * Contact: info@blender.org + * Information: http://www.blender.org + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#ifndef PLUGIN_H +#define PLUGIN_H + +#include "externdef.h" +#include "iff.h" +#include "util.h" +#include "floatpatch.h" + +#define B_PLUGIN_VERSION 5 + +typedef int (*TexDoit)(int, void*, float*, float*, float*); +typedef void (*SeqDoit)(void*, float, float, int, int, ImBuf*, ImBuf*, ImBuf*, ImBuf*); + +typedef struct VarStruct { + int type; + char name[16]; + float def, min, max; + char tip[80]; +} VarStruct; + +typedef struct _PluginInfo { + char *name; + char *snames; + + int stypes; + int nvars; + VarStruct *varstr; + float *result; + float *cfra; + + void (*init)(void); + void (*callback)(int); + TexDoit tex_doit; + SeqDoit seq_doit; + + void (*instance_init)(void *); +} PluginInfo; + +int plugin_tex_getversion(void); +int plugin_seq_getversion(void); +void plugin_getinfo(PluginInfo *); + +/* *************** defines for button types ************** */ + +#define CHA 32 +#define INT 96 +#define FLO 128 + +#define TOG (3<<9) +#define NUM (5<<9) +#define LABEL (10<<9) +#define NUMSLI (14<<9) +#define COL (15<<9) + +/* return values (bitfield like) for textures (DNA_texture_types.h) */ +#define TEX_INT 0 +#define TEX_RGB 1 +#define TEX_NOR 2 + +/* *************** API functions ******************** */ + + /* derived from the famous Perlin noise */ +LIBEXPORT float hnoise(float noisesize, float x, float y, float z); + /* the original Perlin noise */ +LIBEXPORT float hnoisep(float noisesize, float x, float y, float z); + + /* soft turbulence */ +LIBEXPORT float turbulence(float noisesize, float x, float y, float z, int depth); + /* hard turbulence */ +LIBEXPORT float turbulence1(float noisesize, float x, float y, float z, int depth); + +#endif /* PLUGIN_H */ + diff --git a/source/blender/blenpluginapi/util.h b/source/blender/blenpluginapi/util.h new file mode 100644 index 00000000000..b0b5f3aae54 --- /dev/null +++ b/source/blender/blenpluginapi/util.h @@ -0,0 +1,100 @@ +/* Copyright (c) 1999, Not a Number / NeoGeo b.v. + * $Id$ + * + * All rights reserved. + * + * Contact: info@blender.org + * Information: http://www.blender.org + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#ifndef UTIL_H +#define UTIL_H + +#include +#include +#include +#include "externdef.h" + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef ulong +#define ulong unsigned long +#endif + +#ifndef ushort +#define ushort unsigned short +#endif + +#ifndef uchar +#define uchar unsigned char +#endif + +#ifndef uint +#define uint unsigned int +#endif + +#define MIN2(x,y) ( (x)<(y) ? (x) : (y) ) +#define MIN3(x,y,z) MIN2( MIN2((x),(y)) , (z) ) +#define MIN4(x,y,z,a) MIN2( MIN2((x),(y)) , MIN2((z),(a)) ) + +#define MAX2(x,y) ( (x)>(y) ? (x) : (y) ) +#define MAX3(x,y,z) MAX2( MAX2((x),(y)) , (z) ) +#define MAX4(x,y,z,a) MAX2( MAX2((x),(y)) , MAX2((z),(a)) ) + +#define SWAP(type, a, b) { type sw_ap; sw_ap=(a); (a)=(b); (b)=sw_ap; } + +#define ABS(x) ((x) < 0 ? -(x) : (x)) +#define FLOOR(x) ((int)(x) - ((x) < 0 && (x) != (int)(x))) +#define CEIL(x) ((int)(x) + ((x) > 0 && (x) != (int)(x))) +#define STEP(a,b) ( (a)>(b) ? (1) : (0) ) +#define CLAMP(val, low, high) ((val>high)?high:((val +#include "FTF_Settings.h" + +/** + * Set Font Size + * @param int size + */ +FTF_EXPORT void FTF_SetSize(int size); + +/** + * Get Font Size + * @return Font size + */ +FTF_EXPORT int FTF_GetSize(void); + +/** + * Ascender + * @return Ascend size + */ +FTF_EXPORT int FTF_Ascender(void); + +/** + * Descender + * @return Descend size + */ +FTF_EXPORT int FTF_Descender(void); + +/** + * String Translation and Code Conversion + * @param str source string + * @param ustr distnation string + * @param flag mode flag + */ +FTF_EXPORT void FTF_TransConvString(char* str, char* ustr, unsigned int flag); + +/** + * Draw a character at the current raster position. + * @param c the character to draw + * @param mode flag to forward to FTF_TransConvString() + * @return Width drawing + */ +//FTF_EXPORT float FTF_DrawCharacter(char c, unsigned int flag); + +/** + * Draws a string at the current raster postion. + * @param str The string to draw + * @param mode flag to forward to FTF_TransConvString() + * @return Width drawing + */ +FTF_EXPORT float FTF_DrawString(char* str, unsigned int flag); + + +/** + * Get a character width + * @param mode flag to forward to FTF_TransConvString() + */ +FTF_EXPORT float FTF_GetCharacterWidth(char c, unsigned int flag); + + +/** + * Get a string width + * @param mode flag to forward to FTF_TransConvString() + */ +FTF_EXPORT float FTF_GetStringWidth(char* str, unsigned int flag); + +/** + * Get Bounding Box + * @param llx Lower left near x coord + * @param lly Lower left near y coord + * @param llz Lower left near z coord + * @param urx Upper right far x coord + * @param ury Upper right far y coord + * @param urz Upper right far z coord + * @param mode flag to forward to FTF_TransConvString() + * not test yet. + */ +FTF_EXPORT void FTF_GetBoundingBox(char* str, float*llx, float *lly, float *llz, float *urx, float *ury, float *urz, unsigned int flag); + +/** + * Following stuff added by phase, ton + */ + +/** + * SetFontSize + * @param size + */ +FTF_EXPORT void FTF_SetFontSize(char size); + +/** + * SetFont + * @param str + * @param size + */ +FTF_EXPORT int FTF_SetFont(const unsigned char* str, int datasize, int fontsize); + +/** + * SetLanguage + * @param str + * not test yet. + */ +FTF_EXPORT void FTF_SetLanguage(char* str); + +/** + * SetLanguage + * @param str + * not tested yet. + */ +FTF_EXPORT void FTF_SetEncoding(char* str); + +FTF_EXPORT void FTF_SetPosition(float x, float y); +FTF_EXPORT void FTF_SetMode(int mode); +FTF_EXPORT void FTF_SetScale(float fsize); + +FTF_EXPORT void FTF_End(void); + +/* Font preview functions */ +FTF_EXPORT int FTF_GetNewFont (const unsigned char *str, int datasize, int fontsize); +FTF_EXPORT float FTF_DrawNewFontString(char* str, unsigned int flag); + +#ifdef __cplusplus +} +#endif + +#endif /* __FTF_API_H */ + diff --git a/source/blender/ftfont/FTF_Settings.h b/source/blender/ftfont/FTF_Settings.h new file mode 100644 index 00000000000..dc325c1de41 --- /dev/null +++ b/source/blender/ftfont/FTF_Settings.h @@ -0,0 +1,49 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Copyright (C) 2002 Blender Foundation. All Rights Reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * Allows you to determine which fonts to include in the library. + */ + +#ifndef __FTF_SETTINGS_H +#define __FTF_SETTINGS_H + +#define FTF_BIT(num) ((unsigned int)1 << (num)) +#define FTF_NO_TRANSCONV 0 +#define FTF_INPUT_SYSTEM_ENCODING FTF_BIT(1) +#define FTF_USE_GETTEXT FTF_BIT(2) +#define FTF_INPUT_UTF8 FTF_BIT(3) +#define FTF_PIXMAPFONT 0 +#define FTF_TEXTUREFONT 1 + +#endif /* __FTF_SETTINGS_H */ diff --git a/source/blender/ftfont/Makefile b/source/blender/ftfont/Makefile new file mode 100644 index 00000000000..1717fa34853 --- /dev/null +++ b/source/blender/ftfont/Makefile @@ -0,0 +1,37 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# Bounces make to subdirectories. + +SOURCEDIR = source/blender/ftfont +DIRS = intern + +include nan_subdirs.mk diff --git a/source/blender/ftfont/SConscript b/source/blender/ftfont/SConscript new file mode 100644 index 00000000000..615b274677c --- /dev/null +++ b/source/blender/ftfont/SConscript @@ -0,0 +1,16 @@ +#!/usr/bin/python +import sys +Import ('env') + +sources = env.Glob('intern/*.cpp') + +incs = '. intern ../blenkernel ../blenlib ../makesdna ../include' +incs += ' ' + env['BF_FTGL_INC'] +incs += ' ' + env['BF_FREETYPE_INC'] +incs += ' ' + env['BF_GETTEXT_INC'] + +defs = 'FTGL_STATIC_LIBRARY' +if sys.platform == 'win32': + defs += ' _WIN32 USE_GETTEXT_DLL' + +env.BlenderLib ( 'bf_ftfont', sources, Split(incs), Split(defs), libtype=['international','player'], priority=[0, 205] ) diff --git a/source/blender/ftfont/intern/FTF_Api.cpp b/source/blender/ftfont/intern/FTF_Api.cpp new file mode 100644 index 00000000000..bf6698a1cde --- /dev/null +++ b/source/blender/ftfont/intern/FTF_Api.cpp @@ -0,0 +1,208 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Copyright (C) 2002 Blender Foundation. All Rights Reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * + * Implementation of the API of FTGL library. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "../FTF_Api.h" +#include "FTF_TTFont.h" + +#ifdef __cplusplus +extern "C" { +#endif + #include "datatoc.h" +#ifdef __cplusplus +} +#endif + +#define FTF_EXPORT + +FTF_TTFont *newfont= 0; // preview font + +static FTF_TTFont *_FTF_GetFont(void) { + static FTF_TTFont *theFont = NULL; + + if (!theFont) { + theFont = new FTF_TTFont(); + } + + return theFont; +} + +FTF_EXPORT int FTF_GetNewFont (const unsigned char *str, int datasize, int fontsize) { + + if (newfont) delete newfont; + newfont= new FTF_TTFont(); + + if (!(newfont->SetFont((unsigned char*)str, datasize, fontsize))) { + newfont->SetFont((unsigned char*)datatoc_bfont_ttf, datatoc_bfont_ttf_size, fontsize); + return 0; + } + return 1; +} + +FTF_EXPORT float FTF_DrawNewFontString(char* str, unsigned int flag) +{ + if (newfont) + return newfont->DrawString(str, flag); + return 0.0f; +} + +FTF_EXPORT void FTF_End(void) { + delete _FTF_GetFont(); + delete newfont; +} + +FTF_EXPORT void FTF_SetSize(int size) +{ + _FTF_GetFont()->SetSize(size); +} + +FTF_EXPORT int FTF_GetSize(void) +{ + return _FTF_GetFont()->GetSize(); +} + +/* +FTF_EXPORT int FTF_Ascender(void) +{ + return _FTF_GetFont()->Ascender(); +} + +FTF_EXPORT int FTF_Descender(void) +{ + return _FTF_GetFont()->Descender(); +} +*/ + +FTF_EXPORT void FTF_TransConvString(char* str, char* ustr, unsigned int flag) +{ + _FTF_GetFont()->TransConvString(str, ustr, flag); +} + +/* +FTF_EXPORT float FTF_DrawCharacter(char c, unsigned int flag) +{ + char str[2] = {c, '\0'}; + return FTF_DrawString(str, flag); +} +*/ + + +/* does color too, using glGet */ +FTF_EXPORT float FTF_DrawString(char* str, unsigned int flag) +{ + return _FTF_GetFont()->DrawString(str, flag); +} + + +/** + * not implemente yet. + */ +FTF_EXPORT float FTF_GetCharacterWidth(char c, unsigned int flag) +{ + char str[2] = {c, '\0'}; + return FTF_GetStringWidth(str, flag); +} + + +/** + * not implemente yet. + */ +FTF_EXPORT float FTF_GetStringWidth(char* str, unsigned int flag) +{ + return _FTF_GetFont()->GetStringWidth(str, flag); +} + + +/** + * not implemente yet. + * ## This return string box!! ## + */ +FTF_EXPORT void FTF_GetBoundingBox(char* str, float *llx, float *lly, float *llz, float *urx, float *ury, float *urz, unsigned int flag) +{ + _FTF_GetFont()->GetBoundingBox(str, llx, lly, llz, urx, ury, urz, flag); +} + +/** + * added by phase + * changed by ton; to allow both file load as memory load (datasize!=0) + */ +FTF_EXPORT int FTF_SetFont(const unsigned char* str, int datasize, int fontsize) +{ + return _FTF_GetFont()->SetFont(str, datasize, fontsize); +} + +/* added by ton */ + +FTF_EXPORT void FTF_SetFontSize(char size) +{ + _FTF_GetFont()->SetFontSize( size); +} + +/** + * added by phase + * + */ +FTF_EXPORT void FTF_SetLanguage(char* str) +{ + _FTF_GetFont()->SetLanguage(str); +} + +FTF_EXPORT void FTF_SetEncoding(char* str) +{ + _FTF_GetFont()->SetEncoding(str); +} + +FTF_EXPORT void FTF_SetPosition(float x, float y) +{ + _FTF_GetFont()->SetPosition(x, y); +} + +FTF_EXPORT void FTF_SetMode(int mode) +{ + _FTF_GetFont()->SetMode(mode); +} + +FTF_EXPORT void FTF_SetScale(float fsize) +{ + _FTF_GetFont()->SetScale(fsize); +} + + diff --git a/source/blender/ftfont/intern/FTF_TTFont.cpp b/source/blender/ftfont/intern/FTF_TTFont.cpp new file mode 100644 index 00000000000..34b22e5c9d2 --- /dev/null +++ b/source/blender/ftfont/intern/FTF_TTFont.cpp @@ -0,0 +1,448 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Copyright (C) 2002 Blender Foundation. All Rights Reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include +#include +#include +#include "libintl.h" +#include "BLI_blenlib.h" + +#include "../FTF_Settings.h" + +#include "FTF_TTFont.h" + +#ifdef __APPLE__ +#include "BKE_utildefines.h" +#endif + +#define DOMAIN_NAME "blender" + +#define SYSTEM_ENCODING_DEFAULT "UTF-8" +#define FONT_SIZE_DEFAULT 12 +//#define FONT_PATH_DEFAULT ".bfont.ttf" + +#define FTF_MAX_STR_SIZE 512 + + +int utf8towchar(wchar_t *w, char *c) +{ + int len=0; + if(w==NULL || c==NULL) return(0); + //printf("%s\n",c); + while(*c) + { + //Converts Unicode to wchar: + + if(*c & 0x80) + { + if(*c & 0x40) + { + if(*c & 0x20) + { + if(*c & 0x10) + { + *w=(c[0] & 0x0f)<<18 | (c[1]&0x1f)<<12 | (c[2]&0x3f)<<6 | (c[3]&0x7f); + c++; + } + else + *w=(c[0] & 0x1f)<<12 | (c[1]&0x3f)<<6 | (c[2]&0x7f); + c++; + } + else + *w=(c[0] &0x3f)<<6 | c[1]&0x7f; + c++; + } + else + *w=(c[0] & 0x7f); + } + else + *w=(c[0] & 0x7f); + + c++; + w++; + len++; + } + return len; +} + + +FTF_TTFont::FTF_TTFont(void) +{ +#ifdef __APPLE__ + char *bundlepath; +#endif + + font=NULL; + fontm= fonts= fontl= NULL; + font_size=FONT_SIZE_DEFAULT; + mode = FTF_PIXMAPFONT; + fsize = 1.0; + strcpy(encoding_name, SYSTEM_ENCODING_DEFAULT); + + //set messagepath directory + +#ifndef LOCALEDIR +#define LOCALEDIR "/usr/share/locale" +#endif + + strcpy(messagepath, ".blender/locale"); + + if ( !BLI_exist(messagepath) ) { // locale not in current dir + BLI_make_file_string("/", messagepath, BLI_gethome(), ".blender/locale"); + + if( !BLI_exist(messagepath) ) { // locale not in home dir + +#ifdef WIN32 + BLI_make_file_string("/", messagepath, BLI_gethome(), "/locale"); + if( !BLI_exist(messagepath) ) { +#endif +#ifdef __APPLE__ + /* message catalogs are stored inside the application bundle */ + bundlepath = BLI_getbundle(); + strcpy(messagepath, bundlepath); + strcat(messagepath, "/Contents/Resources/locale"); + if( !BLI_exist(messagepath) ) { // locale not in bundle (now that's odd..) +#endif + strcpy(messagepath, LOCALEDIR); + + if( !BLI_exist(messagepath) ) { // locale not in LOCALEDIR + strcpy(messagepath, "message"); // old compatibility as last + } +#ifdef WIN32 + } +#endif +#ifdef __APPLE__ + } +#endif + } + } +} + + +FTF_TTFont::~FTF_TTFont(void) +{ + if (fonts) delete fonts; + if (fontm) delete fontm; + if (fontl) delete fontl; +} + +void FTF_TTFont::SetFontSize(char size) +{ + if(size=='s') font=fonts; + else if(size=='l') font=fontl; + else font=fontm; +} + +int FTF_TTFont::SetFont(const unsigned char* str, int datasize, int fontsize) +{ + int err = 0; + bool success = 0; + + if (fonts) delete fonts; + if (fontm) delete fontm; + if (fontl) delete fontl; + fonts= NULL; + fontm= NULL; + fontl= NULL; + + if(mode == FTF_PIXMAPFONT) { + + if(datasize) font = new FTGLPixmapFont(str, datasize); + else font = new FTGLPixmapFont( (char *)str); + + err = font->Error(); + + if(err) { + printf("Failed to open font %s\n", str); + return 0; + } else { + + fontm= font; + + if(datasize) fonts = new FTGLPixmapFont(str, datasize); + else fonts = new FTGLPixmapFont((char *)str); + if(datasize) fontl = new FTGLPixmapFont(str, datasize); + else fontl = new FTGLPixmapFont((char *)str); + + success = fonts->FaceSize(fontsize-2<8?8:fontsize-2); + success = fontm->FaceSize(fontsize-1<8?8:fontsize-1); + success = fontl->FaceSize(fontsize); + if(!success) return 0; + + success = fonts->CharMap(ft_encoding_unicode); + success = fontm->CharMap(ft_encoding_unicode); + success = fontl->CharMap(ft_encoding_unicode); + if(!success) return 0; + + return 1; + } + + } else if(mode == FTF_TEXTUREFONT) { + + if(datasize) font = new FTGLTextureFont(str, datasize); + else font = new FTGLTextureFont( (char *)str); + + err = font->Error(); + + if(err) { + printf("Failed to open font %s\n", str); + return 0; + } else { + + fontm= font; + + if(datasize) fonts = new FTGLTextureFont(str, datasize); + else fonts = new FTGLTextureFont((char *)str); + if(datasize) fontl = new FTGLTextureFont(str, datasize); + else fontl = new FTGLTextureFont((char *)str); + + success = fonts->FaceSize(fontsize-2<8?8:fontsize-2); + success = fontm->FaceSize(fontsize-1<8?8:fontsize-1); + success = fontl->FaceSize(fontsize); +// success = fonts->FaceSize(fontsize/2); +// success = fontm->FaceSize(fontsize); +// success = fontl->FaceSize(fontsize*2); + if(!success) return 0; + + success = fonts->CharMap(ft_encoding_unicode); + success = fontm->CharMap(ft_encoding_unicode); + success = fontl->CharMap(ft_encoding_unicode); + if(!success) return 0; + + return 1; + } + } + return 0; +} + +void FTF_TTFont::SetLanguage(char* str) +{ + +#if defined (_WIN32) || defined(__APPLE__) + char envstr[12]; + + sprintf(envstr, "LANG=%s", str); + envstr[strlen(envstr)]='\0'; +#ifdef _WIN32 + gettext_putenv(envstr); +#else + putenv(envstr); +#endif +#else + char *locreturn = setlocale(LC_ALL, str); + if (locreturn == NULL) { + char *lang; + + lang = (char*)malloc(sizeof(char)*(strlen(str)+7)); + + lang[0] = '\0'; + strcat(lang, str); + strcat(lang, ".UTF-8"); + + locreturn = setlocale(LC_ALL, lang); + if (locreturn == NULL) { + printf("could not change language to %s nor %s\n", str, lang); + } + + free(lang); + } + + setlocale(LC_NUMERIC, "C"); +#endif + + + bindtextdomain(DOMAIN_NAME, messagepath); +// bind_textdomain_codeset(DOMAIN_NAME, encoding_name); + textdomain(DOMAIN_NAME); + + strcpy(language, str); +} + + +void FTF_TTFont::SetEncoding(char* str) +{ + strcpy(encoding_name, str); +// bind_textdomain_codeset(DOMAIN_NAME, encoding_name); +} + + +void FTF_TTFont::SetSize(int size) +{ + fonts->FaceSize(size-2<8?8:size-2); + fontm->FaceSize(size-1<8?8:size-1); + fontl->FaceSize(size); + + font_size = size; +} + +int FTF_TTFont::GetSize(void) +{ + return font_size; +} + +/* +int FTF_TTFont::Ascender(void) +{ + return (int)font->Ascender(); +} + +int FTF_TTFont::Descender(void) +{ + return (int)font->Descender(); +} + +*/ +int FTF_TTFont::TransConvString(char* str, char* ustr, unsigned int flag) +{ + return 0; +} + + +float FTF_TTFont::DrawString(char* str, unsigned int flag) +{ + float color[4]; + wchar_t wstr[FTF_MAX_STR_SIZE-1]={'\0'}; + + /* note; this utf8towchar() function I totally don't understand... without using translations it + removes special characters completely. So, for now we just skip that then. (ton) */ + if (FTF_USE_GETTEXT & flag) + utf8towchar(wstr, gettext(str)); + else if (FTF_INPUT_UTF8 & flag) + utf8towchar(wstr, str); + + glGetFloatv(GL_CURRENT_COLOR, color); + + if(mode == FTF_PIXMAPFONT) { + + glPixelTransferf(GL_RED_SCALE, color[0]); + glPixelTransferf(GL_GREEN_SCALE, color[1]); + glPixelTransferf(GL_BLUE_SCALE, color[2]); + + if ((FTF_USE_GETTEXT | FTF_INPUT_UTF8) & flag) + font->Render(wstr); + else + font->Render(str); + + glPixelTransferf(GL_RED_SCALE, 1.0); + glPixelTransferf(GL_GREEN_SCALE, 1.0); + glPixelTransferf(GL_BLUE_SCALE, 1.0); + + } else if(mode == FTF_TEXTUREFONT) { + + glEnable(GL_BLEND); + glEnable(GL_TEXTURE_2D); + + glPushMatrix(); + glTranslatef(pen_x, pen_y, 0.0); + glScalef(fsize, fsize, 1.0); + + if ((FTF_USE_GETTEXT | FTF_INPUT_UTF8) & flag) + font->Render(wstr); + else + font->Render(str); + + glPopMatrix(); + + glDisable(GL_BLEND); + glDisable(GL_TEXTURE_2D); + } + + if ((FTF_USE_GETTEXT | FTF_INPUT_UTF8) & flag) + return font->Advance(wstr); + else + return font->Advance(str); +} + + +float FTF_TTFont::GetStringWidth(char* str, unsigned int flag) +{ + wchar_t wstr[FTF_MAX_STR_SIZE-1]={'\0'}; + int len=0; + + if (strlen(str)==0) return 0.0; + + /* note; this utf8towchar() function I totally don't understand... without using translations it + removes special characters completely. So, for now we just skip that then. (ton) */ + + if (FTF_USE_GETTEXT & flag) { + len=utf8towchar(wstr, gettext(str)); + + if(mode == FTF_PIXMAPFONT) { + return font->Advance(wstr); + } else if(mode == FTF_TEXTUREFONT) { + return font->Advance(wstr);// * fsize; + } + } + else { + if(mode == FTF_PIXMAPFONT) { + return font->Advance(str); + } else if(mode == FTF_TEXTUREFONT) { + return font->Advance(str);// * fsize; + } + } + + return 0.0; +} + + +void FTF_TTFont::GetBoundingBox(char* str, float *llx, float *lly, float *llz, float *urx, float *ury, float *urz, unsigned int flag) +{ + wchar_t wstr[FTF_MAX_STR_SIZE-1]={'\0'}; + int len=0; + + if (FTF_USE_GETTEXT & flag) + len=utf8towchar(wstr,gettext(str)); + else + len=utf8towchar(wstr,str); + + font->BBox(wstr, *llx, *lly, *llz, *urx, *ury, *urz); +} + + +void FTF_TTFont::SetPosition(float x, float y) +{ + pen_x = x; + pen_y = y; +} + + +void FTF_TTFont::SetMode(int m) +{ + mode = m; +} + + +void FTF_TTFont::SetScale(float size) +{ + fsize = size; +} + + diff --git a/source/blender/ftfont/intern/FTF_TTFont.h b/source/blender/ftfont/intern/FTF_TTFont.h new file mode 100644 index 00000000000..b5ff1cc54bf --- /dev/null +++ b/source/blender/ftfont/intern/FTF_TTFont.h @@ -0,0 +1,139 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Copyright (C) 2002 Blender Foundation. All Rights Reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + */ + +#ifndef __FTF_TRUETYPE_FONT_H +#define __FTF_TRUETYPE_FONT_H + +#include "FTGLPixmapFont.h" +#include "FTGLTextureFont.h" + +#include +//#include + + +/** + * Base class for Using FTGL, iconv and gettext Library. + */ +class FTF_TTFont +{ +public: + /** + * Default constructor. + */ + FTF_TTFont(void); + + /** + * Destructor. + */ + virtual ~FTF_TTFont(void); + + + void SetSize(int size); + int GetSize(void); + +// int Ascender(void); +// int Descender(void); + + int TransConvString(char* str, char* ustr, unsigned int flag); + + /** + * Draws a string at the current raster position in current opengl color. + * @param str The string to draw. + * @param flag Whether use gettext and UTF8 or system encoding. + */ + float DrawString(char* str, unsigned int flag); + + float GetStringWidth(char* str, unsigned int flag); + + /** + * Get the bounding box for a string. + * + * @param str The string + * @param llx Lower left near x coord + * @param lly Lower left near y coord + * @param llz Lower left near z coord + * @param urx Upper right far x coord + * @param ury Upper right far y coord + * @param urz Upper right far z coord + */ + void GetBoundingBox(char* str, float *llx, float *lly, float *llz, float *urx, float *ury, float *urz, unsigned int flag); + + /** + * added by phase, ton + * functions to communicate with the preference menu + */ + void SetFontSize(char size); + + int SetFont(const unsigned char* str, int datasize, int fontsize); + + void SetLanguage(char* str); + + void SetEncoding(char* str); + + /** + * functions to communicate with blender ui rasterpos + */ + void SetPosition(float x, float y); + void SetMode(int mode); + void SetScale(float fsize); + +protected: + char messagepath[1024]; + + char language[32]; + char encoding_name[32]; + char font_name[128]; + int font_size; + + int mode; // 0 = pixmap, 1 = texture + float pen_x, pen_y; //rasterpos + float fsize; + + /** FTGL's */ + FTFont* font; /* active */ + + FTFont* fonts; /* opened, small medium and large */ + FTFont* fontm; + FTFont* fontl; + + /** from system encoding in .locale to UNICODE */ +// iconv_t cd; + + /** from UTF-8 to UNICODE */ +// iconv_t ucd; +}; + +#endif // __FTF_TRUETYPE_FONT_H diff --git a/source/blender/ftfont/intern/Makefile b/source/blender/ftfont/intern/Makefile new file mode 100644 index 00000000000..064ec5dc597 --- /dev/null +++ b/source/blender/ftfont/intern/Makefile @@ -0,0 +1,59 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = ftfont +DIR = $(OCGDIR)/blender/ftfont + +include nan_compile.mk + +CFLAGS += $(LEVEL_1_C_WARNINGS) + +#CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include +CPPFLAGS += -I../../makesdna +CPPFLAGS += -I../../blenkernel +CPPFLAGS += -I../../blenlib +CPPFLAGS += -I../../include +CPPFLAGS += -I$(NAN_FTGL)/include +CPPFLAGS += -I$(NAN_FTGL)/include/FTGL +CPPFLAGS += -I$(NAN_GETTEXT)/include +CPPFLAGS += -I$(NAN_FREETYPE)/include +ifeq ($(OS), windows) + CPPFLAGS += -I$(NAN_ICONV)/include + ifeq ($(FREE_WINDOWS), true) + CPPFLAGS += -I$(NAN_FREETYPE)/include/freetype2 + CPPFLAGS += -DUSE_GETTEXT_DLL + endif +else + CPPFLAGS += -I$(NAN_FREETYPE)/include/freetype2 +endif +CPPFLAGS += -I.. diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt new file mode 100644 index 00000000000..146ec654c1e --- /dev/null +++ b/source/blender/imbuf/CMakeLists.txt @@ -0,0 +1,61 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +FILE(GLOB SRC intern/*.c) + +SET(INC + . ../makesdna ../../../intern/guardedalloc ../../../intern/memutil ../blenlib + ../avi ../quicktime ../blenkernel + ${JPEG_INC} + ${PNG_INC} + ${TIFF_INC} + ${ZLIB_INC} +) + +IF(WITH_VERSE) + ADD_DEFINITIONS(-DWITH_VERSE) + SET(INC ${INC} VERSE_INC) +ENDIF(WITH_VERSE) + +IF(WITH_OPENEXR) + ADD_DEFINITIONS(-DWITH_OPENEXR) +ENDIF(WITH_OPENEXR) + +IF(WITH_QUICKTIME) + SET(INC ${INC} ${QUICKTIME_INC}) + ADD_DEFINITIONS(-DWITH_QUICKTIME) +ENDIF(WITH_QUICKTIME) + +IF(WITH_FFMPEG) + SET(INC ${INC} ${FFMPEG_INC}) + ADD_DEFINITIONS(-DWITH_FFMPEG) +ENDIF(WITH_FFMPEG) + +BLENDERLIB(bf_imbuf "${SRC}" "${INC}") +#env.BlenderLib ( libname = 'bf_imbuf', sources = sources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [80, 40] ) diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h new file mode 100644 index 00000000000..dbbddd2a070 --- /dev/null +++ b/source/blender/imbuf/IMB_imbuf.h @@ -0,0 +1,583 @@ +/** + * @file IMB_imbuf.h + * @brief IMage Buffer module. + * + * This module offers import/export of several graphical file formats. + * \ref IMB + * @ingroup imbuf + * @ingroup undoc + * + * @page IMB - Imbuf module external interface + * + * + * @section about About the IMB module + * + * External interface of the IMage Buffer module. This module offers + * import/export of several graphical file formats. It offers the + * ImBuf type as a common structure to refer to different graphical + * file formats, and to enable a uniform way of handling them. + * + * @section issues Known issues with IMB + * + * - imbuf is written in C. + * - Endianness issues are dealt with internally. + * - File I/O must be done externally. The module uses FILE*'s to + * direct input/output. + * - Platform dependency is limited. Some minor patches for + * amiga and Irix are present. A 'posix-compliancy-patch' + * provides the interface to windows. + * + * @section dependencies Dependencies + * + * IMB needs: + * - SDNA module + * The listbase types are used for handling the memory + * management. + * - blenlib module + * blenlib handles guarded memory management in blender-style. + * BLI_winstuff.h makes a few windows specific behaviours + * posix-compliant. + * - avi + * avi defines import/export to the avi format. Only anim.c + * needs this. It uses the following functions: + * - avi_close + * - avi_is_avi + * - avi_print_error + * - avi_open_movie + * - avi_read_frame + * - avi_get_stream + * Additionally, it needs the types from the avi module. + * - external jpeg library + * The jpeg lib defines import/export to the jpeg format. + * only jpeg.c needs these. Used functions are: + * - jpeg_destroy + * - jpeg_resync_to_restart + * - jpeg_set_marker_processor + * - jpeg_read_header + * - jpeg_start_decompress + * - jpeg_abort_decompress + * - jpeg_read_scanlines + * - jpeg_finish_decompress + * - jpeg_std_error + * - jpeg_create_decompress + * - jpeg_stdio_src + * - jpeg_start_compress + * - jpeg_write_marker + * - jpeg_write_scanlines + * - jpeg_finish_compress + * - jpeg_create_compress + * - jpeg_stdio_dest + * - jpeg_set_defaults + * - jpeg_set_quality + * - jpeg_destroy_compress + * Additionally, it needs the types from the jpeg lib. + */ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef IMB_IMBUF_H +#define IMB_IMBUF_H + +/** + * + * @attention defined in ??? + */ +struct ImBuf; + +/** + * + * @attention defined in ??? + */ +struct anim; + +/** + * + * @attention Defined in cmap.c + */ +void IMB_freeImBufdata(void); + +/** + * + * @attention Defined in cmap.c + */ +void IMB_applycmap(struct ImBuf *ibuf); + +/** + * + * @attention Defined in cmap.c + */ +short IMB_converttocmap(struct ImBuf *ibuf); + +/** + * + * @attention Defined in cmap.c + */ +int IMB_alpha_to_col0(int value); + +/** + * + * @attention Defined in readimage.c + */ +struct ImBuf *IMB_ibImageFromMemory(int *mem, int size, int flags); + +/** + * + * @attention Defined in readimage.c + */ +struct ImBuf *IMB_testiffname(char *naam,int flags); + +/** + * + * @attention Defined in readimage.c + */ +struct ImBuf *IMB_loadiffname(const char *naam, int flags); + +/** + * + * @attention Defined in allocimbuf.c + */ +void IMB_freeImBuf(struct ImBuf * ibuf); + +/** + * + * @attention Defined in allocimbuf.c + */ +struct ImBuf *IMB_allocImBuf(short x, short y, + unsigned char d, unsigned int flags, + unsigned char bitmap); + +/** + * + * Increase reference count to imbuf + * (to delete an imbuf you have to call freeImBuf as many times as it + * is referenced) + * + * @attention Defined in allocimbuf.c + */ + +void IMB_refImBuf(struct ImBuf * ibuf); + +/** + * + * @attention Defined in allocimbuf.c + */ +void IMB_cache_limiter_insert(struct ImBuf * i); +void IMB_cache_limiter_unmanage(struct ImBuf * i); +void IMB_cache_limiter_touch(struct ImBuf * i); +void IMB_cache_limiter_ref(struct ImBuf * i); +void IMB_cache_limiter_unref(struct ImBuf * i); +int IMB_cache_limiter_get_refcount(struct ImBuf * i); + +/** + * + * @attention Defined in allocimbuf.c + */ +struct ImBuf *IMB_dupImBuf(struct ImBuf *ibuf1); + +/** + * + * @attention Defined in allocimbuf.c + */ +short addzbufImBuf(struct ImBuf * ibuf); +short addzbuffloatImBuf(struct ImBuf * ibuf); + +/** + * + * @attention Defined in allocimbuf.c + */ +void IMB_freecmapImBuf(struct ImBuf * ibuf); + +/** + * + * @attention Defined in rectop.c + */ + +typedef enum IMB_BlendMode { + IMB_BLEND_MIX = 0, + IMB_BLEND_ADD = 1, + IMB_BLEND_SUB = 2, + IMB_BLEND_MUL = 3, + IMB_BLEND_LIGHTEN = 4, + IMB_BLEND_DARKEN = 5, + IMB_BLEND_ERASE_ALPHA = 6, + IMB_BLEND_ADD_ALPHA = 7, + + IMB_BLEND_COPY = 1000, + IMB_BLEND_COPY_RGB = 1001, + IMB_BLEND_COPY_ALPHA = 1002 +} IMB_BlendMode; + +unsigned int IMB_blend_color(unsigned int src1, unsigned int src2, int fac, + IMB_BlendMode mode); +void IMB_blend_color_float(float *dst, float *src1, float *src2, float fac, + IMB_BlendMode mode); + +void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx, + int *desty, int *srcx, int *srcy, int *width, int *height); +void IMB_rectcpy(struct ImBuf *drect, struct ImBuf *srect, int destx, + int desty, int srcx, int srcy, int width, int height); +void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx, + int desty, int srcx, int srcy, int width, int height, IMB_BlendMode mode); +void IMB_rectblend_torus(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx, + int desty, int srcx, int srcy, int width, int height, IMB_BlendMode mode); + +/** + * Return the length (in frames) of the given @a anim. + */ +int IMB_anim_get_duration(struct anim *anim); + +/** + * + * @attention Defined in anim.c + */ +struct anim * IMB_open_anim(const char * name, int ib_flags); +void IMB_close_anim(struct anim * anim); + +/** + * + * @attention Defined in anim.c + */ + +int ismovie(char *name); +void IMB_anim_set_preseek(struct anim * anim, int preseek); +int IMB_anim_get_preseek(struct anim * anim); + +/** + * + * @attention Defined in anim.c + */ + +struct ImBuf * IMB_anim_absolute(struct anim * anim, int position); + +/** + * + * @attention Defined in anim.c + * fetches a define previewframe, usually half way into the movie + */ +struct ImBuf * IMB_anim_previewframe(struct anim * anim); + +/** + * + * @attention Defined in anim.c + */ +void IMB_free_anim_ibuf(struct anim * anim); + +/** + * + * @attention Defined in anim.c + */ +void IMB_free_anim(struct anim * anim); + +/** + * + * @attention Defined in anim.c + */ +struct ImBuf * IMB_anim_nextpic(struct anim * anim); + + +/** + * + * @attention Defined in antialias.c + */ +void IMB_clever_double (struct ImBuf * ibuf); + +/** + * + * @attention Defined in antialias.c + */ +void IMB_antialias(struct ImBuf * ibuf); + +/** + * + * @attention Defined in filter.c + */ +void IMB_filter(struct ImBuf *ibuf); +void IMB_filterN(struct ImBuf *out, struct ImBuf *in); +void IMB_filter_extend(struct ImBuf *ibuf); +void IMB_makemipmap(struct ImBuf *ibuf, int use_filter); + +/** + * + * @attention Defined in filter.c + */ +void IMB_filtery(struct ImBuf *ibuf); + +/** + * + * @attention Defined in scaling.c + */ +struct ImBuf *IMB_onehalf(struct ImBuf *ibuf1); + +/** + * + * @attention Defined in scaling.c + */ +struct ImBuf *IMB_scaleImBuf(struct ImBuf * ibuf, short newx, short newy); + +/** + * + * @attention Defined in scaling.c + */ +struct ImBuf *IMB_scalefieldImBuf(struct ImBuf *ibuf, short newx, short newy); + +/** + * + * @attention Defined in scaling.c + */ +struct ImBuf *IMB_scalefastImBuf(struct ImBuf *ibuf, short newx, short newy); + +/** + * + * @attention Defined in writeimage.c + */ +short IMB_saveiff(struct ImBuf *ibuf,char *naam,int flags); + +/** + * Encodes a png image from an ImBuf + * + * @attention Defined in png_encode.c + */ +short IMB_png_encode(struct ImBuf *ibuf, int file, int flags); + +/** + * + * @attention Defined in util.c + */ +int IMB_ispic(char *name); + +/** + * + * @attention Defined in util.c + */ +int IMB_isanim(char * name); + +/** + * + * @attention Defined in util.c + */ +int imb_get_anim_type(char * name); + +/** + * + * @attention Defined in divers.c + */ +void IMB_de_interlace(struct ImBuf *ibuf); +void IMB_interlace(struct ImBuf *ibuf); +void IMB_gamwarp(struct ImBuf *ibuf, double gamma); +void IMB_rect_from_float(struct ImBuf *ibuf); +void IMB_float_from_rect(struct ImBuf *ibuf); + +/** + * Change the ordering of the color bytes pointed to by rect from + * rgba to abgr. size * 4 color bytes are reordered. + * + * @attention Defined in imageprocess.c + */ +void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf); +/** + * + * @attention defined in imageprocess.c + */ +void bicubic_interpolation(struct ImBuf *in, struct ImBuf *out, float x, float y, int xout, int yout); +void neareast_interpolation(struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout); +void bilinear_interpolation(struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout); +/** + * Change the ordering of the color bytes pointed to by rect from + * rgba to abgr. size * 4 color bytes are reordered. + * + * @attention Defined in imageprocess.c + */ +void IMB_convert_bgra_to_rgba(int size, unsigned int *rect); + +/** + * + * @attention defined in scaling.c + */ +struct ImBuf *IMB_scalefastfieldImBuf(struct ImBuf *ibuf, + short newx, + short newy); + +/** + * + * @attention defined in readimage.c + * @deprecated Only here for backwards compatibility of the + * @deprecated plugin system. + */ +struct ImBuf *IMB_loadiffmem(int *mem, int flags); + +/** + * + * @attention defined in readimage.c + * @deprecated Only here for backwards compatibility of the + * @deprecated plugin system. + */ +struct ImBuf *IMB_loadifffile(int file, int flags); + +/** + * + * @attention defined in scaling.c + */ +struct ImBuf *IMB_half_x(struct ImBuf *ibuf1); + +/** + * + * @attention defined in scaling.c + */ +struct ImBuf *IMB_double_fast_x(struct ImBuf *ibuf1); + +/** + * + * @attention defined in scaling.c + */ +struct ImBuf *IMB_double_x(struct ImBuf *ibuf1); + +/** + * + * @attention defined in scaling.c + */ +struct ImBuf *IMB_half_y(struct ImBuf *ibuf1); + +/** + * + * @attention defined in scaling.c + */ +struct ImBuf *IMB_double_fast_y(struct ImBuf *ibuf1); + +/** + * + * @attention defined in scaling.c + */ +struct ImBuf *IMB_double_y(struct ImBuf *ibuf1); + +/** + * + * @attention defined in scaling.c + */ +struct ImBuf *IMB_onethird(struct ImBuf *ibuf1); + +/** + * + * @attention defined in scaling.c + */ +struct ImBuf *IMB_halflace(struct ImBuf *ibuf1); + +/** + * + * @attention defined in dither.c + */ +void IMB_dit2(struct ImBuf * ibuf, short ofs, short bits); + +/** + * + * @attention defined in dither.c + */ +void IMB_dit0(struct ImBuf * ibuf, short ofs, short bits); + +/** Externally used vars: fortunately they do not use funny types */ + +/** + * boolean toggle that tells whether or not to + * scale the color map in the y-direction. + * + * @attention declared in hamx.c + */ +extern int scalecmapY; + +/** + * This 'matrix' defines the transformation from rgb to bw color + * maps. You need to do a sort of dot-product for that. It is a matrix + * with fixed coefficients, extracted from some book. + * + * @attention Defined in matrix.h, only included in hamx.c + */ +extern float rgb_to_bw[4][4]; + +/** + * + * @attention Defined in rotate.c + */ +void IMB_flipx(struct ImBuf *ibuf); +void IMB_flipy(struct ImBuf * ibuf); + +/** + * + * @attention Defined in cspace.c + */ +void IMB_cspace(struct ImBuf *ibuf, float mat[][4]); + +/** + * + * @attention Defined in allocimbuf.c + */ +void IMB_freezbufImBuf(struct ImBuf * ibuf); +void IMB_freezbuffloatImBuf(struct ImBuf * ibuf); + +/** + * + * @attention Defined in rectop.c + */ +void IMB_rectfill(struct ImBuf *drect, float col[4]); +void IMB_rectfill_area(struct ImBuf *ibuf, float *col, int x1, int y1, int x2, int y2); + +/* this should not be here, really, we needed it for operating on render data, IMB_rectfill_area calls it */ +void buf_rectfill_area(unsigned char *rect, float *rectf, int width, int height, float *col, int x1, int y1, int x2, int y2); + +/* defined in imginfo.c */ +int IMB_imginfo_change_field(struct ImBuf *img, const char *key, const char *field); + +/* exported for image tools in blender, to quickly allocate 32 bits rect */ +short imb_addrectImBuf(struct ImBuf * ibuf); +void imb_freerectImBuf(struct ImBuf * ibuf); + +short imb_addrectfloatImBuf(struct ImBuf * ibuf); +void imb_freerectfloatImBuf(struct ImBuf * ibuf); +void imb_freemipmapImBuf(struct ImBuf * ibuf); + +#ifdef WITH_QUICKTIME +/** + * + * @attention Defined in quicktime_import.c + */ +void quicktime_init(void); + +/** + * + * @attention Defined in quicktime_import.c + */ +void quicktime_exit(void); + +#endif //WITH_QUICKTIME + +/* intern/dynlibtiff.c */ +void libtiff_init(void); +void libtiff_exit(void); + +#endif diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h new file mode 100644 index 00000000000..91ffa188fcc --- /dev/null +++ b/source/blender/imbuf/IMB_imbuf_types.h @@ -0,0 +1,242 @@ +/** + * IMB_imbuf_types.h (mar-2001 nzc) + * + * Types needed for using the image buffer. + * + * Imbuf is external code, slightly adapted to live in the Blender + * context. It requires an external jpeg module, and the avi-module + * (also external code) in order to function correctly. + * + * This file contains types and some constants that go with them. Most + * are self-explanatory (e.g. IS_amiga tests whether the buffer + * contains an Amiga-format file). + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * \file IMB_imbuf_types.h + * \ingroup imbuf + * \brief Contains defines and structs used throughout the imbuf module. + * \todo Clean up includes. + */ + +#ifndef IMB_IMBUF_TYPES_H +#define IMB_IMBUF_TYPES_H + +#include /* for size_t */ +#include "DNA_listBase.h" /* for ListBase */ +struct _AviMovie; +struct Mdec; + +struct ImgInfo; + +#define IB_MIPMAP_LEVELS 10 + +/** + * \brief The basic imbuf type + * \ingroup imbuf + * This is the abstraction of an image. ImBuf is the basic type used for all + * imbuf operations. + * + * REMINDER: if any changes take place, they need to be carried over + * to source/blender/blenpluginapi/iff.h too, OTHERWISE PLUGINS WON'T + * WORK CORRECTLY! + * + * Also; add new variables to the end to save pain! + * + * Also, that iff.h needs to be in the final release "plugins/include" dir, too! + */ +typedef struct ImBuf { + struct ImBuf *next, *prev; /**< allow lists of ImBufs, for caches or flipbooks */ + short x, y; /**< width and Height of our image buffer */ + short skipx; /**< Width in ints to get to the next scanline */ + unsigned char depth; /**< Active amount of bits/bitplanes */ + unsigned char cbits; /**< Amount of active bits in cmap */ + unsigned short mincol; /**< smallest color in colormap */ + unsigned short maxcol; /**< Largest color in colormap */ + int type; /**< 0=abgr, 1=bitplanes */ + int ftype; /**< File type we are going to save as */ + unsigned int *cmap; /**< Color map data. */ + unsigned int *rect; /**< pixel values stored here */ + unsigned int **planes; /**< bitplanes */ + int flags; /**< Controls which components should exist. */ + int mall; /**< what is malloced internal, and can be freed */ + short xorig, yorig; /**< Cordinates of first pixel of an image used in some formats (example: targa) */ + char name[1023]; /**< The file name assocated with this image */ + char namenull; /**< Unused don't want to remove it thought messes things up */ + int userflags; /**< Used to set imbuf to Dirty and other stuff */ + int *zbuf; /**< z buffer data, original zbuffer */ + float *zbuf_float; /**< z buffer data, camera coordinates */ + void *userdata; + unsigned char *encodedbuffer; /**< Compressed image only used with png currently */ + unsigned int encodedsize; /**< Size of data written to encodedbuffer */ + unsigned int encodedbuffersize; /**< Size of encodedbuffer */ + + float *rect_float; /**< floating point Rect equivilant */ + int channels; /**< amount of channels in rect_float (0 = 4 channel default) */ + float dither; /**< random dither value, for conversion from float -> byte rect */ + + struct MEM_CacheLimiterHandle_s * c_handle; /**< handle for cache limiter */ + struct ImgInfo * img_info; + int refcounter; /**< Refcounter for multiple users */ + int index; /**< reference index for ImBuf lists */ + + struct ImBuf *mipmap[IB_MIPMAP_LEVELS]; /**< MipMap levels, a series of halved images */ +} ImBuf; + +/* Moved from BKE_bmfont_types.h because it is a userflag bit mask. */ +/** + * \brief Flags used internally by blender for imagebuffers + */ +typedef enum { + IB_BITMAPFONT = 1 << 0, /* This image is a font */ + IB_BITMAPDIRTY = 1 << 1 /* Image needs to be saved is not the same as filename */ +} ImBuf_userflagsMask; + + +/* From iff.h. This was once moved away by Frank, now Nzc moves it + * back. Such is the way it is... It is a long list of defines, and + * there are a few external defines in the back. Most of the stuff is + * probably imbuf_intern only. This will need to be merged later + * on. */ + +/** + * \name Imbuf Component flags + * \brief These flags determine the components of an ImBuf struct. + */ +/**@{*/ +/** \brief Flag defining the components of the ImBuf struct. */ +#define IB_rect (1 << 0) +#define IB_planes (1 << 1) +#define IB_cmap (1 << 2) + +#define IB_vert (1 << 4) +#define IB_freem (1 << 6) +#define IB_test (1 << 7) + +#define IB_ttob (1 << 8) +#define IB_subdlta (1 << 9) +#define IB_fields (1 << 11) +#define IB_zbuf (1 << 13) + +#define IB_mem (1 << 14) +#define IB_rectfloat (1 << 15) +#define IB_zbuffloat (1 << 16) +#define IB_multilayer (1 << 17) +#define IB_imginfo (1 << 18) + +/* + * The bit flag is stored in the ImBuf.ftype variable. + * Note that the lower 10 bits is used for storing custom flags + */ +#define AMI (1 << 31) +#define PNG (1 << 30) +#define Anim (1 << 29) +#define TGA (1 << 28) +#define JPG (1 << 27) +#define BMP (1 << 26) + +#ifdef WITH_QUICKTIME +#define QUICKTIME (1 << 25) +#endif + +#define RADHDR (1 << 24) +#define TIF (1 << 23) + +#define OPENEXR (1 << 22) +#define OPENEXR_HALF (1 << 8 ) +#define OPENEXR_COMPRESS (7) + +#define CINEON (1 << 21) +#define DPX (1 << 20) + +#ifdef WITH_DDS +#define DDS (1 << 19) +#endif + +#define RAWTGA (TGA | 1) + +#define JPG_STD (JPG | (0 << 8)) +#define JPG_VID (JPG | (1 << 8)) +#define JPG_JST (JPG | (2 << 8)) +#define JPG_MAX (JPG | (3 << 8)) +#define JPG_MSK (0xffffff00) + +#define AM_ham (0x0800 | AMI) +#define AM_hbrite (0x0080 | AMI) + +#define C233 1 +#define YUVX 2 +#define HAMX 3 +#define TANX 4 + +#define AN_c233 (Anim | C233) +#define AN_yuvx (Anim | YUVX) +#define AN_hamx (Anim | HAMX) +#define AN_tanx (Anim | TANX) +/**@}*/ + +/** \name Imbuf File Type Tests + * \brief These macros test if an ImBuf struct is the corresponding file type. + */ +/**@{*/ +/** \brief Tests the ImBuf.ftype variable for the file format. */ +#define IS_amiga(x) (x->ftype & AMI) +#define IS_ham(x) ((x->ftype & AM_ham) == AM_ham) +#define IS_hbrite(x) ((x->ftype & AM_hbrite) == AM_hbrite) + +#define IS_anim(x) (x->ftype & Anim) +#define IS_hamx(x) (x->ftype == AN_hamx) +#define IS_tga(x) (x->ftype & TGA) +#define IS_png(x) (x->ftype & PNG) +#define IS_openexr(x) (x->ftype & OPENEXR) +#define IS_cineon(x) (x->ftype & CINEON) +#define IS_dpx(x) (x->ftype & DPX) +#define IS_bmp(x) (x->ftype & BMP) +#define IS_tiff(x) (x->ftype & TIF) +#define IS_radhdr(x) (x->ftype & RADHDR) + +#ifdef WITH_DDS +#define IS_dds(x) (x->ftype & DDS) +#endif + +#define IMAGIC 0732 +#define IS_iris(x) (x->ftype == IMAGIC) + +#define IS_jpg(x) (x->ftype & JPG) +#define IS_stdjpg(x) ((x->ftype & JPG_MSK) == JPG_STD) +#define IS_vidjpg(x) ((x->ftype & JPG_MSK) == JPG_VID) +#define IS_jstjpg(x) ((x->ftype & JPG_MSK) == JPG_JST) +#define IS_maxjpg(x) ((x->ftype & JPG_MSK) == JPG_MAX) +/**@}*/ + +#endif + diff --git a/source/blender/imbuf/IMB_thumbs.h b/source/blender/imbuf/IMB_thumbs.h new file mode 100644 index 00000000000..4f4b77ff000 --- /dev/null +++ b/source/blender/imbuf/IMB_thumbs.h @@ -0,0 +1,74 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2007 Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Andrea Weikert. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef _IMB_THUMBS_H +#define _IMB_THUMBS_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct ImBuf; + +/** Thumbnail creation and retrieval according to the 'Thumbnail Management Standard' + * supported by Gimp, Gnome (Nautilus), KDE etc. + * Reference: http://jens.triq.net/thumbnail-spec/index.html + */ + + +typedef enum ThumbSize { + THB_NORMAL, + THB_LARGE, + THB_FAIL +} ThumbSize; + +typedef enum ThumbSource { + THB_SOURCE_IMAGE, + THB_SOURCE_MOVIE +} ThumbSource; + +// IB_imginfo + +/* create thumbnail for file and returns new imbuf for thumbnail */ +ImBuf* IMB_thumb_create(const char* dir, const char* file, ThumbSize size, ThumbSource source); + +/* read thumbnail for file and returns new imbuf for thumbnail */ +ImBuf* IMB_thumb_read(const char* dir, const char* file, ThumbSize size); + +/* delete all thumbs for the file */ +void IMB_thumb_delete(const char* dir, const char* file, ThumbSize size); + +/* return the state of the thumb, needed to determine how to manage the thumb */ +ImBuf* IMB_thumb_manage(const char* dir, const char* file, ThumbSize size, ThumbSource source); + + + + +#endif /* _IMB_THUMBS_H */ + diff --git a/source/blender/imbuf/Makefile b/source/blender/imbuf/Makefile new file mode 100644 index 00000000000..66c1f06c870 --- /dev/null +++ b/source/blender/imbuf/Makefile @@ -0,0 +1,37 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# Bounces make to subdirectories. + +SOURCEDIR = source/blender/imbuf +DIRS = intern + +include nan_subdirs.mk diff --git a/source/blender/imbuf/SConscript b/source/blender/imbuf/SConscript new file mode 100644 index 00000000000..f9e46b20d9a --- /dev/null +++ b/source/blender/imbuf/SConscript @@ -0,0 +1,34 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.c') + +incs = '. ../makesdna #/intern/guardedalloc #/intern/memutil ../blenlib' +incs += ' ../avi ../quicktime ../blenkernel' + +incs += ' ' + env['BF_JPEG_INC'] +incs += ' ' + env['BF_PNG_INC'] +incs += ' ' + env['BF_TIFF_INC'] +incs += ' ' + env['BF_ZLIB_INC'] + +defs = [] + +if env['WITH_BF_VERSE']: + defs.append('WITH_VERSE') + incs += ' ' + env['BF_VERSE_INCLUDE'] + +if env['WITH_BF_OPENEXR'] == 1: + defs.append('WITH_OPENEXR') + +if env['WITH_BF_DDS'] == 1: + defs.append('WITH_DDS') + +if env['WITH_BF_FFMPEG'] == 1: + defs.append('WITH_FFMPEG') + incs += ' ' + env['BF_FFMPEG_INC'] + +if env['WITH_BF_QUICKTIME']==1: + incs += ' ' + env['BF_QUICKTIME_INC'] + defs.append('WITH_QUICKTIME') + +env.BlenderLib ( libname = 'bf_imbuf', sources = sources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [80, 40] ) diff --git a/source/blender/imbuf/intern/IMB_allocimbuf.h b/source/blender/imbuf/intern/IMB_allocimbuf.h new file mode 100644 index 00000000000..7ff44ef29f9 --- /dev/null +++ b/source/blender/imbuf/intern/IMB_allocimbuf.h @@ -0,0 +1,59 @@ +/* + * allocimbuf.h + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + * \file IMB_allocimbuf.h + * \ingroup imbuf + * \brief Header file for allocimbuf.c + */ +#ifndef IMB_ALLOCIMBUF_H +#define IMB_ALLOCIMBUF_H + +struct ImBuf; + +short imb_addrectImBuf(struct ImBuf * ibuf); +short imb_addrectfloatImBuf(struct ImBuf * ibuf); +short imb_addplanesImBuf(struct ImBuf *ibuf); + +short imb_addencodedbufferImBuf(struct ImBuf *ibuf); +short imb_enlargeencodedbufferImBuf(struct ImBuf *ibuf); + +void imb_freerectImBuf(struct ImBuf *ibuf); +void imb_freerectfloatImBuf(struct ImBuf *ibuf); +void imb_freeplanesImBuf(struct ImBuf *ibuf); + +short imb_addcmapImBuf(struct ImBuf *ibuf); + +#endif + diff --git a/source/blender/imbuf/intern/IMB_amiga.h b/source/blender/imbuf/intern/IMB_amiga.h new file mode 100644 index 00000000000..39ca4035753 --- /dev/null +++ b/source/blender/imbuf/intern/IMB_amiga.h @@ -0,0 +1,50 @@ +/** + * IMB_amiga.h + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * \file IMB_amiga.h + * \ingroup imbuf + * \brief Function declarations for amiga.c + */ + +#ifndef IMB_AMIGA_H +#define IMB_AMIGA_H + +struct ImBuf; + +struct ImBuf *imb_loadamiga(int *iffmem,int flags); +short imb_encodebodyh(struct ImBuf *ibuf, int file); +short imb_encodebodyv(struct ImBuf *ibuf, int file); + +#endif + diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h new file mode 100644 index 00000000000..f3514a92ae4 --- /dev/null +++ b/source/blender/imbuf/intern/IMB_anim.h @@ -0,0 +1,193 @@ +/** + * allocimbuf.h + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef IMB_ANIM_H +#define IMB_ANIM_H + +#ifdef _WIN32 +#define INC_OLE2 +#include +#include +#include +#include +#include + +#ifndef FREE_WINDOWS +#include +#endif + +#undef AVIIF_KEYFRAME // redefined in AVI_avi.h +#undef AVIIF_LIST // redefined in AVI_avi.h + +#define FIXCC(fcc) if (fcc == 0) fcc = mmioFOURCC('N', 'o', 'n', 'e'); \ + if (fcc == BI_RLE8) fcc = mmioFOURCC('R', 'l', 'e', '8'); +#endif + +#include +#include +#include +#include +#ifndef _WIN32 +#include +#else +#include +#endif + +#include "BLI_blenlib.h" /* BLI_remlink BLI_filesize BLI_addtail + BLI_countlist BLI_stringdec */ + +#include "imbuf.h" +#include "imbuf_patch.h" + +#include "AVI_avi.h" + +#ifdef WITH_QUICKTIME +#if defined(_WIN32) || defined(__APPLE__) +#include "quicktime_import.h" +#endif /* _WIN32 || __APPLE__ */ +#endif /* WITH_QUICKTIME */ + +#ifdef WITH_FFMPEG +#include +#include +#include +#endif + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "IMB_allocimbuf.h" +#include "IMB_bitplanes.h" + + + +/* actually hard coded endianness */ +#define GET_BIG_LONG(x) (((uchar *) (x))[0] << 24 | ((uchar *) (x))[1] << 16 | ((uchar *) (x))[2] << 8 | ((uchar *) (x))[3]) +#define GET_LITTLE_LONG(x) (((uchar *) (x))[3] << 24 | ((uchar *) (x))[2] << 16 | ((uchar *) (x))[1] << 8 | ((uchar *) (x))[0]) +#define SWAP_L(x) (((x << 24) & 0xff000000) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | ((x >> 24) & 0xff)) +#define SWAP_S(x) (((x << 8) & 0xff00) | ((x >> 8) & 0xff)) + +/* more endianness... should move to a separate file... */ +#if defined(__sgi) || defined (__sparc) || (__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__) +#define GET_ID GET_BIG_LONG +#define LITTLE_LONG SWAP_LONG +#else +#define GET_ID GET_LITTLE_LONG +#define LITTLE_LONG ENDIAN_NOP +#endif + +/****/ + +#define ANIM_NONE (0) +#define ANIM_SEQUENCE (1 << 0) +#define ANIM_DIR (1 << 1) +#define ANIM_ANIM5 (1 << 2) +#define ANIM_TGA (1 << 3) +#define ANIM_MOVIE (1 << 4) +#define ANIM_MDEC (1 << 5) +#define ANIM_AVI (1 << 6) +#define ANIM_QTIME (1 << 7) +#define ANIM_FFMPEG (1 << 8) + +#define ANIM5_MMAP 0 +#define ANIM5_MALLOC 1 +#define ANIM5_SNGBUF 2 +#define ANIM5_XOR 4 + +#define MAXNUMSTREAMS 50 + +struct anim { + int ib_flags; + int curtype; + int curposition; /* index 0 = 1e, 1 = 2e, enz. */ + int duration; + int x, y; + + /* voor op nummer */ + char name[256]; + /* voor sequence */ + char first[256]; + + /* anim5 */ + struct ListBase anim5base; + void * anim5mmap; + int anim5len; + struct Anim5Delta *anim5curdlta; + void (*anim5decode)(struct ImBuf *, unsigned char *); + int anim5flags; + + /* movie */ + void *movie; + void *track; + void *params; + int orientation; + size_t framesize; + int interlacing; + int preseek; + + /* data */ + struct ImBuf * ibuf1, * ibuf2; + + /* avi */ + struct _AviMovie *avi; + +#if defined(_WIN32) && !defined(FREE_WINDOWS) + /* windows avi */ + int avistreams; + int firstvideo; + int pfileopen; + PAVIFILE pfile; + PAVISTREAM pavi[MAXNUMSTREAMS]; // the current streams + PGETFRAME pgf; +#endif + +#ifdef WITH_QUICKTIME + /* quicktime */ + struct _QuicktimeMovie *qtime; +#endif /* WITH_QUICKTIME */ + +#ifdef WITH_FFMPEG + AVFormatContext *pFormatCtx; + AVCodecContext *pCodecCtx; + AVCodec *pCodec; + AVFrame *pFrameRGB; + AVFrame *pFrame; + struct SwsContext *img_convert_ctx; + int videoStream; +#endif + +}; + +#endif + diff --git a/source/blender/imbuf/intern/IMB_anim5.h b/source/blender/imbuf/intern/IMB_anim5.h new file mode 100644 index 00000000000..245b3b9a9be --- /dev/null +++ b/source/blender/imbuf/intern/IMB_anim5.h @@ -0,0 +1,20 @@ +/* IMB_anim.h */ +#ifndef IMB_ANIM5_H +#define IMB_ANIM5_H + +struct anim; + +/** + * + * @attention Defined in anim5.c + */ +int nextanim5(struct anim * anim); +int rewindanim5(struct anim * anim); +int startanim5(struct anim * anim); +void free_anim_anim5(struct anim * anim); +struct ImBuf * anim5_fetchibuf(struct anim * anim); + + +#endif + + diff --git a/source/blender/imbuf/intern/IMB_bitplanes.h b/source/blender/imbuf/intern/IMB_bitplanes.h new file mode 100644 index 00000000000..643c6d57a06 --- /dev/null +++ b/source/blender/imbuf/intern/IMB_bitplanes.h @@ -0,0 +1,50 @@ +/* + * IMB_bitplanes.h + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * \file IMB_bitplanes.h + * \ingroup imbuf + * \brief Function declarations for bitplanes.c + */ + +#ifndef IMB_BITPLANES_H +#define IMB_BITPLANES_H + +struct ImBuf; + +void imb_bptolong(struct ImBuf *ibuf); +void imb_longtobp(struct ImBuf *ibuf); +unsigned int **imb_copyplanelist(struct ImBuf *ibuf); + +#endif + diff --git a/source/blender/imbuf/intern/IMB_bmp.h b/source/blender/imbuf/intern/IMB_bmp.h new file mode 100644 index 00000000000..7516c8b4add --- /dev/null +++ b/source/blender/imbuf/intern/IMB_bmp.h @@ -0,0 +1,50 @@ +/* + * IMB_bmp.h + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * \file IMB_bmp.h + * \ingroup imbuf + * \brief Function declarations for bmp.c + */ + +#ifndef IMB_BMP_H +#define IMB_BMP_H + +struct ImBuf; + +int imb_is_a_bmp(void *buf); +struct ImBuf *imb_bmp_decode(unsigned char *mem, int size, int flags); +short imb_savebmp(struct ImBuf *ibuf, char *name, int flags); + +#endif + diff --git a/source/blender/imbuf/intern/IMB_cmap.h b/source/blender/imbuf/intern/IMB_cmap.h new file mode 100644 index 00000000000..cf6c15ede91 --- /dev/null +++ b/source/blender/imbuf/intern/IMB_cmap.h @@ -0,0 +1,49 @@ +/* + * IMB_cmap.h + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * \file IMB_cmap.h + * \ingroup imbuf + * \brief Function declarations for cmap.c + */ +#ifndef IMB_CMAP_H +#define IMB_CMAP_H + +struct ImBuf; + +void imb_makecolarray(struct ImBuf *ibuf, unsigned char *mem, short nocols); +void imb_losecmapbits(struct ImBuf *ibuf, unsigned int *coltab); +short *imb_coldeltatab(unsigned char *coltab, short mincol, short maxcol, short cbits); + +#endif + diff --git a/source/blender/imbuf/intern/IMB_divers.h b/source/blender/imbuf/intern/IMB_divers.h new file mode 100644 index 00000000000..23d71d2c74d --- /dev/null +++ b/source/blender/imbuf/intern/IMB_divers.h @@ -0,0 +1,48 @@ +/* + * divers.h + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * \file IMB_divers.h + * \ingroup imbuf + * \brief Function declarations for divers.c + */ + +#ifndef IMB_DIVERS_H +#define IMB_DIVERS_H + +struct ImBuf; + +void imb_checkncols(struct ImBuf *ibuf); + +#endif + diff --git a/source/blender/imbuf/intern/IMB_dpxcineon.h b/source/blender/imbuf/intern/IMB_dpxcineon.h new file mode 100644 index 00000000000..9846d018214 --- /dev/null +++ b/source/blender/imbuf/intern/IMB_dpxcineon.h @@ -0,0 +1,47 @@ +/* + * IMB_dpxcineon.h + * + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +/** + * \file IMB_dpxcineon.h + * \ingroup imbuf + */ +#ifndef _IMB_DPX_CINEON_H +#define _IMB_DPX_CINEON_H + +struct ImBuf; + +short imb_savecineon(struct ImBuf *buf, char *myfil, int flags); +struct ImBuf *imb_loadcineon(unsigned char *mem, int size, int flags); +int imb_is_cineon(void *buf); +short imb_save_dpx(struct ImBuf *buf, char *myfile, int flags); +struct ImBuf *imb_loaddpx(unsigned char *mem, int size, int flags); +int imb_is_dpx(void *buf); + +#endif /*_IMB_DPX_CINEON_H*/ diff --git a/source/blender/imbuf/intern/IMB_filter.h b/source/blender/imbuf/intern/IMB_filter.h new file mode 100644 index 00000000000..c544ae9a04c --- /dev/null +++ b/source/blender/imbuf/intern/IMB_filter.h @@ -0,0 +1,48 @@ +/* + * filter.h + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * \file IMB_filter.h + * \ingroup imbuf + * \brief Function declarations for filter.c + */ + +#ifndef IMB_FILTER_H +#define IMB_FILTER_H + +struct ImBuf; + +void imb_filterx(struct ImBuf *ibuf); + +#endif + diff --git a/source/blender/imbuf/intern/IMB_ham.h b/source/blender/imbuf/intern/IMB_ham.h new file mode 100644 index 00000000000..e3302542198 --- /dev/null +++ b/source/blender/imbuf/intern/IMB_ham.h @@ -0,0 +1,48 @@ +/* + * IMB_ham.h + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * \file IMB_ham.h + * \ingroup imbuf + * \brief Function declarations for ham.c + */ + +#ifndef IMB_HAM_H +#define IMB_HAM_H + +struct ImBuf; + +short imb_converttoham(struct ImBuf *ibuf); + +#endif + diff --git a/source/blender/imbuf/intern/IMB_hamx.h b/source/blender/imbuf/intern/IMB_hamx.h new file mode 100644 index 00000000000..d5b23d4e685 --- /dev/null +++ b/source/blender/imbuf/intern/IMB_hamx.h @@ -0,0 +1,50 @@ +/* + * IMB_hamx.h + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * \file IMB_hamx.h + * \ingroup imbuf + * \brief Function declarations for hamx.c + */ + +#ifndef IMB_HAMX_H +#define IMB_HAMX_H + +struct ImBuf; + +struct ImBuf *imb_loadanim(int *iffmem, int flags); +short imb_enc_anim(struct ImBuf *ibuf, int file); +void imb_convhamx(struct ImBuf *ibuf, unsigned char *coltab, short *deltab); + +#endif + diff --git a/source/blender/imbuf/intern/IMB_iff.h b/source/blender/imbuf/intern/IMB_iff.h new file mode 100644 index 00000000000..c65330bad95 --- /dev/null +++ b/source/blender/imbuf/intern/IMB_iff.h @@ -0,0 +1,49 @@ +/* + * IMB_iff.h + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * \file IMB_iff.h + * \ingroup imbuf + * \brief Function declarations for iff.c + */ + +#ifndef IMB_IFF_H +#define IMB_IFF_H + +struct ImBuf; + +unsigned short imb_start_iff(struct ImBuf *ibuf, int file); +unsigned short imb_update_iff(int file, int code); + +#endif + diff --git a/source/blender/imbuf/intern/IMB_imginfo.h b/source/blender/imbuf/intern/IMB_imginfo.h new file mode 100644 index 00000000000..e82cc5f32af --- /dev/null +++ b/source/blender/imbuf/intern/IMB_imginfo.h @@ -0,0 +1,85 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Austin Benesh. Ton Roosendaal. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef _IMB_IMGINFO_H +#define _IMB_IMGINFO_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct ImBuf; + +typedef struct ImgInfo { + struct ImgInfo *next, *prev; + char* key; + char* value; + int len; +} ImgInfo; + +/** The imginfo is a list of key/value pairs (both char*) that can me + saved in the header of several image formats. + Apart from some common keys like + 'Software' and 'Description' (png standard) we'll use keys within the + Blender namespace, so should be called 'Blender::StampInfo' or 'Blender::FrameNum' + etc... +*/ + + +/* free blender ImgInfo struct */ +void IMB_imginfo_free(struct ImBuf* img); + +/** read the field from the image info into the field + * @param img - the ImBuf that contains the image data + * @param key - the key of the field + * @param value - the data in the field, first one found with key is returned, + memory has to be allocated by user. + * @param len - length of value buffer allocated by user. + * @return - 1 (true) if ImageInfo present and value for the key found, 0 (false) otherwise + */ +int IMB_imginfo_get_field(struct ImBuf* img, const char* key, char* value, int len); + +/** set user data in the ImgInfo struct, which has to be allocated with IMB_imginfo_create + * before calling this function. + * @param img - the ImBuf that contains the image data + * @param key - the key of the field + * @param value - the data to be written to the field. zero terminated string + * @return - 1 (true) if ImageInfo present, 0 (false) otherwise + */ +int IMB_imginfo_add_field(struct ImBuf* img, const char* key, const char* field); + +/** delete the key/field par in the ImgInfo struct. + * @param img - the ImBuf that contains the image data + * @param key - the key of the field + * @return - 1 (true) if delete the key/field, 0 (false) otherwise + */ +int IMB_imginfo_del_field(struct ImBuf *img, const char *key); + +#endif /* _IMB_IMGINFO_H */ + diff --git a/source/blender/imbuf/intern/IMB_iris.h b/source/blender/imbuf/intern/IMB_iris.h new file mode 100644 index 00000000000..74126a1a166 --- /dev/null +++ b/source/blender/imbuf/intern/IMB_iris.h @@ -0,0 +1,49 @@ +/* + * IMB_iris.h + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * \file IMB_iris.h + * \ingroup imbuf + * \brief Function declarations for iris.c + */ + +#ifndef IMB_IRIS_H +#define IMB_IRIS_H + +struct ImBuf; + +struct ImBuf *imb_loadiris(unsigned char *mem, int flags); +short imb_saveiris(struct ImBuf * ibuf, char *name, int flags); + +#endif + diff --git a/source/blender/imbuf/intern/IMB_jpeg.h b/source/blender/imbuf/intern/IMB_jpeg.h new file mode 100644 index 00000000000..f78810d27ee --- /dev/null +++ b/source/blender/imbuf/intern/IMB_jpeg.h @@ -0,0 +1,52 @@ +/* + * IMB_jpeg.h + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * \file IMB_jpeg.h + * \ingroup imbuf + * \brief Function declarations for jpeg.c + */ + +#ifndef IMB_JPEG_H +#define IMB_JPEG_H + +struct ImBuf; +struct jpeg_compress_struct; + +int imb_is_a_jpeg(unsigned char *mem); +int imb_savejpeg(struct ImBuf * ibuf, char * name, int flags); +struct ImBuf * imb_ibJpegImageFromFilename (const char * filename, int flags); +struct ImBuf * imb_ibJpegImageFromMemory (unsigned char * buffer, int size, int flags); + +#endif + diff --git a/source/blender/imbuf/intern/IMB_png.h b/source/blender/imbuf/intern/IMB_png.h new file mode 100644 index 00000000000..6557bfb13a0 --- /dev/null +++ b/source/blender/imbuf/intern/IMB_png.h @@ -0,0 +1,51 @@ +/* + * IMB_png.h + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * \file IMB_png.h + * \ingroup imbuf + * \brief Function declarations for png.c + */ + +#ifndef IMB_PNG_H +#define IMB_PNG_H + +struct ImBuf; + +int imb_is_a_png(void *buf); +struct ImBuf *imb_loadpng(unsigned char *mem, int size, int flags); + +short imb_savepng(struct ImBuf *ibuf, char *name, int flags); + +#endif + diff --git a/source/blender/imbuf/intern/IMB_radiance_hdr.h b/source/blender/imbuf/intern/IMB_radiance_hdr.h new file mode 100644 index 00000000000..91a8f380557 --- /dev/null +++ b/source/blender/imbuf/intern/IMB_radiance_hdr.h @@ -0,0 +1,42 @@ +/* + * IMB_radiance_hdr.h + * + * $Id: + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef IMB_RADIANCE_HDR_H +#define IMB_RADIANCE_HDR_H + +struct ImBuf; + +int imb_is_a_hdr(void *buf); + +struct ImBuf *imb_loadhdr(unsigned char *mem, int size, int flags); +short imb_savehdr(struct ImBuf * ibuf, char *name, int flags); + +#endif diff --git a/source/blender/imbuf/intern/IMB_targa.h b/source/blender/imbuf/intern/IMB_targa.h new file mode 100644 index 00000000000..2d3b1ab3288 --- /dev/null +++ b/source/blender/imbuf/intern/IMB_targa.h @@ -0,0 +1,51 @@ +/* + * IMB_targa.h + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * \file IMB_targa.h + * \ingroup imbuf + * \brief Function declarations for targa.c + */ + +#ifndef IMB_TARGA_H +#define IMB_TARGA_H + +struct ImBuf; + +int imb_is_a_targa(void *buf); + +struct ImBuf *imb_loadtarga(unsigned char *mem, int flags); +short imb_savetarga(struct ImBuf * ibuf, char *name, int flags); + +#endif + diff --git a/source/blender/imbuf/intern/IMB_tiff.h b/source/blender/imbuf/intern/IMB_tiff.h new file mode 100644 index 00000000000..b633fbffd23 --- /dev/null +++ b/source/blender/imbuf/intern/IMB_tiff.h @@ -0,0 +1,48 @@ +/* + * IMB_tiff.h + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributor(s): Jonathan Merritt. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * \file IMB_tiff.h + * \ingroup imbuf + * \brief Function declarations for tiff.c + */ + +#ifndef IMB_TIFF_H +#define IMB_TIFF_H + +/* Foward declaration of ImBuf structure. */ +struct ImBuf; + +/* Declarations for tiff.c */ +int imb_is_a_tiff(void *buf); +struct ImBuf *imb_loadtiff(unsigned char *mem, int size, int flags); +short imb_savetiff(struct ImBuf *ibuf, char *name, int flags); +void* libtiff_findsymbol(char *name); + +#endif /* IMB_TIFF_H */ + diff --git a/source/blender/imbuf/intern/Makefile b/source/blender/imbuf/intern/Makefile new file mode 100644 index 00000000000..09eb487b3a6 --- /dev/null +++ b/source/blender/imbuf/intern/Makefile @@ -0,0 +1,82 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = imbuf +DIR = $(OCGDIR)/blender/imbuf +SOURCEDIR = source/blender/imbuf/intern + +include nan_subdirs.mk +include nan_compile.mk +include nan_definitions.mk + +DIRS = cineon + +ifeq ($(WITH_OPENEXR), true) + DIRS += openexr + CFLAGS += -DWITH_OPENEXR +endif + +ifeq ($(WITH_DDS), true) + DIRS += dds + CPPFLAGS += -DWITH_DDS +endif + +CFLAGS += $(LEVEL_1_C_WARNINGS) + +CPPFLAGS += -I$(NAN_JPEG)/include +CPPFLAGS += -I$(NAN_PNG)/include +CPPFLAGS += -I$(NAN_ZLIB)/include +CPPFLAGS += -I$(NAN_TIFF)/include +CPPFLAGS += -I../../include +CPPFLAGS += -I../../blenkernel +CPPFLAGS += -I../../blenlib +CPPFLAGS += -I../../avi +CPPFLAGS += -I../../quicktime +# path to the guarded memory allocator +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include +CPPFLAGS += -I$(NAN_MEMUTIL)/include +# This is not really needed, but until /include is cleaned, it must be +# there for proper compilation. +# - No, it is also needed in antialias, for listbase (nzc) +CPPFLAGS += -I../../makesdna +# external interface of this module +CPPFLAGS += -I.. + +ifeq ($(WITH_QUICKTIME), true) + CPPFLAGS += -DWITH_QUICKTIME +endif + +ifeq ($(WITH_FFMPEG), true) + CPPFLAGS += -DWITH_FFMPEG + CPPFLAGS += $(NAN_FFMPEGCFLAGS) +endif diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c new file mode 100644 index 00000000000..a5d404740cf --- /dev/null +++ b/source/blender/imbuf/intern/allocimbuf.c @@ -0,0 +1,573 @@ +/* + * allocimbuf.c + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* It's become a bit messy... Basically, only the IMB_ prefixed files + * should remain. */ + +#include "IMB_imbuf_types.h" + +#include "imbuf.h" +#include "imbuf_patch.h" +#include "IMB_imbuf.h" + +#include "IMB_divers.h" +#include "IMB_allocimbuf.h" +#include "IMB_imginfo.h" +#include "MEM_CacheLimiterC-Api.h" + +static unsigned int dfltcmap[16] = { + 0x00000000, 0xffffffff, 0x777777ff, 0xccccccff, + 0xcc3344ff, 0xdd8844ff, 0xccdd44ff, 0x888833ff, + 0x338844ff, 0x44dd44ff, 0x44ddccff, 0x3388ccff, + 0x8888ddff, 0x4433ccff, 0xcc33ccff, 0xcc88ddff +}; + +void imb_freeplanesImBuf(struct ImBuf * ibuf) +{ + if (ibuf==NULL) return; + if (ibuf->planes){ + if (ibuf->mall & IB_planes) MEM_freeN(ibuf->planes); + } + ibuf->planes = 0; + ibuf->mall &= ~IB_planes; +} + +void imb_freemipmapImBuf(struct ImBuf * ibuf) +{ + int a; + + for(a=0; amipmap[a]) IMB_freeImBuf(ibuf->mipmap[a]); + ibuf->mipmap[a]= NULL; + } +} + +/* any free rect frees mipmaps to be sure, creation is in render on first request */ +void imb_freerectfloatImBuf(struct ImBuf * ibuf) +{ + if (ibuf==NULL) return; + + if (ibuf->rect_float) { + if (ibuf->mall & IB_rectfloat) { + MEM_freeN(ibuf->rect_float); + ibuf->rect_float=NULL; + } + } + + imb_freemipmapImBuf(ibuf); + + ibuf->rect_float= NULL; + ibuf->mall &= ~IB_rectfloat; +} + +/* any free rect frees mipmaps to be sure, creation is in render on first request */ +void imb_freerectImBuf(struct ImBuf * ibuf) +{ + if (ibuf==NULL) return; + + if (ibuf->rect) { + if (ibuf->mall & IB_rect) { + MEM_freeN(ibuf->rect); + } + } + + imb_freemipmapImBuf(ibuf); + + ibuf->rect= NULL; + ibuf->mall &= ~IB_rect; +} + +static void freeencodedbufferImBuf(struct ImBuf * ibuf) +{ + if (ibuf==NULL) return; + if (ibuf->encodedbuffer){ + if (ibuf->mall & IB_mem) MEM_freeN(ibuf->encodedbuffer); + } + ibuf->encodedbuffer = 0; + ibuf->encodedbuffersize = 0; + ibuf->encodedsize = 0; + ibuf->mall &= ~IB_mem; +} + +void IMB_freezbufImBuf(struct ImBuf * ibuf) +{ + if (ibuf==NULL) return; + if (ibuf->zbuf){ + if (ibuf->mall & IB_zbuf) MEM_freeN(ibuf->zbuf); + } + ibuf->zbuf= NULL; + ibuf->mall &= ~IB_zbuf; +} + +void IMB_freezbuffloatImBuf(struct ImBuf * ibuf) +{ + if (ibuf==NULL) return; + if (ibuf->zbuf_float){ + if (ibuf->mall & IB_zbuffloat) MEM_freeN(ibuf->zbuf_float); + } + ibuf->zbuf_float= NULL; + ibuf->mall &= ~IB_zbuffloat; +} + +void IMB_freecmapImBuf(struct ImBuf * ibuf) +{ + if (ibuf==NULL) return; + if (ibuf->cmap){ + if (ibuf->mall & IB_cmap) MEM_freeN(ibuf->cmap); + } + ibuf->cmap = 0; + ibuf->mall &= ~IB_cmap; +} + +void IMB_freeImBuf(struct ImBuf * ibuf) +{ + if (ibuf){ + if (ibuf->refcounter > 0) { + ibuf->refcounter--; + } else { + imb_freeplanesImBuf(ibuf); + imb_freerectImBuf(ibuf); + imb_freerectfloatImBuf(ibuf); + IMB_freezbufImBuf(ibuf); + IMB_freezbuffloatImBuf(ibuf); + IMB_freecmapImBuf(ibuf); + freeencodedbufferImBuf(ibuf); + IMB_cache_limiter_unmanage(ibuf); + IMB_imginfo_free(ibuf); + MEM_freeN(ibuf); + } + } +} + +void IMB_refImBuf(struct ImBuf * ibuf) +{ + ibuf->refcounter++; +} + +short addzbufImBuf(struct ImBuf * ibuf) +{ + int size; + + if (ibuf==NULL) return(FALSE); + + IMB_freezbufImBuf(ibuf); + + size = ibuf->x * ibuf->y * sizeof(unsigned int); + if ( (ibuf->zbuf = MEM_mapallocN(size, "addzbufImBuf")) ){ + ibuf->mall |= IB_zbuf; + ibuf->flags |= IB_zbuf; + return (TRUE); + } + + return (FALSE); +} + +short addzbuffloatImBuf(struct ImBuf * ibuf) +{ + int size; + + if (ibuf==NULL) return(FALSE); + + IMB_freezbuffloatImBuf(ibuf); + + size = ibuf->x * ibuf->y * sizeof(float); + if ( (ibuf->zbuf_float = MEM_mapallocN(size, "addzbuffloatImBuf")) ){ + ibuf->mall |= IB_zbuffloat; + ibuf->flags |= IB_zbuffloat; + return (TRUE); + } + + return (FALSE); +} + + +short imb_addencodedbufferImBuf(struct ImBuf * ibuf) +{ + if (ibuf==NULL) return(FALSE); + + freeencodedbufferImBuf(ibuf); + + if (ibuf->encodedbuffersize == 0) + ibuf->encodedbuffersize = 10000; + + ibuf->encodedsize = 0; + + if ( (ibuf->encodedbuffer = MEM_mallocN(ibuf->encodedbuffersize, "addencodedbufferImBuf") )){ + ibuf->mall |= IB_mem; + ibuf->flags |= IB_mem; + return (TRUE); + } + + return (FALSE); +} + + +short imb_enlargeencodedbufferImBuf(struct ImBuf * ibuf) +{ + unsigned int newsize, encodedsize; + void *newbuffer; + + if (ibuf==NULL) return(FALSE); + + if (ibuf->encodedbuffersize < ibuf->encodedsize) { + printf("imb_enlargeencodedbufferImBuf: error in parameters\n"); + return(FALSE); + } + + newsize = 2 * ibuf->encodedbuffersize; + if (newsize < 10000) newsize = 10000; + + newbuffer = MEM_mallocN(newsize, "enlargeencodedbufferImBuf"); + if (newbuffer == NULL) return(FALSE); + + if (ibuf->encodedbuffer) { + memcpy(newbuffer, ibuf->encodedbuffer, ibuf->encodedsize); + } else { + ibuf->encodedsize = 0; + } + + encodedsize = ibuf->encodedsize; + + freeencodedbufferImBuf(ibuf); + + ibuf->encodedbuffersize = newsize; + ibuf->encodedsize = encodedsize; + ibuf->encodedbuffer = newbuffer; + ibuf->mall |= IB_mem; + ibuf->flags |= IB_mem; + + return (TRUE); +} + +short imb_addrectfloatImBuf(struct ImBuf * ibuf) +{ + int size; + + if (ibuf==NULL) return(FALSE); + + imb_freerectfloatImBuf(ibuf); + + size = ibuf->x * ibuf->y; + size = size * 4 * sizeof(float); + + if ( (ibuf->rect_float = MEM_mapallocN(size, "imb_addrectfloatImBuf")) ){ + ibuf->mall |= IB_rectfloat; + ibuf->flags |= IB_rectfloat; + return (TRUE); + } + + return (FALSE); +} + +/* question; why also add zbuf? */ +short imb_addrectImBuf(struct ImBuf * ibuf) +{ + int size; + + if (ibuf==NULL) return(FALSE); + imb_freerectImBuf(ibuf); + + size = ibuf->x * ibuf->y; + size = size * sizeof(unsigned int); + + if ( (ibuf->rect = MEM_mapallocN(size, "imb_addrectImBuf")) ){ + ibuf->mall |= IB_rect; + ibuf->flags |= IB_rect; + if (ibuf->depth > 32) return (addzbufImBuf(ibuf)); + else return (TRUE); + } + + return (FALSE); +} + + +short imb_addcmapImBuf(struct ImBuf *ibuf) +{ + int min; + + if (ibuf==NULL) return(FALSE); + IMB_freecmapImBuf(ibuf); + + imb_checkncols(ibuf); + if (ibuf->maxcol == 0) return (TRUE); + + if ( (ibuf->cmap = MEM_callocN(sizeof(unsigned int) * ibuf->maxcol, "imb_addcmapImBuf") ) ){ + min = ibuf->maxcol * sizeof(unsigned int); + if (min > sizeof(dfltcmap)) min = sizeof(dfltcmap); + memcpy(ibuf->cmap, dfltcmap, min); + ibuf->mall |= IB_cmap; + ibuf->flags |= IB_cmap; + return (TRUE); + } + + return (FALSE); +} + + +short imb_addplanesImBuf(struct ImBuf *ibuf) +{ + int size; + short skipx,d,y; + unsigned int **planes; + unsigned int *point2; + + if (ibuf==NULL) return(FALSE); + imb_freeplanesImBuf(ibuf); + + skipx = ((ibuf->x+31) >> 5); + ibuf->skipx=skipx; + y=ibuf->y; + d=ibuf->depth; + + planes = MEM_mallocN( (d*skipx*y)*sizeof(int) + d*sizeof(int *), "imb_addplanesImBuf"); + + ibuf->planes = planes; + if (planes==0) return (FALSE); + + point2 = (unsigned int *)(planes+d); + size = skipx*y; + + for (;d>0;d--){ + *(planes++) = point2; + point2 += size; + } + ibuf->mall |= IB_planes; + ibuf->flags |= IB_planes; + + return (TRUE); +} + + +struct ImBuf *IMB_allocImBuf(short x, short y, uchar d, unsigned int flags, uchar bitmap) +{ + struct ImBuf *ibuf; + + ibuf = MEM_callocN(sizeof(struct ImBuf), "ImBuf_struct"); + if (bitmap) flags |= IB_planes; + + if (ibuf){ + ibuf->x= x; + ibuf->y= y; + ibuf->depth= d; + ibuf->ftype= TGA; + ibuf->channels= 4; /* float option, is set to other values when buffers get assigned */ + + if (flags & IB_rect){ + if (imb_addrectImBuf(ibuf)==FALSE){ + IMB_freeImBuf(ibuf); + return NULL; + } + } + + if (flags & IB_rectfloat){ + if (imb_addrectfloatImBuf(ibuf)==FALSE){ + IMB_freeImBuf(ibuf); + return NULL; + } + } + + if (flags & IB_zbuf){ + if (addzbufImBuf(ibuf)==FALSE){ + IMB_freeImBuf(ibuf); + return NULL; + } + } + + if (flags & IB_zbuffloat){ + if (addzbuffloatImBuf(ibuf)==FALSE){ + IMB_freeImBuf(ibuf); + return NULL; + } + } + + if (flags & IB_planes){ + if (imb_addplanesImBuf(ibuf)==FALSE){ + IMB_freeImBuf(ibuf); + return NULL; + } + } + } + return (ibuf); +} + +/* does no zbuffers? */ +struct ImBuf *IMB_dupImBuf(struct ImBuf *ibuf1) +{ + struct ImBuf *ibuf2, tbuf; + int flags = 0; + int a, x, y; + + if (ibuf1 == NULL) return NULL; + + if (ibuf1->rect) flags |= IB_rect; + if (ibuf1->rect_float) flags |= IB_rectfloat; + if (ibuf1->planes) flags |= IB_planes; + + x = ibuf1->x; + y = ibuf1->y; + if (ibuf1->flags & IB_fields) y *= 2; + + ibuf2 = IMB_allocImBuf(x, y, ibuf1->depth, flags, 0); + if (ibuf2 == NULL) return NULL; + + if (flags & IB_rect) + memcpy(ibuf2->rect, ibuf1->rect, x * y * sizeof(int)); + + if (flags & IB_rectfloat) + memcpy(ibuf2->rect_float, ibuf1->rect_float, 4 * x * y * sizeof(float)); + + if (flags & IB_planes) + memcpy(*(ibuf2->planes),*(ibuf1->planes),ibuf1->depth * ibuf1->skipx * y * sizeof(int)); + + if (ibuf1->encodedbuffer) { + ibuf2->encodedbuffersize = ibuf1->encodedbuffersize; + if (imb_addencodedbufferImBuf(ibuf2) == FALSE) { + IMB_freeImBuf(ibuf2); + return NULL; + } + + memcpy(ibuf2->encodedbuffer, ibuf1->encodedbuffer, ibuf1->encodedsize); + } + + /* silly trick to copy the entire contents of ibuf1 struct over to ibuf */ + tbuf = *ibuf1; + + // fix pointers + tbuf.rect = ibuf2->rect; + tbuf.rect_float = ibuf2->rect_float; + tbuf.planes = ibuf2->planes; + tbuf.cmap = ibuf2->cmap; + tbuf.encodedbuffer = ibuf2->encodedbuffer; + tbuf.zbuf= NULL; + tbuf.zbuf_float= NULL; + for(a=0; amall; + tbuf.c_handle = 0; + + // for now don't duplicate image info + tbuf.img_info = 0; + + *ibuf2 = tbuf; + + if (ibuf1->cmap){ + imb_addcmapImBuf(ibuf2); + if (ibuf2->cmap) memcpy(ibuf2->cmap,ibuf1->cmap,ibuf2->maxcol * sizeof(int)); + } + + return(ibuf2); +} + +/* support for cache limiting */ + +static void imbuf_cache_destructor(void * data) +{ + struct ImBuf * ibuf = (struct ImBuf*) data; + + imb_freeplanesImBuf(ibuf); + imb_freerectImBuf(ibuf); + imb_freerectfloatImBuf(ibuf); + IMB_freezbufImBuf(ibuf); + IMB_freezbuffloatImBuf(ibuf); + IMB_freecmapImBuf(ibuf); + freeencodedbufferImBuf(ibuf); + + ibuf->c_handle = 0; +} + +static MEM_CacheLimiterC ** get_imbuf_cache_limiter() +{ + static MEM_CacheLimiterC * c = 0; + if (!c) { + c = new_MEM_CacheLimiter(imbuf_cache_destructor); + } + return &c; +} + +void IMB_free_cache_limiter() +{ + delete_MEM_CacheLimiter(*get_imbuf_cache_limiter()); + *get_imbuf_cache_limiter() = 0; +} + +void IMB_cache_limiter_insert(struct ImBuf * i) +{ + if (!i->c_handle) { + i->c_handle = MEM_CacheLimiter_insert( + *get_imbuf_cache_limiter(), i); + MEM_CacheLimiter_ref(i->c_handle); + MEM_CacheLimiter_enforce_limits( + *get_imbuf_cache_limiter()); + MEM_CacheLimiter_unref(i->c_handle); + } +} + +void IMB_cache_limiter_unmanage(struct ImBuf * i) +{ + if (i->c_handle) { + MEM_CacheLimiter_unmanage(i->c_handle); + i->c_handle = 0; + } +} + +void IMB_cache_limiter_touch(struct ImBuf * i) +{ + if (i->c_handle) { + MEM_CacheLimiter_touch(i->c_handle); + } +} + +void IMB_cache_limiter_ref(struct ImBuf * i) +{ + if (i->c_handle) { + MEM_CacheLimiter_ref(i->c_handle); + } +} + +void IMB_cache_limiter_unref(struct ImBuf * i) +{ + if (i->c_handle) { + MEM_CacheLimiter_unref(i->c_handle); + } +} + +int IMB_cache_limiter_get_refcount(struct ImBuf * i) +{ + if (i->c_handle) { + return MEM_CacheLimiter_get_refcount(i->c_handle); + } + return 0; +} diff --git a/source/blender/imbuf/intern/amiga.c b/source/blender/imbuf/intern/amiga.c new file mode 100644 index 00000000000..d0b794c23ec --- /dev/null +++ b/source/blender/imbuf/intern/amiga.c @@ -0,0 +1,538 @@ +/** + * amiga.c + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef WIN32 +#include +#endif +#include "imbuf.h" +#include "imbuf_patch.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "BKE_global.h" + +#include "IMB_cmap.h" +#include "IMB_allocimbuf.h" +#include "IMB_bitplanes.h" +#include "IMB_amiga.h" + +/* actually hard coded endianness */ +#define GET_BIG_LONG(x) (((uchar *) (x))[0] << 24 | ((uchar *) (x))[1] << 16 | ((uchar *) (x))[2] << 8 | ((uchar *) (x))[3]) +#define GET_LITTLE_LONG(x) (((uchar *) (x))[3] << 24 | ((uchar *) (x))[2] << 16 | ((uchar *) (x))[1] << 8 | ((uchar *) (x))[0]) +#define SWAP_L(x) (((x << 24) & 0xff000000) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | ((x >> 24) & 0xff)) +#define SWAP_S(x) (((x << 8) & 0xff00) | ((x >> 8) & 0xff)) + +/* more endianness... should move to a separate file... */ +#if defined(__sgi) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__) +#define GET_ID GET_BIG_LONG +#define LITTLE_LONG SWAP_LONG +#else +#define GET_ID GET_LITTLE_LONG +#define LITTLE_LONG ENDIAN_NOP +#endif + +static uchar *decodebodyscanl(uchar *body, short bytes, uchar **list, short d) +{ + for (;d>0;d--){ + uchar *point; + short todo; + uchar i,j; + + point = *(list++); + todo=bytes; + while (todo>0){ + i = *body++; + + if (i & 128){ /* fill */ + if (i==128) continue; /* nop */ + + i=257-i; + todo-=i; + j = *(body++); + do{ + *(point++) = j; + i--; + }while (i); + } else{ /* copy */ + i++; + todo-=i; + + do{ + *(point++) = *(body++); + i--; + }while (i); + } + } + if (todo) return (0); + } + return(body); +} + + +static uchar *decodebodyh(struct ImBuf *ibuf, uchar *body) +{ + if (ibuf->y==1) { + body=decodebodyscanl(body, WIDTHB(ibuf->x), (uchar **)ibuf->planes, ibuf->depth); + } + else { + unsigned int **list; + short skipx,i,bytes,y; + + list = imb_copyplanelist(ibuf); + if (list == 0) return (0); + + y=ibuf->y; + bytes = WIDTHB(ibuf->x); + skipx = ibuf->skipx; + + for (;y>0;y--){ + body=decodebodyscanl(body, bytes, (uchar **)list, ibuf->depth); + if (body == 0) return (0); + + for (i=ibuf->depth-1;i>=0;i--){ + list[i] += skipx; + } + } + free(list); + } + return(body); +} + + +static uchar *decodebodykolum(uchar *body, short bytes, uchar **list, short d, int next) +{ + for (;d>0;d--){ + uchar *point; + short todo; + uchar i,j; + + point = *(list++); + todo=bytes; + while (todo>0){ + i = *body++; + + if (i & 128){ /* fill */ + if (i==128) continue; /* nop */ + + i=257-i; + todo-=i; + j = *body++; + do{ + *point = j; + point += next; + i--; + }while (i); + } + else{ /* copy */ + i++; + todo-=i; + + do{ + *point = *body++; + point += next; + i--; + }while (i); + } + } + if (todo) return (0); + } + return(body); +} + + +static uchar *decodebodyv(struct ImBuf *ibuf, uchar *body) +{ + uchar **list; + int skipx, i, bytes, times; + + list = (uchar **)imb_copyplanelist(ibuf); + if (list == 0) return (0); + + bytes = ibuf->y; + times = WIDTHB(ibuf->x); + skipx = ibuf->skipx << 2; + + for (;times>0;times--){ + body=decodebodykolum(body,bytes,list,ibuf->depth,skipx); + if (body == 0) return (0); + + for (i=ibuf->depth-1;i>=0;i--){ + list[i] += 1; + } + } + free(list); + return(body); +} + +static uchar *makebody(uchar **planes, short bytes, short depth, uchar *buf) +{ + uchar *bitplstart,*temp; + + register uchar last,this,*bitpl; + register short todo; + register int copy; + + bytes--; + for (;depth>0;depth--){ + bitpl = *(planes++); + bitplstart = bitpl; + todo = bytes; + last = *bitpl++; + this = *bitpl++; + copy = last^this; + while (todo>0){ + + if (copy){ + do{ + last = this; + this = *bitpl++; + if (last == this){ + if (this == bitpl[-3]){ /* three identical ones? */ + todo -= 1; /* set todo */ + break; + } + } + }while (--todo != 0); + + copy=bitpl-bitplstart; + copy -= 1; + if (todo) copy -= 2; + + temp = bitpl; + bitpl = bitplstart; + + while (copy){ + last = copy; + if (copy>MAXDAT) last = MAXDAT; + copy -= last; + *buf++ = last-1; + do{ + *buf++ = *bitpl++; + }while(--last != 0); + } + bitplstart = bitpl; + bitpl = temp; + last = this; + + copy = FALSE; + } + else{ + while (*bitpl++ == this){ /* search for first different bye */ + if (--todo == 0) break; /* or end of line */ + } + bitpl -= 1; + copy = bitpl-bitplstart; + bitplstart = bitpl; + todo -= 1; + this = *bitpl++; + + while (copy){ + if (copy>MAXRUN){ + *buf++ = -(MAXRUN-1); + *buf++ = last; + copy -= MAXRUN; + } + else{ + *buf++ = -(copy-1); + *buf++ = last; + break; + } + } + copy=TRUE; + } + } + } + return (buf); +} + + +short imb_encodebodyh(struct ImBuf *ibuf, int file) +{ + uchar *buf, *endbuf, *max; + int size, line, ok = TRUE; + unsigned int **list; + short skipx,i,y; + + line = WIDTHB(ibuf->x) * ibuf->depth; + line += (line >> 6) + 10; + size = 16 * line; + if (size < 16384) size = 16384; + + buf = (uchar *) malloc(size); + if (buf == 0) return (0); + + max = buf + size - line; + + list = imb_copyplanelist(ibuf); + if (list == 0){ + free(buf); + return (0); + } + + y=ibuf->y; + skipx = ibuf->skipx; + endbuf = buf; + + for (y=ibuf->y;y>0;y--){ + endbuf = makebody((uchar **)list, WIDTHB(ibuf->x), ibuf->depth, endbuf); + if (endbuf==0){ + ok = -20; + break; + } + if (endbuf >= max || y == 1){ + size = endbuf-buf; + if (write(file,buf,size)!=size) ok = -19; + endbuf = buf; + } + for (i=ibuf->depth-1;i>=0;i--){ + list[i] += skipx; + } + if (ok != TRUE) break; + } + free(list); + + free(buf); + return(ok); +} + + +short imb_encodebodyv(struct ImBuf *ibuf, int file) +{ + struct ImBuf *ibufv; + uchar *buf,*endbuf; + short x,offset; + + buf = (uchar *) malloc((ibuf->y + (ibuf->y >> 6) + 10) * ibuf->depth); + if (buf == 0) return (0); + + ibufv=IMB_allocImBuf((ibuf->y)<<3,1, ibuf->depth, 0, 1); + if (ibufv == 0){ + free(buf); + return (0); + } + + offset=0; + + for(x = WIDTHB(ibuf->x);x>0;x--){ + register short i; + + for(i = ibuf->depth-1 ;i>=0;i--){ + register uchar *p1,*p2; + register int skipx; + register short y; + + skipx = (ibuf->skipx)*sizeof(int *); + p1=(uchar *)ibuf->planes[i]; + p2=(uchar *)ibufv->planes[i]; + p1 += offset; + + for (y=ibuf->y;y>0;y--){ + *(p2++) = *p1; + p1 += skipx; + } + } + offset += 1; + + endbuf=makebody((uchar **)ibufv->planes, ibuf->y, ibuf->depth, buf); + if (endbuf==0) return (-20); + if (write(file,buf,endbuf-buf)!=endbuf-buf) return (-19); + } + free(buf); + IMB_freeImBuf(ibufv); + return (TRUE); +} + +static uchar *readbody(struct ImBuf *ibuf, uchar *body) +{ + int skipbuf,skipbdy,depth,y,offset = 0; + + skipbuf = ibuf->skipx; + skipbdy = WIDTHB(ibuf->x); + + for (y = ibuf->y; y> 0; y--){ + for( depth = 0; depth < ibuf->depth; depth ++){ + memcpy(ibuf->planes[depth] + offset, body, skipbdy); + body += skipbdy; + } + offset += skipbuf; + } + return body; +} + +struct ImBuf *imb_loadamiga(int *iffmem,int flags) +{ + int chunk,totlen,len,*cmap=0,cmaplen =0,*mem,ftype=0; + uchar *body=0; + struct BitMapHeader bmhd; + struct ImBuf *ibuf=0; + + mem = iffmem; + bmhd.w = 0; + + if (GET_ID(mem) != FORM) return (0); + if (GET_ID(mem+2) != ILBM) return (0); + totlen= (GET_BIG_LONG(mem+1) + 1) & ~1; + mem += 3; + totlen -= 4; + + + while(totlen > 0){ + chunk = GET_ID(mem); + len= (GET_BIG_LONG(mem+1) + 1) & ~1; + mem += 2; + + totlen -= len+8; + + switch (chunk){ + case BMHD: + memcpy(&bmhd, mem, sizeof(struct BitMapHeader)); + + bmhd.w = BIG_SHORT(bmhd.w); + bmhd.h = BIG_SHORT(bmhd.h); + bmhd.x = BIG_SHORT(bmhd.x); + bmhd.y = BIG_SHORT(bmhd.y); + bmhd.transparentColor = BIG_SHORT(bmhd.transparentColor); + bmhd.pageWidth = BIG_SHORT(bmhd.pageWidth); + bmhd.pageHeight = BIG_SHORT(bmhd.pageHeight); + + break; + case BODY: + body = (uchar *)mem; + break; + case CMAP: + cmap = mem; + cmaplen = len/3; + break; + case CAMG: + ftype = GET_BIG_LONG(mem); + break; + } + mem = (int *)((uchar *)mem +len); + if (body) break; + } + if (bmhd.w == 0) return (0); + if (body == 0) return (0); + + if (flags & IB_test) ibuf = IMB_allocImBuf(bmhd.w, bmhd.h, bmhd.nPlanes, 0, 0); + else ibuf = IMB_allocImBuf(bmhd.w, bmhd.h, bmhd.nPlanes + (bmhd.masking & 1),0,1); + + if (ibuf == 0) return (0); + + ibuf->ftype = (ftype | AMI); + + if (cmap){ + ibuf->mincol = 0; + ibuf->maxcol = cmaplen; + imb_addcmapImBuf(ibuf); + imb_makecolarray(ibuf, (uchar *)cmap, 0); + } + + if (flags & IB_test){ + if (flags & IB_freem) free(iffmem); + return(ibuf); + } + + switch (bmhd.compression){ + case 0: + body= readbody(ibuf, body); + break; + case 1: + body= decodebodyh(ibuf,body); + break; + case 2: + body= decodebodyv(ibuf,body); + ibuf->type |= IB_subdlta; + break; + } + + if (flags & IB_freem) free(iffmem); + + if (body == 0){ + free (ibuf); + return(0); + } + + /* forget stencil */ + ibuf->depth = bmhd.nPlanes; + + if (flags & IB_rect){ + imb_addrectImBuf(ibuf); + imb_bptolong(ibuf); + imb_freeplanesImBuf(ibuf); + if (ibuf->cmap){ + if ((flags & IB_cmap) == 0) IMB_applycmap(ibuf); + } else if (ibuf->depth == 18){ + int i,col; + unsigned int *rect; + + rect = ibuf->rect; + for(i=ibuf->x * ibuf->y ; i>0 ; i--){ + col = *rect; + col = ((col & 0x3f000) << 6) + ((col & 0xfc0) << 4) + ((col & 0x3f) << 2); + col += (col & 0xc0c0c0) >> 6; + *rect++ = col; + } + ibuf->depth = 24; + } else if (ibuf->depth <= 8) { /* no colormap and no 24 bits: b&w */ + uchar *rect; + int size, shift; + + if (ibuf->depth < 8){ + rect = (uchar *) ibuf->rect; + rect += 3; + shift = 8 - ibuf->depth; + for (size = ibuf->x * ibuf->y; size > 0; size --){ + rect[0] <<= shift; + rect += 4; + } + } + rect = (uchar *) ibuf->rect; + for (size = ibuf->x * ibuf->y; size > 0; size --){ + rect[1] = rect[2] = rect[3]; + rect += 4; + } + ibuf->depth = 8; + } + } + + if ((flags & IB_ttob) == 0) IMB_flipy(ibuf); + + if (ibuf) { + if (ibuf->rect) + if (G.order == B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf); + } + + return (ibuf); +} diff --git a/source/blender/imbuf/intern/anim.c b/source/blender/imbuf/intern/anim.c new file mode 100644 index 00000000000..e99c35e45ce --- /dev/null +++ b/source/blender/imbuf/intern/anim.c @@ -0,0 +1,932 @@ +/** + * anim.c + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef _WIN32 +#define INC_OLE2 +#include +#include +#include +#include +#include + +#ifndef FREE_WINDOWS +#include +#endif + +#undef AVIIF_KEYFRAME // redefined in AVI_avi.h +#undef AVIIF_LIST // redefined in AVI_avi.h + +#define FIXCC(fcc) if (fcc == 0) fcc = mmioFOURCC('N', 'o', 'n', 'e'); \ + if (fcc == BI_RLE8) fcc = mmioFOURCC('R', 'l', 'e', '8'); +#endif + +#include +#include +#include +#include +#ifndef _WIN32 +#include +#else +#include +#endif + +#include "BLI_blenlib.h" /* BLI_remlink BLI_filesize BLI_addtail + BLI_countlist BLI_stringdec */ +#include "DNA_userdef_types.h" +#include "BKE_global.h" + +#include "imbuf.h" +#include "imbuf_patch.h" + +#include "AVI_avi.h" + +#ifdef WITH_QUICKTIME +#if defined(_WIN32) || defined(__APPLE__) +#include "quicktime_import.h" +#endif /* _WIN32 || __APPLE__ */ +#endif /* WITH_QUICKTIME */ + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "IMB_allocimbuf.h" +#include "IMB_bitplanes.h" +#include "IMB_anim.h" +#include "IMB_anim5.h" + +#ifdef WITH_FFMPEG +#include +#include +#include +#include + +#if LIBAVFORMAT_VERSION_INT < (49 << 16) +#define FFMPEG_OLD_FRAME_RATE 1 +#else +#define FFMPEG_CODEC_IS_POINTER 1 +#endif + +#endif + +/****/ + +#ifdef __sgi + +#include + +static void movie_printerror(char * str) { + const char * errstr = mvGetErrorStr(mvGetErrno()); + + if (str) { + if (errstr) printf("%s: %s\n", str, errstr); + else printf("%s: returned error\n", str); + } else printf("%s\n", errstr); +} + +static int startmovie(struct anim * anim) { + if (anim == 0) return(-1); + + if ( mvOpenFile (anim->name, O_BINARY|O_RDONLY, &anim->movie ) != DM_SUCCESS ) { + printf("Can't open movie: %s\n", anim->name); + return(-1); + } + if ( mvFindTrackByMedium (anim->movie, DM_IMAGE, &anim->track) != DM_SUCCESS ) { + printf("No image track in movie: %s\n", anim->name); + mvClose(anim->movie); + return(-1); + } + + anim->duration = mvGetTrackLength (anim->track); + anim->params = mvGetParams( anim->track ); + + anim->x = dmParamsGetInt( anim->params, DM_IMAGE_WIDTH); + anim->y = dmParamsGetInt( anim->params, DM_IMAGE_HEIGHT); + anim->interlacing = dmParamsGetEnum (anim->params, DM_IMAGE_INTERLACING); + anim->orientation = dmParamsGetEnum (anim->params, DM_IMAGE_ORIENTATION); + anim->framesize = dmImageFrameSize(anim->params); + + anim->curposition = 0; + anim->preseek = 0; + + /*printf("x:%d y:%d size:%d interl:%d dur:%d\n", anim->x, anim->y, anim->framesize, anim->interlacing, anim->duration);*/ + return (0); +} + +static ImBuf * movie_fetchibuf(struct anim * anim, int position) { + ImBuf * ibuf; +/* extern rectcpy(); */ + int size; + unsigned int *rect1, *rect2; + + if (anim == 0) return (0); + + ibuf = IMB_allocImBuf(anim->x, anim->y, 24, IB_rect, 0); + + if ( mvReadFrames(anim->track, position, 1, ibuf->x * ibuf->y * + sizeof(int), ibuf->rect ) != DM_SUCCESS ) { + movie_printerror("mvReadFrames"); + IMB_freeImBuf(ibuf); + return(0); + } + +/* + if (anim->interlacing == DM_IMAGE_INTERLACED_EVEN) { + rect1 = ibuf->rect + (ibuf->x * ibuf->y) - 1; + rect2 = rect1 - ibuf->x; + + for (size = ibuf->x * (ibuf->y - 1); size > 0; size--){ + *rect1-- = *rect2--; + } + } +*/ + + if (anim->interlacing == DM_IMAGE_INTERLACED_EVEN) + { + rect1 = ibuf->rect; + rect2 = rect1 + ibuf->x; + + for (size = ibuf->x * (ibuf->y - 1); size > 0; size--){ + *rect1++ = *rect2++; + } + } + /*if (anim->orientation == DM_TOP_TO_BOTTOM) IMB_flipy(ibuf);*/ + + + return(ibuf); +} + +static void free_anim_movie(struct anim * anim) { + if (anim == NULL) return; + + if (anim->movie) { + mvClose(anim->movie); + anim->movie = NULL; + } + anim->duration = 0; +} + +int ismovie(char *name) { + return (mvIsMovieFile(name) == DM_TRUE); +} + +#else + +int ismovie(char *name) { + return 0; +} + + /* never called, just keep the linker happy */ +static int startmovie(struct anim * anim) { return 1; } +static ImBuf * movie_fetchibuf(struct anim * anim, int position) { return NULL; } +static void free_anim_movie(struct anim * anim) { ; } + +#endif + +static int an_stringdec(char *string, char* kop, char *staart,unsigned short *numlen) { + unsigned short len,nume,nums=0; + short i,found=FALSE; + + len=strlen(string); + nume = len; + + for(i=len-1;i>=0;i--){ + if (string[i]=='/') break; + if (isdigit(string[i])) { + if (found){ + nums=i; + } else{ + nume=i; + nums=i; + found=TRUE; + } + } else{ + if (found) break; + } + } + if (found){ + strcpy(staart,&string[nume+1]); + strcpy(kop,string); + kop[nums]=0; + *numlen=nume-nums+1; + return ((int)atoi(&(string[nums]))); + } + staart[0]=0; + strcpy(kop,string); + *numlen=0; + return (1); +} + + +static void an_stringenc(char *string, char *kop, char *staart, +unsigned short numlen, int pic) { + char numstr[10]; + unsigned short len,i; + + len=sprintf(numstr,"%d",pic); + + strcpy(string,kop); + for(i=len;iavi == NULL) return; + + AVI_close (anim->avi); + MEM_freeN (anim->avi); + anim->avi = NULL; + +#if defined(_WIN32) && !defined(FREE_WINDOWS) + + if (anim->pgf) { + AVIStreamGetFrameClose(anim->pgf); + anim->pgf = NULL; + } + + for (i = 0; i < anim->avistreams; i++){ + AVIStreamRelease(anim->pavi[i]); + } + anim->avistreams = 0; + + if (anim->pfileopen) { + AVIFileRelease(anim->pfile); + anim->pfileopen = 0; + AVIFileExit(); + } +#endif + + anim->duration = 0; +} + +void IMB_free_anim_ibuf(struct anim * anim) { + if (anim == NULL) return; + + if (anim->ibuf1) IMB_freeImBuf(anim->ibuf1); + if (anim->ibuf2) IMB_freeImBuf(anim->ibuf2); + + anim->ibuf1 = anim->ibuf2 = NULL; +} + +#ifdef WITH_FFMPEG +static void free_anim_ffmpeg(struct anim * anim); +#endif + +void IMB_free_anim(struct anim * anim) { + if (anim == NULL) { + printf("free anim, anim == NULL\n"); + return; + } + + IMB_free_anim_ibuf(anim); + free_anim_anim5(anim); + free_anim_movie(anim); + free_anim_avi(anim); + +#ifdef WITH_QUICKTIME + free_anim_quicktime(anim); +#endif +#ifdef WITH_FFMPEG + free_anim_ffmpeg(anim); +#endif + + free(anim); +} + +void IMB_close_anim(struct anim * anim) { + if (anim == 0) return; + + IMB_free_anim(anim); +} + + +struct anim * IMB_open_anim( const char * name, int ib_flags) { + struct anim * anim; + + anim = (struct anim*)MEM_callocN(sizeof(struct anim), "anim struct"); + if (anim != NULL) { + strcpy(anim->name, name); /* fixme: possible buffer overflow here? */ + anim->ib_flags = ib_flags; + } + return(anim); +} + + +static int startavi (struct anim *anim) { + + AviError avierror; +#if defined(_WIN32) && !defined(FREE_WINDOWS) + HRESULT hr; + int i, firstvideo = -1; + BYTE abFormat[1024]; + LONG l; + LPBITMAPINFOHEADER lpbi; + AVISTREAMINFO avis; +#endif + + anim->avi = MEM_callocN (sizeof(AviMovie),"animavi"); + + if (anim->avi == NULL) { + printf("Can't open avi: %s\n", anim->name); + return -1; + } + + avierror = AVI_open_movie (anim->name, anim->avi); + +#if defined(_WIN32) && !defined(FREE_WINDOWS) + if (avierror == AVI_ERROR_COMPRESSION) { + AVIFileInit(); + hr = AVIFileOpen(&anim->pfile, anim->name, OF_READ, 0L); + if (hr == 0) { + anim->pfileopen = 1; + for (i = 0; i < MAXNUMSTREAMS; i++) { + if (AVIFileGetStream(anim->pfile, &anim->pavi[i], 0L, i) != AVIERR_OK) { + break; + } + + AVIStreamInfo(anim->pavi[i], &avis, sizeof(avis)); + if ((avis.fccType == streamtypeVIDEO) && (firstvideo == -1)) { + anim->pgf = AVIStreamGetFrameOpen(anim->pavi[i], NULL); + if (anim->pgf) { + firstvideo = i; + + // get stream length + anim->avi->header->TotalFrames = AVIStreamLength(anim->pavi[i]); + + // get information about images inside the stream + l = sizeof(abFormat); + AVIStreamReadFormat(anim->pavi[i], 0, &abFormat, &l); + lpbi = (LPBITMAPINFOHEADER)abFormat; + anim->avi->header->Height = lpbi->biHeight; + anim->avi->header->Width = lpbi->biWidth; + } else { + FIXCC(avis.fccHandler); + FIXCC(avis.fccType); + printf("Can't find AVI decoder for type : %4.4hs/%4.4hs\n", + (LPSTR)&avis.fccType, + (LPSTR)&avis.fccHandler); + } + } + } + + // register number of opened avistreams + anim->avistreams = i; + + // + // Couldn't get any video streams out of this file + // + if ((anim->avistreams == 0) || (firstvideo == -1)) { + avierror = AVI_ERROR_FORMAT; + } else { + avierror = AVI_ERROR_NONE; + anim->firstvideo = firstvideo; + } + } else { + AVIFileExit(); + } + } +#endif + + if (avierror != AVI_ERROR_NONE) { + AVI_print_error(avierror); + printf ("Error loading avi: %s\n", anim->name); + free_anim_avi(anim); + return -1; + } + + anim->duration = anim->avi->header->TotalFrames; + anim->params = 0; + + anim->x = anim->avi->header->Width; + anim->y = anim->avi->header->Height; + anim->interlacing = 0; + anim->orientation = 0; + anim->framesize = anim->x * anim->y * 4; + + anim->curposition = 0; + anim->preseek = 0; + + /* printf("x:%d y:%d size:%d interl:%d dur:%d\n", anim->x, anim->y, anim->framesize, anim->interlacing, anim->duration);*/ + + return 0; +} + +static ImBuf * avi_fetchibuf (struct anim *anim, int position) { + ImBuf *ibuf = NULL; + int *tmp; + int y; + + if (anim == NULL) return (NULL); + +#if defined(_WIN32) && !defined(FREE_WINDOWS) + if (anim->avistreams) { + LPBITMAPINFOHEADER lpbi; + + if (anim->pgf) { + lpbi = AVIStreamGetFrame(anim->pgf, position + AVIStreamStart(anim->pavi[anim->firstvideo])); + if (lpbi) { + ibuf = IMB_ibImageFromMemory((int *) lpbi, 100, IB_rect); +//Oh brother... + } + } + } else { +#else + if (1) { +#endif + ibuf = IMB_allocImBuf (anim->x, anim->y, 24, IB_rect, 0); + + tmp = AVI_read_frame (anim->avi, AVI_FORMAT_RGB32, position, + AVI_get_stream(anim->avi, AVIST_VIDEO, 0)); + + if (tmp == NULL) { + printf ("Error reading frame from AVI"); + IMB_freeImBuf (ibuf); + return NULL; + } + + for (y=0; y < anim->y; y++) { + memcpy (&(ibuf->rect)[((anim->y-y)-1)*anim->x], &tmp[y*anim->x], + anim->x * 4); + } + + MEM_freeN (tmp); + } + + return ibuf; +} + +#ifdef WITH_FFMPEG + +extern void do_init_ffmpeg(); + +#ifdef FFMPEG_CODEC_IS_POINTER +static AVCodecContext* get_codec_from_stream(AVStream* stream) +{ + return stream->codec; +} +#else +static AVCodecContext* get_codec_from_stream(AVStream* stream) +{ + return &stream->codec; +} +#endif + +static int startffmpeg(struct anim * anim) { + int i, videoStream; + + AVCodec *pCodec; + AVFormatContext *pFormatCtx; + AVCodecContext *pCodecCtx; + + if (anim == 0) return(-1); + + do_init_ffmpeg(); + + if(av_open_input_file(&pFormatCtx, anim->name, NULL, 0, NULL)!=0) { + return -1; + } + + if(av_find_stream_info(pFormatCtx)<0) { + av_close_input_file(pFormatCtx); + return -1; + } + + dump_format(pFormatCtx, 0, anim->name, 0); + + + /* Find the first video stream */ + videoStream=-1; + for(i=0; inb_streams; i++) + if(get_codec_from_stream(pFormatCtx->streams[i])->codec_type + == CODEC_TYPE_VIDEO) { + videoStream=i; + break; + } + + if(videoStream==-1) { + av_close_input_file(pFormatCtx); + return -1; + } + + pCodecCtx = get_codec_from_stream(pFormatCtx->streams[videoStream]); + + /* Find the decoder for the video stream */ + pCodec=avcodec_find_decoder(pCodecCtx->codec_id); + if(pCodec==NULL) { + av_close_input_file(pFormatCtx); + return -1; + } + + pCodecCtx->workaround_bugs = 1; + + if(avcodec_open(pCodecCtx, pCodec)<0) { + av_close_input_file(pFormatCtx); + return -1; + } + +#ifdef FFMPEG_OLD_FRAME_RATE + if(pCodecCtx->frame_rate>1000 && pCodecCtx->frame_rate_base==1) + pCodecCtx->frame_rate_base=1000; + + + anim->duration = pFormatCtx->duration * pCodecCtx->frame_rate + / pCodecCtx->frame_rate_base / AV_TIME_BASE; +#else + anim->duration = pFormatCtx->duration + * av_q2d(pFormatCtx->streams[videoStream]->r_frame_rate) + / AV_TIME_BASE; + +#endif + anim->params = 0; + + anim->x = pCodecCtx->width; + anim->y = pCodecCtx->height; + anim->interlacing = 0; + anim->orientation = 0; + anim->framesize = anim->x * anim->y * 4; + + anim->curposition = -1; + + anim->pFormatCtx = pFormatCtx; + anim->pCodecCtx = pCodecCtx; + anim->pCodec = pCodec; + anim->videoStream = videoStream; + + anim->pFrame = avcodec_alloc_frame(); + anim->pFrameRGB = avcodec_alloc_frame(); + + if (avpicture_get_size(PIX_FMT_RGBA32, anim->x, anim->y) + != anim->x * anim->y * 4) { + fprintf (stderr, + "ffmpeg has changed alloc scheme ... ARGHHH!\n"); + avcodec_close(anim->pCodecCtx); + av_close_input_file(anim->pFormatCtx); + av_free(anim->pFrameRGB); + av_free(anim->pFrame); + return -1; + } + + if (pCodecCtx->has_b_frames) { + anim->preseek = 25; /* FIXME: detect gopsize ... */ + } else { + anim->preseek = 0; + } + + anim->img_convert_ctx = sws_getContext( + anim->pCodecCtx->width, + anim->pCodecCtx->height, + anim->pCodecCtx->pix_fmt, + anim->pCodecCtx->width, + anim->pCodecCtx->height, + PIX_FMT_RGBA, + SWS_FAST_BILINEAR | SWS_PRINT_INFO, + NULL, NULL, NULL); + + return (0); +} + +static ImBuf * ffmpeg_fetchibuf(struct anim * anim, int position) { + ImBuf * ibuf; + int frameFinished; + AVPacket packet; + int64_t pts_to_search = 0; + int pos_found = 1; + + if (anim == 0) return (0); + + ibuf = IMB_allocImBuf(anim->x, anim->y, 24, IB_rect, 0); + + avpicture_fill((AVPicture *)anim->pFrameRGB, + (unsigned char*) ibuf->rect, + PIX_FMT_RGBA32, anim->x, anim->y); + + if (position != anim->curposition + 1) { + if (position > anim->curposition + 1 + && anim->preseek + && position - (anim->curposition + 1) < anim->preseek) { + while(av_read_frame(anim->pFormatCtx, &packet)>=0) { + if (packet.stream_index == anim->videoStream) { + avcodec_decode_video( + anim->pCodecCtx, + anim->pFrame, &frameFinished, + packet.data, packet.size); + + if (frameFinished) { + anim->curposition++; + } + } + av_free_packet(&packet); + if (position == anim->curposition+1) { + break; + } + } + } + } + + if (position != anim->curposition + 1) { +#ifdef FFMPEG_OLD_FRAME_RATE + double frame_rate = + (double) anim->pCodecCtx->frame_rate + / (double) anim->pCodecCtx->frame_rate_base; +#else + double frame_rate = + av_q2d(anim->pFormatCtx->streams[anim->videoStream] + ->r_frame_rate); +#endif + double time_base = + av_q2d(anim->pFormatCtx->streams[anim->videoStream] + ->time_base); + long long pos = (long long) (position - anim->preseek) + * AV_TIME_BASE / frame_rate; + long long st_time = anim->pFormatCtx + ->streams[anim->videoStream]->start_time; + + if (pos < 0) { + pos = 0; + } + + if (st_time != AV_NOPTS_VALUE) { + pos += st_time * AV_TIME_BASE * time_base; + } + + av_seek_frame(anim->pFormatCtx, -1, + pos, AVSEEK_FLAG_BACKWARD); + + pts_to_search = (long long) + (((double) position) / time_base / frame_rate); + if (st_time != AV_NOPTS_VALUE) { + pts_to_search += st_time; + } + + pos_found = 0; + avcodec_flush_buffers(anim->pCodecCtx); + } + + while(av_read_frame(anim->pFormatCtx, &packet)>=0) { + if(packet.stream_index == anim->videoStream) { + avcodec_decode_video(anim->pCodecCtx, + anim->pFrame, &frameFinished, + packet.data, packet.size); + + if (frameFinished && !pos_found) { + if (packet.dts >= pts_to_search) { + pos_found = 1; + } + } + + if(frameFinished && pos_found == 1) { + int * dstStride = anim->pFrameRGB->linesize; + uint8_t** dst = anim->pFrameRGB->data; + int dstStride2[4]= { -dstStride[0], 0, 0, 0 }; + uint8_t* dst2[4]= { + dst[0] + (anim->y - 1)*dstStride[0], + 0, 0, 0 }; + + sws_scale(anim->img_convert_ctx, + anim->pFrame->data, + anim->pFrame->linesize, + 0, + anim->pCodecCtx->height, + dst2, + dstStride2); + + av_free_packet(&packet); + break; + } + } + + av_free_packet(&packet); + } + + return(ibuf); +} + +static void free_anim_ffmpeg(struct anim * anim) { + if (anim == NULL) return; + + if (anim->pCodecCtx) { + avcodec_close(anim->pCodecCtx); + av_close_input_file(anim->pFormatCtx); + av_free(anim->pFrameRGB); + av_free(anim->pFrame); + sws_freeContext(anim->img_convert_ctx); + } + anim->duration = 0; +} + +#endif + + +/* probeer volgende plaatje te lezen */ +/* Geen plaatje, probeer dan volgende animatie te openen */ +/* gelukt, haal dan eerste plaatje van animatie */ + +static struct ImBuf * anim_getnew(struct anim * anim) { + struct ImBuf *ibuf = 0; + + if (anim == NULL) return(0); + + free_anim_anim5(anim); + free_anim_movie(anim); + free_anim_avi(anim); +#ifdef WITH_QUICKTIME + free_anim_quicktime(anim); +#endif +#ifdef WITH_FFMPEG + free_anim_ffmpeg(anim); +#endif + + if (anim->curtype != 0) return (0); + anim->curtype = imb_get_anim_type(anim->name); + + switch (anim->curtype) { + case ANIM_ANIM5: + if (startanim5(anim)) return (0); + ibuf = anim5_fetchibuf(anim); + break; + case ANIM_SEQUENCE: + ibuf = IMB_loadiffname(anim->name, anim->ib_flags); + if (ibuf) { + strcpy(anim->first, anim->name); + anim->duration = 1; + } + break; + case ANIM_MOVIE: + if (startmovie(anim)) return (0); + ibuf = IMB_allocImBuf (anim->x, anim->y, 24, 0, 0); /* fake */ + break; + case ANIM_AVI: + if (startavi(anim)) { + printf("couldnt start avi\n"); + return (0); + } + ibuf = IMB_allocImBuf (anim->x, anim->y, 24, 0, 0); + break; +#ifdef WITH_QUICKTIME + case ANIM_QTIME: + if (startquicktime(anim)) return (0); + ibuf = IMB_allocImBuf (anim->x, anim->y, 24, 0, 0); + break; +#endif +#ifdef WITH_FFMPEG + case ANIM_FFMPEG: + if (startffmpeg(anim)) return (0); + ibuf = IMB_allocImBuf (anim->x, anim->y, 24, 0, 0); + break; +#endif + } + + return(ibuf); +} + +struct ImBuf * IMB_anim_previewframe(struct anim * anim) { + struct ImBuf * ibuf = 0; + int position = 0; + + ibuf = IMB_anim_absolute(anim, 0); + if (ibuf) { + IMB_freeImBuf(ibuf); + position = anim->duration / 2; + ibuf = IMB_anim_absolute(anim, position); + } + return ibuf; +} + +struct ImBuf * IMB_anim_absolute(struct anim * anim, int position) { + struct ImBuf * ibuf = 0; + char head[256], tail[256]; + unsigned short digits; + int pic; + + if (anim == NULL) return(0); + + if (anim->curtype == 0) { + ibuf = anim_getnew(anim); + if (ibuf == NULL) { + return (0); + } + IMB_freeImBuf(ibuf); /* ???? */ + } + + if (position < 0) return(0); + if (position >= anim->duration) return(0); + + switch(anim->curtype) { + case ANIM_ANIM5: + if (anim->curposition > position) rewindanim5(anim); + while (anim->curposition < position) { + if (nextanim5(anim)) return (0); + } + ibuf = anim5_fetchibuf(anim); + break; + case ANIM_SEQUENCE: + pic = an_stringdec(anim->first, head, tail, &digits); + pic += position; + an_stringenc(anim->name, head, tail, digits, pic); + ibuf = IMB_loadiffname(anim->name, LI_rect); + if (ibuf) { + anim->curposition = position; + /* patch... by freeing the cmap you prevent a double apply cmap... */ + /* probably the IB_CMAP option isn't working proper + * after the abgr->rgba reconstruction + */ + IMB_freecmapImBuf(ibuf); + } + break; + case ANIM_MOVIE: + ibuf = movie_fetchibuf(anim, position); + if (ibuf) { + anim->curposition = position; + IMB_convert_rgba_to_abgr(ibuf); + } + break; + case ANIM_AVI: + ibuf = avi_fetchibuf(anim, position); + if (ibuf) anim->curposition = position; + break; +#ifdef WITH_QUICKTIME + case ANIM_QTIME: + ibuf = qtime_fetchibuf(anim, position); + if (ibuf) anim->curposition = position; + break; +#endif +#ifdef WITH_FFMPEG + case ANIM_FFMPEG: + ibuf = ffmpeg_fetchibuf(anim, position); + if (ibuf) anim->curposition = position; + break; +#endif + } + + if (ibuf) { + if (anim->ib_flags & IB_ttob) IMB_flipy(ibuf); + sprintf(ibuf->name, "%s.%04d", anim->name, anim->curposition + 1); + + } + return(ibuf); +} + +struct ImBuf * IMB_anim_nextpic(struct anim * anim) { + struct ImBuf * ibuf = 0; + + if (anim == 0) return(0); + + ibuf = IMB_anim_absolute(anim, anim->curposition + 1); + + return(ibuf); +} + +/***/ + +int IMB_anim_get_duration(struct anim *anim) { + return anim->duration; +} + +void IMB_anim_set_preseek(struct anim * anim, int preseek) +{ + anim->preseek = preseek; +} + +int IMB_anim_get_preseek(struct anim * anim) +{ + return anim->preseek; +} diff --git a/source/blender/imbuf/intern/anim5.c b/source/blender/imbuf/intern/anim5.c new file mode 100644 index 00000000000..89ddf177efe --- /dev/null +++ b/source/blender/imbuf/intern/anim5.c @@ -0,0 +1,534 @@ +/** + * anim5.c + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): phase, code torn apart from anim.c + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BLI_blenlib.h" /* BLI_remlink BLI_filesize BLI_addtail + BLI_countlist BLI_stringdec */ +#include "imbuf.h" +#include "imbuf_patch.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "IMB_cmap.h" +#include "IMB_allocimbuf.h" +#include "IMB_bitplanes.h" +#include "IMB_amiga.h" + +#include "IMB_anim.h" + +#include "IMB_anim5.h" + +typedef struct Anhd{ + unsigned char type, mask; + unsigned short w, h; + unsigned short x, y; + unsigned short abs16, abs, reala6, real; + unsigned char interleave, pad0; + unsigned short bits16, bits; + unsigned char pad[16]; +}Anhd; + +typedef struct Anim5Delta { + struct Anim5Delta * next, * prev; + void * data; + int type; +}Anim5Delta; + + +/* om anim5's te kunnen lezen, moet een aantal gegevens bijgehouden worden: + * Een lijst van pointers naar delta's, in geheugen of ge'mmap'ed + * + * Mogelijk kan er ook een 'skiptab' aangelegd worden, om sneller + * sprongen te kunnen maken. + * + * Er moeten niet direct al plaatjes gegenereed worden, dit maakt de + * routines onbruikbaar om snel naar het goede plaatje te springen. + * Een routine voert dus de delta's uit, een andere routine maakt van + * voorgrondplaatje een ibuf; + */ + + +/* + een aantal functie pointers moet geinporteerd worden, zodat er niet + nog meer library's / objects meegelinkt hoeven te worden. + + Dezelfde structuur moet ook gebruikt kunnen worden voor het wegschrijven + van animaties. Hoe geef je dit aan ? + + Hoe snel kunnen 10 .dlta's gedecomprimeerd worden + (zonder omzetten naar rect). + + 1 - zoek naar 1e plaatje, animatie die aan de eisen voldoet + 2 - probeer volgende plaatje te vinden: + anim5 - decomprimeer + sequence - teller ophogen + directory - volgende entry + 3 - geen succes ? ga naar 1. + + +*/ + +/* + 1. Initialiseer routine met toegestane reeksen, en eerste naam + - series op naam (.0001) + - directories + - anim5 animaties + - TGA delta's + - iff 24bits delta's (.delta) + + 2. haal volgende (vorige ?) plaatje op. + + 3. vrijgeven +*/ + +/* selectie volgorde is: + 1 - anim5() + 2 - name + 3 - dir +*/ + +void free_anim_anim5(struct anim * anim) { + ListBase * animbase; + Anim5Delta * delta, * next; + + if (anim == NULL) return; + + animbase = &anim->anim5base; + delta = animbase->first; + + while (delta) { + next = delta->next; + + if (delta->type == ANIM5_MALLOC) free(delta->data); + BLI_remlink(animbase, delta); + free(delta); + + delta = next; + } + + if (anim->anim5mmap && anim->anim5len) { + MEM_freeN(anim->anim5mmap); + } + + anim->anim5mmap = NULL; + anim->anim5len = 0; + anim->anim5curdlta = 0; + anim->duration = 0; +} + +static void planes_to_rect(struct ImBuf * ibuf, int flags) { + if (ibuf == 0) return; + + /* dit komt regelrecht uit de amiga.c */ + + if (flags & IB_rect && ibuf->rect == 0) { + imb_addrectImBuf(ibuf); + imb_bptolong(ibuf); + IMB_flipy(ibuf); + imb_freeplanesImBuf(ibuf); + + if (ibuf->cmap){ + if ((flags & IB_cmap) == 0) { + IMB_applycmap(ibuf); + IMB_convert_rgba_to_abgr(ibuf); + } + } else if (ibuf->depth == 18){ + int i,col; + unsigned int *rect; + + rect = ibuf->rect; + for(i=ibuf->x * ibuf->y ; i>0 ; i--){ + col = *rect; + col = ((col & 0x3f000) << 6) + ((col & 0xfc0) << 4) + + ((col & 0x3f) << 2); + col += (col & 0xc0c0c0) >> 6; + *rect++ = col; + } + ibuf->depth = 24; + } else if (ibuf->depth <= 8) { + /* geen colormap en geen 24 bits: zwartwit */ + uchar *rect; + int size, shift; + + if (ibuf->depth < 8){ + rect = (uchar *) ibuf->rect; + rect += 3; + shift = 8 - ibuf->depth; + for (size = ibuf->x * ibuf->y; size > 0; size --){ + rect[0] <<= shift; + rect += 4; + } + } + rect = (uchar *) ibuf->rect; + for (size = ibuf->x * ibuf->y; size > 0; size --){ + rect[1] = rect[2] = rect[3]; + rect += 4; + } + ibuf->depth = 8; + } + } +} + + +static void anim5decode(struct ImBuf * ibuf, uchar * dlta) { + uchar depth; + int skip; + int *ofspoint; + uchar **planes; + + /* samenstelling delta: + lijst met ofsets voor delta's per bitplane (ofspoint) + per kolom in delta (point) + aantal handelingen (noops) + code + bijbehorende data + ... + ... + */ + + dlta += 8; + + ofspoint = (int *)dlta; + skip = ibuf->skipx * sizeof(int *); + planes = (uchar **)ibuf->planes; + + for(depth=ibuf->depth ; depth>0 ; depth--){ + if (GET_BIG_LONG(ofspoint)){ + uchar *planestart; + uchar *point; + uchar x; + + point = dlta + GET_BIG_LONG(ofspoint); + planestart = planes[0]; + x = (ibuf->x + 7) >> 3; + + do{ + uchar noop; + + if ( (noop = *(point++)) ){ + uchar *plane; + uchar code; + + plane = planestart; + do{ + if ((code = *(point++))==0){ + uchar val; + + code = *(point++); + val = *(point++); + do { + plane[0] = val; + plane += skip; + } while(--code); + + } else if (code & 128){ + + code &= 0x7f; + do{ + plane[0] = *(point++); + plane += skip; + } while(--code); + + } else plane += code * skip; + + } while(--noop); + } + planestart++; + } while(--x); + } + ofspoint++; + planes++; + } +} + + +static void anim5xordecode(struct ImBuf * ibuf, uchar * dlta) { + uchar depth; + int skip; + int *ofspoint; + uchar **planes; + + /* samenstelling delta: + lijst met ofsets voor delta's per bitplane (ofspoint) + per kolom in delta (point) + aantal handelingen (noops) + code + bijbehorende data + ... + ... + */ + + dlta += 8; + + ofspoint = (int *)dlta; + skip = ibuf->skipx * sizeof(int *); + planes = (uchar **)ibuf->planes; + + for(depth=ibuf->depth ; depth>0 ; depth--){ + + if (GET_BIG_LONG(ofspoint)){ + uchar *planestart; + uchar *point; + uchar x; + + point = dlta + GET_BIG_LONG(ofspoint); + planestart = planes[0]; + x = (ibuf->x + 7) >> 3; + + do{ + uchar noop; + + if ( (noop = *(point++)) ){ + uchar *plane; + uchar code; + + plane = planestart; + do{ + if ((code = *(point++))==0){ + uchar val; + + code = *(point++); + val = *(point++); + do{ + plane[0] ^= val; + plane += skip; + }while(--code); + + } else if (code & 128){ + + code &= 0x7f; + do{ + plane[0] ^= *(point++); + plane += skip; + }while(--code); + + } else plane += code * skip; + + }while(--noop); + } + planestart++; + }while(--x); + } + ofspoint++; + planes++; + } +} + + +int nextanim5(struct anim * anim) { + Anim5Delta * delta; + struct ImBuf * ibuf; + + if (anim == 0) return(-1); + + delta = anim->anim5curdlta; + + if (delta == 0) return (-1); + + if (anim->anim5flags & ANIM5_SNGBUF) { + ibuf = anim->ibuf1; + if (ibuf == 0) return (0); + anim->anim5decode(ibuf, delta->data); + } else { + ibuf = anim->ibuf2; + if (ibuf == 0) return (0); + anim->anim5decode(ibuf, delta->data); + anim->ibuf2 = anim->ibuf1; + anim->ibuf1 = ibuf; + } + + anim->anim5curdlta = anim->anim5curdlta->next; + anim->curposition++; + + return(0); +} + +int rewindanim5(struct anim * anim) { + Anim5Delta * delta; + struct ImBuf * ibuf; + + if (anim == 0) return (-1); + + IMB_free_anim_ibuf(anim); + + delta = anim->anim5base.first; + if (delta == 0) return (-1); + + ibuf = IMB_loadiffmem(delta->data, IB_planes); + if (ibuf == 0) return(-1); + + anim->ibuf1 = ibuf; + if ((anim->anim5flags & ANIM5_SNGBUF) == 0) anim->ibuf2 = IMB_dupImBuf(ibuf); + + anim->anim5curdlta = delta->next; + anim->curposition = 0; + + return(0); +} + + +int startanim5(struct anim * anim) { + int file, buf[20], totlen; + unsigned int len; + short * mem; + ListBase * animbase; + Anim5Delta * delta; + Anhd anhd; + + /* Controles */ + + if (anim == 0) return(-1); + + file = open(anim->name,O_BINARY|O_RDONLY); + if (file < 0) return (-1); + + if (read(file, buf, 24) != 24) { + close(file); + return(-1); + } + + if ((GET_ID(buf) != FORM) || (GET_ID(buf + 2) != ANIM) + || (GET_ID(buf + 3) != FORM) || (GET_ID(buf + 5) != ILBM)){ + printf("No anim5 file %s\n",anim->name); + close(file); + return (-1); + } + + /* de hele file wordt in het geheugen gemapped */ + + totlen = BLI_filesize(file); + if (totlen && file>=0) { + lseek(file, 0L, SEEK_SET); + + mem= MEM_mallocN(totlen, "mmap"); + if (read(file, mem, totlen) != totlen) { + MEM_freeN(mem); + mem = NULL; + } + } else { + mem = NULL; + } + close (file); + + if (!mem) return (-1); + + anhd.interleave = 0; + anhd.bits = 0; + anhd.type = 5; + + anim->anim5mmap = mem; + anim->anim5len = totlen; + anim->anim5flags = 0; + anim->duration = 0; + + animbase = & anim->anim5base; + animbase->first = animbase->last = 0; + + /* eerste plaatje inlezen */ + + mem = mem + 6; + totlen -= 12; + + len = GET_BIG_LONG(mem + 2); + len = (len + 8 + 1) & ~1; + delta = NEW(Anim5Delta); + + delta->data = mem; + delta->type = ANIM5_MMAP; + + BLI_addtail(animbase, delta); + + mem += (len >> 1); + totlen -= len; + + while (totlen > 0) { + len = GET_BIG_LONG(mem + 2); + len = (len + 8 + 1) & ~1; + + switch(GET_ID(mem)){ + case FORM: + len = 12; + break; + case ANHD: + memcpy(&anhd, mem + 4, sizeof(Anhd)); + break; + case DLTA: + delta = NEW(Anim5Delta); + delta->data = mem; + delta->type = ANIM5_MMAP; + BLI_addtail(animbase, delta); + break; + } + + mem += (len >> 1); + totlen -= len; + } + + if (anhd.interleave == 1) anim->anim5flags |= ANIM5_SNGBUF; + if (BIG_SHORT(anhd.bits) & 2) anim->anim5decode = anim5xordecode; + else anim->anim5decode = anim5decode; + + /* laatste twee delta's wissen */ + + delta = animbase->last; + if (delta) { + BLI_remlink(animbase, delta); + free(delta); + } + + if ((anim->anim5flags & ANIM5_SNGBUF) == 0) { + delta = animbase->last; + if (delta) { + BLI_remlink(animbase, delta); + free(delta); + } + } + + anim->duration = BLI_countlist(animbase); + + return(rewindanim5(anim)); +} + + +struct ImBuf * anim5_fetchibuf(struct anim * anim) { + struct ImBuf * ibuf; + + if (anim == 0) return (0); + + ibuf = IMB_dupImBuf(anim->ibuf1); + planes_to_rect(ibuf, anim->ib_flags); + + return(ibuf); +} + diff --git a/source/blender/imbuf/intern/antialias.c b/source/blender/imbuf/intern/antialias.c new file mode 100644 index 00000000000..bf8d0d17daf --- /dev/null +++ b/source/blender/imbuf/intern/antialias.c @@ -0,0 +1,469 @@ +/** + * antialias.c + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "imbuf.h" + +#include "BLI_blenlib.h" +#include "DNA_listBase.h" + +#include "imbuf_patch.h" +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" +#include "IMB_allocimbuf.h" + +/* how it works: + +1 - seek for a transistion in a collumn +2 - check the relationship with left and right, + +Is pixel above transition to the left or right equal to the top color, seek down + +Is pixel below transition to the left or right equal to the bottom color, seek up + +*/ + +/* there should be a funcion * to indicate if two colors are + * equal or not. + * For now we use a define + */ + + +static unsigned int anti_mask = 0xffffffff; +static int anti_a, anti_b, anti_g, anti_r; + +#define compare(x, y) ((x ^ y) & anti_mask) + +typedef struct Edge +{ + struct Edge * next, * prev; + short position; + int col1, col2; +}Edge; + +static void anti_free_listarray(int count, ListBase * listarray) +{ + int i; + + if (listarray == 0) return; + + for (i = 0; i < count; i++) BLI_freelistN(listarray + i); + MEM_freeN(listarray); +} + +static ListBase * scanimage(struct ImBuf * ibuf, int dir) +{ + int step, pixels, lines, nextline, x, y, col1, col2; + unsigned int * rect; + ListBase * listarray, * curlist; + Edge * edge; + int count; + + switch (dir) { + case 'h': + step = 1; nextline = ibuf->x; + pixels = ibuf->x; lines = ibuf->y; + break; +/* case 'v': changed so assured values for step etc.. */ + default: + step = ibuf->x; nextline = 1; + pixels = ibuf->y; lines = ibuf->x; + } + + listarray = (ListBase*)MEM_callocN((lines)* sizeof(ListBase), "listarray"); + for (y = 0; y < lines; y++){ + rect = ibuf->rect; + rect += y * nextline; + curlist = listarray + y; + + col1 = rect[0]; + count = 0; + + for (x = 0; x < pixels; x++) { + col2 = rect[0]; + if (compare(col1, col2)) { + edge = NEW(Edge); + + if (edge == NULL) return(0); + + edge->position = x; + edge->col1 = col1; + edge->col2 = col2; + BLI_addtail(curlist, edge); + col1 = col2; + count++; + if (count > 100) { + printf("\n\n%s: Aborting antialias !\n", ibuf->name); + printf("To many transitions.\nIs this a natural image ?\n\n"), + anti_free_listarray(lines, listarray); + return(0); + } + } + rect += step; + } + } + + return(listarray); +} + + +static Edge * findmatch(Edge * first, Edge * edge) +{ + Edge * match = 0; + int in = 0, out = 65535; + + if (edge->prev) in = edge->prev->position; + if (edge->next) out = edge->next->position; + + while (first) { + if (first->position < edge->position) { + if (first->col1 == edge->col1) { + if (first->position >= in) match = first; + } else if (first->col2 == edge->col2) { + if (first->next == 0) match = first; + else if (first->next->position >= edge->position) match = first; + } else if (first->col2 == edge->col1) { + match = 0; /* at 'sig saw' situations this one can be wrongly set */ + } + } else if (first->position == edge->position) { + if (first->col1 == edge->col1 || first->col2 == edge->col2) match = first; + } else { + if (match) break; /* there is one */ + + if (first->col1 == edge->col1) { + if (first->prev == 0) match = first; + else if (first->prev->position <= edge->position) match = first; + } else if (first->col2 == edge->col2) { + if (first->position <= out) match = first; + } + } + + first = first->next; + } + + return(match); +} + + +static void filterdraw(unsigned int * ldest, unsigned int * lsrce, int zero, int half, int step) +{ + uchar * src, * dst; + int count; + double weight, add; + + /* we filter the pixels at ldest between in and out with pixels from lsrce + * weight values go from 0 to 1 + */ + + + count = half - zero; + if (count < 0) count = -count; + if (count <= 1) return; + + if (zero < half) { + src = (uchar *) (lsrce + (step * zero)); + dst = (uchar *) (ldest + (step * zero)); + } else { + zero--; + src = (uchar *) (lsrce + (step * zero)); + dst = (uchar *) (ldest + (step * zero)); + step = -step; + } + + step = 4 * step; + + dst += step * (count >> 1); + src += step * (count >> 1); + + count = (count + 1) >> 1; + add = 0.5 / count; + weight = 0.5 * add; + + /* this of course gamma corrected */ + + for(; count > 0; count --) { + if (anti_a) dst[0] += weight * (src[0] - dst[0]); + if (anti_b) dst[1] += weight * (src[1] - dst[1]); + if (anti_g) dst[2] += weight * (src[2] - dst[2]); + if (anti_r) dst[3] += weight * (src[3] - dst[3]); + dst += step; + src += step; + weight += add; + } +} + +static void filterimage(struct ImBuf * ibuf, struct ImBuf * cbuf, ListBase * listarray, int dir) +{ + int step, pixels, lines, nextline, y, pos, drawboth; + unsigned int * irect, * crect; + Edge * left, * middle, * right, temp, * any; + + switch (dir) { + case 'h': + step = 1; nextline = ibuf->x; + pixels = ibuf->x; lines = ibuf->y; + break; +/* case 'v': changed so have values */ + default: + step = ibuf->x; nextline = 1; + pixels = ibuf->y; lines = ibuf->x; + } + + for (y = 1; y < lines - 1; y++){ + irect = ibuf->rect; + irect += y * nextline; + crect = cbuf->rect; + crect += y * nextline; + + middle = listarray[y].first; + while (middle) { + left = findmatch(listarray[y - 1].first, middle); + right = findmatch(listarray[y + 1].first, middle); + drawboth = FALSE; + + if (left == 0 || right == 0) { + /* edge */ + any = left; + if (right) any = right; + if (any) { + /* mirroring */ + pos = 2 * middle->position - any->position; + + if (any->position < middle->position) { + if (pos > pixels - 1) pos = pixels - 1; + if (middle->next) { + if (pos > middle->next->position) pos = middle->next->position; + } +/* if (any->next) { + if (pos > any->next->position) pos = any->next->position; + } +*/ } else { + if (pos < 0) pos = 0; + if (middle->prev) { + if (pos < middle->prev->position) pos = middle->prev->position; + } +/* if (any->prev) { + if (pos < any->prev->position) pos = any->prev->position; + } +*/ } + temp.position = pos; + if (left) right = &temp; + else left = &temp; + drawboth = TRUE; + } + } else if (left->position == middle->position || right->position == middle->position) { + /* straight piece */ + /* small corner, with one of the two at distance 2 (the other is at dist 0) ? */ + + if (abs(left->position - right->position) == 2) drawboth = TRUE; + } else if (left->position < middle->position && right->position > middle->position){ + /* stair 1 */ + drawboth = TRUE; + } else if (left->position > middle->position && right->position < middle->position){ + /* stair 2 */ + drawboth = TRUE; + } else { + /* a peek */ + drawboth = TRUE; + } + + if (drawboth) { + filterdraw(irect, crect - nextline, left->position, middle->position, step); + filterdraw(irect, crect + nextline, right->position, middle->position, step); + } + + middle = middle->next; + } + } +} + + +void IMB_antialias(struct ImBuf * ibuf) +{ + struct ImBuf * cbuf; + ListBase * listarray; + + if (ibuf == 0) return; + cbuf = IMB_dupImBuf(ibuf); + if (cbuf == 0) return; + + anti_a = (anti_mask >> 24) & 0xff; + anti_b = (anti_mask >> 16) & 0xff; + anti_g = (anti_mask >> 8) & 0xff; + anti_r = (anti_mask >> 0) & 0xff; + + listarray = scanimage(cbuf, 'h'); + if (listarray) { + filterimage(ibuf, cbuf, listarray, 'h'); + anti_free_listarray(ibuf->y, listarray); + + listarray = scanimage(cbuf, 'v'); + if (listarray) { + filterimage(ibuf, cbuf, listarray, 'v'); + anti_free_listarray(ibuf->x, listarray); + } + } + + IMB_freeImBuf(cbuf); +} + + +/* intelligent scaling */ + +static void _intel_scale(struct ImBuf * ibuf, ListBase * listarray, int dir) +{ + int step, lines, nextline, x, y, col; + unsigned int * irect, * trect; + int start, end; + Edge * left, * right; + struct ImBuf * tbuf; + + switch (dir) { + case 'h': + step = 1; nextline = ibuf->x; + lines = ibuf->y; + tbuf = IMB_double_fast_y(ibuf); + break; + case 'v': + step = 2 * ibuf->x; nextline = 1; + lines = ibuf->x; + tbuf = IMB_double_fast_x(ibuf); + break; + default: + return; + } + + if (tbuf == NULL) return; + + imb_freerectImBuf(ibuf); + + ibuf->rect = tbuf->rect; + ibuf->mall |= IB_rect; + + ibuf->x = tbuf->x; + ibuf->y = tbuf->y; + tbuf->rect = 0; + IMB_freeImBuf(tbuf); + + for (y = 0; y < lines - 2; y++){ + irect = ibuf->rect; + irect += ((2 * y) + 1) * nextline; + + left = listarray[y].first; + while (left) { + right = findmatch(listarray[y + 1].first, left); + if (right) { + if (left->col2 == right->col2) { + if (left->next && right->next) { + if (left->next->position >= right->position) { + start = ((left->position + right->position) >> 1); + end = ((left->next->position + right->next->position) >> 1); + col = left->col2; + trect = irect + (start * step); + for (x = start; x < end; x++) { + *trect = col; + trect += step; + } + } + } + } + + if (left->col1 == right->col1) { + if (left->prev && right->prev) { + if (left->prev->position <= right->position) { + end = ((left->position + right->position) >> 1); + start = ((left->prev->position + right->prev->position) >> 1); + col = left->col1; + trect = irect + (start * step); + for (x = start; x < end; x++) { + *trect = col; + trect += step; + } + } + } + } + + } + left = left->next; + } + } +} + + +void IMB_clever_double(struct ImBuf * ibuf) +{ + ListBase * listarray, * curlist; + Edge * new; + int size; + int i; + + if (ibuf == 0) return; + + size = ibuf->x; + listarray = scanimage(ibuf, 'v'); + if (listarray) { + for (i = 0; i < size; i++) { + curlist = listarray + i; + new = (Edge*)MEM_callocN(sizeof(Edge),"Edge"); + new->col2 = ibuf->rect[i]; /* upper pixel */ + new->col1 = new->col2 - 1; + BLI_addhead(curlist, new); + new = (Edge*)MEM_callocN(sizeof(Edge),"Edge"); + new->position = ibuf->y - 1; + new->col1 = ibuf->rect[i + ((ibuf->y -1) * ibuf->x)]; /* bottom pixel */ + new->col2 = new->col1 - 1; + BLI_addtail(curlist, new); + } + _intel_scale(ibuf, listarray, 'v'); + anti_free_listarray(size, listarray); + + size = ibuf->y; + listarray = scanimage(ibuf, 'h'); + if (listarray) { + for (i = 0; i < size; i++) { + curlist = listarray + i; + new = (Edge*)MEM_callocN(sizeof(Edge),"Edge"); + new->col2 = ibuf->rect[i * ibuf->x]; /* left pixel */ + new->col1 = new->col2 - 1; + BLI_addhead(curlist, new); + new = (Edge*)MEM_callocN(sizeof(Edge),"Edge"); + new->position = ibuf->x - 1; + new->col1 = ibuf->rect[((i + 1) * ibuf->x) - 1]; /* right pixel */ + new->col2 = new->col1 - 1; + BLI_addtail(curlist, new); + } + _intel_scale(ibuf, listarray, 'h'); + anti_free_listarray(size, listarray); + } + } +} diff --git a/source/blender/imbuf/intern/bitplanes.c b/source/blender/imbuf/intern/bitplanes.c new file mode 100644 index 00000000000..b80e829da08 --- /dev/null +++ b/source/blender/imbuf/intern/bitplanes.c @@ -0,0 +1,359 @@ +/** + * bitplanes.c + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "imbuf.h" +#include "BLI_blenlib.h" + +#include "imbuf_patch.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" +#include "IMB_allocimbuf.h" +#include "IMB_bitplanes.h" + +unsigned int **imb_copyplanelist(struct ImBuf *ibuf) +{ + int nobp,i; + unsigned int **listn,**listo; + + nobp=ibuf->depth; + listn= malloc(nobp*sizeof(int *)); /* make copy of bitmap */ + if (listn==0) return (0); + + listo=ibuf->planes; + for (i=nobp;i>0;i--){ + *(listn++) = *(listo++); + } + listn -= nobp; + + return (listn); +} + +static void bptolscanl(unsigned int *buf, int size, unsigned int **list, int nobp, int offset) +{ + /* converts bitplanes to a buffer with ints + by 4 dividiable amount of bitplanes, + the width of bitplanes is rounded at ints */ + + list += nobp; + + for (;nobp>0;) + { + int todo,i; + register int bp1, bp2, bp3, bp4, data; + register unsigned int *point; + int loffset; + /*register unsigned int bp1, bp2, bp3, bp4;*/ + + bp1 = bp2 = bp3 = bp4 = todo = 0; + point = buf; + loffset = offset; + + if (nobp & 1){ + list -= 1; + nobp -= 1; + for(i=size;i>0;i--) + { + if (todo==0) + { + bp1 = BIG_LONG((list[0])[loffset]); + loffset++; + todo=32; + } + + data = *point; + data<<=1; + + if (bp1<0) data+=1; + bp1<<=1; + + /* data += (bp1 >> 31); + bp1 <<= 1; + */ + *(point++)=data; + todo--; + } + } else if (nobp & 2){ + list -= 2; + nobp -= 2; + for(i=size;i>0;i--) + { + if (todo==0) + { + bp1 = BIG_LONG((list[0])[loffset]); + bp2 = BIG_LONG((list[1])[loffset]); + loffset++; + todo=32; + } + + data = *point; + data<<=2; + + if (bp1<0) data+=1; + bp1<<=1; + if (bp2<0) data+=2; + bp2<<=1; + + /* data += (bp1 >> 31) + ((bp2 & 0x80000000) >> 30); + bp1 <<= 1; bp2 <<= 1; + */ + *(point++)=data; + todo--; + } + } else{ + list -= 4; + nobp -= 4; + for(i=size;i>0;i--) + { + if (todo==0) { + bp1 = BIG_LONG((list[0])[loffset]); + bp2 = BIG_LONG((list[1])[loffset]); + bp3 = BIG_LONG((list[2])[loffset]); + bp4 = BIG_LONG((list[3])[loffset]); + loffset++; + todo=32; + } + + data = *point; + data<<=4; + + if (bp1<0) data+=1; + bp1<<=1; + if (bp2<0) data+=2; + bp2<<=1; + if (bp3<0) data+=4; + bp3<<=1; + if (bp4<0) data+=8; + bp4<<=1; + + /* data += (bp1 >> 31) \ + + ((bp2 & 0x80000000) >> 30) \ + + ((bp3 & 0x80000000) >> 29) \ + + ((bp4 & 0x80000000) >> 28); + + bp1 <<= 1; bp2 <<= 1; + bp3 <<= 1; bp4 <<= 1; + */ + + *(point++)=data; + todo--; + } + } + } +} + + +void imb_bptolong(struct ImBuf *ibuf) +{ + int nobp,i,x; + unsigned int *rect,offset; + float black[4] = {0.0,0.0,0.0,1.0}; + float clear[4] = {0.0,0.0,0.0,0.0}; + + /* first clear all ints */ + + if (ibuf == 0) return; + if (ibuf->planes == 0) return; + if (ibuf->rect == 0) imb_addrectImBuf(ibuf); + + nobp=ibuf->depth; + if (nobp != 32){ + if (nobp == 24) IMB_rectfill(ibuf, black); /* set alpha */ + else IMB_rectfill(ibuf, clear); + } + + rect= ibuf->rect; + x= ibuf->x; + offset=0; + + for (i= ibuf->y; i>0; i--){ + bptolscanl(rect, x, ibuf->planes, nobp, offset); + rect += x; + offset += ibuf->skipx; + } +} + + +static void ltobpscanl(unsigned int *rect, int x, unsigned int **list, int nobp, int offset) +{ + /* converts a buffer with ints to bitplanes. Take care, buffer + will be destroyed !*/ + + if (nobp != 32) + { + int *rect2; + int todo,j; + + rect2 = (int*)rect; + + todo = 32-nobp; + for (j = x;j>0;j--){ + *(rect2++) <<= todo; + } + } + + list += nobp; + for (;nobp>0;){ + register int bp1=0, bp2=0, bp3=0, data; + register unsigned int *point; + int i,todo; + int bp4=0,loffset; + + point = rect; + todo=32; + loffset=offset; + + if (nobp & 1){ + list -= 1; + nobp -= 1; + + for(i=x;i>0;i--){ + data = *point; + + bp1 <<= 1; + if (data<0) bp1 += 1; + data <<= 1; + + *(point++) = data; + + todo--; + if (todo == 0){ + (list[0])[loffset] = bp1; + loffset++; + todo=32; + } + } + if (todo != 32) + { + bp1 <<= todo; + (list[0])[loffset] = bp1; + } + } else if (nobp & 2){ + list -= 2; + nobp -= 2; + for(i=x;i>0;i--){ + data = *point; + + bp2 <<= 1; + if (data<0) bp2 += 1; + data <<= 1; + bp1 <<= 1; + if (data<0) bp1 += 1; + data <<= 1; + + *(point++) = data; + + todo--; + if (todo == 0){ + (list[0])[loffset] = bp1; + (list[1])[loffset] = bp2; + loffset++; + todo=32; + } + } + if (todo != 32){ + bp1 <<= todo; + bp2 <<= todo; + (list[0])[loffset] = bp1; + (list[1])[loffset] = bp2; + } + } else{ + list -= 4; + nobp -= 4; + for(i=x;i>0;i--){ + data = *point; + + bp4 <<= 1; + if (data<0) bp4 += 1; + data <<= 1; + bp3 <<= 1; + if (data<0) bp3 += 1; + data <<= 1; + bp2 <<= 1; + if (data<0) bp2 += 1; + data <<= 1; + bp1 <<= 1; + if (data<0) bp1 += 1; + data <<= 1; + + *(point++) = data; + + todo--; + if (todo == 0){ + (list[0])[loffset] = bp1; + (list[1])[loffset] = bp2; + (list[2])[loffset] = bp3; + (list[3])[loffset] = bp4; + loffset++; + todo=32; + } + } + if (todo != 32){ + bp1 <<= todo; + bp2 <<= todo; + bp3 <<= todo; + bp4 <<= todo; + (list[0])[loffset] = bp1; + (list[1])[loffset] = bp2; + (list[2])[loffset] = bp3; + (list[3])[loffset] = bp4; + } + } + } +} + + +void imb_longtobp(struct ImBuf *ibuf) +{ + /* converts a buffer with ints to bitplanes. Take care, buffer + will be destroyed !*/ + + int nobp,i,x; + unsigned int *rect,offset,*buf; + ; + + nobp = ibuf->depth; + rect=ibuf->rect; + x=ibuf->x; + offset=0; + if ((buf=malloc(x*sizeof(int)))==0) return; + + for (i=ibuf->y;i>0;i--){ + memcpy(buf, rect, x*sizeof(int)); + rect +=x ; + ltobpscanl(buf, x, ibuf->planes, nobp, offset); + offset += ibuf->skipx; + } + free(buf); +} diff --git a/source/blender/imbuf/intern/bmp.c b/source/blender/imbuf/intern/bmp.c new file mode 100644 index 00000000000..c14819c8bdf --- /dev/null +++ b/source/blender/imbuf/intern/bmp.c @@ -0,0 +1,248 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BLI_blenlib.h" + +#include "imbuf.h" +#include "imbuf_patch.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" +#include "IMB_allocimbuf.h" +#include "IMB_cmap.h" +#include "IMB_bmp.h" + +/* some code copied from article on microsoft.com, copied + here for enhanced BMP support in the future + http://www.microsoft.com/msj/defaultframe.asp?page=/msj/0197/mfcp1/mfcp1.htm&nav=/msj/0197/newnav.htm +*/ + +typedef struct BMPINFOHEADER{ + unsigned int biSize; + unsigned int biWidth; + unsigned int biHeight; + unsigned short biPlanes; + unsigned short biBitCount; + unsigned int biCompression; + unsigned int biSizeImage; + unsigned int biXPelsPerMeter; + unsigned int biYPelsPerMeter; + unsigned int biClrUsed; + unsigned int biClrImportant; +} BMPINFOHEADER; + +typedef struct BMPHEADER { + unsigned short biType; + unsigned int biSize; + unsigned short biRes1; + unsigned short biRes2; + unsigned int biOffBits; +} BMPHEADER; + +#define BMP_FILEHEADER_SIZE 14 + +static int checkbmp(unsigned char *mem) +{ + int ret_val = 0; + BMPINFOHEADER bmi; + unsigned int u; + + if (mem) { + if ((mem[0] == 'B') && (mem[1] == 'M')) { + /* skip fileheader */ + mem += BMP_FILEHEADER_SIZE; + } else { + } + + /* for systems where an int needs to be 4 bytes aligned */ + memcpy(&bmi, mem, sizeof(bmi)); + + u = LITTLE_LONG(bmi.biSize); + /* we only support uncompressed 24 or 32 bits images for now */ + if (u >= sizeof(BMPINFOHEADER)) { + if ((bmi.biCompression == 0) && (bmi.biClrUsed == 0)) { + u = LITTLE_SHORT(bmi.biBitCount); + if (u >= 16) { + ret_val = 1; + } + } + } + } + + return(ret_val); +} + +int imb_is_a_bmp(void *buf) { + + return checkbmp(buf); +} + +struct ImBuf *imb_bmp_decode(unsigned char *mem, int size, int flags) +{ + struct ImBuf *ibuf = 0; + BMPINFOHEADER bmi; + int x, y, depth, skip, i; + unsigned char *bmp, *rect; + unsigned short col; + + if (checkbmp(mem) == 0) return(0); + + if ((mem[0] == 'B') && (mem[1] == 'M')) { + /* skip fileheader */ + mem += BMP_FILEHEADER_SIZE; + } + + /* for systems where an int needs to be 4 bytes aligned */ + memcpy(&bmi, mem, sizeof(bmi)); + + skip = LITTLE_LONG(bmi.biSize); + x = LITTLE_LONG(bmi.biWidth); + y = LITTLE_LONG(bmi.biHeight); + depth = LITTLE_SHORT(bmi.biBitCount); + + /* printf("skip: %d, x: %d y: %d, depth: %d (%x)\n", skip, x, y, + depth, bmi.biBitCount); */ + /* printf("skip: %d, x: %d y: %d, depth: %d (%x)\n", skip, x, y, + depth, bmi.biBitCount); */ + if (flags & IB_test) { + ibuf = IMB_allocImBuf(x, y, depth, 0, 0); + } else { + ibuf = IMB_allocImBuf(x, y, depth, IB_rect, 0); + bmp = mem + skip; + rect = (unsigned char *) ibuf->rect; + + if (depth == 16) { + for (i = x * y; i > 0; i--) { + col = bmp[0] + (bmp[1] << 8); + rect[0] = ((col >> 10) & 0x1f) << 3; + rect[1] = ((col >> 5) & 0x1f) << 3; + rect[2] = ((col >> 0) & 0x1f) << 3; + + rect[3] = 255; + rect += 4; bmp += 2; + } + + } else if (depth == 24) { + for (i = y; i > 0; i--) { + int j; + for (j = x ; j > 0; j--) { + rect[0] = bmp[2]; + rect[1] = bmp[1]; + rect[2] = bmp[0]; + + rect[3] = 255; + rect += 4; bmp += 3; + } + /* for 24-bit images, rows are padded to multiples of 4 */ + bmp += x % 4; + } + } else if (depth == 32) { + for (i = x * y; i > 0; i--) { + rect[0] = bmp[0]; + rect[1] = bmp[1]; + rect[2] = bmp[2]; + rect[3] = bmp[3]; + rect += 4; bmp += 4; + } + } + } + + if (ibuf) { + ibuf->ftype = BMP; + } + + return(ibuf); +} + +/* Couple of helper functions for writing our data */ +static int putIntLSB(unsigned int ui,FILE *ofile) { + putc((ui>>0)&0xFF,ofile); + putc((ui>>8)&0xFF,ofile); + putc((ui>>16)&0xFF,ofile); + return putc((ui>>24)&0xFF,ofile); +} + +static int putShortLSB(unsigned short us,FILE *ofile) { + putc((us>>0)&0xFF,ofile); + return putc((us>>8)&0xFF,ofile); +} + +/* Found write info at http://users.ece.gatech.edu/~slabaugh/personal/c/bitmapUnix.c */ +short imb_savebmp(struct ImBuf *ibuf, char *name, int flags) { + + BMPINFOHEADER infoheader; + int bytesize, extrabytes, x, y, t, ptr; + uchar *data; + FILE *ofile; + + extrabytes = (4 - ibuf->x*3 % 4) % 4; + bytesize = (ibuf->x * 3 + extrabytes) * ibuf->y; + + data = (uchar *) ibuf->rect; + ofile = fopen(name,"wb"); + if (!ofile) return 0; + + putShortLSB(19778,ofile); /* "BM" */ + putIntLSB(0,ofile); /* This can be 0 for BI_RGB bitmaps */ + putShortLSB(0,ofile); /* Res1 */ + putShortLSB(0,ofile); /* Res2 */ + putIntLSB(BMP_FILEHEADER_SIZE + sizeof(infoheader),ofile); + + putIntLSB(sizeof(infoheader),ofile); + putIntLSB(ibuf->x,ofile); + putIntLSB(ibuf->y,ofile); + putShortLSB(1,ofile); + putShortLSB(24,ofile); + putIntLSB(0,ofile); + putIntLSB(bytesize + BMP_FILEHEADER_SIZE + sizeof(infoheader),ofile); + putIntLSB(0,ofile); + putIntLSB(0,ofile); + putIntLSB(0,ofile); + putIntLSB(0,ofile); + + /* Need to write out padded image data in bgr format */ + for (y=0;yy;y++) { + for (x=0;xx;x++) { + ptr=(x + y * ibuf->x) * 4; + if (putc(data[ptr+2],ofile) == EOF) return 0; + if (putc(data[ptr+1],ofile) == EOF) return 0; + if (putc(data[ptr],ofile) == EOF) return 0; + } + /* add padding here */ + for (t=0;t +#include /*for memcpy*/ + +#include "logImageLib.h" +#include "cineonlib.h" +#include "dpxlib.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "MEM_guardedalloc.h" + +static struct ImBuf *imb_load_dpx_cineon(unsigned char *mem, int use_cineon, int size, int flags) +{ + ImBuf *ibuf; + LogImageFile *image; + int x, y; + unsigned short *row, *upix; + int width, height, depth; + float *frow; + + image = logImageOpenFromMem(mem, size, use_cineon); + + if (!image) { + printf("no image!\n"); + return NULL; + } + + logImageGetSize(image, &width, &height, &depth); + + if (depth != 3) { /*need to do greyscale loading eventually.*/ + logImageClose(image); + return NULL; + } + + if (width == 0 && height == 0) { + logImageClose(image); + return NULL; + } + + ibuf = IMB_allocImBuf(width, height, 32, IB_rectfloat | flags, 0); + + row = MEM_mallocN(sizeof(unsigned short)*width*depth, "row in cineon_dpx.c"); + frow = ibuf->rect_float+width*height*4; + + for (y = 0; y < height; y++) { + logImageGetRowBytes(image, row, y); + upix = row; + frow -= width*4; + + for (x=0; xx; + height = buf->y; + depth = 3; + + if (!buf->rect_float) return 0; + + logImageSetVerbose(0); + logImage = logImageCreate(filename, use_cineon, width, height, depth); + + if (!logImage) return 0; + + logImageSetByteConversion(logImage, &conversion); + + index = 0; + line = MEM_mallocN(sizeof(unsigned short)*depth*width, "line"); + + /*note that image is flipped when sent to logImageSetRowBytes (see last passed parameter).*/ + for (j = 0; j < height; ++j) { + fline = &buf->rect_float[width*j*4]; + for (i=0; i=1.0f) fpix2[0] = 1.0f; else if (fpix2[0]<0.0f) fpix2[0]= 0.0f; + if (fpix2[1]>=1.0f) fpix2[1] = 1.0f; else if (fpix2[1]<0.0f) fpix2[1]= 0.0f; + if (fpix2[2]>=1.0f) fpix2[2] = 1.0f; else if (fpix2[2]<0.0f) fpix2[2]= 0.0f; + + pixel[0] = (unsigned short)(fpix2[0] * 65535.0f); /*float-float math is faster*/ + pixel[1] = (unsigned short)(fpix2[1] * 65535.0f); + pixel[2] = (unsigned short)(fpix2[2] * 65535.0f); + } + logImageSetRowBytes(logImage, (const unsigned short*)line, height-1-j); + } + logImageClose(logImage); + + MEM_freeN(line); + return 1; +} + +short imb_savecineon(struct ImBuf *buf, char *myfile, int flags) +{ + return imb_save_dpx_cineon(buf, myfile, 1, flags); +} + + +int imb_is_cineon(void *buf) +{ + return cineonIsMemFileCineon(buf); +} + +ImBuf *imb_loadcineon(unsigned char *mem, int size, int flags) +{ + if(imb_is_cineon(mem)) + return imb_load_dpx_cineon(mem, 1, size, flags); + return NULL; +} + +short imb_save_dpx(struct ImBuf *buf, char *myfile, int flags) +{ + return imb_save_dpx_cineon(buf, myfile, 0, flags); +} + +int imb_is_dpx(void *buf) +{ + return dpxIsMemFileCineon(buf); +} + +ImBuf *imb_loaddpx(unsigned char *mem, int size, int flags) +{ + if(imb_is_dpx(mem)) + return imb_load_dpx_cineon(mem, 0, size, flags); + return NULL; +} diff --git a/source/blender/imbuf/intern/cineon/cineonfile.h b/source/blender/imbuf/intern/cineon/cineonfile.h new file mode 100644 index 00000000000..7f6f1138902 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/cineonfile.h @@ -0,0 +1,143 @@ +/* + * Cineon image file format library definitions. + * Cineon file format structures. + * + * This header file contains private details. + * User code should generally use cineonlib.h only. + * + * Copyright 1999,2000,2001 David Hodson + * + * 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. + * + */ + +#ifndef _CINEON_FILE_H_ +#define _CINEON_FILE_H_ + +#include "logImageCore.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + U32 magic_num; /* magic number */ + U32 image_offset; /* offset to image data in bytes */ + U32 gen_hdr_size; /* generic header length in bytes */ + U32 ind_hdr_size; /* industry header length in bytes */ + U32 user_data_size; /* user-defined data length in bytes */ + U32 file_size; /* file size in bytes */ + ASCII vers[8]; /* which header format version is being used (v4.5) */ + ASCII file_name[100]; /* image file name */ + ASCII create_date[12]; /* file creation date */ + ASCII create_time[12]; /* file creation time */ + ASCII Reserved[36]; /* reserved field TBD (need to pad) */ +} CineonFileInformation; + +typedef struct { + U8 designator1; + U8 designator2; + U8 bits_per_pixel; + U8 filler; + U32 pixels_per_line; + U32 lines_per_image; + U32 ref_low_data; /* reference low data code value */ + R32 ref_low_quantity; /* reference low quantity represented */ + U32 ref_high_data; /* reference high data code value */ + R32 ref_high_quantity;/* reference high quantity represented */ +} CineonChannelInformation; + +typedef struct { + U8 orientation; /* image orientation */ + U8 channels_per_image; + U16 filler; + CineonChannelInformation channel[8]; + R32 white_point_x; + R32 white_point_y; + R32 red_primary_x; + R32 red_primary_y; + R32 green_primary_x; + R32 green_primary_y; + R32 blue_primary_x; + R32 blue_primary_y; + ASCII label[200]; + ASCII reserved[28]; +} CineonImageInformation; + +typedef struct { + U8 interleave; + U8 packing; + U8 signage; + U8 sense; + U32 line_padding; + U32 channel_padding; + ASCII reserved[20]; +} CineonFormatInformation; + +typedef struct { + S32 x_offset; + S32 y_offset; + ASCII file_name[100]; + ASCII create_date[12]; /* file creation date */ + ASCII create_time[12]; /* file creation time */ + ASCII input_device[64]; + ASCII model_number[32]; + ASCII serial_number[32]; + R32 x_input_samples_per_mm; + R32 y_input_samples_per_mm; + R32 input_device_gamma; + ASCII reserved[40]; +} CineonOriginationInformation; + +typedef struct { + CineonFileInformation fileInfo; + CineonImageInformation imageInfo; + CineonFormatInformation formatInfo; + CineonOriginationInformation originInfo; +} CineonGenericHeader; + +typedef struct { + U8 filmCode; + U8 filmType; + U8 perfOffset; + U8 filler; + U32 keycodePrefix; + U32 keycodeCount; + ASCII format[32]; + U32 framePosition; /* in sequence */ + R32 frameRate; /* frames per second */ + ASCII attribute[32]; + ASCII slate[200]; + ASCII reserved[740]; +} CineonMPISpecificInformation; + +#if 0 +/* create CineonFile from data in header */ +/* return 0 for OK */ +int readCineonGenericHeader(CineonFile* cineon, CineonGenericHeader* header); + +/* create header from data in CineonFile */ +int initCineonGenericHeader( + CineonFile* cineon, CineonGenericHeader* header, const char* imagename); + +/* Note: dump routine assumes network byte order */ +void dumpCineonGenericHeader(CineonGenericHeader* header); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _CINEON_FILE_H_ */ diff --git a/source/blender/imbuf/intern/cineon/cineonlib.c b/source/blender/imbuf/intern/cineon/cineonlib.c new file mode 100644 index 00000000000..20f4e0d4de4 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/cineonlib.c @@ -0,0 +1,802 @@ +/* + * Cineon image file format library routines. + * + * Copyright 1999,2000,2001 David Hodson + * + * 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. + * + */ + +#include "cineonlib.h" +#include "cineonfile.h" + +#include +#include +#include +#include /* strftime() */ +#include +#ifdef WIN32 +#include +#else +#include /* htonl() */ +#endif +#include /* memset */ +#include "cin_debug_stuff.h" +#include "logmemfile.h" + +static void +fillCineonFileInfo(CineonFile* cineon, CineonFileInformation* fileInfo, const char* filename) { + + time_t fileClock; + struct tm* fileTime; + + fileInfo->magic_num = htonl(CINEON_FILE_MAGIC); + fileInfo->image_offset = htonl(cineon->imageOffset); + fileInfo->gen_hdr_size = htonl( + sizeof(CineonFileInformation) + + sizeof(CineonImageInformation) + + sizeof(CineonFormatInformation) + + sizeof(CineonOriginationInformation)); + fileInfo->ind_hdr_size = 0; + fileInfo->user_data_size = 0; + fileInfo->file_size = htonl(cineon->imageOffset + cineon->height * cineon->lineBufferLength); + strcpy(fileInfo->vers, "V4.5"); + strncpy(fileInfo->file_name, filename, 99); + fileInfo->file_name[99] = 0; + + fileClock = time(0); + fileTime = localtime(&fileClock); + strftime(fileInfo->create_date, 12, "%Y:%m:%d", fileTime); + /* Question: is %Z in strftime guaranteed to return 3 chars? */ + strftime(fileInfo->create_time, 12, "%H:%M:%S%Z", fileTime); + fileInfo->create_time[11] = 0; +} + +static void +dumpCineonFileInfo(CineonFileInformation* fileInfo) { + d_printf("\n--File Information--\n"); + d_printf("Magic: %8.8lX\n", (unsigned long)ntohl(fileInfo->magic_num)); + d_printf("Image Offset %ld\n", (long)ntohl(fileInfo->image_offset)); + d_printf("Generic Header size %ld\n", (long)ntohl(fileInfo->gen_hdr_size)); + d_printf("Industry Header size %ld\n", (long)ntohl(fileInfo->ind_hdr_size)); + d_printf("User Data size %ld\n", (long)ntohl(fileInfo->user_data_size)); + d_printf("File size %ld\n", (long)ntohl(fileInfo->file_size)); + d_printf("Version \"%s\"\n", fileInfo->vers); + d_printf("File name \"%s\"\n", fileInfo->file_name); + d_printf("Creation date \"%s\"\n", fileInfo->create_date); + d_printf("Creation time \"%s\"\n", fileInfo->create_time); +} + +static void +fillCineonChannelInfo(CineonFile* cineon, CineonChannelInformation* chan, int des) { + + chan->designator1 = 0; + chan->designator2 = des; + chan->bits_per_pixel = 10; + chan->pixels_per_line = htonl(cineon->width); + chan->lines_per_image = htonl(cineon->height); + chan->ref_low_data = htonl(0); + chan->ref_low_quantity = htonf(0.0); + chan->ref_high_data = htonl(1023); + chan->ref_high_quantity = htonf(2.046); +} + +static void +dumpCineonChannelInfo(CineonChannelInformation* chan) { + d_printf(" Metric selector: %d", chan->designator1); + switch (chan->designator1) { + case 0: d_printf(" (Universal)\n"); break; + default: d_printf(" (Vendor specific)\n"); break; + } + d_printf(" Metric: %d,", chan->designator2); + switch (chan->designator2) { + case 0: d_printf(" B&W (printing density?)\n"); break; + case 1: d_printf(" Red printing density\n"); break; + case 2: d_printf(" Green printing density\n"); break; + case 3: d_printf(" Blue printing density\n"); break; + case 4: d_printf(" Red CCIR XA/11\n"); break; + case 5: d_printf(" Green CCIR XA/11\n"); break; + case 6: d_printf(" Blue CCIR XA/11\n"); break; + default: d_printf(" (unknown)\n"); break; + } + d_printf(" Bits per pixel %d\n", chan->bits_per_pixel); + d_printf(" Pixels per line %ld\n", (long)ntohl(chan->pixels_per_line)); + d_printf(" Lines per image %ld\n", (long)ntohl(chan->lines_per_image)); + d_printf(" Ref low data %ld\n", (long)ntohl(chan->ref_low_data)); + d_printf(" Ref low quantity %f\n", ntohf(chan->ref_low_quantity)); + d_printf(" Ref high data %ld\n", (long)ntohl(chan->ref_high_data)); + d_printf(" Ref high quantity %f\n", ntohf(chan->ref_high_quantity)); +} + +static void +fillCineonImageInfo(CineonFile* cineon, CineonImageInformation* imageInfo) { + + imageInfo->orientation = 0; + imageInfo->channels_per_image = cineon->depth; + + if (cineon->depth == 1) { + fillCineonChannelInfo(cineon, &imageInfo->channel[0], 0); + + } else if (cineon->depth == 3) { + fillCineonChannelInfo(cineon, &imageInfo->channel[0], 1); + fillCineonChannelInfo(cineon, &imageInfo->channel[1], 2); + fillCineonChannelInfo(cineon, &imageInfo->channel[2], 3); + } + + imageInfo->white_point_x = htonf(undefined()); + imageInfo->white_point_y = htonf(undefined()); + imageInfo->red_primary_x = htonf(undefined()); + imageInfo->red_primary_y = htonf(undefined()); + imageInfo->green_primary_x = htonf(undefined()); + imageInfo->green_primary_y = htonf(undefined()); + imageInfo->blue_primary_x = htonf(undefined()); + imageInfo->blue_primary_y = htonf(undefined()); + + strcpy(imageInfo->label, "David's Cineon writer."); + +} + +static void +dumpCineonImageInfo(CineonImageInformation* imageInfo) { + + int i; + d_printf("\n--Image Information--\n"); + d_printf("Image orientation %d,", imageInfo->orientation); + switch (imageInfo->orientation) { + case 0: d_printf(" LRTB\n"); break; + case 1: d_printf(" LRBT\n"); break; + case 2: d_printf(" RLTB\n"); break; + case 3: d_printf(" RLBT\n"); break; + case 4: d_printf(" TBLR\n"); break; + case 5: d_printf(" TBRL\n"); break; + case 6: d_printf(" BTLR\n"); break; + case 7: d_printf(" BTRL\n"); break; + default: d_printf(" (unknown)\n"); break; + } + d_printf("Channels %d\n", imageInfo->channels_per_image); + for (i = 0; i < imageInfo->channels_per_image; ++i) { + d_printf(" --Channel %d--\n", i); + dumpCineonChannelInfo(&imageInfo->channel[i]); + } + + d_printf("White point x %f\n", ntohf(imageInfo->white_point_x)); + d_printf("White point y %f\n", ntohf(imageInfo->white_point_y)); + d_printf("Red primary x %f\n", ntohf(imageInfo->red_primary_x)); + d_printf("Red primary y %f\n", ntohf(imageInfo->red_primary_y)); + d_printf("Green primary x %f\n", ntohf(imageInfo->green_primary_x)); + d_printf("Green primary y %f\n", ntohf(imageInfo->green_primary_y)); + d_printf("Blue primary x %f\n", ntohf(imageInfo->blue_primary_x)); + d_printf("Blue primary y %f\n", ntohf(imageInfo->blue_primary_y)); + d_printf("Label \"%s\"\n", imageInfo->label); +} + +static void +fillCineonFormatInfo(CineonFile* cineon, CineonFormatInformation* formatInfo) { + + formatInfo->interleave = 0; + formatInfo->packing = 5; + formatInfo->signage = 0; + formatInfo->sense = 0; + formatInfo->line_padding = htonl(0); + formatInfo->channel_padding = htonl(0); +} + +static void +dumpCineonFormatInfo(CineonFormatInformation* formatInfo) { + d_printf("\n--Format Information--\n"); + d_printf("Interleave %d,", formatInfo->interleave); + switch (formatInfo->interleave) { + case 0: d_printf(" pixel interleave\n"); break; + case 1: d_printf(" line interleave\n"); break; + case 2: d_printf(" channel interleave\n"); break; + default: d_printf(" (unknown)\n"); break; + } + d_printf("Packing %d,", formatInfo->packing); + if (formatInfo->packing & 0x80) { + d_printf(" multi pixel,"); + } else { + d_printf(" single pixel,"); + } + switch (formatInfo->packing & 0x7F) { + case 0: d_printf(" tight\n"); break; + case 1: d_printf(" byte packed left\n"); break; + case 2: d_printf(" byte packed right\n"); break; + case 3: d_printf(" word packed left\n"); break; + case 4: d_printf(" word packed right\n"); break; + case 5: d_printf(" long packed left\n"); break; + case 6: d_printf(" long packed right\n"); break; + default: d_printf(" (unknown)\n"); break; + } + d_printf("Sign %d,", formatInfo->signage); + if (formatInfo->signage) { + d_printf(" signed\n"); + } else { + d_printf(" unsigned\n"); + } + d_printf("Sense %d,", formatInfo->signage); + if (formatInfo->signage) { + d_printf(" negative\n"); + } else { + d_printf(" positive\n"); + } + d_printf("End of line padding %ld\n", (long)ntohl(formatInfo->line_padding)); + d_printf("End of channel padding %ld\n", (long)ntohl(formatInfo->channel_padding)); +} + +static void +fillCineonOriginationInfo(CineonFile* cineon, + CineonOriginationInformation* originInfo, CineonFileInformation* fileInfo) { + + originInfo->x_offset = htonl(0); + originInfo->y_offset = htonl(0); + strcpy(originInfo->file_name, fileInfo->file_name); + strcpy(originInfo->create_date, fileInfo->create_date); + strcpy(originInfo->create_time, fileInfo->create_time); + strncpy(originInfo->input_device, "David's Cineon writer", 64); + strncpy(originInfo->model_number, "Software", 32); + strncpy(originInfo->serial_number, "001", 32); + originInfo->x_input_samples_per_mm = htonf(undefined()); + originInfo->y_input_samples_per_mm = htonf(undefined()); + /* this should probably be undefined, too */ + originInfo->input_device_gamma = htonf(1.0); +} + +static void +dumpCineonOriginationInfo(CineonOriginationInformation* originInfo) { + d_printf("\n--Origination Information--\n"); + d_printf("X offset %ld\n", (long)ntohl(originInfo->x_offset)); + d_printf("Y offset %ld\n", (long)ntohl(originInfo->y_offset)); + d_printf("File name \"%s\"\n", originInfo->file_name); + d_printf("Creation date \"%s\"\n", originInfo->create_date); + d_printf("Creation time \"%s\"\n", originInfo->create_time); + d_printf("Input device \"%s\"\n", originInfo->input_device); + d_printf("Model number \"%s\"\n", originInfo->model_number); + d_printf("Serial number \"%s\"\n", originInfo->serial_number); + d_printf("Samples per mm in x %f\n", ntohf(originInfo->x_input_samples_per_mm)); + d_printf("Samples per mm in y %f\n", ntohf(originInfo->y_input_samples_per_mm)); + d_printf("Input device gamma %f\n", ntohf(originInfo->input_device_gamma)); +} + +int +initCineonGenericHeader(CineonFile* cineon, CineonGenericHeader* header, const char* imagename) { + + fillCineonFileInfo(cineon, &header->fileInfo, imagename); + fillCineonImageInfo(cineon, &header->imageInfo); + fillCineonFormatInfo(cineon, &header->formatInfo); + fillCineonOriginationInfo(cineon, &header->originInfo, &header->fileInfo); + + return 0; +} + +void +dumpCineonGenericHeader(CineonGenericHeader* header) { + dumpCineonFileInfo(&header->fileInfo); + dumpCineonImageInfo(&header->imageInfo); + dumpCineonFormatInfo(&header->formatInfo); + dumpCineonOriginationInfo(&header->originInfo); +} + +static int verbose = 0; +void +cineonSetVerbose(int verbosity) { + verbose = verbosity; +} + +static void +verboseMe(CineonFile* cineon) { + + d_printf("size %d x %d x %d\n", cineon->width, cineon->height, cineon->depth); + d_printf("ImageStart %d, lineBufferLength %d, implied length %d\n", + cineon->imageOffset, cineon->lineBufferLength * 4, + cineon->imageOffset + cineon->lineBufferLength * 4 * cineon->height); +} + +int +cineonGetRowBytes(CineonFile* cineon, unsigned short* row, int y) { + + int longsRead; + int pixelIndex; + int longIndex; + int numPixels = cineon->width * cineon->depth; + + + /* only seek if not reading consecutive lines */ + if (y != cineon->fileYPos) { + int lineOffset = cineon->imageOffset + y * cineon->lineBufferLength * 4; + if (verbose) d_printf("Seek in getRowBytes\n"); + if (logimage_fseek(cineon, lineOffset, SEEK_SET) != 0) { + if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, lineOffset); + return 1; + } + cineon->fileYPos = y; + } + + longsRead = logimage_fread(cineon->lineBuffer, 4, cineon->lineBufferLength, cineon); + if (longsRead != cineon->lineBufferLength) { + if (verbose) + { d_printf("Couldn't read line %d length %d\n", y, cineon->lineBufferLength * 4); + perror("cineonGetRowBytes"); + } + return 1; + } + + /* remember where we left the car, honey */ + ++cineon->fileYPos; + + /* convert longwords to pixels */ + pixelIndex = 0; + for (longIndex = 0; longIndex < cineon->lineBufferLength; ++longIndex) { + unsigned int t = ntohl(cineon->lineBuffer[longIndex]); + t = t >> 2; + cineon->pixelBuffer[pixelIndex+2] = (unsigned short) t & 0x3ff; + t = t >> 10; + cineon->pixelBuffer[pixelIndex+1] = (unsigned short) t & 0x3ff; + t = t >> 10; + cineon->pixelBuffer[pixelIndex] = (unsigned short) t & 0x3ff; + pixelIndex += 3; + } + + /* extract required pixels */ + for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) { + /* row[pixelIndex] = cineon->lut10[cineon->pixelBuffer[pixelIndex]]; */ + row[pixelIndex] = cineon->pixelBuffer[pixelIndex] << 6; + } + + return 0; +} + +int +cineonSetRowBytes(CineonFile* cineon, const unsigned short* row, int y) { + + int pixelIndex; + int numPixels = cineon->width * cineon->depth; + int longIndex; + int longsWritten; + + /* put new pixels into pixelBuffer */ + for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) { + /* cineon->pixelBuffer[pixelIndex] = cineon->lut8[row[pixelIndex]]; */ + cineon->pixelBuffer[pixelIndex] = row[pixelIndex] >> 6; + } + + /* pack into longwords */ + pixelIndex = 0; + for (longIndex = 0; longIndex < cineon->lineBufferLength; ++longIndex) { + unsigned int t = + (cineon->pixelBuffer[pixelIndex] << 22) | + (cineon->pixelBuffer[pixelIndex+1] << 12) | + (cineon->pixelBuffer[pixelIndex+2] << 2); + cineon->lineBuffer[longIndex] = htonl(t); + pixelIndex += 3; + } + + /* only seek if not reading consecutive lines */ + if (y != cineon->fileYPos) { + int lineOffset = cineon->imageOffset + y * cineon->lineBufferLength * 4; + if (verbose) d_printf("Seek in setRowBytes\n"); + if (logimage_fseek(cineon, lineOffset, SEEK_SET) != 0) { + if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, lineOffset); + return 1; + } + cineon->fileYPos = y; + } + + longsWritten = fwrite(cineon->lineBuffer, 4, cineon->lineBufferLength, cineon->file); + if (longsWritten != cineon->lineBufferLength) { + if (verbose) d_printf("Couldn't write line %d length %d\n", y, cineon->lineBufferLength * 4); + return 1; + } + + ++cineon->fileYPos; + + return 0; +} + +int +cineonGetRow(CineonFile* cineon, unsigned short* row, int y) { + + int longsRead; + int pixelIndex; + int longIndex; +/* int numPixels = cineon->width * cineon->depth; +*/ + /* only seek if not reading consecutive lines */ + if (y != cineon->fileYPos) { + int lineOffset = cineon->imageOffset + y * cineon->lineBufferLength * 4; + if (verbose) d_printf("Seek in getRow\n"); + if (logimage_fseek(cineon, lineOffset, SEEK_SET) != 0) { + if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, lineOffset); + return 1; + } + cineon->fileYPos = y; + } + + longsRead = logimage_fread(cineon->lineBuffer, 4, cineon->lineBufferLength, cineon); + if (longsRead != cineon->lineBufferLength) { + if (verbose) d_printf("Couldn't read line %d length %d\n", y, cineon->lineBufferLength * 4); + return 1; + } + + /* remember where we left the car, honey */ + ++cineon->fileYPos; + + /* convert longwords to pixels */ + pixelIndex = 0; + for (longIndex = 0; longIndex < cineon->lineBufferLength; ++longIndex) { + unsigned int t = ntohl(cineon->lineBuffer[longIndex]); + t = t >> 2; + row[pixelIndex+2] = (unsigned short) t & 0x3ff; + t = t >> 10; + row[pixelIndex+1] = (unsigned short) t & 0x3ff; + t = t >> 10; + row[pixelIndex] = (unsigned short) t & 0x3ff; + pixelIndex += 3; + } + + return 0; +} + +int +cineonSetRow(CineonFile* cineon, const unsigned short* row, int y) { + + int pixelIndex; +/* int numPixels = cineon->width * cineon->depth; +*/ int longIndex; + int longsWritten; + + /* pack into longwords */ + pixelIndex = 0; + for (longIndex = 0; longIndex < cineon->lineBufferLength; ++longIndex) { + unsigned int t = + (row[pixelIndex] << 22) | + (row[pixelIndex+1] << 12) | + (row[pixelIndex+2] << 2); + cineon->lineBuffer[longIndex] = htonl(t); + pixelIndex += 3; + } + + /* only seek if not reading consecutive lines */ + if (y != cineon->fileYPos) { + int lineOffset = cineon->imageOffset + y * cineon->lineBufferLength * 4; + if (verbose) d_printf("Seek in setRowBytes\n"); + if (logimage_fseek(cineon, lineOffset, SEEK_SET) != 0) { + if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, lineOffset); + return 1; + } + cineon->fileYPos = y; + } + + longsWritten = fwrite(cineon->lineBuffer, 4, cineon->lineBufferLength, cineon->file); + if (longsWritten != cineon->lineBufferLength) { + if (verbose) d_printf("Couldn't write line %d length %d\n", y, cineon->lineBufferLength * 4); + return 1; + } + + ++cineon->fileYPos; + + return 0; +} + +CineonFile* +cineonOpen(const char* filename) { + + CineonGenericHeader header; + + CineonFile* cineon = (CineonFile* )malloc(sizeof(CineonFile)); + if (cineon == 0) { + if (verbose) d_printf("Failed to malloc cineon file structure.\n"); + return 0; + } + + /* for close routine */ + cineon->file = 0; + cineon->lineBuffer = 0; + cineon->pixelBuffer = 0; + cineon->membuffer = 0; + cineon->memcursor = 0; + cineon->membuffersize = 0; + + cineon->file = fopen(filename, "rb"); + if (cineon->file == 0) { + if (verbose) d_printf("Failed to open file \"%s\".\n", filename); + cineonClose(cineon); + return 0; + } + cineon->reading = 1; + + if (logimage_fread(&header, sizeof(CineonGenericHeader), 1, cineon) == 0) { + if (verbose) d_printf("Not enough data for header in \"%s\".\n", filename); + cineonClose(cineon); + return 0; + } + + /* let's assume cineon files are always network order */ + if (header.fileInfo.magic_num != ntohl(CINEON_FILE_MAGIC)) { + if (verbose) d_printf("Bad magic number %8.8lX in \"%s\".\n", + (unsigned long)ntohl(header.fileInfo.magic_num), filename); + cineonClose(cineon); + return 0; + } + + if (header.formatInfo.packing != 5) { + if (verbose) d_printf("Can't understand packing %d\n", header.formatInfo.packing); + cineonClose(cineon); + return 0; + } + + cineon->width = ntohl(header.imageInfo.channel[0].pixels_per_line); + cineon->height = ntohl(header.imageInfo.channel[0].lines_per_image); + cineon->depth = header.imageInfo.channels_per_image; + /* cineon->bitsPerPixel = 10; */ + cineon->bitsPerPixel = header.imageInfo.channel[0].bits_per_pixel; + cineon->imageOffset = ntohl(header.fileInfo.image_offset); + + cineon->lineBufferLength = pixelsToLongs(cineon->width * cineon->depth); + cineon->lineBuffer = malloc(cineon->lineBufferLength * 4); + if (cineon->lineBuffer == 0) { + if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", cineon->lineBufferLength * 4); + cineonClose(cineon); + return 0; + } + + cineon->pixelBuffer = malloc(cineon->lineBufferLength * 3 * sizeof(unsigned short)); + if (cineon->pixelBuffer == 0) { + if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n", + (cineon->width * cineon->depth) * sizeof(unsigned short)); + cineonClose(cineon); + return 0; + } + cineon->pixelBufferUsed = 0; + + if (logimage_fseek(cineon, cineon->imageOffset, SEEK_SET) != 0) { + if (verbose) d_printf("Couldn't seek to image data at %d\n", cineon->imageOffset); + cineonClose(cineon); + return 0; + } + cineon->fileYPos = 0; + + logImageGetByteConversionDefaults(&cineon->params); + setupLut(cineon); + + cineon->getRow = &cineonGetRowBytes; + cineon->setRow = 0; + cineon->close = &cineonClose; + + if (verbose) { + verboseMe(cineon); + } + + return cineon; +} + +int cineonIsMemFileCineon(unsigned char *mem) +{ + unsigned int num; + memcpy(&num, mem, sizeof(unsigned int)); + + if (num != ntohl(CINEON_FILE_MAGIC)) { + return 0; + } else return 1; +} + +CineonFile* +cineonOpenFromMem(unsigned char *mem, unsigned int size) { + + CineonGenericHeader header; + int i; + + CineonFile* cineon = (CineonFile* )malloc(sizeof(CineonFile)); + if (cineon == 0) { + if (verbose) d_printf("Failed to malloc cineon file structure.\n"); + return 0; + } + + /* for close routine */ + cineon->file = 0; + cineon->lineBuffer = 0; + cineon->pixelBuffer = 0; + cineon->membuffer = mem; + cineon->membuffersize = size; + cineon->memcursor = mem; + + cineon->file = 0; + cineon->reading = 1; + verbose = 1; + if (size < sizeof(CineonGenericHeader)) { + if (verbose) d_printf("Not enough data for header!\n"); + cineonClose(cineon); + return 0; + } + + logimage_fread(&header, sizeof(CineonGenericHeader), 1, cineon); + + /* let's assume cineon files are always network order */ + if (header.fileInfo.magic_num != ntohl(CINEON_FILE_MAGIC)) { + if (verbose) d_printf("Bad magic number %8.8lX in\n", (unsigned long)ntohl(header.fileInfo.magic_num)); + + cineonClose(cineon); + return 0; + } + + if (header.formatInfo.packing != 5) { + if (verbose) d_printf("Can't understand packing %d\n", header.formatInfo.packing); + cineonClose(cineon); + return 0; + } + + cineon->width = ntohl(header.imageInfo.channel[0].pixels_per_line); + cineon->height = ntohl(header.imageInfo.channel[0].lines_per_image); + cineon->depth = header.imageInfo.channels_per_image; + /* cineon->bitsPerPixel = 10; */ + cineon->bitsPerPixel = header.imageInfo.channel[0].bits_per_pixel; + cineon->imageOffset = ntohl(header.fileInfo.image_offset); + + cineon->lineBufferLength = pixelsToLongs(cineon->width * cineon->depth); + cineon->lineBuffer = malloc(cineon->lineBufferLength * 4); + if (cineon->lineBuffer == 0) { + if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", cineon->lineBufferLength * 4); + cineonClose(cineon); + return 0; + } + + cineon->pixelBuffer = malloc(cineon->lineBufferLength * 3 * sizeof(unsigned short)); + if (cineon->pixelBuffer == 0) { + if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n", + (cineon->width * cineon->depth) * sizeof(unsigned short)); + cineonClose(cineon); + return 0; + } + cineon->pixelBufferUsed = 0; + + i = cineon->imageOffset; + + if (logimage_fseek(cineon, cineon->imageOffset, SEEK_SET) != 0) { + if (verbose) d_printf("Couldn't seek to image data at %d\n", cineon->imageOffset); + cineonClose(cineon); + return 0; + } + + cineon->fileYPos = 0; + + logImageGetByteConversionDefaults(&cineon->params); + setupLut(cineon); + + cineon->getRow = &cineonGetRowBytes; + cineon->setRow = 0; + cineon->close = &cineonClose; + + if (verbose) { + verboseMe(cineon); + } + + return cineon; +} + + +int +cineonGetSize(const CineonFile* cineon, int* width, int* height, int* depth) { + *width = cineon->width; + *height = cineon->height; + *depth = cineon->depth; + return 0; +} + +CineonFile* +cineonCreate(const char* filename, int width, int height, int depth) { + + /* Note: always write files in network order */ + /* By the spec, it shouldn't matter, but ... */ + + CineonGenericHeader header; + const char* shortFilename = 0; + + CineonFile* cineon = (CineonFile*)malloc(sizeof(CineonFile)); + if (cineon == 0) { + if (verbose) d_printf("Failed to malloc cineon file structure.\n"); + return 0; + } + + memset(&header, 0, sizeof(header)); + + /* for close routine */ + cineon->file = 0; + cineon->lineBuffer = 0; + cineon->pixelBuffer = 0; + + cineon->file = fopen(filename, "wb"); + if (cineon->file == 0) { + if (verbose) d_printf("Couldn't open file %s\n", filename); + cineonClose(cineon); + return 0; + } + cineon->reading = 0; + + cineon->width = width; + cineon->height = height; + cineon->depth = depth; + cineon->bitsPerPixel = 10; + cineon->imageOffset = sizeof(CineonGenericHeader); + + cineon->lineBufferLength = pixelsToLongs(cineon->width * cineon->depth); + cineon->lineBuffer = malloc(cineon->lineBufferLength * 4); + if (cineon->lineBuffer == 0) { + if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", cineon->lineBufferLength * 4); + cineonClose(cineon); + return 0; + } + + cineon->pixelBuffer = malloc(cineon->lineBufferLength * 3 * sizeof(unsigned short)); + if (cineon->pixelBuffer == 0) { + if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n", + (cineon->width * cineon->depth) * sizeof(unsigned short)); + cineonClose(cineon); + return 0; + } + cineon->pixelBufferUsed = 0; + + /* find trailing part of filename */ + shortFilename = strrchr(filename, '/'); + if (shortFilename == 0) { + shortFilename = filename; + } else { + ++shortFilename; + } + + if (initCineonGenericHeader(cineon, &header, shortFilename) != 0) { + cineonClose(cineon); + return 0; + } + + if (fwrite(&header, sizeof(header), 1, cineon->file) == 0) { + if (verbose) d_printf("Couldn't write image header\n"); + cineonClose(cineon); + return 0; + } + cineon->fileYPos = 0; + + logImageGetByteConversionDefaults(&cineon->params); + setupLut(cineon); + + cineon->getRow = 0; + cineon->setRow = &cineonSetRowBytes; + cineon->close = &cineonClose; + + return cineon; +} + +void +cineonClose(CineonFile* cineon) { + + if (cineon == 0) { + return; + } + + if (cineon->file) { + fclose(cineon->file); + cineon->file = 0; + } + + if (cineon->lineBuffer) { + free(cineon->lineBuffer); + cineon->lineBuffer = 0; + } + + if (cineon->pixelBuffer) { + free(cineon->pixelBuffer); + cineon->pixelBuffer = 0; + } + + free(cineon); +} diff --git a/source/blender/imbuf/intern/cineon/cineonlib.h b/source/blender/imbuf/intern/cineon/cineonlib.h new file mode 100644 index 00000000000..87fc7add9a6 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/cineonlib.h @@ -0,0 +1,68 @@ +/* + * Cineon image file format library definitions. + * Also handles DPX files (almost) + * + * Copyright 1999,2000,2001 David Hodson + * + * 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. + * + */ + +#ifndef _CINEON_LIB_H_ +#define _CINEON_LIB_H_ + +#include "logImageCore.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Cineon image structure. You don't care what this is. + */ + +typedef struct _Log_Image_File_t_ CineonFile; + +/* int functions return 0 for OK */ + +void cineonSetVerbose(int); + +CineonFile* cineonOpenFromMem(unsigned char *mem, unsigned int size); + +CineonFile* cineonOpen(const char* filename); +int cineonGetSize(const CineonFile* cineon, int* xsize, int* ysize, int* channels); +CineonFile* cineonCreate(const char* filename, int xsize, int ysize, int channels); +int cineonIsMemFileCineon(unsigned char *mem); + +/* get / set header block NYI */ +int cineonGetHeader(CineonFile*, int*, void**); +int cineonSetHeader(CineonFile*, int, void*); + +/* get/set scanline of converted bytes */ +int cineonGetRowBytes(CineonFile* cineon, unsigned short* row, int y); +int cineonSetRowBytes(CineonFile* cineon, const unsigned short* row, int y); + +/* get/set scanline of unconverted shorts */ +int cineonGetRow(CineonFile* cineon, unsigned short* row, int y); +int cineonSetRow(CineonFile* cineon, const unsigned short* row, int y); + +/* closes file and deletes data */ +void cineonClose(CineonFile* cineon); + +#ifdef __cplusplus +} +#endif + +#endif /* _CINEON_LIB_H_ */ diff --git a/source/blender/imbuf/intern/cineon/dpxfile.h b/source/blender/imbuf/intern/cineon/dpxfile.h new file mode 100644 index 00000000000..94145500910 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/dpxfile.h @@ -0,0 +1,124 @@ +/* + * Cineon image file format library definitions. + * Dpx file format structures. + * + * This header file contains private details. + * User code should generally use cineonlib.h only. + * + * Copyright 1999,2000,2001 David Hodson + * + * 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. + * + */ + +#ifndef _DPX_FILE_H_ +#define _DPX_FILE_H_ + +#include "logImageCore.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + U32 magic_num; /* magic number */ + U32 offset; /* offset to image data in bytes */ + ASCII vers[8]; /* which header format version is being used (v1.0) */ + U32 file_size; /* file size in bytes */ + U32 ditto_key; /* I bet some people use this */ + U32 gen_hdr_size; /* generic header length in bytes */ + U32 ind_hdr_size; /* industry header length in bytes */ + U32 user_data_size; /* user-defined data length in bytes */ + ASCII file_name[100]; /* image file name */ + ASCII create_date[24]; /* file creation date, yyyy:mm:dd:hh:mm:ss:LTZ */ + ASCII creator[100]; + ASCII project[200]; + ASCII copyright[200]; + U32 key; /* encryption key, FFFFFFF = unencrypted */ + ASCII Reserved[104]; /* reserved field TBD (need to pad) */ +} DpxFileInformation; + +typedef struct { + U32 signage; + U32 ref_low_data; /* reference low data code value */ + R32 ref_low_quantity; /* reference low quantity represented */ + U32 ref_high_data; /* reference high data code value */ + R32 ref_high_quantity;/* reference high quantity represented */ + U8 designator1; + U8 transfer_characteristics; + U8 colourimetry; + U8 bits_per_pixel; + U16 packing; + U16 encoding; + U32 data_offset; + U32 line_padding; + U32 channel_padding; + ASCII description[32]; +} DpxChannelInformation; + +typedef struct { + U16 orientation; + U16 channels_per_image; + U32 pixels_per_line; + U32 lines_per_image; + DpxChannelInformation channel[8]; + ASCII reserved[52]; +} DpxImageInformation; + +typedef struct { + U32 x_offset; + U32 y_offset; + R32 x_centre; + R32 y_centre; + U32 x_original_size; + U32 y_original_size; + ASCII file_name[100]; + ASCII creation_time[24]; + ASCII input_device[32]; + ASCII input_serial_number[32]; + U16 border_validity[4]; + U32 pixel_aspect_ratio[2]; /* h:v */ + ASCII reserved[28]; +} DpxOriginationInformation; + +typedef struct { + ASCII film_manufacturer_id[2]; + ASCII film_type[2]; + ASCII edge_code_perforation_offset[2]; + ASCII edge_code_prefix[6]; + ASCII edge_code_count[4]; + ASCII film_format[32]; + U32 frame_position; + U32 sequence_length; + U32 held_count; + R32 frame_rate; + R32 shutter_angle; + ASCII frame_identification[32]; + ASCII slate_info[100]; + ASCII reserved[56]; +} DpxMPIInformation; + +typedef struct { + DpxFileInformation fileInfo; + DpxImageInformation imageInfo; + DpxOriginationInformation originInfo; + DpxMPIInformation filmHeader; +} DpxMainHeader; + +#ifdef __cplusplus +} +#endif + +#endif /* _DPX_FILE_H_ */ diff --git a/source/blender/imbuf/intern/cineon/dpxlib.c b/source/blender/imbuf/intern/cineon/dpxlib.c new file mode 100644 index 00000000000..b769d1e6132 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/dpxlib.c @@ -0,0 +1,625 @@ +/* + * Dpx image file format library routines. + * + * Copyright 1999 - 2002 David Hodson + * + * 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. + * + */ + +#include "dpxfile.h" +#include "dpxlib.h" + +#include +#include +#include +#include /* strftime() */ +#include +#ifdef WIN32 +#include +#else +#include /* htonl() */ +#endif +#include /* memset */ +#include "cin_debug_stuff.h" +#include "logmemfile.h" + +static void +fillDpxChannelInfo(DpxFile* dpx, DpxChannelInformation* chan, int des) { + + chan->signage = 0; + chan->ref_low_data = htonl(0); + chan->ref_low_quantity = htonf(0.0); + chan->ref_high_data = htonl(1023); + chan->ref_high_quantity = htonf(2.046); + chan->designator1 = des; + chan->transfer_characteristics = 0; + chan->colourimetry = 0; + chan->bits_per_pixel = 10; + chan->packing = htons(1); + chan->encoding = 0; + chan->data_offset = 0; + chan->line_padding = htonl(0); + chan->channel_padding = htonl(0); + chan->description[0] = 0; +} + +static void +dumpDpxChannelInfo(DpxChannelInformation* chan) { + d_printf(" Signage %ld", (long)ntohl(chan->signage)); + d_printf(" Ref low data %ld\n", (long)ntohl(chan->ref_low_data)); + d_printf(" Ref low quantity %f\n", ntohf(chan->ref_low_quantity)); + d_printf(" Ref high data %ld\n", (long)ntohl(chan->ref_high_data)); + d_printf(" Ref high quantity %f\n", ntohf(chan->ref_high_quantity)); + d_printf(" Designator1: %d,", chan->designator1); + d_printf(" Bits per pixel %d\n", chan->bits_per_pixel); + d_printf(" Packing: %d,", ntohs(chan->packing)); + d_printf(" Data Offset: %ld,", (long)ntohl(chan->data_offset)); +} + +static void +fillDpxFileInfo( + DpxFile* dpx, DpxFileInformation* fileInfo, const char* filename) { + + time_t fileClock; + struct tm* fileTime; + + /* Note: always write files in network order */ + /* By the spec, it shouldn't matter, but ... */ + + fileInfo->magic_num = htonl(DPX_FILE_MAGIC); + fileInfo->offset = htonl(dpx->imageOffset); + strcpy(fileInfo->vers, "v1.0"); + fileInfo->file_size = htonl(dpx->imageOffset + + pixelsToLongs(dpx->height * dpx->width * dpx->depth) * 4); + fileInfo->ditto_key = 0; + fileInfo->gen_hdr_size = htonl( + sizeof(DpxFileInformation) + + sizeof(DpxImageInformation) + + sizeof(DpxOriginationInformation)); + fileInfo->ind_hdr_size = htonl(sizeof(DpxMPIInformation)); + fileInfo->user_data_size = 0; + strncpy(fileInfo->file_name, filename, 99); + fileInfo->file_name[99] = 0; + + fileClock = time(0); + fileTime = localtime(&fileClock); + strftime(fileInfo->create_date, 24, "%Y:%m:%d:%H:%M:%S%Z", fileTime); + /* Question: is %Z in strftime guaranteed to return 3 chars? */ + fileInfo->create_date[23] = 0; + + strcpy(fileInfo->creator, "David's DPX writer"); + fileInfo->project[0] = 0; + fileInfo->copyright[0] = 0; + fileInfo->key = 0xFFFFFFFF; /* same in any byte order */ +} + +static void +dumpDpxFileInfo(DpxFileInformation* fileInfo) { + d_printf("\n--File Information--\n"); + d_printf("Magic: %8.8lX\n", (unsigned long)ntohl(fileInfo->magic_num)); + d_printf("Image Offset %ld\n", (long)ntohl(fileInfo->offset)); + d_printf("Version \"%s\"\n", fileInfo->vers); + d_printf("File size %ld\n", (long)ntohl(fileInfo->file_size)); + d_printf("Ditto key %ld\n", (long)ntohl(fileInfo->ditto_key)); + d_printf("Generic Header size %ld\n", (long)ntohl(fileInfo->gen_hdr_size)); + d_printf("Industry Header size %ld\n", (long)ntohl(fileInfo->ind_hdr_size)); + d_printf("User Data size %ld\n", (long)ntohl(fileInfo->user_data_size)); + d_printf("File name \"%s\"\n", fileInfo->file_name); + d_printf("Creation date \"%s\"\n", fileInfo->create_date); + d_printf("Creator \"%s\"\n", fileInfo->creator); + d_printf("Project \"%s\"\n", fileInfo->project); + d_printf("Copyright \"%s\"\n", fileInfo->copyright); + d_printf("Key %ld\n", (long)ntohl(fileInfo->key)); +} + +static void +fillDpxImageInfo( + DpxFile* dpx, DpxImageInformation* imageInfo) { + imageInfo->orientation = 0; + imageInfo->channels_per_image = htons(1); + imageInfo->pixels_per_line = htonl(dpx->width); + imageInfo->lines_per_image = htonl(dpx->height); + + if (dpx->depth == 1) { + fillDpxChannelInfo(dpx, &imageInfo->channel[0], 0); + + } else if (dpx->depth == 3) { + fillDpxChannelInfo(dpx, &imageInfo->channel[0], 50); + } +} + +static void +dumpDpxImageInfo(DpxImageInformation* imageInfo) { + + int n; + int i; + d_printf("\n--Image Information--\n"); + d_printf("Image orientation %d,", ntohs(imageInfo->orientation)); + n = ntohs(imageInfo->channels_per_image); + d_printf("Channels %d\n", n); + d_printf("Pixels per line %ld\n", (long)ntohl(imageInfo->pixels_per_line)); + d_printf("Lines per image %ld\n", (long)ntohl(imageInfo->lines_per_image)); + for (i = 0; i < n; ++i) { + d_printf(" --Channel %d--\n", i); + dumpDpxChannelInfo(&imageInfo->channel[i]); + } +} + +static void +fillDpxOriginationInfo( + DpxFile* dpx, DpxOriginationInformation* originInfo, DpxFileInformation* fileInfo) { +} + +static void +dumpDpxOriginationInfo(DpxOriginationInformation* originInfo) { + d_printf("\n--Origination Information--\n"); + d_printf("X offset %ld\n", (long)ntohl(originInfo->x_offset)); + d_printf("Y offset %ld\n", (long)ntohl(originInfo->y_offset)); + d_printf("X centre %f\n", ntohf(originInfo->x_centre)); + d_printf("Y centre %f\n", ntohf(originInfo->y_centre)); + d_printf("Original X %ld\n", (long)ntohl(originInfo->x_original_size)); + d_printf("Original Y %ld\n", (long)ntohl(originInfo->y_original_size)); + d_printf("File name \"%s\"\n", originInfo->file_name); + d_printf("Creation time \"%s\"\n", originInfo->creation_time); + d_printf("Input device \"%s\"\n", originInfo->input_device); + d_printf("Serial number \"%s\"\n", originInfo->input_serial_number); +} + +static void +initDpxMainHeader(DpxFile* dpx, DpxMainHeader* header, const char* shortFilename) { + memset(header, 0, sizeof(DpxMainHeader)); + fillDpxFileInfo(dpx, &header->fileInfo, shortFilename); + fillDpxImageInfo(dpx, &header->imageInfo); + fillDpxOriginationInfo(dpx, &header->originInfo, &header->fileInfo); +#if 0 + fillDpxMPIInfo(dpx, &header->filmHeader); +#endif +} + +static void +dumpDpxMainHeader(DpxMainHeader* header) { + dumpDpxFileInfo(&header->fileInfo); + dumpDpxImageInfo(&header->imageInfo); + dumpDpxOriginationInfo(&header->originInfo); +#if 0 + dumpDpxMPIInformation(&header->filmHeader); +#endif +} + +static int verbose = 0; +void +dpxSetVerbose(int verbosity) { + verbose = verbosity; +} + +static void +verboseMe(DpxFile* dpx) { + + d_printf("size %d x %d x %d\n", dpx->width, dpx->height, dpx->depth); + d_printf("ImageStart %d, lineBufferLength %d, implied length %d\n", + dpx->imageOffset, dpx->lineBufferLength * 4, + dpx->imageOffset + pixelsToLongs(dpx->width * dpx->depth * dpx->height) * 4); +} + +int +dpxGetRowBytes(DpxFile* dpx, unsigned short* row, int y) { + + /* Note: this code is bizarre because DPX files can wrap */ + /* packed longwords across line boundaries!!!! */ + + size_t readLongs; + unsigned int longIndex; + int numPixels = dpx->width * dpx->depth; + int pixelIndex; + + /* only seek if not reading consecutive lines */ + /* this is not quite right yet, need to account for leftovers */ + if (y != dpx->fileYPos) { + int lineOffset = pixelsToLongs(y * dpx->width * dpx->depth) * 4; + if (verbose) d_printf("Seek in getRowBytes\n"); + if (logimage_fseek(dpx, dpx->imageOffset + lineOffset, SEEK_SET) != 0) { + if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, dpx->imageOffset + lineOffset); + return 1; + } + dpx->fileYPos = y; + } + + /* read enough longwords */ + readLongs = pixelsToLongs(numPixels - dpx->pixelBufferUsed); + if (logimage_fread(dpx->lineBuffer, 4, readLongs, dpx) != readLongs) { + if (verbose) d_printf("Couldn't read line %d length %d\n", y, readLongs * 4); + return 1; + } + ++dpx->fileYPos; + + /* convert longwords to pixels */ + pixelIndex = dpx->pixelBufferUsed; + + /* this is just strange */ + if (dpx->depth == 1) { + for (longIndex = 0; longIndex < readLongs; ++longIndex) { + unsigned int t = ntohl(dpx->lineBuffer[longIndex]); + dpx->pixelBuffer[pixelIndex] = t & 0x3ff; + t = t >> 10; + dpx->pixelBuffer[pixelIndex+1] = t & 0x3ff; + t = t >> 10; + dpx->pixelBuffer[pixelIndex+2] = t & 0x3ff; + pixelIndex += 3; + } + } else /* if (dpx->depth == 3) */ { + for (longIndex = 0; longIndex < readLongs; ++longIndex) { + unsigned int t = ntohl(dpx->lineBuffer[longIndex]); + t = t >> 2; + dpx->pixelBuffer[pixelIndex+2] = t & 0x3ff; + t = t >> 10; + dpx->pixelBuffer[pixelIndex+1] = t & 0x3ff; + t = t >> 10; + dpx->pixelBuffer[pixelIndex] = t & 0x3ff; + pixelIndex += 3; + } + } + dpx->pixelBufferUsed = pixelIndex; + + /* extract required pixels */ + for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) { + /* row[pixelIndex] = dpx->lut10[dpx->pixelBuffer[pixelIndex]]; */ + row[pixelIndex] = dpx->pixelBuffer[pixelIndex] << 6; + } + + /* save remaining pixels */ + while (pixelIndex < dpx->pixelBufferUsed) { + dpx->pixelBuffer[pixelIndex - numPixels] = dpx->pixelBuffer[pixelIndex]; + ++pixelIndex; + } + dpx->pixelBufferUsed -= numPixels; + + /* done! */ + return 0; +} + +int +dpxSetRowBytes(DpxFile* dpx, const unsigned short* row, int y) { + + /* Note: this code is bizarre because DPX files can wrap */ + /* packed longwords across line boundaries!!!! */ + + size_t writeLongs; + int longIndex; + int numPixels = dpx->width * dpx->depth; + int pixelIndex; + int pixelIndex2; + + /* only seek if not reading consecutive lines */ + /* this is not quite right yet */ + if (y != dpx->fileYPos) { + int lineOffset = pixelsToLongs(y * dpx->width * dpx->depth) * 4; + if (verbose) d_printf("Seek in getRowBytes\n"); + if (logimage_fseek(dpx, dpx->imageOffset + lineOffset, SEEK_SET) != 0) { + if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, dpx->imageOffset + lineOffset); + return 1; + } + dpx->fileYPos = y; + } + + /* put new pixels into pixelBuffer */ + for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) { + /* dpx->pixelBuffer[dpx->pixelBufferUsed + pixelIndex] = dpx->lut8[row[pixelIndex]]; */ + dpx->pixelBuffer[dpx->pixelBufferUsed + pixelIndex] = row[pixelIndex] >> 6; + } + dpx->pixelBufferUsed += numPixels; + + /* pack into longwords */ + writeLongs = dpx->pixelBufferUsed / 3; + /* process whole line at image end */ + if (dpx->fileYPos == (dpx->height - 1)) { + writeLongs = pixelsToLongs(dpx->pixelBufferUsed); + } + pixelIndex = 0; + if (dpx->depth == 1) { + for (longIndex = 0; longIndex < writeLongs; ++longIndex) { + unsigned int t = dpx->pixelBuffer[pixelIndex] | + (dpx->pixelBuffer[pixelIndex+1] << 10) | + (dpx->pixelBuffer[pixelIndex+2] << 20); + dpx->lineBuffer[longIndex] = htonl(t); + pixelIndex += 3; + } + } else { + for (longIndex = 0; longIndex < writeLongs; ++longIndex) { + unsigned int t = dpx->pixelBuffer[pixelIndex+2] << 2 | + (dpx->pixelBuffer[pixelIndex+1] << 12) | + (dpx->pixelBuffer[pixelIndex] << 22); + dpx->lineBuffer[longIndex] = htonl(t); + pixelIndex += 3; + } + } + + /* write them */ + if (fwrite(dpx->lineBuffer, 4, writeLongs, dpx->file) != writeLongs) { + if (verbose) d_printf("Couldn't write line %d length %d\n", y, writeLongs * 4); + return 1; + } + ++dpx->fileYPos; + + /* save remaining pixels */ + pixelIndex2 = 0; + while (pixelIndex < dpx->pixelBufferUsed) { + dpx->pixelBuffer[pixelIndex2] = dpx->pixelBuffer[pixelIndex]; + ++pixelIndex; + ++pixelIndex2; + } + dpx->pixelBufferUsed = pixelIndex2; + + return 0; +} + +#define LFMEMFILE 0 +#define LFREALFILE 1 + +static DpxFile* +intern_dpxOpen(int mode, const char* bytestuff, int bufsize) { + + DpxMainHeader header; + const char *filename = bytestuff; + DpxFile* dpx = (DpxFile*)malloc(sizeof(DpxFile)); + + if (dpx == 0) { + if (verbose) d_printf("Failed to malloc dpx file structure.\n"); + return 0; + } + + /* for close routine */ + dpx->file = 0; + dpx->lineBuffer = 0; + dpx->pixelBuffer = 0; + + if (mode == LFREALFILE) { + filename = bytestuff; + dpx->file = fopen(filename, "rb"); + if (dpx->file == 0) { + if (verbose) d_printf("Failed to open file \"%s\".\n", filename); + dpxClose(dpx); + return 0; + } + dpx->membuffer = 0; + dpx->memcursor = 0; + dpx->membuffersize = 0; + } else if (mode == LFMEMFILE) { + dpx->membuffer = (unsigned char *)bytestuff; + dpx->memcursor = (unsigned char *)bytestuff; + dpx->membuffersize = bufsize; + } + + dpx->reading = 1; + + if (logimage_fread(&header, sizeof(header), 1, dpx) == 0) { + if (verbose) d_printf("Not enough data for header in \"%s\".\n", filename); + dpxClose(dpx); + return 0; + } + + /* let's assume dpx files are always network order */ + if (header.fileInfo.magic_num != ntohl(DPX_FILE_MAGIC)) { + if (verbose) d_printf("Bad magic number %8.8lX in \"%s\".\n", + (unsigned long)ntohl(header.fileInfo.magic_num), filename); + dpxClose(dpx); + return 0; + } + + if (ntohs(header.imageInfo.channel[0].packing) != 1) { + if (verbose) d_printf("Unknown packing %d\n", header.imageInfo.channel[0].packing); + dpxClose(dpx); + return 0; + } + + + dpx->width = ntohl(header.imageInfo.pixels_per_line); + dpx->height = ntohl(header.imageInfo.lines_per_image); + dpx->depth = ntohs(header.imageInfo.channels_per_image); + /* Another DPX vs Cineon wierdness */ + if (dpx->depth == 1) { + switch (header.imageInfo.channel[0].designator1) { + case 50: dpx->depth = 3; break; + case 51: dpx->depth = 4; break; + case 52: dpx->depth = 4; break; + default: break; + } + } + dpx->bitsPerPixel = 10; + /* dpx->bitsPerPixel = header.imageInfo.channel[0].bits_per_pixel; */ + dpx->imageOffset = ntohl(header.fileInfo.offset); + + dpx->lineBufferLength = pixelsToLongs(dpx->width * dpx->depth); + dpx->lineBuffer = malloc(dpx->lineBufferLength * 4); + if (dpx->lineBuffer == 0) { + if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", dpx->lineBufferLength * 4); + dpxClose(dpx); + return 0; + } + + /* could have 2 pixels left over */ + dpx->pixelBuffer = malloc((dpx->lineBufferLength * 3 + 2) * sizeof(unsigned short)); + if (dpx->pixelBuffer == 0) { + if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n", + (dpx->width * dpx->depth + 2 + 2) * sizeof(unsigned short)); + dpxClose(dpx); + return 0; + } + dpx->pixelBufferUsed = 0; + + if (logimage_fseek(dpx, dpx->imageOffset, SEEK_SET) != 0) { + if (verbose) d_printf("Couldn't seek to image data start at %d\n", dpx->imageOffset); + dpxClose(dpx); + return 0; + } + dpx->fileYPos = 0; + + logImageGetByteConversionDefaults(&dpx->params); + setupLut(dpx); + + dpx->getRow = &dpxGetRowBytes; + dpx->setRow = 0; + dpx->close = &dpxClose; + + if (verbose) { + verboseMe(dpx); + } + + return dpx; +} + +DpxFile* +dpxOpen(const char *filename) { + return intern_dpxOpen(LFREALFILE, filename, 0); +} + +DpxFile* +dpxOpenFromMem(unsigned char *buffer, unsigned int size) { + return intern_dpxOpen(LFMEMFILE, (const char *) buffer, size); +} + +int +dpxIsMemFileCineon(void *buffer) { + int magicnum = 0; + magicnum = *((int*)buffer); + if (magicnum == ntohl(DPX_FILE_MAGIC)) return 1; + else return 0; +} + +DpxFile* +dpxCreate(const char* filename, int width, int height, int depth) { + + /* Note: always write files in network order */ + /* By the spec, it shouldn't matter, but ... */ + + DpxMainHeader header; + const char* shortFilename = 0; + + DpxFile* dpx = (DpxFile*)malloc(sizeof(DpxFile)); + if (dpx == 0) { + if (verbose) d_printf("Failed to malloc dpx file structure.\n"); + return 0; + } + + memset(&header, 0, sizeof(header)); + + /* for close routine */ + dpx->file = 0; + dpx->lineBuffer = 0; + dpx->pixelBuffer = 0; + + dpx->file = fopen(filename, "wb"); + if (dpx->file == 0) { + if (verbose) d_printf("Couldn't open file %s\n", filename); + dpxClose(dpx); + return 0; + } + dpx->reading = 0; + + dpx->width = width; + dpx->height = height; + dpx->depth = depth; + dpx->bitsPerPixel = 10; + dpx->imageOffset = sizeof(DpxMainHeader); + + dpx->lineBufferLength = pixelsToLongs(dpx->width * dpx->depth); + dpx->lineBuffer = malloc(dpx->lineBufferLength * 4); + if (dpx->lineBuffer == 0) { + if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", dpx->lineBufferLength * 4); + dpxClose(dpx); + return 0; + } + + dpx->pixelBuffer = malloc((dpx->lineBufferLength * 3 + 2) * sizeof(unsigned short)); + if (dpx->pixelBuffer == 0) { + if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n", + (dpx->width * dpx->depth + 2 + 2) * sizeof(unsigned short)); + dpxClose(dpx); + return 0; + } + dpx->pixelBufferUsed = 0; + + /* find trailing part of filename */ + shortFilename = strrchr(filename, '/'); + if (shortFilename == 0) { + shortFilename = filename; + } else { + ++shortFilename; + } + initDpxMainHeader(dpx, &header, shortFilename); + + if (fwrite(&header, sizeof(header), 1, dpx->file) == 0) { + if (verbose) d_printf("Couldn't write image header\n"); + dpxClose(dpx); + return 0; + } + dpx->fileYPos = 0; + + logImageGetByteConversionDefaults(&dpx->params); + setupLut(dpx); + + dpx->getRow = 0; + dpx->setRow = &dpxSetRowBytes; + dpx->close = &dpxClose; + + return dpx; +} + +void +dpxClose(DpxFile* dpx) { + + if (dpx == 0) { + return; + } + + if (dpx->file) { + fclose(dpx->file); + dpx->file = 0; + } + + if (dpx->lineBuffer) { + free(dpx->lineBuffer); + dpx->lineBuffer = 0; + } + + if (dpx->pixelBuffer) { + free(dpx->pixelBuffer); + dpx->pixelBuffer = 0; + } + + free(dpx); +} + +void +dpxDump(const char* filename) { + + DpxMainHeader header; + FILE* file; + + file = fopen(filename, "rb"); + if (file == 0) { + d_printf("Failed to open file \"%s\".\n", filename); + return; + } + + if (fread(&header, sizeof(header), 1, file) == 0) { + d_printf("Not enough data for header in \"%s\".\n", filename); + fclose(file); + return; + } + + fclose(file); + dumpDpxMainHeader(&header); +} diff --git a/source/blender/imbuf/intern/cineon/dpxlib.h b/source/blender/imbuf/intern/cineon/dpxlib.h new file mode 100644 index 00000000000..25fe84e2296 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/dpxlib.h @@ -0,0 +1,56 @@ +/* + * DPX image file format library definitions. + * + * Copyright 1999 - 2002 David Hodson + * + * 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. + * + */ + +#ifndef _DPX_LIB_H_ +#define _DPX_LIB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "logImageCore.h" + +typedef struct _Log_Image_File_t_ DpxFile; + +/* int functions return 0 for OK */ + +void dpxSetVerbose(int); + +DpxFile* dpxOpen(const char* filename); +DpxFile* dpxCreate(const char* filename, int xsize, int ysize, int channels); +DpxFile* dpxOpenFromMem(unsigned char *buffer, unsigned int size); +int dpxIsMemFileCineon(void *buffer); + +/* get/set scanline of converted bytes */ +int dpxGetRowBytes(DpxFile* dpx, unsigned short* row, int y); +int dpxSetRowBytes(DpxFile* dpx, const unsigned short* row, int y); + +/* closes file and deletes data */ +void dpxClose(DpxFile* dpx); + +/* dumps file to stdout */ +void dpxDump(const char* filename); + +#ifdef __cplusplus +} +#endif + +#endif /* _DPX_LIB_H_ */ diff --git a/source/blender/imbuf/intern/cineon/logImageCore.c b/source/blender/imbuf/intern/cineon/logImageCore.c new file mode 100644 index 00000000000..e88e9241443 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/logImageCore.c @@ -0,0 +1,212 @@ +/* + * Cineon image file format library routines. + * + * Copyright 1999,2000,2001 David Hodson + * + * 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. + * + */ + +#include "logImageCore.h" + +#include /* strftime() */ +#include +/* Makes rint consistent in Windows and Linux: */ +#define rint(x) floor(x+0.5) + +#ifdef WIN32 +#include +#else +#include +#include +#include +#include +#endif + +#if defined(__hpux) +/* These are macros in hpux */ +#ifdef htonl +#undef htonl +#undef htons +#undef ntohl +#undef ntohs +#endif +unsigned int htonl(h) unsigned int h; { return(h); } +unsigned short htons(h) unsigned short h; { return(h); } +unsigned int ntohl(n) unsigned int n; { return(n); } +unsigned short ntohs(n) unsigned short n; { return(n); } +#endif + + +/* obscure LogImage conversion */ +/* from 10 bit int to 0.0 - 1.0 */ +/* magic numbers left intact */ +static double +convertTo(int inp, int white, float gamma) { + /* return pow(pow(10.0, ((inp - white) * 0.002 / 0.6)), gamma); */ + return pow(10.0, (inp - white) * gamma * 0.002 / 0.6); +} + +static double +convertFrom(double inp, int white, float gamma) { + return white + log10(inp) / (gamma * 0.002 / 0.6); +} + +/* set up the 10 bit to 8 bit and 8 bit to 10 bit tables */ +void +setupLut(LogImageFile *logImage) { + + int i; + double f_black; + double scale; + + f_black = convertTo(logImage->params.blackPoint, logImage->params.whitePoint, logImage->params.gamma); + scale = 255.0 / (1.0 - f_black); + + for (i = 0; i <= logImage->params.blackPoint; ++i) { + logImage->lut10[i] = 0; + } + for (; i < logImage->params.whitePoint; ++i) { + double f_i; + f_i = convertTo(i, logImage->params.whitePoint, logImage->params.gamma); + logImage->lut10[i] = (int)rint(scale * (f_i - f_black)); + } + for (; i < 1024; ++i) { + logImage->lut10[i] = 255; + } + + for (i = 0; i < 256; ++i) { + double f_i = f_black + (i / 255.0) * (1.0 - f_black); + logImage->lut8[i] = convertFrom(f_i, logImage->params.whitePoint, logImage->params.gamma); + } +} + +/* how many longwords to hold this many pixels? */ +int +pixelsToLongs(int numPixels) { + return (numPixels + 2) / 3; +} + +/* byte reversed float */ + +typedef union { + U32 i; + R32 f; +} Hack; + +R32 +htonf(R32 f) { + Hack hack; + hack.f = f; + hack.i = htonl(hack.i); + return hack.f; +} + +R32 +ntohf(R32 f) { + Hack hack; + hack.f = f; + hack.i = ntohl(hack.i); + return hack.f; +} + +#define UNDEF_FLOAT 0x7F800000 + +R32 +undefined() { + Hack hack; + hack.i = UNDEF_FLOAT; + return hack.f; +} + +/* reverse an endian-swapped U16 */ +U16 +reverseU16(U16 value) { + + union { + U16 whole; + char part[2]; + } buff; + char temp; + buff.whole = value; + temp = buff.part[0]; + buff.part[0] = buff.part[1]; + buff.part[1] = temp; + return buff.whole; +} + +/* reverse an endian-swapped U32 */ +U32 +reverseU32(U32 value) { + + union { + U32 whole; + char part[4]; + } buff; + char temp; + buff.whole = value; + temp = buff.part[0]; + buff.part[0] = buff.part[3]; + buff.part[3] = temp; + temp = buff.part[1]; + buff.part[1] = buff.part[2]; + buff.part[2] = temp; + return buff.whole; +} + +/* reverse an endian-swapped R32 */ +R32 +reverseR32(R32 value) { + + union { + R32 whole; + char part[4]; + } buff; + char temp; + buff.whole = value; + temp = buff.part[0]; + buff.part[0] = buff.part[3]; + buff.part[3] = temp; + temp = buff.part[1]; + buff.part[1] = buff.part[2]; + buff.part[2] = temp; + return buff.whole; +} + +#if 0 +/* bytes per line for images packed 3 10 bit pixels to 32 bits, 32 bit aligned */ +int +bytesPerLine_10_4(int numPixels) { + return ((numPixels + 2) / 3) * 4; +} + +void +seekLine_noPadding(LogImageFile* logImage, int lineNumber) { + int fileOffset = bytesPerLine_10_4(lineNumber * logImage->width * logImage->depth); + int filePos = logImage->imageOffset + fileOffset; + if (fseek(logImage->file, filePos, SEEK_SET) != 0) { + /* complain? */ + } +} + +void +seekLine_padding(LogImageFile* logImage, int lineNumber) { + int fileOffset = lineNumber * bytesPerLine_10_4(logImage->width * logImage->depth); + int filePos = logImage->imageOffset + fileOffset; + if (fseek(logImage->file, filePos, SEEK_SET) != 0) { + /* complain? */ + } +} +#endif diff --git a/source/blender/imbuf/intern/cineon/logImageCore.h b/source/blender/imbuf/intern/cineon/logImageCore.h new file mode 100644 index 00000000000..1af18d5e3b8 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/logImageCore.h @@ -0,0 +1,109 @@ +/* + * Cineon image file format library definitions. + * Cineon and DPX common structures. + * + * This header file contains private details. + * User code should generally use cineonlib.h and dpxlib.h only. + * Hmm. I thought the two formats would have more in common! + * + * Copyright 1999,2000,2001 David Hodson + * + * 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. + * + */ + +#ifndef _LOG_IMAGE_CORE_H_ +#define _LOG_IMAGE_CORE_H_ + +#include +#include "logImageLib.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef int (GetRowFn)(LogImageFile* logImage, unsigned short* row, int lineNum); +typedef int (SetRowFn)(LogImageFile* logImage, const unsigned short* row, int lineNum); +typedef void (CloseFn)(LogImageFile* logImage); + +struct _Log_Image_File_t_ +{ + /* specified in header */ + int width; + int height; + int depth; + int bitsPerPixel; + int imageOffset; + + /* file buffer, measured in longwords (4 byte) */ + int lineBufferLength; + unsigned int* lineBuffer; + + /* pixel buffer, holds 10 bit pixel values */ + unsigned short* pixelBuffer; + int pixelBufferUsed; + + /* io stuff */ + FILE* file; + int reading; + int fileYPos; + + /* byte conversion stuff */ + LogImageByteConversionParameters params; +#if 0 + float gamma; + int blackPoint; + int whitePoint; +#endif + unsigned char lut10[1024]; + unsigned short lut8[256]; + + /* pixel access functions */ + GetRowFn* getRow; + SetRowFn* setRow; + CloseFn* close; + + unsigned char *membuffer; + unsigned long membuffersize; + unsigned char *memcursor; +}; + +void setupLut(LogImageFile*); + +int pixelsToLongs(int numPixels); + +/* typedefs used in original docs */ +/* note size assumptions! */ + +typedef unsigned int U32; +typedef unsigned short U16; +typedef unsigned char U8; +typedef signed int S32; +typedef float R32; +typedef char ASCII; + +R32 htonf(R32 f); +R32 ntohf(R32 f); +R32 undefined(); +U16 reverseU16(U16 value); +U32 reverseU32(U32 value); +R32 reverseR32(R32 value); + +#ifdef __cplusplus +} +#endif + +#endif /* _LOG_IMAGE_CORE_H_ */ diff --git a/source/blender/imbuf/intern/cineon/logImageLib.c b/source/blender/imbuf/intern/cineon/logImageLib.c new file mode 100644 index 00000000000..ff209d5ebd0 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/logImageLib.c @@ -0,0 +1,158 @@ +/* + * Cineon and DPX image file format library routines. + * + * Copyright 1999 - 2002 David Hodson + * + * 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. + * + */ + +#include "cineonlib.h" +#include "dpxlib.h" + +#include +#include +#include +#include /* strftime() */ +#include +#ifdef WIN32 +#include +#else +#include /* htonl() */ +#endif +#include /* memset */ + +#define MIN_GAMMA 0.01 +#define MAX_GAMMA 99.9 +#define DEFAULT_GAMMA 1.0 +#define DEFAULT_BLACK_POINT 95 +#define DEFAULT_WHITE_POINT 685 + +void +logImageSetVerbose(int verbosity) { + cineonSetVerbose(verbosity); + dpxSetVerbose(verbosity); +} + +LogImageFile* +logImageOpen(const char* filename, int cineon) { + if (cineon) { + return cineonOpen(filename); + } else { + return dpxOpen(filename); + } + return 0; +} + +LogImageFile* +logImageOpenFromMem(unsigned char *buffer, unsigned int size, int cineon) { + if (cineon) { + return cineonOpenFromMem(buffer, size); + } else { + return dpxOpenFromMem(buffer, size); + } + return 0; +} + +LogImageFile* +logImageCreate(const char* filename, int cineon, int width, int height, int depth) { + if (cineon) { + return cineonCreate(filename, width, height, depth); + } else { + return dpxCreate(filename, width, height, depth); + } + return 0; +} + +int +logImageGetSize(const LogImageFile* logImage, int* width, int* height, int* depth) { + *width = logImage->width; + *height = logImage->height; + *depth = logImage->depth; + return 0; +} + +int +logImageGetByteConversionDefaults(LogImageByteConversionParameters* params) { + params->gamma = DEFAULT_GAMMA; + params->blackPoint = DEFAULT_BLACK_POINT; + params->whitePoint = DEFAULT_WHITE_POINT; + return 0; +} + +int +logImageGetByteConversion(const LogImageFile* logImage, LogImageByteConversionParameters* params) { + params->gamma = logImage->params.gamma; + params->blackPoint = logImage->params.blackPoint; + params->whitePoint = logImage->params.whitePoint; + return 0; +} + +int +logImageSetByteConversion(LogImageFile* logImage, const LogImageByteConversionParameters* params) { + if ((params->gamma >= MIN_GAMMA) && + (params->gamma <= MAX_GAMMA) && + (params->blackPoint >= 0) && + (params->blackPoint < params->whitePoint) && + (params->whitePoint <= 1023)) { + logImage->params.gamma = params->gamma; + logImage->params.blackPoint = params->blackPoint; + logImage->params.whitePoint = params->whitePoint; + setupLut(logImage); + return 0; + } + return 1; +} + +int +logImageGetRowBytes(LogImageFile* logImage, unsigned short* row, int y) { + return logImage->getRow(logImage, row, y); +} + +int +logImageSetRowBytes(LogImageFile* logImage, const unsigned short* row, int y) { + return logImage->setRow(logImage, row, y); +} + +void +logImageClose(LogImageFile* logImage) { + logImage->close(logImage); +} + +void +logImageDump(const char* filename) { + + U32 magic; + + FILE* foo = fopen(filename, "rb"); + if (foo == 0) { + return; + } + + if (fread(&magic, sizeof(magic), 1, foo) == 0) { + fclose(foo); + return; + } + + fclose(foo); + + if (magic == ntohl(CINEON_FILE_MAGIC)) { +#if 0 + cineonDump(filename); +#endif + } else if (magic == ntohl(DPX_FILE_MAGIC)) { + dpxDump(filename); + } +} diff --git a/source/blender/imbuf/intern/cineon/logImageLib.h b/source/blender/imbuf/intern/cineon/logImageLib.h new file mode 100644 index 00000000000..ea45c675fe2 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/logImageLib.h @@ -0,0 +1,86 @@ +/* + * Common library definitions for Cineon and DPX image files. + * + * Copyright 1999,2000,2001 David Hodson + * + * 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. + * + */ + +#ifndef _LOG_IMAGE_LIB_H_ +#define _LOG_IMAGE_LIB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Image structure. You don't care what this is. + */ + +typedef struct _Log_Image_File_t_ LogImageFile; + +/* + * Magic numbers for normal and byte-swapped Cineon and Dpx files + */ + +#define CINEON_FILE_MAGIC 0x802A5FD7 +#define DPX_FILE_MAGIC 0x53445058 + +/* + * Image 8 bit <-> 10 bit conversion parameters. + */ + +typedef struct { + float gamma; + int blackPoint; + int whitePoint; +} LogImageByteConversionParameters; + +/* int functions return 0 for OK */ + +void logImageSetVerbose(int); + +LogImageFile* logImageOpenFromMem(unsigned char *buffer, unsigned int size, int cineon); +LogImageFile* logImageOpen(const char* filename, int cineon); +int logImageGetSize(const LogImageFile* logImage, int* xsize, int* ysize, int* channels); +LogImageFile* logImageCreate(const char* filename, int cineon, int xsize, int ysize, int channels); + +/* get / set header block NYI */ +int logImageGetHeader(LogImageFile*, int*, void**); +int logImageSetHeader(LogImageFile*, int, void*); + +/* byte conversion routines for mapping logImage (usually) 10 bit values to 8 bit */ +/* see Kodak docs for details... */ + +int logImageGetByteConversionDefaults(LogImageByteConversionParameters* params); +int logImageGetByteConversion(const LogImageFile* logImage, LogImageByteConversionParameters* params); +int logImageSetByteConversion(LogImageFile* logImage, const LogImageByteConversionParameters* params); + +/* get/set scanline of converted bytes */ +int logImageGetRowBytes(LogImageFile* logImage, unsigned short* row, int y); +int logImageSetRowBytes(LogImageFile* logImage, const unsigned short* row, int y); + +/* closes file and deletes data */ +void logImageClose(LogImageFile* logImage); + +/* read file and dump header info */ +void logImageDump(const char* filename); + +#ifdef __cplusplus +} +#endif + +#endif /* _LOG_IMAGE_LIB_H_ */ diff --git a/source/blender/imbuf/intern/cineon/logmemfile.c b/source/blender/imbuf/intern/cineon/logmemfile.c new file mode 100644 index 00000000000..20359335933 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/logmemfile.c @@ -0,0 +1,77 @@ +/* + * Cineon image file format library routines. + * + * Copyright 2006 Joseph Eagar (joeedh@gmail.com) + * + * 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. + * + */ +#include +#include +#include + +#include "logImageCore.h" + +int logimage_fseek(void* logfile, long offsett, int origin) +{ + struct _Log_Image_File_t_ *file = (struct _Log_Image_File_t_*) logfile; + long offset = offsett; + + if (file->file) fseek(file->file, offset, origin); + else { /*we're seeking in memory*/ + if (origin==SEEK_SET) { + if (offset > file->membuffersize) return 1; + file->memcursor = file->membuffer + offset; + } else if (origin==SEEK_END) { + if (offset > file->membuffersize) return 1; + file->memcursor = (file->membuffer + file->membuffersize) - offset; + } else if (origin==SEEK_CUR) { + unsigned long pos = (unsigned long)file->membuffer - (unsigned long)file->memcursor; + if (pos + offset > file->membuffersize) return 1; + if (pos < 0) return 1; + file->memcursor += offset; + } + } + return 0; +} + +int logimage_fwrite(void *buffer, unsigned int size, unsigned int count, void *logfile) +{ + struct _Log_Image_File_t_ *file = (struct _Log_Image_File_t_*) logfile; + if (file->file) return fwrite(buffer, size, count, file->file); + else { /*we're writing to memory*/ + /*do nothing as this isn't supported yet*/ + return count; + } +} + +int logimage_fread(void *buffer, unsigned int size, unsigned int count, void *logfile) +{ + struct _Log_Image_File_t_ *file = (struct _Log_Image_File_t_*) logfile; + if (file->file) return fread(buffer, size, count, file->file); + else { /*we're reading from memory*/ + int i; + /*we convert ot uchar just on the off chance some platform can't handle + pointer arithmetic with type (void*). */ + unsigned char *buf = (unsigned char *) buffer; + + for (i=0; imemcursor, size); + file->memcursor += size; + buf += size; + } + return count; + } +} diff --git a/source/blender/imbuf/intern/cineon/logmemfile.h b/source/blender/imbuf/intern/cineon/logmemfile.h new file mode 100644 index 00000000000..6e82cf2b145 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/logmemfile.h @@ -0,0 +1,29 @@ +/* + * Cineon image file format library routines. + * + * Copyright 2006 Joseph Eagar (joeedh@gmail.com) + * + * 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. + * + */ + +#ifndef _LOGMEMFILE_H +#define _LOGMEMFILE_H + +int logimage_fseek(void* logfile, long offsett, int origin); +int logimage_fwrite(void *buffer, unsigned int size, unsigned int count, void *logfile); +int logimage_fread(void *buffer, unsigned int size, unsigned int count, void *logfile); + +#endif /* _LOGMEMFILE_H */ diff --git a/source/blender/imbuf/intern/cmap.c b/source/blender/imbuf/intern/cmap.c new file mode 100644 index 00000000000..7b4962d8837 --- /dev/null +++ b/source/blender/imbuf/intern/cmap.c @@ -0,0 +1,583 @@ +/** + * cmap.c + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include "BLI_blenlib.h" + +#include "imbuf.h" +#include "imbuf_patch.h" +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "IMB_cmap.h" + +static short *lastcube = 0; +static uchar *lastcoltab = 0; +static short lastmaxcol; +static short lastmincol; +static short lastcbits; +short alpha_col0 = FALSE; + +extern void IMB_free_cache_limiter(); + +/* + * there still is a bug here. If you want to convert an image to a 1 bit colormap you get + * a black image. All conversion to less than 4 bits is too dark anyway. + */ + +void IMB_freeImBufdata(void) +{ + if (lastcube) free(lastcube); + lastcube= 0; + if (lastcoltab) free(lastcoltab); + lastcoltab= 0; + IMB_free_cache_limiter(); +} + + +int IMB_alpha_to_col0(int value) +{ + int old; + + old = alpha_col0; + alpha_col0 = value; + return (old); +} + + +void imb_losecmapbits(struct ImBuf *ibuf, unsigned int *coltab) +{ + int i,bits; + unsigned int col, and1, and2, *rect; + + if (ibuf == 0) return; + if (ibuf->rect == 0) return; + if (ibuf->cbits == 0) return; + if (ibuf->cbits >= 8) return; + +/* + bij cbits = 5: + and1 = 11100000; + bij cbits = 6: + and1 = 11000000; +*/ + + bits = ibuf->cbits; + and1 = ((1 << (8-bits)) - 1) & 0xff; + and1 |= (and1 << 24) + (and1 << 16) + (and1 << 8); + and2 = ~and1; + and1 <<= bits; + + rect = ibuf->rect; + for (i = ibuf->x * ibuf->y ; i > 0; i--) { + col = rect[0]; + *rect++ = col - ((col & and1) >> bits); + } + + if (coltab){ + for (i = 0 ; i < ibuf->maxcol ; i++) { + col = coltab[i]; + coltab[i] = (col - ((col & and1) >> bits)) & and2; + } + } +} + + +static void addcmapbits(struct ImBuf *ibuf) +{ + int i,bits; + int div,mul; + uchar * cmap; + + if (ibuf == 0) return; + if (ibuf->cmap == 0) return; + if (ibuf->cbits == 0) return; + if (ibuf->cbits >= 8) return; + + bits = ibuf->cbits; + + /* bits = 4 -> div = 0xf0 + * bits = 5 -> div = 0xf8 + */ + + div = ((1 << bits) - 1) << (8 - bits); + mul = 0xffff / div; + + if (ibuf->cmap){ + cmap = (uchar *) ibuf->cmap; + for (i = 0 ; i < ibuf->maxcol ; i++){ + cmap[1] = (mul * cmap[1]) >> 8; + cmap[2] = (mul * cmap[2]) >> 8; + cmap[3] = (mul * cmap[3]) >> 8; + cmap += 4; + } + } +} + + +static short addplanetocube(short *cube, short *plane, int minx, int miny, int sizep, int addcx, int addcy, int sizec, int col) +{ + short done = FALSE; + int x, numx, numy, skipc, skipp, temp; + + /* clip first */ + + numx = numy = sizep; + + temp = minx + sizep - 1; + if (temp > sizec) numx -= temp - sizec; + + temp = miny + sizep - 1; + if (temp > sizec) numy -= temp - sizec; + + if (minx < 0){ + plane -= minx; + cube -= minx * addcx; + numx += minx; + } + + if (miny < 0){ + plane -= miny * sizep; + cube -= miny * addcy; + numy += miny; + } + + skipc = addcy - (numx * addcx); + skipp = sizep - numx; + + for (; numy > 0 ; numy--){ + for (x = numx ; x > 0; x--) { + + if (plane[0] < cube[1]) { + + cube[0] = col; + cube[1] = plane[0]; + done = TRUE; + } + plane ++; + cube += addcx; + } + plane += skipp; + cube += skipc; + } + + return (done); +} + + + +short *imb_coldeltatab(unsigned char *coltab, short mincol, short maxcol, short cbits) +{ + short max, *quadr, *_quadr, *_cube, *cube, *_plane, done, nocol; + unsigned int addcb, addcg, addcr, sizep; + uchar *_colp, *colp, *col; + int i, j, k, addcube; + int r, g, b; + + max = (1 << cbits) - 1; + nocol = maxcol - mincol; + coltab += 4 * mincol; + + /* reduce colors to the right amount of bits */ + + { + unsigned int * lctab, and; + + lctab = (unsigned int *) coltab; + and = max << (8 - cbits); + and = and + (and << 8) + (and << 16) + (and << 24); + for (i=nocol-1 ; i >= 0 ; i--) lctab[i] = (lctab[i] & and) >> (8 - cbits); + } + + /* is this data the same as previous ? */ + + if (lastcube){ + if (mincol == lastmincol && maxcol == lastmaxcol && cbits == lastcbits){ + if (lastcoltab){ + if (memcmp(lastcoltab, coltab, 4 * nocol) == 0) return(lastcube); + } + } + } + if (lastcube) free(lastcube); + if (lastcoltab) free(lastcoltab); + + lastcube = 0; + lastcoltab = 0; + _cube = malloc(2 * (1 << (3 * cbits)) * sizeof(short)); + _plane = malloc((2 * max + 1) * (2 * max + 1) * sizeof(short)); + _quadr = malloc((2 * max + 1) * sizeof(short)); + _colp = malloc(6 * nocol); + + if (_cube == 0 || _plane == 0 || _quadr == 0 || _colp == 0){ + if (_cube) free(_cube); + if (_plane) free(_plane); + if (_quadr) free(_quadr); + if (_colp) free(_colp); + return(0); + } + + lastcoltab = malloc(4 * nocol); + if (lastcoltab) memcpy(lastcoltab, coltab, 4 * nocol); + lastcube = _cube; + lastmincol = mincol; + lastmaxcol = maxcol; + lastcbits = cbits; + + /* cube initialise */ + + cube = _cube; + for (i = (1 << (3 * cbits)); i > 0 ; i--){ + cube[0] = 0; + cube[1] = 32767; + cube += 2; + } + + /* mak error look up table */ + + { + unsigned int delta; + + quadr = _quadr + max + 1; + quadr[0] = 0; + delta = 3; + for (i = 1 ; i <= max ; i++){ + quadr[i] = quadr[-i] = delta; + delta += i + 3; + } + } + + /* colorplane initialise */ + + for (i = 6 * nocol - 1; i >= 0; i--) _colp[i] = 1; + + addcr = 2; + addcg = (addcr << cbits); + addcb = (addcg << cbits); + + /* fill in first round */ + + { + unsigned int ofs; + + col = coltab; + cube = _cube; + + for (i = 0 ; i < nocol ; i++){ + ofs = (col[3] * addcr) + (col[2] * addcg) + (col[1] * addcb); + /* color been filled in -> then skip */ + if (cube[ofs + 1]) cube[ofs] = i + mincol; + cube[ofs + 1] = 0; + col += 4; + } + } + + for (i = 1; i <= max ; i++){ + colp = _colp; + col = coltab; + done = FALSE; + sizep = 2*i +1; + + /* plane initialise */ + { + unsigned int delta; + short *plane; + + plane = _plane; + for (j = -i ; j <= i; j++){ + delta = quadr[i] + quadr[j]; + for (k = -i; k <= i; k++){ + *plane++ = delta + quadr[k]; + } + } + } + + for (j = mincol; j < maxcol; j++){ + b = col[1] - i; + g = col[2] - i; + r = col[3] - i; + + addcube= (addcr * r) + (addcg * g) + (addcb * b); + /* PRINT4(d, d, d, d, addcube, r, g, b); */ + /* if(addcube >= 2 * (1 << (3 * cbits))) { */ + /* printf("maxerror: %d %d\n", addcube, 2 * (1 << (3 * cbits))); */ + /* add_cube= 2 * (1 << (3 * cbits)) -1; */ + /* } */ + cube = _cube + addcube; + + if (colp[0]){ + if (b < 0) colp[0] = 0; + else done |= colp[0] = addplanetocube(cube, _plane, r, g, sizep, addcr, addcg, max, j); + } + if (colp[1]){ + if (g < 0) colp[1] = 0; + else done |= colp[1] = addplanetocube(cube, _plane, r, b, sizep, addcr, addcb, max, j); + } + if (colp[2]){ + if (r < 0) colp[2] = 0; + else done |= colp[2] = addplanetocube(cube, _plane, b, g, sizep, addcb, addcg, max, j); + } + if (colp[3]){ + if ((b + sizep - 1) > max) colp[3] = 0; + else done |= colp[3] = addplanetocube(cube + (sizep -1) * addcb, _plane, r, g, sizep, addcr, + addcg, max, j); + } + if (colp[4]){ + if ((g + sizep - 1) > max) colp[4] = 0; + else done |= colp[4] = addplanetocube(cube + (sizep -1) * addcg, _plane, r, b, sizep, addcr, + addcb, max, j); + } + if (colp[5]){ + if ((r + sizep - 1) > max) colp[5] = 0; + else done |= colp[5] = addplanetocube(cube + (sizep -1) * addcr, _plane, b, g, sizep, addcb, + addcg, max, j); + } + + colp += 6; + col += 4; + } + if (done == 0) break; + } + + free(_quadr); + free(_plane); + free(_colp); + return(_cube); +} + + +static void convcmap(struct ImBuf* ibuf, short *deltab, short cbits) +{ + unsigned int *rect; + short x,y; + unsigned int col; + unsigned int bbits,gbits,rbits; + unsigned int bmask,gmask,rmask; + + bbits = 24 - 3 * cbits - 1; + gbits = 16 - 2 * cbits - 1; + rbits = 8 - cbits - 1; + + rmask = ((1 << cbits) - 1) << (8 - cbits); + gmask = rmask << 8; + bmask = gmask << 8; + + rect =(unsigned int *)ibuf->rect; + + for(y=ibuf->y;y>0;y--){ + for(x=ibuf->x;x>0;x--){ + col = *rect; + col = ((col & bmask) >> bbits) + ((col & gmask) >> gbits) + ((col & rmask) >> rbits); + *rect++ = deltab[col]; + } + } +} + +short IMB_converttocmap(struct ImBuf *ibuf) +{ + unsigned int *coltab; + short *deltab=0, cbits; + int i; + int mincol, mask = 0; + struct ImBuf * abuf = 0; + unsigned int * rect, * arect; + + cbits = 5; + if (ibuf->cmap == 0) return(0); + + if ((ibuf->cbits > 0) && (ibuf->cbits <8)) cbits = ibuf->cbits; + + coltab = calloc(ibuf->maxcol, sizeof(unsigned int)); + if (coltab == 0) return(0); + memcpy(coltab, ibuf->cmap, ibuf->maxcol * sizeof(unsigned int)); + + mincol = ibuf->mincol; + if (alpha_col0) { + if (mincol == 0) mincol = 1; + abuf = IMB_dupImBuf(ibuf); + } + + imb_losecmapbits(ibuf, coltab); + deltab = imb_coldeltatab((uchar *) coltab, mincol ,ibuf->maxcol, cbits); + + if (deltab == 0) { + free(coltab); + if (abuf) IMB_freeImBuf(abuf); + return(0); + } + + + IMB_dit0(ibuf,1,cbits); + IMB_dit0(ibuf,2,cbits); + IMB_dit0(ibuf,3,cbits); + convcmap(ibuf, deltab, cbits); + + if (abuf) { + /* convert alpha to color 0 */ + rect = ibuf->rect; + arect = abuf->rect; + + if (alpha_col0 == 1) mask = 0xff000000; /* alpha == 0 -> 0 */ + if (alpha_col0 == 2) mask = 0x80000000; /* alpha < 128 -> 0 */ + + for (i = ibuf->x * ibuf->y; i > 0; i--) { + if ((*arect++ & mask) == 0) rect[0] = 0; + rect++; + } + + IMB_freeImBuf(abuf); + } + + free(coltab); + + return (TRUE); +} + + +void imb_makecolarray(struct ImBuf *ibuf, unsigned char *mem, short nocols) +{ + short i,bits = 0; + uchar *cmap; + + /* what's the theory behind this? */ + + nocols = ibuf->maxcol; + + if (ibuf->cmap){ + cmap = (uchar *) ibuf->cmap; + for (i = 0; i < nocols; i++){ + cmap[3] = mem[0]; + cmap[2] = mem[1]; + cmap[1] = mem[2]; + cmap[0] = 0; + + bits |= mem[0] | mem[1] | mem[2]; + mem += 3; + cmap += 4; + } + + /* patch voor AdPro II */ + if (IS_ham(ibuf)){ + i = ibuf->depth - 2; + bits = ((1 << i) - 1) << (8 - i); + for (i=0 ; icmap[i] &= (bits << 24) + (bits << 16) + (bits << 8) + bits; + } + + if ((bits & 0x1f) == 0){ + ibuf->cbits = 3; + } else if ((bits & 0x0f) == 0){ + ibuf->cbits = 4; + } else if ((bits & 0x07) == 0){ + ibuf->cbits = 5; + } else if ((bits & 0x03) == 0){ + ibuf->cbits = 6; + } else ibuf->cbits = 8; + + addcmapbits(ibuf); + + if (IS_hbrite(ibuf)){ + for (i=31;i>=0;i--){ + ibuf->cmap[i+32] = (ibuf->cmap[i] & 0xfefefefe) >> 1; + } + } + + if (IS_amiga(ibuf)){ + cmap = (uchar * ) (ibuf->cmap + 1); + for (i = 1; i < nocols; i++){ + cmap[0] = 0xff; + cmap += 4; + } + } + } +} + +/* temporal... rects now are rgba, cmaps are abgr */ +#define SWITCH_INT(a) {char s_i, *p_i; p_i= (char *)&(a); s_i= p_i[0]; p_i[0]= p_i[3]; p_i[3]= s_i; s_i= p_i[1]; p_i[1]= p_i[2]; p_i[2]= s_i; } + +void IMB_applycmap(struct ImBuf *ibuf) +{ + unsigned int *rect, *cmap; + int x, y, i, col, code; + int *mask = 0; + + if (ibuf == 0) return; + if (ibuf->rect == 0 || ibuf->cmap == 0) return; + + rect = ibuf->rect; + cmap = ibuf->cmap; + + if (IS_ham(ibuf)){ + + /* generate mask of max (8 + 2) bits */ + mask = malloc(1024 * 2 * sizeof(int)); + + x = 1 << (ibuf->depth - 2); + y = 65535 / (x - 1); + + for (i = 0; i < x; i++){ + mask[i] = 0; + mask[i + x] = 0x00ffff; + mask[i + x + x] = 0xffff00; + mask[i + x + x + x] = 0xff00ff; + + col = (y * i) >> 8; + + mask[i + 1024] = 0xff000000 | ibuf->cmap[i]; + mask[i + x + 1024] = 0xff000000 | col << 16; + mask[i + x + x + 1024] = 0xff000000 | col; + mask[i + x + x + x + 1024] = 0xff000000 | col << 8; + } + + /* only color 0 transparant */ + mask[0+1024] =ibuf->cmap[0]; + + for (y = ibuf->y ; y>0 ; y--){ + col = cmap[0]; + for (x=ibuf->x ; x>0 ; x--){ + code = *rect; + *rect++ = col = (col & mask[code]) | mask[code + 1024]; + } + } + free(mask); + } else { + + for(i = ibuf->x * ibuf->y; i>0; i--){ + col = *rect; + if (col >= 0 && col < ibuf->maxcol) *rect = cmap[col]; + rect++; + + /* *(rect++) = cmap[*rect]; */ + } + } +} + diff --git a/source/blender/imbuf/intern/cspace.c b/source/blender/imbuf/intern/cspace.c new file mode 100644 index 00000000000..4fbfeb9c3c7 --- /dev/null +++ b/source/blender/imbuf/intern/cspace.c @@ -0,0 +1,179 @@ +/** + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BLI_blenlib.h" + +#include "imbuf.h" +#include "imbuf_patch.h" +#include "IMB_imbuf_types.h" + +void IMB_cspace(struct ImBuf *ibuf, float mat[][4]); + +/************************************************************************/ +/* COLORSPACE */ +/************************************************************************/ + +static void fillmattab(double val, unsigned short *mattab) +{ + int tot,ival; + int i; + + val *= (1 << 22); + ival = val; + tot = 32767; /* een half */ + + for(i = 256; i > 0; i--){ + *(mattab) = (tot >> 16); + mattab += 3; + tot += ival; + } +} + + +static void cspfill(short *buf, unsigned short *fill, int x) +{ + unsigned short r,g,b; + + b = fill[0]; + g = fill[1]; + r = fill[2]; + for (;x>0;x--){ + buf[0] = b; + buf[1] = g; + buf[2] = r; + buf += 3; + } +} + + +static void cspadd(short *buf, unsigned short *cont, unsigned char *rect, int x) +{ + short i; + for (;x>0;x--){ + i = *(rect); + rect += 4; + buf[0] += cont[i*3]; + buf[1] += cont[i*3 + 1]; + buf[2] += cont[i*3 + 2]; + buf += 3; + } +} + + +static void cspret(short *buf, unsigned char *rect, int x) +{ + int r,g,b; + + for(; x > 0; x--){ + b = buf[0]; + g = buf[1]; + r = buf[2]; + + if (b & 0x4000){ + if (b<0) rect[2]=0; + else rect[2]=255; + } else rect[2] = b >> 6; + + if (g & 0x4000){ + if (g<0) rect[1]=0; + else rect[1]=255; + } else rect[1] = g >> 6; + + if (r & 0x4000){ + if (r<0) rect[0]=0; + else rect[0]=255; + } else rect[0] = r >> 6; + + buf += 3; + rect += 4; + } +} + + +static void rotcspace(struct ImBuf *ibuf, unsigned short *cont_1, unsigned short *cont_2, unsigned short *cont_3, unsigned short *add) +{ + short x,y,*buf; + uchar *rect; + + x=ibuf->x; + rect= (uchar *)ibuf->rect; + + buf=(short *)malloc(x*3*sizeof(short)); + if (buf){ + for(y=ibuf->y;y>0;y--){ + cspfill(buf,add,x); + cspadd(buf,cont_1,rect+0,x); + cspadd(buf,cont_2,rect+1,x); + cspadd(buf,cont_3,rect+2,x); + cspret(buf,rect,x); + rect += x<<2; + } + free(buf); + } +} + + +void IMB_cspace(struct ImBuf *ibuf, float mat[][4]) +{ + unsigned short *cont_1,*cont_2,*cont_3,add[3]; + + cont_1=(unsigned short *)malloc(256*3*sizeof(short)); + cont_2=(unsigned short *)malloc(256*3*sizeof(short)); + cont_3=(unsigned short *)malloc(256*3*sizeof(short)); + + if (cont_1 && cont_2 && cont_3){ + + fillmattab(mat[0][0],cont_1); + fillmattab(mat[0][1],cont_1+1); + fillmattab(mat[0][2],cont_1+2); + + fillmattab(mat[1][0],cont_2); + fillmattab(mat[1][1],cont_2+1); + fillmattab(mat[1][2],cont_2+2); + + fillmattab(mat[2][0],cont_3); + fillmattab(mat[2][1],cont_3+1); + fillmattab(mat[2][2],cont_3+2); + + add[0] = (mat[3][0] * 64.0) + .5; + add[1] = (mat[3][1] * 64.0) + .5; + add[2] = (mat[3][2] * 64.0) + .5; + + rotcspace(ibuf, cont_1, cont_2, cont_3, add); + } + + if (cont_1) free(cont_1); + if (cont_2) free(cont_2); + if (cont_3) free(cont_3); +} + diff --git a/source/blender/imbuf/intern/data.c b/source/blender/imbuf/intern/data.c new file mode 100644 index 00000000000..ad9194cb80e --- /dev/null +++ b/source/blender/imbuf/intern/data.c @@ -0,0 +1,145 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * data.c + * + * $Id$ + */ + +#include "imbuf.h" +#include "matrix.h" + +/* +static short quadbase[31] = { + 150,133,117,102, + 88,75,63,52, + 42,33,25,18, + 12,7,3,0, + 3,7,12,18, + 25,33,42,52, + 63,75,88,102, + 117,133,150, +}; + +short *quadr = quadbase+15; +*/ +/* +main() +{ + ushort _quadr[511], *quadr; + int i, delta; + + quadr = _quadr + 255; + + delta = 0; + for (i = 0 ; i <= 255 ; i++){ + quadr[i] = quadr[-i] = delta; + delta += i + 3; + } + + delta = 0; + for (i = 0; i < 511; i++){ + printf("%6d, ", _quadr[i]); + delta++; + if (delta == 8){ + delta = 0; + printf("\n"); + } + } +} +*/ + +static unsigned short quadbase[511] = { + 33150, 32893, 32637, 32382, 32128, 31875, 31623, 31372, + 31122, 30873, 30625, 30378, 30132, 29887, 29643, 29400, + 29158, 28917, 28677, 28438, 28200, 27963, 27727, 27492, + 27258, 27025, 26793, 26562, 26332, 26103, 25875, 25648, + 25422, 25197, 24973, 24750, 24528, 24307, 24087, 23868, + 23650, 23433, 23217, 23002, 22788, 22575, 22363, 22152, + 21942, 21733, 21525, 21318, 21112, 20907, 20703, 20500, + 20298, 20097, 19897, 19698, 19500, 19303, 19107, 18912, + 18718, 18525, 18333, 18142, 17952, 17763, 17575, 17388, + 17202, 17017, 16833, 16650, 16468, 16287, 16107, 15928, + 15750, 15573, 15397, 15222, 15048, 14875, 14703, 14532, + 14362, 14193, 14025, 13858, 13692, 13527, 13363, 13200, + 13038, 12877, 12717, 12558, 12400, 12243, 12087, 11932, + 11778, 11625, 11473, 11322, 11172, 11023, 10875, 10728, + 10582, 10437, 10293, 10150, 10008, 9867, 9727, 9588, + 9450, 9313, 9177, 9042, 8908, 8775, 8643, 8512, + 8382, 8253, 8125, 7998, 7872, 7747, 7623, 7500, + 7378, 7257, 7137, 7018, 6900, 6783, 6667, 6552, + 6438, 6325, 6213, 6102, 5992, 5883, 5775, 5668, + 5562, 5457, 5353, 5250, 5148, 5047, 4947, 4848, + 4750, 4653, 4557, 4462, 4368, 4275, 4183, 4092, + 4002, 3913, 3825, 3738, 3652, 3567, 3483, 3400, + 3318, 3237, 3157, 3078, 3000, 2923, 2847, 2772, + 2698, 2625, 2553, 2482, 2412, 2343, 2275, 2208, + 2142, 2077, 2013, 1950, 1888, 1827, 1767, 1708, + 1650, 1593, 1537, 1482, 1428, 1375, 1323, 1272, + 1222, 1173, 1125, 1078, 1032, 987, 943, 900, + 858, 817, 777, 738, 700, 663, 627, 592, + 558, 525, 493, 462, 432, 403, 375, 348, + 322, 297, 273, 250, 228, 207, 187, 168, + 150, 133, 117, 102, 88, 75, 63, 52, + 42, 33, 25, 18, 12, 7, 3, 0, + 3, 7, 12, 18, 25, 33, 42, 52, + 63, 75, 88, 102, 117, 133, 150, 168, + 187, 207, 228, 250, 273, 297, 322, 348, + 375, 403, 432, 462, 493, 525, 558, 592, + 627, 663, 700, 738, 777, 817, 858, 900, + 943, 987, 1032, 1078, 1125, 1173, 1222, 1272, + 1323, 1375, 1428, 1482, 1537, 1593, 1650, 1708, + 1767, 1827, 1888, 1950, 2013, 2077, 2142, 2208, + 2275, 2343, 2412, 2482, 2553, 2625, 2698, 2772, + 2847, 2923, 3000, 3078, 3157, 3237, 3318, 3400, + 3483, 3567, 3652, 3738, 3825, 3913, 4002, 4092, + 4183, 4275, 4368, 4462, 4557, 4653, 4750, 4848, + 4947, 5047, 5148, 5250, 5353, 5457, 5562, 5668, + 5775, 5883, 5992, 6102, 6213, 6325, 6438, 6552, + 6667, 6783, 6900, 7018, 7137, 7257, 7378, 7500, + 7623, 7747, 7872, 7998, 8125, 8253, 8382, 8512, + 8643, 8775, 8908, 9042, 9177, 9313, 9450, 9588, + 9727, 9867, 10008, 10150, 10293, 10437, 10582, 10728, + 10875, 11023, 11172, 11322, 11473, 11625, 11778, 11932, + 12087, 12243, 12400, 12558, 12717, 12877, 13038, 13200, + 13363, 13527, 13692, 13858, 14025, 14193, 14362, 14532, + 14703, 14875, 15048, 15222, 15397, 15573, 15750, 15928, + 16107, 16287, 16468, 16650, 16833, 17017, 17202, 17388, + 17575, 17763, 17952, 18142, 18333, 18525, 18718, 18912, + 19107, 19303, 19500, 19698, 19897, 20097, 20298, 20500, + 20703, 20907, 21112, 21318, 21525, 21733, 21942, 22152, + 22363, 22575, 22788, 23002, 23217, 23433, 23650, 23868, + 24087, 24307, 24528, 24750, 24973, 25197, 25422, 25648, + 25875, 26103, 26332, 26562, 26793, 27025, 27258, 27492, + 27727, 27963, 28200, 28438, 28677, 28917, 29158, 29400, + 29643, 29887, 30132, 30378, 30625, 30873, 31122, 31372, + 31623, 31875, 32128, 32382, 32637, 32893, 33150, +}; + +unsigned short *quadr = quadbase + 255; diff --git a/source/blender/imbuf/intern/dds/BlockDXT.cpp b/source/blender/imbuf/intern/dds/BlockDXT.cpp new file mode 100644 index 00000000000..5290a677678 --- /dev/null +++ b/source/blender/imbuf/intern/dds/BlockDXT.cpp @@ -0,0 +1,523 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + * This file is based on a similar file from the NVIDIA texture tools + * (http://nvidia-texture-tools.googlecode.com/) + * + * Original license from NVIDIA follows. + */ + +// Copyright NVIDIA Corporation 2007 -- Ignacio Castano +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#include +#include +#include +#include + +/*---------------------------------------------------------------------------- + BlockDXT1 +----------------------------------------------------------------------------*/ + +unsigned int BlockDXT1::evaluatePalette(Color32 color_array[4]) const +{ + // Does bit expansion before interpolation. + color_array[0].b = (col0.b << 3) | (col0.b >> 2); + color_array[0].g = (col0.g << 2) | (col0.g >> 4); + color_array[0].r = (col0.r << 3) | (col0.r >> 2); + color_array[0].a = 0xFF; + + // @@ Same as above, but faster? +// Color32 c; +// c.u = ((col0.u << 3) & 0xf8) | ((col0.u << 5) & 0xfc00) | ((col0.u << 8) & 0xf80000); +// c.u |= (c.u >> 5) & 0x070007; +// c.u |= (c.u >> 6) & 0x000300; +// color_array[0].u = c.u; + + color_array[1].r = (col1.r << 3) | (col1.r >> 2); + color_array[1].g = (col1.g << 2) | (col1.g >> 4); + color_array[1].b = (col1.b << 3) | (col1.b >> 2); + color_array[1].a = 0xFF; + + // @@ Same as above, but faster? +// c.u = ((col1.u << 3) & 0xf8) | ((col1.u << 5) & 0xfc00) | ((col1.u << 8) & 0xf80000); +// c.u |= (c.u >> 5) & 0x070007; +// c.u |= (c.u >> 6) & 0x000300; +// color_array[1].u = c.u; + + if( col0.u > col1.u ) { + // Four-color block: derive the other two colors. + color_array[2].r = (2 * color_array[0].r + color_array[1].r) / 3; + color_array[2].g = (2 * color_array[0].g + color_array[1].g) / 3; + color_array[2].b = (2 * color_array[0].b + color_array[1].b) / 3; + color_array[2].a = 0xFF; + + color_array[3].r = (2 * color_array[1].r + color_array[0].r) / 3; + color_array[3].g = (2 * color_array[1].g + color_array[0].g) / 3; + color_array[3].b = (2 * color_array[1].b + color_array[0].b) / 3; + color_array[3].a = 0xFF; + + return 4; + } + else { + // Three-color block: derive the other color. + color_array[2].r = (color_array[0].r + color_array[1].r) / 2; + color_array[2].g = (color_array[0].g + color_array[1].g) / 2; + color_array[2].b = (color_array[0].b + color_array[1].b) / 2; + color_array[2].a = 0xFF; + + // Set all components to 0 to match DXT specs. + color_array[3].r = 0x00; // color_array[2].r; + color_array[3].g = 0x00; // color_array[2].g; + color_array[3].b = 0x00; // color_array[2].b; + color_array[3].a = 0x00; + + return 3; + } +} + +// Evaluate palette assuming 3 color block. +void BlockDXT1::evaluatePalette3(Color32 color_array[4]) const +{ + color_array[0].b = (col0.b << 3) | (col0.b >> 2); + color_array[0].g = (col0.g << 2) | (col0.g >> 4); + color_array[0].r = (col0.r << 3) | (col0.r >> 2); + color_array[0].a = 0xFF; + + color_array[1].r = (col1.r << 3) | (col1.r >> 2); + color_array[1].g = (col1.g << 2) | (col1.g >> 4); + color_array[1].b = (col1.b << 3) | (col1.b >> 2); + color_array[1].a = 0xFF; + + // Three-color block: derive the other color. + color_array[2].r = (color_array[0].r + color_array[1].r) / 2; + color_array[2].g = (color_array[0].g + color_array[1].g) / 2; + color_array[2].b = (color_array[0].b + color_array[1].b) / 2; + color_array[2].a = 0xFF; + + // Set all components to 0 to match DXT specs. + color_array[3].r = 0x00; // color_array[2].r; + color_array[3].g = 0x00; // color_array[2].g; + color_array[3].b = 0x00; // color_array[2].b; + color_array[3].a = 0x00; +} + +// Evaluate palette assuming 4 color block. +void BlockDXT1::evaluatePalette4(Color32 color_array[4]) const +{ + color_array[0].b = (col0.b << 3) | (col0.b >> 2); + color_array[0].g = (col0.g << 2) | (col0.g >> 4); + color_array[0].r = (col0.r << 3) | (col0.r >> 2); + color_array[0].a = 0xFF; + + color_array[1].r = (col1.r << 3) | (col1.r >> 2); + color_array[1].g = (col1.g << 2) | (col1.g >> 4); + color_array[1].b = (col1.b << 3) | (col1.b >> 2); + color_array[1].a = 0xFF; + + // Four-color block: derive the other two colors. + color_array[2].r = (2 * color_array[0].r + color_array[1].r) / 3; + color_array[2].g = (2 * color_array[0].g + color_array[1].g) / 3; + color_array[2].b = (2 * color_array[0].b + color_array[1].b) / 3; + color_array[2].a = 0xFF; + + color_array[3].r = (2 * color_array[1].r + color_array[0].r) / 3; + color_array[3].g = (2 * color_array[1].g + color_array[0].g) / 3; + color_array[3].b = (2 * color_array[1].b + color_array[0].b) / 3; + color_array[3].a = 0xFF; +} + +void BlockDXT1::decodeBlock(ColorBlock * block) const +{ + // Decode color block. + Color32 color_array[4]; + evaluatePalette(color_array); + + // Write color block. + for( unsigned int j = 0; j < 4; j++ ) { + for( unsigned int i = 0; i < 4; i++ ) { + unsigned int idx = (row[j] >> (2 * i)) & 3; + block->color(i, j) = color_array[idx]; + } + } +} + +void BlockDXT1::setIndices(int * idx) +{ + indices = 0; + for(unsigned int i = 0; i < 16; i++) { + indices |= (idx[i] & 3) << (2 * i); + } +} + + +/// Flip DXT1 block vertically. +inline void BlockDXT1::flip4() +{ + unsigned char tmp; + swap(row[0], row[3], tmp); + swap(row[1], row[2], tmp); +} + +/// Flip half DXT1 block vertically. +inline void BlockDXT1::flip2() +{ + unsigned char tmp; + swap(row[0], row[1], tmp); +} + + +/*---------------------------------------------------------------------------- + BlockDXT3 +----------------------------------------------------------------------------*/ + +void BlockDXT3::decodeBlock(ColorBlock * block) const +{ + // Decode color. + color.decodeBlock(block); + + // Decode alpha. + alpha.decodeBlock(block); +} + +void AlphaBlockDXT3::decodeBlock(ColorBlock * block) const +{ + block->color(0x0).a = (alpha0 << 4) | alpha0; + block->color(0x1).a = (alpha1 << 4) | alpha1; + block->color(0x2).a = (alpha2 << 4) | alpha2; + block->color(0x3).a = (alpha3 << 4) | alpha3; + block->color(0x4).a = (alpha4 << 4) | alpha4; + block->color(0x5).a = (alpha5 << 4) | alpha5; + block->color(0x6).a = (alpha6 << 4) | alpha6; + block->color(0x7).a = (alpha7 << 4) | alpha7; + block->color(0x8).a = (alpha8 << 4) | alpha8; + block->color(0x9).a = (alpha9 << 4) | alpha9; + block->color(0xA).a = (alphaA << 4) | alphaA; + block->color(0xB).a = (alphaB << 4) | alphaB; + block->color(0xC).a = (alphaC << 4) | alphaC; + block->color(0xD).a = (alphaD << 4) | alphaD; + block->color(0xE).a = (alphaE << 4) | alphaE; + block->color(0xF).a = (alphaF << 4) | alphaF; +} + +/// Flip DXT3 alpha block vertically. +void AlphaBlockDXT3::flip4() +{ + unsigned short tmp; + swap(row[0], row[3], tmp); + swap(row[1], row[2], tmp); +} + +/// Flip half DXT3 alpha block vertically. +void AlphaBlockDXT3::flip2() +{ + unsigned short tmp; + swap(row[0], row[1], tmp); +} + +/// Flip DXT3 block vertically. +void BlockDXT3::flip4() +{ + alpha.flip4(); + color.flip4(); +} + +/// Flip half DXT3 block vertically. +void BlockDXT3::flip2() +{ + alpha.flip2(); + color.flip2(); +} + + +/*---------------------------------------------------------------------------- + BlockDXT5 +----------------------------------------------------------------------------*/ + +void AlphaBlockDXT5::evaluatePalette(unsigned char alpha[8]) const +{ + if (alpha0 > alpha1) { + evaluatePalette8(alpha); + } + else { + evaluatePalette6(alpha); + } +} + +void AlphaBlockDXT5::evaluatePalette8(unsigned char alpha[8]) const +{ + // 8-alpha block: derive the other six alphas. + // Bit code 000 = alpha0, 001 = alpha1, others are interpolated. + alpha[0] = alpha0; + alpha[1] = alpha1; + alpha[2] = (6 * alpha0 + 1 * alpha1) / 7; // bit code 010 + alpha[3] = (5 * alpha0 + 2 * alpha1) / 7; // bit code 011 + alpha[4] = (4 * alpha0 + 3 * alpha1) / 7; // bit code 100 + alpha[5] = (3 * alpha0 + 4 * alpha1) / 7; // bit code 101 + alpha[6] = (2 * alpha0 + 5 * alpha1) / 7; // bit code 110 + alpha[7] = (1 * alpha0 + 6 * alpha1) / 7; // bit code 111 +} + +void AlphaBlockDXT5::evaluatePalette6(unsigned char alpha[8]) const +{ + // 6-alpha block. + // Bit code 000 = alpha0, 001 = alpha1, others are interpolated. + alpha[0] = alpha0; + alpha[1] = alpha1; + alpha[2] = (4 * alpha0 + 1 * alpha1) / 5; // Bit code 010 + alpha[3] = (3 * alpha0 + 2 * alpha1) / 5; // Bit code 011 + alpha[4] = (2 * alpha0 + 3 * alpha1) / 5; // Bit code 100 + alpha[5] = (1 * alpha0 + 4 * alpha1) / 5; // Bit code 101 + alpha[6] = 0x00; // Bit code 110 + alpha[7] = 0xFF; // Bit code 111 +} + +void AlphaBlockDXT5::indices(unsigned char index_array[16]) const +{ + index_array[0x0] = bits0; + index_array[0x1] = bits1; + index_array[0x2] = bits2; + index_array[0x3] = bits3; + index_array[0x4] = bits4; + index_array[0x5] = bits5; + index_array[0x6] = bits6; + index_array[0x7] = bits7; + index_array[0x8] = bits8; + index_array[0x9] = bits9; + index_array[0xA] = bitsA; + index_array[0xB] = bitsB; + index_array[0xC] = bitsC; + index_array[0xD] = bitsD; + index_array[0xE] = bitsE; + index_array[0xF] = bitsF; +} + +unsigned int AlphaBlockDXT5::index(unsigned int index) const +{ + int offset = (3 * index + 16); + return (this->u >> offset) & 0x7; +} + +void AlphaBlockDXT5::setIndex(unsigned int index, unsigned int value) +{ + int offset = (3 * index + 16); + unsigned long long mask = ((unsigned long long)(0x7)) << offset; + this->u = (this->u & ~mask) | (((unsigned long long)(value)) << offset); +} + +void AlphaBlockDXT5::decodeBlock(ColorBlock * block) const +{ + unsigned char alpha_array[8]; + evaluatePalette(alpha_array); + + unsigned char index_array[16]; + indices(index_array); + + for(unsigned int i = 0; i < 16; i++) { + block->color(i).a = alpha_array[index_array[i]]; + } +} + +void AlphaBlockDXT5::flip4() +{ + unsigned long long * b = (unsigned long long *)this; + + // @@ The masks might have to be byte swapped. + unsigned long long tmp = (*b & (unsigned long long)(0x000000000000FFFFLL)); + tmp |= (*b & (unsigned long long)(0x000000000FFF0000LL)) << 36; + tmp |= (*b & (unsigned long long)(0x000000FFF0000000LL)) << 12; + tmp |= (*b & (unsigned long long)(0x000FFF0000000000LL)) >> 12; + tmp |= (*b & (unsigned long long)(0xFFF0000000000000LL)) >> 36; + + *b = tmp; +} + +void AlphaBlockDXT5::flip2() +{ + unsigned int * b = (unsigned int *)this; + + // @@ The masks might have to be byte swapped. + unsigned int tmp = (*b & 0xFF000000); + tmp |= (*b & 0x00000FFF) << 12; + tmp |= (*b & 0x00FFF000) >> 12; + + *b = tmp; +} + +void BlockDXT5::decodeBlock(ColorBlock * block) const +{ + // Decode color. + color.decodeBlock(block); + + // Decode alpha. + alpha.decodeBlock(block); +} + +/// Flip DXT5 block vertically. +void BlockDXT5::flip4() +{ + alpha.flip4(); + color.flip4(); +} + +/// Flip half DXT5 block vertically. +void BlockDXT5::flip2() +{ + alpha.flip2(); + color.flip2(); +} + + +/// Decode ATI1 block. +void BlockATI1::decodeBlock(ColorBlock * block) const +{ + unsigned char alpha_array[8]; + alpha.evaluatePalette(alpha_array); + + unsigned char index_array[16]; + alpha.indices(index_array); + + for(unsigned int i = 0; i < 16; i++) { + Color32 & c = block->color(i); + c.b = c.g = c.r = alpha_array[index_array[i]]; + c.a = 255; + } +} + +/// Flip ATI1 block vertically. +void BlockATI1::flip4() +{ + alpha.flip4(); +} + +/// Flip half ATI1 block vertically. +void BlockATI1::flip2() +{ + alpha.flip2(); +} + + +/// Decode ATI2 block. +void BlockATI2::decodeBlock(ColorBlock * block) const +{ + unsigned char alpha_array[8]; + unsigned char index_array[16]; + + x.evaluatePalette(alpha_array); + x.indices(index_array); + + for(unsigned int i = 0; i < 16; i++) { + Color32 & c = block->color(i); + c.r = alpha_array[index_array[i]]; + } + + y.evaluatePalette(alpha_array); + y.indices(index_array); + + for(unsigned int i = 0; i < 16; i++) { + Color32 & c = block->color(i); + c.g = alpha_array[index_array[i]]; + c.b = 0; + c.a = 255; + } +} + +/// Flip ATI2 block vertically. +void BlockATI2::flip4() +{ + x.flip4(); + y.flip4(); +} + +/// Flip half ATI2 block vertically. +void BlockATI2::flip2() +{ + x.flip2(); + y.flip2(); +} + +void mem_read(Stream & mem, BlockDXT1 & block) +{ + mem_read(mem, block.col0.u); + mem_read(mem, block.col1.u); + mem_read(mem, block.indices); +} + +void mem_read(Stream & mem, AlphaBlockDXT3 & block) +{ + for (unsigned int i = 0; i < 4; i++) mem_read(mem, block.row[i]); +} + +void mem_read(Stream & mem, BlockDXT3 & block) +{ + mem_read(mem, block.alpha); + mem_read(mem, block.color); +} + +void mem_read(Stream & mem, AlphaBlockDXT5 & block) +{ + mem_read(mem, block.u); +} + +void mem_read(Stream & mem, BlockDXT5 & block) +{ + mem_read(mem, block.alpha); + mem_read(mem, block.color); +} + +void mem_read(Stream & mem, BlockATI1 & block) +{ + mem_read(mem, block.alpha); +} + +void mem_read(Stream & mem, BlockATI2 & block) +{ + mem_read(mem, block.x); + mem_read(mem, block.y); +} + diff --git a/source/blender/imbuf/intern/dds/BlockDXT.h b/source/blender/imbuf/intern/dds/BlockDXT.h new file mode 100644 index 00000000000..1f710360c3c --- /dev/null +++ b/source/blender/imbuf/intern/dds/BlockDXT.h @@ -0,0 +1,227 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + * This file is based on a similar file from the NVIDIA texture tools + * (http://nvidia-texture-tools.googlecode.com/) + * + * Original license from NVIDIA follows. + */ + +// Copyright NVIDIA Corporation 2007 -- Ignacio Castano +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#ifndef _DDS_BLOCKDXT_H +#define _DDS_BLOCKDXT_H + +#include +#include +#include + +/// DXT1 block. +struct BlockDXT1 +{ + Color16 col0; + Color16 col1; + union { + unsigned char row[4]; + unsigned int indices; + }; + + bool isFourColorMode() const; + + unsigned int evaluatePalette(Color32 color_array[4]) const; + unsigned int evaluatePaletteFast(Color32 color_array[4]) const; + void evaluatePalette3(Color32 color_array[4]) const; + void evaluatePalette4(Color32 color_array[4]) const; + + void decodeBlock(ColorBlock * block) const; + + void setIndices(int * idx); + + void flip4(); + void flip2(); +}; + +/// Return true if the block uses four color mode, false otherwise. +inline bool BlockDXT1::isFourColorMode() const +{ + return col0.u >= col1.u; // @@ > or >= ? +} + + +/// DXT3 alpha block with explicit alpha. +struct AlphaBlockDXT3 +{ + union { + struct { + unsigned int alpha0 : 4; + unsigned int alpha1 : 4; + unsigned int alpha2 : 4; + unsigned int alpha3 : 4; + unsigned int alpha4 : 4; + unsigned int alpha5 : 4; + unsigned int alpha6 : 4; + unsigned int alpha7 : 4; + unsigned int alpha8 : 4; + unsigned int alpha9 : 4; + unsigned int alphaA : 4; + unsigned int alphaB : 4; + unsigned int alphaC : 4; + unsigned int alphaD : 4; + unsigned int alphaE : 4; + unsigned int alphaF : 4; + }; + unsigned short row[4]; + }; + + void decodeBlock(ColorBlock * block) const; + + void flip4(); + void flip2(); +}; + + +/// DXT3 block. +struct BlockDXT3 +{ + AlphaBlockDXT3 alpha; + BlockDXT1 color; + + void decodeBlock(ColorBlock * block) const; + + void flip4(); + void flip2(); +}; + + +/// DXT5 alpha block. +struct AlphaBlockDXT5 +{ + union { + struct { + unsigned int alpha0 : 8; // 8 + unsigned int alpha1 : 8; // 16 + unsigned int bits0 : 3; // 3 - 19 + unsigned int bits1 : 3; // 6 - 22 + unsigned int bits2 : 3; // 9 - 25 + unsigned int bits3 : 3; // 12 - 28 + unsigned int bits4 : 3; // 15 - 31 + unsigned int bits5 : 3; // 18 - 34 + unsigned int bits6 : 3; // 21 - 37 + unsigned int bits7 : 3; // 24 - 40 + unsigned int bits8 : 3; // 27 - 43 + unsigned int bits9 : 3; // 30 - 46 + unsigned int bitsA : 3; // 33 - 49 + unsigned int bitsB : 3; // 36 - 52 + unsigned int bitsC : 3; // 39 - 55 + unsigned int bitsD : 3; // 42 - 58 + unsigned int bitsE : 3; // 45 - 61 + unsigned int bitsF : 3; // 48 - 64 + }; + unsigned long long u; + }; + + void evaluatePalette(unsigned char alpha[8]) const; + void evaluatePalette8(unsigned char alpha[8]) const; + void evaluatePalette6(unsigned char alpha[8]) const; + void indices(unsigned char index_array[16]) const; + + unsigned int index(unsigned int index) const; + void setIndex(unsigned int index, unsigned int value); + + void decodeBlock(ColorBlock * block) const; + + void flip4(); + void flip2(); +}; + + +/// DXT5 block. +struct BlockDXT5 +{ + AlphaBlockDXT5 alpha; + BlockDXT1 color; + + void decodeBlock(ColorBlock * block) const; + + void flip4(); + void flip2(); +}; + +/// ATI1 block. +struct BlockATI1 +{ + AlphaBlockDXT5 alpha; + + void decodeBlock(ColorBlock * block) const; + + void flip4(); + void flip2(); +}; + +/// ATI2 block. +struct BlockATI2 +{ + AlphaBlockDXT5 x; + AlphaBlockDXT5 y; + + void decodeBlock(ColorBlock * block) const; + + void flip4(); + void flip2(); +}; + +void mem_read(Stream & mem, BlockDXT1 & block); +void mem_read(Stream & mem, AlphaBlockDXT3 & block); +void mem_read(Stream & mem, BlockDXT3 & block); +void mem_read(Stream & mem, AlphaBlockDXT5 & block); +void mem_read(Stream & mem, BlockDXT5 & block); +void mem_read(Stream & mem, BlockATI1 & block); +void mem_read(Stream & mem, BlockATI2 & block); + +#endif // _DDS_BLOCKDXT_H diff --git a/source/blender/imbuf/intern/dds/Color.h b/source/blender/imbuf/intern/dds/Color.h new file mode 100644 index 00000000000..f8055afdfc9 --- /dev/null +++ b/source/blender/imbuf/intern/dds/Color.h @@ -0,0 +1,99 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + * This file is based on a similar file from the NVIDIA texture tools + * (http://nvidia-texture-tools.googlecode.com/) + * + * Original license from NVIDIA follows. + */ + +// This code is in the public domain -- castanyo@yahoo.es + +#ifndef _DDS_COLOR_H +#define _DDS_COLOR_H + +/// 32 bit color stored as BGRA. +class Color32 +{ +public: + Color32() { } + Color32(const Color32 & c) : u(c.u) { } + Color32(unsigned char R, unsigned char G, unsigned char B) { setRGBA(R, G, B, 0xFF); } + Color32(unsigned char R, unsigned char G, unsigned char B, unsigned char A) { setRGBA( R, G, B, A); } + //Color32(unsigned char c[4]) { setRGBA(c[0], c[1], c[2], c[3]); } + //Color32(float R, float G, float B) { setRGBA(uint(R*255), uint(G*255), uint(B*255), 0xFF); } + //Color32(float R, float G, float B, float A) { setRGBA(uint(R*255), uint(G*255), uint(B*255), uint(A*255)); } + Color32(unsigned int U) : u(U) { } + + void setRGBA(unsigned char R, unsigned char G, unsigned char B, unsigned char A) + { + r = R; + g = G; + b = B; + a = A; + } + + void setBGRA(unsigned char B, unsigned char G, unsigned char R, unsigned char A = 0xFF) + { + r = R; + g = G; + b = B; + a = A; + } + + operator unsigned int () const { + return u; + } + + union { + struct { + unsigned char b, g, r, a; + }; + unsigned int u; + }; +}; + +/// 16 bit 565 BGR color. +class Color16 +{ +public: + Color16() { } + Color16(const Color16 & c) : u(c.u) { } + explicit Color16(unsigned short U) : u(U) { } + + union { + struct { + unsigned short b : 5; + unsigned short g : 6; + unsigned short r : 5; + }; + unsigned short u; + }; +}; + +#endif // _DDS_COLOR_H diff --git a/source/blender/imbuf/intern/dds/ColorBlock.cpp b/source/blender/imbuf/intern/dds/ColorBlock.cpp new file mode 100644 index 00000000000..63997f93c8c --- /dev/null +++ b/source/blender/imbuf/intern/dds/ColorBlock.cpp @@ -0,0 +1,310 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + * This file is based on a similar file from the NVIDIA texture tools + * (http://nvidia-texture-tools.googlecode.com/) + * + * Original license from NVIDIA follows. + */ + +// This code is in the public domain -- castanyo@yahoo.es + +#include +#include +#include + + // Get approximate luminance. + inline static unsigned int colorLuminance(Color32 c) + { + return c.r + c.g + c.b; + } + + // Get the euclidean distance between the given colors. + inline static unsigned int colorDistance(Color32 c0, Color32 c1) + { + return (c0.r - c1.r) * (c0.r - c1.r) + (c0.g - c1.g) * (c0.g - c1.g) + (c0.b - c1.b) * (c0.b - c1.b); + } + + +/// Default constructor. +ColorBlock::ColorBlock() +{ +} + +/// Init the color block with the contents of the given block. +ColorBlock::ColorBlock(const ColorBlock & block) +{ + for(unsigned int i = 0; i < 16; i++) { + color(i) = block.color(i); + } +} + + +/// Initialize this color block. +ColorBlock::ColorBlock(const Image * img, unsigned int x, unsigned int y) +{ + init(img, x, y); +} + +void ColorBlock::init(const Image * img, unsigned int x, unsigned int y) +{ + const unsigned int bw = min(img->width() - x, 4U); + const unsigned int bh = min(img->height() - y, 4U); + + static int remainder[] = { + 0, 0, 0, 0, + 0, 1, 0, 1, + 0, 1, 2, 0, + 0, 1, 2, 3, + }; + + // Blocks that are smaller than 4x4 are handled by repeating the pixels. + // @@ Thats only correct when block size is 1, 2 or 4, but not with 3. :( + + for(unsigned int i = 0; i < 4; i++) { + //const int by = i % bh; + const int by = remainder[(bh - 1) * 4 + i]; + for(unsigned int e = 0; e < 4; e++) { + //const int bx = e % bw; + const int bx = remainder[(bw - 1) * 4 + e]; + color(e, i) = img->pixel(x + bx, y + by); + } + } +} + + +void ColorBlock::swizzleDXT5n() +{ + for(int i = 0; i < 16; i++) + { + Color32 c = m_color[i]; + m_color[i] = Color32(0, c.g, 0, c.r); + } +} + +void ColorBlock::splatX() +{ + for(int i = 0; i < 16; i++) + { + unsigned char x = m_color[i].r; + m_color[i] = Color32(x, x, x, x); + } +} + +void ColorBlock::splatY() +{ + for(int i = 0; i < 16; i++) + { + unsigned char y = m_color[i].g; + m_color[i] = Color32(y, y, y, y); + } +} + + +/// Count number of unique colors in this color block. +unsigned int ColorBlock::countUniqueColors() const +{ + unsigned int count = 0; + + // @@ This does not have to be o(n^2) + for(int i = 0; i < 16; i++) + { + bool unique = true; + for(int j = 0; j < i; j++) { + if( m_color[i] != m_color[j] ) { + unique = false; + } + } + + if( unique ) { + count++; + } + } + + return count; +} + +/// Get average color of the block. +Color32 ColorBlock::averageColor() const +{ + unsigned int r, g, b, a; + r = g = b = a = 0; + + for(unsigned int i = 0; i < 16; i++) { + r += m_color[i].r; + g += m_color[i].g; + b += m_color[i].b; + a += m_color[i].a; + } + + return Color32((unsigned char)(r / 16), (unsigned char)(g / 16), (unsigned char)(b / 16), (unsigned char)(a / 16)); +} + + +/// Get diameter color range. +void ColorBlock::diameterRange(Color32 * start, Color32 * end) const +{ + Color32 c0, c1; + unsigned int best_dist = 0; + + for(int i = 0; i < 16; i++) { + for (int j = i+1; j < 16; j++) { + unsigned int dist = colorDistance(m_color[i], m_color[j]); + if( dist > best_dist ) { + best_dist = dist; + c0 = m_color[i]; + c1 = m_color[j]; + } + } + } + + *start = c0; + *end = c1; +} + +/// Get luminance color range. +void ColorBlock::luminanceRange(Color32 * start, Color32 * end) const +{ + Color32 minColor, maxColor; + unsigned int minLuminance, maxLuminance; + + maxLuminance = minLuminance = colorLuminance(m_color[0]); + + for(unsigned int i = 1; i < 16; i++) + { + unsigned int luminance = colorLuminance(m_color[i]); + + if (luminance > maxLuminance) { + maxLuminance = luminance; + maxColor = m_color[i]; + } + else if (luminance < minLuminance) { + minLuminance = luminance; + minColor = m_color[i]; + } + } + + *start = minColor; + *end = maxColor; +} + +/// Get color range based on the bounding box. +void ColorBlock::boundsRange(Color32 * start, Color32 * end) const +{ + Color32 minColor(255, 255, 255); + Color32 maxColor(0, 0, 0); + + for(unsigned int i = 0; i < 16; i++) + { + if (m_color[i].r < minColor.r) { minColor.r = m_color[i].r; } + if (m_color[i].g < minColor.g) { minColor.g = m_color[i].g; } + if (m_color[i].b < minColor.b) { minColor.b = m_color[i].b; } + if (m_color[i].r > maxColor.r) { maxColor.r = m_color[i].r; } + if (m_color[i].g > maxColor.g) { maxColor.g = m_color[i].g; } + if (m_color[i].b > maxColor.b) { maxColor.b = m_color[i].b; } + } + + // Offset range by 1/16 of the extents + Color32 inset; + inset.r = (maxColor.r - minColor.r) >> 4; + inset.g = (maxColor.g - minColor.g) >> 4; + inset.b = (maxColor.b - minColor.b) >> 4; + + minColor.r = (minColor.r + inset.r <= 255) ? minColor.r + inset.r : 255; + minColor.g = (minColor.g + inset.g <= 255) ? minColor.g + inset.g : 255; + minColor.b = (minColor.b + inset.b <= 255) ? minColor.b + inset.b : 255; + + maxColor.r = (maxColor.r >= inset.r) ? maxColor.r - inset.r : 0; + maxColor.g = (maxColor.g >= inset.g) ? maxColor.g - inset.g : 0; + maxColor.b = (maxColor.b >= inset.b) ? maxColor.b - inset.b : 0; + + *start = minColor; + *end = maxColor; +} + +/// Get color range based on the bounding box. +void ColorBlock::boundsRangeAlpha(Color32 * start, Color32 * end) const +{ + Color32 minColor(255, 255, 255, 255); + Color32 maxColor(0, 0, 0, 0); + + for(unsigned int i = 0; i < 16; i++) + { + if (m_color[i].r < minColor.r) { minColor.r = m_color[i].r; } + if (m_color[i].g < minColor.g) { minColor.g = m_color[i].g; } + if (m_color[i].b < minColor.b) { minColor.b = m_color[i].b; } + if (m_color[i].a < minColor.a) { minColor.a = m_color[i].a; } + if (m_color[i].r > maxColor.r) { maxColor.r = m_color[i].r; } + if (m_color[i].g > maxColor.g) { maxColor.g = m_color[i].g; } + if (m_color[i].b > maxColor.b) { maxColor.b = m_color[i].b; } + if (m_color[i].a > maxColor.a) { maxColor.a = m_color[i].a; } + } + + // Offset range by 1/16 of the extents + Color32 inset; + inset.r = (maxColor.r - minColor.r) >> 4; + inset.g = (maxColor.g - minColor.g) >> 4; + inset.b = (maxColor.b - minColor.b) >> 4; + inset.a = (maxColor.a - minColor.a) >> 4; + + minColor.r = (minColor.r + inset.r <= 255) ? minColor.r + inset.r : 255; + minColor.g = (minColor.g + inset.g <= 255) ? minColor.g + inset.g : 255; + minColor.b = (minColor.b + inset.b <= 255) ? minColor.b + inset.b : 255; + minColor.a = (minColor.a + inset.a <= 255) ? minColor.a + inset.a : 255; + + maxColor.r = (maxColor.r >= inset.r) ? maxColor.r - inset.r : 0; + maxColor.g = (maxColor.g >= inset.g) ? maxColor.g - inset.g : 0; + maxColor.b = (maxColor.b >= inset.b) ? maxColor.b - inset.b : 0; + maxColor.a = (maxColor.a >= inset.a) ? maxColor.a - inset.a : 0; + + *start = minColor; + *end = maxColor; +} + +/// Sort colors by abosolute value in their 16 bit representation. +void ColorBlock::sortColorsByAbsoluteValue() +{ + // Dummy selection sort. + for( unsigned int a = 0; a < 16; a++ ) { + unsigned int max = a; + Color16 cmax(m_color[a]); + + for( unsigned int b = a+1; b < 16; b++ ) { + Color16 cb(m_color[b]); + + if( cb.u > cmax.u ) { + max = b; + cmax = cb; + } + } + Color32 tmp; + swap( m_color[a], m_color[max], tmp ); + } +} + + diff --git a/source/blender/imbuf/intern/dds/ColorBlock.h b/source/blender/imbuf/intern/dds/ColorBlock.h new file mode 100644 index 00000000000..eba372768ad --- /dev/null +++ b/source/blender/imbuf/intern/dds/ColorBlock.h @@ -0,0 +1,115 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + * This file is based on a similar file from the NVIDIA texture tools + * (http://nvidia-texture-tools.googlecode.com/) + * + * Original license from NVIDIA follows. + */ + +// This code is in the public domain -- castanyo@yahoo.es + +#ifndef _DDS_COLORBLOCK_H +#define _DDS_COLORBLOCK_H + +#include +#include + +/// Uncompressed 4x4 color block. +struct ColorBlock +{ + ColorBlock(); + ColorBlock(const ColorBlock & block); + ColorBlock(const Image * img, unsigned int x, unsigned int y); + + void init(const Image * img, unsigned int x, unsigned int y); + + void swizzleDXT5n(); + void splatX(); + void splatY(); + + unsigned int countUniqueColors() const; + Color32 averageColor() const; + + void diameterRange(Color32 * start, Color32 * end) const; + void luminanceRange(Color32 * start, Color32 * end) const; + void boundsRange(Color32 * start, Color32 * end) const; + void boundsRangeAlpha(Color32 * start, Color32 * end) const; + void bestFitRange(Color32 * start, Color32 * end) const; + + void sortColorsByAbsoluteValue(); + + float volume() const; + + // Accessors + const Color32 * colors() const; + + Color32 color(unsigned int i) const; + Color32 & color(unsigned int i); + + Color32 color(unsigned int x, unsigned int y) const; + Color32 & color(unsigned int x, unsigned int y); + +private: + + Color32 m_color[4*4]; + +}; + + +/// Get pointer to block colors. +inline const Color32 * ColorBlock::colors() const +{ + return m_color; +} + +/// Get block color. +inline Color32 ColorBlock::color(unsigned int i) const +{ + return m_color[i]; +} + +/// Get block color. +inline Color32 & ColorBlock::color(unsigned int i) +{ + return m_color[i]; +} + +/// Get block color. +inline Color32 ColorBlock::color(unsigned int x, unsigned int y) const +{ + return m_color[y * 4 + x]; +} + +/// Get block color. +inline Color32 & ColorBlock::color(unsigned int x, unsigned int y) +{ + return m_color[y * 4 + x]; +} + +#endif // _DDS_COLORBLOCK_H diff --git a/source/blender/imbuf/intern/dds/Common.h b/source/blender/imbuf/intern/dds/Common.h new file mode 100644 index 00000000000..5aa8972e437 --- /dev/null +++ b/source/blender/imbuf/intern/dds/Common.h @@ -0,0 +1,44 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef _DDS_COMMON_H +#define _DDS_COMMON_H + +#ifndef min +#define min(a,b) ((a) <= (b) ? (a) : (b)) +#endif +#ifndef max +#define max(a,b) ((a) >= (b) ? (a) : (b)) +#endif +#ifndef clamp +#define clamp(x,a,b) min(max((x), (a)), (b)) +#endif +#ifndef swap +#define swap(a,b,tmp) tmp=a; a=b; b=tmp; +#endif + +#endif diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp new file mode 100644 index 00000000000..c28f8b5b72d --- /dev/null +++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp @@ -0,0 +1,924 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + * This file is based on a similar file from the NVIDIA texture tools + * (http://nvidia-texture-tools.googlecode.com/) + * + * Original license from NVIDIA follows. + */ + +// Copyright NVIDIA Corporation 2007 -- Ignacio Castano +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#include +#include +#include + +#include // printf +#include // sqrt + +/*** declarations ***/ + +#if !defined(MAKEFOURCC) +# define MAKEFOURCC(ch0, ch1, ch2, ch3) \ + ((unsigned int)((unsigned char)(ch0)) | \ + ((unsigned int)((unsigned char)(ch1)) << 8) | \ + ((unsigned int)((unsigned char)(ch2)) << 16) | \ + ((unsigned int)((unsigned char)(ch3)) << 24 )) +#endif + +static const unsigned int FOURCC_DDS = MAKEFOURCC('D', 'D', 'S', ' '); +static const unsigned int FOURCC_DXT1 = MAKEFOURCC('D', 'X', 'T', '1'); +static const unsigned int FOURCC_DXT2 = MAKEFOURCC('D', 'X', 'T', '2'); +static const unsigned int FOURCC_DXT3 = MAKEFOURCC('D', 'X', 'T', '3'); +static const unsigned int FOURCC_DXT4 = MAKEFOURCC('D', 'X', 'T', '4'); +static const unsigned int FOURCC_DXT5 = MAKEFOURCC('D', 'X', 'T', '5'); +static const unsigned int FOURCC_RXGB = MAKEFOURCC('R', 'X', 'G', 'B'); +static const unsigned int FOURCC_ATI1 = MAKEFOURCC('A', 'T', 'I', '1'); +static const unsigned int FOURCC_ATI2 = MAKEFOURCC('A', 'T', 'I', '2'); + +// RGB formats. +static const unsigned int D3DFMT_R8G8B8 = 20; +static const unsigned int D3DFMT_A8R8G8B8 = 21; +static const unsigned int D3DFMT_X8R8G8B8 = 22; +static const unsigned int D3DFMT_R5G6B5 = 23; +static const unsigned int D3DFMT_X1R5G5B5 = 24; +static const unsigned int D3DFMT_A1R5G5B5 = 25; +static const unsigned int D3DFMT_A4R4G4B4 = 26; +static const unsigned int D3DFMT_R3G3B2 = 27; +static const unsigned int D3DFMT_A8 = 28; +static const unsigned int D3DFMT_A8R3G3B2 = 29; +static const unsigned int D3DFMT_X4R4G4B4 = 30; +static const unsigned int D3DFMT_A2B10G10R10 = 31; +static const unsigned int D3DFMT_A8B8G8R8 = 32; +static const unsigned int D3DFMT_X8B8G8R8 = 33; +static const unsigned int D3DFMT_G16R16 = 34; +static const unsigned int D3DFMT_A2R10G10B10 = 35; +static const unsigned int D3DFMT_A16B16G16R16 = 36; + +// Palette formats. +static const unsigned int D3DFMT_A8P8 = 40; +static const unsigned int D3DFMT_P8 = 41; + +// Luminance formats. +static const unsigned int D3DFMT_L8 = 50; +static const unsigned int D3DFMT_A8L8 = 51; +static const unsigned int D3DFMT_A4L4 = 52; + +// Floating point formats +static const unsigned int D3DFMT_R16F = 111; +static const unsigned int D3DFMT_G16R16F = 112; +static const unsigned int D3DFMT_A16B16G16R16F = 113; +static const unsigned int D3DFMT_R32F = 114; +static const unsigned int D3DFMT_G32R32F = 115; +static const unsigned int D3DFMT_A32B32G32R32F = 116; + +static const unsigned int DDSD_CAPS = 0x00000001U; +static const unsigned int DDSD_PIXELFORMAT = 0x00001000U; +static const unsigned int DDSD_WIDTH = 0x00000004U; +static const unsigned int DDSD_HEIGHT = 0x00000002U; +static const unsigned int DDSD_PITCH = 0x00000008U; +static const unsigned int DDSD_MIPMAPCOUNT = 0x00020000U; +static const unsigned int DDSD_LINEARSIZE = 0x00080000U; +static const unsigned int DDSD_DEPTH = 0x00800000U; + +static const unsigned int DDSCAPS_COMPLEX = 0x00000008U; +static const unsigned int DDSCAPS_TEXTURE = 0x00001000U; +static const unsigned int DDSCAPS_MIPMAP = 0x00400000U; +static const unsigned int DDSCAPS2_VOLUME = 0x00200000U; +static const unsigned int DDSCAPS2_CUBEMAP = 0x00000200U; + +static const unsigned int DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400U; +static const unsigned int DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800U; +static const unsigned int DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000U; +static const unsigned int DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000U; +static const unsigned int DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000U; +static const unsigned int DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000U; +static const unsigned int DDSCAPS2_CUBEMAP_ALL_FACES = 0x0000FC00U; + +static const unsigned int DDPF_ALPHAPIXELS = 0x00000001U; +static const unsigned int DDPF_ALPHA = 0x00000002U; +static const unsigned int DDPF_FOURCC = 0x00000004U; +static const unsigned int DDPF_RGB = 0x00000040U; +static const unsigned int DDPF_PALETTEINDEXED1 = 0x00000800U; +static const unsigned int DDPF_PALETTEINDEXED2 = 0x00001000U; +static const unsigned int DDPF_PALETTEINDEXED4 = 0x00000008U; +static const unsigned int DDPF_PALETTEINDEXED8 = 0x00000020U; +static const unsigned int DDPF_LUMINANCE = 0x00020000U; +static const unsigned int DDPF_ALPHAPREMULT = 0x00008000U; +static const unsigned int DDPF_NORMAL = 0x80000000U; // @@ Custom nv flag. + +/*** implementation ***/ + +void mem_read(Stream & mem, DDSPixelFormat & pf) +{ + mem_read(mem, pf.size); + mem_read(mem, pf.flags); + mem_read(mem, pf.fourcc); + mem_read(mem, pf.bitcount); + mem_read(mem, pf.rmask); + mem_read(mem, pf.gmask); + mem_read(mem, pf.bmask); + mem_read(mem, pf.amask); +} + +void mem_read(Stream & mem, DDSCaps & caps) +{ + mem_read(mem, caps.caps1); + mem_read(mem, caps.caps2); + mem_read(mem, caps.caps3); + mem_read(mem, caps.caps4); +} + +void mem_read(Stream & mem, DDSHeader & header) +{ + mem_read(mem, header.fourcc); + mem_read(mem, header.size); + mem_read(mem, header.flags); + mem_read(mem, header.height); + mem_read(mem, header.width); + mem_read(mem, header.pitch); + mem_read(mem, header.depth); + mem_read(mem, header.mipmapcount); + for (unsigned int i = 0; i < 11; i++) mem_read(mem, header.reserved[i]); + mem_read(mem, header.pf); + mem_read(mem, header.caps); + mem_read(mem, header.notused); +} + +DDSHeader::DDSHeader() +{ + this->fourcc = FOURCC_DDS; + this->size = 124; + this->flags = (DDSD_CAPS|DDSD_PIXELFORMAT); + this->height = 0; + this->width = 0; + this->pitch = 0; + this->depth = 0; + this->mipmapcount = 0; + for (unsigned int i = 0; i < 11; i++) this->reserved[i] = 0; + + // Store version information on the reserved header attributes. + this->reserved[9] = MAKEFOURCC('N', 'V', 'T', 'T'); + this->reserved[10] = (0 << 16) | (9 << 8) | (3); // major.minor.revision + + this->pf.size = 32; + this->pf.flags = 0; + this->pf.fourcc = 0; + this->pf.bitcount = 0; + this->pf.rmask = 0; + this->pf.gmask = 0; + this->pf.bmask = 0; + this->pf.amask = 0; + this->caps.caps1 = DDSCAPS_TEXTURE; + this->caps.caps2 = 0; + this->caps.caps3 = 0; + this->caps.caps4 = 0; + this->notused = 0; +} + +void DDSHeader::setWidth(unsigned int w) +{ + this->flags |= DDSD_WIDTH; + this->width = w; +} + +void DDSHeader::setHeight(unsigned int h) +{ + this->flags |= DDSD_HEIGHT; + this->height = h; +} + +void DDSHeader::setDepth(unsigned int d) +{ + this->flags |= DDSD_DEPTH; + this->height = d; +} + +void DDSHeader::setMipmapCount(unsigned int count) +{ + if (count == 0) + { + this->flags &= ~DDSD_MIPMAPCOUNT; + this->mipmapcount = 0; + + if (this->caps.caps2 == 0) { + this->caps.caps1 = DDSCAPS_TEXTURE; + } + else { + this->caps.caps1 = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX; + } + } + else + { + this->flags |= DDSD_MIPMAPCOUNT; + this->mipmapcount = count; + + this->caps.caps1 |= DDSCAPS_COMPLEX | DDSCAPS_MIPMAP; + } +} + +void DDSHeader::setTexture2D() +{ + // nothing to do here. +} + +void DDSHeader::setTexture3D() +{ + this->caps.caps2 = DDSCAPS2_VOLUME; +} + +void DDSHeader::setTextureCube() +{ + this->caps.caps1 |= DDSCAPS_COMPLEX; + this->caps.caps2 = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALL_FACES; +} + +void DDSHeader::setLinearSize(unsigned int size) +{ + this->flags &= ~DDSD_PITCH; + this->flags |= DDSD_LINEARSIZE; + this->pitch = size; +} + +void DDSHeader::setPitch(unsigned int pitch) +{ + this->flags &= ~DDSD_LINEARSIZE; + this->flags |= DDSD_PITCH; + this->pitch = pitch; +} + +void DDSHeader::setFourCC(unsigned char c0, unsigned char c1, unsigned char c2, unsigned char c3) +{ + // set fourcc pixel format. + this->pf.flags = DDPF_FOURCC; + this->pf.fourcc = MAKEFOURCC(c0, c1, c2, c3); + this->pf.bitcount = 0; + this->pf.rmask = 0; + this->pf.gmask = 0; + this->pf.bmask = 0; + this->pf.amask = 0; +} + +void DDSHeader::setPixelFormat(unsigned int bitcount, unsigned int rmask, unsigned int gmask, unsigned int bmask, unsigned int amask) +{ + // Make sure the masks are correct. + if ((rmask & gmask) || \ + (rmask & bmask) || \ + (rmask & amask) || \ + (gmask & bmask) || \ + (gmask & amask) || \ + (bmask & amask)) { + printf("DDS: bad RGBA masks, pixel format not set\n"); + return; + } + + this->pf.flags = DDPF_RGB; + + if (amask != 0) { + this->pf.flags |= DDPF_ALPHAPIXELS; + } + + if (bitcount == 0) + { + // Compute bit count from the masks. + unsigned int total = rmask | gmask | bmask | amask; + while(total != 0) { + bitcount++; + total >>= 1; + } + // @@ Align to 8? + } + + this->pf.fourcc = 0; + this->pf.bitcount = bitcount; + this->pf.rmask = rmask; + this->pf.gmask = gmask; + this->pf.bmask = bmask; + this->pf.amask = amask; +} + +void DDSHeader::setNormalFlag(bool b) +{ + if (b) this->pf.flags |= DDPF_NORMAL; + else this->pf.flags &= ~DDPF_NORMAL; +} + +/* +void DDSHeader::swapBytes() +{ + this->fourcc = POSH_LittleU32(this->fourcc); + this->size = POSH_LittleU32(this->size); + this->flags = POSH_LittleU32(this->flags); + this->height = POSH_LittleU32(this->height); + this->width = POSH_LittleU32(this->width); + this->pitch = POSH_LittleU32(this->pitch); + this->depth = POSH_LittleU32(this->depth); + this->mipmapcount = POSH_LittleU32(this->mipmapcount); + + for(int i = 0; i < 11; i++) { + this->reserved[i] = POSH_LittleU32(this->reserved[i]); + } + + this->pf.size = POSH_LittleU32(this->pf.size); + this->pf.flags = POSH_LittleU32(this->pf.flags); + this->pf.fourcc = POSH_LittleU32(this->pf.fourcc); + this->pf.bitcount = POSH_LittleU32(this->pf.bitcount); + this->pf.rmask = POSH_LittleU32(this->pf.rmask); + this->pf.gmask = POSH_LittleU32(this->pf.gmask); + this->pf.bmask = POSH_LittleU32(this->pf.bmask); + this->pf.amask = POSH_LittleU32(this->pf.amask); + this->caps.caps1 = POSH_LittleU32(this->caps.caps1); + this->caps.caps2 = POSH_LittleU32(this->caps.caps2); + this->caps.caps3 = POSH_LittleU32(this->caps.caps3); + this->caps.caps4 = POSH_LittleU32(this->caps.caps4); + this->notused = POSH_LittleU32(this->notused); +} +*/ + + +DirectDrawSurface::DirectDrawSurface(unsigned char *mem, unsigned int size) : stream(mem, size), header() +{ + mem_read(stream, header); +} + +DirectDrawSurface::~DirectDrawSurface() +{ +} + +bool DirectDrawSurface::isValid() const +{ + if (header.fourcc != FOURCC_DDS || header.size != 124) + { + return false; + } + + const unsigned int required = (DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS|DDSD_PIXELFORMAT); + if( (header.flags & required) != required ) { + return false; + } + + if (header.pf.size != 32) { + return false; + } + + /* in some files DDSCAPS_TEXTURE is missing: silently ignore */ + /* + if( !(header.caps.caps1 & DDSCAPS_TEXTURE) ) { + return false; + } + */ + + return true; +} + +bool DirectDrawSurface::isSupported() const +{ + if (header.pf.flags & DDPF_FOURCC) + { + if (header.pf.fourcc != FOURCC_DXT1 && + header.pf.fourcc != FOURCC_DXT2 && + header.pf.fourcc != FOURCC_DXT3 && + header.pf.fourcc != FOURCC_DXT4 && + header.pf.fourcc != FOURCC_DXT5 && + header.pf.fourcc != FOURCC_RXGB && + header.pf.fourcc != FOURCC_ATI1 && + header.pf.fourcc != FOURCC_ATI2) + { + // Unknown fourcc code. + return false; + } + } + else if (header.pf.flags & DDPF_RGB) + { + if (header.pf.bitcount == 24) + { + return true; + } + else if (header.pf.bitcount == 32) + { + return true; + } + else + { + // Unsupported pixel format. + return false; + } + } + else + { + return false; + } + + if (isTextureCube() && (header.caps.caps2 & DDSCAPS2_CUBEMAP_ALL_FACES) != DDSCAPS2_CUBEMAP_ALL_FACES) + { + // Cubemaps must contain all faces. + return false; + } + + if (isTexture3D()) + { + // @@ 3D textures not supported yet. + return false; + } + + return true; +} + + +unsigned int DirectDrawSurface::mipmapCount() const +{ + if (header.flags & DDSD_MIPMAPCOUNT) return header.mipmapcount; + else return 0; +} + + +unsigned int DirectDrawSurface::width() const +{ + if (header.flags & DDSD_WIDTH) return header.width; + else return 1; +} + +unsigned int DirectDrawSurface::height() const +{ + if (header.flags & DDSD_HEIGHT) return header.height; + else return 1; +} + +unsigned int DirectDrawSurface::depth() const +{ + if (header.flags & DDSD_DEPTH) return header.depth; + else return 1; +} + +bool DirectDrawSurface::hasAlpha() const +{ + if ((header.pf.flags & DDPF_RGB) && (header.pf.amask == 0)) + { + return false; + } + else if (header.pf.fourcc == FOURCC_DXT1) + { + return false; + } + else + { + return true; + } +} + +bool DirectDrawSurface::isTexture2D() const +{ + return !isTexture3D() && !isTextureCube(); +} + +bool DirectDrawSurface::isTexture3D() const +{ + return (header.caps.caps2 & DDSCAPS2_VOLUME) != 0; +} + +bool DirectDrawSurface::isTextureCube() const +{ + return (header.caps.caps2 & DDSCAPS2_CUBEMAP) != 0; +} + +void DirectDrawSurface::mipmap(Image * img, unsigned int face, unsigned int mipmap) +{ + stream.seek(offset(face, mipmap)); + + unsigned int w = width(); + unsigned int h = height(); + + // Compute width and height. + for (unsigned int m = 0; m < mipmap; m++) + { + w = max(w/2, 1U); + h = max(h/2, 1U); + } + + img->allocate(w, h); + + if (header.pf.flags & DDPF_RGB) + { + readLinearImage(img); + } + else if (header.pf.flags & DDPF_FOURCC) + { + readBlockImage(img); + } +} + +/* helper function for readLinearImage */ +void maskShiftAndSize(unsigned int mask, unsigned int * shift, unsigned int * size) +{ + if (!mask) + { + *shift = 0; + *size = 0; + return; + } + + *shift = 0; + while((mask & 1) == 0) { + ++(*shift); + mask >>= 1; + } + + *size = 0; + while((mask & 1) == 1) { + ++(*size); + mask >>= 1; + } +} + +/* helper function for readLinearImage */ +unsigned int convert(unsigned int c, unsigned int inbits, unsigned int outbits) +{ + if (inbits == 0) { + return 0; + } + else if (inbits == outbits) + { + return c; + } + else if (inbits > outbits) + { + // truncate + return c >> (inbits - outbits); + } + else + { + // bitexpand + return (c << (outbits - inbits)) | convert(c, inbits, outbits - inbits); + } +} + +void DirectDrawSurface::readLinearImage(Image * img) +{ + const unsigned int w = img->width(); + const unsigned int h = img->height(); + + unsigned int rshift, rsize; + maskShiftAndSize(header.pf.rmask, &rshift, &rsize); + + unsigned int gshift, gsize; + maskShiftAndSize(header.pf.gmask, &gshift, &gsize); + + unsigned int bshift, bsize; + maskShiftAndSize(header.pf.bmask, &bshift, &bsize); + + unsigned int ashift, asize; + maskShiftAndSize(header.pf.amask, &ashift, &asize); + + unsigned int byteCount = (header.pf.bitcount + 7) / 8; + if (byteCount > 4) + { + /* just in case... we could have segfaults later on if byteCount > 4 */ + printf("DDS: bitcount too large (file corrupt?)"); + return; + } + + if (header.pf.amask != 0) + { + img->setFormat(Image::Format_ARGB); + } + + // Read linear RGB images. + for (unsigned int y = 0; y < h; y++) + { + for (unsigned int x = 0; x < w; x++) + { + unsigned int c = 0; + mem_read(stream, (unsigned char *)(&c), byteCount); + + Color32 pixel(0, 0, 0, 0xFF); + pixel.r = convert(c >> rshift, rsize, 8); + pixel.g = convert(c >> gshift, gsize, 8); + pixel.b = convert(c >> bshift, bsize, 8); + pixel.a = convert(c >> ashift, asize, 8); + + img->pixel(x, y) = pixel; + } + } +} + +void DirectDrawSurface::readBlockImage(Image * img) +{ + const unsigned int w = img->width(); + const unsigned int h = img->height(); + + const unsigned int bw = (w + 3) / 4; + const unsigned int bh = (h + 3) / 4; + + for (unsigned int by = 0; by < bh; by++) + { + for (unsigned int bx = 0; bx < bw; bx++) + { + ColorBlock block; + + // Read color block. + readBlock(&block); + + // Write color block. + for (unsigned int y = 0; y < min(4U, h-4*by); y++) + { + for (unsigned int x = 0; x < min(4U, w-4*bx); x++) + { + img->pixel(4*bx+x, 4*by+y) = block.color(x, y); + } + } + } + } +} + +static Color32 buildNormal(unsigned char x, unsigned char y) +{ + float nx = 2 * (x / 255) - 1; + float ny = 2 * (x / 255) - 1; + float nz = sqrt(1 - nx*nx - ny*ny); + unsigned char z = clamp(int(255 * (nz + 1) / 2), 0, 255); + + return Color32(x, y, z); +} + + +void DirectDrawSurface::readBlock(ColorBlock * rgba) +{ + if (header.pf.fourcc == FOURCC_DXT1) + { + BlockDXT1 block; + mem_read(stream, block); + block.decodeBlock(rgba); + } + else if (header.pf.fourcc == FOURCC_DXT2 || + header.pf.fourcc == FOURCC_DXT3) + { + BlockDXT3 block; + mem_read(stream, block); + block.decodeBlock(rgba); + } + else if (header.pf.fourcc == FOURCC_DXT4 || + header.pf.fourcc == FOURCC_DXT5 || + header.pf.fourcc == FOURCC_RXGB) + { + BlockDXT5 block; + mem_read(stream, block); + block.decodeBlock(rgba); + + if (header.pf.fourcc == FOURCC_RXGB) + { + // Swap R & A. + for (int i = 0; i < 16; i++) + { + Color32 & c = rgba->color(i); + unsigned int tmp = c.r; + c.r = c.a; + c.a = tmp; + } + } + } + else if (header.pf.fourcc == FOURCC_ATI1) + { + BlockATI1 block; + mem_read(stream, block); + block.decodeBlock(rgba); + } + else if (header.pf.fourcc == FOURCC_ATI2) + { + BlockATI2 block; + mem_read(stream, block); + block.decodeBlock(rgba); + } + + // If normal flag set, convert to normal. + if (header.pf.flags & DDPF_NORMAL) + { + if (header.pf.fourcc == FOURCC_ATI2) + { + for (int i = 0; i < 16; i++) + { + Color32 & c = rgba->color(i); + c = buildNormal(c.r, c.g); + } + } + else if (header.pf.fourcc == FOURCC_DXT5) + { + for (int i = 0; i < 16; i++) + { + Color32 & c = rgba->color(i); + c = buildNormal(c.g, c.a); + } + } + } +} + + +unsigned int DirectDrawSurface::blockSize() const +{ + switch(header.pf.fourcc) + { + case FOURCC_DXT1: + case FOURCC_ATI1: + return 8; + case FOURCC_DXT2: + case FOURCC_DXT3: + case FOURCC_DXT4: + case FOURCC_DXT5: + case FOURCC_RXGB: + case FOURCC_ATI2: + return 16; + }; + + // Not a block image. + return 0; +} + +unsigned int DirectDrawSurface::mipmapSize(unsigned int mipmap) const +{ + unsigned int w = width(); + unsigned int h = height(); + unsigned int d = depth(); + + for (unsigned int m = 0; m < mipmap; m++) + { + w = max(1U, w / 2); + h = max(1U, h / 2); + d = max(1U, d / 2); + } + + if (header.pf.flags & DDPF_FOURCC) + { + // @@ How are 3D textures aligned? + w = (w + 3) / 4; + h = (h + 3) / 4; + return blockSize() * w * h; + } + else if (header.pf.flags & DDPF_RGB) + { + // Align pixels to bytes. + unsigned int byteCount = (header.pf.bitcount + 7) / 8; + + // Align pitch to 4 bytes. + unsigned int pitch = 4 * ((w * byteCount + 3) / 4); + + return pitch * h * d; + } + else { + printf("DDS: mipmap format not supported\n"); + return(0); + }; +} + +unsigned int DirectDrawSurface::faceSize() const +{ + const unsigned int count = mipmapCount(); + unsigned int size = 0; + + for (unsigned int m = 0; m < count; m++) + { + size += mipmapSize(m); + } + + return size; +} + +unsigned int DirectDrawSurface::offset(const unsigned int face, const unsigned int mipmap) +{ + unsigned int size = sizeof(DDSHeader); + + if (face != 0) + { + size += face * faceSize(); + } + + for (unsigned int m = 0; m < mipmap; m++) + { + size += mipmapSize(m); + } + + return size; +} + + +void DirectDrawSurface::printInfo() const +{ + /* printf("FOURCC: %c%c%c%c\n", ((unsigned char *)&header.fourcc)[0], ((unsigned char *)&header.fourcc)[1], ((unsigned char *)&header.fourcc)[2], ((unsigned char *)&header.fourcc)[3]); */ + printf("Flags: 0x%.8X\n", header.flags); + if (header.flags & DDSD_CAPS) printf("\tDDSD_CAPS\n"); + if (header.flags & DDSD_PIXELFORMAT) printf("\tDDSD_PIXELFORMAT\n"); + if (header.flags & DDSD_WIDTH) printf("\tDDSD_WIDTH\n"); + if (header.flags & DDSD_HEIGHT) printf("\tDDSD_HEIGHT\n"); + if (header.flags & DDSD_DEPTH) printf("\tDDSD_DEPTH\n"); + if (header.flags & DDSD_PITCH) printf("\tDDSD_PITCH\n"); + if (header.flags & DDSD_LINEARSIZE) printf("\tDDSD_LINEARSIZE\n"); + if (header.flags & DDSD_MIPMAPCOUNT) printf("\tDDSD_MIPMAPCOUNT\n"); + + printf("Height: %d\n", header.height); + printf("Width: %d\n", header.width); + printf("Depth: %d\n", header.depth); + if (header.flags & DDSD_PITCH) printf("Pitch: %d\n", header.pitch); + else if (header.flags & DDSD_LINEARSIZE) printf("Linear size: %d\n", header.pitch); + printf("Mipmap count: %d\n", header.mipmapcount); + + printf("Pixel Format:\n"); + /* printf("\tSize: %d\n", header.pf.size); */ + printf("\tFlags: 0x%.8X\n", header.pf.flags); + if (header.pf.flags & DDPF_RGB) printf("\t\tDDPF_RGB\n"); + if (header.pf.flags & DDPF_FOURCC) printf("\t\tDDPF_FOURCC\n"); + if (header.pf.flags & DDPF_ALPHAPIXELS) printf("\t\tDDPF_ALPHAPIXELS\n"); + if (header.pf.flags & DDPF_ALPHA) printf("\t\tDDPF_ALPHA\n"); + if (header.pf.flags & DDPF_PALETTEINDEXED1) printf("\t\tDDPF_PALETTEINDEXED1\n"); + if (header.pf.flags & DDPF_PALETTEINDEXED2) printf("\t\tDDPF_PALETTEINDEXED2\n"); + if (header.pf.flags & DDPF_PALETTEINDEXED4) printf("\t\tDDPF_PALETTEINDEXED4\n"); + if (header.pf.flags & DDPF_PALETTEINDEXED8) printf("\t\tDDPF_PALETTEINDEXED8\n"); + if (header.pf.flags & DDPF_ALPHAPREMULT) printf("\t\tDDPF_ALPHAPREMULT\n"); + if (header.pf.flags & DDPF_NORMAL) printf("\t\tDDPF_NORMAL\n"); + + printf("\tFourCC: '%c%c%c%c'\n", ((header.pf.fourcc >> 0) & 0xFF), ((header.pf.fourcc >> 8) & 0xFF), ((header.pf.fourcc >> 16) & 0xFF), ((header.pf.fourcc >> 24) & 0xFF)); + printf("\tBit count: %d\n", header.pf.bitcount); + printf("\tRed mask: 0x%.8X\n", header.pf.rmask); + printf("\tGreen mask: 0x%.8X\n", header.pf.gmask); + printf("\tBlue mask: 0x%.8X\n", header.pf.bmask); + printf("\tAlpha mask: 0x%.8X\n", header.pf.amask); + + printf("Caps:\n"); + printf("\tCaps 1: 0x%.8X\n", header.caps.caps1); + if (header.caps.caps1 & DDSCAPS_COMPLEX) printf("\t\tDDSCAPS_COMPLEX\n"); + if (header.caps.caps1 & DDSCAPS_TEXTURE) printf("\t\tDDSCAPS_TEXTURE\n"); + if (header.caps.caps1 & DDSCAPS_MIPMAP) printf("\t\tDDSCAPS_MIPMAP\n"); + + printf("\tCaps 2: 0x%.8X\n", header.caps.caps2); + if (header.caps.caps2 & DDSCAPS2_VOLUME) printf("\t\tDDSCAPS2_VOLUME\n"); + else if (header.caps.caps2 & DDSCAPS2_CUBEMAP) + { + printf("\t\tDDSCAPS2_CUBEMAP\n"); + if ((header.caps.caps2 & DDSCAPS2_CUBEMAP_ALL_FACES) == DDSCAPS2_CUBEMAP_ALL_FACES) printf("\t\tDDSCAPS2_CUBEMAP_ALL_FACES\n"); + else { + if (header.caps.caps2 & DDSCAPS2_CUBEMAP_POSITIVEX) printf("\t\tDDSCAPS2_CUBEMAP_POSITIVEX\n"); + if (header.caps.caps2 & DDSCAPS2_CUBEMAP_NEGATIVEX) printf("\t\tDDSCAPS2_CUBEMAP_NEGATIVEX\n"); + if (header.caps.caps2 & DDSCAPS2_CUBEMAP_POSITIVEY) printf("\t\tDDSCAPS2_CUBEMAP_POSITIVEY\n"); + if (header.caps.caps2 & DDSCAPS2_CUBEMAP_NEGATIVEY) printf("\t\tDDSCAPS2_CUBEMAP_NEGATIVEY\n"); + if (header.caps.caps2 & DDSCAPS2_CUBEMAP_POSITIVEZ) printf("\t\tDDSCAPS2_CUBEMAP_POSITIVEZ\n"); + if (header.caps.caps2 & DDSCAPS2_CUBEMAP_NEGATIVEZ) printf("\t\tDDSCAPS2_CUBEMAP_NEGATIVEZ\n"); + } + } + + printf("\tCaps 3: 0x%.8X\n", header.caps.caps3); + printf("\tCaps 4: 0x%.8X\n", header.caps.caps4); + + if (header.reserved[9] == MAKEFOURCC('N', 'V', 'T', 'T')) + { + int major = (header.reserved[10] >> 16) & 0xFF; + int minor = (header.reserved[10] >> 8) & 0xFF; + int revision= header.reserved[10] & 0xFF; + + printf("Version:\n"); + printf("\tNVIDIA Texture Tools %d.%d.%d\n", major, minor, revision); + } +} + diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.h b/source/blender/imbuf/intern/dds/DirectDrawSurface.h new file mode 100644 index 00000000000..2b3319d05a1 --- /dev/null +++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.h @@ -0,0 +1,162 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + * This file is based on a similar file from the NVIDIA texture tools + * (http://nvidia-texture-tools.googlecode.com/) + * + * Original license from NVIDIA follows. + */ + +// Copyright NVIDIA Corporation 2007 -- Ignacio Castano +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#ifndef _DDS_DIRECTDRAWSURFACE_H +#define _DDS_DIRECTDRAWSURFACE_H + +#include +#include +#include + +struct DDSPixelFormat { + unsigned int size; + unsigned int flags; + unsigned int fourcc; + unsigned int bitcount; + unsigned int rmask; + unsigned int gmask; + unsigned int bmask; + unsigned int amask; +}; + +struct DDSCaps { + unsigned int caps1; + unsigned int caps2; + unsigned int caps3; + unsigned int caps4; +}; + +/// DDS file header. +struct DDSHeader { + unsigned int fourcc; + unsigned int size; + unsigned int flags; + unsigned int height; + unsigned int width; + unsigned int pitch; + unsigned int depth; + unsigned int mipmapcount; + unsigned int reserved[11]; + DDSPixelFormat pf; + DDSCaps caps; + unsigned int notused; + + // Helper methods. + DDSHeader(); + + void setWidth(unsigned int w); + void setHeight(unsigned int h); + void setDepth(unsigned int d); + void setMipmapCount(unsigned int count); + void setTexture2D(); + void setTexture3D(); + void setTextureCube(); + void setLinearSize(unsigned int size); + void setPitch(unsigned int pitch); + void setFourCC(unsigned char c0, unsigned char c1, unsigned char c2, unsigned char c3); + void setPixelFormat(unsigned int bitcount, unsigned int rmask, unsigned int gmask, unsigned int bmask, unsigned int amask); + void setNormalFlag(bool b); + + /* void swapBytes(); */ +}; + +/// DirectDraw Surface. (DDS) +class DirectDrawSurface +{ +public: + DirectDrawSurface(unsigned char *mem, unsigned int size); + ~DirectDrawSurface(); + + bool isValid() const; + bool isSupported() const; + + unsigned int mipmapCount() const; + unsigned int width() const; + unsigned int height() const; + unsigned int depth() const; + bool isTexture2D() const; + bool isTexture3D() const; + bool isTextureCube() const; + bool hasAlpha() const; /* false for DXT1, true for all others */ + + void mipmap(Image * img, unsigned int f, unsigned int m); + + void printInfo() const; + +private: + + unsigned int blockSize() const; + unsigned int faceSize() const; + unsigned int mipmapSize(unsigned int m) const; + + unsigned int offset(unsigned int f, unsigned int m); + + void readLinearImage(Image * img); + void readBlockImage(Image * img); + void readBlock(ColorBlock * rgba); + + +private: + Stream stream; // memory where DDS file resides + DDSHeader header; +}; + +void mem_read(Stream & mem, DDSPixelFormat & pf); +void mem_read(Stream & mem, DDSCaps & caps); +void mem_read(Stream & mem, DDSHeader & header); + +#endif // _DDS_DIRECTDRAWSURFACE_H diff --git a/source/blender/imbuf/intern/dds/Image.cpp b/source/blender/imbuf/intern/dds/Image.cpp new file mode 100644 index 00000000000..f3e6fa38955 --- /dev/null +++ b/source/blender/imbuf/intern/dds/Image.cpp @@ -0,0 +1,132 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + * This file is based on a similar file from the NVIDIA texture tools + * (http://nvidia-texture-tools.googlecode.com/) + * + * Original license from NVIDIA follows. + */ + +// This code is in the public domain -- castanyo@yahoo.es + +#include +#include + +#include // printf + +Image::Image() : m_width(0), m_height(0), m_format(Format_RGB), m_data(0) +{ +} + +Image::~Image() +{ + free(); +} + +void Image::allocate(unsigned int w, unsigned int h) +{ + free(); + m_width = w; + m_height = h; + m_data = new Color32[w * h]; +} + +void Image::free() +{ + if (m_data) delete [] m_data; + m_data = 0; +} + + +unsigned int Image::width() const +{ + return m_width; +} + +unsigned int Image::height() const +{ + return m_height; +} + +const Color32 * Image::scanline(unsigned int h) const +{ + if (h >= m_height) { + printf("DDS: scanline beyond dimensions of image"); + return m_data; + } + return m_data + h * m_width; +} + +Color32 * Image::scanline(unsigned int h) +{ + if (h >= m_height) { + printf("DDS: scanline beyond dimensions of image"); + return m_data; + } + return m_data + h * m_width; +} + +const Color32 * Image::pixels() const +{ + return m_data; +} + +Color32 * Image::pixels() +{ + return m_data; +} + +const Color32 & Image::pixel(unsigned int idx) const +{ + if (idx >= m_width * m_height) { + printf("DDS: pixel beyond dimensions of image"); + return m_data[0]; + } + return m_data[idx]; +} + +Color32 & Image::pixel(unsigned int idx) +{ + if (idx >= m_width * m_height) { + printf("DDS: pixel beyond dimensions of image"); + return m_data[0]; + } + return m_data[idx]; +} + + +Image::Format Image::format() const +{ + return m_format; +} + +void Image::setFormat(Image::Format f) +{ + m_format = f; +} + diff --git a/source/blender/imbuf/intern/dds/Image.h b/source/blender/imbuf/intern/dds/Image.h new file mode 100644 index 00000000000..10356774777 --- /dev/null +++ b/source/blender/imbuf/intern/dds/Image.h @@ -0,0 +1,103 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + * This file is based on a similar file from the NVIDIA texture tools + * (http://nvidia-texture-tools.googlecode.com/) + * + * Original license from NVIDIA follows. + */ + +// This code is in the public domain -- castanyo@yahoo.es + +#ifndef _DDS_IMAGE_H +#define _DDS_IMAGE_H + +#include + +/// 32 bit RGBA image. +class Image +{ +public: + + enum Format + { + Format_RGB, + Format_ARGB, + }; + + Image(); + ~Image(); + + void allocate(unsigned int w, unsigned int h); + /* + bool load(const char * name); + + void wrap(void * data, unsigned int w, unsigned int h); + void unwrap(); + */ + + unsigned int width() const; + unsigned int height() const; + + const Color32 * scanline(unsigned int h) const; + Color32 * scanline(unsigned int h); + + const Color32 * pixels() const; + Color32 * pixels(); + + const Color32 & pixel(unsigned int idx) const; + Color32 & pixel(unsigned int idx); + + const Color32 & pixel(unsigned int x, unsigned int y) const; + Color32 & pixel(unsigned int x, unsigned int y); + + Format format() const; + void setFormat(Format f); + +private: + void free(); + +private: + unsigned int m_width; + unsigned int m_height; + Format m_format; + Color32 * m_data; +}; + + +inline const Color32 & Image::pixel(unsigned int x, unsigned int y) const +{ + return pixel(y * width() + x); +} + +inline Color32 & Image::pixel(unsigned int x, unsigned int y) +{ + return pixel(y * width() + x); +} + +#endif // _DDS_IMAGE_H diff --git a/source/blender/imbuf/intern/dds/Makefile b/source/blender/imbuf/intern/dds/Makefile new file mode 100644 index 00000000000..88d59080a47 --- /dev/null +++ b/source/blender/imbuf/intern/dds/Makefile @@ -0,0 +1,63 @@ +# +# $Id: Makefile 7037 2006-03-12 14:11:23Z ton $ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = dds +DIR = $(OCGDIR)/blender/imbuf/dds +SOURCEDIR = source/blender/imbuf/intern/dds + +include nan_compile.mk +include nan_definitions.mk + +CFLAGS += $(LEVEL_1_C_WARNINGS) + +CPPFLAGS += -I$(NAN_JPEG)/include +CPPFLAGS += -I$(NAN_PNG)/include +CPPFLAGS += -I$(NAN_ZLIB)/include +CPPFLAGS += -I$(NAN_TIFF)/include +CPPFLAGS += -I../../../include +CPPFLAGS += -I../../../blenkernel +CPPFLAGS += -I../../../blenlib +CPPFLAGS += -I../../../avi +CPPFLAGS += -I../../../quicktime +# path to the guarded memory allocator +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include +CPPFLAGS += -I$(NAN_MEMUTIL)/include +# This is not really needed, but until /include is cleaned, it must be +# there for proper compilation. +# - No, it is also needed in antialias, for listbase (nzc) +CPPFLAGS += -I../../../makesdna +# external interface of this module +CPPFLAGS += -I../.. +CPPFLAGS += -I.. +CPPFLAGS += -I. +CPPFLAGS += -DWITH_DDS diff --git a/source/blender/imbuf/intern/dds/SConscript b/source/blender/imbuf/intern/dds/SConscript new file mode 100644 index 00000000000..d005bae02be --- /dev/null +++ b/source/blender/imbuf/intern/dds/SConscript @@ -0,0 +1,19 @@ +#!/usr/bin/python +Import ('env') + +source_files = ['dds_api.cpp', 'DirectDrawSurface.cpp', 'Stream.cpp', 'BlockDXT.cpp', 'ColorBlock.cpp', 'Image.cpp'] + +incs = ['.', + '../../', + '../..', + '..', + '../../../makesdna', + '../../../blenkernel', + '../../../blenlib', + 'intern/include', + '#/intern/guardedalloc'] + + +defs = ['WITH_DDS'] + +env.BlenderLib ('bf_dds', source_files, incs, defs, libtype=['core','player'], priority = [90, 200]) diff --git a/source/blender/imbuf/intern/dds/Stream.cpp b/source/blender/imbuf/intern/dds/Stream.cpp new file mode 100644 index 00000000000..2340598b4fa --- /dev/null +++ b/source/blender/imbuf/intern/dds/Stream.cpp @@ -0,0 +1,99 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include + +#include // printf +#include // memcpy + +unsigned int Stream::seek(unsigned int p) +{ + if (p > size) { + printf("DDS: trying to seek beyond end of stream (corrupt file?)"); + } + else { + pos = p; + } + + return pos; +} + +unsigned int mem_read(Stream & mem, unsigned long long & i) +{ + if (mem.pos + 8 > mem.size) { + printf("DDS: trying to read beyond end of stream (corrupt file?)"); + return(0); + }; + memcpy(&i, mem.mem + mem.pos, 8); // @@ todo: make sure little endian + mem.pos += 8; + return(8); +} + +unsigned int mem_read(Stream & mem, unsigned int & i) +{ + if (mem.pos + 4 > mem.size) { + printf("DDS: trying to read beyond end of stream (corrupt file?)"); + return(0); + }; + memcpy(&i, mem.mem + mem.pos, 4); // @@ todo: make sure little endian + mem.pos += 4; + return(4); +} + +unsigned int mem_read(Stream & mem, unsigned short & i) +{ + if (mem.pos + 2 > mem.size) { + printf("DDS: trying to read beyond end of stream (corrupt file?)"); + return(0); + }; + memcpy(&i, mem.mem + mem.pos, 2); // @@ todo: make sure little endian + mem.pos += 2; + return(2); +} + +unsigned int mem_read(Stream & mem, unsigned char & i) +{ + if (mem.pos + 1 > mem.size) { + printf("DDS: trying to read beyond end of stream (corrupt file?)"); + return(0); + }; + i = (mem.mem + mem.pos)[0]; + mem.pos += 1; + return(1); +} + +unsigned int mem_read(Stream & mem, unsigned char *i, unsigned int cnt) +{ + if (mem.pos + cnt > mem.size) { + printf("DDS: trying to read beyond end of stream (corrupt file?)"); + return(0); + }; + memcpy(i, mem.mem + mem.pos, cnt); + mem.pos += cnt; + return(cnt); +} + diff --git a/source/blender/imbuf/intern/dds/Stream.h b/source/blender/imbuf/intern/dds/Stream.h new file mode 100644 index 00000000000..373e68db44e --- /dev/null +++ b/source/blender/imbuf/intern/dds/Stream.h @@ -0,0 +1,49 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* simple memory stream functions with buffer overflow check */ + +#ifndef _STREAM_H +#define _STREAM_H + +struct Stream +{ + unsigned char *mem; // location in memory + unsigned int size; // size + unsigned int pos; // current position + Stream(unsigned char *m, unsigned int s) : mem(m), size(s), pos(0) {}; + unsigned int seek(unsigned int p); +}; + +unsigned int mem_read(Stream & mem, unsigned long long & i); +unsigned int mem_read(Stream & mem, unsigned int & i); +unsigned int mem_read(Stream & mem, unsigned short & i); +unsigned int mem_read(Stream & mem, unsigned char & i); +unsigned int mem_read(Stream & mem, unsigned char *i, unsigned int cnt); + +#endif // _STREAM_H + diff --git a/source/blender/imbuf/intern/dds/dds_api.cpp b/source/blender/imbuf/intern/dds/dds_api.cpp new file mode 100644 index 00000000000..3de30b9f183 --- /dev/null +++ b/source/blender/imbuf/intern/dds/dds_api.cpp @@ -0,0 +1,132 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include +#include +#include // printf +#include + +extern "C" { + +#include "imbuf.h" +#include "imbuf_patch.h" +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" +#include "IMB_allocimbuf.h" + + +short imb_save_dds(struct ImBuf * ibuf, char *name, int flags) +{ + return(0); /* todo: finish this function */ + + /* check image buffer */ + if (ibuf == 0) return (0); + if (ibuf->rect == 0) return (0); + + /* open file for writing */ + std::ofstream fildes(name); + + /* write header */ + fildes << "DDS "; + fildes.close(); + + return(1); +} + +int imb_is_a_dds(unsigned char *mem) // note: use at most first 32 bytes +{ + /* heuristic check to see if mem contains a DDS file */ + /* header.fourcc == FOURCC_DDS */ + if ((mem[0] != 'D') || (mem[1] != 'D') || (mem[2] != 'S') || (mem[3] != ' ')) return(0); + /* header.size == 124 */ + if ((mem[4] != 124) || mem[5] || mem[6] || mem[7]) return(0); + return(1); +} + +struct ImBuf *imb_load_dds(unsigned char *mem, int size, int flags) +{ + struct ImBuf * ibuf = 0; + DirectDrawSurface dds(mem, size); /* reads header */ + unsigned char bits_per_pixel; + unsigned int *rect; + Image img; + unsigned int numpixels = 0; + int col; + unsigned char *cp = (unsigned char *) &col; + Color32 pixel; + Color32 *pixels = 0; + + /* check if DDS is valid and supported */ + if (!dds.isValid()) { + printf("DDS: not valid; header follows\n"); + dds.printInfo(); + return(0); + } + if (!dds.isSupported()) { + printf("DDS: format not supported\n"); + return(0); + } + if ((dds.width() > 65535) || (dds.height() > 65535)) { + printf("DDS: dimensions too large\n"); + return(0); + } + + /* convert DDS into ImBuf */ + if (dds.hasAlpha()) bits_per_pixel = 32; + else bits_per_pixel = 24; + ibuf = IMB_allocImBuf(dds.width(), dds.height(), bits_per_pixel, 0, 0); + if (ibuf == 0) return(0); /* memory allocation failed */ + + ibuf->ftype = DDS; + + if ((flags & IB_test) == 0) { + if (!imb_addrectImBuf(ibuf)) return(ibuf); + if (ibuf->rect == 0) return(ibuf); + + rect = ibuf->rect; + dds.mipmap(&img, 0, 0); /* load first face, first mipmap */ + pixels = img.pixels(); + numpixels = dds.width() * dds.height(); + cp[3] = 0xff; /* default alpha if alpha channel is not present */ + + for (unsigned int i = 0; i < numpixels; i++) { + pixel = pixels[i]; + cp[0] = pixel.r; /* set R component of col */ + cp[1] = pixel.g; /* set G component of col */ + cp[2] = pixel.b; /* set B component of col */ + if (bits_per_pixel == 32) + cp[3] = pixel.a; /* set A component of col */ + rect[i] = col; + } + IMB_flipy(ibuf); + } + + return(ibuf); +} + +} // extern "C" diff --git a/source/blender/imbuf/intern/dds/dds_api.h b/source/blender/imbuf/intern/dds/dds_api.h new file mode 100644 index 00000000000..8a0f966dd68 --- /dev/null +++ b/source/blender/imbuf/intern/dds/dds_api.h @@ -0,0 +1,43 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef _DDS_API_H +#define _DDS_API_H + +#ifdef __cplusplus +extern "C" { +#endif + +short imb_save_dds(struct ImBuf *ibuf, char *name, int flags); +int imb_is_a_dds(unsigned char *mem); /* use only first 32 bytes of mem */ +struct ImBuf *imb_load_dds(unsigned char *mem, int size, int flags); + +#ifdef __cplusplus +} +#endif + +#endif /* __DDS_API_H */ diff --git a/source/blender/imbuf/intern/dither.c b/source/blender/imbuf/intern/dither.c new file mode 100644 index 00000000000..608332af244 --- /dev/null +++ b/source/blender/imbuf/intern/dither.c @@ -0,0 +1,133 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * dither.c + * + * $Id$ + */ + +#include "BLI_blenlib.h" + +#include "imbuf.h" +#include "imbuf_patch.h" +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +void IMB_dit0(struct ImBuf * ibuf, short ofs, short bits) +{ + int x, y, and, add, pix; + uchar *rect; + + rect= (uchar *)ibuf->rect; + rect +=ofs; + + bits = 8 - bits; + and = ~((1 << bits)-1); + add = 1 << (bits - 1); + + for (y = ibuf->y; y > 0; y--){ + for (x = ibuf->x; x > 0; x--) { + pix = *rect + add; + if (pix > 255) pix = 255; + *rect = pix & and; + rect += 4; + } + } +} + +void IMB_dit2(struct ImBuf * ibuf, short ofs, short bits) +{ + short x,y,pix,and,add1,add2; + uchar *rect; + uchar dit[4]; + + rect= (uchar *)ibuf->rect; + rect +=ofs; + + bits = 8 - bits; + and = ~((1<>= -bits; + dit[1] >>= -bits; + dit[2] >>= -bits; + dit[3] >>= -bits; + } else{ + dit[0] <<= bits; + dit[1] <<= bits; + dit[2] <<= bits; + dit[3] <<= bits; + } + + for(y=ibuf->y;y>0;y--){ + if(y & 1){ + add1=dit[0]; + add2=dit[1]; + } + else{ + add1=dit[2]; + add2=dit[3]; + } + for(x=ibuf->x;x>0;x--){ + pix = *rect; + if (x & 1) pix += add1; + else pix += add2; + + if (pix>255) pix=255; + *rect = pix & and; + rect += 4; + } + } +} diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c new file mode 100644 index 00000000000..8db07f581f5 --- /dev/null +++ b/source/blender/imbuf/intern/divers.c @@ -0,0 +1,258 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * allocimbuf.c + * + * $Id$ + */ + +#include "BLI_blenlib.h" +#include "BLI_rand.h" + +#include "imbuf.h" +#include "imbuf_patch.h" +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" +#include "IMB_allocimbuf.h" +#include "IMB_divers.h" + +void imb_checkncols(struct ImBuf *ibuf) +{ + unsigned int i; + + if (ibuf==0) return; + + if (IS_amiga(ibuf)){ + if (IS_ham(ibuf)){ + if (ibuf->depth == 0) ibuf->depth = 6; + ibuf->mincol = 0; + ibuf->maxcol = 1 << (ibuf->depth - 2); + /*printf("%d %d\n", ibuf->maxcol, ibuf->depth);*/ + return; + } else if (IS_hbrite(ibuf)){ + ibuf->mincol = 0; + ibuf->maxcol = 64; + ibuf->depth = 6; + return; + } + } + + if (ibuf->maxcol == 0){ + if (ibuf->depth <= 8){ + ibuf->mincol = 0; + ibuf->maxcol = (1 << ibuf->depth); + return; + } else if (ibuf->depth == 0){ + ibuf->depth = 5; + ibuf->mincol = 0; + ibuf->maxcol = 32; + } + return; + } else { + /* ibuf->maxcol defines the depth */ + for (i=1 ; ibuf->maxcol > (1 << i); i++); + ibuf->depth = i; + return; + } +} + + +void IMB_de_interlace(struct ImBuf *ibuf) +{ + struct ImBuf * tbuf1, * tbuf2; + + if (ibuf == 0) return; + if (ibuf->flags & IB_fields) return; + ibuf->flags |= IB_fields; + + if (ibuf->rect) { + /* make copies */ + tbuf1 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect, 0); + tbuf2 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect, 0); + + ibuf->x *= 2; + IMB_rectcpy(tbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y); + IMB_rectcpy(tbuf2, ibuf, 0, 0, tbuf2->x, 0, ibuf->x, ibuf->y); + + ibuf->x /= 2; + IMB_rectcpy(ibuf, tbuf1, 0, 0, 0, 0, tbuf1->x, tbuf1->y); + IMB_rectcpy(ibuf, tbuf2, 0, tbuf2->y, 0, 0, tbuf2->x, tbuf2->y); + + IMB_freeImBuf(tbuf1); + IMB_freeImBuf(tbuf2); + } + ibuf->y /= 2; +} + +void IMB_interlace(struct ImBuf *ibuf) +{ + struct ImBuf * tbuf1, * tbuf2; + + if (ibuf == 0) return; + ibuf->flags &= ~IB_fields; + + ibuf->y *= 2; + + if (ibuf->rect) { + /* make copies */ + tbuf1 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect, 0); + tbuf2 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect, 0); + + IMB_rectcpy(tbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y); + IMB_rectcpy(tbuf2, ibuf, 0, 0, 0, tbuf2->y, ibuf->x, ibuf->y); + + ibuf->x *= 2; + IMB_rectcpy(ibuf, tbuf1, 0, 0, 0, 0, tbuf1->x, tbuf1->y); + IMB_rectcpy(ibuf, tbuf2, tbuf2->x, 0, 0, 0, tbuf2->x, tbuf2->y); + ibuf->x /= 2; + + IMB_freeImBuf(tbuf1); + IMB_freeImBuf(tbuf2); + } +} + + +void IMB_gamwarp(struct ImBuf *ibuf, double gamma) +{ + uchar gam[256]; + int i; + uchar *rect; + float *rectf; + + if (ibuf == 0) return; + if (gamma == 1.0) return; + + rect = (uchar *) ibuf->rect; + rectf = ibuf->rect_float; + + gamma = 1.0 / gamma; + + if (rect) { + for (i = 255 ; i >= 0 ; i--) + gam[i] = (255.0 * pow(i / 255.0 , + gamma)) + 0.5; + + for (i = ibuf->x * ibuf->y ; i>0 ; i--, rect+=4){ + rect[0] = gam[rect[0]]; + rect[1] = gam[rect[1]]; + rect[2] = gam[rect[2]]; + } + } + + if (rectf) { + for (i = ibuf->x * ibuf->y ; i>0 ; i--, rectf+=4){ + rectf[0] = pow(rectf[0] / 255.0, gamma); + rectf[1] = pow(rectf[1] / 255.0, gamma); + rectf[2] = pow(rectf[2] / 255.0, gamma); + } + } +} + +#define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.99f*val)) + +void IMB_rect_from_float(struct ImBuf *ibuf) +{ + /* quick method to convert floatbuf to byte */ + float *tof = ibuf->rect_float; + float dither= ibuf->dither; + int i, channels= ibuf->channels; + unsigned char *to = (unsigned char *) ibuf->rect; + + if(tof==NULL) return; + if(to==NULL) { + imb_addrectImBuf(ibuf); + to = (unsigned char *) ibuf->rect; + } + + if(dither==0.0f || channels!=4) { + if(channels==1) { + for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof++) + to[1]= to[2]= to[3]= to[0] = FTOCHAR(tof[0]); + } + else if(channels==3) { + for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=3) { + to[0] = FTOCHAR(tof[0]); + to[1] = FTOCHAR(tof[1]); + to[2] = FTOCHAR(tof[2]); + to[3] = 255; + } + } + else { + for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=4) { + to[0] = FTOCHAR(tof[0]); + to[1] = FTOCHAR(tof[1]); + to[2] = FTOCHAR(tof[2]); + to[3] = FTOCHAR(tof[3]); + } + } + } + else { + float dither_value, col; + dither= dither/255.0f; + for (i = ibuf->x * ibuf->y; i > 0; i--) { + dither_value = (BLI_frand()-0.5)*dither; + col= tof[0] + dither_value; + to[0] = FTOCHAR(col); + col= tof[1] + dither_value; + to[1] = FTOCHAR(col); + col= tof[2] + dither_value; + to[2] = FTOCHAR(col); + col= tof[3] + dither_value; + to[3] = FTOCHAR(col); + + to += 4; + tof += 4; + } + } +} + +void IMB_float_from_rect(struct ImBuf *ibuf) +{ + /* quick method to convert byte to floatbuf */ + float *tof = ibuf->rect_float; + int i; + unsigned char *to = (unsigned char *) ibuf->rect; + + if(to==NULL) return; + if(tof==NULL) { + imb_addrectfloatImBuf(ibuf); + tof = ibuf->rect_float; + } + + for (i = ibuf->x * ibuf->y; i > 0; i--) + { + tof[0] = ((float)to[0])*(1.0f/255.0f); + tof[1] = ((float)to[1])*(1.0f/255.0f); + tof[2] = ((float)to[2])*(1.0f/255.0f); + tof[3] = ((float)to[3])*(1.0f/255.0f); + to += 4; + tof += 4; + } +} + diff --git a/source/blender/imbuf/intern/dynlibtiff.c b/source/blender/imbuf/intern/dynlibtiff.c new file mode 100644 index 00000000000..cdcb995bcff --- /dev/null +++ b/source/blender/imbuf/intern/dynlibtiff.c @@ -0,0 +1,197 @@ +/** + * Dynamically loaded libtiff support. + * + * This file is automatically generated by the gen_dynlibtiff.py script. + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributor(s): Jonathan Merritt. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + * To use the dynamic libtiff support, you must initialize the library using: + * libtiff_init() + * This attempts to load libtiff dynamically at runtime. G.have_libtiff will + * be set to indicate whether or not libtiff is available. If libtiff is + * not available, Blender can proceed with no ill effects, provided that + * it does not attempt to use any of the libtiff_ functions. When you're + * finished, close the library with: + * libtiff_exit() + * These functions are both declared in IMB_imbuf.h + * + * The functions provided by dyn_libtiff.h are the same as those in the + * normal static / shared libtiff, except that they are prefixed by the + * string "libtiff_" to indicate that they belong to a dynamically-loaded + * version. + */ +#include "dynlibtiff.h" + +#include +#include +#include + +#include "BLI_blenlib.h" + +#include "imbuf.h" +#include "imbuf_patch.h" +#include "IMB_imbuf.h" + +#include "BKE_global.h" +#include "PIL_dynlib.h" + +/********************* + * LOCAL DEFINITIONS * + *********************/ +PILdynlib *libtiff = NULL; +void libtiff_loadlibtiff(void); +void* libtiff_findsymbol(char*); +int libtiff_load_symbols(void); + + +/************************** + * LIBRARY INITIALIZATION * + **************************/ + +void libtiff_loadlibtiff(void) +{ + char *filename; + libtiff = NULL; + + filename = getenv("BF_TIFF_LIB"); + if (filename) libtiff = PIL_dynlib_open(filename); + if (libtiff != NULL) return; + + /* Try to find libtiff in a couple of standard places */ + libtiff = PIL_dynlib_open("libtiff.so"); + if (libtiff != NULL) return; + libtiff = PIL_dynlib_open("libtiff.dll"); + if (libtiff != NULL) return; + libtiff = PIL_dynlib_open("/usr/lib/libtiff.so"); + if (libtiff != NULL) return; + /* OSX has version specific library */ + libtiff = PIL_dynlib_open("/usr/lib/libtiff.so.3"); + if (libtiff != NULL) return; + libtiff = PIL_dynlib_open("/usr/local/lib/libtiff.so"); + if (libtiff != NULL) return; + /* For solaris */ + libtiff = PIL_dynlib_open("/usr/openwin/lib/libtiff.so"); + +} + +void *libtiff_findsymbol(char *name) +{ + void *symbol = NULL; + assert(libtiff != NULL); + symbol = PIL_dynlib_find_symbol(libtiff, name); + if (symbol == NULL) { + printf("libtiff_findsymbol: error %s\n", + PIL_dynlib_get_error_as_string(libtiff)); + libtiff = NULL; + G.have_libtiff = (0); + return NULL; + } + return symbol; +} + +void libtiff_init(void) +{ + if (libtiff != NULL) { + printf("libtiff_init: Attempted to load libtiff twice!\n"); + return; + } + libtiff_loadlibtiff(); + G.have_libtiff = ((libtiff != NULL) && (libtiff_load_symbols())); +} + +void libtiff_exit(void) +{ + if (libtiff != NULL) { + PIL_dynlib_close(libtiff); + libtiff = NULL; + } +} + + +int libtiff_load_symbols(void) +{ + /* Attempt to load TIFFClientOpen */ + libtiff_TIFFClientOpen = libtiff_findsymbol("TIFFClientOpen"); + if (libtiff_TIFFClientOpen == NULL) { + return (0); + } + /* Attempt to load TIFFClose */ + libtiff_TIFFClose = libtiff_findsymbol("TIFFClose"); + if (libtiff_TIFFClose == NULL) { + return (0); + } + /* Attempt to load TIFFGetField */ + libtiff_TIFFGetField = libtiff_findsymbol("TIFFGetField"); + if (libtiff_TIFFGetField == NULL) { + return (0); + } + /* Attempt to load TIFFOpen */ + libtiff_TIFFOpen = libtiff_findsymbol("TIFFOpen"); + if (libtiff_TIFFOpen == NULL) { + return (0); + } + /* Attempt to load TIFFReadRGBAImage */ + libtiff_TIFFReadRGBAImage = libtiff_findsymbol("TIFFReadRGBAImage"); + if (libtiff_TIFFReadRGBAImage == NULL) { + return (0); + } + /* Attempt to load TIFFSetField */ + libtiff_TIFFSetField = libtiff_findsymbol("TIFFSetField"); + if (libtiff_TIFFSetField == NULL) { + return (0); + } + /* Attempt to load TIFFWriteEncodedStrip */ + libtiff_TIFFWriteEncodedStrip = libtiff_findsymbol("TIFFWriteEncodedStrip"); + if (libtiff_TIFFWriteEncodedStrip == NULL) { + return (0); + } + /* Attempt to load _TIFFfree */ + libtiff__TIFFfree = libtiff_findsymbol("_TIFFfree"); + if (libtiff__TIFFfree == NULL) { + return (0); + } + /* Attempt to load _TIFFmalloc */ + libtiff__TIFFmalloc = libtiff_findsymbol("_TIFFmalloc"); + if (libtiff__TIFFmalloc == NULL) { + return (0); + } + return (1); +} + + +/******************* + * SYMBOL POINTERS * + *******************/ + +TIFF* (*libtiff_TIFFClientOpen)(const char*, const char*, thandle_t, TIFFReadWriteProc, TIFFReadWriteProc, TIFFSeekProc, TIFFCloseProc, TIFFSizeProc, TIFFMapFileProc, TIFFUnmapFileProc) = NULL; +void (*libtiff_TIFFClose)(TIFF*) = NULL; +int (*libtiff_TIFFGetField)(TIFF*, ttag_t, ...) = NULL; +TIFF* (*libtiff_TIFFOpen)(const char*, const char*) = NULL; +int (*libtiff_TIFFReadRGBAImage)(TIFF*, uint32, uint32, uint32*, int) = NULL; +int (*libtiff_TIFFSetField)(TIFF*, ttag_t, ...) = NULL; +tsize_t (*libtiff_TIFFWriteEncodedStrip)(TIFF*, tstrip_t, tdata_t, tsize_t) = NULL; +void (*libtiff__TIFFfree)(tdata_t) = NULL; +tdata_t (*libtiff__TIFFmalloc)(tsize_t) = NULL; diff --git a/source/blender/imbuf/intern/dynlibtiff.h b/source/blender/imbuf/intern/dynlibtiff.h new file mode 100644 index 00000000000..8d61ee3ca87 --- /dev/null +++ b/source/blender/imbuf/intern/dynlibtiff.h @@ -0,0 +1,58 @@ +/** + * Dynamically loaded libtiff support. + * + * This file is automatically generated by the gen_dynlibtiff.py script. + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributor(s): Jonathan Merritt. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + * To use the dynamic libtiff support, you must initialize the library using: + * libtiff_init() + * This attempts to load libtiff dynamically at runtime. G.have_libtiff will + * be set to indicate whether or not libtiff is available. If libtiff is + * not available, Blender can proceed with no ill effects, provided that + * it does not attempt to use any of the libtiff_ functions. When you're + * finished, close the library with: + * libtiff_exit() + * These functions are both declared in IMB_imbuf.h + * + * The functions provided by dyn_libtiff.h are the same as those in the + * normal static / shared libtiff, except that they are prefixed by the + * string "libtiff_" to indicate that they belong to a dynamically-loaded + * version. + */ +#ifndef DYN_LIBTIFF_H +#include "tiffio.h" +extern TIFF* (*libtiff_TIFFClientOpen)(const char*, const char*, thandle_t, TIFFReadWriteProc, TIFFReadWriteProc, TIFFSeekProc, TIFFCloseProc, TIFFSizeProc, TIFFMapFileProc, TIFFUnmapFileProc); +extern void (*libtiff_TIFFClose)(TIFF*); +extern int (*libtiff_TIFFGetField)(TIFF*, ttag_t, ...); +extern TIFF* (*libtiff_TIFFOpen)(const char*, const char*); +extern int (*libtiff_TIFFReadRGBAImage)(TIFF*, uint32, uint32, uint32*, int); +extern int (*libtiff_TIFFSetField)(TIFF*, ttag_t, ...); +extern tsize_t (*libtiff_TIFFWriteEncodedStrip)(TIFF*, tstrip_t, tdata_t, tsize_t); +extern void (*libtiff__TIFFfree)(tdata_t); +extern tdata_t (*libtiff__TIFFmalloc)(tsize_t); +#endif /* DYN_LIBTIFF_H */ + diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c new file mode 100644 index 00000000000..fd9dac1af2b --- /dev/null +++ b/source/blender/imbuf/intern/filter.c @@ -0,0 +1,329 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * filter.c + * + * $Id$ + */ + +#include "BLI_blenlib.h" + +#include "imbuf.h" +#include "imbuf_patch.h" +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" +#include "IMB_filter.h" + + +/************************************************************************/ +/* FILTERS */ +/************************************************************************/ + +static void filtrow(unsigned char *point, int x) +{ + unsigned int c1,c2,c3,error; + + if (x>1){ + c1 = c2 = *point; + error = 2; + for(x--;x>0;x--){ + c3 = point[4]; + c1 += (c2<<1) + c3 + error; + error = c1 & 3; + *point = c1 >> 2; + point += 4; + c1=c2; + c2=c3; + } + *point = (c1 + (c2<<1) + c2 + error) >> 2; + } +} + +static void filtrowf(float *point, int x) +{ + float c1,c2,c3; + + if (x>1){ + c1 = c2 = *point; + for(x--;x>0;x--){ + c3 = point[4]; + c1 += (c2 * 2) + c3; + *point = 0.25f*c1; + point += 4; + c1=c2; + c2=c3; + } + *point = 0.25f*(c1 + (c2 * 2) + c2); + } +} + + + +static void filtcolum(unsigned char *point, int y, int skip) +{ + unsigned int c1,c2,c3,error; + unsigned char *point2; + + if (y>1){ + c1 = c2 = *point; + point2 = point; + error = 2; + for(y--;y>0;y--){ + point2 += skip; + c3 = *point2; + c1 += (c2<<1) + c3 +error; + error = c1 & 3; + *point = c1 >> 2; + point=point2; + c1=c2; + c2=c3; + } + *point = (c1 + (c2<<1) + c2 + error) >> 2; + } +} + +static void filtcolumf(float *point, int y, int skip) +{ + float c1,c2,c3, *point2; + + if (y>1){ + c1 = c2 = *point; + point2 = point; + for(y--;y>0;y--){ + point2 += skip; + c3 = *point2; + c1 += (c2 * 2) + c3; + *point = 0.25f*c1; + point=point2; + c1=c2; + c2=c3; + } + *point = 0.25f*(c1 + (c2 * 2) + c2); + } +} + +void IMB_filtery(struct ImBuf *ibuf) +{ + unsigned char *point; + float *pointf; + int x, y, skip; + + point = (unsigned char *)ibuf->rect; + pointf = ibuf->rect_float; + + x = ibuf->x; + y = ibuf->y; + skip = x<<2; + + for (;x>0;x--){ + if (point) { + if (ibuf->depth > 24) filtcolum(point,y,skip); + point++; + filtcolum(point,y,skip); + point++; + filtcolum(point,y,skip); + point++; + filtcolum(point,y,skip); + point++; + } + if (pointf) { + if (ibuf->depth > 24) filtcolumf(pointf,y,skip); + pointf++; + filtcolumf(pointf,y,skip); + pointf++; + filtcolumf(pointf,y,skip); + pointf++; + filtcolumf(pointf,y,skip); + pointf++; + } + } +} + + +void imb_filterx(struct ImBuf *ibuf) +{ + unsigned char *point; + float *pointf; + int x, y, skip; + + point = (unsigned char *)ibuf->rect; + pointf = ibuf->rect_float; + + x = ibuf->x; + y = ibuf->y; + skip = (x<<2) - 3; + + for (;y>0;y--){ + if (point) { + if (ibuf->depth > 24) filtrow(point,x); + point++; + filtrow(point,x); + point++; + filtrow(point,x); + point++; + filtrow(point,x); + point+=skip; + } + if (pointf) { + if (ibuf->depth > 24) filtrowf(pointf,x); + pointf++; + filtrowf(pointf,x); + pointf++; + filtrowf(pointf,x); + pointf++; + filtrowf(pointf,x); + pointf+=skip; + } + } +} + +void IMB_filterN(ImBuf *out, ImBuf *in) +{ + register char *row1, *row2, *row3; + register char *cp; + int rowlen, x, y; + + rowlen= in->x; + + for(y=2; yy; y++) { + /* setup rows */ + row1= (char *)(in->rect + (y-2)*rowlen); + row2= row1 + 4*rowlen; + row3= row2 + 4*rowlen; + + cp= (char *)(out->rect + (y-1)*rowlen); + cp[0]= row2[0]; + cp[1]= row2[1]; + cp[2]= row2[2]; + cp[3]= row2[3]; + cp+= 4; + + for(x=2; x>4; + cp[1]= (row1[1] + 2*row1[5] + row1[9] + 2*row2[1] + 4*row2[5] + 2*row2[9] + row3[1] + 2*row3[5] + row3[9])>>4; + cp[2]= (row1[2] + 2*row1[6] + row1[10] + 2*row2[2] + 4*row2[6] + 2*row2[10] + row3[2] + 2*row3[6] + row3[10])>>4; + cp[3]= (row1[3] + 2*row1[7] + row1[11] + 2*row2[3] + 4*row2[7] + 2*row2[11] + row3[3] + 2*row3[7] + row3[11])>>4; + cp+=4; row1+=4; row2+=4; row3+=4; + } + } +} + +void IMB_filter(struct ImBuf *ibuf) +{ + IMB_filtery(ibuf); + imb_filterx(ibuf); +} + +#define EXTEND_PIXEL(a, w) if((a)[3]) {r+= w*(a)[0]; g+= w*(a)[1]; b+= w*(a)[2]; tot+=w;} + +/* if alpha is zero, it checks surrounding pixels and averages color. sets new alphas to 255 */ +void IMB_filter_extend(struct ImBuf *ibuf) +{ + register char *row1, *row2, *row3; + register char *cp; + int rowlen, x, y; + + rowlen= ibuf->x; + + if(ibuf->rect) { + int *temprect; + + /* make a copy, to prevent flooding */ + temprect= MEM_dupallocN(ibuf->rect); + + for(y=1; y<=ibuf->y; y++) { + /* setup rows */ + row1= (char *)(temprect + (y-2)*rowlen); + row2= row1 + 4*rowlen; + row3= row2 + 4*rowlen; + if(y==1) + row1= row2; + else if(y==ibuf->y) + row3= row2; + + cp= (char *)(ibuf->rect + (y-1)*rowlen); + + for(x=0; xxy?ibuf->x:ibuf->y; + + while(minsize>10 && curmapx, hbuf->y, 32, IB_rect, 0); + IMB_filterN(nbuf, hbuf); + ibuf->mipmap[curmap]= IMB_onehalf(nbuf); + IMB_freeImBuf(nbuf); + } + else { + ibuf->mipmap[curmap]= IMB_onehalf(hbuf); + } + hbuf= ibuf->mipmap[curmap]; + + curmap++; + minsize= hbuf->xy?hbuf->x:hbuf->y; + } +} + + diff --git a/source/blender/imbuf/intern/gen_dynlibtiff.py b/source/blender/imbuf/intern/gen_dynlibtiff.py new file mode 100755 index 00000000000..1ee0275854a --- /dev/null +++ b/source/blender/imbuf/intern/gen_dynlibtiff.py @@ -0,0 +1,254 @@ +#!/usr/bin/env python + +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# Contributor(s): Jonathan Merritt. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +# +# This script generates a C source file and a header file that implement +# dynamic loading functionality for libtiff. +# If you need to make more functions from libtiff available, then simply add +# them to the tiff_functions[] list below. +# + + +FILENAME = 'dynlibtiff' +C_FILENAME = '%s.c' % FILENAME +H_FILENAME = '%s.h' % FILENAME + + +COMMENT = \ +"""/** + * Dynamically loaded libtiff support. + * + * This file is automatically generated by the gen_dynlibtiff.py script. + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributor(s): Jonathan Merritt. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + * To use the dynamic libtiff support, you must initialize the library using: + * libtiff_init() + * This attempts to load libtiff dynamically at runtime. G.have_libtiff will + * be set to indicate whether or not libtiff is available. If libtiff is + * not available, Blender can proceed with no ill effects, provided that + * it does not attempt to use any of the libtiff_ functions. When you're + * finished, close the library with: + * libtiff_exit() + * These functions are both declared in IMB_imbuf.h + * + * The functions provided by dyn_libtiff.h are the same as those in the + * normal static / shared libtiff, except that they are prefixed by the + * string "libtiff_" to indicate that they belong to a dynamically-loaded + * version. + */ +""" + + +C_EXTRA = \ +""" +#include +#include +#include + +#include "BLI_blenlib.h" + +#include "imbuf.h" +#include "imbuf_patch.h" +#include "IMB_imbuf.h" + +#include "BKE_global.h" +#include "PIL_dynlib.h" + +/********************* + * LOCAL DEFINITIONS * + *********************/ +PILdynlib *libtiff = NULL; +void libtiff_loadlibtiff(void); +void* libtiff_findsymbol(char*); +int libtiff_load_symbols(void); + + +/************************** + * LIBRARY INITIALIZATION * + **************************/ + +void libtiff_loadlibtiff(void) +{ + char *filename; + libtiff = NULL; + + filename = getenv("BF_TIFF_LIB"); + if (filename) libtiff = PIL_dynlib_open(filename); + if (libtiff != NULL) return; + + /* Try to find libtiff in a couple of standard places */ + libtiff = PIL_dynlib_open("libtiff.so"); + if (libtiff != NULL) return; + libtiff = PIL_dynlib_open("libtiff.dll"); + if (libtiff != NULL) return; + libtiff = PIL_dynlib_open("/usr/lib/libtiff.so"); + if (libtiff != NULL) return; + /* OSX has version specific library */ + libtiff = PIL_dynlib_open("/usr/lib/libtiff.so.3"); + if (libtiff != NULL) return; + libtiff = PIL_dynlib_open("/usr/local/lib/libtiff.so"); + if (libtiff != NULL) return; + /* For solaris */ + libtiff = PIL_dynlib_open("/usr/openwin/lib/libtiff.so"); + +} + +void *libtiff_findsymbol(char *name) +{ + void *symbol = NULL; + assert(libtiff != NULL); + symbol = PIL_dynlib_find_symbol(libtiff, name); + if (symbol == NULL) { + printf("libtiff_findsymbol: error %s\\n", + PIL_dynlib_get_error_as_string(libtiff)); + libtiff = NULL; + G.have_libtiff = (0); + return NULL; + } + return symbol; +} + +void libtiff_init(void) +{ + if (libtiff != NULL) { + printf("libtiff_init: Attempted to load libtiff twice!\\n"); + return; + } + libtiff_loadlibtiff(); + G.have_libtiff = ((libtiff != NULL) && (libtiff_load_symbols())); +} + +void libtiff_exit(void) +{ + if (libtiff != NULL) { + PIL_dynlib_close(libtiff); + libtiff = NULL; + } +} + + +""" + + +class CFun: + def __init__(self, name, retType, args): + self.name = name + self.retType = retType + self.args = args + def getDynamicName(self): + return ('libtiff_%s' % self.name) + def getDynamicDecl(self): + argstr = (('%s, '*len(self.args)) % tuple(self.args))[:-2] + return ('%s (*%s)(%s)' % (self.retType, + self.getDynamicName(), argstr)) + def getLoadSymbol(self): + dname = self.getDynamicName() + return ( + """\t/* Attempt to load %s */ + %s = libtiff_findsymbol("%s"); + if (%s == NULL) { + return (0); + }\n""" % (self.name, dname, self.name, dname)) + + +# If you need more functions, add them to the list below, based upon entries +# in either tiffio.h or tiff.h. +tiff_functions = [ + CFun('TIFFClientOpen', 'TIFF*', ['const char*', 'const char*', + 'thandle_t', 'TIFFReadWriteProc', 'TIFFReadWriteProc', + 'TIFFSeekProc', 'TIFFCloseProc', 'TIFFSizeProc', + 'TIFFMapFileProc', 'TIFFUnmapFileProc']), + CFun('TIFFClose', 'void', ['TIFF*']), + CFun('TIFFGetField', 'int', ['TIFF*', 'ttag_t', '...']), + CFun('TIFFOpen', 'TIFF*', ['const char*', 'const char*']), + CFun('TIFFReadRGBAImage', 'int', ['TIFF*', 'uint32', 'uint32', + 'uint32*', 'int']), + CFun('TIFFSetField', 'int', ['TIFF*', 'ttag_t', '...']), + CFun('TIFFWriteEncodedStrip', 'tsize_t', ['TIFF*', 'tstrip_t', + 'tdata_t', 'tsize_t']), + CFun('_TIFFfree', 'void', ['tdata_t']), + CFun('_TIFFmalloc', 'tdata_t', ['tsize_t']), +] + + +def outputDynCFile(outfile, header_file_name): + outfile.write(COMMENT) + outfile.write('#include "%s"\n' % header_file_name) + outfile.write(C_EXTRA) + outfile.write('int libtiff_load_symbols(void)\n') + outfile.write('{\n') + for function in tiff_functions: + outfile.write(function.getLoadSymbol()) + outfile.write('\treturn (1);\n') + outfile.write('}\n') + outfile.write(""" + +/******************* + * SYMBOL POINTERS * + *******************/\n\n""") + for function in tiff_functions: + outfile.write('%s = NULL;\n' % function.getDynamicDecl()) + + +def outputDynHFile(outfile): + outfile.write(COMMENT) + outfile.write('#ifndef DYN_LIBTIFF_H\n') + outfile.write('#include "tiffio.h"\n') + for function in tiff_functions: + outfile.write('extern %s;\n' % function.getDynamicDecl()) + outfile.write('#endif /* DYN_LIBTIFF_H */\n\n') + + +if __name__ == '__main__': + outfile = file(C_FILENAME, 'w') + outputDynCFile(outfile, H_FILENAME) + outfile.close() + outfile = file(H_FILENAME, 'w') + outputDynHFile(outfile) + outfile.close() diff --git a/source/blender/imbuf/intern/ham.c b/source/blender/imbuf/intern/ham.c new file mode 100644 index 00000000000..de1d504980e --- /dev/null +++ b/source/blender/imbuf/intern/ham.c @@ -0,0 +1,279 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ham.c + * + * $Id$ + */ + +#include "BLI_blenlib.h" + +#include "imbuf.h" +#include "imbuf_patch.h" +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" +#include "IMB_cmap.h" +#include "IMB_hamx.h" +#include "IMB_ham.h" + +extern short alpha_col0; + +#define HAMB 0x0100 +#define HAMG 0x0400 +#define HAMR 0x0200 +#define HAMC 0x1000 +#define HAMFREE 0x2000 + +static void addhamdither(short x, unsigned char *dit, + short dmax, unsigned char *rgb, + unsigned short *ham, + short type, short round, short shift) +{ + short dx = 0; + short c1, c2; + + for (;x>0;x--){ + if (ham[0] & (HAMFREE | type)){ + c2 = c1 = *rgb; + + /* wrap dither */ + while (dx >= dmax) dx -= dmax; + + c1 += dit[dx]; + if (c1 > 255) c1 = 255; + c2 += round; + if (c2 > 255) c2 = 255; + + if (c1 != c2){ + c1 >>= shift; c2 >>= shift; + if (ham[1] & HAMFREE){ + ham[0] = type + c1; + ham[1] = type + c2; + } else if (ham[1] & type){ + ham[0] = type + c1; + } else if ((ham[2] & (type | HAMFREE)) == type){ + ham[0] = type + c1; + } else if ((ham[1] & HAMC) | (ham[2] & HAMC)){ + ham[0] = type + c1; + } + } + } + rgb += 4; + ham ++; + dx ++; + } +} + +static void convhamscanl(short x, short y, + unsigned char *rgbbase, + unsigned char *coltab, + short *deltab, + short bits) +{ + int a, r, g, b, lr, lg, lb, dr, dg, db, col, fout, type, x2; + int round, shift; + uchar *rgb, dit[2]; + unsigned short *ham, *hambase; + + /* Concept: + first we check the entire image, where color transitions are coded: FGRB XXXX XXXX + F - free color value, can be changed by anyone + G/R/B - green/red/blue ham transition, only to be changed by this color + XXXX XXXX - N bits value. + + 0000 XXXX XXXX is palette color. + + after that first the green dither is added, then the red dither, and finally blue dither + */ + + if ((hambase = (unsigned short *) malloc((x+4) * sizeof(unsigned short)))==0) return; + + lb = coltab[1]; + lg = coltab[2]; + lr = coltab[3]; + type = col = 0; + + ham = hambase; + rgb = rgbbase; + + shift = 8 - bits; + round = 1 << (shift - 1); + + /* to prevent 'noise' at the end of the line */ + for (x2 = 3; x2 >= 0; x2 --) hambase[x + x2] = HAMFREE; + + for (x2 = x ;x2 > 0; x2--){ + r = rgb[0] + round; + g = rgb[1] + round; + b = rgb[2] + round; + a = rgb[3]; + + if (a < 128 && alpha_col0) { + a = 1; + } else a = 0; + + if (b > 255) b = 255; + if (g > 255) { + g = 255; + } + if (r > 255) r = 255; + + r >>= shift; + g >>= shift; + b >>= shift; + + if ((b-lb) | (g-lg) | (r-lr) | a){ + if (a) { + col = 0; + type = HAMC; + } else { + col = ((b << (2 * bits)) + (g << bits) + r) << 1; + fout = deltab[col + 1]; + col = deltab[col]; + type = HAMC; + + dr = quadr[lr-r]; + dg = quadr[lg-g]; + db = quadr[lb-b]; + + if ((dr+dg) <= fout){ + fout = dr+dg; + col = b; + type = HAMB; + } + if ((dg+db) <= fout){ + fout = dg+db; + col = r; + type = HAMR; + } + if ((dr+db) <= fout){ + fout = dr+db; + col = g; + type = HAMG; + } + } + + switch(type){ + case HAMG: + lg = g; + break; + case HAMR: + lr = r; + break; + case HAMB: + lb = b; + break; + default: + lb = coltab[col*4 + 1]; + lg = coltab[col*4 + 2]; + lr = coltab[col*4 + 3]; + } + *ham = type + col; + } else *ham = HAMG + HAMFREE + g; + + rgb += 4; + ham ++; + } + + + if (y & 1){ + dit[0] = 0 << (shift - 2); + dit[1] = 3 << (shift - 2); + } else { + dit[0] = 2 << (shift - 2); + dit[1] = 1 << (shift - 2); + } + + addhamdither(x,dit,2,rgbbase+2,hambase,HAMG, round, shift); + + if ((y & 1)==0){ + dit[0] = 3 << (shift - 2); + dit[1] = 0 << (shift - 2); + } else { + dit[0] = 1 << (shift - 2); + dit[1] = 2 << (shift - 2); + } + + addhamdither(x,dit,2,rgbbase+3,hambase,HAMR, round, shift); + addhamdither(x,dit,2,rgbbase+1,hambase,HAMB, round, shift); + + + ham = hambase; + rgb = rgbbase; + rgb += 3; + + for (x2=x;x2>0;x2--){ + type = *(ham++); + if (type & HAMG) type |= HAMR | HAMB; + + *rgb = (type & 0xff) | ((type & (HAMR | HAMB)) >> shift); + rgb += 4; + } + + free (hambase); +} + + +short imb_converttoham(struct ImBuf *ibuf) +{ + unsigned int coltab[256],*rect; + short x,y,* deltab; + int mincol; + + memcpy(coltab,ibuf->cmap,4 * ibuf->maxcol); + + mincol = ibuf->mincol; + if (alpha_col0 && mincol == 0) mincol = 1; + + if (ibuf->ftype == AN_hamx) { + deltab = imb_coldeltatab((uchar *) coltab, 0, ibuf->maxcol, 4); + } else { + ibuf->cbits = ibuf->depth - 2; + imb_losecmapbits(ibuf, coltab); + deltab = imb_coldeltatab((uchar *) coltab, mincol, ibuf->maxcol, ibuf->cbits); + } + + rect = ibuf->rect; + x=ibuf->x; + y=ibuf->y; + + if (ibuf->ftype == AN_hamx){ + IMB_dit2(ibuf, 2, 4); + IMB_dit2(ibuf, 1, 4); + IMB_dit2(ibuf, 0, 4); + imb_convhamx(ibuf, (uchar *)coltab, deltab); + } else { + for(;y > 0; y--){ + convhamscanl(x, y, (uchar *)rect, (uchar *)coltab, deltab, ibuf->cbits); + rect += x; + } + } + + return (TRUE); +} diff --git a/source/blender/imbuf/intern/hamx.c b/source/blender/imbuf/intern/hamx.c new file mode 100644 index 00000000000..8a5cbda72ec --- /dev/null +++ b/source/blender/imbuf/intern/hamx.c @@ -0,0 +1,583 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * hamx.c + * + * $Id$ + */ + +#include "BLI_blenlib.h" + +#ifdef WIN32 +#include +#endif + + +#include "imbuf.h" +#include "imbuf_patch.h" +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "IMB_allocimbuf.h" +#include "IMB_filter.h" +#include "IMB_ham.h" +#include "IMB_hamx.h" + +/* actually hard coded endianness */ +#define GET_BIG_LONG(x) (((uchar *) (x))[0] << 24 | ((uchar *) (x))[1] << 16 | ((uchar *) (x))[2] << 8 | ((uchar *) (x))[3]) +#define GET_LITTLE_LONG(x) (((uchar *) (x))[3] << 24 | ((uchar *) (x))[2] << 16 | ((uchar *) (x))[1] << 8 | ((uchar *) (x))[0]) +#define SWAP_L(x) (((x << 24) & 0xff000000) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | ((x >> 24) & 0xff)) +#define SWAP_S(x) (((x << 8) & 0xff00) | ((x >> 8) & 0xff)) + +/* more endianness... should move to a separate file... */ +#if defined(__sgi) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__) +#define GET_ID GET_BIG_LONG +#define LITTLE_LONG SWAP_LONG +#else +#define GET_ID GET_LITTLE_LONG +#define LITTLE_LONG ENDIAN_NOP +#endif + +#ifndef ABS +#define ABS(x) ((x) < 0 ? -(x) : (x)) +#endif + +static uchar hamx_array_char[] = { + 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, + 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, + 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, + 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, + 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, + 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, + + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + + 0x00,0x00,0x00,0x00, 0x00,0x10,0x00,0x00, 0x00,0x20,0x00,0x00, 0x00,0x30,0x00,0x00, 0x00,0x40,0x00,0x00, 0x00,0x50,0x00,0x00, 0x00,0x60,0x00,0x00, 0x00,0x70,0x00,0x00, + 0x00,0x80,0x00,0x00, 0x00,0x90,0x00,0x00, 0x00,0xA0,0x00,0x00, 0x00,0xB0,0x00,0x00, 0x00,0xC0,0x00,0x00, 0x00,0xD0,0x00,0x00, 0x00,0xE0,0x00,0x00, 0x00,0xF0,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x10,0x00, 0x00,0x00,0x20,0x00, 0x00,0x00,0x30,0x00, 0x00,0x00,0x40,0x00, 0x00,0x00,0x50,0x00, 0x00,0x00,0x60,0x00, 0x00,0x00,0x70,0x00, + 0x00,0x00,0x80,0x00, 0x00,0x00,0x90,0x00, 0x00,0x00,0xA0,0x00, 0x00,0x00,0xB0,0x00, 0x00,0x00,0xC0,0x00, 0x00,0x00,0xD0,0x00, 0x00,0x00,0xE0,0x00, 0x00,0x00,0xF0,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x10, 0x00,0x00,0x00,0x20, 0x00,0x00,0x00,0x30, 0x00,0x00,0x00,0x40, 0x00,0x00,0x00,0x50, 0x00,0x00,0x00,0x60, 0x00,0x00,0x00,0x70, + 0x00,0x00,0x00,0x80, 0x00,0x00,0x00,0x90, 0x00,0x00,0x00,0xA0, 0x00,0x00,0x00,0xB0, 0x00,0x00,0x00,0xC0, 0x00,0x00,0x00,0xD0, 0x00,0x00,0x00,0xE0, 0x00,0x00,0x00,0xF0, + + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x30, 0x00,0x00,0x00,0x60, 0x00,0x00,0x00,0x90, 0x00,0x00,0x00,0xC0, 0x00,0x00,0x00,0xF0, + 0x00,0x00,0x20,0x00, 0x00,0x00,0x20,0x30, 0x00,0x00,0x20,0x60, 0x00,0x00,0x20,0x90, 0x00,0x00,0x20,0xC0, 0x00,0x00,0x20,0xF0, + 0x00,0x00,0x40,0x00, 0x00,0x00,0x40,0x30, 0x00,0x00,0x40,0x60, 0x00,0x00,0x40,0x90, 0x00,0x00,0x40,0xC0, 0x00,0x00,0x40,0xF0, + 0x00,0x00,0x60,0x00, 0x00,0x00,0x60,0x30, 0x00,0x00,0x60,0x60, 0x00,0x00,0x60,0x90, 0x00,0x00,0x60,0xC0, 0x00,0x00,0x60,0xF0, + 0x00,0x00,0x90,0x00, 0x00,0x00,0x90,0x30, 0x00,0x00,0x90,0x60, 0x00,0x00,0x90,0x90, 0x00,0x00,0x90,0xC0, 0x00,0x00,0x90,0xF0, + 0x00,0x00,0xB0,0x00, 0x00,0x00,0xB0,0x30, 0x00,0x00,0xB0,0x60, 0x00,0x00,0xB0,0x90, 0x00,0x00,0xB0,0xC0, 0x00,0x00,0xB0,0xF0, + 0x00,0x00,0xD0,0x00, 0x00,0x00,0xD0,0x30, 0x00,0x00,0xD0,0x60, 0x00,0x00,0xD0,0x90, 0x00,0x00,0xD0,0xC0, 0x00,0x00,0xD0,0xF0, + 0x00,0x00,0xF0,0x00, 0x00,0x00,0xF0,0x30, 0x00,0x00,0xF0,0x60, 0x00,0x00,0xF0,0x90, 0x00,0x00,0xF0,0xC0, 0x00,0x00,0xF0,0xF0, + 0x00,0x50,0x00,0x00, 0x00,0x50,0x00,0x30, 0x00,0x50,0x00,0x60, 0x00,0x50,0x00,0x90, 0x00,0x50,0x00,0xC0, 0x00,0x50,0x00,0xF0, + 0x00,0x50,0x20,0x00, 0x00,0x50,0x20,0x30, 0x00,0x50,0x20,0x60, 0x00,0x50,0x20,0x90, 0x00,0x50,0x20,0xC0, 0x00,0x50,0x20,0xF0, + 0x00,0x50,0x40,0x00, 0x00,0x50,0x40,0x30, 0x00,0x50,0x40,0x60, 0x00,0x50,0x40,0x90, 0x00,0x50,0x40,0xC0, 0x00,0x50,0x40,0xF0, + 0x00,0x50,0x60,0x00, 0x00,0x50,0x60,0x30, 0x00,0x50,0x60,0x60, 0x00,0x50,0x60,0x90, 0x00,0x50,0x60,0xC0, 0x00,0x50,0x60,0xF0, + 0x00,0x50,0x90,0x00, 0x00,0x50,0x90,0x30, 0x00,0x50,0x90,0x60, 0x00,0x50,0x90,0x90, 0x00,0x50,0x90,0xC0, 0x00,0x50,0x90,0xF0, + 0x00,0x50,0xB0,0x00, 0x00,0x50,0xB0,0x30, 0x00,0x50,0xB0,0x60, 0x00,0x50,0xB0,0x90, 0x00,0x50,0xB0,0xC0, 0x00,0x50,0xB0,0xF0, + 0x00,0x50,0xD0,0x00, 0x00,0x50,0xD0,0x30, 0x00,0x50,0xD0,0x60, 0x00,0x50,0xD0,0x90, 0x00,0x50,0xD0,0xC0, 0x00,0x50,0xD0,0xF0, + 0x00,0x50,0xF0,0x00, 0x00,0x50,0xF0,0x30, 0x00,0x50,0xF0,0x60, 0x00,0x50,0xF0,0x90, 0x00,0x50,0xF0,0xC0, 0x00,0x50,0xF0,0xF0, + 0x00,0xA0,0x00,0x00, 0x00,0xA0,0x00,0x30, 0x00,0xA0,0x00,0x60, 0x00,0xA0,0x00,0x90, 0x00,0xA0,0x00,0xC0, 0x00,0xA0,0x00,0xF0, + 0x00,0xA0,0x20,0x00, 0x00,0xA0,0x20,0x30, 0x00,0xA0,0x20,0x60, 0x00,0xA0,0x20,0x90, 0x00,0xA0,0x20,0xC0, 0x00,0xA0,0x20,0xF0, + 0x00,0xA0,0x40,0x00, 0x00,0xA0,0x40,0x30, 0x00,0xA0,0x40,0x60, 0x00,0xA0,0x40,0x90, 0x00,0xA0,0x40,0xC0, 0x00,0xA0,0x40,0xF0, + 0x00,0xA0,0x60,0x00, 0x00,0xA0,0x60,0x30, 0x00,0xA0,0x60,0x60, 0x00,0xA0,0x60,0x90, 0x00,0xA0,0x60,0xC0, 0x00,0xA0,0x60,0xF0, + 0x00,0xA0,0x90,0x00, 0x00,0xA0,0x90,0x30, 0x00,0xA0,0x90,0x60, 0x00,0xA0,0x90,0x90, 0x00,0xA0,0x90,0xC0, 0x00,0xA0,0x90,0xF0, + 0x00,0xA0,0xB0,0x00, 0x00,0xA0,0xB0,0x30, 0x00,0xA0,0xB0,0x60, 0x00,0xA0,0xB0,0x90, 0x00,0xA0,0xB0,0xC0, 0x00,0xA0,0xB0,0xF0, + 0x00,0xA0,0xD0,0x00, 0x00,0xA0,0xD0,0x30, 0x00,0xA0,0xD0,0x60, 0x00,0xA0,0xD0,0x90, 0x00,0xA0,0xD0,0xC0, 0x00,0xA0,0xD0,0xF0, + 0x00,0xA0,0xF0,0x00, 0x00,0xA0,0xF0,0x30, 0x00,0xA0,0xF0,0x60, 0x00,0xA0,0xF0,0x90, 0x00,0xA0,0xF0,0xC0, 0x00,0xA0,0xF0,0xF0, + 0x00,0xF0,0x00,0x00, 0x00,0xF0,0x00,0x30, 0x00,0xF0,0x00,0x60, 0x00,0xF0,0x00,0x90, 0x00,0xF0,0x00,0xC0, 0x00,0xF0,0x00,0xF0, + 0x00,0xF0,0x20,0x00, 0x00,0xF0,0x20,0x30, 0x00,0xF0,0x20,0x60, 0x00,0xF0,0x20,0x90, 0x00,0xF0,0x20,0xC0, 0x00,0xF0,0x20,0xF0, + 0x00,0xF0,0x40,0x00, 0x00,0xF0,0x40,0x30, 0x00,0xF0,0x40,0x60, 0x00,0xF0,0x40,0x90, 0x00,0xF0,0x40,0xC0, 0x00,0xF0,0x40,0xF0, + 0x00,0xF0,0x60,0x00, 0x00,0xF0,0x60,0x30, 0x00,0xF0,0x60,0x60, 0x00,0xF0,0x60,0x90, 0x00,0xF0,0x60,0xC0, 0x00,0xF0,0x60,0xF0, + 0x00,0xF0,0x90,0x00, 0x00,0xF0,0x90,0x30, 0x00,0xF0,0x90,0x60, 0x00,0xF0,0x90,0x90, 0x00,0xF0,0x90,0xC0, 0x00,0xF0,0x90,0xF0, + 0x00,0xF0,0xB0,0x00, 0x00,0xF0,0xB0,0x30, 0x00,0xF0,0xB0,0x60, 0x00,0xF0,0xB0,0x90, 0x00,0xF0,0xB0,0xC0, 0x00,0xF0,0xB0,0xF0, + 0x00,0xF0,0xD0,0x00, 0x00,0xF0,0xD0,0x30, 0x00,0xF0,0xD0,0x60, 0x00,0xF0,0xD0,0x90, 0x00,0xF0,0xD0,0xC0, 0x00,0xF0,0xD0,0xF0, + 0x00,0xF0,0xF0,0x00, 0x00,0xF0,0xF0,0x30, 0x00,0xF0,0xF0,0x60, 0x00,0xF0,0xF0,0x90, 0x00,0xF0,0xF0,0xC0, 0x00,0xF0,0xF0,0xF0, + + 0x00,0x10,0x10,0x10, 0x00,0x20,0x20,0x20, 0x00,0x30,0x30,0x30, 0x00,0x40,0x40,0x40, + 0x00,0x50,0x50,0x50, 0x00,0x60,0x60,0x60, 0x00,0x70,0x70,0x70, 0x00,0x80,0x80,0x80, + 0x00,0x90,0x90,0x90, 0x00,0xA0,0xA0,0xA0, 0x00,0xB0,0xB0,0xB0, 0x00,0xC0,0xC0,0xC0, + 0x00,0xD0,0xD0,0xD0, 0x00,0xE0,0xE0,0xE0 +}; + +static int * hamx_array = (int *) (hamx_array_char); + +static uchar cmap_hamx[] = { + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x30, 0x00,0x00,0x00,0x60, 0x00,0x00,0x00,0x90, 0x00,0x00,0x00,0xC0, 0x00,0x00,0x00,0xF0, + 0x00,0x00,0x20,0x00, 0x00,0x00,0x20,0x30, 0x00,0x00,0x20,0x60, 0x00,0x00,0x20,0x90, 0x00,0x00,0x20,0xC0, 0x00,0x00,0x20,0xF0, + 0x00,0x00,0x40,0x00, 0x00,0x00,0x40,0x30, 0x00,0x00,0x40,0x60, 0x00,0x00,0x40,0x90, 0x00,0x00,0x40,0xC0, 0x00,0x00,0x40,0xF0, + 0x00,0x00,0x60,0x00, 0x00,0x00,0x60,0x30, 0x00,0x00,0x60,0x60, 0x00,0x00,0x60,0x90, 0x00,0x00,0x60,0xC0, 0x00,0x00,0x60,0xF0, + 0x00,0x00,0x90,0x00, 0x00,0x00,0x90,0x30, 0x00,0x00,0x90,0x60, 0x00,0x00,0x90,0x90, 0x00,0x00,0x90,0xC0, 0x00,0x00,0x90,0xF0, + 0x00,0x00,0xB0,0x00, 0x00,0x00,0xB0,0x30, 0x00,0x00,0xB0,0x60, 0x00,0x00,0xB0,0x90, 0x00,0x00,0xB0,0xC0, 0x00,0x00,0xB0,0xF0, + 0x00,0x00,0xD0,0x00, 0x00,0x00,0xD0,0x30, 0x00,0x00,0xD0,0x60, 0x00,0x00,0xD0,0x90, 0x00,0x00,0xD0,0xC0, 0x00,0x00,0xD0,0xF0, + 0x00,0x00,0xF0,0x00, 0x00,0x00,0xF0,0x30, 0x00,0x00,0xF0,0x60, 0x00,0x00,0xF0,0x90, 0x00,0x00,0xF0,0xC0, 0x00,0x00,0xF0,0xF0, + 0x00,0x50,0x00,0x00, 0x00,0x50,0x00,0x30, 0x00,0x50,0x00,0x60, 0x00,0x50,0x00,0x90, 0x00,0x50,0x00,0xC0, 0x00,0x50,0x00,0xF0, + 0x00,0x50,0x20,0x00, 0x00,0x50,0x20,0x30, 0x00,0x50,0x20,0x60, 0x00,0x50,0x20,0x90, 0x00,0x50,0x20,0xC0, 0x00,0x50,0x20,0xF0, + 0x00,0x50,0x40,0x00, 0x00,0x50,0x40,0x30, 0x00,0x50,0x40,0x60, 0x00,0x50,0x40,0x90, 0x00,0x50,0x40,0xC0, 0x00,0x50,0x40,0xF0, + 0x00,0x50,0x60,0x00, 0x00,0x50,0x60,0x30, 0x00,0x50,0x60,0x60, 0x00,0x50,0x60,0x90, 0x00,0x50,0x60,0xC0, 0x00,0x50,0x60,0xF0, + 0x00,0x50,0x90,0x00, 0x00,0x50,0x90,0x30, 0x00,0x50,0x90,0x60, 0x00,0x50,0x90,0x90, 0x00,0x50,0x90,0xC0, 0x00,0x50,0x90,0xF0, + 0x00,0x50,0xB0,0x00, 0x00,0x50,0xB0,0x30, 0x00,0x50,0xB0,0x60, 0x00,0x50,0xB0,0x90, 0x00,0x50,0xB0,0xC0, 0x00,0x50,0xB0,0xF0, + 0x00,0x50,0xD0,0x00, 0x00,0x50,0xD0,0x30, 0x00,0x50,0xD0,0x60, 0x00,0x50,0xD0,0x90, 0x00,0x50,0xD0,0xC0, 0x00,0x50,0xD0,0xF0, + 0x00,0x50,0xF0,0x00, 0x00,0x50,0xF0,0x30, 0x00,0x50,0xF0,0x60, 0x00,0x50,0xF0,0x90, 0x00,0x50,0xF0,0xC0, 0x00,0x50,0xF0,0xF0, + 0x00,0xA0,0x00,0x00, 0x00,0xA0,0x00,0x30, 0x00,0xA0,0x00,0x60, 0x00,0xA0,0x00,0x90, 0x00,0xA0,0x00,0xC0, 0x00,0xA0,0x00,0xF0, + 0x00,0xA0,0x20,0x00, 0x00,0xA0,0x20,0x30, 0x00,0xA0,0x20,0x60, 0x00,0xA0,0x20,0x90, 0x00,0xA0,0x20,0xC0, 0x00,0xA0,0x20,0xF0, + 0x00,0xA0,0x40,0x00, 0x00,0xA0,0x40,0x30, 0x00,0xA0,0x40,0x60, 0x00,0xA0,0x40,0x90, 0x00,0xA0,0x40,0xC0, 0x00,0xA0,0x40,0xF0, + 0x00,0xA0,0x60,0x00, 0x00,0xA0,0x60,0x30, 0x00,0xA0,0x60,0x60, 0x00,0xA0,0x60,0x90, 0x00,0xA0,0x60,0xC0, 0x00,0xA0,0x60,0xF0, + 0x00,0xA0,0x90,0x00, 0x00,0xA0,0x90,0x30, 0x00,0xA0,0x90,0x60, 0x00,0xA0,0x90,0x90, 0x00,0xA0,0x90,0xC0, 0x00,0xA0,0x90,0xF0, + 0x00,0xA0,0xB0,0x00, 0x00,0xA0,0xB0,0x30, 0x00,0xA0,0xB0,0x60, 0x00,0xA0,0xB0,0x90, 0x00,0xA0,0xB0,0xC0, 0x00,0xA0,0xB0,0xF0, + 0x00,0xA0,0xD0,0x00, 0x00,0xA0,0xD0,0x30, 0x00,0xA0,0xD0,0x60, 0x00,0xA0,0xD0,0x90, 0x00,0xA0,0xD0,0xC0, 0x00,0xA0,0xD0,0xF0, + 0x00,0xA0,0xF0,0x00, 0x00,0xA0,0xF0,0x30, 0x00,0xA0,0xF0,0x60, 0x00,0xA0,0xF0,0x90, 0x00,0xA0,0xF0,0xC0, 0x00,0xA0,0xF0,0xF0, + 0x00,0xF0,0x00,0x00, 0x00,0xF0,0x00,0x30, 0x00,0xF0,0x00,0x60, 0x00,0xF0,0x00,0x90, 0x00,0xF0,0x00,0xC0, 0x00,0xF0,0x00,0xF0, + 0x00,0xF0,0x20,0x00, 0x00,0xF0,0x20,0x30, 0x00,0xF0,0x20,0x60, 0x00,0xF0,0x20,0x90, 0x00,0xF0,0x20,0xC0, 0x00,0xF0,0x20,0xF0, + 0x00,0xF0,0x40,0x00, 0x00,0xF0,0x40,0x30, 0x00,0xF0,0x40,0x60, 0x00,0xF0,0x40,0x90, 0x00,0xF0,0x40,0xC0, 0x00,0xF0,0x40,0xF0, + 0x00,0xF0,0x60,0x00, 0x00,0xF0,0x60,0x30, 0x00,0xF0,0x60,0x60, 0x00,0xF0,0x60,0x90, 0x00,0xF0,0x60,0xC0, 0x00,0xF0,0x60,0xF0, + 0x00,0xF0,0x90,0x00, 0x00,0xF0,0x90,0x30, 0x00,0xF0,0x90,0x60, 0x00,0xF0,0x90,0x90, 0x00,0xF0,0x90,0xC0, 0x00,0xF0,0x90,0xF0, + 0x00,0xF0,0xB0,0x00, 0x00,0xF0,0xB0,0x30, 0x00,0xF0,0xB0,0x60, 0x00,0xF0,0xB0,0x90, 0x00,0xF0,0xB0,0xC0, 0x00,0xF0,0xB0,0xF0, + 0x00,0xF0,0xD0,0x00, 0x00,0xF0,0xD0,0x30, 0x00,0xF0,0xD0,0x60, 0x00,0xF0,0xD0,0x90, 0x00,0xF0,0xD0,0xC0, 0x00,0xF0,0xD0,0xF0, + 0x00,0xF0,0xF0,0x00, 0x00,0xF0,0xF0,0x30, 0x00,0xF0,0xF0,0x60, 0x00,0xF0,0xF0,0x90, 0x00,0xF0,0xF0,0xC0, 0x00,0xF0,0xF0,0xF0, + 0x00,0x10,0x10,0x10, 0x00,0x20,0x20,0x20, 0x00,0x30,0x30,0x30, 0x00,0x40,0x40,0x40, 0x00,0x50,0x50,0x50, 0x00,0x60,0x60,0x60, + 0x00,0x70,0x70,0x70, 0x00,0x80,0x80,0x80, 0x00,0x90,0x90,0x90, 0x00,0xA0,0xA0,0xA0, 0x00,0xB0,0xB0,0xB0, 0x00,0xC0,0xC0,0xC0, + 0x00,0xD0,0xD0,0xD0, 0x00,0xE0,0xE0,0xE0 +}; + + +float adat_gamma = 1.0; +float adat_distort = 1.0; + +/* + * + * New version: + * + * 32 brighntesses Y 15 with direct access (black and white are specials) + * 16 colors H ue + * 7 intensities S aturation + * + * Total 3584 'different' colors. First 512 colors free. + * + * + */ + +void imb_convhamx(struct ImBuf *ibuf, unsigned char *coltab, short *deltab) +{ + short r,g,b,lr,lg,lb,dr,dg,db,col,fout,type,step; + int i; + uchar *rect; + + /* + b = 0000 xxxx + g = 0001 xxxx + r = 0010 xxxx + cmap >= 48 + */ + + for (step = 0 ; step < 2 ; step ++){ + rect = (uchar *) ibuf->rect; + rect += 4*step; + i = ((ibuf->x * ibuf->y) + 2 - step - 1) / 2; + + lb = coltab[1]; + lg = coltab[2]; + lr = coltab[3]; + type = col = 0; + + for ( ;i>0;i--){ + b = rect[2] >> 4; + g = rect[1] >> 4; + r = rect[0] >> 4; + + if ((b-lb) | (g-lg) | (r-lr)){ + col = ((b<<8) + (g<<4) + r) << 1; + fout = deltab[col + 1]; + col = deltab[col]; + type = 0; + dr = quadr[lr-r] ; + dg = quadr[lg-g] ; + db = quadr[lb-b]; + + if ((dr+dg)<=fout) { + fout = dr+dg ; + type = 1; + } + if ((dg+db)<=fout) { + fout = dg+db; + type = 2; + } + if ((dr+db)<=fout) { + fout = dr+db; + type = 4; + } + + switch(type){ + case 1: + lb = b ; + col = b; + break; + case 4: + lg = g ; + col = g+16; + break; + case 2: + lr = r ; + col = r + 32; + break; + default: + /*printf("%04x %5d %5d ", (b<<8) + (g<<4) + r, col, fout);*/ + + lb = coltab[col*4 + 1]; + lg = coltab[col*4 + 2]; + lr = coltab[col*4 + 3]; + /*printf("%01x%01x%01x %01x%01x%01x\n", b, g, r, lb, lg, lr);*/ + col += 48; + } + } + rect[3] = col; + rect += 8; + } + } +} + +static short dec_hamx(struct ImBuf * ibuf, unsigned char *body, int cmap[]) +{ + int todo,i; + int j,step,col; + unsigned int *rect; + + for (step = 0 ; step < 2 ; step ++){ + rect = ibuf->rect; + rect += step; + todo = (ibuf->x * ibuf->y + 2 - step - 1) / 2; + col = cmap[0]; + while (todo>0){ + i = *body++; + + if (i & 128){ /* fill */ + + i = 257-i; + todo -= i; + j = *(body++); + + col = ((col & hamx_array[j]) | hamx_array[j + 256]); + + do{ + *rect = col; + rect += 2; + }while (--i); + } else{ /* copy */ + i++; + todo-=i; + + do{ + j = *(body++); + *rect = col = ((col & hamx_array[j]) | hamx_array[j + 256]); + rect += 2; + }while (--i); + } + } + if (todo) return (0); + } + return(1); +} + + +struct ImBuf *imb_loadanim(int *iffmem, int flags) +{ + int chunk, totlen, len, *mem, cmaplen = 0; + unsigned int *cmap = NULL; + uchar *body = 0; + struct Adat adat; + struct ImBuf *ibuf=0; + static int is_flipped = FALSE; + + mem=iffmem; + if (GET_ID(mem) != FORM) return (0); + if (GET_ID(mem + 2) != ANIM) return (0); + totlen= (GET_BIG_LONG(mem + 1) + 1) & ~1; + mem += 3; + totlen -= 4; + adat.w = 0; + adat.xorig = 0; + adat.yorig = 0; + adat.gamma = adat_gamma; + adat.distort = adat_distort; + + while(totlen > 0){ + chunk = GET_ID(mem); + len = (GET_BIG_LONG(mem + 1) + 1) & ~1; + mem += 2; + + totlen -= len+8; + switch (chunk){ + case ADAT: + if (len > sizeof(struct Adat)){ + memcpy(&adat,mem,sizeof(struct Adat)); + } else{ + memcpy(&adat,mem,len); + } + adat.w = BIG_SHORT(adat.w); + adat.h = BIG_SHORT(adat.h); + adat.type = BIG_SHORT(adat.type); + adat.xorig = BIG_SHORT(adat.xorig); + adat.yorig = BIG_SHORT(adat.yorig); + break; + case CMAP: + cmap = (unsigned int *) mem; + cmaplen = len; + break; + case BODY: + body = (uchar *) mem; + break; + } + mem = (int *)((uchar *)mem +len); + } + + if (body == 0) return (0); + if (adat.w == 0) return (0); + + adat_gamma = adat.gamma; + adat_distort = adat.distort; + + if (flags & IB_test) ibuf=IMB_allocImBuf(adat.w, adat.h, 24, 0, 0); + else ibuf=IMB_allocImBuf(adat.w, adat.h, 24, IB_rect, 0); + if (ibuf==0) return (0); + + ibuf->ftype = (Anim | adat.type); + ibuf->xorig = adat.xorig; + ibuf->yorig = adat.yorig; + ibuf->flags = flags; + + if (cmaplen){ + ibuf->cmap = malloc(cmaplen); + memcpy(ibuf->cmap, cmap, cmaplen); + ibuf->maxcol = cmaplen >> 2; + } + + if (flags & IB_test){ + if (flags & IB_freem) free(iffmem); + return(ibuf); + } + + switch (adat.type){ + case HAMX: + if (flags & IB_rect){ + if (!is_flipped) { + int i; + unsigned int * t; + t = (unsigned int *) hamx_array_char; + for (i = 0; i < sizeof(hamx_array_char) / sizeof(int) ; i++) { + t[i] = SWAP_LONG(t[i]); + } + + t = (unsigned int *) cmap_hamx; + + for (i = 0; i < sizeof(cmap_hamx) / sizeof(int) ; i++) { + t[i] = SWAP_LONG(t[i]); + } + + is_flipped= TRUE; + } + + if (dec_hamx(ibuf,body,(int*) cmap_hamx) == 0){ + IMB_freeImBuf(ibuf); + ibuf = 0; + } + if (flags & IB_ttob) IMB_flipy(ibuf); + } + break; + default: + IMB_freeImBuf(ibuf); + ibuf = 0; + } + + if (flags & IB_freem) free(iffmem); + + return (ibuf); +} + + +static unsigned char *makebody_anim(int bytes, + unsigned char *buf, + unsigned char *rect) +{ + register uchar last,this; + register int copy; + register uchar *rectstart,*temp; + + bytes--; + rectstart = rect; + last = *rect++; + this = *rect++; + copy = last^this; + while (bytes>0){ + if (copy){ + do{ + last = this; + this = *rect++; + if (last == this){ + if (this == rect[-3]){ /* three the same? */ + bytes --; /* init bytes */ + break; + } + } + }while (--bytes != 0); + + copy = rect-rectstart; + copy --; + if (bytes) copy -= 2; + + temp = rect; + rect = rectstart; + + while (copy){ + last = copy; + if (copy>MAXDAT) last = MAXDAT; + copy -= last; + *buf++ = last-1; + do{ + *buf++ = *rect++; + }while(--last != 0); + } + rectstart = rect; + rect = temp; + last = this; + + copy = FALSE; + } else { + while (*rect++ == this){ /* seek first different byte */ + if (--bytes == 0) break; /* or end of line */ + } + rect --; + copy = rect-rectstart; + rectstart = rect; + bytes --; + this = *rect++; + + while (copy){ + if (copy>MAXRUN){ + *buf++ = -(MAXRUN-1); + *buf++ = last; + copy -= MAXRUN; + } else { + *buf++ = -(copy-1); + *buf++ = last; + break; + } + } + copy=TRUE; + } + } + return (buf); +} + + +short imb_enc_anim(struct ImBuf *ibuf, int file) +{ + int step, size, i, skip, steps = 0; + uchar *buf1, *crect, *_buf1, *_buf2, *bufend; + short ok = TRUE; + + if (ibuf == 0) return (0); + if (file < 0 ) return (0); + if (ibuf->rect == 0) return(0); + + /* add dither */ + + switch(ibuf->ftype){ + case AN_hamx: + ibuf->cmap = (unsigned int *) cmap_hamx; + ibuf->mincol = 0; + ibuf->maxcol = sizeof(cmap_hamx) / 4; + imb_converttoham(ibuf); + steps = 2; + break; + } + if (steps == 0) return 0; + + size = ((ibuf->x + 1)* (ibuf->y + 1)) / steps + 1024; + if ((_buf1 = malloc(size)) == 0) return(0); + if ((_buf2 = malloc(size)) == 0){ + free(_buf1); + return(0); + } + + skip = 4 * steps; + for (step = 0 ; step < steps ; step ++){ + crect = (uchar *) ibuf->rect; + crect += 4 * step; + size = (ibuf->x * ibuf->y + steps - step - 1) / steps; + buf1 = _buf1; + if ((ibuf->ftype == AN_hamx) || (ibuf->ftype == AN_yuvx)){ + crect += 3; + for (i = size ; i>0 ; i--){ + *(buf1 ++) = *crect; + crect += skip; + } + } else{ + for (i = size ; i>0 ; i--){ + *(buf1 ++) = crect[1] + (crect[2] >> 2) + (crect[3] >> 5); + crect += skip; + } + } + bufend = makebody_anim(size,_buf2,_buf1); + if (bufend == 0){ + ok = FALSE; + break; + } + size = bufend - _buf2; + if (write(file, _buf2, size) != size){ + ok = FALSE; + break; + } + } + free(_buf1); + free(_buf2); + return (ok); +} diff --git a/source/blender/imbuf/intern/iff.c b/source/blender/imbuf/intern/iff.c new file mode 100644 index 00000000000..675de9c76ab --- /dev/null +++ b/source/blender/imbuf/intern/iff.c @@ -0,0 +1,226 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * iff.c + * + * $Id$ + */ + +#ifdef WIN32 +#include +#endif +#include "BLI_blenlib.h" +#include "imbuf.h" +#include "imbuf_patch.h" +#include "IMB_imbuf_types.h" +#include "IMB_iff.h" + +unsigned short imb_start_iff(struct ImBuf *ibuf, int file) +{ + unsigned int *point, size, *buf; + + if ((point=buf=(unsigned int *)malloc(32768))==0) return FALSE; + + *point++ = FORM; /* FORMxxxxILBM in buffer */ + *point++ = 0; + + if (IS_amiga(ibuf)){ + struct BitMapHeader *bmhd; + + *point++ = ILBM; + *point++ = CAMG; + *point++ = 4; + *point++ = (ibuf->ftype & 0xffff); + + *point++=BMHD; + *point++=sizeof(struct BitMapHeader); + + bmhd=(struct BitMapHeader *)point; /* bmhd points to location where bmhd will be */ + point=(unsigned int *)((char *)point+sizeof(struct BitMapHeader)); /* advance pointer already */ + + bmhd->w=ibuf->x; + bmhd->h=ibuf->y; + bmhd->pageWidth=ibuf->x; + bmhd->pageHeight=ibuf->y; + bmhd->x=0; + bmhd->y=0; + bmhd->nPlanes=ibuf->depth; + bmhd->masking=0; + if (ibuf->flags & IB_vert){ + bmhd->compression=2; + } + else{ + bmhd->compression=1; + } + bmhd->pad1=0; + bmhd->transparentColor=0; + bmhd->xAspect=1; + bmhd->yAspect=1; + } else if (IS_anim(ibuf)){ + struct Adat *adat; + extern float adat_gamma; + extern float adat_distort; + + *point++ = ANIM; + *point++ = ADAT; + *point++ = BIG_LONG(sizeof(struct Adat)); + + adat = (struct Adat *)point; + point = (unsigned int *)((char *)point+sizeof(struct Adat)); /* advance pointer already */ + + adat->w = BIG_SHORT(ibuf->x); + adat->h = BIG_SHORT(ibuf->y); + + adat->type = BIG_SHORT(ibuf->ftype); + adat->xorig = BIG_SHORT(ibuf->xorig); + adat->yorig = BIG_SHORT(ibuf->yorig); + adat->pad = 0; + adat->gamma = adat_gamma; + adat->distort = adat_distort; + } + + size=((uchar *)point-(uchar *)buf); + if (write(file,buf,size)!=size){ + free(buf); + return (FALSE); + } + + if (ibuf->cmap){ + if (IS_anim(ibuf)){ + size = ibuf->maxcol * sizeof(int); + buf[0] = CMAP; + buf[1] = BIG_LONG(size); + if (write(file,buf,8) != 8){ + free(buf); + return (FALSE); + } + if (write(file,ibuf->cmap,size) != size){ + free(buf); + return (FALSE); + } + } else{ + uchar *cpoint,*cols; + unsigned int i,bits; + + point = buf; + if (IS_amiga(ibuf)){ + *(point++) = CMAP; + *(point++) = BIG_LONG(3*ibuf->maxcol); + } + + cpoint = (uchar *) point; + cols = (uchar *)ibuf->cmap; + if ((ibuf->cbits > 0) && (ibuf->cbits < 8)){ + bits = ~((1 << (8-ibuf->cbits)) - 1); + } else bits = -1; + + if (IS_ham(ibuf)) bits = -1; + + for (i=0 ; imaxcol ; i++){ + *(cpoint++) = cols[0] & bits; + *(cpoint++) = cols[1] & bits; + *(cpoint++) = cols[2] & bits; + cols += 4; + } + if (ibuf->maxcol & 1) *(cpoint++)=0; + + size=(cpoint-(uchar *)buf); + if (write(file,buf,size)!=size){ + free(buf); + return (FALSE); + } + } + } + + if (IS_amiga(ibuf)) buf[0] = BODY; + if (IS_anim(ibuf)) buf[0] = BODY; + buf[1]=0; + + if (write(file,buf,8)!=8){ + free(buf); + return(FALSE); + } + + free(buf); + return (TRUE); +} + + +unsigned short imb_update_iff(int file, int code) +{ + int buf[2], filelen, skip; + uchar nop; + + if (file<=0) return (FALSE); + + filelen = BLI_filesize(file)-8; /* calc filelength */ + + lseek(file,0L,2); /* seek end */ + + if (filelen & 1){ /* make length 'even' */ + switch(code){ + case BODY: + nop = IFFNOP; + break; + } + if (write(file,&nop,1)!=1) return (FALSE); + filelen++; + } + lseek(file,4L,0); + + buf[0] = BIG_LONG(filelen); + + if (write(file, buf, 4) != 4) return (FALSE); + if (code == 0) return (TRUE); + + filelen-=4; + lseek(file,4L,1); + + while (filelen>0){ /* seek BODY */ + read(file, buf, 8); + filelen -= 8; + if (buf[0] == code) break; + + skip = (BIG_LONG(buf[1]) + 1) & ~1; + filelen -= skip; + lseek(file, skip, 1); + } + if (filelen <= 0) { + printf("update_iff: couldn't find chunk\n"); + return (FALSE); + } + + lseek(file, -4L, 1); + + buf[0] = BIG_LONG(filelen); + + if (write(file, buf, 4)!=4) return (FALSE); + + return (TRUE); +} diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c new file mode 100644 index 00000000000..54e0ec94672 --- /dev/null +++ b/source/blender/imbuf/intern/imageprocess.c @@ -0,0 +1,301 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * This file was moved here from the src/ directory. It is meant to + * deal with endianness. It resided in a general blending lib. The + * other functions were only used during rendering. This single + * function remained. It should probably move to imbuf/intern/util.c, + * but we'll keep it here for the time being. (nzc)*/ + +/* imageprocess.c MIXED MODEL + * + * april 95 + * + * $Id$ + */ + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" +#include "math.h" + +/* This define should be relocated to a global header some where Kent Mein +I stole it from util.h in the plugins api */ +#define MAX2(x,y) ( (x)>(y) ? (x) : (y) ) + +/* Only this one is used liberally here, and in imbuf */ +void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf) +{ + int size, do_float=0; + unsigned char rt, *cp = (unsigned char *)ibuf->rect; + float rtf, *cpf = ibuf->rect_float; + + if (ibuf->rect_float) do_float = 1; + size = ibuf->x * ibuf->y; + + while(size-- > 0) { + rt= cp[0]; + cp[0]= cp[3]; + cp[3]= rt; + rt= cp[1]; + cp[1]= cp[2]; + cp[2]= rt; + cp+= 4; + if (do_float) { + rtf= cpf[0]; + cpf[0]= cpf[3]; + cpf[3]= rtf; + rtf= cpf[1]; + cpf[1]= cpf[2]; + cpf[2]= rtf; + cpf+= 4; + } + } +} + +/************************************************************************** +* INTERPOLATIONS +* +* Reference and docs: +* http://wiki.blender.org/index.php/User:Damiles#Interpolations_Algorithms +***************************************************************************/ + +/* BICUBIC Interpolation functions */ +/* More info: http://wiki.blender.org/index.php/User:Damiles#Bicubic_pixel_interpolation +*/ +/* function assumes out to be zero'ed, only does RGBA */ +static float P(float k){ + float aux; + aux=(float)(1.0f/6.0f)*( pow( MAX2(k+2.0f,0) , 3.0f ) - 4.0f * pow( MAX2(k+1.0f,0) , 3.0f ) + 6.0f * pow( MAX2(k,0) , 3.0f ) - 4.0f * pow( MAX2(k-1.0f,0) , 3.0f)); + return aux ; +} + +void bicubic_interpolation(ImBuf *in, ImBuf *out, float x, float y, int xout, int yout) +{ + int i,j,n,m,x1,y1; + unsigned char *dataI,*outI; + float a,b, outR,outG,outB,outA,*dataF,*outF; + int do_rect, do_float; + + if (in == NULL) return; + if (in->rect == NULL && in->rect_float == NULL) return; + + do_rect= (out->rect != NULL); + do_float= (out->rect_float != NULL); + + i= (int)floor(x); + j= (int)floor(y); + a= x - i; + b= y - j; + + outR= 0.0f; + outG= 0.0f; + outB= 0.0f; + outA= 0.0f; + for(n= -1; n<= 2; n++){ + for(m= -1; m<= 2; m++){ + x1= i+n; + y1= j+m; + if (x1>0 && x1 < in->x && y1>0 && y1y) { + if (do_float) { + dataF= in->rect_float + in->x * y1 * 4 + 4*x1; + outR+= dataF[0] * P(n-a) * P(b-m); + outG+= dataF[1] * P(n-a) * P(b-m); + outB+= dataF[2] * P(n-a) * P(b-m); + outA+= dataF[3] * P(n-a) * P(b-m); + } + if (do_rect) { + dataI= (unsigned char*)in->rect + in->x * y1 * 4 + 4*x1; + outR+= dataI[0] * P(n-a) * P(b-m); + outG+= dataI[1] * P(n-a) * P(b-m); + outB+= dataI[2] * P(n-a) * P(b-m); + outA+= dataI[3] * P(n-a) * P(b-m); + } + } + } + } + if (do_rect) { + outI= (unsigned char *)out->rect + out->x * yout * 4 + 4*xout; + outI[0]= (int)outR; + outI[1]= (int)outG; + outI[2]= (int)outB; + outI[3]= (int)outA; + } + if (do_float) { + outF= (float *)out->rect_float + out->x * yout * 4 + 4*xout; + outF[0]= outR; + outF[1]= outG; + outF[2]= outB; + outF[3]= outA; + } +} + +/* function assumes out to be zero'ed, only does RGBA */ +/* BILINEAR INTERPOLATION */ +void bilinear_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, int yout) +{ + float *row1, *row2, *row3, *row4, a, b, *outF; + unsigned char *row1I, *row2I, *row3I, *row4I, *outI; + float a_b, ma_b, a_mb, ma_mb; + float empty[4]= {0.0f, 0.0f, 0.0f, 0.0f}; + unsigned char emptyI[4]= {0, 0, 0, 0}; + int y1, y2, x1, x2; + int do_rect, do_float; + + if (in==NULL) return; + if (in->rect==NULL && in->rect_float==NULL) return; + + do_rect= (out->rect != NULL); + do_float= (out->rect_float != NULL); + + x1= (int)floor(u); + x2= (int)ceil(u); + y1= (int)floor(v); + y2= (int)ceil(v); + + // sample area entirely outside image? + if (x2<0 || x1>in->x-1 || y2<0 || y1>in->y-1) return; + + if (do_rect) + outI=(unsigned char *)out->rect + out->x * yout * 4 + 4*xout; + else + outI= NULL; + if (do_float) + outF=(float *)out->rect_float + out->x * yout * 4 + 4*xout; + else + outF= NULL; + + if (do_float) { + // sample including outside of edges of image + if (x1<0 || y1<0) row1= empty; + else row1= (float *)in->rect_float + in->x * y1 * 4 + 4*x1; + + if (x1<0 || y2>in->y-1) row2= empty; + else row2= (float *)in->rect_float + in->x * y2 * 4 + 4*x1; + + if (x2>in->x-1 || y1<0) row3= empty; + else row3= (float *)in->rect_float + in->x * y1 * 4 + 4*x2; + + if (x2>in->x-1 || y2>in->y-1) row4= empty; + else row4= (float *)in->rect_float + in->x * y2 * 4 + 4*x2; + + a= u-floor(u); + b= v-floor(v); + a_b= a*b; ma_b= (1.0f-a)*b; a_mb= a*(1.0f-b); ma_mb= (1.0f-a)*(1.0f-b); + + outF[0]= ma_mb*row1[0] + a_mb*row3[0] + ma_b*row2[0]+ a_b*row4[0]; + outF[1]= ma_mb*row1[1] + a_mb*row3[1] + ma_b*row2[1]+ a_b*row4[1]; + outF[2]= ma_mb*row1[2] + a_mb*row3[2] + ma_b*row2[2]+ a_b*row4[2]; + outF[3]= ma_mb*row1[3] + a_mb*row3[3] + ma_b*row2[3]+ a_b*row4[3]; + } + if (do_rect) { + // sample including outside of edges of image + if (x1<0 || y1<0) row1I= emptyI; + else row1I= (unsigned char *)in->rect + in->x * y1 * 4 + 4*x1; + + if (x1<0 || y2>in->y-1) row2I= emptyI; + else row2I= (unsigned char *)in->rect + in->x * y2 * 4 + 4*x1; + + if (x2>in->x-1 || y1<0) row3I= emptyI; + else row3I= (unsigned char *)in->rect + in->x * y1 * 4 + 4*x2; + + if (x2>in->x-1 || y2>in->y-1) row4I= emptyI; + else row4I= (unsigned char *)in->rect + in->x * y2 * 4 + 4*x2; + + a= u-floor(u); + b= v-floor(v); + a_b= a*b; ma_b= (1.0f-a)*b; a_mb= a*(1.0f-b); ma_mb= (1.0f-a)*(1.0f-b); + + outI[0]= ma_mb*row1I[0] + a_mb*row3I[0] + ma_b*row2I[0]+ a_b*row4I[0]; + outI[1]= ma_mb*row1I[1] + a_mb*row3I[1] + ma_b*row2I[1]+ a_b*row4I[1]; + outI[2]= ma_mb*row1I[2] + a_mb*row3I[2] + ma_b*row2I[2]+ a_b*row4I[2]; + outI[3]= ma_mb*row1I[3] + a_mb*row3I[3] + ma_b*row2I[3]+ a_b*row4I[3]; + } +} + +/* function assumes out to be zero'ed, only does RGBA */ +/* NEAREST INTERPOLATION */ +void neareast_interpolation(ImBuf *in, ImBuf *out, float u, float v,int xout, int yout) +{ + float *outF,*dataF; + unsigned char *dataI,*outI; + int y1, x1; + int do_rect, do_float; + + if (in==NULL) return; + if (in->rect==NULL && in->rect_float==NULL) return; + + do_rect= (out->rect != NULL); + do_float= (out->rect_float != NULL); + + x1= (int)(u); + y1= (int)(v); + + if (do_rect) + outI=(unsigned char *)out->rect + out->x * yout * 4 + 4*xout; + else + outI= NULL; + if (do_float) + outF=(float *)out->rect_float + out->x * yout * 4 + 4*xout; + else + outF= NULL; + + // sample area entirely outside image? + if (x1<0 || x1>in->x-1 || y1<0 || y1>in->y-1) return; + + // sample including outside of edges of image + if (x1<0 || y1<0) { + if (do_rect) { + outI[0]= 0; + outI[1]= 0; + outI[2]= 0; + outI[3]= 0; + } + if (do_float) { + outF[0]= 0.0f; + outF[1]= 0.0f; + outF[2]= 0.0f; + outF[3]= 0.0f; + } + } else { + dataI= (unsigned char *)in->rect + in->x * y1 * 4 + 4*x1; + if (do_rect) { + outI[0]= dataI[0]; + outI[1]= dataI[1]; + outI[2]= dataI[2]; + outI[3]= dataI[3]; + } + dataF= in->rect_float + in->x * y1 * 4 + 4*x1; + if (do_float) { + outF[0]= dataF[0]; + outF[1]= dataF[1]; + outF[2]= dataF[2]; + outF[3]= dataF[3]; + } + } +} diff --git a/source/blender/imbuf/intern/imbuf.h b/source/blender/imbuf/intern/imbuf.h new file mode 100644 index 00000000000..1f17217459d --- /dev/null +++ b/source/blender/imbuf/intern/imbuf.h @@ -0,0 +1,171 @@ +/** + * imbuf.h (mar-2001 nzc) + * + * This header might have to become external... + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef IMBUF_H +#define IMBUF_H + +#include +#include +#include + +#ifndef WIN32 +#include +#endif + +#include +#include +#include +#include + +#ifndef WIN32 +#include +#endif + +#if !defined(WIN32) && !defined(__BeOS) +#define O_BINARY 0 +#endif + +#define SWAP_SHORT(x) (((x & 0xff) << 8) | ((x >> 8) & 0xff)) +#define SWAP_LONG(x) (((x) << 24) | (((x) & 0xff00) << 8) | (((x) >> 8) & 0xff00) | (((x) >> 24) & 0xff)) + +#define ENDIAN_NOP(x) (x) + +#if defined(__sgi) || defined(__sparc) || defined(__sparc__) || defined (__PPC__) || (defined (__APPLE__) && !defined(__LITTLE_ENDIAN__)) +#define LITTLE_SHORT SWAP_SHORT +#define LITTLE_LONG SWAP_LONG +#define BIG_SHORT ENDIAN_NOP +#define BIG_LONG ENDIAN_NOP +#else +#define LITTLE_SHORT ENDIAN_NOP +#define LITTLE_LONG ENDIAN_NOP +#define BIG_SHORT SWAP_SHORT +#define BIG_LONG SWAP_LONG +#endif + +#define malloc(x) MEM_mallocN(x, __FILE__) +#define free(x) MEM_freeN(x) +#define calloc(x,y) MEM_callocN((x)*(y), __FILE__) +#define freelist(x) BLI_freelistN(x) + +#ifdef SHLIB +void *(*ib_calloc)(); +#define calloc(x,y) ib_calloc((x),(y)) +void *(*ib_malloc)(); +#define malloc(x) ib_malloc(x) +void (*ib_free)(); +#define free(x) ib_free(x) +void (*ib_memcpy)(); +#define memcpy(x,y,z) ib_memcpy((x),(y),(z)) +int (*ib_abs)(); +#define abs(x) ib_abs(x) +void (*ib_fprin_tf)(); +#define fprintf ib_fprin_tf +int (*ib_sprin_tf)(); +#define sprintf ib_sprin_tf +void (*ib_prin_tf)(); +#define printf ib_prin_tf +int (*ib_lseek)(); +#define lseek(x,y,z) ib_lseek((x),(y),(z)) +void *(*ib_mmap)(); +#define mmap(u,v,w,x,y,z) ib_mmap((u),(v),(w),(x),(y),(z)) +int (*ib_munmap)(); +#define munmap(x,y) ib_munmap((x),(y)) +int (*ib_open)(); +#define open(x,y) ib_open((x),(y)) +void (*ib_close)(); +#define close(x) ib_close(x) +int (*ib_write)(); +#define write(x,y,z) ib_write((x),(y),(z)) +int (*ib_read)(); +#define read(x,y,z) ib_read((x),(y),(z)) +int (*ib_fchmod)(); +#define fchmod(x,y) ib_fchmod((x),(y)) +int (*ib_remove)(); +#define remove(x) ib_remove(x) +size_t (*ib_strlen)(); +#define strlen(x) ib_strlen(x) +int (*ib_isdigit)(); +#define isdigit(x) ib_isdigit(x) +char *(*ib_strcpy)(); +#define strcpy(x,y) ib_strcpy((x),(y)) +int (*ib_atoi)(); +#define atoi(x) ib_atoi(x) +char *(*ib_strcat)(); +#define strcat(x,y) ib_strcat((x),(y)) +int (*ib_stat)(); +/* #define stat(x,y) ib_stat((x),(y)) */ +FILE *ib_iob; +#define _iob ib_iob + +#else + +#define ib_stat stat + +#endif /* SHLIB */ + + +#define WIDTHB(x) (((x+15)>>4)<<1) + +extern unsigned short *quadr; +extern float dyuvrgb[4][4]; +extern float rgbdyuv[4][4]; + + +typedef struct Adat +{ + unsigned short w, h; + unsigned short type; + unsigned short xorig, yorig; + unsigned short pad; + float gamma; + float distort; +}Adat; + +struct BitMapHeader +{ + unsigned short w, h; /* in pixels */ + unsigned short x, y; + char nPlanes; + char masking; + char compression; + char pad1; + unsigned short transparentColor; + char xAspect, yAspect; + short pageWidth, pageHeight; +}; + +#endif /* IMBUF_H */ + diff --git a/source/blender/imbuf/intern/imbuf_patch.h b/source/blender/imbuf/intern/imbuf_patch.h new file mode 100644 index 00000000000..f2d490d235b --- /dev/null +++ b/source/blender/imbuf/intern/imbuf_patch.h @@ -0,0 +1,114 @@ +/** + * imbuf_patch.h + * + * These are some definitions to make imbuf more independent from the + * rest of the blender code. Most of these are dirty and should not + * really exist. + * + * $Id$ * + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef IMBUF_PATCH_H +#define IMBUF_PATCH_H + +/* most of imbuf uses this aloc, and it will disappear soon + * (hopefully) (25-10-2001 nzc) */ +#include "MEM_guardedalloc.h" + +struct ImBuf; + +/* originally, these were defines ... */ +typedef unsigned char uchar; + +/* should not be used at all */ +#define TRUE 1 +#define FALSE 0 + +/* Endianness: flip the byte order. It's strange that this is needed.. + * After all, there is an internal endian.{c,h}... */ +#if defined(__sgi) || defined (__sparc) || defined(__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__) +#define MAKE_ID(a,b,c,d) ( (int)(a)<<24 | (int)(b)<<16 | (c)<<8 | (d) ) +#else +#define MAKE_ID(a,b,c,d) ( (int)(d)<<24 | (int)(c)<<16 | (b)<<8 | (a) ) +#endif + +/* These defines loop back to the internal Blender memory management + * system, implemented in blenlib. */ +#define NEW(x) (x*)MEM_mallocN(sizeof(x),# x) +#define mallocstruct(x,y) (x*)malloc((y)* sizeof(x)) +#define callocstruct(x,y) (x*)calloc((y), sizeof(x)) + +/* These vars are used thoughout the image buffer for conversions. */ +extern float rgbyuv[4][4]; +extern float yuvrgb[4][4]; +extern float rgbbeta[4][4]; + +/* This one helps debugging. */ +extern int IB_verbose; + +/* These ID's are used for checking memory blocks. See blenlib for + * more details. This set is only used in the imbuf internally. */ + +#define CAT MAKE_ID('C','A','T',' ') +#define FORM MAKE_ID('F','O','R','M') +#define ILBM MAKE_ID('I','L','B','M') +#define BMHD MAKE_ID('B','M','H','D') +#define CMAP MAKE_ID('C','M','A','P') +#define CAMG MAKE_ID('C','A','M','G') +#define BODY MAKE_ID('B','O','D','Y') + +#define ANIM MAKE_ID('A','N','I','M') +#define ADAT MAKE_ID('A','D','A','T') +#define CODE MAKE_ID('C','O','D','E') +#define ANHD MAKE_ID('A','N','H','D') +#define DLTA MAKE_ID('D','L','T','A') +#define BLCK MAKE_ID('B','L','C','K') + +#define MAXRUN 126 +#define MAXDAT 126 +#define IFFNOP 128 + +#define camg ftype + +#define LI_rect IB_rect +#define LI_planes IB_planes +#define LI_kcmap IB_cmap +#define LI_cmap IB_cmap +#define LI_freem IB_freem +#define LI_test IB_test + +#define SI_rect IB_rect +#define SI_planes IB_planes +#define SI_kcmap IB_cmap +#define SI_cmap IB_cmap +#define SI_vert IB_vert + +#endif + diff --git a/source/blender/imbuf/intern/imginfo.c b/source/blender/imbuf/intern/imginfo.c new file mode 100644 index 00000000000..37bde9e5ac3 --- /dev/null +++ b/source/blender/imbuf/intern/imginfo.c @@ -0,0 +1,158 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Austin Benesh. Ton Roosendaal. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include +#include + +#include "BLI_blenlib.h" +#include "MEM_guardedalloc.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "IMB_imginfo.h" + + + +void IMB_imginfo_free(struct ImBuf* img) +{ + ImgInfo *info; + + if (!img) + return; + if (!img->img_info) { + return; + } + info = img->img_info; + while (info) { + ImgInfo* next = info->next; + MEM_freeN(info->key); + MEM_freeN(info->value); + MEM_freeN(info); + info = next; + } +} + +int IMB_imginfo_get_field(struct ImBuf* img, const char* key, char* field, int len) +{ + ImgInfo *info; + int retval = 0; + + if (!img) + return 0; + if (!img->img_info) { + return 0; + } + info = img->img_info; + while (info) { + if (strcmp(key, info->key) == 0) { + BLI_strncpy(field, info->value, len); + retval = 1; + break; + } + info = info->next; + } + return retval; +} + +int IMB_imginfo_add_field(struct ImBuf* img, const char* key, const char* field) +{ + ImgInfo *info; + ImgInfo *last; + + if (!img) + return 0; + + if (!img->img_info) { + img->img_info = MEM_callocN(sizeof(ImgInfo), "ImgInfo"); + info = img->img_info; + } else { + info = img->img_info; + last = info; + while (info) { + last = info; + info = info->next; + } + info = MEM_callocN(sizeof(ImgInfo), "ImgInfo"); + last->next = info; + } + info->key = BLI_strdup(key); + info->value = BLI_strdup(field); + return 1; +} + +int IMB_imginfo_del_field(struct ImBuf *img, const char *key) +{ + ImgInfo *p, *p1; + + if ((!img) || (!img->img_info)) + return (0); + + p = img->img_info; + p1 = NULL; + while (p) { + if (!strcmp (key, p->key)) { + if (p1) + p1->next = p->next; + else + img->img_info = p->next; + + MEM_freeN(p->key); + MEM_freeN(p->value); + MEM_freeN(p); + return (1); + } + p1 = p; + p = p->next; + } + return (0); +} + +int IMB_imginfo_change_field(struct ImBuf *img, const char *key, const char *field) +{ + ImgInfo *p; + + if (!img) + return (0); + + if (!img->img_info) + return (IMB_imginfo_add_field (img, key, field)); + + p = img->img_info; + while (p) { + if (!strcmp (key, p->key)) { + MEM_freeN (p->value); + p->value = BLI_strdup (field); + return (1); + } + p = p->next; + } + + return (IMB_imginfo_add_field (img, key, field)); +} diff --git a/source/blender/imbuf/intern/iris.c b/source/blender/imbuf/intern/iris.c new file mode 100644 index 00000000000..5c0a3f94a0e --- /dev/null +++ b/source/blender/imbuf/intern/iris.c @@ -0,0 +1,653 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * iris.c + * + * $Id$ + */ + +#include +#include "BLI_blenlib.h" +#include "imbuf.h" +#include "imbuf_patch.h" +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" +#include "IMB_allocimbuf.h" +#include "IMB_iris.h" + +typedef struct { + unsigned short imagic; /* stuff saved on disk . . */ + unsigned short type; + unsigned short dim; + unsigned short xsize; + unsigned short ysize; + unsigned short zsize; + unsigned int min; + unsigned int max; + unsigned int wastebytes; + char name[80]; + unsigned int colormap; + + int file; /* stuff used in core only */ + unsigned short flags; + short dorev; + short x; + short y; + short z; + short cnt; + unsigned short *ptr; + unsigned short *base; + unsigned short *tmpbuf; + unsigned int offset; + unsigned int rleend; /* for rle images */ + unsigned int *rowstart; /* for rle images */ + int *rowsize; /* for rle images */ +} IMAGE; + +#define RINTLUM (79) +#define GINTLUM (156) +#define BINTLUM (21) + +#define ILUM(r,g,b) ((int)(RINTLUM*(r)+GINTLUM*(g)+BINTLUM*(b))>>8) + +#define OFFSET_R 0 /* this is byte order dependent */ +#define OFFSET_G 1 +#define OFFSET_B 2 +#define OFFSET_A 3 + +#define CHANOFFSET(z) (3-(z)) /* this is byte order dependent */ + +#define TYPEMASK 0xff00 +#define BPPMASK 0x00ff +#define ITYPE_VERBATIM 0x0000 +#define ITYPE_RLE 0x0100 +#define ISRLE(type) (((type) & 0xff00) == ITYPE_RLE) +#define ISVERBATIM(type) (((type) & 0xff00) == ITYPE_VERBATIM) +#define BPP(type) ((type) & BPPMASK) +#define RLE(bpp) (ITYPE_RLE | (bpp)) +#define VERBATIM(bpp) (ITYPE_VERBATIM | (bpp)) +#define IBUFSIZE(pixels) ((pixels+(pixels>>6))<<2) +#define RLE_NOP 0x00 + +/* funcs */ +static void readheader(FILE *inf, IMAGE *image); +static int writeheader(FILE *outf, IMAGE *image); + +static unsigned short getshort(FILE *inf); +static unsigned int getlong(FILE *inf); +static void putshort(FILE *outf, unsigned short val); +static int putlong(FILE *outf, unsigned int val); +static int writetab(FILE *outf, unsigned int *tab, int len); +static void readtab(FILE *inf, unsigned int *tab, int len); + +static void expandrow(unsigned char *optr, unsigned char *iptr, int z); +static void interleaverow(unsigned char *lptr, unsigned char *cptr, int z, int n); +static int compressrow(unsigned char *lbuf, unsigned char *rlebuf, int z, int cnt); +static void lumrow(unsigned char *rgbptr, unsigned char *lumptr, int n); + +/* + * byte order independent read/write of shorts and ints. + * + */ + +static uchar * file_data; +static int file_offset; + +static unsigned short getshort(FILE *inf) +{ + unsigned char * buf; + + buf = file_data + file_offset; + file_offset += 2; + + return (buf[0]<<8)+(buf[1]<<0); +} + +static unsigned int getlong(FILE *inf) +{ + unsigned char * buf; + + buf = file_data + file_offset; + file_offset += 4; + + return (buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+(buf[3]<<0); +} + +static void putshort(FILE *outf, unsigned short val) +{ + unsigned char buf[2]; + + buf[0] = (val>>8); + buf[1] = (val>>0); + fwrite(buf,2,1,outf); +} + +static int putlong(FILE *outf, unsigned int val) +{ + unsigned char buf[4]; + + buf[0] = (val>>24); + buf[1] = (val>>16); + buf[2] = (val>>8); + buf[3] = (val>>0); + return fwrite(buf,4,1,outf); +} + +static void readheader(FILE *inf, IMAGE *image) +{ + memset(image, 0, sizeof(IMAGE)); + image->imagic = getshort(inf); + image->type = getshort(inf); + image->dim = getshort(inf); + image->xsize = getshort(inf); + image->ysize = getshort(inf); + image->zsize = getshort(inf); +} + +static int writeheader(FILE *outf, IMAGE *image) +{ + IMAGE t; + + memset(&t, 0, sizeof(IMAGE)); + fwrite(&t,sizeof(IMAGE),1,outf); + fseek(outf,0,SEEK_SET); + putshort(outf,image->imagic); + putshort(outf,image->type); + putshort(outf,image->dim); + putshort(outf,image->xsize); + putshort(outf,image->ysize); + putshort(outf,image->zsize); + putlong(outf,image->min); + putlong(outf,image->max); + putlong(outf,0); + return fwrite("no name",8,1,outf); +} + +static int writetab(FILE *outf, unsigned int *tab, int len) +{ + int r = 0; + + while(len) { + r = putlong(outf,*tab++); + len -= 4; + } + return r; +} + +static void readtab(FILE *inf, unsigned int *tab, int len) +{ + while(len) { + *tab++ = getlong(inf); + len -= 4; + } +} + +static void test_endian_zbuf(struct ImBuf *ibuf) +{ + int len; + int *zval; + + if( BIG_LONG(1) == 1 ) return; + if(ibuf->zbuf==0) return; + + len= ibuf->x*ibuf->y; + zval= ibuf->zbuf; + + while(len--) { + zval[0]= BIG_LONG(zval[0]); + zval++; + } +} + + +/* + * longimagedata - + * read in a B/W RGB or RGBA iris image file and return a + * pointer to an array of ints. + * + */ + +struct ImBuf *imb_loadiris(unsigned char *mem, int flags) +{ + unsigned int *base, *lptr = NULL; + unsigned int *zbase, *zptr; + unsigned char *rledat; + unsigned int *starttab, *lengthtab; + FILE *inf = NULL; + IMAGE image; + int x, y, z, tablen; + int xsize, ysize, zsize; + int bpp, rle, cur, badorder; + ImBuf * ibuf; + uchar * rect; + + /*printf("new iris\n");*/ + + file_data = mem; + file_offset = 0; + + readheader(inf, &image); + if(image.imagic != IMAGIC) { + fprintf(stderr,"longimagedata: bad magic number in image file\n"); + return(0); + } + + rle = ISRLE(image.type); + bpp = BPP(image.type); + if(bpp != 1 ) { + fprintf(stderr,"longimagedata: image must have 1 byte per pix chan\n"); + return(0); + } + + xsize = image.xsize; + ysize = image.ysize; + zsize = image.zsize; + + if (flags & IB_test) { + ibuf = IMB_allocImBuf(image.xsize, image.ysize, 8 * image.zsize, 0, 0); + if (ibuf) ibuf->ftype = IMAGIC; + return(ibuf); + } + + if (rle) { + tablen = ysize*zsize*sizeof(int); + starttab = (unsigned int *)malloc(tablen); + lengthtab = (unsigned int *)malloc(tablen); + file_offset = 512; + + readtab(inf,starttab,tablen); + readtab(inf,lengthtab,tablen); + + /* check data order */ + cur = 0; + badorder = 0; + for (y = 0; ydepth > 32) ibuf->depth = 32; + base = ibuf->rect; + zbase = (unsigned int *)ibuf->zbuf; + + if (badorder) { + for(z=0; zdepth > 32) ibuf->depth = 32; + + base = ibuf->rect; + zbase = (unsigned int *)ibuf->zbuf; + + file_offset = 512; + rledat = file_data + file_offset; + + for(z = 0; z < zsize; z++) { + + if(z<4) lptr = base; + else if(z<8) lptr= zbase; + + for(y = 0; y < ysize; y++) { + + interleaverow((uchar *)lptr, rledat, 3-z, xsize); + rledat += xsize; + + lptr += xsize; + } + } + } + + if (image.zsize == 1){ + rect = (uchar *) ibuf->rect; + for (x = ibuf->x * ibuf->y; x > 0; x--) { + rect[0] = 255; + rect[1] = rect[2] = rect[3]; + rect += 4; + } + } else if (image.zsize == 2){ + /* grayscale with alpha */ + rect = (uchar *) ibuf->rect; + for (x = ibuf->x * ibuf->y; x > 0; x--) { + rect[0] = rect[2]; + rect[1] = rect[2] = rect[3]; + rect += 4; + } + } else if (image.zsize == 3){ + /* add alpha */ + rect = (uchar *) ibuf->rect; + for (x = ibuf->x * ibuf->y; x > 0; x--) { + rect[0] = 255; + rect += 4; + } + } + + ibuf->ftype = IMAGIC; + if (flags & IB_ttob) IMB_flipy(ibuf); + + test_endian_zbuf(ibuf); + + if (ibuf) { + if (ibuf->rect) + IMB_convert_rgba_to_abgr(ibuf); + } + + return(ibuf); +} + +/* static utility functions for longimagedata */ + +static void interleaverow(unsigned char *lptr, unsigned char *cptr, int z, int n) +{ + lptr += z; + while(n--) { + *lptr = *cptr++; + lptr += 4; + } +} + +static void expandrow(unsigned char *optr, unsigned char *iptr, int z) +{ + unsigned char pixel, count; + + optr += z; + while(1) { + pixel = *iptr++; + if ( !(count = (pixel & 0x7f)) ) + return; + if(pixel & 0x80) { + while(count>=8) { + optr[0*4] = iptr[0]; + optr[1*4] = iptr[1]; + optr[2*4] = iptr[2]; + optr[3*4] = iptr[3]; + optr[4*4] = iptr[4]; + optr[5*4] = iptr[5]; + optr[6*4] = iptr[6]; + optr[7*4] = iptr[7]; + optr += 8*4; + iptr += 8; + count -= 8; + } + while(count--) { + *optr = *iptr++; + optr+=4; + } + } else { + pixel = *iptr++; + while(count>=8) { + optr[0*4] = pixel; + optr[1*4] = pixel; + optr[2*4] = pixel; + optr[3*4] = pixel; + optr[4*4] = pixel; + optr[5*4] = pixel; + optr[6*4] = pixel; + optr[7*4] = pixel; + optr += 8*4; + count -= 8; + } + while(count--) { + *optr = pixel; + optr+=4; + } + } + } +} + +/* + * output_iris - + * copy an array of ints to an iris image file. Each int + * represents one pixel. xsize and ysize specify the dimensions of + * the pixel array. zsize specifies what kind of image file to + * write out. if zsize is 1, the luminance of the pixels are + * calculated, and a sinlge channel black and white image is saved. + * If zsize is 3, an RGB image file is saved. If zsize is 4, an + * RGBA image file is saved. + * + * Added: zbuf write + */ + +static int output_iris(unsigned int *lptr, int xsize, int ysize, int zsize, char *name, int *zptr) +{ + FILE *outf; + IMAGE *image; + int tablen, y, z, pos, len = 0; + unsigned int *starttab, *lengthtab; + unsigned char *rlebuf; + unsigned int *lumbuf; + int rlebuflen, goodwrite; + + goodwrite = 1; + outf = fopen(name, "wb"); + if(!outf) return 0; + + tablen = ysize*zsize*sizeof(int); + + image = (IMAGE *)malloc(sizeof(IMAGE)); + starttab = (unsigned int *)malloc(tablen); + lengthtab = (unsigned int *)malloc(tablen); + rlebuflen = 1.05*xsize+10; + rlebuf = (unsigned char *)malloc(rlebuflen); + lumbuf = (unsigned int *)malloc(xsize*sizeof(int)); + + memset(image, 0, sizeof(IMAGE)); + image->imagic = IMAGIC; + image->type = RLE(1); + if(zsize>1) + image->dim = 3; + else + image->dim = 2; + image->xsize = xsize; + image->ysize = ysize; + image->zsize = zsize; + image->min = 0; + image->max = 255; + goodwrite *= writeheader(outf,image); + fseek(outf,512+2*tablen,SEEK_SET); + pos = 512+2*tablen; + + for (y = 0; y < ysize; y++) { + for (z = 0; z < zsize; z++) { + + if (zsize == 1) { + lumrow((uchar *)lptr,(uchar *)lumbuf,xsize); + len = compressrow((uchar *)lumbuf,rlebuf,CHANOFFSET(z),xsize); + } + else { + if(z<4) { + len = compressrow((uchar *)lptr, rlebuf,CHANOFFSET(z),xsize); + } + else if(z<8 && zptr) { + len = compressrow((uchar *)zptr, rlebuf,CHANOFFSET(z-4),xsize); + } + } + if(len>rlebuflen) { + fprintf(stderr,"output_iris: rlebuf is too small - bad poop\n"); + exit(1); + } + goodwrite *= fwrite(rlebuf, len, 1, outf); + starttab[y+z*ysize] = pos; + lengthtab[y+z*ysize] = len; + pos += len; + } + lptr += xsize; + if(zptr) zptr += xsize; + } + + fseek(outf,512,SEEK_SET); + goodwrite *= writetab(outf,starttab,tablen); + goodwrite *= writetab(outf,lengthtab,tablen); + free(image); + free(starttab); + free(lengthtab); + free(rlebuf); + free(lumbuf); + fclose(outf); + if(goodwrite) + return 1; + else { + fprintf(stderr,"output_iris: not enough space for image!!\n"); + return 0; + } +} + +/* static utility functions for output_iris */ + +static void lumrow(unsigned char *rgbptr, unsigned char *lumptr, int n) +{ + lumptr += CHANOFFSET(0); + while(n--) { + *lumptr = ILUM(rgbptr[OFFSET_R],rgbptr[OFFSET_G],rgbptr[OFFSET_B]); + lumptr += 4; + rgbptr += 4; + } +} + +static int compressrow(unsigned char *lbuf, unsigned char *rlebuf, int z, int cnt) +{ + unsigned char *iptr, *ibufend, *sptr, *optr; + short todo, cc; + int count; + + lbuf += z; + iptr = lbuf; + ibufend = iptr+cnt*4; + optr = rlebuf; + + while(iptr126 ? 126:count; + count -= todo; + *optr++ = 0x80|todo; + while(todo>8) { + optr[0] = sptr[0*4]; + optr[1] = sptr[1*4]; + optr[2] = sptr[2*4]; + optr[3] = sptr[3*4]; + optr[4] = sptr[4*4]; + optr[5] = sptr[5*4]; + optr[6] = sptr[6*4]; + optr[7] = sptr[7*4]; + + optr += 8; + sptr += 8*4; + todo -= 8; + } + while(todo--) { + *optr++ = *sptr; + sptr += 4; + } + } + sptr = iptr; + cc = *iptr; + iptr += 4; + while( (iptr126 ? 126:count; + count -= todo; + *optr++ = todo; + *optr++ = cc; + } + } + *optr++ = 0; + return optr - (unsigned char *)rlebuf; +} + +short imb_saveiris(struct ImBuf * ibuf, char *name, int flags) +{ + short zsize; + int ret; + + zsize = (ibuf->depth + 7) >> 3; + if (flags & IB_zbuf && ibuf->zbuf != 0) zsize = 8; + + IMB_convert_rgba_to_abgr(ibuf); + test_endian_zbuf(ibuf); + + ret = output_iris(ibuf->rect, ibuf->x, ibuf->y, zsize, name, ibuf->zbuf); + + /* restore! Quite clumsy, 2 times a switch... maybe better a malloc ? */ + IMB_convert_rgba_to_abgr(ibuf); + test_endian_zbuf(ibuf); + + return(ret); +} + diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c new file mode 100644 index 00000000000..1774aa7c156 --- /dev/null +++ b/source/blender/imbuf/intern/jpeg.c @@ -0,0 +1,620 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * jpeg.c + * + * $Id$ + */ + + +/* This little block needed for linking to Blender... */ +#include +#include "BLI_blenlib.h" + +#include "imbuf.h" +#include "imbuf_patch.h" +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" +#include "IMB_jpeg.h" +#include "jpeglib.h" + +/* the types are from the jpeg lib */ +static void jpeg_error (j_common_ptr cinfo); +static void init_source(j_decompress_ptr cinfo); +static boolean fill_input_buffer(j_decompress_ptr cinfo); +static void skip_input_data(j_decompress_ptr cinfo, long num_bytes); +static void term_source(j_decompress_ptr cinfo); +static void memory_source(j_decompress_ptr cinfo, unsigned char *buffer, int size); +static boolean handle_app1 (j_decompress_ptr cinfo); +static ImBuf * ibJpegImageFromCinfo(struct jpeg_decompress_struct * cinfo, int flags); + + +/* + * In principle there are 4 jpeg formats. + * + * 1. jpeg - standard printing, u & v at quarter of resulution + * 2. jvid - standaard video, u & v half resolution, frame not interlaced + +type 3 is unsupported as of jul 05 2000 Frank. + + * 3. jstr - as 2, but written in 2 seperate fields + + * 4. jmax - no scaling in the components + */ + +static int jpeg_failed = FALSE; +static int jpeg_default_quality; +static int ibuf_ftype; + +int imb_is_a_jpeg(unsigned char *mem) { + + if ((mem[0]== 0xFF) && (mem[1] == 0xD8))return 1; + return 0; +} + +static void jpeg_error (j_common_ptr cinfo) +{ + /* Always display the message */ + (*cinfo->err->output_message) (cinfo); + + /* Let the memory manager delete any temp files before we die */ + jpeg_destroy(cinfo); + + jpeg_failed = TRUE; +} + +//---------------------------------------------------------- +// INPUT HANDLER FROM MEMORY +//---------------------------------------------------------- + +typedef struct { + unsigned char *buffer; + int filled; +} buffer_struct; + +typedef struct { + struct jpeg_source_mgr pub; /* public fields */ + + unsigned char *buffer; + int size; + JOCTET terminal[2]; +} my_source_mgr; + +typedef my_source_mgr * my_src_ptr; + +static void init_source(j_decompress_ptr cinfo) +{ +} + + +static boolean fill_input_buffer(j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* Since we have given all we have got already + * we simply fake an end of file + */ + + src->pub.next_input_byte = src->terminal; + src->pub.bytes_in_buffer = 2; + src->terminal[0] = (JOCTET) 0xFF; + src->terminal[1] = (JOCTET) JPEG_EOI; + + return TRUE; +} + + +static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + src->pub.next_input_byte = src->pub.next_input_byte + num_bytes; +} + + +static void term_source(j_decompress_ptr cinfo) +{ +} + +static void memory_source(j_decompress_ptr cinfo, unsigned char *buffer, int size) +{ + my_src_ptr src; + + if (cinfo->src == NULL) + { /* first time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *)(*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(my_source_mgr)); + } + + src = (my_src_ptr) cinfo->src; + src->pub.init_source = init_source; + src->pub.fill_input_buffer = fill_input_buffer; + src->pub.skip_input_data = skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; + src->pub.term_source = term_source; + + src->pub.bytes_in_buffer = size; + src->pub.next_input_byte = buffer; + + src->buffer = buffer; + src->size = size; +} + + +#define MAKESTMT(stuff) do { stuff } while (0) + +#define INPUT_VARS(cinfo) \ + struct jpeg_source_mgr * datasrc = (cinfo)->src; \ + const JOCTET * next_input_byte = datasrc->next_input_byte; \ + size_t bytes_in_buffer = datasrc->bytes_in_buffer + +/* Unload the local copies --- do this only at a restart boundary */ +#define INPUT_SYNC(cinfo) \ + ( datasrc->next_input_byte = next_input_byte, \ + datasrc->bytes_in_buffer = bytes_in_buffer ) + +/* Reload the local copies --- seldom used except in MAKE_BYTE_AVAIL */ +#define INPUT_RELOAD(cinfo) \ + ( next_input_byte = datasrc->next_input_byte, \ + bytes_in_buffer = datasrc->bytes_in_buffer ) + +/* Internal macro for INPUT_BYTE and INPUT_2BYTES: make a byte available. + * Note we do *not* do INPUT_SYNC before calling fill_input_buffer, + * but we must reload the local copies after a successful fill. + */ +#define MAKE_BYTE_AVAIL(cinfo,action) \ + if (bytes_in_buffer == 0) { \ + if (! (*datasrc->fill_input_buffer) (cinfo)) \ + { action; } \ + INPUT_RELOAD(cinfo); \ + } \ + bytes_in_buffer-- + +/* Read a byte into variable V. + * If must suspend, take the specified action (typically "return FALSE"). + */ +#define INPUT_BYTE(cinfo,V,action) \ + MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \ + V = GETJOCTET(*next_input_byte++); ) + +/* As above, but read two bytes interpreted as an unsigned 16-bit integer. + * V should be declared unsigned int or perhaps INT32. + */ +#define INPUT_2BYTES(cinfo,V,action) \ + MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \ + V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \ + MAKE_BYTE_AVAIL(cinfo,action); \ + V += GETJOCTET(*next_input_byte++); ) + + +static boolean +handle_app1 (j_decompress_ptr cinfo) +{ + INT32 length, i; + char neogeo[128]; + + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + if (length < 16) { + for (i = 0; i < length; i++) INPUT_BYTE(cinfo, neogeo[i], return FALSE); + length = 0; + if (strncmp(neogeo, "NeoGeo", 6) == 0) memcpy(&ibuf_ftype, neogeo + 6, 4); + ibuf_ftype = BIG_LONG(ibuf_ftype); + } + INPUT_SYNC(cinfo); /* do before skip_input_data */ + if (length > 0) (*cinfo->src->skip_input_data) (cinfo, length); + return TRUE; +} + + +static ImBuf * ibJpegImageFromCinfo(struct jpeg_decompress_struct * cinfo, int flags) +{ + JSAMPARRAY row_pointer; + JSAMPLE * buffer = 0; + int row_stride; + int x, y, depth, r, g, b, k; + struct ImBuf * ibuf = 0; + uchar * rect; + + /* install own app1 handler */ + ibuf_ftype = 0; + jpeg_set_marker_processor(cinfo, 0xe1, handle_app1); + cinfo->dct_method = JDCT_FLOAT; + + if (jpeg_read_header(cinfo, FALSE) == JPEG_HEADER_OK) { + x = cinfo->image_width; + y = cinfo->image_height; + depth = cinfo->num_components; + + if (cinfo->jpeg_color_space == JCS_YCCK) cinfo->out_color_space = JCS_CMYK; + + jpeg_start_decompress(cinfo); + + if (ibuf_ftype == 0) { + ibuf_ftype = JPG_STD; + if (cinfo->max_v_samp_factor == 1) { + if (cinfo->max_h_samp_factor == 1) ibuf_ftype = JPG_MAX; + else ibuf_ftype = JPG_VID; + } + } + + if (flags & IB_test) { + jpeg_abort_decompress(cinfo); + ibuf = IMB_allocImBuf(x, y, 8 * depth, 0, 0); + } else { + ibuf = IMB_allocImBuf(x, y, 8 * depth, IB_rect, 0); + + row_stride = cinfo->output_width * depth; + + row_pointer = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo, JPOOL_IMAGE, row_stride, 1); + + for (y = ibuf->y - 1; y >= 0; y--) { + jpeg_read_scanlines(cinfo, row_pointer, 1); + if (flags & IB_ttob) { + rect = (uchar *) (ibuf->rect + (ibuf->y - 1 - y) * ibuf->x); + } else { + rect = (uchar *) (ibuf->rect + y * ibuf->x); + } + buffer = row_pointer[0]; + + switch(depth) { + case 1: + for (x=ibuf->x; x >0; x--) { + rect[3] = 255; + rect[0] = rect[1] = rect[2] = *buffer++; + rect += 4; + } + break; + case 3: + for (x=ibuf->x; x >0; x--) { + rect[3] = 255; + rect[0] = *buffer++; + rect[1] = *buffer++; + rect[2] = *buffer++; + rect += 4; + } + break; + case 4: + for (x=ibuf->x; x >0; x--) { + r = *buffer++; + g = *buffer++; + b = *buffer++; + k = *buffer++; + + k = 255 - k; + r -= k; + if (r & 0xffffff00) { + if (r < 0) r = 0; + else r = 255; + } + g -= k; + if (g & 0xffffff00) { + if (g < 0) g = 0; + else g = 255; + } + b -= k; + if (b & 0xffffff00) { + if (b < 0) b = 0; + else b = 255; + } + + rect[3] = 255 - k; + rect[2] = b; + rect[1] = g; + rect[0] = r; + rect += 4; + } + } + } + jpeg_finish_decompress(cinfo); + } + + jpeg_destroy((j_common_ptr) cinfo); + ibuf->ftype = ibuf_ftype; + } + + return(ibuf); +} + +ImBuf * imb_ibJpegImageFromFilename (const char * filename, int flags) +{ + struct jpeg_decompress_struct _cinfo, *cinfo = &_cinfo; + struct jpeg_error_mgr jerr; + FILE * infile; + ImBuf * ibuf; + + if ((infile = fopen(filename, "rb")) == NULL) return 0; + + cinfo->err = jpeg_std_error(&jerr); + jerr.error_exit = jpeg_error; + + jpeg_create_decompress(cinfo); + jpeg_stdio_src(cinfo, infile); + + ibuf = ibJpegImageFromCinfo(cinfo, flags); + + fclose(infile); + return(ibuf); +} + +ImBuf * imb_ibJpegImageFromMemory (unsigned char * buffer, int size, int flags) +{ + struct jpeg_decompress_struct _cinfo, *cinfo = &_cinfo; + struct jpeg_error_mgr jerr; + ImBuf * ibuf; + + cinfo->err = jpeg_std_error(&jerr); + jerr.error_exit = jpeg_error; + + jpeg_create_decompress(cinfo); + memory_source(cinfo, buffer, size); + + ibuf = ibJpegImageFromCinfo(cinfo, flags); + + return(ibuf); +} + + +static void write_jpeg(struct jpeg_compress_struct * cinfo, struct ImBuf * ibuf) +{ + JSAMPLE * buffer = 0; + JSAMPROW row_pointer[1]; + uchar * rect; + int x, y; + char neogeo[128]; + + + jpeg_start_compress(cinfo, TRUE); + + strcpy(neogeo, "NeoGeo"); + ibuf_ftype = BIG_LONG(ibuf->ftype); + + memcpy(neogeo + 6, &ibuf_ftype, 4); + jpeg_write_marker(cinfo, 0xe1, (JOCTET*) neogeo, 10); + + row_pointer[0] = + mallocstruct(JSAMPLE, + cinfo->input_components * + cinfo->image_width); + + for(y = ibuf->y - 1; y >= 0; y--){ + rect = (uchar *) (ibuf->rect + y * ibuf->x); + buffer = row_pointer[0]; + + switch(cinfo->in_color_space){ + case JCS_RGB: + for (x = 0; x < ibuf->x; x++) { + *buffer++ = rect[0]; + *buffer++ = rect[1]; + *buffer++ = rect[2]; + rect += 4; + } + break; + case JCS_GRAYSCALE: + for (x = 0; x < ibuf->x; x++) { + *buffer++ = rect[0]; + rect += 4; + } + break; + case JCS_UNKNOWN: + memcpy(buffer, rect, 4 * ibuf->x); + break; + /* default was missing... intentional ? */ + default: + ; /* do nothing */ + } + + jpeg_write_scanlines(cinfo, row_pointer, 1); + + if (jpeg_failed) break; + } + + if (jpeg_failed == FALSE) jpeg_finish_compress(cinfo); + free(row_pointer[0]); +} + + +static int init_jpeg(FILE * outfile, struct jpeg_compress_struct * cinfo, struct ImBuf *ibuf) +{ + int quality; + + quality = ibuf->ftype & 0xff; + if (quality <= 0) quality = jpeg_default_quality; + if (quality > 100) quality = 100; + + jpeg_create_compress(cinfo); + jpeg_stdio_dest(cinfo, outfile); + + cinfo->image_width = ibuf->x; + cinfo->image_height = ibuf->y; + + cinfo->in_color_space = JCS_RGB; + if (ibuf->depth == 8 && ibuf->cmap == 0) cinfo->in_color_space = JCS_GRAYSCALE; + if (ibuf->depth == 32) cinfo->in_color_space = JCS_UNKNOWN; + + switch(cinfo->in_color_space){ + case JCS_RGB: + cinfo->input_components = 3; + break; + case JCS_GRAYSCALE: + cinfo->input_components = 1; + break; + case JCS_UNKNOWN: + cinfo->input_components = 4; + break; + /* default was missing... intentional ? */ + default: + ; /* do nothing */ + } + jpeg_set_defaults(cinfo); + + /* own settings */ + + cinfo->dct_method = JDCT_FLOAT; + jpeg_set_quality(cinfo, quality, TRUE); + + return(0); +} + + +static int save_stdjpeg(char * name, struct ImBuf * ibuf) +{ + FILE * outfile; + struct jpeg_compress_struct _cinfo, *cinfo = &_cinfo; + struct jpeg_error_mgr jerr; + + if ((outfile = fopen(name, "wb")) == NULL) return 0; + jpeg_default_quality = 75; + + cinfo->err = jpeg_std_error(&jerr); + jerr.error_exit = jpeg_error; + + init_jpeg(outfile, cinfo, ibuf); + + write_jpeg(cinfo, ibuf); + + fclose(outfile); + jpeg_destroy_compress(cinfo); + + if (jpeg_failed) { + remove(name); + return 0; + } + return 1; +} + + +static int save_vidjpeg(char * name, struct ImBuf * ibuf) +{ + FILE * outfile; + struct jpeg_compress_struct _cinfo, *cinfo = &_cinfo; + struct jpeg_error_mgr jerr; + + if ((outfile = fopen(name, "wb")) == NULL) return 0; + jpeg_default_quality = 90; + + cinfo->err = jpeg_std_error(&jerr); + jerr.error_exit = jpeg_error; + + init_jpeg(outfile, cinfo, ibuf); + + /* adjust scaling factors */ + if (cinfo->in_color_space == JCS_RGB) { + cinfo->comp_info[0].h_samp_factor = 2; + cinfo->comp_info[0].v_samp_factor = 1; + } + + write_jpeg(cinfo, ibuf); + + fclose(outfile); + jpeg_destroy_compress(cinfo); + + if (jpeg_failed) { + remove(name); + return 0; + } + return 1; +} + +static int save_jstjpeg(char * name, struct ImBuf * ibuf) +{ + char fieldname[1024]; + struct ImBuf * tbuf; + int oldy, returnval; + + tbuf = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 24, IB_rect, 0); + tbuf->ftype = ibuf->ftype; + tbuf->flags = ibuf->flags; + + oldy = ibuf->y; + ibuf->x *= 2; + ibuf->y /= 2; + + IMB_rectcpy(tbuf, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y); + sprintf(fieldname, "%s.jf0", name); + + returnval = save_vidjpeg(fieldname, tbuf) ; + if (returnval == 1) { + IMB_rectcpy(tbuf, ibuf, 0, 0, tbuf->x, 0, ibuf->x, ibuf->y); + sprintf(fieldname, "%s.jf1", name); + returnval = save_vidjpeg(fieldname, tbuf); + } + + ibuf->y = oldy; + ibuf->x /= 2; + IMB_freeImBuf(tbuf); + + return returnval; +} + +static int save_maxjpeg(char * name, struct ImBuf * ibuf) +{ + FILE * outfile; + struct jpeg_compress_struct _cinfo, *cinfo = &_cinfo; + struct jpeg_error_mgr jerr; + + if ((outfile = fopen(name, "wb")) == NULL) return 0; + jpeg_default_quality = 100; + + cinfo->err = jpeg_std_error(&jerr); + jerr.error_exit = jpeg_error; + + init_jpeg(outfile, cinfo, ibuf); + + /* adjust scaling factors */ + if (cinfo->in_color_space == JCS_RGB) { + cinfo->comp_info[0].h_samp_factor = 1; + cinfo->comp_info[0].v_samp_factor = 1; + } + + write_jpeg(cinfo, ibuf); + + fclose(outfile); + jpeg_destroy_compress(cinfo); + + if (jpeg_failed) { + remove(name); + return 0; + } + return 1; +} + +int imb_savejpeg(struct ImBuf * ibuf, char * name, int flags) +{ + + ibuf->flags = flags; + if (IS_stdjpg(ibuf)) return save_stdjpeg(name, ibuf); + if (IS_jstjpg(ibuf)) return save_jstjpeg(name, ibuf); + if (IS_maxjpg(ibuf)) return save_maxjpeg(name, ibuf); + return save_vidjpeg(name, ibuf); +} + diff --git a/source/blender/imbuf/intern/matrix.h b/source/blender/imbuf/intern/matrix.h new file mode 100644 index 00000000000..e062ee38f8f --- /dev/null +++ b/source/blender/imbuf/intern/matrix.h @@ -0,0 +1,87 @@ +/** + * matrix.c + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* rgbyuv is identiek aan rgbbeta */ + +float rgbyuv[4][4]={ /* afgeleid uit videoframer = Y Cr Cb in kopieen van Francois*/ + /* is identriek aan matrix van jpeg */ + { .50000, .11400, -.08131, 0.0,}, /* b */ + {-.33126, .58700, -.41869, 0.0,}, /* g */ + {-.16874, .29900, .50000, 0.0,}, /* r */ + { 128.0, 0.0, 128.0, 1.0}}; + + /* b-y (u) y r-y (v) */ + + +float rgbbeta[4][4]={ /* afgeleid uit videoframer = Y Cr Cb in kopieen van Francois*/ + /* is identriek aan matrix van jpeg */ + {.50000, .11400, -.08131, 0.0,}, /* b-y -> b */ + {-.33126, .58700, -.41869, 0.0,}, /* y -> g */ + {-.16874, .29900, .50000, 0.0,}, /* r-y -> r */ + { 128.0, 0.0, 128.0, 1.0}}; + + /* b-y y r-y */ + + + +float yuvrgb[4][4]={ + {1.77200, -0.34414, 0.0, 0.0, }, + {1.0, 1.0, 1.0, 0.0, }, + {0.0, -0.71414, 1.40200, 0.0, }, + {-226.816, 135.460, -179.456, 1.0}}; + +float rgb_to_bw[4][4]={ + {.299, .299, .299, 0.0,}, + {.587, .587, .587, 0.0,}, + {.114, .114, .114, 0.0,}, + { 0.5, 0.5, 0.5, 1.0}}; + +float dyuvrgb_oud[4][4]={ + {1.0 , 1.0 , 1.0, 0.0,}, + {1.733, -0.337, 0.0, 0.0,}, + {0.0, -.698, 1.371, 0.0,}, + {-221.8, 132.47, -175.5, 1.0}}; + +float dyuvrgb[4][4]={ + {1.164 , 1.164 , 1.164, 0.0,}, + {2.018, -0.391, 0.0, 0.0,}, + {0.0, -0.813, 1.596, 0.0,}, + {-276.7, 135.6, -222.7, 1.0}}; + +float rgbdyuv[4][4]={ + {0.439, 0.098, -0.071, 0.0,}, + {-0.291, 0.504, -0.368, 0.0,}, + {-0.148, 0.257, 0.439, 0.0,}, + {128.0, 16.0, 128.0, 1.0}}; + diff --git a/source/blender/imbuf/intern/md5.c b/source/blender/imbuf/intern/md5.c new file mode 100644 index 00000000000..a3165467b53 --- /dev/null +++ b/source/blender/imbuf/intern/md5.c @@ -0,0 +1,361 @@ +/* md5.c - Functions to compute MD5 message digest of files or memory blocks + according to the definition of MD5 in RFC 1321 from April 1992. + Copyright (C) 1995 Software Foundation, Inc. + + 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Written by Ulrich Drepper . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +# include +# include + +#include "md5.h" + +#ifdef WORDS_BIGENDIAN +# define SWAP(n) \ + (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) +#else +# define SWAP(n) (n) +#endif + + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. (RFC 1321, 3.1: Step 1) */ +static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +void +md5_init_ctx (ctx) + struct md5_ctx *ctx; +{ + ctx->A = 0x67452301; + ctx->B = 0xefcdab89; + ctx->C = 0x98badcfe; + ctx->D = 0x10325476; +} + +/* Put result from CTX in first 16 bytes following RESBUF. The result must + be in little endian byte order. */ +void * +md5_read_ctx (ctx, resbuf) + const struct md5_ctx *ctx; + void *resbuf; +{ + ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A); + ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B); + ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C); + ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D); + + return resbuf; +} + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +int +md5_stream (stream, resblock) + FILE *stream; + void *resblock; +{ + /* Important: BLOCKSIZE must be a multiple of 64. */ +#define BLOCKSIZE 4096 + struct md5_ctx ctx; + md5_uint32 len[2]; + char buffer[BLOCKSIZE + 72]; + size_t pad, sum; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + len[0] = 0; + len[1] = 0; + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + do + { + n = fread (buffer, 1, BLOCKSIZE - sum, stream); + + sum += n; + } + while (sum < BLOCKSIZE && n != 0); + if (n == 0 && ferror (stream)) + return 1; + + /* RFC 1321 specifies the possible length of the file up to 2^64 bits. + Here we only compute the number of bytes. Do a double word + increment. */ + len[0] += sum; + if (len[0] < sum) + ++len[1]; + + /* If end of file is reached, end the loop. */ + if (n == 0) + break; + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + md5_process_block (buffer, BLOCKSIZE, &ctx); + } + + /* We can copy 64 byte because the buffer is always big enough. FILLBUF + contains the needed bits. */ + memcpy (&buffer[sum], fillbuf, 64); + + /* Compute amount of padding bytes needed. Alignment is done to + (N + PAD) % 64 == 56 + There is always at least one byte padded. I.e. even the alignment + is correctly aligned 64 padding bytes are added. */ + pad = sum & 63; + pad = pad >= 56 ? 64 + 56 - pad : 56 - pad; + + /* Put the 64-bit file length in *bits* at the end of the buffer. */ + *(md5_uint32 *) &buffer[sum + pad] = SWAP (len[0] << 3); + *(md5_uint32 *) &buffer[sum + pad + 4] = SWAP ((len[1] << 3) + | (len[0] >> 29)); + + /* Process last bytes. */ + md5_process_block (buffer, sum + pad + 8, &ctx); + + /* Construct result in desired memory. */ + md5_read_ctx (&ctx, resblock); + return 0; +} + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void * +md5_buffer (buffer, len, resblock) + const char *buffer; + size_t len; + void *resblock; +{ + struct md5_ctx ctx; + char restbuf[64 + 72]; + size_t blocks = len & ~63; + size_t pad, rest; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + md5_process_block (buffer, blocks, &ctx); + + /* REST bytes are not processed yet. */ + rest = len - blocks; + /* Copy to own buffer. */ + memcpy (restbuf, &buffer[blocks], rest); + /* Append needed fill bytes at end of buffer. We can copy 64 byte + because the buffer is always big enough. */ + memcpy (&restbuf[rest], fillbuf, 64); + + /* PAD bytes are used for padding to correct alignment. Note that + always at least one byte is padded. */ + pad = rest >= 56 ? 64 + 56 - rest : 56 - rest; + + /* Put length of buffer in *bits* in last eight bytes. */ + *(md5_uint32 *) &restbuf[rest + pad] = (md5_uint32) SWAP (len << 3); + *(md5_uint32 *) &restbuf[rest + pad + 4] = (md5_uint32) SWAP (len >> 29); + + /* Process last bytes. */ + md5_process_block (restbuf, rest + pad + 8, &ctx); + + /* Put result in desired memory area. */ + return md5_read_ctx (&ctx, resblock); +} + + +/* These are the four functions used in the four steps of the MD5 algorithm + and defined in the RFC 1321. The first function is a little bit optimized + (as found in Colin Plumbs public domain implementation). */ +/* #define FF(b, c, d) ((b & c) | (~b & d)) */ +#define FF(b, c, d) (d ^ (b & (c ^ d))) +#define FG(b, c, d) FF (d, b, c) +#define FH(b, c, d) (b ^ c ^ d) +#define FI(b, c, d) (c ^ (b | ~d)) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. */ + +void +md5_process_block (buffer, len, ctx) + const void *buffer; + size_t len; + struct md5_ctx *ctx; +{ + md5_uint32 correct_words[16]; + const md5_uint32 *words = buffer; + size_t nwords = len / sizeof (md5_uint32); + const md5_uint32 *endp = words + nwords; + md5_uint32 A = ctx->A; + md5_uint32 B = ctx->B; + md5_uint32 C = ctx->C; + md5_uint32 D = ctx->D; + + /* Process all bytes in the buffer with 64 bytes in each round of + the loop. */ + while (words < endp) + { + md5_uint32 *cwp = correct_words; + md5_uint32 A_save = A; + md5_uint32 B_save = B; + md5_uint32 C_save = C; + md5_uint32 D_save = D; + + /* First round: using the given function, the context and a constant + the next context is computed. Because the algorithms processing + unit is a 32-bit word and it is determined to work on words in + little endian byte order we perhaps have to change the byte order + before the computation. To reduce the work for the next steps + we store the swapped words in the array CORRECT_WORDS. */ + +#define OP(a, b, c, d, s, T) \ + do \ + { \ + a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ + ++words; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + + /* It is unfortunate that C does not provide an operator for + cyclic rotation. Hope the C compiler is smart enough. */ +#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) + + /* Before we start, one word to the strange constants. + They are defined in RFC 1321 as + + T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 + */ + + /* Round 1. */ + OP (A, B, C, D, 7, 0xd76aa478); + OP (D, A, B, C, 12, 0xe8c7b756); + OP (C, D, A, B, 17, 0x242070db); + OP (B, C, D, A, 22, 0xc1bdceee); + OP (A, B, C, D, 7, 0xf57c0faf); + OP (D, A, B, C, 12, 0x4787c62a); + OP (C, D, A, B, 17, 0xa8304613); + OP (B, C, D, A, 22, 0xfd469501); + OP (A, B, C, D, 7, 0x698098d8); + OP (D, A, B, C, 12, 0x8b44f7af); + OP (C, D, A, B, 17, 0xffff5bb1); + OP (B, C, D, A, 22, 0x895cd7be); + OP (A, B, C, D, 7, 0x6b901122); + OP (D, A, B, C, 12, 0xfd987193); + OP (C, D, A, B, 17, 0xa679438e); + OP (B, C, D, A, 22, 0x49b40821); + + /* For the second to fourth round we have the possibly swapped words + in CORRECT_WORDS. Redefine the macro to take an additional first + argument specifying the function to use. */ +#undef OP +#define OP(f, a, b, c, d, k, s, T) \ + do \ + { \ + a += f (b, c, d) + correct_words[k] + T; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + + /* Round 2. */ + OP (FG, A, B, C, D, 1, 5, 0xf61e2562); + OP (FG, D, A, B, C, 6, 9, 0xc040b340); + OP (FG, C, D, A, B, 11, 14, 0x265e5a51); + OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); + OP (FG, A, B, C, D, 5, 5, 0xd62f105d); + OP (FG, D, A, B, C, 10, 9, 0x02441453); + OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); + OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); + OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); + OP (FG, D, A, B, C, 14, 9, 0xc33707d6); + OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); + OP (FG, B, C, D, A, 8, 20, 0x455a14ed); + OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); + OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); + OP (FG, C, D, A, B, 7, 14, 0x676f02d9); + OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); + + /* Round 3. */ + OP (FH, A, B, C, D, 5, 4, 0xfffa3942); + OP (FH, D, A, B, C, 8, 11, 0x8771f681); + OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); + OP (FH, B, C, D, A, 14, 23, 0xfde5380c); + OP (FH, A, B, C, D, 1, 4, 0xa4beea44); + OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); + OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); + OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); + OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); + OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); + OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); + OP (FH, B, C, D, A, 6, 23, 0x04881d05); + OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); + OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); + OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); + OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); + + /* Round 4. */ + OP (FI, A, B, C, D, 0, 6, 0xf4292244); + OP (FI, D, A, B, C, 7, 10, 0x432aff97); + OP (FI, C, D, A, B, 14, 15, 0xab9423a7); + OP (FI, B, C, D, A, 5, 21, 0xfc93a039); + OP (FI, A, B, C, D, 12, 6, 0x655b59c3); + OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); + OP (FI, C, D, A, B, 10, 15, 0xffeff47d); + OP (FI, B, C, D, A, 1, 21, 0x85845dd1); + OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); + OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); + OP (FI, C, D, A, B, 6, 15, 0xa3014314); + OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); + OP (FI, A, B, C, D, 4, 6, 0xf7537e82); + OP (FI, D, A, B, C, 11, 10, 0xbd3af235); + OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); + OP (FI, B, C, D, A, 9, 21, 0xeb86d391); + + /* Add the starting values of the context. */ + A += A_save; + B += B_save; + C += C_save; + D += D_save; + } + + /* Put checksum in context given as argument. */ + ctx->A = A; + ctx->B = B; + ctx->C = C; + ctx->D = D; +} + diff --git a/source/blender/imbuf/intern/md5.h b/source/blender/imbuf/intern/md5.h new file mode 100644 index 00000000000..8b0d946430e --- /dev/null +++ b/source/blender/imbuf/intern/md5.h @@ -0,0 +1,116 @@ +/* md5.h - Declaration of functions and data types used for MD5 sum + computing library functions. + Copyright (C) 1995 Free Software Foundation, Inc. + +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, 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. */ + +#ifndef _MD5_H +#define _MD5_H + +#include + +#if defined HAVE_LIMITS_H || _LIBC +# include +#endif + +/* The following contortions are an attempt to use the C preprocessor + to determine an unsigned integral type that is 32 bits wide. An + alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but + doing that would require that the configure script compile and *run* + the resulting executable. Locally running cross-compiled executables + is usually not possible. */ + +#if defined __STDC__ && __STDC__ +# define UINT_MAX_32_BITS 4294967295U +#else +# define UINT_MAX_32_BITS 0xFFFFFFFF +#endif + +/* If UINT_MAX isn't defined, assume it's a 32-bit type. + This should be valid for all systems GNU cares about because + that doesn't include 16-bit systems, and only modern systems + (that certainly have ) have 64+-bit integral types. */ + +#ifndef UINT_MAX +# define UINT_MAX UINT_MAX_32_BITS +#endif + +#if UINT_MAX == UINT_MAX_32_BITS + typedef unsigned int md5_uint32; +#else +# if USHRT_MAX == UINT_MAX_32_BITS + typedef unsigned short md5_uint32; +# else +# if ULONG_MAX == UINT_MAX_32_BITS + typedef unsigned long md5_uint32; +# else + /* The following line is intended to evoke an error. + Using #error is not portable enough. */ + "Cannot determine unsigned 32-bit data type." +# endif +# endif +#endif + +#undef __P +#if defined (__STDC__) && __STDC__ +#define __P(x) x +#else +#define __P(x) () +#endif + +/* Structure to save state of computation between the single steps. */ +struct md5_ctx +{ + md5_uint32 A; + md5_uint32 B; + md5_uint32 C; + md5_uint32 D; +}; + +/* + * The following three functions are build up the low level used in + * the functions `md5_stream' and `md5_buffer'. + */ + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +void md5_init_ctx __P ((struct md5_ctx *ctx)); + +/* Starting with the result of former calls of this function (or the + initialzation function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 64!!! */ +void md5_process_block __P ((const void *buffer, size_t len, + struct md5_ctx *ctx)); + +/* Put result from CTX in first 16 bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. */ +void *md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf)); + + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +int md5_stream __P ((FILE *stream, void *resblock)); + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void *md5_buffer __P ((const char *buffer, size_t len, void *resblock)); + +#endif + diff --git a/source/blender/imbuf/intern/openexr/CMakeLists.txt b/source/blender/imbuf/intern/openexr/CMakeLists.txt new file mode 100644 index 00000000000..cfe5b28b7e8 --- /dev/null +++ b/source/blender/imbuf/intern/openexr/CMakeLists.txt @@ -0,0 +1,45 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(SRC openexr_api.cpp) + +SET(INC + . + ../../../blenkernel + ../../ + .. + ../../../blenlib + intern/include + ../../../../../intern/guardedalloc + ../../../makesdna + ${OPENEXR_INC} +) + +BLENDERLIB(bf_openexr "${SRC}" "${INC}") +#env.BlenderLib ('bf_openexr', source_files, incs, defs, libtype=['core','player'], priority = [90, 200]) diff --git a/source/blender/imbuf/intern/openexr/Makefile b/source/blender/imbuf/intern/openexr/Makefile new file mode 100644 index 00000000000..a3b79c951dd --- /dev/null +++ b/source/blender/imbuf/intern/openexr/Makefile @@ -0,0 +1,48 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Gernot Ziegler +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = openexr +DIR = $(OCGDIR)/blender/imbuf/openexr + +include nan_compile.mk + +CFLAGS += $(LEVEL_1_C_WARNINGS) + +CPPFLAGS += -I../../../makesdna +CPPFLAGS += -I../../../blenkernel +CPPFLAGS += -I../../../blenlib +CPPFLAGS += -I../../../imbuf +CPPFLAGS += -I../../../imbuf/intern +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include +CPPFLAGS += $(NAN_OPENEXR_INC) +CPPFLAGS += -I. diff --git a/source/blender/imbuf/intern/openexr/SConscript b/source/blender/imbuf/intern/openexr/SConscript new file mode 100644 index 00000000000..1b0a0ed6110 --- /dev/null +++ b/source/blender/imbuf/intern/openexr/SConscript @@ -0,0 +1,18 @@ +#!/usr/bin/python +Import ('env') + +source_files = ['openexr_api.cpp'] + +incs = ['.', + '../../../blenkernel', + '../../', + '..', + '../../../blenlib', + 'intern/include', + '#/intern/guardedalloc', + '../../../makesdna'] +incs += Split(env['BF_OPENEXR_INC']) + +defs = [] + +env.BlenderLib ('bf_openexr', source_files, incs, defs, libtype=['core','player'], priority = [90, 200]) diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp new file mode 100644 index 00000000000..3cbada812b9 --- /dev/null +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -0,0 +1,967 @@ +/** +* + * ***** BEGIN GPLLICENSE BLOCK ***** + * + * 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. + * + * Copyright by Gernot Ziegler . + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Austin Benesh, Ton Roosendaal (float, half, speedup, cleanup...). + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include +#include +#include + + +#include + +extern "C" +{ + +// The following prevents a linking error in debug mode for MSVC using the libs in CVS +#if defined(WITH_OPENEXR) && defined(_WIN32) && defined(_DEBUG) && !defined(__MINGW32__) && !defined(__CYGWIN__) +_CRTIMP void __cdecl _invalid_parameter_noinfo(void) +{ +} +#endif + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" +#include "IMB_allocimbuf.h" + +#define WITH_OPENEXR +#include "openexr_multi.h" +} + +#include + +#if defined (_WIN32) && !defined(FREE_WINDOWS) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +using namespace Imf; +using namespace Imath; + +class Mem_IStream: public IStream +{ +public: + + Mem_IStream (unsigned char *exrbuf, int exrsize): + IStream("dummy"), _exrpos (0), _exrsize(exrsize) { _exrbuf = exrbuf; } + + virtual bool read (char c[], int n); + virtual Int64 tellg (); + virtual void seekg (Int64 pos); + virtual void clear (); + //virtual ~Mem_IStream() {}; // unused + +private: + + Int64 _exrpos; + Int64 _exrsize; + unsigned char *_exrbuf; +}; + +bool Mem_IStream::read (char c[], int n) +{ + if (n + _exrpos <= _exrsize) + { + memcpy(c, (void *)(&_exrbuf[_exrpos]), n); + _exrpos += n; + return true; + } + else + return false; +} + +Int64 Mem_IStream::tellg () +{ + return _exrpos; +} + +void Mem_IStream::seekg (Int64 pos) +{ + _exrpos = pos; +} + +void Mem_IStream::clear () +{ +} + +struct _RGBAZ +{ + half r; + half g; + half b; + half a; + half z; +}; + +typedef struct _RGBAZ RGBAZ; + +extern "C" +{ + +int imb_is_a_openexr(unsigned char *mem) +{ + return Imf::isImfMagic ((const char *)mem); +} + +static void openexr_header_compression(Header *header, int compression) +{ + switch(compression) + { + case 0: + header->compression() = NO_COMPRESSION; + break; + case 1: + header->compression() = PXR24_COMPRESSION; + break; + case 2: + header->compression() = ZIP_COMPRESSION; + break; + case 3: + header->compression() = PIZ_COMPRESSION; + break; + case 4: + header->compression() = RLE_COMPRESSION; + break; + default: + header->compression() = ZIP_COMPRESSION; + break; + } +} + +static short imb_save_openexr_half(struct ImBuf *ibuf, char *name, int flags) +{ + + int width = ibuf->x; + int height = ibuf->y; + int write_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; // summarize + + try + { + Header header (width, height); + + openexr_header_compression(&header, ibuf->ftype & OPENEXR_COMPRESS); + + header.channels().insert ("R", Channel (HALF)); + header.channels().insert ("G", Channel (HALF)); + header.channels().insert ("B", Channel (HALF)); + if (ibuf->depth==32) + header.channels().insert ("A", Channel (HALF)); + if (write_zbuf) // z we do as float always + header.channels().insert ("Z", Channel (FLOAT)); + + FrameBuffer frameBuffer; + OutputFile *file = new OutputFile(name, header); + + /* we store first everything in half array */ + RGBAZ *pixels = new RGBAZ[height * width]; + RGBAZ *to = pixels; + int xstride= sizeof (RGBAZ); + int ystride= xstride*width; + + /* indicate used buffers */ + frameBuffer.insert ("R", Slice (HALF, (char *) &pixels[0].r, xstride, ystride)); + frameBuffer.insert ("G", Slice (HALF, (char *) &pixels[0].g, xstride, ystride)); + frameBuffer.insert ("B", Slice (HALF, (char *) &pixels[0].b, xstride, ystride)); + if (ibuf->depth==32) + frameBuffer.insert ("A", Slice (HALF, (char *) &pixels[0].a, xstride, ystride)); + if (write_zbuf) + frameBuffer.insert ("Z", Slice (FLOAT, (char *) ibuf->zbuf_float + 4*(height-1)*width, + sizeof(float), sizeof(float) * -width)); + if(ibuf->rect_float) { + float *from; + + for (int i = ibuf->y-1; i >= 0; i--) + { + from= ibuf->rect_float + 4*i*width; + + for (int j = ibuf->x; j > 0; j--) + { + to->r = from[0]; + to->g = from[1]; + to->b = from[2]; + to->a = from[3]; + to++; from += 4; + } + } + } + else { + unsigned char *from; + + for (int i = ibuf->y-1; i >= 0; i--) + { + from= (unsigned char *)(ibuf->rect + i*width); + + for (int j = ibuf->x; j > 0; j--) + { + to->r = (float)(from[0])/255.0; + to->g = (float)(from[1])/255.0; + to->b = (float)(from[2])/255.0; + to->a = (float)(from[3])/255.0; + to++; from += 4; + } + } + } + +// printf("OpenEXR-save: Writing OpenEXR file of height %d.\n", height); + + file->setFrameBuffer (frameBuffer); + file->writePixels (height); + delete file; + delete [] pixels; + } + catch (const std::exception &exc) + { + printf("OpenEXR-save: ERROR: %s\n", exc.what()); + if (ibuf) IMB_freeImBuf(ibuf); + + return (0); + } + + return (1); +} + +static short imb_save_openexr_float(struct ImBuf *ibuf, char *name, int flags) +{ + + int width = ibuf->x; + int height = ibuf->y; + int write_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; // summarize + + try + { + Header header (width, height); + + openexr_header_compression(&header, ibuf->ftype & OPENEXR_COMPRESS); + + header.channels().insert ("R", Channel (FLOAT)); + header.channels().insert ("G", Channel (FLOAT)); + header.channels().insert ("B", Channel (FLOAT)); + if (ibuf->depth==32) + header.channels().insert ("A", Channel (FLOAT)); + if (write_zbuf) + header.channels().insert ("Z", Channel (FLOAT)); + + FrameBuffer frameBuffer; + OutputFile *file = new OutputFile(name, header); + float *first= ibuf->rect_float + 4*(height-1)*width; + int xstride = sizeof(float) * 4; + int ystride = - xstride*width; + + frameBuffer.insert ("R", Slice (FLOAT, (char *) first, xstride, ystride)); + frameBuffer.insert ("G", Slice (FLOAT, (char *) (first+1), xstride, ystride)); + frameBuffer.insert ("B", Slice (FLOAT, (char *) (first+2), xstride, ystride)); + if (ibuf->depth==32) + frameBuffer.insert ("A", Slice (FLOAT, (char *) (first+3), xstride, ystride)); + if (write_zbuf) + frameBuffer.insert ("Z", Slice (FLOAT, (char *) ibuf->zbuf_float + 4*(height-1)*width, + sizeof(float), sizeof(float) * -width)); + file->setFrameBuffer (frameBuffer); + file->writePixels (height); + delete file; + } + catch (const std::exception &exc) + { + printf("OpenEXR-save: ERROR: %s\n", exc.what()); + if (ibuf) IMB_freeImBuf(ibuf); + + return (0); + } + + return (1); + // printf("OpenEXR-save: Done.\n"); +} + + +short imb_save_openexr(struct ImBuf *ibuf, char *name, int flags) +{ + if (flags & IB_mem) + { + printf("OpenEXR-save: Create EXR in memory CURRENTLY NOT SUPPORTED !\n"); + imb_addencodedbufferImBuf(ibuf); + ibuf->encodedsize = 0; + return(0); + } + + if (ibuf->ftype & OPENEXR_HALF) + return imb_save_openexr_half(ibuf, name, flags); + else { + /* when no float rect, we save as half (16 bits is sufficient) */ + if (ibuf->rect_float==NULL) + return imb_save_openexr_half(ibuf, name, flags); + else + return imb_save_openexr_float(ibuf, name, flags); + } +} + +/* ********************* Nicer API, MultiLayer and with Tile file support ************************************ */ + +/* naming rules: + - parse name from right to left + - last character is channel ID, 1 char like 'A' 'R' 'G' 'B' 'X' 'Y' 'Z' 'W' 'U' 'V' + - separated with a dot; the Pass name (like "Depth", "Color", "Diffuse" or "Combined") + - separated with a dot: the Layer name (like "Lamp1" or "Walls" or "Characters") +*/ + +static ListBase exrhandles= {NULL, NULL}; + +typedef struct ExrHandle { + struct ExrHandle *next, *prev; + + InputFile *ifile; + TiledOutputFile *tofile; + OutputFile *ofile; + int tilex, tiley; + int width, height; + + ListBase channels; /* flattened out, ExrChannel */ + ListBase layers; /* hierarchical, pointing in end to ExrChannel */ +} ExrHandle; + +/* flattened out channel */ +typedef struct ExrChannel { + struct ExrChannel *next, *prev; + + char name[EXR_TOT_MAXNAME+1]; /* full name of layer+pass */ + int xstride, ystride; /* step to next pixel, to next scanline */ + float *rect; /* first pointer to write in */ + char chan_id; /* quick lookup of channel char */ +} ExrChannel; + + +/* hierarchical; layers -> passes -> channels[] */ +typedef struct ExrPass { + struct ExrPass *next, *prev; + char name[EXR_PASS_MAXNAME]; + int totchan; + float *rect; + struct ExrChannel *chan[EXR_PASS_MAXCHAN]; + char chan_id[EXR_PASS_MAXCHAN]; +} ExrPass; + +typedef struct ExrLayer { + struct ExrLayer *next, *prev; + char name[EXR_LAY_MAXNAME+1]; + ListBase passes; +} ExrLayer; + +/* ********************** */ + +void *IMB_exr_get_handle(void) +{ + ExrHandle *data= (ExrHandle *)MEM_callocN(sizeof(ExrHandle), "exr handle"); + BLI_addtail(&exrhandles, data); + return data; +} + +/* adds flattened ExrChannels */ +/* xstride, ystride and rect can be done in set_channel too, for tile writing */ +void IMB_exr_add_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect) +{ + ExrHandle *data= (ExrHandle *)handle; + ExrChannel *echan; + + echan= (ExrChannel *)MEM_callocN(sizeof(ExrChannel), "exr tile channel"); + + if(layname) { + char lay[EXR_LAY_MAXNAME+1], pass[EXR_PASS_MAXNAME+1]; + BLI_strncpy(lay, layname, EXR_LAY_MAXNAME); + BLI_strncpy(pass, passname, EXR_PASS_MAXNAME); + + sprintf(echan->name, "%s.%s", lay, pass); + } + else + BLI_strncpy(echan->name, passname, EXR_TOT_MAXNAME-1); + + echan->xstride= xstride; + echan->ystride= ystride; + echan->rect= rect; + + // printf("added channel %s\n", echan->name); + BLI_addtail(&data->channels, echan); +} + +void IMB_exr_begin_write(void *handle, char *filename, int width, int height, int compress) +{ + ExrHandle *data= (ExrHandle *)handle; + Header header (width, height); + ExrChannel *echan; + + data->width= width; + data->height= height; + + for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) + header.channels().insert (echan->name, Channel (FLOAT)); + + openexr_header_compression(&header, compress); + /* header.lineOrder() = DECREASING_Y; this crashes in windows for file read! */ + + header.insert ("BlenderMultiChannel", StringAttribute ("Blender V2.43")); + + data->ofile = new OutputFile(filename, header); +} + +void IMB_exrtile_begin_write(void *handle, char *filename, int width, int height, int tilex, int tiley) +{ + ExrHandle *data= (ExrHandle *)handle; + Header header (width, height); + ExrChannel *echan; + + data->tilex= tilex; + data->tiley= tiley; + data->width= width; + data->height= height; + + for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) + header.channels().insert (echan->name, Channel (FLOAT)); + + header.setTileDescription (TileDescription (tilex, tiley, ONE_LEVEL)); + header.lineOrder() = RANDOM_Y; + header.compression() = RLE_COMPRESSION; + + header.insert ("BlenderMultiChannel", StringAttribute ("Blender V2.43")); + + data->tofile = new TiledOutputFile(filename, header); +} + +/* read from file */ +int IMB_exr_begin_read(void *handle, char *filename, int *width, int *height) +{ + ExrHandle *data= (ExrHandle *)handle; + + if(BLI_exists(filename)) { + data->ifile = new InputFile(filename); + if(data->ifile) { + Box2i dw = data->ifile->header().dataWindow(); + data->width= *width = dw.max.x - dw.min.x + 1; + data->height= *height = dw.max.y - dw.min.y + 1; + + const ChannelList &channels = data->ifile->header().channels(); + + for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) + IMB_exr_add_channel(data, NULL, i.name(), 0, 0, NULL); + + return 1; + } + } + return 0; +} + +/* still clumsy name handling, layers/channels can be ordered as list in list later */ +void IMB_exr_set_channel(void *handle, char *layname, char *passname, int xstride, int ystride, float *rect) +{ + ExrHandle *data= (ExrHandle *)handle; + ExrChannel *echan; + char name[EXR_TOT_MAXNAME + 1]; + + if(layname) { + char lay[EXR_LAY_MAXNAME+1], pass[EXR_PASS_MAXNAME+1]; + BLI_strncpy(lay, layname, EXR_LAY_MAXNAME); + BLI_strncpy(pass, passname, EXR_PASS_MAXNAME); + + sprintf(name, "%s.%s", lay, pass); + } + else + BLI_strncpy(name, passname, EXR_TOT_MAXNAME-1); + + + for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) + if(strcmp(echan->name, name)==0) + break; + + if(echan) { + echan->xstride= xstride; + echan->ystride= ystride; + echan->rect= rect; + } + else + printf("IMB_exrtile_set_channel error %s\n", name); +} + +void IMB_exrtile_clear_channels(void *handle) +{ + ExrHandle *data= (ExrHandle *)handle; + BLI_freelistN(&data->channels); +} + +void IMB_exrtile_write_channels(void *handle, int partx, int party) +{ + ExrHandle *data= (ExrHandle *)handle; + FrameBuffer frameBuffer; + ExrChannel *echan; + + for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) { + float *rect= echan->rect - echan->xstride*partx - echan->ystride*party; + + frameBuffer.insert (echan->name, Slice (FLOAT, (char *)rect, + echan->xstride*sizeof(float), echan->ystride*sizeof(float))); + } + + data->tofile->setFrameBuffer (frameBuffer); + // printf("write tile %d %d\n", partx/data->tilex, party/data->tiley); + data->tofile->writeTile (partx/data->tilex, party/data->tiley); + +} + +void IMB_exr_write_channels(void *handle) +{ + ExrHandle *data= (ExrHandle *)handle; + FrameBuffer frameBuffer; + ExrChannel *echan; + + for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) + frameBuffer.insert (echan->name, Slice (FLOAT, (char *)echan->rect, + echan->xstride*sizeof(float), echan->ystride*sizeof(float))); + + data->ofile->setFrameBuffer (frameBuffer); + data->ofile->writePixels (data->height); + +} + +void IMB_exr_read_channels(void *handle) +{ + ExrHandle *data= (ExrHandle *)handle; + FrameBuffer frameBuffer; + ExrChannel *echan; + + for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) { + /* no datawindow correction needed */ + if(echan->rect) + frameBuffer.insert (echan->name, Slice (FLOAT, (char *)echan->rect, + echan->xstride*sizeof(float), echan->ystride*sizeof(float))); + else + printf("warning, channel with no rect set %s\n", echan->name); + } + + data->ifile->setFrameBuffer (frameBuffer); + data->ifile->readPixels (0, data->height-1); +} + +void IMB_exr_multilayer_convert(void *handle, void *base, + void * (*addlayer)(void *base, char *str), + void (*addpass)(void *base, void *lay, char *str, + float *rect, int totchan, char *chan_id)) +{ + ExrHandle *data= (ExrHandle *)handle; + ExrLayer *lay; + ExrPass *pass; + + if(data->layers.first==NULL) { + printf("cannot convert multilayer, no layers in handle\n"); + return; + } + + for(lay= (ExrLayer *)data->layers.first; lay; lay= lay->next) { + void *laybase= addlayer(base, lay->name); + if(laybase) { + for(pass= (ExrPass *)lay->passes.first; pass; pass= pass->next) { + addpass(base, laybase, pass->name, pass->rect, pass->totchan, pass->chan_id); + pass->rect= NULL; + } + } + } +} + + +void IMB_exr_close(void *handle) +{ + ExrHandle *data= (ExrHandle *)handle; + ExrChannel *echan; + ExrLayer *lay; + ExrPass *pass; + + if(data->ifile) + delete data->ifile; + else if(data->ofile) + delete data->ofile; + else if(data->tofile) + delete data->tofile; + + data->ifile= NULL; + data->ofile= NULL; + data->tofile= NULL; + + BLI_freelistN(&data->channels); + + for(lay= (ExrLayer *)data->layers.first; lay; lay= lay->next) { + for(pass= (ExrPass *)lay->passes.first; pass; pass= pass->next) + if(pass->rect) + MEM_freeN(pass->rect); + BLI_freelistN(&lay->passes); + } + BLI_freelistN(&data->layers); + + BLI_remlink(&exrhandles, data); + MEM_freeN(data); +} + +/* ********* */ + +static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *passname) +{ + int plen, len= strlen(echan->name); + + if(len < 4) { + printf("multilayer read: name too short: %s\n", echan->name); + return 0; + } + if(echan->name[len-2]!='.') { + printf("multilayer read: name has no Channel: %s\n", echan->name); + return 0; + } + echan->chan_id= echan->name[len-1]; + + len-= 3; + while(len>=0) { + if(echan->name[len]=='.') + break; + len--; + } + BLI_strncpy(passname, echan->name+len+1, EXR_PASS_MAXNAME); + plen= strlen(passname); + if(plen < 3) { + printf("multilayer read: should not happen: %s\n", echan->name); + return 0; + } + passname[plen-2]= 0; + + if(len<1) + layname[0]= 0; + else { + BLI_strncpy(layname, echan->name, EXR_LAY_MAXNAME); + layname[len]= 0; + } + // printf("found lay %s pass %s chan %c\n", layname, passname, echan->chan_id); + return 1; +} + +static ExrLayer *imb_exr_get_layer(ListBase *lb, char *layname) +{ + ExrLayer *lay; + + for(lay= (ExrLayer *)lb->first; lay; lay= lay->next) { + if( strcmp(lay->name, layname)==0 ) + return lay; + } + lay= (ExrLayer *)MEM_callocN(sizeof(ExrLayer), "exr layer"); + BLI_addtail(lb, lay); + BLI_strncpy(lay->name, layname, EXR_LAY_MAXNAME); + + return lay; +} + +static ExrPass *imb_exr_get_pass(ListBase *lb, char *passname) +{ + ExrPass *pass; + + for(pass= (ExrPass *)lb->first; pass; pass= pass->next) { + if( strcmp(pass->name, passname)==0 ) + return pass; + } + + pass= (ExrPass *)MEM_callocN(sizeof(ExrPass), "exr pass"); + + if(strcmp(passname, "Combined")==0) + BLI_addhead(lb, pass); + else + BLI_addtail(lb, pass); + + BLI_strncpy(pass->name, passname, EXR_LAY_MAXNAME); + + return pass; +} + +/* creates channels, makes a hierarchy and assigns memory to channels */ +static ExrHandle *imb_exr_begin_read_mem(InputFile *file, int width, int height) +{ + ExrLayer *lay; + ExrPass *pass; + ExrChannel *echan; + ExrHandle *data= (ExrHandle *)IMB_exr_get_handle(); + int a; + char layname[EXR_TOT_MAXNAME], passname[EXR_TOT_MAXNAME]; + + data->ifile= file; + data->width= width; + data->height= height; + + const ChannelList &channels = data->ifile->header().channels(); + + for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) + IMB_exr_add_channel(data, NULL, i.name(), 0, 0, NULL); + + /* now try to sort out how to assign memory to the channels */ + /* first build hierarchical layer list */ + for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) { + if( imb_exr_split_channel_name(echan, layname, passname) ) { + ExrLayer *lay= imb_exr_get_layer(&data->layers, layname); + ExrPass *pass= imb_exr_get_pass(&lay->passes, passname); + + pass->chan[pass->totchan]= echan; + pass->totchan++; + if(pass->totchan>=EXR_PASS_MAXCHAN) + break; + } + } + if(echan) { + printf("error, too many channels in one pass: %s\n", echan->name); + IMB_exr_close(data); + return NULL; + } + + /* with some heuristics, try to merge the channels in buffers */ + for(lay= (ExrLayer *)data->layers.first; lay; lay= lay->next) { + for(pass= (ExrPass *)lay->passes.first; pass; pass= pass->next) { + if(pass->totchan) { + pass->rect= (float *)MEM_mapallocN(width*height*pass->totchan*sizeof(float), "pass rect"); + if(pass->totchan==1) { + echan= pass->chan[0]; + echan->rect= pass->rect; + echan->xstride= 1; + echan->ystride= width; + pass->chan_id[0]= echan->chan_id; + } + else { + char lookup[256]; + + memset(lookup, 0, sizeof(lookup)); + + /* we can have RGB(A), XYZ(W), UVA */ + if(pass->totchan==3 || pass->totchan==4) { + if(pass->chan[0]->chan_id=='B' || pass->chan[1]->chan_id=='B' || pass->chan[2]->chan_id=='B') { + lookup['R']= 0; + lookup['G']= 1; + lookup['B']= 2; + lookup['A']= 3; + } + else if(pass->chan[0]->chan_id=='Y' || pass->chan[1]->chan_id=='Y' || pass->chan[2]->chan_id=='Y') { + lookup['X']= 0; + lookup['Y']= 1; + lookup['Z']= 2; + lookup['W']= 3; + } + else { + lookup['U']= 0; + lookup['V']= 1; + lookup['A']= 2; + } + for(a=0; atotchan; a++) { + echan= pass->chan[a]; + echan->rect= pass->rect + lookup[echan->chan_id]; + echan->xstride= pass->totchan; + echan->ystride= width*pass->totchan; + pass->chan_id[ lookup[echan->chan_id] ]= echan->chan_id; + } + } + else { /* unknown */ + for(a=0; atotchan; a++) { + echan= pass->chan[a]; + echan->rect= pass->rect + a; + echan->xstride= pass->totchan; + echan->ystride= width*pass->totchan; + pass->chan_id[a]= echan->chan_id; + } + } + } + } + } + } + + return data; +} + + +/* ********************************************************* */ + +typedef struct RGBA +{ + float r; + float g; + float b; + float a; +} RGBA; + + +static void exr_print_filecontents(InputFile *file) +{ + const ChannelList &channels = file->header().channels(); + + for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) + { + const Channel &channel = i.channel(); + printf("OpenEXR-load: Found channel %s of type %d\n", i.name(), channel.type); + } +} + +static int exr_has_zbuffer(InputFile *file) +{ + const ChannelList &channels = file->header().channels(); + + for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) + { + const Channel &channel = i.channel(); + if(strcmp("Z", i.name())==0) + return 1; + } + return 0; +} + +static int exr_is_renderresult(InputFile *file) +{ + const StringAttribute *comments= file->header().findTypedAttribute("BlenderMultiChannel"); + if(comments) +// if(comments->value() == "Blender MultiChannel") + return 1; + return 0; +} + +struct ImBuf *imb_load_openexr(unsigned char *mem, int size, int flags) +{ + struct ImBuf *ibuf = NULL; + InputFile *file = NULL; + + if (imb_is_a_openexr(mem) == 0) return(NULL); + + try + { + Mem_IStream *membuf = new Mem_IStream(mem, size); + int is_multi; + file = new InputFile(*membuf); + + Box2i dw = file->header().dataWindow(); + int width = dw.max.x - dw.min.x + 1; + int height = dw.max.y - dw.min.y + 1; + + //printf("OpenEXR-load: image data window %d %d %d %d\n", + // dw.min.x, dw.min.y, dw.max.x, dw.max.y); + + // exr_print_filecontents(file); + + is_multi= exr_is_renderresult(file); + + /* do not make an ibuf when */ + if(is_multi && !(flags & IB_test) && !(flags & IB_multilayer)) + { + printf("Error: can't process EXR multilayer file\n"); + } + else { + + ibuf = IMB_allocImBuf(width, height, 32, 0, 0); + ibuf->ftype = OPENEXR; + + if (!(flags & IB_test)) + { + if(is_multi) /* only enters with IB_multilayer flag set */ + { + /* constructs channels for reading, allocates memory in channels */ + ExrHandle *handle= imb_exr_begin_read_mem(file, width, height); + if(handle) { + IMB_exr_read_channels(handle); + ibuf->userdata= handle; /* potential danger, the caller has to check for this! */ + return ibuf; + } + } + else { + FrameBuffer frameBuffer; + float *first; + int xstride = sizeof(float) * 4; + int ystride = - xstride*width; + + imb_addrectfloatImBuf(ibuf); + + /* inverse correct first pixel for datawindow coordinates (- dw.min.y because of y flip) */ + first= ibuf->rect_float - 4*(dw.min.x - dw.min.y*width); + /* but, since we read y-flipped (negative y stride) we move to last scanline */ + first+= 4*(height-1)*width; + + frameBuffer.insert ("R", Slice (FLOAT, (char *) first, xstride, ystride)); + frameBuffer.insert ("G", Slice (FLOAT, (char *) (first+1), xstride, ystride)); + frameBuffer.insert ("B", Slice (FLOAT, (char *) (first+2), xstride, ystride)); + /* 1.0 is fill value */ + frameBuffer.insert ("A", Slice (FLOAT, (char *) (first+3), xstride, ystride, 1, 1, 1.0f)); + + if(exr_has_zbuffer(file)) + { + float *firstz; + + addzbuffloatImBuf(ibuf); + firstz= ibuf->zbuf_float - (dw.min.x - dw.min.y*width); + firstz+= (height-1)*width; + frameBuffer.insert ("Z", Slice (FLOAT, (char *)firstz , sizeof(float), -width*sizeof(float))); + } + + file->setFrameBuffer (frameBuffer); + file->readPixels (dw.min.y, dw.max.y); + + IMB_rect_from_float(ibuf); + } + } + + } + delete file; + + return(ibuf); + + } + catch (const std::exception &exc) + { + std::cerr << exc.what() << std::endl; + if (ibuf) IMB_freeImBuf(ibuf); + delete file; + + return (0); + } + +} + + +} // export "C" diff --git a/source/blender/imbuf/intern/openexr/openexr_api.h b/source/blender/imbuf/intern/openexr/openexr_api.h new file mode 100644 index 00000000000..7572dbcb292 --- /dev/null +++ b/source/blender/imbuf/intern/openexr/openexr_api.h @@ -0,0 +1,59 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Austin Benesh. Ton Roosendaal. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef _OPENEXR_API_H +#define _OPENEXR_API_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define OPENEXR_FLOATRGB 0x1 +#define OPENEXR_ZBUF 0x2 + +#include + + /** + * Test presence of OpenEXR file. + * @param mem pointer to loaded OpenEXR bitstream + */ + +int imb_is_a_openexr (unsigned char *mem); + +short imb_save_openexr (struct ImBuf *ibuf, char *name, int flags); + +struct ImBuf *imb_load_openexr (unsigned char *mem, int size, int flags); + +#ifdef __cplusplus +} +#endif + + + +#endif /* __OPENEXR_API_H */ diff --git a/source/blender/imbuf/intern/openexr/openexr_multi.h b/source/blender/imbuf/intern/openexr/openexr_multi.h new file mode 100644 index 00000000000..ca4f7405f44 --- /dev/null +++ b/source/blender/imbuf/intern/openexr/openexr_multi.h @@ -0,0 +1,93 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Ton Roosendaal. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef _OPENEXR_MULTI_H +#define _OPENEXR_MULTI_H + +/* experiment with more advanced exr api */ + +/* Note: as for now openexr only supports 32 chars in channel names. + This api also supports max 8 channels per pass now. easy to fix! */ +#define EXR_LAY_MAXNAME 19 +#define EXR_PASS_MAXNAME 11 +#define EXR_TOT_MAXNAME 32 +#define EXR_PASS_MAXCHAN 8 + + +#ifdef WITH_OPENEXR +void * IMB_exr_get_handle (void); +void IMB_exr_add_channel (void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect); + +int IMB_exr_begin_read (void *handle, char *filename, int *width, int *height); +void IMB_exr_begin_write (void *handle, char *filename, int width, int height, int compress); +void IMB_exrtile_begin_write (void *handle, char *filename, int width, int height, int tilex, int tiley); + +void IMB_exr_set_channel (void *handle, char *layname, char *passname, int xstride, int ystride, float *rect); + +void IMB_exr_read_channels (void *handle); +void IMB_exr_write_channels (void *handle); +void IMB_exrtile_write_channels (void *handle, int partx, int party); +void IMB_exrtile_clear_channels (void *handle); + +void IMB_exr_multilayer_convert (void *handle, void *base, + void * (*addlayer)(void *base, char *str), + void (*addpass)(void *base, void *lay, char *str, float *rect, int totchan, char *chan_id)); + +void IMB_exr_close (void *handle); + + +#else + +/* ugly... but we only use it on pipeline.c, render module, now */ + +void * IMB_exr_get_handle (void) {return NULL;} +void IMB_exr_add_channel (void *handle, const char *layname, const char *channame, int xstride, int ystride, float *rect) {} + +int IMB_exr_begin_read (void *handle, char *filename, int *width, int *height) {return 0;} +void IMB_exr_begin_write (void *handle, char *filename, int width, int height, int compress) {} +void IMB_exrtile_begin_write (void *handle, char *filename, int width, int height, int tilex, int tiley) {} + +void IMB_exr_set_channel (void *handle, char *layname, char *channame, int xstride, int ystride, float *rect) {} + +void IMB_exr_read_channels (void *handle) {} +void IMB_exr_write_channels (void *handle) {} +void IMB_exrtile_write_channels (void *handle, int partx, int party) {} +void IMB_exrtile_clear_channels (void *handle) {} + +void IMB_exr_multilayer_convert (void *handle, void *base, + void * (*addlayer)(void *base, char *str), + void (*addpass)(void *base, void *lay, char *str, float *rect, int totchan, char *chan_id)) {} + +void IMB_exr_close (void *handle) {} + +#endif + + + +#endif /* __OPENEXR_MULTI_H */ diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c new file mode 100644 index 00000000000..c77ff7ea56f --- /dev/null +++ b/source/blender/imbuf/intern/png.c @@ -0,0 +1,461 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * $Id$ + */ + + +#include "png.h" + +#include "BLI_blenlib.h" + +#include "imbuf.h" +#include "imbuf_patch.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "IMB_allocimbuf.h" +#include "IMB_cmap.h" +#include "IMB_imginfo.h" +#include "IMB_png.h" + +typedef struct PNGReadStruct { + unsigned char *data; + unsigned int size; + unsigned int seek; +}PNGReadStruct; + +static void ReadData( png_structp png_ptr, png_bytep data, png_size_t length); +static void WriteData( png_structp png_ptr, png_bytep data, png_size_t length); +static void Flush( png_structp png_ptr); + +int imb_is_a_png(void *mem) +{ + int ret_val = 0; + + if (mem) ret_val = !png_sig_cmp(mem, 0, 8); + return(ret_val); +} + +static void Flush(png_structp png_ptr) +{ +} + +static void WriteData( png_structp png_ptr, png_bytep data, png_size_t length) +{ + ImBuf *ibuf = (ImBuf *) png_get_io_ptr(png_ptr); + + // if buffer is to small increase it. + while (ibuf->encodedsize + length > ibuf->encodedbuffersize) { + imb_enlargeencodedbufferImBuf(ibuf); + } + + memcpy(ibuf->encodedbuffer + ibuf->encodedsize, data, length); + ibuf->encodedsize += length; +} + +static void ReadData( png_structp png_ptr, png_bytep data, png_size_t length) +{ + PNGReadStruct *rs= (PNGReadStruct *) png_get_io_ptr(png_ptr); + + if (rs) { + if (length <= rs->size - rs->seek) { + memcpy(data, rs->data + rs->seek, length); + rs->seek += length; + return; + } + } + + printf("Reached EOF while decoding PNG\n"); + longjmp(png_jmpbuf(png_ptr), 1); +} + +short imb_savepng(struct ImBuf *ibuf, char *name, int flags) +{ + png_structp png_ptr; + png_infop info_ptr; + + unsigned char *pixels = 0; + unsigned char *from, *to; + png_bytepp row_pointers = 0; + int i, bytesperpixel, color_type = PNG_COLOR_TYPE_GRAY; + FILE *fp = 0; + + bytesperpixel = (ibuf->depth + 7) >> 3; + if ((bytesperpixel > 4) || (bytesperpixel == 2)) { + printf("imb_savepng: unsupported bytes per pixel: %d\n", bytesperpixel); + return (0); + } + + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + if (png_ptr == NULL) { + printf("Cannot png_create_write_struct\n"); + return 0; + } + + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) { + png_destroy_write_struct(&png_ptr, (png_infopp)NULL); + printf("Cannot png_create_info_struct\n"); + return 0; + } + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_write_struct(&png_ptr, &info_ptr); + if (pixels) MEM_freeN(pixels); + if (row_pointers) MEM_freeN(row_pointers); + // printf("Aborting\n"); + if (fp) { + fflush(fp); + fclose(fp); + } + return 0; + } + + // copy image data + + pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels"); + if (pixels == NULL) { + printf("Cannot allocate pixels array\n"); + return 0; + } + + from = (unsigned char *) ibuf->rect; + to = pixels; + + switch (bytesperpixel) { + case 4: + color_type = PNG_COLOR_TYPE_RGBA; + for (i = ibuf->x * ibuf->y; i > 0; i--) { + to[0] = from[0]; + to[1] = from[1]; + to[2] = from[2]; + to[3] = from[3]; + to += 4; from += 4; + } + break; + case 3: + color_type = PNG_COLOR_TYPE_RGB; + for (i = ibuf->x * ibuf->y; i > 0; i--) { + to[0] = from[0]; + to[1] = from[1]; + to[2] = from[2]; + to += 3; from += 4; + } + break; + case 1: + color_type = PNG_COLOR_TYPE_GRAY; + for (i = ibuf->x * ibuf->y; i > 0; i--) { + to[0] = from[0]; + to++; from += 4; + } + break; + } + + if (flags & IB_mem) { + // create image in memory + imb_addencodedbufferImBuf(ibuf); + ibuf->encodedsize = 0; + + png_set_write_fn(png_ptr, + (png_voidp) ibuf, + WriteData, + Flush); + } else { + fp = fopen(name, "wb"); + if (!fp) { + MEM_freeN(pixels); + return 0; + } + png_init_io(png_ptr, fp); + } + + /* + png_set_filter(png_ptr, 0, + PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE | + PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB | + PNG_FILTER_UP | PNG_FILTER_VALUE_UP | + PNG_FILTER_AVG | PNG_FILTER_VALUE_AVG | + PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH| + PNG_ALL_FILTERS); + + png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); + */ + + // png image settings + png_set_IHDR(png_ptr, + info_ptr, + ibuf->x, + ibuf->y, + 8, + color_type, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + /* image text info */ + if (ibuf->img_info) { + png_text* imginfo; + ImgInfo* iptr; + int num_text = 0; + iptr = ibuf->img_info; + while (iptr) { + num_text++; + iptr = iptr->next; + } + + imginfo = MEM_callocN(num_text*sizeof(png_text), "png_imginfo"); + iptr = ibuf->img_info; + num_text = 0; + while (iptr) { + + imginfo[num_text].compression = PNG_TEXT_COMPRESSION_NONE; + imginfo[num_text].key = iptr->key; + imginfo[num_text].text = iptr->value; + num_text++; + iptr = iptr->next; + } + + png_set_text(png_ptr, info_ptr, imginfo, num_text); + MEM_freeN(imginfo); + + } + + // write the file header information + png_write_info(png_ptr, info_ptr); + + // allocate memory for an array of row-pointers + row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers"); + if (row_pointers == NULL) { + printf("Cannot allocate row-pointers array\n"); + MEM_freeN(pixels); + return 0; + } + + // set the individual row-pointers to point at the correct offsets + for (i = 0; i < ibuf->y; i++) { + row_pointers[ibuf->y-1-i] = (png_bytep) + ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char)); + } + + // write out the entire image data in one call + png_write_image(png_ptr, row_pointers); + + // write the additional chunks to the PNG file (not really needed) + png_write_end(png_ptr, info_ptr); + + // clean up + MEM_freeN(pixels); + MEM_freeN(row_pointers); + png_destroy_write_struct(&png_ptr, &info_ptr); + + if (fp) { + fflush(fp); + fclose(fp); + } + + return(1); +} + +struct ImBuf *imb_loadpng(unsigned char *mem, int size, int flags) +{ + struct ImBuf *ibuf = 0; + png_structp png_ptr; + png_infop info_ptr; + unsigned char *pixels = 0; + png_bytepp row_pointers = 0; + png_uint_32 width, height; + int bit_depth, color_type; + PNGReadStruct ps; + + unsigned char *from, *to; + int i, bytesperpixel; + + if (imb_is_a_png(mem) == 0) return(0); + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + if (png_ptr == NULL) { + printf("Cannot png_create_read_struct\n"); + return 0; + } + + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) { + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, + (png_infopp)NULL); + printf("Cannot png_create_info_struct\n"); + return 0; + } + + ps.size = size; + ps.data = mem; + ps.seek = 0; + + png_set_read_fn(png_ptr, (void *) &ps, ReadData); + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + if (pixels) MEM_freeN(pixels); + if (row_pointers) MEM_freeN(row_pointers); + if (ibuf) IMB_freeImBuf(ibuf); + return 0; + } + + // png_set_sig_bytes(png_ptr, 8); + + png_read_info(png_ptr, info_ptr); + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, + &color_type, NULL, NULL, NULL); + + if (bit_depth == 16) { + png_set_strip_16(png_ptr); + bit_depth = 8; + } + + bytesperpixel = png_get_channels(png_ptr, info_ptr); + + switch(color_type) { + case PNG_COLOR_TYPE_RGB: + case PNG_COLOR_TYPE_RGB_ALPHA: + break; + case PNG_COLOR_TYPE_PALETTE: + png_set_palette_to_rgb(png_ptr); + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { + bytesperpixel = 4; + } else { + bytesperpixel = 3; + } + break; + case PNG_COLOR_TYPE_GRAY: + case PNG_COLOR_TYPE_GRAY_ALPHA: + if (bit_depth < 8) { + png_set_expand(png_ptr); + bit_depth = 8; + } + break; + default: + printf("PNG format not supported\n"); + longjmp(png_jmpbuf(png_ptr), 1); + } + + ibuf = IMB_allocImBuf(width, height, 8 * bytesperpixel, 0, 0); + + if (ibuf) { + ibuf->ftype = PNG; + } else { + printf("Couldn't allocate memory for PNG image\n"); + } + + if (ibuf && ((flags & IB_test) == 0)) { + imb_addrectImBuf(ibuf); + + pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels"); + if (pixels == NULL) { + printf("Cannot allocate pixels array\n"); + longjmp(png_jmpbuf(png_ptr), 1); + } + + // allocate memory for an array of row-pointers + row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers"); + if (row_pointers == NULL) { + printf("Cannot allocate row-pointers array\n"); + longjmp(png_jmpbuf(png_ptr), 1); + } + + // set the individual row-pointers to point at the correct offsets + for (i = 0; i < ibuf->y; i++) { + row_pointers[ibuf->y-1-i] = (png_bytep) + ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char)); + } + + png_read_image(png_ptr, row_pointers); + + // copy image data + + to = (unsigned char *) ibuf->rect; + from = pixels; + + switch (bytesperpixel) { + case 4: + for (i = ibuf->x * ibuf->y; i > 0; i--) { + to[0] = from[0]; + to[1] = from[1]; + to[2] = from[2]; + to[3] = from[3]; + to += 4; from += 4; + } + break; + case 3: + for (i = ibuf->x * ibuf->y; i > 0; i--) { + to[0] = from[0]; + to[1] = from[1]; + to[2] = from[2]; + to[3] = 0xff; + to += 4; from += 3; + } + break; + case 2: + for (i = ibuf->x * ibuf->y; i > 0; i--) { + to[0] = to[1] = to[2] = from[0]; + to[3] = from[1]; + to += 4; from += 2; + } + break; + case 1: + for (i = ibuf->x * ibuf->y; i > 0; i--) { + to[0] = to[1] = to[2] = from[0]; + to[3] = 0xff; + to += 4; from++; + } + break; + } + + if (flags & IB_imginfo) { + png_text* text_chunks; + int count = png_get_text(png_ptr, info_ptr, &text_chunks, NULL); + for(i = 0; i < count; i++) { + IMB_imginfo_add_field(ibuf, text_chunks[i].key, text_chunks[i].text); + ibuf->flags |= IB_imginfo; + } + } + + png_read_end(png_ptr, info_ptr); + } + + // clean up + MEM_freeN(pixels); + MEM_freeN(row_pointers); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + + return(ibuf); +} + diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c new file mode 100644 index 00000000000..3cb9ca79ffc --- /dev/null +++ b/source/blender/imbuf/intern/radiance_hdr.c @@ -0,0 +1,366 @@ +/* + * radiance_hdr.c + * + * $Id: + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** +*/ + +/* ---------------------------------------------------------------------- + Radiance High Dynamic Range image file IO + For description and code for reading/writing of radiance hdr files + by Greg Ward, refer to: + http://radsite.lbl.gov/radiance/refer/Notes/picture_format.html +---------------------------------------------------------------------- +*/ + +#ifdef WIN32 +#include +#endif +#include "BLI_blenlib.h" + +#include "imbuf.h" +#include "imbuf_patch.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "IMB_allocimbuf.h" +#include "IMB_cmap.h" +#include "IMB_radiance_hdr.h" + +/* needed constants */ +#define MINELEN 8 +#define MAXELEN 0x7fff +#define MINRUN 4 /* minimum run length */ +#define RED 0 +#define GRN 1 +#define BLU 2 +#define EXP 3 +#define COLXS 128 +typedef unsigned char RGBE[4]; +typedef float fCOLOR[3]; +/* copy source -> dest */ +#define copy_rgbe(c1, c2) (c2[RED]=c1[RED], c2[GRN]=c1[GRN], c2[BLU]=c1[BLU], c2[EXP]=c1[EXP]) +#define copy_fcol(f1, f2) (f2[RED]=f1[RED], f2[GRN]=f1[GRN], f2[BLU]=f1[BLU]) + +/* read routines */ +static unsigned char* oldreadcolrs(RGBE *scan, unsigned char *mem, int xmax) +{ + int i, rshift = 0, len = xmax; + while (len > 0) { + scan[0][RED] = *mem++; + scan[0][GRN] = *mem++; + scan[0][BLU] = *mem++; + scan[0][EXP] = *mem++; + if (scan[0][RED] == 1 && scan[0][GRN] == 1 && scan[0][BLU] == 1) { + for (i=scan[0][EXP]<0;i--) { + copy_rgbe(scan[-1], scan[0]); + scan++; + len--; + } + rshift += 8; + } + else { + scan++; + len--; + rshift = 0; + } + } + return mem; +} + +static unsigned char* freadcolrs(RGBE *scan, unsigned char* mem, int xmax) +{ + int i, j, code, val; + + if ((xmax < MINELEN) | (xmax > MAXELEN)) return oldreadcolrs(scan, mem, xmax); + + i = *mem++; + if (i != 2) return oldreadcolrs(scan, mem-1, xmax); + + scan[0][GRN] = *mem++; + scan[0][BLU] = *mem++; + + i = *mem++; + if (((scan[0][BLU] << 8) | i) != xmax) return NULL; + + for (i=0;i<4;i++) + for (j=0;j 128) { + code &= 127; + val = *mem++; + while (code--) + scan[j++][i] = (unsigned char)val; + } + else + while (code--) + scan[j++][i] = *mem++; + } + return mem; +} + +/* helper functions */ + +/* rgbe -> float color */ +static void RGBE2FLOAT(RGBE rgbe, fCOLOR fcol) +{ + if (rgbe[EXP]==0) { + fcol[RED] = fcol[GRN] = fcol[BLU] = 0; + } + else { + float f = ldexp(1.0, rgbe[EXP]-(COLXS+8)); + fcol[RED] = f*(rgbe[RED] + 0.5f); + fcol[GRN] = f*(rgbe[GRN] + 0.5f); + fcol[BLU] = f*(rgbe[BLU] + 0.5f); + } +} + +/* float color -> rgbe */ +static void FLOAT2RGBE(fCOLOR fcol, RGBE rgbe) +{ + int e; + float d = (fcol[RED]>fcol[GRN]) ? fcol[RED] : fcol[GRN]; + if (fcol[BLU]>d) d = fcol[BLU]; + if (d <= 1e-32f) + rgbe[RED] = rgbe[GRN] = rgbe[BLU] = rgbe[EXP] = 0; + else { + d = frexp(d, &e) * 256.f / d; + rgbe[RED] = (unsigned char)(fcol[RED] * d); + rgbe[GRN] = (unsigned char)(fcol[GRN] * d); + rgbe[BLU] = (unsigned char)(fcol[BLU] * d); + rgbe[EXP] = (unsigned char)(e + COLXS); + } +} + +/* ImBuf read */ + +int imb_is_a_hdr(void *buf) +{ + // For recognition, Blender only loads first 32 bytes, so use #?RADIANCE id instead + // update: actually, the 'RADIANCE' part is just an optional program name, the magic word is really only the '#?' part + //if (strstr((char*)buf, "#?RADIANCE")) return 1; + if (strstr((char*)buf, "#?")) return 1; + // if (strstr((char*)buf, "32-bit_rle_rgbe")) return 1; + return 0; +} + +struct ImBuf *imb_loadhdr(unsigned char *mem, int size, int flags) +{ + struct ImBuf* ibuf; + RGBE* sline; + fCOLOR fcol; + float* rect_float; + int found=0; + int width=0, height=0; + int x, y; + unsigned char* ptr; + unsigned char* rect; + char oriY[80], oriX[80]; + + if (imb_is_a_hdr((void*)mem)) + { + /* find empty line, next line is resolution info */ + for (x=1;xftype = RADHDR; + ibuf->xorig = ibuf->yorig = 0; + + if (flags & IB_test) return ibuf; + + /* read in and decode the actual data */ + sline = (RGBE*)MEM_mallocN(sizeof(RGBE)*width, "radhdr_read_tmpscan"); + rect = (unsigned char*)ibuf->rect; + rect_float = (float *)ibuf->rect_float; + + for (y=0;y 1.f) ? 255 : (255.f*fcol[RED]))); + *rect++ = (unsigned char)((fcol[GRN] < 0.f) ? 0 : ((fcol[GRN] > 1.f) ? 255 : (255.f*fcol[GRN]))); + *rect++ = (unsigned char)((fcol[BLU] < 0.f) ? 0 : ((fcol[BLU] > 1.f) ? 255 : (255.f*fcol[BLU]))); + *rect++ = 255; + } + } + MEM_freeN(sline); + if (oriY[0]=='-') IMB_flipy(ibuf); + return ibuf; + } + //else printf("Data not found!\n"); + } + //else printf("Not a valid radiance HDR file!\n"); + + return NULL; +} + +/* ImBuf write */ +static int fwritecolrs(FILE* file, int width, unsigned char* ibufscan, float* fpscan) +{ + int x, i, j, beg, c2, cnt=0; + fCOLOR fcol; + RGBE rgbe, *rgbe_scan; + + if ((ibufscan==NULL) && (fpscan==NULL)) return 0; + + rgbe_scan = (RGBE*)MEM_mallocN(sizeof(RGBE)*width, "radhdr_write_tmpscan"); + + /* convert scanline */ + j= 0; + for (i=0;i MAXELEN)) { /* OOBs, write out flat */ + x=fwrite((char *)rgbe_scan, sizeof(RGBE), width, file) - width; + MEM_freeN(rgbe_scan); + return x; + } + /* put magic header */ + putc(2, file); + putc(2, file); + putc((unsigned char)(width >> 8), file); + putc((unsigned char)(width & 255), file); + /* put components seperately */ + for (i=0;i<4;i++) { + for (j=0;j=MINRUN) break; /* long enough */ + } + if (((beg-j)>1) && ((beg-j) < MINRUN)) { + c2 = j+1; + while (rgbe_scan[c2++][i] == rgbe_scan[j][i]) + if (c2 == beg) { /* short run */ + putc((unsigned char)(128+beg-j), file); + putc((unsigned char)(rgbe_scan[j][i]), file); + j = beg; + break; + } + } + while (j < beg) { /* write out non-run */ + if ((c2 = beg-j) > 128) c2 = 128; + putc((unsigned char)(c2), file); + while (c2--) putc(rgbe_scan[j++][i], file); + } + if (cnt >= MINRUN) { /* write out run */ + putc((unsigned char)(128+cnt), file); + putc(rgbe_scan[beg][i], file); + } + else cnt = 0; + } + } + MEM_freeN(rgbe_scan); + return(ferror(file) ? -1 : 0); +} + +static void writeHeader(FILE *file, int width, int height) +{ + fprintf(file, "#?RADIANCE"); + fputc(10, file); + fprintf(file, "# %s", "Created with Blender"); + fputc(10, file); + fprintf(file, "EXPOSURE=%25.13f", 1.0); + fputc(10, file); + fprintf(file, "FORMAT=32-bit_rle_rgbe"); + fputc(10, file); + fputc(10, file); + fprintf(file, "-Y %d +X %d", height, width); + fputc(10, file); +} + +short imb_savehdr(struct ImBuf *ibuf, char *name, int flags) +{ + FILE* file = fopen(name, "wb"); + float *fp= NULL; + int y, width=ibuf->x, height=ibuf->y; + unsigned char *cp= NULL; + + if (file==NULL) return 0; + + writeHeader(file, width, height); + + if(ibuf->rect) + cp= (unsigned char *)(ibuf->rect + (height-1)*width); + if(ibuf->rect_float) + fp= ibuf->rect_float + 4*(height-1)*width; + + for (y=height-1;y>=0;y--) { + if (fwritecolrs(file, width, cp, fp) < 0) { + fclose(file); + printf("HDR write error\n"); + return 0; + } + if(cp) cp-= 4*width; + if(fp) fp-= 4*width; + } + + fclose(file); + return 1; +} + diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c new file mode 100644 index 00000000000..ec0f17a8c2b --- /dev/null +++ b/source/blender/imbuf/intern/readimage.c @@ -0,0 +1,311 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * allocimbuf.c + * + * $Id$ + */ + +#ifdef WIN32 +#include +#endif + +#include "BLI_blenlib.h" + +#include "imbuf.h" +#include "imbuf_patch.h" +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "IMB_amiga.h" +#include "IMB_iris.h" +#include "IMB_targa.h" +#include "IMB_png.h" +#include "IMB_hamx.h" +#include "IMB_jpeg.h" +#include "IMB_bmp.h" +#include "IMB_tiff.h" +#include "IMB_radiance_hdr.h" +#include "IMB_dpxcineon.h" +#include "BKE_global.h" + +#ifdef WITH_OPENEXR +#include "openexr/openexr_api.h" +#endif + +#ifdef WITH_DDS +#include "dds/dds_api.h" +#endif + +#ifdef WITH_QUICKTIME +#if defined(_WIN32) || defined (__APPLE__) +#include "quicktime_import.h" +#endif +#endif + +/* actually hard coded endianness */ +#define GET_BIG_LONG(x) (((uchar *) (x))[0] << 24 | ((uchar *) (x))[1] << 16 | ((uchar *) (x))[2] << 8 | ((uchar *) (x))[3]) +#define GET_LITTLE_LONG(x) (((uchar *) (x))[3] << 24 | ((uchar *) (x))[2] << 16 | ((uchar *) (x))[1] << 8 | ((uchar *) (x))[0]) +#define SWAP_L(x) (((x << 24) & 0xff000000) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | ((x >> 24) & 0xff)) +#define SWAP_S(x) (((x << 8) & 0xff00) | ((x >> 8) & 0xff)) + +/* more endianness... should move to a separate file... */ +#if defined(__sgi) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__) +#define GET_ID GET_BIG_LONG +#define LITTLE_LONG SWAP_LONG +#else +#define GET_ID GET_LITTLE_LONG +#define LITTLE_LONG ENDIAN_NOP +#endif + +/* from misc_util: flip the bytes from x */ +#define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1]) + +/* this one is only def-ed once, strangely... */ +#define GSS(x) (((uchar *)(x))[1] << 8 | ((uchar *)(x))[0]) + +int IB_verbose = TRUE; + +ImBuf *IMB_ibImageFromMemory(int *mem, int size, int flags) { + int len; + struct ImBuf *ibuf; + + if (mem == NULL) { + printf("Error in ibImageFromMemory: NULL pointer\n"); + } else { + if ((GS(mem) == IMAGIC) || (GSS(mem) == IMAGIC)){ + return (imb_loadiris((uchar *) mem, flags)); + } else if (imb_is_a_jpeg((uchar *)mem)) { + return (imb_ibJpegImageFromMemory((uchar *)mem, size, flags)); + } + + if (GET_ID(mem) == CAT){ + mem += 3; + size -= 4; + while (size > 0){ + if (GET_ID(mem) == FORM){ + len = ((GET_BIG_LONG(mem+1) + 1) & ~1) + 8; + if ((GET_ID(mem+2) == ILBM) || (GET_ID(mem+2) == ANIM)) break; + mem = (int *)((uchar *)mem +len); + size -= len; + } else return(0); + } + } + + if (size > 0){ + if (GET_ID(mem) == FORM){ + if (GET_ID(mem+2) == ILBM){ + return (imb_loadamiga(mem, flags)); + } else if (GET_ID(mem+5) == ILBM){ /* animaties */ + return (imb_loadamiga(mem+3, flags)); + } else if (GET_ID(mem+2) == ANIM){ + return (imb_loadanim(mem, flags)); + } + } + } + + ibuf = imb_loadpng((uchar *)mem, size, flags); + if (ibuf) return(ibuf); + + ibuf = imb_bmp_decode((uchar *)mem, size, flags); + if (ibuf) return(ibuf); + + ibuf = imb_loadtarga((uchar *)mem, flags); + if (ibuf) return(ibuf); + + ibuf = imb_loaddpx((uchar *)mem, size, flags); + if (ibuf) return(ibuf); + + ibuf = imb_loadcineon((uchar *)mem, size, flags); + if (ibuf) return(ibuf); + + if (G.have_libtiff) { + ibuf = imb_loadtiff((uchar *)mem, size, flags); + if (ibuf) return(ibuf); + } + + ibuf = imb_loadhdr((uchar*)mem, size, flags); + if (ibuf) return (ibuf); + +#ifdef WITH_OPENEXR + ibuf = imb_load_openexr((uchar *)mem, size, flags); + if (ibuf) return (ibuf); +#endif + +#ifdef WITH_DDS + ibuf = imb_load_dds((uchar *)mem, size, flags); + if (ibuf) return (ibuf); +#endif + +#ifdef WITH_QUICKTIME +#if defined(_WIN32) || defined (__APPLE__) + if(G.have_quicktime) { + ibuf = imb_quicktime_decode((uchar *)mem, size, flags); + if (ibuf) return(ibuf); + } +#endif +#endif + + if (IB_verbose) fprintf(stderr, "Unknown fileformat\n"); + } + + return (0); +} + + +struct ImBuf *IMB_loadiffmem(int *mem, int flags) { + int len,maxlen; + struct ImBuf *ibuf; + + // IMB_loadiffmem shouldn't be used anymore in new development + // it's still here to be backwards compatible... + + maxlen= (GET_BIG_LONG(mem+1) + 1) & ~1; + + if (GET_ID(mem) == CAT){ + mem += 3; + maxlen -= 4; + while(maxlen > 0){ + if (GET_ID(mem) == FORM){ + len = ((GET_BIG_LONG(mem+1) + 1) & ~1) + 8; + if ((GET_ID(mem+2) == ILBM) || (GET_ID(mem+2) == ANIM)) break; + mem = (int *)((uchar *)mem +len); + maxlen -= len; + } else return(0); + } + } + + if (maxlen > 0){ + if (GET_ID(mem) == FORM){ + if (GET_ID(mem+2) == ILBM){ + return (imb_loadamiga(mem, flags)); + } else if (GET_ID(mem+5) == ILBM){ /* animaties */ + return (imb_loadamiga(mem+3, flags)); + } else if (GET_ID(mem+2) == ANIM){ + return (imb_loadanim(mem, flags)); + } + } else if ((GS(mem) == IMAGIC) || (GSS(mem) == IMAGIC)){ + return (imb_loadiris((uchar *) mem,flags)); + } else if ((BIG_LONG(mem[0]) & 0xfffffff0) == 0xffd8ffe0) { + return (0); + } + } + + ibuf = imb_loadtarga((uchar *) mem,flags); + if (ibuf) return(ibuf); + + if (IB_verbose) fprintf(stderr,"Unknown fileformat\n"); + return (0); +} + +struct ImBuf *IMB_loadifffile(int file, int flags) { + struct ImBuf *ibuf; + int size, *mem; + + if (file == -1) return (0); + + size = BLI_filesize(file); + +#if defined(AMIGA) || defined(__BeOS) || defined(WIN32) + mem= (int *)malloc(size); + if (mem==0) { + printf("Out of mem\n"); + return (0); + } + + if (read(file, mem, size)!=size){ + printf("Read Error\n"); + free(mem); + return (0); + } + + ibuf = IMB_ibImageFromMemory(mem, size, flags); + free(mem); + + /* for jpeg read */ + lseek(file, 0L, SEEK_SET); + +#else + mem= (int *)mmap(0,size,PROT_READ,MAP_SHARED,file,0); + if (mem==(int *)-1){ + printf("Couldn't get mapping\n"); + return (0); + } + + ibuf = IMB_ibImageFromMemory(mem, size, flags); + + if (munmap( (void *) mem, size)){ + printf("Couldn't unmap file.\n"); + } +#endif + return(ibuf); +} + + +struct ImBuf *IMB_loadiffname(const char *naam, int flags) { + int file; + struct ImBuf *ibuf; + int buf[1]; + + file = open(naam, O_BINARY|O_RDONLY); + + if (file == -1) return (0); + + ibuf= IMB_loadifffile(file, flags); + + if (ibuf == NULL) { + if (read(file, buf, 4) != 4) buf[0] = 0; + if ((BIG_LONG(buf[0]) & 0xfffffff0) == 0xffd8ffe0) + ibuf = imb_ibJpegImageFromFilename(naam, flags); + } + + if (ibuf) { + strncpy(ibuf->name, naam, sizeof(ibuf->name)); + if (flags & IB_fields) IMB_de_interlace(ibuf); + } + close(file); + return(ibuf); +} + +struct ImBuf *IMB_testiffname(char *naam,int flags) { + int file; + struct ImBuf *ibuf; + + flags |= IB_test; + file = open(naam,O_BINARY|O_RDONLY); + + if (file<=0) return (0); + + ibuf=IMB_loadifffile(file,flags); + if (ibuf) { + strncpy(ibuf->name, naam, sizeof(ibuf->name)); + } + close(file); + return(ibuf); +} diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c new file mode 100644 index 00000000000..63de3bd2355 --- /dev/null +++ b/source/blender/imbuf/intern/rectop.c @@ -0,0 +1,601 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * allocimbuf.c + * + * $Id$ + */ + +#include "BLI_blenlib.h" + +#include "imbuf.h" +#include "imbuf_patch.h" +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "IMB_allocimbuf.h" + +/* blend modes */ + +static void blend_color_mix(char *cp, char *cp1, char *cp2, int fac) +{ + /* this and other blending modes previously used >>8 instead of /255. both + are not equivalent (>>8 is /256), and the former results in rounding + errors that can turn colors black fast after repeated blending */ + int mfac= 255-fac; + + cp[0]= (mfac*cp1[0]+fac*cp2[0])/255; + cp[1]= (mfac*cp1[1]+fac*cp2[1])/255; + cp[2]= (mfac*cp1[2]+fac*cp2[2])/255; +} + +static void blend_color_add(char *cp, char *cp1, char *cp2, int fac) +{ + int temp; + + temp= cp1[0] + ((fac*cp2[0])/255); + if(temp>254) cp[0]= 255; else cp[0]= temp; + temp= cp1[1] + ((fac*cp2[1])/255); + if(temp>254) cp[1]= 255; else cp[1]= temp; + temp= cp1[2] + ((fac*cp2[2])/255); + if(temp>254) cp[2]= 255; else cp[2]= temp; +} + +static void blend_color_sub(char *cp, char *cp1, char *cp2, int fac) +{ + int temp; + + temp= cp1[0] - ((fac*cp2[0])/255); + if(temp<0) cp[0]= 0; else cp[0]= temp; + temp= cp1[1] - ((fac*cp2[1])/255); + if(temp<0) cp[1]= 0; else cp[1]= temp; + temp= cp1[2] - ((fac*cp2[2])/255); + if(temp<0) cp[2]= 0; else cp[2]= temp; +} + +static void blend_color_mul(char *cp, char *cp1, char *cp2, int fac) +{ + int mfac= 255-fac; + + /* first mul, then blend the fac */ + cp[0]= (mfac*cp1[0] + fac*((cp1[0]*cp2[0])/255))/255; + cp[1]= (mfac*cp1[1] + fac*((cp1[1]*cp2[1])/255))/255; + cp[2]= (mfac*cp1[2] + fac*((cp1[2]*cp2[2])/255))/255; +} + +static void blend_color_lighten(char *cp, char *cp1, char *cp2, int fac) +{ + /* See if are lighter, if so mix, else dont do anything. + if the paint col is darker then the original, then ignore */ + if (cp1[0]+cp1[1]+cp1[2] > cp2[0]+cp2[1]+cp2[2]) { + cp[0]= cp1[0]; + cp[1]= cp1[1]; + cp[2]= cp1[2]; + } + else + blend_color_mix(cp, cp1, cp2, fac); +} + +static void blend_color_darken(char *cp, char *cp1, char *cp2, int fac) +{ + /* See if were darker, if so mix, else dont do anything. + if the paint col is brighter then the original, then ignore */ + if (cp1[0]+cp1[1]+cp1[2] < cp2[0]+cp2[1]+cp2[2]) { + cp[0]= cp1[0]; + cp[1]= cp1[1]; + cp[2]= cp1[2]; + } + else + blend_color_mix(cp, cp1, cp2, fac); +} + +unsigned int IMB_blend_color(unsigned int src1, unsigned int src2, int fac, IMB_BlendMode mode) +{ + unsigned int dst; + int temp; + char *cp, *cp1, *cp2; + + if (fac==0) + return src1; + + cp = (char*)&dst; + cp1 = (char*)&src1; + cp2 = (char*)&src2; + + switch (mode) { + case IMB_BLEND_MIX: + blend_color_mix(cp, cp1, cp2, fac); break; + case IMB_BLEND_ADD: + blend_color_add(cp, cp1, cp2, fac); break; + case IMB_BLEND_SUB: + blend_color_sub(cp, cp1, cp2, fac); break; + case IMB_BLEND_MUL: + blend_color_mul(cp, cp1, cp2, fac); break; + case IMB_BLEND_LIGHTEN: + blend_color_lighten(cp, cp1, cp2, fac); break; + case IMB_BLEND_DARKEN: + blend_color_darken(cp, cp1, cp2, fac); break; + default: + cp[0]= cp1[0]; + cp[1]= cp1[1]; + cp[2]= cp1[2]; + } + + if (mode == IMB_BLEND_ERASE_ALPHA) { + temp= (cp1[3] - fac*cp2[3]/255); + cp[3]= (temp < 0)? 0: temp; + } + else { /* this does ADD_ALPHA also */ + temp= (cp1[3] + fac*cp2[3]/255); + cp[3]= (temp > 255)? 255: temp; + } + + return dst; +} + +static void blend_color_mix_float(float *cp, float *cp1, float *cp2, float fac) +{ + float mfac= 1.0-fac; + cp[0]= mfac*cp1[0] + fac*cp2[0]; + cp[1]= mfac*cp1[1] + fac*cp2[1]; + cp[2]= mfac*cp1[2] + fac*cp2[2]; +} + +static void blend_color_add_float(float *cp, float *cp1, float *cp2, float fac) +{ + cp[0] = cp1[0] + fac*cp2[0]; + cp[1] = cp1[1] + fac*cp2[1]; + cp[2] = cp1[2] + fac*cp2[2]; + + if (cp[0] > 1.0f) cp[0]= 1.0f; + if (cp[1] > 1.0f) cp[1]= 1.0f; + if (cp[2] > 1.0f) cp[2]= 1.0f; +} + +static void blend_color_sub_float(float *cp, float *cp1, float *cp2, float fac) +{ + cp[0] = cp1[0] - fac*cp2[0]; + cp[1] = cp1[1] - fac*cp2[1]; + cp[2] = cp1[2] - fac*cp2[2]; + + if (cp[0] < 0.0f) cp[0]= 0.0f; + if (cp[1] < 0.0f) cp[1]= 0.0f; + if (cp[2] < 0.0f) cp[2]= 0.0f; +} + +static void blend_color_mul_float(float *cp, float *cp1, float *cp2, float fac) +{ + float mfac= 1.0-fac; + + cp[0]= mfac*cp1[0] + fac*(cp1[0]*cp2[0]); + cp[1]= mfac*cp1[1] + fac*(cp1[1]*cp2[1]); + cp[2]= mfac*cp1[2] + fac*(cp1[2]*cp2[2]); +} + +static void blend_color_lighten_float(float *cp, float *cp1, float *cp2, float fac) +{ + /* See if are lighter, if so mix, else dont do anything. + if the pafloat col is darker then the original, then ignore */ + if (cp1[0]+cp1[1]+cp1[2] > cp2[0]+cp2[1]+cp2[2]) { + cp[0]= cp1[0]; + cp[1]= cp1[1]; + cp[2]= cp1[2]; + } + else + blend_color_mix_float(cp, cp1, cp2, fac); +} + +static void blend_color_darken_float(float *cp, float *cp1, float *cp2, float fac) +{ + /* See if were darker, if so mix, else dont do anything. + if the pafloat col is brighter then the original, then ignore */ + if (cp1[0]+cp1[1]+cp1[2] < cp2[0]+cp2[1]+cp2[2]) { + cp[0]= cp1[0]; + cp[1]= cp1[1]; + cp[2]= cp1[2]; + } + else + blend_color_mix_float(cp, cp1, cp2, fac); +} + +void IMB_blend_color_float(float *dst, float *src1, float *src2, float fac, IMB_BlendMode mode) +{ + if (fac==0) { + dst[0]= src1[0]; + dst[1]= src1[1]; + dst[2]= src1[2]; + dst[3]= src1[3]; + return; + } + + switch (mode) { + case IMB_BLEND_MIX: + blend_color_mix_float(dst, src1, src2, fac); break; + case IMB_BLEND_ADD: + blend_color_add_float(dst, src1, src2, fac); break; + case IMB_BLEND_SUB: + blend_color_sub_float(dst, src1, src2, fac); break; + case IMB_BLEND_MUL: + blend_color_mul_float(dst, src1, src2, fac); break; + case IMB_BLEND_LIGHTEN: + blend_color_lighten_float(dst, src1, src2, fac); break; + case IMB_BLEND_DARKEN: + blend_color_darken_float(dst, src1, src2, fac); break; + default: + dst[0]= src1[0]; + dst[1]= src1[1]; + dst[2]= src1[2]; + } + + if (mode == IMB_BLEND_ERASE_ALPHA) { + dst[3]= (src1[3] - fac*src2[3]); + if (dst[3] < 0.0f) dst[3] = 0.0f; + } + else { /* this does ADD_ALPHA also */ + dst[3]= (src1[3] + fac*src2[3]); + if (dst[3] > 1.0f) dst[3] = 1.0f; + } +} + +/* clipping */ + +void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx, + int *desty, int *srcx, int *srcy, int *width, int *height) +{ + int tmp; + + if (dbuf == NULL) return; + + if (*destx < 0) { + *srcx -= *destx; + *width += *destx; + *destx = 0; + } + if (*srcx < 0) { + *destx -= *srcx; + *width += *destx; + *srcx = 0; + } + if (*desty < 0) { + *srcy -= *desty; + *height += *desty; + *desty = 0; + } + if (*srcy < 0) { + *desty -= *srcy; + *height += *desty; + *srcy = 0; + } + + tmp = dbuf->x - *destx; + if (*width > tmp) *width = tmp; + tmp = dbuf->y - *desty; + if (*height > tmp) *height = tmp; + + if (sbuf) { + tmp = sbuf->x - *srcx; + if (*width > tmp) *width = tmp; + tmp = sbuf->y - *srcy; + if (*height > tmp) *height = tmp; + } + + if ((*height <= 0) || (*width <= 0)) { + *width = 0; + *height = 0; + } +} + +/* copy and blend */ + +void IMB_rectcpy(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx, + int desty, int srcx, int srcy, int width, int height) +{ + IMB_rectblend(dbuf, sbuf, destx, desty, srcx, srcy, width, height, + IMB_BLEND_COPY); +} + +void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx, + int desty, int srcx, int srcy, int width, int height, IMB_BlendMode mode) +{ + unsigned int *drect = NULL, *srect = NULL, *dr, *sr; + float *drectf = NULL, *srectf = NULL, *drf, *srf; + int do_float, do_char, srcskip, destskip, x; + + if (dbuf == NULL) return; + + IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &width, &height); + + if (width == 0 || height == 0) return; + if (sbuf && sbuf->channels!=4) return; + if (dbuf->channels!=4) return; + + do_char = (sbuf && sbuf->rect && dbuf->rect); + do_float = (sbuf && sbuf->rect_float && dbuf->rect_float); + + if (do_char) drect = dbuf->rect + desty * dbuf->x + destx; + if (do_float) drectf = dbuf->rect_float + (desty * dbuf->x + destx)*4; + + destskip = dbuf->x; + + if (sbuf) { + if (do_char) srect = sbuf->rect + srcy * sbuf->x + srcx; + if (do_float) srectf = sbuf->rect_float + (srcy * sbuf->x + srcx)*4; + srcskip = sbuf->x; + } else { + srect = drect; + srectf = drectf; + srcskip = destskip; + } + + if (mode == IMB_BLEND_COPY) { + /* copy */ + for (;height > 0; height--) { + if (do_char) { + memcpy(drect,srect, width * sizeof(int)); + drect += destskip; + srect += srcskip; + } + + if (do_float) { + memcpy(drectf,srectf, width * sizeof(float) * 4); + drectf += destskip*4; + srectf += srcskip*4; + } + } + } + else if (mode == IMB_BLEND_COPY_RGB) { + /* copy rgb only */ + for (;height > 0; height--) { + if (do_char) { + dr = drect; + sr = srect; + for (x=width; x > 0; x--, dr++, sr++) { + ((char*)dr)[0]= ((char*)sr)[0]; + ((char*)dr)[1]= ((char*)sr)[1]; + ((char*)dr)[2]= ((char*)sr)[2]; + } + drect += destskip; + srect += srcskip; + } + + if (do_float) { + drf = drectf; + srf = srectf; + for (x=width; x > 0; x--, drf+=4, srf+=4) { + drf[0]= srf[0]; + drf[1]= srf[1]; + drf[2]= srf[2]; + } + drectf += destskip*4; + srectf += srcskip*4; + } + } + } + else if (mode == IMB_BLEND_COPY_ALPHA) { + /* copy alpha only */ + for (;height > 0; height--) { + if (do_char) { + dr = drect; + sr = srect; + for (x=width; x > 0; x--, dr++, sr++) + ((char*)dr)[3]= ((char*)sr)[3]; + drect += destskip; + srect += srcskip; + } + + if (do_float) { + drf = drectf; + srf = srectf; + for (x=width; x > 0; x--, drf+=4, srf+=4) + drf[3]= srf[3]; + drectf += destskip*4; + srectf += srcskip*4; + } + } + } + else { + /* blend */ + for (;height > 0; height--) { + if (do_char) { + dr = drect; + sr = srect; + for (x=width; x > 0; x--, dr++, sr++) + *dr = IMB_blend_color(*dr, *sr, ((char*)sr)[3], mode); + + drect += destskip; + srect += srcskip; + } + + if (do_float) { + drf = drectf; + srf = srectf; + for (x=width; x > 0; x--, drf+=4, srf+=4) + IMB_blend_color_float(drf, drf, srf, srf[3], mode); + + drectf += destskip*4; + srectf += srcskip*4; + } + } + } +} + +void IMB_rectblend_torus(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx, + int desty, int srcx, int srcy, int width, int height, IMB_BlendMode mode) +{ + int origw, origh, w, h; + + if (dbuf->x == 0 || dbuf->y == 0 || sbuf->x == 0 || sbuf->y == 0) + return; + + /* convert destination and source coordinates too be withing image */ + destx = destx % dbuf->x; + if (destx < 0) destx += dbuf->x; + desty = desty % dbuf->y; + if (desty < 0) desty += dbuf->y; + srcx = srcx % sbuf->x; + if (srcx < 0) srcx += sbuf->x; + srcy = srcy % sbuf->y; + if (srcy < 0) srcy += sbuf->y; + + /* clip width of blending area to destination imbuf, to avoid writing the + same pixel twice */ + origw = w = (width > dbuf->x)? dbuf->x: width; + origh = h = (height > dbuf->y)? dbuf->y: height; + + /* clip and blend */ + IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &w, &h); + IMB_rectblend(dbuf, sbuf, destx, desty, srcx, srcy, w, h, mode); + + /* do 3 other rects if needed */ + if (w < origw) + IMB_rectblend(dbuf, sbuf, (destx+w)%dbuf->x, desty, (srcx+w)%sbuf->x, srcy, + origw-w, h, mode); + if (h < origh) + IMB_rectblend(dbuf, sbuf, destx, (desty+h)%dbuf->y, srcx, (srcy+h)%sbuf->y, + w, origh-h, mode); + if ((w < origw) && (h < origh)) + IMB_rectblend(dbuf, sbuf, (destx+w)%dbuf->x, (desty+h)%dbuf->y, + (srcx+w)%sbuf->x, (srcy+h)%sbuf->y, origw-w, origh-h, mode); +} + +/* fill */ + +void IMB_rectfill(struct ImBuf *drect, float col[4]) +{ + int num; + + if(drect->rect) { + unsigned int *rrect = drect->rect; + char ccol[4]; + + ccol[0]= (int)(col[0]*255); + ccol[1]= (int)(col[1]*255); + ccol[2]= (int)(col[2]*255); + ccol[3]= (int)(col[3]*255); + + num = drect->x * drect->y; + for (;num > 0; num--) + *rrect++ = *((unsigned int*)ccol); + } + + if(drect->rect_float) { + float *rrectf = drect->rect_float; + + num = drect->x * drect->y; + for (;num > 0; num--) { + *rrectf++ = col[0]; + *rrectf++ = col[1]; + *rrectf++ = col[2]; + *rrectf++ = col[3]; + } + } +} + +/* maybe we should use BKE_utildefines.h */ +#define FTOCHAR(val) (val<=0.0f ? 0: (val>=1.0f ? 255: (char)(255.99f*val))) +#define CLAMP(a, b, c) if((a)<(b)) (a)=(b); else if((a)>(c)) (a)=(c) +#define SWAP(type, a, b) { type sw_ap; sw_ap=(a); (a)=(b); (b)=sw_ap; } + +void buf_rectfill_area(unsigned char *rect, float *rectf, int width, int height, float *col, int x1, int y1, int x2, int y2) +{ + int i, j; + float a, ai; + if ((!rect && !rectf) || (!col) || col[3]==0.0) + return; + + /* sanity checks for coords */ + CLAMP(x1, 0, width); + CLAMP(x2, 0, width); + CLAMP(y1, 0, height); + CLAMP(y2, 0, height); + + if (x1>x2) SWAP(int,x1,x2); + if (y1>y2) SWAP(int,y1,y2); + if (x1==x2 || y1==y2) return; + + a = col[3]; + ai = 1-a; + + + if (rect) { + unsigned char *pixel; + unsigned char chr=0, chg=0, chb=0; + float fr=0, fg=0, fb=0; + + if (a == 1.0) { + chr = FTOCHAR(col[0]); + chg = FTOCHAR(col[1]); + chb = FTOCHAR(col[2]); + } else { + fr = col[0]*a; + fg = col[1]*a; + fb = col[2]*a; + } + for (j = 0; j < y2-y1; j++) { + for (i = 0; i < x2-x1; i++) { + pixel = rect + 4 * (((y1 + j) * width) + (x1 + i)); + if (pixel >= rect && pixel < rect+ (4 * (width * height))) { + if (a == 1.0) { + pixel[0] = chr; + pixel[1] = chg; + pixel[2] = chb; + } else { + pixel[0] = (char)(fr + ((float)pixel[0]*ai)); + pixel[1] = (char)(fg + ((float)pixel[1]*ai)); + pixel[2] = (char)(fb + ((float)pixel[2]*ai)); + } + } + } + } + } + + if (rectf) { + float *pixel; + for (j = 0; j < y2-y1; j++) { + for (i = 0; i < x2-x1; i++) { + pixel = rectf + 4 * (((y1 + j) * width) + (x1 + i)); + if (a == 1.0) { + pixel[0] = col[0]; + pixel[1] = col[1]; + pixel[2] = col[2]; + } else { + pixel[0] = (col[0]*a) + (pixel[0]*ai); + pixel[1] = (col[1]*a) + (pixel[1]*ai); + pixel[2] = (col[2]*a) + (pixel[2]*ai); + } + } + } + } +} + +void IMB_rectfill_area(struct ImBuf *ibuf, float *col, int x1, int y1, int x2, int y2) +{ + if (!ibuf) return; + buf_rectfill_area((unsigned char *) ibuf->rect, ibuf->rect_float, ibuf->x, ibuf->y, col, x1, y1, x2, y2); +} diff --git a/source/blender/imbuf/intern/rotate.c b/source/blender/imbuf/intern/rotate.c new file mode 100644 index 00000000000..42b30d6284f --- /dev/null +++ b/source/blender/imbuf/intern/rotate.c @@ -0,0 +1,120 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * rotate.c + * + * $Id$ + */ + +#include "BLI_blenlib.h" + +#include "imbuf.h" +#include "imbuf_patch.h" +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "IMB_allocimbuf.h" + +void IMB_flipy(struct ImBuf * ibuf) +{ + short x, y; + unsigned int *top, *bottom, do_float=0, *line; + float *topf=NULL, *bottomf=NULL, *linef=NULL; + + if (ibuf == NULL) return; + if (ibuf->rect == NULL) return; + + if (ibuf->rect_float) do_float =1; + + x = ibuf->x; + y = ibuf->y; + + top = ibuf->rect; + bottom = top + ((y-1) * x); + line= MEM_mallocN(x*sizeof(int), "linebuf"); + + if (do_float) { + topf= ibuf->rect_float; + bottomf = topf + 4*((y-1) * x); + linef= MEM_mallocN(4*x*sizeof(float), "linebuff"); + } + y >>= 1; + + for(;y>0;y--) { + + memcpy(line, top, x*sizeof(int)); + memcpy(top, bottom, x*sizeof(int)); + memcpy(bottom, line, x*sizeof(int)); + bottom -= x; + top+= x; + + if(do_float) { + memcpy(linef, topf, 4*x*sizeof(float)); + memcpy(topf, bottomf, 4*x*sizeof(float)); + memcpy(bottomf, linef, 4*x*sizeof(float)); + bottomf -= 4*x; + topf+= 4*x; + } + } + + MEM_freeN(line); + if(linef) MEM_freeN(linef); +} + +void IMB_flipx(struct ImBuf * ibuf) +{ + short x, y, xr, xl, yi; + unsigned int px; + float px_f[4]; + + if (ibuf == NULL) return; + + x = ibuf->x; + y = ibuf->y; + + if (ibuf->rect) { + for(yi=y-1;yi>=0;yi--) { + for(xr=x-1, xl=0; xr>=xl; xr--, xl++) { + px = ibuf->rect[(x*yi)+xr]; + ibuf->rect[(x*yi)+xr] = ibuf->rect[(x*yi)+xl]; + ibuf->rect[(x*yi)+xl] = px; + } + } + } + + if (ibuf->rect_float) { + for(yi=y-1;yi>=0;yi--) { + for(xr=x-1, xl=0; xr>=xl; xr--, xl++) { + memcpy(&px_f, &ibuf->rect_float[((x*yi)+xr)*4], 4*sizeof(float)); + memcpy(&ibuf->rect_float[((x*yi)+xr)*4], &ibuf->rect_float[((x*yi)+xl)*4], 4*sizeof(float)); + memcpy(&ibuf->rect_float[((x*yi)+xl)*4], &px_f, 4*sizeof(float)); + } + } + } +} diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c new file mode 100644 index 00000000000..cd933cb0767 --- /dev/null +++ b/source/blender/imbuf/intern/scaling.c @@ -0,0 +1,1267 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * allocimbuf.c + * + * $Id$ + */ + +#include "BLI_blenlib.h" + +#include "imbuf.h" +#include "imbuf_patch.h" +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "IMB_allocimbuf.h" +#include "IMB_filter.h" + +/************************************************************************/ +/* SCALING */ +/************************************************************************/ + + +struct ImBuf *IMB_half_x(struct ImBuf *ibuf1) +{ + struct ImBuf *ibuf2; + uchar *p1,*_p1,*dest; + short a,r,g,b,x,y; + float af,rf,gf,bf, *p1f, *_p1f, *destf; + int do_rect, do_float; + + if (ibuf1==NULL) return (0); + if (ibuf1->rect==NULL && ibuf1->rect_float==NULL) return (0); + + do_rect= (ibuf1->rect != NULL); + do_float= (ibuf1->rect_float != NULL); + + if (ibuf1->x <= 1) return(IMB_dupImBuf(ibuf1)); + + ibuf2 = IMB_allocImBuf((ibuf1->x)/2, ibuf1->y, ibuf1->depth, ibuf1->flags, 0); + if (ibuf2==NULL) return (0); + + _p1 = (uchar *) ibuf1->rect; + dest=(uchar *) ibuf2->rect; + + _p1f = ibuf1->rect_float; + destf= ibuf2->rect_float; + + for(y=ibuf2->y;y>0;y--){ + p1 = _p1; + p1f = _p1f; + for(x = ibuf2->x ; x>0 ; x--){ + if (do_rect) { + a = *(p1++) ; + b = *(p1++) ; + g = *(p1++) ; + r = *(p1++); + a += *(p1++) ; + b += *(p1++) ; + g += *(p1++) ; + r += *(p1++); + *(dest++) = a >> 1; + *(dest++) = b >> 1; + *(dest++) = g >> 1; + *(dest++) = r >> 1; + } + if (do_float) { + af = *(p1f++); + bf = *(p1f++); + gf = *(p1f++); + rf = *(p1f++); + af += *(p1f++); + bf += *(p1f++); + gf += *(p1f++); + rf += *(p1f++); + *(destf++) = 0.5f*af; + *(destf++) = 0.5f*bf; + *(destf++) = 0.5f*gf; + *(destf++) = 0.5f*rf; + } + } + if (do_rect) _p1 += (ibuf1->x << 2); + if (do_float) _p1f += (ibuf1->x << 2); + } + return (ibuf2); +} + + +struct ImBuf *IMB_double_fast_x(struct ImBuf *ibuf1) +{ + struct ImBuf *ibuf2; + int *p1,*dest, i, col, do_rect, do_float; + float *p1f, *destf; + + if (ibuf1==NULL) return (0); + if (ibuf1->rect==NULL && ibuf1->rect_float==NULL) return (0); + + do_rect= (ibuf1->rect != NULL); + do_float= (ibuf1->rect_float != NULL); + + ibuf2 = IMB_allocImBuf(2 * ibuf1->x , ibuf1->y , ibuf1->depth, ibuf1->flags, 0); + if (ibuf2==NULL) return (0); + + p1 = (int *) ibuf1->rect; + dest=(int *) ibuf2->rect; + p1f = (float *)ibuf1->rect_float; + destf = (float *)ibuf2->rect_float; + + for(i = ibuf1->y * ibuf1->x ; i>0 ; i--) { + if (do_rect) { + col = *p1++; + *dest++ = col; + *dest++ = col; + } + if (do_float) { + destf[0]= destf[4] =p1f[0]; + destf[1]= destf[5] =p1f[1]; + destf[2]= destf[6] =p1f[2]; + destf[3]= destf[7] =p1f[3]; + destf+= 8; + p1f+= 4; + } + } + + return (ibuf2); +} + +struct ImBuf *IMB_double_x(struct ImBuf *ibuf1) +{ + struct ImBuf *ibuf2; + + if (ibuf1==NULL) return (0); + if (ibuf1->rect==NULL && ibuf1->rect_float==NULL) return (0); + + ibuf2 = IMB_double_fast_x(ibuf1); + + imb_filterx(ibuf2); + return (ibuf2); +} + + +struct ImBuf *IMB_half_y(struct ImBuf *ibuf1) +{ + struct ImBuf *ibuf2; + uchar *p1,*p2,*_p1,*dest; + short a,r,g,b,x,y; + int do_rect, do_float; + float af,rf,gf,bf,*p1f,*p2f,*_p1f,*destf; + + p1= p2= NULL; + p1f= p2f= NULL; + if (ibuf1==NULL) return (0); + if (ibuf1->rect==NULL && ibuf1->rect_float==NULL) return (0); + if (ibuf1->y <= 1) return(IMB_dupImBuf(ibuf1)); + + do_rect= (ibuf1->rect != NULL); + do_float= (ibuf1->rect_float != NULL); + + ibuf2 = IMB_allocImBuf(ibuf1->x , (ibuf1->y) / 2 , ibuf1->depth, ibuf1->flags, 0); + if (ibuf2==NULL) return (0); + + _p1 = (uchar *) ibuf1->rect; + dest=(uchar *) ibuf2->rect; + _p1f = (float *) ibuf1->rect_float; + destf= (float *) ibuf2->rect_float; + + for(y=ibuf2->y ; y>0 ; y--){ + if (do_rect) { + p1 = _p1; + p2 = _p1 + (ibuf1->x << 2); + } + if (do_float) { + p1f = _p1f; + p2f = _p1f + (ibuf1->x << 2); + } + for(x = ibuf2->x ; x>0 ; x--){ + if (do_rect) { + a = *(p1++) ; + b = *(p1++) ; + g = *(p1++) ; + r = *(p1++); + a += *(p2++) ; + b += *(p2++) ; + g += *(p2++) ; + r += *(p2++); + *(dest++) = a >> 1; + *(dest++) = b >> 1; + *(dest++) = g >> 1; + *(dest++) = r >> 1; + } + if (do_float) { + af = *(p1f++) ; + bf = *(p1f++) ; + gf = *(p1f++) ; + rf = *(p1f++); + af += *(p2f++) ; + bf += *(p2f++) ; + gf += *(p2f++) ; + rf += *(p2f++); + *(destf++) = 0.5f*af; + *(destf++) = 0.5f*bf; + *(destf++) = 0.5f*gf; + *(destf++) = 0.5f*rf; + } + } + if (do_rect) _p1 += (ibuf1->x << 3); + if (do_float) _p1f += (ibuf1->x << 3); + } + return (ibuf2); +} + + +struct ImBuf *IMB_double_fast_y(struct ImBuf *ibuf1) +{ + struct ImBuf *ibuf2; + int *p1, *dest1, *dest2; + float *p1f, *dest1f, *dest2f; + short x,y; + int do_rect, do_float; + + if (ibuf1==NULL) return (0); + if (ibuf1->rect==NULL && ibuf1->rect_float==NULL) return (0); + + do_rect= (ibuf1->rect != NULL); + do_float= (ibuf1->rect_float != NULL); + + ibuf2 = IMB_allocImBuf(ibuf1->x , 2 * ibuf1->y , ibuf1->depth, ibuf1->flags, 0); + if (ibuf2==NULL) return (0); + + p1 = (int *) ibuf1->rect; + dest1= (int *) ibuf2->rect; + p1f = (float *) ibuf1->rect_float; + dest1f= (float *) ibuf2->rect_float; + + for(y = ibuf1->y ; y>0 ; y--){ + if (do_rect) { + dest2 = dest1 + ibuf2->x; + for(x = ibuf2->x ; x>0 ; x--) *dest1++ = *dest2++ = *p1++; + dest1 = dest2; + } + if (do_float) { + dest2f = dest1f + (4*ibuf2->x); + for(x = ibuf2->x*4 ; x>0 ; x--) *dest1f++ = *dest2f++ = *p1f++; + dest1f = dest2f; + } + } + + return (ibuf2); +} + +struct ImBuf *IMB_double_y(struct ImBuf *ibuf1) +{ + struct ImBuf *ibuf2; + + if (ibuf1==NULL) return (0); + if (ibuf1->rect==NULL) return (0); + + ibuf2 = IMB_double_fast_y(ibuf1); + + IMB_filtery(ibuf2); + return (ibuf2); +} + + +struct ImBuf *IMB_onehalf(struct ImBuf *ibuf1) +{ + struct ImBuf *ibuf2; + uchar *p1, *p2 = NULL, *dest; + float *p1f, *destf, *p2f = NULL; + int x,y; + int do_rect, do_float; + + if (ibuf1==NULL) return (0); + if (ibuf1->rect==NULL && ibuf1->rect_float==NULL) return (0); + + do_rect= (ibuf1->rect != NULL); + do_float= (ibuf1->rect_float != NULL); + + if (ibuf1->x <= 1) return(IMB_half_y(ibuf1)); + if (ibuf1->y <= 1) return(IMB_half_x(ibuf1)); + + ibuf2=IMB_allocImBuf((ibuf1->x)/2, (ibuf1->y)/2, ibuf1->depth, ibuf1->flags, 0); + if (ibuf2==NULL) return (0); + + p1f = ibuf1->rect_float; + destf=ibuf2->rect_float; + p1 = (uchar *) ibuf1->rect; + dest=(uchar *) ibuf2->rect; + + for(y=ibuf2->y;y>0;y--){ + if (do_rect) p2 = p1 + (ibuf1->x << 2); + if (do_float) p2f = p1f + (ibuf1->x << 2); + for(x=ibuf2->x;x>0;x--){ + if (do_rect) { + dest[0] = (p1[0] + p2[0] + p1[4] + p2[4]) >> 2; + dest[1] = (p1[1] + p2[1] + p1[5] + p2[5]) >> 2; + dest[2] = (p1[2] + p2[2] + p1[6] + p2[6]) >> 2; + dest[3] = (p1[3] + p2[3] + p1[7] + p2[7]) >> 2; + p1 += 8; + p2 += 8; + dest += 4; + } + if (do_float){ + destf[0] = 0.25f*(p1f[0] + p2f[0] + p1f[4] + p2f[4]); + destf[1] = 0.25f*(p1f[1] + p2f[1] + p1f[5] + p2f[5]); + destf[2] = 0.25f*(p1f[2] + p2f[2] + p1f[6] + p2f[6]); + destf[3] = 0.25f*(p1f[3] + p2f[3] + p1f[7] + p2f[7]); + p1f += 8; + p2f += 8; + destf += 4; + } + } + if (do_rect) p1=p2; + if (do_float) p1f=p2f; + if(ibuf1->x & 1) { + if (do_rect) p1+=4; + if (do_float) p1f+=4; + } + } + return (ibuf2); +} + + + +struct ImBuf *IMB_onethird(struct ImBuf *ibuf1) +{ + struct ImBuf *ibuf2; + uchar *p1,*p2,*p3,*dest; + float *p1f, *p2f, *p3f, *destf; + int do_rect, do_float; + short a,r,g,b,x,y,i; + float af,rf,gf,bf; + + p2= p3= NULL; + p2f= p3f= NULL; + if (ibuf1==NULL) return (0); + if (ibuf1->rect==NULL && ibuf1->rect_float==NULL) return (0); + + do_rect= (ibuf1->rect != NULL); + do_float= (ibuf1->rect_float != NULL); + + ibuf2=IMB_allocImBuf((ibuf1->x)/3, (ibuf1->y)/3, ibuf1->depth, ibuf1->flags, 0); + if (ibuf2==NULL) return (0); + + p1f = ibuf1->rect_float; + destf = ibuf2->rect_float; + p1 = (uchar *) ibuf1->rect; + dest=(uchar *) ibuf2->rect; + + for(y=ibuf2->y;y>0;y--){ + if (do_rect) { + p2 = p1 + (ibuf1->x << 2); + p3 = p2 + (ibuf1->x << 2); + } + if (do_float) { + p2f = p1f + (ibuf1->x <<2); + p3f = p2f + (ibuf1->x <<2); + } + for(x=ibuf2->x;x>0;x--){ + a=r=g=b=0; + af=rf=gf=bf=0; + for (i=3;i>0;i--){ + if (do_rect) { + a += *(p1++) + *(p2++) + *(p3++); + b += *(p1++) + *(p2++) + *(p3++); + g += *(p1++) + *(p2++) + *(p3++); + r += *(p1++) + *(p2++) + *(p3++); + } + if (do_float) { + af += *(p1f++) + *(p2f++) + *(p3f++); + bf += *(p1f++) + *(p2f++) + *(p3f++); + gf += *(p1f++) + *(p2f++) + *(p3f++); + rf += *(p1f++) + *(p2f++) + *(p3f++); + } + } + if (do_rect) { + *(dest++) = a/9; + *(dest++) = b/9; + *(dest++) = g/9; + *(dest++) = r/9; + } + if (do_float) { + *(destf++) = af/9.0f; + *(destf++) = bf/9.0f; + *(destf++) = gf/9.0f; + *(destf++) = rf/9.0f; + } + } + if (do_rect) p1=p3; + if (do_float) p1f = p3f; + } + return (ibuf2); +} + + +struct ImBuf *IMB_halflace(struct ImBuf *ibuf1) +{ + struct ImBuf *ibuf2; + uchar *p1,*p2,*dest; + float *p1f,*p2f,*destf; + short a,r,g,b,x,y,i; + float af,rf,gf,bf; + int do_rect, do_float; + + p2= NULL; + p2f= NULL; + if (ibuf1==NULL) return (0); + if (ibuf1->rect==NULL && ibuf1->rect_float==NULL) return (0); + + do_rect= (ibuf1->rect != NULL); + do_float= (ibuf1->rect_float != NULL); + + ibuf2=IMB_allocImBuf((ibuf1->x)/4, (ibuf1->y)/2, ibuf1->depth, ibuf1->flags, 0); + if (ibuf2==NULL) return (0); + + p1f = ibuf1->rect_float; + destf= ibuf2->rect_float; + p1 = (uchar *) ibuf1->rect; + dest=(uchar *) ibuf2->rect; + + for(y= ibuf2->y / 2 ; y>0;y--){ + if (do_rect) p2 = p1 + (ibuf1->x << 3); + if (do_float) p2f = p1f + (ibuf1->x << 3); + for(x = 2 * ibuf2->x;x>0;x--){ + a=r=g=b=0; + af=rf=gf=bf=0; + for (i=4;i>0;i--){ + if (do_rect) { + a += *(p1++) + *(p2++); + b += *(p1++) + *(p2++); + g += *(p1++) + *(p2++); + r += *(p1++) + *(p2++); + } + if (do_float) { + af += *(p1f++) + *(p2f++); + bf += *(p1f++) + *(p2f++); + gf += *(p1f++) + *(p2f++); + rf += *(p1f++) + *(p2f++); + } + } + if (do_rect) { + *(dest++) = a >> 3; + *(dest++) = b >> 3; + *(dest++) = g >> 3; + *(dest++) = r >> 3; + } + if (do_float) { + *(destf++) = 0.125f*af; + *(destf++) = 0.125f*bf; + *(destf++) = 0.125f*gf; + *(destf++) = 0.125f*rf; + } + } + if (do_rect) p1 = p2; + if (do_float) p1f = p2f; + } + return (ibuf2); +} + + +static struct ImBuf *scaledownx(struct ImBuf *ibuf, int newx) +{ + uchar *rect, *_newrect, *newrect; + float *rectf, *_newrectf, *newrectf; + float sample, add, val[4], nval[4], valf[4], nvalf[4]; + int x, y, do_rect = 0, do_float = 0; + + rectf= _newrectf= newrectf= NULL; + rect=_newrect= newrect= NULL; + nval[0]= nval[1]= nval[2]= nval[3]= 0.0f; + nvalf[0]=nvalf[1]=nvalf[2]=nvalf[3]= 0.0f; + + if (ibuf==NULL) return(0); + if (ibuf->rect==NULL && ibuf->rect_float==NULL) return (ibuf); + + if (ibuf->rect) { + do_rect = 1; + _newrect = MEM_mallocN(newx * ibuf->y * sizeof(int), "scaledownx"); + if (_newrect==NULL) return(ibuf); + } + if (ibuf->rect_float) { + do_float = 1; + _newrectf = MEM_mallocN(newx * ibuf->y * sizeof(float) * 4, "scaledownxf"); + if (_newrectf==NULL) { + if (_newrect) MEM_freeN(_newrect); + return(ibuf); + } + } + + add = (ibuf->x - 0.001) / newx; + + if (do_rect) { + rect = (uchar *) ibuf->rect; + newrect = _newrect; + } + if (do_float) { + rectf = ibuf->rect_float; + newrectf = _newrectf; + } + + for (y = ibuf->y; y>0 ; y--) { + sample = 0.0f; + val[0]= val[1]= val[2]= val[3]= 0.0f; + valf[0]=valf[1]=valf[2]=valf[3]= 0.0f; + + for (x = newx ; x>0 ; x--) { + if (do_rect) { + nval[0] = - val[0] * sample; + nval[1] = - val[1] * sample; + nval[2] = - val[2] * sample; + nval[3] = - val[3] * sample; + } + if (do_float) { + nvalf[0] = - valf[0] * sample; + nvalf[1] = - valf[1] * sample; + nvalf[2] = - valf[2] * sample; + nvalf[3] = - valf[3] * sample; + } + + sample += add; + + while (sample >= 1.0f){ + sample -= 1.0f; + + if (do_rect) { + nval[0] += rect[0]; + nval[1] += rect[1]; + nval[2] += rect[2]; + nval[3] += rect[3]; + rect += 4; + } + if (do_float) { + nvalf[0] += rectf[0]; + nvalf[1] += rectf[1]; + nvalf[2] += rectf[2]; + nvalf[3] += rectf[3]; + rectf += 4; + } + } + + if (do_rect) { + val[0]= rect[0];val[1]= rect[1];val[2]= rect[2];val[3]= rect[3]; + rect += 4; + + newrect[0] = ((nval[0] + sample * val[0])/add + 0.5f); + newrect[1] = ((nval[1] + sample * val[1])/add + 0.5f); + newrect[2] = ((nval[2] + sample * val[2])/add + 0.5f); + newrect[3] = ((nval[3] + sample * val[3])/add + 0.5f); + + newrect += 4; + } + if (do_float) { + + valf[0]= rectf[0];valf[1]= rectf[1];valf[2]= rectf[2];valf[3]= rectf[3]; + rectf += 4; + + newrectf[0] = ((nvalf[0] + sample * valf[0])/add); + newrectf[1] = ((nvalf[1] + sample * valf[1])/add); + newrectf[2] = ((nvalf[2] + sample * valf[2])/add); + newrectf[3] = ((nvalf[3] + sample * valf[3])/add); + + newrectf += 4; + } + + sample -= 1.0f; + } + } + + if (do_rect) { + imb_freerectImBuf(ibuf); + ibuf->mall |= IB_rect; + ibuf->rect = (unsigned int *) _newrect; + } + if (do_float) { + imb_freerectfloatImBuf(ibuf); + ibuf->mall |= IB_rectfloat; + ibuf->rect_float = _newrectf; + } + + ibuf->x = newx; + return(ibuf); +} + + +static struct ImBuf *scaledowny(struct ImBuf *ibuf, int newy) +{ + uchar *rect, *_newrect, *newrect; + float *rectf, *_newrectf, *newrectf; + float sample, add, val[4], nval[4], valf[4], nvalf[4]; + int x, y, skipx, do_rect = 0, do_float = 0; + + rectf= _newrectf= newrectf= NULL; + rect= _newrect= newrect= NULL; + nval[0]= nval[1]= nval[2]= nval[3]= 0.0f; + nvalf[0]=nvalf[1]=nvalf[2]=nvalf[3]= 0.0f; + + if (ibuf==NULL) return(0); + if (ibuf->rect==NULL && ibuf->rect_float==NULL) return (ibuf); + + if (ibuf->rect) { + do_rect = 1; + _newrect = MEM_mallocN(newy * ibuf->x * sizeof(int), "scaledowny"); + if (_newrect==NULL) return(ibuf); + } + if (ibuf->rect_float) { + do_float = 1; + _newrectf = MEM_mallocN(newy * ibuf->x * sizeof(float) * 4, "scaldownyf"); + if (_newrectf==NULL) { + if (_newrect) MEM_freeN(_newrect); + return(ibuf); + } + } + + add = (ibuf->y - 0.001) / newy; + skipx = 4 * ibuf->x; + + for (x = skipx - 4; x>=0 ; x-= 4) { + if (do_rect) { + rect = ((uchar *) ibuf->rect) + x; + newrect = _newrect + x; + } + if (do_float) { + rectf = ibuf->rect_float + x; + newrectf = _newrectf + x; + } + + sample = 0.0f; + val[0]= val[1]= val[2]= val[3]= 0.0f; + valf[0]=valf[1]=valf[2]=valf[3]= 0.0f; + + for (y = newy ; y>0 ; y--) { + if (do_rect) { + nval[0] = - val[0] * sample; + nval[1] = - val[1] * sample; + nval[2] = - val[2] * sample; + nval[3] = - val[3] * sample; + } + if (do_float) { + nvalf[0] = - valf[0] * sample; + nvalf[1] = - valf[1] * sample; + nvalf[2] = - valf[2] * sample; + nvalf[3] = - valf[3] * sample; + } + + sample += add; + + while (sample >= 1.0) { + sample -= 1.0; + + if (do_rect) { + nval[0] += rect[0]; + nval[1] += rect[1]; + nval[2] += rect[2]; + nval[3] += rect[3]; + rect += skipx; + } + if (do_float) { + nvalf[0] += rectf[0]; + nvalf[1] += rectf[1]; + nvalf[2] += rectf[2]; + nvalf[3] += rectf[3]; + rectf += skipx; + } + } + + if (do_rect) { + val[0]= rect[0];val[1]= rect[1];val[2]= rect[2];val[3]= rect[3]; + rect += skipx; + + newrect[0] = ((nval[0] + sample * val[0])/add + 0.5f); + newrect[1] = ((nval[1] + sample * val[1])/add + 0.5f); + newrect[2] = ((nval[2] + sample * val[2])/add + 0.5f); + newrect[3] = ((nval[3] + sample * val[3])/add + 0.5f); + + newrect += skipx; + } + if (do_float) { + + valf[0]= rectf[0];valf[1]= rectf[1];valf[2]= rectf[2];valf[3]= rectf[3]; + rectf += skipx; + + newrectf[0] = ((nvalf[0] + sample * valf[0])/add); + newrectf[1] = ((nvalf[1] + sample * valf[1])/add); + newrectf[2] = ((nvalf[2] + sample * valf[2])/add); + newrectf[3] = ((nvalf[3] + sample * valf[3])/add); + + newrectf += skipx; + } + + sample -= 1.0; + } + } + + if (do_rect) { + imb_freerectImBuf(ibuf); + ibuf->mall |= IB_rect; + ibuf->rect = (unsigned int *) _newrect; + } + if (do_float) { + imb_freerectfloatImBuf(ibuf); + ibuf->mall |= IB_rectfloat; + ibuf->rect_float = (float *) _newrectf; + } + + ibuf->y = newy; + return(ibuf); +} + + +static struct ImBuf *scaleupx(struct ImBuf *ibuf, int newx) +{ + uchar *rect,*_newrect=NULL,*newrect; + float *rectf,*_newrectf=NULL,*newrectf; + float sample,add; + float val_a,nval_a,diff_a; + float val_b,nval_b,diff_b; + float val_g,nval_g,diff_g; + float val_r,nval_r,diff_r; + float val_af,nval_af,diff_af; + float val_bf,nval_bf,diff_bf; + float val_gf,nval_gf,diff_gf; + float val_rf,nval_rf,diff_rf; + int x,y, do_rect = 0, do_float = 0; + + val_a = nval_a = diff_a = val_b = nval_b = diff_b = 0; + val_g = nval_g = diff_g = val_r = nval_r = diff_r = 0; + val_af = nval_af = diff_af = val_bf = nval_bf = diff_bf = 0; + val_gf = nval_gf = diff_gf = val_rf = nval_rf = diff_rf = 0; + if (ibuf==NULL) return(0); + if (ibuf->rect==NULL && ibuf->rect_float==NULL) return (ibuf); + + if (ibuf->rect) { + do_rect = 1; + _newrect = MEM_mallocN(newx * ibuf->y * sizeof(int), "scaleupx"); + if (_newrect==NULL) return(ibuf); + } + if (ibuf->rect_float) { + do_float = 1; + _newrectf = MEM_mallocN(newx * ibuf->y * sizeof(float) * 4, "scaleupxf"); + if (_newrectf==NULL) { + if (_newrect) MEM_freeN(_newrect); + return(ibuf); + } + } + + add = (ibuf->x - 1.001) / (newx - 1.0); + + rect = (uchar *) ibuf->rect; + rectf = (float *) ibuf->rect_float; + newrect = _newrect; + newrectf = _newrectf; + + for (y = ibuf->y; y>0 ; y--){ + + sample = 0; + + if (do_rect) { + val_a = rect[0] ; + nval_a = rect[4]; + diff_a = nval_a - val_a ; + val_a += 0.5; + + val_b = rect[1] ; + nval_b = rect[5]; + diff_b = nval_b - val_b ; + val_b += 0.5; + + val_g = rect[2] ; + nval_g = rect[6]; + diff_g = nval_g - val_g ; + val_g += 0.5; + + val_r = rect[3] ; + nval_r = rect[7]; + diff_r = nval_r - val_r ; + val_r += 0.5; + + rect += 8; + } + if (do_float) { + val_af = rectf[0] ; + nval_af = rectf[4]; + diff_af = nval_af - val_af; + + val_bf = rectf[1] ; + nval_bf = rectf[5]; + diff_bf = nval_bf - val_bf; + + val_gf = rectf[2] ; + nval_gf = rectf[6]; + diff_gf = nval_gf - val_gf; + + val_rf = rectf[3] ; + nval_rf = rectf[7]; + diff_rf = nval_rf - val_rf; + + rectf += 8; + } + for (x = newx ; x>0 ; x--){ + if (sample >= 1.0){ + sample -= 1.0; + + if (do_rect) { + val_a = nval_a ; + nval_a = rect[0] ; + diff_a = nval_a - val_a ; + val_a += 0.5; + + val_b = nval_b ; + nval_b = rect[1] ; + diff_b = nval_b - val_b ; + val_b += 0.5; + + val_g = nval_g ; + nval_g = rect[2] ; + diff_g = nval_g - val_g ; + val_g += 0.5; + + val_r = nval_r ; + nval_r = rect[3] ; + diff_r = nval_r - val_r ; + val_r += 0.5; + rect += 4; + } + if (do_float) { + val_af = nval_af ; + nval_af = rectf[0] ; + diff_af = nval_af - val_af ; + + val_bf = nval_bf ; + nval_bf = rectf[1] ; + diff_bf = nval_bf - val_bf ; + + val_gf = nval_gf ; + nval_gf = rectf[2] ; + diff_gf = nval_gf - val_gf ; + + val_rf = nval_rf ; + nval_rf = rectf[3] ; + diff_rf = nval_rf - val_rf; + rectf += 4; + } + } + if (do_rect) { + newrect[0] = val_a + sample * diff_a; + newrect[1] = val_b + sample * diff_b; + newrect[2] = val_g + sample * diff_g; + newrect[3] = val_r + sample * diff_r; + newrect += 4; + } + if (do_float) { + newrectf[0] = val_af + sample * diff_af; + newrectf[1] = val_bf + sample * diff_bf; + newrectf[2] = val_gf + sample * diff_gf; + newrectf[3] = val_rf + sample * diff_rf; + newrectf += 4; + } + sample += add; + } + } + + if (do_rect) { + imb_freerectImBuf(ibuf); + ibuf->mall |= IB_rect; + ibuf->rect = (unsigned int *) _newrect; + } + if (do_float) { + imb_freerectfloatImBuf(ibuf); + ibuf->mall |= IB_rectfloat; + ibuf->rect_float = (float *) _newrectf; + } + + ibuf->x = newx; + return(ibuf); +} + +static struct ImBuf *scaleupy(struct ImBuf *ibuf, int newy) +{ + uchar *rect,*_newrect=NULL,*newrect; + float *rectf,*_newrectf=NULL,*newrectf; + float sample,add; + float val_a,nval_a,diff_a; + float val_b,nval_b,diff_b; + float val_g,nval_g,diff_g; + float val_r,nval_r,diff_r; + float val_af,nval_af,diff_af; + float val_bf,nval_bf,diff_bf; + float val_gf,nval_gf,diff_gf; + float val_rf,nval_rf,diff_rf; + int x,y, do_rect = 0, do_float = 0, skipx; + + val_a = nval_a = diff_a = val_b = nval_b = diff_b = 0; + val_g = nval_g = diff_g = val_r = nval_r = diff_r = 0; + val_af = nval_af = diff_af = val_bf = nval_bf = diff_bf = 0; + val_gf = nval_gf = diff_gf = val_rf = nval_rf = diff_rf = 0; + if (ibuf==NULL) return(0); + if (ibuf->rect==NULL && ibuf->rect_float==NULL) return (ibuf); + + if (ibuf->rect) { + do_rect = 1; + _newrect = MEM_mallocN(ibuf->x * newy * sizeof(int), "scaleupy"); + if (_newrect==NULL) return(ibuf); + } + if (ibuf->rect_float) { + do_float = 1; + _newrectf = MEM_mallocN(ibuf->x * newy * sizeof(float) * 4, "scaleupyf"); + if (_newrectf==NULL) { + if (_newrect) MEM_freeN(_newrect); + return(ibuf); + } + } + + add = (ibuf->y - 1.001) / (newy - 1.0); + skipx = 4 * ibuf->x; + + rect = (uchar *) ibuf->rect; + rectf = (float *) ibuf->rect_float; + newrect = _newrect; + newrectf = _newrectf; + + for (x = ibuf->x; x>0 ; x--){ + + sample = 0; + if (do_rect) { + rect = ((uchar *)ibuf->rect) + 4*(x-1); + newrect = _newrect + 4*(x-1); + + val_a = rect[0] ; + nval_a = rect[skipx]; + diff_a = nval_a - val_a ; + val_a += 0.5; + + val_b = rect[1] ; + nval_b = rect[skipx+1]; + diff_b = nval_b - val_b ; + val_b += 0.5; + + val_g = rect[2] ; + nval_g = rect[skipx+2]; + diff_g = nval_g - val_g ; + val_g += 0.5; + + val_r = rect[3] ; + nval_r = rect[skipx+4]; + diff_r = nval_r - val_r ; + val_r += 0.5; + + rect += 2*skipx; + } + if (do_float) { + rectf = ((float *)ibuf->rect_float) + 4*(x-1); + newrectf = _newrectf + 4*(x-1); + + val_af = rectf[0] ; + nval_af = rectf[skipx]; + diff_af = nval_af - val_af; + + val_bf = rectf[1] ; + nval_bf = rectf[skipx+1]; + diff_bf = nval_bf - val_bf; + + val_gf = rectf[2] ; + nval_gf = rectf[skipx+2]; + diff_gf = nval_gf - val_gf; + + val_rf = rectf[3] ; + nval_rf = rectf[skipx+3]; + diff_rf = nval_rf - val_rf; + + rectf += 2*skipx; + } + + for (y = newy ; y>0 ; y--){ + if (sample >= 1.0){ + sample -= 1.0; + + if (do_rect) { + val_a = nval_a ; + nval_a = rect[0] ; + diff_a = nval_a - val_a ; + val_a += 0.5; + + val_b = nval_b ; + nval_b = rect[1] ; + diff_b = nval_b - val_b ; + val_b += 0.5; + + val_g = nval_g ; + nval_g = rect[2] ; + diff_g = nval_g - val_g ; + val_g += 0.5; + + val_r = nval_r ; + nval_r = rect[3] ; + diff_r = nval_r - val_r ; + val_r += 0.5; + rect += skipx; + } + if (do_float) { + val_af = nval_af ; + nval_af = rectf[0] ; + diff_af = nval_af - val_af ; + + val_bf = nval_bf ; + nval_bf = rectf[1] ; + diff_bf = nval_bf - val_bf ; + + val_gf = nval_gf ; + nval_gf = rectf[2] ; + diff_gf = nval_gf - val_gf ; + + val_rf = nval_rf ; + nval_rf = rectf[3] ; + diff_rf = nval_rf - val_rf; + rectf += skipx; + } + } + if (do_rect) { + newrect[0] = val_a + sample * diff_a; + newrect[1] = val_b + sample * diff_b; + newrect[2] = val_g + sample * diff_g; + newrect[3] = val_r + sample * diff_r; + newrect += skipx; + } + if (do_float) { + newrectf[0] = val_af + sample * diff_af; + newrectf[1] = val_bf + sample * diff_bf; + newrectf[2] = val_gf + sample * diff_gf; + newrectf[3] = val_rf + sample * diff_rf; + newrectf += skipx; + } + sample += add; + } + } + + if (do_rect) { + imb_freerectImBuf(ibuf); + ibuf->mall |= IB_rect; + ibuf->rect = (unsigned int *) _newrect; + } + if (do_float) { + imb_freerectfloatImBuf(ibuf); + ibuf->mall |= IB_rectfloat; + ibuf->rect_float = (float *) _newrectf; + } + + ibuf->y = newy; + return(ibuf); +} + + +/* no float buf needed here! */ +static void scalefast_Z_ImBuf(ImBuf *ibuf, short newx, short newy) +{ + unsigned int *rect, *_newrect, *newrect; + int x, y; + int ofsx, ofsy, stepx, stepy; + + if (ibuf->zbuf) { + _newrect = MEM_mallocN(newx * newy * sizeof(int), "z rect"); + if (_newrect==NULL) return; + + stepx = (65536.0 * (ibuf->x - 1.0) / (newx - 1.0)) + 0.5; + stepy = (65536.0 * (ibuf->y - 1.0) / (newy - 1.0)) + 0.5; + ofsy = 32768; + + newrect = _newrect; + + for (y = newy; y > 0 ; y--){ + rect = (unsigned int*) ibuf->zbuf; + rect += (ofsy >> 16) * ibuf->x; + ofsy += stepy; + ofsx = 32768; + for (x = newx ; x > 0 ; x--){ + *newrect++ = rect[ofsx >> 16]; + ofsx += stepx; + } + } + + IMB_freezbufImBuf(ibuf); + ibuf->mall |= IB_zbuf; + ibuf->zbuf = (int*) _newrect; + } +} + +struct ImBuf *IMB_scaleImBuf(struct ImBuf * ibuf, short newx, short newy) +{ + if (ibuf==NULL) return (0); + if (ibuf->rect==NULL && ibuf->rect_float==NULL) return (ibuf); + + // scaleup / scaledown functions below change ibuf->x and ibuf->y + // so we first scale the Z-buffer (if any) + scalefast_Z_ImBuf(ibuf, newx, newy); + + if (newx < ibuf->x) if (newx) scaledownx(ibuf,newx); + if (newy < ibuf->y) if (newy) scaledowny(ibuf,newy); + if (newx > ibuf->x) if (newx) scaleupx(ibuf,newx); + if (newy > ibuf->y) if (newy) scaleupy(ibuf,newy); + + return(ibuf); +} + +struct imbufRGBA { + float r, g, b, a; +}; + +struct ImBuf *IMB_scalefastImBuf(struct ImBuf *ibuf, short newx, short newy) +{ + unsigned int *rect,*_newrect,*newrect; + struct imbufRGBA *rectf, *_newrectf, *newrectf; + int x,y, do_float=0, do_rect=0; + int ofsx,ofsy,stepx,stepy; + + rect = NULL; _newrect = NULL; newrect = NULL; + rectf = NULL; _newrectf = NULL; newrectf = NULL; + + if (ibuf==NULL) return(0); + if (ibuf->rect) do_rect = 1; + if (ibuf->rect_float) do_float = 1; + if (do_rect==0 && do_float==0) return(ibuf); + + if (newx == ibuf->x && newy == ibuf->y) return(ibuf); + + if(do_rect) { + _newrect = MEM_mallocN(newx * newy * sizeof(int), "scalefastimbuf"); + if (_newrect==NULL) return(ibuf); + newrect = _newrect; + } + + if (do_float) { + _newrectf = MEM_mallocN(newx * newy * sizeof(float) * 4, "scalefastimbuf f"); + if (_newrectf==NULL) { + if (_newrect) MEM_freeN(_newrect); + return(ibuf); + } + newrectf = _newrectf; + } + + stepx = (65536.0 * (ibuf->x - 1.0) / (newx - 1.0)) + 0.5; + stepy = (65536.0 * (ibuf->y - 1.0) / (newy - 1.0)) + 0.5; + ofsy = 32768; + + for (y = newy; y > 0 ; y--){ + if(do_rect) { + rect = ibuf->rect; + rect += (ofsy >> 16) * ibuf->x; + } + if (do_float) { + rectf = (struct imbufRGBA *)ibuf->rect_float; + rectf += (ofsy >> 16) * ibuf->x; + } + ofsy += stepy; + ofsx = 32768; + + if (do_rect) { + for (x = newx ; x>0 ; x--){ + *newrect++ = rect[ofsx >> 16]; + ofsx += stepx; + } + } + + if (do_float) { + ofsx = 32768; + for (x = newx ; x>0 ; x--){ + *newrectf++ = rectf[ofsx >> 16]; + ofsx += stepx; + } + } + } + + if (do_rect) { + imb_freerectImBuf(ibuf); + ibuf->mall |= IB_rect; + ibuf->rect = _newrect; + } + + if (do_float) { + imb_freerectfloatImBuf(ibuf); + ibuf->mall |= IB_rectfloat; + ibuf->rect_float = (float *)_newrectf; + } + + scalefast_Z_ImBuf(ibuf, newx, newy); + + ibuf->x = newx; + ibuf->y = newy; + return(ibuf); +} + + +static struct ImBuf *generic_fieldscale(struct ImBuf *ibuf, short newx, short newy, struct ImBuf *(*scalefunc)(ImBuf *, short, short) ) +{ + struct ImBuf *sbuf1, *sbuf2; + + sbuf1 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, ibuf->depth, ibuf->flags, 0); + sbuf2 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, ibuf->depth, ibuf->flags, 0); + + ibuf->x *= 2; + + /* more args needed, 0 assumed... (nzc) */ + IMB_rectcpy(sbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y); + IMB_rectcpy(sbuf2, ibuf, 0, 0, sbuf2->x, 0, ibuf->x, ibuf->y); + + imb_freerectImBuf(ibuf); + imb_freerectfloatImBuf(ibuf); + + ibuf->x = newx; + ibuf->y = newy; + + imb_addrectImBuf(ibuf); + if(ibuf->flags & IB_rectfloat) + imb_addrectfloatImBuf(ibuf); + + scalefunc(sbuf1, newx, newy / 2); + scalefunc(sbuf2, newx, newy / 2); + + ibuf->x *= 2; + + /* more args needed, 0 assumed... (nzc) */ + IMB_rectcpy(ibuf, sbuf1, 0, 0, 0, 0, sbuf1->x, sbuf1->y); + IMB_rectcpy(ibuf, sbuf2, sbuf2->x, 0, 0, 0, sbuf2->x, sbuf2->y); + + ibuf->x /= 2; + + IMB_freeImBuf(sbuf1); + IMB_freeImBuf(sbuf2); + + return(ibuf); +} + + +struct ImBuf *IMB_scalefastfieldImBuf(struct ImBuf *ibuf, short newx, short newy) +{ + return(generic_fieldscale(ibuf, newx, newy, IMB_scalefastImBuf)); +} + +struct ImBuf *IMB_scalefieldImBuf(struct ImBuf *ibuf, short newx, short newy) +{ + return(generic_fieldscale(ibuf, newx, newy, IMB_scaleImBuf)); +} + diff --git a/source/blender/imbuf/intern/targa.c b/source/blender/imbuf/intern/targa.c new file mode 100644 index 00000000000..d2979215872 --- /dev/null +++ b/source/blender/imbuf/intern/targa.c @@ -0,0 +1,647 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * $Id$ + */ + +#ifdef WIN32 +#include +#endif +#include "BLI_blenlib.h" + +#include "imbuf.h" +#include "imbuf_patch.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "IMB_allocimbuf.h" +#include "IMB_cmap.h" +#include "IMB_targa.h" + + +/* this one is only def-ed once, strangely... related to GS? */ +#define GSS(x) (((uchar *)(x))[1] << 8 | ((uchar *)(x))[0]) + +/***/ + +typedef struct TARGA +{ + unsigned char numid; + unsigned char maptyp; + unsigned char imgtyp; + short maporig; + short mapsize; + unsigned char mapbits; + short xorig; + short yorig; + short xsize; + short ysize; + unsigned char pixsize; + unsigned char imgdes; +} TARGA; + +/***/ + +static int tga_out1(unsigned int data, FILE *file) +{ + uchar *p; + + p = (uchar *) & data; + if (putc(p[0],file) == EOF) return(EOF); + return (~EOF); +} + +static int tga_out2(unsigned int data, FILE * file) +{ + uchar *p; + + p = (uchar *) & data; + if (putc(p[0],file) == EOF) return(EOF); + if (putc(p[1],file) == EOF) return(EOF); + return (~EOF); +} + + +static int tga_out3(unsigned int data, FILE * file) +{ + uchar *p; + + p = (uchar *) & data; + if (putc(p[2],file) == EOF) return(EOF); + if (putc(p[1],file) == EOF) return(EOF); + if (putc(p[0],file) == EOF) return(EOF); + return (~EOF); +} + + +static int tga_out4(unsigned int data, FILE * file) +{ + uchar *p; + + p = (uchar *) & data; + /* order = bgra */ + if (putc(p[2],file) == EOF) return(EOF); + if (putc(p[1],file) == EOF) return(EOF); + if (putc(p[0],file) == EOF) return(EOF); + if (putc(p[3],file) == EOF) return(EOF); + return (~EOF); +} + +static short makebody_tga(ImBuf * ibuf, FILE * file, int (*out)(unsigned int, FILE*)) +{ + register int last,this; + register int copy, bytes; + register unsigned int *rect, *rectstart, *temp; + int y; + + for (y = 0; y < ibuf->y; y++) { + bytes = ibuf->x - 1; + rectstart = rect = ibuf->rect + (y * ibuf->x); + last = *rect++; + this = *rect++; + copy = last^this; + while (bytes > 0){ + if (copy){ + do{ + last = this; + this = *rect++; + if (last == this){ + if (this == rect[-3]){ /* three the same? */ + bytes --; /* set bytes */ + break; + } + } + }while (--bytes != 0); + + copy = rect-rectstart; + copy --; + if (bytes) copy -= 2; + + temp = rect; + rect = rectstart; + + while (copy){ + last = copy; + if (copy>=128) last = 128; + copy -= last; + if (fputc(last-1,file) == EOF) return(0); + do{ + if (out(*rect++,file) == EOF) return(0); + }while(--last != 0); + } + rectstart = rect; + rect = temp; + last = this; + + copy = FALSE; + } else { + while (*rect++ == this){ /* seek for first different byte */ + if (--bytes == 0) break; /* oor end of line */ + } + rect --; + copy = rect-rectstart; + rectstart = rect; + bytes --; + this = *rect++; + + while (copy){ + if (copy>128){ + if (fputc(255,file) == EOF) return(0); + copy -= 128; + } else { + if (copy == 1){ + if (fputc(0,file) == EOF) return(0); + } else if (fputc(127 + copy,file) == EOF) return(0); + copy = 0; + } + if (out(last,file) == EOF) return(0); + } + copy=TRUE; + } + } + } + return (1); +} + +static int dumptarga(struct ImBuf * ibuf, FILE * file) +{ + int size; + uchar *rect; + + if (ibuf == 0) return (0); + if (ibuf->rect == 0) return (0); + + size = ibuf->x * ibuf->y; + rect = (uchar *) ibuf->rect; + + if (ibuf->depth <= 8) { + while(size > 0){ + if (putc(*rect, file) == EOF) return (0); + size--; + rect += 4; + } + } else if (ibuf->depth <= 16) { + while(size > 0){ + putc(rect[0], file); + if (putc(rect[1], file) == EOF) return (0); + size--; + rect += 4; + } + } else if (ibuf->depth <= 24) { + while(size > 0){ + putc(rect[2], file); + putc(rect[1], file); + if (putc(rect[0], file) == EOF) return (0); + size--; + rect += 4; + } + } else if (ibuf->depth <= 32) { + while(size > 0){ + putc(rect[2], file); + putc(rect[1], file); + putc(rect[0], file); + if (putc(rect[3], file) == EOF) return (0); + size--; + rect += 4; + } + } else return (0); + + return (1); +} + + +short imb_savetarga(struct ImBuf * ibuf, char *name, int flags) +{ + char buf[20]; + FILE *fildes; + int i; + short ok = 0; + + if (ibuf == 0) return (0); + if (ibuf->rect == 0) return (0); + + memset(buf,0,sizeof(buf)); + + /* buf[0] = 0; length string */ + + buf[16] = (ibuf->depth + 0x7 ) & ~0x7; + if (ibuf->cmap) { + buf[1] = 1; + buf[2] = 9; + buf[3] = ibuf->mincol & 0xff; + buf[4] = ibuf->mincol >> 8; + buf[5] = ibuf->maxcol & 0xff; + buf[6] = ibuf->maxcol >> 8; + buf[7] = 24; + if ((flags & IB_ttob) == 0) { + IMB_flipy(ibuf); + buf[17] = 0x20; + } + } else if (ibuf->depth > 8 ){ + buf[2] = 10; + } else{ + buf[2] = 11; + } + + if (ibuf->ftype == RAWTGA) buf[2] &= ~8; + + buf[8] = ibuf->xorig & 0xff; + buf[9] = ibuf->xorig >> 8; + buf[10] = ibuf->yorig & 0xff; + buf[11] = ibuf->yorig >> 8; + + buf[12] = ibuf->x & 0xff; + buf[13] = ibuf->x >> 8; + buf[14] = ibuf->y & 0xff; + buf[15] = ibuf->y >> 8; + + if (flags & IB_ttob) buf[17] ^= 0x20; + + /* Don't forget to indicate that your 32 bit + * targa uses 8 bits for the alpha channel! */ + if (ibuf->depth==32) { + buf[17] |= 0x08; + } + fildes = fopen(name,"wb"); + if (!fildes) return 0; + + if (fwrite(buf, 1, 18,fildes) != 18) return (0); + + if (ibuf->cmap){ + for (i = 0 ; imaxcol ; i++){ + if (fwrite(((uchar *)(ibuf->cmap + i)) + 1,1,3,fildes) != 3) return (0); + } + } + + if (ibuf->cmap && (flags & IB_cmap) == 0) IMB_converttocmap(ibuf); + + if (ibuf->ftype == RAWTGA) { + ok = dumptarga(ibuf, fildes); + } else { + switch((ibuf->depth + 7) >> 3){ + case 1: + ok = makebody_tga(ibuf, fildes, tga_out1); + break; + case 2: + ok = makebody_tga(ibuf, fildes, tga_out2); + break; + case 3: + ok = makebody_tga(ibuf, fildes, tga_out3); + break; + case 4: + ok = makebody_tga(ibuf, fildes, tga_out4); + break; + } + } + + fclose(fildes); + return (ok); +} + + +static int checktarga(TARGA *tga, unsigned char *mem) +{ + tga->numid = mem[0]; + tga->maptyp = mem[1]; + tga->imgtyp = mem[2]; + + tga->maporig = GSS(mem+3); + tga->mapsize = GSS(mem+5); + tga->mapbits = mem[7]; + tga->xorig = GSS(mem+8); + tga->yorig = GSS(mem+10); + tga->xsize = GSS(mem+12); + tga->ysize = GSS(mem+14); + tga->pixsize = mem[16]; + tga->imgdes = mem[17]; + + if (tga->maptyp > 1) return(0); + switch (tga->imgtyp){ + case 1: /* raw cmap */ + case 2: /* raw rgb */ + case 3: /* raw b&w */ + case 9: /* cmap */ + case 10: /* rgb */ + case 11: /* b&w */ + break; + default: + return(0); + } + if (tga->mapsize && tga->mapbits > 32) return(0); + if (tga->xsize <= 0 || tga->xsize >= 8192) return(0); + if (tga->ysize <= 0 || tga->ysize >= 8192) return(0); + if (tga->pixsize > 32) return(0); + if (tga->pixsize == 0) return(0); + return(1); +} + +int imb_is_a_targa(void *buf) { + TARGA tga; + + return checktarga(&tga, buf); +} + +static void decodetarga(struct ImBuf *ibuf, unsigned char *mem, int psize) +{ + int count, col, size; + unsigned int *rect; + uchar * cp = (uchar *) &col; + + if (ibuf == 0) return; + if (ibuf->rect == 0) return; + + size = ibuf->x * ibuf->y; + rect = ibuf->rect; + + /* set alpha */ + cp[0] = 0xff; + cp[1] = cp[2] = 0; + + while(size > 0){ + count = *mem++; + if (count >= 128) { + /*if (count == 128) printf("TARGA: 128 in file !\n");*/ + count -= 127; + + if (psize & 2){ + if (psize & 1){ + /* order = bgra */ + cp[0] = mem[3]; + cp[1] = mem[0]; + cp[2] = mem[1]; + cp[3] = mem[2]; + /*col = (mem[3] << 24) + (mem[0] << 16) + (mem[1] << 8) + mem[2];*/ + mem += 4; + } else{ + cp[1] = mem[0]; + cp[2] = mem[1]; + cp[3] = mem[2]; + /*col = 0xff000000 + (mem[0] << 16) + (mem[1] << 8) + mem[2];*/ + mem += 3; + } + } else{ + if (psize & 1){ + cp[0] = mem[0]; + cp[1] = mem[1]; + mem += 2; + } else{ + col = *mem++; + } + } + + size -= count; + if (size >= 0) { + while (count > 0) { + *rect++ = col; + count--; + } + } + } else{ + count ++; + size -= count; + if (size >= 0) { + while (count > 0){ + if (psize & 2){ + if (psize & 1){ + /* order = bgra */ + cp[0] = mem[3]; + cp[1] = mem[0]; + cp[2] = mem[1]; + cp[3] = mem[2]; + /*col = (mem[3] << 24) + (mem[0] << 16) + (mem[1] << 8) + mem[2];*/ + mem += 4; + } else{ + cp[1] = mem[0]; + cp[2] = mem[1]; + cp[3] = mem[2]; + /*col = 0xff000000 + (mem[0] << 16) + (mem[1] << 8) + mem[2];*/ + mem += 3; + } + } else{ + if (psize & 1){ + cp[0] = mem[0]; + cp[1] = mem[1]; + mem += 2; + } else{ + col = *mem++; + } + } + *rect++ = col; + count --; + } + } + } + } + if (size) printf("decodetarga: count would overwrite %d pixels\n", -size); +} + +static void ldtarga(struct ImBuf * ibuf,unsigned char * mem, int psize) +{ + int col,size; + unsigned int *rect; + uchar * cp = (uchar *) &col; + + if (ibuf == 0) return; + if (ibuf->rect == 0) return; + + size = ibuf->x * ibuf->y; + rect = ibuf->rect; + + /* set alpha */ + cp[0] = 0xff; + cp[1] = cp[2] = 0; + + while(size > 0){ + if (psize & 2){ + if (psize & 1){ + /* order = bgra */ + cp[0] = mem[3]; + cp[1] = mem[0]; + cp[2] = mem[1]; + cp[3] = mem[2]; + /*col = (mem[3] << 24) + (mem[0] << 16) + (mem[1] << 8) + mem[2];*/ + mem += 4; + } else{ + /* set alpha for 24 bits colors */ + cp[1] = mem[0]; + cp[2] = mem[1]; + cp[3] = mem[2]; + /*col = 0xff000000 + (mem[0] << 16) + (mem[1] << 8) + mem[2];*/ + mem += 3; + } + } else{ + if (psize & 1){ + cp[0] = mem[0]; + cp[1] = mem[1]; + mem += 2; + } else{ + col = *mem++; + } + } + *rect++ = col; + size--; + } +} + + +struct ImBuf *imb_loadtarga(unsigned char *mem, int flags) +{ + TARGA tga; + struct ImBuf * ibuf; + int col, count, size; + unsigned int * rect; + uchar * cp = (uchar *) &col; + + if (checktarga(&tga,mem) == 0) return(0); + + if (flags & IB_test) ibuf = IMB_allocImBuf(tga.xsize,tga.ysize,tga.pixsize, 0, 0); + else ibuf = IMB_allocImBuf(tga.xsize,tga.ysize,(tga.pixsize + 0x7) & ~0x7, IB_rect, 0); + + if (ibuf == 0) return(0); + ibuf->ftype = TGA; + ibuf->xorig = tga.xorig; + ibuf->yorig = tga.yorig; + mem = mem + 18 + tga.numid; + + cp[0] = 0xff; + cp[1] = cp[2] = 0; + + if (tga.mapsize){ + ibuf->mincol = tga.maporig; + ibuf->maxcol = tga.mapsize; + imb_addcmapImBuf(ibuf); + ibuf->cbits = 8; + for (count = 0 ; count < ibuf->maxcol ; count ++) { + switch (tga.mapbits >> 3) { + case 4: + cp[0] = mem[3]; + cp[1] = mem[0]; + cp[2] = mem[1]; + cp[3] = mem[2]; + mem += 4; + break; + case 3: + cp[1] = mem[0]; + cp[2] = mem[1]; + cp[3] = mem[2]; + mem += 3; + break; + case 2: + cp[1] = mem[1]; + cp[0] = mem[0]; + mem += 2; + break; + case 1: + col = *mem++; + break; + } + ibuf->cmap[count] = col; + } + + size = 0; + for (col = ibuf->maxcol - 1; col > 0; col >>= 1) size++; + ibuf->depth = size; + + if (tga.mapbits != 32) { /* set alpha bits */ + ibuf->cmap[0] &= BIG_LONG(0x00ffffff); + } + } + + if (flags & IB_test) return (ibuf); + + if (tga.imgtyp != 1 && tga.imgtyp != 9) IMB_freecmapImBuf(ibuf); /* happens sometimes (beuh) */ + + switch(tga.imgtyp){ + case 1: + case 2: + case 3: + if (tga.pixsize <= 8) ldtarga(ibuf,mem,0); + else if (tga.pixsize <= 16) ldtarga(ibuf,mem,1); + else if (tga.pixsize <= 24) ldtarga(ibuf,mem,2); + else if (tga.pixsize <= 32) ldtarga(ibuf,mem,3); + break; + case 9: + case 10: + case 11: + if (tga.pixsize <= 8) decodetarga(ibuf,mem,0); + else if (tga.pixsize <= 16) decodetarga(ibuf,mem,1); + else if (tga.pixsize <= 24) decodetarga(ibuf,mem,2); + else if (tga.pixsize <= 32) decodetarga(ibuf,mem,3); + break; + } + + if (ibuf->cmap){ + if ((flags & IB_cmap) == 0) IMB_applycmap(ibuf); + } + + if (tga.pixsize == 16 && ibuf->cmap == 0){ + rect = ibuf->rect; + for (size = ibuf->x * ibuf->y; size > 0; --size, ++rect){ + col = *rect; + cp = (uchar*)rect; + mem = (uchar*)&col; + + cp[3] = ((mem[1] << 1) & 0xf8); + cp[2] = ((mem[0] & 0xe0) >> 2) + ((mem[1] & 0x03) << 6); + cp[1] = ((mem[0] << 3) & 0xf8); + cp[1] += cp[1] >> 5; + cp[2] += cp[2] >> 5; + cp[3] += cp[3] >> 5; + cp[0] = 0xff; + } + ibuf->depth = 24; + } + + if (tga.imgtyp == 3 || tga.imgtyp == 11){ + uchar *crect; + unsigned int *lrect, col; + + crect = (uchar *) ibuf->rect; + lrect = (unsigned int *) ibuf->rect; + + for (size = ibuf->x * ibuf->y; size > 0; size --){ + col = *lrect++; + + crect[0] = 255; + crect[1] = crect[2] = crect[3] = col; + crect += 4; + } + } + + if (flags & IB_ttob) tga.imgdes ^= 0x20; + if (tga.imgdes & 0x20) IMB_flipy(ibuf); + + if (ibuf) { + if (ibuf->rect && (flags & IB_cmap)==0) + IMB_convert_rgba_to_abgr(ibuf); + } + + return(ibuf); +} diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c new file mode 100644 index 00000000000..131d2ef38f7 --- /dev/null +++ b/source/blender/imbuf/intern/thumbs.c @@ -0,0 +1,459 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2007 Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Andrea Weikert. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "BKE_global.h" +#include "BKE_utildefines.h" +#include "BLI_blenlib.h" +#include "MEM_guardedalloc.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" +#include "IMB_thumbs.h" +#include "IMB_imginfo.h" + + +#include "md5.h" + +#ifdef WIN32 +#include /* need to include windows.h so _WIN32_IE is defined */ +#ifndef _WIN32_IE +#define _WIN32_IE 0x0400 /* minimal requirements for SHGetSpecialFolderPath on MINGW MSVC has this defined already */ +#endif +#include /* for SHGetSpecialFolderPath, has to be done before BLI_winstuff because 'near' is disabled through BLI_windstuff */ +#include "BLI_winstuff.h" +#include /* getpid */ +#include /* chdir */ +#else +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#define URI_MAX FILE_MAX*3 + 8 + +static int get_thumb_dir( char* dir , ThumbSize size) +{ +#ifdef WIN32 + /* yes, applications shouldn't store data there, but so does GIMP :)*/ + SHGetSpecialFolderPath(0, dir, CSIDL_PROFILE, 0); +#else + char* home = getenv("HOME"); + if (!home) return 0; + BLI_strncpy(dir, home, FILE_MAX); +#endif + switch(size) { + case THB_NORMAL: + strcat(dir, "/.thumbnails/normal"); + break; + case THB_LARGE: + strcat(dir, "/.thumbnails/large"); + break; + case THB_FAIL: + strcat(dir, "/.thumbnails/fail/blender"); + break; + default: + return 0; /* unknown size */ + } + BLI_cleanup_dir(G.sce, dir); + return 1; +} + +/** ----- begin of adapted code from glib --- + * The following code is adapted from function g_escape_uri_string from the gnome glib + * Source: http://svn.gnome.org/viewcvs/glib/trunk/glib/gconvert.c?view=markup + * released under the Gnu General Public License. + */ +typedef enum { + UNSAFE_ALL = 0x1, /* Escape all unsafe characters */ + UNSAFE_ALLOW_PLUS = 0x2, /* Allows '+' */ + UNSAFE_PATH = 0x8, /* Allows '/', '&', '=', ':', '@', '+', '$' and ',' */ + UNSAFE_HOST = 0x10, /* Allows '/' and ':' and '@' */ + UNSAFE_SLASHES = 0x20 /* Allows all characters except for '/' and '%' */ +} UnsafeCharacterSet; + +static const unsigned char acceptable[96] = { + /* A table of the ASCII chars from space (32) to DEL (127) */ + /* ! " # $ % & ' ( ) * + , - . / */ + 0x00,0x3F,0x20,0x20,0x28,0x00,0x2C,0x3F,0x3F,0x3F,0x3F,0x2A,0x28,0x3F,0x3F,0x1C, + /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x38,0x20,0x20,0x2C,0x20,0x20, + /* @ A B C D E F G H I J K L M N O */ + 0x38,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, + /* P Q R S T U V W X Y Z [ \ ] ^ _ */ + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x20,0x3F, + /* ` a b c d e f g h i j k l m n o */ + 0x20,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, + /* p q r s t u v w x y z { | } ~ DEL */ + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x3F,0x20 +}; + +static const char hex[17] = "0123456789abcdef"; + +/* Note: This escape function works on file: URIs, but if you want to + * escape something else, please read RFC-2396 */ +void escape_uri_string (const char *string, char* escaped_string, int len,UnsafeCharacterSet mask) +{ +#define ACCEPTABLE(a) ((a)>=32 && (a)<128 && (acceptable[(a)-32] & use_mask)) + + const char *p; + char *q; + int c; + UnsafeCharacterSet use_mask; + use_mask = mask; + + for (q = escaped_string, p = string; (*p != '\0') && len; p++) { + c = (unsigned char) *p; + len--; + + if (!ACCEPTABLE (c)) { + *q++ = '%'; /* means hex coming */ + *q++ = hex[c >> 4]; + *q++ = hex[c & 15]; + } else { + *q++ = *p; + } + } + + *q = '\0'; +} + +void to_hex_char(char* hexbytes, const unsigned char* bytes, int len) +{ + const unsigned char *p; + char *q; + + for (q = hexbytes, p = bytes; len; p++) { + const unsigned char c = (unsigned char) *p; + len--; + *q++ = hex[c >> 4]; + *q++ = hex[c & 15]; + } +} + +/** ----- end of adapted code from glib --- */ + +static int uri_from_filename( const char *dir, const char *file, char *uri ) +{ + char orig_uri[URI_MAX]; + const char* dirstart = dir; + +#ifdef WIN32 + { + char vol[3]; + + BLI_strncpy(orig_uri, "file:///", FILE_MAX); + if (strlen(dir) < 2 && dir[1] != ':') { + /* not a correct absolute path */ + return 0; + } + /* on windows, using always uppercase drive/volume letter in uri */ + vol[0] = (unsigned char)toupper(dir[0]); + vol[1] = ':'; + vol[2] = '\0'; + strcat(orig_uri, vol); + dirstart += 2; + } +#else + BLI_strncpy(orig_uri, "file://", FILE_MAX); +#endif + strcat(orig_uri, dirstart); + strcat(orig_uri, file); + BLI_char_switch(orig_uri, '\\', '/'); + +#ifdef WITH_ICONV + { + char uri_utf8[FILE_MAX*3+8]; + escape_uri_string(orig_uri, uri_utf8, FILE_MAX*3+8, UNSAFE_PATH); + BLI_string_to_utf8(uri_utf8, uri, NULL); + } +#else + escape_uri_string(orig_uri, uri, FILE_MAX*3+8, UNSAFE_PATH); +#endif + return 1; +} + +static void thumbname_from_uri(const char* uri, char* thumb) +{ + char hexdigest[33]; + unsigned char digest[16]; + + md5_buffer( uri, strlen(uri), digest); + hexdigest[0] = '\0'; + to_hex_char(hexdigest, digest, 16); + hexdigest[32] = '\0'; + sprintf(thumb, "%s.png", hexdigest); +} + +static int thumbpath_from_uri(const char* uri, char* path, ThumbSize size) +{ + char tmppath[FILE_MAX]; + int rv = 0; + + if (get_thumb_dir(tmppath, size)) { + char thumb[40]; + thumbname_from_uri(uri, thumb); + BLI_snprintf(path, FILE_MAX, "%s%s", tmppath, thumb); + rv = 1; + } + return rv; +} + + +/* create thumbnail for file and returns new imbuf for thumbnail */ +ImBuf* IMB_thumb_create(const char* dir, const char* file, ThumbSize size, ThumbSource source) +{ + ImBuf *img = 0; + char uri[URI_MAX]; + char desc[URI_MAX+22]; + char tpath[FILE_MAX]; + char tdir[FILE_MAX]; + char wdir[FILE_MAX]; + char temp[FILE_MAX]; + char mtime[40]; + char cwidth[40]; + char cheight[40]; + char thumb[40]; + short tsize = 128; + short ex, ey; + float scaledx, scaledy; + struct stat info; + + switch(size) { + case THB_NORMAL: + tsize = 128; + break; + case THB_LARGE: + tsize = 256; + break; + case THB_FAIL: + tsize = 0; + break; + default: + return 0; /* unknown size */ + } + + uri_from_filename(dir, file,uri); + thumbname_from_uri(uri, thumb); + if (get_thumb_dir(tdir, size)) { + BLI_snprintf(tpath, FILE_MAX, "%s%s", tdir, thumb); + thumb[8] = '\0'; /* shorten for tempname, not needed anymore */ + BLI_snprintf(temp, FILE_MAX, "%sblender_%d_%s.png", tdir, abs(getpid()), thumb); + if (strncmp(thumb, dir, strlen(dir)) == 0) { + return NULL; + } + if (size == THB_FAIL) { + img = IMB_allocImBuf(0,0,32, IB_rect | IB_imginfo, 0); + if (!img) return 0; + } else { + if (THB_SOURCE_IMAGE == source) { + BLI_getwdN(wdir); + chdir(dir); + img = IMB_loadiffname(file, IB_rect | IB_imginfo); + if (img != NULL) { + stat(file, &info); + sprintf(mtime, "%ld", info.st_mtime); + sprintf(cwidth, "%d", img->x); + sprintf(cheight, "%d", img->y); + chdir(wdir); + } + } else if (THB_SOURCE_MOVIE == source) { + struct anim * anim = NULL; + BLI_getwdN(wdir); + chdir(dir); + anim = IMB_open_anim(file, IB_rect | IB_imginfo); + if (anim != NULL) { + img = IMB_anim_absolute(anim, 0); + if (img == NULL) { + printf("not an anim; %s\n", file); + } else { + IMB_freeImBuf(img); + img = IMB_anim_previewframe(anim); + } + IMB_free_anim(anim); + } + stat(file, &info); + sprintf(mtime, "%ld", info.st_mtime); + chdir(wdir); + } + if (!img) return 0; + + if (img->x > img->y) { + scaledx = (float)tsize; + scaledy = ( (float)img->y/(float)img->x )*tsize; + } + else { + scaledy = (float)tsize; + scaledx = ( (float)img->x/(float)img->y )*tsize; + } + ex = (short)scaledx; + ey = (short)scaledy; + + IMB_scaleImBuf(img, ex, ey); + } + sprintf(desc, "Thumbnail for %s", uri); + IMB_imginfo_change_field(img, "Description", desc); + IMB_imginfo_change_field(img, "Software", "Blender"); + IMB_imginfo_change_field(img, "Thumb::URI", uri); + IMB_imginfo_change_field(img, "Thumb::MTime", mtime); + if (THB_SOURCE_IMAGE == source) { + IMB_imginfo_change_field(img, "Thumb::Image::Width", cwidth); + IMB_imginfo_change_field(img, "Thumb::Image::Height", cheight); + } + img->ftype = PNG; + img->depth = 32; + if (IMB_saveiff(img, temp, IB_rect | IB_imginfo)) { +#ifndef WIN32 + chmod(temp, S_IRUSR | S_IWUSR); +#endif + BLI_rename(temp, tpath); + } + + return img; + } + return img; +} + +/* read thumbnail for file and returns new imbuf for thumbnail */ +ImBuf* IMB_thumb_read(const char* dir, const char* file, ThumbSize size) +{ + char thumb[FILE_MAX]; + char uri[FILE_MAX*3+8]; + ImBuf *img = 0; + + if (!uri_from_filename(dir, file,uri)) { + return NULL; + } + if (thumbpath_from_uri(uri, thumb, size)) { + img = IMB_loadiffname(thumb, IB_rect | IB_imginfo); + } + + return img; +} + +/* delete all thumbs for the file */ +void IMB_thumb_delete(const char* dir, const char* file, ThumbSize size) +{ + char thumb[FILE_MAX]; + char uri[FILE_MAX*3+8]; + + if (!uri_from_filename(dir, file,uri)) { + return; + } + if (thumbpath_from_uri(uri, thumb, size)) { + if (strncmp(thumb, dir, strlen(dir)) == 0) { + return; + } + if (BLI_exists(thumb)) { + BLI_delete(thumb, 0, 0); + } + } +} + + +/* create the thumb if necessary and manage failed and old thumbs */ +ImBuf* IMB_thumb_manage(const char* dir, const char* file, ThumbSize size, ThumbSource source) +{ + char path[FILE_MAX]; + char thumb[FILE_MAX]; + char uri[FILE_MAX*3+8]; + struct stat st; + ImBuf* img = NULL; + + BLI_join_dirfile(path, dir, file); + if (stat(path, &st)) { + return NULL; + } + if (!uri_from_filename(dir, file,uri)) { + return NULL; + } + if (thumbpath_from_uri(uri, thumb, THB_FAIL)) { + /* failure thumb exists, don't try recreating */ + if (BLI_exists(thumb)) { + return NULL; + } + } + + if (thumbpath_from_uri(uri, thumb, size)) { + if (strncmp(thumb, dir, strlen(dir)) == 0) { + img = IMB_loadiffname(path, IB_rect); + } else { + img = IMB_loadiffname(thumb, IB_rect | IB_imginfo); + if (img) { + char mtime[40]; + if (!IMB_imginfo_get_field(img, "Thumb::MTime", mtime, 40)) { + /* illegal thumb, forget it! */ + IMB_freeImBuf(img); + img = 0; + } else { + time_t t = atol(mtime); + if (st.st_mtime != t) { + /* recreate all thumbs */ + IMB_freeImBuf(img); + img = 0; + IMB_thumb_delete(dir, file, THB_NORMAL); + IMB_thumb_delete(dir, file, THB_LARGE); + IMB_thumb_delete(dir, file, THB_FAIL); + img = IMB_thumb_create(dir, file, size, source); + if(!img){ + /* thumb creation failed, write fail thumb */ + img = IMB_thumb_create(dir, file, THB_FAIL, source); + if (img) { + /* we don't need failed thumb anymore */ + IMB_freeImBuf(img); + img = 0; + } + } + } + } + } else { + img = IMB_thumb_create(dir, file, size, source); + if(!img){ + /* thumb creation failed, write fail thumb */ + img = IMB_thumb_create(dir, file, THB_FAIL, source); + if (img) { + /* we don't need failed thumb anymore */ + IMB_freeImBuf(img); + img = 0; + } + } + } + } + } + + return img; +} + + diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c new file mode 100644 index 00000000000..6fc5fb99f8b --- /dev/null +++ b/source/blender/imbuf/intern/tiff.c @@ -0,0 +1,547 @@ +/* + * tiff.c + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributor(s): Jonathan Merritt. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + * Provides TIFF file loading and saving for Blender, via libtiff. + * + * The task of loading is complicated somewhat by the fact that Blender has + * already loaded the file into a memory buffer. libtiff is not well + * configured to handle files in memory, so a client wrapper is written to + * surround the memory and turn it into a virtual file. Currently, reading + * of TIFF files is done using libtiff's RGBAImage support. This is a + * high-level routine that loads all images as 32-bit RGBA, handling all the + * required conversions between many different TIFF types internally. + * + * Saving supports RGB, RGBA and BW (greyscale) images correctly, with + * 8 bits per channel in all cases. The "deflate" compression algorithm is + * used to compress images. + */ + +#include +#include + +#include "imbuf.h" +#include "imbuf_patch.h" + +#include "BKE_global.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "IMB_allocimbuf.h" +#include "IMB_cmap.h" +#include "IMB_tiff.h" + +#include "dynlibtiff.h" + + + +/*********************** + * Local declarations. * + ***********************/ +/* Reading and writing of an in-memory TIFF file. */ +tsize_t imb_tiff_ReadProc(thandle_t handle, tdata_t data, tsize_t n); +tsize_t imb_tiff_WriteProc(thandle_t handle, tdata_t data, tsize_t n); +toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence); +int imb_tiff_CloseProc(thandle_t handle); +toff_t imb_tiff_SizeProc(thandle_t handle); +int imb_tiff_DummyMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize); +void imb_tiff_DummyUnmapProc(thandle_t fd, tdata_t base, toff_t size); + + +/* Structure for in-memory TIFF file. */ +struct ImbTIFFMemFile { + unsigned char *mem; /* Location of first byte of TIFF file. */ + toff_t offset; /* Current offset within the file. */ + tsize_t size; /* Size of the TIFF file. */ +}; +#define IMB_TIFF_GET_MEMFILE(x) ((struct ImbTIFFMemFile*)(x)); + + + +/***************************** + * Function implementations. * + *****************************/ + + +void imb_tiff_DummyUnmapProc(thandle_t fd, tdata_t base, toff_t size) +{ +} + +int imb_tiff_DummyMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) +{ + return (0); +} + +/** + * Reads data from an in-memory TIFF file. + * + * @param handle: Handle of the TIFF file (pointer to ImbTIFFMemFile). + * @param data: Buffer to contain data (treat as void*). + * @param n: Number of bytes to read. + * + * @return: Number of bytes actually read. + * 0 = EOF. + * -1 = Error (never returned). + */ +tsize_t imb_tiff_ReadProc(thandle_t handle, tdata_t data, tsize_t n) +{ + tsize_t nRemaining, nCopy; + struct ImbTIFFMemFile* mfile; + void *srcAddr; + + /* get the pointer to the in-memory file */ + mfile = IMB_TIFF_GET_MEMFILE(handle); + assert(mfile != NULL); + assert(mfile->mem != NULL); + + /* find the actual number of bytes to read (copy) */ + nCopy = n; + if ((tsize_t)mfile->offset >= mfile->size) + nRemaining = 0; + else + nRemaining = mfile->size - mfile->offset; + + if (nCopy > nRemaining) + nCopy = nRemaining; + + /* on EOF, return immediately and read (copy) nothing */ + if (nCopy <= 0) + return (0); + + /* all set -> do the read (copy) */ + assert(sizeof(unsigned char) == 1); + srcAddr = (void*)(&(mfile->mem[mfile->offset])); + memcpy((void*)data, srcAddr, nCopy); + mfile->offset += nCopy; /* advance file ptr by copied bytes */ + return nCopy; +} + + + +/** + * Writes data to an in-memory TIFF file. + * + * NOTE: The current Blender implementation should not need this function. It + * is simply a stub. + */ +tsize_t imb_tiff_WriteProc(thandle_t handle, tdata_t data, tsize_t n) +{ + printf("imb_tiff_WriteProc: this function should not be called.\n"); + return (-1); +} + + + +/** + * Seeks to a new location in an in-memory TIFF file. + * + * @param handle: Handle of the TIFF file (pointer to ImbTIFFMemFile). + * @param ofs: Offset value (interpreted according to whence below). + * @param whence: This can be one of three values: + * SEEK_SET - The offset is set to ofs bytes. + * SEEK_CUR - The offset is set to its current location plus ofs bytes. + * SEEK_END - (This is unsupported and will return -1, indicating an + * error). + * + * @return: Resulting offset location within the file, measured in bytes from + * the beginning of the file. (-1) indicates an error. + */ +toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence) +{ + struct ImbTIFFMemFile *mfile; + toff_t new_offset; + + /* get the pointer to the in-memory file */ + mfile = IMB_TIFF_GET_MEMFILE(handle); + assert(mfile != NULL); + assert(mfile->mem != NULL); + + /* find the location we plan to seek to */ + switch (whence) { + case SEEK_SET: + new_offset = ofs; + break; + case SEEK_CUR: + new_offset = mfile->offset + ofs; + break; + default: + /* no other types are supported - return an error */ + printf("Unsupported TIFF SEEK type.\n"); + return (-1); + } + + /* set the new location */ + mfile->offset = new_offset; + return mfile->offset; +} + + + +/** + * Closes (virtually) an in-memory TIFF file. + * + * NOTE: All this function actually does is sets the data pointer within the + * TIFF file to NULL. That should trigger assertion errors if attempts + * are made to access the file after that point. However, no such + * attempts should ever be made (in theory). + * + * @param handle: Handle of the TIFF file (pointer to ImbTIFFMemFile). + * + * @return: 0 + */ +int imb_tiff_CloseProc(thandle_t handle) +{ + struct ImbTIFFMemFile *mfile; + + /* get the pointer to the in-memory file */ + mfile = IMB_TIFF_GET_MEMFILE(handle); + assert(mfile != NULL); + assert(mfile->mem != NULL); /* the file has not been closed yet */ + + /* virtually close the file */ + mfile->mem = NULL; + mfile->offset = 0; + mfile->size = 0; + + return (0); +} + + + +/** + * Returns the size of an in-memory TIFF file in bytes. + * + * @return: Size of file (in bytes). + */ +toff_t imb_tiff_SizeProc(thandle_t handle) +{ + struct ImbTIFFMemFile* mfile; + + /* get the pointer to the in-memory file */ + mfile = IMB_TIFF_GET_MEMFILE(handle); + assert(mfile != NULL); + assert(mfile->mem != NULL); + + /* return the size */ + return (toff_t)(mfile->size); +} + + + +/** + * Checks whether a given memory buffer contains a TIFF file. + * + * FIXME: Possible memory leak if mem is less than IMB_TIFF_NCB bytes long. + * However, changing this will require up-stream modifications. + * + * This method uses the format identifiers from: + * http://www.faqs.org/faqs/graphics/fileformats-faq/part4/section-9.html + * The first four bytes of big-endian and little-endian TIFF files + * respectively are (hex): + * 4d 4d 00 2a + * 49 49 2a 00 + * Note that TIFF files on *any* platform can be either big- or little-endian; + * it's not platform-specific. + * + * AFAICT, libtiff doesn't provide a method to do this automatically, and + * hence my manual comparison. - Jonathan Merritt (lancelet) 4th Sept 2005. + */ +#define IMB_TIFF_NCB 4 /* number of comparison bytes used */ +int imb_is_a_tiff(void *mem) +{ + char big_endian[IMB_TIFF_NCB] = { 0x4d, 0x4d, 0x00, 0x2a }; + char lil_endian[IMB_TIFF_NCB] = { 0x49, 0x49, 0x2a, 0x00 }; + + return ( (memcmp(big_endian, mem, IMB_TIFF_NCB) == 0) || + (memcmp(lil_endian, mem, IMB_TIFF_NCB) == 0) ); +} + + + +/** + * Loads a TIFF file. + * + * This function uses the "RGBA Image" support from libtiff, which enables + * it to load most commonly-encountered TIFF formats. libtiff handles format + * conversion, color depth conversion, etc. + * + * @param mem: Memory containing the TIFF file. + * @param size: Size of the mem buffer. + * @param flags: If flags has IB_test set then the file is not actually loaded, + * but all other operations take place. + * + * @return: A newly allocated ImBuf structure if successful, otherwise NULL. + */ +struct ImBuf *imb_loadtiff(unsigned char *mem, int size, int flags) +{ + TIFF *image = NULL; + struct ImBuf *ibuf = NULL; + struct ImbTIFFMemFile memFile; + uint32 width, height; + int bytesperpixel; + int success; + unsigned int pixel_i, byte_i; + uint32 *raster = NULL; + uint32 pixel; + unsigned char *to = NULL; + + memFile.mem = mem; + memFile.offset = 0; + memFile.size = size; + + /* check whether or not we have a TIFF file */ + assert(size >= IMB_TIFF_NCB); + if (imb_is_a_tiff(mem) == 0) + return NULL; + + /* open the TIFF client layer interface to the in-memory file */ + image = libtiff_TIFFClientOpen("(Blender TIFF Interface Layer)", + "r", (thandle_t)(&memFile), + imb_tiff_ReadProc, imb_tiff_WriteProc, + imb_tiff_SeekProc, imb_tiff_CloseProc, + imb_tiff_SizeProc, imb_tiff_DummyMapProc, imb_tiff_DummyUnmapProc); + if (image == NULL) { + printf("imb_loadtiff: could not open TIFF IO layer.\n"); + return NULL; + } + + /* allocate the image buffer */ + bytesperpixel = 4; /* 1 byte per channel, 4 channels */ + libtiff_TIFFGetField(image, TIFFTAG_IMAGEWIDTH, &width); + libtiff_TIFFGetField(image, TIFFTAG_IMAGELENGTH, &height); + ibuf = IMB_allocImBuf(width, height, 8*bytesperpixel, 0, 0); + if (ibuf) { + ibuf->ftype = TIF; + } else { + printf("imb_loadtiff: could not allocate memory for TIFF " \ + "image.\n"); + libtiff_TIFFClose(image); + return NULL; + } + + /* read in the image data */ + if (!(flags & IB_test)) { + + /* allocate memory for the ibuf->rect */ + imb_addrectImBuf(ibuf); + + /* perform actual read */ + raster = (uint32*)libtiff__TIFFmalloc( + width*height * sizeof(uint32)); + if (raster == NULL) { + libtiff_TIFFClose(image); + return NULL; + } + success = libtiff_TIFFReadRGBAImage( + image, width, height, raster, 0); + if (!success) { + printf("imb_loadtiff: This TIFF format is not " \ + "currently supported by Blender.\n"); + libtiff__TIFFfree(raster); + libtiff_TIFFClose(image); + return NULL; + } + + /* copy raster to ibuf->rect; we do a fast copy if possible, + * otherwise revert to a slower component-wise copy */ + if (sizeof(unsigned int) == sizeof(uint32)) { + memcpy(ibuf->rect, raster, + width*height*sizeof(uint32)); + } else { + /* this may not be entirely necessary, but is put here + * in case sizeof(unsigned int) is not a 32-bit + * quantity */ + printf("imb_loadtiff: using (slower) component-wise " \ + "buffer copy.\n"); + to = (unsigned char*)ibuf->rect; + for (pixel_i=0; pixel_i < width*height; pixel_i++) + { + byte_i = sizeof(unsigned int)*pixel_i; + pixel = raster[pixel_i]; + + to[byte_i++] = (unsigned char)TIFFGetR(pixel); + to[byte_i++] = (unsigned char)TIFFGetG(pixel); + to[byte_i++] = (unsigned char)TIFFGetB(pixel); + to[byte_i++] = (unsigned char)TIFFGetA(pixel); + } + } + + libtiff__TIFFfree(raster); + } + + /* close the client layer interface to the in-memory file */ + libtiff_TIFFClose(image); + + if (G.order == B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf); + + /* return successfully */ + return (ibuf); +} + + + +/** + * Saves a TIFF file. + * + * ImBuf structures with 1, 3 or 4 bytes per pixel (GRAY, RGB, RGBA + * respectively) are accepted, and interpreted correctly. Note that the TIFF + * convention is to use pre-multiplied alpha, which can be achieved within + * Blender by setting "Premul" alpha handling. Other alpha conventions are + * not strictly correct, but are permitted anyhow. + * + * @param ibuf: Image buffer. + * @param name: Name of the TIFF file to create. + * @param flags: Currently largely ignored. + * + * @return: 1 if the function is successful, 0 on failure. + */ +short imb_savetiff(struct ImBuf *ibuf, char *name, int flags) +{ + TIFF *image = NULL; + uint16 samplesperpixel; + size_t npixels; + unsigned char *pixels = NULL; + unsigned char *from = NULL, *to = NULL; + int x, y, from_i, to_i; + int extraSampleTypes[1] = { EXTRASAMPLE_ASSOCALPHA }; + + /* check for a valid number of bytes per pixel. Like the PNG writer, + * the TIFF writer supports 1, 3 or 4 bytes per pixel, corresponding + * to gray, RGB, RGBA respectively. */ + samplesperpixel = (uint16)((ibuf->depth + 7) >> 3); + if ((samplesperpixel > 4) || (samplesperpixel == 2)) { + printf("imb_savetiff: unsupported number of bytes per " \ + "pixel: %d\n", samplesperpixel); + return (0); + } + + /* open TIFF file for writing */ + if (flags & IB_mem) { + /* bork at the creation of a TIFF in memory */ + printf("imb_savetiff: creation of in-memory TIFF files is " \ + "not yet supported.\n"); + return (0); + } else { + /* create image as a file */ + image = libtiff_TIFFOpen(name, "w"); + } + if (image == NULL) { + printf("imb_savetiff: could not open TIFF for writing.\n"); + return (0); + } + + /* allocate array for pixel data */ + npixels = ibuf->x * ibuf->y; + pixels = (unsigned char*)libtiff__TIFFmalloc(npixels * + samplesperpixel * sizeof(unsigned char)); + if (pixels == NULL) { + printf("imb_savetiff: could not allocate pixels array.\n"); + libtiff_TIFFClose(image); + return (0); + } + + /* copy pixel data. While copying, we flip the image + * vertically. */ + from = (unsigned char*)ibuf->rect; + to = pixels; + libtiff_TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel); + switch (samplesperpixel) { + case 4: /* RGBA images, 8 bits per channel */ + libtiff_TIFFSetField(image, TIFFTAG_EXTRASAMPLES, 1, + extraSampleTypes); + libtiff_TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, 8); + libtiff_TIFFSetField(image, TIFFTAG_PHOTOMETRIC, + PHOTOMETRIC_RGB); + for (x = 0; x < ibuf->x; x++) { + for (y = 0; y < ibuf->y; y++) { + from_i = 4*(y*ibuf->x+x); + to_i = 4*((ibuf->y-y-1)*ibuf->x+x); + + to[to_i++] = from[from_i++]; + to[to_i++] = from[from_i++]; + to[to_i++] = from[from_i++]; + to[to_i] = from[from_i]; + } + } + break; + case 3: /* RGB images, 8 bits per channel */ + libtiff_TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, 8); + libtiff_TIFFSetField(image, TIFFTAG_PHOTOMETRIC, + PHOTOMETRIC_RGB); + for (x = 0; x < ibuf->x; x++) { + for (y = 0; y < ibuf->y; y++) { + from_i = 4*(y*ibuf->x+x); + to_i = 3*((ibuf->y-y-1)*ibuf->x+x); + + to[to_i++] = from[from_i++]; + to[to_i++] = from[from_i++]; + to[to_i] = from[from_i]; + } + } + break; + case 1: /* greyscale images, 1 channel with 8 bits */ + libtiff_TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, 8); + libtiff_TIFFSetField(image, TIFFTAG_PHOTOMETRIC, + PHOTOMETRIC_MINISBLACK); + for (x = 0; x < ibuf->x; x++) { + for (y = 0; y < ibuf->y; y++) { + from_i = 4*(y*ibuf->x+x); + to_i = 1*((ibuf->y-y-1)*ibuf->x+x); + + to[to_i] = from[from_i]; + } + } + break; + } + + /* write the actual TIFF file */ + libtiff_TIFFSetField(image, TIFFTAG_IMAGEWIDTH, ibuf->x); + libtiff_TIFFSetField(image, TIFFTAG_IMAGELENGTH, ibuf->y); + libtiff_TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, ibuf->y); + libtiff_TIFFSetField(image, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE); + libtiff_TIFFSetField(image, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB); + libtiff_TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + libtiff_TIFFSetField(image, TIFFTAG_XRESOLUTION, 150.0); + libtiff_TIFFSetField(image, TIFFTAG_YRESOLUTION, 150.0); + libtiff_TIFFSetField(image, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); + if (libtiff_TIFFWriteEncodedStrip(image, 0, pixels, + ibuf->x*ibuf->y*samplesperpixel) == -1) { + printf("imb_savetiff: Could not write encoded TIFF.\n"); + libtiff_TIFFClose(image); + libtiff__TIFFfree(pixels); + return (1); + } + + /* close the TIFF file */ + libtiff_TIFFClose(image); + libtiff__TIFFfree(pixels); + return (1); +} + diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c new file mode 100644 index 00000000000..4c7b5fec2c4 --- /dev/null +++ b/source/blender/imbuf/intern/util.c @@ -0,0 +1,397 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * util.c + * + * $Id$ + */ + +#include "BLI_blenlib.h" + +#include "DNA_userdef_types.h" +#include "BKE_global.h" + +#include "imbuf.h" +#include "imbuf_patch.h" +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "IMB_targa.h" +#include "IMB_png.h" + +#ifdef WITH_DDS +#include "dds/dds_api.h" +#endif + +#include "IMB_bmp.h" +#include "IMB_tiff.h" +#include "IMB_radiance_hdr.h" +#include "IMB_dpxcineon.h" + +#include "IMB_anim.h" + +#ifdef WITH_OPENEXR +#include "openexr/openexr_api.h" +#endif + +#ifdef WITH_QUICKTIME +#include "quicktime_import.h" +#endif + +#ifdef WITH_FFMPEG +#include +#include + +#if LIBAVFORMAT_VERSION_INT < (49 << 16) +#define FFMPEG_OLD_FRAME_RATE 1 +#else +#define FFMPEG_CODEC_IS_POINTER 1 +#endif + +#endif + +#define UTIL_DEBUG 0 + +/* from misc_util: flip the bytes from x */ +#define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1]) + +/* this one is only def-ed once, strangely... */ +#define GSS(x) (((uchar *)(x))[1] << 8 | ((uchar *)(x))[0]) + +static int IMB_ispic_name(char *name) +{ + struct stat st; + int fp, buf[10]; + int ofs = 0; + + if(UTIL_DEBUG) printf("IMB_ispic_name: loading %s\n", name); + + if (ib_stat(name,&st) == -1) return(0); + if (((st.st_mode) & S_IFMT) == S_IFREG){ + if ((fp = open(name,O_BINARY|O_RDONLY)) >= 0){ + if (read(fp,buf,32)==32){ + close(fp); + if (buf[ofs] == CAT) ofs += 3; + if (buf[ofs] == FORM){ + if (buf[ofs + 2] == ILBM) return(AMI); + if (buf[ofs + 2] == ANIM){ + if (buf[ofs + 3] == FORM){ + return(ANIM); + }else{ + return(Anim); + } + } + } else { + if (GS(buf) == IMAGIC) return(IMAGIC); + if (GSS(buf) == IMAGIC) return(IMAGIC); + if ((BIG_LONG(buf[0]) & 0xfffffff0) == 0xffd8ffe0) return(JPG); + + /* at windows there are ".ffl" files with the same magic numnber... + besides that, tim images are not really important anymore! */ + /* if ((BIG_LONG(buf[0]) == 0x10000000) && ((BIG_LONG(buf[1]) & 0xf0ffffff) == 0)) return(TIM); */ + + } + if (imb_is_a_png(buf)) return(PNG); +#ifdef WITH_DDS + if (imb_is_a_dds((uchar *)buf)) return(DDS); +#endif + if (imb_is_a_targa(buf)) return(TGA); +#ifdef WITH_OPENEXR + if (imb_is_a_openexr((uchar *)buf)) return(OPENEXR); +#endif + if (imb_is_a_tiff(buf)) return(TIF); + if (imb_is_dpx(buf)) return (DPX); + if (imb_is_cineon(buf)) return(CINEON); + /* radhdr: check if hdr format */ + if (imb_is_a_hdr(buf)) return(RADHDR); + +/* + if (imb_is_a_bmp(buf)) return(BMP); +*/ + +#ifdef WITH_QUICKTIME +#if defined(_WIN32) || defined(__APPLE__) + if(G.have_quicktime) { + if (imb_is_a_quicktime(name)) return(QUICKTIME); + } +#endif +#endif + + return(FALSE); + } + close(fp); + } + } + return(FALSE); +} + + + +int IMB_ispic(char *filename) +{ + if(U.uiflag & USER_FILTERFILEEXTS) { + if (G.have_libtiff && (BLI_testextensie(filename, ".tif") + || BLI_testextensie(filename, ".tiff"))) { + return IMB_ispic_name(filename); + } + if (G.have_quicktime){ + if( BLI_testextensie(filename, ".jpg") + || BLI_testextensie(filename, ".jpeg") + || BLI_testextensie(filename, ".tif") + || BLI_testextensie(filename, ".tiff") + || BLI_testextensie(filename, ".hdr") + || BLI_testextensie(filename, ".tga") + || BLI_testextensie(filename, ".rgb") + || BLI_testextensie(filename, ".bmp") + || BLI_testextensie(filename, ".png") +#ifdef WITH_DDS + || BLI_testextensie(filename, ".dds") +#endif + || BLI_testextensie(filename, ".iff") + || BLI_testextensie(filename, ".lbm") + || BLI_testextensie(filename, ".gif") + || BLI_testextensie(filename, ".psd") + || BLI_testextensie(filename, ".pct") + || BLI_testextensie(filename, ".pict") + || BLI_testextensie(filename, ".pntg") //macpaint + || BLI_testextensie(filename, ".qtif") + || BLI_testextensie(filename, ".cin") +#ifdef WITH_BF_OPENEXR + || BLI_testextensie(filename, ".exr") +#endif + || BLI_testextensie(filename, ".sgi")) { + return IMB_ispic_name(filename); + } else { + return(FALSE); + } + } else { /* no quicktime or libtiff */ + if( BLI_testextensie(filename, ".jpg") + || BLI_testextensie(filename, ".jpeg") + || BLI_testextensie(filename, ".hdr") + || BLI_testextensie(filename, ".tga") + || BLI_testextensie(filename, ".rgb") + || BLI_testextensie(filename, ".bmp") + || BLI_testextensie(filename, ".png") + || BLI_testextensie(filename, ".cin") +#ifdef WITH_DDS + || BLI_testextensie(filename, ".dds") +#endif +#ifdef WITH_BF_OPENEXR + || BLI_testextensie(filename, ".exr") +#endif + || BLI_testextensie(filename, ".iff") + || BLI_testextensie(filename, ".lbm") + || BLI_testextensie(filename, ".sgi")) { + return IMB_ispic_name(filename); + } + else { + return(FALSE); + } + } + } else { /* no FILTERFILEEXTS */ + return IMB_ispic_name(filename); + } +} + + + +static int isavi (char *name) { + return AVI_is_avi (name); +} + +#ifdef WITH_QUICKTIME +static int isqtime (char *name) { + return anim_is_quicktime (name); +} +#endif + +#ifdef WITH_FFMPEG +void do_init_ffmpeg() +{ + static int ffmpeg_init = 0; + if (!ffmpeg_init) { + ffmpeg_init = 1; + av_register_all(); + } +} + +#ifdef FFMPEG_CODEC_IS_POINTER +static AVCodecContext* get_codec_from_stream(AVStream* stream) +{ + return stream->codec; +} +#else +static AVCodecContext* get_codec_from_stream(AVStream* stream) +{ + return &stream->codec; +} +#endif + + +static int isffmpeg (char *filename) { + AVFormatContext *pFormatCtx; + int i, videoStream; + AVCodec *pCodec; + AVCodecContext *pCodecCtx; + + do_init_ffmpeg(); + + if( BLI_testextensie(filename, ".swf") || + BLI_testextensie(filename, ".jpg") || + BLI_testextensie(filename, ".png") || + BLI_testextensie(filename, ".dds") || + BLI_testextensie(filename, ".tga") || + BLI_testextensie(filename, ".bmp") || + BLI_testextensie(filename, ".exr") || + BLI_testextensie(filename, ".cin") || + BLI_testextensie(filename, ".wav")) return 0; + + if(av_open_input_file(&pFormatCtx, filename, NULL, 0, NULL)!=0) { + if(UTIL_DEBUG) fprintf(stderr, "isffmpeg: av_open_input_file failed\n"); + return 0; + } + + if(av_find_stream_info(pFormatCtx)<0) { + if(UTIL_DEBUG) fprintf(stderr, "isffmpeg: av_find_stream_info failed\n"); + av_close_input_file(pFormatCtx); + return 0; + } + + if(UTIL_DEBUG) dump_format(pFormatCtx, 0, filename, 0); + + + /* Find the first video stream */ + videoStream=-1; + for(i=0; inb_streams; i++) + if(get_codec_from_stream(pFormatCtx->streams[i]) + ->codec_type==CODEC_TYPE_VIDEO) + { + videoStream=i; + break; + } + + if(videoStream==-1) { + av_close_input_file(pFormatCtx); + return 0; + } + + pCodecCtx = get_codec_from_stream(pFormatCtx->streams[videoStream]); + + /* Find the decoder for the video stream */ + pCodec=avcodec_find_decoder(pCodecCtx->codec_id); + if(pCodec==NULL) { + avcodec_close(pCodecCtx); + av_close_input_file(pFormatCtx); + return 0; + } + + if(avcodec_open(pCodecCtx, pCodec)<0) { + avcodec_close(pCodecCtx); + av_close_input_file(pFormatCtx); + return 0; + } + + avcodec_close(pCodecCtx); + av_close_input_file(pFormatCtx); + + return 1; +} +#endif + +int imb_get_anim_type(char * name) { + int type; + struct stat st; + + if(UTIL_DEBUG) printf("in getanimtype: %s\n", name); + +#ifndef _WIN32 +# ifdef WITH_FFMPEG + /* stat test below fails on large files > 4GB */ + if (isffmpeg(name)) return (ANIM_FFMPEG); +# endif + if (ib_stat(name,&st) == -1) return(0); + if (((st.st_mode) & S_IFMT) != S_IFREG) return(0); + + if (isavi(name)) return (ANIM_AVI); + + if (ismovie(name)) return (ANIM_MOVIE); +# ifdef WITH_QUICKTIME + if (isqtime(name)) return (ANIM_QTIME); +# endif +#else + if (ib_stat(name,&st) == -1) return(0); + if (((st.st_mode) & S_IFMT) != S_IFREG) return(0); + + if (isavi(name)) return (ANIM_AVI); + + if (ismovie(name)) return (ANIM_MOVIE); +# ifdef WITH_QUICKTIME + if (isqtime(name)) return (ANIM_QTIME); +# endif +# ifdef WITH_FFMPEG + if (isffmpeg(name)) return (ANIM_FFMPEG); +# endif +#endif + type = IMB_ispic(name); + if (type == ANIM) return (ANIM_ANIM5); + if (type) return(ANIM_SEQUENCE); + return(0); +} + +int IMB_isanim(char *filename) { + int type; + + if(U.uiflag & USER_FILTERFILEEXTS) { + if (G.have_quicktime){ + if( BLI_testextensie(filename, ".avi") + || BLI_testextensie(filename, ".flc") + || BLI_testextensie(filename, ".dv") + || BLI_testextensie(filename, ".mov") + || BLI_testextensie(filename, ".movie") + || BLI_testextensie(filename, ".mv")) { + type = imb_get_anim_type(filename); + } else { + return(FALSE); + } + } else { // no quicktime + if( BLI_testextensie(filename, ".avi") + || BLI_testextensie(filename, ".dv") + || BLI_testextensie(filename, ".mv")) { + type = imb_get_anim_type(filename); + } + else { + return(FALSE); + } + } + } else { // no FILTERFILEEXTS + type = imb_get_anim_type(filename); + } + + return (type && type!=ANIM_SEQUENCE); +} diff --git a/source/blender/imbuf/intern/writeimage.c b/source/blender/imbuf/intern/writeimage.c new file mode 100644 index 00000000000..ccca8e9f859 --- /dev/null +++ b/source/blender/imbuf/intern/writeimage.c @@ -0,0 +1,185 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * writeimage.c + * + * $Id$ + */ + +#ifdef WIN32 +#include +#endif + +#include "BKE_global.h" +#include "BLI_blenlib.h" + +#include "imbuf.h" +#include "imbuf_patch.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "IMB_allocimbuf.h" + +#include "IMB_dpxcineon.h" +#include "IMB_targa.h" +#include "IMB_jpeg.h" +#include "IMB_iris.h" +#include "IMB_ham.h" +#include "IMB_hamx.h" +#include "IMB_amiga.h" +#include "IMB_png.h" +#include "IMB_bmp.h" +#include "IMB_tiff.h" +#include "IMB_radiance_hdr.h" +#ifdef WITH_OPENEXR +#include "openexr/openexr_api.h" +#endif +#ifdef WITH_DDS +#include "dds/dds_api.h" +#endif + +#include "IMB_iff.h" +#include "IMB_bitplanes.h" +#include "IMB_divers.h" + +/* added facility to copy with saving non-float rects */ + +short IMB_saveiff(struct ImBuf *ibuf, char *name, int flags) +{ + short ok=TRUE,delpl=FALSE; + int file = -1; + + if (ibuf==0) return (FALSE); + ibuf->flags = flags; + + /* Put formats that take a filename here */ + if (IS_jpg(ibuf)) { + if(ibuf->rect==NULL && ibuf->rect_float) + IMB_rect_from_float(ibuf); + return imb_savejpeg(ibuf, name, flags); + } + if (IS_radhdr(ibuf)) { + return imb_savehdr(ibuf, name, flags); + } + if (IS_png(ibuf)) { + if(ibuf->rect==NULL && ibuf->rect_float) + IMB_rect_from_float(ibuf); + return imb_savepng(ibuf, name, flags); + } + if (IS_bmp(ibuf)) { + if(ibuf->rect==NULL && ibuf->rect_float) + IMB_rect_from_float(ibuf); + return imb_savebmp(ibuf, name, flags); + } + if (IS_tga(ibuf)) { + if(ibuf->rect==NULL && ibuf->rect_float) + IMB_rect_from_float(ibuf); + return imb_savetarga(ibuf, name, flags); + } + if (IS_iris(ibuf)) { + if(ibuf->rect==NULL && ibuf->rect_float) + IMB_rect_from_float(ibuf); + return imb_saveiris(ibuf, name, flags); + } + if (G.have_libtiff && IS_tiff(ibuf)) { + if(ibuf->rect==NULL && ibuf->rect_float) + IMB_rect_from_float(ibuf); + return imb_savetiff(ibuf, name, flags); + } +#ifdef WITH_OPENEXR + if (IS_openexr(ibuf)) { + return imb_save_openexr(ibuf, name, flags); + } +#endif +/* not supported yet +#ifdef WITH_DDS + if (IS_dds(ibuf)) { + return imb_save_dds(ibuf, name, flags); + } +#endif +*/ + if (IS_cineon(ibuf)) { + return imb_savecineon(ibuf, name, flags); + + } + if (IS_dpx(ibuf)) { + return imb_save_dpx(ibuf, name, flags); + } + file = open(name, O_BINARY | O_RDWR | O_CREAT | O_TRUNC, 0666); + if (file < 0) return (FALSE); + + if (flags & IB_rect){ + if (ibuf->cmap){ + imb_checkncols(ibuf); + } + } + + /* Put formats that take a filehandle here */ + ok = imb_start_iff(ibuf,file); + if (IS_amiga(ibuf)){ + IMB_flipy(ibuf); + if (flags & IB_rect){ + if ((flags & IB_cmap) == 0) { + if (IS_ham(ibuf)){ + if (ok) ok = imb_converttoham(ibuf); + }else if (ibuf->cmap){ + if (ok) ok = IMB_converttocmap(ibuf); + } + } + if (ok){ + if (ibuf->planes==0){ + delpl=TRUE; + ok=imb_addplanesImBuf(ibuf); + } + imb_longtobp(ibuf); + } + } + + if (flags & IB_vert){ + if (ok) ok = imb_encodebodyv(ibuf,file); + } + else{ + if (ok) ok = imb_encodebodyh(ibuf,file); + } + if (ok) ok = imb_update_iff(file,BODY); + }else if (IS_anim(ibuf)) { + if (ok) ok = imb_enc_anim(ibuf, file); + if (ok) ok = imb_update_iff(file, BODY); + } + close(file); + + if (ok==FALSE) { + fprintf(stderr,"Couldn't save picture.\n"); + } + if (delpl) imb_freeplanesImBuf(ibuf); + + return (ok); +} + diff --git a/source/blender/imbuf/readme.txt b/source/blender/imbuf/readme.txt new file mode 100644 index 00000000000..181d5485310 --- /dev/null +++ b/source/blender/imbuf/readme.txt @@ -0,0 +1,50 @@ +The following 4 steps to adding a new image format to blender, its +probably easiest to look at the png code for a clean clear example, +animation formats are a bit more complicated but very similar: + +Step 1: +create a new file named after the format for example lets say we were +creating an openexr read/writer use openexr.c +It should contain functions to match the following prototypes: + +struct ImBuf *imb_loadopenexr(unsigned char *mem,int size,int flags); +/* Use one of the following depending on whats easyer for your file format */ +short imb_saveopenexr(struct ImBuf *ibuf, FILE myfile, int flags); +short imb_saveopenexr(struct ImBuf *ibuf, char *myfile, int flags); + +/* Used to test if its the correct format +int IMB_is_openexr(void *buf); + +Step 2: +Add your hooks to read and write the image format these go in + writeimage.c and readimage.c just look at how the others are done + +Step 3: +Add in IS_openexr to blender/source/blender/imbuf/IMB_imbuf_types.h +Add in R_openexr to source/blender/makesdna/DNA_scene_types.h + +Step 4: +Add your hooks to the gui. +source/blender/src/buttons_scene.c +source/blender/src/toets.c +source/blender/src/writeimage.c + +Step 5: +edit the following files: +blender/source/blender/imbuf/intern/util.c +blender/source/blender/src/filesel.c +blender/source/blender/src/screendump.c +and add your extension so that your format gets recognized in the thumbnails. + +Step 6: +Alter the build process: +For scons you need to edit blender/source/blender/imbuf/SConscript +and add in your additional files to source_files. +For msvp you need to edit blender/projectfiles/blender/imbuf/BL_imbuf.dsp +and add in your additional files. +If you have any external library info you will also need to add that +to the various build processes. + +Step 7: +Its also good to add your image format to: +makepicstring in blender/source/blender/blenkernel/intern/image.c diff --git a/source/blender/include/BDR_drawaction.h b/source/blender/include/BDR_drawaction.h new file mode 100644 index 00000000000..673b13672c1 --- /dev/null +++ b/source/blender/include/BDR_drawaction.h @@ -0,0 +1,88 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BDR_DRAWACTION_H +#define BDR_DRAWACTION_H + +struct BezTriple; +struct Ipo; +struct IpoCurve; +struct gla2DDrawInfo; +struct bAction; +struct Object; +struct ListBase; + +/* ****************************** Base Structs ****************************** */ + +/* Keyframe Column Struct */ +typedef struct ActKeyColumn { + struct ActKeyColumn *next, *prev; + short sel, handle_type; + float cfra; + + /* only while drawing - used to determine if long-keyframe needs to be drawn */ + short modified; + short totcurve; +} ActKeyColumn; + +/* 'Long Keyframe' Struct */ +typedef struct ActKeyBlock { + struct ActKeyBlock *next, *prev; + short sel, handle_type; + float val; + float start, end; + + /* only while drawing - used to determine if block needs to be drawn */ + short modified; + short totcurve; +} ActKeyBlock; + + +/* ******************************* Methods ****************************** */ + +/* Action Generics */ +void draw_cfra_action(void); + +/* Channel Drawing */ +void draw_icu_channel(struct gla2DDrawInfo *di, struct IpoCurve *icu, float ypos); +void draw_ipo_channel(struct gla2DDrawInfo *di, struct Ipo *ipo, float ypos); +void draw_action_channel(struct gla2DDrawInfo *di, bAction *act, float ypos); +void draw_object_channel(struct gla2DDrawInfo *di, Object *ob, float ypos); + +/* Keydata Generation */ +void icu_to_keylist(struct IpoCurve *icu, ListBase *keys, ListBase *blocks); +void ipo_to_keylist(struct Ipo *ipo, ListBase *keys, ListBase *blocks); +void action_to_keylist(bAction *act, ListBase *keys, ListBase *blocks); +void ob_to_keylist(Object *ob, ListBase *keys, ListBase *blocks); + +#endif /* BDR_DRAWACTION_H */ + diff --git a/source/blender/include/BDR_drawmesh.h b/source/blender/include/BDR_drawmesh.h new file mode 100644 index 00000000000..998cadc18a3 --- /dev/null +++ b/source/blender/include/BDR_drawmesh.h @@ -0,0 +1,84 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BDR_DRAWMESH_H +#define BDR_DRAWMESH_H + +struct Image; +struct MTFace; +struct Object; +struct DerivedMesh; +struct Mesh; +struct EdgeHash; + +/** + * Enables or disable mipmapping for realtime images (textures). + * Note that this will will destroy all texture bindings in OpenGL. + * @see free_realtime_image() + * @param mipmap Turn mipmapping on (mipmap!=0) or off (mipmap==0). + */ +void set_mipmap(int mipmap); + +/** + * Enables or disable linear mipmap setting for realtime images (textures). + * Note that this will will destroy all texture bindings in OpenGL. + * @see free_realtime_image() + * @param mipmap Turn linear mipmapping on (linear!=0) or off (linear==0). + */ +void set_linear_mipmap(int linear); + +/** + * Returns the current setting for linear mipmapping. + */ +int get_linear_mipmap(void); + +/** + * Resets the realtime image cache variables. + */ +void clear_realtime_image_cache(void); + + +void update_realtime_image(struct Image *ima, int x, int y, int w, int h); +void free_realtime_image(struct Image *ima); +void free_all_realtime_images(void); +void make_repbind(struct Image *ima); +int set_tpage(struct MTFace *tface); + +void texpaint_enable_mipmap(void); +void texpaint_disable_mipmap(void); + +void draw_mesh_textured(struct Object *ob, struct DerivedMesh *dm, int facesel); +struct EdgeHash *get_tface_mesh_marked_edge_info(struct Mesh *me); +void init_realtime_GL(void); + +#endif /* BDR_DRAWMESH_H */ + diff --git a/source/blender/include/BDR_drawobject.h b/source/blender/include/BDR_drawobject.h new file mode 100644 index 00000000000..05bf4d75e88 --- /dev/null +++ b/source/blender/include/BDR_drawobject.h @@ -0,0 +1,82 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BDR_DRAWOBJECT_H +#define BDR_DRAWOBJECT_H + +#ifdef __cplusplus +extern "C" { +#endif + + +struct Object; +struct Nurb; +struct Lamp; +struct ListBase; +struct BoundBox; +struct Base; +struct BPoint; +struct BezTriple; +struct EditVert; +struct EditFace; +struct EditEdge; + +int set_gl_material(int nr); +int init_gl_materials(struct Object *ob, int check_alpha); + +void mesh_foreachScreenVert(void (*func)(void *userData, struct EditVert *eve, int x, int y, int index), void *userData, int clipVerts); +void mesh_foreachScreenEdge(void (*func)(void *userData, struct EditEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts); +void mesh_foreachScreenFace(void (*func)(void *userData, struct EditFace *efa, int x, int y, int index), void *userData); + +void lattice_foreachScreenVert(void (*func)(void *userData, struct BPoint *bp, int x, int y), void *userData); +void nurbs_foreachScreenVert(void (*func)(void *userData, struct Nurb *nu, struct BPoint *bp, struct BezTriple *bezt, int beztindex, int x, int y), void *userData); + +void drawcircball(int mode, float *cent, float rad, float tmat[][4]); +void get_local_bounds(struct Object *ob, float *center, float *size); + +/* drawing flags: */ +#define DRAW_PICKING 1 +#define DRAW_CONSTCOLOR 2 +void draw_object(struct Base *base, int flag); +void drawaxes(float size, int flag, char drawtype); + +void draw_object_ext(struct Base *base); +void drawsolidcube(float size); +extern void draw_object_backbufsel(struct Object *ob); +void draw_object_instance(struct Object *ob, int dt, int outline); + +#ifdef __cplusplus +} +#endif + +#endif /* BDR_DRAWOBJECT_H */ + diff --git a/source/blender/include/BDR_editcurve.h b/source/blender/include/BDR_editcurve.h new file mode 100644 index 00000000000..a8c36c3485b --- /dev/null +++ b/source/blender/include/BDR_editcurve.h @@ -0,0 +1,102 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BDR_EDITCURVE_H +#define BDR_EDITCURVE_H + +struct Object; +struct Curve; +struct Nurb; +struct BezTriple; +struct BPoint; +struct BezTripleNurb; + +short isNurbsel(struct Nurb *nu); +int isNurbsel_count(struct Nurb *nu); +void printknots(void); +void load_editNurb(void); +void make_editNurb(void); +void remake_editNurb(void); +void separate_nurb(void); +short isNurbselUV(struct Nurb *nu, int *u, int *v, int flag); +void setflagsNurb(short flag); +void rotateflagNurb(short flag, float *cent, float rotmat[][3]); +void translateflagNurb(short flag, float *vec); +void weightflagNurb(short flag, float w, int mode); +void deleteflagNurb(short flag); +short extrudeflagNurb(int flag); +void adduplicateflagNurb(short flag); +void switchdirectionNurb2(void); +void switchdirection_knots(float *base, int tot); +void deselectall_nurb(void); +void hideNurb(int swap); +void revealNurb(void); +void selectswapNurb(void); +void subdivideNurb(void); + +int convertspline(short type, struct Nurb *nu); +void setsplinetype(short type); +void rotate_direction_nurb(struct Nurb *nu); +int is_u_selected(struct Nurb *nu, int u); +void make_selection_list_nurb(void); +void merge_2_nurb(struct Nurb *nu1, struct Nurb *nu2); +void merge_nurb(void); +void addsegment_nurb(void); +void mouse_nurb(void); +void spinNurb(float *dvec, short mode); +void addvert_Nurb(int mode); +void extrude_nurb(void); +void makecyclicNurb(void); +void selectconnected_nurb(void); +void selectrow_nurb(void); +void selectend_nurb(short selfirst, short doswap, short selstatus); +void select_more_nurb(void); +void select_less_nurb(void); +void select_next_nurb(void); +void select_prev_nurb(void); +void select_random_nurb(void); +void select_every_nth_nurb(void); +void adduplicate_nurb(void); +void delNurb(void); +void nurb_set_smooth(short event); +int join_curve(int type); +struct Nurb *addNurbprim(int type, int stype, int newname); +void default_curve_ipo(struct Curve *cu); +void add_primitiveCurve(int stype); +void add_primitiveNurb(int type); +void clear_tilt(void); +void clever_numbuts_curve(void); +int bezt_compare (const void *e1, const void *e2); + +extern void undo_push_curve(char *name); + +#endif /* BDR_EDITCURVE_H */ diff --git a/source/blender/include/BDR_editface.h b/source/blender/include/BDR_editface.h new file mode 100644 index 00000000000..72b0e7352da --- /dev/null +++ b/source/blender/include/BDR_editface.h @@ -0,0 +1,61 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BDR_EDITFACE_H +#define BDR_EDITFACE_H + +struct MTFace; +struct EditFace; +struct Mesh; +struct MCol; + +struct MTFace *get_active_mtface(struct EditFace **efa, struct MCol **mcol, short sloppy); +void calculate_uv_map(unsigned short mapmode); +void default_uv(float uv[][2], float size); +void make_tfaces(struct Mesh *me); +void reveal_tface(void); +void hide_tface(void); +void select_linked_tfaces(int mode); +void deselectall_tface(void); +void selectswap_tface(void); +void rotate_uv_tface(void); +void mirror_uv_tface(void); +int minmax_tface(float *min, float *max); +void face_select(void); +void face_borderselect(void); +void uv_autocalc_tface(void); +void set_texturepaint(void); +void get_same_uv(void); +void seam_mark_clear_tface(short mode); + +#endif /* BDR_EDITFACE_H */ + diff --git a/source/blender/include/BDR_editmball.h b/source/blender/include/BDR_editmball.h new file mode 100644 index 00000000000..e2b529acaf8 --- /dev/null +++ b/source/blender/include/BDR_editmball.h @@ -0,0 +1,56 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BDR_EDITMBALL_H +#define BDR_EDITMBALL_H + +void make_editMball(void); +void load_editMball(void); + +/** + * @attention The argument is discarded. It is there for + * compatibility. + */ +void add_primitiveMball(int); +void deselectall_mball(void); +void selectinverse_mball(void); +void selectrandom_mball(void); +void mouse_mball(void); +void adduplicate_mball(void); +void delete_mball(void); +void freeMetaElemlist(struct ListBase *lb); +void undo_push_mball(char *name); +void hide_mball(char hide); +void reveal_mball(void); + +#endif /* BDR_EDITMBALL_H */ + diff --git a/source/blender/include/BDR_editobject.h b/source/blender/include/BDR_editobject.h new file mode 100644 index 00000000000..2a96a8d65cb --- /dev/null +++ b/source/blender/include/BDR_editobject.h @@ -0,0 +1,125 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BDR_EDITOBJECT_H +#define BDR_EDITOBJECT_H + +struct Object; +struct Tex; +struct Material; +struct Base; +struct HookModifierData; +struct Scene; + +void add_object_draw(int type); +void add_objectLamp(short type); +void free_and_unlink_base_from_scene(struct Scene *scene, struct Base *base); +void free_and_unlink_base(struct Base *base); +void delete_obj(int ok); +void make_track(void); +void apply_obmat(struct Object *ob); +void clear_parent(void); +void clear_track(void); +void clear_object(char mode); +void reset_slowparents(void); +void set_slowparent(void); +void make_vertex_parent(void); +int test_parent_loop(struct Object *par, struct Object *ob); +void make_parent(void); +void make_proxy(void); + +#define EM_WAITCURSOR (1 << 0) +#define EM_FREEDATA (1 << 1) +#define EM_FREEUNDO (1 << 2) + +void exit_editmode(int flag); +void check_editmode(int type); +void enter_editmode(int wc); + +void docenter(int centermode); +void docenter_new(void); +void docenter_cursor(void); +void movetolayer(void); +void special_editmenu(void); +void convertmenu(void); +void copy_attr_menu(void); +void copy_attr(short event); +void link_to_scene(unsigned short nr); +void make_links_menu(void); +void make_links(short event); +void make_duplilist_real(void); +void apply_object(void); + +/* old transform */ +void apply_keyb_grid(float *val, float fac1, float fac2, float fac3, int invert); +void headerprint(char *str); +/* used for old game engine collision optimize */ +int cylinder_intersect_test(void); +int sphere_intersect_test(void); + + +void std_rmouse_transform(void (*xf_func)(int, int)); +void rightmouse_transform(void); +void single_object_users(int flag); +void new_id_matar(struct Material **matar, int totcol); +void single_obdata_users(int flag); +void single_mat_users(int flag); +void do_single_tex_user(struct Tex **from); +void single_tex_users_expand(void); +void single_mat_users_expand(void); +void single_user(void); +void make_local_menu(void); +void make_local(int mode); +void adduplicate(int mode, int dupflag); /* when the dupflag is 0 no data is duplicated */ +void selectlinks_menu(void); +void selectlinks(int nr); +void image_aspect(void); +void set_ob_ipoflags(void); +void select_select_keys(void); +int vergbaseco(const void *a1, const void *a2); +void auto_timeoffs(void); +void texspace_edit(void); +void flip_subdivison(int); +void mirrormenu(void); +void hookmenu(void); /* object mode hook menu */ + + +void add_hook(void); +void hook_select(struct HookModifierData *hmd); +int hook_getIndexArray(int *tot, int **indexar, char *name, float *cent_r); + +int object_data_is_libdata(struct Object *ob); +void hide_objects(int select); +void show_objects(void); + +#endif /* BDR_EDITOBJECT_H */ + diff --git a/source/blender/include/BDR_imagepaint.h b/source/blender/include/BDR_imagepaint.h new file mode 100644 index 00000000000..e687d220906 --- /dev/null +++ b/source/blender/include/BDR_imagepaint.h @@ -0,0 +1,44 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BDR_IMAGEPAINT_H +#define BDR_IMAGEPAINT_H + +void imagepaint_redraw_tool(void); +void imagepaint_pick(short mousebutton); +void imagepaint_paint(short mousebutton, short texturepaint); + +void imagepaint_undo(); +void free_imagepaint(); + +#endif /* BDR_IMAGEPAINT_H */ + diff --git a/source/blender/include/BDR_sculptmode.h b/source/blender/include/BDR_sculptmode.h new file mode 100644 index 00000000000..c80f9ea8626 --- /dev/null +++ b/source/blender/include/BDR_sculptmode.h @@ -0,0 +1,142 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 by Nicholas Bishop + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BDR_SCULPTMODE_H +#define BDR_SCULPTMODE_H + +#include "DNA_listBase.h" +#include "DNA_vec_types.h" +/* For bglMats */ +#include "BIF_glutil.h" +#include "transform.h" + +struct uiBlock; +struct BrushData; +struct EditData; +struct IndexNode; +struct KeyBlock; +struct Mesh; +struct Object; +struct PartialVisibility; +struct Scene; +struct ScrArea; +struct SculptData; +struct SculptStroke; + +typedef enum PropsetMode { + PropsetNone = 0, + PropsetSize, + PropsetStrength, + PropsetTexRot +} PropsetMode; +typedef struct PropsetData { + PropsetMode mode; + unsigned int tex; + short origloc[2]; + float *texdata; + + short origsize; + char origstrength; + float origtexrot; + + NumInput num; +} PropsetData; + +typedef struct SculptSession { + bglMats mats; + + /* An array of lists; array is sized as + large as the number of verts in the mesh, + the list for each vert contains the index + for all the faces that use that vertex */ + struct ListBase *vertex_users; + struct IndexNode *vertex_users_mem; + int vertex_users_size; + + /* Used temporarily per-stroke */ + float *vertexcosnos; + ListBase damaged_rects; + ListBase damaged_verts; + + /* Used to cache the render of the active texture */ + unsigned int texcache_w, texcache_h, *texcache; + + PropsetData *propset; + + /* For rotating around a pivot point */ + vec3f pivot; + + struct SculptStroke *stroke; +} SculptSession; + +SculptSession *sculpt_session(void); +struct SculptData *sculpt_data(void); + +/* Memory */ +void sculptmode_init(struct Scene *); +void sculptmode_free_all(struct Scene *); +void sculptmode_correct_state(void); + +/* Interface */ +void sculptmode_draw_interface_tools(struct uiBlock *block,unsigned short cx, unsigned short cy); +void sculptmode_draw_interface_textures(struct uiBlock *block,unsigned short cx, unsigned short cy); +void sculptmode_rem_tex(void*,void*); +void sculptmode_propset_init(PropsetMode mode); +void sculptmode_propset(const unsigned short event); +void sculptmode_selectbrush_menu(void); +void sculptmode_draw_mesh(int); +void sculpt_paint_brush(char clear); +void sculpt_stroke_draw(); + +struct BrushData *sculptmode_brush(void); +float tex_angle(void); +void do_symmetrical_brush_actions(struct EditData *e, short *, short *); + +void sculptmode_update_tex(void); +char sculpt_modifiers_active(struct Object *ob); +void sculpt(void); +void set_sculptmode(void); + +/* Stroke */ +void sculpt_stroke_new(const int max); +void sculpt_stroke_free(); +void sculpt_stroke_add_point(const short x, const short y); +void sculpt_stroke_apply(struct EditData *); +void sculpt_stroke_apply_all(struct EditData *e); +void sculpt_stroke_draw(); + + +/* Partial Mesh Visibility */ +struct PartialVisibility *sculptmode_copy_pmv(struct PartialVisibility *); +void sculptmode_pmv_free(struct PartialVisibility *); +void sculptmode_revert_pmv(struct Mesh *me); +void sculptmode_pmv_off(struct Mesh *me); +void sculptmode_pmv(int mode); + +#endif diff --git a/source/blender/include/BDR_unwrapper.h b/source/blender/include/BDR_unwrapper.h new file mode 100644 index 00000000000..6a2b54409c3 --- /dev/null +++ b/source/blender/include/BDR_unwrapper.h @@ -0,0 +1,51 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BDR_UNWRAPPER_H +#define BDR_UNWRAPPER_H + +struct Mesh; + +void set_seamtface(void); /* set TF_SEAM flags in tfaces */ +void select_linked_tfaces_with_seams(int mode, struct Mesh *me, unsigned int index); + +void unwrap_lscm(short seamcut); /* unwrap faces selected in 3d view */ +void minimize_stretch_tface_uv(void); /* optimize faces selected in uv editor */ +void pack_charts_tface_uv(void); + +/* for live mode: no undo pushes, caching for quicky re-unwrap */ +void unwrap_lscm_live_begin(void); +void unwrap_lscm_live_re_solve(void); +void unwrap_lscm_live_end(short cancel); + +#endif /* BDR_UNWRAPPER_H */ + diff --git a/source/blender/include/BDR_vpaint.h b/source/blender/include/BDR_vpaint.h new file mode 100644 index 00000000000..dcf9d4ce51a --- /dev/null +++ b/source/blender/include/BDR_vpaint.h @@ -0,0 +1,58 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BDR_VPAINT_H +#define BDR_VPAINT_H + +struct Mesh; +struct MDeformVert; /* __NLA */ + +unsigned int rgba_to_mcol(float r, float g, float b, float a); +void do_shared_vertexcol(struct Mesh *me); +void make_vertexcol(int shade); + +void clear_vpaint(void); +void clear_vpaint_selectedfaces(void); +void vpaint_dogamma(void); +void sample_vpaint(void); + +void free_vertexpaint(void); +void vertex_paint(void); +void set_vpaint(void); + +void set_wpaint(void); +void clear_wpaint_selectedfaces(void); +void weight_paint(void); + + +#endif /* BDR_VPAINT_H */ + diff --git a/source/blender/include/BIF_butspace.h b/source/blender/include/BIF_butspace.h new file mode 100644 index 00000000000..eb2cafad792 --- /dev/null +++ b/source/blender/include/BIF_butspace.h @@ -0,0 +1,139 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BIF_BUTSPACE_H +#define BIF_BUTSPACE_H + +/* all internal/external calls and event codes for buttons space */ +/* should be split in 2 parts... */ + +struct Base; +struct ID; + +/* external, butspace.c */ +extern void do_butspace(unsigned short event); +extern void redraw_test_buttons(struct Object *new); + +extern char *image_type_pup(void); + +/* buttons_editing.c */ +extern void validate_editbonebutton_cb(void *bonev, void *namev); + +/* buts->mainb old */ +#define BUTS_VIEW 0 +#define BUTS_LAMP 1 +#define BUTS_MAT 2 +#define BUTS_TEX 3 +#define BUTS_ANIM 4 +#define BUTS_WORLD 5 +#define BUTS_RENDER 6 +#define BUTS_EDIT 7 +#define BUTS_GAME 8 +#define BUTS_FPAINT 9 +#define BUTS_RADIO 10 +#define BUTS_SCRIPT 11 +#define BUTS_SOUND 12 +#define BUTS_CONSTRAINT 13 +#define BUTS_EFFECTS 14 + +/* warning: the values of these defines are used in sbuts->tabs[7] */ +/* buts->mainb new */ +#define CONTEXT_SCENE 0 +#define CONTEXT_OBJECT 1 +#define CONTEXT_TYPES 2 +#define CONTEXT_SHADING 3 +#define CONTEXT_EDITING 4 +#define CONTEXT_SCRIPT 5 +#define CONTEXT_LOGIC 6 + +/* buts->tab new */ +#define TAB_SHADING_MAT 0 +#define TAB_SHADING_TEX 1 +#define TAB_SHADING_RAD 2 +#define TAB_SHADING_WORLD 3 +#define TAB_SHADING_LAMP 4 + +#define TAB_OBJECT_OBJECT 0 +#define TAB_OBJECT_PHYSICS 1 + +#define TAB_SCENE_RENDER 0 +#define TAB_SCENE_WORLD 1 +#define TAB_SCENE_ANIM 2 +#define TAB_SCENE_SOUND 3 + + +/* buts->scaflag */ +#define BUTS_SENS_SEL 1 +#define BUTS_SENS_ACT 2 +#define BUTS_SENS_LINK 4 +#define BUTS_CONT_SEL 8 +#define BUTS_CONT_ACT 16 +#define BUTS_CONT_LINK 32 +#define BUTS_ACT_SEL 64 +#define BUTS_ACT_ACT 128 +#define BUTS_ACT_LINK 256 + + +/* buttons grid */ +#define PANELX 320 +#define PANELY 0 +#define PANELW 318 +#define PANELH 204 + +#define BUTW1 300 +#define BUTW2 145 +#define BUTW3 93 +#define BUTW4 67 +#define ICONBUTW 20 +#define BUTH 22 + +#define YSPACE 6 +#define XSPACE 10 +#define PANEL_YMAX 210 +#define PANEL_XMAX 310 + +#define X1CLM1 10 + +#define X2CLM1 X1CLM1 +#define X2CLM2 165 + +#define X3CLM1 X1CLM1 +#define X3CLM2 113 +#define X3CLM3 217 + +#define X4CLM1 X1CLM1 +#define X4CLM2 77 +#define X4CLM3 165 +#define X4CLM4 232 + + +#endif + diff --git a/source/blender/include/BIF_cursors.h b/source/blender/include/BIF_cursors.h new file mode 100644 index 00000000000..fe3ff6e2506 --- /dev/null +++ b/source/blender/include/BIF_cursors.h @@ -0,0 +1,103 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + + + +#ifndef __BLI_CURSORS_DOT_H__ +#define __BLI_CURSORS_DOT_H__ + +void InitCursorData(void); +short GetBlenderCursor(void); +void SetBlenderCursor(short cursornum); + +//typedef struct BCursor_s BCursor; +typedef struct BCursor { + + char *small_bm; + char *small_mask; + + char small_sizex; + char small_sizey; + char small_hotx; + char small_hoty; + + char *big_bm; + char *big_mask; + + char big_sizex; + char big_sizey; + char big_hotx; + char big_hoty; + + char fg_color; + char bg_color; + +} BCursor; + +#define LASTCURSOR -2 +#define SYSCURSOR -1 +enum { + BC_NW_ARROWCURSOR=0, + BC_NS_ARROWCURSOR, + BC_EW_ARROWCURSOR, + BC_WAITCURSOR, + BC_CROSSCURSOR, + BC_EDITCROSSCURSOR, + BC_BOXSELCURSOR, + BC_KNIFECURSOR, + BC_VLOOPCURSOR, + BC_TEXTEDITCURSOR, + BC_PAINTBRUSHCURSOR, + BC_HANDCURSOR, + BC_NSEW_SCROLLCURSOR, + BC_NS_SCROLLCURSOR, + BC_EW_SCROLLCURSOR, + BC_EYEDROPPER_CURSOR, +/* --- ALWAYS LAST ----- */ + BC_NUMCURSORS, +}; + + +enum { + BC_BLACK=0, + BC_WHITE, + BC_RED, + BC_BLUE, + BC_GREEN, + BC_YELLOW +}; + +#define SMALL_CURSOR 0 +#define BIG_CURSOR 1 + +#endif + diff --git a/source/blender/include/BIF_drawimage.h b/source/blender/include/BIF_drawimage.h new file mode 100644 index 00000000000..44e40b8cabb --- /dev/null +++ b/source/blender/include/BIF_drawimage.h @@ -0,0 +1,74 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_DRAWIMAGE_H +#define BIF_DRAWIMAGE_H + +struct ScrArea; +struct SpaceImage; +struct Render; +struct Image; +struct ImBuf; +struct uiBlock; +struct MTFace; + +void do_imagebuts(unsigned short event); +void calc_image_view(struct SpaceImage *sima, char mode); +void drawimagespace(struct ScrArea *sa, void *spacedata); +void image_changed(struct SpaceImage *sima, struct Image *image); +int draw_uvs_face_check(void); +void tface_center(struct MTFace *tf, float cent[2], void * isquad); +void draw_uvs_sima(void); +void image_set_tile(struct SpaceImage *sima, int dotile); +void image_home(void); +void image_viewmove(int mode); +void image_viewzoom(unsigned short event, int invert); +void image_viewcenter(void); +void uvco_to_areaco(float *vec, short *mval); +void uvco_to_areaco_noclip(float *vec, int *mval); +void what_image(struct SpaceImage *sima); +void image_preview_event(int event); + +void image_info(struct Image *ima, struct ImBuf *ibuf, char *str); +void imagespace_composite_flipbook(struct ScrArea *sa); + +void imagewindow_render_callbacks(struct Render *re); +void imagewindow_toggle_render(void); +void imagewindow_swap_render_rects(void); +void imagewin_store_spare(void); +struct ImBuf *imagewindow_get_ibuf(struct SpaceImage *sima); + +void image_editvertex_buts(struct uiBlock *block); +void image_editcursor_buts(struct uiBlock *block); + +#endif + diff --git a/source/blender/include/BIF_drawoops.h b/source/blender/include/BIF_drawoops.h new file mode 100644 index 00000000000..b42158d14fe --- /dev/null +++ b/source/blender/include/BIF_drawoops.h @@ -0,0 +1,41 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_DRAWOOPS_H +#define BIF_DRAWOOPS_H + +void give_oopslink_line(Oops *oops, OopsLink *ol, float *v1, float *v2); +void mysbox(float x1, float y1, float x2, float y2); +void boundbox_oops(short sel); + +#endif + diff --git a/source/blender/include/BIF_drawscene.h b/source/blender/include/BIF_drawscene.h new file mode 100644 index 00000000000..ad18542ebb4 --- /dev/null +++ b/source/blender/include/BIF_drawscene.h @@ -0,0 +1,35 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +struct Scene; +void set_scene(struct Scene *sce); + diff --git a/source/blender/include/BIF_drawscript.h b/source/blender/include/BIF_drawscript.h new file mode 100644 index 00000000000..b50f12e836b --- /dev/null +++ b/source/blender/include/BIF_drawscript.h @@ -0,0 +1,41 @@ +/** + * + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_DRAWSCRIPT_H +#define BIF_DRAWSCRIPT_H + +struct ScrArea; +struct SpaceScript; + +void free_scriptspace(struct SpaceScript *sc); + +#endif /* BIF_DRAWSCRIPT_H */ diff --git a/source/blender/include/BIF_drawseq.h b/source/blender/include/BIF_drawseq.h new file mode 100644 index 00000000000..4571267a09c --- /dev/null +++ b/source/blender/include/BIF_drawseq.h @@ -0,0 +1,46 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_DRAWSEQ_H +#define BIF_DRAWSEQ_H + +struct ScrArea; +struct Sequence; + +void drawprefetchseqspace(struct ScrArea *sa, void *spacedata); +void drawseqspace(struct ScrArea *sa, void *spacedata); +void set_special_seq_update(int val); + +void seq_viewmove(SpaceSeq *sseq); +void seq_reset_imageofs(SpaceSeq *sseq); +#endif + diff --git a/source/blender/include/BIF_drawtext.h b/source/blender/include/BIF_drawtext.h new file mode 100644 index 00000000000..a63e2bb264d --- /dev/null +++ b/source/blender/include/BIF_drawtext.h @@ -0,0 +1,54 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_DRAWTEXT_H +#define BIF_DRAWTEXT_H + +struct ScrArea; +struct SpaceText; +struct Text; + +void unlink_text(struct Text *text); + +void free_textspace(struct SpaceText *st); + +void txt_write_file(struct Text *text); +void add_text_fs(char *file); + +void free_txt_data(void); +void pop_space_text(struct SpaceText *st); + +void get_format_string(void); +void do_brackets(void); + +#endif + diff --git a/source/blender/include/BIF_editaction.h b/source/blender/include/BIF_editaction.h new file mode 100644 index 00000000000..fe6f81b9416 --- /dev/null +++ b/source/blender/include/BIF_editaction.h @@ -0,0 +1,162 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): 2007, Joshua Leung, Action Editor Recode + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_EDITACTION_H +#define BIF_EDITACTION_H + +/* some interface related sizes*/ +#define CHANNELHEIGHT 16 +#define CHANNELSKIP 2 +#define NAMEWIDTH 164 +#define SLIDERWIDTH 125 +#define ACTWIDTH (G.saction->actwidth) + +/* Some types for easier type-testing */ +enum { + ACTTYPE_NONE= 0, + ACTTYPE_ACHAN, + ACTTYPE_CONCHAN, + ACTTYPE_ICU, + ACTTYPE_FILLIPO, + ACTTYPE_FILLCON, + ACTTYPE_IPO, + ACTTYPE_SHAPEKEY +}; + +/* Macros for easier/more consistant state testing */ +#define VISIBLE_ACHAN(achan) ((achan->flag & ACHAN_HIDDEN)==0) +#define EDITABLE_ACHAN(achan) ((VISIBLE_ACHAN(achan)) && ((achan->flag & ACHAN_PROTECTED)==0)) +#define EXPANDED_ACHAN(achan) ((VISIBLE_ACHAN(achan)) && (achan->flag & ACHAN_EXPANDED)) +#define SEL_ACHAN(achan) ((achan->flag & ACHAN_SELECTED) || (achan->flag & ACHAN_HILIGHTED)) +#define FILTER_IPO_ACHAN(achan) ((achan->flag & ACHAN_SHOWIPO)) +#define FILTER_CON_ACHAN(achan) ((achan->flag & ACHAN_SHOWCONS)) + +#define EDITABLE_CONCHAN(conchan) ((conchan->flag & CONSTRAINT_CHANNEL_PROTECTED)==0) +#define SEL_CONCHAN(conchan) (conchan->flag & CONSTRAINT_CHANNEL_SELECT) + +#define EDITABLE_ICU(icu) ((icu->flag & IPO_PROTECT)==0) +#define SEL_ICU(icu) (icu->flag & IPO_SELECT) + +#define NLA_ACTION_SCALED (G.saction->pin==0 && OBACT && OBACT->action) +#define NLA_IPO_SCALED (OBACT && OBACT->action && G.sipo->pin==0 && G.sipo->actname) + +/* constants for setting ipo-interpolation type */ +enum { + SET_IPO_MENU = -1, + SET_IPO_POPUP = 0, + + SET_IPO_CONSTANT, + SET_IPO_LINEAR, + SET_IPO_BEZIER, +}; + +/* constants for setting ipo-extrapolation type */ +enum { + + SET_EXTEND_MENU = 9, + SET_EXTEND_POPUP = 10, + + SET_EXTEND_CONSTANT, + SET_EXTEND_EXTRAPOLATION, + SET_EXTEND_CYCLIC, + SET_EXTEND_CYCLICEXTRAPOLATION +}; + + +struct bAction; +struct bActionChannel; +struct bPoseChannel; +struct Object; +struct Ipo; +struct BWinEvent; +struct Key; +struct ListBase; + +/* Key operations */ +void transform_action_keys(int mode, int dummy); +void duplicate_action_keys(void); +void snap_action_keys(short mode); +void mirror_action_keys(short mode); +void insertkey_action(void); +void delete_action_keys(void); +void delete_action_channels(void); +void clean_action(void); + +/* Column/Channel Key select */ +void column_select_action_keys(int mode); +void selectall_action_keys(short mval[], short mode, short selectmode); +void markers_selectkeys_between(void); + +/* Action Data Copying */ +void free_actcopybuf(void); +void copy_actdata(void); +void paste_actdata(void); + +/* channel/strip operations */ +void up_sel_action(void); +void down_sel_action(void); +void top_sel_action(void); +void bottom_sel_action(void); + +/* IPO/Handle Types */ +void sethandles_action_keys(int code); +void action_set_ipo_flags(short mode, short event); + +/* Select */ +void borderselect_action(void); +void deselect_action_keys(short test, short sel); +void deselect_action_channels(short test); +void deselect_actionchannels(struct bAction *act, short test); +int select_channel(struct bAction *act, struct bActionChannel *achan, int selectmode); +void select_actionchannel_by_name(struct bAction *act, char *name, int select); + +/* ShapeKey stuff */ +struct Key *get_action_mesh_key(void); +int get_nearest_key_num(struct Key *key, short *mval, float *x); + +void *get_nearest_act_channel(short mval[], short *ret_type); + +/* Action */ +struct bActionChannel *get_hilighted_action_channel(struct bAction* action); +struct bAction *add_empty_action(char *name); +struct bAction *ob_get_action(struct Object *ob); + +void actdata_filter(ListBase *act_data, int filter_mode, void *data, short datatype); +void *get_action_context(short *datatype); + +void remake_action_ipos(struct bAction *act); + +/* event handling */ +void winqreadactionspace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt); + +#endif + diff --git a/source/blender/include/BIF_editarmature.h b/source/blender/include/BIF_editarmature.h new file mode 100644 index 00000000000..903c663e5f3 --- /dev/null +++ b/source/blender/include/BIF_editarmature.h @@ -0,0 +1,142 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BIF_EDITARMATURE_H +#define BIF_EDITARMATURE_H + +struct Object; +struct Base; +struct Bone; +struct bArmature; +struct ListBase; + +typedef struct EditBone +{ + struct EditBone *next, *prev; + struct EditBone *parent;/* Editbones have a one-way link (i.e. children refer + to parents. This is converted to a two-way link for + normal bones when leaving editmode. */ + void *temp; /* Used to store temporary data */ + + char name[32]; + float roll; /* Roll along axis. We'll ultimately use the axis/angle method + for determining the transformation matrix of the bone. The axis + is tail-head while roll provides the angle. Refer to Graphics + Gems 1 p. 466 (section IX.6) if it's not already in here somewhere*/ + + float head[3]; /* Orientation and length is implicit during editing */ + float tail[3]; + /* All joints are considered to have zero rotation with respect to + their parents. Therefore any rotations specified during the + animation are automatically relative to the bones' rest positions*/ + int flag; + + int parNr; /* Used for retrieving values from the menu system */ + + float dist, weight; + float xwidth, length, zwidth; /* put them in order! transform uses this as scale */ + float ease1, ease2; + float rad_head, rad_tail; + short layer, segments; + + float oldlength; /* for envelope scaling */ + +} EditBone; + + +void adduplicate_armature(void); +void addvert_armature(void); +void add_primitiveArmature(int type); +void apply_rot_armature (struct Object *ob, float mat[3][3]); +void docenter_armature (struct Object *ob, int centermode); + +void clear_armature(struct Object *ob, char mode); + +void delete_armature(void); +void deselectall_armature(int toggle, int doundo); +void deselectall_posearmature (struct Object *ob, int test, int doundo); +int draw_armature(struct Base *base, int dt); +void extrude_armature(int forked); +void subdivide_armature(int numcuts); + +void free_editArmature(void); + +int join_armature(void); +void load_editArmature(void); + +void make_bone_parent(void); +void clear_bone_parent(void); +struct Bone *get_indexed_bone (struct Object *ob, int index); + +void make_editArmature(void); +void make_trans_bones (char mode); + +int do_pose_selectbuffer(struct Base *base, unsigned int *buffer, short hits); + +void mouse_armature(void); +void remake_editArmature(void); +void selectconnected_armature(void); +void selectconnected_posearmature(void); +void select_bone_parent(void); +void unique_editbone_name (struct ListBase *ebones, char *name); + +void auto_align_armature(short mode); + +void create_vgroups_from_armature(struct Object *ob, struct Object *par); +void add_verts_to_dgroups(struct Object *ob, struct Object *par, int heat, int mirror); + +void hide_selected_pose_bones(void); +void hide_unselected_pose_bones(void); +void show_all_pose_bones(void); + +int bone_looper(Object *ob, struct Bone *bone, void *data, + int (*bone_func)(Object *, struct Bone *, void *)); + +void undo_push_armature(char *name); +void armature_bone_rename(struct bArmature *arm, char *oldname, char *newname); +void armature_flip_names(void); +EditBone *armature_bone_get_mirrored(EditBone *ebo); +void transform_armature_mirror_update(void); + +void hide_selected_armature_bones(void); +void hide_unselected_armature_bones(void); +void show_all_armature_bones(void); + +#define BONESEL_ROOT 0x10000000 +#define BONESEL_TIP 0x20000000 +#define BONESEL_BONE 0x40000000 +#define BONESEL_ANY (BONESEL_TIP|BONESEL_ROOT|BONESEL_BONE) + +#define BONESEL_NOSEL 0x80000000 /* Indicates a negative number */ + +#endif + + diff --git a/source/blender/include/BIF_editconstraint.h b/source/blender/include/BIF_editconstraint.h new file mode 100644 index 00000000000..b8977c00d89 --- /dev/null +++ b/source/blender/include/BIF_editconstraint.h @@ -0,0 +1,72 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_EDITCONSTRAINT_H +#define BIF_EDITCONSTRAINT_H + +struct ID; +struct ListBase; +struct Object; +struct bConstraint; +struct bConstraintChannel; +struct Text; + +/* generic constraint editing functions */ + +struct bConstraint *add_new_constraint(short type); + +void add_constraint_to_object(struct bConstraint *con, struct Object *ob); + +struct ListBase *get_active_constraints(struct Object *ob); +struct bConstraint *get_active_constraint(struct Object *ob); +struct ListBase *get_active_constraint_channels (struct Object *ob, int forcevalid); +struct bConstraintChannel *get_active_constraint_channel(struct Object *ob); + +void object_test_constraints(struct Object *owner); + +void add_constraint(int only_IK); +void ob_clear_constraints(void); + +void rename_constraint(struct Object *ob, struct bConstraint *con, char *newname); + + +/* a few special functions for PyConstraints */ +char *buildmenu_pyconstraints(struct Text *con_text, int *pyconindex); +void validate_pyconstraint_cb(void *arg1, void *arg2); +void update_pyconstraint_cb(void *arg1, void *arg2); + +/* two special functions for ChildOf Constriant */ +void childof_const_setinv (void *conv, void *unused); +void childof_const_clearinv(void *conv, void *unused); + +#endif + diff --git a/source/blender/include/BIF_editdeform.h b/source/blender/include/BIF_editdeform.h new file mode 100644 index 00000000000..2a8f43c14e7 --- /dev/null +++ b/source/blender/include/BIF_editdeform.h @@ -0,0 +1,74 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_DEFORM_H +#define BIF_DEFORM_H + +#define WEIGHT_REPLACE 1 +#define WEIGHT_ADD 2 +#define WEIGHT_SUBTRACT 3 + +struct Object; +struct Mesh; +struct MDeformVert; +struct MDeformWeight; +struct bDeformGroup; + +struct bDeformGroup *add_defgroup_name (struct Object *ob, char *name); +void add_defgroup (struct Object *ob); +void del_defgroup_in_object_mode ( Object *ob ); +void del_defgroup (struct Object *ob); +void duplicate_defgroup ( struct Object *ob ); +void assign_verts_defgroup (void); +void remove_verts_defgroup (int allverts); +void sel_verts_defgroup (int select); + +struct MDeformWeight *get_defweight (struct MDeformVert *dv, int defgroup); +struct MDeformWeight *verify_defweight (struct MDeformVert *dv, int defgroup); + + +void add_vert_to_defgroup (struct Object *ob, struct bDeformGroup *dg, + int vertnum, float weight, + int assignmode); +void remove_vert_defgroup (struct Object *ob, struct bDeformGroup *dg, + int vertnum); +void create_dverts(ID *id); + +void vertexgroup_select_by_name(struct Object *ob, char *name); + +extern void object_apply_deform(struct Object *ob); + +void vgroup_assign_with_menu(void); +void vgroup_operation_with_menu(void); + +#endif + diff --git a/source/blender/include/BIF_editfont.h b/source/blender/include/BIF_editfont.h new file mode 100644 index 00000000000..0c2c9d2779f --- /dev/null +++ b/source/blender/include/BIF_editfont.h @@ -0,0 +1,73 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include + +#ifndef BIF_EDITFONT_H +#define BIF_EDITFONT_H + +struct Text; + +extern char *BIF_lorem; +extern wchar_t *copybuf; +extern wchar_t *copybufinfo; + +typedef struct unicodect +{ + char *name; + char *longname; + int start; + int end; +} unicodect; + +void do_textedit(unsigned short event, short val, unsigned long _ascii); +void make_editText(void); +void load_editText(void); +void remake_editText(void); +void free_editText(void); +void paste_editText(void); +void txt_export_to_object(struct Text *text); +void txt_export_to_objects(struct Text *text); +void undo_push_font(char *); +void load_3dtext_fs(char *); +void add_lorem(void); +void paste_unicodeText(char *filename); + +/** + * @attention The argument is discarded. It is there for + * compatibility. + */ +void add_primitiveFont(int); +void to_upper(void); + +#endif + diff --git a/source/blender/include/BIF_editgroup.h b/source/blender/include/BIF_editgroup.h new file mode 100644 index 00000000000..9873a7aaef3 --- /dev/null +++ b/source/blender/include/BIF_editgroup.h @@ -0,0 +1,40 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +struct Group; +struct Base; + +void add_selected_to_group(struct Group *group); +void rem_selected_from_group(void); +void group_operation_with_menu(void); +void group_operation(int mode); + diff --git a/source/blender/include/BIF_editkey.h b/source/blender/include/BIF_editkey.h new file mode 100644 index 00000000000..6c03e62a24c --- /dev/null +++ b/source/blender/include/BIF_editkey.h @@ -0,0 +1,70 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_EDITKEY_H +#define BIF_EDITKEY_H + +struct Key; +struct KeyBlock; +struct Mesh; +struct Object; +struct Lattice; +struct Curve; +struct uiBlock; +struct BezTriple; +struct IpoCurve; + +void mesh_to_key(struct Mesh *me, struct KeyBlock *kb); +void key_to_mesh(struct KeyBlock *kb, struct Mesh *me); +void insert_meshkey(struct Mesh *me, short rel); + +void latt_to_key(struct Lattice *lt, struct KeyBlock *kb); +void key_to_latt(struct KeyBlock *kb, struct Lattice *lt); +void insert_lattkey(struct Lattice *lt, short rel); + +void curve_to_key(struct Curve *cu, struct KeyBlock *kb, ListBase *nurb); +void key_to_curve(struct KeyBlock *kb, struct Curve *cu, ListBase *nurb); +void insert_curvekey(struct Curve *cu, short rel); + +void insert_shapekey(struct Object *ob); + +void delete_key(struct Object *ob); +void move_keys(struct Object *ob); + +void make_rvk_slider(struct uiBlock *block, struct Object *ob, int keynum, + int x, int y, int w, int h, char *tip); + +// FIXME: move me somewhere else +struct BezTriple *get_bezt_icu_time(struct IpoCurve *icu, float *frame, float *val); + +#endif + diff --git a/source/blender/include/BIF_editlattice.h b/source/blender/include/BIF_editlattice.h new file mode 100644 index 00000000000..c7cf6c570ac --- /dev/null +++ b/source/blender/include/BIF_editlattice.h @@ -0,0 +1,45 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_EDITLATTICE_H +#define BIF_EDITLATTICE_H + +void free_editLatt(void); +void make_editLatt(void); +void load_editLatt(void); +void remake_editLatt(void); +void deselectall_Latt(void); +void mouse_lattice(void); +void undo_push_lattice(char *name); + +#endif + diff --git a/source/blender/include/BIF_editmesh.h b/source/blender/include/BIF_editmesh.h new file mode 100644 index 00000000000..42d581ee758 --- /dev/null +++ b/source/blender/include/BIF_editmesh.h @@ -0,0 +1,265 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* External for editmesh_xxxx.c functions */ + +#ifndef BIF_EDITMESH_H +#define BIF_EDITMESH_H + +#include "BKE_mesh.h" + +struct EditMesh; +struct EditFace; +struct EditEdge; +struct EditVert; +struct Mesh; +struct bDeformGroup; +struct View3D; +struct EditSelection; +struct CustomData; + +// edge and face flag both +#define EM_FGON 2 +// face flag +#define EM_FGON_DRAW 1 + +extern unsigned int em_vertoffs, em_solidoffs, em_wireoffs; + +/* ******************* editmesh.c */ +extern void make_editMesh(void); +extern void load_editMesh(void); +extern void free_editMesh(struct EditMesh *); +extern void remake_editMesh(void); + + /* Editmesh Undo code */ +extern void undo_push_mesh(char *name); + +extern void separatemenu(void); +extern void separate_mesh(void); +extern void separate_mesh_loose(void); +extern void separate_material(void); + +/* ******************* editmesh_add.c */ +extern void make_prim(int type, float imat[3][3], int tot, int seg, + int subdiv, float dia, float d, int ext, int fill, + float cent[3] ); +extern void add_primitiveMesh(int type); +extern void adduplicate_mesh(void); +extern void add_click_mesh(void); +extern void addedgeface_mesh(void); +void addfaces_from_edgenet(); + +/* ******************* editmesh_lib.c */ + +extern void EM_set_flag_all(int flag); +extern void EM_clear_flag_all(int flag); + +extern void EM_select_face(struct EditFace *efa, int sel); +extern void EM_select_edge(struct EditEdge *eed, int sel); +extern float EM_face_area(struct EditFace *efa); +extern float EM_face_perimeter(struct EditFace *efa); +extern void EM_editselection_center(float *center, struct EditSelection *ese); +extern void EM_editselection_normal(float *normal, struct EditSelection *ese); +extern void EM_editselection_plane(float *plane, struct EditSelection *ese); + +extern void EM_deselect_flush(void); // vertices to edges/faces (exception!) +extern void EM_select_flush(void); // vertices to edges/faces (exception!) +extern void EM_selectmode_set(void); // when mode changes +extern void EM_selectmode_flush(void); // when selection changes +extern void EM_convertsel(short oldmode, short selectmode); +extern void EM_remove_selection(void *data, int type); +extern void EM_store_selection(void *data, int type); +extern void EM_validate_selections(void); + +extern int EM_nfaces_selected(void); +extern int EM_nvertices_selected(void); + +extern int faceselectedAND(struct EditFace *efa, int flag); +extern void recalc_editnormals(void); +extern void flip_editnormals(void); + +extern void EM_data_interp_from_verts(struct EditVert *v1, + struct EditVert *v2, struct EditVert *eve, float fac); +extern struct EditFace *EM_face_from_faces(struct EditFace *efa1, + struct EditFace *efa2, int i1, int i2, int i3, int i4); +extern void EM_data_interp_from_faces(struct EditFace *efa1, + struct EditFace *efa2, struct EditFace *efan, int i1, int i2, int i3, int i4); + +void EM_add_data_layer(struct CustomData *data, int type); +void EM_free_data_layer(struct CustomData *data, int type); + +/* ******************* editmesh_mods.c */ + +extern void EM_init_index_arrays(int forVert, int forEdge, int forFace); +extern void EM_free_index_arrays(void); + +extern struct EditVert *EM_get_vert_for_index(int index); +extern struct EditEdge *EM_get_edge_for_index(int index); +extern struct EditFace *EM_get_face_for_index(int index); + +extern void EM_select_face_fgon(struct EditFace *efa, int sel); + +extern int EM_init_backbuf_border(short xmin, short ymin, short xmax, short ymax); +extern int EM_mask_init_backbuf_border(short mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax); +extern int EM_init_backbuf_circle(short xs, short ys, short rads); +extern int EM_check_backbuf(unsigned int index); +extern void EM_free_backbuf(void); + +extern void EM_selectmode_menu(void); + + +extern void vertexnoise(void); +extern void vertexsmooth(void); +extern void righthandfaces(int select); +extern void mouse_mesh(void); + +extern void deselectall_mesh(void); +extern void selectconnected_mesh_all(void); +extern void selectconnected_mesh(void); +extern void selectconnected_delimit_mesh(void); +extern void selectconnected_delimit_mesh_all(void); +extern void selectswap_mesh(void); + +extern void hide_mesh(int swap); +extern void reveal_mesh(void); + +extern void vertices_to_sphere(void); + + /** Aligns the selected MTFace's of @a me to the @a v3d, + * using the given axis (0-2). Can give a user error. + */ +extern void faceselect_align_view_to_selected(struct View3D *v3d, struct Mesh *me, int axis); + /** Aligns the selected faces or vertices of @a me to the @a v3d, + * using the given axis (0-2). Can give a user error. + */ +extern void editmesh_align_view_to_selected(struct View3D *v3d, int axis); + + /* Selection */ +extern void select_non_manifold(void); +extern void select_sharp_edges(void); +extern void select_linked_flat_faces(void); +extern void select_faces_by_numverts(int numverts); +extern void select_more(void); +extern void select_less(void); +extern void selectrandom_mesh(void); +extern void editmesh_select_by_material(int index); +extern void editmesh_deselect_by_material(int index); + +extern void Vertex_Menu(void); +extern void Edge_Menu(void); +extern void Face_Menu(void); +extern void select_mesh_group_menu(void); +extern void editmesh_mark_seam(int clear); +extern void loop_multiselect(int looptype); + + +/* ******************* editmesh_loop.c */ + +#define KNIFE_PROMPT 0 +#define KNIFE_EXACT 1 +#define KNIFE_MIDPOINT 2 +#define KNIFE_MULTICUT 3 + +extern void CutEdgeloop(int numcuts); +extern void KnifeSubdivide(char mode); +extern void LoopMenu(void); + +#define LOOP_SELECT 1 +#define LOOP_CUT 2 + +extern short sharesFace(struct EditEdge* e1, struct EditEdge* e2); + +/* ******************* editmesh_tools.c */ + +#define SUBDIV_SELECT_ORIG 0 +#define SUBDIV_SELECT_INNER 1 +#define SUBDIV_SELECT_INNER_SEL 2 +#define SUBDIV_SELECT_LOOPCUT 3 + +extern void convert_to_triface(int direction); +extern int removedoublesflag(short flag, short automerge, float limit); +extern void xsortvert_flag(int flag); +extern void hashvert_flag(int flag); + +extern void esubdivideflag(int flag, float rad, int beauty, int numcuts, int selecttype); + +extern void extrude_mesh(void); +extern void split_mesh(void); +extern void extrude_repeat_mesh(int steps, float offs); +extern void spin_mesh(int steps,float degr,float *dvec, int mode); +extern void screw_mesh(int steps,int turns); +extern void delete_mesh(void); +extern void beauty_fill(void); +extern void join_triangles(void); +extern void edge_flip(void); +extern void fill_mesh(void); +extern void bevel_menu(); +void mesh_set_face_flags(short mode); +extern void mesh_set_smooth_faces(short event); +extern void mesh_rotate_uvs(void); +extern void mesh_mirror_uvs(void); +extern void mesh_rotate_colors(void); +extern void mesh_mirror_colors(void); +void mesh_copy_menu(void); +void edge_rotate_selected(int dir); +int EdgeSlide(short immediate, float imperc); +int EdgeLoopDelete(void); +void mesh_rip(void); + +struct EditVert *editedge_getOtherVert(struct EditEdge *eed, struct EditVert *ev); +struct EditVert *editedge_getSharedVert(struct EditEdge *eed, struct EditEdge *eed2); +int editedge_containsVert(struct EditEdge *eed, struct EditVert *eve); +int editface_containsVert(struct EditFace *efa, struct EditVert *eve); +int editface_containsEdge(struct EditFace *efa, struct EditEdge *eed); + +void shape_copy_select_from(void); +void shape_propagate(void); + +int collapseEdges(void); +int merge_firstlast(int first, int uvmerge); +int merge_target( int target, int uvmerge); + +void pathselect(void); +void loop_to_region(void); +void region_to_loop(void); + +UvVertMap *make_uv_vert_map_EM(int selected, int do_face_idx_array, float *limit); +UvMapVert *get_uv_map_vert_EM(UvVertMap *vmap, unsigned int v); +void free_uv_vert_map_EM(UvVertMap *vmap); + +int EM_texFaceCheck(void); /* can we edit UV's for this mesh?*/ +int EM_vertColorCheck(void); /* can we edit colors for this mesh?*/ + +void EM_set_actFace(struct EditFace *efa); +struct EditFace * EM_get_actFace(void); + +#endif diff --git a/source/blender/include/BIF_editmode_undo.h b/source/blender/include/BIF_editmode_undo.h new file mode 100644 index 00000000000..b03b4160166 --- /dev/null +++ b/source/blender/include/BIF_editmode_undo.h @@ -0,0 +1,59 @@ +/** + * $Id: + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + + +#ifndef BIF_EDITMODE_UNDO_H +#define BIF_EDITMODE_UNDO_H + +// Add this in your local code: + +extern void undo_editmode_push(char *name, + void (*freedata)(void *), // pointer to function freeing data + void (*to_editmode)(void *), // data to editmode conversion + void *(*from_editmode)(void)); // editmode to data conversion + + +// Further exported for UI is: + +struct uiBlock; + +extern void undo_editmode_step(int step); // undo and redo +extern void undo_editmode_clear(void); // free & clear all data +extern void undo_editmode_menu(void); // history menu +extern struct uiBlock *editmode_undohistorymenu(void *arg_unused); + +/* Hack to avoid multires undo data taking up insane amounts of memory */ +struct Object; +void *undo_editmode_get_prev(struct Object *ob); + +#endif + diff --git a/source/blender/include/BIF_editnla.h b/source/blender/include/BIF_editnla.h new file mode 100644 index 00000000000..f12a313b903 --- /dev/null +++ b/source/blender/include/BIF_editnla.h @@ -0,0 +1,65 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_EDITNLA_H +#define BIF_EDITNLA_H + +struct BWinEvent; + +extern void winqreadnlaspace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt); + +/* NLA channel operations */ +void delete_nlachannel_keys(void); +void duplicate_nlachannel_keys(void); +void transform_nlachannel_keys(int mode, int dummy); + +/* Select */ +void borderselect_nla(void); +void deselect_nlachannel_keys (int test); +void deselect_nlachannels(int test); + +/* NLA Strip operations */ +void shift_nlastrips_up(void); +void shift_nlastrips_down(void); +void reset_action_strips(int val); +void synchronize_action_strips(void); +void snap_action_strips(int snap_mode); +void add_nlablock(void); +void add_empty_nlablock(void); +void convert_nla(void); +void copy_action_modifiers(void); + +/* Baking */ +void bake_all_to_action(void); + +#endif + diff --git a/source/blender/include/BIF_editoops.h b/source/blender/include/BIF_editoops.h new file mode 100644 index 00000000000..ac1badfd7bd --- /dev/null +++ b/source/blender/include/BIF_editoops.h @@ -0,0 +1,47 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_EDITOOPS_H +#define BIF_EDITOOPS_H + +void borderselect_oops(void); +void deselect_all_area_oops(void); +void mouse_select_oops(void); +void select_backlinked_oops(void); +void select_linked_oops(void); +void set_select_flag_oops(void); +void swap_select_all_oops(void); +void transform_oops(int mode, int context); + +void clever_numbuts_oops(void); +#endif + diff --git a/source/blender/include/BIF_editsca.h b/source/blender/include/BIF_editsca.h new file mode 100644 index 00000000000..c8e8a33d475 --- /dev/null +++ b/source/blender/include/BIF_editsca.h @@ -0,0 +1,41 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_EDITSCA_H +#define BIF_EDITSCA_H + +void make_unique_prop_names(char *str); +void do_gamebuts(unsigned short event); +void gamebuts(void); + +#endif + diff --git a/source/blender/include/BIF_editseq.h b/source/blender/include/BIF_editseq.h new file mode 100644 index 00000000000..74baf12c11a --- /dev/null +++ b/source/blender/include/BIF_editseq.h @@ -0,0 +1,134 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_EDITSEQ_H +#define BIF_EDITSEQ_H + +struct Sequence; + +void add_duplicate_seq(void); +void add_sequence(int type); +void borderselect_seq(void); +void boundbox_seq(void); +void change_sequence(void); +void reload_sequence(void); +void update_seq_ipo_rect(struct Sequence * seq); +void update_seq_icu_rects(struct Sequence * seq); +struct Sequence* get_last_seq(); +void set_last_seq(struct Sequence * seq); +void clear_last_seq(); +void del_seq(void); +void enter_meta(void); +void exit_meta(void); +struct Sequence* find_neighboring_sequence(struct Sequence *test, int lr, int sel); +struct Sequence* find_next_prev_sequence(struct Sequence *test, int lr, int sel); +struct Sequence* find_nearest_seq(int *hand); +int insert_gap(int gap, int cfra); +void make_meta(void); +void select_channel_direction(struct Sequence *test,int lr); +void select_more_seq(void); +void select_less_seq(void); +void mouse_select_seq(void); +void no_gaps(void); +void seq_snap(short event); +void seq_snap_menu(void); +void set_filter_seq(void); +void swap_select_seq(void); +void touch_seq_files(void); +void seq_remap_paths(void); +void transform_seq(int mode, int context); +void transform_seq_nomarker(int mode, int context); +void un_meta(void); +void seq_cut(int cutframe); +void seq_separate_images(void); +void reassign_inputs_seq_effect(void); +void select_surrounding_handles(struct Sequence *test); +void select_surround_from_last(); +void select_dir_from_last(int lr); +void select_neighbor_from_last(int lr); +void select_linked_seq(int mode); +struct Sequence* alloc_sequence(ListBase *lb, int cfra, int machine); /*used from python*/ +int check_single_seq(struct Sequence *seq); + +/* sequence transform functions, for internal used */ +int seq_tx_get_start(struct Sequence *seq); +int seq_tx_get_end(struct Sequence *seq); + +int seq_tx_get_final_left(struct Sequence *seq); +int seq_tx_get_final_right(struct Sequence *seq); + +void seq_tx_set_final_left(struct Sequence *seq, int i); +void seq_tx_set_final_right(struct Sequence *seq, int i); + +/* check if one side can be transformed */ +int seq_tx_check_left(struct Sequence *seq); +int seq_tx_check_right(struct Sequence *seq); + +#define SEQ_DEBUG_INFO(seq) printf("seq into '%s' -- len:%i start:%i startstill:%i endstill:%i startofs:%i endofs:%i\n",\ + seq->name, seq->len, seq->start, seq->startstill, seq->endstill, seq->startofs, seq->endofs) + +/* seq macro's for transform + notice the difference between start/end and left/right. + + left and right are the bounds at which the setuence is rendered, +start and end are from the start and fixed length of the sequence. +*/ +/* +#define SEQ_GET_START(seq) (seq->start) +#define SEQ_GET_END(seq) (seq->start+seq->len) + +#define SEQ_GET_FINAL_LEFT(seq) ((seq->start - seq->startstill) + seq->startofs) +#define SEQ_GET_FINAL_RIGHT(seq) (((seq->start+seq->len) + seq->endstill) - seq->endofs) + +#define SEQ_SET_FINAL_LEFT(seq, val) \ + if (val < (seq)->start) { \ + (seq)->startstill = abs(val - (seq)->start); \ + (seq)->startofs = 0; \ +} else { \ + (seq)->startofs = abs(val - (seq)->start); \ + (seq)->startstill = 0; \ +} + +#define SEQ_SET_FINAL_RIGHT(seq, val) \ + if (val > (seq)->start + (seq)->len) { \ + (seq)->endstill = abs(val - ((seq)->start + (seq)->len)); \ + (seq)->endofs = 0; \ +} else { \ + (seq)->endofs = abs(val - ((seq)->start + (seq)->len)); \ + (seq)->endstill = 0; \ +} +*/ +/* drawseq.c */ +void do_seqbuttons(short); + +#endif + diff --git a/source/blender/include/BIF_editsima.h b/source/blender/include/BIF_editsima.h new file mode 100644 index 00000000000..a8a5c16df1a --- /dev/null +++ b/source/blender/include/BIF_editsima.h @@ -0,0 +1,124 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +struct Mesh; +struct EditMesh; +struct SpaceImage; +struct EditFace; +struct MTFace; + +/* id can be from 0 to 3 */ +#define TF_PIN_MASK(id) (TF_PIN1 << id) +#define TF_SEL_MASK(id) (TF_SEL1 << id) + + +/* this checks weather a face is drarn without the local image check + * - warning - no check for G.sima->flag, use SIMA_FACEDRAW_CHECK + */ +#define SIMA_FACEDRAW_CHECK_NOLOCAL(efa) \ + ((G.sima->flag & SI_SYNC_UVSEL) ? (efa->h==0) : (efa->h==0 && efa->f & SELECT)) + +/* this check includes the local image check - (does the faces image match the space image?) */ +#define SIMA_FACEDRAW_CHECK(efa, tf) \ + ((G.sima && G.sima->flag & SI_LOCAL_UV) ? ((tf->tpage==G.sima->image) ? SIMA_FACEDRAW_CHECK_NOLOCAL(efa):0) : (SIMA_FACEDRAW_CHECK_NOLOCAL(efa))) + +#define SIMA_FACESEL_CHECK(efa, tf) \ + ((G.sima && G.sima->flag & SI_SYNC_UVSEL) ? (efa->f & SELECT) : (!(~tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) &&(!efa->v4 || tf->flag & TF_SEL4))) +#define SIMA_FACESEL_SET(efa, tf) \ + ((G.sima && G.sima->flag & SI_SYNC_UVSEL) ? (EM_select_face(efa, 1)) : (tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4))) +#define SIMA_FACESEL_UNSET(efa, tf) \ + ((G.sima && G.sima->flag & SI_SYNC_UVSEL) ? (EM_select_face(efa, 0)) : (tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4))) + +#define SIMA_UVSEL_CHECK(efa, tf, i) ((G.sima && G.sima->flag & SI_SYNC_UVSEL) ? \ + (G.scene->selectmode == SCE_SELECT_FACE ? efa->f & SELECT : ((*(&efa->v1 + i))->f & SELECT) ) : (tf->flag & TF_SEL_MASK(i) )) +#define SIMA_UVSEL_SET(efa, tf, i) ((G.sima && G.sima->flag & SI_SYNC_UVSEL) ? \ + (G.scene->selectmode == SCE_SELECT_FACE ? EM_select_face(efa, 1) : ((*(&efa->v1 + i))->f |= SELECT) ) : (tf->flag |= TF_SEL_MASK(i) )) +#define SIMA_UVSEL_UNSET(efa, tf, i) ((G.sima && G.sima->flag & SI_SYNC_UVSEL) ? \ + (G.scene->selectmode == SCE_SELECT_FACE ? EM_select_face(efa, 0) : ((*(&efa->v1 + i))->f &= ~SELECT) ) : (tf->flag &= ~TF_SEL_MASK(i) )) + +struct Object; + +void object_uvs_changed(struct Object *ob); +void object_tface_flags_changed(struct Object *ob, int updateButtons); + +int is_uv_tface_editing_allowed(void); +int is_uv_tface_editing_allowed_silent(void); + +void get_connected_limit_tface_uv(float *limit); +int minmax_tface_uv(float *min, float *max); +int cent_tface_uv(float *cent, int mode); + +void transform_width_height_tface_uv(int *width, int *height); +void transform_aspect_ratio_tface_uv(float *aspx, float *aspy); + +void mouseco_to_cursor_sima(void); +void borderselect_sima(short whichuvs); +void mouseco_to_curtile(void); +void mouse_select_sima(void); +void snap_menu_sima(void); +void aspect_sima(struct SpaceImage *sima, float *x, float *y); + +void select_invert_tface_uv(void); +void select_swap_tface_uv(void); +void mirrormenu_tface_uv(void); +void mirror_tface_uv(char mirroraxis); +void hide_tface_uv(int swap); +void reveal_tface_uv(void); +void stitch_limit_uv_tface(void); +void stitch_vert_uv_tface(void); +void unlink_selection(void); +void uvface_setsel__internal(short select); +void select_linked_tface_uv(int mode); +void pin_tface_uv(int mode); +void weld_align_menu_tface_uv(void); +void weld_align_tface_uv(char tool); +void be_square_tface_uv(struct EditMesh *em); +void select_pinned_tface_uv(void); + +void sima_sample_color(void); + +#define UV_SELECT_ALL 1 +#define UV_SELECT_PINNED 2 + +void new_image_sima(void); +void reload_image_sima(void); +void save_image_sima(void); +void save_as_image_sima(void); +void save_image_sequence_sima(void); +void replace_image_sima(short imageselect); +void open_image_sima(short imageselect); +void pack_image_sima(void); + +/* checks images for forced updates on frame change */ +void BIF_image_update_frame(void); + +void find_nearest_uv(struct MTFace **nearesttf, struct EditFace **nearestefa, unsigned int *nearestv, int *nearestuv); diff --git a/source/blender/include/BIF_editsound.h b/source/blender/include/BIF_editsound.h new file mode 100644 index 00000000000..6e341bfb204 --- /dev/null +++ b/source/blender/include/BIF_editsound.h @@ -0,0 +1,87 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_EDITSOUND_H +#define BIF_EDITSOUND_H + +struct bSound; +struct bSample; +struct ListBase; +struct PackedFile; +struct hdaudio; + +void sound_init_audio(void); +void sound_initialize_sounds(void); +void sound_exit_audio(void); +int sound_get_mixrate(void); + +void* sound_get_audiodevice(void); +void* sound_get_listener(void); + +int sound_set_sample(struct bSound* sound, struct bSample* sample); +int sound_sample_is_null(struct bSound* sound); +int sound_load_sample(struct bSound* sound); + +struct bSample* sound_find_sample(struct bSound* sound); +struct bSample* sound_new_sample(struct bSound* sound); + +struct bSound* sound_new_sound(char *name); +struct bSound* sound_make_copy(struct bSound* originalsound); +void sound_end_all_sounds(void); + +void sound_initialize_sample(struct bSound * sound); +void sound_load_samples(void); + +void sound_play_sound(struct bSound *sound); +void sound_stop_all_sounds(void); + +void sound_set_position(void *object, + struct bSound *sound, + float obmatrix[4][4]); + +struct hdaudio * sound_open_hdaudio(char * name); +struct hdaudio * sound_copy_hdaudio(struct hdaudio * c); + +long sound_hdaudio_get_duration(struct hdaudio * hdaudio, double frame_rate); +void sound_hdaudio_extract(struct hdaudio * hdaudio, + short * target_buffer, + int sample_position /* units of target_rate */, + int target_rate, + int target_channels, + int nb_samples /* in target */); + +void sound_close_hdaudio(struct hdaudio * hdaudio); + + + +#endif + diff --git a/source/blender/include/BIF_editview.h b/source/blender/include/BIF_editview.h new file mode 100644 index 00000000000..676bc3bd9f0 --- /dev/null +++ b/source/blender/include/BIF_editview.h @@ -0,0 +1,60 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_EDITVIEW_H +#define BIF_EDITVIEW_H + +struct Base; +struct Object; +struct Camera; +struct View3D; + +void arrows_move_cursor(unsigned short event); +void borderselect(void); +void circle_select(void); +void deselectall(void); +void selectswap(void); +void selectall_type(short obtype); +void selectall_layer(unsigned int layernum); +void draw_sel_circle(short *mval, short *mvalo, float rad, float rado, int selecting); +void fly(void); +int gesture(void); +void mouse_cursor(void); +void mouse_select(void); +void set_active_base(struct Base *base); +void set_active_object(struct Object *ob); +void set_render_border(void); +void view3d_border_zoom(void); +void view3d_edit_clipping(struct View3D *v3d); + +#endif + diff --git a/source/blender/include/BIF_filelist.h b/source/blender/include/BIF_filelist.h new file mode 100644 index 00000000000..b81be38da01 --- /dev/null +++ b/source/blender/include/BIF_filelist.h @@ -0,0 +1,87 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2007 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BIF_FILELIST_H +#define BIF_FILELIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct FileList; +struct direntry; +struct BlendHandle; + +struct FileList * BIF_filelist_new(); +void BIF_filelist_init_icons(); +void BIF_filelist_free_icons(); +struct FileList * BIF_filelist_copy(struct FileList* filelist); +int BIF_filelist_find(struct FileList* filelist, char *file); +void BIF_filelist_free(struct FileList* filelist); +void BIF_filelist_freelib(struct FileList* filelist); +void BIF_filelist_sort(struct FileList* filelist, short sort); +int BIF_filelist_numfiles(struct FileList* filelist); +const char * BIF_filelist_dir(struct FileList* filelist); +void BIF_filelist_setdir(struct FileList* filelist, const char *dir); +void BIF_filelist_appenddir(struct FileList* filelist, const char *relname); +struct direntry * BIF_filelist_file(struct FileList* filelist, int index); +void BIF_filelist_hidedot(struct FileList* filelist, short hide); +void BIF_filelist_setfilter(struct FileList* filelist, unsigned int filter); +void BIF_filelist_filter(struct FileList* filelist); +void BIF_filelist_swapselect(struct FileList* filelist); +void BIF_filelist_imgsize(struct FileList* filelist, short w, short h); +void BIF_filelist_loadimage(struct FileList* filelist, int index); +struct ImBuf * BIF_filelist_getimage(struct FileList* filelist, int index); + +void BIF_filelist_readdir(struct FileList* filelist); + +int BIF_filelist_empty(struct FileList* filelist); +void BIF_filelist_parent(struct FileList* filelist); +void BIF_filelist_setfiletypes(struct FileList* filelist, short has_quicktime); +int BIF_filelist_islibrary (struct FileList* filelist, char* dir, char* group); +void BIF_filelist_from_main(struct FileList* filelist); +void BIF_filelist_from_library(struct FileList* filelist); +void BIF_filelist_append_library(struct FileList* filelist, char *dir, char* file, short flag, int idcode); +void BIF_filelist_settype(struct FileList* filelist, int type); +short BIF_filelist_gettype(struct FileList* filelist); +void BIF_filelist_setipotype(struct FileList* filelist, short ipotype); +void BIF_filelist_hasfunc(struct FileList* filelist, int has_func); + +struct BlendHandle *BIF_filelist_lib(struct FileList* filelist); +int BIF_groupname_to_code(char *group); /* TODO: where should this go */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/source/blender/include/BIF_fsmenu.h b/source/blender/include/BIF_fsmenu.h new file mode 100644 index 00000000000..1c5280c14f8 --- /dev/null +++ b/source/blender/include/BIF_fsmenu.h @@ -0,0 +1,76 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + */ + +#ifndef BSE_FSMENU_H +#define BSE_FSMENU_H + + /** Returns the number of entries in the Fileselect Menu */ +int fsmenu_get_nentries (void); + + /** Returns true if the fsmenu entry at @a index exists and + * is a seperator. + */ +int fsmenu_is_entry_a_seperator (int index); + + /** Returns the fsmenu entry at @a index (or NULL if a bad index) + * or a seperator. + */ +char* fsmenu_get_entry (int index); + + /** Returns a new menu description string representing the + * fileselect menu. Should be free'd with MEM_freeN. + */ +char* fsmenu_build_menu (void); + + /** Append a seperator to the FSMenu, inserts always follow the + * last seperator. + */ +void fsmenu_append_separator (void); + + /** Inserts a new fsmenu entry with the given @a path. + * Duplicate entries are not added. + * @param sorted Should entry be inserted in sorted order? + */ +void fsmenu_insert_entry (char *path, int sorted, short save); + + /** Removes the fsmenu entry at the given @a index. */ +void fsmenu_remove_entry (int index); + + /** saves the 'favourites' to the specified file */ +void fsmenu_write_file(const char *filename); + + /** Free's all the memory associated with the fsmenu */ +void fsmenu_free (void); + +#endif + diff --git a/source/blender/include/BIF_gl.h b/source/blender/include/BIF_gl.h new file mode 100644 index 00000000000..215e88dc002 --- /dev/null +++ b/source/blender/include/BIF_gl.h @@ -0,0 +1,82 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * os dependent include locations of gl.h + */ + +#ifndef BIF_GL_H +#define BIF_GL_H + + /* Although not really a great idea to copy these defines + * from Windows' winnt.h, this lets us use GL without including + * windows.h everywhere (or BLI_winstuff.h) which is a good thing. + */ +#ifdef WIN32 +#ifndef APIENTRY +#define APIENTRY __stdcall +#endif + +#ifndef CALLBACK +#define CALLBACK __stdcall +#endif + +#ifndef WINGDIAPI +#define WINGDIAPI __declspec(dllimport) +#endif +#endif + +#ifdef __APPLE__ +#include +#include +#else +#include +#include +#endif + /* + * these should be phased out. cpack should be replaced in + * code with calls to glColor3ub, lrectwrite probably should + * change to a function. - zr + */ + +/* + * + * This define converts a numerical value to the equivalent 24-bit + * color, while not being endian-sensitive. On little-endians, this + * is the same as doing a 'naive'indexing, on big-endian, it is not! + * */ +#define cpack(x) glColor3ub( ((x)&0xFF), (((x)>>8)&0xFF), (((x)>>16)&0xFF) ) + +#define glMultMatrixf(x) glMultMatrixf( (float *)(x)) +#define glLoadMatrixf(x) glLoadMatrixf( (float *)(x)) + +#define lrectwrite(a, b, c, d, rect) {glRasterPos2i(a, b);glDrawPixels((c)-(a)+1, (d)-(b)+1, GL_RGBA, GL_UNSIGNED_BYTE, rect);} + +#endif /* #ifdef BIF_GL_H */ + diff --git a/source/blender/include/BIF_glutil.h b/source/blender/include/BIF_glutil.h new file mode 100644 index 00000000000..237f7a85002 --- /dev/null +++ b/source/blender/include/BIF_glutil.h @@ -0,0 +1,225 @@ +/** + * @file BIF_glutil.h + * + * OpenGL drawing utility functions. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_GLUTIL_H +#define BIF_GLUTIL_H + +struct rcti; +struct rctf; + +void sdrawXORline(int x0, int y0, int x1, int y1); +void sdrawXORline4(int nr, int x0, int y0, int x1, int y1); + +void fdrawXORellipse(float xofs, float yofs, float hw, float hh); +void fdrawXORcirc(float xofs, float yofs, float rad); + + /** + * Draw an XOR'd line in the front buffer between + * the given points. + * + * @attention This function also handles flushing the GL + * pipeline, which means it is inappropriate for drawing + * a large number of lines at once. + */ +void glutil_draw_front_xor_line(int x0, int y0, int x1, int y1); + + /** + * Draw a lined (non-looping) arc with the given + * @a radius, starting at angle @a start and arcing + * through @a angle. The arc is centered at the origin + * and drawn in the XY plane. + * + * @param start The initial angle (in radians). + * @param angle The length of the arc (in radians). + * @param radius The arc radius. + * @param nsegments The number of segments to use in drawing the arc. + */ +void glutil_draw_lined_arc (float start, float angle, float radius, int nsegments); + + /** + * Draw a filled arc with the given @a radius, + * starting at angle @a start and arcing through + * @a angle. The arc is centered at the origin + * and drawn in the XY plane. + * + * @param start The initial angle (in radians). + * @param angle The length of the arc (in radians). + * @param radius The arc radius. + * @param nsegments The number of segments to use in drawing the arc. + */ +void glutil_draw_filled_arc (float start, float angle, float radius, int nsegments); + + /** + * Routines an integer value as obtained by glGetIntegerv. + * The param must cause only one value to be gotten from GL. + */ +int glaGetOneInteger (int param); + + /** + * Routines a float value as obtained by glGetIntegerv. + * The param must cause only one value to be gotten from GL. + */ +float glaGetOneFloat (int param); + + /** + * Functions like glRasterPos2i, except ensures that the resulting + * raster position is valid. @a known_good_x and @a known_good_y + * should be coordinates of a point known to be within the current + * view frustum. + * @attention This routine should be used when the distance of @a x + * and @y away from the known good point is small (ie. for small icons + * and for bitmap characters), when drawing large+zoomed images it is + * possible for overflow to occur, the glaDrawPixelsSafe routine should + * be used instead. + */ +void glaRasterPosSafe2f (float x, float y, float known_good_x, float known_good_y); + + /** + * Functions like a limited glDrawPixels, except ensures that + * the image is displayed onscreen even if the @a x and @a y + * coordinates for would be clipped. The routine respects the + * glPixelZoom values, pixel unpacking parameters are _not_ + * respected. + + * @attention This routine makes many assumptions: the rect data + * is expected to be in RGBA unsigned byte format, the coordinate + * (0.375, 0.375) is assumed to be within the view frustum, and the + * modelview and projection matrices are assumed to define a + * 1-to-1 mapping to screen space. + * @attention Furthmore, in the case of zoomed or unpixel aligned + * images extending outside the view frustum, but still within the + * window, some portion of the image may be visible left and/or + * below of the given @a x and @a y coordinates. It is recommended + * to use the glScissor functionality if images are to be drawn + * with an inset view matrix. + */ +void glaDrawPixelsSafe (float x, float y, int img_w, int img_h, int row_w, int format, int type, void *rect); + + /** + * Functions like a limited glDrawPixels, but actually draws the + * image using textures, which can be tremendously faster on low-end + * cards, and also avoids problems with the raster position being + * clipped when offscreen. The routine respects the glPixelZoom values, + * pixel unpacking parameters are _not_ respected. + + * @attention This routine makes many assumptions: the rect data + * is expected to be in RGBA byte or float format, and the + * modelview and projection matrices are assumed to define a + * 1-to-1 mapping to screen space. + */ + + /* only for float rects, converts to 32 bits and draws */ +void glaDrawPixelsSafe_to32(float fx, float fy, int img_w, int img_h, int row_w, float *rectf); + + +void glaDrawPixelsTex (float x, float y, int img_w, int img_h, int format, void *rect); + + /* 2D Drawing Assistance */ + + /** Define a 2D area (viewport, scissor, matrices) for OpenGL rendering. + * This routine sets up an OpenGL state appropriate for drawing using + * both vertice (glVertex, etc) and raster (glRasterPos, glRect) commands. + * All coordinates should be at integer positions. There is little to + * no reason to use glVertex2f etc. functions during 2D rendering, and + * thus no reason to +-0.5 the coordinates or perform other silly + * tricks. + * + * @param screen_rect The screen rectangle to be defined for 2D drawing. + */ +void glaDefine2DArea (struct rcti *screen_rect); + +typedef struct gla2DDrawInfo gla2DDrawInfo; + + /** Save the current OpenGL state and initialize OpenGL for 2D + * rendering. glaEnd2DDraw should be called on the returned structure + * to free it and to return OpenGL to its previous state. The + * scissor rectangle is set to match the viewport. + * + * This routine sets up an OpenGL state appropriate for drawing using + * both vertice (glVertex, etc) and raster (glRasterPos, glRect) commands. + * All coordinates should be at integer positions. There is little to + * no reason to use glVertex2f etc. functions during 2D rendering, and + * thus no reason to +-0.5 the coordinates or perform other silly + * tricks. + * + * @param screen_rect The screen rectangle to be used for 2D drawing. + * @param world_rect The world rectangle that the 2D area represented + * by @a screen_rect is supposed to represent. If NULL it is assumed the + * world has a 1 to 1 mapping to the screen. + */ +gla2DDrawInfo* glaBegin2DDraw (struct rcti *screen_rect, struct rctf *world_rect); + + /** Translate the (@a wo_x, @a wo_y) point from world coordinates into screen space. */ +void gla2DDrawTranslatePt (gla2DDrawInfo *di, float wo_x, float wo_y, int *sc_x_r, int *sc_y_r); + + /** Translate the @a world point from world coordiantes into screen space. */ +void gla2DDrawTranslatePtv (gla2DDrawInfo *di, float world[2], int screen_r[2]); + + /* Restores the previous OpenGL state and free's the auxilary + * gla data. + */ +void glaEnd2DDraw (gla2DDrawInfo *di); + + /** Adjust the transformation mapping of a 2d area */ +void gla2DGetMap(gla2DDrawInfo *di, struct rctf *rect); +void gla2DSetMap(gla2DDrawInfo *di, struct rctf *rect); + + +/* use this for platform hacks. glPointSize is solved here */ +void bglBegin(int mode); +void bglEnd(void); +void bglVertex3fv(float *vec); +void bglVertex3f(float x, float y, float z); +void bglVertex2fv(float *vec); +/* intel gfx cards frontbuffer problem */ +void bglFlush(void); +int is_a_really_crappy_intel_card(void); +void set_inverted_drawing(int enable); + + +/* own working polygon offset */ +void bglPolygonOffset(float dist); + +/* For caching opengl matrices (gluProject/gluUnProject) */ +typedef struct bglMats { + double modelview[16]; + double projection[16]; + int viewport[4]; +} bglMats; +void bgl_get_mats(bglMats *mats); + +#endif /* BIF_GLUTIL_H */ + diff --git a/source/blender/include/BIF_graphics.h b/source/blender/include/BIF_graphics.h new file mode 100644 index 00000000000..51aa2ceeb01 --- /dev/null +++ b/source/blender/include/BIF_graphics.h @@ -0,0 +1,59 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_GRAPHICS_H +#define BIF_GRAPHICS_H + + /* XXX, should move somewhere else, with collected windowing + * stuff, to be done once the proper windowing stuff has + * been formed. + */ + +enum { + CURSOR_VPAINT, + CURSOR_FACESEL, + CURSOR_WAIT, + CURSOR_EDIT, + CURSOR_X_MOVE, + CURSOR_Y_MOVE, + CURSOR_HELP, + CURSOR_STD, + CURSOR_NONE, + CURSOR_PENCIL, + CURSOR_TEXTEDIT +}; + +void set_cursor(int curs); +int get_cursor(void); + +#endif /* BIF_GRAPHICS_H */ + diff --git a/source/blender/include/BIF_imasel.h b/source/blender/include/BIF_imasel.h new file mode 100644 index 00000000000..0e92abe14e4 --- /dev/null +++ b/source/blender/include/BIF_imasel.h @@ -0,0 +1,51 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BIF_IMASEL_H +#define BIF_IMASEL_H + +struct SpaceImaSel; +struct ScrArea; + +void free_imasel(struct SpaceImaSel *simasel); + +void clever_numbuts_imasel(void); + +void activate_imageselect(int type, char *title, char *file, void (*func)(char *)); +void activate_imageselect_menu(int type, char *title, char *file, char *pupmenu, short *menup, void (*func)(char *)); +void activate_imageselect_args(int type, char *title, char *file, void (*func)(char *, void *, void *), void *arg1, void *arg2); + +void activate_databrowse_imasel(struct ID *id, int idcode, int fromcode, int retval, short *menup, void (*func)(unsigned short)); +/* +void activate_databrowse_imasel_args(struct ID *id, int idcode, int fromcode, short *menup, void (*func)(char *, void *, void *), void *arg1, void *arg2); +*/ +#endif + diff --git a/source/blender/include/BIF_interface.h b/source/blender/include/BIF_interface.h new file mode 100644 index 00000000000..453e4e628fe --- /dev/null +++ b/source/blender/include/BIF_interface.h @@ -0,0 +1,331 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_INTERFACE_H +#define BIF_INTERFACE_H + +struct ID; +struct ListBase; +struct ScrArea; +struct AutoComplete; + +/* uiBlock->dt */ +#define UI_EMBOSS 0 /* use one of the themes for drawing */ +#define UI_EMBOSSN 1 /* Nothing */ +#define UI_EMBOSSM 2 /* Minimal builtin emboss, also for logic buttons */ +#define UI_EMBOSSP 3 /* Pulldown */ +#define UI_EMBOSSR 4 /* Rounded */ + +#define UI_EMBOSSX 0 /* for a python file, which i can't change.... duh! */ + +/* uiBlock->direction */ +#define UI_TOP 1 +#define UI_DOWN 2 +#define UI_LEFT 4 +#define UI_RIGHT 8 +#define UI_DIRECTION 15 +#define UI_CENTER 16 +#define UI_SHIFT_FLIPPED 32 + +/* uiBlock->autofill */ +#define UI_BLOCK_COLLUMNS 1 +#define UI_BLOCK_ROWS 2 + +/* return from uiDoBlock */ +#define UI_CONT 0 +#define UI_NOTHING 1 +#define UI_RETURN_CANCEL 2 +#define UI_RETURN_OK 4 +#define UI_RETURN_OUT 8 +#define UI_RETURN 14 +#define UI_EXIT_LOOP 16 + +/* uiBlock->flag (controls) */ +#define UI_BLOCK_LOOP 1 +#define UI_BLOCK_REDRAW 2 +#define UI_BLOCK_RET_1 4 +#define UI_BLOCK_BUSY 8 +#define UI_BLOCK_NUMSELECT 16 +#define UI_BLOCK_ENTER_OK 32 +#define UI_BLOCK_NOSHADOW 64 +#define UI_BLOCK_FRONTBUFFER 128 +#define UI_BLOCK_NO_HILITE 256 + + /* block->flag bits 12-15 are identical to but->flag bits */ + +/* block->font, for now: bold = medium+1 */ +#define UI_HELV 0 +#define UI_HELVB 1 + +/* panel controls */ +#define UI_PNL_TRANSP 1 +#define UI_PNL_SOLID 2 + +#define UI_PNL_CLOSE 32 +#define UI_PNL_STOW 64 +#define UI_PNL_TO_MOUSE 128 +#define UI_PNL_UNSTOW 256 +#define UI_PNL_SCALE 512 + +/* warning the first 4 flags are internal */ +/* but->flag */ +#define UI_TEXT_LEFT 16 +#define UI_ICON_LEFT 32 +#define UI_ICON_RIGHT 64 + /* control for button type block */ +#define UI_MAKE_TOP 128 +#define UI_MAKE_DOWN 256 +#define UI_MAKE_LEFT 512 +#define UI_MAKE_RIGHT 1024 + /* dont draw hilite on mouse over */ +#define UI_NO_HILITE 2048 + /* button align flag, for drawing groups together */ +#define UI_BUT_ALIGN (15<<12) +#define UI_BUT_ALIGN_TOP (1<<12) +#define UI_BUT_ALIGN_LEFT (1<<13) +#define UI_BUT_ALIGN_RIGHT (1<<14) +#define UI_BUT_ALIGN_DOWN (1<<15) + + +/* Button types, bits stored in 1 value... and a short even! +- bits 0-4: bitnr (0-31) +- bits 5-7: pointer type +- bit 8: for 'bit' +- bit 9-15: button type (now 6 bits, 64 types) +*/ + +#define CHA 32 +#define SHO 64 +#define INT 96 +#define FLO 128 +#define FUN 192 +#define BIT 256 + +#define BUTPOIN (128+64+32) + +#define BUT (1<<9) +#define ROW (2<<9) +#define TOG (3<<9) +#define SLI (4<<9) +#define NUM (5<<9) +#define TEX (6<<9) +#define TOG3 (7<<9) +#define TOGR (8<<9) +#define TOGN (9<<9) +#define LABEL (10<<9) +#define MENU (11<<9) +#define ICONROW (12<<9) +#define ICONTOG (13<<9) +#define NUMSLI (14<<9) +#define COL (15<<9) +#define IDPOIN (16<<9) +#define HSVSLI (17<<9) +#define SCROLL (18<<9) +#define BLOCK (19<<9) +#define BUTM (20<<9) +#define SEPR (21<<9) +#define LINK (22<<9) +#define INLINK (23<<9) +#define KEYEVT (24<<9) +#define ICONTEXTROW (25<<9) +#define HSVCUBE (26<<9) +#define PULLDOWN (27<<9) +#define ROUNDBOX (28<<9) +#define CHARTAB (29<<9) +#define BUT_COLORBAND (30<<9) +#define BUT_NORMAL (31<<9) +#define BUT_CURVE (32<<9) +#define BUT_TOGDUAL (33<<9) +#define ICONTOGN (34<<9) +#define FTPREVIEW (35<<9) +#define BUTTYPE (63<<9) + + + +typedef struct uiBut uiBut; +typedef struct uiBlock uiBlock; + +void uiEmboss(float x1, float y1, float x2, float y2, int sel); +void uiRoundBoxEmboss(float minx, float miny, float maxx, float maxy, float rad, int active); +void uiRoundBox(float minx, float miny, float maxx, float maxy, float rad); +void uiSetRoundBox(int type); +void uiRoundRect(float minx, float miny, float maxx, float maxy, float rad); + +void uiDrawMenuBox(float minx, float miny, float maxx, float maxy, short flag); +void uiTextBoundsBlock(uiBlock *block, int addval); +void uiBoundsBlock(struct uiBlock *block, int addval); +void uiDrawBlock(struct uiBlock *block); +void uiGetMouse(int win, short *adr); +void uiComposeLinks(uiBlock *block); +void uiSetButLock(int val, char *lockstr); +void uiClearButLock(void); +int uiDoBlocks(struct ListBase *lb, int event); +void uiSetCurFont(uiBlock *block, int index); +void uiDefFont(unsigned int index, void *xl, void *large, void *medium, void *small); +void uiFreeBlock(uiBlock *block); +void uiFreeBlocks(struct ListBase *lb); +void uiFreeBlocksWin(struct ListBase *lb, int win); +uiBlock *uiNewBlock(struct ListBase *lb, char *name, short dt, short font, short win); +uiBlock *uiGetBlock(char *name, struct ScrArea *sa); + +void uiBlockPickerButtons(struct uiBlock *block, float *col, float *hsv, float *old, char *hexcol, char mode, short retval); + + +/* automatic aligning, horiz or verical */ +void uiBlockBeginAlign(uiBlock *block); +void uiBlockEndAlign(uiBlock *block); + +uiBut *uiDefBut(uiBlock *block, + int type, int retval, char *str, + short x1, short y1, + short x2, short y2, + void *poin, + float min, float max, + float a1, float a2, char *tip); +uiBut *uiDefButF(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip); +uiBut *uiDefButBitF(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip); +uiBut *uiDefButI(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip); +uiBut *uiDefButBitI(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip); +uiBut *uiDefButS(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip); +uiBut *uiDefButBitS(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip); +uiBut *uiDefButC(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip); +uiBut *uiDefButBitC(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip); + +uiBut *uiDefIconBut(uiBlock *block, + int type, int retval, int icon, + short x1, short y1, + short x2, short y2, + void *poin, + float min, float max, + float a1, float a2, char *tip); +uiBut *uiDefIconButF(uiBlock *block, int type, int retval, int icon, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip); +uiBut *uiDefIconButBitF(uiBlock *block, int type, int bit, int retval, int icon, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip); +uiBut *uiDefIconButI(uiBlock *block, int type, int retval, int icon, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip); +uiBut *uiDefIconButBitI(uiBlock *block, int type, int bit, int retval, int icon, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip); +uiBut *uiDefIconButS(uiBlock *block, int type, int retval, int icon, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip); +uiBut *uiDefIconButBitS(uiBlock *block, int type, int bit, int retval, int icon, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip); +uiBut *uiDefIconButC(uiBlock *block, int type, int retval, int icon, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip); +uiBut *uiDefIconButBitC(uiBlock *block, int type, int bit, int retval, int icon, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip); + +uiBut *uiDefIconTextBut(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip); + +uiBut *uiDefIconTextButF(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip); +uiBut *uiDefIconTextButBitF(uiBlock *block, int type, int bit, int retval, int icon, char *str, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip); +uiBut *uiDefIconTextButI(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip); +uiBut *uiDefIconTextButBitI(uiBlock *block, int type, int bit, int retval, int icon, char *str, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip); +uiBut *uiDefIconTextButS(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip); +uiBut *uiDefIconTextButBitS(uiBlock *block, int type, int bit, int retval, int icon, char *str, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip); +uiBut *uiDefIconTextButC(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip); +uiBut *uiDefIconTextButBitC(uiBlock *block, int type, int bit, int retval, int icon, char *str, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip); + +typedef void (*uiIDPoinFuncFP) (char *str, struct ID **idpp); +uiBut *uiDefIDPoinBut(struct uiBlock *block, uiIDPoinFuncFP func, short blocktype, int retval, char *str, + short x1, short y1, short x2, short y2, void *idpp, char *tip); + +typedef uiBlock* (*uiBlockFuncFP) (void *arg1); +uiBut *uiDefBlockBut(uiBlock *block, uiBlockFuncFP func, void *func_arg1, char *str, short x1, short y1, short x2, short y2, char *tip); +uiBut *uiDefPulldownBut(uiBlock *block, uiBlockFuncFP func, void *func_arg1, char *str, short x1, short y1, short x2, short y2, char *tip); + +uiBut *uiDefIconTextBlockBut(uiBlock *block, uiBlockFuncFP func, void *arg, int icon, char *str, short x1, short y1, short x2, short y2, char *tip); +uiBut *uiDefIconBlockBut(uiBlock *block, uiBlockFuncFP func, void *arg, int retval, int icon, short x1, short y1, short x2, short y2, char *tip); + +void uiDefKeyevtButS(uiBlock *block, int retval, char *str, short x1, short y1, short x2, short y2, short *spoin, char *tip); + +void uiAutoBlock(struct uiBlock *block, + float minx, float miny, + float sizex, float sizey, int flag); +void uiSetButLink(struct uiBut *but, + void **poin, + void ***ppoin, + short *tot, + int from, int to); + +int uiBlocksGetYMin (ListBase *lb); +int uiBlockGetCol (uiBlock *block); +void* uiBlockGetCurFont (uiBlock *block); + +void uiBlockSetCol (uiBlock *block, int col); +void uiBlockSetEmboss (uiBlock *block, int emboss); +void uiBlockSetDirection (uiBlock *block, int direction); +void uiBlockFlipOrder (uiBlock *block); +void uiBlockSetFlag (uiBlock *block, int flag); +void uiBlockSetXOfs (uiBlock *block, int xofs); + +int uiButGetRetVal (uiBut *but); + +void uiButSetFlag (uiBut *but, int flag); +void uiButClearFlag (uiBut *but, int flag); + +void uiBlockSetButmFunc (uiBlock *block, void (*butmfunc)(void *arg, int but_a2), void *arg); + +void uiBlockSetFunc (uiBlock *block, void (*func)(void *arg1, void *arg2), void *arg1, void *arg2); +void uiButSetFunc (uiBut *but, void (*func)(void *arg1, void *arg2), void *arg1, void *arg2); + +void uiButSetCompleteFunc(uiBut *but, void (*func)(char *str, void *arg), void *arg); + +void uiBlockSetDrawExtraFunc(uiBlock *block, void (*func)(struct ScrArea *sa, uiBlock *block)); + + +extern void pupmenu_set_active(int val); +extern short pupmenu(char *instr); +extern short pupmenu_col(char *instr, int maxrow); + +extern void uiFreePanels(struct ListBase *lb); +extern void uiNewPanelTabbed(char *, char *); +extern int uiNewPanel(struct ScrArea *sa, struct uiBlock *block, char *panelname, char *tabname, int ofsx, int ofsy, int sizex, int sizey); + +extern void uiSetPanel_view2d(struct ScrArea *sa); +extern void uiMatchPanel_view2d(struct ScrArea *sa); + +extern void uiDrawBlocksPanels(struct ScrArea *sa, int re_align); +extern void uiNewPanelHeight(struct uiBlock *block, int sizey); +extern void uiNewPanelTitle(struct uiBlock *block, char *str); +extern void uiPanelPush(struct uiBlock *block); +extern void uiPanelPop(struct uiBlock *block); +extern uiBlock *uiFindOpenPanelBlockName(ListBase *lb, char *name); +extern int uiAlignPanelStep(struct ScrArea *sa, float fac); +extern void uiPanelControl(int); +extern void uiSetPanelHandler(int); + +extern void uiDrawBoxShadow(unsigned char alpha, float minx, float miny, float maxx, float maxy); +extern void *uiSetCurFont_ext(float aspect); + +void shade_buttons_change_3d(void); + +typedef struct AutoComplete AutoComplete; + +AutoComplete *autocomplete_begin(char *startname, int maxlen); +void autocomplete_do_name(AutoComplete *autocpl, const char *name); +void autocomplete_end(AutoComplete *autocpl, char *autoname); + +#endif /* BIF_INTERFACE_H */ + diff --git a/source/blender/include/BIF_interface_icons.h b/source/blender/include/BIF_interface_icons.h new file mode 100644 index 00000000000..c628d68e9db --- /dev/null +++ b/source/blender/include/BIF_interface_icons.h @@ -0,0 +1,72 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_PREVIEW_ICONS_H +#define BIF_PREVIEW_ICONS_H + +struct Image; +struct ImBuf; +struct World; +struct Tex; +struct Lamp; +struct Material; + +typedef struct IconFile { + struct IconFile *next, *prev; + char filename[80]; // FILE_MAXFILE size + int index; +} IconFile; + + +#define ICON_DEFAULT_HEIGHT 16 +#define PREVIEW_DEFAULT_HEIGHT 96 + +/* + Resizable Icons for Blender +*/ +void BIF_icons_init(int first_dyn_id); +int BIF_icon_get_width(int icon_id); +int BIF_icon_get_height(int icon_id); + +void BIF_icon_draw(float x, float y, int icon_id); +void BIF_icon_draw_preview(float x, float y, int icon_id, int nocreate); + +void BIF_icon_draw_aspect(float x, float y, int icon_id, float aspect); +void BIF_icon_draw_aspect_blended(float x, float y, int icon_id, float aspect, int shade); +void BIF_icons_free(); +void BIF_icons_free_drawinfo(void *drawinfo); + +struct ListBase *BIF_iconfile_list(void); +int BIF_iconfile_get_index(char *filename); + + +#endif /* BIF_ICONS_H */ diff --git a/source/blender/include/BIF_keyval.h b/source/blender/include/BIF_keyval.h new file mode 100644 index 00000000000..7134bd2b153 --- /dev/null +++ b/source/blender/include/BIF_keyval.h @@ -0,0 +1,39 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_KEYVAL_H +#define BIF_KEYVAL_H + +char *key_event_to_string(unsigned short event); + +#endif + diff --git a/source/blender/include/BIF_language.h b/source/blender/include/BIF_language.h new file mode 100644 index 00000000000..6ed8a8d1574 --- /dev/null +++ b/source/blender/include/BIF_language.h @@ -0,0 +1,69 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_LANGUAGE_H +#define BIF_LANGUAGE_H + +#include "DNA_vec_types.h" + +struct BMF_Font; + +int read_languagefile(void); /* usiblender.c */ +void free_languagemenu(void); /* usiblender.c */ + +void set_interface_font(char *str); /* headerbuttons.c */ +void start_interface_font(void); /* headerbuttons.c */ +void lang_setlanguage(void); /* usiblender.c */ + +char *language_pup(void); +char *fontsize_pup(void); + +int BIF_DrawString(struct BMF_Font* font, char *str, int translate); +float BIF_GetStringWidth(struct BMF_Font* font, char *str, int translate); +void BIF_GetBoundingBox(struct BMF_Font* font, char* str, int translate, rctf* bbox); + +void BIF_RasterPos(float x, float y); +void BIF_SetScale(float aspect); +void refresh_interface_font(void); + +struct LANGMenuEntry { + struct LANGMenuEntry *next; + char *line; + char *language; + char *code; + int id; +}; + +struct LANGMenuEntry *find_language(short langid); + +#endif /* BIF_LANGUAGE_H */ + diff --git a/source/blender/include/BIF_mainqueue.h b/source/blender/include/BIF_mainqueue.h new file mode 100644 index 00000000000..e2eaeea4dca --- /dev/null +++ b/source/blender/include/BIF_mainqueue.h @@ -0,0 +1,47 @@ +/* + * Central queue handling functions. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_MAINQUEUE_H +#define BIF_MAINQUEUE_H + +#define MAXQUEUE 4096 + +unsigned short mainqtest (void); +unsigned short mainqread (short *val, char *ascii); +void mainqenter (unsigned short event, short val); +void mainqenter_ext (unsigned short event, short val, char ascii); +void mainqpushback (unsigned short event, short val, char ascii); + +#endif /* BIF_MAINQUEUE_H */ + diff --git a/source/blender/include/BIF_meshlaplacian.h b/source/blender/include/BIF_meshlaplacian.h new file mode 100644 index 00000000000..74e4fef0937 --- /dev/null +++ b/source/blender/include/BIF_meshlaplacian.h @@ -0,0 +1,87 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * BIF_meshlaplacian.h: Algorithms using the mesh laplacian. + */ + +#ifndef BIF_MESHLAPLACIAN_H +#define BIF_MESHLAPLACIAN_H + +//#define RIGID_DEFORM + +struct Object; +struct Mesh; +struct bDeformGroup; +struct MeshDeformModifierData; + +#ifdef RIGID_DEFORM +struct EditMesh; +#endif + +/* Laplacian System */ + +struct LaplacianSystem; +typedef struct LaplacianSystem LaplacianSystem; + +LaplacianSystem *laplacian_construct_begin(int totvert, int totface); + +void laplacian_add_vertex(LaplacianSystem *sys, float *co, int pinned); +void laplacian_add_triangle(LaplacianSystem *sys, int v1, int v2, int v3); + +void laplacian_construct_end(LaplacianSystem *sys); +void laplacian_delete(LaplacianSystem *sys); + +void laplacian_begin_solve(LaplacianSystem *sys, int index); +void laplacian_add_right_hand_side(LaplacianSystem *sys, int v, float value); +int laplacian_system_solve(LaplacianSystem *sys); +float laplacian_system_get_solution(int v); + +/* Heat Weighting */ + +void heat_bone_weighting(struct Object *ob, struct Mesh *me, float (*verts)[3], + int numbones, struct bDeformGroup **dgrouplist, + struct bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3], + int *selected); + +#ifdef RIGID_DEFORM +/* As-Rigid-As-Possible Deformation */ + +void rigid_deform_begin(struct EditMesh *em); +void rigid_deform_iteration(void); +void rigid_deform_end(int cancel); +#endif + +/* Harmonic Coordinates */ + +void harmonic_coordinates_bind(struct MeshDeformModifierData *mmd, + float (*vertexcos)[3], int totvert, float cagemat[][4]); + +#endif + diff --git a/source/blender/include/BIF_meshtools.h b/source/blender/include/BIF_meshtools.h new file mode 100644 index 00000000000..a08f800d7b6 --- /dev/null +++ b/source/blender/include/BIF_meshtools.h @@ -0,0 +1,50 @@ +/** + * $Id: + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_MESHTOOLS_H +#define BIF_MESHTOOLS_H + +struct Object; +struct EditVert; + +extern int join_mesh(void); + +extern void sort_faces(void); +extern void objects_bake_render_menu(void); +extern void objects_bake_render(short event); + +extern long mesh_octree_table(struct Object *ob, float *co, char mode); +extern int mesh_get_x_mirror_vert(struct Object *ob, int index); +extern struct EditVert *editmesh_get_x_mirror_vert(struct Object *ob, float *co); + +#endif + diff --git a/source/blender/include/BIF_mywindow.h b/source/blender/include/BIF_mywindow.h new file mode 100644 index 00000000000..28de60d2bc0 --- /dev/null +++ b/source/blender/include/BIF_mywindow.h @@ -0,0 +1,145 @@ + +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * These are the protos for mywindow.c -- an emulation of the + * (obsolete) IrisGL command set + */ + +#ifndef BIF_MYWINDOW_H +#define BIF_MYWINDOW_H + +struct rcti; + +/*---*/ + +typedef struct BWinEvent { + unsigned short event; + short val; + char ascii; +} BWinEvent; + +/*---*/ + +int mywinget(void); +void mywinclose(int winid); +void mywinposition(int winid, + int xmin, int xmax, + int ymin, int ymax); +/*---*/ + + /** Test if there are events available on a BWin queue. + * + * @param winid The ID of the window to query. + * @return True if there is an event available for _qread'ing. + */ +int bwin_qtest(int winid); + + /** Read an event off of the BWin queue (if available). + * + * @param winid The ID of the window to read from. + * @param event_r A pointer to return the event in. + * @return True if an event was read and @a event_r filled. + */ +int bwin_qread(int winid, BWinEvent *event_r); + + /** Add an event to the BWin queue. + * + * @param winid The ID of the window to add to. + * @param event A pointer to copy the event from. + */ +void bwin_qadd(int winid, BWinEvent *event); + +/*---*/ + +void bwin_load_viewmatrix(int winid, float mat[][4]); +void bwin_load_winmatrix(int winid, float mat[][4]); + +void bwin_get_viewmatrix(int winid, float mat[][4]); +void bwin_get_winmatrix(int winid, float mat[][4]); + +void bwin_multmatrix(int winid, float mat[][4]); +void bwin_scalematrix(int winid, float x, float y, float z); + +void bwin_ortho(int winid, float x1, float x2, float y1, float y2, float n, float f); +void bwin_ortho2(int win, float x1, float x2, float y1, float y2); +void bwin_frustum(int winid, float x1, float x2, float y1, float y2, float n, float f); + +void bwin_getsize(int winid, int *x, int *y); +void bwin_getsuborigin(int winid, int *x, int *y); +void bwin_get_rect(int winid, struct rcti *rect_r); +void bwin_getsinglematrix(int winid, float mat[][4]); +void bwin_clear_viewmat(int winid); + +int myswinopen(int parentid, int xmin, int xmax, int ymin, int ymax); +int myswinopen_allowed(void); +void myswapbuffers(void); + +void mygetmatrix(float mat[][4]); +void mymultmatrix(float [][4]); + +void myloadmatrix(float mat[][4]); +void mywinset(int wid); +void myortho(float x1, float x2, float y1, float y2, float n, float f); +void myortho2(float x1, float x2, float y1, float y2); +void mywindow(float x1, float x2, float y1, float y2, float n, float f); +void mygetsingmatrix(float (*)[4]); + +void setlinestyle(int nr); + +void BIF_wait_for_statechange(void); + +#define L_MOUSE 1 +#define M_MOUSE 2 +#define R_MOUSE 4 +short get_mbut(void); +short get_qual(void); +void getmouse(short *mval); + +float get_pressure(void); +void get_tilt(float *xtilt, float *ytilt); +#define DEV_MOUSE 0 +#define DEV_STYLUS 1 +#define DEV_ERASER 2 +short get_activedevice(void); + +void warp_pointer(int x, int y); + +int framebuffer_to_index(unsigned int col); +void set_framebuffer_index_color(int index); + +int mywin_inmenu(void); +void mywin_getmenu_rect(int *x, int *y, int *sx, int *sy); + +void my_put_frontbuffer_image(void); +void my_get_frontbuffer_image(int x, int y, int sx, int sy); + +#endif + diff --git a/source/blender/include/BIF_oops.h b/source/blender/include/BIF_oops.h new file mode 100644 index 00000000000..5da088a5ea7 --- /dev/null +++ b/source/blender/include/BIF_oops.h @@ -0,0 +1,71 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_OOPS_H +#define BIF_OOPS_H + +struct Curve; +struct Oops; +struct OopsLink; +struct SpaceOops; +struct Material; +struct Mesh; +struct MetaBall; +struct Object; +struct Lamp; +void add_curve_oopslinks(struct Curve *cu, struct Oops *oops, short flag); +void add_from_link(struct Oops *from, struct Oops *oops); +void add_material_oopslinks(struct Material *ma, struct Oops *oops, short flag); +void add_mball_oopslinks(struct MetaBall *mb, struct Oops *oops, short flag); +void add_mesh_oopslinks(struct Mesh *me, struct Oops *oops, short flag); +void add_object_oopslinks(struct Object *ob, struct Oops *oops, short flag); +void add_lamp_oopslinks(struct Lamp *la, struct Oops *oops, short flag); +struct Oops *add_oops(void *id); +struct OopsLink *add_oopslink(char *name, struct Oops *oops, short type, void *from, float xof, float yof); +struct Oops *add_test_oops(void *id); /* incl links */ +void add_texture_oops(struct Material *ma); +void build_oops(void); +struct Oops *find_oops(ID *id); +void free_oops(struct Oops *oops); /* ook oops zelf */ +void free_oopspace(struct SpaceOops *so); +void new_oops_location(struct Oops *); +int oops_test_overlap(struct Oops *test); +int oops_test_overlaphide(struct Oops *test); +float oopslink_totlen(struct Oops *oops); +void shrink_oops(void); +void shuffle_oops(void); +int test_oops(struct Oops *oops); +void test_oopslink(struct OopsLink *ol); +void test_oopslinko(struct OopsLink *ol); + +#endif + diff --git a/source/blender/include/BIF_outliner.h b/source/blender/include/BIF_outliner.h new file mode 100644 index 00000000000..34ed7950421 --- /dev/null +++ b/source/blender/include/BIF_outliner.h @@ -0,0 +1,106 @@ +/** + * $Id: BIF_outliner.h + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_OUTLINER_H +#define BIF_OUTLINER_H + +struct TreeStoreElem; + +typedef struct TreeElement { + struct TreeElement *next, *prev, *parent; + ListBase subtree; + float xs, ys; // do selection + int store_index; // offset in tree store + short flag, index; // flag for non-saved stuff, index for data arrays + short idcode; // from TreeStore id + short xend; // width of item display, for select + char *name; + void *directdata; // Armature Bones, Base, ... +} TreeElement; + +/* TreeElement->flag */ +#define TE_ACTIVE 1 +#define TE_ICONROW 2 + +/* TreeStoreElem types */ +#define TSE_NLA 1 +#define TSE_NLA_ACTION 2 +#define TSE_DEFGROUP_BASE 3 +#define TSE_DEFGROUP 4 +#define TSE_BONE 5 +#define TSE_EBONE 6 +#define TSE_CONSTRAINT_BASE 7 +#define TSE_CONSTRAINT 8 +#define TSE_MODIFIER_BASE 9 +#define TSE_MODIFIER 10 +#define TSE_LINKED_OB 11 +#define TSE_SCRIPT_BASE 12 +#define TSE_POSE_BASE 13 +#define TSE_POSE_CHANNEL 14 +/*#ifdef WITH_VERSE*/ +#define TSE_VERSE_SESSION 15 +#define TSE_VERSE_OBJ_NODE 16 +#define TSE_VERSE_GEOM_NODE 17 +/*#endif*/ +#define TSE_PROXY 18 +#define TSE_R_LAYER_BASE 19 +#define TSE_R_LAYER 20 +#define TSE_R_PASS 21 +#define TSE_LINKED_MAT 22 + /* NOTE, is used for light group */ +#define TSE_LINKED_LAMP 23 + +/* outliner search flags */ +#define OL_FIND 0 +#define OL_FIND_CASE 1 +#define OL_FIND_COMPLETE 2 +#define OL_FIND_COMPLETE_CASE 3 + +/* button events */ +#define OL_NAMEBUTTON 1 + +extern void draw_outliner(struct ScrArea *sa, struct SpaceOops *so); +extern void outliner_free_tree(struct ListBase *lb); +extern void outliner_mouse_event(struct ScrArea *sa, short event); +extern void outliner_toggle_visible(struct ScrArea *sa); +extern void outliner_show_active(struct ScrArea *sa); +extern void outliner_show_hierarchy(struct ScrArea *sa); +extern void outliner_one_level(struct ScrArea *sa, int add); +extern void outliner_select(struct ScrArea *sa); +extern void outliner_toggle_selected(struct ScrArea *sa); +extern void outliner_del(struct ScrArea *sa); +extern void outliner_operation_menu(struct ScrArea *sa); +extern void outliner_page_up_down(struct ScrArea *sa, int up); +extern void outliner_find_panel(struct ScrArea *sa, int again, int flags); + +#endif + diff --git a/source/blender/include/BIF_poseobject.h b/source/blender/include/BIF_poseobject.h new file mode 100644 index 00000000000..a640d3abe84 --- /dev/null +++ b/source/blender/include/BIF_poseobject.h @@ -0,0 +1,71 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_POSEOBJECT +#define BIF_POSEOBJECT + + +struct Object; +struct bPoseChannel; + +void enter_posemode(void); +void exit_posemode(void); + + // sets chan->flag to POSE_KEY if bone selected +void set_pose_keys(struct Object *ob); + +struct bPoseChannel *get_active_posechannel (struct Object *ob); +int pose_channel_in_IK_chain(struct Object *ob, struct bPoseChannel *pchan); + +/* tools */ +void pose_select_constraint_target(void); +void pose_special_editmenu(void); +void pose_add_IK(void); +void pose_clear_IK(void); +void pose_clear_constraints(void); +void pose_copy_menu(void); + +void free_posebuf(void); +void copy_posebuf (void); +void paste_posebuf (int flip); + +void pose_adds_vgroups(struct Object *meshobj, int heatweights); + +void pose_calculate_path(struct Object *ob); +void pose_clear_paths(struct Object *ob); + +void pose_flip_names(void); +void pose_activate_flipped_bone(void); +void pose_movetolayer(void); + +#endif + diff --git a/source/blender/include/BIF_previewrender.h b/source/blender/include/BIF_previewrender.h new file mode 100644 index 00000000000..f5661fa313d --- /dev/null +++ b/source/blender/include/BIF_previewrender.h @@ -0,0 +1,94 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_PREVIEWRENDER_H +#define BIF_PREVIEWRENDER_H + +#include "DNA_vec_types.h" + +struct View3D; +struct SpaceButs; +struct RenderInfo; +struct Image; +struct ScrArea; +struct uiBlock; +struct Render; + +#define PREVIEW_RENDERSIZE 140 + +typedef void (*VectorDrawFunc)(int x, int y, int w, int h, float alpha); + +/* stores rendered preview - is also used for icons */ +typedef struct RenderInfo { + int pr_rectx; + int pr_recty; + short curtile, tottile, status; + rcti disprect; /* storage for view3d preview rect */ + unsigned int* rect; + struct Render *re; /* persistant render */ +} RenderInfo; + +/* ri->status */ +#define PR_DBASE 1 +#define PR_DISPRECT 2 +#define PR_PROJECTED 4 +#define PR_ROTATED 8 + +/* Render the preview + +pr_method: +- PR_DRAW_RENDER: preview is rendered and drawn, as indicated by called context (buttons panel) +- PR_ICON_RENDER: the preview is not drawn and the function is not dynamic, + so no events are processed. Hopefully fast enough for at least 32x32 +- PR_DO_RENDER: preview is rendered, not drawn, but events are processed for afterqueue, + in use for node editor now. +*/ + +#define PR_DRAW_RENDER 0 +#define PR_ICON_RENDER 1 +#define PR_DO_RENDER 2 + +void BIF_previewrender (struct ID *id, struct RenderInfo *ri, struct ScrArea *area, int pr_method); +void BIF_previewrender_buts (struct SpaceButs *sbuts); +void BIF_previewdraw (struct ScrArea *sa, struct uiBlock *block); +void BIF_preview_changed (short id_code); + +void BIF_preview_init_dbase (void); +void BIF_preview_free_dbase (void); + +void BIF_view3d_previewrender(struct ScrArea *sa); +void BIF_view3d_previewdraw (struct ScrArea *sa, struct uiBlock *block); +void BIF_view3d_previewrender_free(struct View3D *v3d); +void BIF_view3d_previewrender_clear(struct ScrArea *sa); +void BIF_view3d_previewrender_signal(struct ScrArea *sa, short signal); + +#endif diff --git a/source/blender/include/BIF_renderwin.h b/source/blender/include/BIF_renderwin.h new file mode 100644 index 00000000000..789c3661db7 --- /dev/null +++ b/source/blender/include/BIF_renderwin.h @@ -0,0 +1,67 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +struct Render; +struct ScrArea; +struct RenderStats; + +void calc_renderwin_rectangle(int rectx, int recty, int posmask, int renderpos_r[2], int rendersize_r[2]); + +void BIF_close_render_display(void); + +void BIF_do_render(int anim); + +/** + * @param v3d The View3D space to render. + */ +void BIF_do_ogl_render(struct View3D *v3d, int anim); + +void BIF_renderwin_set_for_ogl_render(void); +void BIF_renderwin_set_custom_cursor(unsigned char mask[16][2], unsigned char bitmap[16][2]); + +void BIF_redraw_render_rect(void); +void BIF_swap_render_rects(void); +void BIF_store_spare(void); +void BIF_toggle_render_display(void); + +void BIF_init_render_callbacks(struct Render *re, int do_display); +void BIF_end_render_callbacks(void); + +/* should not be here, ~WIP~ */ +void make_renderinfo_string(struct RenderStats *rs, char *str); + +/* space for info text */ +#define RW_HEADERY 18 + +/* header print for window */ +#define RW_MAXTEXT 512 + diff --git a/source/blender/include/BIF_resources.h b/source/blender/include/BIF_resources.h new file mode 100644 index 00000000000..e63e84efcbd --- /dev/null +++ b/source/blender/include/BIF_resources.h @@ -0,0 +1,599 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_RESOURCES_H +#define BIF_RESOURCES_H + +/* elubie: TODO: move the typedef for icons to BIF_interface_icons.h */ +/* and add/replace include of BIF_resources.h by BIF_interface_icons.h */ +typedef enum { +#define BIFICONID_FIRST (ICON_VIEW3D) + ICON_VIEW3D, + ICON_IPO, + ICON_OOPS, + ICON_BUTS, + ICON_FILESEL, + ICON_IMAGE_COL, + ICON_INFO, + ICON_SEQUENCE, + ICON_TEXT, + ICON_IMASEL, + ICON_SOUND, + ICON_ACTION, + ICON_NLA, + ICON_SCRIPTWIN, + ICON_TIME, + ICON_NODE, + ICON_SPACE2, + ICON_SPACE3, + ICON_SPACE4, + ICON_TRIA_LEFT, + ICON_TRIA_UP, + ICON_FONTPREVIEW, + ICON_BLANK4, + ICON_BLANK5, + ICON_BLANK6, + + ICON_ORTHO, + ICON_PERSP, + ICON_CAMERA, + ICON_EFFECTS, + ICON_BBOX, + ICON_WIRE, + ICON_SOLID, + ICON_SMOOTH, + ICON_POTATO, + ICON_MARKER_HLT, + ICON_NORMALVIEW, + ICON_LOCALVIEW, + ICON_UNUSEDVIEW, + ICON_VIEWZOOM, + ICON_SORTALPHA, + ICON_SORTTIME, + ICON_SORTSIZE, + ICON_LONGDISPLAY, + ICON_SHORTDISPLAY, + ICON_TRIA_DOWN, + ICON_TRIA_RIGHT, + ICON_BLANK7, + ICON_BLANK8, + ICON_BLANK9, + ICON_BLANK10, + + ICON_VIEW_AXIS_ALL, + ICON_VIEW_AXIS_NONE, + ICON_VIEW_AXIS_NONE2, + ICON_VIEW_AXIS_TOP, + ICON_VIEW_AXIS_FRONT, + ICON_VIEW_AXIS_SIDE, + ICON_POSE_DEHLT, + ICON_POSE_HLT, + ICON_BORDERMOVE, + ICON_MAYBE_ITS_A_LASSO, + ICON_BLANK1, /* ATTENTION, someone decided to use this throughout blender + and didn't care to neither rename it nor update the PNG */ + ICON_VERSE, + ICON_MOD_BOOLEAN, + ICON_ARMATURE, + ICON_PAUSE, + ICON_ALIGN, + ICON_REC, + ICON_PLAY, + ICON_FF, + ICON_REW, + ICON_PYTHON, + ICON_BLANK11, + ICON_BLANK12, + ICON_BLANK13, + ICON_BLANK14, + + + ICON_DOTSUP, + ICON_DOTSDOWN, + ICON_MENU_PANEL, + ICON_AXIS_SIDE, + ICON_AXIS_FRONT, + ICON_AXIS_TOP, + ICON_STICKY_UVS_LOC, + ICON_STICKY_UVS_DISABLE, + ICON_STICKY_UVS_VERT, + ICON_PREV_KEYFRAME, + ICON_NEXT_KEYFRAME, + ICON_ENVMAP, + ICON_TRANSP_HLT, + ICON_TRANSP_DEHLT, + ICON_CIRCLE_DEHLT, + ICON_CIRCLE_HLT, + ICON_TPAINT_DEHLT, + ICON_TPAINT_HLT, + ICON_WPAINT_DEHLT, + ICON_WPAINT_HLT, + ICON_MARKER, + ICON_BLANK15, + ICON_BLANK16, + ICON_BLANK17, + ICON_BLANK18, + + ICON_X, + ICON_GO_LEFT, + ICON_NO_GO_LEFT, + ICON_UNLOCKED, + ICON_LOCKED, + ICON_PARLIB, + ICON_DATALIB, + ICON_AUTO, + ICON_MATERIAL_DEHLT2, + ICON_RING, + ICON_GRID, + ICON_PROPEDIT, + ICON_KEEPRECT, + ICON_DESEL_CUBE_VERTS, + ICON_EDITMODE_DEHLT, + ICON_EDITMODE_HLT, + ICON_VPAINT_DEHLT, + ICON_VPAINT_HLT, + ICON_FACESEL_DEHLT, + ICON_FACESEL_HLT, + ICON_EDIT_DEHLT, + ICON_BOOKMARKS, + ICON_BLANK20, + ICON_BLANK21, + ICON_BLANK22, + + ICON_HELP, + ICON_ERROR, + ICON_FOLDER_DEHLT, + ICON_FOLDER_HLT, + ICON_BLUEIMAGE_DEHLT, + ICON_BLUEIMAGE_HLT, + ICON_BPIBFOLDER_DEHLT, + ICON_BPIBFOLDER_HLT, + ICON_BPIBFOLDER_ERR, + ICON_UGLY_GREEN_RING, + ICON_GHOST, + ICON_SORTBYEXT, + ICON_SCULPTMODE_HLT, + ICON_VERTEXSEL, + ICON_EDGESEL, + ICON_FACESEL, + ICON_PLUS, + ICON_BPIBFOLDER_X, + ICON_BPIBFOLDERGREY, + ICON_MAGNIFY, + ICON_INFO2, + ICON_BLANK23, + ICON_BLANK24, + ICON_BLANK25, + ICON_BLANK26, + + ICON_RIGHTARROW, + ICON_DOWNARROW_HLT, + ICON_ROUNDBEVELTHING, + ICON_FULLTEXTURE, + ICON_HOOK, + ICON_DOT, + ICON_WORLD_DEHLT, + ICON_CHECKBOX_DEHLT, + ICON_CHECKBOX_HLT, + ICON_LINK, + ICON_INLINK, + ICON_ZOOMIN, + ICON_ZOOMOUT, + ICON_PASTEDOWN, + ICON_COPYDOWN, + ICON_CONSTANT, + ICON_LINEAR, + ICON_CYCLIC, + ICON_KEY_DEHLT, + ICON_KEY_HLT, + ICON_GRID2, + ICON_BLANK27, + ICON_BLANK28, + ICON_BLANK29, + ICON_BLANK30, + + ICON_EYE, + ICON_LAMP, + ICON_MATERIAL, + ICON_TEXTURE, + ICON_ANIM, + ICON_WORLD, + ICON_SCENE, + ICON_EDIT, + ICON_GAME, + ICON_PAINT, + ICON_RADIO, + ICON_SCRIPT, + ICON_SPEAKER, + ICON_PASTEUP, + ICON_COPYUP, + ICON_PASTEFLIPUP, + ICON_PASTEFLIPDOWN, + ICON_CYCLICLINEAR, + ICON_PIN_DEHLT, + ICON_PIN_HLT, + ICON_LITTLEGRID, + ICON_BLANK31, + ICON_BLANK32, + ICON_BLANK33, + ICON_BLANK34, + + ICON_FULLSCREEN, + ICON_SPLITSCREEN, + ICON_RIGHTARROW_THIN, + ICON_DISCLOSURE_TRI_RIGHT, + ICON_DISCLOSURE_TRI_DOWN, + ICON_SCENE_SEPIA, + ICON_SCENE_DEHLT, + ICON_OBJECT, + ICON_MESH, + ICON_CURVE, + ICON_MBALL, + ICON_LATTICE, + ICON_LAMP_DEHLT, + ICON_MATERIAL_DEHLT, + ICON_TEXTURE_DEHLT, + ICON_IPO_DEHLT, + ICON_LIBRARY_DEHLT, + ICON_IMAGE_DEHLT, + ICON_EYEDROPPER, + ICON_WINDOW_WINDOW, + ICON_PANEL_CLOSE, + ICON_BLANK35, + ICON_BLANK36, + ICON_BLANK37, + ICON_BLANK38, + + ICON_BLENDER, + ICON_PACKAGE, + ICON_UGLYPACKAGE, + ICON_MATPLANE, + ICON_MATSPHERE, + ICON_MATCUBE, + ICON_SCENE_HLT, + ICON_OBJECT_HLT, + ICON_MESH_HLT, + ICON_CURVE_HLT, + ICON_MBALL_HLT, + ICON_LATTICE_HLT, + ICON_LAMP_HLT, + ICON_MATERIAL_HLT, + ICON_TEXTURE_HLT, + ICON_IPO_HLT, + ICON_LIBRARY_HLT, + ICON_IMAGE_HLT, + ICON_CONSTRAINT, + ICON_CAMERA_DEHLT, + ICON_ARMATURE_DEHLT, + ICON_SNAP_GEAR, + ICON_SNAP_GEO, + ICON_BLANK41, + ICON_BLANK42, + + ICON_SMOOTHCURVE, + ICON_SPHERECURVE, + ICON_ROOTCURVE, + ICON_SHARPCURVE, + ICON_LINCURVE, + ICON_NOCURVE, + ICON_RNDCURVE, + ICON_PROP_OFF, + ICON_PROP_ON, + ICON_PROP_CON, + ICON_SYNTAX, + ICON_SYNTAX_OFF, + ICON_MONKEY, + ICON_HAIR, + ICON_VIEWMOVE, + ICON_HOME, + ICON_CLIPUV_DEHLT, + ICON_CLIPUV_HLT, + ICON_BLANK2, + ICON_BLANK3, + ICON_VPAINT_COL, + ICON_RESTRICT_SELECT_OFF, + ICON_RESTRICT_SELECT_ON, + ICON_MUTE_IPO_OFF, + ICON_MUTE_IPO_ON, + + ICON_MAN_TRANS, + ICON_MAN_ROT, + ICON_MAN_SCALE, + ICON_MANIPUL, + ICON_BLANK_47, + ICON_MODIFIER, + ICON_MOD_WAVE, + ICON_MOD_BUILD, + ICON_MOD_DECIM, + ICON_MOD_MIRROR, + ICON_MOD_SOFT, + ICON_MOD_SUBSURF, + ICON_SEQ_SEQUENCER, + ICON_SEQ_PREVIEW, + ICON_SEQ_LUMA_WAVEFORM, + ICON_SEQ_CHROMA_SCOPE, + ICON_ROTATE, + ICON_CURSOR, + ICON_ROTATECOLLECTION, + ICON_ROTATECENTER, + ICON_ROTACTIVE, + ICON_RESTRICT_VIEW_OFF, + ICON_RESTRICT_VIEW_ON, + ICON_RESTRICT_RENDER_OFF, + ICON_RESTRICT_RENDER_ON, + + VICON_VIEW3D, + VICON_EDIT, + VICON_EDITMODE_DEHLT, + VICON_EDITMODE_HLT, + VICON_DISCLOSURE_TRI_RIGHT, + VICON_DISCLOSURE_TRI_DOWN, + VICON_MOVE_UP, + VICON_MOVE_DOWN, + VICON_X + +#define BIFICONID_LAST (VICON_X) +#define BIFNICONIDS (BIFICONID_LAST-BIFICONID_FIRST + 1) +} BIFIconID; + +typedef enum { +#define BIFCOLORSHADE_FIRST (COLORSHADE_DARK) + COLORSHADE_DARK, + COLORSHADE_GREY, + COLORSHADE_MEDIUM, + COLORSHADE_HILITE, + COLORSHADE_LIGHT, + COLORSHADE_WHITE +#define BIFCOLORSHADE_LAST (COLORSHADE_WHITE) +#define BIFNCOLORSHADES (BIFCOLORSHADE_LAST-BIFCOLORSHADE_FIRST + 1) +} BIFColorShade; + +typedef enum { +#define BIFCOLORID_FIRST (BUTGREY) + BUTGREY = 0, + BUTGREEN, + BUTBLUE, + BUTSALMON, + MIDGREY, + BUTPURPLE, + BUTYELLOW, + REDALERT, + BUTRUST, + BUTWHITE, + BUTDBLUE, + BUTPINK, + BUTDPINK, + BUTMACTIVE, + + BUTIPO, + BUTAUDIO, + BUTCAMERA, + BUTRANDOM, + BUTEDITOBJECT, + BUTPROPERTY, + BUTSCENE, + BUTMOTION, + BUTMESSAGE, + BUTACTION, + BUTCD, + BUTGAME, + BUTVISIBILITY, + BUTYUCK, + BUTSEASICK, + BUTCHOKE, + BUTIMPERIAL, + + BUTTEXTCOLOR, + BUTTEXTPRESSED, + BUTSBACKGROUND, + + VIEWPORTBACKCOLOR, + VIEWPORTGRIDCOLOR, + VIEWPORTACTIVECOLOR, + VIEWPORTSELECTEDCOLOR, + VIEWPORTUNSELCOLOR, + + EDITVERTSEL, + EDITVERTUNSEL, + EDITEDGESEL, + EDITEDGEUNSEL + +#define BIFCOLORID_LAST (EDITEDGEUNSEL) +#define BIFNCOLORIDS (BIFCOLORID_LAST-BIFCOLORID_FIRST + 1) + +} BIFColorID; + +/* XXX WARNING: this is saved in file, so do not change order! */ +enum { + TH_AUTO, /* for buttons, to signal automatic color assignment */ + +// uibutton colors + TH_BUT_OUTLINE, + TH_BUT_NEUTRAL, + TH_BUT_ACTION, + TH_BUT_SETTING, + TH_BUT_SETTING1, + TH_BUT_SETTING2, + TH_BUT_NUM, + TH_BUT_TEXTFIELD, + TH_BUT_POPUP, + TH_BUT_TEXT, + TH_BUT_TEXT_HI, + TH_MENU_BACK, + TH_MENU_ITEM, + TH_MENU_HILITE, + TH_MENU_TEXT, + TH_MENU_TEXT_HI, + + TH_BUT_DRAWTYPE, + + TH_REDALERT, + TH_CUSTOM, + + TH_BUT_TEXTFIELD_HI, + TH_ICONFILE, + + TH_THEMEUI, +// common colors among spaces + + TH_BACK, + TH_TEXT, + TH_TEXT_HI, + TH_HEADER, + TH_HEADERDESEL, + TH_PANEL, + TH_SHADE1, + TH_SHADE2, + TH_HILITE, + + TH_GRID, + TH_WIRE, + TH_SELECT, + TH_ACTIVE, + TH_GROUP, + TH_GROUP_ACTIVE, + TH_TRANSFORM, + TH_VERTEX, + TH_VERTEX_SELECT, + TH_VERTEX_SIZE, + TH_EDGE, + TH_EDGE_SELECT, + TH_EDGE_SEAM, + TH_EDGE_FACESEL, + TH_FACE, + TH_FACE_SELECT, + TH_NORMAL, + TH_FACE_DOT, + TH_FACEDOT_SIZE, + + TH_SYNTAX_B, + TH_SYNTAX_V, + TH_SYNTAX_C, + TH_SYNTAX_L, + TH_SYNTAX_N, + + TH_BONE_SOLID, + TH_BONE_POSE, + + TH_STRIP, + TH_STRIP_SELECT, + + TH_LAMP, + + TH_NODE, + TH_NODE_IN_OUT, + TH_NODE_OPERATOR, + TH_NODE_CONVERTOR, + TH_NODE_GROUP, + + TH_SEQ_MOVIE, + TH_SEQ_IMAGE, + TH_SEQ_SCENE, + TH_SEQ_AUDIO, + TH_SEQ_EFFECT, + TH_SEQ_PLUGIN, + TH_SEQ_TRANSITION, + TH_SEQ_META, + + TH_EDGE_SHARP, + TH_EDITMESH_ACTIVE, +}; +/* XXX WARNING: previous is saved in file, so do not change order! */ + +/* theme drawtypes */ +#define TH_MINIMAL 0 +#define TH_SHADED 1 +#define TH_ROUNDED 2 +#define TH_OLDSKOOL 3 + +/* specific defines per space should have higher define values */ + +struct bTheme; + +// THE CODERS API FOR THEMES: + +// sets the color +void BIF_ThemeColor(int colorid); + +// sets the color plus alpha +void BIF_ThemeColor4(int colorid); + +// sets color plus offset for shade +void BIF_ThemeColorShade(int colorid, int offset); + +// sets color plus offset for alpha +void BIF_ThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset); + +// sets color, which is blend between two theme colors +void BIF_ThemeColorBlend(int colorid1, int colorid2, float fac); +// same, with shade offset +void BIF_ThemeColorBlendShade(int colorid1, int colorid2, float fac, int offset); + +// returns one value, not scaled +float BIF_GetThemeValuef(int colorid); +int BIF_GetThemeValue(int colorid); + +// get three color values, scaled to 0.0-1.0 range +void BIF_GetThemeColor3fv(int colorid, float *col); + +// get the 3 or 4 byte values +void BIF_GetThemeColor3ubv(int colorid, char *col); +void BIF_GetThemeColor4ubv(int colorid, char *col); + +// get a theme color from specified space type +void BIF_GetThemeColorType4ubv(int colorid, int spacetype, char *col); + +// blends and shades between two color pointers +void BIF_ColorPtrBlendShade3ubv(char *cp1, char *cp2, float fac, int offset); + +// get a 3 byte color, blended and shaded between two other char color pointers +void BIF_GetColorPtrBlendShade3ubv(char *cp1, char *cp2, char *col, float fac, int offset); + + +struct ScrArea; + +// internal (blender) usage only, for init and set active +void BIF_InitTheme(void); +void BIF_SetTheme(struct ScrArea *sa); +void BIF_resources_init (void); +void BIF_resources_free (void); +void BIF_colors_init (void); +void BIF_load_ui_colors (void); + +/* only for buttons in theme editor! */ +char *BIF_ThemeGetColorPtr(struct bTheme *btheme, int spacetype, int colorid); +char *BIF_ThemeColorsPup(int spacetype); + + +void BIF_def_color (BIFColorID colorid, unsigned char r, unsigned char g, unsigned char b); + +#endif /* BIF_ICONS_H */ diff --git a/source/blender/include/BIF_retopo.h b/source/blender/include/BIF_retopo.h new file mode 100644 index 00000000000..5d39923a398 --- /dev/null +++ b/source/blender/include/BIF_retopo.h @@ -0,0 +1,110 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 by Nicholas Bishop + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BIF_RETOPO_H +#define BIF_RETOPO_H + +#include "DNA_vec_types.h" + +/* For bglMats */ +#include "BIF_glutil.h" + +struct EditVert; +struct Mesh; +struct View3D; + +typedef struct RetopoViewData { + bglMats mats; + + char queue_matrix_update; +} RetopoViewData; + +typedef struct RetopoPaintPoint { + struct RetopoPaintPoint *next, *prev; + vec2s loc; + short index; + float co[3]; + struct EditVert *eve; +} RetopoPaintPoint; + +typedef struct RetopoPaintLine { + struct RetopoPaintLine *next, *prev; + ListBase points; + ListBase hitlist; /* RetopoPaintHit */ + RetopoPaintPoint *cyclic; +} RetopoPaintLine; + +typedef struct RetopoPaintSel { + struct RetopoPaintSel *next, *prev; + RetopoPaintLine *line; + char first; +} RetopoPaintSel; + +typedef struct RetopoPaintData { + char in_drag; + short sloc[2]; + + ListBase lines; + ListBase intersections; /* RetopoPaintPoint */ + + short seldist; + RetopoPaintSel nearest; + + struct View3D *paint_v3d; +} RetopoPaintData; + +RetopoPaintData *get_retopo_paint_data(); + +char retopo_mesh_check(); +char retopo_curve_check(); + +void retopo_end_okee(); + +void retopo_free_paint_data(RetopoPaintData *rpd); +void retopo_free_paint(); + +char retopo_mesh_paint_check(); +void retopo_paint_view_update(struct View3D *v3d); +void retopo_force_update(); +void retopo_paint_toggle(void*,void*); +char retopo_paint(const unsigned short event); +void retopo_draw_paint_lines(); +RetopoPaintData *retopo_paint_data_copy(RetopoPaintData *rpd); + +void retopo_toggle(void*,void*); +void retopo_do_vert(struct View3D *v3d, float *v); +void retopo_do_all(); +void retopo_do_all_cb(void *, void *); +void retopo_queue_updates(struct View3D *v3d); + +void retopo_matrix_update(struct View3D *v3d); + +void retopo_free_view_data(struct View3D *v3d); + +#endif diff --git a/source/blender/include/BIF_scrarea.h b/source/blender/include/BIF_scrarea.h new file mode 100644 index 00000000000..c2953078edc --- /dev/null +++ b/source/blender/include/BIF_scrarea.h @@ -0,0 +1,54 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct ScrArea; + + /** + * Finds the first spacedata of @a type within + * the scrarea. + */ +void *scrarea_find_space_of_type(ScrArea *sa, int type); + +int scrarea_get_win_x (struct ScrArea *sa); +int scrarea_get_win_y (struct ScrArea *sa); +int scrarea_get_win_width (struct ScrArea *sa); +int scrarea_get_win_height (struct ScrArea *sa); + +#ifdef __cplusplus +} + +#endif + diff --git a/source/blender/include/BIF_screen.h b/source/blender/include/BIF_screen.h new file mode 100644 index 00000000000..36719af7aa2 --- /dev/null +++ b/source/blender/include/BIF_screen.h @@ -0,0 +1,137 @@ +/* replacement for screen.h */ +/* + * + * Leftovers here are actually editscreen.c thingies + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_SCREEN_H +#define BIF_SCREEN_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/* externs in editscreen.c */ +extern int displaysizex, displaysizey; +extern struct ScrArea *curarea; + +struct View3D; +struct bScreen; +struct ScrArea; +struct ScrVert; +struct ScrEdge; +struct ListBase; + +struct View3D *find_biggest_view3d(void); +struct ScrArea *find_biggest_area_of_type(int spacecode); +struct ScrArea *find_biggest_area(void); + +void scrarea_queue_redraw(struct ScrArea *area); +void scrarea_queue_winredraw(struct ScrArea *area); +void scrarea_queue_headredraw(struct ScrArea *area); + +int blender_test_break(void); + +void duplicate_screen(void); +void init_screen_cursors(void); +void set_timecursor(int nr); +void waitcursor(int val); +void wich_cursor(struct ScrArea *sa); +void setcursor_space(int spacetype, short cur); +void set_g_activearea(struct ScrArea *sa); +void getmouseco_sc(short *mval); +void getmouseco_areawin(short *mval); +void getmouseco_headwin(short *mval); +int qtest(void); +int anyqtest(void); +void areawinset(short win); +void headerbox(struct ScrArea *sa); +void defheaddraw(void); +void defheadchange(void); +unsigned short winqtest(struct ScrArea *sa); +unsigned short headqtest(struct ScrArea *sa); +void winqdelete(struct ScrArea *sa); +void winqclear(struct ScrArea *sa); +void addqueue(short win, unsigned short event, short val); +void addafterqueue(short win, unsigned short event, short val); +void add_readfile_event(char *filename); +short ext_qtest(void); +unsigned short extern_qread(short *val); +unsigned short extern_qread_ext(short *val, char *ascii); + +extern void markdirty_all(void); // also sets redraw event +extern void markdirty_all_back(void); +extern void markdirty_win_back(short winid); + +void screen_swapbuffers(void); +void set_debug_swapbuffers_ovveride(struct bScreen *sc, int mode); +int is_allowed_to_change_screen(struct bScreen *newp); +void splash(void * data, int datasizei, char * string); +void screen_delayed_undo_push(char *name); +void screenmain(void); +void getdisplaysize(void); +void setprefsize(int stax, int stay, int sizx, int sizy, int maximized); +void calc_arearcts(struct ScrArea *sa); +void resize_screen(int x, int y, int w, int h); +struct ScrArea *closest_bigger_area(void); +int mywinopen(int mode, short posx, short posy, short sizex, short sizey); +void setscreen(struct bScreen *sc); +void area_fullscreen(void); +int select_area(int spacetype); +struct bScreen *default_twosplit(void); +void initscreen(void); +void unlink_screen(struct bScreen *sc); +void reset_autosave(void); +int area_is_active_area(struct ScrArea *area); +void draw_area_emboss(struct ScrArea *sa); + +void headerprint(char *str); + +/* ******* handlers ****** */ +void add_screenhandler(struct bScreen *sc, short eventcode, short val); +void rem_screenhandler(struct bScreen *sc, short eventcode); +int do_screenhandlers(struct bScreen *sc); +int has_screenhandler(struct bScreen *sc, short eventcode); + + /***/ + +/* return all layers of all 3d windows in a screen */ +unsigned int screen_view3d_layers(void); + +#ifdef __cplusplus +} +#endif + +#endif /* BIF_SCREEN_H */ + diff --git a/source/blender/include/BIF_space.h b/source/blender/include/BIF_space.h new file mode 100644 index 00000000000..855773b3497 --- /dev/null +++ b/source/blender/include/BIF_space.h @@ -0,0 +1,148 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_SPACE_H +#define BIF_SPACE_H + +struct ListBase; +struct ScrArea; +struct SpaceButs; +struct View2D; +struct BWinEvent; +struct SpaceOops; + +#define REMAKEIPO 1 +#define OOPS_TEST 2 + +#define BUT_HORIZONTAL 1 +#define BUT_VERTICAL 2 + +/* is hardcoded in DNA_space_types.h */ +#define SPACE_MAXHANDLER 8 + +/* view3d handler codes */ +#define VIEW3D_HANDLER_BACKGROUND 1 +#define VIEW3D_HANDLER_PROPERTIES 2 +#define VIEW3D_HANDLER_OBJECT 3 +#define VIEW3D_HANDLER_PREVIEW 4 +#define VIEW3D_HANDLER_MULTIRES 5 + +/* ipo handler codes */ +#define IPO_HANDLER_PROPERTIES 20 + +/* image handler codes */ +#define IMAGE_HANDLER_PROPERTIES 30 +#define IMAGE_HANDLER_PAINT 31 +#define IMAGE_HANDLER_CURVES 32 +#define IMAGE_HANDLER_PREVIEW 33 +#define IMAGE_HANDLER_GAME_PROPERTIES 34 +#define IMAGE_HANDLER_VIEW_PROPERTIES 35 +/*#define IMAGE_HANDLER_TRANSFORM_PROPERTIES 36*/ + +/* action handler codes */ +#define ACTION_HANDLER_PROPERTIES 40 + +/* nla handler codes */ +#define NLA_HANDLER_PROPERTIES 50 + +/* sequence handler codes */ +#define SEQ_HANDLER_PROPERTIES 60 + +/* imasel handler codes */ +#define IMASEL_HANDLER_IMAGE 70 + +/* theme codes */ +#define B_ADD_THEME 3301 +#define B_DEL_THEME 3302 +#define B_NAME_THEME 3303 +#define B_THEMECOL 3304 +#define B_UPDATE_THEME 3305 +#define B_CHANGE_THEME 3306 +#define B_THEME_COPY 3307 +#define B_THEME_PASTE 3308 +#define B_UPDATE_THEME_ICONS 3309 + +#define B_RECALCLIGHT 3310 + + +void scrarea_do_winprefetchdraw (struct ScrArea *sa); +void scrarea_do_windraw (struct ScrArea *sa); +void scrarea_do_winchange (struct ScrArea *sa); +void scrarea_do_winhandle (struct ScrArea *sa, struct BWinEvent *evt); +void scrarea_do_headdraw (struct ScrArea *sa); +void scrarea_do_headchange (struct ScrArea *sa); + +/* space.c */ +extern void add_blockhandler(struct ScrArea *sa, short eventcode, short action); +extern void rem_blockhandler(struct ScrArea *sa, short eventcode); +extern void toggle_blockhandler(struct ScrArea *sa, short eventcode, short action); + +extern void space_set_commmandline_options(void); +extern void allqueue(unsigned short event, short val); +extern void allspace(unsigned short event, short val); +extern void copy_view3d_lock(short val); +extern void drawemptyspace(struct ScrArea *sa, void *spacedata); +extern void drawinfospace(struct ScrArea *sa, void *spacedata); +extern void duplicatespacelist(struct ScrArea *area, struct ListBase *lb1, struct ListBase *lb2); +extern void extern_set_butspace(int fkey, int do_cycle); +extern void force_draw(int header); +extern void force_draw_all(int header); +extern void force_draw_plus(int type, int header); +extern void freespacelist(struct ScrArea *sa); +extern void handle_view3d_around(void); +extern void handle_view3d_lock(void); +extern void init_v2d_oops(struct ScrArea *, struct SpaceOops *); +extern void initipo(struct ScrArea *sa); +extern void newspace(struct ScrArea *sa, int type); +extern void set_rects_butspace(struct SpaceButs *buts); +extern void test_butspace(void); +extern void start_game(void); +extern void select_object_grouped(short nr); +extern void join_menu(void); + +extern void BIF_undo_push(char *str); +extern void BIF_undo(void); +extern void BIF_redo(void); +extern void BIF_undo_menu(void); + +#if 0 +//#ifdef _WIN32 // FULLSCREEN +extern void mainwindow_toggle_fullscreen(int fullscreen); +#endif + +extern void mainwindow_set_filename_to_title(char *title); +extern void mainwindow_raise(void); +extern void mainwindow_make_active(void); +extern void mainwindow_close(void); + +#endif + diff --git a/source/blender/include/BIF_spacetypes.h b/source/blender/include/BIF_spacetypes.h new file mode 100644 index 00000000000..6125cfd5926 --- /dev/null +++ b/source/blender/include/BIF_spacetypes.h @@ -0,0 +1,67 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +struct ScrArea; +struct BWinEvent; + +typedef struct _SpaceType SpaceType; + +typedef void (*SpacePrefetchDrawFP) (struct ScrArea *sa, void *spacedata); +typedef void (*SpaceDrawFP) (struct ScrArea *sa, void *spacedata); +typedef void (*SpaceChangeFP) (struct ScrArea *sa, void *spacedata); +typedef void (*SpaceHandleFP) (struct ScrArea *sa, void *spacedata, struct BWinEvent *evt); + + /***/ + +SpaceType* spacetype_new (char *name); + +void spacetype_set_winfuncs (SpaceType *st, SpacePrefetchDrawFP prefetch, SpaceDrawFP draw, SpaceChangeFP change, SpaceHandleFP handle); + + /***/ + +SpaceType *spaceaction_get_type (void); +SpaceType *spacebuts_get_type (void); +SpaceType *spacefile_get_type (void); +SpaceType *spaceimage_get_type (void); +SpaceType *spaceimasel_get_type (void); +SpaceType *spaceinfo_get_type (void); +SpaceType *spaceipo_get_type (void); +SpaceType *spacenla_get_type (void); +SpaceType *spaceoops_get_type (void); +SpaceType *spaceseq_get_type (void); +SpaceType *spacesound_get_type (void); +SpaceType *spacetext_get_type (void); +SpaceType *spacescript_get_type (void); +SpaceType *spaceview3d_get_type (void); +SpaceType *spacetime_get_type (void); +SpaceType *spacenode_get_type (void); + diff --git a/source/blender/include/BIF_tbcallback.h b/source/blender/include/BIF_tbcallback.h new file mode 100644 index 00000000000..98aebf5c863 --- /dev/null +++ b/source/blender/include/BIF_tbcallback.h @@ -0,0 +1,42 @@ +/* $Id$ +*/ +/* + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK *****/ + +/* defines callback structure for toolbox menu */ +typedef struct _TBcallback { + char *desc; + char *key; + void (*cb)(int v); /* callback function takes value */ + int val; +} TBcallback; + +typedef TBcallback * (*Tbox_callbackfunc)(int l, int x); +void tboxSetCallback(Tbox_callbackfunc f); + diff --git a/source/blender/include/BIF_toets.h b/source/blender/include/BIF_toets.h new file mode 100644 index 00000000000..f5a435d3d50 --- /dev/null +++ b/source/blender/include/BIF_toets.h @@ -0,0 +1,41 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_TOETS_H +#define BIF_TOETS_H + +int blenderqread(unsigned short event, short val); +void persptoetsen(unsigned short event); /* dutch rules man */ +int untitled(char *name); + +#endif + diff --git a/source/blender/include/BIF_toolbox.h b/source/blender/include/BIF_toolbox.h new file mode 100644 index 00000000000..72867cbfa05 --- /dev/null +++ b/source/blender/include/BIF_toolbox.h @@ -0,0 +1,68 @@ +/* toolbox (SPACEKEY) related + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_TOOLBOX_H +#define BIF_TOOLBOX_H + +/* toolbox.c */ +void asciitoraw (int ch, short unsigned int *event, short unsigned int *qual); + +void toolbox_n(void); +void toolbox_n_add(void); +void reset_toolbox(void); + +void notice (char *str, ...); +void error (char *fmt, ...); + +void error_libdata (void); + +int saveover (char *filename); +int okee (char *fmt, ...); + +short button (short *var, short min, short max, char *str); +short fbutton (float *var, float min, float max, float a1, float a2, char *str); +short sbutton (char *var, float min, float max, char *str); /* __NLA */ + +int movetolayer_buts (unsigned int *lay, char *title); +int movetolayer_short_buts (short *lay, char *title); + +void draw_numbuts_tip (char *str, int x1, int y1, int x2, int y2); +int do_clever_numbuts (char *name, int tot, int winevent); +void clever_numbuts_buts(void); +void add_numbut (int nr, int type, char *str, float min, float max, void *poin, char *tip); +void clever_numbuts (void); +void replace_names_but (void); + +void BIF_screendump(int fscreen); +void write_screendump(char *name); + +#endif diff --git a/source/blender/include/BIF_transform.h b/source/blender/include/BIF_transform.h new file mode 100644 index 00000000000..26900b06c52 --- /dev/null +++ b/source/blender/include/BIF_transform.h @@ -0,0 +1,108 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_TRANSFORM_H +#define BIF_TRANSFORM_H + +/* ******************** Macros & Prototypes *********************** */ + +/* MODE AND NUMINPUT FLAGS */ +#define TFM_INIT -1 +#define TFM_DUMMY 0 +#define TFM_TRANSLATION 1 +#define TFM_ROTATION 2 +#define TFM_RESIZE 3 +#define TFM_TOSPHERE 4 +#define TFM_SHEAR 5 +#define TFM_WARP 7 +#define TFM_SHRINKFATTEN 8 +#define TFM_TILT 9 +#define TFM_LAMP_ENERGY 10 +#define TFM_TRACKBALL 11 +#define TFM_PUSHPULL 12 +#define TFM_CREASE 13 +#define TFM_MIRROR 14 +#define TFM_BONESIZE 15 +#define TFM_BONE_ENVELOPE 16 +#define TFM_CURVE_SHRINKFATTEN 17 +#define TFM_BONE_ROLL 18 +#define TFM_TIME_TRANSLATE 19 +#define TFM_TIME_SLIDE 20 +#define TFM_TIME_SCALE 21 +#define TFM_TIME_EXTEND 22 + +/* TRANSFORM CONTEXTS */ +#define CTX_NONE 0 +#define CTX_TEXTURE 1 +#define CTX_EDGE 2 +#define CTX_NO_PET 4 +#define CTX_TWEAK 8 + +void initTransform(int mode, int context); +void Transform(void); +void Mirror(short mode); + +/* Standalone call to get the transformation center corresponding to the current situation + * returns 1 if successful, 0 otherwise (usually means there's no selection) + * (if 0 is returns, *vec is unmodified) + * */ +int calculateTransformCenter(int centerMode, float *vec); + +struct TransInfo; +struct ScrArea; + +struct TransInfo * BIF_GetTransInfo(void); +void BIF_setSingleAxisConstraint(float vec[3], char *text); +void BIF_setDualAxisConstraint(float vec1[3], float vec2[3], char *text); +void BIF_setLocalAxisConstraint(char axis, char *text); +void BIF_setLocalLockConstraint(char axis, char *text); + +/* Drawing callbacks */ +void BIF_drawConstraint(void); +void BIF_drawPropCircle(void); +void BIF_drawSnap(void); + +void BIF_getPropCenter(float *center); + +void BIF_TransformSetUndo(char *str); + +void BIF_selectOrientation(void); + +/* view3d manipulators */ +void initManipulator(int mode); +void ManipulatorTransform(); + +int BIF_do_manipulator(struct ScrArea *sa); +void BIF_draw_manipulator(struct ScrArea *sa); + +#endif + diff --git a/source/blender/include/BIF_usiblender.h b/source/blender/include/BIF_usiblender.h new file mode 100644 index 00000000000..e77d1e98487 --- /dev/null +++ b/source/blender/include/BIF_usiblender.h @@ -0,0 +1,54 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_USIBLENDER_H +#define BIF_USIBLENDER_H + +typedef struct RecentFile { + struct RecentFile *next, *prev; + char *filename; +} RecentFile; + +void exit_usiblender(void); + +void BIF_init(void); + +void BIF_read_file(char *name); +int BIF_read_homefile(int from_memory, int do_undo); +void BIF_read_autosavefile(void); + +void BIF_write_file(char *target); +void BIF_write_homefile(void); +void BIF_write_autosave(void); + +#endif + diff --git a/source/blender/include/BIF_verse.h b/source/blender/include/BIF_verse.h new file mode 100644 index 00000000000..d491316662d --- /dev/null +++ b/source/blender/include/BIF_verse.h @@ -0,0 +1,142 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Contributor(s): Jiri Hnidek. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef WITH_VERSE + +#ifndef BIF_VERSE_H +#define BIF_VERSE_H + +#include "BKE_verse.h" +#include "DNA_meshdata_types.h" + +struct Object; + +struct EditMesh; +struct EditVert; +struct EditFace; +struct Mesh; +struct MVert; +struct Mface; + +/* verse_object.c */ +void unsubscribe_from_obj_node(struct VNode *vnode); +void unsubscribe_from_geom_node(struct VNode *vnode); +void unsubscribe_from_bitmap_node(struct VNode *vnode); + +void test_and_send_idbutton_cb(void *obj, void *ob_name); + +struct Object *create_object_from_verse_node(struct VNode *vnode); + +void b_verse_pop_node(struct VNode *vnode); +void b_verse_unsubscribe(VNode *vnode); +void b_verse_push_object(struct VerseSession *session, struct Object *ob); +void b_verse_delete_object(struct Object *ob); +void b_verse_ms_get(void); + +void post_transform_pos(struct VNode *vnode); +void post_transform_rot(struct VNode *vnode); +void post_transform_scale(struct VNode *vnode); + +/*void post_transform(struct VNode *vnode);*/ +void post_link_set(struct VLink *vlink); +void post_link_destroy(struct VLink *vlink); +void post_object_free_constraint(struct VNode *vnode); + +void b_verse_send_transformation(struct Object *ob); + +/* verse_mesh.c */ +void b_verse_send_vertex_delete(struct EditVert *eve); +void send_versevert_pos(struct VerseVert *vvert); + +void b_verse_send_face_delete(struct EditFace *efa); + +void sync_all_versefaces_with_editfaces(struct VNode *vnode); +void sync_all_verseverts_with_editverts(struct VNode *vnode); + +void createVerseVert(struct EditVert *ev); +void createVerseFace(struct EditFace *efa); + +void b_verse_duplicate_object(struct VerseSession *session, struct Object *ob, struct Object *n_ob); +struct VNode *create_geom_vnode_from_geom_vnode(struct VNode *vnode); +struct VNode *create_geom_vnode_data_from_editmesh(struct VerseSession *session, struct EditMesh *em); +struct VNode *create_geom_vnode_data_from_mesh(struct VerseSession *session, struct Mesh *me); + +void destroy_unused_geometry(struct VNode *vnode); +void destroy_binding_between_versemesh_and_editmesh(struct VNode *vnode); + +void destroy_versemesh(struct VNode *vnode); + +void unsubscribe_from_geom_node(struct VNode *vnode); + +void create_edit_mesh_from_geom_node(struct VNode *vnode); +struct Mesh *create_mesh_from_geom_node(struct VNode *vnode); +void create_meshdata_from_geom_node(struct Mesh *me, struct VNode *vnode); + +/* geometry post callback functions */ +void post_layer_create(struct VLayer *vlayer); +void post_layer_destroy(struct VLayer *vlayer); + +void post_vertex_create(struct VerseVert *vvert); +void post_vertex_set_xyz(struct VerseVert *vvert); +void post_vertex_delete(struct VerseVert *vvert); +void post_vertex_free_constraint(struct VerseVert *vvert); + +void post_polygon_set_uint8(struct VerseFace *vface); +void post_polygon_create(struct VerseFace *vface); +void post_polygon_set_corner(struct VerseFace *vface); +void post_polygon_delete(struct VerseFace *vface); +void post_polygon_free_constraint(struct VerseFace *vface); + +void post_geometry_free_constraint(struct VNode *vnode); + +/* verse_common.c */ +struct VerseSession *session_menu(void); +char *verse_client_name(void); + +void post_tag_change(struct VTag *vtag); +void post_taggroup_create(struct VTagGroup *vtaggroup); + +void post_node_create(struct VNode *vnode); +void post_node_destroy(struct VNode *vnode); +void post_node_name_set(struct VNode *vnode); + +void post_connect_accept(struct VerseSession *session); +void post_connect_terminated(struct VerseSession *session); +void post_connect_update(struct VerseSession *session); +void post_server_add(void); + +/* verse_image.c */ + +void sync_blender_image_with_verse_bitmap_node(struct VNode *vnode); +void post_bitmap_dimension_set(struct VNode *vnode); +void post_bitmap_layer_create(struct VBitmapLayer *vblayer); +void post_bitmap_layer_destroy(struct VBitmapLayer *vblayer); +void post_bitmap_tile_set(struct VBitmapLayer *vblayer, unsigned int xs, unsigned int ys); + +#endif + +#endif diff --git a/source/blender/include/BIF_writeavicodec.h b/source/blender/include/BIF_writeavicodec.h new file mode 100644 index 00000000000..5b8ccdce4e2 --- /dev/null +++ b/source/blender/include/BIF_writeavicodec.h @@ -0,0 +1,44 @@ +/** + * Functions for writing windows avi-format files. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + */ + +#ifdef _WIN32 + +void start_avi_codec(RenderData *rd,int rectx, int recty ); +void append_avi_codec(int frame,int *pixels,int rectx, int recty); +void end_avi_codec(void); +int get_avicodec_settings(void); + +#endif + diff --git a/source/blender/include/BIF_writeimage.h b/source/blender/include/BIF_writeimage.h new file mode 100644 index 00000000000..70978a033c2 --- /dev/null +++ b/source/blender/include/BIF_writeimage.h @@ -0,0 +1,45 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_WRITEIMAGE_H +#define BIF_WRITEIMAGE_H + +struct ImBuf; +struct EnvMap; + +void BIF_save_rendered_image(char *name); +void BIF_save_rendered_image_fs(void); +void BIF_save_envmap(struct EnvMap *env, char *str); +void save_image_filesel_str(char *str); + +#endif + diff --git a/source/blender/include/BIF_writemovie.h b/source/blender/include/BIF_writemovie.h new file mode 100644 index 00000000000..8dab1d4e7f8 --- /dev/null +++ b/source/blender/include/BIF_writemovie.h @@ -0,0 +1,41 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_WRITEMOVIE_H +#define BIF_WRITEMOVIE_H + +void start_movie(void); +void append_movie(int fnum); +void end_movie(void); + +#endif + diff --git a/source/blender/include/BPI_script.h b/source/blender/include/BPI_script.h new file mode 100644 index 00000000000..80ac8b46900 --- /dev/null +++ b/source/blender/include/BPI_script.h @@ -0,0 +1,71 @@ +/** + * include/BPI_script.h (jan-2004 ianwill) + * + * $Id$ + * + * Header for BPython's script structure. BPI: Blender Python external include + * file. + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BPI_SCRIPT_H +#define BPI_SCRIPT_H + +//#include "DNA_listBase.h" +#include "DNA_ID.h" + +typedef struct Script { + ID id; + + void *py_draw; + void *py_event; + void *py_button; + void *py_browsercallback; + void *py_globaldict; + + int flags, lastspace; + +} Script; + +/* Note: a script that registers callbacks in the script->py_* pointers + * above (or calls the file or image selectors) needs to keep its global + * dictionary until Draw.Exit() is called and the callbacks removed. + * Unsetting SCRIPT_RUNNING means the interpreter reached the end of the + * script and returned control to Blender, but we can't get rid of its + * namespace (global dictionary) while SCRIPT_GUI or SCRIPT_FILESEL is set, + * because of the callbacks. The flags and the script name are saved in + * each running script's global dictionary, under '__script__'. */ + +/* Flags */ +#define SCRIPT_RUNNING 0x01 +#define SCRIPT_GUI 0x02 +#define SCRIPT_FILESEL 0x04 + +#endif /* BPI_SCRIPT_H */ diff --git a/source/blender/include/BSE_drawimasel.h b/source/blender/include/BSE_drawimasel.h new file mode 100644 index 00000000000..6c68ba79bb9 --- /dev/null +++ b/source/blender/include/BSE_drawimasel.h @@ -0,0 +1,60 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BSE_DRAWIMASEL_H +#define BSE_DRAWIMASEL_H + + +/* button events */ +#define B_FS_FILENAME 1 +#define B_FS_DIRNAME 2 +#define B_FS_DIR_MENU 3 +#define B_FS_PARDIR 4 +#define B_FS_LOAD 5 +#define B_FS_CANCEL 6 +#define B_FS_LIBNAME 7 +#define B_FS_BOOKMARK 8 + +/* ui geometry */ +#define IMASEL_BUTTONS_HEIGHT 60 +#define TILE_BORDER_X 8 +#define TILE_BORDER_Y 8 + +struct ScrArea; +struct SpaceImaSel; + +void drawimaselspace(struct ScrArea *sa, void *spacedata); +void calc_imasel_rcts(SpaceImaSel *simasel, int winx, int winy); +void do_imasel_buttonevents(short event, SpaceImaSel *simasel); + +#endif /* BSE_DRAWIMASEL_H */ + diff --git a/source/blender/include/BSE_drawipo.h b/source/blender/include/BSE_drawipo.h new file mode 100644 index 00000000000..07f116d8d67 --- /dev/null +++ b/source/blender/include/BSE_drawipo.h @@ -0,0 +1,76 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BSE_DRAWIPO_H +#define BSE_DRAWIPO_H + +#define IN_2D_VERT_SCROLL(A) (BLI_in_rcti(&G.v2d->vert, A[0], A[1])) +#define IN_2D_HORIZ_SCROLL(A) (BLI_in_rcti(&G.v2d->hor, A[0], A[1])) + +#define SELECT_REPLACE 1 +#define SELECT_ADD 2 +#define SELECT_SUBTRACT 4 +#define SELECT_INVERT 16 + +struct ScrArea; +struct EditIpo; +struct View2D; +struct rctf; + +void calc_ipogrid(void); +void draw_ipogrid(void); + +void areamouseco_to_ipoco (struct View2D *v2d, short *mval, float *x, float *y); +void ipoco_to_areaco (struct View2D *v2d, float *vec, short *mval); +void ipoco_to_areaco_noclip (struct View2D *v2d, float *vec, short *mval); + +void view2d_do_locks (struct ScrArea *cursa, int flag); +void view2d_zoom (struct View2D *v2d, float factor, int winx, int winy); +void test_view2d (struct View2D *v2d, int winx, int winy); +void calc_scrollrcts (struct ScrArea *sa, struct View2D *v2d, int winx, int winy); + +int in_ipo_buttons(void); +void draw_view2d_numbers_horiz(int drawframes); +void drawscroll(int disptype); +void drawipospace(struct ScrArea *sa, void *spacedata); + +void center_currframe(void); +void scroll_ipobuts(void); +int view2dzoom(unsigned short event); +int view2dmove(unsigned short event); +void view2dborder(void); + +struct EditIpo *select_proj_ipo(struct rctf *rectf, int event); + + +#endif /* BSE_DRAWIPO_H */ + diff --git a/source/blender/include/BSE_drawnla.h b/source/blender/include/BSE_drawnla.h new file mode 100644 index 00000000000..923d9a3f0df --- /dev/null +++ b/source/blender/include/BSE_drawnla.h @@ -0,0 +1,52 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BSE_DRAWNLA_H +#define BSE_DRAWNLA_H + +struct ScrArea; +struct Base; +struct gla2DDrawInfo; +struct Object; + +void drawnlaspace(struct ScrArea *sa, void *spacedata); +void do_nlabuts(unsigned short event); + +int count_nla_levels(void); +int nla_filter (struct Base* base); + + /* changes the gla2d system to map the strip transform */ +void map_active_strip(struct gla2DDrawInfo *di, struct Object *ob, int restore); + + +#endif /* BSE_DRAWNLA */ + diff --git a/source/blender/include/BSE_drawoops.h b/source/blender/include/BSE_drawoops.h new file mode 100644 index 00000000000..43e1dee5943 --- /dev/null +++ b/source/blender/include/BSE_drawoops.h @@ -0,0 +1,50 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BSE_DRAWOOPS_H +#define BSE_DRAWOOPS_H + +struct ScrArea; +struct Oops; + +void boundbox_oops(short sel); +void give_oopslink_line(struct Oops *oops, struct OopsLink *ol, float *v1, float *v2); +void draw_oopslink(struct Oops *oops); +void draw_icon_oops(float *co, short type); +void mysbox(float x1, float y1, float x2, float y2); +unsigned int give_oops_color(short type, short sel, unsigned int *border); +void calc_oopstext(char *str, float *v1); +void draw_oops(struct Oops *oops); +void drawoopsspace(struct ScrArea *sa, void *spacedata); + +#endif /* BSE_DRAWOOPS */ + diff --git a/source/blender/include/BSE_drawview.h b/source/blender/include/BSE_drawview.h new file mode 100644 index 00000000000..9c577746da9 --- /dev/null +++ b/source/blender/include/BSE_drawview.h @@ -0,0 +1,88 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BSE_DRAWVIEW_H +#define BSE_DRAWVIEW_H + +struct Object; +struct BGpic; +struct rctf; +struct ScrArea; +struct ImBuf; + +void default_gl_light(void); +void init_gl_stuff(void); +void circf(float x, float y, float rad); +void circ(float x, float y, float rad); + +void do_viewbuts(unsigned short event); + +/* View3DAfter->type */ +#define V3D_XRAY 1 +#define V3D_TRANSP 2 +void add_view3d_after(struct View3D *v3d, struct Base *base, int type); + +void backdrawview3d(int test); +void check_backbuf(void); +unsigned int sample_backbuf(int x, int y); +struct ImBuf *read_backbuf(short xmin, short ymin, short xmax, short ymax); +unsigned int sample_backbuf_rect(short mval[2], int size, unsigned int min, unsigned int max, int *dist, short strict, unsigned int (*indextest)(unsigned int index)); + +void drawview3dspace(struct ScrArea *sa, void *spacedata); +void drawview3d_render(struct View3D *v3d, int winx, int winy); + +int update_time(void); +void calc_viewborder(struct View3D *v3d, struct rctf *viewborder_r); +void view3d_set_1_to_1_viewborder(struct View3D *v3d); + +int view3d_test_clipping(struct View3D *v3d, float *vec); +void view3d_set_clipping(struct View3D *v3d); +void view3d_clr_clipping(void); + +void sumo_callback(void *obp); +void init_anim_sumo(void); +void update_anim_sumo(void); +void end_anim_sumo(void); + +void inner_play_anim_loop(int init, int mode); +int play_anim(int mode); + +void make_axis_color(char *col, char *col2, char axis); + +/* SMOOTHVIEW */ +void smooth_view(struct View3D *v3d, float *ofs, float *quat, float *dist, float *lens); +void smooth_view_to_camera(struct View3D *v3d); +void view_settings_from_ob(struct Object *ob, float *ofs, float *quat, float *dist, float *lens); +void object_view_settings(struct Object *ob, float *lens, float *clipsta, float *clipend); + +#endif /* BSE_DRAWVIEW_H */ + diff --git a/source/blender/include/BSE_edit.h b/source/blender/include/BSE_edit.h new file mode 100644 index 00000000000..048d4d012b2 --- /dev/null +++ b/source/blender/include/BSE_edit.h @@ -0,0 +1,55 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BSE_EDIT_H +#define BSE_EDIT_H + +struct Object; +struct rcti; + +int get_border(struct rcti *rect, short col); +void countall(void); +void snapmenu(void); +void mergemenu(void); +void delete_context_selected(void); +void duplicate_context_selected(void); +void toggle_shading(void); +int minmax_verts(float *min, float *max); + +void snap_sel_to_grid(void); +void snap_sel_to_curs(void); +void snap_curs_to_grid(void); +void snap_curs_to_sel(void); +void snap_to_center(void); + +#endif /* BSE_EDIT_H */ + diff --git a/source/blender/include/BSE_editaction_types.h b/source/blender/include/BSE_editaction_types.h new file mode 100644 index 00000000000..48f0bc39ffc --- /dev/null +++ b/source/blender/include/BSE_editaction_types.h @@ -0,0 +1,77 @@ +/** + * $Id: BIF_editaction.h 10519 2007-04-13 11:15:08Z aligorith $ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): 2007, Joshua Leung (major Action Editor recode) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BIF_EDITACTION_TYPES_H +#define BIF_EDITACTION_TYPES_H + +/******************************************************* */ +/* FILTERED ACTION DATA - TYPES */ + +/* types of keyframe data in ActListElem */ +#define ALE_NONE 0 +#define ALE_IPO 1 +#define ALE_ICU 2 + +/* This struct defines a structure used for quick access */ +typedef struct bActListElem { + struct bActListElem *next, *prev; + + void *data; /* source data this elem represents */ + int type; /* one of the ACTTYPE_* values */ + int flag; /* copy of elem's flags for quick access */ + int index; /* copy of adrcode where applicable */ + + void *key_data; /* motion data - ipo or ipo-curve */ + short datatype; /* type of motion data to expect */ + + void *owner; /* will either be an action channel or fake ipo-channel (for keys) */ + short ownertype; /* type of owner */ +} bActListElem; + +/******************************************************* */ +/* FILTER ACTION DATA - METHODS/TYPES */ + +/* filtering flags - under what circumstances should a channel be added */ +#define ACTFILTER_VISIBLE 0x001 /* should channels be visible */ +#define ACTFILTER_SEL 0x002 /* should channels be selected */ +#define ACTFILTER_FOREDIT 0x004 /* does editable status matter */ +#define ACTFILTER_CHANNELS 0x008 /* do we only care that it is a channel */ +#define ACTFILTER_IPOKEYS 0x010 /* only channels referencing ipo's */ +#define ACTFILTER_ONLYICU 0x020 /* only reference ipo-curves */ +#define ACTFILTER_FORDRAWING 0x040 /* make list for interface drawing */ + +/* Action Editor - Main Data types */ +#define ACTCONT_NONE 0 +#define ACTCONT_ACTION 1 +#define ACTCONT_SHAPEKEY 2 + +#endif diff --git a/source/blender/include/BSE_editipo.h b/source/blender/include/BSE_editipo.h new file mode 100644 index 00000000000..37cae858656 --- /dev/null +++ b/source/blender/include/BSE_editipo.h @@ -0,0 +1,178 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BSE_EDITIPO_H +#define BSE_EDITIPO_H + +struct TransVert; +struct IpoCurve; +struct BezTriple; +struct Ipo; +struct EditIpo; +struct ID; +struct ListBase; +struct Object; +struct IpoKey; +struct TransOb; +struct Tex; +struct TransInfo; + +void remake_object_ipos(struct Object *ob); +char *getname_ac_ei(int nr); +char *getname_co_ei(int nr); +char *getname_ob_ei(int nr, int colipo); +char *getname_mtex_ei(int nr); +char *getname_tex_ei(int nr); +char *getname_mat_ei(int nr); +char *getname_world_ei(int nr); +char *getname_seq_ei(int nr); +char *getname_cu_ei(int nr); +char *getname_la_ei(int nr); +char *getname_cam_ei(int nr); +char *getname_snd_ei(int nr); +char *getname_fluidsim_ei(int nr); + +char *getname_ipocurve(struct IpoCurve *icu, struct Object *ob); +int geticon_ipo_blocktype(short blocktype); + +struct EditIpo *get_active_editipo(void); + +void boundbox_ipocurve(struct IpoCurve *icu, int selectedonly); +void boundbox_ipo(struct Ipo *ipo, struct rctf *bb, int selectedonly); +void editipo_changed(struct SpaceIpo *si, int doredraw); +void scale_editipo(void); + +unsigned int ipo_rainbow(int cur, int tot); + +void test_editipo(int doit); +void get_status_editipo(void); +void update_editipo_flags(void); +void set_editflag_editipo(void); +void ipo_toggle_showkey(void); +void swap_selectall_editipo(void); +void swap_visible_editipo(void); +void deselectall_editipo(void); + +void move_to_frame(void); +void do_ipowin_buts(short event); +void do_ipo_selectbuttons(void); + + +/* gets ipo curve, creates if needed */ +struct IpoCurve *verify_ipocurve(struct ID *, short, char *, char *, int); +struct Ipo *verify_ipo(struct ID *, short, char *, char *); +int texchannel_to_adrcode(int channel); + +int insert_bezt_icu(struct IpoCurve *icu, struct BezTriple *bezt); +void insert_vert_icu(struct IpoCurve *icu, float x, float y, short fast); +void add_vert_ipo(void); + +void add_duplicate_editipo(void); +void remove_doubles_ipo(void); +void clean_ipo(void); +void clean_ipo_curve(struct IpoCurve *icu); +void smooth_ipo(void); +void join_ipo_menu(void); +void join_ipo(int mode); +void ipo_snap_menu(void); +void ipo_snap(short event); +void ipo_mirror_menu(void); +void ipo_mirror(short event); +void mouse_select_ipo(void); +void sethandles_ipo(int code); +void select_ipo_bezier_keys(struct Ipo *ipo, int selectmode); +void select_icu_bezier_keys(struct IpoCurve *icu, int selectmode); +void set_ipotype(void); +void borderselect_ipo(void); +void del_ipo(int need_check); +void del_ipoCurve ( struct IpoCurve * icu ); +void free_ipocopybuf(void); +void copy_editipo(void); +void paste_editipo(void); + +void set_exprap_ipo(int mode); + +void set_speed_editipo(float speed); +void insertkey(ID *id, int blocktype, char *actname, char *constname, int adrcode, short fast); +void insertkey_smarter(ID *id, int blocktype, char *actname, char *constname, int adrcode); +void insertkey_editipo(void); +void common_insertkey(void); +void free_ipokey(struct ListBase *lb); +void add_to_ipokey(struct ListBase *lb, struct BezTriple *bezt, int nr, int len); +void make_ipokey(void); +void make_ipokey_spec(struct ListBase *lb, struct Ipo *ipo); +void make_ipokey_transform(struct Object *ob, struct ListBase *lb, int sel); +void update_ipokey_val(void); +void set_tob_old(float *old, float *poin); +void set_ipo_pointers_transob(struct IpoKey *ik, struct TransOb *tob); +void nextkey(struct ListBase *elems, int dir); +void movekey_ipo(int dir); +void movekey_obipo(int dir); +void nextkey_ipo(int dir); +void nextkey_obipo(int dir); +void filter_sampledata(float *data, int sfra, int efra); +void sampledata_to_ipocurve(float *data, int sfra, int efra, struct IpoCurve *icu); +void ipo_record(void); + +void make_ipo_transdata(struct TransInfo *t); +void remake_ipo_transdata(struct TransInfo *t); +void transform_ipo(int mode); + +void actstrip_map_ipo_keys(struct Object *ob, struct Ipo *ipo, short restore, short only_keys); + +void sethandles_ipo_keys(struct Ipo *ipo, int code); +void snap_ipo_keys(struct Ipo *ipo, short snaptype); +void mirror_ipo_keys(struct Ipo *ipo, short mirror_mode); +void setipotype_ipo(struct Ipo *ipo, int code); +void set_ipo_key_selection(struct Ipo *ipo, int sel); +int is_ipo_key_selected(struct Ipo *ipo); +void delete_icu_key(struct IpoCurve *icu, int index); +void delete_ipo_keys(struct Ipo *ipo); +int fullselect_ipo_keys(struct Ipo *ipo); +int add_trans_ipo_keys(struct Ipo *ipo, struct TransVert *tv, int tvtot); +void duplicate_ipo_keys(struct Ipo *ipo); +void borderselect_ipo_key(struct Ipo *ipo, float xmin, float xmax, int val); +void borderselect_icu_key(struct IpoCurve *icu, float xmin, float xmax, + int (*select_function)(struct BezTriple *)); +int insertmatrixkey(ID *id, int blocktype, char *actname, char *constname, int adrcode); +void insertfloatkey(ID *id, int blocktype, char *actname, char *constname, int adrcode, float floatkey); +void select_ipo_key(struct Ipo *ipo, float selx, int sel); +void select_icu_key(struct IpoCurve *icu, float selx, int selectmode); +void setexprap_ipoloop(struct Ipo *ipo, int code); + +/* callbacks */ +int select_bezier_add(struct BezTriple *bezt); +int select_bezier_subtract(struct BezTriple *bezt); +int select_bezier_invert(struct BezTriple *bezt); + +#endif /* BSE_EDITIPO_H */ + diff --git a/source/blender/include/BSE_editipo_types.h b/source/blender/include/BSE_editipo_types.h new file mode 100644 index 00000000000..5076b36083a --- /dev/null +++ b/source/blender/include/BSE_editipo_types.h @@ -0,0 +1,53 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BSE_EDITIPO_TYPES_H +#define BSE_EDITIPO_TYPES_H + +struct BezTriple; + +typedef struct IpoKey { + struct IpoKey *next, *prev; + short flag, rt; + float val; + struct BezTriple **data; +} IpoKey; + +typedef struct EditIpo { + char name[32]; // same length as keyblock->name + IpoCurve *icu; + short adrcode, flag; + short disptype, rt; + unsigned int col; +} EditIpo; + +#endif /* BSE_EDITIPO_TYPES_H */ diff --git a/source/blender/include/BSE_editnla_types.h b/source/blender/include/BSE_editnla_types.h new file mode 100644 index 00000000000..434e87fbbc4 --- /dev/null +++ b/source/blender/include/BSE_editnla_types.h @@ -0,0 +1,41 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BSE_EDITNLA_TYPES_H +#define BSE_EDITNLA_TYPES_H + +#define NLAWIDTH 196 +#define NLACHANNELHEIGHT 16 +#define NLACHANNELSKIP 1 + +#endif /* BSE_EDITNLA_TYPES_H */ + diff --git a/source/blender/include/BSE_filesel.h b/source/blender/include/BSE_filesel.h new file mode 100644 index 00000000000..a41eea32040 --- /dev/null +++ b/source/blender/include/BSE_filesel.h @@ -0,0 +1,66 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + */ + +#ifndef BSE_FILESEL_H +#define BSE_FILESEL_H + +struct SpaceFile; +struct direntry; +struct ID; +struct ScrArea; +struct BWinEvent; + +void filesel_statistics(struct SpaceFile *sfile, int *totfile, int *selfile, float *totlen, float *sellen); +void test_flags_file(struct SpaceFile *sfile); +void sort_filelist(struct SpaceFile *sfile); +void read_dir(struct SpaceFile *sfile); +void freefilelist(struct SpaceFile *sfile); +void parent(struct SpaceFile *sfile); +void swapselect_file(struct SpaceFile *sfile); +void drawfilespace(struct ScrArea *sa, void *spacedata); + +void activate_fileselect(int type, char *title, char *file, void (*func)(char *)); +void activate_fileselect_menu(int type, char *title, char *file, char *pupmenu, short *menup, void (*func)(char *)); +void activate_fileselect_args(int type, char *title, char *file, void (*func)(char *, void *, void *), void *arg1, void *arg2); + +void activate_databrowse(struct ID *id, int idcode, int fromcode, int retval, short *menup, void (*func)(unsigned short)); +void activate_databrowse_args(struct ID *id, int idcode, int fromcode, short *menup, void (*func)(char *, void *, void *), void *arg1, void *arg2); + +void filesel_prevspace(void); +void free_filesel_spec(char *dir); +void winqreadfilespace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt); +void main_to_filelist(struct SpaceFile *sfile); + +void clever_numbuts_filesel(void); +#endif + diff --git a/source/blender/include/BSE_headerbuttons.h b/source/blender/include/BSE_headerbuttons.h new file mode 100644 index 00000000000..112517dbe7f --- /dev/null +++ b/source/blender/include/BSE_headerbuttons.h @@ -0,0 +1,158 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BSE_HEADERBUTTONS_H +#define BSE_HEADERBUTTONS_H + +struct uiBlock; +struct ScrArea; +struct ID; +struct SpaceIpo; +struct Ipo; + +/* these used to be in blender/src/headerbuttons.c: */ +#define XIC 20 +#define YIC 20 + +int std_libbuttons(struct uiBlock *block, + short xco, short yco, int pin, short *pinpoin, + int browse, short id_code, short special, struct ID *id, struct ID *parid, + short *menupoin, int users, + int lib, int del, int autobut, int keepbut); + +char *windowtype_pup(void); + +int GetButStringLength(char *str); +void load_space_sound(char *str); +void load_sound_buttons(char *str); +/* end of declarations moved from old headerbuttons.c */ + +void update_for_newframe_muted(void); +void update_for_newframe_nodraw(int nosound); +void free_matcopybuf(void); +void clear_matcopybuf(void); +void write_vrml_fs(void); +void write_dxf_fs(void); +void write_stl_fs(void); +int buttons_do_unpack(void); +struct Scene *copy_scene(struct Scene *sce, int level); + +void buttons_active_id(struct ID **id, struct ID **idfrom); + +int start_progress_bar(void); +void end_progress_bar(void); +int progress_bar(float done, char *busy_info); + +void update_for_newframe(void); + +void action_buttons(void); +void buts_buttons(void); +void file_buttons(void); +void image_buttons(void); +void imasel_buttons(void); +void info_buttons(void); +void ipo_buttons(void); +void nla_buttons(void); +void oops_buttons(void); +void seq_buttons(void); +void sound_buttons(void); +void text_buttons(void); +void script_buttons(void); +void view3d_buttons(void); +void time_buttons(struct ScrArea *sa); +void node_buttons(struct ScrArea *sa); + +void do_global_buttons(unsigned short event); +void do_global_buttons2(short event); + +void do_action_buttons(unsigned short event); +void do_buts_buttons(short event); +void do_file_buttons(short event); +void do_image_buttons(unsigned short event); +void do_imasel_buttons(short event); +void do_info_buttons(unsigned short event); +void do_ipo_buttons(short event); +void do_layer_buttons(short event); +void do_nla_buttons(unsigned short event); +void do_oops_buttons(short event); +void do_seq_buttons(short event); +void do_sound_buttons(unsigned short event); +void do_text_buttons(unsigned short event); +void do_script_buttons(unsigned short event); +void do_view3d_buttons(short event); +void do_time_buttons(struct ScrArea *sa, unsigned short event); +void do_node_buttons(struct ScrArea *sa, unsigned short event); + +void do_headerbuttons(short event); + +/* header_ipo.c */ +void spaceipo_assign_ipo(struct SpaceIpo *si, struct Ipo *ipo); + +/* header_text.c */ +void do_text_editmenu_to3dmenu(void *arg, int event); +void do_text_formatmenu_convert(void *arg, int event); + +/* header_info.c */ +void do_info_add_meshmenu(void *arg, int event); +void do_info_add_curvemenu(void *arg, int event); +void do_info_add_surfacemenu(void *arg, int event); +void do_info_add_metamenu(void *arg, int event); +void do_info_add_lampmenu(void *arg, int event); +void do_info_addmenu(void *arg, int event); + +/* header_node.c */ +void do_node_addmenu(void *arg, int event); + +/* header_view3d.c */ +void do_view3d_select_objectmenu(void *arg, int event); +void do_view3d_select_object_groupedmenu(void *arg, int event); +void do_view3d_select_object_linkedmenu(void *arg, int event); +void do_view3d_select_object_layermenu(void *arg, int event); +void do_view3d_select_object_typemenu(void *arg, int event); +void do_view3d_select_faceselmenu(void *arg, int event); +void do_view3d_select_meshmenu(void *arg, int event); +void do_view3d_select_curvemenu(void *arg, int event); +void do_view3d_select_metaballmenu(void *arg, int event); +void do_view3d_edit_snapmenu(void *arg, int event); +void do_view3d_edit_mirrormenu(void *arg, int event); +void do_view3d_transform_moveaxismenu(void *arg, int event); +void do_view3d_transform_rotateaxismenu(void *arg, int event); +void do_view3d_transform_scaleaxismenu(void *arg, int event); +void do_view3d_object_mirrormenu(void *arg, int event); +void do_view3d_edit_mesh_normalsmenu(void *arg, int event); +void do_view3d_edit_mesh_verticesmenu(void *arg, int event); +void do_view3d_edit_mesh_edgesmenu(void *arg, int event); +void do_view3d_edit_mesh_facesmenu(void *arg, int event); +void do_view3d_edit_curve_segmentsmenu(void *arg, int event); +void do_view3d_edit_curve_showhidemenu(void *arg, int event); + +#endif /* BSE_HEADERBUTTONS_H */ diff --git a/source/blender/include/BSE_node.h b/source/blender/include/BSE_node.h new file mode 100644 index 00000000000..171a277e8e6 --- /dev/null +++ b/source/blender/include/BSE_node.h @@ -0,0 +1,137 @@ +/** + * $Id: + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 opt ion) 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL BLOCK ***** + */ + +#ifndef BSE_NODE_H +#define BSE_NODE_H + +/* ********** drawing sizes *********** */ +#define NODE_DY 20 +#define NODE_DYS 10 +#define NODE_SOCKSIZE 5 +#define BASIS_RAD 8.0f +#define HIDDEN_RAD 15.0f + + +struct SpaceNode; +struct bNode; +struct bNodeTree; +struct Material; +struct ID; +struct Scene; +struct Image; +struct ImageUser; + +/* ************* API for editnode.c *********** */ + + /* helper calls to retreive active context for buttons, does groups */ +struct Material *editnode_get_active_material(struct Material *ma); +struct bNode *editnode_get_active_idnode(struct bNodeTree *ntree, short id_code); +struct bNode *editnode_get_active(struct bNodeTree *ntree); + +void snode_tag_dirty(struct SpaceNode *snode); + +void snode_set_context(struct SpaceNode *snode); + +void snode_home(struct ScrArea *sa, struct SpaceNode *snode); +void snode_zoom_in(struct ScrArea *sa); +void snode_zoom_out(struct ScrArea *sa); + +void node_deselectall(struct SpaceNode *snode, int swap); +void node_border_select(struct SpaceNode *snode); + +void node_delete(struct SpaceNode *snode); +void node_make_group(struct SpaceNode *snode); +void node_ungroup(struct SpaceNode *snode); +void snode_make_group_editable(struct SpaceNode *snode, struct bNode *gnode); +void node_hide(struct SpaceNode *snode); +void node_read_renderlayers(struct SpaceNode *snode); +void clear_scene_in_nodes(struct Scene *sce); + +void node_transform_ext(int mode, int unused); +void node_shader_default(struct Material *ma); +void node_composit_default(struct Scene *scene); + +int node_has_hidden_sockets(struct bNode *node); + +struct bNode *node_add_node(struct SpaceNode *snode, int type, float locx, float locy); +void node_adduplicate(struct SpaceNode *snode); + +void snode_autoconnect(struct SpaceNode *snode, struct bNode *node_to, int flag); +void node_select_linked(struct SpaceNode *snode, int out); + +struct ImageUser *ntree_get_active_iuser(struct bNodeTree *ntree); + +void imagepaint_composite_tags(struct bNodeTree *ntree, struct Image *image, struct ImageUser *iuser); + + + +/* ************* drawnode.c *************** */ +struct SpaceNode; +struct bNodeLink; +void node_draw_link(struct SpaceNode *snode, struct bNodeLink *link); + +void init_node_butfuncs(void); + +/* exported to CMP and SHD nodes */ +//void node_ID_title_cb(void *node_v, void *unused_v); +//void node_but_title_cb(void *node_v, void *but_v); +//void node_texmap_cb(void *texmap_v, void *unused_v); +//void node_new_mat_cb(void *ntree_v, void *node_v); +//void node_browse_mat_cb(void *ntree_v, void *node_v); +//void node_mat_alone_cb(void *node_v, void *unused); + + +//void node_browse_image_cb(void *ntree_v, void *node_v); +//void node_active_cb(void *ntree_v, void *node_v); +//void node_image_type_cb(void *node_v, void *unused); +//char *node_image_type_pup(void); +//char *layer_menu(struct RenderResult *rr); +//void image_layer_cb(void *ima_v, void *iuser_v); +//void set_render_layers_title(void *node_v, void *unused); +//char *scene_layer_menu(struct Scene *sce); +//void node_browse_scene_cb(void *ntree_v, void *node_v); + + +//int node_buts_curvevec(struct uiBlock *block, struct bNodeTree *ntree, struct bNode *node, struct rctf *butr); +//int node_buts_curvecol(struct uiBlock *block, struct bNodeTree *ntree, struct bNode *node, struct rctf *butr); +//int node_buts_rgb(struct uiBlock *block, struct bNodeTree *ntree, struct bNode *node, struct rctf *butr); +//int node_buts_texture(struct uiBlock *block, struct bNodeTree *ntree, struct bNode *node, struct rctf *butr); +//int node_buts_valtorgb(struct uiBlock *block, struct bNodeTree *ntree, struct bNode *node, struct rctf *butr); +//int node_buts_value(struct uiBlock *block, struct bNodeTree *ntree, struct bNode *node, struct rctf *butr); +//int node_buts_mix_rgb(struct uiBlock *block, struct bNodeTree *ntree, struct bNode *node, struct rctf *butr); +//int node_buts_group(struct uiBlock *block, struct bNodeTree *ntree, struct bNode *node, struct rctf *butr); +//int node_buts_normal(struct uiBlock *block, struct bNodeTree *ntree, struct bNode *node, struct rctf *butr); +//int node_buts_math(struct uiBlock *block, struct bNodeTree *ntree, struct bNode *node, struct rctf *butr) ; + + +/* ************* Shader nodes ***************** */ + + +#endif + diff --git a/source/blender/include/BSE_seqaudio.h b/source/blender/include/BSE_seqaudio.h new file mode 100644 index 00000000000..985c4be73d2 --- /dev/null +++ b/source/blender/include/BSE_seqaudio.h @@ -0,0 +1,53 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2003 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + */ + +#ifndef BSE_SEQAUDIO_H +#define BSE_SEQAUDIO_H + +#include "SDL.h" +/* muha, we don't init (no SDL_main)! */ +#ifdef main +# undef main +#endif + +#include "DNA_sound_types.h" + +void audio_mixdown(); +void audio_makestream(bSound *sound); +void audiostream_play(Uint32 startframe, Uint32 duration, int mixdown); +void audiostream_fill(Uint8* mixdown, int len); +void audiostream_start(Uint32 frame); +void audiostream_scrub(Uint32 frame); +void audiostream_stop(void); +int audiostream_pos(void); + +#endif + diff --git a/source/blender/include/BSE_seqeffects.h b/source/blender/include/BSE_seqeffects.h new file mode 100644 index 00000000000..2962bbf3676 --- /dev/null +++ b/source/blender/include/BSE_seqeffects.h @@ -0,0 +1,96 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Peter Schlaile < peter [at] schlaile [dot] de > + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + */ + +#ifndef BSE_SEQUENCE_EFFECTS_H +#define BSE_SEQUENCE_EFFECTS_H + +/* Wipe effect */ +enum {DO_SINGLE_WIPE, DO_DOUBLE_WIPE, DO_BOX_WIPE, DO_CROSS_WIPE, + DO_IRIS_WIPE,DO_CLOCK_WIPE}; + +struct Sequence; +struct ImBuf; + +struct SeqEffectHandle { + /* constructors & destructor */ + /* init & init_plugin are _only_ called on first creation */ + void (*init)(struct Sequence *seq); + void (*init_plugin)(struct Sequence * seq, const char * fname); + + /* number of input strips needed + (called directly after construction) */ + int (*num_inputs)(); + + /* load is called first time after readblenfile in + get_sequence_effect automatically */ + void (*load)(struct Sequence *seq); + + /* duplicate */ + void (*copy)(struct Sequence *dst, struct Sequence * src); + + /* destruct */ + void (*free)(struct Sequence *seq); + + /* returns: -1: no input needed, + 0: no early out, + 1: out = ibuf1, + 2: out = ibuf2 */ + int (*early_out)(struct Sequence *seq, + float facf0, float facf1); + + /* stores the y-range of the effect IPO */ + void (*store_icu_yrange)(struct Sequence * seq, + short adrcode, float * ymin, float * ymax); + + /* stores the default facf0 and facf1 if no IPO is present */ + void (*get_default_fac)(struct Sequence * seq, int cfra, + float * facf0, float * facf1); + + /* execute the effect + sequence effects are only required to either support + float-rects or byte-rects + (mixed cases are handled one layer up...) */ + + void (*execute)(struct Sequence *seq, int cfra, + float facf0, float facf1, + int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out); +}; + +struct SeqEffectHandle get_sequence_effect(struct Sequence * seq); +int get_sequence_effect_num_inputs(int seq_type); +void sequence_effect_speed_rebuild_map(struct Sequence * seq, int force); + +#endif + diff --git a/source/blender/include/BSE_seqscopes.h b/source/blender/include/BSE_seqscopes.h new file mode 100644 index 00000000000..3dd5e495928 --- /dev/null +++ b/source/blender/include/BSE_seqscopes.h @@ -0,0 +1,38 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Author: Peter Schlaile < peter [at] schlaile [dot] de > + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +#ifndef BSE_SEQUENCE_SCOPES_H +#define BSE_SEQUENCE_SCOPES_H + +struct ImBuf; + +struct ImBuf *make_waveform_view_from_ibuf(struct ImBuf * ibuf); +struct ImBuf *make_vectorscope_view_from_ibuf(struct ImBuf * ibuf); + +#endif + diff --git a/source/blender/include/BSE_sequence.h b/source/blender/include/BSE_sequence.h new file mode 100644 index 00000000000..ff79d417537 --- /dev/null +++ b/source/blender/include/BSE_sequence.h @@ -0,0 +1,85 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + */ + +#ifndef BSE_SEQUENCE_H +#define BSE_SEQUENCE_H + + +struct PluginSeq; +struct StripElem; +struct Strip; +struct Sequence; +struct ListBase; +struct Editing; +struct ImBuf; +struct Scene; + +void free_stripdata(int len, struct StripElem *se); +void free_strip(struct Strip *strip); +void new_stripdata(struct Sequence *seq); +void free_sequence(struct Sequence *seq); +void build_seqar(struct ListBase *seqbase, struct Sequence ***seqar, int *totseq); +void free_editing(struct Editing *ed); +void calc_sequence(struct Sequence *seq); +void calc_sequence_disp(struct Sequence *seq); +void sort_seq(void); +void clear_scene_in_allseqs(struct Scene *sce); + +int evaluate_seq_frame(int cfra); +struct StripElem *give_stripelem(struct Sequence *seq, int cfra); +void set_meta_stripdata(struct Sequence *seqm); +struct ImBuf *give_ibuf_seq(int rectx, int recty, int cfra, int chansel); +/* chansel: render this channel. Default=0 (renders end result)*/ + +/* sequence prefetch API */ +void seq_start_threads(); +void seq_stop_threads(); +void give_ibuf_prefetch_request(int rectx, int recty, int cfra, int chanshown); +void seq_wait_for_prefetch_ready(); +struct ImBuf * give_ibuf_threaded(int rectx, int recty, int cfra, + int chanshown); + + +void free_imbuf_seq_except(int cfra); +void free_imbuf_seq_with_ipo(struct Ipo * ipo); +void free_imbuf_seq(void); + +void update_changed_seq_and_deps(struct Sequence *seq, int len_change, int ibuf_change); + +/* still bad level call... */ +struct RenderResult; +void do_render_seq(struct RenderResult *rr, int cfra); + + +#endif + diff --git a/source/blender/include/BSE_time.h b/source/blender/include/BSE_time.h new file mode 100644 index 00000000000..d5cff9f5e5f --- /dev/null +++ b/source/blender/include/BSE_time.h @@ -0,0 +1,71 @@ +/** + * $Id: + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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 opt ion) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BSE_TIME_H +#define BSE_TIME_H + +struct ListBase; +struct View2D; + +/* ******** Markers - General Api ********* */ +void add_marker(int frame); +void duplicate_marker(void); +void remove_marker(void); +void rename_marker(void); +void transform_markers(int mode, int smode); + +void borderselect_markers(void); +void deselect_markers(short test, short sel); +struct TimeMarker *find_nearest_marker(int clip_y); + +void nextprev_marker(short dir); +void get_minmax_markers(short sel, float *first, float *last); +int find_nearest_marker_time(float dx); + +void add_marker_to_cfra_elem(struct ListBase *lb, struct TimeMarker *marker, short only_sel); +void make_marker_cfra_list(struct ListBase *lb, short only_sel); + +void draw_markers_timespace(int lines); +TimeMarker *get_frame_marker(int frame); + +/* ******** Animation - Preview Range ************* */ +void anim_previewrange_set(void); +void anim_previewrange_clear(void); + +void draw_anim_preview_timespace(void); + +/* *********** TimeLine Specific ***************/ +void timeline_frame_to_center(void); +void nextprev_timeline_key(short dir); + +#endif + diff --git a/source/blender/include/BSE_trans_types.h b/source/blender/include/BSE_trans_types.h new file mode 100644 index 00000000000..9c8b9e5595f --- /dev/null +++ b/source/blender/include/BSE_trans_types.h @@ -0,0 +1,90 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BSE_TRANS_TYPES_H +#define BSE_TRANS_TYPES_H + +struct Object; +struct MDeformVert; +struct ColorBand; + +typedef struct TransOb { + float *loc; + float oldloc[9]; + float *eff; + float oldeff[3]; + float *rot; + float oldrot[12]; + float olddrot[3]; + float *quat; + float oldquat[16]; + float olddquat[4]; + float *size; + float oldsize[12]; + float olddsize[3]; + float obmat[3][3]; + float obinv[3][3]; + float parmat[3][3]; + float parinv[3][3]; + float obvec[3]; + int flag; /* keys */ + float *locx, *locy, *locz; + float *rotx, *roty, *rotz; + float *quatx, *quaty, *quatz, *quatw; + float *sizex, *sizey, *sizez; + /* __NLA */ + float axismat[3][3]; /* Restmat of object (for localspace transforms) */ + void *data; /* Arbitrary data */ + /* end __NLA */ + struct Object *ob; +} TransOb; + +typedef struct TransVert { + float *loc; + float oldloc[3], fac; + float *val, oldval; + int flag; + float *nor; +} TransVert; + +typedef struct VPaint { + float r, g, b, a; + float size; /* of brush */ + float gamma, mul; + short mode, flag; + int tot, pad; /* allocation size of prev buffers */ + unsigned int *vpaint_prev; /* previous mesh colors */ + struct MDeformVert *wpaint_prev; /* previous vertex weights */ +} VPaint; + +#endif /* BSE_TRANS_TYPES_H */ + diff --git a/source/blender/include/BSE_types.h b/source/blender/include/BSE_types.h new file mode 100644 index 00000000000..591ea2f5168 --- /dev/null +++ b/source/blender/include/BSE_types.h @@ -0,0 +1,69 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/* forward declarations for some prototype header */ +/* these may wildly occur in other header files, too */ + +struct BGpic; +struct SpaceText; +struct Oops; +struct OopsLink; +struct uiBlock; +struct BoundBox; +struct Image; +struct ImBuf; +struct SpaceImaSel; +struct Sequence; +struct Scene; +struct IpoCurve; +struct Ipo; +struct IpoKey; +struct Mesh; +struct MTFace; +struct Object; +struct TransOb; +struct TransVert; +struct BPoint; +struct BezTriple; + +struct Nurb; + +struct EditFace; +struct EditVert; +struct EditEdge; +struct EditIpo; + +struct bArmature; +struct Bone; + +/* interface crap */ +struct uiBut; + diff --git a/source/blender/include/BSE_view.h b/source/blender/include/BSE_view.h new file mode 100644 index 00000000000..4e27f9f1a81 --- /dev/null +++ b/source/blender/include/BSE_view.h @@ -0,0 +1,97 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * protos for view.c -- not complete + */ + +#ifndef BSE_VIEW_H +#define BSE_VIEW_H + +struct Object; +struct BoundBox; +struct View3D; +struct ScrArea; + +typedef struct ViewDepths { + unsigned short w, h; + float *depths; + double depth_range[2]; + + char damaged; +} ViewDepths; + +#define PERSP_WIN 0 +#define PERSP_VIEW 1 +#define PERSP_STORE 2 + +void persp_general(int a); +void persp(int a); + +/* note, the define below is still used for shorts, to calc distances... */ +#define IS_CLIPPED 12000 +void view3d_get_object_project_mat(struct ScrArea *area, struct Object *ob, float pmat[4][4], float vmat[4][4]); +void view3d_project_float(struct ScrArea *area, float *vec, float *adr, float mat[4][4]); +void view3d_project_short_clip(struct ScrArea *area, float *vec, short *adr, float projmat[4][4], float viewmat[4][4]); +void view3d_project_short_noclip(struct ScrArea *area, float *vec, short *adr, float mat[4][4]); + +void initgrabz(float x, float y, float z); +void window_to_3d(float *vec, short mx, short my); +void project_short(float *vec, short *adr); +void project_short_noclip(float *vec, short *adr); +void project_int(float *vec, int *adr); +void project_float(float *vec, float *adr); + +int boundbox_clip(float obmat[][4], struct BoundBox *bb); +void fdrawline(float x1, float y1, float x2, float y2); +void fdrawbox(float x1, float y1, float x2, float y2); +void sdrawline(short x1, short y1, short x2, short y2); +void sdrawbox(short x1, short y1, short x2, short y2); +void calctrackballvecfirst(struct rcti *area, short *mval, float *vec); +void calctrackballvec(struct rcti *area, short *mval, float *vec); +void viewmove(int mode); +void view_zoom_mouseloc(float dfac, short *mouseloc); + +int get_view3d_viewplane(int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize); +void setwinmatrixview3d(int winx, int winy, struct rctf *rect); + +void obmat_to_viewmat(struct Object *ob, short smooth); +void setviewmatrixview3d(void); +float *give_cursor(void); +unsigned int free_localbit(void); +void initlocalview(void); +void centerview(void); +void restore_localviewdata(struct View3D *vd); +void endlocalview(struct ScrArea *sa); +void view3d_home(int center); +short view3d_opengl_select(unsigned int *buffer, unsigned int buffsize, short x1, short y1, short x2, short y2); +void view3d_align_axis_to_vector(struct View3D *v3d, int axisidx, float vec[3]); + +#endif + diff --git a/source/blender/include/LOD_DependKludge.h b/source/blender/include/LOD_DependKludge.h new file mode 100644 index 00000000000..43034201b81 --- /dev/null +++ b/source/blender/include/LOD_DependKludge.h @@ -0,0 +1,40 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * Decimation file dependency fix (and kludge) + * Use together with a NAN_DECIMATIONTEST env.var. for Makefile-based linking + */ +#ifndef LOD_DEPENDKLUDGE_H +#define LOD_DEPENDKLUDGE_H + +#define NAN_DECIMATION + +#endif //LOD_DEPENDKLUDGE_H + diff --git a/source/blender/include/blendef.h b/source/blender/include/blendef.h new file mode 100644 index 00000000000..4c42ba85968 --- /dev/null +++ b/source/blender/include/blendef.h @@ -0,0 +1,460 @@ +/* $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BLENDEF_H +#define BLENDEF_H + + +/* **************** MAX ********************* */ + +#define MAXFRAME 300000 +#define MAXFRAMEF 300000.0f + +#define MINFRAME 1 +#define MINFRAMEF 1.0 + +/* max length material array, 16 because of bits in matfrom */ +#define MAXPICKBUF 10000 +#define MAXSEQ 32 + +/* in buttons.c */ +#define MAX_EFFECT 20 + +#ifndef MAXFLOAT +#define MAXFLOAT ((float)3.40282347e+38) +#endif + +/* also fill in structs itself, dna cannot handle defines, duplicate with utildefines.h still */ +#ifndef FILE_MAXDIR +#define FILE_MAXDIR 160 +#define FILE_MAXFILE 80 +#endif + + +#include + + + + +/* **************** GENERAL ********************* */ + +// return values + +#define RET_OK 0 +#define RET_ERROR 1 +#define RET_CANCEL 2 +#define RET_YES (1 == 1) +#define RET_NO (1 == 0) + +#if defined(__sgi) || defined(__sparc) || defined(__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__) +/* big endian */ +#define MAKE_ID2(c, d) ( (c)<<8 | (d) ) +#define MOST_SIG_BYTE 0 +#define BBIG_ENDIAN +#else +/* little endian */ +#define MAKE_ID2(c, d) ( (d)<<8 | (c) ) +#define MOST_SIG_BYTE 1 +#define BLITTLE_ENDIAN +#endif + +#define SELECT 1 +#define HIDDEN 1 +#define FIRST 1 +#define ACTIVE 2 +/*#ifdef WITH_VERSE*/ +#define VERSE 3 +/*#endif*/ +#define DESELECT 0 +#define NOT_YET 0 +#define VISIBLE 0 +#define LAST 0 + +#define TESTBASE(base) ( ((base)->flag & SELECT) && ((base)->lay & G.vd->lay) && (((base)->object->restrictflag & OB_RESTRICT_VIEW)==0) ) +#define TESTBASELIB(base) ( ((base)->flag & SELECT) && ((base)->lay & G.vd->lay) && ((base)->object->id.lib==0) && (((base)->object->restrictflag & OB_RESTRICT_VIEW)==0)) +#define BASE_SELECTABLE(base) ((base->lay & G.vd->lay) && (base->object->restrictflag & (OB_RESTRICT_SELECT|OB_RESTRICT_VIEW))==0) +#define FIRSTBASE G.scene->base.first +#define LASTBASE G.scene->base.last +#define BASACT (G.scene->basact) +#define OBACT (BASACT? BASACT->object: 0) +#define ID_NEW(a) if( (a) && (a)->id.newid ) (a)= (void *)(a)->id.newid +#define ID_NEW_US(a) if( (a)->id.newid) {(a)= (void *)(a)->id.newid; (a)->id.us++;} +#define ID_NEW_US2(a) if( ((ID *)a)->newid) {(a)= ((ID *)a)->newid; ((ID *)a)->us++;} +#define CFRA (G.scene->r.cfra) +#define F_CFRA ((float)(G.scene->r.cfra)) +#define SFRA (G.scene->r.sfra) +#define EFRA (G.scene->r.efra) +#define PSFRA ((G.scene->r.psfra != 0)? (G.scene->r.psfra): (G.scene->r.sfra)) +#define PEFRA ((G.scene->r.psfra != 0)? (G.scene->r.pefra): (G.scene->r.efra)) +#define FRA2TIME(a) ((((double) G.scene->r.frs_sec_base) * (a)) / G.scene->r.frs_sec) +#define TIME2FRA(a) ((((double) G.scene->r.frs_sec) * (a)) / G.scene->r.frs_sec_base) +#define FPS (((double) G.scene->r.frs_sec) / G.scene->r.frs_sec_base) + +#define ISPOIN(a, b, c) ( (a->b) && (a->c) ) +#define ISPOIN3(a, b, c, d) ( (a->b) && (a->c) && (a->d) ) +#define ISPOIN4(a, b, c, d, e) ( (a->b) && (a->c) && (a->d) && (a->e) ) + +#define BEZSELECTED(bezt) (((bezt)->f1 & 1) || ((bezt)->f2 & 1) || ((bezt)->f3 & 1)) + +/* psfont */ +#define FNT_PDRAW 1 +#define FNT_HAEBERLI 2 + +/* getbutton */ + +/* do_global_buttons(event) */ + +// (first event) +#define B_LOCAL_ALONE 20 + + +#define B_ACTLOCAL 24 /* __NLA */ +#define B_ACTALONE 25 /* __NLA */ +#define B_ARMLOCAL 26 /* __NLA */ +#define B_ARMALONE 27 /* __NLA */ + +#define B_WORLDLOCAL 28 +#define B_WORLDALONE 29 +#define B_LATTLOCAL 30 +#define B_MBALLLOCAL 31 +#define B_CAMERALOCAL 32 +#define B_OBLOCAL 33 +#define B_IPOLOCAL 34 +#define B_LAMPLOCAL 35 +#define B_MATLOCAL 36 +#define B_TEXLOCAL 37 +#define B_MESHLOCAL 38 +#define B_CURVELOCAL 39 + +#define B_LATTALONE 40 +#define B_MBALLALONE 41 +#define B_CAMERAALONE 42 +#define B_OBALONE 43 +#define B_IPOALONE 44 +#define B_LAMPALONE 45 +#define B_MATALONE 46 +#define B_TEXALONE 47 +#define B_MESHALONE 48 +#define B_CURVEALONE 49 + +/* EVENT < 50: alones en locals */ + +#define B_KEEPDATA 60 +#define B_CONSOLETOG 61 +#define B_DRAWINFO 62 +#define B_REDRCURW3D 63 +#define B_FLIPINFOMENU 64 +#define B_FLIPFULLSCREEN 65 +#define B_PLAINMENUS 66 + + +#define B_GLRESLIMITCHANGED 69 +#define B_SHOWSPLASH 70 +#define B_RESETAUTOSAVE 71 +#define B_SOUNDTOGGLE 72 +#define B_MIPMAPCHANGED 73 +#define B_CONSTRAINTBROWSE 74 /* __NLA */ +#define B_ACTIONDELETE 75 /* __NLA */ +#define B_ACTIONBROWSE 76 /* __NLA */ +#define B_IMAGEDELETE 77 +#define B_LTEXBROWSE 78 +#define B_MESHBROWSE 79 +#define B_EXTEXBROWSE 80 +#define B_LOADTEMP 81 +#define B_MATDELETE 82 +#define B_TEXDELETE 83 +#define B_IPODELETE 84 +#define B_WORLDDELETE 85 +#define B_WTEXBROWSE 86 +#define B_WORLDBROWSE 87 +#define B_IPOBROWSE 88 +#define B_NEWFRAME 89 +#define B_LAMPBROWSE 90 +#define B_MATBROWSE 91 +#define B_TEXBROWSE 92 +#define B_EDITBROWSE 93 +#define B_AUTOTEXNAME 94 +#define B_AUTOMATNAME 95 +#define B_MATLOCK 96 +#define B_IDNAME 97 +#define B_NEWSPACE 98 +#define B_FULL 99 +#define B_REDR 100 + + +/* VIEW3D: 100 */ +#define B_HOME 101 +#define B_LAY 102 +/* watch: codes 102-132 in in use for layers */ +#define B_AUTOKEY 139 +#define B_SCENELOCK 140 +#define B_LOCALVIEW 141 +#define B_U_CAPSLOCK 142 + +#define B_VIEWBUT 146 +#define B_PERSP 147 +#define B_PROPTOOL 148 +#define B_VIEWRENDER 149 +#define B_STARTGAME 150 + +#define B_MODESELECT 156 +#define B_AROUND 157 +#define B_SEL_VERT 158 +#define B_SEL_EDGE 159 +#define B_SEL_FACE 160 +#define B_MAN_TRANS 161 +#define B_MAN_ROT 162 +#define B_MAN_SCALE 163 + +/* IPO: 200 */ +#define B_IPOHOME 201 +#define B_IPOBORDER 202 +#define B_IPOCOPY 203 +#define B_IPOPASTE 204 +#define B_IPOCONT 205 +#define B_IPOEXTRAP 206 +#define B_IPOCYCLIC 207 +#define B_IPOMAIN 208 +#define B_IPOSHOWKEY 209 +#define B_IPOCYCLICX 210 + /* warn: also used for oops and seq */ +#define B_VIEW2DZOOM 211 +#define B_IPOPIN 212 +#define B_IPO_ACTION_OB 213 +#define B_IPO_ACTION_KEY 214 +#define B_IPOVIEWCENTER 215 +#define B_IPOVIEWALL 216 + + +/* OOPS: 250 */ +#define B_OOPSHOME 251 +#define B_OOPSBORDER 252 +#define B_NEWOOPS 253 +#define B_OOPSVIEWSEL 254 + +/* INFO: 300 */ +/* watch: also in filesel.c and editobject.c */ +#define B_INFOSCR 301 +#define B_INFODELSCR 302 +#define B_INFOSCE 304 +#define B_INFODELSCE 305 +#define B_FILEMENU 306 +#define B_PACKFILE 307 + +#define B_CONSOLEOUT 308 +#define B_CONSOLENUMLINES 309 +#define B_USERPREF 310 +#define B_LOADUIFONT 311 +#define B_SETLANGUAGE 312 +#define B_SETFONTSIZE 313 +#define B_SETENCODING 314 +#define B_SETTRANSBUTS 315 +#define B_DOLANGUIFONT 316 +#define B_RESTOREFONT 317 +#define B_USETEXTUREFONT 318 + +#define B_UITHEMECHANGED 320 +#define B_UITHEMECOLORMOD 321 +#define B_UITHEMERESET 322 +#define B_UITHEMEIMPORT 323 +#define B_UITHEMEEXPORT 324 + +#define B_MEMCACHELIMIT 325 +#define B_WPAINT_RANGE 326 + +/* Definitions for the fileselect buttons in user prefs */ +#define B_FONTDIRFILESEL 330 +#define B_TEXTUDIRFILESEL 331 +#define B_PLUGTEXDIRFILESEL 332 +#define B_PLUGSEQDIRFILESEL 333 +#define B_RENDERDIRFILESEL 334 +#define B_PYTHONDIRFILESEL 335 +#define B_SOUNDDIRFILESEL 336 +#define B_TEMPDIRFILESEL 337 +/* yafray: for exportdir select */ +#define B_YAFRAYDIRFILESEL 338 +#define B_PYMENUEVAL 339 /* re-eval scripts registration in menus */ +/* END Definitions for the fileselect buttons in user prefs */ + +/* IMAGE: 350 */ +#define B_SIMAGEHOME 351 +#define B_SIMABROWSE 352 +#define B_SIMAGELOAD 353 +#define B_SIMA_REDR_IMA_3D 354 +#define B_SIMAGETILE 355 +#define B_BE_SQUARE 356 +#define B_TWINANIM 357 +#define B_SIMAGEREPLACE 358 +#define B_CLIP_UV 359 +#define B_SIMAGELOAD1 360 +#define B_SIMAGEREPLACE1 361 +#define B_SIMAGEPAINTTOOL 362 +#define B_SIMAPACKIMA 363 +#define B_SIMAGESAVE 364 +#define B_SIMACLONEBROWSE 365 +#define B_SIMACLONEDELETE 366 +#define B_SIMANOTHING 368 +#define B_SIMACURVES 369 +#define B_SIMARANGE 370 +#define B_SIMA_USE_ALPHA 371 +#define B_SIMA_SHOW_ALPHA 372 +#define B_SIMA_SHOW_ZBUF 373 +#define B_SIMABRUSHBROWSE 374 +#define B_SIMABRUSHDELETE 375 +#define B_SIMABRUSHLOCAL 376 +#define B_SIMABRUSHCHANGE 377 +#define B_SIMABTEXBROWSE 378 +#define B_SIMABTEXDELETE 379 +#define B_SIMARELOAD 380 +#define B_SIMANAME 381 +#define B_SIMAMULTI 382 +#define B_TRANS_IMAGE 383 +#define B_CURSOR_IMAGE 384 +#define B_SIMA_REPACK 385 +#define B_SIMA_PLAY 386 +#define B_SIMA_RECORD 387 +#define B_SIMAPIN 388 +#define B_SIMA3DVIEWDRAW 389 + + +/* BUTS: 400 */ +#define B_BUTSHOME 401 +#define B_BUTSPREVIEW 402 +#define B_MATCOPY 403 +#define B_MATPASTE 404 +#define B_MESHTYPE 405 +#define B_CONTEXT_SWITCH 406 + +/* IMASEL: 450 */ +/* in imasel.h - not any more - elubie */ +#define B_SORTIMASELLIST 451 +#define B_RELOADIMASELDIR 452 +#define B_FILTERIMASELDIR 453 + +/* TEXT: 500 */ +#define B_TEXTBROWSE 501 +#define B_TEXTALONE 502 +#define B_TEXTLOCAL 503 +#define B_TEXTDELETE 504 +#define B_TEXTFONT 505 +#define B_TEXTSTORE 506 +#define B_TEXTLINENUM 507 +#define B_TAB_NUMBERS 508 +#define B_SYNTAX 509 + +/* SCRIPT: 525 */ +#define B_SCRIPTBROWSE 526 +#define B_SCRIPT2PREV 527 + +/* FILE: 550 */ +#define B_SORTFILELIST 551 +#define B_RELOADDIR 552 + +/* SEQUENCE: 600 */ +#define B_SEQHOME 601 +#define B_SEQCLEAR 602 + +/* SOUND: 650 */ +#define B_SOUNDBROWSE 651 +#define B_SOUNDBROWSE2 652 +#define B_SOUNDHOME 653 +#define B_PACKSOUND 654 + +/* ACTION: 701 - 750 */ +#define B_ACTHOME 701 +#define B_ACTCOPY 702 +#define B_ACTPASTE 703 +#define B_ACTPASTEFLIP 704 +#define B_ACTCYCLIC 705 +#define B_ACTCONT 706 +#define B_ACTMAIN 707 +#define B_ACTPIN 708 +#define B_ACTBAKE 709 +#define B_ACTCOPYKEYS 710 +#define B_ACTPASTEKEYS 711 + +/* TIME: 751 - 800 */ +#define B_TL_REW 751 +#define B_TL_PLAY 752 +#define B_TL_FF 753 +#define B_TL_PREVKEY 754 +#define B_TL_NEXTKEY 755 +#define B_TL_STOP 756 +#define B_TL_PREVIEWON 757 + +/* NLA: 801-850 */ +#define B_NLAHOME 801 + +/* NODE: 851-900 */ +#define B_NODEHOME 851 +#define B_NODE_USEMAT 852 +#define B_NODE_USESCENE 853 + +/* FREE 901 - 999 */ + + +#define B_NOP -1 + + +/* editbutflag */ +#define B_CLOCKWISE 1 +#define B_KEEPORIG 2 +#define B_BEAUTY 4 +#define B_SMOOTH 8 +#define B_BEAUTY_SHORT 16 +#define B_AUTOFGON 32 +#define B_KNIFE 0x80 +#define B_PERCENTSUBD 0x40 +#define B_MESH_X_MIRROR 0x100 +#define B_JOINTRIA_UV 0x200 +#define B_JOINTRIA_VCOL 0X400 +#define B_JOINTRIA_SHARP 0X800 +#define B_JOINTRIA_MAT 0X1000 + +/* DISPLAYMODE */ +#define R_DISPLAYIMAGE 0 +#define R_DISPLAYWIN 1 +#define R_DISPLAYSCREEN 2 + +/* Gvp.flag and Gwp.flag */ +#define VP_COLINDEX 1 +#define VP_AREA 2 +#define VP_SOFT 4 +#define VP_NORMALS 8 +#define VP_SPRAY 16 +#define VP_MIRROR_X 32 +#define VP_HARD 64 +#define VP_ONLYVGROUP 128 + +/* Error messages */ +#define ERROR_LIBDATA_MESSAGE "Can't edit external libdata" + + +#endif diff --git a/source/blender/include/butspace.h b/source/blender/include/butspace.h new file mode 100644 index 00000000000..fec85c03b77 --- /dev/null +++ b/source/blender/include/butspace.h @@ -0,0 +1,723 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BUTSPACE_H +#define BUTSPACE_H + +/* all internal calls and event codes for buttons space */ + +struct Base; +struct Object; +struct ID; +struct ColorBand; +struct uiBlock; +struct rctf; +struct CurveMap; +struct ImageUser; +struct RenderResult; +struct Image; + +/* buts->scaflag */ +#define BUTS_SENS_SEL 1 +#define BUTS_SENS_ACT 2 +#define BUTS_SENS_LINK 4 +#define BUTS_CONT_SEL 8 +#define BUTS_CONT_ACT 16 +#define BUTS_CONT_LINK 32 +#define BUTS_ACT_SEL 64 +#define BUTS_ACT_ACT 128 +#define BUTS_ACT_LINK 256 + +/* internal */ + +/* scene */ +extern void render_panels(void); +extern void do_render_panels(unsigned short event); +extern void anim_panels(void); +extern void sound_panels(void); +extern void do_soundbuts(unsigned short event); + +/* object */ +extern void object_panels(void); +extern void physics_panels(void); +extern void do_object_panels(unsigned short event); +extern void do_constraintbuts(unsigned short event); +extern void object_panel_constraint(char *context); +extern void autocomplete_bone(char *str, void *arg_v); +extern void autocomplete_vgroup(char *str, void *arg_v); + +/* effects */ +extern void effects_panels(void); +extern void do_effects_panels(unsigned short event); + +/* modifiers */ +extern int mod_moveUp(void *ob_v, void *md_v); +extern int mod_moveDown(void *ob_v, void *md_v); + +/* constraint */ +extern void const_moveUp(void *ob_v, void *con_v); +extern void const_moveDown(void *ob_v, void *con_v); +extern void del_constr_func (void *ob_v, void *con_v); +extern void get_constraint_ipo_context(void *ob_v, char *actname); + +/* editing */ +extern void editing_panels(void); +extern void do_common_editbuts(unsigned short event); +extern void do_meshbuts(unsigned short event); +extern void do_vgroupbuts(unsigned short event); +extern void do_curvebuts(unsigned short event); +extern void do_fontbuts(unsigned short event); +extern void do_mballbuts(unsigned short event); +extern void do_latticebuts(unsigned short event); +extern void do_fpaintbuts(unsigned short event); +extern void do_cambuts(unsigned short event); +extern void do_armbuts(unsigned short event); +extern void do_uvcalculationbuts(unsigned short event); +extern void weight_paint_buttons(struct uiBlock *); + +extern char *get_vertexgroup_menustr(struct Object *ob); // used in object buttons + +/* shading */ +extern void draw_colorband_buts_small(struct uiBlock *block, struct ColorBand *coba, rctf *rct, int event); +extern void material_panels(void); +extern void do_matbuts(unsigned short event); +extern void lamp_panels(void); +extern void do_lampbuts(unsigned short event); +extern void world_panels(void); +extern void do_worldbuts(unsigned short event); +extern void radio_panels(void); +extern void do_radiobuts(unsigned short event); +extern void texture_panels(void); +extern void do_texbuts(unsigned short event); +void uiblock_image_panel(struct uiBlock *block, struct Image **ima_pp, struct ImageUser *iuser, + short redraw, short imagechanged); +void uiblock_layer_pass_buttons(struct uiBlock *block, struct RenderResult *rr, + struct ImageUser *iuser, int event, int x, int y, int w); + +/* logic */ +extern void do_logic_buts(unsigned short event); +extern void logic_buts(void); + +/* script */ +extern void script_panels(void); +extern void do_scriptbuts(unsigned short event); + +/* ipowindow */ +extern void do_ipobuts(unsigned short event); // drawipo.c (bad! ton) + +/* butspace.c */ +void test_meshpoin_but(char *name, struct ID **idpp); +void test_obpoin_but(char *name, struct ID **idpp); +void test_meshobpoin_but(char *name, struct ID **idpp); +void test_scenepoin_but(char *name, struct ID **idpp); +void test_matpoin_but(char *name, struct ID **idpp); +void test_scriptpoin_but(char *name, struct ID **idpp); +void test_actionpoin_but(char *name, ID **idpp); +void test_grouppoin_but(char *name, ID **idpp); +void test_texpoin_but(char *name, ID **idpp); +void test_imapoin_but(char *name, ID **idpp); + +void test_idbutton_cb(void *namev, void *arg2_unused); + +struct CurveMapping; +void curvemap_buttons(struct uiBlock *block, struct CurveMapping *cumap, char labeltype, short event, short redraw, struct rctf *rect); + +/* -------------- internal event defines ------------ */ + + +#define B_DIFF 1 + +/* *********************** */ +#define B_VIEWBUTS 1100 + +#define B_OBJECTPANELROT 1007 +#define B_OBJECTPANELMEDIAN 1008 +#define B_ARMATUREPANEL1 1009 +#define B_ARMATUREPANEL2 1010 +#define B_OBJECTPANELPARENT 1011 +#define B_OBJECTPANEL 1012 +#define B_ARMATUREPANEL3 1013 +#define B_OBJECTPANELSCALE 1014 +#define B_OBJECTPANELDIMS 1015 + +/* *********************** */ +#define B_LAMPBUTS 1200 + +#define B_LAMPREDRAW 1101 +#define B_COLLAMP 1102 +#define B_TEXCLEARLAMP 1103 +#define B_SBUFF 1104 +#define B_SHADBUF 1105 +#define B_SHADRAY 1106 +#define B_LMTEXPASTE 1107 +#define B_LMTEXCOPY 1108 +#define B_LFALLOFFCHANGED 1109 + +/* *********************** */ +#define B_MATBUTS 1300 + +#define B_MATCOL 1201 +#define B_SPECCOL 1202 +#define B_MIRCOL 1203 +#define B_ACTCOL 1204 +#define B_MATFROM 1205 +#define B_MATPRV 1206 +#define B_LAMPPRV 1207 +#define B_WORLDPRV 1208 +#define B_MTEXCOL 1210 +#define B_TEXCLEAR 1211 +#define B_MTEXPASTE 1212 +#define B_MTEXCOPY 1213 +#define B_MATLAY 1214 +#define B_MATHALO 1215 +#define B_MATZTRANSP 1216 +#define B_MATRAYTRANSP 1217 +#define B_MATCOLORBAND 1218 + /* yafray: material preset menu event */ +#define B_MAT_YF_PRESET 1219 + +#define B_MAT_LAYERBROWSE 1220 +#define B_MAT_USENODES 1221 +#define B_MAT_VCOL_PAINT 1222 +#define B_MAT_VCOL_LIGHT 1223 + + /* world buttons: buttons-preview update, and redraw 3dview */ +#define B_WORLDPRV2 1224 + +/* *********************** */ +#define B_TEXBUTS 1400 + +#define B_TEXTYPE 1301 +#define B_DEFTEXVAR 1302 + +#define B_NAMEIMA 1304 +#define B_TEXCHANNEL 1305 +#define B_TEXREDR_PRV 1306 +#define B_IMAGECHANGED 1307 + +#define B_LOADPLUGIN 1310 +#define B_NAMEPLUGIN 1311 +#define B_COLORBAND 1312 +#define B_ADDCOLORBAND 1313 +#define B_DELCOLORBAND 1314 +#define B_CALCCBAND 1315 +#define B_CALCCBAND2 1316 +#define B_DOCOLORBAND 1317 +#define B_REDRAWCBAND 1318 +#define B_BANDCOL 1319 +#define B_LOADTEXIMA1 1320 +#define B_TEXPRV 1321 + + +#define B_PLUGBUT 1325 +/* B_PLUGBUT reserves 24 buttons at least! */ + +#define B_ENV_MAKE 1350 +#define B_ENV_FREE 1351 +#define B_ENV_DELETE 1352 +#define B_ENV_SAVE 1353 +#define B_ENV_OB 1354 + +#define B_ENV_FREE_ALL 1357 + + +/* **************** animbuts = object buttons ******* */ +#define B_ANIMBUTS 1500 + +#define B_RECALCPATH 1401 +#define B_TRACKBUTS 1402 +#define B_DUPLI_FRAME 1403 +#define B_DUPLI_VERTS 1404 +#define B_DUPLI_FACES 1405 +#define B_DUPLI_GROUP 1406 + + +#define B_PRINTSPEED 1413 +#define B_PRINTLEN 1414 +#define B_RELKEY 1415 +#define B_CURVECHECK 1416 + +#define B_SOFTBODY_CHANGE 1420 +#define B_SOFTBODY_DEL_VG 1421 +#define B_SOFTBODY_BAKE 1422 +#define B_SOFTBODY_BAKE_FREE 1423 + +/* this has MAX_EFFECT settings! Next free define is 1450... */ +#define B_SELEFFECT 1430 + +/* Fluidsim button defines */ +#define B_FLUIDSIM_BAKE 1450 +#define B_FLUIDSIM_SELDIR 1451 +#define B_FLUIDSIM_FORCEREDRAW 1452 +#define B_FLUIDSIM_MAKEPART 1453 + +#define B_GROUP_RELINK 1460 +#define B_OBJECT_IPOFLAG 1461 + +/* *********************** */ +#define B_WORLDBUTS 1600 + +#define B_TEXCLEARWORLD 1501 +#define B_COLHOR 1502 +#define B_COLZEN 1503 +#define B_WMTEXPASTE 1504 +#define B_WMTEXCOPY 1505 +#define B_AO_FALLOFF 1506 + +/* *********************** */ +#define B_RENDERBUTS 1700 + +#define B_FS_PIC 1601 +#define B_FS_BACKBUF 1602 + +#define B_FS_FTYPE 1604 +#define B_DORENDER 1605 +#define B_DOANIM 1606 +#define B_PLAYANIM 1607 +#define B_PR_PAL 1608 +#define B_PR_FULL 1609 +#define B_PR_PRV 1610 +#define B_PR_HD 1611 +#define B_PR_PAL169 1612 + +#define B_REDRAWDISP 1615 +#define B_SETBROWSE 1616 +#define B_CLEARSET 1617 +#define B_PR_PRESET 1618 +#define B_PR_PANO 1619 +#define B_PR_NTSC 1620 + +#define B_IS_FTYPE 1622 +#define B_IS_BACKBUF 1623 +#define B_PR_PC 1624 + +#define B_PR_PANO360 1627 +#define B_PR_HALFFIELDS 1628 +#define B_NEWRENDERPIPE 1629 +#define B_R_SCALE 1630 +#define B_G_SCALE 1631 +#define B_B_SCALE 1632 +#define B_USE_R_SCALE 1633 +#define B_USE_G_SCALE 1634 +#define B_USE_B_SCALE 1635 +#define B_EDGECOLSLI 1636 +#define B_GAMMASLI 1637 + +#define B_FILETYPEMENU 1638 +#define B_SELECTCODEC 1639 +#define B_RTCHANGED 1640 +#define B_SWITCHRENDER 1641 +#define B_FBUF_REDO 1642 + +#define B_SET_EDGE 1643 +#define B_SET_ZBLUR 1644 +#define B_ADD_RENDERLAYER 1645 +#define B_SET_PASS 1646 + +/* *********************** */ +#define B_ARMATUREBUTS 1800 +#define B_POSE 1701 + +/* *********************** */ +#define B_COMMONEDITBUTS 2049 + +#define B_CHANGEDEP 2002 +#define B_MATWICH 2003 +#define B_MATNEW 2004 +#define B_MATDEL 2005 +#define B_MATASS 2006 +#define B_MATSEL 2007 +#define B_MATDESEL 2008 +#define B_HIDE 2009 +#define B_REVEAL 2010 +#define B_SELSWAP 2011 +#define B_SETSMOOTH 2012 +#define B_SETSOLID 2013 +#define B_AUTOTEX 2014 +#define B_DOCENTER 2015 +#define B_DOCENTERNEW 2016 +#define B_DOCENTERCURSOR 2017 + + /* 20 values! */ +#define B_OBLAY 2019 + +#define B_ADDKEY 2041 +#define B_SETKEY 2042 +#define B_DELKEY 2043 +#define B_NAMEKEY 2044 +#define B_PREVKEY 2045 +#define B_NEXTKEY 2046 +#define B_LOCKKEY 2047 + +#define B_MESHBUTS 2090 + +#define B_FLIPNORM 2050 +#define B_SPIN 2051 +#define B_SPINDUP 2052 +#define B_EXTR 2053 +#define B_SCREW 2054 +#define B_EXTREP 2055 +#define B_SPLIT 2056 +#define B_REMDOUB 2057 +#define B_SUBDIV 2058 +#define B_FRACSUBDIV 2059 +#define B_XSORT 2060 +#define B_HASH 2061 +#define B_MAKESTICKY 2062 +#define B_DELSTICKY 2063 +#define B_NEWMCOL 2064 +#define B_DELMCOL 2065 +#define B_TOSPHERE 2066 +#define B_DECIM_FACES 2067 +#define B_DECIM_CANCEL 2068 +#define B_DECIM_APPLY 2069 +/* B_SLOWERDRAW and B_FASTERDRAW removed */ +#define B_VERTEXNOISE 2072 +#define B_VERTEXSMOOTH 2073 +#define B_NEWTFACE 2074 +#define B_DELTFACE 2075 +#define B_CHROMADEPTH 2076 +#define B_DRAWEDGES 2077 +#define B_DRAWCREASES 2078 +#define B_SETTFACE 2079 +#define B_SETMCOL 2080 +#define B_JOINTRIA 2081 +#define B_SETTFACE_RND 2082 +#define B_SETMCOL_RND 2083 + +/* *********************** */ +#define B_VGROUPBUTS 2100 + +#define B_NEWVGROUP 2091 +#define B_DELVGROUP 2092 +#define B_ASSIGNVGROUP 2093 +#define B_REMOVEVGROUP 2094 +#define B_SELVGROUP 2095 +#define B_DESELVGROUP 2096 +#define B_AUTOVGROUP 2097 +#define B_LINKEDVGROUP 2098 +#define B_COPYVGROUP 2099 + + + +/* *********************** */ +#define B_CURVEBUTS 2200 + +#define B_CONVERTPOLY 2101 +#define B_CONVERTBEZ 2102 +#define B_CONVERTBSPL 2103 +#define B_CONVERTCARD 2104 +#define B_CONVERTNURB 2105 +#define B_UNIFU 2106 +#define B_ENDPU 2107 +#define B_BEZU 2108 +#define B_UNIFV 2109 +#define B_ENDPV 2110 +#define B_BEZV 2111 +#define B_SETWEIGHT 2112 +#define B_SETW1 2113 +#define B_SETW2 2114 +#define B_SETW3 2115 +#define B_SETORDER 2116 +#define B_MAKEDISP 2117 +#define B_SUBDIVCURVE 2118 +#define B_SPINNURB 2119 +#define B_CU3D 2120 +#define B_SETRESOLU 2121 +#define B_SETW4 2122 +#define B_SUBSURFTYPE 2123 +#define B_TILTINTERP 2124 + +/* *********************** */ +#define B_FONTBUTS 2300 + +#define B_MAKEFONT 2201 +#define B_TOUPPER 2202 +#define B_SETFONT 2203 +#define B_LOADFONT 2204 +#define B_TEXTONCURVE 2205 +#define B_PACKFONT 2206 +#define B_LOAD3DTEXT 2207 +#define B_LOREM 2208 +#define B_FASTFONT 2209 +#define B_INSTB 2210 +#define B_DELTB 2211 +#define B_STYLETOSELB 2212 +#define B_STYLETOSELU 2213 +#define B_STYLETOSELI 2214 + +#define B_SETCHAR 2215 +#define B_SETUPCHAR 2216 +#define B_SETDOWNCHAR 2217 +#define B_SETCAT 2218 +#define B_SETUNITEXT 2219 + +/* *********************** */ +#define B_ARMBUTS 2400 + +#define B_ARM_RECALCDATA 2301 +#define B_ARM_STRIDE 2302 +#define B_ARM_CALCPATHS 2303 +#define B_ARM_CLEARPATHS 2304 + +/* *********************** */ +#define B_CAMBUTS 2500 + +/* *********************** */ +#define B_MBALLBUTS 2600 + +#define B_RECALCMBALL 2501 + +/* *********************** */ +#define B_LATTBUTS 2700 + +#define B_RESIZELAT 2601 +#define B_DRAWLAT 2602 +#define B_LATTCHANGED 2603 +#define B_REGULARLAT 2604 + +/* *********************** */ +#define B_GAMEBUTS 2800 + +#define B_ADD_PROP 2701 +#define B_CHANGE_PROP 2702 + +#define B_ADD_SENS 2703 +#define B_CHANGE_SENS 2704 +#define B_DEL_SENS 2705 + +#define B_ADD_CONT 2706 +#define B_CHANGE_CONT 2707 +#define B_DEL_CONT 2708 + +#define B_ADD_ACT 2709 +#define B_CHANGE_ACT 2710 +#define B_DEL_ACT 2711 + +#define B_SOUNDACT_BROWSE 2712 + +#define B_SETSECTOR 2713 +#define B_SETPROP 2714 +#define B_SETACTOR 2715 +#define B_SETMAINACTOR 2716 +#define B_SETDYNA 2717 + +/* *********************** */ +#define B_FPAINTBUTS 2900 + +#define B_VPCOLSLI 2801 +#define B_VPGAMMA 2802 + +#define B_COPY_TF_MODE 2804 +#define B_COPY_TF_UV 2805 +#define B_COPY_TF_COL 2806 +#define B_REDR_3D_IMA 2807 +#define B_SET_VCOL 2808 + +#define B_COPY_TF_TEX 2814 +#define B_TFACE_HALO 2815 +#define B_TFACE_BILLB 2816 + +#define B_SHOWTEX 2832 +#define B_ASSIGNMESH 2833 + +#define B_WEIGHT0_0 2840 +#define B_WEIGHT1_4 2841 +#define B_WEIGHT1_2 2842 +#define B_WEIGHT3_4 2843 +#define B_WEIGHT1_0 2844 + +#define B_OPA1_8 2845 +#define B_OPA1_4 2846 +#define B_OPA1_2 2847 +#define B_OPA3_4 2848 +#define B_OPA1_0 2849 + +#define B_CLR_WPAINT 2850 + +#define B_BRUSHBROWSE 2851 +#define B_BRUSHDELETE 2852 +#define B_BRUSHLOCAL 2853 +#define B_BRUSHCHANGE 2854 +#define B_BTEXBROWSE 2855 +#define B_BTEXDELETE 2856 +#define B_BRUSHKEEPDATA 2857 + +/* Sculptmode */ +#define B_SCULPT_TEXBROWSE 2860 + +/* *********************** */ +#define B_RADIOBUTS 3000 + +#define B_RAD_GO 2901 +#define B_RAD_INIT 2902 +#define B_RAD_LIMITS 2903 +#define B_RAD_FAC 2904 +#define B_RAD_NODELIM 2905 +#define B_RAD_NODEFILT 2906 +#define B_RAD_FACEFILT 2907 +#define B_RAD_ADD 2908 +#define B_RAD_DELETE 2909 +#define B_RAD_COLLECT 2910 +#define B_RAD_SHOOTP 2911 +#define B_RAD_SHOOTE 2912 +#define B_RAD_REPLACE 2913 +#define B_RAD_DRAW 2914 +#define B_RAD_FREE 2915 +#define B_RAD_ADDMESH 2916 + +/* *********************** */ +#define B_SCRIPTBUTS 3100 + +#define B_SCRIPT_ADD 3001 +#define B_SCRIPT_DEL 3002 +#define B_SCRIPT_TYPE 3003 + +/* Scene script buttons */ +#define B_SSCRIPT_ADD 3004 +#define B_SSCRIPT_DEL 3005 +#define B_SSCRIPT_TYPE 3006 + +/* *********************** */ +#define B_SOUNDBUTS 3200 +enum B_SOUND_BUTTONS { + B_SOUND_CHANGED = 3101, + B_SOUND_REDRAW, + B_SOUND_VOLUME, + B_SOUND_PANNING, + B_SOUND_PITCH, + B_SOUND_LOAD_SAMPLE, + B_SOUND_MENU_SAMPLE, + B_SOUND_NAME_SAMPLE, + B_SOUND_UNLINK_SAMPLE, + B_SOUND_RELOAD_SAMPLE, + B_SOUND_UNPACK_SAMPLE, + B_SOUND_PLAY_SAMPLE, + B_SOUND_COPY_SOUND, + B_SOUND_LOOPSTART, + B_SOUND_LOOPEND, + B_SOUND_BIDIRECTIONAL, + B_SOUND_RECALC, + B_SOUND_RATECHANGED, + B_SOUND_MIXDOWN +}; + +/* *********************** */ +#define B_CONSTRAINTBUTS 3300 +enum { + B_CONSTRAINT_TEST = 3201, + B_CONSTRAINT_CHANGETARGET, + B_CONSTRAINT_ADD_NULL, + B_CONSTRAINT_ADD_KINEMATIC, + B_CONSTRAINT_ADD_TRACKTO, + B_CONSTRAINT_ADD_MINMAX, + B_CONSTRAINT_ADD_ROTLIKE, + B_CONSTRAINT_ADD_LOCLIKE, + B_CONSTRAINT_ADD_SIZELIKE, + B_CONSTRAINT_ADD_ACTION, + B_CONSTRAINT_ADD_LOCKTRACK, + B_CONSTRAINT_ADD_FOLLOWPATH, + B_CONSTRAINT_ADD_DISTANCELIMIT, + B_CONSTRAINT_ADD_STRETCHTO, + B_CONSTRAINT_ADD_LOCLIMIT, + B_CONSTRAINT_ADD_ROTLIMIT, + B_CONSTRAINT_ADD_SIZELIMIT, + B_CONSTRAINT_ADD_RIGIDBODYJOINT, + B_CONSTRAINT_ADD_CHILDOF, + B_CONSTRAINT_ADD_PYTHON, + B_CONSTRAINT_ADD_CLAMPTO, + B_CONSTRAINT_ADD_TRANSFORM, + B_CONSTRAINT_INF +}; + +/* *********************** */ +#define B_UVAUTOCALCBUTS 3400 +enum { + B_UVAUTO_REDRAW = 3301, + B_UVAUTO_SPHERE, + B_UVAUTO_CYLINDER, + B_UVAUTO_CYLRADIUS, + B_UVAUTO_WINDOW, + B_UVAUTO_CUBE, + B_UVAUTO_CUBESIZE, + B_UVAUTO_RESET, + B_UVAUTO_BOUNDS, + B_UVAUTO_TOP, + B_UVAUTO_FACE, + B_UVAUTO_OBJECT, + B_UVAUTO_ALIGNX, + B_UVAUTO_ALIGNY, + B_UVAUTO_UNWRAP, + B_UVAUTO_DRAWFACES +}; + +#define B_EFFECTSBUTS 3500 + +#define B_AUTOTIMEOFS 3403 +#define B_FRAMEMAP 3404 +#define B_NEWEFFECT 3405 +#define B_PREVEFFECT 3406 +#define B_NEXTEFFECT 3407 +#define B_CHANGEEFFECT 3408 +#define B_CALCEFFECT 3409 +#define B_DELEFFECT 3410 +#define B_RECALCAL 3411 +#define B_RECALC_DEFL 3412 +#define B_EFFECT_DEP 3413 +#define B_FIELD_DEP 3414 +#define B_FIELD_CHANGE 3415 +#define B_PAF_SET_VG 3416 +#define B_PAF_SET_VG1 3417 + +#define B_MODIFIER_BUTS 3600 + +#define B_MODIFIER_RECALC 3501 +#define B_MODIFIER_REDRAW 3502 + +/* *********************** */ +#define B_NODE_BUTS 4000 + /* 400 slots reserved, we want an exec event for each node */ +#define B_NODE_LOADIMAGE 3601 +#define B_NODE_TREE_EXEC 3602 + + /* exec should be last in this list */ +#define B_NODE_EXEC 3610 + + +/* *********************** */ +/* BUTTON 4001-4032: layers? (sort this out!) */ + +/* *********************** */ +/* event code 0x4000 (16384) and larger: general events (redraws, etc) */ + + +#endif + diff --git a/source/blender/include/datatoc.h b/source/blender/include/datatoc.h new file mode 100644 index 00000000000..7afd4428d70 --- /dev/null +++ b/source/blender/include/datatoc.h @@ -0,0 +1,63 @@ +/* + * datatoc.h + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef DATATOC_H +#define DATATOC_H + +extern int datatoc_B_blend_size; +extern char datatoc_B_blend[]; + +extern int datatoc_Bfs_size; +extern char datatoc_Bfs[]; + +extern int datatoc_blenderbuttons_size; +extern char datatoc_blenderbuttons[]; + +extern int datatoc_prvicons_size; +extern char datatoc_prvicons[]; + +extern int datatoc_Bfont_size; +extern char datatoc_Bfont[]; + +extern int datatoc_bfont_ttf_size; +extern char datatoc_bfont_ttf[]; + +extern int datatoc_cmap_tga_size; +extern char datatoc_cmap_tga[]; + +extern int datatoc_cmovie_tga_size; +extern char datatoc_cmovie_tga[]; + +#endif /* DATATOC_H */ + diff --git a/source/blender/include/editlattice_ext.h b/source/blender/include/editlattice_ext.h new file mode 100644 index 00000000000..afb109df5f7 --- /dev/null +++ b/source/blender/include/editlattice_ext.h @@ -0,0 +1,42 @@ +/* + * editlattice_ext.h + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef EDITLATTICE_EXT_H +#define EDITLATTICE_EXT_H "$Id$" +#define EDITLATTICE_EXT_H "Copyright (C) 2001 NaN Technologies B.V. + +void end_latt_deform(void); + +#endif /* EDITLATTICE_EXT_H */ + diff --git a/source/blender/include/editmesh.h b/source/blender/include/editmesh.h new file mode 100644 index 00000000000..1b2d91e22b8 --- /dev/null +++ b/source/blender/include/editmesh.h @@ -0,0 +1,110 @@ +/** + * $Id: + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* Internal for editmesh_xxxx.c functions */ + +#ifndef EDITMESH_H +#define EDITMESH_H + +#define TEST_EDITMESH if(G.obedit==0) return; \ + if( (G.vd->lay & G.obedit->lay)==0 ) return; + +#define UVCOPY(t, s) memcpy(t, s, 2 * sizeof(float)); + + + +/* ******************* editmesh.c */ +extern void free_editvert(EditVert *eve); +extern void free_editedge(EditEdge *eed); +extern void free_editface(EditFace *efa); + +extern void free_vertlist(ListBase *edve); +extern void free_edgelist(ListBase *lb); +extern void free_facelist(ListBase *lb); + +extern void remedge(EditEdge *eed); + +extern struct EditVert *addvertlist(float *vec, struct EditVert *example); +extern struct EditEdge *addedgelist(struct EditVert *v1, struct EditVert *v2, struct EditEdge *example); +extern struct EditFace *addfacelist(struct EditVert *v1, struct EditVert *v2, struct EditVert *v3, struct EditVert *v4, struct EditFace *example, struct EditFace *exampleEdges); +extern struct EditEdge *findedgelist(struct EditVert *v1, struct EditVert *v2); + +/* ******************* editmesh_add.c */ + + +/* ******************* editmesh_lib.c */ +extern void EM_fgon_flags(void); +extern void EM_hide_reset(void); + +extern int faceselectedOR(EditFace *efa, int flag); +extern int faceselectedAND(EditFace *efa, int flag); + +extern EditFace *exist_face(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4); +extern void flipface(EditFace *efa); // flips for normal direction +extern int compareface(EditFace *vl1, EditFace *vl2); + +/* flag for selection bits, *nor will be filled with normal for extrusion constraint */ +/* return value defines if such normal was set */ +extern short extrudeflag_face_indiv(short flag, float *nor); +extern short extrudeflag_verts_indiv(short flag, float *nor); +extern short extrudeflag_edges_indiv(short flag, float *nor); +extern short extrudeflag_vert(short flag, float *nor); +extern short extrudeflag(short flag, float *nor); + +extern void adduplicateflag(int flag); +extern void delfaceflag(int flag); + +extern void rotateflag(short flag, float *cent, float rotmat[][3]); +extern void translateflag(short flag, float *vec); + +extern int convex(float *v1, float *v2, float *v3, float *v4); + +/* ******************* editmesh_mods.c */ +extern EditEdge *findnearestedge(int *dist); +extern void EM_automerge(int update); + +/** + * findnearestvert + * + * dist (in/out): minimal distance to the nearest and at the end, actual distance + * sel: selection bias + * if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts + * if 0, unselected vertice are given the bias + * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased + */ +extern EditVert *findnearestvert(int *dist, short sel, short strict); + +/* ******************* editmesh_tools.c */ + + +#endif + diff --git a/source/blender/include/interface.h b/source/blender/include/interface.h new file mode 100644 index 00000000000..d8e779b9af8 --- /dev/null +++ b/source/blender/include/interface.h @@ -0,0 +1,236 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef INTERFACE_H +#define INTERFACE_H + +#include "BIF_resources.h" + +/* general defines */ + +#define UI_MAX_DRAW_STR 400 +#define UI_MAX_NAME_STR 64 +#define UI_ARRAY 29 + +/* panel limits */ +#define UI_PANEL_MINX 100 +#define UI_PANEL_MINY 70 + +/* uiBut->flag */ +#define UI_SELECT 1 +#define UI_MOUSE_OVER 2 +#define UI_ACTIVE 4 +#define UI_HAS_ICON 8 +/* warn: rest of uiBut->flag in BIF_interface.c */ + + +/* internal panel drawing defines */ +#define PNL_GRID 4 +#define PNL_DIST 8 +#define PNL_SAFETY 8 +#define PNL_HEADER 20 + +/* panel->flag */ +#define PNL_SELECT 1 +#define PNL_CLOSEDX 2 +#define PNL_CLOSEDY 4 +#define PNL_CLOSED 6 +#define PNL_TABBED 8 +#define PNL_OVERLAP 16 + +/* Button text selection: + * extension direction, selextend, inside ui_do_but_TEX */ +#define EXTEND_LEFT 1 +#define EXTEND_RIGHT 2 + +typedef struct { + short xim, yim; + unsigned int *rect; + short xofs, yofs; +} uiIconImage; + +typedef struct { + short mval[2]; + short qual, val; + int event; +} uiEvent; + +typedef struct { + void *xl, *large, *medium, *small; +} uiFont; + +typedef struct uiLinkLine { /* only for draw/edit */ + struct uiLinkLine *next, *prev; + + short flag, pad; + + struct uiBut *from, *to; +} uiLinkLine; + +typedef struct { + void **poin; /* pointer to original pointer */ + void ***ppoin; /* pointer to original pointer-array */ + short *totlink; /* if pointer-array, here is the total */ + + short maxlink, pad; + short fromcode, tocode; + + ListBase lines; +} uiLink; + +struct uiBut { + struct uiBut *next, *prev; + short type, pointype, bit, bitnr, retval, strwidth, ofs, pos, selsta, selend; + int flag; + + char *str; + char strdata[UI_MAX_NAME_STR]; + char drawstr[UI_MAX_DRAW_STR]; + + float x1, y1, x2, y2; + + char *poin; + float min, max; + float a1, a2, hsv[3]; // hsv is temp memory for hsv buttons + float aspect; + + void (*func)(void *, void *); + void *func_arg1; + void *func_arg2; + + void (*embossfunc)(int , int , float, float, float, float, float, int); + void (*sliderfunc)(int , float, float, float, float, float, float, int); + + void (*autocomplete_func)(char *, void *); + void *autofunc_arg; + + uiLink *link; + + char *tip, *lockstr; + + int themecol; /* themecolor id */ + void *font; + + BIFIconID icon; + short but_align; /* aligning buttons, horiz/vertical */ + short lock, win; + short iconadd, dt; + + /* IDPOIN data */ + uiIDPoinFuncFP idpoin_func; + ID **idpoin_idpp; + + /* BLOCK data */ + uiBlockFuncFP block_func; + + /* BUTM data */ + void (*butm_func)(void *arg, int event); + void *butm_func_arg; + + /* pointer back */ + uiBlock *block; +}; + +struct uiBlock { + uiBlock *next, *prev; + + ListBase buttons; + Panel *panel; + + char name[UI_MAX_NAME_STR]; + + float winmat[4][4]; + + float minx, miny, maxx, maxy; + float aspect; + + void (*butm_func)(void *arg, int event); + void *butm_func_arg; + + void (*func)(void *arg1, void *arg2); + void *func_arg1; + void *func_arg2; + + /* extra draw function for custom blocks */ + void (*drawextra)(); + + int themecol; /* themecolor id */ + + short font; /* indices */ + int afterval, flag; + void *curfont; + + short autofill, win, winq, direction, dt; + short needflush, auto_open, in_use, pad; //flush see below + void *overdraw; + struct uiBlock *parent; // nested pulldowns + + float xofs, yofs; // offset to parent button + rctf parentrct; // for pulldowns, rect the mouse is allowed outside of menu (parent button) + rctf safety; // pulldowns, to detect outside, can differ per case how it is created + + rctf flush; // rect to be flushed to frontbuffer + int handler; // for panels in other windows than buttonswin... just event code +}; + +/* interface.c */ + +extern void ui_graphics_to_window(int win, float *x, float *y); +extern void ui_graphics_to_window_rct(int win, rctf *graph, rcti *winr); +extern void ui_window_to_graphics(int win, float *x, float *y); + +extern void ui_block_flush_back(uiBlock *block); +extern void ui_block_set_flush(uiBlock *block, uiBut *but); + +extern void ui_check_but(uiBut *but); +extern double ui_get_but_val(uiBut *but); +extern void ui_get_but_vectorf(uiBut *but, float *vec); +extern void ui_set_but_vectorf(uiBut *but, float *vec); +extern void ui_autofill(uiBlock *block); + +/* interface_panel.c */ +extern void ui_draw_panel(uiBlock *block); +extern void ui_do_panel(uiBlock *block, uiEvent *uevent); +extern void ui_scale_panel(uiBlock *block); +extern void gl_round_box(int mode, float minx, float miny, float maxx, float maxy, float rad); +extern void gl_round_box_shade(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadetop, float shadedown); + +/* interface_draw.c */ +extern void ui_set_embossfunc(uiBut *but, int drawtype); +extern void ui_draw_but(uiBut *but); +extern void ui_rasterpos_safe(float x, float y, float aspect); +extern void ui_draw_tria_icon(float x, float y, float aspect, char dir); +extern void ui_draw_anti_x(float x1, float y1, float x2, float y2); +extern void ui_dropshadow(rctf *rct, float radius, float aspect, int select); + +#endif + diff --git a/source/blender/include/keyed_functions.h b/source/blender/include/keyed_functions.h new file mode 100644 index 00000000000..405fec16992 --- /dev/null +++ b/source/blender/include/keyed_functions.h @@ -0,0 +1,58 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#define KEY_GETPTR(x) (g_ptrtab ? g_ptrtab[x] : 0) + +/* these are the defines for the keyed functions: + + #define key_func + + This function must be of type "int func(void*)" + + To prevent symbol table dumpers from retrieving certain key + functions too easily, some of those functions have nonsense names. +*/ + +#define key_func1 key_return_true +/* add the corresponding function pointer defines here. + Example: + + #define key_func4 my_protected_function_name + #define MY_PROTECTED_FUNCTION_PTR KEY_GETPTR(KEY_FUNC3) + + KEY_GETPTR(KEY_FUNC3) corresponds to the function pointer to function + key_func3 after the python key code unscrambled the function pointer tables. + Also add pointer initializations to these functions in + license_key.c:init_ftable() if necessary. +*/ + +#define KEY_RETURN_TRUE KEY_GETPTR(KEY_FUNC1) + diff --git a/source/blender/include/license_key.h b/source/blender/include/license_key.h new file mode 100644 index 00000000000..1346998f520 --- /dev/null +++ b/source/blender/include/license_key.h @@ -0,0 +1,95 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef LICENCEKEY_H +#define LICENCEKEY_H + +#define I_AM_PUBLISHER temp_val2 +#define LICENSE_KEY_VALID temp_val +#define SHOW_LICENSE_KEY rotop + +extern int LICENSE_KEY_VALID; +extern int I_AM_PUBLISHER; + +extern char * license_key_name; +extern void loadKeyboard(char * name); +extern void checkhome(void); +extern void SHOW_LICENSE_KEY(void); + +#define LICENSE_CHECK_0 (0==0) + +// Stuff from the Python files from Strubi + +typedef int (*Fptr)(void *); + +extern Fptr g_functab[]; +extern Fptr g_ptrtab[]; + +// TODO: From here on, this should be a generated header file... + +// change all KEY_FUNC values +// if you change PYKEY_TABLEN or PYKEY_SEED +// see below + +#define PYKEY_TABLEN 21 // don't change this unless needed. Other values + // may yield bad random orders + +#define PYKEY_SEED {26,8,1972} + +// these values are generated by $HOME/develop/intern/keymaker/makeseed.py +// from the above seed value. + +// DO NOT EDIT THESE VALUES BY HAND! + +#define KEY_FUNC1 12 +#define KEY_FUNC2 8 +#define KEY_FUNC3 1 +#define KEY_FUNC4 16 +#define KEY_FUNC5 20 +#define KEY_FUNC6 18 +#define KEY_FUNC7 13 +#define KEY_FUNC8 6 +#define KEY_FUNC9 9 +#define KEY_FUNC10 7 +#define KEY_FUNC11 14 +#define KEY_FUNC12 0 +#define KEY_FUNC13 5 +#define KEY_FUNC14 10 +#define KEY_FUNC15 19 +#define KEY_FUNC16 2 +#define KEY_FUNC17 11 +#define KEY_FUNC18 3 +#define KEY_FUNC19 17 +#define KEY_FUNC20 15 +#define KEY_FUNC21 4 + +#endif + diff --git a/source/blender/include/multires.h b/source/blender/include/multires.h new file mode 100644 index 00000000000..bfa765e62ef --- /dev/null +++ b/source/blender/include/multires.h @@ -0,0 +1,81 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 by Nicholas Bishop + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef MULTIRES_H +#define MULTIRES_H + +struct CustomData; +struct EditMesh; +struct Object; +struct MDeformVert; +struct Mesh; +struct MultiresLevel; +struct Multires; +struct uiBlock; + +/* For canceling operations that don't work with multires on or on a non-base level */ +int multires_test(); +int multires_level1_test(); + +struct MultiresLevel *multires_level_n(struct Multires *mr, int n); + +void multires_draw_interface(struct uiBlock *block, unsigned short cx, unsigned short cy); +void multires_disp_map(void *, void*); + +void multires_make(void *ob, void *me); +void multires_delete(void *ob, void *me); +struct Multires *multires_copy(struct Multires *orig); +void multires_free(struct Multires *mr); +void multires_free_level(struct MultiresLevel *lvl); +void multires_del_lower(void *ob, void *me); +void multires_del_higher(void *ob, void *me); +void multires_add_level(void *ob, void *me); +void multires_set_level_cb(void *ob, void *me); +void multires_set_level(struct Object *ob, struct Mesh *me, const int render); +void multires_update_levels(struct Mesh *me, const int render); +void multires_level_to_mesh(struct Object *ob, struct Mesh *me, const int render); +void multires_edge_level_update(void *ob, void *me); +int multires_modifier_warning(); + +/* after adding or removing vcolor layers, run this */ +void multires_load_cols(Mesh *me); + +/* multires-firstlevel.c */ +/* Generic */ +void multires_update_first_level(struct Mesh *me, struct EditMesh *em); +void multires_update_customdata(struct MultiresLevel *lvl1, struct CustomData *src, + struct CustomData *dst, const int type); +void multires_customdata_to_mesh(struct Mesh *me, struct EditMesh *em, struct MultiresLevel *lvl, + struct CustomData *src, struct CustomData *dst, const int type); +void multires_del_lower_customdata(struct Multires *mr, struct MultiresLevel *cr_lvl); + +void multires_add_layer(struct Mesh *me, struct CustomData *cd, const int type, const int n); +void multires_delete_layer(struct Mesh *me, struct CustomData *cd, const int type, int n); + +#endif diff --git a/source/blender/include/mydevice.h b/source/blender/include/mydevice.h new file mode 100644 index 00000000000..bec0e13726b --- /dev/null +++ b/source/blender/include/mydevice.h @@ -0,0 +1,260 @@ + +#ifndef __MYDEVICE_H__ +#define __MYDEVICE_H__ + +/* + * This file has its origin at sgi, where all device defines were written down. + * Blender copied this concept quite some, and expanded it with internal new defines (ton) + * + * mouse / timer / window: until 0x020 + * custom codes: 0x4... + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* MOUSE : 0x00x */ + +#define LEFTMOUSE 0x001 +#define MIDDLEMOUSE 0x002 +#define RIGHTMOUSE 0x003 +#define MOUSEX 0x004 +#define MOUSEY 0x005 +#define WHEELUPMOUSE 0x00a +#define WHEELDOWNMOUSE 0x00b + +/* timers */ + +#define TIMER0 0x006 +#define TIMER1 0x007 +#define TIMER2 0x008 +#define TIMER3 0x009 + +/* SYSTEM : 0x01x */ + +#define KEYBD 0x010 /* keyboard */ +#define RAWKEYBD 0x011 /* raw keyboard for keyboard manager */ +#define REDRAW 0x012 /* used by port manager to signal redraws */ +#define INPUTCHANGE 0x013 /* input connected or disconnected */ +#define QFULL 0x014 /* queue was filled */ +#define WINFREEZE 0x015 /* user wants process in this win to shut up */ +#define WINTHAW 0x016 /* user wants process in this win to go again */ +#define WINCLOSE 0x017 /* window close */ +#define WINQUIT 0x018 /* signal from user that app is to go away */ +#define Q_FIRSTTIME 0x019 /* on startup */ + +/* standard keyboard */ + +#define AKEY 'a' +#define BKEY 'b' +#define CKEY 'c' +#define DKEY 'd' +#define EKEY 'e' +#define FKEY 'f' +#define GKEY 'g' +#define HKEY 'h' +#define IKEY 'i' +#define JKEY 'j' +#define KKEY 'k' +#define LKEY 'l' +#define MKEY 'm' +#define NKEY 'n' +#define OKEY 'o' +#define PKEY 'p' +#define QKEY 'q' +#define RKEY 'r' +#define SKEY 's' +#define TKEY 't' +#define UKEY 'u' +#define VKEY 'v' +#define WKEY 'w' +#define XKEY 'x' +#define YKEY 'y' +#define ZKEY 'z' + +#define ZEROKEY '0' +#define ONEKEY '1' +#define TWOKEY '2' +#define THREEKEY '3' +#define FOURKEY '4' +#define FIVEKEY '5' +#define SIXKEY '6' +#define SEVENKEY '7' +#define EIGHTKEY '8' +#define NINEKEY '9' + +#define CAPSLOCKKEY 211 + +#define LEFTCTRLKEY 212 +#define LEFTALTKEY 213 +#define RIGHTALTKEY 214 +#define RIGHTCTRLKEY 215 +#define RIGHTSHIFTKEY 216 +#define LEFTSHIFTKEY 217 + +#define ESCKEY 218 +#define TABKEY 219 +#define RETKEY 220 +#define SPACEKEY 221 +#define LINEFEEDKEY 222 +#define BACKSPACEKEY 223 +#define DELKEY 224 +#define SEMICOLONKEY 225 +#define PERIODKEY 226 +#define COMMAKEY 227 +#define QUOTEKEY 228 +#define ACCENTGRAVEKEY 229 +#define MINUSKEY 230 +#define SLASHKEY 232 +#define BACKSLASHKEY 233 +#define EQUALKEY 234 +#define LEFTBRACKETKEY 235 +#define RIGHTBRACKETKEY 236 + +#define LEFTARROWKEY 137 +#define DOWNARROWKEY 138 +#define RIGHTARROWKEY 139 +#define UPARROWKEY 140 + +#define PAD0 150 +#define PAD1 151 +#define PAD2 152 +#define PAD3 153 +#define PAD4 154 +#define PAD5 155 +#define PAD6 156 +#define PAD7 157 +#define PAD8 158 +#define PAD9 159 + + +#define PADPERIOD 199 +#define PADSLASHKEY 161 +#define PADASTERKEY 160 + + +#define PADMINUS 162 +#define PADENTER 163 +#define PADPLUSKEY 164 + + +#define F1KEY 300 +#define F2KEY 301 +#define F3KEY 302 +#define F4KEY 303 +#define F5KEY 304 +#define F6KEY 305 +#define F7KEY 306 +#define F8KEY 307 +#define F9KEY 308 +#define F10KEY 309 +#define F11KEY 310 +#define F12KEY 311 + +#define PAUSEKEY 165 +#define INSERTKEY 166 +#define HOMEKEY 167 +#define PAGEUPKEY 168 +#define PAGEDOWNKEY 169 +#define ENDKEY 170 + +#define UNKNOWNKEY 171 +#define COMMANDKEY 172 +#define GRLESSKEY 173 + +/* used as fake leftmouse events, special handled in interface.c */ +#define BUT_ACTIVATE 200 +#define BUT_NEXT 201 +#define BUT_PREV 202 + +/* **************** BLENDER QUEUE EVENTS ********************* */ + +#define CHANGED 0x4000 +#define DRAWEDGES 0x4001 +#define AFTERQUEUE 0x4002 +#define BACKBUFDRAW 0x4003 +#define EXECUTE 0x4004 +#define IGNORE_REDRAW 0x4005 +#define LOAD_FILE 0x4006 +#define RESHAPE 0x4007 +#define UI_BUT_EVENT 0x4008 +#define AUTOSAVE_FILE 0x4009 +#define UNDOPUSH 0x400A + +/* REDRAWVIEW3D has to be the first one (lowest number) for buttons! */ +#define REDRAWVIEW3D 0x4010 +#define REDRAWVIEWCAM 0x4011 +#define REDRAWVIEW3D_Z 0x4012 + +#define REDRAWALL 0x4013 +#define REDRAWHEADERS 0x4014 + +#define REDRAWBUTSHEAD 0x4015 +#define REDRAWBUTSALL 0x4016 + +#define REDRAWBUTSSCENE 0x4017 +#define REDRAWBUTSOBJECT 0x4018 +#define REDRAWBUTSEDIT 0x4019 +#define REDRAWBUTSSCRIPT 0x401A +#define REDRAWBUTSLOGIC 0x401B +#define REDRAWBUTSSHADING 0x401C +#define REDRAWBUTSGAME 0x401D +#define REDRAWBUTSEFFECTS 0x401D + +#define REDRAWINFO 0x4021 +#define RENDERPREVIEW 0x4022 +#define REDRAWIPO 0x4023 +#define REDRAWDATASELECT 0x4024 +#define REDRAWSEQ 0x4025 +#define REDRAWIMAGE 0x4026 +#define REDRAWOOPS 0x4027 +#define REDRAWIMASEL 0x4028 +#define AFTERIMASELIMA 0x4029 +#define AFTERIMASELGET 0x402A +#define AFTERIMAWRITE 0x402B +#define IMALEFTMOUSE 0x402C +#define AFTERPIBREAD 0x402D +#define REDRAWTEXT 0x402E +#define REDRAWSOUND 0x402F +#define REDRAWACTION 0x4030 +#define REDRAWNLA 0x4031 +#define REDRAWSCRIPT 0x4032 +#define REDRAWTIME 0x4033 +#define REDRAWBUTSCONSTRAINT 0x4034 +#define ONLOAD_SCRIPT 0x4035 +#define SCREEN_HANDLER 0x4036 +#define REDRAWANIM 0x4037 +#define REDRAWNODE 0x4038 +#define RECALC_COMPOSITE 0x4039 +#define REDRAWMARKER 0x4040 /* all views that display markers */ +#define REDRAWVIEW3D_IMAGE 0x4041 + +#endif /* !__MYDEVICE_H__ */ + diff --git a/source/blender/include/nla.h b/source/blender/include/nla.h new file mode 100644 index 00000000000..f07121bd56b --- /dev/null +++ b/source/blender/include/nla.h @@ -0,0 +1,59 @@ +/* nla.h May 2001 + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + * Use this to turn experimental options on + * or off with the #define flags. Please do not + * put other includes, typdefs etc in this file. + * =========================================== + * + * __NLA + * This encompasses the new armature object, the + * action datablock and the action window-type. + * + * __CON_IPO + * Support for constraint ipo keys + * + * __NLA_ACTION_BY_MOTION_ACTUATOR + * New action actuator playback type + * + * $Id$ + */ + +#ifndef NLA_H +#define NLA_H + +#define __NLA + +#define __CON_IPO // Not for Release: Not yet fully implemented +//#define __NLA_ACTION_BY_MOTION_ACTUATOR // Not for release: Not yet fully implemented + +#endif + diff --git a/source/blender/include/objfnt.h b/source/blender/include/objfnt.h new file mode 100644 index 00000000000..e54b7b5e1e3 --- /dev/null +++ b/source/blender/include/objfnt.h @@ -0,0 +1,105 @@ +/* $Id$ +*/ +/* + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +#ifndef OBJFNTDEF +#define OBJFNTDEF + +typedef struct chardesc { + short movex, movey; /* advance */ + short llx, lly; /* bounding box */ + short urx, ury; + short *data; /* char data */ + long datalen; +} chardesc; + +typedef struct objfnt { + struct objfnt *freeaddr; /* if freeaddr != 0, objfnt is one chunck */ + short type; + short charmin, charmax; + short my_nchars; + short scale; + chardesc *my_chars; +} objfnt; + +#define OFMAGIC 0x93339333 + +#define TM_TYPE 1 +#define PO_TYPE 2 +#define SP_TYPE 3 + +/* ops for tmesh characters */ + +#define TM_BGNTMESH (1) +#define TM_SWAPTMESH (2) +#define TM_ENDBGNTMESH (3) +#define TM_RETENDTMESH (4) +#define TM_RET (5) + +/* ops for poly characters */ + +#define PO_BGNLOOP (1) +#define PO_ENDBGNLOOP (2) +#define PO_RETENDLOOP (3) +#define PO_RET (4) + +/* ops for spline characters */ + +#define SP_MOVETO (1) +#define SP_LINETO (2) +#define SP_CURVETO (3) +#define SP_CLOSEPATH (4) +#define SP_RETCLOSEPATH (5) +#define SP_RET (6) + + +#define MIN_ASCII ' ' +#define MAX_ASCII '~' +#define NASCII (256 - 32) + +#define NOBBOX (30000) + +typedef struct pschar { + char *name; + int code; + int prog; +} pschar; + +extern pschar charlist[NASCII]; + +/* objfnt *fontname(void); */ +/* objfnt *readobjfnt(void); */ +/* objfnt *newobjfnt(void); */ +/* float fontstringwidth(void); */ +/* short *getcharprog(void); */ +/* chardesc *BLI_getchardesc(void); */ +/* char *asciiname(void); */ + +#endif + diff --git a/source/blender/include/particle_effect.h b/source/blender/include/particle_effect.h new file mode 100644 index 00000000000..883331ac740 --- /dev/null +++ b/source/blender/include/particle_effect.h @@ -0,0 +1,47 @@ +/* dec 95 + * jan feb 96 + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef PARTICLE_EFFECT_H +#define PARTICLE_EFFECT_H + +/* effect.c */ +extern Effect *add_effect(int type); +extern PartEff *give_parteff(Object *ob); +extern void where_is_particle(PartEff *paf, Particle *pa, float ctime, float *vec); +extern void free_effect(Effect *eff); +extern void free_effects(ListBase *lb); +extern void copy_effects(ListBase *lbn, ListBase *lb); +extern void build_particle_system(Object *ob); + +#endif + diff --git a/source/blender/include/playanim_ext.h b/source/blender/include/playanim_ext.h new file mode 100644 index 00000000000..bef610ac018 --- /dev/null +++ b/source/blender/include/playanim_ext.h @@ -0,0 +1,41 @@ +/* + * external interface + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef PLAYANIM_EXT_H +#define PLAYANIM_EXT_H + +/* used in apps */ +extern void playanim(int argc, char **argv); + +#endif + diff --git a/source/blender/include/transform.h b/source/blender/include/transform.h new file mode 100644 index 00000000000..a01bf92c871 --- /dev/null +++ b/source/blender/include/transform.h @@ -0,0 +1,452 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef TRANSFORM_H +#define TRANSFORM_H + +#include "BIF_transform.h" + +/* ************************** Types ***************************** */ + +struct TransInfo; +struct TransData; +struct TransSnap; +struct NumInput; +struct Object; +struct View3D; +struct ScrArea; +struct bPose; + + +typedef struct NumInput { + short idx; + short idx_max; + short flag; /* Different flags to indicate different behaviors */ + float val[3]; /* Direct value of the input */ + int ctrl[3]; /* Control to indicate what to do with the numbers that are typed */ +} NumInput ; + +/* + The ctrl value has different meaning: + 0 : No value has been typed + + otherwise, |value| - 1 is where the cursor is located after the period + Positive : number is positive + Negative : number is negative +*/ + +typedef struct TransSnap { + short modePoint; + short modeTarget; + int status; + float snapPoint[3]; + float snapTarget[3]; + float dist; // Distance from snapPoint to snapTarget + double last; + void (*applySnap)(struct TransInfo *, float *); + void (*calcSnap)(struct TransInfo *, float *); + void (*targetSnap)(struct TransInfo *); + float (*distance)(struct TransInfo *, float p1[3], float p2[3]); // Get the transform distance between two points (used by Closest snap) +} TransSnap; + +typedef struct TransCon { + char text[50]; /* Description of the Constraint for header_print */ + float mtx[3][3]; /* Matrix of the Constraint space */ + float imtx[3][3]; /* Inverse Matrix of the Constraint space */ + float pmtx[3][3]; /* Projection Constraint Matrix (same as imtx with some axis == 0) */ + float center[3]; /* transformation center to define where to draw the view widget + ALWAYS in global space. Unlike the transformation center */ + short imval[2]; /* initial mouse value for visual calculation */ + /* the one in TransInfo is not garanty to stay the same (Rotates change it) */ + int mode; /* Mode flags of the Constraint */ + void (*drawExtra)(struct TransInfo *); + /* For constraints that needs to draw differently from the other + uses this instead of the generic draw function */ + void (*applyVec)(struct TransInfo *, struct TransData *, float *, float *, float *); + /* Apply function pointer for linear vectorial transformation */ + /* The last three parameters are pointers to the in/out/printable vectors */ + void (*applySize)(struct TransInfo *, struct TransData *, float [3][3]); + /* Apply function pointer for rotation transformation (prototype will change */ + void (*applyRot)(struct TransInfo *, struct TransData *, float [3]); + /* Apply function pointer for rotation transformation (prototype will change */ +} TransCon; + +typedef struct TransDataIpokey { + int flag; /* which keys */ + float *locx, *locy, *locz; /* channel pointers */ + float *rotx, *roty, *rotz; + float *quatx, *quaty, *quatz, *quatw; + float *sizex, *sizey, *sizez; + float oldloc[9]; /* storage old values */ + float oldrot[9]; + float oldsize[9]; + float oldquat[12]; +} TransDataIpokey; + +typedef struct TransDataExtension { + float drot[3]; /* Initial object drot */ + float dsize[3]; /* Initial object dsize */ + float *rot; /* Rotation of the data to transform (Faculative) */ + float irot[3]; /* Initial rotation */ + float *quat; /* Rotation quaternion of the data to transform (Faculative) */ + float iquat[4]; /* Initial rotation quaternion */ + float *size; /* Size of the data to transform (Faculative) */ + float isize[3]; /* Initial size */ + float obmat[3][3]; /* Object matrix */ +} TransDataExtension; + +typedef struct TransData2D { + float loc[3]; /* Location of data used to transform (x,y,0) */ + float *loc2d; /* Pointer to real 2d location of data */ +} TransData2D; + +typedef struct TransData { + float dist; /* Distance needed to affect element (for Proportionnal Editing) */ + float rdist; /* Distance to the nearest element (for Proportionnal Editing) */ + float factor; /* Factor of the transformation (for Proportionnal Editing) */ + float *loc; /* Location of the data to transform */ + float iloc[3]; /* Initial location */ + float *val; /* Value pointer for special transforms */ + float ival; /* Old value*/ + float center[3]; /* Individual data center */ + float mtx[3][3]; /* Transformation matrix from data space to global space */ + float smtx[3][3]; /* Transformation matrix from global space to data space */ + float axismtx[3][3];/* Axis orientation matrix of the data */ + struct Object *ob; + TransDataExtension *ext; /* for objects, poses. 1 single malloc per TransInfo! */ + TransDataIpokey *tdi; /* for objects, ipo keys. per transdata a malloc */ + void *tdmir; /* mirrored element pointer, in editmode mesh to EditVert */ + short flag; /* Various flags */ + short protectflag; /* If set, copy of Object or PoseChannel protection */ +/*#ifdef WITH_VERSE*/ + void *verse; /* pointer at verse data struct (VerseVert, etc.) */ +/*#endif*/ +} TransData; + +typedef struct TransInfo { + int mode; /* current mode */ + int flag; /* generic flags for special behaviors */ + short state; /* current state (running, canceled,...)*/ + int context; /* current context */ + float val; /* init value for some transformations (and rotation angle) */ + float fac; /* factor for distance based transform */ + int (*transform)(struct TransInfo *, short *); + /* transform function pointer */ + int (*handleEvent)(struct TransInfo *, unsigned short event, short val); + /* event handler function pointer RETURN 1 if redraw is needed */ + int total; /* total number of transformed data */ + TransData *data; /* transformed data (array) */ + TransDataExtension *ext; /* transformed data extension (array) */ + TransData2D *data2d; /* transformed data for 2d (array) */ + TransCon con; /* transformed constraint */ + TransSnap tsnap; + NumInput num; /* numerical input */ + char redraw; /* redraw flag */ + float propsize; /* proportional circle radius */ + char proptext[20]; /* proportional falloff text */ + float center[3]; /* center of transformation */ + int center2d[2]; /* center in screen coordinates */ + short imval[2]; /* initial mouse position */ + short shiftmval[2]; /* mouse position when shift was pressed */ + short idx_max; /* maximum index on the input vector */ + float snap[3]; /* Snapping Gears */ + + float viewmat[4][4]; /* copy from G.vd, prevents feedback, */ + float viewinv[4][4]; /* and to make sure we don't have to */ + float persmat[4][4]; /* access G.vd from other space types */ + float persinv[4][4]; + short persp; + short around; + char spacetype; /* spacetype where transforming is */ + + float vec[3]; /* translation, to show for widget */ + float mat[3][3]; /* rot/rescale, to show for widget */ + + char *undostr; /* if set, uses this string for undo */ + float spacemtx[3][3]; /* orientation matrix of the current space */ + char spacename[32]; /* name of the current space */ + + struct Object *poseobj; /* if t->flag & T_POSE, this denotes pose object */ + + void *customData; /* Per Transform custom data */ +} TransInfo; + + +/* ******************** Macros & Prototypes *********************** */ + +/* NUMINPUT FLAGS */ +#define NUM_NULL_ONE 2 +#define NUM_NO_NEGATIVE 4 +#define NUM_NO_ZERO 8 +#define NUM_NO_FRACTION 16 +#define NUM_AFFECT_ALL 32 + +/* transinfo->state */ +#define TRANS_RUNNING 0 +#define TRANS_CONFIRM 1 +#define TRANS_CANCEL 2 + +/* transinfo->flag */ +#define T_OBJECT (1 << 0) +#define T_EDIT (1 << 1) +#define T_POSE (1 << 2) +#define T_TEXTURE (1 << 3) +#define T_CAMERA (1 << 4) + // when shift pressed, higher resolution transform. cannot rely on G.qual, need event! +#define T_SHIFT_MOD (1 << 5) + // trans on points, having no rotation/scale +#define T_POINTS (1 << 6) + // for manipulator exceptions, like scaling using center point, drawing help lines +#define T_USES_MANIPULATOR (1 << 7) + +/* restrictions flags */ +#define T_ALL_RESTRICTIONS ((1 << 8)|(1 << 9)|(1 << 10)) +#define T_NO_CONSTRAINT (1 << 8) +#define T_NULL_ONE (1 << 9) +#define T_NO_ZERO (1 << 10) + +#define T_PROP_EDIT (1 << 11) +#define T_PROP_CONNECTED (1 << 12) + +/* if MMB is pressed or not */ +#define T_MMB_PRESSED (1 << 13) + +#define T_V3D_ALIGN (1 << 14) +#define T_2D_EDIT (1 << 15) /* for 2d views like uv or ipo */ +#define T_CLIP_UV (1 << 16) + +#define T_FREE_CUSTOMDATA (1 << 17) + +/* ******************************************************************************** */ + +/* transinfo->con->mode */ +#define CON_APPLY 1 +#define CON_AXIS0 2 +#define CON_AXIS1 4 +#define CON_AXIS2 8 +#define CON_SELECT 16 +#define CON_NOFLIP 32 /* does not reorient vector to face viewport when on */ +#define CON_LOCAL 64 +#define CON_USER 128 + +/* transdata->flag */ +#define TD_SELECTED 1 +#define TD_NOACTION 2 +#define TD_USEQUAT 4 +#define TD_NOTCONNECTED 8 +#define TD_SINGLESIZE 16 /* used for scaling of MetaElem->rad */ +#ifdef WITH_VERSE + #define TD_VERSE_OBJECT 32 + #define TD_VERSE_VERT 64 +#endif +#define TD_TIMEONLY 128 +#define TD_NOCENTER 256 + +/* transsnap->status */ +#define SNAP_ON 1 +#define TARGET_INIT 2 +#define POINT_INIT 4 + +/* transsnap->modePoint */ +#define SNAP_GRID 0 +#define SNAP_GEO 1 + +/* transsnap->modeTarget */ +#define SNAP_CLOSEST 0 +#define SNAP_CENTER 1 +#define SNAP_MEDIAN 2 + +void checkFirstTime(void); + +void setTransformViewMatrices(TransInfo *t); +void convertViewVec(TransInfo *t, float *vec, short dx, short dy); +void projectIntView(TransInfo *t, float *vec, int *adr); +void projectFloatView(TransInfo *t, float *vec, float *adr); + +void convertVecToDisplayNum(float *vec, float *num); +void convertDisplayNumToVec(float *num, float *vec); + +void initWarp(TransInfo *t); +int Warp(TransInfo *t, short mval[2]); + +void initShear(TransInfo *t); +int handleEventShear(TransInfo *t, unsigned short evenl, short val); +int Shear(TransInfo *t, short mval[2]); + +void initResize(TransInfo *t); +int Resize(TransInfo *t, short mval[2]); + +void initTranslation(TransInfo *t); +int Translation(TransInfo *t, short mval[2]); + +void initToSphere(TransInfo *t); +int ToSphere(TransInfo *t, short mval[2]); + +void initRotation(TransInfo *t); +int Rotation(TransInfo *t, short mval[2]); + +void initShrinkFatten(TransInfo *t); +int ShrinkFatten(TransInfo *t, short mval[2]); + +void initTilt(TransInfo *t); +int Tilt(TransInfo *t, short mval[2]); + +void initCurveShrinkFatten(TransInfo *t); +int CurveShrinkFatten(TransInfo *t, short mval[2]); + +void initTrackball(TransInfo *t); +int Trackball(TransInfo *t, short mval[2]); + +void initPushPull(TransInfo *t); +int PushPull(TransInfo *t, short mval[2]); + +void initCrease(TransInfo *t); +int Crease(TransInfo *t, short mval[2]); + +void initBoneSize(TransInfo *t); +int BoneSize(TransInfo *t, short mval[2]); + +void initBoneEnvelope(TransInfo *t); +int BoneEnvelope(TransInfo *t, short mval[2]); + +void initBoneRoll(TransInfo *t); +int BoneRoll(TransInfo *t, short mval[2]); + +void initTimeTranslate(TransInfo *t); +int TimeTranslate(TransInfo *t, short mval[2]); + +void initTimeSlide(TransInfo *t); +int TimeSlide(TransInfo *t, short mval[2]); + +void initTimeScale(TransInfo *t); +int TimeScale(TransInfo *t, short mval[2]); + +/*********************** transform_conversions.c ********** */ +struct ListBase; +void flushTransIpoData(TransInfo *t); +void flushTransUVs(TransInfo *t); +int clipUVTransform(TransInfo *t, float *vec, int resize); + +/*********************** exported from transform_manipulator.c ********** */ +void draw_manipulator_ext(struct ScrArea *sa, int type, char axis, int col, float vec[3], float mat[][3]); +int calc_manipulator_stats(struct ScrArea *sa); +float get_drawsize(struct View3D *v3d); + +/*********************** TransData Creation and General Handling *********** */ +void createTransData(TransInfo *t); +void sort_trans_data_dist(TransInfo *t); +void add_tdi_poin(float *poin, float *old, float delta); +void special_aftertrans_update(TransInfo *t); + +/* auto-keying stuff used by special_aftertrans_update */ +void autokeyframe_ob_cb_func(struct Object *ob, int tmode); +void autokeyframe_pose_cb_func(struct Object *ob, int tmode, short targetless_ik); + +/*********************** Constraints *****************************/ + +void getConstraintMatrix(TransInfo *t); +void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]); +void setLocalConstraint(TransInfo *t, int mode, const char text[]); +void setUserConstraint(TransInfo *t, int mode, const char text[]); + +void constraintNumInput(TransInfo *t, float vec[3]); + +void getConstraintMatrix(TransInfo *t); +int isLockConstraint(TransInfo *t); +int getConstraintSpaceDimension(TransInfo *t); +char constraintModeToChar(TransInfo *t); + +void startConstraint(TransInfo *t); +void stopConstraint(TransInfo *t); + +void initSelectConstraint(TransInfo *t, float mtx[3][3]); +void selectConstraint(TransInfo *t); +void postSelectConstraint(TransInfo *t); + +void setNearestAxis(TransInfo *t); + +/*********************** Snapping ********************************/ + +typedef enum { + NO_GEARS = 0, + BIG_GEARS = 1, + SMALL_GEARS = 2 +} GearsType; + +void snapGrid(TransInfo *t, float *val); +void snapGridAction(TransInfo *t, float *val, GearsType action); + +void initSnapping(struct TransInfo *t); +void applySnapping(TransInfo *t, float *vec); +void resetSnapping(TransInfo *t); +int handleSnapping(TransInfo *t, int event); +void drawSnapping(TransInfo *t); + +/*********************** Generics ********************************/ + +void initTrans(TransInfo *t); +void initTransModeFlags(TransInfo *t, int mode); +void postTrans (TransInfo *t); + +void drawLine(float *center, float *dir, char axis, short options); + +/* DRAWLINE options flags */ +#define DRAWLIGHT 1 +#define DRAWDASHED 2 +#define DRAWBOLD 4 + +void applyTransObjects(TransInfo *t); +void restoreTransObjects(TransInfo *t); +void recalcData(TransInfo *t); + +void calculateCenter(TransInfo *t); +void calculateCenter2D(TransInfo *t); +void calculateCenterBound(TransInfo *t); +void calculateCenterMedian(TransInfo *t); +void calculateCenterCursor(TransInfo *t); + +void calculateCenterCursor2D(TransInfo *t); +void calculatePropRatio(TransInfo *t); + +void getViewVector(float coord[3], float vec[3]); + +TransInfo * BIF_GetTransInfo(void); + +/*********************** NumInput ********************************/ + +void outputNumInput(NumInput *n, char *str); +short hasNumInput(NumInput *n); +void applyNumInput(NumInput *n, float *vec); +char handleNumInput(NumInput *n, unsigned short event); + +#endif + diff --git a/source/blender/makesdna/CMakeLists.txt b/source/blender/makesdna/CMakeLists.txt new file mode 100644 index 00000000000..0311c5f0e5a --- /dev/null +++ b/source/blender/makesdna/CMakeLists.txt @@ -0,0 +1,30 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SUBDIRS(intern) diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h new file mode 100644 index 00000000000..d939d0dc879 --- /dev/null +++ b/source/blender/makesdna/DNA_ID.h @@ -0,0 +1,229 @@ +/** + * blenlib/DNA_ID.h (mar-2001 nzc) + * + * ID and Library types, which are fundamental for sdna, + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_ID_H +#define DNA_ID_H + +#include "DNA_listBase.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct Library; +struct FileData; +struct ID; + +typedef struct IDPropertyData { + void *pointer; + ListBase group; + int val, pad; +} IDPropertyData; + +typedef struct IDProperty { + struct IDProperty *next, *prev; + char name[32]; + char type, subtype; + short flag; + int saved; /*saved is used to indicate if this struct has been saved yet. + seemed like a good idea as a pad var was needed anyway :)*/ + IDPropertyData data; /* note, alignment for 64 bits */ + int len; /* array length, also (this is important!) string length + 1. + the idea is to be able to reuse array realloc functions on strings.*/ + /*totallen is total length of allocated array/string, including a buffer. + Note that the buffering is mild; the code comes from python's list implementation.*/ + int totallen; /*strings and arrays are both buffered, though the buffer isn't + saved.*/ +} IDProperty; + +#define MAX_IDPROP_NAME 32 +#define DEFAULT_ALLOC_FOR_NULL_STRINGS 64 + +/*->type*/ +#define IDP_STRING 0 +#define IDP_INT 1 +#define IDP_FLOAT 2 +#define IDP_ARRAY 5 +#define IDP_GROUP 6 +/*the ID link property type hasn't been implemented yet, this will require + some cleanup of blenkernel, most likely.*/ +#define IDP_ID 7 + +/*add any future new id property types here.*/ + +/* watch it: Sequence has identical beginning. */ +/** + * ID is the first thing included in all serializable types. It + * provides a common handle to place all data in double-linked lists. + * */ + +/* There's a nasty circular dependency here.... void* to the rescue! I + * really wonder why this is needed. */ +typedef struct ID { + void *next, *prev; + struct ID *newid; + struct Library *lib; + char name[24]; + short us; + /** + * LIB_... flags report on status of the datablock this ID belongs + * to. + */ + short flag; + int icon_id; + IDProperty *properties; +} ID; + +/** + * For each library file used, a Library struct is added to Main + * WARNING: readfile.c, expand_doit() reads this struct without DNA check! + */ +typedef struct Library { + ID id; + ID *idblock; + struct FileData *filedata; + char name[240]; /* reveiled in the UI, can store relative path */ + char filename[240]; /* expanded name, not relative, used while reading */ + int tot, pad; /* tot, idblock and filedata are only fo read and write */ + struct Library *parent; /* for outliner, showing dependency */ +} Library; + +#define PREVIEW_MIPMAPS 2 +#define PREVIEW_MIPMAP_ZERO 0 +#define PREVIEW_MIPMAP_LARGE 1 + +typedef struct PreviewImage { + unsigned int w[2]; + unsigned int h[2]; + short changed[2]; + short pad0, pad1; + unsigned int * rect[2]; +} PreviewImage; + +/** + * Defines for working with IDs. + * + * The tags represent types! This is a dirty way of enabling RTTI. The + * sig_byte end endian defines aren't really used much. + * + **/ + +#if defined(__sgi) || defined(__sparc) || defined(__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__) +/* big endian */ +#define MAKE_ID2(c, d) ( (c)<<8 | (d) ) +#define MOST_SIG_BYTE 0 +#define BBIG_ENDIAN +#else +/* little endian */ +#define MAKE_ID2(c, d) ( (d)<<8 | (c) ) +#define MOST_SIG_BYTE 1 +#define BLITTLE_ENDIAN +#endif + +/* ID from database */ +#define ID_SCE MAKE_ID2('S', 'C') +#define ID_LI MAKE_ID2('L', 'I') +#define ID_OB MAKE_ID2('O', 'B') +#define ID_ME MAKE_ID2('M', 'E') +#define ID_CU MAKE_ID2('C', 'U') +#define ID_MB MAKE_ID2('M', 'B') +#define ID_MA MAKE_ID2('M', 'A') +#define ID_TE MAKE_ID2('T', 'E') +#define ID_IM MAKE_ID2('I', 'M') +#define ID_IK MAKE_ID2('I', 'K') +#define ID_WV MAKE_ID2('W', 'V') +#define ID_LT MAKE_ID2('L', 'T') +#define ID_SE MAKE_ID2('S', 'E') +#define ID_LF MAKE_ID2('L', 'F') +#define ID_LA MAKE_ID2('L', 'A') +#define ID_CA MAKE_ID2('C', 'A') +#define ID_IP MAKE_ID2('I', 'P') +#define ID_KE MAKE_ID2('K', 'E') +#define ID_WO MAKE_ID2('W', 'O') +#define ID_SCR MAKE_ID2('S', 'R') +#define ID_VF MAKE_ID2('V', 'F') +#define ID_TXT MAKE_ID2('T', 'X') +#define ID_SO MAKE_ID2('S', 'O') +#define ID_GR MAKE_ID2('G', 'R') +#define ID_ID MAKE_ID2('I', 'D') +#define ID_AR MAKE_ID2('A', 'R') +#define ID_AC MAKE_ID2('A', 'C') +#define ID_SCRIPT MAKE_ID2('P', 'Y') +#define ID_NT MAKE_ID2('N', 'T') +#define ID_BR MAKE_ID2('B', 'R') + + /* NOTE! Fake IDs, needed for g.sipo->blocktype or outliner */ +#define ID_SEQ MAKE_ID2('S', 'Q') + /* constraint */ +#define ID_CO MAKE_ID2('C', 'O') + /* pose (action channel, used to be ID_AC in code, so we keep code for backwards compat) */ +#define ID_PO MAKE_ID2('A', 'C') + /* used in outliner... */ +#define ID_NLA MAKE_ID2('N', 'L') + /* fluidsim Ipo */ +#define ID_FLUIDSIM MAKE_ID2('F', 'S') + + +/*#ifdef WITH_VERSE*/ +#define ID_VS MAKE_ID2('V', 'S') /* fake id for VerseSession, needed for outliner */ +#define ID_VN MAKE_ID2('V', 'N') /* fake id for VerseNode, needed for outliner */ +#define ID_MS MAKE_ID2('M', 'S') /* fake id for VerseServer root entry, needed for outliner */ +#define ID_SS MAKE_ID2('S', 'S') /* fake id for VerseServer entry, needed for ountliner */ +/*#endif*/ + + +/* id->flag: set frist 8 bits always at zero while reading */ +#define LIB_LOCAL 0 +#define LIB_EXTERN 1 +#define LIB_INDIRECT 2 +#define LIB_TEST 8 +#define LIB_TESTEXT 9 +#define LIB_TESTIND 10 +#define LIB_READ 16 +#define LIB_NEEDLINK 32 + +#define LIB_NEW 256 +#define LIB_FAKEUSER 512 +/* free test flag */ +#define LIB_DOIT 1024 +/* */ +#define LIB_APPEND_TAG 2048 + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h new file mode 100644 index 00000000000..3c5ef7c94e6 --- /dev/null +++ b/source/blender/makesdna/DNA_action_types.h @@ -0,0 +1,225 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Original design: Reevan McKay + * Contributor(s): Full recode, Ton Roosendaal, Crete 2005 + * + * ***** END GPL LICENSE BLOCK ***** + */ + + +#ifndef DNA_ACTION_TYPES_H +#define DNA_ACTION_TYPES_H + +#include "DNA_listBase.h" +#include "DNA_ID.h" +#include "DNA_view2d_types.h" + +struct SpaceLink; +struct Object; + +/* PoseChannel stores the results of Actions (ipos) and transform information + with respect to the restposition of Armature bones */ + +typedef struct bPoseChannel { + struct bPoseChannel *next, *prev; + ListBase constraints;/* Constraints that act on this PoseChannel */ + char name[32]; /* Channels need longer names than normal blender objects */ + + short flag; /* dynamic, for detecting transform changes */ + short constflag; /* for quick detecting which constraints affect this channel */ + short ikflag; /* settings for IK bones */ + short selectflag; /* copy of bone flag, so you can work with library armatures */ + short protectflag; /* protect channels from being transformed */ + short pad2; + + int pathlen; /* for drawing paths, the amount of frames */ + int pathsf; /* for drawing paths, the start frame number */ + int pathef; /* for drawing paths, the end frame number */ + + struct Bone *bone; /* set on read file or rebuild pose */ + struct bPoseChannel *parent; /* set on read file or rebuild pose */ + struct bPoseChannel *child; /* set on read file or rebuild pose, the 'ik' child, for b-bones */ + struct ListBase iktree; /* only while evaluating pose */ + + /* only while deform, stores precalculated b_bone deform mats, + dual quaternions */ + void *b_bone_mats; + void *dual_quat; + void *b_bone_dual_quats; + + float loc[3]; /* written in by actions or transform */ + float size[3]; + float quat[4]; + + float chan_mat[4][4]; /* matrix result of loc/quat/size , and where we put deform in, see next line */ + float pose_mat[4][4]; /* constraints accumulate here. in the end, pose_mat = bone->arm_mat * chan_mat */ + float constinv[4][4]; /* inverse result of constraints. doesn't include effect of restposition, parent, and local transform*/ + + float pose_head[3]; /* actually pose_mat[3] */ + float pose_tail[3]; /* also used for drawing help lines... */ + + float limitmin[3], limitmax[3]; /* DOF constraint */ + float stiffness[3]; /* DOF stiffness */ + float ikstretch; + + float *path; /* totpath x 3 x float */ + struct Object *custom; /* draws custom object instead of this channel */ + +} bPoseChannel; + +/* Pose-Object. It is only found under ob->pose. It is not library data, even + * though there is a define for it (hack for the outliner). + */ +typedef struct bPose { + ListBase chanbase; /* list of pose channels */ + short flag, proxy_layer; /* proxy layer: copy from armature, gets synced */ + float ctime; /* local action time of this pose */ + float stride_offset[3]; /* applied to object */ + float cyclic_offset[3]; /* result of match and cycles, applied in where_is_pose() */ +} bPose; + +/* Action Channels belong to Actions. They are linked with an IPO block, and can also own + * Constraint Channels in certain situations. + */ +typedef struct bActionChannel { + struct bActionChannel *next, *prev; + struct Ipo *ipo; /* IPO block this action channel references */ + ListBase constraintChannels; /* Constraint Channels (when Action Channel represents an Object or Bone) */ + + int flag; /* settings accessed via bitmapping */ + char name[32]; /* channel name */ + int reserved1; +} bActionChannel; + +/* Action. A recyclable block that contains a series of Action Channels (ipo), which define + * a clip of reusable animation for use in the NLA. + */ +typedef struct bAction { + ID id; + ListBase chanbase; /* Action Channels in this Action */ +} bAction; + +/* Action Editor Space. This is defined here instead of in DNA_space_types.h */ +typedef struct SpaceAction { + struct SpaceLink *next, *prev; + int spacetype; + float blockscale; + struct ScrArea *area; + + short blockhandler[8]; + + View2D v2d; + + bAction *action; /* the currently active action */ + short flag, autosnap; /* flag: bitmapped settings; autosnap: automatic keyframe snapping mode */ + short pin, actnr, lock; /* pin: keep showing current action; actnr: used for finding chosen action from menu; lock: lock time to other windows */ + short actwidth; /* width of the left-hand side name panel (in pixels?) */ + float timeslide; /* for Time-Slide transform mode drawing - current frame? */ +} SpaceAction; + +/* Action Channel flags */ +typedef enum ACHAN_FLAG { + ACHAN_SELECTED = (1<<0), + ACHAN_HILIGHTED = (1<<1), + ACHAN_HIDDEN = (1<<2), + ACHAN_PROTECTED = (1<<3), + ACHAN_EXPANDED = (1<<4), + ACHAN_SHOWIPO = (1<<5), + ACHAN_SHOWCONS = (1<<6), + ACHAN_MOVED = (1<<31), +} ACHAN_FLAG; + +/* SpaceAction flag */ +typedef enum SACTION_FLAG { + /* during transform */ + SACTION_MOVING = (1<<0), + /* show sliders (if relevant) */ + SACTION_SLIDERS = (1<<1), + /* draw time in seconds instead of time in frames */ + SACTION_DRAWTIME = (1<<2) +} SACTION_FLAG; + +/* SpaceAction AutoSnap Settings (also used by SpaceNLA) */ +typedef enum SACTSNAP_MODES { + /* no auto-snap */ + SACTSNAP_OFF = 0, + /* snap to 1.0 frame/second intervals */ + SACTSNAP_STEP, + /* snap to actual frames/seconds (nla-action time) */ + SACTSNAP_FRAME, + /* snap to nearest marker */ + SACTSNAP_MARKER, +} SACTSNAP_MODES; + +/* Pose->flag */ +typedef enum POSE_FLAG { + /* results in armature_rebuild_pose being called */ + POSE_RECALC = (1<<0), + /* prevents any channel from getting overridden by anim from IPO */ + POSE_LOCKED = (1<<1), + /* clears the POSE_LOCKED flag for the next time the pose is evaluated */ + POSE_DO_UNLOCK = (1<<2) +} POSE_FLAG; + +/* PoseChannel (transform) flags */ +enum { + POSE_LOC = 0x0001, + POSE_ROT = 0x0002, + POSE_SIZE = 0x0004, + POSE_IK_MAT = 0x0008, + POSE_UNUSED2 = 0x0010, + POSE_UNUSED3 = 0x0020, + POSE_UNUSED4 = 0x0040, + POSE_UNUSED5 = 0x0080, + POSE_HAS_IK = 0x0100, + POSE_CHAIN = 0x0200, + POSE_DONE = 0x0400, + POSE_KEY = 0x1000, + POSE_STRIDE = 0x2000 +}; + +/* PoseChannel constflag (constraint detection) */ +typedef enum PCHAN_CONSTFLAG { + PCHAN_HAS_IK = (1<<0), + PCHAN_HAS_CONST = (1<<1), + /* only used for drawing Posemode, not stored in channel */ + PCHAN_HAS_ACTION = (1<<2), + PCHAN_HAS_TARGET = (1<<3), + /* only for drawing Posemode too */ + PCHAN_HAS_STRIDE = (1<<4) +} PCHAN_CONSTFLAG; + +/* PoseChannel->ikflag */ +typedef enum PCHAN_IKFLAG { + BONE_IK_NO_XDOF = (1<<0), + BONE_IK_NO_YDOF = (1<<1), + BONE_IK_NO_ZDOF = (1<<2), + + BONE_IK_XLIMIT = (1<<3), + BONE_IK_YLIMIT = (1<<4), + BONE_IK_ZLIMIT = (1<<5) +} PCHAN_IKFLAG; + + +#endif + diff --git a/source/blender/makesdna/DNA_actuator_types.h b/source/blender/makesdna/DNA_actuator_types.h new file mode 100644 index 00000000000..0531e70bb97 --- /dev/null +++ b/source/blender/makesdna/DNA_actuator_types.h @@ -0,0 +1,395 @@ +/** + * blenlib/DNA_actuator_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_ACTUATOR_TYPES_H +#define DNA_ACTUATOR_TYPES_H + +struct Object; +struct Mesh; +struct Scene; +struct Group; + +/* ****************** ACTUATORS ********************* */ + +/* unused now, moved to editobjectactuator in 2.02. Still needed for dna */ +typedef struct bAddObjectActuator { + int time, pad; + struct Object *ob; +} bAddObjectActuator; + +typedef struct bActionActuator { + struct bAction *act; /* Pointer to action */ + short type, flag; /* Playback type */ + int sta, end; /* Start & End frames */ + char name[32]; /* For property-driven playback */ + int blendin; /* Number of frames of blending */ + short priority; /* Execution priority */ + short strideaxis; /* Displacement axis */ + float stridelength; /* Displacement incurred by cycle */ +} bActionActuator; + +typedef struct bSoundActuator { + short flag, sndnr; + int sta, end; + short pad1[2]; + struct bSound *sound; + short type, makecopy; + short copymade, pad2[1]; +} bSoundActuator; + +typedef struct bCDActuator { + short flag, sndnr; + int sta, end; + short type, track; + float volume; +} bCDActuator; + +typedef struct bEditObjectActuator { + int time; + short type, flag; + struct Object *ob; + struct Mesh *me; + char name[32]; + float linVelocity[3]; /* initial lin. velocity on creation */ + short localflag; /* flag for the lin. vel: apply locally */ + short pad; +} bEditObjectActuator; + +typedef struct bSceneActuator { + short type, flag; + int pad; + struct Scene *scene; + struct Object *camera; +} bSceneActuator; + +typedef struct bPropertyActuator { + int flag, type; + char name[32], value[32]; + struct Object *ob; +} bPropertyActuator; + +typedef struct bObjectActuator { + int flag, type; + float forceloc[3], forcerot[3]; + float loc[3], rot[3]; + float dloc[3], drot[3]; + float linearvelocity[3], angularvelocity[3]; +} bObjectActuator; + +typedef struct bIpoActuator { + short flag, type; + int sta, end; + char name[32]; + + short pad1, cur, butsta, butend; + +} bIpoActuator; + +typedef struct bCameraActuator { + struct Object *ob; + float height, min, max; + float fac; + short flag, axis; + float visifac; +} bCameraActuator ; + +typedef struct bConstraintActuator { + short flag, damp; + float slow; + float minloc[3], maxloc[3]; + float minrot[3], maxrot[3]; +} bConstraintActuator; + +typedef struct bGroupActuator { + short flag, type; + int sta, end; + char name[32]; /* property or groupkey */ + + short pad[3], cur, butsta, butend;/* not referenced, can remove? */ + struct Group *group; /* only during game */ + +} bGroupActuator; + +/* I added a few extra fields here, to facilitate conversions */ +typedef struct bRandomActuator { + int seed; + int distribution; + int int_arg_1; + int int_arg_2; + float float_arg_1; + float float_arg_2; + char propname[32]; +} bRandomActuator; + +typedef struct bMessageActuator { + /** + * Send to all objects with this propertyname. Empty to broadcast. + */ + char toPropName[32]; + + /** + * (Possible future use) pointer to a single destination object. + */ + struct Object *toObject; + + /** + * Message Subject to send. + */ + char subject[32]; + + /** + * bodyType is either 'User defined text' or PropName + */ + short bodyType, pad1; + int pad2; + + /** + * Either User Defined Text or our PropName to send value of + */ + char body[32]; +} bMessageActuator; + +typedef struct bGameActuator { + short flag, type; + int sta, end; + char filename[64]; + char loadaniname[64]; +} bGameActuator; + +typedef struct bVisibilityActuator { + /** bit 0: Is this object visible? */ + int flag; +} bVisibilityActuator; + +typedef struct bActuator { + struct bActuator *next, *prev, *mynew; + short type; + /** + * Tells what type of actuator data holds. + */ + short flag; + short otype, go; + char name[32]; + + /** + * Data must point to an object actuator type struct. + */ + void *data; + + /** + * For ipo's and props: to find out which object the actuator + * belongs to */ + struct Object *ob; + +} bActuator; + +typedef struct FreeCamera { + float mass, accelleration; + float maxspeed, maxrotspeed, maxtiltspeed; + int flag; + float rotdamp, tiltdamp, speeddamp, pad; +} FreeCamera; + +/* objectactuator->flag */ +#define ACT_FORCE_LOCAL 1 +#define ACT_TORQUE_LOCAL 2 +#define ACT_DLOC_LOCAL 4 +#define ACT_DROT_LOCAL 8 +#define ACT_LIN_VEL_LOCAL 16 +#define ACT_ANG_VEL_LOCAL 32 +//#define ACT_ADD_LIN_VEL_LOCAL 64 +#define ACT_ADD_LIN_VEL 64 + +#define ACT_OBJECT_FORCE 0 +#define ACT_OBJECT_TORQUE 1 +#define ACT_OBJECT_DLOC 2 +#define ACT_OBJECT_DROT 3 +#define ACT_OBJECT_LINV 4 +#define ACT_OBJECT_ANGV 5 + +/* actuator->type */ +#define ACT_OBJECT 0 +#define ACT_IPO 1 +#define ACT_LAMP 2 +#define ACT_CAMERA 3 +#define ACT_MATERIAL 4 +#define ACT_SOUND 5 +#define ACT_PROPERTY 6 + /* these two obsolete since 2.02 */ +#define ACT_ADD_OBJECT 7 +#define ACT_END_OBJECT 8 + +#define ACT_CONSTRAINT 9 +#define ACT_EDIT_OBJECT 10 +#define ACT_SCENE 11 +#define ACT_GROUP 12 +#define ACT_RANDOM 13 +#define ACT_MESSAGE 14 +#define ACT_ACTION 15 /* __ NLA */ +#define ACT_CD 16 +#define ACT_GAME 17 +#define ACT_VISIBILITY 18 + +/* actuator flag */ +#define ACT_SHOW 1 +#define ACT_DEL 2 +#define ACT_NEW 4 + +/* link codes */ +#define LINK_SENSOR 0 +#define LINK_CONTROLLER 1 +#define LINK_ACTUATOR 2 + +/* keyboardsensor->type */ +#define SENS_ALL_KEYS 1 + +/* actionactuator->type */ +#define ACT_ACTION_PLAY 0 +#define ACT_ACTION_PINGPONG 1 +#define ACT_ACTION_FLIPPER 2 +#define ACT_ACTION_LOOP_STOP 3 +#define ACT_ACTION_LOOP_END 4 +#define ACT_ACTION_KEY2KEY 5 +#define ACT_ACTION_FROM_PROP 6 +#define ACT_ACTION_MOTION 7 + +/* ipoactuator->type */ +#define ACT_IPO_PLAY 0 +#define ACT_IPO_PINGPONG 1 +#define ACT_IPO_FLIPPER 2 +#define ACT_IPO_LOOP_STOP 3 +#define ACT_IPO_LOOP_END 4 +#define ACT_IPO_KEY2KEY 5 +#define ACT_IPO_FROM_PROP 6 + +/* groupactuator->type */ +#define ACT_GROUP_PLAY 0 +#define ACT_GROUP_PINGPONG 1 +#define ACT_GROUP_FLIPPER 2 +#define ACT_GROUP_LOOP_STOP 3 +#define ACT_GROUP_LOOP_END 4 +#define ACT_GROUP_FROM_PROP 5 +#define ACT_GROUP_SET 6 + +/* ipoactuator->flag */ +#define ACT_IPOFORCE (1 << 0) +#define ACT_IPOEND (1 << 1) +#define ACT_IPOFORCE_LOCAL (1 << 2) +#define ACT_IPOCHILD (1 << 4) + +/* ipoactuator->flag for k2k */ +#define ACT_K2K_PREV 1 +#define ACT_K2K_CYCLIC 2 +#define ACT_K2K_PINGPONG 4 +#define ACT_K2K_HOLD 8 + +/* property actuator->type */ +#define ACT_PROP_ASSIGN 0 +#define ACT_PROP_ADD 1 +#define ACT_PROP_COPY 2 + +/* constraint flag */ +#define ACT_CONST_LOCX 1 +#define ACT_CONST_LOCY 2 +#define ACT_CONST_LOCZ 4 +#define ACT_CONST_ROTX 8 +#define ACT_CONST_ROTY 16 +#define ACT_CONST_ROTZ 32 + +/* editObjectActuator->type */ +#define ACT_EDOB_ADD_OBJECT 0 +#define ACT_EDOB_END_OBJECT 1 +#define ACT_EDOB_REPLACE_MESH 2 +#define ACT_EDOB_TRACK_TO 3 +#define ACT_EDOB_MAKE_CHILD 4 +#define ACT_EDOB_END_CHILD 5 + +/* editObjectActuator->flag */ +#define ACT_TRACK_3D 1 + +/* SceneActuator->type */ +#define ACT_SCENE_RESTART 0 +#define ACT_SCENE_SET 1 +#define ACT_SCENE_CAMERA 2 +#define ACT_SCENE_ADD_FRONT 3 +#define ACT_SCENE_ADD_BACK 4 +#define ACT_SCENE_REMOVE 5 +#define ACT_SCENE_SUSPEND 6 +#define ACT_SCENE_RESUME 7 + + +/* randomAct->distribution */ +#define ACT_RANDOM_BOOL_CONST 0 +#define ACT_RANDOM_BOOL_UNIFORM 1 +#define ACT_RANDOM_BOOL_BERNOUILLI 2 +#define ACT_RANDOM_INT_CONST 3 +#define ACT_RANDOM_INT_UNIFORM 4 +#define ACT_RANDOM_INT_POISSON 5 +#define ACT_RANDOM_FLOAT_CONST 6 +#define ACT_RANDOM_FLOAT_UNIFORM 7 +#define ACT_RANDOM_FLOAT_NORMAL 8 +#define ACT_RANDOM_FLOAT_NEGATIVE_EXPONENTIAL 9 + +/* SoundActuator->type */ +#define ACT_SND_PLAY_STOP_SOUND 0 +#define ACT_SND_PLAY_END_SOUND 1 +#define ACT_SND_LOOP_STOP_SOUND 2 +#define ACT_SND_LOOP_END_SOUND 3 +#define ACT_SND_LOOP_BIDIRECTIONAL_SOUND 4 +#define ACT_SND_LOOP_BIDIRECTIONAL_STOP_SOUND 5 + +/* messageactuator->type */ +#define ACT_MESG_MESG 0 +#define ACT_MESG_PROP 1 + +/* cdactuator->type */ +#define ACT_CD_PLAY_ALL 0 +#define ACT_CD_PLAY_TRACK 1 +#define ACT_CD_LOOP_TRACK 2 +#define ACT_CD_VOLUME 3 +#define ACT_CD_STOP 4 +#define ACT_CD_PAUSE 5 +#define ACT_CD_RESUME 6 + +/* gameactuator->type */ +#define ACT_GAME_LOAD 0 +#define ACT_GAME_START 1 +#define ACT_GAME_RESTART 2 +#define ACT_GAME_QUIT 3 + +/* visibilityact->flag */ +/* Set means the object will become invisible */ +#define ACT_VISIBILITY_INVISIBLE (1 << 0) + +#endif + diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h new file mode 100644 index 00000000000..9f64a31c90c --- /dev/null +++ b/source/blender/makesdna/DNA_armature_types.h @@ -0,0 +1,154 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Full recode, Ton Roosendaal, Crete 2005 + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef DNA_ARMATURE_TYPES_H +#define DNA_ARMATURE_TYPES_H + +#include "DNA_listBase.h" +#include "DNA_ID.h" + +/* this system works on different transformation space levels; + +1) Bone Space; with each Bone having own (0,0,0) origin +2) Armature Space; the rest position, in Object space, Bones Spaces are applied hierarchical +3) Pose Space; the animation position, in Object space +4) World Space; Object matrix applied to Pose or Armature space + +*/ + +typedef struct Bone { + struct Bone *next, *prev; /* Next/prev elements within this list */ + struct Bone *parent; /* Parent (ik parent if appropriate flag is set */ + ListBase childbase; /* Children */ + char name[32]; /* Name of the bone - must be unique within the armature */ + + float roll; /* roll is input for editmode, length calculated */ + float head[3]; + float tail[3]; /* head/tail and roll in Bone Space */ + float bone_mat[3][3]; /* rotation derived from head/tail/roll */ + + int flag; + + float arm_head[3]; + float arm_tail[3]; /* head/tail and roll in Armature Space (rest pos) */ + float arm_mat[4][4]; /* matrix: (bonemat(b)+head(b))*arm_mat(b-1), rest pos*/ + + float dist, weight; /* dist, weight: for non-deformgroup deforms */ + float xwidth, length, zwidth; /* width: for block bones. keep in this order, transform! */ + float ease1, ease2; /* length of bezier handles */ + float rad_head, rad_tail; /* radius for head/tail sphere, defining deform as well, parent->rad_tip overrides rad_head*/ + + float size[3]; /* patch for upward compat, UNUSED! */ + short layer; + short segments; /* for B-bones */ +}Bone; + +typedef struct bArmature { + ID id; + ListBase bonebase; + ListBase chainbase; + int flag; + int drawtype; + short deformflag; + short pathflag; + short layer, layer_protected; /* for buttons to work, both variables in this order together */ + short ghostep, ghostsize; /*number of frames to ghosts to show, and step between them */ + short ghosttype, pathsize; /* ghost drawing options and number of frames between points of path */ + int ghostsf, ghostef; /* start and end frames of ghost-drawing range */ + int pathsf, pathef; /* start and end frames of path-calculation range for all bones */ +}bArmature; + +/* armature->flag */ +/* dont use bit 7, was saved in files to disable stuff */ + +/* armature->flag */ +#define ARM_RESTPOS 0x001 + /* XRAY is here only for backwards converting */ +#define ARM_DRAWXRAY 0x002 +#define ARM_DRAWAXES 0x004 +#define ARM_DRAWNAMES 0x008 +#define ARM_POSEMODE 0x010 +#define ARM_EDITMODE 0x020 +#define ARM_DELAYDEFORM 0x040 +#define ARM_DONT_USE 0x080 +#define ARM_MIRROR_EDIT 0x100 +#define ARM_AUTO_IK 0x200 + /* made option negative, for backwards compat */ +#define ARM_NO_CUSTOM 0x400 +#define ARM_COL_CUSTOM 0x800 + +/* armature->drawtype */ +#define ARM_OCTA 0 +#define ARM_LINE 1 +#define ARM_B_BONE 2 +#define ARM_ENVELOPE 3 + +/* armature->deformflag */ +#define ARM_DEF_VGROUP 1 +#define ARM_DEF_ENVELOPE 2 +#define ARM_DEF_QUATERNION 4 +#define ARM_DEF_B_BONE_REST 8 + +/* armature->pathflag */ +#define ARM_PATH_FNUMS 0x001 +#define ARM_PATH_KFRAS 0x002 +#define ARM_PATH_HEADS 0x004 + +/* armature->ghosttype */ +#define ARM_GHOST_CUR 0 +#define ARM_GHOST_RANGE 1 + +/* bone->flag */ +#define BONE_SELECTED 1 +#define BONE_ROOTSEL 2 +#define BONE_TIPSEL 4 + /* Used instead of BONE_SELECTED during transform */ +#define BONE_TRANSFORM 8 +#define BONE_CONNECTED 16 + /* 32 used to be quatrot, was always set in files, do not reuse unless you clear it always */ + /* hidden Bones when drawing Posechannels */ +#define BONE_HIDDEN_P 64 + /* For detecting cyclic dependancies */ +#define BONE_DONE 128 + /* active is on mouse clicks only */ +#define BONE_ACTIVE 256 + /* No parent rotation or scale */ +#define BONE_HINGE 512 + /* hidden Bones when drawing Armature Editmode */ +#define BONE_HIDDEN_A 1024 + /* multiplies vgroup with envelope */ +#define BONE_MULT_VG_ENV 2048 +#define BONE_NO_DEFORM 4096 + /* set to prevent destruction of its unkeyframed pose (after transform) */ +#define BONE_UNKEYED 8192 + /* set to prevent hinge child bones from influencing the transform center */ +#define BONE_HINGE_CHILD_TRANSFORM 16384 + +#endif diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h new file mode 100644 index 00000000000..1c272105067 --- /dev/null +++ b/source/blender/makesdna/DNA_brush_types.h @@ -0,0 +1,91 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef DNA_BRUSH_TYPES_H +#define DNA_BRUSH_TYPES_H + +#include "DNA_ID.h" + +#ifndef MAX_MTEX +#define MAX_MTEX 10 +#endif + +struct MTex; +struct Image; + +typedef struct BrushClone { + struct Image *image; /* image for clone tool */ + float offset[2]; /* offset of clone image from canvas */ + float alpha, pad; /* transparency for drawing of clone image */ +} BrushClone; + +typedef struct Brush { + ID id; + + short flag, blend; /* general purpose flag, blend mode */ + int size; /* brush diameter */ + float innerradius; /* inner radius after which the falloff starts */ + float spacing; /* spacing of paint operations */ + float rate; /* paint operations / second (airbrush) */ + + float rgb[3]; /* color */ + float alpha; /* opacity */ + + short texact, pad; + struct MTex *mtex[10]; + + struct BrushClone clone; +} Brush; + +/* Brush.flag */ +#define BRUSH_AIRBRUSH 1 +#define BRUSH_TORUS 2 +#define BRUSH_ALPHA_PRESSURE 4 +#define BRUSH_SIZE_PRESSURE 8 +#define BRUSH_RAD_PRESSURE 16 +#define BRUSH_SPACING_PRESSURE 32 +#define BRUSH_FIXED_TEX 64 + +/* Brush.blend */ +#define BRUSH_BLEND_MIX 0 +#define BRUSH_BLEND_ADD 1 +#define BRUSH_BLEND_SUB 2 +#define BRUSH_BLEND_MUL 3 +#define BRUSH_BLEND_LIGHTEN 4 +#define BRUSH_BLEND_DARKEN 5 +#define BRUSH_BLEND_ERASE_ALPHA 6 +#define BRUSH_BLEND_ADD_ALPHA 7 + +#define PAINT_TOOL_DRAW 0 +#define PAINT_TOOL_SOFTEN 1 +#define PAINT_TOOL_SMEAR 2 +#define PAINT_TOOL_CLONE 3 + +#endif + diff --git a/source/blender/makesdna/DNA_camera_types.h b/source/blender/makesdna/DNA_camera_types.h new file mode 100644 index 00000000000..4cb8ec25ebc --- /dev/null +++ b/source/blender/makesdna/DNA_camera_types.h @@ -0,0 +1,91 @@ +/** + * blenlib/DNA_camera_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_CAMERA_TYPES_H +#define DNA_CAMERA_TYPES_H + +#include "DNA_ID.h" +#include "DNA_scriptlink_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct Ipo; +struct Object; + +typedef struct Camera { + ID id; + + short type, flag; + float passepartalpha, angle; + float clipsta, clipend; + float lens, ortho_scale, drawsize; + float shiftx, shifty; + + /* yafray: dof params */ + /* qdn: yafray var 'YF_dofdist' now enabled for defocus composit node as well. + The name was not changed so that no other files need to be modified */ + float YF_dofdist, YF_aperture; + short YF_bkhtype, YF_bkhbias; + float YF_bkhrot; + + struct Ipo *ipo; + + ScriptLink scriptlink; + struct Object *dof_ob; +} Camera; + +/* **************** CAMERA ********************* */ + +/* type */ +#define CAM_PERSP 0 +#define CAM_ORTHO 1 + +/* flag */ +#define CAM_SHOWLIMITS 1 +#define CAM_SHOWMIST 2 +#define CAM_SHOWPASSEPARTOUT 4 +#define CAM_SHOWTITLESAFE 8 +#define CAM_SHOWNAME 16 +#define CAM_ANGLETOGGLE 32 + +/* yafray: dof sampling switch */ +#define CAM_YF_NO_QMC 512 + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/blender/makesdna/DNA_color_types.h b/source/blender/makesdna/DNA_color_types.h new file mode 100644 index 00000000000..a4224976f5f --- /dev/null +++ b/source/blender/makesdna/DNA_color_types.h @@ -0,0 +1,81 @@ +/** + * + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_COLOR_TYPES_H +#define DNA_COLOR_TYPES_H + +#include "DNA_vec_types.h" + +/* general defines for kernel functions */ +#define CM_RESOL 32 +#define CM_TABLE 256 +#define CM_TABLEDIV (1.0f/256.0f) + +#define CM_TOT 4 + +typedef struct CurveMapPoint { + float x, y; + short flag, shorty; /* shorty for result lookup */ +} CurveMapPoint; + +/* curvepoint->flag */ +#define CUMA_SELECT 1 +#define CUMA_VECTOR 2 + +typedef struct CurveMap { + short totpoint, flag; + + float range; /* quick multiply value for reading table */ + float mintable, maxtable; /* the x-axis range for the table */ + float ext_in[2], ext_out[2]; /* for extrapolated curves, the direction vector */ + CurveMapPoint *curve; /* actual curve */ + CurveMapPoint *table; /* display and evaluate table */ + CurveMapPoint *premultable; /* for RGB curves, premulled table */ +} CurveMap; + +/* cuma->flag */ +#define CUMA_EXTEND_EXTRAPOLATE 1 + +typedef struct CurveMapping { + int flag, cur; /* cur; for buttons, to show active curve */ + + rctf curr, clipr; /* current rect, clip rect (is default rect too) */ + + CurveMap cm[4]; /* max 4 builtin curves per mapping struct now */ + float black[3], white[3]; /* black/white point (black[0] abused for current frame) */ + float bwmul[3], padf; /* black/white point multiply value, for speed */ +} CurveMapping; + +/* cumapping->flag */ +#define CUMA_DO_CLIP 1 +#define CUMA_PREMULLED 2 +#define CUMA_DRAW_CFRA 4 + +#endif + diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h new file mode 100644 index 00000000000..431ef56e1c4 --- /dev/null +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -0,0 +1,493 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): 2007, Joshua Leung, major recode + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * Constraint DNA data + */ + +#ifndef DNA_CONSTRAINT_TYPES_H +#define DNA_CONSTRAINT_TYPES_H + +#include "DNA_ID.h" +#include "DNA_ipo_types.h" +#include "DNA_listBase.h" +#include "DNA_object_types.h" + +struct Action; +struct Text; + +/* channels reside in Object or Action (ListBase) constraintChannels */ +typedef struct bConstraintChannel { + struct bConstraintChannel *next, *prev; + Ipo *ipo; + short flag; + char name[30]; +} bConstraintChannel; + +/* A Constraint */ +typedef struct bConstraint { + struct bConstraint *next, *prev; + + void *data; /* Constraint data (a valid constraint type) */ + short type; /* Constraint type */ + short flag; /* Flag - General Settings */ + + char ownspace; /* Space that owner should be evaluated in */ + char tarspace; /* Space that target should be evaluated in (only used if 1 target) */ + + char name[30]; /* Constraint name */ + + float enforce; /* Amount of influence exherted by constraint (0.0-1.0) */ +} bConstraint; + + +/* Multiple-target constraints --------------------- */ + +/* This struct defines a constraint target. + * It is used during constraint solving regardless of how many targets the + * constraint has. + */ +typedef struct bConstraintTarget { + struct bConstraintTarget *next, *prev; + + Object *tar; /* object to use as target */ + char subtarget[32]; /* subtarget - pchan or vgroup name */ + + float matrix[4][4]; /* matrix used during constraint solving - should be cleared before each use */ + + short space; /* space that target should be evaluated in (overrides bConstraint->tarspace) */ + short flag; /* runtime settings (for editor, etc.) */ + short type; /* type of target (B_CONSTRAINT_OB_TYPE) */ + short pad; +} bConstraintTarget; + +/* bConstraintTarget -> flag */ +typedef enum B_CONSTRAINT_TARGET_FLAG { + CONSTRAINT_TAR_TEMP = (1<<0), /* temporary target-struct that needs to be freed after use */ +} B_CONSTRAINT_TARGET_FLAG; + +/* bConstraintTarget/bConstraintOb -> type */ +typedef enum B_CONSTRAINT_OB_TYPE { + CONSTRAINT_OBTYPE_OBJECT = 1, /* string is "" */ + CONSTRAINT_OBTYPE_BONE, /* string is bone-name */ + CONSTRAINT_OBTYPE_VERT, /* string is vertex-group name */ + CONSTRAINT_OBTYPE_CV /* string is vertex-group name - is not available until curves get vgroups */ +} B_CONSTRAINT_OB_TYPE; + + + +/* Python Script Constraint */ +typedef struct bPythonConstraint { + struct Text *text; /* text-buffer (containing script) to execute */ + IDProperty *prop; /* 'id-properties' used to store custom properties for constraint */ + + int flag; /* general settings/state indicators accessed by bitmapping */ + int tarnum; /* number of targets - usually only 1-3 are needed */ + + ListBase targets; /* a list of targets that this constraint has (bConstraintTarget-s) */ + + Object *tar; /* target from previous implementation (version-patch sets this to NULL on file-load) */ + char subtarget[32]; /* subtarger from previous implentation (version-patch sets this to "" on file-load) */ +} bPythonConstraint; + +/* Single-target subobject constraints --------------------- */ +/* Inverse-Kinematics (IK) constraint */ +typedef struct bKinematicConstraint { + Object *tar; + short iterations; /* Maximum number of iterations to try */ + short flag; /* Like CONSTRAINT_IK_TIP */ + int rootbone; /* index to rootbone, if zero go all the way to mother bone */ + char subtarget[32]; /* String to specify sub-object target */ + + Object *poletar; /* Pole vector target */ + char polesubtarget[32]; /* Pole vector sub-object target */ + float poleangle; /* Pole vector rest angle */ + + float weight; /* Weight of goal in IK tree */ + float orientweight; /* Amount of rotation a target applies on chain */ + float grabtarget[3]; /* for target-less IK */ +} bKinematicConstraint; + +/* Track To Constraint */ +typedef struct bTrackToConstraint { + Object *tar; + int reserved1; /* I'll be using reserved1 and reserved2 as Track and Up flags, not sure if that's what they were intented for anyway. Not sure either if it would create backward incompatibility if I were to rename them. - theeth*/ + int reserved2; + int flags; + int pad; + char subtarget[32]; +} bTrackToConstraint; + +/* Copy Rotation Constraint */ +typedef struct bRotateLikeConstraint { + Object *tar; + int flag; + int reserved1; + char subtarget[32]; +} bRotateLikeConstraint; + +/* Copy Location Constraint */ +typedef struct bLocateLikeConstraint { + Object *tar; + int flag; + int reserved1; + char subtarget[32]; +} bLocateLikeConstraint; + +/* Floor Constraint */ +typedef struct bMinMaxConstraint { + Object *tar; + int minmaxflag; + float offset; + int flag; + short sticky, stuck, pad1, pad2; /* for backward compatability */ + float cache[3]; + char subtarget[32]; +} bMinMaxConstraint; + +/* Copy Scale Constraint */ +typedef struct bSizeLikeConstraint { + Object *tar; + int flag; + int reserved1; + char subtarget[32]; +} bSizeLikeConstraint; + +/* Action Constraint */ +typedef struct bActionConstraint { + Object *tar; + short type; /* what transform 'channel' drives the result */ + short local; /* was used in versions prior to the Constraints recode */ + int start; + int end; + float min; + float max; + int pad; + struct bAction *act; + char subtarget[32]; +} bActionConstraint; + +/* Locked Axis Tracking constraint */ +typedef struct bLockTrackConstraint { + Object *tar; + int trackflag; + int lockflag; + char subtarget[32]; +} bLockTrackConstraint; + +/* Follow Path constraints */ +typedef struct bFollowPathConstraint { + Object *tar; /* Must be path object */ + float offset; /* Offset in time on the path (in frame) */ + int followflag; + int trackflag; + int upflag; +} bFollowPathConstraint; + +/* Stretch to constraint */ +typedef struct bStretchToConstraint { + Object *tar; + int volmode; + int plane; + float orglength; + float bulge; + char subtarget[32]; +} bStretchToConstraint; + +/* Rigid Body constraint */ +typedef struct bRigidBodyJointConstraint { + Object *tar; + Object *child; + int type; + float pivX; + float pivY; + float pivZ; + float axX; + float axY; + float axZ; + float minLimit[6]; + float maxLimit[6]; + float extraFz; + short flag; + short pad; + short pad1; + short pad2; +} bRigidBodyJointConstraint; + +/* Clamp-To Constraint */ +typedef struct bClampToConstraint { + Object *tar; /* 'target' must be a curve */ + int flag; /* which axis/plane to compare owner's location on */ + int flag2; /* for legacy reasons, this is flag2. used for any extra settings */ +} bClampToConstraint; + +/* Child Of Constraint */ +typedef struct bChildOfConstraint { + Object *tar; /* object which will act as parent (or target comes from) */ + int flag; /* settings */ + int pad; + float invmat[4][4]; /* parent-inverse matrix to use */ + char subtarget[32]; /* string to specify a subobject target */ +} bChildOfConstraint; + +/* Generic Transform->Transform Constraint */ +typedef struct bTransformConstraint { + Object *tar; /* target (i.e. 'driver' object/bone) */ + char subtarget[32]; + + short from, to; /* can be loc(0) , rot(1), or size(2) */ + char map[3]; /* defines which target-axis deform is copied by each owner-axis */ + char expo; /* extrapolate motion? if 0, confine to ranges */ + + float from_min[3]; /* from_min/max defines range of target transform */ + float from_max[3]; /* to map on to to_min/max range. */ + + float to_min[3]; /* range of motion on owner caused by target */ + float to_max[3]; +} bTransformConstraint; + +/* transform limiting constraints - zero target ---------------------------- */ +/* Limit Location Constraint */ +typedef struct bLocLimitConstraint { + float xmin, xmax; + float ymin, ymax; + float zmin, zmax; + short flag; + short flag2; +} bLocLimitConstraint; + +/* Limit Rotation Constraint */ +typedef struct bRotLimitConstraint { + float xmin, xmax; + float ymin, ymax; + float zmin, zmax; + short flag; + short pad1; +} bRotLimitConstraint; + +/* Limit Scaling Constraint */ +typedef struct bSizeLimitConstraint { + float xmin, xmax; + float ymin, ymax; + float zmin, zmax; + short flag; + short pad1; +} bSizeLimitConstraint; + +/* ------------------------------------------ */ + +/* bConstraint->type + * - Do not ever change the order of these, or else files could get + * broken as their correct value cannot be resolved + */ +typedef enum B_CONSTAINT_TYPES { + CONSTRAINT_TYPE_NULL = 0, /* Invalid/legacy constraint */ + CONSTRAINT_TYPE_CHILDOF, /* Unimplemented non longer :) - during constraints recode, Aligorith */ + CONSTRAINT_TYPE_TRACKTO, + CONSTRAINT_TYPE_KINEMATIC, + CONSTRAINT_TYPE_FOLLOWPATH, + CONSTRAINT_TYPE_ROTLIMIT, /* Unimplemented no longer :) - Aligorith */ + CONSTRAINT_TYPE_LOCLIMIT, /* Unimplemented no longer :) - Aligorith */ + CONSTRAINT_TYPE_SIZELIMIT, /* Unimplemented no longer :) - Aligorith */ + CONSTRAINT_TYPE_ROTLIKE, + CONSTRAINT_TYPE_LOCLIKE, + CONSTRAINT_TYPE_SIZELIKE, + CONSTRAINT_TYPE_PYTHON, /* Unimplemented no longer :) - Aligorith. Scripts */ + CONSTRAINT_TYPE_ACTION, + CONSTRAINT_TYPE_LOCKTRACK, /* New Tracking constraint that locks an axis in place - theeth */ + CONSTRAINT_TYPE_DISTANCELIMIT, /* was never properly coded - removed! */ + CONSTRAINT_TYPE_STRETCHTO, /* claiming this to be mine :) is in tuhopuu bjornmose */ + CONSTRAINT_TYPE_MINMAX, /* floor constraint */ + CONSTRAINT_TYPE_RIGIDBODYJOINT, /* rigidbody constraint */ + CONSTRAINT_TYPE_CLAMPTO, /* clampto constraint */ + CONSTRAINT_TYPE_TRANSFORM, /* transformation (loc/rot/size -> loc/rot/size) constraint */ + + /* NOTE: everytime a new constraint is added, update this */ + NUM_CONSTRAINT_TYPES= CONSTRAINT_TYPE_TRANSFORM +} B_CONSTRAINT_TYPES; + +/* bConstraint->flag */ +/* flags 0x2 (1<<1) and 0x8 (1<<3) were used in past */ +/* flag 0x20 (1<<5) was used to indicate that a constraint was evaluated using a 'local' hack for posebones only */ +typedef enum B_CONSTRAINT_FLAG { + /* expand for UI */ + CONSTRAINT_EXPAND = (1<<0), + /* pre-check for illegal object name or bone name */ + CONSTRAINT_DISABLE = (1<<2), + /* to indicate which Ipo should be shown, maybe for 3d access later too */ + CONSTRAINT_ACTIVE = (1<<4), + /* to indicate that the owner's space should only be changed into ownspace, but not out of it */ + CONSTRAINT_SPACEONCE = (1<<6) +} B_CONSTRAINT_FLAG; + +/* bConstraint->ownspace/tarspace */ +typedef enum B_CONSTRAINT_SPACETYPES { + /* default for all - worldspace */ + CONSTRAINT_SPACE_WORLD = 0, + /* for objects (relative to parent/without parent influence), + * for bones (along normals of bone, without parent/restpositions) + */ + CONSTRAINT_SPACE_LOCAL, + /* for posechannels - pose space */ + CONSTRAINT_SPACE_POSE, + /* for posechannels - local with parent */ + CONSTRAINT_SPACE_PARLOCAL, +} B_CONSTRAINT_SPACETYPES; + +/* bConstraintChannel.flag */ +typedef enum B_CONSTRAINTCHANNEL_FLAG { + CONSTRAINT_CHANNEL_SELECT = (1<<0), + CONSTRAINT_CHANNEL_PROTECTED = (1<<1) +} B_CONSTRAINTCHANNEL_FLAG; + +/* -------------------------------------- */ + +/** + * The flags for ROTLIKE, LOCLIKE and SIZELIKE should be kept identical + * (that is, same effect, different name). It simplifies the Python API access a lot. + */ + +/* bRotateLikeConstraint.flag */ +#define ROTLIKE_X 0x01 +#define ROTLIKE_Y 0x02 +#define ROTLIKE_Z 0x04 +#define ROTLIKE_X_INVERT 0x10 +#define ROTLIKE_Y_INVERT 0x20 +#define ROTLIKE_Z_INVERT 0x40 +#define ROTLIKE_OFFSET 0x80 + +/* bLocateLikeConstraint.flag */ +#define LOCLIKE_X 0x01 +#define LOCLIKE_Y 0x02 +#define LOCLIKE_Z 0x04 +#define LOCLIKE_TIP 0x08 +#define LOCLIKE_X_INVERT 0x10 +#define LOCLIKE_Y_INVERT 0x20 +#define LOCLIKE_Z_INVERT 0x40 +#define LOCLIKE_OFFSET 0x80 + +/* bSizeLikeConstraint.flag */ +#define SIZELIKE_X 0x01 +#define SIZELIKE_Y 0x02 +#define SIZELIKE_Z 0x04 +#define SIZELIKE_OFFSET 0x80 + +/* Axis flags */ +#define LOCK_X 0x00 +#define LOCK_Y 0x01 +#define LOCK_Z 0x02 + +#define UP_X 0x00 +#define UP_Y 0x01 +#define UP_Z 0x02 + +#define TRACK_X 0x00 +#define TRACK_Y 0x01 +#define TRACK_Z 0x02 +#define TRACK_nX 0x03 +#define TRACK_nY 0x04 +#define TRACK_nZ 0x05 + +/* bTrackToConstraint->flags */ +#define TARGET_Z_UP 0x01 + +#define VOLUME_XZ 0x00 +#define VOLUME_X 0x01 +#define VOLUME_Z 0x02 +#define NO_VOLUME 0x03 + +#define PLANE_X 0x00 +#define PLANE_Y 0x01 +#define PLANE_Z 0x02 + +/* Clamp-To Constraint ->flag */ +#define CLAMPTO_AUTO 0 +#define CLAMPTO_X 1 +#define CLAMPTO_Y 2 +#define CLAMPTO_Z 3 + +/* ClampTo Constraint ->flag2 */ +#define CLAMPTO_CYCLIC 1 + +/* bKinematicConstraint->flag */ +#define CONSTRAINT_IK_TIP 1 +#define CONSTRAINT_IK_ROT 2 +#define CONSTRAINT_IK_AUTO 4 +#define CONSTRAINT_IK_TEMP 8 +#define CONSTRAINT_IK_STRETCH 16 +#define CONSTRAINT_IK_POS 32 +#define CONSTRAINT_IK_SETANGLE 64 +#define CONSTRAINT_IK_GETANGLE 128 + +/* MinMax (floor) flags */ +#define MINMAX_STICKY 0x01 +#define MINMAX_STUCK 0x02 +#define MINMAX_USEROT 0x04 + +/* transform limiting constraints -> flag */ +#define LIMIT_XMIN 0x01 +#define LIMIT_XMAX 0x02 +#define LIMIT_YMIN 0x04 +#define LIMIT_YMAX 0x08 +#define LIMIT_ZMIN 0x10 +#define LIMIT_ZMAX 0x20 + +#define LIMIT_XROT 0x01 +#define LIMIT_YROT 0x02 +#define LIMIT_ZROT 0x04 + +/* not used anymore - for older Limit Location constraints only */ +#define LIMIT_NOPARENT 0x01 + +/* python constraint -> flag */ +#define PYCON_USETARGETS 0x01 +#define PYCON_SCRIPTERROR 0x02 + +/* ChildOf Constraint -> flag */ +#define CHILDOF_LOCX 0x001 +#define CHILDOF_LOCY 0x002 +#define CHILDOF_LOCZ 0x004 +#define CHILDOF_ROTX 0x008 +#define CHILDOF_ROTY 0x010 +#define CHILDOF_ROTZ 0x020 +#define CHILDOF_SIZEX 0x040 +#define CHILDOF_SIZEY 0x080 +#define CHILDOF_SIZEZ 0x100 + +/* Rigid-Body Constraint */ +#define CONSTRAINT_DRAW_PIVOT 0x40 + +/* important: these defines need to match up with PHY_DynamicTypes headerfile */ +#define CONSTRAINT_RB_BALL 1 +#define CONSTRAINT_RB_HINGE 2 +#define CONSTRAINT_RB_CONETWIST 4 +#define CONSTRAINT_RB_VEHICLE 11 +#define CONSTRAINT_RB_GENERIC6DOF 12 + +#endif diff --git a/source/blender/makesdna/DNA_controller_types.h b/source/blender/makesdna/DNA_controller_types.h new file mode 100644 index 00000000000..b8bffd68db8 --- /dev/null +++ b/source/blender/makesdna/DNA_controller_types.h @@ -0,0 +1,79 @@ +/** + * blenlib/DNA_controller_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_CONTROLLER_TYPES_H +#define DNA_CONTROLLER_TYPES_H + +struct bActuator; +struct Text; +struct bSensor; + +/* ****************** CONTROLLERS ********************* */ + +typedef struct bExpressionCont { + char str[128]; +} bExpressionCont; + +typedef struct bPythonCont { + struct Text *text; +} bPythonCont; + +typedef struct bController { + struct bController *next, *prev, *mynew; + short type, flag, inputs, totlinks; + short otype, totslinks, pad2, pad3; + + char name[32]; + void *data; + + struct bActuator **links; + + struct bSensor **slinks; + short val, valo; + int pad5; + +} bController; + +/* controller->type */ +#define CONT_LOGIC_AND 0 +#define CONT_LOGIC_OR 1 +#define CONT_EXPRESSION 2 +#define CONT_PYTHON 3 + +/* controller->flag */ +#define CONT_SHOW 1 +#define CONT_DEL 2 +#define CONT_NEW 4 + +#endif + diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h new file mode 100644 index 00000000000..807fc2add07 --- /dev/null +++ b/source/blender/makesdna/DNA_curve_types.h @@ -0,0 +1,290 @@ +/** + * blenlib/DNA_curve_types.h (mar-2001 nzc) + * + * Curve stuff. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_CURVE_TYPES_H +#define DNA_CURVE_TYPES_H + +#include "DNA_listBase.h" +#include "DNA_vec_types.h" +#include "DNA_ID.h" + +#define MAXTEXTBOX 256 /* used in readfile.c and editfont.c */ + +struct BoundBox; +struct Object; +struct Ipo; +struct Key; +struct Material; +struct VFont; + +/* These two Lines with # tell makesdna this struct can be excluded. */ +# +# +typedef struct Path { + int len; + float *data; + float totdist; +} Path; + +/* These two Lines with # tell makesdna this struct can be excluded. */ +# +# +typedef struct BevList { + struct BevList *next, *prev; + int nr, flag; + short poly, gat; +} BevList; + +/* These two Lines with # tell makesdna this struct can be excluded. */ +# +# +typedef struct BevPoint { + float x, y, z, alfa, sina, cosa, mat[3][3]; + short f1, f2; +} BevPoint; + +/* Keyframes on IPO curves and Points on Bezier Curves/Paths are generally BezTriples */ +/* note: alfa location in struct is abused by Key system */ +/* vec in BezTriple looks like this: + vec[0][0]=x location of handle 1 + vec[0][1]=y location of handle 1 + vec[0][2]=z location of handle 1 (not used for IpoCurve Points(2d)) + vec[1][0]=x location of control point + vec[1][1]=y location of control point + vec[1][2]=z location of control point + vec[2][0]=x location of handle 2 + vec[2][1]=y location of handle 2 + vec[2][2]=z location of handle 2 (not used for IpoCurve Points(2d)) +*/ +typedef struct BezTriple { + float vec[3][3]; + float alfa, weight, radius; /* alfa: tilt in 3D View, weight: used for softbody goal weight, radius: for bevel tapering */ + short h1, h2; /* h1, h2: the handle type of the two handles */ + char f1, f2, f3, hide; /* f1, f2, f3: used for selection status, hide: used to indicate whether BezTriple is hidden */ +} BezTriple; + +/* note; alfa location in struct is abused by Key system */ +typedef struct BPoint { + float vec[4]; + float alfa, weight; /* alfa: tilt in 3D View, weight: used for softbody goal weight */ + short f1, hide; /* f1: selection status, hide: is point hidden or not */ + float radius, pad; /* user-set radius per point for bevelling etc */ +} BPoint; + +typedef struct Nurb { + struct Nurb *next, *prev; /* multiple nurbs per curve object are allowed */ + short type; + short mat_nr; /* index into material list */ + short hide, flag; + short pntsu, pntsv; /* number of points in the U or V directions */ + short resolu, resolv; /* tesselation resolution in the U or V directions */ + short orderu, orderv; + short flagu, flagv; + + float *knotsu, *knotsv; + BPoint *bp; + BezTriple *bezt; + + short tilt_interp; /* KEY_LINEAR, KEY_CARDINAL, KEY_BSPLINE */ + short pad; + + int charidx; +} Nurb; + +typedef struct CharInfo { + short kern; + short mat_nr; + char flag; + char pad; + short pad2; +} CharInfo; + +typedef struct TextBox { + float x, y, w, h; +} TextBox; + +typedef struct Curve { + ID id; + + struct BoundBox *bb; + + ListBase nurb; + ListBase disp; + struct Object *bevobj, *taperobj, *textoncurve; + struct Ipo *ipo; + Path *path; + struct Key *key; + struct Material **mat; + + ListBase bev; + + /* texture space, copied as one block in editobject.c */ + float loc[3]; + float size[3]; + float rot[3]; + + int texflag; + + short pathlen, totcol; + short flag, bevresol; + float width, ext1, ext2; + + /* default */ + short resolu, resolv; + short resolu_ren, resolv_ren; + int pad2; + + /* font part */ + short len, lines, pos, spacemode; + float spacing, linedist, shear, fsize, wordspace, ulpos, ulheight; + float xof, yof; + float linewidth; + + char *str; + char family[24]; + struct VFont *vfont; + struct VFont *vfontb; + struct VFont *vfonti; + struct VFont *vfontbi; + + int sepchar; + + int totbox, actbox, pad; + struct TextBox *tb; + + int selstart, selend; + + struct CharInfo *strinfo; + struct CharInfo curinfo; +} Curve; + +typedef struct IpoDriver { + struct Object *ob; + short blocktype, adrcode, type, flag; + char name[128]; /* bone or constraint(?), or python expression here */ +} IpoDriver; + +/* temp? we store more bone names in 1 driver... */ +#define DRIVER_NAME_OFFS 32 + +typedef struct IpoCurve { + struct IpoCurve *next, *prev; + + struct BPoint *bp; /* are these even used anywhere? */ + struct BezTriple *bezt; /* array of BezTriples (sizeof(BezTriple)*totvert. i.e. keyframes */ + + rctf maxrct, totrct; /* bounding boxes */ + + short blocktype, adrcode, vartype; /* blocktype= ipo-blocktype; adrcode= type of ipo-curve; vartype= 'format' of data */ + short totvert; /* total number of BezTriples (i.e. keyframes) on curve */ + short ipo, extrap; /* interpolation and extrapolation modes */ + short flag, rt; /* flag= settings; rt= ??? */ + float ymin, ymax; /* minimum/maximum y-extents for curve */ + unsigned int bitmask; /* ??? */ + + float slide_min, slide_max; /* minimum/maximum values for sliders (in action editor) */ + float curval; /* value of ipo-curve for current frame */ + + IpoDriver *driver; /* pointer to ipo-driver for this curve */ + +} IpoCurve; + +/* **************** CURVE ********************* */ + +/* texflag */ +#define CU_AUTOSPACE 1 + +/* flag */ +#define CU_3D 1 +#define CU_FRONT 2 +#define CU_BACK 4 +#define CU_PATH 8 +#define CU_FOLLOW 16 +#define CU_UV_ORCO 32 +#define CU_NOPUNOFLIP 64 +#define CU_STRETCH 128 +#define CU_OFFS_PATHDIST 256 +#define CU_FAST 512 /* Font: no filling inside editmode */ +#define CU_RETOPO 1024 + +/* spacemode */ +#define CU_LEFT 0 +#define CU_MIDDLE 1 +#define CU_RIGHT 2 +#define CU_JUSTIFY 3 +#define CU_FLUSH 4 + +/* flag (nurb) */ +#define CU_SMOOTH 1 + +/* type (nurb) */ +#define CU_POLY 0 +#define CU_BEZIER 1 +#define CU_BSPLINE 2 +#define CU_CARDINAL 3 +#define CU_NURBS 4 +#define CU_2D 8 + +/* flagu flagv (nurb) */ +#define CU_CYCLIC 1 + +/* h1 h2 (beztriple) */ +#define HD_FREE 0 +#define HD_AUTO 1 +#define HD_VECT 2 +#define HD_ALIGN 3 +#define HD_AUTO_ANIM 4 + +/* *************** CHARINFO **************** */ + +/* flag */ +#define CU_STYLE (1+2) +#define CU_BOLD 1 +#define CU_ITALIC 2 +#define CU_UNDERLINE 4 +#define CU_WRAP 8 /* wordwrap occured here */ + +/* *************** driver ****************** */ + +/* driver->type */ +#define IPO_DRIVER_TYPE_NORMAL 0 +#define IPO_DRIVER_TYPE_PYTHON 1 + +/* driver->flag */ +/* invalid flag: currently only used for buggy pydriver expressions: */ +#define IPO_DRIVER_FLAG_INVALID 1 + +#endif + diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h new file mode 100644 index 00000000000..1c1676ba277 --- /dev/null +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -0,0 +1,102 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_CUSTOMDATA_TYPES_H +#define DNA_CUSTOMDATA_TYPES_H + +/* descriptor and storage for a custom data layer */ +typedef struct CustomDataLayer { + int type; /* type of data in layer */ + int offset; /* in editmode, offset of layer in block */ + int flag; /* general purpose flag */ + int active; /* number of the active layer of this type */ + int active_rnd; /* number of the layer to render*/ + char pad[4]; + char name[32]; /* layer name */ + void *data; /* layer data */ +} CustomDataLayer; + +/* structure which stores custom element data associated with mesh elements + * (vertices, edges or faces). The custom data is organised into a series of + * layers, each with a data type (e.g. MTFace, MDeformVert, etc.). */ +typedef struct CustomData { + CustomDataLayer *layers; /* CustomDataLayers, ordered by type */ + int totlayer, maxlayer; /* number of layers, size of layers array */ + int totsize, pad; /* in editmode, total size of all data layers */ +} CustomData; + +/* CustomData.type */ +#define CD_MVERT 0 +#define CD_MSTICKY 1 +#define CD_MDEFORMVERT 2 +#define CD_MEDGE 3 +#define CD_MFACE 4 +#define CD_MTFACE 5 +#define CD_MCOL 6 +#define CD_ORIGINDEX 7 +#define CD_NORMAL 8 +#define CD_FLAGS 9 +#define CD_PROP_FLT 10 +#define CD_PROP_INT 11 +#define CD_PROP_STR 12 +#define CD_NUMTYPES 13 + +/* Bits for CustomDataMask */ +#define CD_MASK_MVERT (1 << CD_MVERT) +#define CD_MASK_MSTICKY (1 << CD_MSTICKY) +#define CD_MASK_MDEFORMVERT (1 << CD_MDEFORMVERT) +#define CD_MASK_MEDGE (1 << CD_MEDGE) +#define CD_MASK_MFACE (1 << CD_MFACE) +#define CD_MASK_MTFACE (1 << CD_MTFACE) +#define CD_MASK_MCOL (1 << CD_MCOL) +#define CD_MASK_ORIGINDEX (1 << CD_ORIGINDEX) +#define CD_MASK_NORMAL (1 << CD_NORMAL) +#define CD_MASK_FLAGS (1 << CD_FLAGS) +#define CD_MASK_PROP_FLT (1 << CD_PROP_FLT) +#define CD_MASK_PROP_INT (1 << CD_PROP_INT) +#define CD_MASK_PROP_STR (1 << CD_PROP_STR) + + +/* CustomData.flag */ + +/* indicates layer should not be copied by CustomData_from_template or + * CustomData_copy_data */ +#define CD_FLAG_NOCOPY (1<<0) +/* indicates layer should not be freed (for layers backed by external data) */ +#define CD_FLAG_NOFREE (1<<1) +/* indicates the layer is only temporary, also implies no copy */ +#define CD_FLAG_TEMPORARY ((1<<2)|CD_FLAG_NOCOPY) + +/* Limits */ +#define MAX_MTFACE 8 +#define MAX_MCOL 8 + +#endif diff --git a/source/blender/makesdna/DNA_documentation.h b/source/blender/makesdna/DNA_documentation.h new file mode 100644 index 00000000000..45b58f17750 --- /dev/null +++ b/source/blender/makesdna/DNA_documentation.h @@ -0,0 +1,79 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + * @mainpage DNA- Makesdna modules + * + * @section about About the DNA module + * + * The DNA module holds all type definitions that are serialized in a + * blender file. There is an executable that scans all files, looking + * for struct-s to serialize (hence sdna: Struct DNA). From this + * information, it builds a file with numbers that encode the format, + * the names of variables, and the plce to look for them. + * + * @section issues Known issues with DNA + * + * - Function pointers: + * + * Because of historical reasons, some function pointers were + * untyped. The parser/dna generator has been modified to explicitly + * handle these special cases. Most pointers have been given proper + * proto's by now. DNA_space_types.h::Spacefile::returnfuncmay still + * be badly defined. The reason for this is that is is called with + * different types of arguments. It takes a char* at this moment... + * + * - Path to the header files + * + * Also because of historical reasons, there is a path prefix to the + * headers that need to be scanned. This is the BASE_HEADER + * define. If you change the file-layout for DNA, you will probably + * have to change this (Not very flexible, but it is hardly ever + * changed. Sorry.). + * + * @section dependencies Dependencies + * + * DNA has no external dependencies (except for a few system + * includes). + * + **/ + + +/* PLEASE READ INSTRUCTIONS ABOUT ADDING VARIABLES IN 'DNA' STRUCTS IN + + ../blenloader/intern/genfile.c + (ton) + + */ + + + +/* This file has intentionally no definitions or implementation. */ + diff --git a/source/blender/makesdna/DNA_effect_types.h b/source/blender/makesdna/DNA_effect_types.h new file mode 100644 index 00000000000..4d910861acd --- /dev/null +++ b/source/blender/makesdna/DNA_effect_types.h @@ -0,0 +1,144 @@ +/** + * blenlib/DNA_effect_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_EFFECT_TYPES_H +#define DNA_EFFECT_TYPES_H + +/* don't forget, new effects also in writefile.c for dna!!! */ + +#define PAF_MAXMULT 4 + +/* paf->flag (keep bit 0 free for compatibility) */ +#define PAF_BSPLINE 2 +#define PAF_STATIC 4 +#define PAF_FACE 8 +#define PAF_ANIMATED 16 + /* show particles before they're emitted*/ +#define PAF_UNBORN 32 + /* emit only from faces*/ +#define PAF_OFACE 64 + /* show emitter (don't hide actual mesh)*/ +#define PAF_SHOWE 128 + /* true random emit from faces (not just ordered jitter)*/ +#define PAF_TRAND 256 + /* even distribution in face emission based on face areas*/ +#define PAF_EDISTR 512 + /*show particles after they've died*/ +#define PAF_DIED 2048 + + +/*paf->flag2 for pos/neg paf->flag2neg*/ +#define PAF_TEXTIME 1 /*texture timing*/ + + /* eff->type */ +#define EFF_BUILD 0 +#define EFF_PARTICLE 1 +#define EFF_WAVE 2 + + /* eff->flag */ +#define EFF_SELECT 1 + + /* paf->stype */ +#define PAF_NORMAL 0 +#define PAF_VECT 1 + + /* paf->texmap */ +#define PAF_TEXINT 0 +#define PAF_TEXRGB 1 +#define PAF_TEXGRAD 2 + +typedef struct Effect { + struct Effect *next, *prev; + short type, flag, buttype, rt; + +} Effect; + +typedef struct BuildEff { + struct BuildEff *next, *prev; + short type, flag, buttype, rt; + + float len, sfra; + +} BuildEff; + +# +# +typedef struct Particle { + float co[3], no[3]; + float time, lifetime; + short mat_nr, rt; +} Particle; + +struct Group; + +typedef struct PartEff { + struct PartEff *next, *prev; + short type, flag, buttype, stype, vertgroup, userjit; + + float sta, end, lifetime; + int totpart, totkey, seed; + + float normfac, obfac, randfac, texfac, randlife; + float force[3]; + float damp; + + float nabla, vectsize, maxlen, pad, defvec[3]; + + float mult[4], life[4]; + short child[4], mat[4]; + short texmap, curmult; + short staticstep, omat, timetex, speedtex, flag2, flag2neg; + short disp, vertgroup_v; + + char vgroupname[32], vgroupname_v[32]; + float imat[4][4]; /* inverse matrix of parent Object */ + + Particle *keys; + struct Group *group; + +} PartEff; + + +typedef struct WaveEff { + struct WaveEff *next, *prev; + short type, flag, buttype, stype; + + float startx, starty, height, width; + float narrow, speed, minfac, damp; + + float timeoffs, lifetime; + +} WaveEff; + +#endif + diff --git a/source/blender/makesdna/DNA_fileglobal_types.h b/source/blender/makesdna/DNA_fileglobal_types.h new file mode 100644 index 00000000000..1aecf4da017 --- /dev/null +++ b/source/blender/makesdna/DNA_fileglobal_types.h @@ -0,0 +1,60 @@ +/** + * blenlib/DNA_fileglobal_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_FILEGLOBAL_TYPES_H +#define DNA_FILEGLOBAL_TYPES_H + +/** + * FileGlobal stores a part of the current user-unterface settings at + * the moment of saving, and the file-specific settings. + */ +typedef struct FileGlobal { + char subvstr[4]; /* needs to be here, for human fileformat recognition */ + short subversion, pads; + short minversion, minsubversion; + short displaymode, winpos; + void *curscreen; + void *curscene; + int fileflags; + int globalf; +} FileGlobal; + + +/* minversion: in file, the oldest past blender version you can use compliant */ +/* example: if in 2.43 the meshes lose mesh data, minversion is 2.43 then too */ +/* or: in 2.42, subversion 1, same as above, minversion then is 2.42, min subversion 1 */ +/* (defines for version are in the BKE_blender.h file, for historic reasons) */ + + +#endif + diff --git a/source/blender/makesdna/DNA_group_types.h b/source/blender/makesdna/DNA_group_types.h new file mode 100644 index 00000000000..3a074dd63bc --- /dev/null +++ b/source/blender/makesdna/DNA_group_types.h @@ -0,0 +1,65 @@ +/** + * blenlib/DNA_group_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_GROUP_TYPES_H +#define DNA_GROUP_TYPES_H + +#include "DNA_listBase.h" +#include "DNA_ID.h" + +struct Object; + +typedef struct GroupObject { + struct GroupObject *next, *prev; + struct Object *ob; + void *lampren; /* used while render */ + int recalc; /* copy of ob->recalc, used to set animated groups OK */ + int pad; +} GroupObject; + + +typedef struct Group { + ID id; + + ListBase gobject; /* GroupObject */ + + /* Bad design, since layers stored in the scenes 'Base' + * the objects that show in the group can change depending + * on the last used scene */ + unsigned int layer; + int pad; +} Group; + + +#endif + diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h new file mode 100644 index 00000000000..8a5a7ce4a4c --- /dev/null +++ b/source/blender/makesdna/DNA_image_types.h @@ -0,0 +1,124 @@ +/** + * blenlib/DNA_image_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_IMAGE_TYPES_H +#define DNA_IMAGE_TYPES_H + +#include "DNA_ID.h" + +struct PackedFile; +struct anim; +struct ImBuf; +struct RenderResult; + + +/* ImageUser is in Texture, in Nodes, Background Image, Image Window, .... */ +/* should be used in conjunction with an ID * to Image. */ +typedef struct ImageUser { + int framenr; /* movies, sequences: current to display */ + int frames; /* total amount of frames to use */ + int offset, sfra; /* offset within movie, start frame in global time */ + short fie_ima, cycl; /* fields/image in movie, cyclic flag */ + short flag, ok; + + short multi_index, layer, pass; /* listbase indices, for menu browsing or retrieve buffer */ + short menunr; /* localized menu entry, for handling browse event */ +} ImageUser; + +/* iuser->flag */ +#define IMA_ANIM_ALWAYS 1 +#define IMA_ANIM_REFRESHED 2 + +typedef struct Image { + ID id; + + char name[240]; /* file path */ + + ListBase ibufs; /* not written in file */ + + /* sources from: */ + struct anim *anim; + struct RenderResult *rr; + + short ok, flag; + short source, type, pad, pad1; + int lastframe; + + /* texture page */ + short tpageflag, totbind; + short xrep, yrep; + short twsta, twend; + unsigned int bindcode; /* only for current image... */ + unsigned int *repbind; /* for repeat of parts of images */ + + struct PackedFile * packedfile; + struct PreviewImage * preview; + + float lastupdate; + int lastused; + short animspeed; + + short gen_x, gen_y, gen_type; /* for generated images */ + + /* display aspect - for UV editing images resized for faster openGL display */ + float aspx, aspy; + +/*#ifdef WITH_VERSE*/ + void *vnode; /* pointer at verse bitmap node */ +/*#endif*/ +} Image; + + +/* **************** IMAGE ********************* */ + +/* flag */ +#define IMA_FIELDS 1 +#define IMA_STD_FIELD 2 + +#define IMA_REFLECT 16 +#define IMA_NOCOLLECT 32 +#define IMA_ANTIALI 64 + + +/* tpageflag */ +#define IMA_TILES 1 +#define IMA_TWINANIM 2 +#define IMA_COLCYCLE 4 /* Depreciated */ +#define IMA_MIPMAP_COMPLETE 8 /* all mipmap levels in OpenGL texture set? */ +#define IMA_CLAMP_U 16 +#define IMA_CLAMP_V 32 + +/* ima->type and ima->source moved to BKE_image.h, for API */ + +#endif + diff --git a/source/blender/makesdna/DNA_ipo_types.h b/source/blender/makesdna/DNA_ipo_types.h new file mode 100644 index 00000000000..1fca73b576c --- /dev/null +++ b/source/blender/makesdna/DNA_ipo_types.h @@ -0,0 +1,401 @@ +/** + * blenlib/DNA_ipo_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_IPO_TYPES_H +#define DNA_IPO_TYPES_H + +#include "DNA_listBase.h" +#include "DNA_vec_types.h" + +#include "DNA_ID.h" + +/* IPO Data-Block */ +typedef struct Ipo { + ID id; + + ListBase curve; /* A list of IpoCurve structs in a linked list. */ + rctf cur; /* Rect defining extents of keyframes? */ + + short blocktype, showkey; /* blocktype: self-explanatory; showkey: either 0 or 1 (show vertical yellow lines for editing) */ + short muteipo, pad; /* muteipo: either 0 or 1 (whether ipo block is muted) */ +} Ipo; + +/* NOTE: IpoCurve struct is defined in DNA_curve_types.h, not in here... */ + +/* sometimes used */ +typedef short IPO_Channel; + +/* defines: are these duped or new? */ + +#define IPOBUTY 17 + +#define TOB_IPO 1 +#define TOB_IPODROT 2 + +/* disptype */ +#define IPO_DISPDEGR 1 +#define IPO_DISPBITS 2 +#define IPO_DISPTIME 3 + +/* ******************** */ + +#define OB_TOTIPO 29 +#define OB_TOTNAM 29 + +#define OB_LOC_X 1 +#define OB_LOC_Y 2 +#define OB_LOC_Z 3 +#define OB_DLOC_X 4 +#define OB_DLOC_Y 5 +#define OB_DLOC_Z 6 + +#define OB_ROT_X 7 +#define OB_ROT_Y 8 +#define OB_ROT_Z 9 +#define OB_DROT_X 10 +#define OB_DROT_Y 11 +#define OB_DROT_Z 12 + +#define OB_SIZE_X 13 +#define OB_SIZE_Y 14 +#define OB_SIZE_Z 15 +#define OB_DSIZE_X 16 +#define OB_DSIZE_Y 17 +#define OB_DSIZE_Z 18 + +#define OB_LAY 19 + +#define OB_TIME 20 + +#define OB_COL_R 21 +#define OB_COL_G 22 +#define OB_COL_B 23 +#define OB_COL_A 24 + +#define OB_PD_FSTR 25 +#define OB_PD_FFALL 26 +#define OB_PD_SDAMP 27 +#define OB_PD_RDAMP 28 +#define OB_PD_PERM 29 + +/* exception: driver channel, for bone driver only */ +#define OB_ROT_DIFF 100 + + +/* ******************** */ + +#define MA_TOTIPO 40 +#define MA_TOTNAM 26 + +#define MA_COL_R 1 +#define MA_COL_G 2 +#define MA_COL_B 3 +#define MA_SPEC_R 4 +#define MA_SPEC_G 5 +#define MA_SPEC_B 6 +#define MA_MIR_R 7 +#define MA_MIR_G 8 +#define MA_MIR_B 9 +#define MA_REF 10 +#define MA_ALPHA 11 +#define MA_EMIT 12 +#define MA_AMB 13 +#define MA_SPEC 14 +#define MA_HARD 15 +#define MA_SPTR 16 +#define MA_IOR 17 +#define MA_MODE 18 +#define MA_HASIZE 19 +#define MA_TRANSLU 20 +#define MA_RAYM 21 +#define MA_FRESMIR 22 +#define MA_FRESMIRI 23 +#define MA_FRESTRA 24 +#define MA_FRESTRAI 25 +#define MA_ADD 26 + +#define MA_MAP1 0x20 +#define MA_MAP2 0x40 +#define MA_MAP3 0x80 +#define MA_MAP4 0x100 +#define MA_MAP5 0x200 +#define MA_MAP6 0x400 +#define MA_MAP7 0x800 +#define MA_MAP8 0x1000 +#define MA_MAP9 0x2000 +#define MA_MAP10 0x4000 + +#define TEX_TOTNAM 14 + +#define MAP_OFS_X 1 +#define MAP_OFS_Y 2 +#define MAP_OFS_Z 3 +#define MAP_SIZE_X 4 +#define MAP_SIZE_Y 5 +#define MAP_SIZE_Z 6 +#define MAP_R 7 +#define MAP_G 8 +#define MAP_B 9 + +#define MAP_DVAR 10 +#define MAP_COLF 11 +#define MAP_NORF 12 +#define MAP_VARF 13 +#define MAP_DISP 14 + +/* ******************** */ + +#define TE_TOTIPO 26 +#define TE_TOTNAM 26 + +#define TE_NSIZE 1 +#define TE_NDEPTH 2 +#define TE_NTYPE 3 +#define TE_TURB 4 + +#define TE_VNW1 5 +#define TE_VNW2 6 +#define TE_VNW3 7 +#define TE_VNW4 8 +#define TE_VNMEXP 9 +#define TE_VN_DISTM 10 +#define TE_VN_COLT 11 + +#define TE_ISCA 12 +#define TE_DISTA 13 + +#define TE_MG_TYP 14 +#define TE_MGH 15 +#define TE_MG_LAC 16 +#define TE_MG_OCT 17 +#define TE_MG_OFF 18 +#define TE_MG_GAIN 19 + +#define TE_N_BAS1 20 +#define TE_N_BAS2 21 + +#define TE_COL_R 22 +#define TE_COL_G 23 +#define TE_COL_B 24 +#define TE_BRIGHT 25 +#define TE_CONTRA 26 + +/* ******************** */ + +#define SEQ_TOTIPO 1 +#define SEQ_TOTNAM 1 + +#define SEQ_FAC1 1 + +/* ******************** */ + +#define CU_TOTIPO 1 +#define CU_TOTNAM 1 + +#define CU_SPEED 1 + +/* ******************** */ + +#define KEY_TOTIPO 64 +#define KEY_TOTNAM 64 + +#define KEY_SPEED 0 +#define KEY_NR 1 + +/* ******************** */ + +#define WO_TOTIPO 29 +#define WO_TOTNAM 16 + +#define WO_HOR_R 1 +#define WO_HOR_G 2 +#define WO_HOR_B 3 +#define WO_ZEN_R 4 +#define WO_ZEN_G 5 +#define WO_ZEN_B 6 + +#define WO_EXPOS 7 + +#define WO_MISI 8 +#define WO_MISTDI 9 +#define WO_MISTSTA 10 +#define WO_MISTHI 11 + +#define WO_STAR_R 12 +#define WO_STAR_G 13 +#define WO_STAR_B 14 +#define WO_STARDIST 15 +#define WO_STARSIZE 16 + +/* ******************** */ + +#define LA_TOTIPO 21 +#define LA_TOTNAM 10 + +#define LA_ENERGY 1 +#define LA_COL_R 2 +#define LA_COL_G 3 +#define LA_COL_B 4 +#define LA_DIST 5 +#define LA_SPOTSI 6 +#define LA_SPOTBL 7 +#define LA_QUAD1 8 +#define LA_QUAD2 9 +#define LA_HALOINT 10 + +/* ******************** */ + +/* yafray: totipo & totnam +2 because of added curves */ +#define CAM_TOTIPO 7 +#define CAM_TOTNAM 7 + +#define CAM_LENS 1 +#define CAM_STA 2 +#define CAM_END 3 + +/* yafray aperture & focal distance curves */ +#define CAM_YF_APERT 4 +#define CAM_YF_FDIST 5 + +#define CAM_SHIFT_X 6 +#define CAM_SHIFT_Y 7 + +/* ******************** */ + +#define SND_TOTIPO 4 +#define SND_TOTNAM 4 + +#define SND_VOLUME 1 +#define SND_PITCH 2 +#define SND_PANNING 3 +#define SND_ATTEN 4 + +/* ******************** */ + +#define AC_TOTIPO 10 /* __NLA */ +#define AC_TOTNAM 10 + +#define AC_LOC_X 1 +#define AC_LOC_Y 2 +#define AC_LOC_Z 3 + +#define AC_SIZE_X 13 +#define AC_SIZE_Y 14 +#define AC_SIZE_Z 15 + +#define AC_QUAT_W 25 +#define AC_QUAT_X 26 +#define AC_QUAT_Y 27 +#define AC_QUAT_Z 28 + +/* ******************** */ +#define CO_TOTIPO 1 /* Constraint Ipos */ +#define CO_TOTNAM 1 + +#define CO_ENFORCE 1 +/* +#define CO_TIME 2 +#define CO_OFFSET_X 3 +#define CO_OFFSET_Y 4 +#define CO_OFFSET_Z 5 +#define CO_ORIENT_X 6 +#define CO_ORIENT_Y 7 +#define CO_ORIENT_Z 8 +#define CO_ROLL 9 +*/ + +/* ******************** */ +/* fluidsim ipos NT */ + +#define FLUIDSIM_TOTIPO 9 +#define FLUIDSIM_TOTNAM 9 + +#define FLUIDSIM_VISC 1 +#define FLUIDSIM_TIME 2 + +#define FLUIDSIM_GRAV_X 3 +#define FLUIDSIM_GRAV_Y 4 +#define FLUIDSIM_GRAV_Z 5 + +#define FLUIDSIM_VEL_X 6 +#define FLUIDSIM_VEL_Y 7 +#define FLUIDSIM_VEL_Z 8 + +#define FLUIDSIM_ACTIVE 9 + + +/* these are IpoCurve specific */ +/* **************** IPO ********************* */ + +/* icu->vartype */ +#define IPO_CHAR 0 +#define IPO_SHORT 1 +#define IPO_INT 2 +#define IPO_LONG 3 +#define IPO_FLOAT 4 +#define IPO_DOUBLE 5 +#define IPO_FLOAT_DEGR 6 + /* very special case, in keys */ +#define IPO_BEZTRIPLE 100 +#define IPO_BPOINT 101 + +/* icu->vartype */ +#define IPO_BITS 16 +#define IPO_CHAR_BIT 16 +#define IPO_SHORT_BIT 17 +#define IPO_INT_BIT 18 + +/* icu->ipo: the type of curve */ +#define IPO_CONST 0 +#define IPO_LIN 1 +#define IPO_BEZ 2 +#define IPO_MIXED 3 /* not used yet */ + +/* icu->extrap */ +#define IPO_HORIZ 0 +#define IPO_DIR 1 +#define IPO_CYCL 2 +#define IPO_CYCLX 3 + +/* icu->flag */ +#define IPO_VISIBLE 1 +#define IPO_SELECT 2 +#define IPO_EDIT 4 +#define IPO_LOCK 8 +#define IPO_AUTO_HORIZ 16 +#define IPO_ACTIVE 32 +#define IPO_PROTECT 64 +#define IPO_MUTE 128 + +#endif + diff --git a/source/blender/makesdna/DNA_key_types.h b/source/blender/makesdna/DNA_key_types.h new file mode 100644 index 00000000000..3292e07f80e --- /dev/null +++ b/source/blender/makesdna/DNA_key_types.h @@ -0,0 +1,91 @@ +/** + * blenlib/DNA_key_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_KEY_TYPES_H +#define DNA_KEY_TYPES_H + +#include "DNA_listBase.h" +#include "DNA_ID.h" + +struct Ipo; + +typedef struct KeyBlock { + struct KeyBlock *next, *prev; + + float pos; + float curval; + short type, adrcode; + int totelem; + + void *data; + float *weights; + char name[32]; + char vgroup[32]; + + float slidermin; + float slidermax; +} KeyBlock; + + +typedef struct Key { + ID id; + + KeyBlock *refkey; + char elemstr[32]; + int elemsize; + float curval; + + ListBase block; + struct Ipo *ipo; + + ID *from; + + short type, totkey; + short slurph, flag; +} Key; + +/* **************** KEY ********************* */ + +/* key->type */ +#define KEY_NORMAL 0 +#define KEY_RELATIVE 1 + +/* key->flag */ + +/* keyblock->type */ +#define KEY_LINEAR 0 +#define KEY_CARDINAL 1 +#define KEY_BSPLINE 2 + +#endif + diff --git a/source/blender/makesdna/DNA_lamp_types.h b/source/blender/makesdna/DNA_lamp_types.h new file mode 100644 index 00000000000..f8cc2378cb1 --- /dev/null +++ b/source/blender/makesdna/DNA_lamp_types.h @@ -0,0 +1,174 @@ +/** + * blenlib/DNA_lamp_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_LAMP_TYPES_H +#define DNA_LAMP_TYPES_H + +#include "DNA_ID.h" +#include "DNA_scriptlink_types.h" + +#ifndef MAX_MTEX +#define MAX_MTEX 10 +#endif + +struct MTex; +struct Ipo; +struct CurveMapping; + +typedef struct Lamp { + ID id; + + short type, mode; + + short colormodel, totex; + float r, g, b, k; + + float energy, dist, spotsize, spotblend; + float haint; + + + float att1, att2; /* Quad1 and Quad2 attenuation */ + int pad2; + struct CurveMapping *curfalloff; + short falloff_type; + short pad3; + + float clipsta, clipend, shadspotsize; + float bias, soft; + short bufsize, samp, buffers, filtertype; + char bufflag, buftype; + + short ray_samp, ray_sampy, ray_sampz; + short ray_samp_type; + short area_shape; + float area_size, area_sizey, area_sizez; + float adapt_thresh; + short ray_samp_method; + short pad1; + + /* texact is for buttons */ + short texact, shadhalostep; + + /* yafray: photonlight params */ + int YF_numphotons, YF_numsearch; + short YF_phdepth, YF_useqmc, YF_bufsize, YF_pad; + float YF_causticblur, YF_ltradius; + /* yafray: glow params */ + float YF_glowint, YF_glowofs; + short YF_glowtype, YF_pad2; + + struct MTex *mtex[10]; + struct Ipo *ipo; + + /* preview */ + struct PreviewImage *preview; + + ScriptLink scriptlink; +} Lamp; + +/* **************** LAMP ********************* */ + +/* type */ +#define LA_LOCAL 0 +#define LA_SUN 1 +#define LA_SPOT 2 +#define LA_HEMI 3 +#define LA_AREA 4 +/* yafray: extra lamp type used for caustic photonmap */ +#define LA_YF_PHOTON 5 + +/* mode */ +#define LA_SHAD_BUF 1 +#define LA_HALO 2 +#define LA_LAYER 4 +#define LA_QUAD 8 /* no longer used */ +#define LA_NEG 16 +#define LA_ONLYSHADOW 32 +#define LA_SPHERE 64 +#define LA_SQUARE 128 +#define LA_TEXTURE 256 +#define LA_OSATEX 512 +#define LA_DEEP_SHADOW 1024 +#define LA_NO_DIFF 2048 +#define LA_NO_SPEC 4096 +#define LA_SHAD_RAY 8192 +/* yafray: lamp shadowbuffer flag, softlight */ +/* Since it is used with LOCAL lamp, can't use LA_SHAD */ +#define LA_YF_SOFT 16384 + +/* falloff_type */ +#define LA_FALLOFF_CONSTANT 0 +#define LA_FALLOFF_INVLINEAR 1 +#define LA_FALLOFF_INVSQUARE 2 +#define LA_FALLOFF_CURVE 3 +#define LA_FALLOFF_SLIDERS 4 + + +/* buftype, no flag */ +#define LA_SHADBUF_REGULAR 0 +#define LA_SHADBUF_IRREGULAR 1 +#define LA_SHADBUF_HALFWAY 2 + +/* bufflag, auto clipping */ +#define LA_SHADBUF_AUTO_START 1 +#define LA_SHADBUF_AUTO_END 2 + +/* filtertype */ +#define LA_SHADBUF_BOX 0 +#define LA_SHADBUF_TENT 1 +#define LA_SHADBUF_GAUSS 2 + +/* area shape */ +#define LA_AREA_SQUARE 0 +#define LA_AREA_RECT 1 +#define LA_AREA_CUBE 2 +#define LA_AREA_BOX 3 + +/* ray_samp_method */ +#define LA_SAMP_CONSTANT 0 +#define LA_SAMP_HALTON 1 +#define LA_SAMP_HAMMERSLEY 2 + + +/* ray_samp_type */ +#define LA_SAMP_ROUND 1 +#define LA_SAMP_UMBRA 2 +#define LA_SAMP_DITHER 4 +#define LA_SAMP_JITTER 8 + +/* mapto */ +#define LAMAP_COL 1 + + +#endif /* DNA_LAMP_TYPES_H */ + diff --git a/source/blender/makesdna/DNA_lattice_types.h b/source/blender/makesdna/DNA_lattice_types.h new file mode 100644 index 00000000000..823dc2ba485 --- /dev/null +++ b/source/blender/makesdna/DNA_lattice_types.h @@ -0,0 +1,67 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_LATTICE_TYPES_H +#define DNA_LATTICE_TYPES_H + +#include "DNA_ID.h" + +struct BPoint; +struct Ipo; +struct Key; +struct MDeformVert; + +typedef struct Lattice { + ID id; + + short pntsu, pntsv, pntsw, flag; + short opntsu, opntsv, opntsw, pad2; + char typeu, typev, typew, type; + int pad; + + float fu, fv, fw, du, dv, dw; + + struct BPoint *def; + + struct Ipo *ipo; + struct Key *key; + + struct MDeformVert *dvert; +} Lattice; + +/* ***************** LATTICE ********************* */ + +/* flag */ +#define LT_GRID 1 +#define LT_OUTSIDE 2 + +#endif + diff --git a/source/blender/makesdna/DNA_listBase.h b/source/blender/makesdna/DNA_listBase.h new file mode 100644 index 00000000000..10a1b59fb01 --- /dev/null +++ b/source/blender/makesdna/DNA_listBase.h @@ -0,0 +1,64 @@ +/** + * blenlib/BLI_listBase.h mar 2001 Nzc + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + * These structs are the foundation for all linked lists in the + * library system. + * + */ + +#ifndef DNA_LISTBASE_H +#define DNA_LISTBASE_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Link +{ + struct Link *next,*prev; +} Link; + +/* never change the size of this! genfile.c detects pointerlen with it */ +typedef struct ListBase +{ + void *first, *last; +} ListBase; + +/* 8 byte alignment! */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h new file mode 100644 index 00000000000..252af0ebdb1 --- /dev/null +++ b/source/blender/makesdna/DNA_material_types.h @@ -0,0 +1,294 @@ +/** + * blenlib/DNA_material_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_MATERIAL_TYPES_H +#define DNA_MATERIAL_TYPES_H + +#include "DNA_ID.h" +#include "DNA_scriptlink_types.h" +#include "DNA_listBase.h" + +#ifndef MAX_MTEX +#define MAX_MTEX 10 +#endif + +struct MTex; +struct Ipo; +struct Material; +struct ColorBand; +struct Group; +struct bNodeTree; + +/* WATCH IT: change type? also make changes in ipo.h */ + +typedef struct Material { + ID id; + + short colormodel, flag; + /* note, keep this below synced with render_types.h */ + float r, g, b; + float specr, specg, specb; + float mirr, mirg, mirb; + float ambr, ambb, ambg; + float amb, emit, ang, spectra, ray_mirror; + float alpha, ref, spec, zoffs, add; + float translucency; + /* end synced with render_types.h */ + + float fresnel_mir, fresnel_mir_i; + float fresnel_tra, fresnel_tra_i; + float filter; /* filter added, for raytrace transparency and transmissivity */ + float tx_limit, tx_falloff; + short ray_depth, ray_depth_tra; + short har; + char seed1, seed2; + + float gloss_mir, gloss_tra; + short samp_gloss_mir, samp_gloss_tra; + float adapt_thresh_mir, adapt_thresh_tra; + float aniso_gloss_mir; + float dist_mir; + short fadeto_mir; + short pad1; + + int mode, mode_l; /* mode_l is the or-ed result of all layer modes */ + short flarec, starc, linec, ringc; + float hasize, flaresize, subsize, flareboost; + float strand_sta, strand_end, strand_ease; + + float sbias; /* shadow bias */ + float shad_alpha, padf; /* in use for irregular shadowbuffer */ + + /* for buttons and render*/ + char rgbsel, texact, pr_type, use_nodes; + short pr_back, pr_lamp, septex, ml_flag; /* ml_flag is for disable base material */ + + /* shaders */ + short diff_shader, spec_shader; + float roughness, refrac; + float param[4]; /* size, smooth, size, smooth, for toonshader */ + float rms; + float darkness; + short texco, mapto; + + /* ramp colors */ + struct ColorBand *ramp_col; + struct ColorBand *ramp_spec; + char rampin_col, rampin_spec; + char rampblend_col, rampblend_spec; + short ramp_show, pad3; + float rampfac_col, rampfac_spec; + + struct MTex *mtex[10]; + struct bNodeTree *nodetree; + struct Ipo *ipo; + struct Group *group; /* light group */ + struct PreviewImage * preview; + + /* dynamic properties */ + float friction, fh, reflect; + float fhdist, xyfrict; + short dynamode, pad2; + + float sss_radius[3], sss_col[3]; + float sss_error, sss_scale, sss_ior; + float sss_colfac, sss_texfac; + float sss_front, sss_back; + short sss_flag, sss_preset; + + /* yafray: absorption color, dispersion parameters and material preset menu */ + float YF_ar, YF_ag, YF_ab, YF_dscale, YF_dpwr; + int YF_dsmp, YF_preset, YF_djit; + + ScriptLink scriptlink; +} Material; + +/* **************** MATERIAL ********************* */ + + /* maximum number of materials per material array + * (on object, mesh, lamp, etc.) + */ +#define MAXMAT 16 + +/* colormodel */ +#define MA_RGB 0 +#define MA_CMYK 1 +#define MA_YUV 2 +#define MA_HSV 3 + +/* flag */ + /* for render */ +#define MA_IS_USED 1 + +/* mode (is int) */ +#define MA_TRACEBLE 1 +#define MA_SHADOW 2 +#define MA_SHLESS 4 +#define MA_WIRE 8 +#define MA_VERTEXCOL 16 +#define MA_HALO 32 +#define MA_ZTRA 64 +#define MA_VERTEXCOLP 128 +#define MA_ZINV 256 +#define MA_HALO_RINGS 256 +#define MA_ENV 512 +#define MA_HALO_LINES 512 +#define MA_ONLYSHADOW 1024 +#define MA_HALO_XALPHA 1024 +#define MA_STAR 0x800 +#define MA_FACETEXTURE 0x800 +#define MA_HALOTEX 0x1000 +#define MA_HALOPUNO 0x2000 +#define MA_ONLYCAST 0x2000 +#define MA_NOMIST 0x4000 +#define MA_HALO_SHADE 0x4000 +#define MA_HALO_FLARE 0x8000 +#define MA_RADIO 0x10000 +#define MA_RAYTRANSP 0x20000 +#define MA_RAYMIRROR 0x40000 +#define MA_SHADOW_TRA 0x80000 +#define MA_RAMP_COL 0x100000 +#define MA_RAMP_SPEC 0x200000 +#define MA_RAYBIAS 0x400000 +#define MA_FULL_OSA 0x800000 +#define MA_TANGENT_STR 0x1000000 +#define MA_SHADBUF 0x2000000 + /* note; we drop MA_TANGENT_STR later to become tangent_u */ +#define MA_TANGENT_V 0x4000000 +/* qdn: a bit clumsy this, tangents needed for normal maps separated from shading */ +#define MA_NORMAP_TANG 0x8000000 +#define MA_GROUP_NOLAY 0x10000000 + +#define MA_MODE_MASK 0x1fffffff /* all valid mode bits */ + +/* ray mirror fadeout */ +#define MA_RAYMIR_FADETOSKY 0 +#define MA_RAYMIR_FADETOMAT 1 + +/* diff_shader */ +#define MA_DIFF_LAMBERT 0 +#define MA_DIFF_ORENNAYAR 1 +#define MA_DIFF_TOON 2 +#define MA_DIFF_MINNAERT 3 +#define MA_DIFF_FRESNEL 4 + +/* spec_shader */ +#define MA_SPEC_COOKTORR 0 +#define MA_SPEC_PHONG 1 +#define MA_SPEC_BLINN 2 +#define MA_SPEC_TOON 3 +#define MA_SPEC_WARDISO 4 + +/* dynamode */ +#define MA_DRAW_DYNABUTS 1 +#define MA_FH_NOR 2 + +/* ramps */ +#define MA_RAMP_IN_SHADER 0 +#define MA_RAMP_IN_ENERGY 1 +#define MA_RAMP_IN_NOR 2 +#define MA_RAMP_IN_RESULT 3 + +#define MA_RAMP_BLEND 0 +#define MA_RAMP_ADD 1 +#define MA_RAMP_MULT 2 +#define MA_RAMP_SUB 3 +#define MA_RAMP_SCREEN 4 +#define MA_RAMP_DIV 5 +#define MA_RAMP_DIFF 6 +#define MA_RAMP_DARK 7 +#define MA_RAMP_LIGHT 8 +#define MA_RAMP_OVERLAY 9 +#define MA_RAMP_DODGE 10 +#define MA_RAMP_BURN 11 +#define MA_RAMP_HUE 12 +#define MA_RAMP_SAT 13 +#define MA_RAMP_VAL 14 +#define MA_RAMP_COLOR 15 + +/* texco */ +#define TEXCO_ORCO 1 +#define TEXCO_REFL 2 +#define TEXCO_NORM 4 +#define TEXCO_GLOB 8 +#define TEXCO_UV 16 +#define TEXCO_OBJECT 32 +#define TEXCO_LAVECTOR 64 +#define TEXCO_VIEW 128 +#define TEXCO_STICKY 256 +#define TEXCO_OSA 512 +#define TEXCO_WINDOW 1024 +#define NEED_UV 2048 +#define TEXCO_TANGENT 4096 + /* still stored in vertex->accum, 1 D */ +#define TEXCO_STRAND 8192 +#define TEXCO_STRESS 16384 +#define TEXCO_SPEED 32768 + +/* mapto */ +#define MAP_COL 1 +#define MAP_NORM 2 +#define MAP_COLSPEC 4 +#define MAP_COLMIR 8 +#define MAP_VARS (0xFFF0) +#define MAP_REF 16 +#define MAP_SPEC 32 +#define MAP_EMIT 64 +#define MAP_ALPHA 128 +#define MAP_HAR 256 +#define MAP_RAYMIRR 512 +#define MAP_TRANSLU 1024 +#define MAP_AMB 2048 +#define MAP_DISPLACE 4096 +#define MAP_WARP 8192 +#define MAP_LAYER 16384 + +/* pr_type */ +#define MA_FLAT 0 +#define MA_SPHERE 1 +#define MA_CUBE 2 +#define MA_MONKEY 3 +#define MA_SPHERE_A 4 +#define MA_TEXTURE 5 +#define MA_LAMP 6 +#define MA_SKY 7 +#define MA_HAIR 10 + +/* pr_back */ +#define MA_DARK 1 + +/* sss_flag */ +#define MA_DIFF_SSS 1 + +#endif + diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h new file mode 100644 index 00000000000..59f3a64ba5e --- /dev/null +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -0,0 +1,139 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_MESH_TYPES_H +#define DNA_MESH_TYPES_H + +#include "DNA_listBase.h" +#include "DNA_ID.h" +#include "DNA_customdata_types.h" + +struct DerivedMesh; +struct Ipo; +struct Key; +struct Material; +struct MVert; +struct MEdge; +struct MFace; +struct MCol; +struct MSticky; +struct Mesh; +struct OcInfo; +struct Multires; +struct PartialVisibility; + +typedef struct Mesh { + ID id; + + struct BoundBox *bb; + + ListBase effect; + + struct Ipo *ipo; + struct Key *key; + struct Material **mat; + + struct MFace *mface; /* array of mesh object mode faces */ + struct MTFace *mtface; /* store face UV's and texture here */ + struct TFace *tface; /* depecrated, use mtface */ + struct MVert *mvert; /* array of verts */ + struct MEdge *medge; /* array of edges */ + struct MDeformVert *dvert; /* __NLA */ + struct MCol *mcol; /* array of colors, this must be the number of faces * 4 */ + struct MSticky *msticky; + struct Mesh *texcomesh; + struct MSelect *mselect; + + struct CustomData vdata, edata, fdata; + + int totvert, totedge, totface, totselect; + + /* the last selected vertex/edge/face are used for the active face however + * this means the active face must always be selected, this is to keep track + * of the last selected face and is similar to the old active face flag where + * the face does not need to be selected, -1 is inactive */ + int act_face; + + int texflag; + + /* texture space, copied as one block in editobject.c */ + float loc[3]; + float size[3]; + float rot[3]; + + float cubemapsize, pad; + + short smoothresh, flag; + + short subdiv, subdivr; + short totcol; + short subsurftype; /* only kept for backwards compat, not used anymore */ + + struct Multires *mr; /* Multiresolution modeling data */ + struct PartialVisibility *pv; +/*ifdef WITH_VERSE*/ + /* not written in file, pointer at geometry VerseNode */ + void *vnode; +/*#endif*/ +} Mesh; + +/* deprecated by MTFace, only here for file reading */ +typedef struct TFace { + void *tpage; /* the faces image for the active UVLayer */ + float uv[4][2]; + unsigned int col[4]; + char flag, transp; + short mode, tile, unwrap; +} TFace; + +/* **************** MESH ********************* */ + +/* texflag */ +#define AUTOSPACE 1 + +/* me->flag */ +#define ME_ISDONE 1 +#define ME_NOPUNOFLIP 2 +#define ME_TWOSIDED 4 +#define ME_UVEFFECT 8 +#define ME_VCOLEFFECT 16 +#define ME_AUTOSMOOTH 32 +#define ME_SMESH 64 +#define ME_SUBSURF 128 +#define ME_OPT_EDGES 256 + +/* Subsurf Type */ +#define ME_CC_SUBSURF 0 +#define ME_SIMPLE_SUBSURF 1 + +#define MESH_MAX_VERTS 2000000000L + +#endif diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h new file mode 100644 index 00000000000..68d9bb245cf --- /dev/null +++ b/source/blender/makesdna/DNA_meshdata_types.h @@ -0,0 +1,250 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_MESHDATA_TYPES_H +#define DNA_MESHDATA_TYPES_H + +#include "DNA_customdata_types.h" + +struct Bone; +struct Image; + +typedef struct MFace { + unsigned int v1, v2, v3, v4; + char pad, mat_nr; + char edcode, flag; /* we keep edcode, for conversion to edges draw flags in old files */ +} MFace; + +typedef struct MEdge { + unsigned int v1, v2; + char crease, pad; + short flag; +} MEdge; + +typedef struct MDeformWeight { + int def_nr; + float weight; +} MDeformWeight; + +typedef struct MDeformVert { + struct MDeformWeight *dw; + int totweight; + int flag; /* flag only in use for weightpaint now */ +} MDeformVert; + +typedef struct MVert { + float co[3]; + short no[3]; + char flag, mat_nr; +} MVert; + +/* at the moment alpha is abused for vertex painting + * and not used for transperency, note that red and blue are swapped */ +typedef struct MCol { + char a, r, g, b; +} MCol; + +typedef struct MSticky { + float co[2]; +} MSticky; + +typedef struct MSelect { + int index; + int type; +} MSelect; + +typedef struct MTFace { + float uv[4][2]; + struct Image *tpage; + char flag, transp; + short mode, tile, unwrap; +} MTFace; + +/*Custom Data Properties*/ +typedef struct MFloatProperty{ + float f; +} MFloatProperty; +typedef struct MIntProperty{ + int i; +} MIntProperty; +typedef struct MStringProperty{ + char s[256]; +} MStringProperty; + + +/* Multiresolution modeling */ +typedef struct MultiresCol { + float a, r, g, b; +} MultiresCol; +typedef struct MultiresColFace { + /* vertex colors */ + MultiresCol col[4]; +} MultiresColFace; +typedef struct MultiresFace { + unsigned int v[4]; + unsigned int mid; + char flag, mat_nr, pad[2]; +} MultiresFace; +typedef struct MultiresEdge { + unsigned int v[2]; + unsigned int mid; +} MultiresEdge; + +struct MultiresMapNode; +typedef struct MultiresLevel { + struct MultiresLevel *next, *prev; + + MultiresFace *faces; + MultiresColFace *colfaces; + MultiresEdge *edges; + + /* Temporary connectivity data */ + char *edge_boundary_states; + struct ListBase *vert_edge_map; + struct ListBase *vert_face_map; + struct MultiresMapNode *map_mem; + + unsigned int totvert, totface, totedge, pad; + + /* Kept for compatibility with older files */ + MVert *verts; +} MultiresLevel; + +typedef struct Multires { + ListBase levels; + MVert *verts; + + unsigned char level_count, current, newlvl, edgelvl, pinlvl, renderlvl; + unsigned char use_col, pad; + + /* Special level 1 data that cannot be modified from other levels */ + CustomData vdata; + CustomData fdata; + short *edge_flags; + char *edge_creases; +} Multires; + +typedef struct PartialVisibility { + unsigned int *vert_map; /* vert_map[Old Index]= New Index */ + int *edge_map; /* edge_map[Old Index]= New Index, -1= hidden */ + MFace *old_faces; + MEdge *old_edges; + unsigned int totface, totedge, totvert, pad; +} PartialVisibility; + +/* mvert->flag (1=SELECT) */ +#define ME_SPHERETEST 2 +#define ME_SPHERETEMP 4 +#define ME_HIDE 16 +#define ME_VERT_MERGED (1<<6) + +/* medge->flag (1=SELECT)*/ +#define ME_EDGEDRAW (1<<1) +#define ME_SEAM (1<<2) +#define ME_FGON (1<<3) + /* reserve 16 for ME_HIDE */ +#define ME_EDGERENDER (1<<5) +#define ME_LOOSEEDGE (1<<7) +#define ME_SEAM_LAST (1<<8) +#define ME_SHARP (1<<9) + +/* puno = vertexnormal (mface) */ +/* render assumes flips to be ordered like this */ +#define ME_FLIPV1 1 +#define ME_FLIPV2 2 +#define ME_FLIPV3 4 +#define ME_FLIPV4 8 +#define ME_PROJXY 16 +#define ME_PROJXZ 32 +#define ME_PROJYZ 64 + +/* edcode (mface) */ +#define ME_V1V2 1 +#define ME_V2V3 2 +#define ME_V3V1 4 +#define ME_V3V4 4 +#define ME_V4V1 8 + +/* flag (mface) */ +#define ME_SMOOTH 1 +#define ME_FACE_SEL 2 + /* flag ME_HIDE==16 is used here too */ +/* mselect->type */ +#define ME_VSEl 0 +#define ME_ESEl 1 +#define ME_FSEL 2 + +/* mtface->flag */ +#define TF_SELECT 1 /* use MFace hide flag (after 2.43), should be able to reuse after 2.44 */ +#define TF_ACTIVE 2 /* deprecated! */ +#define TF_SEL1 4 +#define TF_SEL2 8 +#define TF_SEL3 16 +#define TF_SEL4 32 +#define TF_HIDE 64 /* unused, same as TF_SELECT */ + +/* mtface->mode */ +#define TF_DYNAMIC 1 +#define TF_DEPRECATED 2 +#define TF_TEX 4 +#define TF_SHAREDVERT 8 +#define TF_LIGHT 16 + +#define TF_SHAREDCOL 64 +#define TF_TILES 128 +#define TF_BILLBOARD 256 +#define TF_TWOSIDE 512 +#define TF_INVISIBLE 1024 + +#define TF_OBCOL 2048 +#define TF_BILLBOARD2 4096 /* with Z axis constraint */ +#define TF_SHADOW 8192 +#define TF_BMFONT 16384 + +/* mtface->transp */ +#define TF_SOLID 0 +#define TF_ADD 1 +#define TF_ALPHA 2 + +/* sub is not available in the user interface anymore */ +#define TF_SUB 3 + +/* mtface->unwrap */ +#define TF_DEPRECATED1 1 +#define TF_DEPRECATED2 2 +#define TF_DEPRECATED3 4 +#define TF_DEPRECATED4 8 +#define TF_PIN1 16 +#define TF_PIN2 32 +#define TF_PIN3 64 +#define TF_PIN4 128 + +#endif diff --git a/source/blender/makesdna/DNA_meta_types.h b/source/blender/makesdna/DNA_meta_types.h new file mode 100644 index 00000000000..e14782cf5ca --- /dev/null +++ b/source/blender/makesdna/DNA_meta_types.h @@ -0,0 +1,120 @@ +/** + * blenlib/DNA_meta_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_META_TYPES_H +#define DNA_META_TYPES_H + +#include "DNA_listBase.h" +#include "DNA_ID.h" + +struct BoundBox; +struct Ipo; +struct Material; + + +typedef struct MetaElem { + struct MetaElem *next, *prev; + + struct BoundBox *bb; /* Bound Box of MetaElem */ + int i1,j1,k1, i2,j2,k2; /* corners of Bounding Box in lattice */ + + short type, flag, selcol1, selcol2; + float x, y, z; /* Position of center of MetaElem */ + float quat[4]; /* Rotation of MetaElem */ + float expx, expy, expz; /* dimension parameters, used for some types like cubes */ + float rad; /* radius of the meta element */ + float rad2; /* temp field, used only while processing */ + float s; /* stiffness, how much of the element to fill */ + float len; /* old, only used for backwards compat. use dimensions now */ + + float *mat, *imat; /* matrix and inverted matrix */ + +} MetaElem; + +typedef struct MetaBall { + ID id; + + struct BoundBox *bb; + + ListBase elems; + ListBase disp; + struct Ipo *ipo; + + /* material of the mother ball will define the material used of all others */ + struct Material **mat; + + short flag, totcol; + int texflag; /* used to store MB_AUTOSPACE */ + + /* texture space, copied as one block in editobject.c */ + float loc[3]; + float size[3]; + float rot[3]; + + float wiresize, rendersize; /* display and render res */ + + /* bias elements to have an offset volume. + mother ball changes will effect other objects thresholds, + but these may also have their own thresh as an offset */ + float thresh; + + +} MetaBall; + +/* **************** METABALL ********************* */ + +/* texflag */ +#define MB_AUTOSPACE 1 + +/* mb->flag */ +#define MB_UPDATE_ALWAYS 0 +#define MB_UPDATE_HALFRES 1 +#define MB_UPDATE_FAST 2 +#define MB_UPDATE_NEVER 3 + +/* ml->type */ +#define MB_BALL 0 +#define MB_TUBEX 1 /* depercated */ +#define MB_TUBEY 2 /* depercated */ +#define MB_TUBEZ 3 /* depercated */ +#define MB_TUBE 4 +#define MB_PLANE 5 +#define MB_ELIPSOID 6 +#define MB_CUBE 7 + +/* ml->flag */ +#define MB_NEGATIVE 2 +#define MB_HIDE 8 +#define MB_SCALE_RAD 16 + +#endif diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h new file mode 100644 index 00000000000..42016ad1c16 --- /dev/null +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -0,0 +1,366 @@ +/** + * $Id$ + */ + +#ifndef DNA_MODIFIER_TYPES_H +#define DNA_MODIFIER_TYPES_H + +#define MODSTACK_DEBUG 1 + +/* WARNING ALERT! TYPEDEF VALUES ARE WRITTEN IN FILES! SO DO NOT CHANGE! */ + +typedef enum ModifierType { + eModifierType_None = 0, + eModifierType_Subsurf, + eModifierType_Lattice, + eModifierType_Curve, + eModifierType_Build, + eModifierType_Mirror, + eModifierType_Decimate, + eModifierType_Wave, + eModifierType_Armature, + eModifierType_Hook, + eModifierType_Softbody, + eModifierType_Boolean, + eModifierType_Array, + eModifierType_EdgeSplit, + eModifierType_Displace, + eModifierType_UVProject, + eModifierType_Smooth, + eModifierType_Cast, + eModifierType_MeshDeform, + NUM_MODIFIER_TYPES +} ModifierType; + +typedef enum ModifierMode { + eModifierMode_Realtime = (1<<0), + eModifierMode_Render = (1<<1), + eModifierMode_Editmode = (1<<2), + eModifierMode_OnCage = (1<<3), + eModifierMode_Expanded = (1<<4), + eModifierMode_Virtual = (1<<5), + eModifierMode_DisableTemporary = (1 << 31) +} ModifierMode; + +typedef struct ModifierData { + struct ModifierData *next, *prev; + + int type, mode; + char name[32]; + + char *error; +} ModifierData; + +typedef enum { + eSubsurfModifierFlag_Incremental = (1<<0), + eSubsurfModifierFlag_DebugIncr = (1<<1), + eSubsurfModifierFlag_ControlEdges = (1<<2), + eSubsurfModifierFlag_SubsurfUv = (1<<3) +} SubsurfModifierFlag; + +typedef struct SubsurfModifierData { + ModifierData modifier; + + short subdivType, levels, renderLevels, flags; + + void *emCache, *mCache; +} SubsurfModifierData; + +typedef struct LatticeModifierData { + ModifierData modifier; + + struct Object *object; + char name[32]; /* optional vertexgroup name */ +} LatticeModifierData; + +typedef struct CurveModifierData { + ModifierData modifier; + + struct Object *object; + char name[32]; /* optional vertexgroup name */ + short defaxis; /* axis along which curve deforms */ + char pad[6]; +} CurveModifierData; + +/* CurveModifierData->defaxis */ +#define MOD_CURVE_POSX 1 +#define MOD_CURVE_POSY 2 +#define MOD_CURVE_POSZ 3 +#define MOD_CURVE_NEGX 4 +#define MOD_CURVE_NEGY 5 +#define MOD_CURVE_NEGZ 6 + +typedef struct BuildModifierData { + ModifierData modifier; + + float start, length; + int randomize, seed; +} BuildModifierData; + +typedef struct ArrayModifierData { + ModifierData modifier; + + /* the object with which to cap the start of the array */ + struct Object *start_cap; + /* the object with which to cap the end of the array */ + struct Object *end_cap; + /* the curve object to use for MOD_ARR_FITCURVE */ + struct Object *curve_ob; + /* the object to use for object offset */ + struct Object *offset_ob; + /* a constant duplicate offset; + 1 means the duplicates are 1 unit apart + */ + float offset[3]; + /* a scaled factor for duplicate offsets; + 1 means the duplicates are 1 object-width apart + */ + float scale[3]; + /* the length over which to distribute the duplicates */ + float length; + /* the limit below which to merge vertices in adjacent duplicates */ + float merge_dist; + /* determines how duplicate count is calculated; one of: + MOD_ARR_FIXEDCOUNT -> fixed + MOD_ARR_FITLENGTH -> calculated to fit a set length + MOD_ARR_FITCURVE -> calculated to fit the length of a Curve object + */ + int fit_type; + /* flags specifying how total offset is calculated; binary OR of: + MOD_ARR_OFF_CONST -> total offset += offset + MOD_ARR_OFF_RELATIVE -> total offset += relative * object width + MOD_ARR_OFF_OBJ -> total offset += offset_ob's matrix + total offset is the sum of the individual enabled offsets + */ + int offset_type; + /* general flags: + MOD_ARR_MERGE -> merge vertices in adjacent duplicates + */ + int flags; + /* the number of duplicates to generate for MOD_ARR_FIXEDCOUNT */ + int count; +} ArrayModifierData; + +/* ArrayModifierData->fit_type */ +#define MOD_ARR_FIXEDCOUNT 0 +#define MOD_ARR_FITLENGTH 1 +#define MOD_ARR_FITCURVE 2 + +/* ArrayModifierData->offset_type */ +#define MOD_ARR_OFF_CONST 1<<0 +#define MOD_ARR_OFF_RELATIVE 1<<1 +#define MOD_ARR_OFF_OBJ 1<<2 + +/* ArrayModifierData->flags */ +#define MOD_ARR_MERGE 1<<0 +#define MOD_ARR_MERGEFINAL 1<<1 + +typedef struct MirrorModifierData { + ModifierData modifier; + + short axis, flag; + float tolerance; +} MirrorModifierData; + +/* MirrorModifierData->flag */ +#define MOD_MIR_CLIPPING 1<<0 +#define MOD_MIR_MIRROR_U 1<<1 +#define MOD_MIR_MIRROR_V 1<<2 +#define MOD_MIR_AXIS_X 1<<3 +#define MOD_MIR_AXIS_Y 1<<4 +#define MOD_MIR_AXIS_Z 1<<5 + +typedef struct EdgeSplitModifierData { + ModifierData modifier; + + float split_angle; /* angle above which edges should be split */ + int flags; +} EdgeSplitModifierData; + +/* EdgeSplitModifierData->flags */ +#define MOD_EDGESPLIT_FROMANGLE 1<<1 +#define MOD_EDGESPLIT_FROMFLAG 1<<2 + +typedef struct DisplaceModifierData { + ModifierData modifier; + + struct Tex *texture; + float strength; + int direction; + char defgrp_name[32]; + float midlevel; + int texmapping; + struct Object *map_object; + char uvlayer_name[32]; + int uvlayer_tmp, pad; +} DisplaceModifierData; + +/* DisplaceModifierData->direction */ +enum { + MOD_DISP_DIR_X, + MOD_DISP_DIR_Y, + MOD_DISP_DIR_Z, + MOD_DISP_DIR_NOR, + MOD_DISP_DIR_RGB_XYZ, +}; + +/* DisplaceModifierData->texmapping */ +enum { + MOD_DISP_MAP_LOCAL, + MOD_DISP_MAP_GLOBAL, + MOD_DISP_MAP_OBJECT, + MOD_DISP_MAP_UV, +}; + +typedef struct UVProjectModifierData { + ModifierData modifier; + + /* the objects which do the projecting */ + struct Object *projectors[10]; + struct Image *image; /* the image to project */ + int flags; + int num_projectors; + float aspectx, aspecty; + char uvlayer_name[32]; + int uvlayer_tmp, pad; +} UVProjectModifierData; + +#define MOD_UVPROJECT_MAXPROJECTORS 10 + +/* UVProjectModifierData->flags */ +#define MOD_UVPROJECT_OVERRIDEIMAGE 1<<0 + +typedef struct DecimateModifierData { + ModifierData modifier; + + float percent; + int faceCount; +} DecimateModifierData; + +/* Smooth modifier flags */ +#define MOD_SMOOTH_X (1<<1) +#define MOD_SMOOTH_Y (1<<2) +#define MOD_SMOOTH_Z (1<<3) + +typedef struct SmoothModifierData { + ModifierData modifier; + float fac; + char defgrp_name[32]; + short flag, repeat; + +} SmoothModifierData; + +/* Cast modifier flags */ +#define MOD_CAST_X (1<<1) +#define MOD_CAST_Y (1<<2) +#define MOD_CAST_Z (1<<3) +#define MOD_CAST_USE_OB_TRANSFORM (1<<4) +#define MOD_CAST_SIZE_FROM_RADIUS (1<<5) + +/* Cast modifier projection types */ +#define MOD_CAST_TYPE_SPHERE 0 +#define MOD_CAST_TYPE_CYLINDER 1 +#define MOD_CAST_TYPE_CUBOID 2 + +typedef struct CastModifierData { + ModifierData modifier; + + struct Object *object; + float fac; + float radius; + float size; + char defgrp_name[32]; + short flag, type; +} CastModifierData; + +enum { + MOD_WAV_MAP_LOCAL, + MOD_WAV_MAP_GLOBAL, + MOD_WAV_MAP_OBJECT, + MOD_WAV_MAP_UV, +}; + +/* WaveModifierData.flag */ +#define MOD_WAVE_X 1<<1 +#define MOD_WAVE_Y 1<<2 +#define MOD_WAVE_CYCL 1<<3 +#define MOD_WAVE_NORM 1<<4 +#define MOD_WAVE_NORM_X 1<<5 +#define MOD_WAVE_NORM_Y 1<<6 +#define MOD_WAVE_NORM_Z 1<<7 + +typedef struct WaveModifierData { + ModifierData modifier; + + struct Object *objectcenter; + char defgrp_name[32]; + struct Tex *texture; + struct Object *map_object; + + short flag, pad; + + float startx, starty, height, width; + float narrow, speed, damp; + + int texmapping, uvlayer_tmp; + + char uvlayer_name[32]; + + float timeoffs, lifetime; +} WaveModifierData; + +typedef struct ArmatureModifierData { + ModifierData modifier; + + short deformflag, pad1; /* deformflag replaces armature->deformflag */ + int pad2; + struct Object *object; + char defgrp_name[32]; +} ArmatureModifierData; + +typedef struct HookModifierData { + ModifierData modifier; + + struct Object *object; + float parentinv[4][4]; /* matrix making current transform unmodified */ + float cent[3]; /* visualization of hook */ + float falloff; /* if not zero, falloff is distance where influence zero */ + + int *indexar; /* if NULL, it's using vertexgroup */ + int totindex; + float force; + char name[32]; /* optional vertexgroup name */ +} HookModifierData; + +typedef struct SoftbodyModifierData { + ModifierData modifier; +} SoftbodyModifierData; + +typedef enum { + eBooleanModifierOp_Intersect, + eBooleanModifierOp_Union, + eBooleanModifierOp_Difference, +} BooleanModifierOp; +typedef struct BooleanModifierData { + ModifierData modifier; + + struct Object *object; + int operation, pad; +} BooleanModifierData; + +#define MOD_MDEF_INVERT_VGROUP (1<<0) + +typedef struct MeshDeformModifierData { + ModifierData modifier; + + struct Object *object; /* mesh object */ + char defgrp_name[32]; /* optional vertexgroup name */ + + float *bindweights, *bindcos; /* computed binding weights */ + short gridsize, needbind; + short flag, pad; + + int totvert, totcagevert; +} MeshDeformModifierData; + +#endif diff --git a/source/blender/makesdna/DNA_nla_types.h b/source/blender/makesdna/DNA_nla_types.h new file mode 100644 index 00000000000..d7ccfe01085 --- /dev/null +++ b/source/blender/makesdna/DNA_nla_types.h @@ -0,0 +1,105 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef DNA_NLA_TYPES_H +#define DNA_NLA_TYPES_H + +#include "DNA_listBase.h" + +struct bAction; +struct Ipo; +struct Object; + +/* simple uniform modifier structure, assumed it can hold all type info */ +typedef struct bActionModifier { + struct bActionModifier *next, *prev; + short type, flag; + char channel[32]; + + /* noise modifier */ + float noisesize, turbul; + short channels; + + /* path deform modifier */ + short no_rot_axis; + struct Object *ob; +} bActionModifier; + +/* NLA-Modifier Types */ +#define ACTSTRIP_MOD_DEFORM 0 +#define ACTSTRIP_MOD_NOISE 1 +#define ACTSTRIP_MOD_OOMPH 2 + +typedef struct bActionStrip { + struct bActionStrip *next, *prev; + short flag, mode; + short stride_axis; /* axis 0=x, 1=y, 2=z */ + short curmod; /* current modifier for buttons */ + + struct Ipo *ipo; /* Blending ipo - was used for some old NAN era experiments. Non-functional currently. */ + struct bAction *act; /* The action referenced by this strip */ + struct Object *object; /* For groups, the actual object being nla'ed */ + float start, end; /* The range of frames covered by this strip */ + float actstart, actend; /* The range of frames taken from the action */ + float actoffs, padf; /* Offset within action, for cycles and striding */ + float stridelen; /* The stridelength (considered when flag & ACT_USESTRIDE) */ + float repeat; /* The number of times to repeat the action range */ + + float blendin, blendout; /* The number of frames on either end of the strip's length to fade in/out */ + + char stridechannel[32]; /* Instead of stridelen, it uses an action channel */ + char offs_bone[32]; /* if repeat, use this bone/channel for defining offset */ + + struct ListBase modifiers; /* modifier stack */ + +} bActionStrip; + +/* strip->mode (these defines aren't really used, but are here for reference) */ +#define ACTSTRIPMODE_BLEND 0 +#define ACTSTRIPMODE_ADD 1 + +/* strip->flag */ +#define ACTSTRIP_SELECT 0x01 +#define ACTSTRIP_USESTRIDE 0x02 +#define ACTSTRIP_BLENDTONEXT 0x04 /* Not implemented. Is not used anywhere */ +#define ACTSTRIP_HOLDLASTFRAME 0x08 +#define ACTSTRIP_ACTIVE 0x10 +#define ACTSTRIP_LOCK_ACTION 0x20 +#define ACTSTRIP_MUTE 0x40 +#define ACTSTRIP_REVERSE 0x80 /* This has yet to be implemented. To indicate that a strip should be played backwards */ +#define ACTSTRIP_CYCLIC_USEX 0x100 +#define ACTSTRIP_CYCLIC_USEY 0x200 +#define ACTSTRIP_CYCLIC_USEZ 0x400 +#define ACTSTRIP_AUTO_BLENDS 0x800 + +#endif + diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h new file mode 100644 index 00000000000..5f20939fc23 --- /dev/null +++ b/source/blender/makesdna/DNA_node_types.h @@ -0,0 +1,257 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef DNA_NODE_TYPES_H +#define DNA_NODE_TYPES_H + +#include "DNA_ID.h" +#include "DNA_vec_types.h" +#include "DNA_listBase.h" + +struct ListBase; +struct SpaceNode; +struct bNodeLink; +struct bNodeType; +struct bNodeGroup; + +#define NODE_MAXSTR 32 + + +typedef struct bNodeStack { + float vec[4]; + float min, max; /* min/max for values (UI writes it, execute might use it) */ + void *data; + short hasinput; /* when input has link, tagged before executing */ + short hasoutput; /* when output is linked, tagged before executing */ + short datatype; /* type of data pointer */ + short sockettype; /* type of socket stack comes from, to remap linking different sockets */ +} bNodeStack; + +/* ns->datatype, shadetree only */ +#define NS_OSA_VECTORS 1 +#define NS_OSA_VALUES 2 + +typedef struct bNodeSocket { + struct bNodeSocket *next, *prev; + + char name[32]; + bNodeStack ns; /* custom data for inputs, only UI writes in this */ + + short type, flag; /* type is copy from socket type struct */ + short limit, stack_index; /* limit for dependency sort, stack_index for exec */ + short intern; /* intern = tag for group nodes */ + short stack_index_ext; /* for groups, to find the caller stack index */ + int pad1; + + float locx, locy; + + /* internal data to retrieve relations and groups */ + + int own_index, to_index; /* group socket identifiers, to find matching pairs after reading files */ + + struct bNodeSocket *tosock; /* group-node sockets point to the internal group counterpart sockets, set after read file */ + struct bNodeLink *link; /* a link pointer, set in nodeSolveOrder() */ + +} bNodeSocket; + +/* sock->type */ +#define SOCK_VALUE 0 +#define SOCK_VECTOR 1 +#define SOCK_RGBA 2 + +/* sock->flag, first bit is select */ + /* hidden is user defined, to hide unused */ +#define SOCK_HIDDEN 2 + /* only used now for groups... */ +#define SOCK_IN_USE 4 + /* unavailable is for dynamic sockets */ +#define SOCK_UNAVAIL 8 + +# +# +typedef struct bNodePreview { + float *rect; + short xsize, ysize; +} bNodePreview; + + +/* limit data in bNode to what we want to see saved? */ +typedef struct bNode { + struct bNode *next, *prev, *new_node; + + char name[32]; + short type, flag; + short done, level; /* both for dependency and sorting */ + short lasty, menunr; /* lasty: check preview render status, menunr: browse ID blocks */ + short stack_index; /* for groupnode, offset in global caller stack */ + short nr; /* number of this node in list, used for UI exec events */ + + ListBase inputs, outputs; + struct ID *id; /* optional link to libdata */ + void *storage; /* custom data, must be struct, for storage in file */ + + float locx, locy; /* root offset for drawing */ + float width, miniwidth; + short custom1, custom2; /* to be abused for buttons */ + + short need_exec, exec; /* need_exec is set as UI execution event, exec is flag during exec */ + + rctf totr; /* entire boundbox */ + rctf butr; /* optional buttons area */ + rctf prvr; /* optional preview area */ + bNodePreview *preview; /* optional preview image */ + + struct bNodeType *typeinfo; /* lookup of callbacks and defaults */ + +} bNode; + +/* node->flag */ +#define NODE_SELECT 1 +#define NODE_OPTIONS 2 +#define NODE_PREVIEW 4 +#define NODE_HIDDEN 8 +#define NODE_ACTIVE 16 +#define NODE_ACTIVE_ID 32 +#define NODE_DO_OUTPUT 64 +#define NODE_GROUP_EDIT 128 + /* free test flag, undefined */ +#define NODE_TEST 256 + +typedef struct bNodeLink { + struct bNodeLink *next, *prev; + + bNode *fromnode, *tonode; + bNodeSocket *fromsock, *tosock; + +} bNodeLink; + +/* the basis for a Node tree, all links and nodes reside internal here */ +/* only re-usable node trees are in the library though, materials allocate own tree struct */ +typedef struct bNodeTree { + ID id; + + ListBase nodes, links; + + bNodeStack **stack; /* stack is only while executing, no read/write in file */ + + int type, init; /* set init on fileread */ + int stacksize; /* amount of elements in stack */ + int cur_index; /* sockets in groups have unique identifiers, adding new sockets always + will increase this counter */ + ListBase alltypes; /* type definitions */ + struct bNodeType *owntype; /* for groups or dynamic trees, no read/write */ + + /* callbacks */ + void (*timecursor)(int nr); + void (*stats_draw)(char *str); + int (*test_break)(void); +} bNodeTree; + +/* ntree->type, index */ +#define NTREE_SHADER 0 +#define NTREE_COMPOSIT 1 + +/* ntree->init, flag */ +#define NTREE_TYPE_INIT 1 +#define NTREE_EXEC_INIT 2 + +/* data structs, for node->storage */ + +/* this one has been replaced with ImageUser, keep it for do_versions() */ +typedef struct NodeImageAnim { + int frames, sfra, nr; + char cyclic, movie; + short pad; +} NodeImageAnim; + +typedef struct NodeBlurData { + short sizex, sizey, samples, maxspeed, minspeed, pad1; + float fac; + short filtertype; + char bokeh, gamma; + int pad2; +} NodeBlurData; + +typedef struct NodeHueSat { + float hue, sat, val; +} NodeHueSat; + +typedef struct NodeImageFile { + char name[256]; + short imtype, subimtype, quality, codec; + int sfra, efra; +} NodeImageFile; + +typedef struct NodeChroma { + float t1,t2,t3; + float fsize,fstrength,falpha; + float key[4]; +} NodeChroma; + +typedef struct NodeTwoXYs { + short x1, x2, y1, y2; +} NodeTwoXYs; + +typedef struct NodeGeometry { + char uvname[32]; + char colname[32]; +} NodeGeometry; + +typedef struct NodeVertexCol { + char name[32]; +} NodeVertexCol; + +/* qdn: Defocus blur node */ +typedef struct NodeDefocus { + char bktype, rotation, preview, gamco; + short samples, no_zbuf; + float fstop, maxblur, bthresh, scale; +} NodeDefocus; + + +/* qdn: glare node */ +typedef struct NodeGlare { + char quality, type, iter; + char angle, angle_ofs, size, pad[2]; + float colmod, mix, threshold, fade; +} NodeGlare; + +/* qdn: tonemap node */ +typedef struct NodeTonemap { + float key, offset, gamma; + float f, m, a, c; + int type; +} NodeTonemap; + +/* qdn: lens distortion node */ +typedef struct NodeLensDist { + short jit, proj, fit, pad; +} NodeLensDist; + +#endif diff --git a/source/blender/makesdna/DNA_object_fluidsim.h b/source/blender/makesdna/DNA_object_fluidsim.h new file mode 100644 index 00000000000..91c25d2ec1d --- /dev/null +++ b/source/blender/makesdna/DNA_object_fluidsim.h @@ -0,0 +1,157 @@ +/** + * + * $Id: + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2004-2005 by Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_OBJECT_FLUIDSIM_H +#define DNA_OBJECT_FLUIDSIM_H + +#include "DNA_ID.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct Mesh; +struct Ipo; +struct MVert; + +typedef struct FluidsimSettings { + /* domain,fluid or obstacle */ + short type; + /* display advanced options in fluid sim tab (on=1,off=0)*/ + short show_advancedoptions; + + /* domain object settings */ + /* resolutions */ + short resolutionxyz; + short previewresxyz; + /* size of the domain in real units (meters along largest resolution x,y,z extent) */ + float realsize; + /* show original meshes, preview or final sim */ + short guiDisplayMode; + short renderDisplayMode; + + /* fluid properties */ + float viscosityValue; + short viscosityMode; + short viscosityExponent; + /* gravity strength */ + float gravx,gravy,gravz; + /* anim start end time */ + float animStart, animEnd; + /* g star param (LBM compressibility) */ + float gstar; + /* activate refinement? */ + int maxRefine; + + /* fluid object type settings */ + /* gravity strength */ + float iniVelx,iniVely,iniVelz; + + /* store pointer to original mesh (for replacing the current one) */ + struct Mesh *orgMesh; + /* pointer to the currently loaded fluidsim mesh */ + struct Mesh *meshSurface; + /* a mesh to display the bounding box used for simulation */ + struct Mesh *meshBB; + + /* store output path, and file prefix for baked fluid surface */ + /* strlens; 80= FILE_MAXFILE, 160= FILE_MAXDIR */ + char surfdataPath[240]; + + /* store start coords of axis aligned bounding box together with size */ + /* values are inited during derived mesh display */ + float bbStart[3], bbSize[3]; + + /* animated params */ + struct Ipo *ipo; + + /* additional flags depending on the type, lower short contains flags + * to check validity, higher short additional flags */ + short typeFlags; + /* switch off velocity genration, volume init type for fluid/obstacles (volume=1,shell=2,both=3) */ + char domainNovecgen,volumeInitType; + + /* boundary "stickiness" for part slip values */ + float partSlipValue; + + /* number of tracers to generate */ + int generateTracers; + /* particle generation - on if >0, then determines amount (experimental...) */ + float generateParticles; + /* smooth fluid surface? */ + float surfaceSmoothing; + /* number of surface subdivisions*/ + int surfaceSubdivs; + int unusedDNADummy; + + /* particle display - size scaling, and alpha influence */ + float particleInfSize, particleInfAlpha; + /* testing vars */ + float farFieldSize; + + /* save fluidsurface normals in mvert.no, and surface vertex velocities (if available) in mvert.co */ + struct MVert *meshSurfNormals; + +} FluidsimSettings; + +/* ob->fluidsimSettings defines */ +#define OB_FLUIDSIM_ENABLE 1 +#define OB_FLUIDSIM_DOMAIN 2 +#define OB_FLUIDSIM_FLUID 4 +#define OB_FLUIDSIM_OBSTACLE 8 +#define OB_FLUIDSIM_INFLOW 16 +#define OB_FLUIDSIM_OUTFLOW 32 +#define OB_FLUIDSIM_PARTICLE 64 + +#define OB_TYPEFLAG_START 0 +#define OB_FSGEO_THIN (1<<(OB_TYPEFLAG_START+1)) +#define OB_FSBND_NOSLIP (1<<(OB_TYPEFLAG_START+2)) +#define OB_FSBND_PARTSLIP (1<<(OB_TYPEFLAG_START+3)) +#define OB_FSBND_FREESLIP (1<<(OB_TYPEFLAG_START+4)) +#define OB_FSINFLOW_LOCALCOORD (1<<(OB_TYPEFLAG_START+5)) + +// guiDisplayMode particle flags +#define OB_FSDOM_GEOM 1 +#define OB_FSDOM_PREVIEW 2 +#define OB_FSDOM_FINAL 3 +#define OB_FSPART_BUBBLE (1<<1) +#define OB_FSPART_DROP (1<<2) +#define OB_FSPART_NEWPART (1<<3) +#define OB_FSPART_FLOAT (1<<4) + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/source/blender/makesdna/DNA_object_force.h b/source/blender/makesdna/DNA_object_force.h new file mode 100644 index 00000000000..a821e209ef0 --- /dev/null +++ b/source/blender/makesdna/DNA_object_force.h @@ -0,0 +1,154 @@ +/** + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2004-2005 by Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_OBJECT_FORCE_H +#define DNA_OBJECT_FORCE_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct PartDeflect { + short deflect; /* Deflection flag - does mesh deflect particles*/ + short forcefield; /* Force field type, do the vertices attract / repel particles ? */ + short flag; /* general settings flag */ + short pad; + + float pdef_damp; /* Damping factor for particle deflection */ + float pdef_rdamp; /* Random element of damping for deflection */ + float pdef_perm; /* Chance of particle passing through mesh */ + + float f_strength; /* The strength of the force (+ or - ) */ + float f_power; /* The power law - real gravitation is 2 (square) */ + float maxdist; /* if indicated, use this maximum */ + + float pdef_sbdamp; /* Damping factor for softbody deflection */ + float pdef_sbift; /* inner face thickness for softbody deflection */ + float pdef_sboft; /* outer face thickness for softbody deflection */ +} PartDeflect; + + +typedef struct SBVertex { + float vec[4]; +} SBVertex; + +typedef struct SoftBody { + /* dynamic data */ + int totpoint, totspring; + struct BodyPoint *bpoint; /* not saved in file */ + struct BodySpring *bspring; /* not saved in file */ + float ctime; /* last time calculated */ + + /* part of UI: */ + + /* general options */ + float nodemass; /* softbody mass of *vertex* */ + float grav; /* softbody amount of gravitaion to apply */ + float mediafrict; /* friction to env */ + float rklimit; /* error limit for ODE solver */ + float physics_speed;/* user control over simulation speed */ + + /* goal */ + float goalspring; /* softbody goal springs */ + float goalfrict; /* softbody goal springs friction */ + float mingoal; /* quick limits for goal */ + float maxgoal; + float defgoal; /* default goal for vertices without vgroup */ + short vertgroup; /* index starting at 1 */ + + short fuzzyness; /* */ + + /* springs */ + float inspring; /* softbody inner springs */ + float infrict; /* softbody inner springs friction */ + + /* baking */ + int sfra, efra; + int interval; + short local, solverflags; /* local==1: use local coords for baking */ + + SBVertex **keys; /* array of size totpointkey */ + int totpointkey, totkey; /* if totpointkey != totpoint or totkey!- (efra-sfra)/interval -> free keys */ + float secondspring; + + /* self collision*/ + float colball; /* fixed collision ball size if > 0 */ + float balldamp; /* cooling down collision response */ + float ballstiff; /* pressure the ball is loaded with */ + short sbc_mode; + short aeroedge, + minloops, + maxloops, + choke, + pad3,pad4,pad5 + ; + + struct SBScratch *scratch; /* scratch pad/cache on live time not saved in file */ + +} SoftBody; + +/* pd->forcefield: Effector Fields types */ +#define PFIELD_FORCE 1 +#define PFIELD_VORTEX 2 +#define PFIELD_MAGNET 3 +#define PFIELD_WIND 4 +#define PFIELD_GUIDE 5 + +/* pd->flag: various settings */ +#define PFIELD_USEMAX 1 +#define PDEFLE_DEFORM 2 +#define PFIELD_GUIDE_PATH_ADD 4 + +/* ob->softflag */ +#define OB_SB_ENABLE 1 +#define OB_SB_GOAL 2 +#define OB_SB_EDGES 4 +#define OB_SB_QUADS 8 +#define OB_SB_POSTDEF 16 +#define OB_SB_REDO 32 +#define OB_SB_BAKESET 64 +#define OB_SB_BAKEDO 128 +#define OB_SB_RESET 256 +#define OB_SB_SELF 512 +#define OB_SB_FACECOLL 1024 +#define OB_SB_EDGECOLL 2048 +#define OB_SB_COLLFINAL 4096 + +#define SBSO_MONITOR 1 +#define SBSO_OLDERR 2 + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h new file mode 100644 index 00000000000..cb4aa42a847 --- /dev/null +++ b/source/blender/makesdna/DNA_object_types.h @@ -0,0 +1,442 @@ +/** + * blenlib/DNA_object_types.h (mar-2001 nzc) + * + * Object is a sort of wrapper for general info. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_OBJECT_TYPES_H +#define DNA_OBJECT_TYPES_H + +#include "DNA_listBase.h" +#include "DNA_ID.h" +#include "DNA_scriptlink_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct bPose; +struct Object; +struct Ipo; +struct BoundBox; +struct Path; +struct Material; +struct bConstraintChannel; +struct PartDeflect; +struct SoftBody; +struct FluidsimSettings; +struct DerivedMesh; + +typedef struct bDeformGroup { + struct bDeformGroup *next, *prev; + char name[32]; +} bDeformGroup; + +typedef struct BoundBox { + float vec[8][3]; + int flag, pad; +} BoundBox; + +/* boundbox flag */ +#define OB_BB_DISABLED 1 + +typedef struct Object { + ID id; + + short type, partype; + int par1, par2, par3; /* can be vertexnrs */ + char parsubstr[32]; /* String describing subobject info */ + struct Object *parent, *track; + /* if ob->proxy (or proxy_group), this object is proxy for object ob->proxy */ + /* proxy_from is set in target back to the proxy. */ + struct Object *proxy, *proxy_group, *proxy_from; + struct Ipo *ipo; + struct Path *path; + struct BoundBox *bb; + struct bAction *action; + struct bPose *pose; + void *data; + + ListBase constraintChannels; + ListBase effect; + ListBase disp; + ListBase defbase; + ListBase modifiers; /* list of ModifierData structures */ + + struct Material **mat; + + /* rot en drot have to be together! (transform('r' en 's')) */ + float loc[3], dloc[3], orig[3]; + float size[3], dsize[3]; + float rot[3], drot[3]; + float quat[4], dquat[4]; + float obmat[4][4]; + float parentinv[4][4]; /* inverse result of parent, so that object doesn't 'stick' to parent */ + float constinv[4][4]; /* inverse result of constraints. doesn't include effect of parent or object local transform */ + float imat[4][4]; /* for during render, old game engine, temporally: ipokeys of transform */ + + unsigned int lay; /* copy of Base */ + + short flag; /* copy of Base */ + short colbits; /* when zero, from obdata */ + + short transflag, ipoflag; /* transformation and ipo settings */ + short trackflag, upflag; + short nlaflag, protectflag; /* nlaflag defines NLA override, protectflag is bits to lock transform */ + short ipowin, scaflag; /* ipowin: blocktype last ipowindow */ + short scavisflag, boundtype; + + int dupon, dupoff, dupsta, dupend; + + float sf, ctime; + + /* during realtime */ + + /* note that inertia is only called inertia for historical reasons + * and is not changed to avoid DNA surgery. It actually reflects the + * Size value in the GameButtons (= radius) */ + + float mass, damping, inertia; + /* The form factor k is introduced to give the user more control + * and to fix incompatibility problems. + * For rotational symmetric objects, the inertia value can be + * expressed as: Theta = k * m * r^2 + * where m = Mass, r = Radius + * For a Sphere, the form factor is by default = 0.4 + */ + + float formfactor; + float rdamping, sizefac; + + char dt, dtx; + char totcol; /* copy of mesh or curve or meta */ + char actcol; /* currently selected material in the user interface */ + char empty_drawtype, pad1[7]; + float empty_drawsize; + + ScriptLink scriptlink; + ListBase prop; + ListBase sensors; + ListBase controllers; + ListBase actuators; + + /* now used to store cache particles, + * should be renamed see effect.c (Campbell) */ + void *sumohandle; + + float bbsize[3]; + short index; /* custom index, for renderpasses */ + unsigned short actdef; /* current deformation group */ + float col[4]; /* object color, adjusted via IPO's only */ + /** + * Settings for game objects + * bit 0: Object has dynamic behaviour + * bit 2: Object is evaluated by the gameengine + * bit 6: Use Fh settings in Materials + * bit 7: Use face normal to rotate Object + * bit 8: Friction is anisotropic + * bit 9: Object is a ghost + * bit 10: Do rigid body dynamics. + * bit 11: Use bounding object for physics + */ + int gameflag; + /** + * More settings + * bit 15: Always ignore activity culling + */ + int gameflag2; + short softflag; /* softboday settings */ + short recalc; /* dependency flag */ + float anisotropicFriction[3]; + + ListBase constraints; + ListBase nlastrips; + ListBase hooks; + + struct PartDeflect *pd; /* particle deflector/attractor/collision data */ + struct SoftBody *soft; /* if exists, saved in file */ + struct Group *dup_group; /* object duplicator for group */ + + short fluidsimFlag; /* NT toggle fluidsim participation on/off */ + + short restrictflag; /* for restricting view, select, render etc. accessible in outliner */ + + short shapenr, shapeflag; /* current shape key for menu or pinned, flag for pinning */ + float smoothresh; /* smoothresh is phong interpolation ray_shadow correction in render */ + short recalco, pad4; /* recalco for temp storage of ob->recalc, bad design warning */ + + struct FluidsimSettings *fluidsimSettings; /* if fluidsim enabled, store additional settings */ + + struct DerivedMesh *derivedDeform, *derivedFinal; + int lastDataMask; /* the custom data layer mask that was last used to calculate derivedDeform and derivedFinal */ + int pad; + +/*#ifdef WITH_VERSE*/ + void *vnode; /* pointer at object VerseNode */ +/*#endif*/ +} Object; + +/* Warning, this is not used anymore because hooks are now modifiers */ +typedef struct ObHook { + struct ObHook *next, *prev; + + struct Object *parent; + float parentinv[4][4]; /* matrix making current transform unmodified */ + float mat[4][4]; /* temp matrix while hooking */ + float cent[3]; /* visualization of hook */ + float falloff; /* if not zero, falloff is distance where influence zero */ + + char name[32]; + + int *indexar; + int totindex, curindex; /* curindex is cache for fast lookup */ + short type, active; /* active is only first hook, for button menu */ + float force; +} ObHook; + + +/* this work object is defined in object.c */ +extern Object workob; + + +/* **************** OBJECT ********************* */ + +/* used many places... should be specialized */ +#define SELECT 1 + +/* type */ +#define OB_EMPTY 0 +#define OB_MESH 1 +#define OB_CURVE 2 +#define OB_SURF 3 +#define OB_FONT 4 +#define OB_MBALL 5 + +#define OB_LAMP 10 +#define OB_CAMERA 11 + +#define OB_WAVE 21 +#define OB_LATTICE 22 + +/* 23 and 24 are for life and sector (old file compat.) */ +#define OB_ARMATURE 25 + +/* partype: first 4 bits: type */ +#define PARTYPE 15 +#define PAROBJECT 0 +#define PARCURVE 1 +#define PARKEY 2 + +#define PARSKEL 4 +#define PARVERT1 5 +#define PARVERT3 6 +#define PARBONE 7 +#define PARSLOW 16 + +/* (short) transflag */ +#define OB_OFFS_LOCAL 1 +#define OB_QUAT 2 +#define OB_NEG_SCALE 4 +#define OB_DUPLI (8+16+256+512) +#define OB_DUPLIFRAMES 8 +#define OB_DUPLIVERTS 16 +#define OB_DUPLIROT 32 +#define OB_DUPLINOSPEED 64 +#define OB_POWERTRACK 128 +#define OB_DUPLIGROUP 256 +#define OB_DUPLIFACES 512 +#define OB_DUPLIFACES_SCALE 1024 + +/* (short) ipoflag */ +#define OB_DRAWKEY 1 +#define OB_DRAWKEYSEL 2 +#define OB_OFFS_OB 4 +#define OB_OFFS_MAT 8 +#define OB_OFFS_VKEY 16 +#define OB_OFFS_PATH 32 +#define OB_OFFS_PARENT 64 +#define OB_OFFS_PARTICLE 128 + /* get ipo from from action or not? */ +#define OB_ACTION_OB 256 +#define OB_ACTION_KEY 512 + /* for stride edit */ +#define OB_DISABLE_PATH 1024 + +/* (short) trackflag / upflag */ +#define OB_POSX 0 +#define OB_POSY 1 +#define OB_POSZ 2 +#define OB_NEGX 3 +#define OB_NEGY 4 +#define OB_NEGZ 5 + +/* gameflag in game.h */ + +/* dt: no flags */ +#define OB_BOUNDBOX 1 +#define OB_WIRE 2 +#define OB_SOLID 3 +#define OB_SHADED 4 +#define OB_TEXTURE 5 + +/* this condition has been made more complex since editmode can draw textures */ +#define CHECK_OB_DRAWTEXTURE(vd, dt) ((vd->drawtype==OB_TEXTURE && dt>OB_SOLID) || (vd->drawtype==OB_SOLID && vd->flag2 & V3D_SOLID_TEX)) + +/* dtx: flags, char! */ +#define OB_AXIS 2 +#define OB_TEXSPACE 4 +#define OB_DRAWNAME 8 +#define OB_DRAWIMAGE 16 + /* for solid+wire display */ +#define OB_DRAWWIRE 32 + /* for overdraw */ +#define OB_DRAWXRAY 64 + /* enable transparent draw */ +#define OB_DRAWTRANSP 128 + +/* empty_drawtype: no flags */ +#define OB_ARROWS 1 +#define OB_PLAINAXES 2 +#define OB_CIRCLE 3 +#define OB_SINGLE_ARROW 4 +#define OB_CUBE 5 + +/* boundtype */ +#define OB_BOUND_BOX 0 +#define OB_BOUND_SPHERE 1 +#define OB_BOUND_CYLINDER 2 +#define OB_BOUND_CONE 3 +#define OB_BOUND_POLYH 4 +#define OB_BOUND_POLYT 5 +#define OB_BOUND_DYN_MESH 6 + + +/* **************** BASE ********************* */ + +/* also needed for base!!!!! or rather, thy interfere....*/ +/* base->flag and ob->flag */ +#define BA_WAS_SEL 2 +#define BA_HAS_RECALC_OB 4 +#define BA_HAS_RECALC_DATA 8 + +#define BA_DO_IPO 32 + +#define BA_FROMSET 128 + +/* an initial attempt as making selection more specific! */ +#define BA_DESELECT 0 +#define BA_SELECT 1 + + +#define OB_FROMDUPLI 512 +#define OB_DONE 1024 +#define OB_RADIO 2048 +#define OB_FROMGROUP 4096 +#define OB_POSEMODE 8192 + +/* ob->recalc (flag bits!) */ +#define OB_RECALC_OB 1 +#define OB_RECALC_DATA 2 + /* time flag is set when time changes need recalc, so baked systems can ignore it */ +#define OB_RECALC_TIME 4 +#define OB_RECALC 7 + +/* ob->gameflag */ +#define OB_DYNAMIC 1 +#define OB_CHILD 2 +#define OB_ACTOR 4 +#define OB_INERTIA_LOCK_X 8 +#define OB_INERTIA_LOCK_Y 16 +#define OB_INERTIA_LOCK_Z 32 +#define OB_DO_FH 64 +#define OB_ROT_FH 128 +#define OB_ANISOTROPIC_FRICTION 256 +#define OB_GHOST 512 +#define OB_RIGID_BODY 1024 +#define OB_BOUNDS 2048 + +#define OB_COLLISION_RESPONSE 4096 +#define OB_SECTOR 8192 +#define OB_PROP 16384 +#define OB_MAINACTOR 32768 + +/* ob->gameflag2 */ +#define OB_NEVER_DO_ACTIVITY_CULLING 1 + +#define OB_LIFE (OB_PROP|OB_DYNAMIC|OB_ACTOR|OB_MAINACTOR|OB_CHILD) + +/* ob->scavisflag */ +#define OB_VIS_SENS 1 +#define OB_VIS_CONT 2 +#define OB_VIS_ACT 4 + +/* ob->scaflag */ +#define OB_SHOWSENS 64 +#define OB_SHOWACT 128 +#define OB_ADDSENS 256 +#define OB_ADDCONT 512 +#define OB_ADDACT 1024 +#define OB_SHOWCONT 2048 + +/* ob->restrictflag */ +#define OB_RESTRICT_VIEW 1 +#define OB_RESTRICT_SELECT 2 +#define OB_RESTRICT_RENDER 4 + +/* ob->shapeflag */ +#define OB_SHAPE_LOCK 1 +#define OB_SHAPE_TEMPLOCK 2 + +/* ob->nlaflag */ +#define OB_NLA_OVERRIDE 1 +#define OB_NLA_COLLAPSED 2 + +/* ob->protectflag */ +#define OB_LOCK_LOCX 1 +#define OB_LOCK_LOCY 2 +#define OB_LOCK_LOCZ 4 +#define OB_LOCK_LOC 7 +#define OB_LOCK_ROTX 8 +#define OB_LOCK_ROTY 16 +#define OB_LOCK_ROTZ 32 +#define OB_LOCK_SCALEX 64 +#define OB_LOCK_SCALEY 128 +#define OB_LOCK_SCALEZ 256 + +/* ob->softflag in DNA_object_force.h */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/source/blender/makesdna/DNA_oops_types.h b/source/blender/makesdna/DNA_oops_types.h new file mode 100644 index 00000000000..aaee18e3249 --- /dev/null +++ b/source/blender/makesdna/DNA_oops_types.h @@ -0,0 +1,86 @@ +/** + * blenlib/DNA_oops_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_OOPS_TYPES_H +#define DNA_OOPS_TYPES_H + +#define OOPSX 5.0 +#define OOPSY 1.8 + +#include "DNA_listBase.h" + +struct ID; + +typedef struct TreeStoreElem { + short type, nr, flag, used; + struct ID *id; +} TreeStoreElem; + +typedef struct TreeStore { + int totelem, usedelem; + TreeStoreElem *data; +} TreeStore; + +typedef struct Oops { + struct Oops *next, *prev; + short type, flag, dt, hide; + float x, y; /* left - bottom */ + float dx, dy; /* shuffle */ + struct ID *id; + ListBase link; +} Oops; + +# +# +typedef struct OopsLink { + struct OopsLink *next, *prev; + short type, flag; + struct ID **idfrom; + Oops *to, *from; /* from is for temp */ + float xof, yof; + char name[12]; +} OopsLink; + +/* oops->flag (1==SELECT) */ +#define OOPS_DOSELECT 2 +#define OOPS_REFER 4 + +/* TreeStoreElem->flag */ +#define TSE_CLOSED 1 +#define TSE_SELECTED 2 +#define TSE_TEXTBUT 4 + +/* TreeStoreElem types in BIF_outliner.h */ + +#endif + diff --git a/source/blender/makesdna/DNA_packedFile_types.h b/source/blender/makesdna/DNA_packedFile_types.h new file mode 100644 index 00000000000..a0fdd892106 --- /dev/null +++ b/source/blender/makesdna/DNA_packedFile_types.h @@ -0,0 +1,65 @@ +/* DNA_packedFile_types.h + * + * 12-oct-2000 nzc + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef DNA_PACKEDFILE_TYPES_H +#define DNA_PACKEDFILE_TYPES_H + +typedef struct PackedFile { + int size; + int seek; + int flags; + int pad; + void * data; +} PackedFile; + +enum PF_FileStatus +{ + PF_EQUAL = 0, + PF_DIFFERS, + PF_NOFILE, + + PF_WRITE_ORIGINAL, + PF_WRITE_LOCAL, + PF_USE_LOCAL, + PF_USE_ORIGINAL, + PF_KEEP, + PF_REMOVE, + PF_NOOP, + + PF_ASK +}; + +#endif /* PACKEDFILE_TYPES_H */ + diff --git a/source/blender/makesdna/DNA_property_types.h b/source/blender/makesdna/DNA_property_types.h new file mode 100644 index 00000000000..e46d557cc8b --- /dev/null +++ b/source/blender/makesdna/DNA_property_types.h @@ -0,0 +1,68 @@ +/** + * blenlib/DNA_property_types.h (mar-2001 nzc) + * + * Renderrecipe and scene decription. The fact that there is a + * hierarchy here is a bit strange, and not desirable. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_PROPERTY_TYPES_H +#define DNA_PROPERTY_TYPES_H + +/* ********************* PROPERTY ************************ */ + +typedef struct bProperty { + struct bProperty *next, *prev; + char name[32]; + short type, otype; /* otype is for buttons, when a property type changes */ + int data; /* data should be 4 bytes to store int,float stuff */ + int old; /* old is for simul */ + short flag, pad; + void *poin; + void *oldpoin; /* oldpoin is for simul */ + +} bProperty; + +/* property->type */ +#define PROP_BOOL 0 +#define PROP_INT 1 +#define PROP_FLOAT 2 +#define PROP_STRING 3 +#define PROP_VECTOR 4 +#define PROP_TIME 5 + +/* property->flag */ +#define PROP_DEBUG 1 + +#define MAX_PROPSTRING 128 + +#endif + diff --git a/source/blender/makesdna/DNA_radio_types.h b/source/blender/makesdna/DNA_radio_types.h new file mode 100644 index 00000000000..adaa4e6e159 --- /dev/null +++ b/source/blender/makesdna/DNA_radio_types.h @@ -0,0 +1,53 @@ +/** + * radio_types.h dec 2000 Nzc + * + * All type defs for the Blender core. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + */ + +#ifndef DNA_RADIO_TYPES_H +#define DNA_RADIO_TYPES_H + +typedef struct Radio { + short hemires, maxiter; + short drawtype, flag; /* bit 0 and 1: show limits */ + short subshootp, subshoote, nodelim, maxsublamp; + short pama, pami, elma, elmi; /* patch and elem limits */ + int maxnode; + float convergence; + float radfac, gamma; /* for display */ + +} Radio; + +#endif + diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h new file mode 100644 index 00000000000..031a88c517a --- /dev/null +++ b/source/blender/makesdna/DNA_scene_types.h @@ -0,0 +1,672 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_SCENE_TYPES_H +#define DNA_SCENE_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "DNA_vec_types.h" +#include "DNA_listBase.h" +#include "DNA_scriptlink_types.h" +#include "DNA_ID.h" +#include "DNA_scriptlink_types.h" + +struct Radio; +struct Object; +struct World; +struct Scene; +struct Image; +struct Group; +struct bNodeTree; + +typedef struct Base { + struct Base *next, *prev; + unsigned int lay, selcol; + int flag; + short sx, sy; + struct Object *object; +} Base; + +typedef struct AviCodecData { + void *lpFormat; /* save format */ + void *lpParms; /* compressor options */ + unsigned int cbFormat; /* size of lpFormat buffer */ + unsigned int cbParms; /* size of lpParms buffer */ + + unsigned int fccType; /* stream type, for consistency */ + unsigned int fccHandler; /* compressor */ + unsigned int dwKeyFrameEvery; /* keyframe rate */ + unsigned int dwQuality; /* compress quality 0-10,000 */ + unsigned int dwBytesPerSecond; /* bytes per second */ + unsigned int dwFlags; /* flags... see below */ + unsigned int dwInterleaveEvery; /* for non-video streams only */ + unsigned int pad; + + char avicodecname[128]; +} AviCodecData; + +typedef struct QuicktimeCodecData { + + void *cdParms; /* codec/compressor options */ + void *pad; /* padding */ + + unsigned int cdSize; /* size of cdParms buffer */ + unsigned int pad2; /* padding */ + + char qtcodecname[128]; +} QuicktimeCodecData; + +typedef struct FFMpegCodecData { + int type; + int codec; + int audio_codec; + int video_bitrate; + int audio_bitrate; + int gop_size; + int flags; + + int rc_min_rate; + int rc_max_rate; + int rc_buffer_size; + int mux_packet_size; + int mux_rate; +} FFMpegCodecData; + + +typedef struct AudioData { + int mixrate; + float main; /* Main mix in dB */ + short flag; + short pad[3]; +} AudioData; + +typedef struct SceneRenderLayer { + struct SceneRenderLayer *next, *prev; + + char name[32]; + + struct Material *mat_override; + struct Group *light_override; + + unsigned int lay; /* scene->lay itself has priority over this */ + int layflag; + int passflag; /* pass_xor has to be after passflag */ + int pass_xor; +} SceneRenderLayer; + +/* srl->layflag */ +#define SCE_LAY_SOLID 1 +#define SCE_LAY_ZTRA 2 +#define SCE_LAY_HALO 4 +#define SCE_LAY_EDGE 8 +#define SCE_LAY_SKY 16 +#define SCE_LAY_STRAND 32 + /* flags between 32 and 0x8000 are set to 1 already, for future options */ + +#define SCE_LAY_ALL_Z 0x8000 +#define SCE_LAY_XOR 0x10000 +#define SCE_LAY_DISABLE 0x20000 + +/* srl->passflag */ +#define SCE_PASS_COMBINED 1 +#define SCE_PASS_Z 2 +#define SCE_PASS_RGBA 4 +#define SCE_PASS_DIFFUSE 8 +#define SCE_PASS_SPEC 16 +#define SCE_PASS_SHADOW 32 +#define SCE_PASS_AO 64 +#define SCE_PASS_REFLECT 128 +#define SCE_PASS_NORMAL 256 +#define SCE_PASS_VECTOR 512 +#define SCE_PASS_REFRACT 1024 +#define SCE_PASS_INDEXOB 2048 +#define SCE_PASS_UV 4096 +#define SCE_PASS_RADIO 8192 +/* note, srl->passflag is treestore element 'nr' in outliner, short still... */ + + +typedef struct RenderData { + + struct AviCodecData *avicodecdata; + struct QuicktimeCodecData *qtcodecdata; + struct FFMpegCodecData ffcodecdata; + + int cfra, sfra, efra; /* frames as in 'images' */ + int psfra, pefra; /* start+end frames of preview range */ + + int images, framapto; + short flag, threads; + + float ctime; /* use for calcutions */ + float framelen, blurfac; + + /** For UR edge rendering: give the edges this color */ + float edgeR, edgeG, edgeB; + + short fullscreen, xplay, yplay, freqplay; /* standalone player */ + short depth, attrib, rt1, rt2; /* standalone player */ + + short stereomode; /* standalone player stereo settings */ + + short dimensionspreset; /* for the dimensions presets menu */ + + short filtertype; /* filter is box, tent, gauss, mitch, etc */ + + short size, maximsize; /* size in %, max in Kb */ + /* from buttons: */ + /** + * The desired number of pixels in the x direction + */ + short xsch; + /** + * The desired number of pixels in the y direction + */ + short ysch; + /** + * Adjustment factors for the aspect ratio in the x direction + */ + short xasp; + /** + * Adjustment factors for the aspect ratio in the x direction + */ + short yasp; + /** + * The number of part to use in the x direction + */ + short xparts; + /** + * The number of part to use in the y direction + */ + short yparts; + + short winpos, planes, imtype, subimtype; + + /** Mode bits: */ + /* 0: Enable backbuffering for images */ + short bufflag; + short quality; + + /** + * Flags for render settings. Use bit-masking to access the settings. + */ + short scemode; + + /** + * Flags for render settings. Use bit-masking to access the settings. + */ + int mode; + + /* render engine, octree resolution */ + short renderer, ocres, rpad[2]; + + /** + * What to do with the sky/background. Picks sky/premul/key + * blending for the background + */ + short alphamode; + + /** + * The number of samples to use per pixel. + */ + short osa; + + short frs_sec, edgeint; + + /* safety, border and display rect */ + rctf safety, border; + rcti disprect; + + /* information on different layers to be rendered */ + ListBase layers; + short actlay, pad; + + float frs_sec_base; + + /** + * Value used to define filter size for all filter options */ + float gauss; + + /** post-production settings. Depricated, but here for upwards compat (initialized to 1) */ + float postmul, postgamma, posthue, postsat; + + /* Dither noise intensity */ + float dither_intensity; + + /* Bake Render options */ + short bake_osa, bake_filter, bake_mode, bake_flag; + + /* yafray: global panel params. TODO: move elsewhere */ + short GIquality, GIcache, GImethod, GIphotons, GIdirect; + short YF_AA, YFexportxml, YF_nobump, YF_clamprgb, yfpad1; + int GIdepth, GIcausdepth, GIpixelspersample; + int GIphotoncount, GImixphotons; + float GIphotonradius; + int YF_numprocs, YF_raydepth, YF_AApasses, YF_AAsamples; + float GIshadowquality, GIrefinement, GIpower, GIindirpower; + float YF_gamma, YF_exposure, YF_raybias, YF_AApixelsize, YF_AAthreshold; + + /* paths to backbufffer, output, ftype */ + char backbuf[160], pic[160], ftype[160]; + + /* stamps flags. */ + int stamp; + short stamp_font_id, pad3; /* select one of blenders bitmap fonts */ + + /* stamp info user data. */ + char stamp_udata[160]; + + /* foreground/background color. */ + float fg_stamp[4]; + float bg_stamp[4]; +} RenderData; + + +typedef struct GameFraming { + float col[3]; + char type, pad1, pad2, pad3; +} GameFraming; + +#define SCE_GAMEFRAMING_BARS 0 +#define SCE_GAMEFRAMING_EXTEND 1 +#define SCE_GAMEFRAMING_SCALE 2 + +typedef struct TimeMarker { + struct TimeMarker *next, *prev; + int frame; + char name[64]; + unsigned int flag; +} TimeMarker; + +struct ImagePaintSettings { + struct Brush *brush; + short flag, tool; + int pad3; +}; + +typedef struct ToolSettings { + /* Subdivide Settings */ + short cornertype; + short editbutflag; + /*Triangle to Quad conversion threshold*/ + float jointrilimit; + /* Extrude Tools */ + float degr; + short step; + short turn; + + float extr_offs; + float doublimit; + + /* Primitive Settings */ + /* UV Sphere */ + short segments; + short rings; + + /* Cylinder - Tube - Circle */ + short vertices; + + /* UV Calculation */ + short unwrapper; + float uvcalc_radius; + float uvcalc_cubesize; + short uvcalc_mapdir; + short uvcalc_mapalign; + short uvcalc_flag; + + short pad2; + + /* Image Paint (8 byte aligned please!) */ + struct ImagePaintSettings imapaint; + + /* Select Group Threshold */ + float select_thresh; + + /* IPO-Editor */ + float clean_thresh; + + /* Retopo */ + char retopo_mode; + char retopo_paint_tool; + char line_div, ellipse_div, retopo_hotspot; + + /* Multires */ + char multires_subdiv_type; + + char pad4[2]; +} ToolSettings; + +/* Used by all brushes to store their properties, which can be directly set + by the interface code. Note that not all properties are actually used by + all the brushes. */ +typedef struct BrushData +{ + short size; + char strength, dir; /* Not used for smooth brush */ + char airbrush; + char view; + char pad[2]; +} BrushData; + +struct SculptSession; +typedef struct SculptData +{ + /* Data stored only from entering sculptmode until exiting sculptmode */ + struct SculptSession *session; + + /* Pointers to all of sculptmodes's textures */ + struct MTex *mtex[10]; + + /* Settings for each brush */ + BrushData drawbrush, smoothbrush, pinchbrush, inflatebrush, grabbrush, layerbrush, flattenbrush; + short brush_type; + + /* For the Brush Shape */ + short texact, texnr; + short spacing; + char texrept; + char texfade; + char texsep; + + char averaging; + char flags; + + /* Control tablet input */ + char tablet_size, tablet_strength; + + /* Symmetry is separate from the other BrushData because the same + settings are always used for all brush types */ + char symm; +} SculptData; + +typedef struct Scene { + ID id; + struct Object *camera; + struct World *world; + + struct Scene *set; + struct Image *ima; + + ListBase base; + struct Base *basact; + + float cursor[3]; + float twcent[3]; /* center for transform widget */ + float twmin[3], twmax[3]; /* boundbox of selection for transform widget */ + unsigned int lay; + + /* editmode stuff */ + float editbutsize; /* size of normals */ + short selectmode; /* for mesh only! */ + short proportional, prop_mode; + short automerge, pad5, pad6, pad7; + + short use_nodes; + + struct bNodeTree *nodetree; + + void *ed; /* sequence editor data is allocated here */ + struct Radio *radio; + + struct GameFraming framing; + + struct ToolSettings *toolsettings; + + /* migrate or replace? depends on some internal things... */ + /* no, is on the right place (ton) */ + struct RenderData r; + struct AudioData audio; + + ScriptLink scriptlink; + + ListBase markers; + + short jumpframe, pad1; + short snap_flag, snap_target; + + /* none of the dependancy graph vars is mean to be saved */ + struct DagForest *theDag; + short dagisvalid, dagflags; + short pad4, recalc; /* recalc = counterpart of ob->recalc */ + + /* Sculptmode data */ + struct SculptData sculptdata; +} Scene; + + +/* **************** RENDERDATA ********************* */ + +/* bufflag */ +#define R_BACKBUF 1 +#define R_BACKBUFANIM 2 +#define R_FRONTBUF 4 +#define R_FRONTBUFANIM 8 + +/* mode (int now) */ +#define R_OSA 0x0001 +#define R_SHADOW 0x0002 +#define R_GAMMA 0x0004 +#define R_ORTHO 0x0008 +#define R_ENVMAP 0x0010 +#define R_EDGE 0x0020 +#define R_FIELDS 0x0040 +#define R_FIELDSTILL 0x0080 +#define R_RADIO 0x0100 +#define R_BORDER 0x0200 +#define R_PANORAMA 0x0400 +#define R_CROP 0x0800 +#define R_COSMO 0x1000 +#define R_ODDFIELD 0x2000 +#define R_MBLUR 0x4000 + /* unified was here */ +#define R_RAYTRACE 0x10000 + /* R_GAUSS is obsolete, but used to retrieve setting from old files */ +#define R_GAUSS 0x20000 + /* fbuf obsolete... */ +#define R_FBUF 0x40000 + /* threads obsolete... is there for old files */ +#define R_THREADS 0x80000 +#define R_SPEED 0x100000 +#define R_SSS 0x200000 + +/* filtertype */ +#define R_FILTER_BOX 0 +#define R_FILTER_TENT 1 +#define R_FILTER_QUAD 2 +#define R_FILTER_CUBIC 3 +#define R_FILTER_CATROM 4 +#define R_FILTER_GAUSS 5 +#define R_FILTER_MITCH 6 +#define R_FILTER_FAST_GAUSS 7 /* note, this is only used for nodes at the moment */ + +/* yafray: renderer flag (not only exclusive to yafray) */ +#define R_INTERN 0 +#define R_YAFRAY 1 + +/* scemode */ +#define R_DOSEQ 0x0001 +#define R_BG_RENDER 0x0002 + /* passepartout is camera option now, keep this for backward compatibility */ +#define R_PASSEPARTOUT 0x0004 +#define R_PREVIEWBUTS 0x0008 +#define R_EXTENSION 0x0010 +#define R_NODE_PREVIEW 0x0020 +#define R_DOCOMP 0x0040 +#define R_COMP_CROP 0x0080 +#define R_FREE_IMAGE 0x0100 +#define R_SINGLE_LAYER 0x0200 +#define R_EXR_TILE_FILE 0x0400 +#define R_COMP_FREE 0x0800 +#define R_NO_IMAGE_LOAD 0x1000 +#define R_NO_TEX 0x2000 +#define R_STAMP_INFO 0x4000 + +/* r->stamp */ +#define R_STAMP_TIME 0x0001 +#define R_STAMP_FRAME 0x0002 +#define R_STAMP_DATE 0x0004 +#define R_STAMP_CAMERA 0x0008 +#define R_STAMP_SCENE 0x0010 +#define R_STAMP_NOTE 0x0020 +#define R_STAMP_DRAW 0x0040 /* draw in the image */ +#define R_STAMP_MARKER 0x0080 + +/* alphamode */ +#define R_ADDSKY 0 +#define R_ALPHAPREMUL 1 +#define R_ALPHAKEY 2 + +/* planes */ +#define R_PLANES24 24 +#define R_PLANES32 32 +#define R_PLANESBW 8 + +/* imtype */ +#define R_TARGA 0 +#define R_IRIS 1 +#define R_HAMX 2 +#define R_FTYPE 3 +#define R_JPEG90 4 +#define R_MOVIE 5 +#define R_IRIZ 7 +#define R_RAWTGA 14 +#define R_AVIRAW 15 +#define R_AVIJPEG 16 +#define R_PNG 17 +#define R_AVICODEC 18 +#define R_QUICKTIME 19 +#define R_BMP 20 +#define R_RADHDR 21 +#define R_TIFF 22 +#define R_OPENEXR 23 +#define R_FFMPEG 24 +#define R_FRAMESERVER 25 +#define R_CINEON 26 +#define R_DPX 27 +#define R_MULTILAYER 28 +#define R_DDS 29 + +/* subimtype, flag options for imtype */ +#define R_OPENEXR_HALF 1 +#define R_OPENEXR_ZBUF 2 +#define R_PREVIEW_JPG 4 + +/* bake_mode: same as RE_BAKE_xxx defines */ +/* bake_flag: */ +#define R_BAKE_CLEAR 1 +#define R_BAKE_OSA 2 + +/* **************** SCENE ********************* */ +#define RAD_PHASE_PATCHES 1 +#define RAD_PHASE_FACES 2 + +/* base->flag is in DNA_object_types.h */ + +/* scene->snap_flag */ +#define SCE_SNAP 1 +/* scene->snap_target */ +#define SCE_SNAP_TARGET_CLOSEST 0 +#define SCE_SNAP_TARGET_CENTER 1 +#define SCE_SNAP_TARGET_MEDIAN 2 + +/* sce->selectmode */ +#define SCE_SELECT_VERTEX 1 /* for mesh */ +#define SCE_SELECT_EDGE 2 +#define SCE_SELECT_FACE 4 + +/* sce->recalc (now in use by previewrender) */ +#define SCE_PRV_CHANGED 1 + +/* sce->prop_mode (proportional falloff) */ +#define PROP_SMOOTH 0 +#define PROP_SPHERE 1 +#define PROP_ROOT 2 +#define PROP_SHARP 3 +#define PROP_LIN 4 +#define PROP_CONST 5 +#define PROP_RANDOM 6 + + /* return flag next_object function */ +#define F_START 0 +#define F_SCENE 1 +#define F_SET 2 +#define F_DUPLI 3 + +/* audio->flag */ +#define AUDIO_MUTE 1 +#define AUDIO_SYNC 2 +#define AUDIO_SCRUB 4 + +#define FFMPEG_MULTIPLEX_AUDIO 1 +#define FFMPEG_AUTOSPLIT_OUTPUT 2 + +/* SculptData.flags */ +#define SCULPT_INPUT_SMOOTH 1 +#define SCULPT_DRAW_FAST 2 +#define SCULPT_DRAW_BRUSH 4 +/* SculptData.brushtype */ +#define DRAW_BRUSH 1 +#define SMOOTH_BRUSH 2 +#define PINCH_BRUSH 3 +#define INFLATE_BRUSH 4 +#define GRAB_BRUSH 5 +#define LAYER_BRUSH 6 +#define FLATTEN_BRUSH 7 +/* SculptData.texrept */ +#define SCULPTREPT_DRAG 1 +#define SCULPTREPT_TILE 2 +#define SCULPTREPT_3D 3 + +#define SYMM_X 1 +#define SYMM_Y 2 +#define SYMM_Z 4 + +/* toolsettings->imagepaint_flag */ +#define IMAGEPAINT_DRAWING 1 +#define IMAGEPAINT_DRAW_TOOL 2 +#define IMAGEPAINT_DRAW_TOOL_DRAWING 4 + +/* toolsettings->retopo_mode */ +#define RETOPO 1 +#define RETOPO_PAINT 2 + +/* toolsettings->retopo_paint_tool */ +#define RETOPO_PEN 1 +#define RETOPO_LINE 2 +#define RETOPO_ELLIPSE 4 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h new file mode 100644 index 00000000000..65374983af5 --- /dev/null +++ b/source/blender/makesdna/DNA_screen_types.h @@ -0,0 +1,171 @@ +/** + * blenlib/DNA_screen_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_SCREEN_TYPES_H +#define DNA_SCREEN_TYPES_H + +#include "DNA_listBase.h" +#include "DNA_vec_types.h" + +#include "DNA_ID.h" +#include "DNA_scriptlink_types.h" + +struct Scene; + +typedef struct bScreen { + ID id; + ListBase vertbase, edgebase, areabase; + struct Scene *scene; + short startx, endx, starty, endy; /* framebuffer coords */ + short sizex, sizey; + short scenenr, screennr; /* only for pupmenu */ + short full, pad; + short mainwin, winakt; + short handler[8]; /* similar to space handler now */ +} bScreen; + +typedef struct ScrVert { + struct ScrVert *next, *prev, *newv; + vec2s vec; + int flag; +} ScrVert; + +typedef struct ScrEdge { + struct ScrEdge *next, *prev; + ScrVert *v1, *v2; + short border; /* 1 when at edge of screen */ + short flag; + int pad; +} ScrEdge; + +#ifndef DNA_USHORT_FIX +#define DNA_USHORT_FIX +/** + * @deprecated This typedef serves to avoid badly typed functions when + * @deprecated compiling while delivering a proper dna.c. Do not use + * @deprecated it in any case. + */ +typedef unsigned short dna_ushort_fix; +#endif + + + +typedef struct Panel { /* the part from uiBlock that needs saved in file */ + struct Panel *next, *prev; + char panelname[64], tabname[64]; /* defined as UI_MAX_NAME_STR */ + char drawname[64]; /* panelname is identifier for restoring location */ + short ofsx, ofsy, sizex, sizey; + short flag, active; /* active= used currently by a uiBlock */ + short control; + short snap; + short old_ofsx, old_ofsy; /* for stow */ + int sortcounter; /* when sorting panels, it uses this to put new ones in right place */ + struct Panel *paneltab; /* this panel is tabbed in *paneltab */ +} Panel; + +typedef struct ScrArea { + struct ScrArea *next, *prev; + ScrVert *v1, *v2, *v3, *v4; + bScreen *full; /* if area==full, this is the parent */ + float winmat[4][4]; + rcti totrct, headrct, winrct; + + short headwin, win; + short headertype; /* 0=no header, 1= down, 2= up */ + char spacetype, butspacetype; /* SPACE_... */ + short winx, winy; /* size */ + char head_swap, head_equal; + char win_swap, win_equal; + + short headbutlen, headbutofs; + short cursor, flag; + + ScriptLink scriptlink; + + ListBase spacedata; + ListBase uiblocks; + ListBase panels; +} ScrArea; + +#define MAXWIN 128 + +/* area->flag */ +#define HEADER_NO_PULLDOWN 1 + +/* If you change EDGEWIDTH, also do the global arrat edcol[] */ +#define EDGEWIDTH 1 +#define EDGEWIDTH2 0 +#define AREAGRID 4 +#define AREAMINX 32 +#define HEADERY 26 +#define AREAMINY (HEADERY+EDGEWIDTH) + +#define HEADERDOWN 1 +#define HEADERTOP 2 + +#define SCREENNORMAL 0 +#define SCREENFULL 1 +#define SCREENAUTOPLAY 2 + +/* sa->win_swap */ +#define WIN_FRONT_OK 1 +#define WIN_BACK_OK 2 +#define WIN_EQUAL 3 + +#define L_SCROLL 1 /* left scrollbar */ +#define R_SCROLL 2 +#define VERT_SCROLL 3 +#define T_SCROLL 4 +#define B_SCROLL 8 +#define HOR_SCROLL 12 +#define B_SCROLLO 16 /* special hack for outliner hscroll - prevent hanging */ +#define HOR_SCROLLO 20 /* in older versions of blender */ + +/* Panel->snap - for snapping to screen edges */ +#define PNL_SNAP_NONE 0 +#define PNL_SNAP_TOP 1 +#define PNL_SNAP_RIGHT 2 +#define PNL_SNAP_BOTTOM 4 +#define PNL_SNAP_LEFT 8 + +#define PNL_SNAP_DIST 9.0 + +/* screen handlers */ +#define SCREEN_MAXHANDLER 8 + +#define SCREEN_HANDLER_ANIM 1 +#define SCREEN_HANDLER_PYTHON 2 +#define SCREEN_HANDLER_VERSE 3 + +#endif + diff --git a/source/blender/makesdna/DNA_scriptlink_types.h b/source/blender/makesdna/DNA_scriptlink_types.h new file mode 100644 index 00000000000..8a08d3f12c1 --- /dev/null +++ b/source/blender/makesdna/DNA_scriptlink_types.h @@ -0,0 +1,77 @@ +/** + * blenlib/DNA_object_types.h (mar-2001 nzc) + * + * Scriptlink is hard-coded in object for some reason. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_SCRIPTLINK_TYPES_H +#define DNA_SCRIPTLINK_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct ID; + +typedef struct ScriptLink { + struct ID **scripts; + short *flag; + + short actscript, totscript; + int pad; +} ScriptLink; + +/* **************** SCRIPTLINKS ********************* */ + +#define SCRIPT_FRAMECHANGED 1 +#define SCRIPT_ONLOAD 2 +#define SCRIPT_REDRAW 4 +#define SCRIPT_ONSAVE 8 +#define SCRIPT_RENDER 16 +/* POSTRENDER is not meant for the UI, it simply calls the + * RENDER script links for clean-up actions */ +#define SCRIPT_POSTRENDER 32 + +/* **************** SPACE HANDLERS ********************* */ +/* these are special scriptlinks that can be assigned to + * a given space in a given ScrArea to: + * - (EVENT type) handle events sent to that space; + * - (DRAW type) draw on the space after its own drawing function finishes + */ +#define SPACEHANDLER_VIEW3D_EVENT 1 +#define SPACEHANDLER_VIEW3D_DRAW 2 + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/source/blender/makesdna/DNA_sdna_types.h b/source/blender/makesdna/DNA_sdna_types.h new file mode 100644 index 00000000000..8553a3868d1 --- /dev/null +++ b/source/blender/makesdna/DNA_sdna_types.h @@ -0,0 +1,83 @@ +/** + * blenlib/DNA_sdna.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_SDNA_H +#define DNA_SDNA_H + +# +# +struct SDNA { + char *data; + int datalen, nr_names; + char **names; + int nr_types, pointerlen; + char **types; + short *typelens; + int nr_structs; + short **structs; + + /* wrong place for this really, its a simple + * cache for findstruct_nr. + */ + int lastfind; +}; + +# +# +typedef struct BHead { + int code, len; + void *old; + int SDNAnr, nr; +} BHead; +# +# +typedef struct BHead4 { + int code, len; + int old; + int SDNAnr, nr; +} BHead4; +# +# +typedef struct BHead8 { + int code, len; +#if defined(WIN32) && !defined(FREE_WINDOWS) + /* This is a compiler type! */ + __int64 old; +#else + long long old; +#endif + int SDNAnr, nr; +} BHead8; + +#endif + diff --git a/source/blender/makesdna/DNA_sensor_types.h b/source/blender/makesdna/DNA_sensor_types.h new file mode 100644 index 00000000000..7fcb400d66e --- /dev/null +++ b/source/blender/makesdna/DNA_sensor_types.h @@ -0,0 +1,253 @@ +/** + * blenlib/DNA_sensor_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_SENSOR_TYPES_H +#define DNA_SENSOR_TYPES_H + +struct Object; +struct Material; + +/* ****************** SENSORS ********************* */ + +typedef struct bNearSensor { + char name[32]; + float dist, resetdist; + int lastval, pad; +} bNearSensor; + +/** + * Defines the settings of a mouse sensor. + */ +typedef struct bMouseSensor { + /** + * The type of key this sensor listens to. + */ + short type; + short flag; + short pad1; + short pad2; +} bMouseSensor; + +typedef struct bTouchSensor { + char name[32]; + struct Material *ma; + float dist, pad; +} bTouchSensor; + +typedef struct bKeyboardSensor { + short key, qual; + short type, qual2; + /** + * Name of the target property + */ + char targetName[32]; + /** + * Name of the toggle property + */ + char toggleName[32]; +} bKeyboardSensor; + +typedef struct bPropertySensor { + int type; + int pad; + char name[32]; + char value[32]; + char maxvalue[32]; +} bPropertySensor; + +typedef struct bCollisionSensor { + char name[32]; /* property name */ + char materialName[32]; /* material */ + short damptimer, damp; + short mode; /* flag to choose material or property */ + short pad2; +} bCollisionSensor; + +typedef struct bRadarSensor { + char name[32]; + float angle; + float range; + short flag, axis; +} bRadarSensor; + +typedef struct bRandomSensor { + char name[32]; + int seed; + int delay; +} bRandomSensor; + +typedef struct bRaySensor { + char name[32]; + float range; + char propname[32]; + char matname[32]; + short mode; + short pad1; + int axisflag; +} bRaySensor; + +typedef struct bMessageSensor { + /** + * (Possible future use) pointer to a single sender object + */ + struct Object *fromObject; + + /** + * Can be used to filter on subjects like this + */ + char subject[32]; + + /** + * (Possible future use) body to filter on + */ + char body[32]; +} bMessageSensor; + +typedef struct bSensor { + struct bSensor *next, *prev; + /* pulse and freq are the bool toggle and frame count for pulse mode */ + short type, otype, flag, pulse; + short freq, totlinks, pad1, pad2; + char name[32]; + void *data; + + struct bController **links; + + struct Object *ob; + + /* just add here, to avoid align errors... */ + short invert; /* Whether or not to invert the output. */ + short freq2; /* The negative pulsing frequency? Not used anymore... */ + int pad; +} bSensor; + +typedef struct bJoystickSensor { + char name[32]; + short type; + short pad; + int axis; + int axisf; + int button; + int buttonf; + int hat; + int hatf; + int precision; +} bJoystickSensor; + +/* bMouseSensor->type: uses blender event defines */ + +/* propertysensor->type */ +#define SENS_PROP_EQUAL 0 +#define SENS_PROP_NEQUAL 1 +#define SENS_PROP_INTERVAL 2 +#define SENS_PROP_CHANGED 3 +#define SENS_PROP_EXPRESSION 4 + +/* raysensor->axisflag */ +/* flip x and y to make y default!!! */ +#define SENS_RAY_X_AXIS 1 +#define SENS_RAY_Y_AXIS 0 +#define SENS_RAY_Z_AXIS 2 +#define SENS_RAY_NEG_X_AXIS 3 +#define SENS_RAY_NEG_Y_AXIS 4 +#define SENS_RAY_NEG_Z_AXIS 5 +//#define SENS_RAY_NEGATIVE_AXIS 1 + +/* bMessageSensor->type */ +#define SENS_MESG_MESG 0 +#define SENS_MESG_PROP 1 + +/* sensor->type */ +#define SENS_ALWAYS 0 +#define SENS_TOUCH 1 +#define SENS_NEAR 2 +#define SENS_KEYBOARD 3 +#define SENS_PROPERTY 4 +#define SENS_MOUSE 5 +#define SENS_COLLISION 6 +#define SENS_RADAR 7 +#define SENS_RANDOM 8 +#define SENS_RAY 9 +#define SENS_MESSAGE 10 +#define SENS_JOYSTICK 11 +/* sensor->flag */ +#define SENS_SHOW 1 +#define SENS_DEL 2 +#define SENS_NEW 4 +#define SENS_NOT 8 + +/* sensor->pulse */ +#define SENS_PULSE_CONT 0 +#define SENS_PULSE_REPEAT 1 +//#define SENS_PULSE_ONCE 2 +#define SENS_NEG_PULSE_MODE 4 + +/* sensor->suppress */ +#define SENS_SUPPRESS_POSITIVE (1 << 0) +#define SENS_SUPPRESS_NEGATIVE (1 << 1) + +/* collision, ray sensor modes: */ +/* A little bit fake: when property is active, the first bit is + * reset. Bite me :) So we don't actually use it, so we comment it out + * ... The reason for this is that we need to be backward compatible, + * and have a proper default value for this thing. + * */ +/* #define SENS_COLLISION_PROPERTY 0 */ +#define SENS_COLLISION_MATERIAL 1 + +/* Some stuff for the mouse sensor Type: */ +#define BL_SENS_MOUSE_LEFT_BUTTON 1 +#define BL_SENS_MOUSE_MIDDLE_BUTTON 2 +#define BL_SENS_MOUSE_RIGHT_BUTTON 4 +#define BL_SENS_MOUSE_WHEEL_UP 5 +#define BL_SENS_MOUSE_WHEEL_DOWN 6 +#define BL_SENS_MOUSE_MOVEMENT 8 +#define BL_SENS_MOUSE_MOUSEOVER 16 +#define BL_SENS_MOUSE_MOUSEOVER_ANY 32 + +#define SENS_JOY_BUTTON 0 +#define SENS_JOY_BUTTON_PRESSED 0 +#define SENS_JOY_BUTTON_RELEASED 1 + +#define SENS_JOY_AXIS 1 +#define SENS_JOY_X_AXIS 0 +#define SENS_JOY_Y_AXIS 1 +#define SENS_JOY_NEG_X_AXIS 2 +#define SENS_JOY_NEG_Y_AXIS 3 +#define SENS_JOY_PRECISION 4 + +#define SENS_JOY_HAT 2 +#define SENS_JOY_HAT_DIR 0 + +#endif + diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h new file mode 100644 index 00000000000..839d804fbea --- /dev/null +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -0,0 +1,239 @@ +/** + * blenlib/DNA_sequence_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_SEQUENCE_TYPES_H +#define DNA_SEQUENCE_TYPES_H + +#include "DNA_listBase.h" + +/* needed for sound support */ +#include "DNA_sound_types.h" + +struct Ipo; +struct Scene; + +/* strlens; 80= FILE_MAXFILE, 160= FILE_MAXDIR */ + +typedef struct StripElem { + char name[80]; + struct ImBuf *ibuf; + struct StripElem *se1, *se2, *se3; + short ok; + short pad; + int nr; +} StripElem; + +typedef struct Strip { + struct Strip *next, *prev; + int rt, len, us, done; + StripElem *stripdata; + char dir[160]; + int orx, ory; +} Strip; + + +typedef struct PluginSeq { + char name[256]; + void *handle; + + char *pname; + + int vars, version; + + void *varstr; + float *cfra; + + float data[32]; + + void *instance_private_data; + void **current_private_data; + + void (*doit)(void); + + void (*callback)(void); +} PluginSeq; + +/* The sequence structure is the basic struct used by any strip. each of the strips uses a different sequence structure.*/ +/* WATCH IT: first part identical to ID (for use in ipo's) */ + +typedef struct Sequence { + + struct Sequence *next, *prev; + void *tmp; /* tmp var for copying, and tagging for linked selection */ + void *lib; /* needed (to be like ipo), else it will raise libdata warnings, this should never be used */ + char name[24]; /* name, not set by default and dosnt need to be unique as with ID's */ + + short flag, type; /*flags bitmap (see below) and the type of sequence*/ + int len; /* the length of the contense of this strip - before handles are applied */ + int start, startofs, endofs; + int startstill, endstill; + int machine, depth; /*machine - the strip channel, depth - the depth in the sequence when dealing with metastrips */ + int startdisp, enddisp; /*starting and ending points in the sequence*/ + float mul, handsize; + /* is sfra needed anymore? - it looks like its only used in one place */ + int sfra; /* starting frame according to the timeline of the scene. */ + + Strip *strip; + StripElem *curelem; /* reference the current frame - value from give_stripelem */ + + struct Ipo *ipo; + struct Scene *scene; + struct anim *anim; + float facf0, facf1; + + PluginSeq *plugin; + + /* pointers for effects: */ + struct Sequence *seq1, *seq2, *seq3; + + ListBase seqbase; /* list of strips for metastrips */ + + struct bSound *sound; /* the linked "bSound" object */ + struct hdaudio *hdaudio; /* external hdaudio object */ + float level, pan; /* level in dB (0=full), pan -1..1 */ + int curpos; /* last sample position in audio_fill() */ + float strobe; + + void *effectdata; /* Struct pointer for effect settings */ + + int anim_preseek; + int pad; +} Sequence; + +typedef struct MetaStack { + struct MetaStack *next, *prev; + ListBase *oldbasep; + Sequence *parseq; +} MetaStack; + +typedef struct Editing { + ListBase *seqbasep; + ListBase seqbase; + ListBase metastack; + short flag; + short pad; + int rt; +} Editing; + +/* ************* Effect Variable Structs ********* */ +typedef struct WipeVars { + float edgeWidth,angle; + short forward, wipetype; +} WipeVars; + +typedef struct GlowVars { + float fMini; /* Minimum intensity to trigger a glow */ + float fClamp; + float fBoost; /* Amount to multiply glow intensity */ + float dDist; /* Radius of glow blurring */ + int dQuality; + int bNoComp; /* SHOW/HIDE glow buffer */ +} GlowVars; + +typedef struct TransformVars { + float ScalexIni; + float ScaleyIni; + float ScalexFin; + float ScaleyFin; + float xIni; + float xFin; + float yIni; + float yFin; + float rotIni; + float rotFin; + int percent; + int interpolation; +} TransformVars; + +typedef struct SolidColorVars { + float col[3]; + float pad; +} SolidColorVars; + +typedef struct SpeedControlVars { + float * frameMap; + float globalSpeed; + int flags; + int length; + int lastValidFrame; +} SpeedControlVars; + +/* SpeedControlVars->flags */ +#define SEQ_SPEED_INTEGRATE 1 +#define SEQ_SPEED_BLEND 2 +#define SEQ_SPEED_COMPRESS_IPO_Y 4 + +/* ***************** SEQUENCE ****************** */ + +/* seq->flag */ +#define SEQ_LEFTSEL 2 +#define SEQ_RIGHTSEL 4 +#define SEQ_OVERLAP 8 +#define SEQ_FILTERY 16 +#define SEQ_MUTE 32 +#define SEQ_MAKE_PREMUL 64 +#define SEQ_REVERSE_FRAMES 128 +#define SEQ_IPO_FRAME_LOCKED 256 +#define SEQ_EFFECT_NOT_LOADED 512 +#define SEQ_FLAG_DELETE 1024 +#define SEQ_FLIPX 2048 +#define SEQ_FLIPY 4096 + +/* seq->type WATCH IT: SEQ_EFFECT BIT is used to determine if this is an effect strip!!! */ +#define SEQ_IMAGE 0 +#define SEQ_META 1 +#define SEQ_SCENE 2 +#define SEQ_MOVIE 3 +#define SEQ_RAM_SOUND 4 +#define SEQ_HD_SOUND 5 +#define SEQ_MOVIE_AND_HD_SOUND 6 /* helper for add_sequence */ + +#define SEQ_EFFECT 8 +#define SEQ_CROSS 8 +#define SEQ_ADD 9 +#define SEQ_SUB 10 +#define SEQ_ALPHAOVER 11 +#define SEQ_ALPHAUNDER 12 +#define SEQ_GAMCROSS 13 +#define SEQ_MUL 14 +#define SEQ_OVERDROP 15 +#define SEQ_PLUGIN 24 +#define SEQ_WIPE 25 +#define SEQ_GLOW 26 +#define SEQ_TRANSFORM 27 +#define SEQ_COLOR 28 +#define SEQ_SPEED 29 + + +#endif + diff --git a/source/blender/makesdna/DNA_sound_types.h b/source/blender/makesdna/DNA_sound_types.h new file mode 100644 index 00000000000..27b9c373484 --- /dev/null +++ b/source/blender/makesdna/DNA_sound_types.h @@ -0,0 +1,183 @@ +/** + * blenlib/DNA_sound_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_SOUND_TYPES_H +#define DNA_SOUND_TYPES_H + +#include "DNA_listBase.h" +#include "DNA_ID.h" + +/* stupid... could easily be solved */ +#include "DNA_view2d_types.h" + +/* extern int noaudio; * defined in sound.c . also not very nice */ +/* extern ListBase *samples; don't do this in DNA, but in BKE_... instead */ + +struct bSample; +struct Ipo; +struct PackedFile; +struct SpaceLink; + +/* should not be here! */ +# +# +typedef struct bSample { + ID id; + void *data; + void *snd_sample; + short type, bits; + short channels; + int len, rate; +// int buffer; + int alindex; + char fakedata[16]; + int flags; + char name[160]; + struct PackedFile * packedfile; + short us; +} bSample; + + + +typedef struct bSound { + ID id; + char name[160]; + struct bSample *sample; + void *stream; + struct PackedFile *packedfile; + struct PackedFile *newpackedfile; + void *snd_sound; + struct Ipo *ipo; + float volume, panning; + /** + * Sets the rollofffactor. The rollofffactor is a per-Source parameter + * the application can use to increase or decrease the range of a source + * by decreasing or increasing the attenuation, respectively. The default + * value is 1. The implementation is free to optimize for a rollofffactor + * value of 0, which indicates that the application does not wish any + * distance attenuation on the respective Source. + */ + float attenuation; + float pitch; + /** + * min_gain indicates the minimal gain which is always guaranteed for this sound + */ + float min_gain; + /** + * max_gain indicates the maximal gain which is always guaranteed for this sound + */ + float max_gain; + /** + * Sets the referencedistance at which the listener will experience gain. + */ + float distance; + int flags; + int streamlen; + char channels; + char highprio; + char pad[10]; +} bSound; + +typedef struct bSoundListener { + ID id; + /** + * Overall gain + */ + float gain; + /** + * Sets a scaling to exaggerate or deemphasize the Doppler (pitch) shift + * resulting from the calculation. + */ + float dopplerfactor; + /** + * Sets the value of the propagation speed relative to which the source + * velocities are interpreted. + */ + float dopplervelocity; + short numsoundsblender; + short numsoundsgameengine; + +} bSoundListener; + +/* spacesound->flag */ +#define SND_DRAWFRAMES 1 +#define SND_CFRA_NUM 2 + +typedef struct SpaceSound { + struct SpaceLink *next, *prev; + int spacetype; + float blockscale; + struct ScrArea *area; + + View2D v2d; + + bSound *sound; + short mode, sndnr; + short xof, yof; + short flag, lock; + int pad2; +} SpaceSound; + + +enum SAMPLE_FileTypes { + SAMPLE_INVALID = -1, // must be negative + SAMPLE_UNKNOWN = 0, + SAMPLE_RAW, + SAMPLE_WAV, + SAMPLE_MP2, + SAMPLE_MP3, + SAMPLE_OGG_VORBIS, + SAMPLE_WMA, + SAMPLE_ASF, + SAMPLE_AIFF +}; + + +#define SOUND_CHANNELS_STEREO 0 +#define SOUND_CHANNELS_LEFT 1 +#define SOUND_CHANNELS_RIGHT 2 + +#define SOUND_FLAGS_LOOP (1 << 0) +#define SOUND_FLAGS_FIXED_VOLUME (1 << 1) +#define SOUND_FLAGS_FIXED_PANNING (1 << 2) +#define SOUND_FLAGS_3D (1 << 3) +#define SOUND_FLAGS_BIDIRECTIONAL_LOOP (1 << 4) +#define SOUND_FLAGS_PRIORITY (1 << 5) +#define SOUND_FLAGS_SEQUENCE (1 << 6) + +#define SAMPLE_NEEDS_SAVE (1 << 0) + +/* to DNA_sound_types.h*/ + +#endif + diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h new file mode 100644 index 00000000000..10f488c9f61 --- /dev/null +++ b/source/blender/makesdna/DNA_space_types.h @@ -0,0 +1,649 @@ +/** + * blenlib/DNA_space_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_SPACE_TYPES_H +#define DNA_SPACE_TYPES_H + +#include "DNA_listBase.h" +#include "DNA_vec_types.h" +#include "DNA_oops_types.h" /* for TreeStoreElem */ +#include "DNA_image_types.h" /* ImageUser */ +/* Hum ... Not really nice... but needed for spacebuts. */ +#include "DNA_view2d_types.h" + +struct Ipo; +struct ID; +struct Text; +struct Script; +struct ImBuf; +struct Image; +struct SpaceIpo; +struct BlendHandle; +struct RenderInfo; +struct bNodeTree; +struct uiBlock; +struct FileList; + + /** + * The base structure all the other spaces + * are derived (implicitly) from. Would be + * good to make this explicit. + */ +typedef struct SpaceLink SpaceLink; +struct SpaceLink { + SpaceLink *next, *prev; + int spacetype; + float blockscale; + struct ScrArea *area; + short blockhandler[8]; +}; + +typedef struct SpaceInfo { + SpaceLink *next, *prev; + int spacetype; + float blockscale; + struct ScrArea *area; + + short blockhandler[8]; +} SpaceInfo; + +typedef struct SpaceIpo { + SpaceLink *next, *prev; + int spacetype; + float blockscale; + struct ScrArea *area; + + short blockhandler[8]; + + unsigned int rowbut, pad2; + View2D v2d; + + void *editipo; + ListBase ipokey; + + /* the ipo context we need to store */ + struct Ipo *ipo; + struct ID *from; + char actname[32], constname[32]; + + short totipo, pin; + short butofs, channel; + short showkey, blocktype; + short menunr, lock; + int flag; + float median[3]; + rctf tot; +} SpaceIpo; + +typedef struct SpaceButs { + SpaceLink *next, *prev; + int spacetype; + float blockscale; + struct ScrArea *area; + struct RenderInfo *ri; + + short blockhandler[8]; + + short cursens, curact; + short align, tabo; /* align for panels, tab is old tab */ + View2D v2d; + + short mainb, menunr; /* texnr and menunr have to remain shorts */ + short pin, mainbo; + void *lockpoin; + + short texnr; + char texfrom, showgroup; + + short modeltype; + short scriptblock; + short scaflag; + short re_align; + + short oldkeypress; /* for keeping track of the sub tab key cycling */ + char pad, flag; + + char texact, tab[7]; /* storing tabs for each context */ + +} SpaceButs; + +typedef struct SpaceSeq { + SpaceLink *next, *prev; + int spacetype; + float blockscale; + struct ScrArea *area; + + short blockhandler[8]; + + View2D v2d; + + float xof, yof; /* offset for drawing the image preview */ + short mainb, zoom; + short chanshown; + short pad2; + int flag; + int pad; +} SpaceSeq; + +typedef struct SpaceFile { + SpaceLink *next, *prev; + int spacetype; + float blockscale; + struct ScrArea *area; + + short blockhandler[8]; + + struct direntry *filelist; + int totfile; + + char title[24]; + char dir[160]; + char file[80]; + + short type, ofs, flag, sort; + short maxnamelen, collums, f_fp, pad1; + int pad2; + char fp_str[8]; + + struct BlendHandle *libfiledata; + + unsigned short retval; /* event */ + short menu, act, ipotype; + + /* one day we'll add unions to dna */ + void (*returnfunc)(char *); + void (*returnfunc_event)(unsigned short); + void (*returnfunc_args)(char *, void *, void *); + + void *arg1, *arg2; + short *menup; /* pointer to menu result or ID browsing */ + char *pupmenu; /* optional menu in header */ +} SpaceFile; + +typedef struct SpaceOops { + SpaceLink *next, *prev; + int spacetype; + float blockscale; + struct ScrArea *area; + + short blockhandler[8]; + + View2D v2d; + + ListBase oops; + short pin, visiflag, flag, rt; + void *lockpoin; + + ListBase tree; + struct TreeStore *treestore; + + /* search stuff */ + char search_string[32]; + struct TreeStoreElem search_tse; + int search_flags, do_; + + short type, outlinevis, storeflag; + short deps_flags; + +} SpaceOops; + +typedef struct SpaceImage { + SpaceLink *next, *prev; + int spacetype; + float blockscale; + struct ScrArea *area; + + short blockhandler[8]; + + View2D v2d; + + struct Image *image; + struct ImageUser iuser; + + struct CurveMapping *cumap; + short mode, menunr; + short imanr; + short curtile; /* the currently active tile of the image when tile is enabled, is kept in sync with the active faces tile */ + int flag; + short imtypenr, lock; + short showspare, pin; + float zoom; + char dt_uv; /* UV draw type */ + char sticky; /* sticky selection type */ + char pad[6]; + + float xof, yof; /* user defined offset, image is centered */ + float centx, centy; /* storage for offset while render drawing */ + + char *info_str, *info_spare; /* info string for render */ + struct ImBuf *spare; + +} SpaceImage; + +typedef struct SpaceNla { + struct SpaceLink *next, *prev; + int spacetype; + float blockscale; + struct ScrArea *area; + + short blockhandler[8]; + + short menunr, lock; + short autosnap; /* this uses the same settings as autosnap for Action Editor */ + short flag; + + View2D v2d; +} SpaceNla; + +typedef struct SpaceText { + SpaceLink *next, *prev; + int spacetype; + float blockscale; + struct ScrArea *area; + + short blockhandler[8]; + + struct Text *text; + + int top, viewlines; + short flags, menunr; + + int font_id; + int lheight; + int left; + int showlinenrs; + + int tabnumber; + int currtab_set; + int showsyntax; + int unused_padd; + + float pix_per_line; + + struct rcti txtscroll, txtbar; + +} SpaceText; + +typedef struct SpaceScript { + SpaceLink *next, *prev; + int spacetype; + float blockscale; + struct ScrArea *area; + struct Script *script; + + short flags, menunr; + int pad1; + + void *but_refs; +} SpaceScript; + +typedef struct SpaceTime { + SpaceLink *next, *prev; + int spacetype; + float blockscale; + struct ScrArea *area; + + View2D v2d; + + int flag, redraws; + +} SpaceTime; + +typedef struct SpaceNode { + SpaceLink *next, *prev; + int spacetype; + float blockscale; + struct ScrArea *area; + + View2D v2d; + + struct ID *id, *from; /* context, no need to save in file? well... pinning... */ + short flag, menunr; /* menunr: browse id block in header */ + float aspect; + void *curfont; + + float xof, yof; /* offset for drawing the backdrop */ + + struct bNodeTree *nodetree, *edittree; + int treetype, pad; /* treetype: as same nodetree->type */ + +} SpaceNode; + +/* snode->flag */ +#define SNODE_DO_PREVIEW 1 +#define SNODE_BACKDRAW 2 + +typedef struct SpaceImaSel { + SpaceLink *next, *prev; + int spacetype; + float blockscale; + struct ScrArea *area; + + short blockhandler[8]; + + View2D v2d; + + struct FileList *files; + + /* specific stuff for drawing */ + char title[24]; + char dir[160]; + char file[80]; + + short type, menu, flag, sort; + + void *curfont; + int active_file; + + int numtilesx; + int numtilesy; + + int selstate; + + struct rcti viewrect; + struct rcti bookmarkrect; + + float scrollpos; /* current position of scrollhandle */ + float scrollheight; /* height of the scrollhandle */ + float scrollarea; /* scroll region, scrollpos is from 0 to scrollarea */ + + float aspect; + unsigned short retval; /* event */ + + short ipotype; + + short filter; + short active_bookmark; + short pad, pad1; + + /* view settings */ + short prv_w; + short prv_h; + + /* one day we'll add unions to dna */ + void (*returnfunc)(char *); + void (*returnfunc_event)(unsigned short); + void (*returnfunc_args)(char *, void *, void *); + + void *arg1, *arg2; + short *menup; /* pointer to menu result or ID browsing */ + char *pupmenu; /* optional menu in header */ + + struct ImBuf *img; +} SpaceImaSel; + + +/* **************** SPACE ********************* */ + + +/* view3d Now in DNA_view3d_types.h */ + +/* button defines in BIF_butspace.h */ + +/* sbuts->flag */ +#define SB_PRV_OSA 1 + +/* these values need to be hardcoded in structs, dna does not recognize defines */ +/* also defined in BKE */ +#define FILE_MAXDIR 160 +#define FILE_MAXFILE 80 +#define FILE_MAX 240 + +/* filesel types */ +#define FILE_UNIX 8 +#define FILE_BLENDER 8 +#define FILE_SPECIAL 9 + +#define FILE_LOADLIB 1 +#define FILE_MAIN 2 +#define FILE_LOADFONT 3 + +/* sfile->flag and simasel->flag */ +#define FILE_SHOWSHORT 1 +#define FILE_STRINGCODE 2 +#define FILE_LINK 4 +#define FILE_HIDE_DOT 8 +#define FILE_AUTOSELECT 16 +#define FILE_ACTIVELAY 32 +#define FILE_ATCURSOR 64 +#define FILE_SYNCPOSE 128 +#define FILE_FILTER 256 +#define FILE_BOOKMARKS 512 + +/* sfile->sort */ +#define FILE_SORTALPHA 0 +#define FILE_SORTDATE 1 +#define FILE_SORTSIZE 2 +#define FILE_SORTEXTENS 3 + +/* files in filesel list: 2=ACTIVE */ +#define HILITE 1 +#define BLENDERFILE 4 +#define PSXFILE 8 +#define IMAGEFILE 16 +#define MOVIEFILE 32 +#define PYSCRIPTFILE 64 +#define FTFONTFILE 128 +#define SOUNDFILE 256 +#define TEXTFILE 512 +#define MOVIEFILE_ICON 1024 /* movie file that preview can't load */ +#define FOLDERFILE 2048 /* represents folders for filtering */ + +#define SCROLLH 16 /* height scrollbar */ +#define SCROLLB 16 /* width scrollbar */ + +/* SpaceImage->mode */ +#define SI_TEXTURE 0 +#define SI_SHOW 1 + +/* SpaceImage->dt_uv */ +#define SI_UVDT_DASH 0 +#define SI_UVDT_BLACK 1 +#define SI_UVDT_WHITE 2 +#define SI_UVDT_OUTLINE 3 + +/* SpaceImage->sticky + * Note DISABLE should be 0, however would also need to re-arrange icon order, + * also, sticky loc is the default mode so this means we dont need to 'do_versons' */ +#define SI_STICKY_LOC 0 +#define SI_STICKY_DISABLE 1 +#define SI_STICKY_VERTEX 2 + +/* SpaceImage->flag */ +#define SI_BE_SQUARE 1<<0 +#define SI_EDITTILE 1<<1 +#define SI_CLIP_UV 1<<2 +#define SI_DRAWTOOL 1<<3 +#define SI_DEPRECATED1 1<<4 /* stick UVs to others in the same location */ +#define SI_DRAWSHADOW 1<<5 +#define SI_SELACTFACE 1<<6 +#define SI_DEPRECATED2 1<<7 +#define SI_DEPRECATED3 1<<8 /* stick UV selection to mesh vertex (UVs wont always be touching) */ +#define SI_COORDFLOATS 1<<9 +#define SI_PIXELSNAP 1<<10 +#define SI_LIVE_UNWRAP 1<<11 +#define SI_USE_ALPHA 1<<12 +#define SI_SHOW_ALPHA 1<<13 +#define SI_SHOW_ZBUF 1<<14 + /* next two for render window dislay */ +#define SI_PREVSPACE 1<<15 +#define SI_FULLWINDOW 1<<16 +#define SI_SYNC_UVSEL 1<<17 +#define SI_LOCAL_UV 1<<18 + /* this means that the image is drawn until it reaches the view edge, + * in the image view, its unrelated to the 'tile' mode for texface */ +#define SI_DRAW_TILE 1<<19 +#define SI_SMOOTH_UV 1<<20 + +/* SpaceText flags (moved from DNA_text_types.h) */ + +#define ST_SCROLL_SELECT 0x0001 // scrollable +#define ST_CLEAR_NAMESPACE 0x0010 // clear namespace after script + // execution (see BPY_main.c) + +/* SpaceOops->type */ +#define SO_OOPS 0 +#define SO_OUTLINER 1 +#define SO_DEPSGRAPH 2 + +/* SpaceOops->flag */ +#define SO_TESTBLOCKS 1 +#define SO_NEWSELECTED 2 +#define SO_HIDE_RESTRICTCOLS 4 + +/* SpaceOops->visiflag */ +#define OOPS_SCE 1 +#define OOPS_OB 2 +#define OOPS_ME 4 +#define OOPS_CU 8 +#define OOPS_MB 16 +#define OOPS_LT 32 +#define OOPS_LA 64 +#define OOPS_MA 128 +#define OOPS_TE 256 +#define OOPS_IP 512 +#define OOPS_LAY 1024 +#define OOPS_LI 2048 +#define OOPS_IM 4096 +#define OOPS_AR 8192 +#define OOPS_GR 16384 + +/* SpaceOops->outlinevis */ +#define SO_ALL_SCENES 0 +#define SO_CUR_SCENE 1 +#define SO_VISIBLE 2 +#define SO_SELECTED 3 +#define SO_ACTIVE 4 +#define SO_SAME_TYPE 5 +#define SO_GROUPS 6 +#define SO_LIBRARIES 7 +#define SO_VERSE_SESSION 8 +#define SO_VERSE_MS 9 + +/* SpaceOops->storeflag */ +#define SO_TREESTORE_CLEANUP 1 + /* if set, it allows redraws. gets set for some allqueue events */ +#define SO_TREESTORE_REDRAW 2 + +/* headerbuttons: 450-499 */ + +#define B_IMASELHOME 451 +#define B_IMASELREMOVEBIP 452 + +#define C_BACK 0xBAAAAA +#define C_DARK 0x665656 +#define C_DERK 0x766666 +#define C_HI 0xCBBBBB +#define C_LO 0x544444 + +/* queue settings */ +#define IMS_KNOW_WIN 1 +#define IMS_KNOW_BIP 2 +#define IMS_KNOW_DIR 4 +#define IMS_DOTHE_INF 8 +#define IMS_KNOW_INF 16 +#define IMS_DOTHE_IMA 32 +#define IMS_KNOW_IMA 64 +#define IMS_FOUND_BIP 128 +#define IMS_DOTHE_BIP 256 +#define IMS_WRITE_NO_BIP 512 + +/* imasel->mode */ +#define IMS_NOIMA 0 +#define IMS_IMA 1 +#define IMS_ANIM 2 +#define IMS_DIR 4 +#define IMS_FILE 8 +#define IMS_STRINGCODE 16 + +#define IMS_INDIR 1 +#define IMS_INDIRSLI 2 +#define IMS_INFILE 3 +#define IMS_INFILESLI 4 + +/* nla->flag */ +#define SNLA_ALLKEYED 1 +#define SNLA_ACTIVELAYERS 2 +#define SNLA_DRAWTIME 4 + +/* time->flag */ + /* show timing in frames instead of in seconds */ +#define TIME_DRAWFRAMES 1 + /* temporary flag set when scrubbing time */ +#define TIME_CFRA_NUM 2 + /* only keyframes from active/selected channels get shown */ +#define TIME_ONLYACTSEL 4 + +/* time->redraws */ +#define TIME_LEFTMOST_3D_WIN 1 +#define TIME_ALL_3D_WIN 2 +#define TIME_ALL_ANIM_WIN 4 +#define TIME_ALL_BUTS_WIN 8 +#define TIME_WITH_SEQ_AUDIO 16 +#define TIME_SEQ 32 +#define TIME_ALL_IMAGE_WIN 64 + +/* sseq->mainb */ +#define SEQ_DRAW_SEQUENCE 0 +#define SEQ_DRAW_IMG_IMBUF 1 +#define SEQ_DRAW_IMG_WAVEFORM 2 +#define SEQ_DRAW_IMG_VECTORSCOPE 3 + +/* sseq->flag */ +#define SEQ_DRAWFRAMES 1 +#define SEQ_MARKER_TRANS 2 + +/* space types, moved from DNA_screen_types.h */ +enum { + SPACE_EMPTY, + SPACE_VIEW3D, + SPACE_IPO, + SPACE_OOPS, + SPACE_BUTS, + SPACE_FILE, + SPACE_IMAGE, + SPACE_INFO, + SPACE_SEQ, + SPACE_TEXT, + SPACE_IMASEL, + SPACE_SOUND, + SPACE_ACTION, + SPACE_NLA, + SPACE_SCRIPT, + SPACE_TIME, + SPACE_NODE, + SPACEICONMAX = SPACE_NODE +/* SPACE_LOGIC */ +}; + +#endif diff --git a/source/blender/makesdna/DNA_text_types.h b/source/blender/makesdna/DNA_text_types.h new file mode 100644 index 00000000000..8f2b40f7ff6 --- /dev/null +++ b/source/blender/makesdna/DNA_text_types.h @@ -0,0 +1,80 @@ +/** + * blenlib/DNA_text_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_TEXT_TYPES_H +#define DNA_TEXT_TYPES_H + +#include "DNA_listBase.h" +#include "DNA_ID.h" + +typedef struct TextLine { + struct TextLine *next, *prev; + + char *line; + char *format; + int len, blen; +} TextLine; + +typedef struct Text { + ID id; + + char *name; + + int flags, nlines; + + ListBase lines; + TextLine *curl, *sell; + int curc, selc; + + char *undo_buf; + int undo_pos, undo_len; + + void *compiled; +} Text; + + +#define TXT_OFFSET 35 +#define TXT_TABSIZE 4 +#define TXT_INIT_UNDO 1024 +#define TXT_MAX_UNDO (TXT_INIT_UNDO*TXT_INIT_UNDO) + +/* text flags */ +#define TXT_ISDIRTY 0x0001 +#define TXT_ISTMP 0x0002 +#define TXT_ISMEM 0x0004 +#define TXT_ISEXT 0x0008 +#define TXT_ISSCRIPT 0x0010 /* used by space handler scriptlinks */ +#define TXT_READONLY 0x0100 +#define TXT_FOLLOW 0x0200 /* always follow cursor (console) */ + +#endif diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h new file mode 100644 index 00000000000..cf51990c9bf --- /dev/null +++ b/source/blender/makesdna/DNA_texture_types.h @@ -0,0 +1,377 @@ +/** + * blenlib/DNA_texture_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_TEXTURE_TYPES_H +#define DNA_TEXTURE_TYPES_H + +#include "DNA_ID.h" +#include "DNA_image_types.h" + +struct Ipo; +struct PluginTex; +struct ColorBand; +struct EnvMap; +struct Object; +struct Tex; +struct Image; +struct PreviewImage; +struct ImBuf; + +typedef struct MTex { + + short texco, mapto, maptoneg, blendtype; + struct Object *object; + struct Tex *tex; + char uvname[32]; + + char projx, projy, projz, mapping; + float ofs[3], size[3]; + + short texflag, colormodel; + float r, g, b, k; + float def_var; + + float colfac, norfac, varfac; + float dispfac; + float warpfac; + +} MTex; + +#ifndef DNA_USHORT_FIX +#define DNA_USHORT_FIX +/** + * @deprecated This typedef serves to avoid badly typed functions when + * @deprecated compiling while delivering a proper dna.c. Do not use + * @deprecated it in any case. + */ +typedef unsigned short dna_ushort_fix; +#endif + +typedef struct PluginTex { + char name[160]; + void *handle; + + char *pname; + char *stnames; + + int stypes; + int vars; + void *varstr; + float *result; + float *cfra; + + float data[32]; + + int (*doit)(void); + void (*instance_init)(void *); + + /* should be void (*)(unsigned short)... patched */ + void (*callback)(dna_ushort_fix); + + int version, pad; +} PluginTex; + +typedef struct CBData { + float r, g, b, a, pos; + int cur; +} CBData; + +/* 32 = MAXCOLORBAND */ +/* note that this has to remain a single struct, for UserDef */ +typedef struct ColorBand { + short flag, tot, cur, ipotype; + CBData data[32]; + +} ColorBand; + +typedef struct EnvMap { + struct Object *object; + struct Image *ima; /* type ENV_LOAD */ + struct ImBuf *cube[6]; /* these images are dynamic, not part of the main struct */ + float imat[4][4]; + float obimat[3][3]; + short type, stype; + float clipsta, clipend; + float viewscale; /* viewscale is for planar envmaps to zoom in or out */ + unsigned int notlay; + short cuberes, depth; + int ok, lastframe; + short recalc, lastsize; +} EnvMap; + +typedef struct Tex { + ID id; + + float noisesize, turbul; + float bright, contrast, rfac, gfac, bfac; + float filtersize; + + /* newnoise: musgrave parameters */ + float mg_H, mg_lacunarity, mg_octaves, mg_offset, mg_gain; + + /* newnoise: distorted noise amount, musgrave & voronoi ouput scale */ + float dist_amount, ns_outscale; + + /* newnoise: voronoi nearest neighbour weights, minkovsky exponent, distance metric & color type */ + float vn_w1, vn_w2, vn_w3, vn_w4, vn_mexp; + short vn_distm, vn_coltype; + + short noisedepth, noisetype; + + /* newnoise: noisebasis type for clouds/marble/etc, noisebasis2 only used for distorted noise */ + short noisebasis, noisebasis2; + + short imaflag, flag; + short type, stype; + + float cropxmin, cropymin, cropxmax, cropymax; + short xrepeat, yrepeat; + short extend; + + /* variables disabled, moved to struct iuser */ + short fie_ima; + int len; + int frames, offset, sfra; + + float checkerdist, nabla; + float norfac; + + struct ImageUser iuser; + + struct Ipo *ipo; + struct Image *ima; + struct PluginTex *plugin; + struct ColorBand *coba; + struct EnvMap *env; + struct PreviewImage * preview; + +} Tex; + +/* used for mapping node. note: rot is in degrees */ + +typedef struct TexMapping { + float loc[3], rot[3], size[3]; + int flag; + + float mat[4][4]; + float min[3], max[3]; + struct Object *ob; + +} TexMapping; + +/* texmap->flag */ +#define TEXMAP_CLIP_MIN 1 +#define TEXMAP_CLIP_MAX 2 + + +/* **************** TEX ********************* */ + +/* type */ +#define TEX_CLOUDS 1 +#define TEX_WOOD 2 +#define TEX_MARBLE 3 +#define TEX_MAGIC 4 +#define TEX_BLEND 5 +#define TEX_STUCCI 6 +#define TEX_NOISE 7 +#define TEX_IMAGE 8 +#define TEX_PLUGIN 9 +#define TEX_ENVMAP 10 +#define TEX_MUSGRAVE 11 +#define TEX_VORONOI 12 +#define TEX_DISTNOISE 13 + +/* musgrave stype */ +#define TEX_MFRACTAL 0 +#define TEX_RIDGEDMF 1 +#define TEX_HYBRIDMF 2 +#define TEX_FBM 3 +#define TEX_HTERRAIN 4 + +/* newnoise: noisebasis 1 & 2 */ +#define TEX_BLENDER 0 +#define TEX_STDPERLIN 1 +#define TEX_NEWPERLIN 2 +#define TEX_VORONOI_F1 3 +#define TEX_VORONOI_F2 4 +#define TEX_VORONOI_F3 5 +#define TEX_VORONOI_F4 6 +#define TEX_VORONOI_F2F1 7 +#define TEX_VORONOI_CRACKLE 8 +#define TEX_CELLNOISE 14 + +/* newnoise: Voronoi distance metrics, vn_distm */ +#define TEX_DISTANCE 0 +#define TEX_DISTANCE_SQUARED 1 +#define TEX_MANHATTAN 2 +#define TEX_CHEBYCHEV 3 +#define TEX_MINKOVSKY_HALF 4 +#define TEX_MINKOVSKY_FOUR 5 +#define TEX_MINKOVSKY 6 + +/* imaflag */ +#define TEX_INTERPOL 1 +#define TEX_USEALPHA 2 +#define TEX_MIPMAP 4 +#define TEX_IMAROT 16 +#define TEX_CALCALPHA 32 +#define TEX_NORMALMAP 2048 +#define TEX_GAUSS_MIP 4096 + +/* imaflag unused, only for version check */ +#define TEX_FIELDS_ 8 +#define TEX_ANIMCYCLIC_ 64 +#define TEX_ANIM5_ 128 +#define TEX_ANTIALI_ 256 +#define TEX_ANTISCALE_ 512 +#define TEX_STD_FIELD_ 1024 + +/* flag */ +#define TEX_COLORBAND 1 +#define TEX_FLIPBLEND 2 +#define TEX_NEGALPHA 4 +#define TEX_CHECKER_ODD 8 +#define TEX_CHECKER_EVEN 16 +#define TEX_PRV_ALPHA 32 +#define TEX_PRV_NOR 64 +#define TEX_REPEAT_XMIR 128 +#define TEX_REPEAT_YMIR 256 +#define TEX_FLAG_MASK ( TEX_COLORBAND | TEX_FLIPBLEND | TEX_NEGALPHA | TEX_CHECKER_ODD | TEX_CHECKER_EVEN | TEX_PRV_ALPHA | TEX_PRV_NOR | TEX_REPEAT_XMIR | TEX_REPEAT_YMIR ) + +/* extend (starts with 1 because of backward comp.) */ +#define TEX_EXTEND 1 +#define TEX_CLIP 2 +#define TEX_REPEAT 3 +#define TEX_CLIPCUBE 4 +#define TEX_CHECKER 5 + +/* noisetype */ +#define TEX_NOISESOFT 0 +#define TEX_NOISEPERL 1 + +/* tex->noisebasis2 in texture.c - wood waveforms */ +#define TEX_SIN 0 +#define TEX_SAW 1 +#define TEX_TRI 2 + +/* tex->stype in texture.c - wood types */ +#define TEX_BAND 0 +#define TEX_RING 1 +#define TEX_BANDNOISE 2 +#define TEX_RINGNOISE 3 + +/* tex->stype in texture.c - cloud types */ +#define TEX_DEFAULT 0 +#define TEX_COLOR 1 + +/* tex->stype in texture.c - marble types */ +#define TEX_SOFT 0 +#define TEX_SHARP 1 +#define TEX_SHARPER 2 + +/* tex->stype in texture.c - blend types */ +#define TEX_LIN 0 +#define TEX_QUAD 1 +#define TEX_EASE 2 +#define TEX_DIAG 3 +#define TEX_SPHERE 4 +#define TEX_HALO 5 +#define TEX_RAD 6 + +/* tex->stype in texture.c - stucci types */ +#define TEX_PLASTIC 0 +#define TEX_WALLIN 1 +#define TEX_WALLOUT 2 + +/* tex->stype in texture.c - voronoi types */ +#define TEX_INTENSITY 0 +#define TEX_COL1 1 +#define TEX_COL2 2 +#define TEX_COL3 3 + +/* wrap */ +#define MTEX_FLAT 0 +#define MTEX_CUBE 1 +#define MTEX_TUBE 2 +#define MTEX_SPHERE 3 + +/* return value */ +#define TEX_INT 0 +#define TEX_RGB 1 +#define TEX_NOR 2 + +/* **************** MTEX ********************* */ + +/* proj */ +#define PROJ_N 0 +#define PROJ_X 1 +#define PROJ_Y 2 +#define PROJ_Z 3 + +/* texflag */ +#define MTEX_RGBTOINT 1 +#define MTEX_STENCIL 2 +#define MTEX_NEGATIVE 4 +#define MTEX_ALPHAMIX 8 +#define MTEX_VIEWSPACE 16 + +/* blendtype */ +#define MTEX_BLEND 0 +#define MTEX_MUL 1 +#define MTEX_ADD 2 +#define MTEX_SUB 3 +#define MTEX_DIV 4 +#define MTEX_DARK 5 +#define MTEX_DIFF 6 +#define MTEX_LIGHT 7 +#define MTEX_SCREEN 8 +#define MTEX_OVERLAY 9 + +/* **************** EnvMap ********************* */ + +/* type */ +#define ENV_CUBE 0 +#define ENV_PLANE 1 +#define ENV_SPHERE 2 + +/* stype */ +#define ENV_STATIC 0 +#define ENV_ANIM 1 +#define ENV_LOAD 2 + +/* ok */ +#define ENV_NORMAL 1 +#define ENV_OSA 2 + +#endif + diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h new file mode 100644 index 00000000000..47c00813913 --- /dev/null +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -0,0 +1,288 @@ +/** + * blenkernel/DNA_userdef_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef DNA_USERDEF_TYPES_H +#define DNA_USERDEF_TYPES_H + +#include "DNA_listBase.h" +#include "DNA_texture_types.h" + +/* themes; defines in BIF_resource.h */ +struct ColorBand; + +// global, button colors + +typedef struct ThemeUI { + char outline[4]; + char neutral[4]; + char action[4]; + char setting[4]; + char setting1[4]; + char setting2[4]; + char num[4]; + char textfield[4]; + char textfield_hi[4]; + char popup[4]; + char text[4]; + char text_hi[4]; + char menu_back[4]; + char menu_item[4]; + char menu_hilite[4]; + char menu_text[4]; + char menu_text_hi[4]; + + char but_drawtype; + char pad[3]; + char iconfile[80]; // FILE_MAXFILE length + +} ThemeUI; + +// try to put them all in one, if needed a special struct can be created as well +// for example later on, when we introduce wire colors for ob types or so... +typedef struct ThemeSpace { + char back[4]; + char text[4]; + char text_hi[4]; + char header[4]; + char panel[4]; + + char shade1[4]; + char shade2[4]; + + char hilite[4]; + char grid[4]; + + char wire[4], select[4]; + char lamp[4]; + char active[4], group[4], group_active[4], transform[4]; + char vertex[4], vertex_select[4]; + char edge[4], edge_select[4]; + char edge_seam[4], edge_sharp[4], edge_facesel[4]; + char face[4], face_select[4]; // solid faces + char face_dot[4]; // selected color + char normal[4]; + char bone_solid[4], bone_pose[4]; + char strip[4], strip_select[4]; + + char vertex_size, facedot_size; + char bpad[2]; + + char syntaxl[4], syntaxn[4], syntaxb[4]; // syntax for textwindow and nodes + char syntaxv[4], syntaxc[4]; + + char movie[4], image[4], scene[4], audio[4]; // for sequence editor + char effect[4], plugin[4], transition[4], meta[4]; + char editmesh_active[4]; + +} ThemeSpace; + + +typedef struct bTheme { + struct bTheme *next, *prev; + char name[32]; + + ThemeUI tui; + + ThemeSpace tbuts; + ThemeSpace tv3d; + ThemeSpace tfile; + ThemeSpace tipo; + ThemeSpace tinfo; + ThemeSpace tsnd; + ThemeSpace tact; + ThemeSpace tnla; + ThemeSpace tseq; + ThemeSpace tima; + ThemeSpace timasel; + ThemeSpace text; + ThemeSpace toops; + ThemeSpace ttime; + ThemeSpace tnode; + + unsigned char bpad[4], bpad1[4]; + +} bTheme; + +typedef struct SolidLight { + int flag, pad; + float col[4], spec[4], vec[4]; +} SolidLight; + +typedef struct UserDef { + int flag, dupflag; + int savetime; + char tempdir[160]; // FILE_MAXDIR length + char fontdir[160]; + char renderdir[160]; + char textudir[160]; + char plugtexdir[160]; + char plugseqdir[160]; + char pythondir[160]; + char sounddir[160]; + /* yafray: temporary xml export directory */ + char yfexportdir[160]; + short versions, vrmlflag; // tmp for export, will be replaced by strubi + int gameflags; + int wheellinescroll; + int uiflag, language; + short userpref, viewzoom; + short console_buffer; //console vars here for tuhopuu compat, --phase + short console_out; + int mixbufsize; + int fontsize; + short encoding; + short transopts; + short menuthreshold1, menuthreshold2; + char fontname[256]; // FILE_MAXDIR+FILE length + struct ListBase themes; + short undosteps; + short curssize; + short tb_leftmouse, tb_rightmouse; + struct SolidLight light[3]; + short tw_hotspot, tw_flag, tw_handlesize, tw_size; + int textimeout, texcollectrate; + int memcachelimit; + int prefetchframes; + short frameserverport; + short pad_rot_angle; /*control the rotation step of the view when PAD2,PAD4,PAD6&PAD8 is use*/ + short obcenter_dia; + short rvisize; /* rotating view icon size */ + short rvibright; /* rotating view icon brightness */ + short recent_files; /* maximum number of recently used files to remember */ + short smooth_viewtx; /* miliseconds to spend spinning the view */ + short glreslimit; + char versemaster[160]; + char verseuser[160]; + float glalphaclip, pad; + + struct ColorBand coba_weight; /* from texture.h */ +} UserDef; + +extern UserDef U; /* from usiblender.c !!!! */ + +/* ***************** USERDEF ****************** */ + +/* flag */ +#define USER_AUTOSAVE (1 << 0) +#define USER_AUTOGRABGRID (1 << 1) +#define USER_AUTOROTGRID (1 << 2) +#define USER_AUTOSIZEGRID (1 << 3) +#define USER_SCENEGLOBAL (1 << 4) +#define USER_TRACKBALL (1 << 5) +#define USER_DUPLILINK (1 << 6) +#define USER_FSCOLLUM (1 << 7) +#define USER_MAT_ON_OB (1 << 8) +#define USER_NO_CAPSLOCK (1 << 9) +#define USER_VIEWMOVE (1 << 10) +#define USER_TOOLTIPS (1 << 11) +#define USER_TWOBUTTONMOUSE (1 << 12) +#define USER_NONUMPAD (1 << 13) +#define USER_LMOUSESELECT (1 << 14) +#define USER_FILECOMPRESS (1 << 15) +#define USER_SAVE_PREVIEWS (1 << 16) +#define USER_CUSTOM_RANGE (1 << 17) +#define USER_ADD_EDITMODE (1 << 18) +#define USER_ADD_VIEWALIGNED (1 << 19) + + +/* viewzom */ +#define USER_ZOOM_CONT 0 +#define USER_ZOOM_SCALE 1 +#define USER_ZOOM_DOLLY 2 + +/* uiflag */ + +#define USER_KEYINSERTACT (1 << 0) +#define USER_KEYINSERTOBJ (1 << 1) +#define USER_WHEELZOOMDIR (1 << 2) +#define USER_FILTERFILEEXTS (1 << 3) +#define USER_DRAWVIEWINFO (1 << 4) +#define USER_PLAINMENUS (1 << 5) // old EVTTOCONSOLE print ghost events, here for tuhopuu compat. --phase + // old flag for hide pulldown was here +#define USER_FLIPFULLSCREEN (1 << 7) +#define USER_ALLWINCODECS (1 << 8) +#define USER_MENUOPENAUTO (1 << 9) +#define USER_PANELPINNED (1 << 10) +#define USER_AUTOPERSP (1 << 11) +#define USER_LOCKAROUND (1 << 12) +#define USER_GLOBALUNDO (1 << 13) +#define USER_ORBIT_SELECTION (1 << 14) +#define USER_KEYINSERTAVAI (1 << 15) +#define USER_HIDE_DOT (1 << 16) +#define USER_SHOW_ROTVIEWICON (1 << 17) +#define USER_SHOW_VIEWPORTNAME (1 << 18) +#define USER_KEYINSERTNEED (1 << 19) +#define USER_ZOOM_TO_MOUSEPOS (1 << 20) + +/* transopts */ + +#define USER_TR_TOOLTIPS (1 << 0) +#define USER_TR_BUTTONS (1 << 1) +#define USER_TR_MENUS (1 << 2) +#define USER_TR_FILESELECT (1 << 3) +#define USER_TR_TEXTEDIT (1 << 4) +#define USER_DOTRANSLATE (1 << 5) +#define USER_USETEXTUREFONT (1 << 6) +#define CONVERT_TO_UTF8 (1 << 7) + +/* dupflag */ + +#define USER_DUP_MESH (1 << 0) +#define USER_DUP_CURVE (1 << 1) +#define USER_DUP_SURF (1 << 2) +#define USER_DUP_FONT (1 << 3) +#define USER_DUP_MBALL (1 << 4) +#define USER_DUP_LAMP (1 << 5) +#define USER_DUP_IPO (1 << 6) +#define USER_DUP_MAT (1 << 7) +#define USER_DUP_TEX (1 << 8) +#define USER_DUP_ARM (1 << 9) +#define USER_DUP_ACT (1 << 10) + +/* gameflags */ + +#define USER_VERTEX_ARRAYS 1 +#define USER_DISABLE_SOUND 2 +#define USER_DISABLE_MIPMAP 4 + +/* vrml flag */ + +#define USER_VRML_LAYERS 1 +#define USER_VRML_AUTOSCALE 2 +#define USER_VRML_TWOSIDED 4 + +/* tw_flag (transform widget) */ + + +#endif diff --git a/source/blender/makesdna/DNA_vec_types.h b/source/blender/makesdna/DNA_vec_types.h new file mode 100644 index 00000000000..9ae72b1c641 --- /dev/null +++ b/source/blender/makesdna/DNA_vec_types.h @@ -0,0 +1,91 @@ +/** + * vec_types.h dec 2000 Nzc + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + */ + +#ifndef DNA_VEC_TYPES_H +#define DNA_VEC_TYPES_H + +/* types */ +typedef struct vec2s { + short x, y; +} vec2s; + +typedef struct vec2i { + int x, y; +} vec2i; + +typedef struct vec2f { + float x, y; +} vec2f; + +typedef struct vec2d { + double x, y; +} vec2d; + +typedef struct vec3i { + int x, y, z; +} vec3i; + +typedef struct vec3f { + float x, y, z; +} vec3f; + +typedef struct vec3d { + double x, y, z; +} vec3d; + +typedef struct vec4i { + int x, y, z, w; +} vec4i; + +typedef struct vec4f { + float x, y, z, w; +} vec4f; + +typedef struct vec4d { + double x, y, z, w; +} vec4d; + +typedef struct rcti { + int xmin, xmax; + int ymin, ymax; +} rcti; + +typedef struct rctf { + float xmin, xmax; + float ymin, ymax; +} rctf; + +#endif + diff --git a/source/blender/makesdna/DNA_vfont_types.h b/source/blender/makesdna/DNA_vfont_types.h new file mode 100644 index 00000000000..df9279d6243 --- /dev/null +++ b/source/blender/makesdna/DNA_vfont_types.h @@ -0,0 +1,63 @@ +/** + * blenlib/DNA_vfont_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_VFONT_TYPES_H +#define DNA_VFONT_TYPES_H + +#include "DNA_ID.h" + +struct PackedFile; +struct VFontData; + +typedef struct VFont { + ID id; + + char name[256]; + float scale, pad; + + struct VFontData *data; + struct PackedFile * packedfile; +} VFont; + +/* *************** FONT ****************** */ + +#define FO_CURS 1 +#define FO_CURSUP 2 +#define FO_CURSDOWN 3 +#define FO_DUPLI 4 +#define FO_PAGEUP 8 +#define FO_PAGEDOWN 9 +#define FO_SELCHANGE 10 + +#endif + diff --git a/source/blender/makesdna/DNA_view2d_types.h b/source/blender/makesdna/DNA_view2d_types.h new file mode 100644 index 00000000000..3ed82ddc793 --- /dev/null +++ b/source/blender/makesdna/DNA_view2d_types.h @@ -0,0 +1,67 @@ +/** + * blenlib/DNA_view2d_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_VIEW2D_TYPES_H +#define DNA_VIEW2D_TYPES_H + +#include "DNA_vec_types.h" + +typedef struct View2D { + rctf tot, cur; + rcti vert, hor, mask; + float min[2], max[2]; + float minzoom, maxzoom; + short scroll, keeptot; + short keepaspect, keepzoom; + short oldwinx, oldwiny; + int flag; + + float cursor[2]; /* only used in the UV view for now*/ + short around; + char pad[6]; +} View2D; + +/* v2d->keepzoom */ +#define V2D_KEEPZOOM 0x0001 +#define V2D_LOCKZOOM_X 0x0100 +#define V2D_LOCKZOOM_Y 0x0200 + +/* event codes for locking function */ +#define V2D_LOCK_COPY 1 +#define V2D_LOCK_REDRAW 2 + +/* v2d->flag */ +#define V2D_VIEWLOCK 1 + +#endif + diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h new file mode 100644 index 00000000000..ee75d7b8f0f --- /dev/null +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -0,0 +1,212 @@ +/** + * blenlib/DNA_view3d_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_VIEW3D_TYPES_H +#define DNA_VIEW3D_TYPES_H + +struct ViewDepths; +struct Object; +struct Image; +struct Tex; +struct SpaceLink; +struct Base; +struct BoundBox; +struct RenderInfo; +struct RetopoViewData; + +/* This is needed to not let VC choke on near and far... old + * proprietary MS extensions... */ +#ifdef WIN32 +#undef near +#undef far +#define near clipsta +#define far clipend +#endif + +#include "DNA_listBase.h" +#include "DNA_image_types.h" + +/* The near/far thing is a Win EXCEPTION. Thus, leave near/far in the + * code, and patch for windows. */ + +typedef struct BGpic { + struct Image *ima; + struct ImageUser iuser; + float xof, yof, size, zoom, blend; + short xim, yim; +} BGpic; + +typedef struct View3D { + struct SpaceLink *next, *prev; + int spacetype; + float blockscale; + struct ScrArea *area; + + short blockhandler[8]; + + float viewmat[4][4]; + float viewinv[4][4]; + float persmat[4][4]; + float persinv[4][4]; + + float winmat1[4][4]; // persp(1) storage, for swap matrices + float viewmat1[4][4]; + + float viewquat[4], dist, zfac, pad0; /* zfac is initgrabz() result */ + + /** + * 0 - ortho + * 1 - do 3d perspective + * 2 - use the camera + */ + short persp; + short view; + + struct Object *camera, *ob_centre; + struct BGpic *bgpic; + struct View3D *localvd; + struct RenderInfo *ri; + struct RetopoViewData *retopo_view_data; + struct ViewDepths *depths; + + char ob_centre_bone[32]; /* optional string for armature bone to define center */ + + /** + * The drawing mode for the 3d display. Set to OB_WIRE, OB_SOLID, + * OB_SHADED or OB_TEXTURED */ + short drawtype; + short localview; + int lay, layact; + short scenelock, around, camzoom; + + char pivot_last, pad1; /* pivot_last is for rotating around the last edited element */ + + float lens, grid, gridview, pixsize, near, far; + float camdx, camdy; /* camera view offsets, 1.0 = viewplane moves entire width/height */ + float ofs[3], cursor[3]; + + short gridlines, viewbut; + short gridflag; + short modeselect, menunr, texnr; + + /* transform widget info */ + short twtype, twmode, twflag, twdrawflag; + float twmat[4][4]; + + /* user defined clipping planes */ + float clip[4][4]; + + struct BoundBox *clipbb; + + /* afterdraw, for xray & transparent */ + struct ListBase afterdraw; + /* drawflags, denoting state */ + short zbuf, transp, xray; + + short flag, flag2; + + short gridsubdiv; /* Number of subdivisions in the grid between each highlighted grid line */ + + short pad3; + + short pad2; + + void *properties_storage; /* Nkey panel stores stuff here, not in file */ + +} View3D; + +/* View3D->flag (short) */ +#define V3D_MODE (16+32+64+128+256+512) +#define V3D_DISPIMAGE 1 +#define V3D_DISPBGPIC 2 +#define V3D_HIDE_HELPLINES 4 +#define V3D_NEEDBACKBUFDRAW 8 +#define V3D_EDITMODE 16 +#define V3D_VERTEXPAINT 32 +#define V3D_FACESELECT 64 +#define V3D_POSEMODE 128 +#define V3D_TEXTUREPAINT 256 +#define V3D_WEIGHTPAINT 512 +#define V3D_ALIGN 1024 +#define V3D_SELECT_OUTLINE 2048 +#define V3D_ZBUF_SELECT 4096 +#define V3D_GLOBAL_STATS 8192 +#define V3D_CLIPPING 16384 +#define V3D_DRAW_CENTERS 32768 + + +/* View3d->flag2 (short) */ +#define V3D_OPP_DIRECTION_NAME 1 +#define V3D_FLYMODE 2 +#define V3D_DEPRECATED 4 /* V3D_TRANSFORM_SNAP, moved to a scene setting */ +#define V3D_SOLID_TEX 8 + +/* View3D->around */ +#define V3D_CENTER 0 +#define V3D_CENTROID 3 +#define V3D_CURSOR 1 +#define V3D_LOCAL 2 +#define V3D_ACTIVE 4 + + +/* View3d->persp */ +#define V3D_PERSP_ORTHO 0 +#define V3D_PERSP_DO_3D_PERSP 1 +#define V3D_PERSP_USE_THE_CAMERA 2 + +/* View3d->gridflag */ +#define V3D_SHOW_FLOOR 1 +#define V3D_SHOW_X 2 +#define V3D_SHOW_Y 4 +#define V3D_SHOW_Z 8 + +/* View3d->twtype (bits, we can combine them) */ +#define V3D_MANIP_TRANSLATE 1 +#define V3D_MANIP_ROTATE 2 +#define V3D_MANIP_SCALE 4 + +/* View3d->twmode */ +#define V3D_MANIP_GLOBAL 0 +#define V3D_MANIP_LOCAL 1 +#define V3D_MANIP_NORMAL 2 +#define V3D_MANIP_VIEW 3 + +/* View3d->twflag */ + /* USE = user setting, DRAW = based on selection */ +#define V3D_USE_MANIPULATOR 1 +#define V3D_DRAW_MANIPULATOR 2 +#define V3D_CALC_MANIPULATOR 4 + + +#endif + diff --git a/source/blender/makesdna/DNA_wave_types.h b/source/blender/makesdna/DNA_wave_types.h new file mode 100644 index 00000000000..f499004fff8 --- /dev/null +++ b/source/blender/makesdna/DNA_wave_types.h @@ -0,0 +1,53 @@ +/** + * blenlib/DNA_wave_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_WAVE_TYPES_H +#define DNA_WAVE_TYPES_H + +#include "DNA_ID.h" + +struct Ipo; + + +/* a Wave has never been implemented... it was meant as a 'free' mathematical + deformation object type (ton) */ + +typedef struct Wave { + ID id; + + struct Ipo *ipo; + +} Wave; + +#endif + diff --git a/source/blender/makesdna/DNA_world_types.h b/source/blender/makesdna/DNA_world_types.h new file mode 100644 index 00000000000..9e5ec4cdb9a --- /dev/null +++ b/source/blender/makesdna/DNA_world_types.h @@ -0,0 +1,181 @@ +/** + * blenlib/DNA_world_types.h (mar-2001 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_WORLD_TYPES_H +#define DNA_WORLD_TYPES_H + +#include "DNA_ID.h" +#include "DNA_scriptlink_types.h" + +struct Ipo; +struct MTex; + +#ifndef MAX_MTEX +#define MAX_MTEX 10 +#endif + + +/** + * World defines general modeling data such as a background fill, + * gravity, color model, stars, etc. It mixes game-data, rendering + * data and modeling data. */ +typedef struct World { + ID id; + + short colormodel, totex; + short texact, mistype; + + /* TODO - hork, zenk and ambk are not used, should remove at some point (Campbell) */ + float horr, horg, horb, hork; + float zenr, zeng, zenb, zenk; + float ambr, ambg, ambb, ambk; + + unsigned int fastcol; + + /** + * Exposure= mult factor. unused now, but maybe back later. Kept in to be upward compat. + * New is exp/range control. linfac & logfac are constants... don't belong in + * file, but allocating 8 bytes for temp mem isnt useful either. + */ + float exposure, exp, range; + float linfac, logfac; + + /** + * Gravitation constant for the game world + */ + float gravity; + + /** + * Radius of the activity bubble, in Manhattan length. Objects + * outside the box are activity-culled. */ + float activityBoxRadius; + + short skytype; + /** + * Some world modes + * bit 0: Do mist + * bit 1: Do stars + * bit 2: (reserved) depth of field + * bit 3: (gameengine): Activity culling is enabled. + */ + short mode; + int physicsEngine; /* here it's aligned */ + + float misi, miststa, mistdist, misthi; + + float starr, starg, starb, stark; + float starsize, starmindist; + float stardist, starcolnoise; + + /* unused now: DOF */ + short dofsta, dofend, dofmin, dofmax; + + /* ambient occlusion */ + float aodist, aodistfac, aoenergy, aobias; + short aomode, aosamp, aomix, aocolor; + float ao_adapt_thresh, ao_adapt_speed_fac; + float pad2[2]; + short ao_samp_method; + short pad1[3]; + + float *aosphere, *aotables; + + + struct Ipo *ipo; + struct MTex *mtex[10]; + + /* previews */ + struct PreviewImage *preview; + + ScriptLink scriptlink; + +} World; + +/* **************** WORLD ********************* */ + +/* skytype */ +#define WO_SKYBLEND 1 +#define WO_SKYREAL 2 +#define WO_SKYPAPER 4 +/* while render: */ +#define WO_SKYTEX 8 +#define WO_ZENUP 16 + +/* mode */ +#define WO_MIST 1 +#define WO_STARS 2 +#define WO_DOF 4 +#define WO_ACTIVITY_CULLING 8 +#define WO_AMB_OCC 16 + +/* aomix */ +#define WO_AOADD 0 +#define WO_AOSUB 1 +#define WO_AOADDSUB 2 + +/* ao_samp_method - methods for sampling the AO hemi */ +#define WO_AOSAMP_CONSTANT 0 +#define WO_AOSAMP_HALTON 1 +#define WO_AOSAMP_HAMMERSLEY 2 + +/* aomode (use distances & random sampling modes) */ +#define WO_AODIST 1 +#define WO_AORNDSMP 2 + +/* aocolor */ +#define WO_AOPLAIN 0 +#define WO_AOSKYCOL 1 +#define WO_AOSKYTEX 2 + +/* texco (also in DNA_material_types.h) */ +#define TEXCO_ANGMAP 64 +#define TEXCO_H_SPHEREMAP 256 +#define TEXCO_H_TUBEMAP 1024 + +/* mapto */ +#define WOMAP_BLEND 1 +#define WOMAP_HORIZ 2 +#define WOMAP_ZENUP 4 +#define WOMAP_ZENDOWN 8 +#define WOMAP_MIST 16 + +/* physicsEngine */ +#define WOPHY_NONE 0 +#define WOPHY_ENJI 1 +#define WOPHY_SUMO 2 +#define WOPHY_DYNAMO 3 +#define WOPHY_ODE 4 +#define WOPHY_BULLET 5 + +#endif + diff --git a/source/blender/makesdna/Makefile b/source/blender/makesdna/Makefile new file mode 100644 index 00000000000..f8274102b8c --- /dev/null +++ b/source/blender/makesdna/Makefile @@ -0,0 +1,42 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# +# This module does not build normal .o's, but a DNA.c file, to be +# compiled with the rest of the sources. To speed things up a little, +# the compilation is done here. +# +# Bounces make to subdirectories. + +SOURCEDIR = source/blender/makesdna +DIRS = intern + +include nan_subdirs.mk diff --git a/source/blender/makesdna/SConscript b/source/blender/makesdna/SConscript new file mode 100644 index 00000000000..d67be4955c4 --- /dev/null +++ b/source/blender/makesdna/SConscript @@ -0,0 +1,11 @@ +#!/usr/bin/python +Import ('env') + +objs = [] + +o = SConscript('intern/SConscript') +objs.append (o) + +incs = '#/intern/guardedalloc' + +env.BlenderLib ( 'bf_dna', objs, Split(incs), [], libtype=['common','player'], priority = [10, 215] ) diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt new file mode 100644 index 00000000000..58aa4b3cd21 --- /dev/null +++ b/source/blender/makesdna/intern/CMakeLists.txt @@ -0,0 +1,37 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(SRC makesdna.c ../../../../intern/guardedalloc/intern/mallocn.c) + +INCLUDE_DIRECTORIES(../../../../intern/guardedalloc ..) + +FILE(GLOB INC_FILES ../*.h) +ADD_EXECUTABLE(makesdna ${SRC} ${INC_FILES}) + +MESSAGE(STATUS "Configuring makesdna") diff --git a/source/blender/makesdna/intern/Makefile b/source/blender/makesdna/intern/Makefile new file mode 100644 index 00000000000..bd498961e7a --- /dev/null +++ b/source/blender/makesdna/intern/Makefile @@ -0,0 +1,86 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +DIR = $(OCGDIR)/blender/makesdna +CSRCS = $(wildcard *.c) + +ALLTARGETS = $(OBJS) $(DIR)/$(DEBUG_DIR)makesdna $(DIR)/$(SHARED_DIR)$(DEBUG_DIR)DNA.o + +include nan_compile.mk + +CFLAGS += $(LEVEL_1_C_WARNINGS) + +CPPFLAGS += -I$(OPENGL_HEADERS) +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include +CPPFLAGS += -I../../blenlib +CPPFLAGS += -I.. + +ifeq ($(OS),windows) + # Windows needs these extra libs because of winstuff... It is not + # _really_ needed, but it is the easiest fix for now. If you have + # some spare time, try to trace down the exact dep. Then again, you + # could also spend that time making the sdna system more robust. + ifneq ($(FREE_WINDOWS),true) + WINLIBS = kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib + WINLIBS += advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib + WINLIBS += winmm.lib opengl32.lib glu32.lib largeint.lib + WINLIBS += /link /nodefaultlib:libc + else + LDFLAGS += -mwindows -mno-cygwin + endif +endif + +clean:: + @$(RM) $(DIR)/makesdna* $(DIR)/DNA.c + @$(RM) $(DIR)/debug/makesdna* $(DIR)/debug/DNA.c + +# TODO include right .mk for ldflags + +# A small note: we do not use the debug version of the alloc lib. That +# is done quite intentionally. If there is a bug in that lib, it needs +# to be fixed by the module maintainer. +$(DIR)/$(DEBUG_DIR)makesdna: $(OBJS) $(OCGDIR)/blender/blenlib/$(DEBUG_DIR)libblenlib.a + $(CC) $(LDFLAGS) -o $@ $(OBJS) \ + $(NAN_GUARDEDALLOC)/lib/libguardedalloc.a $(WINLIBS) + +$(DIR)/$(DEBUG_DIR)DNA.c: $(DIR)/$(DEBUG_DIR)makesdna + ifeq ($(OS),windows) + $(SRCHOME)/tools/cygwin/cl_wrapper.pl - $(DIR)/$(DEBUG_DIR)makesdna \ + $(DIR)/$(DEBUG_DIR)DNA.c + else + $(DIR)/$(DEBUG_DIR)makesdna $(DIR)/$(DEBUG_DIR)DNA.c + endif + +$(DIR)/$(SHARED_DIR)$(DEBUG_DIR)DNA.o: $(DIR)/$(DEBUG_DIR)DNA.c + $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@ + diff --git a/source/blender/makesdna/intern/SConscript b/source/blender/makesdna/intern/SConscript new file mode 100644 index 00000000000..fe712afbeeb --- /dev/null +++ b/source/blender/makesdna/intern/SConscript @@ -0,0 +1,41 @@ +#!/usr/bin/python +import sys +import os + +Import ('env') +cflags = '' +defines = [] +root_build_dir=env['BF_BUILDDIR'] + +source_files = ['makesdna.c'] + +makesdna_tool = env.Copy() +dna = env.Copy() +makesdna_tool.Append(CCFLAGS = '-DBASE_HEADER="\\"source/blender/makesdna/\\"" ') + +makesdna_tool.Append (CPPPATH = ['#/intern/guardedalloc', + '../../makesdna']) + +if env['OURPLATFORM'] == 'linuxcross': + makesdna_tool.Replace(CC='gcc') + makesdna_tool.Replace(AR='ar') + makesdna_tool.Replace(LINK='gcc') + +if sys.platform != 'cygwin': + makesdna_tool.Append (CCFLAGS = cflags) +makesdna_tool.Append (CPPDEFINES = defines) +makesdna_tool.Append (LIBPATH = '#'+root_build_dir+'/lib') + +if env['OURPLATFORM'] == 'linux2' and root_build_dir[0]==os.sep: + makesdna = makesdna_tool.Program (target = root_build_dir+'/makesdna', source = source_files, LIBS=['bf_guardedalloc']) +else: + makesdna = makesdna_tool.Program (target = '#'+root_build_dir+'/makesdna', source = source_files, LIBS=['bf_guardedalloc']) + +dna_dict = dna.Dictionary() +dna.Depends ('dna.c', makesdna) +if env['OURPLATFORM'] != 'linuxcross': + dna.Command ('dna.c', '', root_build_dir+os.sep+"makesdna $TARGET") +else: + dna.Command ('dna.c', '', root_build_dir+os.sep+"makesdna.exe $TARGET") +obj = 'intern/dna.c' +Return ('obj') diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c new file mode 100644 index 00000000000..af41380d5f8 --- /dev/null +++ b/source/blender/makesdna/intern/makesdna.c @@ -0,0 +1,1149 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + * Struct muncher for making SDNA + * + * Originally by Ton, some mods by Frank, and some cleaning and + * extension by Nzc. + * + * Makesdna creates a .c file with a long string of numbers that + * encode the Blender file format. It is fast, because it is basically + * a binary dump. There are some details to mind when reconstructing + * the file (endianness and byte-alignment). + * + * This little program scans all structs that need to be serialized, + * and determined the names and types of all members. It calculates + * how much memory (on disk or in ram) is needed to store that struct, + * and the offsets for reaching a particular one. + * + * There is a facility to get verbose output from sdna. Search for + * debugSDNA. This int can be set to 0 (no output) to some int. Higher + * numbers give more output. + * */ + +#define DNA_VERSION_DATE "$Id$" + +#include +#include +#include + +#include "MEM_guardedalloc.h" +#include "DNA_sdna_types.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define SDNA_MAX_FILENAME_LENGTH 255 + + +/* Included the path relative from /source/blender/ here, so we can move */ +/* headers around with more freedom. */ +char *includefiles[] = { + + // if you add files here, please add them at the end + // of makesdna.c (this file) as well + + "DNA_listBase.h", + "DNA_vec_types.h", + "DNA_ID.h", + "DNA_ipo_types.h", + "DNA_key_types.h", + "DNA_scriptlink_types.h", + "DNA_text_types.h", + "DNA_packedFile_types.h", + "DNA_camera_types.h", + "DNA_image_types.h", + "DNA_texture_types.h", + "DNA_lamp_types.h", + "DNA_wave_types.h", + "DNA_material_types.h", + "DNA_vfont_types.h", + // if you add files here, please add them at the end + // of makesdna.c (this file) as well + "DNA_meta_types.h", + "DNA_curve_types.h", + "DNA_mesh_types.h", + "DNA_meshdata_types.h", + "DNA_modifier_types.h", + "DNA_lattice_types.h", + "DNA_object_types.h", + "DNA_object_force.h", + "DNA_object_fluidsim.h", + "DNA_world_types.h", + "DNA_radio_types.h", + "DNA_scene_types.h", + "DNA_view3d_types.h", + "DNA_view2d_types.h", + "DNA_space_types.h", + "DNA_userdef_types.h", + "DNA_screen_types.h", + "DNA_sdna_types.h", + // if you add files here, please add them at the end + // of makesdna.c (this file) as well + "DNA_fileglobal_types.h", + "DNA_sequence_types.h", + "DNA_effect_types.h", + "DNA_oops_types.h", + "DNA_property_types.h", + "DNA_sensor_types.h", + "DNA_controller_types.h", + "DNA_actuator_types.h", + "DNA_sound_types.h", + "DNA_group_types.h", + "DNA_armature_types.h", + "DNA_action_types.h", + "DNA_constraint_types.h", + "DNA_nla_types.h", + "DNA_node_types.h", + "DNA_color_types.h", + "DNA_brush_types.h", + "DNA_customdata_types.h", + // if you add files here, please add them at the end + // of makesdna.c (this file) as well + + // empty string to indicate end of includefiles + "" +}; + +int maxdata= 500000, maxnr= 50000; +int nr_names=0; +int nr_types=0; +int nr_structs=0; +char **names, *namedata; /* at adress names[a] is string a */ +char **types, *typedata; /* at adress types[a] is string a */ +short *typelens; /* at typelens[a] is de length of type a */ +short *alphalens; /* contains sizes as they are calculated on the DEC Alpha (64 bits) */ +short **structs, *structdata; /* at sp= structs[a] is the first adress of a struct definition + sp[0] is type number + sp[1] is amount of elements + sp[2] sp[3] is typenr, namenr (etc) */ +/* + * debugSDNA: + * - 0 = no output, except errors + * - 1 = detail actions + * - 2 = full trace, tell which names and types were found + * - 4 = full trace, plus all gritty details + */ +int debugSDNA = 0; +int additional_slen_offset; + +/* ************************************************************************** */ +/* Functions */ +/* ************************************************************************** */ + +/** + * Add type to struct indexed by , if it was not yet found. + */ +int add_type(char *str, int len); + +/** + * Add variable to + */ +int add_name(char *str); + +/** + * Search whether this structure type was already found, and if not, + * add it. + */ +short *add_struct(int namecode); + +/** + * Remove comments from this buffer. Assumes that the buffer refers to + * ascii-code text. + */ +int preprocess_include(char *maindata, int len); + +/** + * Scan this file for serializable types. + */ +int convert_include(char *filename); + +/** + * Determine how many bytes are needed for an array. + */ +int arraysize(char *astr, int len); + +/** + * Determine how many bytes are needed for each struct. + */ +static int calculate_structlens(int); + +/** + * Construct the DNA.c file + */ +void dna_write(FILE *file, void *pntr, int size); + +/** + * Report all structures found so far, and print their lenghts. + */ +void printStructLenghts(void); + + + +/* ************************************************************************** */ +/* Implementation */ +/* ************************************************************************** */ + +/* ************************* MAKEN DNA ********************** */ + +int add_type(char *str, int len) +{ + int nr; + char *cp; + + if(str[0]==0) return -1; + + /* search through type array */ + for(nr=0; nr=maxnr) { + printf("too many types\n"); + return nr_types-1;; + } + nr_types++; + + return nr_types-1; +} + + +/** + * + * Because of the weird way of tokenizing, we have to 'cast' function + * pointers to ... (*f)(), whatever the original signature. In fact, + * we add name and type at the same time... There are two special + * cases, unfortunately. These are explicitly checked. + * + * */ +int add_name(char *str) +{ + int nr, i, j, k; + char *cp; + char buf[255]; /* stupid limit, change it :) */ + char *name; + + additional_slen_offset = 0; + + if((str[0]==0) /* || (str[1]==0) */) return -1; + + if (str[0] == '(' && str[1] == '*') { + if (debugSDNA > 3) printf("\t\t\t\t*** Function pointer found\n"); + /* functionpointer: transform the type (sometimes) */ + i = 0; + j = 0; + + while (str[i] != ')') { + buf[i] = str[i]; + i++; + } + + /* Another number we need is the extra slen offset. This extra + * offset is the overshoot after a space. If there is no + * space, no overshoot should be calculated. */ + j = i; /* j at first closing brace */ + + if (debugSDNA > 3) printf("first brace after offset %d\n", i); + + j++; /* j beyond closing brace ? */ + while ((str[j] != 0) && (str[j] != ')' )) { + if (debugSDNA > 3) printf("seen %c ( %d) \n", str[j], str[j]); + j++; + } + if (debugSDNA > 3) printf("seen %c ( %d) \n", str[j], str[j]); + if (debugSDNA > 3) printf("special after offset %d\n", j); + + if (str[j] == 0 ) { + if (debugSDNA > 3) printf("offsetting for space\n"); + /* get additional offset */ + k = 0; + while (str[j] != ')') { + j++; + k++; + } + if (debugSDNA > 3) printf("extra offset %d\n", k); + additional_slen_offset = k; + } else if (str[j] == ')' ) { + if (debugSDNA > 3) printf("offsetting for brace\n"); + ; /* don't get extra offset */ + } else { + printf("Error during tokening function pointer argument list\n"); + } + + /* + * Put )(void) at the end? Maybe )(). Should check this with + * old sdna. Actually, sometimes )(), sometimes )(void...) + * Alas.. such is the nature of braindamage :( + * + * Sorted it out: always do )(), except for headdraw and + * windraw, part of ScrArea. This is important, because some + * linkers will treat different fp's differently when called + * !!! This has to do with interference in byte-alignment and + * the way args are pushed on the stack. + * + * */ + buf[i] = 0; + if (debugSDNA > 3) printf("Name before chomping: %s\n", buf); + if ( (strncmp(buf,"(*headdraw", 10) == 0) + || (strncmp(buf,"(*windraw", 9) == 0) ) { + buf[i] = ')'; + buf[i+1] = '('; + buf[i+2] = 'v'; + buf[i+3] = 'o'; + buf[i+4] = 'i'; + buf[i+5] = 'd'; + buf[i+6] = ')'; + buf[i+7] = 0; + } else { + buf[i] = ')'; + buf[i+1] = '('; + buf[i+2] = ')'; + buf[i+3] = 0; + } + /* now precede with buf*/ + if (debugSDNA > 3) printf("\t\t\t\t\tProposing fp name %s\n", buf); + name = buf; + } else { + /* normal field: old code */ + name = str; + } + + /* search name array */ + for(nr=0; nr=maxnr) { + printf("too many names\n"); + return nr_names-1; + } + nr_names++; + + return nr_names-1; +} + +short *add_struct(int namecode) +{ + int len; + short *sp; + + if(nr_structs==0) { + structs[0]= structdata; + } + else { + sp= structs[nr_structs-1]; + len= sp[1]; + structs[nr_structs]= sp+ 2*len+2; + } + + sp= structs[nr_structs]; + sp[0]= namecode; + + if(nr_structs>=maxnr) { + printf("too many structs\n"); + return sp; + } + nr_structs++; + + return sp; +} + +int preprocess_include(char *maindata, int len) +{ + int a, newlen, comment = 0; + char *cp, *temp, *md; + + temp= MEM_mallocN(len, "preprocess_include"); + memcpy(temp, maindata, len); + + // remove all c++ comments + /* replace all enters/tabs/etc with spaces */ + cp= temp; + a= len; + comment = 0; + while(a--) { + if(cp[0]=='/' && cp[1]=='/') { + comment = 1; + } else if (*cp<32) { + comment = 0; + } + if (comment || *cp<32 || *cp>128 ) *cp= 32; + cp++; + } + + + /* data from temp copy to maindata, remove comments and double spaces */ + cp= temp; + md= maindata; + newlen= 0; + comment= 0; + a= len; + while(a--) { + + if(cp[0]=='/' && cp[1]=='*') { + comment= 1; + cp[0]=cp[1]= 32; + } + if(cp[0]=='*' && cp[1]=='/') { + comment= 0; + cp[0]=cp[1]= 32; + } + + /* do not copy when: */ + if(comment); + else if( cp[0]==' ' && cp[1]==' ' ); + else if( cp[-1]=='*' && cp[0]==' ' ); /* pointers with a space */ + else { + md[0]= cp[0]; + md++; + newlen++; + } + cp++; + } + + MEM_freeN(temp); + return newlen; +} + +static void *read_file_data(char *filename, int *len_r) +{ +#ifdef WIN32 + FILE *fp= fopen(filename, "rb"); +#else + FILE *fp= fopen(filename, "r"); +#endif + void *data; + + if (!fp) { + *len_r= -1; + return NULL; + } + + fseek(fp, 0L, SEEK_END); + *len_r= ftell(fp); + fseek(fp, 0L, SEEK_SET); + + data= MEM_mallocN(*len_r, "read_file_data"); + if (!data) { + *len_r= -1; + return NULL; + } + + if (fread(data, *len_r, 1, fp)!=1) { + *len_r= -1; + MEM_freeN(data); + return NULL; + } + + return data; +} + +int convert_include(char *filename) +{ + /* read include file, skip structs with a '#' before it. + store all data in temporal arrays. + */ + int filelen, count, overslaan, slen, type, name, strct; + short *structpoin, *sp; + char *maindata, *mainend, *md, *md1; + + md= maindata= read_file_data(filename, &filelen); + if (filelen==-1) { + printf("Can't read file %s\n", filename); + return 1; + } + + filelen= preprocess_include(maindata, filelen); + mainend= maindata+filelen-1; + + /* we look for '{' and then back to 'struct' */ + count= 0; + overslaan= 0; + while(count 1) printf("\t|\t|-- detected struct %s\n", types[strct]); + + /* first lets make it all nice strings */ + md1= md+1; + while(*md1 != '}') { + if(md1>mainend) break; + + if(*md1==',' || *md1==' ') *md1= 0; + md1++; + } + + /* read types and names until first character that is not '}' */ + md1= md+1; + while( *md1 != '}' ) { + if(md1>mainend) break; + + /* skip when it says 'struct' or 'unsigned' */ + if(*md1) { + if( strncmp(md1, "struct", 6)==0 ) md1+= 7; + if( strncmp(md1, "unsigned", 6)==0 ) md1+= 9; + + /* we've got a type! */ + type= add_type(md1, 0); + + if (debugSDNA > 1) printf("\t|\t|\tfound type %s (", md1); + + md1+= strlen(md1); + + + /* read until ';' */ + while( *md1 != ';' ) { + if(md1>mainend) break; + + if(*md1) { + /* We've got a name. slen needs + * correction for function + * pointers! */ + slen= (int) strlen(md1); + if( md1[slen-1]==';' ) { + md1[slen-1]= 0; + + + name= add_name(md1); + slen += additional_slen_offset; + sp[0]= type; + sp[1]= name; + + if ((debugSDNA>1) && (names[name] != 0 )) printf("%s |", names[name]); + + structpoin[1]++; + sp+= 2; + + md1+= slen; + break; + } + + + name= add_name(md1); + slen += additional_slen_offset; + + sp[0]= type; + sp[1]= name; + if ((debugSDNA > 1) && (names[name] != 0 )) printf("%s ||", names[name]); + + structpoin[1]++; + sp+= 2; + + md1+= slen; + } + md1++; + } + + if (debugSDNA > 1) printf(")\n"); + + } + md1++; + } + } + } + } + count++; + md++; + } + + MEM_freeN(maindata); + + return 0; +} + +int arraysize(char *astr, int len) +{ + int a, mul=1; + char str[100], *cp=0; + + memcpy(str, astr, len+1); + + for(a=0; a= firststruct) { + if(sizeof(void *)==8 && (len % 8) ) { + printf("Align struct error: %s %s\n", types[structtype],cp); + dna_error = 1; + } + } + + /* 2-4 aligned/ */ + if(typelens[type]>3 && (len % 4) ) { + printf("Align 4 error in struct: %s %s (add %d padding bytes)\n", types[structtype], cp, len%4); + dna_error = 1; + } + else if(typelens[type]==2 && (len % 2) ) { + printf("Align 2 error in struct: %s %s (add %d padding bytes)\n", types[structtype], cp, len%2); + dna_error = 1; + } + + len += mul*typelens[type]; + alphalen += mul * alphalens[type]; + + } else { + len= 0; + alphalen = 0; + break; + } + } + + if (len==0) { + unknown++; + } else { + typelens[structtype]= len; + alphalens[structtype]= alphalen; + // two ways to detect if a struct contains a pointer: + // has_pointer is set or alphalen != len + if (has_pointer || alphalen != len) { + if (alphalen % 8) { + printf("Sizeerror in struct: %s (add %d bytes)\n", types[structtype], alphalen%8); + dna_error = 1; + } + } + + if(len % 4) { + printf("Sizeerror in struct: %s (add %d bytes)\n", types[structtype], len%4); + dna_error = 1; + } + + } + } + } + + if(unknown==lastunknown) break; + } + + if(unknown) { + printf("ERROR: still %d structs unknown\n", unknown); + + if (debugSDNA) { + printf("*** Known structs : \n"); + + for(a=0; a= MAX_DNA_LINE_LENGTH) { + fprintf(file, "\n"); + linelength = 0; + } + } +} + +void printStructLenghts(void) +{ + int a, unknown= nr_structs, lastunknown, structtype; + short *structpoin; + printf("\n\n*** All detected structs:\n"); + + while(unknown) { + lastunknown= unknown; + unknown= 0; + + /* check all structs... */ + for(a=0; a -1) { + fflush(stdout); + printf("Running makesdna at debug level %d\n", debugSDNA); + printf("\tProgram version: %s\n", DNA_VERSION_DATE); + } + + /* the longest known struct is 50k, so we assume 100k is sufficent! */ + namedata= MEM_callocN(maxdata, "namedata"); + typedata= MEM_callocN(maxdata, "typedata"); + structdata= MEM_callocN(maxdata, "structdata"); + + /* a maximum of 5000 variables, must be sufficient? */ + names= MEM_callocN(sizeof(char *)*maxnr, "names"); + types= MEM_callocN(sizeof(char *)*maxnr, "types"); + typelens= MEM_callocN(sizeof(short)*maxnr, "typelens"); + alphalens= MEM_callocN(sizeof(short)*maxnr, "alphalens"); + structs= MEM_callocN(sizeof(short)*maxnr, "structs"); + + /* insertion of all known types */ + /* watch it: uint is not allowed! use in structs an unsigned int */ + add_type("char", 1); /* 0 */ + add_type("uchar", 1); /* 1 */ + add_type("short", 2); /* 2 */ + add_type("ushort", 2); /* 3 */ + add_type("int", 4); /* 4 */ + add_type("long", 4); /* 5 */ /* should it be 8 on 64 bits? */ + add_type("ulong", 4); /* 6 */ + add_type("float", 4); /* 7 */ + add_type("double", 8); /* 8 */ + add_type("void", 0); /* 9 */ + + // the defines above shouldn't be output in the padding file... + firststruct = nr_types; + + /* add all include files defined in the global array */ + /* Since the internal file+path name buffer has limited length, I do a */ + /* little test first... */ + /* Mind the breaking condition here! */ + if (debugSDNA) printf("\tStart of header scan:\n"); + for (i = 0; strlen(includefiles[i]); i++) { + sprintf(str, "%s%s", baseDirectory, includefiles[i]); + if (debugSDNA) printf("\t|-- Converting %s\n", str); + if (convert_include(str)) { + return (1); + } + } + if (debugSDNA) printf("\tFinished scanning %d headers.\n", i); + + if (calculate_structlens(firststruct)) { + // error + return(1); + } + + /* FOR DEBUG */ + if (debugSDNA > 1) + { + int a,b; +/* short *elem; */ + short num_types; + + printf("nr_names %d nr_types %d nr_structs %d\n", nr_names, nr_types, nr_structs); + for(a=0; a -1) printf("Writing file ... "); + + if(nr_names==0 || nr_structs==0); + else { + strcpy(str, "SDNA"); + dna_write(file, str, 4); + + /* write names */ + strcpy(str, "NAME"); + dna_write(file, str, 4); + len= nr_names; + dna_write(file, &len, 4); + + /* calculate size of datablock with strings */ + cp= names[nr_names-1]; + cp+= strlen(names[nr_names-1]) + 1; /* +1: null-terminator */ + len= (long) (cp - (char*) names[0]); + len= (len+3) & ~3; + dna_write(file, names[0], len); + + /* write TYPES */ + strcpy(str, "TYPE"); + dna_write(file, str, 4); + len= nr_types; + dna_write(file, &len, 4); + + /* calculate datablock size */ + cp= types[nr_types-1]; + cp+= strlen(types[nr_types-1]) + 1; /* +1: null-terminator */ + len= (long) (cp - (char*) types[0]); + len= (len+3) & ~3; + + dna_write(file, types[0], len); + + /* WRITE TYPELENGTHS */ + strcpy(str, "TLEN"); + dna_write(file, str, 4); + + len= 2*nr_types; + if(nr_types & 1) len+= 2; + dna_write(file, typelens, len); + + /* WRITE STRUCTS */ + strcpy(str, "STRC"); + dna_write(file, str, 4); + len= nr_structs; + dna_write(file, &len, 4); + + /* calc datablock size */ + sp= structs[nr_structs-1]; + sp+= 2+ 2*( sp[1] ); + len= (long) ((char*) sp - (char*) structs[0]); + len= (len+3) & ~3; + + dna_write(file, structs[0], len); + + /* a simple dna padding test */ + if (0) { + FILE *fp; + int a; + + fp= fopen("padding.c", "w"); + if(fp==NULL); + else { + + // add all include files defined in the global array + for (i = 0; strlen(includefiles[i]); i++) { + fprintf(fp, "#include \"%s%s\"\n", baseDirectory, includefiles[i]); + } + + fprintf(fp, "main(){\n"); + sp = typelens; + sp += firststruct; + for(a=firststruct; a -1) printf("done.\n"); + + return(0); +} + +/* ************************* END MAKE DNA ********************** */ + +static void make_bad_file(char *file) +{ + FILE *fp= fopen(file, "w"); + fprintf(fp, "ERROR! Cannot make correct DNA.c file, STUPID!\n"); + fclose(fp); +} + +#ifndef BASE_HEADER +#define BASE_HEADER "../" +#endif + +int main(int argc, char ** argv) +{ + FILE *file; + int return_status = 0; + + if (argc!=2 && argc!=3) { + printf("Usage: %s outfile.c [base directory]\n", argv[0]); + return_status = 1; + } else { + file = fopen(argv[1], "w"); + if (!file) { + printf ("Unable to open file: %s\n", argv[1]); + return_status = 1; + } else { + char baseDirectory[256]; + + if (argc==3) { + strcpy(baseDirectory, argv[2]); + } else { + strcpy(baseDirectory, BASE_HEADER); + } + + fprintf (file, "unsigned char DNAstr[]= {\n"); + if (make_structDNA(baseDirectory, file)) { + // error + fclose(file); + make_bad_file(argv[1]); + return_status = 1; + } else { + fprintf(file, "};\n"); + fprintf(file, "int DNAlen= sizeof(DNAstr);\n"); + + fclose(file); + } + } + } + + + return(return_status); +} + +// include files for automatic dependancies +#include "DNA_listBase.h" +#include "DNA_vec_types.h" +#include "DNA_ID.h" +#include "DNA_ipo_types.h" +#include "DNA_key_types.h" +#include "DNA_scriptlink_types.h" +#include "DNA_text_types.h" +#include "DNA_packedFile_types.h" +#include "DNA_camera_types.h" +#include "DNA_image_types.h" +#include "DNA_texture_types.h" +#include "DNA_lamp_types.h" +#include "DNA_wave_types.h" +#include "DNA_material_types.h" +#include "DNA_vfont_types.h" +#include "DNA_meta_types.h" +#include "DNA_curve_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_lattice_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force.h" +#include "DNA_object_fluidsim.h" +#include "DNA_world_types.h" +#include "DNA_radio_types.h" +#include "DNA_scene_types.h" +#include "DNA_view3d_types.h" +#include "DNA_view2d_types.h" +#include "DNA_space_types.h" +#include "DNA_userdef_types.h" +#include "DNA_screen_types.h" +#include "DNA_sdna_types.h" +#include "DNA_fileglobal_types.h" +#include "DNA_sequence_types.h" +#include "DNA_effect_types.h" +#include "DNA_oops_types.h" +#include "DNA_property_types.h" +#include "DNA_sensor_types.h" +#include "DNA_controller_types.h" +#include "DNA_actuator_types.h" +#include "DNA_sound_types.h" +#include "DNA_group_types.h" +#include "DNA_armature_types.h" +#include "DNA_action_types.h" +#include "DNA_constraint_types.h" +#include "DNA_nla_types.h" +#include "DNA_node_types.h" +#include "DNA_color_types.h" +#include "DNA_brush_types.h" +#include "DNA_customdata_types.h" +/* end of list */ diff --git a/source/blender/nodes/CMP_node.h b/source/blender/nodes/CMP_node.h new file mode 100644 index 00000000000..4b7e721ca57 --- /dev/null +++ b/source/blender/nodes/CMP_node.h @@ -0,0 +1,105 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef CMP_NODE_H +#define CMP_NODE_H + +#include "BKE_node.h" + + +/* ****************** types array for all composite nodes ****************** */ + +extern bNodeType cmp_node_rlayers; +extern bNodeType cmp_node_image; +extern bNodeType cmp_node_texture; +extern bNodeType cmp_node_value; +extern bNodeType cmp_node_rgb; +extern bNodeType cmp_node_curve_time; + +extern bNodeType cmp_node_composite; +extern bNodeType cmp_node_viewer; +extern bNodeType cmp_node_splitviewer; +extern bNodeType cmp_node_output_file; + +extern bNodeType cmp_node_curve_rgb; +extern bNodeType cmp_node_mix_rgb; +extern bNodeType cmp_node_hue_sat; +extern bNodeType cmp_node_brightcontrast; +extern bNodeType cmp_node_gamma; +extern bNodeType cmp_node_invert; +extern bNodeType cmp_node_alphaover; +extern bNodeType cmp_node_zcombine; + +extern bNodeType cmp_node_normal; +extern bNodeType cmp_node_curve_vec; +extern bNodeType cmp_node_map_value; +extern bNodeType cmp_node_normalize; + +extern bNodeType cmp_node_filter; +extern bNodeType cmp_node_blur; +extern bNodeType cmp_node_vecblur; +extern bNodeType cmp_node_dilateerode; +extern bNodeType cmp_node_defocus; + +extern bNodeType cmp_node_valtorgb; +extern bNodeType cmp_node_rgbtobw; +extern bNodeType cmp_node_setalpha; +extern bNodeType cmp_node_idmask; +extern bNodeType cmp_node_math; +extern bNodeType cmp_node_seprgba; +extern bNodeType cmp_node_combrgba; +extern bNodeType cmp_node_sephsva; +extern bNodeType cmp_node_combhsva; +extern bNodeType cmp_node_sepyuva; +extern bNodeType cmp_node_combyuva; +extern bNodeType cmp_node_sepycca; +extern bNodeType cmp_node_combycca; + +extern bNodeType cmp_node_diff_matte; +extern bNodeType cmp_node_chroma; +extern bNodeType cmp_node_channel_matte; +extern bNodeType cmp_node_color_spill; +extern bNodeType cmp_node_luma_matte; + +extern bNodeType cmp_node_translate; +extern bNodeType cmp_node_rotate; +extern bNodeType cmp_node_scale; +extern bNodeType cmp_node_flip; +extern bNodeType cmp_node_crop; +extern bNodeType cmp_node_displace; +extern bNodeType cmp_node_mapuv; + +extern bNodeType cmp_node_glare; +extern bNodeType cmp_node_tonemap; +extern bNodeType cmp_node_lensdist; + +#endif diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt new file mode 100644 index 00000000000..6729d5099f0 --- /dev/null +++ b/source/blender/nodes/CMakeLists.txt @@ -0,0 +1,71 @@ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +FILE(GLOB SRC intern/*.c intern/CMP_nodes/*.c intern/SHD_nodes/*.c) + +SET(INC + . ../../../intern/guardedalloc ../include ../blenlib ../makesdna + ../python ../render/extern/include ../../../intern/decimation/extern + ../imbuf ../avi ../../../intern/elbeem/extern + ../../../intern/iksolver/extern ../blenloader ../quicktime + ../blenkernel + ${SDL_INC} + ${ZLIB_INC} +) + +IF(WITH_VERSE) + ADD_DEFINITIONS(-DWITH_VERSE) + SET(INC ${INC} ${VERSE_INC}) +ENDIF(WITH_VERSE) + +IF(WITH_OPENEXR) + ADD_DEFINITIONS(-DWITH_OPENEXR) +ENDIF(WITH_OPENEXR) + +IF(WITH_QUICKTIME) + SET(INC ${INC} ${QUICKTIME_INC}) + ADD_DEFINITIONS(-DWITH_QUICKTIME) +ENDIF(WITH_QUICKTIME) + +IF(WITH_FFMPEG) + SET(INC ${INC} ${FFMPEG_INC}) + ADD_DEFINITIONS(-DWITH_FFMPEG) +ENDIF(WITH_FFMPEG) + +ADD_DEFINITIONS(-DWITH_CCGSUBSURF) + +BLENDERLIB(bf_nodes "${SRC}" "${INC}") + +IF(WITH_VERSE) + ADD_DEPENDENCIES(bf_nodes mkprot verse) +ENDIF(WITH_VERSE) + +IF(WITH_INTERNATIONAL) + ADD_DEFINITIONS(-DWITH_FREETYPE2) +ENDIF(WITH_INTERNATIONAL) + diff --git a/source/blender/nodes/Makefile b/source/blender/nodes/Makefile new file mode 100644 index 00000000000..37edf74b3ea --- /dev/null +++ b/source/blender/nodes/Makefile @@ -0,0 +1,37 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# Bounces make to subdirectories. + +SOURCEDIR = source/blender/nodes +DIRS = intern intern/CMP_nodes intern/SHD_nodes + +include nan_subdirs.mk diff --git a/source/blender/nodes/SConscript b/source/blender/nodes/SConscript new file mode 100644 index 00000000000..0460848b4a5 --- /dev/null +++ b/source/blender/nodes/SConscript @@ -0,0 +1,46 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.c') +sources += env.Glob('intern/CMP_nodes/*.c') +sources += env.Glob('intern/SHD_nodes/*.c') + +incs = '. ./intern ' +incs += '#/intern/guardedalloc ../include ../blenlib ../makesdna' +incs += ' ../python ../render/extern/include ' +incs += ' ../imbuf ../avi ' +incs += ' ../blenloader ../quicktime' +incs += ' ../blenkernel ../renderconverter ' + + + +incs += ' ' + env['BF_OPENGL_INC'] +incs += ' ' + env['BF_ZLIB_INC'] +incs += ' ' + env['BF_SDL_INC'] + +defs = '' + +if env['WITH_BF_INTERNATIONAL']: + defs += 'WITH_FREETYPE2' + +if env['WITH_BF_VERSE']: + defs += ' WITH_VERSE' + incs += ' ' + env['BF_VERSE_INCLUDE'] + +if env['WITH_BF_VERSE']: + defs += ' WITH_VERSE' + +if env['WITH_BF_OPENEXR'] == 1: + defs += ' WITH_OPENEXR' + +if env['WITH_BF_FFMPEG'] == 1: + defs += ' WITH_FFMPEG' + incs += ' ' + env['BF_FFMPEG_INC'] + +if env['WITH_BF_QUICKTIME'] == 1: + defs += ' WITH_QUICKTIME' + incs += ' ' + env['BF_QUICKTIME_INC'] + +defs += ' WITH_CCGSUBSURF' + +env.BlenderLib ( libname = 'nodes', sources = sources, includes = Split(incs), defines = Split(defs), libtype=['core','player'], priority = [65, 20] ) diff --git a/source/blender/nodes/SHD_node.h b/source/blender/nodes/SHD_node.h new file mode 100644 index 00000000000..8064a543ca0 --- /dev/null +++ b/source/blender/nodes/SHD_node.h @@ -0,0 +1,68 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef SHD_NODE_H +#define SHD_NODE_H + +#include "BKE_node.h" + + +/* the type definitions array */ +/* ****************** types array for all shaders ****************** */ + +extern bNodeType sh_node_output; +extern bNodeType sh_node_material; +extern bNodeType sh_node_camera; +extern bNodeType sh_node_value; +extern bNodeType sh_node_rgb; +extern bNodeType sh_node_mix_rgb; +extern bNodeType sh_node_valtorgb; +extern bNodeType sh_node_rgbtobw; +extern bNodeType sh_node_texture; +extern bNodeType sh_node_normal; +extern bNodeType sh_node_geom; +extern bNodeType sh_node_mapping; +extern bNodeType sh_node_curve_vec; +extern bNodeType sh_node_curve_rgb; +extern bNodeType sh_node_math; +extern bNodeType sh_node_vect_math; +extern bNodeType sh_node_squeeze; +extern bNodeType sh_node_material_ext; +extern bNodeType sh_node_invert; +extern bNodeType sh_node_seprgb; +extern bNodeType sh_node_combrgb; +extern bNodeType sh_node_hue_sat; + + +#endif + + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_alphaOver.c b/source/blender/nodes/intern/CMP_nodes/CMP_alphaOver.c new file mode 100644 index 00000000000..f108098750c --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_alphaOver.c @@ -0,0 +1,128 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + +/* **************** ALPHAOVER ******************** */ +static bNodeSocketType cmp_node_alphaover_in[]= { + { SOCK_VALUE, 1, "Fac", 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_alphaover_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_alphaover_premul(bNode *node, float *out, float *src, float *over, float *fac) +{ + + if(over[3]<=0.0f) { + QUATCOPY(out, src); + } + else if(*fac==1.0f && over[3]>=1.0f) { + QUATCOPY(out, over); + } + else { + float mul= 1.0f - *fac*over[3]; + + out[0]= (mul*src[0]) + *fac*over[0]; + out[1]= (mul*src[1]) + *fac*over[1]; + out[2]= (mul*src[2]) + *fac*over[2]; + out[3]= (mul*src[3]) + *fac*over[3]; + } +} + +/* result will be still premul, but the over part is premulled */ +static void do_alphaover_key(bNode *node, float *out, float *src, float *over, float *fac) +{ + + if(over[3]<=0.0f) { + QUATCOPY(out, src); + } + else if(*fac==1.0f && over[3]>=1.0f) { + QUATCOPY(out, over); + } + else { + float premul= fac[0]*over[3]; + float mul= 1.0f - premul; + + out[0]= (mul*src[0]) + premul*over[0]; + out[1]= (mul*src[1]) + premul*over[1]; + out[2]= (mul*src[2]) + premul*over[2]; + out[3]= (mul*src[3]) + fac[0]*over[3]; + } +} + + +static void node_composit_exec_alphaover(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order in: col col */ + /* stack order out: col */ + if(out[0]->hasoutput==0) + return; + + /* input no image? then only color operation */ + if(in[1]->data==NULL && in[2]->data==NULL) { + do_alphaover_premul(node, out[0]->vec, in[1]->vec, in[2]->vec, in[0]->vec); + } + else { + /* make output size of input image */ + CompBuf *cbuf= in[1]->data?in[1]->data:in[2]->data; + CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */ + + if(node->custom1) + composit3_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[2]->data, in[2]->vec, in[0]->data, in[0]->vec, do_alphaover_key, CB_RGBA, CB_RGBA, CB_VAL); + else + composit3_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[2]->data, in[2]->vec, in[0]->data, in[0]->vec, do_alphaover_premul, CB_RGBA, CB_RGBA, CB_VAL); + + out[0]->data= stackbuf; + } +} + +bNodeType cmp_node_alphaover= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_ALPHAOVER, + /* name */ "AlphaOver", + /* width+range */ 80, 40, 120, + /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS, + /* input sock */ cmp_node_alphaover_in, + /* output sock */ cmp_node_alphaover_out, + /* storage */ "", + /* execfunc */ node_composit_exec_alphaover, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; + + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_blur.c b/source/blender/nodes/intern/CMP_nodes/CMP_blur.c new file mode 100644 index 00000000000..8ef4af4d219 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_blur.c @@ -0,0 +1,687 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + +/* **************** BLUR ******************** */ +static bNodeSocketType cmp_node_blur_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Size", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_blur_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static float *make_gausstab(int filtertype, int rad) +{ + float *gausstab, sum, val; + int i, n; + + n = 2 * rad + 1; + + gausstab = (float *) MEM_mallocN(n * sizeof(float), "gauss"); + + sum = 0.0f; + for (i = -rad; i <= rad; i++) { + val= RE_filter_value(filtertype, (float)i/(float)rad); + sum += val; + gausstab[i+rad] = val; + } + + sum= 1.0f/sum; + for(i=0; istorage; + CompBuf *work; + register float sum, val; + float rval, gval, bval, aval; + float *gausstab, *gausstabcent; + int rad, imgx= img->x, imgy= img->y; + int x, y, pix= img->type; + int i, bigstep; + float *src, *dest; + + /* helper image */ + work= alloc_compbuf(imgx, imgy, img->type, 1); /* allocs */ + + /* horizontal */ + rad = scale*(float)nbd->sizex; + if(rad>imgx/2) + rad= imgx/2; + else if(rad<1) + rad= 1; + + gausstab= make_gausstab(nbd->filtertype, rad); + gausstabcent= gausstab+rad; + + for (y = 0; y < imgy; y++) { + float *srcd= img->rect + pix*(y*img->x); + + dest = work->rect + pix*(y * img->x); + + for (x = 0; x < imgx ; x++) { + int minr= x-rad<0?-x:-rad; + int maxr= x+rad>imgx?imgx-x:rad; + + src= srcd + pix*(x+minr); + + sum= gval = rval= bval= aval= 0.0f; + for (i= minr; i < maxr; i++) { + val= gausstabcent[i]; + sum+= val; + rval += val * (*src++); + if(pix==4) { + gval += val * (*src++); + bval += val * (*src++); + aval += val * (*src++); + } + } + sum= 1.0f/sum; + *dest++ = rval*sum; + if(pix==4) { + *dest++ = gval*sum; + *dest++ = bval*sum; + *dest++ = aval*sum; + } + } + if(node->exec & NODE_BREAK) + break; + } + + /* vertical */ + MEM_freeN(gausstab); + + rad = scale*(float)nbd->sizey; + if(rad>imgy/2) + rad= imgy/2; + else if(rad<1) + rad= 1; + + gausstab= make_gausstab(nbd->filtertype, rad); + gausstabcent= gausstab+rad; + + bigstep = pix*imgx; + for (x = 0; x < imgx; x++) { + float *srcd= work->rect + pix*x; + + dest = new->rect + pix*x; + + for (y = 0; y < imgy ; y++) { + int minr= y-rad<0?-y:-rad; + int maxr= y+rad>imgy?imgy-y:rad; + + src= srcd + bigstep*(y+minr); + + sum= gval = rval= bval= aval= 0.0f; + for (i= minr; i < maxr; i++) { + val= gausstabcent[i]; + sum+= val; + rval += val * src[0]; + if(pix==4) { + gval += val * src[1]; + bval += val * src[2]; + aval += val * src[3]; + } + src += bigstep; + } + sum= 1.0f/sum; + dest[0] = rval*sum; + if(pix==4) { + dest[1] = gval*sum; + dest[2] = bval*sum; + dest[3] = aval*sum; + } + dest+= bigstep; + } + if(node->exec & NODE_BREAK) + break; + } + + free_compbuf(work); + MEM_freeN(gausstab); +} + +/* reference has to be mapped 0-1, and equal in size */ +static void bloom_with_reference(CompBuf *new, CompBuf *img, CompBuf *ref, float fac, NodeBlurData *nbd) +{ + CompBuf *wbuf; + register float val; + float radxf, radyf; + float **maintabs; + float *gausstabx, *gausstabcenty; + float *gausstaby, *gausstabcentx; + int radx, rady, imgx= img->x, imgy= img->y; + int x, y; + int i, j; + float *src, *dest, *wb; + + wbuf= alloc_compbuf(imgx, imgy, CB_VAL, 1); + + /* horizontal */ + radx = (float)nbd->sizex; + if(radx>imgx/2) + radx= imgx/2; + else if(radx<1) + radx= 1; + + /* vertical */ + rady = (float)nbd->sizey; + if(rady>imgy/2) + rady= imgy/2; + else if(rady<1) + rady= 1; + + x= MAX2(radx, rady); + maintabs= MEM_mallocN(x*sizeof(void *), "gauss array"); + for(i= 0; irect; + src= img->rect; + + radxf= (float)radx; + radyf= (float)rady; + + for (y = 0; y < imgy; y++) { + for (x = 0; x < imgx ; x++, src+=4) {//, refd++) { + +// int refradx= (int)(refd[0]*radxf); +// int refrady= (int)(refd[0]*radyf); + + int refradx= (int)(radxf*0.3f*src[3]*(src[0]+src[1]+src[2])); + int refrady= (int)(radyf*0.3f*src[3]*(src[0]+src[1]+src[2])); + + if(refradx>radx) refradx= radx; + else if(refradx<1) refradx= 1; + if(refrady>rady) refrady= rady; + else if(refrady<1) refrady= 1; + + if(refradx==1 && refrady==1) { + wb= wbuf->rect + ( y*imgx + x); + dest= new->rect + 4*( y*imgx + x); + wb[0]+= 1.0f; + dest[0] += src[0]; + dest[1] += src[1]; + dest[2] += src[2]; + dest[3] += src[3]; + } + else { + int minxr= x-refradx<0?-x:-refradx; + int maxxr= x+refradx>imgx?imgx-x:refradx; + int minyr= y-refrady<0?-y:-refrady; + int maxyr= y+refrady>imgy?imgy-y:refrady; + + float *destd= new->rect + 4*( (y + minyr)*imgx + x + minxr); + float *wbufd= wbuf->rect + ( (y + minyr)*imgx + x + minxr); + + gausstabx= maintabs[refradx-1]; + gausstabcentx= gausstabx+refradx; + gausstaby= maintabs[refrady-1]; + gausstabcenty= gausstaby+refrady; + + for (i= minyr; i < maxyr; i++, destd+= 4*imgx, wbufd+= imgx) { + dest= destd; + wb= wbufd; + for (j= minxr; j < maxxr; j++, dest+=4, wb++) { + + val= gausstabcenty[i]*gausstabcentx[j]; + wb[0]+= val; + dest[0] += val * src[0]; + dest[1] += val * src[1]; + dest[2] += val * src[2]; + dest[3] += val * src[3]; + } + } + } + } + } + + x= imgx*imgy; + dest= new->rect; + wb= wbuf->rect; + while(x--) { + val= 1.0f/wb[0]; + dest[0]*= val; + dest[1]*= val; + dest[2]*= val; + dest[3]*= val; + wb++; + dest+= 4; + } + + free_compbuf(wbuf); + + x= MAX2(radx, rady); + for(i= 0; i0.33f) { + fj= (fj-0.33f)/0.66f; + if(fi+fj>1.0f) + return 0.0f; + else + return 1.0f; + } + else return 1.0f; +} +#endif + +/* uses full filter, no horizontal/vertical optimize possible */ +/* both images same type, either 1 or 4 channels */ +static void bokeh_single_image(bNode *node, CompBuf *new, CompBuf *img, float fac) +{ + NodeBlurData *nbd= node->storage; + register float val; + float radxf, radyf; + float *gausstab, *dgauss; + int radx, rady, imgx= img->x, imgy= img->y; + int x, y, pix= img->type; + int i, j, n; + float *src= NULL, *dest, *srcd= NULL; + + /* horizontal */ + radxf = fac*(float)nbd->sizex; + if(radxf>imgx/2.0f) + radxf= imgx/2.0f; + else if(radxf<1.0f) + radxf= 1.0f; + + /* vertical */ + radyf = fac*(float)nbd->sizey; + if(radyf>imgy/2.0f) + radyf= imgy/2.0f; + else if(radyf<1.0f) + radyf= 1.0f; + + radx= ceil(radxf); + rady= ceil(radyf); + + n = (2*radx+1)*(2*rady+1); + + /* create a full filter image */ + gausstab= MEM_mallocN(sizeof(float)*n, "filter tab"); + dgauss= gausstab; + val= 0.0f; + for(j=-rady; j<=rady; j++) { + for(i=-radx; i<=radx; i++, dgauss++) { + float fj= (float)j/radyf; + float fi= (float)i/radxf; + float dist= sqrt(fj*fj + fi*fi); + + //*dgauss= hexagon_filter(fi, fj); + *dgauss= RE_filter_value(nbd->filtertype, 2.0f*dist - 1.0f); + + val+= *dgauss; + } + } + + if(val!=0.0f) { + val= 1.0f/val; + for(j= n -1; j>=0; j--) + gausstab[j]*= val; + } + else gausstab[4]= 1.0f; + + for (y = -rady+1; y < imgy+rady-1; y++) { + + if(y<=0) srcd= img->rect; + else if(yrect + pix*(imgy-1)*imgx; + + for (x = -radx+1; x < imgx+radx-1 ; x++) { + int minxr= x-radx<0?-x:-radx; + int maxxr= x+radx>=imgx?imgx-x-1:radx; + int minyr= y-rady<0?-y:-rady; + int maxyr= y+rady>imgy-1?imgy-y-1:rady; + + float *destd= new->rect + pix*( (y + minyr)*imgx + x + minxr); + float *dgausd= gausstab + (minyr+rady)*2*radx + minxr+radx; + + if(x<=0) src= srcd; + else if(x1) { + dest[1] += val * src[1]; + dest[2] += val * src[2]; + dest[3] += val * src[3]; + } + } + } + } + } + if(node->exec & NODE_BREAK) + break; + } + + MEM_freeN(gausstab); +} + + +/* reference has to be mapped 0-1, and equal in size */ +static void blur_with_reference(bNode *node, CompBuf *new, CompBuf *img, CompBuf *ref) +{ + NodeBlurData *nbd= node->storage; + CompBuf *blurbuf, *ref_use; + register float sum, val; + float rval, gval, bval, aval, radxf, radyf; + float **maintabs; + float *gausstabx, *gausstabcenty; + float *gausstaby, *gausstabcentx; + int radx, rady, imgx= img->x, imgy= img->y; + int x, y, pix= img->type; + int i, j; + float *src, *dest, *refd, *blurd; + + if(ref->x!=img->x && ref->y!=img->y) + return; + + ref_use= typecheck_compbuf(ref, CB_VAL); + + /* trick is; we blur the reference image... but only works with clipped values*/ + blurbuf= alloc_compbuf(imgx, imgy, CB_VAL, 1); + blurd= blurbuf->rect; + refd= ref_use->rect; + for(x= imgx*imgy; x>0; x--, refd++, blurd++) { + if(refd[0]<0.0f) blurd[0]= 0.0f; + else if(refd[0]>1.0f) blurd[0]= 1.0f; + else blurd[0]= refd[0]; + } + + blur_single_image(node, blurbuf, blurbuf, 1.0f); + + /* horizontal */ + radx = (float)nbd->sizex; + if(radx>imgx/2) + radx= imgx/2; + else if(radx<1) + radx= 1; + + /* vertical */ + rady = (float)nbd->sizey; + if(rady>imgy/2) + rady= imgy/2; + else if(rady<1) + rady= 1; + + x= MAX2(radx, rady); + maintabs= MEM_mallocN(x*sizeof(void *), "gauss array"); + for(i= 0; ifiltertype, i+1); + + refd= blurbuf->rect; + dest= new->rect; + radxf= (float)radx; + radyf= (float)rady; + + for (y = 0; y < imgy; y++) { + for (x = 0; x < imgx ; x++, dest+=pix, refd++) { + int refradx= (int)(refd[0]*radxf); + int refrady= (int)(refd[0]*radyf); + + if(refradx>radx) refradx= radx; + else if(refradx<1) refradx= 1; + if(refrady>rady) refrady= rady; + else if(refrady<1) refrady= 1; + + if(refradx==1 && refrady==1) { + src= img->rect + pix*( y*imgx + x); + if(pix==1) + dest[0]= src[0]; + else + QUATCOPY(dest, src); + } + else { + int minxr= x-refradx<0?-x:-refradx; + int maxxr= x+refradx>imgx?imgx-x:refradx; + int minyr= y-refrady<0?-y:-refrady; + int maxyr= y+refrady>imgy?imgy-y:refrady; + + float *srcd= img->rect + pix*( (y + minyr)*imgx + x + minxr); + + gausstabx= maintabs[refradx-1]; + gausstabcentx= gausstabx+refradx; + gausstaby= maintabs[refrady-1]; + gausstabcenty= gausstaby+refrady; + + sum= gval = rval= bval= aval= 0.0f; + + for (i= minyr; i < maxyr; i++, srcd+= pix*imgx) { + src= srcd; + for (j= minxr; j < maxxr; j++, src+=pix) { + + val= gausstabcenty[i]*gausstabcentx[j]; + sum+= val; + rval += val * src[0]; + if(pix>1) { + gval += val * src[1]; + bval += val * src[2]; + aval += val * src[3]; + } + } + } + sum= 1.0f/sum; + dest[0] = rval*sum; + if(pix>1) { + dest[1] = gval*sum; + dest[2] = bval*sum; + dest[3] = aval*sum; + } + } + } + if(node->exec & NODE_BREAK) + break; + } + + free_compbuf(blurbuf); + + x= MAX2(radx, rady); + for(i= 0; idata; + + if(img==NULL || out[0]->hasoutput==0) + return; + + if (((NodeBlurData *)node->storage)->filtertype == R_FILTER_FAST_GAUSS) { + CompBuf *new, *img = in[0]->data; + /*from eeshlo's original patch, removed to fit in with the existing blur node */ + /*const float sx = in[1]->vec[0], sy = in[2]->vec[0];*/ + + NodeBlurData *nbd= node->storage; + const float sx = ((float)nbd->sizex)/2.0f, sy = ((float)nbd->sizey)/2.0f; + int c; + + if ((img==NULL) || (out[0]->hasoutput==0)) return; + + if (img->type == CB_VEC2) + new = typecheck_compbuf(img, CB_VAL); + else if (img->type == CB_VEC3) + new = typecheck_compbuf(img, CB_RGBA); + else + new = dupalloc_compbuf(img); + + if ((sx == sy) && (sx > 0.f)) { + for (c=0; ctype; ++c) + IIR_gauss(new, sx, c, 3); + } + else { + if (sx > 0.f) { + for (c=0; ctype; ++c) + IIR_gauss(new, sx, c, 1); + } + if (sy > 0.f) { + for (c=0; ctype; ++c) + IIR_gauss(new, sy, c, 2); + } + } + out[0]->data = new; + + } else { + /* All non fast gauss blur methods */ + if(img->type==CB_VEC2 || img->type==CB_VEC3) { + img= typecheck_compbuf(in[0]->data, CB_RGBA); + } + + /* if fac input, we do it different */ + if(in[1]->data) { + + /* make output size of input image */ + new= alloc_compbuf(img->x, img->y, img->type, 1); /* allocs */ + + /* accept image offsets from other nodes */ + new->xof = img->xof; + new->yof = img->yof; + + blur_with_reference(node, new, img, in[1]->data); + if(node->exec & NODE_BREAK) { + free_compbuf(new); + new= NULL; + } + out[0]->data= new; + } + else { + + if(in[1]->vec[0]<=0.001f) { /* time node inputs can be a tiny value */ + new= pass_on_compbuf(img); + } + else { + NodeBlurData *nbd= node->storage; + CompBuf *gammabuf; + + /* make output size of input image */ + new= alloc_compbuf(img->x, img->y, img->type, 1); /* allocs */ + + /* accept image offsets from other nodes */ + new->xof = img->xof; + new->yof = img->yof; + + if(nbd->gamma) { + gammabuf= dupalloc_compbuf(img); + gamma_correct_compbuf(gammabuf, 0); + } + else gammabuf= img; + + if(nbd->bokeh) + bokeh_single_image(node, new, gammabuf, in[1]->vec[0]); + else if(1) + blur_single_image(node, new, gammabuf, in[1]->vec[0]); + else /* bloom experimental... */ + bloom_with_reference(new, gammabuf, NULL, in[1]->vec[0], nbd); + + if(nbd->gamma) { + gamma_correct_compbuf(new, 1); + free_compbuf(gammabuf); + } + if(node->exec & NODE_BREAK) { + free_compbuf(new); + new= NULL; + } + } + out[0]->data= new; + } + if(img!=in[0]->data) + free_compbuf(img); + } +} + +static void node_composit_init_blur(bNode* node) +{ + node->storage= MEM_callocN(sizeof(NodeBlurData), "node blur data"); +} + +bNodeType cmp_node_blur= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_BLUR, + /* name */ "Blur", + /* width+range */ 120, 80, 200, + /* class+opts */ NODE_CLASS_OP_FILTER, NODE_OPTIONS, + /* input sock */ cmp_node_blur_in, + /* output sock */ cmp_node_blur_out, + /* storage */ "NodeBlurData", + /* execfunc */ node_composit_exec_blur, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_blur, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL +}; + + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_brightness.c b/source/blender/nodes/intern/CMP_nodes/CMP_brightness.c new file mode 100644 index 00000000000..c87307434b5 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_brightness.c @@ -0,0 +1,113 @@ +/** +* $Id$ +* +* ***** BEGIN GPL LICENSE BLOCK ***** +* +* 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. +* +* The Original Code is Copyright (C) 2006 Blender Foundation. +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): none yet. +* +* ***** END GPL LICENSE BLOCK ***** + +*/ + +#include "../CMP_util.h" + + +/* **************** Brigh and contrsast ******************** */ + +static bNodeSocketType cmp_node_brightcontrast_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "bright", 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f}, + { SOCK_VALUE, 1, "contrast", 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_brightcontrast_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_brightnesscontrast(bNode *node, float *out, float *in) +{ + float i; + int c; + float a, b, contrast, brightness, delta, v; + contrast = node->custom2; + brightness = (float)(node->custom1); + brightness = (brightness) / 100.0f; + delta = contrast / 200.0f; + a = 1.0f - delta * 2.0f; + /* + * The algorithm is by Werner D. Streidt + * (http://visca.com/ffactory/archives/5-99/msg00021.html) + * Extracted of OpenCV demhist.c + */ + if( contrast > 0 ) +{ + a = 1.0f / a; + b = a * (brightness - delta); + } + else + { + delta *= -1; + b = a * (brightness + delta); + } + + for(c=0; c<3; c++){ + i = in[c]; + v = a*i + b; + out[c] = v; + } +} + +static void node_composit_exec_brightcontrast(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + if(out[0]->hasoutput==0) + return; + + if(in[0]->data) { + CompBuf *stackbuf, *cbuf= typecheck_compbuf(in[0]->data, CB_RGBA); + node->custom1 = in[1]->vec[0]; + node->custom2 = in[2]->vec[0]; + stackbuf= dupalloc_compbuf(cbuf); + composit1_pixel_processor(node, stackbuf, cbuf, in[0]->vec, do_brightnesscontrast, CB_RGBA); + out[0]->data = stackbuf; + if(cbuf != in[0]->data) + free_compbuf(cbuf); + } +} + +bNodeType cmp_node_brightcontrast= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_BRIGHTCONTRAST, + /* name */ "Bright/Contrast", + /* width+range */ 140, 100, 320, + /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS, + /* input sock */ cmp_node_brightcontrast_in, + /* output sock */ cmp_node_brightcontrast_out, + /* storage */ "", + /* execfunc */ node_composit_exec_brightcontrast, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copysotragefunc */ NULL, + /* id */ NULL +}; + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_channelMatte.c b/source/blender/nodes/intern/CMP_nodes/CMP_channelMatte.c new file mode 100644 index 00000000000..d0cc4e5b88d --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_channelMatte.c @@ -0,0 +1,207 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + + +/* ******************* Channel Matte Node ********************************* */ +static bNodeSocketType cmp_node_channel_matte_in[]={ + {SOCK_RGBA,1,"Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + {-1,0,""} +}; + +static bNodeSocketType cmp_node_channel_matte_out[]={ + {SOCK_RGBA,0,"Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + {SOCK_VALUE,0,"Matte",0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + {-1,0,""} +}; + +static void do_normalized_rgba_to_ycca2(bNode *node, float *out, float *in) +{ + /*normalize to the range 0.0 to 1.0) */ + rgb_to_ycc(in[0],in[1],in[2], &out[0], &out[1], &out[2]); + out[0]=(out[0])/255.0; + out[1]=(out[1])/255.0; + out[2]=(out[2])/255.0; + out[3]=in[3]; +} + +static void do_normalized_ycca_to_rgba2(bNode *node, float *out, float *in) +{ + /*un-normalize the normalize from above */ + in[0]=in[0]*255.0; + in[1]=in[1]*255.0; + in[2]=in[2]*255.0; + ycc_to_rgb(in[0],in[1],in[2], &out[0], &out[1], &out[2]); + out[3]=in[3]; +} + + +static void do_channel_matte(bNode *node, float *out, float *in) +{ + NodeChroma *c=(NodeChroma *)node->storage; + float alpha=0.0; + + /* Alpha=G-MAX(R, B) */ + + switch(node->custom2) + { + case 1: + { + alpha=in[0]-MAX2(in[1],in[2]); + break; + } + case 2: + { + alpha=in[1]-MAX2(in[0],in[2]); + break; + } + case 3: + { + alpha=in[2]-MAX2(in[0],in[1]); + break; + } + default: + break; + } + + /*flip because 0.0 is transparent, not 1.0*/ + alpha=1-alpha; + + /* test range*/ + if(alpha>c->t1) { + alpha=in[3]; /*whatever it was prior */ + } + else if(alphat2){ + alpha=0.0; + } + else {/*blend */ + alpha=(alpha-c->t2)/(c->t1-c->t2); + } + + + /* don't make something that was more transparent less transparent */ + if (alphahasinput==0) return; + if(in[0]->data==NULL) return; + if(out[0]->hasoutput==0 && out[1]->hasoutput==0) return; + + cbuf=typecheck_compbuf(in[0]->data, CB_RGBA); + + outbuf=dupalloc_compbuf(cbuf); + + /*convert to colorspace*/ + switch(node->custom1) { + case 1: /*RGB */ + break; + case 2: /*HSV*/ + composit1_pixel_processor(node, outbuf, cbuf, in[1]->vec, do_rgba_to_hsva, CB_RGBA); + break; + case 3: /*YUV*/ + composit1_pixel_processor(node, outbuf, cbuf, in[1]->vec, do_rgba_to_yuva, CB_RGBA); + break; + case 4: /*YCC*/ + composit1_pixel_processor(node, outbuf, cbuf, in[1]->vec, do_normalized_rgba_to_ycca2, CB_RGBA); + break; + default: + break; + } + + /*use the selected channel information to do the key */ + composit1_pixel_processor(node, outbuf, outbuf, in[1]->vec, do_channel_matte, CB_RGBA); + + /*convert back to RGB colorspace in place*/ + switch(node->custom1) { + case 1: /*RGB*/ + break; + case 2: /*HSV*/ + composit1_pixel_processor(node, outbuf, outbuf, in[1]->vec, do_hsva_to_rgba, CB_RGBA); + break; + case 3: /*YUV*/ + composit1_pixel_processor(node, outbuf, outbuf, in[1]->vec, do_yuva_to_rgba, CB_RGBA); + break; + case 4: /*YCC*/ + composit1_pixel_processor(node, outbuf, outbuf, in[1]->vec, do_normalized_ycca_to_rgba2, CB_RGBA); + break; + default: + break; + } + + generate_preview(node, outbuf); + out[0]->data=outbuf; + if(out[1]->hasoutput) + out[1]->data=valbuf_from_rgbabuf(outbuf, CHAN_A); + + if(cbuf!=in[0]->data) + free_compbuf(cbuf); + +} + +static void node_composit_init_channel_matte(bNode *node) +{ + NodeChroma *c= MEM_callocN(sizeof(NodeChroma), "node chroma"); + node->storage=c; + c->t1= 0.0f; + c->t2= 0.0f; + c->t3= 0.0f; + c->fsize= 0.0f; + c->fstrength= 0.0f; + node->custom1= 1; /* RGB channel */ + node->custom2= 2; /* Green Channel */ +} + +bNodeType cmp_node_channel_matte={ + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_CHANNEL_MATTE, + /* name */ "Channel Key", + /* width+range */ 200, 80, 250, + /* class+opts */ NODE_CLASS_MATTE, NODE_PREVIEW|NODE_OPTIONS, + /* input sock */ cmp_node_channel_matte_in, + /* output sock */ cmp_node_channel_matte_out, + /* storage */ "NodeChroma", + /* execfunc */ node_composit_exec_channel_matte, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_channel_matte, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL +}; diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_chromaMatte.c b/source/blender/nodes/intern/CMP_nodes/CMP_chromaMatte.c new file mode 100644 index 00000000000..d836a829696 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_chromaMatte.c @@ -0,0 +1,192 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + +/* ******************* Chroma Key ********************************************************** */ +static bNodeSocketType cmp_node_chroma_in[]={ + {SOCK_RGBA,1,"Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + {SOCK_RGBA,1,"Key Color", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + {-1,0,""} +}; + +static bNodeSocketType cmp_node_chroma_out[]={ + {SOCK_RGBA,0,"Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + {SOCK_VALUE,0,"Matte",0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + {-1,0,""} +}; + +static void do_rgba_to_ycca_normalized(bNode *node, float *out, float *in) +{ + /*normalize to the range -1.0 to 1.0) */ + rgb_to_ycc(in[0],in[1],in[2], &out[0], &out[1], &out[2]); + out[0]=((out[0])-16)/255.0; + out[1]=((out[1])-128)/255.0; + out[2]=((out[2])-128)/255.0; + out[3]=in[3]; +} + +static void do_ycca_to_rgba_normalized(bNode *node, float *out, float *in) +{ + /*un-normalize the normalize from above */ + in[0]=(in[0]*255.0)+16; + in[1]=(in[1]*255.0)+128; + in[2]=(in[2]*255.0)+128; + ycc_to_rgb(in[0],in[1],in[2], &out[0], &out[1], &out[2]); + out[3]=in[3]; +} + +static void do_chroma_key(bNode *node, float *out, float *in) +{ + NodeChroma *c; + float x, z, alpha; + float theta, beta, angle; + float kfg, newY, newCb, newCr; + + c=node->storage; + + /* Algorithm from book "Video Demistified" */ + + /* find theta, the angle that the color space should be rotated based on key*/ + theta=atan2(c->key[2],c->key[1]); + + /*rotate the cb and cr into x/z space */ + x=in[1]*cos(theta)+in[2]*sin(theta); + z=in[2]*cos(theta)-in[1]*sin(theta); + + /*if within the acceptance angle */ + angle=c->t1*M_PI/180.0; /* convert to radians */ + + /* if kfg is <0 then the pixel is outside of the key color */ + kfg=x-(fabs(z)/tan(angle/2.0)); + + if(kfg>0.0) { /* found a pixel that is within key color */ + + newY=in[0]-(1-c->t3)*kfg; + newCb=in[1]-kfg*cosf(theta); + newCr=in[2]-kfg*sinf(theta); + alpha=(kfg+c->fsize)*(c->fstrength); + + beta=atan2(newCr,newCb); + beta=beta*180.0/M_PI; /* convert to degrees for compare*/ + + /* if beta is within the clippin angle */ + if(fabs(beta)<(c->t2/2.0)) { + newCb=0.0; + newCr=0.0; + alpha=0.0; + } + + out[0]=newY; + out[1]=newCb; + out[2]=newCr; + + /* don't make something that was more transparent less transparent */ + if (alphahasinput==0) return; + if(in[0]->data==NULL) return; + if(out[0]->hasoutput==0 && out[1]->hasoutput==0) return; + + cbuf= typecheck_compbuf(in[0]->data, CB_RGBA); + + chromabuf= dupalloc_compbuf(cbuf); + + c=node->storage; + + /*convert rgbbuf to normalized chroma space*/ + composit1_pixel_processor(node, chromabuf, cbuf, in[0]->vec, do_rgba_to_ycca_normalized, CB_RGBA); + /*convert key to normalized chroma color space */ + do_rgba_to_ycca_normalized(node, c->key, in[1]->vec); + + /*per pixel chroma key*/ + composit1_pixel_processor(node, chromabuf, chromabuf, in[0]->vec, do_chroma_key, CB_RGBA); + + /*convert back*/ + composit1_pixel_processor(node, chromabuf, chromabuf, in[0]->vec, do_ycca_to_rgba_normalized, CB_RGBA); + + out[0]->data= chromabuf; + if(out[1]->hasoutput) + out[1]->data= valbuf_from_rgbabuf(chromabuf, CHAN_A); + + generate_preview(node, chromabuf); + + if(cbuf!=in[0]->data) + free_compbuf(cbuf); +}; + + +static void node_composit_init_chroma_matte(bNode *node) +{ + NodeChroma *c= MEM_callocN(sizeof(NodeChroma), "node chroma"); + node->storage= c; + c->t1= 30.0f; + c->t2= 10.0f; + c->t3= 0.0f; + c->fsize= 0.0f; + c->fstrength= 1.0f; +}; + +bNodeType cmp_node_chroma={ + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_CHROMA, + /* name */ "Chroma Key", + /* width+range */ 200, 80, 300, + /* class+opts */ NODE_CLASS_MATTE, NODE_PREVIEW|NODE_OPTIONS, + /* input sock */ cmp_node_chroma_in, + /* output sock */ cmp_node_chroma_out, + /* storage */ "NodeChroma", + /* execfunc */ node_composit_exec_chroma_matte, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_chroma_matte, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL +}; + + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_colorSpill.c b/source/blender/nodes/intern/CMP_nodes/CMP_colorSpill.c new file mode 100644 index 00000000000..152180afc08 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_colorSpill.c @@ -0,0 +1,144 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + + +#include "../CMP_util.h" + + +/* ******************* Color Spill Supression ********************************* */ +static bNodeSocketType cmp_node_color_spill_in[]={ + {SOCK_RGBA,1,"Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + {-1,0,""} +}; + +static bNodeSocketType cmp_node_color_spill_out[]={ + {SOCK_RGBA,0,"Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + {-1,0,""} +}; + +static void do_reduce_red(bNode *node, float* out, float *in) +{ + NodeChroma *c; + c=node->storage; + + if(in[0] > in[1] && in[0] > in[2]) { + out[0]=((in[1]+in[2])/2)*(1-c->t1); + } +} + +static void do_reduce_green(bNode *node, float* out, float *in) +{ + NodeChroma *c; + c=node->storage; + + if(in[1] > in[0] && in[1] > in[2]) { + out[1]=((in[0]+in[2])/2)*(1-c->t1); + } +} + +static void do_reduce_blue(bNode *node, float* out, float *in) +{ + NodeChroma *c; + c=node->storage; + + if(in[2] > in[1] && in[2] > in[1]) { + out[2]=((in[1]+in[0])/2)*(1-c->t1); + } +} + +static void node_composit_exec_color_spill(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* + Originally based on the information from the book "The Art and Science of Digital Composition" and + discussions from vfxtalk.com.*/ + CompBuf *cbuf; + CompBuf *rgbbuf; + + if(out[0]->hasoutput==0 || in[0]->hasinput==0) return; + if(in[0]->data==NULL) return; + + cbuf=typecheck_compbuf(in[0]->data, CB_RGBA); + rgbbuf=dupalloc_compbuf(cbuf); + + switch(node->custom1) + { + case 1: /*red spill*/ + { + composit1_pixel_processor(node, rgbbuf, cbuf, in[1]->vec, do_reduce_red, CB_RGBA); + break; + } + case 2: /*green spill*/ + { + composit1_pixel_processor(node, rgbbuf, cbuf, in[1]->vec, do_reduce_green, CB_RGBA); + break; + } + case 3: /*blue spill*/ + { + composit1_pixel_processor(node, rgbbuf, cbuf, in[1]->vec, do_reduce_blue, CB_RGBA); + break; + } + default: + break; + } + + out[0]->data=rgbbuf; + + if(cbuf!=in[0]->data) + free_compbuf(cbuf); +} + +static void node_composit_init_color_spill(bNode *node) +{ + NodeChroma *c= MEM_callocN(sizeof(NodeChroma), "node chroma"); + node->storage=c; + c->t1= 0.0f; + c->t2= 0.0f; + c->t3= 0.0f; + c->fsize= 0.0f; + c->fstrength= 0.0f; + node->custom1= 2; /* green channel */ +} + +bNodeType cmp_node_color_spill={ + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_COLOR_SPILL, + /* name */ "Color Spill", + /* width+range */ 140, 80, 200, + /* class+opts */ NODE_CLASS_MATTE, NODE_OPTIONS, + /* input sock */ cmp_node_color_spill_in, + /* output sock */ cmp_node_color_spill_out, + /* storage */ "NodeChroma", + /* execfunc */ node_composit_exec_color_spill, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_color_spill, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL +}; + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_composite.c b/source/blender/nodes/intern/CMP_nodes/CMP_composite.c new file mode 100644 index 00000000000..89bd8e43694 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_composite.c @@ -0,0 +1,105 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + + + +/* **************** COMPOSITE ******************** */ +static bNodeSocketType cmp_node_composite_in[]= { + { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Z", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +/* applies to render pipeline */ +static void node_composit_exec_composite(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* image assigned to output */ + /* stack order input sockets: col, alpha, z */ + + if(node->flag & NODE_DO_OUTPUT) { /* only one works on out */ + RenderData *rd= data; + if(rd->scemode & R_DOCOMP) { + RenderResult *rr= RE_GetResult(RE_GetRender(G.scene->id.name)); /* G.scene is WEAK! */ + if(rr) { + CompBuf *outbuf, *zbuf=NULL; + + if(rr->rectf) + MEM_freeN(rr->rectf); + outbuf= alloc_compbuf(rr->rectx, rr->recty, CB_RGBA, 1); + + if(in[1]->data==NULL) + composit1_pixel_processor(node, outbuf, in[0]->data, in[0]->vec, do_copy_rgba, CB_RGBA); + else + composit2_pixel_processor(node, outbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_copy_a_rgba, CB_RGBA, CB_VAL); + + if(in[2]->data) { + if(rr->rectz) + MEM_freeN(rr->rectz); + zbuf= alloc_compbuf(rr->rectx, rr->recty, CB_VAL, 1); + composit1_pixel_processor(node, zbuf, in[2]->data, in[2]->vec, do_copy_value, CB_VAL); + rr->rectz= zbuf->rect; + zbuf->malloc= 0; + free_compbuf(zbuf); + } + generate_preview(node, outbuf); + + /* we give outbuf to rr... */ + rr->rectf= outbuf->rect; + outbuf->malloc= 0; + free_compbuf(outbuf); + + /* signal for imageviewer to refresh (it converts to byte rects...) */ + BKE_image_signal(BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"), NULL, IMA_SIGNAL_FREE); + return; + } + } + } + if(in[0]->data) + generate_preview(node, in[0]->data); +} + +bNodeType cmp_node_composite= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_COMPOSITE, + /* name */ "Composite", + /* width+range */ 80, 60, 200, + /* class+opts */ NODE_CLASS_OUTPUT, NODE_PREVIEW, + /* input sock */ cmp_node_composite_in, + /* output sock */ NULL, + /* storage */ "", + /* execfunc */ node_composit_exec_composite, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_crop.c b/source/blender/nodes/intern/CMP_nodes/CMP_crop.c new file mode 100644 index 00000000000..f3a00dec084 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_crop.c @@ -0,0 +1,119 @@ +/** + * + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Juho Vepsäläinen + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + +/* **************** Crop ******************** */ + +static bNodeSocketType cmp_node_crop_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_crop_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_composit_exec_crop(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + if(in[0]->data) { + NodeTwoXYs *ntxy= node->storage; + CompBuf *cbuf= in[0]->data; + CompBuf *stackbuf; + int x, y; + float *srcfp, *outfp; + rcti outputrect; + + /* check input image size */ + if(cbuf->x <= ntxy->x1 + 1) + ntxy->x1= cbuf->x - 1; + + if(cbuf->y <= ntxy->y1 + 1) + ntxy->y1= cbuf->y - 1; + + if(cbuf->x <= ntxy->x2 + 1) + ntxy->x2= cbuf->x - 1; + + if(cbuf->y <= ntxy->y2 + 1) + ntxy->y2= cbuf->y - 1; + + /* figure out the minimums and maximums */ + outputrect.xmax=MAX2(ntxy->x1, ntxy->x2) + 1; + outputrect.xmin=MIN2(ntxy->x1, ntxy->x2); + outputrect.ymax=MAX2(ntxy->y1, ntxy->y2) + 1; + outputrect.ymin=MIN2(ntxy->y1, ntxy->y2); + + if(node->custom1) { + /* this option crops the image size too */ + stackbuf= get_cropped_compbuf(&outputrect, cbuf->rect, cbuf->x, cbuf->y, cbuf->type); + } + else { + /* this option won't crop the size of the image as well */ + /* allocate memory for the output image */ + stackbuf = alloc_compbuf(cbuf->x, cbuf->y, cbuf->type, 1); + + /* select the cropped part of the image and set it to the output */ + for(y=outputrect.ymin; yrect + (y * cbuf->x + outputrect.xmin) * cbuf->type; + outfp= stackbuf->rect + (y * stackbuf->x + outputrect.xmin) * stackbuf->type; + for(x=outputrect.xmin; xtype, srcfp+= cbuf->type) + memcpy(outfp, srcfp, sizeof(float)*stackbuf->type); + } + } + + out[0]->data= stackbuf; + } +} + +static void node_composit_init_crop(bNode* node) +{ + NodeTwoXYs *nxy= MEM_callocN(sizeof(NodeTwoXYs), "node xy data"); + node->storage= nxy; + nxy->x1= 0; + nxy->x2= 0; + nxy->y1= 0; + nxy->y2= 0; +} + +bNodeType cmp_node_crop= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_CROP, + /* name */ "Crop", + /* width+range */ 140, 100, 320, + /* class+opts */ NODE_CLASS_DISTORT, NODE_OPTIONS, + /* input sock */ cmp_node_crop_in, + /* output sock */ cmp_node_crop_out, + /* storage */ "NodeTwoXYs", + /* execfunc */ node_composit_exec_crop, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_crop, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL +}; diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_curves.c b/source/blender/nodes/intern/CMP_nodes/CMP_curves.c new file mode 100644 index 00000000000..17d9821a5ef --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_curves.c @@ -0,0 +1,206 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + + +/* **************** CURVE Time ******************** */ + +/* custom1 = sfra, custom2 = efra */ +static bNodeSocketType cmp_node_time_out[]= { + { SOCK_VALUE, 0, "Fac", 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_composit_exec_curves_time(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order output: fac */ + float fac= 0.0f; + + if(node->custom1 < node->custom2) + fac= (G.scene->r.cfra - node->custom1)/(float)(node->custom2-node->custom1); + + fac= curvemapping_evaluateF(node->storage, 0, fac); + out[0]->vec[0]= CLAMPIS(fac, 0.0f, 1.0f); +} + + +static void node_composit_init_curves_time(bNode* node) +{ + node->custom1= G.scene->r.sfra; + node->custom2= G.scene->r.efra; + node->storage= curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); +} + +bNodeType cmp_node_curve_time= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_TIME, + /* name */ "Time", + /* width+range */ 140, 100, 320, + /* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS, + /* input sock */ NULL, + /* output sock */ cmp_node_time_out, + /* storage */ "CurveMapping", + /* execfunc */ node_composit_exec_curves_time, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_curves_time, + /* freestoragefunc */ node_free_curves, + /* copystoragefunc */ node_copy_curves, + /* id */ NULL +}; + + + +/* **************** CURVE VEC ******************** */ +static bNodeSocketType cmp_node_curve_vec_in[]= { + { SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, + { -1, 0, "" } +}; + +static bNodeSocketType cmp_node_curve_vec_out[]= { + { SOCK_VECTOR, 0, "Vector", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_composit_exec_curve_vec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order input: vec */ + /* stack order output: vec */ + + curvemapping_evaluate_premulRGBF(node->storage, out[0]->vec, in[0]->vec); +}; + +static void node_composit_init_curve_vec(bNode* node) +{ + node->storage= curvemapping_add(3, -1.0f, -1.0f, 1.0f, 1.0f); +}; + +bNodeType cmp_node_curve_vec= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_CURVE_VEC, + /* name */ "Vector Curves", + /* width+range */ 200, 140, 320, + /* class+opts */ NODE_CLASS_OP_VECTOR, NODE_OPTIONS, + /* input sock */ cmp_node_curve_vec_in, + /* output sock */ cmp_node_curve_vec_out, + /* storage */ "CurveMapping", + /* execfunc */ node_composit_exec_curve_vec, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_curve_vec, + /* freestoragefunc */ node_free_curves, + /* copystoragefunc */ node_copy_curves, + /* id */ NULL + +}; + +/* **************** CURVE RGB ******************** */ +static bNodeSocketType cmp_node_curve_rgb_in[]= { + { SOCK_VALUE, 1, "Fac", 1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, + { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, + { -1, 0, "" } +}; + +static bNodeSocketType cmp_node_curve_rgb_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_curves(bNode *node, float *out, float *in) +{ + curvemapping_evaluate_premulRGBF(node->storage, out, in); + out[3]= in[3]; +} + +static void do_curves_fac(bNode *node, float *out, float *in, float *fac) +{ + + if(*fac>=1.0) + curvemapping_evaluate_premulRGBF(node->storage, out, in); + else if(*fac<=0.0) { + VECCOPY(out, in); + } + else { + float col[4], mfac= 1.0f-*fac; + curvemapping_evaluate_premulRGBF(node->storage, col, in); + out[0]= mfac*in[0] + *fac*col[0]; + out[1]= mfac*in[1] + *fac*col[1]; + out[2]= mfac*in[2] + *fac*col[2]; + } + out[3]= in[3]; +} + +static void node_composit_exec_curve_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order input: fac, image */ + /* stack order output: image */ + + if(out[0]->hasoutput==0) + return; + + /* input no image? then only color operation */ + if(in[1]->data==NULL) { + curvemapping_evaluateRGBF(node->storage, out[0]->vec, in[1]->vec); + } + else { + /* make output size of input image */ + CompBuf *cbuf= in[1]->data; + CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */ + + if(in[0]->vec[0] == 1.0) + composit1_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, do_curves, CB_RGBA); + else + composit2_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[0]->data, in[0]->vec, do_curves_fac, CB_RGBA, CB_VAL); + + out[0]->data= stackbuf; + } + +}; + +static void node_composit_init_curve_rgb(bNode* node) +{ + node->storage= curvemapping_add(4, 0.0f, 0.0f, 1.0f, 1.0f); +}; + +bNodeType cmp_node_curve_rgb= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_CURVE_RGB, + /* name */ "RGB Curves", + /* width+range */ 200, 140, 320, + /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS, + /* input sock */ cmp_node_curve_rgb_in, + /* output sock */ cmp_node_curve_rgb_out, + /* storage */ "CurveMapping", + /* execfunc */ node_composit_exec_curve_rgb, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_curve_rgb, + /* freestoragefunc */ node_free_curves, + /* copystoragefunc */ node_copy_curves, + /* id */ NULL +}; + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_defocus.c b/source/blender/nodes/intern/CMP_nodes/CMP_defocus.c new file mode 100644 index 00000000000..53d01ab1d12 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_defocus.c @@ -0,0 +1,855 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + +/* ************ qdn: Defocus node ****************** */ +static bNodeSocketType cmp_node_defocus_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Z", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_defocus_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + + +// line coefs for point sampling & scancon. data. +typedef struct BokehCoeffs { + float x0, y0, dx, dy; + float ls_x, ls_y; + float min_x, min_y, max_x, max_y; +} BokehCoeffs; + +// returns array of BokehCoeffs +// returns length of array in 'len_bkh', +// radius squared of inscribed disk in 'inradsq', needed in getWeight() test, +// BKH[8] is the data returned for the bokeh shape & bkh_b[4] is it's 2d bound +static void makeBokeh(char bktype, char ro, int* len_bkh, float* inradsq, BokehCoeffs BKH[8], float bkh_b[4]) +{ + float x0, x1, y0, y1, dx, dy, iDxy; + float w = MAX2(1e-5f, ro)*M_PI/180.f; // never reported stangely enough, but a zero offset causes missing center line... + float wi = (360.f/bktype)*M_PI/180.f; + int i, ov, nv; + + // bktype must be at least 3 & <= 8 + bktype = (bktype<3) ? 3 : ((bktype>8) ? 8 : bktype); + *len_bkh = bktype; + *inradsq = -1.f; + + for (i=0; i<(*len_bkh); i++) { + x0 = cos(w); + y0 = sin(w); + w += wi; + x1 = cos(w); + y1 = sin(w); + if ((*inradsq)<0.f) { + // radius squared of inscribed disk + float idx=(x0+x1)*0.5f, idy=(y0+y1)*0.5f; + *inradsq = idx*idx + idy*idy; + } + BKH[i].x0 = x0; + BKH[i].y0 = y0; + dx = x1-x0, dy = y1-y0; + iDxy = 1.f / sqrt(dx*dx + dy*dy); + dx *= iDxy; + dy *= iDxy; + BKH[i].dx = dx; + BKH[i].dy = dy; + } + + // precalc scanconversion data + // bokeh bound, not transformed, for scanconvert + bkh_b[0] = bkh_b[2] = 1e10f; // xmin/ymin + bkh_b[1] = bkh_b[3] = -1e10f; // xmax/ymax + ov = (*len_bkh) - 1; + for (nv=0; nv<(*len_bkh); nv++) { + bkh_b[0] = MIN2(bkh_b[0], BKH[nv].x0); // xmin + bkh_b[1] = MAX2(bkh_b[1], BKH[nv].x0); // xmax + bkh_b[2] = MIN2(bkh_b[2], BKH[nv].y0); // ymin + bkh_b[3] = MAX2(bkh_b[3], BKH[nv].y0); // ymax + BKH[nv].min_x = MIN2(BKH[ov].x0, BKH[nv].x0); + BKH[nv].max_x = MAX2(BKH[ov].x0, BKH[nv].x0); + BKH[nv].min_y = MIN2(BKH[ov].y0, BKH[nv].y0); + BKH[nv].max_y = MAX2(BKH[ov].y0, BKH[nv].y0); + dy = BKH[nv].y0 - BKH[ov].y0; + BKH[nv].ls_x = (BKH[nv].x0 - BKH[ov].x0) / ((dy==0.f) ? 1.f : dy); + BKH[nv].ls_y = (BKH[nv].ls_x==0.f) ? 1.f : (1.f/BKH[nv].ls_x); + ov = nv; + } +} + +// test if u/v inside shape & returns weight value +static float getWeight(BokehCoeffs* BKH, int len_bkh, float u, float v, float rad, float inradsq) +{ + BokehCoeffs* bc = BKH; + float cdist, irad = (rad==0.f) ? 1.f : (1.f/rad); + u *= irad; + v *= irad; + + // early out test1: if point outside outer unit disk, it cannot be inside shape + cdist = u*u + v*v; + if (cdist>1.f) return 0.f; + + // early out test2: if point inside or on inner disk, point must be inside shape + if (cdist<=inradsq) return 1.f; + + while (len_bkh--) { + if ((bc->dy*(u - bc->x0) - bc->dx*(v - bc->y0)) > 0.f) return 0.f; + bc++; + } + return 1.f; +} + +// QMC.seq. for sampling, A.Keller, EMS +static float RI_vdC(unsigned int bits, unsigned int r) +{ + bits = ( bits << 16) | ( bits >> 16); + bits = ((bits & 0x00ff00ff) << 8) | ((bits & 0xff00ff00) >> 8); + bits = ((bits & 0x0f0f0f0f) << 4) | ((bits & 0xf0f0f0f0) >> 4); + bits = ((bits & 0x33333333) << 2) | ((bits & 0xcccccccc) >> 2); + bits = ((bits & 0x55555555) << 1) | ((bits & 0xaaaaaaaa) >> 1); + bits ^= r; + return (float)((double)bits / 4294967296.0); +} + +// single channel IIR gaussian filtering +// much faster than anything else, constant time independent of width +// should extend to multichannel and make this a node, could be useful +static void IIR_gauss_single(CompBuf* buf, float sigma) +{ + double q, q2, sc, cf[4], tsM[9], tsu[3], tsv[3]; + float *X, *Y, *W; + int i, x, y, sz; + + // single channel only for now + if (buf->type != CB_VAL) return; + + // <0.5 not valid, though can have a possibly useful sort of sharpening effect + if (sigma < 0.5) return; + + // see "Recursive Gabor Filtering" by Young/VanVliet + // all factors here in double.prec. Required, because for single.prec it seems to blow up if sigma > ~200 + if (sigma >= 3.556) + q = 0.9804*(sigma - 3.556) + 2.5091; + else // sigma >= 0.5 + q = (0.0561*sigma + 0.5784)*sigma - 0.2568; + q2 = q*q; + sc = (1.1668 + q)*(3.203729649 + (2.21566 + q)*q); + // no gabor filtering here, so no complex multiplies, just the regular coefs. + // all negated here, so as not to have to recalc Triggs/Sdika matrix + cf[1] = q*(5.788961737 + (6.76492 + 3.0*q)*q)/ sc; + cf[2] = -q2*(3.38246 + 3.0*q)/sc; + // 0 & 3 unchanged + cf[3] = q2*q/sc; + cf[0] = 1.0 - cf[1] - cf[2] - cf[3]; + + // Triggs/Sdika border corrections, + // it seems to work, not entirely sure if it is actually totally correct, + // Besides J.M.Geusebroek's anigauss.c (see http://www.science.uva.nl/~mark), + // found one other implementation by Cristoph Lampert, + // but neither seem to be quite the same, result seems to be ok sofar anyway. + // Extra scale factor here to not have to do it in filter, + // though maybe this had something to with the precision errors + sc = cf[0]/((1.0 + cf[1] - cf[2] + cf[3])*(1.0 - cf[1] - cf[2] - cf[3])*(1.0 + cf[2] + (cf[1] - cf[3])*cf[3])); + tsM[0] = sc*(-cf[3]*cf[1] + 1.0 - cf[3]*cf[3] - cf[2]); + tsM[1] = sc*((cf[3] + cf[1])*(cf[2] + cf[3]*cf[1])); + tsM[2] = sc*(cf[3]*(cf[1] + cf[3]*cf[2])); + tsM[3] = sc*(cf[1] + cf[3]*cf[2]); + tsM[4] = sc*(-(cf[2] - 1.0)*(cf[2] + cf[3]*cf[1])); + tsM[5] = sc*(-(cf[3]*cf[1] + cf[3]*cf[3] + cf[2] - 1.0)*cf[3]); + tsM[6] = sc*(cf[3]*cf[1] + cf[2] + cf[1]*cf[1] - cf[2]*cf[2]); + tsM[7] = sc*(cf[1]*cf[2] + cf[3]*cf[2]*cf[2] - cf[1]*cf[3]*cf[3] - cf[3]*cf[3]*cf[3] - cf[3]*cf[2] + cf[3]); + tsM[8] = sc*(cf[3]*(cf[1] + cf[3]*cf[2])); + +#define YVV(L)\ +{\ + W[0] = cf[0]*X[0] + cf[1]*X[0] + cf[2]*X[0] + cf[3]*X[0];\ + W[1] = cf[0]*X[1] + cf[1]*W[0] + cf[2]*X[0] + cf[3]*X[0];\ + W[2] = cf[0]*X[2] + cf[1]*W[1] + cf[2]*W[0] + cf[3]*X[0];\ + for (i=3; i=0; i--)\ + Y[i] = cf[0]*W[i] + cf[1]*Y[i+1] + cf[2]*Y[i+2] + cf[3]*Y[i+3];\ +} + + // intermediate buffers + sz = MAX2(buf->x, buf->y); + Y = MEM_callocN(sz*sizeof(float), "IIR_gauss Y buf"); + W = MEM_callocN(sz*sizeof(float), "IIR_gauss W buf"); + // H + for (y=0; yy; y++) { + X = &buf->rect[y*buf->x]; + YVV(buf->x); + memcpy(X, Y, sizeof(float)*buf->x); + } + // V + X = MEM_callocN(buf->y*sizeof(float), "IIR_gauss X buf"); + for (x=0; xx; x++) { + for (y=0; yy; y++) + X[y] = buf->rect[x + y*buf->x]; + YVV(buf->y); + for (y=0; yy; y++) + buf->rect[x + y*buf->x] = Y[y]; + } + MEM_freeN(X); + + MEM_freeN(W); + MEM_freeN(Y); +#undef YVV +} + +static void defocus_blur(bNode *node, CompBuf *new, CompBuf *img, CompBuf *zbuf, float inpval) +{ + NodeDefocus *nqd = node->storage; + CompBuf *wts; // weights buffer + CompBuf *crad; // CoC radius buffer + BokehCoeffs BKH[8]; // bokeh shape data, here never > 8 pts. + float bkh_b[4] = {0}; // shape 2D bound + unsigned int p, px, p4, zp, cp, cp4; + float *ctcol, u, v, iZ, ct_crad, lwt, wt=0, cR2=0; + float dof_sp, maxfgc, bk_hn_theta=0, inradsq=0; + float cam_fdist=1, cam_invfdist=1, cam_lens=35; + int x, y, sx, sy, len_bkh=0; + float aspect, aperture; + int minsz; + //float bcrad, nmaxc, scf; + + // get some required params from the current scene camera + // (ton) this is wrong, needs fixed + Object* camob = G.scene->camera; + if (camob && camob->type==OB_CAMERA) { + Camera* cam = (Camera*)camob->data; + cam_lens = cam->lens; + cam_fdist = dof_camera(camob); + if (cam_fdist==0.0) cam_fdist = 1e10f; /* if the dof is 0.0 then set it be be far away */ + cam_invfdist = 1.f/cam_fdist; + } + + // guess work here.. best match with raytraced result + minsz = MIN2(img->x, img->y); + dof_sp = (float)minsz / (16.f / cam_lens); // <- == aspect * MIN2(img->x, img->y) / tan(0.5f * fov); + + // aperture + aspect = (img->x > img->y) ? (img->y / (float)img->x) : (img->x / (float)img->y); + aperture = 0.5f*(cam_lens / (aspect*32.f)) / nqd->fstop; + + // if not disk, make bokeh coefficients and other needed data + if (nqd->bktype!=0) { + makeBokeh(nqd->bktype, nqd->rotation, &len_bkh, &inradsq, BKH, bkh_b); + bk_hn_theta = 0.5 * nqd->bktype * sin(2.0 * M_PI / nqd->bktype); // weight factor + } + + // accumulated weights + wts = alloc_compbuf(img->x, img->y, CB_VAL, 1); + // CoC radius buffer + crad = alloc_compbuf(img->x, img->y, CB_VAL, 1); + + // if 'no_zbuf' flag set (which is always set if input is not an image), + // values are instead interpreted directly as blur radius values + if (nqd->no_zbuf) { + // to prevent *reaaallly* big radius values and impossible calculation times, + // limit the maximum to half the image width or height, whichever is smaller + float maxr = 0.5f*(float)MIN2(img->x, img->y); + for (p=0; p<(unsigned int)(img->x*img->y); p++) { + crad->rect[p] = zbuf ? (zbuf->rect[p]*nqd->scale) : inpval; + // bug #5921, limit minimum + crad->rect[p] = MAX2(1e-5f, crad->rect[p]); + crad->rect[p] = MIN2(crad->rect[p], maxr); + // if maxblur!=0, limit maximum + if (nqd->maxblur != 0.f) crad->rect[p] = MIN2(crad->rect[p], nqd->maxblur); + } + } + else { + // actual zbuffer. + // separate foreground from background CoC's + // then blur background and blend in again with foreground, + // improves the 'blurred foreground overlapping in-focus midground' sharp boundary problem. + // wts buffer here used for blendmask + maxfgc = 0.f; // maximum foreground CoC radius + for (y=0; yy; y++) { + p = y * img->x; + for (x=0; xx; x++) { + px = p + x; + iZ = (zbuf->rect[px]==0.f) ? 0.f : (1.f/zbuf->rect[px]); + crad->rect[px] = 0.5f*(aperture*(dof_sp*(cam_invfdist - iZ) - 1.f)); + if (crad->rect[px] <= 0.f) { + wts->rect[px] = 1.f; + crad->rect[px] = -crad->rect[px]; + if (crad->rect[px] > maxfgc) maxfgc = crad->rect[px]; + } + else crad->rect[px] = wts->rect[px] = 0; + } + } + + // fast blur... + // bug #6656 part 1, probably when previous node_composite.c was split into separate files, it was not properly updated + // to include recent cvs commits (well, at least not defocus node), so this part was missing... + wt = aperture*128.f; + IIR_gauss_single(crad, wt); + IIR_gauss_single(wts, wt); + + // bug #6656 part 2a, although foreground blur is not based anymore on closest object, + // the rescaling op below was still based on that anyway, and unlike the comment in below code, + // the difference is therefore not always that small at all... + // so for now commented out, not sure if this is going to cause other future problems, lets just wait and see... + /* + // find new maximum to scale it back to original + // (could skip this, not strictly necessary, in general, difference is quite small, but just in case...) + nmaxc = 0; + for (p=0; p<(img->x*img->y); p++) + if (crad->rect[p] > nmaxc) nmaxc = crad->rect[p]; + // rescale factor + scf = (nmaxc==0.f) ? 1.f: (maxfgc / nmaxc); + */ + + // and blend... + for (y=0; yy; y++) { + p = y*img->x; + for (x=0; xx; x++) { + px = p + x; + if (zbuf->rect[px]!=0.f) { + iZ = (zbuf->rect[px]==0.f) ? 0.f : (1.f/zbuf->rect[px]); + + // bug #6656 part 2b, do not rescale + /* + bcrad = 0.5f*fabs(aperture*(dof_sp*(cam_invfdist - iZ) - 1.f)); + // scale crad back to original maximum and blend + crad->rect[px] = bcrad + wts->rect[px]*(scf*crad->rect[px] - bcrad); + */ + crad->rect[px] = 0.5f*fabs(aperture*(dof_sp*(cam_invfdist - iZ) - 1.f)); + + // 'bug' #6615, limit minimum radius to 1 pixel, not really a solution, but somewhat mitigates the problem + crad->rect[px] = MAX2(crad->rect[px], 0.5f); + // if maxblur!=0, limit maximum + if (nqd->maxblur != 0.f) crad->rect[px] = MIN2(crad->rect[px], nqd->maxblur); + } + else crad->rect[px] = 0.f; + // clear weights for next part + wts->rect[px] = 0.f; + } + // esc set by main calling process + if(node->exec & NODE_BREAK) + break; + } + } + + //------------------------------------------------------------------ + // main loop + for (y=0; yy; y++) { + // some sort of visual feedback would be nice, or at least this text in the renderwin header + // but for now just print some info in the console every 8 scanlines. + if (((y & 7)==0) || (y==(img->y-1))) { + printf("\rdefocus: Processing Line %d of %d ... ", y+1, img->y); + fflush(stdout); + } + // esc set by main calling process + if(node->exec & NODE_BREAK) + break; + + zp = y * img->x; + for (x=0; xx; x++) { + cp = zp + x; + cp4 = cp * img->type; + + // Circle of Confusion radius for current pixel + cR2 = ct_crad = crad->rect[cp]; + // skip if zero (border render) + if (ct_crad==0.f) { + // related to bug #5921, forgot output image when skipping 0 radius values + new->rect[cp4] = img->rect[cp4]; + if (new->type != CB_VAL) { + new->rect[cp4+1] = img->rect[cp4+1]; + new->rect[cp4+2] = img->rect[cp4+2]; + new->rect[cp4+3] = img->rect[cp4+3]; + } + continue; + } + cR2 *= cR2; + + // pixel color + ctcol = &img->rect[cp4]; + + if (!nqd->preview) { + int xs, xe, ys, ye; + float lwt, wtcol[4] = {0}, aacol[4] = {0}; + + // shape weight + if (nqd->bktype==0) // disk + wt = 1.f/((float)M_PI*cR2); + else + wt = 1.f/(cR2*bk_hn_theta); + + // weighted color + wtcol[0] = wt*ctcol[0]; + if (new->type != CB_VAL) { + wtcol[1] = wt*ctcol[1]; + wtcol[2] = wt*ctcol[2]; + wtcol[3] = wt*ctcol[3]; + } + + // macro for background blur overlap test + // unfortunately, since this is done per pixel, + // it has a very significant negative impact on processing time... + // (eg. aa disk blur without test: 112 sec, vs with test: 176 sec...) + // iff center blur radius > threshold + // and if overlap pixel in focus, do nothing, else add color/weigbt + // (threshold constant is dependant on amount of blur) + #define TESTBG1(c, w) {\ + if (ct_crad > nqd->bthresh) {\ + if (crad->rect[p] > nqd->bthresh) {\ + new->rect[p] += c[0];\ + wts->rect[p] += w;\ + }\ + }\ + else {\ + new->rect[p] += c[0];\ + wts->rect[p] += w;\ + }\ + } + #define TESTBG4(c, w) {\ + if (ct_crad > nqd->bthresh) {\ + if (crad->rect[p] > nqd->bthresh) {\ + new->rect[p4] += c[0];\ + new->rect[p4+1] += c[1];\ + new->rect[p4+2] += c[2];\ + new->rect[p4+3] += c[3];\ + wts->rect[p] += w;\ + }\ + }\ + else {\ + new->rect[p4] += c[0];\ + new->rect[p4+1] += c[1];\ + new->rect[p4+2] += c[2];\ + new->rect[p4+3] += c[3];\ + wts->rect[p] += w;\ + }\ + } + if (nqd->bktype == 0) { + // Disk + int _x, i, j, di; + float Dj, T; + // AA pixel + #define AAPIX(a, b) {\ + int _ny = b;\ + if ((_ny >= 0) && (_ny < new->y)) {\ + int _nx = a;\ + if ((_nx >=0) && (_nx < new->x)) {\ + p = _ny*new->x + _nx;\ + if (new->type==CB_VAL) {\ + TESTBG1(aacol, lwt);\ + }\ + else {\ + p4 = p * new->type;\ + TESTBG4(aacol, lwt);\ + }\ + }\ + }\ + } + // circle scanline + #define CSCAN(a, b) {\ + int _ny = y + b;\ + if ((_ny >= 0) && (_ny < new->y)) {\ + xs = x - a + 1;\ + if (xs < 0) xs = 0;\ + xe = x + a;\ + if (xe > new->x) xe = new->x;\ + p = _ny*new->x + xs;\ + if (new->type==CB_VAL) {\ + for (_x=xs; _xtype;\ + for (_x=xs; _xtype) TESTBG4(wtcol, wt);\ + }\ + }\ + } + i = ceil(ct_crad); + j = 0; + T = 0; + while (i > j) { + Dj = sqrt(cR2 - j*j); + Dj -= floor(Dj); + di = 0; + if (Dj > T) { i--; di = 1; } + T = Dj; + aacol[0] = wtcol[0]*Dj; + if (new->type != CB_VAL) { + aacol[1] = wtcol[1]*Dj; + aacol[2] = wtcol[2]*Dj; + aacol[3] = wtcol[3]*Dj; + } + lwt = wt*Dj; + if (i!=j) { + // outer pixels + AAPIX(x+j, y+i); + AAPIX(x+j, y-i); + if (j) { + AAPIX(x-j, y+i); // BL + AAPIX(x-j, y-i); // TL + } + if (di) { // only when i changed, interior of outer section + CSCAN(j, i); // bottom + CSCAN(j, -i); // top + } + } + // lower mid section + AAPIX(x+i, y+j); + if (i) AAPIX(x-i, y+j); + CSCAN(i, j); + // upper mid section + if (j) { + AAPIX(x+i, y-j); + if (i) AAPIX(x-i, y-j); + CSCAN(i, -j); + } + j++; + } + #undef CSCAN + #undef AAPIX + } + else { + // n-agonal + int ov, nv; + float mind, maxd, lwt; + ys = MAX2((int)floor(bkh_b[2]*ct_crad + y), 0); + ye = MIN2((int)ceil(bkh_b[3]*ct_crad + y), new->y - 1); + for (sy=ys; sy<=ye; sy++) { + float fxs = 1e10f, fxe = -1e10f; + float yf = (sy - y)/ct_crad; + int found = 0; + ov = len_bkh - 1; + mind = maxd = 0; + for (nv=0; nv= yf) && (BKH[nv].min_y <= yf)) { + float tx = BKH[ov].x0 + BKH[nv].ls_x*(yf - BKH[ov].y0); + if (tx < fxs) { fxs = tx; mind = BKH[nv].ls_x; } + if (tx > fxe) { fxe = tx; maxd = BKH[nv].ls_x; } + if (++found == 2) break; + } + ov = nv; + } + if (found) { + fxs = fxs*ct_crad + x; + fxe = fxe*ct_crad + x; + xs = (int)floor(fxs), xe = (int)ceil(fxe); + // AA hack for first and last x pixel, near vertical edges only + if (fabs(mind) <= 1.f) { + if ((xs >= 0) && (xs < new->x)) { + lwt = 1.f-(fxs - xs); + aacol[0] = wtcol[0]*lwt; + p = xs + sy*new->x; + if (new->type==CB_VAL) { + lwt *= wt; + TESTBG1(aacol, lwt); + } + else { + p4 = p * new->type; + aacol[1] = wtcol[1]*lwt; + aacol[2] = wtcol[2]*lwt; + aacol[3] = wtcol[3]*lwt; + lwt *= wt; + TESTBG4(aacol, lwt); + } + } + } + if (fabs(maxd) <= 1.f) { + if ((xe >= 0) && (xe < new->x)) { + lwt = 1.f-(xe - fxe); + aacol[0] = wtcol[0]*lwt; + p = xe + sy*new->x; + if (new->type==CB_VAL) { + lwt *= wt; + TESTBG1(aacol, lwt); + } + else { + p4 = p * new->type; + aacol[1] = wtcol[1]*lwt; + aacol[2] = wtcol[2]*lwt; + aacol[3] = wtcol[3]*lwt; + lwt *= wt; + TESTBG4(aacol, lwt); + } + } + } + xs = MAX2(xs+1, 0); + xe = MIN2(xe, new->x); + // remaining interior scanline + p = sy*new->x + xs; + if (new->type==CB_VAL) { + for (sx=xs; sxtype; + for (sx=xs; sxtype) TESTBG4(wtcol, wt); + } + } + } + + // now traverse in opposite direction, y scanlines, + // but this time only draw the near horizontal edges, + // applying same AA hack as above + xs = MAX2((int)floor(bkh_b[0]*ct_crad + x), 0); + xe = MIN2((int)ceil(bkh_b[1]*ct_crad + x), img->x - 1); + for (sx=xs; sx<=xe; sx++) { + float xf = (sx - x)/ct_crad; + float fys = 1e10f, fye = -1e10f; + int found = 0; + ov = len_bkh - 1; + mind = maxd = 0; + for (nv=0; nv= xf) && (BKH[nv].min_x <= xf)) { + float ty = BKH[ov].y0 + BKH[nv].ls_y*(xf - BKH[ov].x0); + if (ty < fys) { fys = ty; mind = BKH[nv].ls_y; } + if (ty > fye) { fye = ty; maxd = BKH[nv].ls_y; } + if (++found == 2) break; + } + ov = nv; + } + if (found) { + fys = fys*ct_crad + y; + fye = fye*ct_crad + y; + // near horizontal edges only, line slope <= 1 + if (fabs(mind) <= 1.f) { + int iys = (int)floor(fys); + if ((iys >= 0) && (iys < new->y)) { + lwt = 1.f - (fys - iys); + aacol[0] = wtcol[0]*lwt; + p = sx + iys*new->x; + if (new->type==CB_VAL) { + lwt *= wt; + TESTBG1(aacol, lwt); + } + else { + p4 = p * new->type; + aacol[1] = wtcol[1]*lwt; + aacol[2] = wtcol[2]*lwt; + aacol[3] = wtcol[3]*lwt; + lwt *= wt; + TESTBG4(aacol, lwt); + } + } + } + if (fabs(maxd) <= 1.f) { + int iye = ceil(fye); + if ((iye >= 0) && (iye < new->y)) { + lwt = 1.f - (iye - fye); + aacol[0] = wtcol[0]*lwt; + p = sx + iye*new->x; + if (new->type==CB_VAL) { + lwt *= wt; + TESTBG1(aacol, lwt); + } + else { + p4 = p * new->type; + aacol[1] = wtcol[1]*lwt; + aacol[2] = wtcol[2]*lwt; + aacol[3] = wtcol[3]*lwt; + lwt *= wt; + TESTBG4(aacol, lwt); + } + } + } + } + } + + } + #undef TESTBG4 + #undef TESTBG1 + + } + else { + // sampled, simple rejection sampling here, good enough + unsigned int maxsam, s, ui = BLI_rand()*BLI_rand(); + float wcor, cpr = BLI_frand(); + if (nqd->no_zbuf) + maxsam = nqd->samples; // no zbuffer input, use sample value directly + else { + // depth adaptive sampling hack, the more out of focus, the more samples taken, 16 minimum. + maxsam = (int)(0.5f + nqd->samples*(1.f-(float)exp(-fabs(zbuf->rect[cp] - cam_fdist)))); + if (maxsam < 16) maxsam = 16; + } + wcor = 1.f/(float)maxsam; + for (s=0; s= new->x) || (sy<0) || (sy >= new->y)) continue; + p = sx + sy*new->x; + p4 = p * new->type; + if (nqd->bktype==0) // Disk + lwt = ((u*u + v*v)<=cR2) ? wcor : 0.f; + else // AA not needed here + lwt = wcor * getWeight(BKH, len_bkh, u, v, ct_crad, inradsq); + // prevent background bleeding onto in-focus pixels, user-option + if (ct_crad > nqd->bthresh) { // if center blur > threshold + if (crad->rect[p] > nqd->bthresh) { // if overlap pixel in focus, do nothing, else add color/weigbt + new->rect[p4] += ctcol[0] * lwt; + if (new->type != CB_VAL) { + new->rect[p4+1] += ctcol[1] * lwt; + new->rect[p4+2] += ctcol[2] * lwt; + new->rect[p4+3] += ctcol[3] * lwt; + } + wts->rect[p] += lwt; + } + } + else { + new->rect[p4] += ctcol[0] * lwt; + if (new->type != CB_VAL) { + new->rect[p4+1] += ctcol[1] * lwt; + new->rect[p4+2] += ctcol[2] * lwt; + new->rect[p4+3] += ctcol[3] * lwt; + } + wts->rect[p] += lwt; + } + } + } + + } + } + + // finally, normalize + for (y=0; yy; y++) { + p = y * new->x; + p4 = p * new->type; + for (x=0; xx; x++) { + float dv = (wts->rect[p]==0.f) ? 1.f : (1.f/wts->rect[p]); + new->rect[p4] *= dv; + if (new->type!=CB_VAL) { + new->rect[p4+1] *= dv; + new->rect[p4+2] *= dv; + new->rect[p4+3] *= dv; + } + p++; + p4 += new->type; + } + } + + free_compbuf(crad); + free_compbuf(wts); + + printf("Done\n"); +} + + +static void node_composit_exec_defocus(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + CompBuf *new, *old, *zbuf_use = NULL, *img = in[0]->data, *zbuf = in[1]->data; + NodeDefocus *nqd = node->storage; + + if ((img==NULL) || (out[0]->hasoutput==0)) return; + + // if image not valid type or fstop==infinite (128), nothing to do, pass in to out + if (((img->type!=CB_RGBA) && (img->type!=CB_VAL)) || ((nqd->no_zbuf==0) && (nqd->fstop==128.f))) { + new = alloc_compbuf(img->x, img->y, img->type, 0); + new->rect = img->rect; + out[0]->data = new; + return; + } + + if (zbuf!=NULL) { + // Zbuf input, check to make sure, single channel, same size + // doesn't have to be actual zbuffer, but must be value type + if ((zbuf->x != img->x) || (zbuf->y != img->y)) { + // could do a scale here instead... + printf("Z input must be same size as image !\n"); + return; + } + zbuf_use = typecheck_compbuf(zbuf, CB_VAL); + } + else nqd->no_zbuf = 1; // no zbuffer input + + // ok, process + old = img; + if (nqd->gamco) { + // gamma correct, blender func is simplified, fixed value & RGBA only, should make user param + old = dupalloc_compbuf(img); + gamma_correct_compbuf(old, 0); + } + + new = alloc_compbuf(old->x, old->y, old->type, 1); + defocus_blur(node, new, old, zbuf_use, in[1]->vec[0]*nqd->scale); + + if (nqd->gamco) { + gamma_correct_compbuf(new, 1); + free_compbuf(old); + } + if(node->exec & NODE_BREAK) { + free_compbuf(new); + new= NULL; + } + out[0]->data = new; + if (zbuf_use && (zbuf_use != zbuf)) free_compbuf(zbuf_use); +} + +static void node_composit_init_defocus(bNode* node) +{ + /* qdn: defocus node */ + NodeDefocus *nbd = MEM_callocN(sizeof(NodeDefocus), "node defocus data"); + nbd->bktype = 0; + nbd->rotation = 0.f; + nbd->preview = 1; + nbd->gamco = 0; + nbd->samples = 16; + nbd->fstop = 128.f; + nbd->maxblur = 0; + nbd->bthresh = 1.f; + nbd->scale = 1.f; + nbd->no_zbuf = 1; + node->storage = nbd; +} + +bNodeType cmp_node_defocus = { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_DEFOCUS, + /* name */ "Defocus", + /* width+range */ 150, 120, 200, + /* class+opts */ NODE_CLASS_OP_FILTER, NODE_OPTIONS, + /* input sock */ cmp_node_defocus_in, + /* output sock */ cmp_node_defocus_out, + /* storage */ "NodeDefocus", + /* execfunc */ node_composit_exec_defocus, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_defocus, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL +}; + + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_diffMatte.c b/source/blender/nodes/intern/CMP_nodes/CMP_diffMatte.c new file mode 100644 index 00000000000..ade2111f246 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_diffMatte.c @@ -0,0 +1,217 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + +/* ******************* channel Difference Matte ********************************* */ +static bNodeSocketType cmp_node_diff_matte_in[]={ + {SOCK_RGBA,1,"Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + {SOCK_RGBA,1,"Key Color", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + {-1,0,""} +}; + +static bNodeSocketType cmp_node_diff_matte_out[]={ + {SOCK_RGBA,0,"Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + {SOCK_VALUE,0,"Matte",0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + {-1,0,""} +}; + +/* note, keyvals is passed on from caller as stack array */ +/* might have been nicer as temp struct though... */ +static void do_diff_matte(bNode *node, float *colorbuf, float *inbuf, float *keyvals) +{ + NodeChroma *c= (NodeChroma *)node->storage; + float *keymin= keyvals; + float *keymax= keyvals+3; + float *key= keyvals+6; + float tolerance= keyvals[9]; + float distance, alpha; + + /*process the pixel if it is close to the key or already transparent*/ + if(((colorbuf[0]>keymin[0] && colorbuf[0]keymin[1] && colorbuf[1]keymin[2] && colorbuf[2] inbuf[3]) alpha= inbuf[3]; + if(alpha > c->fstrength) alpha= 0.0f; + + /*clamp*/ + if (alpha>1.0f) alpha=1.0f; + if (alpha<0.0f) alpha=0.0f; + + /*premultiplied picture*/ + colorbuf[3]= alpha; + } + else { + /*foreground object*/ + colorbuf[3]= inbuf[3]; + } +} + +static void node_composit_exec_diff_matte(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* + Losely based on the Sequencer chroma key plug-in, but enhanced to work in other color spaces and + uses a differnt difference function (suggested in forums of vfxtalk.com). + */ + CompBuf *workbuf; + CompBuf *inbuf; + NodeChroma *c; + float keyvals[10]; + float *keymin= keyvals; + float *keymax= keyvals+3; + float *key= keyvals+6; + float *tolerance= keyvals+9; + float t[3]; + + /*is anything connected?*/ + if(out[0]->hasoutput==0 && out[1]->hasoutput==0) return; + /*must have an image imput*/ + if(in[0]->data==NULL) return; + + inbuf=typecheck_compbuf(in[0]->data, CB_RGBA); + + c=node->storage; + workbuf=dupalloc_compbuf(inbuf); + + /*use the input color*/ + key[0]= in[1]->vec[0]; + key[1]= in[1]->vec[1]; + key[2]= in[1]->vec[2]; + + /*get the tolerances from the UI*/ + t[0]=c->t1; + t[1]=c->t2; + t[2]=c->t3; + + /*convert to colorspace*/ + switch(node->custom1) { + case 1: /*RGB*/ + break; + case 2: /*HSV*/ + /*convert the key (in place)*/ + rgb_to_hsv(key[0], key[1], key[2], &key[0], &key[1], &key[2]); + composit1_pixel_processor(node, workbuf, inbuf, in[1]->vec, do_rgba_to_hsva, CB_RGBA); + break; + case 3: /*YUV*/ + rgb_to_yuv(key[0], key[1], key[2], &key[0], &key[1], &key[2]); + composit1_pixel_processor(node, workbuf, inbuf, in[1]->vec, do_rgba_to_yuva, CB_RGBA); + break; + case 4: /*YCC*/ + rgb_to_ycc(key[0], key[1], key[2], &key[0], &key[1], &key[2]); + composit1_pixel_processor(node, workbuf, inbuf, in[1]->vec, do_rgba_to_ycca, CB_RGBA); + /*account for ycc is on a 0..255 scale*/ + t[0]= c->t1*255.0; + t[1]= c->t2*255.0; + t[2]= c->t3*255.0; + break; + default: + break; + } + + /*find min/max tolerances*/ + keymin[0]= key[0]-t[0]; + keymin[1]= key[1]-t[1]; + keymin[2]= key[2]-t[2]; + keymax[0]= key[0]+t[0]; + keymax[1]= key[1]+t[1]; + keymax[2]= key[2]+t[2]; + + /*tolerance*/ + *tolerance= sqrt((t[0])*(t[0])+ + (t[1])*(t[1])+ + (t[2])*(t[2])); + + /* note, processor gets a keyvals array passed on as buffer constant */ + composit2_pixel_processor(node, workbuf, workbuf, in[0]->vec, NULL, keyvals, do_diff_matte, CB_RGBA, CB_VAL); + + /*convert back to RGB colorspace*/ + switch(node->custom1) { + case 1: /*RGB*/ + composit1_pixel_processor(node, workbuf, workbuf, in[1]->vec, do_copy_rgba, CB_RGBA); + break; + case 2: /*HSV*/ + composit1_pixel_processor(node, workbuf, workbuf, in[1]->vec, do_hsva_to_rgba, CB_RGBA); + break; + case 3: /*YUV*/ + composit1_pixel_processor(node, workbuf, workbuf, in[1]->vec, do_yuva_to_rgba, CB_RGBA); + break; + case 4: /*YCC*/ + composit1_pixel_processor(node, workbuf, workbuf, in[1]->vec, do_ycca_to_rgba, CB_RGBA); + break; + default: + break; + } + + out[0]->data=workbuf; + if(out[1]->hasoutput) + out[1]->data=valbuf_from_rgbabuf(workbuf, CHAN_A); + generate_preview(node, workbuf); + + if(inbuf!=in[0]->data) + free_compbuf(inbuf); +} + +static void node_composit_init_diff_matte(bNode *node) +{ + NodeChroma *c= MEM_callocN(sizeof(NodeChroma), "node chroma"); + node->storage= c; + c->t1= 0.01f; + c->t2= 0.01f; + c->t3= 0.01f; + c->fsize= 0.0f; + c->fstrength= 0.0f; + node->custom1= 1; /* RGB */ +} + +bNodeType cmp_node_diff_matte={ + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_DIFF_MATTE, + /* name */ "Difference Key", + /* width+range */ 200, 80, 250, + /* class+opts */ NODE_CLASS_MATTE, NODE_PREVIEW|NODE_OPTIONS, + /* input sock */ cmp_node_diff_matte_in, + /* output sock */ cmp_node_diff_matte_out, + /* storage */ "NodeChroma", + /* execfunc */ node_composit_exec_diff_matte, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_diff_matte, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL +}; + + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_dilate.c b/source/blender/nodes/intern/CMP_nodes/CMP_dilate.c new file mode 100644 index 00000000000..81430436227 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_dilate.c @@ -0,0 +1,163 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + + +/* **************** Dilate/Erode ******************** */ + +static bNodeSocketType cmp_node_dilateerode_in[]= { + { SOCK_VALUE, 1, "Mask", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_dilateerode_out[]= { + { SOCK_VALUE, 0, "Mask", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void morpho_dilate(CompBuf *cbuf) +{ + int x, y; + float *p, *rectf = cbuf->rect; + + for (y=0; y < cbuf->y; y++) { + for (x=0; x < cbuf->x-1; x++) { + p = rectf + cbuf->x*y + x; + *p = MAX2(*p, *(p + 1)); + } + } + + for (y=0; y < cbuf->y; y++) { + for (x=cbuf->x-1; x >= 1; x--) { + p = rectf + cbuf->x*y + x; + *p = MAX2(*p, *(p - 1)); + } + } + + for (x=0; x < cbuf->x; x++) { + for (y=0; y < cbuf->y-1; y++) { + p = rectf + cbuf->x*y + x; + *p = MAX2(*p, *(p + cbuf->x)); + } + } + + for (x=0; x < cbuf->x; x++) { + for (y=cbuf->y-1; y >= 1; y--) { + p = rectf + cbuf->x*y + x; + *p = MAX2(*p, *(p - cbuf->x)); + } + } +} + +static void morpho_erode(CompBuf *cbuf) +{ + int x, y; + float *p, *rectf = cbuf->rect; + + for (y=0; y < cbuf->y; y++) { + for (x=0; x < cbuf->x-1; x++) { + p = rectf + cbuf->x*y + x; + *p = MIN2(*p, *(p + 1)); + } + } + + for (y=0; y < cbuf->y; y++) { + for (x=cbuf->x-1; x >= 1; x--) { + p = rectf + cbuf->x*y + x; + *p = MIN2(*p, *(p - 1)); + } + } + + for (x=0; x < cbuf->x; x++) { + for (y=0; y < cbuf->y-1; y++) { + p = rectf + cbuf->x*y + x; + *p = MIN2(*p, *(p + cbuf->x)); + } + } + + for (x=0; x < cbuf->x; x++) { + for (y=cbuf->y-1; y >= 1; y--) { + p = rectf + cbuf->x*y + x; + *p = MIN2(*p, *(p - cbuf->x)); + } + } + +} + +static void node_composit_exec_dilateerode(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order in: mask */ + /* stack order out: mask */ + if(out[0]->hasoutput==0) + return; + + /* input no image? then only color operation */ + if(in[0]->data==NULL) { + out[0]->vec[0] = out[0]->vec[1] = out[0]->vec[2] = 0.0f; + out[0]->vec[3] = 0.0f; + } + else { + /* make output size of input image */ + CompBuf *cbuf= typecheck_compbuf(in[0]->data, CB_VAL); + CompBuf *stackbuf= dupalloc_compbuf(cbuf); + short i; + + if (node->custom2 > 0) { // positive, dilate + for (i = 0; i < node->custom2; i++) + morpho_dilate(stackbuf); + } else if (node->custom2 < 0) { // negative, erode + for (i = 0; i > node->custom2; i--) + morpho_erode(stackbuf); + } + + if(cbuf!=in[0]->data) + free_compbuf(cbuf); + + out[0]->data= stackbuf; + } +} + +bNodeType cmp_node_dilateerode= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_DILATEERODE, + /* name */ "Dilate/Erode", + /* width+range */ 130, 100, 320, + /* class+opts */ NODE_CLASS_OP_FILTER, NODE_OPTIONS, + /* input sock */ cmp_node_dilateerode_in, + /* output sock */ cmp_node_dilateerode_out, + /* storage */ "", + /* execfunc */ node_composit_exec_dilateerode, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; + + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_displace.c b/source/blender/nodes/intern/CMP_nodes/CMP_displace.c new file mode 100644 index 00000000000..0ec15d9eb77 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_displace.c @@ -0,0 +1,163 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + + +/* **************** Displace ******************** */ + +static bNodeSocketType cmp_node_displace_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_VECTOR, 1, "Vector", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "X Scale", 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f}, + { SOCK_VALUE, 1, "Y Scale", 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_displace_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_displace(CompBuf *stackbuf, CompBuf *cbuf, CompBuf *vecbuf, float *veccol, float *xscale, float *yscale) +{ + ImBuf *ibuf; + int x, y, sx, sy; + float dx=0.0, dy=0.0; + float dspx, dspy; + float uv[2]; + + float *out= stackbuf->rect, *vec=vecbuf->rect, *in= cbuf->rect; + float *vp, *vpnext, *vpprev; + + int row = 3*vecbuf->x; + + /* ibuf needed for sampling */ + ibuf= IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0, 0); + ibuf->rect_float= cbuf->rect; + + vec = vecbuf->rect; + + sx= stackbuf->x; + sy= stackbuf->y; + + for(y=0; yxrad, y-vecbuf->yrad, vecbuf->xrad, vecbuf->yrad); + + /* find the new displaced co-ords, also correcting for translate offset */ + dspx = x - (*xscale * vp[0]); + dspy = y - (*yscale * vp[1]); + + /* convert image space to 0.0-1.0 UV space for sampling, correcting for translate offset */ + uv[0] = dspx / (float)sx; + uv[1] = dspy / (float)sy; + + if(x>0 && x< vecbuf->x-1 && y>0 && y< vecbuf->y-1) { + vpnext = vp+row; + vpprev = vp-row; + + /* adaptive sampling, X channel */ + dx= 0.5f*(fabs(vp[0]-vp[-3]) + fabs(vp[0]-vp[3])); + + dx+= 0.25f*(fabs(vp[0]-vpprev[-3]) + fabs(vp[0]-vpnext[-3])); + dx+= 0.25f*(fabs(vp[0]-vpprev[+3]) + fabs(vp[0]-vpnext[+3])); + + /* adaptive sampling, Y channel */ + dy= 0.5f*(fabs(vp[1]-vp[-row+1]) + fabs(vp[1]-vp[row+1])); + + dy+= 0.25f*(fabs(vp[1]-vpprev[+1-3]) + fabs(vp[1]-vpnext[+1-3])); + dy+= 0.25f*(fabs(vp[1]-vpprev[+1+3]) + fabs(vp[1]-vpnext[+1+3])); + + /* scaled down to prevent blurriness */ + /* 8: magic number, provides a good level of sharpness without getting too aliased */ + dx /= 8; + dy /= 8; + } + + /* should use mipmap */ + if(dx > 0.006f) dx= 0.006f; + if(dy > 0.006f) dy= 0.006f; + if ((vp[0]> 0.0) && (dx < 0.004)) dx = 0.004; + if ((vp[1]> 0.0) && (dy < 0.004)) dy = 0.004; + + + ibuf_sample(ibuf, uv[0], uv[1], dx, dy, out); + } + } + + IMB_freeImBuf(ibuf); +} + + +static void node_composit_exec_displace(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + if(out[0]->hasoutput==0) + return; + + if(in[0]->data && in[1]->data) { + CompBuf *cbuf= in[0]->data; + CompBuf *vecbuf= in[1]->data; + CompBuf *stackbuf; + + cbuf= typecheck_compbuf(cbuf, CB_RGBA); + vecbuf= typecheck_compbuf(vecbuf, CB_VEC3); + stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */ + + do_displace(stackbuf, cbuf, vecbuf, in[1]->vec, in[2]->vec, in[3]->vec); + + out[0]->data= stackbuf; + + + if(cbuf!=in[0]->data) + free_compbuf(cbuf); + if(vecbuf!=in[1]->data) + free_compbuf(vecbuf); + } +} + +bNodeType cmp_node_displace= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_DISPLACE, + /* name */ "Displace", + /* width+range */ 140, 100, 320, + /* class+opts */ NODE_CLASS_DISTORT, NODE_OPTIONS, + /* input sock */ cmp_node_displace_in, + /* output sock */ cmp_node_displace_out, + /* storage */ "", + /* execfunc */ node_composit_exec_displace, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_filter.c b/source/blender/nodes/intern/CMP_nodes/CMP_filter.c new file mode 100644 index 00000000000..46a9d747ac1 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_filter.c @@ -0,0 +1,235 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + +/* **************** FILTER ******************** */ +static bNodeSocketType cmp_node_filter_in[]= { + { SOCK_VALUE, 1, "Fac", 1.0f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_filter_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_filter_edge(CompBuf *out, CompBuf *in, float *filter, float fac) +{ + float *row1, *row2, *row3; + float *fp, f1, f2, mfac= 1.0f-fac; + int rowlen, x, y, c, pix= in->type; + + rowlen= in->x; + + for(y=0; yy; y++) { + /* setup rows */ + if(y==0) row1= in->rect; + else row1= in->rect + pix*(y-1)*rowlen; + + row2= in->rect + y*pix*rowlen; + + if(y==in->y-1) row3= row2; + else row3= row2 + pix*rowlen; + + fp= out->rect + pix*y*rowlen; + + if(pix==CB_RGBA) { + QUATCOPY(fp, row2); + fp+= pix; + + for(x=2; xtype; + + rowlen= in->x; + + for(y=0; yy; y++) { + /* setup rows */ + if(y==0) row1= in->rect; + else row1= in->rect + pixlen*(y-1)*rowlen; + + row2= in->rect + y*pixlen*rowlen; + + if(y==in->y-1) row3= row2; + else row3= row2 + pixlen*rowlen; + + fp= out->rect + pixlen*(y)*rowlen; + + if(pixlen==1) { + fp[0]= row2[0]; + fp+= 1; + + for(x=2; xhasoutput==0) return; + + /* stack order in: Image */ + /* stack order out: Image */ + + if(in[1]->data) { + /* make output size of first available input image */ + CompBuf *cbuf= in[1]->data; + CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, cbuf->type, 1); /* allocs */ + + /* warning note: xof and yof are applied in pixelprocessor, but should be copied otherwise? */ + stackbuf->xof= cbuf->xof; + stackbuf->yof= cbuf->yof; + + switch(node->custom1) { + case CMP_FILT_SOFT: + do_filter3(stackbuf, cbuf, soft, in[0]->vec[0]); + break; + case CMP_FILT_SHARP: + do_filter3(stackbuf, cbuf, sharp, in[0]->vec[0]); + break; + case CMP_FILT_LAPLACE: + do_filter3(stackbuf, cbuf, laplace, in[0]->vec[0]); + break; + case CMP_FILT_SOBEL: + do_filter_edge(stackbuf, cbuf, sobel, in[0]->vec[0]); + break; + case CMP_FILT_PREWITT: + do_filter_edge(stackbuf, cbuf, prewitt, in[0]->vec[0]); + break; + case CMP_FILT_KIRSCH: + do_filter_edge(stackbuf, cbuf, kirsch, in[0]->vec[0]); + break; + case CMP_FILT_SHADOW: + do_filter3(stackbuf, cbuf, shadow, in[0]->vec[0]); + break; + } + + out[0]->data= stackbuf; + } +} + + +bNodeType cmp_node_filter= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_FILTER, + /* name */ "Filter", + /* width+range */ 80, 40, 120, + /* class+opts */ NODE_CLASS_OP_FILTER, NODE_OPTIONS, + /* input sock */ cmp_node_filter_in, + /* output sock */ cmp_node_filter_out, + /* storage */ "", + /* execfunc */ node_composit_exec_filter, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; + + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_flip.c b/source/blender/nodes/intern/CMP_nodes/CMP_flip.c new file mode 100644 index 00000000000..cd6fdf70ac4 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_flip.c @@ -0,0 +1,105 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + +/* **************** Flip ******************** */ +static bNodeSocketType cmp_node_flip_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static bNodeSocketType cmp_node_flip_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_composit_exec_flip(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + if(in[0]->data) { + CompBuf *cbuf= in[0]->data; + CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, cbuf->type, 1); /* note, this returns zero'd image */ + int i, src_pix, src_width, src_height, srcydelt, outydelt, x, y; + float *srcfp, *outfp; + + src_pix= cbuf->type; + src_width= cbuf->x; + src_height= cbuf->y; + srcfp= cbuf->rect; + outfp= stackbuf->rect; + srcydelt= src_width*src_pix; + outydelt= srcydelt; + + if(node->custom1) { /*set up output pointer for y flip*/ + outfp+= (src_height-1)*outydelt; + outydelt= -outydelt; + } + + for(y=0; ycustom1 == 1) { /* no x flip so just copy line*/ + memcpy(outfp, srcfp, sizeof(float) * src_pix * src_width); + srcfp+=srcydelt; + } + else { + outfp += (src_width-1)*src_pix; + for(x=0; xdata= stackbuf; + + } +} + +bNodeType cmp_node_flip= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_FLIP, + /* name */ "Flip", + /* width+range */ 140, 100, 320, + /* class+opts */ NODE_CLASS_DISTORT, NODE_OPTIONS, + /* input sock */ cmp_node_flip_in, + /* output sock */ cmp_node_flip_out, + /* storage */ "", + /* execfunc */ node_composit_exec_flip, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; + + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_gamma.c b/source/blender/nodes/intern/CMP_nodes/CMP_gamma.c new file mode 100644 index 00000000000..5d0ab729e08 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_gamma.c @@ -0,0 +1,91 @@ +/** +* $Id$ +* +* ***** BEGIN GPL LICENSE BLOCK ***** +* +* 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. +* +* The Original Code is Copyright (C) 2006 Blender Foundation. +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): none yet. +* +* ***** END GPL LICENSE BLOCK ***** + +*/ + +#include "../CMP_util.h" + +/* **************** Gamma Tools ******************** */ + +static bNodeSocketType cmp_node_gamma_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Gamma", 1.0f, 0.0f, 0.0f, 0.0f, 0.001f, 2.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_gamma_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_gamma(bNode *node, float *out, float *in, float *fac) +{ + int i=0; + for(i=0; i<3; i++) { + out[i] = pow(in[i],fac[0]); + } + out[3] = in[3]; +} +static void node_composit_exec_gamma(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order in: Fac, Image */ + /* stack order out: Image */ + if(out[0]->hasoutput==0) return; + + /* input no image? then only color operation */ + if(in[0]->data==NULL) { + do_gamma(node, out[0]->vec, in[0]->vec, in[1]->vec); + } + else { + /* make output size of input image */ + CompBuf *cbuf= in[0]->data; + CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs + + composit2_pixel_processor(node, stackbuf, cbuf, in[0]->vec, in[1]->data, in[1]->vec, do_gamma, CB_RGBA, CB_VAL); + + out[0]->data= stackbuf; + } +} + +bNodeType cmp_node_gamma= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_GAMMA, + /* name */ "Gamma", + /* width+range */ 140, 100, 320, + /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS, + /* input sock */ cmp_node_gamma_in, + /* output sock */ cmp_node_gamma_out, + /* storage */ "", + /* execfunc */ node_composit_exec_gamma, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copysotragefunc */ NULL, + /* id */ NULL +}; + + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_glare.c b/source/blender/nodes/intern/CMP_nodes/CMP_glare.c new file mode 100644 index 00000000000..9943dd2246d --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_glare.c @@ -0,0 +1,498 @@ +/** + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Alfredo de Greef (eeshlo) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + +static bNodeSocketType cmp_node_glare_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_glare_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + + +// mix two images, src buffer does not have to be same size, +static void mixImages(CompBuf *dst, CompBuf *src, float mix) +{ + int x, y; + fRGB c1, c2, *dcolp, *scolp; + const float mf = 2.f - 2.f*fabsf(mix - 0.5f); + if ((dst->x == src->x) && (dst->y == src->y)) { + for (y=0; yy; y++) { + dcolp = (fRGB*)&dst->rect[y*dst->x*dst->type]; + scolp = (fRGB*)&src->rect[y*dst->x*dst->type]; + for (x=0; xx; x++) { + fRGB_copy(c1, dcolp[x]); + fRGB_copy(c2, scolp[x]); + c1[0] += mix*(c2[0] - c1[0]); + c1[1] += mix*(c2[1] - c1[1]); + c1[2] += mix*(c2[2] - c1[2]); + if (c1[0] < 0.f) c1[0] = 0.f; + if (c1[1] < 0.f) c1[1] = 0.f; + if (c1[2] < 0.f) c1[2] = 0.f; + fRGB_mult(c1, mf); + fRGB_copy(dcolp[x], c1); + } + } + } + else { + float xr = src->x / (float)dst->x; + float yr = src->y / (float)dst->y; + for (y=0; yy; y++) { + dcolp = (fRGB*)&dst->rect[y*dst->x*dst->type]; + for (x=0; xx; x++) { + fRGB_copy(c1, dcolp[x]); + qd_getPixelLerp(src, (x + 0.5f)*xr - 0.5f, (y + 0.5f)*yr - 0.5f, c2); + c1[0] += mix*(c2[0] - c1[0]); + c1[1] += mix*(c2[1] - c1[1]); + c1[2] += mix*(c2[2] - c1[2]); + if (c1[0] < 0.f) c1[0] = 0.f; + if (c1[1] < 0.f) c1[1] = 0.f; + if (c1[2] < 0.f) c1[2] = 0.f; + fRGB_mult(c1, mf); + fRGB_copy(dcolp[x], c1); + } + } + } +} + + +// adds src to dst image, must be of same size +static void addImage(CompBuf* dst, CompBuf* src, float scale) +{ + if ((dst->x == src->x) && (dst->y == src->y)) { + int p = dst->x*dst->y*dst->type; + float *dcol = dst->rect, *scol = src->rect; + while (p--) *dcol++ += *scol++ * scale; + } +} + + +// returns possibly downscaled copy of all pixels above threshold +static CompBuf* BTP(CompBuf* src, float threshold, int scaledown) +{ + int x, y; + CompBuf* bsrc = qd_downScaledCopy(src, scaledown); + float* cr = bsrc->rect; + for (y=0; yy; ++y) + for (x=0; xx; ++x, cr+=4) { + if ((0.212671f*cr[0] + 0.71516f*cr[1] + 0.072169f*cr[2]) >= threshold) { + cr[0] -= threshold, cr[1] -= threshold, cr[2] -= threshold; + cr[0] = MAX2(cr[0], 0.f); + cr[1] = MAX2(cr[1], 0.f); + cr[2] = MAX2(cr[2], 0.f); + } + else cr[0] = cr[1] = cr[2] = 0.f; + } + return bsrc; +} + +//-------------------------------------------------------------------------------------------- +// simple 4-point star filter + +static void star4(NodeGlare* ndg, CompBuf* dst, CompBuf* src) +{ + int x, y, i, xm, xp, ym, yp; + float c[4] = {0,0,0,0}, tc[4] = {0,0,0,0}; + CompBuf *tbuf1, *tbuf2, *tsrc; + const float f1 = 1.f - ndg->fade, f2 = (1.f - f1)*0.5f; + //const float t3 = ndg->threshold*3.f; + const float sc = (float)(1 << ndg->quality); + const float isc = 1.f/sc; + + tsrc = BTP(src, ndg->threshold, (int)sc); + + tbuf1 = dupalloc_compbuf(tsrc); + tbuf2 = dupalloc_compbuf(tsrc); + + for (i=0; iiter; i++) { + // (x || x-1, y-1) to (x || x+1, y+1) + // F + for (y=0; yy; y++) { + ym = y - i; + yp = y + i; + for (x=0; xx; x++) { + xm = x - i; + xp = x + i; + qd_getPixel(tbuf1, x, y, c); + fRGB_mult(c, f1); + qd_getPixel(tbuf1, (ndg->angle ? xm : x), ym, tc); + fRGB_madd(c, tc, f2); + qd_getPixel(tbuf1, (ndg->angle ? xp : x), yp, tc); + fRGB_madd(c, tc, f2); + qd_setPixel(tbuf1, x, y, c); + } + } + // B + for (y=tbuf1->y-1; y>=0; y--) { + ym = y - i; + yp = y + i; + for (x=tbuf1->x-1; x>=0; x--) { + xm = x - i; + xp = x + i; + qd_getPixel(tbuf1, x, y, c); + fRGB_mult(c, f1); + qd_getPixel(tbuf1, (ndg->angle ? xm : x), ym, tc); + fRGB_madd(c, tc, f2); + qd_getPixel(tbuf1, (ndg->angle ? xp : x), yp, tc); + fRGB_madd(c, tc, f2); + qd_setPixel(tbuf1, x, y, c); + } + } + // (x-1, y || y+1) to (x+1, y || y-1) + // F + for (y=0; yy; y++) { + ym = y - i; + yp = y + i; + for (x=0; xx; x++) { + xm = x - i; + xp = x + i; + qd_getPixel(tbuf2, x, y, c); + fRGB_mult(c, f1); + qd_getPixel(tbuf2, xm, (ndg->angle ? yp : y), tc); + fRGB_madd(c, tc, f2); + qd_getPixel(tbuf2, xp, (ndg->angle ? ym : y), tc); + fRGB_madd(c, tc, f2); + qd_setPixel(tbuf2, x, y, c); + } + } + // B + for (y=tbuf2->y-1; y>=0; y--) { + ym = y - i; + yp = y + i; + for (x=tbuf2->x-1; x>=0; x--) { + xm = x - i; + xp = x + i; + qd_getPixel(tbuf2, x, y, c); + fRGB_mult(c, f1); + qd_getPixel(tbuf2, xm, (ndg->angle ? yp : y), tc); + fRGB_madd(c, tc, f2); + qd_getPixel(tbuf2, xp, (ndg->angle ? ym : y), tc); + fRGB_madd(c, tc, f2); + qd_setPixel(tbuf2, x, y, c); + } + } + } + + for (y=0; yy; ++y) + for (x=0; xx; ++x) { + unsigned int p = (x + y*tbuf1->x)*tbuf1->type; + tbuf1->rect[p] += tbuf2->rect[p]; + tbuf1->rect[p+1] += tbuf2->rect[p+1]; + tbuf1->rect[p+2] += tbuf2->rect[p+2]; + } + + for (y=0; yy; ++y) { + const float m = 0.5f + 0.5f*ndg->mix; + for (x=0; xx; ++x) { + unsigned int p = (x + y*dst->x)*dst->type; + qd_getPixelLerp(tbuf1, x*isc, y*isc, tc); + dst->rect[p] = src->rect[p] + m*(tc[0] - src->rect[p]); + dst->rect[p+1] = src->rect[p+1] + m*(tc[1] - src->rect[p+1]); + dst->rect[p+2] = src->rect[p+2] + m*(tc[2] - src->rect[p+2]); + } + } + + free_compbuf(tbuf1); + free_compbuf(tbuf2); + free_compbuf(tsrc); +} + +//-------------------------------------------------------------------------------------------- +// streak filter + +static void streaks(NodeGlare* ndg, CompBuf* dst, CompBuf* src) +{ + CompBuf *bsrc, *tsrc, *tdst, *sbuf; + int x, y, n; + unsigned int nump=0; + fRGB c1, c2, c3, c4; + float a, ang = 360.f/(float)ndg->angle; + + bsrc = BTP(src, ndg->threshold, 1 << ndg->quality); + tsrc = dupalloc_compbuf(bsrc); // sample from buffer + tdst = alloc_compbuf(tsrc->x, tsrc->y, tsrc->type, 1); // sample to buffer + sbuf = alloc_compbuf(tsrc->x, tsrc->y, tsrc->type, 1); // streak sum buffer + + + for (a=0.f; a<360.f; a+=ang) { + const float an = (a + (float)ndg->angle_ofs)*(float)M_PI/180.f; + const float vx = cosf(an), vy = sinf(an); + for (n=0; niter; ++n) { + const float p4 = powf(4.f, n); + const float vxp = vx*p4, vyp = vy*p4; + const float wt = powf(ndg->fade, p4); + const float cmo = 1.f - powf(ndg->colmod, n+1); // colormodulation amount relative to current pass + float* tdstcol = tdst->rect; + for (y=0; yy; ++y) { + for (x=0; xx; ++x, tdstcol+=4) { + // first pass no offset, always same for every pass, exact copy, + // otherwise results in uneven brightness, only need once + if (n==0) qd_getPixel(tsrc, x, y, c1); else c1[0]=c1[1]=c1[2]=0; + qd_getPixelLerp(tsrc, x + vxp, y + vyp, c2); + qd_getPixelLerp(tsrc, x + vxp*2.f, y + vyp*2.f, c3); + qd_getPixelLerp(tsrc, x + vxp*3.f, y + vyp*3.f, c4); + // modulate color to look vaguely similar to a color spectrum + fRGB_rgbmult(c2, 1.f, cmo, cmo); + fRGB_rgbmult(c3, cmo, cmo, 1.f); + fRGB_rgbmult(c4, cmo, 1.f, cmo); + tdstcol[0] = 0.5f*(tdstcol[0] + c1[0] + wt*(c2[0] + wt*(c3[0] + wt*c4[0]))); + tdstcol[1] = 0.5f*(tdstcol[1] + c1[1] + wt*(c2[1] + wt*(c3[1] + wt*c4[1]))); + tdstcol[2] = 0.5f*(tdstcol[2] + c1[2] + wt*(c2[2] + wt*(c3[2] + wt*c4[2]))); + } + } + memcpy(tsrc->rect, tdst->rect, sizeof(float)*tdst->x*tdst->y*tdst->type); + } + + addImage(sbuf, tsrc, 1.f/(float)(6 - ndg->iter)); + memset(tdst->rect, 0, tdst->x*tdst->y*tdst->type*sizeof(float)); + memcpy(tsrc->rect, bsrc->rect, bsrc->x*bsrc->y*bsrc->type*sizeof(float)); + nump++; + } + + mixImages(dst, sbuf, 0.5f + 0.5f*ndg->mix); + + free_compbuf(tsrc); + free_compbuf(tdst); + free_compbuf(sbuf); + free_compbuf(bsrc); +} + + +//-------------------------------------------------------------------------------------------- +// Ghosts (lensflare) + +static float smoothMask(float x, float y) +{ + float t; + x = 2.f*x - 1.f, y = 2.f*y - 1.f; + if ((t = 1.f - sqrtf(x*x + y*y)) <= 0.f) return 0.f; + return t; +} + +static void ghosts(NodeGlare* ndg, CompBuf* dst, CompBuf* src) +{ + // colormodulation and scale factors (cm & scalef) for 16 passes max: 64 + int x, y, n, p, np; + fRGB c, tc, cm[64]; + float sc, isc, u, v, sm, s, t, ofs, scalef[64]; + CompBuf *tbuf1, *tbuf2, *gbuf; + const float cmo = 1.f - ndg->colmod; + const int qt = 1 << ndg->quality; + const float s1 = 4.f/(float)qt, s2 = 2.f*s1; + + gbuf = BTP(src, ndg->threshold, qt); + tbuf1 = dupalloc_compbuf(gbuf); + IIR_gauss(tbuf1, s1, 0, 3); + IIR_gauss(tbuf1, s1, 1, 3); + IIR_gauss(tbuf1, s1, 2, 3); + tbuf2 = dupalloc_compbuf(tbuf1); + IIR_gauss(tbuf2, s2, 0, 3); + IIR_gauss(tbuf2, s2, 1, 3); + IIR_gauss(tbuf2, s2, 2, 3); + + if (ndg->iter & 1) ofs = 0.5f; else ofs = 0.f; + for (x=0; x<(ndg->iter*4); x++) { + y = x & 3; + cm[x][0] = cm[x][1] = cm[x][2] = 1; + if (y==1) fRGB_rgbmult(cm[x], 1.f, cmo, cmo); + if (y==2) fRGB_rgbmult(cm[x], cmo, cmo, 1.f); + if (y==3) fRGB_rgbmult(cm[x], cmo, 1.f, cmo); + scalef[x] = 2.1f*(1.f-(x+ofs)/(float)(ndg->iter*4)); + if (x & 1) scalef[x] = -0.99f/scalef[x]; + } + + sc = 2.13; + isc = -0.97; + for (y=0; yy; y++) { + v = (float)(y+0.5f) / (float)gbuf->y; + for (x=0; xx; x++) { + u = (float)(x+0.5f) / (float)gbuf->x; + s = (u-0.5f)*sc + 0.5f, t = (v-0.5f)*sc + 0.5f; + qd_getPixelLerp(tbuf1, s*gbuf->x, t*gbuf->y, c); + sm = smoothMask(s, t); + fRGB_mult(c, sm); + s = (u-0.5f)*isc + 0.5f, t = (v-0.5f)*isc + 0.5f; + qd_getPixelLerp(tbuf2, s*gbuf->x - 0.5f, t*gbuf->y - 0.5f, tc); + sm = smoothMask(s, t); + fRGB_madd(c, tc, sm); + qd_setPixel(gbuf, x, y, c); + } + } + + memset(tbuf1->rect, 0, tbuf1->x*tbuf1->y*tbuf1->type*sizeof(float)); + for (n=1; niter; n++) { + for (y=0; yy; y++) { + v = (float)(y+0.5f) / (float)gbuf->y; + for (x=0; xx; x++) { + u = (float)(x+0.5f) / (float)gbuf->x; + tc[0] = tc[1] = tc[2] = 0.f; + for (p=0;p<4;p++) { + np = (n<<2) + p; + s = (u-0.5f)*scalef[np] + 0.5f; + t = (v-0.5f)*scalef[np] + 0.5f; + qd_getPixelLerp(gbuf, s*gbuf->x - 0.5f, t*gbuf->y - 0.5f, c); + fRGB_colormult(c, cm[np]); + sm = smoothMask(s, t)*0.25f; + fRGB_madd(tc, c, sm); + } + p = (x + y*tbuf1->x)*tbuf1->type; + tbuf1->rect[p] += tc[0]; + tbuf1->rect[p+1] += tc[1]; + tbuf1->rect[p+2] += tc[2]; + } + } + memcpy(gbuf->rect, tbuf1->rect, tbuf1->x*tbuf1->y*tbuf1->type*sizeof(float)); + } + + free_compbuf(tbuf1); + free_compbuf(tbuf2); + + mixImages(dst, gbuf, 0.5f + 0.5f*ndg->mix); + free_compbuf(gbuf); +} + +//-------------------------------------------------------------------------------------------- +// Fog glow (convolution with kernel of exponential falloff) + +static void fglow(NodeGlare* ndg, CompBuf* dst, CompBuf* src) +{ + int x, y; + float scale, u, v, r, w, d; + fRGB fcol; + CompBuf *tsrc, *ckrn; + unsigned int sz = 1 << ndg->size; + const float cs_r = 1.f, cs_g = 1.f, cs_b = 1.f; + + // temp. src image + tsrc = BTP(src, ndg->threshold, 1 << ndg->quality); + // make the convolution kernel + ckrn = alloc_compbuf(sz, sz, CB_RGBA, 1); + + scale = 0.25f*sqrtf(sz*sz); + + for (y=0; ymix); + free_compbuf(tsrc); +} + +//-------------------------------------------------------------------------------------------- + +static void node_composit_exec_glare(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + CompBuf *new, *img = in[0]->data; + NodeGlare* ndg = node->storage; + + if ((img == NULL) || (out[0]->hasoutput == 0)) return; + + if (img->type != CB_RGBA) + new = typecheck_compbuf(img, CB_RGBA); + else + new = dupalloc_compbuf(img); + + { + int x, y; + for (y=0; yy; ++y) { + fRGB* col = (fRGB*)&new->rect[y*new->x*new->type]; + for (x=0; xx; ++x) { + col[x][0] = MAX2(col[x][0], 0.f); + col[x][1] = MAX2(col[x][1], 0.f); + col[x][2] = MAX2(col[x][2], 0.f); + } + } + } + + switch (ndg->type) { + case 0: + star4(ndg, new, img); + break; + case 1: + fglow(ndg, new, img); + break; + case 3: + ghosts(ndg, new, img); + break; + case 2: + default: + streaks(ndg, new, img); + } + + out[0]->data = new; +} + +static void node_composit_init_glare(bNode* node) +{ + NodeGlare *ndg = MEM_callocN(sizeof(NodeGlare), "node glare data"); + ndg->quality = 1; + ndg->type = 2; + ndg->iter = 3; + ndg->colmod = 0.25; + ndg->mix = 0; + ndg->threshold = 1; + ndg->angle = 4; + ndg->angle_ofs = 0; + ndg->fade = 0.9; + ndg->size = 8; + node->storage = ndg; +} + +bNodeType cmp_node_glare = { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_GLARE, + /* name */ "Glare", + /* width+range */ 150, 120, 200, + /* class+opts */ NODE_CLASS_OP_FILTER, NODE_OPTIONS, + /* input sock */ cmp_node_glare_in, + /* output sock */ cmp_node_glare_out, + /* storage */ "NodeGlare", + /* execfunc */ node_composit_exec_glare, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_glare, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL +}; diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_hueSatVal.c b/source/blender/nodes/intern/CMP_nodes/CMP_hueSatVal.c new file mode 100644 index 00000000000..eeddb4ce756 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_hueSatVal.c @@ -0,0 +1,122 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + + +/* **************** Hue Saturation ******************** */ +static bNodeSocketType cmp_node_hue_sat_in[]= { + { SOCK_VALUE, 1, "Fac", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_hue_sat_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_hue_sat_fac(bNode *node, float *out, float *in, float *fac) +{ + NodeHueSat *nhs= node->storage; + + if(*fac!=0.0f && (nhs->hue!=0.5f || nhs->sat!=1.0 || nhs->val!=1.0)) { + float col[3], hsv[3], mfac= 1.0f - *fac; + + rgb_to_hsv(in[0], in[1], in[2], hsv, hsv+1, hsv+2); + hsv[0]+= (nhs->hue - 0.5f); + if(hsv[0]>1.0) hsv[0]-=1.0; else if(hsv[0]<0.0) hsv[0]+= 1.0; + hsv[1]*= nhs->sat; + if(hsv[1]>1.0) hsv[1]= 1.0; else if(hsv[1]<0.0) hsv[1]= 0.0; + hsv[2]*= nhs->val; + if(hsv[2]>1.0) hsv[2]= 1.0; else if(hsv[2]<0.0) hsv[2]= 0.0; + hsv_to_rgb(hsv[0], hsv[1], hsv[2], col, col+1, col+2); + + out[0]= mfac*in[0] + *fac*col[0]; + out[1]= mfac*in[1] + *fac*col[1]; + out[2]= mfac*in[2] + *fac*col[2]; + out[3]= in[3]; + } + else { + QUATCOPY(out, in); + } +} + +static void node_composit_exec_hue_sat(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order in: Fac, Image */ + /* stack order out: Image */ + if(out[0]->hasoutput==0) return; + + /* input no image? then only color operation */ + if(in[1]->data==NULL) { + do_hue_sat_fac(node, out[0]->vec, in[1]->vec, in[0]->vec); + } + else { + /* make output size of input image */ + CompBuf *cbuf= dupalloc_compbuf(in[1]->data); + CompBuf *stackbuf=typecheck_compbuf(cbuf,CB_RGBA); + + composit2_pixel_processor(node, stackbuf, stackbuf, in[1]->vec, in[0]->data, in[0]->vec, do_hue_sat_fac, CB_RGBA, CB_VAL); + + out[0]->data= stackbuf; + + /* get rid of intermediary cbuf if it's extra */ + if(stackbuf!=cbuf) + free_compbuf(cbuf); + } +} + +static void node_composit_init_hue_sat(bNode* node) +{ + NodeHueSat *nhs= MEM_callocN(sizeof(NodeHueSat), "node hue sat"); + node->storage= nhs; + nhs->hue= 0.5f; + nhs->sat= 1.0f; + nhs->val= 1.0f; +} + +bNodeType cmp_node_hue_sat= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_HUE_SAT, + /* name */ "Hue Saturation Value", + /* width+range */ 150, 80, 250, + /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS, + /* input sock */ cmp_node_hue_sat_in, + /* output sock */ cmp_node_hue_sat_out, + /* storage */ "NodeHueSat", + /* execfunc */ node_composit_exec_hue_sat, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_hue_sat, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL + +}; + + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_idMask.c b/source/blender/nodes/intern/CMP_nodes/CMP_idMask.c new file mode 100644 index 00000000000..abb9fa98d97 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_idMask.c @@ -0,0 +1,104 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + + +/* **************** ID Mask ******************** */ + +static bNodeSocketType cmp_node_idmask_in[]= { + { SOCK_VALUE, 1, "ID value", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_idmask_out[]= { + { SOCK_VALUE, 0, "Alpha", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +/* stackbuf should be zeroed */ +static void do_idmask(CompBuf *stackbuf, CompBuf *cbuf, float idnr) +{ + float *rect; + int x; + char *abuf= MEM_mapallocN(cbuf->x*cbuf->y, "anti ali buf"); + + rect= cbuf->rect; + for(x= cbuf->x*cbuf->y - 1; x>=0; x--) + if(rect[x]==idnr) + abuf[x]= 255; + + antialias_tagbuf(cbuf->x, cbuf->y, abuf); + + rect= stackbuf->rect; + for(x= cbuf->x*cbuf->y - 1; x>=0; x--) + if(abuf[x]>1) + rect[x]= (1.0f/255.0f)*(float)abuf[x]; + + MEM_freeN(abuf); +} + +static void node_composit_exec_idmask(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + if(out[0]->hasoutput==0) + return; + + if(in[0]->data) { + CompBuf *cbuf= in[0]->data; + CompBuf *stackbuf; + + if(cbuf->type!=CB_VAL) + return; + + stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); /* allocs */; + + do_idmask(stackbuf, cbuf, (float)node->custom1); + + out[0]->data= stackbuf; + } +} + + +bNodeType cmp_node_idmask= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_ID_MASK, + /* name */ "ID Mask", + /* width+range */ 140, 100, 320, + /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS, + /* input sock */ cmp_node_idmask_in, + /* output sock */ cmp_node_idmask_out, + /* storage */ "", + /* execfunc */ node_composit_exec_idmask, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; + + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_image.c b/source/blender/nodes/intern/CMP_nodes/CMP_image.c new file mode 100644 index 00000000000..20308e968d3 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_image.c @@ -0,0 +1,352 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + + +/* **************** IMAGE (and RenderResult, multilayer image) ******************** */ + +static bNodeSocketType cmp_node_rlayers_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "Z", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_VECTOR, 0, "UV", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_VECTOR, 0, "Speed", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 0, "Diffuse", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 0, "Specular", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 0, "Shadow", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 0, "AO", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 0, "Reflect", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 0, "Refract", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 0, "Radio", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "IndexOB", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + + +/* note: this function is used for multilayer too, to ensure uniform + handling with BKE_image_get_ibuf() */ +static CompBuf *node_composit_get_image(RenderData *rd, Image *ima, ImageUser *iuser) +{ + ImBuf *ibuf; + CompBuf *stackbuf; + int type; + + ibuf= BKE_image_get_ibuf(ima, iuser); + if(ibuf==NULL) + return NULL; + + if(ibuf->rect_float==NULL) + IMB_float_from_rect(ibuf); + + type= ibuf->channels; + + if(rd->scemode & R_COMP_CROP) { + stackbuf= get_cropped_compbuf(&rd->disprect, ibuf->rect_float, ibuf->x, ibuf->y, type); + } + else { + /* we put imbuf copy on stack, cbuf knows rect is from other ibuf when freed! */ + stackbuf= alloc_compbuf(ibuf->x, ibuf->y, type, 0); + stackbuf->rect= ibuf->rect_float; + } + + return stackbuf; +}; + +static CompBuf *node_composit_get_zimage(bNode *node, RenderData *rd) +{ + ImBuf *ibuf= BKE_image_get_ibuf((Image *)node->id, node->storage); + CompBuf *zbuf= NULL; + + if(ibuf && ibuf->zbuf_float) { + if(rd->scemode & R_COMP_CROP) { + zbuf= get_cropped_compbuf(&rd->disprect, ibuf->zbuf_float, ibuf->x, ibuf->y, CB_VAL); + } + else { + zbuf= alloc_compbuf(ibuf->x, ibuf->y, CB_VAL, 0); + zbuf->rect= ibuf->zbuf_float; + } + } + return zbuf; +}; + +/* check if layer is available, returns pass buffer */ +static CompBuf *compbuf_multilayer_get(RenderData *rd, RenderLayer *rl, Image *ima, ImageUser *iuser, int passtype) +{ + RenderPass *rpass; + short index; + + for(index=0, rpass= rl->passes.first; rpass; rpass= rpass->next, index++) + if(rpass->passtype==passtype) + break; + + if(rpass) { + CompBuf *cbuf; + + iuser->pass= index; + BKE_image_multilayer_index(ima->rr, iuser); + cbuf= node_composit_get_image(rd, ima, iuser); + + return cbuf; + } + return NULL; +}; + +void outputs_multilayer_get(RenderData *rd, RenderLayer *rl, bNodeStack **out, Image *ima, ImageUser *iuser) +{ + if(out[RRES_OUT_Z]->hasoutput) + out[RRES_OUT_Z]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_Z); + if(out[RRES_OUT_VEC]->hasoutput) + out[RRES_OUT_VEC]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_VECTOR); + if(out[RRES_OUT_NORMAL]->hasoutput) + out[RRES_OUT_NORMAL]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_NORMAL); + if(out[RRES_OUT_UV]->hasoutput) + out[RRES_OUT_UV]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_UV); + + if(out[RRES_OUT_RGBA]->hasoutput) + out[RRES_OUT_RGBA]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_RGBA); + if(out[RRES_OUT_DIFF]->hasoutput) + out[RRES_OUT_DIFF]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_DIFFUSE); + if(out[RRES_OUT_SPEC]->hasoutput) + out[RRES_OUT_SPEC]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_SPEC); + if(out[RRES_OUT_SHADOW]->hasoutput) + out[RRES_OUT_SHADOW]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_SHADOW); + if(out[RRES_OUT_AO]->hasoutput) + out[RRES_OUT_AO]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_AO); + if(out[RRES_OUT_REFLECT]->hasoutput) + out[RRES_OUT_REFLECT]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_REFLECT); + if(out[RRES_OUT_REFRACT]->hasoutput) + out[RRES_OUT_REFRACT]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_REFRACT); + if(out[RRES_OUT_RADIO]->hasoutput) + out[RRES_OUT_RADIO]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_RADIO); + if(out[RRES_OUT_INDEXOB]->hasoutput) + out[RRES_OUT_INDEXOB]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_INDEXOB); + +}; + + +static void node_composit_exec_image(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + + /* image assigned to output */ + /* stack order input sockets: col, alpha */ + if(node->id) { + RenderData *rd= data; + Image *ima= (Image *)node->id; + ImageUser *iuser= (ImageUser *)node->storage; + CompBuf *stackbuf= NULL; + + /* first set the right frame number in iuser */ + BKE_image_user_calc_imanr(iuser, rd->cfra, 0); + + /* force a load, we assume iuser index will be set OK anyway */ + if(ima->type==IMA_TYPE_MULTILAYER) + BKE_image_get_ibuf(ima, iuser); + + if(ima->type==IMA_TYPE_MULTILAYER && ima->rr) { + RenderLayer *rl= BLI_findlink(&ima->rr->layers, iuser->layer); + + if(rl) { + out[0]->data= stackbuf= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_COMBINED); + + /* go over all layers */ + outputs_multilayer_get(rd, rl, out, ima, iuser); + } + } + else { + stackbuf= node_composit_get_image(rd, ima, iuser); + + /* put image on stack */ + out[0]->data= stackbuf; + + if(out[2]->hasoutput) + out[2]->data= node_composit_get_zimage(node, rd); + } + + /* alpha and preview for both types */ + if(stackbuf) { + if(out[1]->hasoutput) + out[1]->data= valbuf_from_rgbabuf(stackbuf, CHAN_A); + + generate_preview(node, stackbuf); + } + } +}; + +static void node_composit_init_image(bNode* node) +{ + ImageUser *iuser= MEM_callocN(sizeof(ImageUser), "node image user"); + node->storage= iuser; + iuser->sfra= 1; + iuser->fie_ima= 2; + iuser->ok= 1; +} + +bNodeType cmp_node_image= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_IMAGE, + /* name */ "Image", + /* width+range */ 120, 80, 300, + /* class+opts */ NODE_CLASS_INPUT, NODE_PREVIEW|NODE_OPTIONS, + /* input sock */ NULL, + /* output sock */ cmp_node_rlayers_out, + /* storage */ "ImageUser", + /* execfunc */ node_composit_exec_image, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_image, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL +}; + +/* **************** RENDER RESULT ******************** */ + +static CompBuf *compbuf_from_pass(RenderData *rd, RenderLayer *rl, int rectx, int recty, int passcode) +{ + float *fp= RE_RenderLayerGetPass(rl, passcode); + if(fp) { + CompBuf *buf; + int buftype= CB_VEC3; + + if(ELEM(passcode, SCE_PASS_Z, SCE_PASS_INDEXOB)) + buftype= CB_VAL; + else if(passcode==SCE_PASS_VECTOR) + buftype= CB_VEC4; + else if(ELEM(passcode, SCE_PASS_COMBINED, SCE_PASS_RGBA)) + buftype= CB_RGBA; + + if(rd->scemode & R_COMP_CROP) + buf= get_cropped_compbuf(&rd->disprect, fp, rectx, recty, buftype); + else { + buf= alloc_compbuf(rectx, recty, buftype, 0); + buf->rect= fp; + } + return buf; + } + return NULL; +}; + +void node_composit_rlayers_out(RenderData *rd, RenderLayer *rl, bNodeStack **out, int rectx, int recty) +{ + if(out[RRES_OUT_Z]->hasoutput) + out[RRES_OUT_Z]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_Z); + if(out[RRES_OUT_VEC]->hasoutput) + out[RRES_OUT_VEC]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_VECTOR); + if(out[RRES_OUT_NORMAL]->hasoutput) + out[RRES_OUT_NORMAL]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_NORMAL); + if(out[RRES_OUT_UV]->hasoutput) + out[RRES_OUT_UV]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_UV); + + if(out[RRES_OUT_RGBA]->hasoutput) + out[RRES_OUT_RGBA]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_RGBA); + if(out[RRES_OUT_DIFF]->hasoutput) + out[RRES_OUT_DIFF]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_DIFFUSE); + if(out[RRES_OUT_SPEC]->hasoutput) + out[RRES_OUT_SPEC]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_SPEC); + if(out[RRES_OUT_SHADOW]->hasoutput) + out[RRES_OUT_SHADOW]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_SHADOW); + if(out[RRES_OUT_AO]->hasoutput) + out[RRES_OUT_AO]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_AO); + if(out[RRES_OUT_REFLECT]->hasoutput) + out[RRES_OUT_REFLECT]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_REFLECT); + if(out[RRES_OUT_REFRACT]->hasoutput) + out[RRES_OUT_REFRACT]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_REFRACT); + if(out[RRES_OUT_RADIO]->hasoutput) + out[RRES_OUT_RADIO]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_RADIO); + if(out[RRES_OUT_INDEXOB]->hasoutput) + out[RRES_OUT_INDEXOB]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_INDEXOB); + +}; + +static void node_composit_exec_rlayers(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + Scene *sce= node->id?(Scene *)node->id:G.scene; /* G.scene is WEAK! */ + RenderData *rd= data; + RenderResult *rr; + + rr= RE_GetResult(RE_GetRender(sce->id.name)); + + if(rr) { + SceneRenderLayer *srl= BLI_findlink(&sce->r.layers, node->custom1); + if(srl) { + RenderLayer *rl= RE_GetRenderLayer(rr, srl->name); + if(rl && rl->rectf) { + CompBuf *stackbuf; + + /* we put render rect on stack, cbuf knows rect is from other ibuf when freed! */ + if(rd->scemode & R_COMP_CROP) + stackbuf= get_cropped_compbuf(&rd->disprect, rl->rectf, rr->rectx, rr->recty, CB_RGBA); + else { + stackbuf= alloc_compbuf(rr->rectx, rr->recty, CB_RGBA, 0); + stackbuf->rect= rl->rectf; + } + if(stackbuf==NULL) { + printf("Error; Preview Panel in UV Window returns zero sized image\n"); + } + else { + stackbuf->xof= rr->xof; + stackbuf->yof= rr->yof; + + /* put on stack */ + out[RRES_OUT_IMAGE]->data= stackbuf; + + if(out[RRES_OUT_ALPHA]->hasoutput) + out[RRES_OUT_ALPHA]->data= valbuf_from_rgbabuf(stackbuf, CHAN_A); + + node_composit_rlayers_out(rd, rl, out, rr->rectx, rr->recty); + + generate_preview(node, stackbuf); + } + } + } + } +}; + + +bNodeType cmp_node_rlayers= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_R_LAYERS, + /* name */ "Render Layers", + /* width+range */ 150, 100, 300, + /* class+opts */ NODE_CLASS_INPUT, NODE_PREVIEW|NODE_OPTIONS, + /* input sock */ NULL, + /* output sock */ cmp_node_rlayers_out, + /* storage */ "", + /* execfunc */ node_composit_exec_rlayers, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; + + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_invert.c b/source/blender/nodes/intern/CMP_nodes/CMP_invert.c new file mode 100644 index 00000000000..4d8f5d63e75 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_invert.c @@ -0,0 +1,134 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#include "../CMP_util.h" + +/* **************** INVERT ******************** */ +static bNodeSocketType cmp_node_invert_in[]= { + { SOCK_VALUE, 1, "Fac", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static bNodeSocketType cmp_node_invert_out[]= { + { SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_invert(bNode *node, float *out, float *in) +{ + if(node->custom1 & CMP_CHAN_RGB) { + out[0] = 1.0f - in[0]; + out[1] = 1.0f - in[1]; + out[2] = 1.0f - in[2]; + } else + VECCOPY(out, in); + + if(node->custom1 & CMP_CHAN_A) + out[3] = 1.0f - in[3]; + else + out[3] = in[3]; +} + +static void do_invert_fac(bNode *node, float *out, float *in, float *fac) +{ + float col[4], facm; + + do_invert(node, col, in); + + /* blend inverted result against original input with fac */ + facm = 1.0 - fac[0]; + + if(node->custom1 & CMP_CHAN_RGB) { + col[0] = fac[0]*col[0] + (facm*in[0]); + col[1] = fac[0]*col[1] + (facm*in[1]); + col[2] = fac[0]*col[2] + (facm*in[2]); + } + if(node->custom1 & CMP_CHAN_A) + col[3] = fac[0]*col[3] + (facm*in[3]); + + QUATCOPY(out, col); +} + +static void node_composit_exec_invert(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order in: fac, Image, Image */ + /* stack order out: Image */ + float *fac= in[0]->vec; + + if(out[0]->hasoutput==0) return; + + /* input no image? then only color operation */ + if(in[1]->data==NULL && in[0]->data==NULL) { + do_invert_fac(node, out[0]->vec, in[1]->vec, fac); + } + else { + /* make output size of first available input image, or then size of fac */ + CompBuf *cbuf= in[1]->data?in[1]->data:in[0]->data; + + /* if neither RGB or A toggled on, pass through */ + if (node->custom1 != 0) { + CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */ + + if (fac[0] < 1.0f || in[0]->data!=NULL) + composit2_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[0]->data, fac, do_invert_fac, CB_RGBA, CB_VAL); + else + composit1_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, do_invert, CB_RGBA); + out[0]->data= stackbuf; + return; + + } else { + out[0]->data = pass_on_compbuf(cbuf); + return; + } + } +} + +static void node_composit_init_invert(bNode *node) +{ + node->custom1 |= CMP_CHAN_RGB; +} + +/* custom1 = mix type */ +bNodeType cmp_node_invert= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_INVERT, + /* name */ "Invert", + /* width+range */ 120, 120, 140, + /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS, + /* input sock */ cmp_node_invert_in, + /* output sock */ cmp_node_invert_out, + /* storage */ "", + /* execfunc */ node_composit_exec_invert, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_invert, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_lensdist.c b/source/blender/nodes/intern/CMP_nodes/CMP_lensdist.c new file mode 100644 index 00000000000..5dec6115fba --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_lensdist.c @@ -0,0 +1,192 @@ +/** + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Alfredo de Greef (eeshlo) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + +static bNodeSocketType cmp_node_lensdist_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Distort", 0.f, 0.f, 0.f, 0.f, -0.999f, 1.f}, + { SOCK_VALUE, 1, "Dispersion", 0.f, 0.f, 0.f, 0.f, 0.f, 1.f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_lensdist_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + + +static void lensDistort(CompBuf* dst, CompBuf* src, float kr, float kg, float kb, int jit, int proj, int fit) +{ + int x, y, z; + const float cx = 0.5f*(float)dst->x, cy = 0.5f*(float)dst->y; + + if (proj) { + // shift + CompBuf* tsrc = dupalloc_compbuf(src); + for (z=0; ztype; ++z) + IIR_gauss(tsrc, (kr+0.5f)*(kr+0.5f), z, 1); + kr *= 20.f; + for (y=0; yy; y++) { + fRGB* colp = (fRGB*)&dst->rect[y*dst->x*dst->type]; + const float v = (y + 0.5f)/(float)dst->y; + for (x=0; xx; x++) { + const float u = (x + 0.5f)/(float)dst->x; + qd_getPixelLerpChan(tsrc, (u*dst->x + kr) - 0.5f, v*dst->y - 0.5f, 0, colp[x]); + if (tsrc->type == CB_VAL) + colp[x][1] = tsrc->rect[x + y*tsrc->x]; + else + colp[x][1] = tsrc->rect[(x + y*tsrc->x)*tsrc->type + 1]; + qd_getPixelLerpChan(tsrc, (u*dst->x - kr) - 0.5f, v*dst->y - 0.5f, 2, colp[x]+2); + } + } + free_compbuf(tsrc); + } + else { + // Spherical + // Scale factor to make bottom/top & right/left sides fit in window after deform + // so in the case of pincushion (kn < 0), corners will be outside window. + // Now also optionally scales image such that black areas are not visible when distort factor is positive + // (makes distorted corners match window corners, but really only valid if mk<=0.5) + const float mk = MAX3(kr, kg, kb); + const float sc = (fit && (mk > 0.f)) ? (1.f/(1.f + 2.f*mk)) : (1.f/(1.f + mk)); + const float drg = 4.f*(kg - kr), dgb = 4.f*(kb - kg); + kr *= 4.f, kg *= 4.f, kb *= 4.f; + + for (y=0; yy; y++) { + fRGB* colp = (fRGB*)&dst->rect[y*dst->x*dst->type]; + const float v = sc*((y + 0.5f) - cy)/cy; + for (x=0; xx; x++) { + int dr = 0, dg = 0, db = 0; + float d, t, ln[6] = {0, 0, 0, 0, 0, 0}; + fRGB c1, tc = {0, 0, 0, 0}; + const float u = sc*((x + 0.5f) - cx)/cx; + int sta = 0, mid = 0, end = 0; + if ((t = 1.f - kr*(u*u + v*v)) >= 0.f) { + d = 1.f/(1.f + sqrtf(t)); + ln[0] = (u*d + 0.5f)*dst->x - 0.5f, ln[1] = (v*d + 0.5f)*dst->y - 0.5f; + sta = 1; + } + if ((t = 1.f - kg*(u*u + v*v)) >= 0.f) { + d = 1.f/(1.f + sqrtf(t)); + ln[2] = (u*d + 0.5f)*dst->x - 0.5f, ln[3] = (v*d + 0.5f)*dst->y - 0.5f; + mid = 1; + } + if ((t = 1.f - kb*(u*u + v*v)) >= 0.f) { + d = 1.f/(1.f + sqrtf(t)); + ln[4] = (u*d + 0.5f)*dst->x - 0.5f, ln[5] = (v*d + 0.5f)*dst->y - 0.5f; + end = 1; + } + + if (sta && mid && end) { + // RG + const int dx = ln[2] - ln[0], dy = ln[3] - ln[1]; + const float dsf = sqrtf(dx*dx + dy*dy) + 1.f; + const int ds = (int)(jit ? ((dsf < 4.f) ? 2.f : sqrtf(dsf)) : dsf); + const float sd = 1.f/(float)ds; + for (z=0; zx - 0.5f, (v*d + 0.5f)*dst->y - 0.5f, c1); + if (src->type == CB_VAL) c1[1] = c1[2] = c1[0]; + tc[0] += (1.f-tz)*c1[0], tc[1] += tz*c1[1]; + dr++, dg++; + } + // GB + { + const int dx = ln[4] - ln[2], dy = ln[5] - ln[3]; + const float dsf = sqrtf(dx*dx + dy*dy) + 1.f; + const int ds = (int)(jit ? ((dsf < 4.f) ? 2.f : sqrtf(dsf)) : dsf); + const float sd = 1.f/(float)ds; + for (z=0; zx - 0.5f, (v*d + 0.5f)*dst->y - 0.5f, c1); + if (src->type == CB_VAL) c1[1] = c1[2] = c1[0]; + tc[1] += (1.f-tz)*c1[1], tc[2] += tz*c1[2]; + dg++, db++; + } + } + } + + if (dr) colp[x][0] = 2.f*tc[0] / (float)dr; + if (dg) colp[x][1] = 2.f*tc[1] / (float)dg; + if (db) colp[x][2] = 2.f*tc[2] / (float)db; + + } + } + + } + +} + + +static void node_composit_exec_lensdist(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + CompBuf *new, *img = in[0]->data; + NodeLensDist* nld = node->storage; + const float k = MAX2(MIN2(in[1]->vec[0], 1.f), -0.999f); + // smaller dispersion range for somewhat more control + const float d = 0.25f*MAX2(MIN2(in[2]->vec[0], 1.f), 0.f); + const float kr = MAX2(MIN2((k+d), 1.f), -0.999f), kb = MAX2(MIN2((k-d), 1.f), -0.999f); + + if ((img==NULL) || (out[0]->hasoutput==0)) return; + + new = alloc_compbuf(img->x, img->y, CB_RGBA, 1); + + lensDistort(new, img, (nld->proj ? d : kr), k, kb, nld->jit, nld->proj, nld->fit); + + out[0]->data = new; +} + + +static void node_composit_init_lensdist(bNode* node) +{ + NodeLensDist *nld = MEM_callocN(sizeof(NodeLensDist), "node lensdist data"); + nld->jit = nld->proj = nld->fit = 0; + node->storage = nld; +} + + +bNodeType cmp_node_lensdist = { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_LENSDIST, + /* name */ "Lens Distortion", + /* width+range */ 150, 120, 200, + /* class+opts */ NODE_CLASS_DISTORT, NODE_OPTIONS, + /* input sock */ cmp_node_lensdist_in, + /* output sock */ cmp_node_lensdist_out, + /* storage */ "NodeLensDist", + /* execfunc */ node_composit_exec_lensdist, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_lensdist, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL +}; diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_lummaMatte.c b/source/blender/nodes/intern/CMP_nodes/CMP_lummaMatte.c new file mode 100644 index 00000000000..973d74d71ff --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_lummaMatte.c @@ -0,0 +1,122 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + + +/* ******************* Luma Matte Node ********************************* */ +static bNodeSocketType cmp_node_luma_matte_in[]={ + {SOCK_RGBA,1,"Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + {-1,0,""} +}; + +static bNodeSocketType cmp_node_luma_matte_out[]={ + {SOCK_RGBA,0,"Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + {SOCK_VALUE,0,"Matte",0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + {-1,0,""} +}; + +static void do_luma_matte(bNode *node, float *out, float *in) +{ + NodeChroma *c=(NodeChroma *)node->storage; + float alpha; + + alpha=0.0; + + /* test range*/ + if(in[0]>c->t1) { + alpha=1.0; + } + else if(in[1]t2){ + alpha=0.0; + } + else {/*blend */ + alpha=(in[0]-c->t2)/(c->t1-c->t2); + } + + /* don't make something that was more transparent less transparent */ + if (alphahasinput==0) return; + if(in[0]->data==NULL) return; + if(out[0]->hasoutput==0 && out[1]->hasoutput==0) return; + + cbuf=typecheck_compbuf(in[0]->data, CB_RGBA); + + outbuf=dupalloc_compbuf(cbuf); + + composit1_pixel_processor(node, outbuf, cbuf, in[1]->vec, do_rgba_to_yuva, CB_RGBA); + composit1_pixel_processor(node, outbuf, outbuf, in[1]->vec, do_luma_matte, CB_RGBA); + composit1_pixel_processor(node, outbuf, outbuf, in[1]->vec, do_yuva_to_rgba, CB_RGBA); + + generate_preview(node, outbuf); + out[0]->data=outbuf; + if (out[1]->hasoutput) + out[1]->data=valbuf_from_rgbabuf(outbuf, CHAN_A); + if(cbuf!=in[0]->data) + free_compbuf(cbuf); +} + +static void node_composit_init_luma_matte(bNode *node) +{ + NodeChroma *c= MEM_callocN(sizeof(NodeChroma), "node chroma"); + node->storage=c; + c->t1= 0.0f; + c->t2= 0.0f; +}; + +bNodeType cmp_node_luma_matte={ + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_LUMA_MATTE, + /* name */ "Luminance Key", + /* width+range */ 200, 80, 250, + /* class+opts */ NODE_CLASS_MATTE, NODE_PREVIEW|NODE_OPTIONS, + /* input sock */ cmp_node_luma_matte_in, + /* output sock */ cmp_node_luma_matte_out, + /* storage */ "NodeChroma", + /* execfunc */ node_composit_exec_luma_matte, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_luma_matte, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL +}; + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_mapUV.c b/source/blender/nodes/intern/CMP_nodes/CMP_mapUV.c new file mode 100644 index 00000000000..ae3e5875aae --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_mapUV.c @@ -0,0 +1,149 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + +/* **************** Map UV ******************** */ + +static bNodeSocketType cmp_node_mapuv_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_VECTOR, 1, "UV", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_mapuv_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +/* foreach UV, use these values to read in cbuf and write to stackbuf */ +/* stackbuf should be zeroed */ +static void do_mapuv(CompBuf *stackbuf, CompBuf *cbuf, CompBuf *uvbuf, float threshold) +{ + ImBuf *ibuf; + float *out= stackbuf->rect, *uv, *uvnext, *uvprev; + float dx, dy, alpha; + int x, y, sx, sy, row= 3*stackbuf->x; + + /* ibuf needed for sampling */ + ibuf= IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0, 0); + ibuf->rect_float= cbuf->rect; + + /* vars for efficient looping */ + uv= uvbuf->rect; + uvnext= uv+row; + uvprev= uv-row; + sx= stackbuf->x; + sy= stackbuf->y; + + for(y=0; y0 && x0 && y 0.20f) dx= 0.20f; + if(dy > 0.20f) dy= 0.20f; + + ibuf_sample(ibuf, uv[0], uv[1], dx, dy, out); + /* premul */ + if(alpha<1.0f) { + out[0]*= alpha; + out[1]*= alpha; + out[2]*= alpha; + out[3]*= alpha; + } + } + } + } + } + + IMB_freeImBuf(ibuf); +} + + +static void node_composit_exec_mapuv(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + if(out[0]->hasoutput==0) + return; + + if(in[0]->data && in[1]->data) { + CompBuf *cbuf= in[0]->data; + CompBuf *uvbuf= in[1]->data; + CompBuf *stackbuf; + + cbuf= typecheck_compbuf(cbuf, CB_RGBA); + uvbuf= typecheck_compbuf(uvbuf, CB_VEC3); + stackbuf= alloc_compbuf(uvbuf->x, uvbuf->y, CB_RGBA, 1); /* allocs */; + + do_mapuv(stackbuf, cbuf, uvbuf, 0.05f*(float)node->custom1); + + out[0]->data= stackbuf; + + if(cbuf!=in[0]->data) + free_compbuf(cbuf); + if(uvbuf!=in[1]->data) + free_compbuf(uvbuf); + } +} + +bNodeType cmp_node_mapuv= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_MAP_UV, + /* name */ "Map UV", + /* width+range */ 140, 100, 320, + /* class+opts */ NODE_CLASS_DISTORT, NODE_OPTIONS, + /* input sock */ cmp_node_mapuv_in, + /* output sock */ cmp_node_mapuv_out, + /* storage */ "", + /* execfunc */ node_composit_exec_mapuv, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; + + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_mapValue.c b/source/blender/nodes/intern/CMP_nodes/CMP_mapValue.c new file mode 100644 index 00000000000..8f0f9621c2e --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_mapValue.c @@ -0,0 +1,101 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + +/* **************** MAP VALUE ******************** */ +static bNodeSocketType cmp_node_map_value_in[]= { + { SOCK_VALUE, 1, "Value", 1.0f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_map_value_out[]= { + { SOCK_VALUE, 0, "Value", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_map_value(bNode *node, float *out, float *src) +{ + TexMapping *texmap= node->storage; + + out[0]= (src[0] + texmap->loc[0])*texmap->size[0]; + if(texmap->flag & TEXMAP_CLIP_MIN) + if(out[0]min[0]) + out[0]= texmap->min[0]; + if(texmap->flag & TEXMAP_CLIP_MAX) + if(out[0]>texmap->max[0]) + out[0]= texmap->max[0]; +} + +static void node_composit_exec_map_value(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order in: valbuf */ + /* stack order out: valbuf */ + if(out[0]->hasoutput==0) return; + + /* input no image? then only value operation */ + if(in[0]->data==NULL) { + do_map_value(node, out[0]->vec, in[0]->vec); + } + else { + /* make output size of input image */ + CompBuf *cbuf= in[0]->data; + CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); /* allocs */ + + composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_map_value, CB_VAL); + + out[0]->data= stackbuf; + } +} + + +static void node_composit_init_map_value(bNode* node) +{ + node->storage= add_mapping(); +} + +bNodeType cmp_node_map_value= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_MAP_VALUE, + /* name */ "Map Value", + /* width+range */ 100, 60, 150, + /* class+opts */ NODE_CLASS_OP_VECTOR, NODE_OPTIONS, + /* input sock */ cmp_node_map_value_in, + /* output sock */ cmp_node_map_value_out, + /* storage */ "TexMapping", + /* execfunc */ node_composit_exec_map_value, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_map_value, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL + +}; + + + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_math.c b/source/blender/nodes/intern/CMP_nodes/CMP_math.c new file mode 100644 index 00000000000..cf2af9bbc11 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_math.c @@ -0,0 +1,187 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + + +/* **************** SCALAR MATH ******************** */ +static bNodeSocketType cmp_node_math_in[]= { + { SOCK_VALUE, 1, "Value", 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f}, + { SOCK_VALUE, 1, "Value", 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f}, + { -1, 0, "" } +}; + +static bNodeSocketType cmp_node_math_out[]= { + { SOCK_VALUE, 0, "Value", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_math(bNode *node, float *out, float *in, float *in2) +{ + switch(node->custom1) + { + case 0: /* Add */ + out[0]= in[0] + in2[0]; + break; + case 1: /* Subtract */ + out[0]= in[0] - in2[0]; + break; + case 2: /* Multiply */ + out[0]= in[0] * in2[0]; + break; + case 3: /* Divide */ + { + if(in[1]==0) /* We don't want to divide by zero. */ + out[0]= 0.0; + else + out[0]= in[0] / in2[0]; + } + break; + case 4: /* Sine */ + out[0]= sin(in[0]); + break; + case 5: /* Cosine */ + out[0]= cos(in[0]); + break; + case 6: /* Tangent */ + out[0]= tan(in[0]); + break; + case 7: /* Arc-Sine */ + { + /* Can't do the impossible... */ + if(in[0] <= 1 && in[0] >= -1 ) + out[0]= asin(in[0]); + else + out[0]= 0.0; + } + break; + case 8: /* Arc-Cosine */ + { + /* Can't do the impossible... */ + if( in[0] <= 1 && in[0] >= -1 ) + out[0]= acos(in[0]); + else + out[0]= 0.0; + } + break; + case 9: /* Arc-Tangent */ + out[0]= atan(in[0]); + break; + case 10: /* Power */ + { + /* Don't want any imaginary numbers... */ + if( in[0] >= 0 ) + out[0]= pow(in[0], in2[0]); + else + out[0]= 0.0; + } + break; + case 11: /* Logarithm */ + { + /* Don't want any imaginary numbers... */ + if( in[0] > 0 && in2[0] > 0 ) + out[0]= log(in[0]) / log(in2[0]); + else + out[0]= 0.0; + } + break; + case 12: /* Minimum */ + { + if( in[0] < in2[0] ) + out[0]= in[0]; + else + out[0]= in2[0]; + } + break; + case 13: /* Maximum */ + { + if( in[0] > in2[0] ) + out[0]= in[0]; + else + out[0]= in2[0]; + } + break; + case 14: /* Round */ + { + out[0]= (int)(in[0] + 0.5f); + } + break; + } +} + +static void node_composit_exec_math(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + CompBuf *cbuf=in[0]->data; + CompBuf *cbuf2=in[1]->data; + CompBuf *stackbuf; + + /* check for inputs and outputs for early out*/ + if(in[0]->hasinput==0 && in[1]->hasinput==0) return; + if(out[0]->hasoutput==0) return; + + /* no image-color operation */ + if(in[0]->data==NULL && in[1]->data==NULL) { + do_math(node, out[0]->vec, in[0]->vec, in[1]->vec); + return; + } + + /*create output based on first input */ + if(cbuf) { + stackbuf=alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); + } + /* and if it doesn't exist use the second input since we + know that one of them must exist at this point*/ + else { + stackbuf=alloc_compbuf(cbuf2->x, cbuf2->y, CB_VAL, 1); + } + + /* operate in case there's valid size */ + composit2_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_math, CB_VAL, CB_VAL); + out[0]->data= stackbuf; +} + +bNodeType cmp_node_math= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_MATH, + /* name */ "Math", + /* width+range */ 120, 110, 160, + /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS, + /* input sock */ cmp_node_math_in, + /* output sock */ cmp_node_math_out, + /* storage */ "", + /* execfunc */ node_composit_exec_math, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; + + + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_mixrgb.c b/source/blender/nodes/intern/CMP_nodes/CMP_mixrgb.c new file mode 100644 index 00000000000..6a4916b3fac --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_mixrgb.c @@ -0,0 +1,96 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#include "../CMP_util.h" + +/* **************** MIX RGB ******************** */ +static bNodeSocketType cmp_node_mix_rgb_in[]= { + { SOCK_VALUE, 1, "Fac", 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 5.0f}, + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_mix_rgb_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_mix_rgb(bNode *node, float *out, float *in1, float *in2, float *fac) +{ + float col[3]; + + VECCOPY(col, in1); + if(node->custom2) + ramp_blend(node->custom1, col, col+1, col+2, in2[3]*fac[0], in2); + else + ramp_blend(node->custom1, col, col+1, col+2, fac[0], in2); + VECCOPY(out, col); + out[3]= in1[3]; +} + +static void node_composit_exec_mix_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order in: fac, Image, Image */ + /* stack order out: Image */ + float *fac= in[0]->vec; + + if(out[0]->hasoutput==0) return; + + /* input no image? then only color operation */ + if(in[1]->data==NULL && in[2]->data==NULL) { + do_mix_rgb(node, out[0]->vec, in[1]->vec, in[2]->vec, fac); + } + else { + /* make output size of first available input image */ + CompBuf *cbuf= in[1]->data?in[1]->data:in[2]->data; + CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */ + + composit3_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[2]->data, in[2]->vec, in[0]->data, fac, do_mix_rgb, CB_RGBA, CB_RGBA, CB_VAL); + + out[0]->data= stackbuf; + } +} + +/* custom1 = mix type */ +bNodeType cmp_node_mix_rgb= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_MIX_RGB, + /* name */ "Mix", + /* width+range */ 110, 60, 120, + /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS, + /* input sock */ cmp_node_mix_rgb_in, + /* output sock */ cmp_node_mix_rgb_out, + /* storage */ "", + /* execfunc */ node_composit_exec_mix_rgb, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_normal.c b/source/blender/nodes/intern/CMP_nodes/CMP_normal.c new file mode 100644 index 00000000000..5219b224c6c --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_normal.c @@ -0,0 +1,97 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + + +/* **************** NORMAL ******************** */ +static bNodeSocketType cmp_node_normal_in[]= { + { SOCK_VECTOR, 1, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, + { -1, 0, "" } +}; + +static bNodeSocketType cmp_node_normal_out[]= { + { SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f}, + { SOCK_VALUE, 0, "Dot", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_normal(bNode *node, float *out, float *in) +{ + bNodeSocket *sock= node->outputs.first; + float *nor= sock->ns.vec; + + /* render normals point inside... the widget points outside */ + out[0]= -INPR(nor, in); +} + +/* generates normal, does dot product */ +static void node_composit_exec_normal(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + bNodeSocket *sock= node->outputs.first; + /* stack order input: normal */ + /* stack order output: normal, value */ + + /* input no image? then only vector op */ + if(in[0]->data==NULL) { + VECCOPY(out[0]->vec, sock->ns.vec); + /* render normals point inside... the widget points outside */ + out[1]->vec[0]= -INPR(out[0]->vec, in[0]->vec); + } + else if(out[1]->hasoutput) { + /* make output size of input image */ + CompBuf *cbuf= in[0]->data; + CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); /* allocs */ + + composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_normal, CB_VEC3); + + out[1]->data= stackbuf; + } + + +} + +bNodeType cmp_node_normal= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_NORMAL, + /* name */ "Normal", + /* width+range */ 100, 60, 200, + /* class+opts */ NODE_CLASS_OP_VECTOR, NODE_OPTIONS, + /* input sock */ cmp_node_normal_in, + /* output sock */ cmp_node_normal_out, + /* storage */ "", + /* execfunc */ node_composit_exec_normal, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_normalize.c b/source/blender/nodes/intern/CMP_nodes/CMP_normalize.c new file mode 100644 index 00000000000..a62e4be4015 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_normalize.c @@ -0,0 +1,113 @@ +/** + * $Id: CMP_normalize.c,v 1.0 2007/03/24 06:57:29 scourage Exp $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): gsr b3d, and a very minor edit from Robert Holcomb + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + + +/* **************** NORMALIZE single channel, useful for Z buffer ******************** */ +static bNodeSocketType cmp_node_normalize_in[]= { + { SOCK_VALUE, 1, "Value", 1.0f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_normalize_out[]= { + { SOCK_VALUE, 0, "Value", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_normalize(bNode *node, float *out, float *src, float *min, float *mult) +{ + float res; + res = (src[0] - min[0]) * mult[0]; + if (res > 1.0f) { + out[0] = 1.0f; + } + else if (res < 0.0f) { + out[0] = 0.0f; + } + else { + out[0] = res; + } +} + +#define BLENDER_ZMAX 10000.0f + +static void node_composit_exec_normalize(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order in: valbuf */ + /* stack order out: valbuf */ + if(out[0]->hasoutput==0) return; + + /* input no image? then only value operation */ + if(in[0]->data==NULL) { + QUATCOPY(out[0]->vec, in[0]->vec); + } + else { + float min = 1.0f+BLENDER_ZMAX; + float max = -1.0f-BLENDER_ZMAX; + float mult = 1.0f; + float *val; + /* make output size of input image */ + CompBuf *cbuf= in[0]->data; + int tot= cbuf->x*cbuf->y; + CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); /* allocs */ + + for (val = cbuf->rect; tot; tot--, val++) { + if ((*val > max) && (*val < BLENDER_ZMAX)) { + max = *val; + } + if (*val < min) { + min = *val; + } + } + mult = 1.0f/(max-min); + + printf("min %f max %f\n", min, max); + + composit3_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, NULL, &min, NULL, &mult, do_normalize, CB_VAL, CB_VAL, CB_VAL); + + out[0]->data= stackbuf; + } +} + +bNodeType cmp_node_normalize= { + /* *next, *prev*/ NULL, NULL, + /* type code */ CMP_NODE_NORMALIZE, + /* name */ "Normalize", + /* width+range */ 100, 60, 150, + /* class+opts */ NODE_CLASS_OP_VECTOR, NODE_OPTIONS, + /* input sock */ cmp_node_normalize_in, + /* output sock */ cmp_node_normalize_out, + /* storage */ "TexMapping", + /* execfunc */ node_composit_exec_normalize, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_outputFile.c b/source/blender/nodes/intern/CMP_nodes/CMP_outputFile.c new file mode 100644 index 00000000000..722b00d57a9 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_outputFile.c @@ -0,0 +1,112 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + +/* **************** OUTPUT FILE ******************** */ +static bNodeSocketType cmp_node_output_file_in[]= { + { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Z", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_composit_exec_output_file(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* image assigned to output */ + /* stack order input sockets: col, alpha */ + + if(in[0]->data) { + RenderData *rd= data; + NodeImageFile *nif= node->storage; + if(nif->sfra!=nif->efra && (rd->cfrasfra || rd->cfra>nif->efra)) { + return; /* BAIL OUT RETURN */ + } + else { + CompBuf *cbuf= typecheck_compbuf(in[0]->data, CB_RGBA); + ImBuf *ibuf= IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0, 0); + char string[256]; + + ibuf->rect_float= cbuf->rect; + ibuf->dither= rd->dither_intensity; + if(in[1]->data) { + CompBuf *zbuf= in[1]->data; + if(zbuf->type==CB_VAL && zbuf->x==cbuf->x && zbuf->y==cbuf->y) { + nif->subimtype|= R_OPENEXR_ZBUF; + ibuf->zbuf_float= zbuf->rect; + } + } + + BKE_makepicstring(string, nif->name, rd->cfra, nif->imtype); + + if(0 == BKE_write_ibuf(ibuf, string, nif->imtype, nif->subimtype, nif->imtype==R_OPENEXR?nif->codec:nif->quality)) + printf("Cannot save Node File Output to %s\n", string); + else + printf("Saved: %s\n", string); + + IMB_freeImBuf(ibuf); + + generate_preview(node, cbuf); + + if(in[0]->data != cbuf) + free_compbuf(cbuf); + } + } +} + +static void node_composit_init_output_file(bNode *node) +{ + NodeImageFile *nif= MEM_callocN(sizeof(NodeImageFile), "node image file"); + node->storage= nif; + BLI_strncpy(nif->name, G.scene->r.pic, sizeof(nif->name)); + nif->imtype= G.scene->r.imtype; + nif->subimtype= G.scene->r.subimtype; + nif->quality= G.scene->r.quality; + nif->sfra= G.scene->r.sfra; + nif->efra= G.scene->r.efra; +}; + +bNodeType cmp_node_output_file= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_OUTPUT_FILE, + /* name */ "File Output", + /* width+range */ 140, 80, 300, + /* class+opts */ NODE_CLASS_OUTPUT, NODE_PREVIEW|NODE_OPTIONS, + /* input sock */ cmp_node_output_file_in, + /* output sock */ NULL, + /* storage */ "NodeImageFile", + /* execfunc */ node_composit_exec_output_file, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_output_file, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL + +}; + + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_rgb.c b/source/blender/nodes/intern/CMP_nodes/CMP_rgb.c new file mode 100644 index 00000000000..ae2678dc5f0 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_rgb.c @@ -0,0 +1,64 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + + +/* **************** RGB ******************** */ +static bNodeSocketType cmp_node_rgb_out[]= { + { SOCK_RGBA, 0, "RGBA", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_composit_exec_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + bNodeSocket *sock= node->outputs.first; + + VECCOPY(out[0]->vec, sock->ns.vec); +} + +bNodeType cmp_node_rgb= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_RGB, + /* name */ "RGB", + /* width+range */ 100, 60, 140, + /* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS, + /* input sock */ NULL, + /* output sock */ cmp_node_rgb_out, + /* storage */ "", + /* execfunc */ node_composit_exec_rgb, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; + + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_rotate.c b/source/blender/nodes/intern/CMP_nodes/CMP_rotate.c new file mode 100644 index 00000000000..d32c2ccd9e7 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_rotate.c @@ -0,0 +1,150 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + +/* **************** Rotate ******************** */ + +static bNodeSocketType cmp_node_rotate_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Degr", 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_rotate_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +/* function assumes out to be zero'ed, only does RGBA */ +static void bilinear_interpolation_rotate(CompBuf *in, float *out, float u, float v) +{ + float *row1, *row2, *row3, *row4, a, b; + float a_b, ma_b, a_mb, ma_mb; + float empty[4]= {0.0f, 0.0f, 0.0f, 0.0f}; + int y1, y2, x1, x2; + + x1= (int)floor(u); + x2= (int)ceil(u); + y1= (int)floor(v); + y2= (int)ceil(v); + + /* sample area entirely outside image? */ + if(x2<0 || x1>in->x-1 || y2<0 || y1>in->y-1) + return; + + /* sample including outside of edges of image */ + if(x1<0 || y1<0) row1= empty; + else row1= in->rect + in->x * y1 * in->type + in->type*x1; + + if(x1<0 || y2>in->y-1) row2= empty; + else row2= in->rect + in->x * y2 * in->type + in->type*x1; + + if(x2>in->x-1 || y1<0) row3= empty; + else row3= in->rect + in->x * y1 * in->type + in->type*x2; + + if(x2>in->x-1 || y2>in->y-1) row4= empty; + else row4= in->rect + in->x * y2 * in->type + in->type*x2; + + a= u-floor(u); + b= v-floor(v); + a_b= a*b; ma_b= (1.0f-a)*b; a_mb= a*(1.0f-b); ma_mb= (1.0f-a)*(1.0f-b); + + out[0]= ma_mb*row1[0] + a_mb*row3[0] + ma_b*row2[0]+ a_b*row4[0]; + out[1]= ma_mb*row1[1] + a_mb*row3[1] + ma_b*row2[1]+ a_b*row4[1]; + out[2]= ma_mb*row1[2] + a_mb*row3[2] + ma_b*row2[2]+ a_b*row4[2]; + out[3]= ma_mb*row1[3] + a_mb*row3[3] + ma_b*row2[3]+ a_b*row4[3]; +} + +/* only supports RGBA nodes now */ +static void node_composit_exec_rotate(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + + if(out[0]->hasoutput==0) + return; + + if(in[0]->data) { + CompBuf *cbuf= typecheck_compbuf(in[0]->data, CB_RGBA); + CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* note, this returns zero'd image */ + float *ofp, rad, u, v, s, c, centx, centy, miny, maxy, minx, maxx; + int x, y, yo; + + rad= (M_PI*in[1]->vec[0])/180.0f; + + s= sin(rad); + c= cos(rad); + centx= cbuf->x/2; + centy= cbuf->y/2; + + minx= -centx; + maxx= -centx + (float)cbuf->x; + miny= -centy; + maxy= -centy + (float)cbuf->y; + + for(y=miny; yrect + 4*yo*stackbuf->x; + + for(x=minx; xxof; centy= (float)cbuf->yof; + stackbuf->xof= (int)( c*centx + s*centy); + stackbuf->yof= (int)(-s*centx + c*centy); + + /* pass on output and free */ + out[0]->data= stackbuf; + if(cbuf!=in[0]->data) + free_compbuf(cbuf); + + } +} + +bNodeType cmp_node_rotate= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_ROTATE, + /* name */ "Rotate", + /* width+range */ 140, 100, 320, + /* class+opts */ NODE_CLASS_DISTORT, NODE_OPTIONS, + /* input sock */ cmp_node_rotate_in, + /* output sock */ cmp_node_rotate_out, + /* storage */ "", + /* execfunc */ node_composit_exec_rotate, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_scale.c b/source/blender/nodes/intern/CMP_nodes/CMP_scale.c new file mode 100644 index 00000000000..a8477f4264e --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_scale.c @@ -0,0 +1,125 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + +/* **************** Scale ******************** */ + +#define CMP_SCALE_MAX 12000 + +static bNodeSocketType cmp_node_scale_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "X", 1.0f, 0.0f, 0.0f, 0.0f, 0.0001f, CMP_SCALE_MAX}, + { SOCK_VALUE, 1, "Y", 1.0f, 0.0f, 0.0f, 0.0f, 0.0001f, CMP_SCALE_MAX}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_scale_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +/* only supports RGBA nodes now */ +/* node->custom1 stores if input values are absolute or relative scale */ +static void node_composit_exec_scale(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + if(out[0]->hasoutput==0) + return; + + if(in[0]->data) { + CompBuf *stackbuf, *cbuf= typecheck_compbuf(in[0]->data, CB_RGBA); + ImBuf *ibuf; + int newx, newy; + + if(node->custom1==CMP_SCALE_RELATIVE) { + newx= MAX2((int)(in[1]->vec[0]*cbuf->x), 1); + newy= MAX2((int)(in[2]->vec[0]*cbuf->y), 1); + } + else { /* CMP_SCALE_ABSOLUTE */ + newx= (int)in[1]->vec[0]; + newy= (int)in[2]->vec[0]; + } + newx= MIN2(newx, CMP_SCALE_MAX); + newy= MIN2(newy, CMP_SCALE_MAX); + + ibuf= IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0, 0); + if(ibuf) { + ibuf->rect_float= cbuf->rect; + IMB_scaleImBuf(ibuf, newx, newy); + + if(ibuf->rect_float == cbuf->rect) { + /* no scaling happened. */ + stackbuf= pass_on_compbuf(in[0]->data); + } + else { + stackbuf= alloc_compbuf(newx, newy, CB_RGBA, 0); + stackbuf->rect= ibuf->rect_float; + stackbuf->malloc= 1; + } + + ibuf->rect_float= NULL; + ibuf->mall &= ~IB_rectfloat; + IMB_freeImBuf(ibuf); + + /* also do the translation vector */ + stackbuf->xof = (int)(((float)newx/(float)cbuf->x) * (float)cbuf->xof); + stackbuf->yof = (int)(((float)newy/(float)cbuf->y) * (float)cbuf->yof); + } + else { + stackbuf= dupalloc_compbuf(cbuf); + printf("Scaling to %dx%d failed\n", newx, newy); + } + + out[0]->data= stackbuf; + if(cbuf!=in[0]->data) + free_compbuf(cbuf); + } +}; + +bNodeType cmp_node_scale= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_SCALE, + /* name */ "Scale", + /* width+range */ 140, 100, 320, + /* class+opts */ NODE_CLASS_DISTORT, NODE_OPTIONS, + /* input sock */ cmp_node_scale_in, + /* output sock */ cmp_node_scale_out, + /* storage */ "", + /* execfunc */ node_composit_exec_scale, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; + + + + + + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_sepcombHSVA.c b/source/blender/nodes/intern/CMP_nodes/CMP_sepcombHSVA.c new file mode 100644 index 00000000000..e7598726555 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_sepcombHSVA.c @@ -0,0 +1,191 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + + +/* **************** SEPARATE HSVA ******************** */ +static bNodeSocketType cmp_node_sephsva_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_sephsva_out[]= { + { SOCK_VALUE, 0, "H", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "S", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "V", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "A", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_sephsva(bNode *node, float *out, float *in) +{ + float h, s, v; + + rgb_to_hsv(in[0], in[1], in[2], &h, &s, &v); + + out[0]= h; + out[1]= s; + out[2]= v; + out[3]= in[3]; +} + +static void node_composit_exec_sephsva(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order out: bw channels */ + /* stack order in: col */ + + /* input no image? then only color operation */ + if(in[0]->data==NULL) { + float h, s, v; + + rgb_to_hsv(in[0]->vec[0], in[0]->vec[1], in[0]->vec[2], &h, &s, &v); + + out[0]->vec[0] = h; + out[1]->vec[0] = s; + out[2]->vec[0] = v; + out[3]->vec[0] = in[0]->vec[3]; + } + else if ((out[0]->hasoutput) || (out[1]->hasoutput) || (out[2]->hasoutput) || (out[3]->hasoutput)) { + /* create new buffer so input buffer doesn't get corrupted */ + CompBuf *cbuf= dupalloc_compbuf(in[0]->data); + CompBuf *cbuf2= typecheck_compbuf(cbuf, CB_RGBA); + + /* convert the RGB stackbuf to an HSV representation */ + composit1_pixel_processor(node, cbuf2, cbuf2, in[0]->vec, do_sephsva, CB_RGBA); + + /* separate each of those channels */ + if(out[0]->hasoutput) + out[0]->data= valbuf_from_rgbabuf(cbuf2, CHAN_R); + if(out[1]->hasoutput) + out[1]->data= valbuf_from_rgbabuf(cbuf2, CHAN_G); + if(out[2]->hasoutput) + out[2]->data= valbuf_from_rgbabuf(cbuf2, CHAN_B); + if(out[3]->hasoutput) + out[3]->data= valbuf_from_rgbabuf(cbuf2, CHAN_A); + + /*not used anymore */ + if(cbuf2!=cbuf) + free_compbuf(cbuf2); + free_compbuf(cbuf); + } +} + +bNodeType cmp_node_sephsva= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_SEPHSVA, + /* name */ "Separate HSVA", + /* width+range */ 80, 40, 140, + /* class+opts */ NODE_CLASS_CONVERTOR, 0, + /* input sock */ cmp_node_sephsva_in, + /* output sock */ cmp_node_sephsva_out, + /* storage */ "", + /* execfunc */ node_composit_exec_sephsva, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; + +/* **************** COMBINE HSVA ******************** */ +static bNodeSocketType cmp_node_combhsva_in[]= { + { SOCK_VALUE, 1, "H", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "S", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "V", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "A", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_combhsva_out[]= { + { SOCK_RGBA, 0, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_comb_hsva(bNode *node, float *out, float *in1, float *in2, float *in3, float *in4) +{ + float r,g,b; + hsv_to_rgb(in1[0], in2[0], in3[0], &r, &g, &b); + + out[0] = r; + out[1] = g; + out[2] = b; + out[3] = in4[0]; +} + +static void node_composit_exec_combhsva(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order out: 1 rgba channels */ + /* stack order in: 4 value channels */ + + /* input no image? then only color operation */ + if((in[0]->data==NULL) && (in[1]->data==NULL) && (in[2]->data==NULL) && (in[3]->data==NULL)) { + out[0]->vec[0] = in[0]->vec[0]; + out[0]->vec[1] = in[1]->vec[0]; + out[0]->vec[2] = in[2]->vec[0]; + out[0]->vec[3] = in[3]->vec[0]; + } + else { + /* make output size of first available input image */ + CompBuf *cbuf; + CompBuf *stackbuf; + + /* allocate a CompBuf the size of the first available input */ + if (in[0]->data) cbuf = in[0]->data; + else if (in[1]->data) cbuf = in[1]->data; + else if (in[2]->data) cbuf = in[2]->data; + else cbuf = in[3]->data; + + stackbuf = alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */ + + composit4_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, + in[2]->data, in[2]->vec, in[3]->data, in[3]->vec, + do_comb_hsva, CB_VAL, CB_VAL, CB_VAL, CB_VAL); + + out[0]->data= stackbuf; + } +} + +bNodeType cmp_node_combhsva= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_COMBHSVA, + /* name */ "Combine HSVA", + /* width+range */ 80, 40, 140, + /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS, + /* input sock */ cmp_node_combhsva_in, + /* output sock */ cmp_node_combhsva_out, + /* storage */ "", + /* execfunc */ node_composit_exec_combhsva, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; + + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_sepcombRGBA.c b/source/blender/nodes/intern/CMP_nodes/CMP_sepcombRGBA.c new file mode 100644 index 00000000000..08546c15450 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_sepcombRGBA.c @@ -0,0 +1,167 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + +/* **************** SEPARATE RGBA ******************** */ +static bNodeSocketType cmp_node_seprgba_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_seprgba_out[]= { + { SOCK_VALUE, 0, "R", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "G", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "B", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "A", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_composit_exec_seprgba(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order out: bw channels */ + /* stack order in: col */ + + /* input no image? then only color operation */ + if(in[0]->data==NULL) { + out[0]->vec[0] = in[0]->vec[0]; + out[1]->vec[0] = in[0]->vec[1]; + out[2]->vec[0] = in[0]->vec[2]; + out[3]->vec[0] = in[0]->vec[3]; + } + else { + /* make sure we get right rgba buffer */ + CompBuf *cbuf= typecheck_compbuf(in[0]->data, CB_RGBA); + + /* don't do any pixel processing, just copy the stack directly (faster, I presume) */ + if(out[0]->hasoutput) + out[0]->data= valbuf_from_rgbabuf(cbuf, CHAN_R); + if(out[1]->hasoutput) + out[1]->data= valbuf_from_rgbabuf(cbuf, CHAN_G); + if(out[2]->hasoutput) + out[2]->data= valbuf_from_rgbabuf(cbuf, CHAN_B); + if(out[3]->hasoutput) + out[3]->data= valbuf_from_rgbabuf(cbuf, CHAN_A); + + if(cbuf!=in[0]->data) + free_compbuf(cbuf); + + } +} + +bNodeType cmp_node_seprgba= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_SEPRGBA, + /* name */ "Separate RGBA", + /* width+range */ 80, 40, 140, + /* class+opts */ NODE_CLASS_CONVERTOR, 0, + /* input sock */ cmp_node_seprgba_in, + /* output sock */ cmp_node_seprgba_out, + /* storage */ "", + /* execfunc */ node_composit_exec_seprgba, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; + + +/* **************** COMBINE RGBA ******************** */ +static bNodeSocketType cmp_node_combrgba_in[]= { + { SOCK_VALUE, 1, "R", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "G", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "B", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "A", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_combrgba_out[]= { + { SOCK_RGBA, 0, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_combrgba(bNode *node, float *out, float *in1, float *in2, float *in3, float *in4) +{ + out[0] = in1[0]; + out[1] = in2[0]; + out[2] = in3[0]; + out[3] = in4[0]; +} + +static void node_composit_exec_combrgba(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order out: 1 rgba channels */ + /* stack order in: 4 value channels */ + + /* input no image? then only color operation */ + if((in[0]->data==NULL) && (in[1]->data==NULL) && (in[2]->data==NULL) && (in[3]->data==NULL)) { + out[0]->vec[0] = in[0]->vec[0]; + out[0]->vec[1] = in[1]->vec[0]; + out[0]->vec[2] = in[2]->vec[0]; + out[0]->vec[3] = in[3]->vec[0]; + } + else { + /* make output size of first available input image */ + CompBuf *cbuf; + CompBuf *stackbuf; + + /* allocate a CompBuf the size of the first available input */ + if (in[0]->data) cbuf = in[0]->data; + else if (in[1]->data) cbuf = in[1]->data; + else if (in[2]->data) cbuf = in[2]->data; + else cbuf = in[3]->data; + + stackbuf = alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */ + + composit4_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, + in[2]->data, in[2]->vec, in[3]->data, in[3]->vec, + do_combrgba, CB_VAL, CB_VAL, CB_VAL, CB_VAL); + + out[0]->data= stackbuf; + } +} + +bNodeType cmp_node_combrgba= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_COMBRGBA, + /* name */ "Combine RGBA", + /* width+range */ 80, 40, 140, + /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS, + /* input sock */ cmp_node_combrgba_in, + /* output sock */ cmp_node_combrgba_out, + /* storage */ "", + /* execfunc */ node_composit_exec_combrgba, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_sepcombYCCA.c b/source/blender/nodes/intern/CMP_nodes/CMP_sepcombYCCA.c new file mode 100644 index 00000000000..6802fab0bfc --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_sepcombYCCA.c @@ -0,0 +1,197 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + + +/* **************** SEPARATE YCCA ******************** */ +static bNodeSocketType cmp_node_sepycca_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_sepycca_out[]= { + { SOCK_VALUE, 0, "Y", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "Cb", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "Cr", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "A", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_sepycca(bNode *node, float *out, float *in) +{ + float y, cb, cr; + + rgb_to_ycc(in[0], in[1], in[2], &y, &cb, &cr); + + /*divided by 255 to normalize for viewing in */ + out[0]= y/255.0; + out[1]= cb/255.0; + out[2]= cr/255.0; + out[3]= in[3]; +} + +static void node_composit_exec_sepycca(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* input no image? then only color operation */ + if(in[0]->data==NULL) { + float y, cb, cr; + + rgb_to_ycc(in[0]->vec[0], in[0]->vec[1], in[0]->vec[2], &y, &cb, &cr); + + /*divided by 255 to normalize for viewing in */ + out[0]->vec[0] = y/255.0; + out[1]->vec[0] = cb/255.0; + out[2]->vec[0] = cr/255.0; + out[3]->vec[0] = in[0]->vec[3]; + } + else if ((out[0]->hasoutput) || (out[1]->hasoutput) || (out[2]->hasoutput) || (out[3]->hasoutput)) { + /* make copy of buffer so input buffer doesn't get corrupted */ + CompBuf *cbuf= dupalloc_compbuf(in[0]->data); + CompBuf *cbuf2=typecheck_compbuf(cbuf, CB_RGBA); + + /* convert the RGB stackbuf to an HSV representation */ + composit1_pixel_processor(node, cbuf2, cbuf2, in[0]->vec, do_sepycca, CB_RGBA); + + /* separate each of those channels */ + if(out[0]->hasoutput) + out[0]->data= valbuf_from_rgbabuf(cbuf2, CHAN_R); + if(out[1]->hasoutput) + out[1]->data= valbuf_from_rgbabuf(cbuf2, CHAN_G); + if(out[2]->hasoutput) + out[2]->data= valbuf_from_rgbabuf(cbuf2, CHAN_B); + if(out[3]->hasoutput) + out[3]->data= valbuf_from_rgbabuf(cbuf2, CHAN_A); + + /*not used anymore */ + if(cbuf2!=cbuf) + free_compbuf(cbuf2); + free_compbuf(cbuf); + } +} + +bNodeType cmp_node_sepycca= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_SEPYCCA, + /* name */ "Separate YCbCrA", + /* width+range */ 80, 40, 140, + /* class+opts */ NODE_CLASS_CONVERTOR, 0, + /* input sock */ cmp_node_sepycca_in, + /* output sock */ cmp_node_sepycca_out, + /* storage */ "", + /* execfunc */ node_composit_exec_sepycca, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; + + +/* **************** COMBINE YCCA ******************** */ +static bNodeSocketType cmp_node_combycca_in[]= { + { SOCK_VALUE, 1, "Y", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Cb", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Cr", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "A", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_combycca_out[]= { + { SOCK_RGBA, 0, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_comb_ycca(bNode *node, float *out, float *in1, float *in2, float *in3, float *in4) +{ + float r,g,b; + float y, cb, cr; + + /*need to un-normalize the data*/ + y=in1[0]*255; + cb=in2[0]*255; + cr=in3[0]*255; + + ycc_to_rgb(y,cb,cr, &r, &g, &b); + + out[0] = r; + out[1] = g; + out[2] = b; + out[3] = in4[0]; +} + +static void node_composit_exec_combycca(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order out: 1 ycca channels */ + /* stack order in: 4 value channels */ + + /* input no image? then only color operation */ + if((in[0]->data==NULL) && (in[1]->data==NULL) && (in[2]->data==NULL) && (in[3]->data==NULL)) { + out[0]->vec[0] = in[0]->vec[0]; + out[0]->vec[1] = in[1]->vec[0]; + out[0]->vec[2] = in[2]->vec[0]; + out[0]->vec[3] = in[3]->vec[0]; + } + else { + /* make output size of first available input image */ + CompBuf *cbuf; + CompBuf *stackbuf; + + /* allocate a CompBuf the size of the first available input */ + if (in[0]->data) cbuf = in[0]->data; + else if (in[1]->data) cbuf = in[1]->data; + else if (in[2]->data) cbuf = in[2]->data; + else cbuf = in[3]->data; + + stackbuf = alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */ + + composit4_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, + in[2]->data, in[2]->vec, in[3]->data, in[3]->vec, + do_comb_ycca, CB_VAL, CB_VAL, CB_VAL, CB_VAL); + + out[0]->data= stackbuf; + } +} + +bNodeType cmp_node_combycca= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_COMBYCCA, + /* name */ "Combine YCbCrA", + /* width+range */ 80, 40, 140, + /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS, + /* input sock */ cmp_node_combycca_in, + /* output sock */ cmp_node_combycca_out, + /* storage */ "", + /* execfunc */ node_composit_exec_combycca, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; + + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_sepcombYUVA.c b/source/blender/nodes/intern/CMP_nodes/CMP_sepcombYUVA.c new file mode 100644 index 00000000000..08027c5bc04 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_sepcombYUVA.c @@ -0,0 +1,190 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + + +/* **************** SEPARATE YUVA ******************** */ +static bNodeSocketType cmp_node_sepyuva_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_sepyuva_out[]= { + { SOCK_VALUE, 0, "Y", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "U", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "V", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "A", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_sepyuva(bNode *node, float *out, float *in) +{ + float y, u, v; + + rgb_to_yuv(in[0], in[1], in[2], &y, &u, &v); + + out[0]= y; + out[1]= u; + out[2]= v; + out[3]= in[3]; +} + +static void node_composit_exec_sepyuva(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order out: bw channels */ + /* stack order in: col */ + + /* input no image? then only color operation */ + if(in[0]->data==NULL) { + float y, u, v; + + rgb_to_yuv(in[0]->vec[0], in[0]->vec[1], in[0]->vec[2], &y, &u, &v); + + out[0]->vec[0] = y; + out[1]->vec[0] = u; + out[2]->vec[0] = v; + out[3]->vec[0] = in[0]->vec[3]; + } + else if ((out[0]->hasoutput) || (out[1]->hasoutput) || (out[2]->hasoutput) || (out[3]->hasoutput)) { + /* make copy of buffer so input image doesn't get corrupted */ + CompBuf *cbuf= dupalloc_compbuf(in[0]->data); + CompBuf *cbuf2=typecheck_compbuf(cbuf, CB_RGBA); + + /* convert the RGB stackbuf to an YUV representation */ + composit1_pixel_processor(node, cbuf2, cbuf2, in[0]->vec, do_sepyuva, CB_RGBA); + + /* separate each of those channels */ + if(out[0]->hasoutput) + out[0]->data= valbuf_from_rgbabuf(cbuf2, CHAN_R); + if(out[1]->hasoutput) + out[1]->data= valbuf_from_rgbabuf(cbuf2, CHAN_G); + if(out[2]->hasoutput) + out[2]->data= valbuf_from_rgbabuf(cbuf2, CHAN_B); + if(out[3]->hasoutput) + out[3]->data= valbuf_from_rgbabuf(cbuf2, CHAN_A); + + /*not used anymore */ + if(cbuf2!=cbuf) + free_compbuf(cbuf2); + free_compbuf(cbuf); + } +} + +bNodeType cmp_node_sepyuva= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_SEPYUVA, + /* name */ "Separate YUVA", + /* width+range */ 80, 40, 140, + /* class+opts */ NODE_CLASS_CONVERTOR, 0, + /* input sock */ cmp_node_sepyuva_in, + /* output sock */ cmp_node_sepyuva_out, + /* storage */ "", + /* execfunc */ node_composit_exec_sepyuva, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; + + +/* **************** COMBINE YUVA ******************** */ +static bNodeSocketType cmp_node_combyuva_in[]= { + { SOCK_VALUE, 1, "Y", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "U", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "V", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "A", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_combyuva_out[]= { + { SOCK_RGBA, 0, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_comb_yuva(bNode *node, float *out, float *in1, float *in2, float *in3, float *in4) +{ + float r,g,b; + yuv_to_rgb(in1[0], in2[0], in3[0], &r, &g, &b); + + out[0] = r; + out[1] = g; + out[2] = b; + out[3] = in4[0]; +} + +static void node_composit_exec_combyuva(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order out: 1 rgba channels */ + /* stack order in: 4 value channels */ + + /* input no image? then only color operation */ + if((in[0]->data==NULL) && (in[1]->data==NULL) && (in[2]->data==NULL) && (in[3]->data==NULL)) { + out[0]->vec[0] = in[0]->vec[0]; + out[0]->vec[1] = in[1]->vec[0]; + out[0]->vec[2] = in[2]->vec[0]; + out[0]->vec[3] = in[3]->vec[0]; + } + else { + /* make output size of first available input image */ + CompBuf *cbuf; + CompBuf *stackbuf; + + /* allocate a CompBuf the size of the first available input */ + if (in[0]->data) cbuf = in[0]->data; + else if (in[1]->data) cbuf = in[1]->data; + else if (in[2]->data) cbuf = in[2]->data; + else cbuf = in[3]->data; + + stackbuf = alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */ + + composit4_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, + in[2]->data, in[2]->vec, in[3]->data, in[3]->vec, + do_comb_yuva, CB_VAL, CB_VAL, CB_VAL, CB_VAL); + + out[0]->data= stackbuf; + } +} + +bNodeType cmp_node_combyuva= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_COMBYUVA, + /* name */ "Combine YUVA", + /* width+range */ 80, 40, 140, + /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS, + /* input sock */ cmp_node_combyuva_in, + /* output sock */ cmp_node_combyuva_out, + /* storage */ "", + /* execfunc */ node_composit_exec_combyuva, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_setalpha.c b/source/blender/nodes/intern/CMP_nodes/CMP_setalpha.c new file mode 100644 index 00000000000..a7e0e28989b --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_setalpha.c @@ -0,0 +1,89 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + +/* **************** SET ALPHA ******************** */ +static bNodeSocketType cmp_node_setalpha_in[]= { + { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_setalpha_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_composit_exec_setalpha(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order out: RGBA image */ + /* stack order in: col, alpha */ + + /* input no image? then only color operation */ + if(in[0]->data==NULL && in[1]->data==NULL) { + out[0]->vec[0] = in[0]->vec[0]; + out[0]->vec[1] = in[0]->vec[1]; + out[0]->vec[2] = in[0]->vec[2]; + out[0]->vec[3] = in[1]->vec[0]; + } + else { + /* make output size of input image */ + CompBuf *cbuf= in[0]->data?in[0]->data:in[1]->data; + CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */ + + if(in[1]->data==NULL && in[1]->vec[0]==1.0f) { + /* pass on image */ + composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_copy_rgb, CB_RGBA); + } + else { + /* send an compbuf or a value to set as alpha - composit2_pixel_processor handles choosing the right one */ + composit2_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_copy_a_rgba, CB_RGBA, CB_VAL); + } + + out[0]->data= stackbuf; + } +} + +bNodeType cmp_node_setalpha= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_SETALPHA, + /* name */ "Set Alpha", + /* width+range */ 120, 40, 140, + /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS, + /* input sock */ cmp_node_setalpha_in, + /* output sock */ cmp_node_setalpha_out, + /* storage */ "", + /* execfunc */ node_composit_exec_setalpha, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_splitViewer.c b/source/blender/nodes/intern/CMP_nodes/CMP_splitViewer.c new file mode 100644 index 00000000000..8ce5a7caa04 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_splitViewer.c @@ -0,0 +1,164 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + +/* **************** SPLIT VIEWER ******************** */ +static bNodeSocketType cmp_node_splitviewer_in[]= { + { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_copy_split_rgba(bNode *node, float *out, float *in1, float *in2, float *fac) +{ + if(*fac==0.0f) { + QUATCOPY(out, in1); + } + else { + QUATCOPY(out, in2); + } +} + +static void node_composit_exec_splitviewer(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* image assigned to output */ + /* stack order input sockets: image image */ + + if(in[0]->data==NULL || in[1]->data==NULL) + return; + + if(node->id && (node->flag & NODE_DO_OUTPUT)) { /* only one works on out */ + Image *ima= (Image *)node->id; + RenderData *rd= data; + ImBuf *ibuf; + CompBuf *cbuf, *buf1, *buf2, *mask; + int x, y; + float offset; + + buf1= typecheck_compbuf(in[0]->data, CB_RGBA); + buf2= typecheck_compbuf(in[1]->data, CB_RGBA); + + BKE_image_user_calc_imanr(node->storage, rd->cfra, 0); + + /* always returns for viewer image, but we check nevertheless */ + ibuf= BKE_image_get_ibuf(ima, node->storage); + if(ibuf==NULL) { + printf("node_composit_exec_viewer error\n"); + return; + } + + /* free all in ibuf */ + imb_freerectImBuf(ibuf); + imb_freerectfloatImBuf(ibuf); + IMB_freezbuffloatImBuf(ibuf); + + /* make ibuf, and connect to ima */ + ibuf->x= buf1->x; + ibuf->y= buf1->y; + imb_addrectfloatImBuf(ibuf); + + ima->ok= IMA_OK_LOADED; + + /* output buf */ + cbuf= alloc_compbuf(buf1->x, buf1->y, CB_RGBA, 0); /* no alloc*/ + cbuf->rect= ibuf->rect_float; + + /* mask buf */ + mask= alloc_compbuf(buf1->x, buf1->y, CB_VAL, 1); + + + /* Check which offset mode is selected and limit offset if needed */ + if(node->custom2 == 0) { + offset = buf1->x / 100.0f * node->custom1; + CLAMP(offset, 0, buf1->x); + } + else { + offset = buf1->y / 100.0f * node->custom1; + CLAMP(offset, 0, buf1->y); + } + + if(node->custom2 == 0) { + for(y=0; yy; y++) { + float *fac= mask->rect + y*buf1->x; + for(x=offset; x>0; x--, fac++) + *fac= 1.0f; + } + } + else { + for(y=0; yrect + y*buf1->x; + for(x=buf1->x; x>0; x--, fac++) + *fac= 1.0f; + } + } + + composit3_pixel_processor(node, cbuf, buf1, in[0]->vec, buf2, in[1]->vec, mask, NULL, do_copy_split_rgba, CB_RGBA, CB_RGBA, CB_VAL); + + generate_preview(node, cbuf); + free_compbuf(cbuf); + free_compbuf(mask); + + if(in[0]->data != buf1) + free_compbuf(buf1); + if(in[1]->data != buf2) + free_compbuf(buf2); + } +} + +static void node_composit_init_splitviewer(bNode* node) +{ + ImageUser *iuser= MEM_callocN(sizeof(ImageUser), "node image user"); + node->storage= iuser; + iuser->sfra= 1; + iuser->fie_ima= 2; + iuser->ok= 1; + node->custom1= 50; /* default 50% split */ +} + +bNodeType cmp_node_splitviewer= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_SPLITVIEWER, + /* name */ "SplitViewer", + /* width+range */ 140, 100, 320, + /* class+opts */ NODE_CLASS_OUTPUT, NODE_PREVIEW|NODE_OPTIONS, + /* input sock */ cmp_node_splitviewer_in, + /* output sock */ NULL, + /* storage */ "ImageUser", + /* execfunc */ node_composit_exec_splitviewer, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_splitviewer, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL +}; + + + + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_texture.c b/source/blender/nodes/intern/CMP_nodes/CMP_texture.c new file mode 100644 index 00000000000..4ddab661627 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_texture.c @@ -0,0 +1,149 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + +/* **************** TEXTURE ******************** */ +static bNodeSocketType cmp_node_texture_in[]= { + { SOCK_VECTOR, 1, "Offset", 0.0f, 0.0f, 0.0f, 0.0f, -2.0f, 2.0f}, + { SOCK_VECTOR, 1, "Scale", 1.0f, 1.0f, 1.0f, 1.0f, -10.0f, 10.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_texture_out[]= { + { SOCK_VALUE, 0, "Value", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_RGBA , 0, "Color", 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +/* called without rect allocated */ +static void texture_procedural(CompBuf *cbuf, float *col, float xco, float yco) +{ + bNode *node= cbuf->node; + bNodeSocket *sock= node->inputs.first; + TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL}; + float vec[3], *size, nor[3]={0.0f, 0.0f, 0.0f}; + int retval, type= cbuf->type; + + size= sock->next->ns.vec; + + vec[0]= size[0]*(xco + sock->ns.vec[0]); + vec[1]= size[1]*(yco + sock->ns.vec[1]); + vec[2]= size[2]*sock->ns.vec[2]; + + retval= multitex_ext((Tex *)node->id, vec, NULL, NULL, 0, &texres); + + if(type==CB_VAL) { + if(texres.talpha) + col[0]= texres.ta; + else + col[0]= texres.tin; + } + else if(type==CB_RGBA) { + if(texres.talpha) + col[3]= texres.ta; + else + col[3]= texres.tin; + + if((retval & TEX_RGB)) { + col[0]= texres.tr; + col[1]= texres.tg; + col[2]= texres.tb; + } + else col[0]= col[1]= col[2]= col[3]; + } + else { + VECCOPY(col, nor); + } +} + +/* texture node outputs get a small rect, to make sure all other nodes accept it */ +/* only the pixel-processor nodes do something with it though */ +static void node_composit_exec_texture(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* outputs: value, color, normal */ + + if(node->id) { + RenderResult *rr= RE_GetResult(RE_GetRender(G.scene->id.name)); /* G.scene is WEAK! */ + short sizex, sizey; + + /* first make the preview image */ + CompBuf *prevbuf= alloc_compbuf(140, 140, CB_RGBA, 1); /* alloc */ + + if (rr) { + sizex = rr->rectx; + sizey = rr->recty; + } else { + sizex = G.scene->r.xsch; + sizey = G.scene->r.ysch; + } + + prevbuf->rect_procedural= texture_procedural; + prevbuf->node= node; + composit1_pixel_processor(node, prevbuf, prevbuf, out[0]->vec, do_copy_rgba, CB_RGBA); + generate_preview(node, prevbuf); + free_compbuf(prevbuf); + + if(out[0]->hasoutput) { + CompBuf *stackbuf= alloc_compbuf(sizex, sizey, CB_VAL, 1); /* alloc */ + + stackbuf->rect_procedural= texture_procedural; + stackbuf->node= node; + + out[0]->data= stackbuf; + } + if(out[1]->hasoutput) { + CompBuf *stackbuf= alloc_compbuf(sizex, sizey, CB_RGBA, 1); /* alloc */ + + stackbuf->rect_procedural= texture_procedural; + stackbuf->node= node; + + out[1]->data= stackbuf; + } + } +} + +bNodeType cmp_node_texture= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_TEXTURE, + /* name */ "Texture", + /* width+range */ 120, 80, 240, + /* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS|NODE_PREVIEW, + /* input sock */ cmp_node_texture_in, + /* output sock */ cmp_node_texture_out, + /* storage */ "", + /* execfunc */ node_composit_exec_texture, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; + + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_tonemap.c b/source/blender/nodes/intern/CMP_nodes/CMP_tonemap.c new file mode 100644 index 00000000000..cd617eca5c5 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_tonemap.c @@ -0,0 +1,173 @@ +/** + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Alfredo de Greef (eeshlo) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + +static bNodeSocketType cmp_node_tonemap_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_tonemap_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + + +static float avgLogLum(CompBuf *src, float* auto_key, float* Lav, float* Cav) +{ + float lsum = 0; + int p = src->x*src->y; + fRGB* bc = (fRGB*)src->rect; + float avl, maxl = -1e10f, minl = 1e10f; + const float sc = 1.f/(src->x*src->y); + *Lav = 0.f; + while (p--) { + float L = 0.212671f*bc[0][0] + 0.71516f*bc[0][1] + 0.072169f*bc[0][2]; + *Lav += L; + fRGB_add(Cav, bc[0]); + lsum += logf(MAX2(L, 0.f) + 1e-5f); + maxl = (L > maxl) ? L : maxl; + minl = (L < minl) ? L : minl; + bc++; + } + *Lav *= sc; + fRGB_mult(Cav, sc); + maxl = logf(maxl + 1e-5f); minl = logf(minl + 1e-5f); avl = lsum*sc; + *auto_key = (maxl > minl) ? ((maxl - avl) / (maxl - minl)) : 1.f; + return expf(avl); +} + + +void static tonemap(NodeTonemap* ntm, CompBuf* dst, CompBuf* src) +{ + int x, y; + float dr, dg, db, al, igm = (ntm->gamma==0.f) ? 1 : (1.f / ntm->gamma); + float auto_key, Lav, Cav[3] = {0, 0, 0}; + + al = avgLogLum(src, &auto_key, &Lav, Cav); + al = (al == 0.f) ? 0.f : (ntm->key / al); + + if (ntm->type == 1) { + // Reinhard/Devlin photoreceptor + const float f = expf(-ntm->f); + const float m = (ntm->m > 0.f) ? ntm->m : (0.3f + 0.7f*powf(auto_key, 1.4f)); + const float ic = 1.f - ntm->c, ia = 1.f - ntm->a; + if (ntm->m == 0.f) printf("tonemap node, M: %g\n", m); + for (y=0; yy; ++y) { + fRGB* sp = (fRGB*)&src->rect[y*src->x*src->type]; + fRGB* dp = (fRGB*)&dst->rect[y*src->x*src->type]; + for (x=0; xx; ++x) { + const float L = 0.212671f*sp[x][0] + 0.71516f*sp[x][1] + 0.072169f*sp[x][2]; + float I_l = sp[x][0] + ic*(L - sp[x][0]); + float I_g = Cav[0] + ic*(Lav - Cav[0]); + float I_a = I_l + ia*(I_g - I_l); + dp[x][0] /= (dp[x][0] + powf(f*I_a, m)); + I_l = sp[x][1] + ic*(L - sp[x][1]); + I_g = Cav[1] + ic*(Lav - Cav[1]); + I_a = I_l + ia*(I_g - I_l); + dp[x][1] /= (dp[x][1] + powf(f*I_a, m)); + I_l = sp[x][2] + ic*(L - sp[x][2]); + I_g = Cav[2] + ic*(Lav - Cav[2]); + I_a = I_l + ia*(I_g - I_l); + dp[x][2] /= (dp[x][2] + powf(f*I_a, m)); + } + } + return; + } + + // Reinhard simple photographic tm (simplest, not using whitepoint var) + for (y=0; yy; y++) { + fRGB* sp = (fRGB*)&src->rect[y*src->x*src->type]; + fRGB* dp = (fRGB*)&dst->rect[y*src->x*src->type]; + for (x=0; xx; x++) { + fRGB_copy(dp[x], sp[x]); + fRGB_mult(dp[x], al); + dr = dp[x][0] + ntm->offset; + dg = dp[x][1] + ntm->offset; + db = dp[x][2] + ntm->offset; + dp[x][0] /= ((dr == 0.f) ? 1.f : dr); + dp[x][1] /= ((dg == 0.f) ? 1.f : dg); + dp[x][2] /= ((db == 0.f) ? 1.f : db); + if (igm != 0.f) { + dp[x][0] = powf(MAX2(dp[x][0], 0.f), igm); + dp[x][1] = powf(MAX2(dp[x][1], 0.f), igm); + dp[x][2] = powf(MAX2(dp[x][2], 0.f), igm); + } + } + } +} + + +static void node_composit_exec_tonemap(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + CompBuf *new, *img = in[0]->data; + + if ((img==NULL) || (out[0]->hasoutput==0)) return; + + if (img->type != CB_RGBA) + new = typecheck_compbuf(img, CB_RGBA); + else + new = dupalloc_compbuf(img); + + tonemap(node->storage, new, img); + + out[0]->data = new; +} + +static void node_composit_init_tonemap(bNode* node) +{ + NodeTonemap *ntm = MEM_callocN(sizeof(NodeTonemap), "node tonemap data"); + ntm->type = 1; + ntm->key = 0.18; + ntm->offset = 1; + ntm->gamma = 1; + ntm->f = 0; + ntm->m = 0; // actual value is set according to input + // default a of 1 works well with natural HDR images, but not always so for cgi. + // Maybe should use 0 or at least lower initial value instead + ntm->a = 1; + ntm->c = 0; + node->storage = ntm; +} + +bNodeType cmp_node_tonemap = { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_TONEMAP, + /* name */ "Tonemap", + /* width+range */ 150, 120, 200, + /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS, + /* input sock */ cmp_node_tonemap_in, + /* output sock */ cmp_node_tonemap_out, + /* storage */ "NodeTonemap", + /* execfunc */ node_composit_exec_tonemap, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_tonemap, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL +}; diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_translate.c b/source/blender/nodes/intern/CMP_nodes/CMP_translate.c new file mode 100644 index 00000000000..0b198a18b4e --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_translate.c @@ -0,0 +1,75 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + + +/* **************** Translate ******************** */ + +static bNodeSocketType cmp_node_translate_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "X", 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f}, + { SOCK_VALUE, 1, "Y", 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_translate_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_composit_exec_translate(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + if(in[0]->data) { + CompBuf *cbuf= in[0]->data; + CompBuf *stackbuf= pass_on_compbuf(cbuf); + + stackbuf->xof+= (int)floor(in[1]->vec[0]); + stackbuf->yof+= (int)floor(in[2]->vec[0]); + + out[0]->data= stackbuf; + } +} + +bNodeType cmp_node_translate= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_TRANSLATE, + /* name */ "Translate", + /* width+range */ 140, 100, 320, + /* class+opts */ NODE_CLASS_DISTORT, NODE_OPTIONS, + /* input sock */ cmp_node_translate_in, + /* output sock */ cmp_node_translate_out, + /* storage */ "", + /* execfunc */ node_composit_exec_translate, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_valToRgb.c b/source/blender/nodes/intern/CMP_nodes/CMP_valToRgb.c new file mode 100644 index 00000000000..0d50cb6374d --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_valToRgb.c @@ -0,0 +1,157 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + + +/* **************** VALTORGB ******************** */ +static bNodeSocketType cmp_node_valtorgb_in[]= { + { SOCK_VALUE, 1, "Fac", 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_valtorgb_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_colorband_composit(bNode *node, float *out, float *in) +{ + do_colorband(node->storage, in[0], out); +} + +static void node_composit_exec_valtorgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order in: fac */ + /* stack order out: col, alpha */ + + if(out[0]->hasoutput==0 && out[1]->hasoutput==0) + return; + + if(node->storage) { + /* input no image? then only color operation */ + if(in[0]->data==NULL) { + do_colorband(node->storage, in[0]->vec[0], out[0]->vec); + } + else { + /* make output size of input image */ + CompBuf *cbuf= in[0]->data; + CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */ + + composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_colorband_composit, CB_VAL); + + out[0]->data= stackbuf; + + if(out[1]->hasoutput) + out[1]->data= valbuf_from_rgbabuf(stackbuf, CHAN_A); + + } + } +} + +static void node_composit_init_valtorgb(bNode* node) +{ + node->storage= add_colorband(1); +} + +bNodeType cmp_node_valtorgb= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_VALTORGB, + /* name */ "ColorRamp", + /* width+range */ 240, 200, 300, + /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS, + /* input sock */ cmp_node_valtorgb_in, + /* output sock */ cmp_node_valtorgb_out, + /* storage */ "ColorBand", + /* execfunc */ node_composit_exec_valtorgb, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_valtorgb, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL + +}; + + +/* **************** RGBTOBW ******************** */ +static bNodeSocketType cmp_node_rgbtobw_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_rgbtobw_out[]= { + { SOCK_VALUE, 0, "Val", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_rgbtobw(bNode *node, float *out, float *in) +{ + out[0]= in[0]*0.35f + in[1]*0.45f + in[2]*0.2f; +} + +static void node_composit_exec_rgbtobw(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order out: bw */ + /* stack order in: col */ + + if(out[0]->hasoutput==0) + return; + + /* input no image? then only color operation */ + if(in[0]->data==NULL) { + do_rgbtobw(node, out[0]->vec, in[0]->vec); + } + else { + /* make output size of input image */ + CompBuf *cbuf= in[0]->data; + CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); /* allocs */ + + composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_rgbtobw, CB_RGBA); + + out[0]->data= stackbuf; + } +} + +bNodeType cmp_node_rgbtobw= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_RGBTOBW, + /* name */ "RGB to BW", + /* width+range */ 80, 40, 120, + /* class+opts */ NODE_CLASS_CONVERTOR, 0, + /* input sock */ cmp_node_rgbtobw_in, + /* output sock */ cmp_node_rgbtobw_out, + /* storage */ "", + /* execfunc */ node_composit_exec_rgbtobw, + /* butfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; + + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_value.c b/source/blender/nodes/intern/CMP_nodes/CMP_value.c new file mode 100644 index 00000000000..7430a373d23 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_value.c @@ -0,0 +1,61 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + +/* **************** VALUE ******************** */ +static bNodeSocketType cmp_node_value_out[]= { + { SOCK_VALUE, 0, "Value", 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_composit_exec_value(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + bNodeSocket *sock= node->outputs.first; + + out[0]->vec[0]= sock->ns.vec[0]; +} + +bNodeType cmp_node_value= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_VALUE, + /* name */ "Value", + /* width+range */ 80, 40, 120, + /* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS, + /* input sock */ NULL, + /* output sock */ cmp_node_value_out, + /* storage */ "", + /* execfunc */ node_composit_exec_value, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_vecBlur.c b/source/blender/nodes/intern/CMP_nodes/CMP_vecBlur.c new file mode 100644 index 00000000000..9e6c963126b --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_vecBlur.c @@ -0,0 +1,110 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + + +/* **************** VECTOR BLUR ******************** */ +static bNodeSocketType cmp_node_vecblur_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Z", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_VECTOR, 1, "Speed", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_vecblur_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + + + +static void node_composit_exec_vecblur(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + NodeBlurData *nbd= node->storage; + CompBuf *new, *img= in[0]->data, *vecbuf= in[2]->data, *zbuf= in[1]->data; + + if(img==NULL || vecbuf==NULL || zbuf==NULL || out[0]->hasoutput==0) + return; + if(vecbuf->x!=img->x || vecbuf->y!=img->y) { + printf("ERROR: cannot do different sized vecbuf yet\n"); + return; + } + if(vecbuf->type!=CB_VEC4) { + printf("ERROR: input should be vecbuf\n"); + return; + } + if(zbuf->type!=CB_VAL) { + printf("ERROR: input should be zbuf\n"); + return; + } + if(zbuf->x!=img->x || zbuf->y!=img->y) { + printf("ERROR: cannot do different sized zbuf yet\n"); + return; + } + + /* allow the input image to be of another type */ + img= typecheck_compbuf(in[0]->data, CB_RGBA); + + new= dupalloc_compbuf(img); + + /* call special zbuffer version */ + RE_zbuf_accumulate_vecblur(nbd, img->x, img->y, new->rect, img->rect, vecbuf->rect, zbuf->rect); + + out[0]->data= new; + + if(img!=in[0]->data) + free_compbuf(img); +} + +static void node_composit_init_vecblur(bNode* node) +{ + NodeBlurData *nbd= MEM_callocN(sizeof(NodeBlurData), "node blur data"); + node->storage= nbd; + nbd->samples= 32; + nbd->fac= 1.0f; +}; + +/* custom1: itterations, custom2: maxspeed (0 = nolimit) */ +bNodeType cmp_node_vecblur= { + /* next, prev */ NULL, NULL, + /* type code */ CMP_NODE_VECBLUR, + /* name */ "Vector Blur", + /* width+range */ 120, 80, 200, + /* class+opts */ NODE_CLASS_OP_FILTER, NODE_OPTIONS, + /* input sock */ cmp_node_vecblur_in, + /* output sock */ cmp_node_vecblur_out, + /* storage */ "NodeBlurData", + /* execfunc */ node_composit_exec_vecblur, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_vecblur, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL +}; + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_viewer.c b/source/blender/nodes/intern/CMP_nodes/CMP_viewer.c new file mode 100644 index 00000000000..c9e95e768c1 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_viewer.c @@ -0,0 +1,144 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + + +/* **************** VIEWER ******************** */ +static bNodeSocketType cmp_node_viewer_in[]= { + { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Z", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + + +static void node_composit_exec_viewer(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* image assigned to output */ + /* stack order input sockets: col, alpha, z */ + + if(node->id && (node->flag & NODE_DO_OUTPUT)) { /* only one works on out */ + RenderData *rd= data; + Image *ima= (Image *)node->id; + ImBuf *ibuf; + CompBuf *cbuf, *tbuf; + int rectx, recty; + + BKE_image_user_calc_imanr(node->storage, rd->cfra, 0); + + /* always returns for viewer image, but we check nevertheless */ + ibuf= BKE_image_get_ibuf(ima, node->storage); + if(ibuf==NULL) { + printf("node_composit_exec_viewer error\n"); + return; + } + + /* free all in ibuf */ + imb_freerectImBuf(ibuf); + imb_freerectfloatImBuf(ibuf); + IMB_freezbuffloatImBuf(ibuf); + + /* get size */ + tbuf= in[0]->data?in[0]->data:(in[1]->data?in[1]->data:in[2]->data); + if(tbuf==NULL) { + rectx= 320; recty= 256; + } + else { + rectx= tbuf->x; + recty= tbuf->y; + } + + /* make ibuf, and connect to ima */ + ibuf->x= rectx; + ibuf->y= recty; + imb_addrectfloatImBuf(ibuf); + + ima->ok= IMA_OK_LOADED; + + /* now we combine the input with ibuf */ + cbuf= alloc_compbuf(rectx, recty, CB_RGBA, 0); /* no alloc*/ + cbuf->rect= ibuf->rect_float; + + /* when no alpha, we can simply copy */ + if(in[1]->data==NULL) { + composit1_pixel_processor(node, cbuf, in[0]->data, in[0]->vec, do_copy_rgba, CB_RGBA); + } + else + composit2_pixel_processor(node, cbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_copy_a_rgba, CB_RGBA, CB_VAL); + + /* zbuf option */ + if(in[2]->data) { + CompBuf *zbuf= alloc_compbuf(rectx, recty, CB_VAL, 1); + ibuf->zbuf_float= zbuf->rect; + ibuf->mall |= IB_zbuffloat; + + composit1_pixel_processor(node, zbuf, in[2]->data, in[2]->vec, do_copy_value, CB_VAL); + + /* free compbuf, but not the rect */ + zbuf->malloc= 0; + free_compbuf(zbuf); + } + + generate_preview(node, cbuf); + free_compbuf(cbuf); + + } + else if(in[0]->data) { + generate_preview(node, in[0]->data); + } +} + +static void node_composit_init_viewer(bNode* node) +{ + ImageUser *iuser= MEM_callocN(sizeof(ImageUser), "node image user"); + node->storage= iuser; + iuser->sfra= 1; + iuser->fie_ima= 2; + iuser->ok= 1; +} + +bNodeType cmp_node_viewer= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_VIEWER, + /* name */ "Viewer", + /* width+range */ 80, 60, 200, + /* class+opts */ NODE_CLASS_OUTPUT, NODE_PREVIEW, + /* input sock */ cmp_node_viewer_in, + /* output sock */ NULL, + /* storage */ "ImageUser", + /* execfunc */ node_composit_exec_viewer, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_viewer, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL + +}; + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_zcombine.c b/source/blender/nodes/intern/CMP_nodes/CMP_zcombine.c new file mode 100644 index 00000000000..29cf8f34d54 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_zcombine.c @@ -0,0 +1,155 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + + +/* **************** Z COMBINE ******************** */ + /* lazy coder note: node->custom1 is abused to send signal */ +static bNodeSocketType cmp_node_zcombine_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Z", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 10000.0f}, + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Z", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 10000.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_zcombine_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "Z", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 10000.0f}, + { -1, 0, "" } +}; + +static void do_zcombine_mask(bNode *node, float *out, float *z1, float *z2) +{ + if(*z1 > *z2) { + *out= 1.0f; + if(node->custom1) + *z1= *z2; + } +} + +static void do_zcombine_add(bNode *node, float *out, float *col1, float *col2, float *acol) +{ + float alpha= *acol; + float malpha= 1.0f - alpha; + + out[0]= malpha*col1[0] + alpha*col2[0]; + out[1]= malpha*col1[1] + alpha*col2[1]; + out[2]= malpha*col1[2] + alpha*col2[2]; + out[3]= malpha*col1[3] + alpha*col2[3]; +} + +static void node_composit_exec_zcombine(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order in: col z col z */ + /* stack order out: col z */ + if(out[0]->hasoutput==0) + return; + + /* no input image; do nothing now */ + if(in[0]->data==NULL) { + return; + } + else { + /* make output size of first input image */ + CompBuf *cbuf= in[0]->data; + CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */ + CompBuf *zbuf, *mbuf; + float *fp; + int x; + char *aabuf; + + if(out[1]->hasoutput) { + /* copy or make a buffer for for the first z value, here we write result in */ + if(in[1]->data) + zbuf= dupalloc_compbuf(in[1]->data); + else { + float *zval; + int tot= cbuf->x*cbuf->y; + + zbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); + for(zval= zbuf->rect; tot; tot--, zval++) + *zval= in[1]->vec[0]; + } + /* lazy coder hack */ + node->custom1= 1; + } + else { + node->custom1= 0; + zbuf= in[1]->data; + } + + /* make a mask based on comparison, optionally write zvalue */ + mbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); + composit2_pixel_processor(node, mbuf, zbuf, in[1]->vec, in[3]->data, in[3]->vec, do_zcombine_mask, CB_VAL, CB_VAL); + + /* convert to char */ + aabuf= MEM_mallocN(cbuf->x*cbuf->y, "aa buf"); + fp= mbuf->rect; + for(x= cbuf->x*cbuf->y-1; x>=0; x--) + if(fp[x]==0.0f) aabuf[x]= 0; + else aabuf[x]= 255; + + antialias_tagbuf(cbuf->x, cbuf->y, aabuf); + + /* convert to float */ + fp= mbuf->rect; + for(x= cbuf->x*cbuf->y-1; x>=0; x--) + if(aabuf[x]>1) + fp[x]= (1.0f/255.0f)*(float)aabuf[x]; + + composit3_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[2]->data, in[2]->vec, mbuf, NULL, + do_zcombine_add, CB_RGBA, CB_RGBA, CB_VAL); + /* free */ + free_compbuf(mbuf); + MEM_freeN(aabuf); + + out[0]->data= stackbuf; + if(node->custom1) + out[1]->data= zbuf; + } +} + +bNodeType cmp_node_zcombine= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_ZCOMBINE, + /* name */ "Z Combine", + /* width+range */ 80, 40, 120, + /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS, + /* input sock */ cmp_node_zcombine_in, + /* output sock */ cmp_node_zcombine_out, + /* storage */ "", + /* execfunc */ node_composit_exec_zcombine, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; diff --git a/source/blender/nodes/intern/CMP_nodes/Makefile b/source/blender/nodes/intern/CMP_nodes/Makefile new file mode 100644 index 00000000000..036812548b4 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/Makefile @@ -0,0 +1,47 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = nodes_cmp +DIR = $(OCGDIR)/blender/$(LIBNAME) + +include nan_compile.mk + +CFLAGS += $(LEVEL_1_C_WARNINGS) + +CPPFLAGS += -I../../../blenkernel +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include +CPPFLAGS += -I../../../makesdna +CPPFLAGS += -I../../../blenlib +CPPFLAGS += -I../../../include +CPPFLAGS += -I../../../imbuf +CPPFLAGS += -I../../../render/extern/include diff --git a/source/blender/nodes/intern/CMP_util.c b/source/blender/nodes/intern/CMP_util.c new file mode 100644 index 00000000000..eee33e33ff5 --- /dev/null +++ b/source/blender/nodes/intern/CMP_util.c @@ -0,0 +1,1166 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "CMP_util.h" + +CompBuf *alloc_compbuf(int sizex, int sizey, int type, int alloc) +{ + CompBuf *cbuf= MEM_callocN(sizeof(CompBuf), "compbuf"); + + cbuf->x= sizex; + cbuf->y= sizey; + cbuf->xrad= sizex/2; + cbuf->yrad= sizey/2; + + cbuf->type= type; + if(alloc) { + if(cbuf->type==CB_RGBA) + cbuf->rect= MEM_mapallocN(4*sizeof(float)*sizex*sizey, "compbuf RGBA rect"); + else if(cbuf->type==CB_VEC3) + cbuf->rect= MEM_mapallocN(3*sizeof(float)*sizex*sizey, "compbuf Vector3 rect"); + else if(cbuf->type==CB_VEC2) + cbuf->rect= MEM_mapallocN(2*sizeof(float)*sizex*sizey, "compbuf Vector2 rect"); + else + cbuf->rect= MEM_mapallocN(sizeof(float)*sizex*sizey, "compbuf Fac rect"); + cbuf->malloc= 1; + } + cbuf->disprect.xmin= 0; + cbuf->disprect.ymin= 0; + cbuf->disprect.xmax= sizex; + cbuf->disprect.ymax= sizey; + + return cbuf; +} + +CompBuf *dupalloc_compbuf(CompBuf *cbuf) +{ + CompBuf *dupbuf= alloc_compbuf(cbuf->x, cbuf->y, cbuf->type, 1); + if(dupbuf) { + memcpy(dupbuf->rect, cbuf->rect, cbuf->type*sizeof(float)*cbuf->x*cbuf->y); + + dupbuf->xof= cbuf->xof; + dupbuf->yof= cbuf->yof; + } + return dupbuf; +} + +/* instead of reference counting, we create a list */ +CompBuf *pass_on_compbuf(CompBuf *cbuf) +{ + CompBuf *dupbuf= alloc_compbuf(cbuf->x, cbuf->y, cbuf->type, 0); + CompBuf *lastbuf; + + if(dupbuf) { + dupbuf->rect= cbuf->rect; + dupbuf->xof= cbuf->xof; + dupbuf->yof= cbuf->yof; + dupbuf->malloc= 0; + + /* get last buffer in list, and append dupbuf */ + for(lastbuf= cbuf; lastbuf; lastbuf= lastbuf->next) + if(lastbuf->next==NULL) + break; + lastbuf->next= dupbuf; + dupbuf->prev= lastbuf; + } + return dupbuf; +} + + +void free_compbuf(CompBuf *cbuf) +{ + /* check referencing, then remove from list and set malloc tag */ + if(cbuf->prev || cbuf->next) { + if(cbuf->prev) + cbuf->prev->next= cbuf->next; + if(cbuf->next) + cbuf->next->prev= cbuf->prev; + if(cbuf->malloc) { + if(cbuf->prev) + cbuf->prev->malloc= 1; + else + cbuf->next->malloc= 1; + cbuf->malloc= 0; + } + } + + if(cbuf->malloc && cbuf->rect) + MEM_freeN(cbuf->rect); + + MEM_freeN(cbuf); +} + +void print_compbuf(char *str, CompBuf *cbuf) +{ + printf("Compbuf %s %d %d %p\n", str, cbuf->x, cbuf->y, cbuf->rect); + +} + +CompBuf *get_cropped_compbuf(rcti *drect, float *rectf, int rectx, int recty, int type) +{ + CompBuf *cbuf; + rcti disprect= *drect; + float *outfp; + int dx, y; + + if(disprect.xmax>rectx) disprect.xmax= rectx; + if(disprect.ymax>recty) disprect.ymax= recty; + if(disprect.xmin>= disprect.xmax) return NULL; + if(disprect.ymin>= disprect.ymax) return NULL; + + cbuf= alloc_compbuf(disprect.xmax-disprect.xmin, disprect.ymax-disprect.ymin, type, 1); + outfp= cbuf->rect; + rectf += type*(disprect.ymin*rectx + disprect.xmin); + dx= type*cbuf->x; + for(y=cbuf->y; y>0; y--, outfp+=dx, rectf+=type*rectx) + memcpy(outfp, rectf, sizeof(float)*dx); + + return cbuf; +} + +CompBuf *scalefast_compbuf(CompBuf *inbuf, int newx, int newy) +{ + CompBuf *outbuf; + float *rectf, *newrectf, *rf; + int x, y, c, pixsize= inbuf->type; + int ofsx, ofsy, stepx, stepy; + + if(inbuf->x==newx && inbuf->y==newy) + return dupalloc_compbuf(inbuf); + + outbuf= alloc_compbuf(newx, newy, inbuf->type, 1); + newrectf= outbuf->rect; + + stepx = (65536.0 * (inbuf->x - 1.0) / (newx - 1.0)) + 0.5; + stepy = (65536.0 * (inbuf->y - 1.0) / (newy - 1.0)) + 0.5; + ofsy = 32768; + + for (y = newy; y > 0 ; y--){ + rectf = inbuf->rect; + rectf += pixsize * (ofsy >> 16) * inbuf->x; + + ofsy += stepy; + ofsx = 32768; + + for (x = newx ; x>0 ; x--) { + + rf= rectf + pixsize*(ofsx >> 16); + for(c=0; ctype!=type && inbuf->rect_procedural==NULL) { + CompBuf *outbuf= alloc_compbuf(inbuf->x, inbuf->y, type, 1); + float *inrf= inbuf->rect; + float *outrf= outbuf->rect; + int x= inbuf->x*inbuf->y; + + /* warning note: xof and yof are applied in pixelprocessor, but should be copied otherwise? */ + outbuf->xof= inbuf->xof; + outbuf->yof= inbuf->yof; + + if(type==CB_VAL) { + if(inbuf->type==CB_VEC2) { + for(; x>0; x--, outrf+= 1, inrf+= 2) + *outrf= 0.5f*(inrf[0]+inrf[1]); + } + else if(inbuf->type==CB_VEC3) { + for(; x>0; x--, outrf+= 1, inrf+= 3) + *outrf= 0.333333f*(inrf[0]+inrf[1]+inrf[2]); + } + else if(inbuf->type==CB_RGBA) { + for(; x>0; x--, outrf+= 1, inrf+= 4) + *outrf= inrf[0]*0.35f + inrf[1]*0.45f + inrf[2]*0.2f; + } + } + else if(type==CB_VEC2) { + if(inbuf->type==CB_VAL) { + for(; x>0; x--, outrf+= 2, inrf+= 1) { + outrf[0]= inrf[0]; + outrf[1]= inrf[0]; + } + } + else if(inbuf->type==CB_VEC3) { + for(; x>0; x--, outrf+= 2, inrf+= 3) { + outrf[0]= inrf[0]; + outrf[1]= inrf[1]; + } + } + else if(inbuf->type==CB_RGBA) { + for(; x>0; x--, outrf+= 2, inrf+= 4) { + outrf[0]= inrf[0]; + outrf[1]= inrf[1]; + } + } + } + else if(type==CB_VEC3) { + if(inbuf->type==CB_VAL) { + for(; x>0; x--, outrf+= 3, inrf+= 1) { + outrf[0]= inrf[0]; + outrf[1]= inrf[0]; + outrf[2]= inrf[0]; + } + } + else if(inbuf->type==CB_VEC2) { + for(; x>0; x--, outrf+= 3, inrf+= 2) { + outrf[0]= inrf[0]; + outrf[1]= inrf[1]; + outrf[2]= 0.0f; + } + } + else if(inbuf->type==CB_RGBA) { + for(; x>0; x--, outrf+= 3, inrf+= 4) { + outrf[0]= inrf[0]; + outrf[1]= inrf[1]; + outrf[2]= inrf[2]; + } + } + } + else if(type==CB_RGBA) { + if(inbuf->type==CB_VAL) { + for(; x>0; x--, outrf+= 4, inrf+= 1) { + outrf[0]= inrf[0]; + outrf[1]= inrf[0]; + outrf[2]= inrf[0]; + outrf[3]= 1.0f; + } + } + else if(inbuf->type==CB_VEC2) { + for(; x>0; x--, outrf+= 4, inrf+= 2) { + outrf[0]= inrf[0]; + outrf[1]= inrf[1]; + outrf[2]= 0.0f; + outrf[3]= 1.0f; + } + } + else if(inbuf->type==CB_VEC3) { + for(; x>0; x--, outrf+= 4, inrf+= 3) { + outrf[0]= inrf[0]; + outrf[1]= inrf[1]; + outrf[2]= inrf[2]; + outrf[3]= 1.0f; + } + } + } + + return outbuf; + } + return inbuf; +} + +float *compbuf_get_pixel(CompBuf *cbuf, float *rectf, int x, int y, int xrad, int yrad) +{ + if(cbuf) { + if(cbuf->rect_procedural) { + cbuf->rect_procedural(cbuf, rectf, (float)x/(float)xrad, (float)y/(float)yrad); + return rectf; + } + else { + static float col[4]= {0.0f, 0.0f, 0.0f, 0.0f}; + + /* map coords */ + x-= cbuf->xof; + y-= cbuf->yof; + + if(y<-cbuf->yrad || y>= -cbuf->yrad+cbuf->y) return col; + if(x<-cbuf->xrad || x>= -cbuf->xrad+cbuf->x) return col; + + return cbuf->rect + cbuf->type*( (cbuf->yrad+y)*cbuf->x + (cbuf->xrad+x) ); + } + } + else return rectf; +} + +/* **************************************************** */ + +/* Pixel-to-Pixel operation, 1 Image in, 1 out */ +void composit1_pixel_processor(bNode *node, CompBuf *out, CompBuf *src_buf, float *src_col, + void (*func)(bNode *, float *, float *), + int src_type) +{ + CompBuf *src_use; + float *outfp=out->rect, *srcfp; + int xrad, yrad, x, y; + + src_use= typecheck_compbuf(src_buf, src_type); + + xrad= out->xrad; + yrad= out->yrad; + + for(y= -yrad; y<-yrad+out->y; y++) { + for(x= -xrad; x<-xrad+out->x; x++, outfp+=out->type) { + srcfp= compbuf_get_pixel(src_use, src_col, x, y, xrad, yrad); + func(node, outfp, srcfp); + } + } + + if(src_use!=src_buf) + free_compbuf(src_use); +} + +/* Pixel-to-Pixel operation, 2 Images in, 1 out */ +void composit2_pixel_processor(bNode *node, CompBuf *out, CompBuf *src_buf, float *src_col, + CompBuf *fac_buf, float *fac, void (*func)(bNode *, float *, float *, float *), + int src_type, int fac_type) +{ + CompBuf *src_use, *fac_use; + float *outfp=out->rect, *srcfp, *facfp; + int xrad, yrad, x, y; + + src_use= typecheck_compbuf(src_buf, src_type); + fac_use= typecheck_compbuf(fac_buf, fac_type); + + xrad= out->xrad; + yrad= out->yrad; + + for(y= -yrad; y<-yrad+out->y; y++) { + for(x= -xrad; x<-xrad+out->x; x++, outfp+=out->type) { + srcfp= compbuf_get_pixel(src_use, src_col, x, y, xrad, yrad); + facfp= compbuf_get_pixel(fac_use, fac, x, y, xrad, yrad); + + func(node, outfp, srcfp, facfp); + } + } + if(src_use!=src_buf) + free_compbuf(src_use); + if(fac_use!=fac_buf) + free_compbuf(fac_use); +} + +/* Pixel-to-Pixel operation, 3 Images in, 1 out */ +void composit3_pixel_processor(bNode *node, CompBuf *out, CompBuf *src1_buf, float *src1_col, CompBuf *src2_buf, float *src2_col, + CompBuf *fac_buf, float *fac, void (*func)(bNode *, float *, float *, float *, float *), + int src1_type, int src2_type, int fac_type) +{ + CompBuf *src1_use, *src2_use, *fac_use; + float *outfp=out->rect, *src1fp, *src2fp, *facfp; + int xrad, yrad, x, y; + + src1_use= typecheck_compbuf(src1_buf, src1_type); + src2_use= typecheck_compbuf(src2_buf, src2_type); + fac_use= typecheck_compbuf(fac_buf, fac_type); + + xrad= out->xrad; + yrad= out->yrad; + + for(y= -yrad; y<-yrad+out->y; y++) { + for(x= -xrad; x<-xrad+out->x; x++, outfp+=out->type) { + src1fp= compbuf_get_pixel(src1_use, src1_col, x, y, xrad, yrad); + src2fp= compbuf_get_pixel(src2_use, src2_col, x, y, xrad, yrad); + facfp= compbuf_get_pixel(fac_use, fac, x, y, xrad, yrad); + + func(node, outfp, src1fp, src2fp, facfp); + } + } + + if(src1_use!=src1_buf) + free_compbuf(src1_use); + if(src2_use!=src2_buf) + free_compbuf(src2_use); + if(fac_use!=fac_buf) + free_compbuf(fac_use); +} + +/* Pixel-to-Pixel operation, 4 Images in, 1 out */ +void composit4_pixel_processor(bNode *node, CompBuf *out, CompBuf *src1_buf, float *src1_col, CompBuf *fac1_buf, float *fac1, + CompBuf *src2_buf, float *src2_col, CompBuf *fac2_buf, float *fac2, + void (*func)(bNode *, float *, float *, float *, float *, float *), + int src1_type, int fac1_type, int src2_type, int fac2_type) +{ + CompBuf *src1_use, *src2_use, *fac1_use, *fac2_use; + float *outfp=out->rect, *src1fp, *src2fp, *fac1fp, *fac2fp; + int xrad, yrad, x, y; + + src1_use= typecheck_compbuf(src1_buf, src1_type); + src2_use= typecheck_compbuf(src2_buf, src2_type); + fac1_use= typecheck_compbuf(fac1_buf, fac1_type); + fac2_use= typecheck_compbuf(fac2_buf, fac2_type); + + xrad= out->xrad; + yrad= out->yrad; + + for(y= -yrad; y<-yrad+out->y; y++) { + for(x= -xrad; x<-xrad+out->x; x++, outfp+=out->type) { + src1fp= compbuf_get_pixel(src1_use, src1_col, x, y, xrad, yrad); + src2fp= compbuf_get_pixel(src2_use, src2_col, x, y, xrad, yrad); + fac1fp= compbuf_get_pixel(fac1_use, fac1, x, y, xrad, yrad); + fac2fp= compbuf_get_pixel(fac2_use, fac2, x, y, xrad, yrad); + + func(node, outfp, src1fp, fac1fp, src2fp, fac2fp); + } + } + + if(src1_use!=src1_buf) + free_compbuf(src1_use); + if(src2_use!=src2_buf) + free_compbuf(src2_use); + if(fac1_use!=fac1_buf) + free_compbuf(fac1_use); + if(fac2_use!=fac2_buf) + free_compbuf(fac2_use); +} + + +CompBuf *valbuf_from_rgbabuf(CompBuf *cbuf, int channel) +{ + CompBuf *valbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); + float *valf, *rectf; + int tot; + + /* warning note: xof and yof are applied in pixelprocessor, but should be copied otherwise? */ + valbuf->xof= cbuf->xof; + valbuf->yof= cbuf->yof; + + valf= valbuf->rect; + + /* defaults to returning alpha channel */ + if ((channel < CHAN_R) && (channel > CHAN_A)) channel = CHAN_A; + + rectf= cbuf->rect + channel; + + for(tot= cbuf->x*cbuf->y; tot>0; tot--, valf++, rectf+=4) + *valf= *rectf; + + return valbuf; +} + +void generate_preview(bNode *node, CompBuf *stackbuf) +{ + bNodePreview *preview= node->preview; + + if(preview && stackbuf) { + CompBuf *cbuf, *stackbuf_use; + + if(stackbuf->rect==NULL) return; + + stackbuf_use= typecheck_compbuf(stackbuf, CB_RGBA); + + if(stackbuf->x > stackbuf->y) { + preview->xsize= 140; + preview->ysize= (140*stackbuf->y)/stackbuf->x; + } + else { + preview->ysize= 140; + preview->xsize= (140*stackbuf->x)/stackbuf->y; + } + + cbuf= scalefast_compbuf(stackbuf_use, preview->xsize, preview->ysize); + + /* this ensures free-compbuf does the right stuff */ + SWAP(float *, cbuf->rect, node->preview->rect); + + free_compbuf(cbuf); + if(stackbuf_use!=stackbuf) + free_compbuf(stackbuf_use); + + } +} + +void do_rgba_to_yuva(bNode *node, float *out, float *in) +{ + rgb_to_yuv(in[0],in[1],in[2], &out[0], &out[1], &out[2]); + out[3]=in[3]; +} + +void do_rgba_to_hsva(bNode *node, float *out, float *in) +{ + rgb_to_hsv(in[0],in[1],in[2], &out[0], &out[1], &out[2]); + out[3]=in[3]; +} + +void do_rgba_to_ycca(bNode *node, float *out, float *in) +{ + rgb_to_ycc(in[0],in[1],in[2], &out[0], &out[1], &out[2]); + out[3]=in[3]; +} + +void do_yuva_to_rgba(bNode *node, float *out, float *in) +{ + yuv_to_rgb(in[0],in[1],in[2], &out[0], &out[1], &out[2]); + out[3]=in[3]; +} + +void do_hsva_to_rgba(bNode *node, float *out, float *in) +{ + hsv_to_rgb(in[0],in[1],in[2], &out[0], &out[1], &out[2]); + out[3]=in[3]; +} + +void do_ycca_to_rgba(bNode *node, float *out, float *in) +{ + ycc_to_rgb(in[0],in[1],in[2], &out[0], &out[1], &out[2]); + out[3]=in[3]; +} + +void do_copy_rgba(bNode *node, float *out, float *in) +{ + QUATCOPY(out, in); +} + +void do_copy_rgb(bNode *node, float *out, float *in) +{ + VECCOPY(out, in); + out[3]= 1.0f; +} + +void do_copy_value(bNode *node, float *out, float *in) +{ + out[0]= in[0]; +} + +void do_copy_a_rgba(bNode *node, float *out, float *in, float *fac) +{ + VECCOPY(out, in); + out[3]= *fac; +} + +/* only accepts RGBA buffers */ +void gamma_correct_compbuf(CompBuf *img, int inversed) +{ + float *drect; + int x; + + if(img->type!=CB_RGBA) return; + + drect= img->rect; + if(inversed) { + for(x=img->x*img->y; x>0; x--, drect+=4) { + if(drect[0]>0.0f) drect[0]= sqrt(drect[0]); else drect[0]= 0.0f; + if(drect[1]>0.0f) drect[1]= sqrt(drect[1]); else drect[1]= 0.0f; + if(drect[2]>0.0f) drect[2]= sqrt(drect[2]); else drect[2]= 0.0f; + } + } + else { + for(x=img->x*img->y; x>0; x--, drect+=4) { + if(drect[0]>0.0f) drect[0]*= drect[0]; else drect[0]= 0.0f; + if(drect[1]>0.0f) drect[1]*= drect[1]; else drect[1]= 0.0f; + if(drect[2]>0.0f) drect[2]*= drect[2]; else drect[2]= 0.0f; + } + } +} + + + + +/* + * 2D Fast Hartley Transform, used for convolution + */ + +typedef float fREAL; + +// returns next highest power of 2 of x, as well it's log2 in L2 +static unsigned int nextPow2(unsigned int x, unsigned int* L2) +{ + unsigned int pw, x_notpow2 = x & (x-1); + *L2 = 0; + while (x>>=1) ++(*L2); + pw = 1 << (*L2); + if (x_notpow2) { (*L2)++; pw<<=1; } + return pw; +} + +//------------------------------------------------------------------------------ + +// from FXT library by Joerg Arndt, faster in order bitreversal +// use: r = revbin_upd(r, h) where h = N>>1 +static unsigned int revbin_upd(unsigned int r, unsigned int h) +{ + while (!((r^=h)&h)) h >>= 1; + return r; +} +//------------------------------------------------------------------------------ +static void FHT(fREAL* data, unsigned int M, unsigned int inverse) +{ + double tt, fc, dc, fs, ds, a = M_PI; + fREAL t1, t2; + int n2, bd, bl, istep, k, len = 1 << M, n = 1; + + int i, j = 0; + unsigned int Nh = len >> 1; + for (i=1;i<(len-1);++i) { + j = revbin_upd(j, Nh); + if (j>i) { + t1 = data[i]; + data[i] = data[j]; + data[j] = t1; + } + } + + do { + fREAL* data_n = &data[n]; + + istep = n << 1; + for (k=0; k> 1; + if (n>2) { + fc = dc = cos(a); + fs = ds = sqrt(1.0 - fc*fc); //sin(a); + bd = n-2; + for (bl=1; bl1) { + for (k=n2; k log2 of width/height, + nzp -> the row where zero pad data starts, + inverse -> see above */ +static void FHT2D(fREAL *data, unsigned int Mx, unsigned int My, + unsigned int nzp, unsigned int inverse) +{ + unsigned int i, j, Nx, Ny, maxy; + fREAL t; + + Nx = 1 << Mx; + Ny = 1 << My; + + // rows (forward transform skips 0 pad data) + maxy = inverse ? Ny : nzp; + for (j=0; j0; i++) { + #define pred(k) (((k & Nym) << Mx) + (k >> My)) + for (j=pred(i); j>i; j=pred(j)); + if (j < i) continue; + for (k=i, j=pred(i); j!=i; k=j, j=pred(j), stm--) + { t=data[j], data[j]=data[k], data[k]=t; } + #undef pred + stm--; + } + } + // swap Mx/My & Nx/Ny + i = Nx, Nx = Ny, Ny = i; + i = Mx, Mx = My, My = i; + + // now columns == transposed rows + for (j=0; j> 1); j++) { + unsigned int jm = (Ny - j) & (Ny-1); + unsigned int ji = j << Mx; + unsigned int jmi = jm << Mx; + for (i=0; i<=(Nx >> 1); i++) { + unsigned int im = (Nx - i) & (Nx-1); + fREAL A = data[ji + i]; + fREAL B = data[jmi + i]; + fREAL C = data[ji + im]; + fREAL D = data[jmi + im]; + fREAL E = (fREAL)0.5*((A + D) - (B + C)); + data[ji + i] = A - E; + data[jmi + i] = B + E; + data[ji + im] = C + E; + data[jmi + im] = D - E; + } + } + +} + +//------------------------------------------------------------------------------ + +/* 2D convolution calc, d1 *= d2, M/N - > log2 of width/height */ +static void fht_convolve(fREAL* d1, fREAL* d2, unsigned int M, unsigned int N) +{ + fREAL a, b; + unsigned int i, j, k, L, mj, mL; + unsigned int m = 1 << M, n = 1 << N; + unsigned int m2 = 1 << (M-1), n2 = 1 << (N-1); + unsigned int mn2 = m << (N-1); + + d1[0] *= d2[0]; + d1[mn2] *= d2[mn2]; + d1[m2] *= d2[m2]; + d1[m2 + mn2] *= d2[m2 + mn2]; + for (i=1; ix, in1->y, in1->type, 1); + + // convolution result width & height + w2 = 2*in2->x - 1; + h2 = 2*in2->y - 1; + // FFT pow2 required size & log2 + w2 = nextPow2(w2, &log2_w); + h2 = nextPow2(h2, &log2_h); + + // alloc space + data1 = (fREAL*)MEM_callocN(3*w2*h2*sizeof(fREAL), "convolve_fast FHT data1"); + data2 = (fREAL*)MEM_callocN(w2*h2*sizeof(fREAL), "convolve_fast FHT data2"); + + // normalize convolutor + wt[0] = wt[1] = wt[2] = 0.f; + for (y=0; yy; y++) { + colp = (fRGB*)&in2->rect[y*in2->x*in2->type]; + for (x=0; xx; x++) + fRGB_add(wt, colp[x]); + } + if (wt[0] != 0.f) wt[0] = 1.f/wt[0]; + if (wt[1] != 0.f) wt[1] = 1.f/wt[1]; + if (wt[2] != 0.f) wt[2] = 1.f/wt[2]; + for (y=0; yy; y++) { + colp = (fRGB*)&in2->rect[y*in2->x*in2->type]; + for (x=0; xx; x++) + fRGB_colormult(colp[x], wt); + } + + // copy image data, unpacking interleaved RGBA into separate channels + // only need to calc data1 once + + // block add-overlap + hw = in2->x >> 1; + hh = in2->y >> 1; + xbsz = (w2 + 1) - in2->x; + ybsz = (h2 + 1) - in2->y; + nxb = in1->x / xbsz; + if (in1->x % xbsz) nxb++; + nyb = in1->y / ybsz; + if (in1->y % ybsz) nyb++; + for (ybl=0; ybl data1 + for (y=0; yy; y++) { + fp = &data1ch[y*w2]; + colp = (fRGB*)&in2->rect[y*in2->x*in2->type]; + for (x=0; xx; x++) + fp[x] = colp[x][ch]; + } + } + + // in1, channel ch -> data2 + memset(data2, 0, w2*h2*sizeof(fREAL)); + for (y=0; y= in1->y) continue; + fp = &data2[y*w2]; + colp = (fRGB*)&in1->rect[yy*in1->x*in1->type]; + for (x=0; x= in1->x) continue; + fp[x] = colp[xx][ch]; + } + } + + // forward FHT + // zero pad data start is different for each == height+1 + if (!in2done) FHT2D(data1ch, log2_w, log2_h, in2->y+1, 0); + FHT2D(data2, log2_w, log2_h, in2->y+1, 0); + + // FHT2D transposed data, row/col now swapped + // convolve & inverse FHT + fht_convolve(data2, data1ch, log2_h, log2_w); + FHT2D(data2, log2_h, log2_w, 0, 1); + // data again transposed, so in order again + + // overlap-add result + for (y=0; y<(int)h2; y++) { + const int yy = ybl*ybsz + y - hh; + if ((yy < 0) || (yy >= in1->y)) continue; + fp = &data2[y*w2]; + colp = (fRGB*)&rdst->rect[yy*in1->x*in1->type]; + for (x=0; x<(int)w2; x++) { + const int xx = xbl*xbsz + x - hw; + if ((xx < 0) || (xx >= in1->x)) continue; + colp[xx][ch] += fp[x]; + } + } + + } + in2done = 1; + } + } + + MEM_freeN(data2); + MEM_freeN(data1); + memcpy(dst->rect, rdst->rect, sizeof(float)*dst->x*dst->y*dst->type); + free_compbuf(rdst); +} + + +/* + * + * Utility functions qd_* should probably be intergrated better with other functions here. + * + */ +// sets fcol to pixelcolor at (x, y) +void qd_getPixel(CompBuf* src, int x, int y, float* col) +{ + if ((x >= 0) && (x < src->x) && (y >= 0) && (y < src->y)) { + float* bc = &src->rect[(x + y*src->x)*src->type]; + col[0] = bc[0], col[1] = bc[1], col[2] = bc[2]; + } + else col[0] = col[1] = col[2] = 0.f; +} + +// sets pixel (x, y) to color col +void qd_setPixel(CompBuf* src, int x, int y, float* col) +{ + if ((x >= 0) && (x < src->x) && (y >= 0) && (y < src->y)) { + float* bc = &src->rect[(x + y*src->x)*src->type]; + bc[0] = col[0], bc[1] = col[1], bc[2] = col[2]; + } +} + +// adds fcol to pixelcolor (x, y) +void qd_addPixel(CompBuf* src, int x, int y, float* col) +{ + if ((x >= 0) && (x < src->x) && (y >= 0) && (y < src->y)) { + float* bc = &src->rect[(x + y*src->x)*src->type]; + bc[0] += col[0], bc[1] += col[1], bc[2] += col[2]; + } +} + +// multiplies pixel by factor value f +void qd_multPixel(CompBuf* src, int x, int y, float f) +{ + if ((x >= 0) && (x < src->x) && (y >= 0) && (y < src->y)) { + float* bc = &src->rect[(x + y*src->x)*src->type]; + bc[0] *= f, bc[1] *= f, bc[2] *= f; + } +} + +// bilinear interpolation with wraparound +void qd_getPixelLerpWrap(CompBuf* src, float u, float v, float* col) +{ + const float ufl = floor(u), vfl = floor(v); + const int nx = (int)ufl % src->x, ny = (int)vfl % src->y; + const int x1 = (nx < 0) ? (nx + src->x) : nx; + const int y1 = (ny < 0) ? (ny + src->y) : ny; + const int x2 = (x1 + 1) % src->x, y2 = (y1 + 1) % src->y; + const float* c00 = &src->rect[(x1 + y1*src->x)*src->type]; + const float* c10 = &src->rect[(x2 + y1*src->x)*src->type]; + const float* c01 = &src->rect[(x1 + y2*src->x)*src->type]; + const float* c11 = &src->rect[(x2 + y2*src->x)*src->type]; + const float uf = u - ufl, vf = v - vfl; + const float w00=(1.f-uf)*(1.f-vf), w10=uf*(1.f-vf), w01=(1.f-uf)*vf, w11=uf*vf; + col[0] = w00*c00[0] + w10*c10[0] + w01*c01[0] + w11*c11[0]; + if (src->type != CB_VAL) { + col[1] = w00*c00[1] + w10*c10[1] + w01*c01[1] + w11*c11[1]; + col[2] = w00*c00[2] + w10*c10[2] + w01*c01[2] + w11*c11[2]; + col[3] = w00*c00[3] + w10*c10[3] + w01*c01[3] + w11*c11[3]; + } +} + +// as above, without wrap around +void qd_getPixelLerp(CompBuf* src, float u, float v, float* col) +{ + const float ufl = floor(u), vfl = floor(v); + const int x1 = (int)ufl, y1 = (int)vfl; + const int x2 = (int)ceil(u), y2 = (int)ceil(v); + if ((x2 >= 0) && (y2 >= 0) && (x1 < src->x) && (y1 < src->y)) { + const float B[4] = {0,0,0,0}; + const int ox1 = (x1 < 0), oy1 = (y1 < 0), ox2 = (x2 >= src->x), oy2 = (y2 >= src->y); + const float* c00 = (ox1 || oy1) ? B : &src->rect[(x1 + y1*src->x)*src->type]; + const float* c10 = (ox2 || oy1) ? B : &src->rect[(x2 + y1*src->x)*src->type]; + const float* c01 = (ox1 || oy2) ? B : &src->rect[(x1 + y2*src->x)*src->type]; + const float* c11 = (ox2 || oy2) ? B : &src->rect[(x2 + y2*src->x)*src->type]; + const float uf = u - ufl, vf = v - vfl; + const float w00=(1.f-uf)*(1.f-vf), w10=uf*(1.f-vf), w01=(1.f-uf)*vf, w11=uf*vf; + col[0] = w00*c00[0] + w10*c10[0] + w01*c01[0] + w11*c11[0]; + if (src->type != CB_VAL) { + col[1] = w00*c00[1] + w10*c10[1] + w01*c01[1] + w11*c11[1]; + col[2] = w00*c00[2] + w10*c10[2] + w01*c01[2] + w11*c11[2]; + col[3] = w00*c00[3] + w10*c10[3] + w01*c01[3] + w11*c11[3]; + } + } + else col[0] = col[1] = col[2] = col[3] = 0.f; +} + +// as above, sampling only one channel +void qd_getPixelLerpChan(CompBuf* src, float u, float v, int chan, float* out) +{ + const float ufl = floor(u), vfl = floor(v); + const int x1 = (int)ufl, y1 = (int)vfl; + const int x2 = (int)ceil(u), y2 = (int)ceil(v); + if (chan >= src->type) chan = 0; + if ((x2 >= 0) && (y2 >= 0) && (x1 < src->x) && (y1 < src->y)) { + const float B[4] = {0,0,0,0}; + const int ox1 = (x1 < 0), oy1 = (y1 < 0), ox2 = (x2 >= src->x), oy2 = (y2 >= src->y); + const float* c00 = (ox1 || oy1) ? B : &src->rect[(x1 + y1*src->x)*src->type + chan]; + const float* c10 = (ox2 || oy1) ? B : &src->rect[(x2 + y1*src->x)*src->type + chan]; + const float* c01 = (ox1 || oy2) ? B : &src->rect[(x1 + y2*src->x)*src->type + chan]; + const float* c11 = (ox2 || oy2) ? B : &src->rect[(x2 + y2*src->x)*src->type + chan]; + const float uf = u - ufl, vf = v - vfl; + const float w00=(1.f-uf)*(1.f-vf), w10=uf*(1.f-vf), w01=(1.f-uf)*vf, w11=uf*vf; + out[0] = w00*c00[0] + w10*c10[0] + w01*c01[0] + w11*c11[0]; + } + else *out = 0.f; +} + + +CompBuf* qd_downScaledCopy(CompBuf* src, int scale) +{ + CompBuf* fbuf; + if (scale <= 1) + fbuf = dupalloc_compbuf(src); + else { + int nw = src->x/scale, nh = src->y/scale; + if ((2*(src->x % scale)) > scale) nw++; + if ((2*(src->y % scale)) > scale) nh++; + fbuf = alloc_compbuf(nw, nh, src->type, 1); + { + int x, y, xx, yy, sx, sy, mx, my; + float colsum[4]; + float fscale = 1.f/(float)(scale*scale); + for (y=0; yrect[y*fbuf->x*fbuf->type]; + yy = y*scale; + my = yy + scale; + if (my > src->y) my = src->y; + for (x=0; x src->x) mx = src->x; + colsum[0] = colsum[1] = colsum[2] = 0.f; + for (sy=yy; syrect[sy*src->x*src->type]; + for (sx=xx; sx 3)) xy = 3; + + // see "Recursive Gabor Filtering" by Young/VanVliet + // all factors here in double.prec. Required, because for single.prec it seems to blow up if sigma > ~200 + if (sigma >= 3.556) + q = 0.9804*(sigma - 3.556) + 2.5091; + else // sigma >= 0.5 + q = (0.0561*sigma + 0.5784)*sigma - 0.2568; + q2 = q*q; + sc = (1.1668 + q)*(3.203729649 + (2.21566 + q)*q); + // no gabor filtering here, so no complex multiplies, just the regular coefs. + // all negated here, so as not to have to recalc Triggs/Sdika matrix + cf[1] = q*(5.788961737 + (6.76492 + 3.0*q)*q)/ sc; + cf[2] = -q2*(3.38246 + 3.0*q)/sc; + // 0 & 3 unchanged + cf[3] = q2*q/sc; + cf[0] = 1.0 - cf[1] - cf[2] - cf[3]; + + // Triggs/Sdika border corrections, + // it seems to work, not entirely sure if it is actually totally correct, + // Besides J.M.Geusebroek's anigauss.c (see http://www.science.uva.nl/~mark), + // found one other implementation by Cristoph Lampert, + // but neither seem to be quite the same, result seems to be ok sofar anyway. + // Extra scale factor here to not have to do it in filter, + // though maybe this had something to with the precision errors + sc = cf[0]/((1.0 + cf[1] - cf[2] + cf[3])*(1.0 - cf[1] - cf[2] - cf[3])*(1.0 + cf[2] + (cf[1] - cf[3])*cf[3])); + tsM[0] = sc*(-cf[3]*cf[1] + 1.0 - cf[3]*cf[3] - cf[2]); + tsM[1] = sc*((cf[3] + cf[1])*(cf[2] + cf[3]*cf[1])); + tsM[2] = sc*(cf[3]*(cf[1] + cf[3]*cf[2])); + tsM[3] = sc*(cf[1] + cf[3]*cf[2]); + tsM[4] = sc*(-(cf[2] - 1.0)*(cf[2] + cf[3]*cf[1])); + tsM[5] = sc*(-(cf[3]*cf[1] + cf[3]*cf[3] + cf[2] - 1.0)*cf[3]); + tsM[6] = sc*(cf[3]*cf[1] + cf[2] + cf[1]*cf[1] - cf[2]*cf[2]); + tsM[7] = sc*(cf[1]*cf[2] + cf[3]*cf[2]*cf[2] - cf[1]*cf[3]*cf[3] - cf[3]*cf[3]*cf[3] - cf[3]*cf[2] + cf[3]); + tsM[8] = sc*(cf[3]*(cf[1] + cf[3]*cf[2])); + +#define YVV(L)\ +{\ + W[0] = cf[0]*X[0] + cf[1]*X[0] + cf[2]*X[0] + cf[3]*X[0];\ + W[1] = cf[0]*X[1] + cf[1]*W[0] + cf[2]*X[0] + cf[3]*X[0];\ + W[2] = cf[0]*X[2] + cf[1]*W[1] + cf[2]*W[0] + cf[3]*X[0];\ + for (i=3; i=0; i--)\ + Y[i] = cf[0]*W[i] + cf[1]*Y[i+1] + cf[2]*Y[i+2] + cf[3]*Y[i+3];\ +} + + // intermediate buffers + sz = MAX2(src->x, src->y); + X = MEM_callocN(sz*sizeof(float), "IIR_gauss X buf"); + Y = MEM_callocN(sz*sizeof(float), "IIR_gauss Y buf"); + W = MEM_callocN(sz*sizeof(float), "IIR_gauss W buf"); + if (xy & 1) { // H + for (y=0; yy; ++y) { + const int yx = y*src->x; + for (x=0; xx; ++x) + X[x] = src->rect[(x + yx)*src->type + chan]; + YVV(src->x); + for (x=0; xx; ++x) + src->rect[(x + yx)*src->type + chan] = Y[x]; + } + } + if (xy & 2) { // V + for (x=0; xx; ++x) { + for (y=0; yy; ++y) + X[y] = src->rect[(x + y*src->x)*src->type + chan]; + YVV(src->y); + for (y=0; yy; ++y) + src->rect[(x + y*src->x)*src->type + chan] = Y[y]; + } + } + + MEM_freeN(X); + MEM_freeN(W); + MEM_freeN(Y); +#undef YVV +} + diff --git a/source/blender/nodes/intern/CMP_util.h b/source/blender/nodes/intern/CMP_util.h new file mode 100644 index 00000000000..7cb10b75f3a --- /dev/null +++ b/source/blender/nodes/intern/CMP_util.h @@ -0,0 +1,221 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef CMP_NODE_UTILS_H_ +#define CMP_NODE_UTILS_H_ + +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_camera_types.h" /* qdn: defocus node, need camera info */ +#include "DNA_action_types.h" +#include "DNA_color_types.h" +#include "DNA_ipo_types.h" +#include "DNA_ID.h" +#include "DNA_image_types.h" +#include "DNA_material_types.h" +#include "DNA_node_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_space_types.h" +#include "DNA_screen_types.h" +#include "DNA_texture_types.h" +#include "DNA_userdef_types.h" + +#include "BKE_blender.h" +#include "BKE_colortools.h" +#include "BKE_global.h" +#include "BKE_image.h" +#include "BKE_main.h" +#include "BKE_material.h" +#include "BKE_texture.h" +#include "BKE_utildefines.h" +#include "BKE_library.h" +#include "BKE_object.h" + +#include "../CMP_node.h" +#include "node_util.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" +#include "BIF_interface.h" +#include "BIF_interface_icons.h" +#include "BIF_language.h" +#include "BIF_mywindow.h" +#include "BIF_previewrender.h" +#include "BIF_resources.h" +#include "BIF_screen.h" +#include "BIF_space.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" +#include "BLI_rand.h" +#include "BLI_threads.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "BSE_drawipo.h" +#include "BSE_node.h" +#include "BSE_view.h" + +#include "RE_pipeline.h" +#include "RE_shader_ext.h" +#include "RE_render_ext.h" + +#include "butspace.h" +#include "blendef.h" +#include "mydevice.h" + +/* *************************** operations support *************************** */ + +/* general signal that's in output sockets, and goes over the wires */ +typedef struct CompBuf { + float *rect; + int x, y, xrad, yrad; + short type, malloc; + rcti disprect; /* cropped part of image */ + int xof, yof; /* relative to center of target image */ + + void (*rect_procedural)(struct CompBuf *, float *, float, float); + bNode *node; /* only in use for procedural bufs */ + + struct CompBuf *next, *prev; /* for pass-on, works nicer than reference counting */ +} CompBuf; + +/* defines also used for pixel size */ +#define CB_RGBA 4 +#define CB_VEC4 4 +#define CB_VEC3 3 +#define CB_VEC2 2 +#define CB_VAL 1 + +/* defines for RGBA channels */ +#define CHAN_R 0 +#define CHAN_G 1 +#define CHAN_B 2 +#define CHAN_A 3 + + + +CompBuf *alloc_compbuf(int sizex, int sizey, int type, int alloc); +CompBuf *dupalloc_compbuf(CompBuf *cbuf); +CompBuf *pass_on_compbuf(CompBuf *cbuf); +void free_compbuf(CompBuf *cbuf); +void print_compbuf(char *str, CompBuf *cbuf); + +CompBuf *get_cropped_compbuf(rcti *drect, float *rectf, int rectx, int recty, int type); +CompBuf *scalefast_compbuf(CompBuf *inbuf, int newx, int newy); +CompBuf *typecheck_compbuf(CompBuf *inbuf, int type); +float *compbuf_get_pixel(CompBuf *cbuf, float *rectf, int x, int y, int xrad, int yrad); + +/* **************************************************** */ + +/* Pixel-to-Pixel operation, 1 Image in, 1 out */ +void composit1_pixel_processor(bNode *node, CompBuf *out, CompBuf *src_buf, float *src_col, + void (*func)(bNode *, float *, float *), + int src_type); +/* Pixel-to-Pixel operation, 2 Images in, 1 out */ +void composit2_pixel_processor(bNode *node, CompBuf *out, CompBuf *src_buf, float *src_col, + CompBuf *fac_buf, float *fac, void (*func)(bNode *, float *, float *, float *), + int src_type, int fac_type); + +/* Pixel-to-Pixel operation, 3 Images in, 1 out */ +void composit3_pixel_processor(bNode *node, CompBuf *out, CompBuf *src1_buf, float *src1_col, CompBuf *src2_buf, float *src2_col, + CompBuf *fac_buf, float *fac, void (*func)(bNode *, float *, float *, float *, float *), + int src1_type, int src2_type, int fac_type); + +/* Pixel-to-Pixel operation, 4 Images in, 1 out */ +void composit4_pixel_processor(bNode *node, CompBuf *out, CompBuf *src1_buf, float *src1_col, CompBuf *fac1_buf, float *fac1, + CompBuf *src2_buf, float *src2_col, CompBuf *fac2_buf, float *fac2, + void (*func)(bNode *, float *, float *, float *, float *, float *), + int src1_type, int fac1_type, int src2_type, int fac2_type); + +CompBuf *valbuf_from_rgbabuf(CompBuf *cbuf, int channel); +void generate_preview(bNode *node, CompBuf *stackbuf); + +void do_copy_rgba(bNode *node, float *out, float *in); +void do_copy_rgb(bNode *node, float *out, float *in); +void do_copy_value(bNode *node, float *out, float *in); +void do_copy_a_rgba(bNode *node, float *out, float *in, float *fac); + +void do_rgba_to_yuva(bNode *node, float *out, float *in); +void do_rgba_to_hsva(bNode *node, float *out, float *in); +void do_rgba_to_ycca(bNode *node, float *out, float *in); +void do_yuva_to_rgba(bNode *node, float *out, float *in); +void do_hsva_to_rgba(bNode *node, float *out, float *in); +void do_ycca_to_rgba(bNode *node, float *out, float *in); + +void gamma_correct_compbuf(CompBuf *img, int inversed); +void convolve(CompBuf* dst, CompBuf* in1, CompBuf* in2); + +extern void node_ID_title_cb(void *node_v, void *unused_v); + + +/* utility functions used by glare, tonemap and lense distortion */ +/* soms macros for color handling */ +typedef float fRGB[4]; +/* clear color */ +#define fRGB_clear(c) { c[0]=c[1]=c[2]=0.f; } +/* copy c2 to c1 */ +#define fRGB_copy(c1, c2) { c1[0]=c2[0]; c1[1]=c2[1]; c1[2]=c2[2]; } +/* add c2 to c1 */ +#define fRGB_add(c1, c2) { c1[0]+=c2[0]; c1[1]+=c2[1]; c1[2]+=c2[2]; } +/* subtract c2 from c1 */ +#define fRGB_sub(c1, c2) { c1[0]-=c2[0]; c1[1]-=c2[1]; c1[2]-=c2[2]; } +/* multiply c by float value s */ +#define fRGB_mult(c, s) { c[0]*=s; c[1]*=s; c[2]*=s; } +/* multiply c2 by s and add to c1 */ +#define fRGB_madd(c1, c2, s) { c1[0]+=c2[0]*s; c1[1]+=c2[1]*s; c1[2]+=c2[2]*s; } +/* multiply c2 by color c1 */ +#define fRGB_colormult(c, cs) { c[0]*=cs[0]; c[1]*=cs[1]; c[2]*=cs[2]; } +/* multiply c2 by color c3 and add to c1 */ +#define fRGB_colormadd(c1, c2, c3) { c1[0]+=c2[0]*c3[0]; c1[1]+=c2[1]*c3[1]; c1[2]+=c2[2]*c3[2]; } +/* multiply c2 by color rgb, rgb as separate arguments */ +#define fRGB_rgbmult(c, r, g, b) { c[0]*=(r); c[1]*=(g); c[2]*=(b); } +/* swap colors c1 & c2 */ +#define fRGB_swap(c1, c2) { float _t=c1[0]; c1[0]=c2[0]; c2[0]=_t;\ + _t=c1[1]; c1[1]=c2[1]; c2[1]=_t;\ + _t=c1[2]; c1[2]=c2[2]; c2[2]=_t; } + +void qd_getPixel(CompBuf* src, int x, int y, float* col); +void qd_setPixel(CompBuf* src, int x, int y, float* col); +void qd_addPixel(CompBuf* src, int x, int y, float* col); +void qd_multPixel(CompBuf* src, int x, int y, float f); +void qd_getPixelLerpWrap(CompBuf* src, float u, float v, float* col); +void qd_getPixelLerp(CompBuf* src, float u, float v, float* col); +void qd_getPixelLerpChan(CompBuf* src, float u, float v, int chan, float* out); +CompBuf* qd_downScaledCopy(CompBuf* src, int scale); +void IIR_gauss(CompBuf* src, float sigma, int chan, int xy); +/* end utility funcs */ + +#endif diff --git a/source/blender/nodes/intern/Makefile b/source/blender/nodes/intern/Makefile new file mode 100644 index 00000000000..bae9a8dcf1d --- /dev/null +++ b/source/blender/nodes/intern/Makefile @@ -0,0 +1,47 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = nodes +DIR = $(OCGDIR)/blender/$(LIBNAME) + +include nan_compile.mk + +CFLAGS += $(LEVEL_1_C_WARNINGS) + +CPPFLAGS += -I../../blenkernel +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include +CPPFLAGS += -I../../makesdna +CPPFLAGS += -I../../blenlib +CPPFLAGS += -I../../include +CPPFLAGS += -I../../imbuf +CPPFLAGS += -I../../render/extern/include diff --git a/source/blender/nodes/intern/SHD_nodes/Makefile b/source/blender/nodes/intern/SHD_nodes/Makefile new file mode 100644 index 00000000000..6344af4a5cb --- /dev/null +++ b/source/blender/nodes/intern/SHD_nodes/Makefile @@ -0,0 +1,47 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = nodes_shd +DIR = $(OCGDIR)/blender/$(LIBNAME) + +include nan_compile.mk + +CFLAGS += $(LEVEL_1_C_WARNINGS) + +CPPFLAGS += -I../../../blenkernel +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include +CPPFLAGS += -I../../../makesdna +CPPFLAGS += -I../../../blenlib +CPPFLAGS += -I../../../include +CPPFLAGS += -I../../../imbuf +CPPFLAGS += -I../../../render/extern/include diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_camera.c b/source/blender/nodes/intern/SHD_nodes/SHD_camera.c new file mode 100644 index 00000000000..63260ff91ed --- /dev/null +++ b/source/blender/nodes/intern/SHD_nodes/SHD_camera.c @@ -0,0 +1,68 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../SHD_util.h" + +/* **************** CAMERA INFO ******************** */ +static bNodeSocketType sh_node_camera_out[]= { + { SOCK_VECTOR, 0, "View Vector", 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f}, /* None of these actually */ + { SOCK_VALUE, 0, "View Z Depth", 0.f, 0.0f, 0.0f, 0.0f, 0.0f, 99999999999.0f}, /* have any limits on their */ + { SOCK_VALUE, 0, "View Distance", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 99999999999.0f}, /* values. */ + { -1, 0, "" } +}; + + +static void node_shader_exec_camera(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + if(data) { + ShadeInput *shi= ((ShaderCallData *)data)->shi; /* Data we need for shading. */ + + VECCOPY(out[0]->vec, shi->co); /* get view vector */ + out[1]->vec[0]= fabs(shi->co[2]); /* get view z-depth */ + out[2]->vec[0]= Normalize(out[0]->vec); /* get view distance */ + } + } + +bNodeType sh_node_camera= { + /* *next,*prev */ NULL, NULL, + /* type code */ SH_NODE_CAMERA, + /* name */ "Camera Data", + /* width+range */ 95, 95, 120, + /* class+opts */ NODE_CLASS_INPUT, 0, + /* input sock */ NULL, + /* output sock */ sh_node_camera_out, + /* storage */ "node_camera", + /* execfunc */ node_shader_exec_camera, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; + diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_curves.c b/source/blender/nodes/intern/SHD_nodes/SHD_curves.c new file mode 100644 index 00000000000..b6f1f8d52cd --- /dev/null +++ b/source/blender/nodes/intern/SHD_nodes/SHD_curves.c @@ -0,0 +1,119 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../SHD_util.h" + + +/* **************** CURVE VEC ******************** */ +static bNodeSocketType sh_node_curve_vec_in[]= { + { SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, + { -1, 0, "" } +}; + +static bNodeSocketType sh_node_curve_vec_out[]= { + { SOCK_VECTOR, 0, "Vector", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_shader_exec_curve_vec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + float vec[3]; + + /* stack order input: vec */ + /* stack order output: vec */ + nodestack_get_vec(vec, SOCK_VECTOR, in[0]); + curvemapping_evaluate3F(node->storage, out[0]->vec, vec); +} + +static void node_shader_init_curve_vec(bNode* node) +{ + node->storage= curvemapping_add(3, -1.0f, -1.0f, 1.0f, 1.0f); +} + +bNodeType sh_node_curve_vec= { + /* *next,*prev */ NULL, NULL, + /* type code */ SH_NODE_CURVE_VEC, + /* name */ "Vector Curves", + /* width+range */ 200, 140, 320, + /* class+opts */ NODE_CLASS_OP_VECTOR, NODE_OPTIONS, + /* input sock */ sh_node_curve_vec_in, + /* output sock */ sh_node_curve_vec_out, + /* storage */ "CurveMapping", + /* execfunc */ node_shader_exec_curve_vec, + /* butfunc */ NULL, + /* initfunc */ node_shader_init_curve_vec, + /* freestoragefunc */ node_free_curves, + /* copystoragefunc */ node_copy_curves, + /* id */ NULL + +}; + +/* **************** CURVE RGB ******************** */ +static bNodeSocketType sh_node_curve_rgb_in[]= { + { SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, + { -1, 0, "" } +}; + +static bNodeSocketType sh_node_curve_rgb_out[]= { + { SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_shader_exec_curve_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + float vec[3]; + + /* stack order input: vec */ + /* stack order output: vec */ + nodestack_get_vec(vec, SOCK_VECTOR, in[0]); + curvemapping_evaluateRGBF(node->storage, out[0]->vec, vec); +} + +static void node_shader_init_curve_rgb(bNode *node) +{ + node->storage= curvemapping_add(4, 0.0f, 0.0f, 1.0f, 1.0f); +} + +bNodeType sh_node_curve_rgb= { + /* *next,*prev */ NULL, NULL, + /* type code */ SH_NODE_CURVE_RGB, + /* name */ "RGB Curves", + /* width+range */ 200, 140, 320, + /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS, + /* input sock */ sh_node_curve_rgb_in, + /* output sock */ sh_node_curve_rgb_out, + /* storage */ "CurveMapping", + /* execfunc */ node_shader_exec_curve_rgb, + /* butfunc */ NULL, + /* initfunc */ node_shader_init_curve_rgb, + /* freestoragefunc */ node_free_curves, + /* copystoragefunc */ node_copy_curves, + /* id */ NULL +}; + diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c b/source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c new file mode 100644 index 00000000000..1ba777a0533 --- /dev/null +++ b/source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c @@ -0,0 +1,247 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2007 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Nathan Letwory + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifdef USE_PYNODES /* note: won't work without patch */ + +#include +#include + +#include "DNA_text_types.h" +#include "BKE_text.h" + +#include "api2_2x/Node.h" +#include "api2_2x/gen_utils.h" +#include "BPY_extern.h" + +#include "../SHD_util.h" + +static PyObject *init_dynamicdict(void) { + PyObject *newscriptdict= PyDict_New(); + PyDict_SetItemString(newscriptdict, "__builtins__", PyEval_GetBuiltins()); + EXPP_dict_set_item_str(newscriptdict, "__name__", PyString_FromString("__main__")); + return newscriptdict; +} + +static void free_dynamicdict(PyObject *dict) { + if(dict!=NULL) { + Py_DECREF(dict); + } +} + +static void node_dynamic_init(bNode *node) { + NodeScriptDict *nsd= MEM_callocN(sizeof(NodeScriptDict), "node script dictionary"); + int type= node->custom2; + node->custom2= 0; + node->storage= nsd; + if(type>=NODE_DYNAMIC_MENU) { + if(type==NODE_DYNAMIC_MENU) { + nodeMakeDynamicType(node); + node->custom1= SH_NODE_DYNAMIC_NEW; + } else { + node->custom1= SH_NODE_DYNAMIC_ADDEXIST; + } + node->id= node->typeinfo->id; + nodeDynamicParse(node); + } else { + if(node->custom1== SH_NODE_DYNAMIC_LOADED) { + nodeMakeDynamicType(node); + nodeDynamicParse(node); + } else if(node->custom1== SH_NODE_DYNAMIC_ADDEXIST) + nodeDynamicParse(node); + } +} + +static void node_dynamic_free(bNode *node) +{ + NodeScriptDict *nsd= (NodeScriptDict *)(node->storage); + BPy_Node *pynode= nsd->node; + Py_XDECREF(pynode); + free_dynamicdict((PyObject *)(nsd->dict)); + MEM_freeN(node->storage); +} + +static void node_dynamic_copy(bNode *orig_node, bNode *new_node) +{ + NodeScriptDict *nsd= (NodeScriptDict *)(orig_node->storage); + new_node->storage= MEM_dupallocN(orig_node->storage); + if(nsd->node) + Py_INCREF((PyObject *)(nsd->node)); + if(nsd->dict) + Py_INCREF((PyObject *)(nsd->dict)); +} + +static void node_dynamic_exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { + BPy_Node *mynode = NULL; + NodeScriptDict *nsd = NULL; + PyObject *pyresult = NULL; + PyObject *args = NULL; + ShadeInput *shi= ((ShaderCallData *)data)->shi; + + if(node->custom1==SH_NODE_DYNAMIC_NEW) { + nodeDynamicParse(node); + return; + } + + if(node->custom2<0) + return; + + if(node->custom1==SH_NODE_DYNAMIC_READY || node->custom1==SH_NODE_DYNAMIC_UPDATED) { + if(node->custom1== SH_NODE_DYNAMIC_UPDATED) + node->custom1= SH_NODE_DYNAMIC_READY; + + nsd = (NodeScriptDict *)node->storage; + + mynode = (BPy_Node *)(nsd->node); + if(mynode && PyCallable_Check((PyObject *)mynode)) { + mynode->node= node; + Node_SetStack(mynode, in, NODE_INPUTSTACK); + Node_SetStack(mynode, out, NODE_OUTPUTSTACK); + Node_SetShi(mynode, shi); + args=Py_BuildValue("()"); + pyresult= PyObject_Call((PyObject *)mynode, args, NULL); + if(!pyresult) { + if(PyErr_Occurred()) { + PyErr_Print(); + node->custom2= -1; + } else { + printf("PyObject_Call __call__ failed\n"); + } + } + Py_XDECREF(pyresult); + Py_DECREF(args); + } + } +} + +void nodeDynamicParse(struct bNode *node) +{ + BPy_Node *pynode= NULL; + PyObject *dict= NULL; + PyObject *key= NULL; + PyObject *value= NULL; + PyObject *testinst= NULL; + PyObject *args= NULL; + int pos = 0; + NodeScriptDict *nsd= NULL; + PyObject *pyresult = NULL; + PyObject *pycompiled = NULL; + Text *txt = NULL; + char *buf= NULL; + + if(! node->id) { + return; + } + + if(node->custom1!=SH_NODE_DYNAMIC_READY) { + txt = (Text *)node->id; + nsd = (NodeScriptDict *)node->storage; + + if(nsd->dict==NULL && (node->custom1==SH_NODE_DYNAMIC_NEW||node->custom1==SH_NODE_DYNAMIC_LOADED)) { + nsd->dict= init_dynamicdict(); + } else if(nsd->dict==NULL && node->custom1==SH_NODE_DYNAMIC_ADDEXIST) { + nsd->dict= node->typeinfo->pydict; + nsd->node= node->typeinfo->pynode; + Py_INCREF((PyObject *)(nsd->dict)); + Py_INCREF((PyObject *)(nsd->node)); + node->custom1= SH_NODE_DYNAMIC_READY; + return; + } + dict= (PyObject *)(nsd->dict); + + if(node->custom1!=SH_NODE_DYNAMIC_ADDEXIST) { + buf = txt_to_buf( txt ); + /*printf("Running script (%s, %d)...", node->name, node->custom1);*/ + pyresult = PyRun_String(buf, Py_file_input, dict, dict); + /*printf(" done\n");*/ + + MEM_freeN(buf); + + if(!pyresult) { + if(PyErr_Occurred()) { + PyErr_Print(); + } + Py_XDECREF(pyresult); + return; + } + + Py_DECREF(pyresult); + + while(PyDict_Next( (PyObject *)(nsd->dict), &pos, &key, &value) ) { + if(PyObject_TypeCheck(value, &PyType_Type)==1) { + BPy_DefinitionMap *outputdef= Node_CreateOutputDefMap(node); + BPy_DefinitionMap *inputdef= Node_CreateInputDefMap(node); + + args= Py_BuildValue("(OO)", inputdef, outputdef); + testinst= PyObject_Call(value, args, NULL); + + Py_DECREF(outputdef); + Py_DECREF(inputdef); + if(testinst && PyObject_TypeCheck(testinst, &Node_Type)==1) { + Py_INCREF(testinst); + Py_INCREF(dict); + InitNode((BPy_Node *)(testinst), node); + nsd->node= testinst; + node->typeinfo->execfunc= node_dynamic_exec; + if(node->custom1== SH_NODE_DYNAMIC_NEW || node->custom1== SH_NODE_DYNAMIC_LOADED) { + node->typeinfo->pynode= testinst; + node->typeinfo->pydict= nsd->dict; + node->typeinfo->id= node->id; + nodeAddSockets(node, node->typeinfo); + nodeRegisterType(&node_all_shaders, node->typeinfo); + node->custom1= SH_NODE_DYNAMIC_READY; + } + break; + } + Py_DECREF(args); + } + } + } + } +} + + +bNodeType sh_node_dynamic = { + /* next, prev */ NULL, NULL, + /* type code */ SH_NODE_DYNAMIC, + /* name */ "Dynamic", + /* width+range */ 150, 60, 300, + /* class+opts */ NODE_CLASS_OP_DYNAMIC, NODE_OPTIONS, + /* input sock */ NULL, + /* output sock */ NULL, + /* storage */ "NodeScriptDict", + /* execfunc */ node_dynamic_exec, + /* butfunc */ NULL, + /* initfunc */ node_dynamic_init, + /* freefunc */ node_dynamic_free, + /* copyfunc */ node_dynamic_copy, + /* id */ NULL +}; + +#endif /* USE_PYNODES */ + diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_geom.c b/source/blender/nodes/intern/SHD_nodes/SHD_geom.c new file mode 100644 index 00000000000..b15aa6802f3 --- /dev/null +++ b/source/blender/nodes/intern/SHD_nodes/SHD_geom.c @@ -0,0 +1,144 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../SHD_util.h" + + +/* **************** GEOMETRY ******************** */ + +/* output socket type definition */ +static bNodeSocketType sh_node_geom_out[]= { + { SOCK_VECTOR, 0, "Global", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, /* btw; uses no limit */ + { SOCK_VECTOR, 0, "Local", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, + { SOCK_VECTOR, 0, "View", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, + { SOCK_VECTOR, 0, "Orco", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, + { SOCK_VECTOR, 0, "UV", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, + { SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, + { SOCK_RGBA, 0, "Vertex Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "Front/Back", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +/* node execute callback */ +static void node_shader_exec_geom(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + if(data) { + ShadeInput *shi= ((ShaderCallData *)data)->shi; + NodeGeometry *ngeo= (NodeGeometry*)node->storage; + ShadeInputUV *suv= &shi->uv[0]; + static float defaultvcol[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + static float front= 0.0; + int i; + + if(ngeo->uvname[0]) { + /* find uv layer by name */ + for(i = 0; i < shi->totuv; i++) { + if(strcmp(shi->uv[i].name, ngeo->uvname)==0) { + suv= &shi->uv[i]; + break; + } + } + } + + /* out: global, local, view, orco, uv, normal, vertex color */ + VECCOPY(out[GEOM_OUT_GLOB]->vec, shi->gl); + VECCOPY(out[GEOM_OUT_LOCAL]->vec, shi->co); + VECCOPY(out[GEOM_OUT_VIEW]->vec, shi->view); + VECCOPY(out[GEOM_OUT_ORCO]->vec, shi->lo); + VECCOPY(out[GEOM_OUT_UV]->vec, suv->uv); + VECCOPY(out[GEOM_OUT_NORMAL]->vec, shi->vno); + + if (shi->totcol) { + /* find vertex color layer by name */ + ShadeInputCol *scol= &shi->col[0]; + + if(ngeo->colname[0]) { + for(i = 0; i < shi->totcol; i++) { + if(strcmp(shi->col[i].name, ngeo->colname)==0) { + scol= &shi->col[i]; + break; + } + } + } + + VECCOPY(out[GEOM_OUT_VCOL]->vec, scol->col); + out[GEOM_OUT_VCOL]->vec[3]= 1.0f; + } + else + memcpy(out[GEOM_OUT_VCOL]->vec, defaultvcol, sizeof(defaultvcol)); + + if(shi->osatex) { + out[GEOM_OUT_GLOB]->data= shi->dxgl; + out[GEOM_OUT_GLOB]->datatype= NS_OSA_VECTORS; + out[GEOM_OUT_LOCAL]->data= shi->dxco; + out[GEOM_OUT_LOCAL]->datatype= NS_OSA_VECTORS; + out[GEOM_OUT_VIEW]->data= &shi->dxview; + out[GEOM_OUT_VIEW]->datatype= NS_OSA_VALUES; + out[GEOM_OUT_ORCO]->data= shi->dxlo; + out[GEOM_OUT_ORCO]->datatype= NS_OSA_VECTORS; + out[GEOM_OUT_UV]->data= suv->dxuv; + out[GEOM_OUT_UV]->datatype= NS_OSA_VECTORS; + out[GEOM_OUT_NORMAL]->data= shi->dxno; + out[GEOM_OUT_NORMAL]->datatype= NS_OSA_VECTORS; + } + + /* front/back + * check the original un-flipped normals to determine front or back side */ + if (shi->orignor[2] < FLT_EPSILON) { + front= 1.0f; + } else { + front = 0.0f; + } + out[GEOM_OUT_FRONTBACK]->vec[0]= front; + } +} + +static void node_shader_init_geometry(bNode *node) +{ + node->storage= MEM_callocN(sizeof(NodeGeometry), "NodeGeometry"); +} + +/* node type definition */ +bNodeType sh_node_geom= { + /* *next,*prev */ NULL, NULL, + /* type code */ SH_NODE_GEOMETRY, + /* name */ "Geometry", + /* width+range */ 120, 80, 160, + /* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS, + /* input sock */ NULL, + /* output sock */ sh_node_geom_out, + /* storage */ "NodeGeometry", + /* execfunc */ node_shader_exec_geom, + /* butfunc */ NULL, + /* initfunc */ node_shader_init_geometry, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL + +}; diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_hueSatVal.c b/source/blender/nodes/intern/SHD_nodes/SHD_hueSatVal.c new file mode 100644 index 00000000000..8c07a2d1dc8 --- /dev/null +++ b/source/blender/nodes/intern/SHD_nodes/SHD_hueSatVal.c @@ -0,0 +1,94 @@ +/** + * + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Juho Vepsäläinen + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../SHD_util.h" + + +/* **************** Hue Saturation ******************** */ +static bNodeSocketType sh_node_hue_sat_in[]= { + { SOCK_VALUE, 1, "Hue", 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Saturation", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f}, + { SOCK_VALUE, 1, "Value", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f}, + { SOCK_VALUE, 1, "Fac", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 1, "Color", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType sh_node_hue_sat_out[]= { + { SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +/* note: it would be possible to use CMP version for both nodes */ +static void do_hue_sat_fac(bNode *node, float *out, float *hue, float *sat, float *val, float *in, float *fac) +{ + if(*fac!=0.0f && (*hue!=0.5f || *sat!=1.0 || *val!=1.0)) { + float col[3], hsv[3], mfac= 1.0f - *fac; + + rgb_to_hsv(in[0], in[1], in[2], hsv, hsv+1, hsv+2); + hsv[0]+= (*hue - 0.5f); + if(hsv[0]>1.0) hsv[0]-=1.0; else if(hsv[0]<0.0) hsv[0]+= 1.0; + hsv[1]*= *sat; + if(hsv[1]>1.0) hsv[1]= 1.0; else if(hsv[1]<0.0) hsv[1]= 0.0; + hsv[2]*= *val; + if(hsv[2]>1.0) hsv[2]= 1.0; else if(hsv[2]<0.0) hsv[2]= 0.0; + hsv_to_rgb(hsv[0], hsv[1], hsv[2], col, col+1, col+2); + + out[0]= mfac*in[0] + *fac*col[0]; + out[1]= mfac*in[1] + *fac*col[1]; + out[2]= mfac*in[2] + *fac*col[2]; + } + else { + QUATCOPY(out, in); + } +} + +static void node_shader_exec_hue_sat(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + do_hue_sat_fac(node, out[0]->vec, in[0]->vec, in[1]->vec, in[2]->vec, in[4]->vec, in[3]->vec); +} + +bNodeType sh_node_hue_sat= { + /* *next,*prev */ NULL, NULL, + /* type code */ SH_NODE_HUE_SAT, + /* name */ "Hue Saturation Value", + /* width+range */ 150, 80, 250, + /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS, + /* input sock */ sh_node_hue_sat_in, + /* output sock */ sh_node_hue_sat_out, + /* storage */ "", + /* execfunc */ node_shader_exec_hue_sat, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; + + diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_invert.c b/source/blender/nodes/intern/SHD_nodes/SHD_invert.c new file mode 100644 index 00000000000..4d1ce282fce --- /dev/null +++ b/source/blender/nodes/intern/SHD_nodes/SHD_invert.c @@ -0,0 +1,83 @@ +/** + * $Id: SHD_math.c,v 1.4 2007/04/04 13:58:12 jesterking Exp $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../SHD_util.h" + + + +/* **************** INVERT ******************** */ +static bNodeSocketType sh_node_invert_in[]= { + { SOCK_VALUE, 1, "Fac", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static bNodeSocketType sh_node_invert_out[]= { + { SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_shader_exec_invert(void *data, bNode *node, bNodeStack **in, +bNodeStack **out) +{ + float col[3], facm; + + col[0] = 1.0f - in[1]->vec[0]; + col[1] = 1.0f - in[1]->vec[1]; + col[2] = 1.0f - in[1]->vec[2]; + + /* if fac, blend result against original input */ + if (in[0]->vec[0] < 1.0f) { + facm = 1.0 - in[0]->vec[0]; + + col[0] = in[0]->vec[0]*col[0] + (facm*in[1]->vec[0]); + col[1] = in[0]->vec[0]*col[1] + (facm*in[1]->vec[1]); + col[2] = in[0]->vec[0]*col[2] + (facm*in[1]->vec[2]); + } + + VECCOPY(out[0]->vec, col); +} + +bNodeType sh_node_invert= { + /* *next,*prev */ NULL, NULL, + /* type code */ SH_NODE_INVERT, + /* name */ "Invert", + /* width+range */ 90, 80, 100, + /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS, + /* input sock */ sh_node_invert_in, + /* output sock */ sh_node_invert_out, + /* storage */ "", + /* execfunc */ node_shader_exec_invert, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; + diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_mapping.c b/source/blender/nodes/intern/SHD_nodes/SHD_mapping.c new file mode 100644 index 00000000000..589954c8f7b --- /dev/null +++ b/source/blender/nodes/intern/SHD_nodes/SHD_mapping.c @@ -0,0 +1,89 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../SHD_util.h" + +/* **************** MAPPING ******************** */ +static bNodeSocketType sh_node_mapping_in[]= { + { SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, + { -1, 0, "" } +}; + +static bNodeSocketType sh_node_mapping_out[]= { + { SOCK_VECTOR, 0, "Vector", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f}, + { -1, 0, "" } +}; + +/* do the regular mapping options for blender textures */ +static void node_shader_exec_mapping(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + TexMapping *texmap= node->storage; + float *vec= out[0]->vec; + + /* stack order input: vector */ + /* stack order output: vector */ + nodestack_get_vec(vec, SOCK_VECTOR, in[0]); + Mat4MulVecfl(texmap->mat, vec); + + if(texmap->flag & TEXMAP_CLIP_MIN) { + if(vec[0]min[0]) vec[0]= texmap->min[0]; + if(vec[1]min[1]) vec[1]= texmap->min[1]; + if(vec[2]min[2]) vec[2]= texmap->min[2]; + } + if(texmap->flag & TEXMAP_CLIP_MAX) { + if(vec[0]>texmap->max[0]) vec[0]= texmap->max[0]; + if(vec[1]>texmap->max[1]) vec[1]= texmap->max[1]; + if(vec[2]>texmap->max[2]) vec[2]= texmap->max[2]; + } +} + + +static void node_shader_init_mapping(bNode *node) +{ + node->storage= add_mapping(); +} + +bNodeType sh_node_mapping= { + /* *next,*prev */ NULL, NULL, + /* type code */ SH_NODE_MAPPING, + /* name */ "Mapping", + /* width+range */ 240, 160, 320, + /* class+opts */ NODE_CLASS_OP_VECTOR, NODE_OPTIONS, + /* input sock */ sh_node_mapping_in, + /* output sock */ sh_node_mapping_out, + /* storage */ "TexMapping", + /* execfunc */ node_shader_exec_mapping, + /* butfunc */ NULL, + /* initfunc */ node_shader_init_mapping, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL + +}; + diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_material.c b/source/blender/nodes/intern/SHD_nodes/SHD_material.c new file mode 100644 index 00000000000..bdceb134c0d --- /dev/null +++ b/source/blender/nodes/intern/SHD_nodes/SHD_material.c @@ -0,0 +1,224 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../SHD_util.h" + +/* **************** MATERIAL ******************** */ + +static bNodeSocketType sh_node_material_in[]= { + { SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 1, "Spec", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Refl", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VECTOR, 1, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, + { -1, 0, "" } +}; + +static bNodeSocketType sh_node_material_out[]= { + { SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, + { -1, 0, "" } +}; + +/* **************** EXTENDED MATERIAL ******************** */ + +static bNodeSocketType sh_node_material_ext_in[]= { + { SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 1, "Spec", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Refl", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VECTOR, 1, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, + { SOCK_RGBA, 1, "Mirror", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 1, "AmbCol", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Ambient", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Emit", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "SpecTra", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Ray Mirror", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Alpha", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Translucency", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static bNodeSocketType sh_node_material_ext_out[]= { + { SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, + { SOCK_RGBA, 0, "Diffuse", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 0, "Spec", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 0, "AO", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_shader_exec_material(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + if(data && node->id) { + ShadeResult shrnode; + ShadeInput *shi; + ShaderCallData *shcd= data; + float col[4]; + + shi= shcd->shi; + shi->mat= (Material *)node->id; + + /* copy all relevant material vars, note, keep this synced with render_types.h */ + memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); + shi->har= shi->mat->har; + + /* write values */ + if(in[MAT_IN_COLOR]->hasinput) + nodestack_get_vec(&shi->r, SOCK_VECTOR, in[MAT_IN_COLOR]); + + if(in[MAT_IN_SPEC]->hasinput) + nodestack_get_vec(&shi->specr, SOCK_VECTOR, in[MAT_IN_SPEC]); + + if(in[MAT_IN_REFL]->hasinput) + nodestack_get_vec(&shi->refl, SOCK_VALUE, in[MAT_IN_REFL]); + + /* retrieve normal */ + if(in[MAT_IN_NORMAL]->hasinput) { + nodestack_get_vec(shi->vn, SOCK_VECTOR, in[MAT_IN_NORMAL]); + Normalize(shi->vn); + } + else + VECCOPY(shi->vn, shi->vno); + + /* custom option to flip normal */ + if(node->custom1 & SH_NODE_MAT_NEG) { + shi->vn[0]= -shi->vn[0]; + shi->vn[1]= -shi->vn[1]; + shi->vn[2]= -shi->vn[2]; + } + + if (node->type == SH_NODE_MATERIAL_EXT) { + if(in[MAT_IN_MIR]->hasinput) + nodestack_get_vec(&shi->mirr, SOCK_VECTOR, in[MAT_IN_MIR]); + if(in[MAT_IN_AMBCOL]->hasinput) + nodestack_get_vec(&shi->ambr, SOCK_VECTOR, in[MAT_IN_AMBCOL]); + if(in[MAT_IN_AMB]->hasinput) + nodestack_get_vec(&shi->amb, SOCK_VALUE, in[MAT_IN_AMB]); + if(in[MAT_IN_EMIT]->hasinput) + nodestack_get_vec(&shi->emit, SOCK_VALUE, in[MAT_IN_EMIT]); + if(in[MAT_IN_SPECTRA]->hasinput) + nodestack_get_vec(&shi->spectra, SOCK_VALUE, in[MAT_IN_SPECTRA]); + if(in[MAT_IN_RAY_MIRROR]->hasinput) + nodestack_get_vec(&shi->ray_mirror, SOCK_VALUE, in[MAT_IN_RAY_MIRROR]); + if(in[MAT_IN_ALPHA]->hasinput) + nodestack_get_vec(&shi->alpha, SOCK_VALUE, in[MAT_IN_ALPHA]); + if(in[MAT_IN_TRANSLUCENCY]->hasinput) + nodestack_get_vec(&shi->translucency, SOCK_VALUE, in[MAT_IN_TRANSLUCENCY]); + } + + node_shader_lamp_loop(shi, &shrnode); /* clears shrnode */ + + /* write to outputs */ + if(node->custom1 & SH_NODE_MAT_DIFF) { + VECCOPY(col, shrnode.combined); + if(!(node->custom1 & SH_NODE_MAT_SPEC)) { + VecSubf(col, col, shrnode.spec); + } + } + else if(node->custom1 & SH_NODE_MAT_SPEC) { + VECCOPY(col, shrnode.spec); + } + else + col[0]= col[1]= col[2]= 0.0f; + + col[3]= shrnode.alpha; + + if(shi->do_preview) + nodeAddToPreview(node, col, shi->xs, shi->ys); + + VECCOPY(out[MAT_OUT_COLOR]->vec, col); + out[MAT_OUT_ALPHA]->vec[0]= shrnode.alpha; + + if(node->custom1 & SH_NODE_MAT_NEG) { + shi->vn[0]= -shi->vn[0]; + shi->vn[1]= -shi->vn[1]; + shi->vn[2]= -shi->vn[2]; + } + + VECCOPY(out[MAT_OUT_NORMAL]->vec, shi->vn); + + /* Extended material options */ + if (node->type == SH_NODE_MATERIAL_EXT) { + /* Shadow, Reflect, Refract, Radiosity, Speed seem to cause problems inside + * a node tree :( */ + VECCOPY(out[MAT_OUT_DIFFUSE]->vec, shrnode.diff); + VECCOPY(out[MAT_OUT_SPEC]->vec, shrnode.spec); + VECCOPY(out[MAT_OUT_AO]->vec, shrnode.ao); + } + + /* copy passes, now just active node */ + if(node->flag & NODE_ACTIVE_ID) + *(shcd->shr)= shrnode; + } +} + + +static void node_shader_init_material(bNode* node) +{ + node->custom1= SH_NODE_MAT_DIFF|SH_NODE_MAT_SPEC; +} + + +bNodeType sh_node_material= { + /* *next,*prev */ NULL, NULL, + /* type code */ SH_NODE_MATERIAL, + /* name */ "Material", + /* width+range */ 120, 80, 240, + /* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS|NODE_PREVIEW, + /* input sock */ sh_node_material_in, + /* output sock */ sh_node_material_out, + /* storage */ "", + /* execfunc */ node_shader_exec_material, + /* butfunc */ NULL, + /* initfunc */ node_shader_init_material, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; + +bNodeType sh_node_material_ext= { + /* *next,*prev */ NULL, NULL, + /* type code */ SH_NODE_MATERIAL_EXT, + /* name */ "Extended Material", + /* width+range */ 120, 80, 240, + /* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS|NODE_PREVIEW, + /* input sock */ sh_node_material_ext_in, + /* output sock */ sh_node_material_ext_out, + /* storage */ "", + /* execfunc */ node_shader_exec_material, + /* butfunc */ NULL, + /* initfunc */ node_shader_init_material, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; + diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_math.c b/source/blender/nodes/intern/SHD_nodes/SHD_math.c new file mode 100644 index 00000000000..95162e508d5 --- /dev/null +++ b/source/blender/nodes/intern/SHD_nodes/SHD_math.c @@ -0,0 +1,197 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../SHD_util.h" + + + +/* **************** SCALAR MATH ******************** */ +static bNodeSocketType sh_node_math_in[]= { + { SOCK_VALUE, 1, "Value", 0.5f, 0.5f, 0.5f, 1.0f, -100.0f, 100.0f}, + { SOCK_VALUE, 1, "Value", 0.5f, 0.5f, 0.5f, 1.0f, -100.0f, 100.0f}, + { -1, 0, "" } +}; + +static bNodeSocketType sh_node_math_out[]= { + { SOCK_VALUE, 0, "Value", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_shader_exec_math(void *data, bNode *node, bNodeStack **in, +bNodeStack **out) +{ + switch(node->custom1){ + + case 0: /* Add */ + out[0]->vec[0]= in[0]->vec[0] + in[1]->vec[0]; + break; + case 1: /* Subtract */ + out[0]->vec[0]= in[0]->vec[0] - in[1]->vec[0]; + break; + case 2: /* Multiply */ + out[0]->vec[0]= in[0]->vec[0] * in[1]->vec[0]; + break; + case 3: /* Divide */ + { + if(in[1]->vec[0]==0) /* We don't want to divide by zero. */ + out[0]->vec[0]= 0.0; + else + out[0]->vec[0]= in[0]->vec[0] / in[1]->vec[0]; + } + break; + case 4: /* Sine */ + { + if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */ + out[0]->vec[0]= sin(in[0]->vec[0]); + else + out[0]->vec[0]= sin(in[1]->vec[0]); + } + break; + case 5: /* Cosine */ + { + if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */ + out[0]->vec[0]= cos(in[0]->vec[0]); + else + out[0]->vec[0]= cos(in[1]->vec[0]); + } + break; + case 6: /* Tangent */ + { + if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */ + out[0]->vec[0]= tan(in[0]->vec[0]); + else + out[0]->vec[0]= tan(in[1]->vec[0]); + } + break; + case 7: /* Arc-Sine */ + { + if(in[0]->hasinput || !in[1]->hasinput) { /* This one only takes one input, so we've got to choose. */ + /* Can't do the impossible... */ + if( in[0]->vec[0] <= 1 && in[0]->vec[0] >= -1 ) + out[0]->vec[0]= asin(in[0]->vec[0]); + else + out[0]->vec[0]= 0.0; + } + else { + /* Can't do the impossible... */ + if( in[1]->vec[0] <= 1 && in[1]->vec[0] >= -1 ) + out[0]->vec[0]= asin(in[1]->vec[0]); + else + out[0]->vec[0]= 0.0; + } + } + break; + case 8: /* Arc-Cosine */ + { + if(in[0]->hasinput || !in[1]->hasinput) { /* This one only takes one input, so we've got to choose. */ + /* Can't do the impossible... */ + if( in[0]->vec[0] <= 1 && in[0]->vec[0] >= -1 ) + out[0]->vec[0]= acos(in[0]->vec[0]); + else + out[0]->vec[0]= 0.0; + } + else { + /* Can't do the impossible... */ + if( in[1]->vec[0] <= 1 && in[1]->vec[0] >= -1 ) + out[0]->vec[0]= acos(in[1]->vec[0]); + else + out[0]->vec[0]= 0.0; + } + } + break; + case 9: /* Arc-Tangent */ + { + if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */ + out[0]->vec[0]= atan(in[0]->vec[0]); + else + out[0]->vec[0]= atan(in[1]->vec[0]); + } + break; + case 10: /* Power */ + { + /* Don't want any imaginary numbers... */ + if( in[0]->vec[0] >= 0 ) + out[0]->vec[0]= pow(in[0]->vec[0], in[1]->vec[0]); + else + out[0]->vec[0]= 0.0; + } + break; + case 11: /* Logarithm */ + { + /* Don't want any imaginary numbers... */ + if( in[0]->vec[0] > 0 && in[1]->vec[0] > 0 ) + out[0]->vec[0]= log(in[0]->vec[0]) / log(in[1]->vec[0]); + else + out[0]->vec[0]= 0.0; + } + break; + case 12: /* Minimum */ + { + if( in[0]->vec[0] < in[1]->vec[0] ) + out[0]->vec[0]= in[0]->vec[0]; + else + out[0]->vec[0]= in[1]->vec[0]; + } + break; + case 13: /* Maximum */ + { + if( in[0]->vec[0] > in[1]->vec[0] ) + out[0]->vec[0]= in[0]->vec[0]; + else + out[0]->vec[0]= in[1]->vec[0]; + } + break; + case 14: /* Round */ + { + if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */ + out[0]->vec[0]= (int)(in[0]->vec[0] + 0.5f); + else + out[0]->vec[0]= (int)(in[1]->vec[0] + 0.5f); + } + break; + } +} + +bNodeType sh_node_math= { + /* *next,*prev */ NULL, NULL, + /* type code */ SH_NODE_MATH, + /* name */ "Math", + /* width+range */ 120, 110, 160, + /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS, + /* input sock */ sh_node_math_in, + /* output sock */ sh_node_math_out, + /* storage */ "node_math", + /* execfunc */ node_shader_exec_math, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; + diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_mixRgb.c b/source/blender/nodes/intern/SHD_nodes/SHD_mixRgb.c new file mode 100644 index 00000000000..dba70253fda --- /dev/null +++ b/source/blender/nodes/intern/SHD_nodes/SHD_mixRgb.c @@ -0,0 +1,79 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../SHD_util.h" + + +/* **************** MIX RGB ******************** */ +static bNodeSocketType sh_node_mix_rgb_in[]= { + { SOCK_VALUE, 1, "Fac", 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 1, "Color1", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 1, "Color2", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType sh_node_mix_rgb_out[]= { + { SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_shader_exec_mix_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order in: fac, col1, col2 */ + /* stack order out: col */ + float col[3]; + float fac; + float vec[3]; + + nodestack_get_vec(&fac, SOCK_VALUE, in[0]); + CLAMP(fac, 0.0f, 1.0f); + + nodestack_get_vec(col, SOCK_VECTOR, in[1]); + nodestack_get_vec(vec, SOCK_VECTOR, in[2]); + + ramp_blend(node->custom1, col, col+1, col+2, fac, vec); + VECCOPY(out[0]->vec, col); +} + +bNodeType sh_node_mix_rgb= { + /* *next,*prev */ NULL, NULL, + /* type code */ SH_NODE_MIX_RGB, + /* name */ "Mix", + /* width+range */ 100, 60, 150, + /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS, + /* input sock */ sh_node_mix_rgb_in, + /* output sock */ sh_node_mix_rgb_out, + /* storage */ "", + /* execfunc */ node_shader_exec_mix_rgb, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_normal.c b/source/blender/nodes/intern/SHD_nodes/SHD_normal.c new file mode 100644 index 00000000000..f1ffd3446af --- /dev/null +++ b/source/blender/nodes/intern/SHD_nodes/SHD_normal.c @@ -0,0 +1,76 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../SHD_util.h" + +/* **************** NORMAL ******************** */ +static bNodeSocketType sh_node_normal_in[]= { + { SOCK_VECTOR, 1, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, + { -1, 0, "" } +}; + +static bNodeSocketType sh_node_normal_out[]= { + { SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f}, + { SOCK_VALUE, 0, "Dot", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +/* generates normal, does dot product */ +static void node_shader_exec_normal(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + bNodeSocket *sock= node->outputs.first; + float vec[3]; + + /* stack order input: normal */ + /* stack order output: normal, value */ + + nodestack_get_vec(vec, SOCK_VECTOR, in[0]); + + VECCOPY(out[0]->vec, sock->ns.vec); + /* render normals point inside... the widget points outside */ + out[1]->vec[0]= -INPR(out[0]->vec, vec); +} + +bNodeType sh_node_normal= { + /* *next,*prev */ NULL, NULL, + /* type code */ SH_NODE_NORMAL, + /* name */ "Normal", + /* width+range */ 100, 60, 200, + /* class+opts */ NODE_CLASS_OP_VECTOR, NODE_OPTIONS, + /* input sock */ sh_node_normal_in, + /* output sock */ sh_node_normal_out, + /* storage */ "", + /* execfunc */ node_shader_exec_normal, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; + diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_output.c b/source/blender/nodes/intern/SHD_nodes/SHD_output.c new file mode 100644 index 00000000000..0a9a30c452b --- /dev/null +++ b/source/blender/nodes/intern/SHD_nodes/SHD_output.c @@ -0,0 +1,82 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../SHD_util.h" + +/* **************** OUTPUT ******************** */ +static bNodeSocketType sh_node_output_in[]= { + { SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_shader_exec_output(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + if(data) { + ShadeInput *shi= ((ShaderCallData *)data)->shi; + float col[4]; + + /* stack order input sockets: col, alpha, normal */ + nodestack_get_vec(col, SOCK_VECTOR, in[0]); + nodestack_get_vec(col+3, SOCK_VALUE, in[1]); + + if(shi->do_preview) { + nodeAddToPreview(node, col, shi->xs, shi->ys); + node->lasty= shi->ys; + } + + if(node->flag & NODE_DO_OUTPUT) { + ShadeResult *shr= ((ShaderCallData *)data)->shr; + + QUATCOPY(shr->combined, col); + shr->alpha= col[3]; + + // VECCOPY(shr->nor, in[3]->vec); + } + } +} + +bNodeType sh_node_output= { + /* *next,*prev */ NULL, NULL, + /* type code */ SH_NODE_OUTPUT, + /* name */ "Output", + /* width+range */ 80, 60, 200, + /* class+opts */ NODE_CLASS_OUTPUT, NODE_PREVIEW, + /* input sock */ sh_node_output_in, + /* output sock */ NULL, + /* storage */ "", + /* execfunc */ node_shader_exec_output, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; + diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_rgb.c b/source/blender/nodes/intern/SHD_nodes/SHD_rgb.c new file mode 100644 index 00000000000..4e56e26d3ad --- /dev/null +++ b/source/blender/nodes/intern/SHD_nodes/SHD_rgb.c @@ -0,0 +1,61 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../SHD_util.h" + +/* **************** RGB ******************** */ +static bNodeSocketType sh_node_rgb_out[]= { + { SOCK_RGBA, 0, "Color", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_shader_exec_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + bNodeSocket *sock= node->outputs.first; + + VECCOPY(out[0]->vec, sock->ns.vec); +} + +bNodeType sh_node_rgb= { + /* *next,*prev */ NULL, NULL, + /* type code */ SH_NODE_RGB, + /* name */ "RGB", + /* width+range */ 100, 60, 140, + /* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS, + /* input sock */ NULL, + /* output sock */ sh_node_rgb_out, + /* storage */ "", + /* execfunc */ node_shader_exec_rgb, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_sepcombRGB.c b/source/blender/nodes/intern/SHD_nodes/SHD_sepcombRGB.c new file mode 100644 index 00000000000..2b52a8e2229 --- /dev/null +++ b/source/blender/nodes/intern/SHD_nodes/SHD_sepcombRGB.c @@ -0,0 +1,105 @@ +/** + * + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Juho Vepsäläinen + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../SHD_util.h" + +/* **************** SEPARATE RGBA ******************** */ +static bNodeSocketType sh_node_seprgb_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType sh_node_seprgb_out[]= { + { SOCK_VALUE, 0, "R", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "G", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "B", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_shader_exec_seprgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + out[0]->vec[0] = in[0]->vec[0]; + out[1]->vec[0] = in[0]->vec[1]; + out[2]->vec[0] = in[0]->vec[2]; +} + +bNodeType sh_node_seprgb= { + /* *next,*prev */ NULL, NULL, + /* type code */ SH_NODE_SEPRGB, + /* name */ "Separate RGB", + /* width+range */ 80, 40, 140, + /* class+opts */ NODE_CLASS_CONVERTOR, 0, + /* input sock */ sh_node_seprgb_in, + /* output sock */ sh_node_seprgb_out, + /* storage */ "", + /* execfunc */ node_shader_exec_seprgb, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; + + +/* **************** COMBINE RGB ******************** */ +static bNodeSocketType sh_node_combrgb_in[]= { + { SOCK_VALUE, 1, "R", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "G", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "B", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType sh_node_combrgb_out[]= { + { SOCK_RGBA, 0, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_shader_exec_combrgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + out[0]->vec[0] = in[0]->vec[0]; + out[0]->vec[1] = in[1]->vec[0]; + out[0]->vec[2] = in[2]->vec[0]; +} + +bNodeType sh_node_combrgb= { + /* *next,*prev */ NULL, NULL, + /* type code */ SH_NODE_COMBRGB, + /* name */ "Combine RGB", + /* width+range */ 80, 40, 140, + /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS, + /* input sock */ sh_node_combrgb_in, + /* output sock */ sh_node_combrgb_out, + /* storage */ "", + /* execfunc */ node_shader_exec_combrgb, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_squeeze.c b/source/blender/nodes/intern/SHD_nodes/SHD_squeeze.c new file mode 100644 index 00000000000..30abad666c4 --- /dev/null +++ b/source/blender/nodes/intern/SHD_nodes/SHD_squeeze.c @@ -0,0 +1,73 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../SHD_util.h" + +/* **************** VALUE SQUEEZE ******************** */ +static bNodeSocketType sh_node_squeeze_in[]= { + { SOCK_VALUE, 1, "Value", 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f}, + { SOCK_VALUE, 1, "Width", 1.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f}, + { SOCK_VALUE, 1, "Center", 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f}, + { -1, 0, "" } +}; + +static bNodeSocketType sh_node_squeeze_out[]= { + { SOCK_VALUE, 0, "Value", 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_shader_exec_squeeze(void *data, bNode *node, bNodeStack **in, +bNodeStack **out) +{ + float vec[3]; + + nodestack_get_vec(vec, SOCK_VALUE, in[0]); + nodestack_get_vec(vec+1, SOCK_VALUE, in[1]); + nodestack_get_vec(vec+2, SOCK_VALUE, in[2]); + + out[0]->vec[0] = 1.0f / (1.0f + pow(2.71828183,-((vec[0]-vec[2])*vec[1]))) ; +} + +bNodeType sh_node_squeeze= { + /* *next,*prev */ NULL, NULL, + /* type code */ SH_NODE_SQUEEZE, + /* name */ "Squeeze Value", + /* width+range */ 120, 110, 160, + /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS, + /* input sock */ sh_node_squeeze_in, + /* output sock */ sh_node_squeeze_out, + /* storage */ "node_squeeze", + /* execfunc */ node_shader_exec_squeeze, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; + diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_texture.c b/source/blender/nodes/intern/SHD_nodes/SHD_texture.c new file mode 100644 index 00000000000..ace11a20d42 --- /dev/null +++ b/source/blender/nodes/intern/SHD_nodes/SHD_texture.c @@ -0,0 +1,130 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../SHD_util.h" + +/* **************** TEXTURE ******************** */ +static bNodeSocketType sh_node_texture_in[]= { + { SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, /* no limit */ + { -1, 0, "" } +}; +static bNodeSocketType sh_node_texture_out[]= { + { SOCK_VALUE, 0, "Value", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_RGBA , 0, "Color", 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_shader_exec_texture(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + if(data && node->id) { + ShadeInput *shi= ((ShaderCallData *)data)->shi; + TexResult texres; + float vec[3], nor[3]={0.0f, 0.0f, 0.0f}; + int retval; + + /* out: value, color, normal */ + + /* we should find out if a normal as output is needed, for now we do all */ + texres.nor= nor; + + if(in[0]->hasinput) { + nodestack_get_vec(vec, SOCK_VECTOR, in[0]); + + if(in[0]->datatype==NS_OSA_VECTORS) { + float *fp= in[0]->data; + retval= multitex_ext((Tex *)node->id, vec, fp, fp+3, shi->osatex, &texres); + } + else if(in[0]->datatype==NS_OSA_VALUES) { + float *fp= in[0]->data; + float dxt[3], dyt[3]; + + dxt[0]= fp[0]; dxt[1]= dxt[2]= 0.0f; + dyt[0]= fp[1]; dyt[1]= dyt[2]= 0.0f; + retval= multitex_ext((Tex *)node->id, vec, dxt, dyt, shi->osatex, &texres); + } + else + retval= multitex_ext((Tex *)node->id, vec, NULL, NULL, 0, &texres); + } + else { /* only for previewrender, so we see stuff */ + VECCOPY(vec, shi->lo); + retval= multitex_ext((Tex *)node->id, vec, NULL, NULL, 0, &texres); + } + + /* stupid exception */ + if( ((Tex *)node->id)->type==TEX_STUCCI) { + texres.tin= 0.5f + 0.7f*texres.nor[0]; + CLAMP(texres.tin, 0.0f, 1.0f); + } + + /* intensity and color need some handling */ + if(texres.talpha) + out[0]->vec[0]= texres.ta; + else + out[0]->vec[0]= texres.tin; + + if((retval & TEX_RGB)==0) { + out[1]->vec[0]= out[0]->vec[0]; + out[1]->vec[1]= out[0]->vec[0]; + out[1]->vec[2]= out[0]->vec[0]; + out[1]->vec[3]= 1.0f; + } + else { + out[1]->vec[0]= texres.tr; + out[1]->vec[1]= texres.tg; + out[1]->vec[2]= texres.tb; + out[1]->vec[3]= 1.0f; + } + + VECCOPY(out[2]->vec, nor); + + if(shi->do_preview) + nodeAddToPreview(node, out[1]->vec, shi->xs, shi->ys); + + } +} + +bNodeType sh_node_texture= { + /* *next,*prev */ NULL, NULL, + /* type code */ SH_NODE_TEXTURE, + /* name */ "Texture", + /* width+range */ 120, 80, 240, + /* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS|NODE_PREVIEW, + /* input sock */ sh_node_texture_in, + /* output sock */ sh_node_texture_out, + /* storage */ "", + /* execfunc */ node_shader_exec_texture, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; + diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_valToRgb.c b/source/blender/nodes/intern/SHD_nodes/SHD_valToRgb.c new file mode 100644 index 00000000000..cf7e33d9dca --- /dev/null +++ b/source/blender/nodes/intern/SHD_nodes/SHD_valToRgb.c @@ -0,0 +1,116 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../SHD_util.h" + +/* **************** VALTORGB ******************** */ +static bNodeSocketType sh_node_valtorgb_in[]= { + { SOCK_VALUE, 1, "Fac", 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType sh_node_valtorgb_out[]= { + { SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_shader_exec_valtorgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order in: fac */ + /* stack order out: col, alpha */ + + if(node->storage) { + float fac; + nodestack_get_vec(&fac, SOCK_VALUE, in[0]); + + do_colorband(node->storage, fac, out[0]->vec); + out[1]->vec[0]= out[0]->vec[3]; + } +} + +static void node_shader_init_valtorgb(bNode *node) +{ + node->storage= add_colorband(1); +} + +bNodeType sh_node_valtorgb= { + /* *next,*prev */ NULL, NULL, + /* type code */ SH_NODE_VALTORGB, + /* name */ "ColorRamp", + /* width+range */ 240, 200, 300, + /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS, + /* input sock */ sh_node_valtorgb_in, + /* output sock */ sh_node_valtorgb_out, + /* storage */ "ColorBand", + /* execfunc */ node_shader_exec_valtorgb, + /* butfunc */ NULL, + /* initfunc */ node_shader_init_valtorgb, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL + +}; + +/* **************** RGBTOBW ******************** */ +static bNodeSocketType sh_node_rgbtobw_in[]= { + { SOCK_RGBA, 1, "Color", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType sh_node_rgbtobw_out[]= { + { SOCK_VALUE, 0, "Val", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + + +static void node_shader_exec_rgbtobw(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order out: bw */ + /* stack order in: col */ + + out[0]->vec[0]= in[0]->vec[0]*0.35f + in[0]->vec[1]*0.45f + in[0]->vec[2]*0.2f; +} + +bNodeType sh_node_rgbtobw= { + /* *next,*prev */ NULL, NULL, + /* type code */ SH_NODE_RGBTOBW, + /* name */ "RGB to BW", + /* width+range */ 80, 40, 120, + /* class+opts */ NODE_CLASS_CONVERTOR, 0, + /* input sock */ sh_node_rgbtobw_in, + /* output sock */ sh_node_rgbtobw_out, + /* storage */ "", + /* execfunc */ node_shader_exec_rgbtobw, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; + diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_value.c b/source/blender/nodes/intern/SHD_nodes/SHD_value.c new file mode 100644 index 00000000000..57ef7226066 --- /dev/null +++ b/source/blender/nodes/intern/SHD_nodes/SHD_value.c @@ -0,0 +1,64 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../SHD_util.h" + +/* **************** VALUE ******************** */ +static bNodeSocketType sh_node_value_out[]= { + { SOCK_VALUE, 0, "Value", 0.5f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f}, + { -1, 0, "" } +}; + +static void node_shader_exec_value(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + bNodeSocket *sock= node->outputs.first; + + out[0]->vec[0]= sock->ns.vec[0]; +} + + + +bNodeType sh_node_value= { + /* *next,*prev */ NULL, NULL, + /* type code */ SH_NODE_VALUE, + /* name */ "Value", + /* width+range */ 80, 50, 120, + /* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS, + /* input sock */ NULL, + /* output sock */ sh_node_value_out, + /* storage */ "", + /* execfunc */ node_shader_exec_value, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; + diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_vectMath.c b/source/blender/nodes/intern/SHD_nodes/SHD_vectMath.c new file mode 100644 index 00000000000..8d0a4b3abe3 --- /dev/null +++ b/source/blender/nodes/intern/SHD_nodes/SHD_vectMath.c @@ -0,0 +1,118 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + + +#include "../SHD_util.h" + + +/* **************** VECTOR MATH ******************** */ +static bNodeSocketType sh_node_vect_math_in[]= { + { SOCK_VECTOR, 1, "Vector", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f}, + { SOCK_VECTOR, 1, "Vector", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static bNodeSocketType sh_node_vect_math_out[]= { + { SOCK_VECTOR, 0, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "Value", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_shader_exec_vect_math(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + float vec1[3], vec2[3]; + + nodestack_get_vec(vec1, SOCK_VECTOR, in[0]); + nodestack_get_vec(vec2, SOCK_VECTOR, in[1]); + + if(node->custom1 == 0) { /* Add */ + out[0]->vec[0]= vec1[0] + vec2[0]; + out[0]->vec[1]= vec1[1] + vec2[1]; + out[0]->vec[2]= vec1[2] + vec2[2]; + + out[1]->vec[0]= (fabs(out[0]->vec[0]) + fabs(out[0]->vec[0]) + fabs(out[0]->vec[0])) / 3; + } + else if(node->custom1 == 1) { /* Subtract */ + out[0]->vec[0]= vec1[0] - vec2[0]; + out[0]->vec[1]= vec1[1] - vec2[1]; + out[0]->vec[2]= vec1[2] - vec2[2]; + + out[1]->vec[0]= (fabs(out[0]->vec[0]) + fabs(out[0]->vec[0]) + fabs(out[0]->vec[0])) / 3; + } + else if(node->custom1 == 2) { /* Average */ + out[0]->vec[0]= vec1[0] + vec2[0]; + out[0]->vec[1]= vec1[1] + vec2[1]; + out[0]->vec[2]= vec1[2] + vec2[2]; + + out[1]->vec[0] = Normalize( out[0]->vec ); + } + else if(node->custom1 == 3) { /* Dot product */ + out[1]->vec[0]= (vec1[0] * vec2[0]) + (vec1[1] * vec2[1]) + (vec1[2] * vec2[2]); + } + else if(node->custom1 == 4) { /* Cross product */ + out[0]->vec[0]= (vec1[1] * vec2[2]) - (vec1[2] * vec2[1]); + out[0]->vec[1]= (vec1[2] * vec2[0]) - (vec1[0] * vec2[2]); + out[0]->vec[2]= (vec1[0] * vec2[1]) - (vec1[1] * vec2[0]); + + out[1]->vec[0] = Normalize( out[0]->vec ); + } + else if(node->custom1 == 5) { /* Normalize */ + if(in[0]->hasinput || !in[1]->hasinput) { /* This one only takes one input, so we've got to choose. */ + out[0]->vec[0]= vec1[0]; + out[0]->vec[1]= vec1[1]; + out[0]->vec[2]= vec1[2]; + } + else { + out[0]->vec[0]= vec2[0]; + out[0]->vec[1]= vec2[1]; + out[0]->vec[2]= vec2[2]; + } + + out[1]->vec[0] = Normalize( out[0]->vec ); + } + +} + +bNodeType sh_node_vect_math= { + /* *next,*prev */ NULL, NULL, + /* type code */ SH_NODE_VECT_MATH, + /* name */ "Vector Math", + /* width+range */ 80, 75, 140, + /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS, + /* input sock */ sh_node_vect_math_in, + /* output sock */ sh_node_vect_math_out, + /* storage */ "node_vect_math", + /* execfunc */ node_shader_exec_vect_math, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; + diff --git a/source/blender/nodes/intern/SHD_util.c b/source/blender/nodes/intern/SHD_util.c new file mode 100644 index 00000000000..c9f58fbce49 --- /dev/null +++ b/source/blender/nodes/intern/SHD_util.c @@ -0,0 +1,208 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "SHD_util.h" + + + + + +/* ****** */ + +void nodestack_get_vec(float *in, short type_in, bNodeStack *ns) +{ + float *from= ns->vec; + + if(type_in==SOCK_VALUE) { + if(ns->sockettype==SOCK_VALUE) + *in= *from; + else + *in= 0.333333f*(from[0]+from[1]+from[2]); + } + else if(type_in==SOCK_VECTOR) { + if(ns->sockettype==SOCK_VALUE) { + in[0]= from[0]; + in[1]= from[0]; + in[2]= from[0]; + } + else { + VECCOPY(in, from); + } + } + else { /* type_in==SOCK_RGBA */ + if(ns->sockettype==SOCK_RGBA) { + QUATCOPY(in, from); + } + else if(ns->sockettype==SOCK_VALUE) { + in[0]= from[0]; + in[1]= from[0]; + in[2]= from[0]; + in[3]= 1.0f; + } + else { + VECCOPY(in, from); + in[3]= 1.0f; + } + } +} + + +/* ******************* execute and parse ************ */ + +void ntreeShaderExecTree(bNodeTree *ntree, ShadeInput *shi, ShadeResult *shr) +{ + ShaderCallData scd; + + /* convert caller data to struct */ + scd.shi= shi; + scd.shr= shr; + /* each material node has own local shaderesult, with optional copying */ + memset(shr, 0, sizeof(ShadeResult)); + + ntreeExecTree(ntree, &scd, shi->thread); /* threads */ + + /* better not allow negative for now */ + if(shr->combined[0]<0.0f) shr->combined[0]= 0.0f; + if(shr->combined[1]<0.0f) shr->combined[1]= 0.0f; + if(shr->combined[2]<0.0f) shr->combined[2]= 0.0f; + +} + +/* go over all used Geometry and Texture nodes, and return a texco flag */ +/* no group inside needed, this function is called for groups too */ +void ntreeShaderGetTexcoMode(bNodeTree *ntree, int r_mode, short *texco, int *mode) +{ + bNode *node; + bNodeSocket *sock; + int a; + + ntreeSocketUseFlags(ntree); + + for(node= ntree->nodes.first; node; node= node->next) { + if(node->type==SH_NODE_TEXTURE) { + if((r_mode & R_OSA) && node->id) { + Tex *tex= (Tex *)node->id; + if ELEM3(tex->type, TEX_IMAGE, TEX_PLUGIN, TEX_ENVMAP) + *texco |= TEXCO_OSA|NEED_UV; + } + /* usability exception... without input we still give the node orcos */ + sock= node->inputs.first; + if(sock==NULL || sock->link==NULL) + *texco |= TEXCO_ORCO|NEED_UV; + } + else if(node->type==SH_NODE_GEOMETRY) { + /* note; sockets always exist for the given type! */ + for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) { + if(sock->flag & SOCK_IN_USE) { + switch(a) { + case GEOM_OUT_GLOB: + *texco |= TEXCO_GLOB|NEED_UV; break; + case GEOM_OUT_VIEW: + *texco |= TEXCO_VIEW|NEED_UV; break; + case GEOM_OUT_ORCO: + *texco |= TEXCO_ORCO|NEED_UV; break; + case GEOM_OUT_UV: + *texco |= TEXCO_UV|NEED_UV; break; + case GEOM_OUT_NORMAL: + *texco |= TEXCO_NORM|NEED_UV; break; + case GEOM_OUT_VCOL: + *texco |= NEED_UV; *mode |= MA_VERTEXCOL; break; + } + } + } + } + } +} + +/* nodes that use ID data get synced with local data */ +void nodeShaderSynchronizeID(bNode *node, int copyto) +{ + if(node->id==NULL) return; + + if(ELEM(node->type, SH_NODE_MATERIAL, SH_NODE_MATERIAL_EXT)) { + bNodeSocket *sock; + Material *ma= (Material *)node->id; + int a; + + /* hrmf, case in loop isnt super fast, but we dont edit 100s of material at same time either! */ + for(a=0, sock= node->inputs.first; sock; sock= sock->next, a++) { + if(!(sock->flag & SOCK_HIDDEN)) { + if(copyto) { + switch(a) { + case MAT_IN_COLOR: + VECCOPY(&ma->r, sock->ns.vec); break; + case MAT_IN_SPEC: + VECCOPY(&ma->specr, sock->ns.vec); break; + case MAT_IN_REFL: + ma->ref= sock->ns.vec[0]; break; + case MAT_IN_MIR: + VECCOPY(&ma->mirr, sock->ns.vec); break; + case MAT_IN_AMB: + VECCOPY(&ma->ambr, sock->ns.vec); break; + case MAT_IN_EMIT: + ma->emit= sock->ns.vec[0]; break; + case MAT_IN_SPECTRA: + ma->spectra= sock->ns.vec[0]; break; + case MAT_IN_RAY_MIRROR: + ma->ray_mirror= sock->ns.vec[0]; break; + case MAT_IN_ALPHA: + ma->alpha= sock->ns.vec[0]; break; + case MAT_IN_TRANSLUCENCY: + ma->translucency= sock->ns.vec[0]; break; + } + } + else { + switch(a) { + case MAT_IN_COLOR: + VECCOPY(sock->ns.vec, &ma->r); break; + case MAT_IN_SPEC: + VECCOPY(sock->ns.vec, &ma->specr); break; + case MAT_IN_REFL: + sock->ns.vec[0]= ma->ref; break; + case MAT_IN_MIR: + VECCOPY(sock->ns.vec, &ma->mirr); break; + case MAT_IN_AMB: + VECCOPY(sock->ns.vec, &ma->ambr); break; + case MAT_IN_EMIT: + sock->ns.vec[0]= ma->emit; break; + case MAT_IN_SPECTRA: + sock->ns.vec[0]= ma->spectra; break; + case MAT_IN_RAY_MIRROR: + sock->ns.vec[0]= ma->ray_mirror; break; + case MAT_IN_ALPHA: + sock->ns.vec[0]= ma->alpha; break; + case MAT_IN_TRANSLUCENCY: + sock->ns.vec[0]= ma->translucency; break; + } + } + } + } + } + +} diff --git a/source/blender/nodes/intern/SHD_util.h b/source/blender/nodes/intern/SHD_util.h new file mode 100644 index 00000000000..f75802b7c15 --- /dev/null +++ b/source/blender/nodes/intern/SHD_util.h @@ -0,0 +1,140 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef SHD_NODE_UTIL_H_ +#define SHD_NODE_UTIL_H_ + +#include +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_action_types.h" +#include "DNA_color_types.h" +#include "DNA_ipo_types.h" +#include "DNA_ID.h" +#include "DNA_image_types.h" +#include "DNA_material_types.h" +#include "DNA_node_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_space_types.h" +#include "DNA_screen_types.h" +#include "DNA_texture_types.h" +#include "DNA_userdef_types.h" + +#include "BKE_blender.h" +#include "BKE_colortools.h" +#include "BKE_global.h" +#include "BKE_image.h" +#include "BKE_main.h" +#include "BKE_material.h" +#include "BKE_texture.h" +#include "BKE_utildefines.h" +#include "BKE_library.h" + +#include "../SHD_node.h" +#include "node_util.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" +#include "BIF_interface.h" +#include "BIF_interface_icons.h" +#include "BIF_language.h" +#include "BIF_mywindow.h" +#include "BIF_previewrender.h" +#include "BIF_resources.h" +#include "BIF_screen.h" +#include "BIF_space.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" +#include "BLI_rand.h" +#include "BLI_threads.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "BSE_drawipo.h" +#include "BSE_node.h" +#include "BSE_view.h" + +#include "RE_pipeline.h" +#include "RE_shader_ext.h" + +#include "butspace.h" +#include "blendef.h" +#include "mydevice.h" + + +/* ********* exec data struct, remains internal *********** */ + +typedef struct ShaderCallData { + ShadeInput *shi; /* from render pipe */ + ShadeResult *shr; /* from render pipe */ +} ShaderCallData; + +/* output socket defines */ +#define GEOM_OUT_GLOB 0 +#define GEOM_OUT_LOCAL 1 +#define GEOM_OUT_VIEW 2 +#define GEOM_OUT_ORCO 3 +#define GEOM_OUT_UV 4 +#define GEOM_OUT_NORMAL 5 +#define GEOM_OUT_VCOL 6 +#define GEOM_OUT_FRONTBACK 7 + + +/* input socket defines */ +#define MAT_IN_COLOR 0 +#define MAT_IN_SPEC 1 +#define MAT_IN_REFL 2 +#define MAT_IN_NORMAL 3 +#define MAT_IN_MIR 4 +#define MAT_IN_AMBCOL 5 +#define MAT_IN_AMB 6 +#define MAT_IN_EMIT 7 +#define MAT_IN_SPECTRA 8 +#define MAT_IN_RAY_MIRROR 9 +#define MAT_IN_ALPHA 10 +#define MAT_IN_TRANSLUCENCY 11 + +/* output socket defines */ +#define MAT_OUT_COLOR 0 +#define MAT_OUT_ALPHA 1 +#define MAT_OUT_NORMAL 2 +#define MAT_OUT_DIFFUSE 3 +#define MAT_OUT_SPEC 4 +#define MAT_OUT_AO 5 + + +extern void node_ID_title_cb(void *node_v, void *unused_v); +void nodestack_get_vec(float *in, short type_in, bNodeStack *ns); + +#endif diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c new file mode 100644 index 00000000000..4fb74911482 --- /dev/null +++ b/source/blender/nodes/intern/node_util.c @@ -0,0 +1,52 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2007 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Nathan Letwory. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "CMP_util.h" +#include "SHD_util.h" + +void node_free_curves(bNode *node) +{ + curvemapping_free(node->storage); +} + +void node_free_standard_storage(bNode *node) +{ + MEM_freeN(node->storage); +} + +void node_copy_curves(bNode *orig_node, bNode *new_node) +{ + new_node->storage= curvemapping_copy(orig_node->storage); +} + +void node_copy_standard_storage(bNode *orig_node, bNode *new_node) +{ + new_node->storage= MEM_dupallocN(orig_node->storage); +} + diff --git a/source/blender/nodes/intern/node_util.h b/source/blender/nodes/intern/node_util.h new file mode 100644 index 00000000000..5c8ed19a8d1 --- /dev/null +++ b/source/blender/nodes/intern/node_util.h @@ -0,0 +1,42 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2007 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Nathan Letwory. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef NODE_UTIL_H_ +#define NODE_UTIL_H_ + +#include "MEM_guardedalloc.h" + +extern void node_free_curves(struct bNode *node); +extern void node_free_standard_storage(struct bNode *node); + +extern void node_copy_curves(struct bNode *orig_node, struct bNode *new_node); +extern void node_copy_standard_storage(struct bNode *orig_node, struct bNode *new_node); + +#endif + diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h new file mode 100644 index 00000000000..e4986727ab1 --- /dev/null +++ b/source/blender/python/BPY_extern.h @@ -0,0 +1,136 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code was in: source/blender/bpython/include/BPY_extern.h + * + * Contributor(s): Michel Selten, Willian P. Germano, Chris Keith + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BPY_EXTERN_H +#define BPY_EXTERN_H + +extern char bprogname[]; /* holds a copy of argv[0], from creator.c */ + +struct Text; /* defined in DNA_text_types.h */ +struct ID; /* DNA_ID.h */ +struct Object; /* DNA_object_types.h */ +struct IpoDriver; /* DNA_curve_types.h */ +struct ScriptLink; /* DNA_scriptlink_types.h */ +struct ListBase; /* DNA_listBase.h */ +struct SpaceText; /* DNA_space_types.h */ +struct SpaceScript; /* DNA_space_types.h */ +struct Script; /* BPI_script.h */ +struct ScrArea; /* DNA_screen_types.h */ +struct bScreen; /* DNA_screen_types.h */ +struct bConstraint; /* DNA_constraint_types.h */ +struct bPythonConstraint; /* DNA_constraint_types.h */ +struct bConstraintOb; /* DNA_constraint_types.h */ +struct bConstraintTarget; /* DNA_constraint_types.h*/ +#ifdef __cplusplus +extern "C" { +#endif + + /*These two next functions are important for making sure the Draw module + works correctly. Before calling any gui callback using the Draw module, + the following code must be executed: + + if (some_drawspace_pylist) { + BPy_Set_DrawButtonsList(some_drawspace_pylist->but_refs); + BPy_Free_DrawButtonsList(); + } + some_drawspace_pylist = PyList_New(0); + BPy_Set_DrawButtonsList(some_drawspace_pylist); + + Also, BPy_Free_DrawButtonsList() must be called as necassary when a drawspace + with python callbacks is destroyed. + + This is necassary to avoid blender buttons storing invalid pointers to freed + python data.*/ + void BPy_Set_DrawButtonsList(void *list); + void BPy_Free_DrawButtonsList(void); + + void BPY_pyconstraint_eval(struct bPythonConstraint *con, struct bConstraintOb *cob, struct ListBase *targets); + void BPY_pyconstraint_settings(void *arg1, void *arg2); + void BPY_pyconstraint_target(struct bPythonConstraint *con, struct bConstraintTarget *ct); + void BPY_pyconstraint_update(struct Object *owner, struct bConstraint *con); + int BPY_is_pyconstraint(struct Text *text); + + void BPY_start_python( int argc, char **argv ); + void BPY_end_python( void ); + void BPY_post_start_python( void ); + void init_syspath( int first_time ); + void syspath_append( char *dir ); + + int BPY_Err_getLinenumber( void ); + const char *BPY_Err_getFilename( void ); + + int BPY_txt_do_python_Text( struct Text *text ); + int BPY_menu_do_python( short menutype, int event ); + void BPY_run_python_script( char *filename ); + void BPY_free_compiled_text( struct Text *text ); + + void BPY_clear_bad_scriptlinks( struct Text *byebye ); + int BPY_has_onload_script( void ); + void BPY_do_all_scripts( short event ); + int BPY_check_all_scriptlinks( struct Text *text ); + void BPY_do_pyscript( struct ID *id, short event ); + void BPY_free_scriptlink( struct ScriptLink *slink ); + void BPY_copy_scriptlink( struct ScriptLink *scriptlink ); + + int BPY_is_spacehandler(struct Text *text, char spacetype); + int BPY_del_spacehandler(struct Text *text, struct ScrArea *sa); + int BPY_add_spacehandler(struct Text *txt, struct ScrArea *sa,char spacetype); + int BPY_has_spacehandler(struct Text *text, struct ScrArea *sa); + void BPY_screen_free_spacehandlers(struct bScreen *sc); + int BPY_do_spacehandlers(struct ScrArea *sa, unsigned short event, + unsigned short space_event); + + void BPY_pydriver_update(void); + float BPY_pydriver_eval(struct IpoDriver *driver); + struct Object **BPY_pydriver_get_objects(struct IpoDriver *driver); + + int BPY_button_eval(char *expr, double *value); + +/* format importer hook */ + int BPY_call_importloader( char *name ); + + void BPY_spacescript_do_pywin_draw( struct SpaceScript *sc ); + void BPY_spacescript_do_pywin_event( struct SpaceScript *sc, + unsigned short event, short val, char ascii ); + void BPY_clear_script( struct Script *script ); + void BPY_free_finished_script( struct Script *script ); + +/* void BPY_Err_Handle(struct Text *text); */ +/* void BPY_clear_bad_scriptlink(struct ID *id, struct Text *byebye); */ +/* void BPY_clear_bad_scriptlist(struct ListBase *, struct Text *byebye); */ +/* int BPY_spacetext_is_pywin(struct SpaceText *st); */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* BPY_EXTERN_H */ diff --git a/source/blender/python/BPY_interface.c b/source/blender/python/BPY_interface.c new file mode 100644 index 00000000000..9c8203cf3fd --- /dev/null +++ b/source/blender/python/BPY_interface.c @@ -0,0 +1,2663 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Michel Selten, Willian P. Germano, Stephen Swaney, + * Chris Keith, Chris Want, Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#include + +#include "compile.h" /* for the PyCodeObject */ +#include "eval.h" /* for PyEval_EvalCode */ +#include "BLI_blenlib.h" /* for BLI_last_slash() */ +#include "BIF_interface.h" /* for pupmenu() */ +#include "BIF_space.h" +#include "BIF_screen.h" +#include "BIF_toolbox.h" +#include "BKE_action.h" /* for get_pose_channel() */ +#include "BKE_library.h" +#include "BKE_object.h" /* during_scriptlink() */ +#include "BKE_text.h" +#include "BKE_constraint.h" /* for bConstraintOb */ +#include "BKE_idprop.h" + +#include "DNA_curve_types.h" /* for struct IpoDriver */ +#include "DNA_ID.h" /* ipo driver */ +#include "DNA_object_types.h" /* ipo driver */ +#include "DNA_constraint_types.h" /* for pyconstraint */ + +#include "DNA_screen_types.h" +#include "DNA_userdef_types.h" /* for U.pythondir */ +#include "MEM_guardedalloc.h" +#include "BPY_extern.h" +#include "BPY_menus.h" +#include "BPI_script.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_armature.h" +#include "api2_2x/EXPP_interface.h" +#include "api2_2x/constant.h" +#include "api2_2x/gen_utils.h" +#include "api2_2x/gen_library.h" /* GetPyObjectFromID */ +#include "api2_2x/BGL.h" +#include "api2_2x/Blender.h" +#include "api2_2x/Camera.h" +#include "api2_2x/Draw.h" +#include "api2_2x/Object.h" +#include "api2_2x/Registry.h" +#include "api2_2x/Pose.h" +#include "api2_2x/bpy.h" /* for the new "bpy" module */ + +/*these next two are for pyconstraints*/ +#include "api2_2x/IDProp.h" +#include "api2_2x/matrix.h" + +/* for scriptlinks */ +#include "DNA_lamp_types.h" +#include "DNA_camera_types.h" +#include "DNA_world_types.h" +#include "DNA_scene_types.h" +#include "DNA_material_types.h" + +/* bpy_registryDict is declared in api2_2x/Registry.h and defined + * in api2_2x/Registry.c + * This Python dictionary will be used to store data that scripts + * choose to preserve after they are executed, so user changes can be + * restored next time the script is used. Check the Blender.Registry module. + */ +/*#include "api2_2x/Registry.h" */ + +/* for pydrivers (ipo drivers defined by one-line Python expressions) */ +PyObject *bpy_pydriver_Dict = NULL; + +/* + * set up a weakref list for Armatures + * creates list in __main__ module dict + */ + +int setup_armature_weakrefs() +{ + PyObject *maindict; + PyObject *main_module; + char *list_name = ARM_WEAKREF_LIST_NAME; + + main_module = PyImport_AddModule( "__main__"); + if(main_module){ + PyObject *weakreflink; + maindict= PyModule_GetDict(main_module); + + /* check if there is already a dict entry for the armature weakrefs, + * and delete if so before making another one */ + + weakreflink= PyDict_GetItemString(maindict,list_name); + if( weakreflink != NULL ) { + PyDict_DelItemString(maindict,list_name); + Py_XDECREF( weakreflink ); + } + + if (PyDict_SetItemString(maindict, + list_name, + PyList_New(0)) == -1){ + printf("Oops - setup_armature_weakrefs()\n"); + + return 0; + } + } + return 1; +} + +/* Declares the modules and their initialization functions + * These are TOP-LEVEL modules e.g. import `module` - there is no + * support for packages here e.g. import `package.module` */ + +static struct _inittab BPy_Inittab_Modules[] = { + {"Blender", M_Blender_Init}, + {"bpy", m_bpy_init}, + {NULL, NULL} +}; + +/************************************************************************* +* Structure definitions +**************************************************************************/ +#define FILENAME_LENGTH 24 + +typedef struct _ScriptError { + char filename[FILENAME_LENGTH]; + int lineno; +} ScriptError; + +/**************************************************************************** +* Global variables +****************************************************************************/ +ScriptError g_script_error; + +/*************************************************************************** +* Function prototypes +***************************************************************************/ +PyObject *RunPython( Text * text, PyObject * globaldict ); +char *GetName( Text * text ); +PyObject *CreateGlobalDictionary( void ); +void ReleaseGlobalDictionary( PyObject * dict ); +void DoAllScriptsFromList( ListBase * list, short event ); +PyObject *importText( char *name ); +void init_ourImport( void ); +void init_ourReload( void ); +PyObject *blender_import( PyObject * self, PyObject * args ); +PyObject *RunPython2( Text * text, PyObject * globaldict, PyObject *localdict ); + + +void BPY_Err_Handle( char *script_name ); +PyObject *traceback_getFilename( PyObject * tb ); + +/**************************************************************************** +* Description: This function will start the interpreter and load all modules +* as well as search for a python installation. +****************************************************************************/ +void BPY_start_python( int argc, char **argv ) +{ + static int argc_copy = 0; + static char **argv_copy = NULL; + int first_time = argc; + + /* we keep a copy of the values of argc and argv so that the game engine + * can call BPY_start_python(0, NULL) whenever a game ends, without having + * to know argc and argv there (in source/blender/src/space.c) */ + if( first_time ) { + argc_copy = argc; + argv_copy = argv; + } + + //stuff for Registry module + bpy_registryDict = PyDict_New( );/* check comment at start of this file */ + if( !bpy_registryDict ) + printf( "Error: Couldn't create the Registry Python Dictionary!" ); + Py_SetProgramName( "blender" ); + + /* Py_Initialize() will attempt to import the site module and + * print an error if not found. See init_syspath() for the + * rest of our init msgs. + */ + + /* print Python version + * Py_GetVersion() returns a ptr to a static string "9.9.9 (aaaa..." + */ + { + int count = 3; /* a nice default for major.minor. example 2.5 */ + const char *version = Py_GetVersion(); + /* we know a blank is there somewhere! */ + char *blank_ptr = strchr( version, ' '); + if(blank_ptr) + count = blank_ptr - version; + + printf( "Compiled with Python version %.*s.\n", count, version ); + } + + + //Initialize the TOP-LEVEL modules + PyImport_ExtendInittab(BPy_Inittab_Modules); + + //Start the interpreter + Py_Initialize( ); + PySys_SetArgv( argc_copy, argv_copy ); + + //Overrides __import__ + init_ourImport( ); + init_ourReload( ); + + //init a global dictionary + g_blenderdict = NULL; + + //Look for a python installation + init_syspath( first_time ); /* not first_time: some msgs are suppressed */ + + return; +} + +/*****************************************************************************/ +/* Description: This function will terminate the Python interpreter */ +/*****************************************************************************/ +void BPY_end_python( void ) +{ + Script *script = NULL; + + if( bpy_registryDict ) { + Py_DECREF( bpy_registryDict ); + bpy_registryDict = NULL; + } + + if( bpy_pydriver_Dict ) { + Py_DECREF( bpy_pydriver_Dict ); + bpy_pydriver_Dict = NULL; + } + + /* Freeing all scripts here prevents problems with the order in which + * Python is finalized and G.main is freed in exit_usiblender() */ + for (script = G.main->script.first; script; script = script->id.next) { + BPY_clear_script(script); + free_libblock( &G.main->script, script ); + } + + Py_Finalize( ); + + BPyMenu_RemoveAllEntries( ); /* freeing bpymenu mem */ + + /* a script might've opened a .blend file but didn't close it, so: */ + EXPP_Library_Close( ); + + return; +} + +void syspath_append( char *dirname ) +{ + PyObject *mod_sys= NULL, *dict= NULL, *path= NULL, *dir= NULL; + short ok=1; + PyErr_Clear( ); + + dir = Py_BuildValue( "s", dirname ); + + mod_sys = PyImport_ImportModule( "sys" ); /* new ref */ + + if (mod_sys) { + dict = PyModule_GetDict( mod_sys ); /* borrowed ref */ + path = PyDict_GetItemString( dict, "path" ); /* borrowed ref */ + if ( !PyList_Check( path ) ) { + ok = 0; + } + } else { + /* cant get the sys module */ + ok = 0; + } + + if (ok && PyList_Append( path, dir ) != 0) + ok = 0; /* append failed */ + + if( (ok==0) || PyErr_Occurred( ) ) + Py_FatalError( "could import or build sys.path, can't continue" ); + + Py_XDECREF( mod_sys ); +} + +void init_syspath( int first_time ) +{ + PyObject *path; + PyObject *mod, *d; + char *progname; + char execdir[FILE_MAXDIR]; /*defines from DNA_space_types.h */ + + int n; + + path = Py_BuildValue( "s", bprogname ); + + mod = PyImport_ImportModule( "Blender.sys" ); + + if( mod ) { + d = PyModule_GetDict( mod ); + EXPP_dict_set_item_str( d, "progname", path ); + Py_DECREF( mod ); + } else + printf( "Warning: could not set Blender.sys.progname\n" ); + + progname = BLI_last_slash( bprogname ); /* looks for the last dir separator */ + + n = progname - bprogname; + if( n > 0 ) { + strncpy( execdir, bprogname, n ); + if( execdir[n - 1] == '.' ) + n--; /*fix for when run as ./blender */ + execdir[n] = '\0'; + + syspath_append( execdir ); /* append to module search path */ + } else + printf( "Warning: could not determine argv[0] path\n" ); + + /* + attempt to import 'site' module as a check for valid + python install found. + */ + + printf("Checking for installed Python... "); /* appears after msg "Compiled with Python 2.x" */ + mod = PyImport_ImportModule( "site" ); /* new ref */ + + if( mod ) { + printf("got it!\n"); + Py_DECREF( mod ); + } else { /* import 'site' failed */ + PyErr_Clear( ); + if( first_time ) { + printf( "No installed Python found.\n" ); + printf( "Only built-in modules are available. Some scripts may not run.\n" ); + printf( "Continuing happily.\n" ); + } + } + + + /* + * initialize the sys module + * set sys.executable to the Blender exe + */ + + mod = PyImport_ImportModule( "sys" ); /* new ref */ + + if( mod ) { + d = PyModule_GetDict( mod ); /* borrowed ref */ + EXPP_dict_set_item_str( d, "executable", + Py_BuildValue( "s", bprogname ) ); + Py_DECREF( mod ); + } else{ + printf("import of sys module failed\n"); + } +} + +/**************************************************************************** +* Description: This function finishes Python initialization in Blender. + +Because U.pythondir (user defined dir for scripts) isn't +initialized when BPY_start_Python needs to be executed, we +postpone adding U.pythondir to sys.path and also BPyMenus +(mechanism to register scripts in Blender menus) for when +that dir info is available. +****************************************************************************/ +void BPY_post_start_python( void ) +{ + char dirpath[FILE_MAX]; + char *sdir = NULL; + + if(U.pythondir[0] != '\0' ) { + char modpath[FILE_MAX]; + int upyslen = strlen(U.pythondir); + + /* check if user pydir ends with a slash and, if so, remove the slash + * (for eventual implementations of c library's stat function that might + * not like it) */ + if (upyslen > 2) { /* avoids doing anything if dir == '//' */ + char ending = U.pythondir[upyslen - 1]; + + if (ending == '/' || ending == '\\') + U.pythondir[upyslen - 1] = '\0'; + } + + BLI_strncpy(dirpath, U.pythondir, FILE_MAX); + BLI_convertstringcode(dirpath, G.sce, 0); + syspath_append(dirpath); /* append to module search path */ + + BLI_make_file_string("/", modpath, dirpath, "bpymodules"); + if (BLI_exists(modpath)) syspath_append(modpath); + } + + sdir = bpy_gethome(1); + if (sdir) { + + syspath_append(sdir); + + BLI_make_file_string("/", dirpath, sdir, "bpymodules"); + if (BLI_exists(dirpath)) syspath_append(dirpath); + } + + BPyMenu_Init( 0 ); /* get dynamic menus (registered scripts) data */ + + return; +} + +/**************************************************************************** +* Description: This function will return the linenumber on which an error +* has occurred in the Python script. +****************************************************************************/ +int BPY_Err_getLinenumber( void ) +{ + return g_script_error.lineno; +} + +/*****************************************************************************/ +/* Description: This function will return the filename of the python script. */ +/*****************************************************************************/ +const char *BPY_Err_getFilename( void ) +{ + return g_script_error.filename; +} + +/*****************************************************************************/ +/* Description: Return PyString filename from a traceback object */ +/*****************************************************************************/ +PyObject *traceback_getFilename( PyObject * tb ) +{ + PyObject *v = NULL; + +/* co_filename is in f_code, which is in tb_frame, which is in tb */ + + v = PyObject_GetAttrString( tb, "tb_frame" ); + if (v) { + Py_DECREF( v ); + v = PyObject_GetAttrString( v, "f_code" ); + if (v) { + Py_DECREF( v ); + v = PyObject_GetAttrString( v, "co_filename" ); + } + } + + if (v) return v; + else return PyString_FromString("unknown"); +} + +/**************************************************************************** +* Description: Blender Python error handler. This catches the error and +* stores filename and line number in a global +*****************************************************************************/ +void BPY_Err_Handle( char *script_name ) +{ + PyObject *exception, *err, *tb, *v; + + if( !script_name ) { + printf( "Error: script has NULL name\n" ); + return; + } + + PyErr_Fetch( &exception, &err, &tb ); + + if (!script_name) script_name = "untitled"; + //if( !exception && !tb ) { + // printf( "FATAL: spurious exception\n" ); + // return; + //} + + strcpy( g_script_error.filename, script_name ); + + if( exception + && PyErr_GivenExceptionMatches( exception, PyExc_SyntaxError ) ) { + /* no traceback available when SyntaxError */ + PyErr_Restore( exception, err, tb ); /* takes away reference! */ + PyErr_Print( ); + v = PyObject_GetAttrString( err, "lineno" ); + if( v ) { + g_script_error.lineno = PyInt_AsLong( v ); + Py_DECREF( v ); + } else { + g_script_error.lineno = -1; + } + /* this avoids an abort in Python 2.3's garbage collecting: */ + PyErr_Clear( ); + return; + } else { + PyErr_NormalizeException( &exception, &err, &tb ); + PyErr_Restore( exception, err, tb ); /* takes away reference! */ + PyErr_Print( ); + tb = PySys_GetObject( "last_traceback" ); + + if( !tb ) { + printf( "\nCan't get traceback\n" ); + return; + } + + Py_INCREF( tb ); + +/* From old bpython BPY_main.c: + * 'check traceback objects and look for last traceback in the + * same text file. This is used to jump to the line of where the + * error occured. "If the error occured in another text file or module, + * the last frame in the current file is adressed."' + */ + + for(;;) { + v = PyObject_GetAttrString( tb, "tb_next" ); + + if( !v || v == Py_None || + strcmp(PyString_AsString(traceback_getFilename(v)), script_name)) { + break; + } + + Py_DECREF( tb ); + tb = v; + } + + v = PyObject_GetAttrString( tb, "tb_lineno" ); + if (v) { + g_script_error.lineno = PyInt_AsLong(v); + Py_DECREF(v); + } + v = traceback_getFilename( tb ); + if (v) { + strncpy( g_script_error.filename, PyString_AsString( v ), + FILENAME_LENGTH ); + Py_DECREF(v); + } + Py_DECREF( tb ); + } + + return; +} + +/**************************************************************************** +* Description: This function executes the script passed by st. +* Notes: It is called by blender/src/drawtext.c when a Blender user +* presses ALT+PKEY in the script's text window. +*****************************************************************************/ +int BPY_txt_do_python_Text( struct Text *text ) +{ + PyObject *py_dict, *py_result; + BPy_constant *info; + char textname[24]; + Script *script = G.main->script.first; + + if( !text ) + return 0; + + /* check if this text is already running */ + while( script ) { + if( !strcmp( script->id.name + 2, text->id.name + 2 ) ) { + /* if this text is already a running script, + * just move to it: */ + SpaceScript *sc; + newspace( curarea, SPACE_SCRIPT ); + sc = curarea->spacedata.first; + sc->script = script; + return 1; + } + script = script->id.next; + } + + /* Create a new script structure and initialize it: */ + script = alloc_libblock( &G.main->script, ID_SCRIPT, GetName( text ) ); + + if( !script ) { + printf( "couldn't allocate memory for Script struct!" ); + return 0; + } + + /* if in the script Blender.Load(blendfile) is not the last command, + * an error after it will call BPY_Err_Handle below, but the text struct + * will have been deallocated already, so we need to copy its name here. + */ + BLI_strncpy( textname, GetName( text ), + strlen( GetName( text ) ) + 1 ); + + script->id.us = 1; + script->flags = SCRIPT_RUNNING; + script->py_draw = NULL; + script->py_event = NULL; + script->py_button = NULL; + script->py_browsercallback = NULL; + + py_dict = CreateGlobalDictionary( ); + + if( !setup_armature_weakrefs()){ + printf("Oops - weakref dict\n"); + return 0; + } + + script->py_globaldict = py_dict; + + info = ( BPy_constant * ) PyConstant_New( ); + if( info ) { + PyConstant_Insert( info, "name", + PyString_FromString( script->id.name + 2 ) ); + Py_INCREF( Py_None ); + PyConstant_Insert( info, "arg", Py_None ); + EXPP_dict_set_item_str( py_dict, "__script__", + ( PyObject * ) info ); + } + + py_result = RunPython( text, py_dict ); /* Run the script */ + + if( !py_result ) { /* Failed execution of the script */ + + BPY_Err_Handle( textname ); + ReleaseGlobalDictionary( py_dict ); + script->py_globaldict = NULL; + if( G.main->script.first ) + free_libblock( &G.main->script, script ); + + return 0; + } else { + Py_DECREF( py_result ); + script->flags &= ~SCRIPT_RUNNING; + if( !script->flags ) { + ReleaseGlobalDictionary( py_dict ); + script->py_globaldict = NULL; + free_libblock( &G.main->script, script ); + } + } + + return 1; /* normal return */ +} + +/**************************************************************************** +* Description: Called from command line to run a Python script +* automatically. The script can be a file or a Blender Text in the current +* .blend. +****************************************************************************/ +void BPY_run_python_script( char *fn ) +{ + Text *text = NULL; + int is_blender_text = 0; + + if (!BLI_exists(fn)) { /* if there's no such filename ... */ + text = G.main->text.first; /* try an already existing Blender Text */ + + while (text) { + if (!strcmp(fn, text->id.name + 2)) break; + text = text->id.next; + } + + if (text == NULL) { + printf("\nError: no such file or Blender text -- %s.\n", fn); + return; + } + else is_blender_text = 1; /* fn is already a Blender Text */ + } + + else { + text = add_text(fn); + + if (text == NULL) { + printf("\nError in BPY_run_python_script:\n" + "couldn't create Blender text from %s\n", fn); + /* Chris: On Windows if I continue I just get a segmentation + * violation. To get a baseline file I exit here. */ + exit(2); + /* return; */ + } + } + + if (BPY_txt_do_python_Text(text) != 1) { + printf("\nError executing Python script from command-line:\n" + "%s (at line %d).\n", fn, BPY_Err_getLinenumber()); + } + + if (!is_blender_text) { + /* We can't simply free the text, since the script might have called + * Blender.Load() to load a new .blend, freeing previous data. + * So we check if the pointer is still valid. */ + Text *txtptr = G.main->text.first; + while (txtptr) { + if (txtptr == text) { + free_libblock(&G.main->text, text); + break; + } + txtptr = txtptr->id.next; + } + } +} + +/**************************************************************************** +* Description: This function executes the script chosen from a menu. +* Notes: It is called by the ui code in src/header_???.c when a user +* clicks on a menu entry that refers to a script. +* Scripts are searched in the BPyMenuTable, using the given +* menutype and event values to know which one was chosen. +*****************************************************************************/ +int BPY_menu_do_python( short menutype, int event ) +{ + PyObject *py_dict, *py_res, *pyarg = NULL; + BPy_constant *info; + BPyMenu *pym; + BPySubMenu *pysm; + FILE *fp = NULL; + char *buffer, *s; + char filestr[FILE_MAXDIR + FILE_MAXFILE]; + char scriptname[21]; + Script *script = NULL; + int len; + + pym = BPyMenu_GetEntry( menutype, ( short ) event ); + + if( !pym ) + return 0; + + if( pym->version > G.version ) + notice( "Version mismatch: script was written for Blender %d. " + "It may fail with yours: %d.", pym->version, + G.version ); + +/* if there are submenus, let the user choose one from a pupmenu that we + * create here.*/ + pysm = pym->submenus; + if( pysm ) { + char *pupstr; + int arg; + + pupstr = BPyMenu_CreatePupmenuStr( pym, menutype ); + + if( pupstr ) { + arg = pupmenu( pupstr ); + MEM_freeN( pupstr ); + + if( arg >= 0 ) { + while( arg-- ) + pysm = pysm->next; + pyarg = PyString_FromString( pysm->arg ); + } else + return 0; + } + } + + if( !pyarg ) { /* no submenus */ + Py_INCREF( Py_None ); + pyarg = Py_None; + } + + if( pym->dir ) { /* script is in U.pythondir */ + char upythondir[FILE_MAXDIR]; + + /* dirs in Blender can be "//", which has a special meaning */ + BLI_strncpy(upythondir, U.pythondir, FILE_MAXDIR); + BLI_convertstringcode(upythondir, G.sce, 0); /* if so, this expands it */ + BLI_make_file_string( "/", filestr, upythondir, pym->filename ); + } + else { /* script is in default scripts dir */ + char *scriptsdir = bpy_gethome(1); + + if (!scriptsdir) { + printf("Error loading script: can't find default scripts dir!"); + return 0; + } + + BLI_make_file_string( "/", filestr, scriptsdir, pym->filename ); + } + + fp = fopen( filestr, "rb" ); + if( !fp ) { + printf( "Error loading script: couldn't open file %s\n", + filestr ); + return 0; + } + + BLI_strncpy(scriptname, pym->name, 21); + len = strlen(scriptname) - 1; + /* by convention, scripts that open the file browser or have submenus + * display '...'. Here we remove them from the datablock name */ + while ((len > 0) && scriptname[len] == '.') { + scriptname[len] = '\0'; + len--; + } + + /* Create a new script structure and initialize it: */ + script = alloc_libblock( &G.main->script, ID_SCRIPT, scriptname ); + + if( !script ) { + printf( "couldn't allocate memory for Script struct!" ); + fclose( fp ); + return 0; + } + + /* let's find a proper area for an eventual script gui: + * (still experimenting here, need definition on which win + * each group will be put to code this properly) */ + switch ( menutype ) { + + case PYMENU_IMPORT: /* first 4 were handled in header_info.c */ + case PYMENU_EXPORT: + case PYMENU_HELP: + case PYMENU_RENDER: + case PYMENU_WIZARDS: + case PYMENU_SCRIPTTEMPLATE: + case PYMENU_MESHFACEKEY: + break; + + default: + if( curarea->spacetype != SPACE_SCRIPT ) { + ScrArea *sa = NULL; + + sa = find_biggest_area_of_type( SPACE_BUTS ); + if( sa ) { + if( ( 1.5 * sa->winx ) < sa->winy ) + sa = NULL; /* too narrow? */ + } + + if( !sa ) + sa = find_biggest_area_of_type( SPACE_SCRIPT ); + if( !sa ) + sa = find_biggest_area_of_type( SPACE_TEXT ); + if( !sa ) + sa = find_biggest_area_of_type( SPACE_IMAGE ); /* group UV */ + if( !sa ) + sa = find_biggest_area_of_type( SPACE_VIEW3D ); + + if( !sa ) + sa = find_biggest_area( ); + + areawinset( sa->win ); + } + break; + } + + script->id.us = 1; + script->flags = SCRIPT_RUNNING; + script->py_draw = NULL; + script->py_event = NULL; + script->py_button = NULL; + script->py_browsercallback = NULL; + + py_dict = CreateGlobalDictionary( ); + + script->py_globaldict = py_dict; + + info = ( BPy_constant * ) PyConstant_New( ); + if( info ) { + PyConstant_Insert( info, "name", + PyString_FromString( script->id.name + 2 ) ); + PyConstant_Insert( info, "arg", pyarg ); + EXPP_dict_set_item_str( py_dict, "__script__", + ( PyObject * ) info ); + } + + /* Previously we used PyRun_File to run directly the code on a FILE + * object, but as written in the Python/C API Ref Manual, chapter 2, + * 'FILE structs for different C libraries can be different and + * incompatible'. + * So now we load the script file data to a buffer */ + + fseek( fp, 0L, SEEK_END ); + len = ftell( fp ); + fseek( fp, 0L, SEEK_SET ); + + buffer = MEM_mallocN( len + 2, "pyfilebuf" ); /* len+2 to add '\n\0' */ + len = fread( buffer, 1, len, fp ); + + buffer[len] = '\n'; /* fix syntax error in files w/o eol */ + buffer[len + 1] = '\0'; + + /* fast clean-up of dos cr/lf line endings: change '\r' to space */ + + /* we also have to check for line splitters: '\\' */ + /* to avoid possible syntax errors on dos files on win */ + /**/ + /* but first make sure we won't disturb memory below &buffer[0]: */ + if( *buffer == '\r' ) + *buffer = ' '; + + /* now handle the whole buffer */ + for( s = buffer + 1; *s != '\0'; s++ ) { + if( *s == '\r' ) { + if( *( s - 1 ) == '\\' ) { /* special case: long lines split with '\': */ + *( s - 1 ) = ' '; /* we write ' \', because '\ ' is a syntax error */ + *s = '\\'; + } else + *s = ' '; /* not a split line, just replace '\r' with ' ' */ + } + } + + fclose( fp ); + + + if( !setup_armature_weakrefs()){ + printf("Oops - weakref dict\n"); + MEM_freeN( buffer ); + return 0; + } + + /* run the string buffer */ + + py_res = PyRun_String( buffer, Py_file_input, py_dict, py_dict ); + + MEM_freeN( buffer ); + + if( !py_res ) { /* Failed execution of the script */ + + BPY_Err_Handle( script->id.name + 2 ); + ReleaseGlobalDictionary( py_dict ); + script->py_globaldict = NULL; + if( G.main->script.first ) + free_libblock( &G.main->script, script ); + error( "Python script error: check console" ); + + return 0; + } else { + Py_DECREF( py_res ); + script->flags &= ~SCRIPT_RUNNING; + + if( !script->flags ) { + ReleaseGlobalDictionary( py_dict ); + script->py_globaldict = NULL; + free_libblock( &G.main->script, script ); + + /* special case: called from the menu in the Scripts window + * we have to change sc->script pointer, since it'll be freed here.*/ + if( curarea->spacetype == SPACE_SCRIPT ) { + SpaceScript *sc = curarea->spacedata.first; + sc->script = G.main->script.first; /* can be null, which is ok ... */ + /* ... meaning no other script is running right now. */ + } + + } + } + + return 1; /* normal return */ +} + +/***************************************************************************** +* Description: +* Notes: +*****************************************************************************/ +void BPY_free_compiled_text( struct Text *text ) +{ + if( !text->compiled ) + return; + Py_DECREF( ( PyObject * ) text->compiled ); + text->compiled = NULL; + + return; +} + +/***************************************************************************** +* Description: This function frees a finished (flags == 0) script. +*****************************************************************************/ +void BPY_free_finished_script( Script * script ) +{ + if( !script ) + return; + + if( PyErr_Occurred( ) ) { /* if script ended after filesel */ + PyErr_Print( ); /* eventual errors are handled now */ + error( "Python script error: check console" ); + } + + free_libblock( &G.main->script, script ); + return; +} + +static void unlink_script( Script * script ) +{ /* copied from unlink_text in drawtext.c */ + bScreen *scr; + ScrArea *area; + SpaceLink *sl; + + for( scr = G.main->screen.first; scr; scr = scr->id.next ) { + for( area = scr->areabase.first; area; area = area->next ) { + for( sl = area->spacedata.first; sl; sl = sl->next ) { + if( sl->spacetype == SPACE_SCRIPT ) { + SpaceScript *sc = ( SpaceScript * ) sl; + + if( sc->script == script ) { + sc->script = NULL; + + if( sc == + area->spacedata.first ) { + scrarea_queue_redraw + ( area ); + } + } + } + } + } + } +} + +void BPY_clear_script( Script * script ) +{ + PyObject *dict; + + if( !script ) + return; + + if (!Py_IsInitialized()) { + printf("\nError: trying to free script data after finalizing Python!"); + printf("\nScript name: %s\n", script->id.name+2); + return; + } + + Py_XDECREF( ( PyObject * ) script->py_draw ); + Py_XDECREF( ( PyObject * ) script->py_event ); + Py_XDECREF( ( PyObject * ) script->py_button ); + Py_XDECREF( ( PyObject * ) script->py_browsercallback ); + script->py_draw = NULL; + script->py_event = NULL; + script->py_button = NULL; + script->py_browsercallback = NULL; + + dict = script->py_globaldict; + + if( dict ) { + PyDict_Clear( dict ); + Py_DECREF( dict ); /* Release dictionary. */ + script->py_globaldict = NULL; + } + + unlink_script( script ); +} + +/* PyDrivers */ + +/* PyDrivers are Ipo Drivers governed by expressions written in Python. + * Expressions here are one-liners that evaluate to a float value. */ + +/* For faster execution we keep a special dictionary for pydrivers, with + * the needed modules and aliases. */ +static int bpy_pydriver_create_dict(void) +{ + PyObject *d, *mod; + + if (bpy_pydriver_Dict) return -1; + + d = PyDict_New(); + if (!d) return -1; + + bpy_pydriver_Dict = d; + + /* import some modules: builtins, Blender, math, Blender.noise */ + + PyDict_SetItemString(d, "__builtins__", PyEval_GetBuiltins()); + + mod = PyImport_ImportModule("Blender"); + if (mod) { + PyDict_SetItemString(d, "Blender", mod); + PyDict_SetItemString(d, "b", mod); + Py_DECREF(mod); + } + + mod = PyImport_ImportModule("math"); + if (mod) { + PyDict_SetItemString(d, "math", mod); + PyDict_SetItemString(d, "m", mod); + Py_DECREF(mod); + } + + mod = PyImport_ImportModule("Blender.Noise"); + if (mod) { + PyDict_SetItemString(d, "noise", mod); + PyDict_SetItemString(d, "n", mod); + Py_DECREF(mod); + } + + /* If there's a Blender text called pydrivers.py, import it. + * Users can add their own functions to this module. */ + mod = importText("pydrivers"); /* can also use PyImport_Import() */ + if (mod) { + PyDict_SetItemString(d, "pydrivers", mod); + PyDict_SetItemString(d, "p", mod); + Py_DECREF(mod); + } + else + PyErr_Clear(); + + /* short aliases for some Get() functions: */ + + /* ob(obname) == Blender.Object.Get(obname) */ + mod = PyImport_ImportModule("Blender.Object"); + if (mod) { + PyObject *fcn = PyObject_GetAttrString(mod, "Get"); + Py_DECREF(mod); + if (fcn) { + PyDict_SetItemString(d, "ob", fcn); + Py_DECREF(fcn); + } + } + + /* me(meshname) == Blender.Mesh.Get(meshname) */ + mod = PyImport_ImportModule("Blender.Mesh"); + if (mod) { + PyObject *fcn = PyObject_GetAttrString(mod, "Get"); + Py_DECREF(mod); + if (fcn) { + PyDict_SetItemString(d, "me", fcn); + Py_DECREF(fcn); + } + } + + /* ma(matname) == Blender.Material.Get(matname) */ + mod = PyImport_ImportModule("Blender.Material"); + if (mod) { + PyObject *fcn = PyObject_GetAttrString(mod, "Get"); + Py_DECREF(mod); + if (fcn) { + PyDict_SetItemString(d, "ma", fcn); + Py_DECREF(fcn); + } + } + + return 0; +} + +/* error return function for BPY_eval_pydriver */ +static float pydriver_error(IpoDriver *driver) { + + if (bpy_pydriver_oblist) + bpy_pydriver_freeList(); + + if (bpy_pydriver_Dict) { /* free the global dict used by pydrivers */ + PyDict_Clear(bpy_pydriver_Dict); + Py_DECREF(bpy_pydriver_Dict); + bpy_pydriver_Dict = NULL; + } + + driver->flag |= IPO_DRIVER_FLAG_INVALID; /* py expression failed */ + + if (driver->ob) + fprintf(stderr, "\nError in Ipo Driver: Object %s\nThis is the failed Python expression:\n'%s'\n\n", driver->ob->id.name+2, driver->name); + else + fprintf(stderr, "\nError in Ipo Driver: No Object\nThis is the failed Python expression:\n'%s'\n\n", driver->name); + + PyErr_Print(); + + return 0.0f; +} + + +/********PyConstraints*********/ + +/* This function checks whether a text-buffer is a PyConstraint candidate. + * It uses simple text parsing that could be easily confused! + */ +int BPY_is_pyconstraint(Text *text) +{ + TextLine *tline = text->lines.first; + + if (tline && (tline->len > 10)) { + char *line = tline->line; + + /* Expected format: #BPYCONSTRAINT + * The actual checks are forgiving, so slight variations also work. */ + if (line && line[0] == '#' && strstr(line, "BPYCONSTRAINT")) return 1; + } + return 0; +} + +/* This function is called to update PyConstraint data so that it is compatible with the script. + * Some of the allocating/freeing of memory for constraint targets occurs here, espcially + * if the number of targets changes. + */ +void BPY_pyconstraint_update(Object *owner, bConstraint *con) +{ + bPythonConstraint *data= con->data; + + if (data->text) { + /* script does exist. it is assumed that this is a valid pyconstraint script */ + PyObject *globals; + PyObject *retval, *gval; + int num, i; + + /* clear the relevant flags first */ + data->flag = 0; + + /* populate globals dictionary */ + globals = CreateGlobalDictionary(); + retval = RunPython(data->text, globals); + + if (retval == NULL) { + BPY_Err_Handle(data->text->id.name); + ReleaseGlobalDictionary(globals); + data->flag |= PYCON_SCRIPTERROR; + return; + } + + Py_XDECREF(retval); + retval = NULL; + + /* try to find NUM_TARGETS */ + gval = PyDict_GetItemString(globals, "NUM_TARGETS"); + if ( (gval) && (num= PyInt_AsLong(gval)) ) { + /* NUM_TARGETS is defined... and non-zero */ + bConstraintTarget *ct; + + /* check if it is valid (just make sure it is not negative) + * TODO: PyInt_AsLong may return -1 as sign of invalid input... + */ + num = abs(num); + data->flag |= PYCON_USETARGETS; + + /* check if the number of targets has changed */ + if (num < data->tarnum) { + /* free a few targets */ + num= data->tarnum - num; + for (i = 0; i < num; i++, data->tarnum--) { + ct= data->targets.last; + BLI_freelinkN(&data->targets, ct); + } + } + else if (num > data->tarnum) { + /* add a few targets */ + num = num - data->tarnum; + for (i = 0; i < num; i++, data->tarnum++) { + ct= MEM_callocN(sizeof(bConstraintTarget), "PyConTarget"); + BLI_addtail(&data->targets, ct); + } + } + + /* validate targets */ + con->flag &= ~CONSTRAINT_DISABLE; + for (ct= data->targets.first; ct; ct= ct->next) { + if (!exist_object(ct->tar)) { + ct->tar = NULL; + con->flag |= CONSTRAINT_DISABLE; + break; + } + + if ((ct->tar == owner) && (ct->subtarget[0] != 0)) { + if (get_named_bone(get_armature(owner), ct->subtarget) == NULL) { + con->flag |= CONSTRAINT_DISABLE; + break; + } + } + } + + /* clear globals */ + ReleaseGlobalDictionary(globals); + } + else { + /* NUM_TARGETS is not defined or equals 0 */ + ReleaseGlobalDictionary(globals); + + /* free all targets */ + BLI_freelistN(&data->targets); + data->tarnum = 0; + data->flag &= ~PYCON_USETARGETS; + + return; + } + } + else { + /* no script, so clear any settings/data now */ + data->tarnum = 0; + data->flag = 0; + con->flag &= ~CONSTRAINT_DISABLE; + + BLI_freelistN(&data->targets); + + /* supposedly this should still leave the base struct... */ + IDP_FreeProperty(data->prop); + } +} + +/* PyConstraints Evaluation Function (only called from evaluate_constraint) + * This function is responsible for modifying the ownermat that it is passed. + */ +void BPY_pyconstraint_eval(bPythonConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + PyObject *srcmat, *tarmat, *tarmats, *idprop; + PyObject *globals; + PyObject *gval; + PyObject *pyargs, *retval; + bConstraintTarget *ct; + MatrixObject *retmat; + int row, col, index; + + if (!con->text) return; + if (con->flag & PYCON_SCRIPTERROR) return; + + globals = CreateGlobalDictionary(); + + /* wrap blender-data as PyObjects for evaluation + * - we expose the owner's matrix as pymatrix + * - id-properties are wrapped using the id-properties pyapi + * - targets are presented as a list of matrices + */ + srcmat = newMatrixObject((float *)cob->matrix, 4, 4, Py_NEW); + idprop = BPy_Wrap_IDProperty(NULL, con->prop, NULL); + + tarmats= PyList_New(con->tarnum); + for (ct=targets->first, index=0; ct; ct=ct->next, index++) { + tarmat = newMatrixObject((float *)ct->matrix, 4, 4, Py_NEW); + PyList_SetItem(tarmats, index, tarmat); + } + + +/* since I can't remember what the armature weakrefs do, I'll just leave this here + commented out. This function was based on pydrivers, and it might still be relevent. + if( !setup_armature_weakrefs()){ + fprintf( stderr, "Oops - weakref dict setup\n"); + return result; + } +*/ + + retval = RunPython(con->text, globals); + + if (retval == NULL) { + BPY_Err_Handle(con->text->id.name); + con->flag |= PYCON_SCRIPTERROR; + + /* free temp objects */ + Py_XDECREF(idprop); + Py_XDECREF(srcmat); + Py_XDECREF(tarmats); + + ReleaseGlobalDictionary(globals); + + return; + } + + if (retval) {Py_XDECREF( retval );} + retval = NULL; + + gval = PyDict_GetItemString(globals, "doConstraint"); + if (!gval) { + printf("ERROR: no doConstraint function in constraint!\n"); + + /* free temp objects */ + Py_XDECREF(idprop); + Py_XDECREF(srcmat); + Py_XDECREF(tarmats); + + ReleaseGlobalDictionary(globals); + + return; + } + + /* Now for the fun part! Try and find the functions we need. */ + if (PyFunction_Check(gval)) { + pyargs = Py_BuildValue("OOO", srcmat, tarmats, idprop); + retval = PyObject_CallObject(gval, pyargs); + Py_XDECREF(pyargs); + } + else { + printf("ERROR: doConstraint is supposed to be a function!\n"); + con->flag |= PYCON_SCRIPTERROR; + + Py_XDECREF(idprop); + Py_XDECREF(srcmat); + Py_XDECREF(tarmats); + + ReleaseGlobalDictionary(globals); + + return; + } + + if (!retval) { + BPY_Err_Handle(con->text->id.name); + con->flag |= PYCON_SCRIPTERROR; + + /* free temp objects */ + Py_XDECREF(idprop); + Py_XDECREF(srcmat); + Py_XDECREF(tarmats); + + ReleaseGlobalDictionary(globals); + + return; + } + + + if (!PyObject_TypeCheck(retval, &matrix_Type)) { + printf("Error in PyConstraint - doConstraint: Function not returning a matrix!\n"); + con->flag |= PYCON_SCRIPTERROR; + + Py_XDECREF(idprop); + Py_XDECREF(srcmat); + Py_XDECREF(tarmats); + Py_XDECREF(retval); + + ReleaseGlobalDictionary(globals); + + return; + } + + retmat = (MatrixObject *)retval; + if (retmat->rowSize != 4 || retmat->colSize != 4) { + printf("Error in PyConstraint - doConstraint: Matrix returned is the wrong size!\n"); + con->flag |= PYCON_SCRIPTERROR; + + Py_XDECREF(idprop); + Py_XDECREF(srcmat); + Py_XDECREF(tarmats); + Py_XDECREF(retval); + + ReleaseGlobalDictionary(globals); + + return; + } + + /* this is the reverse of code taken from newMatrix() */ + for(row = 0; row < 4; row++) { + for(col = 0; col < 4; col++) { + cob->matrix[row][col] = retmat->contigPtr[row*4+col]; + } + } + + /* free temp objects */ + Py_XDECREF(idprop); + Py_XDECREF(srcmat); + Py_XDECREF(tarmats); + Py_XDECREF(retval); + + /* clear globals */ + ReleaseGlobalDictionary(globals); +} + +/* This evaluates the target matrix for each target the PyConstraint uses. + * NOTE: it only does one target at a time! + */ +void BPY_pyconstraint_target(bPythonConstraint *con, bConstraintTarget *ct) +{ + PyObject *tar, *subtar; + PyObject *tarmat, *idprop; + PyObject *globals; + PyObject *gval; + PyObject *pyargs, *retval; + MatrixObject *retmat; + int row, col; + + if (!con->text) return; + if (con->flag & PYCON_SCRIPTERROR) return; + if (!ct) return; + + globals = CreateGlobalDictionary(); + + tar = Object_CreatePyObject(ct->tar); + if ((ct->tar) && (ct->tar->type==OB_ARMATURE)) { + bPoseChannel *pchan; + pchan = get_pose_channel(ct->tar->pose, ct->subtarget); + subtar = PyPoseBone_FromPosechannel(pchan); + } + else + subtar = PyString_FromString(ct->subtarget); + + tarmat = newMatrixObject((float *)ct->matrix, 4, 4, Py_NEW); + idprop = BPy_Wrap_IDProperty( NULL, con->prop, NULL); + +/* since I can't remember what the armature weakrefs do, I'll just leave this here + commented out. This function was based on pydrivers, and it might still be relevent. + if( !setup_armature_weakrefs()){ + fprintf( stderr, "Oops - weakref dict setup\n"); + return result; + } +*/ + retval = RunPython(con->text, globals); + + if (retval == NULL) { + BPY_Err_Handle(con->text->id.name); + con->flag |= PYCON_SCRIPTERROR; + + /* free temp objects */ + Py_XDECREF(tar); + Py_XDECREF(subtar); + Py_XDECREF(idprop); + Py_XDECREF(tarmat); + + ReleaseGlobalDictionary(globals); + + return; + } + + Py_XDECREF(retval); + retval = NULL; + + /* try to find doTarget function to set the target matrix */ + gval = PyDict_GetItemString(globals, "doTarget"); + if (!gval) { + /* free temp objects */ + Py_XDECREF(tar); + Py_XDECREF(subtar); + Py_XDECREF(idprop); + Py_XDECREF(tarmat); + + ReleaseGlobalDictionary(globals); + + return; + } + + /* Now for the fun part! Try and find the functions we need.*/ + if (PyFunction_Check(gval)) { + pyargs = Py_BuildValue("OOOO", tar, subtar, tarmat, idprop); + retval = PyObject_CallObject(gval, pyargs); + Py_XDECREF(pyargs); + } + else { + printf("ERROR: doTarget is supposed to be a function!\n"); + con->flag |= PYCON_SCRIPTERROR; + + Py_XDECREF(tar); + Py_XDECREF(subtar); + Py_XDECREF(idprop); + Py_XDECREF(tarmat); + + ReleaseGlobalDictionary(globals); + return; + } + + if (!retval) { + BPY_Err_Handle(con->text->id.name); + con->flag |= PYCON_SCRIPTERROR; + + + /* free temp objects */ + Py_XDECREF(tar); + Py_XDECREF(subtar); + Py_XDECREF(idprop); + Py_XDECREF(tarmat); + + ReleaseGlobalDictionary(globals); + return; + } + + if (!PyObject_TypeCheck(retval, &matrix_Type)) { + con->flag |= PYCON_SCRIPTERROR; + + Py_XDECREF(tar); + Py_XDECREF(subtar); + Py_XDECREF(idprop); + Py_XDECREF(tarmat); + Py_XDECREF(retval); + + ReleaseGlobalDictionary(globals); + return; + } + + retmat = (MatrixObject *)retval; + if (retmat->rowSize != 4 || retmat->colSize != 4) { + printf("Error in PyConstraint - doTarget: Matrix returned is the wrong size!\n"); + con->flag |= PYCON_SCRIPTERROR; + + Py_XDECREF(tar); + Py_XDECREF(subtar); + Py_XDECREF(idprop); + Py_XDECREF(tarmat); + Py_XDECREF(retval); + + ReleaseGlobalDictionary(globals); + return; + } + + /* this is the reverse of code taken from newMatrix() */ + for(row = 0; row < 4; row++) { + for(col = 0; col < 4; col++) { + ct->matrix[row][col] = retmat->contigPtr[row*4+col]; + } + } + + /* free temp objects */ + Py_XDECREF(tar); + Py_XDECREF(subtar); + Py_XDECREF(idprop); + Py_XDECREF(tarmat); + Py_XDECREF(retval); + + /* clear globals */ + ReleaseGlobalDictionary(globals); +} + +/* This draws+handles the user-defined interface for editing pyconstraints idprops */ +void BPY_pyconstraint_settings(void *arg1, void *arg2) +{ + bPythonConstraint *con= (bPythonConstraint *)arg1; + PyObject *idprop; + PyObject *globals; + PyObject *gval; + PyObject *retval; + + if (!con->text) return; + if (con->flag & PYCON_SCRIPTERROR) return; + + globals = CreateGlobalDictionary(); + + idprop = BPy_Wrap_IDProperty( NULL, con->prop, NULL); + + retval = RunPython(con->text, globals); + + if (retval == NULL) { + BPY_Err_Handle(con->text->id.name); + ReleaseGlobalDictionary(globals); + con->flag |= PYCON_SCRIPTERROR; + + /* free temp objects */ + Py_XDECREF(idprop); + return; + } + + if (retval) {Py_XDECREF( retval );} + retval = NULL; + + gval = PyDict_GetItemString(globals, "getSettings"); + if (!gval) { + printf("ERROR: no getSettings function in constraint!\n"); + + /* free temp objects */ + ReleaseGlobalDictionary( globals ); + Py_XDECREF(idprop); + return; + } + + /* Now for the fun part! Try and find the functions we need. */ + if (PyFunction_Check(gval)) { + retval = PyObject_CallFunction(gval, "O", idprop); + } + else { + printf("ERROR: getSettings is supposed to be a function!\n"); + ReleaseGlobalDictionary( globals ); + + Py_XDECREF(idprop); + return; + } + + if (!retval) { + BPY_Err_Handle(con->text->id.name); + con->flag |= PYCON_SCRIPTERROR; + + /* free temp objects */ + ReleaseGlobalDictionary(globals); + Py_XDECREF(idprop); + return; + } + else { + /* clear globals */ + ReleaseGlobalDictionary(globals); + + /* free temp objects */ + Py_XDECREF(idprop); + Py_DECREF(retval); + return; + } +} + +/* Update function, it gets rid of pydrivers global dictionary, forcing + * BPY_pydriver_eval to recreate it. This function is used to force + * reloading the Blender text module "pydrivers.py", if available, so + * updates in it reach pydriver evaluation. */ +void BPY_pydriver_update(void) +{ + if (bpy_pydriver_Dict) { /* free the global dict used by pydrivers */ + PyDict_Clear(bpy_pydriver_Dict); + Py_DECREF(bpy_pydriver_Dict); + bpy_pydriver_Dict = NULL; + } + + return; +} + +/* for depsgraph.c, runs py expr once to collect all refs. made + * to objects (self refs. to the object that owns the py driver + * are not allowed). */ +struct Object **BPY_pydriver_get_objects(IpoDriver *driver) +{ + /*if (!driver || !driver->ob || driver->name[0] == '\0') + return NULL;*/ + + /*PyErr_Clear();*/ + + /* clear the flag that marks invalid python expressions */ + driver->flag &= ~IPO_DRIVER_FLAG_INVALID; + + /* tell we're running a pydriver, so Get() functions know they need + * to add the requested obj to our list */ + bpy_pydriver_running(1); + + /* append driver owner object as the 1st ob in the list; + * we put it there to make sure it is not itself referenced in + * its pydriver expression */ + bpy_pydriver_appendToList(driver->ob); + + /* this will append any other ob referenced in expr (driver->name) + * or set the driver's error flag if driver's py expression fails */ + BPY_pydriver_eval(driver); + + bpy_pydriver_running(0); /* ok, we're done */ + + return bpy_pydriver_obArrayFromList(); /* NULL if eval failed */ +} + +/* This evals py driver expressions, 'expr' is a Python expression that + * should evaluate to a float number, which is returned. */ +float BPY_pydriver_eval(IpoDriver *driver) +{ + char *expr = NULL; + PyObject *retval, *floatval, *bpy_ob = NULL; + float result = 0.0f; /* default return */ + int setitem_retval; + + if (!driver) return result; + + expr = driver->name; /* the py expression to be evaluated */ + if (!expr || expr[0]=='\0') return result; + + if (!bpy_pydriver_Dict) { + if (bpy_pydriver_create_dict() != 0) { + fprintf(stderr, "Pydriver error: couldn't create Python dictionary"); + return result; + } + } + + if (driver->ob) + bpy_ob = Object_CreatePyObject(driver->ob); + + if (!bpy_ob) { + Py_INCREF(Py_None); + bpy_ob = Py_None; + } + + setitem_retval = EXPP_dict_set_item_str(bpy_pydriver_Dict, "self", bpy_ob); + + if( !setup_armature_weakrefs()){ + fprintf( stderr, "Oops - weakref dict setup\n"); + return result; + } + + retval = PyRun_String(expr, Py_eval_input, bpy_pydriver_Dict, + bpy_pydriver_Dict); + + if (retval == NULL) { + return pydriver_error(driver); + } + + floatval = PyNumber_Float(retval); + Py_DECREF(retval); + + if (floatval == NULL) + return pydriver_error(driver); + + result = (float)PyFloat_AsDouble(floatval); + Py_DECREF(floatval); + + /* remove 'self', since this dict is also used by py buttons */ + if (setitem_retval == 0) PyDict_DelItemString(bpy_pydriver_Dict, "self"); + + /* all fine, make sure the "invalid expression" flag is cleared */ + driver->flag &= ~IPO_DRIVER_FLAG_INVALID; + + return result; +} + +/* Button Python Evaluation */ + +/* Python evaluation for gui buttons: + * users can write any valid Python expression (that evals to an int or float) + * inside Blender's gui number buttons and have them evaluated to their + * actual int or float value. + * + * The global dict used for pydrivers is also used here, so all imported + * modules for pydrivers (including the pydrivers.py Blender text) are + * available for button py eval, too. */ + +static int bpy_button_eval_error(char *expr) { + + if (bpy_pydriver_oblist) + bpy_pydriver_freeList(); + + if (bpy_pydriver_Dict) { /* free the persistent global dict */ + /* it's the same dict used by pydrivers */ + PyDict_Clear(bpy_pydriver_Dict); + Py_DECREF(bpy_pydriver_Dict); + bpy_pydriver_Dict = NULL; + } + + fprintf(stderr, "\nError in button evaluation:\nThis is the failed Python expression:\n'%s'\n\n", expr); + + PyErr_Print(); + + return -1; +} + +int BPY_button_eval(char *expr, double *value) +{ + PyObject *retval, *floatval; + + if (!value || !expr || expr[0]=='\0') return -1; + + *value = 0.0; /* default value */ + + if (!bpy_pydriver_Dict) { + if (bpy_pydriver_create_dict() != 0) { + fprintf(stderr, + "Button Python Eval error: couldn't create Python dictionary"); + return -1; + } + } + + + if( !setup_armature_weakrefs()){ + fprintf(stderr, "Oops - weakref dict\n"); + return -1; + } + + retval = PyRun_String(expr, Py_eval_input, bpy_pydriver_Dict, + bpy_pydriver_Dict); + + if (retval == NULL) { + return bpy_button_eval_error(expr); + } + else { + floatval = PyNumber_Float(retval); + Py_DECREF(retval); + } + + if (floatval == NULL) + return bpy_button_eval_error(expr); + else { + *value = (float)PyFloat_AsDouble(floatval); + Py_DECREF(floatval); + } + + return 0; /* successful exit */ +} + + +/*****************************************************************************/ +/* ScriptLinks */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* Description: */ +/* Notes: Not implemented yet */ +/*****************************************************************************/ +void BPY_clear_bad_scriptlinks( struct Text *byebye ) +{ +/* + BPY_clear_bad_scriptlist(getObjectList(), byebye); + BPY_clear_bad_scriptlist(getLampList(), byebye); + BPY_clear_bad_scriptlist(getCameraList(), byebye); + BPY_clear_bad_scriptlist(getMaterialList(), byebye); + BPY_clear_bad_scriptlist(getWorldList(), byebye); + BPY_clear_bad_scriptlink(&scene_getCurrent()->id, byebye); + + allqueue(REDRAWBUTSSCRIPT, 0); +*/ + return; +} + +/***************************************************************************** +* Description: Loop through all scripts of a list of object types, and +* execute these scripts. +* For the scene, only the current active scene the scripts are +* executed (if any). +*****************************************************************************/ +void BPY_do_all_scripts( short event ) +{ + DoAllScriptsFromList( &( G.main->object ), event ); + DoAllScriptsFromList( &( G.main->lamp ), event ); + DoAllScriptsFromList( &( G.main->camera ), event ); + DoAllScriptsFromList( &( G.main->mat ), event ); + DoAllScriptsFromList( &( G.main->world ), event ); + + BPY_do_pyscript( &( G.scene->id ), event ); + + return; +} + +/***************************************************************************** +* Description: Execute a Python script when an event occurs. The following +* events are possible: frame changed, load script and redraw. +* Only events happening to one of the following object types +* are handled: Object, Lamp, Camera, Material, World and +* Scene. +*****************************************************************************/ + +static ScriptLink *ID_getScriptlink( ID * id ) +{ + switch ( MAKE_ID2( id->name[0], id->name[1] ) ) { + case ID_OB: + return &( ( Object * ) id )->scriptlink; + case ID_LA: + return &( ( Lamp * ) id )->scriptlink; + case ID_CA: + return &( ( Camera * ) id )->scriptlink; + case ID_MA: + return &( ( Material * ) id )->scriptlink; + case ID_WO: + return &( ( World * ) id )->scriptlink; + case ID_SCE: + return &( ( Scene * ) id )->scriptlink; + default: + return NULL; + } +} + +int BPY_has_onload_script( void ) +{ + ScriptLink *slink = &G.scene->scriptlink; + int i; + + if( !slink || !slink->totscript ) + return 0; + + for( i = 0; i < slink->totscript; i++ ) { + if( ( slink->flag[i] == SCRIPT_ONLOAD ) + && ( slink->scripts[i] != NULL ) ) + return 1; + } + + return 0; +} + +void BPY_do_pyscript( ID * id, short event ) +{ + ScriptLink *scriptlink; + + if( !id ) return; + + scriptlink = ID_getScriptlink( id ); + + if( scriptlink && scriptlink->totscript ) { + PyObject *value; + PyObject *dict; + PyObject *ret; + int index, during_slink = during_scriptlink( ); + + /* invalid scriptlinks (new .blend was just loaded), return */ + if( during_slink < 0 ) + return; + + if( !setup_armature_weakrefs()){ + printf("Oops - weakref dict, this is a bug\n"); + return; + } + + value = GetPyObjectFromID( id ); + if( !value){ + printf("Oops - could not get a valid python object for Blender.link, this is a bug\n"); + return; + } + + /* tell we're running a scriptlink. The sum also tells if this script + * is running nested inside another. Blender.Load needs this info to + * avoid trouble with invalid slink pointers. */ + during_slink++; + disable_where_scriptlink( (short)during_slink ); + + /* set globals in Blender module to identify scriptlink */ + EXPP_dict_set_item_str( g_blenderdict, "bylink", EXPP_incr_ret_True() ); + + EXPP_dict_set_item_str( g_blenderdict, "link", value ); + EXPP_dict_set_item_str( g_blenderdict, "event", + PyString_FromString( event_to_name + ( event ) ) ); + + if (event == SCRIPT_POSTRENDER) event = SCRIPT_RENDER; + + for( index = 0; index < scriptlink->totscript; index++ ) { + if( ( scriptlink->flag[index] == event ) && + ( scriptlink->scripts[index] != NULL ) ) { + dict = CreateGlobalDictionary( ); + ret = RunPython( ( Text * ) scriptlink-> + scripts[index], dict ); + ReleaseGlobalDictionary( dict ); + + if( !ret ) { + /* Failed execution of the script */ + BPY_Err_Handle( scriptlink-> + scripts[index]->name + + 2 ); + //BPY_end_python (); + //BPY_start_python (); + } else { + Py_DECREF( ret ); + } + /* If a scriptlink has just loaded a new .blend file, the + * scriptlink pointer became invalid (see api2_2x/Blender.c), + * so we stop here. */ + if( during_scriptlink( ) == -1 ) { + during_slink = 1; + break; + } + } + } + + disable_where_scriptlink( (short)(during_slink - 1) ); + + /* cleanup bylink flag and clear link so PyObject + * can be released + */ + EXPP_dict_set_item_str( g_blenderdict, "bylink", EXPP_incr_ret_False() ); + PyDict_SetItemString( g_blenderdict, "link", Py_None ); + EXPP_dict_set_item_str( g_blenderdict, "event", + PyString_FromString( "" ) ); + } +} + + +/* SPACE HANDLERS */ + +/* These are special script links that can be assigned to ScrArea's to + * (EVENT type) receive events sent to a given space (and use or ignore them) or + * (DRAW type) be called after the space is drawn, to draw anything on top of + * the space area. */ + +/* How to add space handlers to other spaces: + * - add the space event defines to DNA_scriptlink_types.h, as done for + * 3d view: SPACEHANDLER_VIEW3D_EVENT, for example; + * - add the new defines to Blender.SpaceHandler dictionary in Blender.c; + * - check space.c for how to call the event handlers; + * - check drawview.c for how to call the draw handlers; + * - check header_view3d.c for how to add the "Space Handler Scripts" menu. + * Note: DRAW handlers should be called with 'event = 0', chech drawview.c */ + +int BPY_has_spacehandler(Text *text, ScrArea *sa) +{ + ScriptLink *slink; + int index; + + if (!sa || !text) return 0; + + slink = &sa->scriptlink; + + for (index = 0; index < slink->totscript; index++) { + if (slink->scripts[index] && (slink->scripts[index] == (ID *)text)) + return 1; + } + + return 0; +} + +int BPY_is_spacehandler(Text *text, char spacetype) +{ + TextLine *tline = text->lines.first; + unsigned short type = 0; + + if (tline && (tline->len > 10)) { + char *line = tline->line; + + /* Expected format: # SPACEHANDLER.SPACE.TYPE + * Ex: # SPACEHANDLER.VIEW3D.DRAW + * The actual checks are forgiving, so slight variations also work. */ + if (line && line[0] == '#' && strstr(line, "HANDLER")) { + line++; /* skip '#' */ + + /* only done for 3D View right now, trivial to add for others: */ + switch (spacetype) { + case SPACE_VIEW3D: + if (strstr(line, "3D")) { /* VIEW3D, 3DVIEW */ + if (strstr(line, "DRAW")) type = SPACEHANDLER_VIEW3D_DRAW; + else if (strstr(line, "EVENT")) type = SPACEHANDLER_VIEW3D_EVENT; + } + break; + } + } + } + return type; /* 0 if not a space handler */ +} + +int BPY_del_spacehandler(Text *text, ScrArea *sa) +{ + ScriptLink *slink; + int i, j; + + if (!sa || !text) return -1; + + slink = &sa->scriptlink; + if (slink->totscript < 1) return -1; + + for (i = 0; i < slink->totscript; i++) { + if (text == (Text *)slink->scripts[i]) { + + for (j = i; j < slink->totscript - 1; j++) { + slink->flag[j] = slink->flag[j+1]; + slink->scripts[j] = slink->scripts[j+1]; + } + slink->totscript--; + /* like done in buttons_script.c we just free memory + * if all slinks have been removed -- less fragmentation, + * these should be quite small arrays */ + if (slink->totscript == 0) { + if (slink->scripts) MEM_freeN(slink->scripts); + if (slink->flag) MEM_freeN(slink->flag); + break; + } + } + } + return 0; +} + +int BPY_add_spacehandler(Text *text, ScrArea *sa, char spacetype) +{ + unsigned short handlertype; + + if (!sa || !text) return -1; + + handlertype = (unsigned short)BPY_is_spacehandler(text, spacetype); + + if (handlertype) { + ScriptLink *slink = &sa->scriptlink; + void *stmp, *ftmp; + unsigned short space_event = SPACEHANDLER_VIEW3D_EVENT; + + /* extend slink */ + + stmp= slink->scripts; + slink->scripts= MEM_mallocN(sizeof(ID*)*(slink->totscript+1), + "spacehandlerscripts"); + + ftmp= slink->flag; + slink->flag= MEM_mallocN(sizeof(short*)*(slink->totscript+1), + "spacehandlerflags"); + + if (slink->totscript) { + memcpy(slink->scripts, stmp, sizeof(ID*)*(slink->totscript)); + MEM_freeN(stmp); + + memcpy(slink->flag, ftmp, sizeof(short)*(slink->totscript)); + MEM_freeN(ftmp); + } + + switch (spacetype) { + case SPACE_VIEW3D: + if (handlertype == 1) space_event = SPACEHANDLER_VIEW3D_EVENT; + else space_event = SPACEHANDLER_VIEW3D_DRAW; + break; + default: + break; + } + + slink->scripts[slink->totscript] = (ID *)text; + slink->flag[slink->totscript]= space_event; + + slink->totscript++; + slink->actscript = slink->totscript; + + } + return 0; +} + +int BPY_do_spacehandlers( ScrArea *sa, unsigned short event, + unsigned short space_event ) +{ + ScriptLink *scriptlink; + int retval = 0; + + if (!sa || !(G.f & G_DOSCRIPTLINKS)) return 0; + + scriptlink = &sa->scriptlink; + + if (scriptlink->totscript > 0) { + PyObject *dict; + PyObject *ret; + int index, during_slink = during_scriptlink(); + + /* invalid scriptlinks (new .blend was just loaded), return */ + if (during_slink < 0) return 0; + + /* tell we're running a scriptlink. The sum also tells if this script + * is running nested inside another. Blender.Load needs this info to + * avoid trouble with invalid slink pointers. + * Update (test): allow EVENT space handlers to call file/image selectors, + * still disabled for DRAW space handlers: */ + if (event == 0) { /* event = 0: DRAW space handler */ + during_slink++; + disable_where_scriptlink( (short)during_slink ); + } + + if( !setup_armature_weakrefs()){ + printf("Oops - weakref dict, this is a bug\n"); + return 0; + } + + /* set globals in Blender module to identify space handler scriptlink */ + EXPP_dict_set_item_str(g_blenderdict, "bylink", EXPP_incr_ret_True()); + /* unlike normal scriptlinks, here Blender.link is int (space event type) */ + EXPP_dict_set_item_str(g_blenderdict, "link", PyInt_FromLong(space_event)); + /* note: DRAW space_events set event to 0 */ + EXPP_dict_set_item_str(g_blenderdict, "event", PyInt_FromLong(event)); + + /* now run all assigned space handlers for this space and space_event */ + for( index = 0; index < scriptlink->totscript; index++ ) { + + /* for DRAW handlers: */ + if (event == 0) { + glPushAttrib(GL_ALL_ATTRIB_BITS); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + } + + if( ( scriptlink->flag[index] == space_event ) && + ( scriptlink->scripts[index] != NULL ) ) { + dict = CreateGlobalDictionary(); + ret = RunPython( ( Text * ) scriptlink->scripts[index], dict ); + ReleaseGlobalDictionary( dict ); + + if (!ret) { /* Failed execution of the script */ + BPY_Err_Handle( scriptlink->scripts[index]->name+2 ); + } else { + Py_DECREF(ret); + + /* an EVENT type (event != 0) script can either accept an event or + * ignore it: + * if the script sets Blender.event to None it accepted it; + * otherwise the space's event handling callback that called us + * can go on processing the event */ + if (event && (PyDict_GetItemString(g_blenderdict,"event") == Py_None)) + retval = 1; /* event was swallowed */ + } + + /* If a scriptlink has just loaded a new .blend file, the + * scriptlink pointer became invalid (see api2_2x/Blender.c), + * so we stop here. */ + if( during_scriptlink( ) == -1 ) { + during_slink = 1; + if (event == 0) glPopAttrib(); + break; + } + } + + /* for DRAW handlers: */ + if (event == 0) { + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glPopAttrib(); + disable_where_scriptlink( (short)(during_slink - 1) ); + } + + } + + EXPP_dict_set_item_str(g_blenderdict, "bylink", EXPP_incr_ret_False()); + PyDict_SetItemString(g_blenderdict, "link", Py_None ); + EXPP_dict_set_item_str(g_blenderdict, "event", PyString_FromString("")); + } + + /* retval: + * space_event is of type EVENT: + * 0 - event was returned, + * 1 - event was processed; + * space_event is of type DRAW: + * 0 always */ + + return retval; +} + +/***************************************************************************** +* Description: +* Notes: +*****************************************************************************/ +void BPY_free_scriptlink( struct ScriptLink *slink ) +{ + if( slink->totscript ) { + if( slink->flag ) { + MEM_freeN( slink->flag ); + slink->flag= NULL; + } + if( slink->scripts ) { + MEM_freeN( slink->scripts ); + slink->scripts= NULL; + } + } + + return; +} + +static int CheckAllSpaceHandlers(Text *text) +{ + bScreen *screen; + ScrArea *sa; + ScriptLink *slink; + int fixed = 0; + + for (screen = G.main->screen.first; screen; screen = screen->id.next) { + for (sa = screen->areabase.first; sa; sa = sa->next) { + slink = &sa->scriptlink; + if (!slink->totscript) continue; + if (BPY_del_spacehandler(text, sa) == 0) fixed++; + } + } + return fixed; +} + +static int CheckAllScriptsFromList( ListBase * list, Text * text ) +{ + ID *id; + ScriptLink *scriptlink; + int index; + int fixed = 0; + + id = list->first; + + while( id != NULL ) { + scriptlink = ID_getScriptlink( id ); + if( scriptlink && scriptlink->totscript ) { + for( index = 0; index < scriptlink->totscript; index++) { + if ((Text *)scriptlink->scripts[index] == text) { + scriptlink->scripts[index] = NULL; + fixed++; + } + } + } + id = id->next; + } + + return fixed; +} + +/* When a Text is deleted, we need to unlink it from eventual scriptlinks */ +int BPY_check_all_scriptlinks( Text * text ) +{ + int fixed = 0; + fixed += CheckAllScriptsFromList( &( G.main->object ), text ); + fixed += CheckAllScriptsFromList( &( G.main->lamp ), text ); + fixed += CheckAllScriptsFromList( &( G.main->camera ), text ); + fixed += CheckAllScriptsFromList( &( G.main->mat ), text ); + fixed += CheckAllScriptsFromList( &( G.main->world ), text ); + fixed += CheckAllScriptsFromList( &( G.main->scene ), text ); + fixed += CheckAllSpaceHandlers(text); + + return fixed; +} + +/***************************************************************************** +* Description: +* Notes: +*****************************************************************************/ +void BPY_copy_scriptlink( struct ScriptLink *scriptlink ) +{ + void *tmp; + + if( scriptlink->totscript ) { + + tmp = scriptlink->scripts; + scriptlink->scripts = + MEM_mallocN( sizeof( ID * ) * scriptlink->totscript, + "scriptlistL" ); + memcpy( scriptlink->scripts, tmp, + sizeof( ID * ) * scriptlink->totscript ); + + tmp = scriptlink->flag; + scriptlink->flag = + MEM_mallocN( sizeof( short ) * scriptlink->totscript, + "scriptlistF" ); + memcpy( scriptlink->flag, tmp, + sizeof( short ) * scriptlink->totscript ); + } + + return; +} + +/**************************************************************************** +* Description: +* Notes: Not implemented yet +*****************************************************************************/ +int BPY_call_importloader( char *name ) +{ /* XXX Should this function go away from Blender? */ + printf( "In BPY_call_importloader(name=%s)\n", name ); + return ( 0 ); +} + +/***************************************************************************** +* Private functions +*****************************************************************************/ + +/***************************************************************************** +* Description: This function executes the python script passed by text. +* The Python dictionary containing global variables needs to +* be passed in globaldict. +*****************************************************************************/ +PyObject *RunPython( Text * text, PyObject * globaldict ) +{ + char *buf = NULL; + +/* The script text is compiled to Python bytecode and saved at text->compiled + * to speed-up execution if the user executes the script multiple times */ + + if( !text->compiled ) { /* if it wasn't already compiled, do it now */ + buf = txt_to_buf( text ); + + text->compiled = + Py_CompileString( buf, GetName( text ), + Py_file_input ); + + MEM_freeN( buf ); + + if( PyErr_Occurred( ) ) { + BPY_free_compiled_text( text ); + return NULL; + } + + } + + return PyEval_EvalCode( text->compiled, globaldict, globaldict ); +} + +/***************************************************************************** +* Description: This function returns the value of the name field of the +* given Text struct. +*****************************************************************************/ +char *GetName( Text * text ) +{ + return ( text->id.name + 2 ); +} + +/***************************************************************************** +* Description: This function creates a new Python dictionary object. +*****************************************************************************/ +PyObject *CreateGlobalDictionary( void ) +{ + PyObject *dict = PyDict_New( ); + + PyDict_SetItemString( dict, "__builtins__", PyEval_GetBuiltins( ) ); + EXPP_dict_set_item_str( dict, "__name__", + PyString_FromString( "__main__" ) ); + + return dict; +} + +/***************************************************************************** +* Description: This function deletes a given Python dictionary object. +*****************************************************************************/ +void ReleaseGlobalDictionary( PyObject * dict ) +{ + PyDict_Clear( dict ); + Py_DECREF( dict ); /* Release dictionary. */ + + return; +} + +/*************************************************************************** +* Description: This function runs all scripts (if any) present in the +* list argument. The event by which the function has been +* called, is passed in the event argument. +*****************************************************************************/ +void DoAllScriptsFromList( ListBase * list, short event ) +{ + ID *id; + + id = list->first; + + while( id != NULL ) { + BPY_do_pyscript( id, event ); + id = id->next; + } + + return; +} + +PyObject *importText( char *name ) +{ + Text *text; + char *txtname; + char *buf = NULL; + int namelen = strlen( name ); + + txtname = malloc( namelen + 3 + 1 ); + if( !txtname ) + return NULL; + + memcpy( txtname, name, namelen ); + memcpy( &txtname[namelen], ".py", 4 ); + + text = ( Text * ) & ( G.main->text.first ); + + while( text ) { + if( !strcmp( txtname, GetName( text ) ) ) + break; + text = text->id.next; + } + + if( !text ) { + free( txtname ); + return NULL; + } + + if( !text->compiled ) { + buf = txt_to_buf( text ); + text->compiled = + Py_CompileString( buf, GetName( text ), + Py_file_input ); + MEM_freeN( buf ); + + if( PyErr_Occurred( ) ) { + PyErr_Print( ); + BPY_free_compiled_text( text ); + free( txtname ); + return NULL; + } + } + + free( txtname ); + return PyImport_ExecCodeModule( name, text->compiled ); +} + +static PyMethodDef bimport[] = { + {"blimport", blender_import, METH_VARARGS, "our own import"} +}; + +PyObject *blender_import( PyObject * self, PyObject * args ) +{ + PyObject *exception, *err, *tb; + char *name; + PyObject *globals = NULL, *locals = NULL, *fromlist = NULL; + PyObject *m; + + if( !PyArg_ParseTuple( args, "s|OOO:bimport", + &name, &globals, &locals, &fromlist ) ) + return NULL; + + m = PyImport_ImportModuleEx( name, globals, locals, fromlist ); + + if( m ) + return m; + else + PyErr_Fetch( &exception, &err, &tb ); /*restore for probable later use */ + + m = importText( name ); + if( m ) { /* found module, ignore above exception */ + PyErr_Clear( ); + Py_XDECREF( exception ); + Py_XDECREF( err ); + Py_XDECREF( tb ); + printf( "imported from text buffer...\n" ); + } else { + PyErr_Restore( exception, err, tb ); + } + return m; +} + +void init_ourImport( void ) +{ + PyObject *m, *d; + PyObject *import = PyCFunction_New( bimport, NULL ); + + m = PyImport_AddModule( "__builtin__" ); + d = PyModule_GetDict( m ); + + EXPP_dict_set_item_str( d, "__import__", import ); +} + +/* + * find in-memory module and recompile + */ + +static PyObject *reimportText( PyObject *module ) +{ + Text *text; + char *txtname; + char *name; + char *buf = NULL; + + /* get name, filename from the module itself */ + + txtname = PyModule_GetFilename( module ); + name = PyModule_GetName( module ); + if( !txtname || !name) + return NULL; + + /* look up the text object */ + text = ( Text * ) & ( G.main->text.first ); + while( text ) { + if( !strcmp( txtname, GetName( text ) ) ) + break; + text = text->id.next; + } + + /* uh-oh.... didn't find it */ + if( !text ) + return NULL; + + /* if previously compiled, free the object */ + /* (can't see how could be NULL, but check just in case) */ + if( text->compiled ){ + Py_DECREF( (PyObject *)text->compiled ); + } + + /* compile the buffer */ + buf = txt_to_buf( text ); + text->compiled = Py_CompileString( buf, GetName( text ), + Py_file_input ); + MEM_freeN( buf ); + + /* if compile failed.... return this error */ + if( PyErr_Occurred( ) ) { + PyErr_Print( ); + BPY_free_compiled_text( text ); + return NULL; + } + + /* make into a module */ + return PyImport_ExecCodeModule( name, text->compiled ); +} + +/* + * our reload() module, to handle reloading in-memory scripts + */ + +static PyObject *blender_reload( PyObject * self, PyObject * args ) +{ + PyObject *exception, *err, *tb; + PyObject *module = NULL; + PyObject *newmodule = NULL; + + /* check for a module arg */ + if( !PyArg_ParseTuple( args, "O:breload", &module ) ) + return NULL; + + /* try reimporting from file */ + newmodule = PyImport_ReloadModule( module ); + if( newmodule ) + return newmodule; + + /* no file, try importing from memory */ + PyErr_Fetch( &exception, &err, &tb ); /*restore for probable later use */ + + newmodule = reimportText( module ); + if( newmodule ) { /* found module, ignore above exception */ + PyErr_Clear( ); + Py_XDECREF( exception ); + Py_XDECREF( err ); + Py_XDECREF( tb ); + } else + PyErr_Restore( exception, err, tb ); + + return newmodule; +} + +static PyMethodDef breload[] = { + {"blreload", blender_reload, METH_VARARGS, "our own reload"} +}; + +void init_ourReload( void ) +{ + PyObject *m, *d; + PyObject *reload = PyCFunction_New( breload, NULL ); + + m = PyImport_AddModule( "__builtin__" ); + d = PyModule_GetDict( m ); + EXPP_dict_set_item_str( d, "reload", reload ); +} diff --git a/source/blender/python/BPY_menus.c b/source/blender/python/BPY_menus.c new file mode 100644 index 00000000000..5f16aa0241b --- /dev/null +++ b/source/blender/python/BPY_menus.c @@ -0,0 +1,1118 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano, Michael Reimpell + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +/* + *This is the main file responsible for having bpython scripts accessible + * from Blender menus. To know more, please start with its header file. + */ + +#include "BPY_menus.h" + +#include +#ifndef WIN32 + #include +#else + #include "BLI_winstuff.h" +#endif +#include "BKE_global.h" +#include "BKE_utildefines.h" +#include "BLI_blenlib.h" +#include "MEM_guardedalloc.h" +#include "DNA_userdef_types.h" /* for U.pythondir */ +#include "api2_2x/EXPP_interface.h" /* for bpy_gethome() */ + +#define BPYMENU_DATAFILE "Bpymenus" +#define MAX_DIR_DEPTH 4 /* max depth for traversing scripts dirs */ +#define MAX_DIR_NUMBER 30 /* max number of dirs in scripts dirs trees */ + +static int DEBUG; +static int Dir_Depth; +static int Dirs_Number; + +/* BPyMenuTable holds all registered pymenus, as linked lists for each menu + * where they can appear (see PYMENUHOOKS enum in BPY_menus.h). +*/ +BPyMenu *BPyMenuTable[PYMENU_TOTAL]; + +static int bpymenu_group_atoi( char *str ) +{ + if( !strcmp( str, "Export" ) ) + return PYMENU_EXPORT; + else if( !strcmp( str, "Import" ) ) + return PYMENU_IMPORT; + else if( !strcmp( str, "Help" ) ) + return PYMENU_HELP; + else if( !strcmp( str, "HelpWebsites" ) ) + return PYMENU_HELPWEBSITES; + else if( !strcmp( str, "HelpSystem" ) ) + return PYMENU_HELPSYSTEM; + else if( !strcmp( str, "Render" ) ) + return PYMENU_RENDER; + else if( !strcmp( str, "System" ) ) + return PYMENU_SYSTEM; + else if( !strcmp( str, "Object" ) ) + return PYMENU_OBJECT; + else if( !strcmp( str, "Mesh" ) ) + return PYMENU_MESH; + else if( !strncmp( str, "Theme", 5 ) ) + return PYMENU_THEMES; + else if( !strcmp( str, "Add" ) ) + return PYMENU_ADD; + else if( !strcmp( str, "Wizards" ) ) + return PYMENU_WIZARDS; + else if( !strcmp( str, "Animation" ) ) + return PYMENU_ANIMATION; + else if( !strcmp( str, "Materials" ) ) + return PYMENU_MATERIALS; + else if( !strcmp( str, "UV" ) ) + return PYMENU_UV; + else if( !strcmp( str, "Image" ) ) + return PYMENU_IMAGE; + else if( !strcmp( str, "FaceSelect" ) ) + return PYMENU_FACESELECT; + else if( !strcmp( str, "WeightPaint" ) ) + return PYMENU_WEIGHTPAINT; + else if( !strcmp( str, "VertexPaint" ) ) + return PYMENU_VERTEXPAINT; + else if( !strcmp( str, "UVCalculation" ) ) + return PYMENU_UVCALCULATION; + else if( !strcmp( str, "Armature" ) ) + return PYMENU_ARMATURE; + else if( !strcmp( str, "ScriptTemplate" ) ) + return PYMENU_SCRIPTTEMPLATE; + else if( !strcmp( str, "MeshFaceKey" ) ) + return PYMENU_MESHFACEKEY; + else if( !strcmp( str, "AddMesh" ) ) + return PYMENU_ADDMESH; + /* "Misc" or an inexistent group name: use misc */ + else + return PYMENU_MISC; +} + +char *BPyMenu_group_itoa( short menugroup ) +{ + switch ( menugroup ) { + case PYMENU_EXPORT: + return "Export"; + break; + case PYMENU_IMPORT: + return "Import"; + break; + case PYMENU_ADD: + return "Add"; + break; + case PYMENU_HELP: + return "Help"; + break; + case PYMENU_HELPWEBSITES: + return "HelpWebsites"; + break; + case PYMENU_HELPSYSTEM: + return "HelpSystem"; + break; + case PYMENU_RENDER: + return "Render"; + break; + case PYMENU_SYSTEM: + return "System"; + break; + case PYMENU_OBJECT: + return "Object"; + break; + case PYMENU_MESH: + return "Mesh"; + break; + case PYMENU_THEMES: + return "Themes"; + break; + case PYMENU_WIZARDS: + return "Wizards"; + break; + case PYMENU_ANIMATION: + return "Animation"; + break; + case PYMENU_MATERIALS: + return "Materials"; + break; + case PYMENU_UV: + return "UV"; + break; + case PYMENU_IMAGE: + return "Image"; + break; + case PYMENU_FACESELECT: + return "FaceSelect"; + break; + case PYMENU_WEIGHTPAINT: + return "WeightPaint"; + break; + case PYMENU_VERTEXPAINT: + return "VertexPaint"; + break; + case PYMENU_UVCALCULATION: + return "UVCalculation"; + break; + case PYMENU_ARMATURE: + return "Armature"; + break; + case PYMENU_SCRIPTTEMPLATE: + return "ScriptTemplate"; + break; + case PYMENU_MESHFACEKEY: + return "MeshFaceKey"; + break; + case PYMENU_ADDMESH: + return "AddMesh"; + break; + case PYMENU_MISC: + return "Misc"; + break; + } + return NULL; +} + +/* BPyMenu_CreatePupmenuStr: + * build and return a meaninful string to be used by pupmenu(). The + * string is made of a bpymenu name as title and its submenus as possible + * choices for the user. +*/ +char *BPyMenu_CreatePupmenuStr( BPyMenu * pym, short menugroup ) +{ + BPySubMenu *pysm = pym->submenus; + char str[1024], str2[100]; + int i = 0, rlen; + + if( !pym || !pysm ) + return NULL; + + str[0] = '\0'; + + PyOS_snprintf( str2, sizeof( str2 ), "%s: %s%%t", + BPyMenu_group_itoa( menugroup ), pym->name ); + strcat( str, str2 ); + + while( pysm ) { + PyOS_snprintf( str2, sizeof( str2 ), "|%s%%x%d", pysm->name, + i ); + rlen = sizeof( str ) - strlen( str ); + strncat( str, str2, rlen ); + i++; + pysm = pysm->next; + } + + return BLI_strdup( str ); +} + +static void bpymenu_RemoveAllSubEntries( BPySubMenu * smenu ) +{ + BPySubMenu *tmp; + + while( smenu ) { + tmp = smenu->next; + if( smenu->name ) + MEM_freeN( smenu->name ); + if( smenu->arg ) + MEM_freeN( smenu->arg ); + MEM_freeN( smenu ); + smenu = tmp; + } + return; +} + +void BPyMenu_RemoveAllEntries( void ) +{ + BPyMenu *tmp, *pymenu; + int i; + + for( i = 0; i < PYMENU_TOTAL; i++ ) { + pymenu = BPyMenuTable[i]; + while( pymenu ) { + tmp = pymenu->next; + if( pymenu->name ) + MEM_freeN( pymenu->name ); + if( pymenu->filename ) + MEM_freeN( pymenu->filename ); + if( pymenu->tooltip ) + MEM_freeN( pymenu->tooltip ); + if( pymenu->submenus ) + bpymenu_RemoveAllSubEntries( pymenu-> + submenus ); + MEM_freeN( pymenu ); + pymenu = tmp; + } + BPyMenuTable[i] = NULL; + } + + Dirs_Number = 0; + Dir_Depth = 0; + + return; +} + +static BPyMenu *bpymenu_FindEntry( short group, char *name ) +{ + BPyMenu *pymenu; + + if( ( group < 0 ) || ( group >= PYMENU_TOTAL ) ) + return NULL; + + pymenu = BPyMenuTable[group]; + + while( pymenu ) { + if( !strcmp( pymenu->name, name ) ) + return pymenu; + pymenu = pymenu->next; + } + + return NULL; +} + +/* BPyMenu_GetEntry: + * given a group and a position, return the entry in that position from + * that group. +*/ +BPyMenu *BPyMenu_GetEntry( short group, short pos ) +{ + BPyMenu *pym = NULL; + + if( ( group < 0 ) || ( group >= PYMENU_TOTAL ) ) + return NULL; + + pym = BPyMenuTable[group]; + + while( pos-- ) { + if( pym ) + pym = pym->next; + else + break; + } + + return pym; /* found entry or NULL */ +} + +static void bpymenu_set_tooltip( BPyMenu * pymenu, char *tip ) +{ + if( !pymenu ) + return; + + if( pymenu->tooltip ) + MEM_freeN( pymenu->tooltip ); + pymenu->tooltip = BLI_strdup( tip ); + + return; +} + +/* bpymenu_AddEntry: + * try to find an existing pymenu entry with the given type and name; + * if found, update it with new info, otherwise create a new one and fill it. + */ +static BPyMenu *bpymenu_AddEntry( short group, short version, char *name, + char *fname, int is_userdir, char *tooltip ) +{ + BPyMenu *menu, *next = NULL, **iter; + int nameclash = 0; + + if( ( group < 0 ) || ( group >= PYMENU_TOTAL ) ) + return NULL; + if( !name || !fname ) + return NULL; + + menu = bpymenu_FindEntry( group, name ); /* already exists? */ + + /* if a menu with this name already exists in the same group: + * - if one script is in the default dir and the other in U.pythondir, + * accept and let the new one override the other. + * - otherwise, report the error and return NULL. */ + if( menu ) { + if( menu->dir < is_userdir ) { /* new one is in U.pythondir */ + nameclash = 1; + if( menu->name ) + MEM_freeN( menu->name ); + if( menu->filename ) + MEM_freeN( menu->filename ); + if( menu->tooltip ) + MEM_freeN( menu->tooltip ); + if( menu->submenus ) + bpymenu_RemoveAllSubEntries( menu->submenus ); + next = menu->next; + } else { /* they are in the same dir */ + if (DEBUG) { + fprintf(stderr, "\n\ +Warning: script %s's menu name is already in use.\n\ +Edit the script and change its \n\ +Name: '%s'\n\ +field, please.\n\ +Note: if you really want to have two scripts for the same menu with\n\ +the same name, keep one in the default dir and the other in\n\ +the user defined dir (only the later will be registered).\n", fname, name); + } + return NULL; + } + } else + menu = MEM_mallocN( sizeof( BPyMenu ), "pymenu" ); + + if( !menu ) + return NULL; + + menu->name = BLI_strdup( name ); + menu->version = version; + menu->filename = BLI_strdup( fname ); + menu->tooltip = NULL; + if( tooltip ) + menu->tooltip = BLI_strdup( tooltip ); + menu->dir = is_userdir; + menu->submenus = NULL; + menu->next = next; /* non-NULL if menu already existed */ + + if( nameclash ) + return menu; /* no need to place it, it's already at the list */ + else { /* insert the new entry in its correct position at the table */ + BPyMenu *prev = NULL; + char *s = NULL; + + iter = &BPyMenuTable[group]; + while( *iter ) { + s = ( *iter )->name; + if( s ) + if( strcmp( menu->name, s ) < 0 ) + break; /* sort by names */ + prev = *iter; + iter = &( ( *iter )->next ); + } + + if( *iter ) { /* prepend */ + menu->next = *iter; + if( prev ) + prev->next = menu; + else + BPyMenuTable[group] = menu; /* is first entry */ + } else + *iter = menu; /* append */ + } + + return menu; +} + +/* bpymenu_AddSubEntry: + * add a submenu to an existing python menu. + */ +static int bpymenu_AddSubEntry( BPyMenu * mentry, char *name, char *arg ) +{ + BPySubMenu *smenu, **iter; + + smenu = MEM_mallocN( sizeof( BPySubMenu ), "pysubmenu" ); + if( !smenu ) + return -1; + + smenu->name = BLI_strdup( name ); + smenu->arg = BLI_strdup( arg ); + smenu->next = NULL; + + if( !smenu->name || !smenu->arg ) + return -1; + + iter = &( mentry->submenus ); + while( *iter ) + iter = &( ( *iter )->next ); + + *iter = smenu; + + return 0; +} + +/* bpymenu_CreateFromFile: + * parse the bpymenus data file where Python menu data is stored; + * based on this data, create and fill the pymenu structs. + */ +static int bpymenu_CreateFromFile( void ) +{ + FILE *fp; + char line[255], w1[255], w2[255], tooltip[255], *tip; + char *homedir = NULL; + int parsing, version, is_userdir; + short group; + BPyMenu *pymenu = NULL; + + /* init global bpymenu table (it is a list of pointers to struct BPyMenus + * for each available cathegory: import, export, etc.) */ + for( group = 0; group < PYMENU_TOTAL; group++ ) + BPyMenuTable[group] = NULL; + + /* let's try to open the file with bpymenu data */ + homedir = bpy_gethome(0); + if (!homedir) { + if( DEBUG ) + fprintf(stderr, + "BPyMenus error: couldn't open config file Bpymenus: no home dir.\n"); + return -1; + } + + BLI_make_file_string( "/", line, homedir, BPYMENU_DATAFILE ); + + fp = fopen( line, "rb" ); + + if( !fp ) { + if( DEBUG ) + fprintf(stderr, "BPyMenus error: couldn't open config file %s.\n", line ); + return -1; + } + + fgets( line, 255, fp ); /* header */ + + /* check if the U.pythondir we saved at the file is different from the + * current one. If so, return to force updating from dirs */ + w1[0] = '\0'; + fscanf( fp, "# User defined scripts dir: %[^\n]\n", w1 ); + if( w1 ) { + char upythondir[FILE_MAXDIR]; + + BLI_strncpy(upythondir, U.pythondir, FILE_MAXDIR); + BLI_convertstringcode(upythondir, G.sce, 0); + if( strcmp( w1, upythondir ) != 0 ) + return -1; + w1[0] = '\0'; + } + + while( fgets( line, 255, fp ) ) { /* parsing file lines */ + + switch ( line[0] ) { /* check first char */ + case '#': /* comment */ + continue; + break; + case '\n': + continue; + break; + default: + parsing = sscanf( line, "%s {\n", w1 ); /* menu group */ + break; + } + + if( parsing == 1 ) { /* got menu group string */ + group = (short)bpymenu_group_atoi( w1 ); + if( group < 0 && DEBUG ) { /* invalid type */ + fprintf(stderr, + "BPyMenus error parsing config file: wrong group: %s,\n\ +will use 'Misc'.\n", w1 ); + } + } else + continue; + + for(;;) { + tip = NULL; /* optional tooltip */ + fgets( line, 255, fp ); + if( line[0] == '}' ) + break; + else if( line[0] == '\n' ) + continue; + else if( line[0] == '\'' ) { /* menu entry */ + parsing = + sscanf( line, + "'%[^']' %d %s %d '%[^']'\n", + w1, &version, w2, &is_userdir, + tooltip ); + + if( parsing <= 0 ) { /* invalid line, get rid of it */ + fgets( line, 255, fp ); + } else if( parsing == 5 ) + tip = tooltip; /* has tooltip */ + + pymenu = bpymenu_AddEntry( group, + ( short ) version, + w1, w2, is_userdir, + tip ); + if( !pymenu ) { + puts( "BPyMenus error: couldn't create bpymenu entry.\n" ); + fclose( fp ); + return -1; + } + } else if( line[0] == '|' && line[1] == '_' ) { /* menu sub-entry */ + if( !pymenu ) + continue; /* no menu yet, skip this line */ + sscanf( line, "|_%[^:]: %s\n", w1, w2 ); + bpymenu_AddSubEntry( pymenu, w1, w2 ); + } + } + } + + fclose( fp ); + return 0; +} + +/* bpymenu_WriteDataFile: + * writes the registered scripts info to the user's home dir, for faster + * access when the scripts dir hasn't changed. +*/ +static void bpymenu_WriteDataFile( void ) +{ + BPyMenu *pymenu; + BPySubMenu *smenu; + FILE *fp; + char fname[FILE_MAXDIR], *homedir; + int i; + + homedir = bpy_gethome(0); + + if (!homedir) { + if( DEBUG ) + fprintf(stderr, + "BPyMenus error: couldn't write Bpymenus file: no home dir.\n\n"); + return; + } + + BLI_make_file_string( "/", fname, homedir, BPYMENU_DATAFILE ); + + fp = fopen( fname, "w" ); + if( !fp ) { + if( DEBUG ) + fprintf(stderr, "BPyMenus error: couldn't write %s file.\n\n", + fname ); + return; + } + + fprintf( fp, + "# Blender: registered menu entries for bpython scripts\n" ); + + if (U.pythondir[0] != '\0' && + strcmp(U.pythondir, "/") != 0 && strcmp(U.pythondir, "//") != 0) + { + char upythondir[FILE_MAXDIR]; + + BLI_strncpy(upythondir, U.pythondir, FILE_MAXDIR); + BLI_convertstringcode(upythondir, G.sce, 0); + fprintf( fp, "# User defined scripts dir: %s\n", upythondir ); + } + + for( i = 0; i < PYMENU_TOTAL; i++ ) { + pymenu = BPyMenuTable[i]; + if( !pymenu ) + continue; + fprintf( fp, "\n%s {\n", BPyMenu_group_itoa( (short)i ) ); + while( pymenu ) { + fprintf( fp, "'%s' %d %s %d", pymenu->name, + pymenu->version, pymenu->filename, + pymenu->dir ); + if( pymenu->tooltip ) + fprintf( fp, " '%s'\n", pymenu->tooltip ); + else + fprintf( fp, "\n" ); + smenu = pymenu->submenus; + while( smenu ) { + fprintf( fp, "|_%s: %s\n", smenu->name, + smenu->arg ); + smenu = smenu->next; + } + pymenu = pymenu->next; + } + fprintf( fp, "}\n" ); + } + + fclose( fp ); + return; +} + +/* BPyMenu_PrintAllEntries: + * useful for debugging. + */ +void BPyMenu_PrintAllEntries( void ) +{ + BPyMenu *pymenu; + BPySubMenu *smenu; + int i; + + printf( "# Blender: registered menu entries for bpython scripts\n" ); + + for( i = 0; i < PYMENU_TOTAL; i++ ) { + pymenu = BPyMenuTable[i]; + printf( "\n%s {\n", BPyMenu_group_itoa( (short)i ) ); + while( pymenu ) { + printf( "'%s' %d %s %d", pymenu->name, pymenu->version, + pymenu->filename, pymenu->dir ); + if( pymenu->tooltip ) + printf( " '%s'\n", pymenu->tooltip ); + else + printf( "\n" ); + smenu = pymenu->submenus; + while( smenu ) { + printf( "|_%s: %s\n", smenu->name, + smenu->arg ); + smenu = smenu->next; + } + pymenu = pymenu->next; + } + printf( "}\n" ); + } +} + +/* bpymenu_ParseFile: + * recursively scans folders looking for scripts to register. + * + * This function scans the scripts directory looking for .py files with the + * right header and menu info, using that to fill the bpymenu structs. + * is_userdir defines if the script is in the default scripts dir or the + * user defined one (U.pythondir: is_userdir == 1). + * Speed is important. + * + * The first line of the script must be '#!BPY'. + * The header registration lines must appear between the first pair of + * '\"\"\"' and follow this order (the single-quotes are part of + * the format): + * + * # \"\"\"
+ * # Name: 'script name for the menu' + * # Blender: short int (minimal Blender version) + * # Group: 'group name' (defines menu) + * # Submenu: 'submenu name' related_1word_arg + * # Tooltip: 'tooltip for the menu' + * # \"\"\" + * + * Notes: + * + * - Commenting out header lines with "#" is optional, but recommended. + * - There may be more than one submenu line, or none: + * submenus and the tooltip are optional; + * - The Blender version is the same number reported by + * Blender.Get('version') in BPython or G.version in C; + * - Line length must be less than 99. + */ +static int bpymenu_ParseFile(FILE *file, char *fname, int is_userdir) +{ + char line[100]; + char head[100]; + char middle[100]; + char tail[100]; + int matches; + int parser_state; + + char script_name[100]; + int script_version = 1; + int script_group; + + BPyMenu *scriptMenu = NULL; + + if (file != NULL) { + parser_state = 1; /* state of parser, 0 to terminate */ + + while ((parser_state != 0) && (fgets(line, 100, file) != NULL)) { + + switch (parser_state) { + + case 1: /* !BPY */ + if (strncmp(line, "#!BPY", 5) == 0) { + parser_state++; + } else { + parser_state = 0; + } + break; + + case 2: /* \"\"\" */ + if ((strstr(line, "\"\"\""))) { + parser_state++; + } + break; + + case 3: /* Name: 'script name for the menu' */ + matches = sscanf(line, "%[^']'%[^']'%c", head, script_name, tail); + if ((matches == 3) && (strstr(head, "Name:") != NULL)) { + parser_state++; + } else { + if (DEBUG) + fprintf(stderr, "BPyMenus error: Wrong 'Name' line: %s\n", fname); + parser_state = 0; + } + break; + + case 4: /* Blender: */ + matches = sscanf(line, "%[^1234567890]%i%c", head, &script_version, + tail); + if (matches == 3) { + parser_state++; + } else { + if (DEBUG) + fprintf(stderr,"BPyMenus error: Wrong 'Blender' line: %s\n",fname); + parser_state = 0; + } + break; + + case 5: /* Group: 'group name' */ + matches = sscanf(line, "%[^']'%[^']'%c", head, middle, tail); + if ((matches == 3) && (strstr(head, "Group:") != NULL)) { + script_group = bpymenu_group_atoi(middle); + if (script_group < 0) { + if (DEBUG) + fprintf(stderr, "BPyMenus error: Unknown group \"%s\": %s\n", + middle, fname); + parser_state = 0; + } + + else { /* register script */ + scriptMenu = bpymenu_AddEntry((short)script_group, + (short int)script_version, script_name, fname, is_userdir,NULL); + if (scriptMenu == NULL) { + if (DEBUG) + fprintf(stderr, + "BPyMenus error: Couldn't create entry for: %s\n", fname); + parser_state = 0; + } else { + parser_state++; + } + } + + } else { + if (DEBUG) + fprintf(stderr, "BPyMenus error: Wrong 'Group' line: %s\n",fname); + parser_state = 0; + } + break; + + case 6: /* optional elements */ + /* Submenu: 'submenu name' related_1word_arg */ + matches = sscanf(line, "%[^']'%[^']'%s\n", head, middle, tail); + if ((matches == 3) && (strstr(head, "Submenu:") != NULL)) { + bpymenu_AddSubEntry(scriptMenu, middle, tail); + } else { + /* Tooltip: 'tooltip for the menu */ + matches = sscanf(line, "%[^']'%[^']'%c", head, middle, tail); + if ((matches == 3) && ((strstr(head, "Tooltip:") != NULL) || + (strstr(head, "Tip:") != NULL))) { + bpymenu_set_tooltip(scriptMenu, middle); + } + parser_state = 0; + } + break; + + default: + parser_state = 0; + break; + } + } + } + + else { /* shouldn't happen, it's checked in bpymenus_ParseDir */ + if (DEBUG) + fprintf(stderr, "BPyMenus error: Couldn't open %s.\n", fname); + return -1; + } + + return 0; +} + +/* bpymenu_ParseDir: + * recursively scans folders looking for scripts to register. + * + * This function scans the scripts directory looking for .py files with the + * right header and menu info. + * - is_userdir defines if the script is in the default scripts dir or the + * user defined one (U.pythondir: is_userdir == 1); + * - parentdir is the parent dir name to store as part of the script filename, + * if we're down a subdir. + * Speed is important. + */ +static int bpymenu_ParseDir(char *dirname, char *parentdir, int is_userdir ) +{ + DIR *dir; + FILE *file = NULL; + struct dirent *de; + struct stat status; + char *file_extension; + char path[FILE_MAX]; + char subdir[FILE_MAX]; + char *s = NULL; + + dir = opendir(dirname); + + if (dir != NULL) { + while ((de = readdir(dir)) != NULL) { + + /* skip files and dirs starting with '.' or 'bpy' */ + if ((de->d_name[0] == '.') || !strncmp(de->d_name, "bpy", 3)) { + continue; + } + + BLI_make_file_string("/", path, dirname, de->d_name); + + if (stat(path, &status) != 0) { + if (DEBUG) + fprintf(stderr, "stat %s failed: %s\n", path, strerror(errno)); + } + + if (S_ISREG(status.st_mode)) { /* is file */ + + file_extension = strstr(de->d_name, ".py"); + + if (file_extension && *(file_extension + 3) == '\0') { + file = fopen(path, "rb"); + + if (file) { + s = de->d_name; + if (parentdir) { + /* Join parentdir and de->d_name */ + BLI_join_dirfile(subdir, parentdir, de->d_name); + + s = subdir; + } + bpymenu_ParseFile(file, s, is_userdir); + fclose(file); + } + + else { + if (DEBUG) + fprintf(stderr, "BPyMenus error: Couldn't open %s.\n", path); + } + } + } + + else if (S_ISDIR(status.st_mode)) { /* is subdir */ + Dirs_Number++; + Dir_Depth++; + if (Dirs_Number > MAX_DIR_NUMBER) { + if (DEBUG) { + fprintf(stderr, "BPyMenus error: too many subdirs.\n"); + } + closedir(dir); + return -1; + } + else if (Dir_Depth > MAX_DIR_DEPTH) { + if (DEBUG) + fprintf(stderr, + "BPyMenus error: max depth reached traversing dir tree.\n"); + closedir(dir); + return -1; + } + s = de->d_name; + if (parentdir) { + /* Join parentdir and de->d_name */ + BLI_join_dirfile(subdir, parentdir, de->d_name); + s = subdir; + } + if (bpymenu_ParseDir(path, s, is_userdir) == -1) { + closedir(dir); + return -1; + } + Dir_Depth--; + } + + } + closedir(dir); + } + + else { /* open directory stream failed */ + if (DEBUG) + fprintf(stderr, "opendir %s failed: %s\n", dirname, strerror(errno)); + return -1; + } + + return 0; +} + +static int bpymenu_GetStatMTime( char *name, int is_file, time_t * mtime ) +{ + struct stat st; + int result; + + result = stat( name, &st ); + + if( result == -1 ) + return -1; + + if( is_file ) { + if( !S_ISREG( st.st_mode ) ) + return -2; + } else if( !S_ISDIR( st.st_mode ) ) + return -2; + + *mtime = st.st_mtime; + + return 0; +} + +/* BPyMenu_Init: + * import the bpython menus data to Blender, either from: + * - the BPYMENU_DATAFILE file (?/.blender/Bpymenus) or + * - the scripts dir(s), case newer than the datafile (then update the file). + * then fill the bpymenu table with this data. + * if param usedir != 0, then the data is recreated from the dir(s) anyway. +*/ +int BPyMenu_Init( int usedir ) +{ + char fname[FILE_MAXDIR]; + char dirname[FILE_MAXDIR]; + char upythondir[FILE_MAXDIR]; + char *upydir = U.pythondir, *sdir = NULL; + time_t time_dir1 = 0, time_dir2 = 0, time_file = 0; + int stat_dir1 = 0, stat_dir2 = 0, stat_file = 0; + int i; + + DEBUG = G.f & G_DEBUG; /* is Blender in debug mode (started with -d) ? */ + + /* init global bpymenu table (it is a list of pointers to struct BPyMenus + * for each available group: import, export, etc.) */ + for( i = 0; i < PYMENU_TOTAL; i++ ) + BPyMenuTable[i] = NULL; + + if( DEBUG ) + fprintf(stdout, "\nRegistering scripts in Blender menus ...\n\n" ); + + if( U.pythondir[0] == '\0') { + upydir = NULL; + } + else if (strcmp(U.pythondir, "/") == 0 || strcmp(U.pythondir, "//") == 0) { + /* these are not accepted to prevent possible slight slowdowns on startup; + * they should not be used as user defined scripts dir, anyway, also from + * speed considerations, since they'd not be dedicated scripts dirs */ + if (DEBUG) fprintf(stderr, + "BPyMenus: invalid user defined Python scripts dir: \"/\" or \"//\".\n"); + upydir = NULL; + } + else { + BLI_strncpy(upythondir, upydir, FILE_MAXDIR); + BLI_convertstringcode(upythondir, G.sce, 0); + } + + sdir = bpy_gethome(1); + + if (sdir) { + BLI_strncpy(dirname, sdir, FILE_MAXDIR); + stat_dir1 = bpymenu_GetStatMTime( dirname, 0, &time_dir1 ); + + if( stat_dir1 < 0 ) { + time_dir1 = 0; + if( DEBUG ) { + fprintf(stderr, + "\nDefault scripts dir: %s:\n%s\n", dirname, strerror(errno)); + if( upydir ) + fprintf(stdout, + "Getting scripts menu data from user defined dir: %s.\n", + upythondir ); + } + } + } + else stat_dir1 = -1; + + if( upydir ) { + stat_dir2 = bpymenu_GetStatMTime( upythondir, 0, &time_dir2 ); + + if( stat_dir2 < 0 ) { + time_dir2 = 0; + upydir = NULL; + if( DEBUG ) + fprintf(stderr, "\nUser defined scripts dir: %s:\n%s.\n", + upythondir, strerror( errno ) ); + if( stat_dir1 < 0 ) { + if( DEBUG ) + fprintf(stderr, "\ +To have scripts in menus, please add them to the default scripts dir:\n\ +%s\n\ +and / or go to 'Info window -> File Paths tab' and set a valid path for\n\ +the user defined Python scripts dir.\n", dirname ); + return -1; + } + } + } + else stat_dir2 = -1; + + if( ( stat_dir1 < 0 ) && ( stat_dir2 < 0 ) ) { + if( DEBUG ) { + fprintf(stderr, "\nCannot register scripts in menus, no scripts dir" + " available.\nExpected default dir at: %s \n", dirname ); + } + return -1; + } + + if (usedir) stat_file = -1; + else { /* if we're not forced to use the dir */ + char *homedir = bpy_gethome(0); + + if (homedir) { + BLI_make_file_string( "/", fname, homedir, BPYMENU_DATAFILE ); + stat_file = bpymenu_GetStatMTime( fname, 1, &time_file ); + if( stat_file < 0 ) + time_file = 0; + + /* comparing dates */ + + if((stat_file == 0) + && (time_file > time_dir1) && (time_file > time_dir2)) + { /* file is newer */ + stat_file = bpymenu_CreateFromFile( ); /* -1 if an error occurred */ + if( !stat_file && DEBUG ) + fprintf(stdout, + "Getting menu data for scripts from file:\n%s\n\n", fname ); + } + else stat_file = -1; + } + else stat_file = -1; /* -1 to use dirs: didn't use file or it was corrupted */ + } + + if( stat_file == -1 ) { /* use dirs */ + if( DEBUG ) { + fprintf(stdout, + "Getting menu data for scripts from dir(s):\ndefault: %s\n", dirname ); + if( upydir ) + fprintf(stdout, "user defined: %s\n", upythondir ); + fprintf(stdout, "\n"); + } + if( stat_dir1 == 0 ) { + i = bpymenu_ParseDir( dirname, NULL, 0 ); + if (i == -1 && DEBUG) + fprintf(stderr, "Default scripts dir does not seem valid.\n\n"); + } + if( stat_dir2 == 0 ) { + BLI_strncpy(dirname, U.pythondir, FILE_MAXDIR); + BLI_convertstringcode(dirname, G.sce, 0); + i = bpymenu_ParseDir( dirname, NULL, 1 ); + if (i == -1 && DEBUG) + fprintf(stderr, "User defined scripts dir does not seem valid.\n\n"); + } + + /* check if we got any data */ + for( i = 0; i < PYMENU_TOTAL; i++ ) + if( BPyMenuTable[i] ) + break; + + /* if we got, recreate the file */ + if( i < PYMENU_TOTAL ) + bpymenu_WriteDataFile( ); + else if( DEBUG ) { + fprintf(stderr, "\n\ +Warning: Registering scripts in menus -- no info found.\n\ +Either your scripts dirs have no .py scripts or the scripts\n\ +don't have a header with registration data.\n\ +Default scripts dir is:\n\ +%s\n", dirname ); + if( upydir ) + fprintf(stderr, "User defined scripts dir is: %s\n", + upythondir ); + } + } + + return 0; +} diff --git a/source/blender/python/BPY_menus.h b/source/blender/python/BPY_menus.h new file mode 100644 index 00000000000..89491ce3ef2 --- /dev/null +++ b/source/blender/python/BPY_menus.h @@ -0,0 +1,128 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano, Matt Ebb + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef BPY_MENUS_H +#define BPY_MENUS_H + +/* This header exposes BPyMenu related public declarations. The implementation + * adds 'dynamic' menus to Blender, letting scripts register themselves in any + * of a few pre-defined (trivial to upgrade) places in menus. These places or + * slots are called groups here (Import, Export, etc). This is how it works: + * - scripts at dirs user pref U.pythondir and .blender/scripts/ are scanned + * for registration info. + * - this data is also saved to a Bpymenus file at the user's .blender/ dir and + * only re-created when the scripts folder gets modified. + * - on start-up Blender uses this info to fill a table, which is used to + * create the menu entries when they are needed (see header_info.c or + * header_script.c, under source/blender/src/, for examples). +*/ + +/* These two structs hold py menu/submenu info. + * BPyMenu holds a script's name (as should appear in the menu) and filename, + * plus an optional list of submenus. Each submenu is related to a string + * (arg) that the script can get from the __script__ pydict, to know which + * submenu was chosen. */ + +typedef struct BPySubMenu { + char *name; + char *arg; + struct BPySubMenu *next; +} BPySubMenu; + +typedef struct BPyMenu { + char *name; + char *filename; + char *tooltip; + short version; /* Blender version */ + int dir; /* 0: default, 1: U.pythondir */ + struct BPySubMenu *submenus; + struct BPyMenu *next; +} BPyMenu; + +/* Scripts can be added to only a few pre-defined places in menus, like + * File->Import, File->Export, etc. (for speed and better control). + * To make a new menu 'slot' available for scripts: + * - add an entry to the enum below, before PYMENU_TOTAL, of course; + * - update the bpymenu_group_atoi() and BPyMenu_group_itoa() functions in + * BPY_menus.c; + * - add the necessary code to the header_***.c file in + * source/blender/src/, like done in header_info.c for import/export; +*/ +typedef enum { + PYMENU_ADD,/* creates new objects */ + PYMENU_ANIMATION, + PYMENU_EXPORT, + PYMENU_IMPORT, + PYMENU_MATERIALS, + PYMENU_MESH, + PYMENU_MISC, + PYMENU_OBJECT, + PYMENU_RENDER,/* exporters to external renderers */ + PYMENU_SYSTEM, + PYMENU_THEMES, + PYMENU_UV,/* UV editing tools, to go in UV/Image editor space, 'UV' menu */ + PYMENU_IMAGE,/* Image editing tools, to go in UV/Image editor space, 'Image' menu */ + PYMENU_WIZARDS,/* complex 'app' scripts */ + + /* entries put after Wizards don't appear at the Scripts win->Scripts menu; + * see define right below */ + + PYMENU_FACESELECT, + PYMENU_WEIGHTPAINT, + PYMENU_VERTEXPAINT, + PYMENU_UVCALCULATION, + PYMENU_ARMATURE, + PYMENU_SCRIPTTEMPLATE, + PYMENU_HELP,/*Main Help menu items - prob best to leave for 'official' ones*/ + PYMENU_HELPSYSTEM,/* Resources, troubleshooting, system tools */ + PYMENU_HELPWEBSITES,/* Help -> Websites submenu */ + PYMENU_MESHFACEKEY, /* face key in mesh editmode */ + PYMENU_ADDMESH, /* adds mesh */ + PYMENU_TOTAL +} PYMENUHOOKS; + +#define PYMENU_SCRIPTS_MENU_TOTAL (PYMENU_WIZARDS + 1) + +/* BPyMenuTable holds all registered pymenus, as linked lists for each menu + * where they can appear (see PYMENUHOOKS enum above). +*/ +extern BPyMenu *BPyMenuTable[]; /* defined in BPY_menus.c */ + +/* public functions: */ +int BPyMenu_Init( int usedir ); +void BPyMenu_RemoveAllEntries( void ); +void BPyMenu_PrintAllEntries( void ); +char *BPyMenu_CreatePupmenuStr( BPyMenu * pym, short group ); +char *BPyMenu_group_itoa( short group ); +struct BPyMenu *BPyMenu_GetEntry( short group, short pos ); + +#endif /* BPY_MENUS_H */ diff --git a/source/blender/python/CMakeLists.txt b/source/blender/python/CMakeLists.txt new file mode 100644 index 00000000000..7df1f8a02d5 --- /dev/null +++ b/source/blender/python/CMakeLists.txt @@ -0,0 +1,57 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +FILE(GLOB SRC api2_2x/*.c) +SET(SRC ${SRC} + BPY_interface.c + BPY_menus.c +) + +SET(INC + api2_2x ../blenkernel ../blenlib ../blenloader + ../render/extern/include ../radiosity/extern/include + ../makesdna ../../../intern/guardedalloc ../../../intern/bmfont ../imbuf ../include + ${PYTHON_INC} +) + +IF(WITH_QUICKTIME) + SET(INC ${INC} ${QUICKTIME_INC}) + ADD_DEFINITIONS(-DWITH_QUICKTIME) +ENDIF(WITH_QUICKTIME) + +IF(WITH_OPENEXR) + ADD_DEFINITIONS(-DWITH_OPENEXR) +ENDIF(WITH_OPENEXR) + +IF(WITH_FFMPEG) + ADD_DEFINITIONS(-DWITH_FFMPEG) +ENDIF(WITH_FFMPEG) + +BLENDERLIB_NOLIST(blender_python "${SRC}" "${INC}") +#env.BlenderLib ( libname='blender_python', sources = Split(sources), includes = Split(incs), defines = defs, libtype=['core','game2'], priority = [60,115] ) diff --git a/source/blender/python/Makefile b/source/blender/python/Makefile new file mode 100644 index 00000000000..149e40092f3 --- /dev/null +++ b/source/blender/python/Makefile @@ -0,0 +1,37 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# Bounces make to subdirectories. + +SOURCEDIR = source/blender/python +DIRS = api2_2x + +include nan_subdirs.mk diff --git a/source/blender/python/SConscript b/source/blender/python/SConscript new file mode 100644 index 00000000000..9cd245394b0 --- /dev/null +++ b/source/blender/python/SConscript @@ -0,0 +1,26 @@ +#!/usr/bin/python +Import ('env') + +sources = Split('BPY_interface.c BPY_menus.c') + env.Glob('api2_2x/*.c') + +incs = 'api2_2x ../blenkernel ../blenlib ../blenloader' +incs += ' ../render/extern/include ../radiosity/extern/include' +incs += ' ../makesdna #intern/guardedalloc #intern/bmfont ../imbuf ../include' +incs += ' ' + env['BF_PYTHON_INC'] +incs += ' ' + env['BF_OPENGL_INC'] + +defs = [] +if env['OURPLATFORM'] in ('win32-mingw') and env['BF_DEBUG']: + defs.append('Py_TRACE_REFS') + +if env['WITH_BF_QUICKTIME']==1: + incs += ' ' + env['BF_QUICKTIME_INC'] + defs.append('WITH_QUICKTIME') + +if env['WITH_BF_OPENEXR'] == 1: + defs.append('WITH_OPENEXR') + +if env['WITH_BF_FFMPEG'] == 1: + defs.append('WITH_FFMPEG') + +env.BlenderLib ( libname='blender_python', sources = Split(sources), includes = Split(incs), defines = defs, libtype=['core','game2'], priority = [60,115] ) diff --git a/source/blender/python/api2_2x/Armature.c b/source/blender/python/api2_2x/Armature.c new file mode 100644 index 00000000000..6c22e831bd4 --- /dev/null +++ b/source/blender/python/api2_2x/Armature.c @@ -0,0 +1,1490 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#include + +#include "Armature.h" //This must come first + +#include "BKE_main.h" +#include "BKE_global.h" +#include "BKE_armature.h" +#include "BKE_library.h" +#include "BKE_depsgraph.h" +#include "BKE_utildefines.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "MEM_guardedalloc.h" +#include "Bone.h" +#include "NLA.h" +#include "gen_utils.h" +#include "gen_library.h" + +#include "DNA_object_types.h" //This must come before BIF_editarmature.h... +#include "BIF_editarmature.h" + +//------------------EXTERNAL PROTOTYPES-------------------- +extern void make_boneList(ListBase* list, ListBase *bones, EditBone *parent); +extern void editbones_to_armature (ListBase *list, Object *ob); + +//------------------------ERROR CODES--------------------------------- +//This is here just to make me happy and to have more consistant error strings :) +static const char sBoneDictError[] = "ArmatureType.bones - Error: "; +static const char sBoneDictBadArgs[] = "ArmatureType.bones - Bad Arguments: "; +static const char sArmatureError[] = "ArmatureType - Error: "; +static const char sArmatureBadArgs[] = "ArmatureType - Bad Arguments: "; +static const char sModuleError[] = "Blender.Armature - Error: "; +static const char sModuleBadArgs[] = "Blender.Armature - Bad Arguments: "; + +PyObject * arm_weakref_callback_weakref_dealloc(PyObject *self, PyObject *weakref); +/* python callable */ +PyObject * arm_weakref_callback_weakref_dealloc__pyfunc; + +//################## BonesDict_Type (internal) ######################## +/*This is an internal psuedo-dictionary type that allows for manipulation +* of bones inside of an armature. It is a subobject of armature. +* i.e. Armature.bones['key']*/ +//##################################################################### + +//------------------METHOD IMPLEMENTATIONS----------------------------- +//------------------------Armature.bones.items() +//Returns a list of key:value pairs like dict.items() +static PyObject* BonesDict_items(BPy_BonesDict *self) +{ + if (self->editmode_flag){ + return PyDict_Items(self->editbonesMap); + }else{ + return PyDict_Items(self->bonesMap); + } +} +//------------------------Armature.bones.keys() +//Returns a list of keys like dict.keys() +static PyObject* BonesDict_keys(BPy_BonesDict *self) +{ + if (self->editmode_flag){ + return PyDict_Keys(self->editbonesMap); + }else{ + return PyDict_Keys(self->bonesMap); + } +} +//------------------------Armature.bones.values() +//Returns a list of values like dict.values() +static PyObject* BonesDict_values(BPy_BonesDict *self) +{ + if (self->editmode_flag){ + return PyDict_Values(self->editbonesMap); + }else{ + return PyDict_Values(self->bonesMap); + } +} +//------------------ATTRIBUTE IMPLEMENTATION--------------------------- +//------------------TYPE_OBECT IMPLEMENTATION----------------------- +//------------------------tp_doc +//The __doc__ string for this object +static char BPy_BonesDict_doc[] = "This is an internal subobject of armature\ +designed to act as a Py_Bone dictionary."; + +//------------------------tp_methods +//This contains a list of all methods the object contains +static PyMethodDef BPy_BonesDict_methods[] = { + {"items", (PyCFunction) BonesDict_items, METH_NOARGS, + "() - Returns the key:value pairs from the dictionary"}, + {"keys", (PyCFunction) BonesDict_keys, METH_NOARGS, + "() - Returns the keys the dictionary"}, + {"values", (PyCFunction) BonesDict_values, METH_NOARGS, + "() - Returns the values from the dictionary"}, + {NULL, NULL, 0, NULL} +}; +//-----------------(internal) +static int BoneMapping_Init(PyObject *dictionary, ListBase *bones){ + Bone *bone = NULL; + PyObject *py_bone = NULL; + + for (bone = bones->first; bone; bone = bone->next){ + py_bone = PyBone_FromBone(bone); + if (!py_bone) + return -1; + + if(PyDict_SetItemString(dictionary, bone->name, py_bone) == -1) { + /* unlikely but possible */ + Py_DECREF(py_bone); + return -1; + } + + Py_DECREF(py_bone); + if (bone->childbase.first) + BoneMapping_Init(dictionary, &bone->childbase); + } + return 0; +} +//-----------------(internal) +static int EditBoneMapping_Init(PyObject *dictionary, ListBase *editbones){ + EditBone *editbone = NULL; + PyObject *py_editbone = NULL; + + for (editbone = editbones->first; editbone; editbone = editbone->next){ + py_editbone = PyEditBone_FromEditBone(editbone); + if (!py_editbone) + return -1; + + if(PyDict_SetItemString(dictionary, editbone->name, py_editbone) == -1) { + Py_DECREF(py_editbone); + return -1; + } + Py_DECREF(py_editbone); + } + return 0; +} +//----------------- BonesDict_InitBones +static int BonesDict_InitBones(BPy_BonesDict *self) +{ + PyDict_Clear(self->bonesMap); + if (BoneMapping_Init(self->bonesMap, self->bones) == -1) + return 0; + return 1; +} +//----------------- BonesDict_InitEditBones +static int BonesDict_InitEditBones(BPy_BonesDict *self) +{ + PyDict_Clear(self->editbonesMap); + if (EditBoneMapping_Init(self->editbonesMap, &self->editbones) == -1) + return 0; + return 1; +} +//------------------------tp_repr +//This is the string representation of the object +static PyObject *BonesDict_repr(BPy_BonesDict *self) +{ + char str[2048]; + PyObject *key, *value; + int pos = 0; + char *p = str; + char *keys, *vals; + + p += sprintf(str, "[Bone Dict: {"); + + if (self->editmode_flag){ + while (PyDict_Next(self->editbonesMap, &pos, &key, &value)) { + keys = PyString_AsString(key); + vals = PyString_AsString(value->ob_type->tp_repr(value)); + if( strlen(str) + strlen(keys) + strlen(vals) < sizeof(str)-20 ) + p += sprintf(p, "%s : %s, ", keys, vals ); + else { + p += sprintf(p, "...." ); + break; + } + } + }else{ + while (PyDict_Next(self->bonesMap, &pos, &key, &value)) { + keys = PyString_AsString(key); + vals = PyString_AsString(value->ob_type->tp_repr(value)); + if( strlen(str) + strlen(keys) + strlen(vals) < sizeof(str)-20 ) + p += sprintf(p, "%s : %s, ", keys, vals ); + else { + p += sprintf(p, "...." ); + break; + } + } + } + sprintf(p, "}]"); + return PyString_FromString(str); +} + +//------------------------tp_dealloc +//This tells how to 'tear-down' our object when ref count hits 0 +static void BonesDict_dealloc(BPy_BonesDict * self) +{ + Py_DECREF(self->bonesMap); + Py_DECREF(self->editbonesMap); + BLI_freelistN(&self->editbones); + PyObject_DEL( self ); + return; +} +//------------------------mp_length +//This gets the size of the dictionary +static int BonesDict_len(BPy_BonesDict *self) +{ + if (self->editmode_flag){ + return BLI_countlist(&self->editbones); + }else{ + return BLI_countlist(self->bones); + } +} +//-----------------------mp_subscript +//This defines getting a bone from the dictionary - x = Bones['key'] +static PyObject *BonesDict_GetItem(BPy_BonesDict *self, PyObject* key) +{ + PyObject *value = NULL; + + if (self->editmode_flag){ + value = PyDict_GetItem(self->editbonesMap, key); + }else{ + value = PyDict_GetItem(self->bonesMap, key); + } + if(value == NULL){ /* item not found in dict. throw exception */ + char* key_str = PyString_AsString( key ); + if (key_str) { + return EXPP_ReturnPyObjError(PyExc_KeyError, "bone key must be a string" ); + } else { + char buffer[128]; + PyOS_snprintf( buffer, sizeof(buffer), "bone %s not found", key_str); + return EXPP_ReturnPyObjError(PyExc_KeyError, buffer ); + } + } + return EXPP_incr_ret(value); +} +//-----------------------mp_ass_subscript +//This does dict assignment - Bones['key'] = value +static int BonesDict_SetItem(BPy_BonesDict *self, PyObject *key, PyObject *value) +{ + BPy_EditBone *editbone_for_deletion; + struct EditBone *editbone = NULL; + char *key_str = PyString_AsString(key); + + if (!self->editmode_flag) + return EXPP_intError(PyExc_AttributeError, "%s%s", + sBoneDictBadArgs, "You must call makeEditable() first"); + + if (!key_str) + return EXPP_intError(PyExc_AttributeError, "%s%s", + sBoneDictBadArgs, "The key must be the name of an editbone"); + + if (value && !EditBoneObject_Check(value)) + return EXPP_intError(PyExc_AttributeError, "%s%s", + sBoneDictBadArgs, "Can only assign editbones as values"); + + //parse value for assignment + if (value){ /* we know this must be an editbone from the above check */ + //create a new editbone + editbone = MEM_callocN(sizeof(EditBone), "eBone"); + BLI_strncpy(editbone->name, key_str, 32); + unique_editbone_name(NULL, editbone->name); + editbone->dist = ((BPy_EditBone*)value)->dist; + editbone->ease1 = ((BPy_EditBone*)value)->ease1; + editbone->ease2 = ((BPy_EditBone*)value)->ease2; + editbone->flag = ((BPy_EditBone*)value)->flag; + editbone->parent = ((BPy_EditBone*)value)->parent; + editbone->rad_head = ((BPy_EditBone*)value)->rad_head; + editbone->rad_tail = ((BPy_EditBone*)value)->rad_tail; + editbone->roll = ((BPy_EditBone*)value)->roll; + editbone->segments = ((BPy_EditBone*)value)->segments; + editbone->weight = ((BPy_EditBone*)value)->weight; + editbone->xwidth = ((BPy_EditBone*)value)->xwidth; + editbone->zwidth = ((BPy_EditBone*)value)->zwidth; + VECCOPY(editbone->head, ((BPy_EditBone*)value)->head); + VECCOPY(editbone->tail, ((BPy_EditBone*)value)->tail); + editbone->layer= ((BPy_EditBone*)value)->layer; + + //set object pointer + ((BPy_EditBone*)value)->editbone = editbone; + + //fix the bone's head position if flags indicate that it is 'connected' + if (editbone->flag & BONE_CONNECTED){ + if(!editbone->parent){ + ((BPy_EditBone*)value)->editbone = NULL; + MEM_freeN(editbone); + return EXPP_intError(PyExc_AttributeError, "%s%s", + sBoneDictBadArgs, "The 'connected' flag is set but the bone has no parent!"); + }else{ + VECCOPY(editbone->head, editbone->parent->tail); + } + } + + //set in editbonelist + BLI_addtail(&self->editbones, editbone); + + //set the new editbone in the mapping + if(PyDict_SetItemString(self->editbonesMap, key_str, value) == -1){ + ((BPy_EditBone*)value)->editbone = NULL; + BLI_freelinkN(&self->editbones, editbone); + return EXPP_intError(PyExc_RuntimeError, "%s%s", + sBoneDictError, "Unable to access dictionary!"); + } + }else { + //they are trying to delete the bone using 'del' + editbone_for_deletion = (BPy_EditBone*)PyDict_GetItem(self->editbonesMap, key); + + if (!editbone_for_deletion) + return EXPP_intError(PyExc_KeyError, "%s%s%s%s", + sBoneDictError, "The key: ", key_str, " is not present in this dictionary!"); + + /*first kill the datastruct then remove the item from the dict + and wait for GC to pick it up. + We have to delete the datastruct here because the tp_dealloc + doesn't handle it*/ + + /*this is ugly but you have to set the parent to NULL for else + editbones_to_armature will crash looking for this bone*/ + for (editbone = self->editbones.first; editbone; editbone = editbone->next){ + if (editbone->parent == editbone_for_deletion->editbone) { + editbone->parent = NULL; + /* remove the connected flag or else the 'root' ball + * doesn't get drawn */ + editbone->flag &= ~BONE_CONNECTED; + } + } + BLI_freelinkN(&self->editbones, editbone_for_deletion->editbone); + if(PyDict_DelItem(self->editbonesMap, key) == -1) + return EXPP_intError(PyExc_RuntimeError, "%s%s", + sBoneDictError, "Unable to access dictionary!"); + } + return 0; +} +//------------------TYPE_OBJECT DEFINITION-------------------------- +//Mapping Protocol +static PyMappingMethods BonesDict_MapMethods = { + (inquiry) BonesDict_len, //mp_length + (binaryfunc)BonesDict_GetItem, //mp_subscript + (objobjargproc)BonesDict_SetItem, //mp_ass_subscript +}; +//BonesDict TypeObject +PyTypeObject BonesDict_Type = { + PyObject_HEAD_INIT(NULL) //tp_head + 0, //tp_internal + "BonesDict", //tp_name + sizeof(BPy_BonesDict), //tp_basicsize + 0, //tp_itemsize + (destructor)BonesDict_dealloc, //tp_dealloc + 0, //tp_print + 0, //tp_getattr + 0, //tp_setattr + 0, //tp_compare + (reprfunc) BonesDict_repr, //tp_repr + 0, //tp_as_number + 0, //tp_as_sequence + &BonesDict_MapMethods, //tp_as_mapping + 0, //tp_hash + 0, //tp_call + 0, //tp_str + 0, //tp_getattro + 0, //tp_setattro + 0, //tp_as_buffer + Py_TPFLAGS_DEFAULT, //tp_flags + BPy_BonesDict_doc, //tp_doc + 0, //tp_traverse + 0, //tp_clear + 0, //tp_richcompare + 0, //tp_weaklistoffset + 0, //tp_iter + 0, //tp_iternext + BPy_BonesDict_methods, //tp_methods + 0, //tp_members + 0, //tp_getset + 0, //tp_base + 0, //tp_dict + 0, //tp_descr_get + 0, //tp_descr_set + 0, //tp_dictoffset + 0, //tp_init + 0, //tp_alloc + 0, //tp_new + 0, //tp_free + 0, //tp_is_gc + 0, //tp_bases + 0, //tp_mro + 0, //tp_cache + 0, //tp_subclasses + 0, //tp_weaklist + 0 //tp_del +}; +//-----------------------PyBonesDict_FromPyArmature +static PyObject *PyBonesDict_FromPyArmature(BPy_Armature *py_armature) +{ + BPy_BonesDict *py_BonesDict = (BPy_BonesDict *)PyObject_NEW( BPy_BonesDict, &BonesDict_Type ); + if (!py_BonesDict) + goto RuntimeError; + + py_BonesDict->bones = NULL; + py_BonesDict->editbones.first = py_BonesDict->editbones.last = NULL; + + //create internal dictionaries + py_BonesDict->bonesMap = PyDict_New(); + py_BonesDict->editbonesMap = PyDict_New(); + if (!py_BonesDict->bonesMap || !py_BonesDict->editbonesMap) + goto RuntimeError; + + //set listbase pointer + py_BonesDict->bones = &py_armature->armature->bonebase; + + //now that everything is setup - init the mappings + if (!BonesDict_InitBones(py_BonesDict)) + goto RuntimeError; + if (!BonesDict_InitEditBones(py_BonesDict)) + goto RuntimeError; + + //set editmode flag + py_BonesDict->editmode_flag = 0; + + return (PyObject*)py_BonesDict; + +RuntimeError: + return EXPP_objError(PyExc_RuntimeError, "%s%s", + sBoneDictError, "Failed to create class"); +} + +//######################### Armature_Type ############################# +/*This type represents a thin wrapper around bArmature data types +* internal to blender. It contains the psuedo-dictionary BonesDict +* as an assistant in manipulating it's own bone collection*/ +//################################################################# + +//------------------METHOD IMPLEMENTATION------------------------------ +//------------------------Armature.makeEditable() +static PyObject *Armature_makeEditable(BPy_Armature *self) +{ + if (self->armature->flag & ARM_EDITMODE) + goto AttributeError; + + make_boneList(&self->Bones->editbones, self->Bones->bones, NULL); + if (!BonesDict_InitEditBones(self->Bones)) + return NULL; + self->Bones->editmode_flag = 1; + return EXPP_incr_ret(Py_None); + +AttributeError: + return EXPP_objError(PyExc_AttributeError, "%s%s", + sArmatureBadArgs, "The armature cannot be placed manually in editmode before you call makeEditable()!"); +} + +//------------------------Armature.update() +//This is a bit ugly because you need an object link to do this +static PyObject *Armature_update(BPy_Armature *self) +{ + Object *obj = NULL; + + for (obj = G.main->object.first; obj; obj = obj->id.next){ + if (obj->data == self->armature) + break; + } + if (obj){ + editbones_to_armature (&self->Bones->editbones, obj); + if (!BonesDict_InitBones(self->Bones)) + return NULL; + self->Bones->editmode_flag = 0; + BLI_freelistN(&self->Bones->editbones); + }else{ + goto AttributeError; + + } + return EXPP_incr_ret(Py_None); + +AttributeError: + return EXPP_objError(PyExc_AttributeError, "%s%s", + sArmatureBadArgs, "The armature must be linked to an object before you can save changes!"); +} + +//------------------------Armature.__copy__() +static PyObject *Armature_copy(BPy_Armature *self) +{ + PyObject *py_armature = NULL; + bArmature *bl_armature; + bl_armature= copy_armature(self->armature); + bl_armature->id.us= 0; + py_armature= Armature_CreatePyObject( bl_armature ); + return py_armature; +} + +//------------------ATTRIBUTE IMPLEMENTATION--------------------------- +//------------------------Armature.autoIK (getter) +static PyObject *Armature_getAutoIK(BPy_Armature *self, void *closure) +{ + if (self->armature->flag & ARM_AUTO_IK) + return EXPP_incr_ret(Py_True); + else + return EXPP_incr_ret(Py_False); +} +//------------------------Armature.autoIK (setter) +static int Armature_setAutoIK(BPy_Armature *self, PyObject *value, void *closure) +{ + if(value){ + if(PyBool_Check(value)){ + if (value == Py_True){ + self->armature->flag |= ARM_AUTO_IK; + return 0; + }else if (value == Py_False){ + self->armature->flag &= ~ARM_AUTO_IK; + return 0; + } + } + } + goto AttributeError; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s", + sArmatureBadArgs, "Expects True or False"); +} +//------------------------Armature.layers (getter) +static PyObject *Armature_getLayers(BPy_Armature *self, void *closure) +{ + int layers, bit = 0, val = 0; + PyObject *item = NULL, *laylist = PyList_New( 0 ); + + if( !laylist ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create pylist!" ); + + layers = self->armature->layer; + + while( bit < 20 ) { + val = 1 << bit; + if( layers & val ) { + item = Py_BuildValue( "i", bit + 1 ); + PyList_Append( laylist, item ); + Py_DECREF( item ); + } + bit++; + } + return laylist; +} +//------------------------Armature.layer (setter) +static int Armature_setLayers(BPy_Armature *self, PyObject *value, void *closure) +{ + if(value){ + if(PyList_Check(value)){ + int layers = 0, len_list = 0; + int val; + PyObject *item = NULL; + + len_list = PyList_Size(value); + + if( len_list == 0 ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "list can't be empty, at least one layer must be set" ); + + while( len_list ) { + --len_list; + item = PyList_GetItem( value, len_list ); + if( !PyInt_Check( item ) ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "list must contain only integer numbers" ); + + val = ( int ) PyInt_AsLong( item ); + if( val < 1 || val > 20 ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "layer values must be in the range [1, 20]" ); + + layers |= 1 << ( val - 1 ); + } + + /* update any bases pointing to our object */ + self->armature->layer = (short)layers; + + return 0; + } + } + goto AttributeError; + +AttributeError: + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a list of integers" ); +} + +//------------------------Armature.mirrorEdit (getter) +static PyObject *Armature_getMirrorEdit(BPy_Armature *self, void *closure) +{ + if (self->armature->flag & ARM_MIRROR_EDIT) + return EXPP_incr_ret(Py_True); + else + return EXPP_incr_ret(Py_False); +} +//------------------------Armature.mirrorEdit (setter) +static int Armature_setMirrorEdit(BPy_Armature *self, PyObject *value, void *closure) +{ + if(value){ + if(PyBool_Check(value)){ + if (value == Py_True){ + self->armature->flag |= ARM_MIRROR_EDIT; + return 0; + }else if (value == Py_False){ + self->armature->flag &= ~ARM_MIRROR_EDIT; + return 0; + } + } + } + goto AttributeError; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s", + sArmatureBadArgs, "Expects True or False"); +} +//------------------------Armature.drawType (getter) +static PyObject *Armature_getDrawType(BPy_Armature *self, void *closure) +{ + if (self->armature->drawtype == ARM_OCTA){ + return EXPP_GetModuleConstant("Blender.Armature", "OCTAHEDRON") ; + }else if (self->armature->drawtype == ARM_LINE){ + return EXPP_GetModuleConstant("Blender.Armature", "STICK") ; + }else if (self->armature->drawtype == ARM_B_BONE){ + return EXPP_GetModuleConstant("Blender.Armature", "BBONE") ; + }else if (self->armature->drawtype == ARM_ENVELOPE){ + return EXPP_GetModuleConstant("Blender.Armature", "ENVELOPE") ; + }else{ + goto RuntimeError; + } + +RuntimeError: + return EXPP_objError(PyExc_RuntimeError, "%s%s%s", + sArmatureError, "drawType: ", "Internal failure!"); +} +//------------------------Armature.drawType (setter) +static int Armature_setDrawType(BPy_Armature *self, PyObject *value, void *closure) +{ + PyObject *val = NULL, *name = NULL; + long numeric_value; + + if(value){ + if(BPy_Constant_Check(value)){ + name = PyDict_GetItemString(((BPy_constant*)value)->dict, "name"); + if (!STREQ2(PyString_AsString(name), "OCTAHEDRON", "STICK") && + !STREQ2(PyString_AsString(name), "BBONE", "ENVELOPE")) + goto ValueError; + val = PyDict_GetItemString(((BPy_constant*)value)->dict, "value"); + if (PyInt_Check(val)){ + numeric_value = PyInt_AS_LONG(val); + self->armature->drawtype = (int)numeric_value; + return 0; + } + } + } + goto AttributeError; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s", + sArmatureBadArgs, "Expects module constant"); + +ValueError: + return EXPP_intError(PyExc_AttributeError, "%s%s", + sArmatureBadArgs, "Argument must be the constant OCTAHEDRON, STICK, BBONE, or ENVELOPE"); +} +//------------------------Armature.ghostStep (getter) +static PyObject *Armature_getStep(BPy_Armature *self, void *closure) +{ + return PyInt_FromLong((long)self->armature->ghostsize); +} +//------------------------Armature.ghostStep (setter) +static int Armature_setStep(BPy_Armature *self, PyObject *value, void *closure) +{ + long numerical_value; + + if(value){ + if(PyInt_Check(value)){ + numerical_value = PyInt_AS_LONG(value); + if (numerical_value > 20.0f || numerical_value < 1.0f) + goto ValueError; + self->armature->ghostsize = (short)numerical_value; + return 0; + } + } + goto AttributeError; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s", + sArmatureBadArgs, "Expects Integer"); + +ValueError: + return EXPP_intError(PyExc_AttributeError, "%s%s", + sArmatureBadArgs, "Argument must fall within 1-20"); +} +//------------------------Armature.ghost (getter) +static PyObject *Armature_getGhost(BPy_Armature *self, void *closure) +{ + return PyInt_FromLong((long)self->armature->ghostep); +} +//------------------------Armature.ghost (setter) +static int Armature_setGhost(BPy_Armature *self, PyObject *value, void *closure) +{ + long numerical_value; + + if(value){ + if(PyInt_Check(value)){ + numerical_value = PyInt_AS_LONG(value); + if (numerical_value > 30.0f || numerical_value < 0.0f) + goto ValueError; + self->armature->ghostep = (short)numerical_value; + return 0; + } + } + goto AttributeError; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s", + sArmatureBadArgs, "Expects Integer"); + +ValueError: + return EXPP_intError(PyExc_AttributeError, "%s%s", + sArmatureBadArgs, "Argument must fall within 0-30"); +} +//------------------------Armature.drawNames (getter) +static PyObject *Armature_getDrawNames(BPy_Armature *self, void *closure) +{ + if (self->armature->flag & ARM_DRAWNAMES) + return EXPP_incr_ret(Py_True); + else + return EXPP_incr_ret(Py_False); +} +//------------------------Armature.drawNames (setter) +static int Armature_setDrawNames(BPy_Armature *self, PyObject *value, void *closure) +{ + if(value){ + if(PyBool_Check(value)){ + if (value == Py_True){ + self->armature->flag |= ARM_DRAWNAMES; + return 0; + }else if (value == Py_False){ + self->armature->flag &= ~ARM_DRAWNAMES; + return 0; + } + } + } + goto AttributeError; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s", + sArmatureBadArgs, "Expects True or False"); +} +//------------------------Armature.drawAxes (getter) +static PyObject *Armature_getDrawAxes(BPy_Armature *self, void *closure) +{ + if (self->armature->flag & ARM_DRAWAXES) + return EXPP_incr_ret(Py_True); + else + return EXPP_incr_ret(Py_False); +} +//------------------------Armature.drawAxes (setter) +static int Armature_setDrawAxes(BPy_Armature *self, PyObject *value, void *closure) +{ + if(value){ + if(PyBool_Check(value)){ + if (value == Py_True){ + self->armature->flag |= ARM_DRAWAXES; + return 0; + }else if (value == Py_False){ + self->armature->flag &= ~ARM_DRAWAXES; + return 0; + } + } + } + goto AttributeError; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s", + sArmatureBadArgs, "Expects True or False"); +} +//------------------------Armature.delayDeform (getter) +static PyObject *Armature_getDelayDeform(BPy_Armature *self, void *closure) +{ + if (self->armature->flag & ARM_DELAYDEFORM) + return EXPP_incr_ret(Py_True); + else + return EXPP_incr_ret(Py_False); +} +//------------------------Armature.delayDeform (setter) +static int Armature_setDelayDeform(BPy_Armature *self, PyObject *value, void *closure) +{ + if(value){ + if(PyBool_Check(value)){ + if (value == Py_True){ + self->armature->flag |= ARM_DELAYDEFORM; + return 0; + }else if (value == Py_False){ + self->armature->flag &= ~ARM_DELAYDEFORM; + return 0; + } + } + } + goto AttributeError; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s", + sArmatureBadArgs, "Expects True or False"); +} +//------------------------Armature.restPosition (getter) +static PyObject *Armature_getRestPosition(BPy_Armature *self, void *closure) +{ + if (self->armature->flag & ARM_RESTPOS) + return EXPP_incr_ret(Py_True); + else + return EXPP_incr_ret(Py_False); +} +//------------------------Armature.restPosition (setter) +static int Armature_setRestPosition(BPy_Armature *self, PyObject *value, void *closure) +{ + if(value){ + if(PyBool_Check(value)){ + if (value == Py_True){ + self->armature->flag |= ARM_RESTPOS; + return 0; + }else if (value == Py_False){ + self->armature->flag &= ~ARM_RESTPOS; + return 0; + } + } + } + goto AttributeError; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s", + sArmatureBadArgs, "Expects True or False"); +} +//------------------------Armature.envelopes (getter) +static PyObject *Armature_getEnvelopes(BPy_Armature *self, void *closure) +{ + if (self->armature->deformflag & ARM_DEF_ENVELOPE) + return EXPP_incr_ret(Py_True); + else + return EXPP_incr_ret(Py_False); +} +//------------------------Armature.envelopes (setter) +static int Armature_setEnvelopes(BPy_Armature *self, PyObject *value, void *closure) +{ + if(value){ + if(PyBool_Check(value)){ + if (value == Py_True){ + self->armature->deformflag |= ARM_DEF_ENVELOPE; + return 0; + }else if (value == Py_False){ + self->armature->deformflag &= ~ARM_DEF_ENVELOPE; + return 0; + } + } + } + goto AttributeError; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s", + sArmatureBadArgs, "Expects True or False"); +} +//------------------------Armature.vertexGroups (getter) +static PyObject *Armature_getVertexGroups(BPy_Armature *self, void *closure) +{ + if (self->armature->deformflag & ARM_DEF_VGROUP) + return EXPP_incr_ret(Py_True); + else + return EXPP_incr_ret(Py_False); +} +//------------------------Armature.vertexGroups (setter) +static int Armature_setVertexGroups(BPy_Armature *self, PyObject *value, void *closure) +{ + if(value){ + if(PyBool_Check(value)){ + if (value == Py_True){ + self->armature->deformflag |= ARM_DEF_VGROUP; + return 0; + }else if (value == Py_False){ + self->armature->deformflag &= ~ARM_DEF_VGROUP; + return 0; + } + } + } + goto AttributeError; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s", + sArmatureBadArgs, "Expects True or False"); +} + +//------------------------Armature.bones (getter) +//Gets the name of the armature +static PyObject *Armature_getBoneDict(BPy_Armature *self, void *closure) +{ + return EXPP_incr_ret((PyObject*)self->Bones); +} +//------------------------Armature.bones (setter) +//Sets the name of the armature +/*TODO*/ +/*Copy Bones through x = y*/ +static int Armature_setBoneDict(BPy_Armature *self, PyObject *value, void *closure) +{ + goto AttributeError; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s", + sArmatureError, "You are not allowed to change the .Bones attribute"); +} + +//------------------------Bone.layerMask (get) +static PyObject *Armature_getLayerMask(BPy_Armature *self) +{ + /* do this extra stuff because the short's bits can be negative values */ + unsigned short laymask = 0; + laymask |= self->armature->layer; + return PyInt_FromLong((int)laymask); +} +//------------------------Bone.layerMask (set) +static int Armature_setLayerMask(BPy_Armature *self, PyObject *value) +{ + int laymask; + if (!PyInt_Check(value)) { + return EXPP_ReturnIntError( PyExc_AttributeError, + "expected an integer (bitmask) as argument" ); + } + + laymask = PyInt_AsLong(value); + + if (laymask <= 0 || laymask > (1<<16) - 1) + return EXPP_ReturnIntError( PyExc_AttributeError, + "bitmask must have from 1 up to 16 bits set"); + + self->armature->layer = 0; + self->armature->layer |= laymask; + + return 0; +} + +//------------------TYPE_OBECT IMPLEMENTATION-------------------------- +//------------------------tp_doc +//The __doc__ string for this object +static char BPy_Armature_doc[] = "This object wraps a Blender Armature object."; +//------------------------tp_methods +//This contains a list of all methods the object contains +static PyMethodDef BPy_Armature_methods[] = { + {"makeEditable", (PyCFunction) Armature_makeEditable, METH_NOARGS, + "() - Unlocks the ability to modify armature bones"}, + {"update", (PyCFunction) Armature_update, METH_NOARGS, + "() - Rebuilds the armature based on changes to bones since the last call to makeEditable"}, + {"__copy__", (PyCFunction) Armature_copy, METH_NOARGS, + "() - Return a copy of the armature."}, + {"copy", (PyCFunction) Armature_copy, METH_NOARGS, + "() - Return a copy of the armature."}, + {NULL, NULL, 0, NULL} +}; +//------------------------tp_getset +//This contains methods for attributes that require checking +static PyGetSetDef BPy_Armature_getset[] = { + GENERIC_LIB_GETSETATTR, + {"bones", (getter)Armature_getBoneDict, (setter)Armature_setBoneDict, + "The armature's Bone dictionary", NULL}, + {"vertexGroups", (getter)Armature_getVertexGroups, (setter)Armature_setVertexGroups, + "Enable/Disable vertex group defined deformation", NULL}, + {"envelopes", (getter)Armature_getEnvelopes, (setter)Armature_setEnvelopes, + "Enable/Disable bone envelope defined deformation", NULL}, + {"restPosition", (getter)Armature_getRestPosition, (setter)Armature_setRestPosition, + "Show armature rest position - disables posing", NULL}, + {"delayDeform", (getter)Armature_getDelayDeform, (setter)Armature_setDelayDeform, + "Don't deform children when manipulating bones in pose mode", NULL}, + {"drawAxes", (getter)Armature_getDrawAxes, (setter)Armature_setDrawAxes, + "Enable/Disable drawing the bone axes", NULL}, + {"drawNames", (getter)Armature_getDrawNames, (setter)Armature_setDrawNames, + "Enable/Disable drawing the bone names", NULL}, + {"ghost", (getter)Armature_getGhost, (setter)Armature_setGhost, + "Draw a number of ghosts around the current frame for current Action", NULL}, + {"ghostStep", (getter)Armature_getStep, (setter)Armature_setStep, + "The number of frames between ghost instances", NULL}, + {"drawType", (getter)Armature_getDrawType, (setter)Armature_setDrawType, + "The type of drawing currently applied to the armature", NULL}, + {"mirrorEdit", (getter)Armature_getMirrorEdit, (setter)Armature_setMirrorEdit, + "Enable/Disable X-axis mirrored editing", NULL}, + {"autoIK", (getter)Armature_getAutoIK, (setter)Armature_setAutoIK, + "Adds temporal IK chains while grabbing bones", NULL}, + {"layers", (getter)Armature_getLayers, (setter)Armature_setLayers, + "List of layers for the armature", NULL}, + {"layerMask", (getter)Armature_getLayerMask, (setter)Armature_setLayerMask, + "Layer bitmask", NULL }, + {NULL, NULL, NULL, NULL, NULL} +}; +//------------------------tp_new +//This methods creates a new object (note it does not initialize it - only the building) +//This can be called through python by myObject.__new__() however, tp_init is not called +static PyObject *Armature_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + BPy_Armature *py_armature = NULL; + bArmature *bl_armature; + + bl_armature = add_armature("Armature"); + if(bl_armature) { + bl_armature->id.us = 0; // return count to 0 - add_armature() inc'd it + + py_armature = (BPy_Armature*)type->tp_alloc(type, 0); //*new* + if (py_armature == NULL) + goto RuntimeError; + + py_armature->armature = bl_armature; + + //create armature.bones + py_armature->Bones = (BPy_BonesDict*)PyBonesDict_FromPyArmature(py_armature); + if (!py_armature->Bones) + goto RuntimeError; + + } else { + goto RuntimeError; + } + return (PyObject*)py_armature; + +RuntimeError: + return EXPP_objError(PyExc_RuntimeError, "%s%s%s", + sArmatureError, " __new__: ", "couldn't create Armature Data in Blender"); +} +//------------------------tp_init +//This methods does initialization of the new object +//This method will get called in python by 'myObject(argument, keyword=value)' +//tp_new will be automatically called before this +static int Armature_init(BPy_Armature *self, PyObject *args, PyObject *kwds) +{ + char buf[21]; + char *name = "myArmature"; + static char *kwlist[] = {"name", NULL}; + + if(!PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist, &name)){ + goto AttributeError; + } + + //rename the armature if a name is supplied + if(!BLI_streq(name, "myArmature")){ + PyOS_snprintf(buf, sizeof(buf), "%s", name); + rename_id(&self->armature->id, buf); + } + return 0; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sArmatureBadArgs, " __init__: ", "Expects string(name)"); +} + + +/*****************************************************************************/ +/* Function: Armature_compare */ +/* Description: This is a callback function for the BPy_Armature type. It */ +/* compares two Armature_Type objects. Only the "==" and "!=" */ +/* comparisons are meaninful. Returns 0 for equality and -1 if */ +/* they don't point to the same Blender Object struct. */ +/* In Python it becomes 1 if they are equal, 0 otherwise. */ +/*****************************************************************************/ +static int Armature_compare( BPy_Armature * a, BPy_Armature * b ) +{ + return ( a->armature == b->armature ) ? 0 : -1; +} + +//------------------------tp_repr +//This is the string representation of the object +static PyObject *Armature_repr(BPy_Armature *self) +{ + return PyString_FromFormat( "[Armature: \"%s\"]", self->armature->id.name + 2 ); //*new* +} +//------------------------tp_dealloc +//This tells how to 'tear-down' our object when ref count hits 0 +///tp_dealloc +static void Armature_dealloc(BPy_Armature * self) +{ + if (self->weaklist != NULL) + PyObject_ClearWeakRefs((PyObject *) self); /* this causes the weakref dealloc func to be called */ + + Py_DECREF(self->Bones); + PyObject_DEL( self ); +} +//------------------TYPE_OBECT DEFINITION-------------------------- +PyTypeObject Armature_Type = { + PyObject_HEAD_INIT(NULL) //tp_head + 0, //tp_internal + "Armature", //tp_name + sizeof(BPy_Armature), //tp_basicsize + 0, //tp_itemsize + (destructor)Armature_dealloc, //tp_dealloc + 0, //tp_print + 0, //tp_getattr + 0, //tp_setattr + (cmpfunc) Armature_compare, //tp_compare + (reprfunc) Armature_repr, //tp_repr + 0, //tp_as_number + 0, //tp_as_sequence + 0, //tp_as_mapping + ( hashfunc ) GenericLib_hash, //tp_hash + 0, //tp_call + 0, //tp_str + 0, //tp_getattro + 0, //tp_setattro + 0, //tp_as_buffer + Py_TPFLAGS_DEFAULT| Py_TPFLAGS_HAVE_WEAKREFS, //tp_flags + BPy_Armature_doc, //tp_doc + 0, //tp_traverse + 0, //tp_clear + 0, //tp_richcompare + offsetof(BPy_Armature, weaklist), //tp_weaklistoffset + 0, //tp_iter + 0, //tp_iternext + BPy_Armature_methods, //tp_methods + 0, //tp_members + BPy_Armature_getset, //tp_getset + 0, //tp_base + 0, //tp_dict + 0, //tp_descr_get + 0, //tp_descr_set + 0, //tp_dictoffset + (initproc)Armature_init, //tp_init + 0, //tp_alloc + (newfunc)Armature_new, //tp_new + 0, //tp_free + 0, //tp_is_gc + 0, //tp_bases + 0, //tp_mro + 0, //tp_cache + 0, //tp_subclasses + 0, //tp_weaklist + 0 //tp_del +}; + +//-------------------MODULE METHODS IMPLEMENTATION------------------------ +//----------------Blender.Armature.Get() +/* This function will return a Py_Armature when a single string is passed +* or else it will return a {key:value} dictionary when mutliple strings are passed +* or it will return a {key:value} dictionary of all armatures when nothing is passed */ +static PyObject *M_Armature_Get(PyObject * self, PyObject * args) +{ + PyObject *seq = NULL, *item = NULL, *dict = NULL, *py_armature = NULL; + char *name = "", buffer[24]; + int size = 0, i; + void *data; + + //GET ARGUMENTS - () ('s') ('s',..) (['s',..]) are exceptable + size = PySequence_Length(args); + if (size == 1) { + seq = PySequence_GetItem(args, 0); //*new* + if (!seq) + goto RuntimeError; + if(!PyString_Check(seq)){ + if (PySequence_Check(seq)) { + size = PySequence_Length(seq); + } else { + Py_DECREF(seq); + goto AttributeError; + } + } + } else { + seq = EXPP_incr_ret(args); //*take ownership* + } + //'seq' should be a list, empty tuple or string - check list for strings + if(!PyString_Check(seq)){ + for(i = 0; i < size; i++){ + item = PySequence_GetItem(seq, i); //*new* + if (!item) { + Py_DECREF(seq); + goto RuntimeError; + } + if(!PyString_Check(item)){ + EXPP_decr2(item, seq); + goto AttributeError; + } + Py_DECREF(item); + } + } + + //GET ARMATURES + if(size != 1){ + dict = PyDict_New(); //*new* + if(!dict){ + Py_DECREF(seq); + goto RuntimeError; + } + if(size == 0){ //GET ALL ARMATURES + data = G.main->armature.first; //get the first data ID from the armature library + while (data){ + py_armature = Armature_CreatePyObject(data); //*new* + if (!py_armature) { + EXPP_decr2(seq, dict); + return NULL; /* error is set from Armature_CreatePyObject */ + } + sprintf(buffer, "%s", ((bArmature*)data)->id.name +2); + if(PyDict_SetItemString(dict, buffer, py_armature) == -1){ //add to dictionary + EXPP_decr3(seq, dict, py_armature); + goto RuntimeError; + } + Py_DECREF(py_armature); + data = ((ID*)data)->next; + } + Py_DECREF(seq); + }else{ //GET ARMATURE LIST + for (i = 0; i < size; i++) { + item = PySequence_GetItem(seq, i); //*new* + name = PyString_AsString(item); + Py_DECREF(item); + data = find_id("AR", name); //get data from library + if (data != NULL){ + py_armature = Armature_CreatePyObject(data); //*new* + if (!py_armature) { + EXPP_decr2(seq, dict); + return NULL; /* error is set from Armature_CreatePyObject */ + } + + if(PyDict_SetItemString(dict, name, py_armature) == -1){ //add to dictionary + EXPP_decr3(seq, dict, py_armature); + goto RuntimeError; + } + Py_DECREF(py_armature); + }else{ + if(PyDict_SetItemString(dict, name, Py_None) == -1){ //add to dictionary + EXPP_decr2(seq, dict); + goto RuntimeError; + } + Py_DECREF(Py_None); + } + } + Py_DECREF(seq); + } + return dict; + }else{ //GET SINGLE ARMATURE + if(!PyString_Check(seq)){ //This handles the bizarre case where (['s']) is passed + item = PySequence_GetItem(seq, 0); //*new* + name = PyString_AsString(item); + Py_DECREF(item); + }else{ + name = PyString_AsString(seq); + } + Py_DECREF(seq); + data = find_id("AR", name); //get data from library + if (data != NULL){ + return Armature_CreatePyObject(data); //*new* + }else{ + char buffer[128]; + PyOS_snprintf( buffer, sizeof(buffer), + "Armature \"%s\" not found", name); + return EXPP_ReturnPyObjError( PyExc_ValueError, + buffer ); + } + } + +RuntimeError: + return EXPP_objError(PyExc_RuntimeError, "%s%s%s", + sModuleError, "Get(): ", "Internal Error Ocurred"); + +AttributeError: + return EXPP_objError(PyExc_AttributeError, "%s%s%s", + sModuleBadArgs, "Get(): ", "- Expects (optional) string sequence"); +} + + +//----------------Blender.Armature.New() +static PyObject *M_Armature_New(PyObject * self, PyObject * args) +{ + char *name = "Armature"; + struct bArmature *armature; + BPy_Armature *obj; + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected nothing or a string as argument" ); + + armature= add_armature(name); + armature->id.us = 0; + obj = (BPy_Armature *)Armature_CreatePyObject(armature); /*new*/ + + if( !obj ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyObject_New() failed" ); + + obj->armature = armature; + return (PyObject *)obj; +} + + +//-------------------MODULE METHODS DEFINITION----------------------------- + +static char M_Armature_Get_doc[] = "(name) - return the armature with the name 'name', \ + returns None if not found.\n If 'name' is not specified, it returns a list of all \ + armatures in the\ncurrent scene."; + +static char M_Armature_New_doc[] = "(name) - return a new armature object."; + +struct PyMethodDef M_Armature_methods[] = { + {"Get", M_Armature_Get, METH_VARARGS, M_Armature_Get_doc}, + {"New", M_Armature_New, METH_VARARGS, M_Armature_New_doc}, + {NULL, NULL, 0, NULL} +}; +//------------------VISIBLE PROTOTYPE IMPLEMENTATION----------------------- +//------------------------Armature_RebuildEditbones (internal) +PyObject * Armature_RebuildEditbones(PyObject *pyarmature) +{ + return Armature_makeEditable((BPy_Armature*)pyarmature); +} + +//------------------------Armature_RebuildBones (internal) +PyObject *Armature_RebuildBones(PyObject *pyarmature) +{ + return Armature_update((BPy_Armature*)pyarmature); +} + +/* internal func to remove weakref from weakref list */ +PyObject * arm_weakref_callback_weakref_dealloc(PyObject *self, PyObject *weakref) +{ + char *list_name = ARM_WEAKREF_LIST_NAME; + PyObject *maindict = NULL, *armlist = NULL; + int i; + + maindict= PyModule_GetDict(PyImport_AddModule( "__main__")); + armlist = PyDict_GetItemString(maindict, list_name); + if( !armlist){ + printf("Oops - update_armature_weakrefs()\n"); + Py_RETURN_NONE; + } + + i = PySequence_Index(armlist, weakref); + if (i==-1) { + printf("callback weakref internal error, weakref not in list\n\tthis should never happen.\n"); + Py_RETURN_NONE; + } + PySequence_DelItem(armlist, i); + Py_RETURN_NONE; +} + +/*-----------------(internal) + * Converts a bArmature to a PyArmature */ + +PyObject *Armature_CreatePyObject(struct bArmature *armature) +{ + BPy_Armature *py_armature = NULL; + PyObject *maindict = NULL, *weakref = NULL; + PyObject *armlist = NULL; /* list of armature weak refs */ + char *list_name = ARM_WEAKREF_LIST_NAME; + int i; + + //put a weakreference in __main__ + maindict= PyModule_GetDict(PyImport_AddModule( "__main__")); + + armlist = PyDict_GetItemString(maindict, list_name); + if(!armlist) { + printf("Oops - can't get the armature weakref list\n"); + goto RuntimeError; + } + + /* see if we alredy have it */ + for (i=0; i< PyList_Size(armlist); i++) { + py_armature = (BPy_Armature *)PyWeakref_GetObject(PyList_GET_ITEM(armlist, i)); + if (BPy_Armature_Check(py_armature) && py_armature->armature == armature) { + Py_INCREF(py_armature); + /*printf("reusing armature\n");*/ + return (PyObject *)py_armature; + } + } + + + /*create armature type*/ + py_armature = PyObject_NEW( BPy_Armature, &Armature_Type ); + + if (!py_armature){ + printf("Oops - can't create py armature\n"); + goto RuntimeError; + } + + py_armature->armature = armature; + py_armature->weaklist = NULL; //init the weaklist + + //create armature.bones + py_armature->Bones = (BPy_BonesDict*)PyBonesDict_FromPyArmature(py_armature); + if (!py_armature->Bones){ + printf("Oops - creating armature.bones\n"); + goto RuntimeError; + } + + weakref = PyWeakref_NewRef((PyObject*)py_armature, arm_weakref_callback_weakref_dealloc__pyfunc); + if (PyList_Append(armlist, weakref) == -1){ + printf("Oops - list-append failed\n"); + goto RuntimeError; + } + Py_DECREF(weakref); + + return (PyObject *) py_armature; + +RuntimeError: + return EXPP_objError(PyExc_RuntimeError, "%s%s%s", + sModuleError, "Armature_CreatePyObject: ", "Internal Error Ocurred"); +} +//-----------------(internal) +//Converts a PyArmature to a bArmature +struct bArmature *PyArmature_AsArmature(BPy_Armature *py_armature) +{ + return (py_armature->armature); +} + +struct bArmature *Armature_FromPyObject( PyObject * py_obj ) +{ + return PyArmature_AsArmature((BPy_Armature*)py_obj); +} + +/* internal use only */ +static PyMethodDef bpy_arm_weakref_callback_weakref_dealloc[] = { + {"arm_weakref_callback_weakref_dealloc", arm_weakref_callback_weakref_dealloc, METH_O, ""} +}; + +//-------------------MODULE INITIALIZATION-------------------------------- +PyObject *Armature_Init(void) +{ + PyObject *module, *dict; + + //Initializes TypeObject.ob_type + if (PyType_Ready(&Armature_Type) < 0 || PyType_Ready(&BonesDict_Type) < 0 || + PyType_Ready(&EditBone_Type) < 0 || PyType_Ready(&Bone_Type) < 0) { + return EXPP_incr_ret(Py_None); + } + + /* Weakref management - used for callbacks so we can + * tell when a callback has been removed that a UI button referenced */ + arm_weakref_callback_weakref_dealloc__pyfunc = PyCFunction_New(bpy_arm_weakref_callback_weakref_dealloc, NULL); + + + //Register the module + module = Py_InitModule3("Blender.Armature", M_Armature_methods, + "The Blender Armature module"); + + //Add TYPEOBJECTS to the module + PyModule_AddObject(module, "Armature", + EXPP_incr_ret((PyObject *)&Armature_Type)); //*steals* + PyModule_AddObject(module, "Bone", + EXPP_incr_ret((PyObject *)&Bone_Type)); //*steals* + PyModule_AddObject(module, "Editbone", + EXPP_incr_ret((PyObject *)&EditBone_Type)); //*steals* + + //Add CONSTANTS to the module + PyModule_AddObject(module, "CONNECTED", + PyConstant_NewInt("CONNECTED", BONE_CONNECTED)); + PyModule_AddObject(module, "HINGE", + PyConstant_NewInt("HINGE", BONE_HINGE)); + PyModule_AddObject(module, "NO_DEFORM", + PyConstant_NewInt("NO_DEFORM", BONE_NO_DEFORM)); + PyModule_AddObject(module, "MULTIPLY", + PyConstant_NewInt("MULTIPLY", BONE_MULT_VG_ENV)); + PyModule_AddObject(module, "HIDDEN_EDIT", + PyConstant_NewInt("HIDDEN_EDIT", BONE_HIDDEN_A)); + PyModule_AddObject(module, "ROOT_SELECTED", + PyConstant_NewInt("ROOT_SELECTED", BONE_ROOTSEL)); + PyModule_AddObject(module, "BONE_SELECTED", + PyConstant_NewInt("BONE_SELECTED", BONE_SELECTED)); + PyModule_AddObject(module, "TIP_SELECTED", + PyConstant_NewInt("TIP_SELECTED", BONE_TIPSEL)); + + PyModule_AddObject(module, "OCTAHEDRON", + PyConstant_NewInt("OCTAHEDRON", ARM_OCTA)); + PyModule_AddObject(module, "STICK", + PyConstant_NewInt("STICK", ARM_LINE)); + PyModule_AddObject(module, "BBONE", + PyConstant_NewInt("BBONE", ARM_B_BONE)); + PyModule_AddObject(module, "ENVELOPE", + PyConstant_NewInt("ENVELOPE", ARM_ENVELOPE)); + + //Add SUBMODULES to the module + dict = PyModule_GetDict( module ); //borrowed + PyDict_SetItemString(dict, "NLA", NLA_Init()); //creates a *new* module + + return module; +} diff --git a/source/blender/python/api2_2x/Armature.h b/source/blender/python/api2_2x/Armature.h new file mode 100644 index 00000000000..7f543e375a1 --- /dev/null +++ b/source/blender/python/api2_2x/Armature.h @@ -0,0 +1,70 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Joseph gilbert + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_ARMATURE_H +#define EXPP_ARMATURE_H + +#include +#include "DNA_armature_types.h" + +//-------------------TYPE CHECKS--------------------------------- +#define BPy_Armature_Check(v) ((v)->ob_type == &Armature_Type) +#define BPy_BonesDict_Check(v) ((v)->ob_type == &BonesDict_Type) +//-------------------MODULE INIT--------------------------------- +PyObject *Armature_Init( void ); +//-------------------TYPEOBJECT---------------------------------- +extern PyTypeObject Armature_Type; +extern PyTypeObject BonesDict_Type; +//-------------------STRUCT DEFINITION--------------------------- +typedef struct { + PyObject_HEAD + PyObject *bonesMap; //wrapper for bones + PyObject *editbonesMap; //wrapper for editbones + ListBase *bones; //pointer to armature->bonebase + ListBase editbones; //allocated list of EditBones + short editmode_flag; //1 = in , 0 = not in +} BPy_BonesDict; + +typedef struct { + PyObject_HEAD + struct bArmature * armature; + BPy_BonesDict *Bones; //BPy_BonesDict + PyObject *weaklist; +} BPy_Armature; + +//-------------------VISIBLE PROTOTYPES------------------------- +PyObject *Armature_CreatePyObject(struct bArmature *armature); +struct bArmature *PyArmature_AsArmature(BPy_Armature *py_armature); +PyObject * Armature_RebuildEditbones(PyObject *pyarmature); +PyObject *Armature_RebuildBones(PyObject *pyarmature); + +struct bArmature *Armature_FromPyObject( PyObject * py_obj ); + +#endif diff --git a/source/blender/python/api2_2x/BGL.c b/source/blender/python/api2_2x/BGL.c new file mode 100644 index 00000000000..56cc8c63b5f --- /dev/null +++ b/source/blender/python/api2_2x/BGL.c @@ -0,0 +1,1590 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +/* This file is the Blender.BGL part of opy_draw.c, from the old + * bpython/intern dir, with minor changes to adapt it to the new Python + * implementation. The BGL submodule "wraps" OpenGL functions and constants, + * allowing script writers to make OpenGL calls in their Python scripts. */ + +#include "BGL.h" /*This must come first */ + +#include "MEM_guardedalloc.h" +#include "gen_utils.h" + +static int type_size( int type ); +static Buffer *make_buffer( int type, int ndimensions, int *dimensions ); + +static char Method_Buffer_doc[] = + "(type, dimensions, [template]) - Create a new Buffer object\n\n\ +(type) - The format to store data in\n\ +(dimensions) - An int or sequence specifying the dimensions of the buffer\n\ +[template] - A sequence of matching dimensions to the buffer to be created\n\ + which will be used to initialize the Buffer.\n\n\ +If a template is not passed in all fields will be initialized to 0.\n\n\ +The type should be one of GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT, or GL_DOUBLE.\n\ +If the dimensions are specified as an int a linear buffer will be\n\ +created. If a sequence is passed for the dimensions the buffer\n\ +will have len(sequence) dimensions, where the size for each dimension\n\ +is determined by the value in the sequence at that index.\n\n\ +For example, passing [100, 100] will create a 2 dimensional\n\ +square buffer. Passing [16, 16, 32] will create a 3 dimensional\n\ +buffer which is twice as deep as it is wide or high."; + +static PyObject *Method_Buffer( PyObject * self, PyObject * args ); + +/* Buffer sequence methods */ + +static int Buffer_len( PyObject * self ); +static PyObject *Buffer_item( PyObject * self, int i ); +static PyObject *Buffer_slice( PyObject * self, int begin, int end ); +static int Buffer_ass_item( PyObject * self, int i, PyObject * v ); +static int Buffer_ass_slice( PyObject * self, int begin, int end, + PyObject * seq ); + +static PySequenceMethods Buffer_SeqMethods = { + ( inquiry ) Buffer_len, /*sq_length */ + ( binaryfunc ) 0, /*sq_concat */ + ( intargfunc ) 0, /*sq_repeat */ + ( intargfunc ) Buffer_item, /*sq_item */ + ( intintargfunc ) Buffer_slice, /*sq_slice */ + ( intobjargproc ) Buffer_ass_item, /*sq_ass_item */ + ( intintobjargproc ) Buffer_ass_slice, /*sq_ass_slice */ +}; + +static void Buffer_dealloc( PyObject * self ); +static PyObject *Buffer_tolist( PyObject * self ); +static PyObject *Buffer_dimensions( PyObject * self ); +static PyObject *Buffer_getattr( PyObject * self, char *name ); +static PyObject *Buffer_repr( PyObject * self ); + +PyTypeObject buffer_Type = { + PyObject_HEAD_INIT( NULL ) /* required python macro */ + 0, /*ob_size */ + "buffer", /*tp_name */ + sizeof( Buffer ), /*tp_basicsize */ + 0, /*tp_itemsize */ + ( destructor ) Buffer_dealloc, /*tp_dealloc */ + ( printfunc ) 0, /*tp_print */ + ( getattrfunc ) Buffer_getattr, /*tp_getattr */ + ( setattrfunc ) 0, /*tp_setattr */ + ( cmpfunc ) 0, /*tp_compare */ + ( reprfunc ) Buffer_repr, /*tp_repr */ + 0, /*tp_as_number */ + &Buffer_SeqMethods, /*tp_as_sequence */ +}; + +/* #ifndef __APPLE__ */ + +#define BGL_Wrap(nargs, funcname, ret, arg_list) \ +static PyObject *Method_##funcname (PyObject *self, PyObject *args) {\ + arg_def##nargs arg_list; \ + ret_def_##ret; \ + if(!PyArg_ParseTuple(args, arg_str##nargs arg_list, arg_ref##nargs arg_list)) return NULL;\ + ret_set_##ret gl##funcname (arg_var##nargs arg_list);\ + ret_ret_##ret; \ +} + +#define BGLU_Wrap(nargs, funcname, ret, arg_list) \ +static PyObject *Method_##funcname (PyObject *self, PyObject *args) {\ + arg_def##nargs arg_list; \ + ret_def_##ret; \ + if(!PyArg_ParseTuple(args, arg_str##nargs arg_list, arg_ref##nargs arg_list)) return NULL;\ + ret_set_##ret glu##funcname (arg_var##nargs arg_list);\ + ret_ret_##ret; \ +} + +/* #endif */ + +PyObject *BGL_Init( void ); + +/********/ +static int type_size(int type) +{ + switch (type) { + case GL_BYTE: + return sizeof(char); + case GL_SHORT: + return sizeof(short); + case GL_INT: + return sizeof(int); + case GL_FLOAT: + return sizeof(float); + case GL_DOUBLE: + return sizeof(double); + } + return -1; +} + +static Buffer *make_buffer(int type, int ndimensions, int *dimensions) +{ + Buffer *buffer; + void *buf= NULL; + int i, size, length; + + length= 1; + for (i=0; iparent= NULL; + buffer->ndimensions= ndimensions; + buffer->dimensions= dimensions; + buffer->type= type; + buffer->buf.asvoid= buf; + + for (i= 0; ibuf.asbyte[i]= 0; + else if (type==GL_SHORT) + buffer->buf.asshort[i]= 0; + else if (type==GL_INT) + buffer->buf.asint[i]= 0; + else if (type==GL_FLOAT) + buffer->buf.asfloat[i]= 0.0f; + else if (type==GL_DOUBLE) + buffer->buf.asdouble[i]= 0.0; + } + return buffer; +} + +static PyObject *Method_Buffer (PyObject *self, PyObject *args) +{ + PyObject *length_ob= NULL, *template= NULL; + Buffer *buffer; + + int i, type; + int *dimensions = 0, ndimensions = 0; + + if (!PyArg_ParseTuple(args, "iO|O", &type, &length_ob, &template)) + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "expected an int and one or two PyObjects"); + + if (type!=GL_BYTE && type!=GL_SHORT && type!=GL_INT && type!=GL_FLOAT && type!=GL_DOUBLE) { + PyErr_SetString(PyExc_AttributeError, "type"); + return NULL; + } + + if (PyNumber_Check(length_ob)) { + ndimensions= 1; + dimensions= MEM_mallocN(ndimensions*sizeof(int), "Buffer dimensions"); + dimensions[0]= PyInt_AsLong(length_ob); + } else if (PySequence_Check(length_ob)) { + ndimensions= PySequence_Length(length_ob); + dimensions= MEM_mallocN(ndimensions*sizeof(int), "Buffer dimensions"); + for (i=0; idimensions[0]; +} + +static PyObject *Buffer_item(PyObject *self, int i) +{ + Buffer *buf= (Buffer *) self; + + if (i >= buf->dimensions[0]) { + PyErr_SetString(PyExc_IndexError, "array index out of range"); + return NULL; + } + + if (buf->ndimensions==1) { + switch (buf->type) { + case GL_BYTE: return Py_BuildValue("b", buf->buf.asbyte[i]); + case GL_SHORT: return Py_BuildValue("h", buf->buf.asshort[i]); + case GL_INT: return Py_BuildValue("i", buf->buf.asint[i]); + case GL_FLOAT: return PyFloat_FromDouble(buf->buf.asfloat[i]); + case GL_DOUBLE: return Py_BuildValue("d", buf->buf.asdouble[i]); + } + } else { + Buffer *newbuf; + int j, length, size; + + length= 1; + for (j=1; jndimensions; j++) { + length*= buf->dimensions[j]; + } + size= type_size(buf->type); + + newbuf= (Buffer *) PyObject_NEW(Buffer, &buffer_Type); + + Py_INCREF(self); + newbuf->parent= self; + + newbuf->ndimensions= buf->ndimensions-1; + newbuf->type= buf->type; + newbuf->buf.asvoid= buf->buf.asbyte + i*length*size; + newbuf->dimensions= MEM_mallocN(newbuf->ndimensions*sizeof(int), + "Buffer dimensions"); + memcpy(newbuf->dimensions, buf->dimensions+1, + newbuf->ndimensions*sizeof(int)); + + return (PyObject *) newbuf; + } + + return NULL; +} + +static PyObject *Buffer_slice(PyObject *self, int begin, int end) +{ + Buffer *buf= (Buffer *) self; + PyObject *list; + int count; + + if (begin<0) begin= 0; + if (end>buf->dimensions[0]) + end= buf->dimensions[0]; + if (begin>end) begin= end; + + list= PyList_New(end-begin); + + for (count= begin; count= buf->dimensions[0]) { + PyErr_SetString(PyExc_IndexError, "array assignment index out of range"); + return -1; + } + + if (buf->ndimensions!=1) { + PyObject *row= Buffer_item(self, i); + int ret; + + if (!row) return -1; + ret= Buffer_ass_slice(row, 0, buf->dimensions[1], v); + Py_DECREF(row); + return ret; + } + + if (buf->type==GL_BYTE) { + if (!PyArg_Parse(v, "b;Coordinates must be ints", &buf->buf.asbyte[i])) + return -1; + } else if (buf->type==GL_SHORT) { + if (!PyArg_Parse(v, "h;Coordinates must be ints", &buf->buf.asshort[i])) + return -1; + + } else if (buf->type==GL_INT) { + if (!PyArg_Parse(v, "i;Coordinates must be ints", &buf->buf.asint[i])) + return -1; + } else if (buf->type==GL_FLOAT) { + if (!PyArg_Parse(v, "f;Coordinates must be floats", &buf->buf.asfloat[i])) + return -1; + } else if (buf->type==GL_DOUBLE) { + if (!PyArg_Parse(v, "d;Coordinates must be floats", &buf->buf.asdouble[i])) + return -1; + } + return 0; +} + +static int Buffer_ass_slice(PyObject *self, int begin, int end, PyObject *seq) +{ + Buffer *buf= (Buffer *) self; + PyObject *item; + int count, err=0; + + if (begin<0) begin= 0; + if (end>buf->dimensions[0]) end= buf->dimensions[0]; + if (begin>end) begin= end; + + if (!PySequence_Check(seq)) { + PyErr_SetString(PyExc_TypeError, + "illegal argument type for built-in operation"); + return -1; + } + + if (PySequence_Length(seq)!=(end-begin)) { + PyErr_SetString(PyExc_TypeError, "size mismatch in assignment"); + return -1; + } + + for (count= begin; countparent) Py_DECREF (buf->parent); + else MEM_freeN (buf->buf.asvoid); + + MEM_freeN (buf->dimensions); + + PyObject_DEL (self); +} + +static PyObject *Buffer_tolist(PyObject *self) +{ + int i, len= ((Buffer *)self)->dimensions[0]; + PyObject *list= PyList_New(len); + + for (i=0; indimensions); + int i; + + for (i= 0; indimensions; i++) { + PyList_SetItem(list, i, PyInt_FromLong(buffer->dimensions[i])); + } + + return list; +} + +static PyObject *Buffer_getattr(PyObject *self, char *name) +{ + if (strcmp(name, "list")==0) return Buffer_tolist(self); + else if (strcmp(name, "dimensions")==0) return Buffer_dimensions(self); + + PyErr_SetString(PyExc_AttributeError, name); + return NULL; +} + +static PyObject *Buffer_repr(PyObject *self) +{ + PyObject *list= Buffer_tolist(self); + PyObject *repr= PyObject_Repr(list); + Py_DECREF(list); + + return repr; +} + + +BGL_Wrap(2, Accum, void, (GLenum, GLfloat)) +BGL_Wrap(2, AlphaFunc, void, (GLenum, GLclampf)) +BGL_Wrap(3, AreTexturesResident, GLboolean, (GLsizei, GLuintP, GLbooleanP)) +BGL_Wrap(1, Begin, void, (GLenum)) +BGL_Wrap(2, BindTexture, void, (GLenum, GLuint)) +BGL_Wrap(7, Bitmap, void, (GLsizei, GLsizei, GLfloat, + GLfloat, GLfloat, GLfloat, GLubyteP)) +BGL_Wrap(2, BlendFunc, void, (GLenum, GLenum)) +BGL_Wrap(1, CallList, void, (GLuint)) +BGL_Wrap(3, CallLists, void, (GLsizei, GLenum, GLvoidP)) +BGL_Wrap(1, Clear, void, (GLbitfield)) +BGL_Wrap(4, ClearAccum, void, (GLfloat, GLfloat, GLfloat, GLfloat)) +BGL_Wrap(4, ClearColor, void, (GLclampf, GLclampf, GLclampf, GLclampf)) +BGL_Wrap(1, ClearDepth, void, (GLclampd)) +BGL_Wrap(1, ClearIndex, void, (GLfloat)) +BGL_Wrap(1, ClearStencil, void, (GLint)) +BGL_Wrap(2, ClipPlane, void, (GLenum, GLdoubleP)) +BGL_Wrap(3, Color3b, void, (GLbyte, GLbyte, GLbyte)) +BGL_Wrap(1, Color3bv, void, (GLbyteP)) +BGL_Wrap(3, Color3d, void, (GLdouble, GLdouble, GLdouble)) +BGL_Wrap(1, Color3dv, void, (GLdoubleP)) +BGL_Wrap(3, Color3f, void, (GLfloat, GLfloat, GLfloat)) +BGL_Wrap(1, Color3fv, void, (GLfloatP)) +BGL_Wrap(3, Color3i, void, (GLint, GLint, GLint)) +BGL_Wrap(1, Color3iv, void, (GLintP)) +BGL_Wrap(3, Color3s, void, (GLshort, GLshort, GLshort)) +BGL_Wrap(1, Color3sv, void, (GLshortP)) +BGL_Wrap(3, Color3ub, void, (GLubyte, GLubyte, GLubyte)) +BGL_Wrap(1, Color3ubv, void, (GLubyteP)) +BGL_Wrap(3, Color3ui, void, (GLuint, GLuint, GLuint)) +BGL_Wrap(1, Color3uiv, void, (GLuintP)) +BGL_Wrap(3, Color3us, void, (GLushort, GLushort, GLushort)) +BGL_Wrap(1, Color3usv, void, (GLushortP)) +BGL_Wrap(4, Color4b, void, (GLbyte, GLbyte, GLbyte, GLbyte)) +BGL_Wrap(1, Color4bv, void, (GLbyteP)) +BGL_Wrap(4, Color4d, void, (GLdouble, GLdouble, GLdouble, GLdouble)) +BGL_Wrap(1, Color4dv, void, (GLdoubleP)) +BGL_Wrap(4, Color4f, void, (GLfloat, GLfloat, GLfloat, GLfloat)) +BGL_Wrap(1, Color4fv, void, (GLfloatP)) +BGL_Wrap(4, Color4i, void, (GLint, GLint, GLint, GLint)) +BGL_Wrap(1, Color4iv, void, (GLintP)) +BGL_Wrap(4, Color4s, void, (GLshort, GLshort, GLshort, GLshort)) +BGL_Wrap(1, Color4sv, void, (GLshortP)) +BGL_Wrap(4, Color4ub, void, (GLubyte, GLubyte, GLubyte, GLubyte)) +BGL_Wrap(1, Color4ubv, void, (GLubyteP)) +BGL_Wrap(4, Color4ui, void, (GLuint, GLuint, GLuint, GLuint)) +BGL_Wrap(1, Color4uiv, void, (GLuintP)) +BGL_Wrap(4, Color4us, void, (GLushort, GLushort, GLushort, GLushort)) +BGL_Wrap(1, Color4usv, void, (GLushortP)) +BGL_Wrap(4, ColorMask, void, (GLboolean, GLboolean, GLboolean, GLboolean)) +BGL_Wrap(2, ColorMaterial, void, (GLenum, GLenum)) +BGL_Wrap(5, CopyPixels, void, (GLint, GLint, GLsizei, GLsizei, GLenum)) +BGL_Wrap(1, CullFace, void, (GLenum)) +BGL_Wrap(2, DeleteLists, void, (GLuint, GLsizei)) +BGL_Wrap(2, DeleteTextures, void, (GLsizei, GLuintP)) +BGL_Wrap(1, DepthFunc, void, (GLenum)) +BGL_Wrap(1, DepthMask, void, (GLboolean)) +BGL_Wrap(2, DepthRange, void, (GLclampd, GLclampd)) +BGL_Wrap(1, Disable, void, (GLenum)) +BGL_Wrap(1, DrawBuffer, void, (GLenum)) +BGL_Wrap(5, DrawPixels, void, (GLsizei, GLsizei, GLenum, GLenum, GLvoidP)) +BGL_Wrap(1, EdgeFlag, void, (GLboolean)) +BGL_Wrap(1, EdgeFlagv, void, (GLbooleanP)) +BGL_Wrap(1, Enable, void, (GLenum)) +BGL_Wrap(1, End, void, (void)) +BGL_Wrap(1, EndList, void, (void)) +BGL_Wrap(1, EvalCoord1d, void, (GLdouble)) +BGL_Wrap(1, EvalCoord1dv, void, (GLdoubleP)) +BGL_Wrap(1, EvalCoord1f, void, (GLfloat)) +BGL_Wrap(1, EvalCoord1fv, void, (GLfloatP)) +BGL_Wrap(2, EvalCoord2d, void, (GLdouble, GLdouble)) +BGL_Wrap(1, EvalCoord2dv, void, (GLdoubleP)) +BGL_Wrap(2, EvalCoord2f, void, (GLfloat, GLfloat)) +BGL_Wrap(1, EvalCoord2fv, void, (GLfloatP)) +BGL_Wrap(3, EvalMesh1, void, (GLenum, GLint, GLint)) +BGL_Wrap(5, EvalMesh2, void, (GLenum, GLint, GLint, GLint, GLint)) +BGL_Wrap(1, EvalPoint1, void, (GLint)) +BGL_Wrap(2, EvalPoint2, void, (GLint, GLint)) +BGL_Wrap(3, FeedbackBuffer, void, (GLsizei, GLenum, GLfloatP)) +BGL_Wrap(1, Finish, void, (void)) +BGL_Wrap(1, Flush, void, (void)) +BGL_Wrap(2, Fogf, void, (GLenum, GLfloat)) +BGL_Wrap(2, Fogfv, void, (GLenum, GLfloatP)) +BGL_Wrap(2, Fogi, void, (GLenum, GLint)) +BGL_Wrap(2, Fogiv, void, (GLenum, GLintP)) +BGL_Wrap(1, FrontFace, void, (GLenum)) +BGL_Wrap(6, Frustum, void, (GLdouble, GLdouble, + GLdouble, GLdouble, GLdouble, GLdouble)) +BGL_Wrap(1, GenLists, GLuint, (GLsizei)) +BGL_Wrap(2, GenTextures, void, (GLsizei, GLuintP)) +BGL_Wrap(2, GetBooleanv, void, (GLenum, GLbooleanP)) +BGL_Wrap(2, GetClipPlane, void, (GLenum, GLdoubleP)) +BGL_Wrap(2, GetDoublev, void, (GLenum, GLdoubleP)) +BGL_Wrap(1, GetError, GLenum, (void)) +BGL_Wrap(2, GetFloatv, void, (GLenum, GLfloatP)) +BGL_Wrap(2, GetIntegerv, void, (GLenum, GLintP)) +BGL_Wrap(3, GetLightfv, void, (GLenum, GLenum, GLfloatP)) +BGL_Wrap(3, GetLightiv, void, (GLenum, GLenum, GLintP)) +BGL_Wrap(3, GetMapdv, void, (GLenum, GLenum, GLdoubleP)) +BGL_Wrap(3, GetMapfv, void, (GLenum, GLenum, GLfloatP)) +BGL_Wrap(3, GetMapiv, void, (GLenum, GLenum, GLintP)) +BGL_Wrap(3, GetMaterialfv, void, (GLenum, GLenum, GLfloatP)) +BGL_Wrap(3, GetMaterialiv, void, (GLenum, GLenum, GLintP)) +BGL_Wrap(2, GetPixelMapfv, void, (GLenum, GLfloatP)) +BGL_Wrap(2, GetPixelMapuiv, void, (GLenum, GLuintP)) +BGL_Wrap(2, GetPixelMapusv, void, (GLenum, GLushortP)) +BGL_Wrap(1, GetPolygonStipple,void, (GLubyteP)) +BGL_Wrap(1, GetString, GLstring, (GLenum)) +BGL_Wrap(3, GetTexEnvfv, void, (GLenum, GLenum, GLfloatP)) +BGL_Wrap(3, GetTexEnviv, void, (GLenum, GLenum, GLintP)) +BGL_Wrap(3, GetTexGendv, void, (GLenum, GLenum, GLdoubleP)) +BGL_Wrap(3, GetTexGenfv, void, (GLenum, GLenum, GLfloatP)) +BGL_Wrap(3, GetTexGeniv, void, (GLenum, GLenum, GLintP)) +BGL_Wrap(5, GetTexImage, void, (GLenum, GLint, GLenum, GLenum, GLvoidP)) +BGL_Wrap(4, GetTexLevelParameterfv, void, (GLenum, GLint, GLenum, GLfloatP)) +BGL_Wrap(4, GetTexLevelParameteriv, void, (GLenum, GLint, GLenum, GLintP)) +BGL_Wrap(3, GetTexParameterfv, void, (GLenum, GLenum, GLfloatP)) +BGL_Wrap(3, GetTexParameteriv, void, (GLenum, GLenum, GLintP)) +BGL_Wrap(2, Hint, void, (GLenum, GLenum)) +BGL_Wrap(1, IndexMask, void, (GLuint)) +BGL_Wrap(1, Indexd, void, (GLdouble)) +BGL_Wrap(1, Indexdv, void, (GLdoubleP)) +BGL_Wrap(1, Indexf, void, (GLfloat)) +BGL_Wrap(1, Indexfv, void, (GLfloatP)) +BGL_Wrap(1, Indexi, void, (GLint)) +BGL_Wrap(1, Indexiv, void, (GLintP)) +BGL_Wrap(1, Indexs, void, (GLshort)) +BGL_Wrap(1, Indexsv, void, (GLshortP)) +BGL_Wrap(1, InitNames, void, (void)) +BGL_Wrap(1, IsEnabled, GLboolean, (GLenum)) +BGL_Wrap(1, IsList, GLboolean, (GLuint)) +BGL_Wrap(1, IsTexture, GLboolean, (GLuint)) +BGL_Wrap(2, LightModelf, void, (GLenum, GLfloat)) +BGL_Wrap(2, LightModelfv, void, (GLenum, GLfloatP)) +BGL_Wrap(2, LightModeli, void, (GLenum, GLint)) +BGL_Wrap(2, LightModeliv, void, (GLenum, GLintP)) +BGL_Wrap(3, Lightf, void, (GLenum, GLenum, GLfloat)) +BGL_Wrap(3, Lightfv, void, (GLenum, GLenum, GLfloatP)) +BGL_Wrap(3, Lighti, void, (GLenum, GLenum, GLint)) +BGL_Wrap(3, Lightiv, void, (GLenum, GLenum, GLintP)) +BGL_Wrap(2, LineStipple, void, (GLint, GLushort)) +BGL_Wrap(1, LineWidth, void, (GLfloat)) +BGL_Wrap(1, ListBase, void, (GLuint)) +BGL_Wrap(1, LoadIdentity, void, (void)) +BGL_Wrap(1, LoadMatrixd, void, (GLdoubleP)) +BGL_Wrap(1, LoadMatrixf, void, (GLfloatP)) +BGL_Wrap(1, LoadName, void, (GLuint)) +BGL_Wrap(1, LogicOp, void, (GLenum)) +BGL_Wrap(6, Map1d, void, (GLenum, GLdouble, GLdouble, + GLint, GLint, GLdoubleP)) +BGL_Wrap(6, Map1f, void, (GLenum, GLfloat, GLfloat, + GLint, GLint, GLfloatP)) +BGL_Wrap(10, Map2d, void, (GLenum, GLdouble, GLdouble, + GLint, GLint, GLdouble, GLdouble, GLint, GLint, GLdoubleP)) +BGL_Wrap(10, Map2f, void, (GLenum, GLfloat, GLfloat, + GLint, GLint, GLfloat, GLfloat, GLint, GLint, GLfloatP)) +BGL_Wrap(3, MapGrid1d, void, (GLint, GLdouble, GLdouble)) +BGL_Wrap(3, MapGrid1f, void, (GLint, GLfloat, GLfloat)) +BGL_Wrap(6, MapGrid2d, void, (GLint, GLdouble, GLdouble, + GLint, GLdouble, GLdouble)) +BGL_Wrap(6, MapGrid2f, void, (GLint, GLfloat, GLfloat, + GLint, GLfloat, GLfloat)) +BGL_Wrap(3, Materialf, void, (GLenum, GLenum, GLfloat)) +BGL_Wrap(3, Materialfv, void, (GLenum, GLenum, GLfloatP)) +BGL_Wrap(3, Materiali, void, (GLenum, GLenum, GLint)) +BGL_Wrap(3, Materialiv, void, (GLenum, GLenum, GLintP)) +BGL_Wrap(1, MatrixMode, void, (GLenum)) +BGL_Wrap(1, MultMatrixd, void, (GLdoubleP)) +BGL_Wrap(1, MultMatrixf, void, (GLfloatP)) +BGL_Wrap(2, NewList, void, (GLuint, GLenum)) +BGL_Wrap(3, Normal3b, void, (GLbyte, GLbyte, GLbyte)) +BGL_Wrap(1, Normal3bv, void, (GLbyteP)) +BGL_Wrap(3, Normal3d, void, (GLdouble, GLdouble, GLdouble)) +BGL_Wrap(1, Normal3dv, void, (GLdoubleP)) +BGL_Wrap(3, Normal3f, void, (GLfloat, GLfloat, GLfloat)) +BGL_Wrap(1, Normal3fv, void, (GLfloatP)) +BGL_Wrap(3, Normal3i, void, (GLint, GLint, GLint)) +BGL_Wrap(1, Normal3iv, void, (GLintP)) +BGL_Wrap(3, Normal3s, void, (GLshort, GLshort, GLshort)) +BGL_Wrap(1, Normal3sv, void, (GLshortP)) +BGL_Wrap(6, Ortho, void, (GLdouble, GLdouble, + GLdouble, GLdouble, GLdouble, GLdouble)) +BGL_Wrap(1, PassThrough, void, (GLfloat)) +BGL_Wrap(3, PixelMapfv, void, (GLenum, GLint, GLfloatP)) +BGL_Wrap(3, PixelMapuiv, void, (GLenum, GLint, GLuintP)) +BGL_Wrap(3, PixelMapusv, void, (GLenum, GLint, GLushortP)) +BGL_Wrap(2, PixelStoref, void, (GLenum, GLfloat)) +BGL_Wrap(2, PixelStorei, void, (GLenum, GLint)) +BGL_Wrap(2, PixelTransferf, void, (GLenum, GLfloat)) +BGL_Wrap(2, PixelTransferi, void, (GLenum, GLint)) +BGL_Wrap(2, PixelZoom, void, (GLfloat, GLfloat)) +BGL_Wrap(1, PointSize, void, (GLfloat)) +BGL_Wrap(2, PolygonMode, void, (GLenum, GLenum)) +BGL_Wrap(2, PolygonOffset, void, (GLfloat, GLfloat)) +BGL_Wrap(1, PolygonStipple, void, (GLubyteP)) +BGL_Wrap(1, PopAttrib, void, (void)) +BGL_Wrap(1, PopClientAttrib, void, (void)) +BGL_Wrap(1, PopMatrix, void, (void)) +BGL_Wrap(1, PopName, void, (void)) +BGL_Wrap(3, PrioritizeTextures, void, (GLsizei, GLuintP, GLclampfP)) +BGL_Wrap(1, PushAttrib, void, (GLbitfield)) +BGL_Wrap(1, PushClientAttrib, void, (GLbitfield)) +BGL_Wrap(1, PushMatrix, void, (void)) +BGL_Wrap(1, PushName, void, (GLuint)) +BGL_Wrap(2, RasterPos2d, void, (GLdouble, GLdouble)) +BGL_Wrap(1, RasterPos2dv, void, (GLdoubleP)) +BGL_Wrap(2, RasterPos2f, void, (GLfloat, GLfloat)) +BGL_Wrap(1, RasterPos2fv, void, (GLfloatP)) +BGL_Wrap(2, RasterPos2i, void, (GLint, GLint)) +BGL_Wrap(1, RasterPos2iv, void, (GLintP)) +BGL_Wrap(2, RasterPos2s, void, (GLshort, GLshort)) +BGL_Wrap(1, RasterPos2sv, void, (GLshortP)) +BGL_Wrap(3, RasterPos3d, void, (GLdouble, GLdouble, GLdouble)) +BGL_Wrap(1, RasterPos3dv, void, (GLdoubleP)) +BGL_Wrap(3, RasterPos3f, void, (GLfloat, GLfloat, GLfloat)) +BGL_Wrap(1, RasterPos3fv, void, (GLfloatP)) +BGL_Wrap(3, RasterPos3i, void, (GLint, GLint, GLint)) +BGL_Wrap(1, RasterPos3iv, void, (GLintP)) +BGL_Wrap(3, RasterPos3s, void, (GLshort, GLshort, GLshort)) +BGL_Wrap(1, RasterPos3sv, void, (GLshortP)) +BGL_Wrap(4, RasterPos4d, void, (GLdouble, GLdouble, GLdouble, GLdouble)) +BGL_Wrap(1, RasterPos4dv, void, (GLdoubleP)) +BGL_Wrap(4, RasterPos4f, void, (GLfloat, GLfloat, GLfloat, GLfloat)) +BGL_Wrap(1, RasterPos4fv, void, (GLfloatP)) +BGL_Wrap(4, RasterPos4i, void, (GLint, GLint, GLint, GLint)) +BGL_Wrap(1, RasterPos4iv, void, (GLintP)) +BGL_Wrap(4, RasterPos4s, void, (GLshort, GLshort, GLshort, GLshort)) +BGL_Wrap(1, RasterPos4sv, void, (GLshortP)) +BGL_Wrap(1, ReadBuffer, void, (GLenum)) +BGL_Wrap(7, ReadPixels, void, (GLint, GLint, GLsizei, + GLsizei, GLenum, GLenum, GLvoidP)) +BGL_Wrap(4, Rectd, void, (GLdouble, GLdouble, GLdouble, GLdouble)) +BGL_Wrap(2, Rectdv, void, (GLdoubleP, GLdoubleP)) +BGL_Wrap(4, Rectf, void, (GLfloat, GLfloat, GLfloat, GLfloat)) +BGL_Wrap(2, Rectfv, void, (GLfloatP, GLfloatP)) +BGL_Wrap(4, Recti, void, (GLint, GLint, GLint, GLint)) +BGL_Wrap(2, Rectiv, void, (GLintP, GLintP)) +BGL_Wrap(4, Rects, void, (GLshort, GLshort, GLshort, GLshort)) +BGL_Wrap(2, Rectsv, void, (GLshortP, GLshortP)) +BGL_Wrap(1, RenderMode, GLint, (GLenum)) +BGL_Wrap(4, Rotated, void, (GLdouble, GLdouble, GLdouble, GLdouble)) +BGL_Wrap(4, Rotatef, void, (GLfloat, GLfloat, GLfloat, GLfloat)) +BGL_Wrap(3, Scaled, void, (GLdouble, GLdouble, GLdouble)) +BGL_Wrap(3, Scalef, void, (GLfloat, GLfloat, GLfloat)) +BGL_Wrap(4, Scissor, void, (GLint, GLint, GLsizei, GLsizei)) +BGL_Wrap(2, SelectBuffer, void, (GLsizei, GLuintP)) +BGL_Wrap(1, ShadeModel, void, (GLenum)) +BGL_Wrap(3, StencilFunc, void, (GLenum, GLint, GLuint)) +BGL_Wrap(1, StencilMask, void, (GLuint)) +BGL_Wrap(3, StencilOp, void, (GLenum, GLenum, GLenum)) +BGL_Wrap(1, TexCoord1d, void, (GLdouble)) +BGL_Wrap(1, TexCoord1dv, void, (GLdoubleP)) +BGL_Wrap(1, TexCoord1f, void, (GLfloat)) +BGL_Wrap(1, TexCoord1fv, void, (GLfloatP)) +BGL_Wrap(1, TexCoord1i, void, (GLint)) +BGL_Wrap(1, TexCoord1iv, void, (GLintP)) +BGL_Wrap(1, TexCoord1s, void, (GLshort)) +BGL_Wrap(1, TexCoord1sv, void, (GLshortP)) +BGL_Wrap(2, TexCoord2d, void, (GLdouble, GLdouble)) +BGL_Wrap(1, TexCoord2dv, void, (GLdoubleP)) +BGL_Wrap(2, TexCoord2f, void, (GLfloat, GLfloat)) +BGL_Wrap(1, TexCoord2fv, void, (GLfloatP)) +BGL_Wrap(2, TexCoord2i, void, (GLint, GLint)) +BGL_Wrap(1, TexCoord2iv, void, (GLintP)) +BGL_Wrap(2, TexCoord2s, void, (GLshort, GLshort)) +BGL_Wrap(1, TexCoord2sv, void, (GLshortP)) +BGL_Wrap(3, TexCoord3d, void, (GLdouble, GLdouble, GLdouble)) +BGL_Wrap(1, TexCoord3dv, void, (GLdoubleP)) +BGL_Wrap(3, TexCoord3f, void, (GLfloat, GLfloat, GLfloat)) +BGL_Wrap(1, TexCoord3fv, void, (GLfloatP)) +BGL_Wrap(3, TexCoord3i, void, (GLint, GLint, GLint)) +BGL_Wrap(1, TexCoord3iv, void, (GLintP)) +BGL_Wrap(3, TexCoord3s, void, (GLshort, GLshort, GLshort)) +BGL_Wrap(1, TexCoord3sv, void, (GLshortP)) +BGL_Wrap(4, TexCoord4d, void, (GLdouble, GLdouble, GLdouble, GLdouble)) +BGL_Wrap(1, TexCoord4dv, void, (GLdoubleP)) +BGL_Wrap(4, TexCoord4f, void, (GLfloat, GLfloat, GLfloat, GLfloat)) +BGL_Wrap(1, TexCoord4fv, void, (GLfloatP)) +BGL_Wrap(4, TexCoord4i, void, (GLint, GLint, GLint, GLint)) +BGL_Wrap(1, TexCoord4iv, void, (GLintP)) +BGL_Wrap(4, TexCoord4s, void, (GLshort, GLshort, GLshort, GLshort)) +BGL_Wrap(1, TexCoord4sv, void, (GLshortP)) +BGL_Wrap(3, TexEnvf, void, (GLenum, GLenum, GLfloat)) +BGL_Wrap(3, TexEnvfv, void, (GLenum, GLenum, GLfloatP)) +BGL_Wrap(3, TexEnvi, void, (GLenum, GLenum, GLint)) +BGL_Wrap(3, TexEnviv, void, (GLenum, GLenum, GLintP)) +BGL_Wrap(3, TexGend, void, (GLenum, GLenum, GLdouble)) +BGL_Wrap(3, TexGendv, void, (GLenum, GLenum, GLdoubleP)) +BGL_Wrap(3, TexGenf, void, (GLenum, GLenum, GLfloat)) +BGL_Wrap(3, TexGenfv, void, (GLenum, GLenum, GLfloatP)) +BGL_Wrap(3, TexGeni, void, (GLenum, GLenum, GLint)) +BGL_Wrap(3, TexGeniv, void, (GLenum, GLenum, GLintP)) +BGL_Wrap(8, TexImage1D, void, (GLenum, GLint, GLint, + GLsizei, GLint, GLenum, GLenum, GLvoidP)) +BGL_Wrap(9, TexImage2D, void, (GLenum, GLint, GLint, + GLsizei, GLsizei, GLint, GLenum, GLenum, GLvoidP)) +BGL_Wrap(3, TexParameterf, void, (GLenum, GLenum, GLfloat)) +BGL_Wrap(3, TexParameterfv, void, (GLenum, GLenum, GLfloatP)) +BGL_Wrap(3, TexParameteri, void, (GLenum, GLenum, GLint)) +BGL_Wrap(3, TexParameteriv, void, (GLenum, GLenum, GLintP)) +BGL_Wrap(3, Translated, void, (GLdouble, GLdouble, GLdouble)) +BGL_Wrap(3, Translatef, void, (GLfloat, GLfloat, GLfloat)) +BGL_Wrap(2, Vertex2d, void, (GLdouble, GLdouble)) +BGL_Wrap(1, Vertex2dv, void, (GLdoubleP)) +BGL_Wrap(2, Vertex2f, void, (GLfloat, GLfloat)) +BGL_Wrap(1, Vertex2fv, void, (GLfloatP)) +BGL_Wrap(2, Vertex2i, void, (GLint, GLint)) +BGL_Wrap(1, Vertex2iv, void, (GLintP)) +BGL_Wrap(2, Vertex2s, void, (GLshort, GLshort)) +BGL_Wrap(1, Vertex2sv, void, (GLshortP)) +BGL_Wrap(3, Vertex3d, void, (GLdouble, GLdouble, GLdouble)) +BGL_Wrap(1, Vertex3dv, void, (GLdoubleP)) +BGL_Wrap(3, Vertex3f, void, (GLfloat, GLfloat, GLfloat)) +BGL_Wrap(1, Vertex3fv, void, (GLfloatP)) +BGL_Wrap(3, Vertex3i, void, (GLint, GLint, GLint)) +BGL_Wrap(1, Vertex3iv, void, (GLintP)) +BGL_Wrap(3, Vertex3s, void, (GLshort, GLshort, GLshort)) +BGL_Wrap(1, Vertex3sv, void, (GLshortP)) +BGL_Wrap(4, Vertex4d, void, (GLdouble, GLdouble, GLdouble, GLdouble)) +BGL_Wrap(1, Vertex4dv, void, (GLdoubleP)) +BGL_Wrap(4, Vertex4f, void, (GLfloat, GLfloat, GLfloat, GLfloat)) +BGL_Wrap(1, Vertex4fv, void, (GLfloatP)) +BGL_Wrap(4, Vertex4i, void, (GLint, GLint, GLint, GLint)) +BGL_Wrap(1, Vertex4iv, void, (GLintP)) +BGL_Wrap(4, Vertex4s, void, (GLshort, GLshort, GLshort, GLshort)) +BGL_Wrap(1, Vertex4sv, void, (GLshortP)) +BGL_Wrap(4, Viewport, void, (GLint, GLint, GLsizei, GLsizei)) +BGLU_Wrap(4, Perspective, void, (GLdouble, GLdouble, GLdouble, GLdouble)) +BGLU_Wrap(9, LookAt, void, (GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble)) +BGLU_Wrap(4, Ortho2D, void, (GLdouble, GLdouble, GLdouble, GLdouble)) +BGLU_Wrap(5, PickMatrix, void, (GLdouble, GLdouble, GLdouble, GLdouble, GLintP)) +BGLU_Wrap(9, Project, GLint, (GLdouble, GLdouble, GLdouble, GLdoubleP, GLdoubleP, GLintP, GLdoubleP, GLdoubleP, GLdoubleP)) +BGLU_Wrap(9, UnProject, GLint, (GLdouble, GLdouble, GLdouble, GLdoubleP, GLdoubleP, GLintP, GLdoubleP, GLdoubleP, GLdoubleP)) + +#undef MethodDef +#define MethodDef(func) {"gl"#func, Method_##func, METH_VARARGS, "no string"} +#define MethodDefu(func) {"glu"#func, Method_##func, METH_VARARGS, "no string"} +/* So that MethodDef(Accum) becomes: + * {"glAccum", Method_Accumfunc, METH_VARARGS} */ + +static struct PyMethodDef BGL_methods[] = { + {"Buffer", Method_Buffer, METH_VARARGS, Method_Buffer_doc}, + +/* #ifndef __APPLE__ */ + MethodDef(Accum), + MethodDef(AlphaFunc), + MethodDef(AreTexturesResident), + MethodDef(Begin), + MethodDef(BindTexture), + MethodDef(Bitmap), + MethodDef(BlendFunc), + MethodDef(CallList), + MethodDef(CallLists), + MethodDef(Clear), + MethodDef(ClearAccum), + MethodDef(ClearColor), + MethodDef(ClearDepth), + MethodDef(ClearIndex), + MethodDef(ClearStencil), + MethodDef(ClipPlane), + MethodDef(Color3b), + MethodDef(Color3bv), + MethodDef(Color3d), + MethodDef(Color3dv), + MethodDef(Color3f), + MethodDef(Color3fv), + MethodDef(Color3i), + MethodDef(Color3iv), + MethodDef(Color3s), + MethodDef(Color3sv), + MethodDef(Color3ub), + MethodDef(Color3ubv), + MethodDef(Color3ui), + MethodDef(Color3uiv), + MethodDef(Color3us), + MethodDef(Color3usv), + MethodDef(Color4b), + MethodDef(Color4bv), + MethodDef(Color4d), + MethodDef(Color4dv), + MethodDef(Color4f), + MethodDef(Color4fv), + MethodDef(Color4i), + MethodDef(Color4iv), + MethodDef(Color4s), + MethodDef(Color4sv), + MethodDef(Color4ub), + MethodDef(Color4ubv), + MethodDef(Color4ui), + MethodDef(Color4uiv), + MethodDef(Color4us), + MethodDef(Color4usv), + MethodDef(ColorMask), + MethodDef(ColorMaterial), + MethodDef(CopyPixels), + MethodDef(CullFace), + MethodDef(DeleteLists), + MethodDef(DeleteTextures), + MethodDef(DepthFunc), + MethodDef(DepthMask), + MethodDef(DepthRange), + MethodDef(Disable), + MethodDef(DrawBuffer), + MethodDef(DrawPixels), + MethodDef(EdgeFlag), + MethodDef(EdgeFlagv), + MethodDef(Enable), + MethodDef(End), + MethodDef(EndList), + MethodDef(EvalCoord1d), + MethodDef(EvalCoord1dv), + MethodDef(EvalCoord1f), + MethodDef(EvalCoord1fv), + MethodDef(EvalCoord2d), + MethodDef(EvalCoord2dv), + MethodDef(EvalCoord2f), + MethodDef(EvalCoord2fv), + MethodDef(EvalMesh1), + MethodDef(EvalMesh2), + MethodDef(EvalPoint1), + MethodDef(EvalPoint2), + MethodDef(FeedbackBuffer), + MethodDef(Finish), + MethodDef(Flush), + MethodDef(Fogf), + MethodDef(Fogfv), + MethodDef(Fogi), + MethodDef(Fogiv), + MethodDef(FrontFace), + MethodDef(Frustum), + MethodDef(GenLists), + MethodDef(GenTextures), + MethodDef(GetBooleanv), + MethodDef(GetClipPlane), + MethodDef(GetDoublev), + MethodDef(GetError), + MethodDef(GetFloatv), + MethodDef(GetIntegerv), + MethodDef(GetLightfv), + MethodDef(GetLightiv), + MethodDef(GetMapdv), + MethodDef(GetMapfv), + MethodDef(GetMapiv), + MethodDef(GetMaterialfv), + MethodDef(GetMaterialiv), + MethodDef(GetPixelMapfv), + MethodDef(GetPixelMapuiv), + MethodDef(GetPixelMapusv), + MethodDef(GetPolygonStipple), + MethodDef(GetString), + MethodDef(GetTexEnvfv), + MethodDef(GetTexEnviv), + MethodDef(GetTexGendv), + MethodDef(GetTexGenfv), + MethodDef(GetTexGeniv), + MethodDef(GetTexImage), + MethodDef(GetTexLevelParameterfv), + MethodDef(GetTexLevelParameteriv), + MethodDef(GetTexParameterfv), + MethodDef(GetTexParameteriv), + MethodDef(Hint), + MethodDef(IndexMask), + MethodDef(Indexd), + MethodDef(Indexdv), + MethodDef(Indexf), + MethodDef(Indexfv), + MethodDef(Indexi), + MethodDef(Indexiv), + MethodDef(Indexs), + MethodDef(Indexsv), + MethodDef(InitNames), + MethodDef(IsEnabled), + MethodDef(IsList), + MethodDef(IsTexture), + MethodDef(LightModelf), + MethodDef(LightModelfv), + MethodDef(LightModeli), + MethodDef(LightModeliv), + MethodDef(Lightf), + MethodDef(Lightfv), + MethodDef(Lighti), + MethodDef(Lightiv), + MethodDef(LineStipple), + MethodDef(LineWidth), + MethodDef(ListBase), + MethodDef(LoadIdentity), + MethodDef(LoadMatrixd), + MethodDef(LoadMatrixf), + MethodDef(LoadName), + MethodDef(LogicOp), + MethodDef(Map1d), + MethodDef(Map1f), + MethodDef(Map2d), + MethodDef(Map2f), + MethodDef(MapGrid1d), + MethodDef(MapGrid1f), + MethodDef(MapGrid2d), + MethodDef(MapGrid2f), + MethodDef(Materialf), + MethodDef(Materialfv), + MethodDef(Materiali), + MethodDef(Materialiv), + MethodDef(MatrixMode), + MethodDef(MultMatrixd), + MethodDef(MultMatrixf), + MethodDef(NewList), + MethodDef(Normal3b), + MethodDef(Normal3bv), + MethodDef(Normal3d), + MethodDef(Normal3dv), + MethodDef(Normal3f), + MethodDef(Normal3fv), + MethodDef(Normal3i), + MethodDef(Normal3iv), + MethodDef(Normal3s), + MethodDef(Normal3sv), + MethodDef(Ortho), + MethodDef(PassThrough), + MethodDef(PixelMapfv), + MethodDef(PixelMapuiv), + MethodDef(PixelMapusv), + MethodDef(PixelStoref), + MethodDef(PixelStorei), + MethodDef(PixelTransferf), + MethodDef(PixelTransferi), + MethodDef(PixelZoom), + MethodDef(PointSize), + MethodDef(PolygonMode), + MethodDef(PolygonOffset), + MethodDef(PolygonStipple), + MethodDef(PopAttrib), + MethodDef(PopClientAttrib), + MethodDef(PopMatrix), + MethodDef(PopName), + MethodDef(PrioritizeTextures), + MethodDef(PushAttrib), + MethodDef(PushClientAttrib), + MethodDef(PushMatrix), + MethodDef(PushName), + MethodDef(RasterPos2d), + MethodDef(RasterPos2dv), + MethodDef(RasterPos2f), + MethodDef(RasterPos2fv), + MethodDef(RasterPos2i), + MethodDef(RasterPos2iv), + MethodDef(RasterPos2s), + MethodDef(RasterPos2sv), + MethodDef(RasterPos3d), + MethodDef(RasterPos3dv), + MethodDef(RasterPos3f), + MethodDef(RasterPos3fv), + MethodDef(RasterPos3i), + MethodDef(RasterPos3iv), + MethodDef(RasterPos3s), + MethodDef(RasterPos3sv), + MethodDef(RasterPos4d), + MethodDef(RasterPos4dv), + MethodDef(RasterPos4f), + MethodDef(RasterPos4fv), + MethodDef(RasterPos4i), + MethodDef(RasterPos4iv), + MethodDef(RasterPos4s), + MethodDef(RasterPos4sv), + MethodDef(ReadBuffer), + MethodDef(ReadPixels), + MethodDef(Rectd), + MethodDef(Rectdv), + MethodDef(Rectf), + MethodDef(Rectfv), + MethodDef(Recti), + MethodDef(Rectiv), + MethodDef(Rects), + MethodDef(Rectsv), + MethodDef(RenderMode), + MethodDef(Rotated), + MethodDef(Rotatef), + MethodDef(Scaled), + MethodDef(Scalef), + MethodDef(Scissor), + MethodDef(SelectBuffer), + MethodDef(ShadeModel), + MethodDef(StencilFunc), + MethodDef(StencilMask), + MethodDef(StencilOp), + MethodDef(TexCoord1d), + MethodDef(TexCoord1dv), + MethodDef(TexCoord1f), + MethodDef(TexCoord1fv), + MethodDef(TexCoord1i), + MethodDef(TexCoord1iv), + MethodDef(TexCoord1s), + MethodDef(TexCoord1sv), + MethodDef(TexCoord2d), + MethodDef(TexCoord2dv), + MethodDef(TexCoord2f), + MethodDef(TexCoord2fv), + MethodDef(TexCoord2i), + MethodDef(TexCoord2iv), + MethodDef(TexCoord2s), + MethodDef(TexCoord2sv), + MethodDef(TexCoord3d), + MethodDef(TexCoord3dv), + MethodDef(TexCoord3f), + MethodDef(TexCoord3fv), + MethodDef(TexCoord3i), + MethodDef(TexCoord3iv), + MethodDef(TexCoord3s), + MethodDef(TexCoord3sv), + MethodDef(TexCoord4d), + MethodDef(TexCoord4dv), + MethodDef(TexCoord4f), + MethodDef(TexCoord4fv), + MethodDef(TexCoord4i), + MethodDef(TexCoord4iv), + MethodDef(TexCoord4s), + MethodDef(TexCoord4sv), + MethodDef(TexEnvf), + MethodDef(TexEnvfv), + MethodDef(TexEnvi), + MethodDef(TexEnviv), + MethodDef(TexGend), + MethodDef(TexGendv), + MethodDef(TexGenf), + MethodDef(TexGenfv), + MethodDef(TexGeni), + MethodDef(TexGeniv), + MethodDef(TexImage1D), + MethodDef(TexImage2D), + MethodDef(TexParameterf), + MethodDef(TexParameterfv), + MethodDef(TexParameteri), + MethodDef(TexParameteriv), + MethodDef(Translated), + MethodDef(Translatef), + MethodDef(Vertex2d), + MethodDef(Vertex2dv), + MethodDef(Vertex2f), + MethodDef(Vertex2fv), + MethodDef(Vertex2i), + MethodDef(Vertex2iv), + MethodDef(Vertex2s), + MethodDef(Vertex2sv), + MethodDef(Vertex3d), + MethodDef(Vertex3dv), + MethodDef(Vertex3f), + MethodDef(Vertex3fv), + MethodDef(Vertex3i), + MethodDef(Vertex3iv), + MethodDef(Vertex3s), + MethodDef(Vertex3sv), + MethodDef(Vertex4d), + MethodDef(Vertex4dv), + MethodDef(Vertex4f), + MethodDef(Vertex4fv), + MethodDef(Vertex4i), + MethodDef(Vertex4iv), + MethodDef(Vertex4s), + MethodDef(Vertex4sv), + MethodDef(Viewport), + MethodDefu(Perspective), + MethodDefu(LookAt), + MethodDefu(Ortho2D), + MethodDefu(PickMatrix), + MethodDefu(Project), + MethodDefu(UnProject), +/* #endif */ + {NULL, NULL, 0, NULL} +}; + +PyObject *BGL_Init(void) +{ + PyObject *mod= Py_InitModule("Blender.BGL", BGL_methods); + PyObject *dict= PyModule_GetDict(mod); + + if( PyType_Ready( &buffer_Type) < 0) + Py_RETURN_NONE; + +#define EXPP_ADDCONST(x) EXPP_dict_set_item_str(dict, #x, PyInt_FromLong(x)) + +/* So, for example: + * EXPP_ADDCONST(GL_CURRENT_BIT) becomes + * EXPP_dict_set_item_str(dict, "GL_CURRENT_BIT", PyInt_FromLong(GL_CURRENT_BIT)) */ + + EXPP_ADDCONST(GL_CURRENT_BIT); + EXPP_ADDCONST(GL_POINT_BIT); + EXPP_ADDCONST(GL_LINE_BIT); + EXPP_ADDCONST(GL_POLYGON_BIT); + EXPP_ADDCONST(GL_POLYGON_STIPPLE_BIT); + EXPP_ADDCONST(GL_PIXEL_MODE_BIT); + EXPP_ADDCONST(GL_LIGHTING_BIT); + EXPP_ADDCONST(GL_FOG_BIT); + EXPP_ADDCONST(GL_DEPTH_BUFFER_BIT); + EXPP_ADDCONST(GL_ACCUM_BUFFER_BIT); + EXPP_ADDCONST(GL_STENCIL_BUFFER_BIT); + EXPP_ADDCONST(GL_VIEWPORT_BIT); + EXPP_ADDCONST(GL_TRANSFORM_BIT); + EXPP_ADDCONST(GL_ENABLE_BIT); + EXPP_ADDCONST(GL_COLOR_BUFFER_BIT); + EXPP_ADDCONST(GL_HINT_BIT); + EXPP_ADDCONST(GL_EVAL_BIT); + EXPP_ADDCONST(GL_LIST_BIT); + EXPP_ADDCONST(GL_TEXTURE_BIT); + EXPP_ADDCONST(GL_SCISSOR_BIT); + EXPP_ADDCONST(GL_ALL_ATTRIB_BITS); + + EXPP_ADDCONST(GL_FALSE); + EXPP_ADDCONST(GL_TRUE); + + EXPP_ADDCONST(GL_POINTS); + EXPP_ADDCONST(GL_LINES); + EXPP_ADDCONST(GL_LINE_LOOP); + EXPP_ADDCONST(GL_LINE_STRIP); + EXPP_ADDCONST(GL_TRIANGLES); + EXPP_ADDCONST(GL_TRIANGLE_STRIP); + EXPP_ADDCONST(GL_TRIANGLE_FAN); + EXPP_ADDCONST(GL_QUADS); + EXPP_ADDCONST(GL_QUAD_STRIP); + EXPP_ADDCONST(GL_POLYGON); + + EXPP_ADDCONST(GL_ACCUM); + EXPP_ADDCONST(GL_LOAD); + EXPP_ADDCONST(GL_RETURN); + EXPP_ADDCONST(GL_MULT); + EXPP_ADDCONST(GL_ADD); + + EXPP_ADDCONST(GL_NEVER); + EXPP_ADDCONST(GL_LESS); + EXPP_ADDCONST(GL_EQUAL); + EXPP_ADDCONST(GL_LEQUAL); + EXPP_ADDCONST(GL_GREATER); + EXPP_ADDCONST(GL_NOTEQUAL); + EXPP_ADDCONST(GL_GEQUAL); + EXPP_ADDCONST(GL_ALWAYS); + + EXPP_ADDCONST(GL_ZERO); + EXPP_ADDCONST(GL_ONE); + EXPP_ADDCONST(GL_SRC_COLOR); + EXPP_ADDCONST(GL_ONE_MINUS_SRC_COLOR); + EXPP_ADDCONST(GL_SRC_ALPHA); + EXPP_ADDCONST(GL_ONE_MINUS_SRC_ALPHA); + EXPP_ADDCONST(GL_DST_ALPHA); + EXPP_ADDCONST(GL_ONE_MINUS_DST_ALPHA); + + EXPP_ADDCONST(GL_DST_COLOR); + EXPP_ADDCONST(GL_ONE_MINUS_DST_COLOR); + EXPP_ADDCONST(GL_SRC_ALPHA_SATURATE); + + EXPP_ADDCONST(GL_NONE); + EXPP_ADDCONST(GL_FRONT_LEFT); + EXPP_ADDCONST(GL_FRONT_RIGHT); + EXPP_ADDCONST(GL_BACK_LEFT); + EXPP_ADDCONST(GL_BACK_RIGHT); + EXPP_ADDCONST(GL_FRONT); + EXPP_ADDCONST(GL_BACK); + EXPP_ADDCONST(GL_LEFT); + EXPP_ADDCONST(GL_RIGHT); + EXPP_ADDCONST(GL_FRONT_AND_BACK); + EXPP_ADDCONST(GL_AUX0); + EXPP_ADDCONST(GL_AUX1); + EXPP_ADDCONST(GL_AUX2); + EXPP_ADDCONST(GL_AUX3); + + EXPP_ADDCONST(GL_NO_ERROR); + EXPP_ADDCONST(GL_INVALID_ENUM); + EXPP_ADDCONST(GL_INVALID_VALUE); + EXPP_ADDCONST(GL_INVALID_OPERATION); + EXPP_ADDCONST(GL_STACK_OVERFLOW); + EXPP_ADDCONST(GL_STACK_UNDERFLOW); + EXPP_ADDCONST(GL_OUT_OF_MEMORY); + + EXPP_ADDCONST(GL_2D); + EXPP_ADDCONST(GL_3D); + EXPP_ADDCONST(GL_3D_COLOR); + EXPP_ADDCONST(GL_3D_COLOR_TEXTURE); + EXPP_ADDCONST(GL_4D_COLOR_TEXTURE); + + EXPP_ADDCONST(GL_PASS_THROUGH_TOKEN); + EXPP_ADDCONST(GL_POINT_TOKEN); + EXPP_ADDCONST(GL_LINE_TOKEN); + EXPP_ADDCONST(GL_POLYGON_TOKEN); + EXPP_ADDCONST(GL_BITMAP_TOKEN); + EXPP_ADDCONST(GL_DRAW_PIXEL_TOKEN); + EXPP_ADDCONST(GL_COPY_PIXEL_TOKEN); + EXPP_ADDCONST(GL_LINE_RESET_TOKEN); + + EXPP_ADDCONST(GL_EXP); + EXPP_ADDCONST(GL_EXP2); + + EXPP_ADDCONST(GL_CW); + EXPP_ADDCONST(GL_CCW); + + EXPP_ADDCONST(GL_COEFF); + EXPP_ADDCONST(GL_ORDER); + EXPP_ADDCONST(GL_DOMAIN); + + EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_I); + EXPP_ADDCONST(GL_PIXEL_MAP_S_TO_S); + EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_R); + EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_G); + EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_B); + EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_A); + EXPP_ADDCONST(GL_PIXEL_MAP_R_TO_R); + EXPP_ADDCONST(GL_PIXEL_MAP_G_TO_G); + EXPP_ADDCONST(GL_PIXEL_MAP_B_TO_B); + EXPP_ADDCONST(GL_PIXEL_MAP_A_TO_A); + + EXPP_ADDCONST(GL_CURRENT_COLOR); + EXPP_ADDCONST(GL_CURRENT_INDEX); + EXPP_ADDCONST(GL_CURRENT_NORMAL); + EXPP_ADDCONST(GL_CURRENT_TEXTURE_COORDS); + EXPP_ADDCONST(GL_CURRENT_RASTER_COLOR); + EXPP_ADDCONST(GL_CURRENT_RASTER_INDEX); + EXPP_ADDCONST(GL_CURRENT_RASTER_TEXTURE_COORDS); + EXPP_ADDCONST(GL_CURRENT_RASTER_POSITION); + EXPP_ADDCONST(GL_CURRENT_RASTER_POSITION_VALID); + EXPP_ADDCONST(GL_CURRENT_RASTER_DISTANCE); + EXPP_ADDCONST(GL_POINT_SMOOTH); + EXPP_ADDCONST(GL_POINT_SIZE); + EXPP_ADDCONST(GL_POINT_SIZE_RANGE); + EXPP_ADDCONST(GL_POINT_SIZE_GRANULARITY); + EXPP_ADDCONST(GL_LINE_SMOOTH); + EXPP_ADDCONST(GL_LINE_WIDTH); + EXPP_ADDCONST(GL_LINE_WIDTH_RANGE); + EXPP_ADDCONST(GL_LINE_WIDTH_GRANULARITY); + EXPP_ADDCONST(GL_LINE_STIPPLE); + EXPP_ADDCONST(GL_LINE_STIPPLE_PATTERN); + EXPP_ADDCONST(GL_LINE_STIPPLE_REPEAT); + EXPP_ADDCONST(GL_LIST_MODE); + EXPP_ADDCONST(GL_MAX_LIST_NESTING); + EXPP_ADDCONST(GL_LIST_BASE); + EXPP_ADDCONST(GL_LIST_INDEX); + EXPP_ADDCONST(GL_POLYGON_MODE); + EXPP_ADDCONST(GL_POLYGON_SMOOTH); + EXPP_ADDCONST(GL_POLYGON_STIPPLE); + EXPP_ADDCONST(GL_EDGE_FLAG); + EXPP_ADDCONST(GL_CULL_FACE); + EXPP_ADDCONST(GL_CULL_FACE_MODE); + EXPP_ADDCONST(GL_FRONT_FACE); + EXPP_ADDCONST(GL_LIGHTING); + EXPP_ADDCONST(GL_LIGHT_MODEL_LOCAL_VIEWER); + EXPP_ADDCONST(GL_LIGHT_MODEL_TWO_SIDE); + EXPP_ADDCONST(GL_LIGHT_MODEL_AMBIENT); + EXPP_ADDCONST(GL_SHADE_MODEL); + EXPP_ADDCONST(GL_COLOR_MATERIAL_FACE); + EXPP_ADDCONST(GL_COLOR_MATERIAL_PARAMETER); + EXPP_ADDCONST(GL_COLOR_MATERIAL); + EXPP_ADDCONST(GL_FOG); + EXPP_ADDCONST(GL_FOG_INDEX); + EXPP_ADDCONST(GL_FOG_DENSITY); + EXPP_ADDCONST(GL_FOG_START); + EXPP_ADDCONST(GL_FOG_END); + EXPP_ADDCONST(GL_FOG_MODE); + EXPP_ADDCONST(GL_FOG_COLOR); + EXPP_ADDCONST(GL_DEPTH_RANGE); + EXPP_ADDCONST(GL_DEPTH_TEST); + EXPP_ADDCONST(GL_DEPTH_WRITEMASK); + EXPP_ADDCONST(GL_DEPTH_CLEAR_VALUE); + EXPP_ADDCONST(GL_DEPTH_FUNC); + EXPP_ADDCONST(GL_ACCUM_CLEAR_VALUE); + EXPP_ADDCONST(GL_STENCIL_TEST); + EXPP_ADDCONST(GL_STENCIL_CLEAR_VALUE); + EXPP_ADDCONST(GL_STENCIL_FUNC); + EXPP_ADDCONST(GL_STENCIL_VALUE_MASK); + EXPP_ADDCONST(GL_STENCIL_FAIL); + EXPP_ADDCONST(GL_STENCIL_PASS_DEPTH_FAIL); + EXPP_ADDCONST(GL_STENCIL_PASS_DEPTH_PASS); + EXPP_ADDCONST(GL_STENCIL_REF); + EXPP_ADDCONST(GL_STENCIL_WRITEMASK); + EXPP_ADDCONST(GL_MATRIX_MODE); + EXPP_ADDCONST(GL_NORMALIZE); + EXPP_ADDCONST(GL_VIEWPORT); + EXPP_ADDCONST(GL_MODELVIEW_STACK_DEPTH); + EXPP_ADDCONST(GL_PROJECTION_STACK_DEPTH); + EXPP_ADDCONST(GL_TEXTURE_STACK_DEPTH); + EXPP_ADDCONST(GL_MODELVIEW_MATRIX); + EXPP_ADDCONST(GL_PROJECTION_MATRIX); + EXPP_ADDCONST(GL_TEXTURE_MATRIX); + EXPP_ADDCONST(GL_ATTRIB_STACK_DEPTH); + EXPP_ADDCONST(GL_ALPHA_TEST); + EXPP_ADDCONST(GL_ALPHA_TEST_FUNC); + EXPP_ADDCONST(GL_ALPHA_TEST_REF); + EXPP_ADDCONST(GL_DITHER); + EXPP_ADDCONST(GL_BLEND_DST); + EXPP_ADDCONST(GL_BLEND_SRC); + EXPP_ADDCONST(GL_BLEND); + EXPP_ADDCONST(GL_LOGIC_OP_MODE); + EXPP_ADDCONST(GL_LOGIC_OP); + EXPP_ADDCONST(GL_AUX_BUFFERS); + EXPP_ADDCONST(GL_DRAW_BUFFER); + EXPP_ADDCONST(GL_READ_BUFFER); + EXPP_ADDCONST(GL_SCISSOR_BOX); + EXPP_ADDCONST(GL_SCISSOR_TEST); + EXPP_ADDCONST(GL_INDEX_CLEAR_VALUE); + EXPP_ADDCONST(GL_INDEX_WRITEMASK); + EXPP_ADDCONST(GL_COLOR_CLEAR_VALUE); + EXPP_ADDCONST(GL_COLOR_WRITEMASK); + EXPP_ADDCONST(GL_INDEX_MODE); + EXPP_ADDCONST(GL_RGBA_MODE); + EXPP_ADDCONST(GL_DOUBLEBUFFER); + EXPP_ADDCONST(GL_STEREO); + EXPP_ADDCONST(GL_RENDER_MODE); + EXPP_ADDCONST(GL_PERSPECTIVE_CORRECTION_HINT); + EXPP_ADDCONST(GL_POINT_SMOOTH_HINT); + EXPP_ADDCONST(GL_LINE_SMOOTH_HINT); + EXPP_ADDCONST(GL_POLYGON_SMOOTH_HINT); + EXPP_ADDCONST(GL_FOG_HINT); + EXPP_ADDCONST(GL_TEXTURE_GEN_S); + EXPP_ADDCONST(GL_TEXTURE_GEN_T); + EXPP_ADDCONST(GL_TEXTURE_GEN_R); + EXPP_ADDCONST(GL_TEXTURE_GEN_Q); + EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_I_SIZE); + EXPP_ADDCONST(GL_PIXEL_MAP_S_TO_S_SIZE); + EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_R_SIZE); + EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_G_SIZE); + EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_B_SIZE); + EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_A_SIZE); + EXPP_ADDCONST(GL_PIXEL_MAP_R_TO_R_SIZE); + EXPP_ADDCONST(GL_PIXEL_MAP_G_TO_G_SIZE); + EXPP_ADDCONST(GL_PIXEL_MAP_B_TO_B_SIZE); + EXPP_ADDCONST(GL_PIXEL_MAP_A_TO_A_SIZE); + EXPP_ADDCONST(GL_UNPACK_SWAP_BYTES); + EXPP_ADDCONST(GL_UNPACK_LSB_FIRST); + EXPP_ADDCONST(GL_UNPACK_ROW_LENGTH); + EXPP_ADDCONST(GL_UNPACK_SKIP_ROWS); + EXPP_ADDCONST(GL_UNPACK_SKIP_PIXELS); + EXPP_ADDCONST(GL_UNPACK_ALIGNMENT); + EXPP_ADDCONST(GL_PACK_SWAP_BYTES); + EXPP_ADDCONST(GL_PACK_LSB_FIRST); + EXPP_ADDCONST(GL_PACK_ROW_LENGTH); + EXPP_ADDCONST(GL_PACK_SKIP_ROWS); + EXPP_ADDCONST(GL_PACK_SKIP_PIXELS); + EXPP_ADDCONST(GL_PACK_ALIGNMENT); + EXPP_ADDCONST(GL_MAP_COLOR); + EXPP_ADDCONST(GL_MAP_STENCIL); + EXPP_ADDCONST(GL_INDEX_SHIFT); + EXPP_ADDCONST(GL_INDEX_OFFSET); + EXPP_ADDCONST(GL_RED_SCALE); + EXPP_ADDCONST(GL_RED_BIAS); + EXPP_ADDCONST(GL_ZOOM_X); + EXPP_ADDCONST(GL_ZOOM_Y); + EXPP_ADDCONST(GL_GREEN_SCALE); + EXPP_ADDCONST(GL_GREEN_BIAS); + EXPP_ADDCONST(GL_BLUE_SCALE); + EXPP_ADDCONST(GL_BLUE_BIAS); + EXPP_ADDCONST(GL_ALPHA_SCALE); + EXPP_ADDCONST(GL_ALPHA_BIAS); + EXPP_ADDCONST(GL_DEPTH_SCALE); + EXPP_ADDCONST(GL_DEPTH_BIAS); + EXPP_ADDCONST(GL_MAX_EVAL_ORDER); + EXPP_ADDCONST(GL_MAX_LIGHTS); + EXPP_ADDCONST(GL_MAX_CLIP_PLANES); + EXPP_ADDCONST(GL_MAX_TEXTURE_SIZE); + EXPP_ADDCONST(GL_MAX_PIXEL_MAP_TABLE); + EXPP_ADDCONST(GL_MAX_ATTRIB_STACK_DEPTH); + EXPP_ADDCONST(GL_MAX_MODELVIEW_STACK_DEPTH); + EXPP_ADDCONST(GL_MAX_NAME_STACK_DEPTH); + EXPP_ADDCONST(GL_MAX_PROJECTION_STACK_DEPTH); + EXPP_ADDCONST(GL_MAX_TEXTURE_STACK_DEPTH); + EXPP_ADDCONST(GL_MAX_VIEWPORT_DIMS); + EXPP_ADDCONST(GL_SUBPIXEL_BITS); + EXPP_ADDCONST(GL_INDEX_BITS); + EXPP_ADDCONST(GL_RED_BITS); + EXPP_ADDCONST(GL_GREEN_BITS); + EXPP_ADDCONST(GL_BLUE_BITS); + EXPP_ADDCONST(GL_ALPHA_BITS); + EXPP_ADDCONST(GL_DEPTH_BITS); + EXPP_ADDCONST(GL_STENCIL_BITS); + EXPP_ADDCONST(GL_ACCUM_RED_BITS); + EXPP_ADDCONST(GL_ACCUM_GREEN_BITS); + EXPP_ADDCONST(GL_ACCUM_BLUE_BITS); + EXPP_ADDCONST(GL_ACCUM_ALPHA_BITS); + EXPP_ADDCONST(GL_NAME_STACK_DEPTH); + EXPP_ADDCONST(GL_AUTO_NORMAL); + EXPP_ADDCONST(GL_MAP1_COLOR_4); + EXPP_ADDCONST(GL_MAP1_INDEX); + EXPP_ADDCONST(GL_MAP1_NORMAL); + EXPP_ADDCONST(GL_MAP1_TEXTURE_COORD_1); + EXPP_ADDCONST(GL_MAP1_TEXTURE_COORD_2); + EXPP_ADDCONST(GL_MAP1_TEXTURE_COORD_3); + EXPP_ADDCONST(GL_MAP1_TEXTURE_COORD_4); + EXPP_ADDCONST(GL_MAP1_VERTEX_3); + EXPP_ADDCONST(GL_MAP1_VERTEX_4); + EXPP_ADDCONST(GL_MAP2_COLOR_4); + EXPP_ADDCONST(GL_MAP2_INDEX); + EXPP_ADDCONST(GL_MAP2_NORMAL); + EXPP_ADDCONST(GL_MAP2_TEXTURE_COORD_1); + EXPP_ADDCONST(GL_MAP2_TEXTURE_COORD_2); + EXPP_ADDCONST(GL_MAP2_TEXTURE_COORD_3); + EXPP_ADDCONST(GL_MAP2_TEXTURE_COORD_4); + EXPP_ADDCONST(GL_MAP2_VERTEX_3); + EXPP_ADDCONST(GL_MAP2_VERTEX_4); + EXPP_ADDCONST(GL_MAP1_GRID_DOMAIN); + EXPP_ADDCONST(GL_MAP1_GRID_SEGMENTS); + EXPP_ADDCONST(GL_MAP2_GRID_DOMAIN); + EXPP_ADDCONST(GL_MAP2_GRID_SEGMENTS); + EXPP_ADDCONST(GL_TEXTURE_1D); + EXPP_ADDCONST(GL_TEXTURE_2D); + + EXPP_ADDCONST(GL_TEXTURE_WIDTH); + EXPP_ADDCONST(GL_TEXTURE_HEIGHT); + EXPP_ADDCONST(GL_TEXTURE_COMPONENTS); + EXPP_ADDCONST(GL_TEXTURE_BORDER_COLOR); + EXPP_ADDCONST(GL_TEXTURE_BORDER); + + EXPP_ADDCONST(GL_DONT_CARE); + EXPP_ADDCONST(GL_FASTEST); + EXPP_ADDCONST(GL_NICEST); + + EXPP_ADDCONST(GL_AMBIENT); + EXPP_ADDCONST(GL_DIFFUSE); + EXPP_ADDCONST(GL_SPECULAR); + EXPP_ADDCONST(GL_POSITION); + EXPP_ADDCONST(GL_SPOT_DIRECTION); + EXPP_ADDCONST(GL_SPOT_EXPONENT); + EXPP_ADDCONST(GL_SPOT_CUTOFF); + EXPP_ADDCONST(GL_CONSTANT_ATTENUATION); + EXPP_ADDCONST(GL_LINEAR_ATTENUATION); + EXPP_ADDCONST(GL_QUADRATIC_ATTENUATION); + + EXPP_ADDCONST(GL_COMPILE); + EXPP_ADDCONST(GL_COMPILE_AND_EXECUTE); + + EXPP_ADDCONST(GL_BYTE); + EXPP_ADDCONST(GL_UNSIGNED_BYTE); + EXPP_ADDCONST(GL_SHORT); + EXPP_ADDCONST(GL_UNSIGNED_SHORT); + EXPP_ADDCONST(GL_INT); + EXPP_ADDCONST(GL_UNSIGNED_INT); + EXPP_ADDCONST(GL_FLOAT); + EXPP_ADDCONST(GL_DOUBLE); + EXPP_ADDCONST(GL_2_BYTES); + EXPP_ADDCONST(GL_3_BYTES); + EXPP_ADDCONST(GL_4_BYTES); + + EXPP_ADDCONST(GL_CLEAR); + EXPP_ADDCONST(GL_AND); + EXPP_ADDCONST(GL_AND_REVERSE); + EXPP_ADDCONST(GL_COPY); + EXPP_ADDCONST(GL_AND_INVERTED); + EXPP_ADDCONST(GL_NOOP); + EXPP_ADDCONST(GL_XOR); + EXPP_ADDCONST(GL_OR); + EXPP_ADDCONST(GL_NOR); + EXPP_ADDCONST(GL_EQUIV); + EXPP_ADDCONST(GL_INVERT); + EXPP_ADDCONST(GL_OR_REVERSE); + EXPP_ADDCONST(GL_COPY_INVERTED); + EXPP_ADDCONST(GL_OR_INVERTED); + EXPP_ADDCONST(GL_NAND); + EXPP_ADDCONST(GL_SET); + + EXPP_ADDCONST(GL_EMISSION); + EXPP_ADDCONST(GL_SHININESS); + EXPP_ADDCONST(GL_AMBIENT_AND_DIFFUSE); + EXPP_ADDCONST(GL_COLOR_INDEXES); + + EXPP_ADDCONST(GL_MODELVIEW); + EXPP_ADDCONST(GL_PROJECTION); + EXPP_ADDCONST(GL_TEXTURE); + + EXPP_ADDCONST(GL_COLOR); + EXPP_ADDCONST(GL_DEPTH); + EXPP_ADDCONST(GL_STENCIL); + + EXPP_ADDCONST(GL_COLOR_INDEX); + EXPP_ADDCONST(GL_STENCIL_INDEX); + EXPP_ADDCONST(GL_DEPTH_COMPONENT); + EXPP_ADDCONST(GL_RED); + EXPP_ADDCONST(GL_GREEN); + EXPP_ADDCONST(GL_BLUE); + EXPP_ADDCONST(GL_ALPHA); + EXPP_ADDCONST(GL_RGB); + EXPP_ADDCONST(GL_RGBA); + EXPP_ADDCONST(GL_LUMINANCE); + EXPP_ADDCONST(GL_LUMINANCE_ALPHA); + + EXPP_ADDCONST(GL_BITMAP); + + EXPP_ADDCONST(GL_POINT); + EXPP_ADDCONST(GL_LINE); + EXPP_ADDCONST(GL_FILL); + + EXPP_ADDCONST(GL_RENDER); + EXPP_ADDCONST(GL_FEEDBACK); + EXPP_ADDCONST(GL_SELECT); + + EXPP_ADDCONST(GL_FLAT); + EXPP_ADDCONST(GL_SMOOTH); + + EXPP_ADDCONST(GL_KEEP); + EXPP_ADDCONST(GL_REPLACE); + EXPP_ADDCONST(GL_INCR); + EXPP_ADDCONST(GL_DECR); + + EXPP_ADDCONST(GL_VENDOR); + EXPP_ADDCONST(GL_RENDERER); + EXPP_ADDCONST(GL_VERSION); + EXPP_ADDCONST(GL_EXTENSIONS); + + EXPP_ADDCONST(GL_S); + EXPP_ADDCONST(GL_T); + EXPP_ADDCONST(GL_R); + EXPP_ADDCONST(GL_Q); + + EXPP_ADDCONST(GL_MODULATE); + EXPP_ADDCONST(GL_DECAL); + + EXPP_ADDCONST(GL_TEXTURE_ENV_MODE); + EXPP_ADDCONST(GL_TEXTURE_ENV_COLOR); + + EXPP_ADDCONST(GL_TEXTURE_ENV); + + EXPP_ADDCONST(GL_EYE_LINEAR); + EXPP_ADDCONST(GL_OBJECT_LINEAR); + EXPP_ADDCONST(GL_SPHERE_MAP); + + EXPP_ADDCONST(GL_TEXTURE_GEN_MODE); + EXPP_ADDCONST(GL_OBJECT_PLANE); + EXPP_ADDCONST(GL_EYE_PLANE); + + EXPP_ADDCONST(GL_NEAREST); + EXPP_ADDCONST(GL_LINEAR); + + EXPP_ADDCONST(GL_NEAREST_MIPMAP_NEAREST); + EXPP_ADDCONST(GL_LINEAR_MIPMAP_NEAREST); + EXPP_ADDCONST(GL_NEAREST_MIPMAP_LINEAR); + EXPP_ADDCONST(GL_LINEAR_MIPMAP_LINEAR); + + EXPP_ADDCONST(GL_TEXTURE_MAG_FILTER); + EXPP_ADDCONST(GL_TEXTURE_MIN_FILTER); + EXPP_ADDCONST(GL_TEXTURE_WRAP_S); + EXPP_ADDCONST(GL_TEXTURE_WRAP_T); + + EXPP_ADDCONST(GL_CLAMP); + EXPP_ADDCONST(GL_REPEAT); + + EXPP_ADDCONST(GL_CLIP_PLANE0); + EXPP_ADDCONST(GL_CLIP_PLANE1); + EXPP_ADDCONST(GL_CLIP_PLANE2); + EXPP_ADDCONST(GL_CLIP_PLANE3); + EXPP_ADDCONST(GL_CLIP_PLANE4); + EXPP_ADDCONST(GL_CLIP_PLANE5); + + EXPP_ADDCONST(GL_LIGHT0); + EXPP_ADDCONST(GL_LIGHT1); + EXPP_ADDCONST(GL_LIGHT2); + EXPP_ADDCONST(GL_LIGHT3); + EXPP_ADDCONST(GL_LIGHT4); + EXPP_ADDCONST(GL_LIGHT5); + EXPP_ADDCONST(GL_LIGHT6); + EXPP_ADDCONST(GL_LIGHT7); + + EXPP_ADDCONST(GL_POLYGON_OFFSET_UNITS); + EXPP_ADDCONST(GL_POLYGON_OFFSET_POINT); + EXPP_ADDCONST(GL_POLYGON_OFFSET_LINE); + EXPP_ADDCONST(GL_POLYGON_OFFSET_FILL); + EXPP_ADDCONST(GL_POLYGON_OFFSET_FACTOR); + + EXPP_ADDCONST(GL_TEXTURE_PRIORITY); + EXPP_ADDCONST(GL_TEXTURE_RESIDENT); + EXPP_ADDCONST(GL_TEXTURE_BINDING_1D); + EXPP_ADDCONST(GL_TEXTURE_BINDING_2D); + + return mod; +} + diff --git a/source/blender/python/api2_2x/BGL.h b/source/blender/python/api2_2x/BGL.h new file mode 100644 index 00000000000..c7fbf079010 --- /dev/null +++ b/source/blender/python/api2_2x/BGL.h @@ -0,0 +1,333 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +/* This is the Blender.BGL part of opy_draw.c, from the old bpython/intern + * dir, with minor changes to adapt it to the new Python implementation. + * The BGL submodule "wraps" OpenGL functions and constants, allowing script + * writers to make OpenGL calls in their Python scripts for Blender. The + * more important original comments are marked with an @ symbol. */ + +#ifndef EXPP_BGL_H +#define EXPP_BGL_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include "BIF_gl.h" + + +/*@ Buffer Object */ +/*@ For Python access to OpenGL functions requiring a pointer. */ + +typedef struct _Buffer { + PyObject_VAR_HEAD + PyObject * parent; + + int type; /* GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT */ + int ndimensions; + int *dimensions; + + union { + char *asbyte; + short *asshort; + int *asint; + float *asfloat; + double *asdouble; + + void *asvoid; + } buf; +} Buffer; + + +/*@ By golly George! It looks like fancy pants macro time!!! */ + +/* +#define int_str "i" +#define int_var(number) bgl_int##number +#define int_ref(number) &bgl_int##number +#define int_def(number) int int_var(number) + +#define float_str "f" +#define float_var(number) bgl_float##number +#define float_ref(number) &bgl_float##number +#define float_def(number) float float_var(number) +*/ + +/* TYPE_str is the string to pass to Py_ArgParse (for the format) */ +/* TYPE_var is the name to pass to the GL function */ +/* TYPE_ref is the pointer to pass to Py_ArgParse (to store in) */ +/* TYPE_def is the C initialization of the variable */ + +#define void_str "" +#define void_var(num) +#define void_ref(num) &bgl_var##num +#define void_def(num) char bgl_var##num + +#define buffer_str "O!" +#define buffer_var(number) (bgl_buffer##number)->buf.asvoid +#define buffer_ref(number) &buffer_Type, &bgl_buffer##number +#define buffer_def(number) Buffer *bgl_buffer##number + +/* GL Pointer fields, handled by buffer type */ +/* GLdoubleP, GLfloatP, GLintP, GLuintP, GLshortP */ + +#define GLbooleanP_str "O!" +#define GLbooleanP_var(number) (bgl_buffer##number)->buf.asvoid +#define GLbooleanP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLbooleanP_def(number) Buffer *bgl_buffer##number + +#define GLbyteP_str "O!" +#define GLbyteP_var(number) (bgl_buffer##number)->buf.asvoid +#define GLbyteP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLbyteP_def(number) Buffer *bgl_buffer##number + +#define GLubyteP_str "O!" +#define GLubyteP_var(number) (bgl_buffer##number)->buf.asvoid +#define GLubyteP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLubyteP_def(number) Buffer *bgl_buffer##number + +#define GLintP_str "O!" +#define GLintP_var(number) (bgl_buffer##number)->buf.asvoid +#define GLintP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLintP_def(number) Buffer *bgl_buffer##number + +#define GLuintP_str "O!" +#define GLuintP_var(number) (bgl_buffer##number)->buf.asvoid +#define GLuintP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLuintP_def(number) Buffer *bgl_buffer##number + +#define GLshortP_str "O!" +#define GLshortP_var(number) (bgl_buffer##number)->buf.asvoid +#define GLshortP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLshortP_def(number) Buffer *bgl_buffer##number + +#define GLushortP_str "O!" +#define GLushortP_var(number) (bgl_buffer##number)->buf.asvoid +#define GLushortP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLushortP_def(number) Buffer *bgl_buffer##number + +#define GLfloatP_str "O!" +#define GLfloatP_var(number) (bgl_buffer##number)->buf.asvoid +#define GLfloatP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLfloatP_def(number) Buffer *bgl_buffer##number + +#define GLdoubleP_str "O!" +#define GLdoubleP_var(number) (bgl_buffer##number)->buf.asvoid +#define GLdoubleP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLdoubleP_def(number) Buffer *bgl_buffer##number + +#define GLclampfP_str "O!" +#define GLclampfP_var(number) (bgl_buffer##number)->buf.asvoid +#define GLclampfP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLclampfP_def(number) Buffer *bgl_buffer##number + +#define GLvoidP_str "O!" +#define GLvoidP_var(number) (bgl_buffer##number)->buf.asvoid +#define GLvoidP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLvoidP_def(number) Buffer *bgl_buffer##number + +#define buffer_str "O!" +#define buffer_var(number) (bgl_buffer##number)->buf.asvoid +#define buffer_ref(number) &buffer_Type, &bgl_buffer##number +#define buffer_def(number) Buffer *bgl_buffer##number + +/*@The standard GL typedefs are used as prototypes, we can't + * use the GL type directly because Py_ArgParse expects normal + * C types. + * + * Py_ArgParse doesn't grok writing into unsigned variables, + * so we use signed everything (even stuff that should be unsigned. + */ + +/* typedef unsigned int GLenum; */ +#define GLenum_str "i" +#define GLenum_var(num) bgl_var##num +#define GLenum_ref(num) &bgl_var##num +#define GLenum_def(num) /* unsigned */ int GLenum_var(num) + +/* typedef unsigned int GLboolean; */ +#define GLboolean_str "b" +#define GLboolean_var(num) bgl_var##num +#define GLboolean_ref(num) &bgl_var##num +#define GLboolean_def(num) /* unsigned */ char GLboolean_var(num) + +/* typedef unsigned int GLbitfield; */ +#define GLbitfield_str "i" +#define GLbitfield_var(num) bgl_var##num +#define GLbitfield_ref(num) &bgl_var##num +#define GLbitfield_def(num) /* unsigned */ int GLbitfield_var(num) + +/* typedef signed char GLbyte; */ +#define GLbyte_str "b" +#define GLbyte_var(num) bgl_var##num +#define GLbyte_ref(num) &bgl_var##num +#define GLbyte_def(num) signed char GLbyte_var(num) + +/* typedef short GLshort; */ +#define GLshort_str "h" +#define GLshort_var(num) bgl_var##num +#define GLshort_ref(num) &bgl_var##num +#define GLshort_def(num) short GLshort_var(num) + +/* typedef int GLint; */ +#define GLint_str "i" +#define GLint_var(num) bgl_var##num +#define GLint_ref(num) &bgl_var##num +#define GLint_def(num) int GLint_var(num) + +/* typedef int GLsizei; */ +#define GLsizei_str "i" +#define GLsizei_var(num) bgl_var##num +#define GLsizei_ref(num) &bgl_var##num +#define GLsizei_def(num) int GLsizei_var(num) + +/* typedef unsigned char GLubyte; */ +#define GLubyte_str "b" +#define GLubyte_var(num) bgl_var##num +#define GLubyte_ref(num) &bgl_var##num +#define GLubyte_def(num) /* unsigned */ char GLubyte_var(num) + +/* typedef unsigned short GLushort; */ +#define GLushort_str "h" +#define GLushort_var(num) bgl_var##num +#define GLushort_ref(num) &bgl_var##num +#define GLushort_def(num) /* unsigned */ short GLushort_var(num) + +/* typedef unsigned int GLuint; */ +#define GLuint_str "i" +#define GLuint_var(num) bgl_var##num +#define GLuint_ref(num) &bgl_var##num +#define GLuint_def(num) /* unsigned */ int GLuint_var(num) + +/* typedef float GLfloat; */ +#define GLfloat_str "f" +#define GLfloat_var(num) bgl_var##num +#define GLfloat_ref(num) &bgl_var##num +#define GLfloat_def(num) float GLfloat_var(num) + +/* typedef float GLclampf; */ +#define GLclampf_str "f" +#define GLclampf_var(num) bgl_var##num +#define GLclampf_ref(num) &bgl_var##num +#define GLclampf_def(num) float GLclampf_var(num) + +/* typedef double GLdouble; */ +#define GLdouble_str "d" +#define GLdouble_var(num) bgl_var##num +#define GLdouble_ref(num) &bgl_var##num +#define GLdouble_def(num) double GLdouble_var(num) + +/* typedef double GLclampd; */ +#define GLclampd_str "d" +#define GLclampd_var(num) bgl_var##num +#define GLclampd_ref(num) &bgl_var##num +#define GLclampd_def(num) double GLclampd_var(num) + +/* typedef void GLvoid; */ +/* #define GLvoid_str "" */ +/* #define GLvoid_var(num) bgl_var##num */ +/* #define GLvoid_ref(num) &bgl_var##num */ +/* #define GLvoid_def(num) char bgl_var##num */ + +#define arg_def1(a1) a1##_def(1) +#define arg_def2(a1, a2) arg_def1(a1); a2##_def(2) +#define arg_def3(a1, a2, a3) arg_def2(a1, a2); a3##_def(3) +#define arg_def4(a1, a2, a3, a4) arg_def3(a1, a2, a3); a4##_def(4) +#define arg_def5(a1, a2, a3, a4, a5) arg_def4(a1, a2, a3, a4); a5##_def(5) +#define arg_def6(a1, a2, a3, a4, a5, a6)arg_def5(a1, a2, a3, a4, a5); a6##_def(6) +#define arg_def7(a1, a2, a3, a4, a5, a6, a7)arg_def6(a1, a2, a3, a4, a5, a6); a7##_def(7) +#define arg_def8(a1, a2, a3, a4, a5, a6, a7, a8)arg_def7(a1, a2, a3, a4, a5, a6, a7); a8##_def(8) +#define arg_def9(a1, a2, a3, a4, a5, a6, a7, a8, a9)arg_def8(a1, a2, a3, a4, a5, a6, a7, a8); a9##_def(9) +#define arg_def10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)arg_def9(a1, a2, a3, a4, a5, a6, a7, a8, a9); a10##_def(10) + +#define arg_var1(a1) a1##_var(1) +#define arg_var2(a1, a2) arg_var1(a1), a2##_var(2) +#define arg_var3(a1, a2, a3) arg_var2(a1, a2), a3##_var(3) +#define arg_var4(a1, a2, a3, a4) arg_var3(a1, a2, a3), a4##_var(4) +#define arg_var5(a1, a2, a3, a4, a5) arg_var4(a1, a2, a3, a4), a5##_var(5) +#define arg_var6(a1, a2, a3, a4, a5, a6)arg_var5(a1, a2, a3, a4, a5), a6##_var(6) +#define arg_var7(a1, a2, a3, a4, a5, a6, a7)arg_var6(a1, a2, a3, a4, a5, a6), a7##_var(7) +#define arg_var8(a1, a2, a3, a4, a5, a6, a7, a8)arg_var7(a1, a2, a3, a4, a5, a6, a7), a8##_var(8) +#define arg_var9(a1, a2, a3, a4, a5, a6, a7, a8, a9)arg_var8(a1, a2, a3, a4, a5, a6, a7, a8), a9##_var(9) +#define arg_var10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)arg_var9(a1, a2, a3, a4, a5, a6, a7, a8, a9), a10##_var(10) + +#define arg_ref1(a1) a1##_ref(1) +#define arg_ref2(a1, a2) arg_ref1(a1), a2##_ref(2) +#define arg_ref3(a1, a2, a3) arg_ref2(a1, a2), a3##_ref(3) +#define arg_ref4(a1, a2, a3, a4) arg_ref3(a1, a2, a3), a4##_ref(4) +#define arg_ref5(a1, a2, a3, a4, a5) arg_ref4(a1, a2, a3, a4), a5##_ref(5) +#define arg_ref6(a1, a2, a3, a4, a5, a6)arg_ref5(a1, a2, a3, a4, a5), a6##_ref(6) +#define arg_ref7(a1, a2, a3, a4, a5, a6, a7)arg_ref6(a1, a2, a3, a4, a5, a6), a7##_ref(7) +#define arg_ref8(a1, a2, a3, a4, a5, a6, a7, a8)arg_ref7(a1, a2, a3, a4, a5, a6, a7), a8##_ref(8) +#define arg_ref9(a1, a2, a3, a4, a5, a6, a7, a8, a9)arg_ref8(a1, a2, a3, a4, a5, a6, a7, a8), a9##_ref(9) +#define arg_ref10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)arg_ref9(a1, a2, a3, a4, a5, a6, a7, a8, a9), a10##_ref(10) + +#define arg_str1(a1) a1##_str +#define arg_str2(a1, a2) arg_str1(a1) a2##_str +#define arg_str3(a1, a2, a3) arg_str2(a1, a2) a3##_str +#define arg_str4(a1, a2, a3, a4) arg_str3(a1, a2, a3) a4##_str +#define arg_str5(a1, a2, a3, a4, a5) arg_str4(a1, a2, a3, a4) a5##_str +#define arg_str6(a1, a2, a3, a4, a5, a6)arg_str5(a1, a2, a3, a4, a5) a6##_str +#define arg_str7(a1, a2, a3, a4, a5, a6, a7)arg_str6(a1, a2, a3, a4, a5, a6) a7##_str +#define arg_str8(a1, a2, a3, a4, a5, a6, a7, a8)arg_str7(a1, a2, a3, a4, a5, a6, a7) a8##_str +#define arg_str9(a1, a2, a3, a4, a5, a6, a7, a8, a9)arg_str8(a1, a2, a3, a4, a5, a6, a7, a8) a9##_str +#define arg_str10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)arg_str9(a1, a2, a3, a4, a5, a6, a7, a8, a9) a10##_str + +#define ret_def_void +#define ret_set_void +#define ret_ret_void return EXPP_incr_ret(Py_None) + +#define ret_def_GLint int ret_int +#define ret_set_GLint ret_int= +#define ret_ret_GLint return PyInt_FromLong(ret_int); + +#define ret_def_GLuint unsigned int ret_uint +#define ret_set_GLuint ret_uint= +#define ret_ret_GLuint return PyInt_FromLong((long) ret_uint); + +#define ret_def_GLenum unsigned int ret_uint +#define ret_set_GLenum ret_uint= +#define ret_ret_GLenum return PyInt_FromLong((long) ret_uint); + +#define ret_def_GLboolean unsigned char ret_bool +#define ret_set_GLboolean ret_bool= +#define ret_ret_GLboolean return PyInt_FromLong((long) ret_bool); + +#define ret_def_GLstring const unsigned char *ret_str; +#define ret_set_GLstring ret_str= +#define ret_ret_GLstring return PyString_FromString(ret_str); + + + +#endif /* EXPP_BGL_H */ diff --git a/source/blender/python/api2_2x/BezTriple.c b/source/blender/python/api2_2x/BezTriple.c new file mode 100644 index 00000000000..2aa908ff2b0 --- /dev/null +++ b/source/blender/python/api2_2x/BezTriple.c @@ -0,0 +1,716 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Jacques Guignot RIP 2005, + * Stephen Swaney, Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BezTriple.h" /*This must come first */ +#include "DNA_ipo_types.h" + +#include "MEM_guardedalloc.h" +#include "gen_utils.h" + + +/*************************************************************************** + Python API function prototypes for the BezTriple module. +***************************************************************************/ +static PyObject *M_BezTriple_New( PyObject * self, PyObject * args ); +static PyObject *M_BezTriple_Get( PyObject * self, PyObject * args ); + +/************************************* + Doc strings for the BezTriple module +*************************************/ + +static char M_BezTriple_doc[] = "The Blender BezTriple module\n"; + +/**************************************************************************** + Python BPy_BezTriple instance methods declarations: +****************************************************************************/ +static PyObject *BezTriple_oldsetPoints( BPy_BezTriple * self, PyObject * args ); +static int BezTriple_setPoints( BPy_BezTriple * self, PyObject * args ); +static PyObject *BezTriple_getPoints( BPy_BezTriple * self ); +static PyObject *BezTriple_getTriple( BPy_BezTriple * self ); + +/**************************************************************************** + Python method structure definition for Blender.BezTriple module: +****************************************************************************/ + +struct PyMethodDef M_BezTriple_methods[] = { + {"New", ( PyCFunction ) M_BezTriple_New, METH_VARARGS | METH_KEYWORDS, + 0}, +/* {"New", ( PyCFunction ) M_BezTriple_New, METH_O, 0}, */ + {"Get", M_BezTriple_Get, METH_VARARGS, 0}, + {"get", M_BezTriple_Get, METH_VARARGS, 0}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python BPy_BezTriple methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_BezTriple_methods[] = { + /* name, method, flags, doc */ + {"setPoints", ( PyCFunction ) BezTriple_oldsetPoints, METH_VARARGS, + "(str) - Change BezTriple point coordinates"}, + {"getPoints", ( PyCFunction ) BezTriple_getPoints, METH_NOARGS, + "() - return BezTriple knot point x and y coordinates"}, + {"getTriple", ( PyCFunction ) BezTriple_getTriple, METH_NOARGS, + "() - return list of 3 floating point triplets. order is H1, knot, H2"}, + {NULL, NULL, 0, NULL} +}; + +/**************************************************************************** + Function: M_BezTriple_New + Python equivalent: Blender.BezTriple.New +****************************************************************************/ + +static PyObject *M_BezTriple_New( PyObject* self, PyObject * args ) +{ + float numbuf[9]; + PyObject* in_args = NULL; + int length; + + /* accept list, tuple, or 3 or 9 args (which better be floats) */ + + length = PyTuple_Size( args ); + if( length == 3 || length == 9 ) + in_args = args; + else if( !PyArg_ParseTuple( args, "|O", &in_args) ) + goto TypeError; + + if( !in_args ) { + numbuf[0] = 0.0f; numbuf[1] = 0.0f; numbuf[2] = 0.0f; + numbuf[3] = 0.0f; numbuf[4] = 0.0f; numbuf[5] = 0.0f; + numbuf[6] = 0.0f; numbuf[7] = 0.0f; numbuf[8] = 0.0f; + } else { + int i, length; + if( !PySequence_Check( in_args ) ) + goto TypeError; + + length = PySequence_Length( in_args ); + if( length != 9 && length != 3 ) + goto TypeError; + + for( i = 0; i < length; i++ ) { + PyObject *item, *pyfloat; + item = PySequence_ITEM( in_args, i); + if( !item ) + goto TypeError; + pyfloat = PyNumber_Float( item ); + Py_DECREF( item ); + if( !pyfloat ) + goto TypeError; + numbuf[i] = ( float )PyFloat_AS_DOUBLE( pyfloat ); + Py_DECREF( pyfloat ); + } + + if( length == 3 ) { + numbuf[3] = numbuf[0]; numbuf[6] = numbuf[0]; + numbuf[4] = numbuf[1]; numbuf[7] = numbuf[1]; + numbuf[5] = numbuf[2]; numbuf[8] = numbuf[2]; + } + } + + return newBezTriple( numbuf ); + +TypeError: + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected sequence of 3 or 9 floats or nothing" ); +} + +/**************************************************************************** + Function: M_BezTriple_Get + Python equivalent: Blender.BezTriple.Get + Description: Receives a string and returns the ipo data obj + whose name matches the string. If no argument is + passed in, a list of all ipo data names in the + current scene is returned. +****************************************************************************/ +static PyObject *M_BezTriple_Get( PyObject * self, PyObject * args ) +{ + return 0; +} + +/**************************************************************************** + Function: BezTriple_dealloc + Description: This is a callback function for the BPy_BezTriple type. It is + the destructor function. +****************************************************************************/ +static void BezTriple_dealloc( BPy_BezTriple * self ) +{ + if( self->own_memory) + MEM_freeN( self->beztriple ); + + PyObject_DEL( self ); +} + +/* + * BezTriple_getTriple + * + * Get the coordinate data for a BezTriple. Returns a list of 3 points. + * List order is handle1, knot, handle2. each point consists of a list + * of x,y,z float values. + */ + +static PyObject *BezTriple_getTriple( BPy_BezTriple * self ) +{ + BezTriple *bezt = self->beztriple; + return Py_BuildValue( "[[fff][fff][fff]]", + bezt->vec[0][0], bezt->vec[0][1], bezt->vec[0][2], + bezt->vec[1][0], bezt->vec[1][1], bezt->vec[1][2], + bezt->vec[2][0], bezt->vec[2][1], bezt->vec[2][2] ); +} + +/* + * BezTriple_setTriple + * + * Set the cordinate data for a BezTriple. Takes a sequence of 3 points, + * of the same format at BezTriple_getTriple. + */ + +static int BezTriple_setTriple( BPy_BezTriple * self, PyObject * args ) +{ + int i, j; + struct BezTriple *bezt = self->beztriple; + float vec[3][3]; + + if( !PySequence_Check( args ) || PySequence_Size( args ) != 3 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected three sequences of three floats" ); + + for( i = 0; i < 3; i++ ) { + PyObject *obj1 = PySequence_ITEM( args, i ); + if( !PySequence_Check( obj1 ) || PySequence_Size( obj1 ) != 3 ) { + Py_DECREF( obj1 ); + return EXPP_ReturnIntError( PyExc_TypeError, + "expected three sequences of three floats" ); + } + for( j = 0; j < 3; j++ ) { + PyObject *obj2 = PySequence_ITEM( obj1, j ); + PyObject *num = PyNumber_Float( obj2 ); + Py_DECREF( obj2 ); + + if( !num ) { + Py_DECREF( obj1 ); + return EXPP_ReturnIntError( PyExc_ValueError, + "expected float parameter" ); + } + vec[i][j] = ( float )PyFloat_AsDouble( num ); + Py_DECREF( num ); + } + Py_DECREF( obj1 ); + } + + for( i = 0; i < 3; i++ ) + for( j = 0; j < 3; j++ ) + bezt->vec[i][j] = vec[i][j]; + + return 0; +} + +/* + * BezTriple_getPoint + * + * Get the coordinate data for a BezTriple. Returns the control point, + * as a list of x,y float values. + */ + +static PyObject *BezTriple_getPoints( BPy_BezTriple * self ) +{ + BezTriple *bezt = self->beztriple; + return Py_BuildValue( "[ff]", bezt->vec[1][0], bezt->vec[1][1] ); +} + +/* + * BezTriple_setPoint + * + * Set the coordinate data for a BezTriple. Accepts the x,y for the control + * point and builds handle values based on control point. + */ + +static int BezTriple_setPoints( BPy_BezTriple * self, PyObject * args ) +{ + int i; + struct BezTriple *bezt = self->beztriple; + float vec[2]; + + if( !PySequence_Check( args ) || PySequence_Size( args ) != 2 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected sequence of two floats" ); + + for( i = 0; i < 2; i++ ) { + PyObject *obj = PySequence_ITEM( args, i ); + PyObject *num = PyNumber_Float( obj ); + Py_DECREF( obj ); + + if( !num ) + return EXPP_ReturnIntError( PyExc_ValueError, + "expected float parameter" ); + vec[i] = ( float )PyFloat_AsDouble( num ); + Py_DECREF( num ); + } + + for( i = 0; i < 2; i++ ) { + bezt->vec[0][i] = vec[i] - 1; + bezt->vec[1][i] = vec[i]; + bezt->vec[2][i] = vec[i] + 1; + } + + /* experimental fussing with handles - ipo.c: calchandles_ipocurve */ + if( bezt->vec[0][0] > bezt->vec[1][0] ) + bezt->vec[0][0] = bezt->vec[1][0]; + + if( bezt->vec[2][0] < bezt->vec[1][0] ) + bezt->vec[2][0] = bezt->vec[1][0]; + + return 0; +} + +static PyObject *BezTriple_getTilt( BPy_BezTriple * self ) +{ + return PyFloat_FromDouble( self->beztriple->alfa ); +} + +static int BezTriple_setTilt( BPy_BezTriple * self, PyObject *value ) +{ + PyObject *num = PyNumber_Float( value ); + + if( !num ) + return EXPP_ReturnIntError( PyExc_TypeError, "expected a float" ); + + self->beztriple->alfa = (float)PyFloat_AsDouble( num ); + Py_DECREF( num ); + return 0; +} + +static PyObject *BezTriple_getWeight( BPy_BezTriple * self ) +{ + return PyFloat_FromDouble( self->beztriple->weight ); +} + +static int BezTriple_setWeight( BPy_BezTriple * self, PyObject *value ) +{ + PyObject *num = PyNumber_Float( value ); + + if( !num ) + return EXPP_ReturnIntError( PyExc_TypeError, "expected a float" ); + + self->beztriple->weight = (float)PyFloat_AsDouble( num ); + Py_DECREF( num ); + return 0; +} + +static PyObject *BezTriple_getRadius( BPy_BezTriple * self ) +{ + return PyFloat_FromDouble( self->beztriple->radius ); +} + +static int BezTriple_setRadius( BPy_BezTriple * self, PyObject *value ) +{ + PyObject *num = PyNumber_Float( value ); + + if( !num ) + return EXPP_ReturnIntError( PyExc_TypeError, "expected a float" ); + + self->beztriple->radius = (float)PyFloat_AsDouble( num ); + Py_DECREF( num ); + return 0; +} + +static PyObject *BezTriple_getHide( BPy_BezTriple * self ) +{ + return PyInt_FromLong( self->beztriple->hide == IPO_BEZ ); +} + +static int BezTriple_setHide( BPy_BezTriple * self, PyObject *value ) +{ + int param = PyObject_IsTrue( value ); + if( param == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected True/False or 0/1" ); + + if( param ) + self->beztriple->hide = IPO_BEZ; + else + self->beztriple->hide = 0; + return 0; +} + +static PyObject *BezTriple_getSelects( BPy_BezTriple * self ) +{ + BezTriple *bezt = self->beztriple; + + return Py_BuildValue( "[iii]", bezt->f1, bezt->f2, bezt->f3 ); +} + +static int BezTriple_setSelects( BPy_BezTriple * self, PyObject *args ) +{ + struct BezTriple *bezt = self->beztriple; + PyObject *ob1, *ob2, *ob3; + int param1, param2, param3; + + /* only accept a sequence of three booleans */ + + if( !PySequence_Check( args ) || PySequence_Size( args ) != 3 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected sequence of three integers" ); + + ob1 = PySequence_ITEM( args, 0 ); + ob2 = PySequence_ITEM( args, 1 ); + ob3 = PySequence_ITEM( args, 2 ); + + param1 = PyObject_IsTrue( ob1 ); + param2 = PyObject_IsTrue( ob2 ); + param3 = PyObject_IsTrue( ob3 ); + + if (param1==-1 || param2==-1 || param3==-1) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a sequence of 3 items: True/False or 0/1" ); + + /* assign the selects */ + bezt->f1 = (char)param1; + bezt->f2 = (char)param2; + bezt->f3 = (char)param3; + + Py_DECREF( ob1 ); + Py_DECREF( ob2 ); + Py_DECREF( ob3 ); + return 0; +} + +static PyObject *BezTriple_getHandles( BPy_BezTriple * self ) +{ + BezTriple *bezt = self->beztriple; + + return Py_BuildValue( "[ii]", bezt->h1, bezt->h2 ); +} + +static int BezTriple_setHandles( BPy_BezTriple * self, PyObject *args ) +{ + struct BezTriple *bezt = self->beztriple; + PyObject *ob1, *ob2; + short h1, h2; + + /* only accept a sequence of two ints */ + + if( !PySequence_Check( args ) || PySequence_Size( args ) != 2 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected sequence of two integers" ); + + ob1 = PySequence_ITEM( args, 0 ); + ob2 = PySequence_ITEM( args, 1 ); + + if( !PyInt_Check( ob1 ) || !PyInt_Check( ob2 ) ) { + Py_DECREF( ob1 ); + Py_DECREF( ob2 ); + return EXPP_ReturnIntError( PyExc_TypeError, + "expected sequence of two integers" ); + } + + h1 = ( short ) PyInt_AsLong( ob1 ); + h2 = ( short ) PyInt_AsLong( ob2 ); + Py_DECREF( ob1 ); + Py_DECREF( ob2 ); + + if( h1 < HD_FREE || h2 < HD_FREE || + h1 > HD_AUTO_ANIM || h2 > HD_AUTO_ANIM ) + return EXPP_ReturnIntError( PyExc_ValueError, + "expected int in range [0,4]" ); + + /* assign the handles */ + + bezt->h1 = h1; + bezt->h2 = h2; + + return 0; +} + +/* + * Python BezTriple attributes get/set structure + */ + +static PyGetSetDef BPy_BezTriple_getseters[] = { + {"pt", + (getter)BezTriple_getPoints, (setter)BezTriple_setPoints, + "point knot values", + NULL}, + {"vec", + (getter)BezTriple_getTriple, (setter)BezTriple_setTriple, + "point handle and knot values", + NULL}, + {"tilt", + (getter)BezTriple_getTilt, (setter)BezTriple_setTilt, + "point tilt", + NULL}, + {"hide", + (getter)BezTriple_getHide, (setter)BezTriple_setHide, + "point hide status", + NULL}, + {"selects", + (getter)BezTriple_getSelects, (setter)BezTriple_setSelects, + "point select statuses", + NULL}, + {"handleTypes", + (getter)BezTriple_getHandles, (setter)BezTriple_setHandles, + "point handle types", + NULL}, + {"weight", + (getter)BezTriple_getWeight, (setter)BezTriple_setWeight, + "point weight", + NULL}, + {"radius", + (getter)BezTriple_getRadius, (setter)BezTriple_setRadius, + "point radius", + NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/*****************************************************************************/ +/* Function: BezTriple_repr */ +/* Description: This is a callback function for the BPy_BezTriple type. It */ +/* builds a meaninful string to represent BezTriple objects. */ +/*****************************************************************************/ +static PyObject *BezTriple_repr( BPy_BezTriple * self ) +{ + char str[512]; + sprintf( str, + "[BezTriple [%.6f, %.6f, %.6f] [%.6f, %.6f, %.6f] [%.6f, %.6f, %.6f]\n", + self->beztriple->vec[0][0], self->beztriple->vec[0][1], self->beztriple->vec[0][2], + self->beztriple->vec[1][0], self->beztriple->vec[1][1], self->beztriple->vec[1][2], + self->beztriple->vec[2][0], self->beztriple->vec[2][1], self->beztriple->vec[2][2]); + return PyString_FromString( str ); +} + +/************************************************************************ + * + * Python BezTriple_Type structure definition + * + ************************************************************************/ + +PyTypeObject BezTriple_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "BezTriple", /* char *tp_name; */ + sizeof( BPy_BezTriple ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + ( destructor ) BezTriple_dealloc,/* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + ( reprfunc ) BezTriple_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_BezTriple_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_BezTriple_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +static PyObject *M_BezTriple_HandleDict( void ) +{ + PyObject *HM = PyConstant_New( ); + + if( HM ) { + BPy_constant *d = ( BPy_constant * ) HM; + + PyConstant_Insert( d, "FREE", PyInt_FromLong( HD_FREE ) ); + PyConstant_Insert( d, "AUTO", PyInt_FromLong( HD_AUTO ) ); + PyConstant_Insert( d, "VECT", PyInt_FromLong( HD_VECT ) ); + PyConstant_Insert( d, "ALIGN", PyInt_FromLong( HD_ALIGN ) ); + PyConstant_Insert( d, "AUTOANIM", PyInt_FromLong( HD_AUTO_ANIM ) ); + } + return HM; +} + +/* + BezTriple_Init +*/ + +PyObject *BezTriple_Init( void ) +{ + PyObject *submodule; + PyObject *HandleTypes = M_BezTriple_HandleDict( ); + + if( PyType_Ready( &BezTriple_Type ) < 0 ) + return NULL; + + submodule = Py_InitModule3( "Blender.BezTriple", + M_BezTriple_methods, + M_BezTriple_doc ); + if( HandleTypes ) + PyModule_AddObject( submodule, "HandleTypes", HandleTypes ); + + + return submodule; +} + +/* Three Python BezTriple_Type helper functions needed by the Object module: */ + +/**************************************************************************** + Function: BezTriple_CreatePyObject + Description: This function will create a new BPy_BezTriple from an existing + Blender ipo structure. +****************************************************************************/ +PyObject *BezTriple_CreatePyObject( BezTriple * bzt ) +{ + BPy_BezTriple *pybeztriple; + + pybeztriple = + ( BPy_BezTriple * ) PyObject_NEW( BPy_BezTriple, &BezTriple_Type ); + + if( !pybeztriple ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create BPy_BezTriple object" ); + + pybeztriple->beztriple = bzt; + pybeztriple->own_memory = 0; + + return ( PyObject * ) pybeztriple; +} + + +/*****************************************************************************/ +/* Function: BezTriple_FromPyObject */ +/* Description: This function returns the Blender beztriple from the given */ +/* PyObject. */ +/*****************************************************************************/ +BezTriple *BezTriple_FromPyObject( PyObject * pyobj ) +{ + return ( ( BPy_BezTriple * ) pyobj )->beztriple; +} + + +/* + Create a new BezTriple + input args is a sequence - either 3 or 9 floats +*/ + +PyObject *newBezTriple( float *numbuf ) +{ + int i, j, num; + PyObject *pyobj = NULL; + BezTriple *bzt = NULL; + + /* create our own beztriple data */ + bzt = MEM_callocN( sizeof( BezTriple ), "new bpytriple"); + + /* check malloc */ + if( !bzt ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "MEM_callocN failed"); + + /* copy the data */ + num = 0; + for( i = 0; i < 3; i++ ) { + for( j = 0; j < 3; j++) { + bzt->vec[i][j] = numbuf[num++]; + } + } + bzt->h1 = HD_ALIGN; + bzt->h2 = HD_ALIGN; + + /* wrap it */ + pyobj = BezTriple_CreatePyObject( bzt ); + + /* we own it. must free later */ + ( ( BPy_BezTriple * )pyobj)->own_memory = 1; + + return pyobj; +} + +/* #####DEPRECATED###### */ + +static PyObject *BezTriple_oldsetPoints( BPy_BezTriple * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)BezTriple_setPoints ); +} diff --git a/source/blender/python/api2_2x/BezTriple.h b/source/blender/python/api2_2x/BezTriple.h new file mode 100644 index 00000000000..e2e015b502d --- /dev/null +++ b/source/blender/python/api2_2x/BezTriple.h @@ -0,0 +1,64 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Jacques Guignot, Stephen Swaney + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_BEZTRIPLE_H +#define EXPP_BEZTRIPLE_H + +#include +#include "DNA_curve_types.h" + +extern PyTypeObject BezTriple_Type; + +/* type check macro */ +#define BPy_BezTriple_Check(o) \ + ( (o)->ob_type == &BezTriple_Type) + +/**************************************************************************** + Python BPy_BezTriple structure definition: +****************************************************************************/ + +typedef struct { + PyObject_HEAD /* required python macro */ + BezTriple * beztriple; + int own_memory; /* true == we own this memory and must delete. */ +} BPy_BezTriple; + +/* + * prototypes + */ + +PyObject *BezTriple_CreatePyObject( BezTriple * bzt ); +BezTriple *BezTriple_FromPyObject( PyObject * pyobj ); +PyObject *newBezTriple( float *args ); +PyObject *BezTriple_Init( void ); + +#endif /* EXPP_BEZTRIPLE_H */ diff --git a/source/blender/python/api2_2x/Blender.c b/source/blender/python/api2_2x/Blender.c new file mode 100644 index 00000000000..24b9f4d5186 --- /dev/null +++ b/source/blender/python/api2_2x/Blender.c @@ -0,0 +1,982 @@ +/* + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Michel Selten, Willian P. Germano, Joseph Gilbert, + * Campbell Barton + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ +struct ID; /*keep me up here */ + +#include "Blender.h" /*This must come first */ + +/* for open, close in Blender_Load */ +#include +#include "BDR_editobject.h" /* exit_editmode() */ +#include "BIF_usiblender.h" +#include "BLI_blenlib.h" +#include "BLO_writefile.h" +#include "BKE_blender.h" +#include "BKE_exotic.h" +#include "BKE_global.h" +#include "BKE_packedFile.h" +#include "BKE_utildefines.h" +#include "BKE_object.h" +#include "BKE_scene.h" +#include "BKE_text.h" +#include "BKE_ipo.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BPI_script.h" +#include "BSE_headerbuttons.h" +#include "DNA_screen_types.h" /* for SPACE_VIEW3D */ +#include "DNA_userdef_types.h" +#include "DNA_packedFile_types.h" +#include "EXPP_interface.h" /* for bpy_gethome() */ +#include "gen_utils.h" +#include "modules.h" +#include "constant.h" +#include "../BPY_extern.h" /* BPY_txt_do_python_Text */ +#include "../BPY_menus.h" /* to update menus */ +#include "Armature.h" +#include "BezTriple.h" +#include "Camera.h" +#include "Constraint.h" +#include "Curve.h" +#include "CurNurb.h" +#include "Draw.h" +#include "Effect.h" +#include "Ipo.h" +#include "Ipocurve.h" +#include "IDProp.h" +#include "Key.h" +#include "Lamp.h" +#include "Lattice.h" +#include "Library.h" +#include "Mathutils.h" +#include "Geometry.h" +#include "Mesh.h" +#include "Metaball.h" +#include "Modifier.h" +#include "NMesh.h" +#include "Object.h" +#include "Group.h" +#include "Registry.h" +#include "Scene.h" +#include "Sound.h" +#include "SurfNurb.h" +#include "Sys.h" +#include "Text.h" +#include "Texture.h" +#include "Window.h" +#include "World.h" +#include "Types.h" + +/**********************************************************/ +/* Python API function prototypes for the Blender module. */ +/**********************************************************/ +static PyObject *Blender_Set( PyObject * self, PyObject * args ); +static PyObject *Blender_Get( PyObject * self, PyObject * value ); +static PyObject *Blender_Redraw( PyObject * self, PyObject * args ); +static PyObject *Blender_Quit( PyObject * self ); +static PyObject *Blender_Load( PyObject * self, PyObject * args ); +static PyObject *Blender_Save( PyObject * self, PyObject * args ); +static PyObject *Blender_Run( PyObject * self, PyObject * value ); +static PyObject *Blender_ShowHelp( PyObject * self, PyObject * script ); +static PyObject *Blender_UpdateMenus( PyObject * self); +static PyObject *Blender_PackAll( PyObject * self); +static PyObject *Blender_UnpackAll( PyObject * self, PyObject * value); +static PyObject *Blender_CountPackedFiles( PyObject * self ); + +extern PyObject *Text3d_Init( void ); /* missing in some include */ + +/*****************************************************************************/ +/* The following string definitions are used for documentation strings. */ +/* In Python these will be written to the console when doing a */ +/* Blender.__doc__ */ +/*****************************************************************************/ +static char Blender_Set_doc[] = + "(request, data) - Update settings in Blender\n\ +\n\ +(request) A string identifying the setting to change\n\ + 'curframe' - Sets the current frame using the number in data"; + +static char Blender_Get_doc[] = "(request) - Retrieve settings from Blender\n\ +\n\ +(request) A string indentifying the data to be returned\n\ + 'curframe' - Returns the current animation frame\n\ + 'curtime' - Returns the current animation time\n\ + 'staframe' - Returns the start frame of the animation\n\ + 'endframe' - Returns the end frame of the animation\n\ + 'filename' - Returns the name of the last file read or written\n\ + 'homedir' - Returns Blender's home dir\n\ + 'datadir' - Returns the dir where scripts can save their data, if available\n\ + 'scriptsdir' - Returns the main dir where scripts are kept, if available\n\ + 'uscriptsdir' - Returns the user defined dir for scripts, if available\n\ + 'version' - Returns the Blender version number"; + +static char Blender_Redraw_doc[] = "() - Redraw all 3D windows"; + +static char Blender_Quit_doc[] = + "() - Quit Blender. The current data is saved as 'quit.blend' before leaving."; + +static char Blender_Load_doc[] = "(filename) - Load the given file.\n\ +Supported formats:\n\ +Blender, DXF, Inventor 1.0 ASCII, VRML 1.0 asc, STL, Videoscape, radiogour.\n\ +\n\ +Notes:\n\ +1 - () - an empty argument loads the default .B.blend file;\n\ +2 - if the substring '.B.blend' occurs inside 'filename', the default\n\ +.B.blend file is loaded;\n\ +3 - If a Blender file is loaded the script ends immediately.\n\ +4 - The current data is always preserved as an autosave file, for safety;\n\ +5 - This function only works if the script where it's executed is the\n\ +only one running at the moment."; + +static char Blender_Save_doc[] = + "(filename) - Save data to a file based on the filename's extension.\n\ +Supported are: Blender's .blend and the builtin exporters:\n\ +VRML 1.0 (.wrl), Videoscape (.obj), DXF (.dxf) and STL (.stl)\n\ +(filename) - A filename with one of the supported extensions.\n\ +Note 1: 'filename' should not contain the substring \".B.blend\" in it.\n\ +Note 2: only .blend raises an error if file wasn't saved.\n\ +\tYou can use Blender.sys.exists(filename) to make sure the file was saved\n\ +\twhen writing to one of the other formats."; + +static char Blender_Run_doc[] = + "(script) - Run the given Python script.\n\ +(script) - the path to a file or the name of an available Blender Text."; + +static char Blender_ShowHelp_doc[] = +"(script) - Show help for the given Python script.\n\ + This will try to open the 'Scripts Help Browser' script, so to have\n\ +any help displayed the passed 'script' must be properly documented\n\ +with the expected strings (check API ref docs or any bundled script\n\ +for examples).\n\n\ +(script) - the filename of a script in the default or user defined\n\ + scripts dir (no need to supply the full path name)."; + +static char Blender_UpdateMenus_doc[] = + "() - Update the menus where scripts are registered. Only needed for\n\ +scripts that save other new scripts in the default or user defined folders."; + +static char Blender_PackAll_doc[] = +"() - Pack all files.\n\ +All files will packed into the blend file."; +static char Blender_UnpackAll_doc[] = +"(mode) - Unpack files.\n\ +All files will be unpacked using specified mode.\n\n\ +(mode) - the unpack mode."; + +static char Blender_CountPackedFiles_doc[] = +"() - Returns the number of packed files."; + +/*****************************************************************************/ +/* Python method structure definition. */ +/*****************************************************************************/ +static struct PyMethodDef Blender_methods[] = { + {"Set", Blender_Set, METH_VARARGS, Blender_Set_doc}, + {"Get", Blender_Get, METH_O, Blender_Get_doc}, + {"Redraw", Blender_Redraw, METH_VARARGS, Blender_Redraw_doc}, + {"Quit", ( PyCFunction ) Blender_Quit, METH_NOARGS, Blender_Quit_doc}, + {"Load", Blender_Load, METH_VARARGS, Blender_Load_doc}, + {"Save", Blender_Save, METH_VARARGS, Blender_Save_doc}, + {"Run", Blender_Run, METH_O, Blender_Run_doc}, + {"ShowHelp", Blender_ShowHelp, METH_O, Blender_ShowHelp_doc}, + {"CountPackedFiles", ( PyCFunction ) Blender_CountPackedFiles, METH_NOARGS, Blender_CountPackedFiles_doc}, + {"PackAll", ( PyCFunction ) Blender_PackAll, METH_NOARGS, Blender_PackAll_doc}, + {"UnpackAll", Blender_UnpackAll, METH_O, Blender_UnpackAll_doc}, + {"UpdateMenus", ( PyCFunction ) Blender_UpdateMenus, METH_NOARGS, + Blender_UpdateMenus_doc}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Global variables */ +/*****************************************************************************/ +PyObject *g_blenderdict; + +/*****************************************************************************/ +/* Function: Blender_Set */ +/* Python equivalent: Blender.Set */ +/*****************************************************************************/ +static PyObject *Blender_Set( PyObject * self, PyObject * args ) +{ + char *name, *dir = NULL; + PyObject *arg; + + if( !PyArg_ParseTuple( args, "sO", &name, &arg ) ) + return EXPP_ReturnPyObjError( PyExc_ValueError, "expected 2 args, where the first is always a string" ); + + if( StringEqual( name, "curframe" ) ) { + if( !PyInt_Check( arg ) ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "expected an integer" ); + + G.scene->r.cfra = (short)PyInt_AsLong( arg ) ; + + /* update all objects, so python scripts can export all objects + in a scene without worrying about the view layers */ + scene_update_for_newframe(G.scene, (1<<20) - 1); + + } else if (StringEqual( name , "uscriptsdir" ) ) { + if ( !PyArg_Parse( arg , "s" , &dir )) + return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string" ); + BLI_strncpy(U.pythondir, dir, FILE_MAXDIR); + } else if (StringEqual( name , "yfexportdir" ) ) { + if ( !PyArg_Parse( arg , "s" , &dir )) + return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string" ); + BLI_strncpy(U.yfexportdir, dir, FILE_MAXDIR); + } else if (StringEqual( name , "fontsdir" ) ) { + if ( !PyArg_Parse( arg , "s" , &dir )) + return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string" ); + BLI_strncpy(U.fontdir, dir, FILE_MAXDIR); + } else if (StringEqual( name , "texturesdir" ) ) { + if ( !PyArg_Parse( arg , "s" , &dir )) + return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string" ); + BLI_strncpy(U.textudir, dir, FILE_MAXDIR); + } else if (StringEqual( name , "texpluginsdir" ) ) { + if ( !PyArg_Parse( arg , "s" , &dir )) + return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string" ); + BLI_strncpy(U.plugtexdir, dir, FILE_MAXDIR); + } else if (StringEqual( name , "seqpluginsdir" ) ) { + if ( !PyArg_Parse( arg , "s" , &dir )) + return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string" ); + BLI_strncpy(U.plugseqdir, dir, FILE_MAXDIR); + } else if (StringEqual( name , "renderdir" ) ) { + if ( !PyArg_Parse( arg , "s" , &dir )) + return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string" ); + BLI_strncpy(U.renderdir, dir, FILE_MAXDIR); + } else if (StringEqual( name , "soundsdir" ) ) { + if ( !PyArg_Parse( arg , "s" , &dir )) + return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string" ); + BLI_strncpy(U.sounddir, dir, FILE_MAXDIR); + } else if (StringEqual( name , "tempdir" ) ) { + if ( !PyArg_Parse( arg , "s" , &dir )) + return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string" ); + BLI_strncpy(U.tempdir, dir, FILE_MAXDIR); + } else + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "value given is not a blender setting" ) ); + Py_RETURN_NONE; +} + +/*****************************************************************************/ +/* Function: Blender_Get */ +/* Python equivalent: Blender.Get */ +/*****************************************************************************/ +static PyObject *Blender_Get( PyObject * self, PyObject * value ) +{ + PyObject *ret = NULL; + char *str = PyString_AsString(value); + + if( !str ) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "expected string argument"); + + if( StringEqual( str, "curframe" ) ) + ret = PyInt_FromLong( G.scene->r.cfra ); + else if( StringEqual( str, "curtime" ) ) + ret = PyFloat_FromDouble( frame_to_float( G.scene->r.cfra ) ); + else if( StringEqual( str, "rt" ) ) + ret = PyInt_FromLong( (long)frame_to_float( G.rt ) ); + else if( StringEqual( str, "staframe" ) ) + ret = PyInt_FromLong( G.scene->r.sfra ); + else if( StringEqual( str, "endframe" ) ) + ret = PyInt_FromLong( G.scene->r.efra ); + else if( StringEqual( str, "filename" ) ) { + if ( strstr(G.main->name, ".B.blend") != 0) + ret = PyString_FromString(""); + else + ret = PyString_FromString(G.main->name); + } + else if( StringEqual( str, "homedir" ) ) { + char *hdir = bpy_gethome(0); + if( hdir && BLI_exists( hdir )) + ret = PyString_FromString( hdir ); + else + ret = EXPP_incr_ret( Py_None ); + } + else if( StringEqual( str, "datadir" ) ) { + char datadir[FILE_MAXDIR]; + char *sdir = bpy_gethome(1); + + if (sdir) { + BLI_make_file_string( "/", datadir, sdir, "bpydata" ); + if( BLI_exists( datadir ) ) + ret = PyString_FromString( datadir ); + } + if (!ret) ret = EXPP_incr_ret( Py_None ); + } + else if(StringEqual(str, "udatadir")) { + if (U.pythondir[0] != '\0') { + char upydir[FILE_MAXDIR]; + + BLI_strncpy(upydir, U.pythondir, FILE_MAXDIR); + BLI_convertstringcode(upydir, G.sce, 0); + + if (BLI_exists(upydir)) { + char udatadir[FILE_MAXDIR]; + + BLI_make_file_string("/", udatadir, upydir, "bpydata"); + + if (BLI_exists(udatadir)) + ret = PyString_FromString(udatadir); + } + } + if (!ret) ret = EXPP_incr_ret(Py_None); + } + else if( StringEqual( str, "scriptsdir" ) ) { + char *sdir = bpy_gethome(1); + + if (sdir) + ret = PyString_FromString(sdir); + else + ret = EXPP_incr_ret( Py_None ); + } + else if( StringEqual( str, "uscriptsdir" ) ) { + if (U.pythondir[0] != '\0') { + char upydir[FILE_MAXDIR]; + + BLI_strncpy(upydir, U.pythondir, FILE_MAXDIR); + BLI_convertstringcode(upydir, G.sce, 0); + + if( BLI_exists( upydir ) ) + ret = PyString_FromString( upydir ); + } + if (!ret) ret = EXPP_incr_ret(Py_None); + } + /* USER PREFS: */ + else if( StringEqual( str, "yfexportdir" ) ) { + if (U.yfexportdir[0] != '\0') { + char yfexportdir[FILE_MAXDIR]; + + BLI_strncpy(yfexportdir, U.yfexportdir, FILE_MAXDIR); + BLI_convertstringcode(yfexportdir, G.sce, 0); + + if( BLI_exists( yfexportdir ) ) + ret = PyString_FromString( yfexportdir ); + } + if (!ret) ret = EXPP_incr_ret(Py_None); + } + /* fontsdir */ + else if( StringEqual( str, "fontsdir" ) ) { + if (U.fontdir[0] != '\0') { + char fontdir[FILE_MAXDIR]; + + BLI_strncpy(fontdir, U.fontdir, FILE_MAXDIR); + BLI_convertstringcode(fontdir, G.sce, 0); + + if( BLI_exists( fontdir ) ) + ret = PyString_FromString( fontdir ); + } + if (!ret) ret = EXPP_incr_ret(Py_None); + } + /* texturesdir */ + else if( StringEqual( str, "texturesdir" ) ) { + if (U.textudir[0] != '\0') { + char textudir[FILE_MAXDIR]; + + BLI_strncpy(textudir, U.textudir, FILE_MAXDIR); + BLI_convertstringcode(textudir, G.sce, 0); + + if( BLI_exists( textudir ) ) + ret = PyString_FromString( textudir ); + } + if (!ret) ret = EXPP_incr_ret(Py_None); + } + /* texpluginsdir */ + else if( StringEqual( str, "texpluginsdir" ) ) { + if (U.plugtexdir[0] != '\0') { + char plugtexdir[FILE_MAXDIR]; + + BLI_strncpy(plugtexdir, U.plugtexdir, FILE_MAXDIR); + BLI_convertstringcode(plugtexdir, G.sce, 0); + + if( BLI_exists( plugtexdir ) ) + ret = PyString_FromString( plugtexdir ); + } + if (!ret) ret = EXPP_incr_ret(Py_None); + } + /* seqpluginsdir */ + else if( StringEqual( str, "seqpluginsdir" ) ) { + if (U.plugseqdir[0] != '\0') { + char plugseqdir[FILE_MAXDIR]; + + BLI_strncpy(plugseqdir, U.plugseqdir, FILE_MAXDIR); + BLI_convertstringcode(plugseqdir, G.sce, 0); + + if( BLI_exists( plugseqdir ) ) + ret = PyString_FromString( plugseqdir ); + } + if (!ret) ret = EXPP_incr_ret(Py_None); + } + /* renderdir */ + else if( StringEqual( str, "renderdir" ) ) { + if (U.renderdir[0] != '\0') { + char renderdir[FILE_MAXDIR]; + + BLI_strncpy(renderdir, U.renderdir, FILE_MAXDIR); + BLI_convertstringcode(renderdir, G.sce, 0); + + if( BLI_exists( renderdir ) ) + ret = PyString_FromString( renderdir ); + } + if (!ret) ret = EXPP_incr_ret(Py_None); + } + /* soundsdir */ + else if( StringEqual( str, "soundsdir" ) ) { + if (U.sounddir[0] != '\0') { + char sounddir[FILE_MAXDIR]; + + BLI_strncpy(sounddir, U.sounddir, FILE_MAXDIR); + BLI_convertstringcode(sounddir, G.sce, 0); + + if( BLI_exists( sounddir ) ) + ret = PyString_FromString( sounddir ); + } + if (!ret) ret = EXPP_incr_ret(Py_None); + } + /* tempdir */ + else if( StringEqual( str, "tempdir" ) ) { + if (U.tempdir[0] != '\0') { + char tempdir[FILE_MAXDIR]; + + BLI_strncpy(tempdir, U.tempdir, FILE_MAXDIR); + BLI_convertstringcode(tempdir, G.sce, 0); + + if( BLI_exists( tempdir ) ) + ret = PyString_FromString( tempdir ); + } + if (!ret) ret = EXPP_incr_ret(Py_None); + } + /* icondir */ + else if( StringEqual( str, "icondir" ) ) { + + char icondirstr[FILE_MAXDIR]; + + #ifdef WIN32 + BLI_make_file_string("/", icondirstr, BLI_gethome(), "icons"); + #else + BLI_make_file_string("/", icondirstr, BLI_gethome(), ".blender/icons"); + #endif + + if( BLI_exists( icondirstr ) ) + ret = PyString_FromString( icondirstr ); + + if (!ret) ret = EXPP_incr_ret(Py_None); + } + /* According to the old file (opy_blender.c), the following if + statement is a quick hack and needs some clean up. */ + else if( StringEqual( str, "vrmloptions" ) ) { + ret = PyDict_New( ); + + EXPP_dict_set_item_str( ret, "twoside", + PyInt_FromLong( U.vrmlflag & USER_VRML_TWOSIDED ) ); + + EXPP_dict_set_item_str( ret, "layers", + PyInt_FromLong( U.vrmlflag & USER_VRML_LAYERS ) ); + + EXPP_dict_set_item_str( ret, "autoscale", + PyInt_FromLong( U.vrmlflag & USER_VRML_AUTOSCALE ) ); + + } /* End 'quick hack' part. */ + else if(StringEqual( str, "version" )) + ret = PyInt_FromLong( G.version ); + else + return EXPP_ReturnPyObjError( PyExc_AttributeError, "unknown attribute" ); + + if (ret) return ret; + else + return EXPP_ReturnPyObjError (PyExc_MemoryError, + "could not create pystring!"); +} + +/*****************************************************************************/ +/* Function: Blender_Redraw */ +/* Python equivalent: Blender.Redraw */ +/*****************************************************************************/ +static PyObject *Blender_Redraw( PyObject * self, PyObject * args ) +{ + return M_Window_Redraw( self, args ); +} + +/*****************************************************************************/ +/* Function: Blender_Quit */ +/* Python equivalent: Blender.Quit */ +/*****************************************************************************/ +static PyObject *Blender_Quit( PyObject * self ) +{ + BIF_write_autosave( ); /* save the current data first */ + + exit_usiblender( ); /* renames last autosave to quit.blend */ + + Py_RETURN_NONE; +} + +/** + * Blender.Load + * loads Blender's .blend, DXF, radiogour(?), STL, Videoscape, + * Inventor 1.0 ASCII, VRML 1.0 asc. + */ +static PyObject *Blender_Load( PyObject * self, PyObject * args ) +{ + char *fname = NULL; + int keep_oldfname = 0; + Script *script = NULL; + char str[32], name[FILE_MAXDIR]; + int file, is_blend_file = 0; + + if( !PyArg_ParseTuple( args, "|si", &fname, &keep_oldfname ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected filename and optional int or nothing as arguments" ); + + if( fname ) { + if( strlen( fname ) > FILE_MAXDIR ) /* G.main->name's max length */ + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "filename too long!" ); + else if( !BLI_exists( fname ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "requested file doesn't exist!" ); + + if( keep_oldfname ) + BLI_strncpy( name, G.sce, FILE_MAXDIR ); + } + + /* We won't let a new .blend file be loaded if there are still other + * scripts running, since loading a new file will close and remove them. */ + + if( G.main->script.first != G.main->script.last ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "there are other scripts running at the Scripts win, close them first!" ); + + if( fname ) { + file = open( fname, O_BINARY | O_RDONLY ); + + if( file <= 0 ) { + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "cannot open file!" ); + } else { + read( file, str, 31 ); + close( file ); + + if( strncmp( str, "BLEN", 4 ) == 0 ) + is_blend_file = 1; + } + } else + is_blend_file = 1; /* no arg given means default: .B.blend */ + + if( is_blend_file ) { + + int during_slink = during_scriptlink( ); + + /* when loading a .blend file from a scriptlink, the scriptlink pointer + * in BPY_do_pyscript becomes invalid during a loop. Inform it here. + * Also do not allow a nested scriptlink (called from inside another) + * to load .blend files, to avoid nasty problems. */ + if( during_slink >= 1 ) { + if( during_slink == 1 ) + disable_where_scriptlink( -1 ); + else { + return EXPP_ReturnPyObjError + ( PyExc_EnvironmentError, + "Blender.Load: cannot load .blend files from a nested scriptlink." ); + } + } + + /* trick: mark the script so that its script struct won't be freed after + * the script is executed (to avoid a double free warning on exit): */ + script = G.main->script.first; + if( script ) + script->flags |= SCRIPT_GUI; + + BIF_write_autosave( ); /* for safety let's preserve the current data */ + } + + if( G.obedit ) + exit_editmode(EM_FREEDATA); + + if (G.background) { /* background mode */ + if (is_blend_file) + BKE_read_file(fname, NULL); + else { + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "only .blend files can be loaded from command line,\n\ + other file types require interactive mode."); + } + } + else { /* interactive mode */ + /* for safety, any filename with .B.blend is considered the default one. + * It doesn't seem necessary to compare file attributes (like st_ino and + * st_dev, according to the glibc info pages) to find out if the given + * filename, that may have been given with a twisted misgiving path, is the + * default one for sure. Taking any .B.blend file as the default is good + * enough here. Note: the default file requires extra clean-up done by + * BIF_read_homefile: freeing the user theme data. */ + if( !fname || ( strstr( fname, ".B.blend" ) && is_blend_file ) ) + BIF_read_homefile(0, 1); + else + BIF_read_file( fname ); + + if( fname && keep_oldfname ) { + /*BLI_strncpy(G.main->name, name, FILE_MAXDIR); */ + BLI_strncpy( G.sce, name, FILE_MAXDIR ); + } + } + + Py_RETURN_NONE; +} + +static PyObject *Blender_Save( PyObject * self, PyObject * args ) +{ + char *fname = NULL; + int overwrite = 0, len = 0; + char *error = NULL; + Library *li; + + if( !PyArg_ParseTuple( args, "s|i", &fname, &overwrite ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected filename and optional int (overwrite flag) as arguments" ); + + for( li = G.main->library.first; li; li = li->id.next ) { + if( BLI_streq( li->name, fname ) ) { + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "cannot overwrite used library" ); + } + } + + /* for safety, any filename with .B.blend is considered the default one + * and not accepted here. */ + if( strstr( fname, ".B.blend" ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "filename can't contain the substring \".B.blend\" in it." ); + + len = strlen( fname ); + + if( len > FILE_MAXDIR + FILE_MAXFILE ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "filename is too long!" ); + else if( BLI_exists( fname ) && !overwrite ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "file already exists and overwrite flag was not given." ); + + disable_where_script( 1 ); /* to avoid error popups in the write_* functions */ + + if( BLI_testextensie( fname, ".blend" ) ) { + if( G.fileflags & G_AUTOPACK ) + packAll( ); + if( !BLO_write_file( fname, G.fileflags, &error ) ) { + disable_where_script( 0 ); + return EXPP_ReturnPyObjError( PyExc_SystemError, + error ); + } + } else if( BLI_testextensie( fname, ".dxf" ) ) + write_dxf( fname ); + else if( BLI_testextensie( fname, ".stl" ) ) + write_stl( fname ); + else if( BLI_testextensie( fname, ".wrl" ) ) + write_vrml( fname ); + else if( BLI_testextensie( fname, ".obj" ) ) + write_videoscape( fname ); + else { + disable_where_script( 0 ); + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "unknown file extension." ); + } + + disable_where_script( 0 ); + + Py_RETURN_NONE; +} + +static PyObject *Blender_ShowHelp(PyObject *self, PyObject *script) +{ + char hspath[FILE_MAXDIR + FILE_MAXFILE]; /* path to help_browser.py */ + char *sdir = bpy_gethome(1); + PyObject *rkeyd = NULL, *arglist = NULL; + + if (!PyString_Check(script)) + return EXPP_ReturnPyObjError(PyExc_TypeError, + "expected a script filename as argument"); + + /* first we try to find the help_browser script */ + + if (sdir) BLI_make_file_string("/", hspath, sdir, "help_browser.py"); + + if (!sdir || (!BLI_exists(hspath) && (U.pythondir[0] != '\0'))) { + char upydir[FILE_MAXDIR]; + + BLI_strncpy(upydir, U.pythondir, FILE_MAXDIR); + BLI_convertstringcode(upydir, G.sce, 0); + BLI_make_file_string("/", hspath, upydir, "help_browser.py"); + + if (!BLI_exists(hspath)) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "can't find script help_browser.py"); + } + + /* now we store the passed script in the registry dict and call the + * help_browser to show help info for it */ + rkeyd = PyDict_New(); + if (!rkeyd) + return EXPP_ReturnPyObjError(PyExc_MemoryError, + "can't create py dictionary!"); + + /* note: don't use EXPP_dict_set_item_str for 'script', which is an + * argument to the function we're in and so shouldn't be decref'ed: */ + PyDict_SetItemString(rkeyd, "script", script); + + EXPP_dict_set_item_str(bpy_registryDict, "__help_browser", rkeyd); + + arglist = Py_BuildValue("(s)", hspath); + Blender_Run(self, arglist); + Py_DECREF(arglist); + + Py_RETURN_NONE; +} + +static PyObject *Blender_Run(PyObject *self, PyObject *value) +{ + char *fname = PyString_AsString(value); + Text *text = NULL; + int is_blender_text = 0; + Script *script = NULL; + + if (!fname) + return EXPP_ReturnPyObjError(PyExc_TypeError, + "expected a filename or a Blender Text name as argument"); + + if (!BLI_exists(fname)) { /* if there's no such filename ... */ + text = G.main->text.first; /* try an already existing Blender Text */ + + while (text) { + if (!strcmp(fname, text->id.name + 2)) break; + text = text->id.next; + } + + if (!text) { + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "no such file or Blender text"); + } + else is_blender_text = 1; /* fn is already a Blender Text */ + } + + else { + text = add_text(fname); + + if (!text) { + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "couldn't create Blender Text from given file"); + } + } + + /* (this is messy, check Draw.c's Method_Register and Window.c's file + * selector for more info) + * - caller script is the one that called this Blender_Run function; + * - called script is the argument to this function: fname; + * To mark scripts whose global dicts can't be freed right after + * the script execution (or better, 'first pass', since these scripts + * leave callbacks for gui or file/image selectors) we flag them. But to + * get a pointer to them we need to check which one is currently + * running (if none we're already at a spacescript). To make sure only + * the called script will have the SCRIPT_RUNNING flag on, we unset it + * for the caller script here: */ + script = G.main->script.first; + while (script) { + if (script->flags & SCRIPT_RUNNING) break; + script = script->id.next; + } + + if (script) script->flags &= ~SCRIPT_RUNNING; /* unset */ + + BPY_txt_do_python_Text(text); /* call new script */ + + if (script) script->flags |= SCRIPT_RUNNING; /* set */ + + if (!is_blender_text) free_libblock(&G.main->text, text); + + Py_RETURN_NONE; +} + +static PyObject * Blender_UpdateMenus( PyObject * self ) +{ + + BPyMenu_RemoveAllEntries(); + + if (BPyMenu_Init(1) == -1) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "invalid scripts dir"); + + Py_RETURN_NONE; +} + +/*****************************************************************************/ +/* Function: Blender_PackAll */ +/* Python equivalent: Blender.PackAll */ +/*****************************************************************************/ +static PyObject *Blender_PackAll( PyObject * self) +{ + packAll(); + Py_RETURN_NONE; +} + +/*****************************************************************************/ +/* Function: Blender_UnpackAll */ +/* Python equivalent: Blender.UnpackAll */ +/*****************************************************************************/ +static PyObject *Blender_UnpackAll( PyObject * self, PyObject *value) +{ + int mode = PyInt_AsLong(value); + + if (mode==-1) + return EXPP_ReturnPyObjError( PyExc_ValueError, "expected an int Blender.UnpackModes"); + unpackAll(mode); + Py_RETURN_NONE; +} + +/*****************************************************************************/ +/* Function: Blender_CountPackedFiles */ +/* Python equivalent: Blender.CountPackedFiles */ +/*****************************************************************************/ +static PyObject *Blender_CountPackedFiles( PyObject * self ) +{ + int nfiles = countPackedFiles(); + return PyInt_FromLong( nfiles ); +} +static PyObject *Blender_UnpackModesDict( void ) +{ + PyObject *UnpackModes = PyConstant_New( ); + if( UnpackModes ) { + BPy_constant *d = ( BPy_constant * ) UnpackModes; + PyConstant_Insert( d, "EQUAL", PyInt_FromLong((long)PF_EQUAL) ); + PyConstant_Insert( d, "DIFFERS",PyInt_FromLong((long)PF_DIFFERS) ); + PyConstant_Insert( d, "NOFILE", PyInt_FromLong((long)PF_NOFILE) ); + PyConstant_Insert( d, "WRITE_ORIGINAL", PyInt_FromLong((long)PF_WRITE_ORIGINAL) ); + PyConstant_Insert( d, "WRITE_LOCAL", PyInt_FromLong((long)PF_WRITE_LOCAL) ); + PyConstant_Insert( d, "USE_LOCAL", PyInt_FromLong((long)PF_USE_LOCAL) ); + PyConstant_Insert( d, "USE_ORIGINAL", PyInt_FromLong((long)PF_USE_ORIGINAL) ); + PyConstant_Insert( d, "KEEP", PyInt_FromLong((long)PF_KEEP) ); + PyConstant_Insert( d, "NOOP", PyInt_FromLong((long)PF_NOOP) ); + PyConstant_Insert( d, "ASK", PyInt_FromLong((long)PF_EQUAL) ); + } + return UnpackModes; +} + +/*****************************************************************************/ +/* Function: initBlender */ +/*****************************************************************************/ + +void M_Blender_Init(void) +{ + PyObject *module; + PyObject *dict, *smode, *SpaceHandlers, *UnpackModes; + + /* G.scene should only aver be NULL if blender is executed in + background mode, not loading a blend file and executing a python script eg. + blender -P somescript.py -b + The if below solves the segfaults that happen when python runs and + G.scene is NULL */ + if(G.background && G.main->scene.first==NULL) { + Scene *sce= add_scene("1"); + /*set_scene(sce);*/ /* causes a crash */ + G.scene= sce; + } + + module = Py_InitModule3("Blender", Blender_methods, + "The main Blender module"); + + types_InitAll(); /* set all our pytypes to &PyType_Type */ + + /* constants for packed files*/ + UnpackModes = Blender_UnpackModesDict( ); + if( UnpackModes ) + PyModule_AddObject( module, "UnpackModes", UnpackModes ); + + SpaceHandlers = PyConstant_New(); + if (SpaceHandlers) { + BPy_constant *d = (BPy_constant *)SpaceHandlers; + + PyConstant_Insert(d,"VIEW3D_EVENT",PyInt_FromLong(SPACEHANDLER_VIEW3D_EVENT)); + PyConstant_Insert(d,"VIEW3D_DRAW", PyInt_FromLong(SPACEHANDLER_VIEW3D_DRAW)); + + PyModule_AddObject(module, "SpaceHandlers", SpaceHandlers); + } + + if (G.background) + smode = PyString_FromString("background"); + else + smode = PyString_FromString("interactive"); + + dict = PyModule_GetDict(module); + g_blenderdict = dict; + + PyModule_AddIntConstant(module, "TRUE", 1); + PyModule_AddIntConstant( module, "FALSE", 0 ); + + EXPP_dict_set_item_str(dict, "bylink", EXPP_incr_ret_False()); + PyDict_SetItemString(dict, "link", Py_None); + EXPP_dict_set_item_str(dict, "event", PyString_FromString("")); + EXPP_dict_set_item_str(dict, "mode", smode); + + PyDict_SetItemString(dict, "Armature", Armature_Init()); + PyDict_SetItemString(dict, "BezTriple", BezTriple_Init()); + PyDict_SetItemString(dict, "BGL", BGL_Init()); + PyDict_SetItemString(dict, "CurNurb", CurNurb_Init()); + PyDict_SetItemString(dict, "Constraint", Constraint_Init()); + PyDict_SetItemString(dict, "Curve", Curve_Init()); + PyDict_SetItemString(dict, "Camera", Camera_Init()); + PyDict_SetItemString(dict, "Draw", Draw_Init()); + PyDict_SetItemString(dict, "Effect", Effect_Init()); + PyDict_SetItemString(dict, "Ipo", Ipo_Init()); + PyDict_SetItemString(dict, "IpoCurve", IpoCurve_Init()); + PyDict_SetItemString(dict, "Image", Image_Init()); + PyDict_SetItemString(dict, "Key", Key_Init()); + PyDict_SetItemString(dict, "Lamp", Lamp_Init()); + PyDict_SetItemString(dict, "Lattice", Lattice_Init()); + PyDict_SetItemString(dict, "Library", oldLibrary_Init()); + PyDict_SetItemString(dict, "Material", Material_Init()); + PyDict_SetItemString(dict, "Mesh", Mesh_Init()); + PyDict_SetItemString(dict, "Metaball", Metaball_Init()); + PyDict_SetItemString(dict, "Mathutils", Mathutils_Init()); + PyDict_SetItemString(dict, "Geometry", Geometry_Init()); + PyDict_SetItemString(dict, "Modifier", Modifier_Init()); + PyDict_SetItemString(dict, "NMesh", NMesh_Init()); + PyDict_SetItemString(dict, "Noise", Noise_Init()); + PyDict_SetItemString(dict, "Object", Object_Init()); + PyDict_SetItemString(dict, "Group", Group_Init()); + PyDict_SetItemString(dict, "Registry", Registry_Init()); + PyDict_SetItemString(dict, "Scene", Scene_Init()); + PyDict_SetItemString(dict, "Sound", Sound_Init()); + PyDict_SetItemString(dict, "SurfNurb", SurfNurb_Init()); + PyDict_SetItemString(dict, "sys", sys_Init()); + PyDict_SetItemString(dict, "Types", Types_Init()); + PyDict_SetItemString(dict, "Text", Text_Init()); + PyDict_SetItemString(dict, "Text3d", Text3d_Init()); + PyDict_SetItemString(dict, "Texture", Texture_Init()); + PyDict_SetItemString(dict, "Window", Window_Init()); + PyDict_SetItemString(dict, "World", World_Init()); + +} diff --git a/source/blender/python/api2_2x/Blender.h b/source/blender/python/api2_2x/Blender.h new file mode 100644 index 00000000000..df80daf3cea --- /dev/null +++ b/source/blender/python/api2_2x/Blender.h @@ -0,0 +1,41 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Michel Selten, Willian P. Germano + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_BLENDER_H +#define EXPP_BLENDER_H + +#include + +extern PyObject *g_blenderdict; +void M_Blender_Init( void ); + +#endif /* EXPP_BLENDER_H */ diff --git a/source/blender/python/api2_2x/Bone.c b/source/blender/python/api2_2x/Bone.c new file mode 100644 index 00000000000..5eeb4bb2817 --- /dev/null +++ b/source/blender/python/api2_2x/Bone.c @@ -0,0 +1,1425 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#include "Bone.h" +#include "vector.h" +#include "matrix.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BKE_utildefines.h" +#include "gen_utils.h" +#include "BKE_armature.h" +#include "Mathutils.h" +#include "BKE_library.h" + +//these must come in this order +#include "DNA_object_types.h" //1 +#include "BIF_editarmature.h" //2 + +//------------------------ERROR CODES--------------------------------- +//This is here just to make me happy and to have more consistant error strings :) +static const char sEditBoneError[] = "EditBone - Error: "; +// static const char sEditBoneBadArgs[] = "EditBone - Bad Arguments: "; +static const char sBoneError[] = "Bone - Error: "; +// static const char sBoneBadArgs[] = "Bone - Bad Arguments: "; + +//----------------------(internal) +//gets the bone->roll (which is a localspace roll) and puts it in parentspace +//(which is the 'roll' value the user sees) +static double boneRoll_ToArmatureSpace(struct Bone *bone) +{ + float head[3], tail[3], delta[3]; + float premat[3][3], postmat[3][3]; + float imat[3][3], difmat[3][3]; + double roll = 0.0f; + + VECCOPY(head, bone->arm_head); + VECCOPY(tail, bone->arm_tail); + VECSUB (delta, tail, head); + vec_roll_to_mat3(delta, 0.0f, postmat); + Mat3CpyMat4(premat, bone->arm_mat); + Mat3Inv(imat, postmat); + Mat3MulMat3(difmat, imat, premat); + + roll = atan2(difmat[2][0], difmat[2][2]); + if (difmat[0][0] < 0.0){ + roll += M_PI; + } + return roll; //result is in radians +} + +//################## EditBone_Type ######################## +/*This type is a wrapper for a tempory bone. This is an 'unparented' bone +*object. The armature->bonebase will be calculated from these temporary +*python tracked objects.*/ +//#################################################### + +//------------------METHOD IMPLEMENTATIONS----------------------------- +//-------------------------EditBone.hasParent() +static PyObject *EditBone_hasParent(BPy_EditBone *self) +{ + if (self->editbone){ + if (self->editbone->parent) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; + }else{ + goto AttributeError; + } + +AttributeError: + return EXPP_objError(PyExc_AttributeError, "%s%s%s", + sEditBoneError, ".hasParent: ", "EditBone must be added to the armature first"); +} +//-------------------------EditBone.clearParent() +static PyObject *EditBone_clearParent(BPy_EditBone *self) +{ + if (self->editbone){ + if (self->editbone->parent) + self->editbone->parent = NULL; + Py_RETURN_NONE; + }else{ + goto AttributeError; + } + +AttributeError: + return EXPP_objError(PyExc_AttributeError, "%s%s%s", + sEditBoneError, ".clearParent: ", "EditBone must be added to the armature first"); +} +//------------------ATTRIBUTE IMPLEMENTATION--------------------------- +//------------------------EditBone.name (get) +static PyObject *EditBone_getName(BPy_EditBone *self, void *closure) +{ + if (self->editbone) + return PyString_FromString(self->editbone->name); + else + return PyString_FromString(self->name); +} +//------------------------EditBone.name (set) +//check for char[] overflow here... +static int EditBone_setName(BPy_EditBone *self, PyObject *value, void *closure) +{ + char *name = ""; + + if (!PyArg_Parse(value, "s", &name)) + goto AttributeError; + + if (self->editbone) + BLI_strncpy(self->editbone->name, name, 32); + else + BLI_strncpy(self->name, name, 32); + return 0; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sEditBoneError, ".name: ", "expects a string"); +} +//------------------------EditBone.roll (get) +static PyObject *EditBone_getRoll(BPy_EditBone *self, void *closure) +{ + if (self->editbone){ + return PyFloat_FromDouble((self->editbone->roll * (180/Py_PI))); + }else{ + return PyFloat_FromDouble((self->roll * (180/Py_PI))); + } +} +//------------------------EditBone.roll (set) +static int EditBone_setRoll(BPy_EditBone *self, PyObject *value, void *closure) +{ + float roll = 0.0f; + + if (!PyArg_Parse(value, "f", &roll)) + goto AttributeError; + + if (self->editbone){ + self->editbone->roll = (float)(roll * (Py_PI/180)); + }else{ + self->roll = (float)(roll * (Py_PI/180)); + } + return 0; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sEditBoneError, ".roll: ", "expects a float"); +} +//------------------------EditBone.head (get) +static PyObject *EditBone_getHead(BPy_EditBone *self, void *closure) +{ + if (self->editbone){ + return newVectorObject(self->editbone->head, 3, Py_WRAP); + }else{ + return newVectorObject(self->head, 3, Py_NEW); + } +} +//------------------------EditBone.head (set) +static int EditBone_setHead(BPy_EditBone *self, PyObject *value, void *closure) +{ + VectorObject *vec = NULL; + int x; + + if (!PyArg_Parse(value, "O!", &vector_Type, &vec)) + goto AttributeError; + if (vec->size != 3) + goto AttributeError2; + + if (self->editbone){ + for (x = 0; x < 3; x++){ + self->editbone->head[x] = vec->vec[x]; + } + }else{ + for (x = 0; x < 3; x++){ + self->head[x] = vec->vec[x]; + } + } + return 0; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sEditBoneError, ".head: ", "expects a Vector Object"); + +AttributeError2: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sEditBoneError, ".head: ", "Vector Object needs to be (x,y,z)"); +} +//------------------------EditBone.tail (get) +static PyObject *EditBone_getTail(BPy_EditBone *self, void *closure) +{ + if (self->editbone){ + return newVectorObject(self->editbone->tail, 3, Py_WRAP); + }else{ + return newVectorObject(self->tail, 3, Py_NEW); + } +} +//------------------------EditBone.tail (set) +static int EditBone_setTail(BPy_EditBone *self, PyObject *value, void *closure) +{ + VectorObject *vec = NULL; + int x; + + if (!PyArg_Parse(value, "O!", &vector_Type, &vec)) + goto AttributeError; + if (vec->size != 3) + goto AttributeError2; + + if (self->editbone){ + for (x = 0; x < 3; x++){ + self->editbone->tail[x] = vec->vec[x]; + } + }else{ + for (x = 0; x < 3; x++){ + self->tail[x] = vec->vec[x]; + } + } + return 0; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sEditBoneError, ".tail: ", "expects a Vector Object"); + +AttributeError2: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sEditBoneError, ".tail: ", "Vector Object needs to be (x,y,z)"); +} +//------------------------EditBone.weight (get) +static PyObject *EditBone_getWeight(BPy_EditBone *self, void *closure) +{ + if (self->editbone) + return PyFloat_FromDouble(self->editbone->weight); + else + return PyFloat_FromDouble(self->weight); +} +//------------------------EditBone.weight (set) +static int EditBone_setWeight(BPy_EditBone *self, PyObject *value, void *closure) +{ + float weight; + + if (!PyArg_Parse(value, "f", &weight)) + goto AttributeError; + CLAMP(weight, 0.0f, 1000.0f); + + if (self->editbone) + self->editbone->weight = weight; + else + self->weight = weight; + return 0; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sEditBoneError, ".weight: ", "expects a float"); +} +//------------------------EditBone.deform_dist (get) +static PyObject *EditBone_getDeform_dist(BPy_EditBone *self, void *closure) +{ + if (self->editbone) + return PyFloat_FromDouble(self->editbone->dist); + else + return PyFloat_FromDouble(self->dist); +} +//------------------------EditBone.deform_dist (set) +static int EditBone_setDeform_dist(BPy_EditBone *self, PyObject *value, void *closure) +{ + float deform; + + if (!PyArg_Parse(value, "f", &deform)) + goto AttributeError; + CLAMP(deform, 0.0f, 1000.0f); + + if (self->editbone) + self->editbone->dist = deform; + else + self->dist = deform; + return 0; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sEditBoneError, ".deform_dist: ", "expects a float"); +} +//------------------------EditBone.subdivisions (get) +static PyObject *EditBone_getSubdivisions(BPy_EditBone *self, void *closure) +{ + if (self->editbone) + return PyInt_FromLong(self->editbone->segments); + else + return PyInt_FromLong(self->segments); +} +//------------------------EditBone.subdivisions (set) +static int EditBone_setSubdivisions(BPy_EditBone *self, PyObject *value, void *closure) +{ + int segs; + + if (!PyArg_Parse(value, "i", &segs)) + goto AttributeError; + CLAMP(segs, 1, 32); + + if (self->editbone) + self->editbone->segments = (short)segs; + else + self->segments = (short)segs; + return 0; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sEditBoneError, ".subdivisions: ", "expects a integer"); +} +//------------------------EditBone.options (get) +static PyObject *EditBone_getOptions(BPy_EditBone *self, void *closure) +{ + PyObject *list = NULL; + + list = PyList_New(0); + if (!list) + goto RuntimeError; + + if(self->editbone){ + if(self->editbone->flag & BONE_CONNECTED) + if (PyList_Append(list, + EXPP_GetModuleConstant("Blender.Armature", "CONNECTED")) == -1) + goto RuntimeError; + if(self->editbone->flag & BONE_HINGE) + if (PyList_Append(list, + EXPP_GetModuleConstant("Blender.Armature", "HINGE")) == -1) + goto RuntimeError; + if(self->editbone->flag & BONE_NO_DEFORM) + if (PyList_Append(list, + EXPP_GetModuleConstant("Blender.Armature", "NO_DEFORM")) == -1) + goto RuntimeError; + if(self->editbone->flag & BONE_MULT_VG_ENV) + if (PyList_Append(list, + EXPP_GetModuleConstant("Blender.Armature", "MULTIPLY")) == -1) + goto RuntimeError; + if(self->editbone->flag & BONE_HIDDEN_A) + if (PyList_Append(list, + EXPP_GetModuleConstant("Blender.Armature", "HIDDEN_EDIT")) == -1) + goto RuntimeError; + if(self->editbone->flag & BONE_ROOTSEL) + if (PyList_Append(list, + EXPP_GetModuleConstant("Blender.Armature", "ROOT_SELECTED")) == -1) + goto RuntimeError; + if(self->editbone->flag & BONE_SELECTED) + if (PyList_Append(list, + EXPP_GetModuleConstant("Blender.Armature", "BONE_SELECTED")) == -1) + goto RuntimeError; + if(self->editbone->flag & BONE_TIPSEL) + if (PyList_Append(list, + EXPP_GetModuleConstant("Blender.Armature", "TIP_SELECTED")) == -1) + goto RuntimeError; + }else{ + if(self->flag & BONE_CONNECTED) + if (PyList_Append(list, + EXPP_GetModuleConstant("Blender.Armature", "CONNECTED")) == -1) + goto RuntimeError; + if(self->flag & BONE_HINGE) + if (PyList_Append(list, + EXPP_GetModuleConstant("Blender.Armature", "HINGE")) == -1) + goto RuntimeError; + if(self->flag & BONE_NO_DEFORM) + if (PyList_Append(list, + EXPP_GetModuleConstant("Blender.Armature", "NO_DEFORM")) == -1) + goto RuntimeError; + if(self->flag & BONE_MULT_VG_ENV) + if (PyList_Append(list, + EXPP_GetModuleConstant("Blender.Armature", "MULTIPLY")) == -1) + goto RuntimeError; + if(self->flag & BONE_HIDDEN_A) + if (PyList_Append(list, + EXPP_GetModuleConstant("Blender.Armature", "HIDDEN_EDIT")) == -1) + goto RuntimeError; + if(self->flag & BONE_ROOTSEL) + if (PyList_Append(list, + EXPP_GetModuleConstant("Blender.Armature", "ROOT_SELECTED")) == -1) + goto RuntimeError; + if(self->flag & BONE_SELECTED) + if (PyList_Append(list, + EXPP_GetModuleConstant("Blender.Armature", "BONE_SELECTED")) == -1) + goto RuntimeError; + if(self->flag & BONE_TIPSEL) + if (PyList_Append(list, + EXPP_GetModuleConstant("Blender.Armature", "TIP_SELECTED")) == -1) + goto RuntimeError; + } + + return list; + +RuntimeError: + Py_XDECREF( list ); + return EXPP_objError(PyExc_RuntimeError, "%s%s%s", + sEditBoneError, ".options: ", "Internal failure!"); +} +//----------------------(internal) EditBone_CheckValidConstant +static int EditBone_CheckValidConstant(PyObject *constant) +{ + PyObject *name = NULL; + + if (constant){ + if (BPy_Constant_Check(constant)){ + name = PyDict_GetItemString(((BPy_constant*)constant)->dict, "name"); + if (!name) + return 0; + if (!STREQ3(PyString_AsString(name), "CONNECTED", "HINGE", "NO_DEFORM") && + !STREQ3(PyString_AsString(name), "ROOT_SELECTED", "BONE_SELECTED", "TIP_SELECTED") && + !STREQ2(PyString_AsString(name), "MULTIPLY", "HIDDEN_EDIT")) + return 0; + else + return 1; + }else{ + return 0; + } + }else{ + return 0; + } +} + +//------------------------EditBone.options (set) +static int EditBone_setOptions(BPy_EditBone *self, PyObject *value, void *closure) +{ + int length, numeric_value, new_flag = 0, x; + PyObject *val = NULL, *index = NULL; + + if (PyList_Check(value)){ + length = PyList_Size(value); + for (x = 0; x < length; x++){ + index = PyList_GetItem(value, x); + if (!EditBone_CheckValidConstant(index)) + goto AttributeError2; + val = PyDict_GetItemString(((BPy_constant*)index)->dict, "value"); + if (PyInt_Check(val)){ + numeric_value = (int)PyInt_AS_LONG(val); + new_flag |= numeric_value; + }else{ + goto AttributeError2; + } + } + + //set the options + if(self->editbone){ + //make sure the 'connected' property is set up correctly + if (new_flag & BONE_CONNECTED) { + if(!self->editbone->parent) + goto AttributeError3; + else + VECCOPY(self->editbone->head, self->editbone->parent->tail); + } + self->editbone->flag = new_flag; + }else{ + self->flag = new_flag; + } + return 0; + }else if (BPy_Constant_Check(value)){ + if (!EditBone_CheckValidConstant(value)) + goto AttributeError2; + val = PyDict_GetItemString(((BPy_constant*)value)->dict, "value"); + if (PyInt_Check(val)){ + numeric_value = (int)PyInt_AS_LONG(val); + + if(self->editbone){ + //make sure the 'connected' property is set up correctly + if (numeric_value & BONE_CONNECTED) { + if(!self->editbone->parent) + goto AttributeError3; + else + VECCOPY(self->editbone->head, self->editbone->parent->tail); + } + self->editbone->flag = numeric_value; + }else{ + self->flag = numeric_value; + } + return 0; + }else{ + goto AttributeError2; + } + }else{ + goto AttributeError1; + } + +AttributeError1: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sEditBoneError, ".options: ", "Expects a constant or list of constants"); +AttributeError2: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sEditBoneError, ".options: ", "Please use a constant defined in the Armature module"); +AttributeError3: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sEditBoneError, ".options: ", "You can't connect to parent because no parent is set"); +} +//------------------------EditBone.parent (get) +static PyObject *EditBone_getParent(BPy_EditBone *self, void *closure) +{ + if (self->editbone){ + if (self->editbone->parent) + return PyEditBone_FromEditBone(self->editbone->parent); + else + Py_RETURN_NONE; + }else{ + Py_RETURN_NONE; //not in the list yet can't have a parent + } +} +//------------------------EditBone.parent (set) +static int EditBone_setParent(BPy_EditBone *self, PyObject *value, void *closure) +{ + BPy_EditBone *parent = NULL; + + if (!PyArg_Parse(value, "O!", &EditBone_Type, &parent)) + goto AttributeError; + + if (!parent->editbone) + goto AttributeError2; + + if (self->editbone){ + self->editbone->parent = parent->editbone; + }else{ + self->parent = parent->editbone; + } + return 0; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sEditBoneError, ".parent: ", "expects a EditBone Object"); +AttributeError2: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sEditBoneError, ".parent: ", "This object is not in the armature's bone list!"); +} +//------------------------EditBone.matrix (get) +static PyObject *EditBone_getMatrix(BPy_EditBone *self, void *closure) +{ + float boneMatrix[3][3]; + float axis[3]; + + if (self->editbone){ + VECSUB(axis, self->editbone->tail, self->editbone->head); + vec_roll_to_mat3(axis, self->editbone->roll, boneMatrix); + }else{ + VECSUB(axis, self->tail, self->head); + vec_roll_to_mat3(axis, self->roll, boneMatrix); + } + + return newMatrixObject((float*)boneMatrix, 3, 3, Py_NEW); +} +//------------------------EditBone.matrix (set) +static int EditBone_setMatrix(BPy_EditBone *self, PyObject *value, void *closure) +{ + PyObject *matrix; + float roll, length, vec[3], axis[3], mat3[3][3]; + + if (!PyArg_Parse(value, "O!", &matrix_Type, &matrix)) + goto AttributeError; + + //make sure we have the right sizes + if (((MatrixObject*)matrix)->rowSize != 3 && ((MatrixObject*)matrix)->colSize != 3){ + if(((MatrixObject*)matrix)->rowSize != 4 && ((MatrixObject*)matrix)->colSize != 4){ + goto AttributeError; + } + } + + /*vec will be a normalized directional vector + * together with the length of the old bone vec*length = the new vector*/ + /*The default rotation is 0,1,0 on the Y axis (see mat3_to_vec_roll)*/ + if (((MatrixObject*)matrix)->rowSize == 4){ + Mat3CpyMat4(mat3, ((float (*)[4])*((MatrixObject*)matrix)->matrix)); + }else{ + Mat3CpyMat3(mat3, ((float (*)[3])*((MatrixObject*)matrix)->matrix)); + } + mat3_to_vec_roll(mat3, vec, &roll); + + //if a 4x4 matrix was passed we'll translate the vector otherwise not + if (self->editbone){ + self->editbone->roll = roll; + VecSubf(axis, self->editbone->tail, self->editbone->head); + length = VecLength(axis); + VecMulf(vec, length); + if (((MatrixObject*)matrix)->rowSize == 4) + VecCopyf(self->editbone->head, ((MatrixObject*)matrix)->matrix[3]); + VecAddf(self->editbone->tail, self->editbone->head, vec); + return 0; + }else{ + self->roll = roll; + VecSubf(axis, self->tail, self->head); + length = VecLength(axis); + VecMulf(vec, length); + if (((MatrixObject*)matrix)->rowSize == 4) + VecCopyf(self->head, ((MatrixObject*)matrix)->matrix[3]); + VecAddf(self->tail, self->head, vec); + return 0; + } + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sEditBoneError, ".matrix: ", "expects a 3x3 or 4x4 Matrix Object"); +} +//------------------------Bone.length (get) +static PyObject *EditBone_getLength(BPy_EditBone *self, void *closure) +{ + float delta[3]; + double dot = 0.0f; + int x; + + if (self->editbone){ + VECSUB(delta, self->editbone->tail, self->editbone->head); + for(x = 0; x < 3; x++){ + dot += (delta[x] * delta[x]); + } + return PyFloat_FromDouble(sqrt(dot)); + }else{ + VECSUB(delta, self->tail, self->head); + for(x = 0; x < 3; x++){ + dot += (delta[x] * delta[x]); + } + return PyFloat_FromDouble(sqrt(dot)); + } +} +//------------------------Bone.length (set) +static int EditBone_setLength(BPy_EditBone *self, PyObject *value, void *closure) +{ + printf("Sorry this isn't implemented yet.... :/"); + return 1; +} + + +//------------------------Bone.headRadius (get) +static PyObject *EditBone_getHeadRadius(BPy_EditBone *self, void *closure) +{ + if (self->editbone) + if (self->editbone->parent && self->editbone->flag & BONE_CONNECTED) + return PyFloat_FromDouble(self->editbone->parent->rad_tail); + else + return PyFloat_FromDouble(self->editbone->rad_head); + else + if (self->parent && self->flag & BONE_CONNECTED) + return PyFloat_FromDouble(self->parent->rad_tail); + else + return PyFloat_FromDouble(self->rad_head); +} +//------------------------Bone.headRadius (set) +static int EditBone_setHeadRadius(BPy_EditBone *self, PyObject *value, void *closure) +{ + float radius; + if (!PyArg_Parse(value, "f", &radius)) + goto AttributeError; + CLAMP(radius, 0.0f, 10000.0f); + + if (self->editbone) + if (self->editbone->parent && self->editbone->flag & BONE_CONNECTED) + self->editbone->parent->rad_tail= radius; + else + self->editbone->rad_head= radius; + else + if (self->parent && self->flag & BONE_CONNECTED) + self->parent->rad_tail= radius; + else + self->rad_head= radius; + return 0; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sEditBoneError, ".headRadius: ", "expects a float"); +} + + +//------------------------Bone.tailRadius (get) +static PyObject *EditBone_getTailRadius(BPy_EditBone *self, void *closure) +{ + if (self->editbone) + return PyFloat_FromDouble(self->editbone->rad_tail); + else + return PyFloat_FromDouble(self->rad_tail); +} +//------------------------Bone.tailRadius (set) +static int EditBone_setTailRadius(BPy_EditBone *self, PyObject *value, void *closure) +{ + float radius; + if (!PyArg_Parse(value, "f", &radius)) + goto AttributeError; + CLAMP(radius, 0.0f, 10000.0f); + + if (self->editbone) + self->editbone->rad_tail = radius; + else + self->rad_tail = radius; + return 0; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sEditBoneError, ".tailRadius: ", "expects a float"); +} + +//------------------------Bone.layerMask (get) +static PyObject *EditBone_getLayerMask(BPy_EditBone *self) +{ + /* do this extra stuff because the short's bits can be negative values */ + unsigned short laymask = 0; + if (self->editbone) laymask |= self->editbone->layer; + else laymask |= self->layer; + return PyInt_FromLong((int)laymask); +} +//------------------------Bone.layerMask (set) +static int EditBone_setLayerMask(BPy_EditBone *self, PyObject *value) +{ + int laymask; + if (!PyInt_Check(value)) { + return EXPP_ReturnIntError( PyExc_AttributeError, + "expected an integer (bitmask) as argument" ); + } + + laymask = PyInt_AsLong(value); + + if (laymask <= 0 || laymask > (1<<16) - 1) + return EXPP_ReturnIntError( PyExc_AttributeError, + "bitmask must have from 1 up to 16 bits set"); + + if (self->editbone) { + self->editbone->layer = 0; + self->editbone->layer |= laymask; + } else { + self->layer = 0; + self->layer |= laymask; + } + + return 0; +} + +//------------------TYPE_OBECT IMPLEMENTATION-------------------------- +//------------------------tp_methods +//This contains a list of all methods the object contains +static PyMethodDef BPy_EditBone_methods[] = { + {"hasParent", (PyCFunction) EditBone_hasParent, METH_NOARGS, + "() - True/False - Bone has a parent"}, + {"clearParent", (PyCFunction) EditBone_clearParent, METH_NOARGS, + "() - sets the parent to None"}, + {NULL, NULL, 0, NULL} +}; +///------------------------tp_getset +//This contains methods for attributes that require checking +static PyGetSetDef BPy_EditBone_getset[] = { + {"name", (getter)EditBone_getName, (setter)EditBone_setName, + "The name of the bone", NULL}, + {"roll", (getter)EditBone_getRoll, (setter)EditBone_setRoll, + "The roll (or rotation around the axis) of the bone", NULL}, + {"head", (getter)EditBone_getHead, (setter)EditBone_setHead, + "The start point of the bone", NULL}, + {"tail", (getter)EditBone_getTail, (setter)EditBone_setTail, + "The end point of the bone", NULL}, + {"matrix", (getter)EditBone_getMatrix, (setter)EditBone_setMatrix, + "The matrix of the bone", NULL}, + {"weight", (getter)EditBone_getWeight, (setter)EditBone_setWeight, + "The weight of the bone in relation to a parented mesh", NULL}, + {"deformDist", (getter)EditBone_getDeform_dist, (setter)EditBone_setDeform_dist, + "The distance at which deformation has effect", NULL}, + {"subdivisions", (getter)EditBone_getSubdivisions, (setter)EditBone_setSubdivisions, + "The number of subdivisions (for B-Bones)", NULL}, + {"options", (getter)EditBone_getOptions, (setter)EditBone_setOptions, + "The options effective on this bone", NULL}, + {"parent", (getter)EditBone_getParent, (setter)EditBone_setParent, + "The parent bone of this bone", NULL}, + {"length", (getter)EditBone_getLength, (setter)EditBone_setLength, + "The length of this bone", NULL}, + {"tailRadius", (getter)EditBone_getTailRadius, (setter)EditBone_setTailRadius, + "Set the radius of this bones tip", NULL}, + {"headRadius", (getter)EditBone_getHeadRadius, (setter)EditBone_setHeadRadius, + "Set the radius of this bones head", NULL}, + {"layerMask", (getter)EditBone_getLayerMask, (setter)EditBone_setLayerMask, + "Layer bitmask", NULL }, + {NULL, NULL, NULL, NULL,NULL} +}; + +//------------------------tp_repr +//This is the string representation of the object +static PyObject *EditBone_repr(BPy_EditBone *self) +{ + if (self->editbone) + return PyString_FromFormat( "[EditBone \"%s\"]", self->editbone->name ); + else + return PyString_FromFormat( "[EditBone \"%s\"]", self->name ); +} + +static int EditBone_compare( BPy_EditBone * a, BPy_EditBone * b ) +{ + /* if they are not wrapped, then they cant be the same */ + if (a->editbone==NULL && b->editbone==NULL) return -1; + return ( a->editbone == b->editbone ) ? 0 : -1; +} + + +//------------------------tp_doc +//The __doc__ string for this object +static char BPy_EditBone_doc[] = "This is an internal subobject of armature\ +designed to act as a wrapper for an 'edit bone'."; + +//------------------------tp_new +//This methods creates a new object (note it does not initialize it - only the building) +static PyObject *EditBone_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + char *name = "myEditBone"; + BPy_EditBone *py_editBone = NULL; + float head[3], tail[3]; + + py_editBone = (BPy_EditBone*)type->tp_alloc(type, 0); //new + if (py_editBone == NULL) + goto RuntimeError; + + //this pointer will be set when this bone is placed in ListBase + //otherwise this will act as a py_object + py_editBone->editbone = NULL; + + unique_editbone_name(NULL, name); + BLI_strncpy(py_editBone->name, name, 32); + py_editBone->parent = NULL; + py_editBone->weight= 1.0f; + py_editBone->dist= 0.25f; + py_editBone->xwidth= 0.1f; + py_editBone->zwidth= 0.1f; + py_editBone->ease1= 1.0f; + py_editBone->ease2= 1.0f; + py_editBone->rad_head= 0.10f; + py_editBone->rad_tail= 0.05f; + py_editBone->segments= 1; + py_editBone->layer= 1; + py_editBone->flag = 0; + py_editBone->roll = 0.0f; + + head[0] = head[1] = head[2] = 0.0f; + tail[1] = tail[2] = 0.0f; + tail[0] = 1.0f; + VECCOPY(py_editBone->head, head); + VECCOPY(py_editBone->tail, tail); + + return (PyObject*)py_editBone; + +RuntimeError: + return EXPP_objError(PyExc_RuntimeError, "%s%s%s", + sEditBoneError, " __new__: ", "Internal Error"); +} +//------------------------tp_dealloc +//This tells how to 'tear-down' our object when ref count hits 0 +//the struct EditBone pointer will be handled by the BPy_BonesDict class +static void EditBone_dealloc(BPy_EditBone * self) +{ + EditBone_Type.tp_free(self); + return; +} +//------------------TYPE_OBECT DEFINITION-------------------------- +PyTypeObject EditBone_Type = { + PyObject_HEAD_INIT(NULL) //tp_head + 0, //tp_internal + "EditBone", //tp_name + sizeof(BPy_EditBone), //tp_basicsize + 0, //tp_itemsize + (destructor)EditBone_dealloc, //tp_dealloc + 0, //tp_print + 0, //tp_getattr + 0, //tp_setattr + (cmpfunc)EditBone_compare, //tp_compare + (reprfunc)EditBone_repr, //tp_repr + 0, //tp_as_number + 0, //tp_as_sequence + 0, //tp_as_mapping + 0, //tp_hash + 0, //tp_call + 0, //tp_str + 0, //tp_getattro + 0, //tp_setattro + 0, //tp_as_buffer + Py_TPFLAGS_DEFAULT, //tp_flags + BPy_EditBone_doc, //tp_doc + 0, //tp_traverse + 0, //tp_clear + 0, //tp_richcompare + 0, //tp_weaklistoffset + 0, //tp_iter + 0, //tp_iternext + BPy_EditBone_methods, //tp_methods + 0, //tp_members + BPy_EditBone_getset, //tp_getset + 0, //tp_base + 0, //tp_dict + 0, //tp_descr_get + 0, //tp_descr_set + 0, //tp_dictoffset + 0, //tp_init + 0, //tp_alloc + (newfunc)EditBone_new, //tp_new + 0, //tp_free + 0, //tp_is_gc + 0, //tp_bases + 0, //tp_mro + 0, //tp_cache + 0, //tp_subclasses + 0, //tp_weaklist + 0 //tp_del +}; + +//------------------METHOD IMPLEMENTATIONS-------------------------------- +//------------------------(internal) PyBone_ChildrenAsList +static int PyBone_ChildrenAsList(PyObject *list, ListBase *bones){ + Bone *bone = NULL; + PyObject *py_bone = NULL; + + for (bone = bones->first; bone; bone = bone->next){ + py_bone = PyBone_FromBone(bone); + if (py_bone == NULL) + return 0; + + if(PyList_Append(list, py_bone) == -1){ + return 0; + } + Py_DECREF(py_bone); + if (bone->childbase.first) + if (!PyBone_ChildrenAsList(list, &bone->childbase)) + return 0; + } + return 1; +} +//-------------------------Bone.hasParent() +static PyObject *Bone_hasParent(BPy_Bone *self) +{ + if (self->bone->parent) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} +//-------------------------Bone.hasChildren() +static PyObject *Bone_hasChildren(BPy_Bone *self) +{ + if (self->bone->childbase.first) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} +//-------------------------Bone.getAllChildren() +static PyObject *Bone_getAllChildren(BPy_Bone *self) +{ + PyObject *list = PyList_New(0); + if (!self->bone->childbase.first) { + /* do nothing */ + } else if (!PyBone_ChildrenAsList(list, &self->bone->childbase)) { + Py_XDECREF(list); + EXPP_objError(PyExc_RuntimeError, "%s%s", + sBoneError, "Internal error trying to wrap blender bones!"); + } + return list; +} + +//------------------ATTRIBUTE IMPLEMENTATIONS----------------------------- +//------------------------Bone.name (get) +static PyObject *Bone_getName(BPy_Bone *self, void *closure) +{ + return PyString_FromString(self->bone->name); +} +//------------------------Bone.name (set) +//check for char[] overflow here... +static int Bone_setName(BPy_Bone *self, PyObject *value, void *closure) +{ + return EXPP_intError(PyExc_ValueError, "%s%s", + sBoneError, "You must first call .makeEditable() to edit the armature"); +} +//------------------------Bone.roll (get) +static PyObject *Bone_getRoll(BPy_Bone *self, void *closure) +{ + return Py_BuildValue("{s:f, s:f}", + "BONESPACE", self->bone->roll * (180/Py_PI), + "ARMATURESPACE", boneRoll_ToArmatureSpace(self->bone) * (180/Py_PI)); +} +//------------------------Bone.roll (set) +static int Bone_setRoll(BPy_Bone *self, PyObject *value, void *closure) +{ + return EXPP_intError(PyExc_ValueError, "%s%s", + sBoneError, "You must first call .makeEditable() to edit the armature"); +} +//------------------------Bone.head (get) +static PyObject *Bone_getHead(BPy_Bone *self, void *closure) +{ + PyObject *val1 = newVectorObject(self->bone->head, 3, Py_WRAP); + PyObject *val2 = newVectorObject(self->bone->arm_head, 3, Py_WRAP); + PyObject *ret = Py_BuildValue( + "{s:O, s:O}", "BONESPACE", val1, "ARMATURESPACE", val2); + + Py_DECREF(val1); + Py_DECREF(val2); + return ret; +} +//------------------------Bone.head (set) +static int Bone_setHead(BPy_Bone *self, PyObject *value, void *closure) +{ + return EXPP_intError(PyExc_ValueError, "%s%s", + sBoneError, "You must first call .makeEditable() to edit the armature"); +} +//------------------------Bone.tail (get) +static PyObject *Bone_getTail(BPy_Bone *self, void *closure) +{ + PyObject *val1 = newVectorObject(self->bone->tail, 3, Py_WRAP); + PyObject *val2 = newVectorObject(self->bone->arm_tail, 3, Py_WRAP); + PyObject *ret = Py_BuildValue("{s:O, s:O}", + "BONESPACE", val1, "ARMATURESPACE", val2); + + Py_DECREF(val1); + Py_DECREF(val2); + return ret; +} +//------------------------Bone.tail (set) +static int Bone_setTail(BPy_Bone *self, PyObject *value, void *closure) +{ + return EXPP_intError(PyExc_ValueError, "%s%s", + sBoneError, "You must first call .makeEditable() to edit the armature"); +} +//------------------------Bone.weight (get) +static PyObject *Bone_getWeight(BPy_Bone *self, void *closure) +{ + return PyFloat_FromDouble(self->bone->weight); +} +//------------------------Bone.weight (set) +static int Bone_setWeight(BPy_Bone *self, PyObject *value, void *closure) +{ + return EXPP_intError(PyExc_ValueError, "%s%s", + sBoneError, "You must first call .makeEditable() to edit the armature"); +} +//------------------------Bone.deform_dist (get) +static PyObject *Bone_getDeform_dist(BPy_Bone *self, void *closure) +{ + return PyFloat_FromDouble(self->bone->dist); +} +//------------------------Bone.deform_dist (set) +static int Bone_setDeform_dist(BPy_Bone *self, PyObject *value, void *closure) +{ + return EXPP_intError(PyExc_ValueError, "%s%s", + sBoneError, "You must first call .makeEditable() to edit the armature"); +} +//------------------------Bone.subdivisions (get) +static PyObject *Bone_getSubdivisions(BPy_Bone *self, void *closure) +{ + return PyInt_FromLong(self->bone->segments); +} +//------------------------Bone.subdivisions (set) +static int Bone_setSubdivisions(BPy_Bone *self, PyObject *value, void *closure) +{ + return EXPP_intError(PyExc_ValueError, "%s%s", + sBoneError, "You must first call .makeEditable() to edit the armature"); +} +//------------------------Bone.connected (get) +static PyObject *Bone_getOptions(BPy_Bone *self, void *closure) +{ + PyObject *list = NULL; + + list = PyList_New(0); + if (list == NULL) + goto RuntimeError; + + if(self->bone->flag & BONE_CONNECTED) + if (PyList_Append(list, + EXPP_GetModuleConstant("Blender.Armature", "CONNECTED")) == -1) + goto RuntimeError; + if(self->bone->flag & BONE_HINGE) + if (PyList_Append(list, + EXPP_GetModuleConstant("Blender.Armature", "HINGE")) == -1) + goto RuntimeError; + if(self->bone->flag & BONE_NO_DEFORM) + if (PyList_Append(list, + EXPP_GetModuleConstant("Blender.Armature", "NO_DEFORM")) == -1) + goto RuntimeError; + if(self->bone->flag & BONE_MULT_VG_ENV) + if (PyList_Append(list, + EXPP_GetModuleConstant("Blender.Armature", "MULTIPLY")) == -1) + goto RuntimeError; + if(self->bone->flag & BONE_HIDDEN_A) + if (PyList_Append(list, + EXPP_GetModuleConstant("Blender.Armature", "HIDDEN_EDIT")) == -1) + goto RuntimeError; + if(self->bone->flag & BONE_ROOTSEL) + if (PyList_Append(list, + EXPP_GetModuleConstant("Blender.Armature", "ROOT_SELECTED")) == -1) + goto RuntimeError; + if(self->bone->flag & BONE_SELECTED) + if (PyList_Append(list, + EXPP_GetModuleConstant("Blender.Armature", "BONE_SELECTED")) == -1) + goto RuntimeError; + if(self->bone->flag & BONE_TIPSEL) + if (PyList_Append(list, + EXPP_GetModuleConstant("Blender.Armature", "TIP_SELECTED")) == -1) + goto RuntimeError; + + return list; + +RuntimeError: + Py_XDECREF(list); + return EXPP_objError(PyExc_RuntimeError, "%s%s%s", + sBoneError, "getOptions(): ", "Internal failure!"); +} +//------------------------Bone.connected (set) +static int Bone_setOptions(BPy_Bone *self, PyObject *value, void *closure) +{ + return EXPP_intError(PyExc_ValueError, "%s%s", + sBoneError, "You must first call .makeEditable() to edit the armature"); +} +//------------------------Bone.parent (get) +static PyObject *Bone_getParent(BPy_Bone *self, void *closure) +{ + if (self->bone->parent) + return PyBone_FromBone(self->bone->parent); + else + Py_RETURN_NONE; +} +//------------------------Bone.parent (set) +static int Bone_setParent(BPy_Bone *self, PyObject *value, void *closure) +{ + return EXPP_intError(PyExc_ValueError, "%s%s", + sBoneError, "You must first call .makeEditable() to edit the armature"); +} +//------------------------Bone.children (get) +static PyObject *Bone_getChildren(BPy_Bone *self, void *closure) +{ + PyObject *list = PyList_New(0); + Bone *bone = NULL; + PyObject *py_bone = NULL; + + if (self->bone->childbase.first){ + for (bone = self->bone->childbase.first; bone; bone = bone->next){ + py_bone = PyBone_FromBone(bone); + if (py_bone == NULL) + goto RuntimeError; + if (PyList_Append(list, py_bone) == -1) + goto RuntimeError; + Py_DECREF(py_bone); + } + } + return list; + +RuntimeError: + Py_XDECREF(list); + Py_XDECREF(py_bone); + return EXPP_objError(PyExc_RuntimeError, "%s%s", + sBoneError, "Internal error trying to wrap blender bones!"); +} +//------------------------Bone.children (set) +static int Bone_setChildren(BPy_Bone *self, PyObject *value, void *closure) +{ + return EXPP_intError(PyExc_ValueError, "%s%s", + sBoneError, "You must first call .makeEditable() to edit the armature"); +} +//------------------------Bone.matrix (get) +static PyObject *Bone_getMatrix(BPy_Bone *self, void *closure) +{ + PyObject *val1 = newMatrixObject((float*)self->bone->bone_mat, 3,3, Py_WRAP); + PyObject *val2 = newMatrixObject((float*)self->bone->arm_mat, 4,4, Py_WRAP); + PyObject *ret = Py_BuildValue("{s:O, s:O}", + "BONESPACE", val1, "ARMATURESPACE", val2); + Py_DECREF(val1); + Py_DECREF(val2); + return ret; + + +} +//------------------------Bone.matrix (set) +static int Bone_setMatrix(BPy_Bone *self, PyObject *value, void *closure) +{ + return EXPP_intError(PyExc_ValueError, "%s%s", + sBoneError, "You must first call .makeEditable() to edit the armature"); +} +//------------------------Bone.length (get) +static PyObject *Bone_getLength(BPy_Bone *self, void *closure) +{ + return PyFloat_FromDouble(self->bone->length); +} +//------------------------Bone.length (set) +static int Bone_setLength(BPy_Bone *self, PyObject *value, void *closure) +{ + return EXPP_intError(PyExc_ValueError, "%s%s", + sBoneError, "You must first call .makeEditable() to edit the armature"); +} + +//------------------------Bone.headRadius (get) +static PyObject *Bone_getHeadRadius(BPy_Bone *self, void *closure) +{ + + if (self->bone->parent && self->bone->flag & BONE_CONNECTED) + return PyFloat_FromDouble(self->bone->parent->rad_tail); + else + return PyFloat_FromDouble(self->bone->rad_head); +} +//------------------------Bone.headRadius (set) +static int Bone_setHeadRadius(BPy_Bone *self, PyObject *value, void *closure) +{ + float radius; + if (!PyArg_Parse(value, "f", &radius)) + goto AttributeError; + CLAMP(radius, 0.0f, 10000.0f); + + if (self->bone->parent && self->bone->flag & BONE_CONNECTED) + self->bone->parent->rad_tail= radius; + else + self->bone->rad_head= radius; + return 0; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sEditBoneError, ".headRadius: ", "expects a float"); +} + +//------------------------Bone.tailRadius (get) +static PyObject *Bone_getTailRadius(BPy_Bone *self, void *closure) +{ + return PyFloat_FromDouble(self->bone->rad_tail); +} + +//------------------------Bone.headRadius (set) +static int Bone_setTailRadius(BPy_Bone *self, PyObject *value, void *closure) +{ + float radius; + if (!PyArg_Parse(value, "f", &radius)) + goto AttributeError; + CLAMP(radius, 0.0f, 10000.0f); + self->bone->rad_tail= radius; + return 0; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sEditBoneError, ".headRadius: ", "expects a float"); +} + +//------------------------Bone.layerMask (get) +static PyObject *Bone_getLayerMask(BPy_Bone *self) +{ + /* do this extra stuff because the short's bits can be negative values */ + unsigned short laymask = 0; + laymask |= self->bone->layer; + return PyInt_FromLong((int)laymask); +} +//------------------------Bone.layerMask (set) +static int Bone_setLayerMask(BPy_Bone *self, PyObject *value) +{ + int laymask; + if (!PyInt_Check(value)) { + return EXPP_ReturnIntError( PyExc_AttributeError, + "expected an integer (bitmask) as argument" ); + } + + laymask = PyInt_AsLong(value); + + if (laymask <= 0 || laymask > (1<<16) - 1) + return EXPP_ReturnIntError( PyExc_AttributeError, + "bitmask must have from 1 up to 16 bits set"); + + self->bone->layer = 0; + self->bone->layer |= laymask; + + return 0; +} + +//------------------TYPE_OBECT IMPLEMENTATION-------------------------- +//------------------------tp_methods +//This contains a list of all methods the object contains +static PyMethodDef BPy_Bone_methods[] = { + {"hasParent", (PyCFunction) Bone_hasParent, METH_NOARGS, + "() - True/False - Bone has a parent"}, + {"hasChildren", (PyCFunction) Bone_hasChildren, METH_NOARGS, + "() - True/False - Bone has 1 or more children"}, + {"getAllChildren", (PyCFunction) Bone_getAllChildren, METH_NOARGS, + "() - All the children for this bone - including children's children"}, + {NULL, NULL, 0, NULL} +}; +//------------------------tp_getset +//This contains methods for attributes that require checking +static PyGetSetDef BPy_Bone_getset[] = { + {"name", (getter)Bone_getName, (setter)Bone_setName, + "The name of the bone", NULL}, + {"roll", (getter)Bone_getRoll, (setter)Bone_setRoll, + "The roll (or rotation around the axis) of the bone", NULL}, + {"head", (getter)Bone_getHead, (setter)Bone_setHead, + "The start point of the bone", NULL}, + {"tail", (getter)Bone_getTail, (setter)Bone_setTail, + "The end point of the bone", NULL}, + {"matrix", (getter)Bone_getMatrix, (setter)Bone_setMatrix, + "The matrix of the bone", NULL}, + {"weight", (getter)Bone_getWeight, (setter)Bone_setWeight, + "The weight of the bone in relation to a parented mesh", NULL}, + {"deform_dist", (getter)Bone_getDeform_dist, (setter)Bone_setDeform_dist, + "The distance at which deformation has effect", NULL}, + {"subdivisions", (getter)Bone_getSubdivisions, (setter)Bone_setSubdivisions, + "The number of subdivisions (for B-Bones)", NULL}, + {"options", (getter)Bone_getOptions, (setter)Bone_setOptions, + "The options effective on this bone", NULL}, + {"parent", (getter)Bone_getParent, (setter)Bone_setParent, + "The parent bone of this bone", NULL}, + {"children", (getter)Bone_getChildren, (setter)Bone_setChildren, + "The child bones of this bone", NULL}, + {"length", (getter)Bone_getLength, (setter)Bone_setLength, + "The length of this bone", NULL}, + {"tailRadius", (getter)Bone_getTailRadius, (setter)Bone_setTailRadius, + "Set the radius of this bones tip", NULL}, + {"headRadius", (getter)Bone_getHeadRadius, (setter)Bone_setHeadRadius, + "Set the radius of this bones head", NULL}, + {"layerMask", (getter)Bone_getLayerMask, (setter)Bone_setLayerMask, + "Layer bitmask", NULL }, + {NULL, NULL, NULL, NULL,NULL} +}; +//------------------------tp_repr +//This is the string representation of the object +static PyObject *Bone_repr(BPy_Bone *self) +{ + return PyString_FromFormat( "[Bone \"%s\"]", self->bone->name ); +} +static int Bone_compare( BPy_Bone * a, BPy_Bone * b ) +{ + return ( a->bone == b->bone ) ? 0 : -1; +} +//------------------------tp_dealloc +//This tells how to 'tear-down' our object when ref count hits 0 +static void Bone_dealloc(BPy_Bone * self) +{ + Bone_Type.tp_free(self); + return; +} +//------------------------tp_doc +//The __doc__ string for this object +static char BPy_Bone_doc[] = "This object wraps a Blender Boneobject.\n\ + This object is a subobject of the Armature object."; + +//------------------TYPE_OBECT DEFINITION-------------------------- +PyTypeObject Bone_Type = { + PyObject_HEAD_INIT(NULL) //tp_head + 0, //tp_internal + "Bone", //tp_name + sizeof(BPy_Bone), //tp_basicsize + 0, //tp_itemsize + (destructor)Bone_dealloc, //tp_dealloc + 0, //tp_print + 0, //tp_getattr + 0, //tp_setattr + (cmpfunc) Bone_compare, //tp_compare + (reprfunc) Bone_repr, //tp_repr + 0, //tp_as_number + 0, //tp_as_sequence + 0, //tp_as_mapping + 0, //tp_hash + 0, //tp_call + 0, //tp_str + 0, //tp_getattro + 0, //tp_setattro + 0, //tp_as_buffer + Py_TPFLAGS_DEFAULT, //tp_flags + BPy_Bone_doc, //tp_doc + 0, //tp_traverse + 0, //tp_clear + 0, //tp_richcompare + 0, //tp_weaklistoffset + 0, //tp_iter + 0, //tp_iternext + BPy_Bone_methods, //tp_methods + 0, //tp_members + BPy_Bone_getset, //tp_getset + 0, //tp_base + 0, //tp_dict + 0, //tp_descr_get + 0, //tp_descr_set + 0, //tp_dictoffset + 0, //tp_init + 0, //tp_alloc + 0, //tp_new + 0, //tp_free + 0, //tp_is_gc + 0, //tp_bases + 0, //tp_mro + 0, //tp_cache + 0, //tp_subclasses + 0, //tp_weaklist + 0 //tp_del +}; +//------------------VISIBLE PROTOTYPE IMPLEMENTATION----------------------- +//-----------------(internal) +//Converts a struct EditBone to a BPy_EditBone +PyObject *PyEditBone_FromEditBone(struct EditBone *editbone) +{ + BPy_EditBone *py_editbone = NULL; + + py_editbone = (BPy_EditBone*)EditBone_Type.tp_alloc(&EditBone_Type, 0); //*new* + if (!py_editbone) + goto RuntimeError; + + py_editbone->editbone = editbone; + + return (PyObject *) py_editbone; + +RuntimeError: + return EXPP_objError(PyExc_RuntimeError, "%s%s%s", + sEditBoneError, "PyEditBone_FromEditBone: ", "Internal Error Ocurred"); +} +//-----------------(internal) +//Converts a struct Bone to a BPy_Bone +PyObject *PyBone_FromBone(struct Bone *bone) +{ + BPy_Bone *py_Bone = ( BPy_Bone * ) PyObject_NEW( BPy_Bone, &Bone_Type ); + + py_Bone->bone = bone; + + return (PyObject *) py_Bone; +} +//-----------------(internal) +//Converts a PyBone to a bBone +struct Bone *PyBone_AsBone(BPy_Bone *py_Bone) +{ + return (py_Bone->bone); +} diff --git a/source/blender/python/api2_2x/Bone.h b/source/blender/python/api2_2x/Bone.h new file mode 100644 index 00000000000..aa076afbed7 --- /dev/null +++ b/source/blender/python/api2_2x/Bone.h @@ -0,0 +1,76 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_BONE_H +#define EXPP_BONE_H + +#include +#include "DNA_armature_types.h" + +/*-------------------TYPE CHECKS---------------------------------*/ +#define BoneObject_Check(v) ((v)->ob_type == &Bone_Type) +#define EditBoneObject_Check(v) ((v)->ob_type == &EditBone_Type) +/*-------------------TYPEOBJECT----------------------------------*/ +extern PyTypeObject EditBone_Type; +extern PyTypeObject Bone_Type; +/*-------------------STRUCT DEFINITION----------------------------*/ + +typedef struct { + PyObject_HEAD + Bone * bone; +} BPy_Bone; + +typedef struct { + PyObject_HEAD + struct EditBone *editbone; + struct EditBone *parent; + char name[32]; + float roll; + float head[3]; + float tail[3]; + int flag; + float dist; + float weight; + float xwidth; + float zwidth; + float ease1; + float ease2; + float rad_head; + float rad_tail; + short segments; + short layer; +} BPy_EditBone; +/*-------------------VISIBLE PROTOTYPES-------------------------*/ +PyObject *PyBone_FromBone(struct Bone *bone); +struct Bone *PyBone_AsBone(BPy_Bone *py_Bone); +PyObject *PyEditBone_FromBone(Bone *bone); +PyObject *PyEditBone_FromEditBone(struct EditBone *editbone); + +#endif diff --git a/source/blender/python/api2_2x/Camera.c b/source/blender/python/api2_2x/Camera.c new file mode 100644 index 00000000000..f6b443e5d06 --- /dev/null +++ b/source/blender/python/api2_2x/Camera.c @@ -0,0 +1,1057 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano, Johnny Matthews, Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#include "Camera.h" /*This must come first */ + +#include "BKE_main.h" +#include "BKE_global.h" +#include "BKE_object.h" +#include "BKE_library.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" /* for M_PI */ +#include "BSE_editipo.h" +#include "BIF_space.h" +#include "mydevice.h" +#include "gen_utils.h" +#include "gen_library.h" +#include "Ipo.h" + + +#define IPOKEY_LENS 0 +#define IPOKEY_CLIPPING 1 + + + +enum cam_consts { + EXPP_CAM_ATTR_LENS = 0, + EXPP_CAM_ATTR_ANGLE, + EXPP_CAM_ATTR_DOFDIST, + EXPP_CAM_ATTR_CLIPEND, + EXPP_CAM_ATTR_CLIPSTART, + EXPP_CAM_ATTR_SCALE, + EXPP_CAM_ATTR_DRAWSIZE, + EXPP_CAM_ATTR_SHIFTX, + EXPP_CAM_ATTR_SHIFTY, + EXPP_CAM_ATTR_ALPHA, +}; + +/*****************************************************************************/ +/* Python API function prototypes for the Camera module. */ +/*****************************************************************************/ +static PyObject *M_Camera_New( PyObject * self, PyObject * args, + PyObject * keywords ); +static PyObject *M_Camera_Get( PyObject * self, PyObject * args ); + +/*****************************************************************************/ +/* The following string definitions are used for documentation strings. */ +/* In Python these will be written to the console when doing a */ +/* Blender.Camera.__doc__ */ +/*****************************************************************************/ +static char M_Camera_doc[] = "The Blender Camera module\n\ +\n\ +This module provides access to **Camera Data** objects in Blender\n\ +\n\ +Example::\n\ +\n\ + from Blender import Camera, Object, Scene\n\ + c = Camera.New('ortho') # create new ortho camera data\n\ + c.scale = 6.0 # set scale value\n\ + scn = Scene.GetCurrent() # get current Scene\n\ + ob = scn.objects.new(c) # Make an object from this data in the scene\n\ + cur.setCurrentCamera(ob) # make this camera the active"; + +static char M_Camera_New_doc[] = + "Camera.New (type = 'persp', name = 'CamData'):\n\ + Return a new Camera Data object with the given type and name."; + +static char M_Camera_Get_doc[] = "Camera.Get (name = None):\n\ + Return the camera data with the given 'name', None if not found, or\n\ + Return a list with all Camera Data objects in the current scene,\n\ + if no argument was given."; + +/*****************************************************************************/ +/* Python method structure definition for Blender.Camera module: */ +/*****************************************************************************/ +struct PyMethodDef M_Camera_methods[] = { + {"New", ( PyCFunction ) M_Camera_New, METH_VARARGS | METH_KEYWORDS, + M_Camera_New_doc}, + {"Get", M_Camera_Get, METH_VARARGS, M_Camera_Get_doc}, + {"get", M_Camera_Get, METH_VARARGS, M_Camera_Get_doc}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python BPy_Camera methods declarations: */ +/*****************************************************************************/ +static PyObject *Camera_oldgetType( BPy_Camera * self ); +static PyObject *Camera_oldgetMode( BPy_Camera * self ); +static PyObject *Camera_oldgetLens( BPy_Camera * self ); +static PyObject *Camera_oldgetClipStart( BPy_Camera * self ); +static PyObject *Camera_oldgetClipEnd( BPy_Camera * self ); +static PyObject *Camera_oldgetDrawSize( BPy_Camera * self ); +static PyObject *Camera_oldgetScale( BPy_Camera * self ); +static PyObject *Camera_getIpo( BPy_Camera * self ); +static int Camera_setIpo( BPy_Camera * self, PyObject * value ); +static PyObject *Camera_oldsetIpo( BPy_Camera * self, PyObject * args ); +static PyObject *Camera_oldsetType( BPy_Camera * self, PyObject * args ); +static PyObject *Camera_oldsetMode( BPy_Camera * self, PyObject * args ); +static PyObject *Camera_oldsetLens( BPy_Camera * self, PyObject * args ); +static PyObject *Camera_oldsetClipStart( BPy_Camera * self, PyObject * args ); +static PyObject *Camera_oldsetClipEnd( BPy_Camera * self, PyObject * args ); +static PyObject *Camera_oldsetDrawSize( BPy_Camera * self, PyObject * args ); +static PyObject *Camera_oldsetScale( BPy_Camera * self, PyObject * args ); +static PyObject *Camera_oldgetScriptLinks( BPy_Camera * self, PyObject * value ); +static PyObject *Camera_addScriptLink( BPy_Camera * self, PyObject * args ); +static PyObject *Camera_oldclearIpo( BPy_Camera * self ); +static PyObject *Camera_clearScriptLinks( BPy_Camera * self, PyObject * args ); +static PyObject *Camera_insertIpoKey( BPy_Camera * self, PyObject * args ); +static PyObject *Camera_copy( BPy_Camera * self ); + + +/*****************************************************************************/ +/* Python BPy_Camera methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_Camera_methods[] = { + /* name, method, flags, doc */ + {"getIpo", ( PyCFunction ) Camera_getIpo, METH_NOARGS, + "() - Return Camera Data Ipo"}, + {"getName", ( PyCFunction ) GenericLib_getName, METH_NOARGS, + "() - Return Camera Data name"}, + {"getType", ( PyCFunction ) Camera_oldgetType, METH_NOARGS, + "() - Return Camera type - 'persp':0, 'ortho':1"}, + {"getMode", ( PyCFunction ) Camera_oldgetMode, METH_NOARGS, + "() - Return Camera mode flags (or'ed value) -\n" + " 'showLimits':1, 'showMist':2"}, + {"getLens", ( PyCFunction ) Camera_oldgetLens, METH_NOARGS, + "() - Return *perspective* Camera lens value"}, + {"getScale", ( PyCFunction ) Camera_oldgetScale, METH_NOARGS, + "() - Return *ortho* Camera scale value"}, + {"getClipStart", ( PyCFunction ) Camera_oldgetClipStart, METH_NOARGS, + "() - Return Camera clip start value"}, + {"getClipEnd", ( PyCFunction ) Camera_oldgetClipEnd, METH_NOARGS, + "() - Return Camera clip end value"}, + {"getDrawSize", ( PyCFunction ) Camera_oldgetDrawSize, METH_NOARGS, + "() - Return Camera draw size value"}, + {"setIpo", ( PyCFunction ) Camera_oldsetIpo, METH_VARARGS, + "(Blender Ipo) - Set Camera Ipo"}, + {"clearIpo", ( PyCFunction ) Camera_oldclearIpo, METH_NOARGS, + "() - Unlink Ipo from this Camera."}, + {"insertIpoKey", ( PyCFunction ) Camera_insertIpoKey, METH_VARARGS, + "( Camera IPO type ) - Inserts a key into IPO"}, + {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS, + "(s) - Set Camera Data name"}, + {"setType", ( PyCFunction ) Camera_oldsetType, METH_O, + "(s) - Set Camera type, which can be 'persp' or 'ortho'"}, + {"setMode", ( PyCFunction ) Camera_oldsetMode, METH_VARARGS, + "(>) - Set Camera mode flag(s): 'showLimits' and 'showMist'"}, + {"setLens", ( PyCFunction ) Camera_oldsetLens, METH_O, + "(f) - Set *perpective* Camera lens value"}, + {"setScale", ( PyCFunction ) Camera_oldsetScale, METH_O, + "(f) - Set *ortho* Camera scale value"}, + {"setClipStart", ( PyCFunction ) Camera_oldsetClipStart, METH_O, + "(f) - Set Camera clip start value"}, + {"setClipEnd", ( PyCFunction ) Camera_oldsetClipEnd, METH_O, + "(f) - Set Camera clip end value"}, + {"setDrawSize", ( PyCFunction ) Camera_oldsetDrawSize, METH_O, + "(f) - Set Camera draw size value"}, + {"getScriptLinks", ( PyCFunction ) Camera_oldgetScriptLinks, METH_O, + "(eventname) - Get a list of this camera's scriptlinks (Text names) " + "of the given type\n" + "(eventname) - string: FrameChanged, Redraw or Render."}, + {"addScriptLink", ( PyCFunction ) Camera_addScriptLink, METH_VARARGS, + "(text, evt) - Add a new camera scriptlink.\n" + "(text) - string: an existing Blender Text name;\n" + "(evt) string: FrameChanged, Redraw or Render."}, + {"clearScriptLinks", ( PyCFunction ) Camera_clearScriptLinks, + METH_NOARGS, + "() - Delete all scriptlinks from this camera.\n" + "([s1<,s2,s3...>]) - Delete specified scriptlinks from this camera."}, + {"__copy__", ( PyCFunction ) Camera_copy, METH_NOARGS, + "() - Return a copy of the camera."}, + {"copy", ( PyCFunction ) Camera_copy, METH_NOARGS, + "() - Return a copy of the camera."}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python Camera_Type callback function prototypes: */ +/*****************************************************************************/ +static int Camera_compare( BPy_Camera * a, BPy_Camera * b ); +static PyObject *Camera_repr( BPy_Camera * self ); + +static PyObject *M_Camera_New( PyObject * self, PyObject * args, + PyObject * kwords ) +{ + char *type_str = "persp"; /* "persp" is type 0, "ortho" is type 1 */ + char *name_str = "Camera"; + static char *kwlist[] = { "type_str", "name_str", NULL }; + PyObject *pycam; /* for Camera Data object wrapper in Python */ + Camera *blcam; /* for actual Camera Data we create in Blender */ + + /* Parse the arguments passed in by the Python interpreter */ + if( !PyArg_ParseTupleAndKeywords( args, kwords, "|ss", kwlist, + &type_str, &name_str ) ) + /* We expected string(s) (or nothing) as argument, but we didn't get that. */ + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected zero, one or two strings as arguments" ); + + blcam = add_camera( name_str ); /* first create the Camera Data in Blender */ + + if( blcam ) /* now create the wrapper obj in Python */ + pycam = Camera_CreatePyObject( blcam ); + else + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't create Camera Data in Blender" ); + + /* let's return user count to zero, because ... */ + blcam->id.us = 0; /* ... add_camera() incref'ed it */ + /* XXX XXX Do this in other modules, too */ + + if( pycam == NULL ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create Camera PyObject" ); + + if( strcmp( type_str, "persp" ) == 0 ) + /* default, no need to set, so */ + /*blcam->type = (short)EXPP_CAM_TYPE_PERSP */ + ; + /* we comment this line */ + else if( strcmp( type_str, "ortho" ) == 0 ) + blcam->type = ( short ) EXPP_CAM_TYPE_ORTHO; + else + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "unknown camera type" ); + + return pycam; +} + +static PyObject *M_Camera_Get( PyObject * self, PyObject * args ) +{ + char *name = NULL; + Camera *cam_iter; + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument (or nothing)" ); + + cam_iter = G.main->camera.first; + + if( name ) { /* (name) - Search camera by name */ + + PyObject *wanted_cam = NULL; + + while( cam_iter && !wanted_cam ) { + + if( strcmp( name, cam_iter->id.name + 2 ) == 0 ) { + wanted_cam = Camera_CreatePyObject( cam_iter ); + break; + } + + cam_iter = cam_iter->id.next; + } + + if( !wanted_cam ) { /* Requested camera doesn't exist */ + char error_msg[64]; + PyOS_snprintf( error_msg, sizeof( error_msg ), + "Camera \"%s\" not found", name ); + return EXPP_ReturnPyObjError( PyExc_NameError, + error_msg ); + } + + return wanted_cam; + } + + else { /* () - return a list of wrappers for all cameras in the scene */ + int index = 0; + PyObject *cam_pylist, *pyobj; + + cam_pylist = + PyList_New( BLI_countlist( &( G.main->camera ) ) ); + + if( !cam_pylist ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyList" ); + + while( cam_iter ) { + pyobj = Camera_CreatePyObject( cam_iter ); + + if( !pyobj ) { + Py_DECREF(cam_pylist); + return EXPP_ReturnPyObjError + ( PyExc_MemoryError, + "couldn't create Camera PyObject" ); + } + PyList_SET_ITEM( cam_pylist, index, pyobj ); + + cam_iter = cam_iter->id.next; + index++; + } + + return cam_pylist; + } +} + +PyObject *Camera_Init( void ) +{ + PyObject *submodule; + + if( PyType_Ready( &Camera_Type ) < 0 ) + return NULL; + + submodule = Py_InitModule3( "Blender.Camera", + M_Camera_methods, M_Camera_doc ); + + PyModule_AddIntConstant( submodule, "LENS", IPOKEY_LENS ); + PyModule_AddIntConstant( submodule, "CLIPPING", IPOKEY_CLIPPING ); + + return submodule; +} + +/* Three Python Camera_Type helper functions needed by the Object module: */ + +PyObject *Camera_CreatePyObject( Camera * cam ) +{ + BPy_Camera *pycam; + + pycam = ( BPy_Camera * ) PyObject_NEW( BPy_Camera, &Camera_Type ); + + if( !pycam ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create BPy_Camera PyObject" ); + + pycam->camera = cam; + return ( PyObject * ) pycam; +} + +Camera *Camera_FromPyObject( PyObject * pyobj ) +{ + return ( ( BPy_Camera * ) pyobj )->camera; +} + +/*****************************************************************************/ +/* Python BPy_Camera methods: */ +/*****************************************************************************/ + +static PyObject *Camera_oldgetType( BPy_Camera * self ) +{ + return PyInt_FromLong( self->camera->type ); +} + +static PyObject *Camera_oldgetMode( BPy_Camera * self ) +{ + return PyInt_FromLong( self->camera->flag ); +} + +static PyObject *Camera_oldgetLens( BPy_Camera * self ) +{ + return PyFloat_FromDouble( self->camera->lens ); +} + +static PyObject *Camera_oldgetScale( BPy_Camera * self ) +{ + return PyFloat_FromDouble( self->camera->ortho_scale ); +} + +static PyObject *Camera_oldgetClipStart( BPy_Camera * self ) +{ + return PyFloat_FromDouble( self->camera->clipsta ); +} + +static PyObject *Camera_oldgetClipEnd( BPy_Camera * self ) +{ + return PyFloat_FromDouble( self->camera->clipend ); +} + +static PyObject *Camera_oldgetDrawSize( BPy_Camera * self ) +{ + return PyFloat_FromDouble( self->camera->drawsize ); +} + + + +static PyObject *Camera_oldsetIpo( BPy_Camera * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Camera_setIpo ); +} + +static PyObject *Camera_oldclearIpo( BPy_Camera * self ) +{ + Camera *cam = self->camera; + Ipo *ipo = ( Ipo * ) cam->ipo; + + if( ipo ) { + ID *id = &ipo->id; + if( id->us > 0 ) + id->us--; + cam->ipo = NULL; + + return EXPP_incr_ret_True(); + } + + return EXPP_incr_ret_False(); /* no ipo found */ +} + +static PyObject *Camera_oldsetType( BPy_Camera * self, PyObject * value ) +{ + char *type = PyString_AsString(value); + + if(!value) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + + if( strcmp( type, "persp" ) == 0 ) + self->camera->type = ( short ) EXPP_CAM_TYPE_PERSP; + else if( strcmp( type, "ortho" ) == 0 ) + self->camera->type = ( short ) EXPP_CAM_TYPE_ORTHO; + else + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "unknown camera type" ); + + Py_RETURN_NONE; +} + +static PyObject *Camera_oldsetMode( BPy_Camera * self, PyObject * args ) +{ + char *mode_str1 = NULL, *mode_str2 = NULL; + short flag = 0; + + if( !PyArg_ParseTuple( args, "|ss", &mode_str1, &mode_str2 ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected one or two strings as arguments" ); + + if( mode_str1 != NULL ) { + if( strcmp( mode_str1, "showLimits" ) == 0 ) + flag |= ( short ) EXPP_CAM_MODE_SHOWLIMITS; + else if( strcmp( mode_str1, "showMist" ) == 0 ) + flag |= ( short ) EXPP_CAM_MODE_SHOWMIST; + else + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "first argument is an unknown camera flag" ); + + if( mode_str2 != NULL ) { + if( strcmp( mode_str2, "showLimits" ) == 0 ) + flag |= ( short ) EXPP_CAM_MODE_SHOWLIMITS; + else if( strcmp( mode_str2, "showMist" ) == 0 ) + flag |= ( short ) EXPP_CAM_MODE_SHOWMIST; + else + return EXPP_ReturnPyObjError + ( PyExc_AttributeError, + "second argument is an unknown camera flag" ); + } + } + + self->camera->flag = flag; + + Py_RETURN_NONE; +} + +static PyObject *Camera_oldsetLens( BPy_Camera * self, PyObject * value ) +{ + float param = PyFloat_AsDouble(value); + + if( !PyFloat_Check(value) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected float argument" ); + + self->camera->lens = EXPP_ClampFloat( param, + EXPP_CAM_LENS_MIN, + EXPP_CAM_LENS_MAX ); + + Py_RETURN_NONE; +} + +static PyObject *Camera_oldsetScale( BPy_Camera * self, PyObject * value ) +{ + float param = PyFloat_AsDouble(value); + + if( !PyFloat_Check(value) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected float argument" ); + + self->camera->ortho_scale = EXPP_ClampFloat( param, + EXPP_CAM_SCALE_MIN, + EXPP_CAM_SCALE_MAX ); + + Py_RETURN_NONE; +} + +static PyObject *Camera_oldsetClipStart( BPy_Camera * self, PyObject * value ) +{ + float param = PyFloat_AsDouble(value); + + if( !PyFloat_Check(value) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected float argument" ); + + self->camera->clipsta = EXPP_ClampFloat( param, + EXPP_CAM_CLIPSTART_MIN, + EXPP_CAM_CLIPSTART_MAX ); + + Py_RETURN_NONE; +} + +static PyObject *Camera_oldsetClipEnd( BPy_Camera * self, PyObject * value ) +{ + float param = PyFloat_AsDouble(value); + + if( !PyFloat_Check(value) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected float argument" ); + + self->camera->clipend = EXPP_ClampFloat( param, + EXPP_CAM_CLIPEND_MIN, + EXPP_CAM_CLIPEND_MAX ); + + Py_RETURN_NONE; +} + +static PyObject *Camera_oldsetDrawSize( BPy_Camera * self, PyObject * value ) +{ + float param = PyFloat_AsDouble(value); + + if( !PyFloat_Check(value) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected float argument" ); + + self->camera->drawsize = EXPP_ClampFloat( param, + EXPP_CAM_DRAWSIZE_MIN, + EXPP_CAM_DRAWSIZE_MAX ); + + Py_RETURN_NONE; +} + +/* cam.addScriptLink */ +static PyObject *Camera_addScriptLink( BPy_Camera * self, PyObject * args ) +{ + Camera *cam = self->camera; + ScriptLink *slink = NULL; + + slink = &( cam )->scriptlink; + + return EXPP_addScriptLink( slink, args, 0 ); +} + +/* cam.clearScriptLinks */ +static PyObject *Camera_clearScriptLinks( BPy_Camera * self, PyObject * args ) +{ + Camera *cam = self->camera; + ScriptLink *slink = NULL; + + slink = &( cam )->scriptlink; + + return EXPP_clearScriptLinks( slink, args ); +} + +/* cam.getScriptLinks */ +static PyObject *Camera_oldgetScriptLinks( BPy_Camera * self, PyObject * value ) +{ + Camera *cam = self->camera; + ScriptLink *slink = NULL; + PyObject *ret = NULL; + + slink = &( cam )->scriptlink; + + ret = EXPP_getScriptLinks( slink, value, 0 ); + + if( ret ) + return ret; + else + return NULL; +} + +/* cam.__copy__ */ +static PyObject *Camera_copy( BPy_Camera * self ) +{ + PyObject *pycam; /* for Camera Data object wrapper in Python */ + Camera *blcam; /* for actual Camera Data we create in Blender */ + + blcam = copy_camera( self->camera ); /* first create the Camera Data in Blender */ + + if( blcam ) /* now create the wrapper obj in Python */ + pycam = Camera_CreatePyObject( blcam ); + else + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't create Camera Data in Blender" ); + + /* let's return user count to zero, because ... */ + blcam->id.us = 0; /* ... copy_camera() incref'ed it */ + /* XXX XXX Do this in other modules, too */ + + if( pycam == NULL ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create Camera PyObject" ); + + return pycam; +} + +static PyObject *Camera_getType( BPy_Camera * self ) +{ + if (self->camera->type == EXPP_CAM_TYPE_PERSP) + return PyString_FromString("persp"); + else /* must be EXPP_CAM_TYPE_ORTHO */ + return PyString_FromString("ortho"); +} + +static int Camera_setType( BPy_Camera * self, PyObject * value ) +{ + char *type = NULL; + type = PyString_AsString(value); + + if (!type) + return EXPP_ReturnIntError( PyExc_ValueError, + "expected a string" ); + if (strcmp("persp", type)==0) { + self->camera->type = EXPP_CAM_TYPE_PERSP; + return 0; + } else if (strcmp("ortho", type)==0) { + self->camera->type = EXPP_CAM_TYPE_ORTHO; + return 0; + } + + return EXPP_ReturnIntError( PyExc_ValueError, + "expected a string \"ortho\" or \"persp\"" ); +} + + + +static PyObject *Camera_getMode( BPy_Camera * self ) +{ + return PyInt_FromLong(self->camera->flag); +} + +static int Camera_setMode( BPy_Camera * self, PyObject * value ) +{ + unsigned int flag = 0; + + if( !PyInt_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected an integer (bitmask) as argument" ); + + flag = ( unsigned int )PyInt_AS_LONG( value ); + + self->camera->flag = flag; + return 0; +} + +static PyObject *Camera_getIpo( BPy_Camera * self ) +{ + struct Ipo *ipo = self->camera->ipo; + + if( ipo ) + return Ipo_CreatePyObject( ipo ); + Py_RETURN_NONE; +} + +static int Camera_setIpo( BPy_Camera * self, PyObject * value ) +{ + return GenericLib_assignData(value, (void **) &self->camera->ipo, 0, 1, ID_IP, ID_CA); +} + +/* + * get floating point attributes + */ + +static PyObject *getFloatAttr( BPy_Camera *self, void *type ) +{ + float param; + struct Camera *cam= self->camera; + + switch( (int)type ) { + case EXPP_CAM_ATTR_LENS: + param = cam->lens; + break; + case EXPP_CAM_ATTR_ANGLE: + param = 360.0f * atan(16.0f/cam->lens) / M_PI; + break; + case EXPP_CAM_ATTR_DOFDIST: + param = cam->YF_dofdist; + break; + case EXPP_CAM_ATTR_CLIPSTART: + param = cam->clipsta; + break; + case EXPP_CAM_ATTR_CLIPEND: + param = cam->clipend; + break; + case EXPP_CAM_ATTR_DRAWSIZE: + param = cam->drawsize; + break; + case EXPP_CAM_ATTR_SCALE: + param = cam->ortho_scale; + break; + case EXPP_CAM_ATTR_ALPHA: + param = cam->passepartalpha; + break; + case EXPP_CAM_ATTR_SHIFTX: + param = cam->shiftx; + break; + case EXPP_CAM_ATTR_SHIFTY: + param = cam->shifty; + break; + + default: + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "undefined type in getFloatAttr" ); + } + + return PyFloat_FromDouble( param ); +} + + + +/* + * set floating point attributes which require clamping + */ + +static int setFloatAttrClamp( BPy_Camera *self, PyObject *value, void *type ) +{ + float *param; + struct Camera *cam = self->camera; + float min, max; + int ret; + + switch( (int)type ) { + case EXPP_CAM_ATTR_LENS: + min = 1.0; + max = 250.0; + param = &cam->lens; + break; + case EXPP_CAM_ATTR_ANGLE: + min = 7.323871; + max = 172.847331; + param = &cam->lens; + break; + case EXPP_CAM_ATTR_DOFDIST: + min = 0.0; + max = 5000.0; + param = &cam->YF_dofdist; + break; + case EXPP_CAM_ATTR_CLIPSTART: + min = 0.0; + max = 100.0; + param = &cam->clipsta; + break; + case EXPP_CAM_ATTR_CLIPEND: + min = 1.0; + max = 5000.0; + param = &cam->clipend; + break; + case EXPP_CAM_ATTR_DRAWSIZE: + min = 0.1f; + max = 10.0; + param = &cam->drawsize; + break; + case EXPP_CAM_ATTR_SCALE: + min = 0.01f; + max = 1000.0; + param = &cam->ortho_scale; + break; + case EXPP_CAM_ATTR_ALPHA: + min = 0.0; + max = 1.0; + param = &cam->passepartalpha; + break; + case EXPP_CAM_ATTR_SHIFTX: + min = -2.0; + max = 2.0; + param = &cam->shiftx; + break; + case EXPP_CAM_ATTR_SHIFTY: + min = -2.0; + max = 2.0; + param = &cam->shifty; + break; + + default: + return EXPP_ReturnIntError( PyExc_RuntimeError, + "undefined type in setFloatAttrClamp" ); + } + + ret = EXPP_setFloatClamped( value, param, min, max ); + + if (ret==0) { + if ((int)type == EXPP_CAM_ATTR_ANGLE) { + cam->lens = 16.0f / tan(M_PI*cam->lens/360.0f); + } + } + return ret; +} + + +/* + * get floating point attributes + */ + +static PyObject *getFlagAttr( BPy_Camera *self, void *type ) +{ + if (self->camera->flag & (int)type) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +/* + * set floating point attributes which require clamping + */ + +static int setFlagAttr( BPy_Camera *self, PyObject *value, void *type ) +{ + int param = PyObject_IsTrue( value ); + if( param == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected True/False or 0/1" ); + + if (param) + self->camera->flag |= (int)type; + else + self->camera->flag &= ~(int)type; + return 0; +} + + +/*****************************************************************************/ +/* Python attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef BPy_Camera_getseters[] = { + GENERIC_LIB_GETSETATTR, + {"type", + (getter)Camera_getType, (setter)Camera_setType, + "camera type \"persp\" or \"ortho\"", + NULL}, + {"mode", + (getter)Camera_getMode, (setter)Camera_setMode, + "Cameras mode", + NULL}, + {"ipo", + (getter)Camera_getIpo, (setter)Camera_setIpo, + "Cameras ipo", + NULL}, + + /* float settings */ + {"lens", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "lens angle for perspective cameras", + (void *)EXPP_CAM_ATTR_LENS}, + {"angle", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "lens angle for perspective cameras", + (void *)EXPP_CAM_ATTR_ANGLE}, + + {"scale", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "scale for ortho cameras", + (void *)EXPP_CAM_ATTR_SCALE}, + {"clipStart", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "the cameras clip start", + (void *)EXPP_CAM_ATTR_CLIPSTART}, + {"clipEnd", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "the cameras clip end", + (void *)EXPP_CAM_ATTR_CLIPEND}, + {"shiftX", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "the cameras X perspective shift", + (void *)EXPP_CAM_ATTR_SHIFTX}, + {"shiftY", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "the cameras Y perspective shift", + (void *)EXPP_CAM_ATTR_SHIFTY}, + {"dofDist", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "cameras dof distance", + (void *)EXPP_CAM_ATTR_DOFDIST}, + {"drawSize", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "the cameras display size", + (void *)EXPP_CAM_ATTR_DRAWSIZE}, + {"alpha", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "passepart alpha value for display", + (void *)EXPP_CAM_ATTR_ALPHA}, + + /* flags - use flags as defined in DNA_camera_types.h */ + {"drawLimits", + (getter)getFlagAttr, (setter)setFlagAttr, + "toggle the draw limits display flag", + (void *)CAM_SHOWLIMITS}, + {"drawMist", + (getter)getFlagAttr, (setter)setFlagAttr, + "toggle the draw mist display flag", + (void *)CAM_SHOWMIST}, + {"drawName", + (getter)getFlagAttr, (setter)setFlagAttr, + "toggle the draw name display flag", + (void *)CAM_SHOWNAME}, + {"drawTileSafe", + (getter)getFlagAttr, (setter)setFlagAttr, + "toggle the tile safe display flag", + (void *)CAM_SHOWTITLESAFE}, + {"drawPassepartout", + (getter)getFlagAttr, (setter)setFlagAttr, + "toggle the passPartOut display flag", + (void *)CAM_SHOWPASSEPARTOUT}, + {"angleToggle", + (getter)getFlagAttr, (setter)setFlagAttr, + "toggle the camera input unit flag", + (void *)CAM_ANGLETOGGLE}, + {NULL,NULL,NULL,NULL} /* Sentinel */ +}; + + +/*****************************************************************************/ +/* Python Camera_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject Camera_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender Camera", /* char *tp_name; */ + sizeof( BPy_Camera ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) Camera_compare, /* cmpfunc tp_compare; */ + ( reprfunc ) Camera_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_Camera_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_Camera_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + + + +static int Camera_compare( BPy_Camera * a, BPy_Camera * b ) +{ + Camera *pa = a->camera, *pb = b->camera; + return ( pa == pb ) ? 0 : -1; +} + +static PyObject *Camera_repr( BPy_Camera * self ) +{ + return PyString_FromFormat( "[Camera \"%s\"]", + self->camera->id.name + 2 ); +} + +/* + * Camera_insertIpoKey() + * inserts Camera IPO key for LENS and CLIPPING + */ + +static PyObject *Camera_insertIpoKey( BPy_Camera * self, PyObject * args ) +{ + int key = 0; + + if( !PyArg_ParseTuple( args, "i", &( key ) ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected int argument" ) ); + + if (key == IPOKEY_LENS){ + insertkey((ID *)self->camera, ID_CA, NULL, NULL, CAM_LENS, 0); + } + else if (key == IPOKEY_CLIPPING){ + insertkey((ID *)self->camera, ID_CA, NULL, NULL, CAM_STA, 0); + insertkey((ID *)self->camera, ID_CA, NULL, NULL, CAM_END, 0); + } + + allspace(REMAKEIPO, 0); + EXPP_allqueue(REDRAWIPO, 0); + EXPP_allqueue(REDRAWVIEW3D, 0); + EXPP_allqueue(REDRAWACTION, 0); + EXPP_allqueue(REDRAWNLA, 0); + + Py_RETURN_NONE; +} diff --git a/source/blender/python/api2_2x/Camera.h b/source/blender/python/api2_2x/Camera.h new file mode 100644 index 00000000000..c92e51c1468 --- /dev/null +++ b/source/blender/python/api2_2x/Camera.h @@ -0,0 +1,82 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_CAMERA_H +#define EXPP_CAMERA_H + +#include +#include "DNA_camera_types.h" + +extern PyTypeObject Camera_Type; + +#define BPy_Camera_Check(v) \ + ((v)->ob_type == &Camera_Type) /* for type checking */ + +/* Python BPy_Camera structure definition */ +typedef struct { + PyObject_HEAD /* required py macro */ + Camera * camera; + +} BPy_Camera; + +/*****************************************************************************/ +/* Python BPy_Camera defaults: */ +/*****************************************************************************/ + +/* Camera types */ + +#define EXPP_CAM_TYPE_PERSP 0 +#define EXPP_CAM_TYPE_ORTHO 1 + +/* Camera mode flags */ + +#define EXPP_CAM_MODE_SHOWLIMITS 1 +#define EXPP_CAM_MODE_SHOWMIST 2 + +/* Camera MIN, MAX values */ + +#define EXPP_CAM_LENS_MIN 1.0 +#define EXPP_CAM_LENS_MAX 250.0 +#define EXPP_CAM_SCALE_MIN 0.01f +#define EXPP_CAM_SCALE_MAX 1000.0 +#define EXPP_CAM_CLIPSTART_MIN 0.0 +#define EXPP_CAM_CLIPSTART_MAX 100.0 +#define EXPP_CAM_CLIPEND_MIN 1.0 +#define EXPP_CAM_CLIPEND_MAX 5000.0 +#define EXPP_CAM_DRAWSIZE_MIN 0.1f +#define EXPP_CAM_DRAWSIZE_MAX 10.0 + +PyObject *Camera_Init( void ); +PyObject *Camera_CreatePyObject( Camera * cam ); +Camera *Camera_FromPyObject( PyObject * pyobj ); + +#endif /* EXPP_CAMERA_H */ diff --git a/source/blender/python/api2_2x/Constraint.c b/source/blender/python/api2_2x/Constraint.c new file mode 100644 index 00000000000..1836c0c6bc2 --- /dev/null +++ b/source/blender/python/api2_2x/Constraint.c @@ -0,0 +1,2678 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Joseph Gilbert, Ken Hughes, Joshua Leung + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "Constraint.h" /*This must come first*/ + +#include "DNA_object_types.h" +#include "DNA_effect_types.h" +#include "DNA_vec_types.h" +#include "DNA_curve_types.h" +#include "DNA_text_types.h" + +#include "BKE_main.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_action.h" +#include "BKE_armature.h" +#include "BKE_constraint.h" +#include "BLI_blenlib.h" +#include "BIF_editconstraint.h" +#include "BSE_editipo.h" +#include "MEM_guardedalloc.h" +#include "butspace.h" +#include "blendef.h" +#include "mydevice.h" + +#include "IDProp.h" +#include "Object.h" +#include "NLA.h" +#include "Text.h" +#include "gen_utils.h" + +enum constraint_constants { + EXPP_CONSTR_XROT = 0, + EXPP_CONSTR_YROT = 1, + EXPP_CONSTR_ZROT = 2, + EXPP_CONSTR_XSIZE = 10, + EXPP_CONSTR_YSIZE = 11, + EXPP_CONSTR_ZSIZE = 12, + EXPP_CONSTR_XLOC = 20, + EXPP_CONSTR_YLOC = 21, + EXPP_CONSTR_ZLOC = 22, + + EXPP_CONSTR_MAXX = TRACK_X, + EXPP_CONSTR_MAXY = TRACK_Y, + EXPP_CONSTR_MAXZ = TRACK_Z, + EXPP_CONSTR_MINX = TRACK_nX, + EXPP_CONSTR_MINY = TRACK_nY, + EXPP_CONSTR_MINZ = TRACK_nZ, + + EXPP_CONSTR_TARGET = 100, + EXPP_CONSTR_STRETCH, + EXPP_CONSTR_ITERATIONS, + EXPP_CONSTR_BONE, + EXPP_CONSTR_CHAINLEN, + EXPP_CONSTR_POSWEIGHT, + EXPP_CONSTR_ROTWEIGHT, + EXPP_CONSTR_ROTATE, + EXPP_CONSTR_USETIP, + + EXPP_CONSTR_ACTION, + EXPP_CONSTR_START, + EXPP_CONSTR_END, + EXPP_CONSTR_MIN, + EXPP_CONSTR_MAX, + EXPP_CONSTR_KEYON, + + EXPP_CONSTR_TRACK, + EXPP_CONSTR_UP, + + EXPP_CONSTR_RESTLENGTH, + EXPP_CONSTR_VOLVARIATION, + EXPP_CONSTR_VOLUMEMODE, + EXPP_CONSTR_PLANE, + + EXPP_CONSTR_FOLLOW, + EXPP_CONSTR_OFFSET, + EXPP_CONSTR_FORWARD, + + EXPP_CONSTR_LOCK, + + EXPP_CONSTR_MINMAX, + EXPP_CONSTR_STICKY, + + EXPP_CONSTR_COPY, + EXPP_CONSTR_LIMIT, + EXPP_CONSTR_CLAMP, + + EXPP_CONSTR_LIMXMIN = LIMIT_XMIN, + EXPP_CONSTR_LIMXMAX = LIMIT_XMAX, + EXPP_CONSTR_LIMYMIN = LIMIT_YMIN, + EXPP_CONSTR_LIMYMAX = LIMIT_YMAX, + EXPP_CONSTR_LIMZMIN = LIMIT_ZMIN, + EXPP_CONSTR_LIMZMAX = LIMIT_ZMAX, + + EXPP_CONSTR_LIMXROT = LIMIT_XROT, + EXPP_CONSTR_LIMYROT = LIMIT_YROT, + EXPP_CONSTR_LIMZROT = LIMIT_ZROT, + + EXPP_CONSTR_CLAMPCYCLIC, + + EXPP_CONSTR_XMIN, + EXPP_CONSTR_XMAX, + EXPP_CONSTR_YMIN, + EXPP_CONSTR_YMAX, + EXPP_CONSTR_ZMIN, + EXPP_CONSTR_ZMAX, + + EXPP_CONSTR_SCRIPT, + EXPP_CONSTR_PROPS, + + EXPP_CONSTR_FROM, + EXPP_CONSTR_TO, + EXPP_CONSTR_EXPO, + EXPP_CONSTR_FROMMINX, + EXPP_CONSTR_FROMMAXX, + EXPP_CONSTR_FROMMINY, + EXPP_CONSTR_FROMMAXY, + EXPP_CONSTR_FROMMINZ, + EXPP_CONSTR_FROMMAXZ, + EXPP_CONSTR_TOMINX, + EXPP_CONSTR_TOMAXX, + EXPP_CONSTR_TOMINY, + EXPP_CONSTR_TOMAXY, + EXPP_CONSTR_TOMINZ, + EXPP_CONSTR_TOMAXZ, + EXPP_CONSTR_MAPX, + EXPP_CONSTR_MAPY, + EXPP_CONSTR_MAPZ, + + EXPP_CONSTR_OWNSPACE, + EXPP_CONSTR_TARSPACE, + + EXPP_CONSTR_RB_TYPE, + EXPP_CONSTR_RB_BALL, + EXPP_CONSTR_RB_HINGE, + EXPP_CONSTR_RB_GENERIC6DOF, + EXPP_CONSTR_RB_VEHICLE, + EXPP_CONSTR_RB_PIVX, + EXPP_CONSTR_RB_PIVY, + EXPP_CONSTR_RB_PIVZ, + EXPP_CONSTR_RB_AXX, + EXPP_CONSTR_RB_AXY, + EXPP_CONSTR_RB_AXZ, + EXPP_CONSTR_RB_MINLIMIT0, + EXPP_CONSTR_RB_MINLIMIT1, + EXPP_CONSTR_RB_MINLIMIT2, + EXPP_CONSTR_RB_MINLIMIT3, + EXPP_CONSTR_RB_MINLIMIT4, + EXPP_CONSTR_RB_MINLIMIT5, + EXPP_CONSTR_RB_MAXLIMIT0, + EXPP_CONSTR_RB_MAXLIMIT1, + EXPP_CONSTR_RB_MAXLIMIT2, + EXPP_CONSTR_RB_MAXLIMIT3, + EXPP_CONSTR_RB_MAXLIMIT4, + EXPP_CONSTR_RB_MAXLIMIT5, + EXPP_CONSTR_RB_EXTRAFZ, + EXPP_CONSTR_RB_FLAG, + +}; + +/*****************************************************************************/ +/* Python BPy_Constraint methods declarations: */ +/*****************************************************************************/ +static PyObject *Constraint_getName( BPy_Constraint * self ); +static int Constraint_setName( BPy_Constraint * self, PyObject *arg ); +static PyObject *Constraint_getType( BPy_Constraint * self ); +static PyObject *Constraint_getInfluence( BPy_Constraint * self ); +static int Constraint_setInfluence( BPy_Constraint * self, PyObject * arg ); + +static PyObject *Constraint_insertKey( BPy_Constraint * self, PyObject * arg ); + +static PyObject *Constraint_getData( BPy_Constraint * self, PyObject * key ); +static int Constraint_setData( BPy_Constraint * self, PyObject * key, + PyObject * value ); + +/*****************************************************************************/ +/* Python BPy_Constraint methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_Constraint_methods[] = { + /* name, method, flags, doc */ + {"insertKey", ( PyCFunction ) Constraint_insertKey, METH_O, + "Insert influence keyframe for constraint"}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python BPy_Constraint attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef BPy_Constraint_getseters[] = { + {"name", + (getter)Constraint_getName, (setter)Constraint_setName, + "Constraint name", NULL}, + {"type", + (getter)Constraint_getType, (setter)NULL, + "Constraint type (read only)", NULL}, + {"influence", + (getter)Constraint_getInfluence, (setter)Constraint_setInfluence, + "Constraint influence", NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/*****************************************************************************/ +/* Python Constraint_Type Mapping Methods table: */ +/*****************************************************************************/ +static PyMappingMethods Constraint_as_mapping = { + NULL, /* mp_length */ + ( binaryfunc ) Constraint_getData, /* mp_subscript */ + ( objobjargproc ) Constraint_setData, /* mp_ass_subscript */ +}; + +/*****************************************************************************/ +/* Python Constraint_Type callback function prototypes: */ +/*****************************************************************************/ +static PyObject *Constraint_repr( BPy_Constraint * self ); +static int Constraint_compare( BPy_Constraint * a, BPy_Constraint * b ); + +/*****************************************************************************/ +/* Python Constraint_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject Constraint_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender Constraint", /* char *tp_name; */ + sizeof( BPy_Constraint ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) Constraint_compare, /* cmpfunc tp_compare; */ + ( reprfunc ) Constraint_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + &Constraint_as_mapping, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_Constraint_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_Constraint_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +/*****************************************************************************/ +/* Python BPy_Constraint methods: */ +/*****************************************************************************/ + +/* + * return the name of this constraint + */ + +static PyObject *Constraint_getName( BPy_Constraint * self ) +{ + if( !self->con ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This constraint has been removed!" ); + + return PyString_FromString( self->con->name ); +} + +/* + * set the name of this constraint + */ + +static int Constraint_setName( BPy_Constraint * self, PyObject * attr ) +{ + char *name = PyString_AsString( attr ); + if( !name ) + return EXPP_ReturnIntError( PyExc_TypeError, "expected string arg" ); + + if( !self->con ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "This constraint has been removed!" ); + + BLI_strncpy( self->con->name, name, sizeof( self->con->name ) ); + + return 0; +} + +/* + * return the influence of this constraint + */ + +static PyObject *Constraint_getInfluence( BPy_Constraint * self ) +{ + if( !self->con ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This constraint has been removed!" ); + + return PyFloat_FromDouble( (double)self->con->enforce ); +} + +/* + * set the influence of this constraint + */ + +static int Constraint_setInfluence( BPy_Constraint * self, PyObject * value ) +{ + if( !self->con ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "This constraint has been removed!" ); + + return EXPP_setFloatClamped( value, &self->con->enforce, 0.0, 1.0 ); +} + +/* + * return the type of this constraint + */ + +static PyObject *Constraint_getType( BPy_Constraint * self ) +{ + if( !self->con ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This constraint has been removed!" ); + + return PyInt_FromLong( self->con->type ); +} + +/* + * add keyframe for influence + base on code in add_influence_key_to_constraint_func() + */ +static PyObject *Constraint_insertKey( BPy_Constraint * self, PyObject * value ) +{ + IpoCurve *icu; + float cfra = (float)PyFloat_AsDouble(value); + char actname[32] = ""; + Object *ob = self->obj; + bConstraint *con = self->con; + + if( !self->con ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This constraint has been removed!" ); + + /* get frame for inserting key */ + if( PyFloat_Check(value) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a float argument" ); + + /* constraint_active_func(ob_v, con_v); */ + get_constraint_ipo_context( ob, actname ); + icu= verify_ipocurve((ID *)ob, ID_CO, actname, con->name, CO_ENFORCE); + + if (!icu) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "cannot get a curve from this IPO, may be using libdata" ); + + if( ob->action ) + insert_vert_icu( icu, get_action_frame(ob, cfra), con->enforce, 0); + else + insert_vert_icu( icu, cfra, con->enforce, 0); + + Py_RETURN_NONE; +} + +/******************************************************************************/ +/* Constraint Space Conversion get/set procedures */ +/* - These are called before/instead of individual constraint */ +/* get/set procedures when OWNERSPACE or TARGETSPACE are chosen */ +/* - They are only called from Constraint_g/setData */ +/******************************************************************************/ + +static PyObject *constspace_getter( BPy_Constraint * self, int type ) +{ + bConstraint *con= (bConstraint *)(self->con); + + /* depends on type being asked for + * NOTE: not all constraints support all space types + */ + if (type == EXPP_CONSTR_OWNSPACE) { + switch (con->type) { + /* all of these support this... */ + case CONSTRAINT_TYPE_PYTHON: + case CONSTRAINT_TYPE_LOCLIKE: + case CONSTRAINT_TYPE_ROTLIKE: + case CONSTRAINT_TYPE_SIZELIKE: + case CONSTRAINT_TYPE_TRACKTO: + case CONSTRAINT_TYPE_LOCLIMIT: + case CONSTRAINT_TYPE_ROTLIMIT: + case CONSTRAINT_TYPE_SIZELIMIT: + case CONSTRAINT_TYPE_TRANSFORM: + return PyInt_FromLong( (long)con->ownspace ); + } + } + else if (type == EXPP_CONSTR_TARSPACE) { + switch (con->type) { + /* all of these support this... */ + case CONSTRAINT_TYPE_PYTHON: + case CONSTRAINT_TYPE_ACTION: + case CONSTRAINT_TYPE_LOCLIKE: + case CONSTRAINT_TYPE_ROTLIKE: + case CONSTRAINT_TYPE_SIZELIKE: + case CONSTRAINT_TYPE_TRACKTO: + case CONSTRAINT_TYPE_TRANSFORM: + return PyInt_FromLong( (long)con->tarspace ); + } + } + + /* raise error if failed */ + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); +} + +static int constspace_setter( BPy_Constraint *self, int type, PyObject *value ) +{ + bConstraint *con= (bConstraint *)(self->con); + + /* depends on type being asked for + * NOTE: not all constraints support all space types + */ + if (type == EXPP_CONSTR_OWNSPACE) { + switch (con->type) { + /* all of these support this... */ + case CONSTRAINT_TYPE_PYTHON: + case CONSTRAINT_TYPE_LOCLIKE: + case CONSTRAINT_TYPE_ROTLIKE: + case CONSTRAINT_TYPE_SIZELIKE: + case CONSTRAINT_TYPE_TRACKTO: + case CONSTRAINT_TYPE_LOCLIMIT: + case CONSTRAINT_TYPE_ROTLIMIT: + case CONSTRAINT_TYPE_SIZELIMIT: + case CONSTRAINT_TYPE_TRANSFORM: + { + /* only copy depending on ownertype */ + if (self->pchan) { + return EXPP_setIValueClamped( value, &con->ownspace, + CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_PARLOCAL, 'h' ); + } + else { + return EXPP_setIValueClamped( value, &con->ownspace, + CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, 'h' ); + } + } + break; + } + } + else if (type == EXPP_CONSTR_TARSPACE) { + switch (con->type) { + /* all of these support this... */ + case CONSTRAINT_TYPE_PYTHON: + case CONSTRAINT_TYPE_ACTION: + case CONSTRAINT_TYPE_LOCLIKE: + case CONSTRAINT_TYPE_ROTLIKE: + case CONSTRAINT_TYPE_SIZELIKE: + case CONSTRAINT_TYPE_TRACKTO: + case CONSTRAINT_TYPE_TRANSFORM: + { + Object *tar; + char *subtarget; + + // FIXME!!! + //tar= get_constraint_target(con, &subtarget); + tar = NULL; + subtarget = NULL; + + /* only copy depending on target-type */ + if (tar && subtarget[0]) { + return EXPP_setIValueClamped( value, &con->tarspace, + CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_PARLOCAL, 'h' ); + } + else if (tar) { + return EXPP_setIValueClamped( value, &con->tarspace, + CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, 'h' ); + } + } + break; + } + } + + /* raise error if failed */ + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); +} + +/*****************************************************************************/ +/* Specific constraint get/set procedures */ +/*****************************************************************************/ + +static PyObject *kinematic_getter( BPy_Constraint * self, int type ) +{ + bKinematicConstraint *con = (bKinematicConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: + return Object_CreatePyObject( con->tar ); + case EXPP_CONSTR_BONE: + return PyString_FromString( con->subtarget ); + case EXPP_CONSTR_STRETCH: + return PyBool_FromLong( (long)( con->flag & CONSTRAINT_IK_STRETCH ) ) ; + case EXPP_CONSTR_ITERATIONS: + return PyInt_FromLong( (long)con->iterations ); + case EXPP_CONSTR_CHAINLEN: + return PyInt_FromLong( (long)con->rootbone ); + case EXPP_CONSTR_POSWEIGHT: + return PyFloat_FromDouble( (double)con->weight ); + case EXPP_CONSTR_ROTWEIGHT: + return PyFloat_FromDouble( (double)con->orientweight ); + case EXPP_CONSTR_ROTATE: + return PyBool_FromLong( (long)( con->flag & CONSTRAINT_IK_ROT ) ) ; + case EXPP_CONSTR_USETIP: + return PyBool_FromLong( (long)( con->flag & CONSTRAINT_IK_TIP ) ) ; + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int kinematic_setter( BPy_Constraint *self, int type, PyObject *value ) +{ + bKinematicConstraint *con = (bKinematicConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: { + Object *obj = (( BPy_Object * )value)->object; + if( !BPy_Object_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected BPy object argument" ); + con->tar = obj; + return 0; + } + case EXPP_CONSTR_BONE: { + char *name = PyString_AsString( value ); + if( !name ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected string arg" ); + + BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) ); + + return 0; + } + case EXPP_CONSTR_STRETCH: + return EXPP_setBitfield( value, &con->flag, CONSTRAINT_IK_STRETCH, 'h' ); + case EXPP_CONSTR_ITERATIONS: + return EXPP_setIValueClamped( value, &con->iterations, 1, 10000, 'h' ); + case EXPP_CONSTR_CHAINLEN: + return EXPP_setIValueClamped( value, &con->rootbone, 0, 255, 'i' ); + case EXPP_CONSTR_POSWEIGHT: + return EXPP_setFloatClamped( value, &con->weight, 0.01f, 1.0 ); + case EXPP_CONSTR_ROTWEIGHT: + return EXPP_setFloatClamped( value, &con->orientweight, 0.01f, 1.0 ); + case EXPP_CONSTR_ROTATE: + return EXPP_setBitfield( value, &con->flag, CONSTRAINT_IK_ROT, 'h' ); + case EXPP_CONSTR_USETIP: + return EXPP_setBitfield( value, &con->flag, CONSTRAINT_IK_TIP, 'h' ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *action_getter( BPy_Constraint * self, int type ) +{ + bActionConstraint *con = (bActionConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: + return Object_CreatePyObject( con->tar ); + case EXPP_CONSTR_BONE: + return PyString_FromString( con->subtarget ); + case EXPP_CONSTR_ACTION: + return Action_CreatePyObject( con->act ); + case EXPP_CONSTR_START: + return PyInt_FromLong( (long)con->start ); + case EXPP_CONSTR_END: + return PyInt_FromLong( (long)con->end ); + case EXPP_CONSTR_MIN: + return PyFloat_FromDouble( (double)con->min ); + case EXPP_CONSTR_MAX: + return PyFloat_FromDouble( (double)con->max ); + case EXPP_CONSTR_KEYON: + return PyInt_FromLong( (long)con->type ); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int action_setter( BPy_Constraint *self, int type, PyObject *value ) +{ + bActionConstraint *con = (bActionConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: { + Object *obj = (( BPy_Object * )value)->object; + if( !BPy_Object_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected BPy object argument" ); + con->tar = obj; + return 0; + } + case EXPP_CONSTR_BONE: { + char *name = PyString_AsString( value ); + if( !name ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected string arg" ); + + BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) ); + + return 0; + } + case EXPP_CONSTR_ACTION: { + bAction *act = (( BPy_Action * )value)->action; + if( !BPy_Action_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected BPy action argument" ); + con->act = act; + return 0; + } + case EXPP_CONSTR_START: + return EXPP_setIValueClamped( value, &con->start, 1, MAXFRAME, 'h' ); + case EXPP_CONSTR_END: + return EXPP_setIValueClamped( value, &con->end, 1, MAXFRAME, 'h' ); + case EXPP_CONSTR_MIN: + if (con->type < 10) + return EXPP_setFloatClamped( value, &con->min, -180.0, 180.0 ); + else if (con->type < 20) + return EXPP_setFloatClamped( value, &con->min, 0.0001, 1000.0 ); + else + return EXPP_setFloatClamped( value, &con->min, -1000.0, 1000.0 ); + case EXPP_CONSTR_MAX: + if (con->type < 10) + return EXPP_setFloatClamped( value, &con->max, -180.0, 180.0 ); + else if (con->type < 20) + return EXPP_setFloatClamped( value, &con->max, 0.0001, 1000.0 ); + else + return EXPP_setFloatClamped( value, &con->max, -1000.0, 1000.0 ); + case EXPP_CONSTR_KEYON: + return EXPP_setIValueRange( value, &con->type, + EXPP_CONSTR_XROT, EXPP_CONSTR_ZLOC, 'h' ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *trackto_getter( BPy_Constraint * self, int type ) +{ + bTrackToConstraint *con = (bTrackToConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: + return Object_CreatePyObject( con->tar ); + case EXPP_CONSTR_BONE: + return PyString_FromString( con->subtarget ); + case EXPP_CONSTR_TRACK: + return PyInt_FromLong( (long)con->reserved1 ); + case EXPP_CONSTR_UP: + return PyInt_FromLong( (long)con->reserved2 ); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int trackto_setter( BPy_Constraint *self, int type, PyObject *value ) +{ + bTrackToConstraint *con = (bTrackToConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: { + Object *obj = (( BPy_Object * )value)->object; + if( !BPy_Object_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected BPy object argument" ); + con->tar = obj; + return 0; + } + case EXPP_CONSTR_BONE: { + char *name = PyString_AsString( value ); + if( !name ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected string arg" ); + + BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) ); + + return 0; + } + case EXPP_CONSTR_TRACK: + return EXPP_setIValueRange( value, &con->reserved1, + TRACK_X, TRACK_nZ, 'i' ); + case EXPP_CONSTR_UP: + return EXPP_setIValueRange( value, &con->reserved2, + UP_X, UP_Z, 'i' ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *stretchto_getter( BPy_Constraint * self, int type ) +{ + bStretchToConstraint *con = (bStretchToConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: + return Object_CreatePyObject( con->tar ); + case EXPP_CONSTR_BONE: + return PyString_FromString( con->subtarget ); + case EXPP_CONSTR_RESTLENGTH: + return PyFloat_FromDouble( (double)con->orglength ); + case EXPP_CONSTR_VOLVARIATION: + return PyFloat_FromDouble( (double)con->bulge ); + case EXPP_CONSTR_VOLUMEMODE: + return PyInt_FromLong( (long)con->volmode ); + case EXPP_CONSTR_PLANE: + return PyInt_FromLong( (long)con->plane ); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int stretchto_setter( BPy_Constraint *self, int type, PyObject *value ) +{ + bStretchToConstraint *con = (bStretchToConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: { + Object *obj = (( BPy_Object * )value)->object; + if( !BPy_Object_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected BPy object argument" ); + con->tar = obj; + return 0; + } + case EXPP_CONSTR_BONE: { + char *name = PyString_AsString( value ); + if( !name ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected string arg" ); + + BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) ); + + return 0; + } + case EXPP_CONSTR_RESTLENGTH: + return EXPP_setFloatClamped( value, &con->orglength, 0.0, 100.0 ); + case EXPP_CONSTR_VOLVARIATION: + return EXPP_setFloatClamped( value, &con->bulge, 0.0, 100.0 ); + case EXPP_CONSTR_VOLUMEMODE: + return EXPP_setIValueRange( value, &con->volmode, + VOLUME_XZ, NO_VOLUME, 'h' ); + case EXPP_CONSTR_PLANE: { + int status, oldcode = con->plane; + status = EXPP_setIValueRange( value, &con->plane, + PLANE_X, PLANE_Z, 'h' ); + if( !status && con->plane == PLANE_Y ) { + con->plane = oldcode; + return EXPP_ReturnIntError( PyExc_ValueError, + "value must be either PLANEX or PLANEZ" ); + } + return status; + } + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *followpath_getter( BPy_Constraint * self, int type ) +{ + bFollowPathConstraint *con = (bFollowPathConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: + return Object_CreatePyObject( con->tar ); + case EXPP_CONSTR_FOLLOW: + return PyBool_FromLong( (long)( con->followflag & SELECT ) ); + case EXPP_CONSTR_OFFSET: + return PyFloat_FromDouble( (double)con->offset ); + case EXPP_CONSTR_FORWARD: + return PyInt_FromLong( (long)con->trackflag ); + case EXPP_CONSTR_UP: + return PyInt_FromLong( (long)con->upflag ); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int followpath_setter( BPy_Constraint *self, int type, PyObject *value ) +{ + bFollowPathConstraint *con = (bFollowPathConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: { + Object *obj = (( BPy_Object * )value)->object; + if( !BPy_Object_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected BPy object argument" ); + con->tar = obj; + return 0; + } + case EXPP_CONSTR_FOLLOW: + return EXPP_setBitfield( value, &con->followflag, SELECT, 'i' ); + case EXPP_CONSTR_OFFSET: + return EXPP_setFloatClamped( value, &con->offset, + -MAXFRAMEF, MAXFRAMEF ); + case EXPP_CONSTR_FORWARD: + return EXPP_setIValueRange( value, &con->trackflag, + TRACK_X, TRACK_nZ, 'i' ); + case EXPP_CONSTR_UP: + return EXPP_setIValueRange( value, &con->upflag, + UP_X, UP_Z, 'i' ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *clampto_getter( BPy_Constraint * self, int type ) +{ + bClampToConstraint *con = (bClampToConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: + return Object_CreatePyObject( con->tar ); + case EXPP_CONSTR_CLAMP: + return PyInt_FromLong( (long)con->flag ); + case EXPP_CONSTR_CLAMPCYCLIC: + return PyBool_FromLong( (long)(con->flag2 & CLAMPTO_CYCLIC) ); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int clampto_setter( BPy_Constraint *self, int type, PyObject *value ) +{ + bClampToConstraint *con = (bClampToConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: { + Object *obj = (( BPy_Object * )value)->object; + if( !BPy_Object_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected BPy object argument" ); + con->tar = obj; + return 0; + } + case EXPP_CONSTR_CLAMP: + return EXPP_setIValueRange( value, &con->flag, + CLAMPTO_AUTO, CLAMPTO_Z, 'i' ); + case EXPP_CONSTR_CLAMPCYCLIC: + return EXPP_setBitfield( value, &con->flag2, CLAMPTO_CYCLIC, 'i' ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} +static PyObject *locktrack_getter( BPy_Constraint * self, int type ) +{ + bLockTrackConstraint *con = (bLockTrackConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: + return Object_CreatePyObject( con->tar ); + case EXPP_CONSTR_BONE: + return PyString_FromString( con->subtarget ); + case EXPP_CONSTR_TRACK: + return PyInt_FromLong( (long)con->trackflag ); + case EXPP_CONSTR_LOCK: + return PyInt_FromLong( (long)con->lockflag ); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int locktrack_setter( BPy_Constraint *self, int type, PyObject *value ) +{ + bLockTrackConstraint *con = (bLockTrackConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: { + Object *obj = (( BPy_Object * )value)->object; + if( !BPy_Object_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected BPy object argument" ); + con->tar = obj; + return 0; + } + case EXPP_CONSTR_BONE: { + char *name = PyString_AsString( value ); + if( !name ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected string arg" ); + + BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) ); + + return 0; + } + case EXPP_CONSTR_TRACK: + return EXPP_setIValueRange( value, &con->trackflag, + TRACK_X, TRACK_nZ, 'i' ); + case EXPP_CONSTR_LOCK: + return EXPP_setIValueRange( value, &con->lockflag, + LOCK_X, LOCK_Z, 'i' ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *floor_getter( BPy_Constraint * self, int type ) +{ + bMinMaxConstraint *con = (bMinMaxConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: + return Object_CreatePyObject( con->tar ); + case EXPP_CONSTR_BONE: + return PyString_FromString( con->subtarget ); + case EXPP_CONSTR_MINMAX: + return PyInt_FromLong( (long)con->minmaxflag ); + case EXPP_CONSTR_OFFSET: + return PyFloat_FromDouble( (double)con->offset ); + case EXPP_CONSTR_STICKY: + return PyBool_FromLong( (long)( con->flag & MINMAX_STICKY ) ) ; + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int floor_setter( BPy_Constraint *self, int type, PyObject *value ) +{ + bMinMaxConstraint *con = (bMinMaxConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: { + Object *obj = (( BPy_Object * )value)->object; + if( !BPy_Object_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected BPy object argument" ); + con->tar = obj; + return 0; + } + case EXPP_CONSTR_BONE: { + char *name = PyString_AsString( value ); + if( !name ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected string arg" ); + + BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) ); + + return 0; + } + case EXPP_CONSTR_MINMAX: + return EXPP_setIValueRange( value, &con->minmaxflag, + EXPP_CONSTR_MAXX, EXPP_CONSTR_MINZ, 'i' ); + case EXPP_CONSTR_OFFSET: + return EXPP_setFloatClamped( value, &con->offset, -100.0, 100.0 ); + case EXPP_CONSTR_STICKY: + return EXPP_setBitfield( value, &con->flag, MINMAX_STICKY, 'h' ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *locatelike_getter( BPy_Constraint * self, int type ) +{ + bLocateLikeConstraint *con = (bLocateLikeConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: + return Object_CreatePyObject( con->tar ); + case EXPP_CONSTR_BONE: + return PyString_FromString( con->subtarget ); + case EXPP_CONSTR_COPY: + return PyInt_FromLong( (long)con->flag ); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int locatelike_setter( BPy_Constraint *self, int type, PyObject *value ) +{ + bLocateLikeConstraint *con = (bLocateLikeConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: { + Object *obj = (( BPy_Object * )value)->object; + if( !BPy_Object_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected BPy object argument" ); + con->tar = obj; + return 0; + } + case EXPP_CONSTR_BONE: { + char *name = PyString_AsString( value ); + if( !name ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected string arg" ); + + BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) ); + + return 0; + } + case EXPP_CONSTR_COPY: + return EXPP_setIValueRange( value, &con->flag, + 0, LOCLIKE_X | LOCLIKE_Y | LOCLIKE_Z | LOCLIKE_X_INVERT | LOCLIKE_Y_INVERT | LOCLIKE_Z_INVERT, 'i' ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *rotatelike_getter( BPy_Constraint * self, int type ) +{ + bRotateLikeConstraint *con = (bRotateLikeConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: + return Object_CreatePyObject( con->tar ); + case EXPP_CONSTR_BONE: + return PyString_FromString( con->subtarget ); + case EXPP_CONSTR_COPY: + return PyInt_FromLong( (long)con->flag ); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int rotatelike_setter( BPy_Constraint *self, int type, PyObject *value ) +{ + bRotateLikeConstraint *con = (bRotateLikeConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: { + Object *obj = (( BPy_Object * )value)->object; + if( !BPy_Object_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected BPy object argument" ); + con->tar = obj; + return 0; + } + case EXPP_CONSTR_BONE: { + char *name = PyString_AsString( value ); + if( !name ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected string arg" ); + + BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) ); + + return 0; + } + case EXPP_CONSTR_COPY: + return EXPP_setIValueRange( value, &con->flag, + 0, ROTLIKE_X | ROTLIKE_Y | ROTLIKE_Z | ROTLIKE_X_INVERT | ROTLIKE_Y_INVERT | ROTLIKE_Z_INVERT, 'i' ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *sizelike_getter( BPy_Constraint * self, int type ) +{ + bSizeLikeConstraint *con = (bSizeLikeConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: + return Object_CreatePyObject( con->tar ); + case EXPP_CONSTR_BONE: + return PyString_FromString( con->subtarget ); + case EXPP_CONSTR_COPY: + return PyInt_FromLong( (long)con->flag ); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int sizelike_setter( BPy_Constraint *self, int type, PyObject *value ) +{ + bSizeLikeConstraint *con = (bSizeLikeConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: { + Object *obj = (( BPy_Object * )value)->object; + if( !BPy_Object_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected BPy object argument" ); + con->tar = obj; + return 0; + } + case EXPP_CONSTR_BONE: { + char *name = PyString_AsString( value ); + if( !name ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected string arg" ); + + BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) ); + + return 0; + } + case EXPP_CONSTR_COPY: + return EXPP_setIValueRange( value, &con->flag, + 0, SIZELIKE_X | SIZELIKE_Y | SIZELIKE_Z, 'i' ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *loclimit_getter( BPy_Constraint * self, int type) +{ + bLocLimitConstraint *con = (bLocLimitConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_LIMIT: + return PyInt_FromLong( (long)con->flag ); + case EXPP_CONSTR_XMIN: + return PyFloat_FromDouble( (double)con->xmin ); + case EXPP_CONSTR_XMAX: + return PyFloat_FromDouble( (double)con->xmax ); + case EXPP_CONSTR_YMIN: + return PyFloat_FromDouble( (double)con->ymin ); + case EXPP_CONSTR_YMAX: + return PyFloat_FromDouble( (double)con->ymax ); + case EXPP_CONSTR_ZMIN: + return PyFloat_FromDouble( (double)con->zmin ); + case EXPP_CONSTR_ZMAX: + return PyFloat_FromDouble( (double)con->zmax ); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int loclimit_setter( BPy_Constraint *self, int type, PyObject *value ) +{ + bLocLimitConstraint *con = (bLocLimitConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_LIMIT: + return EXPP_setIValueRange( value, &con->flag, 0, + LIMIT_XMIN | LIMIT_XMAX | LIMIT_YMIN | LIMIT_YMAX | LIMIT_ZMIN | LIMIT_ZMAX , 'i' ); + case EXPP_CONSTR_XMIN: + return EXPP_setFloatClamped( value, &con->xmin, -1000.0, 1000.0 ); + case EXPP_CONSTR_XMAX: + return EXPP_setFloatClamped( value, &con->xmax, -1000.0, 1000.0 ); + case EXPP_CONSTR_YMIN: + return EXPP_setFloatClamped( value, &con->ymin, -1000.0, 1000.0 ); + case EXPP_CONSTR_YMAX: + return EXPP_setFloatClamped( value, &con->ymax, -1000.0, 1000.0 ); + case EXPP_CONSTR_ZMIN: + return EXPP_setFloatClamped( value, &con->zmin, -1000.0, 1000.0 ); + case EXPP_CONSTR_ZMAX: + return EXPP_setFloatClamped( value, &con->zmax, -1000.0, 1000.0 ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *rotlimit_getter( BPy_Constraint * self, int type ) +{ + bRotLimitConstraint *con = (bRotLimitConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_LIMIT: + return PyInt_FromLong( (long)con->flag ); + case EXPP_CONSTR_XMIN: + return PyFloat_FromDouble( (double)con->xmin ); + case EXPP_CONSTR_XMAX: + return PyFloat_FromDouble( (double)con->xmax ); + case EXPP_CONSTR_YMIN: + return PyFloat_FromDouble( (double)con->ymin ); + case EXPP_CONSTR_YMAX: + return PyFloat_FromDouble( (double)con->ymax ); + case EXPP_CONSTR_ZMIN: + return PyFloat_FromDouble( (double)con->zmin ); + case EXPP_CONSTR_ZMAX: + return PyFloat_FromDouble( (double)con->zmax ); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int rotlimit_setter( BPy_Constraint *self, int type, PyObject *value ) +{ + bRotLimitConstraint *con = (bRotLimitConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_LIMIT: + return EXPP_setIValueRange( value, &con->flag, 0, + LIMIT_XROT | LIMIT_YROT | LIMIT_ZROT, 'i' ); + case EXPP_CONSTR_XMIN: + return EXPP_setFloatClamped( value, &con->xmin, -360.0, 360.0 ); + case EXPP_CONSTR_XMAX: + return EXPP_setFloatClamped( value, &con->xmax, -360.0, 360.0 ); + case EXPP_CONSTR_YMIN: + return EXPP_setFloatClamped( value, &con->ymin, -360.0, 360.0 ); + case EXPP_CONSTR_YMAX: + return EXPP_setFloatClamped( value, &con->ymax, -360.0, 360.0 ); + case EXPP_CONSTR_ZMIN: + return EXPP_setFloatClamped( value, &con->zmin, -360.0, 360.0 ); + case EXPP_CONSTR_ZMAX: + return EXPP_setFloatClamped( value, &con->zmax, -360.0, 360.0 ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *sizelimit_getter( BPy_Constraint * self, int type) +{ + bSizeLimitConstraint *con = (bSizeLimitConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_LIMIT: + return PyInt_FromLong( (long)con->flag ); + case EXPP_CONSTR_XMIN: + return PyFloat_FromDouble( (double)con->xmin ); + case EXPP_CONSTR_XMAX: + return PyFloat_FromDouble( (double)con->xmax ); + case EXPP_CONSTR_YMIN: + return PyFloat_FromDouble( (double)con->ymin ); + case EXPP_CONSTR_YMAX: + return PyFloat_FromDouble( (double)con->ymax ); + case EXPP_CONSTR_ZMIN: + return PyFloat_FromDouble( (double)con->zmin ); + case EXPP_CONSTR_ZMAX: + return PyFloat_FromDouble( (double)con->zmax ); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int sizelimit_setter( BPy_Constraint *self, int type, PyObject *value ) +{ + bSizeLimitConstraint *con = (bSizeLimitConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_LIMIT: + return EXPP_setIValueRange( value, &con->flag, 0, + LIMIT_XMIN | LIMIT_XMAX | LIMIT_YMIN | LIMIT_YMAX | LIMIT_ZMIN | LIMIT_ZMAX, 'i' ); + case EXPP_CONSTR_XMIN: + return EXPP_setFloatClamped( value, &con->xmin, -1000.0, 1000.0 ); + case EXPP_CONSTR_XMAX: + return EXPP_setFloatClamped( value, &con->xmax, -1000.0, 1000.0 ); + case EXPP_CONSTR_YMIN: + return EXPP_setFloatClamped( value, &con->ymin, -1000.0, 1000.0 ); + case EXPP_CONSTR_YMAX: + return EXPP_setFloatClamped( value, &con->ymax, -1000.0, 1000.0 ); + case EXPP_CONSTR_ZMIN: + return EXPP_setFloatClamped( value, &con->zmin, -1000.0, 1000.0 ); + case EXPP_CONSTR_ZMAX: + return EXPP_setFloatClamped( value, &con->zmax, -1000.0, 1000.0 ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *script_getter( BPy_Constraint * self, int type ) +{ + bPythonConstraint *con = (bPythonConstraint *)(self->con->data); + + switch( type ) { + // FIXME!!! + //case EXPP_CONSTR_TARGET: + // return Object_CreatePyObject( con->tar ); + //case EXPP_CONSTR_BONE: + // return PyString_FromString( con->subtarget ); + case EXPP_CONSTR_SCRIPT: + return Text_CreatePyObject( con->text ); + case EXPP_CONSTR_PROPS: + return BPy_Wrap_IDProperty( NULL, con->prop, NULL); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int script_setter( BPy_Constraint *self, int type, PyObject *value ) +{ + bPythonConstraint *con = (bPythonConstraint *)(self->con->data); + + switch( type ) { + // FIXME!!! + //case EXPP_CONSTR_TARGET: { + // Object *obj = (( BPy_Object * )value)->object; + // if( !BPy_Object_Check( value ) ) + // return EXPP_ReturnIntError( PyExc_TypeError, + // "expected BPy object argument" ); + // con->tar = obj; + // return 0; + // } + //case EXPP_CONSTR_BONE: { + // char *name = PyString_AsString( value ); + // if( !name ) + // return EXPP_ReturnIntError( PyExc_TypeError, + // "expected string arg" ); + // + // BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) ); + // + // return 0; + // } + case EXPP_CONSTR_SCRIPT: { + Text *text = (( BPy_Text * )value)->text; + if( !BPy_Object_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected BPy text argument" ); + con->text = text; + return 0; + } + case EXPP_CONSTR_PROPS: + return EXPP_ReturnIntError( PyExc_RuntimeError, + "setting ID-Properties of PyConstraints this way is not supported" ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + + +static PyObject *rigidbody_getter( BPy_Constraint * self, int type) +{ + bRigidBodyJointConstraint *con = (bRigidBodyJointConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: + return Object_CreatePyObject( con->tar ); + case EXPP_CONSTR_RB_PIVX: + return PyFloat_FromDouble( (double)con->pivX ); + case EXPP_CONSTR_RB_PIVY: + return PyFloat_FromDouble( (double)con->pivY ); + case EXPP_CONSTR_RB_PIVZ: + return PyFloat_FromDouble( (double)con->pivZ ); + case EXPP_CONSTR_RB_AXX: + return PyFloat_FromDouble( (double)con->axX ); + case EXPP_CONSTR_RB_AXY: + return PyFloat_FromDouble( (double)con->axY ); + case EXPP_CONSTR_RB_AXZ: + return PyFloat_FromDouble( (double)con->axZ ); + case EXPP_CONSTR_RB_MINLIMIT0: + return PyFloat_FromDouble( (double)con->minLimit[0] ); + case EXPP_CONSTR_RB_MINLIMIT1: + return PyFloat_FromDouble( (double)con->minLimit[1] ); + case EXPP_CONSTR_RB_MINLIMIT2: + return PyFloat_FromDouble( (double)con->minLimit[2] ); + case EXPP_CONSTR_RB_MINLIMIT3: + return PyFloat_FromDouble( (double)con->minLimit[3] ); + case EXPP_CONSTR_RB_MINLIMIT4: + return PyFloat_FromDouble( (double)con->minLimit[4] ); + case EXPP_CONSTR_RB_MINLIMIT5: + return PyFloat_FromDouble( (double)con->minLimit[5] ); + case EXPP_CONSTR_RB_MAXLIMIT0: + return PyFloat_FromDouble( (double)con->maxLimit[0] ); + case EXPP_CONSTR_RB_MAXLIMIT1: + return PyFloat_FromDouble( (double)con->maxLimit[1] ); + case EXPP_CONSTR_RB_MAXLIMIT2: + return PyFloat_FromDouble( (double)con->maxLimit[2] ); + case EXPP_CONSTR_RB_MAXLIMIT3: + return PyFloat_FromDouble( (double)con->maxLimit[3] ); + case EXPP_CONSTR_RB_MAXLIMIT4: + return PyFloat_FromDouble( (double)con->maxLimit[4] ); + case EXPP_CONSTR_RB_MAXLIMIT5: + return PyFloat_FromDouble( (double)con->maxLimit[5] ); + case EXPP_CONSTR_RB_EXTRAFZ: + return PyFloat_FromDouble( (double)con->extraFz ); + case EXPP_CONSTR_LIMIT: + return PyInt_FromLong( (int)con->flag ); + + case EXPP_CONSTR_RB_TYPE: + return PyInt_FromLong( (int)con->type ); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + + +static int rigidbody_setter( BPy_Constraint *self, int type, PyObject *value ) +{ + bRigidBodyJointConstraint *con = (bRigidBodyJointConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: { + Object *obj = (( BPy_Object * )value)->object; + if( !BPy_Object_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected BPy object argument" ); + con->tar = obj; + return 0; + } + case EXPP_CONSTR_RB_PIVX: + return EXPP_setFloatClamped( value, &con->pivX , -1000.0, 1000.0 ); + case EXPP_CONSTR_RB_PIVY: + return EXPP_setFloatClamped( value, &con->pivY , -1000.0, 1000.0 ); + case EXPP_CONSTR_RB_PIVZ: + return EXPP_setFloatClamped( value, &con->pivZ , -1000.0, 1000.0 ); + case EXPP_CONSTR_RB_AXX: + return EXPP_setFloatClamped( value, &con->axX , -1000.0, 1000.0 ); + case EXPP_CONSTR_RB_AXY: + return EXPP_setFloatClamped( value, &con->axY , -1000.0, 1000.0 ); + case EXPP_CONSTR_RB_AXZ: + return EXPP_setFloatClamped( value, &con->axZ , -1000.0, 1000.0 ); + case EXPP_CONSTR_RB_MINLIMIT0: + return EXPP_setFloatClamped( value, &con->minLimit[0] , -1000.0, 1000.0 ); + case EXPP_CONSTR_RB_MINLIMIT1: + return EXPP_setFloatClamped( value, &con->minLimit[1] , -1000.0, 1000.0 ); + case EXPP_CONSTR_RB_MINLIMIT2: + return EXPP_setFloatClamped( value, &con->minLimit[2] , -1000.0, 1000.0 ); + case EXPP_CONSTR_RB_MINLIMIT3: + return EXPP_setFloatClamped( value, &con->minLimit[3] , -1000.0, 1000.0 ); + case EXPP_CONSTR_RB_MINLIMIT4: + return EXPP_setFloatClamped( value, &con->minLimit[4] , -1000.0, 1000.0 ); + case EXPP_CONSTR_RB_MINLIMIT5: + return EXPP_setFloatClamped( value, &con->minLimit[5] , -1000.0, 1000.0 ); + case EXPP_CONSTR_RB_MAXLIMIT0: + return EXPP_setFloatClamped( value, &con->maxLimit[0] , -1000.0, 1000.0 ); + case EXPP_CONSTR_RB_MAXLIMIT1: + return EXPP_setFloatClamped( value, &con->maxLimit[1] , -1000.0, 1000.0 ); + case EXPP_CONSTR_RB_MAXLIMIT2: + return EXPP_setFloatClamped( value, &con->maxLimit[2] , -1000.0, 1000.0 ); + case EXPP_CONSTR_RB_MAXLIMIT3: + return EXPP_setFloatClamped( value, &con->maxLimit[3] , -1000.0, 1000.0 ); + case EXPP_CONSTR_RB_MAXLIMIT4: + return EXPP_setFloatClamped( value, &con->maxLimit[4] , -1000.0, 1000.0 ); + case EXPP_CONSTR_RB_MAXLIMIT5: + return EXPP_setFloatClamped( value, &con->maxLimit[5] , -1000.0, 1000.0 ); + case EXPP_CONSTR_RB_EXTRAFZ: + return EXPP_setFloatClamped( value, &con->extraFz , -1000.0, 1000.0 ); + case EXPP_CONSTR_LIMIT: + return EXPP_setIValueRange( value, &con->flag, 0, + LIMIT_XMIN | LIMIT_XMAX | LIMIT_YMIN | LIMIT_YMAX | LIMIT_ZMIN | LIMIT_ZMAX, 'i' ); + case EXPP_CONSTR_RB_TYPE: + return EXPP_setIValueRange( value, &con->type, 0, + EXPP_CONSTR_RB_BALL | EXPP_CONSTR_RB_HINGE | EXPP_CONSTR_RB_GENERIC6DOF | EXPP_CONSTR_RB_VEHICLE, 'i' ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *childof_getter( BPy_Constraint * self, int type ) +{ + bChildOfConstraint *con = (bChildOfConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: + return Object_CreatePyObject( con->tar ); + case EXPP_CONSTR_BONE: + return PyString_FromString( con->subtarget ); + case EXPP_CONSTR_COPY: + return PyInt_FromLong( (long)con->flag ); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int childof_setter( BPy_Constraint *self, int type, PyObject *value ) +{ + bChildOfConstraint *con = (bChildOfConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: { + Object *obj = (( BPy_Object * )value)->object; + if( !BPy_Object_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected BPy object argument" ); + con->tar = obj; + return 0; + } + case EXPP_CONSTR_BONE: { + char *name = PyString_AsString( value ); + if( !name ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected string arg" ); + + BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) ); + + return 0; + } + case EXPP_CONSTR_COPY: + return EXPP_setIValueRange( value, &con->flag, + 0, CHILDOF_LOCX| CHILDOF_LOCY | CHILDOF_LOCZ | CHILDOF_ROTX | CHILDOF_ROTY | CHILDOF_ROTZ | + CHILDOF_SIZEX |CHILDOF_SIZEY| CHILDOF_SIZEZ, 'i' ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *transf_getter( BPy_Constraint * self, int type ) +{ + bTransformConstraint *con = (bTransformConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: + return Object_CreatePyObject( con->tar ); + case EXPP_CONSTR_BONE: + return PyString_FromString( con->subtarget ); + case EXPP_CONSTR_FROM: + return PyInt_FromLong( (long)con->from ); + case EXPP_CONSTR_TO: + return PyInt_FromLong( (long)con->to ); + case EXPP_CONSTR_MAPX: + return PyInt_FromLong( (long)con->map[0] ); + case EXPP_CONSTR_MAPY: + return PyInt_FromLong( (long)con->map[1] ); + case EXPP_CONSTR_MAPZ: + return PyInt_FromLong( (long)con->map[2] ); + case EXPP_CONSTR_FROMMINX: + return PyFloat_FromDouble( (double)con->from_min[0] ); + case EXPP_CONSTR_FROMMAXX: + return PyFloat_FromDouble( (double)con->from_max[0] ); + case EXPP_CONSTR_FROMMINY: + return PyFloat_FromDouble( (double)con->from_min[1] ); + case EXPP_CONSTR_FROMMAXY: + return PyFloat_FromDouble( (double)con->from_max[1] ); + case EXPP_CONSTR_FROMMINZ: + return PyFloat_FromDouble( (double)con->from_min[2] ); + case EXPP_CONSTR_FROMMAXZ: + return PyFloat_FromDouble( (double)con->from_max[2] ); + case EXPP_CONSTR_TOMINX: + return PyFloat_FromDouble( (double)con->to_min[0] ); + case EXPP_CONSTR_TOMAXX: + return PyFloat_FromDouble( (double)con->to_max[0] ); + case EXPP_CONSTR_TOMINY: + return PyFloat_FromDouble( (double)con->to_min[1] ); + case EXPP_CONSTR_TOMAXY: + return PyFloat_FromDouble( (double)con->to_max[1] ); + case EXPP_CONSTR_TOMINZ: + return PyFloat_FromDouble( (double)con->to_min[2] ); + case EXPP_CONSTR_TOMAXZ: + return PyFloat_FromDouble( (double)con->to_max[2] ); + case EXPP_CONSTR_EXPO: + return PyBool_FromLong( (long)con->expo ); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int transf_setter( BPy_Constraint *self, int type, PyObject *value ) +{ + bTransformConstraint *con = (bTransformConstraint *)(self->con->data); + float fmin, fmax, tmin, tmax; + + if (con->from == 2) { + fmin = 0.0001; + fmax = 1000.0; + } + else if (con->from == 1) { + fmin = -360.0; + fmax = 360.0; + } + else { + fmin = -1000.0; + fmax = 1000.0; + } + + if (con->to == 2) { + tmin = 0.0001; + tmax = 1000.0; + } + else if (con->to == 1) { + tmin = -360.0; + tmax = 360.0; + } + else { + tmin = -1000.0; + tmax = 1000.0; + } + + switch( type ) { + case EXPP_CONSTR_TARGET: { + Object *obj = (( BPy_Object * )value)->object; + if( !BPy_Object_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected BPy object argument" ); + con->tar = obj; + return 0; + } + case EXPP_CONSTR_BONE: { + char *name = PyString_AsString( value ); + if( !name ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected string arg" ); + + BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) ); + + return 0; + } + case EXPP_CONSTR_FROM: + return EXPP_setIValueClamped( value, &con->from, 0, 3, 'h' ); + case EXPP_CONSTR_TO: + return EXPP_setIValueClamped( value, &con->to, 0, 3, 'h' ); + case EXPP_CONSTR_MAPX: + return EXPP_setIValueClamped( value, &con->map[0], 0, 3, 'h' ); + case EXPP_CONSTR_MAPY: + return EXPP_setIValueClamped( value, &con->map[1], 0, 3, 'h' ); + case EXPP_CONSTR_MAPZ: + return EXPP_setIValueClamped( value, &con->map[2], 0, 3, 'h' ); + case EXPP_CONSTR_FROMMINX: + return EXPP_setFloatClamped( value, &con->from_min[0], fmin, fmax ); + case EXPP_CONSTR_FROMMAXX: + return EXPP_setFloatClamped( value, &con->from_max[0], fmin, fmax ); + case EXPP_CONSTR_FROMMINY: + return EXPP_setFloatClamped( value, &con->from_min[1], fmin, fmax ); + case EXPP_CONSTR_FROMMAXY: + return EXPP_setFloatClamped( value, &con->from_max[1], fmin, fmax ); + case EXPP_CONSTR_FROMMINZ: + return EXPP_setFloatClamped( value, &con->from_min[2], fmin, fmax ); + case EXPP_CONSTR_FROMMAXZ: + return EXPP_setFloatClamped( value, &con->from_max[2], fmin, fmax ); + case EXPP_CONSTR_TOMINX: + return EXPP_setFloatClamped( value, &con->to_min[0], tmin, tmax ); + case EXPP_CONSTR_TOMAXX: + return EXPP_setFloatClamped( value, &con->to_max[0], tmin, tmax ); + case EXPP_CONSTR_TOMINY: + return EXPP_setFloatClamped( value, &con->to_min[1], tmin, tmax ); + case EXPP_CONSTR_TOMAXY: + return EXPP_setFloatClamped( value, &con->to_max[1], tmin, tmax ); + case EXPP_CONSTR_TOMINZ: + return EXPP_setFloatClamped( value, &con->to_min[2], tmin, tmax ); + case EXPP_CONSTR_TOMAXZ: + return EXPP_setFloatClamped( value, &con->to_max[2], tmin, tmax ); + case EXPP_CONSTR_EXPO: + return EXPP_setBitfield( value, &con->expo, 1, 'h' ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +/* + * get data from a constraint + */ + +static PyObject *Constraint_getData( BPy_Constraint * self, PyObject * key ) +{ + int setting; + + if( !PyInt_Check( key ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected an int arg" ); + + if( !self->con ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This constraint has been removed!" ); + + setting = PyInt_AsLong( key ); + + /* bypass doing settings of individual constraints, if we're just doing + * constraint space access-stuff + */ + if ((setting==EXPP_CONSTR_OWNSPACE) || (setting==EXPP_CONSTR_TARSPACE)) { + return constspace_getter( self, setting ); + } + switch( self->con->type ) { + case CONSTRAINT_TYPE_NULL: + Py_RETURN_NONE; + case CONSTRAINT_TYPE_TRACKTO: + return trackto_getter( self, setting ); + case CONSTRAINT_TYPE_KINEMATIC: + return kinematic_getter( self, setting ); + case CONSTRAINT_TYPE_FOLLOWPATH: + return followpath_getter( self, setting ); + case CONSTRAINT_TYPE_ACTION: + return action_getter( self, setting ); + case CONSTRAINT_TYPE_LOCKTRACK: + return locktrack_getter( self, setting ); + case CONSTRAINT_TYPE_STRETCHTO: + return stretchto_getter( self, setting ); + case CONSTRAINT_TYPE_MINMAX: + return floor_getter( self, setting ); + case CONSTRAINT_TYPE_LOCLIKE: + return locatelike_getter( self, setting ); + case CONSTRAINT_TYPE_ROTLIKE: + return rotatelike_getter( self, setting ); + case CONSTRAINT_TYPE_SIZELIKE: + return sizelike_getter( self, setting ); + case CONSTRAINT_TYPE_ROTLIMIT: + return rotlimit_getter( self, setting ); + case CONSTRAINT_TYPE_LOCLIMIT: + return loclimit_getter( self, setting ); + case CONSTRAINT_TYPE_SIZELIMIT: + return sizelimit_getter( self, setting ); + case CONSTRAINT_TYPE_RIGIDBODYJOINT: + return rigidbody_getter( self, setting ); + case CONSTRAINT_TYPE_CLAMPTO: + return clampto_getter( self, setting ); + case CONSTRAINT_TYPE_PYTHON: + return script_getter( self, setting ); + case CONSTRAINT_TYPE_CHILDOF: + return childof_getter( self, setting ); + case CONSTRAINT_TYPE_TRANSFORM: + return transf_getter( self, setting ); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, + "unknown constraint type" ); + } +} + +static int Constraint_setData( BPy_Constraint * self, PyObject * key, + PyObject * arg ) +{ + int key_int, result; + + if( !PyNumber_Check( key ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected an int arg" ); + if( !self->con ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "This constraint has been removed!" ); + + key_int = PyInt_AsLong( key ); + + /* bypass doing settings of individual constraints, if we're just doing + * constraint space access-stuff + */ + if ((key_int==EXPP_CONSTR_OWNSPACE) || (key_int==EXPP_CONSTR_TARSPACE)) { + result = constspace_setter( self, key_int, arg ); + } + else { + switch( self->con->type ) { + case CONSTRAINT_TYPE_KINEMATIC: + result = kinematic_setter( self, key_int, arg ); + break; + case CONSTRAINT_TYPE_ACTION: + result = action_setter( self, key_int, arg ); + break; + case CONSTRAINT_TYPE_TRACKTO: + result = trackto_setter( self, key_int, arg ); + break; + case CONSTRAINT_TYPE_STRETCHTO: + result = stretchto_setter( self, key_int, arg ); + break; + case CONSTRAINT_TYPE_FOLLOWPATH: + result = followpath_setter( self, key_int, arg ); + break; + case CONSTRAINT_TYPE_LOCKTRACK: + result = locktrack_setter( self, key_int, arg ); + break; + case CONSTRAINT_TYPE_MINMAX: + result = floor_setter( self, key_int, arg ); + break; + case CONSTRAINT_TYPE_LOCLIKE: + result = locatelike_setter( self, key_int, arg ); + break; + case CONSTRAINT_TYPE_ROTLIKE: + result = rotatelike_setter( self, key_int, arg ); + break; + case CONSTRAINT_TYPE_SIZELIKE: + result = sizelike_setter( self, key_int, arg ); + break; + case CONSTRAINT_TYPE_ROTLIMIT: + result = rotlimit_setter( self, key_int, arg ); + break; + case CONSTRAINT_TYPE_LOCLIMIT: + result = loclimit_setter( self, key_int, arg ); + break; + case CONSTRAINT_TYPE_SIZELIMIT: + result = sizelimit_setter( self, key_int, arg); + break; + case CONSTRAINT_TYPE_RIGIDBODYJOINT: + result = rigidbody_setter( self, key_int, arg); + break; + case CONSTRAINT_TYPE_CLAMPTO: + result = clampto_setter( self, key_int, arg); + break; + case CONSTRAINT_TYPE_PYTHON: + result = script_setter( self, key_int, arg); + break; + case CONSTRAINT_TYPE_CHILDOF: + result = childof_setter( self, key_int, arg); + break; + case CONSTRAINT_TYPE_TRANSFORM: + result = transf_setter( self, key_int, arg); + break; + case CONSTRAINT_TYPE_NULL: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + default: + return EXPP_ReturnIntError( PyExc_RuntimeError, + "unsupported constraint setting" ); + } + } + if( !result && self->pchan ) + update_pose_constraint_flags( self->obj->pose ); + return result; +} + +/*****************************************************************************/ +/* Function: Constraint_compare */ +/* Description: This compares 2 constraint python types, == or != only. */ +/*****************************************************************************/ +static int Constraint_compare( BPy_Constraint * a, BPy_Constraint * b ) +{ + return ( a->con == b->con ) ? 0 : -1; +} + +/*****************************************************************************/ +/* Function: Constraint_repr */ +/* Description: This is a callback function for the BPy_Constraint type. It */ +/* builds a meaningful string to represent constraint objects. */ +/*****************************************************************************/ + +static PyObject *Constraint_repr( BPy_Constraint * self ) +{ + bConstraintTypeInfo *cti; + + if (!self->con) + return PyString_FromString("[Constraint - Removed]"); + else + cti= constraint_get_typeinfo(self->con); + + if (cti) { + return PyString_FromFormat("[Constraint \"%s\", Type \"%s\"]", + self->con->name, cti->name); + } + else { + return PyString_FromString("[Constraint \"%s\", Type \"Unknown\"]"); + } +} + +/* Three Python Constraint_Type helper functions needed by the Object module: */ + +/*****************************************************************************/ +/* Function: Constraint_CreatePyObject */ +/* Description: This function will create a new BPy_Constraint from an */ +/* existing Blender constraint structure. */ +/*****************************************************************************/ +PyObject *Constraint_CreatePyObject( bPoseChannel *pchan, Object *obj, + bConstraint *con ) +{ + BPy_Constraint *pycon; + pycon = ( BPy_Constraint * ) PyObject_NEW( BPy_Constraint, + &Constraint_Type ); + if( !pycon ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create BPy_Constraint object" ); + + pycon->con = con; + + /* one of these two will be NULL */ + pycon->obj = obj; + pycon->pchan = pchan; + return ( PyObject * ) pycon; +} + +/*****************************************************************************/ +/* Function: Constraint_FromPyObject */ +/* Description: This function returns the Blender constraint from the given */ +/* PyObject. */ +/*****************************************************************************/ +bConstraint *Constraint_FromPyObject( BPy_Constraint * self ) +{ + return self->con; +} + +/*****************************************************************************/ +/* Constraint Sequence wrapper */ +/*****************************************************************************/ + +/* + * Initialize the interator + */ + +static PyObject *ConstraintSeq_getIter( BPy_ConstraintSeq * self ) +{ + if( self->pchan ) + self->iter = (bConstraint *)self->pchan->constraints.first; + else + self->iter = (bConstraint *)self->obj->constraints.first; + return EXPP_incr_ret ( (PyObject *) self ); +} + +/* + * Get the next Constraint + */ + +static PyObject *ConstraintSeq_nextIter( BPy_ConstraintSeq * self ) +{ + bConstraint *this = self->iter; + if( this ) { + self->iter = this->next; + return Constraint_CreatePyObject( self->pchan, self->obj, this ); + } + + return EXPP_ReturnPyObjError( PyExc_StopIteration, + "iterator at end" ); +} + +/* return the number of constraints */ + +static int ConstraintSeq_length( BPy_ConstraintSeq * self ) +{ + return BLI_countlist( self->pchan ? + &self->pchan->constraints : &self->obj->constraints ); +} + +/* return a constraint */ + +static PyObject *ConstraintSeq_item( BPy_ConstraintSeq * self, int i ) +{ + bConstraint *con = NULL; + + /* if index is negative, start counting from the end of the list */ + if( i < 0 ) + i += ConstraintSeq_length( self ); + + /* skip through the list until we get the constraint or end of list */ + + if( self->pchan ) + con = self->pchan->constraints.first; + else + con = self->obj->constraints.first; + + while( i && con ) { + --i; + con = con->next; + } + + if( con ) + return Constraint_CreatePyObject( self->pchan, self->obj, con ); + else + return EXPP_ReturnPyObjError( PyExc_IndexError, + "array index out of range" ); +} + +/*****************************************************************************/ +/* Python BPy_ConstraintSeq sequence table: */ +/*****************************************************************************/ +static PySequenceMethods ConstraintSeq_as_sequence = { + ( inquiry ) ConstraintSeq_length, /* sq_length */ + ( binaryfunc ) 0, /* sq_concat */ + ( intargfunc ) 0, /* sq_repeat */ + ( intargfunc ) ConstraintSeq_item, /* sq_item */ + ( intintargfunc ) 0, /* sq_slice */ + ( intobjargproc ) 0, /* sq_ass_item */ + ( intintobjargproc ) 0, /* sq_ass_slice */ + ( objobjproc ) 0, /* sq_contains */ + ( binaryfunc ) 0, /* sq_inplace_concat */ + ( intargfunc ) 0, /* sq_inplace_repeat */ +}; + +/* + * helper function to check for a valid constraint argument + */ + +static bConstraint *locate_constr( BPy_ConstraintSeq *self, BPy_Constraint * value ) +{ + bConstraint *con; + + /* check that argument is a modifier */ + if (!BPy_Constraint_Check(value)) + return (bConstraint *)EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a constraint as an argument" ); + + /* check whether constraint has been removed */ + if( !value->con ) + return (bConstraint *)EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This constraint has been removed!" ); + + /* verify the constraint is still exists in the stack */ + if( self->pchan ) + con = self->pchan->constraints.first; + else + con = self->obj->constraints.first; + while( con && con != value->con ) + con = con->next; + + /* if we didn't find it, exception */ + if( !con ) + return (bConstraint *)EXPP_ReturnPyObjError( PyExc_AttributeError, + "This constraint is no longer in the object's stack" ); + + return con; +} + + +/* create a new constraint at the end of the list */ + +static PyObject *ConstraintSeq_append( BPy_ConstraintSeq *self, PyObject *value ) +{ + int type = (int)PyInt_AsLong(value); + bConstraint *con; + + /* type 0 is CONSTRAINT_TYPE_NULL, should we be able to add one of these? + * if the value is not an int it will be -1 */ + if( type < CONSTRAINT_TYPE_NULL || type > CONSTRAINT_TYPE_RIGIDBODYJOINT ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "arg not in int or out of range" ); + + con = add_new_constraint( type ); + if( self->pchan ) { + BLI_addtail( &self->pchan->constraints, con ); + update_pose_constraint_flags( self->obj->pose ); + } + else + BLI_addtail( &self->obj->constraints, con ); + + return Constraint_CreatePyObject( self->pchan, self->obj, con ); +} + +/* move the constraint up in the stack */ + +static PyObject *ConstraintSeq_moveUp( BPy_ConstraintSeq *self, BPy_Constraint *value ) +{ + bConstraint *con = locate_constr( self, value ); + + /* if we can't locate the constraint, return (exception already set) */ + if( !con ) + return (PyObject *)NULL; + + const_moveUp( self->obj, con ); + Py_RETURN_NONE; +} + +/* move the constraint down in the stack */ + +static PyObject *ConstraintSeq_moveDown( BPy_ConstraintSeq *self, BPy_Constraint *value ) +{ + bConstraint *con = locate_constr( self, value ); + + /* if we can't locate the constraint, return (exception already set) */ + if( !con ) + return (PyObject *)NULL; + + const_moveDown( self->obj, con ); + Py_RETURN_NONE; +} + +/* remove an existing constraint */ + +static PyObject *ConstraintSeq_remove( BPy_ConstraintSeq *self, BPy_Constraint *value ) +{ + bConstraint *con = locate_constr( self, value ); + + /* if we can't locate the constraint, return (exception already set) */ + if( !con ) + return (PyObject *)NULL; + + /* do the actual removal */ + if( self->pchan ) + BLI_remlink( &self->pchan->constraints, con ); + else + BLI_remlink( &self->obj->constraints, con); + del_constr_func( self->obj, con ); + + /* erase the link to the constraint */ + value->con = NULL; + + Py_RETURN_NONE; +} + +/*****************************************************************************/ +/* Function: ConstraintSeq_dealloc */ +/* Description: This is a callback function for the BPy_ConstraintSeq type. */ +/* It destroys data when the object is deleted. */ +/*****************************************************************************/ +static void ConstraintSeq_dealloc( BPy_Constraint * self ) +{ + PyObject_DEL( self ); +} + +/*****************************************************************************/ +/* Python BPy_ConstraintSeq methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_ConstraintSeq_methods[] = { + /* name, method, flags, doc */ + {"append", ( PyCFunction ) ConstraintSeq_append, METH_O, + "(type) - add a new constraint, where type is the constraint type"}, + {"remove", ( PyCFunction ) ConstraintSeq_remove, METH_O, + "(con) - remove an existing constraint, where con is a constraint from this object."}, + {"moveUp", ( PyCFunction ) ConstraintSeq_moveUp, METH_O, + "(con) - Move constraint up in stack"}, + {"moveDown", ( PyCFunction ) ConstraintSeq_moveDown, METH_O, + "(con) - Move constraint down in stack"}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python ConstraintSeq_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject ConstraintSeq_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender.Constraints", /* char *tp_name; */ + sizeof( BPy_ConstraintSeq ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + ( destructor ) ConstraintSeq_dealloc,/* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + ( reprfunc ) NULL, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + &ConstraintSeq_as_sequence, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + ( getiterfunc )ConstraintSeq_getIter, /* getiterfunc tp_iter; */ + ( iternextfunc )ConstraintSeq_nextIter, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_ConstraintSeq_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + NULL, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +/*****************************************************************************/ +/* Function: PoseConstraintSeq_CreatePyObject */ +/* Description: This function will create a new BPy_ConstraintSeq from an */ +/* existing ListBase structure. */ +/*****************************************************************************/ +PyObject *PoseConstraintSeq_CreatePyObject( bPoseChannel *pchan ) +{ + BPy_ConstraintSeq *pyseq; + Object *ob; + + for( ob = G.main->object.first; ob; ob = ob->id.next ) { + if( ob->type == OB_ARMATURE ) { + bPoseChannel *p = ob->pose->chanbase.first; + while( p ) { + if( p == pchan ) { + pyseq = ( BPy_ConstraintSeq * ) PyObject_NEW( + BPy_ConstraintSeq, &ConstraintSeq_Type ); + if( !pyseq ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create BPy_ConstraintSeq object" ); + pyseq->pchan = pchan; + pyseq->obj = ob; + return ( PyObject * ) pyseq; + } else + p = p->next; + } + } + } + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't find ANY armature with the pose!" ); + +} + +/*****************************************************************************/ +/* Function: ObConstraintSeq_CreatePyObject */ +/* Description: This function will create a new BPy_ConstraintSeq from an */ +/* existing ListBase structure. */ +/*****************************************************************************/ +PyObject *ObConstraintSeq_CreatePyObject( Object *obj ) +{ + BPy_ConstraintSeq *pyseq; + pyseq = ( BPy_ConstraintSeq * ) PyObject_NEW( BPy_ConstraintSeq, + &ConstraintSeq_Type ); + if( !pyseq ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create BPy_ConstraintSeq object" ); + pyseq->obj = obj; + pyseq->pchan = NULL; + return ( PyObject * ) pyseq; +} + +static PyObject *M_Constraint_TypeDict( void ) +{ + PyObject *S = PyConstant_New( ); + + if( S ) { + BPy_constant *d = ( BPy_constant * ) S; + PyConstant_Insert( d, "NULL", + PyInt_FromLong( CONSTRAINT_TYPE_NULL ) ); + PyConstant_Insert( d, "TRACKTO", + PyInt_FromLong( CONSTRAINT_TYPE_TRACKTO ) ); + PyConstant_Insert( d, "IKSOLVER", + PyInt_FromLong( CONSTRAINT_TYPE_KINEMATIC ) ); + PyConstant_Insert( d, "FOLLOWPATH", + PyInt_FromLong( CONSTRAINT_TYPE_FOLLOWPATH ) ); + PyConstant_Insert( d, "COPYROT", + PyInt_FromLong( CONSTRAINT_TYPE_ROTLIKE ) ); + PyConstant_Insert( d, "COPYLOC", + PyInt_FromLong( CONSTRAINT_TYPE_LOCLIKE ) ); + PyConstant_Insert( d, "COPYSIZE", + PyInt_FromLong( CONSTRAINT_TYPE_SIZELIKE ) ); + PyConstant_Insert( d, "ACTION", + PyInt_FromLong( CONSTRAINT_TYPE_ACTION ) ); + PyConstant_Insert( d, "LOCKTRACK", + PyInt_FromLong( CONSTRAINT_TYPE_LOCKTRACK ) ); + PyConstant_Insert( d, "STRETCHTO", + PyInt_FromLong( CONSTRAINT_TYPE_STRETCHTO ) ); + PyConstant_Insert( d, "FLOOR", + PyInt_FromLong( CONSTRAINT_TYPE_MINMAX ) ); + PyConstant_Insert( d, "LIMITLOC", + PyInt_FromLong( CONSTRAINT_TYPE_LOCLIMIT ) ); + PyConstant_Insert( d, "LIMITROT", + PyInt_FromLong( CONSTRAINT_TYPE_ROTLIMIT ) ); + PyConstant_Insert( d, "LIMITSIZE", + PyInt_FromLong( CONSTRAINT_TYPE_SIZELIMIT ) ); + PyConstant_Insert( d, "RIGIDBODYJOINT", + PyInt_FromLong( CONSTRAINT_TYPE_RIGIDBODYJOINT ) ); + PyConstant_Insert( d, "CLAMPTO", + PyInt_FromLong( CONSTRAINT_TYPE_CLAMPTO ) ); + PyConstant_Insert( d, "PYTHON", + PyInt_FromLong( CONSTRAINT_TYPE_PYTHON ) ); + PyConstant_Insert( d, "CHILDOF", + PyInt_FromLong( CONSTRAINT_TYPE_CHILDOF ) ); + PyConstant_Insert( d, "TRANSFORM", + PyInt_FromLong( CONSTRAINT_TYPE_TRANSFORM ) ); + } + return S; +} + +static PyObject *M_Constraint_SettingsDict( void ) +{ + PyObject *S = PyConstant_New( ); + + if( S ) { + BPy_constant *d = ( BPy_constant * ) S; + PyConstant_Insert( d, "XROT", + PyInt_FromLong( EXPP_CONSTR_XROT ) ); + PyConstant_Insert( d, "YROT", + PyInt_FromLong( EXPP_CONSTR_YROT ) ); + PyConstant_Insert( d, "ZROT", + PyInt_FromLong( EXPP_CONSTR_ZROT ) ); + PyConstant_Insert( d, "XSIZE", + PyInt_FromLong( EXPP_CONSTR_XSIZE ) ); + PyConstant_Insert( d, "YSIZE", + PyInt_FromLong( EXPP_CONSTR_YSIZE ) ); + PyConstant_Insert( d, "ZSIZE", + PyInt_FromLong( EXPP_CONSTR_ZSIZE ) ); + PyConstant_Insert( d, "XLOC", + PyInt_FromLong( EXPP_CONSTR_XLOC ) ); + PyConstant_Insert( d, "YLOC", + PyInt_FromLong( EXPP_CONSTR_YLOC ) ); + PyConstant_Insert( d, "ZLOC", + PyInt_FromLong( EXPP_CONSTR_ZLOC ) ); + + PyConstant_Insert( d, "UPX", + PyInt_FromLong( UP_X ) ); + PyConstant_Insert( d, "UPY", + PyInt_FromLong( UP_Y ) ); + PyConstant_Insert( d, "UPZ", + PyInt_FromLong( UP_Z ) ); + + PyConstant_Insert( d, "TRACKX", + PyInt_FromLong( TRACK_X ) ); + PyConstant_Insert( d, "TRACKY", + PyInt_FromLong( TRACK_Y ) ); + PyConstant_Insert( d, "TRACKZ", + PyInt_FromLong( TRACK_Z ) ); + PyConstant_Insert( d, "TRACKNEGX", + PyInt_FromLong( TRACK_nX ) ); + PyConstant_Insert( d, "TRACKNEGY", + PyInt_FromLong( TRACK_nY ) ); + PyConstant_Insert( d, "TRACKNEGZ", + PyInt_FromLong( TRACK_nZ ) ); + + PyConstant_Insert( d, "VOLUMEXZ", + PyInt_FromLong( VOLUME_XZ ) ); + PyConstant_Insert( d, "VOLUMEX", + PyInt_FromLong( VOLUME_X ) ); + PyConstant_Insert( d, "VOLUMEZ", + PyInt_FromLong( VOLUME_Z ) ); + PyConstant_Insert( d, "VOLUMENONE", + PyInt_FromLong( NO_VOLUME ) ); + + PyConstant_Insert( d, "PLANEX", + PyInt_FromLong( PLANE_X ) ); + PyConstant_Insert( d, "PLANEY", + PyInt_FromLong( PLANE_Y ) ); + PyConstant_Insert( d, "PLANEZ", + PyInt_FromLong( PLANE_Z ) ); + + PyConstant_Insert( d, "LOCKX", + PyInt_FromLong( LOCK_X ) ); + PyConstant_Insert( d, "LOCKY", + PyInt_FromLong( LOCK_Y ) ); + PyConstant_Insert( d, "LOCKZ", + PyInt_FromLong( LOCK_Z ) ); + + PyConstant_Insert( d, "MAXX", + PyInt_FromLong( EXPP_CONSTR_MAXX ) ); + PyConstant_Insert( d, "MAXY", + PyInt_FromLong( EXPP_CONSTR_MAXY ) ); + PyConstant_Insert( d, "MAXZ", + PyInt_FromLong( EXPP_CONSTR_MAXZ ) ); + PyConstant_Insert( d, "MINX", + PyInt_FromLong( EXPP_CONSTR_MINX ) ); + PyConstant_Insert( d, "MINY", + PyInt_FromLong( EXPP_CONSTR_MINY ) ); + PyConstant_Insert( d, "MINZ", + PyInt_FromLong( EXPP_CONSTR_MINZ ) ); + + PyConstant_Insert( d, "COPYX", + PyInt_FromLong( LOCLIKE_X ) ); + PyConstant_Insert( d, "COPYY", + PyInt_FromLong( LOCLIKE_Y ) ); + PyConstant_Insert( d, "COPYZ", + PyInt_FromLong( LOCLIKE_Z ) ); + PyConstant_Insert( d, "COPYXINVERT", + PyInt_FromLong( LOCLIKE_X_INVERT ) ); + PyConstant_Insert( d, "COPYYINVERT", + PyInt_FromLong( LOCLIKE_Y_INVERT ) ); + PyConstant_Insert( d, "COPYZINVERT", + PyInt_FromLong( LOCLIKE_Z_INVERT ) ); + + PyConstant_Insert( d, "PARLOCX", + PyInt_FromLong( CHILDOF_LOCX ) ); + PyConstant_Insert( d, "PARLOCY", + PyInt_FromLong( CHILDOF_LOCY ) ); + PyConstant_Insert( d, "PARLOCZ", + PyInt_FromLong( CHILDOF_LOCZ ) ); + PyConstant_Insert( d, "PARROTX", + PyInt_FromLong( CHILDOF_ROTX ) ); + PyConstant_Insert( d, "PARROTY", + PyInt_FromLong( CHILDOF_ROTY ) ); + PyConstant_Insert( d, "PARROTZ", + PyInt_FromLong( CHILDOF_ROTZ ) ); + PyConstant_Insert( d, "PARSIZEX", + PyInt_FromLong( CHILDOF_LOCX ) ); + PyConstant_Insert( d, "PARSIZEY", + PyInt_FromLong( CHILDOF_SIZEY ) ); + PyConstant_Insert( d, "PARSIZEZ", + PyInt_FromLong( CHILDOF_SIZEZ ) ); + + PyConstant_Insert( d, "CLAMPAUTO", + PyInt_FromLong( CLAMPTO_AUTO ) ); + PyConstant_Insert( d, "CLAMPX", + PyInt_FromLong( CLAMPTO_X ) ); + PyConstant_Insert( d, "CLAMPY", + PyInt_FromLong( CLAMPTO_Y ) ); + PyConstant_Insert( d, "CLAMPZ", + PyInt_FromLong( CLAMPTO_Z ) ); + PyConstant_Insert( d, "CLAMPCYCLIC", + PyInt_FromLong( EXPP_CONSTR_CLAMPCYCLIC )); + + PyConstant_Insert( d, "TARGET", + PyInt_FromLong( EXPP_CONSTR_TARGET ) ); + PyConstant_Insert( d, "STRETCH", + PyInt_FromLong( EXPP_CONSTR_STRETCH ) ); + PyConstant_Insert( d, "ITERATIONS", + PyInt_FromLong( EXPP_CONSTR_ITERATIONS ) ); + PyConstant_Insert( d, "BONE", + PyInt_FromLong( EXPP_CONSTR_BONE ) ); + PyConstant_Insert( d, "CHAINLEN", + PyInt_FromLong( EXPP_CONSTR_CHAINLEN ) ); + PyConstant_Insert( d, "POSWEIGHT", + PyInt_FromLong( EXPP_CONSTR_POSWEIGHT ) ); + PyConstant_Insert( d, "ROTWEIGHT", + PyInt_FromLong( EXPP_CONSTR_ROTWEIGHT ) ); + PyConstant_Insert( d, "ROTATE", + PyInt_FromLong( EXPP_CONSTR_ROTATE ) ); + PyConstant_Insert( d, "USETIP", + PyInt_FromLong( EXPP_CONSTR_USETIP ) ); + + PyConstant_Insert( d, "ACTION", + PyInt_FromLong( EXPP_CONSTR_ACTION ) ); + PyConstant_Insert( d, "START", + PyInt_FromLong( EXPP_CONSTR_START ) ); + PyConstant_Insert( d, "END", + PyInt_FromLong( EXPP_CONSTR_END ) ); + PyConstant_Insert( d, "MIN", + PyInt_FromLong( EXPP_CONSTR_MIN ) ); + PyConstant_Insert( d, "MAX", + PyInt_FromLong( EXPP_CONSTR_MAX ) ); + PyConstant_Insert( d, "KEYON", + PyInt_FromLong( EXPP_CONSTR_KEYON ) ); + + PyConstant_Insert( d, "TRACK", + PyInt_FromLong( EXPP_CONSTR_TRACK ) ); + PyConstant_Insert( d, "UP", + PyInt_FromLong( EXPP_CONSTR_UP ) ); + + PyConstant_Insert( d, "RESTLENGTH", + PyInt_FromLong( EXPP_CONSTR_RESTLENGTH ) ); + PyConstant_Insert( d, "VOLVARIATION", + PyInt_FromLong( EXPP_CONSTR_VOLVARIATION ) ); + PyConstant_Insert( d, "VOLUMEMODE", + PyInt_FromLong( EXPP_CONSTR_VOLUMEMODE ) ); + PyConstant_Insert( d, "PLANE", + PyInt_FromLong( EXPP_CONSTR_PLANE ) ); + + PyConstant_Insert( d, "FOLLOW", + PyInt_FromLong( EXPP_CONSTR_FOLLOW ) ); + PyConstant_Insert( d, "OFFSET", + PyInt_FromLong( EXPP_CONSTR_OFFSET ) ); + PyConstant_Insert( d, "FORWARD", + PyInt_FromLong( EXPP_CONSTR_FORWARD ) ); + + PyConstant_Insert( d, "LOCK", + PyInt_FromLong( EXPP_CONSTR_LOCK ) ); + + PyConstant_Insert( d, "COPY", + PyInt_FromLong( EXPP_CONSTR_COPY ) ); + PyConstant_Insert( d, "LIMIT", + PyInt_FromLong( EXPP_CONSTR_LIMIT ) ); + PyConstant_Insert( d, "CLAMP", + PyInt_FromLong( EXPP_CONSTR_CLAMP ) ); + + PyConstant_Insert( d, "LIMIT_XMIN", + PyInt_FromLong( EXPP_CONSTR_LIMXMIN ) ); + PyConstant_Insert( d, "LIMIT_XMAX", + PyInt_FromLong( EXPP_CONSTR_LIMXMAX ) ); + PyConstant_Insert( d, "LIMIT_YMIN", + PyInt_FromLong( EXPP_CONSTR_LIMYMIN ) ); + PyConstant_Insert( d, "LIMIT_YMAX", + PyInt_FromLong( EXPP_CONSTR_LIMYMAX ) ); + PyConstant_Insert( d, "LIMIT_ZMIN", + PyInt_FromLong( EXPP_CONSTR_LIMZMIN ) ); + PyConstant_Insert( d, "LIMIT_ZMAX", + PyInt_FromLong( EXPP_CONSTR_LIMZMAX ) ); + + PyConstant_Insert( d, "LIMIT_XROT", + PyInt_FromLong( EXPP_CONSTR_LIMXROT ) ); + PyConstant_Insert( d, "LIMIT_YROT", + PyInt_FromLong( EXPP_CONSTR_LIMYROT ) ); + PyConstant_Insert( d, "LIMIT_ZROT", + PyInt_FromLong( EXPP_CONSTR_LIMZROT ) ); + + PyConstant_Insert( d, "XMIN", + PyInt_FromLong( EXPP_CONSTR_XMIN ) ); + PyConstant_Insert( d, "XMAX", + PyInt_FromLong( EXPP_CONSTR_XMAX ) ); + PyConstant_Insert( d, "YMIN", + PyInt_FromLong( EXPP_CONSTR_YMIN ) ); + PyConstant_Insert( d, "YMAX", + PyInt_FromLong( EXPP_CONSTR_YMAX ) ); + PyConstant_Insert( d, "ZMIN", + PyInt_FromLong( EXPP_CONSTR_ZMIN ) ); + PyConstant_Insert( d, "ZMAX", + PyInt_FromLong( EXPP_CONSTR_ZMAX ) ); + + PyConstant_Insert( d, "SCRIPT", + PyInt_FromLong( EXPP_CONSTR_SCRIPT ) ); + PyConstant_Insert( d, "PROPERTIES", + PyInt_FromLong( EXPP_CONSTR_PROPS ) ); + + PyConstant_Insert( d, "FROM", + PyInt_FromLong( EXPP_CONSTR_FROM ) ); + PyConstant_Insert( d, "TO", + PyInt_FromLong( EXPP_CONSTR_TO ) ); + PyConstant_Insert( d, "EXTRAPOLATE", + PyInt_FromLong( EXPP_CONSTR_EXPO ) ); + PyConstant_Insert( d, "MAPX", + PyInt_FromLong( EXPP_CONSTR_MAPX ) ); + PyConstant_Insert( d, "MAPY", + PyInt_FromLong( EXPP_CONSTR_MAPY ) ); + PyConstant_Insert( d, "MAPZ", + PyInt_FromLong( EXPP_CONSTR_MAPZ ) ); + PyConstant_Insert( d, "FROM_MINX", + PyInt_FromLong( EXPP_CONSTR_FROMMINX ) ); + PyConstant_Insert( d, "FROM_MAXX", + PyInt_FromLong( EXPP_CONSTR_FROMMAXX ) ); + PyConstant_Insert( d, "FROM_MINY", + PyInt_FromLong( EXPP_CONSTR_FROMMINY ) ); + PyConstant_Insert( d, "FROM_MAXY", + PyInt_FromLong( EXPP_CONSTR_FROMMAXY ) ); + PyConstant_Insert( d, "FROM_MINZ", + PyInt_FromLong( EXPP_CONSTR_FROMMINZ ) ); + PyConstant_Insert( d, "FROM_MAXZ", + PyInt_FromLong( EXPP_CONSTR_FROMMAXZ ) ); + PyConstant_Insert( d, "TO_MINX", + PyInt_FromLong( EXPP_CONSTR_TOMINX ) ); + PyConstant_Insert( d, "TO_MAXX", + PyInt_FromLong( EXPP_CONSTR_TOMAXX ) ); + PyConstant_Insert( d, "TO_MINY", + PyInt_FromLong( EXPP_CONSTR_TOMINY ) ); + PyConstant_Insert( d, "TO_MAXY", + PyInt_FromLong( EXPP_CONSTR_TOMAXY ) ); + PyConstant_Insert( d, "TO_MINZ", + PyInt_FromLong( EXPP_CONSTR_TOMINZ ) ); + PyConstant_Insert( d, "TO_MAXZ", + PyInt_FromLong( EXPP_CONSTR_TOMAXZ ) ); + + PyConstant_Insert( d, "LOC", + PyInt_FromLong( 0 ) ); + PyConstant_Insert( d, "ROT", + PyInt_FromLong( 1 ) ); + PyConstant_Insert( d, "SCALE", + PyInt_FromLong( 2 ) ); + + PyConstant_Insert( d, "CONSTR_RB_TYPE", + PyInt_FromLong( EXPP_CONSTR_RB_TYPE ) ); + PyConstant_Insert( d, "CONSTR_RB_BALL", + PyInt_FromLong( EXPP_CONSTR_RB_BALL ) ); + PyConstant_Insert( d, "CONSTR_RB_HINGE", + PyInt_FromLong( EXPP_CONSTR_RB_HINGE ) ); + PyConstant_Insert( d, "CONSTR_RB_GENERIC6DOF", + PyInt_FromLong( EXPP_CONSTR_RB_GENERIC6DOF ) ); + PyConstant_Insert( d, "CONSTR_RB_VEHICLE", + PyInt_FromLong( EXPP_CONSTR_RB_VEHICLE ) ); + PyConstant_Insert( d, "CONSTR_RB_PIVX", + PyInt_FromLong( EXPP_CONSTR_RB_PIVX ) ); + PyConstant_Insert( d, "CONSTR_RB_PIVY", + PyInt_FromLong( EXPP_CONSTR_RB_PIVY ) ); + PyConstant_Insert( d, "CONSTR_RB_PIVZ", + PyInt_FromLong( EXPP_CONSTR_RB_PIVZ ) ); + PyConstant_Insert( d, "CONSTR_RB_AXX", + PyInt_FromLong( EXPP_CONSTR_RB_AXX ) ); + PyConstant_Insert( d, "CONSTR_RB_AXY", + PyInt_FromLong( EXPP_CONSTR_RB_AXY ) ); + PyConstant_Insert( d, "CONSTR_RB_AXZ", + PyInt_FromLong( EXPP_CONSTR_RB_AXZ ) ); + PyConstant_Insert( d, "CONSTR_RB_MINLIMIT0", + PyInt_FromLong( EXPP_CONSTR_RB_MINLIMIT0 ) ); + PyConstant_Insert( d, "CONSTR_RB_MINLIMIT1", + PyInt_FromLong( EXPP_CONSTR_RB_MINLIMIT1 ) ); + PyConstant_Insert( d, "CONSTR_RB_MINLIMIT2", + PyInt_FromLong( EXPP_CONSTR_RB_MINLIMIT2 ) ); + PyConstant_Insert( d, "CONSTR_RB_MINLIMIT3", + PyInt_FromLong( EXPP_CONSTR_RB_MINLIMIT3 ) ); + PyConstant_Insert( d, "CONSTR_RB_MINLIMIT4", + PyInt_FromLong( EXPP_CONSTR_RB_MINLIMIT4 ) ); + PyConstant_Insert( d, "CONSTR_RB_MINLIMIT5", + PyInt_FromLong( EXPP_CONSTR_RB_MINLIMIT5 ) ); + PyConstant_Insert( d, "CONSTR_RB_MAXLIMIT0", + PyInt_FromLong( EXPP_CONSTR_RB_MAXLIMIT0 ) ); + PyConstant_Insert( d, "CONSTR_RB_MAXLIMIT1", + PyInt_FromLong( EXPP_CONSTR_RB_MAXLIMIT1 ) ); + PyConstant_Insert( d, "CONSTR_RB_MAXLIMIT2", + PyInt_FromLong( EXPP_CONSTR_RB_MAXLIMIT2 ) ); + PyConstant_Insert( d, "CONSTR_RB_MAXLIMIT3", + PyInt_FromLong( EXPP_CONSTR_RB_MAXLIMIT3 ) ); + PyConstant_Insert( d, "CONSTR_RB_MAXLIMIT4", + PyInt_FromLong( EXPP_CONSTR_RB_MAXLIMIT4 ) ); + PyConstant_Insert( d, "CONSTR_RB_MAXLIMIT5", + PyInt_FromLong( EXPP_CONSTR_RB_MAXLIMIT5 ) ); + PyConstant_Insert( d, "CONSTR_RB_EXTRAFZ", + PyInt_FromLong( EXPP_CONSTR_RB_EXTRAFZ ) ); + PyConstant_Insert( d, "CONSTR_RB_FLAG", + PyInt_FromLong( EXPP_CONSTR_RB_FLAG ) ); + + + PyConstant_Insert( d, "OWNERSPACE", + PyInt_FromLong( EXPP_CONSTR_OWNSPACE ) ); + PyConstant_Insert( d, "TARGETSPACE", + PyInt_FromLong( EXPP_CONSTR_TARSPACE ) ); + + PyConstant_Insert( d, "SPACE_WORLD", + PyInt_FromLong( CONSTRAINT_SPACE_WORLD) ); + PyConstant_Insert( d, "SPACE_LOCAL", + PyInt_FromLong( CONSTRAINT_SPACE_LOCAL ) ); + PyConstant_Insert( d, "SPACE_POSE", + PyInt_FromLong( CONSTRAINT_SPACE_POSE) ); + PyConstant_Insert( d, "SPACE_PARLOCAL", + PyInt_FromLong( CONSTRAINT_SPACE_PARLOCAL ) ); + } + return S; +} + +/*****************************************************************************/ +/* Function: Constraint_Init */ +/*****************************************************************************/ +PyObject *Constraint_Init( void ) +{ + PyObject *submodule; + PyObject *TypeDict = M_Constraint_TypeDict( ); + PyObject *SettingsDict = M_Constraint_SettingsDict( ); + + if( PyType_Ready( &ConstraintSeq_Type ) < 0 + || PyType_Ready( &Constraint_Type ) < 0 ) + return NULL; + + submodule = Py_InitModule3( "Blender.Constraint", NULL, + "Constraint module for accessing and creating constraint data" ); + + if( TypeDict ) + PyModule_AddObject( submodule, "Type", TypeDict ); + + if( SettingsDict ) + PyModule_AddObject( submodule, "Settings", SettingsDict ); + + return submodule; +} diff --git a/source/blender/python/api2_2x/Constraint.h b/source/blender/python/api2_2x/Constraint.h new file mode 100644 index 00000000000..116eabbf380 --- /dev/null +++ b/source/blender/python/api2_2x/Constraint.h @@ -0,0 +1,76 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Joseph Gilbert, Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_CONSTRAINT_H +#define EXPP_CONSTRAINT_H + +#include +#include "DNA_object_types.h" +#include "DNA_action_types.h" +#include "DNA_constraint_types.h" +#include "DNA_listBase.h" + +/*****************************************************************************/ +/* Python BPy_Modifier structure definition: */ +/*****************************************************************************/ +typedef struct { + PyObject_HEAD /* required macro */ + Object *obj; /* "parent" object */ + bPoseChannel *pchan;/* "parent" pose channel */ + /* if con this is null, the constraint has been removed and we need to + * raise an error when its data is accessed */ + bConstraint *con; +} BPy_Constraint; + +extern PyTypeObject Constraint_Type; + +#define BPy_Constraint_Check(v) ((v)->ob_type == &Constraint_Type) /* for type checking */ +typedef struct { + PyObject_HEAD /* required macro */ + Object *obj; /* "parent" object */ + bPoseChannel *pchan;/* "parent" pose channel */ + bConstraint *iter; +} BPy_ConstraintSeq; + +/* + * prototypes + */ + +PyObject *Constraint_Init( void ); +PyObject *Constraint_CreatePyObject( bPoseChannel *pchan, Object *obj, + bConstraint *con ); +bConstraint *Constraint_FromPyObject( BPy_Constraint * obj ); + +PyObject *PoseConstraintSeq_CreatePyObject( bPoseChannel *pchan ); +PyObject *ObConstraintSeq_CreatePyObject( Object *obj ); + +#endif /* EXPP_CONSTRAINT_H */ diff --git a/source/blender/python/api2_2x/CurNurb.c b/source/blender/python/api2_2x/CurNurb.c new file mode 100644 index 00000000000..642e7b7b5e6 --- /dev/null +++ b/source/blender/python/api2_2x/CurNurb.c @@ -0,0 +1,1078 @@ +/* + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Stephen Swaney, Campbell Barton, Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "CurNurb.h" /*This must come first */ + +#include "BKE_curve.h" +#include "BDR_editcurve.h" /* for convertspline */ +#include "MEM_guardedalloc.h" +#include "gen_utils.h" +#include "BezTriple.h" + +/* + * forward declarations go here + */ + +static PyObject *M_CurNurb_New( PyObject * self, PyObject * args ); +static PyObject *CurNurb_oldsetMatIndex( BPy_CurNurb * self, PyObject * args ); +static int CurNurb_setMatIndex( BPy_CurNurb * self, PyObject * args ); +static PyObject *CurNurb_getMatIndex( BPy_CurNurb * self ); +static PyObject *CurNurb_getFlagU( BPy_CurNurb * self ); +static PyObject *CurNurb_oldsetFlagU( BPy_CurNurb * self, PyObject * args ); +static int CurNurb_setFlagU( BPy_CurNurb * self, PyObject * args ); +static PyObject *CurNurb_getFlagV( BPy_CurNurb * self ); +static PyObject *CurNurb_oldsetFlagV( BPy_CurNurb * self, PyObject * args ); +static int CurNurb_setFlagV( BPy_CurNurb * self, PyObject * args ); +static PyObject *CurNurb_getType( BPy_CurNurb * self ); +static PyObject *CurNurb_oldsetType( BPy_CurNurb * self, PyObject * args ); +static int CurNurb_setType( BPy_CurNurb * self, PyObject * args ); +static PyObject *CurNurb_getKnotsU( BPy_CurNurb * self ); +static PyObject *CurNurb_getKnotsV( BPy_CurNurb * self ); +static PyObject *CurNurb_getPoints( BPy_CurNurb * self ); +/* static PyObject* CurNurb_setXXX( BPy_CurNurb* self, PyObject* args ); */ +static int CurNurb_setPoint( BPy_CurNurb * self, int index, PyObject * ob ); +static int CurNurb_length( PyInstanceObject * inst ); +static PyObject *CurNurb_getIter( BPy_CurNurb * self ); +static PyObject *CurNurb_iterNext( BPy_CurNurb * self ); +PyObject *CurNurb_append( BPy_CurNurb * self, PyObject * value ); + +static PyObject *CurNurb_isNurb( BPy_CurNurb * self ); +static PyObject *CurNurb_isCyclic( BPy_CurNurb * self ); +static PyObject *CurNurb_dump( BPy_CurNurb * self ); +static PyObject *CurNurb_switchDirection( BPy_CurNurb * self ); +static PyObject *CurNurb_recalc( BPy_CurNurb * self ); + +char M_CurNurb_doc[] = "CurNurb"; + + +/* + CurNurb_Type callback function prototypes: +*/ + +static int CurNurb_compare( BPy_CurNurb * a, BPy_CurNurb * b ); +static PyObject *CurNurb_repr( BPy_CurNurb * self ); + +/* + table of module methods + these are the equivalent of class or static methods. + you do not need an object instance to call one. + +*/ + +static PyMethodDef M_CurNurb_methods[] = { +/* name, method, flags, doc_string */ + {"New", ( PyCFunction ) M_CurNurb_New, METH_VARARGS | METH_KEYWORDS, + " () - doc string"}, +/* {"Get", (PyCFunction) M_CurNurb_method, METH_NOARGS, " () - doc string"}, */ +/* {"method", (PyCFunction) M_CurNurb_method, METH_NOARGS, " () - doc string"}, */ + + {NULL, NULL, 0, NULL} +}; + + + +/* + * method table + * table of instance methods + * these methods are invoked on an instance of the type. +*/ + +static PyMethodDef BPy_CurNurb_methods[] = { +/* name, method, flags, doc */ +/* {"method", (PyCFunction) CurNurb_method, METH_NOARGS, " () - doc string"} */ + {"setMatIndex", ( PyCFunction ) CurNurb_oldsetMatIndex, METH_VARARGS, + "( index ) - set index into materials list"}, + {"getMatIndex", ( PyCFunction ) CurNurb_getMatIndex, METH_NOARGS, + "( ) - get current material index"}, + {"setFlagU", ( PyCFunction ) CurNurb_oldsetFlagU, METH_VARARGS, + "( index ) - set flagU and recalculate the knots (0: uniform, 1: endpoints, 2: bezier)"}, + {"getFlagU", ( PyCFunction ) CurNurb_getFlagU, METH_NOARGS, + "( ) - get flagU of the knots"}, + {"setFlagV", ( PyCFunction ) CurNurb_oldsetFlagV, METH_VARARGS, + "( index ) - set flagV and recalculate the knots (0: uniform, 1: endpoints, 2: bezier)"}, + {"getFlagV", ( PyCFunction ) CurNurb_getFlagV, METH_NOARGS, + "( ) - get flagV of the knots"}, + {"setType", ( PyCFunction ) CurNurb_oldsetType, METH_VARARGS, + "( type ) - change the type of the curve (Poly: 0, Bezier: 1, NURBS: 4)"}, + {"getType", ( PyCFunction ) CurNurb_getType, METH_NOARGS, + "( ) - get the type of the curve (Poly: 0, Bezier: 1, NURBS: 4)"}, + {"append", ( PyCFunction ) CurNurb_append, METH_O, + "( point ) - add a new point. arg is BezTriple or list of x,y,z,w floats"}, + {"isNurb", ( PyCFunction ) CurNurb_isNurb, METH_NOARGS, + "( ) - boolean function tests if this spline is type nurb or bezier"}, + {"isCyclic", ( PyCFunction ) CurNurb_isCyclic, METH_NOARGS, + "( ) - boolean function tests if this spline is cyclic (closed) or not (open)"}, + {"dump", ( PyCFunction ) CurNurb_dump, METH_NOARGS, + "( ) - dumps Nurb data)"}, + {"switchDirection", ( PyCFunction ) CurNurb_switchDirection, METH_NOARGS, + "( ) - swaps curve beginning and end)"}, + {"recalc", ( PyCFunction ) CurNurb_recalc, METH_NOARGS, + "( ) - recalc Nurb data)"}, + {NULL, NULL, 0, NULL} +}; + +/* + * methods for CurNurb as sequece + */ + +static PySequenceMethods CurNurb_as_sequence = { + ( inquiry ) CurNurb_length, /* sq_length */ + ( binaryfunc ) 0, /* sq_concat */ + ( intargfunc ) 0, /* sq_repeat */ + ( intargfunc ) CurNurb_getPoint, /* sq_item */ + ( intintargfunc ) 0, /* sq_slice */ + ( intobjargproc ) CurNurb_setPoint, /* sq_ass_item */ + 0, /* sq_ass_slice */ + ( objobjproc ) 0, /* sq_contains */ + 0, + 0 +}; + +static PyGetSetDef BPy_CurNurb_getseters[] = { + {"mat_index", + (getter)CurNurb_getMatIndex, (setter)CurNurb_setMatIndex, + "CurNurb's material index", + NULL}, + {"points", + (getter)CurNurb_getPoints, (setter)NULL, + "The number of curve points", + NULL}, + {"flagU", + (getter)CurNurb_getFlagU, (setter)CurNurb_setFlagU, + "The knot type in the U direction", + NULL}, + {"flagV", + (getter)CurNurb_getFlagV, (setter)CurNurb_setFlagV, + "The knot type in the V direction", + NULL}, + {"type", + (getter)CurNurb_getType, (setter)CurNurb_setType, + "The curve type (poly: bezier, or NURBS)", + NULL}, + {"knotsU", + (getter)CurNurb_getKnotsU, (setter)NULL, + "The The knot vector in the U direction", + NULL}, + {"knotsV", + (getter)CurNurb_getKnotsV, (setter)NULL, + "The The knot vector in the V direction", + NULL}, + + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/* + Object Type definition + full blown 2.3 struct + if you are having trouble building with an earlier version of python, + this is why. +*/ + +PyTypeObject CurNurb_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "CurNurb", /* char *tp_name; */ + sizeof( CurNurb_Type ), /* int tp_basicsize, */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) CurNurb_compare, /* cmpfunc tp_compare; */ + ( reprfunc ) CurNurb_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + 0, /* PyNumberMethods *tp_as_number; */ + &CurNurb_as_sequence, /* PySequenceMethods *tp_as_sequence; */ + 0, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + 0, /* hashfunc tp_hash; */ + 0, /* ternaryfunc tp_call; */ + 0, /* reprfunc tp_str; */ + 0, /* getattrofunc tp_getattro; */ + 0, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + 0, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + 0, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + 0, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + 0, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + 0, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + ( getiterfunc ) CurNurb_getIter, /* getiterfunc tp_iter; */ + ( iternextfunc ) CurNurb_iterNext, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_CurNurb_methods, /* struct PyMethodDef *tp_methods; */ + 0, /* struct PyMemberDef *tp_members; */ + BPy_CurNurb_getseters, /* struct PyGetSetDef *tp_getset; */ + 0, /* struct _typeobject *tp_base; */ + 0, /* PyObject *tp_dict; */ + 0, /* descrgetfunc tp_descr_get; */ + 0, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + 0, /* initproc tp_init; */ + 0, /* allocfunc tp_alloc; */ + 0, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + 0, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + 0, /* inquiry tp_is_gc; */ + 0, /* PyObject *tp_bases; */ + /* method resolution order */ + 0, /* PyObject *tp_mro; */ + 0, /* PyObject *tp_cache; */ + 0, /* PyObject *tp_subclasses; */ + 0, /* PyObject *tp_weaklist; */ + 0 +}; + +/* + compare + in this case, we consider two CurNurbs equal, if they point to the same + blender data. +*/ + +static int CurNurb_compare( BPy_CurNurb * a, BPy_CurNurb * b ) +{ + Nurb *pa = a->nurb; + Nurb *pb = b->nurb; + + return ( pa == pb ) ? 0 : -1; +} + + +/* + factory method to create a BPy_CurNurb from a Blender Nurb +*/ + +PyObject *CurNurb_CreatePyObject( Nurb * blen_nurb ) +{ + BPy_CurNurb *pyNurb; + + pyNurb = ( BPy_CurNurb * ) PyObject_NEW( BPy_CurNurb, &CurNurb_Type ); + + if( !pyNurb ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "could not create BPy_CurNurb PyObject" ); + + pyNurb->nurb = blen_nurb; + return ( PyObject * ) pyNurb; +} + + +/* + * CurNurb_repr + */ +static PyObject *CurNurb_repr( BPy_CurNurb * self ) +{ /* used by 'repr' */ + + return PyString_FromFormat( "[CurNurb \"%d\"]", self->nurb->type ); +} + +/* XXX Can't this be simply removed? */ +static PyObject *M_CurNurb_New( PyObject * self, PyObject * args ) +{ + return ( PyObject * ) 0; + +} + +/* + * Curve.getType + */ +static PyObject *CurNurb_getType( BPy_CurNurb * self ) +{ + /* type is on 3 first bits only */ + return PyInt_FromLong( self->nurb->type & 7 ); +} + +/* + * Curve.setType + * + * Convert the curve using Blender's convertspline fonction + */ +static int CurNurb_setType( BPy_CurNurb * self, PyObject * args ) +{ + PyObject* integer = PyNumber_Int( args ); + short value; + + if( !integer ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected integer argument" ); + + value = ( short )PyInt_AS_LONG( integer ); + Py_DECREF( integer ); + + /* parameter value checking */ + if (value != CU_POLY && value != CU_BEZIER && value != CU_NURBS) + return EXPP_ReturnIntError( PyExc_ValueError, + "expected integer argument" ); + + /* convert and raise error if impossible */ + if (convertspline(value, self->nurb)) + return EXPP_ReturnIntError( PyExc_ValueError, + "Conversion Impossible" ); + + return 0; +} + +/* + * CurNurb_getKnotsU + * + * returns curve's knotsU in a tuple. Empty tuple is returned if curve + * isn't Nurbs or it doesn't have knots in U + */ + +static PyObject *CurNurb_getKnotsU( BPy_CurNurb * self ) +{ + if(self->nurb->knotsu) { + int len = KNOTSU(self->nurb); + int i; + PyObject *knotsu = PyTuple_New(len); + if( !knotsu ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "could not get CurNurb.knotsU attribute" ); + + for(i = 0; i < len; ++i) + PyTuple_SetItem(knotsu, i, + PyFloat_FromDouble(self->nurb->knotsu[i])); + + return knotsu; + } + return PyTuple_New(0); +} + +/* + * CurNurb_getKnotsV + * + * returns curve's knotsV in a tuple. Empty tuple is returned if curve doesn't have knots in V + */ + +static PyObject *CurNurb_getKnotsV( BPy_CurNurb * self ) +{ + if(self->nurb->knotsv) { + int len = KNOTSV(self->nurb); + int i; + PyObject *knotsv = PyTuple_New(len); + if( !knotsv ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "could not get CurNurb.knotsV index" ); + + for(i = 0; i < len; ++i) + PyTuple_SetItem(knotsv, i, + PyFloat_FromDouble(self->nurb->knotsv[i] )); + + return knotsv; + } + return PyTuple_New(0); +} + +static PyObject *CurNurb_getPoints( BPy_CurNurb * self ) +{ + return PyInt_FromLong( ( long ) self->nurb->pntsu ); +} + +/* + * CurNurb_append( point ) + * append a new point to a nurb curve. + * arg is BezTriple or list of xyzw floats + */ + +PyObject *CurNurb_append( BPy_CurNurb * self, PyObject * value ) +{ + return CurNurb_appendPointToNurb( self->nurb, value ); +} + + +/* + * CurNurb_appendPointToNurb + * this is a non-bpy utility func to add a point to a given nurb. + * notice the first arg is Nurb*. + */ + +PyObject *CurNurb_appendPointToNurb( Nurb * nurb, PyObject * value ) +{ + + int i; + int size; + int npoints = nurb->pntsu; + + /* + do we have a list of four floats or a BezTriple? + */ + + /* if curve is empty, adjust type depending on input type */ + if (nurb->bezt==NULL && nurb->bp==NULL) { + if (BPy_BezTriple_Check( value )) + nurb->type |= CU_BEZIER; + else if (PySequence_Check( value )) + nurb->type |= CU_NURBS; + else + return( EXPP_ReturnPyObjError( PyExc_TypeError, + "Expected a BezTriple or a Sequence of 4 (or 5) floats" ) ); + } + + + + if ((nurb->type & 7)==CU_BEZIER) { + BezTriple *tmp; + + if( !BPy_BezTriple_Check( value ) ) + return( EXPP_ReturnPyObjError( PyExc_TypeError, + "Expected a BezTriple\n" ) ); + +/* printf("\ndbg: got a BezTriple\n"); */ + tmp = nurb->bezt; /* save old points */ + nurb->bezt = + ( BezTriple * ) MEM_mallocN( sizeof( BezTriple ) * + ( npoints + 1 ), + "CurNurb_append2" ); + + if( !nurb->bezt ) + return ( EXPP_ReturnPyObjError + ( PyExc_MemoryError, "allocation failed" ) ); + + /* copy old points to new */ + if( tmp ) { + memmove( nurb->bezt, tmp, sizeof( BezTriple ) * npoints ); + MEM_freeN( tmp ); + } + + nurb->pntsu++; + /* add new point to end of list */ + memcpy( nurb->bezt + npoints, + BezTriple_FromPyObject( value ), sizeof( BezTriple ) ); + + } + else if( PySequence_Check( value ) ) { + size = PySequence_Size( value ); +/* printf("\ndbg: got a sequence of size %d\n", size ); */ + if( size == 4 || size == 5 ) { + BPoint *tmp; + + tmp = nurb->bp; /* save old pts */ + + nurb->bp = + ( BPoint * ) MEM_mallocN( sizeof( BPoint ) * + ( npoints + 1 ), + "CurNurb_append1" ); + if( !nurb->bp ) + return ( EXPP_ReturnPyObjError + ( PyExc_MemoryError, + "allocation failed" ) ); + + memmove( nurb->bp, tmp, sizeof( BPoint ) * npoints ); + if( tmp ) + MEM_freeN( tmp ); + + ++nurb->pntsu; + /* initialize new BPoint from old */ + memcpy( nurb->bp + npoints, nurb->bp, + sizeof( BPoint ) ); + + for( i = 0; i < 4; ++i ) { + PyObject *item = PySequence_GetItem( value, i ); + + if (item == NULL) + return NULL; + + + nurb->bp[npoints].vec[i] = ( float ) PyFloat_AsDouble( item ); + Py_DECREF( item ); + } + + if (size == 5) { + PyObject *item = PySequence_GetItem( value, i ); + + if (item == NULL) + return NULL; + + nurb->bp[npoints].alfa = ( float ) PyFloat_AsDouble( item ); + Py_DECREF( item ); + } + else { + nurb->bp[npoints].alfa = 0.0f; + } + + makeknots( nurb, 1, nurb->flagu >> 1 ); + + } else { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a sequence of 4 or 5 floats" ); + } + + } else { + /* bail with error */ + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a sequence of 4 or 5 floats" ); + + } + + Py_RETURN_NONE; +} + + +/* + * CurNurb_setMatIndex + * + * set index into material list + */ + +static int CurNurb_setMatIndex( BPy_CurNurb * self, PyObject * args ) +{ + printf ("%d\n", self->nurb->mat_nr); + return EXPP_setIValueRange( args, &self->nurb->mat_nr, 0, 15, 'h' ); +} + +/* + * CurNurb_getMatIndex + * + * returns index into material list + */ + +static PyObject *CurNurb_getMatIndex( BPy_CurNurb * self ) +{ + PyObject *index = PyInt_FromLong( ( long ) self->nurb->mat_nr ); + + if( index ) + return index; + + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "could not get material index" ); +} + +/* + * CurNurb_getFlagU + * + * returns curve's flagu + */ + +static PyObject *CurNurb_getFlagU( BPy_CurNurb * self ) +{ + PyObject *flagu = PyInt_FromLong( ( long ) self->nurb->flagu ); + + if( flagu ) + return flagu; + + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "could not get CurNurb.flagu index" ) ); +} + +/* + * CurNurb_setFlagU + * + * set curve's flagu and recalculate the knots + * + * Possible values: 0 - uniform, 2 - endpoints, 4 - bezier + * bit 0 controls CU_CYCLIC + */ + +static int CurNurb_setFlagU( BPy_CurNurb * self, PyObject * args ) +{ + PyObject* integer = PyNumber_Int( args ); + short value; + + if( !integer ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected integer argument" ); + + value = ( short )PyInt_AS_LONG( integer ); + Py_DECREF( integer ); + + if( value < 0 || value > 5 ) + return EXPP_ReturnIntError( PyExc_ValueError, + "expected integer argument in range [0,5]" ); + + if( self->nurb->flagu != value ) { + self->nurb->flagu = (short)value; + makeknots( self->nurb, 1, self->nurb->flagu >> 1 ); + } + + return 0; +} + +/* + * CurNurb_getFlagV + * + * returns curve's flagu + */ + +static PyObject *CurNurb_getFlagV( BPy_CurNurb * self ) +{ + PyObject *flagv = PyInt_FromLong( ( long ) self->nurb->flagv ); + + if( flagv ) + return flagv; + + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "could not get CurNurb.flagv" ) ); +} + +/* + * CurNurb_setFlagV + * + * set curve's flagu and recalculate the knots + * + * Possible values: 0 - uniform, 1 - endpoints, 2 - bezier + */ + +static int CurNurb_setFlagV( BPy_CurNurb * self, PyObject * args ) +{ + PyObject* integer = PyNumber_Int( args ); + short value; + + if( !integer ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected integer argument" ); + + value = ( short )PyInt_AS_LONG( integer ); + Py_DECREF( integer ); + + if( value < 0 || value > 5 ) + return EXPP_ReturnIntError( PyExc_ValueError, + "expected integer argument in range [0,5]" ); + + if( self->nurb->flagv != value ) { + self->nurb->flagv = (short)value; + makeknots( self->nurb, 2, self->nurb->flagv >> 1 ); + } + + return 0; +} + +/* + * CurNurb_getIter + * + * create an iterator for our CurNurb. + * this iterator returns the points for this CurNurb. + */ + +static PyObject *CurNurb_getIter( BPy_CurNurb * self ) +{ + self->bp = self->nurb->bp; + self->bezt = self->nurb->bezt; + self->atEnd = 0; + self->nextPoint = 0; + + /* set exhausted flag if both bp and bezt are zero */ + if( ( !self->bp ) && ( !self->bezt ) ) + self->atEnd = 1; + + Py_INCREF( self ); + return ( PyObject * ) self; +} + + +static PyObject *CurNurb_iterNext( BPy_CurNurb * self ) +{ + PyObject *po; /* return value */ + Nurb *pnurb = self->nurb; + int npoints = pnurb->pntsu; + + /* are we at end already? */ + if( self->atEnd ) + return ( EXPP_ReturnPyObjError( PyExc_StopIteration, + "iterator at end" ) ); + + if( self->nextPoint < npoints ) { + + po = CurNurb_pointAtIndex( self->nurb, self->nextPoint ); + self->nextPoint++; + + return po; + + } else { + self->atEnd = 1; /* set flag true */ + } + + return ( EXPP_ReturnPyObjError( PyExc_StopIteration, + "iterator at end" ) ); +} + + + +/* + * CurNurb_isNurb() + * test whether spline nurb or bezier + */ + +static PyObject *CurNurb_isNurb( BPy_CurNurb * self ) +{ + /* NOTE: a Nurb has bp and bezt pointers + * depending on type. + * It is possible both are NULL if no points exist. + * in that case, we return False + */ + + if( self->nurb->bp ) { + return EXPP_incr_ret_True(); + } else { + return EXPP_incr_ret_False(); + } +} + +/* + * CurNurb_isCyclic() + * test whether spline cyclic (closed) or not (open) + */ + +static PyObject *CurNurb_isCyclic( BPy_CurNurb * self ) +{ + /* supposing that the flagu is always set */ + + if( self->nurb->flagu & CU_CYCLIC ) { + return EXPP_incr_ret_True(); + } else { + return EXPP_incr_ret_False(); + } +} + +/* + * CurNurb_length + * returns the number of points in a Nurb + * this is a tp_as_sequence method, not a regular instance method. + */ + +static int CurNurb_length( PyInstanceObject * inst ) +{ + Nurb *nurb; + int len; + + if( BPy_CurNurb_Check( ( PyObject * ) inst ) ) { + nurb = ( ( BPy_CurNurb * ) inst )->nurb; + len = nurb->pntsu; + return len; + } + + return EXPP_ReturnIntError( PyExc_RuntimeError, + "arg is not a BPy_CurNurb" ); +} + +/* + * CurNurb_getPoint + * returns the Nth point in a Nurb + * this is one of the tp_as_sequence methods, hence the int N argument. + * it is called via the [] operator, not as a usual instance method. + */ + +PyObject *CurNurb_getPoint( BPy_CurNurb * self, int index ) +{ + Nurb *myNurb; + + int npoints; + + /* for convenince */ + myNurb = self->nurb; + npoints = myNurb->pntsu; + + /* DELETED: bail if index < 0 */ + /* actually, this check is not needed since python treats */ + /* negative indices as starting from the right end of a sequence */ + /* + THAT IS WRONG, when passing a negative index, python adjusts it to be positive + BUT it can still overflow in the negatives if the index is too small. + For example, list[-6] when list contains 5 items means index = -1 in here. + (theeth) + */ + + /* bail if no Nurbs in Curve */ + if( npoints == 0 ) + return ( EXPP_ReturnPyObjError( PyExc_IndexError, + "no points in this CurNurb" ) ); + + /* check index limits */ + if( index >= npoints || index < 0 ) + return ( EXPP_ReturnPyObjError( PyExc_IndexError, + "index out of range" ) ); + + return CurNurb_pointAtIndex( myNurb, index ); +} + +/* + * CurNurb_setPoint + * modifies the Nth point in a Nurb + * this is one of the tp_as_sequence methods, hence the int N argument. + * it is called via the [] = operator, not as a usual instance method. + */ +static int CurNurb_setPoint( BPy_CurNurb * self, int index, PyObject * pyOb ) +{ + Nurb *nurb = self->nurb; + int size; + + /* check index limits */ + if( index < 0 || index >= nurb->pntsu ) + return EXPP_ReturnIntError( PyExc_IndexError, + "array assignment index out of range" ); + + + /* branch by curve type */ + if ((nurb->type & 7)==CU_BEZIER) { /* BEZIER */ + /* check parameter type */ + if( !BPy_BezTriple_Check( pyOb ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a BezTriple" ); + + /* copy bezier in array */ + memcpy( nurb->bezt + index, + BezTriple_FromPyObject( pyOb ), sizeof( BezTriple ) ); + + return 0; /* finished correctly */ + } + else { /* NURBS or POLY */ + int i; + + /* check parameter type */ + if (!PySequence_Check( pyOb )) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a list of 4 (or optionally 5 if the curve is 3D) floats" ); + + size = PySequence_Size( pyOb ); + + /* check sequence size */ + if( size != 4 && size != 5 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a list of 4 (or optionally 5 if the curve is 3D) floats" ); + + /* copy x, y, z, w */ + for( i = 0; i < 4; ++i ) { + PyObject *item = PySequence_GetItem( pyOb, i ); + + if (item == NULL) + return -1; + + nurb->bp[index].vec[i] = ( float ) PyFloat_AsDouble( item ); + Py_DECREF( item ); + } + + if (size == 5) { /* set tilt, if present */ + PyObject *item = PySequence_GetItem( pyOb, i ); + + if (item == NULL) + return -1; + + nurb->bp[index].alfa = ( float ) PyFloat_AsDouble( item ); + Py_DECREF( item ); + } + else { /* if not, set default */ + nurb->bp[index].alfa = 0.0f; + } + + return 0; /* finished correctly */ + } +} + + +/* + * this is an internal routine. not callable directly from python + */ + +PyObject *CurNurb_pointAtIndex( Nurb * nurb, int index ) +{ + PyObject *pyo; + + if( nurb->bp ) { /* we have a nurb curve */ + int i; + + /* add Tilt only if curve is 3D */ + if (nurb->flag & CU_3D) + pyo = PyList_New( 5 ); + else + pyo = PyList_New( 4 ); + + for( i = 0; i < 4; i++ ) { + PyList_SetItem( pyo, i, + PyFloat_FromDouble( nurb->bp[index].vec[i] ) ); + } + + /* add Tilt only if curve is 3D */ + if (nurb->flag & CU_3D) + PyList_SetItem( pyo, 4, PyFloat_FromDouble( nurb->bp[index].alfa ) ); + + } else if( nurb->bezt ) { /* we have a bezier */ + /* if an error occurs, we just pass it on */ + pyo = BezTriple_CreatePyObject( &( nurb->bezt[index] ) ); + + } else /* something is horribly wrong */ + /* neither bp or bezt is set && pntsu != 0 */ + return EXPP_ReturnPyObjError( PyExc_SystemError, + "inconsistant structure found" ); + + return pyo; +} + +/* + dump nurb +*/ + +PyObject *CurNurb_dump( BPy_CurNurb * self ) +{ + BPoint *bp = NULL; + BezTriple *bezt = NULL; + Nurb *nurb = self->nurb; + int npoints = 0; + + if( !self->nurb ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "no Nurb in this CurNurb"); + + printf(" type: %d, mat_nr: %d hide: %d flag: %d", + nurb->type, nurb->mat_nr, nurb->hide, nurb->flag); + printf("\n pntsu: %d, pntsv: %d, resolu: %d resolv: %d", + nurb->pntsu, nurb->pntsv, nurb->resolu, nurb->resolv ); + printf("\n orderu: %d orderv: %d", nurb->orderu, nurb->orderv ); + printf("\n flagu: %d flagv: %d", + nurb->flagu, nurb->flagv ); + + npoints = nurb->pntsu; + + if( nurb->bp ) { /* we have a BPoint */ + int n; + for( n = 0, bp = nurb->bp; + n < npoints; + n++, bp++ ) + { + /* vec[4] */ + printf( "\ncoords[%d]: ", n); + { + int i; + for( i = 0; i < 4; i++){ + printf("%10.3f ", bp->vec[i] ); + } + } + + /* alfa, s[2] */ + printf("\n alpha: %5.2f", bp->alfa); + /* f1, hide */ + printf(" f1 %d hide %d", bp->f1, bp->hide ); + printf("\n"); + } + } + else { /* we have a BezTriple */ + int n; + for( n = 0, bezt = nurb->bezt; + n < npoints; + n++, bezt++ ) + { + int i, j; + printf("\npoint %d: ", n); + for( i = 0; i < 3; i++ ) { + printf("\nvec[%i] ",i ); + for( j = 0; j < 3; j++ ) { + printf(" %5.2f ", bezt->vec[i][j] ); + } + } + + + } + printf("\n"); + } + + Py_RETURN_NONE; +} + +/* + recalc nurb +*/ + +static PyObject *CurNurb_recalc( BPy_CurNurb * self ) +{ + calchandlesNurb ( self->nurb ); + Py_RETURN_NONE; +} + +PyObject *CurNurb_switchDirection( BPy_CurNurb * self ) +{ + if( !self->nurb ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "no Nurb in this CurNurb"); + + switchdirectionNurb( self->nurb ); + + Py_RETURN_NONE; +} + +PyObject *CurNurb_Init( void ) +{ + if( PyType_Ready( &CurNurb_Type ) < 0) + return NULL; + + return Py_InitModule3( "Blender.CurNurb", M_CurNurb_methods, + M_CurNurb_doc ); +} + +/* #####DEPRECATED###### */ + +static PyObject *CurNurb_oldsetType( BPy_CurNurb * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)CurNurb_setType ); +} + +static PyObject *CurNurb_oldsetMatIndex( BPy_CurNurb * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)CurNurb_setMatIndex ); +} + +static PyObject *CurNurb_oldsetFlagU( BPy_CurNurb * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)CurNurb_setFlagU ); +} + +static PyObject *CurNurb_oldsetFlagV( BPy_CurNurb * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)CurNurb_setFlagV ); +} diff --git a/source/blender/python/api2_2x/CurNurb.h b/source/blender/python/api2_2x/CurNurb.h new file mode 100644 index 00000000000..06dbf7190ac --- /dev/null +++ b/source/blender/python/api2_2x/CurNurb.h @@ -0,0 +1,70 @@ +/* + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Stephen Swaney + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef EXPP_NURB_H +#define EXPP_NURB_H + +#include +#include "DNA_curve_types.h" + +extern PyTypeObject CurNurb_Type; + +#define BPy_CurNurb_Check(v) ((v)->ob_type == &CurNurb_Type) /* for type checking */ + +/* Python BPy_CurNurb structure definition */ +typedef struct { + PyObject_HEAD /* required py macro */ + Nurb * nurb; /* pointer to Blender data */ + + /* iterator stuff */ + /* internal ptrs to point data. do not free */ + BPoint *bp; + BezTriple *bezt; + int atEnd; /* iter exhausted flag */ + int nextPoint; + +} BPy_CurNurb; + + +/* + * prototypes + */ + +PyObject *CurNurb_Init( void ); +PyObject *CurNurb_CreatePyObject( Nurb * bzt ); +Nurb *CurNurb_FromPyObject( PyObject * pyobj ); + +PyObject *CurNurb_getPoint( BPy_CurNurb * self, int index ); +PyObject *CurNurb_pointAtIndex( Nurb * nurb, int index ); + +PyObject *CurNurb_appendPointToNurb( Nurb * nurb, PyObject * args ); + +#endif /* EXPP_NURB_H */ diff --git a/source/blender/python/api2_2x/Curve.c b/source/blender/python/api2_2x/Curve.c new file mode 100644 index 00000000000..e849522ef00 --- /dev/null +++ b/source/blender/python/api2_2x/Curve.c @@ -0,0 +1,1659 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Jacques Guignot, Stephen Swaney + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "Curve.h" /*This must come first*/ + +#include "BLI_blenlib.h" +#include "BKE_main.h" +#include "BKE_displist.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_curve.h" +#include "BKE_material.h" +#include "MEM_guardedalloc.h" /* because we wil be mallocing memory */ +#include "CurNurb.h" +#include "SurfNurb.h" +#include "Material.h" +#include "Object.h" +#include "Key.h" +#include "gen_utils.h" +#include "gen_library.h" +#include "mydevice.h" + + +/*****************************************************************************/ +/* The following string definitions are used for documentation strings. */ +/* In Python these will be written to the console when doing a */ +/* Blender.Curve.__doc__ */ +/*****************************************************************************/ + +char M_Curve_doc[] = "The Blender Curve module\n\n\ +This module provides access to **Curve Data** in Blender.\n\ +Functions :\n\ + New(opt name) : creates a new curve object with the given name (optional)\n\ + Get(name) : retreives a curve with the given name (mandatory)\n\ + get(name) : same as Get. Kept for compatibility reasons"; +char M_Curve_New_doc[] = ""; +char M_Curve_Get_doc[] = "xxx"; + + + +/*****************************************************************************/ +/* Python API function prototypes for the Curve module. */ +/*****************************************************************************/ +static PyObject *M_Curve_New( PyObject * self, PyObject * args ); +static PyObject *M_Curve_Get( PyObject * self, PyObject * args ); + + +/*****************************************************************************/ +/* Python BPy_Curve instance methods declarations: */ +/*****************************************************************************/ + +static PyObject *Curve_getPathLen( BPy_Curve * self ); +static PyObject *Curve_setPathLen( BPy_Curve * self, PyObject * args ); +static PyObject *Curve_getTotcol( BPy_Curve * self ); +static PyObject *Curve_setTotcol( BPy_Curve * self, PyObject * args ); +#if 0 +PyObject *Curve_getResolu( BPy_Curve * self ); +PyObject *Curve_setResolu( BPy_Curve * self, PyObject * args ); +PyObject *Curve_getResolv( BPy_Curve * self ); +PyObject *Curve_setResolv( BPy_Curve * self, PyObject * args ); +PyObject *Curve_getWidth( BPy_Curve * self ); +PyObject *Curve_setWidth( BPy_Curve * self, PyObject * args ); +PyObject *Curve_getExt1( BPy_Curve * self ); +PyObject *Curve_setExt1( BPy_Curve * self, PyObject * args ); +PyObject *Curve_getExt2( BPy_Curve * self ); +PyObject *Curve_setExt2( BPy_Curve * self, PyObject * args ); +#endif +static PyObject *Curve_getControlPoint( BPy_Curve * self, PyObject * args ); +static PyObject *Curve_setControlPoint( BPy_Curve * self, PyObject * args ); +static PyObject *Curve_getLoc( BPy_Curve * self ); +static PyObject *Curve_setLoc( BPy_Curve * self, PyObject * args ); +static PyObject *Curve_getRot( BPy_Curve * self ); +static PyObject *Curve_setRot( BPy_Curve * self, PyObject * args ); +static PyObject *Curve_getSize( BPy_Curve * self ); +static PyObject *Curve_setSize( BPy_Curve * self, PyObject * args ); +static PyObject *Curve_getNumCurves( BPy_Curve * self ); +static PyObject *Curve_getKey( BPy_Curve * self ); +static PyObject *Curve_isNurb( BPy_Curve * self, PyObject * args ); +static PyObject *Curve_isCyclic( BPy_Curve * self, PyObject * args); +static PyObject *Curve_getNumPoints( BPy_Curve * self, PyObject * args ); + +static PyObject *Curve_appendPoint( BPy_Curve * self, PyObject * args ); +static PyObject *Curve_appendNurb( BPy_Curve * self, PyObject * args ); + +static PyObject *Curve_getMaterials( BPy_Curve * self ); + +static PyObject *Curve_getBevOb( BPy_Curve * self ); +static PyObject *Curve_setBevOb( BPy_Curve * self, PyObject * args ); + +static PyObject *Curve_getTaperOb( BPy_Curve * self ); +static PyObject *Curve_setTaperOb( BPy_Curve * self, PyObject * args ); +static PyObject *Curve_copy( BPy_Curve * self ); + +static PyObject *Curve_getIter( BPy_Curve * self ); +static PyObject *Curve_iterNext( BPy_Curve * self ); + +PyObject *Curve_getNurb( BPy_Curve * self, int n ); +static int Curve_length( PyInstanceObject * inst ); + + +struct chartrans *text_to_curve( Object * ob, int mode ); +/*****************************************************************************/ +/* Python BPy_Curve methods: */ +/* gives access to */ +/* name, pathlen totcol flag bevresol */ +/* resolu resolv width ext1 ext2 */ +/* controlpoint loc rot size */ +/* numpts */ +/*****************************************************************************/ + + +PyObject *Curve_getName( BPy_Curve * self ) +{ + return PyString_FromString( self->curve->id.name + 2 ); +} + +static int Curve_newsetName( BPy_Curve * self, PyObject * args ) +{ + char *name; + + name = PyString_AsString( args ); + if( !name ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected string argument" ); + + rename_id( &self->curve->id, name ); /* proper way in Blender */ + Curve_update( self ); + + return 0; +} + +static PyObject *Curve_getPathLen( BPy_Curve * self ) +{ + return PyInt_FromLong( ( long ) self->curve->pathlen ); +} + + +static int Curve_newsetPathLen( BPy_Curve * self, PyObject * args ) +{ + PyObject *num; + + if( !PyNumber_Check( args ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected int argument" ); + + num = PyNumber_Int( args ); + self->curve->pathlen = (short)PyInt_AS_LONG( num ); + Py_DECREF( num ); + + return 0; +} + +static PyObject *Curve_getTotcol( BPy_Curve * self ) +{ + return PyInt_FromLong( ( long ) self->curve->totcol ); +} + + +PyObject *Curve_getMode( BPy_Curve * self ) +{ + return PyInt_FromLong( ( long ) self->curve->flag ); +} + + +static int Curve_newsetMode( BPy_Curve * self, PyObject * args ) +{ + PyObject *num; + + if( !PyNumber_Check( args ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected int argument" ); + + num = PyNumber_Int( args ); + self->curve->flag = (short)PyInt_AS_LONG( num ); + Py_DECREF( num ); + + return 0; +} + +PyObject *Curve_getBevresol( BPy_Curve * self ) +{ + return PyInt_FromLong( ( long ) self->curve->bevresol ); +} + +static int Curve_newsetBevresol( BPy_Curve * self, PyObject * args ) +{ + short value; + PyObject *num; + + if( !PyNumber_Check( args ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected int argument" ); + + num = PyNumber_Int( args ); + value = (short)PyInt_AS_LONG( num ); + Py_DECREF( num ); + + if( value > 10 || value < 0 ) + return EXPP_ReturnIntError( PyExc_ValueError, + "acceptable values are between 0 and 10" ); + + self->curve->bevresol = value; + return 0; +} + + +PyObject *Curve_getResolu( BPy_Curve * self ) +{ + return PyInt_FromLong( ( long ) self->curve->resolu ); +} + + +static int Curve_newsetResolu( BPy_Curve * self, PyObject * args ) +{ + short value; + Nurb *nu; + PyObject *num; + + if( !PyNumber_Check( args ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected int argument" ); + + num = PyNumber_Int( args ); + value = (short)PyInt_AS_LONG( num ); + Py_DECREF( num ); + + if( value > 128 || value < 1 ) + return EXPP_ReturnIntError( PyExc_ValueError, + "acceptable values are between 1 and 128" ); + + self->curve->resolu = value; + /* propagate the change through all the curves */ + for( nu = self->curve->nurb.first; nu; nu = nu->next ) + nu->resolu = value; + + return 0; +} + +PyObject *Curve_getResolv( BPy_Curve * self ) +{ + return PyInt_FromLong( ( long ) self->curve->resolv ); +} + +static int Curve_newsetResolv( BPy_Curve * self, PyObject * args ) +{ + short value; + PyObject *num; + + if( !PyNumber_Check( args ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected int argument" ); + + num = PyNumber_Int( args ); + value = (short)PyInt_AS_LONG( num ); + Py_DECREF( num ); + + if(value > 128 || value < 1) + return EXPP_ReturnIntError( PyExc_ValueError, + "acceptable values are between 1 and 128" ); + self->curve->resolv = value; + + return 0; +} + +PyObject *Curve_getWidth( BPy_Curve * self ) +{ + return PyFloat_FromDouble( ( double ) self->curve->width ); +} + + +static int Curve_newsetWidth( BPy_Curve * self, PyObject * args ) +{ + float value; + PyObject *num; + + if( !PyNumber_Check( args ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected float argument" ); + + num = PyNumber_Float( args ); + value = (float)PyFloat_AS_DOUBLE( num ); + Py_DECREF( num ); + + if(value > 2.0f || value < 0.0f) + return EXPP_ReturnIntError( PyExc_ValueError, + "acceptable values are between 2.0 and 0.0" ); + self->curve->width = value; + + return 0; +} + + +PyObject *Curve_getExt1( BPy_Curve * self ) +{ + return PyFloat_FromDouble( ( double ) self->curve->ext1 ); +} + + +static int Curve_newsetExt1( BPy_Curve * self, PyObject * args ) +{ + float value; + PyObject *num; + + if( !PyNumber_Check( args ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected float argument" ); + + num = PyNumber_Float( args ); + value = (float)PyFloat_AS_DOUBLE( num ); + Py_DECREF( num ); + + if(value > 100.0f || value < 0.0f) + return EXPP_ReturnIntError( PyExc_ValueError, + "acceptable values are between 0.0 and 100.0" ); + self->curve->ext1 = value; + + return 0; +} + +PyObject *Curve_getExt2( BPy_Curve * self ) +{ + return PyFloat_FromDouble( ( double ) self->curve->ext2 ); +} + + +static int Curve_newsetExt2( BPy_Curve * self, PyObject * args ) +{ + float value; + PyObject *num; + + if( !PyNumber_Check( args ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected float argument" ); + + num = PyNumber_Float( args ); + value = (float)PyFloat_AS_DOUBLE( num ); + Py_DECREF( num ); + + if(value > 2.0f || value < 0.0f) + return EXPP_ReturnIntError( PyExc_ValueError, + "acceptable values are between 0.0 and 2.0" ); + self->curve->ext2 = value; + + return 0; +} + +/* + * Curve_setControlPoint + * this function sets an EXISTING control point. + * it does NOT add a new one. + */ + +static PyObject *Curve_setControlPoint( BPy_Curve * self, PyObject * args ) +{ + PyObject *listargs = 0; + Nurb *ptrnurb = self->curve->nurb.first; + int numcourbe = 0, numpoint = 0, i, j; + + if( !ptrnurb ) + Py_RETURN_NONE; + + if( ptrnurb->bp ) + if( !PyArg_ParseTuple + ( args, "iiO", &numcourbe, &numpoint, &listargs ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, + "expected int, int, list arguments" ) ); + if( ptrnurb->bezt ) + if( !PyArg_ParseTuple + ( args, "iiO", &numcourbe, &numpoint, &listargs ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, + "expected int, int, list arguments" ) ); + + for( i = 0; i < numcourbe; i++ ) + ptrnurb = ptrnurb->next; + + if( ptrnurb->bp ) + for( i = 0; i < 4; i++ ) + ptrnurb->bp[numpoint].vec[i] = + (float)PyFloat_AsDouble( PyList_GetItem ( listargs, i ) ); + + if( ptrnurb->bezt ) + for( i = 0; i < 3; i++ ) + for( j = 0; j < 3; j++ ) + ptrnurb->bezt[numpoint].vec[i][j] = + (float)PyFloat_AsDouble( PyList_GetItem + ( listargs, + i * 3 + j ) ); + + Py_RETURN_NONE; +} + + +static PyObject *Curve_getControlPoint( BPy_Curve * self, PyObject * args ) +{ + PyObject *liste; + PyObject *item; + + Nurb *ptrnurb; + int i, j; + /* input args: requested curve and point number on curve */ + int numcourbe, numpoint; + + if( !PyArg_ParseTuple( args, "ii", &numcourbe, &numpoint ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int int arguments" ) ); + if( ( numcourbe < 0 ) || ( numpoint < 0 ) ) + return ( EXPP_ReturnPyObjError( PyExc_ValueError, + "arguments must be non-negative" ) ); + + /* if no nurbs in this curve obj */ + if( !self->curve->nurb.first ) + return PyList_New( 0 ); + + /* walk the list of nurbs to find requested numcourbe */ + ptrnurb = self->curve->nurb.first; + for( i = 0; i < numcourbe; i++ ) { + ptrnurb = ptrnurb->next; + if( !ptrnurb ) /* if zero, we ran just ran out of curves */ + return ( EXPP_ReturnPyObjError( PyExc_ValueError, + "curve index out of range" ) ); + } + + /* check numpoint param against pntsu */ + if( numpoint >= ptrnurb->pntsu ) + return ( EXPP_ReturnPyObjError( PyExc_ValueError, + "point index out of range" ) ); + + liste = PyList_New( 0 ); + if( ptrnurb->bp ) { /* if we are a nurb curve, you get 4 values */ + for( i = 0; i < 4; i++ ) { + item = PyFloat_FromDouble( ptrnurb->bp[numpoint].vec[i] ); + PyList_Append( liste, item ); + Py_DECREF(item); + } + } else if( ptrnurb->bezt ) { /* if we are a bezier, you get 9 values */ + for( i = 0; i < 3; i++ ) + for( j = 0; j < 3; j++ ) { + item = PyFloat_FromDouble( ptrnurb->bezt[numpoint].vec[i][j] ); + PyList_Append( liste, item ); + Py_DECREF(item); + } + } + + return liste; +} + +static PyObject *Curve_getLoc( BPy_Curve * self ) +{ + return Py_BuildValue( "[f,f,f]", self->curve->loc[0], + self->curve->loc[1], self->curve->loc[2] ); +} + +static int Curve_newsetLoc( BPy_Curve * self, PyObject * args ) +{ + float loc[3]; + int i; + + if( ( !PyList_Check( args ) && !PyTuple_Check( args ) ) || + PySequence_Size( args ) != 3 ) { +TypeError: + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a sequence of three floats" ); + } + + for( i = 0; i < 3; i++ ) { + PyObject *item = PySequence_GetItem( args, i ); + PyObject *num = PyNumber_Float( item ); + Py_DECREF( item ); + if( !num ) + goto TypeError; + loc[i] = PyFloat_AS_DOUBLE( num ); + Py_DECREF( num ); + } + memcpy( self->curve->loc, loc, sizeof( loc ) ); + + return 0; +} + +static PyObject *Curve_getRot( BPy_Curve * self ) +{ + return Py_BuildValue( "[f,f,f]", self->curve->rot[0], + self->curve->rot[1], self->curve->rot[2] ); +} + +static int Curve_newsetRot( BPy_Curve * self, PyObject * args ) +{ + float rot[3]; + int i; + + if( ( !PyList_Check( args ) && !PyTuple_Check( args ) ) || + PySequence_Size( args ) != 3 ) { +TypeError: + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a sequence of three floats" ); + } + + for( i = 0; i < 3; i++ ) { + PyObject *item = PySequence_GetItem( args, i ); + PyObject *num = PyNumber_Float( item ); + Py_DECREF( item ); + if( !num ) + goto TypeError; + rot[i] = PyFloat_AS_DOUBLE( num ); + Py_DECREF( num ); + } + memcpy( self->curve->rot, rot, sizeof( rot ) ); + + return 0; +} + +static PyObject *Curve_getSize( BPy_Curve * self ) +{ + return Py_BuildValue( "[f,f,f]", self->curve->size[0], + self->curve->size[1], self->curve->size[2] ); +} + +static int Curve_newsetSize( BPy_Curve * self, PyObject * args ) +{ + float size[3]; + int i; + + if( ( !PyList_Check( args ) && !PyTuple_Check( args ) ) || + PySequence_Size( args ) != 3 ) { +TypeError: + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a sequence of three floats" ); + } + + for( i = 0; i < 3; i++ ) { + PyObject *item = PySequence_GetItem( args, i ); + PyObject *num = PyNumber_Float( item ); + Py_DECREF( item ); + if( !num ) + goto TypeError; + size[i] = PyFloat_AS_DOUBLE( num ); + Py_DECREF( num ); + } + memcpy( self->curve->size, size, sizeof( size ) ); + + return 0; +} + +/* + * Count the number of splines in a Curve Object + * int getNumCurves() + */ + +static PyObject *Curve_getNumCurves( BPy_Curve * self ) +{ + Nurb *ptrnurb; + PyObject *ret_val; + int num_curves = 0; /* start with no splines */ + + /* get curve */ + ptrnurb = self->curve->nurb.first; + if( ptrnurb ) { /* we have some nurbs in this curve */ + for(;;) { + ++num_curves; + ptrnurb = ptrnurb->next; + if( !ptrnurb ) /* no more curves */ + break; + } + } + + ret_val = PyInt_FromLong( ( long ) num_curves ); + + if( ret_val ) + return ret_val; + + /* oops! */ + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't get number of curves" ); +} + +/* + * get the key object linked to this curve + */ + +static PyObject *Curve_getKey( BPy_Curve * self ) +{ + PyObject *keyObj; + + if (self->curve->key) + keyObj = Key_CreatePyObject(self->curve->key); + else keyObj = EXPP_incr_ret(Py_None); + + return keyObj; +} + +/* + * count the number of points in a given spline + * int getNumPoints( curve_num=0 ) + * + */ + +static PyObject *Curve_getNumPoints( BPy_Curve * self, PyObject * args ) +{ + Nurb *ptrnurb; + PyObject *ret_val; + int curve_num = 0; /* default spline number */ + int i; + + /* parse input arg */ + if( !PyArg_ParseTuple( args, "|i", &curve_num ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument" ) ); + + /* check arg - must be non-negative */ + if( curve_num < 0 ) + return ( EXPP_ReturnPyObjError( PyExc_ValueError, + "argument must be non-negative" ) ); + + + /* walk the list of curves looking for our curve */ + ptrnurb = self->curve->nurb.first; + if( !ptrnurb ) { /* no splines in this Curve */ + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "no splines in this Curve" ) ); + } + + for( i = 0; i < curve_num; i++ ) { + ptrnurb = ptrnurb->next; + if( !ptrnurb ) /* if zero, we ran just ran out of curves */ + return ( EXPP_ReturnPyObjError( PyExc_ValueError, + "curve index out of range" ) ); + } + + /* pntsu is the number of points in curve */ + ret_val = PyInt_FromLong( ( long ) ptrnurb->pntsu ); + + if( ret_val ) + return ret_val; + + /* oops! */ + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't get number of points for curve" ); +} + +/* + * Test whether a given spline of a Curve is a nurb + * as opposed to a bezier + * int isNurb( curve_num=0 ) + */ + +static PyObject *Curve_isNurb( BPy_Curve * self, PyObject * args ) +{ + int curve_num = 0; /* default value */ + int is_nurb; + Nurb *ptrnurb; + PyObject *ret_val; + int i; + + /* parse and check input args */ + if( !PyArg_ParseTuple( args, "|i", &curve_num ) ) { + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument" ) ); + } + if( curve_num < 0 ) { + return ( EXPP_ReturnPyObjError( PyExc_ValueError, + "curve number must be non-negative" ) ); + } + + ptrnurb = self->curve->nurb.first; + + if( !ptrnurb ) /* no splines in this curve */ + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "no splines in this Curve" ) ); + + for( i = 0; i < curve_num; i++ ) { + ptrnurb = ptrnurb->next; + if( !ptrnurb ) /* if zero, we ran just ran out of curves */ + return ( EXPP_ReturnPyObjError( PyExc_ValueError, + "curve index out of range" ) ); + } + + /* right now, there are only two curve types, nurb and bezier. */ + is_nurb = ptrnurb->bp ? 1 : 0; + + ret_val = PyInt_FromLong( ( long ) is_nurb ); + if( ret_val ) + return ret_val; + + /* oops */ + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't get curve type" ) ); +} + +/* trying to make a check for closedness (cyclic), following on isNurb (above) + copy-pasting done by antont@kyperjokki.fi */ + +static PyObject *Curve_isCyclic( BPy_Curve * self, PyObject * args ) +{ + int curve_num = 0; /* default value */ + /* unused:*/ + /* int is_cyclic; + * PyObject *ret_val;*/ + Nurb *ptrnurb; + int i; + + /* parse and check input args */ + if( !PyArg_ParseTuple( args, "|i", &curve_num ) ) { + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument" ) ); + } + if( curve_num < 0 ) { + return ( EXPP_ReturnPyObjError( PyExc_ValueError, + "curve number must be non-negative" ) ); + } + + ptrnurb = self->curve->nurb.first; + + if( !ptrnurb ) /* no splines in this curve */ + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "no splines in this Curve" ) ); + + for( i = 0; i < curve_num; i++ ) { + ptrnurb = ptrnurb->next; + if( !ptrnurb ) /* if zero, we ran just ran out of curves */ + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "curve index out of range" ) ); + } + + if( ptrnurb->flagu & CU_CYCLIC ){ + return EXPP_incr_ret_True(); + } else { + return EXPP_incr_ret_False(); + } +} + + +/* + * Curve_appendPoint( numcurve, new_point ) + * append a new point to indicated spline + */ + +static PyObject *Curve_appendPoint( BPy_Curve * self, PyObject * args ) +{ + int i; + int nurb_num; /* index of curve we append to */ + PyObject *coord_args; /* coords for new point */ + Nurb *nurb = self->curve->nurb.first; /* first nurb in Curve */ + +/* fixme - need to malloc new Nurb */ + if( !nurb ) + return ( EXPP_ReturnPyObjError + ( PyExc_AttributeError, "no nurbs in this Curve" ) ); + + if( !PyArg_ParseTuple( args, "iO", &nurb_num, &coord_args ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, + "expected int, coords as arguments" ) ); + + /* + chase down the list of Nurbs looking for our curve. + */ + for( i = 0; i < nurb_num; i++ ) { + nurb = nurb->next; + if( !nurb ) /* we ran off end of list */ + return EXPP_ReturnPyObjError( PyExc_ValueError, + "curve index out of range" ); + } + return CurNurb_appendPointToNurb( nurb, coord_args ); +} + + +/**** + appendNurb( new_point ) + create a new nurb in the Curve and add the point param to it. + returns a refernce to the newly created nurb. +*****/ + +static PyObject *Curve_appendNurb( BPy_Curve * self, PyObject * value ) +{ + Nurb *new_nurb; + /* malloc new nurb */ + new_nurb = ( Nurb * ) MEM_callocN( sizeof( Nurb ), "appendNurb" ); + if( !new_nurb ) + return EXPP_ReturnPyObjError + ( PyExc_MemoryError, "unable to malloc Nurb" ); + + if( CurNurb_appendPointToNurb( new_nurb, value ) ) { + new_nurb->resolu = self->curve->resolu; + new_nurb->resolv = self->curve->resolv; + new_nurb->hide = 0; + new_nurb->flag = 1; + + + if( new_nurb->bezt ) { /* do setup for bezt */ + new_nurb->type = CU_BEZIER; + new_nurb->bezt->h1 = HD_ALIGN; + new_nurb->bezt->h2 = HD_ALIGN; + new_nurb->bezt->f1 = 1; + new_nurb->bezt->f2 = 1; + new_nurb->bezt->f3 = 1; + new_nurb->bezt->hide = 0; + /* calchandlesNurb( new_nurb ); */ + } else { /* set up bp */ + new_nurb->pntsv = 1; + new_nurb->type = CU_NURBS; + new_nurb->orderu = 4; + new_nurb->flagu = 0; + new_nurb->flagv = 0; + new_nurb->bp->f1 = 0; + new_nurb->bp->hide = 0; + new_nurb->knotsu = 0; + /*makenots( new_nurb, 1, new_nurb->flagu >> 1); */ + } + BLI_addtail( &self->curve->nurb, new_nurb); + + } else { + freeNurb( new_nurb ); + return NULL; /* with PyErr already set */ + } + + return CurNurb_CreatePyObject( new_nurb ); +} + + +/* + * Curve_update( ) + * method to update display list for a Curve. + * used. after messing with control points + */ + +PyObject *Curve_update( BPy_Curve * self ) +{ + Nurb *nu = self->curve->nurb.first; + + /* recalculate handles for each curve: calchandlesNurb() will make + * sure curves are bezier first */ + while( nu ) { + calchandlesNurb ( nu ); + nu = nu->next; + } + + Object_updateDag( (void*) self->curve ); + + Py_RETURN_NONE; +} + +/* + * Curve_getMaterials + * + */ + +static PyObject *Curve_getMaterials( BPy_Curve * self ) +{ + return EXPP_PyList_fromMaterialList( self->curve->mat, + self->curve->totcol, 1 ); +} + +static int Curve_setMaterials( BPy_Curve *self, PyObject * value ) +{ + Material **matlist; + int len; + + if( !PySequence_Check( value ) || + !EXPP_check_sequence_consistency( value, &Material_Type ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "sequence should only contain materials or None)" ); + + len = PySequence_Size( value ); + if( len > 16 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "list can't have more than 16 materials" ); + + /* free old material list (if it exists) and adjust user counts */ + if( self->curve->mat ) { + Curve *cur = self->curve; + int i; + for( i = cur->totcol; i-- > 0; ) + if( cur->mat[i] ) + cur->mat[i]->id.us--; + MEM_freeN( cur->mat ); + } + + /* build the new material list, increment user count, store it */ + + matlist = EXPP_newMaterialList_fromPyList( value ); + EXPP_incr_mats_us( matlist, len ); + self->curve->mat = matlist; + self->curve->totcol = (short)len; + +/**@ This is another ugly fix due to the weird material handling of blender. + * it makes sure that object material lists get updated (by their length) + * according to their data material lists, otherwise blender crashes. + * It just stupidly runs through all objects...BAD BAD BAD. + */ + + test_object_materials( ( ID * ) self->curve ); + + return 0; +} + +/*****************************************************************************/ +/* Function: Curve_getBevOb */ +/* Description: Get the bevel object assign to the curve. */ +/*****************************************************************************/ +static PyObject *Curve_getBevOb( BPy_Curve * self) +{ + if( self->curve->bevobj ) { + return Object_CreatePyObject( self->curve->bevobj ); + } + + return EXPP_incr_ret( Py_None ); +} + +/*****************************************************************************/ +/* Function: Curve_newsetBevOb */ +/* Description: Assign a bevel object to the curve. */ +/*****************************************************************************/ +static int Curve_newsetBevOb( BPy_Curve * self, PyObject * args ) +{ + + if (BPy_Object_Check( args ) && ((BPy_Object *)args)->object->data == self->curve ) + return EXPP_ReturnIntError( PyExc_ValueError, + "Can't bevel an object to itself" ); + + return GenericLib_assignData(args, (void **) &self->curve->bevobj, 0, 0, ID_OB, OB_CURVE); +} + +/*****************************************************************************/ +/* Function: Curve_getTaperOb */ +/* Description: Get the taper object assign to the curve. */ +/*****************************************************************************/ + +static PyObject *Curve_getTaperOb( BPy_Curve * self) +{ + if( self->curve->taperobj ) + return Object_CreatePyObject( self->curve->taperobj ); + + Py_RETURN_NONE; +} + +/*****************************************************************************/ +/* Function: Curve_newsetTaperOb */ +/* Description: Assign a taper object to the curve. */ +/*****************************************************************************/ + +static int Curve_newsetTaperOb( BPy_Curve * self, PyObject * args ) +{ + if (BPy_Object_Check( args ) && ((BPy_Object *)args)->object->data == self->curve ) + return EXPP_ReturnIntError( PyExc_ValueError, + "Can't taper an object to itself" ); + + return GenericLib_assignData(args, (void **) &self->curve->taperobj, 0, 0, ID_OB, OB_CURVE); +} + +/*****************************************************************************/ +/* Function: Curve_copy */ +/* Description: Return a copy of this curve data. */ +/*****************************************************************************/ + +PyObject *Curve_copy( BPy_Curve * self ) +{ + BPy_Curve *pycurve; /* for Curve Data object wrapper in Python */ + Curve *blcurve = 0; /* for actual Curve Data we create in Blender */ + + /* copies the data */ + blcurve = copy_curve( self->curve ); /* first create the Curve Data in Blender */ + + if( blcurve == NULL ) /* bail out if add_curve() failed */ + return ( EXPP_ReturnPyObjError + ( PyExc_RuntimeError, + "couldn't create Curve Data in Blender" ) ); + + /* return user count to zero because add_curve() inc'd it */ + blcurve->id.us = 0; + + /* create python wrapper obj */ + pycurve = ( BPy_Curve * ) PyObject_NEW( BPy_Curve, &Curve_Type ); + + if( pycurve == NULL ) + return ( EXPP_ReturnPyObjError + ( PyExc_MemoryError, + "couldn't create Curve Data object" ) ); + + pycurve->curve = blcurve; /* link Python curve wrapper to Blender Curve */ + return ( PyObject * ) pycurve; +} + + +/* + * Curve_getIter + * + * create an iterator for our Curve. + * this iterator returns the Nurbs for this Curve. + * the iter_pointer always points to the next available item or null + */ + +static PyObject *Curve_getIter( BPy_Curve * self ) +{ + self->iter_pointer = self->curve->nurb.first; + + Py_INCREF( self ); + return ( PyObject * ) self; + +} + + +/* + * Curve_iterNext + * get the next item. + * iter_pointer always points to the next available element + * or NULL if at the end of the list. + */ + +static PyObject *Curve_iterNext( BPy_Curve * self ) +{ + Nurb *pnurb; + + if( self->iter_pointer ) { + pnurb = self->iter_pointer; + self->iter_pointer = pnurb->next; /* advance iterator */ + if( (pnurb->type & 7) == CU_BEZIER || pnurb->pntsv <= 1 ) + return CurNurb_CreatePyObject( pnurb ); /* make a bpy_curnurb */ + else + return SurfNurb_CreatePyObject( pnurb ); /* make a bpy_surfnurb */ + } + + /* if iter_pointer was null, we are at end */ + return EXPP_ReturnPyObjError( PyExc_StopIteration, + "iterator at end" ); +} + +/* tp_sequence methods */ + +/* + * Curve_length + * returns the number of curves in a Curve + * this is a tp_as_sequence method, not a regular instance method. + */ + +static int Curve_length( PyInstanceObject * inst ) +{ + if( BPy_Curve_Check( ( PyObject * ) inst ) ) + return ( ( int ) PyInt_AsLong + ( Curve_getNumCurves( ( BPy_Curve * ) inst ) ) ); + + return EXPP_ReturnIntError( PyExc_RuntimeError, + "arg is not a BPy_Curve" ); + +} + +/* + * Curve_getNurb + * returns the Nth nurb in a Curve. + * this is one of the tp_as_sequence methods, hence the int N argument. + * it is called via the [] operator, not as a usual instance method. + */ + +PyObject *Curve_getNurb( BPy_Curve * self, int n ) +{ + Nurb *pNurb; + int i; + + /* bail if index < 0 */ + if( n < 0 ) + return ( EXPP_ReturnPyObjError( PyExc_IndexError, + "index less than 0" ) ); + /* bail if no Nurbs in Curve */ + if( self->curve->nurb.first == 0 ) + return ( EXPP_ReturnPyObjError( PyExc_IndexError, + "no Nurbs in this Curve" ) ); + /* set pointer to nth Nurb */ + for( pNurb = self->curve->nurb.first, i = 0; + pNurb != 0 && i < n; pNurb = pNurb->next, ++i ) + /**/; + + if( !pNurb ) /* we came to the end of the list */ + return ( EXPP_ReturnPyObjError( PyExc_IndexError, + "index out of range" ) ); + + /* until there is a Surface BPyType, distinquish between a curve and a + * surface based on whether it's a Bezier and the v size */ + if( (pNurb->type & 7) == CU_BEZIER || pNurb->pntsv <= 1 ) + return CurNurb_CreatePyObject( pNurb ); /* make a bpy_curnurb */ + else + return SurfNurb_CreatePyObject( pNurb ); /* make a bpy_surfnurb */ + +} + +/*****************************************************************************/ +/* Function: Curve_compare */ +/* Description: This compares 2 curve python types, == or != only. */ +/*****************************************************************************/ +static int Curve_compare( BPy_Curve * a, BPy_Curve * b ) +{ + return ( a->curve == b->curve ) ? 0 : -1; +} + +/*****************************************************************************/ +/* Function: Curve_repr */ +/* Description: This is a callback function for the BPy_Curve type. It */ +/* builds a meaninful string to represent curve objects. */ +/*****************************************************************************/ +static PyObject *Curve_repr( BPy_Curve * self ) +{ /* used by 'repr' */ + + return PyString_FromFormat( "[Curve \"%s\"]", + self->curve->id.name + 2 ); +} + +/* attributes for curves */ + +static PyGetSetDef Curve_getseters[] = { + GENERIC_LIB_GETSETATTR, + {"pathlen", + (getter)Curve_getPathLen, (setter)Curve_newsetPathLen, + "The path length, used to set the number of frames for an animation (not the physical length)", + NULL}, + {"totcol", + (getter)Curve_getTotcol, (setter)NULL, + "The maximum number of linked materials", + NULL}, + {"flag", + (getter)Curve_getMode, (setter)Curve_newsetMode, + "The flag bitmask", + NULL}, + {"bevresol", + (getter)Curve_getBevresol, (setter)Curve_newsetBevresol, + "The bevel resolution", + NULL}, + {"resolu", + (getter)Curve_getResolu, (setter)Curve_newsetResolu, + "The resolution in U direction", + NULL}, + {"resolv", + (getter)Curve_getResolv, (setter)Curve_newsetResolv, + "The resolution in V direction", + NULL}, + {"width", + (getter)Curve_getWidth, (setter)Curve_newsetWidth, + "The curve width", + NULL}, + {"ext1", + (getter)Curve_getExt1, (setter)Curve_newsetExt1, + "The extent1 value (for bevels)", + NULL}, + {"ext2", + (getter)Curve_getExt2, (setter)Curve_newsetExt2, + "The extent2 value (for bevels)", + NULL}, + {"loc", + (getter)Curve_getLoc, (setter)Curve_newsetLoc, + "The data location (from the center)", + NULL}, + {"rot", + (getter)Curve_getRot, (setter)Curve_newsetRot, + "The data rotation (from the center)", + NULL}, + {"size", + (getter)Curve_getSize, (setter)Curve_newsetSize, + "The data size (from the center)", + NULL}, + {"bevob", + (getter)Curve_getBevOb, (setter)Curve_newsetBevOb, + "The bevel object", + NULL}, + {"taperob", + (getter)Curve_getTaperOb, (setter)Curve_newsetTaperOb, + "The taper object", + NULL}, + {"key", + (getter)Curve_getKey, (setter)NULL, + "The shape key for the curve (if any)", + NULL}, + {"materials", + (getter)Curve_getMaterials, (setter)Curve_setMaterials, + "The materials associated with the curve", + NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ + +}; + +/*****************************************************************************/ +/* Function: M_Curve_New */ +/* Python equivalent: Blender.Curve.New */ +/*****************************************************************************/ +static PyObject *M_Curve_New( PyObject * self, PyObject * args ) +{ + char *name = "Curve"; + BPy_Curve *pycurve; /* for Curve Data object wrapper in Python */ + Curve *blcurve = 0; /* for actual Curve Data we create in Blender */ + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, + "expected string argument or no argument" ) ); + + blcurve = add_curve( name, OB_CURVE ); /* first create the Curve Data in Blender */ + + if( blcurve == NULL ) /* bail out if add_curve() failed */ + return ( EXPP_ReturnPyObjError + ( PyExc_RuntimeError, + "couldn't create Curve Data in Blender" ) ); + + /* return user count to zero because add_curve() inc'd it */ + blcurve->id.us = 0; + /* create python wrapper obj */ + pycurve = ( BPy_Curve * ) PyObject_NEW( BPy_Curve, &Curve_Type ); + + if( pycurve == NULL ) + return ( EXPP_ReturnPyObjError + ( PyExc_MemoryError, + "couldn't create Curve Data object" ) ); + + pycurve->curve = blcurve; /* link Python curve wrapper to Blender Curve */ + + return ( PyObject * ) pycurve; +} + +/*****************************************************************************/ +/* Function: M_Curve_Get */ +/* Python equivalent: Blender.Curve.Get */ +/*****************************************************************************/ +static PyObject *M_Curve_Get( PyObject * self, PyObject * args ) +{ + + char *name = NULL; + Curve *curv_iter; + BPy_Curve *wanted_curv; + + if( !PyArg_ParseTuple( args, "|s", &name ) ) /* expects nothing or a string */ + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ) ); + if( name ) { /*a name has been given */ + /* Use the name to search for the curve requested */ + wanted_curv = NULL; + curv_iter = G.main->curve.first; + + while( ( curv_iter ) && ( wanted_curv == NULL ) ) { + + if( strcmp( name, curv_iter->id.name + 2 ) == 0 ) { + wanted_curv = ( BPy_Curve * ) + PyObject_NEW( BPy_Curve, &Curve_Type ); + if( wanted_curv ) + wanted_curv->curve = curv_iter; + } + + curv_iter = curv_iter->id.next; + } + + if( wanted_curv == NULL ) { /* Requested curve doesn't exist */ + char error_msg[64]; + PyOS_snprintf( error_msg, sizeof( error_msg ), + "Curve \"%s\" not found", name ); + return ( EXPP_ReturnPyObjError + ( PyExc_NameError, error_msg ) ); + } + + + return ( PyObject * ) wanted_curv; + } /* end of if(name) */ + else { + /* no name has been given; return a list of all curves by name. */ + PyObject *curvlist; + + curv_iter = G.main->curve.first; + curvlist = PyList_New( 0 ); + + if( curvlist == NULL ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyList" ) ); + + while( curv_iter ) { + BPy_Curve *found_cur = + ( BPy_Curve * ) PyObject_NEW( BPy_Curve, + &Curve_Type ); + found_cur->curve = curv_iter; + PyList_Append( curvlist, ( PyObject * ) found_cur ); + Py_DECREF(found_cur); + curv_iter = curv_iter->id.next; + } + + return ( curvlist ); + } /* end of else */ +} + +/*****************************************************************************/ +/* Python method definitions for Blender.Curve module: */ +/*****************************************************************************/ +struct PyMethodDef M_Curve_methods[] = { + {"New", ( PyCFunction ) M_Curve_New, METH_VARARGS, M_Curve_New_doc}, + {"Get", M_Curve_Get, METH_VARARGS, M_Curve_Get_doc}, + {"get", M_Curve_Get, METH_VARARGS, M_Curve_Get_doc}, + {NULL, NULL, 0, NULL} +}; + + +/*****************************************************************************/ +/* Python BPy_Curve instance methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_Curve_methods[] = { + {"getName", ( PyCFunction ) Curve_getName, + METH_NOARGS, "() - Return Curve Data name"}, + {"setName", ( PyCFunction ) Curve_setName, + METH_VARARGS, "() - Sets Curve Data name"}, + {"getPathLen", ( PyCFunction ) Curve_getPathLen, + METH_NOARGS, "() - Return Curve path length"}, + {"setPathLen", ( PyCFunction ) Curve_setPathLen, + METH_VARARGS, "(int) - Sets Curve path length"}, + {"getTotcol", ( PyCFunction ) Curve_getTotcol, + METH_NOARGS, "() - Return the number of materials of the curve"}, + {"setTotcol", ( PyCFunction ) Curve_setTotcol, + METH_VARARGS, "(int) - Sets the number of materials of the curve"}, + {"getFlag", ( PyCFunction ) Curve_getMode, + METH_NOARGS, "() - Return flag (see the doc for semantic)"}, + {"setFlag", ( PyCFunction ) Curve_setMode, + METH_VARARGS, "(int) - Sets flag (see the doc for semantic)"}, + {"getBevresol", ( PyCFunction ) Curve_getBevresol, + METH_NOARGS, "() - Return bevel resolution"}, + {"setBevresol", ( PyCFunction ) Curve_setBevresol, + METH_VARARGS, "(int) - Sets bevel resolution"}, + {"getResolu", ( PyCFunction ) Curve_getResolu, + METH_NOARGS, "() - Return U resolution"}, + {"setResolu", ( PyCFunction ) Curve_setResolu, + METH_VARARGS, "(int) - Sets U resolution"}, + {"getResolv", ( PyCFunction ) Curve_getResolv, + METH_NOARGS, "() - Return V resolution"}, + {"setResolv", ( PyCFunction ) Curve_setResolv, + METH_VARARGS, "(int) - Sets V resolution"}, + {"getWidth", ( PyCFunction ) Curve_getWidth, + METH_NOARGS, "() - Return curve width"}, + {"setWidth", ( PyCFunction ) Curve_setWidth, + METH_VARARGS, "(int) - Sets curve width"}, + {"getExt1", ( PyCFunction ) Curve_getExt1, + METH_NOARGS, "() - Returns extent 1 of the bevel"}, + {"setExt1", ( PyCFunction ) Curve_setExt1, + METH_VARARGS, "(int) - Sets extent 1 of the bevel"}, + {"getExt2", ( PyCFunction ) Curve_getExt2, + METH_NOARGS, "() - Return extent 2 of the bevel "}, + {"setExt2", ( PyCFunction ) Curve_setExt2, + METH_VARARGS, "(int) - Sets extent 2 of the bevel "}, + {"getControlPoint", ( PyCFunction ) Curve_getControlPoint, + METH_VARARGS, "(int numcurve,int numpoint) -\ +Gets a control point.Depending upon the curve type, returne a list of 4 or 9 floats"}, + {"setControlPoint", ( PyCFunction ) Curve_setControlPoint, + METH_VARARGS, "(int numcurve,int numpoint,float x,float y,float z,\ +float w)(nurbs) or (int numcurve,int numpoint,float x1,...,x9(bezier)\ +Sets a control point "}, + {"getLoc", ( PyCFunction ) Curve_getLoc, + METH_NOARGS, "() - Gets Location of the curve (a 3-tuple) "}, + {"setLoc", ( PyCFunction ) Curve_setLoc, + METH_VARARGS, "(3-tuple) - Sets Location "}, + {"getRot", ( PyCFunction ) Curve_getRot, + METH_NOARGS, "() - Gets curve rotation"}, + {"setRot", ( PyCFunction ) Curve_setRot, + METH_VARARGS, "(3-tuple) - Sets curve rotation"}, + {"getSize", ( PyCFunction ) Curve_getSize, + METH_NOARGS, "() - Gets curve size"}, + {"setSize", ( PyCFunction ) Curve_setSize, + METH_VARARGS, "(3-tuple) - Sets curve size"}, + {"getNumCurves", ( PyCFunction ) Curve_getNumCurves, + METH_NOARGS, "() - Gets number of curves in Curve"}, + {"getKey", ( PyCFunction ) Curve_getKey, + METH_NOARGS, "() - Gets curve key"}, + {"isNurb", ( PyCFunction ) Curve_isNurb, + METH_VARARGS, + "(nothing or integer) - returns 1 if curve is type Nurb, O otherwise."}, + {"isCyclic", ( PyCFunction ) Curve_isCyclic, + METH_VARARGS, "( nothing or integer ) - returns true if curve is cyclic (closed), false otherwise."}, + {"getNumPoints", ( PyCFunction ) Curve_getNumPoints, + METH_VARARGS, + "(nothing or integer) - returns the number of points of the specified curve"}, + {"appendPoint", ( PyCFunction ) Curve_appendPoint, METH_VARARGS, + "( int numcurve, list of coordinates) - adds a new point to end of curve"}, + {"appendNurb", ( PyCFunction ) Curve_appendNurb, METH_O, + "( new_nurb ) - adds a new nurb to the Curve"}, + {"update", ( PyCFunction ) Curve_update, METH_NOARGS, + "( ) - updates display lists after changes to Curve"}, + {"getMaterials", ( PyCFunction ) Curve_getMaterials, METH_NOARGS, + "() - returns list of materials assigned to this Curve"}, + {"getBevOb", ( PyCFunction ) Curve_getBevOb, METH_NOARGS, + "() - returns Bevel Object assigned to this Curve"}, + {"setBevOb", ( PyCFunction ) Curve_setBevOb, METH_VARARGS, + "() - assign a Bevel Object to this Curve"}, + {"getTaperOb", ( PyCFunction ) Curve_getTaperOb, METH_NOARGS, + "() - returns Taper Object assigned to this Curve"}, + {"setTaperOb", ( PyCFunction ) Curve_setTaperOb, METH_VARARGS, + "() - assign a Taper Object to this Curve"}, + {"__copy__", ( PyCFunction ) Curve_copy, METH_NOARGS, + "() - make a copy of this curve data"}, + {"copy", ( PyCFunction ) Curve_copy, METH_NOARGS, + "() - make a copy of this curve data"}, + {NULL, NULL, 0, NULL} +}; + + +/*****************************************************************************/ +/* Python Curve_Type callback function prototypes: */ +/*****************************************************************************/ +static int Curve_compare( BPy_Curve * a, BPy_Curve * b ); +static PyObject *Curve_repr( BPy_Curve * msh ); + +static PySequenceMethods Curve_as_sequence = { + ( inquiry ) Curve_length, /* sq_length */ + ( binaryfunc ) 0, /* sq_concat */ + ( intargfunc ) 0, /* sq_repeat */ + ( intargfunc ) Curve_getNurb, /* sq_item */ + ( intintargfunc ) 0, /* sq_slice */ + 0, /* sq_ass_item */ + 0, /* sq_ass_slice */ + ( objobjproc ) 0, /* sq_contains */ + 0, + 0 +}; + +/*****************************************************************************/ +/* Python Curve_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject Curve_Type = { + PyObject_HEAD_INIT( NULL ) /* required macro */ + 0, /* ob_size */ + "Curve", /* tp_name */ + sizeof( BPy_Curve ), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + NULL, /* tp_dealloc */ + 0, /* tp_print */ + ( getattrfunc ) NULL, /* tp_getattr */ + ( setattrfunc ) NULL, /* tp_setattr */ + ( cmpfunc ) Curve_compare, /* tp_compare */ + ( reprfunc ) Curve_repr, /* tp_repr */ + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + &Curve_as_sequence, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + ( getiterfunc ) Curve_getIter, /* getiterfunc tp_iter; */ + ( iternextfunc ) Curve_iterNext, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_Curve_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + Curve_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + + +/*****************************************************************************/ +/* Function: Curve_Init */ +/*****************************************************************************/ +PyObject *Curve_Init( void ) +{ + PyObject *submodule; + + if( PyType_Ready( &Curve_Type) < 0) /* set exception. -1 is failure */ + return NULL; + + submodule = + Py_InitModule3( "Blender.Curve", M_Curve_methods, + M_Curve_doc ); + return ( submodule ); +} + + +/* + * Curve_CreatePyObject + * constructor to build a py object from blender data + */ + +PyObject *Curve_CreatePyObject( struct Curve * curve ) +{ + BPy_Curve *blen_object; + + blen_object = ( BPy_Curve * ) PyObject_NEW( BPy_Curve, &Curve_Type ); + + if( blen_object == NULL ) { + return ( NULL ); + } + blen_object->curve = curve; + return ( ( PyObject * ) blen_object ); + +} + +struct Curve *Curve_FromPyObject( PyObject * py_obj ) +{ + BPy_Curve *blen_obj; + + blen_obj = ( BPy_Curve * ) py_obj; + return ( blen_obj->curve ); + +} + +/* #####DEPRECATED###### */ + +PyObject *Curve_setName( BPy_Curve * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Curve_newsetName ); +} + +static PyObject *Curve_setPathLen( BPy_Curve * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)Curve_newsetPathLen ); +} + +static PyObject *Curve_setTotcol( BPy_Curve * self, PyObject * args ) +{ + if( !PyArg_ParseTuple( args, "i", &( self->curve->totcol ) ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument" ); + Py_RETURN_NONE; +} + +PyObject *Curve_setMode( BPy_Curve * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)Curve_newsetMode ); +} + +PyObject *Curve_setBevresol( BPy_Curve * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)Curve_newsetBevresol); +} + +PyObject *Curve_setResolu( BPy_Curve * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)Curve_newsetResolu ); +} + +PyObject *Curve_setResolv( BPy_Curve * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)Curve_newsetResolv ); +} + +PyObject *Curve_setWidth( BPy_Curve * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)Curve_newsetWidth ); +} + +PyObject *Curve_setExt1( BPy_Curve * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)Curve_newsetExt1 ); +} + +PyObject *Curve_setExt2( BPy_Curve * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)Curve_newsetExt2 ); +} + +static PyObject *Curve_setLoc( BPy_Curve * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)Curve_newsetLoc ); +} + +static PyObject *Curve_setRot( BPy_Curve * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)Curve_newsetRot ); +} + +static PyObject *Curve_setSize( BPy_Curve * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)Curve_newsetSize ); +} + +PyObject *Curve_setBevOb( BPy_Curve * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)Curve_newsetBevOb ); +} + +PyObject *Curve_setTaperOb( BPy_Curve * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)Curve_newsetTaperOb ); +} + diff --git a/source/blender/python/api2_2x/Curve.h b/source/blender/python/api2_2x/Curve.h new file mode 100644 index 00000000000..70be37500f1 --- /dev/null +++ b/source/blender/python/api2_2x/Curve.h @@ -0,0 +1,78 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Jacques Guignot, Stephen Swaney + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_CURVE_H +#define EXPP_CURVE_H + +#include +#include "DNA_curve_types.h" + +extern PyTypeObject Curve_Type; + +#define BPy_Curve_Check(v) ((v)->ob_type==&Curve_Type) + +/* Python BPy_Curve structure definition */ +typedef struct { + PyObject_HEAD /* required py macro */ + Curve * curve; /* libdata must be second */ + /* pointer for iterator: does not point to owned memory */ + Nurb *iter_pointer; +} BPy_Curve; + + +/* + * protoypes + */ + +PyObject *Curve_Init( void ); +PyObject *Curve_CreatePyObject( struct Curve * curve ); +struct Curve *Curve_FromPyObject( PyObject * py_obj ); +PyObject *Curve_update( BPy_Curve * self ); + +PyObject *Curve_getName( BPy_Curve * self ); +PyObject *Curve_setName( BPy_Curve * self, PyObject * args ); +PyObject *Curve_getMode( BPy_Curve * self ); +PyObject *Curve_setMode( BPy_Curve * self, PyObject * args ); +PyObject *Curve_getBevresol( BPy_Curve * self ); +PyObject *Curve_setBevresol( BPy_Curve * self, PyObject * args ); +PyObject *Curve_getResolu( BPy_Curve * self ); +PyObject *Curve_setResolu( BPy_Curve * self, PyObject * args ); +PyObject *Curve_getResolv( BPy_Curve * self ); +PyObject *Curve_setResolv( BPy_Curve * self, PyObject * args ); +PyObject *Curve_getExt1( BPy_Curve * self ); +PyObject *Curve_setExt1( BPy_Curve * self, PyObject * args ); +PyObject *Curve_getExt2( BPy_Curve * self ); +PyObject *Curve_setExt2( BPy_Curve * self, PyObject * args ); +PyObject *Curve_getWidth( BPy_Curve * self ); +PyObject *Curve_setWidth( BPy_Curve * self, PyObject * args ); + +#endif /* EXPP_CURVE_H */ diff --git a/source/blender/python/api2_2x/Draw.c b/source/blender/python/api2_2x/Draw.c new file mode 100644 index 00000000000..54ff927a2b3 --- /dev/null +++ b/source/blender/python/api2_2x/Draw.c @@ -0,0 +1,2210 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano, Campbell Barton, Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +/* This file is the Blender.Draw part of opy_draw.c, from the old + * bpython/intern dir, with minor changes to adapt it to the new Python + * implementation. Non-trivial original comments are marked with an + * @ symbol at their beginning. */ + +#include "Draw.h" /*This must come first*/ + +#include "BLI_blenlib.h" +#include "MEM_guardedalloc.h" +#include "BMF_Api.h" +#include "DNA_screen_types.h" +#include "BKE_global.h" +#include "BKE_image.h" +#include "BKE_object.h" +#include "BKE_main.h" +#include "BKE_utildefines.h" +#include "BIF_gl.h" +#include "BIF_mywindow.h" +#include "BIF_screen.h" +#include "BIF_space.h" +#include "BIF_interface.h" +#include "BIF_toolbox.h" +#include "BPI_script.h" /* script struct */ +#include "Image.h" /* for accessing Blender.Image objects */ +#include "IMB_imbuf_types.h" /* for the IB_rect define */ +#include "interface.h" +#include "mydevice.h" /*@ for all the event constants */ +#include "gen_utils.h" +#include "Window.h" +#include "../BPY_extern.h" + +/* used so we can get G.scene->r.cfra for getting the +current image frame, some images change frame if they are a sequence */ +#include "DNA_scene_types.h" + +/* these delimit the free range for button events */ +#define EXPP_BUTTON_EVENTS_OFFSET 1001 +#define EXPP_BUTTON_EVENTS_MIN 0 +#define EXPP_BUTTON_EVENTS_MAX 15382 /* 16384 - 1 - OFFSET */ + +#define ButtonObject_Check(v) ((v)->ob_type == &Button_Type) + +#define UI_METHOD_ERRORCHECK \ + if (check_button_event(&event) == -1)\ + return EXPP_ReturnPyObjError( PyExc_AttributeError,\ + "button event argument must be in the range [0, 16382]");\ + if (callback && !PyCallable_Check(callback))\ + return EXPP_ReturnPyObjError( PyExc_ValueError,\ + "callback is not a python function");\ + +/* pointer to main dictionary defined in Blender.c */ +extern PyObject *g_blenderdict; + +/*@ hack to flag that window redraw has happened inside slider callback: */ +int EXPP_disable_force_draw = 0; + +/* forward declarations for internal functions */ +static void Button_dealloc( PyObject * self ); +static PyObject *Button_getattr( PyObject * self, char *name ); +static PyObject *Button_repr( PyObject * self ); +static PyObject *Button_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type); +static int Button_setattr( PyObject * self, char *name, PyObject * v ); + +static Button *newbutton( void ); + +/* GUI interface routines */ + +static void exit_pydraw( SpaceScript * sc, short error ); +static void exec_callback( SpaceScript * sc, PyObject * callback, + PyObject * args ); +static void spacescript_do_pywin_buttons( SpaceScript * sc, + unsigned short event ); + +static PyObject *Method_Exit( PyObject * self ); +static PyObject *Method_Register( PyObject * self, PyObject * args ); +static PyObject *Method_Redraw( PyObject * self, PyObject * args ); +static PyObject *Method_Draw( PyObject * self ); +static PyObject *Method_Create( PyObject * self, PyObject * args ); +static PyObject *Method_UIBlock( PyObject * self, PyObject * args ); + +static PyObject *Method_Button( PyObject * self, PyObject * args ); +static PyObject *Method_Menu( PyObject * self, PyObject * args ); +static PyObject *Method_Toggle( PyObject * self, PyObject * args ); +static PyObject *Method_Slider( PyObject * self, PyObject * args ); +static PyObject *Method_Scrollbar( PyObject * self, PyObject * args ); +static PyObject *Method_ColorPicker( PyObject * self, PyObject * args ); +static PyObject *Method_Normal( PyObject * self, PyObject * args ); +static PyObject *Method_Number( PyObject * self, PyObject * args ); +static PyObject *Method_String( PyObject * self, PyObject * args ); +static PyObject *Method_GetStringWidth( PyObject * self, PyObject * args ); +static PyObject *Method_Text( PyObject * self, PyObject * args ); +static PyObject *Method_Label( PyObject * self, PyObject * args ); +/* by Campbell: */ +static PyObject *Method_PupMenu( PyObject * self, PyObject * args ); +static PyObject *Method_PupIntInput( PyObject * self, PyObject * args ); +static PyObject *Method_PupFloatInput( PyObject * self, PyObject * args ); +static PyObject *Method_PupStrInput( PyObject * self, PyObject * args ); +static PyObject *Method_BeginAlign( PyObject * self, PyObject * args ); +static PyObject *Method_EndAlign( PyObject * self, PyObject * args ); +/* next by Jonathan Merritt (lancelet): */ +static PyObject *Method_Image( PyObject * self, PyObject * args); +/* CLEVER NUMBUT */ +static PyObject *Method_PupBlock( PyObject * self, PyObject * args ); + +static uiBlock *Get_uiBlock( void ); + +static void py_slider_update( void *butv, void *data2_unused ); + +/* hack to get 1 block for the UIBlock, only ever 1 at a time */ +static uiBlock *uiblock=NULL; + +static char Draw_doc[] = "The Blender.Draw submodule"; + +static char Method_UIBlock_doc[] = "(drawfunc, x,y) - Popup dialog where buttons can be drawn (expemental)"; + +static char Method_Register_doc[] = + "(draw, event, button) - Register callbacks for windowing\n\n\ +(draw) A function to draw the screen, taking no arguments\n\ +(event) A function to handle events, taking 2 arguments (evt, val)\n\ + (evt) The event number\n\ + (val) The value modifier (for key and mouse press/release)\n\ +(button) A function to handle button events, taking 1 argument (evt)\n\ + (evt) The button number\n\n\ +A None object can be passed if a callback is unused."; + + +static char Method_Redraw_doc[] = "([after]) - Queue a redraw event\n\n\ +[after=0] Determines whether the redraw is processed before\n\ +or after other input events.\n\n\ +Redraw events are buffered so that regardless of how many events\n\ +are queued the window only receives one redraw event."; + +static char Method_Draw_doc[] = "() - Force an immediate redraw\n\n\ +Forced redraws are not buffered, in other words the window is redrawn\n\ +exactly once for everytime this function is called."; + + +static char Method_Create_doc[] = + "(value) - Create a default Button object\n\n\ + (value) - The value to store in the button\n\n\ + Valid values are ints, floats, and strings"; + +static char Method_Button_doc[] = + "(name, event, x, y, width, height, [tooltip]) - Create a new Button \ +(push) button\n\n\ +(name) A string to display on the button\n\ +(event) The event number to pass to the button event function when activated\n\ +(x, y) The lower left coordinate of the button\n\ +(width, height) The button width and height\n\ +[tooltip=] The button's tooltip\n\n\ +This function can be called as Button() or PushButton()."; + +static char Method_BeginAlign_doc[] = + "Buttons after this function will draw aligned (button layout only)"; + +static char Method_EndAlign_doc[] = + "Use after BeginAlign() to stop aligning the buttons (button layout only)."; + +static char Method_Menu_doc[] = + "(name, event, x, y, width, height, default, [tooltip]) - Create a new Menu \ +button\n\n\ +(name) A string to display on the button\n\ +(event) The event number to pass to the button event function when activated\n\ +(x, y) The lower left coordinate of the button\n\ +(width, height) The button width and height\n\ +(default) The number of the option to be selected by default\n\ +[tooltip=" "] The button's tooltip\n\n\ +The menu options are specified through the name of the\n\ +button. Options are followed by a format code and separated\n\ +by the '|' (pipe) character.\n\ +Valid format codes are\n\ + %t - The option should be used as the title\n\ + %xN - The option should set the integer N in the button value."; + +static char Method_Toggle_doc[] = + "(name, event, x, y, width, height, default, [tooltip]) - Create a new Toggle \ +button\n\n\ +(name) A string to display on the button\n\ +(event) The event number to pass to the button event function when activated\n\ +(x, y) The lower left coordinate of the button\n\ +(width, height) The button width and height\n\ +(default) An integer (0 or 1) specifying the default state\n\ +[tooltip=] The button's tooltip"; + + +static char Method_Slider_doc[] = + "(name, event, x, y, width, height, initial, min, max, [update, tooltip]) - \ +Create a new Slider button\n\n\ +(name) A string to display on the button\n\ +(event) The event number to pass to the button event function when activated\n\ +(x, y) The lower left coordinate of the button\n\ +(width, height) The button width and height\n\ +(initial, min, max) Three values (int or float) specifying the initial \ + and limit values.\n\ +[update=1] A value controlling whether the slider will emit events as it \ +is edited.\n\ + A non-zero value (default) enables the events. A zero value supresses them.\n\ +[tooltip=] The button's tooltip"; + + +static char Method_Scrollbar_doc[] = + "(event, x, y, width, height, initial, min, max, [update, tooltip]) - Create a \ +new Scrollbar\n\n\ +(event) The event number to pass to the button event function when activated\n\ +(x, y) The lower left coordinate of the button\n\ +(width, height) The button width and height\n\ +(initial, min, max) Three values (int or float) specifying the initial and limit values.\n\ +[update=1] A value controlling whether the slider will emit events as it is edited.\n\ + A non-zero value (default) enables the events. A zero value supresses them.\n\ +[tooltip=] The button's tooltip"; + +static char Method_ColorPicker_doc[] = + "(event, x, y, width, height, initial, [tooltip]) - Create a new Button \ +Color picker button\n\n\ +(event) The event number to pass to the button event function when the color changes\n\ +(x, y) The lower left coordinate of the button\n\ +(width, height) The button width and height\n\ +(initial) 3-Float tuple of the color (values between 0 and 1)\ +[tooltip=] The button's tooltip"; + +static char Method_Normal_doc[] = + "(event, x, y, width, height, initial, [tooltip]) - Create a new Button \ +Normal button (a sphere that you can roll to change the normal)\n\n\ +(event) The event number to pass to the button event function when the color changes\n\ +(x, y) The lower left coordinate of the button\n\ +(width, height) The button width and height - non square will gave odd results\n\ +(initial) 3-Float tuple of the normal vector (values between -1 and 1)\ +[tooltip=] The button's tooltip"; + +static char Method_Number_doc[] = + "(name, event, x, y, width, height, initial, min, max, [tooltip]) - Create a \ +new Number button\n\n\ +(name) A string to display on the button\n\ +(event) The event number to pass to the button event function when activated\n\ +(x, y) The lower left coordinate of the button\n\ +(width, height) The button width and height\n\ +(initial, min, max) Three values (int or float) specifying the initial and \ +limit values.\n\ +[tooltip=] The button's tooltip"; + +static char Method_String_doc[] = + "(name, event, x, y, width, height, initial, length, [tooltip]) - Create a \ +new String button\n\n\ +(name) A string to display on the button\n\ +(event) The event number to pass to the button event function when activated\n\ +(x, y) The lower left coordinate of the button\n\ +(width, height) The button width and height\n\ +(initial) The string to display initially\n\ +(length) The maximum input length\n\ +[tooltip=] The button's tooltip"; + +static char Method_GetStringWidth_doc[] = + "(text, font = 'normal') - Return the width in pixels of the given string\n\ +(font) The font size: 'normal' (default), 'small' or 'tiny'."; + +static char Method_Text_doc[] = + "(text, font = 'normal') - Draw text onscreen\n\n\ +(text) The text to draw\n\ +(font) The font size: 'normal' (default), 'small' or 'tiny'.\n\n\ +This function returns the width of the drawn string."; + +static char Method_Label_doc[] = + "(text, x, y) - Draw a text label onscreen\n\n\ +(text) The text to draw\n\ +(x, y) The lower left coordinate of the lable"; + +static char Method_PupMenu_doc[] = + "(string, maxrow = None) - Display a pop-up menu at the screen.\n\ +The contents of the pop-up are specified through the 'string' argument,\n\ +like with Draw.Menu.\n\ +'maxrow' is an optional int to control how many rows the pop-up should have.\n\ +Options are followed by a format code and separated\n\ +by the '|' (pipe) character.\n\ +Valid format codes are\n\ + %t - The option should be used as the title\n\ + %xN - The option should set the integer N in the button value.\n\n\ +Ex: Draw.PupMenu('OK?%t|QUIT BLENDER') # should be familiar ..."; + +static char Method_PupIntInput_doc[] = + "(text, default, min, max) - Display an int pop-up input.\n\ +(text) - text string to display on the button;\n\ +(default, min, max) - the default, min and max int values for the button;\n\ +Return the user input value or None on user exit"; + +static char Method_PupFloatInput_doc[] = + "(text, default, min, max, clickStep, floatLen) - Display a float pop-up input.\n\ +(text) - text string to display on the button;\n\ +(default, min, max) - the default, min and max float values for the button;\n\ +(clickStep) - float increment/decrement for each click on the button arrows;\n\ +(floatLen) - an integer defining the precision (number of decimal places) of \n\ +the float value show.\n\ +Return the user input value or None on user exit"; + +static char Method_Image_doc[] = + "(image, x, y, zoomx = 1.0, zoomy = 1.0, [clipx, clipy, clipw, cliph])) \n\ + - Draw an image.\n\ +(image) - Blender.Image to draw.\n\ +(x, y) - floats specifying the location of the image.\n\ +(zoomx, zoomy) - float zoom factors in horizontal and vertical directions.\n\ +(clipx, clipy, clipw, cliph) - integers specifying a clipping rectangle within the original image."; + +static char Method_PupStrInput_doc[] = + "(text, default, max = 20) - Display a float pop-up input.\n\ +(text) - text string to display on the button;\n\ +(default) - the initial string to display (truncated to 'max' chars);\n\ +(max = 20) - The maximum number of chars the user can input;\n\ +Return the user input value or None on user exit"; + +static char Method_PupBlock_doc[] = + "(title, sequence) - Display a pop-up block.\n\ +(title) - The title of the block.\n\ +(sequence) - A sequence defining what the block contains. \ +The order of the list is the order of appearance, from top down.\n\ +Possible format for sequence items:\n\ +[value is an object created with Create]\n\ +\ttext: Defines a label in the block\n\ +\t(text, value, tooltip = ''): Defines a toggle button \n\ +\t(text, value, min, max, tooltip = ''): Defines a num or string button \n\ +\t\t\tdepending on the value.\n\ +\t\tFor string, max is the maximum length of the text and min is unused.\n\ +Return 1 if the pop-up is confirmed, 0 otherwise. \n\ +Warning: On cancel, the value objects are brought back to there previous values, \ +\texcept for string values which will still contain the modified values.\n"; + +static char Method_Exit_doc[] = "() - Exit the windowing interface"; + +/*This is needed for button callbacks. Any button that uses a callback gets added to this list. + On the C side of drawing begin, this list should be cleared. + Each entry is a tuple of the form (button, callback py object) +*/ +PyObject *M_Button_List = NULL; + +/* +* here we engage in some macro trickery to define the PyMethodDef table +*/ + +#define _MethodDef(func, prefix) \ + {#func, prefix##_##func, METH_VARARGS, prefix##_##func##_doc} + +/* So that _MethodDef(delete, Scene) expands to: + * {"delete", Scene_delete, METH_VARARGS, Scene_delete_doc} */ + +#undef MethodDef +#define MethodDef(func) _MethodDef(func, Method) + +static struct PyMethodDef Draw_methods[] = { + MethodDef( Create ), + MethodDef( UIBlock ), + MethodDef( Button ), + MethodDef( Toggle ), + MethodDef( Menu ), + MethodDef( Slider ), + MethodDef( Scrollbar ), + MethodDef( ColorPicker ), + MethodDef( Normal ), + MethodDef( Number ), + MethodDef( String ), + MethodDef( GetStringWidth ), + MethodDef( Text ), + MethodDef( Label ), + MethodDef( PupMenu ), + MethodDef( PupIntInput ), + MethodDef( PupFloatInput ), + MethodDef( PupStrInput ), + MethodDef( PupBlock ), + MethodDef( Image ), + {"Exit", (PyCFunction)Method_Exit, METH_NOARGS, Method_Exit_doc}, + MethodDef( Redraw ), + {"Draw", (PyCFunction)Method_Draw, METH_NOARGS, Method_Draw_doc}, + MethodDef( Register ), + {"PushButton", (PyCFunction)Method_Button, METH_VARARGS, Method_Button_doc}, + MethodDef( BeginAlign ), + MethodDef( EndAlign), + {NULL, NULL, 0, NULL} +}; + +PyTypeObject Button_Type = { + PyObject_HEAD_INIT( NULL ) 0, /*ob_size */ + "Button", /*tp_name */ + sizeof( Button ), /*tp_basicsize */ + 0, /*tp_itemsize */ + ( destructor ) Button_dealloc, /*tp_dealloc */ + ( printfunc ) 0, /*tp_print */ + ( getattrfunc ) Button_getattr, /*tp_getattr */ + ( setattrfunc ) Button_setattr, /*tp_setattr */ + NULL, /*tp_cmp */ + ( reprfunc ) Button_repr, /*tp_repr */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + (richcmpfunc)Button_richcmpr, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + NULL, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + NULL, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +static void Button_dealloc( PyObject * self ) +{ + Button *but = ( Button * ) self; + + if( but->type == BSTRING_TYPE ) { + if( but->val.asstr ) + MEM_freeN( but->val.asstr ); + } + + PyObject_DEL( self ); +} + +static PyObject *Button_getattr( PyObject * self, char *name ) +{ + Button *but = ( Button * ) self; + + if( strcmp( name, "val" ) == 0 ) { + if( but->type == BINT_TYPE ) + return PyInt_FromLong( but->val.asint ); + else if( but->type == BFLOAT_TYPE ) + return PyFloat_FromDouble( but->val.asfloat ); + else if( but->type == BSTRING_TYPE ) + return PyString_FromString( but->val.asstr ); + else if( but->type == BVECTOR_TYPE ) + return Py_BuildValue( "fff", but->val.asvec[0], but->val.asvec[1], but->val.asvec[2] ); + } + + PyErr_SetString( PyExc_AttributeError, name ); + return NULL; +} + +static int Button_setattr( PyObject * self, char *name, PyObject * v ) +{ + Button *but = ( Button * ) self; + + if( strcmp( name, "val" ) == 0 ) { + if( but->type == BINT_TYPE && PyNumber_Check(v) ) { + PyObject *pyVal = PyNumber_Int( v ); + if (pyVal) { + but->val.asint = (int)PyInt_AS_LONG( pyVal ); + Py_DECREF(pyVal); + return 0; + } + } + else if( but->type == BFLOAT_TYPE && PyNumber_Check(v) ) { + PyObject *pyVal = PyNumber_Float( v ); + if (pyVal) { + but->val.asfloat = (float)PyFloat_AS_DOUBLE( pyVal ); + Py_DECREF(pyVal); + return 0; + } + } + else if( but->type == BVECTOR_TYPE ) { + if ( PyArg_ParseTuple( v, "fff", but->val.asvec, but->val.asvec+1, but->val.asvec+2 ) ) + return 0; + } + else if( but->type == BSTRING_TYPE && PyString_Check(v) ) { + char *newstr; + unsigned int newlen; + + PyString_AsStringAndSize( v, &newstr, (int *)&newlen ); + + if (newlen+1> UI_MAX_DRAW_STR) + return EXPP_ReturnIntError( PyExc_ValueError, "Error: button string length exceeded max limit (399 chars)."); + + /* if the length of the new string is the same as */ + /* the old one, just copy, else delete and realloc. */ + if( but->slen == newlen ) { + BLI_strncpy( but->val.asstr, newstr, + but->slen + 1 ); + + return 0; + + } else { + MEM_freeN( but->val.asstr ); + but->slen = newlen; + but->val.asstr = + MEM_mallocN( but->slen + 1, + "button setattr" ); + BLI_strncpy( but->val.asstr, newstr, + but->slen + 1 ); + + return 0; + } + } + } else { + /* + * Accessing the wrong attribute. + */ + return EXPP_ReturnIntError( PyExc_AttributeError, name ); + } + + /* + * Correct attribute but value is incompatible with current button value. + */ + return EXPP_ReturnIntError( PyExc_ValueError, "value incompatible with current button type" ); +} + +static PyObject *Button_repr( PyObject * self ) +{ + return PyObject_Repr( Button_getattr( self, "val" ) ); +} + +static PyObject *Button_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type) +{ + PyObject *ret, *valA=NULL, *valB=NULL; + if (ButtonObject_Check(objectA)) + objectA = valA = Button_getattr( objectA, "val" ); + if (ButtonObject_Check(objectB)) + objectB = valB = Button_getattr( objectB, "val" ); + ret = PyObject_RichCompare(objectA, objectB, comparison_type); + Py_XDECREF(valA); /* Button_getattr created with 1 ref, we dont care about them now */ + Py_XDECREF(valB); + return ret; +} + + +static Button *newbutton( void ) +{ + Button *but = NULL; + + but = ( Button * ) PyObject_NEW( Button, &Button_Type ); + but->tooltip[0] = 0; /*NULL-terminate tooltip string*/ + but->tooltip[255] = 0; /*necassary to insure we always have a NULL-terminated string, as + according to the docs strncpy doesn't do this for us.*/ + return but; +} + +/* GUI interface routines */ + +static void exit_pydraw( SpaceScript * sc, short err ) +{ + Script *script = NULL; + + if( !sc || !sc->script ) + return; + + script = sc->script; + + if( err ) { + PyErr_Print( ); + script->flags = 0; /* mark script struct for deletion */ + error( "Python script error: check console" ); + scrarea_queue_redraw( sc->area ); + } + + BPy_Set_DrawButtonsList(sc->but_refs); + BPy_Free_DrawButtonsList(); /*clear all temp button references*/ + sc->but_refs = NULL; + + Py_XDECREF( ( PyObject * ) script->py_draw ); + Py_XDECREF( ( PyObject * ) script->py_event ); + Py_XDECREF( ( PyObject * ) script->py_button ); + + script->py_draw = script->py_event = script->py_button = NULL; +} + +static void exec_callback( SpaceScript * sc, PyObject * callback, + PyObject * args ) +{ + PyObject *result = PyObject_CallObject( callback, args ); + + if( result == NULL && sc->script ) { /* errors in the script */ + + if( sc->script->lastspace == SPACE_TEXT ) { /*if it can be an ALT+P script */ + Text *text = G.main->text.first; + + while( text ) { /* find it and free its compiled code */ + + if( !strcmp + ( text->id.name + 2, + sc->script->id.name + 2 ) ) { + BPY_free_compiled_text( text ); + break; + } + + text = text->id.next; + } + } + exit_pydraw( sc, 1 ); + } + + Py_XDECREF( result ); + Py_DECREF( args ); +} + +/* BPY_spacescript_do_pywin_draw, the static spacescript_do_pywin_buttons and + * BPY_spacescript_do_pywin_event are the three functions responsible for + * calling the draw, buttons and event callbacks registered with Draw.Register + * (see Method_Register below). They are called (only the two BPY_ ones) + * from blender/src/drawscript.c */ + +void BPY_spacescript_do_pywin_draw( SpaceScript * sc ) +{ + uiBlock *block; + char butblock[20]; + Script *script = sc->script; + + sprintf( butblock, "win %d", curarea->win ); + block = uiNewBlock( &curarea->uiblocks, butblock, UI_EMBOSSX, + UI_HELV, curarea->win ); + + if( script->py_draw ) { + if (sc->but_refs) { + BPy_Set_DrawButtonsList(sc->but_refs); + BPy_Free_DrawButtonsList(); /*clear all temp button references*/ + } + sc->but_refs = PyList_New(0); + BPy_Set_DrawButtonsList(sc->but_refs); + + glPushAttrib( GL_ALL_ATTRIB_BITS ); + exec_callback( sc, script->py_draw, Py_BuildValue( "()" ) ); + glPopAttrib( ); + } else { + glClearColor( 0.4375, 0.4375, 0.4375, 0.0 ); + glClear( GL_COLOR_BUFFER_BIT ); + } + + uiDrawBlock( block ); + + curarea->win_swap = WIN_BACK_OK; +} + +static void spacescript_do_pywin_buttons( SpaceScript * sc, + unsigned short event ) +{ + if( sc->script->py_button ) + exec_callback( sc, sc->script->py_button, + Py_BuildValue( "(i)", event ) ); +} + +void BPY_spacescript_do_pywin_event( SpaceScript * sc, unsigned short event, + short val, char ascii ) +{ + if( event == QKEY && G.qual & ( LR_ALTKEY | LR_CTRLKEY ) ) { + /* finish script: user pressed ALT+Q or CONTROL+Q */ + Script *script = sc->script; + + exit_pydraw( sc, 0 ); + + script->flags &= ~SCRIPT_GUI; /* we're done with this script */ + + return; + } + + if (val) { + + if (uiDoBlocks( &curarea->uiblocks, event ) != UI_NOTHING) event = 0; + + if (event == UI_BUT_EVENT) { + /* check that event is in free range for script button events; + * read the comment before check_button_event() below to understand */ + if (val >= EXPP_BUTTON_EVENTS_OFFSET && val < 0x4000) + spacescript_do_pywin_buttons(sc, val - EXPP_BUTTON_EVENTS_OFFSET); + return; + } + } + + /* We use the "event" main module var, used by scriptlinks, to pass the ascii + * value to event callbacks (gui/event/button callbacks are not allowed + * inside scriptlinks, so this is ok) */ + if( sc->script->py_event ) { + int pass_ascii = 0; + if (ascii > 31 && ascii != 127) { + pass_ascii = 1; + EXPP_dict_set_item_str(g_blenderdict, "event", + PyInt_FromLong((long)ascii)); + } + exec_callback( sc, sc->script->py_event, + Py_BuildValue( "(ii)", event, val ) ); + if (pass_ascii) + EXPP_dict_set_item_str(g_blenderdict, "event", + PyString_FromString("")); + } +} + +static void exec_but_callback(void *pyobj, void *data) +{ + PyObject *result; + PyObject *pyvalue = NULL; + uiBut *but = (uiBut *)data; + PyObject *arg; + PyObject *callback = (PyObject *)pyobj; + + double value = ui_get_but_val(but); + + if (callback==NULL || callback == Py_None) + return; + + /* Button types support + case MENU: + case TEX: + case TOG: + case NUMSLI: + case NUM: + case COL: + case BUT_NORMAL: + case BUT */ + switch (but->type) { + case TEX: + /*printf("TEX\n");*/ + pyvalue = PyString_FromString( (char *)but->poin ); + break; + case NUM: + case NUMSLI: + case TOG: + case MENU: + if (but->pointype==FLO) { + /*printf("FLO\n");*/ + pyvalue = PyFloat_FromDouble( (float)value ); + } else if (but->pointype==INT) { + /*printf("INT\n");*/ + pyvalue = PyInt_FromLong( (int)value ); + } else if (but->pointype==SHO) { + /*printf("SHO\n");*/ + pyvalue = PyInt_FromLong( (short)value ); + } + break; + case COL: + case BUT_NORMAL: + { + float vec[3]; + VECCOPY(vec, (float *)but->poin); + pyvalue = Py_BuildValue("(fff)", vec[0], vec[1], vec[2]); + break; + } + case BUT: + pyvalue = Py_None; + Py_INCREF(pyvalue); + break; + default: + pyvalue = Py_None; + Py_INCREF(pyvalue); + printf("Error, no button type matched."); + } + + arg = PyTuple_New( 2 ); + if (uiblock==NULL) + PyTuple_SetItem( arg, 0, PyInt_FromLong(but->retval - EXPP_BUTTON_EVENTS_OFFSET) ); + else + PyTuple_SetItem( arg, 0, PyInt_FromLong(but->retval) ); + + PyTuple_SetItem( arg, 1, pyvalue ); + + result = PyObject_CallObject( callback, arg ); + Py_DECREF(arg); + + if (!result) { + Py_DECREF(pyvalue); + PyErr_Print( ); + error( "Python script error: check console" ); + } + Py_XDECREF( result ); +} + +/*note that this function populates the drawbutton ref lists.*/ +static void set_pycallback(uiBut *ubut, PyObject *callback, Button *but) +{ + PyObject *tuple; + if (!callback || !PyCallable_Check(callback)) { + if (M_Button_List && but) { + PyList_Append(M_Button_List, (PyObject*)but); + } + return; + } + + if (M_Button_List) { + if (but) tuple = PyTuple_New(2); + else tuple = PyTuple_New(1); + + /*the tuple API mandates this*/ + Py_XINCREF(callback); + Py_XINCREF(but); /*this checks for NULL*/ + + PyTuple_SET_ITEM(tuple, 0, callback); + if (but) PyTuple_SET_ITEM(tuple, 1, (PyObject*)but); + + PyList_Append(M_Button_List, tuple); + Py_DECREF(tuple); /*we have to do this to aovid double references.*/ + + uiButSetFunc(ubut, exec_but_callback, callback, ubut); + } +} + +void BPy_Set_DrawButtonsList(void *list) +{ + M_Button_List = list; +} + +/*this MUST be called after doing UI stuff.*/ +void BPy_Free_DrawButtonsList(void) +{ + /*Clear the list.*/ + if (M_Button_List) { + PyList_SetSlice(M_Button_List, 0, PyList_Size(M_Button_List), NULL); + Py_DECREF(M_Button_List); + M_Button_List = NULL; + } +} + +static PyObject *Method_Exit( PyObject * self ) +{ + SpaceScript *sc; + Script *script; + + /* if users call Draw.Exit when we are already out of the SPACE_SCRIPT, we + * simply return, for compatibility */ + if( curarea->spacetype == SPACE_SCRIPT ) + sc = curarea->spacedata.first; + else + Py_RETURN_NONE; + + exit_pydraw( sc, 0 ); + + script = sc->script; + + /* remove our lock to the current namespace */ + script->flags &= ~SCRIPT_GUI; + + Py_RETURN_NONE; +} + +/* Method_Register (Draw.Register) registers callbacks for drawing, events + * and gui button events, so a script can continue executing after the + * interpreter reached its end and returned control to Blender. Everytime + * the SPACE_SCRIPT window with this script is redrawn, the registered + * callbacks are executed. */ +static PyObject *Method_Register( PyObject * self, PyObject * args ) +{ + PyObject *newdrawc = NULL, *neweventc = NULL, *newbuttonc = NULL; + SpaceScript *sc; + Script *script; + int startspace = 0; + + if( !PyArg_ParseTuple + ( args, "O|OO", &newdrawc, &neweventc, &newbuttonc ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected one or three PyObjects" ); + + if( !PyCallable_Check( newdrawc ) ) + newdrawc = NULL; + if( !PyCallable_Check( neweventc ) ) + neweventc = NULL; + if( !PyCallable_Check( newbuttonc ) ) + newbuttonc = NULL; + + if( !( newdrawc || neweventc || newbuttonc ) ) + Py_RETURN_NONE; + + startspace = curarea->spacetype; + + /* first make sure the current area is of type SPACE_SCRIPT */ + if( startspace != SPACE_SCRIPT ) + newspace( curarea, SPACE_SCRIPT ); + + sc = curarea->spacedata.first; + + /* There are two kinds of scripts: + * a) those that simply run, finish and return control to Blender; + * b) those that do like 'a)' above but leave callbacks for drawing, + * events and button events, with this Method_Register (Draw.Register + * in Python). These callbacks are called by scriptspaces (Scripts windows). + * + * We need to flag scripts that leave callbacks so their namespaces are + * not deleted when they 'finish' execution, because the callbacks will + * still need the namespace. + */ + + /* Let's see if this is a new script */ + script = G.main->script.first; + while (script) { + if (script->flags & SCRIPT_RUNNING) break; + script = script->id.next; + } + + if( !script ) { + /* not new, it's a left callback calling Register again */ + script = sc->script; + if( !script ) { + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Draw.Register can't be used inside script links" ); + } + } + else sc->script = script; + + /* Now we have the right script and can set a lock so its namespace can't be + * deleted for as long as we need it */ + script->flags |= SCRIPT_GUI; + + /* save the last space so we can go back to it upon finishing */ + if( !script->lastspace ) + script->lastspace = startspace; + + /* clean the old callbacks */ + exit_pydraw( sc, 0 ); + + /* prepare the new ones and insert them */ + Py_XINCREF( newdrawc ); + Py_XINCREF( neweventc ); + Py_XINCREF( newbuttonc ); + + script->py_draw = newdrawc; + script->py_event = neweventc; + script->py_button = newbuttonc; + + scrarea_queue_redraw( sc->area ); + + Py_RETURN_NONE; +} + +static PyObject *Method_Redraw( PyObject * self, PyObject * args ) +{ + int after = 0; + + if( !PyArg_ParseTuple( args, "|i", &after ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument (or nothing)" ); + + if( after ) + addafterqueue( curarea->win, REDRAW, 1 ); + else + scrarea_queue_winredraw( curarea ); + + Py_RETURN_NONE; +} + +static PyObject *Method_Draw( PyObject * self ) +{ + /*@ If forced drawing is disable queue a redraw event instead */ + if( EXPP_disable_force_draw ) { + scrarea_queue_winredraw( curarea ); + Py_RETURN_NONE; + } + + scrarea_do_windraw( curarea ); + + screen_swapbuffers( ); + + Py_RETURN_NONE; +} + +static PyObject *Method_Create( PyObject * self, PyObject * args ) +{ + Button *but = NULL; + PyObject *val; + char *newstr; + + but = newbutton(); + /* If this function dosnt sucseed this will need to be deallocated, + * make sure the type is NOT BSTRING_TYPE before deallocing -1 is ok. + * so we dont dealloc with an uninitialized value wich would be bad! */ + if ( PyArg_ParseTuple( args, "fff", but->val.asvec, but->val.asvec+1, but->val.asvec+2 ) ) { + but->type = BVECTOR_TYPE; + + } else if ( PyArg_ParseTuple( args, "O!", &PyFloat_Type, &val ) ) { + but->val.asfloat = (float)PyFloat_AS_DOUBLE(val); + but->type = BFLOAT_TYPE; + + } else if ( PyArg_ParseTuple( args, "O!", &PyInt_Type, &val ) ) { + but->val.asint = (int)PyInt_AS_LONG(val); + but->type = BINT_TYPE; + + } else if ( PyArg_ParseTuple( args, "s#", &newstr, &but->slen ) ) { + if (but->slen + 1 > UI_MAX_DRAW_STR) { + but->type = -1; + Py_DECREF((PyObject *)but); /* will remove */ + but = NULL; + PyErr_SetString( PyExc_TypeError, "string is longer then 399 chars"); + } else { + but->type = BSTRING_TYPE; + but->val.asstr = MEM_mallocN( but->slen + 1, "button string" ); + BLI_strncpy( but->val.asstr, newstr, but->slen+1 ); + } + + } else { + but->type = -1; + Py_DECREF((PyObject *)but); /* will remove */ + but = NULL; + PyErr_SetString( PyExc_TypeError, "expected string, float, int or 3-float tuple argument" ); + } + + if (but != NULL) { + PyErr_Clear(); + } + + return (PyObject*) but; +} + + +static PyObject *Method_UIBlock( PyObject * self, PyObject * args ) +{ + PyObject *val = NULL; + PyObject *result = NULL; + ListBase listb= {NULL, NULL}; + + if ( !PyArg_ParseTuple( args, "O", &val ) || !PyCallable_Check( val ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected 1 python function and 2 ints" ); + + if (uiblock) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "cannot run more then 1 UIBlock at a time" ); + + BPy_Set_DrawButtonsList(PyList_New(0)); + + mywinset(G.curscreen->mainwin); + uiblock= uiNewBlock(&listb, "numbuts", UI_EMBOSS, UI_HELV, G.curscreen->mainwin); + + uiBlockSetFlag(uiblock, UI_BLOCK_LOOP|UI_BLOCK_REDRAW); + result = PyObject_CallObject( val, Py_BuildValue( "()" ) ); + + if (!result) { + PyErr_Print( ); + error( "Python script error: check console" ); + } else { + /* copied from do_clever_numbuts in toolbox.c */ + + /* Clear all events so tooltips work, this is not ideal and + only needed because calls from the menu still have some events + left over when do_clever_numbuts is called. + Calls from keyshortcuts do not have this problem.*/ + ScrArea *sa; + BWinEvent temp_bevt; + for (sa= G.curscreen->areabase.first; sa; sa= sa->next) { + if(sa->win) { + while( bwin_qread( sa->win, &temp_bevt ) ) {} + } + if(sa->headwin) { + while( bwin_qread( sa->headwin, &temp_bevt ) ) {} + } + } + /* Done clearing events */ + + uiBoundsBlock(uiblock, 5); + uiDoBlocks(&listb, 0); + } + uiFreeBlocks(&listb); + uiblock = NULL; + BPy_Free_DrawButtonsList(); /*clear all temp button references*/ + + Py_XDECREF( result ); + Py_RETURN_NONE; +} + +void Set_uiBlock(uiBlock *block) +{ + uiblock = block; +} + +static uiBlock *Get_uiBlock( void ) +{ + char butblock[32]; + /* Global, used now for UIBlock */ + if (uiblock) { + return uiblock; + } + /* Local */ + sprintf( butblock, "win %d", curarea->win ); + + return uiGetBlock( butblock, curarea ); +} + + +/* We restrict the acceptable event numbers to a proper "free" range + * according to other spaces in Blender. + * winqread***space() (space events callbacks) use short for events + * (called 'val' there) and we also translate by EXPP_BUTTON_EVENTS_OFFSET + * to get rid of unwanted events (check BPY_do_pywin_events above for + * explanation). This function takes care of that and proper checking: */ +static int check_button_event(int *event) { + if ((*event < EXPP_BUTTON_EVENTS_MIN) || + (*event > EXPP_BUTTON_EVENTS_MAX)) { + return -1; + } + if (uiblock==NULL) /* For UIBlock we need non offset UI elements */ + *event += EXPP_BUTTON_EVENTS_OFFSET; + return 0; +} + +static PyObject *Method_BeginAlign( PyObject * self, PyObject * args ) +{ + uiBlock *block = Get_uiBlock( ); + + if (block) + uiBlockBeginAlign(block); + + Py_RETURN_NONE; +} + +static PyObject *Method_EndAlign( PyObject * self, PyObject * args ) +{ + uiBlock *block = Get_uiBlock( ); + + if (block) + uiBlockEndAlign(block); + + Py_RETURN_NONE; +} + +static PyObject *Method_Button( PyObject * self, PyObject * args ) +{ + uiBlock *block; + char *name, *tip = NULL; + int event; + int x, y, w, h; + PyObject *callback=NULL; + + if( !PyArg_ParseTuple( args, "siiiii|sO", &name, &event, + &x, &y, &w, &h, &tip, &callback ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a string, five ints and optionally string and callback arguments" ); + + UI_METHOD_ERRORCHECK; + + block = Get_uiBlock( ); + if( block ) { + uiBut *ubut = uiDefBut( block, BUT, event, name, (short)x, (short)y, (short)w, (short)h, 0, 0, 0, 0, 0, tip ); + set_pycallback(ubut, callback, NULL); + } + Py_RETURN_NONE; +} + +static PyObject *Method_Menu( PyObject * self, PyObject * args ) +{ + uiBlock *block; + char *name, *tip = NULL; + int event, def; + int x, y, w, h; + Button *but; + PyObject *callback=NULL; + + if( !PyArg_ParseTuple( args, "siiiiii|sO", &name, &event, + &x, &y, &w, &h, &def, &tip, &callback ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a string, six ints and optionally string and callback arguments" ); + + UI_METHOD_ERRORCHECK; + + but = newbutton( ); + but->type = BINT_TYPE; + but->val.asint = def; + if (tip) strncpy(but->tooltip, tip, BPY_MAX_TOOLTIP); + + block = Get_uiBlock( ); + if( block ) { + uiBut *ubut = uiDefButI( block, MENU, event, name, (short)x, (short)y, (short)w, (short)h, + &but->val.asint, 0, 0, 0, 0, but->tooltip ); + set_pycallback(ubut, callback, but); + } + return ( PyObject * ) but; +} + +static PyObject *Method_Toggle( PyObject * self, PyObject * args ) +{ + uiBlock *block; + char *name, *tip = NULL; + int event; + int x, y, w, h, def; + Button *but; + PyObject *callback=NULL; + + if( !PyArg_ParseTuple( args, "siiiiii|sO", &name, &event, + &x, &y, &w, &h, &def, &tip, &callback ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a string, six ints and optionally string and callback arguments" ); + + UI_METHOD_ERRORCHECK; + + but = newbutton( ); + but->type = BINT_TYPE; + but->val.asint = def; + if (tip) strncpy(but->tooltip, tip, BPY_MAX_TOOLTIP); + + block = Get_uiBlock( ); + if( block ) { + uiBut *ubut = uiDefButI( block, TOG, event, name, (short)x, (short)y, (short)w, (short)h, + &but->val.asint, 0, 0, 0, 0, but->tooltip ); + set_pycallback(ubut, callback, but); + } + return ( PyObject * ) but; +} + +/*@DO NOT TOUCH THIS FUNCTION ! + Redrawing a slider inside its own callback routine is actually forbidden + with the current toolkit architecture (button routines are not reentrant). + But it works anyway. + XXX This is condemned to be dinosource in future - it's a hack. + */ + +static void py_slider_update( void *butv, void *data2_unused ) +{ + uiBut *but = butv; + PyObject *ref = Py_BuildValue( "(i)", SPACE_VIEW3D ); + PyObject *ret = NULL; + + EXPP_disable_force_draw = 1; + /*@ Disable forced drawing, otherwise the button object which + * is still being used might be deleted */ + + curarea->win_swap = WIN_BACK_OK; + /* removed global uiFrontBuf (contact ton when this goes wrong here) */ + + disable_where_script( 1 ); + + spacescript_do_pywin_buttons( curarea->spacedata.first, + (unsigned short)uiButGetRetVal( but ) - EXPP_BUTTON_EVENTS_OFFSET ); + + /* XXX useless right now, investigate better before a bcon 5 */ + ret = M_Window_Redraw( 0, ref ); + + Py_XDECREF(ref); + Py_XDECREF(ret); + + disable_where_script( 0 ); + + EXPP_disable_force_draw = 0; +} + +static PyObject *Method_Slider( PyObject * self, PyObject * args ) +{ + uiBlock *block; + char *name, *tip = NULL; + int event; + int x, y, w, h, realtime = 1; + Button *but; + PyObject *mino, *maxo, *inio; + PyObject *callback=NULL; + + if( !PyArg_ParseTuple( args, "siiiiiOOO|isO", &name, &event, + &x, &y, &w, &h, &inio, &mino, &maxo, &realtime, + &tip, &callback ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a string, five ints, three PyObjects\n\ + and optionally int, string and callback arguments" ); + + if(realtime && uiblock) + realtime = 0; /* realtime dosnt work with UIBlock */ + + UI_METHOD_ERRORCHECK; + + but = newbutton( ); + + if( PyFloat_Check( inio ) ) { + float ini, min, max; + + ini = (float)PyFloat_AsDouble( inio ); + min = (float)PyFloat_AsDouble( mino ); + max = (float)PyFloat_AsDouble( maxo ); + + but->type = BFLOAT_TYPE; + but->val.asfloat = ini; + if (tip) strncpy(but->tooltip, tip, BPY_MAX_TOOLTIP); + + block = Get_uiBlock( ); + if( block ) { + uiBut *ubut; + ubut = uiDefButF( block, NUMSLI, event, name, (short)x, (short)y, (short)w, + (short)h, &but->val.asfloat, min, max, 0, 0, + but->tooltip ); + if( realtime ) + uiButSetFunc( ubut, py_slider_update, ubut, NULL ); + else + set_pycallback(ubut, callback, but); + } + } else { + int ini, min, max; + + ini = PyInt_AsLong( inio ); + min = PyInt_AsLong( mino ); + max = PyInt_AsLong( maxo ); + + but->type = BINT_TYPE; + but->val.asint = ini; + if (tip) strncpy(but->tooltip, tip, BPY_MAX_TOOLTIP); + + block = Get_uiBlock( ); + if( block ) { + uiBut *ubut; + ubut = uiDefButI( block, NUMSLI, event, name, (short)x, (short)y, (short)w, + (short)h, &but->val.asint, (float)min, (float)max, 0, 0, + but->tooltip ); + if( realtime ) + uiButSetFunc( ubut, py_slider_update, ubut, NULL ); + else + set_pycallback(ubut, callback, but); + } + } + return ( PyObject * ) but; +} + +static PyObject *Method_Scrollbar( PyObject * self, PyObject * args ) +{ + char *tip = NULL; + uiBlock *block; + int event; + int x, y, w, h, realtime = 1; + Button *but; + PyObject *mino, *maxo, *inio; + float ini, min, max; + uiBut *ubut; + + if( !PyArg_ParseTuple( args, "iiiiiOOO|isO", &event, &x, &y, &w, &h, + &inio, &mino, &maxo, &realtime, &tip ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected five ints, three PyObjects and optionally\n\ +another int and string as arguments" ); + + if( !PyNumber_Check( inio ) || !PyNumber_Check( inio ) + || !PyNumber_Check( inio ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected numbers for initial, min, and max" ); + + if (check_button_event(&event) == -1) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "button event argument must be in the range [0, 16382]"); + + but = newbutton( ); + if (tip) strncpy(but->tooltip, tip, BPY_MAX_TOOLTIP); + + if( PyFloat_Check( inio ) ) + but->type = BFLOAT_TYPE; + else + but->type = BINT_TYPE; + + ini = (float)PyFloat_AsDouble( inio ); + min = (float)PyFloat_AsDouble( mino ); + max = (float)PyFloat_AsDouble( maxo ); + + block = Get_uiBlock( ); + + if( block ) { + if( but->type == BFLOAT_TYPE ) { + but->val.asfloat = ini; + ubut = uiDefButF( block, SCROLL, event, "", (short)x, (short)y, (short)w, (short)h, + &but->val.asfloat, min, max, 0, 0, but->tooltip ); + if( realtime ) + uiButSetFunc( ubut, py_slider_update, ubut, NULL ); + } else { + but->val.asint = (int)ini; + ubut = uiDefButI( block, SCROLL, event, "", (short)x, (short)y, (short)w, (short)h, + &but->val.asint, min, max, 0, 0, but->tooltip ); + if( realtime ) + uiButSetFunc( ubut, py_slider_update, ubut, NULL ); + } + } + return ( PyObject * ) but; +} + +static PyObject *Method_ColorPicker( PyObject * self, PyObject * args ) +{ + char USAGE_ERROR[] = "expected a 3-float tuple of values between 0 and 1"; + Button *but; + PyObject *inio; + uiBlock *block; + char *tip = NULL; + float col[3]; + int event; + short x, y, w, h; + PyObject *callback=NULL; + + if( !PyArg_ParseTuple( args, "ihhhhO!|sO", &event, + &x, &y, &w, &h, &PyTuple_Type, &inio, &tip, &callback ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected five ints, one tuple and optionally string and callback arguments" ); + + UI_METHOD_ERRORCHECK; + + if ( !PyArg_ParseTuple( inio, "fff", col, col+1, col+2 ) ) + return EXPP_ReturnPyObjError( PyExc_ValueError, USAGE_ERROR); + + if ( col[0] < 0 || col[0] > 1 + || col[1] < 0 || col[1] > 1 + || col[2] < 0 || col[2] > 1 ) + return EXPP_ReturnPyObjError( PyExc_ValueError, USAGE_ERROR); + + if ( EXPP_check_sequence_consistency( inio, &PyFloat_Type ) != 1 ) + return EXPP_ReturnPyObjError( PyExc_ValueError, USAGE_ERROR); + + but = newbutton(); + + but->type = BVECTOR_TYPE; + but->val.asvec[0] = col[0]; + but->val.asvec[1] = col[1]; + but->val.asvec[2] = col[2]; + if (tip) strncpy(but->tooltip, tip, BPY_MAX_TOOLTIP); + + block = Get_uiBlock( ); + if( block ) { + uiBut *ubut; + ubut = uiDefButF( block, COL, event, "", x, y, w, h, but->val.asvec, 0, 0, 0, 0, but->tooltip); + set_pycallback(ubut, callback, but); + } + + return ( PyObject * ) but; +} + + + +static PyObject *Method_Normal( PyObject * self, PyObject * args ) +{ + char USAGE_ERROR[] = "expected a 3-float tuple of values between -1 and 1"; + Button *but; + PyObject *inio; + uiBlock *block; + char *tip = NULL; + float nor[3]; + int event; + short x, y, w, h; + PyObject *callback=NULL; + + if( !PyArg_ParseTuple( args, "ihhhhO!|sO", &event, + &x, &y, &w, &h, &PyTuple_Type, &inio, &tip, &callback ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected five ints, one tuple and optionally string and callback arguments" ); + + UI_METHOD_ERRORCHECK; + + if ( !PyArg_ParseTuple( inio, "fff", nor, nor+1, nor+2 ) ) + return EXPP_ReturnPyObjError( PyExc_ValueError, USAGE_ERROR); + + if ( EXPP_check_sequence_consistency( inio, &PyFloat_Type ) != 1 ) + return EXPP_ReturnPyObjError( PyExc_ValueError, USAGE_ERROR); + + but = newbutton(); + if (tip) strncpy(but->tooltip, tip, BPY_MAX_TOOLTIP); + + but->type = BVECTOR_TYPE; + but->val.asvec[0] = nor[0]; + but->val.asvec[1] = nor[1]; + but->val.asvec[2] = nor[2]; + + block = Get_uiBlock( ); + if( block ) { + uiBut *ubut; + ubut = uiDefButF( block, BUT_NORMAL, event, "", x, y, w, h, but->val.asvec, 0.0f, 1.0f, 0, 0, but->tooltip); + set_pycallback(ubut, callback, but); + } + + return ( PyObject * ) but; +} + +static PyObject *Method_Number( PyObject * self, PyObject * args ) +{ + uiBlock *block; + char *name, *tip = NULL; + int event; + int x, y, w, h; + Button *but; + PyObject *mino, *maxo, *inio; + PyObject *callback=NULL; + uiBut *ubut= NULL; + + if( !PyArg_ParseTuple( args, "siiiiiOOO|sO", &name, &event, + &x, &y, &w, &h, &inio, &mino, &maxo, &tip, &callback ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a string, five ints, three PyObjects and\n\ + optionally string and callback arguments" ); + + UI_METHOD_ERRORCHECK; + + but = newbutton( ); + if (tip) strncpy(but->tooltip, tip, BPY_MAX_TOOLTIP); + block = Get_uiBlock( ); + + if( PyFloat_Check( inio ) ) { + float ini, min, max, range, precission=0; + + ini = (float)PyFloat_AsDouble( inio ); + min = (float)PyFloat_AsDouble( mino ); + max = (float)PyFloat_AsDouble( maxo ); + + range= (float)fabs(max-min); /* Click step will be a 10th of the range. */ + if (!range) range= 1.0f; /* avoid any odd errors */ + + /* set the precission to display*/ + if (range>=1000.0f) precission=1.0f; + else if (range>=100.0f) precission=2.0f; + else if (range>=10.0f) precission=3.0f; + else precission=4.0f; + + but->type = BFLOAT_TYPE; + but->val.asfloat = ini; + + + if( block ) + ubut= uiDefButF( block, NUM, event, name, (short)x, (short)y, (short)w, (short)h, + &but->val.asfloat, min, max, 10*range, precission, but->tooltip ); + } else { + int ini, min, max; + + ini = PyInt_AsLong( inio ); + min = PyInt_AsLong( mino ); + max = PyInt_AsLong( maxo ); + + but->type = BINT_TYPE; + but->val.asint = ini; + + if( block ) + ubut= uiDefButI( block, NUM, event, name, (short)x, (short)y, (short)w, (short)h, + &but->val.asint, (float)min, (float)max, 0, 0, but->tooltip ); + } + + if (ubut) set_pycallback(ubut, callback, but); + + return ( PyObject * ) but; +} + +static PyObject *Method_String( PyObject * self, PyObject * args ) +{ + uiBlock *block; + char *info_arg = NULL, *tip = NULL, *newstr = NULL; + char *info_str = NULL, *info_str0 = " "; + int event; + int x, y, w, h, len, real_len = 0; + Button *but; + PyObject *callback=NULL; + + if( !PyArg_ParseTuple( args, "siiiiisi|sO", &info_arg, &event, + &x, &y, &w, &h, &newstr, &len, &tip, &callback ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a string, five ints, a string, an int and\n\ + optionally string and callback arguments" ); + + UI_METHOD_ERRORCHECK; + + if (len > (UI_MAX_DRAW_STR - 1)) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "The maximum length of a string is 399, your value is too high."); + + real_len = strlen(newstr); + if (real_len > len) real_len = len; + + but = newbutton( ); + but->type = BSTRING_TYPE; + but->slen = len; + but->val.asstr = MEM_mallocN( len + 1, "pybutton str" ); + if (tip) strncpy(but->tooltip, tip, BPY_MAX_TOOLTIP); + + BLI_strncpy( but->val.asstr, newstr, len + 1); /* adds '\0' */ + but->val.asstr[real_len] = '\0'; + + if (info_arg[0] == '\0') info_str = info_str0; + else info_str = info_arg; + + block = Get_uiBlock( ); + if( block ) { + uiBut *ubut = uiDefBut( block, TEX, event, info_str, (short)x, (short)y, (short)w, (short)h, + but->val.asstr, 0, (float)len, 0, 0, but->tooltip ); + set_pycallback(ubut, callback, but); + } + return ( PyObject * ) but; +} + +static PyObject *Method_GetStringWidth( PyObject * self, PyObject * args ) +{ + char *text; + char *font_str = "normal"; + struct BMF_Font *font; + PyObject *width; + + if( !PyArg_ParseTuple( args, "s|s", &text, &font_str ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected one or two string arguments" ); + + if( !strcmp( font_str, "normal" ) ) + font = ( &G )->font; + else if( !strcmp( font_str, "large" ) ) + font = BMF_GetFont(BMF_kScreen15); + else if( !strcmp( font_str, "small" ) ) + font = ( &G )->fonts; + else if( !strcmp( font_str, "tiny" ) ) + font = ( &G )->fontss; + else + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "\"font\" must be: 'large', 'normal' (default), 'small' or 'tiny'." ); + + width = PyInt_FromLong( BMF_GetStringWidth( font, text ) ); + + if( !width ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyInt" ); + + return width; +} + +static PyObject *Method_Text( PyObject * self, PyObject * args ) +{ + char *text; + char *font_str = NULL; + struct BMF_Font *font; + + if( !PyArg_ParseTuple( args, "s|s", &text, &font_str ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected one or two string arguments" ); + + if( !font_str ) + font = ( &G )->font; + else if( !strcmp( font_str, "large" ) ) + font = BMF_GetFont(BMF_kScreen15); + else if( !strcmp( font_str, "normal" ) ) + font = ( &G )->font; + else if( !strcmp( font_str, "small" ) ) + font = ( &G )->fonts; + else if( !strcmp( font_str, "tiny" ) ) + font = ( &G )->fontss; + else + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "\"font\" must be: 'normal' (default), 'large', 'small' or 'tiny'." ); + + BMF_DrawString( font, text ); + + return PyInt_FromLong( BMF_GetStringWidth( font, text ) ); +} + +static PyObject *Method_Label( PyObject * self, PyObject * args ) +{ + uiBlock *block; + char *text; + int x, y, w, h; + + if( !PyArg_ParseTuple( args, "siiii", &text, &x, &y, &w, &h ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a string and four ints" ); + + block = Get_uiBlock( ); + uiDefBut(block, LABEL, 0, text, x, y, w, h, 0, 0, 0, 0, 0, ""); + + Py_RETURN_NONE; +} + + +static PyObject *Method_PupMenu( PyObject * self, PyObject * args ) +{ + char *text; + int maxrow = -1; + PyObject *ret; + + if( !PyArg_ParseTuple( args, "s|i", &text, &maxrow ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a string and optionally an int as arguments" ); + + if( maxrow >= 0 ) + ret = PyInt_FromLong( pupmenu_col( text, maxrow ) ); + else + ret = PyInt_FromLong( pupmenu( text ) ); + + if( ret ) + return ret; + + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create a PyInt" ); +} + +static PyObject *Method_PupIntInput( PyObject * self, PyObject * args ) +{ + char *text = NULL; + int min = 0, max = 1; + short var = 0; + PyObject *ret = NULL; + + if( !PyArg_ParseTuple( args, "s|hii", &text, &var, &min, &max ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected 1 string and 3 int arguments" ); + + if( button( &var, (short)min, (short)max, text ) == 0 ) { + Py_INCREF( Py_None ); + return Py_None; + } + ret = PyInt_FromLong( var ); + if( ret ) + return ret; + + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create a PyInt" ); +} + +static PyObject *Method_PupFloatInput( PyObject * self, PyObject * args ) +{ + char *text = NULL; + float min = 0, max = 1, var = 0, a1 = 10, a2 = 2; + PyObject *ret = NULL; + + if( !PyArg_ParseTuple + ( args, "s|fffff", &text, &var, &min, &max, &a1, &a2 ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected 1 string and 5 float arguments" ); + + if( fbutton( &var, min, max, a1, a2, text ) == 0 ) { + Py_INCREF( Py_None ); + return Py_None; + } + ret = PyFloat_FromDouble( var ); + if( ret ) + return ret; + + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create a PyFloat" ); +} + +static PyObject *Method_PupStrInput( PyObject * self, PyObject * args ) +{ + char *text = NULL, *textMsg = NULL; + char tmp[101]; + char max = 20; + PyObject *ret = NULL; + + if( !PyArg_ParseTuple( args, "ss|b", &textMsg, &text, &max ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected 2 strings and 1 int" ); + + if( ( max <= 0 ) || ( max > 100 ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "max string length value must be in the range [1, 100]." ); + + /* copying the text string handles both cases: + * max < strlen(text) (by truncating) and + * max > strlen(text) (by expanding to strlen(tmp)) */ + BLI_strncpy( tmp, text, max + 1 ); + + if( sbutton( tmp, 0, max, textMsg ) == 0 ) { + Py_INCREF( Py_None ); + return Py_None; + } + + ret = PyString_FromString( tmp ); + + if( ret ) + return ret; + + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create a PyString" ); +} + +static PyObject *Method_PupBlock( PyObject * self, PyObject * args ) +{ + PyObject *pyList, *pyItem; + float min, max; + int len, i; + char *title; + + if (!PyArg_ParseTuple( args, "sO", &title, &pyList ) || !PySequence_Check( pyList )) + return EXPP_ReturnPyObjError( PyExc_TypeError, "expected a string and a sequence" ); + + + len = PySequence_Length(pyList); + + if (len == 0) + return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string and a non-empty sequence." ); + + if (len > 120) /* LIMIT DEFINED IN toolbox.c */ + return EXPP_ReturnPyObjError( PyExc_ValueError, "sequence cannot have more than 120 elements" ); + + for ( i=0 ; itype != BINT_TYPE) { + Py_DECREF( pyItem ); + return EXPP_ReturnPyObjError( PyExc_ValueError, "Button object for toggles should hold an integer" ); + } + + add_numbut(i, TOG|INT, text, 0, 0, &but->val.asint, tip); + break; + case 4: /* TEX and NUM (no tooltip) */ + case 5: /* TEX and NUM */ + if (!PyArg_ParseTuple( pyItem, "sO!OO|s", &text, &Button_Type, &but, &pyMin, &pyMax, &tip )) { + Py_DECREF( pyItem ); + return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a tuple containing a string, a Button object, two numerical values and optionally a string for Text and Num buttons" ); + } + + f1 = PyNumber_Float(pyMin); + f2 = PyNumber_Float(pyMax); + + if (!f1 || !f2) { + Py_DECREF( pyItem ); + return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a tuple containing a string, a Button object, two numerical values and optionally a string for Text and Num buttons" ); + } + + min = (float)PyFloat_AS_DOUBLE(f1); + max = (float)PyFloat_AS_DOUBLE(f2); + Py_DECREF( f1 ); + Py_DECREF( f2 ); + + switch ( but->type ) { + case BINT_TYPE: + add_numbut(i, NUM|INT, text, min, max, &but->val.asint, tip); + break; + case BFLOAT_TYPE: + add_numbut(i, NUM|FLO, text, min, max, &but->val.asfloat, tip); + break; + case BSTRING_TYPE: + if (max+1>UI_MAX_DRAW_STR) { + Py_DECREF( pyItem ); + return EXPP_ReturnPyObjError( PyExc_ValueError, "length of a string buttons must be less then 400" ); + } + max = (float)floor(max); + + if (max > but->slen) { + int old_len = but->slen; + char *old_str = but->val.asstr; + but->slen = (int)max; + but->val.asstr = MEM_callocN( but->slen + 1, "button pupblock"); + BLI_strncpy( but->val.asstr, old_str, old_len + 1 ); + MEM_freeN(old_str); + } + + add_numbut(i, TEX, text, 0.0f, max, but->val.asstr, tip); + } + + break; + default: + Py_DECREF( pyItem ); + return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string or a tuple containing 2 to 5 values." ); + } + Py_DECREF( pyItem ); + } + + if (do_clever_numbuts(title, len, REDRAW)) + return EXPP_incr_ret_True(); + else + return EXPP_incr_ret_False(); +} + + +/***************************************************************************** + * Function: Method_Image * + * Python equivalent: Blender.Draw.Image * + * * + * @author Jonathan Merritt * + ****************************************************************************/ +static PyObject *Method_Image( PyObject * self, PyObject * args ) +{ + PyObject *pyObjImage; + BPy_Image *py_img; + Image *image; + ImBuf *ibuf; + float originX, originY; + float zoomX = 1.0, zoomY = 1.0; + int clipX = 0, clipY = 0, clipW = -1, clipH = -1; + /*GLfloat scissorBox[4];*/ + + /* parse the arguments passed-in from Python */ + if( !PyArg_ParseTuple( args, "Off|ffiiii", &pyObjImage, + &originX, &originY, &zoomX, &zoomY, + &clipX, &clipY, &clipW, &clipH ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a Blender.Image and 2 floats, and " \ + "optionally 2 floats and 4 ints as arguments" ); + /* check that the first PyObject is actually a Blender.Image */ + if( !BPy_Image_Check( pyObjImage ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a Blender.Image and 2 floats, and " \ + "optionally 2 floats and 4 ints as arguments" ); + /* check that the zoom factors are valid */ + if( ( zoomX <= 0.0 ) || ( zoomY <= 0.0 ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "invalid zoom factors - they must be >= 0.0" ); + + /* fetch a C Image pointer from the passed-in Python object */ + py_img = ( BPy_Image * ) pyObjImage; + image = py_img->image; + ibuf = BKE_image_get_ibuf( image, NULL ); + + if( !ibuf ) /* if failed to load the image */ + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't load image data in Blender" ); + if( !ibuf->rect ) /* no float yet */ + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Image has no byte rect" ); + + /* Update the time tag of the image */ + tag_image_time(image); + + /* set up a valid clipping rectangle. if no clip rectangle was + * given, this results in inclusion of the entire image. otherwise, + * the clipping is just checked against the bounds of the image. + * if clipW or clipH are less than zero then they include as much of + * the image as they can. */ + clipX = EXPP_ClampInt( clipX, 0, ibuf->x ); + clipY = EXPP_ClampInt( clipY, 0, ibuf->y ); + if( ( clipW < 0 ) || ( clipW > ( ibuf->x - clipW ) ) ) + clipW = ibuf->x - clipX; + if( ( clipH < 0 ) || ( clipH > ( ibuf->y - clipH ) ) ) + clipH = ibuf->y - clipY; + + /* -- we are "Go" to Draw! -- */ + + /* set the raster position. + * + * If the raster position is negative, then using glRasterPos2i() + * directly would cause it to be clipped. Instead, we first establish + * a valid raster position within the clipping rectangle of the + * window and then use glBitmap() with a NULL image pointer to offset + * it to the true position we require. To pick an initial valid + * raster position within the viewport, we query the clipping rectangle + * and use its lower-left pixel. + * + * This particular technique is documented in the glRasterPos() man + * page, although I haven't seen it used elsewhere in Blender. + */ + + /* update (W): to fix a bug where images wouldn't get drawn if the bottom + * left corner of the Scripts win were above a given height or to the right + * of a given width, the code below is being commented out. It should not + * be needed anyway, because spaces in Blender are projected to lie inside + * their areas, see src/drawscript.c for example. Note: the + * glaRasterPosSafe2i function in src/glutil.c does use the commented out + * technique, but with 0,0 instead of scissorBox. This function can be + * a little optimized, based on glaDrawPixelsSafe in that same fine, but + * we're too close to release 2.37 right now. */ + /* + glGetFloatv( GL_SCISSOR_BOX, scissorBox ); + glRasterPos2i( scissorBox[0], scissorBox[1] ); + glBitmap( 0, 0, 0.0, 0.0, + originX-scissorBox[0], originY-scissorBox[1], NULL ); + */ + + /* update (cont.): using these two lines instead: + * (based on glaRasterPosSafe2i, but Ken Hughes deserves credit + * for suggesting this exact fix in the bug tracker) */ + glRasterPos2i(0, 0); + glBitmap( 0, 0, 0.0, 0.0, originX, originY, NULL ); + + /* set the zoom */ + glPixelZoom( zoomX, zoomY ); + + /* set the width of the image (ROW_LENGTH), and the offset to the + * clip origin within the image in x (SKIP_PIXELS) and + * y (SKIP_ROWS) */ + glPixelStorei( GL_UNPACK_ROW_LENGTH, ibuf->x ); + glPixelStorei( GL_UNPACK_SKIP_PIXELS, clipX ); + glPixelStorei( GL_UNPACK_SKIP_ROWS, clipY ); + + /* draw the image */ + glDrawPixels( clipW, clipH, GL_RGBA, GL_UNSIGNED_BYTE, + ibuf->rect ); + + /* restore the defaults for some parameters (we could also use a + * glPushClientAttrib() and glPopClientAttrib() pair). */ + glPixelZoom( 1.0, 1.0 ); + glPixelStorei( GL_UNPACK_SKIP_ROWS, 0 ); + glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0 ); + glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 ); + + Py_INCREF( Py_None ); + return Py_None; + +} + +PyObject *Draw_Init( void ) +{ + PyObject *submodule, *dict; + + if( PyType_Ready( &Button_Type) < 0) + Py_RETURN_NONE; + + submodule = Py_InitModule3( "Blender.Draw", Draw_methods, Draw_doc ); + + dict = PyModule_GetDict( submodule ); + +#define EXPP_ADDCONST(x) \ + EXPP_dict_set_item_str(dict, #x, PyInt_FromLong(x)) + + /* So, for example: + * EXPP_ADDCONST(LEFTMOUSE) becomes + * EXPP_dict_set_item_str(dict, "LEFTMOUSE", PyInt_FromLong(LEFTMOUSE)) + */ + + EXPP_ADDCONST( LEFTMOUSE ); + EXPP_ADDCONST( MIDDLEMOUSE ); + EXPP_ADDCONST( RIGHTMOUSE ); + EXPP_ADDCONST( WHEELUPMOUSE ); + EXPP_ADDCONST( WHEELDOWNMOUSE ); + EXPP_ADDCONST( MOUSEX ); + EXPP_ADDCONST( MOUSEY ); + EXPP_ADDCONST( TIMER0 ); + EXPP_ADDCONST( TIMER1 ); + EXPP_ADDCONST( TIMER2 ); + EXPP_ADDCONST( TIMER3 ); + EXPP_ADDCONST( KEYBD ); + EXPP_ADDCONST( RAWKEYBD ); + EXPP_ADDCONST( REDRAW ); + EXPP_ADDCONST( INPUTCHANGE ); + EXPP_ADDCONST( QFULL ); + EXPP_ADDCONST( WINFREEZE ); + EXPP_ADDCONST( WINTHAW ); + EXPP_ADDCONST( WINCLOSE ); + EXPP_ADDCONST( WINQUIT ); +#ifndef IRISGL + EXPP_ADDCONST( Q_FIRSTTIME ); +#endif + EXPP_ADDCONST( AKEY ); + EXPP_ADDCONST( BKEY ); + EXPP_ADDCONST( CKEY ); + EXPP_ADDCONST( DKEY ); + EXPP_ADDCONST( EKEY ); + EXPP_ADDCONST( FKEY ); + EXPP_ADDCONST( GKEY ); + EXPP_ADDCONST( HKEY ); + EXPP_ADDCONST( IKEY ); + EXPP_ADDCONST( JKEY ); + EXPP_ADDCONST( KKEY ); + EXPP_ADDCONST( LKEY ); + EXPP_ADDCONST( MKEY ); + EXPP_ADDCONST( NKEY ); + EXPP_ADDCONST( OKEY ); + EXPP_ADDCONST( PKEY ); + EXPP_ADDCONST( QKEY ); + EXPP_ADDCONST( RKEY ); + EXPP_ADDCONST( SKEY ); + EXPP_ADDCONST( TKEY ); + EXPP_ADDCONST( UKEY ); + EXPP_ADDCONST( VKEY ); + EXPP_ADDCONST( WKEY ); + EXPP_ADDCONST( XKEY ); + EXPP_ADDCONST( YKEY ); + EXPP_ADDCONST( ZKEY ); + EXPP_ADDCONST( ZEROKEY ); + EXPP_ADDCONST( ONEKEY ); + EXPP_ADDCONST( TWOKEY ); + EXPP_ADDCONST( THREEKEY ); + EXPP_ADDCONST( FOURKEY ); + EXPP_ADDCONST( FIVEKEY ); + EXPP_ADDCONST( SIXKEY ); + EXPP_ADDCONST( SEVENKEY ); + EXPP_ADDCONST( EIGHTKEY ); + EXPP_ADDCONST( NINEKEY ); + EXPP_ADDCONST( CAPSLOCKKEY ); + EXPP_ADDCONST( LEFTCTRLKEY ); + EXPP_ADDCONST( LEFTALTKEY ); + EXPP_ADDCONST( RIGHTALTKEY ); + EXPP_ADDCONST( RIGHTCTRLKEY ); + EXPP_ADDCONST( RIGHTSHIFTKEY ); + EXPP_ADDCONST( LEFTSHIFTKEY ); + EXPP_ADDCONST( ESCKEY ); + EXPP_ADDCONST( TABKEY ); + EXPP_ADDCONST( RETKEY ); + EXPP_ADDCONST( SPACEKEY ); + EXPP_ADDCONST( LINEFEEDKEY ); + EXPP_ADDCONST( BACKSPACEKEY ); + EXPP_ADDCONST( DELKEY ); + EXPP_ADDCONST( SEMICOLONKEY ); + EXPP_ADDCONST( PERIODKEY ); + EXPP_ADDCONST( COMMAKEY ); + EXPP_ADDCONST( QUOTEKEY ); + EXPP_ADDCONST( ACCENTGRAVEKEY ); + EXPP_ADDCONST( MINUSKEY ); + EXPP_ADDCONST( SLASHKEY ); + EXPP_ADDCONST( BACKSLASHKEY ); + EXPP_ADDCONST( EQUALKEY ); + EXPP_ADDCONST( LEFTBRACKETKEY ); + EXPP_ADDCONST( RIGHTBRACKETKEY ); + EXPP_ADDCONST( LEFTARROWKEY ); + EXPP_ADDCONST( DOWNARROWKEY ); + EXPP_ADDCONST( RIGHTARROWKEY ); + EXPP_ADDCONST( UPARROWKEY ); + EXPP_ADDCONST( PAD2 ); + EXPP_ADDCONST( PAD4 ); + EXPP_ADDCONST( PAD6 ); + EXPP_ADDCONST( PAD8 ); + EXPP_ADDCONST( PAD1 ); + EXPP_ADDCONST( PAD3 ); + EXPP_ADDCONST( PAD5 ); + EXPP_ADDCONST( PAD7 ); + EXPP_ADDCONST( PAD9 ); + EXPP_ADDCONST( PADPERIOD ); + EXPP_ADDCONST( PADSLASHKEY ); + EXPP_ADDCONST( PADASTERKEY ); + EXPP_ADDCONST( PAD0 ); + EXPP_ADDCONST( PADMINUS ); + EXPP_ADDCONST( PADENTER ); + EXPP_ADDCONST( PADPLUSKEY ); + EXPP_ADDCONST( F1KEY ); + EXPP_ADDCONST( F2KEY ); + EXPP_ADDCONST( F3KEY ); + EXPP_ADDCONST( F4KEY ); + EXPP_ADDCONST( F5KEY ); + EXPP_ADDCONST( F6KEY ); + EXPP_ADDCONST( F7KEY ); + EXPP_ADDCONST( F8KEY ); + EXPP_ADDCONST( F9KEY ); + EXPP_ADDCONST( F10KEY ); + EXPP_ADDCONST( F11KEY ); + EXPP_ADDCONST( F12KEY ); + EXPP_ADDCONST( PAUSEKEY ); + EXPP_ADDCONST( INSERTKEY ); + EXPP_ADDCONST( HOMEKEY ); + EXPP_ADDCONST( PAGEUPKEY ); + EXPP_ADDCONST( PAGEDOWNKEY ); + EXPP_ADDCONST( ENDKEY ); + + return submodule; +} diff --git a/source/blender/python/api2_2x/Draw.h b/source/blender/python/api2_2x/Draw.h new file mode 100644 index 00000000000..12712713d1d --- /dev/null +++ b/source/blender/python/api2_2x/Draw.h @@ -0,0 +1,77 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +/* The code in Draw.[ch] and BGL.[ch] comes from opy_draw.c in the old + * bpython/intern dir, with minor modifications to suit the current + * implementation. Important original comments are marked with an @ symbol. */ + +#ifndef EXPP_DRAW_H_ +#define EXPP_DRAW_H_ + +#include +#include "DNA_space_types.h" +#include "DNA_text_types.h" + +void initDraw( void ); + +/* + * Button Object stuct + */ + +typedef struct _Button { + PyObject_VAR_HEAD /* required Py Macro */ + int type; /*@ 1 == int, 2 == float, 3 == string */ + unsigned int slen; /*@ length of string (if type == 3) */ + union { + int asint; + float asfloat; + char *asstr; + float asvec[3]; + } val; + char tooltip[256]; +} Button; + +#define BPY_MAX_TOOLTIP 255 + +#define BINT_TYPE 1 +#define BFLOAT_TYPE 2 +#define BSTRING_TYPE 3 +#define BVECTOR_TYPE 4 + +/* + * these are declared in ../BPY_extern.h +*/ + +PyObject *M_Draw_Init( void ); +PyObject *Draw_Init( void ); + +#endif /* EXPP_DRAW_H */ diff --git a/source/blender/python/api2_2x/EXPP_interface.c b/source/blender/python/api2_2x/EXPP_interface.c new file mode 100644 index 00000000000..ee8b04ebde9 --- /dev/null +++ b/source/blender/python/api2_2x/EXPP_interface.c @@ -0,0 +1,230 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Michel Selten + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#include + +#include "EXPP_interface.h" +#include "BLI_blenlib.h" +#include "MEM_guardedalloc.h" +#include "BLI_linklist.h" /* linked list: LinkNode struct and functions */ +#include "DNA_object_types.h" +#include "DNA_space_types.h" /* for FILE_MAXDIR, FILE_MAXFILE */ +#include "Blender.h" + +extern char bprogname[]; /* argv[0] from creator.c */ + +/* this makes sure BLI_gethome() returns a path with '.blender' appended + * Besides, this function now either returns userhome/.blender (if it exists) + * or blenderInstallDir/.blender/ otherwise (can also be cvs dir). + * If append_scriptsdir is non NULL, "scripts/" is appended to the dir, to + * get the path to the scripts folder ("release/scripts/" if cvs dir). + * Finally, if all else fails BLI_gethome() is returned + * (or NULL if append_scriptdir != 0). +*/ +char *bpy_gethome(int append_scriptsdir) +{ + static char homedir[FILE_MAXDIR]; + static char scriptsdir[FILE_MAXDIR]; + char tmpdir[FILE_MAXDIR]; + char bprogdir[FILE_MAXDIR]; + char *s; + int i; + + if (append_scriptsdir) { + if (scriptsdir[0] != '\0') + return scriptsdir; + } + else if (homedir[0] != '\0') + return homedir; + + /* BLI_gethome() can return NULL if env vars are not set */ + s = BLI_gethome(); + + if( !s ) /* bail if no $HOME */ + { + printf("$HOME is NOT set\n"); + return NULL; + } + + if( strstr( s, ".blender" ) ) + PyOS_snprintf( homedir, FILE_MAXDIR, s ); + else + BLI_make_file_string( "/", homedir, s, ".blender" ); + + /* if userhome/.blender/ exists, return it */ + if( BLI_exists( homedir ) ) { + if (append_scriptsdir) { + BLI_make_file_string("/", scriptsdir, homedir, "scripts"); + if (BLI_exists (scriptsdir)) return scriptsdir; + } + else return homedir; + } + else homedir[0] = '\0'; + + /* if either: + * no homedir was found or + * append_scriptsdir = 1 but there's no scripts/ inside homedir, + * use argv[0] (bprogname) to get .blender/ in + * Blender's installation dir */ + s = BLI_last_slash( bprogname ); + + i = s - bprogname + 1; + + PyOS_snprintf( bprogdir, i, "%s", bprogname ); + + /* using tmpdir to preserve homedir (if) found above: + * the ideal is to have a home dir with scripts dir inside + * it, but if that isn't available, it's possible to + * have a 'broken' home dir somewhere and a scripts dir in the + * cvs sources */ + BLI_make_file_string( "/", tmpdir, bprogdir, ".blender" ); + + if (BLI_exists(tmpdir)) { + if (append_scriptsdir) { + BLI_make_file_string("/", scriptsdir, tmpdir, "scripts"); + if (BLI_exists(scriptsdir)) { + PyOS_snprintf(homedir, FILE_MAXDIR, "%s", tmpdir); + return scriptsdir; + } + else { + homedir[0] = '\0'; + scriptsdir[0] = '\0'; + } + } + else return homedir; + } + + /* last try for scripts dir: blender in cvs dir, scripts/ inside release/: */ + if (append_scriptsdir) { + BLI_make_file_string("/", scriptsdir, bprogdir, "release/scripts"); + if (BLI_exists(scriptsdir)) return scriptsdir; + else scriptsdir[0] = '\0'; + } + + return NULL; +} + +/* PyDrivers */ + +/* + * Pydrivers are Blender Ipo Drivers defined by Python expressions. + * We need to tell DAG about objects used in these expressions, so we + * eval each expression to collect the ob refs. in it. + */ + +/* these are checked for example in Object.c: M_Object_Get (Object.Get()) + * to collect the refs. */ +static int pydriver_running = 0; + +int bpy_during_pydriver(void) +{ + return pydriver_running; +} + +void bpy_pydriver_running(int state) +{ + pydriver_running = state; +} + +/* Obj references are collected in this extern linked list: */ +LinkNode *bpy_pydriver_oblist = NULL; + +void bpy_pydriver_freeList(void) +{ + BLI_linklist_free(bpy_pydriver_oblist, NULL); + bpy_pydriver_oblist = NULL; +} + +void bpy_pydriver_appendToList(struct Object *ob) +{ + LinkNode *ln = bpy_pydriver_oblist; + + /* check that the expression is not referencing its owner object */ + +/* XXX COMMENTED OUT TO TEST IF WE REALLY NEED TO IMPOSE THIS RESTRICTION + if (ln && ln->link) { + if (ob == (Object *)ln->link) { + PyErr_SetString(PyExc_AttributeError, + "Python driver expression can't reference its own object"); + return; + } + else + ln = ln->next; + } +*/ + while (ln) { /* is ob already in list? ... */ + if (ob == (Object *)ln->link) + break; + ln = ln->next; + } + + if (!ln) /* ... not yet, append it */ + BLI_linklist_append(&bpy_pydriver_oblist, (void *)ob); + + return; +} + +/* Get an array from our linked list of objs referenced in the + * current pydriver. The first node in the list is discarded, + * since it is the actual pydriver owner, which shouldn't be + * passed to the depsgraph (no self references). */ +struct Object **bpy_pydriver_obArrayFromList(void) +{ + Object **obarray = NULL; + + if (bpy_pydriver_oblist) { + int i; + short len = BLI_linklist_length(bpy_pydriver_oblist); + + if (len > 1) { + + obarray = (Object **)MEM_mallocN(sizeof(Object*)*len, + "pydriver array"); + + if (obarray) { + LinkNode *ln = bpy_pydriver_oblist; + ln = ln->next; /* skip first ob, which is the pydriver owner */ + + for (i = 0; i < len-1; i++) { + obarray[i] = (Object *)ln->link; + ln = ln->next; + } + + obarray[len-1] = NULL; /* NULL-terminated array */ + } + } + bpy_pydriver_freeList(); + } + + return obarray; +} + diff --git a/source/blender/python/api2_2x/EXPP_interface.h b/source/blender/python/api2_2x/EXPP_interface.h new file mode 100644 index 00000000000..80767af1c01 --- /dev/null +++ b/source/blender/python/api2_2x/EXPP_interface.h @@ -0,0 +1,56 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Michel Selten, Willian P. Germano + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_INTERFACE_H +#define EXPP_INTERFACE_H + +struct Object; +struct Script; +struct LinkNode; + +extern struct LinkNode *bpy_pydriver_oblist; + +void initBlenderApi2_2x( void ); +char *bpy_gethome( int append_scriptsdir ); +void discardFromBDict( char *key ); +void EXPP_Library_Close( void ); /* in Library.c, used by BPY_end_python */ + +/* PyDrivers */ + +void bpy_pydriver_freeList(void); +void bpy_pydriver_appendToList(struct Object *ob); +struct Object **bpy_pydriver_obArrayFromList(void); + +int bpy_during_pydriver(void); +void bpy_pydriver_running(int state); + +#endif /* EXPP_INTERFACE_H */ diff --git a/source/blender/python/api2_2x/Effect.c b/source/blender/python/api2_2x/Effect.c new file mode 100644 index 00000000000..ce6b553da0d --- /dev/null +++ b/source/blender/python/api2_2x/Effect.c @@ -0,0 +1,1575 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Jacques Guignot, Jean-Michel Soler, Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#include "Effect.h" /*This must come first */ + +#include "DNA_object_types.h" +#include "DNA_scene_types.h" /* for G.scene->r.cfra */ +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_effect.h" +#include "BKE_object.h" +#include "BKE_deform.h" +#include "BKE_scene.h" /* for G.scene->r.cfra */ +#include "BKE_ipo.h" /* frame_to_float() */ +#include "BLI_blenlib.h" +#include "gen_utils.h" +#include "blendef.h" +#include "vector.h" +#include "MTC_matrixops.h" + +#define EXPP_EFFECT_STA_MIN -250.0f +#define EXPP_EFFECT_END_MIN 1.0f +#define EXPP_EFFECT_LIFETIME_MIN 1.0f +#define EXPP_EFFECT_NORMFAC_MIN -2.0f +#define EXPP_EFFECT_NORMFAC_MAX 2.0f +#define EXPP_EFFECT_OBFAC_MIN -1.0f +#define EXPP_EFFECT_OBFAC_MAX 1.0f +#define EXPP_EFFECT_RANDFAC_MIN 0.0f +#define EXPP_EFFECT_RANDFAC_MAX 2.0f +#define EXPP_EFFECT_TEXFAC_MIN 0.0f +#define EXPP_EFFECT_TEXFAC_MAX 2.0f +#define EXPP_EFFECT_RANDLIFE_MIN 0.0f +#define EXPP_EFFECT_RANDLIFE_MAX 2.0f +#define EXPP_EFFECT_NABLA_MIN 0.0001f +#define EXPP_EFFECT_NABLA_MAX 1.0f +#define EXPP_EFFECT_VECTSIZE_MIN 0.0f +#define EXPP_EFFECT_VECTSIZE_MAX 1.0f +#define EXPP_EFFECT_TOTPART_MIN 1.0f +#define EXPP_EFFECT_TOTPART_MAX 100000.0f +#define EXPP_EFFECT_FORCE_MIN -1.0f +#define EXPP_EFFECT_FORCE_MAX 1.0f +#define EXPP_EFFECT_MULT_MIN 0.0f +#define EXPP_EFFECT_MULT_MAX 1.0f +#define EXPP_EFFECT_LIFE_MIN 1.0f +#define EXPP_EFFECT_DEFVEC_MIN -1.0f +#define EXPP_EFFECT_DEFVEC_MAX 1.0f +#define EXPP_EFFECT_DAMP_MIN 0.0f +#define EXPP_EFFECT_DAMP_MAX 1.0f + +#define EXPP_EFFECT_TOTKEY_MIN 1 +#define EXPP_EFFECT_TOTKEY_MAX 100 +#define EXPP_EFFECT_SEED_MIN 0 +#define EXPP_EFFECT_SEED_MAX 255 +#define EXPP_EFFECT_CHILD_MIN 1 +#define EXPP_EFFECT_CHILD_MAX 600 +#define EXPP_EFFECT_CHILDMAT_MIN 1 +#define EXPP_EFFECT_CHILDMAT_MAX 16 +#define EXPP_EFFECT_JITTER_MIN 0 +#define EXPP_EFFECT_JITTER_MAX 200 +#define EXPP_EFFECT_DISPMAT_MIN 1 +#define EXPP_EFFECT_DISPMAT_MAX 16 +#define EXPP_EFFECT_TIMETEX_MIN 1 +#define EXPP_EFFECT_TIMETEX_MAX 10 +#define EXPP_EFFECT_SPEEDTEX_MIN 1 +#define EXPP_EFFECT_SPEEDTEX_MAX 10 +#define EXPP_EFFECT_TEXMAP_MIN 1 +#define EXPP_EFFECT_TEXMAP_MAX 3 + +#define EXPP_EFFECT_SPEEDTYPE_INTENSITY 0 +#define EXPP_EFFECT_SPEEDTYPE_RGB 1 +#define EXPP_EFFECT_SPEEDTYPE_GRADIENT 2 + +#define EXPP_EFFECT_STATICSTEP_MIN 1 +#define EXPP_EFFECT_STATICSTEP_MAX 100 +#define EXPP_EFFECT_DISP_MIN 0 +#define EXPP_EFFECT_DISP_MAX 100 + +/*****************************************************************************/ +/* Python API function prototypes for the Blender module. */ +/*****************************************************************************/ +static PyObject *M_Effect_New( PyObject * self, PyObject * args ); +static PyObject *M_Effect_Get( PyObject * self, PyObject * args ); + +/*****************************************************************************/ +/* Python BPy_Effect methods declarations: */ +/*****************************************************************************/ +static PyObject *Effect_getType( BPy_Effect * self ); +static int Effect_setType( void ); +static PyObject *Effect_getStype( BPy_Effect * self ); +static int Effect_setStype( BPy_Effect * self, PyObject * args ); +static PyObject *Effect_getFlag( BPy_Effect * self ); +static int Effect_setFlag( BPy_Effect * self, PyObject * args ); +static PyObject *Effect_getSta( BPy_Effect * self ); +static int Effect_setSta( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getEnd( BPy_Effect * self ); +static int Effect_setEnd( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getLifetime( BPy_Effect * self ); +static int Effect_setLifetime( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getNormfac( BPy_Effect * self ); +static int Effect_setNormfac( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getObfac( BPy_Effect * self ); +static int Effect_setObfac( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getRandfac( BPy_Effect * self ); +static int Effect_setRandfac( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getTexfac( BPy_Effect * self ); +static int Effect_setTexfac( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getRandlife( BPy_Effect * self ); +static int Effect_setRandlife( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getNabla( BPy_Effect * self ); +static int Effect_setNabla( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getVectsize( BPy_Effect * self ); +static int Effect_setVectsize( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getTotpart( BPy_Effect * self ); +static int Effect_setTotpart( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getTotkey( BPy_Effect * self ); +static int Effect_setTotkey( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getSeed( BPy_Effect * self ); +static int Effect_setSeed( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getForce( BPy_Effect * self ); +static int Effect_setForce( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getMult( BPy_Effect * self ); +static int Effect_setMult( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getLife( BPy_Effect * self ); +static int Effect_setLife( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getChildMat( BPy_Effect * self ); +static int Effect_setChildMat( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getChild( BPy_Effect * self ); +static int Effect_setChild( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getDefvec( BPy_Effect * self ); +static int Effect_setDefvec( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getJitter( BPy_Effect * self ); +static int Effect_setJitter( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getDispMat( BPy_Effect * self ); +static int Effect_setDispMat( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getEmissionTex( BPy_Effect * self ); +static int Effect_setEmissionTex( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getForceTex( BPy_Effect * self ); +static int Effect_setForceTex( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getDamping( BPy_Effect * self ); +static int Effect_setDamping( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getSpeedType( BPy_Effect * self ); +static int Effect_setSpeedType( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getVertGroup( BPy_Effect * self ); +static int Effect_setVertGroup( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getSpeedVertGroup( BPy_Effect * self ); +static int Effect_setSpeedVertGroup( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_getStaticStep( BPy_Effect * self ); +static int Effect_setStaticStep( BPy_Effect * self , PyObject * a); +static PyObject *Effect_getDisp( BPy_Effect * self ); +static int Effect_setDisp( BPy_Effect * self , PyObject * a); +static PyObject *Effect_getParticlesLoc( BPy_Effect * self ); + +static PyObject *Effect_oldsetType( void ); +static PyObject *Effect_oldsetStype( BPy_Effect * self, PyObject * args ); +static PyObject *Effect_oldsetFlag( BPy_Effect * self, PyObject * args ); +static PyObject *Effect_oldsetSta( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_oldsetEnd( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_oldsetLifetime( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_oldsetNormfac( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_oldsetObfac( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_oldsetRandfac( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_oldsetTexfac( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_oldsetRandlife( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_oldsetNabla( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_oldsetVectsize( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_oldsetTotpart( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_oldsetTotkey( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_oldsetSeed( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_oldsetForce( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_oldsetMult( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_oldsetLife( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_oldsetMat( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_oldsetChild( BPy_Effect * self, PyObject * a ); +static PyObject *Effect_oldsetDefvec( BPy_Effect * self, PyObject * a ); + +/*****************************************************************************/ +/* Python Effect_Type callback function prototypes: */ +/*****************************************************************************/ +static PyObject *Effect_repr( void ); + +/*****************************************************************************/ +/* The following string definitions are used for documentation strings. */ +/* In Python these will be written to the console when doing a */ +/* Blender.Particle.__doc__ */ +/*****************************************************************************/ +static char M_Particle_doc[] = "The Blender Effect module\n\n\ +This module provides access to **Object Data** in Blender.\n\ +Functions :\n\ + New(name) : creates a new part object and adds it to the given mesh object \n\ + Get(name) : retreives a particle with the given name (mandatory)\n\ + get(name) : same as Get. Kept for compatibility reasons.\n"; +static char M_Effect_New_doc[] = "New(name) : creates a new part object and adds it to the given mesh object\n"; +static char M_Effect_Get_doc[] = "xxx"; + +/*****************************************************************************/ +/* Python method structure definition for Blender.Particle module: */ +/*****************************************************************************/ +static struct PyMethodDef M_Particle_methods[] = { + {"New", ( PyCFunction ) M_Effect_New, METH_VARARGS, M_Effect_New_doc}, + {"Get", M_Effect_Get, METH_VARARGS, M_Effect_Get_doc}, + {"get", M_Effect_Get, METH_VARARGS, M_Effect_Get_doc}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python BPy_Effect methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_Effect_methods[] = { + {"getType", ( PyCFunction ) Effect_getType, + METH_NOARGS, "() - Return Effect type"}, + {"setType", ( PyCFunction ) Effect_oldsetType, + METH_VARARGS, "() - Set Effect type"}, + {"getStype", ( PyCFunction ) Effect_getStype, + METH_NOARGS, "() - Return Effect stype"}, + {"setStype", ( PyCFunction ) Effect_oldsetStype, + METH_VARARGS, "() - Set Effect stype"}, + {"getFlag", ( PyCFunction ) Effect_getFlag, + METH_NOARGS, "() - Return Effect flag"}, + {"setFlag", ( PyCFunction ) Effect_oldsetFlag, + METH_VARARGS, "() - Set Effect flag"}, + {"getStartTime", ( PyCFunction ) Effect_getSta, + METH_NOARGS, "()-Return particle start time"}, + {"setStartTime", ( PyCFunction ) Effect_oldsetSta, METH_VARARGS, + "()- Sets particle start time"}, + {"getEndTime", ( PyCFunction ) Effect_getEnd, + METH_NOARGS, "()-Return particle end time"}, + {"setEndTime", ( PyCFunction ) Effect_oldsetEnd, METH_VARARGS, + "()- Sets particle end time"}, + {"getLifetime", ( PyCFunction ) Effect_getLifetime, + METH_NOARGS, "()-Return particle life time"}, + {"setLifetime", ( PyCFunction ) Effect_oldsetLifetime, METH_VARARGS, + "()- Sets particle life time "}, + {"getNormfac", ( PyCFunction ) Effect_getNormfac, + METH_NOARGS, "()-Return particle life time"}, + {"setNormfac", ( PyCFunction ) Effect_oldsetNormfac, METH_VARARGS, + "()- Sets particle life time "}, + {"getObfac", ( PyCFunction ) Effect_getObfac, + METH_NOARGS, "()-Return particle life time"}, + {"setObfac", ( PyCFunction ) Effect_oldsetObfac, METH_VARARGS, + "()- Sets particle life time "}, + {"getRandfac", ( PyCFunction ) Effect_getRandfac, + METH_NOARGS, "()-Return particle life time"}, + {"setRandfac", ( PyCFunction ) Effect_oldsetRandfac, METH_VARARGS, + "()- Sets particle life time "}, + {"getTexfac", ( PyCFunction ) Effect_getTexfac, + METH_NOARGS, "()-Return particle life time"}, + {"setTexfac", ( PyCFunction ) Effect_oldsetTexfac, METH_VARARGS, + "()- Sets particle life time "}, + {"getRandlife", ( PyCFunction ) Effect_getRandlife, + METH_NOARGS, "()-Return particle life time"}, + {"setRandlife", ( PyCFunction ) Effect_oldsetRandlife, METH_VARARGS, + "()- Sets particle life time "}, + {"getNabla", ( PyCFunction ) Effect_getNabla, + METH_NOARGS, "()-Return particle life time"}, + {"setNabla", ( PyCFunction ) Effect_oldsetNabla, METH_VARARGS, + "()- Sets particle life time "}, + {"getVectsize", ( PyCFunction ) Effect_getVectsize, + METH_NOARGS, "()-Return particle life time"}, + {"setVectsize", ( PyCFunction ) Effect_oldsetVectsize, METH_VARARGS, + "()- Sets particle life time "}, + {"getTotpart", ( PyCFunction ) Effect_getTotpart, + METH_NOARGS, "()-Return particle life time"}, + {"setTotpart", ( PyCFunction ) Effect_oldsetTotpart, METH_VARARGS, + "()- Sets particle life time "}, + {"getTotkey", ( PyCFunction ) Effect_getTotkey, + METH_NOARGS, "()-Return the number of key positions."}, + {"setTotkey", ( PyCFunction ) Effect_oldsetTotkey, METH_VARARGS, + "()-Set the number of key positions. "}, + {"getSeed", ( PyCFunction ) Effect_getSeed, + METH_NOARGS, "()-Return particle life time"}, + {"setSeed", ( PyCFunction ) Effect_oldsetSeed, METH_VARARGS, + "()- Sets particle life time "}, + {"getForce", ( PyCFunction ) Effect_getForce, + METH_NOARGS, "()-Return particle life time"}, + {"setForce", ( PyCFunction ) Effect_oldsetForce, METH_VARARGS, + "()- Sets particle life time "}, + {"getMult", ( PyCFunction ) Effect_getMult, + METH_NOARGS, "()-Return particle life time"}, + {"setMult", ( PyCFunction ) Effect_oldsetMult, METH_VARARGS, + "()- Sets particle life time "}, + {"getLife", ( PyCFunction ) Effect_getLife, + METH_NOARGS, "()-Return particle life time"}, + {"setLife", ( PyCFunction ) Effect_oldsetLife, METH_VARARGS, + "()- Sets particle life time "}, + {"getMat", ( PyCFunction ) Effect_getChildMat, + METH_NOARGS, "()-Return particle life time"}, + {"setMat", ( PyCFunction ) Effect_oldsetMat, METH_VARARGS, + "()- Sets particle life time "}, + {"getChild", ( PyCFunction ) Effect_getChild, + METH_NOARGS, "()-Return particle life time"}, + {"setChild", ( PyCFunction ) Effect_oldsetChild, METH_VARARGS, + "()- Sets particle life time "}, + {"getDefvec", ( PyCFunction ) Effect_getDefvec, + METH_NOARGS, "()-Return particle life time"}, + {"setDefvec", ( PyCFunction ) Effect_oldsetDefvec, METH_VARARGS, + "()- Sets particle life time "}, + {"getParticlesLoc", ( PyCFunction ) Effect_getParticlesLoc, METH_NOARGS, + "()- Sets particle life time "}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python BPy_Effect attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef BPy_Effect_getseters[] = { + {"flag", + (getter)Effect_getFlag, (setter)Effect_setFlag, + "The particle flag bitfield", + NULL}, + {"stype", + (getter)Effect_getStype, (setter)Effect_setStype, + "The particle stype bitfield", + NULL}, + {"disp", + (getter)Effect_getDisp, (setter)Effect_setDisp, + "The particle display value", + NULL}, + {"staticStep", + (getter)Effect_getStaticStep, (setter)Effect_setStaticStep, + "The particle static step value", + NULL}, + {"type", + (getter)Effect_getType, (setter)Effect_setType, + "The effect's type (deprecated)", + NULL}, + {"child", + (getter)Effect_getChild, (setter)Effect_setChild, + "The number of children of a particle that multiply itself", + NULL}, + {"childMat", + (getter)Effect_getChildMat, (setter)Effect_setChildMat, + "Specify the material used for the particles", + NULL}, + {"damping", + (getter)Effect_getDamping, (setter)Effect_setDamping, + "The damping factor", + NULL}, + {"defvec", + (getter)Effect_getDefvec, (setter)Effect_setDefvec, + "The axes of a force, determined by the texture", + NULL}, + {"dispMat", + (getter)Effect_getDispMat, (setter)Effect_setDispMat, + "The material used for the particles", + NULL}, + {"emissionTex", + (getter)Effect_getEmissionTex, (setter)Effect_setEmissionTex, + "The texture used for texture emission", + NULL}, + {"end", + (getter)Effect_getEnd, (setter)Effect_setEnd, + "The endframe for the effect", + NULL}, + {"force", + (getter)Effect_getForce, (setter)Effect_setForce, + "The axes of a continues force", + NULL}, + {"forceTex", + (getter)Effect_getForceTex, (setter)Effect_setForceTex, + "The texture used for force", + NULL}, + {"jitter", + (getter)Effect_getJitter, (setter)Effect_setJitter, + "Jitter table distribution: maximum particles per face", + NULL}, + {"life", + (getter)Effect_getLife, (setter)Effect_setLife, + "The life span of the next generation of particles", + NULL}, + {"lifetime", + (getter)Effect_getLifetime, (setter)Effect_setLifetime, + "The life span of the particles", + NULL}, + {"mult", + (getter)Effect_getMult, (setter)Effect_setMult, + "The probabilities that a \"dying\" particle spawns a new one", + NULL}, + {"nabla", + (getter)Effect_getNabla, (setter)Effect_setNabla, + "The dimension of the area for gradient calculation", + NULL}, + {"normfac", + (getter)Effect_getNormfac, (setter)Effect_setNormfac, + "Particle's starting speed (from the mesh)", + NULL}, + {"obfac", + (getter)Effect_getObfac, (setter)Effect_setObfac, + "Particle's starting speed (from the object)", + NULL}, + {"randfac", + (getter)Effect_getRandfac, (setter)Effect_setRandfac, + "The random variation for the starting speed", + NULL}, + {"randlife", + (getter)Effect_getRandlife, (setter)Effect_setRandlife, + "The random variation for a particle's life", + NULL}, + {"seed", + (getter)Effect_getSeed, (setter)Effect_setSeed, + "The seed for random variations", + NULL}, + {"speedType", + (getter)Effect_getSpeedType, (setter)Effect_setSpeedType, + "Controls which texture property affects particle speeds", + NULL}, + {"speedVGroup", + (getter)Effect_getSpeedVertGroup, (setter)Effect_setSpeedVertGroup, + "Vertex group for speed control", + NULL}, + {"sta", + (getter)Effect_getSta, (setter)Effect_setSta, + "The startframe for the effect", + NULL}, + {"texfac", + (getter)Effect_getTexfac, (setter)Effect_setTexfac, + "Particle's starting speed (from the texture)", + NULL}, + {"totpart", + (getter)Effect_getTotpart, (setter)Effect_setTotpart, + "The total number of particles", + NULL}, + {"totkey", + (getter)Effect_getTotkey, (setter)Effect_setTotkey, + "The total number of key positions", + NULL}, + {"vectsize", + (getter)Effect_getVectsize, (setter)Effect_setVectsize, + "The speed for particle's rotation direction", + NULL}, + {"vGroup", + (getter)Effect_getVertGroup, (setter)Effect_setVertGroup, + "Vertex group for emitted particles", + NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/*****************************************************************************/ +/* Python Effect_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject Effect_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender Effect", /* char *tp_name; */ + sizeof( BPy_Effect ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + ( reprfunc ) Effect_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_Effect_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_Effect_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +/*****************************************************************************/ +/* Python method structure definition for Blender.Effect module: */ +/*****************************************************************************/ + +struct PyMethodDef M_Effect_methods[] = { + {"New", ( PyCFunction ) M_Effect_New, METH_VARARGS, NULL}, + {"Get", M_Effect_Get, METH_VARARGS, NULL}, + {"get", M_Effect_Get, METH_VARARGS, NULL}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Function: M_Effect_New */ +/* Python equivalent: Blender.Effect.New */ +/*****************************************************************************/ +PyObject *M_Effect_New( PyObject * self, PyObject * args ) +{ + Effect *bleffect = 0; + Object *ob; + char *name = NULL; + + if( !PyArg_ParseTuple( args, "s", &name ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + + for( ob = G.main->object.first; ob; ob = ob->id.next ) + if( !strcmp( name, ob->id.name + 2 ) ) + break; + + if( !ob ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "object does not exist" ); + + if( ob->type != OB_MESH ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "object is not a mesh" ); + + bleffect = add_effect( EFF_PARTICLE ); + if( !bleffect ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't create Effect Data in Blender" ); + + BLI_addtail( &ob->effect, bleffect ); + + return EffectCreatePyObject( bleffect, ob ); +} + +/*****************************************************************************/ +/* Function: M_Effect_Get */ +/* Python equivalent: Blender.Effect.Get */ +/*****************************************************************************/ +PyObject *M_Effect_Get( PyObject * self, PyObject * args ) +{ + /*arguments : string object name + int : position of effect in the obj's effect list */ + char *name = NULL; + Object *object_iter; + Effect *eff; + int num = -1, i; + + if( !PyArg_ParseTuple( args, "|si", &name, &num ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected string int argument" ) ); + + object_iter = G.main->object.first; + + if( !object_iter ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "Scene contains no object" ) ); + + if( name ) { /* (name, num = -1) - try to find the given object */ + + while( object_iter ) { + + if( !strcmp( name, object_iter->id.name + 2 ) ) { + + eff = object_iter->effect.first; /*can be NULL: None will be returned*/ + + if (num >= 0) { /* return effect in given num position if available */ + + for( i = 0; i < num; i++ ) { + if (!eff) break; + eff = eff->next; + } + + if (eff) { + return EffectCreatePyObject( eff, object_iter ); + } else { /* didn't find any effect in the given position */ + Py_RETURN_NONE; + } + } + + else {/*return a list with all effects linked to the given object*/ + /* this was pointed by Stephen Swaney */ + PyObject *effectlist = PyList_New( 0 ); + + while (eff) { + PyObject *found_eff = EffectCreatePyObject( eff, + object_iter ); + PyList_Append( effectlist, found_eff ); + Py_DECREF( found_eff ); /* PyList_Append incref'ed it */ + eff = eff->next; + } + return effectlist; + } + } + + object_iter = object_iter->id.next; + } + + if (!object_iter) + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "no such object"); + } + + else { /* () - return a list with all effects currently in Blender */ + PyObject *effectlist = PyList_New( 0 ); + + while( object_iter ) { + if( object_iter->effect.first != NULL ) { + eff = object_iter->effect.first; + while( eff ) { + PyObject *found_eff = EffectCreatePyObject( eff, + object_iter ); + PyList_Append( effectlist, found_eff ); + Py_DECREF( found_eff ); + eff = eff->next; + } + } + object_iter = object_iter->id.next; + } + return effectlist; + } + Py_INCREF( Py_None ); + return Py_None; +} + +/* create the Blender.Effect.Flags constant dict */ + +static PyObject *Effect_FlagsDict( void ) +{ + PyObject *Flags = PyConstant_New( ); + + if( Flags ) { + BPy_constant *c = ( BPy_constant * ) Flags; + + PyConstant_Insert( c, "SELECTED", + PyInt_FromLong( EFF_SELECT ) ); + PyConstant_Insert( c, "BSPLINE", + PyInt_FromLong( PAF_BSPLINE ) ); + PyConstant_Insert( c, "STATIC", + PyInt_FromLong( PAF_STATIC ) ); + PyConstant_Insert( c, "FACES", + PyInt_FromLong( PAF_FACE ) ); + PyConstant_Insert( c, "ANIMATED", + PyInt_FromLong( PAF_ANIMATED ) ); + PyConstant_Insert( c, "UNBORN", + PyInt_FromLong( PAF_UNBORN ) ); + PyConstant_Insert( c, "VERTS", + PyInt_FromLong( PAF_OFACE ) ); + PyConstant_Insert( c, "EMESH", + PyInt_FromLong( PAF_SHOWE ) ); + PyConstant_Insert( c, "TRUERAND", + PyInt_FromLong( PAF_TRAND ) ); + PyConstant_Insert( c, "EVENDIST", + PyInt_FromLong( PAF_EDISTR ) ); + PyConstant_Insert( c, "DIED", + PyInt_FromLong( PAF_DIED ) ); + } + return Flags; +} + +static PyObject *Effect_SpeedTypeDict( void ) +{ + PyObject *Type = PyConstant_New( ); + + if( Type ) { + BPy_constant *c = ( BPy_constant * ) Type; + + PyConstant_Insert( c, "INTENSITY", + PyInt_FromLong( EXPP_EFFECT_SPEEDTYPE_INTENSITY ) ); + PyConstant_Insert( c, "RGB", + PyInt_FromLong( EXPP_EFFECT_SPEEDTYPE_RGB ) ); + PyConstant_Insert( c, "GRADIENT", + PyInt_FromLong( EXPP_EFFECT_SPEEDTYPE_GRADIENT ) ); + } + return Type; +} + +/*****************************************************************************/ +/* Function: Effect_Init */ +/*****************************************************************************/ + +PyObject *Effect_Init( void ) +{ + PyObject *submodule, *dict; + PyObject *particle; + PyObject *Flags; + PyObject *Types; + + if( PyType_Ready( &Effect_Type ) < 0) + return NULL; + + Flags = Effect_FlagsDict( ); + Types = Effect_SpeedTypeDict( ); + + submodule = Py_InitModule3( "Blender.Effect", M_Effect_methods, 0 ); + if( Flags ) + PyModule_AddObject( submodule, "Flags", Flags ); + if( Types ) + PyModule_AddObject( submodule, "SpeedTypes", Types ); + + particle = Py_InitModule3( "Blender.Particle", M_Particle_methods, + M_Particle_doc ); + + dict = PyModule_GetDict( submodule ); + + PyDict_SetItemString( dict, "Particle", particle ); + return ( submodule ); +} + +/*****************************************************************************/ +/* Python BPy_Effect methods: */ +/*****************************************************************************/ + +static PyObject *Effect_getType( BPy_Effect * self ) +{ + return PyInt_FromLong( ( long ) self->effect->type ); +} + +/* does nothing since there is only one type of effect */ + +static int Effect_setType( void ) +{ + return 0; +} + +static int Effect_setStype( BPy_Effect * self, PyObject * args ) +{ + short param; + if( !PyArg_Parse( args, "h", ¶m ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected an int as argument" ); + self->effect->stype = param; + return 0; +} + +static PyObject *Effect_getStype( BPy_Effect * self ) +{ + return PyInt_FromLong( (long)( self->effect->stype ) ); +} + +static PyObject *Effect_getFlag( BPy_Effect * self ) +{ + return PyInt_FromLong( (long)( self->effect->flag ^ PAF_OFACE ) ); +} + +static int Effect_setFlag( BPy_Effect * self, PyObject * args ) +{ + short param; + static short bitmask = PAF_BSPLINE | PAF_STATIC | PAF_FACE | PAF_ANIMATED | + PAF_UNBORN | PAF_OFACE | PAF_SHOWE | PAF_TRAND | PAF_EDISTR | PAF_DIED; + + if( !PyArg_Parse( args, "h", ¶m ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected an int as argument" ); + + /* we don't allow users to change the select bit at this time */ + param &= ~EFF_SELECT; + + if ( ( param & bitmask ) != param ) + return EXPP_ReturnIntError( PyExc_ValueError, + "invalid bit(s) set in mask" ); + + /* the sense of "Verts" is inverted (clear is enabled) */ + param ^= PAF_OFACE; + + /* leave select bit alone, and add in the others */ + self->effect->flag &= EFF_SELECT; + self->effect->flag |= param; + return 0; +} + +static PyObject *Effect_getSta( BPy_Effect * self ) +{ + return PyFloat_FromDouble( self->effect->sta ); +} + +static int Effect_setSta( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setFloatClamped( args, &self->effect->sta, + EXPP_EFFECT_STA_MIN, MAXFRAMEF ); +} + +static PyObject *Effect_getEnd( BPy_Effect * self ) +{ + return PyFloat_FromDouble( ((PartEff *) self->effect)->end ); +} + +static int Effect_setEnd( BPy_Effect * self, PyObject * args ) +{ + float val; + + if( !PyArg_Parse( args, "f", &val ) ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "expected float argument" ); + + self->effect->end = EXPP_ClampFloat( val, + EXPP_EFFECT_END_MIN, MAXFRAMEF ); + return 0; +} + +static PyObject *Effect_getLifetime( BPy_Effect * self ) +{ + return PyFloat_FromDouble( self->effect->lifetime ); +} + +static int Effect_setLifetime( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setFloatClamped( args, &self->effect->lifetime, + EXPP_EFFECT_LIFETIME_MIN, MAXFRAMEF ); +} + +static PyObject *Effect_getNormfac( BPy_Effect * self ) +{ + return PyFloat_FromDouble( self->effect->normfac ); +} + +static int Effect_setNormfac( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setFloatClamped( args, &self->effect->normfac, + EXPP_EFFECT_NORMFAC_MIN, EXPP_EFFECT_NORMFAC_MAX ); +} + +static PyObject *Effect_getObfac( BPy_Effect * self ) +{ + return PyFloat_FromDouble( self->effect->obfac ); +} + +static int Effect_setObfac( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setFloatClamped( args, &self->effect->obfac, + EXPP_EFFECT_OBFAC_MIN, EXPP_EFFECT_OBFAC_MAX ); +} + +static PyObject *Effect_getRandfac( BPy_Effect * self ) +{ + return PyFloat_FromDouble( self->effect->randfac ); +} + +static int Effect_setRandfac( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setFloatClamped( args, &self->effect->randfac, + EXPP_EFFECT_RANDFAC_MIN, EXPP_EFFECT_RANDFAC_MAX ); +} + +static PyObject *Effect_getTexfac( BPy_Effect * self ) +{ + return PyFloat_FromDouble( self->effect->texfac ); +} + +static int Effect_setTexfac( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setFloatClamped( args, &self->effect->texfac, + EXPP_EFFECT_TEXFAC_MIN, EXPP_EFFECT_TEXFAC_MAX ); +} + +static PyObject *Effect_getRandlife( BPy_Effect * self ) +{ + return PyFloat_FromDouble( self->effect->randlife ); +} + +static int Effect_setRandlife( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setFloatClamped( args, &self->effect->randlife, + EXPP_EFFECT_RANDLIFE_MIN, EXPP_EFFECT_RANDLIFE_MAX ); +} + +static PyObject *Effect_getNabla( BPy_Effect * self ) +{ + return PyFloat_FromDouble( self->effect->nabla ); +} + +static int Effect_setNabla( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setFloatClamped( args, &self->effect->nabla, + EXPP_EFFECT_NABLA_MIN, EXPP_EFFECT_NABLA_MAX ); +} + +static PyObject *Effect_getVectsize( BPy_Effect * self ) +{ + return PyFloat_FromDouble( self->effect->vectsize ); +} + +static int Effect_setVectsize( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setFloatClamped( args, &self->effect->vectsize, + EXPP_EFFECT_VECTSIZE_MIN, EXPP_EFFECT_VECTSIZE_MAX ); +} + +static PyObject *Effect_getTotpart( BPy_Effect * self ) +{ + return PyInt_FromLong( self->effect->totpart ); +} + +static int Effect_setTotpart( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setIValueClamped( args, &self->effect->totpart, + (int)EXPP_EFFECT_TOTPART_MIN, (int)EXPP_EFFECT_TOTPART_MAX, 'i' ); +} + +static PyObject *Effect_getTotkey( BPy_Effect * self ) +{ + return PyInt_FromLong( self->effect->totkey ); +} + +static int Effect_setTotkey( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setIValueClamped( args, &self->effect->totkey, + EXPP_EFFECT_TOTKEY_MIN, EXPP_EFFECT_TOTKEY_MAX, 'i' ); +} + +static PyObject *Effect_getSeed( BPy_Effect * self ) +{ + return PyInt_FromLong( self->effect->seed ); +} + +static int Effect_setSeed( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setIValueClamped( args, &self->effect->seed, + EXPP_EFFECT_SEED_MIN, EXPP_EFFECT_SEED_MAX, 'i' ); +} + +static PyObject *Effect_getForce( BPy_Effect * self ) +{ + return Py_BuildValue( "(f,f,f)", self->effect->force[0], + self->effect->force[1], self->effect->force[2] ); +} + +static int Effect_setForce( BPy_Effect * self, PyObject * args ) +{ + float val[3]; + int i; + + if( PyTuple_Check( args ) && PyTuple_Size( args ) == 1 ) + args = PyTuple_GetItem( args, 0 ); + + if( !PyArg_ParseTuple( args, "fff", &val[0], &val[1], &val[2] ) ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "expected a tuple of three float arguments" ); + for( i = 0; i < 3; ++i ) + self->effect->force[i] = EXPP_ClampFloat( val[i], + EXPP_EFFECT_FORCE_MIN, EXPP_EFFECT_FORCE_MAX ); + return 0; +} + +static PyObject *Effect_getMult( BPy_Effect * self ) +{ + return Py_BuildValue( "(f,f,f,f)", self->effect->mult[0], + self->effect->mult[1], self->effect->mult[2], + self->effect->mult[3] ); +} + +static int Effect_setMult( BPy_Effect * self, PyObject * args ) +{ + float val[4]; + int i; + + if( PyTuple_Check( args ) && PyTuple_Size( args ) == 1 ) + args = PyTuple_GetItem( args, 0 ); + + if( !PyArg_ParseTuple( args, "ffff", &val[0], &val[1], &val[2], &val[3] ) ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "expected a tuple of four float arguments" ); + for( i = 0; i < 4; ++i ) + self->effect->mult[i] = EXPP_ClampFloat( val[i], + EXPP_EFFECT_MULT_MIN, EXPP_EFFECT_MULT_MAX ); + return 0; +} + +static PyObject *Effect_getLife( BPy_Effect * self ) +{ + return Py_BuildValue( "(f,f,f,f)", self->effect->life[0], + self->effect->life[1], self->effect->life[2], + self->effect->life[3] ); +} + +static int Effect_setLife( BPy_Effect * self, PyObject * args ) +{ + float val[4]; + int i; + + if( PyTuple_Check( args ) && PyTuple_Size( args ) == 1 ) + args = PyTuple_GetItem( args, 0 ); + + if( !PyArg_ParseTuple( args, "ffff", &val[0], &val[1], &val[2], &val[3] ) ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "expected a tuple of four float arguments" ); + for( i = 0; i < 4; ++i ) + self->effect->life[i] = EXPP_ClampFloat( val[i], + EXPP_EFFECT_LIFE_MIN, MAXFRAMEF ); + return 0; +} + +static PyObject *Effect_getChild( BPy_Effect * self ) +{ + return Py_BuildValue( "(h,h,h,h)", self->effect->child[0], + self->effect->child[1], self->effect->child[2], + self->effect->child[3] ); +} + + +static int Effect_setChild( BPy_Effect * self, PyObject * args ) +{ + short val[4]; + int i; + + if( PyTuple_Check( args ) && PyTuple_Size( args ) == 1 ) + args = PyTuple_GetItem( args, 0 ); + + if( !PyArg_ParseTuple( args, "hhhh", &val[0], &val[1], &val[2], &val[3] ) ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "expected a tuple of four int argument" ); + for( i = 0; i < 4; ++i ) + self->effect->child[i] = (short)EXPP_ClampInt( val[i], + EXPP_EFFECT_CHILD_MIN, EXPP_EFFECT_CHILD_MAX ); + return 0; +} + +static PyObject *Effect_getChildMat( BPy_Effect * self ) +{ + return Py_BuildValue( "(h,h,h,h)", self->effect->mat[0], + self->effect->mat[1], self->effect->mat[2], + self->effect->mat[3] ); +} + +static int Effect_setChildMat( BPy_Effect * self, PyObject * args ) +{ + short val[4]; + int i; + + if( PyTuple_Check( args ) && PyTuple_Size( args ) == 1 ) + args = PyTuple_GetItem( args, 0 ); + + if( !PyArg_ParseTuple( args, "hhhh", &val[0], &val[1], &val[2], &val[3] ) ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "expected a tuple of four int argument" ); + for( i = 0; i < 4; ++i ) + self->effect->mat[i] = (short)EXPP_ClampInt( val[i], + EXPP_EFFECT_CHILDMAT_MIN, EXPP_EFFECT_CHILDMAT_MAX ); + return 0; +} + +static PyObject *Effect_getDefvec( BPy_Effect * self ) +{ + return Py_BuildValue( "(f,f,f)", self->effect->defvec[0], + self->effect->defvec[1], self->effect->defvec[2] ); +} + +static int Effect_setDefvec( BPy_Effect * self, PyObject * args ) +{ + float val[3]; + int i; + + if( PyTuple_Check( args ) && PyTuple_Size( args ) == 1 ) + args = PyTuple_GetItem( args, 0 ); + + if( !PyArg_ParseTuple( args, "fff", &val[0], &val[1], &val[2] ) ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "expected a tuple of three float arguments" ); + + for( i = 0; i < 3; ++i ) + self->effect->defvec[i] = EXPP_ClampFloat( val[i], + EXPP_EFFECT_DEFVEC_MIN, EXPP_EFFECT_DEFVEC_MAX ); + return 0; +} + +static PyObject *Effect_getJitter( BPy_Effect * self ) +{ + return PyInt_FromLong( ( long )self->effect->userjit ); +} + +static int Effect_setJitter( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setIValueClamped( args, &self->effect->userjit, + EXPP_EFFECT_JITTER_MIN, EXPP_EFFECT_JITTER_MAX, 'h' ); +} + +static PyObject *Effect_getDispMat( BPy_Effect * self ) +{ + return PyInt_FromLong( ( long )self->effect->omat ); +} + +static int Effect_setDispMat( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setIValueClamped( args, &self->effect->omat, + EXPP_EFFECT_DISPMAT_MIN, EXPP_EFFECT_DISPMAT_MAX, 'h' ); +} + +static PyObject *Effect_getEmissionTex( BPy_Effect * self ) +{ + return PyInt_FromLong( ( long )self->effect->timetex ); +} + +static int Effect_setEmissionTex( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setIValueClamped( args, &self->effect->timetex, + EXPP_EFFECT_TIMETEX_MIN, EXPP_EFFECT_TIMETEX_MAX, 'h' ); +} + +static PyObject *Effect_getForceTex( BPy_Effect * self ) +{ + return PyInt_FromLong( ( long )self->effect->speedtex ); +} + +static int Effect_setForceTex( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setIValueClamped( args, &self->effect->speedtex, + EXPP_EFFECT_SPEEDTEX_MIN, EXPP_EFFECT_SPEEDTEX_MAX, 'h' ); +} + +static PyObject *Effect_getSpeedType( BPy_Effect * self ) +{ + return PyInt_FromLong( ( long )self->effect->texmap ); +} + +static int Effect_setSpeedType( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setIValueRange( args, &self->effect->texmap, + EXPP_EFFECT_SPEEDTYPE_INTENSITY, EXPP_EFFECT_SPEEDTYPE_GRADIENT, + 'h' ); +} + +static PyObject *Effect_getDamping( BPy_Effect * self ) +{ + return PyFloat_FromDouble( ( double )self->effect->damp ); +} + +static int Effect_setDamping( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setFloatClamped( args, &self->effect->damp, + EXPP_EFFECT_DAMP_MIN, EXPP_EFFECT_DAMP_MAX ); +} + +static PyObject *Effect_getVertGroup( BPy_Effect * self ) +{ + return PyString_FromString( self->effect->vgroupname ); +} + + +static int Effect_setVertGroup( BPy_Effect * self, PyObject * value ) +{ + char *name; + bDeformGroup *dg; + + name = PyString_AsString ( value ); + if( !name ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected string argument" ); + + PyOS_snprintf( self->effect->vgroupname, + sizeof( self->effect->vgroupname )-1, "%s", name ); + + dg = get_named_vertexgroup( self->object, self->effect->vgroupname ); + if( dg ) + self->effect->vertgroup = (short)get_defgroup_num( self->object, dg )+1; + else + self->effect->vertgroup = 0; + + return 0; +} + +static PyObject *Effect_getSpeedVertGroup( BPy_Effect * self ) +{ + return PyString_FromString( self->effect->vgroupname_v ); +} + +static int Effect_setSpeedVertGroup( BPy_Effect * self, PyObject * value ) +{ + char *name; + bDeformGroup *dg; + + name = PyString_AsString ( value ); + if( !name ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected string argument" ); + + PyOS_snprintf( self->effect->vgroupname_v, + sizeof( self->effect->vgroupname_v )-1, "%s", name ); + + dg = get_named_vertexgroup( self->object, self->effect->vgroupname_v ); + if( dg ) + self->effect->vertgroup_v = (short)get_defgroup_num( self->object, dg )+1; + else + self->effect->vertgroup_v = 0; + + return 0; +} + +/*****************************************************************************/ +/* attribute: getDisp */ +/* Description: the current value of the display number button */ +/* Data: self effect */ +/* Return: integer value between 0 and 100 */ +/*****************************************************************************/ +static PyObject *Effect_getDisp( BPy_Effect * self ) +{ + return PyInt_FromLong( ( long )self->effect->disp ); +} + +static int Effect_setDisp( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setIValueRange( args, &self->effect->disp, + EXPP_EFFECT_DISP_MIN, EXPP_EFFECT_DISP_MAX, 'h' ); +} + +/*****************************************************************************/ +/* attribute: getStep */ +/* Description: the current value of the Step number button */ +/* Data: self effect */ +/* Return: integer value between 1 and 100 */ +/*****************************************************************************/ +static PyObject *Effect_getStaticStep( BPy_Effect * self ) +{ + return PyInt_FromLong( ( long )self->effect->staticstep ); +} + +static int Effect_setStaticStep( BPy_Effect * self , PyObject * args ) +{ + return EXPP_setIValueRange( args, &self->effect->staticstep, + EXPP_EFFECT_STATICSTEP_MIN, EXPP_EFFECT_STATICSTEP_MAX, + 'h' ); +} + +/*****************************************************************************/ +/* Method: getParticlesLoc */ +/* Python equivalent: effect.getParticlesLoc */ +/* Description: Get the current location of each particle */ +/* and return a list of 3D vectors */ +/* or a list of ists of two 3D vectors */ +/* if effect.vect has any sense */ +/* Data: notihng get the current time from G.scene */ +/* Return: One python list of 3D vector */ +/*****************************************************************************/ +static PyObject *Effect_getParticlesLoc( BPy_Effect * self ) +{ + Object *ob; + Effect *eff; + PartEff *paf; + Particle *pa=0; + PyObject *list, *strand_list, *pyvec, *pyvec2; + float p_time, c_time, vec[3], vec1[3], cfra, m_time, s_time; + int a; + short disp=100 ; + + cfra=frame_to_float( G.scene->r.cfra ); + + /* as we need to update the particles system we try to retrieve + the object to which the effect is connected */ + eff =(Effect *) self->effect; + + ob= self->object; + if(!ob) + return ( EXPP_ReturnPyObjError (PyExc_AttributeError, + "Effect has no object" ) ); + /*get the particles data */ + paf= (PartEff *)eff; + + /* particles->disp reduce the display number of particles */ + /* as we want the complete list ... we backup the disp value and restore later */ + if (paf->disp<100) + disp= paf->disp; paf->disp=100; + + + build_particle_system(ob); + pa= paf->keys; + + if(!pa) + return ( EXPP_ReturnPyObjError (PyExc_AttributeError, + "Particles Location : no Keys" ) ); + + /* if object is in motion */ + if( ob->ipoflag & OB_OFFS_PARTICLE ) + p_time= ob->sf; + else + p_time= 0.0; + + list = PyList_New( 0 ); + if( !list ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, "PyList() failed" ); + + c_time= bsystem_time( ob, cfra, p_time ); + + for( a=0; a < paf->totpart; a++, pa += paf->totkey ) { + + if(paf->flag & PAF_STATIC ) { + strand_list = PyList_New( 0 ); + m_time= pa->time+pa->lifetime+paf->staticstep-1; + for(c_time= pa->time; c_timestaticstep) { + where_is_particle(paf, pa, c_time, vec); + MTC_Mat4MulVecfl(ob->obmat, vec); /* make worldspace like the others */ + pyvec = newVectorObject(vec, 3, Py_NEW); + if( PyList_Append( strand_list, pyvec) < 0 ) { + Py_DECREF( list ); + Py_DECREF( strand_list ); + Py_XDECREF( pyvec ); + + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Couldn't append item to PyList" ); + } + Py_DECREF( pyvec ); + + } + + if( PyList_Append( list, strand_list) < 0 ) { + Py_DECREF( list ); + Py_DECREF( strand_list ); + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Couldn't append item to PyList" ); + } + Py_DECREF( strand_list ); + } else { + if(c_time > pa->time && c_time < pa->time+pa->lifetime ) { + /* vector particles are a tuple of 2 vectors */ + if( paf->stype==PAF_VECT ) { + s_time= c_time; + p_time= c_time+1.0f; + if(c_time < pa->time) { + if(paf->flag & PAF_UNBORN) + p_time= pa->time+1.0f; + else + continue; + } + if(c_time > pa->time+pa->lifetime) { + if(paf->flag & PAF_DIED) + s_time= pa->time+pa->lifetime-1.0f; + else + continue; + } + where_is_particle(paf, pa, s_time, vec); + where_is_particle(paf, pa, p_time, vec1); + pyvec = newVectorObject(vec, 3, Py_NEW); + pyvec2 = newVectorObject(vec1, 3, Py_NEW); + if( PyList_Append( list, Py_BuildValue("[OO]", pyvec, pyvec2)) < 0 ) { + Py_DECREF( list ); + Py_XDECREF( pyvec ); + Py_XDECREF( pyvec2 ); + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Couldn't append item to PyList" ); + } + Py_DECREF( pyvec ); + Py_DECREF( pyvec2 ); + } else { /* not a vector */ + where_is_particle(paf, pa, c_time, vec); + pyvec = newVectorObject(vec, 3, Py_NEW); + if( PyList_Append( list, pyvec) < 0 ) { + Py_DECREF( list ); + Py_XDECREF( pyvec ); + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Couldn't append item to PyList" ); + } + Py_DECREF( pyvec ); + } + } + } + } + + /* restore the real disp value */ + if (disp<100){ + paf->disp=disp; + build_particle_system(ob); + } + + return list; +} + +/*****************************************************************************/ +/* Function: Effect_repr */ +/* Description: This is a callback function for the BPy_Effect type. It */ +/* builds a meaninful string to represent effcte objects. */ +/*****************************************************************************/ + +static PyObject *Effect_repr( void ) +{ + return PyString_FromString( "Particle" ); +} + +/*****************************************************************************/ +/* These are needed by Object.c */ +/*****************************************************************************/ +PyObject *EffectCreatePyObject( Effect * effect, Object *ob ) +{ + BPy_Effect *blen_object; + + blen_object = + ( BPy_Effect * ) PyObject_NEW( BPy_Effect, &Effect_Type ); + + if( blen_object ) + blen_object->effect = (PartEff *)effect; + blen_object->object = ob; + + return ( PyObject * ) blen_object; +} + +int EffectCheckPyObject( PyObject * py_obj ) +{ + return ( py_obj->ob_type == &Effect_Type ); +} + +/* #####DEPRECATED###### */ + +static PyObject *Effect_oldsetChild( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setterWrapperTuple( (void *)self, args, + (setter)Effect_setChild ); +} + +static PyObject *Effect_oldsetDefvec( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setterWrapperTuple( (void *)self, args, + (setter)Effect_setDefvec ); +} + +static PyObject *Effect_oldsetForce( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setterWrapperTuple( (void *)self, args, + (setter)Effect_setForce ); +} + +static PyObject *Effect_oldsetMat( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setterWrapperTuple( (void *)self, args, + (setter)Effect_setChildMat ); +} + +static PyObject *Effect_oldsetEnd( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setEnd ); +} + +static PyObject *Effect_oldsetLife( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setterWrapperTuple( (void *)self, args, + (setter)Effect_setLife ); +} + +static PyObject *Effect_oldsetLifetime( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setLifetime ); +} + +static PyObject *Effect_oldsetMult( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setterWrapperTuple( (void *)self, args, + (setter)Effect_setMult ); +} + +static PyObject *Effect_oldsetNabla( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setNabla ); +} + +static PyObject *Effect_oldsetNormfac( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setNormfac ); +} + +static PyObject *Effect_oldsetObfac( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setObfac ); +} + +static PyObject *Effect_oldsetRandfac( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setRandfac ); +} + +static PyObject *Effect_oldsetRandlife( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setRandlife ); +} + +static PyObject *Effect_oldsetSeed( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setSeed ); +} + +static PyObject *Effect_oldsetSta( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setSta ); +} + +static PyObject *Effect_oldsetTexfac( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setTexfac ); +} + +static PyObject *Effect_oldsetTotkey( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setTotkey ); +} + +static PyObject *Effect_oldsetTotpart( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setTotpart ); +} + +static PyObject *Effect_oldsetVectsize( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setVectsize ); +} + +static PyObject *Effect_oldsetFlag( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setFlag ); +} + +static PyObject *Effect_oldsetStype( BPy_Effect * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setStype ); +} + +static PyObject *Effect_oldsetType( void ) +{ + return EXPP_incr_ret( Py_None ); +} diff --git a/source/blender/python/api2_2x/Effect.h b/source/blender/python/api2_2x/Effect.h new file mode 100644 index 00000000000..b26e77f1794 --- /dev/null +++ b/source/blender/python/api2_2x/Effect.h @@ -0,0 +1,58 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Jacques Guignot + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_EFFECT_H +#define EXPP_EFFECT_H + +#include +#include "DNA_effect_types.h" +#include "DNA_object_types.h" + +extern PyTypeObject Effect_Type; + +#define BPy_Effect_Check(v) ((v)->ob_type==&Effect_Type) + +/* Python BPy_Effect structure definition */ +typedef struct { + PyObject_HEAD /* required py macro */ + PartEff * effect; + Object * object; +} BPy_Effect; + +/*****************************************************************************/ +/* Python Effect_Type helpder function prototypes: */ +/*****************************************************************************/ +PyObject *Effect_Init( void ); +int EffectCheckPyObject( PyObject * py_obj ); +PyObject *EffectCreatePyObject( Effect * eff, Object * ob ); + +#endif /* EXPP_EFFECT_H */ diff --git a/source/blender/python/api2_2x/Font.c b/source/blender/python/api2_2x/Font.c new file mode 100644 index 00000000000..61edac2841a --- /dev/null +++ b/source/blender/python/api2_2x/Font.c @@ -0,0 +1,403 @@ +/* + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Joilnen Leite + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "Font.h" /*This must come first*/ + +#include "DNA_packedFile_types.h" +#include "BKE_packedFile.h" +#include "BKE_global.h" +#include "BKE_library.h" /* for rename_id() */ +#include "BLI_blenlib.h" +#include "gen_utils.h" +#include "gen_library.h" + +#include "BKE_main.h" /* so we can access G.main->vfont.first */ +#include "DNA_space_types.h" /* for FILE_MAXDIR only */ + +extern PyObject *M_Text3d_LoadFont( PyObject * self, PyObject * args ); + +/*--------------------Python API function prototypes for the Font module----*/ +static PyObject *M_Font_Load( PyObject * self, PyObject * value ); +static PyObject *M_Font_Get( PyObject * self, PyObject * args ); + +/*------------------------Python API Doc strings for the Font module--------*/ +char M_Font_doc[] = "The Blender Font module\n\n\ +This module provides control over **Font Data** objects in Blender.\n\n\ +Example::\n\n\ + from Blender import Text3d.Font\n\ + l = Text3d.Font.Load('/usr/share/fonts/verdata.ttf')\n"; +char M_Font_Get_doc[] = "(name) - return an existing font called 'name'\ +when no argument is given it returns a list of blenders fonts."; +char M_Font_Load_doc[] = + "(filename) - return font from file filename as Font Object, \ +returns None if not found.\n"; + +/*----- Python method structure definition for Blender.Text3d.Font module---*/ +struct PyMethodDef M_Font_methods[] = { + {"Get", ( PyCFunction ) M_Font_Get, METH_VARARGS, M_Font_Get_doc}, + {"Load", ( PyCFunction ) M_Font_Load, METH_O, M_Font_Load_doc}, + {NULL, NULL, 0, NULL} +}; + +/*--------------- Python BPy_Font methods declarations:-------------------*/ +static PyObject *Font_pack( BPy_Font * self ); +static PyObject *Font_unpack( BPy_Font * self, PyObject * args ); + +/*--------------- Python BPy_Font methods table:--------------------------*/ +static PyMethodDef BPy_Font_methods[] = { + {"pack", ( PyCFunction ) Font_pack, METH_NOARGS, + "() - pack this Font"}, + {"unpack", ( PyCFunction ) Font_unpack, METH_O, + "(mode) - unpack this packed font"}, + {NULL, NULL, 0, NULL} +}; + +/*--------------- Python TypeFont callback function prototypes----------*/ +static int Font_compare( BPy_Font * a1, BPy_Font * a2 ); +static PyObject *Font_repr( BPy_Font * font ); + + +/*--------------- Python Font Module methods------------------------*/ + +/*--------------- Blender.Text3d.Font.Get()-----------------------*/ +static PyObject *M_Font_Get( PyObject * self, PyObject * args ) +{ + char *name = NULL; + VFont *vfont_iter; + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument (or nothing)" ) ); + + vfont_iter = G.main->vfont.first; + + if( name ) { /* (name) - Search font by name */ + + BPy_Font *wanted_vfont = NULL; + + while(vfont_iter) { + if( strcmp( name, vfont_iter->id.name + 2 ) == 0 ) { + wanted_vfont = + ( BPy_Font * ) + Font_CreatePyObject( vfont_iter ); + break; + } + vfont_iter = vfont_iter->id.next; + } + + if( wanted_vfont == NULL ) { /* Requested font doesn't exist */ + char error_msg[64]; + PyOS_snprintf( error_msg, sizeof( error_msg ), + "Font \"%s\" not found", name ); + return ( EXPP_ReturnPyObjError + ( PyExc_NameError, error_msg ) ); + } + + return ( PyObject * ) wanted_vfont; + } + + else { /* () - return a list of all fonts in the scene */ + int index = 0; + PyObject *vfontlist, *pyobj; + + vfontlist = PyList_New( BLI_countlist( &( G.main->vfont ) ) ); + + if( vfontlist == NULL ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create font list" ) ); + + while( vfont_iter ) { + pyobj = Font_CreatePyObject( vfont_iter ); + + if( !pyobj ) { + Py_DECREF(vfontlist); + return ( EXPP_ReturnPyObjError + ( PyExc_MemoryError, + "couldn't create Object" ) ); + } + PyList_SET_ITEM( vfontlist, index, pyobj ); + + vfont_iter = vfont_iter->id.next; + index++; + } + + return vfontlist; + } +} + + +/*--------------- Blender.Text3d.Font.New()-----------------------*/ +PyObject *M_Font_Load( PyObject * self, PyObject * value ) +{ + char *filename_str = PyString_AsString(value); + BPy_Font *py_font = NULL; /* for Font Data object wrapper in Python */ + + if( !value ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected string or empty argument" ) ); + + /*create python font*/ + if( !S_ISDIR(BLI_exist(filename_str)) ) { + py_font= (BPy_Font *) M_Text3d_LoadFont (self, value); + } + else + Py_RETURN_NONE; + return ( PyObject * ) py_font; +} + +/*--------------- Python BPy_Font getsetattr funcs ---------------------*/ + + +/*--------------- BPy_Font.filename-------------------------------------*/ +static PyObject *Font_getFilename( BPy_Font * self ) +{ + return PyString_FromString( self->font->name ); +} + +static int Font_setFilename( BPy_Font * self, PyObject * value ) +{ + char *name = NULL; + + /* max len is FILE_MAXDIR = 160 chars like done in DNA_image_types.h */ + + name = PyString_AsString ( value ); + if( !name ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected string argument" ); + + PyOS_snprintf( self->font->name, FILE_MAXDIR * sizeof( char ), "%s", + name ); + + return 0; +} + +/*--------------- BPy_Font.pack()---------------------------------*/ +static PyObject *Font_pack( BPy_Font * self ) +{ + if( !self->font->packedfile ) + self->font->packedfile = newPackedFile(self->font->name); + Py_RETURN_NONE; +} + +/*--------------- BPy_Font.unpack()---------------------------------*/ +static PyObject *Font_unpack( BPy_Font * self, PyObject * value ) +{ + int mode= PyInt_AsLong(value); + VFont *font= self->font; + + if( mode==-1 ) + return ( EXPP_ReturnPyObjError + ( PyExc_AttributeError, + "expected int argument from Blender.UnpackModes" ) ); + + if (font->packedfile) + if (unpackVFont(font, mode) == RET_ERROR) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "error unpacking font" ); + + Py_RETURN_NONE; +} + +/*--------------- BPy_Font.packed---------------------------------*/ +static PyObject *Font_getPacked( BPy_Font * self ) +{ + if (G.fileflags & G_AUTOPACK) + return EXPP_incr_ret_True(); + else + return EXPP_incr_ret_False(); +} + +/*****************************************************************************/ +/* Python attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef BPy_Font_getseters[] = { + GENERIC_LIB_GETSETATTR, + {"filename", + (getter)Font_getFilename, (setter)Font_setFilename, + "Font filepath", + NULL}, + {"packed", + (getter)Font_getPacked, (setter)NULL, + "Packed status", + NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/*****************************************************************************/ +/* Python TypeFont structure definition: */ +/*****************************************************************************/ +PyTypeObject Font_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender Font", /* char *tp_name; */ + sizeof( BPy_Font ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) Font_compare, /* cmpfunc tp_compare; */ + ( reprfunc ) Font_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_Font_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_Font_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + + + + + + +/*--------------- Font Module Init-----------------------------*/ +PyObject *Font_Init( void ) +{ + PyObject *submodule; + + if( PyType_Ready( &Font_Type ) < 0 ) + return NULL; + + submodule = Py_InitModule3( "Blender.Text3d.Font", + M_Font_methods, M_Font_doc ); + + return ( submodule ); +} + +/*--------------- Font module internal callbacks-----------------*/ +/*---------------BPy_Font internal callbacks/methods-------------*/ + +/*--------------- repr---------------------------------------------*/ +static PyObject *Font_repr( BPy_Font * self ) +{ + if( self->font ) + return PyString_FromFormat( "[Font \"%s\"]", + self->font->id.name+2 ); + else + return PyString_FromString( "[Font - no data]" ); +} + +/*--------------- compare------------------------------------------*/ +static int Font_compare( BPy_Font * a, BPy_Font * b ) +{ + return ( a->font == b->font ) ? 0 : -1; +} + +/*--------------- Font_CreatePyObject---------------------------------*/ +PyObject *Font_CreatePyObject( struct VFont * font ) +{ + BPy_Font *blen_font; + + blen_font = ( BPy_Font * ) PyObject_NEW( BPy_Font, &Font_Type ); + + blen_font->font = font; + + return ( ( PyObject * ) blen_font ); +} + +/*--------------- Font_FromPyObject---------------------------------*/ +struct VFont *Font_FromPyObject( PyObject * py_obj ) +{ + BPy_Font *blen_obj; + + blen_obj = ( BPy_Font * ) py_obj; + if( !( ( BPy_Font * ) py_obj )->font ) { /*test to see if linked to text3d*/ + //use python vars + return NULL; + } else { + return ( blen_obj->font ); + } +} + + + diff --git a/source/blender/python/api2_2x/Font.h b/source/blender/python/api2_2x/Font.h new file mode 100644 index 00000000000..c1a1ec73fe2 --- /dev/null +++ b/source/blender/python/api2_2x/Font.h @@ -0,0 +1,53 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Joilnen Leite + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_FONT_H +#define EXPP_FONT_H + +#include +#include "DNA_vfont_types.h" + +extern PyTypeObject Font_Type; + +typedef struct { + PyObject_HEAD /* required py macro */ + VFont * font; /* libdata must be second */ +} BPy_Font; + +/*------------------------------visible prototypes----------------------*/ +PyObject *Font_CreatePyObject( struct VFont * font ); +struct VFont *Font_FromPyObject( PyObject * py_obj ); +PyObject *Font_Init( void ); + +#endif + + diff --git a/source/blender/python/api2_2x/Geometry.c b/source/blender/python/api2_2x/Geometry.c new file mode 100644 index 00000000000..a3b2bc8b244 --- /dev/null +++ b/source/blender/python/api2_2x/Geometry.c @@ -0,0 +1,433 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Joseph Gilbert, Campbell Barton + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "Geometry.h" + +/* - Not needed for now though other geometry functions will probably need them +#include "BLI_arithb.h" +#include "BKE_utildefines.h" +*/ + +/* Used for PolyFill */ +#include "BKE_displist.h" +#include "MEM_guardedalloc.h" +#include "BLI_blenlib.h" + +/* needed for EXPP_ReturnPyObjError and EXPP_check_sequence_consistency */ +#include "gen_utils.h" + +#include "BKE_utildefines.h" +#include "BLI_boxpack2d.h" +#include "BLI_arithb.h" + +#define SWAP_FLOAT(a,b,tmp) tmp=a; a=b; b=tmp +#define eul 0.000001 + +/*-- forward declarations -- */ +static PyObject *M_Geometry_PolyFill( PyObject * self, PyObject * polyLineSeq ); +static PyObject *M_Geometry_LineIntersect2D( PyObject * self, PyObject * args ); +static PyObject *M_Geometry_ClosestPointOnLine( PyObject * self, PyObject * args ); +static PyObject *M_Geometry_PointInTriangle2D( PyObject * self, PyObject * args ); +static PyObject *M_Geometry_BoxPack2D( PyObject * self, PyObject * args ); + + +/*-------------------------DOC STRINGS ---------------------------*/ +static char M_Geometry_doc[] = "The Blender Geometry module\n\n"; +static char M_Geometry_PolyFill_doc[] = "(veclist_list) - takes a list of polylines (each point a vector) and returns the point indicies for a polyline filled with triangles"; +static char M_Geometry_LineIntersect2D_doc[] = "(lineA_p1, lineA_p2, lineB_p1, lineB_p2) - takes 2 lines (as 4 vectors) and returns a vector for their point of intersection or None"; +static char M_Geometry_ClosestPointOnLine_doc[] = "(pt, line_p1, line_p2) - takes a point and a line and returns a (Vector, Bool) for the point on the line, and the bool so you can know if the point was between the 2 points"; +static char M_Geometry_PointInTriangle2D_doc[] = "(pt, tri_p1, tri_p2, tri_p3) - takes 4 vectors, one is the point and the next 3 define the triabgle, only the x and y are used from the vectors"; +static char M_Geometry_BoxPack2D_doc[] = ""; +/*-----------------------METHOD DEFINITIONS ----------------------*/ +struct PyMethodDef M_Geometry_methods[] = { + {"PolyFill", ( PyCFunction ) M_Geometry_PolyFill, METH_O, M_Geometry_PolyFill_doc}, + {"LineIntersect2D", ( PyCFunction ) M_Geometry_LineIntersect2D, METH_VARARGS, M_Geometry_LineIntersect2D_doc}, + {"ClosestPointOnLine", ( PyCFunction ) M_Geometry_ClosestPointOnLine, METH_VARARGS, M_Geometry_ClosestPointOnLine_doc}, + {"PointInTriangle2D", ( PyCFunction ) M_Geometry_PointInTriangle2D, METH_VARARGS, M_Geometry_PointInTriangle2D_doc}, + {"BoxPack2D", ( PyCFunction ) M_Geometry_BoxPack2D, METH_O, M_Geometry_BoxPack2D_doc}, + {NULL, NULL, 0, NULL} +}; +/*----------------------------MODULE INIT-------------------------*/ +PyObject *Geometry_Init(void) +{ + PyObject *submodule; + + submodule = Py_InitModule3("Blender.Geometry", + M_Geometry_methods, M_Geometry_doc); + return (submodule); +} + +/*----------------------------------Geometry.PolyFill() -------------------*/ +/* PolyFill function, uses Blenders scanfill to fill multiple poly lines */ +static PyObject *M_Geometry_PolyFill( PyObject * self, PyObject * polyLineSeq ) +{ + PyObject *tri_list; /*return this list of tri's */ + PyObject *polyLine, *polyVec; + int i, len_polylines, len_polypoints; + + /* display listbase */ + ListBase dispbase={NULL, NULL}; + DispList *dl; + float *fp; /*pointer to the array of malloced dl->verts to set the points from the vectors */ + int index, *dl_face, totpoints=0; + + + dispbase.first= dispbase.last= NULL; + + + if(!PySequence_Check(polyLineSeq)) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a sequence of poly lines" ); + } + + len_polylines = PySequence_Size( polyLineSeq ); + + for( i = 0; i < len_polylines; ++i ) { + polyLine= PySequence_GetItem( polyLineSeq, i ); + if (!PySequence_Check(polyLine)) { + freedisplist(&dispbase); + Py_XDECREF(polyLine); /* may be null so use Py_XDECREF*/ + return EXPP_ReturnPyObjError( PyExc_TypeError, + "One or more of the polylines is not a sequence of Mathutils.Vector's" ); + } + + len_polypoints= PySequence_Size( polyLine ); + if (len_polypoints>0) { /* dont bother adding edges as polylines */ + if (EXPP_check_sequence_consistency( polyLine, &vector_Type ) != 1) { + freedisplist(&dispbase); + Py_DECREF(polyLine); + return EXPP_ReturnPyObjError( PyExc_TypeError, + "A point in one of the polylines is not a Mathutils.Vector type" ); + } + + dl= MEM_callocN(sizeof(DispList), "poly disp"); + BLI_addtail(&dispbase, dl); + dl->type= DL_INDEX3; + dl->nr= len_polypoints; + dl->type= DL_POLY; + dl->parts= 1; /* no faces, 1 edge loop */ + dl->col= 0; /* no material */ + dl->verts= fp= MEM_callocN( sizeof(float)*3*len_polypoints, "dl verts"); + dl->index= MEM_callocN(sizeof(int)*3*len_polypoints, "dl index"); + + for( index = 0; indexvec[0]; + fp[1] = ((VectorObject *)polyVec)->vec[1]; + if( ((VectorObject *)polyVec)->size > 2 ) + fp[2] = ((VectorObject *)polyVec)->vec[2]; + else + fp[2]= 0.0f; /* if its a 2d vector then set the z to be zero */ + + totpoints++; + Py_DECREF(polyVec); + } + } + Py_DECREF(polyLine); + } + + if (totpoints) { + /* now make the list to return */ + filldisplist(&dispbase, &dispbase); + + /* The faces are stored in a new DisplayList + thats added to the head of the listbase */ + dl= dispbase.first; + + tri_list= PyList_New(dl->parts); + if( !tri_list ) { + freedisplist(&dispbase); + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Geometry.PolyFill failed to make a new list" ); + } + + index= 0; + dl_face= dl->index; + while(index < dl->parts) { + PyList_SetItem(tri_list, index, Py_BuildValue("iii", dl_face[0], dl_face[1], dl_face[2]) ); + dl_face+= 3; + index++; + } + freedisplist(&dispbase); + } else { + /* no points, do this so scripts dont barf */ + tri_list= PyList_New(0); + } + + return tri_list; +} + + +static PyObject *M_Geometry_LineIntersect2D( PyObject * self, PyObject * args ) +{ + VectorObject *line_a1, *line_a2, *line_b1, *line_b2; + float a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y, xi, yi, a1,a2,b1,b2, newvec[2]; + if( !PyArg_ParseTuple ( args, "O!O!O!O!", + &vector_Type, &line_a1, + &vector_Type, &line_a2, + &vector_Type, &line_b1, + &vector_Type, &line_b2) + ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "expected 4 vector types\n" ) ); + + a1x= line_a1->vec[0]; + a1y= line_a1->vec[1]; + a2x= line_a2->vec[0]; + a2y= line_a2->vec[1]; + + b1x= line_b1->vec[0]; + b1y= line_b1->vec[1]; + b2x= line_b2->vec[0]; + b2y= line_b2->vec[1]; + + if((MIN2(a1x, a2x) > MAX2(b1x, b2x)) || + (MAX2(a1x, a2x) < MIN2(b1x, b2x)) || + (MIN2(a1y, a2y) > MAX2(b1y, b2y)) || + (MAX2(a1y, a2y) < MIN2(b1y, b2y)) ) { + Py_RETURN_NONE; + } + /* Make sure the hoz/vert line comes first. */ + if (fabs(b1x - b2x) < eul || fabs(b1y - b2y) < eul) { + SWAP_FLOAT(a1x, b1x, xi); /*abuse xi*/ + SWAP_FLOAT(a1y, b1y, xi); + SWAP_FLOAT(a2x, b2x, xi); + SWAP_FLOAT(a2y, b2y, xi); + } + + if (fabs(a1x-a2x) < eul) { /* verticle line */ + if (fabs(b1x-b2x) < eul){ /*verticle second line */ + Py_RETURN_NONE; /* 2 verticle lines dont intersect. */ + } + else if (fabs(b1y-b2y) < eul) { + /*X of vert, Y of hoz. no calculation needed */ + newvec[0]= a1x; + newvec[1]= b1y; + return newVectorObject(newvec, 2, Py_NEW); + } + + yi = (float)(((b1y / fabs(b1x - b2x)) * fabs(b2x - a1x)) + ((b2y / fabs(b1x - b2x)) * fabs(b1x - a1x))); + + if (yi > MAX2(a1y, a2y)) {/* New point above seg1's vert line */ + Py_RETURN_NONE; + } else if (yi < MIN2(a1y, a2y)) { /* New point below seg1's vert line */ + Py_RETURN_NONE; + } + newvec[0]= a1x; + newvec[1]= yi; + return newVectorObject(newvec, 2, Py_NEW); + } else if (fabs(a2y-a1y) < eul) { /* hoz line1 */ + if (fabs(b2y-b1y) < eul) { /*hoz line2*/ + Py_RETURN_NONE; /*2 hoz lines dont intersect*/ + } + + /* Can skip vert line check for seg 2 since its covered above. */ + xi = (float)(((b1x / fabs(b1y - b2y)) * fabs(b2y - a1y)) + ((b2x / fabs(b1y - b2y)) * fabs(b1y - a1y))); + if (xi > MAX2(a1x, a2x)) { /* New point right of hoz line1's */ + Py_RETURN_NONE; + } else if (xi < MIN2(a1x, a2x)) { /*New point left of seg1's hoz line */ + Py_RETURN_NONE; + } + newvec[0]= xi; + newvec[1]= a1y; + return newVectorObject(newvec, 2, Py_NEW); + } + + b1 = (a2y-a1y)/(a2x-a1x); + b2 = (b2y-b1y)/(b2x-b1x); + a1 = a1y-b1*a1x; + a2 = b1y-b2*b1x; + + if (b1 - b2 == 0.0) { + Py_RETURN_NONE; + } + + xi = - (a1-a2)/(b1-b2); + yi = a1+b1*xi; + if ((a1x-xi)*(xi-a2x) >= 0 && (b1x-xi)*(xi-b2x) >= 0 && (a1y-yi)*(yi-a2y) >= 0 && (b1y-yi)*(yi-b2y)>=0) { + newvec[0]= xi; + newvec[1]= yi; + return newVectorObject(newvec, 2, Py_NEW); + } + Py_RETURN_NONE; +} + +static PyObject *M_Geometry_ClosestPointOnLine( PyObject * self, PyObject * args ) +{ + VectorObject *pt, *line_1, *line_2; + float pt_in[3], pt_out[3], l1[3], l2[3]; + float lambda; + PyObject *ret, *val1, *val2; + + if( !PyArg_ParseTuple ( args, "O!O!O!", + &vector_Type, &pt, + &vector_Type, &line_1, + &vector_Type, &line_2) + ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "expected 3 vector types\n" ) ); + + /* accept 2d verts */ + if (pt->size==3) { VECCOPY(pt_in, pt->vec);} + else { pt_in[2]=0.0; VECCOPY2D(pt_in, pt->vec) } + + if (line_1->size==3) { VECCOPY(l1, line_1->vec);} + else { l1[2]=0.0; VECCOPY2D(l1, line_1->vec) } + + if (line_2->size==3) { VECCOPY(l2, line_2->vec);} + else { l2[2]=0.0; VECCOPY2D(l2, line_2->vec) } + + /* do the calculation */ + lambda = lambda_cp_line_ex(pt_in, l1, l2, pt_out); + + val1 = newVectorObject(pt_out, 3, Py_NEW); + val2 = PyFloat_FromDouble(lambda); + + ret = PyTuple_Pack(2, val1, val2); + + Py_DECREF(val1); + Py_DECREF(val2); + + return ret; +} + +#define SIDE_OF_LINE(pa,pb,pp) ((pa[0]-pp[0])*(pb[1]-pp[1]))-((pb[0]-pp[0])*(pa[1]-pp[1])) +#define POINT_IN_TRI(p0,p1,p2,p3) ((SIDE_OF_LINE(p1,p2,p0)>=0) && (SIDE_OF_LINE(p2,p3,p0)>=0) && (SIDE_OF_LINE(p3,p1,p0)>=0)) + +static PyObject *M_Geometry_PointInTriangle2D( PyObject * self, PyObject * args ) +{ + VectorObject *pt_vec, *tri_p1, *tri_p2, *tri_p3; + + if( !PyArg_ParseTuple ( args, "O!O!O!O!", + &vector_Type, &pt_vec, + &vector_Type, &tri_p1, + &vector_Type, &tri_p2, + &vector_Type, &tri_p3) + ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "expected 4 vector types\n" ) ); + + if POINT_IN_TRI(pt_vec->vec, tri_p1->vec, tri_p2->vec, tri_p3->vec) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +int boxPack_FromPyObject(PyObject * value, boxPack **boxarray ) +{ + int len, i; + PyObject *list_item, *item_1, *item_2; + boxPack *box; + + + /* Error checking must alredy be done */ + if( !PyList_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "can only back a list of [x,y,x,w]" ); + + len = PyList_Size( value ); + + (*boxarray) = MEM_mallocN( len*sizeof(boxPack), "boxPack box"); + + + for( i = 0; i < len; i++ ) { + list_item = PyList_GET_ITEM( value, i ); + if( !PyList_Check( list_item ) || PyList_Size( list_item ) < 4 ) { + MEM_freeN(*boxarray); + return EXPP_ReturnIntError( PyExc_TypeError, + "can only back a list of [x,y,x,w]" ); + } + + box = (*boxarray)+i; + + item_1 = PyList_GET_ITEM(list_item, 2); + item_2 = PyList_GET_ITEM(list_item, 3); + + if (!PyNumber_Check(item_1) || !PyNumber_Check(item_2)) { + MEM_freeN(*boxarray); + return EXPP_ReturnIntError( PyExc_TypeError, + "can only back a list of 2d boxes [x,y,x,w]" ); + } + + box->w = (float)PyFloat_AsDouble( item_1 ); + box->h = (float)PyFloat_AsDouble( item_2 ); + box->index = i; + /* verts will be added later */ + } + return 0; +} + +void boxPack_ToPyObject(PyObject * value, boxPack **boxarray) +{ + int len, i; + PyObject *list_item; + boxPack *box; + + len = PyList_Size( value ); + + for( i = 0; i < len; i++ ) { + box = (*boxarray)+i; + list_item = PyList_GET_ITEM( value, box->index ); + PyList_SET_ITEM( list_item, 0, PyFloat_FromDouble( box->x )); + PyList_SET_ITEM( list_item, 1, PyFloat_FromDouble( box->y )); + } + MEM_freeN(*boxarray); +} + + +static PyObject *M_Geometry_BoxPack2D( PyObject * self, PyObject * boxlist ) +{ + boxPack *boxarray; + float tot_width, tot_height; + int len; + int error; + + if(!PyList_Check(boxlist)) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a sequence of boxes [[x,y,w,h], ... ]" ); + + len = PyList_Size( boxlist ); + + if (!len) + return Py_BuildValue( "ff", 0.0, 0.0); + + error = boxPack_FromPyObject(boxlist, &boxarray); + if (error!=0) return NULL; + + /* Non Python function */ + boxPack2D(boxarray, len, &tot_width, &tot_height); + + boxPack_ToPyObject(boxlist, &boxarray); + + return Py_BuildValue( "ff", tot_width, tot_height); +} diff --git a/source/blender/python/api2_2x/Geometry.h b/source/blender/python/api2_2x/Geometry.h new file mode 100644 index 00000000000..c74f832c642 --- /dev/null +++ b/source/blender/python/api2_2x/Geometry.h @@ -0,0 +1,42 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ +/*Include this file for access to vector, quat, matrix, euler, etc...*/ + +#ifndef EXPP_Geometry_H +#define EXPP_Geometry_H + +#include +#include "vector.h" + +PyObject *Geometry_Init( void ); + +#endif /* EXPP_Geometry_H */ diff --git a/source/blender/python/api2_2x/Group.c b/source/blender/python/api2_2x/Group.c new file mode 100644 index 00000000000..26e5edd0733 --- /dev/null +++ b/source/blender/python/api2_2x/Group.c @@ -0,0 +1,813 @@ +/* + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "Group.h" /* This must come first */ + +#include "MEM_guardedalloc.h" + +#include "DNA_group_types.h" +#include "DNA_scene_types.h" /* for Base */ + +#include "BKE_mesh.h" +#include "BKE_library.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_scene.h" +#include "BKE_group.h" + +#include "BLI_blenlib.h" + +#include "blendef.h" +#include "Object.h" +#include "gen_utils.h" +#include "gen_library.h" + +/* checks for the group being removed */ +#define GROUP_DEL_CHECK_PY(bpy_group) if (!(bpy_group->group)) return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, "Group has been removed" ) ) +#define GROUP_DEL_CHECK_INT(bpy_group) if (!(bpy_group->group)) return ( EXPP_ReturnIntError( PyExc_RuntimeError, "Group has been removed" ) ) + +/*****************************************************************************/ +/* Python API function prototypes for the Blender module. */ +/*****************************************************************************/ +static PyObject *M_Group_New( PyObject * self, PyObject * args ); +PyObject *M_Group_Get( PyObject * self, PyObject * args ); +PyObject *M_Group_Unlink( PyObject * self, BPy_Group * pygrp ); + +/* internal */ +static PyObject *GroupObSeq_CreatePyObject( BPy_Group *self, GroupObject *iter ); + +/*****************************************************************************/ +/* Python method structure definition for Blender.Object module: */ +/*****************************************************************************/ +struct PyMethodDef M_Group_methods[] = { + {"New", ( PyCFunction ) M_Group_New, METH_VARARGS, + "(name) Add a new empty group"}, + {"Get", ( PyCFunction ) M_Group_Get, METH_VARARGS, +"(name) - return the group with the name 'name',\ +returns None if notfound.\nIf 'name' is not specified, it returns a list of all groups."}, + {"Unlink", ( PyCFunction ) M_Group_Unlink, METH_O, + "(group) - Unlink (delete) this group from Blender."}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python BPy_Group methods table: */ +/*****************************************************************************/ +static PyObject *BPy_Group_copy( BPy_Group * self ); + +static PyMethodDef BPy_Group_methods[] = { + /* name, method, flags, doc */ + {"__copy__", ( PyCFunction ) BPy_Group_copy, METH_VARARGS, + "() - Return a copy of the group containing the same objects."}, + {"copy", ( PyCFunction ) BPy_Group_copy, METH_VARARGS, + "() - Return a copy of the group containing the same objects."}, + {NULL, NULL, 0, NULL} +}; + + +static PyObject *BPy_Group_copy( BPy_Group * self ) +{ + BPy_Group *py_group; /* for Group Data object wrapper in Python */ + struct Group *bl_group; + GroupObject *group_ob, *group_ob_new; /* Group object, copied and added to the groups */ + + GROUP_DEL_CHECK_PY(self); + + bl_group= add_group( self->group->id.name + 2 ); + + if( bl_group ) /* now create the wrapper grp in Python */ + py_group = ( BPy_Group * ) Group_CreatePyObject( bl_group ); + else + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't create Group Data in Blender" ) ); + + bl_group->id.us = 1; + + /* Now add the objects to the group */ + group_ob= self->group->gobject.first; + while(group_ob) { + /* save time by not using */ + group_ob_new= MEM_callocN(sizeof(GroupObject), "groupobject"); + group_ob_new->ob= group_ob->ob; + BLI_addtail( &bl_group->gobject, group_ob_new); + group_ob= group_ob->next; + } + + return ( PyObject * ) py_group; + +} + + +/************************************************************************ + * + * Python BPy_Object attributes + * + ************************************************************************/ +static PyObject *Group_getObjects( BPy_Group * self ) +{ + return GroupObSeq_CreatePyObject(self, NULL); +} + + +static void add_to_group_wraper(Group *group, Object *ob) { + Base *base; + add_to_group(group, ob); + + if (!(ob->flag & OB_FROMGROUP)) { /* do this to avoid a listbase lookup */ + ob->flag |= OB_FROMGROUP; + + base= object_in_scene(ob, G.scene); + if (base) + base->flag |= OB_FROMGROUP; + } +} + +/* only for internal use Blender.Group.Get("MyGroup").objects= []*/ +static int Group_setObjects( BPy_Group * self, PyObject * args ) +{ + int i, list_size; + Group *group; + Object *blen_ob; + group= self->group; + + GROUP_DEL_CHECK_INT(self); + + if( PyList_Check( args ) ) { + if( EXPP_check_sequence_consistency( args, &Object_Type ) != 1) + return ( EXPP_ReturnIntError( PyExc_TypeError, + "expected a list of objects" ) ); + + /* remove all from the list and add the new items */ + free_group(group); /* unlink all objects from this group, keep the group */ + list_size= PyList_Size( args ); + for( i = 0; i < list_size; i++ ) { + blen_ob= ((BPy_Object *)PyList_GET_ITEM( args, i ))->object; + add_to_group_wraper(group, blen_ob); + } + } else if (PyIter_Check(args)) { + PyObject *iterator = PyObject_GetIter(args); + PyObject *item; + if (iterator == NULL) { + Py_DECREF(iterator); + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a list of objects, This iterator cannot be used." ); + } + free_group(group); /* unlink all objects from this group, keep the group */ + item = PyIter_Next(iterator); + while (item) { + if ( PyObject_TypeCheck(item, &Object_Type) ) { + blen_ob= ((BPy_Object *)item)->object; + add_to_group_wraper(group, blen_ob); + } + Py_DECREF(item); + item = PyIter_Next(iterator); + } + + Py_DECREF(iterator); + + if (PyErr_Occurred()) { + return EXPP_ReturnIntError( PyExc_RuntimeError, + "An unknown error occured while adding iterator objects to the group.\nThe group has been modified." ); + } + + } else + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a list or sequence of objects" ); + return 0; +} + + + +/*****************************************************************************/ +/* PythonTypeObject callback function prototypes */ +/*****************************************************************************/ +static PyObject *Group_repr( BPy_Group * obj ); +static int Group_compare( BPy_Group * a, BPy_Group * b ); + +/*****************************************************************************/ +/* Python BPy_Group getsetattr funcs: */ +/*****************************************************************************/ +static int Group_setLayers( BPy_Group * self, PyObject * value ) +{ + unsigned int laymask = 0; + + GROUP_DEL_CHECK_INT(self); + + if( !PyInt_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected an integer (bitmask) as argument" ); + + laymask = ( unsigned int )PyInt_AS_LONG( value ); + + if( laymask <= 0 ) + return EXPP_ReturnIntError( PyExc_ValueError, + "layer value cannot be zero or below" ); + + self->group->layer= laymask & ((1<<20) - 1); + + return 0; +} + +static PyObject *Group_getLayers( BPy_Group * self ) +{ + return PyInt_FromLong( self->group->layer ); +} + + +/*****************************************************************************/ +/* Python attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef BPy_Group_getseters[] = { + GENERIC_LIB_GETSETATTR, + {"layers", + (getter)Group_getLayers, (setter)Group_setLayers, + "layer mask for this group", + NULL}, + {"objects", + (getter)Group_getObjects, (setter)Group_setObjects, + "objects in this group", + NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/*****************************************************************************/ +/* Python TypeGroup structure definition: */ +/*****************************************************************************/ +PyTypeObject Group_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender Group", /* char *tp_name; */ + sizeof( BPy_Group ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) Group_compare, /* cmpfunc tp_compare; */ + ( reprfunc ) Group_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_Group_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_Group_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + + + + + +/*****************************************************************************/ +/* Function: M_Group_New */ +/* Python equivalent: Blender.Group.New */ +/*****************************************************************************/ +PyObject *M_Group_New( PyObject * self, PyObject * args ) +{ + char *name = "Group"; + BPy_Group *py_group; /* for Group Data object wrapper in Python */ + struct Group *bl_group; + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "string expected as argument or nothing" ); + + bl_group= add_group( name ); + + if( bl_group ) /* now create the wrapper grp in Python */ + py_group = ( BPy_Group * ) Group_CreatePyObject( bl_group ); + else + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't create Group Data in Blender" ) ); + + bl_group->id.us = 1; + + return ( PyObject * ) py_group; +} + +/*****************************************************************************/ +/* Function: M_Group_Get */ +/* Python equivalent: Blender.Group.Get */ +/*****************************************************************************/ +PyObject *M_Group_Get( PyObject * self, PyObject * args ) +{ + char *name = NULL; + Group *group_iter; + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument (or nothing)" ) ); + + group_iter = G.main->group.first; + + if( name ) { /* (name) - Search group by name */ + + BPy_Group *wanted_group = NULL; + + while( ( group_iter ) && ( wanted_group == NULL ) ) { + + if( strcmp( name, group_iter->id.name + 2 ) == 0 ) + wanted_group = + ( BPy_Group * ) + Group_CreatePyObject( group_iter ); + + group_iter = group_iter->id.next; + } + + if( wanted_group == NULL ) { /* Requested group doesn't exist */ + char error_msg[64]; + PyOS_snprintf( error_msg, sizeof( error_msg ), + "Group \"%s\" not found", name ); + return ( EXPP_ReturnPyObjError + ( PyExc_NameError, error_msg ) ); + } + + return ( PyObject * ) wanted_group; + } + + else { /* () - return a list of all groups in the scene */ + int index = 0; + PyObject *grouplist, *pyobj; + + grouplist = PyList_New( BLI_countlist( &( G.main->group ) ) ); + + if( grouplist == NULL ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create group list" ) ); + + while( group_iter ) { + pyobj = Group_CreatePyObject( group_iter ); + + if( !pyobj ) { + Py_DECREF(grouplist); + return ( EXPP_ReturnPyObjError + ( PyExc_MemoryError, + "couldn't create Object" ) ); + } + PyList_SET_ITEM( grouplist, index, pyobj ); + + group_iter = group_iter->id.next; + index++; + } + + return grouplist; + } +} + + +/*****************************************************************************/ +/* Function: M_Group_Unlink */ +/* Python equivalent: Blender.Group.Unlink */ +/*****************************************************************************/ +PyObject *M_Group_Unlink( PyObject * self, BPy_Group * pygrp ) +{ + Group *group; + if( !BPy_Group_Check(pygrp) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a group" ) ); + + GROUP_DEL_CHECK_PY(pygrp); + + group= pygrp->group; + + pygrp->group= NULL; + free_group(group); + unlink_group(group); + group->id.us= 0; + free_libblock( &G.main->group, group ); + Py_RETURN_NONE; +} + + +/*****************************************************************************/ +/* Function: initObject */ +/*****************************************************************************/ +PyObject *Group_Init( void ) +{ + PyObject *submodule; + if( PyType_Ready( &Group_Type ) < 0 ) + return NULL; + if( PyType_Ready( &GroupObSeq_Type ) < 0 ) + return NULL; + + submodule = Py_InitModule3( "Blender.Group", M_Group_methods, + "The Blender Group module\n\n\ +This module provides access to **Group Data** in Blender.\n" ); + + /*Add SUBMODULES to the module*/ + /*PyDict_SetItemString(dict, "Constraint", Constraint_Init()); //creates a *new* module*/ + return submodule; +} + + +/*****************************************************************************/ +/* Function: Group_CreatePyObject */ +/* Description: This function will create a new BlenObject from an existing */ +/* Object structure. */ +/*****************************************************************************/ +PyObject *Group_CreatePyObject( struct Group * grp ) +{ + BPy_Group *pygrp; + + if( !grp ) + Py_RETURN_NONE; + + pygrp = + ( BPy_Group * ) PyObject_NEW( BPy_Group, &Group_Type ); + + if( pygrp == NULL ) { + return ( NULL ); + } + pygrp->group = grp; + return ( ( PyObject * ) pygrp ); +} + +/*****************************************************************************/ +/* Function: Group_FromPyObject */ +/* Description: This function returns the Blender group from the given */ +/* PyObject. */ +/*****************************************************************************/ +Group *Group_FromPyObject( PyObject * py_grp ) +{ + BPy_Group *blen_grp; + + blen_grp = ( BPy_Group * ) py_grp; + return ( blen_grp->group ); +} + +/*****************************************************************************/ +/* Function: Group_compare */ +/* Description: This is a callback function for the BPy_Group type. It */ +/* compares two Group_Type objects. Only the "==" and "!=" */ +/* comparisons are meaninful. Returns 0 for equality and -1 if */ +/* they don't point to the same Blender Object struct. */ +/* In Python it becomes 1 if they are equal, 0 otherwise. */ +/*****************************************************************************/ +static int Group_compare( BPy_Group * a, BPy_Group * b ) +{ + Group *pa = a->group, *pb = b->group; + return ( pa == pb ) ? 0 : -1; +} + +/*****************************************************************************/ +/* Function: Group_repr */ +/* Description: This is a callback function for the BPy_Group type. It */ +/* builds a meaninful string to represent object objects. */ +/*****************************************************************************/ +static PyObject *Group_repr( BPy_Group * self ) +{ + if (!self->group) + return PyString_FromString( "[Group - Removed]" ); + + return PyString_FromFormat( "[Group \"%s\"]", + self->group->id.name + 2 ); +} + + +/************************************************************************ + * + * GroupOb sequence + * + ************************************************************************/ +/* + * create a thin GroupOb object + */ + +static PyObject *GroupObSeq_CreatePyObject( BPy_Group *self, GroupObject *iter ) +{ + BPy_GroupObSeq *seq = PyObject_NEW( BPy_GroupObSeq, &GroupObSeq_Type); + seq->bpygroup = self; Py_INCREF(self); + seq->iter= iter; + return (PyObject *)seq; +} + + +static int GroupObSeq_len( BPy_GroupObSeq * self ) +{ + GROUP_DEL_CHECK_INT(self->bpygroup); + return BLI_countlist( &( self->bpygroup->group->gobject ) ); +} + +/* + * retrive a single GroupOb from somewhere in the GroupObex list + */ + +static PyObject *GroupObSeq_item( BPy_GroupObSeq * self, int i ) +{ + Group *group= self->bpygroup->group; + int index=0; + PyObject *bpy_obj; + GroupObject *gob; + + GROUP_DEL_CHECK_PY(self->bpygroup); + + for (gob= group->gobject.first; gob && i!=index; gob= gob->next, index++) {} + + if (!(gob)) + return EXPP_ReturnPyObjError( PyExc_IndexError, + "array index out of range" ); + + bpy_obj = Object_CreatePyObject( gob->ob ); + + if( !bpy_obj ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyObject_New() failed" ); + + return (PyObject *)bpy_obj; + +} + +static PySequenceMethods GroupObSeq_as_sequence = { + ( inquiry ) GroupObSeq_len, /* sq_length */ + ( binaryfunc ) 0, /* sq_concat */ + ( intargfunc ) 0, /* sq_repeat */ + ( intargfunc ) GroupObSeq_item, /* sq_item */ + ( intintargfunc ) 0, /* sq_slice */ + ( intobjargproc ) 0, /* sq_ass_item */ + ( intintobjargproc ) 0, /* sq_ass_slice */ + 0,0,0, +}; + +/************************************************************************ + * + * Python GroupObSeq_Type iterator (iterates over GroupObjects) + * + ************************************************************************/ + +/* + * Initialize the interator index + */ + +static PyObject *GroupObSeq_getIter( BPy_GroupObSeq * self ) +{ + GROUP_DEL_CHECK_PY(self->bpygroup); + + if (!self->iter) { + self->iter = self->bpygroup->group->gobject.first; + return EXPP_incr_ret ( (PyObject *) self ); + } else { + return GroupObSeq_CreatePyObject(self->bpygroup, self->bpygroup->group->gobject.first); + } +} + +/* + * Return next GroupOb. + */ + +static PyObject *GroupObSeq_nextIter( BPy_GroupObSeq * self ) +{ + PyObject *object; + if( !(self->iter) || !(self->bpygroup->group) ) { + self->iter = NULL; /* so we can add objects again */ + return EXPP_ReturnPyObjError( PyExc_StopIteration, + "iterator at end" ); + } + + object= Object_CreatePyObject( self->iter->ob ); + self->iter= self->iter->next; + return object; +} + + +static PyObject *GroupObSeq_link( BPy_GroupObSeq * self, BPy_Object *value ) +{ + Object *blen_ob; + + GROUP_DEL_CHECK_PY(self->bpygroup); + + if( !BPy_Object_Check(value) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a python object as an argument" ) ); + + /* + if (self->iter != NULL) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Cannot modify group objects while iterating" ); + */ + + blen_ob = value->object; + + add_to_group_wraper(self->bpygroup->group, blen_ob); /* this checks so as not to add the object into the group twice*/ + + Py_RETURN_NONE; +} + +static PyObject *GroupObSeq_unlink( BPy_GroupObSeq * self, BPy_Object *value ) +{ + Object *blen_ob; + Base *base= NULL; + + GROUP_DEL_CHECK_PY(self->bpygroup); + + if( !BPy_Object_Check(value) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a python object as an argument" ) ); + + blen_ob = value->object; + + + + rem_from_group(self->bpygroup->group, blen_ob); + + if(find_group(blen_ob)==NULL) { + blen_ob->flag &= ~OB_FROMGROUP; + + base= object_in_scene(blen_ob, G.scene); + if (base) + base->flag &= ~OB_FROMGROUP; + } + Py_RETURN_NONE; +} + +static struct PyMethodDef BPy_GroupObSeq_methods[] = { + {"link", (PyCFunction)GroupObSeq_link, METH_O, + "make the object a part of this group"}, + {"unlink", (PyCFunction)GroupObSeq_unlink, METH_O, + "unlink an object from this group"}, + {NULL, NULL, 0, NULL} +}; + +/************************************************************************ + * + * Python GroupObSeq_Type standard operations + * + ************************************************************************/ + +static void GroupObSeq_dealloc( BPy_GroupObSeq * self ) +{ + Py_DECREF(self->bpygroup); + PyObject_DEL( self ); +} + +/*****************************************************************************/ +/* Python GroupObSeq_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject GroupObSeq_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender GroupObSeq", /* char *tp_name; */ + sizeof( BPy_GroupObSeq ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + ( destructor ) GroupObSeq_dealloc,/* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + NULL, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + &GroupObSeq_as_sequence, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + ( getiterfunc) GroupObSeq_getIter, /* getiterfunc tp_iter; */ + ( iternextfunc ) GroupObSeq_nextIter, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_GroupObSeq_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + NULL, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; diff --git a/source/blender/python/api2_2x/Group.h b/source/blender/python/api2_2x/Group.h new file mode 100644 index 00000000000..0512623b5f8 --- /dev/null +++ b/source/blender/python/api2_2x/Group.h @@ -0,0 +1,66 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Michel Selten + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_GROUP_H +#define EXPP_GROUP_H + +#include +#include "DNA_group_types.h" + +/* The Group PyTypeObject defined in Group.c */ +extern PyTypeObject Group_Type; +extern PyTypeObject GroupObSeq_Type; + +#define BPy_Group_Check(v) ((v)->ob_type == &Group_Type) +#define BPy_GroupObSeq_Check(v) ((v)->ob_type == &GroupObSeq_Type) + +/*****************************************************************************/ +/* Python BPy_Group structure definition. */ +/*****************************************************************************/ +typedef struct { + PyObject_HEAD + struct Group *group; +} BPy_Group; + + +/* Group object sequence, iterate on the groups object listbase*/ +typedef struct { + PyObject_VAR_HEAD /* required python macro */ + BPy_Group *bpygroup; /* link to the python group so we can know if its been removed */ + GroupObject *iter; /* so we can iterate over the objects */ +} BPy_GroupObSeq; + +PyObject *Group_Init( void ); +PyObject *Group_CreatePyObject( struct Group *group ); +Group *Group_FromPyObject( PyObject * py_obj ); + +#endif /* EXPP_GROUP_H */ diff --git a/source/blender/python/api2_2x/IDProp.c b/source/blender/python/api2_2x/IDProp.c new file mode 100644 index 00000000000..4f2fa82b21e --- /dev/null +++ b/source/blender/python/api2_2x/IDProp.c @@ -0,0 +1,895 @@ +/** + * $Id: IDProp.c + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Joseph Eagar + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "DNA_ID.h" + +#include "BKE_idprop.h" + +#include "IDProp.h" +#include "gen_utils.h" + +#include "MEM_guardedalloc.h" + +#define BSTR_EQ(a, b) (*(a) == *(b) && !strcmp(a, b)) + +/*** Function to wrap ID properties ***/ +PyObject *BPy_Wrap_IDProperty(ID *id, IDProperty *prop, IDProperty *parent); + +extern PyTypeObject IDArray_Type; +extern PyTypeObject IDGroup_Iter_Type; + +/*********************** ID Property Main Wrapper Stuff ***************/ + +PyObject *IDGroup_repr( BPy_IDProperty *self ) +{ + return PyString_FromString( "(ID Property)" ); +} + +extern PyTypeObject IDGroup_Type; + +PyObject *BPy_IDGroup_WrapData( ID *id, IDProperty *prop ) +{ + switch ( prop->type ) { + case IDP_STRING: + return PyString_FromString( prop->data.pointer ); + case IDP_INT: + return PyInt_FromLong( (long)prop->data.val ); + case IDP_FLOAT: + return PyFloat_FromDouble( (double)(*(float*)(&prop->data.val)) ); + case IDP_GROUP: + /*blegh*/ + { + BPy_IDProperty *group = PyObject_New(BPy_IDProperty, &IDGroup_Type); + if (!group) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyObject_New() failed" ); + + group->id = id; + group->prop = prop; + return (PyObject*) group; + } + case IDP_ARRAY: + { + BPy_IDProperty *array = PyObject_New(BPy_IDProperty, &IDArray_Type); + if (!array) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyObject_New() failed" ); + + array->id = id; + array->prop = prop; + return (PyObject*) array; + } + } + Py_RETURN_NONE; +} + +int BPy_IDGroup_SetData(BPy_IDProperty *self, IDProperty *prop, PyObject *value) +{ + switch (prop->type) { + case IDP_STRING: + { + char *st; + if (!PyString_Check(value)) + return EXPP_ReturnIntError(PyExc_TypeError, "expected a string!"); + + st = PyString_AsString(value); + IDP_ResizeArray(prop, strlen(st)+1); + strcpy(prop->data.pointer, st); + return 0; + } + + case IDP_INT: + { + int ivalue; + if (!PyNumber_Check(value)) + return EXPP_ReturnIntError(PyExc_TypeError, "expected an int!"); + value = PyNumber_Int(value); + if (!value) + return EXPP_ReturnIntError(PyExc_TypeError, "expected an int!"); + ivalue = (int) PyInt_AsLong(value); + prop->data.val = ivalue; + Py_XDECREF(value); + break; + } + case IDP_FLOAT: + { + float fvalue; + if (!PyNumber_Check(value)) + return EXPP_ReturnIntError(PyExc_TypeError, "expected a float!"); + value = PyNumber_Float(value); + if (!value) + return EXPP_ReturnIntError(PyExc_TypeError, "expected a float!"); + fvalue = (float) PyFloat_AsDouble(value); + *(float*)&self->prop->data.val = fvalue; + Py_XDECREF(value); + break; + } + + default: + return EXPP_ReturnIntError(PyExc_AttributeError, "attempt to set read-only attribute!"); + } + return 0; +} + +PyObject *BPy_IDGroup_GetName(BPy_IDProperty *self, void *bleh) +{ + return PyString_FromString(self->prop->name); +} + +int BPy_IDGroup_SetName(BPy_IDProperty *self, PyObject *value, void *bleh) +{ + char *st; + if (!PyString_Check(value)) + return EXPP_ReturnIntError(PyExc_TypeError, "expected a string!"); + + st = PyString_AsString(value); + if (strlen(st) >= MAX_IDPROP_NAME) + return EXPP_ReturnIntError(PyExc_TypeError, "string length cannot exceed 31 characters!"); + + strcpy(self->prop->name, st); + return 0; +} + +PyObject *BPy_IDGroup_GetType(BPy_IDProperty *self) +{ + return PyInt_FromLong((long)self->prop->type); +} + +static PyGetSetDef BPy_IDGroup_getseters[] = { + {"name", + (getter)BPy_IDGroup_GetName, (setter)BPy_IDGroup_SetName, + "The name of this Group.", + NULL}, + {NULL, NULL, NULL, NULL, NULL} +}; + +int BPy_IDGroup_Map_Len(BPy_IDProperty *self) +{ + if (self->prop->type != IDP_GROUP) + return EXPP_ReturnIntError( PyExc_TypeError, + "len() of unsized object"); + + return self->prop->len; +} + +PyObject *BPy_IDGroup_Map_GetItem(BPy_IDProperty *self, PyObject *item) +{ + IDProperty *loop; + char *st; + + if (self->prop->type != IDP_GROUP) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "unsubscriptable object"); + + if (!PyString_Check(item)) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "only strings are allowed as keys of ID properties"); + + st = PyString_AsString(item); + for (loop=self->prop->data.group.first; loop; loop=loop->next) { + if (BSTR_EQ(loop->name, st)) return BPy_IDGroup_WrapData(self->id, loop); + } + return EXPP_ReturnPyObjError( PyExc_KeyError, + "key not in subgroup dict"); +} + +/*returns NULL on success, error string on failure*/ +char *BPy_IDProperty_Map_ValidateAndCreate(char *name, IDProperty *group, PyObject *ob) +{ + IDProperty *prop = NULL; + IDPropertyTemplate val = {0}; + + if (PyFloat_Check(ob)) { + val.f = (float) PyFloat_AsDouble(ob); + prop = IDP_New(IDP_FLOAT, val, name); + } else if (PyInt_Check(ob)) { + val.i = (int) PyInt_AsLong(ob); + prop = IDP_New(IDP_INT, val, name); + } else if (PyString_Check(ob)) { + val.str = PyString_AsString(ob); + prop = IDP_New(IDP_STRING, val, name); + } else if (PySequence_Check(ob)) { + PyObject *item; + int i; + + /*validate sequence and derive type. + we assume IDP_INT unless we hit a float + number; then we assume it's */ + val.array.type = IDP_INT; + val.array.len = PySequence_Length(ob); + for (i=0; idata.pointer)[i] = (int)PyInt_AsLong(item); + } else { + item = PyNumber_Float(item); + ((float*)prop->data.pointer)[i] = (float)PyFloat_AsDouble(item); + } + Py_XDECREF(item); + } + } else if (PyMapping_Check(ob)) { + PyObject *keys, *vals, *key, *pval; + int i, len; + /*yay! we get into recursive stuff now!*/ + keys = PyMapping_Keys(ob); + vals = PyMapping_Values(ob); + + /*we allocate the group first; if we hit any invalid data, + we can delete it easily enough.*/ + prop = IDP_New(IDP_GROUP, val, name); + len = PyMapping_Length(ob); + for (i=0; iprop->type != IDP_GROUP) + return EXPP_ReturnIntError( PyExc_TypeError, + "unsubscriptable object"); + + if (!PyString_Check(key)) + return EXPP_ReturnIntError( PyExc_TypeError, + "only strings are allowed as subgroup keys" ); + + if (val == NULL) { + IDProperty *pkey = IDP_GetPropertyFromGroup(self->prop, PyString_AsString(key)); + if (pkey) { + IDP_RemFromGroup(self->prop, pkey); + IDP_FreeProperty(pkey); + MEM_freeN(pkey); + return 0; + } else return EXPP_ReturnIntError( PyExc_RuntimeError, "property not found in group" ); + } + + err = BPy_IDProperty_Map_ValidateAndCreate(PyString_AsString(key), self->prop, val); + if (err) return EXPP_ReturnIntError( PyExc_RuntimeError, err ); + + return 0; +} + +PyObject *BPy_IDGroup_SpawnIterator(BPy_IDProperty *self) +{ + BPy_IDGroup_Iter *iter = PyObject_New(BPy_IDGroup_Iter, &IDGroup_Iter_Type); + + if (!iter) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyObject_New() failed" ); + iter->group = self; + iter->mode = IDPROP_ITER_KEYS; + iter->cur = self->prop->data.group.first; + Py_XINCREF(iter); + return (PyObject*) iter; +} + +PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop) +{ + switch (prop->type) { + case IDP_STRING: + return PyString_FromString(prop->data.pointer); + break; + case IDP_FLOAT: + return PyFloat_FromDouble(*((float*)&prop->data.val)); + break; + case IDP_INT: + return PyInt_FromLong( (long)prop->data.val ); + break; + case IDP_ARRAY: + { + PyObject *seq = PyList_New(prop->len); + int i; + + if (!seq) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyList_New() failed" ); + + for (i=0; ilen; i++) { + if (prop->subtype == IDP_FLOAT) + PyList_SetItem(seq, i, + PyFloat_FromDouble(((float*)prop->data.pointer)[i])); + + else PyList_SetItem(seq, i, + PyInt_FromLong(((int*)prop->data.pointer)[i])); + } + return seq; + } + case IDP_GROUP: + { + PyObject *dict = PyDict_New(), *wrap; + IDProperty *loop; + + if (!dict) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyDict_New() failed" ); + + for (loop=prop->data.group.first; loop; loop=loop->next) { + wrap = BPy_IDGroup_MapDataToPy(loop); + if (!wrap) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "BPy_IDGroup_MapDataToPy() failed" ); + + PyDict_SetItemString(dict, loop->name, wrap); + } + return dict; + } + } + + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "eek!! a property exists with a bad type code!!!" ); +} + +PyObject *BPy_IDGroup_Pop(BPy_IDProperty *self, PyObject *value) +{ + IDProperty *loop; + PyObject *pyform; + char *name = PyString_AsString(value); + + if (!name) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "pop expected at least 1 arguments, got 0" ); + } + + for (loop=self->prop->data.group.first; loop; loop=loop->next) { + if (BSTR_EQ(loop->name, name)) { + pyform = BPy_IDGroup_MapDataToPy(loop); + + if (!pyform) + /*ok something bad happened with the pyobject, + so don't remove the prop from the group. if pyform is + NULL, then it already should have raised an exception.*/ + return NULL; + + IDP_RemFromGroup(self->prop, loop); + return pyform; + } + } + + return EXPP_ReturnPyObjError( PyExc_KeyError, + "item not in group" ); +} + +PyObject *BPy_IDGroup_IterItems(BPy_IDProperty *self) +{ + BPy_IDGroup_Iter *iter = PyObject_New(BPy_IDGroup_Iter, &IDGroup_Iter_Type); + + if (!iter) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyObject_New() failed" ); + + iter->group = self; + iter->mode = IDPROP_ITER_ITEMS; + iter->cur = self->prop->data.group.first; + Py_XINCREF(iter); + return (PyObject*) iter; +} + +PyObject *BPy_IDGroup_GetKeys(BPy_IDProperty *self) +{ + PyObject *seq = PyList_New(self->prop->len); + IDProperty *loop; + int i; + + if (!seq) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyList_New() failed" ); + + for (i=0, loop=self->prop->data.group.first; loop; loop=loop->next, i++) + PyList_SetItem(seq, i, PyString_FromString(loop->name)); + + return seq; +} + +PyObject *BPy_IDGroup_GetValues(BPy_IDProperty *self) +{ + PyObject *seq = PyList_New(self->prop->len); + IDProperty *loop; + int i; + + if (!seq) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyList_New() failed" ); + + for (i=0, loop=self->prop->data.group.first; loop; loop=loop->next, i++) { + PyList_SetItem(seq, i, BPy_IDGroup_WrapData(self->id, loop)); + } + + return seq; +} + +PyObject *BPy_IDGroup_HasKey(BPy_IDProperty *self, PyObject *value) +{ + IDProperty *loop; + char *name = PyString_AsString(value); + + if (!name) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a string"); + + for (loop=self->prop->data.group.first; loop; loop=loop->next) { + if (BSTR_EQ(loop->name, name)) Py_RETURN_TRUE; + } + + Py_RETURN_FALSE; +} + +PyObject *BPy_IDGroup_Update(BPy_IDProperty *self, PyObject *vars) +{ + PyObject *pyob, *pkey, *pval; + int i=0; + + if (PySequence_Size(vars) != 1) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected an object derived from dict."); + + pyob = PyTuple_GET_ITEM(vars, 0); + if (!PyDict_Check(pyob)) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected an object derived from dict."); + + while (PyDict_Next(pyob, &i, &pkey, &pval)) { + BPy_IDGroup_Map_SetItem(self, pkey, pval); + if (PyErr_Occurred()) return NULL; + } + + Py_RETURN_NONE; +} + +PyObject *BPy_IDGroup_ConvertToPy(BPy_IDProperty *self) +{ + return BPy_IDGroup_MapDataToPy(self->prop); +} + +static struct PyMethodDef BPy_IDGroup_methods[] = { + {"pop", (PyCFunction)BPy_IDGroup_Pop, METH_O, + "pop an item from the group; raises KeyError if the item doesn't exist."}, + {"iteritems", (PyCFunction)BPy_IDGroup_IterItems, METH_NOARGS, + "iterate through the items in the dict; behaves like dictionary method iteritems."}, + {"keys", (PyCFunction)BPy_IDGroup_GetKeys, METH_NOARGS, + "get the keys associated with this group as a list of strings."}, + {"values", (PyCFunction)BPy_IDGroup_GetValues, METH_NOARGS, + "get the values associated with this group."}, + {"has_key", (PyCFunction)BPy_IDGroup_HasKey, METH_O, + "returns true if the group contains a key, false if not."}, + {"update", (PyCFunction)BPy_IDGroup_Update, METH_VARARGS, + "updates the values in the group with the values of another or a dict."}, + {"convert_to_pyobject", (PyCFunction)BPy_IDGroup_ConvertToPy, METH_NOARGS, + "return a purely python version of the group."}, + {0, NULL, 0, NULL} +}; + +PyMappingMethods BPy_IDGroup_Mapping = { + (inquiry)BPy_IDGroup_Map_Len, /*inquiry mp_length */ + (binaryfunc)BPy_IDGroup_Map_GetItem, /*binaryfunc mp_subscript */ + (objobjargproc)BPy_IDGroup_Map_SetItem, /*objobjargproc mp_ass_subscript */ +}; + +PyTypeObject IDGroup_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender IDProperty", /* char *tp_name; */ + sizeof( BPy_IDProperty ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + ( reprfunc ) IDGroup_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + &BPy_IDGroup_Mapping, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + (getiterfunc)BPy_IDGroup_SpawnIterator, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + /*** Attribute descriptor and subclassing stuff ***/ + BPy_IDGroup_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_IDGroup_getseters, /* struct PyGetSetDef *tp_getset; */ +}; + +/*********** Main external wrapping function *******/ +PyObject *BPy_Wrap_IDProperty(ID *id, IDProperty *prop, IDProperty *parent) +{ + BPy_IDProperty *wrap = PyObject_New(BPy_IDProperty, &IDGroup_Type); + + if (!wrap) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyObject_New() failed" ); + + wrap->prop = prop; + wrap->parent = parent; + wrap->id = id; + //wrap->destroy = 0; + return (PyObject*) wrap; +} + + +/********Array Wrapper********/ + +PyObject *IDArray_repr(BPy_IDArray *self) +{ + return PyString_FromString("(ID Array)"); +} + + +PyObject *BPy_IDArray_GetType(BPy_IDArray *self) +{ + return PyInt_FromLong( (long)self->prop->subtype ); +} + +PyObject *BPy_IDArray_GetLen(BPy_IDArray *self) +{ + return PyInt_FromLong( (long)self->prop->len ); +} + +static PyGetSetDef BPy_IDArray_getseters[] = { + {"len", + (getter)BPy_IDArray_GetLen, (setter)NULL, + "The length of the array, can also be gotten with len(array).", + NULL}, + {"type", + (getter)BPy_IDArray_GetType, (setter)NULL, + "The type of the data in the array, is an ant.", + NULL}, + {NULL, NULL, NULL, NULL, NULL}, +}; + +int BPy_IDArray_Len(BPy_IDArray *self) +{ + return self->prop->len; +} + +PyObject *BPy_IDArray_GetItem(BPy_IDArray *self, int index) +{ + if (index < 0 || index >= self->prop->len) + return EXPP_ReturnPyObjError( PyExc_IndexError, + "index out of range!"); + + switch (self->prop->subtype) { + case IDP_FLOAT: + return PyFloat_FromDouble( (double)(((float*)self->prop->data.pointer)[index])); + break; + case IDP_INT: + return PyInt_FromLong( (long)((int*)self->prop->data.pointer)[index] ); + break; + } + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "invalid/corrupt array type!"); +} + +int BPy_IDArray_SetItem(BPy_IDArray *self, int index, PyObject *val) +{ + int i; + float f; + + if (index < 0 || index >= self->prop->len) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "index out of range!"); + + switch (self->prop->subtype) { + case IDP_FLOAT: + if (!PyNumber_Check(val)) return EXPP_ReturnIntError( PyExc_TypeError, + "expected a float"); + val = PyNumber_Float(val); + if (!val) return EXPP_ReturnIntError( PyExc_TypeError, + "expected a float"); + + f = (float) PyFloat_AsDouble(val); + ((float*)self->prop->data.pointer)[index] = f; + Py_XDECREF(val); + break; + case IDP_INT: + if (!PyNumber_Check(val)) return EXPP_ReturnIntError( PyExc_TypeError, + "expected an int"); + val = PyNumber_Int(val); + if (!val) return EXPP_ReturnIntError( PyExc_TypeError, + "expected an int"); + + i = (int) PyInt_AsLong(val); + ((int*)self->prop->data.pointer)[index] = i; + Py_XDECREF(val); + break; + } + return 0; +} + +static PySequenceMethods BPy_IDArray_Seq = { + (inquiry) BPy_IDArray_Len, /* inquiry sq_length */ + 0, /* binaryfunc sq_concat */ + 0, /* intargfunc sq_repeat */ + (intargfunc)BPy_IDArray_GetItem, /* intargfunc sq_item */ + 0, /* intintargfunc sq_slice */ + (intobjargproc)BPy_IDArray_SetItem, /* intobjargproc sq_ass_item */ + 0, /* intintobjargproc sq_ass_slice */ + 0, /* objobjproc sq_contains */ + /* Added in release 2.0 */ + 0, /* binaryfunc sq_inplace_concat */ + 0, /* intargfunc sq_inplace_repeat */ +}; + +PyTypeObject IDArray_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender IDArray", /* char *tp_name; */ + sizeof( BPy_IDArray ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + ( reprfunc ) IDArray_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + &BPy_IDArray_Seq, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + NULL, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_IDArray_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +/*********** ID Property Group iterator ********/ + +PyObject *IDGroup_Iter_iterself(PyObject *self) +{ + Py_XINCREF(self); + return self; +} + +PyObject *IDGroup_Iter_repr(BPy_IDGroup_Iter *self) +{ + return PyString_FromString("(ID Property Group)"); +} + +PyObject *BPy_Group_Iter_Next(BPy_IDGroup_Iter *self) +{ + IDProperty *cur=NULL; + PyObject *tmpval; + PyObject *ret; + + if (self->cur) { + cur = self->cur; + self->cur = self->cur->next; + if (self->mode == IDPROP_ITER_ITEMS) { + tmpval = BPy_IDGroup_WrapData(self->group->id, cur); + ret = Py_BuildValue("[s, O]", cur->name, tmpval); + Py_DECREF(tmpval); + return ret; + } else { + return PyString_FromString(cur->name); + } + } else { + return EXPP_ReturnPyObjError( PyExc_StopIteration, + "iterator at end" ); + } +} + +PyTypeObject IDGroup_Iter_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender IDGroup_Iter", /* char *tp_name; */ + sizeof( BPy_IDGroup_Iter ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + ( reprfunc ) IDGroup_Iter_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + IDGroup_Iter_iterself, /* getiterfunc tp_iter; */ + (iternextfunc) BPy_Group_Iter_Next, /* iternextfunc tp_iternext; */ +}; + +void IDProp_Init_Types(void) +{ + PyType_Ready( &IDGroup_Type ); + PyType_Ready( &IDGroup_Iter_Type ); + PyType_Ready( &IDArray_Type ); +} diff --git a/source/blender/python/api2_2x/IDProp.h b/source/blender/python/api2_2x/IDProp.h new file mode 100644 index 00000000000..5fcf4f6e1b7 --- /dev/null +++ b/source/blender/python/api2_2x/IDProp.h @@ -0,0 +1,61 @@ +/** + * $Id: IDProp.h + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Joseph Eagar + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include + +struct ID; +struct IDProperty; +struct BPy_IDGroup_Iter; + +typedef struct BPy_IDProperty { + PyObject_VAR_HEAD + struct ID *id; + struct IDProperty *prop, *parent; + PyObject *data_wrap; +} BPy_IDProperty; + +typedef struct BPy_IDArray { + PyObject_VAR_HEAD + struct ID *id; + struct IDProperty *prop; +} BPy_IDArray; + +typedef struct BPy_IDGroup_Iter { + PyObject_VAR_HEAD + BPy_IDProperty *group; + struct IDProperty *cur; + int mode; +} BPy_IDGroup_Iter; + +PyObject *BPy_Wrap_IDProperty(struct ID *id, struct IDProperty *prop, struct IDProperty *parent); +void IDProp_Init_Types(void); + +#define IDPROP_ITER_KEYS 0 +#define IDPROP_ITER_ITEMS 1 diff --git a/source/blender/python/api2_2x/Image.c b/source/blender/python/api2_2x/Image.c new file mode 100644 index 00000000000..ddfc17c7deb --- /dev/null +++ b/source/blender/python/api2_2x/Image.c @@ -0,0 +1,1339 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano, Campbell Barton, Joilnen B. Leite, + * Austin Benesh + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ +#include "Image.h" /*This must come first */ + +#include "BDR_drawmesh.h" /* free_realtime_image */ +#include "BKE_main.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_image.h" +#include "BKE_idprop.h" +#include "BIF_drawimage.h" +#include "BLI_blenlib.h" +#include "DNA_space_types.h" /* FILE_MAXDIR = 160 */ +#include "IMB_imbuf_types.h" /* for the IB_rect define */ +#include "BIF_gl.h" +#include "gen_utils.h" +#include "gen_library.h" +#include "BKE_packedFile.h" +#include "DNA_packedFile_types.h" +#include "BKE_icons.h" +#include "IMB_imbuf.h" +#include "IDProp.h" + +/* used so we can get G.scene->r.cfra for getting the +current image frame, some images change frame if they are a sequence */ +#include "DNA_scene_types.h" + +/*****************************************************************************/ +/* Python BPy_Image defaults: */ +/*****************************************************************************/ +#define EXPP_IMAGE_REP 1 +#define EXPP_IMAGE_REP_MIN 1 +#define EXPP_IMAGE_REP_MAX 16 + + +enum img_consts { + EXPP_IMAGE_ATTR_XREP = 0, + EXPP_IMAGE_ATTR_YREP, + EXPP_IMAGE_ATTR_START, + EXPP_IMAGE_ATTR_END, + EXPP_IMAGE_ATTR_SPEED, + EXPP_IMAGE_ATTR_BINDCODE, + EXPP_IMAGE_ATTR_SOURCE, +}; + +/************************/ +/*** The Image Module ***/ +/************************/ + +/*****************************************************************************/ +/* Python API function prototypes for the Image module. */ +/*****************************************************************************/ +static PyObject *M_Image_New( PyObject * self, PyObject * args ); +static PyObject *M_Image_Get( PyObject * self, PyObject * args ); +static PyObject *M_Image_GetCurrent( PyObject * self ); +static PyObject *M_Image_Load( PyObject * self, PyObject * value ); + + +/*****************************************************************************/ +/* Python BPy_Image methods declarations: */ +/*****************************************************************************/ +static PyObject *Image_getFilename( BPy_Image * self ); +static PyObject *Image_getSize( BPy_Image * self ); +static PyObject *Image_getDepth( BPy_Image * self ); +static PyObject *Image_getXRep( BPy_Image * self ); +static PyObject *Image_getYRep( BPy_Image * self ); +static PyObject *Image_getBindCode( BPy_Image * self ); +static PyObject *Image_getStart( BPy_Image * self ); +static PyObject *Image_getEnd( BPy_Image * self ); +static PyObject *Image_getSpeed( BPy_Image * self ); +static int Image_setFilename( BPy_Image * self, PyObject * args ); +static PyObject *Image_oldsetFilename( BPy_Image * self, PyObject * args ); +static PyObject *Image_setXRep( BPy_Image * self, PyObject * value ); +static PyObject *Image_setYRep( BPy_Image * self, PyObject * value ); +static PyObject *Image_setStart( BPy_Image * self, PyObject * args ); +static PyObject *Image_setEnd( BPy_Image * self, PyObject * args ); +static PyObject *Image_setSpeed( BPy_Image * self, PyObject * args ); +static PyObject *Image_reload( BPy_Image * self ); +static PyObject *Image_glLoad( BPy_Image * self ); +static PyObject *Image_glFree( BPy_Image * self ); +static PyObject *Image_getPixelF( BPy_Image * self, PyObject * args ); +static PyObject *Image_getPixelI( BPy_Image * self, PyObject * args ); +static PyObject *Image_setPixelF( BPy_Image * self, PyObject * args ); +static PyObject *Image_setPixelI( BPy_Image * self, PyObject * args ); +static PyObject *Image_getMaxXY( BPy_Image * self ); +static PyObject *Image_getMinXY( BPy_Image * self ); +static PyObject *Image_save( BPy_Image * self ); +static PyObject *Image_unpack( BPy_Image * self, PyObject * value ); +static PyObject *Image_pack( BPy_Image * self ); +static PyObject *Image_makeCurrent( BPy_Image * self ); + + +/*****************************************************************************/ +/* Python BPy_Image methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_Image_methods[] = { + /* name, method, flags, doc */ + {"getPixelF", ( PyCFunction ) Image_getPixelF, METH_VARARGS, + "(int, int) - Get pixel color as floats 0.0-1.0 returns [r,g,b,a]"}, + {"getPixelI", ( PyCFunction ) Image_getPixelI, METH_VARARGS, + "(int, int) - Get pixel color as ints 0-255 returns [r,g,b,a]"}, + {"setPixelF", ( PyCFunction ) Image_setPixelF, METH_VARARGS, + "(int, int, [f r,f g,f b,f a]) - Set pixel color using floats 0.0-1.0"}, + {"setPixelI", ( PyCFunction ) Image_setPixelI, METH_VARARGS, + "(int, int, [i r, i g, i b, i a]) - Set pixel color using ints 0-255"}, + {"getMaxXY", ( PyCFunction ) Image_getMaxXY, METH_NOARGS, + "() - Get maximum x & y coordinates of current image as [x, y]"}, + {"getMinXY", ( PyCFunction ) Image_getMinXY, METH_NOARGS, + "() - Get minimun x & y coordinates of image as [x, y]"}, + {"getName", ( PyCFunction ) GenericLib_getName, METH_NOARGS, + "() - Return Image object name"}, + {"getFilename", ( PyCFunction ) Image_getFilename, METH_NOARGS, + "() - Return Image object filename"}, + {"getSize", ( PyCFunction ) Image_getSize, METH_NOARGS, + "() - Return Image object [width, height] dimension in pixels"}, + {"getDepth", ( PyCFunction ) Image_getDepth, METH_NOARGS, + "() - Return Image object pixel depth"}, + {"getXRep", ( PyCFunction ) Image_getXRep, METH_NOARGS, + "() - Return Image object x repetition value"}, + {"getYRep", ( PyCFunction ) Image_getYRep, METH_NOARGS, + "() - Return Image object y repetition value"}, + {"getStart", ( PyCFunction ) Image_getStart, METH_NOARGS, + "() - Return Image object start frame."}, + {"getEnd", ( PyCFunction ) Image_getEnd, METH_NOARGS, + "() - Return Image object end frame."}, + {"getSpeed", ( PyCFunction ) Image_getSpeed, METH_NOARGS, + "() - Return Image object speed (fps)."}, + {"getBindCode", ( PyCFunction ) Image_getBindCode, METH_NOARGS, + "() - Return Image object's bind code value"}, + {"reload", ( PyCFunction ) Image_reload, METH_NOARGS, + "() - Reload the image from the filesystem"}, + {"glLoad", ( PyCFunction ) Image_glLoad, METH_NOARGS, + "() - Load the image data in OpenGL texture memory.\n\ + The bindcode (int) is returned."}, + {"glFree", ( PyCFunction ) Image_glFree, METH_NOARGS, + "() - Free the image data from OpenGL texture memory only,\n\ + see also image.glLoad()."}, + {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS, + "(str) - Change Image object name"}, + {"setFilename", ( PyCFunction ) Image_oldsetFilename, METH_VARARGS, + "(str) - Change Image file name"}, + {"setXRep", ( PyCFunction ) Image_setXRep, METH_O, + "(int) - Change Image object x repetition value"}, + {"setYRep", ( PyCFunction ) Image_setYRep, METH_O, + "(int) - Change Image object y repetition value"}, + {"setStart", ( PyCFunction ) Image_setStart, METH_VARARGS, + "(int) - Change Image object animation start value"}, + {"setEnd", ( PyCFunction ) Image_setEnd, METH_VARARGS, + "(int) - Change Image object animation end value"}, + {"setSpeed", ( PyCFunction ) Image_setSpeed, METH_VARARGS, + "(int) - Change Image object animation speed (fps)"}, + {"save", ( PyCFunction ) Image_save, METH_NOARGS, + "() - Write image buffer to file"}, + {"unpack", ( PyCFunction ) Image_unpack, METH_VARARGS, + "(int) - Unpack image. Uses the values defined in Blender.UnpackModes."}, + {"pack", ( PyCFunction ) Image_pack, METH_NOARGS, + "() - Pack the image"}, + {"makeCurrent", ( PyCFunction ) Image_makeCurrent, METH_NOARGS, + "() - Make this the currently displayed image"}, + {NULL, NULL, 0, NULL} +}; + + +/*****************************************************************************/ +/* The following string definitions are used for documentation strings. */ +/* In Python these will be written to the console when doing a */ +/* Blender.Image.__doc__ */ +/*****************************************************************************/ +static char M_Image_doc[] = "The Blender Image module\n\n"; + +static char M_Image_New_doc[] = + "() - return a new Image object"; + +static char M_Image_Get_doc[] = + "(name) - return the image with the name 'name', \ +returns None if not found.\n If 'name' is not specified, \ +it returns a list of all images in the\ncurrent scene."; + +static char M_Image_GetCurrent_doc[] = + "() - return the current image, from last active the uv/image view, \ +returns None no image is in the view.\n"; + +static char M_Image_Load_doc[] = + "(filename) - return image from file filename as Image Object, \ +returns None if not found.\n"; + +/*****************************************************************************/ +/* Python method structure definition for Blender.Image module: */ +/*****************************************************************************/ +struct PyMethodDef M_Image_methods[] = { + {"New", M_Image_New, METH_VARARGS, M_Image_New_doc}, + {"Get", M_Image_Get, METH_VARARGS, M_Image_Get_doc}, + {"GetCurrent", ( PyCFunction ) M_Image_GetCurrent, METH_NOARGS, M_Image_GetCurrent_doc}, + {"get", M_Image_Get, METH_VARARGS, M_Image_Get_doc}, + {"Load", M_Image_Load, METH_O, M_Image_Load_doc}, + {NULL, NULL, 0, NULL} +}; + + +/*****************************************************************************/ +/* Function: M_Image_New */ +/* Python equivalent: Blender.Image.New */ +/*****************************************************************************/ +static PyObject *M_Image_New( PyObject * self, PyObject * args) +{ + int width, height, depth; + char *name; + float color[] = {0, 0, 0, 1}; + Image *image; + if( !PyArg_ParseTuple( args, "siii", &name, &width, &height, &depth ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected 1 string and 3 ints" ) ); + if (width > 5000 || height > 5000 || width < 1 || height < 1) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "Image width and height must be between 1 and 5000" ) ); + image = BKE_add_image_size(width, height, name, 0, color); + if( !image ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyObject Image_Type" ) ); + + /* reset usage count, since BKE_add_image_size() incremented it */ + /* image->id.us--; */ + /* Strange, new images have a user count of one???, otherwise it messes up */ + + return Image_CreatePyObject( image ); +} + + + +/*****************************************************************************/ +/* Function: M_Image_Get */ +/* Python equivalent: Blender.Image.Get */ +/* Description: Receives a string and returns the image object */ +/* whose name matches the string. If no argument is */ +/* passed in, a list of all image names in the */ +/* current scene is returned. */ +/*****************************************************************************/ +static PyObject *M_Image_Get( PyObject * self, PyObject * args ) +{ + char *name = NULL; + Image *img_iter; + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument (or nothing)" ) ); + + img_iter = G.main->image.first; + + if( name ) { /* (name) - Search image by name */ + + BPy_Image *wanted_image = NULL; + + while( ( img_iter ) && ( wanted_image == NULL ) ) { + if( strcmp( name, img_iter->id.name + 2 ) == 0 ) { + wanted_image = ( BPy_Image * ) + PyObject_NEW( BPy_Image, &Image_Type ); + if( wanted_image ) + wanted_image->image = img_iter; + } + img_iter = img_iter->id.next; + } + + if( wanted_image == NULL ) { /* Requested image doesn't exist */ + char error_msg[64]; + PyOS_snprintf( error_msg, sizeof( error_msg ), + "Image \"%s\" not found", name ); + return ( EXPP_ReturnPyObjError + ( PyExc_NameError, error_msg ) ); + } + + return ( PyObject * ) wanted_image; + } + + else { /* () - return a list of all images in the scene */ + int index = 0; + PyObject *img_list, *pyobj; + + img_list = PyList_New( BLI_countlist( &( G.main->image ) ) ); + + if( img_list == NULL ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyList" ) ); + + while( img_iter ) { + pyobj = Image_CreatePyObject( img_iter ); + + PyList_SET_ITEM( img_list, index, pyobj ); + + img_iter = img_iter->id.next; + index++; + } + + return ( img_list ); + } +} + + + +/*****************************************************************************/ +/* Function: M_Image_GetCurrent*/ +/* Python equivalent: Blender.Image.GetCurrent */ +/* Description: Returns the active current (G.sima) */ +/* This will be the image last under the mouse cursor */ +/* None if there is no Image. */ +/*****************************************************************************/ +static PyObject *M_Image_GetCurrent( PyObject * self ) +{ + if (!G.sima || !G.sima->image) { + Py_RETURN_NONE; + } + what_image( G.sima ); /* make sure image data exists */ + return Image_CreatePyObject( G.sima->image ); +} + + +/*****************************************************************************/ +/* Function: M_Image_Load */ +/* Python equivalent: Blender.Image.Load */ +/* Description: Receives a string and returns the image object */ +/* whose filename matches the string. */ +/*****************************************************************************/ +static PyObject *M_Image_Load( PyObject * self, PyObject * value ) +{ + char *fname = PyString_AsString(value); + Image *img_ptr; + BPy_Image *image; + + if( !value ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ) ); + + image = ( BPy_Image * ) PyObject_NEW( BPy_Image, &Image_Type ); + + if( !image ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyObject Image_Type" ) ); + + img_ptr = BKE_add_image_file( fname ); + if( !img_ptr ) + return ( EXPP_ReturnPyObjError( PyExc_IOError, + "couldn't load image" ) ); + + /* force a load the image buffers*/ + BKE_image_get_ibuf(img_ptr, NULL); + + image->image = img_ptr; + + return ( PyObject * ) image; +} + + +/** + * getPixelF( x, y ) + * returns float list of pixel colors in rgba order. + * returned values are floats normalized to 0.0 - 1.0. + * blender images are all 4x8 bit at the moment apr-2005 + */ + +static PyObject *Image_getPixelF( BPy_Image * self, PyObject * args ) +{ + + PyObject *attr; + ImBuf *ibuf= BKE_image_get_ibuf(self->image, NULL); + char *pixel; /* image data */ + int index; /* offset into image data */ + int x = 0; + int y = 0; + int pixel_size = 4; /* each pixel is 4 x 8-bits packed in unsigned int */ + int i; + + if( !PyArg_ParseTuple( args, "ii", &x, &y ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected 2 integers" ); + + if( !ibuf || !ibuf->rect ) /* loading didn't work */ + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't load image data in Blender" ); + + if( ibuf->type == 1 ) /* bitplane image */ + return EXPP_ReturnPyObjError( PyExc_TypeError, + "unsupported bitplane image format" ); + + if( x > ( ibuf->x - 1 ) + || y > ( ibuf->y - 1 ) + || x < ibuf->xorig || y < ibuf->yorig ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "x or y is out of range" ); + + /* + assumption: from looking at source, skipx is often not set, + so we calc ourselves + */ + + attr = PyList_New(4); + + if (!attr) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't allocate memory for color list" ); + + index = ( x + y * ibuf->x ) * pixel_size; + + pixel = ( char * ) ibuf->rect; + for (i=0; i<4; i++) { + PyList_SetItem( attr, i, PyFloat_FromDouble( ( ( double ) pixel[index+i] ) / 255.0 )); + } + return attr; +} + + +/** + * getPixelI( x, y ) + * returns integer list of pixel colors in rgba order. + * returned values are ints normalized to 0-255. + * blender images are all 4x8 bit at the moment apr-2005 + */ + +static PyObject *Image_getPixelI( BPy_Image * self, PyObject * args ) +{ + PyObject *attr = PyList_New(4); + ImBuf *ibuf= BKE_image_get_ibuf(self->image, NULL); + char *pixel; /* image data */ + int index; /* offset into image data */ + int x = 0; + int y = 0; + int pixel_size = 4; /* each pixel is 4 x 8-bits packed in unsigned int */ + int i; + + if (!attr) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't allocate memory for color list" ); + + if( !PyArg_ParseTuple( args, "ii", &x, &y ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected 2 integers" ); + + if( !ibuf || !ibuf->rect ) /* didn't work */ + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't load image data in Blender" ); + + if( ibuf->type == 1 ) /* bitplane image */ + return EXPP_ReturnPyObjError( PyExc_TypeError, + "unsupported bitplane image format" ); + + if( x > ( ibuf->x - 1 ) + || y > ( ibuf->y - 1 ) + || x < ibuf->xorig || y < ibuf->yorig ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "x or y is out of range" ); + + /* + assumption: from looking at source, skipx is often not set, + so we calc ourselves + */ + + index = ( x + y * ibuf->x ) * pixel_size; + pixel = ( char * ) ibuf->rect; + + for (i=0; i<4; i++) { + PyList_SetItem( attr, i, PyInt_FromLong( pixel[index+i] )); + } + return attr; +} + + +/* set pixel as floats */ + +static PyObject *Image_setPixelF( BPy_Image * self, PyObject * args ) +{ + ImBuf *ibuf= BKE_image_get_ibuf(self->image, NULL); + char *pixel; /* image data */ + int index; /* offset into image data */ + int x = 0; + int y = 0; + int a = 0; + int pixel_size = 4; /* each pixel is 4 x 8-bits packed in unsigned int */ + float p[4]; + + if( !PyArg_ParseTuple + ( args, "ii(ffff)", &x, &y, &p[0], &p[1], &p[2], &p[3] ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected 2 integers and an array of 4 floats" ); + + if( !ibuf || !ibuf->rect ) /* didn't work */ + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't load image data in Blender" ); + + if( ibuf->type == 1 ) /* bitplane image */ + return EXPP_ReturnPyObjError( PyExc_TypeError, + "unsupported bitplane image format" ); + + if( x > ( ibuf->x - 1 ) + || y > ( ibuf->y - 1 ) + || x < ibuf->xorig || y < ibuf->yorig ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "x or y is out of ruange" ); + + for( a = 0; a < 4; a++ ) { + if( p[a] > 1.0 || p[a] < 0.0 ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "r, g, b, or a is out of range" ); + } + + + /* + assumption: from looking at source, skipx is often not set, + so we calc ourselves + */ + + index = ( x + y * ibuf->x ) * pixel_size; + + pixel = ( char * ) ibuf->rect; + + pixel[index] = ( char ) ( p[0] * 255.0 ); + pixel[index + 1] = ( char ) ( p[1] * 255.0 ); + pixel[index + 2] = ( char ) ( p[2] * 255.0 ); + pixel[index + 3] = ( char ) ( p[3] * 255.0 ); + + ibuf->userflags |= IB_BITMAPDIRTY; + Py_RETURN_NONE; +} + + +/* set pixel as ints */ + +static PyObject *Image_setPixelI( BPy_Image * self, PyObject * args ) +{ + ImBuf *ibuf= BKE_image_get_ibuf(self->image, NULL); + char *pixel; /* image data */ + int index; /* offset into image data */ + int x = 0; + int y = 0; + int a = 0; + int pixel_size = 4; /* each pixel is 4 x 8-bits packed in unsigned int */ + int p[4]; + + if( !PyArg_ParseTuple + ( args, "ii(iiii)", &x, &y, &p[0], &p[1], &p[2], &p[3] ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected 2 integers and an list of 4 ints" ); + + if( !ibuf || !ibuf->rect ) /* didn't work */ + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't load image data in Blender" ); + + if( ibuf->type == 1 ) /* bitplane image */ + return EXPP_ReturnPyObjError( PyExc_TypeError, + "unsupported bitplane image format" ); + + if( x > ( ibuf->x - 1 ) + || y > ( ibuf->y - 1 ) + || x < ibuf->xorig || y < ibuf->yorig ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "x or y is out of range" ); + + for( a = 0; a < 4; a++ ) { + if( p[a] > 255 || p[a] < 0 ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "r, g, b, or a is out of range" ); + } + + /* + assumption: from looking at source, skipx is often not set, + so we calc ourselves + */ + + index = ( x + y * ibuf->x ) * pixel_size; + + pixel = ( char * ) ibuf->rect; + + pixel[index] = ( char ) p[0]; + pixel[index + 1] = ( char ) p[1]; + pixel[index + 2] = ( char ) p[2]; + pixel[index + 3] = ( char ) p[3]; + + ibuf->userflags |= IB_BITMAPDIRTY; + Py_RETURN_NONE; +} + + +/* get max extent of image */ + +static PyObject *Image_getMaxXY( BPy_Image * self ) +{ + ImBuf *ibuf= BKE_image_get_ibuf(self->image, NULL); + + if( !ibuf || !ibuf->rect ) /* didn't work */ + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't load image data in Blender" ); + + return Py_BuildValue( "[i,i]", ibuf->x, ibuf->y ); +} + + +/* get min extent of image */ + +static PyObject *Image_getMinXY( BPy_Image * self ) +{ + ImBuf *ibuf= BKE_image_get_ibuf(self->image, NULL); + + if( !ibuf || !ibuf->rect ) /* didn't work */ + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't load image data in Blender" ); + + return Py_BuildValue( "[i,i]", ibuf->xorig, ibuf->yorig ); +} + +/* unpack image */ + +static PyObject *Image_unpack( BPy_Image * self, PyObject * value ) +{ + Image *image = self->image; + int mode = (int)PyInt_AsLong(value); + + /*get the absolute path */ + if( mode==-1 ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected 1 integer from Blender.UnpackModes" ); + + if (image->packedfile==NULL) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "image not packed" ); + + if (unpackImage(image, mode) == RET_ERROR) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "error unpacking image" ); + Py_RETURN_NONE; +} + +/* pack image */ + +static PyObject *Image_pack( BPy_Image * self ) +{ + Image *image = self->image; + ImBuf *ibuf = BKE_image_get_ibuf(image, NULL); + + if( !ibuf || !ibuf->rect ) /* didn't work */ + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't load image data in Blender" ); + + if (image->packedfile ) { /* RePack? */ + if (ibuf->userflags & IB_BITMAPDIRTY) + BKE_image_memorypack(image); + } else { /* Pack for the first time */ + if (ibuf && (ibuf->userflags & IB_BITMAPDIRTY)) + BKE_image_memorypack(image); + else + image->packedfile = newPackedFile(image->name); + } + Py_RETURN_NONE; +} + + +static PyObject *Image_makeCurrent( BPy_Image * self ) +{ +#if 0 /* add back in when bpy becomes "official" */ + static char warning = 1; + if( warning ) { + printf("image.makeCurrent() deprecated!\n\t use 'bpy.images.active = image instead'\n"); + --warning; + } +#endif + + if (!G.sima) + Py_RETURN_FALSE; + + G.sima->image= self->image; + Py_RETURN_TRUE; +} + + +/* save image to file */ + +static PyObject *Image_save( BPy_Image * self ) +{ + ImBuf *ibuf= BKE_image_get_ibuf(self->image, NULL); + + if(!ibuf) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "could not save image (no image buffer)" ); + + /* If this is a packed file, write using writePackedFile + * because IMB_saveiff wont save to a file */ + if (self->image->packedfile) { + if (writePackedFile(self->image->name, self->image->packedfile, 0) != RET_OK) { + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "could not save image (writing image from packedfile failed)" ); + } + } else if (!IMB_saveiff( ibuf, self->image->name, ibuf->flags)) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "could not save image (writing the image buffer failed)" ); + + Py_RETURN_NONE; /* normal return, image saved */ +} + +static PyObject *M_Image_SourceDict( void ) +{ + PyObject *Dict = PyConstant_New( ); + if( Dict ) { + BPy_constant *d = ( BPy_constant * ) Dict; + PyConstant_Insert(d, "STILL", PyInt_FromLong(IMA_SRC_FILE)); + PyConstant_Insert(d, "MOVIE", PyInt_FromLong(IMA_SRC_MOVIE)); + PyConstant_Insert(d, "SEQUENCE", PyInt_FromLong(IMA_SRC_SEQUENCE)); + PyConstant_Insert(d, "GENERATED", PyInt_FromLong(IMA_SRC_GENERATED)); + } + return Dict; +} + +/*****************************************************************************/ +/* Function: Image_Init */ +/*****************************************************************************/ +PyObject *Image_Init( void ) +{ + PyObject *submodule; + PyObject *Sources = M_Image_SourceDict( ); + + if( PyType_Ready( &Image_Type ) < 0 ) + return NULL; + + submodule = + Py_InitModule3( "Blender.Image", M_Image_methods, + M_Image_doc ); + + if( Sources ) + PyModule_AddObject( submodule, "Sources", Sources ); + + return submodule; +} + +/*****************************************************************************/ +/* Python Image_Type callback function prototypes: */ +/*****************************************************************************/ +static int Image_compare( BPy_Image * a, BPy_Image * b ); +static PyObject *Image_repr( BPy_Image * self ); + +/*****************************************************************************/ +/* Function: Image_CreatePyObject */ +/* Description: This function will create a new BPy_Image from an existing */ +/* Blender image structure. */ +/*****************************************************************************/ +PyObject *Image_CreatePyObject( Image * image ) +{ + BPy_Image *py_img; + py_img = ( BPy_Image * ) PyObject_NEW( BPy_Image, &Image_Type ); + + if( !py_img ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create BPy_Image object" ); + + py_img->image = image; + return ( PyObject * ) py_img; +} + +/*****************************************************************************/ +/* Function: Image_FromPyObject */ +/* Description: Returns the Blender Image associated with this object */ +/*****************************************************************************/ +Image *Image_FromPyObject( PyObject * pyobj ) +{ + return ( ( BPy_Image * ) pyobj )->image; +} + +static PyObject *Image_getFilename( BPy_Image * self ) +{ + return PyString_FromString( self->image->name ); +} + +static PyObject *Image_getSize( BPy_Image * self ) +{ + ImBuf *ibuf= BKE_image_get_ibuf(self->image, NULL); + PyObject *attr; + + if( !ibuf ) /* didn't work */ + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't load image data in Blender" ); + + attr = PyList_New(2); + + if( !attr ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't get Image.size attribute" ); + + PyList_SetItem( attr, 0, PyInt_FromLong(ibuf->x)); + PyList_SetItem( attr, 1, PyInt_FromLong(ibuf->y)); + return attr; +} + +static PyObject *Image_getDepth( BPy_Image * self ) +{ + ImBuf *ibuf= BKE_image_get_ibuf(self->image, NULL); + + if( !ibuf ) /* didn't work */ + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't load image data in Blender" ); + + return PyInt_FromLong( (long)ibuf->depth ); +} + + +static PyObject *Image_getXRep( BPy_Image * self ) +{ + return PyInt_FromLong( self->image->xrep ); +} + +static PyObject *Image_getYRep( BPy_Image * self ) +{ + return PyInt_FromLong( self->image->yrep ); +} + +static PyObject *Image_getStart( BPy_Image * self ) +{ + return PyInt_FromLong( self->image->twsta ); +} + +static PyObject *Image_getEnd( BPy_Image * self ) +{ + return PyInt_FromLong( self->image->twend ); +} + +static PyObject *Image_getSpeed( BPy_Image * self ) +{ + return PyInt_FromLong( self->image->animspeed ); +} + +static PyObject *Image_getBindCode( BPy_Image * self ) +{ + return PyLong_FromUnsignedLong( self->image->bindcode ); +} + +static PyObject *Image_reload( BPy_Image * self ) +{ + Image *image = self->image; + + BKE_image_signal(image, NULL, IMA_SIGNAL_RELOAD); + + Py_RETURN_NONE; +} + +static PyObject *Image_glFree( BPy_Image * self ) +{ + Image *image = self->image; + + free_realtime_image( image ); + /* remove the nocollect flag, image is available for garbage collection again */ + image->flag &= ~IMA_NOCOLLECT; + Py_RETURN_NONE; +} + +static PyObject *Image_glLoad( BPy_Image * self ) +{ + Image *image = self->image; + unsigned int *bind = &image->bindcode; + + if( *bind == 0 ) { + ImBuf *ibuf= BKE_image_get_ibuf(self->image, NULL); + + if( !ibuf ) /* didn't work */ + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't load image data in Blender" ); + + glGenTextures( 1, ( GLuint * ) bind ); + glBindTexture( GL_TEXTURE_2D, *bind ); + + gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGBA, ibuf->x, + ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, + ibuf->rect ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + GL_LINEAR_MIPMAP_NEAREST ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + GL_LINEAR ); + glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, ibuf->x, + ibuf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, + ibuf->rect ); + + /* raise the nocollect flag, + image is not available for garbage collection + (python GL might use it directly) + */ + image->flag |= IMA_NOCOLLECT; + } + + return PyLong_FromUnsignedLong( image->bindcode ); +} + +static int Image_setFilename( BPy_Image * self, PyObject * value ) +{ + char *name; + + name = PyString_AsString(value); + + if( !name ) + return ( EXPP_ReturnIntError( PyExc_TypeError, + "expected a string argument" ) ); + + /* max len is FILE_MAXDIR == 160, FILE_MAXFILE == 80 chars like done in DNA_image_types.h */ + if( strlen(name) >= FILE_MAXDIR + FILE_MAXFILE ) + return ( EXPP_ReturnIntError( PyExc_TypeError, + "string argument is limited to 240 chars at most" ) ); + + strcpy( self->image->name, name ); + return 0; +} + +static PyObject *Image_oldsetFilename( BPy_Image * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Image_setFilename ); +} + +static PyObject *Image_setXRep( BPy_Image * self, PyObject * value ) +{ + short param = (short)PyInt_AsLong(value); + + if( param !=-1 && param >= EXPP_IMAGE_REP_MIN && param <= EXPP_IMAGE_REP_MAX) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument in [1,16]" ) ); + + self->image->xrep = param; + Py_RETURN_NONE; +} + +static PyObject *Image_setYRep( BPy_Image * self, PyObject * value ) +{ + short param = (short)PyInt_AsLong(value); + + if( param !=-1 && param >= EXPP_IMAGE_REP_MIN && param <= EXPP_IMAGE_REP_MAX) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument in [1,16]" ) ); + + self->image->yrep = param; + Py_RETURN_NONE; +} + + +static PyObject *Image_setStart( BPy_Image * self, PyObject * args ) +{ + short value; + + if( !PyArg_ParseTuple( args, "h", &value ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument in [0,128]" ) ); + + if( value >= 0 && value <= 128 ) + self->image->twsta = value; + else + return ( EXPP_ReturnPyObjError( PyExc_ValueError, + "expected int argument in [0,128]" ) ); + + Py_RETURN_NONE; +} + + +static PyObject *Image_setEnd( BPy_Image * self, PyObject * args ) +{ + short value; + + if( !PyArg_ParseTuple( args, "h", &value ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument in [0,128]" ) ); + + if( value >= 0 && value <= 128 ) + self->image->twend = value; + else + return ( EXPP_ReturnPyObjError( PyExc_ValueError, + "expected int argument in [0,128]" ) ); + + Py_RETURN_NONE; +} + +static PyObject *Image_setSpeed( BPy_Image * self, PyObject * args ) +{ + short value; + + if( !PyArg_ParseTuple( args, "h", &value ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument in [0,128]" ) ); + + if( value >= 1 && value <= 100 ) + self->image->animspeed = value; + else + return ( EXPP_ReturnPyObjError( PyExc_ValueError, + "expected int argument in [0,128]" ) ); + + Py_RETURN_NONE; +} + + +/*****************************************************************************/ +/* Function: Image_compare */ +/* Description: This is a callback function for the BPy_Image type. It */ +/* compares two Image_Type objects. Only the "==" and "!=" */ +/* comparisons are meaninful. Returns 0 for equality and -1 if */ +/* they don't point to the same Blender Image struct. */ +/* In Python it becomes 1 if they are equal, 0 otherwise. */ +/*****************************************************************************/ +static int Image_compare( BPy_Image * a, BPy_Image * b ) +{ + return ( a->image == b->image ) ? 0 : -1; +} + +/*****************************************************************************/ +/* Function: Image_repr */ +/* Description: This is a callback function for the BPy_Image type. It */ +/* builds a meaninful string to represent image objects. */ +/*****************************************************************************/ +static PyObject *Image_repr( BPy_Image * self ) +{ + return PyString_FromFormat( "[Image \"%s\"]", + self->image->id.name + 2 ); +} + +static PyObject *Image_getPacked(BPy_Image *self, void *closure) +{ + if (self->image->packedfile) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +static PyObject *Image_hasData(BPy_Image *self, void *closure) +{ + if (self->image->ibufs.first) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +static PyObject *Image_getFlag(BPy_Image *self, void *flag) +{ + if (self->image->flag & (int)flag) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; + +} + +static PyObject *Image_getFlagTpage(BPy_Image *self, void *flag) +{ + if (self->image->tpageflag & (int)flag) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; + +} + +static int Image_setSource( BPy_Image *self, PyObject *args) +{ + PyObject* integer = PyNumber_Int( args ); + short value; + + if( !integer ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected integer argument" ); + + value = ( short )PyInt_AS_LONG( integer ); + Py_DECREF( integer ); + + if( value < IMA_SRC_FILE || value > IMA_SRC_GENERATED ) + return EXPP_ReturnIntError( PyExc_ValueError, + "expected integer argument in range 1-4" ); + + self->image->source = value; + return 0; +} + +static int Image_setFlag(BPy_Image *self, PyObject *value, void *flag) +{ + int param = PyObject_IsTrue( value ); + if( param == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected True/False or 0/1" ); + + if ( param ) + self->image->flag |= (int)flag; + else + self->image->flag &= ~(int)flag; + return 0; +} + +static int Image_setFlagTpage(BPy_Image *self, PyObject *value, void *flag) +{ + int param = PyObject_IsTrue( value ); + if( param == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected True/False or 0/1" ); + + if ( param ) + self->image->tpageflag |= (int)flag; + else + self->image->tpageflag &= ~(int)flag; + return 0; +} + +/* + * get integer attributes + */ +static PyObject *getIntAttr( BPy_Image *self, void *type ) +{ + int param; + struct Image *image = self->image; + + switch( (int)type ) { + case EXPP_IMAGE_ATTR_XREP: + param = image->xrep; + break; + case EXPP_IMAGE_ATTR_YREP: + param = image->xrep; + break; + case EXPP_IMAGE_ATTR_START: + param = image->twsta; + break; + case EXPP_IMAGE_ATTR_END: + param = image->twend; + break; + case EXPP_IMAGE_ATTR_SPEED: + param = image->animspeed; + break; + case EXPP_IMAGE_ATTR_BINDCODE: + param = image->bindcode; + break; + case EXPP_IMAGE_ATTR_SOURCE: + param = image->source; + break; + default: + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "undefined type in getIntAttr" ); + } + + return PyInt_FromLong( param ); +} + + +/* + * set integer attributes which require clamping + */ + +static int setIntAttrClamp( BPy_Image *self, PyObject *value, void *type ) +{ + void *param; + struct Image *image = self->image; + int min, max, size; + + switch( (int)type ) { + case EXPP_IMAGE_ATTR_XREP: + min = EXPP_IMAGE_REP_MIN; + max = EXPP_IMAGE_REP_MAX; + size = 'h'; + param = (void *)&image->xrep; + break; + case EXPP_IMAGE_ATTR_YREP: + min = EXPP_IMAGE_REP_MIN; + max = EXPP_IMAGE_REP_MAX; + size = 'h'; + param = (void *)&image->yrep; + break; + case EXPP_IMAGE_ATTR_START: + min = 0; + max = 128; + size = 'h'; + param = (void *)&image->twsta; + break; + case EXPP_IMAGE_ATTR_END: + min = 0; + max = 128; + size = 'h'; + param = (void *)&image->twend; + break; + case EXPP_IMAGE_ATTR_SPEED: + min = 0; + max = 100; + size = 'h'; + param = (void *)&image->animspeed; + break; + default: + return EXPP_ReturnIntError( PyExc_RuntimeError, + "undefined type in setIntAttrClamp"); + } + return EXPP_setIValueClamped( value, param, min, max, size ); +} + +/*****************************************************************************/ +/* Python attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef BPy_Image_getseters[] = { + GENERIC_LIB_GETSETATTR, + {"filename", (getter)Image_getFilename, (setter)Image_setFilename, + "image path", NULL}, + /* readonly */ + {"depth", (getter)Image_getDepth, (setter)NULL, + "image depth", NULL}, + {"size", (getter)Image_getSize, (setter)NULL, + "image size", NULL}, + {"packed", (getter)Image_getPacked, (setter)NULL, + "image packed state", NULL }, + {"has_data", (getter)Image_hasData, (setter)NULL, + "is image data loaded", NULL }, + /* ints */ + {"xrep", (getter)getIntAttr, (setter)setIntAttrClamp, + "image xrep", (void *)EXPP_IMAGE_ATTR_XREP }, + {"yrep", (getter)getIntAttr, (setter)setIntAttrClamp, + "image yrep", (void *)EXPP_IMAGE_ATTR_YREP }, + {"start", (getter)getIntAttr, (setter)setIntAttrClamp, + "image start frame", (void *)EXPP_IMAGE_ATTR_START }, + {"end", (getter)getIntAttr, (setter)setIntAttrClamp, + "image end frame", (void *)EXPP_IMAGE_ATTR_END }, + {"speed", (getter)getIntAttr, (setter)setIntAttrClamp, + "image end frame", (void *)EXPP_IMAGE_ATTR_SPEED }, + {"bindcode", (getter)getIntAttr, (setter)NULL, + "openGL bindcode", (void *)EXPP_IMAGE_ATTR_BINDCODE }, + {"source", (getter)getIntAttr, (setter)Image_setSource, + "image source type", (void *)EXPP_IMAGE_ATTR_SOURCE }, + /* flags */ + {"fields", (getter)Image_getFlag, (setter)Image_setFlag, + "image fields toggle", (void *)IMA_FIELDS }, + {"fields_odd", (getter)Image_getFlag, (setter)Image_setFlag, + "image odd fields toggle", (void *)IMA_STD_FIELD }, + {"antialias", (getter)Image_getFlag, (setter)Image_setFlag, + "image antialiasing toggle", (void *)IMA_ANTIALI }, + {"reflect", (getter)Image_getFlag, (setter)Image_setFlag, + "image reflect toggle", (void *)IMA_REFLECT }, + {"clampX", (getter)Image_getFlagTpage, (setter)Image_setFlagTpage, + "disable tiling on the X axis", (void *)IMA_CLAMP_U }, + {"clampY", (getter)Image_getFlagTpage, (setter)Image_setFlagTpage, + "disable tiling on the Y axis", (void *)IMA_CLAMP_V }, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + + +/*****************************************************************************/ +/* Python Image_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject Image_Type = { + PyObject_HEAD_INIT( NULL ) /* required macro. ( no comma needed ) */ + 0, /* ob_size */ + "Blender Image", /* tp_name */ + sizeof( BPy_Image ), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + NULL, /* tp_dealloc */ + 0, /* tp_print */ + NULL, /* tp_getattr */ + NULL, /* tp_setattr */ + ( cmpfunc ) Image_compare, /* tp_compare */ + ( reprfunc ) Image_repr, /* tp_repr */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_Image_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_Image_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; diff --git a/source/blender/python/api2_2x/Image.h b/source/blender/python/api2_2x/Image.h new file mode 100644 index 00000000000..a36627cb236 --- /dev/null +++ b/source/blender/python/api2_2x/Image.h @@ -0,0 +1,60 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano, Alex Mole + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_IMAGE_H +#define EXPP_IMAGE_H + +#include +#include "DNA_image_types.h" + + +/*****************************************************************************/ +/* Python BPy_Image structure definition */ +/*****************************************************************************/ +typedef struct { + PyObject_HEAD + Image * image; /* libdata must be second */ + +} BPy_Image; + +extern PyTypeObject Image_Type; /* The Image PyType Object */ + +#define BPy_Image_Check(v) ((v)->ob_type == &Image_Type) /*for type checking */ + +/*****************************************************************************/ +/* Module Blender.Image - public functions */ +/*****************************************************************************/ +PyObject *Image_Init( void ); +PyObject *Image_CreatePyObject( Image * image ); +Image *Image_FromPyObject( PyObject * pyobj ); + +#endif /* EXPP_IMAGE_H */ diff --git a/source/blender/python/api2_2x/Ipo.c b/source/blender/python/api2_2x/Ipo.c new file mode 100644 index 00000000000..9b2fd082bee --- /dev/null +++ b/source/blender/python/api2_2x/Ipo.c @@ -0,0 +1,1842 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Jacques Guignot RIP 2005, Nathan Letwory, + * Stephen Swaney, Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "Ipo.h" /*This must come first*/ + +#include "BKE_main.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_object.h" +#include "BKE_ipo.h" +#include "BLI_blenlib.h" +#include "BIF_space.h" +#include "BSE_editipo.h" +#include "MEM_guardedalloc.h" +#include "DNA_key_types.h" +#include "mydevice.h" +#include "Ipocurve.h" +#include "gen_utils.h" +#include "gen_library.h" + +extern int ob_ar[]; +extern int la_ar[]; +extern int ma_ar[]; +extern int ac_ar[]; +extern int cam_ar[]; +extern int co_ar[]; +extern int cu_ar[]; +extern int seq_ar[]; +extern int te_ar[]; +extern int wo_ar[]; + +PyObject *submodule; + +/*****************************************************************************/ +/* Python API function prototypes for the Ipo module. */ +/*****************************************************************************/ +static PyObject *M_Ipo_New( PyObject * self, PyObject * args ); +static PyObject *M_Ipo_Get( PyObject * self, PyObject * args ); +static PyObject *M_Ipo_Recalc( PyObject * self, PyObject * args ); + +/*****************************************************************************/ +/* The following string definitions are used for documentation strings. */ +/* In Python these will be written to the console when doing a */ +/* Blender.Ipo.__doc__ */ +/*****************************************************************************/ +char M_Ipo_doc[] = ""; +char M_Ipo_New_doc[] = ""; +char M_Ipo_Get_doc[] = ""; + +/*****************************************************************************/ +/* Python method structure definition for Blender.Ipo module: */ +/*****************************************************************************/ + +struct PyMethodDef M_Ipo_methods[] = { + {"New", ( PyCFunction ) M_Ipo_New, METH_VARARGS | METH_KEYWORDS, + M_Ipo_New_doc}, + {"Get", M_Ipo_Get, METH_VARARGS, M_Ipo_Get_doc}, + {"get", M_Ipo_Get, METH_VARARGS, M_Ipo_Get_doc}, + {"Recalc", M_Ipo_Recalc, METH_O, M_Ipo_Get_doc}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python BPy_Ipo methods declarations: */ +/*****************************************************************************/ +static PyObject *Ipo_getBlocktype( BPy_Ipo * self ); +static PyObject *Ipo_oldsetBlocktype( BPy_Ipo * self, PyObject * args ); +static int Ipo_setBlocktype( BPy_Ipo * self, PyObject * args ); +static PyObject *Ipo_getRctf( BPy_Ipo * self ); +static PyObject *Ipo_oldsetRctf( BPy_Ipo * self, PyObject * args ); +static int Ipo_setRctf( BPy_Ipo * self, PyObject * args ); + +static PyObject *Ipo_getCurve( BPy_Ipo * self, PyObject * args ); +static PyObject *Ipo_getCurves( BPy_Ipo * self ); +static PyObject *Ipo_getCurveNames( BPy_Ipo * self ); +static PyObject *Ipo_addCurve( BPy_Ipo * self, PyObject * value ); +static PyObject *Ipo_delCurve( BPy_Ipo * self, PyObject * args ); +static PyObject *Ipo_getNcurves( BPy_Ipo * self ); +static PyObject *Ipo_getNBezPoints( BPy_Ipo * self, PyObject * args ); +static PyObject *Ipo_DeleteBezPoints( BPy_Ipo * self, PyObject * args ); +static PyObject *Ipo_getCurveBP( BPy_Ipo * self, PyObject * args ); +static PyObject *Ipo_getCurvecurval( BPy_Ipo * self, PyObject * args ); +static PyObject *Ipo_EvaluateCurveOn( BPy_Ipo * self, PyObject * args ); + +static PyObject *Ipo_setCurveBeztriple( BPy_Ipo * self, PyObject * args ); +static PyObject *Ipo_getCurveBeztriple( BPy_Ipo * self, PyObject * args ); + +static PyObject *Ipo_getChannel( BPy_Ipo * self ); +static PyObject *Ipo_copy( BPy_Ipo * self ); +static int Ipo_setChannel( BPy_Ipo * self, PyObject * args ); + +static int Ipo_length( BPy_Ipo * inst ); +static PyObject *Ipo_getIpoCurveByName( BPy_Ipo * self, PyObject * key ); +static int Ipo_setIpoCurveByName( BPy_Ipo * self, PyObject * key, + PyObject * value ); +static int Ipo_contains( BPy_Ipo * self, PyObject * key ); + +/*****************************************************************************/ +/* Python BPy_Ipo methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_Ipo_methods[] = { + /* name, method, flags, doc */ + {"getName", ( PyCFunction ) GenericLib_getName, METH_NOARGS, + "() - Return Ipo Data name"}, + {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS, + "(str) - Change Ipo Data name"}, + {"getBlocktype", ( PyCFunction ) Ipo_getBlocktype, METH_NOARGS, + "() - Return Ipo blocktype"}, + {"setBlocktype", ( PyCFunction ) Ipo_oldsetBlocktype, METH_VARARGS, + "(str) - Change Ipo blocktype"}, + {"getRctf", ( PyCFunction ) Ipo_getRctf, METH_NOARGS, + "() - Return Ipo rctf"}, + {"setRctf", ( PyCFunction ) Ipo_oldsetRctf, METH_VARARGS, + "(flt,flt,flt,flt) - Change Ipo rctf"}, + {"addCurve", ( PyCFunction ) Ipo_addCurve, METH_O, + "() - Add a curve to Ipo"}, + {"delCurve", ( PyCFunction ) Ipo_delCurve, METH_VARARGS, + "(str) - Delete curve from Ipo"}, + {"getNcurves", ( PyCFunction ) Ipo_getNcurves, METH_NOARGS, + "() - Return number of Ipo curves"}, + {"getCurves", ( PyCFunction ) Ipo_getCurves, METH_NOARGS, + "() - Return list of all defined Ipo curves"}, + {"getCurve", ( PyCFunction ) Ipo_getCurve, METH_VARARGS, + "(str|int) - Returns specified Ipo curve"}, + {"getNBezPoints", ( PyCFunction ) Ipo_getNBezPoints, METH_VARARGS, + "(int) - Return number of Bez points on an Ipo curve"}, + {"delBezPoint", ( PyCFunction ) Ipo_DeleteBezPoints, METH_VARARGS, + "(int) - deprecated: use ipocurve.delBezier()"}, + {"getCurveBP", ( PyCFunction ) Ipo_getCurveBP, METH_VARARGS, + "() - unsupported"}, + {"EvaluateCurveOn", ( PyCFunction ) Ipo_EvaluateCurveOn, METH_VARARGS, + "(int,flt) - deprecated: see ipocurve.evaluate()"}, + {"getCurveCurval", ( PyCFunction ) Ipo_getCurvecurval, METH_VARARGS, + "(int) - deprecated: see ipocurve.evaluate()"}, + {"getCurveBeztriple", ( PyCFunction ) Ipo_getCurveBeztriple, METH_VARARGS, + "(int,int) - deprecated: see ipocurve.bezierPoints[]"}, + {"setCurveBeztriple", ( PyCFunction ) Ipo_setCurveBeztriple, METH_VARARGS, + "(int,int,list) - set a BezTriple"}, + + {"__copy__", ( PyCFunction ) Ipo_copy, METH_NOARGS, + "() - copy the ipo"}, + {"copy", ( PyCFunction ) Ipo_copy, METH_NOARGS, + "() - copy the ipo"}, + + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python BPy_Ipo attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef BPy_Ipo_getseters[] = { + GENERIC_LIB_GETSETATTR, + {"curves", + (getter)Ipo_getCurves, (setter)NULL, + "Ipo curves", + NULL}, + {"curveConsts", + (getter)Ipo_getCurveNames, (setter)NULL, + "Ipo curve constants (values depend on Ipo type)", + NULL}, + {"channel", + (getter)Ipo_getChannel, (setter)Ipo_setChannel, + "Ipo texture channel (world, lamp, material Ipos only)", + NULL}, + + {"blocktype", + (getter)Ipo_getBlocktype, (setter)NULL, + "Ipo block type", + NULL}, + {"rctf", + (getter)Ipo_getRctf, (setter)Ipo_setRctf, + "Ipo type", + NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/*****************************************************************************/ +/* Python Ipo_Type Mapping Methods table: */ +/*****************************************************************************/ +static PyMappingMethods Ipo_as_mapping = { + ( inquiry ) Ipo_length, /* mp_length */ + ( binaryfunc ) Ipo_getIpoCurveByName, /* mp_subscript */ + ( objobjargproc ) Ipo_setIpoCurveByName, /* mp_ass_subscript */ +}; + +static PySequenceMethods Ipo_as_sequence = { + ( inquiry ) 0, /* sq_length */ + ( binaryfunc ) 0, /* sq_concat */ + ( intargfunc ) 0, /* sq_repeat */ + ( intargfunc ) 0, /* sq_item */ + ( intintargfunc ) 0, /* sq_slice */ + ( intobjargproc ) 0, /* sq_ass_item */ + ( intintobjargproc ) 0, /* sq_ass_slice */ + ( objobjproc ) Ipo_contains, /* sq_contains */ + ( binaryfunc ) 0, /* sq_inplace_concat */ + ( intargfunc ) 0, /* sq_inplace_repeat */ +}; + +/*****************************************************************************/ +/* Python Ipo_Type callback function prototypes: */ +/*****************************************************************************/ +/*static int IpoPrint (BPy_Ipo *self, FILE *fp, int flags);*/ +static int Ipo_compare( BPy_Ipo * a, BPy_Ipo * b ); +static PyObject *Ipo_repr( BPy_Ipo * self ); +static PyObject *Ipo_getIter( BPy_Ipo * self ); +static PyObject *Ipo_nextIter( BPy_Ipo * self ); + +/* #define CURVEATTRS */ /* uncomment to enable curves as Ipo attributes */ + +#ifdef CURVEATTRS +static PyGetSetDef BPy_Ipocurve_getseter = { + "noname", + (getter)NULL, (setter)NULL, + "Ipo curve name", + NULL +}; + +void generate_curveattrs( PyObject* dict, int blocktype ) +{ + typedef char * (*namefunc)(int, ... ); + namefunc lookup_name; + int size; + int *vals = NULL; + char name[32]; + PyObject*desc; + + switch ( blocktype ) { + case ID_OB: + lookup_name = (namefunc)getname_ob_ei; + vals = ob_ar; + size = OB_TOTIPO; + break; + case ID_MA: + lookup_name = (namefunc)getname_mat_ei; + vals = ma_ar; + size = MA_TOTIPO; + break; + case ID_CA: + lookup_name = (namefunc)getname_cam_ei; + vals = cam_ar; + size = CAM_TOTIPO; + break; + case ID_LA: + lookup_name = (namefunc)getname_la_ei; + vals = la_ar; + size = LA_TOTIPO; + break; + case ID_TE: + lookup_name = (namefunc)getname_tex_ei; + vals = te_ar; + size = TE_TOTIPO; + break; + case ID_WO: + lookup_name = (namefunc)getname_world_ei; + vals = wo_ar; + size = WO_TOTIPO; + break; + case ID_PO: + lookup_name = (namefunc)getname_ac_ei; + vals = ac_ar; + size = AC_TOTIPO; + break; + case ID_CO: + lookup_name = (namefunc)getname_co_ei; + vals = co_ar; + size = CO_TOTIPO; + break; + case ID_CU: + lookup_name = (namefunc)getname_cu_ei; + vals = cu_ar; + size = CU_TOTIPO; + break; + case ID_SEQ: + lookup_name = (namefunc)getname_seq_ei; + vals = seq_ar; + size = SEQ_TOTIPO; + break; + } + + desc = PyDescr_NewGetSet( &Ipo_Type, &BPy_Ipocurve_getseter ); + while( size-- ) { + strcpy( name, lookup_name( *vals ) ); + *name = tolower( *name ); + PyDict_SetItemString( dict, name, desc ); + ++vals; + } + Py_DECREF( desc ); +} + +static short lookup_curve_name( char *, int , int ); + +static PyObject *getattro( PyObject *self, PyObject *value ) +{ + char *name = PyString_AS_STRING( value ); + Ipo *ipo = ((BPy_Ipo *)self)->ipo; + int adrcode; + IpoCurve *icu; + + if( !strcmp(name, "__class__") ) + return PyObject_GenericGetAttr( self, value ); + + if( !strcmp(name, "__dict__") ) /* no effect */ + { + PyObject *dict; + dict = PyDict_Copy( self->ob_type->tp_dict ); + generate_curveattrs( dict, ipo->blocktype ); + return dict; + } + + adrcode = lookup_curve_name( name, ipo->blocktype, + ((BPy_Ipo *)self)->mtex ); + + if( adrcode != -1 ) { + for( icu = ipo->curve.first; icu; icu = icu->next ) + if( icu->adrcode == adrcode ) + return IpoCurve_CreatePyObject( icu ); + Py_RETURN_NONE; + } + + return PyObject_GenericGetAttr( self, value ); +} +#endif + +/*****************************************************************************/ +/* Python Ipo_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject Ipo_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender Ipo", /* char *tp_name; */ + sizeof( BPy_Ipo ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) Ipo_compare, /* cmpfunc tp_compare; */ + ( reprfunc ) Ipo_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + &Ipo_as_sequence, /* PySequenceMethods *tp_as_sequence; */ + &Ipo_as_mapping, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ +#ifdef CURVEATTRS + (getattrofunc)getattro, +#else + NULL, /* getattrofunc tp_getattro; */ +#endif + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + ( getiterfunc) Ipo_getIter, /* getiterfunc tp_iter; */ + ( iternextfunc ) Ipo_nextIter, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_Ipo_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_Ipo_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +/*****************************************************************************/ +/* internal utility routines */ +/*****************************************************************************/ + +/* + * Search through list of known Ipocurves for a particular name. + * + * str: name of curve we are searching for + * blocktype: type of Ipo + * channel: texture channel number, for World/Lamp/Material curves + * + * returns the adrcode for the named curve if it exists, -1 otherwise + */ + +/* this is needed since getname_ob_ei() is different from the rest */ + +typedef char * (*namefunc)(int, ... ); + +static short lookup_curve_name( char *str, int blocktype, int channel ) +{ + namefunc lookup_name; + int *adrcodes = NULL; + int size = 0; + + /* make sure channel type is ignored when it should be */ + if( blocktype != ID_WO && blocktype != ID_LA && blocktype != ID_MA ) + channel = -1; + + switch ( blocktype ) { + case ID_OB: + lookup_name = (namefunc)getname_ob_ei; + adrcodes = ob_ar; + size = OB_TOTIPO; + break; + case ID_MA: + lookup_name = (namefunc)getname_mat_ei; + adrcodes = ma_ar; + size = MA_TOTIPO; + break; + case ID_CA: + lookup_name = (namefunc)getname_cam_ei; + adrcodes = cam_ar; + size = CAM_TOTIPO; + break; + case ID_LA: + lookup_name = (namefunc)getname_la_ei; + adrcodes = la_ar; + size = LA_TOTIPO; + break; + case ID_TE: + lookup_name = (namefunc)getname_tex_ei; + adrcodes = te_ar; + size = TE_TOTIPO; + break; + case ID_WO: + lookup_name = (namefunc)getname_world_ei; + adrcodes = wo_ar; + size = WO_TOTIPO; + break; + case ID_PO: + lookup_name = (namefunc)getname_ac_ei; + adrcodes = ac_ar; + size = AC_TOTIPO; + break; + case ID_CO: + lookup_name = (namefunc)getname_co_ei; + adrcodes = co_ar; + size = CO_TOTIPO; + break; + case ID_CU: + lookup_name = (namefunc)getname_cu_ei; + adrcodes = cu_ar; + size = CU_TOTIPO; + break; + case ID_SEQ: + lookup_name = (namefunc)getname_seq_ei; + adrcodes = seq_ar; + size = SEQ_TOTIPO; + break; + case ID_KE: /* shouldn't happen */ + default: + return -1; + } + + while ( size-- ) { + char *name = lookup_name ( *adrcodes ); + + /* if not a texture channel, just return the adrcode */ + if( !strcmp( str, name ) ) { + if( channel == -1 || *adrcodes < MA_MAP1 ) + return (short)*adrcodes; + + /* otherwise adjust adrcode to include current channel */ + else { + int param = (short)*adrcodes & ~MA_MAP1; + param |= texchannel_to_adrcode( channel ); + return (short)param; + } + } + ++adrcodes; + } + return -1; +} + +static short lookup_curve_key( char *str, Ipo *ipo ) +{ + Key *keyiter; + + /* find the ipo in the keylist */ + for( keyiter = G.main->key.first; keyiter; keyiter = keyiter->id.next ) { + if( keyiter->ipo == ipo ) { + KeyBlock *block = keyiter->block.first; + + /* look for a matching string, get the adrcode */ + for( block = keyiter->block.first; block; block = block->next ) + if( !strcmp( str, block->name ) ) + return block->adrcode; + + /* no match; no addr code */ + return -1; + } + } + + /* error if the ipo isn't in the list */ + return -2; +} + +/* + * Search through list of known Ipocurves for a particular adrcode. + * + * code: adrcode of curve we are searching for + * blocktype: type of Ipo + * channel: texture channel number, for World/Lamp/Material curves + * + * returns the adrcode for the named curve if it exists, -1 otherwise + */ + +static short lookup_curve_adrcode( int code, int blocktype, int channel ) +{ + int *adrcodes = NULL; + int size = 0; + + switch ( blocktype ) { + case ID_OB: + adrcodes = ob_ar; + size = OB_TOTIPO; + break; + case ID_MA: + adrcodes = ma_ar; + size = MA_TOTIPO; + break; + case ID_CA: + adrcodes = cam_ar; + size = CAM_TOTIPO; + break; + case ID_LA: + adrcodes = la_ar; + size = LA_TOTIPO; + break; + case ID_TE: + adrcodes = te_ar; + size = TE_TOTIPO; + break; + case ID_WO: + adrcodes = wo_ar; + size = WO_TOTIPO; + break; + case ID_PO: + adrcodes = ac_ar; + size = AC_TOTIPO; + break; + case ID_CO: + adrcodes = co_ar; + size = CO_TOTIPO; + break; + case ID_CU: + adrcodes = cu_ar; + size = CU_TOTIPO; + break; + case ID_SEQ: + adrcodes = seq_ar; + size = SEQ_TOTIPO; + break; + case ID_KE: + default: + return -1; + } + + while ( size-- ) { + if( *adrcodes == code ) { + + /* if not a texture channel, just return the adrcode */ + if( channel == -1 || *adrcodes < MA_MAP1 ) + return (short)*adrcodes; + + /* otherwise adjust adrcode to include current channel */ + else { + int param = *adrcodes & ~MA_MAP1; + param |= texchannel_to_adrcode( channel ); + return (short)param; + } + } + ++adrcodes; + } + return -1; +} + +/* + * Delete an IpoCurve from an Ipo + */ + +static void del_ipocurve( Ipo * ipo, IpoCurve * icu ) { + BLI_remlink( &( ipo->curve ), icu ); + if( icu->bezt ) + MEM_freeN( icu->bezt ); + if( icu->driver ) + MEM_freeN( icu->driver ); + MEM_freeN( icu ); + + /* have to do this to avoid crashes in the IPO window */ + allspace( REMAKEIPO, 0 ); + EXPP_allqueue( REDRAWIPO, 0 ); +} + +/*****************************************************************************/ +/* Python BPy_Ipo functions: */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* Function: M_Ipo_New */ +/* Python equivalent: Blender.Ipo.New */ +/*****************************************************************************/ + +static PyObject *M_Ipo_New( PyObject * self_unused, PyObject * args ) +{ + char *name = NULL, *code = NULL; + int idcode = -1; + Ipo *blipo; + + if( !PyArg_ParseTuple( args, "ss", &code, &name ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected two string arguments" ); + + if( !strcmp( code, "Object" ) ) + idcode = ID_OB; + else if( !strcmp( code, "Camera" ) ) + idcode = ID_CA; + else if( !strcmp( code, "World" ) ) + idcode = ID_WO; + else if( !strcmp( code, "Material" ) ) + idcode = ID_MA; + else if( !strcmp( code, "Texture" ) ) + idcode = ID_TE; + else if( !strcmp( code, "Lamp" ) ) + idcode = ID_LA; + else if( !strcmp( code, "Action" ) ) + idcode = ID_PO; + else if( !strcmp( code, "Constraint" ) ) + idcode = ID_CO; + else if( !strcmp( code, "Sequence" ) ) + idcode = ID_SEQ; + else if( !strcmp( code, "Curve" ) ) + idcode = ID_CU; + else if( !strcmp( code, "Key" ) ) + idcode = ID_KE; + else return EXPP_ReturnPyObjError( PyExc_ValueError, + "unknown Ipo code" ); + + blipo = add_ipo( name, idcode ); + + if( blipo ) { + /* return user count to zero because add_ipo() inc'd it */ + blipo->id.us = 0; + /* create python wrapper obj */ + return Ipo_CreatePyObject( blipo ); + } else + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't create Ipo Data in Blender" ); +} + +/*****************************************************************************/ +/* Function: M_Ipo_Get */ +/* Python equivalent: Blender.Ipo.Get */ +/* Description: Receives a string and returns the ipo data obj */ +/* whose name matches the string. If no argument is */ +/* passed in, a list of all ipo data names in the */ +/* current scene is returned. */ +/*****************************************************************************/ +static PyObject *M_Ipo_Get( PyObject * self_unused, PyObject * args ) +{ + char *name = NULL; + Ipo *ipo_iter; + PyObject *ipolist, *pyobj; + char error_msg[64]; + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument (or nothing)" ) ); + + ipo_iter = G.main->ipo.first; + + if( name ) { /* (name) - Search ipo by name */ + while( ipo_iter ) { + if( !strcmp( name, ipo_iter->id.name + 2 ) ) { + return Ipo_CreatePyObject( ipo_iter ); + } + ipo_iter = ipo_iter->id.next; + } + + PyOS_snprintf( error_msg, sizeof( error_msg ), + "Ipo \"%s\" not found", name ); + return EXPP_ReturnPyObjError( PyExc_NameError, error_msg ); + } + + else { /* () - return a list with all ipos in the scene */ + int index = 0; + + ipolist = PyList_New( BLI_countlist( &( G.main->ipo ) ) ); + + if( !ipolist ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyList" ); + + while( ipo_iter ) { + pyobj = Ipo_CreatePyObject( ipo_iter ); + + if( !pyobj ) + return NULL; + + PyList_SET_ITEM( ipolist, index, pyobj ); + + ipo_iter = ipo_iter->id.next; + index++; + } + + return ipolist; + } +} + +/* + * This should probably be deprecated too? Or else documented in epydocs. + * Seems very similar to Ipocurve.recalc(). + */ + +/*****************************************************************************/ +/* Function: M_Ipo_Recalc */ +/* Python equivalent: Blender.Ipo.Recalc */ +/* Description: Receives (presumably) an IpoCurve object and */ +/* updates the curve after changes to control points. */ +/*****************************************************************************/ +static PyObject *M_Ipo_Recalc( PyObject * self_unused, PyObject * value ) +{ + if( !BPy_IpoCurve_Check(value) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected Ipo curve argument" ); + + testhandles_ipocurve( IpoCurve_FromPyObject( value ) ); + + Py_RETURN_NONE; +} + +/*****************************************************************************/ +/* Python BPy_Ipo methods: */ +/*****************************************************************************/ +static PyObject *Ipo_getBlocktype( BPy_Ipo * self ) +{ + return PyInt_FromLong( self->ipo->blocktype ); +} + +static int Ipo_setBlocktype( BPy_Ipo * self, PyObject * args ) +{ + if( !PyInt_Check( args ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected int argument" ); + + self->ipo->blocktype = (short)PyInt_AS_LONG( args ); + + return 0; +} + +static PyObject *Ipo_getRctf( BPy_Ipo * self ) +{ + PyObject *l = PyList_New( 4 ); + PyList_SET_ITEM( l, 0, PyFloat_FromDouble( self->ipo->cur.xmin ) ); + PyList_SET_ITEM( l, 1, PyFloat_FromDouble( self->ipo->cur.xmax ) ); + PyList_SET_ITEM( l, 2, PyFloat_FromDouble( self->ipo->cur.ymin ) ); + PyList_SET_ITEM( l, 3, PyFloat_FromDouble( self->ipo->cur.ymax ) ); + return l; +} + +static int Ipo_setRctf( BPy_Ipo * self, PyObject * args ) +{ + float v[4]; + + if( !PyArg_ParseTuple( args, "ffff", v, v + 1, v + 2, v + 3 ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a tuple of 4 floats" ); + + self->ipo->cur.xmin = v[0]; + self->ipo->cur.xmax = v[1]; + self->ipo->cur.ymin = v[2]; + self->ipo->cur.ymax = v[3]; + + return 0; +} + +/* + * Get total number of Ipo curves for this Ipo. NOTE: this function + * returns all curves for Ipos which have texture channels, unlike + * Ipo_length(). + */ + +static PyObject *Ipo_getNcurves( BPy_Ipo * self ) +{ + IpoCurve *icu; + int i = 0; + + for( icu = self->ipo->curve.first; icu; icu = icu->next ) { + i++; + } + + return PyInt_FromLong( (long)i ); +} + +/* + Function: Ipo_addCurve + Bpy: Blender.Ipo.addCurve( 'curname') + + add a new curve to an existing IPO. + example: + ipo = Blender.Ipo.New('Object','ObIpo') + cu = ipo.addCurve('LocX') +*/ + +static PyObject *Ipo_addCurve( BPy_Ipo * self, PyObject * value ) +{ + short param; /* numeric curve name constant */ + char *cur_name = PyString_AsString(value); /* input arg: curve name */ + Ipo *ipo = 0; + IpoCurve *icu = 0; + Link *link; + + if( !cur_name ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "expected string argument" ) ); + + + /* chase down the ipo list looking for ours */ + link = G.main->ipo.first; + + while( link ) { + ipo = ( Ipo * ) link; + if( ipo == self->ipo ) + break; + link = link->next; + } + + if( !link ) + return EXPP_ReturnPyObjError + ( PyExc_RuntimeError, "Ipo not found" ); + + /* + * Check if the input arg curve name is valid depending on the block + * type, and set param to numeric value. Invalid names will return + * param = -1. + */ + + if( ipo->blocktype != ID_KE ) { + param = lookup_curve_name( cur_name, ipo->blocktype, self->mtex ); + } else { + param = lookup_curve_key( cur_name, ipo ); + if( param == -2 ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "unable to find matching key data for Ipo" ); + } + + if( param == -1 ) + return EXPP_ReturnPyObjError( PyExc_NameError, + "curve name is not valid" ); + + /* see if the curve already exists */ + for( icu = ipo->curve.first; icu; icu = icu->next ) + if( icu->adrcode == param ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "Ipo curve already exists" ); + + /* create the new ipo curve */ + icu = MEM_callocN( sizeof(IpoCurve), "Python added ipocurve"); + icu->blocktype = ipo->blocktype; + icu->adrcode = param; + icu->flag |= IPO_VISIBLE|IPO_AUTO_HORIZ; + set_icu_vars( icu ); + BLI_addtail( &(ipo->curve), icu); + + allspace( REMAKEIPO, 0 ); + EXPP_allqueue( REDRAWIPO, 0 ); + + /* create a bpy wrapper for the new ipo curve */ + return IpoCurve_CreatePyObject( icu ); +} + +/* + Function: Ipo_delCurve + Bpy: Blender.Ipo.delCurve(curtype) + + delete an existing curve from IPO. + example: + ipo = Blender.Ipo.New('Object','ObIpo') + cu = ipo.delCurve('LocX') +*/ + +static PyObject *Ipo_delCurve( BPy_Ipo * self, PyObject * value ) +{ + IpoCurve *icu; + char *strname = PyString_AsString(value); + + if( !strname ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + + for( icu = self->ipo->curve.first; icu; icu = icu->next ) { + if( !strcmp( strname, getIpoCurveName( icu ) ) ) { + del_ipocurve( self->ipo, icu ); + Py_RETURN_NONE; + } + } + + return EXPP_ReturnPyObjError( PyExc_ValueError, "IpoCurve not found" ); +} +/* + */ + +static PyObject *Ipo_getCurve( BPy_Ipo * self, PyObject * args ) +{ + IpoCurve *icu = NULL; + short adrcode; + PyObject *value = NULL; + + if( !PyArg_ParseTuple( args, "|O", &value ) ) + goto typeError; + + /* if no name give, get all the Ipocurves */ + if( !value ) + return Ipo_getCurves( self ); + + /* if arg is a string or int, look up the adrcode */ + if( PyString_Check( value ) ) { + char *str = PyString_AsString( value ); + for( icu = self->ipo->curve.first; icu; icu = icu->next ) { + if( !strcmp( str, getIpoCurveName( icu ) ) ) + return IpoCurve_CreatePyObject( icu ); + } + Py_RETURN_NONE; + } + else if( PyInt_Check( value ) ) { + adrcode = ( short )PyInt_AsLong( value ); + for( icu = self->ipo->curve.first; icu; icu = icu->next ) { + if( icu->adrcode == adrcode ) + return IpoCurve_CreatePyObject( icu ); + } + Py_RETURN_NONE; + } + +typeError: + return EXPP_ReturnPyObjError(PyExc_TypeError, + "expected string or int argument" ); +} + +static PyObject *Ipo_getCurves( BPy_Ipo * self ) +{ + PyObject *attr = PyList_New( 0 ), *pyipo; + IpoCurve *icu; + + for( icu = self->ipo->curve.first; icu; icu = icu->next ) { + pyipo = IpoCurve_CreatePyObject( icu ); + PyList_Append( attr, pyipo ); + Py_DECREF(pyipo); + } + return attr; +} + +/* + * return a list of valid curve name constants for the Ipo + */ + +static PyObject *Ipo_getCurveNames( BPy_Ipo * self ) +{ + namefunc lookup_name; + int size; + PyObject *dict; + int *vals = NULL; + char name[32]; + PyObject *attr = Py_None; + + /* determine what type of Ipo we are */ + + switch ( self->ipo->blocktype ) { + case ID_OB: + lookup_name = (namefunc)getname_ob_ei; + vals = ob_ar; + size = OB_TOTIPO; + strcpy( name, "OB_" ); + break; + case ID_MA: + lookup_name = (namefunc)getname_mat_ei; + vals = ma_ar; + size = MA_TOTIPO; + strcpy( name, "MA_" ); + break; + case ID_CA: + lookup_name = (namefunc)getname_cam_ei; + vals = cam_ar; + size = CAM_TOTIPO; + strcpy( name, "CA_" ); + break; + case ID_LA: + lookup_name = (namefunc)getname_la_ei; + vals = la_ar; + size = LA_TOTIPO; + strcpy( name, "LA_" ); + break; + case ID_TE: + lookup_name = (namefunc)getname_tex_ei; + vals = te_ar; + size = TE_TOTIPO; + strcpy( name, "TE_" ); + break; + case ID_WO: + lookup_name = (namefunc)getname_world_ei; + vals = wo_ar; + size = WO_TOTIPO; + strcpy( name, "WO_" ); + break; + case ID_PO: + lookup_name = (namefunc)getname_ac_ei; + vals = ac_ar; + size = AC_TOTIPO; + strcpy( name, "PO_" ); + break; + case ID_CO: + lookup_name = (namefunc)getname_co_ei; + vals = co_ar; + size = CO_TOTIPO; + strcpy( name, "CO_" ); + break; + case ID_CU: + lookup_name = (namefunc)getname_cu_ei; + vals = cu_ar; + size = CU_TOTIPO; + strcpy( name, "CU_" ); + break; + case ID_SEQ: + lookup_name = (namefunc)getname_seq_ei; + vals = seq_ar; + size = SEQ_TOTIPO; + strcpy( name, "SQ_" ); + break; + case ID_KE: + { + Key *key; + + /* find the ipo in the keylist */ + for( key = G.main->key.first; key; key = key->id.next ) { + if( key->ipo == self->ipo ) { + PyObject *tmpstr; + KeyBlock *block = key->block.first; + attr = PyList_New( 0 ); + + /* add each name to the list */ + for( block = key->block.first; block; block = block->next ) { + tmpstr = PyString_FromString( block->name ); + PyList_Append( attr, tmpstr); + Py_DECREF(tmpstr); + } + return attr; + } + } + + /* error if the ipo isn't in the list */ + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "unable to find matching key data for Ipo" ); + } + default: + Py_DECREF( attr ); + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "unknown Ipo type" ); + } + + /* + * go through the list of adrcodes to find names, then add to dictionary + * with string as key and adrcode as value + */ + + dict = PyModule_GetDict( submodule ); + attr = PyConstant_New(); + + while( size-- ) { + char *ptr = name+3; + strcpy( name+3, lookup_name( *vals ) ); + while( *ptr ) { + *ptr = (char)toupper( *ptr ); + ++ptr; + } + PyConstant_Insert( (BPy_constant *)attr, name, + PyInt_FromLong( *vals ) ); + ++vals; + } + return attr; +} + +void generate_curveconsts( PyObject* module ) +{ + namefunc lookup_name = NULL; + int size = 0; + int *vals = NULL; + char name[32]; + + unsigned int i = 0; + static short curvelist[] = { + ID_OB, ID_MA, ID_CA, ID_LA, ID_TE, ID_WO, ID_PO, ID_CO, ID_CU, ID_SEQ + }; + + for( i = 0; i < sizeof(curvelist)/sizeof(short); ++i ) { + switch ( curvelist[i] ) { + case ID_OB: + lookup_name = (namefunc)getname_ob_ei; + vals = ob_ar; + size = OB_TOTIPO; + strcpy( name, "OB_" ); + break; + case ID_MA: + lookup_name = (namefunc)getname_mat_ei; + vals = ma_ar; + size = MA_TOTIPO; + strcpy( name, "MA_" ); + break; + case ID_CA: + lookup_name = (namefunc)getname_cam_ei; + vals = cam_ar; + size = CAM_TOTIPO; + strcpy( name, "CA_" ); + break; + case ID_LA: + lookup_name = (namefunc)getname_la_ei; + vals = la_ar; + size = LA_TOTIPO; + strcpy( name, "LA_" ); + break; + case ID_TE: + lookup_name = (namefunc)getname_tex_ei; + vals = te_ar; + size = TE_TOTIPO; + strcpy( name, "TE_" ); + break; + case ID_WO: + lookup_name = (namefunc)getname_world_ei; + vals = wo_ar; + size = WO_TOTIPO; + strcpy( name, "WO_" ); + break; + case ID_PO: + lookup_name = (namefunc)getname_ac_ei; + vals = ac_ar; + size = AC_TOTIPO; + strcpy( name, "PO_" ); + break; + case ID_CO: + lookup_name = (namefunc)getname_co_ei; + vals = co_ar; + size = CO_TOTIPO; + strcpy( name, "CO_" ); + break; + case ID_CU: + lookup_name = (namefunc)getname_cu_ei; + vals = cu_ar; + size = CU_TOTIPO; + strcpy( name, "CU_" ); + break; + case ID_SEQ: + lookup_name = (namefunc)getname_seq_ei; + vals = seq_ar; + size = SEQ_TOTIPO; + strcpy( name, "SQ_" ); + break; + } + + while( size-- ) { + char *ptr = name+3; + strcpy( name+3, lookup_name( *vals ) ); + while( *ptr ) { + *ptr = (char)toupper( *ptr ); + ++ptr; + } + PyModule_AddIntConstant( module, name, *vals ); + ++vals; + } + } +} + + +/* + * get the current texture channel number, if defined + */ + +static PyObject *Ipo_getChannel( BPy_Ipo * self ) +{ + if( self->mtex != -1 ) + return PyInt_FromLong( (long)self->mtex ); + Py_RETURN_NONE; +} + +/* + * set the current texture channel number, if defined + */ + +static int Ipo_setChannel( BPy_Ipo * self, PyObject * value ) +{ + if( self->mtex != -1 ) + return EXPP_setIValueRange( value, &self->mtex, 0, 9, 'h' ); + return 0; +} + +/*****************************************************************************/ +/* Function: Ipo_compare */ +/* Description: This compares 2 ipo python types, == or != only. */ +/*****************************************************************************/ +static int Ipo_compare( BPy_Ipo * a, BPy_Ipo * b ) +{ + return ( a->ipo == b->ipo ) ? 0 : -1; +} + +/*****************************************************************************/ +/* Function: Ipo_repr */ +/* Description: This is a callback function for the BPy_Ipo type. It */ +/* builds a meaningful string to represent ipo objects. */ +/*****************************************************************************/ +static PyObject *Ipo_repr( BPy_Ipo * self ) +{ + char *param; + + switch ( self->ipo->blocktype ) { + case ID_OB: + param = "Object"; break; + case ID_CA: + param = "Camera"; break; + case ID_LA: + param = "Lamp"; break; + case ID_TE: + param = "Texture"; break; + case ID_WO: + param = "World"; break; + case ID_MA: + param = "Material"; break; + case ID_PO: + param = "Action"; break; + case ID_CO: + param = "Constriant"; break; + case ID_CU: + param = "Curve"; break; + case ID_SEQ: + param = "Sequence"; break; + case ID_KE: + param = "Key"; break; + default: + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "unknown Ipo type" ); + } + return PyString_FromFormat( "[Ipo \"%s\" (%s)]", self->ipo->id.name + 2, + param ); +} + +/* Three Python Ipo_Type helper functions needed by the Object module: */ + +/*****************************************************************************/ +/* Function: Ipo_CreatePyObject */ +/* Description: This function will create a new BPy_Ipo from an existing */ +/* Blender ipo structure. */ +/*****************************************************************************/ +PyObject *Ipo_CreatePyObject( Ipo * ipo ) +{ + BPy_Ipo *pyipo; + pyipo = ( BPy_Ipo * ) PyObject_NEW( BPy_Ipo, &Ipo_Type ); + if( !pyipo ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create BPy_Ipo object" ); + pyipo->ipo = ipo; + pyipo->iter = 0; + if( pyipo->ipo->blocktype == ID_WO || pyipo->ipo->blocktype == ID_LA || + pyipo->ipo->blocktype == ID_MA ) + pyipo->mtex = 0; + else + pyipo->mtex = -1; + return ( PyObject * ) pyipo; +} + +/*****************************************************************************/ +/* Function: Ipo_FromPyObject */ +/* Description: This function returns the Blender ipo from the given */ +/* PyObject. */ +/*****************************************************************************/ +Ipo *Ipo_FromPyObject( PyObject * pyobj ) +{ + return ( ( BPy_Ipo * ) pyobj )->ipo; +} + +/*****************************************************************************/ +/* Function: Ipo_length */ +/* Description: This function counts the number of curves accessible for the */ +/* PyObject. */ +/*****************************************************************************/ +static int Ipo_length( BPy_Ipo * self ) +{ + IpoCurve *icu; + int len = 0; + + for( icu = self->ipo->curve.first; icu; icu = icu->next ) { + if( self->mtex == -1 || icu->adrcode < MA_MAP1 || + icu->adrcode & texchannel_to_adrcode( self->mtex ) ) + ++len; + } + return len; +} + +/* + * "mapping" operator getter: return an IpoCurve it we can find it + */ + +static PyObject *Ipo_getIpoCurveByName( BPy_Ipo * self, PyObject * key ) +{ + IpoCurve *icu = NULL; + int adrcode; + + /* if Ipo is not ShapeKey and arg is an int, look up the adrcode */ + if( self->ipo->blocktype != ID_KE && PyNumber_Check( key ) ) + adrcode = lookup_curve_adrcode( PyInt_AsLong( key ), + self->ipo->blocktype, self->mtex ); + /* if Ipo is ShapeKey and arg is string, look up the adrcode */ + else if( self->ipo->blocktype == ID_KE && PyString_Check( key ) ) { + adrcode = lookup_curve_key( PyString_AS_STRING( key ), self->ipo ); + if( adrcode == -2 ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "unable to find matching key data for Ipo" ); + } + else + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int or string key" ); + + /* if no adrcode found, value error */ + if( adrcode == -1 ) + return EXPP_ReturnPyObjError( PyExc_KeyError, "invalid curve key" ); + + /* search for a matching adrcode */ + for( icu = self->ipo->curve.first; icu; icu = icu->next ) + if( icu->adrcode == adrcode ) + return IpoCurve_CreatePyObject( icu ); + + /* no curve found */ + Py_RETURN_NONE; +} + +/* + * "mapping" operator setter: create or delete an IpoCurve it we can find it + */ + +static int Ipo_setIpoCurveByName( BPy_Ipo * self, PyObject * key, + PyObject * arg ) +{ + IpoCurve *icu; + Ipo *ipo = self->ipo; + short adrcode; + + /* "del ipo[const]" will send NULL here; give an error */ + if( !arg ) + return EXPP_ReturnIntError( PyExc_NotImplementedError, + "del operator not supported" ); + + /* "del ipo[const]" will send NULL here; give an error */ + if( self->ipo->blocktype == ID_KE ) + return EXPP_ReturnIntError( PyExc_TypeError, + "creation or deletion of Shape Keys not supported" ); + + /* check for int argument */ + if( !PyNumber_Check( key ) ) + return EXPP_ReturnIntError( PyExc_TypeError, "expected int key" ); + + /* look up the key, return error if not found */ + adrcode = lookup_curve_adrcode( PyInt_AsLong( key ), + self->ipo->blocktype, self->mtex ); + + if( adrcode == -1 ) + return EXPP_ReturnIntError( PyExc_KeyError, + "invalid curve specified" ); + + /* if arg is None, delete the curve */ + if( arg == Py_None ) { + for( icu = self->ipo->curve.first; icu; icu = icu->next ) { + if( icu->adrcode == adrcode ) { + del_ipocurve( ipo, icu ); + return 0; + } + } + + return EXPP_ReturnIntError( PyExc_ValueError, "IpoCurve not found" ); + } else { + + /* create the new ipo curve */ + float time, curval; + PyObject *tmp, *flt=NULL, *val=NULL; + + /* error if not a sequence or sequence with other than 2 values */ + if( PySequence_Size( arg ) != 2 ) + goto AttrError; + + /* get the time and curval */ + tmp = PySequence_ITEM( arg, 0 ); + flt = PyNumber_Float( tmp ); + Py_DECREF( tmp ); + tmp = PySequence_ITEM( arg, 1 ); + val = PyNumber_Float( tmp ); + Py_DECREF( tmp ); + + if( !flt || !val ) + goto AttrError; + + time = (float)PyFloat_AS_DOUBLE( flt ); + curval = (float)PyFloat_AS_DOUBLE( val ); + Py_DECREF( flt ); + Py_DECREF( val ); + + /* if curve already exist, delete the original */ + for( icu = ipo->curve.first; icu; icu = icu->next ) + if( icu->adrcode == adrcode ) { + del_ipocurve( ipo, icu ); + break; + } + + /* create the new curve, then add the key */ + icu = MEM_callocN( sizeof(IpoCurve), "Python added ipocurve"); + icu->blocktype = ipo->blocktype; + icu->adrcode = adrcode; + icu->flag |= IPO_VISIBLE|IPO_AUTO_HORIZ; + set_icu_vars( icu ); + BLI_addtail( &(ipo->curve), icu); + insert_vert_icu( icu, time, curval, 0); + + allspace( REMAKEIPO, 0 ); + EXPP_allqueue( REDRAWIPO, 0 ); + + return 0; + +AttrError: + Py_XDECREF( val ); + Py_XDECREF( flt ); + return EXPP_ReturnIntError( PyExc_AttributeError, + "expected sequence of two floats" ); + } +} + +/* + * sequence __contains__ method (implements "x in ipo") + */ + +static int Ipo_contains( BPy_Ipo *self, PyObject *key ) +{ + IpoCurve *icu = NULL; + int adrcode; + + /* take a Ipo curve name: key must be a int */ + + if( self->ipo->blocktype != ID_KE && PyNumber_Check( key ) ) { + adrcode = lookup_curve_adrcode( PyInt_AsLong( key ), + self->ipo->blocktype, self->mtex ); + + /* if we found an adrcode for the key, search the ipo's curve */ + if( adrcode != -1 ) { + for( icu = self->ipo->curve.first; icu; icu = icu->next ) + if( icu->adrcode == adrcode ) + return 1; + } + } else if( self->ipo->blocktype == ID_KE && PyString_Check( key ) ) { + adrcode = lookup_curve_key( PyString_AS_STRING( key ), self->ipo ); + + /* if we found an adrcode for the key, search the ipo's curve */ + if( adrcode >= 0 ) { + for( icu = self->ipo->curve.first; icu; icu = icu->next ) + if( icu->adrcode == adrcode ) + return 1; + } + } + + /* no curve found */ + return 0; +} + +/* + * Initialize the interator index + */ + +static PyObject *Ipo_getIter( BPy_Ipo * self ) +{ + /* return a new IPO object if we are looping on the existing one + This allows nested loops */ + if (self->iter==0) { + return EXPP_incr_ret ( (PyObject *) self ); + } else { + return Ipo_CreatePyObject(self->ipo); + } +} + +/* + * Get the next Ipo curve + */ + +static PyObject *Ipo_nextIter( BPy_Ipo * self ) +{ + int i; + IpoCurve *icu = self->ipo->curve.first; + + ++self->iter; + + /* + * count curves only if + * (a) Ipo has no texture channels + * (b) Ipo has texture channels, but curve is not that type + * (c) Ipo has texture channels, and curve is that type, and it is + * in the active texture channel + */ + for( i = 0; icu; icu = icu->next ) { + if( self->mtex == -1 || icu->adrcode < MA_MAP1 || + icu->adrcode & texchannel_to_adrcode( self->mtex ) ) { + ++i; + + /* if indices match, return the curve */ + if( i == self->iter ) + return IpoCurve_CreatePyObject( icu ); + } + } + + self->iter = 0; /* allow iter use again */ + /* ran out of curves */ + return EXPP_ReturnPyObjError( PyExc_StopIteration, + "iterator at end" ); +} + +/*****************************************************************************/ +/* Function: Ipo_Init */ +/*****************************************************************************/ +PyObject *Ipo_Init( void ) +{ + /* PyObject *submodule; */ + + if( PyType_Ready( &Ipo_Type ) < 0 ) + return NULL; + + submodule = Py_InitModule3( "Blender.Ipo", M_Ipo_methods, M_Ipo_doc ); + generate_curveconsts( submodule ); + + return submodule; +} + +/* + * The following methods should be deprecated when there are equivalent + * methods in Ipocurve (if there aren't already). + */ + +static PyObject *Ipo_getNBezPoints( BPy_Ipo * self, PyObject * args ) +{ + int num = 0; + IpoCurve *icu = NULL; + + if( !PyArg_ParseTuple( args, "i", &num ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument" ); + + icu = self->ipo->curve.first; + while( icu && num > 0 ) { + icu = icu->next; + --num; + } + + if( num < 0 || !icu ) + return EXPP_ReturnPyObjError( PyExc_IndexError, + "index out of range" ); + + return PyInt_FromLong( icu->totvert ); +} + +static PyObject *Ipo_DeleteBezPoints( BPy_Ipo * self, PyObject * args ) +{ + int num = 0, i = 0; + IpoCurve *icu = 0; + if( !PyArg_ParseTuple( args, "i", &num ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "expected int argument" ) ); + icu = self->ipo->curve.first; + if( !icu ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "No IPO curve" ) ); + for( i = 0; i < num; i++ ) { + if( !icu ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "Bad curve number" ) ); + icu = icu->next; + + } + icu->totvert--; + return ( PyInt_FromLong( icu->totvert ) ); +} + +/* + * Ipo_getCurveBP() + * this method is UNSUPPORTED. + * Calling this method throws a TypeError Exception. + * + * it looks like the original intent was to return the first point + * of a BPoint Ipo curve. However, BPoint ipos are not currently + * implemented. + */ + +static PyObject *Ipo_getCurveBP( BPy_Ipo * self_unused, PyObject * args_unused ) +{ + return EXPP_ReturnPyObjError( PyExc_NotImplementedError, + "bpoint ipos are not supported" ); +} + +static PyObject *Ipo_getCurveBeztriple( BPy_Ipo * self, PyObject * args ) +{ + struct BezTriple *ptrbt; + int num = 0, pos, i, j; + IpoCurve *icu; + PyObject *l, *pyfloat; + + if( !PyArg_ParseTuple( args, "ii", &num, &pos ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "expected int argument" ) ); + icu = self->ipo->curve.first; + if( !icu ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "No IPO curve" ) ); + for( i = 0; i < num; i++ ) { + if( !icu ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "Bad ipo number" ) ); + icu = icu->next; + } + if( pos >= icu->totvert ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "Bad bezt number" ); + + ptrbt = icu->bezt + pos; + if( !ptrbt ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "No bez triple" ); + + l = PyList_New( 0 ); + for( i = 0; i < 3; i++ ) { + for( j = 0; j < 3; j++ ) { + pyfloat = PyFloat_FromDouble( ptrbt->vec[i][j] ); + PyList_Append( l, pyfloat ); + Py_DECREF(pyfloat); + } + } + return l; +} + +static PyObject *Ipo_setCurveBeztriple( BPy_Ipo * self, PyObject * args ) +{ + struct BezTriple *ptrbt; + int num = 0, pos, i; + IpoCurve *icu; + PyObject *listargs = 0; + + if( !PyArg_ParseTuple( args, "iiO", &num, &pos, &listargs ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, + "expected int int object argument" ) ); + if( !PyTuple_Check( listargs ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "3rd arg should be a tuple" ) ); + icu = self->ipo->curve.first; + if( !icu ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "No IPO curve" ) ); + for( i = 0; i < num; i++ ) { + if( !icu ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "Bad ipo number" ) ); + icu = icu->next; + } + if( pos >= icu->totvert ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "Bad bezt number" ); + + ptrbt = icu->bezt + pos; + if( !ptrbt ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "No bez triple" ); + + for( i = 0; i < 9; i++ ) { + PyObject *xx = PyTuple_GetItem( listargs, i ); + ptrbt->vec[i / 3][i % 3] = (float)PyFloat_AsDouble( xx ); + } + + Py_INCREF( Py_None ); + return Py_None; +} + +/* Ipo.__copy__ */ +static PyObject *Ipo_copy( BPy_Ipo * self ) +{ + Ipo *ipo = copy_ipo(self->ipo ); + ipo->id.us = 0; + return Ipo_CreatePyObject(ipo); +} + +static PyObject *Ipo_EvaluateCurveOn( BPy_Ipo * self, PyObject * args ) +{ + int num = 0, i; + IpoCurve *icu; + float time = 0; + + if( !PyArg_ParseTuple( args, "if", &num, &time ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "expected int argument" ) ); + + icu = self->ipo->curve.first; + if( !icu ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "No IPO curve" ) ); + + for( i = 0; i < num; i++ ) { + if( !icu ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "Bad ipo number" ) ); + icu = icu->next; + + } + return PyFloat_FromDouble( eval_icu( icu, time ) ); +} + +static PyObject *Ipo_getCurvecurval( BPy_Ipo * self, PyObject * args ) +{ + int numcurve = 0, i; + IpoCurve *icu; + char *stringname = 0, *str1 = 0; + + icu = self->ipo->curve.first; + if( !icu ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "No IPO curve" ) ); + + if( PyNumber_Check( PyTuple_GetItem( args, 0 ) ) ) /* args is an integer */ + { + if( !PyArg_ParseTuple( args, "i", &numcurve ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, + "expected int or string argument" ) ); + for( i = 0; i < numcurve; i++ ) { + if( !icu ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, + "Bad ipo number" ) ); + icu = icu->next; + } + } + + else /* args is a string */ + { + if( !PyArg_ParseTuple( args, "s", &stringname ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, + "expected int or string argument" ) ); + while( icu ) { + str1 = getIpoCurveName( icu ); + if( !strcmp( str1, stringname ) ) + break; + icu = icu->next; + } + } + + if( icu ) + return PyFloat_FromDouble( icu->curval ); + Py_RETURN_NONE; +} + +/* + * The following methods should be deprecated when methods are pruned out. + */ + +static PyObject *Ipo_oldsetRctf( BPy_Ipo * self, PyObject * args ) +{ + return EXPP_setterWrapperTuple( (void *)self, args, + (setter)Ipo_setRctf ); +} + +static PyObject *Ipo_oldsetBlocktype( BPy_Ipo * self, PyObject * args ) +{ + return EXPP_setterWrapperTuple( (void *)self, args, + (setter)Ipo_setBlocktype ); +} diff --git a/source/blender/python/api2_2x/Ipo.h b/source/blender/python/api2_2x/Ipo.h new file mode 100644 index 00000000000..d3bf2fd108b --- /dev/null +++ b/source/blender/python/api2_2x/Ipo.h @@ -0,0 +1,63 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Jacques Guignot + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_IPO_H +#define EXPP_IPO_H + +#include +#include "DNA_ipo_types.h" + +/*****************************************************************************/ +/* Python BPy_Ipo structure definition: */ +/*****************************************************************************/ +typedef struct { + PyObject_HEAD /* required macro */ + Ipo * ipo; /* libdata must be second */ + short iter; + short mtex; +} BPy_Ipo; + +extern PyTypeObject Ipo_Type; + +#define BPy_Ipo_Check(v) ((v)->ob_type == &Ipo_Type) /* for type checking */ + + +/* + * prototypes + */ + +PyObject *Ipo_Init( void ); +PyObject *Ipo_CreatePyObject( struct Ipo *ipo ); +Ipo *Ipo_FromPyObject( PyObject * py_obj ); + + +#endif /* EXPP_IPO_H */ diff --git a/source/blender/python/api2_2x/Ipocurve.c b/source/blender/python/api2_2x/Ipocurve.c new file mode 100644 index 00000000000..b8f3c3f6dd0 --- /dev/null +++ b/source/blender/python/api2_2x/Ipocurve.c @@ -0,0 +1,1080 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Jacques Guignot, Nathan Letwory, Ken Hughes, Johnny Matthews + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "Ipocurve.h" /*This must come first*/ + +#include "Object.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_depsgraph.h" +#include "BKE_ipo.h" +#include "BIF_space.h" +#include "BSE_editipo.h" +#include "MEM_guardedalloc.h" +#include "DNA_ipo_types.h" +#include "DNA_key_types.h" +#include "BezTriple.h" +#include "gen_utils.h" + +/*****************************************************************************/ +/* The following string definitions are used for documentation strings. */ +/* In Python these will be written to the console when doing a */ +/* Blender.IpoCurve.__doc__ */ +/*****************************************************************************/ +char M_IpoCurve_doc[] = ""; +char M_IpoCurve_New_doc[] = ""; +char M_IpoCurve_Get_doc[] = ""; + +/*****************************************************************************/ +/* Python method structure definition for Blender.IpoCurve module: */ +/*****************************************************************************/ + +struct PyMethodDef M_IpoCurve_methods[] = { + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python C_IpoCurve methods declarations: */ +/*****************************************************************************/ +static PyObject *IpoCurve_getName( C_IpoCurve * self ); +static PyObject *IpoCurve_Recalc( C_IpoCurve * self ); +static PyObject *IpoCurve_append( C_IpoCurve * self, PyObject * value ); +static PyObject *IpoCurve_addBezier( C_IpoCurve * self, PyObject * value ); +static PyObject *IpoCurve_delBezier( C_IpoCurve * self, PyObject * args ); +static PyObject *IpoCurve_setInterpolation( C_IpoCurve * self, + PyObject * value ); +static PyObject *IpoCurve_getInterpolation( C_IpoCurve * self ); +static PyObject *IpoCurve_newgetInterp( C_IpoCurve * self ); +static int IpoCurve_newsetInterp( C_IpoCurve * self, PyObject * args ); +static PyObject *IpoCurve_setExtrapolation( C_IpoCurve * self, + PyObject * value ); +static PyObject *IpoCurve_getExtrapolation( C_IpoCurve * self ); +static PyObject *IpoCurve_newgetExtend( C_IpoCurve * self ); +static int IpoCurve_newsetExtend( C_IpoCurve * self, PyObject * args ); +static PyObject *IpoCurve_getPoints( C_IpoCurve * self ); +static PyObject *IpoCurve_evaluate( C_IpoCurve * self, PyObject * args ); +static PyObject *IpoCurve_getDriver( C_IpoCurve * self ); +static int IpoCurve_setDriver( C_IpoCurve * self, PyObject * args ); +static PyObject *IpoCurve_getDriverObject( C_IpoCurve * self); +static int IpoCurve_setDriverObject( C_IpoCurve * self, PyObject * args ); +static PyObject *IpoCurve_getDriverChannel( C_IpoCurve * self); +static int IpoCurve_setDriverChannel( C_IpoCurve * self, PyObject * args ); +static PyObject *IpoCurve_getDriverExpression( C_IpoCurve * self); +static PyObject *IpoCurve_getFlag( C_IpoCurve * self, void *type); +static int IpoCurve_setFlag( C_IpoCurve * self, PyObject *value, void *type); + +static int IpoCurve_setDriverExpression( C_IpoCurve * self, PyObject * args ); +static PyObject *IpoCurve_getCurval( C_IpoCurve * self, PyObject * args ); +static int IpoCurve_setCurval( C_IpoCurve * self, PyObject * key, + PyObject * value ); + +/*****************************************************************************/ +/* Python C_IpoCurve methods table: */ +/*****************************************************************************/ +static PyMethodDef C_IpoCurve_methods[] = { + /* name, method, flags, doc */ + {"getName", ( PyCFunction ) IpoCurve_getName, METH_NOARGS, + "() - Return IpoCurve name"}, + {"Recalc", ( PyCFunction ) IpoCurve_Recalc, METH_NOARGS, + "() - deprecated method. use recalc() instead"}, + {"recalc", ( PyCFunction ) IpoCurve_Recalc, METH_NOARGS, + "() - Recomputes the curve after changes"}, + {"update", ( PyCFunction ) IpoCurve_Recalc, METH_NOARGS, + "() - deprecated method: use recalc method instead."}, + {"append", ( PyCFunction ) IpoCurve_append, METH_O, + "(coordlist) - Adds a Bezier point to a curve"}, + {"addBezier", ( PyCFunction ) IpoCurve_addBezier, METH_O, + "() - deprecated method. use append() instead"}, + {"delBezier", ( PyCFunction ) IpoCurve_delBezier, METH_VARARGS, + "() - deprecated method. use \"del icu[index]\" instead"}, + {"setInterpolation", ( PyCFunction ) IpoCurve_setInterpolation, + METH_O, "(str) - Sets the interpolation type of the curve"}, + {"getInterpolation", ( PyCFunction ) IpoCurve_getInterpolation, + METH_NOARGS, "() - Gets the interpolation type of the curve"}, + {"setExtrapolation", ( PyCFunction ) IpoCurve_setExtrapolation, + METH_O, "(str) - Sets the extend mode of the curve"}, + {"getExtrapolation", ( PyCFunction ) IpoCurve_getExtrapolation, + METH_NOARGS, "() - Gets the extend mode of the curve"}, + {"getPoints", ( PyCFunction ) IpoCurve_getPoints, METH_NOARGS, + "() - Returns list of all bezTriples of the curve"}, + {"evaluate", ( PyCFunction ) IpoCurve_evaluate, METH_VARARGS, + "(float) - Evaluate curve at given time"}, + {NULL, NULL, 0, NULL} +}; + +/* + * IpoCurve methods + */ + +static PyGetSetDef C_IpoCurve_getseters[] = { + {"name", + (getter)IpoCurve_getName, (setter)NULL, + "the IpoCurve name", + NULL}, + {"bezierPoints", + (getter)IpoCurve_getPoints, (setter)NULL, + "list of all bezTriples of the curve", + NULL}, + {"driver", + (getter)IpoCurve_getDriver, (setter)IpoCurve_setDriver, + "The status of the driver 1-object, 2-py expression, 0-off", + NULL}, + {"driverObject", + (getter)IpoCurve_getDriverObject, (setter)IpoCurve_setDriverObject, + "The object used to drive the IpoCurve", + NULL}, + {"driverChannel", + (getter)IpoCurve_getDriverChannel, (setter)IpoCurve_setDriverChannel, + "The channel on the driver object used to drive the IpoCurve", + NULL}, + {"driverExpression", + (getter)IpoCurve_getDriverExpression, (setter)IpoCurve_setDriverExpression, + "The python expression on the driver used to drive the IpoCurve", + NULL}, + {"interpolation", + (getter)IpoCurve_newgetInterp, (setter)IpoCurve_newsetInterp, + "The interpolation mode of the curve", + NULL}, + {"extend", + (getter)IpoCurve_newgetExtend, (setter)IpoCurve_newsetExtend, + "The extend mode of the curve", + NULL}, + + {"sel", + (getter)IpoCurve_getFlag, (setter)IpoCurve_setFlag, + "the selection state of the curve", + (void *)IPO_SELECT}, + + {NULL,NULL,NULL,NULL,NULL} +}; + +/*****************************************************************************/ +/* Python IpoCurve_Type Mapping Methods table: */ +/*****************************************************************************/ + +static PyMappingMethods IpoCurve_as_mapping = { + ( inquiry ) 0, /* mp_length */ + ( binaryfunc ) IpoCurve_getCurval, /* mp_subscript */ + ( objobjargproc ) IpoCurve_setCurval, /* mp_ass_subscript */ +}; + +/*****************************************************************************/ +/* Python IpoCurve_Type callback function prototypes: */ +/*****************************************************************************/ +static int IpoCurve_compare( C_IpoCurve * a, C_IpoCurve * b ); +static PyObject *IpoCurve_repr( C_IpoCurve * self ); + +/*****************************************************************************/ +/* Python IpoCurve_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject IpoCurve_Type = { + PyObject_HEAD_INIT( NULL ) /* required macro */ + 0, /* ob_size */ + "IpoCurve", /* tp_name */ + sizeof( C_IpoCurve ), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + NULL, /* tp_dealloc */ + 0, /* tp_print */ + ( getattrfunc ) NULL, /* tp_getattr */ + ( setattrfunc ) NULL, /* tp_setattr */ + ( cmpfunc ) IpoCurve_compare, /* tp_compare */ + ( reprfunc ) IpoCurve_repr, /* tp_repr */ + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + &IpoCurve_as_mapping, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + C_IpoCurve_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + C_IpoCurve_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +/*****************************************************************************/ +/* local utility functions */ +/*****************************************************************************/ + +/* + * Keys are handled differently than other Ipos, so go through contortions + * to find their names. + */ + +static char *get_key_curvename( IpoCurve *ipocurve ) +{ + Key *key_iter; + char *empty = ""; + + /* search for keys with an Ipo */ + + for( key_iter = G.main->key.first; key_iter; key_iter=key_iter->id.next) { + if( key_iter->ipo ) { + IpoCurve *icu = key_iter->ipo->curve.first; + /* search curves for a match */ + while( icu ) { + if( icu == ipocurve ) { + KeyBlock *block = key_iter->block.first; + /* search for matching adrcode */ + while( block ) { + if( block->adrcode == ipocurve->adrcode ) + return block->name; + block = block->next; + } + } + icu = icu->next; + } + } + } + + /* shouldn't get here unless deleted in UI while BPy object alive */ + return empty; +} + +/* + * internal bpy func to get Ipo Curve Name, used by Ipo.c and + * KX_BlenderSceneConverter.cpp. + * + * We are returning a pointer to string constants so there are + * no issues with who owns pointers. + */ + +char *getIpoCurveName( IpoCurve * icu ) +{ + switch ( icu->blocktype ) { + case ID_MA: + return getname_mat_ei( icu->adrcode ); + case ID_WO: + return getname_world_ei( icu->adrcode ); + case ID_CA: + return getname_cam_ei( icu->adrcode ); + case ID_OB: + return getname_ob_ei( icu->adrcode, 1 ); + /* solve: what if EffX/Y/Z are wanted? */ + case ID_TE: + return getname_tex_ei( icu->adrcode ); + case ID_LA: + return getname_la_ei( icu->adrcode ); + case ID_PO: + return getname_ac_ei( icu->adrcode ); + case ID_CU: + return getname_cu_ei( icu->adrcode ); + case ID_KE: + /* return "Key"; */ + /* ipo curves have no names... that was only meant for drawing the buttons... (ton) */ + return get_key_curvename( icu ); + case ID_SEQ: + return getname_seq_ei( icu->adrcode ); + case ID_CO: + return getname_co_ei( icu->adrcode ); + } + return NULL; +} + +/* + * delete a bezTriple from a curve + */ + +static void del_beztriple( IpoCurve *icu, int index ) +{ + int npoints = icu->totvert - 1; + BezTriple * tmp = icu->bezt; + + /* + * if delete empties list, then delete it, otherwise copy the remaining + * points to a new list + */ + + if( !npoints ) { + icu->bezt = NULL; + } else { + icu->bezt = + MEM_mallocN( sizeof( BezTriple ) * npoints, "bezt" ); + if( index > 0 ) + memmove( icu->bezt, tmp, index * sizeof( BezTriple ) ); + if( index < npoints ) + memmove( icu->bezt + index, tmp + index + 1, + ( npoints - index ) * sizeof( BezTriple ) ); + } + + /* free old list, adjust vertex count */ + MEM_freeN( tmp ); + icu->totvert--; + + /* call calchandles_* instead of testhandles_* */ + /* I'm not sure this is a complete solution but since we do not */ + /* deal with curve handles right now, it seems ok */ + calchandles_ipocurve( icu ); +} + +/*****************************************************************************/ +/* Python C_IpoCurve methods: */ +/*****************************************************************************/ + +static PyObject *IpoCurve_setInterpolation( C_IpoCurve * self, + PyObject * value ) +{ + char *interpolationtype = PyString_AsString(value); + short id; + + if( !interpolationtype ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + + if( !strcmp( interpolationtype, "Bezier" ) ) + id = IPO_BEZ; + else if( !strcmp( interpolationtype, "Constant" ) ) + id = IPO_CONST; + else if( !strcmp( interpolationtype, "Linear" ) ) + id = IPO_LIN; + else + return EXPP_ReturnPyObjError( PyExc_TypeError, + "bad interpolation type" ); + + self->ipocurve->ipo = id; + Py_RETURN_NONE; +} + +static PyObject *IpoCurve_getInterpolation( C_IpoCurve * self ) +{ + char *str = 0; + IpoCurve *icu = self->ipocurve; + + switch( icu->ipo ) { + case IPO_BEZ: + str = "Bezier"; + break; + case IPO_CONST: + str = "Constant"; + break; + case IPO_LIN: + str = "Linear"; + break; + default: + return EXPP_ReturnPyObjError( PyExc_TypeError, + "unknown interpolation type" ); + } + + return PyString_FromString( str ); +} + +static PyObject * IpoCurve_setExtrapolation( C_IpoCurve * self, + PyObject * value ) +{ + char *extrapolationtype = PyString_AsString(value); + short id; + + if( !extrapolationtype ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + + if( !strcmp( extrapolationtype, "Constant" ) ) + id = 0; + else if( !strcmp( extrapolationtype, "Extrapolation" ) ) + id = 1; + else if( !strcmp( extrapolationtype, "Cyclic" ) ) + id = 2; + else if( !strcmp( extrapolationtype, "Cyclic_extrapolation" ) ) + id = 3; + else + return EXPP_ReturnPyObjError( PyExc_TypeError, + "bad interpolation type" ); + + self->ipocurve->extrap = id; + Py_RETURN_NONE; +} + +static PyObject *IpoCurve_getExtrapolation( C_IpoCurve * self ) +{ + char *str; + IpoCurve *icu = self->ipocurve; + + switch( icu->extrap ) { + case 0: + str = "Constant"; + break; + case 1: + str = "Extrapolation"; + break; + case 2: + str = "Cyclic"; + break; + case 3: + str = "Cyclic_extrapolation"; + break; + default: + return EXPP_ReturnPyObjError( PyExc_TypeError, + "bad extrapolation type" ); + } + + return PyString_FromString( str ); +} + +/* + * append a new BezTriple to curve + */ + +static PyObject *IpoCurve_append( C_IpoCurve * self, PyObject * value ) +{ + float x, y; + IpoCurve *icu = self->ipocurve; + + /* if args is a already a beztriple, tack onto end of list */ + if( BPy_BezTriple_Check ( value ) ) { + BPy_BezTriple *bobj = (BPy_BezTriple *)value; + + BezTriple *newb = MEM_callocN( (icu->totvert+1)*sizeof(BezTriple), + "BPyBeztriple" ); + if( icu->bezt ) { + memcpy( newb, icu->bezt, ( icu->totvert )*sizeof( BezTriple ) ); + MEM_freeN( icu->bezt ); + } + icu->bezt = newb; + memcpy( &icu->bezt[icu->totvert], bobj->beztriple, + sizeof( BezTriple ) ); + icu->totvert++; + calchandles_ipocurve( icu ); + + /* otherwise try to get two floats and add to list */ + } else { + PyObject *xobj, *yobj; + xobj = PyNumber_Float( PyTuple_GetItem( value, 0 ) ); + yobj = PyNumber_Float( PyTuple_GetItem( value, 1 ) ); + + if( !xobj || !yobj ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected tuple of floats" ); + + x = (float)PyFloat_AsDouble( xobj ); + Py_DECREF( xobj ); + y = (float)PyFloat_AsDouble( yobj ); + Py_DECREF( yobj ); + insert_vert_icu( icu, x, y, 0); + } + + Py_RETURN_NONE; +} + +/* + Function: IpoCurve_delBezier + Bpy: Blender.Ipocurve.delBezier(0) + + Delete an BezTriple from an IPO curve. + example: + ipo = Blender.Ipo.Get('ObIpo') + cu = ipo.getCurve('LocX') + cu.delBezier(0) +*/ + +static PyObject *IpoCurve_delBezier( C_IpoCurve * self, PyObject * args ) +{ + int index; + + if( !PyArg_ParseTuple( args, "i", &index ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument" ); + + /* if index is negative, count from end of list */ + if( index < 0 ) + index += self->ipocurve->totvert; + /* check range of index */ + if( index < 0 || index > self->ipocurve->totvert - 1 ) + return EXPP_ReturnPyObjError( PyExc_IndexError, + "index outside of list" ); + + del_beztriple( self->ipocurve, index ); + + Py_RETURN_NONE; +} + +static PyObject *IpoCurve_Recalc( C_IpoCurve * self ) +{ + IpoCurve *icu = self->ipocurve; + + /* testhandles_ipocurve (icu); */ + /* call calchandles_* instead of testhandles_* */ + /* I'm not sure this is a complete solution but since we do not */ + /* deal with curve handles right now, it seems ok */ + calchandles_ipocurve( icu ); + sort_time_ipocurve( icu ); + + Py_INCREF( Py_None ); + return Py_None; +} + +static PyObject *IpoCurve_getName( C_IpoCurve * self ) +{ + switch ( self->ipocurve->blocktype ) { + case ID_OB: + return PyString_FromString( getname_ob_ei( self->ipocurve->adrcode, 1 ) ); /* solve: what if EffX/Y/Z are wanted? */ + case ID_TE: + return PyString_FromString( getname_tex_ei + ( self->ipocurve->adrcode ) ); + case ID_LA: + return PyString_FromString( getname_la_ei + ( self->ipocurve->adrcode ) ); + case ID_MA: + return PyString_FromString( getname_mat_ei + ( self->ipocurve->adrcode ) ); + case ID_CA: + return PyString_FromString( getname_cam_ei + ( self->ipocurve->adrcode ) ); + case ID_WO: + return PyString_FromString( getname_world_ei + ( self->ipocurve->adrcode ) ); + case ID_PO: + return PyString_FromString( getname_ac_ei + ( self->ipocurve->adrcode ) ); + case ID_CU: + return PyString_FromString( getname_cu_ei + ( self->ipocurve->adrcode ) ); + case ID_KE: + return PyString_FromString( get_key_curvename( self->ipocurve ) ); + case ID_SEQ: + return PyString_FromString( getname_seq_ei + ( self->ipocurve->adrcode ) ); + case ID_CO: + return PyString_FromString( getname_co_ei + ( self->ipocurve->adrcode ) ); + default: + return EXPP_ReturnPyObjError( PyExc_TypeError, + "This function doesn't support this ipocurve type yet" ); + } +} + +static PyObject *IpoCurve_getPoints( C_IpoCurve * self ) +{ + BezTriple *bezt; + PyObject *po; + int i; + PyObject *list = PyList_New( self->ipocurve->totvert ); + + if( !list ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "PyList_New() failed" ); + + for( bezt = self->ipocurve->bezt, i = 0; + i < self->ipocurve->totvert; i++, bezt++ ) { + po = BezTriple_CreatePyObject( bezt ); + if( !po ) { + Py_DECREF( list ); + return NULL; /* This is okay since the error is alredy set */ + } + PyList_SET_ITEM( list, i, po ); + } + return list; +} + +/*****************************************************************************/ +/* Function: IpoCurve_compare */ +/* Description: This compares 2 python types, == or != only. */ +/*****************************************************************************/ +static int IpoCurve_compare( C_IpoCurve * a, C_IpoCurve * b ) +{ + return ( a->ipocurve == b->ipocurve ) ? 0 : -1; +} + +/*****************************************************************************/ +/* Function: IpoCurve_repr */ +/* Description: This is a callback function for the C_IpoCurve type. It */ +/* builds a meaningful string to represent ipocurve objects. */ +/*****************************************************************************/ +static PyObject *IpoCurve_repr( C_IpoCurve * self ) +{ + return PyString_FromFormat( "[IpoCurve \"%s\"]", + getIpoCurveName( self->ipocurve ) ); +} + +/* Three Python IpoCurve_Type helper functions needed by the Object module: */ + +/*****************************************************************************/ +/* Function: IpoCurve_CreatePyObject */ +/* Description: This function will create a new C_IpoCurve from an existing */ +/* Blender ipo structure. */ +/*****************************************************************************/ +PyObject *IpoCurve_CreatePyObject( IpoCurve * icu ) +{ + C_IpoCurve *pyipo; + + pyipo = ( C_IpoCurve * ) PyObject_NEW( C_IpoCurve, &IpoCurve_Type ); + + if( !pyipo ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create C_IpoCurve object" ); + + pyipo->ipocurve = icu; + + return ( PyObject * ) pyipo; +} + +/*****************************************************************************/ +/* Function: IpoCurve_FromPyObject */ +/* Description: This function returns the Blender ipo from the given */ +/* PyObject. */ +/*****************************************************************************/ +IpoCurve *IpoCurve_FromPyObject( PyObject * pyobj ) +{ + return ( ( C_IpoCurve * ) pyobj )->ipocurve; +} + +/* + * get the value of an Ipocurve at a particular time + */ + +static PyObject *IpoCurve_getCurval( C_IpoCurve * self, PyObject * args ) +{ + float time; + PyObject *pyfloat = PyNumber_Float( args ); + + if( !pyfloat ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected float argument" ); + time = ( float )PyFloat_AS_DOUBLE( pyfloat ); + Py_DECREF( pyfloat ); + + return PyFloat_FromDouble( ( double ) eval_icu( self->ipocurve, time ) ); +} + +/* + * set the value of an Ipocurve at a particular time + */ + +static int IpoCurve_setCurval( C_IpoCurve * self, PyObject * key, + PyObject * value ) +{ + float time, curval; + PyObject *pyfloat; + + /* make sure time, curval are both floats */ + + pyfloat = PyNumber_Float( key ); + if( !pyfloat ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected float key" ); + time = ( float )PyFloat_AS_DOUBLE( pyfloat ); + Py_DECREF( pyfloat ); + + pyfloat = PyNumber_Float( value ); + if( !pyfloat ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected float argument" ); + curval = ( float )PyFloat_AS_DOUBLE( pyfloat ); + Py_DECREF( pyfloat ); + + /* insert a key at the specified time */ + + insert_vert_icu( self->ipocurve, time, curval, 0); + allspace(REMAKEIPO, 0); + return 0; +} + +/***************************************************************************/ +/* Function: IpoCurve_evaluate( time ) */ +/* Description: Evaluates IPO curve at the given time. */ +/***************************************************************************/ + +static PyObject *IpoCurve_evaluate( C_IpoCurve * self, PyObject * args ) +{ + float time = 0; + double eval = 0; + + /* expecting float */ + if( !PyArg_ParseTuple( args, "f", &time ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "expected float argument" ) ); + + eval = ( double ) eval_icu( self->ipocurve, time ); + + return PyFloat_FromDouble( eval ); + +} + +static PyObject *IpoCurve_getDriver( C_IpoCurve * self ) +{ + if( !self->ipocurve->driver ) + return PyInt_FromLong( 0 ); + else { + if (self->ipocurve->driver->type == IPO_DRIVER_TYPE_NORMAL) + return PyInt_FromLong( 1 ); + if (self->ipocurve->driver->type == IPO_DRIVER_TYPE_PYTHON) + return PyInt_FromLong( 2 ); + } + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "unknown driver type, internal error" ); + +} + +/* + sets the driver to + 0: disabled + 1: enabled (object) + 2: enabled (python expression) +*/ +static int IpoCurve_setDriver( C_IpoCurve * self, PyObject * args ) +{ + IpoCurve *ipo = self->ipocurve; + int type; + if( !PyInt_Check( args ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected int argument 0 or 1 " ); + + type = PyInt_AS_LONG( args ); + + if (type < 0 || type > 2) + return EXPP_ReturnIntError( PyExc_ValueError, + "expected int argument 0, 1 or 2" ); + + if (type==0) { /* disable driver */ + if( ipo->driver ) { + MEM_freeN( ipo->driver ); + ipo->driver = NULL; + } + } else { + if( !ipo->driver ) { /*add driver if its not there */ + ipo->driver = MEM_callocN( sizeof(IpoDriver), "ipo driver" ); + ipo->driver->blocktype = ID_OB; + ipo->driver->adrcode = OB_LOC_X; + } + + if (type==1 && ipo->driver->type != IPO_DRIVER_TYPE_NORMAL) { + ipo->driver->type = IPO_DRIVER_TYPE_NORMAL; + ipo->driver->ob = NULL; + ipo->driver->flag &= ~IPO_DRIVER_FLAG_INVALID; + + } else if (type==2 && ipo->driver->type != IPO_DRIVER_TYPE_PYTHON) { + ipo->driver->type = IPO_DRIVER_TYPE_PYTHON; + /* we should probably set ipo->driver->ob, but theres no way to do it properly */ + ipo->driver->ob = NULL; + } + } + + return 0; +} + +static PyObject *IpoCurve_getDriverObject( C_IpoCurve * self ) +{ + IpoCurve *ipo = self->ipocurve; + + if( ipo->driver ) + return Object_CreatePyObject( ipo->driver->ob ); + + Py_RETURN_NONE; +} + +static int IpoCurve_setDriverObject( C_IpoCurve * self, PyObject * arg ) +{ + IpoCurve *ipo = self->ipocurve; + + if( !ipo->driver ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "This IpoCurve does not have an active driver" ); + + if(!BPy_Object_Check(arg) ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "expected an object argument" ); + ipo->driver->ob = ((BPy_Object *)arg)->object; + + DAG_scene_sort(G.scene); + + return 0; +} + +static PyObject *IpoCurve_getDriverChannel( C_IpoCurve * self ) +{ + if( !self->ipocurve->driver ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This IpoCurve does not have an active driver" ); + + return PyInt_FromLong( self->ipocurve->driver->adrcode ); +} + +static int IpoCurve_setDriverChannel( C_IpoCurve * self, PyObject * args ) +{ + IpoCurve *ipo = self->ipocurve; + short param; + + if( !ipo->driver ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "This IpoCurve does not have an active driver" ); + + if( !PyInt_Check( args ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected int argument" ); + + param = (short)PyInt_AS_LONG ( args ); + if( ( param >= OB_LOC_X && param <= OB_LOC_Z ) + || ( param >= OB_ROT_X && param <= OB_ROT_Z ) + || ( param >= OB_SIZE_X && param <= OB_SIZE_Z ) ) { + ipo->driver->adrcode = (short)PyInt_AS_LONG ( args ); + return 0; + } + + return EXPP_ReturnIntError( PyExc_ValueError, "invalid int argument" ); +} + +static PyObject *IpoCurve_getDriverExpression( C_IpoCurve * self ) +{ + IpoCurve *ipo = self->ipocurve; + + if( ipo->driver && ipo->driver->type == IPO_DRIVER_TYPE_PYTHON ) + return PyString_FromString( ipo->driver->name ); + + Py_RETURN_NONE; +} + +static int IpoCurve_setDriverExpression( C_IpoCurve * self, PyObject * arg ) +{ + IpoCurve *ipo = self->ipocurve; + char *exp; /* python expression */ + + if( !ipo->driver ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "This IpoCurve does not have an active driver" ); + + if (ipo->driver->type != IPO_DRIVER_TYPE_PYTHON) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "This IpoCurve is not a python expression set the driver attribute to 2" ); + + if(!PyString_Check(arg) ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "expected a string argument" ); + + exp = PyString_AsString(arg); + if (strlen(exp)>127) + return EXPP_ReturnIntError( PyExc_ValueError, + "string is too long, use 127 characters or less" ); + + strcpy(ipo->driver->name, exp); + return 0; +} + +static PyObject *M_IpoCurve_ExtendDict( void ) +{ + PyObject *EM = PyConstant_New( ); + + if( EM ) { + BPy_constant *d = ( BPy_constant * ) EM; + + PyConstant_Insert( d, "CONST", PyInt_FromLong( IPO_HORIZ ) ); + PyConstant_Insert( d, "EXTRAP", PyInt_FromLong( IPO_DIR ) ); + PyConstant_Insert( d, "CYCLIC", PyInt_FromLong( IPO_CYCL ) ); + PyConstant_Insert( d, "CYCLIC_EXTRAP", PyInt_FromLong( IPO_CYCLX ) ); + } + return EM; +} + +static PyObject *M_IpoCurve_InterpDict( void ) +{ + PyObject *IM = PyConstant_New( ); + + if( IM ) { + BPy_constant *d = ( BPy_constant * ) IM; + + PyConstant_Insert( d, "CONST", PyInt_FromLong( IPO_CONST ) ); + PyConstant_Insert( d, "LINEAR", PyInt_FromLong( IPO_LIN ) ); + PyConstant_Insert( d, "BEZIER", PyInt_FromLong( IPO_BEZ ) ); + } + return IM; +} + +/*****************************************************************************/ +/* Function: IpoCurve_Init */ +/*****************************************************************************/ +PyObject *IpoCurve_Init( void ) +{ + PyObject *submodule; + PyObject *ExtendTypes = M_IpoCurve_ExtendDict( ); + PyObject *InterpTypes = M_IpoCurve_InterpDict( ); + + if( PyType_Ready( &IpoCurve_Type ) < 0) + return NULL; + + submodule = + Py_InitModule3( "Blender.IpoCurve", M_IpoCurve_methods, + M_IpoCurve_doc ); + + PyModule_AddIntConstant( submodule, "LOC_X", OB_LOC_X ); + PyModule_AddIntConstant( submodule, "LOC_Y", OB_LOC_Y ); + PyModule_AddIntConstant( submodule, "LOC_Z", OB_LOC_Z ); + PyModule_AddIntConstant( submodule, "ROT_X", OB_ROT_X ); + PyModule_AddIntConstant( submodule, "ROT_Y", OB_ROT_Y ); + PyModule_AddIntConstant( submodule, "ROT_Z", OB_ROT_Z ); + PyModule_AddIntConstant( submodule, "SIZE_X", OB_SIZE_X ); + PyModule_AddIntConstant( submodule, "SIZE_Y", OB_SIZE_Y ); + PyModule_AddIntConstant( submodule, "SIZE_Z", OB_SIZE_Z ); + + if( ExtendTypes ) + PyModule_AddObject( submodule, "ExtendTypes", ExtendTypes ); + if( InterpTypes ) + PyModule_AddObject( submodule, "InterpTypes", InterpTypes ); + + return submodule; +} + +/* + */ + +static PyObject *IpoCurve_newgetInterp( C_IpoCurve * self ) +{ + return PyInt_FromLong( self->ipocurve->ipo ); +} + +static int IpoCurve_newsetInterp( C_IpoCurve * self, PyObject * value ) +{ + return EXPP_setIValueRange( value, &self->ipocurve->ipo, + IPO_CONST, IPO_BEZ, 'h' ); +} + +static PyObject *IpoCurve_newgetExtend( C_IpoCurve * self ) +{ + return PyInt_FromLong( self->ipocurve->extrap ); +} + +static int IpoCurve_newsetExtend( C_IpoCurve * self, PyObject * value ) +{ + return EXPP_setIValueRange( value, &self->ipocurve->extrap, + IPO_HORIZ, IPO_CYCLX, 'h' ); +} + +static PyObject *IpoCurve_getFlag( C_IpoCurve * self, void *type ) +{ + if (self->ipocurve->flag & (int)type) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +static int IpoCurve_setFlag( C_IpoCurve * self, PyObject *value, void *type ) +{ + int param = PyObject_IsTrue( value ); + if( param == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected True/False or 0/1" ); + + if (param) + self->ipocurve->flag |= (int)type; + else + self->ipocurve->flag &= ~(int)type; + + return 0; +} + + +/* #####DEPRECATED###### */ + +static PyObject *IpoCurve_addBezier( C_IpoCurve * self, PyObject * value ) +{ + float x, y; + int npoints; + IpoCurve *icu; + BezTriple *bzt, *tmp; + static char name[10] = "mlml"; + if( !PyArg_ParseTuple( value, "ff", &x, &y ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "expected a tuple of 2 floats" ) ); + + icu = self->ipocurve; + npoints = icu->totvert; + tmp = icu->bezt; + icu->bezt = MEM_mallocN( sizeof( BezTriple ) * ( npoints + 1 ), name ); + if( tmp ) { + memmove( icu->bezt, tmp, sizeof( BezTriple ) * npoints ); + MEM_freeN( tmp ); + } + memmove( icu->bezt + npoints, icu->bezt, sizeof( BezTriple ) ); + icu->totvert++; + bzt = icu->bezt + npoints; + bzt->vec[0][0] = x - 1; + bzt->vec[1][0] = x; + bzt->vec[2][0] = x + 1; + bzt->vec[0][1] = y - 1; + bzt->vec[1][1] = y; + bzt->vec[2][1] = y + 1; + /* set handle type to Auto */ + bzt->h1 = HD_AUTO; + bzt->h2 = HD_AUTO; + + Py_RETURN_NONE; +} diff --git a/source/blender/python/api2_2x/Ipocurve.h b/source/blender/python/api2_2x/Ipocurve.h new file mode 100644 index 00000000000..0844e11b04b --- /dev/null +++ b/source/blender/python/api2_2x/Ipocurve.h @@ -0,0 +1,58 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Jacques Guignot + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_IPOCURVE_H +#define EXPP_IPOCURVE_H + +#include +#include "DNA_curve_types.h" /* declaration of IpoCurve */ + +/*****************************************************************************/ +/* Python C_IpoCurve structure definition: */ +/*****************************************************************************/ +typedef struct { + PyObject_HEAD /* required macro */ + IpoCurve * ipocurve; + char wrapped; +} C_IpoCurve; + +extern PyTypeObject IpoCurve_Type; + +#define BPy_IpoCurve_Check(v) ((v)->ob_type == &IpoCurve_Type) /* for type checking */ + +PyObject *IpoCurve_Init( void ); +PyObject *IpoCurve_CreatePyObject( IpoCurve * ipo ); +IpoCurve *IpoCurve_FromPyObject( PyObject * pyobj ); +char *getIpoCurveName( IpoCurve * icu ); + + +#endif /* EXPP_IPOCURVE_H */ diff --git a/source/blender/python/api2_2x/Key.c b/source/blender/python/api2_2x/Key.c new file mode 100644 index 00000000000..88facd80b4e --- /dev/null +++ b/source/blender/python/api2_2x/Key.c @@ -0,0 +1,683 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Pontus Lidman, Johnny Matthews, Ken Hughes, + * Michael Reimpell + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "Key.h" /*This must come first*/ +#include "vector.h" + +#include "DNA_scene_types.h" + +#include +#include +#include +#include +#include +#include "BIF_space.h" + +#include "Ipocurve.h" +#include "NMesh.h" /* we create NMesh.NMVert objects */ +#include "Ipo.h" +#include "BezTriple.h" + +#include "BSE_editipo.h" +#include "mydevice.h" +#include "BKE_depsgraph.h" +#include "blendef.h" +#include "constant.h" +#include "gen_utils.h" +#include "gen_library.h" + +#define KEY_TYPE_MESH 0 +#define KEY_TYPE_CURVE 1 +#define KEY_TYPE_LATTICE 2 + +/* macro from blenkernel/intern/key.c:98 */ +#define GS(a) (*((short *)(a))) + +static int Key_compare( BPy_Key * a, BPy_Key * b ); +static PyObject *Key_repr( BPy_Key * self ); +static void Key_dealloc( BPy_Key * self ); + +static PyObject *Key_getBlocks( BPy_Key * self ); +static PyObject *Key_getType( BPy_Key * self ); +static PyObject *Key_getRelative( BPy_Key * self ); +static PyObject *Key_getIpo( BPy_Key * self ); +static int Key_setIpo( BPy_Key * self, PyObject * args ); +static PyObject *Key_getValue( BPy_Key * self ); +static int Key_setRelative( BPy_Key * self, PyObject * value ); + +static struct PyMethodDef Key_methods[] = { + { "getBlocks", (PyCFunction) Key_getBlocks, METH_NOARGS, "Get key blocks" }, + { "getIpo", (PyCFunction) Key_getIpo, METH_NOARGS, "Get key Ipo" }, + { 0, 0, 0, 0 } +}; + +static PyGetSetDef BPy_Key_getsetters[] = { + {"type",(getter)Key_getType, (setter)NULL, + "Key Type",NULL}, + {"value",(getter)Key_getValue, (setter)NULL, + "Key value",NULL}, + {"ipo",(getter)Key_getIpo, (setter)Key_setIpo, + "Ipo linked to key",NULL}, + {"blocks",(getter)Key_getBlocks, (setter)NULL, + "Blocks linked to the key",NULL}, + {"relative",(getter)Key_getRelative, (setter)Key_setRelative, + "Non-zero is key is relative",NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +static PyObject *KeyBlock_getData( PyObject * self ); +static PyObject *KeyBlock_getCurval( BPy_KeyBlock * self ); +static PyObject *KeyBlock_getName( BPy_KeyBlock * self ); +static PyObject *KeyBlock_getPos( BPy_KeyBlock * self ); +static PyObject *KeyBlock_getSlidermin( BPy_KeyBlock * self ); +static PyObject *KeyBlock_getSlidermax( BPy_KeyBlock * self ); +static PyObject *KeyBlock_getVgroup( BPy_KeyBlock * self ); + +static int KeyBlock_setName( BPy_KeyBlock *, PyObject * args ); +static int KeyBlock_setVgroup( BPy_KeyBlock *, PyObject * args ); +static int KeyBlock_setSlidermin( BPy_KeyBlock *, PyObject * args ); +static int KeyBlock_setSlidermax( BPy_KeyBlock *, PyObject * args ); + +static void KeyBlock_dealloc( BPy_KeyBlock * self ); +static int KeyBlock_compare( BPy_KeyBlock * a, BPy_KeyBlock * b ); +static PyObject *KeyBlock_repr( BPy_KeyBlock * self ); + +static struct PyMethodDef KeyBlock_methods[] = { + { "getData", (PyCFunction) KeyBlock_getData, METH_NOARGS, + "Get keyblock data" }, + { 0, 0, 0, 0 } +}; + +static PyGetSetDef BPy_KeyBlock_getsetters[] = { + {"curval",(getter)KeyBlock_getCurval, (setter)NULL, + "Current value of the corresponding IpoCurve",NULL}, + {"name",(getter)KeyBlock_getName, (setter)KeyBlock_setName, + "Keyblock Name",NULL}, + {"pos",(getter)KeyBlock_getPos, (setter)NULL, + "Keyblock Pos",NULL}, + {"slidermin",(getter)KeyBlock_getSlidermin, (setter)KeyBlock_setSlidermin, + "Keyblock Slider Minimum",NULL}, + {"slidermax",(getter)KeyBlock_getSlidermax, (setter)KeyBlock_setSlidermax, + "Keyblock Slider Maximum",NULL}, + {"vgroup",(getter)KeyBlock_getVgroup, (setter)KeyBlock_setVgroup, + "Keyblock VGroup",NULL}, + {"data",(getter)KeyBlock_getData, (setter)NULL, + "Keyblock VGroup",NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +PyTypeObject Key_Type = { + PyObject_HEAD_INIT( NULL ) 0, /*ob_size */ + "Blender Key", /*tp_name */ + sizeof( BPy_Key ), /*tp_basicsize */ + 0, /*tp_itemsize */ + /* methods */ + ( destructor ) Key_dealloc,/* destructor tp_dealloc; */ + ( printfunc ) 0, /*tp_print */ + ( getattrfunc ) 0, /*tp_getattr */ + ( setattrfunc ) 0, /*tp_setattr */ + ( cmpfunc) Key_compare, /*tp_compare*/ + ( reprfunc ) Key_repr, /* tp_repr */ + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + Key_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_Key_getsetters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +PyTypeObject KeyBlock_Type = { + PyObject_HEAD_INIT( NULL ) 0, /*ob_size */ + "Blender KeyBlock", /*tp_name */ + sizeof( BPy_KeyBlock ), /*tp_basicsize */ + 0, /*tp_itemsize */ + /* methods */ + ( destructor ) KeyBlock_dealloc,/* destructor tp_dealloc; */ + ( printfunc ) 0, /*tp_print */ + ( getattrfunc ) 0, /*tp_getattr */ + ( setattrfunc ) 0, /*tp_setattr */ + ( cmpfunc) KeyBlock_compare, /*tp_compare*/ + ( reprfunc ) KeyBlock_repr, /* tp_repr */ + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + KeyBlock_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_KeyBlock_getsetters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +PyObject *Key_CreatePyObject( Key * blenkey ) +{ + BPy_Key *bpykey = PyObject_NEW( BPy_Key, &Key_Type ); + /* blenkey may be NULL so be careful */ + bpykey->key = blenkey; + return ( PyObject * ) bpykey; +} + +static void Key_dealloc( BPy_Key * self ) +{ + PyObject_DEL( self ); +} + +static int Key_compare( BPy_Key * a, BPy_Key * b ) +{ + return ( a->key == b->key ) ? 0 : -1; +} + +static PyObject *Key_repr( BPy_Key * self ) +{ + return PyString_FromFormat( "[Key \"%s\"]", self->key->id.name + 2 ); +} + +static PyObject *Key_getIpo( BPy_Key * self ) +{ + if (self->key->ipo) + return Ipo_CreatePyObject( self->key->ipo ); + Py_RETURN_NONE; +} + +static int Key_setIpo( BPy_Key * self, PyObject * value ) +{ + return GenericLib_assignData(value, (void **) &self->key->ipo, 0, 1, ID_IP, ID_KE); +} + +static PyObject *Key_getRelative( BPy_Key * self ) +{ + if( self->key->type == KEY_RELATIVE ) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +static int Key_setRelative( BPy_Key * self, PyObject * value ) +{ + int param = PyObject_IsTrue( value ); + if( param == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected True/False or 0/1" ); + + if( param ) + self->key->type = KEY_RELATIVE; + else + self->key->type = KEY_NORMAL; + allqueue(REDRAWIPO, 0); + allspace(REMAKEIPO, 0); + + return 0; +} + +static PyObject *Key_getType( BPy_Key * self ) +{ + int idcode; + int type = -1; + + idcode = GS( self->key->from->name ); + + switch( idcode ) { + case ID_ME: + type = KEY_TYPE_MESH; + break; + case ID_CU: + type = KEY_TYPE_CURVE; + break; + case ID_LT: + type = KEY_TYPE_LATTICE; + break; + } + + return PyInt_FromLong( type ); +} + +static PyObject *Key_getBlocks( BPy_Key * self ) +{ + Key *key = self->key; + KeyBlock *kb; + int i=0; + PyObject *l = PyList_New( BLI_countlist( &(key->block)) ); + + for (kb = key->block.first; kb; kb = kb->next, i++) + PyList_SET_ITEM( l, i, KeyBlock_CreatePyObject( kb, key ) ); + + return l; +} + +static PyObject *Key_getValue( BPy_Key * self ) +{ + BPy_Key *k = ( BPy_Key * ) self; + + return PyFloat_FromDouble( k->key->curval ); +} + +/* ------------ Key Block Functions -------------- */ +PyObject *KeyBlock_CreatePyObject( KeyBlock * keyblock, Key *parentKey ) +{ + BPy_KeyBlock *bpykb = PyObject_NEW( BPy_KeyBlock, &KeyBlock_Type ); + bpykb->key = parentKey; + bpykb->keyblock = keyblock; /* keyblock maye be NULL, thats ok */ + return ( PyObject * ) bpykb; +} + +static PyObject *KeyBlock_getCurval( BPy_KeyBlock * self ) { + return PyFloat_FromDouble( self->keyblock->curval ); +} + +static PyObject *KeyBlock_getName( BPy_KeyBlock * self ) { + return PyString_FromString(self->keyblock->name); +} + +static PyObject *KeyBlock_getPos( BPy_KeyBlock * self ){ + return PyFloat_FromDouble( self->keyblock->pos ); +} + +static PyObject *KeyBlock_getSlidermin( BPy_KeyBlock * self ){ + return PyFloat_FromDouble( self->keyblock->slidermin ); +} + +static PyObject *KeyBlock_getSlidermax( BPy_KeyBlock * self ){ + return PyFloat_FromDouble( self->keyblock->slidermax ); +} + +static PyObject *KeyBlock_getVgroup( BPy_KeyBlock * self ){ + return PyString_FromString(self->keyblock->vgroup); +} + +static int KeyBlock_setName( BPy_KeyBlock * self, PyObject * args ){ + char* text = NULL; + + text = PyString_AsString ( args ); + if( !text ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected string argument" ); + strncpy( self->keyblock->name, text , 32); + + return 0; +} + +static int KeyBlock_setVgroup( BPy_KeyBlock * self, PyObject * args ){ + char* text = NULL; + + text = PyString_AsString ( args ); + if( !text ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected string argument" ); + strncpy( self->keyblock->vgroup, text , 32); + + return 0; +} +static int KeyBlock_setSlidermin( BPy_KeyBlock * self, PyObject * args ){ + return EXPP_setFloatClamped ( args, &self->keyblock->slidermin, + -10.0f, + 10.0f ); +} +static int KeyBlock_setSlidermax( BPy_KeyBlock * self, PyObject * args ){ + return EXPP_setFloatClamped ( args, &self->keyblock->slidermax, + -10.0f, + 10.0f ); +} + +static void KeyBlock_dealloc( BPy_KeyBlock * self ) +{ + PyObject_DEL( self ); +} + +static int KeyBlock_compare( BPy_KeyBlock * a, BPy_KeyBlock * b ) +{ + return ( a->keyblock == b->keyblock ) ? 0 : -1; +} + +static PyObject *KeyBlock_repr( BPy_KeyBlock * self ) +{ + return PyString_FromFormat( "[KeyBlock \"%s\"]", self->keyblock->name ); +} + + +static Curve *find_curve( Key *key ) +{ + Curve *cu; + + if( !key ) + return NULL; + + for( cu = G.main->curve.first; cu; cu = cu->id.next ) { + if( cu->key == key ) + break; + } + return cu; +} + +static PyObject *KeyBlock_getData( PyObject * self ) +{ + /* If this is a mesh key, data is an array of MVert coords. + If lattice, data is an array of BPoint coords + If curve, data is an array of BezTriple or BPoint */ + + char *datap; + int datasize; + int idcode; + int i; + Curve *cu; + Nurb* nu; + PyObject *l; + BPy_KeyBlock *kb = ( BPy_KeyBlock * ) self; + Key *key = kb->key; + + if( !kb->keyblock->data ) { + Py_RETURN_NONE; + } + + l = PyList_New( kb->keyblock->totelem ); + if( !l ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "PyList_New() failed" ); + + idcode = GS( key->from->name ); + + switch(idcode) { + case ID_ME: + + for (i=0, datap = kb->keyblock->data; ikeyblock->totelem; i++) { + PyObject *vec = newVectorObject((float*)datap, 3, Py_WRAP); + + if (!vec) return EXPP_ReturnPyObjError( PyExc_MemoryError, + "could not allocate memory for Blender.Mathutils.Vector wrapper!" ); + + PyList_SetItem(l, i, vec); + datap += kb->key->elemsize; + } + break; + + case ID_CU: + cu = find_curve ( key ); + if( !cu ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "key is no linked to any curve!" ); + datasize = count_curveverts(&cu->nurb); + nu = cu->nurb.first; + if( nu->bezt ) { + datasize /= 3; + Py_DECREF (l); + l = PyList_New( datasize ); + for( i = 0, datap = kb->keyblock->data; i < datasize; + i++, datap += sizeof(float)*3*4) { + PyObject *tuple = PyTuple_New(4), *vec; + float *vecs = (float*)datap; + + if (!tuple) return EXPP_ReturnPyObjError( PyExc_MemoryError, + "PyTuple_New() failed!" ); + + vec = newVectorObject(vecs, 3, Py_WRAP); + if (!vec) return EXPP_ReturnPyObjError( PyExc_MemoryError, + "Could not allocate memory for Blender.Mathutils.Vector wrapper!" ); + + PyTuple_SET_ITEM( tuple, 0, vec); + + vecs += 3; + vec = newVectorObject(vecs, 3, Py_WRAP); + if (!vec) return EXPP_ReturnPyObjError( PyExc_MemoryError, + "Could not allocate memory for Blender.Mathutils.Vector wrapper!" ); + + PyTuple_SET_ITEM( tuple, 1, vec); + + vecs += 3; + vec = newVectorObject(vecs, 3, Py_WRAP); + if (!vec) return EXPP_ReturnPyObjError( PyExc_MemoryError, + "Could not allocate memory for Blender.Mathutils.Vector wrapper!" ); + + PyTuple_SET_ITEM( tuple, 2, vec); + + /*tilts*/ + vecs += 3; + vec = newVectorObject(vecs, 3, Py_WRAP); + if (!vec) return EXPP_ReturnPyObjError( PyExc_MemoryError, + "Could not allocate memory for Blender.Mathutils.Vector wrapper!" ); + + PyTuple_SET_ITEM( tuple, 3, vec); + + PyList_SetItem( l, i, tuple ); + } + } else { + for( i = 0, datap = kb->keyblock->data; i < datasize; + i++, datap += kb->key->elemsize ) { + PyObject *vec = newVectorObject((float*)datap, 4, Py_WRAP); + if (!vec) return EXPP_ReturnPyObjError( PyExc_MemoryError, + "could not allocate memory for Blender.Mathutils.Vector wrapper!" ); + + PyList_SetItem( l, i, vec ); + } + } + break; + + case ID_LT: + for( i = 0, datap = kb->keyblock->data; i < kb->keyblock->totelem; + i++, datap += kb->key->elemsize ) { + PyObject *vec = newVectorObject((float*)datap, 3, Py_WRAP); + if (!vec) return EXPP_ReturnPyObjError( PyExc_MemoryError, + "Could not allocate memory for Blender.Mathutils.Vector wrapper!" ); + + PyList_SetItem( l, i, vec ); + } + break; + } + + return l; +} + +static PyObject *M_Key_Get( PyObject * self, PyObject * args ) +{ + char *name = NULL; + Key *key_iter; + char error_msg[64]; + int i; + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument (or nothing)" ) ); + + if ( name ) { + for (key_iter = G.main->key.first; key_iter; + key_iter=key_iter->id.next) { + if (strcmp ( key_iter->id.name + 2, name ) == 0 ) { + return Key_CreatePyObject( key_iter ); + } + } + + PyOS_snprintf( error_msg, sizeof( error_msg ), + "Key \"%s\" not found", name ); + return EXPP_ReturnPyObjError ( PyExc_NameError, error_msg ); + + } else { + + PyObject *keylist; + + keylist = PyList_New( BLI_countlist( &( G.main->key ) ) ); + + for ( i=0, key_iter = G.main->key.first; key_iter; + key_iter=key_iter->id.next, i++ ) { + PyList_SetItem(keylist, i, Key_CreatePyObject(key_iter)); + } + return keylist; + } +} + +struct PyMethodDef M_Key_methods[] = { + {"Get", M_Key_Get, METH_VARARGS, "Get a key or all key names"}, + {NULL, NULL, 0, NULL} +}; + +static PyObject *M_Key_TypesDict( void ) +{ + PyObject *T = PyConstant_New( ); + + if( T ) { + BPy_constant *d = ( BPy_constant * ) T; + + PyConstant_Insert( d, "MESH", PyInt_FromLong( KEY_TYPE_MESH ) ); + PyConstant_Insert( d, "CURVE", PyInt_FromLong( KEY_TYPE_CURVE ) ); + PyConstant_Insert( d, "LATTICE", PyInt_FromLong( KEY_TYPE_LATTICE ) ); + } + + return T; +} + +PyObject *Key_Init( void ) +{ + PyObject *submodule; + PyObject *Types = NULL; + + if( PyType_Ready( &Key_Type ) < 0 || PyType_Ready( &KeyBlock_Type ) < 0 ) + return NULL; + + submodule = + Py_InitModule3( "Blender.Key", M_Key_methods, "Key module" ); + + Types = M_Key_TypesDict( ); + if( Types ) + PyModule_AddObject( submodule, "Types", Types ); + + return submodule; +} + diff --git a/source/blender/python/api2_2x/Key.h b/source/blender/python/api2_2x/Key.h new file mode 100644 index 00000000000..87cb55d10eb --- /dev/null +++ b/source/blender/python/api2_2x/Key.h @@ -0,0 +1,68 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Pontus Lidman + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef EXPP_KEY_H +#define EXPP_KEY_H + +#include "Python.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +extern PyTypeObject Key_Type; +extern PyTypeObject KeyBlock_Type; + +typedef struct { + PyObject_HEAD /* required python macro */ + Key * key; /* libdata must be second */ + /* Object *object;*/ /* for vertex grouping info, since it's stored on the object */ + /*PyObject *keyBlock;*/ + /*PyObject *ipo;*/ +} BPy_Key; + +typedef struct { + PyObject_HEAD /* required python macro */ + Key *key; + KeyBlock * keyblock; + /* Object *object;*/ /* for vertex grouping info, since it's stored on the object */ +} BPy_KeyBlock; + +PyObject *Key_CreatePyObject( Key * k ); +PyObject *KeyBlock_CreatePyObject( KeyBlock * k, Key *parentKey ); + +PyObject *Key_Init( void ); + +#endif /* EXPP_KEY_H */ diff --git a/source/blender/python/api2_2x/Lamp.c b/source/blender/python/api2_2x/Lamp.c new file mode 100644 index 00000000000..d40cc5a2cfc --- /dev/null +++ b/source/blender/python/api2_2x/Lamp.c @@ -0,0 +1,1570 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano, Nathan Letwory, Stephen Swaney, + * Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#include "Lamp.h" /*This must come first*/ + +#include "BKE_main.h" +#include "BKE_global.h" +#include "BKE_object.h" +#include "BKE_library.h" +#include "BLI_blenlib.h" +#include "BIF_space.h" +#include "BSE_editipo.h" +#include "mydevice.h" +#include "Ipo.h" +#include "constant.h" +#include "gen_utils.h" +#include "gen_library.h" + +/*****************************************************************************/ +/* Python BPy_Lamp defaults: */ +/*****************************************************************************/ + +/* Lamp types */ + +/* NOTE: + these are the same values as LA_* from DNA_lamp_types.h + is there some reason we are not simply using those #defines? + s. swaney 8-oct-2004 +*/ + +#define EXPP_LAMP_TYPE_LAMP 0 +#define EXPP_LAMP_TYPE_SUN 1 +#define EXPP_LAMP_TYPE_SPOT 2 +#define EXPP_LAMP_TYPE_HEMI 3 +#define EXPP_LAMP_TYPE_AREA 4 +#define EXPP_LAMP_TYPE_YF_PHOTON 5 +/* + define a constant to keep magic numbers out of the code + this value should be equal to the last EXPP_LAMP_TYPE_* +*/ +#define EXPP_LAMP_TYPE_MAX 5 + +/* Lamp mode flags */ + +#define EXPP_LAMP_MODE_SHADOWS 1 +#define EXPP_LAMP_MODE_HALO 2 +#define EXPP_LAMP_MODE_LAYER 4 +#define EXPP_LAMP_MODE_QUAD 8 +#define EXPP_LAMP_MODE_NEGATIVE 16 +#define EXPP_LAMP_MODE_ONLYSHADOW 32 +#define EXPP_LAMP_MODE_SPHERE 64 +#define EXPP_LAMP_MODE_SQUARE 128 +#define EXPP_LAMP_MODE_TEXTURE 256 +#define EXPP_LAMP_MODE_OSATEX 512 +#define EXPP_LAMP_MODE_DEEPSHADOW 1024 +#define EXPP_LAMP_MODE_NODIFFUSE 2048 +#define EXPP_LAMP_MODE_NOSPECULAR 4096 +#define EXPP_LAMP_MODE_SHAD_RAY 8192 +/* Lamp MIN, MAX values */ + +#define EXPP_LAMP_SAMPLES_MIN 1 +#define EXPP_LAMP_SAMPLES_MAX 16 +#define EXPP_LAMP_BUFFERSIZE_MIN 512 +#define EXPP_LAMP_BUFFERSIZE_MAX 5120 +#define EXPP_LAMP_ENERGY_MIN 0.0 +#define EXPP_LAMP_ENERGY_MAX 10.0 +#define EXPP_LAMP_DIST_MIN 0.1f +#define EXPP_LAMP_DIST_MAX 5000.0 +#define EXPP_LAMP_SPOTSIZE_MIN 1.0 +#define EXPP_LAMP_SPOTSIZE_MAX 180.0 +#define EXPP_LAMP_SPOTBLEND_MIN 0.00 +#define EXPP_LAMP_SPOTBLEND_MAX 1.00 +#define EXPP_LAMP_CLIPSTART_MIN 0.1f +#define EXPP_LAMP_CLIPSTART_MAX 1000.0 +#define EXPP_LAMP_CLIPEND_MIN 1.0 +#define EXPP_LAMP_CLIPEND_MAX 5000.0 +#define EXPP_LAMP_BIAS_MIN 0.01f +#define EXPP_LAMP_BIAS_MAX 5.00 +#define EXPP_LAMP_SOFTNESS_MIN 1.0 +#define EXPP_LAMP_SOFTNESS_MAX 100.0 +#define EXPP_LAMP_HALOINT_MIN 0.0 +#define EXPP_LAMP_HALOINT_MAX 5.0 +#define EXPP_LAMP_HALOSTEP_MIN 0 +#define EXPP_LAMP_HALOSTEP_MAX 12 +#define EXPP_LAMP_QUAD1_MIN 0.0 +#define EXPP_LAMP_QUAD1_MAX 1.0 +#define EXPP_LAMP_QUAD2_MIN 0.0 +#define EXPP_LAMP_QUAD2_MAX 1.0 +#define EXPP_LAMP_COL_MIN 0.0 +#define EXPP_LAMP_COL_MAX 1.0 + +/* Raytracing settings */ +#define EXPP_LAMP_RAYSAMPLES_MIN 1 +#define EXPP_LAMP_RAYSAMPLES_MAX 16 +#define EXPP_LAMP_AREASIZE_MIN 0.01f +#define EXPP_LAMP_AREASIZE_MAX 100.0f + +/* Lamp_setComponent() keys for which color to get/set */ +#define EXPP_LAMP_COMP_R 0x00 +#define EXPP_LAMP_COMP_G 0x01 +#define EXPP_LAMP_COMP_B 0x02 + +#define IPOKEY_RGB 0 +#define IPOKEY_ENERGY 1 +#define IPOKEY_SPOTSIZE 2 +#define IPOKEY_OFFSET 3 +#define IPOKEY_SIZE 4 + +/*****************************************************************************/ +/* Python API function prototypes for the Lamp module. */ +/*****************************************************************************/ +static PyObject *M_Lamp_New( PyObject * self, PyObject * args, + PyObject * keywords ); +static PyObject *M_Lamp_Get( PyObject * self, PyObject * args ); + +/*****************************************************************************/ +/* The following string definitions are used for documentation strings. */ +/* In Python these will be written to the console when doing a */ +/* Blender.Lamp.__doc__ */ +/*****************************************************************************/ +static char M_Lamp_doc[] = "The Blender Lamp module\n\n\ +This module provides control over **Lamp Data** objects in Blender.\n\n\ +Example::\n\n\ + from Blender import Lamp\n\ + l = Lamp.New('Spot') # create new 'Spot' lamp data\n\ + l.setMode('square', 'shadow') # set these two lamp mode flags\n\ + ob = Object.New('Lamp') # create new lamp object\n\ + ob.link(l) # link lamp obj with lamp data\n"; + +static char M_Lamp_New_doc[] = "Lamp.New (type = 'Lamp', name = 'LampData'):\n\ + Return a new Lamp Data object with the given type and name."; + +static char M_Lamp_Get_doc[] = "Lamp.Get (name = None):\n\ + Return the Lamp Data with the given name, None if not found, or\n\ + Return a list with all Lamp Data objects in the current scene,\n\ + if no argument was given."; + +/*****************************************************************************/ +/* Python method structure definition for Blender.Lamp module: */ +/*****************************************************************************/ +struct PyMethodDef M_Lamp_methods[] = { + {"New", ( PyCFunction ) M_Lamp_New, METH_VARARGS | METH_KEYWORDS, + M_Lamp_New_doc}, + {"Get", M_Lamp_Get, METH_VARARGS, M_Lamp_Get_doc}, + {"get", M_Lamp_Get, METH_VARARGS, M_Lamp_Get_doc}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python BPy_Lamp methods declarations: */ +/*****************************************************************************/ +static PyObject *Lamp_getType( BPy_Lamp * self ); +static PyObject *Lamp_getTypesConst( void ); +static PyObject *Lamp_getMode( BPy_Lamp * self ); +static PyObject *Lamp_getModesConst( void ); +static PyObject *Lamp_getSamples( BPy_Lamp * self ); +static PyObject *Lamp_getRaySamplesX( BPy_Lamp * self ); +static PyObject *Lamp_getRaySamplesY( BPy_Lamp * self ); +static PyObject *Lamp_getAreaSizeX( BPy_Lamp * self ); +static PyObject *Lamp_getAreaSizeY( BPy_Lamp * self ); +static PyObject *Lamp_getBufferSize( BPy_Lamp * self ); +static PyObject *Lamp_getHaloStep( BPy_Lamp * self ); +static PyObject *Lamp_getEnergy( BPy_Lamp * self ); +static PyObject *Lamp_getDist( BPy_Lamp * self ); +static PyObject *Lamp_getSpotSize( BPy_Lamp * self ); +static PyObject *Lamp_getSpotBlend( BPy_Lamp * self ); +static PyObject *Lamp_getClipStart( BPy_Lamp * self ); +static PyObject *Lamp_getClipEnd( BPy_Lamp * self ); +static PyObject *Lamp_getBias( BPy_Lamp * self ); +static PyObject *Lamp_getSoftness( BPy_Lamp * self ); +static PyObject *Lamp_getHaloInt( BPy_Lamp * self ); +static PyObject *Lamp_getQuad1( BPy_Lamp * self ); +static PyObject *Lamp_getQuad2( BPy_Lamp * self ); +static PyObject *Lamp_getCol( BPy_Lamp * self ); +static PyObject *Lamp_getIpo( BPy_Lamp * self ); +static PyObject *Lamp_getComponent( BPy_Lamp * self, void * closure ); +static PyObject *Lamp_clearIpo( BPy_Lamp * self ); +static PyObject *Lamp_insertIpoKey( BPy_Lamp * self, PyObject * args ); +static PyObject *Lamp_oldsetIpo( BPy_Lamp * self, PyObject * args ); +static PyObject *Lamp_oldsetType( BPy_Lamp * self, PyObject * value ); +static PyObject *Lamp_oldsetMode( BPy_Lamp * self, PyObject * args ); +static PyObject *Lamp_oldsetSamples( BPy_Lamp * self, PyObject * args ); +static PyObject *Lamp_oldsetRaySamplesX( BPy_Lamp * self, PyObject * args ); +static PyObject *Lamp_oldsetRaySamplesY( BPy_Lamp * self, PyObject * args ); +static PyObject *Lamp_oldsetAreaSizeX( BPy_Lamp * self, PyObject * args ); +static PyObject *Lamp_oldsetAreaSizeY( BPy_Lamp * self, PyObject * args ); +static PyObject *Lamp_oldsetBufferSize( BPy_Lamp * self, PyObject * args ); +static PyObject *Lamp_oldsetHaloStep( BPy_Lamp * self, PyObject * args ); +static PyObject *Lamp_oldsetEnergy( BPy_Lamp * self, PyObject * args ); +static PyObject *Lamp_oldsetDist( BPy_Lamp * self, PyObject * args ); +static PyObject *Lamp_oldsetSpotSize( BPy_Lamp * self, PyObject * args ); +static PyObject *Lamp_oldsetSpotBlend( BPy_Lamp * self, PyObject * args ); +static PyObject *Lamp_oldsetClipStart( BPy_Lamp * self, PyObject * args ); +static PyObject *Lamp_oldsetClipEnd( BPy_Lamp * self, PyObject * args ); +static PyObject *Lamp_oldsetBias( BPy_Lamp * self, PyObject * args ); +static PyObject *Lamp_oldsetSoftness( BPy_Lamp * self, PyObject * args ); +static PyObject *Lamp_oldsetHaloInt( BPy_Lamp * self, PyObject * args ); +static PyObject *Lamp_oldsetQuad1( BPy_Lamp * self, PyObject * args ); +static PyObject *Lamp_oldsetQuad2( BPy_Lamp * self, PyObject * args ); +static PyObject *Lamp_oldsetCol( BPy_Lamp * self, PyObject * args ); +static PyObject *Lamp_copy( BPy_Lamp * self ); +static int Lamp_setIpo( BPy_Lamp * self, PyObject * args ); +static int Lamp_setType( BPy_Lamp * self, PyObject * args ); +static int Lamp_setMode( BPy_Lamp * self, PyObject * args ); +static int Lamp_setSamples( BPy_Lamp * self, PyObject * args ); +static int Lamp_setRaySamplesX( BPy_Lamp * self, PyObject * args ); +static int Lamp_setRaySamplesY( BPy_Lamp * self, PyObject * args ); +static int Lamp_setAreaSizeX( BPy_Lamp * self, PyObject * args ); +static int Lamp_setAreaSizeY( BPy_Lamp * self, PyObject * args ); +static int Lamp_setBufferSize( BPy_Lamp * self, PyObject * args ); +static int Lamp_setHaloStep( BPy_Lamp * self, PyObject * args ); +static int Lamp_setEnergy( BPy_Lamp * self, PyObject * args ); +static int Lamp_setDist( BPy_Lamp * self, PyObject * args ); +static int Lamp_setSpotSize( BPy_Lamp * self, PyObject * args ); +static int Lamp_setSpotBlend( BPy_Lamp * self, PyObject * args ); +static int Lamp_setClipStart( BPy_Lamp * self, PyObject * args ); +static int Lamp_setClipEnd( BPy_Lamp * self, PyObject * args ); +static int Lamp_setBias( BPy_Lamp * self, PyObject * args ); +static int Lamp_setSoftness( BPy_Lamp * self, PyObject * args ); +static int Lamp_setHaloInt( BPy_Lamp * self, PyObject * args ); +static int Lamp_setQuad1( BPy_Lamp * self, PyObject * args ); +static int Lamp_setQuad2( BPy_Lamp * self, PyObject * args ); +static int Lamp_setCol( BPy_Lamp * self, PyObject * args ); +static PyObject *Lamp_getScriptLinks( BPy_Lamp * self, PyObject * value ); +static PyObject *Lamp_addScriptLink( BPy_Lamp * self, PyObject * args ); +static PyObject *Lamp_clearScriptLinks( BPy_Lamp * self, PyObject * args ); +static int Lamp_setComponent( BPy_Lamp * self, PyObject * value, void * closure ); + +/*****************************************************************************/ +/* Python BPy_Lamp methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_Lamp_methods[] = { + /* name, method, flags, doc */ + + {"getType", ( PyCFunction ) Lamp_getType, METH_NOARGS, + "() - return Lamp type - 'Lamp':0, 'Sun':1, 'Spot':2, 'Hemi':3, 'Area':4, 'Photon':5"}, + {"getMode", ( PyCFunction ) Lamp_getMode, METH_NOARGS, + "() - return Lamp mode flags (or'ed value)"}, + {"getSamples", ( PyCFunction ) Lamp_getSamples, METH_NOARGS, + "() - return Lamp samples value"}, + {"getRaySamplesX", ( PyCFunction ) Lamp_getRaySamplesX, METH_NOARGS, + "() - return Lamp raytracing samples on the X axis"}, + {"getRaySamplesY", ( PyCFunction ) Lamp_getRaySamplesY, METH_NOARGS, + "() - return Lamp raytracing samples on the Y axis"}, + {"getAreaSizeX", ( PyCFunction ) Lamp_getAreaSizeX, METH_NOARGS, + "() - return Lamp area size on the X axis"}, + {"getAreaSizeY", ( PyCFunction ) Lamp_getAreaSizeY, METH_NOARGS, + "() - return Lamp area size on the Y axis"}, + {"getBufferSize", ( PyCFunction ) Lamp_getBufferSize, METH_NOARGS, + "() - return Lamp buffer size value"}, + {"getHaloStep", ( PyCFunction ) Lamp_getHaloStep, METH_NOARGS, + "() - return Lamp halo step value"}, + {"getEnergy", ( PyCFunction ) Lamp_getEnergy, METH_NOARGS, + "() - return Lamp energy value"}, + {"getDist", ( PyCFunction ) Lamp_getDist, METH_NOARGS, + "() - return Lamp clipping distance value"}, + {"getSpotSize", ( PyCFunction ) Lamp_getSpotSize, METH_NOARGS, + "() - return Lamp spot size value"}, + {"getSpotBlend", ( PyCFunction ) Lamp_getSpotBlend, METH_NOARGS, + "() - return Lamp spot blend value"}, + {"getClipStart", ( PyCFunction ) Lamp_getClipStart, METH_NOARGS, + "() - return Lamp clip start value"}, + {"getClipEnd", ( PyCFunction ) Lamp_getClipEnd, METH_NOARGS, + "() - return Lamp clip end value"}, + {"getBias", ( PyCFunction ) Lamp_getBias, METH_NOARGS, + "() - return Lamp bias value"}, + {"getSoftness", ( PyCFunction ) Lamp_getSoftness, METH_NOARGS, + "() - return Lamp softness value"}, + {"getHaloInt", ( PyCFunction ) Lamp_getHaloInt, METH_NOARGS, + "() - return Lamp halo intensity value"}, + {"getQuad1", ( PyCFunction ) Lamp_getQuad1, METH_NOARGS, + "() - return light intensity value #1 for a Quad Lamp"}, + {"getQuad2", ( PyCFunction ) Lamp_getQuad2, METH_NOARGS, + "() - return light intensity value #2 for a Quad Lamp"}, + {"getCol", ( PyCFunction ) Lamp_getCol, METH_NOARGS, + "() - return light rgb color triplet"}, + {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS, + "(str) - rename Lamp"}, + {"setType", ( PyCFunction ) Lamp_oldsetType, METH_O, + "(str) - change Lamp type, which can be 'Lamp', 'Sun', 'Spot', 'Hemi', 'Area', 'Photon'"}, + {"setMode", ( PyCFunction ) Lamp_oldsetMode, METH_VARARGS, + "([up to eight str's]) - Set Lamp mode flag(s)"}, + {"setSamples", ( PyCFunction ) Lamp_oldsetSamples, METH_VARARGS, + "(int) - change Lamp samples value"}, + {"setRaySamplesX", ( PyCFunction ) Lamp_oldsetRaySamplesX, METH_VARARGS, + "(int) - change Lamp ray X samples value in [1,16]"}, + {"setRaySamplesY", ( PyCFunction ) Lamp_oldsetRaySamplesY, METH_VARARGS, + "(int) - change Lamp ray Y samples value in [1,16]"}, + {"setAreaSizeX", ( PyCFunction ) Lamp_oldsetAreaSizeX, METH_VARARGS, + "(float) - change Lamp ray X size for area lamps, value in [0.01, 100.0]"}, + {"setAreaSizeY", ( PyCFunction ) Lamp_oldsetAreaSizeY, METH_VARARGS, + "(float) - change Lamp ray Y size for area lamps, value in [0.01, 100.0]"}, + {"setBufferSize", ( PyCFunction ) Lamp_oldsetBufferSize, METH_VARARGS, + "(int) - change Lamp buffer size value"}, + {"setHaloStep", ( PyCFunction ) Lamp_oldsetHaloStep, METH_VARARGS, + "(int) - change Lamp halo step value"}, + {"setEnergy", ( PyCFunction ) Lamp_oldsetEnergy, METH_VARARGS, + "(float) - change Lamp energy value"}, + {"setDist", ( PyCFunction ) Lamp_oldsetDist, METH_VARARGS, + "(float) - change Lamp clipping distance value"}, + {"setSpotSize", ( PyCFunction ) Lamp_oldsetSpotSize, METH_VARARGS, + "(float) - change Lamp spot size value"}, + {"setSpotBlend", ( PyCFunction ) Lamp_oldsetSpotBlend, METH_VARARGS, + "(float) - change Lamp spot blend value"}, + {"setClipStart", ( PyCFunction ) Lamp_oldsetClipStart, METH_VARARGS, + "(float) - change Lamp clip start value"}, + {"setClipEnd", ( PyCFunction ) Lamp_oldsetClipEnd, METH_VARARGS, + "(float) - change Lamp clip end value"}, + {"setBias", ( PyCFunction ) Lamp_oldsetBias, METH_VARARGS, + "(float) - change Lamp draw size value"}, + {"setSoftness", ( PyCFunction ) Lamp_oldsetSoftness, METH_VARARGS, + "(float) - change Lamp softness value"}, + {"setHaloInt", ( PyCFunction ) Lamp_oldsetHaloInt, METH_VARARGS, + "(float) - change Lamp halo intensity value"}, + {"setQuad1", ( PyCFunction ) Lamp_oldsetQuad1, METH_VARARGS, + "(float) - change light intensity value #1 for a Quad Lamp"}, + {"setQuad2", ( PyCFunction ) Lamp_oldsetQuad2, METH_VARARGS, + "(float) - change light intensity value #2 for a Quad Lamp"}, + {"setCol", ( PyCFunction ) Lamp_oldsetCol, METH_VARARGS, + "(f,f,f) or ([f,f,f]) - change light's rgb color triplet"}, + {"getScriptLinks", ( PyCFunction ) Lamp_getScriptLinks, METH_O, + "(eventname) - Get a list of this lamp's scriptlinks (Text names) " + "of the given type\n" + "(eventname) - string: FrameChanged, Redraw or Render."}, + {"addScriptLink", ( PyCFunction ) Lamp_addScriptLink, METH_VARARGS, + "(text, evt) - Add a new lamp scriptlink.\n" + "(text) - string: an existing Blender Text name;\n" + "(evt) string: FrameChanged, Redraw or Render."}, + {"clearScriptLinks", ( PyCFunction ) Lamp_clearScriptLinks, + METH_VARARGS, + "() - Delete all scriptlinks from this lamp.\n" + "([s1<,s2,s3...>]) - Delete specified scriptlinks from this lamp."}, + {"getIpo", ( PyCFunction ) Lamp_getIpo, METH_NOARGS, + "() - get IPO for this lamp"}, + {"clearIpo", ( PyCFunction ) Lamp_clearIpo, METH_NOARGS, + "() - unlink the IPO for this lamp"}, + {"setIpo", ( PyCFunction ) Lamp_oldsetIpo, METH_VARARGS, + "( lamp-ipo ) - link an IPO to this lamp"}, + {"insertIpoKey", ( PyCFunction ) Lamp_insertIpoKey, METH_VARARGS, + "( Lamp IPO type ) - Inserts a key into IPO"}, + {"__copy__", ( PyCFunction ) Lamp_copy, METH_NOARGS, + "() - Makes a copy of this lamp."}, + {"copy", ( PyCFunction ) Lamp_copy, METH_NOARGS, + "() - Makes a copy of this lamp."}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef BPy_Lamp_getseters[] = { + GENERIC_LIB_GETSETATTR, + {"bias", + (getter)Lamp_getBias, (setter)Lamp_setBias, + "Lamp shadow map sampling bias", + NULL}, + {"bufferSize", + (getter)Lamp_getBufferSize, (setter)Lamp_setBufferSize, + "Lamp shadow buffer size", + NULL}, + {"clipEnd", + (getter)Lamp_getClipEnd, (setter)Lamp_setClipEnd, + "Lamp shadow map clip end", + NULL}, + {"clipStart", + (getter)Lamp_getClipStart, (setter)Lamp_setClipStart, + "Lamp shadow map clip start", + NULL}, + {"col", + (getter)Lamp_getCol, (setter)Lamp_setCol, + "Lamp RGB color triplet", + NULL}, + {"dist", + (getter)Lamp_getDist, (setter)Lamp_setDist, + "Lamp clipping distance", + NULL}, + {"energy", + (getter)Lamp_getEnergy, (setter)Lamp_setEnergy, + "Lamp light intensity", + NULL}, + {"haloInt", + (getter)Lamp_getHaloInt, (setter)Lamp_setHaloInt, + "Lamp spotlight halo intensity", + NULL}, + {"haloStep", + (getter)Lamp_getHaloStep, (setter)Lamp_setHaloStep, + "Lamp volumetric halo sampling frequency", + NULL}, + {"ipo", + (getter)Lamp_getIpo, (setter)Lamp_setIpo, + "Lamp Ipo", + NULL}, + {"mode", + (getter)Lamp_getMode, (setter)Lamp_setMode, + "Lamp mode bitmask", + NULL}, + {"quad1", + (getter)Lamp_getQuad1, (setter)Lamp_setQuad1, + "Quad lamp linear distance attenuation", + NULL}, + {"quad2", + (getter)Lamp_getQuad2, (setter)Lamp_setQuad2, + "Quad lamp quadratic distance attenuation", + NULL}, + {"samples", + (getter)Lamp_getSamples, (setter)Lamp_setSamples, + "Lamp shadow map samples", + NULL}, + {"raySamplesX", + (getter)Lamp_getRaySamplesX, (setter)Lamp_setRaySamplesX, + "Lamp raytracing samples on the X axis", + NULL}, + {"raySamplesY", + (getter)Lamp_getRaySamplesY, (setter)Lamp_setRaySamplesY, + "Lamp raytracing samples on the Y axis", + NULL}, + {"areaSizeX", + (getter)Lamp_getAreaSizeX, (setter)Lamp_setAreaSizeX, + "Lamp X size for an arealamp", + NULL}, + {"areaSizeY", + (getter)Lamp_getAreaSizeY, (setter)Lamp_setAreaSizeY, + "Lamp Y size for an arealamp", + NULL}, + {"softness", + (getter)Lamp_getSoftness, (setter)Lamp_setSoftness, + "Lamp shadow sample area size", + NULL}, + {"spotBlend", + (getter)Lamp_getSpotBlend, (setter)Lamp_setSpotBlend, + "Lamp spotlight edge softness", + NULL}, + {"spotSize", + (getter)Lamp_getSpotSize, (setter)Lamp_setSpotSize, + "Lamp spotlight beam angle (in degrees)", + NULL}, + {"type", + (getter)Lamp_getType, (setter)Lamp_setType, + "Lamp type", + NULL}, + {"R", + (getter)Lamp_getComponent, (setter)Lamp_setComponent, + "Lamp color red component", + (void *)EXPP_LAMP_COMP_R}, + {"r", + (getter)Lamp_getComponent, (setter)Lamp_setComponent, + "Lamp color red component", + (void *)EXPP_LAMP_COMP_R}, + {"G", + (getter)Lamp_getComponent, (setter)Lamp_setComponent, + "Lamp color green component", + (void *)EXPP_LAMP_COMP_G}, + {"g", + (getter)Lamp_getComponent, (setter)Lamp_setComponent, + "Lamp color green component", + (void *)EXPP_LAMP_COMP_G}, + {"B", + (getter)Lamp_getComponent, (setter)Lamp_setComponent, + "Lamp color blue component", + (void *)EXPP_LAMP_COMP_B}, + {"b", + (getter)Lamp_getComponent, (setter)Lamp_setComponent, + "Lamp color blue component", + (void *)EXPP_LAMP_COMP_B}, + {"Modes", + (getter)Lamp_getModesConst, (setter)NULL, + "Dictionary of values for 'mode' attribute", + NULL}, + {"Types", + (getter)Lamp_getTypesConst, (setter)NULL, + "Dictionary of values for 'type' attribute", + NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/*****************************************************************************/ +/* Python TypeLamp callback function prototypes: */ +/*****************************************************************************/ +static void Lamp_dealloc( BPy_Lamp * lamp ); +static int Lamp_compare( BPy_Lamp * a, BPy_Lamp * b ); +static PyObject *Lamp_repr( BPy_Lamp * lamp ); + +/*****************************************************************************/ +/* Python TypeLamp structure definition: */ +/*****************************************************************************/ +PyTypeObject Lamp_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender Lamp", /* char *tp_name; */ + sizeof( BPy_Lamp ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + ( destructor ) Lamp_dealloc,/* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) Lamp_compare, /* cmpfunc tp_compare; */ + ( reprfunc ) Lamp_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_Lamp_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_Lamp_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +/*****************************************************************************/ +/* Function: M_Lamp_New */ +/* Python equivalent: Blender.Lamp.New */ +/*****************************************************************************/ +static PyObject *M_Lamp_New( PyObject * self, PyObject * args, + PyObject * keywords ) +{ + char *type_str = "Lamp"; + char *name_str = "Lamp"; + static char *kwlist[] = { "type_str", "name_str", NULL }; + BPy_Lamp *py_lamp; /* for Lamp Data object wrapper in Python */ + Lamp *bl_lamp; /* for actual Lamp Data we create in Blender */ + + if( !PyArg_ParseTupleAndKeywords( args, keywords, "|ss", kwlist, + &type_str, &name_str ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected string(s) or empty argument" ) ); + + bl_lamp = add_lamp( name_str ); /* first create in Blender */ + + if( bl_lamp ) /* now create the wrapper obj in Python */ + py_lamp = ( BPy_Lamp * ) Lamp_CreatePyObject( bl_lamp ); + else + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't create Lamp Data in Blender" ) ); + + /* let's return user count to zero, because ... */ + bl_lamp->id.us = 0; /* ... add_lamp() incref'ed it */ + + if( py_lamp == NULL ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create Lamp Data object" ) ); + + if( strcmp( type_str, "Lamp" ) == 0 ) + bl_lamp->type = ( short ) EXPP_LAMP_TYPE_LAMP; + else if( strcmp( type_str, "Sun" ) == 0 ) + bl_lamp->type = ( short ) EXPP_LAMP_TYPE_SUN; + else if( strcmp( type_str, "Spot" ) == 0 ) + bl_lamp->type = ( short ) EXPP_LAMP_TYPE_SPOT; + else if( strcmp( type_str, "Hemi" ) == 0 ) + bl_lamp->type = ( short ) EXPP_LAMP_TYPE_HEMI; + else if( strcmp( type_str, "Area" ) == 0 ) + bl_lamp->type = ( short ) EXPP_LAMP_TYPE_AREA; + else if( strcmp( type_str, "Photon" ) == 0 ) + bl_lamp->type = ( short ) EXPP_LAMP_TYPE_YF_PHOTON; + else + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "unknown lamp type" ) ); + + return ( PyObject * ) py_lamp; +} + +/*****************************************************************************/ +/* Function: M_Lamp_Get */ +/* Python equivalent: Blender.Lamp.Get */ +/* Description: Receives a string and returns the lamp data obj */ +/* whose name matches the string. If no argument is */ +/* passed in, a list of all lamp data names in the */ +/* current scene is returned. */ +/*****************************************************************************/ +static PyObject *M_Lamp_Get( PyObject * self, PyObject * args ) +{ + char *name = NULL; + Lamp *lamp_iter; + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument (or nothing)" ) ); + + lamp_iter = G.main->lamp.first; + + if( name ) { /* (name) - Search lamp by name */ + + BPy_Lamp *wanted_lamp = NULL; + + while( ( lamp_iter ) && ( wanted_lamp == NULL ) ) { + + if( strcmp( name, lamp_iter->id.name + 2 ) == 0 ) + wanted_lamp = + ( BPy_Lamp * ) + Lamp_CreatePyObject( lamp_iter ); + + lamp_iter = lamp_iter->id.next; + } + + if( wanted_lamp == NULL ) { /* Requested lamp doesn't exist */ + char error_msg[64]; + PyOS_snprintf( error_msg, sizeof( error_msg ), + "Lamp \"%s\" not found", name ); + return ( EXPP_ReturnPyObjError + ( PyExc_NameError, error_msg ) ); + } + + return ( PyObject * ) wanted_lamp; + } + + else { /* () - return a list of all lamps in the scene */ + int index = 0; + PyObject *lamplist, *pyobj; + + lamplist = PyList_New( BLI_countlist( &( G.main->lamp ) ) ); + + if( lamplist == NULL ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyList" ) ); + + while( lamp_iter ) { + pyobj = Lamp_CreatePyObject( lamp_iter ); + + if( !pyobj ) { + Py_DECREF(lamplist); + return ( EXPP_ReturnPyObjError + ( PyExc_MemoryError, + "couldn't create PyLamp" ) ); + } + + PyList_SET_ITEM( lamplist, index, pyobj ); + + lamp_iter = lamp_iter->id.next; + index++; + } + + return lamplist; + } +} + +static PyObject *Lamp_TypesDict( void ) +{ /* create the Blender.Lamp.Types constant dict */ + PyObject *Types = PyConstant_New( ); + + if( Types ) { + BPy_constant *c = ( BPy_constant * ) Types; + + PyConstant_Insert( c, "Lamp", + PyInt_FromLong( EXPP_LAMP_TYPE_LAMP ) ); + PyConstant_Insert( c, "Sun", + PyInt_FromLong( EXPP_LAMP_TYPE_SUN ) ); + PyConstant_Insert( c, "Spot", + PyInt_FromLong( EXPP_LAMP_TYPE_SPOT ) ); + PyConstant_Insert( c, "Hemi", + PyInt_FromLong( EXPP_LAMP_TYPE_HEMI ) ); + PyConstant_Insert( c, "Area", + PyInt_FromLong( EXPP_LAMP_TYPE_AREA ) ); + PyConstant_Insert( c, "Photon", + PyInt_FromLong( EXPP_LAMP_TYPE_YF_PHOTON ) ); + } + + return Types; +} + +static PyObject *Lamp_ModesDict( void ) +{ /* create the Blender.Lamp.Modes constant dict */ + PyObject *Modes = PyConstant_New( ); + + if( Modes ) { + BPy_constant *c = ( BPy_constant * ) Modes; + + PyConstant_Insert( c, "Shadows", + PyInt_FromLong( EXPP_LAMP_MODE_SHADOWS ) ); + PyConstant_Insert( c, "Halo", + PyInt_FromLong( EXPP_LAMP_MODE_HALO ) ); + PyConstant_Insert( c, "Layer", + PyInt_FromLong( EXPP_LAMP_MODE_LAYER ) ); + PyConstant_Insert( c, "Quad", + PyInt_FromLong( EXPP_LAMP_MODE_QUAD ) ); + PyConstant_Insert( c, "Negative", + PyInt_FromLong( EXPP_LAMP_MODE_NEGATIVE ) ); + PyConstant_Insert( c, "Sphere", + PyInt_FromLong( EXPP_LAMP_MODE_SPHERE ) ); + PyConstant_Insert( c, "Square", + PyInt_FromLong( EXPP_LAMP_MODE_SQUARE ) ); + PyConstant_Insert( c, "OnlyShadow", + PyInt_FromLong( EXPP_LAMP_MODE_ONLYSHADOW ) ); + PyConstant_Insert( c, "NoDiffuse", + PyInt_FromLong( EXPP_LAMP_MODE_NODIFFUSE ) ); + PyConstant_Insert( c, "NoSpecular", + PyInt_FromLong( EXPP_LAMP_MODE_NOSPECULAR ) ); + PyConstant_Insert( c, "RayShadow", + PyInt_FromLong( EXPP_LAMP_MODE_SHAD_RAY ) ); + } + + return Modes; +} + +/*****************************************************************************/ +/* Function: Lamp_Init */ +/*****************************************************************************/ +/* Needed by the Blender module, to register the Blender.Lamp submodule */ +PyObject *Lamp_Init( void ) +{ + PyObject *submodule, *Types, *Modes; + + if( PyType_Ready( &Lamp_Type ) < 0) + return NULL; + + Types = Lamp_TypesDict( ); + Modes = Lamp_ModesDict( ); + + submodule = + Py_InitModule3( "Blender.Lamp", M_Lamp_methods, M_Lamp_doc ); + + if( Types ) + PyModule_AddObject( submodule, "Types", Types ); + if( Modes ) + PyModule_AddObject( submodule, "Modes", Modes ); + + PyModule_AddIntConstant( submodule, "RGB", IPOKEY_RGB ); + PyModule_AddIntConstant( submodule, "ENERGY", IPOKEY_ENERGY ); + PyModule_AddIntConstant( submodule, "SPOTSIZE", IPOKEY_SPOTSIZE ); + PyModule_AddIntConstant( submodule, "OFFSET", IPOKEY_OFFSET ); + PyModule_AddIntConstant( submodule, "SIZE", IPOKEY_SIZE ); + + return submodule; +} + +/* Three Python Lamp_Type helper functions needed by the Object module: */ + +/*****************************************************************************/ +/* Function: Lamp_CreatePyObject */ +/* Description: This function will create a new BPy_Lamp from an existing */ +/* Blender lamp structure. */ +/*****************************************************************************/ +PyObject *Lamp_CreatePyObject( Lamp * lamp ) +{ + BPy_Lamp *pylamp; + float *rgb[3]; + + pylamp = ( BPy_Lamp * ) PyObject_NEW( BPy_Lamp, &Lamp_Type ); + + if( !pylamp ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create BPy_Lamp object" ); + + pylamp->lamp = lamp; + + rgb[0] = &lamp->r; + rgb[1] = &lamp->g; + rgb[2] = &lamp->b; + + pylamp->color = ( BPy_rgbTuple * ) rgbTuple_New( rgb ); + Py_INCREF(pylamp->color); + + return ( PyObject * ) pylamp; +} + +/*****************************************************************************/ +/* Function: Lamp_FromPyObject */ +/* Description: This function returns the Blender lamp from the given */ +/* PyObject. */ +/*****************************************************************************/ +Lamp *Lamp_FromPyObject( PyObject * pyobj ) +{ + return ( ( BPy_Lamp * ) pyobj )->lamp; +} + +/*****************************************************************************/ +/* Python BPy_Lamp methods: */ +/*****************************************************************************/ + +/* Lamp.__copy__ */ +static PyObject *Lamp_copy( BPy_Lamp * self ) +{ + Lamp *lamp = copy_lamp(self->lamp ); + lamp->id.us = 0; + return Lamp_CreatePyObject(lamp); +} + +static PyObject *Lamp_getType( BPy_Lamp * self ) +{ + return PyInt_FromLong( self->lamp->type ); +} + +static PyObject *Lamp_getMode( BPy_Lamp * self ) +{ + return PyInt_FromLong( self->lamp->mode ); +} + +static PyObject *Lamp_getSamples( BPy_Lamp * self ) +{ + return PyInt_FromLong( self->lamp->samp ); +} + +static PyObject *Lamp_getRaySamplesX( BPy_Lamp * self ) +{ + return PyInt_FromLong( self->lamp->ray_samp ); +} + +static PyObject *Lamp_getRaySamplesY( BPy_Lamp * self ) +{ + return PyInt_FromLong( self->lamp->ray_sampy ); +} + +static PyObject *Lamp_getAreaSizeX( BPy_Lamp * self ) +{ + return PyFloat_FromDouble( self->lamp->area_size ); +} + +static PyObject *Lamp_getAreaSizeY( BPy_Lamp * self ) +{ + return PyFloat_FromDouble( self->lamp->area_sizey ); +} + +static PyObject *Lamp_getBufferSize( BPy_Lamp * self ) +{ + return PyInt_FromLong( self->lamp->bufsize ); +} + +static PyObject *Lamp_getHaloStep( BPy_Lamp * self ) +{ + return PyInt_FromLong( self->lamp->shadhalostep ); +} + +static PyObject *Lamp_getEnergy( BPy_Lamp * self ) +{ + return PyFloat_FromDouble( self->lamp->energy ); +} + +static PyObject *Lamp_getDist( BPy_Lamp * self ) +{ + return PyFloat_FromDouble( self->lamp->dist ); +} + +static PyObject *Lamp_getSpotSize( BPy_Lamp * self ) +{ + return PyFloat_FromDouble( self->lamp->spotsize ); +} + +static PyObject *Lamp_getSpotBlend( BPy_Lamp * self ) +{ + return PyFloat_FromDouble( self->lamp->spotblend ); +} + +static PyObject *Lamp_getClipStart( BPy_Lamp * self ) +{ + return PyFloat_FromDouble( self->lamp->clipsta ); +} + +static PyObject *Lamp_getClipEnd( BPy_Lamp * self ) +{ + return PyFloat_FromDouble( self->lamp->clipend ); +} + +static PyObject *Lamp_getBias( BPy_Lamp * self ) +{ + return PyFloat_FromDouble( self->lamp->bias ); +} + +static PyObject *Lamp_getSoftness( BPy_Lamp * self ) +{ + return PyFloat_FromDouble( self->lamp->soft ); +} + +static PyObject *Lamp_getHaloInt( BPy_Lamp * self ) +{ + return PyFloat_FromDouble( self->lamp->haint ); +} + +static PyObject *Lamp_getQuad1( BPy_Lamp * self ) +{ /* should we complain if Lamp is not of type Quad? */ + return PyFloat_FromDouble( self->lamp->att1 ); +} + +static PyObject *Lamp_getQuad2( BPy_Lamp * self ) +{ /* should we complain if Lamp is not of type Quad? */ + return PyFloat_FromDouble( self->lamp->att2 ); +} + +static PyObject *Lamp_getCol( BPy_Lamp * self ) +{ + return rgbTuple_getCol( self->color ); +} + +static int Lamp_setType( BPy_Lamp * self, PyObject * value ) +{ + return EXPP_setIValueRange ( value, &self->lamp->type, + 0, EXPP_LAMP_TYPE_MAX, 'h' ); +} + +static int Lamp_setMode( BPy_Lamp * self, PyObject * value ) +{ + short param; + static short bitmask = EXPP_LAMP_MODE_SHADOWS + | EXPP_LAMP_MODE_HALO + | EXPP_LAMP_MODE_LAYER + | EXPP_LAMP_MODE_QUAD + | EXPP_LAMP_MODE_NEGATIVE + | EXPP_LAMP_MODE_ONLYSHADOW + | EXPP_LAMP_MODE_SPHERE + | EXPP_LAMP_MODE_SQUARE + | EXPP_LAMP_MODE_NODIFFUSE + | EXPP_LAMP_MODE_NOSPECULAR + | EXPP_LAMP_MODE_SHAD_RAY; + + if( !PyInt_Check ( value ) ) { + char errstr[128]; + sprintf ( errstr , "expected int bitmask of 0x%04x", bitmask ); + return EXPP_ReturnIntError( PyExc_TypeError, errstr ); + } + param = (short)PyInt_AS_LONG ( value ); + + if ( ( param & bitmask ) != param ) + return EXPP_ReturnIntError( PyExc_ValueError, + "invalid bit(s) set in mask" ); + + self->lamp->mode = param; + + return 0; +} + +static int Lamp_setSamples( BPy_Lamp * self, PyObject * value ) +{ + return EXPP_setIValueClamped ( value, &self->lamp->samp, + EXPP_LAMP_SAMPLES_MIN, + EXPP_LAMP_SAMPLES_MAX, 'h' ); +} + + +static int Lamp_setRaySamplesX( BPy_Lamp * self, PyObject * value ) +{ + return EXPP_setIValueClamped ( value, &self->lamp->ray_samp, + EXPP_LAMP_RAYSAMPLES_MIN, + EXPP_LAMP_RAYSAMPLES_MAX, 'h' ); +} + +static int Lamp_setRaySamplesY( BPy_Lamp * self, PyObject * value ) +{ + return EXPP_setIValueClamped ( value, &self->lamp->ray_sampy, + EXPP_LAMP_RAYSAMPLES_MIN, + EXPP_LAMP_RAYSAMPLES_MAX, 'h' ); +} + +static int Lamp_setAreaSizeX( BPy_Lamp * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->lamp->area_size, + EXPP_LAMP_AREASIZE_MIN, + EXPP_LAMP_AREASIZE_MAX ); +} + +static int Lamp_setAreaSizeY( BPy_Lamp * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->lamp->area_sizey, + EXPP_LAMP_AREASIZE_MIN, + EXPP_LAMP_AREASIZE_MAX ); +} + +static int Lamp_setBufferSize( BPy_Lamp * self, PyObject * value ) +{ + return EXPP_setIValueClamped ( value, &self->lamp->bufsize, + EXPP_LAMP_BUFFERSIZE_MIN, + EXPP_LAMP_BUFFERSIZE_MAX, 'h' ); +} + +static int Lamp_setHaloStep( BPy_Lamp * self, PyObject * value ) +{ + return EXPP_setIValueClamped ( value, &self->lamp->shadhalostep, + EXPP_LAMP_HALOSTEP_MIN, + EXPP_LAMP_HALOSTEP_MAX, 'h' ); +} + +static int Lamp_setEnergy( BPy_Lamp * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->lamp->energy, + EXPP_LAMP_ENERGY_MIN, + EXPP_LAMP_ENERGY_MAX ); +} + +static int Lamp_setDist( BPy_Lamp * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->lamp->dist, + EXPP_LAMP_DIST_MIN, + EXPP_LAMP_DIST_MAX ); +} + +static int Lamp_setSpotSize( BPy_Lamp * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->lamp->spotsize, + EXPP_LAMP_SPOTSIZE_MIN, + EXPP_LAMP_SPOTSIZE_MAX ); +} + +static int Lamp_setSpotBlend( BPy_Lamp * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->lamp->spotblend, + EXPP_LAMP_SPOTBLEND_MIN, + EXPP_LAMP_SPOTBLEND_MAX ); +} + +static int Lamp_setClipStart( BPy_Lamp * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->lamp->clipsta, + EXPP_LAMP_CLIPSTART_MIN, + EXPP_LAMP_CLIPSTART_MAX ); +} + +static int Lamp_setClipEnd( BPy_Lamp * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->lamp->clipend, + EXPP_LAMP_CLIPEND_MIN, + EXPP_LAMP_CLIPEND_MAX ); +} + +static int Lamp_setBias( BPy_Lamp * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->lamp->bias, + EXPP_LAMP_BIAS_MIN, + EXPP_LAMP_BIAS_MAX ); +} + +static int Lamp_setSoftness( BPy_Lamp * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->lamp->soft, + EXPP_LAMP_SOFTNESS_MIN, + EXPP_LAMP_SOFTNESS_MAX ); +} + +static int Lamp_setHaloInt( BPy_Lamp * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->lamp->haint, + EXPP_LAMP_HALOINT_MIN, + EXPP_LAMP_HALOINT_MAX ); +} + +static int Lamp_setQuad1( BPy_Lamp * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->lamp->att1, + EXPP_LAMP_QUAD1_MIN, + EXPP_LAMP_QUAD1_MAX ); +} + +static int Lamp_setQuad2( BPy_Lamp * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->lamp->att2, + EXPP_LAMP_QUAD2_MIN, + EXPP_LAMP_QUAD2_MAX ); +} + +static PyObject *Lamp_getComponent( BPy_Lamp * self, void * closure ) +{ + switch ( (int)closure ) { + case EXPP_LAMP_COMP_R: + return PyFloat_FromDouble( self->lamp->r ); + case EXPP_LAMP_COMP_G: + return PyFloat_FromDouble( self->lamp->g ); + case EXPP_LAMP_COMP_B: + return PyFloat_FromDouble( self->lamp->b ); + default: + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "unknown color component specified" ); + } +} + +static int Lamp_setComponent( BPy_Lamp * self, PyObject * value, + void * closure ) +{ + float color; + + if( !PyNumber_Check ( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected float argument in [0.0,1.0]" ); + + color = (float)PyFloat_AsDouble( value ); + color = EXPP_ClampFloat( color, EXPP_LAMP_COL_MIN, EXPP_LAMP_COL_MAX ); + + switch ( (int)closure ) { + case EXPP_LAMP_COMP_R: + self->lamp->r = color; + return 0; + case EXPP_LAMP_COMP_G: + self->lamp->g = color; + return 0; + case EXPP_LAMP_COMP_B: + self->lamp->b = color; + return 0; + } + return EXPP_ReturnIntError( PyExc_RuntimeError, + "unknown color component specified" ); +} + +static int Lamp_setCol( BPy_Lamp * self, PyObject * args ) +{ + return rgbTuple_setCol( self->color, args ); +} + +/* lamp.addScriptLink */ +static PyObject *Lamp_addScriptLink( BPy_Lamp * self, PyObject * args ) +{ + Lamp *lamp = self->lamp; + ScriptLink *slink = NULL; + + slink = &( lamp )->scriptlink; + + return EXPP_addScriptLink( slink, args, 0 ); +} + +/* lamp.clearScriptLinks */ +static PyObject *Lamp_clearScriptLinks( BPy_Lamp * self, PyObject * args ) +{ + Lamp *lamp = self->lamp; + ScriptLink *slink = NULL; + + slink = &( lamp )->scriptlink; + + return EXPP_clearScriptLinks( slink, args ); +} + +/* mat.getScriptLinks */ +static PyObject *Lamp_getScriptLinks( BPy_Lamp * self, PyObject * value ) +{ + Lamp *lamp = self->lamp; + ScriptLink *slink = NULL; + PyObject *ret = NULL; + + slink = &( lamp )->scriptlink; + + ret = EXPP_getScriptLinks( slink, value, 0 ); + + if( ret ) + return ret; + else + return NULL; +} + +/*****************************************************************************/ +/* Function: Lamp_dealloc */ +/* Description: This is a callback function for the BPy_Lamp type. It is */ +/* the destructor function. */ +/*****************************************************************************/ +static void Lamp_dealloc( BPy_Lamp * self ) +{ + Py_DECREF( self->color ); + PyObject_DEL( self ); +} + +/*****************************************************************************/ +/* Function: Lamp_compare */ +/* Description: This is a callback function for the BPy_Lamp type. It */ +/* compares two Lamp_Type objects. Only the "==" and "!=" */ +/* comparisons are meaningful. Returns 0 for equality and -1 */ +/* if they don't point to the same Blender Lamp struct. */ +/* In Python it becomes 1 if they are equal, 0 otherwise. */ +/*****************************************************************************/ +static int Lamp_compare( BPy_Lamp * a, BPy_Lamp * b ) +{ + return ( a->lamp == b->lamp ) ? 0 : -1; +} + +/*****************************************************************************/ +/* Function: Lamp_repr */ +/* Description: This is a callback function for the BPy_Lamp type. It */ +/* builds a meaninful string to represent lamp objects. */ +/*****************************************************************************/ +static PyObject *Lamp_repr( BPy_Lamp * self ) +{ + return PyString_FromFormat( "[Lamp \"%s\"]", self->lamp->id.name + 2 ); +} + +static PyObject *Lamp_getIpo( BPy_Lamp * self ) +{ + struct Ipo *ipo = self->lamp->ipo; + + if( !ipo ) + Py_RETURN_NONE; + + return Ipo_CreatePyObject( ipo ); +} + +/* + * this should accept a Py_None argument and just delete the Ipo link + * (as Lamp_clearIpo() does) + */ + +static int Lamp_setIpo( BPy_Lamp * self, PyObject * value ) +{ + return GenericLib_assignData(value, (void **) &self->lamp->ipo, 0, 1, ID_IP, ID_LA); +} + +/* + * Lamp_insertIpoKey() + * inserts Lamp IPO key for RGB,ENERGY,SPOTSIZE,OFFSET,SIZE + */ + +static PyObject *Lamp_insertIpoKey( BPy_Lamp * self, PyObject * args ) +{ + int key = 0, map; + + if( !PyArg_ParseTuple( args, "i", &( key ) ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected int argument" ) ); + + map = texchannel_to_adrcode(self->lamp->texact); + + if (key == IPOKEY_RGB ) { + insertkey((ID *)self->lamp, ID_LA, NULL, NULL, LA_COL_R, 0); + insertkey((ID *)self->lamp, ID_LA, NULL, NULL,LA_COL_G, 0); + insertkey((ID *)self->lamp, ID_LA, NULL, NULL,LA_COL_B, 0); + } + if (key == IPOKEY_ENERGY ) { + insertkey((ID *)self->lamp, ID_LA, NULL, NULL,LA_ENERGY, 0); + } + if (key == IPOKEY_SPOTSIZE ) { + insertkey((ID *)self->lamp, ID_LA, NULL, NULL,LA_SPOTSI, 0); + } + if (key == IPOKEY_OFFSET ) { + insertkey((ID *)self->lamp, ID_LA, NULL, NULL, map+MAP_OFS_X, 0); + insertkey((ID *)self->lamp, ID_LA, NULL, NULL, map+MAP_OFS_Y, 0); + insertkey((ID *)self->lamp, ID_LA, NULL, NULL, map+MAP_OFS_Z, 0); + } + if (key == IPOKEY_SIZE ) { + insertkey((ID *)self->lamp, ID_LA, NULL, NULL, map+MAP_SIZE_X, 0); + insertkey((ID *)self->lamp, ID_LA, NULL, NULL, map+MAP_SIZE_Y, 0); + insertkey((ID *)self->lamp, ID_LA, NULL, NULL, map+MAP_SIZE_Z, 0); + } + + allspace(REMAKEIPO, 0); + EXPP_allqueue(REDRAWIPO, 0); + EXPP_allqueue(REDRAWVIEW3D, 0); + EXPP_allqueue(REDRAWACTION, 0); + EXPP_allqueue(REDRAWNLA, 0); + + Py_RETURN_NONE; +} + +static PyObject *Lamp_getModesConst( void ) +{ + return Py_BuildValue + ( "{s:h,s:h,s:h,s:h,s:h,s:h,s:h,s:h,s:h,s:h,s:h}", + "Shadows", EXPP_LAMP_MODE_SHADOWS, "Halo", + EXPP_LAMP_MODE_HALO, "Layer", EXPP_LAMP_MODE_LAYER, + "Quad", EXPP_LAMP_MODE_QUAD, "Negative", + EXPP_LAMP_MODE_NEGATIVE, "OnlyShadow", + EXPP_LAMP_MODE_ONLYSHADOW, "Sphere", + EXPP_LAMP_MODE_SPHERE, "Square", + EXPP_LAMP_MODE_SQUARE, "NoDiffuse", + EXPP_LAMP_MODE_NODIFFUSE, "NoSpecular", + EXPP_LAMP_MODE_NOSPECULAR, "RayShadow", + EXPP_LAMP_MODE_SHAD_RAY); +} + +static PyObject *Lamp_getTypesConst( void ) +{ + return Py_BuildValue( "{s:h,s:h,s:h,s:h,s:h,s:h}", + "Lamp", EXPP_LAMP_TYPE_LAMP, + "Sun", EXPP_LAMP_TYPE_SUN, + "Spot", EXPP_LAMP_TYPE_SPOT, + "Hemi", EXPP_LAMP_TYPE_HEMI, + "Area", EXPP_LAMP_TYPE_AREA, + "Photon", EXPP_LAMP_TYPE_YF_PHOTON ); +} + +/* #####DEPRECATED###### */ + +static PyObject *Lamp_oldsetSamples( BPy_Lamp * self, PyObject * args ) +{ + return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setSamples ); +} + +static PyObject *Lamp_oldsetRaySamplesX( BPy_Lamp * self, PyObject * args ) +{ + return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setRaySamplesX ); +} + +static PyObject *Lamp_oldsetRaySamplesY( BPy_Lamp * self, PyObject * args ) +{ + return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setRaySamplesY ); +} + +static PyObject *Lamp_oldsetAreaSizeX( BPy_Lamp * self, PyObject * args ) +{ + return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setAreaSizeX ); +} + +static PyObject *Lamp_oldsetAreaSizeY( BPy_Lamp * self, PyObject * args ) +{ + return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setAreaSizeY ); +} + +static PyObject *Lamp_oldsetBufferSize( BPy_Lamp * self, PyObject * args ) +{ + return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setBufferSize ); +} + +static PyObject *Lamp_oldsetHaloStep( BPy_Lamp * self, PyObject * args ) +{ + return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setHaloStep ); +} + +static PyObject *Lamp_oldsetEnergy( BPy_Lamp * self, PyObject * args ) +{ + return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setEnergy ); +} + +static PyObject *Lamp_oldsetDist( BPy_Lamp * self, PyObject * args ) +{ + return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setDist ); +} + +static PyObject *Lamp_oldsetSpotSize( BPy_Lamp * self, PyObject * args ) +{ + return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setSpotSize ); +} + +static PyObject *Lamp_oldsetSpotBlend( BPy_Lamp * self, PyObject * args ) +{ + return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setSpotBlend ); +} + +static PyObject *Lamp_oldsetClipStart( BPy_Lamp * self, PyObject * args ) +{ + return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setClipStart ); +} + +static PyObject *Lamp_oldsetClipEnd( BPy_Lamp * self, PyObject * args ) +{ + return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setClipEnd ); +} + +static PyObject *Lamp_oldsetBias( BPy_Lamp * self, PyObject * args ) +{ + return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setBias ); +} + +static PyObject *Lamp_oldsetSoftness( BPy_Lamp * self, PyObject * args ) +{ + return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setSoftness ); +} + +static PyObject *Lamp_oldsetHaloInt( BPy_Lamp * self, PyObject * args ) +{ + return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setHaloInt ); +} + +static PyObject *Lamp_oldsetQuad1( BPy_Lamp * self, PyObject * args ) +{ + return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setQuad1 ); +} + +static PyObject *Lamp_oldsetQuad2( BPy_Lamp * self, PyObject * args ) +{ + return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setQuad2 ); +} + +static PyObject *Lamp_oldsetIpo( BPy_Lamp * self, PyObject * args ) +{ + return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setIpo ); +} + +static PyObject *Lamp_oldsetCol( BPy_Lamp * self, PyObject * args ) +{ + return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setCol ); +} + +/* + * the "not-well-behaved" methods which require more processing than + * just the simple wrapper + */ + +/* + * clearIpo() returns True/False depending on whether lamp has an Ipo + */ + +static PyObject *Lamp_clearIpo( BPy_Lamp * self ) +{ + /* if Ipo defined, delete it and return true */ + + if( self->lamp->ipo ) { + PyObject *value = Py_BuildValue( "(O)", Py_None ); + EXPP_setterWrapper ( (void *)self, value, (setter)Lamp_setIpo ); + Py_DECREF ( value ); + return EXPP_incr_ret_True(); + } + return EXPP_incr_ret_False(); /* no ipo found */ +} + +/* + * setType() accepts a string while mode setter takes an integer + */ + +static PyObject *Lamp_oldsetType( BPy_Lamp * self, PyObject * value ) +{ + char *type = PyString_AsString(value); + PyObject *arg, *error; + + /* parse string argument */ + + if( !value ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ) ); + + /* check for valid arguments, set type accordingly */ + + if( !strcmp( type, "Lamp" ) ) + self->lamp->type = ( short ) EXPP_LAMP_TYPE_LAMP; + else if( !strcmp( type, "Sun" ) ) + self->lamp->type = ( short ) EXPP_LAMP_TYPE_SUN; + else if( !strcmp( type, "Spot" ) ) + self->lamp->type = ( short ) EXPP_LAMP_TYPE_SPOT; + else if( !strcmp( type, "Hemi" ) ) + self->lamp->type = ( short ) EXPP_LAMP_TYPE_HEMI; + else if( !strcmp( type, "Area" ) ) + self->lamp->type = ( short ) EXPP_LAMP_TYPE_AREA; + else if( !strcmp( type, "Photon" ) ) + self->lamp->type = ( short ) EXPP_LAMP_TYPE_YF_PHOTON; + else + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "unknown lamp type" ); + + /* build tuple, call wrapper */ + + arg = PyInt_FromLong( (long)type ); + error = EXPP_setterWrapper ( (void *)self, arg, (setter)Lamp_setType ); + Py_DECREF ( arg ); + return error; +} + +/* + * setMode() accepts up to ten strings while mode setter takes an integer + */ + +static PyObject *Lamp_oldsetMode( BPy_Lamp * self, PyObject * args ) +{ + short i, flag = 0; + PyObject *error, *value; + char *name; + + /* check that we're passed a tuple of no more than 10 args*/ + + if ( !PyTuple_Check( args ) || PyTuple_Size( args ) > 10 ) + return EXPP_ReturnPyObjError ( PyExc_AttributeError, + "expected up to 10 string arguments" ); + + /* check each argument for type, find its value */ + + for ( i = (short)PyTuple_Size( args ); i-- ; ) { + name = PyString_AsString ( PyTuple_GET_ITEM( args, i ) ); + if( !name ) + return EXPP_ReturnPyObjError ( PyExc_AttributeError, + "expected string argument" ); + + if( !strcmp( name, "Shadows" ) ) + flag |= ( short ) EXPP_LAMP_MODE_SHADOWS; + else if( !strcmp( name, "Halo" ) ) + flag |= ( short ) EXPP_LAMP_MODE_HALO; + else if( !strcmp( name, "Layer" ) ) + flag |= ( short ) EXPP_LAMP_MODE_LAYER; + else if( !strcmp( name, "Quad" ) ) + flag |= ( short ) EXPP_LAMP_MODE_QUAD; + else if( !strcmp( name, "Negative" ) ) + flag |= ( short ) EXPP_LAMP_MODE_NEGATIVE; + else if( !strcmp( name, "OnlyShadow" ) ) + flag |= ( short ) EXPP_LAMP_MODE_ONLYSHADOW; + else if( !strcmp( name, "Sphere" ) ) + flag |= ( short ) EXPP_LAMP_MODE_SPHERE; + else if( !strcmp( name, "Square" ) ) + flag |= ( short ) EXPP_LAMP_MODE_SQUARE; + else if( !strcmp( name, "NoDiffuse" ) ) + flag |= ( short ) EXPP_LAMP_MODE_NODIFFUSE; + else if( !strcmp( name, "NoSpecular" ) ) + flag |= ( short ) EXPP_LAMP_MODE_NOSPECULAR; + else if( !strcmp( name, "RayShadow" ) ) + flag |= ( short ) EXPP_LAMP_MODE_SHAD_RAY; + else + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "unknown lamp flag argument" ); + } + + /* build tuple, call wrapper */ + + value = PyInt_FromLong( (long)flag ); + error = EXPP_setterWrapper ( (void *)self, value, (setter)Lamp_setMode ); + Py_DECREF ( value ); + return error; +} + diff --git a/source/blender/python/api2_2x/Lamp.h b/source/blender/python/api2_2x/Lamp.h new file mode 100644 index 00000000000..3ad6348a152 --- /dev/null +++ b/source/blender/python/api2_2x/Lamp.h @@ -0,0 +1,61 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano, Nathan Letwory + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_LAMP_H +#define EXPP_LAMP_H + +#include +#include "DNA_lamp_types.h" +#include "rgbTuple.h" + +extern PyTypeObject Lamp_Type; + +#define BPy_Lamp_Check(v) \ + ((v)->ob_type == &Lamp_Type) /* for type checking */ + +/* Python BPy_Lamp structure definition */ +typedef struct { + PyObject_HEAD /* required py macro */ + Lamp * lamp; /* libdata must be second */ + BPy_rgbTuple *color; +} BPy_Lamp; + + +/* + * prototypes + */ + +PyObject *Lamp_Init( void ); +PyObject *Lamp_CreatePyObject( struct Lamp *lamp ); +Lamp *Lamp_FromPyObject( PyObject * pyobj ); + +#endif /* EXPP_LAMP_H */ diff --git a/source/blender/python/api2_2x/Lattice.c b/source/blender/python/api2_2x/Lattice.c new file mode 100644 index 00000000000..070e8225531 --- /dev/null +++ b/source/blender/python/api2_2x/Lattice.c @@ -0,0 +1,813 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "Lattice.h" /*This must come first*/ + +#include "BKE_utildefines.h" +#include "BKE_main.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_lattice.h" +#include "BLI_blenlib.h" +#include "DNA_object_types.h" +#include "DNA_key_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_curve_types.h" +#include "DNA_scene_types.h" +#include "BIF_editkey.h" +#include "BIF_editdeform.h" +#include "BIF_space.h" +#include "blendef.h" +#include "gen_utils.h" +#include "gen_library.h" + +#include "Key.h" + +/*****************************************************************************/ +/* Python API function prototypes for the Lattice module. */ +/*****************************************************************************/ +static PyObject *M_Lattice_New( PyObject * self, PyObject * args ); +static PyObject *M_Lattice_Get( PyObject * self, PyObject * args ); + +/*****************************************************************************/ +/* Lattice Module strings */ +/* The following string definitions are used for documentation strings. */ +/* In Python these will be written to the console when doing a */ +/* Blender.Lattice.__doc__ */ +/*****************************************************************************/ +static char M_Lattice_doc[] = "The Blender Lattice module\n\n"; + +static char M_Lattice_New_doc[] = "() - return a new Lattice object"; + +static char M_Lattice_Get_doc[] = "() - get a Lattice from blender"; + +/*****************************************************************************/ +/* Python method structure definition for Blender.Lattice module: */ +/*****************************************************************************/ +struct PyMethodDef M_Lattice_methods[] = { + {"New", ( PyCFunction ) M_Lattice_New, METH_VARARGS, + M_Lattice_New_doc}, + {"Get", ( PyCFunction ) M_Lattice_Get, METH_VARARGS, + M_Lattice_Get_doc}, + {NULL, NULL, 0, NULL} +}; + + +/*****************************************************************************/ +/* Lattice Strings */ +/* The following string definitions are used for documentation strings. */ +/* In Python these will be written to the console when doing a */ +/* Blender.Lattice.__doc__ */ +/*****************************************************************************/ +static char Lattice_getName_doc[] = "() - Return Lattice Object name"; + +static char Lattice_setName_doc[] = "(str) - Change Lattice Object name"; + +static char Lattice_setPartitions_doc[] = + "(str) - Set the number of Partitions in x,y,z"; + +static char Lattice_getPartitions_doc[] = + "(str) - Get the number of Partitions in x,y,z"; + +static char Lattice_getKey_doc[] = + "() - Get the Key object attached to this Lattice"; + +static char Lattice_setKeyTypes_doc[] = + "(str) - Set the key types for x,y,z dimensions"; + +static char Lattice_getKeyTypes_doc[] = + "(str) - Get the key types for x,y,z dimensions"; + +static char Lattice_setMode_doc[] = "(str) - Make an outside or grid lattice"; + +static char Lattice_getMode_doc[] = "(str) - Get lattice mode type"; + +static char Lattice_setPoint_doc[] = + "(str) - Set the coordinates of a point on the lattice"; + +static char Lattice_getPoint_doc[] = + "(str) - Get the coordinates of a point on the lattice"; + +static char Lattice_insertKey_doc[] = + "(str) - Set a new key for the lattice at specified frame"; + +static char Lattice_copy_doc[] = + "() - Return a copy of the lattice."; + +//*************************************************************************** +// Function: Lattice_CreatePyObject +//*************************************************************************** +PyObject *Lattice_CreatePyObject( Lattice * lt ) +{ + BPy_Lattice *pyLat; + + pyLat = ( BPy_Lattice * ) PyObject_NEW( BPy_Lattice, &Lattice_Type ); + + if( !pyLat ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create BPy_Lattice PyObject" ); + + pyLat->lattice = lt; + + return ( PyObject * ) pyLat; +} + +//*************************************************************************** +// Function: Lattice_FromPyObject +//*************************************************************************** + +Lattice *Lattice_FromPyObject( PyObject * pyobj ) +{ + return ( ( BPy_Lattice * ) pyobj )->lattice; +} + +//*************************************************************************** +// Function: M_Lattice_New +// Python equivalent: Blender.Lattice.New +//*************************************************************************** +static PyObject *M_Lattice_New( PyObject * self, PyObject * args ) +{ + char *name = NULL; + Lattice *bl_Lattice; // blender Lattice object + PyObject *py_Lattice; // python wrapper + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected string and int arguments (or nothing)" ); + + bl_Lattice = add_lattice( "Lattice" ); + + if( bl_Lattice ) { + bl_Lattice->id.us = 0; + py_Lattice = Lattice_CreatePyObject( bl_Lattice ); + } else + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't create Lattice Object in Blender" ); + if( !py_Lattice ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create Lattice Object wrapper" ); + + if( name ) + rename_id( &bl_Lattice->id, name ); + + return py_Lattice; +} + +//*************************************************************************** +// Function: M_Lattice_Get +// Python equivalent: Blender.Lattice.Get +//*************************************************************************** +static PyObject *M_Lattice_Get( PyObject * self, PyObject * args ) +{ + char *name = NULL; + Lattice *lat_iter; + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument (or nothing)" ) ); + + lat_iter = G.main->latt.first; + + if( name ) { /* (name) - Search Lattice by name */ + + PyObject *wanted_lat = NULL; + + while( ( lat_iter ) && ( wanted_lat == NULL ) ) { + if( strcmp( name, lat_iter->id.name + 2 ) == 0 ) { + wanted_lat = + Lattice_CreatePyObject( lat_iter ); + } + + lat_iter = lat_iter->id.next; + } + + if( wanted_lat == NULL ) { /* Requested Lattice doesn't exist */ + char error_msg[64]; + PyOS_snprintf( error_msg, sizeof( error_msg ), + "Lattice \"%s\" not found", name ); + return ( EXPP_ReturnPyObjError + ( PyExc_NameError, error_msg ) ); + } + + return wanted_lat; + } + + else { /* () - return a list of all Lattices in the scene */ + int index = 0; + PyObject *latlist, *pyobj; + + latlist = PyList_New( BLI_countlist( &( G.main->latt ) ) ); + + if( latlist == NULL ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyList" ) ); + + while( lat_iter ) { + pyobj = Lattice_CreatePyObject( lat_iter ); + + if( !pyobj ) { + Py_DECREF(latlist); + return ( EXPP_ReturnPyObjError + ( PyExc_MemoryError, + "couldn't create PyString" ) ); + } + PyList_SET_ITEM( latlist, index, pyobj ); + + lat_iter = lat_iter->id.next; + index++; + } + + return ( latlist ); + } +} + +//*************************************************************************** +// Function: Lattice_Init +//*************************************************************************** +PyObject *Lattice_Init( void ) +{ + PyObject *mod; + PyObject *dict; + + if( PyType_Ready( &Lattice_Type ) < 0 ) + return NULL; + + mod = Py_InitModule3( "Blender.Lattice", M_Lattice_methods, + M_Lattice_doc ); + + dict = PyModule_GetDict( mod ); + + //Module dictionary +#define EXPP_ADDCONST(x) EXPP_dict_set_item_str(dict, #x, PyInt_FromLong(LT_##x)) + EXPP_ADDCONST( GRID ); + EXPP_ADDCONST( OUTSIDE ); + +#undef EXPP_ADDCONST +#define EXPP_ADDCONST(x) EXPP_dict_set_item_str(dict, #x, PyInt_FromLong(KEY_##x)) + EXPP_ADDCONST( LINEAR ); + EXPP_ADDCONST( CARDINAL ); + EXPP_ADDCONST( BSPLINE ); + + return ( mod ); +} + +static PyObject *Lattice_setPartitions( BPy_Lattice * self, PyObject * args ) +{ + int x = 0; + int y = 0; + int z = 0; + Lattice *bl_Lattice; + + if( !PyArg_ParseTuple( args, "iii", &x, &y, &z ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int,int,int argument" ) ); + + bl_Lattice = self->lattice; + + if( x < 2 || y < 2 || z < 2 ) + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "partition values must be 2 or greater" ) ); + + resizelattice(bl_Lattice, x, y, z, NULL); + + Py_RETURN_NONE; +} + +static PyObject *Lattice_getPartitions( BPy_Lattice * self ) +{ + Lattice *bl_Lattice; + bl_Lattice = self->lattice; + + return Py_BuildValue( "[i,i,i]", ( int ) bl_Lattice->pntsu, + ( int ) bl_Lattice->pntsv, + ( int ) bl_Lattice->pntsw ); +} + +static PyObject *Lattice_getKey( BPy_Lattice * self ) +{ + Key *key = self->lattice->key; + + if (key) + return Key_CreatePyObject(key); + else + Py_RETURN_NONE; +} + +static PyObject *Lattice_getKeyTypes( BPy_Lattice * self ) +{ + Lattice *bl_Lattice; + char *linear = "linear"; + char *cardinal = "cardinal"; + char *bspline = "bspline"; + char *s_x = NULL, *s_y = NULL, *s_z = NULL; + + bl_Lattice = self->lattice; + + if( ( bl_Lattice->typeu ) == KEY_LINEAR ) + s_x = linear; + else if( ( bl_Lattice->typeu ) == KEY_CARDINAL ) + s_x = cardinal; + else if( ( bl_Lattice->typeu ) == KEY_BSPLINE ) + s_x = bspline; + else + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "bad key type..." ); + + if( ( bl_Lattice->typev ) == KEY_LINEAR ) + s_y = linear; + else if( ( bl_Lattice->typev ) == KEY_CARDINAL ) + s_y = cardinal; + else if( ( bl_Lattice->typev ) == KEY_BSPLINE ) + s_y = bspline; + else + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "bad key type..." ); + + if( ( bl_Lattice->typew ) == KEY_LINEAR ) + s_z = linear; + else if( ( bl_Lattice->typew ) == KEY_CARDINAL ) + s_z = cardinal; + else if( ( bl_Lattice->typew ) == KEY_BSPLINE ) + s_z = bspline; + else + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "bad key type..." ); + + /* we made sure no s_[xyz] is NULL */ + return Py_BuildValue( "[s,s,s]", s_x, s_y, s_z ); +} + +static PyObject *Lattice_setKeyTypes( BPy_Lattice * self, PyObject * args ) +{ + int x; + int y; + int z; + Lattice *bl_Lattice; + + if( !PyArg_ParseTuple( args, "iii", &x, &y, &z ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int,int,int argument" ) ); + + bl_Lattice = self->lattice; + + if( x == KEY_LINEAR ) + bl_Lattice->typeu = KEY_LINEAR; + else if( x == KEY_CARDINAL ) + bl_Lattice->typeu = KEY_CARDINAL; + else if( x == KEY_BSPLINE ) + bl_Lattice->typeu = KEY_BSPLINE; + else + return EXPP_ReturnPyObjError( PyExc_TypeError, + "type must be LINEAR, CARDINAL OR BSPLINE" ); + + if( y == KEY_LINEAR ) + bl_Lattice->typev = KEY_LINEAR; + else if( y == KEY_CARDINAL ) + bl_Lattice->typev = KEY_CARDINAL; + else if( y == KEY_BSPLINE ) + bl_Lattice->typev = KEY_BSPLINE; + else + return EXPP_ReturnPyObjError( PyExc_TypeError, + "type must be LINEAR, CARDINAL OR BSPLINE" ); + + if( z == KEY_LINEAR ) + bl_Lattice->typew = KEY_LINEAR; + else if( z == KEY_CARDINAL ) + bl_Lattice->typew = KEY_CARDINAL; + else if( z == KEY_BSPLINE ) + bl_Lattice->typew = KEY_BSPLINE; + else + return EXPP_ReturnPyObjError( PyExc_TypeError, + "type must be LINEAR, CARDINAL OR BSPLINE" ); + + Py_RETURN_NONE; +} + +static PyObject *Lattice_setMode( BPy_Lattice * self, PyObject * args ) +{ + short type; + Lattice *bl_Lattice; + bl_Lattice = self->lattice; + + if( !PyArg_ParseTuple( args, "h", &type ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument" ) ); + + if( type == LT_GRID ) + bl_Lattice->flag = LT_GRID; + else if( type == LT_OUTSIDE ) { + bl_Lattice->flag = LT_OUTSIDE + LT_GRID; + outside_lattice( bl_Lattice ); + } else + return EXPP_ReturnPyObjError( PyExc_TypeError, + "type must be either GRID or OUTSIDE" ); + + Py_RETURN_NONE; +} + +static PyObject *Lattice_getMode(BPy_Lattice * self) +{ + if( self->lattice->flag == 1 ) + return PyString_FromString( "Grid" ); + else if( self->lattice->flag == 3 ) + return PyString_FromString( "Outside" ); + Py_RETURN_NONE; +} + +static PyObject *Lattice_setPoint( BPy_Lattice * self, PyObject * args ) +{ + BPoint *bp, *bpoint; + short size; + Lattice *bl_Lattice; + int index, x; + float tempInt; + PyObject *listObject; + + if( !PyArg_ParseTuple + ( args, "iO!", &index, &PyList_Type, &listObject ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "expected int & list argument" ) ); + + if( !PyList_Check( listObject ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "2nd parameter should be a python list" ) ); + + if( !( PyList_Size( listObject ) == 3 ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "Please pass 3 parameters in the list [x,y,z]" ) ); + + //init + bp = 0; + bl_Lattice = self->lattice; + + //get bpoints + bp = bl_Lattice->def; + + if( bp == 0 ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "no lattice points!" ) ); + + //calculate size of lattice + size = bl_Lattice->pntsu * bl_Lattice->pntsv * bl_Lattice->pntsw; + + if( index < 0 || index > size ) + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "index outside of lattice size!" ) ); + + //get the bpoint + while( index ) { + index--; + bp++; + } + bpoint = bp; + + for( x = 0; x < PyList_Size( listObject ); x++ ) { + if( ! + ( PyArg_Parse + ( ( PyList_GetItem( listObject, x ) ), "f", + &tempInt ) ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "python list integer not parseable" ); + bpoint->vec[x] = tempInt; + } + + Py_RETURN_NONE; +} + +static PyObject *Lattice_getPoint( BPy_Lattice * self, PyObject * args ) +{ + BPoint *bp, *bpoint; + short size; + Lattice *bl_Lattice; + int index; + + if( !PyArg_ParseTuple( args, "i", &index ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument" ) ); + + //init + bp = 0; + bl_Lattice = self->lattice; + + //get bpoints + bp = bl_Lattice->def; + + if( bp == 0 ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "no lattice points!" ) ); + + //calculate size of lattice + size = bl_Lattice->pntsu * bl_Lattice->pntsv * bl_Lattice->pntsw; + + if( index < 0 || index > size ) + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "index outside of lattice size!" ) ); + + //get the bpoint + while( index ) { + index--; + bp++; + } + bpoint = bp; + + if( bpoint == 0 ) + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "bpoint does not exist" ) ); + + return Py_BuildValue( "[f,f,f]", bp->vec[0], bp->vec[1], bp->vec[2] ); +} + +static PyObject *Lattice_insertKey( BPy_Lattice * self, PyObject * args ) +{ + Lattice *lt; + int frame = -1, oldfra = -1; + + if( !PyArg_ParseTuple( args, "i", &frame ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument" ) ); + + lt = self->lattice; + + //set the current frame + if( frame > 0 ) { + frame = EXPP_ClampInt( frame, 1, MAXFRAME ); + oldfra = G.scene->r.cfra; + G.scene->r.cfra = (int)frame; + } +// else just use current frame, then +// return (EXPP_ReturnPyObjError (PyExc_RuntimeError, +// "frame value has to be greater than 0")); + + //insert a keybock for the lattice (1=relative) + insert_lattkey( lt , 1); + allspace(REMAKEIPO, 0); + + if( frame > 0 ) + G.scene->r.cfra = (int)oldfra; + + Py_RETURN_NONE; +} + +static PyObject *Lattice_copy( BPy_Lattice * self ) +{ + Lattice *bl_Lattice; // blender Lattice object + PyObject *py_Lattice; // python wrapper + + bl_Lattice = copy_lattice( self->lattice ); + bl_Lattice->id.us = 0; + + if( bl_Lattice ) + py_Lattice = Lattice_CreatePyObject( bl_Lattice ); + else + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't create Lattice Object in Blender" ); + if( !py_Lattice ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create Lattice Object wrapper" ); + + return py_Lattice; +} + +static int Lattice_compare( BPy_Lattice * a, BPy_Lattice * b ) +{ + return ( a->lattice == b->lattice ) ? 0 : -1; +} + + +//*************************************************************************** +// Function: Lattice_repr +// Description: This is a callback function for the BPy_Lattice type. It +// builds a meaninful string to represent Lattice objects. +//*************************************************************************** +static PyObject *Lattice_repr( BPy_Lattice * self ) +{ + if( self->lattice ) + return PyString_FromFormat( "[Lattice \"%s\"]", + self->lattice->id.name + 2 ); + else + return PyString_FromString( "[Lattice ]" ); +} + +/*****************************************************************************/ +/* Python BPy_Lattice methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_Lattice_methods[] = { + /* name, method, flags, doc */ + {"getName", ( PyCFunction ) GenericLib_getName, METH_NOARGS, + Lattice_getName_doc}, + {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS, + Lattice_setName_doc}, + {"setPartitions", ( PyCFunction ) Lattice_setPartitions, METH_VARARGS, + Lattice_setPartitions_doc}, + {"getPartitions", ( PyCFunction ) Lattice_getPartitions, METH_NOARGS, + Lattice_getPartitions_doc}, + {"getKey", ( PyCFunction ) Lattice_getKey, METH_NOARGS, + Lattice_getKey_doc}, + {"setKeyTypes", ( PyCFunction ) Lattice_setKeyTypes, METH_VARARGS, + Lattice_setKeyTypes_doc}, + {"getKeyTypes", ( PyCFunction ) Lattice_getKeyTypes, METH_NOARGS, + Lattice_getKeyTypes_doc}, + {"setMode", ( PyCFunction ) Lattice_setMode, METH_VARARGS, + Lattice_setMode_doc}, + {"getMode", ( PyCFunction ) Lattice_getMode, METH_NOARGS, + Lattice_getMode_doc}, + {"setPoint", ( PyCFunction ) Lattice_setPoint, METH_VARARGS, + Lattice_setPoint_doc}, + {"getPoint", ( PyCFunction ) Lattice_getPoint, METH_VARARGS, + Lattice_getPoint_doc}, + {"insertKey", ( PyCFunction ) Lattice_insertKey, METH_VARARGS, + Lattice_insertKey_doc}, + {"__copy__", ( PyCFunction ) Lattice_copy, METH_NOARGS, + Lattice_copy_doc}, + {"copy", ( PyCFunction ) Lattice_copy, METH_NOARGS, + Lattice_copy_doc}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python attributes get/set functions: */ +/*****************************************************************************/ +static PyObject *Lattice_getWidth(BPy_Lattice * self) +{ + return PyInt_FromLong( self->lattice->pntsu ); +} +static PyObject *Lattice_getHeight(BPy_Lattice * self) +{ + return PyInt_FromLong( self->lattice->pntsv ); +} +static PyObject *Lattice_getDepth(BPy_Lattice * self) +{ + return PyInt_FromLong( self->lattice->pntsw ); +} +static PyObject *Lattice_getLatSize(BPy_Lattice * self) +{ + return PyInt_FromLong( + self->lattice->pntsu * self->lattice->pntsv * self->lattice->pntsw ); +} + + +static PyObject *Lattice_getAxisType(BPy_Lattice * self, void * type) +{ + char interp_type = 0; + switch ( (int)type ) { + case 0: + interp_type = self->lattice->typeu; + break; + case 1: + interp_type = self->lattice->typev; + break; + case 2: + interp_type = self->lattice->typew; + break; + } + + switch (interp_type) { + case 0: + return PyString_FromString( "Linear" ); + case 1: + return PyString_FromString( "Cardinal" ); + case 2: + return PyString_FromString( "Bspline" ); + } + Py_RETURN_NONE; +} + +/*****************************************************************************/ +/* Python attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef BPy_Lattice_getseters[] = { + GENERIC_LIB_GETSETATTR, + {"width", (getter)Lattice_getWidth, (setter)NULL, + "lattice U subdivision ", NULL}, + {"height", (getter)Lattice_getHeight, (setter)NULL, + "lattice V subdivision", NULL}, + {"depth", (getter)Lattice_getDepth, (setter)NULL, + "lattice W subdivision", NULL}, + {"latSize", (getter)Lattice_getLatSize, (setter)NULL, + "lattice W subdivision", NULL}, + + {"widthType", (getter)Lattice_getAxisType, NULL, + "lattice U interpolation type", (void *)0}, + {"heightType", (getter)Lattice_getAxisType, NULL, + "lattice V interpolation type", (void *)1}, + {"depthType", (getter)Lattice_getAxisType, NULL, + "lattice W interpolation type", (void *)2}, + + {"key", (getter)Lattice_getKey, NULL, + "lattice key", NULL}, + {"mode", (getter)Lattice_getMode, NULL, + "lattice key", NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/*****************************************************************************/ +/* Python Lattice_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject Lattice_Type = { + PyObject_HEAD_INIT( NULL ) + 0, /* ob_size */ + "Blender Lattice", /* tp_name */ + sizeof( BPy_Lattice ), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + NULL, /* tp_dealloc */ + 0, /* tp_print */ + NULL, /* tp_getattr */ + NULL, /* tp_setattr */ + ( cmpfunc ) Lattice_compare, /* tp_compare */ + ( reprfunc ) Lattice_repr, /* tp_repr */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_Lattice_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_Lattice_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; diff --git a/source/blender/python/api2_2x/Lattice.h b/source/blender/python/api2_2x/Lattice.h new file mode 100644 index 00000000000..fb47c2dd2e4 --- /dev/null +++ b/source/blender/python/api2_2x/Lattice.h @@ -0,0 +1,60 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_Lattice_H +#define EXPP_Lattice_H + +#include +#include "DNA_lattice_types.h" + +/* The Group PyTypeObject defined in Lattice.c */ +extern PyTypeObject Lattice_Type; + +#define BPy_Lattice_Check(v) ((v)->ob_type == &Lattice_Type) + +/*****************************************************************************/ +/* Python BPy_Lattice structure definition: */ +/*****************************************************************************/ +typedef struct { + PyObject_HEAD + Lattice * lattice; /* libdata must be second */ +} BPy_Lattice; + +/* + * prototypes + */ + +PyObject *Lattice_Init( void ); +PyObject *Lattice_CreatePyObject( Lattice * lt ); +Lattice *Lattice_FromPyObject( PyObject * pyobj ); + +#endif /* EXPP_LATTICE_H */ diff --git a/source/blender/python/api2_2x/Library.c b/source/blender/python/api2_2x/Library.c new file mode 100644 index 00000000000..1aacaf56786 --- /dev/null +++ b/source/blender/python/api2_2x/Library.c @@ -0,0 +1,1192 @@ +/** + * $Id$ + * + * Blender.Library BPython module implementation. + * This submodule has functions to append data from .blend files. + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano, Campbell Barton, Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +/************************************************************/ +/* Original library module code */ +/************************************************************/ + +#include + +#include "DNA_curve_types.h" +#include "DNA_object_types.h" +#include "DNA_space_types.h" /* for line linked */ +#include "BKE_library.h" /* for all_local */ +#include "BKE_font.h" /* for text_to_curve */ +#include "BKE_utildefines.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BLI_blenlib.h" +#include "BLO_readfile.h" +#include "BLI_linklist.h" +#include "MEM_guardedalloc.h" +#include "gen_utils.h" + +/** + * Global variables. + */ +static BlendHandle *bpy_openlib = NULL; /* ptr to the open .blend file */ +static char *bpy_openlibname = NULL; /* its pathname */ +static int bpy_relative= 0; + +/** + * Function prototypes for the Library submodule. + */ +static PyObject *M_Library_Open( PyObject * self, PyObject * args ); +static PyObject *M_Library_Close( PyObject * self ); +static PyObject *M_Library_GetName( PyObject * self ); +static PyObject *M_Library_Update( PyObject * self ); +static PyObject *M_Library_Datablocks( PyObject * self, PyObject * value ); +static PyObject *oldM_Library_Load( PyObject * self, PyObject * args ); +static PyObject *M_Library_LinkableGroups( PyObject * self ); +static PyObject *M_Library_LinkedLibs( PyObject * self ); + +PyObject *Library_Init( void ); +void EXPP_Library_Close( void ); + +/** + * Module doc strings. + */ +static char M_Library_doc[] = "The Blender.Library submodule:\n\n\ +This module gives access to .blend files, using them as libraries of\n\ +data that can be loaded into the current scene in Blender."; + +static char Library_Open_doc[] = + "(filename) - Open the given .blend file for access to its objects.\n\ +If another library file is still open, it's closed automatically."; + +static char Library_Close_doc[] = + "() - Close the currently open library file, if any."; + +static char Library_GetName_doc[] = + "() - Get the filename of the currently open library file, if any."; + +static char Library_Datablocks_doc[] = + "(datablock) - List all datablocks of the given type in the currently\n\ +open library file.\n\ +(datablock) - datablock name as a string: Object, Mesh, etc."; + +static char Library_Load_doc[] = + "(name, datablock [,update = 1]) - Append object 'name' of type 'datablock'\n\ +from the open library file to the current scene.\n\ +(name) - (str) the name of the object.\n\ +(datablock) - (str) the datablock of the object.\n\ +(update = 1) - (int) if non-zero, all display lists are recalculated and the\n\ +links are updated. This is slow, set it to zero if you have more than one\n\ +object to load, then call Library.Update() after loading them all."; + +static char Library_Update_doc[] = + "() - Update the current scene, linking all loaded library objects and\n\ +remaking all display lists. This is slow, call it only once after loading\n\ +all objects (load each of them with update = 0:\n\ +Library.Load(name, datablock, 0), or the update will be automatic, repeated\n\ +for each loaded object."; + +static char Library_LinkableGroups_doc[] = + "() - Get all linkable groups from the open .blend library file."; + +static char Library_LinkedLibs_doc[] = + "() - Get all libs used in the the open .blend file."; + +/** + * Python method structure definition for Blender.Library submodule. + */ +struct PyMethodDef oldM_Library_methods[] = { + {"Open", M_Library_Open, METH_O, Library_Open_doc}, + {"Close", ( PyCFunction ) M_Library_Close, METH_NOARGS, + Library_Close_doc}, + {"GetName", ( PyCFunction ) M_Library_GetName, METH_NOARGS, + Library_GetName_doc}, + {"Update", ( PyCFunction ) M_Library_Update, METH_NOARGS, + Library_Update_doc}, + {"Datablocks", M_Library_Datablocks, METH_O, + Library_Datablocks_doc}, + {"Load", oldM_Library_Load, METH_VARARGS, Library_Load_doc}, + {"LinkableGroups", ( PyCFunction ) M_Library_LinkableGroups, + METH_NOARGS, Library_LinkableGroups_doc}, + {"LinkedLibs", ( PyCFunction ) M_Library_LinkedLibs, + METH_NOARGS, Library_LinkedLibs_doc}, + {NULL, NULL, 0, NULL} +}; + +/* Submodule Python functions: */ + +/** + * Open a new .blend file. + * Only one can be open at a time, so this function also closes + * the previously opened file, if any. + */ +static PyObject *M_Library_Open( PyObject * self, PyObject * value ) +{ + char *fname = PyString_AsString(value); + char filename[FILE_MAXDIR+FILE_MAXFILE]; + char fname1[FILE_MAXDIR+FILE_MAXFILE]; + + int len = 0; + + bpy_relative= 0; /* assume non relative each time we load */ + + if( !fname ) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a .blend filename" ); + } + + if( bpy_openlib ) { + M_Library_Close( self ); + Py_DECREF( Py_None ); /* incref'ed by above function */ + } + + /* copy the name to make it absolute so BLO_blendhandle_from_file doesn't complain */ + BLI_strncpy(fname1, fname, sizeof(fname1)); + BLI_convertstringcode(fname1, G.sce, 0); /* make absolute */ + + /* G.sce = last file loaded, save for UI and restore after opening file */ + BLI_strncpy(filename, G.sce, sizeof(filename)); + bpy_openlib = BLO_blendhandle_from_file( fname1 ); + BLI_strncpy(G.sce, filename, sizeof(filename)); + + if( !bpy_openlib ) + return EXPP_ReturnPyObjError( PyExc_IOError, "file not found" ); + + /* "//someblend.blend" enables relative paths */ + if (sizeof(fname) > 2 && fname[0] == '/' && fname[1] == '/') + bpy_relative= 1; /* global that makes the library relative on loading */ + + len = strlen( fname1 ) + 1; /* +1 for terminating '\0' */ + + bpy_openlibname = MEM_mallocN( len, "bpy_openlibname" ); + + if( bpy_openlibname ) + PyOS_snprintf( bpy_openlibname, len, "%s", fname1 ); + + Py_RETURN_TRUE; +} + +/** + * Close the current .blend file, if any. + */ +static PyObject *M_Library_Close( PyObject * self ) +{ + if( bpy_openlib ) { + BLO_blendhandle_close( bpy_openlib ); + bpy_openlib = NULL; + } + + if( bpy_openlibname ) { + MEM_freeN( bpy_openlibname ); + bpy_openlibname = NULL; + } + + Py_RETURN_NONE; +} + +/** + * helper function for 'atexit' clean-ups, used by BPY_end_python, + * declared in EXPP_interface.h. + */ +void EXPP_Library_Close( void ) +{ + if( bpy_openlib ) { + BLO_blendhandle_close( bpy_openlib ); + bpy_openlib = NULL; + } + + if( bpy_openlibname ) { + MEM_freeN( bpy_openlibname ); + bpy_openlibname = NULL; + } +} + +/** + * Get the filename of the currently open library file, if any. + */ +static PyObject *M_Library_GetName( PyObject * self ) +{ + if( bpy_openlib && bpy_openlibname ) + return Py_BuildValue( "s", bpy_openlibname ); + + Py_INCREF( Py_None ); + return Py_None; +} + +/** + * Return a list with all items of a given datablock type + * (like 'Object', 'Mesh', etc.) in the open library file. + */ +static PyObject *M_Library_Datablocks( PyObject * self, PyObject * value ) +{ + char *name = PyString_AsString(value); + int blocktype = 0; + LinkNode *l = NULL, *names = NULL; + PyObject *list = NULL; + + if( !bpy_openlib ) { + return EXPP_ReturnPyObjError( PyExc_IOError, + "no library file: open one first with Blender.Lib_Open(filename)" ); + } + + if( !name ) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a string (datablock type) as argument." ); + } + + blocktype = ( int ) BLO_idcode_from_name( name ); + + if( !blocktype ) { + return EXPP_ReturnPyObjError( PyExc_NameError, + "no such Blender datablock type" ); + } + + names = BLO_blendhandle_get_datablock_names( bpy_openlib, blocktype ); + + if( names ) { + int counter = 0; + list = PyList_New( BLI_linklist_length( names ) ); + for( l = names; l; l = l->next ) { + PyList_SET_ITEM( list, counter, + PyString_FromString( ( char * ) l->link ) ); + counter++; + } + BLI_linklist_free( names, free ); /* free linklist *and* each node's data */ + return list; + } + + Py_RETURN_NONE; +} + +/** + * Return a list with the names of all linkable groups in the + * open library file. + */ +static PyObject *M_Library_LinkableGroups( PyObject * self ) +{ + LinkNode *l = NULL, *names = NULL; + PyObject *list = NULL; + + if( !bpy_openlib ) { + return EXPP_ReturnPyObjError( PyExc_IOError, + "no library file: open one first with Blender.Lib_Open(filename)" ); + } + + names = BLO_blendhandle_get_linkable_groups( bpy_openlib ); + list = PyList_New( BLI_linklist_length( names ) ); + + if( names ) { + int counter = 0; + + for( l = names; l; l = l->next ) { + PyList_SET_ITEM( list, counter, PyString_FromString( ( char * ) l->link ) ); + counter++; + } + BLI_linklist_free( names, free ); /* free linklist *and* each node's data */ + return list; + } + return list; +} + +/** + * Return a list with the names of all externally linked libs used in the current Blend file + */ +static PyObject *M_Library_LinkedLibs( PyObject * self ) +{ + int counter = 0; + Library *li; + PyObject *list; + + list = PyList_New( BLI_countlist( &( G.main->library ) ) ); + for (li= G.main->library.first; li; li= li->id.next) { + PyList_SET_ITEM( list, counter, PyString_FromString( li->name )); + counter++; + } + return list; +} + +/** + * Load (append) a given datablock of a given datablock type + * to the current scene. + */ +static PyObject *oldM_Library_Load( PyObject * self, PyObject * args ) +{ + char *name = NULL; + char *base = NULL; + int update = 1; + int blocktype = 0; + int linked = 0; + + if( !bpy_openlib ) { + return EXPP_ReturnPyObjError( PyExc_IOError, + "no library file: you need to open one, first." ); + } + + if( !PyArg_ParseTuple( args, "ss|ii", &name, &base, &update, &linked ) ) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected two strings as arguments." ); + } + + blocktype = ( int ) BLO_idcode_from_name( base ); + + if( !blocktype ) + return EXPP_ReturnPyObjError( PyExc_NameError, + "no such Blender datablock type" ); + + if (linked) + BLO_script_library_append( bpy_openlib, bpy_openlibname, name, blocktype, FILE_LINK, G.scene); + else + BLO_script_library_append( bpy_openlib, bpy_openlibname, name, blocktype, 0, G.scene); + + if( update ) { + M_Library_Update( self ); + Py_DECREF( Py_None ); /* incref'ed by above function */ + } + + if( bpy_relative ) { + /* and now find the latest append lib file */ + Library *lib = G.main->library.first; + while( lib ) { + if( strcmp( bpy_openlibname, lib->name ) == 0 ) { + + /* use the full path, this could have been read by other library even */ + BLI_strncpy(lib->name, lib->filename, sizeof(lib->name)); + + /* uses current .blend file as reference */ + BLI_makestringcode(G.sce, lib->name); + break; + } + lib = lib->id.next; + } + + } + + Py_INCREF( Py_None ); + return Py_None; +} + +/** + * Update all links and remake displists. + */ +static PyObject *M_Library_Update( PyObject * self ) +{ /* code adapted from do_library_append in src/filesel.c: */ + Library *lib = NULL; + + /* Displist code that was here is obsolete... depending on what + * this function is supposed to do (it should technically be unnecessary) + * can be replaced with depgraph calls - zr + */ + + if( bpy_openlibname ) { + strcpy( G.lib, bpy_openlibname ); + + /* and now find the latest append lib file */ + lib = G.main->library.first; + while( lib ) { + if( strcmp( bpy_openlibname, lib->name ) == 0 ) + break; + lib = lib->id.next; + } + all_local( lib, 0 ); + } + + Py_INCREF( Py_None ); + return Py_None; +} + +/** + * Initialize the Blender.Library submodule. + * Called by Blender_Init in Blender.c . + * @return the registered submodule. + */ +PyObject *oldLibrary_Init( void ) +{ + PyObject *submod; + + submod = Py_InitModule3( "Blender.Library", oldM_Library_methods, + M_Library_doc ); + + return submod; +} + +/************************************************************/ +/* New library (LibData) module code */ +/************************************************************/ + +#include "Library.h" + +/* if this module supercedes the old library module, include these instead */ +#if 0 +#include "BLI_blenlib.h" +#include "MEM_guardedalloc.h" + +#include "DNA_curve_types.h" +#include "DNA_object_types.h" +#include "DNA_space_types.h" /* for line linked */ +#include "BKE_library.h" /* for all_local */ +#include "BKE_utildefines.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BLO_readfile.h" +#include "BLI_linklist.h" + +#include "Object.h" +#include "gen_utils.h" +#endif + +#include "gen_library.h" + +/* Helper function */ + +/* + * Try to open a library, set Python exceptions as necessary if not + * successful. On success, return a valid handle; othewise return NULL. + */ + +static BlendHandle *open_library( char *filename, char *longFilename ) +{ + char globalFilename[FILE_MAX]; + BlendHandle *openlib = NULL; + + /* get complete file name if necessary */ + BLI_strncpy( longFilename, filename, FILE_MAX ); + BLI_convertstringcode( longFilename, G.sce, 0 ); + + /* throw exceptions for wrong file type, cyclic reference */ + if( !BLO_has_bfile_extension(longFilename) ) { + PyErr_SetString( PyExc_ValueError, "file not a library" ); + return NULL; + } + if( BLI_streq(G.main->name, longFilename) ) { + PyErr_SetString( PyExc_ValueError, + "cannot use current file as library" ); + return NULL; + } + + /* G.sce = last file loaded, save for UI and restore after opening file */ + BLI_strncpy(globalFilename, G.sce, sizeof(globalFilename)); + openlib = BLO_blendhandle_from_file( longFilename ); + BLI_strncpy(G.sce, globalFilename, sizeof(globalFilename)); + + /* if failed, set that exception code too */ + if( !openlib ) + PyErr_SetString( PyExc_IOError, "library not found" ); + + return openlib; +} + +/* + * Create a specific type of LibraryData object. These are used for + * .append() and .link() access, for iterators, and (for Blender Objects) + * for defining "pseudo objects" for scene linking. + */ + +static PyObject *CreatePyObject_LibData( int idtype, int kind, + void *name, void *iter, char *filename ) +{ + BPy_LibraryData *seq = PyObject_NEW( BPy_LibraryData, &LibraryData_Type); + seq->iter = iter; /* the name list (for iterators) */ + seq->type = idtype; /* the Blender ID type */ + seq->kind = kind; /* used by Blender Objects */ + seq->name = name; /* object name, iterator name list, or NULL */ + /* save the library name */ + BLI_strncpy( seq->filename, filename, strlen(filename)+1 ); + return (PyObject *)seq; +} + +/* + * Link/append data to the current .blend file, or create a pseudo object + * which can be linked/appended to a scene. + */ + +static PyObject *lib_link_or_append( BPy_LibraryData *self, PyObject * value, + int mode ) +{ + char *name = PyString_AsString(value); + + /* get the name of the data used wants to append */ + if( !name ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a string" ); + + /* + * For everything except objects, just add to Blender's DB. For objects, + * create an APPEND or LINK "pseudo object" for the Scene module. + */ + if( self->type != ID_OB ) + return LibraryData_importLibData( self, name, 0, NULL ); + else { + /* + * If this is already a pseudo object, throw an exception: re-linking + * or re-appending is not allowed + */ + if( self->kind != OTHER ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "object has already been marked for append or link" ); + + /* otherwise, create a pseudo object ready for appending or linking */ + + return CreatePyObject_LibData( ID_OB, mode, + BLI_strdupn( name, strlen( name ) ), NULL, self->filename ); + } +} + +/* + * Perform the actual link or append operation. This procedure is also + * called externally from the Scene module using a "pseudo Object" so we + * can be sure objects get linked to a scene. + */ + +PyObject *LibraryData_importLibData( BPy_LibraryData *self, char *name, + int mode, Scene *scene ) +{ + char longFilename[FILE_MAX]; + BlendHandle *openlib; + Library *lib; + LinkNode *names, *ptr; + ID *id; + ListBase *lb; + char newName[32]; + + /* try to open the library */ + openlib = open_library( self->filename, longFilename ); + if( !openlib ) + return NULL; + + /* find all datablocks for the specified type */ + names = BLO_blendhandle_get_datablock_names ( openlib, self->type ); + + /* now check for a match to the user-specified name */ + for( ptr = names; ptr; ptr = ptr->next ) + if( strcmp( ptr->link, name ) == 0 ) break; + BLI_linklist_free( names, free ); + + /* if no match, throw exception */ + if( !ptr ) { + BLO_blendhandle_close( openlib ); + return EXPP_ReturnPyObjError( PyExc_ValueError, + "library does not contain specified item" ); + } + + /* + * Figure out what the datablock will be named after it's imported. If + * it's a link, nothing to do. If it's an append, find what it might + * be renamed to. + */ + + if( mode != FILE_LINK ) { + flag_all_listbases_ids(LIB_APPEND_TAG, 1); + + /* see what new block will be called */ + strncpy( newName, name, strlen(name)+1 ); + check_for_dupid( wich_libbase(G.main, self->type), NULL, newName ); + } + + /* import from the libary */ + BLO_script_library_append( openlib, longFilename, name, self->type, mode, + scene ); + + /* + * locate the library. If this is an append, make the data local. If it + * is link, we need the library for later + */ + for( lib = G.main->library.first; lib; lib = lib->id.next ) + if( strcmp( longFilename, lib->name ) == 0 ) { + if( mode != FILE_LINK ) { + all_local( lib, 1 ); + /* important we unset, otherwise these object wont + * link into other scenes from this blend file */ + flag_all_listbases_ids(LIB_APPEND_TAG, 0); + } + break; + } + + /* done with library; close it */ + BLO_blendhandle_close( openlib ); + + /* this should not happen, but just in case */ + if( !lib ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "could not library" ); + + /* find the base for this type */ + lb = wich_libbase( G.main, self->type ); + + /* + * Check for linked data matching the name first. Even if we are trying + * to append, if the data has already been linked we need to return it + * (it won't be appended from the library). + */ + for( id = lb->first; id; id = id->next ) { + if( id->lib == lib && id->name[2]==name[0] && + strcmp(id->name+2, name)==0 ) + return GetPyObjectFromID( id ); + } + + /* + * If we didn't find it, and we're appending, then try searching for the + * new datablock, possibly under a new name. + */ + if( mode != FILE_LINK ) + for( id = lb->first; id; id = id->next ) { + if( id->lib == NULL && id->name[2]==newName[0] && + strcmp(id->name+2, newName)==0 ) + return GetPyObjectFromID( id ); + } + + /* if we get here, something's really wrong */ + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "could not find data after reading from library" ); +} + +/************************************************************ + * Python LibraryData_Type getseters + ************************************************************/ + +/* .append(): make a local copy of the library's data (except for objects) */ + +static PyObject *LibraryData_getAppend( BPy_LibraryData *self, PyObject * value) +{ + return lib_link_or_append( self, value, OBJECT_IS_APPEND ); +} + +/* .link(): make a link to the library's data (except for objects) */ + +static PyObject *LibraryData_getLink( BPy_LibraryData *self, PyObject * value) +{ + return lib_link_or_append( self, value, OBJECT_IS_LINK ); +} + +/************************************************************************ + * Python LibraryData_Type iterator + ************************************************************************/ + +/* Create and initialize the interator indices */ + +static PyObject *LibraryData_getIter( BPy_LibraryData * self ) +{ + char longFilename[FILE_MAX]; + BlendHandle *openlib; + LinkNode *names; + + /* try to open library */ + openlib = open_library( self->filename, longFilename ); + + /* if failed, return exception */ + if( !openlib ) + return NULL; + + /* find all datablocks for the specified type */ + names = BLO_blendhandle_get_datablock_names ( openlib, self->type ); + + /* close library*/ + BLO_blendhandle_close( openlib ); + + /* build an iterator object for the name list */ + return CreatePyObject_LibData( self->type, OTHER, names, + names, self->filename ); +} + +/* Return next name. */ + +static PyObject *LibraryData_nextIter( BPy_LibraryData * self ) +{ + LinkNode *ptr = (LinkNode *)self->iter; + PyObject *ob; + + /* if at the end of list, clean up */ + if( !ptr ) { + /* If name list is still allocated, free storage. This check is + * necessary since iter.next() can technically be called repeatedly */ + if( self->name ) { + BLI_linklist_free( (LinkNode *)self->name, free ); + self->name = NULL; + } + return EXPP_ReturnPyObjError( PyExc_StopIteration, + "iterator at end" ); + } + + /* otherwise, return the next name in the list */ + ob = PyString_FromString( ptr->link ); + ptr = ptr->next; + self->iter = ptr; + return ob; +} + +/************************************************************************ + * Python LibraryData_type methods structure + ************************************************************************/ + +static struct PyMethodDef BPy_LibraryData_methods[] = { + {"append", (PyCFunction)LibraryData_getAppend, METH_O, + "(str) - create new data from library"}, + {"link", (PyCFunction)LibraryData_getLink, METH_O, + "(str) - link data from library"}, + {NULL, NULL, 0, NULL} +}; + +/* Deallocate object and its data */ + +static void LibraryData_dealloc( BPy_LibraryData * self ) +{ + if( self->name ) + MEM_freeN( self->name ); + + PyObject_DEL( self ); +} + +/* Display representation of what Library Data is wrapping */ + +static PyObject *LibraryData_repr( BPy_LibraryData * self ) +{ + char *linkstate = ""; + char *str; + + switch (self->type) { + case ID_OB: + /* objects can be lib data or pseudo objects */ + switch( self->kind ) { + case OBJECT_IS_APPEND : + linkstate = ", appended"; + break; + case OBJECT_IS_LINK : + linkstate = ", linked"; + break; + default: + break; + } + str = "Object"; + break; + case ID_SCE: + str = "Scene"; + break; + case ID_ME: + str = "Mesh"; + break; + case ID_CU: + str = "Curve"; + break; + case ID_MB: + str = "Metaball"; + break; + case ID_MA: + str = "Material"; + break; + case ID_TE: + str = "Texture"; + break; + case ID_IM: + str = "Image"; + break; + case ID_LT: + str = "Lattice"; + break; + case ID_LA: + str = "Lamp"; + break; + case ID_CA: + str = "Camera"; + break; + case ID_IP: + str = "Ipo"; + break; + case ID_WO: + str = "World"; + break; + case ID_VF: + str = "Font"; + break; + case ID_TXT: + str = "Text"; + break; + case ID_SO: + str = "Sound"; + break; + case ID_GR: + str = "Group"; + break; + case ID_AR: + str = "Armature"; + break; + case ID_AC: + str = "Action"; + break; + default: + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "unsupported ID type" ); + } + + return PyString_FromFormat( "[Library Data (%s%s)]", str, linkstate ); +} + +PyTypeObject LibraryData_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender LibData", /* char *tp_name; */ + sizeof( BPy_LibraryData ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + ( destructor ) LibraryData_dealloc,/* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) NULL, /* cmpfunc tp_compare; */ + ( reprfunc ) LibraryData_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + (getiterfunc)LibraryData_getIter, /* getiterfunc tp_iter; */ + (iternextfunc)LibraryData_nextIter, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_LibraryData_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + NULL, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +/* + * Create a LibraryData object for a specific type of Blender Group (ID_OB, + * ID_MA, etc). These can then be used to link or append the data. + */ + +static PyObject *LibraryData_CreatePyObject( BPy_Library *self, void *mode ) +{ + return CreatePyObject_LibData( (int)mode, OTHER, NULL, NULL, + self->filename ); +} + +/************************************************************ + * Python Library_Type getseters + ************************************************************/ + +/* + * Return the library's filename. + */ + +static PyObject *Library_getFilename( BPy_Library * self ) +{ + return PyString_FromString( self->filename ); +} + +/* + * Set/change the library's filename. + */ + +static int Library_setFilename( BPy_Library * self, PyObject * args ) +{ + char *filename = PyString_AsString( args ); + if( !filename ) + return EXPP_ReturnIntError( PyExc_TypeError, "expected a string" ); + + BLI_strncpy( self->filename, filename, sizeof(self->filename) ); + return 0; +} + +/************************************************************************ + * Python Library_type attributes get/set structure + ************************************************************************/ + +static PyGetSetDef Library_getseters[] = { + {"filename", + (getter)Library_getFilename, (setter)Library_setFilename, + "library filename", + NULL}, + {"objects", + (getter)LibraryData_CreatePyObject, (setter)NULL, + "objects from the library", + (void *)ID_OB}, + {"scenes", + (getter)LibraryData_CreatePyObject, (setter)NULL, + "scenes from the library", + (void *)ID_SCE}, + {"meshes", + (getter)LibraryData_CreatePyObject, (setter)NULL, + "meshes from the library", + (void *)ID_ME}, + {"curves", + (getter)LibraryData_CreatePyObject, (setter)NULL, + "curves from the library", + (void *)ID_CU}, + {"metaballs", + (getter)LibraryData_CreatePyObject, (setter)NULL, + "metaballs from the library", + (void *)ID_MB}, + {"lattices", + (getter)LibraryData_CreatePyObject, (setter)NULL, + "lattices from the library", + (void *)ID_LT}, + {"lamps", + (getter)LibraryData_CreatePyObject, (setter)NULL, + "lamps from the library", + (void *)ID_LA}, + {"cameras", + (getter)LibraryData_CreatePyObject, (setter)NULL, + "cameras from the library", + (void *)ID_CA}, + {"materials", + (getter)LibraryData_CreatePyObject, (setter)NULL, + "objects from the library", + (void *)ID_MA}, + {"textures", + (getter)LibraryData_CreatePyObject, (setter)NULL, + "textures from the library", + (void *)ID_TE}, + {"images", + (getter)LibraryData_CreatePyObject, (setter)NULL, + "images from the library", + (void *)ID_IM}, + {"ipos", + (getter)LibraryData_CreatePyObject, (setter)NULL, + "ipos from the library", + (void *)ID_IP}, + {"worlds", + (getter)LibraryData_CreatePyObject, (setter)NULL, + "worlds from the library", + (void *)ID_WO}, + {"fonts", + (getter)LibraryData_CreatePyObject, (setter)NULL, + "fonts from the library", + (void *)ID_VF}, + {"texts", + (getter)LibraryData_CreatePyObject, (setter)NULL, + "texts from the library", + (void *)ID_TXT}, + {"groups", + (getter)LibraryData_CreatePyObject, (setter)NULL, + "groups from the library", + (void *)ID_GR}, + {"sounds", + (getter)LibraryData_CreatePyObject, (setter)NULL, + "sounds from the library", + (void *)ID_SO}, + {"actions", + (getter)LibraryData_CreatePyObject, (setter)NULL, + "actions from the library", + (void *)ID_AC}, + {"armatures", + (getter)LibraryData_CreatePyObject, (setter)NULL, + "armatures from the library", + (void *)ID_AR}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/* + * Define a new library and create a library object. We don't actually test + * if the library is valid here since we have to do it when the file is + * actually accessed later. + */ + +static PyObject *M_Library_Load(PyObject *self, PyObject * value) +{ + char *filename = PyString_AsString(value); + BPy_Library *lib; + + if( !filename ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a string" ); + + /* try to create a new object */ + lib = (BPy_Library *)PyObject_NEW( BPy_Library, &Library_Type ); + if( !lib ) + return NULL; + + /* assign the library filename for future use, then return */ + BLI_strncpy( lib->filename, filename, sizeof(lib->filename) ); + + return (PyObject *)lib; +} + +static struct PyMethodDef M_Library_methods[] = { + {"load", (PyCFunction)M_Library_Load, METH_O, + "(string) - declare a .blend file for use as a library"}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python Library_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject Library_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender Library", /* char *tp_name; */ + sizeof( BPy_Library ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) NULL, /* cmpfunc tp_compare; */ + ( reprfunc ) NULL, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + NULL, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + Library_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +/* + * Library module initialization + */ + +static char M_newLibrary_doc[] = "The Blender.lib submodule"; + +PyObject *Library_Init( void ) +{ + PyObject *submodule; + + if( PyType_Ready( &Library_Type ) < 0 ) + return NULL; + if( PyType_Ready( &LibraryData_Type ) < 0 ) + return NULL; + + submodule = Py_InitModule3( "Blender.lib", M_Library_methods, + M_newLibrary_doc ); + return submodule; +} diff --git a/source/blender/python/api2_2x/Library.h b/source/blender/python/api2_2x/Library.h new file mode 100644 index 00000000000..4814bf1410c --- /dev/null +++ b/source/blender/python/api2_2x/Library.h @@ -0,0 +1,78 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_LIBRARY_H +#define EXPP_LIBRARY_H + +#include +#include "DNA_scene_types.h" +#include "BLI_linklist.h" + +#include "blendef.h" + +/*****************************************************************************/ +/* Python BPy_Library structure definition: */ +/*****************************************************************************/ +typedef struct { + PyObject_HEAD + char filename[FILE_MAXDIR + FILE_MAXFILE]; +} BPy_Library; + +typedef struct { + PyObject_HEAD + LinkNode *iter; + int type; + char filename[FILE_MAXDIR + FILE_MAXFILE]; + char *name; + enum { + OBJECT_IS_LINK, + OBJECT_IS_APPEND, + OTHER + } kind; +} BPy_LibraryData; + +extern PyTypeObject Library_Type; +extern PyTypeObject LibraryData_Type; + +#define BPy_LibraryData_Check(v) ((v)->ob_type == &LibraryData_Type) +#define BPy_Library_Check(v) ((v)->ob_type == &Library_Type) + +/*****************************************************************************/ +/* Module Blender.Library - public functions */ +/*****************************************************************************/ +PyObject *Library_Init( void ); +PyObject *oldLibrary_Init( void ); + +PyObject *LibraryData_importLibData( BPy_LibraryData *self, char *name, + int mode, Scene *scene ); + +#endif /* EXPP_LIBRARY_H */ diff --git a/source/blender/python/api2_2x/MTex.c b/source/blender/python/api2_2x/MTex.c new file mode 100644 index 00000000000..4f7cff35c11 --- /dev/null +++ b/source/blender/python/api2_2x/MTex.c @@ -0,0 +1,827 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Alex Mole, Yehoshua Sapir + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ +#include "MTex.h" /*This must come first*/ + +#include "BKE_utildefines.h" +#include "BLI_blenlib.h" +#include "Texture.h" +#include "Object.h" +#include "gen_utils.h" +#include "gen_library.h" + +#include + +/*****************************************************************************/ +/* Python BPy_MTex methods declarations: */ +/*****************************************************************************/ +static PyObject *MTex_setTexMethod( BPy_MTex * self, PyObject * args ); + +/*****************************************************************************/ +/* Python method structure definition for Blender.Texture.MTex module: */ +/*****************************************************************************/ +struct PyMethodDef M_MTex_methods[] = { + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python BPy_MTex methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_MTex_methods[] = { + /* name, method, flags, doc */ + {"setTex", ( PyCFunction ) MTex_setTexMethod, METH_VARARGS, + "(i) - Set MTex Texture"}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python MTex_Type callback function prototypes: */ +/*****************************************************************************/ +static int MTex_compare( BPy_MTex * a, BPy_MTex * b ); +static PyObject *MTex_repr( BPy_MTex * self ); + +#define MTEXGET(x) \ + static PyObject *MTex_get##x( BPy_MTex *self, void *closure ); +#define MTEXSET(x) \ + static int MTex_set##x( BPy_MTex *self, PyObject *value, void *closure); +#define MTEXGETSET(x) \ + MTEXGET(x) \ + MTEXSET(x) + +MTEXGETSET(Tex) +MTEXGETSET(TexCo) +MTEXGETSET(Object) +MTEXGETSET(UVLayer) +MTEXGETSET(MapTo) +MTEXGETSET(Col) +MTEXGETSET(DVar) +MTEXGETSET(BlendMode) +MTEXGETSET(ColFac) +MTEXGETSET(NorFac) +MTEXGETSET(VarFac) +MTEXGETSET(DispFac) +MTEXGETSET(WarpFac) +MTEXGETSET(Ofs) +MTEXGETSET(Size) +MTEXGETSET(Mapping) +MTEXGETSET(Flag) +MTEXGETSET(ProjX) +MTEXGETSET(ProjY) +MTEXGETSET(ProjZ) +MTEXGETSET(MapToFlag) + +/*****************************************************************************/ +/* Python get/set methods table */ +/*****************************************************************************/ + +static PyGetSetDef MTex_getseters[] = { + { "tex", (getter) MTex_getTex, (setter) MTex_setTex, + "Texture whose mapping this MTex describes", NULL }, + { "texco", (getter) MTex_getTexCo, (setter) MTex_setTexCo, + "Texture coordinate space (UV, Global, etc.)", NULL }, + { "object", (getter) MTex_getObject, (setter) MTex_setObject, + "Object whose space to use when texco is Object", NULL }, + { "uvlayer", (getter) MTex_getUVLayer, (setter) MTex_setUVLayer, + "Name of the UV layer to use", NULL }, + { "mapto", (getter) MTex_getMapTo, (setter) MTex_setMapTo, + "What values the texture affects", NULL }, + { "col", (getter) MTex_getCol, (setter) MTex_setCol, + "Color that the texture blends with", NULL }, + { "dvar", (getter) MTex_getDVar, (setter) MTex_setDVar, + "Value that the texture blends with when not blending colors", NULL }, + { "blendmode", (getter) MTex_getBlendMode, (setter) MTex_setBlendMode, + "Texture blending mode", NULL }, + { "colfac", (getter) MTex_getColFac, (setter) MTex_setColFac, + "Factor by which texture affects color", NULL }, + { "norfac", (getter) MTex_getNorFac, (setter) MTex_setNorFac, + "Factor by which texture affects normal", NULL }, + { "varfac", (getter) MTex_getVarFac, (setter) MTex_setVarFac, + "Factor by which texture affects most variables", NULL }, + { "dispfac", (getter) MTex_getDispFac, (setter) MTex_setDispFac, + "Factor by which texture affects displacement", NULL }, + { "warpfac", (getter) MTex_getWarpFac, (setter) MTex_setWarpFac, + "Factor by which texture affects warp", NULL }, + { "ofs", (getter) MTex_getOfs, (setter) MTex_setOfs, + "Offset to adjust texture space", NULL }, + { "size", (getter) MTex_getSize, (setter) MTex_setSize, + "Size to scale texture space", NULL }, + { "mapping", (getter) MTex_getMapping, (setter) MTex_setMapping, + "Mapping of texture coordinates (flat, cube, etc.)", NULL }, + { "stencil", (getter) MTex_getFlag, (setter) MTex_setFlag, + "Stencil mode", (void*) MTEX_STENCIL }, + { "neg", (getter) MTex_getFlag, (setter) MTex_setFlag, + "Negate texture values mode", (void*) MTEX_NEGATIVE }, + { "noRGB", (getter) MTex_getFlag, (setter) MTex_setFlag, + "Convert texture RGB values to intensity values", + (void*) MTEX_RGBTOINT }, + { "correctNor", (getter) MTex_getFlag, (setter) MTex_setFlag, + "Correct normal mapping for Texture space and Object space", + (void*) MTEX_VIEWSPACE }, + { "xproj", (getter) MTex_getProjX, (setter) MTex_setProjX, + "Projection of X axis to Texture space", NULL }, + { "yproj", (getter) MTex_getProjY, (setter) MTex_setProjY, + "Projection of Y axis to Texture space", NULL }, + { "zproj", (getter) MTex_getProjZ, (setter) MTex_setProjZ, + "Projection of Z axis to Texture space", NULL }, + { "mtCol", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag, + "How texture maps to color", (void*) MAP_COL }, + { "mtNor", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag, + "How texture maps to normals", (void*) MAP_NORM }, + { "mtCsp", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag, + "How texture maps to specularity color", (void*) MAP_COLSPEC }, + { "mtCmir", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag, + "How texture maps to mirror color", (void*) MAP_COLMIR }, + { "mtRef", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag, + "How texture maps to reflectivity", (void*) MAP_REF }, + { "mtSpec", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag, + "How texture maps to specularity", (void*) MAP_SPEC }, + { "mtEmit", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag, + "How texture maps to emit value", (void*) MAP_EMIT }, + { "mtAlpha", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag, + "How texture maps to alpha value", (void*) MAP_ALPHA }, + { "mtHard", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag, + "How texture maps to hardness", (void*) MAP_HAR }, + { "mtRayMir", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag, + "How texture maps to RayMir value", (void*) MAP_RAYMIRR }, + { "mtTranslu", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag, + "How texture maps to translucency", (void*) MAP_TRANSLU }, + { "mtAmb", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag, + "How texture maps to ambient value", (void*) MAP_AMB }, + { "mtDisp", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag, + "How texture maps to displacement", (void*) MAP_DISPLACE }, + { "mtWarp", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag, + "How texture maps to warp", (void*) MAP_WARP }, + { NULL, NULL, NULL, NULL, NULL } +}; + + + +/*****************************************************************************/ +/* Python MTex_Type structure definition: */ +/*****************************************************************************/ + +PyTypeObject MTex_Type = { + PyObject_HEAD_INIT( NULL ) + 0, /* ob_size */ + "Blender MTex", /* tp_name */ + sizeof( BPy_MTex ), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + NULL, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + ( cmpfunc ) MTex_compare, /* tp_compare */ + ( reprfunc ) MTex_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_as_hash */ + 0, 0, 0, 0, 0, + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + 0, /* tp_doc */ + 0, 0, 0, 0, 0, 0, + BPy_MTex_methods, /* tp_methods */ + 0, /* tp_members */ + MTex_getseters, /* struct PyGetSetDef *tp_getset; */ + 0, /* struct _typeobject *tp_base; */ + 0, /* PyObject *tp_dict; */ + 0, /* descrgetfunc tp_descr_get; */ + 0, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + 0, /* initproc tp_init; */ + 0, /* allocfunc tp_alloc; */ + 0, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + 0, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + 0, /* inquiry tp_is_gc; */ + 0, /* PyObject *tp_bases; */ + /* method resolution order */ + 0, /* PyObject *tp_mro; */ + 0, /* PyObject *tp_cache; */ + 0, /* PyObject *tp_subclasses; */ + 0, /* PyObject *tp_weaklist; */ + 0 +}; + + +PyObject *MTex_Init( void ) +{ + PyObject *submodule; +/* PyObject *dict; */ + + /* call PyType_Ready() to init dictionaries & such */ + if( PyType_Ready( &MTex_Type) < 0) + Py_RETURN_NONE; + + submodule = Py_InitModule( "Blender.Texture.MTex", M_MTex_methods ); + + return submodule; +} + +PyObject *MTex_CreatePyObject( MTex * mtex ) +{ + BPy_MTex *pymtex; + + pymtex = ( BPy_MTex * ) PyObject_NEW( BPy_MTex, &MTex_Type ); + if( !pymtex ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create BPy_MTex PyObject" ); + + pymtex->mtex = mtex; + return ( PyObject * ) pymtex; +} + +MTex *MTex_FromPyObject( PyObject * pyobj ) +{ + return ( ( BPy_MTex * ) pyobj )->mtex; +} + +/*****************************************************************************/ +/* Python BPy_MTex methods: */ +/*****************************************************************************/ + +static PyObject *MTex_setTexMethod( BPy_MTex * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)MTex_setTex ); +} + +static int MTex_compare( BPy_MTex * a, BPy_MTex * b ) +{ + return ( a->mtex == b->mtex ) ? 0 : -1; +} + +static PyObject *MTex_repr( BPy_MTex * self ) +{ + return PyString_FromFormat( "[MTex]" ); +} + + +/*****************************************************************************/ +/* Python BPy_MTex get and set functions: */ +/*****************************************************************************/ + +static PyObject *MTex_getTex( BPy_MTex *self, void *closure ) +{ + if( self->mtex->tex ) + return Texture_CreatePyObject( self->mtex->tex ); + else + Py_RETURN_NONE; +} + +static int MTex_setTex( BPy_MTex *self, PyObject *value, void *closure) +{ + return GenericLib_assignData(value, (void **) &self->mtex->tex, 0, 1, ID_TE, 0); +} + +static PyObject *MTex_getTexCo( BPy_MTex *self, void *closure ) +{ + return PyInt_FromLong( self->mtex->texco ); +} + +static int MTex_setTexCo( BPy_MTex *self, PyObject *value, void *closure) +{ + int texco; + + if( !PyInt_Check( value ) ) { + return EXPP_ReturnIntError( PyExc_TypeError, + "Value must be a member of Texture.TexCo dictionary" ); + } + + texco = PyInt_AsLong( value ) ; + + if (texco != TEXCO_ORCO && texco != TEXCO_REFL && texco != TEXCO_NORM && + texco != TEXCO_GLOB && texco != TEXCO_UV && texco != TEXCO_OBJECT && + texco != TEXCO_STRESS && texco != TEXCO_TANGENT && texco != TEXCO_WINDOW && + texco != TEXCO_VIEW && texco != TEXCO_STICKY ) + return EXPP_ReturnIntError( PyExc_ValueError, + "Value must be a member of Texture.TexCo dictionary" ); + + self->mtex->texco = (short)texco; + + return 0; +} + +static PyObject *MTex_getObject( BPy_MTex *self, void *closure ) +{ + if( self->mtex->object ) + return Object_CreatePyObject( self->mtex->object ); + else + Py_RETURN_NONE; +} + +static int MTex_setObject( BPy_MTex *self, PyObject *value, void *closure) +{ + return GenericLib_assignData(value, (void **) &self->mtex->object, 0, 1, ID_OB, 0); +} + +static PyObject *MTex_getUVLayer( BPy_MTex *self, void *closure ) +{ + return PyString_FromString(self->mtex->uvname); +} + +static int MTex_setUVLayer( BPy_MTex *self, PyObject *value, void *closure) +{ + if ( !PyString_Check(value) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected string value" ); + BLI_strncpy(self->mtex->uvname, PyString_AsString(value), 31); + return 0; +} + +static PyObject *MTex_getMapTo( BPy_MTex *self, void *closure ) +{ + return PyInt_FromLong( self->mtex->mapto ); +} + +static int MTex_setMapTo( BPy_MTex *self, PyObject *value, void *closure) +{ + int mapto; + + if( !PyInt_Check( value ) ) { + return EXPP_ReturnIntError( PyExc_TypeError, + "expected an int" ); + } + + mapto = PyInt_AsLong( value ); + + /* This method is deprecated anyway. */ + if ( mapto < 0 || mapto > 16383 ) { + return EXPP_ReturnIntError( PyExc_ValueError, + "Value must be a sum of values from Texture.MapTo dictionary" ); + } + + self->mtex->mapto = (short)mapto; + + return 0; +} + +static PyObject *MTex_getCol( BPy_MTex *self, void *closure ) +{ + return Py_BuildValue( "(f,f,f)", self->mtex->r, self->mtex->g, + self->mtex->b ); +} + +static int MTex_setCol( BPy_MTex *self, PyObject *value, void *closure) +{ + float rgb[3]; + int i; + + if( !PyArg_ParseTuple( value, "fff", + &rgb[0], &rgb[1], &rgb[2] ) ) + + return EXPP_ReturnIntError( PyExc_TypeError, + "expected tuple of 3 floats" ); + + for( i = 0; i < 3; ++i ) + if( rgb[i] < 0 || rgb[i] > 1 ) + return EXPP_ReturnIntError( PyExc_ValueError, + "values must be in range [0,1]" ); + + self->mtex->r = rgb[0]; + self->mtex->g = rgb[1]; + self->mtex->b = rgb[2]; + + return 0; +} + +static PyObject *MTex_getDVar( BPy_MTex *self, void *closure ) +{ + return PyFloat_FromDouble(self->mtex->def_var); +} + +static int MTex_setDVar( BPy_MTex *self, PyObject *value, void *closure) +{ + float f; + + if ( !PyFloat_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a float" ); + + f = (float)PyFloat_AsDouble(value); + + if (f < 0 || f > 1) + return EXPP_ReturnIntError( PyExc_ValueError, + "values must be in range [0,1]" ); + + self->mtex->def_var = f; + + return 0; +} + +static PyObject *MTex_getBlendMode( BPy_MTex *self, void *closure ) +{ + return PyInt_FromLong(self->mtex->blendtype); +} + +static int MTex_setBlendMode( BPy_MTex *self, PyObject *value, void *closure) +{ + int n; + + if ( !PyInt_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "Value must be member of Texture.BlendModes dictionary" ); + + n = PyInt_AsLong(value); + +/* if (n != MTEX_BLEND && n != MTEX_MUL && n != MTEX_ADD && + n != MTEX_SUB && n != MTEX_DIV && n != MTEX_DARK && + n != MTEX_DIFF && n != MTEX_LIGHT && n != MTEX_SCREEN)*/ + if (n < 0 || n > 8) + { + return EXPP_ReturnIntError( PyExc_ValueError, + "Value must be member of Texture.BlendModes dictionary" ); + } + + self->mtex->blendtype = (short)n; + + return 0; +} + +static PyObject *MTex_getColFac( BPy_MTex *self, void *closure ) +{ + return PyFloat_FromDouble(self->mtex->colfac); +} + +static int MTex_setColFac( BPy_MTex *self, PyObject *value, void *closure) +{ + float f; + + if ( !PyFloat_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a float" ); + + f = (float)PyFloat_AsDouble(value); + + if (f < 0 || f > 1) + return EXPP_ReturnIntError( PyExc_ValueError, + "values must be in range [0,1]" ); + + self->mtex->colfac = f; + + return 0; +} + +static PyObject *MTex_getNorFac( BPy_MTex *self, void *closure ) +{ + return PyFloat_FromDouble(self->mtex->norfac); +} + +static int MTex_setNorFac( BPy_MTex *self, PyObject *value, void *closure) +{ + float f; + + if ( !PyFloat_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a float" ); + + f = (float)PyFloat_AsDouble(value); + + if (f < 0 || f > 25) + return EXPP_ReturnIntError( PyExc_ValueError, + "values must be in range [0,25]" ); + + self->mtex->norfac = f; + + return 0; +} + +static PyObject *MTex_getVarFac( BPy_MTex *self, void *closure ) +{ + return PyFloat_FromDouble(self->mtex->varfac); +} + +static int MTex_setVarFac( BPy_MTex *self, PyObject *value, void *closure) +{ + float f; + + if ( !PyFloat_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a float" ); + + f = (float)PyFloat_AsDouble(value); + + if (f < 0 || f > 1) + return EXPP_ReturnIntError( PyExc_ValueError, + "values must be in range [0,1]" ); + + self->mtex->varfac = f; + + return 0; +} + +static PyObject *MTex_getDispFac( BPy_MTex *self, void *closure ) +{ + return PyFloat_FromDouble(self->mtex->dispfac); +} + +static int MTex_setDispFac( BPy_MTex *self, PyObject *value, void *closure) +{ + float f; + + if ( !PyFloat_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a float" ); + + f = (float)PyFloat_AsDouble(value); + + if (f < 0 || f > 1) + return EXPP_ReturnIntError( PyExc_ValueError, + "values must be in range [0,1]" ); + + self->mtex->dispfac = f; + + return 0; +} + +static PyObject *MTex_getWarpFac( BPy_MTex *self, void *closure ) +{ + return PyFloat_FromDouble(self->mtex->warpfac); +} + +static int MTex_setWarpFac( BPy_MTex *self, PyObject *value, void *closure) +{ + float f; + + if ( !PyFloat_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a float" ); + + f = (float)PyFloat_AsDouble(value); + + if (f < 0 || f > 1) + return EXPP_ReturnIntError( PyExc_ValueError, + "values must be in range [0,1]" ); + + self->mtex->warpfac = f; + + return 0; +} + +static PyObject *MTex_getOfs( BPy_MTex *self, void *closure ) +{ + return Py_BuildValue( "(f,f,f)", self->mtex->ofs[0], self->mtex->ofs[1], + self->mtex->ofs[2] ); +} + +static int MTex_setOfs( BPy_MTex *self, PyObject *value, void *closure) +{ + float f[3]; + int i; + + if( !PyArg_ParseTuple( value, "fff", &f[0], &f[1], &f[2] ) ) + + return EXPP_ReturnIntError( PyExc_TypeError, + "expected tuple of 3 floats" ); + + for( i = 0; i < 3; ++i ) + if( f[i] < -10 || f[i] > 10 ) + return EXPP_ReturnIntError( PyExc_ValueError, + "values must be in range [-10,10]" ); + + self->mtex->ofs[0] = f[0]; + self->mtex->ofs[1] = f[1]; + self->mtex->ofs[2] = f[2]; + + return 0; +} + +static PyObject *MTex_getSize( BPy_MTex *self, void *closure ) +{ + return Py_BuildValue( "(f,f,f)", self->mtex->size[0], self->mtex->size[1], + self->mtex->size[2] ); +} + +static int MTex_setSize( BPy_MTex *self, PyObject *value, void *closure) +{ + float f[3]; + int i; + + if( !PyArg_ParseTuple( value, "fff", &f[0], &f[1], &f[2] ) ) + + return EXPP_ReturnIntError( PyExc_TypeError, + "expected tuple of 3 floats" ); + + for( i = 0; i < 3; ++i ) + if( f[i] < -100 || f[i] > 100 ) + return EXPP_ReturnIntError( PyExc_ValueError, + "values must be in range [-100,100]" ); + + self->mtex->size[0] = f[0]; + self->mtex->size[1] = f[1]; + self->mtex->size[2] = f[2]; + + return 0; +} + +static PyObject *MTex_getMapping( BPy_MTex *self, void *closure ) +{ + return PyInt_FromLong( self->mtex->mapping ); +} + +static int MTex_setMapping( BPy_MTex *self, PyObject *value, void *closure) +{ + int n; + + if ( !PyInt_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "Value must be member of Texture.Mappings dictionary" ); + + n = PyInt_AsLong(value); + +/* if (n != MTEX_FLAT && n != MTEX_TUBE && n != MTEX_CUBE && + n != MTEX_SPHERE) */ + if (n < 0 || n > 3) + { + return EXPP_ReturnIntError( PyExc_ValueError, + "Value must be member of Texture.Mappings dictionary" ); + } + + self->mtex->mapping = (char)n; + + return 0; +} + +static PyObject *MTex_getFlag( BPy_MTex *self, void *closure ) +{ + return PyBool_FromLong( self->mtex->texflag & ((int) closure) ); +} + +static int MTex_setFlag( BPy_MTex *self, PyObject *value, void *closure) +{ + if ( !PyBool_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a bool"); + + if ( value == Py_True ) + self->mtex->texflag |= (int)closure; + else + self->mtex->texflag &= ~((int) closure); + + return 0; +} + +static PyObject *MTex_getProjX( BPy_MTex *self, void *closure ) +{ + return PyInt_FromLong( self->mtex->projx ); +} + +static int MTex_setProjX( BPy_MTex *self, PyObject *value, void *closure) +{ + int proj; + + if( !PyInt_Check( value ) ) { + return EXPP_ReturnIntError( PyExc_TypeError, + "Value must be a member of Texture.Proj dictionary" ); + } + + proj = PyInt_AsLong( value ) ; + + /* valid values are from PROJ_N to PROJ_Z = 0 to 3 */ + if (proj < 0 || proj > 3) + return EXPP_ReturnIntError( PyExc_ValueError, + "Value must be a member of Texture.Proj dictionary" ); + + self->mtex->projx = (char)proj; + + return 0; +} + +static PyObject *MTex_getProjY( BPy_MTex *self, void *closure ) +{ + return PyInt_FromLong( self->mtex->projy ); +} + +static int MTex_setProjY( BPy_MTex *self, PyObject *value, void *closure ) +{ + int proj; + + if( !PyInt_Check( value ) ) { + return EXPP_ReturnIntError( PyExc_TypeError, + "Value must be a member of Texture.Proj dictionary" ); + } + + proj = PyInt_AsLong( value ) ; + + /* valid values are from PROJ_N to PROJ_Z = 0 to 3 */ + if (proj < 0 || proj > 3) + return EXPP_ReturnIntError( PyExc_ValueError, + "Value must be a member of Texture.Proj dictionary" ); + + self->mtex->projy = (char)proj; + + return 0; +} + +static PyObject *MTex_getProjZ( BPy_MTex *self, void *closure ) +{ + return PyInt_FromLong( self->mtex->projz ); +} + +static int MTex_setProjZ( BPy_MTex *self, PyObject *value, void *closure) +{ + int proj; + + if( !PyInt_Check( value ) ) { + return EXPP_ReturnIntError( PyExc_TypeError, + "Value must be a member of Texture.Proj dictionary" ); + } + + proj = PyInt_AsLong( value ) ; + + /* valid values are from PROJ_N to PROJ_Z = 0 to 3 */ + if (proj < 0 || proj > 3) + return EXPP_ReturnIntError( PyExc_ValueError, + "Value must be a member of Texture.Proj dictionary" ); + + self->mtex->projz = (char)proj; + + return 0; +} + +static PyObject *MTex_getMapToFlag( BPy_MTex *self, void *closure ) +{ + int flag = (int) closure; + + if ( self->mtex->mapto & flag ) + { + return PyInt_FromLong( ( self->mtex->maptoneg & flag ) ? -1 : 1 ); + } else { + return PyInt_FromLong( 0 ); + } +} + +static int MTex_setMapToFlag( BPy_MTex *self, PyObject *value, void *closure) +{ + int flag = (int) closure; + int intVal; + + if ( !PyInt_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected an int"); + + intVal = PyInt_AsLong( value ); + + if (flag == MAP_COL || flag == MAP_COLSPEC || flag == MAP_COLMIR || + flag == MAP_WARP) { + if (intVal < 0 || intVal > 1) { + return EXPP_ReturnIntError( PyExc_ValueError, + "value for that mapping must be 0 or 1" ); + } + } else { + if (intVal < -1 || intVal > 1) { + return EXPP_ReturnIntError( PyExc_ValueError, + "value for that mapping must be -1, 0 or 1" ); + } + } + + switch (intVal) + { + case 0: + self->mtex->mapto &= ~flag; + self->mtex->maptoneg &= ~flag; + break; + + case 1: + self->mtex->mapto |= flag; + self->mtex->maptoneg &= ~flag; + break; + + case -1: + self->mtex->mapto |= flag; + self->mtex->maptoneg |= flag; + break; + } + + return 0; +} diff --git a/source/blender/python/api2_2x/MTex.h b/source/blender/python/api2_2x/MTex.h new file mode 100644 index 00000000000..2148212d82f --- /dev/null +++ b/source/blender/python/api2_2x/MTex.h @@ -0,0 +1,63 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Alex Mole + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_MTEX_H +#define EXPP_MTEX_H + +#include +#include "DNA_texture_types.h" + + +/*****************************************************************************/ +/* Python BPy_MTex structure definition */ +/*****************************************************************************/ + +typedef struct { + PyObject_HEAD + MTex * mtex; +} BPy_MTex; + +extern PyTypeObject MTex_Type; + +#define BPy_MTex_Check(v) ((v)->ob_type == &MTex_Type) + + +/*****************************************************************************/ +/* Module Blender.Texture.MTex - public functions */ +/*****************************************************************************/ + +PyObject *MTex_Init( void ); +PyObject *MTex_CreatePyObject( struct MTex *obj ); +MTex *MTex_FromPyObject( PyObject * py_obj ); + + +#endif /* EXPP_MTEX_H */ diff --git a/source/blender/python/api2_2x/Makefile b/source/blender/python/api2_2x/Makefile new file mode 100644 index 00000000000..8a13adae989 --- /dev/null +++ b/source/blender/python/api2_2x/Makefile @@ -0,0 +1,64 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = python +DIR = $(OCGDIR)/blender/python + +CSRCS ?= $(wildcard *.c) $(wildcard ../*.c) + +include nan_compile.mk + +CFLAGS += $(LEVEL_1_C_WARNINGS) + +ifeq ($(WITH_FFMPEG), true) + CPPFLAGS += -DWITH_FFMPEG +endif + +CPPFLAGS += -I$(OPENGL_HEADERS) +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include +CPPFLAGS += -I../../makesdna +CPPFLAGS += -I../../blenkernel +CPPFLAGS += -I../../blenlib +CPPFLAGS += -I../../blenloader +CPPFLAGS += -I../../include +CPPFLAGS += -I../../render/extern/include +CPPFLAGS += -I../../radiosity/extern/include +CPPFLAGS += -I$(NAN_BMFONT)/include +CPPFLAGS += -I../../imbuf +CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) + +# We'll just add a little duct tape to fix things here ... +.PHONY: clean +clean:: + @rm -f $(OCGDIR)/blender/BPY_*.o + @rm -f $(OCGDIR)/blender/BPY_*.d diff --git a/source/blender/python/api2_2x/Material.c b/source/blender/python/api2_2x/Material.c new file mode 100644 index 00000000000..851a46d51e5 --- /dev/null +++ b/source/blender/python/api2_2x/Material.c @@ -0,0 +1,3048 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano, Michel Selten, Alex Mole, + * Alexander Szakaly, Campbell Barton, Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#include "Material.h" /*This must come first*/ + +#include "DNA_space_types.h" +#include "DNA_material_types.h" +#include "BKE_main.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_material.h" +#include "BKE_texture.h" +#include "BKE_idprop.h" +#include "BKE_utildefines.h" /* for CLAMP */ +#include "MEM_guardedalloc.h" +#include "BLI_blenlib.h" +#include "BSE_editipo.h" +#include "BIF_space.h" +#include "mydevice.h" +#include "constant.h" +#include "MTex.h" +#include "Texture.h" +#include "Ipo.h" +#include "Group.h" +#include "gen_utils.h" +#include "gen_library.h" +#include "IDProp.h" + +/*****************************************************************************/ +/* Python BPy_Material defaults: */ +/*****************************************************************************/ +/* Material MIN, MAX values */ +#define EXPP_MAT_ADD_MIN 0.0f +#define EXPP_MAT_ADD_MAX 1.0f +#define EXPP_MAT_ALPHA_MIN 0.0f +#define EXPP_MAT_ALPHA_MAX 1.0f +#define EXPP_MAT_AMB_MIN 0.0f +#define EXPP_MAT_AMB_MAX 1.0f +#define EXPP_MAT_COL_MIN 0.0f /* min/max for all ... */ +#define EXPP_MAT_COL_MAX 1.0f /* ... color triplets */ +#define EXPP_MAT_EMIT_MIN 0.0f +#define EXPP_MAT_EMIT_MAX 1.0f +#define EXPP_MAT_REF_MIN 0.0f +#define EXPP_MAT_REF_MAX 1.0f +#define EXPP_MAT_SPEC_MIN 0.0f +#define EXPP_MAT_SPEC_MAX 2.0f +#define EXPP_MAT_SPECTRA_MIN 0.0f +#define EXPP_MAT_SPECTRA_MAX 1.0f + +/* Shader specific settings */ + +#define EXPP_MAT_ROUGHNESS_MIN 0.0f +#define EXPP_MAT_ROUGHNESS_MAX 3.140f +#define EXPP_MAT_SPECSIZE_MIN 0.0f +#define EXPP_MAT_SPECSIZE_MAX 1.530f +#define EXPP_MAT_DIFFUSESIZE_MIN 0.0f +#define EXPP_MAT_DIFFUSESIZE_MAX 3.140f +#define EXPP_MAT_SPECSMOOTH_MIN 0.0f +#define EXPP_MAT_SPECSMOOTH_MAX 1.0f +#define EXPP_MAT_DIFFUSESMOOTH_MIN 0.0f +#define EXPP_MAT_DIFFUSESMOOTH_MAX 1.0f +#define EXPP_MAT_DIFFUSE_DARKNESS_MIN 0.0f +#define EXPP_MAT_DIFFUSE_DARKNESS_MAX 2.0f +#define EXPP_MAT_REFRACINDEX_MIN 1.0f +#define EXPP_MAT_REFRACINDEX_MAX 10.0f +#define EXPP_MAT_RMS_MIN 0.0f +#define EXPP_MAT_RMS_MAX 0.4f +/* End shader settings */ + +#define EXPP_MAT_ZOFFS_MIN 0.0 +#define EXPP_MAT_ZOFFS_MAX 10.0 +#define EXPP_MAT_HALOSIZE_MIN 0.0 +#define EXPP_MAT_HALOSIZE_MAX 100.0 +#define EXPP_MAT_FLARESIZE_MIN 0.1f +#define EXPP_MAT_FLARESIZE_MAX 25.0 +#define EXPP_MAT_FLAREBOOST_MIN 0.1f +#define EXPP_MAT_FLAREBOOST_MAX 10.0 +#define EXPP_MAT_SUBSIZE_MIN 0.1f +#define EXPP_MAT_SUBSIZE_MAX 25.0 + +#define EXPP_MAT_HARD_MIN 1 +#define EXPP_MAT_HARD_MAX 255 /* 127 with MODE HALO ON */ +#define EXPP_MAT_HALOSEED_MIN 0 +#define EXPP_MAT_HALOSEED_MAX 255 +#define EXPP_MAT_NFLARES_MIN 1 +#define EXPP_MAT_NFLARES_MAX 32 +#define EXPP_MAT_FLARESEED_MIN 0 +#define EXPP_MAT_FLARESEED_MAX 255 +#define EXPP_MAT_NSTARS_MIN 3 +#define EXPP_MAT_NSTARS_MAX 50 +#define EXPP_MAT_NLINES_MIN 0 +#define EXPP_MAT_NLINES_MAX 250 +#define EXPP_MAT_NRINGS_MIN 0 +#define EXPP_MAT_NRINGS_MAX 24 + +#define EXPP_MAT_RAYMIRR_MIN 0.0 +#define EXPP_MAT_RAYMIRR_MAX 1.0 +#define EXPP_MAT_MIRRDEPTH_MIN 0 +#define EXPP_MAT_MIRRDEPTH_MAX 10 +#define EXPP_MAT_FRESNELMIRR_MIN 0.0 +#define EXPP_MAT_FRESNELMIRR_MAX 5.0 +#define EXPP_MAT_FRESNELMIRRFAC_MIN 1.0 +#define EXPP_MAT_FRESNELMIRRFAC_MAX 5.0 +#define EXPP_MAT_FILTER_MIN 0.0 +#define EXPP_MAT_FILTER_MAX 1.0 +#define EXPP_MAT_TRANSLUCENCY_MIN 0.0 +#define EXPP_MAT_TRANSLUCENCY_MAX 1.0 +#define EXPP_MAT_ZOFFS_MIN 0.0 +#define EXPP_MAT_ZOFFS_MAX 10.0 +#define EXPP_MAT_IOR_MIN 1.0 +#define EXPP_MAT_IOR_MAX 3.0 +#define EXPP_MAT_TRANSDEPTH_MIN 0 +#define EXPP_MAT_TRANSDEPTH_MAX 10 +#define EXPP_MAT_FRESNELTRANS_MIN 0.0 +#define EXPP_MAT_FRESNELTRANS_MAX 5.0 +#define EXPP_MAT_FRESNELTRANSFAC_MIN 1.0 +#define EXPP_MAT_FRESNELTRANSFAC_MAX 5.0 +#define EXPP_MAT_SPECTRANS_MIN 0.0 +#define EXPP_MAT_SPECTRANS_MAX 1.0 +#define EXPP_MAT_MIRRTRANSADD_MIN 0.0 +#define EXPP_MAT_MIRRTRANSADD_MAX 1.0 + +/* closure values for getColorComponent()/setColorComponent() */ + +#define EXPP_MAT_COMP_R 0 +#define EXPP_MAT_COMP_G 1 +#define EXPP_MAT_COMP_B 2 +#define EXPP_MAT_COMP_SPECR 3 +#define EXPP_MAT_COMP_SPECG 4 +#define EXPP_MAT_COMP_SPECB 5 +#define EXPP_MAT_COMP_MIRR 6 +#define EXPP_MAT_COMP_MIRG 7 +#define EXPP_MAT_COMP_MIRB 8 +#define EXPP_MAT_COMP_SSSR 9 +#define EXPP_MAT_COMP_SSSG 10 +#define EXPP_MAT_COMP_SSSB 11 + + +#define IPOKEY_RGB 0 +#define IPOKEY_ALPHA 1 +#define IPOKEY_HALOSIZE 2 +#define IPOKEY_MODE 3 +#define IPOKEY_ALLCOLOR 10 +#define IPOKEY_ALLMIRROR 14 +#define IPOKEY_OFS 12 +#define IPOKEY_SIZE 13 +#define IPOKEY_ALLMAPPING 11 + +/* SSS Settings */ +#define EXPP_MAT_SSS_SCALE_MIN 0.001 +#define EXPP_MAT_SSS_SCALE_MAX 1000.0 +#define EXPP_MAT_SSS_RADIUS_MIN 0.0 +#define EXPP_MAT_SSS_RADIUS_MAX 10000.0 +#define EXPP_MAT_SSS_IOR_MIN 0.1 +#define EXPP_MAT_SSS_IOR_MAX 2.0 +#define EXPP_MAT_SSS_ERROR_MIN 0.0 +#define EXPP_MAT_SSS_ERROR_MAX 1.0 +#define EXPP_MAT_SSS_FRONT_MIN 0.0 +#define EXPP_MAT_SSS_FRONT_MAX 2.0 +#define EXPP_MAT_SSS_BACK_MIN 0.0 +#define EXPP_MAT_SSS_BACK_MAX 10.0 + + +/*****************************************************************************/ +/* Python API function prototypes for the Material module. */ +/*****************************************************************************/ +static PyObject *M_Material_New( PyObject * self, PyObject * args, + PyObject * keywords ); +static PyObject *M_Material_Get( PyObject * self, PyObject * args ); + +/*****************************************************************************/ +/* The following string definitions are used for documentation strings. In */ +/* Python these will be written to the console when doing a */ +/* Blender.Material.__doc__ */ +/*****************************************************************************/ +static char M_Material_doc[] = "The Blender Material module"; + +static char M_Material_New_doc[] = + "(name) - return a new material called 'name'\n\ +() - return a new material called 'Mat'"; + +static char M_Material_Get_doc[] = + "(name) - return the material called 'name', None if not found.\n\ +() - return a list of all materials in the current scene."; + +/*****************************************************************************/ +/* Python method structure definition for Blender.Material module: */ +/*****************************************************************************/ +struct PyMethodDef M_Material_methods[] = { + {"New", ( PyCFunction ) M_Material_New, METH_VARARGS | METH_KEYWORDS, + M_Material_New_doc}, + {"Get", M_Material_Get, METH_VARARGS, M_Material_Get_doc}, + {"get", M_Material_Get, METH_VARARGS, M_Material_Get_doc}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Function: M_Material_New */ +/* Python equivalent: Blender.Material.New */ +/*****************************************************************************/ +static PyObject *M_Material_New( PyObject * self, PyObject * args, + PyObject * keywords ) +{ + char *name = "Mat"; + static char *kwlist[] = { "name", NULL }; + BPy_Material *pymat; /* for Material Data object wrapper in Python */ + Material *blmat; /* for actual Material Data we create in Blender */ + char buf[21]; + + if( !PyArg_ParseTupleAndKeywords + ( args, keywords, "|s", kwlist, &name ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_AttributeError, + "expected string or nothing as argument" ) ); + + if( strcmp( name, "Mat" ) != 0 ) /* use gave us a name ? */ + PyOS_snprintf( buf, sizeof( buf ), "%s", name ); + + blmat = add_material( name ); /* first create the Material Data in Blender */ + + if( blmat ) /* now create the wrapper obj in Python */ + pymat = ( BPy_Material * ) Material_CreatePyObject( blmat ); + else + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't create Material Data in Blender" ) ); + + blmat->id.us = 0; /* was incref'ed by add_material() above */ + + if( pymat == NULL ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create Material Data object" ) ); + + return ( PyObject * ) pymat; +} + +/*****************************************************************************/ +/* Function: M_Material_Get */ +/* Python equivalent: Blender.Material.Get */ +/* Description: Receives a string and returns the material whose */ +/* name matches the string. If no argument is */ +/* passed in, a list with all materials in the */ +/* current scene is returned. */ +/*****************************************************************************/ +static PyObject *M_Material_Get( PyObject * self, PyObject * args ) +{ + char *name = NULL; + Material *mat_iter; + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument (or nothing)" ) ); + + if( name ) { /* (name) - Search material by name */ + + mat_iter = ( Material * ) GetIdFromList( &( G.main->mat ), name ); + + if( mat_iter == NULL ) { /* Requested material doesn't exist */ + char error_msg[64]; + PyOS_snprintf( error_msg, sizeof( error_msg ), + "Material \"%s\" not found", name ); + return EXPP_ReturnPyObjError( PyExc_NameError, + error_msg ); + } + + return Material_CreatePyObject( mat_iter ); + } + + else { /* () - return a list with all materials in the scene */ + int index = 0; + PyObject *matlist, *pyobj; + + matlist = PyList_New( BLI_countlist( &( G.main->mat ) ) ); + + if( !matlist ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyList" ) ); + + mat_iter = G.main->mat.first; + while( mat_iter ) { + pyobj = Material_CreatePyObject( mat_iter ); + + if( !pyobj ) { + Py_DECREF(matlist); + return ( EXPP_ReturnPyObjError + ( PyExc_MemoryError, + "couldn't create PyObject" ) ); + } + PyList_SET_ITEM( matlist, index, pyobj ); + + mat_iter = mat_iter->id.next; + index++; + } + + return matlist; + } +} + +static PyObject *Material_ModesDict( void ) +{ + PyObject *Modes = PyConstant_New( ); + + if( Modes ) { + BPy_constant *c = ( BPy_constant * ) Modes; + + PyConstant_Insert(c, "TRACEABLE", PyInt_FromLong(MA_TRACEBLE)); + PyConstant_Insert(c, "SHADOW", PyInt_FromLong(MA_SHADOW)); + PyConstant_Insert(c, "SHADOWBUF", PyInt_FromLong(MA_SHADBUF)); + PyConstant_Insert(c, "TANGENTSTR", PyInt_FromLong(MA_TANGENT_STR)); + PyConstant_Insert(c, "FULLOSA", PyInt_FromLong(MA_FULL_OSA)); + PyConstant_Insert(c, "RAYBIAS", PyInt_FromLong(MA_RAYBIAS)); + PyConstant_Insert(c, "TRANSPSHADOW", PyInt_FromLong(MA_SHADOW_TRA)); + PyConstant_Insert(c, "RAMPCOL", PyInt_FromLong(MA_RAMP_COL)); + PyConstant_Insert(c, "RAMPSPEC", PyInt_FromLong(MA_RAMP_SPEC)); + PyConstant_Insert(c, "SHADELESS", PyInt_FromLong(MA_SHLESS)); + PyConstant_Insert(c, "WIRE", PyInt_FromLong(MA_WIRE)); + PyConstant_Insert(c, "VCOL_LIGHT", PyInt_FromLong(MA_VERTEXCOL)); + PyConstant_Insert(c, "HALO", PyInt_FromLong(MA_HALO)); + PyConstant_Insert(c, "ZTRANSP", PyInt_FromLong(MA_ZTRA)); + PyConstant_Insert(c, "VCOL_PAINT", PyInt_FromLong(MA_VERTEXCOLP)); + PyConstant_Insert(c, "ZINVERT", PyInt_FromLong(MA_ZINV)); + PyConstant_Insert(c, "HALORINGS", PyInt_FromLong(MA_HALO_RINGS)); + PyConstant_Insert(c, "ENV", PyInt_FromLong(MA_ENV)); + PyConstant_Insert(c, "HALOLINES", PyInt_FromLong(MA_HALO_LINES)); + PyConstant_Insert(c, "ONLYSHADOW", PyInt_FromLong(MA_ONLYSHADOW)); + PyConstant_Insert(c, "HALOXALPHA", PyInt_FromLong(MA_HALO_XALPHA)); + PyConstant_Insert(c, "HALOSTAR", PyInt_FromLong(MA_STAR)); + PyConstant_Insert(c, "TEXFACE", PyInt_FromLong(MA_FACETEXTURE)); + PyConstant_Insert(c, "HALOTEX", PyInt_FromLong(MA_HALOTEX)); + PyConstant_Insert(c, "HALOPUNO", PyInt_FromLong(MA_HALOPUNO)); + PyConstant_Insert(c, "NOMIST", PyInt_FromLong(MA_NOMIST)); + PyConstant_Insert(c, "HALOSHADE", PyInt_FromLong(MA_HALO_SHADE)); + PyConstant_Insert(c, "HALOFLARE", PyInt_FromLong(MA_HALO_FLARE)); + PyConstant_Insert(c, "RADIO", PyInt_FromLong(MA_RADIO)); + PyConstant_Insert(c, "RAYMIRROR", PyInt_FromLong(MA_RAYMIRROR)); + PyConstant_Insert(c, "ZTRA", PyInt_FromLong(MA_ZTRA)); + PyConstant_Insert(c, "RAYTRANSP", PyInt_FromLong(MA_RAYTRANSP)); + PyConstant_Insert(c, "TANGENT_V", PyInt_FromLong(MA_TANGENT_V)); + PyConstant_Insert(c, "NMAP_TS", PyInt_FromLong(MA_NORMAP_TANG)); + PyConstant_Insert(c, "GROUP_EXCLUSIVE", PyInt_FromLong(MA_GROUP_NOLAY)); + } + + return Modes; +} + + +static PyObject *Material_ShadersDict( void ) +{ + PyObject *Shaders = PyConstant_New( ); + + if( Shaders ) { + BPy_constant *c = ( BPy_constant * ) Shaders; + + PyConstant_Insert(c, "DIFFUSE_LAMBERT", PyInt_FromLong(MA_DIFF_LAMBERT)); + PyConstant_Insert(c, "DIFFUSE_ORENNAYAR", PyInt_FromLong(MA_DIFF_ORENNAYAR)); + PyConstant_Insert(c, "DIFFUSE_TOON", PyInt_FromLong(MA_DIFF_TOON)); + PyConstant_Insert(c, "DIFFUSE_MINNAERT", PyInt_FromLong(MA_DIFF_MINNAERT)); + PyConstant_Insert(c, "SPEC_COOKTORR", PyInt_FromLong(MA_SPEC_COOKTORR)); + PyConstant_Insert(c, "SPEC_PHONG", PyInt_FromLong(MA_SPEC_PHONG)); + PyConstant_Insert(c, "SPEC_BLINN", PyInt_FromLong(MA_SPEC_BLINN)); + PyConstant_Insert(c, "SPEC_TOON", PyInt_FromLong(MA_SPEC_TOON)); + PyConstant_Insert(c, "SPEC_WARDISO", PyInt_FromLong(MA_SPEC_WARDISO)); + + } + + return Shaders; +} + + +/*****************************************************************************/ +/* Function: Material_Init */ +/*****************************************************************************/ +PyObject *Material_Init( void ) +{ + PyObject *submodule, *Modes, *Shaders; + + if( PyType_Ready( &Material_Type ) < 0) + return NULL; + + Modes = Material_ModesDict( ); + Shaders = Material_ShadersDict( ); + + submodule = Py_InitModule3( "Blender.Material", + M_Material_methods, M_Material_doc ); + + if( Modes ) + PyModule_AddObject( submodule, "Modes", Modes ); + if( Shaders ) + PyModule_AddObject( submodule, "Shaders", Shaders ); + + PyModule_AddIntConstant( submodule, "RGB", IPOKEY_RGB ); + PyModule_AddIntConstant( submodule, "ALPHA", IPOKEY_ALPHA ); + PyModule_AddIntConstant( submodule, "HALOSIZE", IPOKEY_HALOSIZE ); + PyModule_AddIntConstant( submodule, "MODE", IPOKEY_MODE ); + PyModule_AddIntConstant( submodule, "ALLCOLOR", IPOKEY_ALLCOLOR ); + PyModule_AddIntConstant( submodule, "ALLMIRROR", IPOKEY_ALLMIRROR ); + PyModule_AddIntConstant( submodule, "OFS", IPOKEY_OFS ); + PyModule_AddIntConstant( submodule, "SIZE", IPOKEY_SIZE ); + PyModule_AddIntConstant( submodule, "ALLMAPPING", IPOKEY_ALLMAPPING ); + + return ( submodule ); +} + +/***************************/ +/*** The Material PyType ***/ +/***************************/ + +static PyObject *Matr_oldsetAdd( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetAlpha( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetAmb( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetEmit( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetFilter( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetFlareBoost( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetFlareSeed( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetFlareSize( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetFresnelMirr( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetFresnelMirrFac( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetFresnelTrans( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetFresnelTransFac( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetHaloSeed( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetHaloSize( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetHardness( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetIOR( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetNFlares( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetNLines( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetNRings( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetNStars( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetRayMirr( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetMirrDepth( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetRef( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetSpec( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetSpecTransp( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetSubSize( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetTransDepth( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetZOffset( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetMode( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetIpo( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetRGBCol( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetSpecCol( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetSpecShader( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetMirCol( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetDiffuseShader( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetRoughness( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetSpecSize( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetDiffuseSize( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetSpecSmooth( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetDiffuseSmooth( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetDiffuseDarkness( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetRefracIndex( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetRms( BPy_Material * self, PyObject * args ); +static PyObject *Matr_oldsetTranslucency( BPy_Material * self, PyObject * args ); + +static int Material_setIpo( BPy_Material * self, PyObject * value ); + +static int Material_setMode( BPy_Material * self, PyObject * value ); +static int Material_setRGBCol( BPy_Material * self, PyObject * value ); +static int Material_setSpecCol( BPy_Material * self, PyObject * value ); +static int Material_setMirCol( BPy_Material * self, PyObject * value ); +static int Material_setSssCol( BPy_Material * self, PyObject * value ); +static int Material_setColorComponent( BPy_Material * self, PyObject * value, + void * closure ); +static int Material_setAmb( BPy_Material * self, PyObject * value ); +static int Material_setEmit( BPy_Material * self, PyObject * value ); +static int Material_setSpecTransp( BPy_Material * self, PyObject * value ); +static int Material_setAlpha( BPy_Material * self, PyObject * value ); +static int Material_setShadAlpha( BPy_Material * self, PyObject * value ); +static int Material_setRef( BPy_Material * self, PyObject * value ); +static int Material_setSpec( BPy_Material * self, PyObject * value ); +static int Material_setZOffset( BPy_Material * self, PyObject * value ); +static int Material_setLightGroup( BPy_Material * self, PyObject * value ); +static int Material_setAdd( BPy_Material * self, PyObject * value ); +static int Material_setHaloSize( BPy_Material * self, PyObject * value ); +static int Material_setFlareSize( BPy_Material * self, PyObject * value ); +static int Material_setFlareBoost( BPy_Material * self, PyObject * value ); +static int Material_setSubSize( BPy_Material * self, PyObject * value ); +static int Material_setHaloSeed( BPy_Material * self, PyObject * value ); +static int Material_setFlareSeed( BPy_Material * self, PyObject * value ); +static int Material_setHardness( BPy_Material * self, PyObject * value ); +static int Material_setNFlares( BPy_Material * self, PyObject * value ); +static int Material_setNStars( BPy_Material * self, PyObject * value ); +static int Material_setNLines( BPy_Material * self, PyObject * value ); +static int Material_setNRings( BPy_Material * self, PyObject * value ); +static int Material_setRayMirr( BPy_Material * self, PyObject * value ); +static int Material_setMirrDepth( BPy_Material * self, PyObject * value ); +static int Material_setFresnelMirr( BPy_Material * self, PyObject * value ); +static int Material_setFresnelMirrFac( BPy_Material * self, PyObject * value ); +static int Material_setIOR( BPy_Material * self, PyObject * value ); +static int Material_setTransDepth( BPy_Material * self, PyObject * value ); +static int Material_setFresnelTrans( BPy_Material * self, PyObject * value ); +static int Material_setFresnelTransFac( BPy_Material * self, PyObject * value ); +static int Material_setRigidBodyFriction( BPy_Material * self, PyObject * value ); +static int Material_setRigidBodyRestitution( BPy_Material * self, PyObject * value ); + +static int Material_setSpecShader( BPy_Material * self, PyObject * value ); +static int Material_setDiffuseShader( BPy_Material * self, PyObject * value ); +static int Material_setRoughness( BPy_Material * self, PyObject * value ); +static int Material_setSpecSize( BPy_Material * self, PyObject * value ); +static int Material_setDiffuseSize( BPy_Material * self, PyObject * value ); +static int Material_setSpecSmooth( BPy_Material * self, PyObject * value ); +static int Material_setDiffuseSmooth( BPy_Material * self, PyObject * value ); +static int Material_setDiffuseDarkness( BPy_Material * self, PyObject * value ); +static int Material_setRefracIndex( BPy_Material * self, PyObject * value ); +static int Material_setRms( BPy_Material * self, PyObject * value ); +static int Material_setFilter( BPy_Material * self, PyObject * value ); +static int Material_setTranslucency( BPy_Material * self, PyObject * value ); + +static int Material_setSssEnable( BPy_Material * self, PyObject * value ); +static int Material_setSssScale( BPy_Material * self, PyObject * value ); +static int Material_setSssRadius( BPy_Material * self, PyObject * value, void * type ); +static int Material_setSssIOR( BPy_Material * self, PyObject * value ); +static int Material_setSssError( BPy_Material * self, PyObject * value ); +static int Material_setSssColorBlend( BPy_Material * self, PyObject * value ); +static int Material_setSssTexScatter( BPy_Material * self, PyObject * value ); +static int Material_setSssFront( BPy_Material * self, PyObject * value ); +static int Material_setSssBack( BPy_Material * self, PyObject * value ); +static int Material_setSssBack( BPy_Material * self, PyObject * value ); + +static PyObject *Material_getColorComponent( BPy_Material * self, + void * closure ); + +/*static int Material_setSeptex( BPy_Material * self, PyObject * value ); + static PyObject *Material_getSeptex( BPy_Material * self );*/ + +/*****************************************************************************/ +/* Python BPy_Material methods declarations: */ +/*****************************************************************************/ +static PyObject *Material_getIpo( BPy_Material * self ); +static PyObject *Material_getMode( BPy_Material * self ); +static PyObject *Material_getRGBCol( BPy_Material * self ); +/*static PyObject *Material_getAmbCol(BPy_Material *self);*/ +static PyObject *Material_getSpecCol( BPy_Material * self ); +static PyObject *Material_getMirCol( BPy_Material * self ); +static PyObject *Material_getSssCol( BPy_Material * self ); +static PyObject *Material_getAmb( BPy_Material * self ); +static PyObject *Material_getEmit( BPy_Material * self ); +static PyObject *Material_getAlpha( BPy_Material * self ); +static PyObject *Material_getShadAlpha( BPy_Material * self ); +static PyObject *Material_getRef( BPy_Material * self ); +static PyObject *Material_getSpec( BPy_Material * self ); +static PyObject *Material_getSpecTransp( BPy_Material * self ); +static PyObject *Material_getAdd( BPy_Material * self ); +static PyObject *Material_getZOffset( BPy_Material * self ); +static PyObject *Material_getLightGroup( BPy_Material * self ); +static PyObject *Material_getHaloSize( BPy_Material * self ); +static PyObject *Material_getHaloSeed( BPy_Material * self ); +static PyObject *Material_getFlareSize( BPy_Material * self ); +static PyObject *Material_getFlareSeed( BPy_Material * self ); +static PyObject *Material_getFlareBoost( BPy_Material * self ); +static PyObject *Material_getSubSize( BPy_Material * self ); +static PyObject *Material_getHardness( BPy_Material * self ); +static PyObject *Material_getNFlares( BPy_Material * self ); +static PyObject *Material_getNStars( BPy_Material * self ); +static PyObject *Material_getNLines( BPy_Material * self ); +static PyObject *Material_getNRings( BPy_Material * self ); +/* Shader settings */ +static PyObject *Material_getSpecShader( BPy_Material * self ); +static PyObject *Material_getDiffuseShader( BPy_Material * self ); +static PyObject *Material_getRoughness( BPy_Material * self ); +static PyObject *Material_getSpecSize( BPy_Material * self ); +static PyObject *Material_getDiffuseSize( BPy_Material * self ); +static PyObject *Material_getSpecSmooth( BPy_Material * self ); +static PyObject *Material_getDiffuseSmooth( BPy_Material * self ); +static PyObject *Material_getDiffuseDarkness( BPy_Material * self ); +static PyObject *Material_getRefracIndex( BPy_Material * self ); +static PyObject *Material_getRms( BPy_Material * self ); + +static PyObject *Material_getRayMirr( BPy_Material * self ); +static PyObject *Material_getMirrDepth( BPy_Material * self ); +static PyObject *Material_getFresnelMirr( BPy_Material * self ); +static PyObject *Material_getFresnelMirrFac( BPy_Material * self ); +static PyObject *Material_getIOR( BPy_Material * self ); +static PyObject *Material_getTransDepth( BPy_Material * self ); +static PyObject *Material_getFresnelTrans( BPy_Material * self ); +static PyObject *Material_getFresnelTransFac( BPy_Material * self ); +static PyObject *Material_getRigidBodyFriction( BPy_Material * self ); +static PyObject *Material_getRigidBodyRestitution( BPy_Material * self ); + +static PyObject *Material_getSssEnable( BPy_Material * self ); +static PyObject *Material_getSssScale( BPy_Material * self ); +static PyObject *Material_getSssRadius( BPy_Material * self, void * type ); +static PyObject *Material_getSssIOR( BPy_Material * self ); +static PyObject *Material_getSssError( BPy_Material * self ); +static PyObject *Material_getSssColorBlend( BPy_Material * self ); +static PyObject *Material_getSssTexScatter( BPy_Material * self ); +static PyObject *Material_getSssFront( BPy_Material * self ); +static PyObject *Material_getSssBack( BPy_Material * self ); +static PyObject *Material_getSssBack( BPy_Material * self ); + +static PyObject *Material_getFilter( BPy_Material * self ); +static PyObject *Material_getTranslucency( BPy_Material * self ); +static PyObject *Material_getTextures( BPy_Material * self ); +static PyObject *Material_clearIpo( BPy_Material * self ); + +static PyObject *Material_setTexture( BPy_Material * self, PyObject * args ); +static PyObject *Material_clearTexture( BPy_Material * self, PyObject * value ); + +static PyObject *Material_getScriptLinks(BPy_Material *self, PyObject * value ); +static PyObject *Material_addScriptLink(BPy_Material * self, PyObject * args ); +static PyObject *Material_clearScriptLinks(BPy_Material *self, PyObject *args); + +static PyObject *Material_insertIpoKey( BPy_Material * self, PyObject * args ); +static PyObject *Material_getColorband( BPy_Material * self, void * type); +int Material_setColorband( BPy_Material * self, PyObject * value, void * type); +static PyObject *Material_copy( BPy_Material * self ); + + +/*****************************************************************************/ +/* Python BPy_Material methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_Material_methods[] = { + /* name, method, flags, doc */ + {"getName", ( PyCFunction ) GenericLib_getName, METH_NOARGS, + "() - Return Material's name"}, + {"getIpo", ( PyCFunction ) Material_getIpo, METH_NOARGS, + "() - Return Material's ipo or None if not found"}, + {"getMode", ( PyCFunction ) Material_getMode, METH_NOARGS, + "() - Return Material's mode flags"}, + {"getRGBCol", ( PyCFunction ) Material_getRGBCol, METH_NOARGS, + "() - Return Material's rgb color triplet"}, +/* {"getAmbCol", (PyCFunction)Material_getAmbCol, METH_NOARGS, + "() - Return Material's ambient color"},*/ + {"getSpecCol", ( PyCFunction ) Material_getSpecCol, METH_NOARGS, + "() - Return Material's specular color"}, + {"getMirCol", ( PyCFunction ) Material_getMirCol, METH_NOARGS, + "() - Return Material's mirror color"}, + {"getAmb", ( PyCFunction ) Material_getAmb, METH_NOARGS, + "() - Return Material's ambient color blend factor"}, + {"getEmit", ( PyCFunction ) Material_getEmit, METH_NOARGS, + "() - Return Material's emitting light intensity"}, + {"getAlpha", ( PyCFunction ) Material_getAlpha, METH_NOARGS, + "() - Return Material's alpha (transparency) value"}, + {"getRef", ( PyCFunction ) Material_getRef, METH_NOARGS, + "() - Return Material's reflectivity"}, + {"getSpec", ( PyCFunction ) Material_getSpec, METH_NOARGS, + "() - Return Material's specularity"}, + /* Shader specific settings */ + {"getSpecShader", ( PyCFunction ) Material_getSpecShader, METH_NOARGS, + "() - Returns Material's specular shader" }, + {"getDiffuseShader", ( PyCFunction ) Material_getDiffuseShader, METH_NOARGS, + "() - Returns Material's diffuse shader" }, + {"getRoughness", ( PyCFunction ) Material_getRoughness, METH_NOARGS, + "() - Returns Material's Roughness (applies to the \"Oren Nayar\" Diffuse Shader only)" }, + {"getSpecSize", ( PyCFunction ) Material_getSpecSize, METH_NOARGS, + "() - Returns Material's size of specular area (applies to the \"Toon\" Specular Shader only)" }, + {"getDiffuseSize", ( PyCFunction ) Material_getDiffuseSize, METH_NOARGS, + "() - Returns Material's size of diffuse area (applies to the \"Toon\" Diffuse Shader only)" }, + {"getSpecSmooth", ( PyCFunction ) Material_getSpecSmooth, METH_NOARGS, + "() - Returns Material's smoothing of specular area (applies to the \"Toon\" Diffuse Shader only)" }, + {"getDiffuseSmooth", ( PyCFunction ) Material_getDiffuseSmooth, METH_NOARGS, + "() - Returns Material's smoothing of diffuse area (applies to the \"Toon\" Diffuse Shader only)" }, + {"getDiffuseDarkness", ( PyCFunction ) Material_getDiffuseDarkness, METH_NOARGS, + "() - Returns Material's diffuse darkness (applies to the \"Minnaert\" Diffuse Shader only)" }, + {"getRefracIndex", ( PyCFunction ) Material_getRefracIndex, METH_NOARGS, + "() - Returns Material's Index of Refraction (applies to the \"Blinn\" Specular Shader only)" }, + {"getRms", ( PyCFunction ) Material_getRms, METH_NOARGS, + "() - Returns Material's standard deviation of surface slope (applies to the \"WardIso\" Specular Shader only)" }, + /* End shader settings */ + {"getSpecTransp", ( PyCFunction ) Material_getSpecTransp, METH_NOARGS, + "() - Return Material's specular transparency"}, + {"getAdd", ( PyCFunction ) Material_getAdd, METH_NOARGS, + "() - Return Material's glow factor"}, + {"getZOffset", ( PyCFunction ) Material_getZOffset, METH_NOARGS, + "() - Return Material's artificial offset for faces"}, + {"getHaloSize", ( PyCFunction ) Material_getHaloSize, METH_NOARGS, + "() - Return Material's halo size"}, + {"getHaloSeed", ( PyCFunction ) Material_getHaloSeed, METH_NOARGS, + "() - Return Material's seed for random ring dimension and line " + "location in halos"}, + {"getFlareSize", ( PyCFunction ) Material_getFlareSize, METH_NOARGS, + "() - Return Material's (flare size)/(halo size) factor"}, + {"getFlareSeed", ( PyCFunction ) Material_getFlareSeed, METH_NOARGS, + "() - Return Material's flare offset in the seed table"}, + {"getFlareBoost", ( PyCFunction ) Material_getFlareBoost, METH_NOARGS, + "() - Return Material's flare boost"}, + {"getSubSize", ( PyCFunction ) Material_getSubSize, METH_NOARGS, + "() - Return Material's dimension of subflare, dots and circles"}, + {"getHardness", ( PyCFunction ) Material_getHardness, METH_NOARGS, + "() - Return Material's specular hardness"}, + {"getNFlares", ( PyCFunction ) Material_getNFlares, METH_NOARGS, + "() - Return Material's number of flares in halo"}, + {"getNStars", ( PyCFunction ) Material_getNStars, METH_NOARGS, + "() - Return Material's number of points in the halo stars"}, + {"getNLines", ( PyCFunction ) Material_getNLines, METH_NOARGS, + "() - Return Material's number of lines in halo"}, + {"getNRings", ( PyCFunction ) Material_getNRings, METH_NOARGS, + "() - Return Material's number of rings in halo"}, + {"getRayMirr", ( PyCFunction ) Material_getRayMirr, METH_NOARGS, + "() - Return mount mirror"}, + {"getMirrDepth", ( PyCFunction ) Material_getMirrDepth, METH_NOARGS, + "() - Return amount mirror depth"}, + {"getFresnelMirr", ( PyCFunction ) Material_getFresnelMirr, METH_NOARGS, + "() - Return fresnel power for refractions"}, + {"getFresnelMirrFac", ( PyCFunction ) Material_getFresnelMirrFac, METH_NOARGS, + "() - Return fresnel power for refractions factor"}, + {"getFilter", ( PyCFunction ) Material_getFilter, METH_NOARGS, + "() - Return the amount of filtering when transparent raytrace is enabled"}, + {"getTranslucency", ( PyCFunction ) Material_getTranslucency, METH_NOARGS, + "() - Return the Translucency, the amount of diffuse shading of the back side"}, + {"getIOR", ( PyCFunction ) Material_getIOR, METH_NOARGS, + "() - Return IOR"}, + {"getTransDepth", ( PyCFunction ) Material_getTransDepth, METH_NOARGS, + "() - Return amount inter-refractions"}, + {"getFresnelTrans", ( PyCFunction ) Material_getFresnelTrans, METH_NOARGS, + "() - Return fresnel power for refractions"}, + {"getFresnelTransFac", ( PyCFunction ) Material_getFresnelTransFac, METH_NOARGS, + "() - Return fresnel power for refractions factor"}, + + {"getTextures", ( PyCFunction ) Material_getTextures, METH_NOARGS, + "() - Return Material's texture list as a tuple"}, + {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS, + "(s) - Change Material's name"}, + {"setIpo", ( PyCFunction ) Matr_oldsetIpo, METH_VARARGS, + "(Blender Ipo) - Change Material's Ipo"}, + {"clearIpo", ( PyCFunction ) Material_clearIpo, METH_NOARGS, + "(Blender Ipo) - Unlink Ipo from this Material"}, + {"insertIpoKey", ( PyCFunction ) Material_insertIpoKey, METH_VARARGS, + "(Material Ipo Constant) - Insert IPO Key at current frame"}, + {"setMode", ( PyCFunction ) Matr_oldsetMode, METH_VARARGS, + "([s[,s]]) - Set Material's mode flag(s)"}, + {"setRGBCol", ( PyCFunction ) Matr_oldsetRGBCol, METH_VARARGS, + "(f,f,f or [f,f,f]) - Set Material's rgb color triplet"}, +/* {"setAmbCol", (PyCFunction)Matr_oldsetAmbCol, METH_VARARGS, + "(f,f,f or [f,f,f]) - Set Material's ambient color"},*/ + {"setSpecCol", ( PyCFunction ) Matr_oldsetSpecCol, METH_VARARGS, + "(f,f,f or [f,f,f]) - Set Material's specular color"}, + + /* Shader spesific settings */ + {"setSpecShader", ( PyCFunction ) Matr_oldsetSpecShader, METH_VARARGS, + "(i) - Set the Material's specular shader" }, + {"setDiffuseShader", ( PyCFunction ) Matr_oldsetDiffuseShader, METH_VARARGS, + "(i) - Set the Material's diffuse shader" }, + {"setRoughness", ( PyCFunction ) Matr_oldsetRoughness, METH_VARARGS, + "(f) - Set the Material's Roughness (applies to the \"Oren Nayar\" Diffuse Shader only)" }, + {"setSpecSize", ( PyCFunction ) Matr_oldsetSpecSize, METH_VARARGS, + "(f) - Set the Material's size of specular area (applies to the \"Toon\" Specular Shader only)" }, + {"setDiffuseSize", ( PyCFunction ) Matr_oldsetDiffuseSize, METH_VARARGS, + "(f) - Set the Material's size of diffuse area (applies to the \"Toon\" Diffuse Shader only)" }, + {"setSpecSmooth", ( PyCFunction ) Matr_oldsetSpecSmooth, METH_VARARGS, + "(f) - Set the Material's smoothing of specular area (applies to the \"Toon\" Specular Shader only)" }, + {"setDiffuseSmooth", ( PyCFunction ) Matr_oldsetDiffuseSmooth, METH_VARARGS, + "(f) - Set the Material's smoothing of diffuse area (applies to the \"Toon\" Diffuse Shader only)" }, + {"setDiffuseDarkness", ( PyCFunction ) Matr_oldsetDiffuseDarkness, METH_VARARGS, + "(f) - Set the Material's diffuse darkness (applies to the \"Minnaert\" Diffuse Shader only)" }, + {"setRefracIndex", ( PyCFunction ) Matr_oldsetRefracIndex, METH_VARARGS, + "(f) - Set the Material's Index of Refraction (applies to the \"Blinn\" Specular Shader only)" }, + {"setRms", ( PyCFunction ) Matr_oldsetRms, METH_VARARGS, + "(f) - Set the Material's standard deviation of surface slope (applies to the \"WardIso\" Specular Shader only)" }, + /* End shader settings */ + + {"setMirCol", ( PyCFunction ) Matr_oldsetMirCol, METH_VARARGS, + "(f,f,f or [f,f,f]) - Set Material's mirror color"}, + {"setAmb", ( PyCFunction ) Matr_oldsetAmb, METH_VARARGS, + "(f) - Set how much the Material's color is affected" + " by \nthe global ambient colors - [0.0, 1.0]"}, + {"setEmit", ( PyCFunction ) Matr_oldsetEmit, METH_VARARGS, + "(f) - Set Material's emitting light intensity - [0.0, 1.0]"}, + {"setAlpha", ( PyCFunction ) Matr_oldsetAlpha, METH_VARARGS, + "(f) - Set Material's alpha (transparency) - [0.0, 1.0]"}, + {"setRef", ( PyCFunction ) Matr_oldsetRef, METH_VARARGS, + "(f) - Set Material's reflectivity - [0.0, 1.0]"}, + {"setSpec", ( PyCFunction ) Matr_oldsetSpec, METH_VARARGS, + "(f) - Set Material's specularity - [0.0, 2.0]"}, + {"setSpecTransp", ( PyCFunction ) Matr_oldsetSpecTransp, METH_VARARGS, + "(f) - Set Material's specular transparency - [0.0, 1.0]"}, + {"setAdd", ( PyCFunction ) Matr_oldsetAdd, METH_VARARGS, + "(f) - Set Material's glow factor - [0.0, 1.0]"}, + {"setZOffset", ( PyCFunction ) Matr_oldsetZOffset, METH_VARARGS, + "(f) - Set Material's artificial offset - [0.0, 10.0]"}, + {"setHaloSize", ( PyCFunction ) Matr_oldsetHaloSize, METH_VARARGS, + "(f) - Set Material's halo size - [0.0, 100.0]"}, + {"setHaloSeed", ( PyCFunction ) Matr_oldsetHaloSeed, METH_VARARGS, + "(i) - Set Material's halo seed - [0, 255]"}, + {"setFlareSize", ( PyCFunction ) Matr_oldsetFlareSize, METH_VARARGS, + "(f) - Set Material's factor: (flare size)/(halo size) - [0.1, 25.0]"}, + {"setFlareSeed", ( PyCFunction ) Matr_oldsetFlareSeed, METH_VARARGS, + "(i) - Set Material's flare seed - [0, 255]"}, + {"setFlareBoost", ( PyCFunction ) Matr_oldsetFlareBoost, METH_VARARGS, + "(f) - Set Material's flare boost - [0.1, 10.0]"}, + {"setSubSize", ( PyCFunction ) Matr_oldsetSubSize, METH_VARARGS, + "(f) - Set Material's dimension of subflare," + " dots and circles - [0.1, 25.0]"}, + {"setHardness", ( PyCFunction ) Matr_oldsetHardness, METH_VARARGS, + "(i) - Set Material's hardness - [1, 255 (127 if halo mode is ON)]"}, + {"setNFlares", ( PyCFunction ) Matr_oldsetNFlares, METH_VARARGS, + "(i) - Set Material's number of flares in halo - [1, 32]"}, + {"setNStars", ( PyCFunction ) Matr_oldsetNStars, METH_VARARGS, + "(i) - Set Material's number of stars in halo - [3, 50]"}, + {"setNLines", ( PyCFunction ) Matr_oldsetNLines, METH_VARARGS, + "(i) - Set Material's number of lines in halo - [0, 250]"}, + {"setNRings", ( PyCFunction ) Matr_oldsetNRings, METH_VARARGS, + "(i) - Set Material's number of rings in halo - [0, 24]"}, + {"setRayMirr", ( PyCFunction ) Matr_oldsetRayMirr, METH_VARARGS, + "(f) - Set amount mirror - [0.0, 1.0]"}, + {"setMirrDepth", ( PyCFunction ) Matr_oldsetMirrDepth, METH_VARARGS, + "(i) - Set amount inter-reflections - [0, 10]"}, + {"setFresnelMirr", ( PyCFunction ) Matr_oldsetFresnelMirr, METH_VARARGS, + "(f) - Set fresnel power for mirror - [0.0, 5.0]"}, + {"setFresnelMirrFac", ( PyCFunction ) Matr_oldsetFresnelMirrFac, METH_VARARGS, + "(f) - Set blend fac for mirror fresnel - [1.0, 5.0]"}, + {"setFilter", ( PyCFunction ) Matr_oldsetFilter, METH_VARARGS, + "(f) - Set the amount of filtering when transparent raytrace is enabled"}, + {"setTranslucency", ( PyCFunction ) Matr_oldsetTranslucency, METH_VARARGS, + "(f) - Set the Translucency, the amount of diffuse shading of the back side"}, + {"setIOR", ( PyCFunction ) Matr_oldsetIOR, METH_VARARGS, + "(f) - Set IOR - [1.0, 3.0]"}, + {"setTransDepth", ( PyCFunction ) Matr_oldsetTransDepth, METH_VARARGS, + "(i) - Set amount inter-refractions - [0, 10]"}, + {"setFresnelTrans", ( PyCFunction ) Matr_oldsetFresnelTrans, METH_VARARGS, + "(f) - Set fresnel power for refractions - [0.0, 5.0]"}, + {"setFresnelTransFac", ( PyCFunction ) Matr_oldsetFresnelTransFac, METH_VARARGS, + "(f) - Set fresnel power for refractions factor- [0.0, 5.0]"}, + {"setTexture", ( PyCFunction ) Material_setTexture, METH_VARARGS, + "(n,tex,texco=0,mapto=0) - Set numbered texture to tex"}, + {"clearTexture", ( PyCFunction ) Material_clearTexture, METH_O, + "(n) - Remove texture from numbered slot"}, + {"getScriptLinks", ( PyCFunction ) Material_getScriptLinks, METH_O, + "(eventname) - Get a list of this material's scriptlinks (Text names) " + "of the given type\n" + "(eventname) - string: FrameChanged, Redraw or Render."}, + {"addScriptLink", ( PyCFunction ) Material_addScriptLink, METH_VARARGS, + "(text, evt) - Add a new material scriptlink.\n" + "(text) - string: an existing Blender Text name;\n" + "(evt) string: FrameChanged, Redraw or Render."}, + {"clearScriptLinks", ( PyCFunction ) Material_clearScriptLinks, METH_VARARGS, + "() - Delete all scriptlinks from this material.\n" + "([s1<,s2,s3...>]) - Delete specified scriptlinks from this material."}, + {"__copy__", ( PyCFunction ) Material_copy, METH_NOARGS, + "() - Return a copy of the material."}, + {"copy", ( PyCFunction ) Material_copy, METH_NOARGS, + "() - Return a copy of the material."}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python attributes get/set structure: */ +/*****************************************************************************/ + +static PyGetSetDef BPy_Material_getseters[] = { + GENERIC_LIB_GETSETATTR, + {"add", + (getter)Material_getAdd, (setter)Material_setAdd, + "Strength of the add effect", + NULL}, + {"alpha", + (getter)Material_getAlpha, (setter)Material_setAlpha, + "Alpha setting ", + NULL}, + {"shadAlpha", + (getter)Material_getShadAlpha, (setter)Material_setShadAlpha, + "Shadow Alpha setting", + NULL}, + {"amb", + (getter)Material_getAmb, (setter)Material_setAmb, + "Amount of global ambient color material receives", + NULL}, + {"diffuseDarkness", + (getter)Material_getDiffuseDarkness, (setter)Material_setDiffuseDarkness, + "Material's diffuse darkness (\"Minnaert\" diffuse shader only)", + NULL}, + {"diffuseShader", + (getter)Material_getDiffuseShader, (setter)Material_setDiffuseShader, + "Diffuse shader type", + NULL}, + {"diffuseSize", + (getter)Material_getDiffuseSize, (setter)Material_setDiffuseSize, + "Material's diffuse area size (\"Toon\" diffuse shader only)", + NULL}, + {"diffuseSmooth", + (getter)Material_getDiffuseSmooth, (setter)Material_setDiffuseSmooth, + "Material's diffuse area smoothing (\"Toon\" diffuse shader only)", + NULL}, + {"emit", + (getter)Material_getEmit, (setter)Material_setEmit, + "Amount of light the material emits", + NULL}, + {"filter", + (getter)Material_getFilter, (setter)Material_setFilter, + "Amount of filtering when transparent raytrace is enabled", + NULL}, + {"flareBoost", + (getter)Material_getFlareBoost, (setter)Material_setFlareBoost, + "Flare's extra strength", + NULL}, + {"flareSeed", + (getter)Material_getFlareSeed, (setter)Material_setFlareSeed, + "Offset in the flare seed table", + NULL}, + {"flareSize", + (getter)Material_getFlareSize, (setter)Material_setFlareSize, + "Ratio of flare size to halo size", + NULL}, + {"fresnelDepth", + (getter)Material_getFresnelMirr, (setter)Material_setFresnelMirr, + "Power of Fresnel for mirror reflection", + NULL}, + {"fresnelDepthFac", + (getter)Material_getFresnelMirrFac, (setter)Material_setFresnelMirrFac, + "Blending factor for Fresnel mirror", + NULL}, + {"fresnelTrans", + (getter)Material_getFresnelTrans, (setter)Material_setFresnelTrans, + "Power of Fresnel for transparency", + NULL}, + {"fresnelTransFac", + (getter)Material_getFresnelTransFac, (setter)Material_setFresnelTransFac, + "Blending factor for Fresnel transparency", + NULL}, + {"rbFriction", + (getter)Material_getRigidBodyFriction, (setter)Material_setRigidBodyFriction, + "Rigid Body Friction coefficient", + NULL}, + {"rbRestitution", + (getter)Material_getRigidBodyRestitution, (setter)Material_setRigidBodyRestitution, + "Rigid Body Restitution coefficient", + NULL}, + + {"haloSeed", + (getter)Material_getHaloSeed, (setter)Material_setHaloSeed, + "Randomizes halo ring dimension and line location", + NULL}, + {"haloSize", + (getter)Material_getHaloSize, (setter)Material_setHaloSize, + "Dimension of the halo", + NULL}, + {"hard", + (getter)Material_getHardness, (setter)Material_setHardness, + "Specularity hardness", + NULL}, + {"IOR", + (getter)Material_getIOR, (setter)Material_setIOR, + "Angular index of refraction for raytrace", + NULL}, + {"ipo", + (getter)Material_getIpo, (setter)Material_setIpo, + "Material Ipo data", + NULL}, + {"mirCol", + (getter)Material_getMirCol, (setter)Material_setMirCol, + "Mirror RGB color triplet", + NULL}, + {"mirR", + (getter)Material_getColorComponent, (setter)Material_setColorComponent, + "Mirror color red component", + (void *) EXPP_MAT_COMP_MIRR }, + {"mirG", + (getter)Material_getColorComponent, (setter)Material_setColorComponent, + "Mirror color green component", + (void *) EXPP_MAT_COMP_MIRG }, + {"mirB", + (getter)Material_getColorComponent, (setter)Material_setColorComponent, + "Mirror color blue component", + (void *) EXPP_MAT_COMP_MIRB }, + {"sssCol", + (getter)Material_getSssCol, (setter)Material_setSssCol, + "Sss RGB color triplet", + NULL}, + {"sssR", + (getter)Material_getColorComponent, (setter)Material_setColorComponent, + "SSS color red component", + (void *) EXPP_MAT_COMP_SSSR }, + {"sssG", + (getter)Material_getColorComponent, (setter)Material_setColorComponent, + "SSS color green component", + (void *) EXPP_MAT_COMP_SSSG }, + {"sssB", + (getter)Material_getColorComponent, (setter)Material_setColorComponent, + "SSS color blue component", + (void *) EXPP_MAT_COMP_SSSB }, + {"mode", + (getter)Material_getMode, (setter)Material_setMode, + "Material mode bitmask", + NULL}, + {"nFlares", + (getter)Material_getNFlares, (setter)Material_setNFlares, + "Number of subflares with halo", + NULL}, + {"nLines", + (getter)Material_getNLines, (setter)Material_setNLines, + "Number of star-shaped lines with halo", + NULL}, + {"nRings", + (getter)Material_getNRings, (setter)Material_setNRings, + "Number of rings with halo", + NULL}, + {"nStars", + (getter)Material_getNStars, (setter)Material_setNStars, + "Number of star points with halo", + NULL}, + {"rayMirr", + (getter)Material_getRayMirr, (setter)Material_setRayMirr, + "Mirror reflection amount for raytrace", + NULL}, + {"rayMirrDepth", + (getter)Material_getMirrDepth, (setter)Material_setMirrDepth, + "Amount of raytrace inter-reflections", + NULL}, + {"ref", + (getter)Material_getRef, (setter)Material_setRef, + "Amount of reflections (for shader)", + NULL}, + {"refracIndex", + (getter)Material_getRefracIndex, (setter)Material_setRefracIndex, + "Material's Index of Refraction (applies to the \"Blinn\" Specular Shader only", + NULL}, + {"rgbCol", + (getter)Material_getRGBCol, (setter)Material_setRGBCol, + "Diffuse RGB color triplet", + NULL}, + {"rms", + (getter)Material_getRms, (setter)Material_setRms, + "Material's surface slope standard deviation (\"WardIso\" specular shader only)", + NULL}, + {"roughness", + (getter)Material_getRoughness, (setter)Material_setRoughness, + "Material's roughness (\"Oren Nayar\" diffuse shader only)", + NULL}, + {"spec", + (getter)Material_getSpec, (setter)Material_setSpec, + "Degree of specularity", + NULL}, + {"specCol", + (getter)Material_getSpecCol, (setter)Material_setSpecCol, + "Specular RGB color triplet", + NULL}, + {"specR", + (getter)Material_getColorComponent, (setter)Material_setColorComponent, + "Specular color red component", + (void *) EXPP_MAT_COMP_SPECR }, + {"specG", + (getter)Material_getColorComponent, (setter)Material_setColorComponent, + "Specular color green component", + (void *) EXPP_MAT_COMP_SPECG }, + {"specB", + (getter)Material_getColorComponent, (setter)Material_setColorComponent, + "Specular color blue component", + (void *) EXPP_MAT_COMP_SPECB }, + {"specTransp", + (getter)Material_getSpecTransp, (setter)Material_setSpecTransp, + "Makes specular areas opaque on transparent materials", + NULL}, + {"specShader", + (getter)Material_getSpecShader, (setter)Material_setSpecShader, + "Specular shader type", + NULL}, + {"specSize", + (getter)Material_getSpecSize, (setter)Material_setSpecSize, + "Material's specular area size (\"Toon\" specular shader only)", + NULL}, + {"specSmooth", + (getter)Material_getSpecSmooth, (setter)Material_setSpecSmooth, + "Sets the smoothness of specular toon area", + NULL}, + {"subSize", + (getter)Material_getSubSize, (setter)Material_setSubSize, + "Dimension of subflares, dots and circles", + NULL}, + {"transDepth", + (getter)Material_getTransDepth, (setter)Material_setTransDepth, + "Amount of refractions for raytrace", + NULL}, + {"translucency", + (getter)Material_getTranslucency, (setter)Material_setTranslucency, + "Amount of diffuse shading of the back side", + NULL}, + {"zOffset", + (getter)Material_getZOffset, (setter)Material_setZOffset, + "Artificial offset in the Z buffer (for Ztransp option)", + NULL}, + {"lightGroup", + (getter)Material_getLightGroup, (setter)Material_setLightGroup, + "Set the light group for this material", + NULL}, + {"R", + (getter)Material_getColorComponent, (setter)Material_setColorComponent, + "Diffuse color red component", + (void *) EXPP_MAT_COMP_R }, + {"G", + (getter)Material_getColorComponent, (setter)Material_setColorComponent, + "Diffuse color green component", + (void *) EXPP_MAT_COMP_G }, + {"B", + (getter)Material_getColorComponent, (setter)Material_setColorComponent, + "Diffuse color blue component", + (void *) EXPP_MAT_COMP_B }, + {"colorbandDiffuse", + (getter)Material_getColorband, (setter)Material_setColorband, + "The diffuse colorband for this material", + (void *) 0}, + {"colorbandSpecular", + (getter)Material_getColorband, (setter)Material_setColorband, + "The specular colorband for this material", + (void *) 1}, + + /* SSS settings */ + {"enableSSS", + (getter)Material_getSssEnable, (setter)Material_setSssEnable, + "if true, SSS will be rendered for this material", + NULL}, + {"sssScale", + (getter)Material_getSssScale, (setter)Material_setSssScale, + "object scale for sss", + NULL}, + {"sssRadiusRed", + (getter)Material_getSssRadius, (setter)Material_setSssRadius, + "Mean red scattering path length", + (void *) 0}, + {"sssRadiusGreen", + (getter)Material_getSssRadius, (setter)Material_setSssRadius, + "Mean red scattering path length", + (void *) 1}, + {"sssRadiusBlue", + (getter)Material_getSssRadius, (setter)Material_setSssRadius, + "Mean red scattering path length", + (void *) 0}, + {"sssIOR", + (getter)Material_getSssIOR, (setter)Material_setSssIOR, + "index of refraction", + NULL}, + {"sssError", + (getter)Material_getSssError, (setter)Material_setSssError, + "Error", + NULL}, + {"sssColorBlend", + (getter)Material_getSssColorBlend, (setter)Material_setSssColorBlend, + "Blend factor for SSS Colors", + NULL}, + {"sssTextureScatter", + (getter)Material_getSssTexScatter, (setter)Material_setSssTexScatter, + "Texture scattering factor", + NULL}, + {"sssFont", + (getter)Material_getSssFront, (setter)Material_setSssFront, + "Front scattering weight", + NULL}, + {"sssBack", + (getter)Material_getSssBack, (setter)Material_setSssBack, + "Back scattering weight", + NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/*****************************************************************************/ +/* Python Material_Type callback function prototypes: */ +/*****************************************************************************/ +static void Material_dealloc( BPy_Material * self ); +static int Material_compare( BPy_Material * a, BPy_Material * b); +static PyObject *Material_repr( BPy_Material * self ); + +/*****************************************************************************/ +/* Python Material_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject Material_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender Material", /* char *tp_name; */ + sizeof( BPy_Material ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + ( destructor ) Material_dealloc,/* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) Material_compare,/* cmpfunc tp_compare; */ + ( reprfunc ) Material_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_Material_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_Material_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +/*****************************************************************************/ +/* Function: Material_dealloc */ +/* Description: This is a callback function for the BPy_Material type. It is */ +/* the destructor function. */ +/*****************************************************************************/ +static void Material_dealloc( BPy_Material * self ) +{ + Py_DECREF( self->col ); + Py_DECREF( self->amb ); + Py_DECREF( self->spec ); + Py_DECREF( self->mir ); + Py_DECREF( self->sss ); + PyObject_DEL( self ); +} + +/*****************************************************************************/ +/* Function: Material_CreatePyObject */ +/* Description: Create a new BPy_Material from an existing */ +/* Blender material structure. */ +/*****************************************************************************/ +PyObject *Material_CreatePyObject( struct Material *mat ) +{ + BPy_Material *pymat; + float *col[3], *amb[3], *spec[3], *mir[3], *sss[3]; + + pymat = ( BPy_Material * ) PyObject_NEW( BPy_Material, + &Material_Type ); + + if( !pymat ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create BPy_Material object" ); + + pymat->material = mat; + + col[0] = &mat->r; + col[1] = &mat->g; + col[2] = &mat->b; + + amb[0] = &mat->ambr; + amb[1] = &mat->ambg; + amb[2] = &mat->ambb; + + spec[0] = &mat->specr; + spec[1] = &mat->specg; + spec[2] = &mat->specb; + + mir[0] = &mat->mirr; + mir[1] = &mat->mirg; + mir[2] = &mat->mirb; + + sss[0] = &mat->sss_col[0]; + sss[1] = &mat->sss_col[1]; + sss[2] = &mat->sss_col[2]; + + pymat->col = ( BPy_rgbTuple * ) rgbTuple_New( col ); + pymat->amb = ( BPy_rgbTuple * ) rgbTuple_New( amb ); + pymat->spec = ( BPy_rgbTuple * ) rgbTuple_New( spec ); + pymat->mir = ( BPy_rgbTuple * ) rgbTuple_New( mir ); + pymat->sss = ( BPy_rgbTuple * ) rgbTuple_New( sss ); + + return ( PyObject * ) pymat; +} + +/*****************************************************************************/ +/* Function: Material_FromPyObject */ +/* Description: This function returns the Blender material from the given */ +/* PyObject. */ +/*****************************************************************************/ +Material *Material_FromPyObject( PyObject * pyobj ) +{ + return ( ( BPy_Material * ) pyobj )->material; +} + +static PyObject *Material_getIpo( BPy_Material * self ) +{ + Ipo *ipo = self->material->ipo; + + if( !ipo ) + Py_RETURN_NONE; + + return Ipo_CreatePyObject( ipo ); +} + +static PyObject *Material_getMode( BPy_Material * self ) +{ + return PyInt_FromLong( ( long ) self->material->mode ); +} + +static PyObject *Material_getRGBCol( BPy_Material * self ) +{ + return rgbTuple_getCol( self->col ); +} + +/* +static PyObject *Material_getAmbCol(BPy_Material *self) +{ + return rgbTuple_getCol(self->amb); +} +*/ +static PyObject *Material_getSpecCol( BPy_Material * self ) +{ + return rgbTuple_getCol( self->spec ); +} + +static PyObject *Material_getMirCol( BPy_Material * self ) +{ + return rgbTuple_getCol( self->mir ); +} + +static PyObject *Material_getSssCol( BPy_Material * self ) +{ + return rgbTuple_getCol( self->sss ); +} + +static PyObject *Material_getSpecShader( BPy_Material * self ) +{ + return PyInt_FromLong( ( long ) self->material->spec_shader ); +} + +static PyObject *Material_getDiffuseShader( BPy_Material * self ) +{ + return PyInt_FromLong( ( long ) self->material->diff_shader ); +} + +static PyObject *Material_getRoughness( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->roughness ); +} + +static PyObject *Material_getSpecSize( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->param[2] ); +} + +static PyObject *Material_getDiffuseSize( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->param[0] ); +} + +static PyObject *Material_getSpecSmooth( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->param[3] ); +} + +static PyObject *Material_getDiffuseSmooth( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->param[1] ); +} + +static PyObject *Material_getDiffuseDarkness( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->darkness ); +} + +static PyObject *Material_getRefracIndex( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->refrac ); +} + +static PyObject *Material_getRms( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->rms ); +} + +static PyObject *Material_getAmb( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->amb ); +} + +static PyObject *Material_getEmit( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->emit ); +} + +static PyObject *Material_getAlpha( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->alpha ); +} + +static PyObject *Material_getShadAlpha( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->shad_alpha ); +} + +static PyObject *Material_getRef( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->ref ); +} + +static PyObject *Material_getSpec( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->spec ); +} + +static PyObject *Material_getSpecTransp( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->spectra ); +} + +static PyObject *Material_getAdd( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->add ); +} + +static PyObject *Material_getZOffset( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->zoffs ); +} + +static PyObject *Material_getLightGroup( BPy_Material * self ) +{ + return Group_CreatePyObject( self->material->group ); +} + +static PyObject *Material_getHaloSize( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->hasize ); +} + +static PyObject *Material_getFlareSize( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->flaresize ); +} + +static PyObject *Material_getFlareBoost( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->flareboost ); +} + +static PyObject *Material_getSubSize( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->subsize ); +} + +static PyObject *Material_getHaloSeed( BPy_Material * self ) +{ + return PyInt_FromLong( ( long ) self->material->seed1 ); +} + +static PyObject *Material_getFlareSeed( BPy_Material * self ) +{ + return PyInt_FromLong( ( long ) self->material->seed2 ); +} + +static PyObject *Material_getHardness( BPy_Material * self ) +{ + return PyInt_FromLong( ( long ) self->material->har ); +} + +static PyObject *Material_getNFlares( BPy_Material * self ) +{ + return PyInt_FromLong( ( long ) self->material->flarec ); +} + +static PyObject *Material_getNStars( BPy_Material * self ) +{ + return PyInt_FromLong( ( long ) self->material->starc ); +} + +static PyObject *Material_getNLines( BPy_Material * self ) +{ + return PyInt_FromLong( ( long ) self->material->linec ); +} + +static PyObject *Material_getNRings( BPy_Material * self ) +{ + return PyInt_FromLong( ( long ) self->material->ringc ); +} + +static PyObject *Material_getRayMirr( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->ray_mirror ); +} + +static PyObject *Material_getMirrDepth( BPy_Material * self ) +{ + return PyInt_FromLong( ( long ) self->material->ray_depth ); +} + +static PyObject *Material_getFresnelMirr( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->fresnel_mir ); +} + +static PyObject *Material_getFresnelMirrFac( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->fresnel_mir_i ); +} + +static PyObject *Material_getFilter( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->filter ); +} + +static PyObject *Material_getTranslucency( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->translucency ); +} + +static PyObject *Material_getIOR( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->ang ); +} + +static PyObject *Material_getTransDepth( BPy_Material * self ) +{ + return PyInt_FromLong( ( long ) self->material->ray_depth_tra ); +} + +static PyObject *Material_getFresnelTrans( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->fresnel_tra ); +} + +static PyObject *Material_getFresnelTransFac( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->fresnel_tra_i ); +} + +static PyObject* Material_getRigidBodyFriction( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->friction ); +} + +static PyObject* Material_getRigidBodyRestitution( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->reflect ); +} + +/* SSS */ +static PyObject* Material_getSssEnable( BPy_Material * self ) +{ + return EXPP_getBitfield( &self->material->sss_flag, MA_DIFF_SSS, 'h' ); +} + +static PyObject* Material_getSssScale( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->sss_scale ); +} + +static PyObject* Material_getSssRadius( BPy_Material * self, void * type ) +{ + return PyFloat_FromDouble( ( double ) (self->material->sss_radius[(int)type]) ); +} + +static PyObject* Material_getSssIOR( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->sss_ior); +} + +static PyObject* Material_getSssError( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->sss_error); +} + +static PyObject* Material_getSssColorBlend( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->sss_colfac); +} + +static PyObject* Material_getSssTexScatter( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->sss_texfac); +} + +static PyObject* Material_getSssFront( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->sss_front); +} + +static PyObject* Material_getSssBack( BPy_Material * self ) +{ + return PyFloat_FromDouble( ( double ) self->material->sss_back); +} + +static PyObject *Material_getTextures( BPy_Material * self ) +{ + int i; + struct MTex *mtex; + PyObject *t[MAX_MTEX]; + PyObject *tuple; + + /* build a texture list */ + for( i = 0; i < MAX_MTEX; ++i ) { + mtex = self->material->mtex[i]; + + if( mtex ) { + t[i] = MTex_CreatePyObject( mtex ); + } else { + Py_INCREF( Py_None ); + t[i] = Py_None; + } + } + + /* turn the array into a tuple */ + tuple = Py_BuildValue( "NNNNNNNNNN", t[0], t[1], t[2], t[3], + t[4], t[5], t[6], t[7], t[8], t[9] ); + if( !tuple ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "Material_getTextures: couldn't create PyTuple" ); + + return tuple; +} + +/* + * this should accept a Py_None argument and just delete the Ipo link + * (as Lamp_clearIpo() does) + */ + +static int Material_setIpo( BPy_Material * self, PyObject * value ) +{ + return GenericLib_assignData(value, (void **) &self->material->ipo, 0, 1, ID_IP, ID_MA); +} + + +/* + * Material_insertIpoKey( key ) + * inserts Material IPO key at current frame + */ + +static PyObject *Material_insertIpoKey( BPy_Material * self, PyObject * args ) +{ + int key = 0, map; + + if( !PyArg_ParseTuple( args, "i", &( key ) ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected int argument" ) ); + + map = texchannel_to_adrcode(self->material->texact); + + if(key==IPOKEY_RGB || key==IPOKEY_ALLCOLOR) { + insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_COL_R, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_COL_G, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_COL_B, 0); + } + if(key==IPOKEY_ALPHA || key==IPOKEY_ALLCOLOR) { + insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_ALPHA, 0); + } + if(key==IPOKEY_HALOSIZE || key==IPOKEY_ALLCOLOR) { + insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_HASIZE, 0); + } + if(key==IPOKEY_MODE || key==IPOKEY_ALLCOLOR) { + insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_MODE, 0); + } + if(key==IPOKEY_ALLCOLOR) { + insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_SPEC_R, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_SPEC_G, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_SPEC_B, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_REF, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_EMIT, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_AMB, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_SPEC, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_HARD, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_MODE, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_TRANSLU, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_ADD, 0); + } + if(key==IPOKEY_ALLMIRROR) { + insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_RAYM, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_FRESMIR, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_FRESMIRI, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_FRESTRA, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_FRESTRAI, 0); + } + if(key==IPOKEY_OFS || key==IPOKEY_ALLMAPPING) { + insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_OFS_X, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_OFS_Y, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_OFS_Z, 0); + } + if(key==IPOKEY_SIZE || key==IPOKEY_ALLMAPPING) { + insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_SIZE_X, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_SIZE_Y, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_SIZE_Z, 0); + } + if(key==IPOKEY_ALLMAPPING) { + insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_R, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_G, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_B, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_DVAR, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_COLF, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_NORF, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_VARF, 0); + insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_DISP, 0); + } + + allspace(REMAKEIPO, 0); + EXPP_allqueue(REDRAWIPO, 0); + EXPP_allqueue(REDRAWVIEW3D, 0); + EXPP_allqueue(REDRAWACTION, 0); + EXPP_allqueue(REDRAWNLA, 0); + + Py_RETURN_NONE; +} + +static int Material_setMode( BPy_Material * self, PyObject * value ) +{ + int param; + + if( !PyInt_Check( value ) ) { + char errstr[128]; + sprintf ( errstr , "expected int bitmask of 0x%08x", MA_MODE_MASK ); + return EXPP_ReturnIntError( PyExc_TypeError, errstr ); + } + param = PyInt_AS_LONG ( value ); + + if ( ( param & MA_MODE_MASK ) != param ) + return EXPP_ReturnIntError( PyExc_ValueError, + "invalid bit(s) set in mask" ); + + self->material->mode &= ( MA_RAMP_COL | MA_RAMP_SPEC ); + self->material->mode |= param & ~( MA_RAMP_COL | MA_RAMP_SPEC ); + + return 0; +} + +static int Material_setRGBCol( BPy_Material * self, PyObject * value ) +{ + return rgbTuple_setCol( self->col, value ); +} + +/* +static PyObject *Material_setAmbCol (BPy_Material *self, PyObject * value ) +{ + return rgbTuple_setCol(self->amb, value); +} +*/ + +static int Material_setSpecCol( BPy_Material * self, PyObject * value ) +{ + return rgbTuple_setCol( self->spec, value ); +} + +static int Material_setMirCol( BPy_Material * self, PyObject * value ) +{ + return rgbTuple_setCol( self->mir, value ); +} + +static int Material_setSssCol( BPy_Material * self, PyObject * value ) +{ + return rgbTuple_setCol( self->sss, value ); +} + +static int Material_setColorComponent( BPy_Material * self, PyObject * value, + void * closure ) +{ + float param; + + if( !PyNumber_Check ( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected float argument in [0.0,1.0]" ); + + param = (float)PyFloat_AsDouble( value ); + param = EXPP_ClampFloat( param, EXPP_MAT_COL_MIN, EXPP_MAT_COL_MAX ); + + switch ( (int)closure ) { + case EXPP_MAT_COMP_R: + self->material->r = param; + return 0; + case EXPP_MAT_COMP_G: + self->material->g = param; + return 0; + case EXPP_MAT_COMP_B: + self->material->b = param; + return 0; + case EXPP_MAT_COMP_SPECR: + self->material->specr = param; + return 0; + case EXPP_MAT_COMP_SPECG: + self->material->specg = param; + return 0; + case EXPP_MAT_COMP_SPECB: + self->material->specb = param; + return 0; + case EXPP_MAT_COMP_MIRR: + self->material->mirr = param; + return 0; + case EXPP_MAT_COMP_MIRG: + self->material->mirg = param; + return 0; + case EXPP_MAT_COMP_MIRB: + self->material->mirb = param; + return 0; + case EXPP_MAT_COMP_SSSR: + self->material->sss_col[0] = param; + return 0; + case EXPP_MAT_COMP_SSSG: + self->material->sss_col[1] = param; + return 0; + case EXPP_MAT_COMP_SSSB: + self->material->sss_col[2] = param; + return 0; + } + return EXPP_ReturnIntError( PyExc_RuntimeError, + "unknown color component specified" ); +} + +/*#define setFloatWrapper(val, min, max) {return EXPP_setFloatClamped ( value, &self->material->#val, #min, #max}*/ + +static int Material_setAmb( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->amb, + EXPP_MAT_AMB_MIN, + EXPP_MAT_AMB_MAX ); +} + +static int Material_setEmit( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->emit, + EXPP_MAT_EMIT_MIN, + EXPP_MAT_EMIT_MAX ); +} + +static int Material_setSpecTransp( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->spectra, + EXPP_MAT_SPECTRA_MIN, + EXPP_MAT_SPECTRA_MAX ); +} + +static int Material_setAlpha( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->alpha, + EXPP_MAT_ALPHA_MIN, + EXPP_MAT_ALPHA_MAX ); +} + +static int Material_setShadAlpha( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->shad_alpha, + EXPP_MAT_ALPHA_MIN, + EXPP_MAT_ALPHA_MAX ); +} + +static int Material_setRef( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->ref, + EXPP_MAT_REF_MIN, + EXPP_MAT_REF_MAX ); +} + +static int Material_setSpec( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->spec, + EXPP_MAT_SPEC_MIN, + EXPP_MAT_SPEC_MAX ); +} + +static int Material_setZOffset( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->zoffs, + EXPP_MAT_ZOFFS_MIN, + EXPP_MAT_ZOFFS_MAX ); +} + +static int Material_setLightGroup( BPy_Material * self, PyObject * value ) +{ + return GenericLib_assignData(value, (void **) &self->material->group, NULL, 1, ID_GR, 0); +} + +static int Material_setAdd( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->add, + EXPP_MAT_ADD_MIN, + EXPP_MAT_ADD_MAX ); +} + +static int Material_setHaloSize( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->hasize, + EXPP_MAT_HALOSIZE_MIN, + EXPP_MAT_HALOSIZE_MAX ); +} + +static int Material_setFlareSize( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->flaresize, + EXPP_MAT_FLARESIZE_MIN, + EXPP_MAT_FLARESIZE_MAX ); +} + +static int Material_setFlareBoost( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->flareboost, + EXPP_MAT_FLAREBOOST_MIN, + EXPP_MAT_FLAREBOOST_MAX ); +} + +static int Material_setSubSize( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->subsize, + EXPP_MAT_SUBSIZE_MIN, + EXPP_MAT_SUBSIZE_MAX ); +} + +static int Material_setHaloSeed( BPy_Material * self, PyObject * value ) +{ + return EXPP_setIValueClamped ( value, &self->material->seed1, + EXPP_MAT_HALOSEED_MIN, + EXPP_MAT_HALOSEED_MAX, 'b' ); +} + +static int Material_setFlareSeed( BPy_Material * self, PyObject * value ) +{ + return EXPP_setIValueClamped ( value, &self->material->seed2, + EXPP_MAT_FLARESEED_MIN, + EXPP_MAT_FLARESEED_MAX, 'b' ); +} + +static int Material_setHardness( BPy_Material * self, PyObject * value ) +{ + return EXPP_setIValueClamped ( value, &self->material->har, + EXPP_MAT_HARD_MIN, + EXPP_MAT_HARD_MAX, 'h' ); +} + +static int Material_setNFlares( BPy_Material * self, PyObject * value ) +{ + return EXPP_setIValueClamped ( value, &self->material->flarec, + EXPP_MAT_NFLARES_MIN, + EXPP_MAT_NFLARES_MAX, 'h' ); +} + +static int Material_setNStars( BPy_Material * self, PyObject * value ) +{ + return EXPP_setIValueClamped ( value, &self->material->starc, + EXPP_MAT_NSTARS_MIN, + EXPP_MAT_NSTARS_MAX, 'h' ); +} + +static int Material_setNLines( BPy_Material * self, PyObject * value ) +{ + return EXPP_setIValueClamped ( value, &self->material->linec, + EXPP_MAT_NLINES_MIN, + EXPP_MAT_NLINES_MAX, 'h' ); +} + +static int Material_setNRings( BPy_Material * self, PyObject * value ) +{ + return EXPP_setIValueClamped ( value, &self->material->ringc, + EXPP_MAT_NRINGS_MIN, + EXPP_MAT_NRINGS_MAX, 'h' ); +} + +static int Material_setRayMirr( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->ray_mirror, + EXPP_MAT_RAYMIRR_MIN, + EXPP_MAT_RAYMIRR_MAX ); +} + +static int Material_setMirrDepth( BPy_Material * self, PyObject * value ) +{ + return EXPP_setIValueClamped ( value, &self->material->ray_depth, + EXPP_MAT_MIRRDEPTH_MIN, + EXPP_MAT_MIRRDEPTH_MAX, 'h' ); +} + +static int Material_setFresnelMirr( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->fresnel_mir, + EXPP_MAT_FRESNELMIRR_MIN, + EXPP_MAT_FRESNELMIRR_MAX ); +} + +static int Material_setFresnelMirrFac( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->fresnel_mir_i, + EXPP_MAT_FRESNELMIRRFAC_MIN, + EXPP_MAT_FRESNELMIRRFAC_MAX ); +} + +static int Material_setIOR( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->ang, + EXPP_MAT_IOR_MIN, + EXPP_MAT_IOR_MAX ); +} + +static int Material_setTransDepth( BPy_Material * self, PyObject * value ) +{ + return EXPP_setIValueClamped ( value, &self->material->ray_depth_tra, + EXPP_MAT_TRANSDEPTH_MIN, + EXPP_MAT_TRANSDEPTH_MAX, 'h' ); +} + +static int Material_setFresnelTrans( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->fresnel_tra, + EXPP_MAT_FRESNELTRANS_MIN, + EXPP_MAT_FRESNELTRANS_MAX ); +} + +static int Material_setFresnelTransFac( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->fresnel_tra_i, + EXPP_MAT_FRESNELTRANSFAC_MIN, + EXPP_MAT_FRESNELTRANSFAC_MAX ); +} + +static int Material_setRigidBodyFriction( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->friction, + 0.f, + 100.f ); +} + +static int Material_setRigidBodyRestitution( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->reflect, + 0.f, + 1.f ); +} + + + + +static int Material_setSpecShader( BPy_Material * self, PyObject * value ) +{ + return EXPP_setIValueRange( value, &self->material->spec_shader, + MA_SPEC_COOKTORR, + MA_SPEC_WARDISO, 'h' ); +} + +static int Material_setDiffuseShader( BPy_Material * self, PyObject * value ) +{ + return EXPP_setIValueRange( value, &self->material->diff_shader, + MA_DIFF_LAMBERT, + MA_DIFF_MINNAERT, 'h' ); +} + +static int Material_setRoughness( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->roughness, + EXPP_MAT_ROUGHNESS_MIN, + EXPP_MAT_ROUGHNESS_MAX ); +} + +static int Material_setSpecSize( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->param[2], + EXPP_MAT_SPECSIZE_MIN, + EXPP_MAT_SPECSIZE_MAX ); +} + +static int Material_setDiffuseSize( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->param[0], + EXPP_MAT_DIFFUSESIZE_MIN, + EXPP_MAT_DIFFUSESIZE_MAX ); +} + +static int Material_setSpecSmooth( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->param[3], + EXPP_MAT_SPECSMOOTH_MIN, + EXPP_MAT_SPECSMOOTH_MAX ); +} + +static int Material_setDiffuseSmooth( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->param[1], + EXPP_MAT_DIFFUSESMOOTH_MIN, + EXPP_MAT_DIFFUSESMOOTH_MAX ); +} + +static int Material_setDiffuseDarkness( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->darkness, + EXPP_MAT_DIFFUSE_DARKNESS_MIN, + EXPP_MAT_DIFFUSE_DARKNESS_MAX ); +} + +static int Material_setRefracIndex( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->refrac, + EXPP_MAT_REFRACINDEX_MIN, + EXPP_MAT_REFRACINDEX_MAX ); +} + +static int Material_setRms( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->rms, + EXPP_MAT_RMS_MIN, + EXPP_MAT_RMS_MAX ); +} + +static int Material_setFilter( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->filter, + EXPP_MAT_FILTER_MIN, + EXPP_MAT_FILTER_MAX ); +} + +static int Material_setTranslucency( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->translucency, + EXPP_MAT_TRANSLUCENCY_MIN, + EXPP_MAT_TRANSLUCENCY_MAX ); +} + +/* SSS */ +static int Material_setSssEnable( BPy_Material * self, PyObject * value ) +{ + return EXPP_setBitfield( value, &self->material->sss_flag, MA_DIFF_SSS, 'h' ); +} + +static int Material_setSssScale( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->sss_scale, + EXPP_MAT_SSS_SCALE_MIN, + EXPP_MAT_SSS_SCALE_MAX); +} + +static int Material_setSssRadius( BPy_Material * self, PyObject * value, void *type ) +{ + return EXPP_setFloatClamped ( value, &self->material->sss_radius[(int)type], + EXPP_MAT_SSS_RADIUS_MIN, + EXPP_MAT_SSS_RADIUS_MAX); +} + +static int Material_setSssIOR( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->sss_ior, + EXPP_MAT_SSS_IOR_MIN, + EXPP_MAT_SSS_IOR_MAX); +} + +static int Material_setSssError( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->sss_error, + EXPP_MAT_SSS_IOR_MIN, + EXPP_MAT_SSS_IOR_MAX); +} + +static int Material_setSssColorBlend( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->sss_colfac, + 0.0, + 1.0); +} + +static int Material_setSssTexScatter( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->sss_texfac, + 0.0, + 1.0); +} + +static int Material_setSssFront( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->sss_front, + EXPP_MAT_SSS_FRONT_MIN, + EXPP_MAT_SSS_FRONT_MAX); +} + +static int Material_setSssBack( BPy_Material * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->material->sss_back, + EXPP_MAT_SSS_BACK_MIN, + EXPP_MAT_SSS_BACK_MAX); +} + + + + +static PyObject *Material_setTexture( BPy_Material * self, PyObject * args ) +{ + int texnum; + PyObject *pytex; + Tex *bltex; + int texco = TEXCO_ORCO, mapto = MAP_COL; + + if( !PyArg_ParseTuple( args, "iO!|ii", &texnum, &Texture_Type, &pytex, + &texco, &mapto ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int in [0,9] and Texture" ); + if( ( texnum < 0 ) || ( texnum >= MAX_MTEX ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int in [0,9] and Texture" ); + + bltex = Texture_FromPyObject( pytex ); + + if( !self->material->mtex[texnum] ) { + /* there isn't an mtex for this slot so we need to make one */ + self->material->mtex[texnum] = add_mtex( ); + } else { + /* we already had a texture here so deal with the old one first */ + self->material->mtex[texnum]->tex->id.us--; + } + + self->material->mtex[texnum]->tex = bltex; + id_us_plus( &bltex->id ); + self->material->mtex[texnum]->texco = (short)texco; + self->material->mtex[texnum]->mapto = (short)mapto; + + Py_RETURN_NONE; +} + +static PyObject *Material_clearTexture( BPy_Material * self, PyObject * value ) +{ + int texnum = (int)PyInt_AsLong(value); + struct MTex *mtex; + /* non ints will be -1 */ + if( ( texnum < 0 ) || ( texnum >= MAX_MTEX ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int in [0,9]" ); + + mtex = self->material->mtex[texnum]; + if( mtex ) { + if( mtex->tex ) + mtex->tex->id.us--; + MEM_freeN( mtex ); + self->material->mtex[texnum] = NULL; + } + + Py_RETURN_NONE; +} + +/* mat.addScriptLink */ +static PyObject *Material_addScriptLink( BPy_Material * self, PyObject * args ) +{ + Material *mat = self->material; + ScriptLink *slink = NULL; + + slink = &( mat )->scriptlink; + + return EXPP_addScriptLink( slink, args, 0 ); +} + +/* mat.clearScriptLinks */ +static PyObject *Material_clearScriptLinks(BPy_Material *self, PyObject *args ) +{ + Material *mat = self->material; + ScriptLink *slink = NULL; + + slink = &( mat )->scriptlink; + + return EXPP_clearScriptLinks( slink, args ); +} + +/* mat.getScriptLinks */ +static PyObject *Material_getScriptLinks( BPy_Material * self, + PyObject * value ) +{ + Material *mat = self->material; + ScriptLink *slink = NULL; + PyObject *ret = NULL; + + slink = &( mat )->scriptlink; + + /* can't this just return? EXP_getScriptLinks() returns a PyObject* + * or NULL anyway */ + + ret = EXPP_getScriptLinks( slink, value, 0 ); + + if( ret ) + return ret; + else + return NULL; +} + +/* mat.__copy__ */ +static PyObject *Material_copy( BPy_Material * self ) +{ + BPy_Material *pymat; /* for Material Data object wrapper in Python */ + Material *blmat; /* for actual Material Data we create in Blender */ + + blmat = copy_material( self->material ); /* first copy the Material Data in Blender */ + + if( blmat ) /* now create the wrapper obj in Python */ + pymat = ( BPy_Material * ) Material_CreatePyObject( blmat ); + else + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't create Material Data in Blender" ) ); + + blmat->id.us = 0; /* was incref'ed by add_material() above */ + + if( pymat == NULL ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create Material Data object" ) ); + + return ( PyObject * ) pymat; +} + +/* mat_a==mat_b or mat_a!=mat_b*/ +static int Material_compare( BPy_Material * a, BPy_Material * b ) +{ + return ( a->material == b->material) ? 0 : -1; +} + +/*****************************************************************************/ +/* Function: Material_repr */ +/* Description: This is a callback function for the BPy_Material type. It */ +/* builds a meaninful string to represent material objects. */ +/*****************************************************************************/ +static PyObject *Material_repr( BPy_Material * self ) +{ + return PyString_FromFormat( "[Material \"%s\"]", + self->material->id.name + 2 ); +} + +/*****************************************************************************/ +/* These functions are used here and in in Texture.c */ +/*****************************************************************************/ +PyObject *EXPP_PyList_fromColorband( ColorBand *coba ) +{ + short i; + PyObject *cbls; + PyObject *colls; + + if (!coba) + return PyList_New( 0 ); + + cbls = PyList_New( coba->tot ); + + for (i=0; i < coba->tot; i++) { + colls = PyList_New( 5 ); + PyList_SET_ITEM( colls, 0, PyFloat_FromDouble(coba->data[i].r) ); + PyList_SET_ITEM( colls, 1, PyFloat_FromDouble(coba->data[i].g) ); + PyList_SET_ITEM( colls, 2, PyFloat_FromDouble(coba->data[i].b) ); + PyList_SET_ITEM( colls, 3, PyFloat_FromDouble(coba->data[i].a) ); + PyList_SET_ITEM( colls, 4, PyFloat_FromDouble(coba->data[i].pos) ); + PyList_SET_ITEM(cbls, i, colls); + } + return cbls; +} + +/* make sure you coba is not none before calling this */ +int EXPP_Colorband_fromPyList( ColorBand **coba, PyObject * value ) +{ + short totcol, i; + PyObject *colseq; + PyObject *pyflt; + float f; + + if ( !PySequence_Check( value ) ) + return ( EXPP_ReturnIntError( PyExc_TypeError, + "Colorband must be a sequence" ) ); + + totcol = PySequence_Size(value); + if ( totcol > 31) + return ( EXPP_ReturnIntError( PyExc_ValueError, + "Colorband must be between 1 and 31 in length" ) ); + + if (totcol==0) { + MEM_freeN(*coba); + *coba = NULL; + return 0; + } + + if (!*coba) + *coba = MEM_callocN( sizeof(ColorBand), "colorband"); + + for (i=0; itot = totcol; + for (i=0; idata[i].r = f; + Py_DECREF ( pyflt ); + + pyflt = PySequence_GetItem( colseq, 1 ); + f = (float)PyFloat_AsDouble( pyflt ); + CLAMP(f, 0.0, 1.0); + (*coba)->data[i].g = f; + Py_DECREF ( pyflt ); + + pyflt = PySequence_GetItem( colseq, 2 ); + f = (float)PyFloat_AsDouble( pyflt ); + CLAMP(f, 0.0, 1.0); + (*coba)->data[i].b = f; + Py_DECREF ( pyflt ); + + pyflt = PySequence_GetItem( colseq, 3 ); + f = (float)PyFloat_AsDouble( pyflt ); + CLAMP(f, 0.0, 1.0); + (*coba)->data[i].a = f; + Py_DECREF ( pyflt ); + + pyflt = PySequence_GetItem( colseq, 4 ); + f = (float)PyFloat_AsDouble( pyflt ); + CLAMP(f, 0.0, 1.0); + (*coba)->data[i].pos = f; + Py_DECREF ( pyflt ); + + Py_DECREF ( colseq ); + } + return 0; +} + + +/*****************************************************************************/ +/* These functions are used in NMesh.c and Object.c */ +/*****************************************************************************/ +PyObject *EXPP_PyList_fromMaterialList( Material ** matlist, int len, int all ) +{ + PyObject *list; + int i; + + list = PyList_New( 0 ); + if( !matlist ) + return list; + + for( i = 0; i < len; i++ ) { + Material *mat = matlist[i]; + PyObject *ob; + + if( mat ) { + ob = Material_CreatePyObject( mat ); + PyList_Append( list, ob ); + Py_DECREF( ob ); /* because Append increfs */ + } else if( all ) { /* return NULL mats (empty slots) as Py_None */ + PyList_Append( list, Py_None ); + } + } + + return list; +} + +Material **EXPP_newMaterialList_fromPyList( PyObject * list ) +{ + int i, len; + BPy_Material *pymat = 0; + Material *mat; + Material **matlist; + + len = PySequence_Length( list ); + if( len > 16 ) + len = 16; + else if( len <= 0 ) + return NULL; + + matlist = EXPP_newMaterialList( len ); + + for( i = 0; i < len; i++ ) { + + pymat = ( BPy_Material * ) PySequence_GetItem( list, i ); + + if( BPy_Material_Check( ( PyObject * ) pymat ) ) { + mat = pymat->material; + matlist[i] = mat; + } else if( ( PyObject * ) pymat == Py_None ) { + matlist[i] = NULL; + } else { /* error; illegal type in material list */ + Py_DECREF( pymat ); + MEM_freeN( matlist ); + return NULL; + } + + Py_DECREF( pymat ); + } + + return matlist; +} + +Material **EXPP_newMaterialList( int len ) +{ + Material **matlist = + ( Material ** ) MEM_mallocN( len * sizeof( Material * ), + "MaterialList" ); + + return matlist; +} + +int EXPP_releaseMaterialList( Material ** matlist, int len ) +{ + int i; + Material *mat; + + if( ( len < 0 ) || ( len > MAXMAT ) ) { + printf( "illegal matindex!\n" ); + return 0; + } + + for( i = 0; i < len; i++ ) { + mat = matlist[i]; + if( mat ) { + if( ( ( ID * ) mat )->us > 0 ) + ( ( ID * ) mat )->us--; + else + printf( "FATAL: material usage=0: %s", + ( ( ID * ) mat )->name ); + } + } + MEM_freeN( matlist ); + + return 1; +} + +/** expands pointer array of length 'oldsize' to length 'newsize'. + * A pointer to the (void *) array must be passed as first argument + * The array pointer content can be NULL, in this case a new array of length + * 'newsize' is created. + */ + +static int expandPtrArray( void **p, int oldsize, int newsize ) +{ + void *newarray; + + if( newsize < oldsize ) { + return 0; + } + newarray = MEM_callocN( sizeof( void * ) * newsize, "PtrArray" ); + if( *p ) { + memcpy( newarray, *p, sizeof( void * ) * oldsize ); + MEM_freeN( *p ); + } + *p = newarray; + return 1; +} + +int EXPP_synchronizeMaterialLists( Object * object ) +{ + Material ***p_dataMaterials = give_matarar( object ); + short *nmaterials = give_totcolp( object ); + int result = 0; + + if( object->totcol > *nmaterials ) { + /* More object mats than data mats */ + result = expandPtrArray( ( void * ) p_dataMaterials, + *nmaterials, object->totcol ); + *nmaterials = object->totcol; + } else { + if( object->totcol < *nmaterials ) { + /* More data mats than object mats */ + result = expandPtrArray( ( void * ) &object->mat, + object->totcol, *nmaterials ); + object->totcol = (char)*nmaterials; + } + } /* else no synchronization needed, they are of equal length */ + + return result; /* 1 if changed, 0 otherwise */ +} + +void EXPP_incr_mats_us( Material ** matlist, int len ) +{ + int i; + Material *mat; + + if( len <= 0 ) + return; + + for( i = 0; i < len; i++ ) { + mat = matlist[i]; + if( mat ) + mat->id.us++; + } + + return; +} + +static PyObject *Material_getColorComponent( BPy_Material * self, + void * closure ) +{ + switch ( (int)closure ) { + case EXPP_MAT_COMP_R: + return PyFloat_FromDouble( ( double ) self->material->r ); + case EXPP_MAT_COMP_G: + return PyFloat_FromDouble( ( double ) self->material->g ); + case EXPP_MAT_COMP_B: + return PyFloat_FromDouble( ( double ) self->material->b ); + case EXPP_MAT_COMP_SPECR: + return PyFloat_FromDouble( ( double ) self->material->specr ); + case EXPP_MAT_COMP_SPECG: + return PyFloat_FromDouble( ( double ) self->material->specg ); + case EXPP_MAT_COMP_SPECB: + return PyFloat_FromDouble( ( double ) self->material->specb ); + case EXPP_MAT_COMP_MIRR: + return PyFloat_FromDouble( ( double ) self->material->mirr ); + case EXPP_MAT_COMP_MIRG: + return PyFloat_FromDouble( ( double ) self->material->mirg ); + case EXPP_MAT_COMP_MIRB: + return PyFloat_FromDouble( ( double ) self->material->mirb ); + case EXPP_MAT_COMP_SSSR: + return PyFloat_FromDouble( ( double ) self->material->sss_col[0] ); + case EXPP_MAT_COMP_SSSG: + return PyFloat_FromDouble( ( double ) self->material->sss_col[1] ); + case EXPP_MAT_COMP_SSSB: + return PyFloat_FromDouble( ( double ) self->material->sss_col[2] ); + default: + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "unknown color component specified" ); + } +} + +static PyObject *Material_getColorband( BPy_Material * self, void * type) +{ + switch( (long)type ) { + case 0: /* these are backwards, but that how it works */ + return EXPP_PyList_fromColorband( self->material->ramp_col ); + case 1: + return EXPP_PyList_fromColorband( self->material->ramp_spec ); + } + Py_RETURN_NONE; +} + +int Material_setColorband( BPy_Material * self, PyObject * value, void * type) +{ + switch( (long)type ) { + case 0: /* these are backwards, but that how it works */ + return EXPP_Colorband_fromPyList( &self->material->ramp_col, value ); + case 1: + return EXPP_Colorband_fromPyList( &self->material->ramp_spec, value ); + } + return 0; +} + +/* #####DEPRECATED###### */ + +static PyObject *Matr_oldsetAdd( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setAdd ); +} + +static PyObject *Matr_oldsetAlpha( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setAlpha ); +} + +static PyObject *Matr_oldsetAmb( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setAmb ); +} + +static PyObject *Matr_oldsetDiffuseDarkness( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setDiffuseDarkness ); +} + +static PyObject *Matr_oldsetDiffuseShader( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setDiffuseShader ); +} + +static PyObject *Matr_oldsetDiffuseSize( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setDiffuseSize ); +} + +static PyObject *Matr_oldsetDiffuseSmooth( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setDiffuseSmooth ); +} + +static PyObject *Matr_oldsetEmit( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setEmit ); +} + +static PyObject *Matr_oldsetFilter( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setFilter ); +} + +static PyObject *Matr_oldsetFlareBoost( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setFlareBoost ); +} + +static PyObject *Matr_oldsetFlareSeed( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setFlareSeed ); +} + +static PyObject *Matr_oldsetFlareSize( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setFlareSize ); +} + +static PyObject *Matr_oldsetFresnelMirr( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setFresnelMirr ); +} + +static PyObject *Matr_oldsetFresnelMirrFac( BPy_Material * self, + PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setFresnelMirrFac ); +} + +static PyObject *Matr_oldsetFresnelTrans( BPy_Material * self, + PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setFresnelTrans ); +} + +static PyObject *Matr_oldsetFresnelTransFac( BPy_Material * self, + PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setFresnelTransFac ); +} + +static PyObject *Matr_oldsetHaloSeed( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setHaloSeed ); +} + +static PyObject *Matr_oldsetHaloSize( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setHaloSize ); +} + +static PyObject *Matr_oldsetHardness( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setHardness ); +} + +static PyObject *Matr_oldsetIOR( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setIOR ); +} + +static PyObject *Matr_oldsetNFlares( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setNFlares ); +} + +static PyObject *Matr_oldsetNLines( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setNLines ); +} + +static PyObject *Matr_oldsetNRings( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setNRings ); +} + +static PyObject *Matr_oldsetNStars( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setNStars ); +} + +static PyObject *Matr_oldsetRayMirr( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setRayMirr ); +} + +static PyObject *Matr_oldsetRoughness( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setRoughness ); +} + +static PyObject *Matr_oldsetMirrDepth( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setMirrDepth ); +} + +static PyObject *Matr_oldsetRef( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setRef ); +} + +static PyObject *Matr_oldsetRefracIndex( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setRefracIndex ); +} + +static PyObject *Matr_oldsetRms( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setRms ); +} + +static PyObject *Matr_oldsetSpec( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setSpec ); +} + +static PyObject *Matr_oldsetSpecShader( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setSpecShader ); +} + +static PyObject *Matr_oldsetSpecSize( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setSpecSize ); +} + +static PyObject *Matr_oldsetSpecSmooth( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setSpecSmooth ); +} + +static PyObject *Matr_oldsetSpecTransp( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setSpecTransp ); +} + +static PyObject *Matr_oldsetSubSize( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setSubSize ); +} + +static PyObject *Matr_oldsetTranslucency( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setTranslucency ); +} + +static PyObject *Matr_oldsetTransDepth( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setTransDepth ); +} + +static PyObject *Matr_oldsetZOffset( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setZOffset ); +} + +static PyObject *Matr_oldsetRGBCol( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapperTuple( (void *)self, args, + (setter)Material_setRGBCol ); +} + +static PyObject *Matr_oldsetSpecCol( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapperTuple( (void *)self, args, + (setter)Material_setSpecCol ); +} + +static PyObject *Matr_oldsetMirCol( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapperTuple( (void *)self, args, + (setter)Material_setMirCol ); +} + + +/* Possible modes are traceable, shadow, shadeless, wire, vcolLight, + * vcolPaint, halo, ztransp, zinvert, haloRings, env, haloLines, + * onlyShadow, xalpha, star, faceTexture, haloTex, haloPuno, noMist, + * haloShaded, haloFlare */ + +static PyObject *Matr_oldsetMode( BPy_Material * self, PyObject * args ) +{ + unsigned int i, flag = 0, ok = 0; + PyObject *value, *error; + char *m[28] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL + }; + + /* + * check for a single integer argument; do a quick check for now + * that the value is not larger than double the highest flag bit + */ + + if ( (PySequence_Size( args ) == 1) + && PyInt_Check ( PyTuple_GET_ITEM ( args , 0 ) ) + && PyArg_ParseTuple( args, "i", &flag ) + && (flag & MA_MODE_MASK ) == flag ) { + ok = 1; + + /* + * check for either an empty argument list, or up to 28 strings + */ + + } else if( PyArg_ParseTuple( args, "|ssssssssssssssssssssssssssss", + &m[0], &m[1], &m[2], &m[3], &m[4], &m[5], &m[6], + &m[7], &m[8], &m[9], &m[10], &m[11], &m[12], + &m[13], &m[14], &m[15], &m[16], &m[17], &m[18], + &m[19], &m[20], &m[21], &m[22], &m[23], &m[24], + &m[25], &m[26], &m[27] ) ) { + for( i = 0; i < 28; i++ ) { + if( m[i] == NULL ) + break; + if( strcmp( m[i], "Traceable" ) == 0 ) + flag |= MA_TRACEBLE; + else if( strcmp( m[i], "Shadow" ) == 0 ) + flag |= MA_SHADOW; + else if( strcmp( m[i], "Shadeless" ) == 0 ) + flag |= MA_SHLESS; + else if( strcmp( m[i], "Wire" ) == 0 ) + flag |= MA_WIRE; + else if( strcmp( m[i], "VColLight" ) == 0 ) + flag |= MA_VERTEXCOL; + else if( strcmp( m[i], "VColPaint" ) == 0 ) + flag |= MA_VERTEXCOLP; + else if( strcmp( m[i], "Halo" ) == 0 ) + flag |= MA_HALO; + else if( strcmp( m[i], "ZTransp" ) == 0 ) + flag |= MA_ZTRA; + else if( strcmp( m[i], "ZInvert" ) == 0 ) + flag |= MA_ZINV; + else if( strcmp( m[i], "HaloRings" ) == 0 ) + flag |= MA_HALO_RINGS; + else if( strcmp( m[i], "HaloLines" ) == 0 ) + flag |= MA_HALO_LINES; + else if( strcmp( m[i], "OnlyShadow" ) == 0 ) + flag |= MA_ONLYSHADOW; + else if( strcmp( m[i], "HaloXAlpha" ) == 0 ) + flag |= MA_HALO_XALPHA; + else if( strcmp( m[i], "HaloStar" ) == 0 ) + flag |= MA_STAR; + else if( strcmp( m[i], "TexFace" ) == 0 ) + flag |= MA_FACETEXTURE; + else if( strcmp( m[i], "HaloTex" ) == 0 ) + flag |= MA_HALOTEX; + else if( strcmp( m[i], "HaloPuno" ) == 0 ) + flag |= MA_HALOPUNO; + else if( strcmp( m[i], "NoMist" ) == 0 ) + flag |= MA_NOMIST; + else if( strcmp( m[i], "HaloShaded" ) == 0 ) + flag |= MA_HALO_SHADE; + else if( strcmp( m[i], "HaloFlare" ) == 0 ) + flag |= MA_HALO_FLARE; + else if( strcmp( m[i], "Radio" ) == 0 ) + flag |= MA_RADIO; + /* ** Mirror ** */ + else if( strcmp( m[i], "RayMirr" ) == 0 ) + flag |= MA_RAYMIRROR; + else if( strcmp( m[i], "ZTransp" ) == 0 ) + flag |= MA_ZTRA; + else if( strcmp( m[i], "RayTransp" ) == 0 ) + flag |= MA_RAYTRANSP; + else if( strcmp( m[i], "OnlyShadow" ) == 0 ) + flag |= MA_ONLYSHADOW; + else if( strcmp( m[i], "NoMist" ) == 0 ) + flag |= MA_NOMIST; + else if( strcmp( m[i], "Env" ) == 0 ) + flag |= MA_ENV; + else + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "unknown Material mode argument" ) ); + } + ok = 1; + } + + /* if neither input method worked, then throw an exception */ + + if ( ok == 0 ) + return ( EXPP_ReturnPyObjError + ( PyExc_AttributeError, + "expected nothing, an integer or up to 22 string argument(s)" ) ); + /* build tuple, call wrapper */ + + value = Py_BuildValue("(i)", flag); + error = EXPP_setterWrapper( (void *)self, value, (setter)Material_setMode ); + Py_DECREF ( value ); + return error; +} + +static PyObject *Matr_oldsetIpo( BPy_Material * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Material_setIpo ); +} + +/* + * clearIpo() returns True/False depending on whether material has an Ipo + */ + +static PyObject *Material_clearIpo( BPy_Material * self ) +{ + /* if Ipo defined, delete it and return true */ + + if( self->material->ipo ) { + PyObject *value = Py_BuildValue( "(O)", Py_None ); + EXPP_setterWrapper( (void *)self, value, (setter)Material_setIpo ); + Py_DECREF ( value ); + return EXPP_incr_ret_True(); + } + return EXPP_incr_ret_False(); /* no ipo found */ +} + diff --git a/source/blender/python/api2_2x/Material.h b/source/blender/python/api2_2x/Material.h new file mode 100644 index 00000000000..c4061f795c7 --- /dev/null +++ b/source/blender/python/api2_2x/Material.h @@ -0,0 +1,78 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_MATERIAL_H +#define EXPP_MATERIAL_H + +#include +#include "DNA_object_types.h" +#include "DNA_material_types.h" +#include "DNA_texture_types.h" /* colorband */ +#include "rgbTuple.h" + +/*****************************************************************************/ +/* Python BPy_Material structure definition: */ +/*****************************************************************************/ +typedef struct { + PyObject_HEAD + Material * material; /* libdata must be second */ + BPy_rgbTuple *col, *amb, *spec, *mir, *sss; +} BPy_Material; + +extern PyTypeObject Material_Type; /* The Material PyType Object */ + +#define BPy_Material_Check(v) \ + ((v)->ob_type == &Material_Type) /* for type checking */ + +/*****************************************************************************/ +/* Module Blender.Material - public functions */ +/*****************************************************************************/ +PyObject *M_Material_Init( void ); + +PyObject *Material_Init( void ); +PyObject *Material_CreatePyObject( Material * mat ); +Material *Material_FromPyObject( PyObject * pyobj ); + +/* colorband tp_getseters */ +PyObject *EXPP_PyList_fromColorband( ColorBand *coba ); +int EXPP_Colorband_fromPyList( ColorBand **coba, PyObject * value ); + +/* Some functions needed by NMesh, Curve and friends */ +PyObject *EXPP_PyList_fromMaterialList( Material ** matlist, int len, + int all ); +Material **EXPP_newMaterialList_fromPyList( PyObject * list ); +Material **EXPP_newMaterialList( int len ); +void EXPP_incr_mats_us( Material ** matlist, int len ); +int EXPP_synchronizeMaterialLists( Object * object ); +int EXPP_releaseMaterialList( Material ** matlist, int len ); + +#endif /* EXPP_MATERIAL_H */ diff --git a/source/blender/python/api2_2x/Mathutils.c b/source/blender/python/api2_2x/Mathutils.c new file mode 100644 index 00000000000..3605c956a58 --- /dev/null +++ b/source/blender/python/api2_2x/Mathutils.c @@ -0,0 +1,1804 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Joseph Gilbert, Campbell Barton + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "Mathutils.h" + +#include "BLI_arithb.h" +#include "PIL_time.h" +#include "BLI_rand.h" +#include "BKE_utildefines.h" + +#include "gen_utils.h" + +//-------------------------DOC STRINGS --------------------------- +static char M_Mathutils_doc[] = "The Blender Mathutils module\n\n"; +static char M_Mathutils_Vector_doc[] = "() - create a new vector object from a list of floats"; +static char M_Mathutils_Matrix_doc[] = "() - create a new matrix object from a list of floats"; +static char M_Mathutils_Quaternion_doc[] = "() - create a quaternion from a list or an axis of rotation and an angle"; +static char M_Mathutils_Euler_doc[] = "() - create and return a new euler object"; +static char M_Mathutils_Rand_doc[] = "() - return a random number"; +static char M_Mathutils_CrossVecs_doc[] = "() - returns a vector perpedicular to the 2 vectors crossed"; +static char M_Mathutils_CopyVec_doc[] = "() - create a copy of vector"; +static char M_Mathutils_DotVecs_doc[] = "() - return the dot product of two vectors"; +static char M_Mathutils_AngleBetweenVecs_doc[] = "() - returns the angle between two vectors in degrees"; +static char M_Mathutils_MidpointVecs_doc[] = "() - return the vector to the midpoint between two vectors"; +static char M_Mathutils_MatMultVec_doc[] = "() - multiplies a matrix by a column vector"; +static char M_Mathutils_VecMultMat_doc[] = "() - multiplies a row vector by a matrix"; +static char M_Mathutils_ProjectVecs_doc[] = "() - returns the projection vector from the projection of vecA onto vecB"; +static char M_Mathutils_RotationMatrix_doc[] = "() - construct a rotation matrix from an angle and axis of rotation"; +static char M_Mathutils_ScaleMatrix_doc[] = "() - construct a scaling matrix from a scaling factor"; +static char M_Mathutils_OrthoProjectionMatrix_doc[] = "() - construct a orthographic projection matrix from a selected plane"; +static char M_Mathutils_ShearMatrix_doc[] = "() - construct a shearing matrix from a plane of shear and a shear factor"; +static char M_Mathutils_CopyMat_doc[] = "() - create a copy of a matrix"; +static char M_Mathutils_TranslationMatrix_doc[] = "(vec) - create a translation matrix from a vector"; +static char M_Mathutils_CopyQuat_doc[] = "() - copy quatB to quatA"; +static char M_Mathutils_CopyEuler_doc[] = "() - copy eulB to eultA"; +static char M_Mathutils_CrossQuats_doc[] = "() - return the mutliplication of two quaternions"; +static char M_Mathutils_DotQuats_doc[] = "() - return the dot product of two quaternions"; +static char M_Mathutils_Slerp_doc[] = "() - returns the interpolation between two quaternions"; +static char M_Mathutils_DifferenceQuats_doc[] = "() - return the angular displacment difference between two quats"; +static char M_Mathutils_RotateEuler_doc[] = "() - rotate euler by an axis and angle"; +static char M_Mathutils_Intersect_doc[] = "(v1, v2, v3, ray, orig, clip=1) - returns the intersection between a ray and a triangle, if possible, returns None otherwise"; +static char M_Mathutils_TriangleArea_doc[] = "(v1, v2, v3) - returns the area size of the 2D or 3D triangle defined"; +static char M_Mathutils_TriangleNormal_doc[] = "(v1, v2, v3) - returns the normal of the 3D triangle defined"; +static char M_Mathutils_QuadNormal_doc[] = "(v1, v2, v3, v4) - returns the normal of the 3D quad defined"; +static char M_Mathutils_LineIntersect_doc[] = "(v1, v2, v3, v4) - returns a tuple with the points on each line respectively closest to the other"; +static char M_Mathutils_Point_doc[] = "Creates a 2d or 3d point object"; +//-----------------------METHOD DEFINITIONS ---------------------- +struct PyMethodDef M_Mathutils_methods[] = { + {"Rand", (PyCFunction) M_Mathutils_Rand, METH_VARARGS, M_Mathutils_Rand_doc}, + {"Vector", (PyCFunction) M_Mathutils_Vector, METH_VARARGS, M_Mathutils_Vector_doc}, + {"CrossVecs", (PyCFunction) M_Mathutils_CrossVecs, METH_VARARGS, M_Mathutils_CrossVecs_doc}, + {"DotVecs", (PyCFunction) M_Mathutils_DotVecs, METH_VARARGS, M_Mathutils_DotVecs_doc}, + {"AngleBetweenVecs", (PyCFunction) M_Mathutils_AngleBetweenVecs, METH_VARARGS, M_Mathutils_AngleBetweenVecs_doc}, + {"MidpointVecs", (PyCFunction) M_Mathutils_MidpointVecs, METH_VARARGS, M_Mathutils_MidpointVecs_doc}, + {"VecMultMat", (PyCFunction) M_Mathutils_VecMultMat, METH_VARARGS, M_Mathutils_VecMultMat_doc}, + {"ProjectVecs", (PyCFunction) M_Mathutils_ProjectVecs, METH_VARARGS, M_Mathutils_ProjectVecs_doc}, + {"CopyVec", (PyCFunction) M_Mathutils_CopyVec, METH_VARARGS, M_Mathutils_CopyVec_doc}, + {"Matrix", (PyCFunction) M_Mathutils_Matrix, METH_VARARGS, M_Mathutils_Matrix_doc}, + {"RotationMatrix", (PyCFunction) M_Mathutils_RotationMatrix, METH_VARARGS, M_Mathutils_RotationMatrix_doc}, + {"ScaleMatrix", (PyCFunction) M_Mathutils_ScaleMatrix, METH_VARARGS, M_Mathutils_ScaleMatrix_doc}, + {"ShearMatrix", (PyCFunction) M_Mathutils_ShearMatrix, METH_VARARGS, M_Mathutils_ShearMatrix_doc}, + {"TranslationMatrix", (PyCFunction) M_Mathutils_TranslationMatrix, METH_O, M_Mathutils_TranslationMatrix_doc}, + {"CopyMat", (PyCFunction) M_Mathutils_CopyMat, METH_VARARGS, M_Mathutils_CopyMat_doc}, + {"OrthoProjectionMatrix", (PyCFunction) M_Mathutils_OrthoProjectionMatrix, METH_VARARGS, M_Mathutils_OrthoProjectionMatrix_doc}, + {"MatMultVec", (PyCFunction) M_Mathutils_MatMultVec, METH_VARARGS, M_Mathutils_MatMultVec_doc}, + {"Quaternion", (PyCFunction) M_Mathutils_Quaternion, METH_VARARGS, M_Mathutils_Quaternion_doc}, + {"CopyQuat", (PyCFunction) M_Mathutils_CopyQuat, METH_VARARGS, M_Mathutils_CopyQuat_doc}, + {"CrossQuats", (PyCFunction) M_Mathutils_CrossQuats, METH_VARARGS, M_Mathutils_CrossQuats_doc}, + {"DotQuats", (PyCFunction) M_Mathutils_DotQuats, METH_VARARGS, M_Mathutils_DotQuats_doc}, + {"DifferenceQuats", (PyCFunction) M_Mathutils_DifferenceQuats, METH_VARARGS,M_Mathutils_DifferenceQuats_doc}, + {"Slerp", (PyCFunction) M_Mathutils_Slerp, METH_VARARGS, M_Mathutils_Slerp_doc}, + {"Euler", (PyCFunction) M_Mathutils_Euler, METH_VARARGS, M_Mathutils_Euler_doc}, + {"CopyEuler", (PyCFunction) M_Mathutils_CopyEuler, METH_VARARGS, M_Mathutils_CopyEuler_doc}, + {"RotateEuler", (PyCFunction) M_Mathutils_RotateEuler, METH_VARARGS, M_Mathutils_RotateEuler_doc}, + {"Intersect", ( PyCFunction ) M_Mathutils_Intersect, METH_VARARGS, M_Mathutils_Intersect_doc}, + {"TriangleArea", ( PyCFunction ) M_Mathutils_TriangleArea, METH_VARARGS, M_Mathutils_TriangleArea_doc}, + {"TriangleNormal", ( PyCFunction ) M_Mathutils_TriangleNormal, METH_VARARGS, M_Mathutils_TriangleNormal_doc}, + {"QuadNormal", ( PyCFunction ) M_Mathutils_QuadNormal, METH_VARARGS, M_Mathutils_QuadNormal_doc}, + {"LineIntersect", ( PyCFunction ) M_Mathutils_LineIntersect, METH_VARARGS, M_Mathutils_LineIntersect_doc}, + {"Point", (PyCFunction) M_Mathutils_Point, METH_VARARGS, M_Mathutils_Point_doc}, + {NULL, NULL, 0, NULL} +}; +//----------------------------MODULE INIT------------------------- +PyObject *Mathutils_Init(void) +{ + PyObject *submodule; + + //seed the generator for the rand function + BLI_srand((unsigned int) (PIL_check_seconds_timer() * + 0x7FFFFFFF)); + + /* needed for getseters */ + if( PyType_Ready( &vector_Type ) < 0 ) + return NULL; + if( PyType_Ready( &matrix_Type ) < 0 ) + return NULL; + if( PyType_Ready( &euler_Type ) < 0 ) + return NULL; + if( PyType_Ready( &quaternion_Type ) < 0 ) + return NULL; + + submodule = Py_InitModule3("Blender.Mathutils", + M_Mathutils_methods, M_Mathutils_doc); + return (submodule); +} +//-----------------------------METHODS---------------------------- +//----------------column_vector_multiplication (internal)--------- +//COLUMN VECTOR Multiplication (Matrix X Vector) +// [1][2][3] [a] +// [4][5][6] * [b] +// [7][8][9] [c] +//vector/matrix multiplication IS NOT COMMUTATIVE!!!! +PyObject *column_vector_multiplication(MatrixObject * mat, VectorObject* vec) +{ + float vecNew[4], vecCopy[4]; + double dot = 0.0f; + int x, y, z = 0; + + if(mat->rowSize != vec->size){ + if(mat->rowSize == 4 && vec->size != 3){ + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "matrix * vector: matrix row size and vector size must be the same"); + }else{ + vecCopy[3] = 1.0f; + } + } + + for(x = 0; x < vec->size; x++){ + vecCopy[x] = vec->vec[x]; + } + + for(x = 0; x < mat->rowSize; x++) { + for(y = 0; y < mat->colSize; y++) { + dot += mat->matrix[x][y] * vecCopy[y]; + } + vecNew[z++] = (float)dot; + dot = 0.0f; + } + return newVectorObject(vecNew, vec->size, Py_NEW); +} +//This is a helper for point/matrix translation + +PyObject *column_point_multiplication(MatrixObject * mat, PointObject* pt) +{ + float ptNew[4], ptCopy[4]; + double dot = 0.0f; + int x, y, z = 0; + + if(mat->rowSize != pt->size){ + if(mat->rowSize == 4 && pt->size != 3){ + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "matrix * point: matrix row size and point size must be the same\n"); + }else{ + ptCopy[3] = 0.0f; + } + } + + for(x = 0; x < pt->size; x++){ + ptCopy[x] = pt->coord[x]; + } + + for(x = 0; x < mat->rowSize; x++) { + for(y = 0; y < mat->colSize; y++) { + dot += mat->matrix[x][y] * ptCopy[y]; + } + ptNew[z++] = (float)dot; + dot = 0.0f; + } + return newPointObject(ptNew, pt->size, Py_NEW); +} +//-----------------row_vector_multiplication (internal)----------- +//ROW VECTOR Multiplication - Vector X Matrix +//[x][y][z] * [1][2][3] +// [4][5][6] +// [7][8][9] +//vector/matrix multiplication IS NOT COMMUTATIVE!!!! +PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat) +{ + float vecNew[4], vecCopy[4]; + double dot = 0.0f; + int x, y, z = 0, vec_size = vec->size; + + if(mat->colSize != vec_size){ + if(mat->rowSize == 4 && vec_size != 3){ + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "vector * matrix: matrix column size and the vector size must be the same"); + }else{ + vecCopy[3] = 1.0f; + } + } + + for(x = 0; x < vec_size; x++){ + vecCopy[x] = vec->vec[x]; + } + + //muliplication + for(x = 0; x < mat->colSize; x++) { + for(y = 0; y < mat->rowSize; y++) { + dot += mat->matrix[y][x] * vecCopy[y]; + } + vecNew[z++] = (float)dot; + dot = 0.0f; + } + return newVectorObject(vecNew, vec_size, Py_NEW); +} +//This is a helper for the point class +PyObject *row_point_multiplication(PointObject* pt, MatrixObject * mat) +{ + float ptNew[4], ptCopy[4]; + double dot = 0.0f; + int x, y, z = 0, size; + + if(mat->colSize != pt->size){ + if(mat->rowSize == 4 && pt->size != 3){ + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "point * matrix: matrix column size and the point size must be the same\n"); + }else{ + ptCopy[3] = 0.0f; + } + } + size = pt->size; + for(x = 0; x < pt->size; x++){ + ptCopy[x] = pt->coord[x]; + } + + //muliplication + for(x = 0; x < mat->colSize; x++) { + for(y = 0; y < mat->rowSize; y++) { + dot += mat->matrix[y][x] * ptCopy[y]; + } + ptNew[z++] = (float)dot; + dot = 0.0f; + } + return newPointObject(ptNew, size, Py_NEW); +} +//-----------------quat_rotation (internal)----------- +//This function multiplies a vector/point * quat or vice versa +//to rotate the point/vector by the quaternion +//arguments should all be 3D +PyObject *quat_rotation(PyObject *arg1, PyObject *arg2) +{ + float rot[3]; + QuaternionObject *quat = NULL; + VectorObject *vec = NULL; + PointObject *pt = NULL; + + if(QuaternionObject_Check(arg1)){ + quat = (QuaternionObject*)arg1; + if(VectorObject_Check(arg2)){ + vec = (VectorObject*)arg2; + rot[0] = quat->quat[0]*quat->quat[0]*vec->vec[0] + 2*quat->quat[2]*quat->quat[0]*vec->vec[2] - + 2*quat->quat[3]*quat->quat[0]*vec->vec[1] + quat->quat[1]*quat->quat[1]*vec->vec[0] + + 2*quat->quat[2]*quat->quat[1]*vec->vec[1] + 2*quat->quat[3]*quat->quat[1]*vec->vec[2] - + quat->quat[3]*quat->quat[3]*vec->vec[0] - quat->quat[2]*quat->quat[2]*vec->vec[0]; + rot[1] = 2*quat->quat[1]*quat->quat[2]*vec->vec[0] + quat->quat[2]*quat->quat[2]*vec->vec[1] + + 2*quat->quat[3]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[3]*vec->vec[0] - + quat->quat[3]*quat->quat[3]*vec->vec[1] + quat->quat[0]*quat->quat[0]*vec->vec[1] - + 2*quat->quat[1]*quat->quat[0]*vec->vec[2] - quat->quat[1]*quat->quat[1]*vec->vec[1]; + rot[2] = 2*quat->quat[1]*quat->quat[3]*vec->vec[0] + 2*quat->quat[2]*quat->quat[3]*vec->vec[1] + + quat->quat[3]*quat->quat[3]*vec->vec[2] - 2*quat->quat[0]*quat->quat[2]*vec->vec[0] - + quat->quat[2]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[1]*vec->vec[1] - + quat->quat[1]*quat->quat[1]*vec->vec[2] + quat->quat[0]*quat->quat[0]*vec->vec[2]; + return newVectorObject(rot, 3, Py_NEW); + }else if(PointObject_Check(arg2)){ + pt = (PointObject*)arg2; + rot[0] = quat->quat[0]*quat->quat[0]*pt->coord[0] + 2*quat->quat[2]*quat->quat[0]*pt->coord[2] - + 2*quat->quat[3]*quat->quat[0]*pt->coord[1] + quat->quat[1]*quat->quat[1]*pt->coord[0] + + 2*quat->quat[2]*quat->quat[1]*pt->coord[1] + 2*quat->quat[3]*quat->quat[1]*pt->coord[2] - + quat->quat[3]*quat->quat[3]*pt->coord[0] - quat->quat[2]*quat->quat[2]*pt->coord[0]; + rot[1] = 2*quat->quat[1]*quat->quat[2]*pt->coord[0] + quat->quat[2]*quat->quat[2]*pt->coord[1] + + 2*quat->quat[3]*quat->quat[2]*pt->coord[2] + 2*quat->quat[0]*quat->quat[3]*pt->coord[0] - + quat->quat[3]*quat->quat[3]*pt->coord[1] + quat->quat[0]*quat->quat[0]*pt->coord[1] - + 2*quat->quat[1]*quat->quat[0]*pt->coord[2] - quat->quat[1]*quat->quat[1]*pt->coord[1]; + rot[2] = 2*quat->quat[1]*quat->quat[3]*pt->coord[0] + 2*quat->quat[2]*quat->quat[3]*pt->coord[1] + + quat->quat[3]*quat->quat[3]*pt->coord[2] - 2*quat->quat[0]*quat->quat[2]*pt->coord[0] - + quat->quat[2]*quat->quat[2]*pt->coord[2] + 2*quat->quat[0]*quat->quat[1]*pt->coord[1] - + quat->quat[1]*quat->quat[1]*pt->coord[2] + quat->quat[0]*quat->quat[0]*pt->coord[2]; + return newPointObject(rot, 3, Py_NEW); + } + }else if(VectorObject_Check(arg1)){ + vec = (VectorObject*)arg1; + if(QuaternionObject_Check(arg2)){ + quat = (QuaternionObject*)arg2; + rot[0] = quat->quat[0]*quat->quat[0]*vec->vec[0] + 2*quat->quat[2]*quat->quat[0]*vec->vec[2] - + 2*quat->quat[3]*quat->quat[0]*vec->vec[1] + quat->quat[1]*quat->quat[1]*vec->vec[0] + + 2*quat->quat[2]*quat->quat[1]*vec->vec[1] + 2*quat->quat[3]*quat->quat[1]*vec->vec[2] - + quat->quat[3]*quat->quat[3]*vec->vec[0] - quat->quat[2]*quat->quat[2]*vec->vec[0]; + rot[1] = 2*quat->quat[1]*quat->quat[2]*vec->vec[0] + quat->quat[2]*quat->quat[2]*vec->vec[1] + + 2*quat->quat[3]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[3]*vec->vec[0] - + quat->quat[3]*quat->quat[3]*vec->vec[1] + quat->quat[0]*quat->quat[0]*vec->vec[1] - + 2*quat->quat[1]*quat->quat[0]*vec->vec[2] - quat->quat[1]*quat->quat[1]*vec->vec[1]; + rot[2] = 2*quat->quat[1]*quat->quat[3]*vec->vec[0] + 2*quat->quat[2]*quat->quat[3]*vec->vec[1] + + quat->quat[3]*quat->quat[3]*vec->vec[2] - 2*quat->quat[0]*quat->quat[2]*vec->vec[0] - + quat->quat[2]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[1]*vec->vec[1] - + quat->quat[1]*quat->quat[1]*vec->vec[2] + quat->quat[0]*quat->quat[0]*vec->vec[2]; + return newVectorObject(rot, 3, Py_NEW); + } + }else if(PointObject_Check(arg1)){ + pt = (PointObject*)arg1; + if(QuaternionObject_Check(arg2)){ + quat = (QuaternionObject*)arg2; + rot[0] = quat->quat[0]*quat->quat[0]*pt->coord[0] + 2*quat->quat[2]*quat->quat[0]*pt->coord[2] - + 2*quat->quat[3]*quat->quat[0]*pt->coord[1] + quat->quat[1]*quat->quat[1]*pt->coord[0] + + 2*quat->quat[2]*quat->quat[1]*pt->coord[1] + 2*quat->quat[3]*quat->quat[1]*pt->coord[2] - + quat->quat[3]*quat->quat[3]*pt->coord[0] - quat->quat[2]*quat->quat[2]*pt->coord[0]; + rot[1] = 2*quat->quat[1]*quat->quat[2]*pt->coord[0] + quat->quat[2]*quat->quat[2]*pt->coord[1] + + 2*quat->quat[3]*quat->quat[2]*pt->coord[2] + 2*quat->quat[0]*quat->quat[3]*pt->coord[0] - + quat->quat[3]*quat->quat[3]*pt->coord[1] + quat->quat[0]*quat->quat[0]*pt->coord[1] - + 2*quat->quat[1]*quat->quat[0]*pt->coord[2] - quat->quat[1]*quat->quat[1]*pt->coord[1]; + rot[2] = 2*quat->quat[1]*quat->quat[3]*pt->coord[0] + 2*quat->quat[2]*quat->quat[3]*pt->coord[1] + + quat->quat[3]*quat->quat[3]*pt->coord[2] - 2*quat->quat[0]*quat->quat[2]*pt->coord[0] - + quat->quat[2]*quat->quat[2]*pt->coord[2] + 2*quat->quat[0]*quat->quat[1]*pt->coord[1] - + quat->quat[1]*quat->quat[1]*pt->coord[2] + quat->quat[0]*quat->quat[0]*pt->coord[2]; + return newPointObject(rot, 3, Py_NEW); + } + } + + return (EXPP_ReturnPyObjError(PyExc_RuntimeError, + "quat_rotation(internal): internal problem rotating vector/point\n")); +} + +//----------------------------------Mathutils.Rand() -------------------- +//returns a random number between a high and low value +PyObject *M_Mathutils_Rand(PyObject * self, PyObject * args) +{ + float high, low, range; + double rand; + //initializers + high = 1.0; + low = 0.0; + + if(!PyArg_ParseTuple(args, "|ff", &low, &high)) + return (EXPP_ReturnPyObjError(PyExc_TypeError, + "Mathutils.Rand(): expected nothing or optional (float, float)\n")); + + if((high < low) || (high < 0 && low > 0)) + return (EXPP_ReturnPyObjError(PyExc_ValueError, + "Mathutils.Rand(): high value should be larger than low value\n")); + + //get the random number 0 - 1 + rand = BLI_drand(); + + //set it to range + range = high - low; + rand = rand * range; + rand = rand + low; + + return PyFloat_FromDouble(rand); +} +//----------------------------------VECTOR FUNCTIONS--------------------- +//----------------------------------Mathutils.Vector() ------------------ +// Supports 2D, 3D, and 4D vector objects both int and float values +// accepted. Mixed float and int values accepted. Ints are parsed to float +PyObject *M_Mathutils_Vector(PyObject * self, PyObject * args) +{ + PyObject *listObject = NULL; + int size, i; + float vec[4]; + PyObject *v, *f; + + size = PySequence_Length(args); + if (size == 1) { + listObject = PySequence_GetItem(args, 0); + if (PySequence_Check(listObject)) { + size = PySequence_Length(listObject); + } else { // Single argument was not a sequence + Py_XDECREF(listObject); + return EXPP_ReturnPyObjError(PyExc_TypeError, + "Mathutils.Vector(): 2-4 floats or ints expected (optionally in a sequence)\n"); + } + } else if (size == 0) { + //returns a new empty 3d vector + return newVectorObject(NULL, 3, Py_NEW); + } else { + listObject = EXPP_incr_ret(args); + } + + if (size<2 || size>4) { // Invalid vector size + Py_XDECREF(listObject); + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.Vector(): 2-4 floats or ints expected (optionally in a sequence)\n"); + } + + for (i=0; isize != 3 || vec2->size != 3) + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.CrossVecs(): expects (2) 3D vector objects\n"); + + vecCross = newVectorObject(NULL, 3, Py_NEW); + Crossf(((VectorObject*)vecCross)->vec, vec1->vec, vec2->vec); + return vecCross; +} +//----------------------------------Mathutils.DotVec() ------------------- +//calculates the dot product of two vectors +PyObject *M_Mathutils_DotVecs(PyObject * self, PyObject * args) +{ + VectorObject *vec1 = NULL, *vec2 = NULL; + double dot = 0.0f; + int x; + + if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2)) + return EXPP_ReturnPyObjError(PyExc_TypeError, + "Mathutils.DotVecs(): expects (2) vector objects of the same size\n"); + if(vec1->size != vec2->size) + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.DotVecs(): expects (2) vector objects of the same size\n"); + + for(x = 0; x < vec1->size; x++) { + dot += vec1->vec[x] * vec2->vec[x]; + } + return PyFloat_FromDouble(dot); +} +//----------------------------------Mathutils.AngleBetweenVecs() --------- +//calculates the angle between 2 vectors +PyObject *M_Mathutils_AngleBetweenVecs(PyObject * self, PyObject * args) +{ + VectorObject *vec1 = NULL, *vec2 = NULL; + double dot = 0.0f, angleRads, test_v1 = 0.0f, test_v2 = 0.0f; + int x, size; + + if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2)) + goto AttributeError1; //not vectors + if(vec1->size != vec2->size) + goto AttributeError1; //bad sizes + + //since size is the same.... + size = vec1->size; + + for(x = 0; x < size; x++) { + test_v1 += vec1->vec[x] * vec1->vec[x]; + test_v2 += vec2->vec[x] * vec2->vec[x]; + } + if (!test_v1 || !test_v2){ + goto AttributeError2; //zero-length vector + } + + //dot product + for(x = 0; x < size; x++) { + dot += vec1->vec[x] * vec2->vec[x]; + } + dot /= (sqrt(test_v1) * sqrt(test_v2)); + + if (dot < -1.0f || dot > 1.0f) { + CLAMP(dot,-1.0f,1.0f); + } + angleRads = (double)acos(dot); + + return PyFloat_FromDouble(angleRads * (180/ Py_PI)); + +AttributeError1: + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.AngleBetweenVecs(): expects (2) VECTOR objects of the same size\n"); + +AttributeError2: + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.AngleBetweenVecs(): zero length vectors are not acceptable arguments\n"); +} +//----------------------------------Mathutils.MidpointVecs() ------------- +//calculates the midpoint between 2 vectors +PyObject *M_Mathutils_MidpointVecs(PyObject * self, PyObject * args) +{ + VectorObject *vec1 = NULL, *vec2 = NULL; + float vec[4]; + int x; + + if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2)) + return EXPP_ReturnPyObjError(PyExc_TypeError, + "Mathutils.MidpointVecs(): expects (2) vector objects of the same size\n"); + if(vec1->size != vec2->size) + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.MidpointVecs(): expects (2) vector objects of the same size\n"); + + for(x = 0; x < vec1->size; x++) { + vec[x] = 0.5f * (vec1->vec[x] + vec2->vec[x]); + } + return newVectorObject(vec, vec1->size, Py_NEW); +} +//----------------------------------Mathutils.ProjectVecs() ------------- +//projects vector 1 onto vector 2 +PyObject *M_Mathutils_ProjectVecs(PyObject * self, PyObject * args) +{ + VectorObject *vec1 = NULL, *vec2 = NULL; + float vec[4]; + double dot = 0.0f, dot2 = 0.0f; + int x, size; + + if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2)) + return EXPP_ReturnPyObjError(PyExc_TypeError, + "Mathutils.ProjectVecs(): expects (2) vector objects of the same size\n"); + if(vec1->size != vec2->size) + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.ProjectVecs(): expects (2) vector objects of the same size\n"); + + //since they are the same size... + size = vec1->size; + + //get dot products + for(x = 0; x < size; x++) { + dot += vec1->vec[x] * vec2->vec[x]; + dot2 += vec2->vec[x] * vec2->vec[x]; + } + //projection + dot /= dot2; + for(x = 0; x < size; x++) { + vec[x] = (float)(dot * vec2->vec[x]); + } + return newVectorObject(vec, size, Py_NEW); +} +//----------------------------------MATRIX FUNCTIONS-------------------- +//----------------------------------Mathutils.Matrix() ----------------- +//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc. +//create a new matrix type +PyObject *M_Mathutils_Matrix(PyObject * self, PyObject * args) +{ + PyObject *listObject = NULL; + PyObject *argObject, *m, *s, *f; + MatrixObject *mat; + int argSize, seqSize = 0, i, j; + float matrix[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + + argSize = PySequence_Length(args); + if(argSize > 4){ //bad arg nums + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n"); + } else if (argSize == 0) { //return empty 4D matrix + return (PyObject *) newMatrixObject(NULL, 4, 4, Py_NEW); + }else if (argSize == 1){ + //copy constructor for matrix objects + argObject = PySequence_GetItem(args, 0); + if(MatrixObject_Check(argObject)){ + mat = (MatrixObject*)argObject; + + argSize = mat->rowSize; //rows + seqSize = mat->colSize; //col + for(i = 0; i < (seqSize * argSize); i++){ + matrix[i] = mat->contigPtr[i]; + } + } + Py_DECREF(argObject); + }else{ //2-4 arguments (all seqs? all same size?) + for(i =0; i < argSize; i++){ + argObject = PySequence_GetItem(args, i); + if (PySequence_Check(argObject)) { //seq? + if(seqSize){ //0 at first + if(PySequence_Length(argObject) != seqSize){ //seq size not same + Py_DECREF(argObject); + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n"); + } + } + seqSize = PySequence_Length(argObject); + }else{ //arg not a sequence + Py_XDECREF(argObject); + return EXPP_ReturnPyObjError(PyExc_TypeError, + "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n"); + } + Py_DECREF(argObject); + } + //all is well... let's continue parsing + listObject = args; + for (i = 0; i < argSize; i++){ + m = PySequence_GetItem(listObject, i); + if (m == NULL) { // Failed to read sequence + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "Mathutils.Matrix(): failed to parse arguments...\n"); + } + + for (j = 0; j < seqSize; j++) { + s = PySequence_GetItem(m, j); + if (s == NULL) { // Failed to read sequence + Py_DECREF(m); + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "Mathutils.Matrix(): failed to parse arguments...\n"); + } + + f = PyNumber_Float(s); + if(f == NULL) { // parsed item is not a number + EXPP_decr2(m,s); + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n"); + } + + matrix[(seqSize*i)+j]=(float)PyFloat_AS_DOUBLE(f); + EXPP_decr2(f,s); + } + Py_DECREF(m); + } + } + return newMatrixObject(matrix, argSize, seqSize, Py_NEW); +} +//----------------------------------Mathutils.RotationMatrix() ---------- +//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc. +//creates a rotation matrix +PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args) +{ + VectorObject *vec = NULL; + char *axis = NULL; + int matSize; + float angle = 0.0f, norm = 0.0f, cosAngle = 0.0f, sinAngle = 0.0f; + float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + + if(!PyArg_ParseTuple + (args, "fi|sO!", &angle, &matSize, &axis, &vector_Type, &vec)) { + return EXPP_ReturnPyObjError (PyExc_TypeError, + "Mathutils.RotationMatrix(): expected float int and optional string and vector\n"); + } + + /* Clamp to -360:360 */ + while (angle<-360.0f) + angle+=360.0; + while (angle>360.0f) + angle-=360.0; + + if(matSize != 2 && matSize != 3 && matSize != 4) + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.RotationMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n"); + if(matSize == 2 && (axis != NULL || vec != NULL)) + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.RotationMatrix(): cannot create a 2x2 rotation matrix around arbitrary axis\n"); + if((matSize == 3 || matSize == 4) && axis == NULL) + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.RotationMatrix(): please choose an axis of rotation for 3d and 4d matrices\n"); + if(axis) { + if(((strcmp(axis, "r") == 0) || + (strcmp(axis, "R") == 0)) && vec == NULL) + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.RotationMatrix(): please define the arbitrary axis of rotation\n"); + } + if(vec) { + if(vec->size != 3) + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.RotationMatrix(): the arbitrary axis must be a 3D vector\n"); + } + //convert to radians + angle = angle * (float) (Py_PI / 180); + if(axis == NULL && matSize == 2) { + //2D rotation matrix + mat[0] = (float) cos (angle); + mat[1] = (float) sin (angle); + mat[2] = -((float) sin(angle)); + mat[3] = (float) cos(angle); + } else if((strcmp(axis, "x") == 0) || (strcmp(axis, "X") == 0)) { + //rotation around X + mat[0] = 1.0f; + mat[4] = (float) cos(angle); + mat[5] = (float) sin(angle); + mat[7] = -((float) sin(angle)); + mat[8] = (float) cos(angle); + } else if((strcmp(axis, "y") == 0) || (strcmp(axis, "Y") == 0)) { + //rotation around Y + mat[0] = (float) cos(angle); + mat[2] = -((float) sin(angle)); + mat[4] = 1.0f; + mat[6] = (float) sin(angle); + mat[8] = (float) cos(angle); + } else if((strcmp(axis, "z") == 0) || (strcmp(axis, "Z") == 0)) { + //rotation around Z + mat[0] = (float) cos(angle); + mat[1] = (float) sin(angle); + mat[3] = -((float) sin(angle)); + mat[4] = (float) cos(angle); + mat[8] = 1.0f; + } else if((strcmp(axis, "r") == 0) || (strcmp(axis, "R") == 0)) { + //arbitrary rotation + //normalize arbitrary axis + norm = (float) sqrt(vec->vec[0] * vec->vec[0] + + vec->vec[1] * vec->vec[1] + + vec->vec[2] * vec->vec[2]); + vec->vec[0] /= norm; + vec->vec[1] /= norm; + vec->vec[2] /= norm; + + //create matrix + cosAngle = (float) cos(angle); + sinAngle = (float) sin(angle); + mat[0] = ((vec->vec[0] * vec->vec[0]) * (1 - cosAngle)) + + cosAngle; + mat[1] = ((vec->vec[0] * vec->vec[1]) * (1 - cosAngle)) + + (vec->vec[2] * sinAngle); + mat[2] = ((vec->vec[0] * vec->vec[2]) * (1 - cosAngle)) - + (vec->vec[1] * sinAngle); + mat[3] = ((vec->vec[0] * vec->vec[1]) * (1 - cosAngle)) - + (vec->vec[2] * sinAngle); + mat[4] = ((vec->vec[1] * vec->vec[1]) * (1 - cosAngle)) + + cosAngle; + mat[5] = ((vec->vec[1] * vec->vec[2]) * (1 - cosAngle)) + + (vec->vec[0] * sinAngle); + mat[6] = ((vec->vec[0] * vec->vec[2]) * (1 - cosAngle)) + + (vec->vec[1] * sinAngle); + mat[7] = ((vec->vec[1] * vec->vec[2]) * (1 - cosAngle)) - + (vec->vec[0] * sinAngle); + mat[8] = ((vec->vec[2] * vec->vec[2]) * (1 - cosAngle)) + + cosAngle; + } else { + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.RotationMatrix(): unrecognizable axis of rotation type - expected x,y,z or r\n"); + } + if(matSize == 4) { + //resize matrix + mat[10] = mat[8]; + mat[9] = mat[7]; + mat[8] = mat[6]; + mat[7] = 0.0f; + mat[6] = mat[5]; + mat[5] = mat[4]; + mat[4] = mat[3]; + mat[3] = 0.0f; + } + //pass to matrix creation + return newMatrixObject(mat, matSize, matSize, Py_NEW); +} +//----------------------------------Mathutils.TranslationMatrix() ------- +//creates a translation matrix +PyObject *M_Mathutils_TranslationMatrix(PyObject * self, VectorObject * vec) +{ + float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + + if(!VectorObject_Check(vec)) { + return EXPP_ReturnPyObjError(PyExc_TypeError, + "Mathutils.TranslationMatrix(): expected vector\n"); + } + if(vec->size != 3 && vec->size != 4) { + return EXPP_ReturnPyObjError(PyExc_TypeError, + "Mathutils.TranslationMatrix(): vector must be 3D or 4D\n"); + } + //create a identity matrix and add translation + Mat4One((float(*)[4]) mat); + mat[12] = vec->vec[0]; + mat[13] = vec->vec[1]; + mat[14] = vec->vec[2]; + + return newMatrixObject(mat, 4, 4, Py_NEW); +} +//----------------------------------Mathutils.ScaleMatrix() ------------- +//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc. +//creates a scaling matrix +PyObject *M_Mathutils_ScaleMatrix(PyObject * self, PyObject * args) +{ + VectorObject *vec = NULL; + float norm = 0.0f, factor; + int matSize, x; + float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + + if(!PyArg_ParseTuple + (args, "fi|O!", &factor, &matSize, &vector_Type, &vec)) { + return EXPP_ReturnPyObjError(PyExc_TypeError, + "Mathutils.ScaleMatrix(): expected float int and optional vector\n"); + } + if(matSize != 2 && matSize != 3 && matSize != 4) + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.ScaleMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n"); + if(vec) { + if(vec->size > 2 && matSize == 2) + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.ScaleMatrix(): please use 2D vectors when scaling in 2D\n"); + } + if(vec == NULL) { //scaling along axis + if(matSize == 2) { + mat[0] = factor; + mat[3] = factor; + } else { + mat[0] = factor; + mat[4] = factor; + mat[8] = factor; + } + } else { //scaling in arbitrary direction + //normalize arbitrary axis + for(x = 0; x < vec->size; x++) { + norm += vec->vec[x] * vec->vec[x]; + } + norm = (float) sqrt(norm); + for(x = 0; x < vec->size; x++) { + vec->vec[x] /= norm; + } + if(matSize == 2) { + mat[0] = 1 +((factor - 1) *(vec->vec[0] * vec->vec[0])); + mat[1] =((factor - 1) *(vec->vec[0] * vec->vec[1])); + mat[2] =((factor - 1) *(vec->vec[0] * vec->vec[1])); + mat[3] = 1 + ((factor - 1) *(vec->vec[1] * vec->vec[1])); + } else { + mat[0] = 1 + ((factor - 1) *(vec->vec[0] * vec->vec[0])); + mat[1] =((factor - 1) *(vec->vec[0] * vec->vec[1])); + mat[2] =((factor - 1) *(vec->vec[0] * vec->vec[2])); + mat[3] =((factor - 1) *(vec->vec[0] * vec->vec[1])); + mat[4] = 1 + ((factor - 1) *(vec->vec[1] * vec->vec[1])); + mat[5] =((factor - 1) *(vec->vec[1] * vec->vec[2])); + mat[6] =((factor - 1) *(vec->vec[0] * vec->vec[2])); + mat[7] =((factor - 1) *(vec->vec[1] * vec->vec[2])); + mat[8] = 1 + ((factor - 1) *(vec->vec[2] * vec->vec[2])); + } + } + if(matSize == 4) { + //resize matrix + mat[10] = mat[8]; + mat[9] = mat[7]; + mat[8] = mat[6]; + mat[7] = 0.0f; + mat[6] = mat[5]; + mat[5] = mat[4]; + mat[4] = mat[3]; + mat[3] = 0.0f; + } + //pass to matrix creation + return newMatrixObject(mat, matSize, matSize, Py_NEW); +} +//----------------------------------Mathutils.OrthoProjectionMatrix() --- +//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc. +//creates an ortho projection matrix +PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * args) +{ + VectorObject *vec = NULL; + char *plane; + int matSize, x; + float norm = 0.0f; + float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + + if(!PyArg_ParseTuple + (args, "si|O!", &plane, &matSize, &vector_Type, &vec)) { + return EXPP_ReturnPyObjError(PyExc_TypeError, + "Mathutils.OrthoProjectionMatrix(): expected string and int and optional vector\n"); + } + if(matSize != 2 && matSize != 3 && matSize != 4) + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.OrthoProjectionMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n"); + if(vec) { + if(vec->size > 2 && matSize == 2) + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.OrthoProjectionMatrix(): please use 2D vectors when scaling in 2D\n"); + } + if(vec == NULL) { //ortho projection onto cardinal plane + if(((strcmp(plane, "x") == 0) + || (strcmp(plane, "X") == 0)) && matSize == 2) { + mat[0] = 1.0f; + } else if(((strcmp(plane, "y") == 0) + || (strcmp(plane, "Y") == 0)) + && matSize == 2) { + mat[3] = 1.0f; + } else if(((strcmp(plane, "xy") == 0) + || (strcmp(plane, "XY") == 0)) + && matSize > 2) { + mat[0] = 1.0f; + mat[4] = 1.0f; + } else if(((strcmp(plane, "xz") == 0) + || (strcmp(plane, "XZ") == 0)) + && matSize > 2) { + mat[0] = 1.0f; + mat[8] = 1.0f; + } else if(((strcmp(plane, "yz") == 0) + || (strcmp(plane, "YZ") == 0)) + && matSize > 2) { + mat[4] = 1.0f; + mat[8] = 1.0f; + } else { + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.OrthoProjectionMatrix(): unknown plane - expected: x, y, xy, xz, yz\n"); + } + } else { //arbitrary plane + //normalize arbitrary axis + for(x = 0; x < vec->size; x++) { + norm += vec->vec[x] * vec->vec[x]; + } + norm = (float) sqrt(norm); + for(x = 0; x < vec->size; x++) { + vec->vec[x] /= norm; + } + if(((strcmp(plane, "r") == 0) + || (strcmp(plane, "R") == 0)) && matSize == 2) { + mat[0] = 1 - (vec->vec[0] * vec->vec[0]); + mat[1] = -(vec->vec[0] * vec->vec[1]); + mat[2] = -(vec->vec[0] * vec->vec[1]); + mat[3] = 1 - (vec->vec[1] * vec->vec[1]); + } else if(((strcmp(plane, "r") == 0) + || (strcmp(plane, "R") == 0)) + && matSize > 2) { + mat[0] = 1 - (vec->vec[0] * vec->vec[0]); + mat[1] = -(vec->vec[0] * vec->vec[1]); + mat[2] = -(vec->vec[0] * vec->vec[2]); + mat[3] = -(vec->vec[0] * vec->vec[1]); + mat[4] = 1 - (vec->vec[1] * vec->vec[1]); + mat[5] = -(vec->vec[1] * vec->vec[2]); + mat[6] = -(vec->vec[0] * vec->vec[2]); + mat[7] = -(vec->vec[1] * vec->vec[2]); + mat[8] = 1 - (vec->vec[2] * vec->vec[2]); + } else { + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.OrthoProjectionMatrix(): unknown plane - expected: 'r' expected for axis designation\n"); + } + } + if(matSize == 4) { + //resize matrix + mat[10] = mat[8]; + mat[9] = mat[7]; + mat[8] = mat[6]; + mat[7] = 0.0f; + mat[6] = mat[5]; + mat[5] = mat[4]; + mat[4] = mat[3]; + mat[3] = 0.0f; + } + //pass to matrix creation + return newMatrixObject(mat, matSize, matSize, Py_NEW); +} +//----------------------------------Mathutils.ShearMatrix() ------------- +//creates a shear matrix +PyObject *M_Mathutils_ShearMatrix(PyObject * self, PyObject * args) +{ + int matSize; + char *plane; + float factor; + float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + + if(!PyArg_ParseTuple(args, "sfi", &plane, &factor, &matSize)) { + return EXPP_ReturnPyObjError(PyExc_TypeError, + "Mathutils.ShearMatrix(): expected string float and int\n"); + } + if(matSize != 2 && matSize != 3 && matSize != 4) + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.ShearMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n"); + + if(((strcmp(plane, "x") == 0) || (strcmp(plane, "X") == 0)) + && matSize == 2) { + mat[0] = 1.0f; + mat[2] = factor; + mat[3] = 1.0f; + } else if(((strcmp(plane, "y") == 0) + || (strcmp(plane, "Y") == 0)) && matSize == 2) { + mat[0] = 1.0f; + mat[1] = factor; + mat[3] = 1.0f; + } else if(((strcmp(plane, "xy") == 0) + || (strcmp(plane, "XY") == 0)) && matSize > 2) { + mat[0] = 1.0f; + mat[4] = 1.0f; + mat[6] = factor; + mat[7] = factor; + } else if(((strcmp(plane, "xz") == 0) + || (strcmp(plane, "XZ") == 0)) && matSize > 2) { + mat[0] = 1.0f; + mat[3] = factor; + mat[4] = 1.0f; + mat[5] = factor; + mat[8] = 1.0f; + } else if(((strcmp(plane, "yz") == 0) + || (strcmp(plane, "YZ") == 0)) && matSize > 2) { + mat[0] = 1.0f; + mat[1] = factor; + mat[2] = factor; + mat[4] = 1.0f; + mat[8] = 1.0f; + } else { + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.ShearMatrix(): expected: x, y, xy, xz, yz or wrong matrix size for shearing plane\n"); + } + if(matSize == 4) { + //resize matrix + mat[10] = mat[8]; + mat[9] = mat[7]; + mat[8] = mat[6]; + mat[7] = 0.0f; + mat[6] = mat[5]; + mat[5] = mat[4]; + mat[4] = mat[3]; + mat[3] = 0.0f; + } + //pass to matrix creation + return newMatrixObject(mat, matSize, matSize, Py_NEW); +} +//----------------------------------QUATERNION FUNCTIONS----------------- +//----------------------------------Mathutils.Quaternion() -------------- +PyObject *M_Mathutils_Quaternion(PyObject * self, PyObject * args) +{ + PyObject *listObject = NULL, *n, *q, *f; + int size, i; + float quat[4]; + double norm = 0.0f, angle = 0.0f; + + size = PySequence_Length(args); + if (size == 1 || size == 2) { //seq? + listObject = PySequence_GetItem(args, 0); + if (PySequence_Check(listObject)) { + size = PySequence_Length(listObject); + if ((size == 4 && PySequence_Length(args) !=1) || + (size == 3 && PySequence_Length(args) !=2) || (size >4 || size < 3)) { + // invalid args/size + Py_DECREF(listObject); + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + } + if(size == 3){ //get angle in axis/angle + n = PyNumber_Float(PySequence_GetItem(args, 1)); + if(n == NULL) { // parsed item not a number or getItem fail + Py_DECREF(listObject); + return EXPP_ReturnPyObjError(PyExc_TypeError, + "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + } + angle = PyFloat_AS_DOUBLE(n); + Py_DECREF(n); + } + }else{ + listObject = PySequence_GetItem(args, 1); + if (size>1 && PySequence_Check(listObject)) { + size = PySequence_Length(listObject); + if (size != 3) { + // invalid args/size + Py_DECREF(listObject); + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + } + n = PyNumber_Float(PySequence_GetItem(args, 0)); + if(n == NULL) { // parsed item not a number or getItem fail + Py_DECREF(listObject); + return EXPP_ReturnPyObjError(PyExc_TypeError, + "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + } + angle = PyFloat_AS_DOUBLE(n); + Py_DECREF(n); + } else { // argument was not a sequence + Py_XDECREF(listObject); + return EXPP_ReturnPyObjError(PyExc_TypeError, + "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + } + } + } else if (size == 0) { //returns a new empty quat + return newQuaternionObject(NULL, Py_NEW); + } else { + listObject = EXPP_incr_ret(args); + } + + if (size == 3) { // invalid quat size + if(PySequence_Length(args) != 2){ + Py_DECREF(listObject); + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + } + }else{ + if(size != 4){ + Py_DECREF(listObject); + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + } + } + + for (i=0; iquat, quatV->quat); + + return newQuaternionObject(quat, Py_NEW); +} +//----------------------------------Mathutils.DotQuats() ---------------- +//returns the dot product of 2 quaternions +PyObject *M_Mathutils_DotQuats(PyObject * self, PyObject * args) +{ + QuaternionObject *quatU = NULL, *quatV = NULL; + double dot = 0.0f; + int x; + + if(!PyArg_ParseTuple(args, "O!O!", &quaternion_Type, &quatU, + &quaternion_Type, &quatV)) + return EXPP_ReturnPyObjError(PyExc_TypeError, "Mathutils.DotQuats(): expected Quaternion types"); + + for(x = 0; x < 4; x++) { + dot += quatU->quat[x] * quatV->quat[x]; + } + return PyFloat_FromDouble(dot); +} +//----------------------------------Mathutils.DifferenceQuats() --------- +//returns the difference between 2 quaternions +PyObject *M_Mathutils_DifferenceQuats(PyObject * self, PyObject * args) +{ + QuaternionObject *quatU = NULL, *quatV = NULL; + float quat[4], tempQuat[4]; + double dot = 0.0f; + int x; + + if(!PyArg_ParseTuple(args, "O!O!", &quaternion_Type, + &quatU, &quaternion_Type, &quatV)) + return EXPP_ReturnPyObjError(PyExc_TypeError, "Mathutils.DifferenceQuats(): expected Quaternion types"); + + tempQuat[0] = quatU->quat[0]; + tempQuat[1] = -quatU->quat[1]; + tempQuat[2] = -quatU->quat[2]; + tempQuat[3] = -quatU->quat[3]; + + dot = sqrt(tempQuat[0] * tempQuat[0] + tempQuat[1] * tempQuat[1] + + tempQuat[2] * tempQuat[2] + tempQuat[3] * tempQuat[3]); + + for(x = 0; x < 4; x++) { + tempQuat[x] /= (float)(dot * dot); + } + QuatMul(quat, tempQuat, quatV->quat); + return newQuaternionObject(quat, Py_NEW); +} +//----------------------------------Mathutils.Slerp() ------------------ +//attemps to interpolate 2 quaternions and return the result +PyObject *M_Mathutils_Slerp(PyObject * self, PyObject * args) +{ + QuaternionObject *quatU = NULL, *quatV = NULL; + float quat[4], quat_u[4], quat_v[4], param; + double x, y, dot, sinT, angle, IsinT; + int z; + + if(!PyArg_ParseTuple(args, "O!O!f", &quaternion_Type, + &quatU, &quaternion_Type, &quatV, ¶m)) + return EXPP_ReturnPyObjError(PyExc_TypeError, + "Mathutils.Slerp(): expected Quaternion types and float"); + + if(param > 1.0f || param < 0.0f) + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.Slerp(): interpolation factor must be between 0.0 and 1.0"); + + //copy quats + for(z = 0; z < 4; z++){ + quat_u[z] = quatU->quat[z]; + quat_v[z] = quatV->quat[z]; + } + + //dot product + dot = quat_u[0] * quat_v[0] + quat_u[1] * quat_v[1] + + quat_u[2] * quat_v[2] + quat_u[3] * quat_v[3]; + + //if negative negate a quat (shortest arc) + if(dot < 0.0f) { + quat_v[0] = -quat_v[0]; + quat_v[1] = -quat_v[1]; + quat_v[2] = -quat_v[2]; + quat_v[3] = -quat_v[3]; + dot = -dot; + } + if(dot > .99999f) { //very close + x = 1.0f - param; + y = param; + } else { + //calculate sin of angle + sinT = sqrt(1.0f - (dot * dot)); + //calculate angle + angle = atan2(sinT, dot); + //caluculate inverse of sin(theta) + IsinT = 1.0f / sinT; + x = sin((1.0f - param) * angle) * IsinT; + y = sin(param * angle) * IsinT; + } + //interpolate + quat[0] = (float)(quat_u[0] * x + quat_v[0] * y); + quat[1] = (float)(quat_u[1] * x + quat_v[1] * y); + quat[2] = (float)(quat_u[2] * x + quat_v[2] * y); + quat[3] = (float)(quat_u[3] * x + quat_v[3] * y); + + return newQuaternionObject(quat, Py_NEW); +} +//----------------------------------EULER FUNCTIONS---------------------- +//----------------------------------Mathutils.Euler() ------------------- +//makes a new euler for you to play with +PyObject *M_Mathutils_Euler(PyObject * self, PyObject * args) +{ + + PyObject *listObject = NULL; + int size, i; + float eul[3]; + PyObject *e, *f; + + size = PySequence_Length(args); + if (size == 1) { + listObject = PySequence_GetItem(args, 0); + if (PySequence_Check(listObject)) { + size = PySequence_Length(listObject); + } else { // Single argument was not a sequence + Py_DECREF(listObject); + return EXPP_ReturnPyObjError(PyExc_TypeError, + "Mathutils.Euler(): 3d numeric sequence expected\n"); + } + } else if (size == 0) { + //returns a new empty 3d euler + return newEulerObject(NULL, Py_NEW); + } else { + listObject = EXPP_incr_ret(args); + } + + if (size != 3) { // Invalid euler size + Py_DECREF(listObject); + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.Euler(): 3d numeric sequence expected\n"); + } + + for (i=0; i3) { // Invalid vector size + Py_XDECREF(listObject); + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mathutils.Point(): 2-3 floats or ints expected (optionally in a sequence)\n"); + } + + for (i=0; isize != 3 || vec2->size != 3 || vec3->size != 3 || + ray->size != 3 || ray_off->size != 3) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "only 3D vectors for all parameters\n" ) ); + + VECCOPY(v1, vec1->vec); + VECCOPY(v2, vec2->vec); + VECCOPY(v3, vec3->vec); + + VECCOPY(dir, ray->vec); + Normalize(dir); + + VECCOPY(orig, ray_off->vec); + + /* find vectors for two edges sharing v1 */ + VecSubf(e1, v2, v1); + VecSubf(e2, v3, v1); + + /* begin calculating determinant - also used to calculated U parameter */ + Crossf(pvec, dir, e2); + + /* if determinant is near zero, ray lies in plane of triangle */ + det = Inpf(e1, pvec); + + if (det > -0.000001 && det < 0.000001) { + return EXPP_incr_ret( Py_None ); + } + + inv_det = 1.0f / det; + + /* calculate distance from v1 to ray origin */ + VecSubf(tvec, orig, v1); + + /* calculate U parameter and test bounds */ + u = Inpf(tvec, pvec) * inv_det; + if (clip && (u < 0.0f || u > 1.0f)) { + return EXPP_incr_ret( Py_None ); + } + + /* prepare to test the V parameter */ + Crossf(qvec, tvec, e1); + + /* calculate V parameter and test bounds */ + v = Inpf(dir, qvec) * inv_det; + + if (clip && (v < 0.0f || u + v > 1.0f)) { + return EXPP_incr_ret( Py_None ); + } + + /* calculate t, ray intersects triangle */ + t = Inpf(e2, qvec) * inv_det; + + VecMulf(dir, t); + VecAddf(pvec, orig, dir); + + return newVectorObject(pvec, 3, Py_NEW); +} +//----------------------------------Mathutils.LineIntersect() ------------------- +/* Line-Line intersection using algorithm from mathworld.wolfram.com */ +PyObject *M_Mathutils_LineIntersect( PyObject * self, PyObject * args ) +{ + PyObject * tuple; + VectorObject *vec1, *vec2, *vec3, *vec4; + float v1[3], v2[3], v3[3], v4[3], i1[3], i2[3]; + + if( !PyArg_ParseTuple + ( args, "O!O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2 + , &vector_Type, &vec3, &vector_Type, &vec4 ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "expected 4 vector types\n" ) ); + if( vec1->size != vec2->size || vec1->size != vec3->size || vec1->size != vec2->size) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "vectors must be of the same size\n" ) ); + + if( vec1->size == 3 || vec1->size == 2) { + float a[3], b[3], c[3], ab[3], cb[3], dir1[3], dir2[3]; + float d; + if (vec1->size == 3) { + VECCOPY(v1, vec1->vec); + VECCOPY(v2, vec2->vec); + VECCOPY(v3, vec3->vec); + VECCOPY(v4, vec4->vec); + } + else { + v1[0] = vec1->vec[0]; + v1[1] = vec1->vec[1]; + v1[2] = 0.0f; + + v2[0] = vec2->vec[0]; + v2[1] = vec2->vec[1]; + v2[2] = 0.0f; + + v3[0] = vec3->vec[0]; + v3[1] = vec3->vec[1]; + v3[2] = 0.0f; + + v4[0] = vec4->vec[0]; + v4[1] = vec4->vec[1]; + v4[2] = 0.0f; + } + + VecSubf(c, v3, v1); + VecSubf(a, v2, v1); + VecSubf(b, v4, v3); + + VECCOPY(dir1, a); + Normalize(dir1); + VECCOPY(dir2, b); + Normalize(dir2); + d = Inpf(dir1, dir2); + if (d == 1.0f || d == -1.0f) { + /* colinear */ + return EXPP_incr_ret( Py_None ); + } + + Crossf(ab, a, b); + d = Inpf(c, ab); + + /* test if the two lines are coplanar */ + if (d > -0.000001f && d < 0.000001f) { + Crossf(cb, c, b); + + VecMulf(a, Inpf(cb, ab) / Inpf(ab, ab)); + VecAddf(i1, v1, a); + VECCOPY(i2, i1); + } + /* if not */ + else { + float n[3], t[3]; + VecSubf(t, v1, v3); + + /* offset between both plane where the lines lies */ + Crossf(n, a, b); + Projf(t, t, n); + + /* for the first line, offset the second line until it is coplanar */ + VecAddf(v3, v3, t); + VecAddf(v4, v4, t); + + VecSubf(c, v3, v1); + VecSubf(a, v2, v1); + VecSubf(b, v4, v3); + + Crossf(ab, a, b); + Crossf(cb, c, b); + + VecMulf(a, Inpf(cb, ab) / Inpf(ab, ab)); + VecAddf(i1, v1, a); + + /* for the second line, just substract the offset from the first intersection point */ + VecSubf(i2, i1, t); + } + + tuple = PyTuple_New( 2 ); + PyTuple_SetItem( tuple, 0, newVectorObject(i1, vec1->size, Py_NEW) ); + PyTuple_SetItem( tuple, 1, newVectorObject(i2, vec1->size, Py_NEW) ); + return tuple; + } + else { + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "2D/3D vectors only\n" ) ); + } +} + + + +//---------------------------------NORMALS FUNCTIONS-------------------- +//----------------------------------Mathutils.QuadNormal() ------------------- +PyObject *M_Mathutils_QuadNormal( PyObject * self, PyObject * args ) +{ + VectorObject *vec1; + VectorObject *vec2; + VectorObject *vec3; + VectorObject *vec4; + float v1[3], v2[3], v3[3], v4[3], e1[3], e2[3], n1[3], n2[3]; + + if( !PyArg_ParseTuple + ( args, "O!O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2 + , &vector_Type, &vec3, &vector_Type, &vec4 ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "expected 4 vector types\n" ) ); + if( vec1->size != vec2->size || vec1->size != vec3->size || vec1->size != vec4->size) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "vectors must be of the same size\n" ) ); + if( vec1->size != 3 ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "only 3D vectors\n" ) ); + + VECCOPY(v1, vec1->vec); + VECCOPY(v2, vec2->vec); + VECCOPY(v3, vec3->vec); + VECCOPY(v4, vec4->vec); + + /* find vectors for two edges sharing v2 */ + VecSubf(e1, v1, v2); + VecSubf(e2, v3, v2); + + Crossf(n1, e2, e1); + Normalize(n1); + + /* find vectors for two edges sharing v4 */ + VecSubf(e1, v3, v4); + VecSubf(e2, v1, v4); + + Crossf(n2, e2, e1); + Normalize(n2); + + /* adding and averaging the normals of both triangles */ + VecAddf(n1, n2, n1); + Normalize(n1); + + return newVectorObject(n1, 3, Py_NEW); +} + +//----------------------------Mathutils.TriangleNormal() ------------------- +PyObject *M_Mathutils_TriangleNormal( PyObject * self, PyObject * args ) +{ + VectorObject *vec1, *vec2, *vec3; + float v1[3], v2[3], v3[3], e1[3], e2[3], n[3]; + + if( !PyArg_ParseTuple + ( args, "O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2 + , &vector_Type, &vec3 ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "expected 3 vector types\n" ) ); + if( vec1->size != vec2->size || vec1->size != vec3->size ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "vectors must be of the same size\n" ) ); + if( vec1->size != 3 ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "only 3D vectors\n" ) ); + + VECCOPY(v1, vec1->vec); + VECCOPY(v2, vec2->vec); + VECCOPY(v3, vec3->vec); + + /* find vectors for two edges sharing v2 */ + VecSubf(e1, v1, v2); + VecSubf(e2, v3, v2); + + Crossf(n, e2, e1); + Normalize(n); + + return newVectorObject(n, 3, Py_NEW); +} + +//--------------------------------- AREA FUNCTIONS-------------------- +//----------------------------------Mathutils.TriangleArea() ------------------- +PyObject *M_Mathutils_TriangleArea( PyObject * self, PyObject * args ) +{ + VectorObject *vec1, *vec2, *vec3; + float v1[3], v2[3], v3[3]; + + if( !PyArg_ParseTuple + ( args, "O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2 + , &vector_Type, &vec3 ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "expected 3 vector types\n" ) ); + if( vec1->size != vec2->size || vec1->size != vec3->size ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "vectors must be of the same size\n" ) ); + + if (vec1->size == 3) { + VECCOPY(v1, vec1->vec); + VECCOPY(v2, vec2->vec); + VECCOPY(v3, vec3->vec); + + return PyFloat_FromDouble( AreaT3Dfl(v1, v2, v3) ); + } + else if (vec1->size == 2) { + v1[0] = vec1->vec[0]; + v1[1] = vec1->vec[1]; + + v2[0] = vec2->vec[0]; + v2[1] = vec2->vec[1]; + + v3[0] = vec3->vec[0]; + v3[1] = vec3->vec[1]; + + return PyFloat_FromDouble( AreaF2Dfl(v1, v2, v3) ); + } + else { + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "only 2D,3D vectors are supported\n" ) ); + } +} +//#############################DEPRECATED################################ +//####################################################################### +//----------------------------------Mathutils.CopyMat() ----------------- +//copies a matrix into a new matrix +PyObject *M_Mathutils_CopyMat(PyObject * self, PyObject * args) +{ + PyObject *matrix = NULL; + static char warning = 1; + + if( warning ) { + printf("Mathutils.CopyMat(): deprecated :use Mathutils.Matrix() to copy matrices\n"); + --warning; + } + + matrix = M_Mathutils_Matrix(self, args); + if(matrix == NULL) + return NULL; //error string already set if we get here + else + return matrix; +} +//----------------------------------Mathutils.CopyVec() ----------------- +//makes a new vector that is a copy of the input +PyObject *M_Mathutils_CopyVec(PyObject * self, PyObject * args) +{ + PyObject *vec = NULL; + static char warning = 1; + + if( warning ) { + printf("Mathutils.CopyVec(): Deprecated: use Mathutils.Vector() to copy vectors\n"); + --warning; + } + + vec = M_Mathutils_Vector(self, args); + if(vec == NULL) + return NULL; //error string already set if we get here + else + return vec; +} +//----------------------------------Mathutils.CopyQuat() -------------- +//Copies a quaternion to a new quat +PyObject *M_Mathutils_CopyQuat(PyObject * self, PyObject * args) +{ + PyObject *quat = NULL; + static char warning = 1; + + if( warning ) { + printf("Mathutils.CopyQuat(): Deprecated: use Mathutils.Quaternion() to copy vectors\n"); + --warning; + } + + quat = M_Mathutils_Quaternion(self, args); + if(quat == NULL) + return NULL; //error string already set if we get here + else + return quat; +} +//----------------------------------Mathutils.CopyEuler() --------------- +//copies a euler to a new euler +PyObject *M_Mathutils_CopyEuler(PyObject * self, PyObject * args) +{ + PyObject *eul = NULL; + static char warning = 1; + + if( warning ) { + printf("Mathutils.CopyEuler(): deprecated:use Mathutils.Euler() to copy vectors\n"); + --warning; + } + + eul = M_Mathutils_Euler(self, args); + if(eul == NULL) + return NULL; //error string already set if we get here + else + return eul; +} +//----------------------------------Mathutils.RotateEuler() ------------ +//rotates a euler a certain amount and returns the result +//should return a unique euler rotation (i.e. no 720 degree pitches :) +PyObject *M_Mathutils_RotateEuler(PyObject * self, PyObject * args) +{ + EulerObject *Eul = NULL; + float angle; + char *axis; + static char warning = 1; + + if( warning ) { + printf("Mathutils.RotateEuler(): Deprecated:use Euler.rotate() to rotate a euler\n"); + --warning; + } + + if(!PyArg_ParseTuple(args, "O!fs", &euler_Type, &Eul, &angle, &axis)) + return EXPP_ReturnPyObjError(PyExc_TypeError, + "Mathutils.RotateEuler(): expected euler type & float & string"); + + Euler_Rotate(Eul, Py_BuildValue("fs", angle, axis)); + Py_RETURN_NONE; +} +//----------------------------------Mathutils.MatMultVec() -------------- +//COLUMN VECTOR Multiplication (Matrix X Vector) +PyObject *M_Mathutils_MatMultVec(PyObject * self, PyObject * args) +{ + MatrixObject *mat = NULL; + VectorObject *vec = NULL; + static char warning = 1; + + if( warning ) { + printf("Mathutils.MatMultVec(): Deprecated: use matrix * vec to perform column vector multiplication\n"); + --warning; + } + + //get pyObjects + if(!PyArg_ParseTuple(args, "O!O!", &matrix_Type, &mat, &vector_Type, &vec)) + return EXPP_ReturnPyObjError(PyExc_TypeError, + "Mathutils.MatMultVec(): MatMultVec() expects a matrix and a vector object - in that order\n"); + + return column_vector_multiplication(mat, vec); +} +//----------------------------------Mathutils.VecMultMat() --------------- +//ROW VECTOR Multiplication - Vector X Matrix +PyObject *M_Mathutils_VecMultMat(PyObject * self, PyObject * args) +{ + MatrixObject *mat = NULL; + VectorObject *vec = NULL; + static char warning = 1; + + if( warning ) { + printf("Mathutils.VecMultMat(): Deprecated: use vec * matrix to perform row vector multiplication\n"); + --warning; + } + + //get pyObjects + if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec, &matrix_Type, &mat)) + return EXPP_ReturnPyObjError(PyExc_TypeError, + "Mathutils.VecMultMat(): VecMultMat() expects a vector and matrix object - in that order\n"); + + return row_vector_multiplication(vec, mat); +} +//####################################################################### +//#############################DEPRECATED################################ diff --git a/source/blender/python/api2_2x/Mathutils.h b/source/blender/python/api2_2x/Mathutils.h new file mode 100644 index 00000000000..901cb2139d7 --- /dev/null +++ b/source/blender/python/api2_2x/Mathutils.h @@ -0,0 +1,85 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ +//Include this file for access to vector, quat, matrix, euler, etc... + +#ifndef EXPP_Mathutils_H +#define EXPP_Mathutils_H + +#include +#include "vector.h" +#include "matrix.h" +#include "quat.h" +#include "euler.h" +#include "point.h" + +PyObject *Mathutils_Init( void ); +PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat); +PyObject *column_vector_multiplication(MatrixObject * mat, VectorObject* vec); +PyObject *row_point_multiplication(PointObject* pt, MatrixObject * mat); +PyObject *column_point_multiplication(MatrixObject * mat, PointObject* pt); +PyObject *quat_rotation(PyObject *arg1, PyObject *arg2); + +PyObject *M_Mathutils_Rand(PyObject * self, PyObject * args); +PyObject *M_Mathutils_Vector(PyObject * self, PyObject * args); +PyObject *M_Mathutils_CrossVecs(PyObject * self, PyObject * args); +PyObject *M_Mathutils_DotVecs(PyObject * self, PyObject * args); +PyObject *M_Mathutils_AngleBetweenVecs(PyObject * self, PyObject * args); +PyObject *M_Mathutils_MidpointVecs(PyObject * self, PyObject * args); +PyObject *M_Mathutils_ProjectVecs(PyObject * self, PyObject * args); +PyObject *M_Mathutils_Matrix(PyObject * self, PyObject * args); +PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args); +PyObject *M_Mathutils_TranslationMatrix(PyObject * self, VectorObject * value); +PyObject *M_Mathutils_ScaleMatrix(PyObject * self, PyObject * args); +PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * args); +PyObject *M_Mathutils_ShearMatrix(PyObject * self, PyObject * args); +PyObject *M_Mathutils_Quaternion(PyObject * self, PyObject * args); +PyObject *M_Mathutils_CrossQuats(PyObject * self, PyObject * args); +PyObject *M_Mathutils_DotQuats(PyObject * self, PyObject * args); +PyObject *M_Mathutils_DifferenceQuats(PyObject * self, PyObject * args); +PyObject *M_Mathutils_Slerp(PyObject * self, PyObject * args); +PyObject *M_Mathutils_Euler(PyObject * self, PyObject * args); +PyObject *M_Mathutils_Intersect( PyObject * self, PyObject * args ); +PyObject *M_Mathutils_TriangleArea( PyObject * self, PyObject * args ); +PyObject *M_Mathutils_TriangleNormal( PyObject * self, PyObject * args ); +PyObject *M_Mathutils_QuadNormal( PyObject * self, PyObject * args ); +PyObject *M_Mathutils_LineIntersect( PyObject * self, PyObject * args ); +PyObject *M_Mathutils_Point(PyObject * self, PyObject * args); +//DEPRECATED +PyObject *M_Mathutils_CopyMat(PyObject * self, PyObject * args); +PyObject *M_Mathutils_CopyVec(PyObject * self, PyObject * args); +PyObject *M_Mathutils_CopyQuat(PyObject * self, PyObject * args); +PyObject *M_Mathutils_CopyEuler(PyObject * self, PyObject * args); +PyObject *M_Mathutils_RotateEuler(PyObject * self, PyObject * args); +PyObject *M_Mathutils_MatMultVec(PyObject * self, PyObject * args); +PyObject *M_Mathutils_VecMultMat(PyObject * self, PyObject * args); + +#endif /* EXPP_Mathutils_H */ diff --git a/source/blender/python/api2_2x/Mesh.c b/source/blender/python/api2_2x/Mesh.c new file mode 100644 index 00000000000..494a1250728 --- /dev/null +++ b/source/blender/python/api2_2x/Mesh.c @@ -0,0 +1,8648 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender, partially based on NMesh.c API. + * + * Contributor(s): Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "Mesh.h" /*This must come first*/ + +#include "MEM_guardedalloc.h" + +#include "DNA_key_types.h" +#include "DNA_armature_types.h" +#include "DNA_scene_types.h" +#include "DNA_oops_types.h" +#include "DNA_space_types.h" +#include "DNA_curve_types.h" +#include "DNA_meta_types.h" +#include "DNA_modifier_types.h" + +#include "BDR_editface.h" /* make_tfaces */ +#include "BDR_vpaint.h" +#include "BDR_editobject.h" + +#include "BIF_editdeform.h" +#include "BIF_editkey.h" /* insert_meshkey */ +#include "BIF_space.h" /* REMAKEIPO - insert_meshkey */ +#include "BIF_editview.h" +#include "BIF_editmesh.h" +#include "BIF_meshtools.h" + +#include "BKE_customdata.h" +#include "BKE_deform.h" +#include "BKE_displist.h" +#include "BKE_mesh.h" +#include "BKE_material.h" +#include "BKE_main.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_DerivedMesh.h" +#include "BKE_object.h" +#include "BKE_mball.h" +#include "BKE_utildefines.h" +#include "BKE_depsgraph.h" +#include "BSE_edit.h" /* for countall(); */ +#include "BKE_curve.h" /* for copy_curve(); */ +#include "BKE_modifier.h" /* for modifier_new(), modifier_copyData(); */ +#include "BKE_idprop.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" + +#include "blendef.h" +#include "mydevice.h" +#include "butspace.h" /* for mesh tools */ +#include "Object.h" +#include "Key.h" +#include "Image.h" +#include "Material.h" +#include "Mathutils.h" +#include "IDProp.h" +#include "meshPrimitive.h" +#include "constant.h" +#include "gen_utils.h" +#include "gen_library.h" +#include "multires.h" + +/* EXPP Mesh defines */ + +#define MESH_SMOOTHRESH 30 +#define MESH_SMOOTHRESH_MIN 1 +#define MESH_SMOOTHRESH_MAX 80 +#define MESH_SUBDIV 1 +#define MESH_SUBDIV_MIN 0 +#define MESH_SUBDIV_MAX 6 + +#define MESH_HASFACEUV 0 +#define MESH_HASMCOL 1 +#define MESH_HASVERTUV 2 +#define MESH_HASMULTIRES 3 + +#define MESH_MULTIRES_LEVEL 0 +#define MESH_MULTIRES_EDGE 1 +#define MESH_MULTIRES_PIN 2 +#define MESH_MULTIRES_RENDER 3 + +#define MESH_TOOL_TOSPHERE 0 +#define MESH_TOOL_VERTEXSMOOTH 1 +#define MESH_TOOL_FLIPNORM 2 +#define MESH_TOOL_SUBDIV 3 +#define MESH_TOOL_REMDOUB 4 +#define MESH_TOOL_FILL 5 +#define MESH_TOOL_RECALCNORM 6 +#define MESH_TOOL_TRI2QUAD 7 +#define MESH_TOOL_QUAD2TRI 8 + +static PyObject *MVertSeq_CreatePyObject( Mesh * mesh ); +static PyObject *MFaceSeq_CreatePyObject( Mesh * mesh ); +static PyObject *MEdgeSeq_CreatePyObject( Mesh * mesh ); +static PyObject *MFace_CreatePyObject( Mesh * mesh, int i ); +static PyObject *MEdge_CreatePyObject( Mesh * mesh, int i ); + +#define MFACE_VERT_BADRANGE_CHECK(me, face) ((int)face->v1 >= me->totvert || (int)face->v2 >= me->totvert || (int)face->v3 >= me->totvert || (int)face->v4 >= me->totvert) +#define MEDGE_VERT_BADRANGE_CHECK(me, edge) ((int)edge->v1 >= me->totvert || (int)edge->v2 >= me->totvert) + +/************************************************************************ + * + * internal utilities + * + ************************************************************************/ + +/* + * internal structures used for sorting edges and faces + */ + +typedef struct SrchEdges { + unsigned int v[2]; /* indices for verts */ + unsigned char swap; /* non-zero if verts swapped */ + unsigned int index; /* index in original param list of this edge */ + /* (will be used by findEdges) */ +} SrchEdges; + +typedef struct SrchFaces { + unsigned int v[4]; /* indices for verts */ + unsigned int index; /* index in original param list of this edge */ + unsigned char order; /* order of original verts, bitpacked */ +} SrchFaces; + +typedef struct FaceEdges { + unsigned int v[2]; /* search key (vert indices) */ + unsigned int index; /* location in edge list */ + unsigned char sel; /* selection state */ +} FaceEdges; + +/* + * compare edges by vertex indices + */ + +int medge_comp( const void *va, const void *vb ) +{ + const unsigned int *a = ((SrchEdges *)va)->v; + const unsigned int *b = ((SrchEdges *)vb)->v; + + /* compare first index for differences */ + + if (a[0] < b[0]) return -1; + else if (a[0] > b[0]) return 1; + + /* if first indices equal, compare second index for differences */ + + else if (a[1] < b[1]) return -1; + else return (a[1] > b[1]); +} + +/* + * compare edges by insert list indices + */ + +int medge_index_comp( const void *va, const void *vb ) +{ + const SrchEdges *a = (SrchEdges *)va; + const SrchEdges *b = (SrchEdges *)vb; + + /* compare list indices for differences */ + + if (a->index < b->index) return -1; + else return (a->index > b->index); +} + + +/* + * compare faces by vertex indices + */ + +int mface_comp( const void *va, const void *vb ) +{ + const SrchFaces *a = va; + const SrchFaces *b = vb; + int i; + + /* compare indices, first to last, for differences */ + for( i = 0; i < 4; ++i ) { + if( a->v[i] < b->v[i] ) + return -1; + if( a->v[i] > b->v[i] ) + return 1; + } + + /* + * don't think this needs be done; if order is different then either + * (a) the face is good, just reversed or has a different starting + * vertex, or (b) face is bad (for 4 verts) and there's a "twist" + */ + +#if 0 + /* if all the same verts, compare their order */ + if( a->order < b->order ) + return -1; + if( a->order > b->order ) + return 1; +#endif + + return 0; +} + +/* + * compare faces by insert list indices + */ + +int mface_index_comp( const void *va, const void *vb ) +{ + const SrchFaces *a = va; + const SrchFaces *b = vb; + + /* compare indices, first to last, for differences */ + if( a->index < b->index ) + return -1; + if( a->index > b->index ) + return 1; + return 0; +} + +/* + * compare edges by vertex indices + */ + +int faceedge_comp( const void *va, const void *vb ) +{ + const unsigned int *a = ((FaceEdges *)va)->v; + const unsigned int *b = ((FaceEdges *)vb)->v; + + /* compare first index for differences */ + + if (a[0] < b[0]) return -1; + else if (a[0] > b[0]) return 1; + + /* if first indices equal, compare second index for differences */ + + else if (a[1] < b[1]) return -1; + else return (a[1] > b[1]); +} + +/* + * update the DAG for all objects linked to this mesh + */ + +static void mesh_update( Mesh * mesh ) +{ + Object_updateDag( (void *) mesh ); +} + +/* + * delete vertices from mesh, then delete edges/keys/faces which used those + * vertices + * + * Deletion is done by "smart compaction"; groups of verts/edges/faces which + * remain in the list are copied to new list instead of one at a time. Since + * Blender has no realloc we would have to copy things anyway, so there's no + * point trying to fill empty entries with data from the end of the lists. + * + * vert_table is a lookup table for mapping old verts to new verts (after the + * vextex list has deleted vertices removed). Each entry contains the + * vertex's new index. + */ + +static void delete_verts( Mesh *mesh, unsigned int *vert_table, int to_delete ) +{ + /* + * (1) allocate vertex table (initialize contents to 0) + * (2) mark each vertex being deleted in vertex table (= UINT_MAX) + * (3) update remaining table entries with "new" vertex index (after + * compaction) + * (4) allocate new vertex list + * (5) do "smart copy" of vertices from old to new + * * each moved vertex is entered into vertex table: if vertex i is + * moving to index j in new list + * vert_table[i] = j; + * (6) if keys, do "smart copy" of keys + * (7) process edge list + * update vert index + * delete edges which delete verts + * (7) allocate new edge list + * (8) do "smart copy" of edges + * (9) allocate new face list + * (10) do "smart copy" of face + */ + + unsigned int *tmpvert; + CustomData vdata; + int i, count, state, dstindex, totvert; + + totvert = mesh->totvert - to_delete; + CustomData_copy( &mesh->vdata, &vdata, CD_MASK_MESH, CD_CALLOC, totvert ); + + /* + * do "smart compaction" of the table; find and copy groups of vertices + * which are not being deleted + */ + + dstindex = 0; + tmpvert = vert_table; + count = 0; + state = 1; + for( i = 0; i < mesh->totvert; ++i, ++tmpvert ) { + switch( state ) { + case 0: /* skipping verts */ + if( *tmpvert == UINT_MAX ) { + ++count; + } else { + count = 1; + state = 1; + } + break; + case 1: /* gathering verts */ + if( *tmpvert != UINT_MAX ) { + ++count; + } else { + if( count ) { + CustomData_copy_data( &mesh->vdata, &vdata, i-count, + dstindex, count ); + dstindex += count; + } + count = 1; + state = 0; + } + } + } + + /* if we were gathering verts at the end of the loop, copy those */ + if( state && count ) + CustomData_copy_data( &mesh->vdata, &vdata, i-count, dstindex, count ); + + /* delete old vertex list, install the new one, update vertex count */ + CustomData_free( &mesh->vdata, mesh->totvert ); + mesh->vdata = vdata; + mesh->totvert = totvert; + mesh_update_customdata_pointers( mesh ); +} + +static void delete_edges( Mesh *mesh, unsigned int *vert_table, int to_delete ) +{ + int i; + MEdge *tmpedge; + + /* if not given, then mark and count edges to be deleted */ + if( !to_delete ) { + tmpedge = mesh->medge; + for( i = mesh->totedge; i-- ; ++tmpedge ) + if( vert_table[tmpedge->v1] == UINT_MAX || + vert_table[tmpedge->v2] == UINT_MAX ) { + tmpedge->v1 = UINT_MAX; + ++to_delete; + } + } + + /* if there are edges to delete, handle it */ + if( to_delete ) { + CustomData edata; + int count, state, dstindex, totedge; + + /* allocate new edge list and populate */ + totedge = mesh->totedge - to_delete; + CustomData_copy( &mesh->edata, &edata, CD_MASK_MESH, CD_CALLOC, totedge); + + /* + * do "smart compaction" of the edges; find and copy groups of edges + * which are not being deleted + */ + + dstindex = 0; + tmpedge = mesh->medge; + count = 0; + state = 1; + for( i = 0; i < mesh->totedge; ++i, ++tmpedge ) { + switch( state ) { + case 0: /* skipping edges */ + if( tmpedge->v1 == UINT_MAX ) { + ++count; + } else { + count = 1; + state = 1; + } + break; + case 1: /* gathering edges */ + if( tmpedge->v1 != UINT_MAX ) { + ++count; + } else { + if( count ) { + CustomData_copy_data( &mesh->edata, &edata, i-count, + dstindex, count ); + dstindex += count; + } + count = 1; + state = 0; + } + } + /* if edge is good, update vertex indices */ + } + + /* copy any pending good edges */ + if( state && count ) + CustomData_copy_data( &mesh->edata, &edata, i-count, dstindex, + count ); + + /* delete old edge list, install the new one, update vertex count */ + CustomData_free( &mesh->edata, mesh->totedge ); + mesh->edata = edata; + mesh->totedge = totedge; + mesh_update_customdata_pointers( mesh ); + } + + /* if vertices were deleted, update edge's vertices */ + if( vert_table ) { + tmpedge = mesh->medge; + for( i = mesh->totedge; i--; ++tmpedge ) { + tmpedge->v1 = vert_table[tmpedge->v1]; + tmpedge->v2 = vert_table[tmpedge->v2]; + } + } +} + +/* +* Since all faces must have 3 or 4 verts, we can't have v3 or v4 be zero. +* If that happens during the deletion, we have to shuffle the vertices +* around; otherwise it can cause an Eeekadoodle or worse. If there are +* texture faces as well, they have to be shuffled as well. +* +* (code borrowed from test_index_face() in mesh.c, but since we know the +* faces already have correct number of vertices, this is a little faster) +*/ + +static void eeek_fix( MFace *mface, int len4 ) +{ + /* if 4 verts, then neither v3 nor v4 can be zero */ + if( len4 ) { + if( !mface->v3 || !mface->v4 ) { + SWAP( int, mface->v1, mface->v3 ); + SWAP( int, mface->v2, mface->v4 ); + } + } else if( !mface->v3 ) { + /* if 2 verts, then just v3 cannot be zero (v4 MUST be zero) */ + SWAP( int, mface->v1, mface->v2 ); + SWAP( int, mface->v2, mface->v3 ); + } +} + +static void delete_faces( Mesh *mesh, unsigned int *vert_table, int to_delete ) +{ + int i; + MFace *tmpface; + + /* if there are faces to delete, handle it */ + if( to_delete ) { + CustomData fdata; + int count, state, dstindex, totface; + + totface = mesh->totface - to_delete; + CustomData_copy( &mesh->fdata, &fdata, CD_MASK_MESH, CD_CALLOC, totface ); + + /* + * do "smart compaction" of the faces; find and copy groups of faces + * which are not being deleted + */ + + dstindex = 0; + tmpface = mesh->mface; + + count = 0; + state = 1; + for( i = 0; i < mesh->totface; ++i ) { + switch( state ) { + case 0: /* skipping faces */ + if( tmpface->v1 == UINT_MAX ) { + ++count; + } else { + count = 1; + state = 1; + } + break; + case 1: /* gathering faces */ + if( tmpface->v1 != UINT_MAX ) { + ++count; + } else { + if( count ) { + CustomData_copy_data( &mesh->fdata, &fdata, i-count, + dstindex, count ); + dstindex += count; + } + count = 1; + state = 0; + } + } + ++tmpface; + } + + /* if we were gathering faces at the end of the loop, copy those */ + if ( state && count ) + CustomData_copy_data( &mesh->fdata, &fdata, i-count, dstindex, + count ); + + /* delete old face list, install the new one, update face count */ + + CustomData_free( &mesh->fdata, mesh->totface ); + mesh->fdata = fdata; + mesh->totface = totface; + mesh_update_customdata_pointers( mesh ); + } + + /* if vertices were deleted, update face's vertices */ + if( vert_table ) { + tmpface = mesh->mface; + + for( i = 0; itotface; ++i, ++tmpface ) { + int len4 = tmpface->v4; + tmpface->v1 = vert_table[tmpface->v1]; + tmpface->v2 = vert_table[tmpface->v2]; + tmpface->v3 = vert_table[tmpface->v3]; + if(len4) + tmpface->v4 = vert_table[tmpface->v4]; + else + tmpface->v4 = 0; + + test_index_face( tmpface, &mesh->fdata, i, len4? 4: 3); + } + } +} + +/* + * fill up vertex lookup table with old-to-new mappings + * + * returns the number of vertices marked for deletion + */ + +static unsigned int make_vertex_table( unsigned int *vert_table, int count ) +{ + int i; + unsigned int *tmpvert = vert_table; + unsigned int to_delete = 0; + unsigned int new_index = 0; + + /* fill the lookup table with old->new index mappings */ + for( i = count; i; --i, ++tmpvert ) { + if( *tmpvert == UINT_MAX ) { + ++to_delete; + } else { + *tmpvert = new_index; + ++new_index; + } + } + return to_delete; +} + + +/************************************************************************ + * + * Color attributes + * + ************************************************************************/ + +/* + * get a color attribute + */ + +static PyObject *MCol_getAttr( BPy_MCol * self, void *type ) +{ + unsigned char param; + + switch( (long)type ) { + case 'R': /* these are backwards, but that how it works */ + param = self->color->b; + break; + case 'G': + param = self->color->g; + break; + case 'B': /* these are backwards, but that how it works */ + param = self->color->r; + break; + case 'A': + param = self->color->a; + break; + default: + { + char errstr[1024]; + sprintf( errstr, "undefined type '%d' in MCol_getAttr", + (int)((long)type & 0xff)); + return EXPP_ReturnPyObjError( PyExc_RuntimeError, errstr ); + } + } + + return PyInt_FromLong( param ); +} + +/* + * set a color attribute + */ + +static int MCol_setAttr( BPy_MCol * self, PyObject * value, void * type ) +{ + unsigned char *param; + + switch( (long)type ) { + case 'R': /* these are backwards, but that how it works */ + param = (unsigned char *)&self->color->b; + break; + case 'G': + param = (unsigned char *)&self->color->g; + break; + case 'B': /* these are backwards, but that how it works */ + param = (unsigned char *)&self->color->r; + break; + case 'A': + param = (unsigned char *)&self->color->a; + break; + default: + { + char errstr[1024]; + sprintf( errstr, "undefined type '%d' in MCol_setAttr", + (int)((long)type & 0xff)); + return EXPP_ReturnIntError( PyExc_RuntimeError, errstr ); + } + } + + return EXPP_setIValueClamped( value, param, 0, 255, 'b' ); +} + +/************************************************************************ + * + * Python MCol_Type attributes get/set structure + * + ************************************************************************/ + +static PyGetSetDef BPy_MCol_getseters[] = { + {"r", + (getter)MCol_getAttr, (setter)MCol_setAttr, + "red component", + (void *)'R'}, + {"g", + (getter)MCol_getAttr, (setter)MCol_setAttr, + "green component", + (void *)'G'}, + {"b", + (getter)MCol_getAttr, (setter)MCol_setAttr, + "blue component", + (void *)'B'}, + {"a", + (getter)MCol_getAttr, (setter)MCol_setAttr, + "alpha component", + (void *)'A'}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + + +/*----------------------------object[]--------------------------- + sequence accessor (get)*/ +static PyObject *MCol_item(BPy_MCol * self, int i) +{ + unsigned char param; + switch (i) { + case 0: + param = self->color->b; + break; + case 1: + param = self->color->g; + break; + case 2: + param = self->color->r; + break; + case 3: + param = self->color->a; + break; + default: + return EXPP_ReturnPyObjError(PyExc_IndexError, + "vector[index] = x: assignment index out of range\n"); + } + + return PyInt_FromLong( param ); +} + +/*----------------------------object[]------------------------- + sequence accessor (set)*/ +static int MCol_ass_item(BPy_MCol * self, int i, PyObject * value) +{ + unsigned char *param; + + switch (i) { + case 0: + param = (unsigned char *)&self->color->b; /* reversed? why */ + break; + case 1: + param = (unsigned char *)&self->color->g; + break; + case 2: + param = (unsigned char *)&self->color->r; /* reversed? why */ + break; + case 3: + param = (unsigned char *)&self->color->a; + break; + default: + { + return EXPP_ReturnIntError( PyExc_RuntimeError, "Index out of range" ); + } + } + return EXPP_setIValueClamped( value, param, 0, 255, 'b' ); +} + +/************************************************************************ + * + * Python MCol_Type methods + * + ************************************************************************/ + +static PyObject *MCol_repr( BPy_MCol * self ) +{ + return PyString_FromFormat( "[MCol %d %d %d %d]", + (int)self->color->b, (int)self->color->g, + (int)self->color->r, (int)self->color->a ); +} + +/*-----------------PROTCOL DECLARATIONS--------------------------*/ +static PySequenceMethods MCol_SeqMethods = { + (inquiry) NULL, /* sq_length */ + (binaryfunc) NULL, /* sq_concat */ + (intargfunc) NULL, /* sq_repeat */ + (intargfunc) MCol_item, /* sq_item */ + (intintargfunc) NULL, /* sq_slice */ + (intobjargproc) MCol_ass_item, /* sq_ass_item */ + (intintobjargproc) NULL, /* sq_ass_slice */ +}; + +/************************************************************************ + * + * Python MCol_Type structure definition + * + ************************************************************************/ + +PyTypeObject MCol_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender MCol", /* char *tp_name; */ + sizeof( BPy_MCol ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + ( reprfunc ) MCol_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + &MCol_SeqMethods, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + NULL, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_MCol_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +static PyObject *MCol_CreatePyObject( MCol * color ) +{ + BPy_MCol *obj = PyObject_NEW( BPy_MCol, &MCol_Type ); + + if( !obj ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyObject_New() failed" ); + + obj->color = color; + return (PyObject *)obj; +} + +/************************************************************************ + * + * BPy_MVert attributes + * + ************************************************************************/ + +static MVert * MVert_get_pointer( BPy_MVert * self ) +{ + if( BPy_MVert_Check( self ) ) { + if( self->index >= ((Mesh *)self->data)->totvert ) + return (MVert *)EXPP_ReturnPyObjError( PyExc_RuntimeError, + "MVert is no longer valid" ); + return &((Mesh *)self->data)->mvert[self->index]; + } + else + return (MVert *)self->data; +} + +/* + * get a vertex's coordinate + */ + +static PyObject *MVert_getCoord( BPy_MVert * self ) +{ + MVert *v; + + v = MVert_get_pointer( self ); + if( !v ) + return NULL; + + return newVectorObject( v->co, 3, Py_WRAP ); +} + +/* + * set a vertex's coordinate + */ + +static int MVert_setCoord( BPy_MVert * self, VectorObject * value ) +{ + int i; + MVert *v; + + v = MVert_get_pointer( self ); + if( !v ) + return -1; + + if( !VectorObject_Check( value ) || value->size != 3 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected vector argument of size 3" ); + + for( i=0; i<3 ; ++i) + v->co[i] = value->vec[i]; + + return 0; +} + +/* + * get a vertex's index + */ + +static PyObject *MVert_getIndex( BPy_MVert * self ) +{ + if( self->index >= ((Mesh *)self->data)->totvert ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "MVert is no longer valid" ); + + return PyInt_FromLong( self->index ); +} + + +/* + * get a verts's hidden state + */ + +static PyObject *MVert_getMFlagBits( BPy_MVert * self, void * type ) +{ + MVert *v; + + v = MVert_get_pointer( self ); + if (!v) + return NULL; /* error is set */ + + return EXPP_getBitfield( &v->flag, (int)((long)type & 0xff), 'b' ); +} + + +/* + * set a verts's hidden state + */ + +static int MVert_setMFlagBits( BPy_MVert * self, PyObject * value, + void * type ) +{ + MVert *v; + + v = MVert_get_pointer( self ); + + if (!v) + return -1; /* error is set */ + + return EXPP_setBitfield( value, &v->flag, + (int)((long)type & 0xff), 'b' ); +} + + +/* + * get a vertex's normal + */ + +static PyObject *MVert_getNormal( BPy_MVert * self ) +{ + float no[3]; + int i; + MVert *v; + + v = MVert_get_pointer( self ); + if( !v ) + return NULL; /* error set */ + + for( i = 0; i < 3; ++i ) + no[i] = (float)(v->no[i] / 32767.0); + return newVectorObject( no, 3, Py_NEW ); +} + +/* + * set a vertex's normal + */ + +static int MVert_setNormal( BPy_MVert * self, VectorObject * value ) +{ + int i; + MVert *v; + float normal[3]; + + v = MVert_get_pointer( self ); + if( !v ) + return -1; /* error set */ + + if( !VectorObject_Check( value ) || value->size != 3 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected vector argument of size 3" ); + + + for( i=0; i<3 ; ++i) + normal[i] = value->vec[i]; + + Normalize(normal); + + for( i=0; i<3 ; ++i) + v->no[i] = (short)(normal[i]*32767.0); + + return 0; +} + + +/* + * get a vertex's select status + */ + +static PyObject *MVert_getSel( BPy_MVert *self ) +{ + MVert *v; + + v = MVert_get_pointer( self ); + if( !v ) + return NULL; /* error is set */ + + return EXPP_getBitfield( &v->flag, SELECT, 'b' ); +} + +/* + * set a vertex's select status + */ + +static int MVert_setSel( BPy_MVert *self, PyObject *value ) +{ + MVert *v = MVert_get_pointer( self ); + Mesh *me = (Mesh *)self->data; + if (!v) + return -1; /* error is set */ + + /* + * if vertex exists and setting status is OK, delete select storage + * of the edges and faces as well + */ + + if( v && !EXPP_setBitfield( value, &v->flag, SELECT, 'b' ) ) { + if( me && me->mselect ) { + MEM_freeN( me->mselect ); + me->mselect = NULL; + } + return 0; + } + return -1; +} + +/* + * get a vertex's UV coordinates + */ + +static PyObject *MVert_getUVco( BPy_MVert *self ) +{ + Mesh *me = (Mesh *)self->data; + + if( !me->msticky ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "mesh has no 'sticky' coordinates" ); + + if( self->index >= ((Mesh *)self->data)->totvert ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "MVert is no longer valid" ); + + return newVectorObject( me->msticky[self->index].co, 2, Py_WRAP ); +} + +/* + * set a vertex's UV coordinates + */ + +static int MVert_setUVco( BPy_MVert *self, PyObject *value ) +{ + float uvco[3] = {0.0, 0.0}; + Mesh *me = (Mesh *)self->data; + struct MSticky *v; + int i; + + /* + * at least for now, don't allow creation of sticky coordinates if they + * don't already exist + */ + + if( !me->msticky ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "mesh has no 'sticky' coordinates" ); + + if( self->index >= ((Mesh *)self->data)->totvert ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "MVert is no longer valid" ); + + if( VectorObject_Check( value ) ) { + VectorObject *vect = (VectorObject *)value; + if( vect->size != 2 ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "expected 2D vector" ); + for( i = 0; i < vect->size; ++i ) + uvco[i] = vect->vec[i]; + } else if( !PyArg_ParseTuple( value, "ff", + &uvco[0], &uvco[1] ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected 2D vector" ); + + v = &me->msticky[self->index]; + + for( i = 0; i < 2; ++i ) + v->co[i] = uvco[i]; + + return 0; +} + +/************************************************************************ + * + * Python MVert_Type attributes get/set structure + * + ************************************************************************/ + +static PyGetSetDef BPy_MVert_getseters[] = { + {"co", + (getter)MVert_getCoord, (setter)MVert_setCoord, + "vertex's coordinate", + NULL}, + {"index", + (getter)MVert_getIndex, (setter)NULL, + "vertex's index", + NULL}, + {"no", + (getter)MVert_getNormal, (setter)MVert_setNormal, + "vertex's normal", + NULL}, + {"sel", + (getter)MVert_getSel, (setter)MVert_setSel, + "vertex's select status", + NULL}, + {"hide", + (getter)MVert_getMFlagBits, (setter)MVert_setMFlagBits, + "vert hidden in edit mode", + (void *)ME_HIDE}, + {"uvco", + (getter)MVert_getUVco, (setter)MVert_setUVco, + "vertex's UV coordinates", + NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +static PyGetSetDef BPy_PVert_getseters[] = { + {"co", + (getter)MVert_getCoord, (setter)MVert_setCoord, + "vertex's coordinate", + NULL}, + {"no", + (getter)MVert_getNormal, (setter)MVert_setNormal, + "vertex's normal", + NULL}, + {"sel", + (getter)MVert_getSel, (setter)MVert_setSel, + "vertex's select status", + NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/************************************************************************ + * + * Python MVert_Type standard operations + * + ************************************************************************/ + +static void MVert_dealloc( BPy_MVert * self ) +{ + if( BPy_PVert_Check( self ) ) /* free memory of thick objects */ + MEM_freeN ( self->data ); + + PyObject_DEL( self ); +} + +static int MVert_compare( BPy_MVert * a, BPy_MVert * b ) +{ + return( a->data == b->data && a->index == b->index ) ? 0 : -1; +} + +static PyObject *MVert_repr( BPy_MVert * self ) +{ + char format[512]; + char index[24]; + MVert *v; + + v = MVert_get_pointer( self ); + if( !v ) + return NULL; + + if( BPy_MVert_Check( self ) ) + sprintf( index, "%d", self->index ); + else + BLI_strncpy( index, "(None)", 24 ); + + sprintf( format, "[MVert (%f %f %f) (%f %f %f) %s]", + v->co[0], v->co[1], v->co[2], (float)(v->no[0] / 32767.0), + (float)(v->no[1] / 32767.0), (float)(v->no[2] / 32767.0), + index ); + + return PyString_FromString( format ); +} + +static long MVert_hash( BPy_MVert *self ) +{ + return (long)self->index; +} + +static PyObject *Mesh_addPropLayer_internal(Mesh *mesh, CustomData *data, int tot, PyObject *args) +{ + char *name=NULL; + int type = -1; + + if( !PyArg_ParseTuple( args, "si", &name, &type) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a string and an int" ); + if (strlen(name)>31) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "error, maximum name length is 31"); + if((type != CD_PROP_FLT) && (type != CD_PROP_INT) && (type != CD_PROP_STR)) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "error, unknown layer type"); + if (name) + CustomData_add_layer_named(data, type, CD_DEFAULT, NULL,tot,name); + + mesh_update_customdata_pointers(mesh); + Py_RETURN_NONE; +} + +static PyObject *Mesh_removePropLayer_internal(Mesh *mesh, CustomData *data, int tot,PyObject *value) +{ + CustomDataLayer *layer; + char *name=PyString_AsString(value); + int i; + + if( !name ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + + if (strlen(name)>31) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "error, maximum name length is 31" ); + + i = CustomData_get_named_layer_index(data, CD_PROP_FLT, name); + if(i == -1) i = CustomData_get_named_layer_index(data, CD_PROP_INT, name); + if(i == -1) i = CustomData_get_named_layer_index(data, CD_PROP_STR, name); + if (i==-1) + return EXPP_ReturnPyObjError(PyExc_ValueError, + "No matching layers to remove" ); + layer = &data->layers[i]; + CustomData_free_layer(data, layer->type, tot, i); + mesh_update_customdata_pointers(mesh); + + Py_RETURN_NONE; +} + +static PyObject *Mesh_renamePropLayer_internal(Mesh *mesh, CustomData *data, PyObject *args) +{ + CustomDataLayer *layer; + int i; + char *name_from, *name_to; + + if( !PyArg_ParseTuple( args, "ss", &name_from, &name_to ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected 2 strings" ); + + if (strlen(name_from)>31 || strlen(name_to)>31) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "error, maximum name length is 31" ); + + i = CustomData_get_named_layer_index(data, CD_PROP_FLT, name_from); + if(i == -1) i = CustomData_get_named_layer_index(data, CD_PROP_INT, name_from); + if(i == -1) i = CustomData_get_named_layer_index(data, CD_PROP_STR, name_from); + if(i == -1) + return EXPP_ReturnPyObjError(PyExc_ValueError, + "No matching layers to rename" ); + + layer = &data->layers[i]; + + strcpy(layer->name, name_to); /* we alredy know the string sizes are under 32 */ + CustomData_set_layer_unique_name(data, i); + Py_RETURN_NONE; +} + +static PyObject *Mesh_propList_internal(CustomData *data) +{ + CustomDataLayer *layer; + PyObject *list = PyList_New( 0 ), *item; + int i; + for(i=0; itotlayer; i++) { + layer = &data->layers[i]; + if( (layer->type == CD_PROP_FLT) || (layer->type == CD_PROP_INT) || (layer->type == CD_PROP_STR)) { + item = PyString_FromString(layer->name); + PyList_Append( list, item ); + Py_DECREF(item); + } + } + return list; +} + +static PyObject *Mesh_getProperty_internal(CustomData *data, int eindex, PyObject *value) +{ + CustomDataLayer *layer; + char *name=PyString_AsString(value); + int i; + MFloatProperty *pf; + MIntProperty *pi; + MStringProperty *ps; + + if(!name) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected an string argument" ); + + if (strlen(name)>31) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "error, maximum name length is 31" ); + + i = CustomData_get_named_layer_index(data, CD_PROP_FLT, name); + if(i == -1) i = CustomData_get_named_layer_index(data, CD_PROP_INT, name); + if(i == -1) i = CustomData_get_named_layer_index(data, CD_PROP_STR, name); + if(i == -1) + return EXPP_ReturnPyObjError(PyExc_ValueError, + "No matching layers" ); + + layer = &data->layers[i]; + + if(layer->type == CD_PROP_FLT){ + pf = layer->data; + return PyFloat_FromDouble(pf[eindex].f); + } + else if(layer->type == CD_PROP_INT){ + pi = layer->data; + return PyInt_FromLong(pi[eindex].i); + + } + else if(layer->type == CD_PROP_STR){ + ps = layer->data; + return PyString_FromString(ps[eindex].s); + } + Py_RETURN_NONE; +} + +static PyObject *Mesh_setProperty_internal(CustomData *data, int eindex, PyObject *args) +{ + CustomDataLayer *layer; + int i = 0, index, type = -1; + float f = 0.0f; + char *s=NULL, *name=NULL; + MFloatProperty *pf; + MIntProperty *pi; + MStringProperty *ps; + PyObject *val; + + if(PyArg_ParseTuple(args, "sO", &name, &val)){ + if (strlen(name)>31) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "error, maximum name length is 31" ); + + if(PyInt_Check(val)){ + type = CD_PROP_INT; + i = (int)PyInt_AS_LONG(val); + } + else if(PyFloat_Check(val)){ + type = CD_PROP_FLT; + f = (float)PyFloat_AsDouble(val); + } + else if(PyString_Check(val)){ + type = CD_PROP_STR; + s = PyString_AsString(val); + } + else + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected an name plus either float/int/string" ); + + } + + index = CustomData_get_named_layer_index(data, type, name); + if(index == -1) + return EXPP_ReturnPyObjError(PyExc_ValueError, + "No matching layers or type mismatch" ); + + layer = &data->layers[index]; + + if(type==CD_PROP_STR){ + if (strlen(s)>255){ + return EXPP_ReturnPyObjError( PyExc_ValueError, + "error, maximum string length is 255"); + } + else{ + ps = layer->data; + strcpy(ps[eindex].s,s); + } + } + else if(type==CD_PROP_FLT){ + pf = layer->data; + pf[eindex].f = f; + } + else{ + pi = layer->data; + pi[eindex].i = i; + } + Py_RETURN_NONE; +} + +static PyObject *MVert_getProp( BPy_MVert *self, PyObject *args) +{ + if( BPy_MVert_Check( self ) ){ + Mesh *me = (Mesh *)self->data; + if(self->index >= me->totvert) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "error, MVert is no longer valid part of mesh!"); + else + return Mesh_getProperty_internal(&(me->vdata), self->index, args); + } + return EXPP_ReturnPyObjError( PyExc_ValueError, + "error, Vertex not part of a mesh!"); +} + +static PyObject *MVert_setProp( BPy_MVert *self, PyObject *args) +{ + if( BPy_MVert_Check( self ) ){ + Mesh *me = (Mesh *)self->data; + if(self->index >= me->totvert) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "error, MVert is no longer valid part of mesh!"); + else + return Mesh_setProperty_internal(&(me->vdata), self->index, args); + } + return EXPP_ReturnPyObjError( PyExc_ValueError, + "error, Vertex not part of a mesh!"); +} + +static struct PyMethodDef BPy_MVert_methods[] = { + {"getProperty", (PyCFunction)MVert_getProp, METH_O, + "get property indicated by name"}, + {"setProperty", (PyCFunction)MVert_setProp, METH_VARARGS, + "set property indicated by name"}, + {NULL, NULL, 0, NULL} +}; + + +/************************************************************************ + * + * Python MVert_Type structure definition + * + ************************************************************************/ + +PyTypeObject MVert_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender MVert", /* char *tp_name; */ + sizeof( BPy_MVert ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + ( destructor ) MVert_dealloc,/* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) MVert_compare, /* cmpfunc tp_compare; */ + ( reprfunc ) MVert_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + ( hashfunc ) MVert_hash, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_MVert_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_MVert_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +/************************************************************************ + * + * Python PVert_Type standard operations + * + ************************************************************************/ + +static int PVert_compare( BPy_MVert * a, BPy_MVert * b ) +{ + return( a->data == b->data ) ? 0 : -1; +} + +/************************************************************************ + * + * Python PVert_Type structure definition + * + ************************************************************************/ + +PyTypeObject PVert_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender PVert", /* char *tp_name; */ + sizeof( BPy_MVert ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + ( destructor ) MVert_dealloc,/* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) PVert_compare, /* cmpfunc tp_compare; */ + ( reprfunc ) MVert_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + ( hashfunc ) MVert_hash, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + NULL, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_PVert_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +/* + * create 'thin' or 'thick' MVert objects + * + * there are two types of objects; thin (wrappers for mesh vertex) and thick + * (not contains in mesh). Thin objects are MVert_Type and thick are + * PVert_Type. For thin objects, data is a pointer to a Mesh and index + * is the vertex's index in mesh->mvert. For thick objects, data is a + * pointer to an MVert; index is unused. + */ + +/* + * create a thin MVert object + */ + +static PyObject *MVert_CreatePyObject( Mesh *mesh, int i ) +{ + BPy_MVert *obj = (BPy_MVert *)PyObject_NEW( BPy_MVert, &MVert_Type ); + + if( !obj ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyObject_New() failed" ); + + obj->index = i; + obj->data = mesh; + return (PyObject *)obj; +} + +/* + * create a thick MVert object + */ + +static PyObject *PVert_CreatePyObject( MVert *vert ) +{ + MVert *newvert; + BPy_MVert *obj = (BPy_MVert *)PyObject_NEW( BPy_MVert, &PVert_Type ); + + if( !obj ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyObject_New() failed" ); + + newvert = (MVert *)MEM_callocN( sizeof( MVert ), "MVert" ); + if( !newvert ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "MEM_callocN() failed" ); + + memcpy( newvert, vert, sizeof( MVert ) ); + obj->data = newvert; + return (PyObject *)obj; +} + +/************************************************************************ + * + * Vertex sequence + * + ************************************************************************/ + +static int MVertSeq_len( BPy_MVertSeq * self ) +{ + return self->mesh->totvert; +} + +/* + * retrive a single MVert from somewhere in the vertex list + */ + +static PyObject *MVertSeq_item( BPy_MVertSeq * self, int i ) +{ + if( i < 0 || i >= self->mesh->totvert ) + return EXPP_ReturnPyObjError( PyExc_IndexError, + "array index out of range" ); + + return MVert_CreatePyObject( self->mesh, i ); +} + +/* + * retrieve a slice of the vertex list (as a Python list) + * + * Python is nice enough to handle negative indices for us: if the user + * specifies -1, Python will pass us len()-1. So we can just check for + * indices in the range 0:len()-1. Of course, we should never actually + * return the high index, but up to one less. + */ + +static PyObject *MVertSeq_slice( BPy_MVertSeq *self, int low, int high ) +{ + PyObject *list; + int i; + + /* + * Python list slice operator returns empty list when asked for a slice + * outside the list, or if indices are reversed (low > high). Clamp + * our input to do the same. + */ + + if( low < 0 ) low = 0; + if( high > self->mesh->totvert ) high = self->mesh->totvert; + if( low > high ) low = high; + + list = PyList_New( high-low ); + if( !list ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyList_New() failed" ); + + /* + * return Py_NEW copies of requested vertices + */ + + for( i = low; i < high; ++i ) + PyList_SET_ITEM( list, i-low, + PVert_CreatePyObject( (void *)&self->mesh->mvert[i] ) ); + return list; +} + +/* + * assign a single MVert to somewhere in the vertex list + */ + +static int MVertSeq_assign_item( BPy_MVertSeq * self, int i, + BPy_MVert *v ) +{ + MVert *dst = &self->mesh->mvert[i]; + MVert *src; + + if( !v ) + return EXPP_ReturnIntError( PyExc_IndexError, + "del() not supported" ); + + if( i < 0 || i >= self->mesh->totvert ) + return EXPP_ReturnIntError( PyExc_IndexError, + "array index out of range" ); + + if( BPy_MVert_Check( v ) ) + src = &((Mesh *)v->data)->mvert[v->index]; + else + src = (MVert *)v->data; + + memcpy( dst, src, sizeof(MVert) ); + /* mesh_update( self->mesh );*/ + return 0; +} + +static int MVertSeq_assign_slice( BPy_MVertSeq *self, int low, int high, + PyObject *args ) +{ + int len, i; + + if( !PyList_Check( args ) ) + return EXPP_ReturnIntError( PyExc_IndexError, + "can only assign lists of MVerts" ); + + len = PyList_Size( args ); + + /* + * Python list slice assign operator allows for changing the size of the + * destination list, by replacement and appending.... + * + * >>> l=[1,2,3,4] + * >>> m=[11,12,13,14] + * >>> l[5:7]=m + * >>> print l + * [1, 2, 3, 4, 11, 12, 13, 14] + * >>> l=[1,2,3,4] + * >>> l[2:3]=m + * >>> print l + * [1, 2, 11, 12, 13, 14, 4] + * + * We don't want the size of the list to change (at least not at time + * point in development) so we are a little more strict: + * - low and high indices must be in range [0:len()] + * - high-low == PyList_Size(v) + */ + + if( low < 0 || high > self->mesh->totvert || low > high ) + return EXPP_ReturnIntError( PyExc_IndexError, + "invalid slice range" ); + + if( high-low != len ) + return EXPP_ReturnIntError( PyExc_IndexError, + "slice range and input list sizes must be equal" ); + + for( i = low; i < high; ++i ) + { + BPy_MVert *v = (BPy_MVert *)PyList_GET_ITEM( args, i-low ); + MVert *dst = &self->mesh->mvert[i]; + MVert *src; + + if( BPy_MVert_Check( v ) ) + src = &((Mesh *)v->data)->mvert[v->index]; + else + src = (MVert *)v->data; + + memcpy( dst, src, sizeof(MVert) ); + } + /* mesh_update( self->mesh );*/ + return 0; +} + +static PySequenceMethods MVertSeq_as_sequence = { + ( inquiry ) MVertSeq_len, /* sq_length */ + ( binaryfunc ) 0, /* sq_concat */ + ( intargfunc ) 0, /* sq_repeat */ + ( intargfunc ) MVertSeq_item, /* sq_item */ + ( intintargfunc ) MVertSeq_slice, /* sq_slice */ + ( intobjargproc ) MVertSeq_assign_item, /* sq_ass_item */ + ( intintobjargproc ) MVertSeq_assign_slice, /* sq_ass_slice */ + 0,0,0, +}; + +/************************************************************************ + * + * Python MVertSeq_Type iterator (iterates over vertices) + * + ************************************************************************/ + +/* + * Initialize the interator index + */ + +static PyObject *MVertSeq_getIter( BPy_MVertSeq * self ) +{ + if (self->iter==-1) { /* iteration for this pyobject is not yet used, just return self */ + self->iter = 0; + return EXPP_incr_ret ( (PyObject *) self ); + } else { + /* were alredy using this as an iterator, make a copy to loop on */ + BPy_MVertSeq *seq = (BPy_MVertSeq *)MVertSeq_CreatePyObject(self->mesh); + seq->iter = 0; + return (PyObject *)seq; + } +} + +/* + * Return next MVert. + */ + +static PyObject *MVertSeq_nextIter( BPy_MVertSeq * self ) +{ + if( self->iter == self->mesh->totvert ) { + self->iter= -1; /* allow it to be used as an iterator again without creating a new BPy_MVertSeq */ + return EXPP_ReturnPyObjError( PyExc_StopIteration, + "iterator at end" ); + } + + return MVert_CreatePyObject( self->mesh, self->iter++ ); +} + +/************************************************************************ + * + * Python MVertSeq_Type methods + * + ************************************************************************/ + +static PyObject *MVertSeq_extend( BPy_MVertSeq * self, PyObject *args ) +{ + int len, newlen; + int i,j; + PyObject *tmp; + MVert *newvert, *tmpvert; + Mesh *mesh = self->mesh; + CustomData vdata; + /* make sure we get a sequence of tuples of something */ + + switch( PySequence_Size( args ) ) { + case 1: /* better be a list or a tuple */ + tmp = PyTuple_GET_ITEM( args, 0 ); + if( !VectorObject_Check ( tmp ) ) { + if( !PySequence_Check ( tmp ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a sequence of sequence triplets" ); + else if( !PySequence_Size ( tmp ) ) { + Py_RETURN_NONE; + } + args = tmp; + } + Py_INCREF( args ); /* so we can safely DECREF later */ + break; + case 3: + tmp = PyTuple_GET_ITEM( args, 0 ); + /* if first item is not a number, it's wrong */ + if( !PyNumber_Check( tmp ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a sequence of sequence triplets" ); + + /* otherwise, put into a new tuple */ + args = Py_BuildValue( "((OOO))", tmp, + PyTuple_GET_ITEM( args, 1 ), PyTuple_GET_ITEM( args, 2 ) ); + if( !args ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Py_BuildValue() failed" ); + break; + + default: /* anything else is definitely wrong */ + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a sequence of sequence triplets" ); + } + + /* if no verts given, return quietly */ + len = PySequence_Size( args ); + if( len == 0 ) { + Py_DECREF ( args ); + Py_RETURN_NONE; + } + + /* create custom vertex data arrays and copy existing vertices into it */ + + newlen = mesh->totvert + len; + CustomData_copy( &mesh->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, newlen ); + CustomData_copy_data( &mesh->vdata, &vdata, 0, 0, mesh->totvert ); + + if ( !CustomData_has_layer( &vdata, CD_MVERT ) ) + CustomData_add_layer( &vdata, CD_MVERT, CD_CALLOC, NULL, newlen ); + + newvert = CustomData_get_layer( &vdata, CD_MVERT ); + + /* scan the input list and insert the new vertices */ + + tmpvert = &newvert[mesh->totvert]; + for( i = 0; i < len; ++i ) { + float co[3]; + tmp = PySequence_GetItem( args, i ); + if( VectorObject_Check( tmp ) ) { + if( ((VectorObject *)tmp)->size != 3 ) { + CustomData_free( &vdata, newlen ); + Py_DECREF ( tmp ); + Py_DECREF ( args ); + return EXPP_ReturnPyObjError( PyExc_ValueError, + "expected vector of size 3" ); + } + for( j = 0; j < 3; ++j ) + co[j] = ((VectorObject *)tmp)->vec[j]; + } else if( PySequence_Check( tmp ) ) { + int ok=1; + PyObject *flt; + if( PySequence_Size( tmp ) != 3 ) + ok = 0; + else + for( j = 0; ok && j < 3; ++j ) { + flt = PySequence_ITEM( tmp, j ); + if( !PyNumber_Check ( flt ) ) + ok = 0; + else + co[j] = (float)PyFloat_AsDouble( flt ); + Py_DECREF( flt ); + } + + if( !ok ) { + CustomData_free( &vdata, newlen ); + Py_DECREF ( args ); + Py_DECREF ( tmp ); + return EXPP_ReturnPyObjError( PyExc_ValueError, + "expected sequence triplet of floats" ); + } + } else { + CustomData_free( &vdata, newlen ); + Py_DECREF ( args ); + Py_DECREF ( tmp ); + return EXPP_ReturnPyObjError( PyExc_ValueError, + "expected sequence triplet of floats" ); + } + + Py_DECREF ( tmp ); + + /* add the coordinate to the new list */ + memcpy( tmpvert->co, co, sizeof(co) ); + + tmpvert->flag |= SELECT; + /* TODO: anything else which needs to be done when we add a vert? */ + /* probably not: NMesh's newvert() doesn't */ + ++tmpvert; + } + + CustomData_free( &mesh->vdata, mesh->totvert ); + mesh->vdata = vdata; + mesh_update_customdata_pointers( mesh ); + + /* + * if there are keys, have to fix those lists up + */ + + if( mesh->key ) { + KeyBlock *currkey = mesh->key->block.first; + float *fp, *newkey; + + while( currkey ) { + + /* create key list, copy existing data if any */ + newkey = MEM_callocN(mesh->key->elemsize*newlen, "keydata"); + if( currkey->data ) { + memcpy( newkey, currkey->data, + mesh->totvert*mesh->key->elemsize ); + MEM_freeN( currkey->data ); + currkey->data = newkey; + } + + /* add data for new vertices */ + fp = (float *)((char *)currkey->data + + (mesh->key->elemsize*mesh->totvert)); + tmpvert = mesh->mvert + mesh->totvert; + for( i = newlen - mesh->totvert; i > 0; --i ) { + VECCOPY(fp, tmpvert->co); + fp += 3; + tmpvert++; + } + currkey->totelem = newlen; + currkey = currkey->next; + } + } + + /* set final vertex list size */ + mesh->totvert = newlen; + + mesh_update( mesh ); + + Py_DECREF ( args ); + Py_RETURN_NONE; +} + +static PyObject *MVertSeq_delete( BPy_MVertSeq * self, PyObject *args ) +{ + unsigned int *vert_table; + int vert_delete, face_count; + int i; + Mesh *mesh = self->mesh; + MFace *tmpface; + + /* + * if input tuple contains a single sequence, use it as input instead; + * otherwise use the sequence as-is and check later that it contains + * one or more integers or MVerts + */ + if( PySequence_Size( args ) == 1 ) { + PyObject *tmp = PyTuple_GET_ITEM( args, 0 ); + if( PySequence_Check( tmp ) ) + args = tmp; + } + + /* if sequence is empty, do nothing */ + if( PySequence_Size( args ) == 0 ) { + Py_RETURN_NONE; + } + + /* allocate vertex lookup table */ + vert_table = (unsigned int *)MEM_callocN( + mesh->totvert*sizeof( unsigned int ), "vert_table" ); + + /* get the indices of vertices to be removed */ + for( i = PySequence_Size( args ); i--; ) { + PyObject *tmp = PySequence_GetItem( args, i ); + int index; + if( BPy_MVert_Check( tmp ) ) { + if( (void *)self->mesh != ((BPy_MVert*)tmp)->data ) { + MEM_freeN( vert_table ); + Py_DECREF( tmp ); + return EXPP_ReturnPyObjError( PyExc_ValueError, + "MVert belongs to a different mesh" ); + } + index = ((BPy_MVert*)tmp)->index; + } else if( PyInt_Check( tmp ) ) { + index = PyInt_AsLong ( tmp ); + } else { + MEM_freeN( vert_table ); + Py_DECREF( tmp ); + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a sequence of ints or MVerts" ); + } + Py_DECREF( tmp ); + if( index < 0 || index >= mesh->totvert ) { + MEM_freeN( vert_table ); + return EXPP_ReturnPyObjError( PyExc_IndexError, + "array index out of range" ); + } + vert_table[index] = UINT_MAX; + } + + /* delete things, then clean up and return */ + + vert_delete = make_vertex_table( vert_table, mesh->totvert ); + if( vert_delete ) + delete_verts( mesh, vert_table, vert_delete ); + + /* calculate edges to delete, fix vertex indices */ + delete_edges( mesh, vert_table, 0 ); + + /* + * find number of faces which contain any of the deleted vertices, + * and mark them, then delete them + */ + tmpface = mesh->mface; + face_count=0; + for( i = mesh->totface; i--; ++tmpface ) { + if( vert_table[tmpface->v1] == UINT_MAX || + vert_table[tmpface->v2] == UINT_MAX || + vert_table[tmpface->v3] == UINT_MAX || + ( tmpface->v4 && vert_table[tmpface->v4] == UINT_MAX ) ) { + tmpface->v1 = UINT_MAX; + ++face_count; + } + } + delete_faces( mesh, vert_table, face_count ); + + /* clean up and exit */ + MEM_freeN( vert_table ); + mesh_update ( mesh ); + Py_RETURN_NONE; +} + +static PyObject *MVertSeq_selected( BPy_MVertSeq * self ) +{ + int i, count; + Mesh *mesh = self->mesh; + MVert *tmpvert; + PyObject *list; + + /* first count selected edges (quicker than appending to PyList?) */ + count = 0; + tmpvert = mesh->mvert; + for( i = 0; i < mesh->totvert; ++i, ++tmpvert ) + if( tmpvert->flag & SELECT ) + ++count; + + list = PyList_New( count ); + if( !list ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyList_New() failed" ); + + /* next, insert selected edges into list */ + count = 0; + tmpvert = mesh->mvert; + for( i = 0; i < mesh->totvert; ++i, ++tmpvert ) { + if( tmpvert->flag & SELECT ) { + PyObject *tmp = PyInt_FromLong( i ); + if( !tmp ) { + Py_DECREF( list ); + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyInt_FromLong() failed" ); + } + PyList_SET_ITEM( list, count, tmp ); + ++count; + } + } + return list; +} +static PyObject *MVertSeq_add_layertype(BPy_MVertSeq *self, PyObject *args) +{ + Mesh *me = (Mesh*)self->mesh; + return Mesh_addPropLayer_internal(me, &(me->vdata), me->totvert, args); +} +static PyObject *MVertSeq_del_layertype(BPy_MVertSeq *self, PyObject *value) +{ + Mesh *me = (Mesh*)self->mesh; + return Mesh_removePropLayer_internal(me, &(me->vdata), me->totvert, value); +} +static PyObject *MVertSeq_rename_layertype(BPy_MVertSeq *self, PyObject *args) +{ + Mesh *me = (Mesh*)self->mesh; + return Mesh_renamePropLayer_internal(me,&(me->vdata),args); +} +static PyObject *MVertSeq_PropertyList(BPy_MVertSeq *self) +{ + Mesh *me = (Mesh*)self->mesh; + return Mesh_propList_internal(&(me->vdata)); +} +static PyObject *M_Mesh_PropertiesTypeDict(void) +{ + PyObject *Types = PyConstant_New( ); + if(Types) { + BPy_constant *d = (BPy_constant *) Types; + PyConstant_Insert(d, "FLOAT", PyInt_FromLong(CD_PROP_FLT)); + PyConstant_Insert(d, "INT" , PyInt_FromLong(CD_PROP_INT)); + PyConstant_Insert(d, "STRING", PyInt_FromLong(CD_PROP_STR)); + } + return Types; +} + +static struct PyMethodDef BPy_MVertSeq_methods[] = { + {"extend", (PyCFunction)MVertSeq_extend, METH_VARARGS, + "add vertices to mesh"}, + {"delete", (PyCFunction)MVertSeq_delete, METH_VARARGS, + "delete vertices from mesh"}, + {"selected", (PyCFunction)MVertSeq_selected, METH_NOARGS, + "returns a list containing indices of selected vertices"}, + {"addPropertyLayer",(PyCFunction)MVertSeq_add_layertype, METH_VARARGS, + "add a new property layer"}, + {"removePropertyLayer",(PyCFunction)MVertSeq_del_layertype, METH_O, + "removes a property layer"}, + {"renamePropertyLayer",(PyCFunction)MVertSeq_rename_layertype, METH_VARARGS, + "renames an existing property layer"}, + {NULL, NULL, 0, NULL} +}; + +static PyGetSetDef BPy_MVertSeq_getseters[] = { + {"properties", + (getter)MVertSeq_PropertyList, (setter)NULL, + "vertex property layers, read only", + NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + + + +/************************************************************************ + * + * Python MVertSeq_Type standard operations + * + ************************************************************************/ + +/*****************************************************************************/ +/* Python MVertSeq_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject MVertSeq_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender MVertSeq", /* char *tp_name; */ + sizeof( BPy_MVertSeq ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + NULL, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + &MVertSeq_as_sequence, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + ( getiterfunc) MVertSeq_getIter, /* getiterfunc tp_iter; */ + ( iternextfunc ) MVertSeq_nextIter, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_MVertSeq_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_MVertSeq_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +/************************************************************************ + * + * Edge attributes + * + ************************************************************************/ + +static MEdge * MEdge_get_pointer( BPy_MEdge * self ) +{ + if( self->index >= self->mesh->totedge ) + return (MEdge *)EXPP_ReturnPyObjError( PyExc_RuntimeError, + "MEdge is no longer valid" ); + return &self->mesh->medge[self->index]; +} + +/* + * get an edge's crease value + */ + +static PyObject *MEdge_getCrease( BPy_MEdge * self ) +{ + MEdge *edge = MEdge_get_pointer( self ); + + if( !edge ) + return NULL; + + return PyInt_FromLong( edge->crease ); +} + +/* + * set an edge's crease value + */ + +static int MEdge_setCrease( BPy_MEdge * self, PyObject * value ) +{ + MEdge *edge = MEdge_get_pointer( self ); + + if( !edge ) + return -1; + + return EXPP_setIValueClamped( value, &edge->crease, 0, 255, 'b' ); +} + +/* + * get an edge's flag + */ + +static PyObject *MEdge_getFlag( BPy_MEdge * self ) +{ + MEdge *edge = MEdge_get_pointer( self ); + + if( !edge ) + return NULL; + + return PyInt_FromLong( edge->flag ); +} + +/* + * set an edge's flag + */ + +static int MEdge_setFlag( BPy_MEdge * self, PyObject * value ) +{ + short param; + static short bitmask = SELECT + | ME_EDGEDRAW + | ME_SEAM + | ME_FGON + | ME_HIDE + | ME_EDGERENDER + | ME_LOOSEEDGE + | ME_SEAM_LAST + | ME_SHARP; + MEdge *edge = MEdge_get_pointer( self ); + + if( !edge ) + return -1; + + if( !PyInt_Check ( value ) ) { + char errstr[128]; + sprintf ( errstr , "expected int bitmask of 0x%04x", bitmask ); + return EXPP_ReturnIntError( PyExc_TypeError, errstr ); + } + param = (short)PyInt_AS_LONG ( value ); + + if ( ( param & bitmask ) != param ) + return EXPP_ReturnIntError( PyExc_ValueError, + "invalid bit(s) set in mask" ); + + edge->flag = param; + + return 0; +} + +/* + * get an edge's first vertex + */ + +static PyObject *MEdge_getV1( BPy_MEdge * self ) +{ + MEdge *edge = MEdge_get_pointer( self ); + + if( !edge ) + return NULL; + + return MVert_CreatePyObject( self->mesh, edge->v1 ); +} + +/* + * set an edge's first vertex + */ + +static int MEdge_setV1( BPy_MEdge * self, BPy_MVert * value ) +{ + MEdge *edge = MEdge_get_pointer( self ); + + if( !edge ) + return -1; + if( !BPy_MVert_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, "expected an MVert" ); + + edge->v1 = value->index; + return 0; +} + +/* + * get an edge's second vertex + */ + +static PyObject *MEdge_getV2( BPy_MEdge * self ) +{ + MEdge *edge = MEdge_get_pointer( self ); + + if( !edge ) + return NULL; /* error is set */ + /* if v2 is out of range, the python mvert will complain, no need to check here */ + return MVert_CreatePyObject( self->mesh, edge->v2 ); +} + +/* + * set an edge's second vertex + */ + +static int MEdge_setV2( BPy_MEdge * self, BPy_MVert * value ) +{ + MEdge *edge = MEdge_get_pointer( self ); + + if( !edge ) + return -1; /* error is set */ + if( !BPy_MVert_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, "expected an MVert" ); + + if ( edge->v1 == value->index ) + return EXPP_ReturnIntError( PyExc_ValueError, "an edge cant use the same vertex for each end" ); + + edge->v2 = value->index; + return 0; +} + +/* + * get an edge's index + */ + +static PyObject *MEdge_getIndex( BPy_MEdge * self ) +{ + if( !MEdge_get_pointer( self ) ) + return NULL; /* error is set */ + + return PyInt_FromLong( self->index ); +} + +/* + * get an edge's flag + */ + +static PyObject *MEdge_getMFlagBits( BPy_MEdge * self, void * type ) +{ + MEdge *edge = MEdge_get_pointer( self ); + + if( !edge ) + return NULL; /* error is set */ + + return EXPP_getBitfield( &edge->flag, (int)((long)type & 0xff), 'b' ); +} + +/* + * get an edge's length + */ + +static PyObject *MEdge_getLength( BPy_MEdge * self ) +{ + MEdge *edge = MEdge_get_pointer( self ); + double dot = 0.0f; + float tmpf; + int i; + float *v1, *v2; + + if (!edge) + return NULL; /* error is set */ + + if MEDGE_VERT_BADRANGE_CHECK(self->mesh, edge) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, "This edge uses removed vert(s)" ); + + /* get the 2 edges vert locations */ + v1= (&((Mesh *)self->mesh)->mvert[edge->v1])->co; + v2= (&((Mesh *)self->mesh)->mvert[edge->v2])->co; + + if( !edge ) + return NULL; + + for( i = 0; i < 3; i++ ) { + tmpf = v1[i] - v2[i]; + dot += tmpf*tmpf; + } + return PyFloat_FromDouble( sqrt( dot ) ); +} + +/* + * get an key for using in a dictionary or set key + */ + +static PyObject *MEdge_getKey( BPy_MEdge * self ) +{ + PyObject *attr; + MEdge *edge = MEdge_get_pointer( self ); + if (!edge) + return NULL; /* error is set */ + + attr = PyTuple_New( 2 ); + if (edge->v1 > edge->v2) { + PyTuple_SET_ITEM( attr, 0, PyInt_FromLong(edge->v2) ); + PyTuple_SET_ITEM( attr, 1, PyInt_FromLong(edge->v1) ); + } else { + PyTuple_SET_ITEM( attr, 0, PyInt_FromLong(edge->v1) ); + PyTuple_SET_ITEM( attr, 1, PyInt_FromLong(edge->v2) ); + } + return attr; +} + +/* + * set an edge's select state + */ + +static int MEdge_setSel( BPy_MEdge * self,PyObject * value, + void * type_unused ) +{ + MEdge *edge = MEdge_get_pointer( self ); + int param = PyObject_IsTrue( value ); + Mesh *me = self->mesh; + + if( !edge ) + return -1; + + if MEDGE_VERT_BADRANGE_CHECK(me, edge) + return EXPP_ReturnIntError( PyExc_RuntimeError, "This edge uses removed vert(s)" ); + + if( param == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected True/False or 0/1" ); + + if( param ) { + edge->flag |= SELECT; + me->mvert[edge->v1].flag |= SELECT; + me->mvert[edge->v2].flag |= SELECT; + } + else { + edge->flag &= ~SELECT; + me->mvert[edge->v1].flag &= ~SELECT; + me->mvert[edge->v2].flag &= ~SELECT; + } + + if( self->mesh->mselect ) { + MEM_freeN( self->mesh->mselect ); + self->mesh->mselect = NULL; + } + + return 0; +} + +/************************************************************************ + * + * Python MEdge_Type attributes get/set structure + * + ************************************************************************/ + +static PyGetSetDef BPy_MEdge_getseters[] = { + {"crease", + (getter)MEdge_getCrease, (setter)MEdge_setCrease, + "edge's crease value", + NULL}, + {"flag", + (getter)MEdge_getFlag, (setter)MEdge_setFlag, + "edge's flags", + NULL}, + {"v1", + (getter)MEdge_getV1, (setter)MEdge_setV1, + "edge's first vertex", + NULL}, + {"v2", + (getter)MEdge_getV2, (setter)MEdge_setV2, + "edge's second vertex", + NULL}, + {"index", + (getter)MEdge_getIndex, (setter)NULL, + "edge's index", + NULL}, + {"sel", + (getter)MEdge_getMFlagBits, (setter)MEdge_setSel, + "edge selected in edit mode", + (void *)SELECT}, + {"length", + (getter)MEdge_getLength, (setter)NULL, + "edge's length, read only", + NULL}, + {"key", + (getter)MEdge_getKey, (setter)NULL, + "edge's key for using with sets or dictionaries, read only", + NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/************************************************************************ + * + * Python MEdge_Type iterator (iterates over vertices) + * + ************************************************************************/ + +/* + * Initialize the interator index + */ + +static PyObject *MEdge_getIter( BPy_MEdge * self ) +{ + if (self->iter==-1) { /* not alredy used to iterator on, just use self */ + self->iter = 0; + return EXPP_incr_ret ( (PyObject *) self ); + } else { /* alredy being iterated on, return a copy */ + BPy_MEdge *seq = (BPy_MEdge *)MEdge_CreatePyObject(self->mesh, self->index); + seq->iter = 0; + return (PyObject *)seq; + } +} + +/* + * Return next MVert. Throw an exception after the second vertex. + */ + +static PyObject *MEdge_nextIter( BPy_MEdge * self ) +{ + if( self->iter == 2 ) { + self->iter = -1; + return EXPP_ReturnPyObjError( PyExc_StopIteration, + "iterator at end" ); + } + + self->iter++; + if( self->iter == 1 ) + return MEdge_getV1( self ); + else + return MEdge_getV2( self ); +} + +/************************************************************************ + * + * Python MEdge_Type standard operations + * + ************************************************************************/ + +static int MEdge_compare( BPy_MEdge * a, BPy_MEdge * b ) +{ + return( a->mesh == b->mesh && a->index == b->index ) ? 0 : -1; +} + +static PyObject *MEdge_repr( BPy_MEdge * self ) +{ + struct MEdge *edge = MEdge_get_pointer( self ); + + if( !edge ) + return NULL; + + return PyString_FromFormat( "[MEdge (%d %d) %d %d]", + (int)edge->v1, (int)edge->v2, (int)edge->crease, + (int)self->index ); +} + +static long MEdge_hash( BPy_MEdge *self ) +{ + return (long)self->index; +} +static PyObject *MEdge_getProp( BPy_MEdge *self, PyObject *args) +{ + Mesh *me = (Mesh *)self->mesh; + return Mesh_getProperty_internal(&(me->edata), self->index, args); +} + +static PyObject *MEdge_setProp( BPy_MEdge *self, PyObject *args) +{ + Mesh *me = (Mesh *)self->mesh; + return Mesh_setProperty_internal(&(me->edata), self->index, args); +} + +static struct PyMethodDef BPy_MEdge_methods[] = { + {"getProperty", (PyCFunction)MEdge_getProp, METH_O, + "get property indicated by name"}, + {"setProperty", (PyCFunction)MEdge_setProp, METH_VARARGS, + "set property indicated by name"}, + {NULL, NULL, 0, NULL} +}; +/************************************************************************ + * + * Python MEdge_Type structure definition + * + ************************************************************************/ + +PyTypeObject MEdge_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender MEdge", /* char *tp_name; */ + sizeof( BPy_MEdge ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) MEdge_compare, /* cmpfunc tp_compare; */ + ( reprfunc ) MEdge_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + ( hashfunc ) MEdge_hash, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + ( getiterfunc) MEdge_getIter, /* getiterfunc tp_iter; */ + ( iternextfunc ) MEdge_nextIter, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_MEdge_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_MEdge_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +static PyObject *MEdge_CreatePyObject( Mesh * mesh, int i ) +{ + BPy_MEdge *obj = PyObject_NEW( BPy_MEdge, &MEdge_Type ); + + if( !obj ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyObject_New() failed" ); + + obj->mesh = mesh; + obj->index = i; + obj->iter = -1; + return (PyObject *)obj; +} + +/************************************************************************ + * + * Edge sequence + * + ************************************************************************/ + +static int MEdgeSeq_len( BPy_MEdgeSeq * self ) +{ + return self->mesh->totedge; +} + +static PyObject *MEdgeSeq_item( BPy_MEdgeSeq * self, int i ) +{ + if( i < 0 || i >= self->mesh->totedge ) + return EXPP_ReturnPyObjError( PyExc_IndexError, + "array index out of range" ); + + return MEdge_CreatePyObject( self->mesh, i ); +} + + +static PySequenceMethods MEdgeSeq_as_sequence = { + ( inquiry ) MEdgeSeq_len, /* sq_length */ + ( binaryfunc ) 0, /* sq_concat */ + ( intargfunc ) 0, /* sq_repeat */ + ( intargfunc ) MEdgeSeq_item, /* sq_item */ + ( intintargfunc ) 0, /* sq_slice */ + ( intobjargproc ) 0, /* sq_ass_item */ + ( intintobjargproc ) 0, /* sq_ass_slice */ + 0,0,0, +}; + +/************************************************************************ + * + * Python MEdgeSeq_Type iterator (iterates over edges) + * + ************************************************************************/ + +/* + * Initialize the interator index + */ + +static PyObject *MEdgeSeq_getIter( BPy_MEdgeSeq * self ) +{ + if (self->iter==-1) { /* iteration for this pyobject is not yet used, just return self */ + self->iter = 0; + return EXPP_incr_ret ( (PyObject *) self ); + } else { + BPy_MEdgeSeq *seq = (BPy_MEdgeSeq *)MEdgeSeq_CreatePyObject(self->mesh); + seq->iter = 0; + return (PyObject *)seq; + } +} + +/* + * Return next MEdge. + */ + +static PyObject *MEdgeSeq_nextIter( BPy_MEdgeSeq * self ) +{ + if( self->iter == self->mesh->totedge ) { + self->iter= -1; + return EXPP_ReturnPyObjError( PyExc_StopIteration, + "iterator at end" ); + } + + return MEdge_CreatePyObject( self->mesh, self->iter++ ); +} + +/************************************************************************ + * + * Python MEdgeSeq_Type methods + * + ************************************************************************/ + +/* + * Create edges from tuples of vertices. Duplicate new edges, or + * edges which already exist, + */ + +static PyObject *MEdgeSeq_extend( BPy_MEdgeSeq * self, PyObject *args ) +{ + int len, nverts; + int i, j, ok; + int new_edge_count, good_edges; + SrchEdges *oldpair, *newpair, *tmppair, *tmppair2; + PyObject *tmp; + BPy_MVert *e[4]; + MEdge *tmpedge; + Mesh *mesh = self->mesh; + + /* make sure we get a tuple of sequences of something */ + switch( PySequence_Size( args ) ) { + case 1: + /* if a sequence... */ + tmp = PyTuple_GET_ITEM( args, 0 ); + if( PySequence_Check( tmp ) ) { + PyObject *tmp2; + + /* ignore empty sequences */ + if( !PySequence_Size( tmp ) ) { + Py_RETURN_NONE; + } + + /* if another sequence, use it */ + tmp2 = PySequence_ITEM( tmp, 0 ); + if( PySequence_Check( tmp2 ) ) + args = tmp; + Py_INCREF( args ); + Py_DECREF( tmp2 ); + } else + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a sequence of sequence pairs" ); + break; + case 2: + case 3: + case 4: /* two to four args may be individual verts */ + tmp = PyTuple_GET_ITEM( args, 0 ); + /* + * if first item isn't a sequence, then assume it's a bunch of MVerts + * and wrap inside a tuple + */ + if( !PySequence_Check( tmp ) ) { + args = Py_BuildValue( "(O)", args ); + if( !args ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Py_BuildValue() failed" ); + /* + * otherwise, assume it already a bunch of sequences so use as-is + */ + } else { + Py_INCREF( args ); /* so we can safely DECREF later */ + } + break; + default: /* anything else is definitely wrong */ + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a sequence of sequence pairs" ); + } + + /* make sure there is something to add */ + len = PySequence_Size( args ); + if( len == 0 ) { + Py_DECREF ( args ); + Py_RETURN_NONE; + } + + /* verify the param list and get a total count of number of edges */ + new_edge_count = 0; + for( i = 0; i < len; ++i ) { + tmp = PySequence_GetItem( args, i ); + + /* not a tuple of MVerts... error */ + if( !PySequence_Check( tmp ) ) { + Py_DECREF( tmp ); + Py_DECREF( args ); + return EXPP_ReturnPyObjError( PyExc_ValueError, + "expected sequence of MVert sequences" ); + } + + /* not the right number of MVerts... error */ + nverts = PySequence_Size( tmp ); + if( nverts < 2 || nverts > 4 ) { + Py_DECREF( tmp ); + Py_DECREF( args ); + return EXPP_ReturnPyObjError( PyExc_ValueError, + "expected 2 to 4 MVerts per sequence" ); + } + + if( EXPP_check_sequence_consistency( tmp, &MVert_Type ) == 1 ) { + + /* get MVerts, check they're from this mesh */ + ok = 1; + for( j = 0; ok && j < nverts; ++j ) { + e[0] = (BPy_MVert *)PySequence_GetItem( tmp, j ); + if( (void *)e[0]->data != (void *)self->mesh ) + ok = 0; + Py_DECREF( e[0] ); + } + Py_DECREF( tmp ); + + /* not MVerts from another mesh ... error */ + if( !ok ) { + Py_DECREF( args ); + return EXPP_ReturnPyObjError( PyExc_ValueError, + "vertices are from a different mesh" ); + } + } else { + ok = 0; + for( j = 0; ok == 0 && j < nverts; ++j ) { + PyObject *item = PySequence_ITEM( tmp, j ); + if( !PyInt_Check( item ) ) + ok = 1; + else { + int index = PyInt_AsLong ( item ); + if( index < 0 || index >= self->mesh->totvert ) + ok = 2; + } + Py_DECREF( item ); + } + Py_DECREF( tmp ); + + /* not ints or outside of vertex list ... error */ + if( ok ) { + Py_DECREF( args ); + if( ok == 1 ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected an integer index" ); + else + return EXPP_ReturnPyObjError( PyExc_KeyError, + "index out of range" ); + } + } + + if( nverts == 2 ) + ++new_edge_count; /* if only two vert, then add only edge */ + else + new_edge_count += nverts; /* otherwise, one edge per vert */ + } + + /* OK, commit to allocating the search structures */ + newpair = (SrchEdges *)MEM_callocN( sizeof(SrchEdges)*new_edge_count, + "MEdgePairs" ); + + /* scan the input list and build the new edge pair list */ + len = PySequence_Size( args ); + tmppair = newpair; + new_edge_count = 0; + for( i = 0; i < len; ++i ) { + int edge_count; + int eedges[4]; + tmp = PySequence_GetItem( args, i ); + nverts = PySequence_Size( tmp ); + + /* get new references for the vertices */ + for(j = 0; j < nverts; ++j ) { + PyObject *item = PySequence_ITEM( tmp, j ); + if( BPy_MVert_Check( item ) ) { + eedges[j] = ((BPy_MVert *)item)->index; + } else { + eedges[j] = PyInt_AsLong ( item ); + } + Py_DECREF( item ); + } + Py_DECREF( tmp ); + + if( nverts == 2 ) + edge_count = 1; /* again, two verts give just one edge */ + else + edge_count = nverts; + + /* now add the edges to the search list */ + for( j = 0; j < edge_count; ++j ) { + int k = j+1; + if( k == nverts ) /* final edge */ + k = 0; + + /* sort verts into search list, skip if two are the same */ + if( eedges[j] != eedges[k] ) { + if( eedges[j] < eedges[k] ) { + tmppair->v[0] = eedges[j]; + tmppair->v[1] = eedges[k]; + tmppair->swap = 0; + } else { + tmppair->v[0] = eedges[k]; + tmppair->v[1] = eedges[j]; + tmppair->swap = 1; + } + tmppair->index = new_edge_count; + ++new_edge_count; + tmppair++; + } + } + + } + + /* sort the new edge pairs */ + qsort( newpair, new_edge_count, sizeof(SrchEdges), medge_comp ); + + /* + * find duplicates in the new list and mark. if it's a duplicate, + * then mark by setting second vert index to 0 (a real edge won't have + * second vert index of 0 since verts are sorted) + */ + + good_edges = new_edge_count; /* all edges are good at this point */ + + tmppair = newpair; /* "last good edge" */ + tmppair2 = &tmppair[1]; /* "current candidate edge" */ + for( i = 0; i < new_edge_count; ++i ) { + if( tmppair->v[0] != tmppair2->v[0] || + tmppair->v[1] != tmppair2->v[1] ) + tmppair = tmppair2; /* last != current, so current == last */ + else { + tmppair2->v[1] = 0; /* last == current, so mark as duplicate */ + --good_edges; /* one less good edge */ + } + tmppair2++; + } + + /* if mesh has edges, see if any of the new edges are already in it */ + if( mesh->totedge ) { + oldpair = (SrchEdges *)MEM_callocN( sizeof(SrchEdges)*mesh->totedge, + "MEdgePairs" ); + + /* + * build a search list of new edges (don't need to update "swap" + * field, since we're not creating edges here) + */ + tmppair = oldpair; + tmpedge = mesh->medge; + for( i = 0; i < mesh->totedge; ++i ) { + if( tmpedge->v1 < tmpedge->v2 ) { + tmppair->v[0] = tmpedge->v1; + tmppair->v[1] = tmpedge->v2; + } else { + tmppair->v[0] = tmpedge->v2; + tmppair->v[1] = tmpedge->v1; + } + ++tmpedge; + ++tmppair; + } + + /* sort the old edge pairs */ + qsort( oldpair, mesh->totedge, sizeof(SrchEdges), medge_comp ); + + /* eliminate new edges already in the mesh */ + tmppair = newpair; + for( i = new_edge_count; i-- ; ) { + if( tmppair->v[1] ) { + if( bsearch( tmppair, oldpair, mesh->totedge, + sizeof(SrchEdges), medge_comp ) ) { + tmppair->v[1] = 0; /* mark as duplicate */ + --good_edges; + } + } + tmppair++; + } + MEM_freeN( oldpair ); + } + + /* if any new edges are left, add to list */ + if( good_edges ) { + CustomData edata; + int totedge = mesh->totedge+good_edges; + + /* create custom edge data arrays and copy existing edges into it */ + CustomData_copy( &mesh->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge ); + CustomData_copy_data( &mesh->edata, &edata, 0, 0, mesh->totedge ); + + if ( !CustomData_has_layer( &edata, CD_MEDGE ) ) + CustomData_add_layer( &edata, CD_MEDGE, CD_CALLOC, NULL, totedge ); + + /* replace old with new data */ + CustomData_free( &mesh->edata, mesh->totedge ); + mesh->edata = edata; + mesh_update_customdata_pointers( mesh ); + + /* resort edges into original order */ + qsort( newpair, new_edge_count, sizeof(SrchEdges), medge_index_comp ); + + /* point to the first edge we're going to add */ + tmpedge = &mesh->medge[mesh->totedge]; + tmppair = newpair; + + /* as we find a good edge, add it */ + while( good_edges ) { + if( tmppair->v[1] ) { /* not marked as duplicate ! */ + if( !tmppair->swap ) { + tmpedge->v1 = tmppair->v[0]; + tmpedge->v2 = tmppair->v[1]; + } else { + tmpedge->v1 = tmppair->v[1]; + tmpedge->v2 = tmppair->v[0]; + } + tmpedge->flag = ME_EDGEDRAW | ME_EDGERENDER | SELECT; + mesh->totedge++; + --good_edges; + ++tmpedge; + } + tmppair++; + } + } + + /* clean up and leave */ + mesh_update( mesh ); + MEM_freeN( newpair ); + Py_DECREF ( args ); + Py_RETURN_NONE; +} + +static PyObject *MEdgeSeq_delete( BPy_MEdgeSeq * self, PyObject *args ) +{ + Mesh *mesh = self->mesh; + MEdge *srcedge; + MFace *srcface; + unsigned int *vert_table, *del_table, *edge_table; + int i, len; + int face_count, edge_count, vert_count; + + /* + * if input tuple contains a single sequence, use it as input instead; + * otherwise use the sequence as-is and check later that it contains + * one or more integers or MVerts + */ + if( PySequence_Size( args ) == 1 ) { + PyObject *tmp = PyTuple_GET_ITEM( args, 0 ); + if( PySequence_Check( tmp ) ) + args = tmp; + } + + /* if sequence is empty, do nothing */ + len = PySequence_Size( args ); + if( len == 0 ) { + Py_RETURN_NONE; + } + + edge_table = (unsigned int *)MEM_callocN( len*sizeof( unsigned int ), + "edge_table" ); + + /* get the indices of edges to be removed */ + for( i = len; i--; ) { + PyObject *tmp = PySequence_GetItem( args, i ); + if( BPy_MEdge_Check( tmp ) ) + edge_table[i] = ((BPy_MEdge *)tmp)->index; + else if( PyInt_Check( tmp ) ) + edge_table[i] = PyInt_AsLong ( tmp ); + else { + MEM_freeN( edge_table ); + Py_DECREF( tmp ); + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a sequence of ints or MEdges" ); + } + Py_DECREF( tmp ); + + /* if index out-of-range, throw exception */ + if( edge_table[i] >= (unsigned int)mesh->totedge ) { + MEM_freeN( edge_table ); + return EXPP_ReturnPyObjError( PyExc_ValueError, + "array index out of range" ); + } + } + + /* + * build two tables: first table marks vertices which belong to an edge + * which is being deleted + */ + del_table = (unsigned int *)MEM_callocN( + mesh->totvert*sizeof( unsigned int ), "vert_table" ); + + /* + * Borrow a trick from editmesh code: for each edge to be deleted, mark + * its vertices as well. Then go through face list and look for two + * consecutive marked vertices. + */ + + /* mark each edge that's to be deleted */ + srcedge = mesh->medge; + for( i = len; i--; ) { + unsigned int idx = edge_table[i]; + del_table[srcedge[idx].v1] = UINT_MAX; + del_table[srcedge[idx].v2] = UINT_MAX; + srcedge[idx].v1 = UINT_MAX; + } + + /* + * second table is used for vertices which become orphaned (belong to no + * edges) and need to be deleted; it's also the normal lookup table for + * old->new vertex indices + */ + + vert_table = (unsigned int *)MEM_mallocN( + mesh->totvert*sizeof( unsigned int ), "vert_table" ); + + /* assume all edges will be deleted (fills with UINT_MAX) */ + memset( vert_table, UCHAR_MAX, mesh->totvert*sizeof( unsigned int ) ); + + /* unmark vertices of each "good" edge; count each "bad" edge */ + edge_count = 0; + for( i = mesh->totedge; i--; ++srcedge ) + if( srcedge->v1 != UINT_MAX ) + vert_table[srcedge->v1] = vert_table[srcedge->v2] = 0; + else + ++edge_count; + + /* + * find faces which no longer have all edges + */ + + face_count = 0; + srcface = mesh->mface; + for( i = 0; i < mesh->totface; ++i, ++srcface ) { + int len = srcface->v4 ? 4 : 3; + unsigned int id[4]; + int del; + + id[0] = del_table[srcface->v1]; + id[1] = del_table[srcface->v2]; + id[2] = del_table[srcface->v3]; + id[3] = del_table[srcface->v4]; + + del = ( id[0] == UINT_MAX && id[1] == UINT_MAX ) || + ( id[1] == UINT_MAX && id[2] == UINT_MAX ); + if( !del ) { + if( len == 3 ) + del = ( id[2] == UINT_MAX && id[0] == UINT_MAX ); + else + del = ( id[2] == UINT_MAX && id[3] == UINT_MAX ) || + ( id[3] == UINT_MAX && id[0] == UINT_MAX ); + } + if( del ) { + srcface->v1 = UINT_MAX; + ++face_count; + } + } + + /* fix the vertex lookup table, if any verts to delete, do so now */ + vert_count = make_vertex_table( vert_table, mesh->totvert ); + if( vert_count ) + delete_verts( mesh, vert_table, vert_count ); + + /* delete faces which have a deleted edge */ + delete_faces( mesh, vert_table, face_count ); + + /* now delete the edges themselves */ + delete_edges( mesh, vert_table, edge_count ); + + /* clean up and return */ + MEM_freeN( del_table ); + MEM_freeN( vert_table ); + MEM_freeN( edge_table ); + mesh_update ( mesh ); + Py_RETURN_NONE; +} + +static PyObject *MEdgeSeq_collapse( BPy_MEdgeSeq * self, PyObject *args ) +{ + MEdge *srcedge; + unsigned int *edge_table; + float (*vert_list)[3]; + int i, len; + Base *base, *basact; + Mesh *mesh = self->mesh; + Object *object = NULL; + PyObject *tmp; + + /* + * when using removedoublesflag(), we need to switch to editmode, so + * nobody else can be using it + */ + + if( G.obedit ) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "can't use collapse() while in edit mode" ); + + /* make sure we get a tuple of sequences of something */ + switch( PySequence_Size( args ) ) { + case 1: + /* if a sequence... */ + tmp = PyTuple_GET_ITEM( args, 0 ); + if( PySequence_Check( tmp ) ) { + PyObject *tmp2; + + /* ignore empty sequences */ + if( !PySequence_Size( tmp ) ) { + Py_RETURN_NONE; + } + + /* if another sequence, use it */ + tmp2 = PySequence_ITEM( tmp, 0 ); + if( PySequence_Check( tmp2 ) ) + args = tmp; + Py_INCREF( args ); + Py_DECREF( tmp2 ); + } else + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a sequence of sequence pairs" ); + break; + case 2: /* two args may be individual edges/verts */ + tmp = PyTuple_GET_ITEM( args, 0 ); + /* + * if first item isn't a sequence, then assume it's a bunch of MVerts + * and wrap inside a tuple + */ + if( !PySequence_Check( tmp ) ) { + args = Py_BuildValue( "(O)", args ); + if( !args ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Py_BuildValue() failed" ); + /* + * otherwise, assume it already a bunch of sequences so use as-is + */ + } else { + Py_INCREF( args ); /* so we can safely DECREF later */ + } + break; + default: /* anything else is definitely wrong */ + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a sequence of sequence pairs" ); + } + + /* if sequence is empty, do nothing */ + len = PySequence_Size( args ); + if( len == 0 ) { + Py_RETURN_NONE; + } + + /* allocate table of edge indices and new vertex values */ + + edge_table = (unsigned int *)MEM_callocN( len*sizeof( unsigned int ), + "edge_table" ); + vert_list = (float (*)[3])MEM_callocN( 3*len*sizeof( float ), + "vert_list" ); + + /* get the indices of edges to be collapsed and new vert locations */ + for( i = len; i--; ) { + PyObject *tmp1; + PyObject *tmp2; + + tmp = PySequence_GetItem( args, i ); + + /* if item isn't sequence of size 2, error */ + if( !PySequence_Check( tmp ) || PySequence_Size( tmp ) != 2 ) { + MEM_freeN( edge_table ); + MEM_freeN( vert_list ); + Py_DECREF( tmp ); + Py_DECREF( args ); + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a sequence of (MEdges, vector)" ); + } + + /* if items aren't a MEdge/int and vector, error */ + tmp1 = PySequence_GetItem( tmp, 0 ); + tmp2 = PySequence_GetItem( tmp, 1 ); + Py_DECREF( tmp ); + if( !(BPy_MEdge_Check( tmp1 ) || PyInt_Check( tmp1 )) || + !VectorObject_Check ( tmp2 ) ) { + MEM_freeN( edge_table ); + MEM_freeN( vert_list ); + Py_DECREF( tmp1 ); + Py_DECREF( tmp2 ); + Py_DECREF( args ); + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a sequence of (MEdges, vector)" ); + } + + /* store edge index, new vertex location */ + if( PyInt_Check( tmp1 ) ) + edge_table[i] = PyInt_AsLong ( tmp1 ); + else + edge_table[i] = ((BPy_MEdge *)tmp1)->index; + memcpy( vert_list[i], ((VectorObject *)tmp2)->vec, + 3*sizeof( float ) ); + Py_DECREF( tmp1 ); + Py_DECREF( tmp2 ); + + /* if index out-of-range, throw exception */ + if( edge_table[i] >= (unsigned int)mesh->totedge ) { + MEM_freeN( edge_table ); + MEM_freeN( vert_list ); + return EXPP_ReturnPyObjError( PyExc_ValueError, + "edge index out of range" ); + } + } + + /* + * simple algorithm: + * (1) deselect all verts + * (2) for each edge + * (2a) replace both verts with the new vert + * (2b) select both verts + * (3) call removedoublesflag() + */ + + /* (1) deselect all verts */ + for( i = mesh->totvert; i--; ) + mesh->mvert[i].flag &= ~SELECT; + + /* (2) replace edge's verts and select them */ + for( i = len; i--; ) { + srcedge = &mesh->medge[edge_table[i]]; + memcpy( &mesh->mvert[srcedge->v1].co, vert_list[i], 3*sizeof( float ) ); + memcpy( &mesh->mvert[srcedge->v2].co, vert_list[i], 3*sizeof( float ) ); + mesh->mvert[srcedge->v1].flag |= SELECT; + mesh->mvert[srcedge->v2].flag |= SELECT; + } + + /* (3) call removedoublesflag() */ + for( base = FIRSTBASE; base; base = base->next ) { + if( base->object->type == OB_MESH && + base->object->data == self->mesh ) { + object = base->object; + break; + } + } + + basact = BASACT; + BASACT = base; + + removedoublesflag( 1, 0, 0.0 ); + /* make mesh's object active, enter mesh edit mode */ + G.obedit = object; + + /* exit edit mode, free edit mesh */ + load_editMesh(); + free_editMesh(G.editMesh); + + BASACT = basact; + + /* clean up and exit */ + Py_DECREF( args ); + MEM_freeN( vert_list ); + MEM_freeN( edge_table ); + mesh_update ( mesh ); + Py_RETURN_NONE; +} + + +static PyObject *MEdgeSeq_selected( BPy_MEdgeSeq * self ) +{ + int i, count; + Mesh *mesh = self->mesh; + MEdge *tmpedge; + PyObject *list; + + /* first count selected edges (quicker than appending to PyList?) */ + count = 0; + tmpedge = mesh->medge; + for( i = 0; i < mesh->totedge; ++i, ++tmpedge ) + if( (mesh->mvert[tmpedge->v1].flag & SELECT) && + (mesh->mvert[tmpedge->v2].flag & SELECT) ) + ++count; + + list = PyList_New( count ); + if( !list ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyList_New() failed" ); + + /* next, insert selected edges into list */ + count = 0; + tmpedge = mesh->medge; + for( i = 0; i < mesh->totedge; ++i, ++tmpedge ) { + if( (mesh->mvert[tmpedge->v1].flag & SELECT) && + (mesh->mvert[tmpedge->v2].flag & SELECT) ) { + PyObject *tmp = PyInt_FromLong( i ); + if( !tmp ) { + Py_DECREF( list ); + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyInt_FromLong() failed" ); + } + PyList_SET_ITEM( list, count, tmp ); + ++count; + } + } + return list; +} + +static PyObject *MEdgeSeq_add_layertype(BPy_MEdgeSeq *self, PyObject *args) +{ + Mesh *me = (Mesh*)self->mesh; + return Mesh_addPropLayer_internal(me, &(me->edata), me->totedge, args); +} +static PyObject *MEdgeSeq_del_layertype(BPy_MEdgeSeq *self, PyObject *value) +{ + Mesh *me = (Mesh*)self->mesh; + return Mesh_removePropLayer_internal(me, &(me->edata), me->totedge, value); +} +static PyObject *MEdgeSeq_rename_layertype(BPy_MEdgeSeq *self, PyObject *args) +{ + Mesh *me = (Mesh*)self->mesh; + return Mesh_renamePropLayer_internal(me,&(me->edata),args); +} +static PyObject *MEdgeSeq_PropertyList(BPy_MEdgeSeq *self) +{ + Mesh *me = (Mesh*)self->mesh; + return Mesh_propList_internal(&(me->edata)); +} + + +static struct PyMethodDef BPy_MEdgeSeq_methods[] = { + {"extend", (PyCFunction)MEdgeSeq_extend, METH_VARARGS, + "add edges to mesh"}, + {"delete", (PyCFunction)MEdgeSeq_delete, METH_VARARGS, + "delete edges from mesh"}, + {"selected", (PyCFunction)MEdgeSeq_selected, METH_NOARGS, + "returns a list containing indices of selected edges"}, + {"collapse", (PyCFunction)MEdgeSeq_collapse, METH_VARARGS, + "collapse one or more edges to a vertex"}, + {"addPropertyLayer",(PyCFunction)MEdgeSeq_add_layertype, METH_VARARGS, + "add a new property layer"}, + {"removePropertyLayer",(PyCFunction)MEdgeSeq_del_layertype, METH_O, + "removes a property layer"}, + {"renamePropertyLayer",(PyCFunction)MEdgeSeq_rename_layertype, METH_VARARGS, + "renames an existing property layer"}, + + {NULL, NULL, 0, NULL} +}; +static PyGetSetDef BPy_MEdgeSeq_getseters[] = { + {"properties", + (getter)MEdgeSeq_PropertyList, (setter)NULL, + "edge property layers, read only", + NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + + +/************************************************************************ + * + * Python MEdgeSeq_Type standard operators + * + ************************************************************************/ + +/*****************************************************************************/ +/* Python MEdgeSeq_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject MEdgeSeq_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender MEdgeSeq", /* char *tp_name; */ + sizeof( BPy_MEdgeSeq ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + NULL, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + &MEdgeSeq_as_sequence, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + ( getiterfunc) MEdgeSeq_getIter, /* getiterfunc tp_iter; */ + ( iternextfunc ) MEdgeSeq_nextIter, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_MEdgeSeq_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_MEdgeSeq_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +/************************************************************************ + * + * Face attributes + * + ************************************************************************/ + +static MFace * MFace_get_pointer( BPy_MFace * self ) +{ + if( self->index >= self->mesh->totface ) + return (MFace *)EXPP_ReturnPyObjError( PyExc_RuntimeError, + "MFace is no longer valid" ); + return &self->mesh->mface[self->index]; +} + +/* + * get a face's vertices + */ + +static PyObject *MFace_getVerts( BPy_MFace * self ) +{ + PyObject *attr; + MFace *face = MFace_get_pointer( self ); + + if( !face ) + return NULL; + + attr = PyTuple_New( face->v4 ? 4 : 3 ); + + if( !attr ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyTuple_New() failed" ); + + PyTuple_SetItem( attr, 0, MVert_CreatePyObject( self->mesh, face->v1 ) ); + PyTuple_SetItem( attr, 1, MVert_CreatePyObject( self->mesh, face->v2 ) ); + PyTuple_SetItem( attr, 2, MVert_CreatePyObject( self->mesh, face->v3 ) ); + if( face->v4 ) + PyTuple_SetItem( attr, 3, MVert_CreatePyObject( self->mesh, + face->v4 ) ); + + return attr; +} + +/* + * set a face's vertices + */ + +static int MFace_setVerts( BPy_MFace * self, PyObject * args ) +{ + BPy_MVert *v1, *v2, *v3, *v4 = NULL; + MFace *face = MFace_get_pointer( self ); + + if( !face ) + return -1; + + if( !PyArg_ParseTuple ( args, "O!O!O!|O!", &MVert_Type, &v1, + &MVert_Type, &v2, &MVert_Type, &v3, &MVert_Type, &v4 ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected tuple of 3 or 4 MVerts" ); + + if( v1->index == v2->index || + v1->index == v3->index || + v2->index == v3->index ) + return EXPP_ReturnIntError( PyExc_ValueError, + "cannot assign 2 or move verts that are the same" ); + + if(v4 && ( v1->index == v4->index || + v2->index == v4->index || + v3->index == v4->index )) + return EXPP_ReturnIntError( PyExc_ValueError, + "cannot assign 2 or move verts that are the same" ); + + if( v1->index >= self->mesh->totvert || + v2->index >= self->mesh->totvert || + v3->index >= self->mesh->totvert || + (v4 &&( v4->index >= self->mesh->totvert))) + return EXPP_ReturnIntError( PyExc_ValueError, + "cannot assign verts that have been removed" ); + + face->v1 = v1->index; + face->v2 = v2->index; + face->v3 = v3->index; + if( v4 ) + face->v4 = v4->index; + return 0; +} + +/* + * get face's material index + */ + +static PyObject *MFace_getMat( BPy_MFace * self ) +{ + MFace *face = MFace_get_pointer( self ); + + if( !face ) + return NULL; + + return PyInt_FromLong( face->mat_nr ); +} + +/* + * set face's material index + */ + +static int MFace_setMat( BPy_MFace * self, PyObject * value ) +{ + MFace *face = MFace_get_pointer( self ); + + if( !face ) + return -1; /* error is set */ + + return EXPP_setIValueRange( value, &face->mat_nr, 0, 15, 'b' ); +} + +/* + * get a face's index + */ + +static PyObject *MFace_getIndex( BPy_MFace * self ) +{ + MFace *face = MFace_get_pointer( self ); + + if( !face ) + return NULL; /* error is set */ + + return PyInt_FromLong( self->index ); +} + +/* + * get face's normal index + */ + +static PyObject *MFace_getNormal( BPy_MFace * self ) +{ + float *vert[4]; + float no[3]; + MFace *face = MFace_get_pointer( self ); + + Mesh *me = self->mesh; + + if( !face ) + return NULL; /* error is set */ + + if MFACE_VERT_BADRANGE_CHECK(me, face) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "one or more MFace vertices are no longer valid" ); + + vert[0] = me->mvert[face->v1].co; + vert[1] = me->mvert[face->v2].co; + vert[2] = me->mvert[face->v3].co; + if( face->v4 ) { + vert[3] = me->mvert[face->v4].co; + CalcNormFloat4( vert[0], vert[1], vert[2], vert[3], no ); + } else + CalcNormFloat( vert[0], vert[1], vert[2], no ); + + return newVectorObject( no, 3, Py_NEW ); +} + +/* + * get face's center location + */ + +static PyObject *MFace_getCent( BPy_MFace * self ) +{ + float *vert[4]; + float cent[3]= {0,0,0}; + int i=3, j, k; + Mesh *me = self->mesh; + MFace *face = MFace_get_pointer( self ); + + if( !face ) + return NULL; /* error is set */ + + + if MFACE_VERT_BADRANGE_CHECK(me, face) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "one or more MFace vertices are no longer valid" ); + + vert[0] = me->mvert[face->v1].co; + vert[1] = me->mvert[face->v2].co; + vert[2] = me->mvert[face->v3].co; + if( face->v4 ) { + vert[3] = me->mvert[face->v4].co; + i=4; + } + + for (j=0;jmesh; + + if( !face ) + return NULL; /* error is set */ + + if MFACE_VERT_BADRANGE_CHECK(me, face) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "one or more MFace vertices are no longer valid" ); + + v1 = me->mvert[face->v1].co; + v2 = me->mvert[face->v2].co; + v3 = me->mvert[face->v3].co; + + if( face->v4 ) { + v4 = me->mvert[face->v4].co; + return PyFloat_FromDouble( AreaQ3Dfl(v1, v2, v3, v4)); + } else + return PyFloat_FromDouble( AreaT3Dfl(v1, v2, v3)); +} + +/* + * get one of a face's mface flag bits + */ + +static PyObject *MFace_getMFlagBits( BPy_MFace * self, void * type ) +{ + MFace *face = MFace_get_pointer( self ); + + if( !face ) + return NULL; /* error is set */ + + return EXPP_getBitfield( &face->flag, (int)((long)type & 0xff), 'b' ); +} + +/* + * set one of a face's mface flag bits + */ + +static int MFace_setMFlagBits( BPy_MFace * self, PyObject * value, + void * type ) +{ + MFace *face = MFace_get_pointer( self ); + + if( !face ) + return -1; /* error is set */ + + return EXPP_setBitfield( value, &face->flag, + (int)((long)type & 0xff), 'b' ); +} + +static int MFace_setSelect( BPy_MFace * self, PyObject * value, + void * type_unused ) +{ + MFace *face = MFace_get_pointer( self ); + int param = PyObject_IsTrue( value ); + Mesh *me; + + if( !face ) + return -1; /* error is set */ + + if( param == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected True/False or 0/1" ); + + me = self->mesh; + if( param ) { + face->flag |= ME_FACE_SEL; + me->mvert[face->v1].flag |= SELECT; + me->mvert[face->v2].flag |= SELECT; + me->mvert[face->v3].flag |= SELECT; + if( face->v4 ) + me->mvert[face->v4].flag |= SELECT; + } + else { + face->flag &= ~ME_FACE_SEL; + me->mvert[face->v1].flag &= ~SELECT; + me->mvert[face->v2].flag &= ~SELECT; + me->mvert[face->v3].flag &= ~SELECT; + if( face->v4 ) + me->mvert[face->v4].flag &= ~SELECT; + } + + if( self->mesh->mselect ) { + MEM_freeN( self->mesh->mselect ); + self->mesh->mselect = NULL; + } + + return 0; +} + +/* + * get face's texture image + */ + +static PyObject *MFace_getImage( BPy_MFace *self ) +{ + MTFace *face; + if( !self->mesh->mtface ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "face has no texture values" ); + + if( !MFace_get_pointer( self ) ) + return NULL; + + face = &self->mesh->mtface[self->index]; + + if( face->tpage ) + return Image_CreatePyObject( face->tpage ); + else + Py_RETURN_NONE; +} + +/* + * change or clear face's texture image + */ + +static int MFace_setImage( BPy_MFace *self, PyObject *value ) +{ + MTFace *face; + + if( !MFace_get_pointer( self ) ) + return -1; + + if( value && value != Py_None && !BPy_Image_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected image object or None" ); + + if( !self->mesh->mtface ) +#if 0 + return EXPP_ReturnIntError( PyExc_ValueError, + "face has no texture values" ); +#else + make_tfaces( self->mesh ); +#endif + + face = &self->mesh->mtface[self->index]; + + if( value == NULL || value == Py_None ) + face->tpage = NULL; /* should memory be freed? */ + else { + face->tpage = ( ( BPy_Image * ) value )->image; + face->mode |= TF_TEX; + } + + return 0; +} + +#define MFACE_FLAG_BITMASK ( TF_SELECT | TF_SEL1 | \ + TF_SEL2 | TF_SEL3 | TF_SEL4 | TF_HIDE ) + +/* +* get face's texture flag +*/ + +static PyObject *MFace_getFlag( BPy_MFace *self ) +{ + int flag; + if( !self->mesh->mtface ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "face has no texture values" ); + + if( !MFace_get_pointer( self ) ) + return NULL; + + flag = self->mesh->mtface[self->index].flag & MFACE_FLAG_BITMASK; + + /* so old scripts still work */ + if (self->index == self->mesh->act_face) + flag |= TF_ACTIVE; + + return PyInt_FromLong( (long)( flag ) ); +} + +/* + * set face's texture flag + */ + +static int MFace_setFlag( BPy_MFace *self, PyObject *value ) +{ + int param; + + if( !self->mesh->mtface ) + return EXPP_ReturnIntError( PyExc_ValueError, + "face has no texture values" ); + + if( !MFace_get_pointer( self ) ) + return -1; + + if( !PyInt_Check ( value ) ) { + char errstr[128]; + sprintf ( errstr , "expected int bitmask of 0x%04x", MFACE_FLAG_BITMASK ); + return EXPP_ReturnIntError( PyExc_TypeError, errstr ); + } + param = PyInt_AS_LONG ( value ); + + /* only one face can be active, so don't allow that here */ + if( param & TF_ACTIVE ) + param &= ~TF_ACTIVE; + + if( ( param & MFACE_FLAG_BITMASK ) != param ) + return EXPP_ReturnIntError( PyExc_ValueError, + "invalid bit(s) set in mask" ); + + /* merge active setting with other new params */ + param |= (self->mesh->mtface[self->index].flag); + self->mesh->mtface[self->index].flag = (char)param; + + return 0; +} + +/* + * get face's texture mode + */ + +static PyObject *MFace_getMode( BPy_MFace *self ) +{ + if( !self->mesh->mtface ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "face has no texture values" ); + + if( !MFace_get_pointer( self ) ) + return NULL; + + return PyInt_FromLong( self->mesh->mtface[self->index].mode ); +} + +/* + * set face's texture mode + */ + +static int MFace_setMode( BPy_MFace *self, PyObject *value ) +{ + int param; + static short bitmask = TF_DYNAMIC + | TF_TEX + | TF_SHAREDVERT + | TF_LIGHT + | TF_SHAREDCOL + | TF_TILES + | TF_BILLBOARD + | TF_TWOSIDE + | TF_INVISIBLE + | TF_OBCOL + | TF_BILLBOARD2 + | TF_SHADOW + | TF_BMFONT; + + if( !self->mesh->mtface ) + return EXPP_ReturnIntError( PyExc_ValueError, + "face has no texture values" ); + + if( !MFace_get_pointer( self ) ) + return -1; + + if( !PyInt_Check ( value ) ) { + char errstr[128]; + sprintf ( errstr , "expected int bitmask of 0x%04x", bitmask ); + return EXPP_ReturnIntError( PyExc_TypeError, errstr ); + } + param = PyInt_AS_LONG ( value ); + + if( param == 0xffff ) /* if param is ALL, set everything but HALO */ + param = bitmask ^ TF_BILLBOARD; + else if( ( param & bitmask ) != param ) + return EXPP_ReturnIntError( PyExc_ValueError, + "invalid bit(s) set in mask" ); + + /* Blender UI doesn't allow these on at the same time */ + + if( ( param & (TF_BILLBOARD | TF_BILLBOARD2) ) == + (TF_BILLBOARD | TF_BILLBOARD2) ) + return EXPP_ReturnIntError( PyExc_ValueError, + "HALO and BILLBOARD cannot be enabled simultaneously" ); + + self->mesh->mtface[self->index].mode = (short)param; + + return 0; +} + +/* + * get face's texture transparency setting + */ + +static PyObject *MFace_getTransp( BPy_MFace *self ) +{ + if( !self->mesh->mtface ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "face has no texture values" ); + + if( !MFace_get_pointer( self ) ) + return NULL; + + return PyInt_FromLong( self->mesh->mtface[self->index].transp ); +} + +/* + * set face's texture transparency setting + */ + +static int MFace_setTransp( BPy_MFace *self, PyObject *value ) +{ + if( !self->mesh->mtface ) + return EXPP_ReturnIntError( PyExc_ValueError, + "face has no texture values" ); + + if( !MFace_get_pointer( self ) ) + return -1; + + return EXPP_setIValueRange( value, + &self->mesh->mtface[self->index].transp, TF_SOLID, TF_SUB, 'b' ); +} + +/* + * get a face's texture UV coord values + */ + +static PyObject *MFace_getUV( BPy_MFace * self ) +{ + MTFace *face; + PyObject *attr; + int length, i; + + if( !self->mesh->mtface ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "face has no texture values" ); + + if( !MFace_get_pointer( self ) ) + return NULL; + + face = &self->mesh->mtface[self->index]; + length = self->mesh->mface[self->index].v4 ? 4 : 3; + attr = PyTuple_New( length ); + + if( !attr ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyTuple_New() failed" ); + + for( i=0; iuv[i], 2, Py_WRAP ); + if( !vector ) + return NULL; + PyTuple_SetItem( attr, i, vector ); + } + + return attr; +} + +/* + * set a face's texture UV coord values + */ + +static int MFace_setUV( BPy_MFace * self, PyObject * value ) +{ + MTFace *face; + int length, i; + + if( !MFace_get_pointer( self ) ) + return -1; + + if( !PySequence_Check( value ) || + EXPP_check_sequence_consistency( value, &vector_Type ) != 1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected sequence of vectors" ); + + length = self->mesh->mface[self->index].v4 ? 4 : 3; + if( length != PySequence_Size( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "size of vertex and UV sequences differ" ); + + if( !self->mesh->mtface ) +#if 0 + return EXPP_ReturnIntError( PyExc_ValueError, + "face has no texture values" ); +#else + make_tfaces( self->mesh ); +#endif + + face = &self->mesh->mtface[self->index]; + for( i=0; iuv[i][0] = vector->vec[0]; + face->uv[i][1] = vector->vec[1]; + Py_DECREF( vector ); + } + return 0; +} + +/* + * get a face's texture UV coord select state + */ + +static PyObject *MFace_getUVSel( BPy_MFace * self ) +{ + MTFace *face; + PyObject *attr; + int length, i, mask; + + if( !self->mesh->mtface ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "face has no texture values" ); + + if( !MFace_get_pointer( self ) ) + return NULL; + + face = &self->mesh->mtface[self->index]; + length = self->mesh->mface[self->index].v4 ? 4 : 3; + attr = PyTuple_New( length ); + + if( !attr ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyTuple_New() failed" ); + + /* get coord select state, one bit at a time */ + mask = TF_SEL1; + for( i=0; iflag & mask ? 1 : 0 ); + if( !value ) { + Py_DECREF( attr ); + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyInt_FromLong() failed" ); + } + PyTuple_SetItem( attr, i, value ); + } + + return attr; +} + +/* + * set a face's texture UV coord select state + */ + +static int MFace_setUVSel( BPy_MFace * self, PyObject * value ) +{ + MTFace *face; + int length, i, mask; + + if( !MFace_get_pointer( self ) ) + return -1; + + if( !PySequence_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a tuple of integers" ); + + length = self->mesh->mface[self->index].v4 ? 4 : 3; + if( length != PySequence_Size( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "size of vertex and UV lists differ" ); + + if( !self->mesh->mtface ) +#if 0 + return EXPP_ReturnIntError( PyExc_ValueError, + "face has no texture values" ); +#else + make_tfaces( self->mesh ); +#endif + + /* set coord select state, one bit at a time */ + face = &self->mesh->mtface[self->index]; + mask = TF_SEL1; + for( i=0; iflag |= mask; + else + face->flag &= ~mask; + Py_DECREF(tmp); + } + return 0; +} + +/* + * get a face's vertex colors. note that if mesh->mtfaces is defined, then + * it takes precedent over mesh->mcol + */ + +static PyObject *MFace_getCol( BPy_MFace * self ) +{ + PyObject *attr; + int length, i; + MCol * mcol; + + /* if there's no mesh color vectors or texture faces, nothing to do */ + + if( !self->mesh->mcol ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "face has no vertex colors" ); + + if( !MFace_get_pointer( self ) ) + return NULL; + + mcol = &self->mesh->mcol[self->index*4]; + + length = self->mesh->mface[self->index].v4 ? 4 : 3; + attr = PyTuple_New( length ); + + if( !attr ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyTuple_New() failed" ); + + for( i=0; imesh->mcol ) + return EXPP_ReturnIntError( PyExc_ValueError, + "face has no vertex colors" ); + + if( !MFace_get_pointer( self ) ) + return -1; + + mcol = &self->mesh->mcol[self->index*4]; + + length = self->mesh->mface[self->index].v4 ? 4 : 3; + + if( !PyList_Check( value ) && !PyTuple_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a sequence of MCols" ); + + if( EXPP_check_sequence_consistency( value, &MCol_Type ) != 1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a sequence of MCols" ); + + if( PySequence_Size( value ) != length ) + return EXPP_ReturnIntError( PyExc_ValueError, + "incorrect number of colors for this face" ); + + for( i=0; icolor->r; + mcol[i].g = obj->color->g; + mcol[i].b = obj->color->b; + mcol[i].a = obj->color->a; + Py_DECREF( obj ); + } + return 0; +} + + +/* + * get edge keys for using in a dictionary or set key + */ + +static PyObject *MFace_getEdgeKeys( BPy_MFace * self ) +{ + MFace *face = MFace_get_pointer( self ); + PyObject *attr, *edpair; + + if (!face) + return NULL; /* error set */ + + if (face->v4) { + attr = PyTuple_New( 4 ); + edpair = PyTuple_New( 2 ); + if (face->v1 > face->v2) { + PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v2) ); + PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v1) ); + } else { + PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v1) ); + PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v2) ); + } + PyTuple_SET_ITEM( attr, 0, edpair ); + + edpair = PyTuple_New( 2 ); + if (face->v2 > face->v3) { + PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v3) ); + PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v2) ); + } else { + PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v2) ); + PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v3) ); + } + PyTuple_SET_ITEM( attr, 1, edpair ); + + edpair = PyTuple_New( 2 ); + if (face->v3 > face->v4) { + PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v4) ); + PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v3) ); + } else { + PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v3) ); + PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v4) ); + } + PyTuple_SET_ITEM( attr, 2, edpair ); + + edpair = PyTuple_New( 2 ); + if (face->v4 > face->v1) { + PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v1) ); + PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v4) ); + } else { + PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v4) ); + PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v1) ); + } + PyTuple_SET_ITEM( attr, 3, edpair ); + + } else { + + attr = PyTuple_New( 3 ); + edpair = PyTuple_New( 2 ); + if (face->v1 > face->v2) { + PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v2) ); + PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v1) ); + } else { + PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v1) ); + PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v2) ); + } + PyTuple_SET_ITEM( attr, 0, edpair ); + + edpair = PyTuple_New( 2 ); + if (face->v2 > face->v3) { + PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v3) ); + PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v2) ); + } else { + PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v2) ); + PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v3) ); + } + PyTuple_SET_ITEM( attr, 1, edpair ); + + edpair = PyTuple_New( 2 ); + if (face->v3 > face->v1) { + PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v1) ); + PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v3) ); + } else { + PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v3) ); + PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v1) ); + } + PyTuple_SET_ITEM( attr, 2, edpair ); + } + + return attr; +} + + +/************************************************************************ + * + * Python MFace_Type attributes get/set structure + * + ************************************************************************/ + +static PyGetSetDef BPy_MFace_getseters[] = { + {"verts", + (getter)MFace_getVerts, (setter)MFace_setVerts, + "face's vertices", + NULL}, + {"v", + (getter)MFace_getVerts, (setter)MFace_setVerts, + "deprecated: see 'verts'", + NULL}, + {"mat", + (getter)MFace_getMat, (setter)MFace_setMat, + "face's material index", + NULL}, + {"index", + (getter)MFace_getIndex, (setter)NULL, + "face's index", + NULL}, + {"no", + (getter)MFace_getNormal, (setter)NULL, + "face's normal", + NULL}, + {"cent", + (getter)MFace_getCent, (setter)NULL, + "face's center", + NULL}, + {"area", + (getter)MFace_getArea, (setter)NULL, + "face's 3D area", + NULL}, + + {"hide", + (getter)MFace_getMFlagBits, (setter)MFace_setMFlagBits, + "face hidden in edit mode", + (void *)ME_HIDE}, + {"sel", + (getter)MFace_getMFlagBits, (setter)MFace_setSelect, + "face selected in edit mode", + (void *)ME_FACE_SEL}, + {"smooth", + (getter)MFace_getMFlagBits, (setter)MFace_setMFlagBits, + "face smooth enabled", + (void *)ME_SMOOTH}, + + /* attributes for texture faces (mostly, I think) */ + + {"col", + (getter)MFace_getCol, (setter)MFace_setCol, + "face's vertex colors", + NULL}, + {"flag", + (getter)MFace_getFlag, (setter)MFace_setFlag, + "flags associated with texture faces", + NULL}, + {"image", + (getter)MFace_getImage, (setter)MFace_setImage, + "image associated with texture faces", + NULL}, + {"mode", + (getter)MFace_getMode, (setter)MFace_setMode, + "modes associated with texture faces", + NULL}, + {"transp", + (getter)MFace_getTransp, (setter)MFace_setTransp, + "transparency of texture faces", + NULL}, + {"uv", + (getter)MFace_getUV, (setter)MFace_setUV, + "face's UV coordinates", + NULL}, + {"uvSel", + (getter)MFace_getUVSel, (setter)MFace_setUVSel, + "face's UV coordinates select status", + NULL}, + {"edge_keys", + (getter)MFace_getEdgeKeys, (setter)NULL, + "for each edge this face uses return an ordered tuple edge pair that can be used as a key in a dictionary or set", + NULL}, + + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/************************************************************************ + * + * Python MFace_Type iterator (iterates over vertices) + * + ************************************************************************/ + +/* + * Initialize the interator index + */ + +static PyObject *MFace_getIter( BPy_MFace * self ) +{ + if (self->iter==-1) { + self->iter = 0; + return EXPP_incr_ret ( (PyObject *) self ); + } else { + BPy_MFace *seq= (BPy_MFace *)MFace_CreatePyObject(self->mesh, self->index); + seq->iter = 0; + return (PyObject *) seq; + } +} + +/* + * Return next MVert. Throw an exception after the final vertex. + */ + +static PyObject *MFace_nextIter( BPy_MFace * self ) +{ + struct MFace *face = &self->mesh->mface[self->index]; + int len = self->mesh->mface[self->index].v4 ? 4 : 3; + + if( self->iter == len ) { + self->iter = -1; + return EXPP_ReturnPyObjError( PyExc_StopIteration, + "iterator at end" ); + } + + ++self->iter; + switch ( self->iter ) { + case 1: + return MVert_CreatePyObject( self->mesh, face->v1 ); + case 2: + return MVert_CreatePyObject( self->mesh, face->v2 ); + case 3: + return MVert_CreatePyObject( self->mesh, face->v3 ); + default : + return MVert_CreatePyObject( self->mesh, face->v4 ); + } +} + +/************************************************************************ + * + * Python MFace_Type methods + * + ************************************************************************/ + +/************************************************************************ + * + * Python MFace_Type standard operations + * + ************************************************************************/ +static int MFace_compare( BPy_MFace * a, BPy_MFace * b ) +{ + return( a->mesh == b->mesh && a->index == b->index ) ? 0 : -1; +} + +static PyObject *MFace_repr( BPy_MFace* self ) +{ + MFace *face = MFace_get_pointer( self ); + + if( !face ) + return NULL; + + if( face->v4 ) + return PyString_FromFormat( "[MFace (%d %d %d %d) %d]", + (int)face->v1, (int)face->v2, + (int)face->v3, (int)face->v4, (int)self->index ); + else + return PyString_FromFormat( "[MFace (%d %d %d) %d]", + (int)face->v1, (int)face->v2, + (int)face->v3, (int)self->index ); +} + +static long MFace_hash( BPy_MFace *self ) +{ + return (long)self->index; +} + +static int MFace_len( BPy_MFace * self ) +{ + if( self->index >= self->mesh->totface ) + return 0; + return self->mesh->mface[self->index].v4 ? 4 : 3; +} + +static PySequenceMethods MFace_as_sequence = { + ( inquiry ) MFace_len, /* sq_length */ + ( binaryfunc ) 0, /* sq_concat */ + ( intargfunc ) 0, /* sq_repeat */ + ( intargfunc ) 0, /* sq_item */ + ( intintargfunc ) 0, /* sq_slice */ + ( intobjargproc ) 0, /* sq_ass_item */ + ( intintobjargproc ) 0, /* sq_ass_slice */ + 0,0,0, +}; + +static PyObject *MFace_getProp( BPy_MFace *self, PyObject *args) +{ + Mesh *me = (Mesh *)self->mesh; + MFace *face = MFace_get_pointer( self ); + if( !face ) + return NULL; + mesh_update_customdata_pointers(me); //! + return Mesh_getProperty_internal(&(me->fdata), self->index, args); +} + +static PyObject *MFace_setProp( BPy_MFace *self, PyObject *args) +{ + Mesh *me = (Mesh *)self->mesh; + PyObject *obj; + MFace *face = MFace_get_pointer( self ); + if( !face ) + return NULL; /* error set */ + + obj = Mesh_setProperty_internal(&(me->fdata), self->index, args); + mesh_update_customdata_pointers(me); //! + return obj; +} + +static struct PyMethodDef BPy_MFace_methods[] = { + {"getProperty", (PyCFunction)MFace_getProp, METH_O, + "get property indicated by name"}, + {"setProperty", (PyCFunction)MFace_setProp, METH_VARARGS, + "set property indicated by name"}, + {NULL, NULL, 0, NULL} +}; +/************************************************************************ + * + * Python MFace_Type structure definition + * + ************************************************************************/ + +PyTypeObject MFace_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender MFace", /* char *tp_name; */ + sizeof( BPy_MFace ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) MFace_compare, /* cmpfunc tp_compare; */ + ( reprfunc ) MFace_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + &MFace_as_sequence, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + ( hashfunc ) MFace_hash, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + ( getiterfunc ) MFace_getIter, /* getiterfunc tp_iter; */ + ( iternextfunc ) MFace_nextIter, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_MFace_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_MFace_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +static PyObject *MFace_CreatePyObject( Mesh * mesh, int i ) +{ + BPy_MFace *obj = PyObject_NEW( BPy_MFace, &MFace_Type ); + + if( !obj ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyObject_New() failed" ); + + obj->mesh = mesh; + obj->index = i; + obj->iter= -1; + return (PyObject *)obj; +} + +/************************************************************************ + * + * Face sequence + * + ************************************************************************/ + +static int MFaceSeq_len( BPy_MFaceSeq * self ) +{ + return self->mesh->totface; +} + +static PyObject *MFaceSeq_item( BPy_MFaceSeq * self, int i ) +{ + if( i < 0 || i >= self->mesh->totface ) + return EXPP_ReturnPyObjError( PyExc_IndexError, + "array index out of range" ); + + return MFace_CreatePyObject( self->mesh, i ); +} + +static PySequenceMethods MFaceSeq_as_sequence = { + ( inquiry ) MFaceSeq_len, /* sq_length */ + ( binaryfunc ) 0, /* sq_concat */ + ( intargfunc ) 0, /* sq_repeat */ + ( intargfunc ) MFaceSeq_item, /* sq_item */ + ( intintargfunc ) 0, /* sq_slice */ + ( intobjargproc ) 0, /* sq_ass_item */ + ( intintobjargproc ) 0, /* sq_ass_slice */ + 0,0,0, +}; + +/************************************************************************ + * + * Python MFaceSeq_Type iterator (iterates over faces) + * + ************************************************************************/ + +/* + * Initialize the interator index + */ + +static PyObject *MFaceSeq_getIter( BPy_MFaceSeq * self ) +{ + if (self->iter==-1) { + self->iter = 0; + return EXPP_incr_ret ( (PyObject *) self ); + } else { + BPy_MFaceSeq *seq = (BPy_MFaceSeq *)MFaceSeq_CreatePyObject(self->mesh); + seq->iter = 0; + return (PyObject *)seq; + } +} + +/* + * Return next MFace. + */ + +static PyObject *MFaceSeq_nextIter( BPy_MFaceSeq * self ) +{ + if( self->iter == self->mesh->totface ) { + self->iter= -1; /* not being used in a seq */ + return EXPP_ReturnPyObjError( PyExc_StopIteration, + "iterator at end" ); + } + return MFace_CreatePyObject( self->mesh, self->iter++ ); +} + +/************************************************************************ + * + * Python MFaceSeq_Type methods + * + ************************************************************************/ + +static PyObject *MFaceSeq_extend( BPy_MEdgeSeq * self, PyObject *args, + PyObject *keywds ) +{ + /* + * (a) check input for valid edge objects, faces which consist of + * only three or four edges + * (b) check input to be sure edges form a closed face (each edge + * contains verts in two other different edges?) + * + * (1) build list of new faces; remove duplicates + * * use existing "v4=0 rule" for 3-vert faces + * (2) build list of existing faces for searching + * (3) from new face list, remove existing faces: + */ + + int len, nverts; + int i, j, k, new_face_count; + int good_faces; + SrchFaces *oldpair, *newpair, *tmppair, *tmppair2; + PyObject *tmp; + MFace *tmpface; + Mesh *mesh = self->mesh; + int ignore_dups = 0; + PyObject *return_list = NULL; + + /* before we try to add faces, add edges; if it fails; exit */ + + tmp = MEdgeSeq_extend( self, args ); + if( !tmp ) + return NULL; + Py_DECREF( tmp ); + + /* process any keyword arguments */ + if( keywds ) { + PyObject *res = PyDict_GetItemString( keywds, "ignoreDups" ); + if( res ) { + ignore_dups = PyObject_IsTrue( res ); + if (ignore_dups==-1) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "keyword argument \"ignoreDups\" expected True/False or 0/1" ); + } + } + res = PyDict_GetItemString( keywds, "indexList" ); + if (res) { + switch( PyObject_IsTrue( res ) ) { + case 0: + break; + case -1: + return EXPP_ReturnPyObjError( PyExc_TypeError, + "keyword argument \"indexList\" expected True/False or 0/1" ); + default: + return_list = PyList_New( 0 ); + } + } + } + + /* make sure we get a tuple of sequences of something */ + + switch( PySequence_Size( args ) ) { + case 1: /* better be a sequence or a tuple */ + /* if a sequence... */ + tmp = PyTuple_GET_ITEM( args, 0 ); + if( PySequence_Check( tmp ) ) { + PyObject *tmp2; + + /* ignore empty sequences */ + if( !PySequence_Size( tmp ) ) { + Py_RETURN_NONE; + } + + /* if another sequence, use it */ + tmp2 = PySequence_ITEM( tmp, 0 ); + if( PySequence_Check( tmp2 ) ) + args = tmp; + Py_INCREF( args ); + Py_DECREF( tmp2 ); + } else + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a sequence of sequence pairs" ); + break; + case 2: + case 3: + case 4: /* two to four args may be individual verts */ + tmp = PyTuple_GET_ITEM( args, 0 ); + /* + * if first item isn't a sequence, then assume it's a bunch of MVerts + * and wrap inside a tuple + */ + if( !PySequence_Check( tmp ) ) { + args = Py_BuildValue( "(O)", args ); + if( !args ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Py_BuildValue() failed" ); + /* + * otherwise, assume it already a bunch of sequences so use as-is + */ + } else { + Py_INCREF( args ); /* so we can safely DECREF later */ + } + break; + default: /* anything else is definitely wrong */ + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a sequence of sequence pairs" ); + } + + /* if nothing to add, just exit */ + len = PySequence_Size( args ); + if( len == 0 ) { + Py_DECREF( args ); + Py_RETURN_NONE; + } + + /* + * Since we call MEdgeSeq_extend first, we already know the input list + * is valid. Here we just need to count the total number of faces. + */ + + new_face_count = 0; + for( i = 0; i < len; ++i ) { + tmp = PySequence_ITEM( args, i ); + nverts = PySequence_Size( tmp ); + if( return_list || nverts != 2 ) + ++new_face_count; /* new faces must have 3 or 4 verts */ + Py_DECREF( tmp ); + } + + /* OK, commit to allocating the search structures */ + newpair = (SrchFaces *)MEM_callocN( sizeof(SrchFaces)*new_face_count, + "MFacePairs" ); + + /* scan the input list and build the new face pair list */ + len = PySequence_Size( args ); + tmppair = newpair; + + for( i = 0; i < len; ++i ) { + MFace tmpface; + unsigned int vert[4]={0,0,0,0}; + unsigned char order[4]={0,1,2,3}; + tmp = PySequence_GetItem( args, i ); + nverts = PySequence_Size( tmp ); + + if( nverts == 2 ) { /* again, ignore 2-vert tuples */ + if( return_list ) /* if returning indices, mark as deleted */ + tmppair->v[1] = 0; + Py_DECREF( tmp ); + continue; + } + + /* + * get the face's vertices' indexes + */ + + for( j = 0; j < nverts; ++j ) { + PyObject *item = PySequence_ITEM( tmp, j ); + if( BPy_MVert_Check( item ) ) + vert[j] = ((BPy_MVert *)item)->index; + else + vert[j] = PyInt_AsLong( item ); + Py_DECREF( item ); + } + Py_DECREF( tmp ); + tmpface.v1 = vert[0]; + tmpface.v2 = vert[1]; + tmpface.v3 = vert[2]; + tmpface.v4 = vert[3]; + + /* + * go through some contortions to guarantee the third and fourth + * vertices are not index 0 + */ + eeek_fix( &tmpface, nverts == 4 ); + vert[0] = tmpface.v1; + vert[1] = tmpface.v2; + vert[2] = tmpface.v3; + if( nverts == 3 ) + vert[3] = tmppair->v[3] = 0; + else + vert[3] = tmpface.v4; + + /* + * sort the verts before placing in pair list. the order of + * vertices in the face is very important, so keep track of + * the original order + */ + + for( j = nverts-1; j >= 0; --j ) { + for( k = 0; k < j; ++k ) { + if( vert[k] > vert[k+1] ) { + SWAP( int, vert[k], vert[k+1] ); + SWAP( char, order[k], order[k+1] ); + } else if( vert[k] == vert[k+1] ) { + break; + } + } + if( k < j ) + break; + tmppair->v[j] = vert[j]; + } + if( j >= 0 ) { /* a duplicate vertex found */ + if( return_list ) { /* if returning index list */ + tmppair->v[1] = 0; /* mark as deleted */ + } else { + --new_face_count; /* otherwise skip */ + continue; + } + } + tmppair->index = i; + + /* pack order into a byte */ + tmppair->order = order[0]|(order[1]<<2)|(order[2]<<4)|(order[3]<<6); + ++tmppair; + } + + /* + * find duplicates in the new list and mark. if it's a duplicate, + * then mark by setting second vert index to 0 (a real edge won't have + * second vert index of 0 since verts are sorted) + */ + + good_faces = new_face_count; /* assume all faces good to start */ + + tmppair = newpair; /* "last good edge" */ + tmppair2 = &tmppair[1]; /* "current candidate edge" */ + if( !ignore_dups ) { + + /* sort the new face pairs */ + qsort( newpair, new_face_count, sizeof(SrchFaces), mface_comp ); + + for( i = 0; i < new_face_count; ++i ) { + if( mface_comp( tmppair, tmppair2 ) ) + tmppair = tmppair2; /* last != current, so current == last */ + else { + tmppair2->v[1] = 0; /* last == current, so mark as duplicate */ + --good_faces; /* one less good face */ + } + tmppair2++; + } + } + + /* if mesh has faces, see if any of the new faces are already in it */ + if( mesh->totface && !ignore_dups ) { + oldpair = (SrchFaces *)MEM_callocN( sizeof(SrchFaces)*mesh->totface, + "MFacePairs" ); + + tmppair = oldpair; + tmpface = mesh->mface; + for( i = 0; i < mesh->totface; ++i ) { + unsigned char order[4]={0,1,2,3}; + int verts[4]; + verts[0]=tmpface->v1; + verts[1]=tmpface->v2; + verts[2]=tmpface->v3; + verts[3]=tmpface->v4; + + len = ( tmpface->v4 ) ? 3 : 2; + tmppair->v[3] = 0; /* for triangular faces */ + + /* sort the verts before placing in pair list here too */ + for( j = len; j >= 0; --j ) { + for( k = 0; k < j; ++k ) + if( verts[k] > verts[k+1] ) { + SWAP( int, verts[k], verts[k+1] ); + SWAP( unsigned char, order[k], order[k+1] ); + } + tmppair->v[j] = verts[j]; + } + + /* pack order into a byte */ + tmppair->order = order[0]|(order[1]<<2)|(order[2]<<4)|(order[3]<<6); + ++tmppair; + ++tmpface; + } + + /* sort the old face pairs */ + qsort( oldpair, mesh->totface, sizeof(SrchFaces), mface_comp ); + + /* eliminate new faces already in the mesh */ + tmppair = newpair; + for( i = good_faces; i ; ) { + if( tmppair->v[1] ) { + if( bsearch( tmppair, oldpair, mesh->totface, + sizeof(SrchFaces), mface_comp ) ) { + tmppair->v[1] = 0; /* mark as duplicate */ + --good_faces; + } + --i; + } + tmppair++; + } + MEM_freeN( oldpair ); + } + + /* if any new faces are left, add to list */ + if( good_faces || return_list ) { + int totface = mesh->totface+good_faces; /* new face count */ + CustomData fdata; + + CustomData_copy( &mesh->fdata, &fdata, CD_MASK_MESH, CD_DEFAULT, totface ); + CustomData_copy_data( &mesh->fdata, &fdata, 0, 0, mesh->totface ); + + if ( !CustomData_has_layer( &fdata, CD_MFACE ) ) + CustomData_add_layer( &fdata, CD_MFACE, CD_CALLOC, NULL, totface ); + + CustomData_free( &mesh->fdata, mesh->totface ); + mesh->fdata = fdata; + mesh_update_customdata_pointers( mesh ); + + /* sort the faces back into their original input list order */ + if( !ignore_dups ) + qsort( newpair, new_face_count, sizeof(SrchFaces), + mface_index_comp ); + + + /* point to the first face we're going to add */ + tmpface = &mesh->mface[mesh->totface]; + tmppair = newpair; + + if( return_list ) + good_faces = new_face_count; /* assume all faces good to start */ + + /* as we find a good face, add it */ + while ( good_faces ) { + if( tmppair->v[1] ) { + int i; + unsigned int index[4]; + unsigned char order = tmppair->order; + + /* unpack the order of the vertices */ + for( i = 0; i < 4; ++i ) { + index[(order & 0x03)] = i; + order >>= 2; + } + + /* now place vertices in the proper order */ + tmpface->v1 = tmppair->v[index[0]]; + tmpface->v2 = tmppair->v[index[1]]; + tmpface->v3 = tmppair->v[index[2]]; + tmpface->v4 = tmppair->v[index[3]]; + + tmpface->flag = ME_FACE_SEL; + + if( return_list ) { + tmp = PyInt_FromLong( mesh->totface ); + PyList_Append( return_list, tmp ); + Py_DECREF(tmp); + } + mesh->totface++; + ++tmpface; + --good_faces; + } else if( return_list ) { + PyList_Append( return_list, Py_None ); + --good_faces; + } + tmppair++; + } + } + + /* clean up and leave */ + mesh_update( mesh ); + Py_DECREF ( args ); + MEM_freeN( newpair ); + + if( return_list ) + return return_list; + else + Py_RETURN_NONE; +} + +struct fourEdges +{ + FaceEdges *v[4]; +}; + +static PyObject *MFaceSeq_delete( BPy_MFaceSeq * self, PyObject *args ) +{ + unsigned int *face_table; + int i, len; + Mesh *mesh = self->mesh; + MFace *tmpface; + int face_count; + int edge_also = 0; + + /* check for valid inputs */ + + if( PySequence_Size( args ) != 2 || + !PyArg_ParseTuple( args, "iO", &edge_also, &args ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected and int and a sequence of ints or MFaces" ); + + if( !PyList_Check( args ) && !PyTuple_Check( args ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected and int and a sequence of ints or MFaces" ); + + /* see how many args we need to parse */ + len = PySequence_Size( args ); + if( len < 1 ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "sequence must contain at least one int or MFace" ); + + face_table = (unsigned int *)MEM_callocN( len*sizeof( unsigned int ), + "face_table" ); + + /* get the indices of faces to be removed */ + for( i = len; i--; ) { + PyObject *tmp = PySequence_GetItem( args, i ); + if( BPy_MFace_Check( tmp ) ) + face_table[i] = ((BPy_MFace *)tmp)->index; + else if( PyInt_Check( tmp ) ) + face_table[i] = PyInt_AsLong( tmp ); + else { + MEM_freeN( face_table ); + Py_DECREF( tmp ); + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a sequence of ints or MFaces" ); + } + Py_DECREF( tmp ); + + /* if index out-of-range, throw exception */ + if( face_table[i] >= (unsigned int)mesh->totface ) { + MEM_freeN( face_table ); + return EXPP_ReturnPyObjError( PyExc_ValueError, + "array index out of range" ); + } + } + + if( edge_also ) { + /* + * long version + * + * (1) build sorted table of all edges + * (2) construct face->edge lookup table for all faces + * face->e1 = mesh->medge[i] + * (3) (delete sorted table) + * (4) mark all edges as live + * (5) mark all edges for deleted faces as dead + * (6) mark all edges for remaining faces as live + * (7) delete all dead edges + * (8) (delete face lookup table) + * + */ + + FaceEdges *edge_table, *tmp_et; + MEdge *tmpedge; + FaceEdges **face_edges; + FaceEdges **tmp_fe; + struct fourEdges *fface; + int edge_count; + + edge_table = MEM_mallocN( mesh->totedge*sizeof( FaceEdges ), + "edge_table" ); + + tmpedge = mesh->medge; + tmp_et = edge_table; + + for( i = 0; i < mesh->totedge; ++i ) { + if( tmpedge->v1 < tmpedge->v2 ) { + tmp_et->v[0] = tmpedge->v1; + tmp_et->v[1] = tmpedge->v2; + } else { + tmp_et->v[0] = tmpedge->v2; + tmp_et->v[1] = tmpedge->v1; + } + tmp_et->index = i; + tmp_et->sel = 1; /* select each edge */ + ++tmpedge; + ++tmp_et; + } + + /* sort the edge pairs */ + qsort( edge_table, mesh->totedge, sizeof(FaceEdges), faceedge_comp ); + + /* build face translation table, lookup edges */ + face_edges = MEM_callocN( 4*sizeof(FaceEdges*)*mesh->totface, + "face_edges" ); + + tmp_fe = face_edges; + tmpface = mesh->mface; + for( i = mesh->totface; i--; ++tmpface ) { + FaceEdges *ptrs[4]; + unsigned int verts[4]; + int j,k; + FaceEdges target; + int len=tmpface->v4 ? 4 : 3; + + ptrs[3] = NULL; + verts[0] = tmpface->v1; + verts[1] = tmpface->v2; + verts[2] = tmpface->v3; + if( len == 4 ) + verts[3] = tmpface->v4; + for( j = 0; j < len; ++j ) { + k = (j+1) % len; + if( verts[j] < verts[k] ) { + target.v[0] = verts[j]; + target.v[1] = verts[k]; + } else { + target.v[0] = verts[k]; + target.v[1] = verts[j]; + } + ptrs[j] = bsearch( &target, edge_table, mesh->totedge, + sizeof(FaceEdges), faceedge_comp ); + } + for( j = 0; j < 4; ++j, ++tmp_fe ) + *tmp_fe = ptrs[j]; + } + + /* for each face, deselect each edge */ + tmpface = mesh->mface; + face_count = 0; + for( i = len; i--; ) { + if( tmpface[face_table[i]].v1 != UINT_MAX ) { + fface = (void *)face_edges; + fface += face_table[i]; + fface->v[0]->sel = 0; + fface->v[1]->sel = 0; + fface->v[2]->sel = 0; + if( fface->v[3] ) + fface->v[3]->sel = 0; + tmpface[face_table[i]].v1 = UINT_MAX; + ++face_count; + } + } + + /* for each face, deselect each edge */ + tmpface = mesh->mface; + fface = (struct fourEdges *)face_edges; + for( i = mesh->totface; i--; ++tmpface, ++fface ) { + if( tmpface->v1 != UINT_MAX ) { + FaceEdges (*face)[4]; + face = (void *)face_edges; + face += face_table[i]; + fface->v[0]->sel = 1; + fface->v[1]->sel = 1; + fface->v[2]->sel = 1; + if( fface->v[3] ) + fface->v[3]->sel = 1; + } + } + + /* now mark the selected edges for deletion */ + + edge_count = 0; + for( i = 0; i < mesh->totedge; ++i ) { + if( !edge_table[i].sel ) { + mesh->medge[edge_table[i].index].v1 = UINT_MAX; + ++edge_count; + } + } + + if( edge_count ) + delete_edges( mesh, NULL, edge_count ); + + MEM_freeN( face_edges ); + MEM_freeN( edge_table ); + } else { + /* mark faces to delete */ + tmpface = mesh->mface; + face_count = 0; + for( i = len; i--; ) + if( tmpface[face_table[i]].v1 != UINT_MAX ) { + tmpface[face_table[i]].v1 = UINT_MAX; + ++face_count; + } + } + + /* delete faces which have a deleted edge */ + delete_faces( mesh, NULL, face_count ); + + /* clean up and return */ + MEM_freeN( face_table ); + mesh_update ( mesh ); + Py_RETURN_NONE; +} + +/* copied from meshtools.c - should make generic? */ +static void permutate(void *list, int num, int size, int *index) +{ + void *buf; + int len; + int i; + + len = num * size; + + buf = MEM_mallocN(len, "permutate"); + memcpy(buf, list, len); + + for (i = 0; i < num; i++) { + memcpy((char *)list + (i * size), (char *)buf + (index[i] * size), size); + } + MEM_freeN(buf); +} + +/* this wrapps list sorting then applies back to the mesh */ +static PyObject *MFaceSeq_sort( BPy_MEdgeSeq * self, PyObject *args, + PyObject *keywds ) +{ + PyObject *ret, *sort_func, *newargs; + + Mesh *mesh = self->mesh; + PyObject *sorting_list; + CustomDataLayer *layer; + int i, *index; + + /* get a list for internal use */ + sorting_list = PySequence_List( (PyObject *)self ); + if( !sorting_list ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyList_New() failed" ); + + /* create index list */ + index = (int *) MEM_mallocN(sizeof(int) * mesh->totface, "sort faces"); + if (!index) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "faces.sort(...) failed to allocate memory" ); + + newargs = EXPP_PyTuple_New_Prepend(args, sorting_list); + sort_func = PyObject_GetAttrString( ((PyObject *)&PyList_Type), "sort"); + + ret = PyObject_Call(sort_func, newargs, keywds); + + Py_DECREF(newargs); + Py_DECREF(sort_func); + + if (ret) { + /* copy the faces indicies to index */ + for (i = 0; i < mesh->totface; i++) + index[i] = ((BPy_MFace *)PyList_GET_ITEM(sorting_list, i))->index; + + for(i = 0; i < mesh->fdata.totlayer; i++) { + layer = &mesh->fdata.layers[i]; + permutate(layer->data, mesh->totface, CustomData_sizeof(layer->type), index); + } + } + Py_DECREF(sorting_list); + MEM_freeN(index); + return ret; +} + +static PyObject *MFaceSeq_selected( BPy_MFaceSeq * self ) +{ + int i, count; + Mesh *mesh = self->mesh; + MFace *tmpface; + PyObject *list; + + /* first count selected faces (quicker than appending to PyList?) */ + count = 0; + tmpface = mesh->mface; + for( i = 0; i < mesh->totface; ++i, ++tmpface ) + if( tmpface->flag & ME_FACE_SEL ) + ++count; + + list = PyList_New( count ); + if( !list ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyList_New() failed" ); + + /* next, insert selected faces into list */ + count = 0; + tmpface = mesh->mface; + for( i = 0; i < mesh->totface; ++i, ++tmpface ) { + if( tmpface->flag & ME_FACE_SEL ) { + PyObject *tmp = PyInt_FromLong( i ); + if( !tmp ) { + Py_DECREF( list ); + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyInt_FromLong() failed" ); + } + PyList_SET_ITEM( list, count, tmp ); + ++count; + } + } + return list; +} + +static PyObject *MFaceSeq_add_layertype(BPy_MFaceSeq *self, PyObject *args) +{ + Mesh *me = (Mesh*)self->mesh; + return Mesh_addPropLayer_internal(me, &(me->fdata), me->totface, args); +} +static PyObject *MFaceSeq_del_layertype(BPy_MFaceSeq *self, PyObject *value) +{ + Mesh *me = (Mesh*)self->mesh; + return Mesh_removePropLayer_internal(me, &(me->fdata), me->totface, value); +} +static PyObject *MFaceSeq_rename_layertype(BPy_MFaceSeq *self, PyObject *args) +{ + Mesh *me = (Mesh*)self->mesh; + return Mesh_renamePropLayer_internal(me,&(me->fdata),args); +} +static PyObject *MFaceSeq_PropertyList(BPy_MFaceSeq *self) +{ + Mesh *me = (Mesh*)self->mesh; + return Mesh_propList_internal(&(me->fdata)); +} + +static struct PyMethodDef BPy_MFaceSeq_methods[] = { + {"extend", (PyCFunction)MFaceSeq_extend, METH_VARARGS|METH_KEYWORDS, + "add faces to mesh"}, + {"delete", (PyCFunction)MFaceSeq_delete, METH_VARARGS, + "delete faces from mesh"}, + {"sort", (PyCFunction)MFaceSeq_sort, METH_VARARGS|METH_KEYWORDS, + "sort the faces using list sorts syntax"}, + {"selected", (PyCFunction)MFaceSeq_selected, METH_NOARGS, + "returns a list containing indices of selected faces"}, + {"addPropertyLayer",(PyCFunction)MFaceSeq_add_layertype, METH_VARARGS, + "add a new property layer"}, + {"removePropertyLayer",(PyCFunction)MFaceSeq_del_layertype, METH_O, + "removes a property layer"}, + {"renamePropertyLayer",(PyCFunction)MFaceSeq_rename_layertype, METH_VARARGS, + "renames an existing property layer"}, + {NULL, NULL, 0, NULL} +}; +static PyGetSetDef BPy_MFaceSeq_getseters[] = { + {"properties", + (getter)MFaceSeq_PropertyList, (setter)NULL, + "vertex property layers, read only", + NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + + +/************************************************************************ + * + * Python MFaceSeq_Type standard operations + * + ************************************************************************/ + +/*****************************************************************************/ +/* Python MFaceSeq_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject MFaceSeq_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender MFaceSeq", /* char *tp_name; */ + sizeof( BPy_MFaceSeq ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + NULL, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + &MFaceSeq_as_sequence, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + ( getiterfunc )MFaceSeq_getIter, /* getiterfunc tp_iter; */ + ( iternextfunc )MFaceSeq_nextIter, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_MFaceSeq_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_MFaceSeq_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +/************************************************************************ + * + * Python BPy_Mesh methods + * + ************************************************************************/ + +static PyObject *Mesh_calcNormals( BPy_Mesh * self ) +{ + Mesh *mesh = self->mesh; + + mesh_calc_normals( mesh->mvert, mesh->totvert, mesh->mface, + mesh->totface, NULL ); + Py_RETURN_NONE; +} + +static PyObject *Mesh_vertexShade( BPy_Mesh * self ) +{ + Base *base = FIRSTBASE; + + if( G.obedit ) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "can't shade vertices while in edit mode" ); + + while( base ) { + if( base->object->type == OB_MESH && + base->object->data == self->mesh ) { + base->flag |= SELECT; + set_active_base( base ); + make_vertexcol(1); + countall(); + Py_RETURN_NONE; + } + base = base->next; + } + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "object not found in baselist!" ); +} + +/* + * force display list update + */ + +static PyObject *Mesh_Update( BPy_Mesh * self, PyObject *args, PyObject *kwd ) +{ + + char *blockname= NULL; + static char *kwlist[] = {"key", NULL}; + + if( !PyArg_ParseTupleAndKeywords(args, kwd, "|s", kwlist, &blockname) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "Expected nothing or the name of a shapeKey"); + + if (blockname) { + Mesh *me = self->mesh; + MVert *mv = me->mvert; + Key *key= me->key; + KeyBlock *kb; + float (*co)[3]; + int i; + + if (!key) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Cannot update the key for this mesh, it has no shape keys"); + + for (kb = key->block.first; kb; kb=kb->next) + if (strcmp(blockname, kb->name)==0) + break; + + if (!kb) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "This requested key to update does not exist"); + + for(i=0, co= kb->data; itotvert; i++, mv++, co++) + VECCOPY(*co, mv->co); + } else { + /* Normal operation */ + mesh_update( self->mesh ); + } + Py_RETURN_NONE; +} + +/* + * search for a single edge in mesh's edge list + */ + +static PyObject *Mesh_findEdge( BPy_Mesh * self, PyObject *args ) +{ + int i; + unsigned int v1, v2; + PyObject *tmp; + MEdge *edge = self->mesh->medge; + + if( EXPP_check_sequence_consistency( args, &MVert_Type ) == 1 && + PySequence_Size( args ) == 2 ) { + tmp = PyTuple_GET_ITEM( args, 0 ); + v1 = ((BPy_MVert *)tmp)->index; + tmp = PyTuple_GET_ITEM( args, 1 ); + v2 = ((BPy_MVert *)tmp)->index; + } else if( PyArg_ParseTuple( args, "ii", &v1, &v2 ) ) { + if( (int)v1 >= self->mesh->totvert || (int)v2 >= self->mesh->totvert ) + return EXPP_ReturnPyObjError( PyExc_IndexError, + "index out of range" ); + } else + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "expected tuple of two ints or MVerts" ); + + for( i = 0; i < self->mesh->totedge; ++i ) { + if( ( edge->v1 == v1 && edge->v2 == v2 ) + || ( edge->v1 == v2 && edge->v2 == v1 ) ) { + tmp = PyInt_FromLong( i ); + if( tmp ) + return tmp; + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyInt_FromLong() failed" ); + } + ++edge; + } + Py_RETURN_NONE; +} + +/* + * search for a group of edges in mesh's edge list + */ + +static PyObject *Mesh_findEdges( PyObject * self, PyObject *args ) +{ + int len; + int i; + SrchEdges *oldpair, *tmppair, target, *result; + PyObject *list, *tmp; + BPy_MVert *v1, *v2; + unsigned int index1, index2; + MEdge *tmpedge; + Mesh *mesh = ((BPy_Mesh *)self)->mesh; + + /* if no edges, nothing to do */ + + if( !mesh->totedge ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "mesh has no edges" ); + + /* make sure we get a sequence of tuples of something */ + + tmp = PyTuple_GET_ITEM( args, 0 ); + switch( PySequence_Size ( args ) ) { + case 1: /* better be a list or a tuple */ + if( !PySequence_Check ( tmp ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a sequence of tuple int or MVert pairs" ); + args = tmp; + Py_INCREF( args ); /* so we can safely DECREF later */ + break; + case 2: /* take any two args and put into a tuple */ + if( PyTuple_Check( tmp ) ) + Py_INCREF( args ); /* if first arg is a tuple, assume both are */ + else { + args = Py_BuildValue( "((OO))", tmp, PyTuple_GET_ITEM( args, 1 ) ); + if( !args ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Py_BuildValue() failed" ); + } + break; + default: /* anything else is definitely wrong */ + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a sequence of tuple pairs" ); + } + + len = PySequence_Size( args ); + if( len == 0 ) { + Py_DECREF( args ); + return EXPP_ReturnPyObjError( PyExc_ValueError, + "expected at least one tuple" ); + } + + /* if a single edge, handle the simpler way */ + if( len == 1 ) { + PyObject *result; + tmp = PySequence_GetItem( args, 0 ); + result = Mesh_findEdge( (BPy_Mesh *)self, tmp ); + Py_DECREF( tmp ); + Py_DECREF( args ); + return result; + } + + /* build a list of all edges so we can search */ + oldpair = (SrchEdges *)MEM_callocN( sizeof(SrchEdges)*mesh->totedge, + "MEdgePairs" ); + + tmppair = oldpair; + tmpedge = mesh->medge; + for( i = 0; i < mesh->totedge; ++i ) { + if( tmpedge->v1 < tmpedge->v2 ) { + tmppair->v[0] = tmpedge->v1; + tmppair->v[1] = tmpedge->v2; + } else { + tmppair->v[0] = tmpedge->v2; + tmppair->v[1] = tmpedge->v1; + } + tmppair->index = i; + ++tmpedge; + ++tmppair; + } + + /* sort the old edge pairs */ + qsort( oldpair, mesh->totedge, sizeof(SrchEdges), medge_comp ); + + list = PyList_New( len ); + if( !len ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyList_New() failed" ); + + /* scan the input list, find vert pairs, then search the edge list */ + + for( i = 0; i < len; ++i ) { + tmp = PySequence_GetItem( args, i ); + if( !PyTuple_Check( tmp ) || PyTuple_Size( tmp ) != 2 ) { + MEM_freeN( oldpair ); + Py_DECREF( tmp ); + Py_DECREF( args ); + Py_DECREF( list ); + return EXPP_ReturnPyObjError( PyExc_ValueError, + "expected tuple pair" ); + } + + /* get objects, check that they are both MVerts of this mesh */ + v1 = (BPy_MVert *)PyTuple_GET_ITEM( tmp, 0 ); + v2 = (BPy_MVert *)PyTuple_GET_ITEM( tmp, 1 ); + Py_DECREF ( tmp ); + if( BPy_MVert_Check( v1 ) && BPy_MVert_Check( v2 ) ) { + if( v1->data != (void *)mesh || v2->data != (void *)mesh ) { + MEM_freeN( oldpair ); + Py_DECREF( args ); + Py_DECREF( list ); + return EXPP_ReturnPyObjError( PyExc_ValueError, + "one or both MVerts do not belong to this mesh" ); + } + index1 = v1->index; + index2 = v2->index; + } else if( PyInt_Check( v1 ) && PyInt_Check( v2 ) ) { + index1 = PyInt_AsLong( (PyObject *)v1 ); + index2 = PyInt_AsLong( (PyObject *)v2 ); + if( (int)index1 >= mesh->totvert + || (int)index2 >= mesh->totvert ) { + MEM_freeN( oldpair ); + Py_DECREF( args ); + Py_DECREF( list ); + return EXPP_ReturnPyObjError( PyExc_IndexError, + "index out of range" ); + } + } else { + MEM_freeN( oldpair ); + Py_DECREF( args ); + Py_DECREF( list ); + return EXPP_ReturnPyObjError( PyExc_ValueError, + "expected tuple to contain MVerts" ); + } + + /* sort verts into order */ + if( index1 < index2 ) { + target.v[0] = index1; + target.v[1] = index2; + } else { + target.v[0] = index2; + target.v[1] = index1; + } + + /* search edge list for a match; result is index or None */ + result = bsearch( &target, oldpair, mesh->totedge, + sizeof(SrchEdges), medge_comp ); + if( result ) + tmp = PyInt_FromLong( result->index ); + else + tmp = EXPP_incr_ret( Py_None ); + if( !tmp ) { + MEM_freeN( oldpair ); + Py_DECREF( args ); + Py_DECREF( list ); + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyInt_FromLong() failed" ); + } + PyList_SET_ITEM( list, i, tmp ); + } + + MEM_freeN( oldpair ); + Py_DECREF ( args ); + return list; +} + +/* + * replace mesh data with mesh data from another object + */ + + +static PyObject *Mesh_getFromObject( BPy_Mesh * self, PyObject * args ) +{ + Object *ob = NULL; + PyObject *object_arg; + ID tmpid; + Mesh *tmpmesh; + Curve *tmpcu = NULL; + DerivedMesh *dm; + Object *tmpobj = NULL; + int cage = 0, render = 0, i; + + if( !PyArg_ParseTuple( args, "O|ii", &object_arg, &cage, &render ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected object or string and optional integer arguments" ); + + if ( PyString_Check( object_arg ) ) { + char *name; + name = PyString_AsString ( object_arg ); + ob = ( Object * ) GetIdFromList( &( G.main->object ), name ); + if( !ob ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, name ); + } else if ( BPy_Object_Check(object_arg) ) { + ob = (( BPy_Object * ) object_arg)->object; + } else { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected object or string and optional integer arguments" ); + } + + if( cage != 0 && cage != 1 ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "cage value must be 0 or 1" ); + + + + /* perform the mesh extraction based on type */ + switch (ob->type) { + case OB_FONT: + case OB_CURVE: + case OB_SURF: + /* copies object and modifiers (but not the data) */ + tmpobj= copy_object( ob ); + tmpcu = (Curve *)tmpobj->data; + tmpcu->id.us--; + + /* if getting the original caged mesh, delete object modifiers */ + if( cage ) + object_free_modifiers(tmpobj); + + /* copies the data */ + tmpobj->data = copy_curve( (Curve *) ob->data ); + +#if 0 + /* copy_curve() sets disp.first null, so currently not need */ + { + Curve *cu; + cu = (Curve *)tmpobj->data; + if( cu->disp.first ) + MEM_freeN( cu->disp.first ); + cu->disp.first = NULL; + } + +#endif + + /* get updated display list, and convert to a mesh */ + makeDispListCurveTypes( tmpobj, 0 ); + nurbs_to_mesh( tmpobj ); + + /* nurbs_to_mesh changes the type tp a mesh, check it worked */ + if (tmpobj->type != OB_MESH) { + free_libblock_us( &G.main->object, tmpobj ); + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "cant convert curve to mesh. Does the curve have any segments?" ); + } + tmpmesh = tmpobj->data; + free_libblock_us( &G.main->object, tmpobj ); + break; + case OB_MBALL: + /* metaballs don't have modifiers, so just convert to mesh */ + ob = find_basis_mball( ob ); + tmpmesh = add_mesh("Mesh"); + mball_to_mesh( &ob->disp, tmpmesh ); + + break; + case OB_MESH: + /* copies object and modifiers (but not the data) */ + if (cage) { + /* copies the data */ + tmpmesh = copy_mesh( ob->data ); + /* if not getting the original caged mesh, get final derived mesh */ + } else { + /* Make a dummy mesh, saves copying */ + + /* Write the display mesh into the dummy mesh */ + if (render) + dm = mesh_create_derived_render( ob, CD_MASK_MESH ); + else + dm = mesh_create_derived_view( ob, CD_MASK_MESH ); + + tmpmesh = add_mesh( "Mesh" ); + DM_to_mesh( dm, tmpmesh ); + dm->release( dm ); + } + + break; + default: + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "Object does not have geometry data" ); + } + + /* free mesh data in the original */ + free_mesh( self->mesh ); + /* save a copy of our ID, dup the temporary mesh, restore the ID */ + tmpid = self->mesh->id; + memcpy( self->mesh, tmpmesh, sizeof( Mesh ) ); + self->mesh->id = tmpid; + + /* if mesh has keys, make sure they point back to this mesh */ + if( self->mesh->key ) + self->mesh->key->from = (ID *)self->mesh; + + + + /* Copy materials to new object */ + switch (ob->type) { + case OB_SURF: + self->mesh->totcol = tmpcu->totcol; + + /* free old material list (if it exists) and adjust user counts */ + if( tmpcu->mat ) { + for( i = tmpcu->totcol; i-- > 0; ) { + + /* are we an object material or data based? */ + if (ob->colbits & 1<mesh->mat[i] = ob->mat[i]; + ob->mat[i]->id.us++; + tmpmesh->mat[i]->id.us--; + } else { + self->mesh->mat[i] = tmpcu->mat[i]; + if (self->mesh->mat[i]) { + tmpmesh->mat[i]->id.us++; + } + } + } + } + break; + +#if 0 + /* Crashes when assigning the new material, not sure why */ + case OB_MBALL: + tmpmb = (MetaBall *)ob->data; + self->mesh->totcol = tmpmb->totcol; + + /* free old material list (if it exists) and adjust user counts */ + if( tmpmb->mat ) { + for( i = tmpmb->totcol; i-- > 0; ) { + self->mesh->mat[i] = tmpmb->mat[i]; /* CRASH HERE ??? */ + if (self->mesh->mat[i]) { + tmpmb->mat[i]->id.us++; + } + } + } + break; +#endif + + case OB_MESH: + if (!cage) { + Mesh *origmesh= ob->data; + self->mesh->flag= origmesh->flag; + self->mesh->mat = MEM_dupallocN(origmesh->mat); + self->mesh->totcol = origmesh->totcol; + self->mesh->smoothresh= origmesh->smoothresh; + if( origmesh->mat ) { + for( i = origmesh->totcol; i-- > 0; ) { + /* are we an object material or data based? */ + if (ob->colbits & 1<mesh->mat[i] = ob->mat[i]; + + if (ob->mat[i]) + ob->mat[i]->id.us++; + if (origmesh->mat[i]) + origmesh->mat[i]->id.us--; + } else { + self->mesh->mat[i] = origmesh->mat[i]; + + if (origmesh->mat[i]) + origmesh->mat[i]->id.us++; + } + } + } + } + break; + } /* end copy materials */ + + + + /* remove the temporary mesh */ + BLI_remlink( &G.main->mesh, tmpmesh ); + MEM_freeN( tmpmesh ); + + /* make sure materials get updated in objects */ + test_object_materials( ( ID * ) self->mesh ); + + mesh_update( self->mesh ); + Py_RETURN_NONE; +} + +/* + * apply a transform to the mesh's vertices + * + * WARNING: unlike NMesh, this method ALWAYS changes the original mesh + */ + +static PyObject *Mesh_transform( BPy_Mesh *self, PyObject *args, PyObject *kwd ) +{ + Mesh *mesh = self->mesh; + MVert *mvert; + /*PyObject *pymat = NULL;*/ + MatrixObject *bpymat=NULL; + int i, recalc_normals = 0, selected_only = 0; + + static char *kwlist[] = {"matrix", "recalc_normals", "selected_only", NULL}; + + if( !PyArg_ParseTupleAndKeywords(args, kwd, "|O!ii", kwlist, + &matrix_Type, &bpymat, &recalc_normals, &selected_only) ) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "matrix must be a 4x4 transformation matrix\n" + "for example as returned by object.matrixWorld\n" + "and optionaly keyword bools, recalc_normals and selected_only\n"); + } + + if (!bpymat) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "the first argument must be a matrix or\n" + "matrix passed as a keyword argument\n"); + + + /*bpymat = ( MatrixObject * ) pymat;*/ + + if( bpymat->colSize != 4 || bpymat->rowSize != 4 ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "matrix must be a 4x4 transformation matrix\n" + "for example as returned by object.getMatrix()" ); + + /* loop through all the verts and transform by the supplied matrix */ + mvert = mesh->mvert; + if (selected_only) { + for( i = 0; i < mesh->totvert; i++, mvert++ ) { + if (mvert->flag & SELECT) { + Mat4MulVecfl( (float(*)[4])*bpymat->matrix, mvert->co ); + } + } + } else { + for( i = 0; i < mesh->totvert; i++, mvert++ ) { + Mat4MulVecfl( (float(*)[4])*bpymat->matrix, mvert->co ); + } + } + + if( recalc_normals ) { + /* loop through all the verts and transform normals by the inverse + * of the transpose of the supplied matrix */ + float invmat[4][4], vec[3], nx, ny, nz; + + /* + * we only need to invert a 3x3 submatrix, because the 4th component of + * affine vectors is 0, but Mat4Invert reports non invertible matrices + */ + + if (!Mat4Invert((float(*)[4])*invmat, (float(*)[4])*bpymat->matrix)) + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "given matrix is not invertible"); + + /* + * since normal is stored as shorts, convert to float + */ + + mvert = mesh->mvert; + for( i = 0; i < mesh->totvert; i++, mvert++ ) { + nx= vec[0] = (float)(mvert->no[0] / 32767.0); + ny= vec[1] = (float)(mvert->no[1] / 32767.0); + nz= vec[2] = (float)(mvert->no[2] / 32767.0); + vec[0] = nx*invmat[0][0] + ny*invmat[0][1] + nz*invmat[0][2]; + vec[1] = nx*invmat[1][0] + ny*invmat[1][1] + nz*invmat[1][2]; + vec[2] = nx*invmat[2][0] + ny*invmat[2][1] + nz*invmat[2][2]; + Normalize( vec ); + mvert->no[0] = (short)(vec[0] * 32767.0); + mvert->no[1] = (short)(vec[1] * 32767.0); + mvert->no[2] = (short)(vec[2] * 32767.0); + } + } + + Py_RETURN_NONE; +} + +static PyObject *Mesh_addVertGroup( PyObject * self, PyObject * value ) +{ + char *groupStr = PyString_AsString(value); + struct Object *object; + + if( !groupStr ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + + object = ( ( BPy_Mesh * ) self )->object; + + if( object == NULL ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "mesh not linked to an object" ); + + /* add_defgroup_name clamps the name to 32, make sure that dosnt change */ + add_defgroup_name( object, groupStr ); + + EXPP_allqueue( REDRAWBUTSALL, 1 ); + + Py_RETURN_NONE; +} + +static PyObject *Mesh_removeVertGroup( PyObject * self, PyObject * value ) +{ + char *groupStr = PyString_AsString(value); + struct Object *object; + int nIndex; + bDeformGroup *pGroup; + + if( !groupStr ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + + if( ( ( BPy_Mesh * ) self )->object == NULL ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "mesh must be linked to an object first..." ); + + object = ( ( BPy_Mesh * ) self )->object; + + pGroup = get_named_vertexgroup( object, groupStr ); + if( pGroup == NULL ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "group does not exist!" ); + + nIndex = get_defgroup_num( object, pGroup ); + if( nIndex == -1 ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "no deform groups assigned to mesh" ); + nIndex++; + object->actdef = (unsigned short)nIndex; + + del_defgroup( object ); + + EXPP_allqueue( REDRAWBUTSALL, 1 ); + + Py_RETURN_NONE; +} + +extern void add_vert_defnr( Object * ob, int def_nr, int vertnum, float weight, + int assignmode ); +extern void remove_vert_def_nr (Object *ob, int def_nr, int vertnum); + +static PyObject *Mesh_assignVertsToGroup( BPy_Mesh * self, PyObject * args ) +{ + char *groupStr; + int nIndex; + bDeformGroup *pGroup; + PyObject *listObject; + int tempInt; + int x; + int assignmode = WEIGHT_REPLACE; + float weight = 1.0; + Object *object = self->object; + Mesh *mesh = self->mesh; + + if( !object ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "mesh must be linked to an object first" ); + + if( ((Mesh *)object->data) != mesh ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "object no longer linked to this mesh" ); + + if( !PyArg_ParseTuple ( args, "sO!fi", &groupStr, &PyList_Type, + &listObject, &weight, &assignmode) ) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string, list, float, string arguments" ); + } + + pGroup = get_named_vertexgroup( object, groupStr ); + if( pGroup == NULL ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "group does not exist!" ); + + nIndex = get_defgroup_num( object, pGroup ); + if( nIndex == -1 ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "no deform groups assigned to mesh" ); + + + if( assignmode != WEIGHT_REPLACE && assignmode != WEIGHT_ADD && + assignmode != WEIGHT_SUBTRACT ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "bad assignment mode" ); + + /* makes a set of dVerts corresponding to the mVerts */ + if( !mesh->dvert ) + create_dverts( &mesh->id ); + + /* loop list adding verts to group */ + for( x = 0; x < PyList_Size( listObject ); x++ ) { + if( !PyArg_Parse ( PyList_GetItem( listObject, x ), "i", &tempInt ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "python list integer not parseable" ); + + if( tempInt < 0 || tempInt >= mesh->totvert ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "bad vertex index in list" ); + + add_vert_defnr( object, nIndex, tempInt, weight, assignmode ); + } + + Py_RETURN_NONE; +} + +static PyObject *Mesh_removeVertsFromGroup( BPy_Mesh * self, PyObject * args ) +{ + /* not passing a list will remove all verts from group */ + + char *groupStr; + int nIndex; + Object *object; + Mesh *mesh; + bDeformGroup *pGroup; + PyObject *listObject = NULL; + int tempInt; + int i; + + object = self->object; + mesh = self->mesh; + if( !object ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "mesh must be linked to an object first" ); + + if( ((Mesh *)object->data) != mesh ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "object no longer linked to this mesh" ); + + if( !PyArg_ParseTuple + ( args, "s|O!", &groupStr, &PyList_Type, &listObject ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string and optional list argument" ); + + if( !mesh->dvert ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "this mesh contains no deform vertices" ); + + pGroup = get_named_vertexgroup( object, groupStr ); + if( pGroup == NULL ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "group does not exist!" ); + + nIndex = get_defgroup_num( object, pGroup ); + if( nIndex == -1 ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "no deform groups assigned to mesh" ); + + /* get out of edit mode */ + + if( G.obedit ) { + load_editMesh(); + free_editMesh(G.editMesh); + G.obedit = NULL; + } + + if( !listObject ) /* no list given */ + for( i = 0; i < mesh->totvert; i++ ) + remove_vert_def_nr( object, nIndex, i ); + else /* loop list removing verts to group */ + for( i = 0; i < PyList_Size( listObject ); i++ ) { + if( !PyArg_Parse( PyList_GetItem( listObject, i ), "i", &tempInt ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "python list integer not parseable" ); + + if( tempInt < 0 || tempInt >= mesh->totvert ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "bad vertex index in list" ); + + remove_vert_def_nr( object, nIndex, tempInt ); + } + + Py_RETURN_NONE; +} + +static PyObject *Mesh_getVertsFromGroup( BPy_Mesh* self, PyObject * args ) +{ + /* + * not passing a list will return all verts from group + * passing indecies not part of the group will not return data in pyList + * can be used as a index/group check for a vertex + */ + + char *groupStr; + int nIndex; + bDeformGroup *pGroup; + MDeformVert *dvert; + int i, k, count; + PyObject *vertexList; + Object *object; + Mesh *mesh; + + int num = 0; + int weightRet = 0; + PyObject *listObject = NULL; + + object = self->object; + mesh = self->mesh; + if( !object ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "mesh must be linked to an object first" ); + + if( ((Mesh *)object->data) != mesh ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "object no longer linked to this mesh" ); + + if( !PyArg_ParseTuple( args, "s|iO!", &groupStr, &weightRet, + &PyList_Type, &listObject ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string and optional int and list arguments" ); + + if( weightRet < 0 || weightRet > 1 ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "return weights flag must be 0 or 1" ); + + if( !mesh->dvert ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "this mesh contains no deform vertices" ); + + pGroup = get_named_vertexgroup( object, groupStr ); + if( !pGroup ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "group does not exist!" ); + + nIndex = get_defgroup_num( object, pGroup ); + if( nIndex == -1 ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "no deform groups assigned to mesh" ); + + count = 0; + + if( !listObject ) { /* do entire group */ + vertexList = PyList_New( mesh->totvert ); + if( !vertexList ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "getVertsFromGroup: can't create pylist!" ); + + dvert = mesh->dvert; + for( num = 0; num < mesh->totvert; num++, ++dvert ) { + for( i = 0; i < dvert->totweight; i++ ) { + if( dvert->dw[i].def_nr == nIndex ) { + PyObject *attr; + if( weightRet ) + attr = Py_BuildValue( "(i,f)", num, + dvert->dw[i].weight ); + else + attr = PyInt_FromLong ( num ); + PyList_SetItem( vertexList, count, attr ); + count++; + } + } + } + + if (count < mesh->totvert) + PyList_SetSlice(vertexList, count, mesh->totvert, NULL); + + } else { /* do individual vertices */ + int listObjectLen = PyList_Size( listObject ); + + vertexList = PyList_New( listObjectLen ); + for( i = 0; i < listObjectLen; i++ ) { + PyObject *attr = NULL; + + num = PyInt_AsLong( PyList_GetItem( listObject, i ) ); + if (num == -1) {/* -1 is an error AND an invalid range, we dont care which */ + Py_DECREF(vertexList); + return EXPP_ReturnPyObjError( PyExc_TypeError, + "python list integer not parseable" ); + } + + if( num < 0 || num >= mesh->totvert ) { + Py_DECREF(vertexList); + return EXPP_ReturnPyObjError( PyExc_ValueError, + "bad vertex index in list" ); + } + dvert = mesh->dvert + num; + for( k = 0; k < dvert->totweight; k++ ) { + if( dvert->dw[k].def_nr == nIndex ) { + if( weightRet ) + attr = Py_BuildValue( "(i,f)", num, + dvert->dw[k].weight ); + else + attr = PyInt_FromLong ( num ); + PyList_SetItem( vertexList, count, attr ); + count++; + } + } + } + if (count < listObjectLen) + PyList_SetSlice(vertexList, count, listObjectLen, NULL); + } + + return vertexList; +} + +static PyObject *Mesh_renameVertGroup( BPy_Mesh * self, PyObject * args ) +{ + char *oldGr = NULL; + char *newGr = NULL; + bDeformGroup *defGroup; + Object *object; + Mesh *mesh; + + object = self->object; + mesh = self->mesh; + if( !object ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "mesh must be linked to an object first" ); + + if( ((Mesh *)object->data) != mesh ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "object no longer linked to this mesh" ); + + if( !PyArg_ParseTuple( args, "ss", &oldGr, &newGr ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected two string arguments" ); + + defGroup = get_named_vertexgroup( object, oldGr ); + if( !defGroup ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't find the vertex group" ); + + PyOS_snprintf( defGroup->name, 32, newGr ); + unique_vertexgroup_name( defGroup, object ); + + Py_RETURN_NONE; +} + + + + +static PyObject *Mesh_getVertGroupNames( BPy_Mesh * self ) +{ + bDeformGroup *defGroup; + PyObject *list; + Object *obj = self->object; + Mesh *mesh = self->mesh; + int count; + + if( !obj ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "mesh must be linked to an object first" ); + + if( ((Mesh *)obj->data) != mesh ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "object no longer linked to this mesh" ); + + if( !obj ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This mesh must be linked to an object" ); + + count = 0; + for( defGroup = obj->defbase.first; defGroup; defGroup = defGroup->next ) + ++count; + + list = PyList_New( count ); + count = 0; + for( defGroup = obj->defbase.first; defGroup; defGroup = defGroup->next ) + PyList_SET_ITEM( list, count++, + PyString_FromString( defGroup->name ) ); + + return list; +} + +static PyObject *Mesh_getVertexInfluences( BPy_Mesh * self, PyObject * args ) +{ + int index; + PyObject *influence_list = NULL; + Object *object = self->object; + Mesh *me = self->mesh; + + /* Get a reference to the mesh object wrapped in here. */ + if( !object ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This mesh must be linked to an object" ); + + /* Parse the parameters: only on integer (vertex index) */ + if( !PyArg_ParseTuple( args, "i", &index ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument (index of the vertex)" ); + + /* check for valid index */ + if( index < 0 || index >= me->totvert ) + return EXPP_ReturnPyObjError( PyExc_IndexError, + "vertex index out of range" ); + + influence_list = PyList_New( 0 ); + + /* Proceed only if we have vertex deformation information */ + if( me->dvert ) { + int i; + MDeformWeight *sweight = NULL; + + /* Number of bones influencing the vertex */ + int totinfluences = me->dvert[index].totweight; + + /* Get the reference of the first weight structure */ + sweight = me->dvert[index].dw; + + /* Build the list only with weights and names of the influent bones */ + for( i = 0; i < totinfluences; i++, sweight++ ) { + bDeformGroup *defgroup = BLI_findlink( &object->defbase, + sweight->def_nr ); + if( defgroup ) + PyList_Append( influence_list, Py_BuildValue( "[sf]", + defgroup->name, sweight->weight ) ); + } + } + + return influence_list; +} + +static PyObject *Mesh_removeAllKeys( BPy_Mesh * self ) +{ + Mesh *mesh = self->mesh; + + if( !mesh || !mesh->key ) + Py_RETURN_FALSE; + + mesh->key->id.us--; + mesh->key = NULL; + + Py_RETURN_TRUE; +} + + +static PyObject *Mesh_insertKey( BPy_Mesh * self, PyObject * args ) +{ + Mesh *mesh = self->mesh; + int fra = -1, oldfra = -1; + char *type = NULL; + short typenum; + + if (mesh->mr) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Shape Keys cannot be added to meshes with multires" ); + + if( !PyArg_ParseTuple( args, "|is", &fra, &type ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected nothing or an int and optionally a string as arguments" ); + + if( !type || !strcmp( type, "relative" ) ) + typenum = 1; + else if( !strcmp( type, "absolute" ) ) + typenum = 2; + else + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "if given, type should be 'relative' or 'absolute'" ); + + if( fra > 0 ) { + fra = EXPP_ClampInt( fra, 1, MAXFRAME ); + oldfra = G.scene->r.cfra; + G.scene->r.cfra = fra; + } + + insert_meshkey( mesh, typenum ); + allspace(REMAKEIPO, 0); + + if( fra > 0 ) + G.scene->r.cfra = oldfra; + + Py_RETURN_NONE; +} + + + + +/* Custom Data Layers */ + +static PyObject * Mesh_addCustomLayer_internal(Mesh *me, PyObject * args, int type) +{ + char *name = NULL; + CustomData *data = &me->fdata; + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a string or nothing" ); + + if (strlen(name)>31) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "error, maximum name length is 31" ); + + if (name) + CustomData_add_layer_named(data, type, CD_DEFAULT, + NULL, me->totface, name); + else + CustomData_add_layer(data, type, CD_DEFAULT, + NULL, me->totface); + mesh_update_customdata_pointers(me); + Py_RETURN_NONE; +} + +static PyObject *Mesh_addUVLayer( BPy_Mesh * self, PyObject * args ) +{ + return Mesh_addCustomLayer_internal(self->mesh, args, CD_MTFACE); +} + +static PyObject *Mesh_addColorLayer( BPy_Mesh * self, PyObject * args ) +{ + return Mesh_addCustomLayer_internal(self->mesh, args, CD_MCOL); +} + +static PyObject *Mesh_removeLayer_internal( BPy_Mesh * self, PyObject * value, int type ) +{ + Mesh *me = self->mesh; + CustomData *data = &me->fdata; + char *name = PyString_AsString(value); + int i; + + if( !name ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + + if (strlen(name)>31) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "error, maximum name length is 31" ); + + i = CustomData_get_named_layer_index(data, type, name); + + if (i==-1) + return EXPP_ReturnPyObjError(PyExc_ValueError, + "No matching layers to remove" ); + + CustomData_free_layer(data, type, me->totface, i); + mesh_update_customdata_pointers(me); + + /* No more Color or UV layers left ? + switch modes if this is the active object */ + if (!CustomData_has_layer(data, type)) { + if (me == get_mesh(OBACT)) { + if(type == CD_MCOL && (G.f & G_VERTEXPAINT)) + G.f &= ~G_VERTEXPAINT; /* get out of vertexpaint mode */ + if(type == CD_MTFACE && (G.f & G_FACESELECT)) + G.f |= ~G_FACESELECT; /* get out of faceselect mode */ + } + } + + Py_RETURN_NONE; +} + + +static PyObject *Mesh_removeUVLayer( BPy_Mesh * self, PyObject * value ) +{ + return Mesh_removeLayer_internal(self, value, CD_MTFACE); +} + +static PyObject *Mesh_removeColorLayer( BPy_Mesh * self, PyObject * value ) +{ + return Mesh_removeLayer_internal(self, value, CD_MCOL); +} + + +static PyObject *Mesh_renameLayer_internal( BPy_Mesh * self, PyObject * args, int type ) +{ + CustomData *data; + CustomDataLayer *layer; + Mesh *mesh = self->mesh; + int i; + char *name_from, *name_to; + + data = &mesh->fdata; + + if( !PyArg_ParseTuple( args, "ss", &name_from, &name_to ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected 2 strings" ); + + if (strlen(name_from)>31 || strlen(name_to)>31) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "error, maximum name length is 31" ); + + i = CustomData_get_named_layer_index(data, type, name_from); + + if (i==-1) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "layer name was not found" ); + + layer = &data->layers[i]; + strcpy(layer->name, name_to); /* we alredy know the string sizes are under 32 */ + CustomData_set_layer_unique_name(data, i); + Py_RETURN_NONE; +} + +static PyObject *Mesh_renameUVLayer( BPy_Mesh * self, PyObject * args ) +{ + return Mesh_renameLayer_internal( self, args, CD_MTFACE ); +} + +static PyObject *Mesh_renameColorLayer( BPy_Mesh * self, PyObject * args ) +{ + return Mesh_renameLayer_internal( self, args, CD_MCOL ); +} + + +static PyObject *Mesh_getLayerNames_internal( BPy_Mesh * self, int type ) +{ + CustomData *data; + CustomDataLayer *layer; + PyObject *str, *list = PyList_New( 0 ); + Mesh *mesh = self->mesh; + int i; + data = &mesh->fdata; + + /* see if there is a duplicate */ + for(i=0; itotlayer; i++) { + layer = &data->layers[i]; + if(layer->type == type) { + str = PyString_FromString(layer->name); + PyList_Append( list, str ); + Py_DECREF(str); + } + } + return list; +} + +static PyObject *Mesh_getUVLayerNames( BPy_Mesh * self ) +{ + return Mesh_getLayerNames_internal(self, CD_MTFACE); +} + +static PyObject *Mesh_getColorLayerNames( BPy_Mesh * self ) +{ + return Mesh_getLayerNames_internal(self, CD_MCOL); +} +/* used by activeUVLayer and activeColorLayer attrs */ +static PyObject *Mesh_getActiveLayer( BPy_Mesh * self, void *type ) +{ + CustomData *data = &self->mesh->fdata; + int layer_type = (int)type; + int i; + if (layer_type < 0) { /* hack, if negative, its the renderlayer.*/ + layer_type = -layer_type; + i = CustomData_get_render_layer_index(data, layer_type); + } else { + i = CustomData_get_active_layer_index(data, layer_type); + } + if (i == -1) /* so -1 is for no active layer 0+ for an active layer */ + Py_RETURN_NONE; + else { + return PyString_FromString( data->layers[i].name); + } +} + +static int Mesh_setActiveLayer( BPy_Mesh * self, PyObject * value, void *type ) +{ + CustomData *data = &self->mesh->fdata; + char *name; + int i,ok,n,layer_type = (int)type, render=0; + + if( !PyString_Check( value ) ) + return EXPP_ReturnIntError( PyExc_ValueError, + "expected a string argument" ); + + if (layer_type<0) { + layer_type = -layer_type; + render = 1; + } + + name = PyString_AsString( value ); + ok = 0; + n = 0; + for(i=0; i < data->totlayer; ++i) { + if(data->layers[i].type == layer_type) { + if (strcmp(data->layers[i].name, name)==0) { + ok = 1; + break; + } + n++; + } + } + + if (!ok) + return EXPP_ReturnIntError( PyExc_ValueError, + "layer name does not exist" ); + if (render) { + CustomData_set_layer_render(data, layer_type, n); + } else { + CustomData_set_layer_active(data, layer_type, n); + mesh_update_customdata_pointers(self->mesh); + } + return 0; +} + + +/* multires */ +static PyObject *Mesh_getMultiresLevelCount( BPy_Mesh * self ) +{ + int i; + if (!self->mesh->mr) + i=0; + else + i= self->mesh->mr->level_count; + + return PyInt_FromLong(i); +} + + +static PyObject *Mesh_getMultires( BPy_Mesh * self, void *type ) +{ + int i=0; + if (self->mesh->mr) { + switch ((int)type) { + case MESH_MULTIRES_LEVEL: + i = self->mesh->mr->newlvl; + break; + case MESH_MULTIRES_EDGE: + i = self->mesh->mr->edgelvl; + break; + case MESH_MULTIRES_PIN: + i = self->mesh->mr->pinlvl; + break; + case MESH_MULTIRES_RENDER: + i = self->mesh->mr->renderlvl; + break; + } + } + + return PyInt_FromLong(i); +} + +static int Mesh_setMultires( BPy_Mesh * self, PyObject *value, void *type ) +{ + int i; + if( !PyInt_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected integer argument" ); + + if (!self->object) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "This mesh must be linked to an object" ); + + if (!self->mesh->mr) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "the mesh has no multires data" ); + + if (!self->mesh->mr->level_count) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "multires data has no levels added" ); + + i = PyInt_AsLong(value); + + if (i<1||i>self->mesh->mr->level_count) + return EXPP_ReturnIntError( PyExc_TypeError, + "value out of range" ); + + switch ((int)type) { + case MESH_MULTIRES_LEVEL: + self->mesh->mr->newlvl = i; + multires_set_level(self->object, self->mesh, 0); + break; + case MESH_MULTIRES_EDGE: + self->mesh->mr->edgelvl = i; + multires_edge_level_update(self->object, self->mesh); + break; + case MESH_MULTIRES_PIN: + self->mesh->mr->pinlvl = i; + break; + case MESH_MULTIRES_RENDER: + self->mesh->mr->renderlvl = i; + break; + } + + return 0; +} + +/* end multires */ + + +static PyObject *Mesh_Tools( BPy_Mesh * self, int type, void **args ) +{ + Base *base; + int result; + Object *object = NULL; + PyObject *attr = NULL; + + /* if already in edit mode, exit */ + + if( G.obedit ) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "can't use mesh tools while in edit mode" ); + + for( base = FIRSTBASE; base; base = base->next ) { + if( base->object->type == OB_MESH && + base->object->data == self->mesh ) { + object = base->object; + break; + } + } + if( !object ) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "can't find an object for the mesh" ); + + if( object->type != OB_MESH ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "Object specified is not a mesh." ); + + /* make mesh's object active, enter mesh edit mode */ + G.obedit = object; + make_editMesh(); + + /* apply operation, then exit edit mode */ + switch( type ) { + case MESH_TOOL_TOSPHERE: + vertices_to_sphere(); + break; + case MESH_TOOL_VERTEXSMOOTH: + vertexsmooth(); + break; + case MESH_TOOL_FLIPNORM: + /* would be simple to rewrite this to not use edit mesh */ + /* see flipface() */ + flip_editnormals(); + break; + case MESH_TOOL_SUBDIV: + esubdivideflag( 1, 0.0, *((int *)args[0]), 1, 0 ); + break; + case MESH_TOOL_REMDOUB: + result = removedoublesflag( 1, 0, *((float *)args[0]) ); + + attr = PyInt_FromLong( result ); + if( !attr ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyInt_FromLong() failed" ); + break; + case MESH_TOOL_FILL: + fill_mesh(); + break; + case MESH_TOOL_RECALCNORM: + righthandfaces( *((int *)args[0]) ); + break; + case MESH_TOOL_TRI2QUAD: + join_triangles(); + break; + case MESH_TOOL_QUAD2TRI: + convert_to_triface( *((int *)args[0]) ); + break; + } + + /* exit edit mode, free edit mesh */ + load_editMesh(); + free_editMesh(G.editMesh); + + if(G.f & G_FACESELECT) + EXPP_allqueue( REDRAWIMAGE, 0 ); + if(G.f & G_WEIGHTPAINT) + mesh_octree_table(G.obedit, NULL, 'e'); + G.obedit = NULL; + + DAG_object_flush_update(G.scene, object, OB_RECALC_DATA); + + if( attr ) + return attr; + + Py_RETURN_NONE; +} + +/* + * "Subdivide" function + */ + +static PyObject *Mesh_subdivide( BPy_Mesh * self, PyObject * args ) +{ + int beauty = 0; + void *params = &beauty; + + if( !PyArg_ParseTuple( args, "|i", &beauty ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected nothing or an int argument" ); + + return Mesh_Tools( self, MESH_TOOL_SUBDIV, ¶ms ); +} + +/* + * "Smooth" function + */ + +static PyObject *Mesh_smooth( BPy_Mesh * self ) +{ + return Mesh_Tools( self, MESH_TOOL_VERTEXSMOOTH, NULL ); +} + +/* + * "Remove doubles" function + */ + +static PyObject *Mesh_removeDoubles( BPy_Mesh * self, PyObject *args ) +{ + float limit; + void *params = &limit; + + if( !PyArg_ParseTuple( args, "f", &limit ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected float argument" ); + + limit = EXPP_ClampFloat( limit, 0.0f, 1.0f ); + + return Mesh_Tools( self, MESH_TOOL_REMDOUB, ¶ms ); +} + +/* + * "recalc normals" function + */ + +static PyObject *Mesh_recalcNormals( BPy_Mesh * self, PyObject *args ) +{ + int direction = 0; + void *params = &direction; + + if( !PyArg_ParseTuple( args, "|i", &direction ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected nothing or an int in range [0,1]" ); + + if( direction < 0 || direction > 1 ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "expected int in range [0,1]" ); + + /* righthandfaces(1) = outward, righthandfaces(2) = inward */ + ++direction; + + return Mesh_Tools( self, MESH_TOOL_RECALCNORM, ¶ms ); +} + +/* + * "Quads to Triangles" function + */ + +static PyObject *Mesh_quad2tri( BPy_Mesh * self, PyObject *args ) +{ + int kind = 0; + void *params = &kind; + + if( !PyArg_ParseTuple( args, "|i", &kind ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected nothing or an int in range [0,1]" ); + + if( kind < 0 || kind > 1 ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "expected int in range [0,1]" ); + + return Mesh_Tools( self, MESH_TOOL_QUAD2TRI, ¶ms ); +} + +/* + * "Triangles to Quads" function + */ + +static PyObject *Mesh_tri2quad( BPy_Mesh * self ) +{ + return Mesh_Tools( self, MESH_TOOL_TRI2QUAD, NULL ); +} + +/* + * "Flip normals" function + */ + +static PyObject *Mesh_flipNormals( BPy_Mesh * self ) +{ + return Mesh_Tools( self, MESH_TOOL_FLIPNORM, NULL ); +} + +/* + * "To sphere" function + */ + +static PyObject *Mesh_toSphere( BPy_Mesh * self ) +{ + return Mesh_Tools( self, MESH_TOOL_TOSPHERE, NULL ); +} + +/* + * "Fill" (scan fill) function + */ + +static PyObject *Mesh_fill( BPy_Mesh * self ) +{ + return Mesh_Tools( self, MESH_TOOL_FILL, NULL ); +} + + +/* + * "pointInside" function + */ +#define SIDE_OF_LINE(pa,pb,pp) ((pa[0]-pp[0])*(pb[1]-pp[1]))-((pb[0]-pp[0])*(pa[1]-pp[1])) +#define POINT_IN_TRI(p0,p1,p2,p3) ((SIDE_OF_LINE(p1,p2,p0)>=0) && (SIDE_OF_LINE(p2,p3,p0)>=0) && (SIDE_OF_LINE(p3,p1,p0)>=0)) +static short pointInside_internal(float *vec, float *v1, float *v2, float *v3 ) +{ + float z,w1,w2,w3,wtot; + + if (!POINT_IN_TRI(vec, v1,v2,v3)) + return 0; + + if (vec[2] < MAX3(v1[2], v2[2], v3[2])) { + w1= AreaF2Dfl(vec, v2, v3); + w2= AreaF2Dfl(v1, vec, v3); + w3= AreaF2Dfl(v1, v2, vec); + wtot = w1+w2+w3; + w1/=wtot; w2/=wtot; w3/=wtot; + z =((v1[2] * (w2+w3)) + + (v2[2] * (w1+w3)) + + (v3[2] * (w1+w2))) * 0.5; + /* only return true if the face is above vec*/ + if (vec[2] < z ) + return 1; + } + return 0; +} + +static PyObject *Mesh_pointInside( BPy_Mesh * self, VectorObject * vec ) +{ + Mesh *mesh = self->mesh; + MFace *mf = mesh->mface; + MVert *mvert = mesh->mvert; + int i; + int isect_count=0; + + if(!VectorObject_Check(vec)) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected one vector type" ); + + if(vec->size < 3) + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Mesh.pointInside(vec) expects a 3D vector objects\n"); + + for( i = 0; i < mesh->totface; ++mf, ++i ) { + if (pointInside_internal(vec->vec, mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co)) + isect_count++; + else if (mf->v4 && pointInside_internal(vec->vec,mvert[mf->v1].co, mvert[mf->v3].co, mvert[mf->v4].co)) + isect_count++; + } + + if (isect_count % 2) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + + +/* + * "__copy__" return a copy of the mesh + */ + +static PyObject *Mesh_copy( BPy_Mesh * self ) +{ + BPy_Mesh *obj; + + obj = (BPy_Mesh *)PyObject_NEW( BPy_Mesh, &Mesh_Type ); + + if( !obj ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyObject_New() failed" ); + + obj->mesh = copy_mesh( self->mesh ); + obj->mesh->id.us= 0; + obj->object = NULL; + obj->new = 1; + return (PyObject *)obj; +} + + +static struct PyMethodDef BPy_Mesh_methods[] = { + {"calcNormals", (PyCFunction)Mesh_calcNormals, METH_NOARGS, + "all recalculate vertex normals"}, + {"vertexShade", (PyCFunction)Mesh_vertexShade, METH_VARARGS, + "color vertices based on the current lighting setup"}, + {"findEdges", (PyCFunction)Mesh_findEdges, METH_VARARGS, + "find indices of an multiple edges in the mesh"}, + {"getFromObject", (PyCFunction)Mesh_getFromObject, METH_VARARGS, + "Get a mesh by name"}, + {"update", (PyCFunction)Mesh_Update, METH_VARARGS | METH_KEYWORDS, + "Update display lists after changes to mesh"}, + {"transform", (PyCFunction)Mesh_transform, METH_VARARGS | METH_KEYWORDS, + "Applies a transformation matrix to mesh's vertices"}, + {"addVertGroup", (PyCFunction)Mesh_addVertGroup, METH_O, + "Assign vertex group name to the object linked to the mesh"}, + {"removeVertGroup", (PyCFunction)Mesh_removeVertGroup, METH_O, + "Delete vertex group name from the object linked to the mesh"}, + {"assignVertsToGroup", (PyCFunction)Mesh_assignVertsToGroup, METH_VARARGS, + "Assigns vertices to a vertex group"}, + {"removeVertsFromGroup", (PyCFunction)Mesh_removeVertsFromGroup, METH_VARARGS, + "Removes vertices from a vertex group"}, + {"getVertsFromGroup", (PyCFunction)Mesh_getVertsFromGroup, METH_VARARGS, + "Get index and optional weight for vertices in vertex group"}, + {"renameVertGroup", (PyCFunction)Mesh_renameVertGroup, METH_VARARGS, + "Rename an existing vertex group"}, + {"getVertGroupNames", (PyCFunction)Mesh_getVertGroupNames, METH_NOARGS, + "Get names of vertex groups"}, + {"getVertexInfluences", (PyCFunction)Mesh_getVertexInfluences, METH_VARARGS, + "Get list of the influences of bones for a given mesh vertex"}, + /* Shape Keys */ + {"removeAllKeys", (PyCFunction)Mesh_removeAllKeys, METH_NOARGS, + "Remove all the shape keys from a mesh"}, + {"insertKey", (PyCFunction)Mesh_insertKey, METH_VARARGS, + "(frame = None, type = 'relative') - inserts a Mesh key at the given frame"}, + /* Mesh tools */ + {"smooth", (PyCFunction)Mesh_smooth, METH_NOARGS, + "Flattens angle of selected faces (experimental)"}, + {"flipNormals", (PyCFunction)Mesh_flipNormals, METH_NOARGS, + "Toggles the direction of selected face's normals (experimental)"}, + {"toSphere", (PyCFunction)Mesh_toSphere, METH_NOARGS, + "Moves selected vertices outward in a spherical shape (experimental)"}, + {"fill", (PyCFunction)Mesh_fill, METH_NOARGS, + "Scan fill a closed edge loop (experimental)"}, + {"triangleToQuad", (PyCFunction)Mesh_tri2quad, METH_VARARGS, + "Convert selected triangles to quads (experimental)"}, + {"quadToTriangle", (PyCFunction)Mesh_quad2tri, METH_VARARGS, + "Convert selected quads to triangles (experimental)"}, + {"subdivide", (PyCFunction)Mesh_subdivide, METH_VARARGS, + "Subdivide selected edges in a mesh (experimental)"}, + {"remDoubles", (PyCFunction)Mesh_removeDoubles, METH_VARARGS, + "Removes duplicates from selected vertices (experimental)"}, + {"recalcNormals", (PyCFunction)Mesh_recalcNormals, METH_VARARGS, + "Recalculates inside or outside normals (experimental)"}, + {"pointInside", (PyCFunction)Mesh_pointInside, METH_O, + "Recalculates inside or outside normals (experimental)"}, + + /* mesh custom data layers */ + {"addUVLayer", (PyCFunction)Mesh_addUVLayer, METH_VARARGS, + "adds a UV layer to this mesh"}, + {"addColorLayer", (PyCFunction)Mesh_addColorLayer, METH_VARARGS, + "adds a color layer to this mesh "}, + {"removeUVLayer", (PyCFunction)Mesh_removeUVLayer, METH_O, + "removes a UV layer to this mesh"}, + {"removeColorLayer", (PyCFunction)Mesh_removeColorLayer, METH_O, + "removes a color layer to this mesh"}, + {"getUVLayerNames", (PyCFunction)Mesh_getUVLayerNames, METH_NOARGS, + "Get names of UV layers"}, + {"getColorLayerNames", (PyCFunction)Mesh_getColorLayerNames, METH_NOARGS, + "Get names of Color layers"}, + {"renameUVLayer", (PyCFunction)Mesh_renameUVLayer, METH_VARARGS, + "Rename a UV Layer"}, + {"renameColorLayer", (PyCFunction)Mesh_renameColorLayer, METH_VARARGS, + "Rename a Color Layer"}, + + /* python standard class functions */ + {"__copy__", (PyCFunction)Mesh_copy, METH_NOARGS, + "Return a copy of the mesh"}, + {"copy", (PyCFunction)Mesh_copy, METH_NOARGS, + "Return a copy of the mesh"}, + {NULL, NULL, 0, NULL} +}; + +/************************************************************************ + * + * Python BPy_Mesh attributes + * + ************************************************************************/ + +static PyObject *MVertSeq_CreatePyObject( Mesh * mesh ) +{ + + BPy_MVertSeq *obj = PyObject_NEW( BPy_MVertSeq, &MVertSeq_Type); + obj->mesh = mesh; + + /* + an iter of -1 means this seq has not been used as an iterator yet + once it is, then any other calls on getIter will return a new copy of BPy_MVertSeq + This means you can loop do nested loops with the same iterator without worrying about + the iter variable being used twice and messing up the loops. + */ + obj->iter = -1; + return (PyObject *)obj; +} + +static PyObject *Mesh_getVerts( BPy_Mesh * self ) +{ + return MVertSeq_CreatePyObject(self->mesh); +} + +static int Mesh_setVerts( BPy_Mesh * self, PyObject * args ) +{ + MVert *dst; + MVert *src; + int i; + + /* special case if None: delete the mesh */ + if( args == NULL || args == Py_None ) { + Mesh *me = self->mesh; + free_mesh( me ); + me->mvert = NULL; me->medge = NULL; me->mface = NULL; + me->mtface = NULL; me->dvert = NULL; me->mcol = NULL; + me->msticky = NULL; me->mat = NULL; me->bb = NULL; + me->totvert = me->totedge = me->totface = me->totcol = 0; + mesh_update( me ); + return 0; + } + + if( PyList_Check( args ) ) { + if( EXPP_check_sequence_consistency( args, &MVert_Type ) != 1 && + EXPP_check_sequence_consistency( args, &PVert_Type ) != 1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a list of MVerts" ); + + if( PyList_Size( args ) != self->mesh->totvert ) + return EXPP_ReturnIntError( PyExc_TypeError, + "list must have the same number of vertices as the mesh" ); + + dst = self->mesh->mvert; + for( i = 0; i < PyList_Size( args ); ++i ) { + BPy_MVert *v = (BPy_MVert *)PyList_GET_ITEM( args, i ); + + if( BPy_MVert_Check( v ) ) + src = &((Mesh *)v->data)->mvert[v->index]; + else + src = (MVert *)v->data; + + memcpy( dst, src, sizeof(MVert) ); + ++dst; + } + } else if( args->ob_type == &MVertSeq_Type ) { + Mesh *mesh = ( (BPy_MVertSeq *) args)->mesh; + + if( mesh->totvert != self->mesh->totvert ) + return EXPP_ReturnIntError( PyExc_TypeError, + "vertex sequences must have the same number of vertices" ); + + memcpy( self->mesh->mvert, mesh->mvert, mesh->totvert*sizeof(MVert) ); + } else + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a list or sequence of MVerts" ); + return 0; +} + +static PyObject *MEdgeSeq_CreatePyObject( Mesh *mesh ) +{ + BPy_MEdgeSeq *obj = PyObject_NEW( BPy_MEdgeSeq, &MEdgeSeq_Type); + obj->mesh = mesh; + obj->iter = -1; /* iterator not yet used */ + return (PyObject *)obj; +} + +static PyObject *Mesh_getEdges( BPy_Mesh * self ) +{ + return MEdgeSeq_CreatePyObject(self->mesh); +} + +static PyObject *MFaceSeq_CreatePyObject( Mesh * mesh ) +{ + BPy_MFaceSeq *obj= PyObject_NEW( BPy_MFaceSeq, &MFaceSeq_Type); + obj->mesh = mesh; + obj->iter = -1; /* iterator not yet used */ + return (PyObject *)obj; +} + +static PyObject *Mesh_getFaces( BPy_Mesh * self ) +{ + return MFaceSeq_CreatePyObject( self->mesh ); +} + +static PyObject *Mesh_getMaterials( BPy_Mesh *self ) +{ + return EXPP_PyList_fromMaterialList( self->mesh->mat, + self->mesh->totcol, 1 ); +} + +static int Mesh_setMaterials( BPy_Mesh *self, PyObject * value ) +{ + Material **matlist; + int len; + + if( !PySequence_Check( value ) || + !EXPP_check_sequence_consistency( value, &Material_Type ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "list should only contain materials or None)" ); + + len = PyList_Size( value ); + if( len > 16 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "list can't have more than 16 materials" ); + + /* free old material list (if it exists) and adjust user counts */ + if( self->mesh->mat ) { + Mesh *me = self->mesh; + int i; + for( i = me->totcol; i-- > 0; ) + if( me->mat[i] ) + me->mat[i]->id.us--; + MEM_freeN( me->mat ); + } + + /* build the new material list, increment user count, store it */ + + matlist = EXPP_newMaterialList_fromPyList( value ); + EXPP_incr_mats_us( matlist, len ); + self->mesh->mat = matlist; + self->mesh->totcol = (short)len; + +/**@ This is another ugly fix due to the weird material handling of blender. + * it makes sure that object material lists get updated (by their length) + * according to their data material lists, otherwise blender crashes. + * It just stupidly runs through all objects...BAD BAD BAD. + */ + + test_object_materials( ( ID * ) self->mesh ); + + return 0; +} + +static PyObject *Mesh_getMaxSmoothAngle( BPy_Mesh * self ) +{ + return PyInt_FromLong( self->mesh->smoothresh ); +} + +static int Mesh_setMaxSmoothAngle( BPy_Mesh *self, PyObject *value ) +{ + return EXPP_setIValueClamped( value, &self->mesh->smoothresh, + MESH_SMOOTHRESH_MIN, + MESH_SMOOTHRESH_MAX, 'h' ); +} + +static PyObject *Mesh_getSubDivLevels( BPy_Mesh * self ) +{ + return Py_BuildValue( "(h,h)", + self->mesh->subdiv, self->mesh->subdivr ); +} + +static int Mesh_setSubDivLevels( BPy_Mesh *self, PyObject *value ) +{ + int subdiv[2]; + int i; + PyObject *tmp; + + if( !PyTuple_Check( value ) || PyTuple_Size( value ) != 2 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected (int, int) as argument" ); + + for( i = 0; i < 2; i++ ) { + tmp = PyTuple_GET_ITEM( value, i ); + if( !PyInt_Check( tmp ) ) + return EXPP_ReturnIntError ( PyExc_TypeError, + "expected a list [int, int] as argument" ); + subdiv[i] = EXPP_ClampInt( PyInt_AsLong( tmp ), + MESH_SUBDIV_MIN, + MESH_SUBDIV_MAX ); + } + + self->mesh->subdiv = (short)subdiv[0]; + self->mesh->subdivr = (short)subdiv[1]; + return 0; +} + +static PyObject *Mesh_getFlag( BPy_Mesh * self, void *type ) +{ + switch( (long)type ) { + case MESH_HASFACEUV: + return self->mesh->mtface ? EXPP_incr_ret_True() : + EXPP_incr_ret_False(); + case MESH_HASMCOL: + return self->mesh->mcol ? EXPP_incr_ret_True() : + EXPP_incr_ret_False(); + case MESH_HASVERTUV: + return self->mesh->msticky ? EXPP_incr_ret_True() : + EXPP_incr_ret_False(); + case MESH_HASMULTIRES: + return self->mesh->mr ? EXPP_incr_ret_True() : + EXPP_incr_ret_False(); + default: + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't get attribute" ); + } +} + +static int Mesh_setFlag( BPy_Mesh * self, PyObject *value, void *type ) +{ + int param; + Mesh *mesh = self->mesh; + + param = PyObject_IsTrue( value ); + + if( param == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected True/False or 0/1" ); + + /* sticky is independent of faceUV and vertUV */ + + switch( (long)type ) { + case MESH_HASFACEUV: + if( !param ) { + if( mesh->mtface ) { + CustomData_free_layers( &mesh->fdata, CD_MTFACE, mesh->totface ); + mesh->mtface = NULL; + } + } else if( !mesh->mtface ) { + if( !mesh->totface ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "mesh has no faces" ); + make_tfaces( mesh ); + } + return 0; + case MESH_HASMCOL: + if( !param ) { + if( mesh->mcol ) { + CustomData_free_layers( &mesh->fdata, CD_MCOL, mesh->totface ); + mesh->mcol = NULL; + } + } else if( !mesh->mcol ) { + /* TODO: mesh_create_shadedColors */ + mesh->mcol = CustomData_add_layer( &mesh->fdata, CD_MCOL, + CD_DEFAULT, NULL, mesh->totface ); + } + return 0; + case MESH_HASVERTUV: + if( !param ) { + if( mesh->msticky ) { + CustomData_free_layer_active( &mesh->vdata, CD_MSTICKY, mesh->totvert ); + mesh->msticky = NULL; + } + } else { + if( !mesh->msticky ) { + mesh->msticky = CustomData_add_layer( &mesh->vdata, CD_MSTICKY, + CD_CALLOC, NULL, mesh->totvert ); + memset( mesh->msticky, 255, mesh->totvert*sizeof( MSticky ) ); + /* TODO: rework RE_make_sticky() so we can calculate */ + } + } + return 0; + case MESH_HASMULTIRES: + if (!self->object) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "This mesh must be linked to an object" ); + + if( !param ) { + if ( mesh->mr ) { + multires_delete(self->object, mesh); + } + } else { + if ( !mesh->mr ) { + if (mesh->key) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "Cannot enable multires for a mesh with shape keys" ); + multires_make(self->object, mesh); + } + } + return 0; + default: + return EXPP_ReturnIntError( PyExc_RuntimeError, + "couldn't get attribute" ); + } +} + +static PyObject *Mesh_getMode( BPy_Mesh * self ) +{ + return PyInt_FromLong( self->mesh->flag ); +} + +static int Mesh_setMode( BPy_Mesh *self, PyObject *value ) +{ + short param; + static short bitmask = ME_ISDONE | ME_NOPUNOFLIP | ME_TWOSIDED | + ME_UVEFFECT | ME_VCOLEFFECT | ME_AUTOSMOOTH | ME_SMESH | + ME_SUBSURF | ME_OPT_EDGES; + + if( !PyInt_Check ( value ) ) { + char errstr[128]; + sprintf ( errstr , "expected int bitmask of 0x%04x", bitmask ); + return EXPP_ReturnIntError( PyExc_TypeError, errstr ); + } + param = (short)PyInt_AS_LONG ( value ); + + if( ( param & bitmask ) != param ) + return EXPP_ReturnIntError( PyExc_ValueError, + "invalid bit(s) set in mask" ); + + self->mesh->flag = param; + + return 0; +} + +static PyObject *Mesh_getKey( BPy_Mesh * self ) +{ + if( self->mesh->key ) + return Key_CreatePyObject(self->mesh->key); + else + Py_RETURN_NONE; +} + + +static PyObject *Mesh_getActiveFace( BPy_Mesh * self ) +{ + /* not needed but keep incase exceptions make use of it */ + if( !self->mesh->mtface ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "face has no texture values" ); + + if (self->mesh->act_face != -1 && self->mesh->act_face <= self->mesh->totface) + return PyInt_FromLong( self->mesh->act_face ); + + Py_RETURN_NONE; +} + +static int Mesh_setActiveFace( BPy_Mesh * self, PyObject * value ) +{ + int param; + + /* if no texture faces, error */ + + if( !self->mesh->mtface ) + return EXPP_ReturnIntError( PyExc_ValueError, + "face has no texture values" ); + + /* if param isn't an int, error */ + + if( !PyInt_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected an int argument" ); + + /* check for a valid index */ + + param = PyInt_AsLong( value ); + if( param < 0 || param > self->mesh->totface ) + return EXPP_ReturnIntError( PyExc_TypeError, + "face index out of range" ); + + self->mesh->act_face = param; + return 0; +} + +static PyObject *Mesh_getActiveGroup( BPy_Mesh * self ) +{ + bDeformGroup *defGroup; + Object *object = self->object; + + if( !object ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This mesh must be linked to an object" ); + + if( object->actdef ) { + defGroup = BLI_findlink( &object->defbase, object->actdef-1 ); + return PyString_FromString( defGroup->name ); + } + + Py_RETURN_NONE; +} + +static int Mesh_setActiveGroup( BPy_Mesh * self, PyObject * arg ) +{ + char *name; + int tmp; + Object *object = self->object; + + if( !object ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "This mesh must be linked to an object" ); + + if( !PyString_Check( arg ) ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "expected a string argument" ); + + name = PyString_AsString( arg ); + tmp = object->actdef; + vertexgroup_select_by_name( object, name ); + if( !object->actdef ) { + object->actdef = tmp; + return EXPP_ReturnIntError( PyExc_ValueError, + "vertex group not found" ); + } + + return 0; +} + +static PyObject *Mesh_getTexMesh( BPy_Mesh * self ) +{ + Mesh *texme= self->mesh->texcomesh; + + if (texme) + return Mesh_CreatePyObject( texme, NULL ); + else + Py_RETURN_NONE; +} + +static int Mesh_setTexMesh( BPy_Mesh * self, PyObject * value ) +{ + int ret = GenericLib_assignData(value, (void **) &self->mesh->texcomesh, 0, 1, ID_ME, 0); + + if (ret==0 && value!=Py_None) /*This must be a mesh type*/ + (( BPy_Mesh * ) value)->new= 0; + + return ret; +} + +static int Mesh_setSel( BPy_Mesh * self, PyObject * value ) +{ + int i, param = PyObject_IsTrue( value ); + Mesh *me = self->mesh; + MVert *mvert = me->mvert; + MEdge *medge = me->medge; + MFace *mface = me->mface; + + if( param == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected True/False or 0/1" ); + + if( param ) { + for( i = 0; i < me->totvert; ++mvert, ++i ) + mvert->flag |= SELECT; + for( i = 0; i < me->totedge; ++medge, ++i ) + medge->flag |= SELECT; + for( i = 0; i < me->totface; ++mface, ++i ) + mface->flag |= ME_FACE_SEL; + } else { + for( i = 0; i < me->totvert; ++mvert, ++i ) + mvert->flag &= ~SELECT; + for( i = 0; i < me->totedge; ++medge, ++i ) + medge->flag &= ~SELECT; + for( i = 0; i < me->totface; ++mface, ++i ) + mface->flag &= ~ME_FACE_SEL; + } + + return 0; +} + +static int Mesh_setHide( BPy_Mesh * self, PyObject * value ) +{ + int i, param = PyObject_IsTrue( value ); + Mesh *me = self->mesh; + MVert *mvert = me->mvert; + MEdge *medge = me->medge; + MFace *mface = me->mface; + + if( param == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected True/False or 0/1" ); + + if( param ) { + for( i = 0; i < me->totvert; ++mvert, ++i ) + mvert->flag |= ME_HIDE; + for( i = 0; i < me->totedge; ++medge, ++i ) + medge->flag |= ME_HIDE; + for( i = 0; i < me->totface; ++mface, ++i ) + mface->flag |= ME_HIDE; + } else { + for( i = 0; i < me->totvert; ++mvert, ++i ) + mvert->flag &= ~ME_HIDE; + for( i = 0; i < me->totedge; ++medge, ++i ) + medge->flag &= ~ME_HIDE; + for( i = 0; i < me->totface; ++mface, ++i ) + mface->flag &= ~ME_HIDE; + } + + return 0; +} + +/************************************************************************ + * + * Python Mesh_Type standard operations + * + ************************************************************************/ + +static void Mesh_dealloc( BPy_Mesh * self ) +{ + Mesh *mesh = self->mesh; + + /* if the mesh is new and has no users, delete it */ + if( self->new && !mesh->id.us ) + free_libblock( &G.main->mesh, mesh ); + + PyObject_DEL( self ); +} + +static int Mesh_compare( BPy_Mesh * a, BPy_Mesh * b ) +{ + return ( a->mesh == b->mesh ) ? 0 : -1; +} + +static PyObject *Mesh_repr( BPy_Mesh * self ) +{ + return PyString_FromFormat( "[Mesh \"%s\"]", + self->mesh->id.name + 2 ); +} + +/*****************************************************************************/ +/* Python Mesh_Type attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef BPy_Mesh_getseters[] = { + GENERIC_LIB_GETSETATTR, + {"verts", + (getter)Mesh_getVerts, (setter)Mesh_setVerts, + "The mesh's vertices (MVert)", + NULL}, + {"edges", + (getter)Mesh_getEdges, (setter)NULL, + "The mesh's edge data (MEdge)", + NULL}, + {"faces", + (getter)Mesh_getFaces, (setter)NULL, + "The mesh's face data (MFace)", + NULL}, + {"materials", + (getter)Mesh_getMaterials, (setter)Mesh_setMaterials, + "List of the mesh's materials", + NULL}, + {"degr", + (getter)Mesh_getMaxSmoothAngle, (setter)Mesh_setMaxSmoothAngle, + "The max angle for auto smoothing", + NULL}, + {"maxSmoothAngle", + (getter)Mesh_getMaxSmoothAngle, (setter)Mesh_setMaxSmoothAngle, + "deprecated: see 'degr'", + NULL}, + {"subDivLevels", + (getter)Mesh_getSubDivLevels, (setter)Mesh_setSubDivLevels, + "The display and rendering subdivision levels", + NULL}, + {"mode", + (getter)Mesh_getMode, (setter)Mesh_setMode, + "The mesh's mode bitfield", + NULL}, + {"key", + (getter)Mesh_getKey, (setter)NULL, + "The mesh's key", + NULL}, + {"faceUV", + (getter)Mesh_getFlag, (setter)Mesh_setFlag, + "UV-mapped textured faces enabled", + (void *)MESH_HASFACEUV}, + {"vertexColors", + (getter)Mesh_getFlag, (setter)Mesh_setFlag, + "Vertex colors for the mesh enabled", + (void *)MESH_HASMCOL}, + {"vertexUV", + (getter)Mesh_getFlag, (setter)Mesh_setFlag, + "'Sticky' flag for per vertex UV coordinates enabled", + (void *)MESH_HASVERTUV}, + {"multires", + (getter)Mesh_getFlag, (setter)Mesh_setFlag, + "'Sticky' flag for per vertex UV coordinates enabled", + (void *)MESH_HASMULTIRES}, + {"activeFace", + (getter)Mesh_getActiveFace, (setter)Mesh_setActiveFace, + "Index of the mesh's active texture face (in UV editor)", + NULL}, + {"activeGroup", + (getter)Mesh_getActiveGroup, (setter)Mesh_setActiveGroup, + "Active group for the mesh", + NULL}, + + /* uv layers */ + {"activeColorLayer", + (getter)Mesh_getActiveLayer, (setter)Mesh_setActiveLayer, + "Name of the active UV layer", + (void *)CD_MCOL}, + {"activeUVLayer", + (getter)Mesh_getActiveLayer, (setter)Mesh_setActiveLayer, + "Name of the active vertex color layer", + (void *)CD_MTFACE}, + /* hack flip CD_MCOL so it uses the render setting */ + {"renderColorLayer", + (getter)Mesh_getActiveLayer, (setter)Mesh_setActiveLayer, + "Name of the render UV layer", + (void *)-CD_MCOL}, + {"renderUVLayer", + (getter)Mesh_getActiveLayer, (setter)Mesh_setActiveLayer, + "Name of the render vertex color layer", + (void *)-CD_MTFACE}, + + + + /* Multires */ + {"multiresLevelCount", + (getter)Mesh_getMultiresLevelCount, (setter)NULL, + "The total number of multires levels", + NULL}, + {"multiresDrawLevel", + (getter)Mesh_getMultires, (setter)Mesh_setMultires, + "The current multires display level", + (void *)MESH_MULTIRES_LEVEL}, + {"multiresEdgeLevel", + (getter)Mesh_getMultires, (setter)Mesh_setMultires, + "The current multires edge level", + (void *)MESH_MULTIRES_EDGE}, + {"multiresPinLevel", + (getter)Mesh_getMultires, (setter)Mesh_setMultires, + "The current multires pin level", + (void *)MESH_MULTIRES_PIN}, + {"multiresRenderLevel", + (getter)Mesh_getMultires, (setter)Mesh_setMultires, + "The current multires render level", + (void *)MESH_MULTIRES_RENDER}, + + {"texMesh", + (getter)Mesh_getTexMesh, (setter)Mesh_setTexMesh, + "The meshes tex mesh proxy texture coord mesh", + NULL}, + {"sel", + (getter)NULL, (setter)Mesh_setSel, + "Select/deselect all verts, edges, faces in the mesh", + NULL}, + {"hide", + (getter)NULL, (setter)Mesh_setHide, + "Hide/unhide all verts, edges, faces in the mesh", + NULL}, + + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/*****************************************************************************/ +/* Python Mesh_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject Mesh_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender Mesh", /* char *tp_name; */ + sizeof( BPy_Mesh ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + ( destructor ) Mesh_dealloc,/* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) Mesh_compare, /* cmpfunc tp_compare; */ + ( reprfunc ) Mesh_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_Mesh_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_Mesh_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +/* + * get one or all mesh data objects + */ + +static PyObject *M_Mesh_Get( PyObject * self_unused, PyObject * args ) +{ + char *name = NULL; + Mesh *mesh = NULL; + BPy_Mesh* obj; + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected zero or one string arguments" ); + + if( name ) { + mesh = ( Mesh * ) GetIdFromList( &( G.main->mesh ), name ); + + if( !mesh ) { + char error_msg[64]; + PyOS_snprintf( error_msg, sizeof( error_msg ), + "Mesh \"%s\" not found", name ); + return ( EXPP_ReturnPyObjError + ( PyExc_NameError, error_msg ) ); + } + return Mesh_CreatePyObject( mesh, NULL ); + } else { /* () - return a list with all meshes in the scene */ + PyObject *meshlist; + Link *link; + int index = 0; + + meshlist = PyList_New( BLI_countlist( &( G.main->mesh ) ) ); + + if( !meshlist ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyList" ); + + link = G.main->mesh.first; + index = 0; + while( link ) { + obj = ( BPy_Mesh * ) Mesh_CreatePyObject( ( Mesh * )link, NULL ); + PyList_SetItem( meshlist, index, ( PyObject * ) obj ); + index++; + link = link->next; + } + return meshlist; + } +} + +/* + * create a new mesh data object + */ + +static PyObject *M_Mesh_New( PyObject * self_unused, PyObject * args ) +{ + char *name = "Mesh"; + Mesh *mesh; + BPy_Mesh *obj; + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected nothing or a string as argument" ); + + obj = (BPy_Mesh *)PyObject_NEW( BPy_Mesh, &Mesh_Type ); + + if( !obj ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyObject_New() failed" ); + + mesh = add_mesh(name); /* doesn't return NULL now, but might someday */ + + if( !mesh ) { + Py_DECREF ( obj ); + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "FATAL: could not create mesh object" ); + } + + /* Bound box set to null needed because a new mesh is initialized + with a bounding box of -1 -1 -1 -1 -1 -1 + if its not set to null the bounding box is not re-calculated + when ob.getBoundBox() is called.*/ + MEM_freeN(mesh->bb); + mesh->bb= NULL; + + mesh->id.us = 0; + + obj->mesh = mesh; + obj->object = NULL; + obj->new = 1; + return (PyObject *)obj; +} + +/* + * creates a new MVert for users to manipulate + */ + +static PyObject *M_Mesh_MVert( PyObject * self_unused, PyObject * args ) +{ + int i; + MVert vert; + + /* initialize the new vert's data */ + memset( &vert, 0, sizeof( MVert ) ); + + /* + * accept either a 3D vector or tuple of three floats + */ + + if( PyTuple_Size ( args ) == 1 ) { + PyObject *tmp = PyTuple_GET_ITEM( args, 0 ); + if( !VectorObject_Check( tmp ) || ((VectorObject *)tmp)->size != 3 ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "expected three floats or vector of size 3" ); + for( i = 0; i < 3; ++i ) + vert.co[i] = ((VectorObject *)tmp)->vec[i]; + } else if( !PyArg_ParseTuple ( args, "fff", + &vert.co[0], &vert.co[1], &vert.co[2] ) ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "expected three floats or vector of size 3" ); + + /* make a new MVert from the data */ + return PVert_CreatePyObject( &vert ); +} + +static PyObject *M_Mesh_Modes( PyObject * self_unused, PyObject * args ) +{ + int modes = 0; + + if( !G.scene ) { + Py_RETURN_NONE; + } + + if( !PyArg_ParseTuple( args, "|i", &modes ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected optional int as argument" ); + + if( modes > ( SCE_SELECT_VERTEX | SCE_SELECT_EDGE | SCE_SELECT_FACE ) ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "value out of range" ); + + if( modes > 0 ) + G.scene->selectmode = (short)modes; + + return PyInt_FromLong( G.scene->selectmode ); +} + +static struct PyMethodDef M_Mesh_methods[] = { + {"New", (PyCFunction)M_Mesh_New, METH_VARARGS, + "Create a new mesh"}, + {"Get", (PyCFunction)M_Mesh_Get, METH_VARARGS, + "Get a mesh by name"}, + {"MVert", (PyCFunction)M_Mesh_MVert, METH_VARARGS, + "Create a new MVert"}, + {"Mode", (PyCFunction)M_Mesh_Modes, METH_VARARGS, + "Get/set edit selection mode(s)"}, + {NULL, NULL, 0, NULL}, +}; + +static PyObject *M_Mesh_ModesDict( void ) +{ + PyObject *Modes = PyConstant_New( ); + + if( Modes ) { + BPy_constant *d = ( BPy_constant * ) Modes; + + PyConstant_Insert( d, "NOVNORMALSFLIP", + PyInt_FromLong( ME_NOPUNOFLIP ) ); + PyConstant_Insert( d, "TWOSIDED", PyInt_FromLong( ME_TWOSIDED ) ); + PyConstant_Insert( d, "AUTOSMOOTH", + PyInt_FromLong( ME_AUTOSMOOTH ) ); + } + + return Modes; +} + +/* Set constants for face drawing mode -- see drawmesh.c */ + +static PyObject *M_Mesh_FaceModesDict( void ) +{ + PyObject *FM = PyConstant_New( ); + + if( FM ) { + BPy_constant *d = ( BPy_constant * ) FM; + + PyConstant_Insert( d, "BILLBOARD", + PyInt_FromLong( TF_BILLBOARD2 ) ); + PyConstant_Insert( d, "ALL", PyInt_FromLong( 0xffff ) ); + PyConstant_Insert( d, "HALO", PyInt_FromLong( TF_BILLBOARD ) ); + PyConstant_Insert( d, "DYNAMIC", PyInt_FromLong( TF_DYNAMIC ) ); + PyConstant_Insert( d, "INVISIBLE", PyInt_FromLong( TF_INVISIBLE ) ); + PyConstant_Insert( d, "LIGHT", PyInt_FromLong( TF_LIGHT ) ); + PyConstant_Insert( d, "OBCOL", PyInt_FromLong( TF_OBCOL ) ); + PyConstant_Insert( d, "SHADOW", PyInt_FromLong( TF_SHADOW ) ); + PyConstant_Insert( d, "TEXT", PyInt_FromLong( TF_BMFONT ) ); + PyConstant_Insert( d, "SHAREDVERT", PyInt_FromLong( TF_SHAREDVERT ) ); + PyConstant_Insert( d, "SHAREDCOL", PyInt_FromLong( TF_SHAREDCOL ) ); + PyConstant_Insert( d, "TEX", PyInt_FromLong( TF_TEX ) ); + PyConstant_Insert( d, "TILES", PyInt_FromLong( TF_TILES ) ); + PyConstant_Insert( d, "TWOSIDE", PyInt_FromLong( TF_TWOSIDE ) ); + } + + return FM; +} + +static PyObject *M_Mesh_FaceFlagsDict( void ) +{ + PyObject *FF = PyConstant_New( ); + + if( FF ) { + BPy_constant *d = ( BPy_constant * ) FF; + + PyConstant_Insert( d, "SELECT", PyInt_FromLong( TF_SELECT ) ); + PyConstant_Insert( d, "HIDE", PyInt_FromLong( TF_HIDE ) ); + PyConstant_Insert( d, "ACTIVE", PyInt_FromLong( TF_ACTIVE ) ); /* deprecated */ + } + + return FF; +} + +static PyObject *M_Mesh_FaceTranspModesDict( void ) +{ + PyObject *FTM = PyConstant_New( ); + + if( FTM ) { + BPy_constant *d = ( BPy_constant * ) FTM; + + PyConstant_Insert( d, "SOLID", PyInt_FromLong( TF_SOLID ) ); + PyConstant_Insert( d, "ADD", PyInt_FromLong( TF_ADD ) ); + PyConstant_Insert( d, "ALPHA", PyInt_FromLong( TF_ALPHA ) ); + PyConstant_Insert( d, "SUB", PyInt_FromLong( TF_SUB ) ); + } + + return FTM; +} + +static PyObject *M_Mesh_EdgeFlagsDict( void ) +{ + PyObject *EF = PyConstant_New( ); + + if( EF ) { + BPy_constant *d = ( BPy_constant * ) EF; + + PyConstant_Insert(d, "SELECT", PyInt_FromLong( SELECT ) ); + PyConstant_Insert(d, "EDGEDRAW", PyInt_FromLong( ME_EDGEDRAW ) ); + PyConstant_Insert(d, "EDGERENDER", PyInt_FromLong( ME_EDGERENDER ) ); + PyConstant_Insert(d, "SEAM", PyInt_FromLong( ME_SEAM ) ); + PyConstant_Insert(d, "FGON", PyInt_FromLong( ME_FGON ) ); + PyConstant_Insert(d, "LOOSE", PyInt_FromLong( ME_LOOSEEDGE ) ); + PyConstant_Insert(d, "SHARP", PyInt_FromLong( ME_SHARP ) ); + } + + return EF; +} + +static PyObject *M_Mesh_VertAssignDict( void ) +{ + PyObject *Vert = PyConstant_New( ); + if( Vert ) { + BPy_constant *d = ( BPy_constant * ) Vert; + PyConstant_Insert(d, "ADD", PyInt_FromLong(WEIGHT_ADD)); + PyConstant_Insert(d, "REPLACE", PyInt_FromLong(WEIGHT_REPLACE)); + PyConstant_Insert(d, "SUBTRACT", PyInt_FromLong(WEIGHT_SUBTRACT)); + } + return Vert; +} + + +static PyObject *M_Mesh_SelectModeDict( void ) +{ + PyObject *Mode = PyConstant_New( ); + if( Mode ) { + BPy_constant *d = ( BPy_constant * ) Mode; + PyConstant_Insert(d, "VERTEX", PyInt_FromLong(SCE_SELECT_VERTEX)); + PyConstant_Insert(d, "EDGE", PyInt_FromLong(SCE_SELECT_EDGE)); + PyConstant_Insert(d, "FACE", PyInt_FromLong(SCE_SELECT_FACE)); + } + return Mode; +} + +static char M_Mesh_doc[] = "The Blender.Mesh submodule"; + +PyObject *Mesh_Init( void ) +{ + PyObject *submodule; + + PyObject *Modes = M_Mesh_ModesDict( ); + PyObject *FaceFlags = M_Mesh_FaceFlagsDict( ); + PyObject *FaceModes = M_Mesh_FaceModesDict( ); + PyObject *FaceTranspModes = M_Mesh_FaceTranspModesDict( ); + PyObject *EdgeFlags = M_Mesh_EdgeFlagsDict( ); + PyObject *AssignModes = M_Mesh_VertAssignDict( ); + PyObject *SelectModes = M_Mesh_SelectModeDict( ); + PyObject *PropertyTypes = M_Mesh_PropertiesTypeDict( ); + + if( PyType_Ready( &MCol_Type ) < 0 ) + return NULL; + if( PyType_Ready( &MVert_Type ) < 0 ) + return NULL; + if( PyType_Ready( &PVert_Type ) < 0 ) + return NULL; + if( PyType_Ready( &MVertSeq_Type ) < 0 ) + return NULL; + if( PyType_Ready( &MEdge_Type ) < 0 ) + return NULL; + if( PyType_Ready( &MEdgeSeq_Type ) < 0 ) + return NULL; + if( PyType_Ready( &MFace_Type ) < 0 ) + return NULL; + if( PyType_Ready( &MFaceSeq_Type ) < 0 ) + return NULL; + if( PyType_Ready( &Mesh_Type ) < 0 ) + return NULL; + + submodule = + Py_InitModule3( "Blender.Mesh", M_Mesh_methods, M_Mesh_doc ); + PyDict_SetItemString( PyModule_GetDict( submodule ), + "Primitives", MeshPrimitives_Init( ) ); + + if( Modes ) + PyModule_AddObject( submodule, "Modes", Modes ); + if( FaceFlags ) + PyModule_AddObject( submodule, "FaceFlags", FaceFlags ); + if( FaceModes ) + PyModule_AddObject( submodule, "FaceModes", FaceModes ); + if( FaceTranspModes ) + PyModule_AddObject( submodule, "FaceTranspModes", + FaceTranspModes ); + if( EdgeFlags ) + PyModule_AddObject( submodule, "EdgeFlags", EdgeFlags ); + if( AssignModes ) + PyModule_AddObject( submodule, "AssignModes", AssignModes ); + if( SelectModes ) + PyModule_AddObject( submodule, "SelectModes", SelectModes ); + if( PropertyTypes ) + PyModule_AddObject( submodule, "PropertyTypes", PropertyTypes ); + + + + return submodule; +} + +/* These are needed by Object.c */ + +PyObject *Mesh_CreatePyObject( Mesh * me, Object *obj ) +{ + BPy_Mesh *nmesh = PyObject_NEW( BPy_Mesh, &Mesh_Type ); + + if( !nmesh ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create BPy_Mesh object" ); + + nmesh->mesh = me; + nmesh->object = obj; + nmesh->new = 0; + G.totmesh++; + + return ( PyObject * ) nmesh; +} + + +Mesh *Mesh_FromPyObject( PyObject * pyobj, Object *obj ) +{ + BPy_Mesh *blen_obj; + + blen_obj = ( BPy_Mesh * ) pyobj; + if (obj) + blen_obj->object = obj; + + return blen_obj->mesh; + +} diff --git a/source/blender/python/api2_2x/Mesh.h b/source/blender/python/api2_2x/Mesh.h new file mode 100644 index 00000000000..0938f5fe8ef --- /dev/null +++ b/source/blender/python/api2_2x/Mesh.h @@ -0,0 +1,127 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* Most of this file comes from opy_nmesh.[ch] in the old bpython dir */ + +#ifndef EXPP_MESH_H +#define EXPP_MESH_H + +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "DNA_object_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "Material.h" +#include "Image.h" + +/* EXPP PyType Objects */ +extern PyTypeObject Mesh_Type; +extern PyTypeObject MVert_Type; +extern PyTypeObject PVert_Type; +extern PyTypeObject MVertSeq_Type; +extern PyTypeObject MEdge_Type; +extern PyTypeObject MFace_Type; +extern PyTypeObject MCol_Type; + +struct BPy_Object; + +/* Type checking for EXPP PyTypes */ +#define BPy_Mesh_Check(v) ((v)->ob_type == &Mesh_Type) +#define BPy_MFace_Check(v) ((v)->ob_type == &MFace_Type) +#define BPy_MEdge_Check(v) ((v)->ob_type == &MEdge_Type) +#define BPy_MVert_Check(v) ((v)->ob_type == &MVert_Type) +#define BPy_PVert_Check(v) ((v)->ob_type == &PVert_Type) +#define BPy_MCol_Check(v) ((v)->ob_type == &MCol_Type) + +/* Typedefs for the new types */ + +typedef struct { + PyObject_HEAD /* required python macro */ + MCol *color; +} BPy_MCol; /* a Mesh color: [r,g,b,a] */ + +typedef struct { + PyObject_VAR_HEAD /* required python macro */ + void * data; /* points to a Mesh or an MVert */ + int index; +} BPy_MVert; /* a Mesh vertex */ + +typedef struct { + PyObject_VAR_HEAD /* required python macro */ + Mesh * mesh; + int iter; +} BPy_MVertSeq; /* a Mesh vertex sequence */ + +typedef struct { + PyObject_VAR_HEAD /* required python macro */ + Mesh *mesh; /* points to a Mesh */ + int index; + short iter; /* char because it can only ever be between -1 and 2 */ +} BPy_MEdge; /* a Mesh edge */ + +typedef struct { + PyObject_VAR_HEAD /* required python macro */ + Mesh * mesh; + int iter; +} BPy_MEdgeSeq; /* a Mesh edge sequence */ + +typedef struct { + PyObject_VAR_HEAD /* required python macro */ + Mesh * mesh; + int index; + short iter; /* char because it can only ever be between -1 and 4 */ +} BPy_MFace; /* a Mesh face */ + +typedef struct { + PyObject_VAR_HEAD /* required python macro */ + Mesh * mesh; + int iter; +} BPy_MFaceSeq; /* a Mesh face sequence */ + +typedef struct { + PyObject_HEAD /* required python macro */ + Mesh *mesh; + Object *object; + char new; /* was mesh created or already existed? */ +} BPy_Mesh; + +/* PROTOS */ + +PyObject *Mesh_Init( void ); +PyObject *Mesh_CreatePyObject( Mesh * me, Object *obj ); +Mesh *Mesh_FromPyObject( PyObject * pyobj, Object *obj ); + +#endif /* EXPP_MESH_H */ diff --git a/source/blender/python/api2_2x/Metaball.c b/source/blender/python/api2_2x/Metaball.c new file mode 100644 index 00000000000..98dc7ea1127 --- /dev/null +++ b/source/blender/python/api2_2x/Metaball.c @@ -0,0 +1,1189 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Jacques Guignot + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "Metaball.h" /*This must come first*/ + +#include "BKE_main.h" +#include "BKE_global.h" +#include "BKE_mball.h" +#include "BKE_library.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" /* for quat normal */ +#include "DNA_object_types.h" +#include "Mathutils.h" +#include "Material.h" +#include "gen_utils.h" +#include "gen_library.h" + +/* for dealing with materials */ +#include "MEM_guardedalloc.h" +#include "BKE_material.h" + +/* checks for the metaelement being removed */ +#define METAELEM_DEL_CHECK_PY(bpy_meta_elem) if (!(bpy_meta_elem->metaelem)) return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, "Metaball has been removed" ) ); +#define METAELEM_DEL_CHECK_INT(bpy_meta_elem) if (!(bpy_meta_elem->metaelem)) return ( EXPP_ReturnIntError( PyExc_RuntimeError, "Metaball has been removed" ) ); + +/*****************************************************************************/ +/* Python API function prototypes for the Metaball module. */ +/*****************************************************************************/ +static PyObject *M_Metaball_New( PyObject * self, PyObject * args ); +static PyObject *M_Metaball_Get( PyObject * self, PyObject * args ); + +/*****************************************************************************/ +/* The following string definitions are used for documentation strings. */ +/* In Python these will be written to the console when doing a */ +/* Blender.Metaball.__doc__ */ +/*****************************************************************************/ +static char M_Metaball_doc[] = + "The Blender Metaball module\n\n\nMetaballs are primitive shapes\ + such as balls, pipes, boxes and planes,\ + that can join each other to create smooth,\ + organic volumes\n. The shapes themseves are called\ + 'Metaelements' and can be accessed from the Metaball module."; + +static char M_Metaball_New_doc[] = "Creates new metaball object data"; + +static char M_Metaball_Get_doc[] = "Retreives an existing metaball object data"; + +/*****************************************************************************/ +/* Python method structure definition for Blender.Metaball module: */ +/*****************************************************************************/ +struct PyMethodDef M_Metaball_methods[] = { + {"New", M_Metaball_New, METH_VARARGS, M_Metaball_New_doc}, + {"Get", M_Metaball_Get, METH_VARARGS, M_Metaball_Get_doc}, + {NULL, NULL, 0, NULL} +}; + +static PyObject *M_MetaElem_TypesDict( void ) +{ + PyObject *Types = PyConstant_New( ); + + if( Types ) { + BPy_constant *d = ( BPy_constant * ) Types; + + PyConstant_Insert( d, "BALL", PyInt_FromLong( MB_BALL ) ); + /* PyConstant_Insert( d, "TUBEX", PyInt_FromLong( MB_TUBEX ) ); - DEPRICATED */ + /* PyConstant_Insert( d, "TUBEY", PyInt_FromLong( MB_TUBEY ) ); - DEPRICATED */ + /* PyConstant_Insert( d, "TUBEZ", PyInt_FromLong( MB_TUBEZ ) ); - DEPRICATED */ + PyConstant_Insert( d, "TUBE", PyInt_FromLong( MB_TUBE ) ); + PyConstant_Insert( d, "PLANE", PyInt_FromLong( MB_PLANE ) ); + PyConstant_Insert( d, "ELIPSOID",PyInt_FromLong( MB_ELIPSOID ) ); + PyConstant_Insert( d, "CUBE", PyInt_FromLong( MB_CUBE ) ); + } + + return Types; +} + +static PyObject *M_MetaElem_UpdateDict( void ) +{ + PyObject *Update = PyConstant_New( ); + + if( Update ) { + BPy_constant *d = ( BPy_constant * ) Update; + PyConstant_Insert( d, "ALWAYS", PyInt_FromLong( MB_UPDATE_ALWAYS ) ); + PyConstant_Insert( d, "HALFRES",PyInt_FromLong( MB_UPDATE_HALFRES ) ); + PyConstant_Insert( d, "FAST", PyInt_FromLong( MB_UPDATE_FAST ) ); + PyConstant_Insert( d, "NEVER", PyInt_FromLong( MB_UPDATE_NEVER ) ); + } + + return Update; +} + +/*****************************************************************************/ +/* Python BPy_Metaball methods declarations: */ +/*****************************************************************************/ +static PyObject *Metaball_getElements( BPy_Metaball * self ); +static PyObject *Metaball_getMaterials( BPy_Metaball * self ); +static int Metaball_setMaterials( BPy_Metaball * self, PyObject * value ); +static PyObject *Metaball_getWiresize( BPy_Metaball * self ); +static int Metaball_setWiresize( BPy_Metaball * self, PyObject * value ); +static PyObject *Metaball_getRendersize( BPy_Metaball * self ); +static int Metaball_setRendersize( BPy_Metaball * self, PyObject * value); +static PyObject *Metaball_getThresh( BPy_Metaball * self ); +static int Metaball_setThresh( BPy_Metaball * self, PyObject * args ); +static PyObject *Metaball_getUpdate( BPy_Metaball * self ); +static int Metaball_setUpdate( BPy_Metaball * self, PyObject * args ); +static PyObject *Metaball_copy( BPy_Metaball * self ); + +/*****************************************************************************/ +/* Python BPy_Metaball methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_Metaball_methods[] = { + /* name, method, flags, doc */ + {"__copy__", ( PyCFunction ) Metaball_copy, + METH_NOARGS, "() - Return a copy of this metaball"}, + {"copy", ( PyCFunction ) Metaball_copy, + METH_NOARGS, "() - Return a copy of this metaball"}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python BPy_Metaelem methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_Metaelem_methods[] = { + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python Metaball_Type callback function prototypes: */ +/*****************************************************************************/ +static PyObject *Metaball_repr( BPy_Metaball * self ); +static int Metaball_compare( BPy_Metaball * a, BPy_Metaball * b ); + +/*****************************************************************************/ +/* Python Metaelem_Type callback function prototypes: */ +/*****************************************************************************/ +static void Metaelem_dealloc( BPy_Metaelem * self ); +static PyObject *Metaelem_repr( BPy_Metaelem * self ); +static int Metaelem_compare( BPy_Metaelem * a, BPy_Metaelem * b ); + +static PyObject *Metaelem_getType( BPy_Metaelem *self ); +static int Metaelem_setType( BPy_Metaelem * self, PyObject * args ); +static PyObject *Metaelem_getCoord( BPy_Metaelem * self ); +static int Metaelem_setCoord( BPy_Metaelem * self, VectorObject * value ); +static PyObject *Metaelem_getDims( BPy_Metaelem * self ); +static int Metaelem_setDims( BPy_Metaelem * self, VectorObject * value ); +static PyObject *Metaelem_getQuat( BPy_Metaelem * self ); +static int Metaelem_setQuat( BPy_Metaelem * self, QuaternionObject * value ); +static PyObject *Metaelem_getStiffness( BPy_Metaelem * self ); +static int Metaelem_setStiffness( BPy_Metaelem * self, PyObject * value ); +static PyObject *Metaelem_getRadius( BPy_Metaelem * self ); +static int Metaelem_setRadius( BPy_Metaelem * self, PyObject * value ); + +static PyObject *Metaelem_getMFlagBits( BPy_Metaelem * self, void * type ); +static int Metaelem_setMFlagBits( BPy_Metaelem * self, PyObject * value, void * type ); + +/*****************************************************************************/ +/* Python attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef BPy_Metaball_getseters[] = { + GENERIC_LIB_GETSETATTR, + {"materials", + (getter)Metaball_getMaterials, (setter)Metaball_setMaterials, + "Number of metaball users", + NULL}, + {"elements", + (getter)Metaball_getElements, (setter)NULL, + "Elements in this metaball", + NULL}, + {"wiresize", + (getter)Metaball_getWiresize, (setter)Metaball_setWiresize, + "The density to draw the metaball in the 3D view", + NULL}, + {"rendersize", + (getter)Metaball_getRendersize, (setter)Metaball_setRendersize, + "The density to render wire", + NULL}, + {"thresh", + (getter)Metaball_getThresh, (setter)Metaball_setThresh, + "The density to render wire", + NULL}, + {"update", + (getter)Metaball_getUpdate, (setter)Metaball_setUpdate, + "The setting for updating this metaball data", + NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + + +/*****************************************************************************/ +/* Python TypeMetaball structure definition: */ +/*****************************************************************************/ +PyTypeObject Metaball_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender Metaball", /* char *tp_name; */ + sizeof( BPy_Metaball ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) Metaball_compare, /* cmpfunc tp_compare; */ + ( reprfunc ) Metaball_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_Metaball_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_Metaball_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + + +static PyGetSetDef BPy_Metaelem_getseters[] = { + {"type", + (getter)Metaelem_getType, (setter)Metaelem_setType, + "Metaelem Type", + NULL}, + {"co", + (getter)Metaelem_getCoord, (setter)Metaelem_setCoord, + "Metaelem Location", + NULL}, + {"quat", + (getter)Metaelem_getQuat, (setter)Metaelem_setQuat, + "Metaelem Rotation Quat", + NULL}, + {"dims", + (getter)Metaelem_getDims, (setter)Metaelem_setDims, + "Metaelem Dimensions", + NULL}, + {"stiffness", + (getter)Metaelem_getStiffness, (setter)Metaelem_setStiffness, + "MetaElem stiffness", + NULL}, + {"radius", + (getter)Metaelem_getRadius, (setter)Metaelem_setRadius, + "The radius of the MetaElem", + NULL}, + {"negative", + (getter)Metaelem_getMFlagBits, (setter)Metaelem_setMFlagBits, + "The density to render wire", + (void *)MB_NEGATIVE}, + {"hide", + (getter)Metaelem_getMFlagBits, (setter)Metaelem_setMFlagBits, + "The density to render wire", + (void *)MB_HIDE}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + + +/*****************************************************************************/ +/* Python TypeMetaelem structure definition: */ +/*****************************************************************************/ +PyTypeObject Metaelem_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender Metaelem", /* char *tp_name; */ + sizeof( BPy_Metaelem ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + ( destructor ) Metaelem_dealloc,/* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) Metaelem_compare, /* cmpfunc tp_compare; */ + ( reprfunc ) Metaelem_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_Metaelem_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_Metaelem_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + + +/*****************************************************************************/ +/* Function: M_Metaball_New */ +/* Python equivalent: Blender.Metaball.New */ +/*****************************************************************************/ +static PyObject *M_Metaball_New( PyObject * self, PyObject * args ) +{ + char *name = 0; + BPy_Metaball *pymball; /* for Data object wrapper in Python */ + MetaBall *blmball; /* for actual Data we create in Blender */ + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "Metaball.New() - expected string argument (or nothing)" ) ); + + /* first create the MetaBall Data in Blender */ + if (name) + blmball = add_mball( name ); + else + blmball = add_mball( "Meta" ); + + if( blmball ) { + /* return user count to zero since add_mball() incref'ed it */ + blmball->id.us = 0; + /* now create the wrapper obj in Python */ + pymball = + ( BPy_Metaball * ) PyObject_NEW( BPy_Metaball, + &Metaball_Type ); + } else + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Metaball.New() - couldn't create data in Blender" ) ); + + if( pymball == NULL ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create MetaBall Data object" ) ); + + pymball->metaball = blmball; + /*link Python mballer wrapper to Blender MetaBall */ + + return ( PyObject * ) pymball; +} + + +/*****************************************************************************/ +/* Function: M_Metaball_Get */ +/* Python equivalent: Blender.Metaball.Get */ +/* Description: Receives a string and returns the metaball data obj */ +/* whose name matches the string. If no argument is */ +/* passed in, a list of all metaball data names in the */ +/* current scene is returned. */ +/*****************************************************************************/ +static PyObject *M_Metaball_Get( PyObject * self, PyObject * args ) +{ + char *name = NULL; + MetaBall *mball_iter = NULL; + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "Metaball.Get() - expected string argument (or nothing)" ) ); + + if( name ) { /* (name) - Search mball by name */ + mball_iter = ( MetaBall * ) GetIdFromList( &( G.main->mball ), name ); + + if (!mball_iter) { + char error_msg[128]; + PyOS_snprintf( error_msg, sizeof( error_msg ), + "Metaball.Get(\"%s\") - not found", name ); + return ( EXPP_ReturnPyObjError + ( PyExc_NameError, error_msg ) ); + } + return Metaball_CreatePyObject(mball_iter); + + } else { /* () - return a list of all mballs in the scene */ + + PyObject *mballlist = PyList_New( BLI_countlist( &( G.main->mball ) ) ); + int index=0; + + if( mballlist == NULL ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "MetaBall.Get() - couldn't create PyList" ) ); + + mball_iter = G.main->mball.first; + while( mball_iter ) { + PyList_SetItem( mballlist, index, Metaball_CreatePyObject(mball_iter) ); + index++; + mball_iter = mball_iter->id.next; + } + return mballlist; + } + +} + + +/*****************************************************************************/ +/* Function: initObject */ +/*****************************************************************************/ +PyObject *Metaball_Init( void ) +{ + PyObject *submodule; + PyObject *Types= M_MetaElem_TypesDict( ); + PyObject *Update= M_MetaElem_UpdateDict( ); + + if( PyType_Ready( &Metaball_Type ) < 0 ) + return NULL; + if( PyType_Ready( &Metaelem_Type ) < 0 ) + return NULL; + if( PyType_Ready( &MetaElemSeq_Type ) < 0 ) + return NULL; + + submodule = Py_InitModule3( "Blender.Metaball", M_Metaball_methods, M_Metaball_doc); + + if( Types ) + PyModule_AddObject( submodule, "Types", Types ); + PyModule_AddObject( submodule, "Update", Update ); + + /*Add SUBMODULES to the module*/ + /*PyDict_SetItemString(dict, "Constraint", Constraint_Init()); */ /*creates a *new* module*/ + return submodule; +} + +MetaBall *Metaball_FromPyObject( PyObject * pyobj ) +{ + return ( ( BPy_Metaball * ) pyobj )->metaball; +} + +static PyObject *Metaball_getMaterials( BPy_Metaball *self ) +{ + return EXPP_PyList_fromMaterialList( self->metaball->mat, + self->metaball->totcol, 1 ); +} +static int Metaball_setMaterials( BPy_Metaball *self, PyObject * value ) +{ + Material **matlist; + int len; + + if( !PySequence_Check( value ) || + !EXPP_check_sequence_consistency( value, &Material_Type ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "metaball.materials - list should only contain materials or None)" ); + + len = PyList_Size( value ); + if( len > 16 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "metaball.materials - list can't have more than 16 materials" ); + + /* free old material list (if it exists) and adjust user counts */ + if( self->metaball->mat ) { + MetaBall *mb = self->metaball; + int i; + for( i = mb->totcol; i-- > 0; ) + if( mb->mat[i] ) + mb->mat[i]->id.us--; + MEM_freeN( mb->mat ); + } + + /* build the new material list, increment user count, store it */ + + matlist = EXPP_newMaterialList_fromPyList( value ); + EXPP_incr_mats_us( matlist, len ); + self->metaball->mat = matlist; + self->metaball->totcol = (short)len; + +/**@ This is another ugly fix due to the weird material handling of blender. + * it makes sure that object material lists get updated (by their length) + * according to their data material lists, otherwise blender crashes. + * It just stupidly runs through all objects...BAD BAD BAD. + */ + + test_object_materials( ( ID * ) self->metaball ); + + return 0; +} + +static PyObject *Metaball_getWiresize( BPy_Metaball * self ) +{ + return PyFloat_FromDouble( self->metaball->wiresize ); +} + +static int Metaball_setWiresize( BPy_Metaball * self, PyObject * value ) +{ + float param; + if( !PyNumber_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "metaball.wiresize - expected float argument" ); + + param = (float)PyFloat_AsDouble( value ); + + self->metaball->wiresize = EXPP_ClampFloat(param, 0.05f, 1.0); + return 0; + +} +static PyObject *Metaball_getRendersize( BPy_Metaball * self ) +{ + return PyFloat_FromDouble( self->metaball->rendersize ); +} + +static int Metaball_setRendersize( BPy_Metaball * self, PyObject * value ) +{ + + float param; + if( !PyNumber_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "metaball.rendersize - expected float argument" ); + + param = (float)PyFloat_AsDouble( value ); + + self->metaball->rendersize = EXPP_ClampFloat(param, 0.05f, 1.0); + return 0; +} + +static PyObject *Metaball_getThresh( BPy_Metaball * self ) +{ + return PyFloat_FromDouble( self->metaball->thresh ); +} + +static int Metaball_setThresh( BPy_Metaball * self, PyObject * value ) +{ + + float param; + if( !PyNumber_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "metaball.thresh - expected float argument" ); + + param = (float)PyFloat_AsDouble( value ); + + self->metaball->thresh = EXPP_ClampFloat(param, 0.0, 5.0); + return 0; +} + +static PyObject *Metaball_getUpdate( BPy_Metaball * self ) +{ + return PyInt_FromLong( (long)self->metaball->flag ); +} + +static int Metaball_setUpdate( BPy_Metaball * self, PyObject * value ) +{ + + int param; + if( !PyInt_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "metaball.update - expected an int argument" ); + + param = (int)PyInt_AS_LONG( value ); + + self->metaball->flag = EXPP_ClampInt( param, 0, 3 ); + return 0; +} + +static PyObject *Metaball_copy( BPy_Metaball * self ) +{ + BPy_Metaball *pymball; /* for Data object wrapper in Python */ + MetaBall *blmball; /* for actual Data we create in Blender */ + + blmball = copy_mball( self->metaball ); /* first create the MetaBall Data in Blender */ + + if( blmball ) { + /* return user count to zero since add_mball() incref'ed it */ + blmball->id.us = 0; + /* now create the wrapper obj in Python */ + pymball = + ( BPy_Metaball * ) PyObject_NEW( BPy_Metaball, + &Metaball_Type ); + } else + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "metaball.__copy__() - couldn't create data in Blender" ) ); + + if( pymball == NULL ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "metaball.__copy__() - couldn't create data in Blender" ) ); + + pymball->metaball = blmball; + + return ( PyObject * ) pymball; +} + + +/* These are needed by Object.c */ +PyObject *Metaball_CreatePyObject( MetaBall * mball) +{ + BPy_Metaball *py_mball= PyObject_NEW( BPy_Metaball, &Metaball_Type ); + + if( !py_mball ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create BPy_Metaball object" ); + + py_mball->metaball= mball; + + return ( PyObject * ) py_mball; +} + + +static PyObject *MetaElemSeq_CreatePyObject(BPy_Metaball *self, MetaElem *iter) +{ + BPy_MetaElemSeq *seq = PyObject_NEW( BPy_MetaElemSeq, &MetaElemSeq_Type); + seq->bpymetaball = self; Py_INCREF(self); + seq->iter= iter; + return (PyObject *)seq; +} + +/* + * Element, get an instance of the iterator. + */ +static PyObject *Metaball_getElements( BPy_Metaball * self ) +{ + return MetaElemSeq_CreatePyObject(self, NULL); +} + +/* + * Metaelem dealloc - free from memory + */ +/* This is a callback function for the BPy_Metaelem type. It is */ +static void Metaelem_dealloc( BPy_Metaelem * self ) +{ + self->metaelem= NULL; /* so any references to the same bpyobject will raise an error */ + PyObject_DEL( self ); +} + +/* + * elem.type - int to set the shape of the element + */ +static PyObject *Metaelem_getType( BPy_Metaelem *self ) +{ + METAELEM_DEL_CHECK_PY(self); + + return PyInt_FromLong( self->metaelem->type ); +} +static int Metaelem_setType( BPy_Metaelem * self, PyObject * value ) +{ + int type; + if( !PyInt_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "metaelem.type - expected an integer (bitmask) as argument" ); + + METAELEM_DEL_CHECK_INT(self); + + type = PyInt_AS_LONG( value ); + + if( (type < 0) || ( type > ( MB_BALL | MB_TUBEX | MB_TUBEY | MB_TUBEZ | MB_TUBE | MB_PLANE | MB_ELIPSOID | MB_CUBE ) )) + return EXPP_ReturnIntError( PyExc_ValueError, + "metaelem.type - value out of range" ); + + self->metaelem->type= type; + return 0; +} + +/* + * elem.co - non wrapped vector representing location + */ +static PyObject *Metaelem_getCoord( BPy_Metaelem * self ) +{ + float co[3]; + + METAELEM_DEL_CHECK_PY(self); + + co[0]= self->metaelem->x; + co[1]= self->metaelem->y; + co[2]= self->metaelem->z; + + return newVectorObject( co, 3, Py_NEW ); +} +static int Metaelem_setCoord( BPy_Metaelem * self, VectorObject * value ) +{ + + if( !VectorObject_Check( value ) || value->size != 3 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "metaelem.co - expected vector argument of size 3" ); + + METAELEM_DEL_CHECK_INT(self); + + self->metaelem->x= value->vec[0]; + self->metaelem->y= value->vec[1]; + self->metaelem->z= value->vec[2]; + return 0; +} + +/* + * elem.dims - non wrapped vector representing the xyz dimensions + * only effects some element types + */ +static PyObject *Metaelem_getDims( BPy_Metaelem * self ) +{ + float co[3]; + METAELEM_DEL_CHECK_PY(self); + + co[0]= self->metaelem->expx; + co[1]= self->metaelem->expy; + co[2]= self->metaelem->expz; + return newVectorObject( co, 3, Py_NEW ); +} +static int Metaelem_setDims( BPy_Metaelem * self, VectorObject * value ) +{ + if( !VectorObject_Check( value ) || value->size != 3 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "metaelem.dims - expected vector argument of size 3" ); + + METAELEM_DEL_CHECK_INT(self); + + self->metaelem->expx= EXPP_ClampFloat(value->vec[0], 0.0, 20.0); + self->metaelem->expy= EXPP_ClampFloat(value->vec[1], 0.0, 20.0); + self->metaelem->expz= EXPP_ClampFloat(value->vec[2], 0.0, 20.0); + return 0; +} + +/* + * elem.quat - non wrapped quat representing the rotation + * only effects some element types - a rotated ball has no effect for eg. + */ +static PyObject *Metaelem_getQuat( BPy_Metaelem * self ) +{ + METAELEM_DEL_CHECK_PY(self); + return newQuaternionObject(self->metaelem->quat, Py_NEW); +} +static int Metaelem_setQuat( BPy_Metaelem * self, QuaternionObject * value ) +{ + int i; + if( !QuaternionObject_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "metaelem.quat - expected quat argument" ); + + METAELEM_DEL_CHECK_INT(self); + + for (i = 0; i < 4; i++) + self->metaelem->quat[i]= value->quat[i]; + + /* need to normalize or metaball drawing can go into an infinate loop */ + NormalQuat(self->metaelem->quat); + + return 0; +} + +/* + * elem.hide and elem.sel - get/set true false + */ +static PyObject *Metaelem_getMFlagBits( BPy_Metaelem * self, void * type ) +{ + METAELEM_DEL_CHECK_PY(self); + return EXPP_getBitfield( &(self->metaelem->flag), (int)((long)type ), 'h' ); +} +static int Metaelem_setMFlagBits( BPy_Metaelem * self, PyObject * value, + void * type ) +{ + METAELEM_DEL_CHECK_INT(self); + return EXPP_setBitfield( value, &(self->metaelem->flag), + (int)((long)type), 'h' ); +} + +/* + * elem.stiffness - floating point, the volume of this element. + */ +static PyObject *Metaelem_getStiffness( BPy_Metaelem *self ) +{ + METAELEM_DEL_CHECK_PY(self); + return PyFloat_FromDouble( self->metaelem->s ); +} +static int Metaelem_setStiffness( BPy_Metaelem *self, PyObject *value) +{ + if( !PyNumber_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "metaelem.stiffness - expected float argument" ); + + self->metaelem->s = EXPP_ClampFloat((float)PyFloat_AsDouble( value ), 0.0, 10.0); + return 0; +} + +/* + * elem.radius- floating point, the size if the element + */ +static PyObject *Metaelem_getRadius( BPy_Metaelem *self ) +{ + METAELEM_DEL_CHECK_PY(self); + return PyFloat_FromDouble( self->metaelem->rad ); +} +static int Metaelem_setRadius( BPy_Metaelem *self, PyObject *value) +{ + if( !PyNumber_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "metaelem.radius - expected float argument" ); + + self->metaelem->rad = /* is 5000 too small? */ + EXPP_ClampFloat((float)PyFloat_AsDouble( value ), 0.0, 5000.0); + + return 0; +} + + +/* + * callback functions for comparison. + * It compares two Metaball_Type objects. Only the "==" and "!=" + * comparisons are meaninful. Returns 0 for equality and -1 if + * they don't point to the same Blender struct. + * In Python it becomes 1 if they are equal, 0 otherwise. + */ +static int Metaball_compare( BPy_Metaball * a, BPy_Metaball * b ) +{ + MetaBall *pa = a->metaball, *pb = b->metaball; + return ( pa == pb ) ? 0 : -1; +} + +static int MetaElemSeq_compare( BPy_MetaElemSeq * a, BPy_MetaElemSeq * b ) +{ + MetaBall *pa = a->bpymetaball->metaball, *pb = b->bpymetaball->metaball; + return ( pa == pb ) ? 0 : -1; +} + +static int Metaelem_compare( BPy_Metaelem * a, BPy_Metaelem * b ) +{ + MetaElem *pa = a->metaelem, *pb = b->metaelem; + return ( pa == pb ) ? 0 : -1; +} + +/* + * repr function + * callback functions building meaninful string to representations + */ +static PyObject *Metaball_repr( BPy_Metaball * self ) +{ + return PyString_FromFormat( "[Metaball \"%s\"]", + self->metaball->id.name + 2 ); +} + +static PyObject *Metaelem_repr( BPy_Metaelem * self ) +{ + return PyString_FromString( "Metaelem" ); +} + +static PyObject *MetaElemSeq_repr( BPy_MetaElemSeq * self ) +{ + return PyString_FromFormat( "[Metaball Iterator \"%s\"]", + self->bpymetaball->metaball->id.name + 2 ); +} + + + +/* + * MeteElem Seq sequence + */ + +static PyObject *MetaElem_CreatePyObject( MetaElem *metaelem ) +{ + BPy_Metaelem *elem= PyObject_NEW( BPy_Metaelem, &Metaelem_Type); + elem->metaelem = metaelem; Py_INCREF(elem); + return (PyObject *)elem; +} + +static int MetaElemSeq_len( BPy_MetaElemSeq * self ) +{ + return BLI_countlist( &( self->bpymetaball->metaball->elems ) ); +} + + +static PySequenceMethods MetaElemSeq_as_sequence = { + ( inquiry ) MetaElemSeq_len, /* sq_length */ + ( binaryfunc ) 0, /* sq_concat */ + ( intargfunc ) 0, /* sq_repeat */ + ( intargfunc ) 0, /* sq_item */ + ( intintargfunc ) 0, /* sq_slice */ + ( intobjargproc ) 0, /* sq_ass_item */ + ( intintobjargproc ) 0, /* sq_ass_slice */ + 0,0,0, +}; + +/************************************************************************ + * + * Python MetaElemSeq_Type iterator (iterates over Metaballs) + * + ************************************************************************/ + +/* + * Initialize the interator + */ + +static PyObject *MetaElemSeq_getIter( BPy_MetaElemSeq * self ) +{ + if (!self->iter) { /* not alredy looping on this data, */ + self->iter = self->bpymetaball->metaball->elems.first; + return EXPP_incr_ret ( (PyObject *) self ); + } else + return MetaElemSeq_CreatePyObject(self->bpymetaball, self->bpymetaball->metaball->elems.first); +} + +/* + * Return next MetaElem. + */ + +static PyObject *MetaElemSeq_nextIter( BPy_MetaElemSeq * self ) +{ + PyObject *object; + if( !(self->iter) || !(self->bpymetaball->metaball) ) { + self->iter= NULL; + return EXPP_ReturnPyObjError( PyExc_StopIteration, + "iterator at end" ); + } + + object= MetaElem_CreatePyObject( self->iter ); + self->iter= self->iter->next; + return object; +} + +/* + * Adds and returns a new metaelement, + * no args are taken so the returned metaball must be modified after adding. + * Accessed as mball.elements.add() where mball is a python metaball data type. + */ +static PyObject *MetaElemSeq_add( BPy_MetaElemSeq * self ) +{ + MetaElem *ml; + + ml = MEM_callocN( sizeof( MetaElem ), "metaelem" ); + BLI_addhead( &( self->bpymetaball->metaball->elems ), ml ); + ml->x = 0; + ml->y = 0; + ml->z = 0; + ml->quat[0]= 1.0; + ml->quat[1]= 0.0; + ml->quat[2]= 0.0; + ml->quat[3]= 0.0; + ml->rad = 2; + ml->s = 2.0; + ml->flag = SELECT; + ml->type = 0; + ml->expx = 1; + ml->expy = 1; + ml->expz = 1; + ml->type = MB_BALL; + + return MetaElem_CreatePyObject(ml); +} + + +/* + * removes a metaelement if it is a part of the metaball, + * no args are taken so the returned metaball must be modified after adding. + * Accessed as mball.elements.add() where mball is a python metaball data type. + */ +static PyObject *MetaElemSeq_remove( BPy_MetaElemSeq * self, BPy_Metaelem *elem ) +{ + MetaElem *ml_iter, *ml_py; + + if( !BPy_Metaelem_Check(elem) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "elements.remove(metaelem) - expected a Metaball element" ); + + METAELEM_DEL_CHECK_PY(elem); + + ml_py= elem->metaelem; + + for (ml_iter= self->bpymetaball->metaball->elems.first; ml_iter; ml_iter= ml_iter->next) { + if (ml_py == ml_iter) { + elem->metaelem= NULL; + BLI_freelinkN( &(self->bpymetaball->metaball->elems), ml_py); + Py_RETURN_NONE; + } + } + + return EXPP_ReturnPyObjError( PyExc_ValueError, + "elements.remove(elem): elem not in meta elements" ); + +} + +static struct PyMethodDef BPy_MetaElemSeq_methods[] = { + {"add", (PyCFunction)MetaElemSeq_add, METH_NOARGS, + "add metaelem to metaball data"}, + {"remove", (PyCFunction)MetaElemSeq_remove, METH_O, + "remove element from metaball data"}, + {NULL, NULL, 0, NULL} +}; + +/************************************************************************ + * + * Python MetaElemSeq_Type standard operations + * + ************************************************************************/ + +static void MetaElemSeq_dealloc( BPy_MetaElemSeq * self ) +{ + Py_DECREF(self->bpymetaball); + PyObject_DEL( self ); +} + +/*****************************************************************************/ +/* Python MetaElemSeq_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject MetaElemSeq_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender MetaElemSeq", /* char *tp_name; */ + sizeof( BPy_MetaElemSeq ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + ( destructor ) MetaElemSeq_dealloc,/* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) MetaElemSeq_compare, /* cmpfunc tp_compare; */ + ( reprfunc ) MetaElemSeq_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + &MetaElemSeq_as_sequence, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + ( getiterfunc) MetaElemSeq_getIter, /* getiterfunc tp_iter; */ + ( iternextfunc ) MetaElemSeq_nextIter, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_MetaElemSeq_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + NULL, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + diff --git a/source/blender/python/api2_2x/Metaball.h b/source/blender/python/api2_2x/Metaball.h new file mode 100644 index 00000000000..a54424302df --- /dev/null +++ b/source/blender/python/api2_2x/Metaball.h @@ -0,0 +1,81 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Jacques Guignot + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef EXPP_METABALL_H +#define EXPP_METABALL_H + +#include +#include "DNA_meta_types.h" + + +extern PyTypeObject Metaball_Type; + +#define BPy_Metaball_Check(v) ((v)->ob_type==&Metaball_Type) + + +/* Python BPy_Metaball structure definition */ +typedef struct { + PyObject_HEAD /* required py macro */ + MetaBall * metaball; /* libdata must be second */ +} BPy_Metaball; + + +extern PyTypeObject Metaelem_Type; + +#define BPy_Metaelem_Check(v) ((v)->ob_type==&Metaelem_Type) + +/* Python BPy_Metaelem structure definition */ +typedef struct { + PyObject_HEAD /* required py macro */ + MetaElem * metaelem; +} BPy_Metaelem; + +extern PyTypeObject MetaElemSeq_Type; + +#define BPy_MetaElemSeq_Check(v) ((v)->ob_type==&MetaElemSeq_Type) + +/* Python BPy_MetaElemSeq structure definition */ +typedef struct { + PyObject_HEAD /* required py macro */ + BPy_Metaball *bpymetaball; /* link to the python group so we can know if its been removed */ + MetaElem * iter; /* so we can iterate over the objects */ +} BPy_MetaElemSeq; + +/* + * prototypes + */ + +PyObject *Metaball_Init( void ); +PyObject *Metaball_CreatePyObject( MetaBall * mball ); +MetaBall *Metaball_FromPyObject( PyObject * py_obj ); + +#endif /* EXPP_METABALL_H */ diff --git a/source/blender/python/api2_2x/Modifier.c b/source/blender/python/api2_2x/Modifier.c new file mode 100644 index 00000000000..a1b052eb674 --- /dev/null +++ b/source/blender/python/api2_2x/Modifier.c @@ -0,0 +1,1693 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * This is a new part of Blender. + * + * Contributor(s): Ken Hughes, Campbell Barton + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* TODO, accessing a modifier sequence of a deleted object will crash blender at the moment, not sure how to fix this. */ + + +#include "Modifier.h" /*This must come first*/ + +#include "DNA_object_types.h" +#include "DNA_effect_types.h" +#include "DNA_armature_types.h" +#include "DNA_vec_types.h" + +#include "BKE_main.h" +#include "BKE_global.h" +#include "BKE_modifier.h" +#include "BKE_library.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "MEM_guardedalloc.h" +#include "butspace.h" +#include "blendef.h" +#include "mydevice.h" + +#include "Object.h" +#include "Texture.h" +#include "Mathutils.h" +#include "gen_utils.h" +#include "gen_library.h" + +/* checks for the scene being removed */ +#define MODIFIER_DEL_CHECK_PY(bpy_modifier) if (!(bpy_modifier->md)) return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, "Modifier has been removed" ) ) +#define MODIFIER_DEL_CHECK_INT(bpy_modifier) if (!(bpy_modifier->md)) return ( EXPP_ReturnIntError( PyExc_RuntimeError, "Modifier has been removed" ) ) + +enum mod_constants { + /*Apply to all modifiers*/ + EXPP_MOD_RENDER = 0, + EXPP_MOD_REALTIME, + EXPP_MOD_EDITMODE, + EXPP_MOD_ONCAGE, + + /*GENERIC*/ + EXPP_MOD_OBJECT, /*ARMATURE, LATTICE, CURVE, BOOLEAN, ARRAY*/ + EXPP_MOD_VERTGROUP, /*ARMATURE, LATTICE, CURVE, SMOOTH, CAST*/ + EXPP_MOD_LIMIT, /*ARRAY, MIRROR*/ + EXPP_MOD_FLAG, /*MIRROR, WAVE*/ + EXPP_MOD_COUNT, /*DECIMATOR, ARRAY*/ + EXPP_MOD_LENGTH, /*BUILD, ARRAY*/ + EXPP_MOD_FACTOR, /*SMOOTH, CAST*/ + EXPP_MOD_ENABLE_X, /*SMOOTH, CAST*/ + EXPP_MOD_ENABLE_Y, /*SMOOTH, CAST*/ + EXPP_MOD_ENABLE_Z, /*SMOOTH, CAST*/ + EXPP_MOD_TYPES, /*SUBSURF, CAST*/ + + /*SUBSURF SPECIFIC*/ + EXPP_MOD_LEVELS, + EXPP_MOD_RENDLEVELS, + EXPP_MOD_OPTIMAL, + EXPP_MOD_UV, + + /*ARMATURE SPECIFIC*/ + EXPP_MOD_ENVELOPES, + + /*ARRAY SPECIFIC*/ + EXPP_MOD_OBJECT_OFFSET, + EXPP_MOD_OBJECT_CURVE, + EXPP_MOD_OFFSET_VEC, + EXPP_MOD_SCALE_VEC, + EXPP_MOD_MERGE_DIST, + + /*BUILD SPECIFIC*/ + EXPP_MOD_START, + EXPP_MOD_SEED, + EXPP_MOD_RANDOMIZE, + + /*MIRROR SPECIFIC*/ + EXPP_MOD_AXIS_X, + EXPP_MOD_AXIS_Y, + EXPP_MOD_AXIS_Z, + + /*DECIMATE SPECIFIC*/ + EXPP_MOD_RATIO, + + /*WAVE SPECIFIC*/ + EXPP_MOD_STARTX, + EXPP_MOD_STARTY, + EXPP_MOD_HEIGHT, + EXPP_MOD_WIDTH, + EXPP_MOD_NARROW, + EXPP_MOD_SPEED, + EXPP_MOD_DAMP, + EXPP_MOD_LIFETIME, + EXPP_MOD_TIMEOFFS, + + /*BOOLEAN SPECIFIC*/ + EXPP_MOD_OPERATION, + + /*EDGE SPLIT SPECIFIC */ + EXPP_MOD_EDGESPLIT_ANGLE, + EXPP_MOD_EDGESPLIT_FROM_ANGLE, + EXPP_MOD_EDGESPLIT_FROM_SHARP, + + /* DISPLACE */ + EXPP_MOD_UVLAYER, + EXPP_MOD_MID_LEVEL, + EXPP_MOD_STRENGTH, + EXPP_MOD_TEXTURE, + EXPP_MOD_MAPPING, + EXPP_MOD_DIRECTION, + + /* SMOOTH */ + EXPP_MOD_REPEAT, + + /* CAST */ + EXPP_MOD_RADIUS, + EXPP_MOD_SIZE, + EXPP_MOD_USE_OB_TRANSFORM, + EXPP_MOD_SIZE_FROM_RADIUS + + /* yet to be implemented */ + /* EXPP_MOD_HOOK_,*/ + /* , */ +}; + +/*****************************************************************************/ +/* Python BPy_Modifier methods declarations: */ +/*****************************************************************************/ +static PyObject *Modifier_getName( BPy_Modifier * self ); +static int Modifier_setName( BPy_Modifier * self, PyObject *arg ); +static PyObject *Modifier_getType( BPy_Modifier * self ); +static PyObject *Modifier_reset( BPy_Modifier * self ); + +static PyObject *Modifier_getData( BPy_Modifier * self, PyObject * key ); +static int Modifier_setData( BPy_Modifier * self, PyObject * key, + PyObject * value ); + +/*****************************************************************************/ +/* Python BPy_Modifier methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_Modifier_methods[] = { + /* name, method, flags, doc */ + {"reset", (PyCFunction)Modifier_reset, METH_NOARGS, + "resets a hook modifier location"}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python BPy_Modifier attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef BPy_Modifier_getseters[] = { + {"name", + (getter)Modifier_getName, (setter)Modifier_setName, + "Modifier name", NULL}, + {"type", + (getter)Modifier_getType, (setter)NULL, + "Modifier type (read only)", NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/*****************************************************************************/ +/* Python Modifier_Type Mapping Methods table: */ +/*****************************************************************************/ +static PyMappingMethods Modifier_as_mapping = { + NULL, /* mp_length */ + ( binaryfunc ) Modifier_getData, /* mp_subscript */ + ( objobjargproc ) Modifier_setData, /* mp_ass_subscript */ +}; + +/*****************************************************************************/ +/* Python Modifier_Type callback function prototypes: */ +/*****************************************************************************/ +static PyObject *Modifier_repr( BPy_Modifier * self ); + +/*****************************************************************************/ +/* Python Modifier_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject Modifier_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender Modifier", /* char *tp_name; */ + sizeof( BPy_Modifier ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + ( reprfunc ) Modifier_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + &Modifier_as_mapping, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_Modifier_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_Modifier_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +/*****************************************************************************/ +/* Python BPy_Modifier methods: */ +/*****************************************************************************/ + +/* + * return the name of this modifier + */ + +static PyObject *Modifier_getName( BPy_Modifier * self ) +{ + MODIFIER_DEL_CHECK_PY(self); + return PyString_FromString( self->md->name ); +} + +/* + * set the name of this modifier + */ + +static int Modifier_setName( BPy_Modifier * self, PyObject * attr ) +{ + char *name = PyString_AsString( attr ); + if( !name ) + return EXPP_ReturnIntError( PyExc_TypeError, "expected string arg" ); + + MODIFIER_DEL_CHECK_INT(self); + + BLI_strncpy( self->md->name, name, sizeof( self->md->name ) ); + + return 0; +} + +/* + * return the type of this modifier + */ + +static PyObject *Modifier_getType( BPy_Modifier * self ) +{ + MODIFIER_DEL_CHECK_PY(self); + + return PyInt_FromLong( self->md->type ); +} + +static PyObject *subsurf_getter( BPy_Modifier * self, int type ) +{ + SubsurfModifierData *md = ( SubsurfModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_TYPES: + return PyInt_FromLong( ( long )md->subdivType ); + case EXPP_MOD_LEVELS: + return PyInt_FromLong( ( long )md->levels ); + case EXPP_MOD_RENDLEVELS: + return PyInt_FromLong( ( long )md->renderLevels ); + case EXPP_MOD_OPTIMAL: + return PyBool_FromLong( ( long ) + ( md->flags & eSubsurfModifierFlag_ControlEdges ) ) ; + case EXPP_MOD_UV: + return PyBool_FromLong( ( long ) + ( md->flags & eSubsurfModifierFlag_SubsurfUv ) ) ; + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, + "key not found" ); + } +} + +static int subsurf_setter( BPy_Modifier * self, int type, + PyObject *value ) +{ + SubsurfModifierData *md = (SubsurfModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_TYPES: + return EXPP_setIValueRange( value, &md->subdivType, 0, 1, 'h' ); + case EXPP_MOD_LEVELS: + return EXPP_setIValueClamped( value, &md->levels, 1, 6, 'h' ); + case EXPP_MOD_RENDLEVELS: + return EXPP_setIValueClamped( value, &md->renderLevels, 1, 6, 'h' ); + case EXPP_MOD_OPTIMAL: + return EXPP_setBitfield( value, &md->flags, + eSubsurfModifierFlag_ControlEdges, 'h' ); + case EXPP_MOD_UV: + return EXPP_setBitfield( value, &md->flags, + eSubsurfModifierFlag_SubsurfUv, 'h' ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *armature_getter( BPy_Modifier * self, int type ) +{ + ArmatureModifierData *md = (ArmatureModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_OBJECT: + return Object_CreatePyObject( md->object ); + case EXPP_MOD_VERTGROUP: + return PyBool_FromLong( ( long )( md->deformflag & 1 ) ) ; + case EXPP_MOD_ENVELOPES: + return PyBool_FromLong( ( long )( md->deformflag & 2 ) ) ; + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int armature_setter( BPy_Modifier *self, int type, PyObject *value ) +{ + ArmatureModifierData *md = (ArmatureModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_OBJECT: + return GenericLib_assignData(value, (void **) &md->object, 0, 0, ID_OB, OB_ARMATURE); + case EXPP_MOD_VERTGROUP: + return EXPP_setBitfield( value, &md->deformflag, 1, 'h' ); + case EXPP_MOD_ENVELOPES: + return EXPP_setBitfield( value, &md->deformflag, 2, 'h' ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *lattice_getter( BPy_Modifier * self, int type ) +{ + LatticeModifierData *md = (LatticeModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_OBJECT: + return Object_CreatePyObject( md->object ); + case EXPP_MOD_VERTGROUP: + return PyString_FromString( md->name ) ; + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int lattice_setter( BPy_Modifier *self, int type, PyObject *value ) +{ + LatticeModifierData *md = (LatticeModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_OBJECT: + return GenericLib_assignData(value, (void **) &md->object, (void **) &self->object, 0, ID_OB, OB_LATTICE); + case EXPP_MOD_VERTGROUP: { + char *name = PyString_AsString( value ); + if( !name ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected string arg" ); + BLI_strncpy( md->name, name, sizeof( md->name ) ); + break; + } + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } + return 0; +} + +static PyObject *curve_getter( BPy_Modifier * self, int type ) +{ + CurveModifierData *md = (CurveModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_OBJECT: + return Object_CreatePyObject( md->object ); + case EXPP_MOD_VERTGROUP: + return PyString_FromString( md->name ) ; + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int curve_setter( BPy_Modifier *self, int type, PyObject *value ) +{ + CurveModifierData *md = (CurveModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_OBJECT: + return GenericLib_assignData(value, (void **) &md->object, (void **) &self->object, 0, ID_OB, OB_CURVE); + case EXPP_MOD_VERTGROUP: { + char *name = PyString_AsString( value ); + if( !name ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected string arg" ); + BLI_strncpy( md->name, name, sizeof( md->name ) ); + break; + } + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } + return 0; +} + +static PyObject *build_getter( BPy_Modifier * self, int type ) +{ + BuildModifierData *md = (BuildModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_START: + return PyFloat_FromDouble( ( float )md->start ); + case EXPP_MOD_LENGTH: + return PyFloat_FromDouble( ( float )md->length ); + case EXPP_MOD_SEED: + return PyInt_FromLong( ( long )md->seed ); + case EXPP_MOD_RANDOMIZE: + return PyBool_FromLong( ( long )md->randomize ) ; + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int build_setter( BPy_Modifier *self, int type, PyObject *value ) +{ + BuildModifierData *md = (BuildModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_START: + return EXPP_setFloatClamped( value, &md->start, 1.0, MAXFRAMEF ); + case EXPP_MOD_LENGTH: + return EXPP_setFloatClamped( value, &md->length, 1.0, MAXFRAMEF ); + case EXPP_MOD_SEED: + return EXPP_setIValueClamped( value, &md->seed, 1, MAXFRAME, 'i' ); + case EXPP_MOD_RANDOMIZE: + return EXPP_setBitfield( value, &md->randomize, 1, 'i' ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *mirror_getter( BPy_Modifier * self, int type ) +{ + MirrorModifierData *md = (MirrorModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_LIMIT: + return PyFloat_FromDouble( (double)md->tolerance ); + case EXPP_MOD_FLAG: + return PyBool_FromLong( (long)( md->flag & MOD_MIR_CLIPPING ) ) ; + case EXPP_MOD_AXIS_X: + return PyBool_FromLong( ( long ) + ( md->flag & MOD_MIR_AXIS_X ) ) ; + case EXPP_MOD_AXIS_Y: + return PyBool_FromLong( ( long ) + ( md->flag & MOD_MIR_AXIS_Y ) ) ; + case EXPP_MOD_AXIS_Z: + return PyBool_FromLong( ( long ) + ( md->flag & MOD_MIR_AXIS_Z ) ) ; + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int mirror_setter( BPy_Modifier *self, int type, PyObject *value ) +{ + MirrorModifierData *md = (MirrorModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_LIMIT: + return EXPP_setFloatClamped( value, &md->tolerance, 0.0, 1.0 ); + case EXPP_MOD_FLAG: + return EXPP_setBitfield( value, &md->flag, MOD_MIR_CLIPPING, 'i' ); + case EXPP_MOD_AXIS_X: + return EXPP_setBitfield( value, &md->flag, MOD_MIR_AXIS_X, 'h' ); + case EXPP_MOD_AXIS_Y: + return EXPP_setBitfield( value, &md->flag, MOD_MIR_AXIS_Y, 'h' ); + case EXPP_MOD_AXIS_Z: + return EXPP_setBitfield( value, &md->flag, MOD_MIR_AXIS_Z, 'h' ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *decimate_getter( BPy_Modifier * self, int type ) +{ + DecimateModifierData *md = (DecimateModifierData *)(self->md); + + if( type == EXPP_MOD_RATIO ) + return PyFloat_FromDouble( (double)md->percent ); + else if( type == EXPP_MOD_COUNT ) + return PyInt_FromLong( (long)md->faceCount ); + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); +} + +static int decimate_setter( BPy_Modifier *self, int type, PyObject *value ) +{ + DecimateModifierData *md = (DecimateModifierData *)(self->md); + + if( type == EXPP_MOD_RATIO ) + return EXPP_setFloatClamped( value, &md->percent, 0.0, 1.0 ); + else if( type == EXPP_MOD_COUNT ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "value is read-only" ); + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); +} + +static PyObject *smooth_getter( BPy_Modifier * self, int type ) +{ + SmoothModifierData *md = (SmoothModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_FACTOR: + return PyFloat_FromDouble( (double)md->fac ); + case EXPP_MOD_REPEAT: + return PyInt_FromLong( (long)md->repeat ); + case EXPP_MOD_VERTGROUP: + return PyString_FromString( md->defgrp_name ) ; + case EXPP_MOD_ENABLE_X: + return EXPP_getBitfield( &md->flag, MOD_SMOOTH_X, 'h' ); + case EXPP_MOD_ENABLE_Y: + return EXPP_getBitfield( &md->flag, MOD_SMOOTH_Y, 'h' ); + case EXPP_MOD_ENABLE_Z: + return EXPP_getBitfield( &md->flag, MOD_SMOOTH_Z, 'h' ); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int smooth_setter( BPy_Modifier *self, int type, PyObject *value ) +{ + SmoothModifierData *md = (SmoothModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_FACTOR: + return EXPP_setFloatClamped( value, &md->fac, -10.0, 10.0 ); + case EXPP_MOD_REPEAT: + return EXPP_setIValueRange( value, &md->repeat, 0, 30, 'h' ); + case EXPP_MOD_VERTGROUP: { + char *name = PyString_AsString( value ); + if( !name ) return EXPP_ReturnIntError( PyExc_TypeError, "expected string arg" ); + BLI_strncpy( md->defgrp_name, name, sizeof( md->defgrp_name ) ); + return 0; + } + case EXPP_MOD_ENABLE_X: + return EXPP_setBitfield( value, &md->flag, MOD_SMOOTH_X, 'h' ); + case EXPP_MOD_ENABLE_Y: + return EXPP_setBitfield( value, &md->flag, MOD_SMOOTH_Y, 'h' ); + case EXPP_MOD_ENABLE_Z: + return EXPP_setBitfield( value, &md->flag, MOD_SMOOTH_Z, 'h' ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *cast_getter( BPy_Modifier * self, int type ) +{ + CastModifierData *md = (CastModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_TYPES: + return PyInt_FromLong( (long)md->type ); + case EXPP_MOD_FACTOR: + return PyFloat_FromDouble( (double)md->fac ); + case EXPP_MOD_RADIUS: + return PyFloat_FromDouble( (double)md->radius ); + case EXPP_MOD_SIZE: + return PyFloat_FromDouble( (double)md->size ); + case EXPP_MOD_OBJECT: + return Object_CreatePyObject( md->object ); + case EXPP_MOD_VERTGROUP: + return PyString_FromString( md->defgrp_name ) ; + case EXPP_MOD_ENABLE_X: + return EXPP_getBitfield( &md->flag, MOD_CAST_X, 'h' ); + case EXPP_MOD_ENABLE_Y: + return EXPP_getBitfield( &md->flag, MOD_CAST_Y, 'h' ); + case EXPP_MOD_ENABLE_Z: + return EXPP_getBitfield( &md->flag, MOD_CAST_Z, 'h' ); + case EXPP_MOD_USE_OB_TRANSFORM: + return EXPP_getBitfield( &md->flag, MOD_CAST_USE_OB_TRANSFORM, 'h' ); + case EXPP_MOD_SIZE_FROM_RADIUS: + return EXPP_getBitfield( &md->flag, MOD_CAST_SIZE_FROM_RADIUS, 'h' ); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int cast_setter( BPy_Modifier *self, int type, PyObject *value ) +{ + CastModifierData *md = (CastModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_TYPES: + return EXPP_setIValueRange( value, &md->type, 0, MOD_CAST_TYPE_CUBOID, 'h' ); + case EXPP_MOD_FACTOR: + return EXPP_setFloatClamped( value, &md->fac, -10.0, 10.0 ); + case EXPP_MOD_RADIUS: + return EXPP_setFloatClamped( value, &md->radius, 0.0, 100.0 ); + case EXPP_MOD_SIZE: + return EXPP_setFloatClamped( value, &md->size, 0.0, 100.0 ); + case EXPP_MOD_OBJECT: { + Object *ob_new=NULL; + if (value == Py_None) { + md->object = NULL; + } else if (BPy_Object_Check( value )) { + ob_new = ((( BPy_Object * )value)->object); + md->object = ob_new; + } else { + return EXPP_ReturnIntError( PyExc_TypeError, + "Expected an Object or None value" ); + } + return 0; + } + case EXPP_MOD_VERTGROUP: { + char *name = PyString_AsString( value ); + if( !name ) return EXPP_ReturnIntError( PyExc_TypeError, "expected string arg" ); + BLI_strncpy( md->defgrp_name, name, sizeof( md->defgrp_name ) ); + return 0; + } + case EXPP_MOD_ENABLE_X: + return EXPP_setBitfield( value, &md->flag, MOD_CAST_X, 'h' ); + case EXPP_MOD_ENABLE_Y: + return EXPP_setBitfield( value, &md->flag, MOD_CAST_Y, 'h' ); + case EXPP_MOD_ENABLE_Z: + return EXPP_setBitfield( value, &md->flag, MOD_CAST_Z, 'h' ); + case EXPP_MOD_USE_OB_TRANSFORM: + return EXPP_setBitfield( value, &md->flag, MOD_CAST_USE_OB_TRANSFORM, 'h' ); + case EXPP_MOD_SIZE_FROM_RADIUS: + return EXPP_setBitfield( value, &md->flag, MOD_CAST_SIZE_FROM_RADIUS, 'h' ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *wave_getter( BPy_Modifier * self, int type ) +{ + WaveModifierData *md = (WaveModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_STARTX: + return PyFloat_FromDouble( (double)md->startx ); + case EXPP_MOD_STARTY: + return PyFloat_FromDouble( (double)md->starty ); + case EXPP_MOD_HEIGHT: + return PyFloat_FromDouble( (double)md->height ); + case EXPP_MOD_WIDTH: + return PyFloat_FromDouble( (double)md->width ); + case EXPP_MOD_NARROW: + return PyFloat_FromDouble( (double)md->narrow ); + case EXPP_MOD_SPEED: + return PyFloat_FromDouble( (double)md->speed ); + case EXPP_MOD_DAMP: + return PyFloat_FromDouble( (double)md->damp ); + case EXPP_MOD_LIFETIME: + return PyFloat_FromDouble( (double)md->lifetime ); + case EXPP_MOD_TIMEOFFS: + return PyFloat_FromDouble( (double)md->timeoffs ); + case EXPP_MOD_FLAG: + return PyInt_FromLong( (long)md->flag ); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int wave_setter( BPy_Modifier *self, int type, PyObject *value ) +{ + WaveModifierData *md = (WaveModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_STARTX: + return EXPP_setFloatClamped( value, &md->startx, -100.0, 100.0 ); + case EXPP_MOD_STARTY: + return EXPP_setFloatClamped( value, &md->starty, -100.0, 100.0 ); + case EXPP_MOD_HEIGHT: + return EXPP_setFloatClamped( value, &md->height, -2.0, 2.0 ); + case EXPP_MOD_WIDTH: + return EXPP_setFloatClamped( value, &md->width, 0.0, 5.0 ); + case EXPP_MOD_NARROW: + return EXPP_setFloatClamped( value, &md->width, 0.0, 5.0 ); + case EXPP_MOD_SPEED: + return EXPP_setFloatClamped( value, &md->speed, -2.0, 2.0 ); + case EXPP_MOD_DAMP: + return EXPP_setFloatClamped( value, &md->damp, -MAXFRAMEF, MAXFRAMEF ); + case EXPP_MOD_LIFETIME: + return EXPP_setFloatClamped( value, &md->lifetime, -MAXFRAMEF, MAXFRAMEF ); + case EXPP_MOD_TIMEOFFS: + return EXPP_setFloatClamped( value, &md->timeoffs, -MAXFRAMEF, MAXFRAMEF ); + case EXPP_MOD_FLAG: + return EXPP_setIValueRange( value, &md->flag, 0, + MOD_WAVE_X | MOD_WAVE_Y | MOD_WAVE_CYCL, 'h' ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *array_getter( BPy_Modifier * self, int type ) +{ + ArrayModifierData *md = (ArrayModifierData *)(self->md); + + if( type == EXPP_MOD_OBJECT_OFFSET ) + return Object_CreatePyObject( md->offset_ob ); + else if( type == EXPP_MOD_OBJECT_CURVE ) + return Object_CreatePyObject( md->curve_ob ); + else if( type == EXPP_MOD_COUNT ) + return PyInt_FromLong( (long)md->count ); + else if( type == EXPP_MOD_LENGTH ) + return PyFloat_FromDouble( md->length ); + else if( type == EXPP_MOD_MERGE_DIST ) + return PyFloat_FromDouble( md->merge_dist ); + else if( type == EXPP_MOD_MERGE_DIST ) + return PyFloat_FromDouble( md->merge_dist ); + else if( type == EXPP_MOD_OFFSET_VEC) + return newVectorObject( md->offset, 3, Py_NEW ); + else if( type == EXPP_MOD_SCALE_VEC) + return newVectorObject( md->scale, 3, Py_NEW ); + + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); +} + +static int array_setter( BPy_Modifier *self, int type, PyObject *value ) +{ + ArrayModifierData *md = (ArrayModifierData *)(self->md); + switch( type ) { + case EXPP_MOD_OBJECT_OFFSET: + return GenericLib_assignData(value, (void **) &md->offset_ob, (void **) &self->object, 0, ID_OB, 0); + case EXPP_MOD_OBJECT_CURVE: + return GenericLib_assignData(value, (void **) &md->curve_ob, 0, 0, ID_OB, OB_CURVE); + case EXPP_MOD_COUNT: + return EXPP_setIValueClamped( value, &md->count, 1, 1000, 'i' ); + case EXPP_MOD_LENGTH: + return EXPP_setFloatClamped( value, &md->length, 0.0, 1000.0 ); + case EXPP_MOD_MERGE_DIST: + return EXPP_setFloatClamped( value, &md->merge_dist, 0.0, 1000.0 ); + case EXPP_MOD_OFFSET_VEC: + return EXPP_setVec3Clamped( value, md->offset, -10000.0, 10000.0 ); + case EXPP_MOD_SCALE_VEC: + return EXPP_setVec3Clamped( value, md->scale, -10000.0, 10000.0 ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *boolean_getter( BPy_Modifier * self, int type ) +{ + BooleanModifierData *md = (BooleanModifierData *)(self->md); + + if( type == EXPP_MOD_OBJECT ) + return Object_CreatePyObject( md->object ); + else if( type == EXPP_MOD_OPERATION ) + return PyInt_FromLong( ( long )md->operation ) ; + + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); +} + +static int boolean_setter( BPy_Modifier *self, int type, PyObject *value ) +{ + BooleanModifierData *md = (BooleanModifierData *)(self->md); + + if( type == EXPP_MOD_OBJECT ) + return GenericLib_assignData(value, (void **) &md->object, (void **) &self->object, 0, ID_OB, OB_MESH); + else if( type == EXPP_MOD_OPERATION ) + return EXPP_setIValueRange( value, &md->operation, + eBooleanModifierOp_Intersect, eBooleanModifierOp_Difference, + 'h' ); + + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); +} + + +static PyObject *edgesplit_getter( BPy_Modifier * self, int type ) +{ + EdgeSplitModifierData *md = (EdgeSplitModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_EDGESPLIT_ANGLE: + return PyFloat_FromDouble( (double)md->split_angle ); + case EXPP_MOD_EDGESPLIT_FROM_ANGLE: + return PyBool_FromLong( ( long ) + ( md->flags & MOD_EDGESPLIT_FROMANGLE ) ) ; + case EXPP_MOD_EDGESPLIT_FROM_SHARP: + return PyBool_FromLong( ( long ) + ( md->flags & MOD_EDGESPLIT_FROMFLAG ) ) ; + + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int edgesplit_setter( BPy_Modifier *self, int type, PyObject *value ) +{ + EdgeSplitModifierData *md = (EdgeSplitModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_EDGESPLIT_ANGLE: + return EXPP_setFloatClamped( value, &md->split_angle, 0.0, 180.0 ); + case EXPP_MOD_EDGESPLIT_FROM_ANGLE: + return EXPP_setBitfield( value, &md->flags, + MOD_EDGESPLIT_FROMANGLE, 'h' ); + case EXPP_MOD_EDGESPLIT_FROM_SHARP: + return EXPP_setBitfield( value, &md->flags, + MOD_EDGESPLIT_FROMFLAG, 'h' ); + + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *displace_getter( BPy_Modifier * self, int type ) +{ + DisplaceModifierData *md = (DisplaceModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_TEXTURE: + if (md->texture) Texture_CreatePyObject( md->texture ); + else Py_RETURN_NONE; + case EXPP_MOD_STRENGTH: + return PyFloat_FromDouble( (double)md->strength ); + case EXPP_MOD_DIRECTION: + PyInt_FromLong( md->direction ); + case EXPP_MOD_VERTGROUP: + return PyString_FromString( md->defgrp_name ) ; + case EXPP_MOD_MID_LEVEL: + return PyFloat_FromDouble( (double)md->midlevel ); + case EXPP_MOD_MAPPING: + PyInt_FromLong( md->texmapping ); + case EXPP_MOD_OBJECT: + return Object_CreatePyObject( md->map_object ); + case EXPP_MOD_UVLAYER: + return PyString_FromString( md->uvlayer_name ); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int displace_setter( BPy_Modifier *self, int type, PyObject *value ) +{ + DisplaceModifierData *md = (DisplaceModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_TEXTURE: + return GenericLib_assignData(value, (void **) &md->texture, 0, 1, ID_TE, 0); + case EXPP_MOD_STRENGTH: + return EXPP_setFloatClamped( value, &md->strength, -1000.0, 1000.0 ); + + case EXPP_MOD_DIRECTION: + return EXPP_setIValueClamped( value, &md->direction, + MOD_DISP_DIR_X, MOD_DISP_DIR_RGB_XYZ, 'i' ); + + case EXPP_MOD_VERTGROUP: { + char *name = PyString_AsString( value ); + if( !name ) return EXPP_ReturnIntError( PyExc_TypeError, "expected string arg" ); + BLI_strncpy( md->defgrp_name, name, sizeof( md->defgrp_name ) ); + return 0; + } + case EXPP_MOD_MID_LEVEL: + return EXPP_setFloatClamped( value, &md->midlevel, 0.0, 1.0 ); + + case EXPP_MOD_MAPPING: + return EXPP_setIValueClamped( value, &md->texmapping, + MOD_DISP_MAP_LOCAL, MOD_DISP_MAP_UV, 'i' ); + + case EXPP_MOD_OBJECT: { + Object *ob_new=NULL; + if (value == Py_None) { + md->map_object = NULL; + } else if (BPy_Object_Check( value )) { + ob_new = ((( BPy_Object * )value)->object); + md->map_object = ob_new; + } else { + return EXPP_ReturnIntError( PyExc_TypeError, + "Expected an Object or None value" ); + } + return 0; + } + + case EXPP_MOD_UVLAYER: { + char *name = PyString_AsString( value ); + if( !name ) return EXPP_ReturnIntError( PyExc_TypeError, "expected string arg" ); + BLI_strncpy( md->uvlayer_name, name, sizeof( md->uvlayer_name ) ); + return 0; + } + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + + +/* static PyObject *uvproject_getter( BPy_Modifier * self, int type ) +{ + DisplaceModifierData *md = (DisplaceModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_MID_LEVEL: + return PyFloat_FromDouble( (double)md->midlevel ); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int uvproject_setter( BPy_Modifier *self, int type, PyObject *value ) +{ + DisplaceModifierData *md = (DisplaceModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_TEXTURE: + return 0; + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} */ + + +/* + * get data from a modifier + */ + +static PyObject *Modifier_getData( BPy_Modifier * self, PyObject * key ) +{ + int setting; + + if( !PyInt_Check( key ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected an int arg as stored in Blender.Modifier.Settings" ); + + MODIFIER_DEL_CHECK_PY(self); + + setting = PyInt_AsLong( key ); + switch( setting ) { + case EXPP_MOD_RENDER: + return EXPP_getBitfield( &self->md->mode, eModifierMode_Render, 'h' ); + case EXPP_MOD_REALTIME: + return EXPP_getBitfield( &self->md->mode, eModifierMode_Realtime, 'h' ); + case EXPP_MOD_EDITMODE: + return EXPP_getBitfield( &self->md->mode, eModifierMode_Editmode, 'h' ); + case EXPP_MOD_ONCAGE: + return EXPP_getBitfield( &self->md->mode, eModifierMode_OnCage, 'h' ); + default: + switch( self->md->type ) { + case eModifierType_Subsurf: + return subsurf_getter( self, setting ); + case eModifierType_Armature: + return armature_getter( self, setting ); + case eModifierType_Lattice: + return lattice_getter( self, setting ); + case eModifierType_Curve: + return curve_getter( self, setting ); + case eModifierType_Build: + return build_getter( self, setting ); + case eModifierType_Mirror: + return mirror_getter( self, setting ); + case eModifierType_Decimate: + return decimate_getter( self, setting ); + case eModifierType_Smooth: + return smooth_getter( self, setting ); + case eModifierType_Cast: + return cast_getter( self, setting ); + case eModifierType_Wave: + return wave_getter( self, setting ); + case eModifierType_Boolean: + return boolean_getter( self, setting ); + case eModifierType_Array: + return array_getter( self, setting ); + case eModifierType_EdgeSplit: + return edgesplit_getter( self, setting ); + case eModifierType_Displace: + return displace_getter( self, setting ); + /*case eModifierType_UVProject: + return uvproject_getter( self, setting );*/ + case eModifierType_Hook: + case eModifierType_Softbody: + case eModifierType_None: + Py_RETURN_NONE; + } + } + return EXPP_ReturnPyObjError( PyExc_KeyError, + "unknown key or modifier type" ); +} + +static int Modifier_setData( BPy_Modifier * self, PyObject * key, + PyObject * arg ) +{ + int key_int; + + if( !PyNumber_Check( key ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected an int arg as stored in Blender.Modifier.Settings" ); + + MODIFIER_DEL_CHECK_INT(self); + + key_int = PyInt_AsLong( key ); + + /* Chach for standard modifier settings */ + switch( key_int ) { + case EXPP_MOD_RENDER: + return EXPP_setBitfield( arg, &self->md->mode, + eModifierMode_Render, 'h' ); + case EXPP_MOD_REALTIME: + return EXPP_setBitfield( arg, &self->md->mode, + eModifierMode_Realtime, 'h' ); + case EXPP_MOD_EDITMODE: + return EXPP_setBitfield( arg, &self->md->mode, + eModifierMode_Editmode, 'h' ); + case EXPP_MOD_ONCAGE: + return EXPP_setBitfield( arg, &self->md->mode, + eModifierMode_OnCage, 'h' ); + } + + switch( self->md->type ) { + case eModifierType_Subsurf: + return subsurf_setter( self, key_int, arg ); + case eModifierType_Armature: + return armature_setter( self, key_int, arg ); + case eModifierType_Lattice: + return lattice_setter( self, key_int, arg ); + case eModifierType_Curve: + return curve_setter( self, key_int, arg ); + case eModifierType_Build: + return build_setter( self, key_int, arg ); + case eModifierType_Mirror: + return mirror_setter( self, key_int, arg ); + case eModifierType_Array: + return array_setter( self, key_int, arg ); + case eModifierType_Decimate: + return decimate_setter( self, key_int, arg ); + case eModifierType_Smooth: + return smooth_setter( self, key_int, arg ); + case eModifierType_Cast: + return cast_setter( self, key_int, arg ); + case eModifierType_Wave: + return wave_setter( self, key_int, arg ); + case eModifierType_Boolean: + return boolean_setter( self, key_int, arg ); + case eModifierType_EdgeSplit: + return edgesplit_setter( self, key_int, arg ); + case eModifierType_Displace: + return displace_setter( self, key_int, arg ); + /*case eModifierType_UVProject: + return uvproject_setter( self, key_int, arg );*/ + case eModifierType_Hook: + case eModifierType_Softbody: + case eModifierType_None: + return 0; + } + return EXPP_ReturnIntError( PyExc_RuntimeError, + "unsupported modifier setting" ); +} + + +static PyObject *Modifier_reset( BPy_Modifier * self ) +{ + Object *ob = self->object; + ModifierData *md = self->md; + HookModifierData *hmd = (HookModifierData*) md; + + MODIFIER_DEL_CHECK_PY(self); + + if (md->type != eModifierType_Hook) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "can only reset hooks" ); + + if (hmd->object) { + Mat4Invert(hmd->object->imat, hmd->object->obmat); + Mat4MulSerie(hmd->parentinv, hmd->object->imat, ob->obmat, NULL, NULL, NULL, NULL, NULL, NULL); + } + Py_RETURN_NONE; +} + +/*****************************************************************************/ +/* Function: Modifier_repr */ +/* Description: This is a callback function for the BPy_Modifier type. It */ +/* builds a meaningful string to represent modifier objects. */ +/*****************************************************************************/ +static PyObject *Modifier_repr( BPy_Modifier * self ) +{ + ModifierTypeInfo *mti; + if (self->md==NULL) + return PyString_FromString( "[Modifier - Removed"); + + mti= modifierType_getInfo(self->md->type); + return PyString_FromFormat( "[Modifier \"%s\", Type \"%s\"]", self->md->name, mti->name ); +} + +/* Three Python Modifier_Type helper functions needed by the Object module: */ + +/*****************************************************************************/ +/* Function: Modifier_CreatePyObject */ +/* Description: This function will create a new BPy_Modifier from an */ +/* existing Blender modifier structure. */ +/*****************************************************************************/ +PyObject *Modifier_CreatePyObject( Object *ob, ModifierData * md ) +{ + BPy_Modifier *pymod; + pymod = ( BPy_Modifier * ) PyObject_NEW( BPy_Modifier, &Modifier_Type ); + if( !pymod ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create BPy_Modifier object" ); + pymod->md = md; + pymod->object = ob; + return ( PyObject * ) pymod; +} + +/*****************************************************************************/ +/* Function: Modifier_FromPyObject */ +/* Description: This function returns the Blender modifier from the given */ +/* PyObject. */ +/*****************************************************************************/ +ModifierData *Modifier_FromPyObject( PyObject * pyobj ) +{ + return ( ( BPy_Modifier * ) pyobj )->md; +} + +/*****************************************************************************/ +/* Modifier Sequence wrapper */ +/*****************************************************************************/ + +/* + * Initialize the interator + */ + +static PyObject *ModSeq_getIter( BPy_ModSeq * self ) +{ + if (!self->iter) { + self->iter = (ModifierData *)self->object->modifiers.first; + return EXPP_incr_ret ( (PyObject *) self ); + } else { + return ModSeq_CreatePyObject(self->object, (ModifierData *)self->object->modifiers.first); + } +} + +/* + * Get the next Modifier + */ + +static PyObject *ModSeq_nextIter( BPy_ModSeq * self ) +{ + ModifierData *iter = self->iter; + if( iter ) { + self->iter = iter->next; + return Modifier_CreatePyObject( self->object, iter ); + } + + self->iter= NULL; /* mark as not iterating */ + return EXPP_ReturnPyObjError( PyExc_StopIteration, + "iterator at end" ); +} + +/* return the number of modifiers */ + +static int ModSeq_length( BPy_ModSeq * self ) +{ + return BLI_countlist( &self->object->modifiers ); +} + +/* return a modifier */ + +static PyObject *ModSeq_item( BPy_ModSeq * self, int i ) +{ + ModifierData *md = NULL; + + /* if index is negative, start counting from the end of the list */ + if( i < 0 ) + i += ModSeq_length( self ); + + /* skip through the list until we get the modifier or end of list */ + + for( md = self->object->modifiers.first; i && md; --i ) md = md->next; + + if( md ) + return Modifier_CreatePyObject( self->object, md ); + else + return EXPP_ReturnPyObjError( PyExc_IndexError, + "array index out of range" ); +} + +/*****************************************************************************/ +/* Python BPy_ModSeq sequence table: */ +/*****************************************************************************/ +static PySequenceMethods ModSeq_as_sequence = { + ( inquiry ) ModSeq_length, /* sq_length */ + ( binaryfunc ) 0, /* sq_concat */ + ( intargfunc ) 0, /* sq_repeat */ + ( intargfunc ) ModSeq_item, /* sq_item */ + ( intintargfunc ) 0, /* sq_slice */ + ( intobjargproc ) 0, /* sq_ass_item */ + ( intintobjargproc ) 0, /* sq_ass_slice */ + ( objobjproc ) 0, /* sq_contains */ + ( binaryfunc ) 0, /* sq_inplace_concat */ + ( intargfunc ) 0, /* sq_inplace_repeat */ +}; + +/* + * helper function to check for a valid modifier argument + */ + +static ModifierData *locate_modifier( BPy_ModSeq *self, BPy_Modifier * value ) +{ + ModifierData *md; + + /* check that argument is a modifier */ + if( !BPy_Modifier_Check(value) ) + return (ModifierData *)EXPP_ReturnPyObjError( PyExc_TypeError, + "expected an modifier as an argument" ); + + /* check whether modifier has been removed */ + if( !value->md ) + return (ModifierData *)EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This modifier has been removed!" ); + + /* find the modifier in the object's list */ + for( md = self->object->modifiers.first; md; md = md->next ) + if( md == value->md ) + return md; + + /* return exception if we can't find the modifier */ + return (ModifierData *)EXPP_ReturnPyObjError( PyExc_AttributeError, + "This modifier is not in the object's stack" ); +} + +/* create a new modifier at the end of the list */ + +static PyObject *ModSeq_append( BPy_ModSeq *self, PyObject *value ) +{ + int type = PyInt_AsLong(value); + + /* type 0 is eModifierType_None, should we be able to add one of these? */ + if( type <= 0 || type >= NUM_MODIFIER_TYPES ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "Not an int or argument out of range, expected an int from Blender.Modifier.Type" ); + + BLI_addtail( &self->object->modifiers, modifier_new( type ) ); + return Modifier_CreatePyObject( self->object, self->object->modifiers.last ); +} + +/* remove an existing modifier */ + +static PyObject *ModSeq_remove( BPy_ModSeq *self, BPy_Modifier *value ) +{ + ModifierData *md = locate_modifier( self, value ); + + /* if we can't locate the modifier, return (exception already set) */ + if( !md ) + return (PyObject *)NULL; + + /* do the actual removal */ + BLI_remlink( &self->object->modifiers, md ); + modifier_free( md ); + + /* erase the link to the modifier */ + value->md = NULL; + + Py_RETURN_NONE; +} + +/* move the modifier up in the stack */ + +static PyObject *ModSeq_moveUp( BPy_ModSeq * self, BPy_Modifier * value ) +{ + ModifierData *md = locate_modifier( self, value ); + + /* if we can't locate the modifier, return (exception already set) */ + if( !md ) + return (PyObject *)NULL; + + if( mod_moveUp( self->object, md ) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "cannot move above a modifier requiring original data" ); + + Py_RETURN_NONE; +} + +/* move the modifier down in the stack */ + +static PyObject *ModSeq_moveDown( BPy_ModSeq * self, BPy_Modifier *value ) +{ + ModifierData *md = locate_modifier( self, value ); + + /* if we can't locate the modifier, return (exception already set) */ + if( !md ) + return (PyObject *)NULL; + + if( mod_moveDown( self->object, md ) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "cannot move beyond a non-deforming modifier" ); + + Py_RETURN_NONE; +} + +/*****************************************************************************/ +/* Python BPy_ModSeq methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_ModSeq_methods[] = { + /* name, method, flags, doc */ + {"append", ( PyCFunction ) ModSeq_append, METH_O, + "(type) - add a new modifier, where type is the type of modifier"}, + {"remove", ( PyCFunction ) ModSeq_remove, METH_O, + "(modifier) - remove an existing modifier, where modifier is a modifier from this object."}, + {"moveUp", ( PyCFunction ) ModSeq_moveUp, METH_O, + "(modifier) - Move a modifier up in stack"}, + {"moveDown", ( PyCFunction ) ModSeq_moveDown, METH_O, + "(modifier) - Move a modifier down in stack"}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python ModSeq_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject ModSeq_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender.Modifiers", /* char *tp_name; */ + sizeof( BPy_ModSeq ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + ( reprfunc ) NULL, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + &ModSeq_as_sequence, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + ( getiterfunc )ModSeq_getIter, /* getiterfunc tp_iter; */ + ( iternextfunc )ModSeq_nextIter, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_ModSeq_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + NULL, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +/*****************************************************************************/ +/* Function: ModSeq_CreatePyObject */ +/* Description: This function will create a new BPy_ModSeq from an */ +/* existing ListBase structure. */ +/*****************************************************************************/ +PyObject *ModSeq_CreatePyObject( Object *ob, ModifierData *iter ) +{ + BPy_ModSeq *pymod; + pymod = ( BPy_ModSeq * ) PyObject_NEW( BPy_ModSeq, &ModSeq_Type ); + if( !pymod ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create BPy_ModSeq object" ); + pymod->object = ob; + pymod->iter = iter; + return ( PyObject * ) pymod; +} + +static PyObject *M_Modifier_TypeDict( void ) +{ + PyObject *S = PyConstant_New( ); + + if( S ) { + BPy_constant *d = ( BPy_constant * ) S; + + PyConstant_Insert( d, "SUBSURF", + PyInt_FromLong( eModifierType_Subsurf ) ); + PyConstant_Insert( d, "ARMATURE", + PyInt_FromLong( eModifierType_Armature ) ); + PyConstant_Insert( d, "LATTICE", + PyInt_FromLong( eModifierType_Lattice ) ); + PyConstant_Insert( d, "CURVE", + PyInt_FromLong( eModifierType_Curve ) ); + PyConstant_Insert( d, "BUILD", + PyInt_FromLong( eModifierType_Build ) ); + PyConstant_Insert( d, "MIRROR", + PyInt_FromLong( eModifierType_Mirror ) ); + PyConstant_Insert( d, "DECIMATE", + PyInt_FromLong( eModifierType_Decimate ) ); + PyConstant_Insert( d, "WAVE", + PyInt_FromLong( eModifierType_Wave ) ); + PyConstant_Insert( d, "BOOLEAN", + PyInt_FromLong( eModifierType_Boolean ) ); + PyConstant_Insert( d, "ARRAY", + PyInt_FromLong( eModifierType_Array ) ); + PyConstant_Insert( d, "EDGESPLIT", + PyInt_FromLong( eModifierType_EdgeSplit ) ); + PyConstant_Insert( d, "SMOOTH", + PyInt_FromLong( eModifierType_Smooth ) ); + PyConstant_Insert( d, "CAST", + PyInt_FromLong( eModifierType_Cast ) ); + } + return S; +} + + +static PyObject *M_Modifier_SettingsDict( void ) +{ + PyObject *S = PyConstant_New( ); + + if( S ) { + BPy_constant *d = ( BPy_constant * ) S; + +/* +# The lines below are a python script that uses the enum variables to create +# the lines below +# START PYSCRIPT +st=''' + EXPP_MOD_RENDER = 0, + EXPP_MOD_REALTIME, + EXPP_MOD_EDITMODE, + etc.. copy from above +''' + +base= ''' + PyConstant_Insert( d, "%s", + PyInt_FromLong( EXPP_MOD_%s ) ); +''' +for var in st.replace(',','').split('\n'): + + var= var.split() + if not var: continue + var= var[0] + if (not var) or var.startswith('/'): continue + + var='_'.join(var.split('_')[2:]) + print base % (var, var), +# END PYSCRIPT +*/ + + /*Auto generated from the above script*/ + PyConstant_Insert( d, "RENDER", + PyInt_FromLong( EXPP_MOD_RENDER ) ); + PyConstant_Insert( d, "REALTIME", + PyInt_FromLong( EXPP_MOD_REALTIME ) ); + PyConstant_Insert( d, "EDITMODE", + PyInt_FromLong( EXPP_MOD_EDITMODE ) ); + PyConstant_Insert( d, "ONCAGE", + PyInt_FromLong( EXPP_MOD_ONCAGE ) ); + PyConstant_Insert( d, "OBJECT", + PyInt_FromLong( EXPP_MOD_OBJECT ) ); + PyConstant_Insert( d, "VERTGROUP", + PyInt_FromLong( EXPP_MOD_VERTGROUP ) ); + PyConstant_Insert( d, "LIMIT", + PyInt_FromLong( EXPP_MOD_LIMIT ) ); + PyConstant_Insert( d, "FLAG", + PyInt_FromLong( EXPP_MOD_FLAG ) ); + PyConstant_Insert( d, "COUNT", + PyInt_FromLong( EXPP_MOD_COUNT ) ); + PyConstant_Insert( d, "LENGTH", + PyInt_FromLong( EXPP_MOD_LENGTH ) ); + PyConstant_Insert( d, "FACTOR", + PyInt_FromLong( EXPP_MOD_FACTOR ) ); + PyConstant_Insert( d, "ENABLE_X", + PyInt_FromLong( EXPP_MOD_ENABLE_X ) ); + PyConstant_Insert( d, "ENABLE_Y", + PyInt_FromLong( EXPP_MOD_ENABLE_Y ) ); + PyConstant_Insert( d, "ENABLE_Z", + PyInt_FromLong( EXPP_MOD_ENABLE_Z ) ); + PyConstant_Insert( d, "TYPES", + PyInt_FromLong( EXPP_MOD_TYPES ) ); + PyConstant_Insert( d, "LEVELS", + PyInt_FromLong( EXPP_MOD_LEVELS ) ); + PyConstant_Insert( d, "RENDLEVELS", + PyInt_FromLong( EXPP_MOD_RENDLEVELS ) ); + PyConstant_Insert( d, "OPTIMAL", + PyInt_FromLong( EXPP_MOD_OPTIMAL ) ); + PyConstant_Insert( d, "UV", + PyInt_FromLong( EXPP_MOD_UV ) ); + PyConstant_Insert( d, "ENVELOPES", + PyInt_FromLong( EXPP_MOD_ENVELOPES ) ); + PyConstant_Insert( d, "OBJECT_OFFSET", + PyInt_FromLong( EXPP_MOD_OBJECT_OFFSET ) ); + PyConstant_Insert( d, "OBJECT_CURVE", + PyInt_FromLong( EXPP_MOD_OBJECT_CURVE ) ); + PyConstant_Insert( d, "OFFSET_VEC", + PyInt_FromLong( EXPP_MOD_OFFSET_VEC ) ); + PyConstant_Insert( d, "SCALE_VEC", + PyInt_FromLong( EXPP_MOD_SCALE_VEC ) ); + PyConstant_Insert( d, "MERGE_DIST", + PyInt_FromLong( EXPP_MOD_MERGE_DIST ) ); + PyConstant_Insert( d, "START", + PyInt_FromLong( EXPP_MOD_START ) ); + PyConstant_Insert( d, "SEED", + PyInt_FromLong( EXPP_MOD_SEED ) ); + PyConstant_Insert( d, "RANDOMIZE", + PyInt_FromLong( EXPP_MOD_RANDOMIZE ) ); + PyConstant_Insert( d, "AXIS_X", + PyInt_FromLong( EXPP_MOD_AXIS_X ) ); + PyConstant_Insert( d, "AXIS_Y", + PyInt_FromLong( EXPP_MOD_AXIS_Y ) ); + PyConstant_Insert( d, "AXIS_Z", + PyInt_FromLong( EXPP_MOD_AXIS_Z ) ); + PyConstant_Insert( d, "RATIO", + PyInt_FromLong( EXPP_MOD_RATIO ) ); + PyConstant_Insert( d, "STARTX", + PyInt_FromLong( EXPP_MOD_STARTX ) ); + PyConstant_Insert( d, "STARTY", + PyInt_FromLong( EXPP_MOD_STARTY ) ); + PyConstant_Insert( d, "HEIGHT", + PyInt_FromLong( EXPP_MOD_HEIGHT ) ); + PyConstant_Insert( d, "WIDTH", + PyInt_FromLong( EXPP_MOD_WIDTH ) ); + PyConstant_Insert( d, "NARROW", + PyInt_FromLong( EXPP_MOD_NARROW ) ); + PyConstant_Insert( d, "SPEED", + PyInt_FromLong( EXPP_MOD_SPEED ) ); + PyConstant_Insert( d, "DAMP", + PyInt_FromLong( EXPP_MOD_DAMP ) ); + PyConstant_Insert( d, "LIFETIME", + PyInt_FromLong( EXPP_MOD_LIFETIME ) ); + PyConstant_Insert( d, "TIMEOFFS", + PyInt_FromLong( EXPP_MOD_TIMEOFFS ) ); + PyConstant_Insert( d, "OPERATION", + PyInt_FromLong( EXPP_MOD_OPERATION ) ); + PyConstant_Insert( d, "EDGESPLIT_ANGLE", + PyInt_FromLong( EXPP_MOD_EDGESPLIT_ANGLE ) ); + PyConstant_Insert( d, "EDGESPLIT_FROM_ANGLE", + PyInt_FromLong( EXPP_MOD_EDGESPLIT_FROM_ANGLE ) ); + PyConstant_Insert( d, "EDGESPLIT_FROM_SHARP", + PyInt_FromLong( EXPP_MOD_EDGESPLIT_FROM_SHARP ) ); + PyConstant_Insert( d, "UVLAYER", + PyInt_FromLong( EXPP_MOD_UVLAYER ) ); + PyConstant_Insert( d, "MID_LEVEL", + PyInt_FromLong( EXPP_MOD_MID_LEVEL ) ); + PyConstant_Insert( d, "STRENGTH", + PyInt_FromLong( EXPP_MOD_STRENGTH ) ); + PyConstant_Insert( d, "TEXTURE", + PyInt_FromLong( EXPP_MOD_TEXTURE ) ); + PyConstant_Insert( d, "MAPPING", + PyInt_FromLong( EXPP_MOD_MAPPING ) ); + PyConstant_Insert( d, "DIRECTION", + PyInt_FromLong( EXPP_MOD_DIRECTION ) ); + PyConstant_Insert( d, "REPEAT", + PyInt_FromLong( EXPP_MOD_REPEAT ) ); + PyConstant_Insert( d, "RADIUS", + PyInt_FromLong( EXPP_MOD_RADIUS ) ); + PyConstant_Insert( d, "SIZE", + PyInt_FromLong( EXPP_MOD_SIZE ) ); + PyConstant_Insert( d, "USE_OB_TRANSFORM", + PyInt_FromLong( EXPP_MOD_USE_OB_TRANSFORM ) ); + PyConstant_Insert( d, "SIZE_FROM_RADIUS", + PyInt_FromLong( EXPP_MOD_SIZE_FROM_RADIUS ) ); + /*End Auto generated code*/ + } + return S; +} + +/*****************************************************************************/ +/* Function: Modifier_Init */ +/*****************************************************************************/ +PyObject *Modifier_Init( void ) +{ + PyObject *submodule; + PyObject *TypeDict = M_Modifier_TypeDict( ); + PyObject *SettingsDict = M_Modifier_SettingsDict( ); + + if( PyType_Ready( &ModSeq_Type ) < 0 || + PyType_Ready( &Modifier_Type ) < 0 ) + return NULL; + + submodule = Py_InitModule3( "Blender.Modifier", NULL, + "Modifer module for accessing and creating object modifier data" ); + + if( TypeDict ) { + PyModule_AddObject( submodule, "Type", TypeDict ); /* deprecated */ + /* since PyModule_AddObject() steals a reference, we need to + incref TypeDict to use it again */ + Py_INCREF( TypeDict); + PyModule_AddObject( submodule, "Types", TypeDict ); + } + + if( SettingsDict ) + PyModule_AddObject( submodule, "Settings", SettingsDict ); + + return submodule; +} diff --git a/source/blender/python/api2_2x/Modifier.h b/source/blender/python/api2_2x/Modifier.h new file mode 100644 index 00000000000..e61371cd192 --- /dev/null +++ b/source/blender/python/api2_2x/Modifier.h @@ -0,0 +1,72 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_MODIFIER_H +#define EXPP_MODIFIER_H + +#include +#include "DNA_object_types.h" +#include "DNA_modifier_types.h" +#include "DNA_listBase.h" + +/*****************************************************************************/ +/* Python BPy_Modifier and BPy_ModSeq structure definition: */ +/*****************************************************************************/ +typedef struct { + PyObject_HEAD /* required macro */ + Object *object; + ModifierData *iter; +} BPy_ModSeq; + +typedef struct { + PyObject_HEAD /* required macro */ + Object *object; + /* if md this is null, the modifier has been removed and we need to raise + an error when its data is accessed */ + ModifierData *md; +} BPy_Modifier; + +extern PyTypeObject ModSeq_Type; +extern PyTypeObject Modifier_Type; +#define BPy_ModSeq_Check(v) ((v)->ob_type == &ModSeq_Type) +#define BPy_Modifier_Check(v) ((v)->ob_type == &Modifier_Type) + +/* + * prototypes + */ + +PyObject *Modifier_Init( void ); +PyObject *ModSeq_CreatePyObject( Object *obj, ModifierData *iter ); +PyObject *Modifier_CreatePyObject( Object *obj, ModifierData *md ); +ModifierData *Modifier_FromPyObject( PyObject * py_obj ); + +#endif /* EXPP_MODIFIER_H */ diff --git a/source/blender/python/api2_2x/NLA.c b/source/blender/python/api2_2x/NLA.c new file mode 100644 index 00000000000..7d701382f7b --- /dev/null +++ b/source/blender/python/api2_2x/NLA.c @@ -0,0 +1,1590 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#include "NLA.h" /*This must come first*/ + +#include "DNA_curve_types.h" +#include "DNA_scene_types.h" +#include "BKE_action.h" +#include "BKE_nla.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_library.h" +#include "BLI_blenlib.h" +#include "Object.h" +#include "Ipo.h" +#include "gen_utils.h" +#include "gen_library.h" +#include "blendef.h" +#include "MEM_guardedalloc.h" + +#define ACTSTRIP_STRIDEAXIS_X 0 +#define ACTSTRIP_STRIDEAXIS_Y 1 +#define ACTSTRIP_STRIDEAXIS_Z 2 + +/*****************************************************************************/ +/* Python API function prototypes for the NLA module. */ +/*****************************************************************************/ +static PyObject *M_NLA_NewAction( PyObject * self, PyObject * args ); +static PyObject *M_NLA_CopyAction( PyObject * self, PyObject * args ); +static PyObject *M_NLA_GetActions( PyObject * self ); + +/*****************************************************************************/ +/* The following string definitions are used for documentation strings. */ +/* In Python these will be written to the console when doing a */ +/* Blender.Armature.NLA.__doc__ */ +/*****************************************************************************/ +char M_NLA_doc[] = + "The Blender NLA module -This module provides control over Armature keyframing in Blender."; +char M_NLA_NewAction_doc[] = + "(name) - Create new action for linking to an object."; +char M_NLA_CopyAction_doc[] = "(name) - Copy action and return copy."; +char M_NLA_GetActions_doc[] = "(name) - Returns a dictionary of actions."; + +/*****************************************************************************/ +/* Python method structure definition for Blender.Armature.NLA module: */ +/*****************************************************************************/ +struct PyMethodDef M_NLA_methods[] = { + {"NewAction", ( PyCFunction ) M_NLA_NewAction, METH_VARARGS, + M_NLA_NewAction_doc}, + {"CopyAction", ( PyCFunction ) M_NLA_CopyAction, METH_VARARGS, + M_NLA_CopyAction_doc}, + {"GetActions", ( PyCFunction ) M_NLA_GetActions, METH_NOARGS, + M_NLA_GetActions_doc}, + {NULL, NULL, 0, NULL} +}; +/*****************************************************************************/ +/* Python BPy_Action methods declarations: */ +/*****************************************************************************/ +static PyObject *Action_setActive( BPy_Action * self, PyObject * args ); +static PyObject *Action_getFrameNumbers(BPy_Action *self); +static PyObject *Action_getChannelIpo( BPy_Action * self, PyObject * value ); +static PyObject *Action_getChannelNames( BPy_Action * self ); +static PyObject *Action_renameChannel( BPy_Action * self, PyObject * args ); +static PyObject *Action_verifyChannel( BPy_Action * self, PyObject * value ); +static PyObject *Action_removeChannel( BPy_Action * self, PyObject * value ); +static PyObject *Action_getAllChannelIpos( BPy_Action * self ); + +/*****************************************************************************/ +/* Python BPy_Action methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_Action_methods[] = { + /* name, method, flags, doc */ + {"getName", ( PyCFunction ) GenericLib_getName, METH_NOARGS, + "() - return Action name"}, + {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS, + "(str) - rename Action"}, + {"setActive", ( PyCFunction ) Action_setActive, METH_VARARGS, + "(str) -set this action as the active action for an object"}, + {"getFrameNumbers", (PyCFunction) Action_getFrameNumbers, METH_NOARGS, + "() - get the frame numbers at which keys have been inserted"}, + {"getChannelIpo", ( PyCFunction ) Action_getChannelIpo, METH_O, + "(str) -get the Ipo from a named action channel in this action"}, + {"getChannelNames", ( PyCFunction ) Action_getChannelNames, METH_NOARGS, + "() -get the channel names for this action"}, + {"renameChannel", ( PyCFunction ) Action_renameChannel, METH_VARARGS, + "(from, to) -rename the channel from string to string"}, + {"verifyChannel", ( PyCFunction ) Action_verifyChannel, METH_O, + "(str) -verify the channel in this action"}, + {"removeChannel", ( PyCFunction ) Action_removeChannel, METH_O, + "(str) -remove the channel from the action"}, + {"getAllChannelIpos", ( PyCFunction ) Action_getAllChannelIpos, + METH_NOARGS, + "() - Return a dict of (name:ipo)-keys containing each channel in the object's action"}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python TypeAction callback function prototypes: */ +/*****************************************************************************/ +static int Action_compare( BPy_Action * a, BPy_Action * b ); +static PyObject *Action_repr( BPy_Action * bone ); + +/*-------------------------------------------------------------------------*/ +static PyObject *M_NLA_NewAction( PyObject * self_unused, PyObject * args ) +{ + char *name_str = "DefaultAction"; + BPy_Action *py_action = NULL; /* for Action Data object wrapper in Python */ + bAction *bl_action = NULL; /* for actual Action Data we create in Blender */ + + if( !PyArg_ParseTuple( args, "|s", &name_str ) ) { + EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected string or nothing" ); + return NULL; + } + /* Create new action globally */ + bl_action = alloc_libblock( &G.main->action, ID_AC, name_str ); + bl_action->id.flag |= LIB_FAKEUSER; /* no need to assign a user because alloc_libblock alredy assigns one */ + + + /* now create the wrapper obj in Python */ + if( bl_action ) + py_action = + ( BPy_Action * ) PyObject_NEW( BPy_Action, + &Action_Type ); + else { + EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't create Action Data in Blender" ); + return NULL; + } + + if( py_action == NULL ) { + EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create Action Data object" ); + return NULL; + } + + py_action->action = bl_action; /* link Python action wrapper with Blender Action */ + + Py_INCREF( py_action ); + return ( PyObject * ) py_action; +} + +static PyObject *M_NLA_CopyAction( PyObject * self_unused, PyObject * args ) +{ + BPy_Action *py_action = NULL; + bAction *copyAction = NULL; + + if( !PyArg_ParseTuple( args, "O!", &Action_Type, &py_action ) ) { + EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected python action type" ); + return NULL; + } + copyAction = copy_action( py_action->action ); + return Action_CreatePyObject( copyAction ); +} + +static PyObject *M_NLA_GetActions( PyObject * self_unused ) +{ + PyObject *dict = PyDict_New( ); + bAction *action = NULL; + + for( action = G.main->action.first; action; action = action->id.next ) { + PyObject *py_action = Action_CreatePyObject( action ); + if( py_action ) { + /* Insert dict entry using the bone name as key */ + if( PyDict_SetItemString + ( dict, action->id.name + 2, py_action ) != 0 ) { + Py_DECREF( py_action ); + Py_DECREF( dict ); + + return EXPP_ReturnPyObjError + ( PyExc_RuntimeError, + "NLA_GetActions: couldn't set dict item" ); + } + Py_DECREF( py_action ); + } else { + Py_DECREF( dict ); + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "NLA_GetActions: could not create Action object" ) ); + } + } + return dict; +} + +static PyObject *Action_getFrameNumbers(BPy_Action *self) +{ + bActionChannel *achan = NULL; + IpoCurve *icu = NULL; + BezTriple *bezt = NULL; + int verts; + PyObject *py_list = NULL; + + py_list = PyList_New(0); + for(achan = self->action->chanbase.first; achan; achan = achan->next){ + if (achan->ipo) { + for (icu = achan->ipo->curve.first; icu; icu = icu->next){ + bezt= icu->bezt; + if(bezt) { + verts = icu->totvert; + while(verts--) { + PyObject *value; + value = PyInt_FromLong((int)bezt->vec[1][0]); + if ( PySequence_Contains(py_list, value) == 0){ + PyList_Append(py_list, value); + } + Py_DECREF(value); + bezt++; + } + } + } + } + } + PyList_Sort(py_list); + return EXPP_incr_ret(py_list); +} + +static PyObject *Action_setActive( BPy_Action * self, PyObject * args ) +{ + BPy_Object *object; + + if( !self->action ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't get attribute from a NULL action" ); + + if( !PyArg_ParseTuple( args, "O!", &Object_Type, &object ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected python object argument" ); + + if( object->object->type != OB_ARMATURE ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "object not of type armature" ); + + /* if object is already attached to an action, decrement user count */ + if( object->object->action ) + --object->object->action->id.us; + + /* set the active action to object */ + object->object->action = self->action; + ++object->object->action->id.us; + + Py_RETURN_NONE; +} + +static PyObject *Action_getChannelIpo( BPy_Action * self, PyObject * value ) +{ + char *chanName = PyString_AsString(value); + bActionChannel *chan; + + if( !chanName ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "string expected" ); + + chan = get_action_channel( self->action, chanName ); + if( !chan ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "no channel with that name" ); + + if( !chan->ipo ) { + Py_RETURN_NONE; + } + + return Ipo_CreatePyObject( chan->ipo ); +} + +static PyObject *Action_getChannelNames( BPy_Action * self ) +{ + PyObject *list = PyList_New( BLI_countlist(&(self->action->chanbase)) ); + bActionChannel *chan = NULL; + int index=0; + for( chan = self->action->chanbase.first; chan; chan = chan->next ) { + PyList_SetItem( list, index, PyString_FromString(chan->name) ); + index++; + } + return list; +} + +static PyObject *Action_renameChannel( BPy_Action * self, PyObject * args ) +{ + char *chanFrom, *chanTo; + bActionChannel *chan; + + if( !PyArg_ParseTuple( args, "ss", &chanFrom, &chanTo ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "2 strings expected" ); + + chan = get_action_channel( self->action, chanFrom ); + if( !chan ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "no channel with that name" ); + if (strlen(chanTo) > 31) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "new name greater then 31 characters long" ); + + if (get_action_channel( self->action, chanTo )) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "channel target name alredy exists" ); + + strcpy(chan->name, chanTo); + + Py_RETURN_NONE; +} + +/*----------------------------------------------------------------------*/ +static PyObject *Action_verifyChannel( BPy_Action * self, PyObject * value ) +{ + char *chanName = PyString_AsString(value); + bActionChannel *chan; + + if( !self->action ) + ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't create channel for a NULL action" ) ); + + if( !chanName ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected string argument" ) ); + + chan = verify_action_channel(self->action, chanName); + + Py_RETURN_NONE; +} + + +static PyObject *Action_removeChannel( BPy_Action * self, PyObject * value ) +{ + char *chanName = PyString_AsString(value); + bActionChannel *chan; + + if( !chanName ) + return (EXPP_ReturnPyObjError( PyExc_AttributeError, + "string expected" )); + + + chan = get_action_channel( self->action, chanName ); + if( chan == NULL ) { + EXPP_ReturnPyObjError( PyExc_AttributeError, + "no channel with that name..." ); + return NULL; + } + /*release ipo*/ + if( chan->ipo ) + chan->ipo->id.us--; + + /*remove channel*/ + BLI_freelinkN( &self->action->chanbase, chan ); + + Py_RETURN_NONE; +} + +static PyObject *Action_getAllChannelIpos( BPy_Action * self ) +{ + PyObject *dict = PyDict_New( ); + bActionChannel *chan = NULL; + + for( chan = self->action->chanbase.first; chan; chan = chan->next ) { + PyObject *ipo_attr; + if( chan->ipo ) + ipo_attr = Ipo_CreatePyObject( chan->ipo ); + else { + ipo_attr = Py_None; + Py_INCREF( ipo_attr ); + } + if( ipo_attr ) { + /* Insert dict entry using the bone name as key*/ + if( PyDict_SetItemString( dict, chan->name, ipo_attr ) + != 0 ) { + Py_DECREF( ipo_attr ); + Py_DECREF( dict ); + + return EXPP_ReturnPyObjError + ( PyExc_RuntimeError, + "Action_getAllChannelIpos: couldn't set dict item" ); + } + Py_DECREF( ipo_attr ); + } else { + Py_DECREF( dict ); + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Action_getAllChannelIpos: could not create Ipo object" ) ); + } + } + return dict; +} + +/*----------------------------------------------------------------------*/ +static int Action_compare( BPy_Action * a, BPy_Action * b ) +{ + return ( a->action == b->action ) ? 0 : -1; +} + +/*----------------------------------------------------------------------*/ +static PyObject *Action_repr( BPy_Action * self ) +{ + if( self->action ) + return PyString_FromFormat( "[Action \"%s\"]", + self->action->id.name + 2 ); + else + return PyString_FromString( "NULL" ); +} + +/*----------------------------------------------------------------------*/ +PyObject *Action_CreatePyObject( struct bAction * act ) +{ + BPy_Action *blen_action; + + if(!act) Py_RETURN_NONE; + + blen_action = + ( BPy_Action * ) PyObject_NEW( BPy_Action, &Action_Type ); + + if( !blen_action) { + return ( EXPP_ReturnPyObjError + ( PyExc_RuntimeError, "failure to create object!" ) ); + } + blen_action->action = act; + return ( ( PyObject * ) blen_action ); +} + +/*----------------------------------------------------------------------*/ +struct bAction *Action_FromPyObject( PyObject * py_obj ) +{ + BPy_Action *blen_obj; + + blen_obj = ( BPy_Action * ) py_obj; + return ( blen_obj->action ); +} + +/*****************************************************************************/ +/* Python attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef BPy_Action_getseters[] = { + GENERIC_LIB_GETSETATTR, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/*****************************************************************************/ +/* Python TypeAction structure definition: */ +/*****************************************************************************/ +PyTypeObject Action_Type = { + PyObject_HEAD_INIT( NULL ) + 0, /* ob_size */ + "Blender Action", /* tp_name */ + sizeof( BPy_Action ), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + NULL, /* tp_dealloc */ + NULL, /* tp_print */ + NULL, /* tp_getattr */ + NULL, /* tp_setattr */ + ( cmpfunc ) Action_compare, /* tp_compare */ + ( reprfunc ) Action_repr, /* tp_repr */ + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_Action_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_Action_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + + + +/*****************************************************************************/ +/* ActionStrip wrapper */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* Python BPy_ActionStrip attributes: */ +/*****************************************************************************/ + +/* + * return the action for the action strip + */ + +static PyObject *ActionStrip_getAction( BPy_ActionStrip * self ) +{ + if( !self->strip ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This strip has been removed!" ); + + return Action_CreatePyObject( self->strip->act ); +} + +/* + * return the start frame of the action strip + */ + +static PyObject *ActionStrip_getStripStart( BPy_ActionStrip * self ) +{ + if( !self->strip ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This strip has been removed!" ); + + return PyFloat_FromDouble( self->strip->start ); +} + +/* + * set the start frame of the action strip + */ + +static int ActionStrip_setStripStart( BPy_ActionStrip * self, PyObject * value ) +{ + int retval; + + if( !self->strip ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "This strip has been removed!" ); + + retval = EXPP_setFloatClamped( value, &self->strip->start, + -1000.0, self->strip->end-1 ); + if( !retval ) { + float max = self->strip->end - self->strip->start; + if( self->strip->blendin > max ) + self->strip->blendin = max; + if( self->strip->blendout > max ) + self->strip->blendout = max; + } + return retval; +} + +/* + * return the ending frame of the action strip + */ + +static PyObject *ActionStrip_getStripEnd( BPy_ActionStrip * self ) +{ + if( !self->strip ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This strip has been removed!" ); + + return PyFloat_FromDouble( self->strip->end ); +} + +/* + * set the ending frame of the action strip + */ + +static int ActionStrip_setStripEnd( BPy_ActionStrip * self, PyObject * value ) +{ + int retval; + + if( !self->strip ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "This strip has been removed!" ); + + retval = EXPP_setFloatClamped( value, &self->strip->end, + self->strip->start+1, MAXFRAMEF ); + if( !retval ) { + float max = self->strip->end - self->strip->start; + if( self->strip->blendin > max ) + self->strip->blendin = max; + if( self->strip->blendout > max ) + self->strip->blendout = max; + } + return retval; +} + +/* + * return the start frame of the action + */ + +static PyObject *ActionStrip_getActionStart( BPy_ActionStrip * self ) +{ + if( !self->strip ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This strip has been removed!" ); + + return PyFloat_FromDouble( self->strip->actstart ); +} + +/* + * set the start frame of the action + */ + +static int ActionStrip_setActionStart( BPy_ActionStrip * self, PyObject * value ) +{ + if( !self->strip ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "This strip has been removed!" ); + + return EXPP_setFloatClamped( value, &self->strip->actstart, + -1000.0, self->strip->actend-1 ); +} + +/* + * return the ending frame of the action + */ + +static PyObject *ActionStrip_getActionEnd( BPy_ActionStrip * self ) +{ + if( !self->strip ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This strip has been removed!" ); + + return PyFloat_FromDouble( self->strip->actend ); +} + +/* + * set the ending frame of the action + */ + +static int ActionStrip_setActionEnd( BPy_ActionStrip * self, PyObject * value ) +{ + if( !self->strip ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "This strip has been removed!" ); + + return EXPP_setFloatClamped( value, &self->strip->actend, + self->strip->actstart+1, MAXFRAMEF ); +} + +/* + * return the repeat value of the action strip + */ + +static PyObject *ActionStrip_getRepeat( BPy_ActionStrip * self ) +{ + if( !self->strip ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This strip has been removed!" ); + + return PyFloat_FromDouble( self->strip->repeat ); +} + +/* + * set the repeat value of the action strip + */ + +static int ActionStrip_setRepeat( BPy_ActionStrip * self, PyObject * value ) +{ + if( !self->strip ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "This strip has been removed!" ); + + return EXPP_setFloatClamped( value, &self->strip->repeat, + 0.001f, 1000.0f ); +} + +/* + * return the blend in of the action strip + */ + +static PyObject *ActionStrip_getBlendIn( BPy_ActionStrip * self ) +{ + if( !self->strip ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This strip has been removed!" ); + + return PyFloat_FromDouble( self->strip->blendin ); +} + +/* + * set the blend in value of the action strip + */ + +static int ActionStrip_setBlendIn( BPy_ActionStrip * self, PyObject * value ) +{ + if( !self->strip ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "This strip has been removed!" ); + + return EXPP_setFloatClamped( value, &self->strip->blendin, + 0.0, self->strip->end - self->strip->start ); +} + +/* + * return the blend out of the action strip + */ + +static PyObject *ActionStrip_getBlendOut( BPy_ActionStrip * self ) +{ + if( !self->strip ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This strip has been removed!" ); + + return PyFloat_FromDouble( self->strip->blendout ); +} + +/* + * set the blend out value of the action strip + */ + +static int ActionStrip_setBlendOut( BPy_ActionStrip * self, PyObject * value ) +{ + if( !self->strip ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "This strip has been removed!" ); + + return EXPP_setFloatClamped( value, &self->strip->blendout, + 0.0, self->strip->end - self->strip->start ); +} + +/* + * return the blend mode of the action strip + */ + +static PyObject *ActionStrip_getBlendMode( BPy_ActionStrip * self ) +{ + if( !self->strip ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This strip has been removed!" ); + + return PyInt_FromLong( (long)self->strip->mode ) ; +} + +/* + * set the blend mode value of the action strip + */ + +static int ActionStrip_setBlendMode( BPy_ActionStrip * self, PyObject * value ) +{ + if( !self->strip ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "This strip has been removed!" ); + + return EXPP_setIValueRange( value, &self->strip->mode, + 0, ACTSTRIPMODE_ADD, 'h' ); +} + +/* + * return the flag settings of the action strip + */ + +#define ACTIONSTRIP_MASK (ACTSTRIP_SELECT | ACTSTRIP_USESTRIDE \ + | ACTSTRIP_HOLDLASTFRAME | ACTSTRIP_ACTIVE | ACTSTRIP_LOCK_ACTION) + +static PyObject *ActionStrip_getFlag( BPy_ActionStrip * self ) +{ + if( !self->strip ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This strip has been removed!" ); + + return PyInt_FromLong( (long)( self->strip->flag & ACTIONSTRIP_MASK ) ) ; +} + +/* + * set the flag settings out value of the action strip + */ + +static int ActionStrip_setFlag( BPy_ActionStrip * self, PyObject * arg ) +{ + PyObject *num = PyNumber_Int( arg ); + int value; + + if( !self->strip ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "This strip has been removed!" ); + if( !num ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected int argument" ); + value = PyInt_AS_LONG( num ); + Py_DECREF( num ); + + if( ( value & ACTIONSTRIP_MASK ) != value ) { + char errstr[128]; + sprintf ( errstr , "expected int bitmask of 0x%04x", ACTIONSTRIP_MASK ); + return EXPP_ReturnIntError( PyExc_TypeError, errstr ); + } + + self->strip->flag = (short)value; + return 0; +} + +/* + * return the stride axis of the action strip + */ + +static PyObject *ActionStrip_getStrideAxis( BPy_ActionStrip * self ) +{ + if( !self->strip ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This strip has been removed!" ); + + return PyInt_FromLong( (long)self->strip->stride_axis ) ; +} + +/* + * set the stride axis of the action strip + */ + +static int ActionStrip_setStrideAxis( BPy_ActionStrip * self, PyObject * value ) +{ + if( !self->strip ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "This strip has been removed!" ); + + return EXPP_setIValueRange( value, &self->strip->stride_axis, + ACTSTRIP_STRIDEAXIS_X, ACTSTRIP_STRIDEAXIS_Z, 'h' ); +} + +/* + * return the stride length of the action strip + */ + +static PyObject *ActionStrip_getStrideLength( BPy_ActionStrip * self ) +{ + if( !self->strip ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This strip has been removed!" ); + + return PyFloat_FromDouble( (double)self->strip->stridelen ) ; +} + +/* + * set the stride length of the action strip + */ + +static int ActionStrip_setStrideLength( BPy_ActionStrip * self, PyObject * value ) +{ + if( !self->strip ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "This strip has been removed!" ); + + return EXPP_setFloatClamped( value, &self->strip->stridelen, + 0.0001f, 1000.0 ); +} + +/* + * return the stride bone name + */ + +static PyObject *ActionStrip_getStrideBone( BPy_ActionStrip * self ) +{ + if( !self->strip ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This strip has been removed!" ); + + return PyString_FromString( self->strip->stridechannel ); +} + +static PyObject *ActionStrip_getGroupTarget( BPy_ActionStrip * self ) +{ + if( !self->strip ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This strip has been removed!" ); + + if (self->strip->object) { + return Object_CreatePyObject( self->strip->object ); + } else { + Py_RETURN_NONE; + } +} + +/* + * set the stride bone name + */ + +static int ActionStrip_setStrideBone( BPy_ActionStrip * self, PyObject * attr ) +{ + char *name = PyString_AsString( attr ); + if( !name ) + return EXPP_ReturnIntError( PyExc_TypeError, "expected string arg" ); + + if( !self->strip ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "This strip has been removed!" ); + + BLI_strncpy( self->strip->stridechannel, name, 32 ); + + return 0; +} + +static int ActionStrip_setGroupTarget( BPy_ActionStrip * self, PyObject * args ) +{ + if( !self->strip ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "This strip has been removed!" ); + + if( (PyObject *)args == Py_None ) + self->strip->object = NULL; + else if( BPy_Object_Check( args ) ) + self->strip->object = ((BPy_Object *)args)->object; + else + return EXPP_ReturnIntError( PyExc_TypeError, + "expected an object or None" ); + return 0; +} + +/*****************************************************************************/ +/* Python BPy_Constraint attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef BPy_ActionStrip_getseters[] = { + {"action", + (getter)ActionStrip_getAction, (setter)NULL, + "Action associated with the strip", NULL}, + {"stripStart", + (getter)ActionStrip_getStripStart, (setter)ActionStrip_setStripStart, + "Starting frame of the strip", NULL}, + {"stripEnd", + (getter)ActionStrip_getStripEnd, (setter)ActionStrip_setStripEnd, + "Ending frame of the strip", NULL}, + {"actionStart", + (getter)ActionStrip_getActionStart, (setter)ActionStrip_setActionStart, + "Starting frame of the action", NULL}, + {"actionEnd", + (getter)ActionStrip_getActionEnd, (setter)ActionStrip_setActionEnd, + "Ending frame of the action", NULL}, + {"repeat", + (getter)ActionStrip_getRepeat, (setter)ActionStrip_setRepeat, + "The number of times to repeat the action range", NULL}, + {"blendIn", + (getter)ActionStrip_getBlendIn, (setter)ActionStrip_setBlendIn, + "Number of frames of motion blending", NULL}, + {"blendOut", + (getter)ActionStrip_getBlendOut, (setter)ActionStrip_setBlendOut, + "Number of frames of ease-out", NULL}, + {"mode", + (getter)ActionStrip_getBlendMode, (setter)ActionStrip_setBlendMode, + "Setting of blending mode", NULL}, + {"flag", + (getter)ActionStrip_getFlag, (setter)ActionStrip_setFlag, + "Setting of blending flags", NULL}, + {"strideAxis", + (getter)ActionStrip_getStrideAxis, (setter)ActionStrip_setStrideAxis, + "Dominant axis for stride bone", NULL}, + {"strideLength", + (getter)ActionStrip_getStrideLength, (setter)ActionStrip_setStrideLength, + "Distance covered by one complete cycle of the action", NULL}, + {"strideBone", + (getter)ActionStrip_getStrideBone, (setter)ActionStrip_setStrideBone, + "Name of Bone used for stride", NULL}, + {"groupTarget", + (getter)ActionStrip_getGroupTarget, (setter)ActionStrip_setGroupTarget, + "Name of target armature within group", NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/*****************************************************************************/ +/* Python BPy_ActionStrip methods: */ +/*****************************************************************************/ + +/* + * restore the values of ActionStart and ActionEnd to their defaults + */ + +static PyObject *ActionStrip_resetLimits( BPy_ActionStrip *self ) +{ + bActionStrip *strip = self->strip; + + if( !strip ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This strip has been removed!" ); + + calc_action_range( strip->act, &strip->actstart, &strip->actend, 1 ); + + Py_RETURN_NONE; +} + +/* + * reset the strip size + */ + +static PyObject *ActionStrip_resetStripSize( BPy_ActionStrip *self ) +{ + float mapping; + bActionStrip *strip = self->strip; + + if( !strip ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This strip has been removed!" ); + + mapping = (strip->actend - strip->actstart) / (strip->end - strip->start); + strip->end = strip->start + mapping*(strip->end - strip->start); + + Py_RETURN_NONE; +} + +/* + * snap to start and end to nearest frames + */ + +static PyObject *ActionStrip_snapToFrame( BPy_ActionStrip *self ) +{ + bActionStrip *strip = self->strip; + + if( !strip ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This strip has been removed!" ); + + strip->start= (float)floor(strip->start+0.5); + strip->end= (float)floor(strip->end+0.5); + + Py_RETURN_NONE; +} + +/*****************************************************************************/ +/* Python BPy_ActionStrip methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_ActionStrip_methods[] = { + /* name, method, flags, doc */ + {"resetActionLimits", ( PyCFunction ) ActionStrip_resetLimits, METH_NOARGS, + "Restores the values of ActionStart and ActionEnd to their defaults"}, + {"resetStripSize", ( PyCFunction ) ActionStrip_resetStripSize, METH_NOARGS, + "Resets the Action Strip size to its creation values"}, + {"snapToFrame", ( PyCFunction ) ActionStrip_snapToFrame, METH_NOARGS, + "Snaps the ends of the action strip to the nearest whole numbered frame"}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python ActionStrip_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject ActionStrip_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender.ActionStrip", /* char *tp_name; */ + sizeof( BPy_ActionStrip ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + ( reprfunc ) NULL, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_ActionStrip_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_ActionStrip_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +static PyObject *M_ActionStrip_FlagsDict( void ) +{ + PyObject *S = PyConstant_New( ); + + if( S ) { + BPy_constant *d = ( BPy_constant * ) S; + PyConstant_Insert( d, "SELECT", + PyInt_FromLong( ACTSTRIP_SELECT ) ); + PyConstant_Insert( d, "STRIDE_PATH", + PyInt_FromLong( ACTSTRIP_USESTRIDE ) ); + PyConstant_Insert( d, "HOLD", + PyInt_FromLong( ACTSTRIP_HOLDLASTFRAME ) ); + PyConstant_Insert( d, "ACTIVE", + PyInt_FromLong( ACTSTRIP_ACTIVE ) ); + PyConstant_Insert( d, "LOCK_ACTION", + PyInt_FromLong( ACTSTRIP_LOCK_ACTION ) ); + } + return S; +} + +static PyObject *M_ActionStrip_AxisDict( void ) +{ + PyObject *S = PyConstant_New( ); + + if( S ) { + BPy_constant *d = ( BPy_constant * ) S; + PyConstant_Insert( d, "STRIDEAXIS_X", + PyInt_FromLong( ACTSTRIP_STRIDEAXIS_X ) ); + PyConstant_Insert( d, "STRIDEAXIS_Y", + PyInt_FromLong( ACTSTRIP_STRIDEAXIS_Y ) ); + PyConstant_Insert( d, "STRIDEAXIS_Z", + PyInt_FromLong( ACTSTRIP_STRIDEAXIS_Z ) ); + } + return S; +} + +static PyObject *M_ActionStrip_ModeDict( void ) +{ + PyObject *S = PyConstant_New( ); + + if( S ) { + BPy_constant *d = ( BPy_constant * ) S; + PyConstant_Insert( d, "MODE_ADD", + PyInt_FromLong( ACTSTRIPMODE_ADD ) ); + } + return S; +} + +PyObject *ActionStrip_CreatePyObject( struct bActionStrip *strip ) +{ + BPy_ActionStrip *pyobj; + pyobj = ( BPy_ActionStrip * ) PyObject_NEW( BPy_ActionStrip, + &ActionStrip_Type ); + if( !pyobj ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create BPy_ActionStrip object" ); + pyobj->strip = strip; + return ( PyObject * ) pyobj; +} + +/*****************************************************************************/ +/* ActionStrip Sequence wrapper */ +/*****************************************************************************/ + +/* + * Initialize the iterator + */ + +static PyObject *ActionStrips_getIter( BPy_ActionStrips * self ) +{ + self->iter = (bActionStrip *)self->ob->nlastrips.first; + return EXPP_incr_ret ( (PyObject *) self ); +} + +/* + * Get the next action strip + */ + +static PyObject *ActionStrips_nextIter( BPy_ActionStrips * self ) +{ + bActionStrip *strip = self->iter; + if( strip ) { + self->iter = strip->next; + return ActionStrip_CreatePyObject( strip ); + } + + return EXPP_ReturnPyObjError( PyExc_StopIteration, + "iterator at end" ); +} + +/* return the number of action strips */ + +static int ActionStrips_length( BPy_ActionStrips * self ) +{ + return BLI_countlist( &self->ob->nlastrips ); +} + +/* return an action strip */ + +static PyObject *ActionStrips_item( BPy_ActionStrips * self, int i ) +{ + bActionStrip *strip = NULL; + + /* if index is negative, start counting from the end of the list */ + if( i < 0 ) + i += ActionStrips_length( self ); + + /* skip through the list until we get the strip or end of list */ + + strip = self->ob->nlastrips.first; + + while( i && strip ) { + --i; + strip = strip->next; + } + + if( strip ) + return ActionStrip_CreatePyObject( strip ); + else + return EXPP_ReturnPyObjError( PyExc_IndexError, + "array index out of range" ); +} + +/*****************************************************************************/ +/* Python BPy_ActionStrips sequence table: */ +/*****************************************************************************/ +static PySequenceMethods ActionStrips_as_sequence = { + ( inquiry ) ActionStrips_length, /* sq_length */ + ( binaryfunc ) 0, /* sq_concat */ + ( intargfunc ) 0, /* sq_repeat */ + ( intargfunc ) ActionStrips_item, /* sq_item */ + ( intintargfunc ) 0, /* sq_slice */ + ( intobjargproc ) 0, /* sq_ass_item */ + ( intintobjargproc ) 0, /* sq_ass_slice */ + ( objobjproc ) 0, /* sq_contains */ + ( binaryfunc ) 0, /* sq_inplace_concat */ + ( intargfunc ) 0, /* sq_inplace_repeat */ +}; + + +/*****************************************************************************/ +/* Python BPy_ActionStrip methods: */ +/*****************************************************************************/ + +/* + * helper function to check for a valid action strip argument + */ + +static bActionStrip *locate_strip( BPy_ActionStrips *self, + PyObject *args, BPy_ActionStrip **stripobj ) +{ + bActionStrip *strip = NULL; + BPy_ActionStrip *pyobj; + + /* check that argument is a constraint */ + if( !PyArg_ParseTuple( args, "O!", &ActionStrip_Type, &pyobj ) ) { + EXPP_ReturnPyObjError( PyExc_TypeError, + "expected an action strip as an argument" ); + return NULL; + } + + if( !pyobj->strip ) { + EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This strip has been removed!" ); + return NULL; + } + + /* if caller needs the object, return it */ + if( stripobj ) + *stripobj = pyobj; + + /* find the action strip in the NLA */ + for( strip = self->ob->nlastrips.first; strip; strip = strip->next ) + if( strip == pyobj->strip ) + return strip; + + /* return exception if we can't find the strip */ + EXPP_ReturnPyObjError( PyExc_AttributeError, + "action strip does not belong to this object" ); + return NULL; +} + +/* + * remove an action strip from the NLA + */ + +static PyObject *ActionStrips_remove( BPy_ActionStrips *self, PyObject * args ) +{ + BPy_ActionStrip *pyobj; + bActionStrip *strip = locate_strip( self, args, &pyobj ); + + /* return exception if we can't find the strip */ + if( !strip ) + return (PyObject *)NULL; + + /* do the actual removal */ + free_actionstrip(strip); + BLI_remlink(&self->ob->nlastrips, strip); + MEM_freeN(strip); + + pyobj->strip = NULL; + Py_RETURN_NONE; +} + +/* + * move an action strip up in the strip list + */ + +static PyObject *ActionStrips_moveUp( BPy_ActionStrips *self, PyObject * args ) +{ + bActionStrip *strip = locate_strip( self, args, NULL ); + + /* return exception if we can't find the strip */ + if( !strip ) + return (PyObject *)NULL; + + /* if strip is not already the first, move it up */ + if( strip != self->ob->nlastrips.first ) { + BLI_remlink(&self->ob->nlastrips, strip); + BLI_insertlink(&self->ob->nlastrips, strip->prev->prev, strip); + } + + Py_RETURN_NONE; +} + +/* + * move an action strip down in the strip list + */ + +static PyObject *ActionStrips_moveDown( BPy_ActionStrips *self, PyObject * args ) +{ + bActionStrip *strip = locate_strip( self, args, NULL ); + + /* return exception if we can't find the strip */ + if( !strip ) + return (PyObject *)NULL; + + /* if strip is not already the last, move it down */ + if( strip != self->ob->nlastrips.last ) { + BLI_remlink(&self->ob->nlastrips, strip); + BLI_insertlink(&self->ob->nlastrips, strip->next, strip); + } + + Py_RETURN_NONE; +} + +static PyObject *ActionStrips_append( BPy_ActionStrips *self, PyObject * args ) +{ + BPy_Action *pyobj; + Object *ob; + bActionStrip *strip; + bAction *act; + + /* check that argument is an action */ + if( !PyArg_ParseTuple( args, "O!", &Action_Type, &pyobj ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected an action as an argument" ); + + ob = self->ob; + act = pyobj->action; + + /* Initialize the new action block */ + strip = MEM_callocN( sizeof(bActionStrip), "bActionStrip" ); + + strip->act = act; + calc_action_range( strip->act, &strip->actstart, &strip->actend, 1 ); + strip->start = (float)G.scene->r.cfra; + strip->end = strip->start + ( strip->actend - strip->actstart ); + /* simple prevention of zero strips */ + if( strip->start > strip->end-2 ) + strip->end = strip->start+100; + + strip->flag = ACTSTRIP_LOCK_ACTION; + find_stridechannel(ob, strip); + + strip->repeat = 1.0; + act->id.us++; + + BLI_addtail(&ob->nlastrips, strip); + + Py_RETURN_NONE; +} + +/*****************************************************************************/ +/* Python BPy_ActionStrips methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_ActionStrips_methods[] = { + /* name, method, flags, doc */ + {"append", ( PyCFunction ) ActionStrips_append, METH_VARARGS, + "(action) - append a new actionstrip using existing action"}, + {"remove", ( PyCFunction ) ActionStrips_remove, METH_VARARGS, + "(strip) - remove an existing strip from this actionstrips"}, + {"moveUp", ( PyCFunction ) ActionStrips_moveUp, METH_VARARGS, + "(strip) - move an existing strip up in the actionstrips"}, + {"moveDown", ( PyCFunction ) ActionStrips_moveDown, METH_VARARGS, + "(strip) - move an existing strip down in the actionstrips"}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python ActionStrips_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject ActionStrips_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender.ActionStrips", /* char *tp_name; */ + sizeof( BPy_ActionStrips ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + ( reprfunc ) NULL, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + &ActionStrips_as_sequence, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + ( getiterfunc )ActionStrips_getIter, /* getiterfunc tp_iter; */ + ( iternextfunc )ActionStrips_nextIter, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_ActionStrips_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + NULL, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +PyObject *ActionStrips_CreatePyObject( Object *ob ) +{ + BPy_ActionStrips *pyseq; + pyseq = ( BPy_ActionStrips * ) PyObject_NEW( BPy_ActionStrips, + &ActionStrips_Type ); + if( !pyseq ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create BPy_ActionStrips object" ); + pyseq->ob = ob; + return ( PyObject * ) pyseq; +} + +/*****************************************************************************/ +/* Function: NLA_Init */ +/*****************************************************************************/ +PyObject *NLA_Init( void ) +{ + PyObject *FlagsDict = M_ActionStrip_FlagsDict( ); + PyObject *AxisDict = M_ActionStrip_AxisDict( ); + PyObject *ModeDict = M_ActionStrip_ModeDict( ); + PyObject *submodule; + + if( PyType_Ready( &Action_Type ) < 0 + || PyType_Ready( &ActionStrip_Type ) < 0 + || PyType_Ready( &ActionStrips_Type ) < 0 ) + return NULL; + + submodule = Py_InitModule3( "Blender.Armature.NLA", + M_NLA_methods, M_NLA_doc ); + + if( FlagsDict ) + PyModule_AddObject( submodule, "Flags", FlagsDict ); + if( AxisDict ) + PyModule_AddObject( submodule, "StrideAxes", AxisDict ); + if( ModeDict ) + PyModule_AddObject( submodule, "Modes", ModeDict ); + + return submodule; +} diff --git a/source/blender/python/api2_2x/NLA.h b/source/blender/python/api2_2x/NLA.h new file mode 100644 index 00000000000..45873db40a4 --- /dev/null +++ b/source/blender/python/api2_2x/NLA.h @@ -0,0 +1,77 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Joseph Gilbert, Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_NLA_H +#define EXPP_NLA_H + +#include +#include "DNA_action_types.h" +#include "DNA_nla_types.h" + +struct Object; + +/** NLA module initialization function. */ +PyObject *NLA_Init( void ); + +extern PyTypeObject Action_Type; +extern PyTypeObject ActionStrip_Type; +extern PyTypeObject ActionStrips_Type; + +/** Python BPy_NLA structure definition. */ +typedef struct { + PyObject_HEAD + bAction * action; /* libdata must be second */ +} BPy_Action; + +typedef struct { + PyObject_HEAD + bActionStrip * strip; +} BPy_ActionStrip; + +typedef struct { + PyObject_HEAD + struct Object * ob; + struct bActionStrip *iter; +} BPy_ActionStrips; + +/* Type checking for EXPP PyTypes */ +#define BPy_Action_Check(v) ((v)->ob_type == &Action_Type) +#define BPy_ActionStrip_Check(v) ((v)->ob_type == &ActionStrip_Type) +#define BPy_ActionStrips_Check(v) ((v)->ob_type == &ActionStrips_Type) + +PyObject *Action_CreatePyObject( struct bAction *action ); +bAction *Action_FromPyObject( PyObject * py_obj ); + +PyObject *ActionStrip_CreatePyObject( struct bActionStrip *strip ); +PyObject *ActionStrips_CreatePyObject( struct Object *ob ); + +#endif diff --git a/source/blender/python/api2_2x/NMesh.c b/source/blender/python/api2_2x/NMesh.c new file mode 100644 index 00000000000..e50c9678606 --- /dev/null +++ b/source/blender/python/api2_2x/NMesh.c @@ -0,0 +1,4164 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender, but it borrows all the old NMesh code. + * + * Contributor(s): Willian P. Germano, Jordi Rovira i Bonet, Joseph Gilbert, + * Bala Gi, Alexander Szakaly, Stephane Soppera, Campbell Barton, Ken Hughes, + * Daniel Dunbar. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "NMesh.h" /*This must come first*/ + +#include "MEM_guardedalloc.h" + +#include "DNA_key_types.h" +#include "DNA_armature_types.h" +#include "DNA_scene_types.h" +#include "DNA_space_types.h" +#include "DNA_curve_types.h" + +#include "BDR_editface.h" /* make_tfaces */ +#include "BDR_vpaint.h" +#include "BDR_editobject.h" + +#include "BIF_editdeform.h" +#include "BIF_editkey.h" /* insert_meshkey */ +#include "BIF_editview.h" +#include "BIF_space.h" + +#include "BKE_customdata.h" +#include "BKE_deform.h" +#include "BKE_mesh.h" +#include "BKE_material.h" +#include "BKE_main.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_DerivedMesh.h" +#include "BKE_displist.h" +#include "BKE_object.h" +#include "BKE_mball.h" +#include "BKE_utildefines.h" +#include "BKE_depsgraph.h" +#include "BKE_idprop.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" + +#include "blendef.h" +#include "mydevice.h" +#include "Object.h" +#include "Key.h" +#include "Mathutils.h" +#include "IDProp.h" +#include "constant.h" +#include "gen_utils.h" +#include "gen_library.h" + +extern void countall(void); + +/* EXPP Mesh defines */ + +#define NMESH_FRAME_MAX 30000 +#define NMESH_SMOOTHRESH 30 +#define NMESH_SMOOTHRESH_MIN 1 +#define NMESH_SMOOTHRESH_MAX 80 +#define NMESH_SUBDIV 1 +#define NMESH_SUBDIV_MIN 0 +#define NMESH_SUBDIV_MAX 6 + +/* Globals */ +static PyObject *g_nmeshmodule = NULL; + +static int unlink_existingMeshData( Mesh * mesh ); +static int convert_NMeshToMesh( Mesh *mesh, BPy_NMesh *nmesh ); +static void check_dverts(Mesh *me, int old_totverts); +static PyObject *NMesh_printDebug( PyObject * self ); +static PyObject *NMesh_addEdge( PyObject * self, PyObject * args ); +static PyObject *NMesh_findEdge( PyObject * self, PyObject * args ); +static PyObject *NMesh_removeEdge( PyObject * self, PyObject * args ); +static PyObject *NMesh_addFace( PyObject * self, PyObject * args ); +static PyObject *NMesh_removeFace( PyObject * self, PyObject * args ); +static PyObject *NMesh_addVertGroup( PyObject * self, PyObject * args ); +static PyObject *NMesh_removeVertGroup( PyObject * self, PyObject * args ); +static PyObject *NMesh_assignVertsToGroup( PyObject * self, PyObject * args ); +static PyObject *NMesh_removeVertsFromGroup( PyObject * self,PyObject * args ); +static PyObject *NMesh_getVertsFromGroup( PyObject * self, PyObject * args ); +static PyObject *NMesh_renameVertGroup( PyObject * self, PyObject * args ); +static PyObject *NMesh_getVertGroupNames( PyObject * self ); +static PyObject *NMesh_transform (PyObject *self, PyObject *args); + +static char NMesh_printDebug_doc[] = + "print debug info about the mesh."; + +static char NMesh_getKey_doc[] = + "get the Key object linked to this mesh"; + +static char NMesh_addEdge_doc[] = + "create an edge between two vertices.\n\ +If an edge already exists between those vertices, it is returned.\n\ +(In Blender, only zero or one edge can link two vertices.)\n\ +Created edge is automatically added to edges list."; + +static char NMesh_findEdge_doc[] = + "find an edge between two vertices."; + +static char NMesh_removeEdge_doc[] = + "remove an edge between two vertices.\n\ +All faces using this edge are removed from faces list."; + +static char NMesh_addFace_doc[] = + "add a face to face list and add to edge list (if edge data exists) necessary edges."; + +static char NMesh_removeFace_doc[] = + "remove a face for face list and remove edges no more used by any other face (if \ +edge data exists)."; + +static char NMesh_addVertGroup_doc[] = + "add a named and empty vertex(deform) Group to a mesh that has been linked\n\ +to an object. "; + +static char NMesh_removeVertGroup_doc[] = + "remove a named vertex(deform) Group from a mesh that has been linked\n\ +to an object. Will remove all verts assigned to group."; + +static char NMesh_assignVertsToGroup_doc[] = + "Adds an array (a python list) of vertex points (by index) to a named\n\ +vertex group. The list will have an associated wieght assigned to them.\n\ +The weight represents the amount of influence this group has over these\n\ +vertex points. Weights should be in the range of 0.0 - 1.0.\n\ +The assignmode can be either 'add', 'subtract', or 'replace'. If this vertex\n\ +is not assigned to the group 'add' creates a new association with the weight\n\ +specified, otherwise the weight given is added to the current weight of the\n\ +vertex.\n\ +'subtract' will attempt to subtract the weight passed from a vertex already\n\ +associated with a group, else it does nothing. 'replace' attempts to replace\n\ +the weight with the new weight value for an already associated vertex/group,\n\ +else it does nothing. The mesh must have all it's vertex points set before\n\ +attempting to assign any vertex points to a vertex group."; + +static char NMesh_removeVertsFromGroup_doc[] = + "Remove an array (a python list) of vertex points from a named group in a\n\ +mesh that has been linked to an object. If no list is given this will remove\n\ +all vertex point associations with the group passed"; + +static char NMesh_getVertsFromGroup_doc[] = + "By passing a python list of vertex indices and a named group, this will\n\ +return a python list representing the indeces that are a part of this vertex.\n\ +group. If no association was found for the index passed nothing will be\n\ +return for the index. An optional flag will also return the weights as well"; + +static char NMesh_renameVertGroup_doc[] = "Renames a vertex group"; + +static char NMesh_getVertGroupNames_doc[] = + "Returns a list of all the vertex group names"; + +static char M_NMesh_doc[] = "The Blender.NMesh submodule"; + +static char M_NMesh_Col_doc[] = "([r, g, b, a]) - Get a new mesh color\n\n\ +[r=255, g=255, b=255, a=255] Specify the color components"; + +static char M_NMesh_Face_doc[] = + "(vertexlist = None) - Get a new face, and pass optional vertex list"; + +static char NMFace_append_doc[] = + "(vert) - appends Vertex 'vert' to face vertex list"; + +static char M_NMesh_Vert_doc[] = "([x, y, z]) - Get a new vertex\n\n\ +[x, y, z] Specify new coordinates"; + +static char NMesh_getMaterials_doc[] = + "(i = -1) - Get this mesh's list of materials.\n\ +(i = -1) - int: determines the list's contents:\n\ +-1: return the current list, possibly modified by the script (default);\n\ + 0: get a fresh list from the Blender mesh -- modifications not included,\n\ + unless the script called mesh.update() first;\n\ + 1: like 0, but does not ignore empty slots, returns them as 'None'."; + +static char NMesh_setMaterials_doc[] = + "(matlist) - Set this mesh's list of materials. This method makes sure\n\ +the passed matlist is valid (can only include up to 16 materials and None's)."; + +static char NMesh_addMaterial_doc[] = + "(material) - add a new Blender Material 'material' to this Mesh's materials\n\ +list."; + +static char NMesh_insertKey_doc[] = + "(frame = None, type = 'relative') - inserts a Mesh key at the given frame\n\ +if called without arguments, it inserts the key at the current Scene frame.\n\ +(type) - 'relative' or 'absolute'. Only relevant on the first call to this\n\ +function for each nmesh."; + +static char NMesh_removeAllKeys_doc[] = + "() - removes all keys from this mesh\n\ +returns True if successful or False if this NMesh wasn't linked to a real\n\ +Blender Mesh yet or the Mesh had no keys"; + +static char NMesh_getSelectedFaces_doc[] = + "(flag = None) - returns list of selected Faces\n\ +If flag = 1, return indices instead"; + +static char NMesh_getActiveFace_doc[] = + "returns the index of the active face "; + +static char NMesh_hasVertexUV_doc[] = + "(flag = None) - returns 1 if Mesh has per vertex UVs ('Sticky')\n\ +The optional argument sets the Sticky flag"; + +static char NMesh_hasFaceUV_doc[] = + "(flag = None) - returns 1 if Mesh has textured faces\n\ +The optional argument sets the textured faces flag"; + +static char NMesh_hasVertexColours_doc[] = + "(flag = None) - returns 1 if Mesh has vertex colors.\n\ +The optional argument sets the vertex color flag"; + +static char NMesh_getVertexInfluences_doc[] = + "Return a list of the influences of bones in the vertex \n\ +specified by index. The list contains pairs with the \n\ +bone name and the weight."; + +static char NMesh_update_doc[] = +"(recalc_normals = 0, store_edges = 0, vertex_shade = 0) - Updates the Mesh.\n\ +Optional arguments: if given and nonzero:\n\ +'recalc_normals': normal vectors are recalculated;\n\ +'store_edges': edges data is stored.\n\ +'vertex_shade': vertex colors are added based on the current lamp setup."; + +static char NMesh_getMode_doc[] = + "() - get the mode flags of this nmesh as an or'ed int value."; + +static char NMesh_setMode_doc[] = + "(int or none to 5 strings) - set the mode flags of this nmesh.\n\ +() - unset all flags."; + +static char NMesh_getMaxSmoothAngle_doc[] = + "() - get the max smooth angle for mesh auto smoothing."; + +static char NMesh_setMaxSmoothAngle_doc[] = + "(int) - set the max smooth angle for mesh auto smoothing in the range\n\ +[1,80] in degrees."; + +static char NMesh_getSubDivLevels_doc[] = + "() - get the subdivision levels for display and rendering: [display, render]"; + +static char NMesh_setSubDivLevels_doc[] = + "([int, int]) - set the subdivision levels for [display, render] -- they are\n\ +clamped to the range [0,6]."; + +static char M_NMesh_New_doc[] = + "() - returns a new, empty NMesh mesh object\n"; + +static char M_NMesh_GetRaw_doc[] = "([name]) - Get a raw mesh from Blender\n\n\ +[name] Name of the mesh to be returned\n\n\ +If name is not specified a new empty mesh is\n\ +returned, otherwise Blender returns an existing\n\ +mesh."; + +static char M_NMesh_GetNames_doc[] = "\ +() - Get a list with the names of all available meshes in Blender\n\n\ +Any of these names can be passed to NMesh.GetRaw() for the actual mesh data."; + +static char M_NMesh_GetRawFromObject_doc[] = + "(name) - Get the raw mesh used by a Blender object\n\n\ +(name) Name of the object to get the mesh from\n\n\ +This returns the mesh as used by the object, which\n\ +means it contains all deformations and modifications."; + +static char M_NMesh_PutRaw_doc[] = + "(mesh, name = None, recalc_normals = 1, store_edges = 0]) -\n\ +Return a raw mesh to Blender\n\n\ +(mesh) The NMesh object to store\n\ +[name] The mesh to replace\n\ +[recalc_normals = 1] Flag to control vertex normal recalculation\n\ +[store_edges=0] Store edges data in the blender mesh\n\ +If the name of a mesh to replace is not given a new\n\ +object is created and returned."; + +static char NMesh_transform_doc[] = +"(matrix, recalc_normals = 0) - Transform the mesh by the supplied 4x4 matrix\n\ +if recalc_normals is True, vertex normals are transformed along with \n\ +vertex coordinatess.\n"; + + +void mesh_update( Mesh * mesh, Object * ob ) +{ + if (ob) { + DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); + } + else { + ob = G.main->object.first; + while (ob) { + if (ob->data == mesh) { + DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); + break; + } + ob = ob->id.next; + } + } +} + +/* + * before trying to convert NMesh data back to mesh, verify that the + * lists contain the right type of data + */ + +static int check_NMeshLists( BPy_NMesh *nmesh ) +{ + int i; + + if( !PySequence_Check( nmesh->verts ) ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "nmesh verts are not a sequence" ); + if( !PySequence_Check( nmesh->edges ) ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "nmesh edges are not a sequence" ); + if( !PySequence_Check( nmesh->faces ) ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "nmesh faces are not a sequence" ); + if( !PySequence_Check( nmesh->materials ) ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "nmesh materials are not a sequence" ); + + if( EXPP_check_sequence_consistency( nmesh->verts, &NMVert_Type ) != 1 ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "nmesh vertices must be NMVerts" ); + if( EXPP_check_sequence_consistency( nmesh->edges, &NMEdge_Type ) != 1 ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "nmesh edges must be NMEdges" ); + if( EXPP_check_sequence_consistency( nmesh->faces, &NMFace_Type ) != 1 ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "nmesh faces must be NMFaces" ); + for( i = 0 ; i < PySequence_Length(nmesh->faces); ++i ) { + int j, err=0; + PyObject *col, *v, *uv; + BPy_NMFace *face=(BPy_NMFace *)PySequence_GetItem(nmesh->faces, i); + + col = face->col; + uv = face->uv; + v = face->v; + Py_DECREF( face ); + if( EXPP_check_sequence_consistency( face->col, &NMCol_Type ) != 1 ) { + return EXPP_ReturnIntError( PyExc_AttributeError, + "nmesh face col must be NMCols" ); + } + if( EXPP_check_sequence_consistency( face->v, &NMVert_Type ) != 1 ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "nmesh face v must be NMVerts" ); + + for( j = 0 ; !err && j < PySequence_Length( face->uv ); ++j ) { + PyObject *uv = PySequence_GetItem( face->uv, j); + if( PySequence_Check(uv) && PySequence_Length(uv) == 2 ) { + PyObject *p1 = PySequence_GetItem(uv, 0); + PyObject *p2 = PySequence_GetItem(uv, 1); + if( !PyNumber_Check(p1) || !PyNumber_Check(p2) ) + err = 1; + Py_DECREF( p1 ); + Py_DECREF( p2 ); + } + else { + err = 1; + } + + Py_DECREF( uv ); + } + if( err ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "nmesh face uv must contain sequence of 2 floats" ); + } + return 0; +} + + +/*****************************/ +/* Mesh Color Object */ +/*****************************/ + +static void NMCol_dealloc( PyObject * self ) +{ + PyObject_DEL( self ); +} + +static BPy_NMCol *newcol( char r, char g, char b, char a ) +{ + BPy_NMCol *mc = ( BPy_NMCol * ) PyObject_NEW( BPy_NMCol, &NMCol_Type ); + + mc->r = r; + mc->g = g; + mc->b = b; + mc->a = a; + + return mc; +} + +static PyObject *M_NMesh_Col( PyObject * self, PyObject * args ) +{ + char r = 255, g = 255, b = 255, a = 255; + + if( PyArg_ParseTuple( args, "|bbbb", &r, &g, &b, &a ) ) + return ( PyObject * ) newcol( r, g, b, a ); + + return NULL; +} + +static PyObject *NMCol_getattr( PyObject * self, char *name ) +{ + BPy_NMCol *mc = ( BPy_NMCol * ) self; + + if( strcmp( name, "r" ) == 0 ) + return Py_BuildValue( "i", mc->r ); + else if( strcmp( name, "g" ) == 0 ) + return Py_BuildValue( "i", mc->g ); + else if( strcmp( name, "b" ) == 0 ) + return Py_BuildValue( "i", mc->b ); + else if( strcmp( name, "a" ) == 0 ) + return Py_BuildValue( "i", mc->a ); + else if( strcmp( name, "__members__" ) == 0 ) + return Py_BuildValue( "[s,s,s,s]", "r", "g", "b", "a" ); + + return EXPP_ReturnPyObjError( PyExc_AttributeError, name ); +} + +static int NMCol_setattr( PyObject * self, char *name, PyObject * v ) +{ + BPy_NMCol *mc = ( BPy_NMCol * ) self; + char ival; + + if( !PyArg_Parse( v, "b", &ival ) ) + return -1; + + ival = ( char ) EXPP_ClampInt( ival, 0, 255 ); + + if( strcmp( name, "r" ) == 0 ) + mc->r = (unsigned char)ival; + else if( strcmp( name, "g" ) == 0 ) + mc->g = (unsigned char)ival; + else if( strcmp( name, "b" ) == 0 ) + mc->b = (unsigned char)ival; + else if( strcmp( name, "a" ) == 0 ) + mc->a = (unsigned char)ival; + else + return -1; + + return 0; +} + +static PyObject *NMCol_repr( BPy_NMCol * self ) +{ + static char s[256]; + sprintf( s, "[NMCol - <%d, %d, %d, %d>]", self->r, self->g, self->b, + self->a ); + return Py_BuildValue( "s", s ); +} + +PyTypeObject NMCol_Type = { + PyObject_HEAD_INIT( NULL ) 0, /* ob_size */ + "Blender NMCol", /* tp_name */ + sizeof( BPy_NMCol ), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + ( destructor ) NMCol_dealloc, /* tp_dealloc */ + ( printfunc ) 0, /* tp_print */ + ( getattrfunc ) NMCol_getattr, /* tp_getattr */ + ( setattrfunc ) NMCol_setattr, /* tp_setattr */ + 0, /* tp_compare */ + ( reprfunc ) NMCol_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* up to tp_del to avoid a warning */ +}; + +/*****************************/ +/* NMesh Python Object */ +/*****************************/ +static void NMFace_dealloc( PyObject * self ) +{ + BPy_NMFace *mf = ( BPy_NMFace * ) self; + + Py_DECREF( mf->v ); + Py_DECREF( mf->uv ); + Py_DECREF( mf->col ); + + PyObject_DEL( self ); +} + +static PyObject *new_NMFace( PyObject * vertexlist ) +{ + BPy_NMFace *mf = PyObject_NEW( BPy_NMFace, &NMFace_Type ); + PyObject *vlcopy; + + if( vertexlist ) { /* create a copy of the given vertex list */ + PyObject *item; + int i, len = PyList_Size( vertexlist ); + + vlcopy = PyList_New( len ); + + if( !vlcopy ) { + Py_DECREF(mf); + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyList" ); + } + for( i = 0; i < len; i++ ) { + item = PySequence_GetItem( vertexlist, i ); /* PySequence increfs */ + + if( item ) + PyList_SET_ITEM( vlcopy, i, item ); + else { + Py_DECREF(mf); + Py_DECREF(vlcopy); + return EXPP_ReturnPyObjError + ( PyExc_RuntimeError, + "couldn't get vertex from a PyList" ); + } + } + } else /* create an empty vertex list */ + vlcopy = PyList_New( 0 ); + + mf->v = vlcopy; + mf->uv = PyList_New( 0 ); + mf->image = NULL; + mf->mode = TF_DYNAMIC + TF_TEX; + mf->flag = TF_SELECT; + mf->transp = TF_SOLID; + mf->col = PyList_New( 0 ); + + mf->mf_flag = 0; + mf->mat_nr = 0; + mf->orig_index = -1; + + return ( PyObject * ) mf; +} + +static PyObject *M_NMesh_Face( PyObject * self, PyObject * args ) +{ + PyObject *vertlist = NULL; + + if( !PyArg_ParseTuple( args, "|O!", &PyList_Type, &vertlist ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a list of vertices or nothing as argument" ); + +/* if (!vertlist) vertlist = PyList_New(0); */ + + return new_NMFace( vertlist ); +} + +static PyObject *NMFace_append( PyObject * self, PyObject * args ) +{ + PyObject *vert; + BPy_NMFace *f = ( BPy_NMFace * ) self; + + if( !PyArg_ParseTuple( args, "O!", &NMVert_Type, &vert ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected an NMVert object" ); + + PyList_Append( f->v, vert ); + + Py_RETURN_NONE; +} + +#undef MethodDef +#define MethodDef(func) {#func, NMFace_##func, METH_VARARGS, NMFace_##func##_doc} + +static struct PyMethodDef NMFace_methods[] = { + MethodDef( append ), + {NULL, NULL, 0, NULL} +}; + +static PyObject *NMFace_getattr( PyObject * self, char *name ) +{ + BPy_NMFace *mf = ( BPy_NMFace * ) self; + + if( strcmp( name, "v" ) == 0 ) + return Py_BuildValue( "O", mf->v ); + else if( strcmp( name, "col" ) == 0 ) + return Py_BuildValue( "O", mf->col ); + else if( strcmp( name, "mat" ) == 0 ) // emulation XXX + return Py_BuildValue( "i", mf->mat_nr ); + else if( strcmp( name, "materialIndex" ) == 0 ) + return Py_BuildValue( "i", mf->mat_nr ); + else if( strcmp( name, "smooth" ) == 0 ) + return Py_BuildValue( "i", (mf->mf_flag & ME_SMOOTH) ? 1:0 ); + else if( strcmp( name, "sel" ) == 0 ) + return Py_BuildValue( "i", (mf->mf_flag & ME_FACE_SEL) ? 1:0 ); + else if( strcmp( name, "hide" ) == 0 ) + return Py_BuildValue( "i", (mf->mf_flag & ME_HIDE) ? 1:0 ); + + else if( strcmp( name, "image" ) == 0 ) { + if( mf->image ) + return Image_CreatePyObject( mf->image ); + else + Py_RETURN_NONE; + } + + else if( strcmp( name, "mode" ) == 0 ) + return Py_BuildValue( "i", mf->mode ); + else if( strcmp( name, "flag" ) == 0 ) + return Py_BuildValue( "i", mf->flag ); + else if( strcmp( name, "transp" ) == 0 ) + return Py_BuildValue( "i", mf->transp ); + else if( strcmp( name, "uv" ) == 0 ) + return Py_BuildValue( "O", mf->uv ); + + else if( ( strcmp( name, "normal" ) == 0 ) + || ( strcmp( name, "no" ) == 0 ) ) { + + if( EXPP_check_sequence_consistency( mf->v, &NMVert_Type ) == + 1 ) { + + float fNormal[3] = { 0.0, 0.0, 0.0 }; + float *vco[4] = { NULL, NULL, NULL, NULL }; + int nSize = PyList_Size( mf->v ); + int loop; + + if( nSize != 3 && nSize != 4 ) + return EXPP_ReturnPyObjError + ( PyExc_AttributeError, + "face must contain either 3 or 4 verts" ); + + for( loop = 0; loop < nSize; loop++ ) { + BPy_NMVert *v = + ( BPy_NMVert * ) PyList_GetItem( mf->v, + loop ); + vco[loop] = ( float * ) v->co; + } + + if( nSize == 4 ) + CalcNormFloat4( vco[0], vco[1], vco[2], vco[3], + fNormal ); + else + CalcNormFloat( vco[0], vco[1], vco[2], + fNormal ); + + return Py_BuildValue( "[f,f,f]", fNormal[0], + fNormal[1], fNormal[2] ); + } else // EXPP_check_sequence_consistency failed + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "this face does not contain a series of NMVerts" ); + } + + else if( strcmp( name, "__members__" ) == 0 ) + return Py_BuildValue( "[s,s,s,s,s,s,s,s,s,s,s,s,s]", + "v", "col", "mat", "materialIndex", + "smooth", "image", "mode", "flag", + "transp", "uv", "normal", "sel", "hide"); + return Py_FindMethod( NMFace_methods, ( PyObject * ) self, name ); +} + +static int NMFace_setattr( PyObject * self, char *name, PyObject * v ) +{ + BPy_NMFace *mf = ( BPy_NMFace * ) self; + short ival; + char cval; + + if( strcmp( name, "v" ) == 0 ) { + + if( PySequence_Check( v ) ) { + Py_DECREF( mf->v ); + mf->v = EXPP_incr_ret( v ); + + return 0; + } + } else if( strcmp( name, "col" ) == 0 ) { + + if( PySequence_Check( v ) ) { + Py_DECREF( mf->col ); + mf->col = EXPP_incr_ret( v ); + + return 0; + } + } else if( !strcmp( name, "mat" ) || !strcmp( name, "materialIndex" ) ) { + PyArg_Parse( v, "b", &cval ); + mf->mat_nr = cval; + + return 0; + } else if( strcmp( name, "smooth" ) == 0 ) { + PyArg_Parse( v, "h", &ival ); + if (ival) mf->mf_flag |= ME_SMOOTH; + else mf->mf_flag &= ~ME_SMOOTH; + + return 0; + } else if( strcmp( name, "sel" ) == 0 ) { + PyArg_Parse( v, "h", &ival ); + if (ival) mf->mf_flag |= ME_FACE_SEL; + else mf->mf_flag &= ~ME_FACE_SEL; + + return 0; + } else if( strcmp( name, "hide" ) == 0 ) { + PyArg_Parse( v, "h", &ival ); + if (ival) mf->mf_flag |= ME_HIDE; + else mf->mf_flag &= ~ME_HIDE; + + return 0; + + } else if( strcmp( name, "uv" ) == 0 ) { + + if( PySequence_Check( v ) ) { + Py_DECREF( mf->uv ); + mf->uv = EXPP_incr_ret( v ); + + return 0; + } + } else if( strcmp( name, "flag" ) == 0 ) { + PyArg_Parse( v, "h", &ival ); + mf->flag = ival; + + return 0; + } else if( strcmp( name, "mode" ) == 0 ) { + PyArg_Parse( v, "h", &ival ); + mf->mode = ival; + + return 0; + } else if( strcmp( name, "transp" ) == 0 ) { + PyArg_Parse( v, "b", &cval ); + mf->transp = cval; + + return 0; + } else if( strcmp( name, "image" ) == 0 ) { + PyObject *pyimg; + if( !PyArg_Parse( v, "O!", &Image_Type, &pyimg ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected image object" ); + + if( pyimg == Py_None ) { + mf->image = NULL; + + return 0; + } + + mf->image = ( ( BPy_Image * ) pyimg )->image; + + return 0; + } + + return EXPP_ReturnIntError( PyExc_AttributeError, name ); +} + +static PyObject *NMFace_repr( PyObject * self ) +{ + return PyString_FromString( "[NMFace]" ); +} + +static int NMFace_len( BPy_NMFace * self ) +{ + return PySequence_Length( self->v ); +} + +static PyObject *NMFace_item( BPy_NMFace * self, int i ) +{ + return PySequence_GetItem( self->v, i ); // new ref +} + +static PyObject *NMFace_slice( BPy_NMFace * self, int begin, int end ) +{ + return PyList_GetSlice( self->v, begin, end ); // new ref +} + +static PySequenceMethods NMFace_SeqMethods = { + ( inquiry ) NMFace_len, /* sq_length */ + ( binaryfunc ) 0, /* sq_concat */ + ( intargfunc ) 0, /* sq_repeat */ + ( intargfunc ) NMFace_item, /* sq_item */ + ( intintargfunc ) NMFace_slice, /* sq_slice */ + ( intobjargproc ) 0, /* sq_ass_item */ + ( intintobjargproc ) 0, /* sq_ass_slice */ + 0,0,0, +}; + +PyTypeObject NMFace_Type = { + PyObject_HEAD_INIT( NULL ) 0, /*ob_size */ + "Blender NMFace", /*tp_name */ + sizeof( BPy_NMFace ), /*tp_basicsize */ + 0, /*tp_itemsize */ + /* methods */ + ( destructor ) NMFace_dealloc, /*tp_dealloc */ + ( printfunc ) 0, /*tp_print */ + ( getattrfunc ) NMFace_getattr, /*tp_getattr */ + ( setattrfunc ) NMFace_setattr, /*tp_setattr */ + 0, /*tp_compare */ + ( reprfunc ) NMFace_repr, /*tp_repr */ + 0, /*tp_as_number */ + &NMFace_SeqMethods, /*tp_as_sequence */ + 0, /*tp_as_mapping */ + 0, /*tp_hash */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* up to tp_del to avoid a warning */ +}; + +static BPy_NMVert *newvert( float *co ) +{ + BPy_NMVert *mv = PyObject_NEW( BPy_NMVert, &NMVert_Type ); + + mv->co[0] = co[0]; + mv->co[1] = co[1]; + mv->co[2] = co[2]; + + mv->no[0] = mv->no[1] = mv->no[2] = 0.0; + mv->uvco[0] = mv->uvco[1] = mv->uvco[2] = 0.0; + mv->flag = 0; + + return mv; +} + +static PyObject *M_NMesh_Vert( PyObject * self, PyObject * args ) +{ + float co[3] = { 0.0, 0.0, 0.0 }; + + if( !PyArg_ParseTuple( args, "|fff", &co[0], &co[1], &co[2] ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected three floats (or nothing) as arguments" ); + + return ( PyObject * ) newvert( co ); +} + +static void NMVert_dealloc( PyObject * self ) +{ + PyObject_DEL( self ); +} + +static PyObject *NMVert_getattr( PyObject * self, char *name ) +{ + BPy_NMVert *mv = ( BPy_NMVert * ) self; + + if( !strcmp( name, "co" ) || !strcmp( name, "loc" ) ) + return newVectorObject(mv->co,3,Py_WRAP); + + else if( strcmp( name, "no" ) == 0 ) + return newVectorObject(mv->no,3,Py_WRAP); + else if( strcmp( name, "uvco" ) == 0 ) + return newVectorObject(mv->uvco,3,Py_WRAP); + else if( strcmp( name, "index" ) == 0 ) + return PyInt_FromLong( mv->index ); + else if( strcmp( name, "sel" ) == 0 ) + return PyInt_FromLong( mv->flag & 1 ); + else if( strcmp( name, "__members__" ) == 0 ) + return Py_BuildValue( "[s,s,s,s,s]", "co", "no", "uvco", + "index", "sel" ); + + return EXPP_ReturnPyObjError( PyExc_AttributeError, name ); +} + +static int NMVert_setattr( PyObject * self, char *name, PyObject * v ) +{ + BPy_NMVert *mv = ( BPy_NMVert * ) self; + int i; + + if( strcmp( name, "index" ) == 0 ) { + PyArg_Parse( v, "i", &i ); + mv->index = i; + return 0; + } else if( strcmp( name, "sel" ) == 0 ) { + PyArg_Parse( v, "i", &i ); + mv->flag = i ? 1 : 0; + return 0; + } else if( strcmp( name, "uvco" ) == 0 ) { + + if( !PyArg_ParseTuple( v, "ff|f", + &( mv->uvco[0] ), &( mv->uvco[1] ), + &( mv->uvco[2] ) ) ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "Vector tuple or triple expected" ); + + return 0; + } + + return EXPP_ReturnIntError( PyExc_AttributeError, name ); +} + +static int NMVert_len( BPy_NMVert * self ) +{ + return 3; +} + +static PyObject *NMVert_item( BPy_NMVert * self, int i ) +{ + if( i < 0 || i >= 3 ) + return EXPP_ReturnPyObjError( PyExc_IndexError, + "array index out of range" ); + + return Py_BuildValue( "f", self->co[i] ); +} + +static PyObject *NMVert_slice( BPy_NMVert * self, int begin, int end ) +{ + PyObject *list; + int count; + + if( begin < 0 ) + begin = 0; + if( end > 3 ) + end = 3; + if( begin > end ) + begin = end; + + list = PyList_New( end - begin ); + + for( count = begin; count < end; count++ ) + PyList_SetItem( list, count - begin, + PyFloat_FromDouble( self->co[count] ) ); + + return list; +} + +static int NMVert_ass_item( BPy_NMVert * self, int i, PyObject * ob ) +{ + if( i < 0 || i >= 3 ) + return EXPP_ReturnIntError( PyExc_IndexError, + "array assignment index out of range" ); + + if( !PyNumber_Check( ob ) ) + return EXPP_ReturnIntError( PyExc_IndexError, + "NMVert member must be a number" ); + + self->co[i] = (float)PyFloat_AsDouble( ob ); + + return 0; +} + +static int NMVert_ass_slice( BPy_NMVert * self, int begin, int end, + PyObject * seq ) +{ + int count; + + if( begin < 0 ) + begin = 0; + if( end > 3 ) + end = 3; + if( begin > end ) + begin = end; + + if( !PySequence_Check( seq ) ) + EXPP_ReturnIntError( PyExc_TypeError, + "illegal argument type for built-in operation" ); + + if( PySequence_Length( seq ) != ( end - begin ) ) + EXPP_ReturnIntError( PyExc_TypeError, + "size mismatch in slice assignment" ); + + for( count = begin; count < end; count++ ) { + PyObject *ob = PySequence_GetItem( seq, count ); + + if( !PyArg_Parse( ob, "f", &self->co[count] ) ) { + Py_DECREF( ob ); + return -1; + } + + Py_DECREF( ob ); + } + + return 0; +} + +static PySequenceMethods NMVert_SeqMethods = { + ( inquiry ) NMVert_len, /* sq_length */ + ( binaryfunc ) 0, /* sq_concat */ + ( intargfunc ) 0, /* sq_repeat */ + ( intargfunc ) NMVert_item, /* sq_item */ + ( intintargfunc ) NMVert_slice, /* sq_slice */ + ( intobjargproc ) NMVert_ass_item, /* sq_ass_item */ + ( intintobjargproc ) NMVert_ass_slice, /* sq_ass_slice */ + 0,0,0, +}; + +PyTypeObject NMVert_Type = { + PyObject_HEAD_INIT( NULL ) + 0, /*ob_size */ + "Blender NMVert", /*tp_name */ + sizeof( BPy_NMVert ), /*tp_basicsize */ + 0, /*tp_itemsize */ + /* methods */ + ( destructor ) NMVert_dealloc, /*tp_dealloc */ + ( printfunc ) 0, /*tp_print */ + ( getattrfunc ) NMVert_getattr, /*tp_getattr */ + ( setattrfunc ) NMVert_setattr, /*tp_setattr */ + 0, /*tp_compare */ + ( reprfunc ) 0, /*tp_repr */ + 0, /*tp_as_number */ + &NMVert_SeqMethods, /*tp_as_sequence */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* tp_del */ +}; + + +/***************************** + * NMEdge + *****************************/ + +static BPy_NMEdge *new_NMEdge( BPy_NMVert * v1, BPy_NMVert * v2, char crease, short flag) +{ + BPy_NMEdge *edge=NULL; + + if (!v1 || !v2) return NULL; + if (!BPy_NMVert_Check(v1) || !BPy_NMVert_Check(v2)) return NULL; + + edge = PyObject_NEW( BPy_NMEdge, &NMEdge_Type ); + + edge->v1=EXPP_incr_ret((PyObject*)v1); + edge->v2=EXPP_incr_ret((PyObject*)v2); + edge->flag=flag; + edge->crease=crease; + + return edge; +} + +static void NMEdge_dealloc( PyObject * self ) +{ + BPy_NMEdge *edge=(BPy_NMEdge *)self; + + Py_DECREF(edge->v1); + Py_DECREF(edge->v2); + + PyObject_DEL(self); +} + +static PyObject *NMEdge_getattr( PyObject * self, char *name ) +{ + BPy_NMEdge *edge=(BPy_NMEdge *)self; + + if ( strcmp( name, "v1" ) == 0 ) + return EXPP_incr_ret( edge->v1 ); + else if ( strcmp( name, "v2" ) == 0 ) + return EXPP_incr_ret( edge->v2 ); + else if ( strcmp( name, "flag" ) == 0 ) + return PyInt_FromLong( edge->flag ); + else if ( strcmp( name, "crease" ) == 0 ) + return PyInt_FromLong( edge->crease ); + else if( strcmp( name, "__members__" ) == 0 ) + return Py_BuildValue( "[s,s,s,s]", + "v1", "v2", "flag", "crease" ); + + return EXPP_ReturnPyObjError( PyExc_AttributeError, name ); +} + +static int NMEdge_setattr( PyObject * self, char *name, PyObject * v ) +{ + BPy_NMEdge *edge=(BPy_NMEdge *)self; + + if ( strcmp( name, "flag" ) == 0 ) + { + short flag=0; + if( !PyInt_Check( v ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected int argument" ); + + flag = ( short ) PyInt_AsLong( v ); + + edge->flag = flag; + + return 0; + } + else if ( strcmp( name, "crease" ) == 0 ) + { + char crease=0; + if( !PyInt_Check( v ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected int argument" ); + + crease = ( char ) PyInt_AsLong( v ); + + edge->crease = crease; + + return 0; + } + + return EXPP_ReturnIntError( PyExc_AttributeError, name ); +} + +PyTypeObject NMEdge_Type = { + PyObject_HEAD_INIT( NULL ) + 0, /*ob_size */ + "Blender NMEdge", /*tp_name */ + sizeof( BPy_NMEdge ), /*tp_basicsize */ + 0, /*tp_itemsize */ + /* methods */ + ( destructor ) NMEdge_dealloc, /*tp_dealloc */ + ( printfunc ) 0, /*tp_print */ + ( getattrfunc ) NMEdge_getattr, /*tp_getattr */ + ( setattrfunc ) NMEdge_setattr, /*tp_setattr */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,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 void NMesh_dealloc( PyObject * self ) +{ + BPy_NMesh *me = ( BPy_NMesh * ) self; + + CustomData_free( &me->fdata, me->totfdata ); + + Py_DECREF( me->name ); + Py_DECREF( me->verts ); + Py_DECREF( me->faces ); + Py_DECREF( me->materials ); + Py_DECREF( me->edges ); + + PyObject_DEL( self ); +} + +static PyObject *NMesh_getMaterials( PyObject * self, PyObject * args ) +{ + BPy_NMesh *nm = ( BPy_NMesh * ) self; + PyObject *list = NULL; + Mesh *me = nm->mesh; + int all = -1; + + if( !PyArg_ParseTuple( args, "|i", &all ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected nothing or an int (bool) as argument" ); + + if( all >= 0 ) { + if (!me) + return EXPP_ReturnPyObjError(PyExc_TypeError, + "meshes obtained with GetRawFromObject don't support this option"); + + list = EXPP_PyList_fromMaterialList( me->mat, me->totcol, + all ); + Py_DECREF( nm->materials ); /* update nmesh.materials attribute */ + nm->materials = EXPP_incr_ret( list ); + } else + list = EXPP_incr_ret( nm->materials ); + + return list; +} + +static PyObject *NMesh_setMaterials( PyObject * self, PyObject * args ) +{ + BPy_NMesh *me = ( BPy_NMesh * ) self; + PyObject *pymats = NULL; + + if( !PyArg_ParseTuple( args, "O!", &PyList_Type, &pymats ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a list of materials (None's also accepted) as argument" ); + + if( !EXPP_check_sequence_consistency( pymats, &Material_Type ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "list should only contain materials (None's also accepted)" ); + + if( PyList_Size( pymats ) > 16 ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "list can't have more than 16 materials" ); + + Py_DECREF( me->materials ); + me->materials = EXPP_incr_ret( pymats ); + + Py_RETURN_NONE; +} + +static PyObject *NMesh_addMaterial( PyObject * self, PyObject * args ) +{ + BPy_NMesh *me = ( BPy_NMesh * ) self; + BPy_Material *pymat; + Material *mat; + PyObject *iter; + int i, len = 0; + + if( !PyArg_ParseTuple( args, "O!", &Material_Type, &pymat ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected Blender Material PyObject" ); + + mat = pymat->material; + len = PyList_Size( me->materials ); + + if( len >= 16 ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "object data material lists can't have more than 16 materials" ); + + for( i = 0; i < len; i++ ) { + iter = PyList_GetItem( me->materials, i ); + if( mat == Material_FromPyObject( iter ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "material already in the list" ); + } + + PyList_Append( me->materials, ( PyObject * ) pymat ); + + Py_RETURN_NONE; +} + +static PyObject *NMesh_getKey( BPy_NMesh * self ) +{ + PyObject *keyobj; + + if( self->mesh->key ) + keyobj = Key_CreatePyObject(self->mesh->key); + else + keyobj = EXPP_incr_ret(Py_None); + + return keyobj; +} + +static PyObject *NMesh_removeAllKeys( PyObject * self, PyObject * args ) +{ + BPy_NMesh *nm = ( BPy_NMesh * ) self; + Mesh *me = nm->mesh; + + if( !PyArg_ParseTuple( args, "" ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "this function expects no arguments" ); + + if( !me || !me->key ) + return EXPP_incr_ret_False(); + + me->key->id.us--; + me->key = 0; + + return EXPP_incr_ret_True(); +} + +static PyObject *NMesh_insertKey( PyObject * self, PyObject * args ) +{ + int fra = -1, oldfra = -1; + char *type = NULL; + short typenum; + BPy_NMesh *nm = ( BPy_NMesh * ) self; + Mesh *mesh = nm->mesh; + + if( !PyArg_ParseTuple( args, "|is", &fra, &type ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected nothing or an int and optionally a string as arguments" ); + + if( !type || !strcmp( type, "relative" ) ) + typenum = 1; + else if( !strcmp( type, "absolute" ) ) + typenum = 2; + else + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "if given, type should be 'relative' or 'absolute'" ); + + if( fra > 0 ) { + fra = EXPP_ClampInt( fra, 1, NMESH_FRAME_MAX ); + oldfra = G.scene->r.cfra; + G.scene->r.cfra = (int)fra; + } + + if( !mesh ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "update this NMesh first with its .update() method" ); + + insert_meshkey( mesh, typenum ); + allspace(REMAKEIPO, 0); + + if( fra > 0 ) + G.scene->r.cfra = (int)oldfra; + + Py_RETURN_NONE; +} + +static PyObject *NMesh_getSelectedFaces( PyObject * self, PyObject * args ) +{ + BPy_NMesh *nm = ( BPy_NMesh * ) self; + Mesh *me = nm->mesh; + int i, totfaces, flag = 0; + PyObject *l, *pyval; + + if( !PyArg_ParseTuple( args, "|i", &flag ) ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "expected int argument (or nothing)" ); + + l = PyList_New( 0 ); + if( me == NULL || me->mface == NULL) + return l; + + /* make sure not to write more faces then we have */ + totfaces= MIN2(me->totface, PySequence_Length(nm->faces)); + + if( flag ) { + for( i = 0; i < totfaces; i++ ) { + if( me->mface[i].flag & ME_FACE_SEL ) { + pyval = PyInt_FromLong( i ); + PyList_Append( l, pyval ); + Py_DECREF(pyval); + } + } + } else { + for( i = 0; i < totfaces; i++ ) { + if( me->mface[i].flag & ME_FACE_SEL ) + PyList_Append( l, PyList_GetItem( nm->faces, i ) ); + } + } + return l; +} + +static PyObject *NMesh_getActiveFace( PyObject * self ) +{ + if( ( ( BPy_NMesh * ) self )->sel_face < 0 ) + Py_RETURN_NONE; + + return Py_BuildValue( "i", ( ( BPy_NMesh * ) self )->sel_face ); +} + +static PyObject *NMesh_hasVertexUV( PyObject * self, PyObject * args ) +{ + BPy_NMesh *me = ( BPy_NMesh * ) self; + int flag = -1; + + if( !PyArg_ParseTuple( args, "|i", &flag ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument (or nothing)" ); + + switch ( flag ) { + case 0: + me->flags &= ~NMESH_HASVERTUV; + break; + case 1: + me->flags |= NMESH_HASVERTUV; + break; + default: + break; + } + + if( me->flags & NMESH_HASVERTUV ) + return EXPP_incr_ret_True(); + else + return EXPP_incr_ret_False(); +} + +static PyObject *NMesh_hasFaceUV( PyObject * self, PyObject * args ) +{ + BPy_NMesh *me = ( BPy_NMesh * ) self; + int flag = -1; + + if( !PyArg_ParseTuple( args, "|i", &flag ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument (or nothing)" ); + + switch ( flag ) { + case 0: + me->flags &= ~NMESH_HASFACEUV; + break; + case 1: + me->flags |= NMESH_HASFACEUV; + break; + default: + break; + } + + if( me->flags & NMESH_HASFACEUV ) + return EXPP_incr_ret_True(); + else + return EXPP_incr_ret_False(); +} + +static PyObject *NMesh_hasVertexColours( PyObject * self, PyObject * args ) +{ + BPy_NMesh *me = ( BPy_NMesh * ) self; + int flag = -1; + + if( !PyArg_ParseTuple( args, "|i", &flag ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument (or nothing)" ); + + switch ( flag ) { + case 0: + me->flags &= ~NMESH_HASMCOL; + break; + case 1: + me->flags |= NMESH_HASMCOL; + break; + default: + break; + } + + if( me->flags & NMESH_HASMCOL ) + return EXPP_incr_ret_True(); + else + return EXPP_incr_ret_False(); +} + +static PyObject *NMesh_update( PyObject *self, PyObject *a, PyObject *kwd ) +{ + BPy_NMesh *nmesh = ( BPy_NMesh * ) self; + Mesh *mesh = nmesh->mesh; + int recalc_normals = 0, store_edges = 0, vertex_shade = 0; + static char *kwlist[] = {"recalc_normals", "store_edges", + "vertex_shade", NULL}; + int needs_redraw = 1; + int old_totvert = 0; + + if (!PyArg_ParseTupleAndKeywords(a, kwd, "|iii", kwlist, &recalc_normals, + &store_edges, &vertex_shade ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected nothing or one to three bool(s) (0 or 1) as argument" ); + + if( check_NMeshLists( nmesh ) ) + return NULL; + + if( mesh ) { + old_totvert = mesh->totvert; + unlink_existingMeshData( mesh ); + if( !convert_NMeshToMesh( mesh, nmesh ) ) + return NULL; + if (mesh->dvert) check_dverts(mesh, old_totvert); + } else { + mesh = Mesh_fromNMesh( nmesh ); + /* if mesh is NULL, there was an error */ + if( !mesh ) + return NULL; + nmesh->mesh = mesh; + } + + if( recalc_normals ) + mesh_calc_normals(mesh->mvert, mesh->totvert, mesh->mface, mesh->totface, NULL); + + mesh_update( mesh, nmesh->object ); + + nmesh_updateMaterials( nmesh ); + + if( nmesh->name && nmesh->name != Py_None ) + new_id( &( G.main->mesh ), &mesh->id, + PyString_AsString( nmesh->name ) ); + + if (vertex_shade) { + Base *base = FIRSTBASE; + + if (!nmesh->object) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "link this mesh to an object first with ob.link(mesh)" ); + + if (G.obedit) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "can't shade vertices while in edit mode" ); + + while (base) { + if (base->object == nmesh->object) { + base->flag |= SELECT; + nmesh->object->flag = (short)base->flag; + set_active_base (base); + needs_redraw = 0; /* already done in make_vertexcol */ + break; + } + base = base->next; + } + + /* recalculate the derived mesh before trying to use it */ + makeDerivedMesh(nmesh->object, CD_MASK_BAREMESH); + make_vertexcol(1); + + countall(); + } + + if( !during_script( ) && needs_redraw) + EXPP_allqueue( REDRAWVIEW3D, 0 ); + + return PyInt_FromLong( 1 ); +} + +/** Implementation of the python method getVertexInfluence for an NMesh object. + * This method returns a list of pairs (string,float) with bone names and + * influences that this vertex receives. + * @author Jordi Rovira i Bonet + */ + +static PyObject *NMesh_getVertexInfluences( PyObject * self, PyObject * args ) +{ + int index; + PyObject *influence_list = NULL; + Object *object = ( ( BPy_NMesh * ) self )->object; + Mesh *me = ( ( BPy_NMesh * ) self )->mesh; + + /* Get a reference to the mesh object wrapped in here. */ + if( !me ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "unlinked nmesh: call its .update() method first" ); + + if( !object ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This mesh must be linked to an object" ); + + /* Parse the parameters: only on integer (vertex index) */ + if( !PyArg_ParseTuple( args, "i", &index ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument (index of the vertex)" ); + + /* check for valid index */ + if( index < 0 || index >= me->totvert ) + return EXPP_ReturnPyObjError( PyExc_IndexError, + "vertex index out of range" ); + + influence_list = PyList_New( 0 ); + + /* Proceed only if we have vertex deformation information */ + if( me->dvert ) { + int i; + MDeformWeight *sweight = NULL; + + /* Number of bones influencing the vertex */ + int totinfluences = me->dvert[index].totweight; + + /* Get the reference of the first weight structure */ + sweight = me->dvert[index].dw; + + /* Build the list only with weights and names of the influent bones */ + for( i = 0; i < totinfluences; i++, sweight++ ) { + bDeformGroup *defgroup = (bDeformGroup *) BLI_findlink( &object->defbase, + sweight->def_nr ); + if( defgroup ) + PyList_Append( influence_list, Py_BuildValue( "[sf]", + defgroup->name, sweight->weight ) ); + } + } + + return influence_list; +} + +Mesh *Mesh_fromNMesh( BPy_NMesh * nmesh ) +{ + Mesh *mesh = NULL; + + mesh = add_mesh( "Mesh" ); + + if( !mesh ) { + PyErr_SetString( PyExc_RuntimeError, + "FATAL: could not create mesh object" ); + return NULL; + } + + mesh->id.us = 0; /* no user yet */ + G.totmesh++; + + if( !convert_NMeshToMesh( mesh, nmesh ) ) + return NULL; + + return mesh; +} + +static PyObject *NMesh_getMaxSmoothAngle( BPy_NMesh * self ) +{ + return PyInt_FromLong( self->smoothresh ); +} + +static PyObject *NMesh_setMaxSmoothAngle( PyObject * self, PyObject * args ) +{ + short value = 0; + BPy_NMesh *nmesh = ( BPy_NMesh * ) self; + + if( !PyArg_ParseTuple( args, "h", &value ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected an int in [1, 80] as argument" ); + + nmesh->smoothresh = + ( short ) EXPP_ClampInt( value, NMESH_SMOOTHRESH_MIN, + NMESH_SMOOTHRESH_MAX ); + + Py_RETURN_NONE; +} + +static PyObject *NMesh_getSubDivLevels( BPy_NMesh * self ) +{ + return Py_BuildValue( "[h,h]", self->subdiv[0], self->subdiv[1] ); +} + +static PyObject *NMesh_setSubDivLevels( PyObject * self, PyObject * args ) +{ + short display = 0, render = 0; + BPy_NMesh *nmesh = ( BPy_NMesh * ) self; + + if( !PyArg_ParseTuple( args, "(hh)", &display, &render ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected a sequence [int, int] as argument" ); + + nmesh->subdiv[0] = + ( short ) EXPP_ClampInt( display, NMESH_SUBDIV_MIN, + NMESH_SUBDIV_MAX ); + + nmesh->subdiv[1] = + ( short ) EXPP_ClampInt( render, NMESH_SUBDIV_MIN, + NMESH_SUBDIV_MAX ); + + Py_RETURN_NONE; +} + +static PyObject *NMesh_getMode( BPy_NMesh * self ) +{ + return PyInt_FromLong( self->mode ); +} + +static PyObject *NMesh_setMode( PyObject * self, PyObject * args ) +{ + BPy_NMesh *nmesh = ( BPy_NMesh * ) self; + PyObject *arg1 = NULL; + char *m[5] = { NULL, NULL, NULL, NULL, NULL }; + short i, mode = 0; + + if( !PyArg_ParseTuple ( args, "|Ossss", &arg1, &m[1], &m[2], &m[3], &m[4] ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected an int or from none to 5 strings as argument(s)" ); + + if (arg1) { + if (PyInt_Check(arg1)) { + mode = (short)PyInt_AsLong(arg1); + } + else if (PyString_Check(arg1)) { + m[0] = PyString_AsString(arg1); + for( i = 0; i < 5; i++ ) { + if( !m[i] ) break; + else if( strcmp( m[i], "NoVNormalsFlip" ) == 0 ) + mode |= ME_NOPUNOFLIP; + else if( strcmp( m[i], "TwoSided" ) == 0 ) + mode |= ME_TWOSIDED; + else if( strcmp( m[i], "AutoSmooth" ) == 0 ) + mode |= ME_AUTOSMOOTH; + else if( m[i][0] == '\0' ) + mode = 0; + else + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "unknown NMesh mode" ); + } + } + else return EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected an int or from none to 5 strings as argument(s)" ); + } + + nmesh->mode = mode; + + Py_RETURN_NONE; +} + +/* METH_VARARGS: function(PyObject *self, PyObject *args) */ +#undef MethodDef +#define MethodDef(func) {#func, NMesh_##func, METH_VARARGS, NMesh_##func##_doc} + +static struct PyMethodDef NMesh_methods[] = { + MethodDef( addEdge ), + MethodDef( findEdge ), + MethodDef( removeEdge ), + MethodDef( addFace ), + MethodDef( removeFace ), + MethodDef( addVertGroup ), + MethodDef( removeVertGroup ), + MethodDef( assignVertsToGroup ), + MethodDef( removeVertsFromGroup ), + MethodDef( getVertsFromGroup ), + MethodDef( renameVertGroup ), + MethodDef( hasVertexColours ), + MethodDef( hasFaceUV ), + MethodDef( hasVertexUV ), + MethodDef( getSelectedFaces ), + MethodDef( getVertexInfluences ), + MethodDef( getMaterials ), + MethodDef( setMaterials ), + MethodDef( addMaterial ), + MethodDef( insertKey ), + MethodDef( removeAllKeys ), + MethodDef( setMode ), + MethodDef( setMaxSmoothAngle ), + MethodDef( setSubDivLevels ), + MethodDef( transform ), + +/* METH_NOARGS: function(PyObject *self) */ +#undef MethodDef +#define MethodDef(func) {#func, (PyCFunction)NMesh_##func, METH_NOARGS,\ + NMesh_##func##_doc} + + MethodDef( printDebug ), + MethodDef( getVertGroupNames ), + MethodDef( getActiveFace ), + MethodDef( getKey ), + MethodDef( getMode ), + MethodDef( getMaxSmoothAngle ), + MethodDef( getSubDivLevels ), + +/* METH_VARARGS | METH_KEYWORDS: + * function(PyObject *self, PyObject *args, PyObject *keywords) */ +#undef MethodDef +#define MethodDef(func) {#func, (PyCFunction)NMesh_##func,\ + METH_VARARGS | METH_KEYWORDS, NMesh_##func##_doc} + + MethodDef( update ), + {NULL, NULL, 0, NULL} +}; + +static PyObject *NMesh_getattr( PyObject * self, char *name ) +{ + BPy_NMesh *me = ( BPy_NMesh * ) self; + + if( strcmp( name, "name" ) == 0 ) + return EXPP_incr_ret( me->name ); + + else if ( strcmp( name, "properties" ) == 0 ) + return BPy_Wrap_IDProperty( (ID*)me->mesh, IDP_GetProperties((ID*)me->mesh, 1), NULL ); + + else if( strcmp( name, "mode" ) == 0 ) + return PyInt_FromLong( me->mode ); + + else if( strcmp( name, "block_type" ) == 0 ) /* for compatibility */ + return PyString_FromString( "NMesh" ); + + else if( strcmp( name, "materials" ) == 0 ) + return EXPP_incr_ret( me->materials ); + + else if( strcmp( name, "verts" ) == 0 ) + return EXPP_incr_ret( me->verts ); + + else if( strcmp( name, "maxSmoothAngle" ) == 0 ) + return PyInt_FromLong( me->smoothresh ); + + else if( strcmp( name, "subDivLevels" ) == 0 ) + return Py_BuildValue( "[h,h]", me->subdiv[0], me->subdiv[1] ); + + else if( strcmp( name, "users" ) == 0 ) { + if( me->mesh ) { + return PyInt_FromLong( me->mesh->id.us ); + } else { /* it's a free mesh: */ + return Py_BuildValue( "i", 0 ); + } + } + else if (strcmp( name, "key") == 0) + return NMesh_getKey((BPy_NMesh*)self); + + else if( strcmp( name, "faces" ) == 0 ) + return EXPP_incr_ret( me->faces ); + + else if( strcmp( name, "edges" ) == 0 ) + { + return EXPP_incr_ret( me->edges ); + } + else if( strcmp( name, "__members__" ) == 0 ) + return Py_BuildValue( "[s,s,s,s,s,s,s,s,s,s,s]", + "name", "materials", "verts", "users", + "faces", "maxSmoothAngle", + "subdivLevels", "edges", "key" ); + + return Py_FindMethod( NMesh_methods, ( PyObject * ) self, name ); +} + +static int NMesh_setattr( PyObject * self, char *name, PyObject * v ) +{ + BPy_NMesh *me = ( BPy_NMesh * ) self; + + if( !strcmp( name, "name" ) ) { + + if( !PyString_Check( v ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected string argument" ); + + Py_DECREF( me->name ); + me->name = EXPP_incr_ret( v ); + } + + else if( !strcmp( name, "mode" ) ) { + short mode; + + if( !PyInt_Check( v ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected int argument" ); + + mode = ( short ) PyInt_AsLong( v ); + if( mode >= 0 ) + me->mode = mode; + else + return EXPP_ReturnIntError( PyExc_ValueError, + "expected positive int argument" ); + } + + else if( !strcmp( name, "verts" ) || !strcmp( name, "faces" ) || + !strcmp( name, "materials" ) ) { + + if( PySequence_Check( v ) ) { + + if( strcmp( name, "materials" ) == 0 ) { + Py_DECREF( me->materials ); + me->materials = EXPP_incr_ret( v ); + } else if( strcmp( name, "verts" ) == 0 ) { + Py_DECREF( me->verts ); + me->verts = EXPP_incr_ret( v ); + } else { + Py_DECREF( me->faces ); + me->faces = EXPP_incr_ret( v ); + } + } + + else + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a list" ); + } + + else if( !strcmp( name, "maxSmoothAngle" ) ) { + short smoothresh = 0; + + if( !PyInt_Check( v ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected int argument" ); + + smoothresh = ( short ) PyInt_AsLong( v ); + + me->smoothresh = + (short)EXPP_ClampInt( smoothresh, NMESH_SMOOTHRESH_MIN, + NMESH_SMOOTHRESH_MAX ); + } + + else if( !strcmp( name, "subDivLevels" ) ) { + int subdiv[2] = { 0, 0 }; + int i; + PyObject *tmp; + + if( !PySequence_Check( v ) || ( PySequence_Length( v ) != 2 ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a list [int, int] as argument" ); + + for( i = 0; i < 2; i++ ) { + tmp = PySequence_GetItem( v, i ); + if( tmp ) { + if( !PyInt_Check( tmp ) ) { + Py_DECREF( tmp ); + return EXPP_ReturnIntError + ( PyExc_TypeError, + "expected a list [int, int] as argument" ); + } + + subdiv[i] = PyInt_AsLong( tmp ); + me->subdiv[i] = + ( short ) EXPP_ClampInt( subdiv[i], + NMESH_SUBDIV_MIN, + NMESH_SUBDIV_MAX ); + Py_DECREF( tmp ); + } else + return EXPP_ReturnIntError( PyExc_RuntimeError, + "couldn't retrieve subdiv values from list" ); + } + } + else if( strcmp( name, "edges" ) == 0 ) + { + if (PySequence_Check(v)) + { + Py_DECREF(me->edges); + me->edges = EXPP_incr_ret( v ); + } + } + else + return EXPP_ReturnIntError( PyExc_AttributeError, name ); + + return 0; +} + +PyTypeObject NMesh_Type = { + PyObject_HEAD_INIT( NULL ) 0, /*ob_size */ + "Blender NMesh", /*tp_name */ + sizeof( BPy_NMesh ), /*tp_basicsize */ + 0, /*tp_itemsize */ + /* methods */ + ( destructor ) NMesh_dealloc, /*tp_dealloc */ + ( printfunc ) 0, /*tp_print */ + ( getattrfunc ) NMesh_getattr, /*tp_getattr */ + ( setattrfunc ) NMesh_setattr, /*tp_setattr */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,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 BPy_NMFace *nmface_from_data( BPy_NMesh * mesh, int vidxs[4], + char mat_nr, char flag, MTFace * tface, MCol * col, int orig_index ) +{ + BPy_NMFace *newf = PyObject_NEW( BPy_NMFace, &NMFace_Type ); + int i, len; + + if( vidxs[3] ) + len = 4; + else + len = 3; + + newf->v = PyList_New( len ); + + for( i = 0; i < len; i++ ) + PyList_SetItem( newf->v, i, + EXPP_incr_ret( PyList_GetItem + ( mesh->verts, vidxs[i] ) ) ); + + if( tface ) { + newf->uv = PyList_New( len ); // per-face UV coordinates + + for( i = 0; i < len; i++ ) { + PyList_SetItem( newf->uv, i, + Py_BuildValue( "(ff)", tface->uv[i][0], + tface->uv[i][1] ) ); + } + + if( tface->tpage ) /* pointer to image per face: */ + newf->image = ( Image * ) tface->tpage; + else + newf->image = NULL; + + newf->mode = tface->mode; /* draw mode */ + newf->flag = tface->flag; /* select flag */ + newf->transp = tface->transp; /* transparency flag */ + } else { + newf->mode = TF_DYNAMIC; /* just to initialize it to something meaninful, */ + /* since without tfaces there are no tface->mode's, obviously. */ + newf->image = NULL; + newf->uv = PyList_New( 0 ); + } + + newf->mat_nr = mat_nr; + newf->mf_flag = flag; /* MFace flag */ + newf->orig_index = orig_index; + + if( col ) { + newf->col = PyList_New( 4 ); + for( i = 0; i < 4; i++, col++ ) { + PyList_SetItem( newf->col, i, + ( PyObject * ) newcol( col->b, col->g, + col->r, + col->a ) ); + } + } else + newf->col = PyList_New( 0 ); + + return newf; +} + +static BPy_NMEdge *nmedge_from_index( BPy_NMesh * mesh, int v0idx, int v1idx) +{ + BPy_NMVert *v1=(BPy_NMVert *)PyList_GetItem( mesh->verts, v0idx); + BPy_NMVert *v2=(BPy_NMVert *)PyList_GetItem( mesh->verts, v1idx); + return new_NMEdge(v1, v2, (char)0.0, 0); +} + +static BPy_NMEdge *nmedge_from_data( BPy_NMesh * mesh, MEdge *edge ) +{ + BPy_NMVert *v1=(BPy_NMVert *)PyList_GetItem( mesh->verts, edge->v1 ); + BPy_NMVert *v2=(BPy_NMVert *)PyList_GetItem( mesh->verts, edge->v2 ); + return new_NMEdge(v1, v2, edge->crease, edge->flag); +} + +static BPy_NMVert *nmvert_from_data( MVert * vert, MSticky * st, float *co, + int idx, char flag ) +{ + BPy_NMVert *mv = PyObject_NEW( BPy_NMVert, &NMVert_Type ); + + mv->co[0] = co[0]; + mv->co[1] = co[1]; + mv->co[2] = co[2]; + + mv->no[0] = (float)(vert->no[0] / 32767.0); + mv->no[1] = (float)(vert->no[1] / 32767.0); + mv->no[2] = (float)(vert->no[2] / 32767.0); + + if( st ) { + mv->uvco[0] = st->co[0]; + mv->uvco[1] = st->co[1]; + mv->uvco[2] = 0.0; + + } else + mv->uvco[0] = mv->uvco[1] = mv->uvco[2] = 0.0; + + mv->index = idx; + mv->flag = flag & 1; + + return mv; +} + +static int get_active_faceindex( Mesh * me ) +{ + if( me == NULL ) + return -1; + + if (me->act_face != -1 && me->act_face < me->totface) + return me->act_face; + return -1; +} + +static BPy_NMVert *nmvert_from_float(float *co, float *no, int idx) { + BPy_NMVert *mv; + + mv = PyObject_NEW( BPy_NMVert, &NMVert_Type ); + + mv->index = idx; + + mv->co[0] = co[0]; + mv->co[1] = co[1]; + mv->co[2] = co[2]; + + mv->no[0] = no[0]; + mv->no[1] = no[1]; + mv->no[2] = no[2]; + + mv->uvco[0] = mv->uvco[1] = mv->uvco[2] = 0.0; + + mv->flag = 0; + + return mv; +} + +static BPy_NMFace *nmface_from_index( BPy_NMesh * mesh, int vidxs[4], char mat_nr ) +{ + BPy_NMFace *newf = PyObject_NEW( BPy_NMFace, &NMFace_Type ); + int i, len; + + if( vidxs[3] ) + len = 4; + else if( vidxs[2] ) + len = 3; + else + len = 2; + + newf->v = PyList_New( len ); + + for( i = 0; i < len; i++ ) + PyList_SetItem( newf->v, i, + EXPP_incr_ret( PyList_GetItem + ( mesh->verts, vidxs[i] ) ) ); + + newf->mode = TF_DYNAMIC; /* just to initialize it to something meaninful, */ + /* since without tfaces there are no tface->mode's, obviously. */ + newf->image = NULL; + newf->uv = PyList_New( 0 ); + + newf->mat_nr = mat_nr; + newf->mf_flag = 0; + newf->orig_index = -1; + + newf->col = PyList_New( 0 ); + + return newf; +} + +/* RATHER EVIL FUNCTION BORROWED FROM fix_faceindices IN editmesh.c */ +static void correctFaceIndex(int vidx[4]) +{ + if (vidx[3]) { + if (vidx[1] == 0) { + vidx[1] = vidx[2]; + vidx[2] = vidx[3]; + vidx[3] = vidx[0]; + vidx[0] = 0; + } + if (vidx[2] == 0) { + int t = vidx[1]; + vidx[2] = vidx[0]; + vidx[1] = vidx[3]; + vidx[3] = t; + vidx[0] = 0; + } + if (vidx[3] == 0) { + vidx[3] = vidx[2]; + vidx[2] = vidx[1]; + vidx[1] = vidx[0]; + vidx[0] = 0; + } + } + else if (vidx[1] == 0) { + vidx[1] = vidx[2]; + vidx[2] = vidx[0]; + vidx[0] = 0; + } + else if (vidx[2] == 0) { + vidx[2] = vidx[1]; + vidx[1] = vidx[0]; + vidx[0] = 0; + } +} + +/* + CREATES A NMESH FROM DISPLIST DATA. INSPIRED BY THE FUNCTIONS CALLED WHEN + CONVERTING OBJECTS TO MESH. + */ +static PyObject *new_NMesh_displist(ListBase *lb, Object *ob) +{ + BPy_NMesh *me; + DispList *dl; + float *data, *ndata; + float normal[3] = {1, 0, 0}; + int vidx[4]; + int parts, p1, p2, p3, p4, a, b, one_normal=0, ioffset=0; + int *index; + + /* Note: This routine does not create new edges for the faces + * it adds... should be fixed for consistency. + */ + + if (ob->type == OB_CURVE || ob->type == OB_FONT) + one_normal = 1; + + me = PyObject_NEW( BPy_NMesh, &NMesh_Type ); + me->name = EXPP_incr_ret( Py_None ); + me->flags = 0; + me->mode = ME_TWOSIDED; /* default for new meshes */ + me->subdiv[0] = NMESH_SUBDIV; + me->subdiv[1] = NMESH_SUBDIV; + me->smoothresh = NMESH_SMOOTHRESH; + me->edges = PyList_New( 0 ); + + me->object = ob; + me->materials = EXPP_PyList_fromMaterialList( ob->mat, ob->totcol, 0 ); + + me->verts = PyList_New( 0 ); + me->faces = PyList_New( 0 ); + + memset(&me->fdata, 0, sizeof(me->fdata)); + me->totfdata = 0; + + dl= lb->first; + while(dl) { + parts= dl->parts; + index= dl->index; + data= dl->verts; + ndata= dl->nors; + + switch(dl->type) { + case DL_SEGM: + for(a=0; aparts*dl->nr; a++, data+=3) { + PyList_Append(me->verts, ( PyObject * ) nmvert_from_float(data, normal, a)); + } + + vidx[2] = vidx[3] = 0; + + for(a=0; aparts; a++) { + for(b=1; bnr; b++) { + int v0 = ioffset + a * dl->nr + b-1; + int v1 = ioffset + a * dl->nr + b; + PyList_Append(me->edges, ( PyObject * ) nmedge_from_index(me, v0, v1)); + } + } + ioffset += dl->parts * dl->nr; + break; + case DL_POLY: + for(a=0; aparts*dl->nr; a++, data+=3) { + PyList_Append(me->verts, ( PyObject * ) nmvert_from_float(data, normal, a)); + } + + vidx[2] = vidx[3] = 0; + + for(a=0; aparts; a++) { + for(b=0; bnr; b++) { + int v1, v0 = ioffset + a * dl->nr + b; + if(b==dl->nr-1) v1 = ioffset + a * dl->nr; + else v1= ioffset + a * dl->nr + b+1; + PyList_Append(me->edges, ( PyObject * ) nmedge_from_index(me, v0, v1)); + } + } + ioffset += dl->parts * dl->nr; + break; + case DL_SURF: + for(a=0; aparts*dl->nr; a++, data+=3, ndata+=3) { + PyList_Append(me->verts, ( PyObject * ) nmvert_from_float(data, ndata, a)); + } + + for(a=0; aparts; a++) { + + DL_SURFINDEX(dl->flag & DL_CYCL_U, dl->flag & DL_CYCL_V, dl->nr, dl->parts); + + + for(; bnr; b++) { + vidx[0] = p2 + ioffset; + vidx[1] = p1 + ioffset; + vidx[2] = p3 + ioffset; + vidx[3] = p4 + ioffset; + correctFaceIndex(vidx); + + PyList_Append(me->faces, ( PyObject * ) nmface_from_index(me, vidx, (char)dl->col)); + + p2 = p1; + p4 = p3; + p1++; + p3++; + } + } + ioffset += dl->parts * dl->nr; + break; + + case DL_INDEX3: + if (one_normal) + for(a=0; anr; a++, data+=3) + PyList_Append(me->verts, ( PyObject * ) nmvert_from_float(data, ndata, a)); + else + for(a=0; anr; a++, data+=3, ndata+=3) + PyList_Append(me->verts, ( PyObject * ) nmvert_from_float(data, ndata, a)); + + while(parts--) { + vidx[0] = index[0] + ioffset; + vidx[1] = index[1] + ioffset; + vidx[2] = index[2] + ioffset; + vidx[3] = 0; + correctFaceIndex(vidx); + + PyList_Append(me->faces, ( PyObject * ) nmface_from_index(me, vidx, (char)dl->col)); + index+= 3; + } + ioffset += dl->nr; + + break; + + case DL_INDEX4: + for(a=0; anr; a++, data+=3, ndata+=3) { + PyList_Append(me->verts, ( PyObject * ) nmvert_from_float(data, ndata, a)); + } + + while(parts--) { + vidx[0] = index[0] + ioffset; + vidx[1] = index[1] + ioffset; + vidx[2] = index[2] + ioffset; + vidx[3] = index[3] + ioffset; + correctFaceIndex(vidx); + + PyList_Append(me->faces, ( PyObject * ) nmface_from_index(me, vidx, (char)dl->col)); + index+= 4; + } + ioffset += dl->nr; + break; + } + dl= dl->next; + } + + return ( PyObject * ) me; +} + +static PyObject *new_NMesh_internal( Mesh * oldmesh, + DerivedMesh *dm ) +{ + BPy_NMesh *me = PyObject_NEW( BPy_NMesh, &NMesh_Type ); + me->flags = 0; + me->mode = ME_TWOSIDED; /* default for new meshes */ + me->subdiv[0] = NMESH_SUBDIV; + me->subdiv[1] = NMESH_SUBDIV; + me->smoothresh = NMESH_SMOOTHRESH; + + me->object = NULL; /* not linked to any object yet */ + + if( !oldmesh ) { + me->name = EXPP_incr_ret( Py_None ); + me->materials = PyList_New( 0 ); + me->verts = PyList_New( 0 ); + me->edges = PyList_New( 0 ); + me->faces = PyList_New( 0 ); + me->mesh = 0; + memset(&me->fdata, 0, sizeof(me->fdata)); + me->totfdata = 0; + } else { + MVert *mverts; + MSticky *msticky; + MFace *mfaces; + MTFace *tfaces; + MCol *mcols; + MEdge *medges; + CustomData *fdata; + int i, totvert, totface, totedge; + + me->name = PyString_FromString( oldmesh->id.name + 2 ); + me->mesh = oldmesh; + me->mode = oldmesh->flag; /* yes, we save the mesh flags in nmesh->mode */ + me->subdiv[0] = oldmesh->subdiv; + me->subdiv[1] = oldmesh->subdivr; + me->smoothresh = oldmesh->smoothresh; + + me->sel_face = get_active_faceindex( oldmesh ); + + if( dm ) { + msticky = NULL; + mverts = dm->getVertArray(dm); + mfaces = dm->getFaceArray(dm); + tfaces = dm->getFaceDataArray(dm, CD_MTFACE); + mcols = dm->getFaceDataArray(dm, CD_MCOL); + medges = dm->getEdgeArray(dm); + fdata = &dm->faceData; + + totvert = dm->getNumVerts(dm); + totedge = dm->getNumEdges(dm); + totface = dm->getNumFaces(dm);; + } else { + msticky = oldmesh->msticky; + mverts = oldmesh->mvert; + mfaces = oldmesh->mface; + tfaces = oldmesh->mtface; + mcols = oldmesh->mcol; + medges = oldmesh->medge; + fdata = &oldmesh->fdata; + + totvert = oldmesh->totvert; + totface = oldmesh->totface; + totedge = oldmesh->totedge; + } + + /* copy non active mcol and mtface layers, these can't be edited + but will be preserved */ + CustomData_copy( fdata, &me->fdata, CD_MASK_MCOL|CD_MASK_MTFACE, + CD_DUPLICATE, totface ); + me->totfdata = totface; + + if( msticky ) + me->flags |= NMESH_HASVERTUV; + if( tfaces ) + me->flags |= NMESH_HASFACEUV; + if( mcols ) + me->flags |= NMESH_HASMCOL; + + me->verts = PyList_New( totvert ); + + for( i = 0; i < totvert; i++ ) { + MVert *oldmv = &mverts[i]; + MSticky *oldst = msticky ? &msticky[i] : NULL; + + PyList_SetItem( me->verts, i, + ( PyObject * ) nmvert_from_data( oldmv, + oldst, + oldmv->co, + i, + oldmv->flag ) ); + } + + me->faces = PyList_New( totface ); + for( i = 0; i < totface; i++ ) { + MTFace *oldtf = tfaces ? &tfaces[i] : NULL; + MCol *oldmc = mcols ? &mcols[i * 4] : NULL; + MFace *oldmf = &mfaces[i]; + int vidxs[4]; + vidxs[0] = oldmf->v1; + vidxs[1] = oldmf->v2; + vidxs[2] = oldmf->v3; + vidxs[3] = oldmf->v4; + + PyList_SetItem( me->faces, i, + ( PyObject * ) nmface_from_data( me, + vidxs, + oldmf-> + mat_nr, + oldmf-> + flag, + oldtf, + oldmc, + i) ); + } + + me->edges = PyList_New( totedge ); + for( i = 0; i < totedge; i++ ) + { + MEdge *edge = &medges[i]; + PyList_SetItem( me->edges, i, (PyObject*)nmedge_from_data ( me, edge ) ); + } + + me->materials = EXPP_PyList_fromMaterialList( oldmesh->mat, oldmesh->totcol, 0 ); + } + + return ( PyObject * ) me; +} + +PyObject *new_NMesh( Mesh * oldmesh ) +{ + return new_NMesh_internal( oldmesh, NULL ); +} + +static PyObject *M_NMesh_New( PyObject * self, PyObject * args ) +{ + char *name = NULL; + PyObject *ret = NULL; + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected nothing or a string as argument" ); + + ret = new_NMesh( NULL ); + + if( ret && name ) { + BPy_NMesh *nmesh = ( BPy_NMesh * ) ret; + Py_DECREF( nmesh->name ); + nmesh->name = PyString_FromString( name ); + } + + return ret; +} + +static PyObject *M_NMesh_GetRaw( PyObject * self, PyObject * args ) +{ + char *name = NULL; + Mesh *oldmesh = NULL; + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument (or nothing)" ); + + if( name ) { + oldmesh = ( Mesh * ) GetIdFromList( &( G.main->mesh ), name ); + + if( !oldmesh ) + return EXPP_incr_ret( Py_None ); + } + + return new_NMesh( oldmesh ); +} + +static PyObject *M_NMesh_GetNames(PyObject *self) +{ + PyObject *names = PyList_New(0), *tmpstr; + Mesh *me = G.main->mesh.first; + + while (me) { + tmpstr = PyString_FromString(me->id.name+2); + PyList_Append(names, tmpstr); + Py_DECREF(tmpstr); + me = me->id.next; + } + + return names; +} + +/* Note: NMesh.GetRawFromObject gets the display list mesh from Blender: + * the vertices are already transformed / deformed. */ +static PyObject *M_NMesh_GetRawFromObject( PyObject * self, PyObject * args ) +{ + Object *ob; + PyObject *nmesh; + ListBase *lb=0; + DispList *dl; + char *name; + + if( !PyArg_ParseTuple( args, "s", &name ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + + ob = ( Object * ) GetIdFromList( &( G.main->object ), name ); + + if( !ob ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, name ); + + + switch (ob->type) { + case OB_MBALL: + if( is_basis_mball(ob)) { + lb= &ob->disp; + if(lb->first==0) makeDispListMBall(ob); + nmesh = new_NMesh_displist(lb, ob); + } + else { + return EXPP_ReturnPyObjError( PyExc_AttributeError, "Object does not have geometry data" ); + } + break; + case OB_FONT: + case OB_CURVE: + { + Curve *cu= ob->data; + + lb= &cu->disp; + if(lb->first==0) makeDispListCurveTypes(ob, 0); + + dl= lb->first; + if(dl==0) + return EXPP_ReturnPyObjError( PyExc_AttributeError, "Object does not have geometry data" ); + + if(dl->nors==0) addnormalsDispList(ob, lb); + + nmesh = new_NMesh_displist(lb, ob); + } + break; + case OB_SURF: + + lb= &((Curve *)ob->data)->disp; + if(lb->first==0) makeDispListCurveTypes(ob, 0); + + dl= lb->first; + if(dl==0) + return EXPP_ReturnPyObjError( PyExc_AttributeError, "Object does not have geometry data" ); + + if(dl->nors==0) addnormalsDispList(ob, lb); + nmesh = new_NMesh_displist(lb, ob); + + break; + case OB_MESH: + { + CustomDataMask dataMask = CD_MASK_BAREMESH | CD_MASK_MTFACE + | CD_MASK_MCOL; + DerivedMesh *dm = mesh_create_derived_render( ob, dataMask ); + nmesh = new_NMesh_internal( ob->data, dm ); + dm->release(dm); + } + break; + default: + return EXPP_ReturnPyObjError( PyExc_AttributeError, "Object does not have geometry data" ); + } + +/* @hack: to mark that (deformed) mesh is readonly, so the update function + * will not try to write it. */ + + ( ( BPy_NMesh * ) nmesh )->mesh = 0; + + return nmesh; +} + +static void mvert_from_data( MVert * mv, MSticky * st, BPy_NMVert * from ) +{ + mv->co[0] = from->co[0]; + mv->co[1] = from->co[1]; + mv->co[2] = from->co[2]; + + mv->no[0] = (short)(from->no[0] * 32767.0); + mv->no[1] = (short)(from->no[1] * 32767.0); + mv->no[2] = (short)(from->no[2] * 32767.0); + + mv->flag = ( from->flag & 1 ); + mv->mat_nr = 0; + + if( st ) { + st->co[0] = from->uvco[0]; + st->co[1] = from->uvco[1]; + } +} + +static int assignFaceUV( MTFace * tf, BPy_NMFace * nmface ) +{ + PyObject *fuv, *tmp; + int i; + int len; + + fuv = nmface->uv; + /* if no UV info, allows things to proceed as normal */ + if( PySequence_Length( fuv ) == 0 ) { + tf->uv[0][0] = 0.0f; tf->uv[0][1] = 1.0f; + tf->uv[1][0] = 0.0f; tf->uv[1][1] = 0.0f; + tf->uv[2][0] = 1.0f; tf->uv[2][1] = 0.0f; + tf->uv[3][1] = 1.0f; tf->uv[3][1] = 1.0f; + return 1; + } + + /* if there are too many uv coordinates, only take the first 4 */ + len = PySequence_Length( fuv ); + if( len > 4 ) + len = 4; + + /* fuv = [(u_1, v_1), ... (u_n, v_n)] */ + for( i = 0; i < len; i++ ) { + tmp = PyList_GetItem( fuv, i ); /* stolen reference ! */ + if( !PyArg_ParseTuple + ( tmp, "ff", &( tf->uv[i][0] ), &( tf->uv[i][1] ) ) ) { + PyErr_SetString ( PyExc_TypeError, + "expected tuple of two floats for uv" ); + return 0; + } + } + if( nmface->image ) { /* image assigned ? */ + tf->tpage = ( void * ) nmface->image; + } else + tf->tpage = 0; + + tf->mode = nmface->mode; /* copy mode */ + tf->flag = (char)nmface->flag; /* copy flag */ + tf->transp = nmface->transp; /* copy transp flag */ + + return 1; +} + +static int mface_from_data( MFace * mf, CustomData *fdata, int findex, + BPy_NMFace * from ) +{ + BPy_NMVert *nmv; + MTFace *tf = CustomData_get(fdata, findex, CD_MTFACE); + MCol *col = CustomData_get(fdata, findex, CD_MCOL); + + int numverts = PyList_Size( from->v ); + if( numverts != 3 && numverts != 4 ) { /* face can only have three or four verts */ + PyErr_SetString ( PyExc_RuntimeError, + "faces must have at 3 or 4 vertices" ); + return 0; + } + + nmv = ( BPy_NMVert * ) PyList_GetItem( from->v, 0 ); + if( BPy_NMVert_Check( nmv ) && nmv->index != -1 ) + mf->v1 = nmv->index; + else + mf->v1 = 0; + + nmv = ( BPy_NMVert * ) PyList_GetItem( from->v, 1 ); + if( BPy_NMVert_Check( nmv ) && nmv->index != -1 ) + mf->v2 = nmv->index; + else + mf->v2 = 0; + + nmv = ( BPy_NMVert * ) PyList_GetItem( from->v, 2 ); + if( BPy_NMVert_Check( nmv ) && nmv->index != -1 ) + mf->v3 = nmv->index; + else + mf->v3 = 0; + + if( numverts == 4 ) { + nmv = ( BPy_NMVert * ) PyList_GetItem( from->v, 3 ); + if( BPy_NMVert_Check( nmv ) && nmv->index != -1 ) + mf->v4 = nmv->index; + else + mf->v4 = 0; + } + + if( tf ) + if( !assignFaceUV( tf, from ) ) + return 0; + + mf->mat_nr = from->mat_nr; + mf->flag = from->mf_flag; + + if( col ) { + int i, len = PySequence_Length( from->col ); + + if( len > 4 ) + len = 4; + + for( i = 0; i < len; i++, col++ ) { + BPy_NMCol *mc = + ( BPy_NMCol * ) PySequence_GetItem( from->col, + i ); + if( !BPy_NMCol_Check( mc ) ) { + Py_DECREF( mc ); + continue; + } + + col->b = mc->r; + col->g = mc->g; + col->r = mc->b; + col->a = mc->a; + + Py_DECREF( mc ); + } + } + + test_index_face(mf, fdata, findex, numverts); + + return 1; +} + +/* check for a valid UV sequence */ +static int check_validFaceUV( BPy_NMesh * nmesh ) +{ + PyObject *faces; + BPy_NMFace *nmface; + int i, n; + + faces = nmesh->faces; + for( i = 0; i < PySequence_Length( faces ); i++ ) { + nmface = ( BPy_NMFace * ) PyList_GetItem( faces, i ); + n = PySequence_Length( nmface->uv ); + if( n != PySequence_Length( nmface->v ) ) { + if( n > 0 ) + printf( "Warning: different length of vertex and UV coordinate " "list in face!\n" ); + return 0; + } + } + return 1; +} + +/* this is a copy of unlink_mesh in mesh.c, because ... */ +static void EXPP_unlink_mesh( Mesh * me ) +{ + int a; + + if( me == 0 ) + return; + + for( a = 0; a < me->totcol; a++ ) { + if( me->mat[a] ) + me->mat[a]->id.us--; + me->mat[a] = 0; + } + +/* ... here we want to preserve mesh keys */ +/* if users want to get rid of them, they can use mesh.removeAllKeys() */ +/* + if(me->key) me->key->id.us--; + me->key= 0; +*/ + if( me->texcomesh ) + me->texcomesh = 0; + + me->totcol = 0; +} + +static int unlink_existingMeshData( Mesh * mesh ) +{ + MDeformVert *dvert= NULL; + + EXPP_unlink_mesh( mesh ); + + if(mesh->dvert) { + /* we don't want to remove dvert here, check_dverts still needs it */ + dvert= mesh->dvert; + CustomData_set_layer( &mesh->vdata, CD_MDEFORMVERT, NULL ); + } + + CustomData_free( &mesh->vdata, mesh->totvert ); + CustomData_free( &mesh->edata, mesh->totedge ); + CustomData_free( &mesh->fdata, mesh->totface ); + mesh_update_customdata_pointers( mesh ); + + if(dvert) + mesh->dvert= CustomData_add_layer( &mesh->vdata, CD_MDEFORMVERT, + CD_ASSIGN, dvert, mesh->totvert ); + + mesh->totedge = 0; + + if( mesh->mat ) { + MEM_freeN( mesh->mat ); + mesh->mat = NULL; + } + + return 1; +} + +Material **nmesh_updateMaterials( BPy_NMesh * nmesh ) +{ + Material **matlist; + Mesh *mesh = nmesh->mesh; + int len = PyList_Size( nmesh->materials ); + + if( !mesh ) { + printf( "FATAL INTERNAL ERROR: illegal call to updateMaterials()\n" ); + return 0; + } + + if( len > 0 ) { + matlist = EXPP_newMaterialList_fromPyList( nmesh->materials ); + EXPP_incr_mats_us( matlist, len ); + + if( mesh->mat ) + MEM_freeN( mesh->mat ); + + mesh->mat = matlist; + + } else { + matlist = 0; + } + mesh->totcol = (short)len; + +/**@ This is another ugly fix due to the weird material handling of blender. + * it makes sure that object material lists get updated (by their length) + * according to their data material lists, otherwise blender crashes. + * It just stupidly runs through all objects...BAD BAD BAD. + */ + test_object_materials( ( ID * ) mesh ); + + return matlist; +} + +PyObject *NMesh_assignMaterials_toObject( BPy_NMesh * nmesh, Object * ob ) +{ + BPy_Material *pymat; + Material *ma; + int i; + short old_matmask; + Mesh *mesh = nmesh->mesh; + int nmats; /* number of mats == len(nmesh->materials) */ + + old_matmask = ob->colbits; /*@ HACK: save previous colbits */ + ob->colbits = 0; /* make assign_material work on mesh linked material */ + + nmats = PyList_Size( nmesh->materials ); + + if( nmats > 0 && !mesh->mat ) { + ob->totcol = (char)nmats; + mesh->totcol = (short)nmats; + mesh->mat = + MEM_callocN( sizeof( void * ) * nmats, "bpy_memats" ); + + if( ob->mat ) + MEM_freeN( ob->mat ); + ob->mat = + MEM_callocN( sizeof( void * ) * nmats, "bpy_obmats" ); + } + + for( i = 0; i < nmats; i++ ) { + pymat = ( BPy_Material * ) PySequence_GetItem( nmesh-> + materials, i ); + + if( BPy_Material_Check( ( PyObject * ) pymat ) ) { + ma = pymat->material; + assign_material( ob, ma, i + 1 ); /*@ XXX don't use this function anymore */ + } else { + Py_DECREF( pymat ); + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected Material type in attribute list 'materials'!" ); + } + + Py_DECREF( pymat ); + } + + ob->colbits = old_matmask; /*@ HACK */ + + ob->actcol = 1; + Py_RETURN_NONE; +} + +static void fill_medge_from_nmesh(Mesh * mesh, BPy_NMesh * nmesh) +{ + int i,j; + MEdge *faces_edges=NULL; + int tot_faces_edges=0; + int tot_valid_faces_edges=0; + int nmeshtotedges=PyList_Size(nmesh->edges); + int tot_valid_nmedges=0; + BPy_NMEdge **valid_nmedges=NULL; + + valid_nmedges=MEM_callocN(nmeshtotedges*sizeof(BPy_NMEdge *), "make BPy_NMEdge"); + + /* First compute the list of edges that exists because faces exists */ + make_edges(mesh, 0); /* 0 = draw all edges */ + + faces_edges=mesh->medge; + tot_faces_edges=mesh->totedge; + tot_valid_faces_edges=tot_faces_edges; + + mesh->medge= CustomData_set_layer(&mesh->edata, CD_MEDGE, NULL); + CustomData_free_layer_active(&mesh->edata, CD_MEDGE, mesh->totedge); + mesh->totedge = 0; + + /* Flag each edge in faces_edges that is already in nmesh->edges list. + * Flaging an edge means MEdge v1=v2=0. + * Each time an edge is flagged, tot_valid_faces_edges is decremented. + * + * Also store in valid_nmedges pointers to each valid NMEdge in nmesh->edges. + * An invalid NMEdge is an edge that has a vertex that is not in the vertices + * list. Ie its index is -1. + * Each time an valid NMEdge is flagged, tot_valid_nmedges is incremented. + */ + for( i = 0; i < nmeshtotedges; ++i ) + { + int v1idx,v2idx; + BPy_NMEdge *edge=( BPy_NMEdge *) PyList_GetItem(nmesh->edges, i); + BPy_NMVert *v=(BPy_NMVert *)edge->v1; + v1idx=v->index; + v=(BPy_NMVert *)edge->v2; + v2idx=v->index; + if (-1 == v1idx || -1 == v2idx) continue; + valid_nmedges[tot_valid_nmedges]=edge; + ++tot_valid_nmedges; + for( j = 0; j < tot_faces_edges; j++ ) + { + MEdge *me=faces_edges+j; + if ( ((int)me->v1==v1idx && (int)me->v2==v2idx) || + ((int)me->v1==v2idx && (int)me->v2==v1idx) ) + { + me->v1=0; me->v2=0; + --tot_valid_faces_edges; + } + } + } + + /* tot_valid_faces_edges < 0 causes a sigsegv crash, so we + * clamp to prevent it + * (this is related to faces (correctly) requiring at least 3 verts now, + * which can break old scripts -- maybe we should also warn about the + * 'broken' mesh the user created, but for now, until we investigate + * better, this should do) */ + if (tot_valid_faces_edges < 0) tot_valid_faces_edges = 0; + + /* Now we have the total count of valid edges */ + mesh->totedge=tot_valid_nmedges+tot_valid_faces_edges; + mesh->medge= CustomData_add_layer( &mesh->edata, CD_MEDGE, CD_CALLOC, NULL, + mesh->totedge ); + + for ( i = 0; i < tot_valid_nmedges; ++i ) + { + BPy_NMEdge *edge=valid_nmedges[i]; + MEdge *medge=mesh->medge+i; + int v1=((BPy_NMVert *)edge->v1)->index; + int v2=((BPy_NMVert *)edge->v2)->index; + medge->v1=v1; + medge->v2=v2; + medge->flag=edge->flag; + medge->crease=edge->crease; + } + for ( i = 0, j = tot_valid_nmedges; i < tot_faces_edges; ++i ) + { + MEdge *edge=faces_edges+i; + if (edge->v1!=0 || edge->v2!=0) // valid edge + { + MEdge *medge=mesh->medge+j; + medge->v1=edge->v1; + medge->v2=edge->v2; + medge->flag=ME_EDGEDRAW|ME_EDGERENDER; + medge->crease=0; + ++j; + } + } + + MEM_freeN( valid_nmedges ); + MEM_freeN( faces_edges ); +} + +/* this should ensure meshes don't end up with wrongly sized + * me->dvert arrays, which can cause hangs; it's not ideal, + * it's better to wrap dverts in NMesh, but it should do for now + * since there are also methods in NMesh to edit dverts in the actual + * mesh in Blender and anyway this is memory friendly */ +static void check_dverts(Mesh *me, int old_totvert) +{ + int totvert = me->totvert; + + /* if vert count didn't change or there are no dverts, all is fine */ + if ((totvert == old_totvert) || (!me->dvert)) return; + /* if all verts have been deleted, free old dverts */ + else if (totvert == 0) { + CustomData_free_layer_active( &me->vdata, CD_MDEFORMVERT, old_totvert ); + me->dvert= NULL; + } + else { + /* verts added or removed, make new me->dvert */ + MDeformVert *mdv = MEM_callocN( sizeof(MDeformVert)*totvert, "mdv" ); + copy_dverts( mdv, me->dvert, MIN2( old_totvert, totvert ) ); + free_dverts( me->dvert, old_totvert ); + me->dvert= CustomData_set_layer( &me->vdata, CD_MDEFORMVERT, mdv ); + } +} + +static void check_mtface_mcols( BPy_NMesh *nmesh, Mesh *mesh ) +{ + int i; + + /* copy non-active mcol and mtface layers based on original index */ + CustomData_merge( &nmesh->fdata, &mesh->fdata, CD_MASK_MCOL|CD_MASK_MTFACE, + CD_DEFAULT, mesh->totface ); + + for( i = 0; i < mesh->totface; i++ ) { + BPy_NMFace *mf = + ( BPy_NMFace * ) PySequence_GetItem( nmesh->faces, i ); + + if ( mf->orig_index != -1 ) + CustomData_copy_data( &nmesh->fdata, &mesh->fdata, mf->orig_index, + i, 1 ); + + Py_DECREF( mf ); + } + + /* add new layers if needed */ + if( ( nmesh->flags & NMESH_HASMCOL ) && + !CustomData_has_layer( &mesh->fdata, CD_MCOL ) ) { + mesh->mcol = CustomData_add_layer( &mesh->fdata, CD_MCOL, + CD_DEFAULT, NULL, mesh->totface ); + } + + if( ( nmesh->flags & NMESH_HASFACEUV ) || check_validFaceUV( nmesh ) ) { + if ( !CustomData_has_layer( &mesh->fdata, CD_MTFACE) ) + make_tfaces( mesh ); + nmesh->flags |= NMESH_HASFACEUV; + } + else + CustomData_free_layers( &mesh->fdata, CD_MTFACE, mesh->totface ); + + /* active uvs and colors from NMFace will be written in mface_from_data */ +} + +static int convert_NMeshToMesh( Mesh * mesh, BPy_NMesh * nmesh) +{ + MFace *newmf; + MVert *newmv; + MSticky *newst; + int nmeshtotedges; + int i, j, ok; + + /* Minor note: we used 'mode' because 'flag' was already used internally + * by nmesh */ + mesh->flag = nmesh->mode; + mesh->smoothresh = nmesh->smoothresh; + mesh->subdiv = nmesh->subdiv[0]; + mesh->subdivr = nmesh->subdiv[1]; + + /*@ material assignment moved to PutRaw */ + mesh->totvert = PySequence_Length( nmesh->verts ); + if( mesh->totvert ) { + if( nmesh->flags & NMESH_HASVERTUV ) + mesh->msticky = CustomData_add_layer( &mesh->vdata, CD_MSTICKY, + CD_CALLOC, NULL, mesh->totvert ); + + mesh->mvert = CustomData_add_layer( &mesh->vdata, CD_MVERT, CD_CALLOC, + NULL, mesh->totvert ); + } + + if( mesh->totvert ) + mesh->totface = PySequence_Length( nmesh->faces ); + else + mesh->totface = 0; + + if( mesh->totface ) { + check_mtface_mcols( nmesh, mesh ); + + mesh->mface = CustomData_add_layer( &mesh->fdata, CD_MFACE, CD_CALLOC, + NULL, mesh->totface ); + } + + mesh_update_customdata_pointers( mesh ); + + /*@ This stuff here is to tag all the vertices referenced + * by faces, then untag the vertices which are actually + * in the vert list. Any vertices untagged will be ignored + * by the mface_from_data function. It comes from my + * screwed up decision to not make faces only store the + * index. - Zr + */ + for( i = 0; i < mesh->totface; i++ ) { + BPy_NMFace *mf = + ( BPy_NMFace * ) PySequence_GetItem( nmesh->faces, i ); + + j = PySequence_Length( mf->v ); + while( j-- ) { + BPy_NMVert *mv = + ( BPy_NMVert * ) PySequence_GetItem( mf->v, + j ); + if( BPy_NMVert_Check( mv ) ) + mv->index = -1; + Py_DECREF( mv ); + } + + Py_DECREF( mf ); + } + /* do the same for edges if there is edge data */ + nmeshtotedges=PyList_Size(nmesh->edges); + for( i = 0; i < nmeshtotedges; ++i ) + { + BPy_NMEdge *edge=( BPy_NMEdge *) PyList_GetItem(nmesh->edges, i); + BPy_NMVert *v=(BPy_NMVert *)edge->v1; + v->index=-1; + v=(BPy_NMVert *)edge->v2; + v->index=-1; + } + + for( i = 0; i < mesh->totvert; i++ ) { + BPy_NMVert *mv = + ( BPy_NMVert * ) PySequence_GetItem( nmesh->verts, i ); + mv->index = i; + Py_DECREF( mv ); + } + + newmv = mesh->mvert; + newst = mesh->msticky; + for( i = 0; i < mesh->totvert; i++ ) { + PyObject *mv = PySequence_GetItem( nmesh->verts, i ); + mvert_from_data( newmv, newst, ( BPy_NMVert * ) mv ); + Py_DECREF( mv ); + + newmv++; + if( newst ) + newst++; + } + + newmf = mesh->mface; + for( i = 0; i < mesh->totface; i++ ) { + PyObject *mf = PySequence_GetItem( nmesh->faces, i ); + ok = mface_from_data( newmf, &mesh->fdata, i, ( BPy_NMFace * ) mf ); + Py_DECREF( mf ); + if( !ok ) + return 0; + newmf++; + } + + /* Always do this to ensure no loose edges in faces */ + fill_medge_from_nmesh(mesh, nmesh); + + return 1; +} + +static PyObject *M_NMesh_PutRaw( PyObject * self, PyObject * args ) +{ + char *name = NULL; + Mesh *mesh = NULL; + Object *ob = NULL; + BPy_NMesh *nmesh; + int recalc_normals = 1; + int store_edges = 0; + int old_totvert = 0; + + if( !PyArg_ParseTuple( args, "O!|sii", + &NMesh_Type, &nmesh, &name, &recalc_normals, &store_edges ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected an NMesh object and optionally also a string and two ints" ); + + if( check_NMeshLists( nmesh ) ) + return NULL; + + if( name ) + mesh = ( Mesh * ) GetIdFromList( &( G.main->mesh ), name ); + + if( !mesh || mesh->id.us == 0 ) { + ob = add_object( OB_MESH ); + if( !ob ) { + PyErr_SetString( PyExc_RuntimeError, + "Fatal: could not create mesh object" ); + return 0; + } + + if( !mesh ) + mesh = ( Mesh * ) ob->data; + else + set_mesh( ob, mesh ); // also does id.us++ + + nmesh->object = ob; // linking so vgrouping methods know which obj to work on + } + + if( name ) + new_id( &( G.main->mesh ), &mesh->id, name ); + else if( nmesh->name && nmesh->name != Py_None ) + new_id( &( G.main->mesh ), &mesh->id, + PyString_AsString( nmesh->name ) ); + + old_totvert = mesh->totvert; + + unlink_existingMeshData( mesh ); + if( !convert_NMeshToMesh( mesh, nmesh ) ) + return NULL; + nmesh->mesh = mesh; + + if (mesh->dvert) check_dverts(mesh, old_totvert); + + if( recalc_normals ) + mesh_calc_normals(mesh->mvert, mesh->totvert, mesh->mface, mesh->totface, NULL); + + mesh_update( mesh, nmesh->object ); + + if( !during_script( ) ) + EXPP_allqueue( REDRAWVIEW3D, 0 ); + + if (ob && G.obedit) { /* prevents a crash when a new object is created */ + exit_editmode(EM_FREEDATA); + enter_editmode(0); + } + + // @OK...this requires some explanation: + // Materials can be assigned two ways: + // a) to the object data (in this case, the mesh) + // b) to the Object + // + // Case a) is wanted, if Mesh data should be shared among objects, + // as well as its materials (up to 16) + // Case b) is wanted, when Mesh data should be shared, but not the + // materials. For example, you want several checker boards sharing their + // mesh data, but having different colors. So you would assign material + // index 0 to all even, index 1 to all odd faces and bind the materials + // to the Object instead (MaterialButtons: [OB] "link materials to object") + // + // This feature implies that pointers to materials can be stored in + // an object or a mesh. The number of total materials MUST be + // synchronized (ob->totcol <-> mesh->totcol). We avoid the dangerous + // direct access by calling blenderkernel/material.c:assign_material(). + + // The flags setting the material binding is found in ob->colbits, where + // each bit indicates the binding PER MATERIAL + + if( ob ) { // we created a new object + NMesh_assignMaterials_toObject( nmesh, ob ); + EXPP_synchronizeMaterialLists( ob ); + return Object_CreatePyObject( ob ); + } else { + mesh->mat = + EXPP_newMaterialList_fromPyList( nmesh->materials ); + EXPP_incr_mats_us( mesh->mat, + PyList_Size( nmesh->materials ) ); + Py_RETURN_NONE; + } + +} + +#undef MethodDef +#define MethodDef(func) \ + {#func, M_NMesh_##func, METH_VARARGS, M_NMesh_##func##_doc} + +static struct PyMethodDef M_NMesh_methods[] = { + MethodDef( Col ), + MethodDef( Vert ), + MethodDef( Face ), + MethodDef( New ), + MethodDef( GetRaw ), + MethodDef( GetRawFromObject ), + MethodDef( PutRaw ), + {"GetNames", (PyCFunction)M_NMesh_GetNames, METH_NOARGS, + M_NMesh_GetNames_doc}, + {NULL, NULL, 0, NULL} +}; + +static PyObject *M_NMesh_Modes( void ) +{ + PyObject *Modes = PyConstant_New( ); + + if( Modes ) { + BPy_constant *d = ( BPy_constant * ) Modes; + + PyConstant_Insert( d, "NOVNORMALSFLIP", + PyInt_FromLong + ( ME_NOPUNOFLIP ) ); + PyConstant_Insert( d, "TWOSIDED", + PyInt_FromLong( ME_TWOSIDED ) ); + PyConstant_Insert( d, "AUTOSMOOTH", + PyInt_FromLong + ( ME_AUTOSMOOTH ) ); + } + + return Modes; +} + +#undef EXPP_ADDCONST +#define EXPP_ADDCONST(dict, name) \ + PyConstant_Insert(dict, #name, PyInt_FromLong(TF_##name)) +/* Set constants for face drawing mode -- see drawmesh.c */ + +static PyObject *M_NMesh_FaceModesDict( void ) +{ + PyObject *FM = PyConstant_New( ); + + if( FM ) { + BPy_constant *d = ( BPy_constant * ) FM; + + PyConstant_Insert( d, "BILLBOARD", + PyInt_FromLong( TF_BILLBOARD2 ) ); + PyConstant_Insert( d, "ALL", PyInt_FromLong( 0x7fff ) ); + PyConstant_Insert( d, "HALO", PyInt_FromLong( TF_BILLBOARD ) ); + PyConstant_Insert( d, "DYNAMIC", PyInt_FromLong( TF_DYNAMIC ) ); + PyConstant_Insert( d, "INVISIBLE", PyInt_FromLong( TF_INVISIBLE ) ); + PyConstant_Insert( d, "LIGHT", PyInt_FromLong( TF_LIGHT ) ); + PyConstant_Insert( d, "OBCOL", PyInt_FromLong( TF_OBCOL ) ); + PyConstant_Insert( d, "SHADOW", PyInt_FromLong( TF_SHADOW ) ); + PyConstant_Insert( d, "TEXT", PyInt_FromLong( TF_BMFONT ) ); + PyConstant_Insert( d, "SHAREDVERT", PyInt_FromLong( TF_SHAREDVERT ) ); + PyConstant_Insert( d, "SHAREDCOL", PyInt_FromLong( TF_SHAREDCOL ) ); + PyConstant_Insert( d, "TEX", PyInt_FromLong( TF_TEX ) ); + PyConstant_Insert( d, "TILES", PyInt_FromLong( TF_TILES ) ); + PyConstant_Insert( d, "TWOSIDE", PyInt_FromLong( TF_TWOSIDE ) ); + } + + return FM; +} + +static PyObject *M_NMesh_FaceFlagsDict( void ) +{ + PyObject *FF = PyConstant_New( ); + + if( FF ) { + BPy_constant *d = ( BPy_constant * ) FF; + + EXPP_ADDCONST( d, SELECT ); + EXPP_ADDCONST( d, HIDE ); + EXPP_ADDCONST( d, ACTIVE ); + } + + return FF; +} + +static PyObject *M_NMesh_FaceTranspModesDict( void ) +{ + PyObject *FTM = PyConstant_New( ); + + if( FTM ) { + BPy_constant *d = ( BPy_constant * ) FTM; + + EXPP_ADDCONST( d, SOLID ); + EXPP_ADDCONST( d, ADD ); + EXPP_ADDCONST( d, ALPHA ); + EXPP_ADDCONST( d, SUB ); + } + + return FTM; +} + +static PyObject *M_NMesh_EdgeFlagsDict( void ) +{ + PyObject *EF = PyConstant_New( ); + + if( EF ) { + BPy_constant *d = ( BPy_constant * ) EF; + + PyConstant_Insert(d, "SELECT", PyInt_FromLong(1)); + PyConstant_Insert(d, "EDGEDRAW", PyInt_FromLong(ME_EDGEDRAW)); + PyConstant_Insert(d, "EDGERENDER", PyInt_FromLong(ME_EDGERENDER)); + PyConstant_Insert(d, "SEAM", PyInt_FromLong(ME_SEAM)); + PyConstant_Insert(d, "FGON", PyInt_FromLong(ME_FGON)); + } + + return EF; +} + +PyObject *NMesh_Init( void ) +{ + PyObject *submodule; + + PyObject *Modes = M_NMesh_Modes( ); + PyObject *FaceFlags = M_NMesh_FaceFlagsDict( ); + PyObject *FaceModes = M_NMesh_FaceModesDict( ); + PyObject *FaceTranspModes = M_NMesh_FaceTranspModesDict( ); + PyObject *EdgeFlags = M_NMesh_EdgeFlagsDict( ); + + NMCol_Type.ob_type = &PyType_Type; + NMFace_Type.ob_type = &PyType_Type; + NMVert_Type.ob_type = &PyType_Type; + NMesh_Type.ob_type = &PyType_Type; + + submodule = + Py_InitModule3( "Blender.NMesh", M_NMesh_methods, + M_NMesh_doc ); + + if( Modes ) + PyModule_AddObject( submodule, "Modes", Modes ); + if( FaceFlags ) + PyModule_AddObject( submodule, "FaceFlags", FaceFlags ); + if( FaceModes ) + PyModule_AddObject( submodule, "FaceModes", FaceModes ); + if( FaceTranspModes ) + PyModule_AddObject( submodule, "FaceTranspModes", + FaceTranspModes ); + if( EdgeFlags ) + PyModule_AddObject( submodule, "EdgeFlags", EdgeFlags ); + + g_nmeshmodule = submodule; + return submodule; +} + +/* These are needed by Object.c */ + +PyObject *NMesh_CreatePyObject( Mesh * me, Object * ob ) +{ + BPy_NMesh *nmesh = ( BPy_NMesh * ) new_NMesh( me ); + + if( nmesh ) + nmesh->object = ob; /* linking nmesh and object for vgrouping methods */ + + return ( PyObject * ) nmesh; +} + +int NMesh_CheckPyObject( PyObject * pyobj ) +{ + return ( pyobj->ob_type == &NMesh_Type ); +} + +Mesh *NMesh_FromPyObject( PyObject * pyobj, Object * ob ) +{ + if( pyobj->ob_type == &NMesh_Type ) { + Mesh *mesh; + BPy_NMesh *nmesh = ( BPy_NMesh * ) pyobj; + + if( nmesh->mesh ) { + mesh = nmesh->mesh; + } else { + mesh = Mesh_fromNMesh( nmesh ); + if( !mesh ) /* NULL means an PyError */ + return NULL; + + nmesh->mesh = mesh; + + nmesh->object = ob; /* linking for vgrouping methods */ + if( nmesh->name && nmesh->name != Py_None ) + new_id( &( G.main->mesh ), &mesh->id, + PyString_AsString( nmesh->name ) ); + mesh_update( mesh, nmesh->object ); + nmesh_updateMaterials( nmesh ); + } + return mesh; + } + + PyErr_SetString( PyExc_AttributeError, + "link argument type is not supported " ); + return NULL; +} + +#define POINTER_CROSS_EQ(a1, a2, b1, b2) (((a1)==(b1) && (a2)==(b2)) || ((a1)==(b2) && (a2)==(b1))) + +static PyObject *findEdge( BPy_NMesh *nmesh, BPy_NMVert *v1, BPy_NMVert *v2, int create) +{ + int i; + + for ( i = 0; i < PyList_Size(nmesh->edges); ++i ) + { + BPy_NMEdge *edge=(BPy_NMEdge*)PyList_GetItem( nmesh->edges, i ); + if (!BPy_NMEdge_Check(edge)) continue; + if ( POINTER_CROSS_EQ((BPy_NMVert*)edge->v1, (BPy_NMVert*)edge->v2, v1, v2) ) + { + return EXPP_incr_ret((PyObject*)edge); + } + } + + /* if this line is reached, edge has not been found */ + if (create) + { + PyObject *newEdge=(PyObject *)new_NMEdge(v1, v2, 0, ME_EDGEDRAW|ME_EDGERENDER); + PyList_Append(nmesh->edges, newEdge); + return newEdge; + } + else + Py_RETURN_NONE; +} + +static void removeEdge( BPy_NMesh *nmesh, BPy_NMVert *v1, BPy_NMVert *v2, int ununsedOnly) +{ + int i,j; + BPy_NMEdge *edge=NULL; + int edgeUsedByFace=0; + int totedge=PyList_Size(nmesh->edges); + + /* find the edge in the edge list */ + for ( i = 0; i < totedge; ++i ) + { + edge=(BPy_NMEdge*)PyList_GetItem( nmesh->edges, i ); + if (!BPy_NMEdge_Check(edge)) continue; + if ( POINTER_CROSS_EQ((BPy_NMVert*)edge->v1, (BPy_NMVert*)edge->v2, v1, v2) ) + { + break; + } + } + + if (i==totedge || !edge) // edge not found + return; + + for ( j = PyList_Size(nmesh->faces)-1; j >= 0 ; --j ) + { + BPy_NMFace *face=(BPy_NMFace *)PyList_GetItem(nmesh->faces, j); + int k, del_face=0; + int totv; + if (!BPy_NMFace_Check(face)) continue; + totv=PyList_Size(face->v); + if (totv<2) continue; + for ( k = 0; k < totv && !del_face; ++k ) + { + BPy_NMVert *fe_v1=(BPy_NMVert *)PyList_GetItem(face->v, k ? k-1 : totv-1); + BPy_NMVert *fe_v2=(BPy_NMVert *)PyList_GetItem(face->v, k); + if ( POINTER_CROSS_EQ(v1, v2, fe_v1, fe_v2) ) + { + edgeUsedByFace=1; + del_face=1; + } + } + if (del_face && !ununsedOnly) + { + PySequence_DelItem(nmesh->faces, j); + } + } + + if (!ununsedOnly || (ununsedOnly && !edgeUsedByFace) ) + PySequence_DelItem(nmesh->edges, PySequence_Index(nmesh->edges, (PyObject*)edge)); +} + + +static PyObject *NMesh_addEdge( PyObject * self, PyObject * args ) +{ + BPy_NMesh *bmesh=(BPy_NMesh *)self; + BPy_NMVert *v1=NULL, *v2=NULL; + + if (!PyArg_ParseTuple + ( args, "O!O!", &NMVert_Type, &v1, &NMVert_Type, &v2 ) ) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected NMVert, NMVert" ); + } + + if (v1==v2) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "vertices must be different" ); + + return findEdge(bmesh, v1, v2, 1); +} + +static PyObject *NMesh_findEdge( PyObject * self, PyObject * args ) +{ + BPy_NMesh *bmesh=(BPy_NMesh *)self; + BPy_NMVert *v1=NULL, *v2=NULL; + + if (!PyArg_ParseTuple + ( args, "O!O!", &NMVert_Type, &v1, &NMVert_Type, &v2 ) ) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected NMVert, NMVert" ); + } + + if (v1==v2) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "vertices must be different" ); + + return findEdge(bmesh, v1, v2, 0); +} + +static PyObject *NMesh_removeEdge( PyObject * self, PyObject * args ) +{ + BPy_NMesh *bmesh=(BPy_NMesh *)self; + BPy_NMVert *v1=NULL, *v2=NULL; + + if (!PyArg_ParseTuple + ( args, "O!O!", &NMVert_Type, &v1, &NMVert_Type, &v2 ) ) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected NMVert, NMVert" ); + } + + if (v1==v2) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "vertices must be different" ); + removeEdge(bmesh, v1, v2, 0); + + Py_RETURN_NONE; +} + + +static PyObject *NMesh_addFace( PyObject * self, PyObject * args ) +{ + BPy_NMesh *nmesh=(BPy_NMesh *)self; + + BPy_NMFace *face; + int totv=0; + + if (!PyArg_ParseTuple + ( args, "O!", &NMFace_Type, &face ) ) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected NMFace argument" ); + } + + totv=PyList_Size(face->v); + + /* + * Before edges data exists, having faces with two vertices was + * the only way of storing edges not attached to any face. + */ + if (totv!=2) + PyList_Append(nmesh->faces, (PyObject*)face); + + if (totv>=2) + { + /* when totv==2, there is only one edge, when totv==3 there is three edges + * and when totv==4 there is four edges. + * that's why in the following line totv==2 is a special case */ + PyObject *edges = PyList_New((totv==2) ? 1 : totv); + if (totv==2) + { + BPy_NMVert *fe_v1=(BPy_NMVert *)PyList_GetItem(face->v, 0); + BPy_NMVert *fe_v2=(BPy_NMVert *)PyList_GetItem(face->v, 1); + BPy_NMEdge *edge=(BPy_NMEdge *)findEdge(nmesh, fe_v1, fe_v2, 1); + PyList_SetItem(edges, 0, (PyObject*)edge); // PyList_SetItem steals the reference + } + else + { + int k; + for ( k = 0; k < totv; ++k ) + { + BPy_NMVert *fe_v1=(BPy_NMVert *)PyList_GetItem(face->v, k ? k-1 : totv-1); + BPy_NMVert *fe_v2=(BPy_NMVert *)PyList_GetItem(face->v, k); + BPy_NMEdge *edge=(BPy_NMEdge *)findEdge(nmesh, fe_v1, fe_v2, 1); + PyList_SetItem(edges, k, (PyObject*)edge); // PyList_SetItem steals the reference + } + } + return edges; + } + + Py_RETURN_NONE; +} + +static PyObject *NMesh_removeFace( PyObject * self, PyObject * args ) +{ + BPy_NMesh *nmesh=(BPy_NMesh *)self; + + BPy_NMFace *face; + int totv=0; + + if (!PyArg_ParseTuple + ( args, "O!", &NMFace_Type, &face ) ) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected NMFace argument" ); + } + + totv=PyList_Size(face->v); + + { + int index=PySequence_Index(nmesh->faces, (PyObject*)face); + if (index>=0) + PySequence_DelItem(nmesh->faces, index); + } + + if (totv>=2) + { + /* when totv==2, there is only one edge, when totv==3 there is three edges + * and when totv==4 there is four edges. + * that's why in the following line totv==2 is a special case */ + if (totv==2) + { + BPy_NMVert *fe_v1=(BPy_NMVert *)PyList_GetItem(face->v, 0); + BPy_NMVert *fe_v2=(BPy_NMVert *)PyList_GetItem(face->v, 1); + removeEdge(nmesh, fe_v1, fe_v2, 1); + } + else + { + int k; + for ( k = 0; k < totv; ++k ) + { + BPy_NMVert *fe_v1=(BPy_NMVert *)PyList_GetItem(face->v, k ? k-1 : totv-1); + BPy_NMVert *fe_v2=(BPy_NMVert *)PyList_GetItem(face->v, k); + removeEdge(nmesh, fe_v1, fe_v2, 1); + } + } + } + + Py_RETURN_NONE; +} + +static PyObject *NMesh_printDebug( PyObject * self ) +{ + BPy_NMesh *bmesh=(BPy_NMesh *)self; + + Mesh *mesh=bmesh->mesh; + + printf("**Vertices\n"); + { + int i; + for (i=0; itotvert; ++i) + { + MVert *v=mesh->mvert+i; + double x=v->co[0]; + double y=v->co[1]; + double z=v->co[2]; + printf(" %2d : %.3f %.3f %.3f\n", i, x, y, z); + } + } + + printf("**Edges\n"); + { + int i; + for (i=0; itotedge; ++i) + { + MEdge *e=mesh->medge+i; + int v1 = e->v1; + int v2 = e->v2; + int flag = e->flag; + printf(" %2d : %2d %2d flag=%d\n", i, v1, v2, flag); + } + } + + printf("**Faces\n"); + { + int i; + for (i=0; itotface; ++i) + { + MFace *e=((MFace*)(mesh->mface))+i; + int v1 = e->v1; + int v2 = e->v2; + int v3 = e->v3; + int v4 = e->v4; + printf(" %2d : %2d %2d %2d %2d\n", i, v1, v2, v3, v4); + } + } + + Py_RETURN_NONE; +} + +static PyObject *NMesh_addVertGroup( PyObject * self, PyObject * args ) +{ + char *groupStr; + struct Object *object; + PyObject *tempStr; + + if( !PyArg_ParseTuple( args, "s", &groupStr ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + + if( ( ( BPy_NMesh * ) self )->object == NULL ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "mesh must be linked to an object first..." ); + + object = ( ( BPy_NMesh * ) self )->object; + + //get clamped name + tempStr = PyString_FromStringAndSize( groupStr, 32 ); + groupStr = PyString_AsString( tempStr ); + + add_defgroup_name( object, groupStr ); + + EXPP_allqueue( REDRAWBUTSALL, 1 ); + + Py_RETURN_NONE; +} + +static PyObject *NMesh_removeVertGroup( PyObject * self, PyObject * args ) +{ + char *groupStr; + struct Object *object; + int nIndex; + bDeformGroup *pGroup; + + if( !PyArg_ParseTuple( args, "s", &groupStr ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + + if( ( ( BPy_NMesh * ) self )->object == NULL ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "mesh must be linked to an object first..." ); + + object = ( ( BPy_NMesh * ) self )->object; + + pGroup = get_named_vertexgroup( object, groupStr ); + if( pGroup == NULL ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "group does not exist!" ); + + nIndex = get_defgroup_num( object, pGroup ); + if( nIndex == -1 ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "no deform groups assigned to mesh" ); + nIndex++; + object->actdef = (unsigned short)nIndex; + + del_defgroup( object ); + + EXPP_allqueue( REDRAWBUTSALL, 1 ); + + Py_RETURN_NONE; +} + +static PyObject *NMesh_assignVertsToGroup( PyObject * self, PyObject * args ) +{ + //listObject is an integer list of vertex indices to add to group + //groupStr = group name + //weight is a float defining the weight this group has on this vertex + //assignmode = "replace", "add", "subtract" + // replace weight - add addition weight to vertex for this group + // - remove group influence from this vertex + //the function will not like it if your in editmode... + + char *groupStr; + char *assignmodeStr = NULL; + int nIndex; + int assignmode; + float weight = 1.0; + struct Object *object; + bDeformGroup *pGroup; + PyObject *listObject; + int tempInt; + int x; + + if( ( ( BPy_NMesh * ) self )->object == NULL ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "mesh must be linked to an object first..." ); + + if( !PyArg_ParseTuple + ( args, "sO!fs", &groupStr, &PyList_Type, &listObject, &weight, + &assignmodeStr ) ) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string, list, float, string arguments" ); + } + + object = ( ( BPy_NMesh * ) self )->object; + + if( object->data == NULL ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "object contains no data..." ); + + pGroup = get_named_vertexgroup( object, groupStr ); + if( pGroup == NULL ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "group does not exist!" ); + + nIndex = get_defgroup_num( object, pGroup ); + if( nIndex == -1 ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "no deform groups assigned to mesh" ); + + if( assignmodeStr == NULL ) + assignmode = 1; /* default */ + else if( STREQ( assignmodeStr, "replace" ) ) + assignmode = 1; + else if( STREQ( assignmodeStr, "add" ) ) + assignmode = 2; + else if( STREQ( assignmodeStr, "subtract" ) ) + assignmode = 3; + else + return EXPP_ReturnPyObjError( PyExc_ValueError, + "bad assignment mode" ); + + //makes a set of dVerts corresponding to the mVerts + if( !( ( Mesh * ) object->data )->dvert ) { + create_dverts( object->data ); + } + //loop list adding verts to group + for( x = 0; x < PyList_Size( listObject ); x++ ) { + if( ! + ( PyArg_Parse + ( ( PyList_GetItem( listObject, x ) ), "i", + &tempInt ) ) ) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "python list integer not parseable" ); + } + + if( tempInt < 0 + || tempInt >= ( ( Mesh * ) object->data )->totvert ) { + return EXPP_ReturnPyObjError( PyExc_ValueError, + "bad vertex index in list" ); + } + + add_vert_defnr( object, nIndex, tempInt, weight, assignmode ); + } + + Py_RETURN_NONE; +} + +static PyObject *NMesh_removeVertsFromGroup( PyObject * self, PyObject * args ) +{ + //not passing a list will remove all verts from group + + char *groupStr; + int nIndex; + struct Object *object; + bDeformGroup *pGroup; + PyObject *listObject; + int tempInt; + int x, argc; + + /* argc is the number of parameters passed in: 1 (no list given) or 2: */ + argc = PyObject_Length( args ); + + if( !PyArg_ParseTuple + ( args, "s|O!", &groupStr, &PyList_Type, &listObject ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string and optional list argument" ); + + if( ( ( BPy_NMesh * ) self )->object == NULL ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "mesh must be linked to an object first..." ); + + object = ( ( BPy_NMesh * ) self )->object; + + if( object->data == NULL ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "object contains no data..." ); + + if( ( !( ( Mesh * ) object->data )->dvert ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "this mesh contains no deform vertices...'" ); + + pGroup = get_named_vertexgroup( object, groupStr ); + if( pGroup == NULL ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "group does not exist!" ); + + nIndex = get_defgroup_num( object, pGroup ); + if( nIndex == -1 ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "no deform groups assigned to mesh" ); + + if( argc == 1 ) { /* no list given */ + //enter editmode + if( ( G.obedit == 0 ) ) { + //set current object + BASACT->object = object; + G.obedit = BASACT->object; + } + //set current vertex group + nIndex++; + object->actdef = (unsigned short)nIndex; + + //clear all dVerts in active group + remove_verts_defgroup( 1 ); + + //exit editmode + G.obedit = 0; + } else { + if( G.obedit != 0 ) //remove_vert_def_nr doesn't like it if your in editmode + G.obedit = 0; + + //loop list adding verts to group + for( x = 0; x < PyList_Size( listObject ); x++ ) { + if( ! + ( PyArg_Parse + ( ( PyList_GetItem( listObject, x ) ), "i", + &tempInt ) ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "python list integer not parseable" ); + + if( tempInt < 0 + || tempInt >= + ( ( Mesh * ) object->data )->totvert ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "bad vertex index in list" ); + + remove_vert_def_nr( object, nIndex, tempInt ); + } + } + + Py_RETURN_NONE; +} + +static PyObject *NMesh_getVertsFromGroup( PyObject * self, PyObject * args ) +{ + //not passing a list will return all verts from group + //passing indecies not part of the group will not return data in pyList + //can be used as a index/group check for a vertex + + char *groupStr; + int nIndex; + int weightRet; + struct Object *object; + bDeformGroup *pGroup; + MVert *mvert; + MDeformVert *dvert; + float weight; + int i, k, l1, l2, count; + int num = 0; + PyObject *tempVertexList = NULL; + PyObject *vertexList; + PyObject *listObject; + int tempInt; + int x; + + listObject = Py_None; //can't use NULL macro because compiler thinks + //it's a 0 and we need to check 0 index vertex pos + l1 = FALSE; + l2 = FALSE; + weightRet = 0; + + if( !PyArg_ParseTuple( args, "s|iO!", &groupStr, &weightRet, + &PyList_Type, &listObject ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string and optional int and list arguments" ); + + if( weightRet < 0 || weightRet > 1 ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "return weights flag must be 0 or 1..." ); + + if( ( ( BPy_NMesh * ) self )->object == NULL ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "mesh must be linked to an object first..." ); + + object = ( ( BPy_NMesh * ) self )->object; + + if( object->data == NULL ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "object contains no data..." ); + + if( ( !( ( Mesh * ) object->data )->dvert ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "this mesh contains no deform vertices...'" ); + + pGroup = get_named_vertexgroup( object, groupStr ); + if( pGroup == NULL ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "group does not exist!" ); + + nIndex = get_defgroup_num( object, pGroup ); + if( nIndex == -1 ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "no deform groups assigned to mesh" ); + + //temporary list + tempVertexList = PyList_New( ( ( Mesh * ) object->data )->totvert ); + if( tempVertexList == NULL ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "getVertsFromGroup: can't create pylist!" ); + + count = 0; + + if( listObject == Py_None ) //do entire group + { + for( k = 0; k < ( ( Mesh * ) object->data )->totvert; k++ ) { + dvert = ( ( Mesh * ) object->data )->dvert + k; + + for( i = 0; i < dvert->totweight; i++ ) { + if( dvert->dw[i].def_nr == nIndex ) { + mvert = ( ( Mesh * ) object->data )-> + mvert + k; + weight = dvert->dw[i].weight; + //printf("index =%3d weight:%10f\n", k, weight); + + if( weightRet == 1 ) + PyList_SetItem( tempVertexList, + count, + Py_BuildValue + ( "(i,f)", k, + weight ) ); + else if( weightRet == 0 ) + PyList_SetItem( tempVertexList, + count, + Py_BuildValue + ( "i", k ) ); + + count++; + } + } + } + } else //do single vertex + { + //loop list adding verts to group + for( x = 0; x < PyList_Size( listObject ); x++ ) { + if( ! + ( PyArg_Parse + ( ( PyList_GetItem( listObject, x ) ), "i", + &tempInt ) ) ) { + Py_DECREF(tempVertexList); + return EXPP_ReturnPyObjError( PyExc_TypeError, + "python list integer not parseable" ); + } + if( tempInt < 0 + || tempInt >= + ( ( Mesh * ) object->data )->totvert ) { + Py_DECREF(tempVertexList); + return EXPP_ReturnPyObjError( PyExc_ValueError, + "bad vertex index in list" ); + } + num = tempInt; + dvert = ( ( Mesh * ) object->data )->dvert + num; + for( i = 0; i < dvert->totweight; i++ ) { + l1 = TRUE; + if( dvert->dw[i].def_nr == nIndex ) { + l2 = TRUE; + mvert = ( ( Mesh * ) object->data )-> + mvert + num; + + weight = dvert->dw[i].weight; + //printf("index =%3d weight:%10f\n", num, weight); + + if( weightRet == 1 ) { + PyList_SetItem( tempVertexList, + count, + Py_BuildValue + ( "(i,f)", num, + weight ) ); + } else if( weightRet == 0 ) + PyList_SetItem( tempVertexList, + count, + Py_BuildValue + ( "i", num ) ); + + count++; + } + if( l2 == FALSE ) + printf( "vertex at index %d is not part of passed group...\n", tempInt ); + } + if( l1 == FALSE ) + printf( "vertex at index %d is not assigned to a vertex group...\n", tempInt ); + + l1 = l2 = FALSE; //reset flags + } + } + //only return what we need + vertexList = PyList_GetSlice( tempVertexList, 0, count ); + + Py_DECREF( tempVertexList ); + + return ( vertexList ); +} + +static PyObject *NMesh_renameVertGroup( PyObject * self, PyObject * args ) +{ + char *oldGr = NULL; + char *newGr = NULL; + bDeformGroup *defGroup = NULL; + /*PyObject *tempStr; */ + + + if( !( ( BPy_NMesh * ) self )->object ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This mesh must be linked to an object" ); + + if( !PyArg_ParseTuple( args, "ss", &oldGr, &newGr ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "Expected string & string argument" ); + + defGroup = + get_named_vertexgroup( ( ( BPy_NMesh * ) self )->object, + oldGr ); + if( defGroup == NULL ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Couldn't find the expected vertex group" ); + + PyOS_snprintf( defGroup->name, 32, newGr ); + unique_vertexgroup_name( defGroup, ( ( BPy_NMesh * ) self )->object ); + + Py_RETURN_NONE; +} + +static PyObject *NMesh_getVertGroupNames( PyObject * self ) +{ + bDeformGroup *defGroup; + PyObject *list, *tmpstr; + + if( !( ( BPy_NMesh * ) self )->object ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This mesh must be linked to an object" ); + + list = PyList_New( 0 ); + for( defGroup = ( ( ( BPy_NMesh * ) self )->object )->defbase.first; + defGroup; defGroup = defGroup->next ) { + + tmpstr = PyString_FromString( defGroup->name ); + if( PyList_Append( list, tmpstr) < 0 ) { + Py_XDECREF(list); + Py_XDECREF(tmpstr); + return EXPP_ReturnPyObjError( PyExc_RuntimeError, "Couldn't add item to list" ); + } + Py_XDECREF(tmpstr); + } + + return list; +} + +static PyObject *NMesh_transform (PyObject *self, PyObject *args) +{ + BPy_NMesh *nmesh = ( BPy_NMesh * ) self; + BPy_NMVert *mv; + PyObject *ob1 = NULL; + MatrixObject *mat; + float vx, vy, vz; + int i, recalc_normals = 0; + + if( !PyArg_ParseTuple( args, "O!|i", &matrix_Type, &ob1, &recalc_normals ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected matrix and optionally an int as arguments" ) ); + + mat = ( MatrixObject * ) ob1; + + if( mat->colSize != 4 || mat->rowSize != 4 ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "matrix must be a 4x4 transformation matrix\n" + "for example as returned by object.getMatrix()" ) ); + + /* loop through all the verts and transform locations by the supplied + * matrix */ + for( i = 0; i < PySequence_Length(nmesh->verts); i++ ) { + mv = ( BPy_NMVert * ) PySequence_GetItem( nmesh->verts, i ); + vx = mv->co[0]; + vy = mv->co[1]; + vz = mv->co[2]; + + /* Mat4MulVecfl(mat->matrix, mv->co); */ + mv->co[0] = vx*mat->matrix[0][0] + vy*mat->matrix[1][0] + + vz*mat->matrix[2][0] + mat->matrix[3][0]; + mv->co[1] = vx*mat->matrix[0][1] + vy*mat->matrix[1][1] + + vz*mat->matrix[2][1] + mat->matrix[3][1]; + mv->co[2] = vx*mat->matrix[0][2] + vy*mat->matrix[1][2] + + vz*mat->matrix[2][2] + mat->matrix[3][2]; + + Py_DECREF(mv); + } + + if ( recalc_normals ) { + /* loop through all the verts and transform normals by the inverse + * of the transpose of the supplied matrix */ + float invmat[4][4]; + + /* we only need to invert a 3x3 submatrix, because the 4th component of + * affine vectors is 0, but Mat4Invert reports non invertible matrices */ + if (!Mat4Invert((float(*)[4])*invmat, (float(*)[4])*mat->matrix)) + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "given matrix is not invertible"); + + for( i = 0; i < PySequence_Length(nmesh->verts); i++ ) { + mv = ( BPy_NMVert * ) PySequence_GetItem( nmesh->verts, i ); + vx = mv->no[0]; + vy = mv->no[1]; + vz = mv->no[2]; + mv->no[0] = vx*invmat[0][0] + vy*invmat[0][1] + vz*invmat[0][2]; + mv->no[1] = vx*invmat[1][0] + vy*invmat[1][1] + vz*invmat[1][2]; + mv->no[2] = vx*invmat[2][0] + vy*invmat[2][1] + vz*invmat[2][2]; + Normalize(mv->no); + Py_DECREF(mv); + } + } + + /* should we alternatively return a list of changed verts (and preserve + * the original ones) ? */ + Py_RETURN_NONE; +} diff --git a/source/blender/python/api2_2x/NMesh.h b/source/blender/python/api2_2x/NMesh.h new file mode 100644 index 00000000000..13ae12af522 --- /dev/null +++ b/source/blender/python/api2_2x/NMesh.h @@ -0,0 +1,157 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano, Jordi Rovira i Bonnet, Joseph Gilbert. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* Most of this file comes from opy_nmesh.[ch] in the old bpython dir */ + +#ifndef EXPP_NMESH_H +#define EXPP_NMESH_H + +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "DNA_customdata_types.h" +#include "DNA_object_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "Material.h" +#include "Image.h" + +/* EXPP PyType Objects */ +extern PyTypeObject NMesh_Type; +extern PyTypeObject NMFace_Type; +extern PyTypeObject NMVert_Type; +extern PyTypeObject NMCol_Type; +extern PyTypeObject NMEdge_Type; + + +struct BPy_Object; + +/* These are from blender/src/editdeform.c, should be declared elsewhere, + * maybe in BIF_editdeform.h, after proper testing of vgrouping methods XXX */ + +extern void add_vert_defnr( Object * ob, int def_nr, int vertnum, float weight, + int assignmode ); +extern void remove_vert_def_nr( Object * ob, int def_nr, int vertnum ); + + + +/* Type checking for EXPP PyTypes */ +#define BPy_NMesh_Check(v) ((v)->ob_type == &NMesh_Type) +#define BPy_NMFace_Check(v) ((v)->ob_type == &NMFace_Type) +#define BPy_NMVert_Check(v) ((v)->ob_type == &NMVert_Type) +#define BPy_NMCol_Check(v) ((v)->ob_type == &NMCol_Type) +#define BPy_NMEdge_Check(v) ((v)->ob_type == &NMEdge_Type) + +/* Typedefs for the new types */ + +typedef struct { + PyObject_HEAD /* required python macro */ + unsigned char r, g, b, a; + +} BPy_NMCol; /* an NMesh color: [r,g,b,a] */ + +typedef struct { + PyObject_VAR_HEAD /* required python macro */ + float co[3]; + float no[3]; + float uvco[3]; + int index; + char flag; /* see MVert flag in DNA_meshdata_types */ + +} BPy_NMVert; /* an NMesh vertex */ + +typedef struct { + PyObject_HEAD /* required python macro */ + PyObject * v; + PyObject *uv; + PyObject *col; + short mode; + short flag; /* tface->flag */ + unsigned char transp; + Image *image; + char mat_nr, mf_flag /* was char smooth */; + int orig_index; + +} BPy_NMFace; /* an NMesh face */ + +typedef struct { + PyObject_HEAD /* required python macro */ + PyObject *v1; + PyObject *v2; + char crease; + short flag; +} BPy_NMEdge; /* an NMesh edge */ + +typedef struct { + PyObject_HEAD /* required python macro */ + Mesh * mesh; /* libdata must be second */ + Object *object; /* for vertex grouping info, since it's stored on the object */ + PyObject *name; + PyObject *materials; + PyObject *verts; + PyObject *faces; + PyObject *edges; + int sel_face; /*@ XXX remove */ + short smoothresh; /* max AutoSmooth angle */ + short subdiv[2]; /* SubDiv Levels: display and rendering */ + short mode; /* see the EXPP_NMESH_* defines in the beginning of this file */ + char flags; + +#define NMESH_HASMCOL (1<<0) +#define NMESH_HASVERTUV (1<<1) +#define NMESH_HASFACEUV (1<<2) + + /* stores original data that is not accesible through NMesh, but that we + still want to preserve, indexed by orig_index in NMFace */ + CustomData fdata; + int totfdata; + +} BPy_NMesh; + +/* PROTOS */ + +PyObject *NMesh_Init( void ); +PyObject *NMesh_CreatePyObject( Mesh * me, Object * ob ); +Mesh *NMesh_FromPyObject( PyObject * pyobj, Object * ob ); + +void mesh_update( Mesh * mesh , Object * ob ); +PyObject *new_NMesh( Mesh * oldmesh ); +Mesh *Mesh_fromNMesh( BPy_NMesh * nmesh ); +PyObject *NMesh_assignMaterials_toObject( BPy_NMesh * nmesh, Object * ob ); +Material **nmesh_updateMaterials( BPy_NMesh * nmesh ); +Material **newMaterialList_fromPyList( PyObject * list ); + + +#endif /* EXPP_NMESH_H */ diff --git a/source/blender/python/api2_2x/Node.c b/source/blender/python/api2_2x/Node.c new file mode 100644 index 00000000000..296a30dea4e --- /dev/null +++ b/source/blender/python/api2_2x/Node.c @@ -0,0 +1,1213 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2006, Blender Foundation + * All rights reserved. + * + * Original code is this file + * + * Contributor(s): Nathan Letwory + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifdef USE_PYNODES /* note: won't work without patch */ +#include "Node.h" + +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_node.h" + +#include "DNA_material_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "gen_utils.h" + +static PyObject *Node_repr( BPy_Node * self ); +static int Node_compare(BPy_Node *a, BPy_Node *b); +static PyObject *ShadeInput_repr( BPy_ShadeInput * self ); +static int ShadeInput_compare(BPy_ShadeInput *a, BPy_ShadeInput *b); + +/** + * Take the descriptions from dict and create sockets for those in socks + * socks is a socketstack from a bNodeTypeInfo + */ +static int dict_socks_to_typeinfo(PyObject *dict, bNodeSocketType **socks, int len, int stage) { + int a = 0, pos = 0; + PyObject *key = NULL, *value = NULL; + bNodeSocketType *newsocks = NULL; + + if(stage!=SH_NODE_DYNAMIC_READY && stage!=SH_NODE_DYNAMIC_ADDEXIST) { + newsocks = MEM_callocN(sizeof(bNodeSocketType)*(len+1), "bNodeSocketType"); + + if (dict) { + if(PyDict_Check(dict)) { + while(PyDict_Next(dict, &pos, &key, &value)) { + if(PyTuple_Check(value) && PyTuple_Size(value)==7) { + newsocks[a].name = BLI_strdup(PyString_AsString(key)); + newsocks[a].type = (int)(PyInt_AsLong(PyTuple_GetItem(value, 0))); + newsocks[a].val1 = (float)(PyFloat_AsDouble(PyTuple_GetItem(value, 1))); + newsocks[a].val2 = (float)(PyFloat_AsDouble(PyTuple_GetItem(value, 2))); + newsocks[a].val3 = (float)(PyFloat_AsDouble(PyTuple_GetItem(value, 3))); + newsocks[a].val4 = (float)(PyFloat_AsDouble(PyTuple_GetItem(value, 4))); + newsocks[a].min = (float)(PyFloat_AsDouble(PyTuple_GetItem(value, 5))); + newsocks[a].max = (float)(PyFloat_AsDouble(PyTuple_GetItem(value, 6))); + a++; + } + } + } else { + return(EXPP_ReturnIntError( PyExc_AttributeError, "INPUT must be a dict")); + } + } + newsocks[a].type = -1; + if(*socks) { + int b = 0; + while((*socks)[b].type!=-1) { + MEM_freeN((*socks)[b].name); + (*socks)[b].name = NULL; + b++; + } + MEM_freeN(*socks); + } + *socks = newsocks; + } + return 0; +} + +/* Get number of complying entries in a dict. + * + */ +static int num_dict_sockets(PyObject *dict) { + int a = 0, pos = 0; + PyObject *key = NULL, *value = NULL; + while(PyDict_Next(dict, &pos, &key, &value)) { + if(PyTuple_Check(value) && PyTuple_Size(value)==7) + a++; + } + return a; +} + +static int Map_socketdef(PyObject *self, PyObject *args, void *closure) +{ + int newincnt = 0, newoutcnt = 0; + bNode *node = NULL; + BPy_DefinitionMap *defs= NULL; + + Py_INCREF(args); + Py_INCREF(self); + + defs= (BPy_DefinitionMap *)self; + node= defs->node; + + if(!node) { + fprintf(stderr,"! no bNode in BPy_Node (Map_socketdef)\n"); + return 0; + } + + if(node->custom1==SH_NODE_DYNAMIC_READY && node->custom1==SH_NODE_DYNAMIC_ADDEXIST) + return 0; + + switch((int)closure) { + case 'I': + if (args) { + if(PyDict_Check(args)) { + newincnt = num_dict_sockets(args); + dict_socks_to_typeinfo(args, &(node->typeinfo->inputs), newincnt, node->custom1); + } else { + Py_DECREF(self); + Py_DECREF(args); + return(EXPP_ReturnIntError( PyExc_AttributeError, "INPUT must be a dict")); + } + } + break; + case 'O': + if (args) { + if(PyDict_Check(args)) { + newoutcnt = num_dict_sockets(args); + dict_socks_to_typeinfo(args, &(node->typeinfo->outputs), newoutcnt, node->custom1); + } else { + Py_DECREF(self); + Py_DECREF(args); + return(EXPP_ReturnIntError( PyExc_AttributeError, "OUTPUT must be a dict")); + } + } + break; + default: + fprintf(stderr, "Hrm, why we got no dict? Todo: figure out proper complaint to scripter\n"); + break; + } + Py_DECREF(self); + Py_DECREF(args); + return 0; +} + +static PyGetSetDef InputDefMap_getseters[] = { + {"definitions", (getter)NULL, (setter)Map_socketdef, + "Set the inputs definition (dictionary)", + (void *)'I'}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +PyTypeObject InputDefMap_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender.Node.InputDefinitions", /* char *tp_name; */ + sizeof( BPy_DefinitionMap ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL,/* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + NULL, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/input buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + 0, //( getiterfunc) MVertSeq_getIter, /* getiterfunc tp_iter; */ + 0, //( iternextfunc ) MVertSeq_nextIter, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + 0, //BPy_MVertSeq_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + InputDefMap_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +BPy_DefinitionMap *Node_CreateInputDefMap(bNode *node) { + BPy_DefinitionMap *map = PyObject_NEW(BPy_DefinitionMap, &InputDefMap_Type); + map->node = node; + return map; +} + +/***************************************/ + +static PyGetSetDef OutputDefMap_getseters[] = { + {"definitions", (getter)NULL, (setter)Map_socketdef, + "Set the outputs definition (dictionary)", + (void *)'O'}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +PyTypeObject OutputDefMap_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender.Node.OutputDefinitions", /* char *tp_name; */ + sizeof( BPy_DefinitionMap ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL,/* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + NULL, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + 0, //( getiterfunc) MVertSeq_getIter, /* getiterfunc tp_iter; */ + 0, //( iternextfunc ) MVertSeq_nextIter, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + 0, //BPy_MVertSeq_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + OutputDefMap_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +BPy_DefinitionMap *Node_CreateOutputDefMap(bNode *node) { + BPy_DefinitionMap *map = PyObject_NEW(BPy_DefinitionMap, &OutputDefMap_Type); + map->node = node; + return map; +} + +/***************************************/ + +static int sockinmap_len ( BPy_SockMap * self) { + int a = 0; + if(self->typeinfo) { + while(self->typeinfo->inputs[a].type!=-1) + a++; + } + return a; +} + +static int sockinmap_has_key( BPy_SockMap *self, PyObject *key) { + int a = 0; + char *strkey = PyString_AsString(key); + + if(self->typeinfo){ + while(self->typeinfo->inputs[a].type!=-1) { + if(BLI_strcaseeq(self->typeinfo->inputs[a].name, strkey)) { + return a; + } + a++; + } + } + return -1; +} + +PyObject *sockinmap_subscript(BPy_SockMap *self, PyObject *idx) { + int a, _idx; + a = sockinmap_len(self); + + if (PyString_Check(idx)) { + _idx = sockinmap_has_key( self, idx); + } + else if(PyInt_Check(idx)) { + PyErr_SetString(PyExc_ValueError, "int index not implemented"); + Py_RETURN_NONE; + } + else if (PySlice_Check(idx)) { + PyErr_SetString(PyExc_ValueError, "slices not implemented"); + Py_RETURN_NONE; + } else { + PyErr_SetString(PyExc_IndexError, "Index must be string"); + Py_RETURN_NONE; + } + + + switch(self->typeinfo->inputs[_idx].type) { + case SOCK_VALUE: + return Py_BuildValue("f", self->stack[_idx]->vec[0]); + break; + case SOCK_VECTOR: + return Py_BuildValue("(fff)", self->stack[_idx]->vec[0], self->stack[_idx]->vec[1], self->stack[_idx]->vec[2]); + break; + case SOCK_RGBA: + return Py_BuildValue("(ffff)", self->stack[_idx]->vec[0], self->stack[_idx]->vec[1], self->stack[_idx]->vec[2], self->stack[_idx]->vec[3]); + break; + default: + break; + } + Py_RETURN_NONE; +} + +/* read only */ +static PyMappingMethods sockinmap_as_mapping = { + ( inquiry ) sockinmap_len, /* mp_length */ + ( binaryfunc ) sockinmap_subscript, /* mp_subscript */ + ( objobjargproc ) 0 /* mp_ass_subscript */ +}; + +PyTypeObject SockInMap_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender.Node.InputSockets", /* char *tp_name; */ + sizeof( BPy_SockMap ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL,/* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + NULL, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + &sockinmap_as_mapping, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + 0, //( getiterfunc) MVertSeq_getIter, /* getiterfunc tp_iter; */ + 0, //( iternextfunc ) MVertSeq_nextIter, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + 0, //BPy_MVertSeq_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + NULL, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +static int sockoutmap_len ( BPy_SockMap * self) { + int a = 0; + if(self->typeinfo) { + while(self->typeinfo->outputs[a].type!=-1) + a++; + } + return a; +} + +static int sockoutmap_has_key( BPy_SockMap *self, PyObject *key) { + int a = 0; + char *strkey = PyString_AsString(key); + + if(self->typeinfo){ + while(self->typeinfo->outputs[a].type!=-1) { + if(BLI_strcaseeq(self->typeinfo->outputs[a].name, strkey)) { + return a; + } + a++; + } + } + return -1; +} + +static int sockoutmap_assign_subscript(BPy_SockMap *self, PyObject *idx, PyObject *value) { + int a, _idx; + a = sockoutmap_len(self); + if(PyInt_Check(idx)) { + _idx = (int)PyInt_AsLong(idx); + } + else if (PyString_Check(idx)) { + _idx = sockoutmap_has_key( self, idx); + } + else if (PySlice_Check(idx)) { + PyErr_SetString(PyExc_ValueError, "slices not implemented, yet"); + return -1; + } else { + PyErr_SetString(PyExc_IndexError, "Index must be int or string"); + return -1; + } + if(_idx > -1) { + switch(self->typeinfo->outputs[_idx].type) { + case SOCK_VALUE: + if(PyTuple_Size(value)==1) + self->stack[_idx]->vec[0] = (float)PyFloat_AsDouble(PyTuple_GetItem(value, 0)); + return 0; + break; + case SOCK_VECTOR: + if(PyTuple_Size(value)==3) { + self->stack[_idx]->vec[0] = (float)PyFloat_AsDouble(PyTuple_GetItem(value, 0)); + self->stack[_idx]->vec[1] = (float)PyFloat_AsDouble(PyTuple_GetItem(value, 1)); + self->stack[_idx]->vec[2] = (float)PyFloat_AsDouble(PyTuple_GetItem(value, 2)); + } + return 0; + break; + case SOCK_RGBA: + if(PyTuple_Size(value)==4) { + self->stack[_idx]->vec[0] = (float)PyFloat_AsDouble(PyTuple_GetItem(value, 0)); + self->stack[_idx]->vec[1] = (float)PyFloat_AsDouble(PyTuple_GetItem(value, 1)); + self->stack[_idx]->vec[2] = (float)PyFloat_AsDouble(PyTuple_GetItem(value, 2)); + self->stack[_idx]->vec[3] = (float)PyFloat_AsDouble(PyTuple_GetItem(value, 3)); + } + return 0; + break; + default: + break; + } + } + return 0; +} + +/* write only */ +static PyMappingMethods sockoutmap_as_mapping = { + ( inquiry ) sockoutmap_len, /* mp_length */ + ( binaryfunc ) 0, /* mp_subscript */ + ( objobjargproc ) sockoutmap_assign_subscript /* mp_ass_subscript */ +}; + +PyTypeObject SockOutMap_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender.Node.OutputSockets", /* char *tp_name; */ + sizeof( BPy_SockMap ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL,/* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + NULL, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + &sockoutmap_as_mapping, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + 0, //( getiterfunc) MVertSeq_getIter, /* getiterfunc tp_iter; */ + 0, //( iternextfunc ) MVertSeq_nextIter, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + 0, //BPy_MVertSeq_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + NULL, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + + +static BPy_SockMap *Node_CreateInputMap(bNode *node, bNodeStack **stack) { + BPy_SockMap *map= PyObject_NEW(BPy_SockMap, &SockInMap_Type); + map->typeinfo= node->typeinfo; + map->stack= stack; + return map; +} + +static PyObject *Node_GetInputMap(BPy_Node *self) { + BPy_SockMap *inmap= Node_CreateInputMap(self->node, self->in); + return (PyObject *)(inmap); +} + +#define SURFACEVIEWVECTOR 0 +#define VIEWNORMAL 1 +#define SURFACENORMAL 2 +#define GLOBALTEXTURE 3 +#define TEXTURE 4 +#define PIXEL 5 +#define COLOR 6 +#define SPECULAR 7 +#define MIRROR 8 +#define AMBIENT 9 +#define AMBIENTFACTOR 10 +#define EMITFACTOR 11 +#define DISPLACE 12 +#define STRAND 13 +#define STRESS 14 +#define TANGENT 15 +#define SURFACE_D 30 +#define TEXTURE_D 31 +#define GLOBALTEXTURE_D 32 +#define REFLECTION_D 33 +#define NORMAL_D 34 +#define STICKY_D 35 +#define REFRACT_D 36 +#define STRAND_D 37 + +static PyObject *ShadeInput_getAttribute(BPy_ShadeInput *self, void *type) { + PyObject *obj= NULL; + if(self->shi) { + switch((int)type) { + case SURFACEVIEWVECTOR: + obj= Py_BuildValue("(fff)", self->shi->view[0], self->shi->view[1], self->shi->view[2]); + break; + case VIEWNORMAL: + obj= Py_BuildValue("(fff)", self->shi->vn[0], self->shi->vn[1], self->shi->vn[2]); + break; + case SURFACENORMAL: + obj= Py_BuildValue("(fff)", self->shi->facenor[0], self->shi->facenor[1], self->shi->facenor[2]); + break; + case GLOBALTEXTURE: + obj= Py_BuildValue("(fff)", self->shi->gl[0], self->shi->gl[1], self->shi->gl[2]); + break; + case TEXTURE: + obj= Py_BuildValue("(fff)", self->shi->lo[0], self->shi->lo[1], self->shi->lo[2]); + break; + case PIXEL: + obj= Py_BuildValue("(ii)", self->shi->xs, self->shi->ys); + break; + case COLOR: + obj= Py_BuildValue("(fff)", self->shi->r, self->shi->g, self->shi->b); + break; + case SPECULAR: + obj= Py_BuildValue("(fff)", self->shi->specr, self->shi->specg, self->shi->specb); + break; + case MIRROR: + obj= Py_BuildValue("(fff)", self->shi->mirr, self->shi->mirg, self->shi->mirb); + break; + case AMBIENT: + obj= Py_BuildValue("(fff)", self->shi->ambr, self->shi->ambg, self->shi->ambb); + break; + case AMBIENTFACTOR: + obj= PyFloat_FromDouble((double)(self->shi->amb)); + break; + case EMITFACTOR: + obj= PyFloat_FromDouble((double)(self->shi->emit)); + break; + case DISPLACE: + obj= Py_BuildValue("(fff)", self->shi->displace[0], self->shi->displace[1], self->shi->displace[2]); + break; + case STRAND: + obj= PyFloat_FromDouble((double)(self->shi->strand)); + break; + case STRESS: + obj= PyFloat_FromDouble((double)(self->shi->stress)); + break; + case TANGENT: + obj= Py_BuildValue("(fff)", self->shi->tang[0], self->shi->tang[1], self->shi->tang[2]); + break; + case SURFACE_D: + obj= Py_BuildValue("(fff)(fff)", self->shi->dxco[0], self->shi->dxco[1], self->shi->dxco[2], self->shi->dyco[0], self->shi->dyco[1], self->shi->dyco[2]); + break; + case TEXTURE_D: + obj= Py_BuildValue("(fff)(fff)", self->shi->dxlo[0], self->shi->dxlo[1], self->shi->dxlo[2], self->shi->dylo[0], self->shi->dylo[1], self->shi->dylo[2]); + break; + case GLOBALTEXTURE_D: + obj= Py_BuildValue("(fff)(fff)", self->shi->dxgl[0], self->shi->dxgl[1], self->shi->dxgl[2], self->shi->dygl[0], self->shi->dygl[1], self->shi->dygl[2]); + break; + case REFLECTION_D: + obj= Py_BuildValue("(fff)(fff)", self->shi->dxref[0], self->shi->dxref[1], self->shi->dxref[2], self->shi->dyref[0], self->shi->dyref[1], self->shi->dyref[2]); + break; + case NORMAL_D: + obj= Py_BuildValue("(fff)(fff)", self->shi->dxno[0], self->shi->dxno[1], self->shi->dxno[2], self->shi->dyno[0], self->shi->dyno[1], self->shi->dyno[2]); + break; + case STICKY_D: + obj= Py_BuildValue("(fff)(fff)", self->shi->dxsticky[0], self->shi->dxsticky[1], self->shi->dxsticky[2], self->shi->dysticky[0], self->shi->dysticky[1], self->shi->dysticky[2]); + break; + case REFRACT_D: + obj= Py_BuildValue("(fff)(fff)", self->shi->dxrefract[0], self->shi->dxrefract[1], self->shi->dxrefract[2], self->shi->dyrefract[0], self->shi->dyrefract[1], self->shi->dyrefract[2]); + break; + case STRAND_D: + obj= Py_BuildValue("(ff)", self->shi->dxstrand, self->shi->dystrand); + break; + default: + break; + } + } + + if(!obj) { + Py_RETURN_NONE; + } + return obj; +} + +static BPy_SockMap *Node_CreateOutputMap(bNode *node, bNodeStack **stack) { + BPy_SockMap *map = PyObject_NEW(BPy_SockMap, &SockOutMap_Type); + map->typeinfo= node->typeinfo; + map->stack= stack; + return map; +} + +static PyObject *Node_GetOutputMap(BPy_Node *self) { + BPy_SockMap *outmap= Node_CreateOutputMap(self->node, self->out); + return (PyObject *)outmap; +} + +static PyObject *Node_GetShi(BPy_Node *self) { + BPy_ShadeInput *shi= ShadeInput_CreatePyObject(self->shi); + return (PyObject *)shi; + +} + +static PyObject *node_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *self; + assert(type!=NULL && type->tp_alloc!=NULL); + self= type->tp_alloc(type, 1); + return self; +} + +static int node_init(BPy_Node *self, PyObject *args, PyObject *kwds) +{ + return 0; +} + +static PyGetSetDef BPy_Node_getseters[] = { + {"ins", + (getter)Node_GetInputMap, (setter)NULL, + "Get the ShadeInput mapping (dictionary)", + NULL}, + {"outs", + (getter)Node_GetOutputMap, (setter)NULL, + "Get the ShadeInput mapping (dictionary)", + NULL}, + {"shi", + (getter)Node_GetShi, (setter)NULL, + "Get the ShadeInput (ShadeInput)", + NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +static PyGetSetDef BPy_ShadeInput_getseters[] = { + {"texture", + (getter)ShadeInput_getAttribute, (setter)NULL, + "Get the current texture coordinate (tuple)", + (void*)TEXTURE}, + {"texture_global", + (getter)ShadeInput_getAttribute, (setter)NULL, + "Get the current global texture coordinate (tuple)", + (void*)GLOBALTEXTURE}, + {"surface_normal", + (getter)ShadeInput_getAttribute, (setter)NULL, + "Get the current surface normal (tuple)", + (void*)SURFACENORMAL}, + {"view_normal", + (getter)ShadeInput_getAttribute, (setter)NULL, + "Get the current view normal (tuple)", + (void*)VIEWNORMAL}, + {"surface_view_vec", + (getter)ShadeInput_getAttribute, (setter)NULL, + "Get the vector pointing to the viewpoint from the point being shaded (tuple)", + (void*)SURFACEVIEWVECTOR}, + {"pixel", + (getter)ShadeInput_getAttribute, (setter)NULL, + "Get the x,y-coordinate for the pixel rendered (tuple)", + (void*)PIXEL}, + {"color", + (getter)ShadeInput_getAttribute, (setter)NULL, + "Get the color for the point being shaded (tuple)", + (void*)COLOR}, + {"specular", + (getter)ShadeInput_getAttribute, (setter)NULL, + "Get the specular color for the point being shaded (tuple)", + (void*)SPECULAR}, + {"mirror", + (getter)ShadeInput_getAttribute, (setter)NULL, + "Get the mirror color for the point being shaded (tuple)", + (void*)MIRROR}, + {"ambient", + (getter)ShadeInput_getAttribute, (setter)NULL, + "Get the ambient color for the point being shaded (tuple)", + (void*)AMBIENT}, + {"ambient_factor", + (getter)ShadeInput_getAttribute, (setter)NULL, + "Get the ambient factor for the point being shaded (float)", + (void*)AMBIENTFACTOR}, + {"emit_factor", + (getter)ShadeInput_getAttribute, (setter)NULL, + "Get the emit factor for the point being shaded (float)", + (void*)EMITFACTOR}, + {"displace", + (getter)ShadeInput_getAttribute, (setter)NULL, + "Get the displace vector for the point being shaded (tuple)", + (void*)DISPLACE}, + {"strand", + (getter)ShadeInput_getAttribute, (setter)NULL, + "Get the strand factor(float)", + (void*)STRAND}, + {"stress", + (getter)ShadeInput_getAttribute, (setter)NULL, + "Get the stress factor(float)", + (void*)STRESS}, + {"tangent", + (getter)ShadeInput_getAttribute, (setter)NULL, + "Get the tangent vector (tuple)", + (void*)TANGENT}, + {"surface_d", + (getter)ShadeInput_getAttribute, (setter)NULL, + "Get the surface d (tuple of tuples)", + (void*)SURFACE_D}, + {"texture_d", + (getter)ShadeInput_getAttribute, (setter)NULL, + "Get the texture d (tuple of tuples)", + (void*)TEXTURE_D}, + {"texture_global_d", + (getter)ShadeInput_getAttribute, (setter)NULL, + "Get the global texture d (tuple of tuples)", + (void*)GLOBALTEXTURE_D}, + {"reflection_d", + (getter)ShadeInput_getAttribute, (setter)NULL, + "Get the reflection d (tuple of tuples)", + (void*)REFLECTION_D}, + {"normal_d", + (getter)ShadeInput_getAttribute, (setter)NULL, + "Get the normal d (tuple of tuples)", + (void*)NORMAL_D}, + {"sticky_d", + (getter)ShadeInput_getAttribute, (setter)NULL, + "Get the sticky d (tuple of tuples)", + (void*)STICKY_D}, + {"refract_d", + (getter)ShadeInput_getAttribute, (setter)NULL, + "Get the refract d (tuple of tuples)", + (void*)REFRACT_D}, + {"strand_d", + (getter)ShadeInput_getAttribute, (setter)NULL, + "Get the strand d (tuple)", + (void*)REFRACT_D}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +PyTypeObject Node_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender.Node.node", /* char *tp_name; */ + sizeof( BPy_Node ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL,/* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL /*( getattrfunc ) PyObject_GenericGetAttr*/, /* getattrfunc tp_getattr; */ + NULL /*( setattrfunc ) PyObject_GenericSetAttr*/, /* setattrfunc tp_setattr; */ + ( cmpfunc ) Node_compare, /* cmpfunc tp_compare; */ + ( reprfunc ) Node_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + NULL, /*BPy_Node_methods,*/ /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_Node_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + (initproc)node_init, /* initproc tp_init; */ + /*PyType_GenericAlloc*/NULL, /* allocfunc tp_alloc; */ + node_new, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +PyTypeObject ShadeInput_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender.Node.ShadeInput", /* char *tp_name; */ + sizeof( BPy_ShadeInput ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL,/* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) ShadeInput_compare, /* cmpfunc tp_compare; */ + ( reprfunc ) ShadeInput_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + NULL, /*BPy_Node_methods,*/ /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_ShadeInput_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + + +/* Initialise Node module */ +PyObject *Node_Init(void) +{ + PyObject *submodule; + + if( PyType_Ready( &Node_Type ) < 0 ) + return NULL; + if( PyType_Ready( &ShadeInput_Type ) < 0 ) + return NULL; + if( PyType_Ready( &OutputDefMap_Type ) < 0 ) + return NULL; + if( PyType_Ready( &InputDefMap_Type ) < 0 ) + return NULL; + if( PyType_Ready( &SockInMap_Type ) < 0 ) + return NULL; + if( PyType_Ready( &SockOutMap_Type ) < 0 ) + return NULL; + submodule = Py_InitModule3( "Blender.Node", NULL, ""); + + PyModule_AddIntConstant(submodule, "VALUE", SOCK_VALUE); + PyModule_AddIntConstant(submodule, "RGBA", SOCK_RGBA); + PyModule_AddIntConstant(submodule, "VECTOR", SOCK_VECTOR); + + Py_INCREF(&Node_Type); + PyModule_AddObject(submodule, "node", (PyObject *)&Node_Type); + + return submodule; + +} + +static int Node_compare(BPy_Node *a, BPy_Node *b) +{ + bNode *pa = a->node, *pb = b->node; + return (pa==pb) ? 0 : -1; +} + +static PyObject *Node_repr(BPy_Node *self) +{ + return PyString_FromFormat( "[Node \"%s\"]", + self->node ? self->node->id->name+2 : "empty node"); +} + +BPy_Node *Node_CreatePyObject(bNode *node) +{ + BPy_Node *pynode; + + pynode = (BPy_Node *)PyObject_NEW(BPy_Node, &Node_Type); + if(!pynode) { + fprintf(stderr,"Couldn't create BPy_Node object\n"); + return (BPy_Node *)(EXPP_ReturnPyObjError(PyExc_MemoryError, "couldn't create BPy_Node object")); + } + + pynode->node= node; + + return pynode; +} + +void InitNode(BPy_Node *self, bNode *node) { + self->node= node; +} + +bNode *Node_FromPyObject(PyObject *pyobj) +{ + return ((BPy_Node *)pyobj)->node; +} + +void Node_SetStack(BPy_Node *self, bNodeStack **stack, int type) +{ + if(type==NODE_INPUTSTACK) { + self->in= stack; + } else if(type==NODE_OUTPUTSTACK) { + self->out= stack; + } +} + +void Node_SetShi(BPy_Node *self, ShadeInput *shi) +{ + self->shi= shi; +} + +/*********************/ + +static int ShadeInput_compare(BPy_ShadeInput *a, BPy_ShadeInput *b) +{ + ShadeInput *pa = a->shi, *pb = b->shi; + return (pa==pb) ? 0 : -1; +} + +static PyObject *ShadeInput_repr(BPy_ShadeInput *self) +{ + return PyString_FromFormat( "[ShadeInput @ \"%p\"]", self); +} + +BPy_ShadeInput *ShadeInput_CreatePyObject(ShadeInput *shi) +{ + BPy_ShadeInput *pyshi; + + pyshi = (BPy_ShadeInput *)PyObject_NEW(BPy_ShadeInput, &ShadeInput_Type); + if(!pyshi) { + fprintf(stderr,"Couldn't create BPy_ShadeInput object\n"); + return (BPy_ShadeInput *)(EXPP_ReturnPyObjError(PyExc_MemoryError, "couldn't create BPy_ShadeInput object")); + } + + pyshi->shi = shi; + + return pyshi; +} +#endif + diff --git a/source/blender/python/api2_2x/Node.h b/source/blender/python/api2_2x/Node.h new file mode 100644 index 00000000000..f4796d1b80b --- /dev/null +++ b/source/blender/python/api2_2x/Node.h @@ -0,0 +1,91 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2006, Blender Foundation + * All rights reserved. + * + * Original code is this file + * + * Contributor(s): Nathan Letwory + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifdef USE_PYNODES /* note: won't work without patch */ +#ifndef __NODE_H__ +#define __NODE_H__ + +#include +#include "DNA_node_types.h" +#include "BKE_node.h" + +#include "RE_shader_ext.h" /* <- ShadeInput Shaderesult TexResult */ + +extern PyTypeObject Node_Type; +extern PyTypeObject ShadeInput_Type; + +#define BPy_Node_Check(v) \ + ((v)->ob_type == &Node_Type) + +#define BPy_ShadeInput_Check(v) \ + ((v)->ob_type == &ShadeInput_Type) + +typedef struct BPy_ShadeInput { + PyObject_HEAD + ShadeInput *shi; +} BPy_ShadeInput; + +typedef struct { + PyObject_VAR_HEAD + bNodeType *typeinfo; + bNodeStack **stack; +} BPy_SockMap; + +typedef struct { + PyObject_HEAD + bNode *node; +} BPy_DefinitionMap; + +typedef struct BPy_Node { + PyObject_HEAD + bNode *node; + bNodeStack **in; + bNodeStack **out; + ShadeInput *shi; +} BPy_Node; + +extern PyObject *Node_Init(void); +extern void InitNode(BPy_Node *self, bNode *node); +extern BPy_Node *Node_CreatePyObject(bNode *node); +extern BPy_DefinitionMap *Node_CreateOutputDefMap(bNode *node); +extern BPy_DefinitionMap *Node_CreateInputDefMap(bNode *node); +extern void Node_SetStack(BPy_Node *self, bNodeStack **stack, int type); +extern void Node_SetShi(BPy_Node *self, ShadeInput *shi); +extern BPy_ShadeInput *ShadeInput_CreatePyObject(ShadeInput *shi); +extern void Node_dealloc(BPy_Node *self); +extern void ShadeInput_dealloc(BPy_ShadeInput *self); + +#define NODE_INPUTSTACK 0 +#define NODE_OUTPUTSTACK 1 + +#endif /* __NODE_H__*/ +#endif /* USE_PYNODES */ diff --git a/source/blender/python/api2_2x/Noise.c b/source/blender/python/api2_2x/Noise.c new file mode 100644 index 00000000000..c1a41d46714 --- /dev/null +++ b/source/blender/python/api2_2x/Noise.c @@ -0,0 +1,713 @@ +/** + * $Id$ + * + * Blender.Noise BPython module implementation. + * This submodule has functions to generate noise of various types. + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): eeshlo + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +/************************/ +/* Blender Noise Module */ +/************************/ + +#include + +#include "BLI_blenlib.h" +#include "DNA_texture_types.h" +#include "constant.h" + +/*-----------------------------------------*/ +/* 'mersenne twister' random number generator */ + +/* + A C-program for MT19937, with initialization improved 2002/2/10. + Coded by Takuji Nishimura and Makoto Matsumoto. + This is a faster version by taking Shawn Cokus's optimization, + Matthe Bellew's simplification, Isaku Wada's real version. + + Before using, initialize the state by using init_genrand(seed) + or init_by_array(init_key, key_length). + + Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. 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. + + 3. The names of its contributors may not 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. + + + Any feedback is very welcome. + http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html + email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) +*/ + +/* Period parameters */ +#define N 624 +#define M 397 +#define MATRIX_A 0x9908b0dfUL /* constant vector a */ +#define UMASK 0x80000000UL /* most significant w-r bits */ +#define LMASK 0x7fffffffUL /* least significant r bits */ +#define MIXBITS(u,v) ( ((u) & UMASK) | ((v) & LMASK) ) +#define TWIST(u,v) ((MIXBITS(u,v) >> 1) ^ ((v)&1UL ? MATRIX_A : 0UL)) + +static unsigned long state[N]; /* the array for the state vector */ +static int left = 1; +static int initf = 0; +static unsigned long *next; + +PyObject *Noise_Init(void); + +/* initializes state[N] with a seed */ +static void init_genrand( unsigned long s ) +{ + int j; + state[0] = s & 0xffffffffUL; + for( j = 1; j < N; j++ ) { + state[j] = + ( 1812433253UL * + ( state[j - 1] ^ ( state[j - 1] >> 30 ) ) + j ); + /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ + /* In the previous versions, MSBs of the seed affect */ + /* only MSBs of the array state[]. */ + /* 2002/01/09 modified by Makoto Matsumoto */ + state[j] &= 0xffffffffUL; /* for >32 bit machines */ + } + left = 1; + initf = 1; +} + +static void next_state( void ) +{ + unsigned long *p = state; + int j; + + /* if init_genrand() has not been called, */ + /* a default initial seed is used */ + if( initf == 0 ) + init_genrand( 5489UL ); + + left = N; + next = state; + + for( j = N - M + 1; --j; p++ ) + *p = p[M] ^ TWIST( p[0], p[1] ); + + for( j = M; --j; p++ ) + *p = p[M - N] ^ TWIST( p[0], p[1] ); + + *p = p[M - N] ^ TWIST( p[0], state[0] ); +} + +/*------------------------------------------------------------*/ + +static void setRndSeed( int seed ) +{ + if( seed == 0 ) + init_genrand( time( NULL ) ); + else + init_genrand( seed ); +} + +/* float number in range [0, 1) using the mersenne twister rng */ +static float frand( ) +{ + unsigned long y; + + if( --left == 0 ) + next_state( ); + y = *next++; + + /* Tempering */ + y ^= ( y >> 11 ); + y ^= ( y << 7 ) & 0x9d2c5680UL; + y ^= ( y << 15 ) & 0xefc60000UL; + y ^= ( y >> 18 ); + + return ( float ) y / 4294967296.f; +} + +/*------------------------------------------------------------*/ + +/* returns random unit vector */ +static void randuvec( float v[3] ) +{ + float r; + v[2] = 2.f * frand( ) - 1.f; + if( ( r = 1.f - v[2] * v[2] ) > 0.f ) { + float a = (float)(6.283185307f * frand( )); + r = (float)sqrt( r ); + v[0] = (float)(r * cos( a )); + v[1] = (float)(r * sin( a )); + } else + v[2] = 1.f; +} + +static PyObject *Noise_random( PyObject * self ) +{ + return Py_BuildValue( "f", frand( ) ); +} + +static PyObject *Noise_randuvec( PyObject * self ) +{ + float v[3] = {0.0f, 0.0f, 0.0f}; + randuvec( v ); + return Py_BuildValue( "[fff]", v[0], v[1], v[2] ); +} + +/*---------------------------------------------------------------------*/ + +/* Random seed init. Only used for MT random() & randuvec() */ + +static PyObject *Noise_setRandomSeed( PyObject * self, PyObject * args ) +{ + int s; + if( !PyArg_ParseTuple( args, "i", &s ) ) + return NULL; + setRndSeed( s ); + Py_INCREF( Py_None ); + return Py_None; +} + +/*-------------------------------------------------------------------------*/ + +/* General noise */ + +static PyObject *Noise_noise( PyObject * self, PyObject * args ) +{ + float x, y, z; + int nb = 1; + if( !PyArg_ParseTuple( args, "(fff)|i", &x, &y, &z, &nb ) ) + return NULL; + + return PyFloat_FromDouble( + (double)(2.0 * BLI_gNoise( 1.0, x, y, z, 0, nb ) - 1.0) ); +} + +/*-------------------------------------------------------------------------*/ + +/* General Vector noise */ + +static void vNoise( float x, float y, float z, int nb, float v[3] ) +{ + /* Simply evaluate noise at 3 different positions */ + v[0] = (float)(2.0 * BLI_gNoise( 1.f, x + 9.321f, y - 1.531f, z - 7.951f, 0, + nb ) - 1.0); + v[1] = (float)(2.0 * BLI_gNoise( 1.f, x, y, z, 0, nb ) - 1.0); + v[2] = (float)(2.0 * BLI_gNoise( 1.f, x + 6.327f, y + 0.1671f, z - 2.672f, 0, + nb ) - 1.0); +} + +static PyObject *Noise_vNoise( PyObject * self, PyObject * args ) +{ + float x, y, z, v[3]; + int nb = 1; + if( !PyArg_ParseTuple( args, "(fff)|i", &x, &y, &z, &nb ) ) + return NULL; + vNoise( x, y, z, nb, v ); + return Py_BuildValue( "[fff]", v[0], v[1], v[2] ); +} + +/*---------------------------------------------------------------------------*/ + +/* General turbulence */ + +static float turb( float x, float y, float z, int oct, int hard, int nb, + float ampscale, float freqscale ) +{ + float amp, out, t; + int i; + amp = 1.f; + out = (float)(2.0 * BLI_gNoise( 1.f, x, y, z, 0, nb ) - 1.0); + if( hard ) + out = (float)fabs( out ); + for( i = 1; i < oct; i++ ) { + amp *= ampscale; + x *= freqscale; + y *= freqscale; + z *= freqscale; + t = (float)(amp * ( 2.0 * BLI_gNoise( 1.f, x, y, z, 0, nb ) - 1.0 )); + if( hard ) + t = (float)fabs( t ); + out += t; + } + return out; +} + +static PyObject *Noise_turbulence( PyObject * self, PyObject * args ) +{ + float x, y, z; + int oct, hd, nb = 1; + float as = 0.5, fs = 2.0; + if( !PyArg_ParseTuple + ( args, "(fff)ii|iff", &x, &y, &z, &oct, &hd, &nb, &as, &fs ) ) + return NULL; + return PyFloat_FromDouble( (double)turb( x, y, z, oct, hd, nb, as, fs ) ); +} + +/*--------------------------------------------------------------------------*/ + +/* Turbulence Vector */ + +static void vTurb( float x, float y, float z, int oct, int hard, int nb, + float ampscale, float freqscale, float v[3] ) +{ + float amp, t[3]; + int i; + amp = 1.f; + vNoise( x, y, z, nb, v ); + if( hard ) { + v[0] = (float)fabs( v[0] ); + v[1] = (float)fabs( v[1] ); + v[2] = (float)fabs( v[2] ); + } + for( i = 1; i < oct; i++ ) { + amp *= ampscale; + x *= freqscale; + y *= freqscale; + z *= freqscale; + vNoise( x, y, z, nb, t ); + if( hard ) { + t[0] = (float)fabs( t[0] ); + t[1] = (float)fabs( t[1] ); + t[2] = (float)fabs( t[2] ); + } + v[0] += amp * t[0]; + v[1] += amp * t[1]; + v[2] += amp * t[2]; + } +} + +static PyObject *Noise_vTurbulence( PyObject * self, PyObject * args ) +{ + float x, y, z, v[3]; + int oct, hd, nb = 1; + float as = 0.5, fs = 2.0; + if( !PyArg_ParseTuple + ( args, "(fff)ii|iff", &x, &y, &z, &oct, &hd, &nb, &as, &fs ) ) + return NULL; + vTurb( x, y, z, oct, hd, nb, as, fs, v ); + return Py_BuildValue( "[fff]", v[0], v[1], v[2] ); +} + +/*---------------------------------------------------------------------*/ + +/* F. Kenton Musgrave's fractal functions */ + +static PyObject *Noise_fBm( PyObject * self, PyObject * args ) +{ + float x, y, z, H, lac, oct; + int nb = 1; + if( !PyArg_ParseTuple + ( args, "(fff)fff|i", &x, &y, &z, &H, &lac, &oct, &nb ) ) + return NULL; + return PyFloat_FromDouble( (double)mg_fBm( x, y, z, H, lac, oct, nb ) ); +} + +/*------------------------------------------------------------------------*/ + +static PyObject *Noise_multiFractal( PyObject * self, PyObject * args ) +{ + float x, y, z, H, lac, oct; + int nb = 1; + if( !PyArg_ParseTuple + ( args, "(fff)fff|i", &x, &y, &z, &H, &lac, &oct, &nb ) ) + return NULL; + return PyFloat_FromDouble( (double)mg_MultiFractal( x, y, z, H, lac, oct, nb ) ); +} + +/*------------------------------------------------------------------------*/ + +static PyObject *Noise_vlNoise( PyObject * self, PyObject * args ) +{ + float x, y, z, d; + int nt1 = 1, nt2 = 1; + if( !PyArg_ParseTuple + ( args, "(fff)f|ii", &x, &y, &z, &d, &nt1, &nt2 ) ) + return NULL; + return PyFloat_FromDouble( (double)mg_VLNoise( x, y, z, d, nt1, nt2 ) ); +} + +/*-------------------------------------------------------------------------*/ + +static PyObject *Noise_heteroTerrain( PyObject * self, PyObject * args ) +{ + float x, y, z, H, lac, oct, ofs; + int nb = 1; + if( !PyArg_ParseTuple + ( args, "(fff)ffff|i", &x, &y, &z, &H, &lac, &oct, &ofs, &nb ) ) + return NULL; + + return PyFloat_FromDouble( + (double)mg_HeteroTerrain( x, y, z, H, lac, oct, ofs, nb ) ); +} + +/*-------------------------------------------------------------------------*/ + +static PyObject *Noise_hybridMFractal( PyObject * self, PyObject * args ) +{ + float x, y, z, H, lac, oct, ofs, gn; + int nb = 1; + if( !PyArg_ParseTuple + ( args, "(fff)fffff|i", &x, &y, &z, &H, &lac, &oct, &ofs, &gn, + &nb ) ) + return NULL; + + return PyFloat_FromDouble( + (double)mg_HybridMultiFractal( x, y, z, H, lac, oct, ofs, gn, nb) ); +} + +/*------------------------------------------------------------------------*/ + +static PyObject *Noise_ridgedMFractal( PyObject * self, PyObject * args ) +{ + float x, y, z, H, lac, oct, ofs, gn; + int nb = 1; + if( !PyArg_ParseTuple + ( args, "(fff)fffff|i", &x, &y, &z, &H, &lac, &oct, &ofs, &gn, + &nb ) ) + return NULL; + return PyFloat_FromDouble( + (double)mg_RidgedMultiFractal( x, y, z, H, lac, oct, ofs, gn, nb) ); +} + +/*-------------------------------------------------------------------------*/ + +static PyObject *Noise_voronoi( PyObject * self, PyObject * args ) +{ + float x, y, z, da[4], pa[12]; + int dtype = 0; + float me = 2.5; /* default minkovsky exponent */ + if( !PyArg_ParseTuple( args, "(fff)|if", &x, &y, &z, &dtype, &me ) ) + return NULL; + voronoi( x, y, z, da, pa, me, dtype ); + return Py_BuildValue( "[[ffff][[fff][fff][fff][fff]]]", + da[0], da[1], da[2], da[3], + pa[0], pa[1], pa[2], + pa[3], pa[4], pa[5], + pa[6], pa[7], pa[8], pa[9], pa[10], pa[11] ); +} + +/*-------------------------------------------------------------------------*/ + +static PyObject *Noise_cellNoise( PyObject * self, PyObject * args ) +{ + float x, y, z; + if( !PyArg_ParseTuple( args, "(fff)", &x, &y, &z ) ) + return NULL; + return Py_BuildValue( "f", cellNoise( x, y, z ) ); +} + +/*--------------------------------------------------------------------------*/ + +static PyObject *Noise_cellNoiseV( PyObject * self, PyObject * args ) +{ + float x, y, z, ca[3]; + if( !PyArg_ParseTuple( args, "(fff)", &x, &y, &z ) ) + return NULL; + cellNoiseV( x, y, z, ca ); + return Py_BuildValue( "[fff]", ca[0], ca[1], ca[2] ); +} + +/*--------------------------------------------------------------------------*/ +/* For all other Blender modules, this stuff seems to be put in a header file. + This doesn't seem really appropriate to me, so I just put it here, feel free to change it. + In the original module I actually kept the docs stings with the functions themselves, + but I grouped them here so that it can easily be moved to a header if anyone thinks that is necessary. */ + +static char random__doc__[] = "() No arguments.\n\n\ +Returns a random floating point number in the range [0, 1)"; + +static char randuvec__doc__[] = + "() No arguments.\n\nReturns a random unit vector (3-float list)."; + +static char setRandomSeed__doc__[] = "(seed value)\n\n\ +Initializes random number generator.\n\ +if seed is zero, the current time will be used instead."; + +static char noise__doc__[] = "((x,y,z) tuple, [noisetype])\n\n\ +Returns general noise of the optional specified type.\n\ +Optional argument noisetype determines the type of noise, STDPERLIN by default, see NoiseTypes."; + +static char vNoise__doc__[] = "((x,y,z) tuple, [noisetype])\n\n\ +Returns noise vector (3-float list) of the optional specified type.\ +Optional argument noisetype determines the type of noise, STDPERLIN by default, see NoiseTypes."; + +static char turbulence__doc__[] = + "((x,y,z) tuple, octaves, hard, [noisebasis], [ampscale], [freqscale])\n\n\ +Returns general turbulence value using the optional specified noisebasis function.\n\ +octaves (integer) is the number of noise values added.\n\ +hard (bool), when false (0) returns 'soft' noise, when true (1) returns 'hard' noise (returned value always positive).\n\ +Optional arguments:\n\ +noisebasis determines the type of noise used for the turbulence, STDPERLIN by default, see NoiseTypes.\n\ +ampscale sets the amplitude scale value of the noise frequencies added, 0.5 by default.\n\ +freqscale sets the frequency scale factor, 2.0 by default."; + +static char vTurbulence__doc__[] = + "((x,y,z) tuple, octaves, hard, [noisebasis], [ampscale], [freqscale])\n\n\ +Returns general turbulence vector (3-float list) using the optional specified noisebasis function.\n\ +octaves (integer) is the number of noise values added.\n\ +hard (bool), when false (0) returns 'soft' noise, when true (1) returns 'hard' noise (returned vector always positive).\n\ +Optional arguments:\n\ +noisebasis determines the type of noise used for the turbulence, STDPERLIN by default, see NoiseTypes.\n\ +ampscale sets the amplitude scale value of the noise frequencies added, 0.5 by default.\n\ +freqscale sets the frequency scale factor, 2.0 by default."; + +static char fBm__doc__[] = + "((x,y,z) tuple, H, lacunarity, octaves, [noisebasis])\n\n\ +Returns Fractal Brownian Motion noise value(fBm).\n\ +H is the fractal increment parameter.\n\ +lacunarity is the gap between successive frequencies.\n\ +octaves is the number of frequencies in the fBm.\n\ +Optional argument noisebasis determines the type of noise used for the turbulence, STDPERLIN by default, see NoiseTypes."; + +static char multiFractal__doc__[] = + "((x,y,z) tuple, H, lacunarity, octaves, [noisebasis])\n\n\ +Returns Multifractal noise value.\n\ +H determines the highest fractal dimension.\n\ +lacunarity is gap between successive frequencies.\n\ +octaves is the number of frequencies in the fBm.\n\ +Optional argument noisebasis determines the type of noise used for the turbulence, STDPERLIN by default, see NoiseTypes."; + +static char vlNoise__doc__[] = + "((x,y,z) tuple, distortion, [noisetype1], [noisetype2])\n\n\ +Returns Variable Lacunarity Noise value, a distorted variety of noise.\n\ +distortion sets the amount of distortion.\n\ +Optional arguments noisetype1 and noisetype2 set the noisetype to distort and the noisetype used for the distortion respectively.\n\ +See NoiseTypes, both are STDPERLIN by default."; + +static char heteroTerrain__doc__[] = + "((x,y,z) tuple, H, lacunarity, octaves, offset, [noisebasis])\n\n\ +returns Heterogeneous Terrain value\n\ +H determines the fractal dimension of the roughest areas.\n\ +lacunarity is the gap between successive frequencies.\n\ +octaves is the number of frequencies in the fBm.\n\ +offset raises the terrain from 'sea level'.\n\ +Optional argument noisebasis determines the type of noise used for the turbulence, STDPERLIN by default, see NoiseTypes."; + +static char hybridMFractal__doc__[] = + "((x,y,z) tuple, H, lacunarity, octaves, offset, gain, [noisebasis])\n\n\ +returns Hybrid Multifractal value.\n\ +H determines the fractal dimension of the roughest areas.\n\ +lacunarity is the gap between successive frequencies.\n\ +octaves is the number of frequencies in the fBm.\n\ +offset raises the terrain from 'sea level'.\n\ +gain scales the values.\n\ +Optional argument noisebasis determines the type of noise used for the turbulence, STDPERLIN by default, see NoiseTypes."; + +static char ridgedMFractal__doc__[] = + "((x,y,z) tuple, H, lacunarity, octaves, offset, gain [noisebasis])\n\n\ +returns Ridged Multifractal value.\n\ +H determines the fractal dimension of the roughest areas.\n\ +lacunarity is the gap between successive frequencies.\n\ +octaves is the number of frequencies in the fBm.\n\ +offset raises the terrain from 'sea level'.\n\ +gain scales the values.\n\ +Optional argument noisebasis determines the type of noise used for the turbulence, STDPERLIN by default, see NoiseTypes."; + +static char voronoi__doc__[] = + "((x,y,z) tuple, distance_metric, [exponent])\n\n\ +returns a list, containing a list of distances in order of closest feature,\n\ +and a list containing the positions of the four closest features\n\ +Optional arguments:\n\ +distance_metric: see DistanceMetrics, default is DISTANCE\n\ +exponent is only used with MINKOVSKY, default is 2.5."; + +static char cellNoise__doc__[] = "((x,y,z) tuple)\n\n\ +returns cellnoise float value."; + +static char cellNoiseV__doc__[] = "((x,y,z) tuple)\n\n\ +returns cellnoise vector/point/color (3-float list)."; + +static char Noise__doc__[] = "Blender Noise and Turbulence Module\n\n\ +This module can be used to generate noise of various types.\n\ +This can be used for terrain generation, to create textures,\n\ +make animations more 'animated', object deformation, etc.\n\ +As an example, this code segment when scriptlinked to a framechanged event,\n\ +will make the camera sway randomly about, by changing parameters this can\n\ +look like anything from an earthquake to a very nervous or maybe even drunk cameraman...\n\ +(the camera needs an ipo with at least one Loc & Rot key for this to work!):\n\ +\n\ +\tfrom Blender import Get, Scene, Noise\n\ +\n\ +\t####################################################\n\ +\t# This controls jitter speed\n\ +\tsl = 0.025\n\ +\t# This controls the amount of position jitter\n\ +\tsp = 0.1\n\ +\t# This controls the amount of rotation jitter\n\ +\tsr = 0.25\n\ +\t####################################################\n\ +\n\ +\ttime = Get('curtime')\n\ +\tob = Scene.GetCurrent().getCurrentCamera()\n\ +\tps = (sl*time, sl*time, sl*time)\n\ +\t# To add jitter only when the camera moves, use this next line instead\n\ +\t#ps = (sl*ob.LocX, sl*ob.LocY, sl*ob.LocZ)\n\ +\trv = Noise.vTurbulence(ps, 3, 0, Noise.NoiseTypes.NEWPERLIN)\n\ +\tob.dloc = (sp*rv[0], sp*rv[1], sp*rv[2])\n\ +\tob.drot = (sr*rv[0], sr*rv[1], sr*rv[2])\n\ +\n"; + +/* Just in case, declarations for a header file */ +/* +static PyObject *Noise_random(PyObject *self); +static PyObject *Noise_randuvec(PyObject *self); +static PyObject *Noise_setRandomSeed(PyObject *self, PyObject *args); +static PyObject *Noise_noise(PyObject *self, PyObject *args); +static PyObject *Noise_vNoise(PyObject *self, PyObject *args); +static PyObject *Noise_turbulence(PyObject *self, PyObject *args); +static PyObject *Noise_vTurbulence(PyObject *self, PyObject *args); +static PyObject *Noise_fBm(PyObject *self, PyObject *args); +static PyObject *Noise_multiFractal(PyObject *self, PyObject *args); +static PyObject *Noise_vlNoise(PyObject *self, PyObject *args); +static PyObject *Noise_heteroTerrain(PyObject *self, PyObject *args); +static PyObject *Noise_hybridMFractal(PyObject *self, PyObject *args); +static PyObject *Noise_ridgedMFractal(PyObject *self, PyObject *args); +static PyObject *Noise_voronoi(PyObject *self, PyObject *args); +static PyObject *Noise_cellNoise(PyObject *self, PyObject *args); +static PyObject *Noise_cellNoiseV(PyObject *self, PyObject *args); +*/ + +static PyMethodDef NoiseMethods[] = { + {"setRandomSeed", ( PyCFunction ) Noise_setRandomSeed, METH_VARARGS, + setRandomSeed__doc__}, + {"random", ( PyCFunction ) Noise_random, METH_NOARGS, random__doc__}, + {"randuvec", ( PyCFunction ) Noise_randuvec, METH_NOARGS, + randuvec__doc__}, + {"noise", ( PyCFunction ) Noise_noise, METH_VARARGS, noise__doc__}, + {"vNoise", ( PyCFunction ) Noise_vNoise, METH_VARARGS, vNoise__doc__}, + {"turbulence", ( PyCFunction ) Noise_turbulence, METH_VARARGS, + turbulence__doc__}, + {"vTurbulence", ( PyCFunction ) Noise_vTurbulence, METH_VARARGS, + vTurbulence__doc__}, + {"fBm", ( PyCFunction ) Noise_fBm, METH_VARARGS, fBm__doc__}, + {"multiFractal", ( PyCFunction ) Noise_multiFractal, METH_VARARGS, + multiFractal__doc__}, + {"vlNoise", ( PyCFunction ) Noise_vlNoise, METH_VARARGS, + vlNoise__doc__}, + {"heteroTerrain", ( PyCFunction ) Noise_heteroTerrain, METH_VARARGS, + heteroTerrain__doc__}, + {"hybridMFractal", ( PyCFunction ) Noise_hybridMFractal, METH_VARARGS, + hybridMFractal__doc__}, + {"ridgedMFractal", ( PyCFunction ) Noise_ridgedMFractal, METH_VARARGS, + ridgedMFractal__doc__}, + {"voronoi", ( PyCFunction ) Noise_voronoi, METH_VARARGS, + voronoi__doc__}, + {"cellNoise", ( PyCFunction ) Noise_cellNoise, METH_VARARGS, + cellNoise__doc__}, + {"cellNoiseV", ( PyCFunction ) Noise_cellNoiseV, METH_VARARGS, + cellNoiseV__doc__}, + {NULL, NULL, 0, NULL} +}; + +/*----------------------------------------------------------------------*/ + +PyObject *Noise_Init(void) +{ + PyObject *NoiseTypes, *DistanceMetrics, + *md = + Py_InitModule3( "Blender.Noise", NoiseMethods, Noise__doc__ ); + + /* use current time as seed for random number generator by default */ + setRndSeed( 0 ); + + /* Constant noisetype dictionary */ + NoiseTypes = PyConstant_New( ); + if( NoiseTypes ) { + BPy_constant *nt = ( BPy_constant * ) NoiseTypes; + PyConstant_Insert( nt, "BLENDER", + PyInt_FromLong( TEX_BLENDER ) ); + PyConstant_Insert( nt, "STDPERLIN", + PyInt_FromLong( TEX_STDPERLIN ) ); + PyConstant_Insert( nt, "NEWPERLIN", + PyInt_FromLong( TEX_NEWPERLIN ) ); + PyConstant_Insert( nt, "VORONOI_F1", + PyInt_FromLong( TEX_VORONOI_F1 ) ); + PyConstant_Insert( nt, "VORONOI_F2", + PyInt_FromLong( TEX_VORONOI_F2 ) ); + PyConstant_Insert( nt, "VORONOI_F3", + PyInt_FromLong( TEX_VORONOI_F3 ) ); + PyConstant_Insert( nt, "VORONOI_F4", + PyInt_FromLong( TEX_VORONOI_F4 ) ); + PyConstant_Insert( nt, "VORONOI_F2F1", + PyInt_FromLong( TEX_VORONOI_F2F1 ) ); + PyConstant_Insert( nt, "VORONOI_CRACKLE", + PyInt_FromLong( TEX_VORONOI_CRACKLE ) ); + PyConstant_Insert( nt, "CELLNOISE", + PyInt_FromLong( TEX_CELLNOISE ) ); + PyModule_AddObject( md, "NoiseTypes", NoiseTypes ); + } + + /* Constant distance metric dictionary for voronoi */ + DistanceMetrics = PyConstant_New( ); + if( DistanceMetrics ) { + BPy_constant *dm = ( BPy_constant * ) DistanceMetrics; + PyConstant_Insert( dm, "DISTANCE", + PyInt_FromLong( TEX_DISTANCE ) ); + PyConstant_Insert( dm, "DISTANCE_SQUARED", + PyInt_FromLong( TEX_DISTANCE_SQUARED ) ); + PyConstant_Insert( dm, "MANHATTAN", + PyInt_FromLong( TEX_MANHATTAN ) ); + PyConstant_Insert( dm, "CHEBYCHEV", + PyInt_FromLong( TEX_CHEBYCHEV ) ); + PyConstant_Insert( dm, "MINKOVSKY_HALF", + PyInt_FromLong( TEX_MINKOVSKY_HALF ) ); + PyConstant_Insert( dm, "MINKOVSKY_FOUR", + PyInt_FromLong( TEX_MINKOVSKY_FOUR ) ); + PyConstant_Insert( dm, "MINKOVSKY", + PyInt_FromLong( TEX_MINKOVSKY ) ); + PyModule_AddObject( md, "DistanceMetrics", DistanceMetrics ); + } + + return md; +} diff --git a/source/blender/python/api2_2x/Object.c b/source/blender/python/api2_2x/Object.c new file mode 100644 index 00000000000..e62f685cdf5 --- /dev/null +++ b/source/blender/python/api2_2x/Object.c @@ -0,0 +1,5942 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * + * The Object module provides generic access to Objects of various types via + * the Python interface. + * + * + * Contributor(s): Michel Selten, Willian Germano, Jacques Guignot, + * Joseph Gilbert, Stephen Swaney, Bala Gi, Campbell Barton, Johnny Matthews, + * Ken Hughes, Alex Mole, Jean-Michel Soler + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +struct SpaceIpo; +struct rctf; + +#include "Object.h" /*This must come first */ + +#include "DNA_object_types.h" +#include "DNA_view3d_types.h" +#include "DNA_object_force.h" +#include "DNA_userdef_types.h" +#include "DNA_key_types.h" /* for pinShape and activeShape */ + +#include "BKE_action.h" +#include "BKE_anim.h" /* used for dupli-objects */ +#include "BKE_depsgraph.h" +#include "BKE_effect.h" +#include "BKE_font.h" +#include "BKE_property.h" +#include "BKE_mball.h" +#include "BKE_softbody.h" +#include "BKE_utildefines.h" +#include "BKE_armature.h" +#include "BKE_lattice.h" +#include "BKE_mesh.h" +#include "BKE_library.h" +#include "BKE_object.h" +#include "BKE_curve.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_scene.h" +#include "BKE_nla.h" +#include "BKE_material.h" +#include "BKE_modifier.h" +#include "BKE_idprop.h" +#include "BKE_object.h" +#include "BKE_key.h" /* for setting the activeShape */ +#include "BKE_displist.h" + +#include "BSE_editipo.h" +#include "BSE_edit.h" + +#include "BIF_space.h" +#include "BIF_editview.h" +#include "BIF_drawscene.h" +#include "BIF_meshtools.h" +#include "BIF_editarmature.h" +#include "BIF_editaction.h" +#include "BIF_editnla.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" + +#include "BDR_editobject.h" +#include "BDR_editcurve.h" +#include "BDR_drawobject.h" + +#include "MEM_guardedalloc.h" + +#include "mydevice.h" +#include "blendef.h" +#include "Scene.h" +#include "Mathutils.h" +#include "Mesh.h" +#include "NMesh.h" +#include "Curve.h" +#include "Ipo.h" +#include "Armature.h" +#include "Pose.h" +#include "Camera.h" +#include "Lamp.h" +#include "Lattice.h" +#include "Text.h" +#include "Text3d.h" +#include "Metaball.h" +#include "Draw.h" +#include "NLA.h" +#include "logic.h" +#include "Effect.h" +#include "Group.h" +#include "Modifier.h" +#include "Constraint.h" +#include "gen_utils.h" +#include "gen_library.h" +#include "EXPP_interface.h" +#include "BIF_editkey.h" +#include "IDProp.h" + +/* Defines for insertIpoKey */ + +#define IPOKEY_LOC 0 +#define IPOKEY_ROT 1 +#define IPOKEY_SIZE 2 +#define IPOKEY_LOCROT 3 +#define IPOKEY_LOCROTSIZE 4 +#define IPOKEY_PI_STRENGTH 5 +#define IPOKEY_PI_FALLOFF 6 +#define IPOKEY_PI_MAXDIST 7 /*Not Ready Yet*/ +#define IPOKEY_PI_SURFACEDAMP 8 +#define IPOKEY_PI_RANDOMDAMP 9 +#define IPOKEY_PI_PERM 10 + +#define PFIELD_FORCE 1 +#define PFIELD_VORTEX 2 +#define PFIELD_MAGNET 3 +#define PFIELD_WIND 4 + +enum obj_consts { + EXPP_OBJ_ATTR_LOC_X = 0, + EXPP_OBJ_ATTR_LOC_Y, + EXPP_OBJ_ATTR_LOC_Z, + EXPP_OBJ_ATTR_DLOC_X, + EXPP_OBJ_ATTR_DLOC_Y, + EXPP_OBJ_ATTR_DLOC_Z, + EXPP_OBJ_ATTR_ROT_X, + EXPP_OBJ_ATTR_ROT_Y, + EXPP_OBJ_ATTR_ROT_Z, + EXPP_OBJ_ATTR_DROT_X, + EXPP_OBJ_ATTR_DROT_Y, + EXPP_OBJ_ATTR_DROT_Z, + EXPP_OBJ_ATTR_SIZE_X, + EXPP_OBJ_ATTR_SIZE_Y, + EXPP_OBJ_ATTR_SIZE_Z, + EXPP_OBJ_ATTR_DSIZE_X, + EXPP_OBJ_ATTR_DSIZE_Y, + EXPP_OBJ_ATTR_DSIZE_Z, + EXPP_OBJ_ATTR_LOC, + EXPP_OBJ_ATTR_DLOC, + EXPP_OBJ_ATTR_DROT, + EXPP_OBJ_ATTR_SIZE, + EXPP_OBJ_ATTR_DSIZE, + EXPP_OBJ_ATTR_LAYERMASK, + EXPP_OBJ_ATTR_COLBITS, + EXPP_OBJ_ATTR_DRAWMODE, + EXPP_OBJ_ATTR_DRAWTYPE, + EXPP_OBJ_ATTR_DUPON, + EXPP_OBJ_ATTR_DUPOFF, + EXPP_OBJ_ATTR_DUPSTA, + EXPP_OBJ_ATTR_DUPEND, + EXPP_OBJ_ATTR_TIMEOFFSET, + EXPP_OBJ_ATTR_DRAWSIZE, + EXPP_OBJ_ATTR_PARENT_TYPE, + EXPP_OBJ_ATTR_PASSINDEX, + EXPP_OBJ_ATTR_ACT_MATERIAL, + EXPP_OBJ_ATTR_ACT_SHAPE, + + EXPP_OBJ_ATTR_PI_SURFACEDAMP, /* these need to stay together */ + EXPP_OBJ_ATTR_PI_RANDOMDAMP, /* and in order */ + EXPP_OBJ_ATTR_PI_PERM, + EXPP_OBJ_ATTR_PI_STRENGTH, + EXPP_OBJ_ATTR_PI_FALLOFF, + EXPP_OBJ_ATTR_PI_MAXDIST, + EXPP_OBJ_ATTR_PI_SBDAMP, + EXPP_OBJ_ATTR_PI_SBIFACETHICK, + EXPP_OBJ_ATTR_PI_SBOFACETHICK, + + EXPP_OBJ_ATTR_SB_NODEMASS, /* these need to stay together */ + EXPP_OBJ_ATTR_SB_GRAV, /* and in order */ + EXPP_OBJ_ATTR_SB_MEDIAFRICT, + EXPP_OBJ_ATTR_SB_RKLIMIT, + EXPP_OBJ_ATTR_SB_PHYSICSSPEED, + EXPP_OBJ_ATTR_SB_GOALSPRING, + EXPP_OBJ_ATTR_SB_GOALFRICT, + EXPP_OBJ_ATTR_SB_MINGOAL, + EXPP_OBJ_ATTR_SB_MAXGOAL, + EXPP_OBJ_ATTR_SB_DEFGOAL, + EXPP_OBJ_ATTR_SB_INSPRING, + EXPP_OBJ_ATTR_SB_INFRICT, + +}; + +#define EXPP_OBJECT_DRAWSIZEMIN 0.01f +#define EXPP_OBJECT_DRAWSIZEMAX 10.0f + +/* clamping and range values for particle interaction settings */ +#define EXPP_OBJECT_PIDAMP_MIN 0.0f +#define EXPP_OBJECT_PIDAMP_MAX 1.0f +#define EXPP_OBJECT_PIRDAMP_MIN 0.0f +#define EXPP_OBJECT_PIRDAMP_MAX 1.0f +#define EXPP_OBJECT_PIPERM_MIN 0.0f +#define EXPP_OBJECT_PIPERM_MAX 1.0f +#define EXPP_OBJECT_PISTRENGTH_MIN 0.0f +#define EXPP_OBJECT_PISTRENGTH_MAX 1000.0f +#define EXPP_OBJECT_PIPOWER_MIN 0.0f +#define EXPP_OBJECT_PIPOWER_MAX 10.0f +#define EXPP_OBJECT_PIMAXDIST_MIN 0.0f +#define EXPP_OBJECT_PIMAXDIST_MAX 1000.0f +#define EXPP_OBJECT_PISBDAMP_MIN 0.0f +#define EXPP_OBJECT_PISBDAMP_MAX 1.0f +#define EXPP_OBJECT_PISBIFTMIN 0.001f +#define EXPP_OBJECT_PISBIFTMAX 1.0f +#define EXPP_OBJECT_PISBOFTMIN 0.001f +#define EXPP_OBJECT_PISBOFTMAX 1.0f + +/* clamping and range values for softbody settings */ +#define EXPP_OBJECT_SBMASS_MIN 0.0f +#define EXPP_OBJECT_SBMASS_MAX 50.0f +#define EXPP_OBJECT_SBGRAVITY_MIN 0.0f +#define EXPP_OBJECT_SBGRAVITY_MAX 10.0f +#define EXPP_OBJECT_SBFRICTION_MIN 0.0f +#define EXPP_OBJECT_SBFRICTION_MAX 10.0f +#define EXPP_OBJECT_SBSPEED_MIN 0.01f +#define EXPP_OBJECT_SBSPEED_MAX 100.0f +#define EXPP_OBJECT_SBERRORLIMIT_MIN 0.01f +#define EXPP_OBJECT_SBERRORLIMIT_MAX 1.0f +#define EXPP_OBJECT_SBGOALSPRING_MIN 0.0f +#define EXPP_OBJECT_SBGOALSPRING_MAX 0.999f +#define EXPP_OBJECT_SBGOALFRICT_MIN 0.0f +#define EXPP_OBJECT_SBGOALFRICT_MAX 10.0f +#define EXPP_OBJECT_SBMINGOAL_MIN 0.0f +#define EXPP_OBJECT_SBMINGOAL_MAX 1.0f +#define EXPP_OBJECT_SBMAXGOAL_MIN 0.0f +#define EXPP_OBJECT_SBMAXGOAL_MAX 1.0f +#define EXPP_OBJECT_SBINSPRING_MIN 0.0f +#define EXPP_OBJECT_SBINSPRING_MAX 0.999f +#define EXPP_OBJECT_SBINFRICT_MIN 0.0f +#define EXPP_OBJECT_SBINFRICT_MAX 10.0f +#define EXPP_OBJECT_SBDEFGOAL_MIN 0.0f +#define EXPP_OBJECT_SBDEFGOAL_MAX 1.0f +#define EXPP_OBJECT_SBNODEMASSMIN 0.001f +#define EXPP_OBJECT_SBNODEMASSMAX 50.0f +#define EXPP_OBJECT_SBGRAVMIN 0.0f +#define EXPP_OBJECT_SBGRAVMAX 10.0f +#define EXPP_OBJECT_SBMEDIAFRICTMIN 0.0f +#define EXPP_OBJECT_SBMEDIAFRICTMAX 10.0f +#define EXPP_OBJECT_SBRKLIMITMIN 0.01f +#define EXPP_OBJECT_SBRKLIMITMAX 1.0f +#define EXPP_OBJECT_SBPHYSICSSPEEDMIN 0.01f +#define EXPP_OBJECT_SBPHYSICSSPEEDMAX 100.0f +#define EXPP_OBJECT_SBGOALSPRINGMIN 0.0f +#define EXPP_OBJECT_SBGOALSPRINGMAX 0.999f +#define EXPP_OBJECT_SBGOALFRICTMIN 0.0f +#define EXPP_OBJECT_SBGOALFRICTMAX 10.0f +#define EXPP_OBJECT_SBMINGOALMIN 0.0f +#define EXPP_OBJECT_SBMINGOALMAX 1.0f +#define EXPP_OBJECT_SBMAXGOALMIN 0.0f +#define EXPP_OBJECT_SBMAXGOALMAX 1.0f +#define EXPP_OBJECT_SBDEFGOALMIN 0.0f +#define EXPP_OBJECT_SBDEFGOALMAX 1.0f +#define EXPP_OBJECT_SBINSPRINGMIN 0.0f +#define EXPP_OBJECT_SBINSPRINGMAX 0.999f +#define EXPP_OBJECT_SBINFRICTMIN 0.0f +#define EXPP_OBJECT_SBINFRICTMAX 10.0f + +/*****************************************************************************/ +/* Python API function prototypes for the Blender module. */ +/*****************************************************************************/ +static PyObject *M_Object_New( PyObject * self, PyObject * args ); +PyObject *M_Object_Get( PyObject * self, PyObject * args ); +static PyObject *M_Object_GetSelected( PyObject * self ); +static PyObject *M_Object_Duplicate( PyObject * self, PyObject * args, PyObject *kwd); + +/* HELPER FUNCTION FOR PARENTING */ +static PyObject *internal_makeParent(Object *parent, PyObject *py_child, int partype, int noninverse, int fast, int v1, int v2, int v3, char *bonename); + +/*****************************************************************************/ +/* The following string definitions are used for documentation strings. */ +/* In Python these will be written to the console when doing a */ +/* Blender.Object.__doc__ */ +/*****************************************************************************/ +char M_Object_doc[] = "The Blender Object module\n\n\ +This module provides access to **Object Data** in Blender.\n"; + +char M_Object_New_doc[] = + "(type) - Add a new object of type 'type' in the current scene"; + +char M_Object_Get_doc[] = + "(name) - return the object with the name 'name', returns None if not\ + found.\n\ + If 'name' is not specified, it returns a list of all objects in the\n\ + current scene."; + +char M_Object_GetSelected_doc[] = + "() - Returns a list of selected Objects in the active layer(s)\n\ +The active object is the first in the list, if visible"; + +char M_Object_Duplicate_doc[] = + "(linked) - Duplicate all selected, visible objects in the current scene"; + + +/*****************************************************************************/ +/* Python method structure definition for Blender.Object module: */ +/*****************************************************************************/ +struct PyMethodDef M_Object_methods[] = { + {"New", ( PyCFunction ) M_Object_New, METH_VARARGS, + M_Object_New_doc}, + {"Get", ( PyCFunction ) M_Object_Get, METH_VARARGS, + M_Object_Get_doc}, + {"GetSelected", ( PyCFunction ) M_Object_GetSelected, METH_NOARGS, + M_Object_GetSelected_doc}, + {"Duplicate", ( PyCFunction ) M_Object_Duplicate, METH_VARARGS | METH_KEYWORDS, + M_Object_Duplicate_doc}, + {NULL, NULL, 0, NULL} +}; + + +/*****************************************************************************/ +/* Python BPy_Object methods declarations: */ +/*****************************************************************************/ +static int setupSB(Object* ob); /*Make sure Softbody Pointer is initialized */ +static int setupPI(Object* ob); + +static PyObject *Object_buildParts( BPy_Object * self ); +static PyObject *Object_clearIpo( BPy_Object * self ); +static PyObject *Object_clrParent( BPy_Object * self, PyObject * args ); +static PyObject *Object_clearTrack( BPy_Object * self, PyObject * args ); +static PyObject *Object_getData(BPy_Object *self, PyObject *args, PyObject *kwd); +static PyObject *Object_getDeltaLocation( BPy_Object * self ); +static PyObject *Object_getDrawMode( BPy_Object * self ); +static PyObject *Object_getDrawType( BPy_Object * self ); +static PyObject *Object_GetEuler( BPy_Object * self, PyObject * args ); +static PyObject *Object_getInverseMatrix( BPy_Object * self ); +static PyObject *Object_getIpo( BPy_Object * self ); +static PyObject *Object_getLocation( BPy_Object * self, PyObject * args ); +static PyObject *Object_getMaterials( BPy_Object * self, PyObject * args ); +static PyObject *Object_getMatrix( BPy_Object * self, PyObject * args ); +static PyObject *Object_getParent( BPy_Object * self ); +static PyObject *Object_getParentBoneName( BPy_Object * self ); +static int Object_setParentBoneName( BPy_Object * self, PyObject * value ); +static PyObject *Object_getSize( BPy_Object * self, PyObject * args ); +static PyObject *Object_getTimeOffset( BPy_Object * self ); +static PyObject *Object_getTracked( BPy_Object * self ); +static PyObject *Object_getType( BPy_Object * self ); +static PyObject *Object_getBoundBox( BPy_Object * self ); +static PyObject *Object_getAction( BPy_Object * self ); +static PyObject *Object_getPose( BPy_Object * self ); +static PyObject *Object_evaluatePose( BPy_Object * self, PyObject *args ); +static PyObject *Object_getSelected( BPy_Object * self ); +static PyObject *Object_makeDisplayList( BPy_Object * self ); +static PyObject *Object_link( BPy_Object * self, PyObject * args ); +static PyObject *Object_makeParent( BPy_Object * self, PyObject * args ); +static PyObject *Object_join( BPy_Object * self, PyObject * args ); +static PyObject *Object_makeParentDeform( BPy_Object * self, PyObject * args ); +static PyObject *Object_makeParentVertex( BPy_Object * self, PyObject * args ); +static PyObject *Object_makeParentBone( BPy_Object * self, PyObject * args ); +static PyObject *Object_materialUsage( void ); +static PyObject *Object_getDupliObjects ( BPy_Object * self); +static PyObject *Object_getEffects( BPy_Object * self ); +static PyObject *Object_setDeltaLocation( BPy_Object * self, PyObject * args ); +static PyObject *Object_SetDrawMode( BPy_Object * self, PyObject * args ); +static PyObject *Object_SetDrawType( BPy_Object * self, PyObject * args ); +static PyObject *Object_SetEuler( BPy_Object * self, PyObject * args ); +static PyObject *Object_SetMatrix( BPy_Object * self, PyObject * args ); +static PyObject *Object_SetIpo( BPy_Object * self, PyObject * args ); +static PyObject *Object_insertIpoKey( BPy_Object * self, PyObject * args ); +static PyObject *Object_insertPoseKey( BPy_Object * self, PyObject * args ); +static PyObject *Object_insertCurrentPoseKey( BPy_Object * self, PyObject * args ); +static PyObject *Object_setConstraintInfluenceForBone( BPy_Object * self, PyObject * args ); +static PyObject *Object_setLocation( BPy_Object * self, PyObject * args ); +static PyObject *Object_setMaterials( BPy_Object * self, PyObject * args ); +static PyObject *Object_setSize( BPy_Object * self, PyObject * args ); +static PyObject *Object_setTimeOffset( BPy_Object * self, PyObject * args ); +static PyObject *Object_makeTrack( BPy_Object * self, PyObject * args ); +static PyObject *Object_shareFrom( BPy_Object * self, PyObject * args ); +static PyObject *Object_Select( BPy_Object * self, PyObject * args ); +static PyObject *Object_getAllProperties( BPy_Object * self ); +static PyObject *Object_addProperty( BPy_Object * self, PyObject * args ); +static PyObject *Object_removeProperty( BPy_Object * self, PyObject * args ); +static PyObject *Object_getProperty( BPy_Object * self, PyObject * args ); +static PyObject *Object_removeAllProperties( BPy_Object * self ); +static PyObject *Object_copyAllPropertiesTo( BPy_Object * self, + PyObject * args ); +static PyObject *Object_getScriptLinks( BPy_Object * self, PyObject * value ); +static PyObject *Object_addScriptLink( BPy_Object * self, PyObject * args ); +static PyObject *Object_clearScriptLinks( BPy_Object * self, PyObject *args ); +static PyObject *Object_getPIStrength( BPy_Object * self ); +static PyObject *Object_setPIStrength( BPy_Object * self, PyObject * args ); +static PyObject *Object_getPIFalloff( BPy_Object * self ); +static PyObject *Object_setPIFalloff( BPy_Object * self, PyObject * args ); +static PyObject *Object_getPIMaxDist( BPy_Object * self ); +static PyObject *Object_setPIMaxDist( BPy_Object * self, PyObject * args ); +static PyObject *Object_getPIUseMaxDist( BPy_Object * self ); +static PyObject *Object_SetPIUseMaxDist( BPy_Object * self, PyObject * args ); +static PyObject *Object_getPIType( BPy_Object * self ); +static PyObject *Object_SetPIType( BPy_Object * self, PyObject * args ); +static PyObject *Object_getPIPerm( BPy_Object * self ); +static PyObject *Object_SetPIPerm( BPy_Object * self, PyObject * args ); +static PyObject *Object_getPIRandomDamp( BPy_Object * self ); +static PyObject *Object_setPIRandomDamp( BPy_Object * self, PyObject * args ); +static PyObject *Object_getPISurfaceDamp( BPy_Object * self ); +static PyObject *Object_SetPISurfaceDamp( BPy_Object * self, PyObject * args ); +static PyObject *Object_getPIDeflection( BPy_Object * self ); +static PyObject *Object_SetPIDeflection( BPy_Object * self, PyObject * args ); + +static int Object_setRBMass( BPy_Object * self, PyObject * args ); +static int Object_setRBFlags( BPy_Object * self, PyObject * args ); +static int Object_setRBShapeBoundType( BPy_Object * self, PyObject * args ); + +static PyObject *Object_getSBMass( BPy_Object * self ); +static PyObject *Object_setSBMass( BPy_Object * self, PyObject * args ); +static PyObject *Object_getSBGravity( BPy_Object * self ); +static PyObject *Object_setSBGravity( BPy_Object * self, PyObject * args ); +static PyObject *Object_getSBFriction( BPy_Object * self ); +static PyObject *Object_setSBFriction( BPy_Object * self, PyObject * args ); +static PyObject *Object_getSBErrorLimit( BPy_Object * self ); +static PyObject *Object_setSBErrorLimit( BPy_Object * self, PyObject * args ); +static PyObject *Object_getSBGoalSpring( BPy_Object * self ); +static PyObject *Object_setSBGoalSpring( BPy_Object * self, PyObject * args ); +static PyObject *Object_getSBGoalFriction( BPy_Object * self ); +static PyObject *Object_setSBGoalFriction( BPy_Object * self, PyObject * args ); +static PyObject *Object_getSBMinGoal( BPy_Object * self ); +static PyObject *Object_setSBMinGoal( BPy_Object * self, PyObject * args ); +static PyObject *Object_getSBMaxGoal( BPy_Object * self ); +static PyObject *Object_setSBMaxGoal( BPy_Object * self, PyObject * args ); +static PyObject *Object_getSBInnerSpring( BPy_Object * self ); +static PyObject *Object_setSBInnerSpring( BPy_Object * self, PyObject * args ); +static PyObject *Object_getSBInnerSpringFriction( BPy_Object * self ); +static PyObject *Object_setSBInnerSpringFriction( BPy_Object * self, PyObject * args ); + +static PyObject *Object_isSB( BPy_Object * self ); +static PyObject *Object_getSBDefaultGoal( BPy_Object * self ); +static PyObject *Object_setSBDefaultGoal( BPy_Object * self, PyObject * args ); +static PyObject *Object_getSBUseGoal( BPy_Object * self ); +static PyObject *Object_SetSBUseGoal( BPy_Object * self, PyObject * args ); +static PyObject *Object_getSBUseEdges( BPy_Object * self ); +static PyObject *Object_SetSBUseEdges( BPy_Object * self, PyObject * args ); +static PyObject *Object_getSBStiffQuads( BPy_Object * self ); +static PyObject *Object_SetSBStiffQuads( BPy_Object * self, PyObject * args ); +static PyObject *Object_insertShapeKey(BPy_Object * self); +static PyObject *Object_copyNLA( BPy_Object * self, PyObject * args ); +static PyObject *Object_convertActionToStrip( BPy_Object * self ); +static PyObject *Object_copy(BPy_Object * self); /* __copy__ */ + +/*****************************************************************************/ +/* Python BPy_Object methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_Object_methods[] = { + /* name, method, flags, doc */ + {"buildParts", ( PyCFunction ) Object_buildParts, METH_NOARGS, + "Recalcs particle system (if any) "}, + {"getIpo", ( PyCFunction ) Object_getIpo, METH_NOARGS, + "Returns the ipo of this object (if any) "}, + {"clrParent", ( PyCFunction ) Object_clrParent, METH_VARARGS, + "Clears parent object. Optionally specify:\n\ +mode\n\tnonzero: Keep object transform\nfast\n\t>0: Don't update scene \ +hierarchy (faster)"}, + {"clearTrack", ( PyCFunction ) Object_clearTrack, METH_VARARGS, + "Make this object not track another anymore. Optionally specify:\n\ +mode\n\t2: Keep object transform\nfast\n\t>0: Don't update scene \ +hierarchy (faster)"}, + {"getData", ( PyCFunction ) Object_getData, METH_VARARGS | METH_KEYWORDS, + "(name_only = 0, mesh = 0) - Returns the datablock object containing the object's \ +data, e.g. Mesh.\n\ +If 'name_only' is nonzero or True, only the name of the datablock is returned"}, + {"getDeltaLocation", ( PyCFunction ) Object_getDeltaLocation, + METH_NOARGS, + "Returns the object's delta location (x, y, z)"}, + {"getDrawMode", ( PyCFunction ) Object_getDrawMode, METH_NOARGS, + "Returns the object draw modes"}, + {"getDrawType", ( PyCFunction ) Object_getDrawType, METH_NOARGS, + "Returns the object draw type"}, + {"getAction", ( PyCFunction ) Object_getAction, METH_NOARGS, + "Returns the active action for this object"}, + {"evaluatePose", ( PyCFunction ) Object_evaluatePose, METH_VARARGS, + "(framenum) - Updates the pose to a certain frame number when the Object is\ + bound to an Action"}, + {"getPose", ( PyCFunction ) Object_getPose, METH_NOARGS, + "() - returns the pose from an object if it exists, else None"}, + {"isSelected", ( PyCFunction ) Object_getSelected, METH_NOARGS, + "Return a 1 or 0 depending on whether the object is selected"}, + {"getEuler", ( PyCFunction ) Object_GetEuler, METH_VARARGS, + "(space = 'localspace' / 'worldspace') - Returns the object's rotation as Euler rotation vector\n\ +(rotX, rotY, rotZ)"}, + {"getInverseMatrix", ( PyCFunction ) Object_getInverseMatrix, + METH_NOARGS, + "Returns the object's inverse matrix"}, + {"getLocation", ( PyCFunction ) Object_getLocation, METH_VARARGS, + "(space = 'localspace' / 'worldspace') - Returns the object's location (x, y, z)\n\ +"}, + {"getMaterials", ( PyCFunction ) Object_getMaterials, METH_VARARGS, + "(i = 0) - Returns list of materials assigned to the object.\n\ +if i is nonzero, empty slots are not ignored: they are returned as None's."}, + {"getMatrix", ( PyCFunction ) Object_getMatrix, METH_VARARGS, + "(str = 'worldspace') - Returns the object matrix.\n\ +(str = 'worldspace') - the desired matrix: worldspace (default), localspace\n\ +or old_worldspace.\n\ +\n\ +'old_worldspace' was the only behavior before Blender 2.34. With it the\n\ +matrix is not updated for changes made by the script itself\n\ +(like obj.LocX = 10) until a redraw happens, either called by the script or\n\ +automatic when the script finishes."}, + {"getName", ( PyCFunction ) GenericLib_getName, METH_NOARGS, + "Returns the name of the object"}, + {"getParent", ( PyCFunction ) Object_getParent, METH_NOARGS, + "Returns the object's parent object"}, + {"getParentBoneName", ( PyCFunction ) Object_getParentBoneName, METH_NOARGS, + "Returns None, or the 'sub-name' of the parent (eg. Bone name)"}, + {"getSize", ( PyCFunction ) Object_getSize, METH_VARARGS, + "(space = 'localspace' / 'worldspace') - Returns the object's size (x, y, z)"}, + {"getTimeOffset", ( PyCFunction ) Object_getTimeOffset, METH_NOARGS, + "Returns the object's time offset"}, + {"getTracked", ( PyCFunction ) Object_getTracked, METH_NOARGS, + "Returns the object's tracked object"}, + {"getType", ( PyCFunction ) Object_getType, METH_NOARGS, + "Returns type of string of Object"}, +/* Particle Interaction */ + + {"getPIStrength", ( PyCFunction ) Object_getPIStrength, METH_NOARGS, + "Returns Particle Interaction Strength"}, + {"setPIStrength", ( PyCFunction ) Object_setPIStrength, METH_VARARGS, + "Sets Particle Interaction Strength"}, + {"getPIFalloff", ( PyCFunction ) Object_getPIFalloff, METH_NOARGS, + "Returns Particle Interaction Falloff"}, + {"setPIFalloff", ( PyCFunction ) Object_setPIFalloff, METH_VARARGS, + "Sets Particle Interaction Falloff"}, + {"getPIMaxDist", ( PyCFunction ) Object_getPIMaxDist, METH_NOARGS, + "Returns Particle Interaction Max Distance"}, + {"setPIMaxDist", ( PyCFunction ) Object_setPIMaxDist, METH_VARARGS, + "Sets Particle Interaction Max Distance"}, + {"getPIUseMaxDist", ( PyCFunction ) Object_getPIUseMaxDist, METH_NOARGS, + "Returns bool for Use Max Distace in Particle Interaction "}, + {"setPIUseMaxDist", ( PyCFunction ) Object_SetPIUseMaxDist, METH_VARARGS, + "Sets if Max Distance should be used in Particle Interaction"}, + {"getPIType", ( PyCFunction ) Object_getPIType, METH_NOARGS, + "Returns Particle Interaction Type"}, + {"setPIType", ( PyCFunction ) Object_SetPIType, METH_VARARGS, + "sets Particle Interaction Type"}, + {"getPIPerm", ( PyCFunction ) Object_getPIPerm, METH_NOARGS, + "Returns Particle Interaction Permiability"}, + {"setPIPerm", ( PyCFunction ) Object_SetPIPerm, METH_VARARGS, + "Sets Particle Interaction Permiability"}, + {"getPISurfaceDamp", ( PyCFunction ) Object_getPISurfaceDamp, METH_NOARGS, + "Returns Particle Interaction Surface Damping"}, + {"setPISurfaceDamp", ( PyCFunction ) Object_SetPISurfaceDamp, METH_VARARGS, + "Sets Particle Interaction Surface Damping"}, + {"getPIRandomDamp", ( PyCFunction ) Object_getPIRandomDamp, METH_NOARGS, + "Returns Particle Interaction Random Damping"}, + {"setPIRandomDamp", ( PyCFunction ) Object_setPIRandomDamp, METH_VARARGS, + "Sets Particle Interaction Random Damping"}, + {"getPIDeflection", ( PyCFunction ) Object_getPIDeflection, METH_NOARGS, + "Returns Particle Interaction Deflection"}, + {"setPIDeflection", ( PyCFunction ) Object_SetPIDeflection, METH_VARARGS, + "Sets Particle Interaction Deflection"}, + +/* Softbody */ + + {"isSB", ( PyCFunction ) Object_isSB, METH_NOARGS, + "True if object is a soft body"}, + {"getSBMass", ( PyCFunction ) Object_getSBMass, METH_NOARGS, + "Returns SB Mass"}, + {"setSBMass", ( PyCFunction ) Object_setSBMass, METH_VARARGS, + "Sets SB Mass"}, + {"getSBGravity", ( PyCFunction ) Object_getSBGravity, METH_NOARGS, + "Returns SB Gravity"}, + {"setSBGravity", ( PyCFunction ) Object_setSBGravity, METH_VARARGS, + "Sets SB Gravity"}, + {"getSBFriction", ( PyCFunction ) Object_getSBFriction, METH_NOARGS, + "Returns SB Friction"}, + {"setSBFriction", ( PyCFunction ) Object_setSBFriction, METH_VARARGS, + "Sets SB Friction"}, + {"getSBErrorLimit", ( PyCFunction ) Object_getSBErrorLimit, METH_NOARGS, + "Returns SB ErrorLimit"}, + {"setSBErrorLimit", ( PyCFunction ) Object_setSBErrorLimit, METH_VARARGS, + "Sets SB ErrorLimit"}, + {"getSBGoalSpring", ( PyCFunction ) Object_getSBGoalSpring, METH_NOARGS, + "Returns SB GoalSpring"}, + {"setSBGoalSpring", ( PyCFunction ) Object_setSBGoalSpring, METH_VARARGS, + "Sets SB GoalSpring"}, + {"getSBGoalFriction", ( PyCFunction ) Object_getSBGoalFriction, METH_NOARGS, + "Returns SB GoalFriction"}, + {"setSBGoalFriction", ( PyCFunction ) Object_setSBGoalFriction, METH_VARARGS, + "Sets SB GoalFriction"}, + {"getSBMinGoal", ( PyCFunction ) Object_getSBMinGoal, METH_NOARGS, + "Returns SB MinGoal"}, + {"setSBMinGoal", ( PyCFunction ) Object_setSBMinGoal, METH_VARARGS, + "Sets SB MinGoal "}, + {"getSBMaxGoal", ( PyCFunction ) Object_getSBMaxGoal, METH_NOARGS, + "Returns SB MaxGoal"}, + {"setSBMaxGoal", ( PyCFunction ) Object_setSBMaxGoal, METH_VARARGS, + "Sets SB MaxGoal"}, + {"getSBInnerSpring", ( PyCFunction ) Object_getSBInnerSpring, METH_NOARGS, + "Returns SB InnerSpring"}, + {"setSBInnerSpring", ( PyCFunction ) Object_setSBInnerSpring, METH_VARARGS, + "Sets SB InnerSpring"}, + {"getSBInnerSpringFriction", ( PyCFunction ) Object_getSBInnerSpringFriction, METH_NOARGS, + "Returns SB InnerSpringFriction"}, + {"setSBInnerSpringFriction", ( PyCFunction ) Object_setSBInnerSpringFriction, METH_VARARGS, + "Sets SB InnerSpringFriction"}, + {"getSBDefaultGoal", ( PyCFunction ) Object_getSBDefaultGoal, METH_NOARGS, + "Returns SB DefaultGoal"}, + {"setSBDefaultGoal", ( PyCFunction ) Object_setSBDefaultGoal, METH_VARARGS, + "Sets SB DefaultGoal"}, + {"getSBUseGoal", ( PyCFunction ) Object_getSBUseGoal, METH_NOARGS, + "Returns SB UseGoal"}, + {"setSBUseGoal", ( PyCFunction ) Object_SetSBUseGoal, METH_VARARGS, + "Sets SB UseGoal"}, + {"getSBUseEdges", ( PyCFunction ) Object_getSBUseEdges, METH_NOARGS, + "Returns SB UseEdges"}, + {"setSBUseEdges", ( PyCFunction ) Object_SetSBUseEdges, METH_VARARGS, + "Sets SB UseEdges"}, + {"getSBStiffQuads", ( PyCFunction ) Object_getSBStiffQuads, METH_NOARGS, + "Returns SB StiffQuads"}, + {"setSBStiffQuads", ( PyCFunction ) Object_SetSBStiffQuads, METH_VARARGS, + "Sets SB StiffQuads"}, + {"getBoundBox", ( PyCFunction ) Object_getBoundBox, METH_NOARGS, + "Returns the object's bounding box"}, + {"makeDisplayList", ( PyCFunction ) Object_makeDisplayList, METH_NOARGS, + "Update this object's Display List. Some changes like turning\n\ +'SubSurf' on for a mesh need this method (followed by a Redraw) to\n\ +show the changes on the 3d window."}, + {"link", ( PyCFunction ) Object_link, METH_VARARGS, + "Links Object with data provided in the argument. The data must\n\ +match the Object's type, so you cannot link a Lamp to a Mesh type object."}, + {"makeParent", ( PyCFunction ) Object_makeParent, METH_VARARGS, + "Makes the object the parent of the objects provided in the\n\ +argument which must be a list of valid Objects. Optional extra arguments:\n\ +mode:\n\t0: make parent with inverse\n\t1: without inverse\n\ +fast:\n\t0: update scene hierarchy automatically\n\t\ +don't update scene hierarchy (faster). In this case, you must\n\t\ +explicitly update the Scene hierarchy."}, + {"join", ( PyCFunction ) Object_join, METH_VARARGS, + "(object_list) - Joins the objects in object list of the same type, into this object."}, + {"makeParentDeform", ( PyCFunction ) Object_makeParentDeform, METH_VARARGS, + "Makes the object the deformation parent of the objects provided in the \n\ +argument which must be a list of valid Objects. Optional extra arguments:\n\ +mode:\n\t0: make parent with inverse\n\t1: without inverse\n\ +fast:\n\t0: update scene hierarchy automatically\n\t\ +don't update scene hierarchy (faster). In this case, you must\n\t\ +explicitly update the Scene hierarchy."}, + {"makeParentVertex", ( PyCFunction ) Object_makeParentVertex, METH_VARARGS, + "Makes the object the vertex parent of the objects provided in the \n\ +argument which must be a list of valid Objects. \n\ +The second argument is a tuple of 1 or 3 positive integers which corresponds \ +to the index of the vertex you are parenting to.\n\ +Optional extra arguments:\n\ +mode:\n\t0: make parent with inverse\n\t1: without inverse\n\ +fast:\n\t0: update scene hierarchy automatically\n\t\ +don't update scene hierarchy (faster). In this case, you must\n\t\ +explicitly update the Scene hierarchy."}, + {"makeParentBone", ( PyCFunction ) Object_makeParentBone, METH_VARARGS, + "Makes this armature objects bone, the parent of the objects provided in the \n\ +argument which must be a list of valid Objects. Optional extra arguments:\n\ +mode:\n\t0: make parent with inverse\n\t1: without inverse\n\ +fast:\n\t0: update scene hierarchy automatically\n\t\ +don't update scene hierarchy (faster). In this case, you must\n\t\ +explicitely update the Scene hierarchy."}, + + {"materialUsage", ( PyCFunction ) Object_materialUsage, METH_NOARGS, + "Determines the way the material is used and returns status.\n\ +Possible arguments (provide as strings):\n\ +\tData: Materials assigned to the object's data are shown. (default)\n\ +\tObject: Materials assigned to the object are shown."}, + {"setDeltaLocation", ( PyCFunction ) Object_setDeltaLocation, + METH_VARARGS, + "Sets the object's delta location which must be a vector triple."}, + {"setDrawMode", ( PyCFunction ) Object_SetDrawMode, METH_VARARGS, + "Sets the object's drawing mode. The argument can be a sum of:\n\ +2: axis\n4: texspace\n8: drawname\n16: drawimage\n32: drawwire\n64: drawxray\n128: drawtransp"}, + {"setDrawType", ( PyCFunction ) Object_SetDrawType, METH_VARARGS, + "Sets the object's drawing type. The argument must be one of:\n\ +1: Bounding box\n2: Wire\n3: Solid\n4: Shaded\n5: Textured"}, + {"setEuler", ( PyCFunction ) Object_SetEuler, METH_VARARGS, + "Set the object's rotation according to the specified Euler\n\ +angles. The argument must be a vector triple"}, + {"setMatrix", ( PyCFunction ) Object_SetMatrix, METH_VARARGS, + "Set and apply a new local matrix for the object"}, + {"setLocation", ( PyCFunction ) Object_setLocation, METH_VARARGS, + "Set the object's location. The first argument must be a vector\n\ +triple."}, + {"setMaterials", ( PyCFunction ) Object_setMaterials, METH_VARARGS, + "Sets materials. The argument must be a list of valid material\n\ +objects."}, + {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS, + "Sets the name of the object"}, + {"setSize", ( PyCFunction ) Object_setSize, METH_VARARGS, + "Set the object's size. The first argument must be a vector\n\ +triple."}, + {"setTimeOffset", ( PyCFunction ) Object_setTimeOffset, METH_VARARGS, + "Set the object's time offset."}, + {"makeTrack", ( PyCFunction ) Object_makeTrack, METH_VARARGS, + "(trackedobj, fast = 0) - Make this object track another.\n\ + (trackedobj) - the object that will be tracked.\n\ + (fast = 0) - if 0: update the scene hierarchy automatically. If you\n\ + set 'fast' to a nonzero value, don't forget to update the scene yourself\n\ + (see scene.update())."}, + {"shareFrom", ( PyCFunction ) Object_shareFrom, METH_VARARGS, + "Link data of self with object specified in the argument. This\n\ +works only if self and the object specified are of the same type."}, + {"select", ( PyCFunction ) Object_Select, METH_VARARGS, + "( 1 or 0 ) - Set the selected state of the object.\n\ + 1 is selected, 0 not selected "}, + {"setIpo", ( PyCFunction ) Object_SetIpo, METH_VARARGS, + "(Blender Ipo) - Sets the object's ipo"}, + {"clearIpo", ( PyCFunction ) Object_clearIpo, METH_NOARGS, + "() - Unlink ipo from this object"}, + + {"insertIpoKey", ( PyCFunction ) Object_insertIpoKey, METH_VARARGS, + "( Object IPO type ) - Inserts a key into IPO"}, + {"insertPoseKey", ( PyCFunction ) Object_insertPoseKey, METH_VARARGS, + "( Object Pose type ) - Inserts a key into Action"}, + {"insertCurrentPoseKey", ( PyCFunction ) Object_insertCurrentPoseKey, METH_VARARGS, + "( Object Pose type ) - Inserts a key into Action based on current pose"}, + {"setConstraintInfluenceForBone", ( PyCFunction ) Object_setConstraintInfluenceForBone, METH_VARARGS, + "( ) - sets a constraint influence for a certain bone in this (armature)object."}, + {"copyNLA", ( PyCFunction ) Object_copyNLA, METH_VARARGS, + "( ) - copies all NLA strips from another object to this object."}, + {"convertActionToStrip", ( PyCFunction ) Object_convertActionToStrip, METH_NOARGS, + "( ) - copies all NLA strips from another object to this object."}, + {"getAllProperties", ( PyCFunction ) Object_getAllProperties, METH_NOARGS, + "() - Get all the properties from this object"}, + {"addProperty", ( PyCFunction ) Object_addProperty, METH_VARARGS, + "() - Add a property to this object"}, + {"removeProperty", ( PyCFunction ) Object_removeProperty, METH_VARARGS, + "() - Remove a property from this object"}, + {"getProperty", ( PyCFunction ) Object_getProperty, METH_VARARGS, + "() - Get a property from this object by name"}, + {"removeAllProperties", ( PyCFunction ) Object_removeAllProperties, + METH_NOARGS, + "() - removeAll a properties from this object"}, + {"copyAllPropertiesTo", ( PyCFunction ) Object_copyAllPropertiesTo, + METH_VARARGS, + "() - copy all properties from this object to another object"}, + {"getScriptLinks", ( PyCFunction ) Object_getScriptLinks, METH_O, + "(eventname) - Get a list of this object's scriptlinks (Text names) " + "of the given type\n" + "(eventname) - string: FrameChanged, Redraw or Render."}, + {"addScriptLink", ( PyCFunction ) Object_addScriptLink, METH_VARARGS, + "(text, evt) - Add a new object scriptlink.\n" + "(text) - string: an existing Blender Text name;\n" + "(evt) string: FrameChanged, Redraw or Render."}, + {"clearScriptLinks", ( PyCFunction ) Object_clearScriptLinks, + METH_VARARGS, + "() - Delete all scriptlinks from this object.\n" + "([s1<,s2,s3...>]) - Delete specified scriptlinks from this object."}, + {"insertShapeKey", ( PyCFunction ) Object_insertShapeKey, METH_NOARGS, + "() - Insert a Shape Key in the current object"}, + {"__copy__", ( PyCFunction ) Object_copy, METH_NOARGS, + "() - Return a copy of this object."}, + {"copy", ( PyCFunction ) Object_copy, METH_NOARGS, + "() - Return a copy of this object."}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* PythonTypeObject callback function prototypes */ +/*****************************************************************************/ +static void Object_dealloc( BPy_Object * obj ); +static PyObject *Object_repr( BPy_Object * obj ); +static int Object_compare( BPy_Object * a, BPy_Object * b ); + +/*****************************************************************************/ +/* Function: M_Object_New */ +/* Python equivalent: Blender.Object.New */ +/*****************************************************************************/ + +/* + * Note: if this method is called without later linking object data to it, + * errors can be caused elsewhere in Blender. Future versions of the API + * will designate obdata as a parameter to this method to prevent this, and + * eventually this method will be deprecated. + * + * When we can guarantee that objects will always have valid obdata, + * unlink_object() should be edited to remove checks for NULL pointers and + * debugging messages. + */ + +PyObject *M_Object_New( PyObject * self_unused, PyObject * args ) +{ + struct Object *object; + int type; + char *str_type; + char *name = NULL; + PyObject *py_object; + BPy_Object *blen_object; + + if( !PyArg_ParseTuple( args, "s|s", &str_type, &name ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "string expected as argument" ); + + if( strcmp( str_type, "Armature" ) == 0 ) + type = OB_ARMATURE; + else if( strcmp( str_type, "Camera" ) == 0 ) + type = OB_CAMERA; + else if( strcmp( str_type, "Curve" ) == 0 ) + type = OB_CURVE; + else if (strcmp (str_type, "Text") == 0) + type = OB_FONT; + else if( strcmp( str_type, "Lamp" ) == 0 ) + type = OB_LAMP; + else if( strcmp( str_type, "Lattice" ) == 0 ) + type = OB_LATTICE; + else if( strcmp( str_type, "Mball" ) == 0 ) + type = OB_MBALL; + else if( strcmp( str_type, "Mesh" ) == 0 ) + type = OB_MESH; + else if( strcmp( str_type, "Surf" ) == 0 ) + type = OB_SURF; +/* else if (strcmp (str_type, "Wave") == 0) type = OB_WAVE; */ + else if( strcmp( str_type, "Empty" ) == 0 ) + type = OB_EMPTY; + else + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "Unknown type specified" ); + + /* Create a new object. */ + if( name == NULL ) { + /* No name is specified, set the name to the type of the object. */ + name = str_type; + } + object = add_only_object(type, name); + + object->flag = 0; + object->lay = 1; /* Layer, by default visible*/ + object->data = NULL; + + /* user count is incremented in Object_CreatePyObject */ + object->id.us = 0; + + /* Create a Python object from it. */ + py_object = Object_CreatePyObject( object ); + blen_object = (BPy_Object *)py_object; + + /* store the real object type in the PyObject, treat this as an Empty + * until it has some obdata */ + blen_object->realtype = object->type; + object->type = OB_EMPTY; + + return py_object; +} + +/*****************************************************************************/ +/* Function: M_Object_Get */ +/* Python equivalent: Blender.Object.Get */ +/*****************************************************************************/ +PyObject *M_Object_Get( PyObject * self_unused, PyObject * args ) +{ + struct Object *object; + PyObject *blen_object; + char *name = NULL; + + PyArg_ParseTuple( args, "|s", &name ); + + if( name != NULL ) { + object = ( Object * ) GetIdFromList( &( G.main->object ), name ); + + /* No object exists with the name specified in the argument name. */ + if( !object ){ + char buffer[128]; + PyOS_snprintf( buffer, sizeof(buffer), + "object \"%s\" not found", name); + return EXPP_ReturnPyObjError( PyExc_ValueError, + buffer ); + } + + /* objects used in pydriver expressions need this */ + if (bpy_during_pydriver()) + bpy_pydriver_appendToList(object); + + return Object_CreatePyObject( object ); + } else { + /* No argument has been given. Return a list of all objects. */ + PyObject *obj_list; + Link *link; + int index; + + /* do not allow Get() (w/o arguments) inside pydriver, otherwise + * we'd have to update all objects in the DAG */ + if (bpy_during_pydriver()) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "Object.Get requires an argument when used in pydrivers" ); + + obj_list = PyList_New( BLI_countlist( &( G.main->object ) ) ); + + if( !obj_list ) + return EXPP_ReturnPyObjError( PyExc_SystemError, + "List creation failed." ); + + link = G.main->object.first; + index = 0; + while( link ) { + object = ( Object * ) link; + blen_object = Object_CreatePyObject( object ); + if( !blen_object ) { + Py_DECREF( obj_list ); + Py_RETURN_NONE; + } + PyList_SetItem( obj_list, index, blen_object ); + index++; + link = link->next; + } + return obj_list; + } +} + +/*****************************************************************************/ +/* Function: M_Object_GetSelected */ +/* Python equivalent: Blender.Object.GetSelected */ +/*****************************************************************************/ +static PyObject *M_Object_GetSelected( PyObject * self_unused ) +{ + PyObject *blen_object; + PyObject *list; + Base *base_iter; + + list = PyList_New( 0 ); + + if( G.vd == NULL ) { + /* No 3d view has been initialized yet, simply return an empty list */ + return list; + } + + if( ( G.scene->basact ) && + ( ( G.scene->basact->flag & SELECT ) && + ( G.scene->basact->lay & G.vd->lay ) ) ) { + + /* Active object is first in the list. */ + blen_object = Object_CreatePyObject( G.scene->basact->object ); + if( !blen_object ) { + Py_DECREF( list ); + Py_RETURN_NONE; + } + PyList_Append( list, blen_object ); + Py_DECREF( blen_object ); + } + + base_iter = G.scene->base.first; + while( base_iter ) { + if( ( ( base_iter->flag & SELECT ) && + ( base_iter->lay & G.vd->lay ) ) && + ( base_iter != G.scene->basact ) ) { + + blen_object = Object_CreatePyObject( base_iter->object ); + if( blen_object ) { + PyList_Append( list, blen_object ); + Py_DECREF( blen_object ); + } + } + base_iter = base_iter->next; + } + return list; +} + + +/*****************************************************************************/ +/* Function: M_Object_Duplicate */ +/* Python equivalent: Blender.Object.Duplicate */ +/*****************************************************************************/ +static PyObject *M_Object_Duplicate( PyObject * self_unused, + PyObject * args, PyObject *kwd ) +{ + int dupflag= 0; /* this a flag, passed to adduplicate() and used instead of U.dupflag sp python can set what is duplicated */ + + /* the following variables are bools, if set true they will modify the dupflag to pass to adduplicate() */ + int mesh_dupe = 0; + int surface_dupe = 0; + int curve_dupe = 0; + int text_dupe = 0; + int metaball_dupe = 0; + int armature_dupe = 0; + int lamp_dupe = 0; + int material_dupe = 0; + int texture_dupe = 0; + int ipo_dupe = 0; + + static char *kwlist[] = {"mesh", "surface", "curve", + "text", "metaball", "armature", "lamp", "material", "texture", "ipo", NULL}; + + /* duplicating in background causes segfaults */ + if( G.background == 1 ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "cannot duplicate objects in background mode" ); + + + if (!PyArg_ParseTupleAndKeywords(args, kwd, "|iiiiiiiiii", kwlist, + &mesh_dupe, &surface_dupe, &curve_dupe, &text_dupe, &metaball_dupe, + &armature_dupe, &lamp_dupe, &material_dupe, &texture_dupe, &ipo_dupe)) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected nothing or bool keywords 'mesh', 'surface', 'curve', 'text', 'metaball', 'armature', 'lamp' 'material', 'texture' and 'ipo' as arguments" ); + + /* USER_DUP_ACT for actions is not supported in the UI so dont support it here */ + if (mesh_dupe) dupflag |= USER_DUP_MESH; + if (surface_dupe) dupflag |= USER_DUP_SURF; + if (curve_dupe) dupflag |= USER_DUP_CURVE; + if (text_dupe) dupflag |= USER_DUP_FONT; + if (metaball_dupe) dupflag |= USER_DUP_MBALL; + if (armature_dupe) dupflag |= USER_DUP_ARM; + if (lamp_dupe) dupflag |= USER_DUP_LAMP; + if (material_dupe) dupflag |= USER_DUP_MAT; + if (texture_dupe) dupflag |= USER_DUP_TEX; + if (ipo_dupe) dupflag |= USER_DUP_IPO; + adduplicate(2, dupflag); /* 2 is a mode with no transform and no redraw, Duplicate the current selection, context sensitive */ + Py_RETURN_NONE; +} + + +/*****************************************************************************/ +/* Python BPy_Object methods: */ +/*****************************************************************************/ + +static PyObject *Object_buildParts( BPy_Object * self ) +{ + build_particle_system( self->object ); + Py_RETURN_NONE; +} + +static PyObject *Object_clearIpo( BPy_Object * self ) +{ + Object *ob = self->object; + Ipo *ipo = ( Ipo * ) ob->ipo; + + if( ipo ) { + ID *id = &ipo->id; + if( id->us > 0 ) + id->us--; + ob->ipo = NULL; + + Py_RETURN_TRUE; + } + + Py_RETURN_FALSE; /* no ipo found */ +} + +static PyObject *Object_clrParent( BPy_Object * self, PyObject * args ) +{ + int mode = 0; + int fast = 0; + + if( !PyArg_ParseTuple( args, "|ii", &mode, &fast ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected one or two optional integers as arguments" ); + + /* Remove the link only, the object is still in the scene. */ + self->object->parent = NULL; + + if( mode == 2 ) { + /* Keep transform */ + apply_obmat( self->object ); + } + + if( !fast ) + DAG_scene_sort( G.scene ); + + Py_RETURN_NONE; +} + +static PyObject *Object_clearTrack( BPy_Object * self, PyObject * args ) +{ + int mode = 0; + int fast = 0; + + if( !PyArg_ParseTuple( args, "|ii", &mode, &fast ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected one or two optional integers as arguments" ); + + /* Remove the link only, the object is still in the scene. */ + self->object->track = NULL; + + if( mode ) { + /* Keep transform */ + apply_obmat( self->object ); + } + + if( !fast ) + DAG_scene_sort( G.scene ); + + Py_RETURN_NONE; +} + +/* adds object data to a Blender object, if object->data = NULL */ +int EXPP_add_obdata( struct Object *object ) +{ + if( object->data != NULL ) + return -1; + + switch ( object->type ) { + case OB_ARMATURE: + /* TODO: Do we need to add something to G? (see the OB_LAMP case) */ + object->data = add_armature( "Armature" ); + break; + case OB_CAMERA: + /* TODO: Do we need to add something to G? (see the OB_LAMP case) */ + object->data = add_camera( "Camera" ); + break; + case OB_CURVE: + object->data = add_curve( "Curve", OB_CURVE ); + G.totcurve++; + break; + case OB_LAMP: + object->data = add_lamp( "Lamp" ); + G.totlamp++; + break; + case OB_MESH: + object->data = add_mesh( "Mesh" ); + G.totmesh++; + break; + case OB_LATTICE: + object->data = ( void * ) add_lattice( "Lattice" ); + object->dt = OB_WIRE; + break; + case OB_MBALL: + object->data = add_mball( "Meta" ); + break; + + /* TODO the following types will be supported later, + be sure to update Scene_link when new types are supported + case OB_SURF: + object->data = add_curve(OB_SURF); + G.totcurve++; + break; + case OB_FONT: + object->data = add_curve(OB_FONT); + break; + case OB_WAVE: + object->data = add_wave(); + break; + */ + default: + break; + } + + if( !object->data ) + return -1; + + return 0; +} + +static PyObject *Object_getDeltaLocation( BPy_Object * self ) +{ + return Py_BuildValue( "fff", self->object->dloc[0], + self->object->dloc[1], self->object->dloc[2] ); +} + +static PyObject *Object_getAction( BPy_Object * self ) +{ + if( self->object->action ) + return Action_CreatePyObject( self->object->action ); + Py_RETURN_NONE; +} + +static int Object_setAction( BPy_Object * self, PyObject * value ) +{ + return GenericLib_assignData(value, (void **) &self->object->action, 0, 1, ID_AC, 0); +} + +static PyObject *Object_evaluatePose(BPy_Object *self, PyObject *args) +{ + int frame = 1; + if( !PyArg_ParseTuple( args, "i", &frame ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument" ); + + frame = EXPP_ClampInt(frame, MINFRAME, MAXFRAME); + G.scene->r.cfra = frame; + do_all_pose_actions(self->object); + where_is_pose (self->object); + + Py_RETURN_NONE; +} + +static PyObject * Object_getPose(BPy_Object *self) +{ + /*if there is no pose will return PyNone*/ + return PyPose_FromPose(self->object->pose, self->object->id.name+2); +} + +static PyObject *Object_getSelected( BPy_Object * self ) +{ + Base *base; + + base = FIRSTBASE; + while( base ) { + if( base->object == self->object ) { + if( base->flag & SELECT ) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + } + base = base->next; + } + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "could not find object's selection state" ); +} + +static int Object_setSelect( BPy_Object * self, PyObject * value ) +{ + Base *base; + int param = PyObject_IsTrue( value ); + + if( param == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected True/False or 0/1" ); + + base = FIRSTBASE; + while( base ) { + if( base->object == self->object ) { + if( param ) { + base->flag |= SELECT; + self->object->flag = (short)base->flag; + set_active_base( base ); + } else { + base->flag &= ~SELECT; + self->object->flag = (short)base->flag; + } + break; + } + base = base->next; + } + if (base) { /* was the object selected? */ + countall( ); + } + return 0; +} + +static PyObject *Object_GetEuler( BPy_Object * self, PyObject * args ) +{ + char *space = "localspace"; /* default to local */ + float eul[3]; + + if( !PyArg_ParseTuple( args, "|s", &space ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a string or nothing" ); + + if( BLI_streq( space, "worldspace" ) ) { /* Worldspace matrix */ + float mat3[3][3]; + disable_where_script( 1 ); + where_is_object( self->object ); + Mat3CpyMat4(mat3, self->object->obmat); + Mat3ToEul(mat3, eul); + disable_where_script( 0 ); + } else if( BLI_streq( space, "localspace" ) ) { /* Localspace matrix */ + eul[0] = self->object->rot[0]; + eul[1] = self->object->rot[1]; + eul[2] = self->object->rot[2]; + } else { + return EXPP_ReturnPyObjError( PyExc_ValueError, + "expected either nothing, 'localspace' (default) or 'worldspace'" ); + } + + return ( PyObject * ) newEulerObject( eul, Py_NEW ); +} + +static PyObject *Object_getInverseMatrix( BPy_Object * self ) +{ + MatrixObject *inverse = + ( MatrixObject * ) newMatrixObject( NULL, 4, 4, Py_NEW ); + Mat4Invert( (float ( * )[4])*inverse->matrix, self->object->obmat ); + + return ( ( PyObject * ) inverse ); +} + +static PyObject *Object_getIpo( BPy_Object * self ) +{ + struct Ipo *ipo = self->object->ipo; + + if( ipo ) + return Ipo_CreatePyObject( ipo ); + Py_RETURN_NONE; +} + +static PyObject *Object_getLocation( BPy_Object * self, PyObject * args ) +{ + char *space = "localspace"; /* default to local */ + PyObject *attr; + if( !PyArg_ParseTuple( args, "|s", &space ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a string or nothing" ); + + if( BLI_streq( space, "worldspace" ) ) { /* Worldspace matrix */ + disable_where_script( 1 ); + where_is_object( self->object ); + + attr = Py_BuildValue( "fff", + self->object->obmat[3][0], + self->object->obmat[3][1], + self->object->obmat[3][2] ); + + disable_where_script( 0 ); + } else if( BLI_streq( space, "localspace" ) ) { /* Localspace matrix */ + attr = Py_BuildValue( "fff", + self->object->loc[0], + self->object->loc[1], + self->object->loc[2] ); + } else { + return EXPP_ReturnPyObjError( PyExc_ValueError, + "expected either nothing, 'localspace' (default) or 'worldspace'" ); + } + + return attr; +} + +static PyObject *Object_getMaterials( BPy_Object * self, PyObject * args ) +{ + int all = 0; + + if( !PyArg_ParseTuple( args, "|i", &all ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected an int or nothing" ); + + return EXPP_PyList_fromMaterialList( self->object->mat, + self->object->totcol, all ); +} + +static PyObject *Object_getParent( BPy_Object * self ) +{ + return Object_CreatePyObject( self->object->parent ); +} + +static PyObject *Object_getParentBoneName( BPy_Object * self ) +{ + if( self->object->parent && self->object->parent->type==OB_ARMATURE && self->object->parsubstr[0] != '\0' ) + return PyString_FromString( self->object->parsubstr ); + Py_RETURN_NONE; +} + +static int Object_setParentBoneName( BPy_Object * self, PyObject *value ) +{ + char *bonename; + + if (!PyString_Check(value)) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected an int or nothing" ); + + if ( + self->object->parent && + self->object->parent->type == OB_ARMATURE && + self->object->partype == PARBONE + ) {/* its all good */} else + return EXPP_ReturnIntError( PyExc_RuntimeError, + "can only set the parent bone name for objects that already have a bone parent" ); + + bonename = PyString_AsString(value); + + if (!get_named_bone(self->object->parent->data, bonename)) + return EXPP_ReturnIntError( PyExc_ValueError, + "cannot parent to this bone: invalid bone name" ); + + strcpy(self->object->parsubstr, bonename); + DAG_scene_sort( G.scene ); + return 0; +} + +static PyObject *Object_getSize( BPy_Object * self, PyObject * args ) +{ + char *space = "localspace"; /* default to local */ + PyObject *attr; + if( !PyArg_ParseTuple( args, "|s", &space ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a string or nothing" ); + + if( BLI_streq( space, "worldspace" ) ) { /* Worldspace matrix */ + float rot[3]; + float mat[3][3], imat[3][3], tmat[3][3]; + disable_where_script( 1 ); + where_is_object( self->object ); + + Mat3CpyMat4(mat, self->object->obmat); + + /* functionality copied from editobject.c apply_obmat */ + Mat3ToEul(mat, rot); + EulToMat3(rot, tmat); + Mat3Inv(imat, tmat); + Mat3MulMat3(tmat, imat, mat); + + attr = Py_BuildValue( "fff", + tmat[0][0], + tmat[1][1], + tmat[2][2] ); + disable_where_script( 0 ); + } else if( BLI_streq( space, "localspace" ) ) { /* Localspace matrix */ + attr = Py_BuildValue( "fff", + self->object->size[0], + self->object->size[1], + self->object->size[2] ); + } else { + return EXPP_ReturnPyObjError( PyExc_ValueError, + "expected either nothing, 'localspace' (default) or 'worldspace'" ); + } + return attr; +} + +static PyObject *Object_getTimeOffset( BPy_Object * self ) +{ + return PyFloat_FromDouble ( (double) self->object->sf ); +} + +static PyObject *Object_getTracked( BPy_Object * self ) +{ + return Object_CreatePyObject( self->object->track ); +} + +static PyObject *Object_getType( BPy_Object * self ) +{ + char *str; + int type = self->object->type; + + /* if object not yet linked to data, return the stored type */ + if( self->realtype != OB_EMPTY ) + type = self->realtype; + + switch ( type ) { + case OB_ARMATURE: + str = "Armature"; + break; + case OB_CAMERA: + str = "Camera"; + break; + case OB_CURVE: + str = "Curve"; + break; + case OB_EMPTY: + str = "Empty"; + break; + case OB_FONT: + str = "Text"; + break; + case OB_LAMP: + str = "Lamp"; + break; + case OB_LATTICE: + str = "Lattice"; + break; + case OB_MBALL: + str = "MBall"; + break; + case OB_MESH: + str = "Mesh"; + break; + case OB_SURF: + str = "Surf"; + break; + case OB_WAVE: + str = "Wave"; + break; + default: + str = "unknown"; + break; + } + + return PyString_FromString( str ); +} + +static PyObject *Object_getBoundBox( BPy_Object * self ) +{ + int i; + float *vec = NULL; + PyObject *vector, *bbox; + + if( !self->object->data ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "This object isn't linked to any object data (mesh, curve, etc) yet" ); + + if( !self->object->bb ) { /* if no ob bbox, we look in obdata */ + Mesh *me; + Curve *curve; + switch ( self->object->type ) { + case OB_MESH: + me = self->object->data; + vec = (float*) mesh_get_bb(me)->vec; + break; + case OB_CURVE: + case OB_FONT: + case OB_SURF: + curve = self->object->data; + if( !curve->bb ) + tex_space_curve( curve ); + vec = ( float * ) curve->bb->vec; + break; + default: + Py_RETURN_NONE; + } + + { /* transform our obdata bbox by the obmat. + the obmat is 4x4 homogeneous coords matrix. + each bbox coord is xyz, so we make it homogenous + by padding it with w=1.0 and doing the matrix mult. + afterwards we divide by w to get back to xyz. + */ + /* printmatrix4( "obmat", self->object->obmat); */ + + float tmpvec[4]; /* tmp vector for homogenous coords math */ + int i; + float *from; + + bbox = PyList_New( 8 ); + if( !bbox ) + return EXPP_ReturnPyObjError + ( PyExc_MemoryError, + "couldn't create pylist" ); + for( i = 0, from = vec; i < 8; i++, from += 3 ) { + memcpy( tmpvec, from, 3 * sizeof( float ) ); + tmpvec[3] = 1.0f; /* set w coord */ + Mat4MulVec4fl( self->object->obmat, tmpvec ); + /* divide x,y,z by w */ + tmpvec[0] /= tmpvec[3]; + tmpvec[1] /= tmpvec[3]; + tmpvec[2] /= tmpvec[3]; + +#if 0 + { /* debug print stuff */ + int i; + + printf( "\nobj bbox transformed\n" ); + for( i = 0; i < 4; ++i ) + printf( "%f ", tmpvec[i] ); + + printf( "\n" ); + } +#endif + + /* because our bounding box is calculated and + does not have its own memory, + we must create vectors that allocate space */ + + vector = newVectorObject( NULL, 3, Py_NEW); + memcpy( ( ( VectorObject * ) vector )->vec, + tmpvec, 3 * sizeof( float ) ); + PyList_SET_ITEM( bbox, i, vector ); + } + } + } else { /* the ob bbox exists */ + vec = ( float * ) self->object->bb->vec; + + if( !vec ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't retrieve bounding box data" ); + + bbox = PyList_New( 8 ); + + if( !bbox ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create pylist" ); + + /* create vectors referencing object bounding box coords */ + for( i = 0; i < 8; i++ ) { + vector = newVectorObject( vec, 3, Py_WRAP ); + PyList_SET_ITEM( bbox, i, vector ); + vec += 3; + } + } + + return bbox; +} + +static PyObject *Object_makeDisplayList( BPy_Object * self ) +{ + Object *ob = self->object; + + if( ob->type == OB_FONT ) { + Curve *cu = ob->data; + freedisplist( &cu->disp ); + text_to_curve( ob, 0 ); + } + + DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); + + Py_RETURN_NONE; +} + +static PyObject *Object_link( BPy_Object * self, PyObject * args ) +{ + PyObject *py_data; + ID *id; + ID *oldid; + int obj_id; + void *data = NULL; + int ok; + + if( !PyArg_ParseTuple( args, "O", &py_data ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected an object as argument" ); + + if( BPy_Armature_Check( py_data ) ) + data = ( void * ) PyArmature_AsArmature((BPy_Armature*)py_data); + else if( BPy_Camera_Check( py_data ) ) + data = ( void * ) Camera_FromPyObject( py_data ); + else if( BPy_Lamp_Check( py_data ) ) + data = ( void * ) Lamp_FromPyObject( py_data ); + else if( BPy_Curve_Check( py_data ) ) + data = ( void * ) Curve_FromPyObject( py_data ); + else if( BPy_NMesh_Check( py_data ) ) { + data = ( void * ) NMesh_FromPyObject( py_data, self->object ); + if( !data ) /* NULL means there is already an error */ + return NULL; + } else if( BPy_Mesh_Check( py_data ) ) + data = ( void * ) Mesh_FromPyObject( py_data, self->object ); + else if( BPy_Lattice_Check( py_data ) ) + data = ( void * ) Lattice_FromPyObject( py_data ); + else if( BPy_Metaball_Check( py_data ) ) + data = ( void * ) Metaball_FromPyObject( py_data ); + else if( BPy_Text3d_Check( py_data ) ) + data = ( void * ) Text3d_FromPyObject( py_data ); + + /* have we set data to something good? */ + if( !data ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "link argument type is not supported " ); + + oldid = ( ID * ) self->object->data; + id = ( ID * ) data; + obj_id = MAKE_ID2( id->name[0], id->name[1] ); + + /* if the object object has not been linked to real data before, we + * can now let it assume its real type */ + if( self->realtype != OB_EMPTY ) { + self->object->type = self->realtype; + self->realtype = OB_EMPTY; + } + + ok = 1; + switch ( obj_id ) { + case ID_AR: + if( self->object->type != OB_ARMATURE ) { + ok = 0; + } + break; + case ID_CA: + if( self->object->type != OB_CAMERA ) { + ok = 0; + } + break; + case ID_LA: + if( self->object->type != OB_LAMP ) { + ok = 0; + } + break; + case ID_ME: + if( self->object->type != OB_MESH ) { + ok = 0; + } + break; + case ID_CU: + if( self->object->type != OB_CURVE && self->object->type != OB_FONT ) { + ok = 0; + } + break; + case ID_LT: + if( self->object->type != OB_LATTICE ) { + ok = 0; + } + break; + case ID_MB: + if( self->object->type != OB_MBALL ) { + ok = 0; + } + break; + default: + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "Linking this object type is not supported" ); + } + + if( !ok ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "The 'link' object is incompatible with the base object" ); + self->object->data = data; + + /* creates the curve for the text object */ + if (self->object->type == OB_FONT) + text_to_curve(self->object, 0); + + id_us_plus( id ); + if( oldid ) { + if( oldid->us > 0 ) { + oldid->us--; + } else { + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "old object reference count below 0" ); + } + } + + /* make sure data and object materials are consistent */ + test_object_materials( id ); + + Py_RETURN_NONE; +} + +static PyObject *Object_makeParentVertex( BPy_Object * self, PyObject * args ) +{ + PyObject *list; + PyObject *vlist; + PyObject *py_child; + PyObject *ret_val; + Object *parent; + int noninverse = 0; + int fast = 0; + int partype; + int v1, v2=0, v3=0; + int i; + + /* Check if the arguments passed to makeParent are valid. */ + if( !PyArg_ParseTuple( args, "OO|ii", &list, &vlist, &noninverse, &fast ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a list of objects, a tuple of integers and one or two integers as arguments" ); + + if( !PySequence_Check( list ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a list of objects" ); + + if (!PyTuple_Check( vlist )) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a tuple of integers" ); + + switch( PyTuple_Size( vlist ) ) { + case 1: + if( !PyArg_ParseTuple( vlist, "i", &v1 ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a tuple of 1 or 3 integers" ); + + if ( v1 < 0 ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "indices must be strictly positive" ); + + partype = PARVERT1; + break; + case 3: + if( !PyArg_ParseTuple( vlist, "iii", &v1, &v2, &v3 ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a tuple of 1 or 3 integers" ); + + if ( v1 < 0 || v2 < 0 || v3 < 0) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "indices must be strictly positive" ); + partype = PARVERT3; + break; + default: + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a tuple of 1 or 3 integers" ); + } + + parent = ( Object * ) self->object; + + if (!ELEM3(parent->type, OB_MESH, OB_CURVE, OB_SURF)) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "Parent Vertex only applies to curve, mesh or surface objects" ); + + if (parent->id.us == 0) + return EXPP_ReturnPyObjError (PyExc_RuntimeError, + "object must be linked to a scene before it can become a parent"); + + /* Check if the PyObject passed in list is a Blender object. */ + for( i = 0; i < PySequence_Length( list ); i++ ) { + py_child = PySequence_GetItem( list, i ); + + ret_val = internal_makeParent(parent, py_child, partype, noninverse, fast, v1, v2, v3, NULL); + Py_DECREF (py_child); + + if (ret_val) + Py_DECREF(ret_val); + else { + if (!fast) /* need to sort when interrupting in the middle of the list */ + DAG_scene_sort( G.scene ); + return NULL; /* error has been set already */ + } + } + + if (!fast) /* otherwise, only sort at the end */ + DAG_scene_sort( G.scene ); + + Py_RETURN_NONE; +} + +static PyObject *Object_makeParentDeform( BPy_Object * self, PyObject * args ) +{ + PyObject *list; + PyObject *py_child; + PyObject *ret_val; + Object *parent; + int noninverse = 0; + int fast = 0; + int i; + + /* Check if the arguments passed to makeParent are valid. */ + if( !PyArg_ParseTuple( args, "O|ii", &list, &noninverse, &fast ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a list of objects and one or two integers as arguments" ); + + if( !PySequence_Check( list ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a list of objects" ); + + parent = ( Object * ) self->object; + + if (parent->type != OB_CURVE && parent->type != OB_ARMATURE) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "Parent Deform only applies to curve or armature objects" ); + + if (parent->id.us == 0) + return EXPP_ReturnPyObjError (PyExc_RuntimeError, + "object must be linked to a scene before it can become a parent"); + + /* Check if the PyObject passed in list is a Blender object. */ + for( i = 0; i < PySequence_Length( list ); i++ ) { + py_child = PySequence_GetItem( list, i ); + + ret_val = internal_makeParent(parent, py_child, PARSKEL, noninverse, fast, 0, 0, 0, NULL); + Py_DECREF (py_child); + + if (ret_val) + Py_DECREF(ret_val); + else { + if (!fast) /* need to sort when interupting in the middle of the list */ + DAG_scene_sort( G.scene ); + return NULL; /* error has been set already */ + } + } + + if (!fast) /* otherwise, only sort at the end */ + DAG_scene_sort( G.scene ); + + Py_RETURN_NONE; +} + + +static PyObject *Object_makeParentBone( BPy_Object * self, PyObject * args ) +{ + char *bonename; + PyObject *list; + PyObject *py_child; + PyObject *ret_val; + Object *parent; + int noninverse = 0; + int fast = 0; + int i; + + /* Check if the arguments passed to makeParent are valid. */ + if( !PyArg_ParseTuple( args, "Os|ii", &list, &bonename, &noninverse, &fast ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a list of objects, bonename and optionally two integers as arguments" ); + + parent = ( Object * ) self->object; + + if (parent->type != OB_ARMATURE) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "Parent Bone only applies to armature objects" ); + + if (parent->id.us == 0) + return EXPP_ReturnPyObjError (PyExc_RuntimeError, + "object must be linked to a scene before it can become a parent"); + + if (!parent->data) + return EXPP_ReturnPyObjError (PyExc_RuntimeError, + "object must be linked to armature data"); + + if (!get_named_bone(parent->data, bonename)) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "Parent Bone Name is not in the armature" ); + + /* Check if the PyObject passed in list is a Blender object. */ + for( i = 0; i < PySequence_Length( list ); i++ ) { + py_child = PySequence_GetItem( list, i ); + + ret_val = internal_makeParent(parent, py_child, PARBONE, noninverse, fast, 0, 0, 0, bonename); + Py_DECREF (py_child); + + if (ret_val) + Py_DECREF(ret_val); + else { + if (!fast) /* need to sort when interupting in the middle of the list */ + DAG_scene_sort( G.scene ); + return NULL; /* error has been set already */ + } + } + + if (!fast) /* otherwise, only sort at the end */ + DAG_scene_sort( G.scene ); + + Py_RETURN_NONE; +} + + +static PyObject *Object_makeParent( BPy_Object * self, PyObject * args ) +{ + PyObject *list; + PyObject *py_child; + PyObject *ret_val; + Object *parent; + int noninverse = 0; + int fast = 0; + int i; + + /* Check if the arguments passed to makeParent are valid. */ + if( !PyArg_ParseTuple( args, "O|ii", &list, &noninverse, &fast ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a list of objects and one or two integers as arguments" ); + + if( !PySequence_Check( list ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a list of objects" ); + + parent = ( Object * ) self->object; + + if (parent->id.us == 0) + return EXPP_ReturnPyObjError (PyExc_RuntimeError, + "object must be linked to a scene before it can become a parent"); + + /* Check if the PyObject passed in list is a Blender object. */ + for( i = 0; i < PySequence_Length( list ); i++ ) { + py_child = PySequence_GetItem( list, i ); + + ret_val = internal_makeParent(parent, py_child, PAROBJECT, noninverse, fast, 0, 0, 0, NULL); + Py_DECREF (py_child); + + if (ret_val) + Py_DECREF(ret_val); + else { + if (!fast) /* need to sort when interupting in the middle of the list */ + DAG_scene_sort( G.scene ); + return NULL; /* error has been set already */ + } + } + + if (!fast) /* otherwise, only sort at the end */ + DAG_scene_sort( G.scene ); + + Py_RETURN_NONE; +} + +static PyObject *Object_join( BPy_Object * self, PyObject * args ) +{ + PyObject *list; + PyObject *py_child; + Object *parent; + Object *child; + Scene *temp_scene; + Scene *orig_scene; + Base *temp_base; + short type; + int i, ok=0, ret_value=0, list_length=0; + + /* joining in background causes segfaults */ + if( G.background == 1 ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "cannot join objects in background mode" ); + + /* Check if the arguments passed to makeParent are valid. */ + if( !PyArg_ParseTuple( args, "O", &list ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a list of objects" ); + + if( !PySequence_Check( list ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a list of objects" ); + + list_length = PySequence_Length( list ); /* if there are no objects to join then exit silently */ + + if( !list_length ) { + Py_RETURN_NONE; + } + + parent = ( Object * ) self->object; + type = parent->type; + + /* Only these object types are sypported */ + if( type!=OB_MESH && type!=OB_CURVE && type!=OB_SURF && type!=OB_ARMATURE ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "Base object is not a type Blender can join" ); + + if( !object_in_scene( parent, G.scene ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "object must be in the current scene" ); + + /* exit editmode so join can be done */ + if( G.obedit ) + exit_editmode( EM_FREEDATA ); + + temp_scene = add_scene( "Scene" ); /* make the new scene */ + temp_scene->lay= 1; /* first layer on */ + + /* TODO: use EXPP_check_sequence_consistency here */ + + /* Check if the PyObject passed in list is a Blender object. */ + for( i = 0; i < list_length; i++ ) { + py_child = PySequence_GetItem( list, i ); + if( !BPy_Object_Check( py_child ) ) { + /* Cleanup */ + free_libblock( &G.main->scene, temp_scene ); + Py_DECREF( py_child ); + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a list of objects, one or more of the list items is not a Blender Object." ); + } else { + /* List item is an object, is it the same type? */ + child = ( Object * ) Object_FromPyObject( py_child ); + Py_DECREF( py_child ); + if( parent->type == child->type ) { + if( !object_in_scene( child, G.scene ) ) { + free_libblock( &G.main->scene, temp_scene ); + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "object must be in the current scene" ); + } + + ok =1; + /* Add a new base, then link the base to the temp_scene */ + temp_base = MEM_callocN( sizeof( Base ), "pynewbase" ); + /* we know these types are the same, link to the temp scene + * for joining */ + temp_base->object = child; /* link object to the new base */ + temp_base->flag |= SELECT; + temp_base->lay = 1; /*1 layer on */ + + BLI_addhead( &temp_scene->base, temp_base ); /* finally, link new base to scene */ + child->id.us += 1; /*Would usually increase user count but in this case it's ok not to */ + + /*DAG_object_flush_update(temp_scene, temp_base->object, OB_RECALC_DATA);*/ + } + } + } + + orig_scene = G.scene; /* backup our scene */ + + /* Add the main object into the temp_scene */ + temp_base = MEM_callocN( sizeof( Base ), "pynewbase" ); + temp_base->object = parent; /* link object to the new base */ + temp_base->flag |= SELECT; + temp_base->lay = 1; /*1 layer on */ + BLI_addhead( &temp_scene->base, temp_base ); /* finally, link new base to scene */ + parent->id.us += 1; + + /* all objects in the scene, set it active and the active object */ + set_scene( temp_scene ); + set_active_base( temp_base ); + + /* Do the joining now we know everythings OK. */ + if(type == OB_MESH) + ret_value = join_mesh(); + else if(type == OB_CURVE) + ret_value = join_curve(OB_CURVE); + else if(type == OB_SURF) + ret_value = join_curve(OB_SURF); + else if(type == OB_ARMATURE) + ret_value = join_armature(); + + /* May use this for correcting object user counts later on */ + /* + if (!ret_value) { + temp_base = temp_scene->base.first; + while( base ) { + object = base->object; + object->id.us +=1 + base = base->next; + } + }*/ + + /* remove old scene */ + set_scene( orig_scene ); + free_libblock( &G.main->scene, temp_scene ); + + /* no objects were of the correct type, return None */ + if (!ok) { + Py_RETURN_NONE; + } + + /* If the join failed then raise an error */ + if (!ret_value) + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, +"Blender failed to join the objects, this is not a script error.\n\ +Please add exception handling to your script with a RuntimeError exception\n\ +letting the user know that their data could not be joined." ) ); + + Py_RETURN_NONE; +} + +static PyObject *internal_makeParent(Object *parent, PyObject *py_child, + int partype, /* parenting type */ + int noninverse, int fast, /* parenting arguments */ + int v1, int v2, int v3, /* for vertex parent */ + char *bonename) /* for bone parents - assume the name is already checked to be a valid bone name*/ +{ + Object *child = NULL; + + if( BPy_Object_Check( py_child ) ) + child = ( Object * ) Object_FromPyObject( py_child ); + + if( child == NULL ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "Object Type expected" ); + + if( test_parent_loop( parent, child ) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "parenting loop detected - parenting failed" ); + + if (partype == PARSKEL && child->type != OB_MESH) + child->partype = PAROBJECT; + else + child->partype = (short)partype; + + if (partype == PARVERT3) { + child->par1 = v1; + child->par2 = v2; + child->par3 = v3; + } + else if (partype == PARVERT1) { + child->par1 = v1; + } else if (partype == PARBONE) { + strcpy( child->parsubstr, bonename ); + } + + + + child->parent = parent; + /* py_obj_child = (BPy_Object *) py_child; */ + if( noninverse == 1 ) { + Mat4One(child->parentinv); + /* Parent inverse = unity */ + child->loc[0] = 0.0; + child->loc[1] = 0.0; + child->loc[2] = 0.0; + } else { + what_does_parent( child ); + Mat4Invert( child->parentinv, workob.obmat ); + clear_workob(); + } + + if( !fast ) + child->recalc |= OB_RECALC_OB; + + Py_RETURN_NONE; +} + +static PyObject *Object_materialUsage( void ) +{ + return EXPP_ReturnPyObjError( PyExc_NotImplementedError, + "materialUsage: not yet implemented" ); +} + +static PyObject *Object_setDeltaLocation( BPy_Object * self, PyObject * args ) +{ + float dloc1; + float dloc2; + float dloc3; + int status; + + if( PyObject_Length( args ) == 3 ) + status = PyArg_ParseTuple( args, "fff", &dloc1, &dloc2, + &dloc3 ); + else + status = PyArg_ParseTuple( args, "(fff)", &dloc1, &dloc2, + &dloc3 ); + + if( !status ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected sequence argument of 3 floats" ); + + self->object->dloc[0] = dloc1; + self->object->dloc[1] = dloc2; + self->object->dloc[2] = dloc3; + + /* since we have messed with object, we need to flag for DAG recalc */ + self->object->recalc |= OB_RECALC_OB; + + Py_RETURN_NONE; +} + +#define DTX_MASK ( OB_AXIS | OB_TEXSPACE | OB_DRAWNAME | \ + OB_DRAWIMAGE | OB_DRAWWIRE | OB_DRAWXRAY | OB_DRAWTRANSP ) + +static PyObject *Object_getDrawMode( BPy_Object * self ) +{ + return PyInt_FromLong( (long)(self->object->dtx & DTX_MASK) ); +} + +static int Object_setDrawMode( BPy_Object * self, PyObject * args ) +{ + PyObject* integer = PyNumber_Int( args ); + int value; + + if( !integer ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected integer argument" ); + + value = ( int )PyInt_AS_LONG( integer ); + Py_DECREF( integer ); + if( value & ~DTX_MASK ) + return EXPP_ReturnIntError( PyExc_ValueError, + "undefined bit(s) set in bitfield" ); + + self->object->dtx = value; + self->object->recalc |= OB_RECALC_OB; + + return 0; +} + +static PyObject *Object_getDrawType( BPy_Object * self ) +{ + return PyInt_FromLong( (long)self->object->dt ); +} + +static int Object_setDrawType( BPy_Object * self, PyObject * value ) +{ + /* since we mess with object, we need to flag for DAG recalc */ + self->object->recalc |= OB_RECALC_OB; + + return EXPP_setIValueRange( value, &self->object->dt, + OB_BOUNDBOX, OB_TEXTURE, 'b' ); +} + +static int Object_setEuler( BPy_Object * self, PyObject * args ) +{ + float rot1, rot2, rot3; + int status = 0; /* failure */ + + if( PyTuple_Check( args ) && PyTuple_Size( args ) == 1 ) + args = PyTuple_GET_ITEM( args, 0 ); + + if( EulerObject_Check( args ) ) { + rot1 = ( ( EulerObject * ) args )->eul[0]; + rot2 = ( ( EulerObject * ) args )->eul[1]; + rot3 = ( ( EulerObject * ) args )->eul[2]; + status = 1; + } else if( PySequence_Check( args ) && PySequence_Size( args ) == 3 ) { + if( PyList_Check( args ) ) + args = PySequence_Tuple( args ); + else + Py_INCREF( args ); + status = PyArg_ParseTuple( args, "fff", &rot1, &rot2, &rot3 ); + Py_DECREF( args ); + } + + if( !status ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected euler or sequence of 3 floats" ); + + self->object->rot[0] = rot1; + self->object->rot[1] = rot2; + self->object->rot[2] = rot3; + + /* since we have messed with object, we need to flag for DAG recalc */ + self->object->recalc |= OB_RECALC_OB; + + return 0; +} + +static int Object_setMatrix( BPy_Object * self, MatrixObject * mat ) +#if 0 +{ + int x, y; + + if( !MatrixObject_Check( mat ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected matrix object as argument" ); + + if( mat->rowSize == 4 && mat->colSize == 4 ) { + for( x = 0; x < 4; x++ ) { + for( y = 0; y < 4; y++ ) { + self->object->obmat[x][y] = mat->matrix[x][y]; + } + } + } else if( mat->rowSize == 3 && mat->colSize == 3 ) { + for( x = 0; x < 3; x++ ) { + for( y = 0; y < 3; y++ ) { + self->object->obmat[x][y] = mat->matrix[x][y]; + } + } + /* if a 3x3 matrix, clear the fourth row/column */ + for( x = 0; x < 3; x++ ) + self->object->obmat[x][3] = self->object->obmat[3][x] = 0.0; + self->object->obmat[3][3] = 1.0; + } else + return EXPP_ReturnIntError( PyExc_ValueError, + "expected 3x3 or 4x4 matrix" ); + + apply_obmat( self->object ); + + /* since we have messed with object, we need to flag for DAG recalc */ + self->object->recalc |= OB_RECALC_OB; + + return 0; +} +#endif +{ + int x, y; + float matrix[4][4]; /* for the result */ + float invmat[4][4]; /* for the result */ + + if( !MatrixObject_Check( mat ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected matrix object as argument" ); + + if( mat->rowSize == 4 && mat->colSize == 4 ) { + for( x = 0; x < 4; x++ ) { + for( y = 0; y < 4; y++ ) { + matrix[x][y] = mat->matrix[x][y]; + } + } + } else if( mat->rowSize == 3 && mat->colSize == 3 ) { + for( x = 0; x < 3; x++ ) { + for( y = 0; y < 3; y++ ) { + matrix[x][y] = mat->matrix[x][y]; + } + } + /* if a 3x3 matrix, clear the fourth row/column */ + for( x = 0; x < 3; x++ ) + matrix[x][3] = matrix[3][x] = 0.0; + matrix[3][3] = 1.0; + } else + return EXPP_ReturnIntError( PyExc_ValueError, + "expected 3x3 or 4x4 matrix" ); + + /* localspace matrix is truly relative to the parent, but parameters + * stored in object are relative to parentinv matrix. Undo the parent + * inverse part before updating obmat and calling apply_obmat() */ + if( self->object->parent ) { + Mat4Invert( invmat, self->object->parentinv ); + Mat4MulMat4( self->object->obmat, matrix, invmat ); + } else + Mat4CpyMat4( self->object->obmat, matrix ); + + apply_obmat( self->object ); + + /* since we have messed with object, we need to flag for DAG recalc */ + self->object->recalc |= OB_RECALC_OB; + + return 0; +} + + +/* + * Object_insertIpoKey() + * inserts Object IPO key for LOC, ROT, SIZE, LOCROT, or LOCROTSIZE + * Note it also inserts actions! + */ + +static PyObject *Object_insertIpoKey( BPy_Object * self, PyObject * args ) +{ + Object *ob= self->object; + int key = 0; + char *actname= NULL; + + if( !PyArg_ParseTuple( args, "i", &key ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument" ); + + if(ob->ipoflag & OB_ACTION_OB) + actname= "Object"; + + if (key == IPOKEY_LOC || key == IPOKEY_LOCROT || key == IPOKEY_LOCROTSIZE){ + insertkey((ID *)ob, ID_OB, actname, NULL,OB_LOC_X, 0); + insertkey((ID *)ob, ID_OB, actname, NULL,OB_LOC_Y, 0); + insertkey((ID *)ob, ID_OB, actname, NULL,OB_LOC_Z, 0); + } + if (key == IPOKEY_ROT || key == IPOKEY_LOCROT || key == IPOKEY_LOCROTSIZE){ + insertkey((ID *)ob, ID_OB, actname, NULL,OB_ROT_X, 0); + insertkey((ID *)ob, ID_OB, actname, NULL,OB_ROT_Y, 0); + insertkey((ID *)ob, ID_OB, actname, NULL,OB_ROT_Z, 0); + } + if (key == IPOKEY_SIZE || key == IPOKEY_LOCROTSIZE ){ + insertkey((ID *)ob, ID_OB, actname, NULL,OB_SIZE_X, 0); + insertkey((ID *)ob, ID_OB, actname, NULL,OB_SIZE_Y, 0); + insertkey((ID *)ob, ID_OB, actname, NULL,OB_SIZE_Z, 0); + } + + if (key == IPOKEY_PI_STRENGTH ){ + insertkey((ID *)ob, ID_OB, actname, NULL, OB_PD_FSTR, 0); + } else if (key == IPOKEY_PI_FALLOFF ){ + insertkey((ID *)ob, ID_OB, actname, NULL, OB_PD_FFALL, 0); + } else if (key == IPOKEY_PI_SURFACEDAMP ){ + insertkey((ID *)ob, ID_OB, actname, NULL, OB_PD_SDAMP, 0); + } else if (key == IPOKEY_PI_RANDOMDAMP ){ + insertkey((ID *)ob, ID_OB, actname, NULL, OB_PD_RDAMP, 0); + } else if (key == IPOKEY_PI_PERM ){ + insertkey((ID *)ob, ID_OB, actname, NULL, OB_PD_PERM, 0); + } + + allspace(REMAKEIPO, 0); + EXPP_allqueue(REDRAWIPO, 0); + EXPP_allqueue(REDRAWVIEW3D, 0); + EXPP_allqueue(REDRAWACTION, 0); + EXPP_allqueue(REDRAWNLA, 0); + + Py_RETURN_NONE; +} + +/* + * Object_insertPoseKey() + * inserts a Action Pose key from a given pose (sourceaction, frame) to the + * active action to a given framenum + */ + +static PyObject *Object_insertPoseKey( BPy_Object * self, PyObject * args ) +{ + Object *ob= self->object; + BPy_Action *sourceact; + char *chanName; + int actframe; + + + /* for doing the time trick, similar to editaction bake_action_with_client() */ + int oldframe; + int curframe; + + if( !PyArg_ParseTuple( args, "O!sii", &Action_Type, &sourceact, + &chanName, &actframe, &curframe ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expects an action to copy poses from, a string for chan/bone name, an int argument for frame to extract from the action and finally another int for the frame where to put the new key in the active object.action" ); + + extract_pose_from_action(ob->pose, sourceact->action, (float)actframe); + + oldframe = G.scene->r.cfra; + G.scene->r.cfra = curframe; + + /* XXX: must check chanName actually exists, otherwise segfaults! */ + //achan = get_action_channel(sourceact->action, chanName); + + insertkey(&ob->id, ID_PO, chanName, NULL, AC_LOC_X, 0); + insertkey(&ob->id, ID_PO, chanName, NULL, AC_LOC_Y, 0); + insertkey(&ob->id, ID_PO, chanName, NULL, AC_LOC_Z, 0); + insertkey(&ob->id, ID_PO, chanName, NULL, AC_QUAT_X, 0); + insertkey(&ob->id, ID_PO, chanName, NULL, AC_QUAT_Y, 0); + insertkey(&ob->id, ID_PO, chanName, NULL, AC_QUAT_Z, 0); + insertkey(&ob->id, ID_PO, chanName, NULL, AC_QUAT_W, 0); + insertkey(&ob->id, ID_PO, chanName, NULL, AC_SIZE_X, 0); + insertkey(&ob->id, ID_PO, chanName, NULL, AC_SIZE_Y, 0); + insertkey(&ob->id, ID_PO, chanName, NULL, AC_SIZE_Z, 0); + + G.scene->r.cfra = oldframe; + + allspace(REMAKEIPO, 0); + EXPP_allqueue(REDRAWIPO, 0); + EXPP_allqueue(REDRAWVIEW3D, 0); + EXPP_allqueue(REDRAWACTION, 0); + EXPP_allqueue(REDRAWNLA, 0); + + /* restore, but now with the new action in place */ + /*extract_pose_from_action(ob->pose, ob->action, G.scene->r.cfra); + where_is_pose(ob);*/ + + EXPP_allqueue(REDRAWACTION, 1); + + Py_RETURN_NONE; +} + +static PyObject *Object_insertCurrentPoseKey( BPy_Object * self, PyObject * args ) +{ + Object *ob= self->object; + char *chanName; + + /* for doing the time trick, similar to editaction bake_action_with_client() */ + int oldframe; + int curframe; + + if( !PyArg_ParseTuple( args, "si", &chanName, &curframe ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected chan/bone name, and a time (int) argument" ); + + oldframe = G.scene->r.cfra; + G.scene->r.cfra = curframe; + + /* XXX: must check chanName actually exists, otherwise segfaults! */ + + insertkey(&ob->id, ID_PO, chanName, NULL, AC_LOC_X, 0); + insertkey(&ob->id, ID_PO, chanName, NULL, AC_LOC_Y, 0); + insertkey(&ob->id, ID_PO, chanName, NULL, AC_LOC_Z, 0); + insertkey(&ob->id, ID_PO, chanName, NULL, AC_QUAT_X, 0); + insertkey(&ob->id, ID_PO, chanName, NULL, AC_QUAT_Y, 0); + insertkey(&ob->id, ID_PO, chanName, NULL, AC_QUAT_Z, 0); + insertkey(&ob->id, ID_PO, chanName, NULL, AC_QUAT_W, 0); + insertkey(&ob->id, ID_PO, chanName, NULL, AC_SIZE_X, 0); + insertkey(&ob->id, ID_PO, chanName, NULL, AC_SIZE_Y, 0); + insertkey(&ob->id, ID_PO, chanName, NULL, AC_SIZE_Z, 0); + + G.scene->r.cfra = oldframe; + + allspace(REMAKEIPO, 0); + EXPP_allqueue(REDRAWIPO, 0); + EXPP_allqueue(REDRAWVIEW3D, 0); + EXPP_allqueue(REDRAWACTION, 0); + EXPP_allqueue(REDRAWNLA, 0); + + /* restore */ + extract_pose_from_action(ob->pose, ob->action, (float)G.scene->r.cfra); + where_is_pose(ob); + + EXPP_allqueue(REDRAWACTION, 1); + + Py_RETURN_NONE; +} + +static PyObject *Object_setConstraintInfluenceForBone( BPy_Object * self, + PyObject * args ) +{ + char *boneName, *constName; + float influence; + IpoCurve *icu; + + if( !PyArg_ParseTuple( args, "ssf", &boneName, &constName, &influence ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expects bonename, constraintname, influenceval" ); + + icu = verify_ipocurve((ID *)self->object, ID_CO, boneName, constName, + CO_ENFORCE); + + if (!icu) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "cannot get a curve from this IPO, may be using libdata" ); + + insert_vert_icu(icu, (float)CFRA, influence, 0); + self->object->recalc |= OB_RECALC_OB; + + Py_RETURN_NONE; +} + +static PyObject *Object_copyNLA( BPy_Object * self, PyObject * args ) { + BPy_Object *bpy_fromob; + + if( !PyArg_ParseTuple( args, "O", &bpy_fromob ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "requires a Blender Object to copy NLA strips from." ); + copy_nlastrips(&self->object->nlastrips, &bpy_fromob->object->nlastrips); + self->object->recalc |= OB_RECALC_OB; + + Py_RETURN_NONE; +} + +/*Now that BPY has a Strip type, return the created strip.*/ +static PyObject *Object_convertActionToStrip( BPy_Object * self ) +{ + bActionStrip *strip = convert_action_to_strip( self->object ); + return ActionStrip_CreatePyObject( strip ); +} + +static PyObject *Object_setLocation( BPy_Object * self, PyObject * args ) +{ + float loc1; + float loc2; + float loc3; + int status; + + if( PyObject_Length( args ) == 3 ) + status = PyArg_ParseTuple( args, "fff", &loc1, &loc2, &loc3 ); + else + status = PyArg_ParseTuple( args, "(fff)", &loc1, &loc2, + &loc3 ); + + if( !status ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected list argument of 3 floats" ); + + self->object->loc[0] = loc1; + self->object->loc[1] = loc2; + self->object->loc[2] = loc3; + + /* since we have messed with object, we need to flag for DAG recalc */ + self->object->recalc |= OB_RECALC_OB; + DAG_object_flush_update(G.scene, self->object, OB_RECALC_DATA); + + Py_RETURN_NONE; +} + +static PyObject *Object_setMaterials( BPy_Object * self, PyObject * args ) +{ + PyObject *list; + int len; + int i; + Material **matlist = NULL; + + if (!self->object->data) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "object must be linked to object data (e.g. to a mesh) first" ); + + if( !PyArg_ParseTuple( args, "O!", &PyList_Type, &list ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a list (of materials or None) as argument" ); + + len = PyList_Size(list); + + /* Object_getMaterials can return '[]' (zero-length list), so that must + * also be accepted by this method for + * ob2.setMaterials(ob1.getMaterials()) to always work. + * In other words, list can be '[]' and so len can be zero. */ + if (len > 0) { + if( len > MAXMAT ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "list must have from 1 up to 16 materials" ); + + matlist = EXPP_newMaterialList_fromPyList( list ); + if( !matlist ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "material list must be a list of valid materials!" ); + } + + if( self->object->mat ) + EXPP_releaseMaterialList( self->object->mat, self->object->totcol ); + + /* Increase the user count on all materials */ + for( i = 0; i < len; i++ ) { + if( matlist[i] ) + id_us_plus( ( ID * ) matlist[i] ); + } + self->object->mat = matlist; + self->object->totcol = (char)len; + self->object->actcol = (char)len; + + switch ( self->object->type ) { + case OB_CURVE: /* fall through */ + case OB_FONT: /* fall through */ + case OB_MESH: /* fall through */ + case OB_MBALL: /* fall through */ + case OB_SURF: + EXPP_synchronizeMaterialLists( self->object ); + break; + default: + break; + } + + /* since we have messed with object, we need to flag for DAG recalc */ + self->object->recalc |= OB_RECALC_OB; + + Py_RETURN_NONE; +} + +static PyObject *Object_setSize( BPy_Object * self, PyObject * args ) +{ + float sizex; + float sizey; + float sizez; + int status; + + if( PyObject_Length( args ) == 3 ) + status = PyArg_ParseTuple( args, "fff", &sizex, &sizey, + &sizez ); + else + status = PyArg_ParseTuple( args, "(fff)", &sizex, &sizey, + &sizez ); + + if( !status ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected list argument of 3 floats" ); + + self->object->size[0] = sizex; + self->object->size[1] = sizey; + self->object->size[2] = sizez; + + /* since we have messed with object, we need to flag for DAG recalc */ + self->object->recalc |= OB_RECALC_OB; + + Py_RETURN_NONE; +} + +static PyObject *Object_makeTrack( BPy_Object * self, PyObject * args ) +{ + BPy_Object *tracked = NULL; + Object *ob = self->object; + int fast = 0; + + if( !PyArg_ParseTuple( args, "O!|i", &Object_Type, &tracked, &fast ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected an object and optionally also an int as arguments." ); + + ob->track = tracked->object; + + if( !fast ) + DAG_scene_sort( G.scene ); + + Py_RETURN_NONE; +} + +static PyObject *Object_shareFrom( BPy_Object * self, PyObject * args ) +{ + BPy_Object *object; + ID *id; + ID *oldid; + + if( !PyArg_ParseTuple( args, "O!", &Object_Type, &object ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected an object argument" ); + + if( !object->object->data ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "Object argument has no data linked yet or is an empty" ); + + if( self->object->type != object->object->type && + self->realtype != object->object->type) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "objects are not of same data type" ); + + switch ( object->object->type ) { + case OB_MESH: + case OB_LAMP: + case OB_CAMERA: /* we can probably add the other types, too */ + case OB_ARMATURE: + case OB_CURVE: + case OB_SURF: + case OB_LATTICE: + + /* if this object had no data, we need to enable the realtype */ + if (self->object->type == OB_EMPTY) { + self->object->type= self->realtype; + self->realtype = OB_EMPTY; + } + + oldid = ( ID * ) self->object->data; + id = ( ID * ) object->object->data; + self->object->data = object->object->data; + + if( self->object->type == OB_MESH && id ) { + self->object->totcol = 0; + EXPP_synchronizeMaterialLists( self->object ); + } + + id_us_plus( id ); + if( oldid ) { + if( oldid->us > 0 ) { + oldid->us--; + } else { + return EXPP_ReturnPyObjError ( PyExc_RuntimeError, + "old object reference count below 0" ); + } + } + + Py_RETURN_NONE; + default: + return EXPP_ReturnPyObjError( PyExc_ValueError, + "object type not supported" ); + } +} + +static PyObject *Object_getAllProperties( BPy_Object * self ) +{ + PyObject *prop_list, *pyval; + bProperty *prop = NULL; + + prop_list = PyList_New( 0 ); + + prop = self->object->prop.first; + while( prop ) { + pyval = Property_CreatePyObject( prop ); + PyList_Append( prop_list, pyval ); + Py_DECREF(pyval); + prop = prop->next; + } + return prop_list; +} + +static PyObject *Object_getProperty( BPy_Object * self, PyObject * args ) +{ + char *prop_name = NULL; + bProperty *prop = NULL; + + if( !PyArg_ParseTuple( args, "s", &prop_name ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a string" ); + + prop = get_property( self->object, prop_name ); + if( prop ) + return Property_CreatePyObject( prop ); + + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't find the property" ); +} + +static PyObject *Object_addProperty( BPy_Object * self, PyObject * args ) +{ + bProperty *prop = NULL; + char *prop_name = NULL; + PyObject *prop_data = Py_None; + char *prop_type = NULL; + short type = -1; + BPy_Property *py_prop = NULL; + int argslen = PyObject_Length( args ); + + if( argslen == 3 || argslen == 2 ) { + if( !PyArg_ParseTuple( args, "sO|s", &prop_name, &prop_data, + &prop_type ) ) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expecting string, data, and optional string" ); + } + } else if( argslen == 1 ) { + if( !PyArg_ParseTuple( args, "O!", &property_Type, &py_prop ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expecting a Property" ); + + if( py_prop->property != NULL ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "Property is already added to an object" ); + } else { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected 1,2 or 3 arguments" ); + } + + /*parse property type*/ + if( !py_prop ) { + if( prop_type ) { + if( BLI_streq( prop_type, "BOOL" ) ) + type = PROP_BOOL; + else if( BLI_streq( prop_type, "INT" ) ) + type = PROP_INT; + else if( BLI_streq( prop_type, "FLOAT" ) ) + type = PROP_FLOAT; + else if( BLI_streq( prop_type, "TIME" ) ) + type = PROP_TIME; + else if( BLI_streq( prop_type, "STRING" ) ) + type = PROP_STRING; + else + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "BOOL, INT, FLOAT, TIME or STRING expected" ); + } else { + /*use the default*/ + if( PyInt_Check( prop_data ) ) + type = PROP_INT; + else if( PyFloat_Check( prop_data ) ) + type = PROP_FLOAT; + else if( PyString_Check( prop_data ) ) + type = PROP_STRING; + } + } else { + type = py_prop->type; + } + + /*initialize a new bProperty of the specified type*/ + prop = new_property( type ); + + /*parse data*/ + if( !py_prop ) { + BLI_strncpy( prop->name, prop_name, 32 ); + if( PyInt_Check( prop_data ) ) { + *( ( int * ) &prop->data ) = + ( int ) PyInt_AsLong( prop_data ); + } else if( PyFloat_Check( prop_data ) ) { + *( ( float * ) &prop->data ) = + ( float ) PyFloat_AsDouble( prop_data ); + } else if( PyString_Check( prop_data ) ) { + BLI_strncpy( prop->poin, + PyString_AsString( prop_data ), + MAX_PROPSTRING ); + } + } else { + py_prop->property = prop; + + /* this should never be able to happen is we just assigned a valid + * proper to py_prop->property */ + + if( !updateProperyData( py_prop ) ) { + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Could not update property data" ); + } + } + + /*add to property listbase for the object*/ + BLI_addtail( &self->object->prop, prop ); + + Py_RETURN_NONE; +} + +static PyObject *Object_removeProperty( BPy_Object * self, PyObject * args ) +{ + char *prop_name = NULL; + BPy_Property *py_prop = NULL; + bProperty *prop = NULL; + + /* we accept either a property stringname or actual object */ + if( PyTuple_Size( args ) == 1 ) { + PyObject *prop = PyTuple_GET_ITEM( args, 0 ); + if( BPy_Property_Check( prop ) ) + py_prop = (BPy_Property *)prop; + else + prop_name = PyString_AsString( prop ); + } + if( !py_prop && !prop_name ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a Property or a string" ); + + /*remove the link, free the data, and update the py struct*/ + if( py_prop ) { + BLI_remlink( &self->object->prop, py_prop->property ); + if( updatePyProperty( py_prop ) ) { + free_property( py_prop->property ); + py_prop->property = NULL; + } + } else { + prop = get_property( self->object, prop_name ); + if( prop ) { + BLI_remlink( &self->object->prop, prop ); + free_property( prop ); + } + } + Py_RETURN_NONE; +} + +static PyObject *Object_removeAllProperties( BPy_Object * self ) +{ + free_properties( &self->object->prop ); + Py_RETURN_NONE; +} + +static PyObject *Object_copyAllPropertiesTo( BPy_Object * self, + PyObject * args ) +{ + PyObject *dest; + bProperty *prop = NULL; + bProperty *propn = NULL; + + if( !PyArg_ParseTuple( args, "O!", &Object_Type, &dest ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected an Object" ); + + /*make a copy of all its properties*/ + prop = self->object->prop.first; + while( prop ) { + propn = copy_property( prop ); + BLI_addtail( &( ( BPy_Object * ) dest )->object->prop, propn ); + prop = prop->next; + } + + Py_RETURN_NONE; +} + +static PyObject *Object_addScriptLink( BPy_Object * self, PyObject * args ) +{ + Object *obj = self->object; + ScriptLink *slink = &obj->scriptlink; + return EXPP_addScriptLink( slink, args, 0 ); +} + +static PyObject *Object_clearScriptLinks( BPy_Object * self, PyObject * args ) +{ + Object *obj = self->object; + ScriptLink *slink = &obj->scriptlink; + return EXPP_clearScriptLinks( slink, args ); +} + +static PyObject *Object_getScriptLinks( BPy_Object * self, PyObject * value ) +{ + Object *obj = self->object; + ScriptLink *slink = &obj->scriptlink; + return EXPP_getScriptLinks( slink, value, 0 ); +} + +static PyObject *Object_getNLAflagBits ( BPy_Object * self ) +{ + if (self->object->nlaflag & OB_NLA_OVERRIDE) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +static int Object_setNLAflagBits ( BPy_Object * self, PyObject * value ) +{ + int param; + + param = PyObject_IsTrue( value ); + if( param == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected True/False or 0/1" ); + + if (param) + self->object->nlaflag |= OB_NLA_OVERRIDE; + else + self->object->nlaflag &= ~OB_NLA_OVERRIDE; + + self->object->recalc |= OB_RECALC_OB; + + return 0; +} + +static PyObject *Object_getDupliObjects( BPy_Object * self ) +{ + Object *ob= self->object; + + if(ob->transflag & OB_DUPLI) { + /* before make duplis, update particle for current frame */ + if(ob->transflag & OB_DUPLIVERTS) { + PartEff *paf= give_parteff(ob); + if(paf) { + if(paf->flag & PAF_ANIMATED) build_particle_system(ob); + } + } + if(ob->type!=OB_MBALL) { + PyObject *list; + DupliObject *dupob; + int index; + ListBase *duplilist = object_duplilist(G.scene, ob); + + list = PyList_New( BLI_countlist(duplilist) ); + if( !list ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyList_New() failed" ); + + for(dupob= duplilist->first, index=0; dupob; dupob= dupob->next, index++) { + PyObject *pair; + pair = PyTuple_New( 2 ); + + PyTuple_SET_ITEM( pair, 0, Object_CreatePyObject(dupob->ob) ); + PyTuple_SET_ITEM( pair, 1, newMatrixObject((float*)dupob->mat,4,4,Py_NEW) ); + PyList_SET_ITEM( list, index, pair); + } + free_object_duplilist(duplilist); + return list; + } + } + return PyList_New( 0 ); +} + +static PyObject *Object_getDupliGroup( BPy_Object * self ) +{ + Object *ob= self->object; + + if( ob->dup_group ) + return Group_CreatePyObject( ob->dup_group ); + + Py_RETURN_NONE; +} + +static int Object_setDupliGroup( BPy_Object * self, PyObject * value ) +{ + return GenericLib_assignData(value, (void **) &self->object->dup_group, 0, 1, ID_GR, 0); +} + +static PyObject *Object_getEffects( BPy_Object * self ) +{ + PyObject *effect_list, *pyval; + Effect *eff; + + effect_list = PyList_New( 0 ); + if( !effect_list ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyList_New() failed" ); + + eff = self->object->effect.first; + + while( eff ) { + pyval = EffectCreatePyObject( eff, self->object ); + PyList_Append( effect_list, pyval ); + Py_DECREF(pyval); + eff = eff->next; + } + return effect_list; +} + +static PyObject *Object_getActionStrips( BPy_Object * self ) +{ + return ActionStrips_CreatePyObject( self->object ); +} + +static PyObject *Object_getConstraints( BPy_Object * self ) +{ + return ObConstraintSeq_CreatePyObject( self->object ); +} + +static PyObject *Object_getModifiers( BPy_Object * self ) +{ + return ModSeq_CreatePyObject( self->object, NULL ); +} + +static int Object_setModifiers( BPy_Object * self, PyObject * value ) +{ + BPy_ModSeq *pymodseq; + ModifierData *md; + + if (!BPy_ModSeq_Check(value)) + return EXPP_ReturnIntError( PyExc_TypeError, + "can only assign another objects modifiers" ); + + pymodseq = ( BPy_ModSeq * ) value; + + if (self->object->type != pymodseq->object->type) + return EXPP_ReturnIntError( PyExc_TypeError, + "can only assign modifiers between objects of the same type" ); + + if (self->object == pymodseq->object) + return 0; + + object_free_modifiers(self->object); + for (md=pymodseq->object->modifiers.first; md; md=md->next) { + if (md->type!=eModifierType_Hook) { + ModifierData *nmd = modifier_new(md->type); + modifier_copyData(md, nmd); + BLI_addtail(&self->object->modifiers, nmd); + } + } + + DAG_object_flush_update(G.scene, self->object, OB_RECALC_DATA); + return 0; +} + +static PyObject *Object_insertShapeKey(BPy_Object * self) +{ + insert_shapekey(self->object); + Py_RETURN_NONE; +} + +/* __copy__() */ +static PyObject *Object_copy(BPy_Object * self) +{ + /* copy_object never returns NULL */ + struct Object *object= copy_object( self->object ); + object->id.us= 0; /*is 1 by default, not sure why */ + + /* Create a Python object from it. */ + return Object_CreatePyObject( object ); +} + +/*****************************************************************************/ +/* Function: Object_CreatePyObject */ +/* Description: This function will create a new BlenObject from an existing */ +/* Object structure. */ +/*****************************************************************************/ +PyObject *Object_CreatePyObject( struct Object * obj ) +{ + BPy_Object *blen_object; + + if( !obj ) Py_RETURN_NONE; + + blen_object = + ( BPy_Object * ) PyObject_NEW( BPy_Object, &Object_Type ); + + if( blen_object == NULL ) { + return ( NULL ); + } + blen_object->object = obj; + blen_object->realtype = OB_EMPTY; + obj->id.us++; + return ( ( PyObject * ) blen_object ); +} + +/*****************************************************************************/ +/* Function: Object_FromPyObject */ +/* Description: This function returns the Blender object from the given */ +/* PyObject. */ +/*****************************************************************************/ +struct Object *Object_FromPyObject( PyObject * py_obj ) +{ + BPy_Object *blen_obj; + + blen_obj = ( BPy_Object * ) py_obj; + return ( blen_obj->object ); +} + +/*****************************************************************************/ +/* Function: Object_dealloc */ +/* Description: This is a callback function for the BlenObject type. It is */ +/* the destructor function. */ +/*****************************************************************************/ +static void Object_dealloc( BPy_Object * self ) +{ + if( self->realtype != OB_EMPTY ) + free_libblock_us( &G.main->object, self->object ); + else + self->object->id.us--; + +#if 0 /* this will adjust the ID and if zero delete the object */ + free_libblock_us( &G.main->object, self->object ); +#endif + PyObject_DEL( self ); +} + +/*****************************************************************************/ +/* Function: Object_compare */ +/* Description: This is a callback function for the BPy_Object type. It */ +/* compares two Object_Type objects. Only the "==" and "!=" */ +/* comparisons are meaninful. Returns 0 for equality and -1 if */ +/* they don't point to the same Blender Object struct. */ +/* In Python it becomes 1 if they are equal, 0 otherwise. */ +/*****************************************************************************/ +static int Object_compare( BPy_Object * a, BPy_Object * b ) +{ + return ( a->object == b->object ) ? 0 : -1; +} + +/*****************************************************************************/ +/* Function: Object_repr */ +/* Description: This is a callback function for the BPy_Object type. It */ +/* builds a meaninful string to represent object objects. */ +/*****************************************************************************/ +static PyObject *Object_repr( BPy_Object * self ) +{ + return PyString_FromFormat( "[Object \"%s\"]", + self->object->id.name + 2 ); +} + +/* Particle Deflection functions */ + +static PyObject *Object_getPIDeflection( BPy_Object * self ) +{ + if( !self->object->pd && !setupPI(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "particle deflection could not be accessed" ); + + return PyBool_FromLong( ( long ) self->object->pd->deflect ); +} + +static int Object_setPIDeflection( BPy_Object * self, PyObject * value ) +{ + int param; + + if( !self->object->pd && !setupPI(self->object) ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "particle deflection could not be accessed" ); + + param = PyObject_IsTrue( value ); + if( param == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected true/false argument" ); + + self->object->pd->deflect = (short)param; + self->object->recalc |= OB_RECALC_OB; + + return 0; +} + +static PyObject *Object_getPIType( BPy_Object * self ) +{ + if( !self->object->pd && !setupPI(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "particle deflection could not be accessed" ); + + return PyInt_FromLong( ( long )self->object->pd->forcefield ); +} + +static int Object_setPIType( BPy_Object * self, PyObject * value ) +{ + int status; + int oldforcefield; + + if( !self->object->pd && !setupPI(self->object) ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "particle deflection could not be accessed" ); + + oldforcefield = self->object->pd->forcefield; + status = EXPP_setIValueRange( value, &self->object->pd->forcefield, + PFIELD_FORCE, PFIELD_GUIDE, 'h' ); + + /* + * if value was set successfully but is PFIELD_MAGNET, restore the old + * value and throw exception + */ + if( !status ) { + if ( self->object->pd->forcefield == PFIELD_MAGNET ) { + self->object->pd->forcefield = oldforcefield; + return EXPP_ReturnIntError( PyExc_ValueError, + "PFIELD_MAGNET not supported" ); + } + self->object->recalc |= OB_RECALC_OB; + } + return status; +} + +static PyObject *Object_getPIUseMaxDist( BPy_Object * self ) +{ + if( !self->object->pd && !setupPI(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "particle deflection could not be accessed" ); + + return PyBool_FromLong( ( long )self->object->pd->flag ); +} + +static int Object_setPIUseMaxDist( BPy_Object * self, PyObject * value ) +{ + int param; + + if( !self->object->pd && !setupPI(self->object) ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "particle deflection could not be accessed" ); + + param = PyObject_IsTrue( value ); + if( param == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected true/false argument" ); + + self->object->pd->flag = (short)param; + self->object->recalc |= OB_RECALC_OB; + + return 0; +} + +/* RIGIDBODY FUNCTIONS */ + +static PyObject *Object_getRBMass( BPy_Object * self ) +{ + return PyFloat_FromDouble( (double)self->object->mass ); +} + +static int Object_setRBMass( BPy_Object * self, PyObject * args ) +{ + float value; + PyObject* flt = PyNumber_Float( args ); + + if( !flt ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected float argument" ); + value = (float)PyFloat_AS_DOUBLE( flt ); + Py_DECREF( flt ); + + if( value < 0.0f ) + return EXPP_ReturnIntError( PyExc_ValueError, + "acceptable values are non-negative, 0.0 or more" ); + + self->object->mass = value; + self->object->recalc |= OB_RECALC_OB; + + return 0; +} + +/* this is too low level, possible to add helper methods */ + +#define GAMEFLAG_MASK ( OB_DYNAMIC | OB_CHILD | OB_ACTOR | OB_DO_FH | \ + OB_ROT_FH | OB_ANISOTROPIC_FRICTION | OB_GHOST | OB_RIGID_BODY | \ + OB_BOUNDS | OB_COLLISION_RESPONSE | OB_SECTOR | OB_PROP | \ + OB_MAINACTOR ) + +static PyObject *Object_getRBFlags( BPy_Object * self ) +{ + return PyInt_FromLong( (long)( self->object->gameflag & GAMEFLAG_MASK ) ); +} + +static int Object_setRBFlags( BPy_Object * self, PyObject * args ) +{ + PyObject* integer = PyNumber_Int( args ); + int value; + + if( !integer ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected integer argument" ); + + value = ( int )PyInt_AS_LONG( integer ); + Py_DECREF( integer ); + if( value & ~GAMEFLAG_MASK ) + return EXPP_ReturnIntError( PyExc_ValueError, + "undefined bit(s) set in bitfield" ); + + self->object->gameflag = value; + self->object->recalc |= OB_RECALC_OB; + + return 0; +} + +static PyObject *Object_getRBShapeBoundType( BPy_Object * self ) +{ + return PyInt_FromLong( (long)self->object->boundtype ); +} + +static int Object_setRBShapeBoundType( BPy_Object * self, PyObject * args ) +{ + self->object->recalc |= OB_RECALC_OB; + return EXPP_setIValueRange( args, &self->object->boundtype, + 0, OB_BOUND_DYN_MESH, 'h' ); +} + +/* SOFTBODY FUNCTIONS */ + +PyObject *Object_isSB(BPy_Object *self) +{ + if( self->object->soft ) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +static PyObject *Object_getSBUseGoal( BPy_Object * self ) +{ + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + if( self->object->softflag & OB_SB_GOAL ) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +static int Object_setSBUseGoal( BPy_Object * self, PyObject * value ) +{ + int setting = PyObject_IsTrue( value ); + + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + if( setting == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected true/false argument" ); + + if( setting ) + self->object->softflag |= OB_SB_GOAL; + else + self->object->softflag &= ~OB_SB_GOAL; + + self->object->recalc |= OB_RECALC_OB; + return 0; +} + +static PyObject *Object_getSBUseEdges( BPy_Object * self ) +{ + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + if( self->object->softflag & OB_SB_EDGES ) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +static int Object_setSBUseEdges( BPy_Object * self, PyObject * value ) +{ + int setting = PyObject_IsTrue( value ); + + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + if( setting == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected true/false argument" ); + + if( setting ) + self->object->softflag |= OB_SB_EDGES; + else + self->object->softflag &= ~OB_SB_EDGES; + + self->object->recalc |= OB_RECALC_OB; + return 0; +} + +static PyObject *Object_getSBStiffQuads( BPy_Object * self ) +{ + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + if( self->object->softflag & OB_SB_QUADS ) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +static int Object_setSBStiffQuads( BPy_Object * self, PyObject * value ) +{ + int setting = PyObject_IsTrue( value ); + + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + if( setting == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected true/false argument" ); + + if( setting ) + self->object->softflag |= OB_SB_QUADS; + else + self->object->softflag &= ~OB_SB_QUADS; + + self->object->recalc |= OB_RECALC_OB; + return 0; +} + +static int setupSB( Object* ob ) +{ + ob->soft= sbNew(); + ob->softflag |= OB_SB_GOAL|OB_SB_EDGES; + + if( !ob->soft ) + return 0; + /* all this is initialized in sbNew() */ +#if 0 + ob->soft->mediafrict = 0.5f; + ob->soft->nodemass = 1.0f; + ob->soft->grav = 0.0f; + ob->soft->rklimit = 0.1f; + + ob->soft->goalspring = 0.5f; + ob->soft->goalfrict = 0.0f; + ob->soft->mingoal = 0.0f; + ob->soft->maxgoal = 1.0f; + ob->soft->defgoal = 0.7f; + + ob->soft->inspring = 0.5f; + ob->soft->infrict = 0.5f; +#endif + return 1; +} + +static int setupPI( Object* ob ) +{ + if( ob->pd==NULL ) { + ob->pd= MEM_callocN(sizeof(PartDeflect), "PartDeflect"); + /* and if needed, init here */ + } + + if( !ob->pd ) + return 0; + + ob->pd->deflect =0; + ob->pd->forcefield =0; + ob->pd->flag =0; + ob->pd->pdef_damp =0; + ob->pd->pdef_rdamp =0; + ob->pd->pdef_perm =0; + ob->pd->f_strength =0; + ob->pd->f_power =0; + ob->pd->maxdist =0; + return 1; +} + +/* + * scan list of Objects looking for matching obdata. + * if found, set OB_RECALC_DATA flag. + * call this from a bpy type update() method. + */ + +void Object_updateDag( void *data ) +{ + Object *ob; + + if( !data ) + return; + + for( ob = G.main->object.first; ob; ob= ob->id.next ){ + if( ob->data == data ) { + ob->recalc |= OB_RECALC_DATA; + } + } +} + +/* + * utilities routines for handling generic getters and setters + */ + +/* + * get integer attributes + */ + +static PyObject *getIntAttr( BPy_Object *self, void *type ) +{ + int param; + struct Object *object = self->object; + + switch( (int)type ) { + case EXPP_OBJ_ATTR_LAYERMASK: + param = object->lay; + break; + case EXPP_OBJ_ATTR_COLBITS: + param = object->colbits; + if( param < 0 ) param += 65536; + break; + case EXPP_OBJ_ATTR_DRAWMODE: + param = object->dtx; + break; + case EXPP_OBJ_ATTR_DRAWTYPE: + param = object->dt; + break; + case EXPP_OBJ_ATTR_PARENT_TYPE: + param = object->partype; + break; + case EXPP_OBJ_ATTR_DUPON: + param = object->dupon; + break; + case EXPP_OBJ_ATTR_DUPOFF: + param = object->dupoff; + break; + case EXPP_OBJ_ATTR_DUPSTA: + param = object->dupsta; + break; + case EXPP_OBJ_ATTR_DUPEND: + param = object->dupend; + break; + case EXPP_OBJ_ATTR_PASSINDEX: + param = object->index; + break; + case EXPP_OBJ_ATTR_ACT_MATERIAL: + param = object->actcol; + break; + case EXPP_OBJ_ATTR_ACT_SHAPE: + param = object->shapenr; + break; + default: + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "undefined type in getIntAttr" ); + } + + return PyInt_FromLong( param ); +} + +/* + * set integer attributes which require clamping + */ + +static int setIntAttrClamp( BPy_Object *self, PyObject *value, void *type ) +{ + void *param; + struct Object *object = self->object; + int min, max, size; + + switch( (int)type ) { + case EXPP_OBJ_ATTR_DUPON: + min = 1; + max = 1500; + size = 'H'; /* in case max is later made > 32767 */ + param = (void *)&object->dupon; + break; + case EXPP_OBJ_ATTR_DUPOFF: + min = 0; + max = 1500; + size = 'H'; /* in case max is later made > 32767 */ + param = (void *)&object->dupoff; + break; + case EXPP_OBJ_ATTR_DUPSTA: + min = 1; + max = 32767; + size = 'H'; /* in case max is later made > 32767 */ + param = (void *)&object->dupsta; + break; + case EXPP_OBJ_ATTR_DUPEND: + min = 1; + max = 32767; + size = 'H'; /* in case max is later made > 32767 */ + param = (void *)&object->dupend; + break; + case EXPP_OBJ_ATTR_PASSINDEX: + min = 0; + max = 1000; + size = 'H'; /* in case max is later made > 32767 */ + param = (void *)&object->index; + break; + case EXPP_OBJ_ATTR_ACT_MATERIAL: + min = 1; + max = object->totcol; + size = 'b'; /* in case max is later made > 128 */ + param = (void *)&object->actcol; + break; + case EXPP_OBJ_ATTR_ACT_SHAPE: + { + Key *key= ob_get_key(object); + KeyBlock *kb; + min = 1; + max = 0; + if (key) { + max= 1; + for (kb = key->block.first; kb; kb=kb->next, max++); + } + size = 'h'; /* in case max is later made > 128 */ + param = (void *)&object->shapenr; + break; + } + default: + return EXPP_ReturnIntError( PyExc_RuntimeError, + "undefined type in setIntAttrClamp"); + } + + self->object->recalc |= OB_RECALC_OB; + return EXPP_setIValueClamped( value, param, min, max, size ); +} + +/* + * set integer attributes which require range checking + */ + +static int setIntAttrRange( BPy_Object *self, PyObject *value, void *type ) +{ + void *param; + struct Object *object = self->object; + int min, max, size; + + if( !PyInt_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected integer argument" ); + + /* these parameters require clamping */ + + switch( (int)type ) { + case EXPP_OBJ_ATTR_COLBITS: + min = 0; + max = 0xffff; + size = 'H'; + param = (void *)&object->colbits; + break; + default: + return EXPP_ReturnIntError( PyExc_RuntimeError, + "undefined type in setIntAttrRange" ); + } + + self->object->recalc |= OB_RECALC_OB; + return EXPP_setIValueRange( value, param, min, max, size ); +} + +/* + * get floating point attributes + */ + +static PyObject *getFloatAttr( BPy_Object *self, void *type ) +{ + float param; + struct Object *object = self->object; + + if( (int)type >= EXPP_OBJ_ATTR_PI_SURFACEDAMP && + (int)type <= EXPP_OBJ_ATTR_PI_SBOFACETHICK ) { + if( !self->object->pd && !setupPI(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "particle deflection could not be accessed" ); + } + else if( (int)type >= EXPP_OBJ_ATTR_SB_NODEMASS && + (int)type <= EXPP_OBJ_ATTR_SB_INFRICT ) { + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + } + + switch( (int)type ) { + case EXPP_OBJ_ATTR_LOC_X: + param = object->loc[0]; + break; + case EXPP_OBJ_ATTR_LOC_Y: + param = object->loc[1]; + break; + case EXPP_OBJ_ATTR_LOC_Z: + param = object->loc[2]; + break; + case EXPP_OBJ_ATTR_DLOC_X: + param = object->dloc[0]; + break; + case EXPP_OBJ_ATTR_DLOC_Y: + param = object->dloc[1]; + break; + case EXPP_OBJ_ATTR_DLOC_Z: + param = object->dloc[2]; + break; + case EXPP_OBJ_ATTR_ROT_X: + param = object->rot[0]; + break; + case EXPP_OBJ_ATTR_ROT_Y: + param = object->rot[1]; + break; + case EXPP_OBJ_ATTR_ROT_Z: + param = object->rot[2]; + break; + case EXPP_OBJ_ATTR_DROT_X: + param = object->drot[0]; + break; + case EXPP_OBJ_ATTR_DROT_Y: + param = object->drot[1]; + break; + case EXPP_OBJ_ATTR_DROT_Z: + param = object->drot[2]; + break; + case EXPP_OBJ_ATTR_SIZE_X: + param = object->size[0]; + break; + case EXPP_OBJ_ATTR_SIZE_Y: + param = object->size[1]; + break; + case EXPP_OBJ_ATTR_SIZE_Z: + param = object->size[2]; + break; + case EXPP_OBJ_ATTR_DSIZE_X: + param = object->dsize[0]; + break; + case EXPP_OBJ_ATTR_DSIZE_Y: + param = object->dsize[1]; + break; + case EXPP_OBJ_ATTR_DSIZE_Z: + param = object->dsize[2]; + break; + case EXPP_OBJ_ATTR_TIMEOFFSET: + param = object->sf; + break; + case EXPP_OBJ_ATTR_DRAWSIZE: + param = object->empty_drawsize; + break; + case EXPP_OBJ_ATTR_PI_SURFACEDAMP: + param = object->pd->pdef_perm; + break; + case EXPP_OBJ_ATTR_PI_RANDOMDAMP: + param = object->pd->pdef_rdamp; + break; + case EXPP_OBJ_ATTR_PI_PERM: + param = object->pd->pdef_perm; + break; + case EXPP_OBJ_ATTR_PI_STRENGTH: + param = object->pd->f_strength; + break; + case EXPP_OBJ_ATTR_PI_FALLOFF: + param = object->pd->f_power; + break; + case EXPP_OBJ_ATTR_PI_MAXDIST: + param = object->pd->maxdist; + break; + case EXPP_OBJ_ATTR_PI_SBDAMP: + param = object->pd->pdef_sbdamp; + break; + case EXPP_OBJ_ATTR_PI_SBIFACETHICK: + param = object->pd->pdef_sbift; + break; + case EXPP_OBJ_ATTR_PI_SBOFACETHICK: + param = object->pd->pdef_sboft; + break; + case EXPP_OBJ_ATTR_SB_NODEMASS: + param = self->object->soft->nodemass; + break; + case EXPP_OBJ_ATTR_SB_GRAV: + param = self->object->soft->grav; + break; + case EXPP_OBJ_ATTR_SB_MEDIAFRICT: + param = self->object->soft->mediafrict; + break; + case EXPP_OBJ_ATTR_SB_RKLIMIT: + param = object->soft->rklimit; + break; + case EXPP_OBJ_ATTR_SB_PHYSICSSPEED: + param = object->soft->physics_speed; + break; + case EXPP_OBJ_ATTR_SB_GOALSPRING: + param = object->soft->goalspring; + break; + case EXPP_OBJ_ATTR_SB_GOALFRICT: + param = object->soft->goalfrict; + break; + case EXPP_OBJ_ATTR_SB_MINGOAL: + param = object->soft->mingoal; + break; + case EXPP_OBJ_ATTR_SB_MAXGOAL: + param = object->soft->maxgoal; + break; + case EXPP_OBJ_ATTR_SB_DEFGOAL: + param = object->soft->defgoal; + break; + case EXPP_OBJ_ATTR_SB_INSPRING: + param = object->soft->inspring; + break; + case EXPP_OBJ_ATTR_SB_INFRICT: + param = object->soft->infrict; + break; + default: + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "undefined type in getFloatAttr" ); + } + + return PyFloat_FromDouble( param ); +} + +/* + * set floating point attributes which require clamping + */ + +static int setFloatAttrClamp( BPy_Object *self, PyObject *value, void *type ) +{ + float *param; + struct Object *object = self->object; + float min, max; + + if( (int)type >= EXPP_OBJ_ATTR_PI_SURFACEDAMP && + (int)type <= EXPP_OBJ_ATTR_PI_SBOFACETHICK ) { + if( !self->object->pd && !setupPI(self->object) ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "particle deflection could not be accessed" ); + } + else if( (int)type >= EXPP_OBJ_ATTR_SB_NODEMASS && + (int)type <= EXPP_OBJ_ATTR_SB_INFRICT ) { + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "softbody could not be accessed" ); + } + + switch( (int)type ) { + case EXPP_OBJ_ATTR_DRAWSIZE: + min = EXPP_OBJECT_DRAWSIZEMIN; + max = EXPP_OBJECT_DRAWSIZEMAX; + param = &object->empty_drawsize; + break; + case EXPP_OBJ_ATTR_TIMEOFFSET: + min = -MAXFRAMEF; + max = MAXFRAMEF; + param = &object->sf; + break; + case EXPP_OBJ_ATTR_PI_SURFACEDAMP: + min = EXPP_OBJECT_PIDAMP_MIN; + max = EXPP_OBJECT_PIDAMP_MAX; + param = &object->pd->pdef_perm; + break; + case EXPP_OBJ_ATTR_PI_RANDOMDAMP: + min = EXPP_OBJECT_PIRDAMP_MIN; + max = EXPP_OBJECT_PIRDAMP_MAX; + param = &object->pd->pdef_rdamp; + break; + case EXPP_OBJ_ATTR_PI_PERM: + min = EXPP_OBJECT_PIPERM_MIN; + max = EXPP_OBJECT_PIPERM_MAX; + param = &object->pd->pdef_perm; + break; + case EXPP_OBJ_ATTR_PI_STRENGTH: + min = EXPP_OBJECT_PISTRENGTH_MIN; + max = EXPP_OBJECT_PISTRENGTH_MAX; + param = &object->pd->f_strength; + break; + case EXPP_OBJ_ATTR_PI_FALLOFF: + min = EXPP_OBJECT_PIPOWER_MIN; + max = EXPP_OBJECT_PIPOWER_MAX; + param = &object->pd->f_power; + break; + case EXPP_OBJ_ATTR_PI_MAXDIST: + min = EXPP_OBJECT_PIMAXDIST_MIN; + max = EXPP_OBJECT_PIMAXDIST_MAX; + param = &object->pd->maxdist; + break; + case EXPP_OBJ_ATTR_PI_SBDAMP: + min = EXPP_OBJECT_PISBDAMP_MIN; + max = EXPP_OBJECT_PISBDAMP_MAX; + param = &object->pd->pdef_sbdamp; + break; + case EXPP_OBJ_ATTR_PI_SBIFACETHICK: + min = EXPP_OBJECT_PISBIFTMIN; + max = EXPP_OBJECT_PISBIFTMAX; + param = &object->pd->pdef_sbift; + break; + case EXPP_OBJ_ATTR_PI_SBOFACETHICK: + min = EXPP_OBJECT_PISBOFTMIN; + max = EXPP_OBJECT_PISBOFTMAX; + param = &object->pd->pdef_sboft; + break; + case EXPP_OBJ_ATTR_SB_NODEMASS: + min = EXPP_OBJECT_SBNODEMASSMIN; + max = EXPP_OBJECT_SBNODEMASSMAX; + param = &self->object->soft->nodemass; + break; + case EXPP_OBJ_ATTR_SB_GRAV: + min = EXPP_OBJECT_SBGRAVMIN; + max = EXPP_OBJECT_SBGRAVMAX; + param = &self->object->soft->grav; + break; + case EXPP_OBJ_ATTR_SB_MEDIAFRICT: + min = EXPP_OBJECT_SBMEDIAFRICTMIN; + max = EXPP_OBJECT_SBMEDIAFRICTMAX; + param = &self->object->soft->mediafrict; + break; + case EXPP_OBJ_ATTR_SB_RKLIMIT: + min = EXPP_OBJECT_SBRKLIMITMIN; + max = EXPP_OBJECT_SBRKLIMITMAX; + param = &self->object->soft->rklimit; + break; + case EXPP_OBJ_ATTR_SB_PHYSICSSPEED: + min = EXPP_OBJECT_SBPHYSICSSPEEDMIN; + max = EXPP_OBJECT_SBPHYSICSSPEEDMAX; + param = &self->object->soft->physics_speed; + break; + case EXPP_OBJ_ATTR_SB_GOALSPRING: + min = EXPP_OBJECT_SBGOALSPRINGMIN; + max = EXPP_OBJECT_SBGOALSPRINGMAX; + param = &self->object->soft->goalspring; + break; + case EXPP_OBJ_ATTR_SB_GOALFRICT: + min = EXPP_OBJECT_SBGOALFRICTMIN; + max = EXPP_OBJECT_SBGOALFRICTMAX; + param = &self->object->soft->goalfrict; + break; + case EXPP_OBJ_ATTR_SB_MINGOAL: + min = EXPP_OBJECT_SBMINGOALMIN; + max = EXPP_OBJECT_SBMINGOALMAX; + param = &self->object->soft->mingoal; + break; + case EXPP_OBJ_ATTR_SB_MAXGOAL: + min = EXPP_OBJECT_SBMAXGOALMIN; + max = EXPP_OBJECT_SBMAXGOALMAX; + param = &self->object->soft->maxgoal; + break; + case EXPP_OBJ_ATTR_SB_DEFGOAL: + min = EXPP_OBJECT_SBDEFGOALMIN; + max = EXPP_OBJECT_SBDEFGOALMAX; + param = &self->object->soft->defgoal; + break; + case EXPP_OBJ_ATTR_SB_INSPRING: + min = EXPP_OBJECT_SBINSPRINGMIN; + max = EXPP_OBJECT_SBINSPRINGMAX; + param = &self->object->soft->inspring; + break; + case EXPP_OBJ_ATTR_SB_INFRICT: + min = EXPP_OBJECT_SBINFRICTMIN; + max = EXPP_OBJECT_SBINFRICTMAX; + param = &self->object->soft->infrict; + break; + default: + return EXPP_ReturnIntError( PyExc_RuntimeError, + "undefined type in setFloatAttrClamp" ); + } + + self->object->recalc |= OB_RECALC_OB; + return EXPP_setFloatClamped( value, param, min, max ); +} + +/* + * set floating point attributes + */ + +static int setFloatAttr( BPy_Object *self, PyObject *value, void *type ) +{ + float param; + struct Object *object = self->object; + + if( !PyNumber_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected float argument" ); + + param = (float)PyFloat_AsDouble( value ); + + switch( (int)type ) { + case EXPP_OBJ_ATTR_LOC_X: + object->loc[0] = param; + break; + case EXPP_OBJ_ATTR_LOC_Y: + object->loc[1] = param; + break; + case EXPP_OBJ_ATTR_LOC_Z: + object->loc[2] = param; + break; + case EXPP_OBJ_ATTR_DLOC_X: + object->dloc[0] = param; + break; + case EXPP_OBJ_ATTR_DLOC_Y: + object->dloc[1] = param; + break; + case EXPP_OBJ_ATTR_DLOC_Z: + object->dloc[2] = param; + break; + case EXPP_OBJ_ATTR_ROT_X: + object->rot[0] = param; + break; + case EXPP_OBJ_ATTR_ROT_Y: + object->rot[1] = param; + break; + case EXPP_OBJ_ATTR_ROT_Z: + object->rot[2] = param; + break; + case EXPP_OBJ_ATTR_DROT_X: + object->drot[0] = param; + break; + case EXPP_OBJ_ATTR_DROT_Y: + object->drot[1] = param; + break; + case EXPP_OBJ_ATTR_DROT_Z: + object->drot[2] = param; + break; + case EXPP_OBJ_ATTR_SIZE_X: + object->size[0] = param; + break; + case EXPP_OBJ_ATTR_SIZE_Y: + object->size[1] = param; + break; + case EXPP_OBJ_ATTR_SIZE_Z: + object->size[2] = param; + break; + case EXPP_OBJ_ATTR_DSIZE_X: + object->dsize[0] = param; + break; + case EXPP_OBJ_ATTR_DSIZE_Y: + object->dsize[1] = param; + break; + case EXPP_OBJ_ATTR_DSIZE_Z: + object->dsize[2] = param; + break; + default: + return EXPP_ReturnIntError( PyExc_RuntimeError, + "undefined type in setFloatAttr " ); + } + self->object->recalc |= OB_RECALC_OB; + return 0; +} + +/* + * get 3-tuple floating point attributes + */ + +static PyObject *getFloat3Attr( BPy_Object *self, void *type ) +{ + float *param; + struct Object *object = self->object; + + switch( (int)type ) { + case EXPP_OBJ_ATTR_LOC: + param = object->loc; + break; + case EXPP_OBJ_ATTR_DLOC: + param = object->dloc; + break; + case EXPP_OBJ_ATTR_DROT: + param = object->drot; + break; + case EXPP_OBJ_ATTR_SIZE: + param = object->size; + break; + case EXPP_OBJ_ATTR_DSIZE: + param = object->dsize; + break; + default: + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "undefined type in getFloat3Attr" ); + } + + return Py_BuildValue( "(fff)", param[0], param[1], param[2] ); +} + +/* + * set 3-tuple floating point attributes + */ + +static int setFloat3Attr( BPy_Object *self, PyObject *value, void *type ) +{ + int i; + float *dst, param[3]; + struct Object *object = self->object; + + value = PySequence_Tuple( value ); + + if( !value || !PyArg_ParseTuple( value, "fff", ¶m[0], ¶m[1], ¶m[2] ) ) { + Py_XDECREF( value ); + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a list or tuple of 3 floats" ); + } + + Py_DECREF( value ); + switch( (int)type ) { + case EXPP_OBJ_ATTR_LOC: + dst = object->loc; + break; + case EXPP_OBJ_ATTR_DLOC: + dst = object->dloc; + break; + case EXPP_OBJ_ATTR_DROT: + dst = object->drot; + break; + case EXPP_OBJ_ATTR_SIZE: + dst = object->size; + break; + case EXPP_OBJ_ATTR_DSIZE: + dst = object->dsize; + break; + default: + return EXPP_ReturnIntError( PyExc_RuntimeError, + "undefined type in setFloat3Attr" ); + } + + for( i = 0; i < 3; ++i ) + dst[i] = param[i]; + + self->object->recalc |= OB_RECALC_OB; + return 0; +} + +/*****************************************************************************/ +/* BPy_Object methods and attribute handlers */ +/*****************************************************************************/ + +static PyObject *Object_getShapeFlag( BPy_Object *self, void *type ) +{ + if (self->object->shapeflag & (int)type) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +static int Object_setShapeFlag( BPy_Object *self, PyObject *value, + void *type ) +{ + if (PyObject_IsTrue(value) ) + self->object->shapeflag |= (int)type; + else + self->object->shapeflag &= ~(int)type; + + self->object->recalc |= OB_RECALC_OB; + return 0; +} + +static PyObject *Object_getRestricted( BPy_Object *self, void *type ) +{ + if (self->object->restrictflag & (int)type) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +static int Object_setRestricted( BPy_Object *self, PyObject *value, + void *type ) +{ + int param = PyObject_IsTrue( value ); + if( param == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected True/False or 0/1" ); + + if ( param ) + self->object->restrictflag |= (int)type; + else + self->object->restrictflag &= ~(int)type; + + return 0; +} + +static PyObject *Object_getDrawModeBits( BPy_Object *self, void *type ) +{ + return EXPP_getBitfield( (void *)&self->object->dtx, (int)type, 'b' ); +} + +static int Object_setDrawModeBits( BPy_Object *self, PyObject *value, + void *type ) +{ + self->object->recalc |= OB_RECALC_OB; + return EXPP_setBitfield( value, (void *)&self->object->dtx, + (int)type, 'b' ); +} + +static PyObject *Object_getTransflagBits( BPy_Object *self, void *type ) +{ + return EXPP_getBitfield( (void *)&self->object->transflag, + (int)type, 'h' ); +} + +static int Object_setTransflagBits( BPy_Object *self, PyObject *value, + void *type ) +{ + self->object->recalc |= OB_RECALC_OB; + return EXPP_setBitfield( value, (void *)&self->object->transflag, + (int)type, 'h' ); +} + +static PyObject *Object_getLayers( BPy_Object * self ) +{ + int layers, bit; + PyObject *laylist = PyList_New( 0 ); + + if( !laylist ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "PyList_New() failed" ); + + layers = self->object->lay & 0xfffff; /* get layer bitmask */ + + /* + * starting with the first layer, and until there are no more layers, + * find which layers are visible + */ + + for( bit = 1; layers; ++bit ) { + if( layers & 1 ) { /* if layer is visible, add to list */ + PyObject *item = PyInt_FromLong( bit ); + PyList_Append( laylist, item ); + Py_DECREF( item ); + } + layers >>= 1; /* go to the next layer */ + } + return laylist; +} + +/* + * usage note: caller of this func needs to do a Blender.Redraw(-1) + * to update and redraw the interface + */ + +static int Object_setLayers( BPy_Object * self, PyObject *value ) +{ + int layers = 0, val, i, len_list, local; + Base *base; + + if( !PyList_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a list of integers in the range [1, 20]" ); + + len_list = PyList_Size( value ); + + /* build a bitmask, check for values outside of range */ + + for( i = 0; i < len_list; i++ ) { + PyObject* integer = PyNumber_Int( PyList_GetItem( value, i ) ); + val = PyInt_AsLong( integer ); + Py_XDECREF( integer ); + if( !integer ) + return EXPP_ReturnIntError( PyExc_TypeError, + "list must contain only integer numbers" ); + if( val < 1 || val > 20 ) + return EXPP_ReturnIntError ( PyExc_ValueError, + "layer values must be in the range [1, 20]" ); + layers |= 1 << ( val - 1 ); + } + + /* do this, to ensure layers are set for objects not in current scene */ + self->object->lay= layers; + + /* update any bases pointing to our object */ + base = FIRSTBASE; /* first base in current scene */ + while( base ) { + if( base->object == self->object ) { + base->lay &= 0xFFF00000; + local = base->lay; + base->lay = local | layers; + self->object->lay = base->lay; + break; + } + base = base->next; + } + + /* these to calls here are overkill! (ton) */ + if (base) { /* The object was found? */ + countall(); + DAG_scene_sort( G.scene ); + } + return 0; +} + +static int Object_setLayersMask( BPy_Object *self, PyObject *value ) +{ + int layers = 0, local; + Base *base; + + if( !PyInt_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected an integer (bitmask) as argument" ); + + layers = PyInt_AS_LONG( value ); + + /* make sure some bits are set, and only those bits are set */ + + if( !( layers & 0xFFFFF ) || ( layers & 0xFFF00000 ) ) + return EXPP_ReturnIntError( PyExc_ValueError, + "bitmask must have between 1 and 20 bits set" ); + + /* update any bases pointing to our object */ + + base = FIRSTBASE; /* first base in current scene */ + while( base ) { + if( base->object == self->object ) { + base->lay &= 0xFFF00000; + local = base->lay; + base->lay = local | layers; + self->object->lay = base->lay; + break; + } + base = base->next; + } + if (base) { /* The object was found? */ + countall(); + DAG_scene_sort( G.scene ); + } + return 0; +} + +/* + * this should accept a Py_None argument and just delete the Ipo link + * (as Object_clearIpo() does) + */ + +static int Object_setIpo( BPy_Object * self, PyObject * value ) +{ + return GenericLib_assignData(value, (void **) &self->object->ipo, 0, 1, ID_IP, ID_OB); +} + +static int Object_setTracked( BPy_Object * self, PyObject * value ) +{ + int ret; + ret = GenericLib_assignData(value, (void **) &self->object->track, 0, 0, ID_OB, 0); + if (ret==0) { + self->object->recalc |= OB_RECALC_OB; + DAG_scene_sort( G.scene ); + } + return ret; +} + +/* Localspace matrix */ + +static PyObject *Object_getMatrixLocal( BPy_Object * self ) +{ + if( self->object->parent ) { + float matrix[4][4]; /* for the result */ + float invmat[4][4]; /* for inverse of parent's matrix */ + + Mat4Invert(invmat, self->object->parent->obmat ); + Mat4MulMat4(matrix, self->object->obmat, invmat); + return newMatrixObject((float*)matrix,4,4,Py_NEW); + } else { /* no parent, so return world space matrix */ + disable_where_script( 1 ); + where_is_object( self->object ); + disable_where_script( 0 ); + return newMatrixObject((float*)self->object->obmat,4,4,Py_WRAP); + } +} + +/* Worldspace matrix */ + +static PyObject *Object_getMatrixWorld( BPy_Object * self ) +{ + disable_where_script( 1 ); + where_is_object( self->object ); + disable_where_script( 0 ); + return newMatrixObject((float*)self->object->obmat,4,4,Py_WRAP); +} + +/* Parent Inverse matrix */ + +static PyObject *Object_getMatrixParentInverse( BPy_Object * self ) +{ + return newMatrixObject((float*)self->object->parentinv,4,4,Py_WRAP); +} + +/* + * Old behavior, prior to Blender 2.34, where eventual changes made by the + * script itself were not taken into account until a redraw happened, either + * called by the script or upon its exit. + */ + +static PyObject *Object_getMatrixOldWorld( BPy_Object * self ) +{ + return newMatrixObject((float*)self->object->obmat,4,4,Py_WRAP); +} + +/* + * get one of three different matrix representations + */ + +static PyObject *Object_getMatrix( BPy_Object * self, PyObject * args ) +{ + char *space = "worldspace"; /* default to world */ + char *errstr = "expected nothing, 'worldspace' (default), 'localspace' or 'old_worldspace'"; + + if( !PyArg_ParseTuple( args, "|s", &space ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, errstr ); + + if( BLI_streq( space, "worldspace" ) ) + return Object_getMatrixWorld( self ); + else if( BLI_streq( space, "localspace" ) ) + return Object_getMatrixLocal( self ); + else if( BLI_streq( space, "old_worldspace" ) ) + return Object_getMatrixOldWorld( self ); + else + return EXPP_ReturnPyObjError( PyExc_ValueError, errstr ); +} + +static PyObject *get_obj_data( BPy_Object *self, int mesh ) +{ + Object *object = self->object; + PyObject *data_object = NULL; + + switch ( object->type ) { + case OB_ARMATURE: + data_object = Armature_CreatePyObject( object->data ); + break; + case OB_CAMERA: + data_object = Camera_CreatePyObject( object->data ); + break; + case OB_CURVE: + case OB_SURF: + data_object = Curve_CreatePyObject( object->data ); + break; + case ID_IM: + data_object = Image_CreatePyObject( object->data ); + break; + case ID_IP: + data_object = Ipo_CreatePyObject( object->data ); + break; + case OB_LAMP: + data_object = Lamp_CreatePyObject( object->data ); + break; + case OB_LATTICE: + data_object = Lattice_CreatePyObject( object->data ); + break; + case ID_MA: + break; + case OB_MESH: + if( !mesh ) /* get as NMesh (default) */ + data_object = NMesh_CreatePyObject( object->data, object ); + else /* else get as Mesh */ + data_object = Mesh_CreatePyObject( object->data, object ); + break; + case OB_MBALL: + data_object = Metaball_CreatePyObject( object->data ); + break; + case ID_OB: + data_object = Object_CreatePyObject( object->data ); + break; + case ID_SCE: + break; + case OB_FONT: + data_object = Text3d_CreatePyObject( object->data ); + break; + case ID_WO: + break; + default: + break; + } + + if( data_object ) + return data_object; + + Py_RETURN_NONE; +} + +static PyObject *Object_getData( BPy_Object *self, PyObject *args, + PyObject *kwd ) +{ + Object *object = self->object; + int name_only = 0; + int mesh = 0; /* default mesh type = NMesh */ + static char *kwlist[] = {"name_only", "mesh", NULL}; + + if( !PyArg_ParseTupleAndKeywords(args, kwd, "|ii", kwlist, + &name_only, &mesh) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected nothing or bool keywords 'name_only' or 'mesh' as argument" ); + + /* if there's no obdata, try to create it */ + if( object->data == NULL ) { + int tmptype = object->type; /* save current type */ + + /* if we have no data and are faking an empty, set the type */ + if( self->realtype != OB_EMPTY ) + object->type = self->realtype; + + if( EXPP_add_obdata( object ) != 0 ) { /* couldn't create obdata */ + object->type = tmptype; /* restore previous type */ + Py_RETURN_NONE; + } + + /* if we set data successfully, clear the fake type */ + self->realtype = OB_EMPTY; + } + + /* user wants only the name of the data object */ + if( name_only ) { + ID *id = object->data; + return PyString_FromString( id->name+2 ); + } + + return get_obj_data( self, mesh ); +} + +static PyObject *Object_getEuler( BPy_Object * self ) +{ + return ( PyObject * ) newEulerObject( self->object->rot, Py_WRAP ); +} + +#define PROTFLAGS_MASK ( OB_LOCK_LOCX | OB_LOCK_LOCY | OB_LOCK_LOCZ | \ + OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | \ + OB_LOCK_SCALEX | OB_LOCK_SCALEY | OB_LOCK_SCALEZ ) + +static PyObject *Object_getProtectFlags( BPy_Object * self ) +{ + return PyInt_FromLong( (long)(self->object->protectflag & PROTFLAGS_MASK) ); +} + +static int Object_setProtectFlags( BPy_Object * self, PyObject * args ) +{ + PyObject* integer = PyNumber_Int( args ); + short value; + + if( !integer ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected integer argument" ); + + value = ( short )PyInt_AS_LONG( integer ); + Py_DECREF( integer ); + if( value & ~PROTFLAGS_MASK ) + return EXPP_ReturnIntError( PyExc_ValueError, + "undefined bit(s) set in bitfield" ); + + self->object->protectflag = value; + self->object->recalc |= OB_RECALC_OB; + return 0; +} + +static PyObject *Object_getRBRadius( BPy_Object * self ) +{ + return PyFloat_FromDouble( (double) self->object->inertia ); +} + +static int Object_setRBRadius( BPy_Object * self, PyObject * args ) +{ + float value; + PyObject* flt = PyNumber_Float( args ); + + if( !flt ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected float argument" ); + value = (float)PyFloat_AS_DOUBLE( flt ); + Py_DECREF( flt ); + + if( value < 0.0f ) + return EXPP_ReturnIntError( PyExc_ValueError, + "acceptable values are non-negative, 0.0 or more" ); + + self->object->inertia = value; + self->object->recalc |= OB_RECALC_OB; + + return 0; +} + +static PyObject *Object_getRBHalfExtents( BPy_Object * self ) +{ + float center[3], extents[3]; + + get_local_bounds( self->object, center, extents ); + return Py_BuildValue( "[fff]", extents[0], extents[1], extents[2] ); +} + +static PyGetSetDef BPy_Object_getseters[] = { + GENERIC_LIB_GETSETATTR, + {"LocX", + (getter)getFloatAttr, (setter)setFloatAttr, + "The X location coordinate of the object", + (void *)EXPP_OBJ_ATTR_LOC_X}, + {"LocY", + (getter)getFloatAttr, (setter)setFloatAttr, + "The Y location coordinate of the object", + (void *)EXPP_OBJ_ATTR_LOC_Y}, + {"LocZ", + (getter)getFloatAttr, (setter)setFloatAttr, + "The Z location coordinate of the object", + (void *)EXPP_OBJ_ATTR_LOC_Z}, + {"dLocX", + (getter)getFloatAttr, (setter)setFloatAttr, + "The delta X location coordinate of the object", + (void *)EXPP_OBJ_ATTR_DLOC_X}, + {"dLocY", + (getter)getFloatAttr, (setter)setFloatAttr, + "The delta Y location coordinate of the object", + (void *)EXPP_OBJ_ATTR_DLOC_Y}, + {"dLocZ", + (getter)getFloatAttr, (setter)setFloatAttr, + "The delta Z location coordinate of the object", + (void *)EXPP_OBJ_ATTR_DLOC_Z}, + {"RotX", + (getter)getFloatAttr, (setter)setFloatAttr, + "The X rotation angle (in radians) of the object", + (void *)EXPP_OBJ_ATTR_ROT_X}, + {"RotY", + (getter)getFloatAttr, (setter)setFloatAttr, + "The Y rotation angle (in radians) of the object", + (void *)EXPP_OBJ_ATTR_ROT_Y}, + {"RotZ", + (getter)getFloatAttr, (setter)setFloatAttr, + "The Z rotation angle (in radians) of the object", + (void *)EXPP_OBJ_ATTR_ROT_Z}, + {"dRotX", + (getter)getFloatAttr, (setter)setFloatAttr, + "The delta X rotation angle (in radians) of the object", + (void *)EXPP_OBJ_ATTR_DROT_X}, + {"dRotY", + (getter)getFloatAttr, (setter)setFloatAttr, + "The delta Y rotation angle (in radians) of the object", + (void *)EXPP_OBJ_ATTR_DROT_Y}, + {"dRotZ", + (getter)getFloatAttr, (setter)setFloatAttr, + "The delta Z rotation angle (in radians) of the object", + (void *)EXPP_OBJ_ATTR_DROT_Z}, + {"SizeX", + (getter)getFloatAttr, (setter)setFloatAttr, + "The X size of the object", + (void *)EXPP_OBJ_ATTR_SIZE_X}, + {"SizeY", + (getter)getFloatAttr, (setter)setFloatAttr, + "The Y size of the object", + (void *)EXPP_OBJ_ATTR_SIZE_Y}, + {"SizeZ", + (getter)getFloatAttr, (setter)setFloatAttr, + "The Z size of the object", + (void *)EXPP_OBJ_ATTR_SIZE_Z}, + {"dSizeX", + (getter)getFloatAttr, (setter)setFloatAttr, + "The delta X size of the object", + (void *)EXPP_OBJ_ATTR_DSIZE_X}, + {"dSizeY", + (getter)getFloatAttr, (setter)setFloatAttr, + "The delta Y size of the object", + (void *)EXPP_OBJ_ATTR_DSIZE_Y}, + {"dSizeZ", + (getter)getFloatAttr, (setter)setFloatAttr, + "The delta Z size of the object", + (void *)EXPP_OBJ_ATTR_DSIZE_Z}, + + {"loc", + (getter)getFloat3Attr, (setter)setFloat3Attr, + "The (X,Y,Z) location coordinates of the object", + (void *)EXPP_OBJ_ATTR_LOC}, + {"dloc", + (getter)getFloat3Attr, (setter)setFloat3Attr, + "The delta (X,Y,Z) location coordinates of the object", + (void *)EXPP_OBJ_ATTR_DLOC}, + {"rot", + (getter)Object_getEuler, (setter)Object_setEuler, + "The (X,Y,Z) rotation angles (in degrees) of the object", + NULL}, + {"drot", + (getter)getFloat3Attr, (setter)setFloat3Attr, + "The delta (X,Y,Z) rotation angles (in radians) of the object", + (void *)EXPP_OBJ_ATTR_DROT}, + {"size", + (getter)getFloat3Attr, (setter)setFloat3Attr, + "The (X,Y,Z) size of the object", + (void *)EXPP_OBJ_ATTR_SIZE}, + {"dsize", + (getter)getFloat3Attr, (setter)setFloat3Attr, + "The delta (X,Y,Z) size of the object", + (void *)EXPP_OBJ_ATTR_DSIZE}, + {"Layer", + (getter)getIntAttr, (setter)Object_setLayersMask, + "The object layers (bitfield)", + (void *)EXPP_OBJ_ATTR_LAYERMASK}, + {"Layers", + (getter)getIntAttr, (setter)Object_setLayersMask, + "The object layers (bitfield)", + (void *)EXPP_OBJ_ATTR_LAYERMASK}, + {"layers", + (getter)Object_getLayers, (setter)Object_setLayers, + "The object layers (list of ints)", + NULL}, + {"ipo", + (getter)Object_getIpo, (setter)Object_setIpo, + "Object's Ipo data", + NULL}, + {"colbits", + (getter)getIntAttr, (setter)setIntAttrRange, + "The Material usage bitfield", + (void *)EXPP_OBJ_ATTR_COLBITS}, + {"drawMode", + (getter)getIntAttr, (setter)Object_setDrawMode, + "The object's drawing mode bitfield", + (void *)EXPP_OBJ_ATTR_DRAWMODE}, + {"drawType", + (getter)getIntAttr, (setter)Object_setDrawType, + "The object's drawing type", + (void *)EXPP_OBJ_ATTR_DRAWTYPE}, + {"parentType", + (getter)getIntAttr, (setter)NULL, + "The object's parent type", + (void *)EXPP_OBJ_ATTR_PARENT_TYPE}, + {"DupOn", + (getter)getIntAttr, (setter)setIntAttrClamp, + "DupOn setting (for DupliFrames)", + (void *)EXPP_OBJ_ATTR_DUPON}, + {"DupOff", + (getter)getIntAttr, (setter)setIntAttrClamp, + "DupOff setting (for DupliFrames)", + (void *)EXPP_OBJ_ATTR_DUPOFF}, + {"DupSta", + (getter)getIntAttr, (setter)setIntAttrClamp, + "Starting frame (for DupliFrames)", + (void *)EXPP_OBJ_ATTR_DUPSTA}, + {"DupEnd", + (getter)getIntAttr, (setter)setIntAttrClamp, + "Ending frame (for DupliFrames)", + (void *)EXPP_OBJ_ATTR_DUPEND}, + {"passIndex", + (getter)getIntAttr, (setter)setIntAttrClamp, + "Index for object masks in the compositor", + (void *)EXPP_OBJ_ATTR_PASSINDEX}, + {"activeMaterial", + (getter)getIntAttr, (setter)setIntAttrClamp, + "Index for the active material (displayed in the material panel)", + (void *)EXPP_OBJ_ATTR_ACT_MATERIAL}, + {"mat", + (getter)Object_getMatrixWorld, (setter)NULL, + "worldspace matrix: absolute, takes vertex parents, tracking and Ipos into account", + NULL}, + {"matrix", + (getter)Object_getMatrixWorld, (setter)NULL, + "worldspace matrix: absolute, takes vertex parents, tracking and Ipos into account", + NULL}, + {"matrixWorld", + (getter)Object_getMatrixWorld, (setter)NULL, + "worldspace matrix: absolute, takes vertex parents, tracking and Ipos into account", + NULL}, + {"matrixLocal", + (getter)Object_getMatrixLocal, (setter)Object_setMatrix, + "localspace matrix: relative to the object's parent", + NULL}, + {"matrixParentInverse", + (getter)Object_getMatrixParentInverse, (setter)NULL, + "parents inverse matrix: parents localspace inverted matrix", + NULL}, + {"matrixOldWorld", + (getter)Object_getMatrixOldWorld, (setter)NULL, + "old-type worldspace matrix (prior to Blender 2.34)", + NULL}, + {"data", + (getter)get_obj_data, (setter)NULL, + "The Datablock object linked to this object", + NULL}, + {"sel", + (getter)Object_getSelected, (setter)Object_setSelect, + "The object's selection state", + NULL}, + {"parent", + (getter)Object_getParent, (setter)NULL, + "The object's parent object (if parented)", + NULL}, + {"parentbonename", + (getter)Object_getParentBoneName, (setter)Object_setParentBoneName, + "The object's parent object's sub name", + NULL}, + {"track", + (getter)Object_getTracked, (setter)Object_setTracked, + "The object's tracked object", + NULL}, + {"timeOffset", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "The time offset of the object's animation", + (void *)EXPP_OBJ_ATTR_TIMEOFFSET}, + {"type", + (getter)Object_getType, (setter)NULL, + "The object's type", + NULL}, + {"boundingBox", + (getter)Object_getBoundBox, (setter)NULL, + "The bounding box of this object", + NULL}, + {"action", + (getter)Object_getAction, (setter)Object_setAction, + "The action associated with this object (if defined)", + NULL}, + {"game_properties", + (getter)Object_getAllProperties, (setter)NULL, + "The object's properties", + NULL}, + + {"piFalloff", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "The particle interaction falloff power", + (void *)EXPP_OBJ_ATTR_PI_FALLOFF}, + {"piMaxDist", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "Max distance for the particle interaction field to work", + (void *)EXPP_OBJ_ATTR_PI_MAXDIST}, + {"piPermeability", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "Probability that a particle will pass through the mesh", + (void *)EXPP_OBJ_ATTR_PI_PERM}, + {"piRandomDamp", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "Random variation of particle interaction damping", + (void *)EXPP_OBJ_ATTR_PI_RANDOMDAMP}, + {"piStrength", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "Particle interaction force field strength", + (void *)EXPP_OBJ_ATTR_PI_STRENGTH}, + {"piSurfaceDamp", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "Amount of damping during particle collision", + (void *)EXPP_OBJ_ATTR_PI_SURFACEDAMP}, + {"piSoftbodyDamp", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "Damping factor for softbody deflection", + (void *)EXPP_OBJ_ATTR_PI_SBDAMP}, + {"piSoftbodyIThick", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "Inner face thickness for softbody deflection", + (void *)EXPP_OBJ_ATTR_PI_SBIFACETHICK}, + {"piSoftbodyOThick", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "Outer face thickness for softbody deflection", + (void *)EXPP_OBJ_ATTR_PI_SBOFACETHICK}, + + {"piDeflection", + (getter)Object_getPIDeflection, (setter)Object_setPIDeflection, + "Deflects particles based on collision", + NULL}, + {"piType", + (getter)Object_getPIType, (setter)Object_setPIType, + "Type of particle interaction (force field, wind, etc)", + NULL}, + {"piUseMaxDist", + (getter)Object_getPIUseMaxDist, (setter)Object_setPIUseMaxDist, + "Use a maximum distance for the field to work", + NULL}, + + {"sbMass", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "Softbody point mass (heavier is slower)", + (void *)EXPP_OBJ_ATTR_SB_NODEMASS}, + {"sbGrav", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "Apply gravitation to softbody point movement", + (void *)EXPP_OBJ_ATTR_SB_GRAV}, + {"sbFriction", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "General media friction for softbody point movements", + (void *)EXPP_OBJ_ATTR_SB_MEDIAFRICT}, + {"sbSpeed", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "Tweak timing for physics to control softbody frequency and speed", + (void *)EXPP_OBJ_ATTR_SB_MEDIAFRICT}, + {"sbErrorLimit", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "Softbody Runge-Kutta ODE solver error limit (low values give more precision)", + (void *)EXPP_OBJ_ATTR_SB_RKLIMIT}, + {"sbGoalSpring", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "Softbody goal (vertex target position) spring stiffness", + (void *)EXPP_OBJ_ATTR_SB_GOALSPRING}, + {"sbGoalFriction", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "Softbody goal (vertex target position) friction", + (void *)EXPP_OBJ_ATTR_SB_GOALFRICT}, + {"sbMinGoal", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "Softbody goal minimum (vertex group weights scaled to match this range)", + (void *)EXPP_OBJ_ATTR_SB_MINGOAL}, + {"sbMaxGoal", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "Softbody goal maximum (vertex group weights scaled to match this range)", + (void *)EXPP_OBJ_ATTR_SB_MAXGOAL}, + {"sbDefaultGoal", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "Default softbody goal value, when no vertex group used", + (void *)EXPP_OBJ_ATTR_SB_DEFGOAL}, + {"sbInnerSpring", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "Softbody edge spring stiffness", + (void *)EXPP_OBJ_ATTR_SB_INSPRING}, + {"sbInnerSpringFrict", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "Softbody edge spring friction", + (void *)EXPP_OBJ_ATTR_SB_INFRICT}, + {"isSoftBody", + (getter)Object_isSB, (setter)NULL, + "True if object is a soft body", + NULL}, + {"sbUseGoal", + (getter)Object_getSBUseGoal, (setter)Object_setSBUseGoal, + "Softbody forces for vertices to stick to animated position enabled", + NULL}, + {"sbUseEdges", + (getter)Object_getSBUseEdges, (setter)Object_setSBUseEdges, + "Softbody use edges as springs enabled", + NULL}, + {"sbStiffQuads", + (getter)Object_getSBStiffQuads, (setter)Object_setSBStiffQuads, + "Softbody adds diagonal springs on 4-gons enabled", + NULL}, + + {"axis", + (getter)Object_getDrawModeBits, (setter)Object_setDrawModeBits, + "Display of active object's center and axis enabled", + (void *)OB_AXIS}, + {"texSpace", + (getter)Object_getDrawModeBits, (setter)Object_setDrawModeBits, + "Display of active object's texture space enabled", + (void *)OB_TEXSPACE}, + {"nameMode", + (getter)Object_getDrawModeBits, (setter)Object_setDrawModeBits, + "Display of active object's name enabled", + (void *)OB_DRAWNAME}, + {"wireMode", + (getter)Object_getDrawModeBits, (setter)Object_setDrawModeBits, + "Add the active object's wireframe over solid drawing enabled", + (void *)OB_DRAWWIRE}, + {"xRay", + (getter)Object_getDrawModeBits, (setter)Object_setDrawModeBits, + "Draw the active object in front of others enabled", + (void *)OB_DRAWXRAY}, + {"transp", + (getter)Object_getDrawModeBits, (setter)Object_setDrawModeBits, + "Transparent materials for the active object (mesh only) enabled", + (void *)OB_DRAWTRANSP}, + + {"enableNLAOverride", + (getter)Object_getNLAflagBits, (setter)Object_setNLAflagBits, + "Toggles Action-NLA based animation", + (void *)OB_NLA_OVERRIDE}, + + {"enableDupVerts", + (getter)Object_getTransflagBits, (setter)Object_setTransflagBits, + "Duplicate child objects on all vertices", + (void *)OB_DUPLIVERTS}, + {"enableDupFaces", + (getter)Object_getTransflagBits, (setter)Object_setTransflagBits, + "Duplicate child objects on all faces", + (void *)OB_DUPLIFACES}, + {"enableDupFacesScale", + (getter)Object_getTransflagBits, (setter)Object_setTransflagBits, + "Use face scale to scale all dupliFaces", + (void *)OB_DUPLIFACES_SCALE}, + {"enableDupFrames", + (getter)Object_getTransflagBits, (setter)Object_setTransflagBits, + "Make copy of object for every frame", + (void *)OB_DUPLIFRAMES}, + {"enableDupGroup", + (getter)Object_getTransflagBits, (setter)Object_setTransflagBits, + "Enable group instancing", + (void *)OB_DUPLIGROUP}, + {"enableDupRot", + (getter)Object_getTransflagBits, (setter)Object_setTransflagBits, + "Rotate dupli according to vertex normal", + (void *)OB_DUPLIROT}, + {"enableDupNoSpeed", + (getter)Object_getTransflagBits, (setter)Object_setTransflagBits, + "Set dupliframes to still, regardless of frame", + (void *)OB_DUPLINOSPEED}, + {"DupObjects", + (getter)Object_getDupliObjects, (setter)NULL, + "Get a list of tuple pairs (object, matrix), for getting dupli objects", + NULL}, + {"DupGroup", + (getter)Object_getDupliGroup, (setter)Object_setDupliGroup, + "Get a list of tuples for object duplicated by dupliframe", + NULL}, + + {"effects", + (getter)Object_getEffects, (setter)NULL, + "The list of particle effects associated with the object", + NULL}, + {"actionStrips", + (getter)Object_getActionStrips, (setter)NULL, + "The action strips associated with the object", + NULL}, + {"constraints", + (getter)Object_getConstraints, (setter)NULL, + "The constraints associated with the object", + NULL}, + {"modifiers", + (getter)Object_getModifiers, (setter)Object_setModifiers, + "The modifiers associated with the object", + NULL}, + {"protectFlags", + (getter)Object_getProtectFlags, (setter)Object_setProtectFlags, + "The \"transform locking\" bitfield for the object", + NULL}, + {"drawSize", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "The size to display the Empty", + (void *)EXPP_OBJ_ATTR_DRAWSIZE}, + + {"rbFlags", + (getter)Object_getRBFlags, (setter)Object_setRBFlags, + "Rigid body flags", + NULL}, + {"rbMass", + (getter)Object_getRBMass, (setter)Object_setRBMass, + "Rigid body object mass", + NULL}, + {"rbRadius", + (getter)Object_getRBRadius, (setter)Object_setRBRadius, + "Rigid body bounding sphere size", + NULL}, + {"rbShapeBoundType", + (getter)Object_getRBShapeBoundType, (setter)Object_setRBShapeBoundType, + "Rigid body physics bounds object type", + NULL}, + {"rbHalfExtents", + (getter)Object_getRBHalfExtents, (setter)NULL, + "Rigid body physics bounds object type", + NULL}, + + {"restrictDisplay", + (getter)Object_getRestricted, (setter)Object_setRestricted, + "Toggle object restrictions", + (void *)OB_RESTRICT_VIEW}, + {"restrictSelect", + (getter)Object_getRestricted, (setter)Object_setRestricted, + "Toggle object restrictions", + (void *)OB_RESTRICT_SELECT}, + {"restrictRender", + (getter)Object_getRestricted, (setter)Object_setRestricted, + "Toggle object restrictions", + (void *)OB_RESTRICT_RENDER}, + + {"pinShape", + (getter)Object_getShapeFlag, (setter)Object_setShapeFlag, + "Set the state for pinning this object", + (void *)OB_SHAPE_LOCK}, + {"activeShape", + (getter)getIntAttr, (setter)setIntAttrClamp, + "set the index for the active shape key", + (void *)EXPP_OBJ_ATTR_ACT_SHAPE}, + + + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/*****************************************************************************/ +/* Python Object_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject Object_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender Object", /* char *tp_name; */ + sizeof( BPy_Object ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + ( destructor ) Object_dealloc,/* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) Object_compare, /* cmpfunc tp_compare; */ + ( reprfunc ) Object_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_Object_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_Object_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +static PyObject *M_Object_DrawModesDict( void ) +{ + PyObject *M = PyConstant_New( ); + + if( M ) { + BPy_constant *d = ( BPy_constant * ) M; + PyConstant_Insert( d, "AXIS", PyInt_FromLong( OB_AXIS ) ); + PyConstant_Insert( d, "TEXSPACE", PyInt_FromLong( OB_TEXSPACE ) ); + PyConstant_Insert( d, "NAME", PyInt_FromLong( OB_DRAWNAME ) ); + PyConstant_Insert( d, "WIRE", PyInt_FromLong( OB_DRAWWIRE ) ); + PyConstant_Insert( d, "XRAY", PyInt_FromLong( OB_DRAWXRAY ) ); + PyConstant_Insert( d, "TRANSP", PyInt_FromLong( OB_DRAWTRANSP ) ); + } + return M; +} + +static PyObject *M_Object_DrawTypesDict( void ) +{ + PyObject *M = PyConstant_New( ); + + if( M ) { + BPy_constant *d = ( BPy_constant * ) M; + PyConstant_Insert( d, "BOUNDBOX", PyInt_FromLong( OB_BOUNDBOX ) ); + PyConstant_Insert( d, "WIRE", PyInt_FromLong( OB_WIRE ) ); + PyConstant_Insert( d, "SOLID", PyInt_FromLong( OB_SOLID ) ); + PyConstant_Insert( d, "SHADED", PyInt_FromLong( OB_SHADED ) ); + } + return M; +} + +static PyObject *M_Object_ParentTypesDict( void ) +{ + PyObject *M = PyConstant_New( ); + + if( M ) { + BPy_constant *d = ( BPy_constant * ) M; + PyConstant_Insert( d, "OBJECT", PyInt_FromLong( PAROBJECT ) ); + PyConstant_Insert( d, "CURVE", PyInt_FromLong( PARCURVE ) ); + + /* 2.43 was released as LATTICE as PARKEY, my bad, + lattice uses PARSKEL also - Campbell */ + PyConstant_Insert( d, "LATTICE", PyInt_FromLong( PARSKEL ) ); + + PyConstant_Insert( d, "ARMATURE", PyInt_FromLong( PARSKEL ) ); + PyConstant_Insert( d, "VERT1", PyInt_FromLong( PARVERT1 ) ); + PyConstant_Insert( d, "VERT3", PyInt_FromLong( PARVERT3 ) ); + PyConstant_Insert( d, "BONE", PyInt_FromLong( PARBONE ) ); + } + return M; +} + +static PyObject *M_Object_PITypesDict( void ) +{ + PyObject *M = PyConstant_New( ); + + if( M ) { + BPy_constant *d = ( BPy_constant * ) M; + PyConstant_Insert( d, "NONE", PyInt_FromLong( 0 ) ); + PyConstant_Insert( d, "FORCE", PyInt_FromLong( PFIELD_FORCE ) ); + PyConstant_Insert( d, "VORTEX", PyInt_FromLong( PFIELD_VORTEX ) ); + PyConstant_Insert( d, "WIND", PyInt_FromLong( PFIELD_WIND ) ); + PyConstant_Insert( d, "GUIDE", PyInt_FromLong( PFIELD_GUIDE ) ); + } + return M; +} + +static PyObject *M_Object_ProtectDict( void ) +{ + PyObject *M = PyConstant_New( ); + + if( M ) { + BPy_constant *d = ( BPy_constant * ) M; + PyConstant_Insert( d, "LOCX", PyInt_FromLong( OB_LOCK_LOCX ) ); + PyConstant_Insert( d, "LOCY", PyInt_FromLong( OB_LOCK_LOCY ) ); + PyConstant_Insert( d, "LOCZ", PyInt_FromLong( OB_LOCK_LOCZ ) ); + PyConstant_Insert( d, "LOC", PyInt_FromLong( OB_LOCK_LOC ) ); + PyConstant_Insert( d, "ROTX", PyInt_FromLong( OB_LOCK_ROTX ) ); + PyConstant_Insert( d, "ROTY", PyInt_FromLong( OB_LOCK_ROTY ) ); + PyConstant_Insert( d, "ROTZ", PyInt_FromLong( OB_LOCK_ROTZ ) ); + PyConstant_Insert( d, "ROT", + PyInt_FromLong( OB_LOCK_ROTX|OB_LOCK_ROTY|OB_LOCK_ROTZ ) ); + PyConstant_Insert( d, "SCALEX", PyInt_FromLong( OB_LOCK_SCALEX ) ); + PyConstant_Insert( d, "SCALEY", PyInt_FromLong( OB_LOCK_SCALEY ) ); + PyConstant_Insert( d, "SCALEZ", PyInt_FromLong( OB_LOCK_SCALEZ ) ); + PyConstant_Insert( d, "SCALE", + PyInt_FromLong( OB_LOCK_SCALEX|OB_LOCK_SCALEY|OB_LOCK_SCALEZ ) ); + } + return M; +} + +static PyObject *M_Object_RBFlagsDict( void ) +{ + PyObject *M = PyConstant_New( ); + + if( M ) { + BPy_constant *d = ( BPy_constant * ) M; + PyConstant_Insert( d, "DYNAMIC", PyInt_FromLong( OB_DYNAMIC ) ); + PyConstant_Insert( d, "CHILD", PyInt_FromLong( OB_CHILD ) ); + PyConstant_Insert( d, "ACTOR", PyInt_FromLong( OB_ACTOR ) ); + PyConstant_Insert( d, "USEFH", PyInt_FromLong( OB_DO_FH ) ); + PyConstant_Insert( d, "ROTFH", PyInt_FromLong( OB_ROT_FH ) ); + PyConstant_Insert( d, "ANISOTROPIC", + PyInt_FromLong( OB_ANISOTROPIC_FRICTION ) ); + PyConstant_Insert( d, "GHOST", PyInt_FromLong( OB_GHOST ) ); + PyConstant_Insert( d, "RIGIDBODY", PyInt_FromLong( OB_RIGID_BODY ) ); + PyConstant_Insert( d, "BOUNDS", PyInt_FromLong( OB_BOUNDS ) ); + PyConstant_Insert( d, "COLLISION_RESPONSE", + PyInt_FromLong( OB_COLLISION_RESPONSE ) ); + PyConstant_Insert( d, "SECTOR", PyInt_FromLong( OB_SECTOR ) ); + PyConstant_Insert( d, "PROP", PyInt_FromLong( OB_PROP ) ); + PyConstant_Insert( d, "MAINACTOR", PyInt_FromLong( OB_MAINACTOR ) ); + } + return M; +} + +static PyObject *M_Object_RBShapeBoundDict( void ) +{ + PyObject *M = PyConstant_New( ); + + if( M ) { + BPy_constant *d = ( BPy_constant * ) M; + PyConstant_Insert( d, "BOX", PyInt_FromLong( OB_BOUND_BOX ) ); + PyConstant_Insert( d, "SPHERE", PyInt_FromLong( OB_BOUND_SPHERE ) ); + PyConstant_Insert( d, "CYLINDER", PyInt_FromLong( OB_BOUND_CYLINDER ) ); + PyConstant_Insert( d, "CONE", PyInt_FromLong( OB_BOUND_CONE ) ); + PyConstant_Insert( d, "POLYHEDERON", PyInt_FromLong( OB_BOUND_POLYH ) ); + } + return M; +} + +static PyObject *M_Object_IpoKeyTypesDict( void ) +{ + PyObject *M = PyConstant_New( ); + + if( M ) { + BPy_constant *d = ( BPy_constant * ) M; + PyConstant_Insert( d, "LOC", PyInt_FromLong( IPOKEY_LOC ) ); + PyConstant_Insert( d, "ROT", PyInt_FromLong( IPOKEY_ROT ) ); + PyConstant_Insert( d, "SIZE", PyInt_FromLong( IPOKEY_SIZE ) ); + PyConstant_Insert( d, "LOCROT", PyInt_FromLong( IPOKEY_LOCROT ) ); + PyConstant_Insert( d, "LOCROTSIZE", PyInt_FromLong( IPOKEY_LOCROTSIZE ) ); + + PyConstant_Insert( d, "PI_STRENGTH", PyInt_FromLong( IPOKEY_PI_STRENGTH ) ); + PyConstant_Insert( d, "PI_FALLOFF", PyInt_FromLong( IPOKEY_PI_FALLOFF ) ); + PyConstant_Insert( d, "PI_SURFACEDAMP", PyInt_FromLong( IPOKEY_PI_SURFACEDAMP ) ); + PyConstant_Insert( d, "PI_RANDOMDAMP", PyInt_FromLong( IPOKEY_PI_RANDOMDAMP ) ); + PyConstant_Insert( d, "PI_PERM", PyInt_FromLong( IPOKEY_PI_PERM ) ); + } + return M; +} + +/*****************************************************************************/ +/* Function: initObject */ +/*****************************************************************************/ +PyObject *Object_Init( void ) +{ + PyObject *module, *dict; + PyObject *DrawModesDict = M_Object_DrawModesDict( ); + PyObject *DrawTypesDict = M_Object_DrawTypesDict( ); + PyObject *ParentTypesDict = M_Object_ParentTypesDict( ); + PyObject *ProtectDict = M_Object_ProtectDict( ); + PyObject *PITypesDict = M_Object_PITypesDict( ); + PyObject *RBFlagsDict = M_Object_RBFlagsDict( ); + PyObject *RBShapesDict = M_Object_RBShapeBoundDict( ); + PyObject *IpoKeyTypesDict = M_Object_IpoKeyTypesDict( ); + + PyType_Ready( &Object_Type ) ; + + module = Py_InitModule3( "Blender.Object", M_Object_methods, + M_Object_doc ); + + + /* We Should Remove these!!!! */ + PyModule_AddIntConstant( module, "LOC", IPOKEY_LOC ); + PyModule_AddIntConstant( module, "ROT", IPOKEY_ROT ); + PyModule_AddIntConstant( module, "SIZE", IPOKEY_SIZE ); + PyModule_AddIntConstant( module, "LOCROT", IPOKEY_LOCROT ); + PyModule_AddIntConstant( module, "LOCROTSIZE", IPOKEY_LOCROTSIZE ); + + PyModule_AddIntConstant( module, "PI_STRENGTH", IPOKEY_PI_STRENGTH ); + PyModule_AddIntConstant( module, "PI_FALLOFF", IPOKEY_PI_FALLOFF ); + PyModule_AddIntConstant( module, "PI_SURFACEDAMP", IPOKEY_PI_SURFACEDAMP ); + PyModule_AddIntConstant( module, "PI_RANDOMDAMP", IPOKEY_PI_RANDOMDAMP ); + PyModule_AddIntConstant( module, "PI_PERM", IPOKEY_PI_PERM ); + + PyModule_AddIntConstant( module, "NONE",0 ); + PyModule_AddIntConstant( module, "FORCE",PFIELD_FORCE ); + PyModule_AddIntConstant( module, "VORTEX",PFIELD_VORTEX ); + PyModule_AddIntConstant( module, "MAGNET",PFIELD_MAGNET ); + PyModule_AddIntConstant( module, "WIND",PFIELD_WIND ); + /* Only keeping above so as not to break compat */ + + + if( DrawModesDict ) + PyModule_AddObject( module, "DrawModes", DrawModesDict ); + if( DrawTypesDict ) + PyModule_AddObject( module, "DrawTypes", DrawTypesDict ); + if( ParentTypesDict ) + PyModule_AddObject( module, "ParentTypes", ParentTypesDict ); + if( PITypesDict ) + PyModule_AddObject( module, "PITypes", PITypesDict ); + if( ProtectDict ) + PyModule_AddObject( module, "ProtectFlags", ProtectDict ); + if( RBFlagsDict ) + PyModule_AddObject( module, "RBFlags", RBFlagsDict ); + if( RBShapesDict ) + PyModule_AddObject( module, "RBShapes", RBShapesDict ); + if( IpoKeyTypesDict ) + PyModule_AddObject( module, "IpoKeyTypes", IpoKeyTypesDict ); + + /*Add SUBMODULES to the module*/ + dict = PyModule_GetDict( module ); /*borrowed*/ + PyDict_SetItemString(dict, "Pose", Pose_Init()); /*creates a *new* module*/ + /*PyDict_SetItemString(dict, "Constraint", Constraint_Init()); */ /*creates a *new* module*/ + + return ( module ); +} + +/* #####DEPRECATED###### */ + +static PyObject *Object_SetIpo( BPy_Object * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Object_setIpo ); +} + +static PyObject *Object_Select( BPy_Object * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Object_setSelect ); +} + +static PyObject *Object_SetDrawMode( BPy_Object * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)Object_setDrawMode ); +} + +static PyObject *Object_SetDrawType( BPy_Object * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)Object_setDrawType ); +} + +static PyObject *Object_SetMatrix( BPy_Object * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)Object_setMatrix ); +} + +static PyObject *Object_SetEuler( BPy_Object * self, PyObject * args ) +{ + return EXPP_setterWrapperTuple( (void *)self, args, + (setter)Object_setEuler ); +} + +static PyObject *Object_setTimeOffset( BPy_Object * self, PyObject * args ) +{ + float newTimeOffset; + + if( !PyArg_ParseTuple( args, "f", &newTimeOffset ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a float as argument" ); + + self->object->sf = newTimeOffset; + self->object->recalc |= OB_RECALC_OB; + + Py_RETURN_NONE; +} + + +/*************************************************************************/ +/* particle defection methods */ +/*************************************************************************/ + +static PyObject *Object_SetPIDeflection( BPy_Object * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)Object_setPIDeflection ); +} + +static PyObject *Object_SetPIType( BPy_Object * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)Object_setPIType ); +} + +static PyObject *Object_SetPIUseMaxDist( BPy_Object * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)Object_setPIUseMaxDist ); +} + +static PyObject *Object_getPISurfaceDamp( BPy_Object * self ) +{ + if( !self->object->pd && !setupPI(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "particle deflection could not be accessed" ); + + return PyFloat_FromDouble( ( double ) self->object->pd->pdef_damp ); +} + +static PyObject *Object_SetPISurfaceDamp( BPy_Object * self, PyObject * args ) +{ + float value; + + if( !self->object->pd && !setupPI(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "particle deflection could not be accessed" ); + + if( !PyArg_ParseTuple( args, "f", &value ) ) + return NULL; + + self->object->pd->pdef_damp = EXPP_ClampFloat( value, + EXPP_OBJECT_PIDAMP_MIN, EXPP_OBJECT_PIDAMP_MAX ); + self->object->recalc |= OB_RECALC_OB; + Py_RETURN_NONE; +} + +static PyObject *Object_getPIPerm( BPy_Object * self ) +{ + if( !self->object->pd && !setupPI(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "particle deflection could not be accessed" ); + return PyFloat_FromDouble ( (double) self->object->pd->pdef_perm ); +} + +static PyObject *Object_SetPIPerm( BPy_Object * self, PyObject * args ) +{ + float value; + + if( !self->object->pd && !setupPI(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "particle deflection could not be accessed" ); + + if( !PyArg_ParseTuple( args, "f", &value ) ) + return NULL; + + self->object->pd->pdef_perm = EXPP_ClampFloat( value, + EXPP_OBJECT_PIPERM_MIN, EXPP_OBJECT_PIPERM_MAX ); + self->object->recalc |= OB_RECALC_OB; + Py_RETURN_NONE; +} + +static PyObject *Object_getPIStrength( BPy_Object * self ) +{ + if( !self->object->pd && !setupPI(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "particle deflection could not be accessed" ); + + return PyFloat_FromDouble( ( double ) self->object->pd->f_strength ); +} + +static PyObject *Object_setPIStrength( BPy_Object * self, PyObject * args ) +{ + float value; + + if( !self->object->pd && !setupPI(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "particle deflection could not be accessed" ); + + if( !PyArg_ParseTuple( args, "f", &value ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected float argument" ); + + self->object->pd->f_strength = EXPP_ClampFloat( value, + EXPP_OBJECT_PISTRENGTH_MIN, EXPP_OBJECT_PISTRENGTH_MAX ); + self->object->recalc |= OB_RECALC_OB; + Py_RETURN_NONE; +} + +static PyObject *Object_getPIFalloff( BPy_Object * self ) +{ + if( !self->object->pd && !setupPI(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "particle deflection could not be accessed" ); + + return PyFloat_FromDouble( ( double ) self->object->pd->f_power ); +} + +static PyObject *Object_setPIFalloff( BPy_Object * self, PyObject * args ) +{ + float value; + + if( !PyArg_ParseTuple( args, "f", &value ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected float argument" ); + + self->object->pd->f_power = EXPP_ClampFloat( value, + EXPP_OBJECT_PIPOWER_MIN, EXPP_OBJECT_PIPOWER_MAX ); + self->object->recalc |= OB_RECALC_OB; + Py_RETURN_NONE; +} + +static PyObject *Object_getPIMaxDist( BPy_Object * self ) +{ + if( !self->object->pd && !setupPI(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "particle deflection could not be accessed" ); + + return PyFloat_FromDouble( ( double ) self->object->pd->maxdist ); +} + +static PyObject *Object_setPIMaxDist( BPy_Object * self, PyObject * args ) +{ + float value; + + if( !self->object->pd && !setupPI(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "particle deflection could not be accessed" ); + + if( !PyArg_ParseTuple( args, "f", &value ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected float argument" ); + + self->object->pd->maxdist = EXPP_ClampFloat( value, + EXPP_OBJECT_PIMAXDIST_MIN, EXPP_OBJECT_PIMAXDIST_MAX ); + self->object->recalc |= OB_RECALC_OB; + Py_RETURN_NONE; +} + +static PyObject *Object_getPIRandomDamp( BPy_Object * self ) +{ + if( !self->object->pd && !setupPI(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "particle deflection could not be accessed" ); + + return PyFloat_FromDouble( ( double ) self->object->pd->pdef_rdamp ); +} + +static PyObject *Object_setPIRandomDamp( BPy_Object * self, PyObject * args ) +{ + float value; + + if( !self->object->pd && !setupPI(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "particle deflection could not be accessed" ); + + if( !PyArg_ParseTuple( args, "f", &value ) ) + return NULL; + + self->object->pd->pdef_rdamp = EXPP_ClampFloat( value, + EXPP_OBJECT_PIRDAMP_MIN, EXPP_OBJECT_PIRDAMP_MAX ); + self->object->recalc |= OB_RECALC_OB; + Py_RETURN_NONE; +} + +/*************************************************************************/ +/* softbody methods */ +/*************************************************************************/ + +static PyObject *Object_getSBMass( BPy_Object * self ) +{ + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + return PyFloat_FromDouble( ( double ) self->object->soft->nodemass ); +} + +static PyObject *Object_setSBMass( BPy_Object * self, PyObject * args ) +{ + float value; + + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + if( !PyArg_ParseTuple( args, "f", &value ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected float argument" ); + + self->object->soft->nodemass = EXPP_ClampFloat( value, + EXPP_OBJECT_SBNODEMASSMIN, EXPP_OBJECT_SBNODEMASSMAX ); + self->object->recalc |= OB_RECALC_OB; + + Py_RETURN_NONE; +} + +static PyObject *Object_getSBGravity( BPy_Object * self ) +{ + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + return PyFloat_FromDouble( ( double ) self->object->soft->grav ); +} + +static PyObject *Object_setSBGravity( BPy_Object * self, PyObject * args ) +{ + float value; + + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + if( !PyArg_ParseTuple( args, "f", &value ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected float argument" ); + + self->object->soft->grav = EXPP_ClampFloat( value, + EXPP_OBJECT_SBGRAVMIN, EXPP_OBJECT_SBGRAVMAX ); + self->object->recalc |= OB_RECALC_OB; + + Py_RETURN_NONE; +} + +static PyObject *Object_getSBFriction( BPy_Object * self ) +{ + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + return PyFloat_FromDouble( ( double ) self->object->soft->mediafrict ); +} + +static PyObject *Object_setSBFriction( BPy_Object * self, PyObject * args ) +{ + float value; + + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + if( !PyArg_ParseTuple( args, "f", &value ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected float argument" ); + + self->object->soft->mediafrict = EXPP_ClampFloat( value, + EXPP_OBJECT_SBMEDIAFRICTMIN, EXPP_OBJECT_SBMEDIAFRICTMAX ); + self->object->recalc |= OB_RECALC_OB; + Py_RETURN_NONE; +} + +static PyObject *Object_getSBErrorLimit( BPy_Object * self ) +{ + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + return PyFloat_FromDouble( ( double ) self->object->soft->rklimit ); +} + +static PyObject *Object_setSBErrorLimit( BPy_Object * self, PyObject * args ) +{ + float value; + + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + if( !PyArg_ParseTuple( args, "f", &value ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected float argument" ); + + self->object->soft->rklimit = EXPP_ClampFloat( value, + EXPP_OBJECT_SBRKLIMITMIN, EXPP_OBJECT_SBRKLIMITMAX ); + self->object->recalc |= OB_RECALC_OB; + + Py_RETURN_NONE; +} + +static PyObject *Object_getSBGoalSpring( BPy_Object * self ) +{ + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + return PyFloat_FromDouble( ( double ) self->object->soft->goalspring ); +} + +static PyObject *Object_setSBGoalSpring( BPy_Object * self, PyObject * args ) +{ + float value; + + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + if( !PyArg_ParseTuple( args, "f", &value ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected float argument" ); + + self->object->soft->goalspring = EXPP_ClampFloat( value, + EXPP_OBJECT_SBGOALSPRINGMIN, EXPP_OBJECT_SBGOALSPRINGMAX ); + self->object->recalc |= OB_RECALC_OB; + + Py_RETURN_NONE; +} + +static PyObject *Object_getSBGoalFriction( BPy_Object * self ) +{ + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + return PyFloat_FromDouble( ( double ) self->object->soft->goalfrict ); +} + +static PyObject *Object_setSBGoalFriction( BPy_Object * self, PyObject * args ) +{ + float value; + + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + if( !PyArg_ParseTuple( args, "f", &value ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected float argument" ); + + self->object->soft->goalfrict = EXPP_ClampFloat( value, + EXPP_OBJECT_SBGOALFRICTMIN, EXPP_OBJECT_SBGOALFRICTMAX ); + self->object->recalc |= OB_RECALC_OB; + + Py_RETURN_NONE; +} + +static PyObject *Object_getSBMinGoal( BPy_Object * self ) +{ + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + return PyFloat_FromDouble( ( double ) self->object->soft->mingoal ); +} + +static PyObject *Object_setSBMinGoal( BPy_Object * self, PyObject * args ) +{ + float value; + + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + if( !PyArg_ParseTuple( args, "f", &value ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected float argument" ); + + self->object->soft->mingoal = EXPP_ClampFloat( value, + EXPP_OBJECT_SBMINGOALMIN, EXPP_OBJECT_SBMINGOALMAX ); + self->object->recalc |= OB_RECALC_OB; + + Py_RETURN_NONE; +} + +static PyObject *Object_getSBMaxGoal( BPy_Object * self ) +{ + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + return PyFloat_FromDouble( ( double ) self->object->soft->maxgoal ); +} + +static PyObject *Object_setSBMaxGoal( BPy_Object * self, PyObject * args ) +{ + float value; + + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + if( !PyArg_ParseTuple( args, "f", &value ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected float argument" ); + + self->object->soft->maxgoal = EXPP_ClampFloat( value, + EXPP_OBJECT_SBMAXGOALMIN, EXPP_OBJECT_SBMAXGOALMAX ); + self->object->recalc |= OB_RECALC_OB; + + Py_RETURN_NONE; +} + +static PyObject *Object_getSBDefaultGoal( BPy_Object * self ) +{ + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + return PyFloat_FromDouble( ( double ) self->object->soft->defgoal ); +} + +static PyObject *Object_setSBDefaultGoal( BPy_Object * self, PyObject * args ) +{ + float value; + + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + if( !PyArg_ParseTuple( args, "f", &value ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected float argument" ); + + self->object->soft->defgoal = EXPP_ClampFloat( value, + EXPP_OBJECT_SBDEFGOALMIN, EXPP_OBJECT_SBDEFGOALMAX ); + self->object->recalc |= OB_RECALC_OB; + + Py_RETURN_NONE; +} + +static PyObject *Object_getSBInnerSpring( BPy_Object * self ) +{ + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + return PyFloat_FromDouble( ( double ) self->object->soft->inspring ); +} + +static PyObject *Object_setSBInnerSpring( BPy_Object * self, PyObject * args ) +{ + float value; + + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + if( !PyArg_ParseTuple( args, "f", &value ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected float argument" ); + + self->object->soft->inspring = EXPP_ClampFloat( value, + EXPP_OBJECT_SBINSPRINGMIN, EXPP_OBJECT_SBINSPRINGMAX ); + self->object->recalc |= OB_RECALC_OB; + + Py_RETURN_NONE; +} + +static PyObject *Object_getSBInnerSpringFriction( BPy_Object * self ) +{ + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + return PyFloat_FromDouble( ( double ) self->object->soft->infrict ); +} + +static PyObject *Object_setSBInnerSpringFriction( BPy_Object * self, + PyObject * args ) +{ + float value; + + if( !self->object->soft && !setupSB(self->object) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "softbody could not be accessed" ); + + if( !PyArg_ParseTuple( args, "f", &value ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected float argument" ); + + self->object->soft->infrict = EXPP_ClampFloat( value, + EXPP_OBJECT_SBINFRICTMIN, EXPP_OBJECT_SBINFRICTMAX ); + self->object->recalc |= OB_RECALC_OB; + + Py_RETURN_NONE; +} + +static PyObject *Object_SetSBUseGoal( BPy_Object * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)Object_setSBUseGoal ); +} + +static PyObject *Object_SetSBUseEdges( BPy_Object * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)Object_setSBUseEdges ); +} + +static PyObject *Object_SetSBStiffQuads( BPy_Object * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)Object_setSBStiffQuads ); +} diff --git a/source/blender/python/api2_2x/Object.h b/source/blender/python/api2_2x/Object.h new file mode 100644 index 00000000000..557513560fd --- /dev/null +++ b/source/blender/python/api2_2x/Object.h @@ -0,0 +1,62 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Michel Selten + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_OBJECT_H +#define EXPP_OBJECT_H + +#include +#include "DNA_object_types.h" + +/* The Object PyType Object defined in Object.c */ +extern PyTypeObject Object_Type; + +#define BPy_Object_Check(v) \ + ((v)->ob_type == &Object_Type) /* for type checking */ + +/*****************************************************************************/ +/* Python BPy_Object structure definition. */ +/*****************************************************************************/ +typedef struct { + PyObject_HEAD + struct Object *object; /* libdata must be second */ + short realtype; +} BPy_Object; + +PyObject *Object_Init( void ); +PyObject *Object_CreatePyObject( struct Object *obj ); +Object *Object_FromPyObject( PyObject * py_obj ); + +void Object_updateDag( void *data ); + +int EXPP_add_obdata( struct Object *object ); + +#endif /* EXPP_OBJECT_H */ diff --git a/source/blender/python/api2_2x/Particle.c b/source/blender/python/api2_2x/Particle.c new file mode 100644 index 00000000000..e2fdbc5b6ad --- /dev/null +++ b/source/blender/python/api2_2x/Particle.c @@ -0,0 +1,1040 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Jacques Guignot, Jean-Michel Soler + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "Particle.h" /*This must come first */ + +#include "DNA_object_types.h" +#include "BKE_effect.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_object.h" +#include "BLI_blenlib.h" +#include "gen_utils.h" + +/*****************************************************************************/ +/* Python API function prototypes for the Particle module. */ +/*****************************************************************************/ +PyObject *M_Particle_New( PyObject * self, PyObject * args ); +PyObject *M_Particle_Get( PyObject * self, PyObject * args ); + +/*****************************************************************************/ +/* Python BPy_Particle methods declarations: */ +/*****************************************************************************/ +PyObject *Effect_getType( BPy_Effect * self ); +PyObject *Effect_setType( BPy_Effect * self, PyObject * args ); +PyObject *Effect_getFlag( BPy_Effect * self ); +PyObject *Effect_setFlag( BPy_Effect * self, PyObject * args ); +PyObject *Particle_getSta( BPy_Particle * self ); +PyObject *Particle_setSta( BPy_Particle * self, PyObject * a ); +PyObject *Particle_getEnd( BPy_Particle * self ); +PyObject *Particle_setEnd( BPy_Particle * self, PyObject * a ); +PyObject *Particle_getLifetime( BPy_Particle * self ); +PyObject *Particle_setLifetime( BPy_Particle * self, PyObject * a ); +PyObject *Particle_getNormfac( BPy_Particle * self ); +PyObject *Particle_setNormfac( BPy_Particle * self, PyObject * a ); +PyObject *Particle_getObfac( BPy_Particle * self ); +PyObject *Particle_setObfac( BPy_Particle * self, PyObject * a ); +PyObject *Particle_getRandfac( BPy_Particle * self ); +PyObject *Particle_setRandfac( BPy_Particle * self, PyObject * a ); +PyObject *Particle_getTexfac( BPy_Particle * self ); +PyObject *Particle_setTexfac( BPy_Particle * self, PyObject * a ); +PyObject *Particle_getRandlife( BPy_Particle * self ); +PyObject *Particle_setRandlife( BPy_Particle * self, PyObject * a ); +PyObject *Particle_getNabla( BPy_Particle * self ); +PyObject *Particle_setNabla( BPy_Particle * self, PyObject * a ); +PyObject *Particle_getVectsize( BPy_Particle * self ); +PyObject *Particle_setVectsize( BPy_Particle * self, PyObject * a ); +PyObject *Particle_getTotpart( BPy_Particle * self ); +PyObject *Particle_setTotpart( BPy_Particle * self, PyObject * a ); +PyObject *Particle_getTotkey( BPy_Particle * self ); +PyObject *Particle_setTotkey( BPy_Particle * self, PyObject * a ); +PyObject *Particle_getSeed( BPy_Particle * self ); +PyObject *Particle_setSeed( BPy_Particle * self, PyObject * a ); +PyObject *Particle_getForce( BPy_Particle * self ); +PyObject *Particle_setForce( BPy_Particle * self, PyObject * a ); +PyObject *Particle_getMult( BPy_Particle * self ); +PyObject *Particle_setMult( BPy_Particle * self, PyObject * a ); +PyObject *Particle_getLife( BPy_Particle * self ); +PyObject *Particle_setLife( BPy_Particle * self, PyObject * a ); +PyObject *Particle_getMat( BPy_Particle * self ); +PyObject *Particle_setMat( BPy_Particle * self, PyObject * a ); +PyObject *Particle_getChild( BPy_Particle * self ); +PyObject *Particle_setChild( BPy_Particle * self, PyObject * a ); +PyObject *Particle_getDefvec( BPy_Particle * self ); +PyObject *Particle_setDefvec( BPy_Particle * self, PyObject * a ); + +/*****************************************************************************/ +/* Python Particle_Type callback function prototypes: */ +/*****************************************************************************/ +void ParticleDeAlloc( BPy_Particle * msh ); +//int ParticlePrint (BPy_Particle *msh, FILE *fp, int flags); +int ParticleSetAttr( BPy_Particle * msh, char *name, PyObject * v ); +PyObject *ParticleGetAttr( BPy_Particle * msh, char *name ); +PyObject *ParticleRepr( void ); +PyObject *ParticleCreatePyObject( struct Effect *particle ); +int ParticleCheckPyObject( PyObject * py_obj ); +struct Particle *ParticleFromPyObject( PyObject * py_obj ); + + +/*****************************************************************************/ +/* Python BPy_Particle methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_Particle_methods[] = { + {"getType", ( PyCFunction ) Effect_getType, + METH_NOARGS, "() - Return Effect type"}, + {"setType", ( PyCFunction ) Effect_setType, + METH_VARARGS, "() - Set Effect type"}, + {"getFlag", ( PyCFunction ) Effect_getFlag, + METH_NOARGS, "() - Return Effect flag"}, + {"setFlag", ( PyCFunction ) Effect_setFlag, + METH_VARARGS, "() - Set Effect flag"}, + {"getStartTime", ( PyCFunction ) Particle_getSta, + METH_NOARGS, "()-Return particle start time"}, + {"setStartTime", ( PyCFunction ) Particle_setSta, METH_VARARGS, + "()- Sets particle start time"}, + {"getEndTime", ( PyCFunction ) Particle_getEnd, + METH_NOARGS, "()-Return particle end time"}, + {"setEndTime", ( PyCFunction ) Particle_setEnd, METH_VARARGS, + "()- Sets particle end time"}, + {"getLifetime", ( PyCFunction ) Particle_getLifetime, + METH_NOARGS, "()-Return particle life time"}, + {"setLifetime", ( PyCFunction ) Particle_setLifetime, METH_VARARGS, + "()- Sets particle life time "}, + {"getNormfac", ( PyCFunction ) Particle_getNormfac, + METH_NOARGS, "()-Return particle life time"}, + {"setNormfac", ( PyCFunction ) Particle_setNormfac, METH_VARARGS, + "()- Sets particle life time "}, + {"getObfac", ( PyCFunction ) Particle_getObfac, + METH_NOARGS, "()-Return particle life time"}, + {"setObfac", ( PyCFunction ) Particle_setObfac, METH_VARARGS, + "()- Sets particle life time "}, + {"getRandfac", ( PyCFunction ) Particle_getRandfac, + METH_NOARGS, "()-Return particle life time"}, + {"setRandfac", ( PyCFunction ) Particle_setRandfac, METH_VARARGS, + "()- Sets particle life time "}, + {"getTexfac", ( PyCFunction ) Particle_getTexfac, + METH_NOARGS, "()-Return particle life time"}, + {"setTexfac", ( PyCFunction ) Particle_setTexfac, METH_VARARGS, + "()- Sets particle life time "}, + {"getRandlife", ( PyCFunction ) Particle_getRandlife, + METH_NOARGS, "()-Return particle life time"}, + {"setRandlife", ( PyCFunction ) Particle_setRandlife, METH_VARARGS, + "()- Sets particle life time "}, + {"getNabla", ( PyCFunction ) Particle_getNabla, + METH_NOARGS, "()-Return particle life time"}, + {"setNabla", ( PyCFunction ) Particle_setNabla, METH_VARARGS, + "()- Sets particle life time "}, + {"getVectsize", ( PyCFunction ) Particle_getVectsize, + METH_NOARGS, "()-Return particle life time"}, + {"setVectsize", ( PyCFunction ) Particle_setVectsize, METH_VARARGS, + "()- Sets particle life time "}, + {"getTotpart", ( PyCFunction ) Particle_getTotpart, + METH_NOARGS, "()-Return particle life time"}, + {"setTotpart", ( PyCFunction ) Particle_setTotpart, METH_VARARGS, + "()- Sets particle life time "}, + {"getTotkey", ( PyCFunction ) Particle_getTotkey, + METH_NOARGS, "()-Return particle life time"}, + {"setTotkey", ( PyCFunction ) Particle_setTotkey, METH_VARARGS, + "()- Sets particle life time "}, + {"getSeed", ( PyCFunction ) Particle_getSeed, + METH_NOARGS, "()-Return particle life time"}, + {"setSeed", ( PyCFunction ) Particle_setSeed, METH_VARARGS, + "()- Sets particle life time "}, + {"getForce", ( PyCFunction ) Particle_getForce, + METH_NOARGS, "()-Return particle life time"}, + {"setForce", ( PyCFunction ) Particle_setForce, METH_VARARGS, + "()- Sets particle life time "}, + {"getMult", ( PyCFunction ) Particle_getMult, + METH_NOARGS, "()-Return particle life time"}, + {"setMult", ( PyCFunction ) Particle_setMult, METH_VARARGS, + "()- Sets particle life time "}, + {"getLife", ( PyCFunction ) Particle_getLife, + METH_NOARGS, "()-Return particle life time"}, + {"setLife", ( PyCFunction ) Particle_setLife, METH_VARARGS, + "()- Sets particle life time "}, + {"getMat", ( PyCFunction ) Particle_getMat, + METH_NOARGS, "()-Return particle life time"}, + {"setMat", ( PyCFunction ) Particle_setMat, METH_VARARGS, + "()- Sets particle life time "}, + {"getChild", ( PyCFunction ) Particle_getChild, + METH_NOARGS, "()-Return particle life time"}, + {"setChild", ( PyCFunction ) Particle_setChild, METH_VARARGS, + "()- Sets particle life time "}, + {"getDefvec", ( PyCFunction ) Particle_getDefvec, + METH_NOARGS, "()-Return particle life time"}, + {"setDefvec", ( PyCFunction ) Particle_setDefvec, METH_VARARGS, + "()- Sets particle life time "}, + + + {NULL, NULL, 0, NULL} +}; + +/**************** prototypes ********************/ +PyObject *Particle_Init( void ); + + +/*****************************************************************************/ +/* Python Particle_Type structure definition: */ +/*****************************************************************************/ + +PyTypeObject Particle_Type = { + PyObject_HEAD_INIT( NULL ) + 0, + "Particle", + sizeof( BPy_Particle ), + 0, + + ( destructor ) ParticleDeAlloc, + 0, + ( getattrfunc ) ParticleGetAttr, + ( setattrfunc ) ParticleSetAttr, + 0, + ( reprfunc ) ParticleRepr, + 0, + 0, + 0, + 0, + 0, 0, 0, 0, 0, 0, + 0, + 0, 0, 0, 0, 0, 0, + BPy_Particle_methods, + 0, +}; +/*****************************************************************************/ +/* The following string definitions are used for documentation strings. */ +/* In Python these will be written to the console when doing a */ +/* Blender.Particle.__doc__ */ +/*****************************************************************************/ +char M_Particle_doc[] = "The Blender Particle module\n\n\ +This module provides access to **Object Data** in Blender.\n\ +Functions :\n\ + New(object mesh's name) : creates a new part object and adds it to the given mesh object \n\ + Get(name) : retreives a particle with the given name (mandatory)\n\ + get(name) : same as Get. Kept for compatibility reasons.\n"; +char M_Particle_New_doc[] = "New(name) : creates a new part object and adds it to the given mesh object\n"; +char M_Particle_Get_doc[] = "xxx"; + + +/*****************************************************************************/ +/* Python method structure definition for Blender.Particle module: */ +/*****************************************************************************/ +struct PyMethodDef M_Particle_methods[] = { + {"New", ( PyCFunction ) M_Particle_New, METH_VARARGS, M_Particle_New_doc}, + {"Get", M_Particle_Get, METH_VARARGS, M_Particle_Get_doc}, + {"get", M_Particle_Get, METH_VARARGS, M_Particle_Get_doc}, + {NULL, NULL, 0, NULL} +}; + + +/*****************************************************************************/ +/* Function: M_Particle_New */ +/* Python equivalent: Blender.Effect.Particle.New */ +/* Description : Create a particle effect and add a link */ +/* to the given mesh-type Object */ +/* Data : String mesh object name */ +/* Return : pyobject particle */ +/*****************************************************************************/ +PyObject *M_Particle_New( PyObject * self, PyObject * args ) +{ + BPy_Effect *pyeffect; + Effect *bleffect = 0; + Object *ob; + char *name = NULL; + + if( !PyArg_ParseTuple( args, "s", &name ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + + for( ob = G.main->object.first; ob; ob = ob->id.next ) + if( !strcmp( name, ob->id.name + 2 ) ) + break; + + if( !ob ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "object does not exist" ); + + if( ob->type != OB_MESH ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "object is not a mesh" ); + + pyeffect = ( BPy_Effect * ) PyObject_NEW( BPy_Effect, &Effect_Type ); + if( !pyeffect ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create Effect Data object" ); + + bleffect = add_effect( EFF_PARTICLE ); + if( !bleffect ) { + Py_DECREF( pyeffect ); + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't create Effect Data in Blender" ); + } + + pyeffect->effect = (PartEff *)bleffect; + BLI_addtail( &ob->effect, bleffect ); + + return ( PyObject * ) pyeffect; +} + +/*****************************************************************************/ +/* Function: M_Particle_Get */ +/* Python equivalent: Blender.Effect.Particle.Get */ +/*****************************************************************************/ +PyObject *M_Particle_Get( PyObject * self, PyObject * args ) +{ + /*arguments : string object name + int : position of effect in the obj's effect list */ + char *name = 0; + Object *object_iter; + Effect *eff; + BPy_Particle *wanted_eff; + int num, i; + + if( !PyArg_ParseTuple( args, "si", &name, &num ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected string int argument" ) ); + + object_iter = G.main->object.first; + if( !object_iter ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "Scene contains no object" ); + + while( object_iter ) { + if( strcmp( name, object_iter->id.name + 2 ) ) { + object_iter = object_iter->id.next; + continue; + } + + if( object_iter->effect.first != NULL ) { + eff = object_iter->effect.first; + for( i = 0; i < num; i++ ) { + if( eff->type != EFF_PARTICLE ) + continue; + eff = eff->next; + if( !eff ) + return ( EXPP_ReturnPyObjError + ( PyExc_AttributeError, + "Object" ) ); + } + wanted_eff = + ( BPy_Particle * ) PyObject_NEW( BPy_Particle, + &Particle_Type ); + wanted_eff->particle = eff; + return ( PyObject * ) wanted_eff; + } + object_iter = object_iter->id.next; + } + Py_INCREF( Py_None ); + return Py_None; +} + +/*****************************************************************************/ +/* Function: Particle_Init */ +/*****************************************************************************/ +PyObject *Particle_Init( void ) +{ + PyObject *submodule; + + if( PyType_Ready( &Particle_Type) < 0) + return NULL; + + submodule = + Py_InitModule3( "Blender.Particle", M_Particle_methods, M_Particle_doc ); + return ( submodule ); +} + +/*****************************************************************************/ +/* Python BPy_Particle methods: */ +/*****************************************************************************/ + +PyObject *Particle_getSta( BPy_Particle * self ) +{ + + PartEff *ptr = ( PartEff * ) self->particle; + return PyFloat_FromDouble( ptr->sta ); +} + + + +PyObject *Particle_setSta( BPy_Particle * self, PyObject * args ) +{ + PartEff *ptr = ( PartEff * ) self->particle; + float val = 0; + if( !PyArg_ParseTuple( args, "f", &val ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected float argument" ) ); + ptr->sta = val; + Py_INCREF( Py_None ); + return Py_None; +} + +PyObject *Particle_getEnd( BPy_Particle * self ) +{ + + PartEff *ptr = ( PartEff * ) self->particle; + return PyFloat_FromDouble( ptr->end ); +} + + + +PyObject *Particle_setEnd( BPy_Particle * self, PyObject * args ) +{ + float val = 0; + PartEff *ptr = ( PartEff * ) self->particle; + if( !PyArg_ParseTuple( args, "f", &val ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected float argument" ) ); + ptr->end = val; + Py_INCREF( Py_None ); + return Py_None; +} + +PyObject *Particle_getLifetime( BPy_Particle * self ) +{ + + PartEff *ptr = ( PartEff * ) self->particle; + return PyFloat_FromDouble( ptr->lifetime ); +} + + + +PyObject *Particle_setLifetime( BPy_Particle * self, PyObject * args ) +{ + PartEff *ptr = ( PartEff * ) self->particle; + float val = 0; + if( !PyArg_ParseTuple( args, "f", &val ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected float argument" ) ); + ptr->lifetime = val; + Py_INCREF( Py_None ); + return Py_None; +} + + +PyObject *Particle_getNormfac( BPy_Particle * self ) +{ + + PartEff *ptr = ( PartEff * ) self->particle; + return PyFloat_FromDouble( ptr->normfac ); +} + + + +PyObject *Particle_setNormfac( BPy_Particle * self, PyObject * args ) +{ + PartEff *ptr = ( PartEff * ) self->particle; + float val = 0; + if( !PyArg_ParseTuple( args, "f", &val ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected float argument" ) ); + ptr->normfac = val; + Py_INCREF( Py_None ); + return Py_None; +} + + + +PyObject *Particle_getObfac( BPy_Particle * self ) +{ + + PartEff *ptr = ( PartEff * ) self->particle; + return PyFloat_FromDouble( ptr->obfac ); +} + + + +PyObject *Particle_setObfac( BPy_Particle * self, PyObject * args ) +{ + float val = 0; + PartEff *ptr = ( PartEff * ) self->particle; + if( !PyArg_ParseTuple( args, "f", &val ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected float argument" ) ); + ptr->obfac = val; + Py_INCREF( Py_None ); + return Py_None; +} + + + +PyObject *Particle_getRandfac( BPy_Particle * self ) +{ + + PartEff *ptr = ( PartEff * ) self->particle; + return PyFloat_FromDouble( ptr->randfac ); +} + + + +PyObject *Particle_setRandfac( BPy_Particle * self, PyObject * args ) +{ + float val = 0; + PartEff *ptr = ( PartEff * ) self->particle; + if( !PyArg_ParseTuple( args, "f", &val ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected float argument" ) ); + ptr->randfac = val; + Py_INCREF( Py_None ); + return Py_None; +} + + + +PyObject *Particle_getTexfac( BPy_Particle * self ) +{ + + PartEff *ptr = ( PartEff * ) self->particle; + return PyFloat_FromDouble( ptr->texfac ); +} + + + +PyObject *Particle_setTexfac( BPy_Particle * self, PyObject * args ) +{ + PartEff *ptr = ( PartEff * ) self->particle; + float val = 0; + if( !PyArg_ParseTuple( args, "f", &val ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected float argument" ) ); + ptr->texfac = val; + Py_INCREF( Py_None ); + return Py_None; +} + + + +PyObject *Particle_getRandlife( BPy_Particle * self ) +{ + + PartEff *ptr = ( PartEff * ) self->particle; + return PyFloat_FromDouble( ptr->randlife ); +} + + + +PyObject *Particle_setRandlife( BPy_Particle * self, PyObject * args ) +{ + PartEff *ptr = ( PartEff * ) self->particle; + float val = 0; + if( !PyArg_ParseTuple( args, "f", &val ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected float argument" ) ); + ptr->randlife = val; + Py_INCREF( Py_None ); + return Py_None; +} + + + +PyObject *Particle_getNabla( BPy_Particle * self ) +{ + + PartEff *ptr = ( PartEff * ) self->particle; + return PyFloat_FromDouble( ptr->nabla ); +} + + + +PyObject *Particle_setNabla( BPy_Particle * self, PyObject * args ) +{ + PartEff *ptr = ( PartEff * ) self->particle; + float val = 0; + if( !PyArg_ParseTuple( args, "f", &val ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected float argument" ) ); + ptr->nabla = val; + Py_INCREF( Py_None ); + return Py_None; +} + + + +PyObject *Particle_getVectsize( BPy_Particle * self ) +{ + + PartEff *ptr = ( PartEff * ) self->particle; + return PyFloat_FromDouble( ptr->vectsize ); +} + + + +PyObject *Particle_setVectsize( BPy_Particle * self, PyObject * args ) +{ + PartEff *ptr = ( PartEff * ) self->particle; + float val = 0; + if( !PyArg_ParseTuple( args, "f", &val ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected float argument" ) ); + ptr->vectsize = val; + Py_INCREF( Py_None ); + return Py_None; +} + + +PyObject *Particle_getTotpart( BPy_Particle * self ) +{ + + PartEff *ptr = ( PartEff * ) self->particle; + return PyInt_FromLong( ptr->totpart ); +} + + + +PyObject *Particle_setTotpart( BPy_Particle * self, PyObject * args ) +{ + int val = 0; + PartEff *ptr = ( PartEff * ) self->particle; + if( !PyArg_ParseTuple( args, "i", &val ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected int argument" ) ); + ptr->totpart = val; + Py_INCREF( Py_None ); + return Py_None; +} + + +PyObject *Particle_getTotkey( BPy_Particle * self ) +{ + + PartEff *ptr = ( PartEff * ) self->particle; + return PyInt_FromLong( ptr->totkey ); +} + + + +PyObject *Particle_setTotkey( BPy_Particle * self, PyObject * args ) +{ + PartEff *ptr = ( PartEff * ) self->particle; + int val = 0; + if( !PyArg_ParseTuple( args, "i", &val ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected int argument" ) ); + ptr->totkey = val; + Py_INCREF( Py_None ); + return Py_None; +} + + + +PyObject *Particle_getSeed( BPy_Particle * self ) +{ + + PartEff *ptr = ( PartEff * ) self->particle; + return PyInt_FromLong( ptr->seed ); +} + + + +PyObject *Particle_setSeed( BPy_Particle * self, PyObject * args ) +{ + PartEff *ptr = ( PartEff * ) self->particle; + int val = 0; + if( !PyArg_ParseTuple( args, "i", &val ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected int argument" ) ); + ptr->seed = val; + Py_INCREF( Py_None ); + return Py_None; +} + +PyObject *Particle_getForce( BPy_Particle * self ) +{ + + PartEff *ptr = ( PartEff * ) self->particle; + return Py_BuildValue( "(f,f,f)", ptr->force[0], ptr->force[1], + ptr->force[2] ); +} + + +PyObject *Particle_setForce( BPy_Particle * self, PyObject * args ) +{ + PartEff *ptr = ( PartEff * ) self->particle; + float val[3]; + if( PyTuple_Size( args ) == 1 ) + args = PyTuple_GetItem( args, 0 ); + val[0] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 0 ) ); + val[1] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 1 ) ); + val[2] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 2 ) ); + /* + if (!PyArg_ParseTuple(args, "fff", val,val+1,val+2 )) + return(EXPP_ReturnPyObjError(PyExc_AttributeError,\ + "expected three float arguments")); + */ + ptr->force[0] = val[0]; + ptr->force[1] = val[1]; + ptr->force[2] = val[2]; + Py_INCREF( Py_None ); + return Py_None; +} + +PyObject *Particle_getMult( BPy_Particle * self ) +{ + + PartEff *ptr = ( PartEff * ) self->particle; + return Py_BuildValue( "(f,f,f,f)", + ptr->mult[0], ptr->mult[1], ptr->mult[2], + ptr->mult[3] ); +} + + +PyObject *Particle_setMult( BPy_Particle * self, PyObject * args ) +{ + PartEff *ptr = ( PartEff * ) self->particle; + float val[4]; + if( PyTuple_Size( args ) == 1 ) + args = PyTuple_GetItem( args, 0 ); + val[0] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 0 ) ); + val[1] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 1 ) ); + val[2] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 2 ) ); + val[3] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 3 ) ); + ptr->mult[0] = val[0]; + ptr->mult[1] = val[1]; + ptr->mult[2] = val[2]; + ptr->mult[3] = val[3]; + Py_INCREF( Py_None ); + return Py_None; +} + + + + +PyObject *Particle_getLife( BPy_Particle * self ) +{ + + PartEff *ptr = ( PartEff * ) self->particle; + return Py_BuildValue( "(f,f,f,f)", + ptr->life[0], ptr->life[1], ptr->life[2], + ptr->life[3] ); +} + + +PyObject *Particle_setLife( BPy_Particle * self, PyObject * args ) +{ + PartEff *ptr = ( PartEff * ) self->particle; + float val[4]; + if( PyTuple_Size( args ) == 1 ) + args = PyTuple_GetItem( args, 0 ); + val[0] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 0 ) ); + val[1] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 1 ) ); + val[2] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 2 ) ); + val[3] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 3 ) ); + ptr->life[0] = val[0]; + ptr->life[1] = val[1]; + ptr->life[2] = val[2]; + ptr->life[3] = val[3]; + Py_INCREF( Py_None ); + return Py_None; +} + + + +PyObject *Particle_getChild( BPy_Particle * self ) +{ + + PartEff *ptr = ( PartEff * ) self->particle; + return Py_BuildValue( "(f,f,f,f)", + ptr->child[0], ptr->child[1], ptr->child[2], + ptr->child[3] ); +} + + +PyObject *Particle_setChild( BPy_Particle * self, PyObject * args ) +{ + PartEff *ptr = ( PartEff * ) self->particle; + float val[4]; + if( PyTuple_Size( args ) == 1 ) + args = PyTuple_GetItem( args, 0 ); + val[0] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 0 ) ); + val[1] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 1 ) ); + val[2] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 2 ) ); + val[3] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 3 ) ); + ptr->child[0] = (short)val[0]; + ptr->child[1] = (short)val[1]; + ptr->child[2] = (short)val[2]; + ptr->child[3] = (short)val[3]; + Py_INCREF( Py_None ); + return Py_None; +} + + + +PyObject *Particle_getMat( BPy_Particle * self ) +{ + + PartEff *ptr = ( PartEff * ) self->particle; + return Py_BuildValue( "(f,f,f,f)", + ptr->mat[0], ptr->mat[1], ptr->mat[2], + ptr->mat[3] ); +} + + +PyObject *Particle_setMat( BPy_Particle * self, PyObject * args ) +{ + PartEff *ptr = ( PartEff * ) self->particle; + float val[4]; + if( PyTuple_Size( args ) == 1 ) + args = PyTuple_GetItem( args, 0 ); + val[0] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 0 ) ); + val[1] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 1 ) ); + val[2] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 2 ) ); + val[3] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 3 ) ); + ptr->mat[0] = (short)val[0]; + ptr->mat[1] = (short)val[1]; + ptr->mat[2] = (short)val[2]; + ptr->mat[3] = (short)val[3]; + Py_INCREF( Py_None ); + return Py_None; +} + + +PyObject *Particle_getDefvec( BPy_Particle * self ) +{ + + PartEff *ptr = ( PartEff * ) self->particle; + return Py_BuildValue( "(f,f,f)", + ptr->defvec[0], ptr->defvec[1], ptr->defvec[2] ); +} + + +PyObject *Particle_setDefvec( BPy_Particle * self, PyObject * args ) +{ + PartEff *ptr = ( PartEff * ) self->particle; + float val[3]; + if( PyTuple_Size( args ) == 1 ) + args = PyTuple_GetItem( args, 0 ); + val[0] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 0 ) ); + val[1] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 1 ) ); + val[2] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 2 ) ); + ptr->defvec[0] = val[0]; + ptr->defvec[1] = val[1]; + ptr->defvec[2] = val[2]; + Py_INCREF( Py_None ); + return Py_None; +} + + +/*****************************************************************************/ +/* Function: ParticleDeAlloc */ +/* Description: This is a callback function for the BPy_Particle type. It is */ +/* the destructor function. */ +/*****************************************************************************/ +void ParticleDeAlloc( BPy_Particle * self ) +{ + PartEff *ptr = ( PartEff * ) self; + PyObject_DEL( ptr ); +} + +/*****************************************************************************/ +/* Function: ParticleGetAttr */ +/* Description: This is a callback function for the BPy_Particle type. It is */ +/* the function that accesses BPy_Particle "member variables" */ +/* and methods. */ +/*****************************************************************************/ + + +PyObject *ParticleGetAttr( BPy_Particle * self, char *name ) +{ + + if( strcmp( name, "seed" ) == 0 ) + return Particle_getSeed( self ); + else if( strcmp( name, "nabla" ) == 0 ) + return Particle_getNabla( self ); + else if( strcmp( name, "sta" ) == 0 ) + return Particle_getSta( self ); + else if( strcmp( name, "end" ) == 0 ) + return Particle_getEnd( self ); + else if( strcmp( name, "lifetime" ) == 0 ) + return Particle_getLifetime( self ); + else if( strcmp( name, "normfac" ) == 0 ) + return Particle_getNormfac( self ); + else if( strcmp( name, "obfac" ) == 0 ) + return Particle_getObfac( self ); + else if( strcmp( name, "randfac" ) == 0 ) + return Particle_getRandfac( self ); + else if( strcmp( name, "texfac" ) == 0 ) + return Particle_getTexfac( self ); + else if( strcmp( name, "randlife" ) == 0 ) + return Particle_getRandlife( self ); + else if( strcmp( name, "vectsize" ) == 0 ) + return Particle_getVectsize( self ); + else if( strcmp( name, "totpart" ) == 0 ) + return Particle_getTotpart( self ); + else if( strcmp( name, "force" ) == 0 ) + return Particle_getForce( self ); + else if( strcmp( name, "mult" ) == 0 ) + return Particle_getMult( self ); + else if( strcmp( name, "life" ) == 0 ) + return Particle_getLife( self ); + else if( strcmp( name, "child" ) == 0 ) + return Particle_getChild( self ); + else if( strcmp( name, "mat" ) == 0 ) + return Particle_getMat( self ); + else if( strcmp( name, "defvec" ) == 0 ) + return Particle_getDefvec( self ); + + + return Py_FindMethod( BPy_Particle_methods, ( PyObject * ) self, + name ); +} + +/*****************************************************************************/ +/* Function: ParticleSetAttr */ +/* Description: This is a callback function for the BPy_Particle type. */ +/* It is the function that sets Particle Data attributes */ +/* (member vars) */ +/*****************************************************************************/ +int ParticleSetAttr( BPy_Particle * self, char *name, PyObject * value ) +{ + + PyObject *valtuple; + PyObject *error = NULL; + + valtuple = Py_BuildValue( "(N)", value ); + + if( !valtuple ) + return EXPP_ReturnIntError( PyExc_MemoryError, + "ParticleSetAttr: couldn't create PyTuple" ); + + if( strcmp( name, "seed" ) == 0 ) + error = Particle_setSeed( self, valtuple ); + else if( strcmp( name, "nabla" ) == 0 ) + error = Particle_setNabla( self, valtuple ); + else if( strcmp( name, "sta" ) == 0 ) + error = Particle_setSta( self, valtuple ); + else if( strcmp( name, "end" ) == 0 ) + error = Particle_setEnd( self, valtuple ); + else if( strcmp( name, "lifetime" ) == 0 ) + error = Particle_setLifetime( self, valtuple ); + else if( strcmp( name, "normfac" ) == 0 ) + error = Particle_setNormfac( self, valtuple ); + else if( strcmp( name, "obfac" ) == 0 ) + error = Particle_setObfac( self, valtuple ); + else if( strcmp( name, "randfac" ) == 0 ) + error = Particle_setRandfac( self, valtuple ); + else if( strcmp( name, "texfac" ) == 0 ) + error = Particle_setTexfac( self, valtuple ); + else if( strcmp( name, "randlife" ) == 0 ) + error = Particle_setRandlife( self, valtuple ); + else if( strcmp( name, "nabla" ) == 0 ) + error = Particle_setNabla( self, valtuple ); + else if( strcmp( name, "vectsize" ) == 0 ) + error = Particle_setVectsize( self, valtuple ); + else if( strcmp( name, "totpart" ) == 0 ) + error = Particle_setTotpart( self, valtuple ); + else if( strcmp( name, "seed" ) == 0 ) + error = Particle_setSeed( self, valtuple ); + else if( strcmp( name, "force" ) == 0 ) + error = Particle_setForce( self, valtuple ); + else if( strcmp( name, "mult" ) == 0 ) + error = Particle_setMult( self, valtuple ); + else if( strcmp( name, "life" ) == 0 ) + error = Particle_setLife( self, valtuple ); + else if( strcmp( name, "child" ) == 0 ) + error = Particle_setChild( self, valtuple ); + else if( strcmp( name, "mat" ) == 0 ) + error = Particle_setMat( self, valtuple ); + else if( strcmp( name, "defvec" ) == 0 ) + error = Particle_setDefvec( self, valtuple ); + + else { + Py_DECREF( valtuple ); + + if( ( strcmp( name, "Types" ) == 0 ) || + ( strcmp( name, "Modes" ) == 0 ) ) + return ( EXPP_ReturnIntError( PyExc_AttributeError, + "constant dictionary -- cannot be changed" ) ); + + else + return ( EXPP_ReturnIntError( PyExc_KeyError, + "attribute not found" ) ); + } + + Py_DECREF(valtuple); + if( error != Py_None ) + return -1; + + Py_DECREF( Py_None ); + return 0; +} + +/*****************************************************************************/ +/* Function: ParticlePrint */ +/* Description: This is a callback function for the BPy_Particle type. It */ +/* particles a meaninful string to 'print' particle objects. */ +/*****************************************************************************/ +/* +int ParticlePrint(BPy_Particle *self, FILE *fp, int flags) +{ + printf("Hi, I'm a particle!"); + return 0; +} +*/ +/*****************************************************************************/ +/* Function: ParticleRepr */ +/* Description: This is a callback function for the BPy_Particle type. It */ +/* particles a meaninful string to represent particle objects. */ +/*****************************************************************************/ +PyObject *ParticleRepr( void ) +{ + return PyString_FromString( "Particle" ); +} + +PyObject *ParticleCreatePyObject( struct Effect * particle ) +{ + BPy_Particle *blen_object; + + + blen_object = + ( BPy_Particle * ) PyObject_NEW( BPy_Particle, + &Particle_Type ); + + if( blen_object == NULL ) { + return ( NULL ); + } + blen_object->particle = particle; + return ( ( PyObject * ) blen_object ); + +} + +int ParticleCheckPyObject( PyObject * py_obj ) +{ + return ( py_obj->ob_type == &Particle_Type ); +} + + +struct Particle *ParticleFromPyObject( PyObject * py_obj ) +{ + BPy_Particle *blen_obj; + + blen_obj = ( BPy_Particle * ) py_obj; + return ( ( struct Particle * ) blen_obj->particle ); + +} diff --git a/source/blender/python/api2_2x/Particle.h b/source/blender/python/api2_2x/Particle.h new file mode 100644 index 00000000000..f9b75b20c63 --- /dev/null +++ b/source/blender/python/api2_2x/Particle.h @@ -0,0 +1,67 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Jacques Guignot + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef EXPP_PARTICLE_H +#define EXPP_PARTICLE_H + +#include +#include "DNA_effect_types.h" + +extern PyTypeObject Particle_Type; + +#define BPy_Particle_Check(v) ((v)->ob_type==&Particle_Type) + +/* Python BPy_Particle structure definition */ +typedef struct { + PyObject_HEAD /* required py macro */ + Effect * particle; +} BPy_Particle; + +#include "Effect.h" + +/*****************************************************************************/ +/* Python Particle_Type callback function prototypes: */ +/*****************************************************************************/ +#if 0 +void ParticleDeAlloc( BPy_Particle * msh ); +//int ParticlePrint (BPy_Particle *msh, FILE *fp, int flags); +int ParticleSetAttr( BPy_Particle * msh, char *name, PyObject * v ); +PyObject *ParticleGetAttr( BPy_Particle * msh, char *name ); +PyObject *ParticleRepr( void ); +PyObject *ParticleCreatePyObject( struct Effect *particle ); +int ParticleCheckPyObject( PyObject * py_obj ); +struct Particle *ParticleFromPyObject( PyObject * py_obj ); +#endif + + + +#endif /* EXPP_PARTICLE_H */ diff --git a/source/blender/python/api2_2x/Pose.c b/source/blender/python/api2_2x/Pose.c new file mode 100644 index 00000000000..01fbe591a74 --- /dev/null +++ b/source/blender/python/api2_2x/Pose.c @@ -0,0 +1,1395 @@ +/* + * $Id: + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#include "Pose.h" + + +#include "mydevice.h" +#include "BKE_armature.h" +#include "BKE_main.h" +#include "BKE_global.h" +#include "BKE_action.h" +#include "BKE_utildefines.h" +#include "BIF_editaction.h" +#include "BIF_space.h" +#include "BIF_poseobject.h" +#include "BKE_depsgraph.h" +#include "DNA_object_types.h" +#include "DNA_ipo_types.h" +#include "DNA_scene_types.h" +#include "DNA_space_types.h" //1 - this order +#include "BSE_editipo.h" //2 +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "Mathutils.h" +#include "Object.h" +#include "Constraint.h" +#include "NLA.h" +#include "gen_utils.h" +#include "gen_library.h" + +#include "DNA_armature_types.h" /*used for pose bone select*/ + +#include "MEM_guardedalloc.h" + +extern void chan_calc_mat(bPoseChannel *chan); + +//------------------------ERROR CODES--------------------------------- +//This is here just to make me happy and to have more consistant error strings :) +static const char sPoseError[] = "Pose - Error: "; +//static const char sPoseBadArgs[] = "Pose - Bad Arguments: "; +static const char sPoseBoneError[] = "PoseBone - Error: "; +//static const char sPoseBoneBadArgs[] = "PoseBone - Bad Arguments: "; +static const char sPoseBonesDictError[] = "PoseBone - Error: "; +//static const char sPoseBonesDictBadArgs[] = "PoseBone - Bad Arguments: "; + +//################## PoseBonesDict_Type (internal) ######################## +/*This is an internal psuedo-dictionary type that allows for manipulation +* of posechannels inside of a pose structure. It is a subobject of pose. +* i.e. Pose.bones['key']*/ +//################################################################ + +//------------------METHOD IMPLEMENTATIONS----------------------------- +//------------------------Pose.bones.items() +//Returns a list of key:value pairs like dict.items() +static PyObject* PoseBonesDict_items(BPy_PoseBonesDict *self) +{ + return PyDict_Items(self->bonesMap); +} +//------------------------Pose.bones.keys() +//Returns a list of keys like dict.keys() +static PyObject* PoseBonesDict_keys(BPy_PoseBonesDict *self) +{ + return PyDict_Keys(self->bonesMap); +} +//------------------------Armature.bones.values() +//Returns a list of values like dict.values() +static PyObject* PoseBonesDict_values(BPy_PoseBonesDict *self) +{ + return PyDict_Values(self->bonesMap); +} +//------------------ATTRIBUTE IMPLEMENTATION--------------------------- +//------------------TYPE_OBECT IMPLEMENTATION----------------------- +//------------------------tp_doc +//The __doc__ string for this object +static char BPy_PoseBonesDict_doc[] = "This is an internal subobject of pose\ +designed to act as a Py_PoseBone dictionary."; + +//------------------------tp_methods +//This contains a list of all methods the object contains +static PyMethodDef BPy_PoseBonesDict_methods[] = { + {"items", (PyCFunction) PoseBonesDict_items, METH_NOARGS, + "() - Returns the key:value pairs from the dictionary"}, + {"keys", (PyCFunction) PoseBonesDict_keys, METH_NOARGS, + "() - Returns the keys the dictionary"}, + {"values", (PyCFunction) PoseBonesDict_values, METH_NOARGS, + "() - Returns the values from the dictionary"}, + {NULL, NULL, 0, NULL} +}; +//-----------------(internal) +static int PoseBoneMapping_Init(PyObject *dictionary, ListBase *posechannels){ + bPoseChannel *pchan = NULL; + PyObject *py_posechannel = NULL; + + for (pchan = posechannels->first; pchan; pchan = pchan->next){ + py_posechannel = PyPoseBone_FromPosechannel(pchan); + if (!py_posechannel) + return -1; + + if(PyDict_SetItemString(dictionary, + pchan->name, py_posechannel) == -1){ + return -1; + } + Py_DECREF(py_posechannel); + } + return 0; +} + +//----------------- BonesDict_InitBones +static int PoseBonesDict_InitBones(BPy_PoseBonesDict *self) +{ + PyDict_Clear(self->bonesMap); + if (PoseBoneMapping_Init(self->bonesMap, self->bones) == -1) + return 0; + return 1; +} + +//------------------------tp_repr +//This is the string representation of the object +static PyObject *PoseBonesDict_repr(BPy_PoseBonesDict *self) +{ + char buffer[128], *str; + PyObject *key, *value; + int pos = 0; + + /* probably a bit of overkill but better then crashing */ + str = MEM_mallocN( 64 + ( PyDict_Size( self->bonesMap ) * 128), "PoseBonesDict_repr" ); + str[0] = '\0'; + + sprintf(buffer, "[Pose Bone Dict: {"); + strcat(str,buffer); + while (PyDict_Next(self->bonesMap, &pos, &key, &value)) { + sprintf(buffer, "%s : %s, ", PyString_AsString(key), + PyString_AsString(value->ob_type->tp_repr(value))); + strcat(str,buffer); + } + sprintf(buffer, "}]\n"); + strcat(str,buffer); + + MEM_freeN( str ); + + return PyString_FromString(str); +} + +//------------------------tp_dealloc +//This tells how to 'tear-down' our object when ref count hits 0 +static void PoseBonesDict_dealloc(BPy_PoseBonesDict * self) +{ + Py_DECREF(self->bonesMap); + PoseBonesDict_Type.tp_free(self); + return; +} +//------------------------mp_length +//This gets the size of the dictionary +static int PoseBonesDict_len(BPy_PoseBonesDict *self) +{ + return BLI_countlist(self->bones); +} +//-----------------------mp_subscript +//This defines getting a bone from the dictionary - x = Bones['key'] +static PyObject *PoseBonesDict_GetItem(BPy_PoseBonesDict *self, PyObject* key) +{ + PyObject *value = NULL; + + value = PyDict_GetItem(self->bonesMap, key); + if(value == NULL) + Py_RETURN_NONE; + + return EXPP_incr_ret(value); +} +//------------------TYPE_OBECT DEFINITION-------------------------- +//Mapping Protocol +static PyMappingMethods PoseBonesDict_MapMethods = { + (inquiry) PoseBonesDict_len, //mp_length + (binaryfunc)PoseBonesDict_GetItem, //mp_subscript + 0, //mp_ass_subscript +}; +//PoseBonesDict TypeObject +PyTypeObject PoseBonesDict_Type = { + PyObject_HEAD_INIT(NULL) //tp_head + 0, //tp_internal + "PoseBonesDict", //tp_name + sizeof(BPy_PoseBonesDict), //tp_basicsize + 0, //tp_itemsize + (destructor)PoseBonesDict_dealloc, //tp_dealloc + 0, //tp_print + 0, //tp_getattr + 0, //tp_setattr + 0, //tp_compare + (reprfunc) PoseBonesDict_repr, //tp_repr + 0, //tp_as_number + 0, //tp_as_sequence + &PoseBonesDict_MapMethods, //tp_as_mapping + 0, //tp_hash + 0, //tp_call + 0, //tp_str + 0, //tp_getattro + 0, //tp_setattro + 0, //tp_as_buffer + Py_TPFLAGS_DEFAULT, //tp_flags + BPy_PoseBonesDict_doc, //tp_doc + 0, //tp_traverse + 0, //tp_clear + 0, //tp_richcompare + 0, //tp_weaklistoffset + 0, //tp_iter + 0, //tp_iternext + BPy_PoseBonesDict_methods, //tp_methods + 0, //tp_members + 0, //tp_getset + 0, //tp_base + 0, //tp_dict + 0, //tp_descr_get + 0, //tp_descr_set + 0, //tp_dictoffset + 0, //tp_init + 0, //tp_alloc + 0, //tp_new + 0, //tp_free + 0, //tp_is_gc + 0, //tp_bases + 0, //tp_mro + 0, //tp_cache + 0, //tp_subclasses + 0, //tp_weaklist + 0 //tp_del +}; +//-----------------------PyPoseBonesDict_FromPyPose +static PyObject *PyPoseBonesDict_FromPyPose(BPy_Pose *py_pose) +{ + BPy_PoseBonesDict *py_posebonesdict = NULL; + + //create py object + py_posebonesdict = (BPy_PoseBonesDict *)PoseBonesDict_Type.tp_alloc(&PoseBonesDict_Type, 0); + if (!py_posebonesdict) + goto RuntimeError; + + //create internal dictionaries + py_posebonesdict->bonesMap = PyDict_New(); + if (!py_posebonesdict->bonesMap) + goto RuntimeError; + + //set listbase pointer + py_posebonesdict->bones = &py_pose->pose->chanbase; + + //now that everything is setup - init the mappings + if (!PoseBonesDict_InitBones(py_posebonesdict)) + goto RuntimeError; + + return (PyObject*)py_posebonesdict; + +RuntimeError: + return EXPP_objError(PyExc_RuntimeError, "%s%s", + sPoseBonesDictError, "Failed to create class"); +} + +//################## Pose_Type ########################## +/*This type is a wrapper for a pose*/ +//#################################################### +//------------------METHOD IMPLEMENTATIONS------------------------------ +static PyObject *Pose_update(BPy_Pose *self) +{ + Object *daddy = NULL; + + self->pose->flag |= POSE_RECALC; + + for (daddy = G.main->object.first; daddy; daddy = daddy->id.next){ + if (daddy->pose == self->pose){ + break; + } + } + + if(daddy) + where_is_pose(daddy); + + Py_RETURN_NONE; +} +//------------------------tp_methods +//This contains a list of all methods the object contains +static PyMethodDef BPy_Pose_methods[] = { + {"update", (PyCFunction) Pose_update, METH_NOARGS, + "() - Rebuilds the pose with new values"}, + {NULL, NULL, 0, NULL} +}; +//------------------ATTRIBUTE IMPLEMENTATIONS--------------------------- +//------------------------Pose.bones (getter) +//Gets the bones attribute +static PyObject *Pose_getBoneDict(BPy_Pose *self, void *closure) +{ + return EXPP_incr_ret((PyObject*)self->Bones); +} +//------------------------Pose.bones (setter) +//Sets the bones attribute +static int Pose_setBoneDict(BPy_Pose *self, PyObject *value, void *closure) +{ + goto AttributeError; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s", + sPoseError, "You are not allowed to change the .bones attribute"); +} +//------------------TYPE_OBECT IMPLEMENTATION--------------------------- +//------------------------tp_getset +//This contains methods for attributes that require checking +static PyGetSetDef BPy_Pose_getset[] = { + {"bones", (getter)Pose_getBoneDict, (setter)Pose_setBoneDict, + "The pose's Bone dictionary", NULL}, + {NULL, NULL, NULL, NULL, NULL} +}; +//------------------------tp_dealloc +//This tells how to 'tear-down' our object when ref count hits 0 +static void Pose_dealloc(BPy_Pose *self) +{ + Py_DECREF(self->Bones); + Pose_Type.tp_free(self); + return; +} +//------------------------tp_cmp +//This compares 2 pose types +static int Pose_compare(BPy_Pose *a, BPy_Pose *b ) +{ + return ( a->pose== b->pose ) ? 0 : -1; +} +//------------------------tp_repr +//This is the string representation of the object +static PyObject *Pose_repr(BPy_Pose *self) +{ + return PyString_FromFormat( "[Pose \"%s\"]", self->name); +} +//------------------------tp_doc +//The __doc__ string for this object +static char BPy_Pose_doc[] = "This object wraps a Blender Pose object."; + +//------------------TYPE_OBECT DEFINITION-------------------------- +PyTypeObject Pose_Type = { + PyObject_HEAD_INIT(NULL) //tp_head + 0, //tp_internal + "Pose", //tp_name + sizeof(BPy_Pose), //tp_basicsize + 0, //tp_itemsize + (destructor)Pose_dealloc, //tp_dealloc + 0, //tp_print + 0, //tp_getattr + 0, //tp_setattr + (cmpfunc)Pose_compare, //tp_compare + (reprfunc)Pose_repr, //tp_repr + 0, //tp_as_number + 0, //tp_as_sequence + 0, //tp_as_mapping + 0, //tp_hash + 0, //tp_call + 0, //tp_str + 0, //tp_getattro + 0, //tp_setattro + 0, //tp_as_buffer + Py_TPFLAGS_DEFAULT, //tp_flags + BPy_Pose_doc, //tp_doc + 0, //tp_traverse + 0, //tp_clear + 0, //tp_richcompare + 0, //tp_weaklistoffset + 0, //tp_iter + 0, //tp_iternext + BPy_Pose_methods, //tp_methods + 0, //tp_members + BPy_Pose_getset, //tp_getset + 0, //tp_base + 0, //tp_dict + 0, //tp_descr_get + 0, //tp_descr_set + 0, //tp_dictoffset + 0, //tp_init + 0, //tp_alloc + 0, //tp_new + 0, //tp_free + 0, //tp_is_gc + 0, //tp_bases + 0, //tp_mro + 0, //tp_cache + 0, //tp_subclasses + 0, //tp_weaklist + 0 //tp_del +}; +//################## PoseBone_Type ##################### +/*This type is a wrapper for a posechannel*/ +//#################################################### +//------------------METHOD IMPLEMENTATIONS------------------------------ +//------------------------------PoseBone.insertKey() +static PyObject *PoseBone_insertKey(BPy_PoseBone *self, PyObject *args) +{ + PyObject *parent_object = NULL; + PyObject *constants = NULL, *item = NULL; + int frame = 1, oldframe, length, x, numeric_value = 0, oldflag, no_ipo_update = 0; + bPoseChannel *pchan = NULL; + + + if (!PyArg_ParseTuple(args, "O!i|Oi", &Object_Type, &parent_object, &frame, &constants, &no_ipo_update )) + goto AttributeError; + + /* incase we ever have a value other then 1 for fast */ + if (no_ipo_update) + no_ipo_update = 1; + + //verify that this pchannel is part of the object->pose + for (pchan = ((BPy_Object*)parent_object)->object->pose->chanbase.first; + pchan; pchan = pchan->next){ + if (pchan == self->posechannel) + break; + } + if (!pchan) + goto AttributeError2; + + //verify that there is an action bound to this object + if (!((BPy_Object*)parent_object)->object->action){ + goto AttributeError5; + } + + oldflag = self->posechannel->flag; + self->posechannel->flag = 0; + //set the flags for this posechannel + if (constants){ + if(PySequence_Check(constants)){ + length = PySequence_Length(constants); + for (x = 0; x < length; x++){ + item = PySequence_GetItem(constants, x); + if (item == EXPP_GetModuleConstant("Blender.Object.Pose", "ROT")){ + numeric_value |= POSE_ROT; + }else if (item == EXPP_GetModuleConstant("Blender.Object.Pose", "LOC")){ + numeric_value |= POSE_LOC; + }else if (item == EXPP_GetModuleConstant("Blender.Object.Pose", "SIZE")){ + numeric_value |= POSE_SIZE; + }else{ + Py_DECREF(item); + self->posechannel->flag = (short)oldflag; + goto AttributeError4; + } + Py_DECREF(item); + } + self->posechannel->flag = (short)numeric_value; + }else if (BPy_Constant_Check(constants)){ + if (constants == EXPP_GetModuleConstant("Blender.Object.Pose", "ROT")){ + numeric_value |= POSE_ROT; + }else if (constants == EXPP_GetModuleConstant("Blender.Object.Pose", "LOC")){ + numeric_value |= POSE_LOC; + }else if (constants == EXPP_GetModuleConstant("Blender.Object.Pose", "SIZE")){ + numeric_value |= POSE_SIZE; + }else{ + self->posechannel->flag = (short)oldflag; + goto AttributeError4; + } + self->posechannel->flag = (short)numeric_value; + }else{ + goto AttributeError3; + } + }else{ //nothing passed so set them all + self->posechannel->flag |= POSE_ROT; + self->posechannel->flag |= POSE_LOC; + self->posechannel->flag |= POSE_SIZE; + } + + //set the frame we want insertion on + oldframe = G.scene->r.cfra; + G.scene->r.cfra = frame; + + //add the action channel if it's not there + verify_action_channel(((BPy_Object*)parent_object)->object->action, + self->posechannel->name); + + //insert the pose keys + if (self->posechannel->flag & POSE_ROT){ + insertkey(&((BPy_Object*)parent_object)->object->id, + ID_PO, self->posechannel->name, NULL, AC_QUAT_X, no_ipo_update); + insertkey(&((BPy_Object*)parent_object)->object->id, + ID_PO, self->posechannel->name, NULL, AC_QUAT_Y, no_ipo_update); + insertkey(&((BPy_Object*)parent_object)->object->id, + ID_PO, self->posechannel->name, NULL, AC_QUAT_Z, no_ipo_update); + insertkey(&((BPy_Object*)parent_object)->object->id, + ID_PO, self->posechannel->name, NULL, AC_QUAT_W, no_ipo_update); + } + if (self->posechannel->flag & POSE_LOC){ + insertkey(&((BPy_Object*)parent_object)->object->id, + ID_PO, self->posechannel->name, NULL, AC_LOC_X, no_ipo_update); + insertkey(&((BPy_Object*)parent_object)->object->id, + ID_PO, self->posechannel->name, NULL, AC_LOC_Y, no_ipo_update); + insertkey(&((BPy_Object*)parent_object)->object->id, + ID_PO, self->posechannel->name, NULL, AC_LOC_Z, no_ipo_update); + } + if (self->posechannel->flag & POSE_SIZE){ + insertkey(&((BPy_Object*)parent_object)->object->id, + ID_PO, self->posechannel->name, NULL, AC_SIZE_X, no_ipo_update); + insertkey(&((BPy_Object*)parent_object)->object->id, + ID_PO, self->posechannel->name, NULL, AC_SIZE_Y, no_ipo_update); + insertkey(&((BPy_Object*)parent_object)->object->id, + ID_PO, self->posechannel->name, NULL, AC_SIZE_Z, no_ipo_update); + } + + //flip the frame back + G.scene->r.cfra = oldframe; + + //update the IPOs + if (no_ipo_update==0) + remake_action_ipos (((BPy_Object*)parent_object)->object->action); + + Py_RETURN_NONE; + +AttributeError: + return EXPP_objError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".insertKey: ", "expects an Object, int, (optional) constants"); +AttributeError2: + return EXPP_objError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".insertKey: ", "wrong object detected. \ + Use the object this pose came from"); +AttributeError3: + return EXPP_objError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".insertKey: ", "Expects a constant or list of constants"); +AttributeError4: + return EXPP_objError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".insertKey: ", "Please use a constant defined in the Pose module"); +AttributeError5: + return EXPP_objError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".insertKey: ", "You must set up and link an Action to this object first"); +} +//------------------------tp_methods +//This contains a list of all methods the object contains +static PyMethodDef BPy_PoseBone_methods[] = { + {"insertKey", (PyCFunction) PoseBone_insertKey, METH_VARARGS, + "() - insert a key for this pose into an action"}, + {NULL, NULL, 0, NULL} +}; +//------------------ATTRIBUTE IMPLEMENTATIONS--------------------------- +//------------------------PoseBone.name (getter) +//Gets the name attribute +static PyObject *PoseBone_getName(BPy_PoseBone *self, void *closure) +{ + return PyString_FromString(self->posechannel->name); +} +//------------------------PoseBone.name (setter) +//Sets the name attribute +static int PoseBone_setName(BPy_PoseBone *self, PyObject *value, void *closure) +{ + char *name = ""; + + if (!PyArg_Parse(value, "s", &name)) + goto AttributeError; + + BLI_strncpy(self->posechannel->name, name, 32); + return 0; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".name: ", "expects a string"); +} +//------------------------PoseBone.loc (getter) +//Gets the loc attribute +static PyObject *PoseBone_getLoc(BPy_PoseBone *self, void *closure) +{ + return newVectorObject(self->posechannel->loc, 3, Py_WRAP); +} +//------------------------PoseBone.loc (setter) +//Sets the loc attribute +static int PoseBone_setLoc(BPy_PoseBone *self, PyObject *value, void *closure) +{ + VectorObject *vec = NULL; + int x; + + if (!PyArg_Parse(value, "O!", &vector_Type, &vec)) + goto AttributeError; + if (vec->size != 3) + goto AttributeError; + + for (x = 0; x < 3; x++){ + self->posechannel->loc[x] = vec->vec[x]; + } + return 0; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".loc: ", "expects a 3d vector object"); +} +//------------------------PoseBone.size (getter) +//Gets the size attribute +static PyObject *PoseBone_getSize(BPy_PoseBone *self, void *closure) +{ + return newVectorObject(self->posechannel->size, 3, Py_WRAP); +} +//------------------------PoseBone.size (setter) +//Sets the size attribute +static int PoseBone_setSize(BPy_PoseBone *self, PyObject *value, void *closure) +{ + VectorObject *vec = NULL; + int x; + + if (!PyArg_Parse(value, "O!", &vector_Type, &vec)) + goto AttributeError; + if (vec->size != 3) + goto AttributeError; + + for (x = 0; x < 3; x++){ + self->posechannel->size[x] = vec->vec[x]; + } + return 0; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".size: ", "expects a 3d vector object"); +} +//------------------------PoseBone.quat (getter) +//Gets the quat attribute +static PyObject *PoseBone_getQuat(BPy_PoseBone *self, void *closure) +{ + return newQuaternionObject(self->posechannel->quat, Py_WRAP); +} +//------------------------PoseBone.quat (setter) +//Sets the quat attribute +static int PoseBone_setQuat(BPy_PoseBone *self, PyObject *value, void *closure) +{ + QuaternionObject *quat = NULL; + int x; + + if (!PyArg_Parse(value, "O!", &quaternion_Type, &quat)) + goto AttributeError; + + for (x = 0; x < 4; x++){ + self->posechannel->quat[x] = quat->quat[x]; + } + return 0; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".quat: ", "expects a quaternion object"); +} +//------------------------PoseBone.localMatrix (getter) +//Gets the chan_mat +static PyObject *PoseBone_getLocalMatrix(BPy_PoseBone *self, void *closure) +{ + return newMatrixObject((float*)self->posechannel->chan_mat, 4, 4, Py_WRAP); +} +//------------------------PoseBone.localMatrix (setter) +//Sets the chan_mat +static int PoseBone_setLocalMatrix(BPy_PoseBone *self, PyObject *value, void *closure) +{ + MatrixObject *matrix = NULL; + float size[3], quat[4], loc[3]; + float mat3[3][3], mat4[4][4]; + int matsize = 0; + + if (!PyArg_Parse(value, "O!", &matrix_Type, &matrix)) + goto AttributeError; + + if (matrix->rowSize == 3 && matrix->colSize == 3){ + matsize = 3; + Mat3CpyMat3(mat3, (float(*)[3])*matrix->matrix); + }else if (matrix->rowSize == 4 && matrix->colSize == 4){ + matsize = 4; + Mat4CpyMat4(mat4, (float(*)[4])*matrix->matrix); + } + + if (matsize != 3 && matsize != 4){ + goto AttributeError; + } + + //get size and rotation + if (matsize == 3){ + Mat3ToSize(mat3, size); + Mat3Ortho(mat3); + Mat3ToQuat(mat3, quat); + }else if (matsize == 4){ + Mat4ToSize(mat4, size); + Mat4Ortho(mat4); + Mat4ToQuat(mat4, quat); + } + + //get loc + if (matsize == 4) { + VECCOPY(loc, matrix->matrix[3]); + } + else { + loc[0]= loc[1]= loc[2]= 0.0f; + } + + //copy new attributes + VECCOPY(self->posechannel->size, size); + QUATCOPY(self->posechannel->quat, quat); + if (matsize == 4){ + VECCOPY(self->posechannel->loc, loc); + } + + //rebuild matrix + chan_calc_mat(self->posechannel); + return 0; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".localMatrix: ", "expects a 3x3 or 4x4 matrix object"); +} +//------------------------PoseBone.poseMatrix (getter) +//Gets the pose_mat +static PyObject *PoseBone_getPoseMatrix(BPy_PoseBone *self, void *closure) +{ + return newMatrixObject((float*)self->posechannel->pose_mat, 4, 4, Py_WRAP); +} +//------------------------PoseBone.poseMatrix (setter) +//Sets the pose_mat +static int PoseBone_setPoseMatrix(BPy_PoseBone *self, MatrixObject *value, void *closure) +{ + float delta_mat[4][4], quat[4]; /* rotation */ + float size[4]; /* size only */ + + if( !MatrixObject_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected matrix object as argument" ); + + if( value->colSize != 4 || value->rowSize != 4 ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "matrix must be a 4x4 transformation matrix\n" + "for example as returned by object.matrixWorld" ); + + /* get bone-space cursor matrix and extract location */ + armature_mat_pose_to_bone(self->posechannel, (float (*)[4]) *value->matrix, delta_mat); + + /* Visual Location */ + VECCOPY(self->posechannel->loc, delta_mat[3]); + + /* Visual Size */ + Mat4ToSize(delta_mat, size); + VECCOPY(self->posechannel->size, size); + + /* Visual Rotation */ + Mat4ToQuat(delta_mat, quat); + QUATCOPY(self->posechannel->quat, quat); + + return 0; +} +//------------------------PoseBone.constraints (getter) +//Gets the constraints sequence +static PyObject *PoseBone_getConstraints(BPy_PoseBone *self, void *closure) +{ + return PoseConstraintSeq_CreatePyObject( self->posechannel ); +} +//------------------------PoseBone.limitmin (getter) +//Gets the pose bone limitmin value +static PyObject *PoseBone_getLimitMin(BPy_PoseBone *self, void *closure) +{ + float mylimitmin[3]; + Object *obj = NULL; + + obj = Object_FromPoseChannel(self->posechannel); + if (obj==NULL){ + return EXPP_ReturnPyObjError(PyExc_AttributeError, "Bone data is not found"); + } + mylimitmin[0]=0.0f; + mylimitmin[1]=0.0f; + mylimitmin[2]=0.0f; + if(pose_channel_in_IK_chain(obj, self->posechannel)){ + if ((self->posechannel->ikflag & BONE_IK_NO_XDOF)==0) { + if ((self->posechannel->ikflag & BONE_IK_XLIMIT)) { + mylimitmin[0] = self->posechannel->limitmin[0]; + } + } + if ((self->posechannel->ikflag & BONE_IK_NO_YDOF)==0) { + if ((self->posechannel->ikflag & BONE_IK_YLIMIT)) { + mylimitmin[1] = self->posechannel->limitmin[1]; + } + } + if ((self->posechannel->ikflag & BONE_IK_NO_ZDOF)==0) { + if ((self->posechannel->ikflag & BONE_IK_ZLIMIT)) { + mylimitmin[2] = self->posechannel->limitmin[2]; + } + } + } + return newVectorObject(mylimitmin, 3, Py_NEW); +} +//------------------------PoseBone.limitmin (setter) +//Sets the pose bone limitmin value +static int PoseBone_setLimitMin(BPy_PoseBone *self, PyObject *value, void *closure) +{ + float newlimitmin[3]; + int x; + Object *obj = NULL; + if(!PySequence_Check(value)){ + return EXPP_ReturnIntError(PyExc_AttributeError, "Argument is not a sequence"); + } + if (PySequence_Size(value) !=3){ + return EXPP_ReturnIntError(PyExc_AttributeError, "Argument size must be 3"); + } + newlimitmin[0]=0.0f; + newlimitmin[1]=0.0f; + newlimitmin[2]=0.0f; + for (x = 0; x<3;x++){ + PyObject *item; + item = PySequence_GetItem(value, x); //new reference + if (PyFloat_Check(item)){ + newlimitmin[x] = (float)PyFloat_AsDouble(item); + }else if (PyInt_Check(item)){ + newlimitmin[x] = (float)PyInt_AsLong(item); + } + Py_DECREF(item); + } + obj = Object_FromPoseChannel(self->posechannel); + if (obj==NULL){ + return EXPP_ReturnIntError(PyExc_AttributeError, "Bone data is not found"); + } + if(!pose_channel_in_IK_chain(obj, self->posechannel)){ + return EXPP_ReturnIntError(PyExc_AttributeError, "Bone is not part of an IK chain"); + } + if ((self->posechannel->ikflag & BONE_IK_NO_XDOF)==0) { + if ((self->posechannel->ikflag & BONE_IK_XLIMIT)) { + self->posechannel->limitmin[0] = EXPP_ClampFloat(newlimitmin[0], -180.0f, 0.0f); + } + } + if ((self->posechannel->ikflag & BONE_IK_NO_YDOF)==0) { + if ((self->posechannel->ikflag & BONE_IK_YLIMIT)) { + self->posechannel->limitmin[1] = EXPP_ClampFloat(newlimitmin[1], -180.0f, 0.0f); + } + } + if ((self->posechannel->ikflag & BONE_IK_NO_ZDOF)==0) { + if ((self->posechannel->ikflag & BONE_IK_ZLIMIT)) { + self->posechannel->limitmin[2] = EXPP_ClampFloat(newlimitmin[2], -180.0f, 0.0f); + } + } + DAG_object_flush_update(G.scene, obj, OB_RECALC_DATA); + return 0; +} + +//------------------------PoseBone.limitmax (getter) +//Gets the pose bone limitmax value +static PyObject *PoseBone_getLimitMax(BPy_PoseBone *self, void *closure) +{ + float mylimitmax[3]; + Object *obj = NULL; + + obj = Object_FromPoseChannel(self->posechannel); + if (obj==NULL){ + return EXPP_ReturnPyObjError(PyExc_AttributeError, "Bone data is not found"); + } + mylimitmax[0]=0.0f; + mylimitmax[1]=0.0f; + mylimitmax[2]=0.0f; + if(pose_channel_in_IK_chain(obj, self->posechannel)){ + if ((self->posechannel->ikflag & BONE_IK_NO_XDOF)==0) { + if ((self->posechannel->ikflag & BONE_IK_XLIMIT)) { + mylimitmax[0] = self->posechannel->limitmax[0]; + } + } + if ((self->posechannel->ikflag & BONE_IK_NO_YDOF)==0) { + if ((self->posechannel->ikflag & BONE_IK_YLIMIT)) { + mylimitmax[1] = self->posechannel->limitmax[1]; + } + } + if ((self->posechannel->ikflag & BONE_IK_NO_ZDOF)==0) { + if ((self->posechannel->ikflag & BONE_IK_ZLIMIT)) { + mylimitmax[2] = self->posechannel->limitmax[2]; + } + } + } + return newVectorObject(mylimitmax, 3, Py_NEW); +} +//------------------------PoseBone.limitmax (setter) +//Sets the pose bone limitmax value +static int PoseBone_setLimitMax(BPy_PoseBone *self, PyObject *value, void *closure) +{ + float newlimitmax[3]; + int x; + Object *obj = NULL; + if(!PySequence_Check(value)){ + return EXPP_ReturnIntError(PyExc_AttributeError, "Argument is not a sequence"); + } + if (PySequence_Size(value) !=3){ + return EXPP_ReturnIntError(PyExc_AttributeError, "Argument size must be 3"); + } + newlimitmax[0]=0.0f; + newlimitmax[1]=0.0f; + newlimitmax[2]=0.0f; + for (x = 0; x<3;x++){ + PyObject *item; + item = PySequence_GetItem(value, x); //new reference + if (PyFloat_Check(item)){ + newlimitmax[x] = (float)PyFloat_AsDouble(item); + }else if (PyInt_Check(item)){ + newlimitmax[x] = (float)PyInt_AsLong(item); + } + Py_DECREF(item); + } + obj = Object_FromPoseChannel(self->posechannel); + if (obj==NULL){ + return EXPP_ReturnIntError(PyExc_AttributeError, "Bone data is not found"); + } + if(!pose_channel_in_IK_chain(obj, self->posechannel)){ + return EXPP_ReturnIntError(PyExc_AttributeError, "Bone is not part of an IK chain"); + } + if ((self->posechannel->ikflag & BONE_IK_NO_XDOF)==0) { + if ((self->posechannel->ikflag & BONE_IK_XLIMIT)) { + self->posechannel->limitmax[0] = EXPP_ClampFloat(newlimitmax[0], 0.0f, 180.0f); + } + } + if ((self->posechannel->ikflag & BONE_IK_NO_YDOF)==0) { + if ((self->posechannel->ikflag & BONE_IK_YLIMIT)) { + self->posechannel->limitmax[1] = EXPP_ClampFloat(newlimitmax[1], 0.0f, 180.0f); + } + } + if ((self->posechannel->ikflag & BONE_IK_NO_ZDOF)==0) { + if ((self->posechannel->ikflag & BONE_IK_ZLIMIT)) { + self->posechannel->limitmax[2] = EXPP_ClampFloat(newlimitmax[2], 0.0f, 180.0f); + } + } + DAG_object_flush_update(G.scene, obj, OB_RECALC_DATA); + return 0; +} +//------------------------PoseBone.head (getter) +//Gets the pose head position +static PyObject *PoseBone_getHead(BPy_PoseBone *self, void *closure) +{ + return newVectorObject(self->posechannel->pose_head, 3, Py_NEW); +} +//------------------------PoseBone.head (setter) +//Sets the pose head position +static int PoseBone_setHead(BPy_PoseBone *self, PyObject *value, void *closure) +{ + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".head: ", "not able to set this property"); +} +//------------------------PoseBone.tail (getter) +//Gets the pose tail position +static PyObject *PoseBone_getTail(BPy_PoseBone *self, void *closure) +{ + return newVectorObject(self->posechannel->pose_tail, 3, Py_NEW); +} +//------------------------PoseBone.tail (setter) +//Sets the pose tail position +static int PoseBone_setTail(BPy_PoseBone *self, PyObject *value, void *closure) +{ + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".tail: ", "not able to set this property"); +} +//------------------------PoseBone.sel (getter) +//Gets the pose bones selection +static PyObject *PoseBone_getSelect(BPy_PoseBone *self, void *closure) +{ + if (self->posechannel->bone->flag & BONE_SELECTED) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} +//------------------------PoseBone.sel (setter) +//Sets the pose bones selection +static int PoseBone_setSelect(BPy_PoseBone *self, PyObject *value, void *closure) +{ + int param = PyObject_IsTrue( value ); + if( param == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected True/False or 0/1" ); + + if ( param ) + self->posechannel->bone->flag |= BONE_SELECTED; + else + self->posechannel->bone->flag &= ~(BONE_SELECTED | BONE_ACTIVE); + return 0; +} + + +//------------------------PoseBone.parent (getter) +//Gets the bones parent if any +static PyObject *PoseBone_getParent(BPy_PoseBone *self, void *closure) +{ + if (self->posechannel->parent) + return PyPoseBone_FromPosechannel(self->posechannel->parent); + else + Py_RETURN_NONE; +} + +//------------------------PoseBone.displayObject (getter) +//Gets the pose bones object used for display +static PyObject *PoseBone_getDisplayObject(BPy_PoseBone *self, void *closure) +{ + if (self->posechannel->custom) + return Object_CreatePyObject(self->posechannel->custom); + else + Py_RETURN_NONE; +} + +//------------------------PoseBone.displayObject (setter) +//Sets the pose bones object used for display +static int PoseBone_setDisplayObject(BPy_PoseBone *self, PyObject *value, void *closure) +{ + return GenericLib_assignData(value, (void **) &self->posechannel->custom, 0, 0, ID_OB, 0); +} + +//------------------------PoseBone.hasIK (getter) +//Returns True/False if the bone has IK's +static PyObject *PoseBone_hasIK(BPy_PoseBone *self, void *closure) +{ + Object *obj = NULL; + + obj = Object_FromPoseChannel(self->posechannel); + if (obj==NULL) + Py_RETURN_FALSE; + + if( pose_channel_in_IK_chain(obj, self->posechannel) ) + Py_RETURN_TRUE; + + Py_RETURN_FALSE; +} + +//------------------------PoseBone.stretch (getter) +//Gets the pose bones IK Stretch value +static PyObject *PoseBone_getStretch(BPy_PoseBone *self, void *closure) +{ + return PyFloat_FromDouble( self->posechannel->ikstretch ); +} + +//------------------------PoseBone.stretch (setter) +//Sets the pose bones IK Stretch value +static int PoseBone_setStretch(BPy_PoseBone *self, PyObject *value, void *closure) +{ + float ikstretch; + + if( !PyNumber_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected float argument" ); + + ikstretch = (float)PyFloat_AsDouble(value); + if (ikstretch<0) ikstretch = 0.0; + if (ikstretch>1) ikstretch = 1.0; + self->posechannel->ikstretch = ikstretch; + return 0; +} + +//------------------------PoseBone.stiffX/Y/Z (getter) +//Gets the pose bones IK stiffness +static PyObject *PoseBone_getStiff(BPy_PoseBone *self, void *axis) +{ + return PyFloat_FromDouble( self->posechannel->stiffness[(int)axis] ); +} + +//------------------------PoseBone.stiffX/Y/Z (setter) +//Sets the pose bones IK stiffness +static int PoseBone_setStiff(BPy_PoseBone *self, PyObject *value, void *axis) +{ + float stiff; + + if( !PyNumber_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected float argument" ); + + stiff = (float)PyFloat_AsDouble(value); + if (stiff<0) stiff = 0; + if (stiff>0.990) stiff = 0.990f; + self->posechannel->stiffness[(int)axis] = stiff; + return 0; +} + +//------------------------PoseBone.* (getter) +//Gets the pose bones flag +/* +static PyObject *PoseBone_getFlag(BPy_PoseBone *self, void *flag) +{ + if (self->posechannel->flag & (int)flag) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; + +} +*/ + +//------------------------PoseBone.* (setter) +//Gets the pose bones flag +/* +static int PoseBone_setFlag(BPy_PoseBone *self, PyObject *value, void *flag) +{ + if ( PyObject_IsTrue(value) ) + self->posechannel->flag |= (int)flag; + else + self->posechannel->flag &= ~(int)flag; + return 0; +} +*/ + +//------------------------PoseBone.* (getter) +//Gets the pose bones ikflag +static PyObject *PoseBone_getIKFlag(BPy_PoseBone *self, void *flag) +{ + if (self->posechannel->ikflag & (int)flag) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; + +} + +//------------------------PoseBone.* (setter) +//Sets the pose bones ikflag +static int PoseBone_setIKFlag(BPy_PoseBone *self, PyObject *value, void *flag) +{ + int param = PyObject_IsTrue( value ); + if( param == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected True/False or 0/1" ); + + if ( param ) + self->posechannel->ikflag |= (int)flag; + else + self->posechannel->ikflag &= ~(int)flag; + return 0; +} + +//------------------------Bone.layerMask (get) +static PyObject *PoseBone_getLayerMask(BPy_PoseBone *self) +{ + /* do this extra stuff because the short's bits can be negative values */ + unsigned short laymask = 0; + laymask |= self->posechannel->bone->layer; + return PyInt_FromLong((int)laymask); +} +//------------------------Bone.layerMask (set) +static int PoseBone_setLayerMask(BPy_PoseBone *self, PyObject *value) +{ + int laymask; + if (!PyInt_Check(value)) { + return EXPP_ReturnIntError( PyExc_AttributeError, + "expected an integer (bitmask) as argument" ); + } + + laymask = PyInt_AsLong(value); + + if (laymask <= 0 || laymask > (1<<16) - 1) + return EXPP_ReturnIntError( PyExc_AttributeError, + "bitmask must have from 1 up to 16 bits set"); + + self->posechannel->bone->layer = 0; + self->posechannel->bone->layer |= laymask; + + return 0; +} + +//------------------TYPE_OBECT IMPLEMENTATION--------------------------- +//------------------------tp_getset +//This contains methods for attributes that require checking +static PyGetSetDef BPy_PoseBone_getset[] = { + {"name", (getter)PoseBone_getName, (setter)PoseBone_setName, + "The pose bone's name", NULL}, + {"loc", (getter)PoseBone_getLoc, (setter)PoseBone_setLoc, + "The pose bone's change in location as a vector", NULL}, + {"size", (getter)PoseBone_getSize, (setter)PoseBone_setSize, + "The pose bone's change in size as a vector", NULL}, + {"quat", (getter)PoseBone_getQuat, (setter)PoseBone_setQuat, + "The pose bone's change in rotation as a quat", NULL}, + {"localMatrix", (getter)PoseBone_getLocalMatrix, (setter)PoseBone_setLocalMatrix, + "The pose bone's change matrix built from the quat, loc, and size", NULL}, + {"poseMatrix", (getter)PoseBone_getPoseMatrix, (setter)PoseBone_setPoseMatrix, + "The pose bone's matrix", NULL}, + {"head", (getter)PoseBone_getHead, (setter)PoseBone_setHead, + "The pose bone's head positon", NULL}, + {"tail", (getter)PoseBone_getTail, (setter)PoseBone_setTail, + "The pose bone's tail positon", NULL}, + {"sel", (getter)PoseBone_getSelect, (setter)PoseBone_setSelect, + "The pose selection state", NULL}, + {"limitMin", (getter)PoseBone_getLimitMin, (setter)PoseBone_setLimitMin, + "The pose bone dof min", NULL}, + {"limitMax", (getter)PoseBone_getLimitMax, (setter)PoseBone_setLimitMax, + "The pose bone dof max", NULL}, + {"constraints", (getter)PoseBone_getConstraints, (setter)NULL, + "The list of contraints that pertain to this pose bone", NULL}, + {"parent", (getter)PoseBone_getParent, (setter)NULL, + "The bones parent (read only for posebones)", NULL}, + {"displayObject", (getter)PoseBone_getDisplayObject, (setter)PoseBone_setDisplayObject, + "The poseMode object to draw in place of this bone", NULL}, + + {"hasIK", (getter)PoseBone_hasIK, (setter)NULL, + "True if the pose bone has IK (readonly)", NULL }, + + {"stretch", (getter)PoseBone_getStretch, (setter)PoseBone_setStretch, + "Stretch the bone to the IK Target", NULL }, + + {"stiffX", (getter)PoseBone_getStiff, (setter)PoseBone_setStiff, + "bones stiffness on the X axis", (void *)0 }, + {"stiffY", (getter)PoseBone_getStiff, (setter)PoseBone_setStiff, + "bones stiffness on the Y axis", (void *)1 }, + {"stiffZ", (getter)PoseBone_getStiff, (setter)PoseBone_setStiff, + "bones stiffness on the Z axis", (void *)2 }, + + {"limitX", (getter)PoseBone_getIKFlag, (setter)PoseBone_setIKFlag, + "limit rotation over X axis when part of an IK", (void *)BONE_IK_XLIMIT }, + {"limitY", (getter)PoseBone_getIKFlag, (setter)PoseBone_setIKFlag, + "limit rotation over Y axis when part of an IK", (void *)BONE_IK_YLIMIT }, + {"limitZ", (getter)PoseBone_getIKFlag, (setter)PoseBone_setIKFlag, + "limit rotation over Z axis when part of an IK", (void *)BONE_IK_ZLIMIT }, + + {"lockXRot", (getter)PoseBone_getIKFlag, (setter)PoseBone_setIKFlag, + "disable X DoF when part of an IK", (void *)BONE_IK_NO_XDOF }, + {"lockYRot", (getter)PoseBone_getIKFlag, (setter)PoseBone_setIKFlag, + "disable Y DoF when part of an IK", (void *)BONE_IK_NO_YDOF }, + {"lockZRot", (getter)PoseBone_getIKFlag, (setter)PoseBone_setIKFlag, + "disable Z DoF when part of an IK", (void *)BONE_IK_NO_ZDOF }, + {"layerMask", (getter)PoseBone_getLayerMask, (setter)PoseBone_setLayerMask, + "Layer bitmask", NULL }, + {NULL, NULL, NULL, NULL, NULL} +}; +//------------------------tp_dealloc +//This tells how to 'tear-down' our object when ref count hits 0 +static void PoseBone_dealloc(BPy_PoseBone *self) +{ + PoseBone_Type.tp_free(self); + return; +} +//------------------------tp_repr +//This is the string representation of the object +static PyObject *PoseBone_repr(BPy_PoseBone *self) +{ + return PyString_FromFormat( "[PoseBone \"%s\"]", self->posechannel->name); +} +//------------------------tp_doc +//The __doc__ string for this object +static char BPy_PoseBone_doc[] = "This object wraps a Blender PoseBone object."; + +//------------------TYPE_OBECT DEFINITION-------------------------- +PyTypeObject PoseBone_Type = { + PyObject_HEAD_INIT(NULL) //tp_head + 0, //tp_internal + "PoseBone", //tp_name + sizeof(BPy_PoseBone), //tp_basicsize + 0, //tp_itemsize + (destructor)PoseBone_dealloc, //tp_dealloc + 0, //tp_print + 0, //tp_getattr + 0, //tp_setattr + 0, //tp_compare + (reprfunc)PoseBone_repr, //tp_repr + 0, //tp_as_number + 0, //tp_as_sequence + 0, //tp_as_mapping + 0, //tp_hash + 0, //tp_call + 0, //tp_str + 0, //tp_getattro + 0, //tp_setattro + 0, //tp_as_buffer + Py_TPFLAGS_DEFAULT, //tp_flags + BPy_PoseBone_doc, //tp_doc + 0, //tp_traverse + 0, //tp_clear + 0, //tp_richcompare + 0, //tp_weaklistoffset + 0, //tp_iter + 0, //tp_iternext + BPy_PoseBone_methods, //tp_methods + 0, //tp_members + BPy_PoseBone_getset, //tp_getset + 0, //tp_base + 0, //tp_dict + 0, //tp_descr_get + 0, //tp_descr_set + 0, //tp_dictoffset + 0, //tp_init + 0, //tp_alloc + 0, //tp_new + 0, //tp_free + 0, //tp_is_gc + 0, //tp_bases + 0, //tp_mro + 0, //tp_cache + 0, //tp_subclasses + 0, //tp_weaklist + 0 //tp_del +}; +//-------------------MODULE METHODS IMPLEMENTATION------------------------ +//-------------------MODULE METHODS DEFINITION----------------------------- +struct PyMethodDef M_Pose_methods[] = { + {NULL, NULL, 0, NULL} +}; +//-------------------MODULE INITIALIZATION-------------------------------- +PyObject *Pose_Init(void) +{ + PyObject *module; + + //Initializes TypeObject.ob_type + if (PyType_Ready(&Pose_Type) < 0 || PyType_Ready(&PoseBone_Type) < 0 || + PyType_Ready(&PoseBonesDict_Type) < 0) { + Py_RETURN_NONE; + } + + //Register the module + module = Py_InitModule3("Blender.Object.Pose", M_Pose_methods, + "The Blender Pose module"); + + //Add TYPEOBJECTS to the module + PyModule_AddObject(module, "Pose", + EXPP_incr_ret((PyObject *)&Pose_Type)); //*steals* + PyModule_AddObject(module, "PoseBone", + EXPP_incr_ret((PyObject *)&PoseBone_Type)); //*steals* + + //Add CONSTANTS to the module + PyModule_AddObject(module, "ROT", + PyConstant_NewInt("ROT", POSE_ROT)); + PyModule_AddObject(module, "LOC", + PyConstant_NewInt("LOC", POSE_LOC)); + PyModule_AddObject(module, "SIZE", + PyConstant_NewInt("SIZE", POSE_SIZE)); + + return module; +} +//------------------VISIBLE PROTOTYPE IMPLEMENTATION----------------------- +//------------------------------PyPose_FromPose (internal) +//Returns a PyPose from a bPose - return PyNone if bPose is NULL +PyObject *PyPose_FromPose(bPose *pose, char *name) +{ + BPy_Pose *py_pose = NULL; + + if (pose){ + py_pose = (BPy_Pose*)Pose_Type.tp_alloc(&Pose_Type, 0); + if (!py_pose) + goto RuntimeError; + + py_pose->pose = pose; + BLI_strncpy(py_pose->name, name, 24); + + //create armature.bones + py_pose->Bones = (BPy_PoseBonesDict*)PyPoseBonesDict_FromPyPose(py_pose); + if (!py_pose->Bones) + goto RuntimeError; + + return (PyObject*)py_pose; + }else{ + Py_RETURN_NONE; + } + +RuntimeError: + return EXPP_objError(PyExc_RuntimeError, "%s%s%s", + sPoseError, "PyPose_FromPose: ", "Internal Error Ocurred"); +} +//------------------------------PyPoseBone_FromPosechannel (internal) +//Returns a PyPoseBone from a bPoseChannel - return PyNone if bPoseChannel is NULL +PyObject *PyPoseBone_FromPosechannel(bPoseChannel *pchan) +{ + BPy_PoseBone *py_posechannel = NULL; + + if (pchan){ + py_posechannel = (BPy_PoseBone*)PoseBone_Type.tp_alloc(&PoseBone_Type, 0); + if (!py_posechannel) + goto RuntimeError; + py_posechannel->posechannel = pchan; + return (PyObject*)py_posechannel; + }else{ + Py_RETURN_NONE; + } + +RuntimeError: + return EXPP_objError(PyExc_RuntimeError, "%s%s%s", + sPoseBoneError, "PyPoseBone_FromPosechannel: ", "Internal Error Ocurred"); +} +//------------------------------Object_FromPoseChannel (internal) +//An ugly method for determining where the pchan chame from +Object *Object_FromPoseChannel(bPoseChannel *curr_pchan) +{ + int success = 0; + Object *obj = NULL; + bPoseChannel *pchan = NULL; + for(obj = G.main->object.first; obj; obj = obj->id.next){ + if (obj->pose){ + for (pchan = obj->pose->chanbase.first; pchan; pchan = pchan->next){ + if (curr_pchan == pchan){ + success = 1; + break; + } + } + if (success) + break; + } + } + return obj; +} diff --git a/source/blender/python/api2_2x/Pose.h b/source/blender/python/api2_2x/Pose.h new file mode 100644 index 00000000000..17a9f871ee3 --- /dev/null +++ b/source/blender/python/api2_2x/Pose.h @@ -0,0 +1,71 @@ +/* + * $Id: + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_POSE_H +#define EXPP_POSE_H + +#include +#include "DNA_action_types.h" +#include "DNA_object_types.h" + +//-------------------TYPE CHECKS--------------------------------- +#define BPy_Pose_Check(v) ((v)->ob_type == &Pose_Type) +#define BPy_PoseBone_Check(v) ((v)->ob_type == &PoseBone_Type) +#define BPy_PoseBonesDict_Check(v) ((v)->ob_type == &PoseBonesDict_Type) +//-------------------TYPEOBJECT---------------------------------- +extern PyTypeObject Pose_Type; +extern PyTypeObject PoseBone_Type; +extern PyTypeObject PoseBonesDict_Type; +//-------------------STRUCT DEFINITION---------------------------- +typedef struct { + PyObject_HEAD + PyObject *bonesMap; + ListBase *bones; +} BPy_PoseBonesDict; + +typedef struct { + PyObject_HEAD + bPose *pose; + char name[24]; //because poses have not names :( + BPy_PoseBonesDict *Bones; +} BPy_Pose; + +typedef struct { + PyObject_HEAD + bPoseChannel *posechannel; + +} BPy_PoseBone; + +//-------------------VISIBLE PROTOTYPES------------------------- +PyObject *Pose_Init(void); +PyObject *PyPose_FromPose(bPose *pose, char *name); +PyObject *PyPoseBone_FromPosechannel(bPoseChannel *pchan); +Object *Object_FromPoseChannel(bPoseChannel *curr_pchan); +#endif diff --git a/source/blender/python/api2_2x/Registry.c b/source/blender/python/api2_2x/Registry.c new file mode 100644 index 00000000000..8fa77b20741 --- /dev/null +++ b/source/blender/python/api2_2x/Registry.c @@ -0,0 +1,245 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#include "Registry.h" /*This must come first */ + +#include "BKE_global.h" +#include "gen_utils.h" + + +/* the Registry dictionary */ +PyObject *bpy_registryDict = NULL; + +/*****************************************************************************/ +/* Python API function prototypes for the Registry module. */ +/*****************************************************************************/ +static PyObject *M_Registry_Keys( PyObject * self ); +static PyObject *M_Registry_GetKey( PyObject * self, PyObject * args ); +static PyObject *M_Registry_SetKey( PyObject * self, PyObject * args ); +static PyObject *M_Registry_RemoveKey( PyObject * self, PyObject * args ); + +/*****************************************************************************/ +/* The following string definitions are used for documentation strings. */ +/* In Python these will be written to the console when doing a */ +/* Blender.Registry.__doc__ */ +/*****************************************************************************/ +char M_Registry_doc[] = + "The Blender Registry module (persistent data cache)\n\n\ + Use this module to store configuration data that a script can reload\n\ + when it is executed again.\n"; + +char M_Registry_Keys_doc[] = + "() - Get all keys in the Registry dictionary.\n\n\ + Each key references another dict with saved data from a specific script.\n"; + +char M_Registry_GetKey_doc[] = + "(name, disk = False) - Get an entry (a dict) from the Registry dictionary\n\ + (name) - a string that references a specific script;\n\ + (disk = False) - search on the user (if available) or default scripts config\n\ +data dir.\n"; + +char M_Registry_SetKey_doc[] = + "(key, dict, disk = False) - Store an entry in the Registry dictionary.\n\ + If an entry with the same 'key' already exists, it is substituted.\n\ + (key) - the string to use as a key for the dict being saved.\n\ + (dict) - a dictionary with the data to be stored.\n\ + (disk = False) - also write data as a config file inside the user (if\n\ +available) or default scripts config data dir.\n"; + +char M_Registry_RemoveKey_doc[] = + "(key, disk = False) - Remove the dict with key 'key' from the Registry.\n\ + (key) - the name of the key to delete;\n\ + (disk = False) - if True the respective config file is also deleted.\n"; + +/*****************************************************************************/ +/* Python method structure definition for Blender.Registry module: */ +/*****************************************************************************/ +struct PyMethodDef M_Registry_methods[] = { + {"Keys", ( PyCFunction ) M_Registry_Keys, METH_VARARGS, + M_Registry_Keys_doc}, + {"GetKey", M_Registry_GetKey, METH_VARARGS, M_Registry_GetKey_doc}, + {"SetKey", M_Registry_SetKey, METH_VARARGS, M_Registry_SetKey_doc}, + {"RemoveKey", M_Registry_RemoveKey, METH_VARARGS, + M_Registry_RemoveKey_doc}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Function: M_Registry_Keys */ +/* Python equivalent: Blender.Registry.Keys */ +/*****************************************************************************/ +PyObject *M_Registry_Keys( PyObject * self ) +{ + PyObject *pydict = NULL; + + if( !bpy_registryDict ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "No Registry dictionary found!" ); + + pydict = PyDict_Keys( bpy_registryDict ); + + if( !pydict ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Registry_Keys: couldn't get keys" ); + + return pydict; +} + +/*****************************************************************************/ +/* Function: M_Registry_GetKey */ +/* Python equivalent: Blender.Registry.GetKey */ +/*****************************************************************************/ +static PyObject *M_Registry_GetKey( PyObject * self, PyObject * args ) +{ + PyObject *pyentry = NULL; + PyObject *pydict = NULL; + int disk = 0; + + if( !bpy_registryDict ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "No Registry dictionary found!" ); + + if( !PyArg_ParseTuple( args, "O!|i", &PyString_Type, &pyentry, &disk ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected a string and optionally a bool" ); + + pydict = PyDict_GetItem( bpy_registryDict, pyentry ); /* borrowed ... */ + + if (!pydict) { + if (disk > 0) { + /* try to get data from disk */ + char buf[256]; + PyOS_snprintf(buf, sizeof(buf), + "import Blender, BPyRegistry; BPyRegistry.LoadConfigData('%s')", + PyString_AsString(pyentry)); + if (!PyRun_SimpleString(buf)) + pydict = PyDict_GetItem(bpy_registryDict, pyentry); + else PyErr_Clear(); + } + + if (!pydict) /* no need to return a KeyError, since without doubt */ + pydict = Py_None; /* Py_None means no key (all valid keys are dicts) */ + } + + return EXPP_incr_ret (pydict); /* ... so we incref it */ +} + +/*****************************************************************************/ +/* Function: M_Registry_SetKey */ +/* Python equivalent: Blender.Registry.SetKey */ +/*****************************************************************************/ +static PyObject *M_Registry_SetKey( PyObject * self, PyObject * args ) +{ + PyObject *pystr = NULL; + PyObject *pydict = NULL; + int disk = 0; + + if( !bpy_registryDict ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "No Registry dictionary found!" ); + + if( !PyArg_ParseTuple( args, "O!O!|i", + &PyString_Type, &pystr, &PyDict_Type, + &pydict, &disk ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected a string and a dictionary" ); + + if( PyDict_SetItem( bpy_registryDict, pystr, pydict ) ) /* 0 on success */ + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Registry_SetKey: couldn't update the Registry dict" ); + + if (disk) { + /* try to save data to disk */ + char buf[256]; + PyOS_snprintf(buf, sizeof(buf), + "import Blender, BPyRegistry; BPyRegistry.SaveConfigData('%s')", + PyString_AsString(pystr)); + if (PyRun_SimpleString(buf) != 0) { + PyErr_Clear(); + if (G.f & G_DEBUG) + fprintf(stderr, "\nCan't save script configuration data!\n"); + } + } + + Py_INCREF( Py_None ); + return Py_None; +} + +/*****************************************************************************/ +/* Function: M_Registry_RemoveKey */ +/* Python equivalent: Blender.Registry.RemoveKey */ +/*****************************************************************************/ +static PyObject *M_Registry_RemoveKey( PyObject * self, PyObject * args ) +{ + PyObject *pystr = NULL; + int disk = 0; + + if( !bpy_registryDict ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "No Registry dictionary found!" ); + + if( !PyArg_ParseTuple( args, "O!|i", &PyString_Type, &pystr, &disk ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected a string and optionally a bool" ); + + if( PyDict_DelItem( bpy_registryDict, pystr ) ) /* returns 0 on success */ + return EXPP_ReturnPyObjError( PyExc_KeyError, + "no such key in the Registry" ); + else if (disk) { + /* try to delete from disk too */ + char buf[256]; + PyOS_snprintf(buf, sizeof(buf), + "import Blender, BPyRegistry; BPyRegistry.RemoveConfigData('%s')", + PyString_AsString(pystr)); + if (PyRun_SimpleString(buf) != 0) { + PyErr_Clear(); + if (G.f & G_DEBUG) + fprintf(stderr, "\nCan't remove script configuration data file!\n"); + } + } + + Py_INCREF( Py_None ); + return Py_None; +} + +/*****************************************************************************/ +/* Function: Registry_Init */ +/*****************************************************************************/ +PyObject *Registry_Init( void ) +{ + PyObject *submodule; + + submodule = Py_InitModule3( "Blender.Registry", M_Registry_methods, + M_Registry_doc ); + + return submodule; +} diff --git a/source/blender/python/api2_2x/Registry.h b/source/blender/python/api2_2x/Registry.h new file mode 100644 index 00000000000..4383d63e0bc --- /dev/null +++ b/source/blender/python/api2_2x/Registry.h @@ -0,0 +1,50 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +/* This submodule was introduced as a way to preserve configured data in + * scripts. A very simple idea: the script writer saves this data in a dict + * and registers this dict in the "Registry" dict. This way we can discard + * the global interpreter dictionary after a script is executed, since the + * data meant to be kept was copied to the Registry elsewhere. The current + * implementation is naive: scripts can deliberately mess with data saved by + * other scripts. This is so new script versions can delete older entries, if + * they need to. XXX Or should we block this? */ + +#ifndef EXPP_REGISTRY_H +#define EXPP_REGISTRY_H + +#include + +extern PyObject *bpy_registryDict; +PyObject *Registry_Init( void ); + +#endif /* EXPP_REGISTRY_H */ diff --git a/source/blender/python/api2_2x/Scene.c b/source/blender/python/api2_2x/Scene.c new file mode 100644 index 00000000000..62b3a44690b --- /dev/null +++ b/source/blender/python/api2_2x/Scene.c @@ -0,0 +1,1839 @@ +/* + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano, Jacques Guignot, Joseph Gilbert, + * Campbell Barton, Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ +struct View3D; + +#include "Scene.h" /*This must come first */ + +#include "BKE_global.h" +#include "BKE_main.h" +#include "MEM_guardedalloc.h" /* for MEM_callocN */ +#include "DNA_space_types.h" /* SPACE_VIEW3D, SPACE_SEQ */ +#include "DNA_screen_types.h" +#include "DNA_userdef_types.h" /* U.userdefs */ +#include "DNA_object_types.h" /* SceneObSeq_new */ +#include "BKE_depsgraph.h" +#include "BKE_library.h" +#include "BKE_object.h" +#include "BKE_scene.h" +#include "BKE_font.h" +#include "BKE_idprop.h" +#include "BLI_blenlib.h" /* only for SceneObSeq_new */ +#include "BSE_drawview.h" /* for play_anim */ +#include "BSE_headerbuttons.h" /* for copy_scene */ +#include "BIF_drawscene.h" /* for set_scene */ +#include "BIF_space.h" /* for copy_view3d_lock() */ +#include "BIF_screen.h" /* curarea */ +#include "BDR_editobject.h" /* free_and_unlink_base() */ +#include "mydevice.h" /* for #define REDRAW */ +#include "DNA_view3d_types.h" +/* python types */ +#include "Object.h" +#include "Camera.h" +/* only for SceneObSeq_new */ +#include "BKE_material.h" +#include "BLI_arithb.h" +#include "Armature.h" +#include "Lamp.h" +#include "Curve.h" +#include "NMesh.h" +#include "Mesh.h" +#include "World.h" +#include "Lattice.h" +#include "Metaball.h" +#include "IDProp.h" +#include "Text3d.h" +#include "Library.h" + +#include "gen_utils.h" +#include "gen_library.h" +#include "sceneRender.h" +#include "sceneRadio.h" +#include "sceneTimeLine.h" +#include "sceneSequence.h" + + +#include "BKE_utildefines.h" /* vec copy */ +#include "vector.h" + +PyObject *M_Object_Get( PyObject * self, PyObject * args ); /* from Object.c */ + +/* checks for the scene being removed */ +#define SCENE_DEL_CHECK_PY(bpy_scene) if (!(bpy_scene->scene)) return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, "Scene has been removed" ) ) +#define SCENE_DEL_CHECK_INT(bpy_scene) if (!(bpy_scene->scene)) return ( EXPP_ReturnIntError( PyExc_RuntimeError, "Scene has been removed" ) ) + + +enum obj_consts { + EXPP_OBSEQ_NORMAL = 0, + EXPP_OBSEQ_SELECTED, + EXPP_OBSEQ_CONTEXT +}; + + +/*-----------------------Python API function prototypes for the Scene module--*/ +static PyObject *M_Scene_New( PyObject * self, PyObject * args, + PyObject * keywords ); +static PyObject *M_Scene_Get( PyObject * self, PyObject * args ); +static PyObject *M_Scene_GetCurrent( PyObject * self ); +static PyObject *M_Scene_getCurrent_deprecated( PyObject * self ); +static PyObject *M_Scene_Unlink( PyObject * self, PyObject * arg ); +/*-----------------------Scene module doc strings-----------------------------*/ +static char M_Scene_doc[] = "The Blender.Scene submodule"; +static char M_Scene_New_doc[] = + "(name = 'Scene') - Create a new Scene called 'name' in Blender."; +static char M_Scene_Get_doc[] = + "(name = None) - Return the scene called 'name'. If 'name' is None, return a list with all Scenes."; +static char M_Scene_GetCurrent_doc[] = + "() - Return the currently active Scene in Blender."; +static char M_Scene_Unlink_doc[] = + "(scene) - Unlink (delete) scene 'Scene' from Blender. (scene) is of type Blender scene."; +/*----------------------Scene module method def----------------------------*/ +struct PyMethodDef M_Scene_methods[] = { + {"New", ( PyCFunction ) M_Scene_New, METH_VARARGS | METH_KEYWORDS, + M_Scene_New_doc}, + {"Get", M_Scene_Get, METH_VARARGS, M_Scene_Get_doc}, + {"get", M_Scene_Get, METH_VARARGS, M_Scene_Get_doc}, + {"GetCurrent", ( PyCFunction ) M_Scene_GetCurrent, + METH_NOARGS, M_Scene_GetCurrent_doc}, + {"getCurrent", ( PyCFunction ) M_Scene_getCurrent_deprecated, + METH_NOARGS, M_Scene_GetCurrent_doc}, + {"Unlink", M_Scene_Unlink, METH_VARARGS, M_Scene_Unlink_doc}, + {"unlink", M_Scene_Unlink, METH_VARARGS, M_Scene_Unlink_doc}, + {NULL, NULL, 0, NULL} +}; +/*-----------------------BPy_Scene method declarations--------------------*/ +static PyObject *Scene_getLayerList( BPy_Scene * self ); +static PyObject *Scene_oldsetLayers( BPy_Scene * self, PyObject * arg ); +static PyObject *Scene_copy( BPy_Scene * self, PyObject * arg ); +static PyObject *Scene_makeCurrent( BPy_Scene * self ); +static PyObject *Scene_update( BPy_Scene * self, PyObject * args ); +static PyObject *Scene_link( BPy_Scene * self, PyObject * args ); +static PyObject *Scene_unlink( BPy_Scene * self, PyObject * args ); +static PyObject *Scene_getChildren( BPy_Scene * self ); +static PyObject *Scene_getActiveObject(BPy_Scene *self); +static PyObject *Scene_getCurrentCamera( BPy_Scene * self ); +static PyObject *Scene_setCurrentCamera( BPy_Scene * self, PyObject * args ); +static PyObject *Scene_getRenderingContext( BPy_Scene * self ); +static PyObject *Scene_getRadiosityContext( BPy_Scene * self ); +static PyObject *Scene_getScriptLinks( BPy_Scene * self, PyObject * value ); +static PyObject *Scene_getSequence( BPy_Scene * self ); +static PyObject *Scene_addScriptLink( BPy_Scene * self, PyObject * args ); +static PyObject *Scene_clearScriptLinks( BPy_Scene * self, PyObject * args ); +static PyObject *Scene_play( BPy_Scene * self, PyObject * args ); +static PyObject *Scene_getTimeLine( BPy_Scene * self ); + + +/*internal*/ +static int Scene_compare( BPy_Scene * a, BPy_Scene * b ); +static PyObject *Scene_repr( BPy_Scene * self ); + +/*object seq*/ +static PyObject *SceneObSeq_CreatePyObject( BPy_Scene *self, Base *iter, int mode); + +/*-----------------------BPy_Scene method def------------------------------*/ +static PyMethodDef BPy_Scene_methods[] = { + /* name, method, flags, doc */ + {"getName", ( PyCFunction ) GenericLib_getName, METH_NOARGS, + "() - Return Scene name"}, + {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS, + "(str) - Change Scene name"}, + {"getLayers", ( PyCFunction ) Scene_getLayerList, METH_NOARGS, + "() - Return a list of layers int indices which are set in this scene "}, + {"setLayers", ( PyCFunction ) Scene_oldsetLayers, METH_VARARGS, + "(layers) - Change layers which are set in this scene\n" + "(layers) - list of integers in the range [1, 20]."}, + {"copy", ( PyCFunction ) Scene_copy, METH_VARARGS, + "(duplicate_objects = 1) - Return a copy of this scene\n" + "The optional argument duplicate_objects defines how the scene\n" + "children are duplicated:\n\t0: Link Objects\n\t1: Link Object Data" + "\n\t2: Full copy\n"}, + {"makeCurrent", ( PyCFunction ) Scene_makeCurrent, METH_NOARGS, + "() - Make self the current scene"}, + {"update", ( PyCFunction ) Scene_update, METH_VARARGS, + "(full = 0) - Update scene self.\n" + "full = 0: sort the base list of objects." + "full = 1: full update -- also regroups, does ipos, keys"}, + {"link", ( PyCFunction ) Scene_link, METH_VARARGS, + "(obj) - Link Object obj to this scene"}, + {"unlink", ( PyCFunction ) Scene_unlink, METH_VARARGS, + "(obj) - Unlink Object obj from this scene"}, + {"getChildren", ( PyCFunction ) Scene_getChildren, METH_NOARGS, + "() - Return list of all objects linked to this scene"}, + {"getActiveObject", (PyCFunction)Scene_getActiveObject, METH_NOARGS, + "() - Return this scene's active object"}, + {"getCurrentCamera", ( PyCFunction ) Scene_getCurrentCamera, + METH_NOARGS, + "() - Return current active Camera"}, + {"getScriptLinks", ( PyCFunction ) Scene_getScriptLinks, METH_O, + "(eventname) - Get a list of this scene's scriptlinks (Text names) " + "of the given type\n" + "(eventname) - string: FrameChanged, OnLoad, OnSave, Redraw or Render."}, + {"addScriptLink", ( PyCFunction ) Scene_addScriptLink, METH_VARARGS, + "(text, evt) - Add a new scene scriptlink.\n" + "(text) - string: an existing Blender Text name;\n" + "(evt) string: FrameChanged, OnLoad, OnSave, Redraw or Render."}, + {"clearScriptLinks", ( PyCFunction ) Scene_clearScriptLinks, + METH_VARARGS, + "() - Delete all scriptlinks from this scene.\n" + "([s1<,s2,s3...>]) - Delete specified scriptlinks from this scene."}, + {"setCurrentCamera", ( PyCFunction ) Scene_setCurrentCamera, + METH_VARARGS, + "() - Set the currently active Camera"}, + {"getRenderingContext", ( PyCFunction ) Scene_getRenderingContext, + METH_NOARGS, + "() - Get the rendering context for the scene and return it as a BPy_RenderData"}, + {"getRadiosityContext", ( PyCFunction ) Scene_getRadiosityContext, + METH_NOARGS, + "() - Get the radiosity context for this scene."}, + {"play", ( PyCFunction ) Scene_play, METH_VARARGS, + "(mode = 0, win = VIEW3D) - Play realtime animation in Blender" + " (not rendered).\n" + "(mode) - int:\n" + "\t0 - keep playing in biggest given 'win';\n" + "\t1 - keep playing in all 'win', VIEW3D and SEQ windows;\n" + "\t2 - play once in biggest given 'win';\n" + "\t3 - play once in all 'win', VIEW3D and SEQ windows.\n" + "(win) - int: see Blender.Window.Types. Only these are meaningful here:" + "VIEW3D, SEQ, IPO, ACTION, NLA, SOUND. But others are also accepted, " + "since they can be used just as an interruptible timer. If 'win' is not" + "available or invalid, VIEW3D is tried, then any bigger window." + "Returns 0 for normal exit or 1 when canceled by user input."}, + {"getTimeLine", ( PyCFunction ) Scene_getTimeLine, METH_NOARGS, + "() - Get time line of this Scene"}, + {NULL, NULL, 0, NULL} +}; + + +/*****************************************************************************/ +/* Python BPy_Scene getsetattr funcs: */ +/*****************************************************************************/ +static PyObject *Scene_getLayerMask( BPy_Scene * self ) +{ + SCENE_DEL_CHECK_PY(self); + return PyInt_FromLong( self->scene->lay & ((1<<20)-1) ); +} + +static int Scene_setLayerMask( BPy_Scene * self, PyObject * value ) +{ + int laymask = 0; + + SCENE_DEL_CHECK_INT(self); + + if (!PyInt_Check(value)) { + return EXPP_ReturnIntError( PyExc_AttributeError, + "expected an integer (bitmask) as argument" ); + } + + laymask = PyInt_AsLong(value); + + if (laymask <= 0 || laymask > (1<<20) - 1) /* binary: 1111 1111 1111 1111 1111 */ + return EXPP_ReturnIntError( PyExc_AttributeError, + "bitmask must have from 1 up to 20 bits set"); + + self->scene->lay = laymask; + /* if this is the current scene then apply the scene layers value + * to the view layers value: */ + if (G.vd && (self->scene == G.scene)) { + int val, bit = 0; + G.vd->lay = laymask; + + while( bit < 20 ) { + val = 1 << bit; + if( laymask & val ) { + G.vd->layact = val; + break; + } + bit++; + } + } + + return 0; +} + +static PyObject *Scene_getLayerList( BPy_Scene * self ) +{ + PyObject *laylist, *item; + int layers, bit = 0, val = 0; + + SCENE_DEL_CHECK_PY(self); + + laylist = PyList_New( 0 ); + + if( !laylist ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create pylist!" ) ); + + layers = self->scene->lay; + + while( bit < 20 ) { + val = 1 << bit; + if( layers & val ) { + item = Py_BuildValue( "i", bit + 1 ); + PyList_Append( laylist, item ); + Py_DECREF( item ); + } + bit++; + } + return laylist; +} + +static int Scene_setLayerList( BPy_Scene * self, PyObject * value ) +{ + PyObject *item = NULL; + int layers = 0, val, i, len_list; + + SCENE_DEL_CHECK_INT(self); + + if( !PySequence_Check( value ) ) + return ( EXPP_ReturnIntError( PyExc_TypeError, + "expected a list of integers in the range [1, 20]" ) ); + + len_list = PySequence_Size(value); + + if (len_list == 0) + return ( EXPP_ReturnIntError( PyExc_AttributeError, + "list can't be empty, at least one layer must be set" ) ); + + for( i = 0; i < len_list; i++ ) { + item = PySequence_GetItem( value, i ); + + if( !PyInt_Check( item ) ) { + Py_DECREF( item ); + return EXPP_ReturnIntError + ( PyExc_AttributeError, + "list must contain only integer numbers" ); + } + + val = ( int ) PyInt_AsLong( item ); + if( val < 1 || val > 20 ) + return EXPP_ReturnIntError + ( PyExc_AttributeError, + "layer values must be in the range [1, 20]" ); + + layers |= 1 << ( val - 1 ); + } + self->scene->lay = layers; + + if (G.vd && (self->scene == G.scene)) { + int bit = 0; + G.vd->lay = layers; + + while( bit < 20 ) { + val = 1 << bit; + if( layers & val ) { + G.vd->layact = val; + break; + } + bit++; + } + } + + return 0; +} + +static PyObject *Scene_getWorld( BPy_Scene * self ) +{ + SCENE_DEL_CHECK_PY(self); + + if (!self->scene->world) + Py_RETURN_NONE; + return World_CreatePyObject(self->scene->world); +} + +static int Scene_setWorld( BPy_Scene * self, PyObject * value ) +{ + SCENE_DEL_CHECK_INT(self); + return GenericLib_assignData(value, (void **) &self->scene->world, NULL, 1, ID_WO, 0); +} + +/* accessed from scn.objects */ +static PyObject *Scene_getObjects( BPy_Scene *self) +{ + SCENE_DEL_CHECK_PY(self); + return SceneObSeq_CreatePyObject(self, NULL, 0); +} + +static PyObject *Scene_getCursor( BPy_Scene * self ) +{ + SCENE_DEL_CHECK_PY(self); + return newVectorObject( self->scene->cursor, 3, Py_WRAP ); +} + +static int Scene_setCursor( BPy_Scene * self, PyObject * value ) +{ + VectorObject *bpy_vec; + SCENE_DEL_CHECK_INT(self); + if (!VectorObject_Check(value)) + return ( EXPP_ReturnIntError( PyExc_TypeError, + "expected a vector" ) ); + + bpy_vec = (VectorObject *)value; + + if (bpy_vec->size != 3) + return ( EXPP_ReturnIntError( PyExc_ValueError, + "can only assign a 3D vector" ) ); + + VECCOPY(self->scene->cursor, bpy_vec->vec); + return 0; +} + +/*****************************************************************************/ +/* Python attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef BPy_Scene_getseters[] = { + GENERIC_LIB_GETSETATTR, + {"Layers", + (getter)Scene_getLayerMask, (setter)Scene_setLayerMask, + "Scene layer bitmask", + NULL}, + {"layers", + (getter)Scene_getLayerList, (setter)Scene_setLayerList, + "Scene layer list", + NULL}, + {"world", + (getter)Scene_getWorld, (setter)Scene_setWorld, + "Scene layer bitmask", + NULL}, + {"cursor", + (getter)Scene_getCursor, (setter)Scene_setCursor, + "Scene layer bitmask", + NULL}, + {"timeline", + (getter)Scene_getTimeLine, (setter)NULL, + "Scenes timeline (read only)", + NULL}, + {"render", + (getter)Scene_getRenderingContext, (setter)NULL, + "Scenes rendering context (read only)", + NULL}, + {"radiosity", + (getter)Scene_getRadiosityContext, (setter)NULL, + "Scenes radiosity context (read only)", + NULL}, + {"sequence", + (getter)Scene_getSequence, (setter)NULL, + "Scene sequencer data (read only)", + NULL}, + + {"objects", + (getter)Scene_getObjects, (setter)NULL, + "Scene object iterator", + NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + + + +/*-----------------------BPy_Scene method def------------------------------*/ +PyTypeObject Scene_Type = { + PyObject_HEAD_INIT( NULL ) + 0, /* ob_size */ + "Scene", /* tp_name */ + sizeof( BPy_Scene ), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + NULL, /* tp_dealloc */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) Scene_compare, /* tp_compare */ + ( reprfunc ) Scene_repr, /* tp_repr */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_Scene_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_Scene_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +/*-----------------------Scene module Init())-----------------------------*/ +PyObject *Scene_Init( void ) +{ + + PyObject *submodule; + PyObject *dict; + + if( PyType_Ready( &Scene_Type ) < 0 ) + return NULL; + if( PyType_Ready( &SceneObSeq_Type ) < 0 ) + return NULL; + + submodule = Py_InitModule3( "Blender.Scene", M_Scene_methods, M_Scene_doc ); + + dict = PyModule_GetDict( submodule ); + PyDict_SetItemString( dict, "Render", Render_Init( ) ); + PyDict_SetItemString( dict, "Radio", Radio_Init( ) ); + PyDict_SetItemString( dict, "Sequence", Sequence_Init( ) ); + + return submodule; +} + +/*-----------------------compare----------------------------------------*/ +static int Scene_compare( BPy_Scene * a, BPy_Scene * b ) +{ + return ( a->scene == b->scene ) ? 0 : -1; +} + +/*----------------------repr--------------------------------------------*/ +static PyObject *Scene_repr( BPy_Scene * self ) +{ + if( !(self->scene) ) + return PyString_FromString( "[Scene - Removed]"); + else + return PyString_FromFormat( "[Scene \"%s\"]", + self->scene->id.name + 2 ); +} + +/*-----------------------CreatePyObject---------------------------------*/ +PyObject *Scene_CreatePyObject( Scene * scene ) +{ + BPy_Scene *pyscene; + + pyscene = ( BPy_Scene * ) PyObject_NEW( BPy_Scene, &Scene_Type ); + + if( !pyscene ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create BPy_Scene object" ); + + pyscene->scene = scene; + + return ( PyObject * ) pyscene; +} + +/*-----------------------FromPyObject-----------------------------------*/ +Scene *Scene_FromPyObject( PyObject * pyobj ) +{ + return ( ( BPy_Scene * ) pyobj )->scene; +} + +/*-----------------------Scene module function defintions---------------*/ +/*-----------------------Scene.New()------------------------------------*/ +static PyObject *M_Scene_New( PyObject * self, PyObject * args, + PyObject * kword ) +{ + char *name = "Scene"; + char *kw[] = { "name", NULL }; + PyObject *pyscene; /* for the Scene object wrapper in Python */ + Scene *blscene; /* for the actual Scene we create in Blender */ + + if( !PyArg_ParseTupleAndKeywords( args, kword, "|s", kw, &name ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected a string or an empty argument list" ) ); + + blscene = add_scene( name ); /* first create the Scene in Blender */ + + if( blscene ) { + /* normally, for most objects, we set the user count to zero here. + * Scene is different than most objs since it is the container + * for all the others. Since add_scene() has already set + * the user count to one, we leave it alone. + */ + + /* now create the wrapper obj in Python */ + pyscene = Scene_CreatePyObject( blscene ); + } else + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't create Scene obj in Blender" ) ); + + if( pyscene == NULL ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create Scene PyObject" ) ); + + return pyscene; +} + +/*-----------------------Scene.Get()------------------------------------*/ +static PyObject *M_Scene_Get( PyObject * self, PyObject * args ) +{ + char *name = NULL; + Scene *scene_iter; + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument (or nothing)" ) ); + + scene_iter = G.main->scene.first; + + if( name ) { /* (name) - Search scene by name */ + + PyObject *wanted_scene = NULL; + + while( ( scene_iter ) && ( wanted_scene == NULL ) ) { + + if( strcmp( name, scene_iter->id.name + 2 ) == 0 ) + wanted_scene = + Scene_CreatePyObject( scene_iter ); + + scene_iter = scene_iter->id.next; + } + + if( wanted_scene == NULL ) { /* Requested scene doesn't exist */ + char error_msg[64]; + PyOS_snprintf( error_msg, sizeof( error_msg ), + "Scene \"%s\" not found", name ); + return ( EXPP_ReturnPyObjError + ( PyExc_NameError, error_msg ) ); + } + + return wanted_scene; + } + + else { /* () - return a list with wrappers for all scenes in Blender */ + int index = 0; + PyObject *sce_pylist, *pyobj; + + sce_pylist = PyList_New( BLI_countlist( &( G.main->scene ) ) ); + + if( sce_pylist == NULL ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyList" ) ); + + while( scene_iter ) { + pyobj = Scene_CreatePyObject( scene_iter ); + + if( !pyobj ) { + Py_DECREF(sce_pylist); + return ( EXPP_ReturnPyObjError + ( PyExc_MemoryError, + "couldn't create PyString" ) ); + } + PyList_SET_ITEM( sce_pylist, index, pyobj ); + + scene_iter = scene_iter->id.next; + index++; + } + + return sce_pylist; + } +} + +/*-----------------------Scene.GetCurrent()------------------------------*/ +static PyObject *M_Scene_GetCurrent( PyObject * self ) +{ + return Scene_CreatePyObject( ( Scene * ) G.scene ); +} + +static PyObject *M_Scene_getCurrent_deprecated( PyObject * self ) +{ + static char warning = 1; + if( warning ) { + printf("Blender.Scene.getCurrent() is deprecated,\n\tuse Blender.Scene.GetCurrent() instead.\n"); + --warning; + } + + return Scene_CreatePyObject( ( Scene * ) G.scene ); +} + + +/*-----------------------Scene.Unlink()----------------------------------*/ +static PyObject *M_Scene_Unlink( PyObject * self, PyObject * args ) +{ + PyObject *pyobj; + BPy_Scene *pyscn; + Scene *scene; + + if( !PyArg_ParseTuple( args, "O!", &Scene_Type, &pyobj ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected Scene PyType object" ); + + pyscn = (BPy_Scene *)pyobj; + scene = pyscn->scene; + + SCENE_DEL_CHECK_PY(pyscn); + + if( scene == G.scene ) + return EXPP_ReturnPyObjError( PyExc_SystemError, + "current Scene cannot be removed!" ); + + free_libblock( &G.main->scene, scene ); + + pyscn->scene= NULL; + Py_RETURN_NONE; +} + +/* DEPRECATE ME !!! */ +/*-----------------------BPy_Scene function defintions-------------------*/ + +/*-----------------------Scene.setLayers()---------------------------------*/ +static PyObject *Scene_oldsetLayers( BPy_Scene * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Scene_setLayerList ); +} +/* END DEPRECATE CODE */ + + +/*-----------------------Scene.copy()------------------------------------*/ +static PyObject *Scene_copy( BPy_Scene * self, PyObject * args ) +{ + short dup_objs = 1; + Scene *scene = self->scene; + + SCENE_DEL_CHECK_PY(self); + + if( !PyArg_ParseTuple( args, "|h", &dup_objs ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int in [0,2] or nothing as argument" ); + + return Scene_CreatePyObject( copy_scene( scene, dup_objs ) ); +} + +/*-----------------------Scene.makeCurrent()-----------------------------*/ +static PyObject *Scene_makeCurrent( BPy_Scene * self ) +{ + Scene *scene = self->scene; +#if 0 /* add back in when bpy becomes "official" */ + static char warning = 1; + if( warning ) { + printf("scene.makeCurrent() deprecated!\n\tuse bpy.scenes.active = scene instead\n"); + --warning; + } +#endif + + SCENE_DEL_CHECK_PY(self); + + if( scene && scene != G.scene) { + set_scene( scene ); + scene_update_for_newframe(scene, scene->lay); + } + + Py_RETURN_NONE; +} + +/*-----------------------Scene.update()----------------------------------*/ +static PyObject *Scene_update( BPy_Scene * self, PyObject * args ) +{ + Scene *scene = self->scene; + int full = 0; + + SCENE_DEL_CHECK_PY(self); + if( !PyArg_ParseTuple( args, "|i", &full ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected nothing or int (0 or 1) argument" ); + +/* Under certain circunstances, DAG_scene_sort *here* can crash Blender. + * A "RuntimeError: max recursion limit" happens when a scriptlink + * on frame change has scene.update(1). + * Investigate better how to avoid this. */ + if( !full ) + DAG_scene_sort( scene ); + + else if( full == 1 ) + set_scene_bg( scene ); + + else + return EXPP_ReturnPyObjError( PyExc_ValueError, + "in method scene.update(full), full should be:\n" + "0: to only sort scene elements (old behavior); or\n" + "1: for a full update (regroups, does ipos, keys, etc.)" ); + + Py_RETURN_NONE; +} + +/*-----------------------Scene.link()------------------------------------*/ +static PyObject *Scene_link( BPy_Scene * self, PyObject * args ) +{ + Scene *scene = self->scene; + BPy_Object *bpy_obj; + Object *object = NULL; + static char warning = 1; + + if( warning ) { + printf("scene.link(ob) deprecated!\n\tuse scene.objects.link(ob) instead\n"); + --warning; + } + + SCENE_DEL_CHECK_PY(self); + + if( !PyArg_ParseTuple( args, "O!", &Object_Type, &bpy_obj ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected Object argument" ); + + + /*return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Could not create data on demand for this object type!" );*/ + + object = bpy_obj->object; + + /* Object.c's EXPP_add_obdata does not support these objects */ + if (!object->data && (object->type == OB_SURF || object->type == OB_FONT || object->type == OB_WAVE )) { + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Object has no data and new data cant be automaticaly created for Surf, Text or Wave type objects!" ); + } else { + /* Ok, all is fine, let's try to link it */ + Base *base; + + /* We need to link the object to a 'Base', then link this base + * to the scene. See DNA_scene_types.h ... */ + + /* First, check if the object isn't already in the scene */ + base = object_in_scene( object, scene ); + /* if base is not NULL ... */ + if( base ) /* ... the object is already in one of the Scene Bases */ + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "object already in scene!" ); + + /* not linked, go get mem for a new base object */ + + base = MEM_callocN( sizeof( Base ), "pynewbase" ); + + if( !base ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't allocate new Base for object" ); + + /* if the object has not yet been linked to object data, then + * set the real type before we try creating data */ + + if( bpy_obj->realtype != OB_EMPTY ) { + object->type = bpy_obj->realtype; + bpy_obj->realtype = OB_EMPTY; + } + + /* check if this object has obdata, case not, try to create it */ + + if( !object->data && ( object->type != OB_EMPTY ) ) + EXPP_add_obdata( object ); /* returns -1 on error, defined in Object.c */ + + base->object = object; /* link object to the new base */ + base->lay = object->lay; + base->flag = object->flag; + + object->id.us += 1; /* incref the object user count in Blender */ + + BLI_addhead( &scene->base, base ); /* finally, link new base to scene */ + } + + Py_RETURN_NONE; +} + +/*-----------------------Scene.unlink()----------------------------------*/ +static PyObject *Scene_unlink( BPy_Scene * self, PyObject * args ) +{ + BPy_Object *bpy_obj = NULL; + Scene *scene = self->scene; + Base *base; + static char warning = 1; + + if( warning ) { + printf("scene.unlink(ob) deprecated!\n\tuse scene.objects.unlink(ob) instead\n"); + --warning; + } + + SCENE_DEL_CHECK_PY(self); + + if( !PyArg_ParseTuple( args, "O!", &Object_Type, &bpy_obj ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected Object as argument" ); + + /* is the object really in the scene? */ + base = object_in_scene( bpy_obj->object, scene ); + + if( base ) { /* if it is, remove it */ + if (scene->basact==base) + scene->basact= NULL; /* in case the object was selected */ + + free_and_unlink_base_from_scene( scene, base ); + Py_RETURN_TRUE; + } + else + Py_RETURN_FALSE; +} + +/*-----------------------Scene.getChildren()-----------------------------*/ +static PyObject *Scene_getChildren( BPy_Scene * self ) +{ + Scene *scene = self->scene; + PyObject *pylist; + PyObject *bpy_obj; + Object *object; + Base *base; + static char warning = 1; + + if( warning ) { + printf("scene.getChildren() deprecated!\n\tuse scene.objects instead\n"); + --warning; + } + + SCENE_DEL_CHECK_PY(self); + + pylist = PyList_New( 0 ); + + base = scene->base.first; + + while( base ) { + object = base->object; + + bpy_obj = Object_CreatePyObject( object ); + + if( !bpy_obj ) { + Py_DECREF(pylist); + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't create new object wrapper" ); + } + PyList_Append( pylist, bpy_obj ); + Py_DECREF( bpy_obj ); /* PyList_Append incref'ed it */ + + base = base->next; + } + + return pylist; +} + +/*-----------------------Scene.getActiveObject()------------------------*/ +static PyObject *Scene_getActiveObject(BPy_Scene *self) +{ + Scene *scene = self->scene; + PyObject *pyob; + Object *ob; + static char warning = 1; + + if( warning ) { + printf("scene.getActiveObject() deprecated!\n\tuse scene.objects.active instead\n"); + --warning; + } + + SCENE_DEL_CHECK_PY(self); + + ob = ((scene->basact) ? (scene->basact->object) : 0); + + if (ob) { + pyob = Object_CreatePyObject( ob ); + + if (!pyob) + return EXPP_ReturnPyObjError(PyExc_MemoryError, + "couldn't create new object wrapper!"); + + return pyob; + } + + Py_RETURN_NONE; /* no active object */ +} + +/*-----------------------Scene.getCurrentCamera()------------------------*/ +static PyObject *Scene_getCurrentCamera( BPy_Scene * self ) +{ + static char warning = 1; + + if( warning ) { + printf("scene.getCurrentCamera() deprecated!\n\tuse scene.objects.camera instead\n"); + --warning; + } + + SCENE_DEL_CHECK_PY(self); + /* None is ok */ + return Object_CreatePyObject( self->scene->camera ); +} + +/*-----------------------Scene.setCurrentCamera()------------------------*/ +static PyObject *Scene_setCurrentCamera( BPy_Scene * self, PyObject * args ) +{ + Object *object; + BPy_Object *cam_obj; + Scene *scene = self->scene; + static char warning = 1; + + if( warning ) { + printf("scene.setCurrentCamera(ob) deprecated!\n\tSet scene.objects.camera = ob instead\n"); + --warning; + } + + SCENE_DEL_CHECK_PY(self); + + if( !PyArg_ParseTuple( args, "O!", &Object_Type, &cam_obj ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected Camera Object as argument" ); + + object = cam_obj->object; + if( object->type != OB_CAMERA ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "expected Camera Object as argument" ); + + scene->camera = object; /* set the current Camera */ + + /* if this is the current scene, update its window now */ + if( !G.background && scene == G.scene ) /* Traced a crash to redrawing while in background mode -Campbell */ + copy_view3d_lock( REDRAW ); + +/* XXX copy_view3d_lock(REDRAW) prints "bad call to addqueue: 0 (18, 1)". + * The same happens in bpython. */ + + Py_RETURN_NONE; +} + +/*-----------------------Scene.getRenderingContext()---------------------*/ +static PyObject *Scene_getRenderingContext( BPy_Scene * self ) +{ + SCENE_DEL_CHECK_PY(self); + return RenderData_CreatePyObject( self->scene ); +} + +static PyObject *Scene_getRadiosityContext( BPy_Scene * self ) +{ + SCENE_DEL_CHECK_PY(self); + return Radio_CreatePyObject( self->scene ); +} + +static PyObject *Scene_getSequence( BPy_Scene * self ) +{ + SCENE_DEL_CHECK_PY(self); + if (self->scene->ed) /* we should create this if its not there :/ */ + return SceneSeq_CreatePyObject( self->scene, NULL ); + else + Py_RETURN_NONE; +} + +/* scene.addScriptLink */ +static PyObject *Scene_addScriptLink( BPy_Scene * self, PyObject * args ) +{ + Scene *scene = self->scene; + ScriptLink *slink = NULL; + + SCENE_DEL_CHECK_PY(self); + + slink = &( scene )->scriptlink; + + return EXPP_addScriptLink( slink, args, 1 ); +} + +/* scene.clearScriptLinks */ +static PyObject *Scene_clearScriptLinks( BPy_Scene * self, PyObject * args ) +{ + Scene *scene = self->scene; + ScriptLink *slink = NULL; + + SCENE_DEL_CHECK_PY(self); + + slink = &( scene )->scriptlink; + + return EXPP_clearScriptLinks( slink, args ); +} + +/* scene.getScriptLinks */ +static PyObject *Scene_getScriptLinks( BPy_Scene * self, PyObject * value ) +{ + Scene *scene = self->scene; + ScriptLink *slink = NULL; + PyObject *ret = NULL; + + SCENE_DEL_CHECK_PY(self); + + slink = &( scene )->scriptlink; + + ret = EXPP_getScriptLinks( slink, value, 1 ); + + if( ret ) + return ret; + else + return NULL; +} + +static PyObject *Scene_play( BPy_Scene * self, PyObject * args ) +{ + int mode = 0, win = SPACE_VIEW3D; + PyObject *ret = NULL; + ScrArea *sa = NULL, *oldsa = curarea; + + SCENE_DEL_CHECK_PY(self); + + if( !PyArg_ParseTuple( args, "|ii", &mode, &win ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected nothing, or or two ints as arguments." ); + + if( mode < 0 || mode > 3 ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "mode should be in range [0, 3]." ); + + switch ( win ) { + case SPACE_VIEW3D: + case SPACE_SEQ: + case SPACE_IPO: + case SPACE_ACTION: + case SPACE_NLA: + case SPACE_SOUND: + case SPACE_BUTS: /* from here they don't 'play', but ... */ + case SPACE_TEXT: /* ... might be used as a timer. */ + case SPACE_SCRIPT: + case SPACE_OOPS: + case SPACE_IMAGE: + case SPACE_IMASEL: + case SPACE_INFO: + case SPACE_FILE: + break; + default: + win = SPACE_VIEW3D; + } + + /* we have to move to a proper win */ + sa = find_biggest_area_of_type( win ); + if( !sa && win != SPACE_VIEW3D ) + sa = find_biggest_area_of_type( SPACE_VIEW3D ); + + if( !sa ) + sa = find_biggest_area( ); + + if( sa ) + areawinset( sa->win ); + + /* play_anim returns 0 for normal exit or 1 if user canceled it */ + ret = PyInt_FromLong( (long)play_anim( mode ) ); + + if( sa ) + areawinset( oldsa->win ); + + return ret; +} + +static PyObject *Scene_getTimeLine( BPy_Scene *self ) +{ + BPy_TimeLine *tm; + + SCENE_DEL_CHECK_PY(self); + + tm= (BPy_TimeLine *) PyObject_NEW (BPy_TimeLine, &TimeLine_Type); + if (!tm) + return EXPP_ReturnPyObjError (PyExc_MemoryError, + "couldn't create BPy_TimeLine object"); + tm->marker_list= &(self->scene->markers); + tm->sfra= (int) self->scene->r.sfra; + tm->efra= (int) self->scene->r.efra; + + return (PyObject *)tm; +} + +/************************************************************************ + * + * Object Sequence + * + ************************************************************************/ +/* + * create a thin wrapper for the scenes objects + */ + +/* accessed from scn.objects.selected or scn.objects.context */ +static PyObject *SceneObSeq_getObjects( BPy_SceneObSeq *self, void *mode) +{ + SCENE_DEL_CHECK_PY(self->bpyscene); + return SceneObSeq_CreatePyObject(self->bpyscene, NULL, (int)((long)mode)); +} + +int SceneObSeq_setObjects( BPy_SceneObSeq *self, PyObject *value, void *_mode_) +{ + /* + ONLY SUPPORTS scn.objects.selected and scn.objects.context + cannot assign to scn.objects yet!!! + */ + PyObject *item; + Scene *scene= self->bpyscene->scene; + Object *blen_ob; + Base *base; + int size, mode = (int)_mode_; + + SCENE_DEL_CHECK_INT(self->bpyscene); + + /* scn.objects.selected = scn.objects - shortcut to select all */ + if (BPy_SceneObSeq_Check(value)) { + BPy_SceneObSeq *bpy_sceneseq = (BPy_SceneObSeq *)value; + if (self->bpyscene->scene != bpy_sceneseq->bpyscene->scene) + return EXPP_ReturnIntError( PyExc_ValueError, + "Cannot assign a SceneObSeq type from another scene" ); + if (bpy_sceneseq->mode != EXPP_OBSEQ_NORMAL) + return EXPP_ReturnIntError( PyExc_ValueError, + "Can only assign scn.objects to scn.objects.context or scn.objects.selected" ); + + for (base= scene->base.first; base; base= base->next) { + base->flag |= SELECT; + base->object->flag |= SELECT; + + if (mode==EXPP_OBSEQ_CONTEXT && G.vd) { + base->object->lay= base->lay= G.vd->lay; + } + } + return 0; + } + + if (!PySequence_Check(value)) + return EXPP_ReturnIntError( PyExc_ValueError, + "Error, must assign a sequence of objects to scn.objects.selected" ); + + /* for context and selected, just deselect, dont remove */ + for (base= scene->base.first; base; base= base->next) { + base->flag &= ~SELECT; + base->object->flag &= ~SELECT; + } + + size = PySequence_Length(value); + while (size) { + size--; + item = PySequence_GetItem(value, size); + if ( PyObject_TypeCheck(item, &Object_Type) ) { + blen_ob= ((BPy_Object *)item)->object; + base = object_in_scene( blen_ob, scene ); + if (base) { + blen_ob->flag |= SELECT; + base->flag |= SELECT; + if (mode==EXPP_OBSEQ_CONTEXT && G.vd) { + blen_ob->restrictflag &= ~OB_RESTRICT_VIEW; + blen_ob->lay= base->lay= G.vd->lay; + } + } + } + Py_DECREF(item); + } + return 0; +} + + +static PyObject *SceneObSeq_CreatePyObject( BPy_Scene *self, Base *iter, int mode ) +{ + BPy_SceneObSeq *seq = PyObject_NEW( BPy_SceneObSeq, &SceneObSeq_Type); + seq->bpyscene = self; Py_INCREF(self); + seq->iter = iter; + seq->mode = mode; + return (PyObject *)seq; +} + +static int SceneObSeq_len( BPy_SceneObSeq * self ) +{ + Scene *scene= self->bpyscene->scene; + SCENE_DEL_CHECK_INT(self->bpyscene); + + if (self->mode == EXPP_OBSEQ_NORMAL) + return BLI_countlist( &( scene->base ) ); + else if (self->mode == EXPP_OBSEQ_SELECTED) { + int len=0; + Base *base; + for (base= scene->base.first; base; base= base->next) { + if (base->flag & SELECT) { + len++; + } + } + return len; + } else if (self->mode == EXPP_OBSEQ_CONTEXT) { + int len=0; + Base *base; + + if( G.vd == NULL ) /* No 3d view has been initialized yet, simply return an empty list */ + return 0; + + for (base= scene->base.first; base; base= base->next) { + if TESTBASE(base) { + len++; + } + } + return len; + } + /*should never run this */ + return 0; +} + +/* + * retrive a single Object from somewhere in the Object list + */ + +static PyObject *SceneObSeq_item( BPy_SceneObSeq * self, int i ) +{ + int index=0; + Base *base= NULL; + Scene *scene= self->bpyscene->scene; + + SCENE_DEL_CHECK_PY(self->bpyscene); + + /* objects */ + if (self->mode==EXPP_OBSEQ_NORMAL) + for (base= scene->base.first; base && i!=index; base= base->next, index++) {} + /* selected */ + else if (self->mode==EXPP_OBSEQ_SELECTED) { + for (base= scene->base.first; base && i!=index; base= base->next) + if (base->flag & SELECT) + index++; + } + /* context */ + else if (self->mode==EXPP_OBSEQ_CONTEXT) { + if (G.vd) + for (base= scene->base.first; base && i!=index; base= base->next) + if TESTBASE(base) + index++; + } + + if (!(base)) + return EXPP_ReturnPyObjError( PyExc_IndexError, + "array index out of range" ); + + return Object_CreatePyObject( base->object ); +} + +static PySequenceMethods SceneObSeq_as_sequence = { + ( inquiry ) SceneObSeq_len, /* sq_length */ + ( binaryfunc ) 0, /* sq_concat */ + ( intargfunc ) 0, /* sq_repeat */ + ( intargfunc ) SceneObSeq_item, /* sq_item */ + ( intintargfunc ) 0, /* sq_slice */ + ( intobjargproc ) 0, /* sq_ass_item */ + ( intintobjargproc ) 0, /* sq_ass_slice */ + 0,0,0, +}; + + +/************************************************************************ + * + * Python SceneObSeq_Type iterator (iterates over GroupObjects) + * + ************************************************************************/ + +/* + * Initialize the interator index + */ + +static PyObject *SceneObSeq_getIter( BPy_SceneObSeq * self ) +{ + /* we need to get the first base, but for selected context we may need to advance + to the first selected or first conext base */ + Base *base= self->bpyscene->scene->base.first; + + SCENE_DEL_CHECK_PY(self->bpyscene); + + if (self->mode==EXPP_OBSEQ_SELECTED) + while (base && !(base->flag & SELECT)) + base= base->next; + else if (self->mode==EXPP_OBSEQ_CONTEXT) { + if (!G.vd) + base= NULL; /* will never iterate if we have no */ + else + while (base && !TESTBASE(base)) + base= base->next; + } + /* create a new iterator if were alredy using this one */ + if (self->iter==NULL) { + self->iter = base; + return EXPP_incr_ret ( (PyObject *) self ); + } else { + return SceneObSeq_CreatePyObject(self->bpyscene, base, self->mode); + } +} + +/* + * Return next SceneOb. + */ + +static PyObject *SceneObSeq_nextIter( BPy_SceneObSeq * self ) +{ + PyObject *object; + Base *base; + if( !(self->iter) || !(self->bpyscene->scene) ) { + self->iter= NULL; + return EXPP_ReturnPyObjError( PyExc_StopIteration, + "iterator at end" ); + } + + object= Object_CreatePyObject( self->iter->object ); + base= self->iter->next; + + if (self->mode==EXPP_OBSEQ_SELECTED) + while (base && !(base->flag & SELECT)) + base= base->next; + else if (self->mode==EXPP_OBSEQ_CONTEXT) { + if (!G.vd) + base= NULL; /* will never iterate if we have no */ + else + while (base && !TESTBASE(base)) + base= base->next; + } + self->iter= base; + return object; +} + + +static PyObject *SceneObSeq_link( BPy_SceneObSeq * self, PyObject *pyobj ) +{ + SCENE_DEL_CHECK_PY(self->bpyscene); + + /* this shold eventually replace Scene_link */ + if (self->mode != EXPP_OBSEQ_NORMAL) + return (EXPP_ReturnPyObjError( PyExc_TypeError, + "Cannot link to objects.selection or objects.context!" )); + + /* + if (self->iter != NULL) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Cannot modify scene objects while iterating" ); + */ + + if( PyTuple_Size(pyobj) == 1 ) { + BPy_LibraryData *seq = ( BPy_LibraryData * )PyTuple_GET_ITEM( pyobj, 0 ); + if( BPy_LibraryData_Check( seq ) ) + return LibraryData_importLibData( seq, seq->name, + ( seq->kind == OBJECT_IS_LINK ? FILE_LINK : 0 ), + self->bpyscene->scene ); + } + return Scene_link(self->bpyscene, pyobj); +} + +/* This is buggy with new object data not already linked to an object, for now use the above code */ +static PyObject *SceneObSeq_new( BPy_SceneObSeq * self, PyObject *args ) +{ + + void *data = NULL; + char *name = NULL; + char *desc = NULL; + short type = OB_EMPTY; + struct Object *object; + Base *base; + PyObject *py_data; + Scene *scene= self->bpyscene->scene; + + SCENE_DEL_CHECK_PY(self->bpyscene); + + if (self->mode != EXPP_OBSEQ_NORMAL) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "Cannot add new to objects.selection or objects.context!" ); + + if( !PyArg_ParseTuple( args, "O|s", &py_data, &name ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "scene.objects.new(obdata) - expected obdata to be\n\ta python obdata type or the string 'Empty'" ); + + if( BPy_Armature_Check( py_data ) ) { + data = ( void * ) Armature_FromPyObject( py_data ); + type = OB_ARMATURE; + } else if( BPy_Camera_Check( py_data ) ) { + data = ( void * ) Camera_FromPyObject( py_data ); + type = OB_CAMERA; + } else if( BPy_Lamp_Check( py_data ) ) { + data = ( void * ) Lamp_FromPyObject( py_data ); + type = OB_LAMP; + } else if( BPy_Curve_Check( py_data ) ) { + data = ( void * ) Curve_FromPyObject( py_data ); + type = OB_CURVE; + } else if( BPy_NMesh_Check( py_data ) ) { + data = ( void * ) NMesh_FromPyObject( py_data, NULL ); + type = OB_MESH; + if( !data ) /* NULL means there is already an error */ + return NULL; + } else if( BPy_Mesh_Check( py_data ) ) { + data = ( void * ) Mesh_FromPyObject( py_data, NULL ); + type = OB_MESH; + } else if( BPy_Lattice_Check( py_data ) ) { + data = ( void * ) Lattice_FromPyObject( py_data ); + type = OB_LATTICE; + } else if( BPy_Metaball_Check( py_data ) ) { + data = ( void * ) Metaball_FromPyObject( py_data ); + type = OB_MBALL; + } else if( BPy_Text3d_Check( py_data ) ) { + data = ( void * ) Text3d_FromPyObject( py_data ); + type = OB_FONT; + } else if( ( desc = PyString_AsString( (PyObject *)py_data ) ) != NULL ) { + if( !strcmp( desc, "Empty" ) ) { + type = OB_EMPTY; + data = NULL; + } else + goto typeError; + } else { +typeError: + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected an object and optionally a string as arguments" ); + } + + if (!name) { + if (type == OB_EMPTY) + name = "Empty"; + else + name = ((ID *)data)->name + 2; + } + + object = add_only_object(type, name); + + if( data ) { + object->data = data; + id_us_plus((ID *)data); + } + + object->flag = SELECT; + + /* creates the curve for the text object */ + if (type == OB_FONT) + text_to_curve(object, 0); + + /* link to scene */ + base = MEM_callocN( sizeof( Base ), "pynewbase" ); + + if( !base ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't allocate new Base for object" ); + + base->object = object; /* link object to the new base */ + + if (scene == G.scene && G.vd) { + if (G.vd->localview) { + object->lay= G.vd->layact + G.vd->lay; + } else { + object->lay= G.vd->layact; + } + } else { + base->lay= object->lay = scene->lay & ((1<<20)-1); /* Layer, by default visible*/ + } + + base->lay= object->lay; + + base->flag = SELECT; + object->id.us = 1; /* we will exist once in this scene */ + + BLI_addhead( &(scene->base), base ); /* finally, link new base to scene */ + + /* make sure data and object materials are consistent */ + test_object_materials( (ID *)object->data ); + + /* so we can deal with vertex groups */ + if (type == OB_MESH) + ((BPy_Mesh *)py_data)->object = object; + + return Object_CreatePyObject( object ); + +} + +static PyObject *SceneObSeq_unlink( BPy_SceneObSeq * self, PyObject *args ) +{ + PyObject *pyobj; + Object *blen_ob; + Scene *scene; + Base *base= NULL; + + SCENE_DEL_CHECK_PY(self->bpyscene); + + if (self->mode != EXPP_OBSEQ_NORMAL) + return (EXPP_ReturnPyObjError( PyExc_TypeError, + "Cannot add new to objects.selection or objects.context!" )); + + if( !PyArg_ParseTuple( args, "O!", &Object_Type, &pyobj ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a python object as an argument" ) ); + + blen_ob = ( ( BPy_Object * ) pyobj )->object; + + scene = self->bpyscene->scene; + + /* is the object really in the scene? */ + base = object_in_scene( blen_ob, scene); + if( base ) { /* if it is, remove it */ + if (scene->basact==base) + scene->basact= NULL; /* in case the object was selected */ + free_and_unlink_base_from_scene(scene, base); + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; +} + +PyObject *SceneObSeq_getActive(BPy_SceneObSeq *self) +{ + Base *base; + SCENE_DEL_CHECK_PY(self->bpyscene); + + if (self->mode!=EXPP_OBSEQ_NORMAL) + return (EXPP_ReturnPyObjError( PyExc_TypeError, + "cannot get active from objects.selected or objects.context" )); + + base= self->bpyscene->scene->basact; + if (!base) + Py_RETURN_NONE; + + return Object_CreatePyObject( base->object ); +} + +static int SceneObSeq_setActive(BPy_SceneObSeq *self, PyObject *value) +{ + Base *base; + + SCENE_DEL_CHECK_INT(self->bpyscene); + + if (self->mode!=EXPP_OBSEQ_NORMAL) + return (EXPP_ReturnIntError( PyExc_TypeError, + "cannot set active from objects.selected or objects.context" )); + + if (value==Py_None) { + self->bpyscene->scene->basact= NULL; + return 0; + } + + if (!BPy_Object_Check(value)) + return (EXPP_ReturnIntError( PyExc_ValueError, + "Object or None types can only be assigned to active!" )); + + base = object_in_scene( ((BPy_Object *)value)->object, self->bpyscene->scene ); + + if (!base) + return (EXPP_ReturnIntError( PyExc_ValueError, + "cannot assign an active object outside the scene." )); + + self->bpyscene->scene->basact= base; + return 0; +} + +PyObject *SceneObSeq_getCamera(BPy_SceneObSeq *self) +{ + SCENE_DEL_CHECK_PY(self->bpyscene); + + if (self->mode!=EXPP_OBSEQ_NORMAL) + return (EXPP_ReturnPyObjError( PyExc_TypeError, + "cannot get camera from objects.selected or objects.context" )); + + return Object_CreatePyObject( self->bpyscene->scene->camera ); +} + +static int SceneObSeq_setCamera(BPy_SceneObSeq *self, PyObject *value) +{ + int ret; + + SCENE_DEL_CHECK_INT(self->bpyscene); + if (self->mode!=EXPP_OBSEQ_NORMAL) + return EXPP_ReturnIntError( PyExc_TypeError, + "cannot set camera from objects.selected or objects.context" ); + + ret = GenericLib_assignData(value, (void **) &self->bpyscene->scene->camera, 0, 0, ID_OB, 0); + + /* if this is the current scene, update its window now */ + if( ret == 0 && !G.background && self->bpyscene->scene == G.scene ) /* Traced a crash to redrawing while in background mode -Campbell */ + copy_view3d_lock( REDRAW ); + +/* XXX copy_view3d_lock(REDRAW) prints "bad call to addqueue: 0 (18, 1)". + * The same happens in bpython. */ + + return ret; +} + + +static struct PyMethodDef BPy_SceneObSeq_methods[] = { + {"link", (PyCFunction)SceneObSeq_link, METH_VARARGS, + "link object to this scene"}, + {"new", (PyCFunction)SceneObSeq_new, METH_VARARGS, + "Create a new object in this scene from the obdata given and return a new object"}, + {"unlink", (PyCFunction)SceneObSeq_unlink, METH_VARARGS, + "unlinks the object from the scene"}, + {NULL, NULL, 0, NULL} +}; + +/************************************************************************ + * + * Python SceneObSeq_Type standard operations + * + ************************************************************************/ + +static void SceneObSeq_dealloc( BPy_SceneObSeq * self ) +{ + Py_DECREF(self->bpyscene); + PyObject_DEL( self ); +} + +static int SceneObSeq_compare( BPy_SceneObSeq * a, BPy_SceneObSeq * b ) +{ + return ( a->bpyscene->scene == b->bpyscene->scene && a->mode == b->mode) ? 0 : -1; +} + +/* + * repr function + * callback functions building meaninful string to representations + */ +static PyObject *SceneObSeq_repr( BPy_SceneObSeq * self ) +{ + if( !(self->bpyscene->scene) ) + return PyString_FromFormat( "[Scene ObjectSeq Removed]" ); + else if (self->mode==EXPP_OBSEQ_SELECTED) + return PyString_FromFormat( "[Scene ObjectSeq Selected \"%s\"]", + self->bpyscene->scene->id.name + 2 ); + else if (self->mode==EXPP_OBSEQ_CONTEXT) + return PyString_FromFormat( "[Scene ObjectSeq Context \"%s\"]", + self->bpyscene->scene->id.name + 2 ); + + /*self->mode==0*/ + return PyString_FromFormat( "[Scene ObjectSeq \"%s\"]", + self->bpyscene->scene->id.name + 2 ); +} + +static PyGetSetDef SceneObSeq_getseters[] = { + {"selected", + (getter)SceneObSeq_getObjects, (setter)SceneObSeq_setObjects, + "sequence of selected objects", + (void *)EXPP_OBSEQ_SELECTED}, + {"context", + (getter)SceneObSeq_getObjects, (setter)SceneObSeq_setObjects, + "sequence of user context objects", + (void *)EXPP_OBSEQ_CONTEXT}, + {"active", + (getter)SceneObSeq_getActive, (setter)SceneObSeq_setActive, + "active object", + NULL}, + {"camera", + (getter)SceneObSeq_getCamera, (setter)SceneObSeq_setCamera, + "camera object", + NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/*****************************************************************************/ +/* Python SceneObSeq_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject SceneObSeq_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender SceneObSeq", /* char *tp_name; */ + sizeof( BPy_SceneObSeq ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + ( destructor ) SceneObSeq_dealloc,/* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) SceneObSeq_compare, /* cmpfunc tp_compare; */ + ( reprfunc ) SceneObSeq_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + &SceneObSeq_as_sequence, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + ( getiterfunc) SceneObSeq_getIter, /* getiterfunc tp_iter; */ + ( iternextfunc ) SceneObSeq_nextIter, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_SceneObSeq_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + SceneObSeq_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; diff --git a/source/blender/python/api2_2x/Scene.h b/source/blender/python/api2_2x/Scene.h new file mode 100644 index 00000000000..e6e509159d5 --- /dev/null +++ b/source/blender/python/api2_2x/Scene.h @@ -0,0 +1,70 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_SCENE_H +#define EXPP_SCENE_H + +#include +#include "DNA_scene_types.h" + +/* The Scene PyType Object defined in Scene.c */ +extern PyTypeObject Scene_Type; +extern PyTypeObject SceneObSeq_Type; + +#define BPy_Scene_Check(v) \ + ((v)->ob_type == &Scene_Type) +#define BPy_SceneObSeq_Check(v) \ + ((v)->ob_type == &SceneObSeq_Type) + +/*---------------------------Python BPy_Scene structure definition----------*/ +typedef struct { + PyObject_HEAD + Scene * scene; /* libdata must be second */ +} BPy_Scene; +/*---------------------------Python BPy_Scene visible prototypes-----------*/ +/* Python Scene_Type helper functions needed by Blender (the Init function) and Object modules. */ + + +/* Scene object sequence, iterate on the scene object listbase*/ +typedef struct { + PyObject_VAR_HEAD /* required python macro */ + BPy_Scene *bpyscene; /* link to the python scene so we can know if its been removed */ + Base *iter; /* so we can iterate over the objects */ + int mode; /*0:all objects, 1:selected objects, 2:user context*/ +} BPy_SceneObSeq; + + +PyObject *Scene_Init( void ); +PyObject *Scene_CreatePyObject( Scene * scene ); +/*Scene *Scene_FromPyObject( PyObject * pyobj );*/ /* not used yet */ + +#endif /* EXPP_SCENE_H */ diff --git a/source/blender/python/api2_2x/Sound.c b/source/blender/python/api2_2x/Sound.c new file mode 100644 index 00000000000..6e20e4c3ee5 --- /dev/null +++ b/source/blender/python/api2_2x/Sound.c @@ -0,0 +1,607 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Chris Keith + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#include "Sound.h" /*This must come first*/ + +#include "BKE_global.h" +#include "BKE_main.h" +#include "BLI_blenlib.h" +#include "BKE_sound.h" +#include "BKE_library.h" +#include "BIF_editsound.h" +#include "BKE_packedFile.h" +#include "mydevice.h" /* redraw defines */ +#include "gen_utils.h" +#include "gen_library.h" +#include "DNA_space_types.h" /* for FILE_MAXDIR only */ + +/*****************************************************************************/ +/* Python BPy_Sound defaults: */ +/*****************************************************************************/ + +#define EXPP_SND_volume_MIN 0.0 +#define EXPP_SND_volume_MAX 1.0 +#define EXPP_SND_pitch_MIN -12.0 +#define EXPP_SND_pitch_MAX 12.0 +#define EXPP_SND_attenuation_MIN 0.0 +#define EXPP_SND_attenuation_MAX 5.0 + +/*****************************************************************************/ +/* Python API function prototypes for the Sound module. */ +/*****************************************************************************/ +static PyObject *M_Sound_Get( PyObject * self, PyObject * args ); +static PyObject *M_Sound_Load( PyObject * self, PyObject * value ); + +/************************************************************************/ +/* The following string definitions are used for documentation strings. */ +/* In Python these will be written to the console when doing a */ +/* Blender.Sound.__doc__ */ +/************************************************************************/ +static char M_Sound_doc[] = "The Blender Sound module\n\n"; + +static char M_Sound_Get_doc[] = + "(name) - return the sound with the name 'name', \ +returns None if not found.\n If 'name' is not specified, \ +it returns a list of all sounds in the\ncurrent scene."; + +static char M_Sound_Load_doc[] = + "(filename) - return sound from file filename as a Sound Object,\n\ +returns None if not found."; + +/*****************************************************************************/ +/* Python method structure definition for Blender.Sound module: */ +/*****************************************************************************/ +struct PyMethodDef M_Sound_methods[] = { + {"Get", M_Sound_Get, METH_VARARGS, M_Sound_Get_doc}, + {"Load", M_Sound_Load, METH_O, M_Sound_Load_doc}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python Sound_Type callback function prototypes: */ +/*****************************************************************************/ +static int Sound_compare( BPy_Sound * a, BPy_Sound * b ); +static PyObject *Sound_repr( BPy_Sound * self ); + +#define SOUND_FLOAT_METHODS(funcname, varname) \ +static PyObject *Sound_get ## funcname(BPy_Sound *self) { \ + return PyFloat_FromDouble(self->sound->varname); \ +} \ +static PyObject *Sound_set ## funcname(BPy_Sound *self, PyObject *args) { \ + float f = 0; \ + if (!PyArg_ParseTuple(args, "f", &f)) \ + return (EXPP_ReturnPyObjError (PyExc_TypeError, \ + "expected float argument")); \ + self->sound->varname = EXPP_ClampFloat(f, \ + EXPP_SND_##varname##_MIN, EXPP_SND_##varname##_MAX); \ + Py_RETURN_NONE; \ +} + +#define SOUND_FLOAT_METHOD_FUNCS(varname) \ +{"get"#varname, (PyCFunction)Sound_get ## varname, METH_NOARGS, \ +"() - Return Sound object "#varname}, \ +{"set"#varname, (PyCFunction)Sound_set ## varname, METH_VARARGS, \ +"(float) - Change Sound object "#varname}, + + +/*****************************************************************************/ +/* Python BPy_Sound methods declarations: */ +/*****************************************************************************/ +static PyObject *Sound_getName( BPy_Sound * self ); +static PyObject *Sound_getFilename( BPy_Sound * self ); +static PyObject *Sound_setName( BPy_Sound * self, PyObject * args ); +static int Sound_setFilename( BPy_Sound * self, PyObject * args ); +static PyObject *Sound_oldsetFilename( BPy_Sound * self, PyObject * args ); +static PyObject *Sound_setCurrent( BPy_Sound * self ); +static PyObject *Sound_play( BPy_Sound * self ); +static PyObject *Sound_unpack( BPy_Sound * self, PyObject * args); +static PyObject *Sound_pack( BPy_Sound * self ); +/*static PyObject *Sound_reload ( BPy_Sound * self );*/ +SOUND_FLOAT_METHODS( Volume, volume ) +SOUND_FLOAT_METHODS( Attenuation, attenuation ) +SOUND_FLOAT_METHODS( Pitch, pitch ) +/* these can't be set via interface, removed for now */ +/* +SOUND_FLOAT_METHODS( Panning, panning ) +SOUND_FLOAT_METHODS( MinGain, min_gain ) +SOUND_FLOAT_METHODS( MaxGain, max_gain ) +SOUND_FLOAT_METHODS( Distance, distance ) +*/ + +/*****************************************************************************/ +/* Python BPy_Sound methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_Sound_methods[] = { + /* name, method, flags, doc */ + {"getName", ( PyCFunction ) Sound_getName, METH_NOARGS, + "() - Return Sound object name"}, + {"getFilename", ( PyCFunction ) Sound_getFilename, METH_NOARGS, + "() - Return Sound object filename"}, + {"setName", ( PyCFunction ) Sound_setName, METH_VARARGS, + "(name) - Set Sound object name"}, + {"setFilename", ( PyCFunction ) Sound_oldsetFilename, METH_VARARGS, + "(filename) - Set Sound object filename"}, + {"setCurrent", ( PyCFunction ) Sound_setCurrent, METH_NOARGS, + "() - make this the active sound in the sound buttons win (also redraws)"}, + {"play", ( PyCFunction ) Sound_play, METH_NOARGS, + "() - play this sound"}, + {"unpack", ( PyCFunction ) Sound_unpack, METH_VARARGS, + "(int) - Unpack sound. Uses one of the values defined in Blender.UnpackModes."}, + {"pack", ( PyCFunction ) Sound_pack, METH_NOARGS, + "() Pack the sound"}, +/* + {"reload", ( PyCFunction ) Sound_setCurrent, METH_NOARGS, + "() - reload this Sound object's sample.\n\ + This is only useful if the original sound file has changed."}, +*/ + SOUND_FLOAT_METHOD_FUNCS( Volume ) + SOUND_FLOAT_METHOD_FUNCS( Attenuation ) + SOUND_FLOAT_METHOD_FUNCS( Pitch ) + /* + SOUND_FLOAT_METHOD_FUNCS( Panning ) + SOUND_FLOAT_METHOD_FUNCS( MinGain ) + SOUND_FLOAT_METHOD_FUNCS( MaxGain ) + SOUND_FLOAT_METHOD_FUNCS( Distance ) + */ + {NULL, NULL, 0, NULL} +}; + +/* NOTE: these were copied and modified from image.h. To Be Done TBD: + * macro-ize them, or C++ templates eventually? + */ +/****************************************************************************/ +/* Function: M_Sound_Get */ +/* Python equivalent: Blender.Sound.Get */ +/* Description: Receives a string and returns the Sound object */ +/* whose name matches the string. If no argument is */ +/* passed in, a list of all Sound names in the */ +/* current scene is returned. */ +/****************************************************************************/ +static PyObject *M_Sound_Get( PyObject * self, PyObject * args ) +{ + char *name = NULL; + bSound *snd_iter; + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument (or nothing)" ) ); + + snd_iter = G.main->sound.first; + + if( name ) { /* (name) - Search Sound by name */ + + BPy_Sound *wanted_Sound = NULL; + + while( ( snd_iter ) && ( wanted_Sound == NULL ) ) { + if( strcmp( name, snd_iter->id.name + 2 ) == 0 ) { + wanted_Sound = + ( BPy_Sound * ) + PyObject_NEW( BPy_Sound, &Sound_Type ); + if( wanted_Sound ) { + wanted_Sound->sound = snd_iter; + break; + } + } + snd_iter = snd_iter->id.next; + } + + if( wanted_Sound == NULL ) { /* Requested Sound doesn't exist */ + char error_msg[64]; + PyOS_snprintf( error_msg, sizeof( error_msg ), + "Sound \"%s\" not found", name ); + return ( EXPP_ReturnPyObjError + ( PyExc_NameError, error_msg ) ); + } + + return ( PyObject * ) wanted_Sound; + } + + else { /* () - return a list of all Sounds in the scene */ + int index = 0; + PyObject *snd_list, *pyobj; + + snd_list = PyList_New( BLI_countlist( &( G.main->sound ) ) ); + + if( snd_list == NULL ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyList" ) ); + + while( snd_iter ) { + pyobj = Sound_CreatePyObject( snd_iter ); + + if( !pyobj ) { + Py_DECREF(snd_list); + return ( EXPP_ReturnPyObjError + ( PyExc_MemoryError, + "couldn't create PyObject" ) ); + } + PyList_SET_ITEM( snd_list, index, pyobj ); + + snd_iter = snd_iter->id.next; + index++; + } + + return ( snd_list ); + } +} + +/*****************************************************************************/ +/* Function: M_Sound_Load */ +/* Python equivalent: Blender.Sound.Load */ +/* Description: Receives a string and returns the Sound object */ +/* whose filename matches the string. */ +/*****************************************************************************/ +static PyObject *M_Sound_Load( PyObject * self, PyObject * value ) +{ + char *fname = PyString_AsString(value); + bSound *snd_ptr; + BPy_Sound *snd; + + if( !fname ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ) ); + + snd = ( BPy_Sound * ) PyObject_NEW( BPy_Sound, &Sound_Type ); + + if( !snd ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyObject Sound_Type" ) ); + + snd_ptr = sound_new_sound( fname ); + + if( snd_ptr ) { + if( G.ssound ) { + G.ssound->sound = snd_ptr; + } + } + + if( !snd_ptr ) + return ( EXPP_ReturnPyObjError( PyExc_IOError, + "not a valid sound sample" ) ); + + snd->sound = snd_ptr; + + return ( PyObject * ) snd; +} + +/*****************************************************************************/ +/* Function: Sound_Init */ +/*****************************************************************************/ +PyObject *Sound_Init( void ) +{ + PyObject *submodule; + + if( PyType_Ready( &Sound_Type ) < 0 ) + return NULL; + + submodule = + Py_InitModule3( "Blender.Sound", M_Sound_methods, + M_Sound_doc ); + + return ( submodule ); +} + +/************************/ +/*** The Sound PyType ***/ +/************************/ + + +/*****************************************************************************/ +/* Function: Sound_CreatePyObject */ +/* Description: This function will create a new BPy_Sound from an existing */ +/* Blender Sound structure. */ +/*****************************************************************************/ +PyObject *Sound_CreatePyObject( bSound * snd ) +{ + BPy_Sound *py_snd; + + py_snd = ( BPy_Sound * ) PyObject_NEW( BPy_Sound, &Sound_Type ); + + if( !py_snd ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create BPy_Sound object" ); + + py_snd->sound = snd; + + return ( PyObject * ) py_snd; +} + +/*****************************************************************************/ +/* Function: Sound_FromPyObject */ +/* Description: Returns the Blender Sound associated with this object */ +/*****************************************************************************/ +bSound *Sound_FromPyObject( PyObject * pyobj ) +{ + return ( ( BPy_Sound * ) pyobj )->sound; +} + +/*****************************************************************************/ +/* Python BPy_Sound methods: */ +/*****************************************************************************/ +static PyObject *Sound_getName( BPy_Sound * self ) +{ + return PyString_FromString( self->sound->id.name + 2 ); +} + +static PyObject *Sound_getFilename( BPy_Sound * self ) +{ + return PyString_FromString( self->sound->name ); +} + +static PyObject *Sound_getPacked( BPy_Sound * self ) +{ + if (!sound_sample_is_null(self->sound)) { + bSample *sample = sound_find_sample(self->sound); + if (sample->packedfile) + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; +} + +static PyObject *Sound_setName( BPy_Sound * self, PyObject * args ) +{ + char *name; + + if( !PyArg_ParseTuple( args, "s", &name ) ) { + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected a String as argument" ) ); + } + + rename_id( &self->sound->id, name ); + + Py_RETURN_NONE; +} + +static int Sound_setFilename( BPy_Sound * self, PyObject * value ) +{ + char *name; + + /* max len is FILE_MAXDIR = 160 chars like in DNA_image_types.h */ + name = PyString_AsString(value); + if (!name || strlen(name) > FILE_MAXDIR) + return ( EXPP_ReturnIntError( PyExc_ValueError, + "string argument is limited to 160 chars at most" ) ); + + strcpy( self->sound->name, name ); + return 0; +} + +static PyObject *Sound_oldsetFilename( BPy_Sound * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)Sound_setFilename ); +} + + +static PyObject *Sound_play( BPy_Sound * self ) +{ + sound_play_sound( self->sound ); + + Py_RETURN_NONE; +} + +static PyObject *Sound_setCurrent( BPy_Sound * self ) +{ + bSound *snd_ptr = self->sound; + + if( snd_ptr ) { + if( G.ssound ) { + G.ssound->sound = snd_ptr; + } + } + + EXPP_allqueue( REDRAWSOUND, 0 ); + EXPP_allqueue( REDRAWBUTSLOGIC, 0 ); + + Py_RETURN_NONE; +} + +/* unpack sound */ + +static PyObject *Sound_unpack( BPy_Sound * self, PyObject * args ) +{ + bSound *sound = self->sound; + int mode; + if( !PyArg_ParseTuple( args, "i", &mode ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected an integer from Blender.UnpackModes" ); + + if (!sound_sample_is_null(sound)) { + bSample *sample = sound_find_sample(sound); + if (sample->packedfile) { + if (unpackSample(sample, mode) == RET_ERROR) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "error unpacking sound"); + } + } else { + return EXPP_ReturnPyObjError( PyExc_RuntimeError, "sound has no samples" ); + } + Py_RETURN_NONE; +} + +/* pack sound */ + +static PyObject *Sound_pack( BPy_Sound * self ) +{ + bSound *sound = self->sound; + if (!sound_sample_is_null(sound)) + { + bSample *sample = sound_find_sample(sound); + if (sample->packedfile ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "sound alredy packed" ); + sound_set_packedfile(sample, newPackedFile(sample->name)); + } + else + { + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "sound has no samples" ); + } + Py_RETURN_NONE; +} + +/* +static PyObject *Sound_reload( BPy_Sound * self) +{ + sound_free_sample(); + + if (sound->snd_sound) { + SND_RemoveSound(ghSoundScene, sound->snd_sound); + sound->snd_sound = NULL; + } + + Py_RETURN_NONE; +} +*/ + + + +/*****************************************************************************/ +/* Function: Sound_compare */ +/* Description: This is a callback function for the BPy_Sound type. It */ +/* compares two Sound_Type objects. Only the "==" and "!=" */ +/* comparisons are meaninful. Returns 0 for equality and -1 if */ +/* they don't point to the same Blender Sound struct. */ +/* In Python it becomes 1 if they are equal, 0 otherwise. */ +/*****************************************************************************/ +static int Sound_compare( BPy_Sound * a, BPy_Sound * b ) +{ + return ( a->sound == b->sound ) ? 0 : -1; +} + +/*****************************************************************************/ +/* Function: Sound_repr */ +/* Description: This is a callback function for the BPy_Sound type. It */ +/* builds a meaninful string to represent Sound objects. */ +/*****************************************************************************/ +static PyObject *Sound_repr( BPy_Sound * self ) +{ + return PyString_FromFormat( "[Sound \"%s\"]", + self->sound->id.name + 2 ); +} + +/*****************************************************************************/ +/* Python attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef BPy_Sound_getseters[] = { + GENERIC_LIB_GETSETATTR, + {"filename", (getter)Sound_getFilename, (setter)Sound_setFilename, + "text filename", NULL}, + {"packed", (getter)Sound_getPacked, (setter)NULL, + "text filename", NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + + + +/*****************************************************************************/ +/* Python Sound_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject Sound_Type = { + PyObject_HEAD_INIT( NULL ) + 0, /* ob_size */ + "Blender Sound", /* tp_name */ + sizeof( BPy_Sound ), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + NULL, /* tp_dealloc */ + 0, /* tp_print */ + NULL, /* tp_getattr */ + NULL, /* tp_setattr */ + ( cmpfunc ) Sound_compare, /* tp_compare */ + ( reprfunc ) Sound_repr, /* tp_repr */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_Sound_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_Sound_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + + diff --git a/source/blender/python/api2_2x/Sound.h b/source/blender/python/api2_2x/Sound.h new file mode 100644 index 00000000000..7a84bbd901d --- /dev/null +++ b/source/blender/python/api2_2x/Sound.h @@ -0,0 +1,57 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Chris Keith + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_SOUND_H +#define EXPP_SOUND_H + +#include +#include "DNA_sound_types.h" + +#define BPy_Sound_Check(v) ((v)->ob_type == &Sound_Type) +extern PyTypeObject Sound_Type; + +/*****************************************************************************/ +/* Python BPy_Sound structure definition */ +/*****************************************************************************/ +typedef struct { + PyObject_HEAD + bSound * sound; +} BPy_Sound; + +/*****************************************************************************/ +/* Module Blender.Sound - public functions */ +/*****************************************************************************/ +PyObject *Sound_Init( void ); +PyObject *Sound_CreatePyObject( bSound * sound ); +bSound *Sound_FromPyObject( PyObject * pyobj ); + +#endif /* EXPP_SOUND_H */ diff --git a/source/blender/python/api2_2x/SurfNurb.c b/source/blender/python/api2_2x/SurfNurb.c new file mode 100644 index 00000000000..3499ec09936 --- /dev/null +++ b/source/blender/python/api2_2x/SurfNurb.c @@ -0,0 +1,857 @@ +/* + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Stephen Swaney + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "SurfNurb.h" /*This must come first */ + +#include "BKE_curve.h" +#include "BDR_editcurve.h" /* for convertspline */ +#include "MEM_guardedalloc.h" +#include "gen_utils.h" +#include "gen_library.h" +#include "BezTriple.h" + +/* + * forward declarations go here + */ + +static int SurfNurb_setPoint( BPy_SurfNurb * self, int index, PyObject * ob ); +static int SurfNurb_length( PyInstanceObject * inst ); +static PyObject *SurfNurb_getIter( BPy_SurfNurb * self ); +static PyObject *SurfNurb_iterNext( BPy_SurfNurb * self ); +PyObject *SurfNurb_append( BPy_SurfNurb * self, PyObject * args ); + +char M_SurfNurb_doc[] = "SurfNurb"; + +/* + table of module methods + these are the equivalent of class or static methods. + you do not need an object instance to call one. +*/ + +static PyMethodDef M_SurfNurb_methods[] = { +/* name, method, flags, doc_string */ +/* {"Get", (PyCFunction) M_SurfNurb_method, METH_NOARGS, " () - doc string"}, */ +/* {"method", (PyCFunction) M_SurfNurb_method, METH_NOARGS, " () - doc string"}, */ + + {NULL, NULL, 0, NULL} +}; + +/* + * method table + * table of instance methods + * these methods are invoked on an instance of the type. +*/ + +static PyMethodDef BPy_SurfNurb_methods[] = { +# if 0 + {"append", ( PyCFunction ) SurfNurb_append, METH_VARARGS, + "( point ) - add a new point. arg is BezTriple or list of x,y,z,w floats"}, +#endif + {NULL, NULL, 0, NULL} +}; + +/* + * SurfNurb_appendPointToNurb + * this is a non-bpy utility func to add a point to a given nurb. + * notice the first arg is Nurb*. + */ + +#if 0 +static PyObject *SurfNurb_appendPointToNurb( Nurb * nurb, PyObject * args ) +{ + + int i; + int size; + PyObject *pyOb; + int npoints = nurb->pntsu; + + /* + do we have a list of four floats or a BezTriple? + */ + if( !PyArg_ParseTuple( args, "O", &pyOb )) + return EXPP_ReturnPyObjError + ( PyExc_RuntimeError, + "Internal error parsing arguments" ); + + + + /* if curve is empty, adjust type depending on input type */ + if (nurb->bezt==NULL && nurb->bp==NULL) { + if (BPy_BezTriple_Check( pyOb )) + nurb->type |= CU_BEZIER; + else if (PySequence_Check( pyOb )) + nurb->type |= CU_NURBS; + else + return( EXPP_ReturnPyObjError( PyExc_TypeError, + "Expected a BezTriple or a Sequence of 4 (or 5) floats" ) ); + } + + + + if ((nurb->type & 7)==CU_BEZIER) { + BezTriple *tmp; + + if( !BPy_BezTriple_Check( pyOb ) ) + return( EXPP_ReturnPyObjError( PyExc_TypeError, + "Expected a BezTriple\n" ) ); + +/* printf("\ndbg: got a BezTriple\n"); */ + tmp = nurb->bezt; /* save old points */ + nurb->bezt = + ( BezTriple * ) MEM_mallocN( sizeof( BezTriple ) * + ( npoints + 1 ), + "SurfNurb_append2" ); + + if( !nurb->bezt ) + return ( EXPP_ReturnPyObjError + ( PyExc_MemoryError, "allocation failed" ) ); + + /* copy old points to new */ + if( tmp ) { + memmove( nurb->bezt, tmp, sizeof( BezTriple ) * npoints ); + MEM_freeN( tmp ); + } + + nurb->pntsu++; + /* add new point to end of list */ + memcpy( nurb->bezt + npoints, + BezTriple_FromPyObject( pyOb ), sizeof( BezTriple ) ); + + } + else if( PySequence_Check( pyOb ) ) { + size = PySequence_Size( pyOb ); +/* printf("\ndbg: got a sequence of size %d\n", size ); */ + if( size == 4 || size == 5 ) { + BPoint *tmp; + + tmp = nurb->bp; /* save old pts */ + + nurb->bp = + ( BPoint * ) MEM_mallocN( sizeof( BPoint ) * + ( npoints + 1 ), + "SurfNurb_append1" ); + if( !nurb->bp ) + return ( EXPP_ReturnPyObjError + ( PyExc_MemoryError, + "allocation failed" ) ); + + memmove( nurb->bp, tmp, sizeof( BPoint ) * npoints ); + if( tmp ) + MEM_freeN( tmp ); + + ++nurb->pntsu; + /* initialize new BPoint from old */ + memcpy( nurb->bp + npoints, nurb->bp, + sizeof( BPoint ) ); + + for( i = 0; i < 4; ++i ) { + PyObject *item = PySequence_GetItem( pyOb, i ); + + if (item == NULL) + return NULL; + + + nurb->bp[npoints].vec[i] = ( float ) PyFloat_AsDouble( item ); + Py_DECREF( item ); + } + + if (size == 5) { + PyObject *item = PySequence_GetItem( pyOb, i ); + + if (item == NULL) + return NULL; + + nurb->bp[npoints].alfa = ( float ) PyFloat_AsDouble( item ); + Py_DECREF( item ); + } + else { + nurb->bp[npoints].alfa = 0.0f; + } + + makeknots( nurb, 1, nurb->flagu >> 1 ); + + } else { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a sequence of 4 or 5 floats" ); + } + + } else { + /* bail with error */ + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a sequence of 4 or 5 floats" ); + + } + + return ( EXPP_incr_ret( Py_None ) ); +} + +/* + * SurfNurb_append( point ) + * append a new point to a nurb curve. + * arg is BezTriple or list of xyzw floats + */ + +PyObject *SurfNurb_append( BPy_SurfNurb * self, PyObject * args ) +{ + Nurb *nurb = self->nurb; + + return SurfNurb_appendPointToNurb( nurb, args ); +} +#endif + +#if 0 +/* + * SurfNurb_getMatIndex + * + * returns index into material list + */ + +static PyObject *SurfNurb_getMatIndex( BPy_SurfNurb * self ) +{ + return PyInt_FromLong( ( long ) self->nurb->mat_nr ); +} + +/* + * SurfNurb_setMatIndex + * + * set index into material list + */ + +static int SurfNurb_setMatIndex( BPy_SurfNurb * self, PyObject * args ) +{ + args = PyNumber_Int( args ); + + if( !args ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected integer argument" ); + + /* fixme: some range checking would be nice! */ + /* can't do range checking without knowing the "parent" curve! */ + self->nurb->mat_nr = ( short )PyInt_AS_LONG( args ); + Py_DECREF( args ); + + return 0; +} +#endif + +/* + * SurfNurb_getPointsU + * + * returns number of control points in U direction + */ + +static PyObject *SurfNurb_getPointsU( BPy_SurfNurb * self ) +{ + return PyInt_FromLong( ( long ) self->nurb->pntsu ); +} + +/* + * SurfNurb_getPointsV + * + * returns number of control points in V direction + */ + +static PyObject *SurfNurb_getPointsV( BPy_SurfNurb * self ) +{ + return PyInt_FromLong( ( long ) self->nurb->pntsv ); +} + +/* + * SurfNurb_getFlagU + * + * returns curve's flagu + */ + +static PyObject *SurfNurb_getFlagU( BPy_SurfNurb * self ) +{ + return PyInt_FromLong( ( long ) (self->nurb->flagu >> 1) ); +} + +/* + * SurfNurb_setFlagU + * + * set curve's flagu and recalculate the knots + * + * Possible values: 0 - uniform, 2 - endpoints, 4 - bezier + * bit 0 controls CU_CYCLIC + */ + +static int SurfNurb_setFlagU( BPy_SurfNurb * self, PyObject * args ) +{ + int flagu; + + args = PyNumber_Int( args ); + if( !args ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected integer argument" ); + + flagu = ( int )PyInt_AS_LONG( args ); + Py_DECREF( args ); + + if( flagu < 0 || flagu > 2 ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "expected integer argument in range [0,2]" ); + + flagu = (flagu << 1) | (self->nurb->flagu & CU_CYCLIC); + if( self->nurb->flagu != flagu ) { + self->nurb->flagu = (short)flagu; + makeknots( self->nurb, 1, self->nurb->flagu >> 1 ); + } + + return 0; +} + +/* + * SurfNurb_getFlagV + * + * returns curve's flagu + */ + +static PyObject *SurfNurb_getFlagV( BPy_SurfNurb * self ) +{ + return PyInt_FromLong( ( long ) (self->nurb->flagv >> 1) ); +} + +/* + * SurfNurb_setFlagV + * + * set curve's flagu and recalculate the knots + * + * Possible values: 0 - uniform, 1 - endpoints, 2 - bezier + */ + +static int SurfNurb_setFlagV( BPy_SurfNurb * self, PyObject * args ) +{ + int flagv; + + args = PyNumber_Int( args ); + if( !args ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected integer argument" ); + + flagv = ( int )PyInt_AS_LONG( args ); + Py_DECREF( args ); + + if( flagv < 0 || flagv > 2 ) + return EXPP_ReturnIntError( PyExc_AttributeError, + "expected integer argument in range [0,2]" ); + + flagv = (flagv << 1) | (self->nurb->flagv & CU_CYCLIC); + if( self->nurb->flagv != flagv ) { + self->nurb->flagv = (short)flagv; + makeknots( self->nurb, 2, self->nurb->flagv >> 1 ); + } + + return 0; +} + +/* + * SurfNurb_getOrder + * + * returns curve's order + */ + +static PyObject *SurfNurb_getOrderU( BPy_SurfNurb * self ) +{ + return PyInt_FromLong( ( long ) self->nurb->orderu ); +} + +static int SurfNurb_setOrderU( BPy_SurfNurb * self, PyObject * args ) +{ + int order; + + args = PyNumber_Int( args ); + if( !args ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected integer argument" ); + + order = ( int )PyInt_AS_LONG( args ); + Py_DECREF( args ); + + if( order < 2 ) order = 2; + else if( order > 6 ) order = 6; + + if( self->nurb->pntsu < order ) + order = self->nurb->pntsu; + + self->nurb->orderu = (short)order; + makeknots( self->nurb, 1, self->nurb->flagu >> 1 ); + + return 0; +} + +static PyObject *SurfNurb_getOrderV( BPy_SurfNurb * self ) +{ + return PyInt_FromLong( ( long ) self->nurb->orderv ); +} + +static int SurfNurb_setOrderV( BPy_SurfNurb * self, PyObject * args ) +{ + int order; + + args = PyNumber_Int( args ); + if( !args ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected integer argument" ); + + order = ( int )PyInt_AS_LONG( args ); + Py_DECREF( args ); + + if( order < 2 ) order = 2; + else if( order > 6 ) order = 6; + + if( self->nurb->pntsv < order ) + order = self->nurb->pntsv; + + self->nurb->orderv = (short)order; + makeknots( self->nurb, 2, self->nurb->flagv >> 1 ); + return 0; +} + +/* + * SurfNurb_getCyclic() + * test whether surface is cyclic (closed) or not (open) + */ + +static PyObject *SurfNurb_getCyclicU( BPy_SurfNurb * self ) +{ + if( self->nurb->flagu & CU_CYCLIC ) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +static PyObject *SurfNurb_getCyclicV( BPy_SurfNurb * self ) +{ + if( self->nurb->flagv & CU_CYCLIC ) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +static int SurfNurb_setCyclicU( BPy_SurfNurb * self, PyObject * value ) +{ + int param = PyObject_IsTrue( value ); + if( param == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected True/False or 0/1" ); + + if( param ) + self->nurb->flagu |= CU_CYCLIC; + else + self->nurb->flagu &= ~CU_CYCLIC; + makeknots( self->nurb, 1, self->nurb->flagu >> 1 ); + return 0; +} + +static int SurfNurb_setCyclicV( BPy_SurfNurb * self, PyObject * value ) +{ + int param = PyObject_IsTrue( value ); + if( param == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected True/False or 0/1" ); + + if( param ) + self->nurb->flagv |= CU_CYCLIC; + else + self->nurb->flagv &= ~CU_CYCLIC; + makeknots( self->nurb, 2, self->nurb->flagu >> 1 ); + return 0; +} + + +/* + * SurfNurb_getIter + * + * create an iterator for our SurfNurb. + * this iterator returns the points for this SurfNurb. + */ + +static PyObject *SurfNurb_getIter( BPy_SurfNurb * self ) +{ + self->bp = self->nurb->bp; + self->bezt = self->nurb->bezt; + self->nextPoint = 0; + + Py_INCREF( self ); + return ( PyObject * ) self; +} + +static PyObject *SurfNurb_iterNext( BPy_SurfNurb * self ) +{ + Nurb *pnurb = self->nurb; + int npoints = pnurb->pntsu * pnurb->pntsv; + + if( self->bp && self->nextPoint < npoints ) + return SurfNurb_pointAtIndex( self->nurb, self->nextPoint++ ); + else + return EXPP_ReturnPyObjError( PyExc_StopIteration, + "iterator at end" ); +} + +/* + * SurfNurb_length + * returns the number of points in a Nurb + * this is a tp_as_sequence method, not a regular instance method. + */ + +static int SurfNurb_length( PyInstanceObject * inst ) +{ + Nurb *nurb; + + if( BPy_SurfNurb_Check( ( PyObject * ) inst ) ) { + nurb = ( ( BPy_SurfNurb * ) inst )->nurb; + return (int)(nurb->pntsu * nurb->pntsu); + } + + return EXPP_ReturnIntError( PyExc_RuntimeError, + "arg is not a BPy_SurfNurb" ); +} + + +/* + * SurfNurb_getPoint + * returns the Nth point in a Nurb + * this is one of the tp_as_sequence methods, hence the int N argument. + * it is called via the [] operator, not as a usual instance method. + */ + +PyObject *SurfNurb_getPoint( BPy_SurfNurb * self, int index ) +{ + Nurb *myNurb; + + int npoints; + + /* for convenince */ + myNurb = self->nurb; + npoints = myNurb->pntsu * myNurb->pntsv; + + /* bail if no Nurbs in Curve */ + if( npoints == 0 ) + return ( EXPP_ReturnPyObjError( PyExc_IndexError, + "no points in this SurfNurb" ) ); + + /* check index limits */ + if( index >= npoints || index < 0 ) + return ( EXPP_ReturnPyObjError( PyExc_IndexError, + "index out of range" ) ); + + return SurfNurb_pointAtIndex( myNurb, index ); +} + +/* + * SurfNurb_setPoint + * modifies the Nth point in a Nurb + * this is one of the tp_as_sequence methods, hence the int N argument. + * it is called via the [] = operator, not as a usual instance method. + */ +static int SurfNurb_setPoint( BPy_SurfNurb * self, int index, PyObject * pyOb ) +{ + Nurb *nurb = self->nurb; + int size; + + /* check index limits */ + if( index < 0 || index >= nurb->pntsu * nurb->pntsv ) + return EXPP_ReturnIntError( PyExc_IndexError, + "array assignment index out of range\n" ); + + /* branch by curve type */ +#if 0 + if ((nurb->type & 7)==CU_BEZIER) { /* BEZIER */ + /* check parameter type */ + if( !BPy_BezTriple_Check( pyOb ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a BezTriple\n" ); + + /* copy bezier in array */ + memcpy( nurb->bezt + index, + BezTriple_FromPyObject( pyOb ), sizeof( BezTriple ) ); + + return 0; /* finished correctly */ + } + else +#endif + { /* NURBS or POLY */ + int i; + + /* check parameter type */ + if (!PySequence_Check( pyOb )) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a list of 4 (or optionaly 5 if the curve is 3D) floats\n" ); + + size = PySequence_Size( pyOb ); + + /* check sequence size */ + if( size != 4 && size != 5 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a list of 4 (or optionaly 5 if the curve is 3D) floats\n" ); + + /* copy x, y, z, w */ + for( i = 0; i < 4; ++i ) { + PyObject *item = PySequence_GetItem( pyOb, i ); + + if (item == NULL) + return -1; + + nurb->bp[index].vec[i] = ( float ) PyFloat_AsDouble( item ); + Py_DECREF( item ); + } + + if (size == 5) { /* set tilt, if present */ + PyObject *item = PySequence_GetItem( pyOb, i ); + + if (item == NULL) + return -1; + + nurb->bp[index].alfa = ( float ) PyFloat_AsDouble( item ); + Py_DECREF( item ); + } + else { /* if not, set default */ + nurb->bp[index].alfa = 0.0f; + } + + return 0; /* finished correctly */ + } +} + + +/* + * this is an internal routine. not callable directly from python + */ + +PyObject *SurfNurb_pointAtIndex( Nurb * nurb, int index ) +{ + PyObject *pyo; + + if( nurb->bp ) { /* we have a nurb curve */ + int i; + + /* add Tilt only if curve is 3D */ + if (nurb->flag & CU_3D) + pyo = PyList_New( 5 ); + else + pyo = PyList_New( 4 ); + + for( i = 0; i < 4; i++ ) { + PyList_SetItem( pyo, i, + PyFloat_FromDouble( nurb->bp[index]. + vec[i] ) ); + } + + /* add Tilt only if curve is 3D */ + if (nurb->flag & CU_3D) + PyList_SetItem( pyo, 4, PyFloat_FromDouble( nurb->bp[index].alfa ) ); + return pyo; + + } else /* something is horribly wrong */ + return EXPP_ReturnPyObjError( PyExc_SystemError, + "non-NURB surface found" ); +} + +/* + * methods for SurfNurb as sequence + */ + +static PySequenceMethods SurfNurb_as_sequence = { + ( inquiry ) SurfNurb_length, /* sq_length */ + ( binaryfunc ) 0, /* sq_concat */ + ( intargfunc ) 0, /* sq_repeat */ + ( intargfunc ) SurfNurb_getPoint, /* sq_item */ + ( intintargfunc ) 0, /* sq_slice */ + ( intobjargproc ) SurfNurb_setPoint, /* sq_ass_item */ + 0, /* sq_ass_slice */ + ( objobjproc ) 0, /* sq_contains */ + 0, + 0 +}; + +static PyGetSetDef BPy_SurfNurb_getseters[] = { +#if 0 + {"matIndex", + (getter)SurfNurb_getMatIndex, (setter)SurfNurb_setMatIndex, + "material index", NULL}, +#endif + {"pointsU", + (getter)SurfNurb_getPointsU, (setter)NULL, + "number of control points in U direction", NULL}, + {"pointsV", + (getter)SurfNurb_getPointsV, (setter)NULL, + "number of control points in V direction", NULL}, + {"flagU", + (getter)SurfNurb_getFlagU, (setter)SurfNurb_setFlagU, + "knot flag for U direction", NULL}, + {"flagV", + (getter)SurfNurb_getFlagV, (setter)SurfNurb_setFlagV, + "knot flag for V direction", NULL}, + {"cyclicU", + (getter)SurfNurb_getCyclicU, (setter)SurfNurb_setCyclicU, + "cyclic setting for U direction", NULL}, + {"cyclicV", + (getter)SurfNurb_getCyclicV, (setter)SurfNurb_setCyclicV, + "cyclic setting for V direction", NULL}, + {"orderU", + (getter)SurfNurb_getOrderU, (setter)SurfNurb_setOrderU, + "order setting for U direction", NULL}, + {"orderV", + (getter)SurfNurb_getOrderV, (setter)SurfNurb_setOrderV, + "order setting for V direction", NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/* + * compare + * in this case, we consider two SurfNurbs equal, if they point to the same + * blender data. +*/ +static int SurfNurb_compare( BPy_SurfNurb * a, BPy_SurfNurb * b ) +{ + return ( a->nurb == b->nurb ) ? 0 : -1; +} + +/* + * SurfNurb_repr + */ +static PyObject *SurfNurb_repr( BPy_SurfNurb * self ) +{ + return PyString_FromFormat( "[SurfNurb \"%d\"]", self->nurb->type ); +} + +/*****************************************************************************/ +/* Python SurfNurb_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject SurfNurb_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "SurfNurb", /* char *tp_name; */ + sizeof( BPy_SurfNurb ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) SurfNurb_compare, /* cmpfunc tp_compare; */ + ( reprfunc ) SurfNurb_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + &SurfNurb_as_sequence, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + ( getiterfunc ) SurfNurb_getIter, /* getiterfunc tp_iter; */ + ( iternextfunc ) SurfNurb_iterNext, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_SurfNurb_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_SurfNurb_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +/* + factory method to create a BPy_SurfNurb from a Blender Nurb +*/ + +PyObject *SurfNurb_CreatePyObject( Nurb * blen_nurb ) +{ + BPy_SurfNurb *pyNurb; + + pyNurb = ( BPy_SurfNurb * ) PyObject_NEW( BPy_SurfNurb, &SurfNurb_Type ); + + if( !pyNurb ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "could not create BPy_SurfNurb PyObject" ); + + pyNurb->nurb = blen_nurb; + return ( PyObject * ) pyNurb; +} + + +PyObject *SurfNurb_Init( void ) +{ + PyType_Ready( &SurfNurb_Type ); + return Py_InitModule3( "Blender.SurfNurb", M_SurfNurb_methods, + M_SurfNurb_doc ); +} + diff --git a/source/blender/python/api2_2x/SurfNurb.h b/source/blender/python/api2_2x/SurfNurb.h new file mode 100644 index 00000000000..0559d84cbaf --- /dev/null +++ b/source/blender/python/api2_2x/SurfNurb.h @@ -0,0 +1,68 @@ +/* + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Stephen Swaney + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef EXPP_SURFNURB_H +#define EXPP_SURFNURB_H + +#include +#include "DNA_curve_types.h" + +extern PyTypeObject SurfNurb_Type; + +#define BPy_SurfNurb_Check(v) ((v)->ob_type == &SurfNurb_Type) /* for type checking */ + +/* Python BPy_SurfNurb structure definition */ +typedef struct { + PyObject_HEAD + Nurb * nurb; + + /* iterator stuff */ + /* internal ptrs to point data. do not free */ + BPoint *bp; + BezTriple *bezt; + int atEnd; /* iter exhausted flag */ + int nextPoint; + +} BPy_SurfNurb; + + +/* + * prototypes + */ + +PyObject *SurfNurb_Init( void ); +PyObject *SurfNurb_CreatePyObject( Nurb * bzt ); +Nurb *SurfNurb_FromPyObject( PyObject * pyobj ); + +PyObject *SurfNurb_getPoint( BPy_SurfNurb * self, int index ); +PyObject *SurfNurb_pointAtIndex( Nurb * nurb, int index ); + +#endif /* EXPP_SURFNURB_H */ diff --git a/source/blender/python/api2_2x/Sys.c b/source/blender/python/api2_2x/Sys.c new file mode 100644 index 00000000000..7dc841e9d68 --- /dev/null +++ b/source/blender/python/api2_2x/Sys.c @@ -0,0 +1,400 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano, Campbell Barton + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#include "Sys.h" /*This must come first*/ + +#include "BKE_utildefines.h" +#include "BKE_global.h" +#include "BLI_blenlib.h" +#include "DNA_scene_types.h" /* G.scene-"r.cfra */ +#include "PIL_time.h" +#include "gen_utils.h" + +#ifdef WIN32 +#define DIRSEP '\\' +#define DIRSEP_STR "\\" +#else +#define DIRSEP '/' +#define DIRSEP_STR "/" +#endif + + +/*****************************************************************************/ +/* Python API function prototypes for the sys module. */ +/*****************************************************************************/ +static PyObject *M_sys_basename( PyObject * self, PyObject * value ); +static PyObject *M_sys_dirname( PyObject * self, PyObject * value ); +static PyObject *M_sys_join( PyObject * self, PyObject * args ); +static PyObject *M_sys_splitext( PyObject * self, PyObject * value ); +static PyObject *M_sys_makename( PyObject * self, PyObject * args, + PyObject * kw ); +static PyObject *M_sys_exists( PyObject * self, PyObject * value ); +static PyObject *M_sys_time( PyObject * self ); +static PyObject *M_sys_sleep( PyObject * self, PyObject * args ); +static PyObject *M_sys_expandpath( PyObject *self, PyObject *value); + +/*****************************************************************************/ +/* The following string definitions are used for documentation strings. */ +/* In Python these will be written to the console when doing a */ +/* Blender.sys.__doc__ */ +/*****************************************************************************/ +static char M_sys_doc[] = "The Blender.sys submodule\n\ +\n\ +This is a minimal system module to supply simple functionality available\n\ +in the default Python module os."; + +static char M_sys_basename_doc[] = + "(path) - Split 'path' in dir and filename.\n\ +Return the filename."; + +static char M_sys_dirname_doc[] = + "(path) - Split 'path' in dir and filename.\n\ +Return the dir."; + +static char M_sys_join_doc[] = + "(dir, file) - Join dir and file to form a full filename.\n\ +Return the filename."; + +static char M_sys_splitext_doc[] = + "(path) - Split 'path' in root and extension:\n\ +/this/that/file.ext -> ('/this/that/file','.ext').\n\ +Return the pair (root, extension)."; + +static char M_sys_makename_doc[] = + "(path = Blender.Get('filename'), ext = \"\", strip = 0) -\n\ +Strip dir and extension from path, leaving only a name, then append 'ext'\n\ +to it (if given) and return the resulting string.\n\n\ +(path) - string: a pathname -- Blender.Get('filename') if 'path' isn't given;\n\ +(ext = \"\") - string: the extension to append.\n\ +(strip = 0) - int: strip dirname from 'path' if given and non-zero.\n\ +Ex: makename('/path/to/file/myfile.foo','-01.abc') returns 'myfile-01.abc'\n\ +Ex: makename(ext='.txt') returns 'untitled.txt' if Blender.Get('filename')\n\ +returns a path to the file 'untitled.blend'"; + +static char M_sys_time_doc[] = + "() - Return a float representing time elapsed in seconds.\n\ +Each successive call is garanteed to return values greater than or\n\ +equal to the previous call."; + +static char M_sys_sleep_doc[] = + "(milliseconds = 10) - Sleep for the specified time.\n\ +(milliseconds = 10) - the amount of time in milliseconds to sleep.\n\ +This function can be necessary in tight 'get event' loops."; + +static char M_sys_exists_doc[] = + "(path) - Check if the given pathname exists.\n\ +The return value is as follows:\n\ +\t 0: path doesn't exist;\n\ +\t 1: path is an existing filename;\n\ +\t 2: path is an existing dirname;\n\ +\t-1: path exists but is neither a regular file nor a dir."; + +static char M_sys_expandpath_doc[] = +"(path) - Expand this Blender internal path to a proper file system path.\n\ +(path) - the string path to convert.\n\n\ +Note: internally Blender paths can contain two special character sequences:\n\ +- '//' (at start) for base path directory (the current .blend's dir path);\n\ +- '#' (at ending) for current frame number.\n\n\ +This function expands these to their actual content, returning a valid path.\n\ +If the special chars are not found in the given path, it is simply returned."; + +/*****************************************************************************/ +/* Python method structure definition for Blender.sys module: */ +/*****************************************************************************/ +struct PyMethodDef M_sys_methods[] = { + {"basename", M_sys_basename, METH_O, M_sys_basename_doc}, + {"dirname", M_sys_dirname, METH_O, M_sys_dirname_doc}, + {"join", M_sys_join, METH_VARARGS, M_sys_join_doc}, + {"splitext", M_sys_splitext, METH_O, M_sys_splitext_doc}, + {"makename", ( PyCFunction ) M_sys_makename, + METH_VARARGS | METH_KEYWORDS, + M_sys_makename_doc}, + {"exists", M_sys_exists, METH_O, M_sys_exists_doc}, + {"sleep", M_sys_sleep, METH_VARARGS, M_sys_sleep_doc}, + {"time", ( PyCFunction ) M_sys_time, METH_NOARGS, M_sys_time_doc}, + {"expandpath", M_sys_expandpath, METH_O, M_sys_expandpath_doc}, + {NULL, NULL, 0, NULL} +}; + +/* Module Functions */ + +static PyObject *g_sysmodule = NULL; /* pointer to Blender.sys module */ + +PyObject *sys_Init( void ) +{ + PyObject *submodule, *dict; + + submodule = Py_InitModule3( "Blender.sys", M_sys_methods, M_sys_doc ); + + g_sysmodule = submodule; + + dict = PyModule_GetDict( submodule ); + + EXPP_dict_set_item_str( dict, "dirsep", PyString_FromString(DIRSEP_STR) ); + EXPP_dict_set_item_str( dict, "sep", PyString_FromString(DIRSEP_STR) ); + + return submodule; +} + +static PyObject *M_sys_basename( PyObject * self, PyObject * value ) +{ + char *name = PyString_AsString(value); + char *p, basename[FILE_MAXDIR + FILE_MAXFILE]; + int n, len; + + if( !name ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + + len = strlen( name ); + +#ifdef WIN32 + p = MAX2(strrchr( name, '/' ), strrchr( name, '\\' )); +#else + p = strrchr( name, DIRSEP ); +#endif + + if( p ) { + n = name + len - p - 1; /* - 1 because we don't want the sep */ + + if( n > FILE_MAXDIR + FILE_MAXFILE ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "path too long" ); + + BLI_strncpy( basename, p + 1, n + 1 ); + return PyString_FromString( basename ); + } + + return PyString_FromString( name ); +} + +static PyObject *M_sys_dirname( PyObject * self, PyObject * value ) +{ + char *name = PyString_AsString(value); + char *p, dirname[FILE_MAXDIR + FILE_MAXFILE]; + int n; + + if( !name ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + +#ifdef WIN32 + p = MAX2(strrchr( name, '/' ), strrchr( name, '\\' )); +#else + p = strrchr( name, DIRSEP ); +#endif + + if( p ) { + n = p - name; + + if( n > FILE_MAXDIR + FILE_MAXFILE ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "path too long" ); + + BLI_strncpy( dirname, name, n + 1 ); + return PyString_FromString( dirname ); + } + + return PyString_FromString( "." ); +} + +static PyObject *M_sys_join( PyObject * self, PyObject * args ) +{ + char *name = NULL, *path = NULL; + char filename[FILE_MAXDIR + FILE_MAXFILE]; + int pathlen = 0, namelen = 0; + + if( !PyArg_ParseTuple( args, "ss", &path, &name ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + + pathlen = strlen( path ) + 1; + namelen = strlen( name ) + 1; /* + 1 to account for '\0' for BLI_strncpy */ + + if( pathlen + namelen > FILE_MAXDIR + FILE_MAXFILE - 1 ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "filename is too long." ); + + BLI_strncpy( filename, path, pathlen ); + + if( filename[pathlen - 2] != DIRSEP ) { + filename[pathlen - 1] = DIRSEP; + pathlen += 1; + } + + BLI_strncpy( filename + pathlen - 1, name, namelen ); + + return PyString_FromString( filename ); +} + +static PyObject *M_sys_splitext( PyObject * self, PyObject * value ) +{ + char *name = PyString_AsString(value); + char *dot, *p, path[FILE_MAXDIR + FILE_MAXFILE], ext[FILE_MAXDIR + FILE_MAXFILE]; + int n, len; + + if( !name ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + + len = strlen( name ); + dot = strrchr( name, '.' ); + + if( !dot ) + return Py_BuildValue( "ss", name, "" ); + + p = strrchr( name, DIRSEP ); + + if( p ) { + if( p > dot ) + return Py_BuildValue( "ss", name, "" ); + } + + n = name + len - dot; + + /* loong extensions are supported -- foolish, but Python's os.path.splitext + * supports them, so ... */ + + if( n >= FILE_MAXDIR + FILE_MAXFILE || ( len - n ) >= FILE_MAXDIR + FILE_MAXFILE ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, "path too long" ); + + BLI_strncpy( ext, dot, n + 1 ); + BLI_strncpy( path, name, dot - name + 1 ); + + return Py_BuildValue( "ss", path, ext ); +} + +static PyObject *M_sys_makename( PyObject * self, PyObject * args, + PyObject * kw ) +{ + char *path = G.sce, *ext = NULL; + int strip = 0; + static char *kwlist[] = { "path", "ext", "strip", NULL }; + char *dot = NULL, *p = NULL, basename[FILE_MAXDIR + FILE_MAXFILE]; + int n, len, lenext = 0; + + if( !PyArg_ParseTupleAndKeywords( args, kw, "|ssi", kwlist, + &path, &ext, &strip ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected one or two strings and an int (or nothing) as arguments" ); + + len = strlen( path ) + 1; /* + 1 to consider ending '\0' */ + if( ext ) + lenext = strlen( ext ) + 1; + + if( ( len + lenext ) > FILE_MAXDIR + FILE_MAXFILE ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "path too long" ); + + p = strrchr( path, DIRSEP ); + + if( p && strip ) { + n = path + len - p; + BLI_strncpy( basename, p + 1, n ); /* + 1 to skip the sep */ + } else + BLI_strncpy( basename, path, len ); + + dot = strrchr( basename, '.' ); + + /* now the extension: always remove the one in basename */ + if( dot || ext ) { + if( !ext ) + basename[dot - basename] = '\0'; + else { /* if user gave an ext, append it */ + + if( dot ) + n = dot - basename; + else + n = strlen( basename ); + + BLI_strncpy( basename + n, ext, lenext ); + } + } + + return PyString_FromString( basename ); +} + +static PyObject *M_sys_time( PyObject * self ) +{ + return PyFloat_FromDouble( PIL_check_seconds_timer( ) ); +} + +static PyObject *M_sys_sleep( PyObject * self, PyObject * args ) +{ + int millisecs = 10; + + if( !PyArg_ParseTuple( args, "|i", &millisecs ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument" ); + + PIL_sleep_ms( millisecs ); + + return EXPP_incr_ret( Py_None ); +} + +static PyObject *M_sys_exists( PyObject * self, PyObject * value ) +{ + char *fname = PyString_AsString(value); + + int mode = 0, i = -1; + + if( !fname ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string (pathname) argument" ); + + mode = BLI_exist(fname); + + if( mode == 0 ) + i = 0; + else if( S_ISREG( mode ) ) + i = 1; + else if( S_ISDIR( mode ) ) + i = 2; + /* i stays as -1 if path exists but is neither a regular file nor a dir */ + + return PyInt_FromLong(i); +} + +static PyObject *M_sys_expandpath( PyObject * self, PyObject * value ) +{ + char *path = PyString_AsString(value); + char expanded[FILE_MAXDIR + FILE_MAXFILE]; + + if (!path) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + + BLI_strncpy(expanded, path, FILE_MAXDIR + FILE_MAXFILE); + BLI_convertstringcode(expanded, G.sce, G.scene->r.cfra); + + return PyString_FromString(expanded); +} diff --git a/source/blender/python/api2_2x/Sys.h b/source/blender/python/api2_2x/Sys.h new file mode 100644 index 00000000000..d6e2689bba5 --- /dev/null +++ b/source/blender/python/api2_2x/Sys.h @@ -0,0 +1,40 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_sys_H +#define EXPP_sys_H + +#include + +PyObject *sys_Init( void ); + +#endif /* EXPP_sys_H */ diff --git a/source/blender/python/api2_2x/Text.c b/source/blender/python/api2_2x/Text.c new file mode 100644 index 00000000000..d507d623c99 --- /dev/null +++ b/source/blender/python/api2_2x/Text.c @@ -0,0 +1,576 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#include "Text.h" /*This must come first*/ + +#include "BKE_library.h" +#include "BKE_sca.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BIF_drawtext.h" +#include "BKE_text.h" +#include "BLI_blenlib.h" +#include "DNA_space_types.h" +#include "gen_utils.h" +#include "gen_library.h" +#include "../BPY_extern.h" + +#define EXPP_TEXT_MODE_FOLLOW TXT_FOLLOW + +/*****************************************************************************/ +/* Python API function prototypes for the Text module. */ +/*****************************************************************************/ +static PyObject *M_Text_New( PyObject * self, PyObject * args); +static PyObject *M_Text_Get( PyObject * self, PyObject * args ); +static PyObject *M_Text_Load( PyObject * self, PyObject * value ); +static PyObject *M_Text_unlink( PyObject * self, PyObject * args ); + +/*****************************************************************************/ +/* The following string definitions are used for documentation strings. */ +/* In Python these will be written to the console when doing a */ +/* Blender.Text.__doc__ */ +/*****************************************************************************/ +static char M_Text_doc[] = "The Blender Text module\n\n"; + +static char M_Text_New_doc[] = "() - return a new Text object"; + +static char M_Text_Get_doc[] = "(name) - return the Text with name 'name', \ +returns None if not found.\n If 'name' is not specified, \ +it returns a list of all Texts in the\ncurrent scene."; + +static char M_Text_Load_doc[] = + "(filename) - return text from file filename as a Text Object, \ +returns None if not found.\n"; + +static char M_Text_unlink_doc[] = + "(text) - remove Text object 'text' from Blender"; + +/*****************************************************************************/ +/* Python method structure definition for Blender.Text module: */ +/*****************************************************************************/ +struct PyMethodDef M_Text_methods[] = { + {"New", M_Text_New, METH_VARARGS, M_Text_New_doc}, + {"Get", M_Text_Get, METH_VARARGS, M_Text_Get_doc}, + {"get", M_Text_Get, METH_VARARGS, M_Text_Get_doc}, + {"Load", M_Text_Load, METH_O, M_Text_Load_doc}, + {"unlink", M_Text_unlink, METH_VARARGS, M_Text_unlink_doc}, + {NULL, NULL, 0, NULL} +}; + + +/*****************************************************************************/ +/* Python BPy_Text methods declarations: */ +/*****************************************************************************/ +static PyObject *Text_getFilename( BPy_Text * self ); +static PyObject *Text_getNLines( BPy_Text * self ); +static PyObject *Text_clear( BPy_Text * self ); +static PyObject *Text_write( BPy_Text * self, PyObject * value ); +static PyObject *Text_set( BPy_Text * self, PyObject * args ); +static PyObject *Text_asLines( BPy_Text * self ); + +/*****************************************************************************/ +/* Python BPy_Text methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_Text_methods[] = { + /* name, method, flags, doc */ + {"getName", ( PyCFunction ) GenericLib_getName, METH_NOARGS, + "() - Return Text Object name"}, + {"getFilename", ( PyCFunction ) Text_getFilename, METH_VARARGS, + "() - Return Text Object filename"}, + {"getNLines", ( PyCFunction ) Text_getNLines, METH_VARARGS, + "() - Return number of lines in text buffer"}, + {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS, + "(str) - Change Text Object name"}, + {"clear", ( PyCFunction ) Text_clear, METH_NOARGS, + "() - Clear Text buffer"}, + {"write", ( PyCFunction ) Text_write, METH_O, + "(line) - Append string 'str' to Text buffer"}, + {"set", ( PyCFunction ) Text_set, METH_VARARGS, + "(name, val) - Set attribute 'name' to value 'val'"}, + {"asLines", ( PyCFunction ) Text_asLines, METH_NOARGS, + "() - Return text buffer as a list of lines"}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python Text_Type callback function prototypes: */ +/*****************************************************************************/ +static int Text_compare( BPy_Text * a, BPy_Text * b ); +static PyObject *Text_repr( BPy_Text * self ); + +/*****************************************************************************/ +/* Function: M_Text_New */ +/* Python equivalent: Blender.Text.New */ +/*****************************************************************************/ +static PyObject *M_Text_New( PyObject * self, PyObject * args) +{ + char *name = "Text"; + int follow = 0; + Text *bl_text; /* blender text object */ + PyObject *py_text; /* python wrapper */ + + if( !PyArg_ParseTuple( args, "|si", &name, &follow ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected string and int arguments (or nothing)" ); + + bl_text = add_empty_text( name ); + + if( bl_text ) { + /* do not set user count because Text is already linked */ + + /* create python wrapper obj */ + py_text = Text_CreatePyObject( bl_text ); + } else + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't create Text Object in Blender" ); + if( !py_text ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create Text Object wrapper" ); + + if( follow ) + bl_text->flags |= EXPP_TEXT_MODE_FOLLOW; + + return py_text; +} + +/*****************************************************************************/ +/* Function: M_Text_Get */ +/* Python equivalent: Blender.Text.Get */ +/* Description: Receives a string and returns the text object */ +/* whose name matches the string. If no argument is */ +/* passed in, a list of all text names in the current */ +/* scene is returned. */ +/*****************************************************************************/ +static PyObject *M_Text_Get( PyObject * self, PyObject * args ) +{ + char *name = NULL; + Text *txt_iter; + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument (or nothing)" ) ); + + txt_iter = G.main->text.first; + + if( name ) { /* (name) - Search text by name */ + + PyObject *wanted_txt = NULL; + + while( ( txt_iter ) && ( wanted_txt == NULL ) ) { + + if( strcmp( name, txt_iter->id.name + 2 ) == 0 ) { + wanted_txt = Text_CreatePyObject( txt_iter ); + } + + txt_iter = txt_iter->id.next; + } + + if( wanted_txt == NULL ) { /* Requested text doesn't exist */ + char error_msg[64]; + PyOS_snprintf( error_msg, sizeof( error_msg ), + "Text \"%s\" not found", name ); + return ( EXPP_ReturnPyObjError + ( PyExc_NameError, error_msg ) ); + } + + return wanted_txt; + } + + else { /* () - return a list of all texts in the scene */ + int index = 0; + PyObject *txtlist, *pyobj; + + txtlist = PyList_New( BLI_countlist( &( G.main->text ) ) ); + + if( txtlist == NULL ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyList" ) ); + + while( txt_iter ) { + pyobj = Text_CreatePyObject( txt_iter ); + + if( !pyobj ) { + Py_DECREF(txtlist); + return ( EXPP_ReturnPyObjError + ( PyExc_MemoryError, + "couldn't create PyString" ) ); + } + PyList_SET_ITEM( txtlist, index, pyobj ); + + txt_iter = txt_iter->id.next; + index++; + } + + return ( txtlist ); + } +} + +/*****************************************************************************/ +/* Function: M_Text_Load */ +/* Python equivalent: Blender.Text.Load */ +/* Description: Receives a filename and returns the text object */ +/* created from the corresponding file. */ +/*****************************************************************************/ +static PyObject *M_Text_Load( PyObject * self, PyObject * value ) +{ + char *fname = PyString_AsString(value); + char fpath[FILE_MAXDIR + FILE_MAXFILE]; + Text *txt_ptr = NULL; + unsigned int maxlen = FILE_MAXDIR + FILE_MAXFILE; + + if( !fname ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ) ); + + if (strlen(fname) > (maxlen - 1)) + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "text filename too long"); + else if (!BLI_exists(fname)) + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "text file not found"); + + BLI_strncpy(fpath, fname, maxlen); + + txt_ptr = add_text( fpath ); + if( !txt_ptr ) + return EXPP_ReturnPyObjError( PyExc_IOError, + "couldn't load text" ); + + return Text_CreatePyObject(txt_ptr); +} + +/*****************************************************************************/ +/* Function: M_Text_unlink */ +/* Python equivalent: Blender.Text.unlink */ +/* Description: Removes the given Text object from Blender */ +/*****************************************************************************/ +static PyObject *M_Text_unlink( PyObject * self, PyObject * args ) +{ + BPy_Text *textobj; + Text *text; + + if( !PyArg_ParseTuple( args, "O!", &Text_Type, &textobj ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a Text object as argument" ); + + text = ( ( BPy_Text * ) textobj )->text; + + if( !text ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "this text was already unlinked!" ); + + BPY_clear_bad_scriptlinks( text ); + free_text_controllers( text ); + unlink_text( text ); + + free_libblock( &G.main->text, text ); + + ( ( BPy_Text * ) textobj )->text = NULL; + + Py_RETURN_NONE; +} + +/*****************************************************************************/ +/* Function: Text_Init */ +/*****************************************************************************/ +PyObject *Text_Init( void ) +{ + PyObject *submodule; + + if( PyType_Ready( &Text_Type ) < 0 ) + return NULL; + + submodule = + Py_InitModule3( "Blender.Text", M_Text_methods, M_Text_doc ); + + return ( submodule ); +} + +/*****************************************************************************/ +/* Function: Text_CreatePyObject */ +/*****************************************************************************/ +PyObject *Text_CreatePyObject( Text * txt ) +{ + BPy_Text *pytxt; + + pytxt = ( BPy_Text * ) PyObject_NEW( BPy_Text, &Text_Type ); + + if( !pytxt ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create BPy_Text PyObject" ); + + pytxt->text = txt; + + return ( PyObject * ) pytxt; +} + +/*****************************************************************************/ +/* Python BPy_Text methods: */ +/*****************************************************************************/ +static PyObject *Text_getFilename( BPy_Text * self ) +{ + if( self->text->name ) + return PyString_FromString( self->text->name ); + + Py_RETURN_NONE; +} + +static PyObject *Text_getNLines( BPy_Text * self ) +{ /* text->nlines isn't updated in Blender (?) */ + int nlines = 0; + TextLine *line; + + line = self->text->lines.first; + + while( line ) { /* so we have to count them ourselves */ + line = line->next; + nlines++; + } + + self->text->nlines = nlines; /* and update Blender, too (should we?) */ + + return PyInt_FromLong( nlines ); +} + +static PyObject *Text_clear( BPy_Text * self) +{ + int oldstate; + + if( !self->text ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This object isn't linked to a Blender Text Object" ); + + oldstate = txt_get_undostate( ); + txt_set_undostate( 1 ); + txt_sel_all( self->text ); + txt_cut_sel( self->text ); + txt_set_undostate( oldstate ); + + Py_RETURN_NONE; +} + +static PyObject *Text_set( BPy_Text * self, PyObject * args ) +{ + int ival; + char *attr; + + if( !PyArg_ParseTuple( args, "si", &attr, &ival ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a string and an int as arguments" ); + + if( strcmp( "follow_cursor", attr ) == 0 ) { + if( ival ) + self->text->flags |= EXPP_TEXT_MODE_FOLLOW; + else + self->text->flags &= EXPP_TEXT_MODE_FOLLOW; + } + + Py_RETURN_NONE; +} + +static PyObject *Text_write( BPy_Text * self, PyObject * value ) +{ + char *str = PyString_AsString(value); + int oldstate; + + if( !self->text ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This object isn't linked to a Blender Text Object" ); + + if( !str ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + + oldstate = txt_get_undostate( ); + txt_insert_buf( self->text, str ); + txt_move_eof( self->text, 0 ); + txt_set_undostate( oldstate ); + + Py_RETURN_NONE; +} + +static PyObject *Text_asLines( BPy_Text * self ) +{ + TextLine *line; + PyObject *list, *tmpstr; + + if( !self->text ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This object isn't linked to a Blender Text Object" ); + + line = self->text->lines.first; + list = PyList_New( 0 ); + + if( !list ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyList" ); + + while( line ) { + tmpstr = PyString_FromString( line->line ); + PyList_Append( list, tmpstr ); + Py_DECREF(tmpstr); + line = line->next; + } + + return list; +} + +/*****************************************************************************/ +/* Function: Text_compare */ +/* Description: This is a callback function for the BPy_Text type. It */ +/* compares two Text_Type objects. Only the "==" and "!=" */ +/* comparisons are meaninful. Returns 0 for equality and -1 if */ +/* they don't point to the same Blender Text struct. */ +/* In Python it becomes 1 if they are equal, 0 otherwise. */ +/*****************************************************************************/ +static int Text_compare( BPy_Text * a, BPy_Text * b ) +{ + return ( a->text == b->text ) ? 0 : -1; +} + +/*****************************************************************************/ +/* Function: Text_repr */ +/* Description: This is a callback function for the BPy_Text type. It */ +/* builds a meaninful string to represent text objects. */ +/*****************************************************************************/ +static PyObject *Text_repr( BPy_Text * self ) +{ + if( self->text ) + return PyString_FromFormat( "[Text \"%s\"]", + self->text->id.name + 2 ); + else + return PyString_FromString( "[Text ]" ); +} + +/*****************************************************************************/ +/* Python attributes get/set functions: */ +/*****************************************************************************/ +static PyObject *Text_getMode(BPy_Text * self) +{ + return PyInt_FromLong( self->text->flags ); +} + +/*****************************************************************************/ +/* Python attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef BPy_Text_getseters[] = { + GENERIC_LIB_GETSETATTR, + {"filename", (getter)Text_getFilename, (setter)NULL, + "text filename", NULL}, + {"mode", (getter)Text_getMode, (setter)NULL, + "text mode flag", NULL}, + {"nlines", (getter)Text_getNLines, (setter)NULL, + "number of lines", NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/*****************************************************************************/ +/* Python Text_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject Text_Type = { + PyObject_HEAD_INIT( NULL ) + 0, /* ob_size */ + "Blender Text", /* tp_name */ + sizeof( BPy_Text ), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + NULL, /* tp_dealloc */ + NULL, /* tp_print */ + NULL, /* tp_getattr */ + NULL, /* tp_setattr */ + ( cmpfunc ) Text_compare, /* tp_compare */ + ( reprfunc ) Text_repr, /* tp_repr */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_Text_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_Text_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; diff --git a/source/blender/python/api2_2x/Text.h b/source/blender/python/api2_2x/Text.h new file mode 100644 index 00000000000..b40c3807a81 --- /dev/null +++ b/source/blender/python/api2_2x/Text.h @@ -0,0 +1,52 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_TEXT_H +#define EXPP_TEXT_H + +#include +#include "DNA_text_types.h" + +extern PyTypeObject Text_Type; + +/* Type checking for EXPP PyTypes */ +#define BPy_Text_Check(v) ((v)->ob_type == &Text_Type) + +typedef struct { + PyObject_HEAD + Text * text; /* libdata must be second */ +} BPy_Text; + +PyObject *Text_Init( void ); +PyObject *Text_CreatePyObject( Text * txt ); + +#endif /* EXPP_TEXT_H */ diff --git a/source/blender/python/api2_2x/Text3d.c b/source/blender/python/api2_2x/Text3d.c new file mode 100644 index 00000000000..57a9c74b71d --- /dev/null +++ b/source/blender/python/api2_2x/Text3d.c @@ -0,0 +1,1206 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Joilnen Leite + * Johnny Matthews + * Campbell BArton + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "Text3d.h" /*This must come first*/ + +#include "DNA_object_types.h" +#include "MEM_guardedalloc.h" +#include "BKE_curve.h" +#include "BKE_library.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BIF_editfont.h" /* do_textedit() */ +#include "Curve.h" +#include "constant.h" +#include "Font.h" +#include "gen_utils.h" +#include "gen_library.h" + + +enum t3d_consts { + EXPP_T3D_ATTR_FRAME_WIDTH = 0, + EXPP_T3D_ATTR_FRAME_HEIGHT, + EXPP_T3D_ATTR_FRAME_X, + EXPP_T3D_ATTR_FRAME_Y +}; + + +/*no prototypes declared in header files - external linkage outside of python*/ +extern VFont *get_builtin_font(void); +extern void freedisplist(struct ListBase *lb); +extern VFont *give_vfontpointer(int); +extern VFont *exist_vfont(char *str); +extern VFont *load_vfont(char *name); +extern int BLI_exist(char *name); + +/*****************************************************************************/ +/* Python API function prototypes for the Text3D module. */ +/*****************************************************************************/ +static PyObject *M_Text3d_New( PyObject * self, PyObject * args ); +static PyObject *M_Text3d_Get( PyObject * self, PyObject * args ); +PyObject *M_Text3d_LoadFont (PyObject * self, PyObject * args ); + +/***************************************************************************** + * Python callback function prototypes for the Text3D module. + *****************************************************************************/ +static PyObject *return_ModuleConstant( char *constant_name); +static PyObject *generate_ModuleIntConstant(char *name, int value); + +/*****************************************************************************/ +/* Python method structure definition for Blender.Text3d module: */ +/*****************************************************************************/ +struct PyMethodDef M_Text3d_methods[] = { + {"New", ( PyCFunction ) M_Text3d_New, METH_VARARGS, NULL}, + {"Get", ( PyCFunction ) M_Text3d_Get, METH_VARARGS, NULL}, + {"LoadFont", ( PyCFunction ) M_Text3d_LoadFont, METH_O, NULL}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python Text3d_Type callback function prototypes: */ +/*****************************************************************************/ +/* int Text3dPrint (BPy_Text3d *msh, FILE *fp, int flags); */ + + +static PyObject *Text3d_repr( BPy_Text3d * self ); +static int Text3d_compare( BPy_Text3d * a, BPy_Text3d * b ); + +/*****************************************************************************/ +/* Python BPy_Text3d methods declarations: */ +/*****************************************************************************/ +/*PyObject *Text3d_getType(BPy_Text3d *self);*/ +static PyObject *Text3d_getName( BPy_Text3d * self ); +static PyObject *Text3d_setName( BPy_Text3d * self, PyObject * args ); +static PyObject *Text3d_setText( BPy_Text3d * self, PyObject * value ); +static PyObject *Text3d_getText( BPy_Text3d * self ); +static PyObject *Text3d_getDrawMode( BPy_Text3d * self ); +static PyObject *Text3d_setDrawMode( BPy_Text3d * self, PyObject * args ); +static PyObject *Text3d_getUVorco( BPy_Text3d * self ); +static PyObject *Text3d_setUVorco( BPy_Text3d * self, PyObject * args ); +static PyObject *Text3d_getBevelAmount( BPy_Text3d * self ); +static PyObject *Text3d_setBevelAmount( BPy_Text3d * self, PyObject * args ); +static PyObject *Text3d_getDefaultResolution( BPy_Text3d * self ); +static PyObject *Text3d_setDefaultResolution( BPy_Text3d * self, PyObject * args ); +static PyObject *Text3d_getWidth( BPy_Text3d * self ); +static PyObject *Text3d_setWidth( BPy_Text3d * self, PyObject * args ); +static PyObject *Text3d_getExtrudeDepth( BPy_Text3d * self ); +static PyObject *Text3d_setExtrudeDepth( BPy_Text3d * self, PyObject * args ); +static PyObject *Text3d_getExtrudeBevelDepth( BPy_Text3d * self ); +static PyObject *Text3d_setExtrudeBevelDepth( BPy_Text3d * self, PyObject * args ); +static PyObject *Text3d_getShear( BPy_Text3d * self ); +static PyObject *Text3d_setShear( BPy_Text3d * self, PyObject * args ); +static PyObject *Text3d_getSize( BPy_Text3d * self ); +static PyObject *Text3d_setSize( BPy_Text3d * self, PyObject * args ); +static PyObject *Text3d_getLineSeparation( BPy_Text3d * self ); +static PyObject *Text3d_setLineSeparation( BPy_Text3d * self, PyObject * args ); +static PyObject *Text3d_getSpacing( BPy_Text3d * self ); +static PyObject *Text3d_setSpacing( BPy_Text3d * self, PyObject * args ); +static PyObject *Text3d_getXoffset( BPy_Text3d * self ); +static PyObject *Text3d_setXoffset( BPy_Text3d * self, PyObject * args ); +static PyObject *Text3d_getYoffset( BPy_Text3d * self ); +static PyObject *Text3d_setYoffset( BPy_Text3d * self, PyObject * args ); +static PyObject *Text3d_getAlignment( BPy_Text3d * self ); +static PyObject *Text3d_setAlignment( BPy_Text3d * self, PyObject * args ); +static PyObject *Text3d_getFont( BPy_Text3d * self ); +static PyObject *Text3d_setFont( BPy_Text3d * self, PyObject * args ); +static PyObject *Text3d_addFrame( BPy_Text3d * self ); +static PyObject *Text3d_removeFrame( BPy_Text3d * self, PyObject * args ); + +/*****************************************************************************/ +/* Python BPy_Text3d methods table: */ +/*****************************************************************************/ +char M_Text3D_doc[] = "The Blender Text3D module\n\n\ + This module provides control over Text Curve objects in Blender.\n"; + +static PyMethodDef BPy_Text3d_methods[] = { + {"getName", ( PyCFunction ) Text3d_getName, + METH_NOARGS, "() - Return Text3d Data name"}, + {"setName", ( PyCFunction ) Text3d_setName, + METH_VARARGS, "() - Sets Text3d Data name"}, + {"setText", ( PyCFunction ) Text3d_setText, + METH_O, "() - Sets Text3d Data"}, + {"getText", ( PyCFunction ) Text3d_getText, + METH_NOARGS, "() - Gets Text3d Data"}, + {"getDrawMode", ( PyCFunction ) Text3d_getDrawMode, + METH_NOARGS, "() - Return the font drawing mode"}, + {"setDrawMode", ( PyCFunction ) Text3d_setDrawMode, + METH_VARARGS, "(int) - Set the font drawing mode"}, + {"getUVorco", ( PyCFunction ) Text3d_getUVorco, + METH_NOARGS, "() - Return wether UV coords are used for Texture mapping"}, + {"setUVorco", ( PyCFunction ) Text3d_setUVorco, + METH_VARARGS, "() - Set the font to use UV coords for Texture mapping"}, + {"getBevelAmount", ( PyCFunction ) Text3d_getBevelAmount, + METH_NOARGS, "() - Return bevel resolution"}, + {"setBevelAmount", ( PyCFunction ) Text3d_setBevelAmount, + METH_VARARGS, "() - Sets bevel resolution"}, + {"getDefaultResolution", ( PyCFunction ) Text3d_getDefaultResolution, + METH_NOARGS, "() - Return Default text resolution"}, + {"setDefaultResolution", ( PyCFunction ) Text3d_setDefaultResolution, + METH_VARARGS, "() - Sets Default text Resolution"}, + {"getWidth", ( PyCFunction ) Text3d_getWidth, + METH_NOARGS, "() - Return curve width"}, + {"setWidth", ( PyCFunction ) Text3d_setWidth, + METH_VARARGS, "(int) - Sets curve width"}, + {"getExtrudeDepth", ( PyCFunction ) Text3d_getExtrudeDepth, + METH_NOARGS, "() - Gets Text3d ExtrudeDepth"}, + {"setExtrudeDepth", ( PyCFunction ) Text3d_setExtrudeDepth, + METH_VARARGS, "() - Sets Text3d ExtrudeDepth"}, + {"getExtrudeBevelDepth", ( PyCFunction ) Text3d_getExtrudeBevelDepth, + METH_NOARGS, "() - Gets Text3d ExtrudeBevelDepth"}, + {"setExtrudeBevelDepth", ( PyCFunction ) Text3d_setExtrudeBevelDepth, + METH_VARARGS, "() - Sets Text3d ExtrudeBevelDepth"}, + {"getShear", ( PyCFunction ) Text3d_getShear, + METH_NOARGS, "() - Gets Text3d Shear Data"}, + {"setShear", ( PyCFunction ) Text3d_setShear, + METH_VARARGS, "() - Sets Text3d Shear Data"}, + {"getSize", ( PyCFunction ) Text3d_getSize, + METH_NOARGS, "() - Gets Text3d Size Data"}, + {"setSize", ( PyCFunction ) Text3d_setSize, + METH_VARARGS, "() - Sets Text3d Size Data"}, + {"getLineSeparation", ( PyCFunction ) Text3d_getLineSeparation, + METH_NOARGS, "() - Gets Text3d LineSeparation Data"}, + {"setLineSeparation", ( PyCFunction ) Text3d_setLineSeparation, + METH_VARARGS, "() - Sets Text3d LineSeparation Data"}, + {"getSpacing", ( PyCFunction ) Text3d_getSpacing, + METH_NOARGS, "() - Gets Text3d letter spacing"}, + {"setSpacing", ( PyCFunction ) Text3d_setSpacing, + METH_VARARGS, "() - Sets Text3d letter spacing"}, + {"getXoffset", ( PyCFunction ) Text3d_getXoffset, + METH_NOARGS, "() - Gets Text3d Xoffset Data"}, + {"setXoffset", ( PyCFunction ) Text3d_setXoffset, + METH_VARARGS, "() - Sets Text3d Xoffset Data"}, + {"getYoffset", ( PyCFunction ) Text3d_getYoffset, + METH_NOARGS, "() - Gets Text3d Yoffset Data"}, + {"setYoffset", ( PyCFunction ) Text3d_setYoffset, + METH_VARARGS, "() - Sets Text3d Yoffset Data"}, + {"getAlignment", ( PyCFunction ) Text3d_getAlignment, + METH_NOARGS, "() - Gets Text3d Alignment Data"}, + {"setAlignment", ( PyCFunction ) Text3d_setAlignment, + METH_VARARGS, "() - Sets Text3d Alignment Data"}, + {"getFont", ( PyCFunction ) Text3d_getFont, + METH_NOARGS, "() - Gets font list for Text3d"}, + {"setFont", ( PyCFunction ) Text3d_setFont, + METH_VARARGS, "() - Sets font for Text3d"}, + {"addFrame", ( PyCFunction ) Text3d_addFrame, + METH_NOARGS, "() - adds a new text frame"}, + {"removeFrame", ( PyCFunction ) Text3d_removeFrame, + METH_VARARGS, "(index) - remove this frame"}, + {NULL, NULL, 0, NULL} +}; + + +static PyObject *Text3d_getTotalFrames( BPy_Text3d * self ) +{ + return PyInt_FromLong( (long)(self->curve->totbox ) ); +} + +static PyObject *Text3d_getActiveFrame( BPy_Text3d * self ) +{ + return PyInt_FromLong( (long)(self->curve->actbox-1) ); +} + +static int Text3d_setActiveFrame( BPy_Text3d * self, PyObject * value ) +{ + struct Curve *curve= self->curve; + PyObject* frame_int = PyNumber_Int( value ); + int index; + + + if( !frame_int ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected integer argument" ); + + index = ( int )PyInt_AS_LONG( frame_int ); + index ++; + if (index < 1 || index > curve->totbox) + return EXPP_ReturnIntError( PyExc_IndexError, + "index out of range" ); + + curve->actbox = index; + + return 0; +} + + +static PyObject *getFloatAttr( BPy_Text3d *self, void *type ) +{ + float param; + struct Curve *curve= self->curve; + + switch( (int)type ) { + case EXPP_T3D_ATTR_FRAME_WIDTH: + param = curve->tb[curve->actbox-1].w; + break; + case EXPP_T3D_ATTR_FRAME_HEIGHT: + param = curve->tb[curve->actbox-1].h; + break; + case EXPP_T3D_ATTR_FRAME_X: + param = curve->tb[curve->actbox-1].x; + break; + case EXPP_T3D_ATTR_FRAME_Y: + param = curve->tb[curve->actbox-1].y; + break; + + default: + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "undefined type in getFloatAttr" ); + } + return PyFloat_FromDouble( param ); +} + +static int setFloatAttrClamp( BPy_Text3d *self, PyObject *value, void *type ) +{ + float *param; + struct Curve *curve= self->curve; + float min, max; + + switch( (int)type ) { + case EXPP_T3D_ATTR_FRAME_WIDTH: + min = 0.0; + max = 50.0; + param = &(curve->tb[curve->actbox-1].w); + break; + case EXPP_T3D_ATTR_FRAME_HEIGHT: + min = 0.0; + max = 50.0; + param = &(curve->tb[curve->actbox-1].h); + break; + case EXPP_T3D_ATTR_FRAME_X: + min = 0.0; + max = 50.0; + param = &(curve->tb[curve->actbox-1].x); + break; + case EXPP_T3D_ATTR_FRAME_Y: + min = 0.0; + max = 50.0; + param = &(curve->tb[curve->actbox-1].y); + break; + + default: + return EXPP_ReturnIntError( PyExc_RuntimeError, + "undefined type in setFloatAttrClamp" ); + } + + return EXPP_setFloatClamped( value, param, min, max ); +} + +/*****************************************************************************/ +/* Python attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef BPy_Text3d_getseters[] = { + GENERIC_LIB_GETSETATTR, /* didnt have any attributes, at least lets have the standard ID attrs */ + {"activeFrame", + (getter)Text3d_getActiveFrame, (setter)Text3d_setActiveFrame, + "the index of the active text frame", + NULL}, + {"totalFrames", + (getter)Text3d_getTotalFrames, (setter)NULL, + "the total number of text frames", + NULL}, + + {"frameWidth", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "the width of the active text frame", + (void *)EXPP_T3D_ATTR_FRAME_WIDTH}, + {"frameHeight", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "the height of the active text frame", + (void *)EXPP_T3D_ATTR_FRAME_HEIGHT}, + {"frameX", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "the X position of the active text frame", + (void *)EXPP_T3D_ATTR_FRAME_X}, + {"frameY", + (getter)getFloatAttr, (setter)setFloatAttrClamp, + "the Y position of the active text frame", + (void *)EXPP_T3D_ATTR_FRAME_Y}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/*****************************************************************************/ +/* Python Text3d_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject Text3d_Type = { + PyObject_HEAD_INIT( NULL ) + 0, /* ob_size */ + "Text3d", /* tp_name */ + sizeof( BPy_Text3d ), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + NULL, /* tp_dealloc */ + NULL, /* tp_print */ + NULL, /* tp_getattr */ + NULL, /* tp_setattr */ + ( cmpfunc ) Text3d_compare, /* tp_compare */ + ( reprfunc ) Text3d_repr, /* tp_repr */ + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_Text3d_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_Text3d_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + + +/* + * Text3d_update( ) + * method to update display list for a Curve. + */ +static PyObject *Text3d_update( BPy_Text3d * self ) +{ + freedisplist( &self->curve->disp ); + Py_RETURN_NONE; +} + +/*****************************************************************************/ +/* Function: M_Text3d_New */ +/* Python equivalent: Blender.Text3d.New */ +/*****************************************************************************/ + +PyObject *M_Text3d_New( PyObject * self, PyObject * args ) +{ + char *name = NULL; + BPy_Text3d *pytext3d; /* for Curve Data object wrapper in Python */ + Text3d *bltext3d = 0; /* for actual Curve Data we create in Blender */ + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_AttributeError, + "expected string argument or no argument" ) ); + + bltext3d = add_curve( "Text", OB_FONT ); /* first create the Curve Data in Blender */ + bltext3d->vfont= get_builtin_font(); + bltext3d->vfont->id.us++; + bltext3d->str= MEM_mallocN(12, "str"); + strcpy(bltext3d->str, "Text"); + bltext3d->pos= 4; + + bltext3d->strinfo= MEM_callocN(12*sizeof(CharInfo), "strinfo"); + bltext3d->totbox= bltext3d->actbox= 1; + bltext3d->tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "textbox"); + bltext3d->tb[0].w = bltext3d->tb[0].h = 0.0; + + if( bltext3d == NULL ) /* bail out if add_curve() failed */ + return ( EXPP_ReturnPyObjError + ( PyExc_RuntimeError, + "couldn't create Curve Data in Blender" ) ); + + /* return user count to zero because add_curve() inc'd it */ + bltext3d->id.us = 0; + /* create python wrapper obj */ + pytext3d = ( BPy_Text3d * ) PyObject_NEW( BPy_Text3d, &Text3d_Type ); + + if( pytext3d == NULL ) + return ( EXPP_ReturnPyObjError + ( PyExc_MemoryError, + "couldn't create Curve Data object" ) ); + + pytext3d->curve = bltext3d; /* link Python curve wrapper to Blender Curve */ + if( name ) + rename_id( &bltext3d->id, name ); + + Text3d_update ( pytext3d ); + return ( PyObject * ) pytext3d; +} + +PyObject *M_Text3d_Get( PyObject * self, PyObject * args ) +{ + char *name = NULL; + Text3d *curv_iter; + BPy_Text3d *wanted_curv; + + if( !PyArg_ParseTuple( args, "|s", &name ) ) /* expects nothing or a string */ + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected string argument" ) ); + if( name ) { /*a name has been given */ + /* Use the name to search for the curve requested */ + wanted_curv = NULL; + curv_iter = G.main->curve.first; + + while( ( curv_iter ) && ( wanted_curv == NULL ) ) { + + if( strcmp( name, curv_iter->id.name + 2 ) == 0 ) { + wanted_curv = ( BPy_Text3d * ) + PyObject_NEW( BPy_Text3d, &Text3d_Type ); + if( wanted_curv ) + wanted_curv->curve = curv_iter; + } + + curv_iter = curv_iter->id.next; + } + + if( wanted_curv == NULL ) { /* Requested curve doesn't exist */ + char error_msg[64]; + PyOS_snprintf( error_msg, sizeof( error_msg ), + "Curve \"%s\" not found", name ); + return ( EXPP_ReturnPyObjError + ( PyExc_NameError, error_msg ) ); + } + + return ( PyObject * ) wanted_curv; + } /* end of if(name) */ + else { + /* no name has been given; return a list of all curves by name. */ + PyObject *curvlist; + + curv_iter = G.main->curve.first; + curvlist = PyList_New( 0 ); + + if( curvlist == NULL ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyList" ) ); + + while( curv_iter && curv_iter->vfont ) { + BPy_Text3d *found_text3d = + ( BPy_Text3d * ) PyObject_NEW( BPy_Text3d, + &Text3d_Type ); + found_text3d->curve = curv_iter; + PyList_Append( curvlist, ( PyObject * ) found_text3d ); + Py_DECREF(found_text3d); + curv_iter = curv_iter->id.next; + } + return ( curvlist ); + } +} + +static PyObject *generate_ModuleIntConstant(char *name, int value) +{ + PyObject *constant = PyConstant_New(); + + PyConstant_Insert((BPy_constant*)constant, + "value", PyInt_FromLong(value)); + PyConstant_Insert((BPy_constant*)constant, + "name", PyString_FromString(name)); + + Py_INCREF(constant); + return constant; +} + +PyObject *Text3d_Init( void ) +{ + //module + PyObject *submodule, *dict; + + //add module... + if( PyType_Ready( &Text3d_Type ) < 0 ) + return NULL; + + submodule = Py_InitModule3( "Blender.Text3d", M_Text3d_methods, + M_Text3D_doc); + + //add constants to module... + PyModule_AddObject( submodule, "LEFT", + generate_ModuleIntConstant("Text3d.LEFT", CU_LEFT)); + PyModule_AddObject( submodule, "MIDDLE", + generate_ModuleIntConstant("Text3d.MIDDLE", CU_MIDDLE)); + PyModule_AddObject( submodule, "RIGHT", + generate_ModuleIntConstant("Text3d.RIGHT", CU_RIGHT)); + PyModule_AddObject( submodule, "FLUSH", + generate_ModuleIntConstant("Text3d.FLUSH", CU_FLUSH)); + PyModule_AddObject( submodule, "JUSTIFY", + generate_ModuleIntConstant("Text3d.JUSTIFY", CU_JUSTIFY)); + PyModule_AddObject( submodule, "DRAW3D", + generate_ModuleIntConstant("Text3d.DRAW3D", CU_3D)); + PyModule_AddObject( submodule, "DRAWFRONT", + generate_ModuleIntConstant("Text3d.DRAWFRONT", CU_FRONT)); + PyModule_AddObject( submodule, "DRAWBACK", + generate_ModuleIntConstant("Text3d.DRAWBACK", CU_BACK)); + PyModule_AddObject( submodule, "UVORCO", + generate_ModuleIntConstant("Text3d.UVORCO", CU_UV_ORCO)); + dict = PyModule_GetDict( submodule ); + PyDict_SetItemString( dict, "Font", Font_Init( ) ); + return ( submodule ); +} + +/**************************************************************************** + * Function: Text3d_repr + * Description: Callback function for the BPy_Text3d type to It + * build a meaninful string to represent Text3d objects. + * + ***************************************************************************/ + +static PyObject *Text3d_repr( BPy_Text3d * self ) +{ + /* skip over CU in idname. CUTEXT */ + return PyString_FromFormat( "[Text3d \"%s\"]", + self->curve->id.name + 2 ); +} + +/**************************************************************************** + * Function: Text3d_compare + * Description: Callback function for the BPy_Text3d type to Compare 2 types + * + ***************************************************************************/ + +/* mat_a==mat_b or mat_a!=mat_b*/ +static int Text3d_compare( BPy_Text3d * a, BPy_Text3d * b ) +{ + return ( a->curve == b->curve) ? 0 : -1; +} + +struct Text3d *Text3d_FromPyObject( PyObject * py_obj ) +{ + BPy_Text3d *blen_obj; + + blen_obj = ( BPy_Text3d * ) py_obj; + return ((struct Text3d*) blen_obj->curve ); +} + +static PyObject *return_ModuleConstant( char *constant_name){ + + PyObject *module = NULL, *dict = NULL, *constant = NULL;; + + module = PyImport_AddModule("Blender.Text3d"); + if(!module){ //null = error returning module + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "error encountered with returning module constant..." ) ); + } + dict = PyModule_GetDict(module); //never fails + + constant = PyDict_GetItemString(dict, constant_name); + if(!constant){ //null = key not found + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "error encountered with returning module constant..." ) ); + } + + return EXPP_incr_ret( constant ); +} + +static PyObject *Text3d_getName( BPy_Text3d * self ) +{ + return Curve_getName( (BPy_Curve*)self ); +} + +static PyObject *Text3d_setName( BPy_Text3d * self, PyObject * args ) +{ + return Curve_setName( (BPy_Curve*)self,args ); +} + +static PyObject *Text3d_setText( BPy_Text3d * self, PyObject * value ) +{ + char *text = PyString_AsString(value); + + if( !text ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected string argument" ); + + /* + * If the text is currently being edited, then we have to put the + * text into the edit buffer. + */ + + if( G.obedit && G.obedit->data == self->curve ) { + short qual = G.qual; + G.qual = 0; /* save key qualifier, then clear it */ + self->curve->pos = self->curve->len = 0; + while ( *text ) + do_textedit( 0, 0, *text++ ); + G.qual = qual; + } else { + short len = (short)strlen(text); + MEM_freeN( self->curve->str ); + self->curve->str = MEM_callocN( len+sizeof(wchar_t), "str" ); + strcpy( self->curve->str, text ); + self->curve->pos = len; + self->curve->len = len; + + if( self->curve->strinfo ) + MEM_freeN( self->curve->strinfo ); + /* don't know why this is +4, just duplicating load_editText() */ + self->curve->strinfo = MEM_callocN( (len+4) *sizeof(CharInfo), + "strinfo"); + } + Py_RETURN_NONE; +} + +static PyObject *Text3d_getText( BPy_Text3d * self ) +{ + if( self->curve->str ) + return PyString_FromString( self->curve->str ); + + Py_RETURN_NONE; +} + +static PyObject* Text3d_getDrawMode(BPy_Text3d* self) +{ + PyObject *tuple = NULL; + int size = 0, pos = 0; + + //get the tuple size + if(self->curve->flag & CU_3D) + size++; + if (self->curve->flag & CU_FRONT) + size++; + if (self->curve->flag & CU_BACK) + size++; + + //generate tuple + tuple = PyTuple_New(size); + + //load tuple + if(self->curve->flag & CU_3D){ + PyTuple_SET_ITEM( tuple, pos, return_ModuleConstant("DRAW3D")); + pos++; + } + if (self->curve->flag & CU_FRONT){ + PyTuple_SET_ITEM( tuple, pos, return_ModuleConstant("DRAWFRONT")); + pos++; + } + if (self->curve->flag & CU_BACK){ + PyTuple_SET_ITEM( tuple, pos, return_ModuleConstant("DRAWBACK")); + pos++; + } + + return tuple; +} + +static PyObject* Text3d_setDrawMode(BPy_Text3d* self,PyObject* args) +{ + PyObject *listObject = NULL; + int size, i; + short temp; + + size = PySequence_Length(args); + if ( size == 1 ) { + listObject = PySequence_GetItem(args, 0); + if ( PySequence_Check(listObject) ) { + size = PySequence_Length(listObject); + }else{ //not a sequence but maybe a single constant + Py_INCREF(args); + listObject = args; + } + } else { //a list of objects (non-sequence) + Py_INCREF(args); + listObject = args; + } + if ( size > 3 || size < 1 ) { + //bad number of arguments + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "too many parameters - expects 1 - 3 constants" ) ); + } + //clear bits + temp = self->curve->flag; //in case of failure + if(self->curve->flag & CU_3D) + self->curve->flag &= ~CU_3D; + if(self->curve->flag & CU_FRONT) + self->curve->flag &= ~CU_FRONT; + if(self->curve->flag & CU_BACK) + self->curve->flag &= ~CU_BACK; + + //parse and set bits + for (i = 0; i < size; i++) { + PyObject *v; + int value; + + v = PySequence_GetItem(listObject, i); + if (v == NULL) { //unable to return item - null = failure + Py_DECREF(listObject); + self->curve->flag = temp; + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "unable to parse list" ) ); + } + if( !BPy_Constant_Check(v)){ + Py_DECREF(listObject); + Py_DECREF(v); + self->curve->flag = temp; + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "bad argument types - expects module constants" ) ); + } + value = PyInt_AS_LONG(PyDict_GetItemString( + ((BPy_constant*)v)->dict, "value")); + self->curve->flag |= (short)value; + Py_DECREF(v); + } + Py_DECREF(listObject); + Py_RETURN_NONE; +} + +static PyObject* Text3d_getUVorco(BPy_Text3d* self) +{ + if(self->curve->flag & CU_UV_ORCO) + return EXPP_incr_ret_True(); + else + return EXPP_incr_ret_False(); +} + +static PyObject* Text3d_setUVorco(BPy_Text3d* self,PyObject* args) +{ + int flag; + + if( !PyArg_ParseTuple( args, "i", &flag ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected TRUE or FALSE (1 or 0)" ); + + if( flag < 0 || flag > 1 ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected TRUE or FALSE (1 or 0)" ); + + if( flag ) + self->curve->flag |= CU_UV_ORCO; + else + self->curve->flag &= ~CU_UV_ORCO; + + Py_RETURN_NONE; +} + +static PyObject* Text3d_getBevelAmount(BPy_Text3d* self) +{ + return Curve_getBevresol((BPy_Curve*)self); +} + +static PyObject* Text3d_setBevelAmount(BPy_Text3d* self,PyObject* args) +{ + return Curve_setBevresol((BPy_Curve*)self,args); +} + +static PyObject *Text3d_getDefaultResolution( BPy_Text3d * self ) +{ + return Curve_getResolu( (BPy_Curve*)self ); +} + +static PyObject *Text3d_setDefaultResolution( BPy_Text3d * self, PyObject * args ) +{ + return Curve_setResolu( (BPy_Curve*)self,args ); +} + +static PyObject *Text3d_getWidth( BPy_Text3d * self ) +{ + return Curve_getWidth( (BPy_Curve*)self ); +} + +static PyObject *Text3d_setWidth( BPy_Text3d * self, PyObject * args ) +{ + return Curve_setWidth( (BPy_Curve*)self,args ); +} + +static PyObject *Text3d_getExtrudeDepth( BPy_Text3d * self ) +{ + return Curve_getExt1( (BPy_Curve*)self ); +} + +static PyObject *Text3d_setExtrudeDepth( BPy_Text3d * self, PyObject * args ) +{ + return Curve_setExt1( (BPy_Curve*)self,args ); +} + +static PyObject *Text3d_getExtrudeBevelDepth( BPy_Text3d * self ) +{ + return Curve_getExt2( (BPy_Curve*)self ); +} + +static PyObject *Text3d_setExtrudeBevelDepth( BPy_Text3d * self, PyObject * args ) +{ + return Curve_setExt2( (BPy_Curve*)self,args ); +} + +static PyObject *Text3d_getShear( BPy_Text3d * self ) +{ + PyObject *attr = PyFloat_FromDouble( (double) self->curve->shear ); + + if( attr ) + return attr; + + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't get Curve.shear attribute" ) ); +} + +static PyObject *Text3d_setShear( BPy_Text3d * self, PyObject * args ) +{ + float value; + + if( !PyArg_ParseTuple( args, "f", &value ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected float argument" ) ); + + if(value > 1.0f || value < -1.0f) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "acceptable values are between 1.0 and -1.0" ) ); + self->curve->shear = value; + + Py_RETURN_NONE; +} + +static PyObject *Text3d_getSize( BPy_Text3d * self ) +{ + PyObject *attr = PyFloat_FromDouble( (double) self->curve->fsize ); + + if( attr ) + return attr; + + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't get Curve.fsize attribute" ) ); +} + +static PyObject *Text3d_setSize( BPy_Text3d * self, PyObject * args ) +{ + float value; + + if( !PyArg_ParseTuple( args, "f", &value ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected float argument" ) ); + + if(value > 10.0f || value < 0.1f) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "acceptable values are between 10.0 and 0.1" ) ); + self->curve->fsize = value; + + Py_RETURN_NONE; +} + +static PyObject *Text3d_getLineSeparation( BPy_Text3d * self ) +{ + PyObject *attr = PyFloat_FromDouble( (double) self->curve->linedist ); + + if( attr ) + return attr; + + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't get Curve.linedist attribute" ) ); +} + +static PyObject *Text3d_setLineSeparation( BPy_Text3d * self, PyObject * args ) +{ + float value; + + if( !PyArg_ParseTuple( args, "f", &value ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected float argument" ) ); + + if(value > 10.0f || value < 0.0f) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "acceptable values are between 10.0 and 0.0" ) ); + self->curve->linedist = value; + + Py_RETURN_NONE; +} + +static PyObject *Text3d_getSpacing( BPy_Text3d * self ) +{ + PyObject *attr = PyFloat_FromDouble( (double) self->curve->spacing ); + + if( attr ) + return attr; + + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't get Curve.spacing attribute" ) ); +} + +static PyObject *Text3d_setSpacing( BPy_Text3d * self, PyObject * args ) +{ + float value; + + if( !PyArg_ParseTuple( args, "f", &value ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected float argument" ) ); + + if(value > 10.0f || value < 0.0f) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "acceptable values are between 10.0 and 0.0" ) ); + self->curve->spacing = value; + + Py_RETURN_NONE; +} +static PyObject *Text3d_getXoffset( BPy_Text3d * self ) +{ + PyObject *attr = PyFloat_FromDouble( (double) self->curve->xof ); + + if( attr ) + return attr; + + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't get Curve.xof attribute" ) ); +} + +static PyObject *Text3d_setXoffset( BPy_Text3d * self, PyObject * args ) +{ + float value; + + if( !PyArg_ParseTuple( args, "f", &value ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected float argument" ) ); + + if(value > 50.0f || value < -50.0f) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "acceptable values are between 50.0 and -50.0" ) ); + self->curve->xof = value; + + Py_RETURN_NONE; +} + +static PyObject *Text3d_getYoffset( BPy_Text3d * self ) +{ + PyObject *attr = PyFloat_FromDouble( (double) self->curve->yof ); + + if( attr ) + return attr; + + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't get Curve.yof attribute" ) ); +} + +static PyObject *Text3d_setYoffset( BPy_Text3d * self, PyObject * args ) +{ + float value; + + if( !PyArg_ParseTuple( args, "f", &value ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected float argument" ) ); + + if(value > 50.0f || value < -50.0f) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "acceptable values are between 50.0 and -50.0" ) ); + self->curve->yof = value; + + Py_RETURN_NONE; +} + +static PyObject *Text3d_getAlignment( BPy_Text3d * self ) +{ + if(self->curve->spacemode == CU_LEFT){ + return return_ModuleConstant("LEFT"); + }else if (self->curve->spacemode == CU_MIDDLE){ + return return_ModuleConstant("MIDDLE"); + }else if (self->curve->spacemode == CU_RIGHT){ + return return_ModuleConstant("RIGHT"); + }else if (self->curve->spacemode == CU_FLUSH){ + return return_ModuleConstant("FLUSH"); + }else if (self->curve->spacemode == CU_JUSTIFY){ + return return_ModuleConstant("JUSTIFY"); + } + + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't get Curve.spacemode attribute" ) ); +} + +static PyObject *Text3d_setAlignment( BPy_Text3d * self, PyObject * args ) +{ + BPy_constant *constant; + int value; + + if( !PyArg_ParseTuple( args, "O!", &constant_Type, &constant ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected module constant" ) ); + + value = PyInt_AS_LONG(PyDict_GetItemString(constant->dict, "value")); + self->curve->spacemode = (short)value; + + Py_RETURN_NONE; +} + + +/***************************************************************************** + * Function: Text3d_CreatePyObject + * Description: This function will create a new BPy_Text3d from an existing + * Blender structure. + *****************************************************************************/ + +PyObject *Text3d_CreatePyObject( Text3d * text3d ) +{ + BPy_Text3d *pytext3d; + + pytext3d = ( BPy_Text3d * ) PyObject_NEW( BPy_Text3d, &Text3d_Type ); + + if( !pytext3d ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create BPy_Text3d object" ); + + pytext3d->curve = text3d; + + return ( PyObject * ) pytext3d; +} + +static PyObject *Text3d_getFont( BPy_Text3d * self ) +{ + if (self->curve) + return Font_CreatePyObject (self->curve->vfont); + else + Py_RETURN_NONE; +} + +static PyObject *Text3d_setFont( BPy_Text3d * self, PyObject * args ) +{ + BPy_Font *pyobj= NULL; + VFont *vf; //, *vfont; + if( !PyArg_ParseTuple( args, "|O!",&Font_Type, &pyobj) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a string" ); + if( !pyobj ) { + // pyobj= M_Text3d_LoadFont (self, Py_BuildValue("(s)", "")); + self->curve->vfont= get_builtin_font (); + Py_RETURN_NONE; + } + vf= exist_vfont(pyobj->font->name); + if (vf) { + id_us_plus((ID *)vf); + self->curve->vfont->id.us--; + self->curve->vfont= vf; + } + else { + vf= load_vfont (pyobj->font->name); + if (vf) { + id_us_plus((ID *)vf); + self->curve->vfont->id.us--; + self->curve->vfont= vf; + } + } + Py_RETURN_NONE; +} + +static PyObject *Text3d_addFrame( BPy_Text3d * self ) +{ + Curve *cu = self->curve; + + if (cu->totbox >= 256) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "limited to 256 frames" ); + + cu->totbox++; + cu->tb[cu->totbox-1]= cu->tb[cu->totbox-2]; + Py_RETURN_NONE; +} + +static PyObject *Text3d_removeFrame( BPy_Text3d * self, PyObject * args ) +{ + Curve *cu = self->curve; + int index, i; + + if (cu->totbox == 1) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "cannot remove the last frame" ); + + index = cu->totbox-1; + + if( !PyArg_ParseTuple( args, "|i", &index ) ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "expected an int" ); + + if (index < 0 || index >= cu->totbox ) + return EXPP_ReturnPyObjError( PyExc_IndexError, + "index out of range" ); + + for (i = index; i < cu->totbox; i++) cu->tb[i]= cu->tb[i+1]; + cu->totbox--; + cu->actbox--; + Py_RETURN_NONE; +} + + +PyObject *M_Text3d_LoadFont( PyObject * self, PyObject * value ) +{ + char *fontfile= PyString_AsString(value); + FILE *file= NULL; + VFont *vf= NULL; + + if( !fontfile ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a string" ); + vf= exist_vfont(fontfile); + if( vf ) + return Font_CreatePyObject( vf ); + /* No use for that -- lukep + else + vf= NULL; + */ + file= fopen( fontfile, "r"); + + if( file || !strcmp (fontfile, "") ) { + load_vfont( fontfile ); + if(file) fclose( file ); + vf = exist_vfont( fontfile ); + if(vf) + return Font_CreatePyObject( vf ); + Py_RETURN_NONE; + } + + return EXPP_ReturnPyObjError( PyExc_TypeError, + "string isn't filename or fontpath" ); +} + diff --git a/source/blender/python/api2_2x/Text3d.h b/source/blender/python/api2_2x/Text3d.h new file mode 100644 index 00000000000..6486278f20d --- /dev/null +++ b/source/blender/python/api2_2x/Text3d.h @@ -0,0 +1,56 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Joilnen Leite + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_TEXT3D_H +#define EXPP_TEXT3D_H + +#include +#include "DNA_curve_types.h" + +extern PyTypeObject Text3d_Type; + +#define BPy_Text3d_Check(v) ((v)->ob_type==&Text3d_Type) +typedef Curve Text3d; + +/*prototypes*/ +PyObject *Text3d_Init( void ); +struct Text3d *Text3d_FromPyObject( PyObject * py_obj ); +PyObject *Text3d_CreatePyObject( Text3d* text3d ); + +/* Python BPy_Text3d structure definition */ +typedef struct { + PyObject_HEAD /* required py macro */ + Text3d * curve; +} BPy_Text3d; + +#endif /* EXPP_TEXT3D_H */ + diff --git a/source/blender/python/api2_2x/Texture.c b/source/blender/python/api2_2x/Texture.c new file mode 100644 index 00000000000..34906757ebd --- /dev/null +++ b/source/blender/python/api2_2x/Texture.c @@ -0,0 +1,2501 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Alex Mole, Nathan Letwory, Joilnen B. Leite, Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ +#include "Texture.h" /*This must come first*/ + +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_idprop.h" +#include "BKE_library.h" +#include "BKE_texture.h" +#include "BKE_utildefines.h" + +#include "BLI_blenlib.h" + +#include "DNA_object_types.h" +#include "DNA_material_types.h" +#include "DNA_scene_types.h" +#include "DNA_texture_types.h" + +#include "MTex.h" +#include "Image.h" +#include "Ipo.h" +#include "IDProp.h" +#include "constant.h" +#include "blendef.h" +#include "gen_utils.h" +#include "gen_library.h" + +#include "vector.h" /* for Texture_evaluate(vec) */ +#include "Material.h" /* for EXPP_Colorband_fromPyList and EXPP_PyList_fromColorband */ +#include "RE_shader_ext.h" + +/*****************************************************************************/ +/* Blender.Texture constants */ +/*****************************************************************************/ +#define EXPP_TEX_TYPE_NONE 0 + +#define EXPP_TEX_TYPE_MIN EXPP_TEX_TYPE_NONE +#define EXPP_TEX_TYPE_MAX TEX_DISTNOISE + +#define EXPP_TEX_ANIMFRAME_MIN 0 +#define EXPP_TEX_ANIMFRAME_MAX ((int)MAXFRAMEF) +#define EXPP_TEX_ANIMLEN_MIN 0 +#define EXPP_TEX_ANIMLEN_MAX ((int)(MAXFRAMEF)/2) +#define EXPP_TEX_ANIMMONSTART_MIN 0 +#define EXPP_TEX_ANIMMONSTART_MAX ((int)MAXFRAMEF) +#define EXPP_TEX_ANIMMONDUR_MIN 0 +#define EXPP_TEX_ANIMMONDUR_MAX 250 +#define EXPP_TEX_ANIMOFFSET_MIN -((int)MAXFRAMEF) +#define EXPP_TEX_ANIMOFFSET_MAX ((int)MAXFRAMEF) +#define EXPP_TEX_ANIMSTART_MIN 1 +#define EXPP_TEX_ANIMSTART_MAX ((int)MAXFRAMEF) +#define EXPP_TEX_FIEIMA_MIN 1 +#define EXPP_TEX_FIEIMA_MAX 200 +#define EXPP_TEX_NOISEDEPTH_MIN 0 +#define EXPP_TEX_NOISEDEPTH_MAX 6 +/* max depth is different for magic type textures */ +#define EXPP_TEX_NOISEDEPTH_MAX_MAGIC 10 +#define EXPP_TEX_REPEAT_MIN 1 +#define EXPP_TEX_REPEAT_MAX 512 + +#define EXPP_TEX_FILTERSIZE_MIN 0.1f +#define EXPP_TEX_FILTERSIZE_MAX 25.0f +#define EXPP_TEX_NOISESIZE_MIN 0.0001f +#define EXPP_TEX_NOISESIZE_MAX 2.0f +#define EXPP_TEX_BRIGHTNESS_MIN 0.0f +#define EXPP_TEX_BRIGHTNESS_MAX 2.0f +#define EXPP_TEX_CONTRAST_MIN 0.01f +#define EXPP_TEX_CONTRAST_MAX 5.0f +#define EXPP_TEX_CROP_MIN -10.0f +#define EXPP_TEX_CROP_MAX 10.0f +#define EXPP_TEX_RGBCOL_MIN 0.0f +#define EXPP_TEX_RGBCOL_MAX 2.0f +#define EXPP_TEX_TURBULENCE_MIN 0.0f +#define EXPP_TEX_TURBULENCE_MAX 200.0f +#define EXPP_TEX_MH_G_MIN 0.0001f +#define EXPP_TEX_MH_G_MAX 2.0f +#define EXPP_TEX_LACUNARITY_MIN 0.0f +#define EXPP_TEX_LACUNARITY_MAX 6.0f +#define EXPP_TEX_OCTS_MIN 0.0f +#define EXPP_TEX_OCTS_MAX 8.0f +#define EXPP_TEX_ISCALE_MIN 0.0f +#define EXPP_TEX_ISCALE_MAX 10.0f +#define EXPP_TEX_EXP_MIN 0.010f +#define EXPP_TEX_EXP_MAX 10.0f +#define EXPP_TEX_WEIGHT1_MIN -2.0f +#define EXPP_TEX_WEIGHT1_MAX 2.0f +#define EXPP_TEX_WEIGHT2_MIN -2.0f +#define EXPP_TEX_WEIGHT2_MAX 2.0f +#define EXPP_TEX_WEIGHT3_MIN -2.0f +#define EXPP_TEX_WEIGHT3_MAX 2.0f +#define EXPP_TEX_WEIGHT4_MIN -2.0f +#define EXPP_TEX_WEIGHT4_MAX 2.0f +#define EXPP_TEX_DISTAMNT_MIN 0.0f +#define EXPP_TEX_DISTAMNT_MAX 10.0f + +/* i can't find these defined anywhere- they're just taken from looking at */ +/* the button creation code in source/blender/src/buttons_shading.c */ +/* cloud stype */ +#define EXPP_TEX_STYPE_CLD_DEFAULT 0 +#define EXPP_TEX_STYPE_CLD_COLOR 1 +/* wood stype */ +#define EXPP_TEX_STYPE_WOD_BANDS 0 +#define EXPP_TEX_STYPE_WOD_RINGS 1 +#define EXPP_TEX_STYPE_WOD_BANDNOISE 2 +#define EXPP_TEX_STYPE_WOD_RINGNOISE 3 +/* magic stype */ +#define EXPP_TEX_STYPE_MAG_DEFAULT 0 +/* marble stype */ +#define EXPP_TEX_STYPE_MBL_SOFT 0 +#define EXPP_TEX_STYPE_MBL_SHARP 1 +#define EXPP_TEX_STYPE_MBL_SHARPER 2 +/* blend stype */ +#define EXPP_TEX_STYPE_BLN_LIN 0 +#define EXPP_TEX_STYPE_BLN_QUAD 1 +#define EXPP_TEX_STYPE_BLN_EASE 2 +#define EXPP_TEX_STYPE_BLN_DIAG 3 +#define EXPP_TEX_STYPE_BLN_SPHERE 4 +#define EXPP_TEX_STYPE_BLN_HALO 5 +/* stucci stype */ +#define EXPP_TEX_STYPE_STC_PLASTIC 0 +#define EXPP_TEX_STYPE_STC_WALLIN 1 +#define EXPP_TEX_STYPE_STC_WALLOUT 2 +/* noise stype */ +#define EXPP_TEX_STYPE_NSE_DEFAULT 0 +/* image stype */ +#define EXPP_TEX_STYPE_IMG_DEFAULT 0 +/* plug-in stype */ +#define EXPP_TEX_STYPE_PLG_DEFAULT 0 +/* envmap stype */ +#define EXPP_TEX_STYPE_ENV_STATIC 0 +#define EXPP_TEX_STYPE_ENV_ANIM 1 +#define EXPP_TEX_STYPE_ENV_LOAD 2 +/* musgrave stype */ +#define EXPP_TEX_STYPE_MUS_MFRACTAL 0 +#define EXPP_TEX_STYPE_MUS_RIDGEDMF 1 +#define EXPP_TEX_STYPE_MUS_HYBRIDMF 2 +#define EXPP_TEX_STYPE_MUS_FBM 3 +#define EXPP_TEX_STYPE_MUS_HTERRAIN 4 +/* voronoi stype */ +#define EXPP_TEX_STYPE_VN_INT 0 +#define EXPP_TEX_STYPE_VN_COL1 1 +#define EXPP_TEX_STYPE_VN_COL2 2 +#define EXPP_TEX_STYPE_VN_COL3 3 + +#define EXPP_TEX_EXTEND_MIN TEX_EXTEND +#define EXPP_TEX_EXTEND_MAX TEX_CHECKER + +#define EXPP_TEX_NOISE_SINE 0 +#define EXPP_TEX_NOISE_SAW 1 +#define EXPP_TEX_NOISE_TRI 2 +#define EXPP_TEX_NOISEBASIS2 0xffff + +/****************************************************************************/ +/* Texture String->Int maps */ +/****************************************************************************/ + +static const EXPP_map_pair tex_type_map[] = { + {"None", EXPP_TEX_TYPE_NONE}, + {"Clouds", TEX_CLOUDS}, + {"Wood", TEX_WOOD}, + {"Marble", TEX_MARBLE}, + {"Magic", TEX_MAGIC}, + {"Blend", TEX_BLEND}, + {"Stucci", TEX_STUCCI}, + {"Noise", TEX_NOISE}, + {"Image", TEX_IMAGE}, + {"Plugin", TEX_PLUGIN}, + {"EnvMap", TEX_ENVMAP}, + {"Musgrave", TEX_MUSGRAVE}, + {"Voronoi", TEX_VORONOI}, + {"DistortedNoise", TEX_DISTNOISE}, + {NULL, 0} +}; + +static const EXPP_map_pair tex_flag_map[] = { +/* NOTE "CheckerOdd" and "CheckerEven" are new */ + {"ColorBand", TEX_COLORBAND }, + {"FlipBlend", TEX_FLIPBLEND}, + {"NegAlpha", TEX_NEGALPHA}, + {"CheckerOdd",TEX_CHECKER_ODD}, + {"CheckerEven",TEX_CHECKER_EVEN}, + {"PreviewAlpha",TEX_PRV_ALPHA}, + {"RepeatXMirror",TEX_REPEAT_XMIR}, + {"RepeatYMirror",TEX_REPEAT_YMIR}, + {NULL, 0} +}; + +/* NOTE: flags moved to image... */ +static const EXPP_map_pair tex_imageflag_map[] = { + {"InterPol", TEX_INTERPOL}, + {"UseAlpha", TEX_USEALPHA}, + {"MipMap", TEX_MIPMAP}, + {"Rot90", TEX_IMAROT}, + {"CalcAlpha", TEX_CALCALPHA}, + {"NormalMap", TEX_NORMALMAP}, + {NULL, 0} +}; + +static const EXPP_map_pair tex_extend_map[] = { + {"Extend", TEX_EXTEND}, + {"Clip", TEX_CLIP}, + {"ClipCube", TEX_CLIPCUBE}, + {"Repeat", TEX_REPEAT}, +/* NOTE "Checker" is new */ + {"Checker", TEX_CHECKER}, + {NULL, 0} +}; + +/* array of maps for stype */ +static const EXPP_map_pair tex_stype_default_map[] = { + {"Default", 0}, + {NULL, 0} +}; +static const EXPP_map_pair tex_stype_clouds_map[] = { + {"Default", 0}, + {"CloudDefault", EXPP_TEX_STYPE_CLD_DEFAULT}, + {"CloudColor", EXPP_TEX_STYPE_CLD_COLOR}, + {NULL, 0} +}; +static const EXPP_map_pair tex_stype_wood_map[] = { + {"Default", 0}, + {"WoodBands", EXPP_TEX_STYPE_WOD_BANDS}, + {"WoodRings", EXPP_TEX_STYPE_WOD_RINGS}, + {"WoodBandNoise", EXPP_TEX_STYPE_WOD_BANDNOISE}, + {"WoodRingNoise", EXPP_TEX_STYPE_WOD_RINGNOISE}, + {NULL, 0} +}; +static const EXPP_map_pair tex_stype_marble_map[] = { + {"Default", 0}, + {"MarbleSoft", EXPP_TEX_STYPE_MBL_SOFT}, + {"MarbleSharp", EXPP_TEX_STYPE_MBL_SHARP}, + {"MarbleSharper", EXPP_TEX_STYPE_MBL_SHARPER}, + {NULL, 0} +}; +static const EXPP_map_pair tex_stype_blend_map[] = { + {"Default", 0}, + {"BlendLin", EXPP_TEX_STYPE_BLN_LIN}, + {"BlendQuad", EXPP_TEX_STYPE_BLN_QUAD}, + {"BlendEase", EXPP_TEX_STYPE_BLN_EASE}, + {"BlendDiag", EXPP_TEX_STYPE_BLN_DIAG}, + {"BlendSphere", EXPP_TEX_STYPE_BLN_SPHERE}, + {"BlendHalo", EXPP_TEX_STYPE_BLN_HALO}, + {NULL, 0} +}; +static const EXPP_map_pair tex_stype_stucci_map[] = { + {"Default", 0}, + {"StucciPlastic", EXPP_TEX_STYPE_STC_PLASTIC}, + {"StucciWallIn", EXPP_TEX_STYPE_STC_WALLIN}, + {"StucciWallOut", EXPP_TEX_STYPE_STC_WALLOUT}, + {NULL, 0} +}; +static const EXPP_map_pair tex_stype_envmap_map[] = { + {"Default", 0}, + {"EnvmapStatic", EXPP_TEX_STYPE_ENV_STATIC}, + {"EnvmapAnim", EXPP_TEX_STYPE_ENV_ANIM}, + {"EnvmapLoad", EXPP_TEX_STYPE_ENV_LOAD}, + {NULL, 0} +}; + +static const EXPP_map_pair tex_stype_musg_map[] = { + {"Default", 0}, + {"MultiFractal", EXPP_TEX_STYPE_MUS_MFRACTAL}, + {"HeteroTerrain", EXPP_TEX_STYPE_MUS_HTERRAIN}, + {"RidgedMultiFractal", EXPP_TEX_STYPE_MUS_RIDGEDMF}, + {"HybridMultiFractal", EXPP_TEX_STYPE_MUS_HYBRIDMF}, + {"fBM", EXPP_TEX_STYPE_MUS_FBM}, + {NULL, 0} +}; + +static const EXPP_map_pair tex_stype_distortednoise_map[] = { + {"Default", 0}, + {"BlenderOriginal", TEX_BLENDER}, + {"OriginalPerlin", TEX_STDPERLIN}, + {"ImprovedPerlin", TEX_NEWPERLIN}, + {"VoronoiF1", TEX_VORONOI_F1}, + {"VoronoiF2", TEX_VORONOI_F2}, + {"VoronoiF3", TEX_VORONOI_F3}, + {"VoronoiF4", TEX_VORONOI_F4}, + {"VoronoiF2-F1", TEX_VORONOI_F2F1}, + {"VoronoiCrackle", TEX_VORONOI_CRACKLE}, + {"CellNoise", TEX_CELLNOISE}, + {NULL, 0} +}; + +static const EXPP_map_pair tex_stype_voronoi_map[] = { + {"Default", 0}, + {"Int", EXPP_TEX_STYPE_VN_INT}, + {"Col1", EXPP_TEX_STYPE_VN_COL1}, + {"Col2", EXPP_TEX_STYPE_VN_COL2}, + {"Col3", EXPP_TEX_STYPE_VN_COL3}, + {NULL, 0} +}; + +static const EXPP_map_pair tex_distance_voronoi_map[] = { + {"Default", 0}, + {"Distance", TEX_DISTANCE}, + {"DistanceSquared", TEX_DISTANCE_SQUARED}, + {"Manhattan", TEX_MANHATTAN}, + {"Chebychev", TEX_CHEBYCHEV}, + {"MinkovskyHalf", TEX_MINKOVSKY_HALF}, + {"MinkovskyFour", TEX_MINKOVSKY_FOUR}, + {"Minkovsky", TEX_MINKOVSKY}, + {NULL, 0} +}; + +static const EXPP_map_pair *tex_stype_map[] = { + tex_stype_default_map, /* none */ + tex_stype_clouds_map, + tex_stype_wood_map, + tex_stype_marble_map, + tex_stype_default_map, /* magic */ + tex_stype_blend_map, + tex_stype_stucci_map, + tex_stype_default_map, /* noise */ + tex_stype_default_map, /* image */ + tex_stype_default_map, /* plugin */ + tex_stype_envmap_map, + tex_stype_musg_map, /* musgrave */ + tex_stype_voronoi_map, /* voronoi */ + tex_stype_distortednoise_map, /* distorted noise */ + tex_distance_voronoi_map +}; + +/*****************************************************************************/ +/* Python API function prototypes for the Texture module. */ +/*****************************************************************************/ +static PyObject *M_Texture_New( PyObject * self, PyObject * args, + PyObject * keywords ); +static PyObject *M_Texture_Get( PyObject * self, PyObject * args ); + +/*****************************************************************************/ +/* The following string definitions are used for documentation strings. */ +/* In Python these will be written to the console when doing a */ +/* Blender.Texture.__doc__ */ +/*****************************************************************************/ +static char M_Texture_doc[] = "The Blender Texture module\n\ +\n\ +This module provides access to **Texture** objects in Blender\n"; + +static char M_Texture_New_doc[] = "Texture.New (name = 'Tex'):\n\ + Return a new Texture object with the given type and name."; + +static char M_Texture_Get_doc[] = "Texture.Get (name = None):\n\ + Return the texture with the given 'name', None if not found, or\n\ + Return a list with all texture objects in the current scene,\n\ + if no argument was given."; + +/*****************************************************************************/ +/* Python method structure definition for Blender.Texture module: */ +/*****************************************************************************/ +struct PyMethodDef M_Texture_methods[] = { + {"New", ( PyCFunction ) M_Texture_New, METH_VARARGS | METH_KEYWORDS, + M_Texture_New_doc}, + {"Get", M_Texture_Get, METH_VARARGS, M_Texture_Get_doc}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python BPy_Texture methods declarations: */ +/*****************************************************************************/ +#define GETFUNC(name) static PyObject *Texture_##name(BPy_Texture *self) +#define OLDSETFUNC(name) static PyObject *Texture_old##name(BPy_Texture *self, \ + PyObject *args) +#define SETFUNC(name) static int Texture_##name(BPy_Texture *self, \ + PyObject *value) +#if 0 +GETFUNC( getExtend ); +GETFUNC( getImage ); +GETFUNC( getType ); +GETFUNC( getSType ); +GETFUNC( clearIpo ); +GETFUNC( getAnimMontage ); +GETFUNC( getAnimLength ); +SETFUNC( setAnimLength ); +SETFUNC( setAnimMontage ); +#endif + +GETFUNC( oldgetSType ); +GETFUNC( oldgetType ); + +GETFUNC( clearIpo ); +GETFUNC( getAnimFrames ); +GETFUNC( getAnimOffset ); +GETFUNC( getAnimStart ); +GETFUNC( getBrightness ); +GETFUNC( getContrast ); +GETFUNC( getCrop ); +GETFUNC( getDistAmnt ); +GETFUNC( getDistMetric ); +GETFUNC( getExp ); +GETFUNC( getExtend ); +GETFUNC( getIntExtend ); +GETFUNC( getFieldsPerImage ); +GETFUNC( getFilterSize ); +GETFUNC( getFlags ); +GETFUNC( getHFracDim ); +GETFUNC( getImage ); +GETFUNC( getIpo ); +GETFUNC( getIScale ); +GETFUNC( getLacunarity ); +GETFUNC( getNoiseBasis ); +GETFUNC( getNoiseDepth ); +GETFUNC( getNoiseSize ); +GETFUNC( getNoiseType ); +GETFUNC( getOcts ); +GETFUNC( getRepeat ); +GETFUNC( getRGBCol ); +GETFUNC( getSType ); +GETFUNC( getTurbulence ); +GETFUNC( getType ); +GETFUNC( getWeight1 ); +GETFUNC( getWeight2 ); +GETFUNC( getWeight3 ); +GETFUNC( getWeight4 ); +#if 0 +/* not defined */ +GETFUNC( getUsers ); +#endif + +OLDSETFUNC( setDistMetric ); +OLDSETFUNC( setDistNoise ); /* special case used for ".noisebasis = ... */ +OLDSETFUNC( setExtend ); +OLDSETFUNC( setFlags ); +OLDSETFUNC( setImage ); +OLDSETFUNC( setImageFlags ); +OLDSETFUNC( setIpo ); +OLDSETFUNC( setNoiseBasis ); +OLDSETFUNC( setSType ); +OLDSETFUNC( setType ); + +SETFUNC( setAnimFrames ); +SETFUNC( setAnimOffset ); +SETFUNC( setAnimStart ); +SETFUNC( setBrightness ); +SETFUNC( setContrast ); +SETFUNC( setCrop ); +SETFUNC( setDistAmnt ); +SETFUNC( setDistMetric ); +SETFUNC( setExp ); +SETFUNC( setIntExtend ); +SETFUNC( setFieldsPerImage ); +SETFUNC( setFilterSize ); +SETFUNC( setFlags ); +SETFUNC( setHFracDim ); +SETFUNC( setImage ); +SETFUNC( setIpo ); +SETFUNC( setIScale ); +SETFUNC( setLacunarity ); +SETFUNC( setNoiseBasis ); +SETFUNC( setNoiseDepth ); +SETFUNC( setNoiseSize ); +SETFUNC( setNoiseType ); +SETFUNC( setOcts ); +SETFUNC( setRepeat ); +SETFUNC( setRGBCol ); +SETFUNC( setSType ); +SETFUNC( setTurbulence ); +SETFUNC( setType ); +SETFUNC( setWeight1 ); +SETFUNC( setWeight2 ); +SETFUNC( setWeight3 ); +SETFUNC( setWeight4 ); + +static PyObject *Texture_getImageFlags( BPy_Texture *self, void *type ); +static PyObject *Texture_getIUserFlags( BPy_Texture *self, void *type ); +static PyObject *Texture_getIUserCyclic( BPy_Texture *self ); +static PyObject *Texture_getNoiseBasis2( BPy_Texture *self, void *type ); +static int Texture_setImageFlags( BPy_Texture *self, PyObject *args, + void *type ); +static int Texture_setIUserFlags( BPy_Texture *self, PyObject *args, + void *type ); +static int Texture_setIUserCyclic( BPy_Texture *self, PyObject *args ); +static int Texture_setNoiseBasis2( BPy_Texture *self, PyObject *args, + void *type ); + +static PyObject *Texture_getColorband( BPy_Texture * self); +int Texture_setColorband( BPy_Texture * self, PyObject * value); +static PyObject *Texture_evaluate( BPy_Texture *self, VectorObject *vec_in ); +static PyObject *Texture_copy( BPy_Texture *self ); + +/*****************************************************************************/ +/* Python BPy_Texture methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_Texture_methods[] = { + /* name, method, flags, doc */ + {"getExtend", ( PyCFunction ) Texture_getExtend, METH_NOARGS, + "() - Return Texture extend mode"}, + {"getImage", ( PyCFunction ) Texture_getImage, METH_NOARGS, + "() - Return Texture Image"}, + {"getName", ( PyCFunction ) GenericLib_getName, METH_NOARGS, + "() - Return Texture name"}, + {"getSType", ( PyCFunction ) Texture_oldgetSType, METH_NOARGS, + "() - Return Texture stype as string"}, + {"getType", ( PyCFunction ) Texture_oldgetType, METH_NOARGS, + "() - Return Texture type as string"}, + {"getIpo", ( PyCFunction ) Texture_getIpo, METH_NOARGS, + "() - Return Texture Ipo"}, + {"setIpo", ( PyCFunction ) Texture_oldsetIpo, METH_VARARGS, + "(Blender Ipo) - Set Texture Ipo"}, + {"clearIpo", ( PyCFunction ) Texture_clearIpo, METH_NOARGS, + "() - Unlink Ipo from this Texture."}, + {"setExtend", ( PyCFunction ) Texture_oldsetExtend, METH_VARARGS, + "(s) - Set Texture extend mode"}, + {"setFlags", ( PyCFunction ) Texture_oldsetFlags, METH_VARARGS, + "(f1,f2,f3,f4,f5) - Set Texture flags"}, + {"setImage", ( PyCFunction ) Texture_oldsetImage, METH_VARARGS, + "(Blender Image) - Set Texture Image"}, + {"setImageFlags", ( PyCFunction ) Texture_oldsetImageFlags, METH_VARARGS, + "(s,s,s,s,...) - Set Texture image flags"}, + {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS, + "(s) - Set Texture name"}, + {"setSType", ( PyCFunction ) Texture_oldsetSType, METH_VARARGS, + "(s) - Set Texture stype"}, + {"setType", ( PyCFunction ) Texture_oldsetType, METH_VARARGS, + "(s) - Set Texture type"}, + {"setNoiseBasis", ( PyCFunction ) Texture_oldsetNoiseBasis, METH_VARARGS, + "(s) - Set Noise basis"}, + {"setDistNoise", ( PyCFunction ) Texture_oldsetDistNoise, METH_VARARGS, + "(s) - Set Dist Noise"}, + {"setDistMetric", ( PyCFunction ) Texture_oldsetDistMetric, METH_VARARGS, + "(s) - Set Dist Metric"}, + {"evaluate", ( PyCFunction ) Texture_evaluate, METH_O, + "(vector) - evaluate the texture at this position"}, + {"__copy__", ( PyCFunction ) Texture_copy, METH_NOARGS, + "() - return a copy of the the texture"}, + {"copy", ( PyCFunction ) Texture_copy, METH_NOARGS, + "() - return a copy of the the texture"}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python Texture_Type attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef BPy_Texture_getseters[] = { + GENERIC_LIB_GETSETATTR, + {"animFrames", + (getter)Texture_getAnimFrames, (setter)Texture_setAnimFrames, + "Number of frames of a movie to use", + NULL}, +#if 0 + {"animLength", + (getter)Texture_getAnimLength, (setter)Texture_setAnimLength, + "Number of frames of a movie to use (0 for all)", + NULL}, + {"animMontage", + (getter)Texture_getAnimMontage, (setter)Texture_setAnimMontage, + "Montage mode, start frames and durations", + NULL}, +#endif + {"animOffset", + (getter)Texture_getAnimOffset, (setter)Texture_setAnimOffset, + "Offsets the number of the first movie frame to use", + NULL}, + {"animStart", + (getter)Texture_getAnimStart, (setter)Texture_setAnimStart, + "Starting frame of the movie to use", + NULL}, + {"brightness", + (getter)Texture_getBrightness, (setter)Texture_setBrightness, + "Changes the brightness of a texture's color", + NULL}, + {"contrast", + (getter)Texture_getContrast, (setter)Texture_setContrast, + "Changes the contrast of a texture's color", + NULL}, + {"crop", + (getter)Texture_getCrop, (setter)Texture_setCrop, + "Sets the cropping extents (for image textures)", + NULL}, + {"distAmnt", + (getter)Texture_getDistAmnt, (setter)Texture_setDistAmnt, + "Amount of distortion (for distorted noise textures)", + NULL}, + {"distMetric", + (getter)Texture_getDistMetric, (setter)Texture_setDistMetric, + "The distance metric (for Voronoi textures)", + NULL}, + {"exp", + (getter)Texture_getExp, (setter)Texture_setExp, + "Minkovsky exponent (for Minkovsky Voronoi textures)", + NULL}, + {"extend", + (getter)Texture_getIntExtend, (setter)Texture_setIntExtend, + "Texture's 'Extend' mode (for image textures)", + NULL}, + {"fieldsPerImage", + (getter)Texture_getFieldsPerImage, (setter)Texture_setFieldsPerImage, + "Number of fields per rendered frame", + NULL}, + {"filterSize", + (getter)Texture_getFilterSize, (setter)Texture_setFilterSize, + "The filter size (for image and envmap textures)", + NULL}, + {"flags", + (getter)Texture_getFlags, (setter)Texture_setFlags, + "Texture's 'Flag' bits", + NULL}, + {"hFracDim", + (getter)Texture_getHFracDim, (setter)Texture_setHFracDim, + "Highest fractional dimension (for Musgrave textures)", + NULL}, + {"imageFlags", + (getter)Texture_getImageFlags, (setter)Texture_setImageFlags, + "Texture's 'ImageFlags' bits", + NULL}, + {"image", + (getter)Texture_getImage, (setter)Texture_setImage, + "Texture's image object", + NULL}, + {"ipo", + (getter)Texture_getIpo, (setter)Texture_setIpo, + "Texture Ipo data", + NULL}, + {"iScale", + (getter)Texture_getIScale, (setter)Texture_setIScale, + "Intensity output scale (for Musgrave and Voronoi textures)", + NULL}, + {"lacunarity", + (getter)Texture_getLacunarity, (setter)Texture_setLacunarity, + "Gap between succesive frequencies (for Musgrave textures)", + NULL}, + {"noiseBasis", + (getter)Texture_getNoiseBasis, (setter)Texture_setNoiseBasis, + "Noise basis type (wood, stucci, marble, clouds, Musgrave, distorted noise)", + NULL}, + {"noiseBasis2", + (getter)Texture_getNoiseBasis2, (setter)Texture_setNoiseBasis2, + "Additional noise basis type (wood, marble, distorted noise)", + (void *)EXPP_TEX_NOISEBASIS2}, + {"noiseDepth", + (getter)Texture_getNoiseDepth, (setter)Texture_setNoiseDepth, + "Noise depth (magic, marble, clouds)", + NULL}, + {"noiseSize", + (getter)Texture_getNoiseSize, (setter)Texture_setNoiseSize, + "Noise size (wood, stucci, marble, clouds, Musgrave, distorted noise, Voronoi)", + NULL}, +/* NOTE for API rewrite: should use dict constants instead of strings */ + {"noiseType", + (getter)Texture_getNoiseType, (setter)Texture_setNoiseType, + "Noise type (for wood, stucci, marble, clouds textures)", + NULL}, + {"octs", + (getter)Texture_getOcts, (setter)Texture_setOcts, + "Number of frequencies (for Musgrave textures)", + NULL}, + {"repeat", + (getter)Texture_getRepeat, (setter)Texture_setRepeat, + "Repetition multiplier (for image textures)", + NULL}, + {"rgbCol", + (getter)Texture_getRGBCol, (setter)Texture_setRGBCol, + "RGB color tuple", + NULL}, + {"stype", + (getter)Texture_getSType, (setter)Texture_setSType, + "Texture's 'SType' mode", + NULL}, + {"turbulence", + (getter)Texture_getTurbulence, (setter)Texture_setTurbulence, + "Turbulence (for magic, wood, stucci, marble textures)", + NULL}, + {"type", + (getter)Texture_getType, (setter)Texture_setType, + "Texture's 'Type' mode", + NULL}, + {"weight1", + (getter)Texture_getWeight1, (setter)Texture_setWeight1, + "Weight 1 (for Voronoi textures)", + NULL}, + {"weight2", + (getter)Texture_getWeight2, (setter)Texture_setWeight2, + "Weight 2 (for Voronoi textures)", + NULL}, + {"weight3", + (getter)Texture_getWeight3, (setter)Texture_setWeight3, + "Weight 3 (for Voronoi textures)", + NULL}, + {"weight4", + (getter)Texture_getWeight4, (setter)Texture_setWeight4, + "Weight 4 (for Voronoi textures)", + NULL}, + {"sine", + (getter)Texture_getNoiseBasis2, (setter)Texture_setNoiseBasis2, + "Produce bands using sine wave (marble, wood textures)", + (void *)EXPP_TEX_NOISE_SINE}, + {"saw", + (getter)Texture_getNoiseBasis2, (setter)Texture_setNoiseBasis2, + "Produce bands using saw wave (marble, wood textures)", + (void *)EXPP_TEX_NOISE_SAW}, + {"tri", + (getter)Texture_getNoiseBasis2, (setter)Texture_setNoiseBasis2, + "Produce bands using triangle wave (marble, wood textures)", + (void *)EXPP_TEX_NOISE_TRI}, + {"interpol", + (getter)Texture_getImageFlags, (setter)Texture_setImageFlags, + "Interpolate image's pixels to fit texture mapping enabled ('ImageFlags')", + (void *)TEX_INTERPOL}, + {"useAlpha", + (getter)Texture_getImageFlags, (setter)Texture_setImageFlags, + "Use of image's alpha channel enabled ('ImageFlags')", + (void *)TEX_USEALPHA}, + {"calcAlpha", + (getter)Texture_getImageFlags, (setter)Texture_setImageFlags, + "Calculation of image's alpha channel enabled ('ImageFlags')", + (void *)TEX_CALCALPHA}, + {"mipmap", + (getter)Texture_getImageFlags, (setter)Texture_setImageFlags, + "Mipmaps enabled ('ImageFlags')", + (void *)TEX_MIPMAP}, + {"rot90", + (getter)Texture_getImageFlags, (setter)Texture_setImageFlags, + "X/Y flip for rendering enabled ('ImageFlags')", + (void *)TEX_IMAROT}, + {"autoRefresh", + (getter)Texture_getIUserFlags, (setter)Texture_setIUserFlags, + "Refresh image on frame changes enabled", + (void *)IMA_ANIM_ALWAYS}, + {"cyclic", + (getter)Texture_getIUserCyclic, (setter)Texture_setIUserCyclic, + "Cycling of animated frames enabled", + NULL}, +#if 0 + /* disabled, moved to image */ + {"fields", + (getter)Texture_getImageFlags, (setter)Texture_setImageFlags, + "Use of image's fields enabled ('ImageFlags')", + (void *)TEX_FIELDS}, + {"movie", + (getter)Texture_getImageFlags, (setter)Texture_setImageFlags, + "Movie frames as images enabled ('ImageFlags')", + (void *)TEX_ANIM5}, + {"anti", + (getter)Texture_getImageFlags, (setter)Texture_setImageFlags, + "Image anti-aliasing enabled ('ImageFlags')", + (void *)TEX_ANTIALI}, + {"stField", + (getter)Texture_getImageFlags, (setter)Texture_setImageFlags, + "Standard field deinterlacing enabled ('ImageFlags')", + (void *)TEX_STD_FIELD}, +#endif + {"normalMap", + (getter)Texture_getImageFlags, (setter)Texture_setImageFlags, + "Use of image RGB values for normal mapping enabled ('ImageFlags')", + (void *)TEX_NORMALMAP}, + {"colorband", + (getter)Texture_getColorband, (setter)Texture_setColorband, + "The colorband for this texture", + NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/*****************************************************************************/ +/* Python Texture_Type callback function prototypes: */ +/*****************************************************************************/ +static int Texture_compare( BPy_Texture * a, BPy_Texture * b ); +static PyObject *Texture_repr( BPy_Texture * self ); + +/*****************************************************************************/ +/* Python Texture_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject Texture_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender Texture", /* char *tp_name; */ + sizeof( BPy_Texture ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) Texture_compare, /* cmpfunc tp_compare; */ + ( reprfunc ) Texture_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_Texture_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_Texture_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +static PyObject *M_Texture_New( PyObject * self, PyObject * args, + PyObject * kwords ) +{ + char *name_str = "Tex"; + static char *kwlist[] = { "name_str", NULL }; + PyObject *pytex; /* for Texture object wrapper in Python */ + Tex *bltex; /* for actual Tex we create in Blender */ + + /* Parse the arguments passed in by the Python interpreter */ + if( !PyArg_ParseTupleAndKeywords + ( args, kwords, "|s", kwlist, &name_str ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected zero, one or two strings as arguments" ); + + bltex = add_texture( name_str ); /* first create the texture in Blender */ + + if( bltex ) /* now create the wrapper obj in Python */ + pytex = Texture_CreatePyObject( bltex ); + else + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't create Texture in Blender" ); + + /* let's return user count to zero, because add_texture() incref'd it */ + bltex->id.us = 0; + + if( pytex == NULL ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create Tex PyObject" ); + + return pytex; +} + +static PyObject *M_Texture_Get( PyObject * self, PyObject * args ) +{ + char *name = NULL; + Tex *tex_iter; + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument (or nothing)" ); + + tex_iter = G.main->tex.first; + + if( name ) { /* (name) - Search for texture by name */ + + PyObject *wanted_tex = NULL; + + while( tex_iter ) { + if( STREQ( name, tex_iter->id.name + 2 ) ) { + wanted_tex = + Texture_CreatePyObject( tex_iter ); + break; + } + + tex_iter = tex_iter->id.next; + } + + if( !wanted_tex ) { /* Requested texture doesn't exist */ + char error_msg[64]; + PyOS_snprintf( error_msg, sizeof( error_msg ), + "Texture \"%s\" not found", name ); + return EXPP_ReturnPyObjError( PyExc_NameError, + error_msg ); + } + + return wanted_tex; + } + + else { /* () - return a list of wrappers for all textures in the scene */ + int index = 0; + PyObject *tex_pylist, *pyobj; + + tex_pylist = PyList_New( BLI_countlist( &( G.main->tex ) ) ); + if( !tex_pylist ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyList" ); + + while( tex_iter ) { + pyobj = Texture_CreatePyObject( tex_iter ); + if( !pyobj ) { + Py_DECREF(tex_pylist); + return EXPP_ReturnPyObjError + ( PyExc_MemoryError, + "couldn't create Texture PyObject" ); + } + PyList_SET_ITEM( tex_pylist, index, pyobj ); + + tex_iter = tex_iter->id.next; + index++; + } + + return tex_pylist; + } +} + +static int Texture_compare( BPy_Texture * a, BPy_Texture * b ) +{ + return ( a->texture == b->texture ) ? 0 : -1; +} + +static PyObject *Texture_repr( BPy_Texture * self ) +{ + return PyString_FromFormat( "[Texture \"%s\"]", + self->texture->id.name + 2 ); +} + +static PyObject *M_Texture_TypesDict( void ) +{ + PyObject *Types = PyConstant_New( ); + if( Types ) { + BPy_constant *d = ( BPy_constant * ) Types; + PyConstant_Insert(d, "NONE", PyInt_FromLong(EXPP_TEX_TYPE_NONE)); + PyConstant_Insert(d, "CLOUDS", PyInt_FromLong(TEX_CLOUDS)); + PyConstant_Insert(d, "WOOD", PyInt_FromLong(TEX_WOOD)); + PyConstant_Insert(d, "MARBLE", PyInt_FromLong(TEX_MARBLE)); + PyConstant_Insert(d, "MAGIC", PyInt_FromLong(TEX_MAGIC)); + PyConstant_Insert(d, "BLEND", PyInt_FromLong(TEX_BLEND)); + PyConstant_Insert(d, "STUCCI", PyInt_FromLong(TEX_STUCCI)); + PyConstant_Insert(d, "NOISE", PyInt_FromLong(TEX_NOISE)); + PyConstant_Insert(d, "IMAGE", PyInt_FromLong(TEX_IMAGE)); + PyConstant_Insert(d, "PLUGIN", PyInt_FromLong(TEX_PLUGIN)); + PyConstant_Insert(d, "ENVMAP", PyInt_FromLong(TEX_ENVMAP)); + PyConstant_Insert(d, "MUSGRAVE", PyInt_FromLong(TEX_MUSGRAVE)); + PyConstant_Insert(d, "VORONOI", PyInt_FromLong(TEX_VORONOI)); + PyConstant_Insert(d, "DISTNOISE", PyInt_FromLong(TEX_DISTNOISE)); + } + return Types; +} + +static PyObject *M_Texture_STypesDict( void ) +{ + PyObject *STypes = PyConstant_New( ); + if( STypes ) { + BPy_constant *d = ( BPy_constant * ) STypes; + + PyConstant_Insert(d, "CLD_DEFAULT", + PyInt_FromLong(EXPP_TEX_STYPE_CLD_DEFAULT)); + PyConstant_Insert(d, "CLD_COLOR", + PyInt_FromLong(EXPP_TEX_STYPE_CLD_COLOR)); + PyConstant_Insert(d, "WOD_BANDS", + PyInt_FromLong(EXPP_TEX_STYPE_WOD_BANDS)); + PyConstant_Insert(d, "WOD_RINGS", + PyInt_FromLong(EXPP_TEX_STYPE_WOD_RINGS)); + PyConstant_Insert(d, "WOD_BANDNOISE", + PyInt_FromLong(EXPP_TEX_STYPE_WOD_BANDNOISE)); + PyConstant_Insert(d, "WOD_RINGNOISE", + PyInt_FromLong(EXPP_TEX_STYPE_WOD_RINGNOISE)); + PyConstant_Insert(d, "MAG_DEFAULT", + PyInt_FromLong(EXPP_TEX_STYPE_MAG_DEFAULT)); + PyConstant_Insert(d, "MBL_SOFT", + PyInt_FromLong(EXPP_TEX_STYPE_MBL_SOFT)); + PyConstant_Insert(d, "MBL_SHARP", + PyInt_FromLong(EXPP_TEX_STYPE_MBL_SHARP)); + PyConstant_Insert(d, "MBL_SHARPER", + PyInt_FromLong(EXPP_TEX_STYPE_MBL_SHARPER)); + PyConstant_Insert(d, "BLN_LIN", + PyInt_FromLong(EXPP_TEX_STYPE_BLN_LIN)); + PyConstant_Insert(d, "BLN_QUAD", + PyInt_FromLong(EXPP_TEX_STYPE_BLN_QUAD)); + PyConstant_Insert(d, "BLN_EASE", + PyInt_FromLong(EXPP_TEX_STYPE_BLN_EASE)); + PyConstant_Insert(d, "BLN_DIAG", + PyInt_FromLong(EXPP_TEX_STYPE_BLN_DIAG)); + PyConstant_Insert(d, "BLN_SPHERE", + PyInt_FromLong(EXPP_TEX_STYPE_BLN_SPHERE)); + PyConstant_Insert(d, "BLN_HALO", + PyInt_FromLong(EXPP_TEX_STYPE_BLN_HALO)); + PyConstant_Insert(d, "STC_PLASTIC", + PyInt_FromLong(EXPP_TEX_STYPE_STC_PLASTIC)); + PyConstant_Insert(d, "STC_WALLIN", + PyInt_FromLong(EXPP_TEX_STYPE_STC_WALLIN)); + PyConstant_Insert(d, "STC_WALLOUT", + PyInt_FromLong(EXPP_TEX_STYPE_STC_WALLOUT)); + PyConstant_Insert(d, "NSE_DEFAULT", + PyInt_FromLong(EXPP_TEX_STYPE_NSE_DEFAULT)); + PyConstant_Insert(d, "IMG_DEFAULT", + PyInt_FromLong(EXPP_TEX_STYPE_IMG_DEFAULT)); + PyConstant_Insert(d, "PLG_DEFAULT", + PyInt_FromLong(EXPP_TEX_STYPE_PLG_DEFAULT)); + PyConstant_Insert(d, "ENV_STATIC", + PyInt_FromLong(EXPP_TEX_STYPE_ENV_STATIC)); + PyConstant_Insert(d, "ENV_ANIM", + PyInt_FromLong(EXPP_TEX_STYPE_ENV_ANIM)); + PyConstant_Insert(d, "ENV_LOAD", + PyInt_FromLong(EXPP_TEX_STYPE_ENV_LOAD)); + PyConstant_Insert(d, "MUS_MFRACTAL", + PyInt_FromLong(EXPP_TEX_STYPE_MUS_MFRACTAL)); + PyConstant_Insert(d, "MUS_RIDGEDMF", + PyInt_FromLong(EXPP_TEX_STYPE_MUS_RIDGEDMF)); + PyConstant_Insert(d, "MUS_HYBRIDMF", + PyInt_FromLong(EXPP_TEX_STYPE_MUS_HYBRIDMF)); + PyConstant_Insert(d, "MUS_FBM", + PyInt_FromLong(EXPP_TEX_STYPE_MUS_FBM)); + PyConstant_Insert(d, "MUS_HTERRAIN", + PyInt_FromLong(EXPP_TEX_STYPE_MUS_HTERRAIN)); + PyConstant_Insert(d, "DN_BLENDER", + PyInt_FromLong(TEX_BLENDER)); + PyConstant_Insert(d, "DN_PERLIN", + PyInt_FromLong(TEX_STDPERLIN)); + PyConstant_Insert(d, "DN_IMPROVEDPERLIN", + PyInt_FromLong(TEX_NEWPERLIN)); + PyConstant_Insert(d, "DN_VORONOIF1", + PyInt_FromLong(TEX_VORONOI_F1)); + PyConstant_Insert(d, "DN_VORONOIF2", + PyInt_FromLong(TEX_VORONOI_F2)); + PyConstant_Insert(d, "DN_VORONOIF3", + PyInt_FromLong(TEX_VORONOI_F3)); + PyConstant_Insert(d, "DN_VORONOIF4", + PyInt_FromLong(TEX_VORONOI_F4)); + PyConstant_Insert(d, "DN_VORONOIF2F1", + PyInt_FromLong(TEX_VORONOI_F2F1)); + PyConstant_Insert(d, "DN_VORONOICRACKLE", + PyInt_FromLong(TEX_VORONOI_CRACKLE)); + PyConstant_Insert(d, "DN_CELLNOISE", + PyInt_FromLong(TEX_CELLNOISE)); + PyConstant_Insert(d, "VN_INT", + PyInt_FromLong(EXPP_TEX_STYPE_VN_INT)); + PyConstant_Insert(d, "VN_COL1", + PyInt_FromLong(EXPP_TEX_STYPE_VN_COL1)); + PyConstant_Insert(d, "VN_COL2", + PyInt_FromLong(EXPP_TEX_STYPE_VN_COL2)); + PyConstant_Insert(d, "VN_COL3", + PyInt_FromLong(EXPP_TEX_STYPE_VN_COL3)); + PyConstant_Insert(d, "VN_TEX_DISTANCE", + PyInt_FromLong(TEX_DISTANCE)); + PyConstant_Insert(d, "VN_TEX_DISTANCE_SQUARED", + PyInt_FromLong(TEX_DISTANCE_SQUARED)); + PyConstant_Insert(d, "VN_TEX_MANHATTAN", + PyInt_FromLong(TEX_MANHATTAN)); + PyConstant_Insert(d, "VN_TEX_CHEBYCHEV", + PyInt_FromLong(TEX_CHEBYCHEV)); + PyConstant_Insert(d, "VN_TEX_MINKOVSKY_HALF", + PyInt_FromLong(TEX_MINKOVSKY_HALF)); + PyConstant_Insert(d, "VN_TEX_MINKOVSKY_FOUR", + PyInt_FromLong(TEX_MINKOVSKY_FOUR)); + PyConstant_Insert(d, "VN_TEX_MINKOVSKY", + PyInt_FromLong(TEX_MINKOVSKY)); + + } + return STypes; +} + +static PyObject *M_Texture_TexCoDict( void ) +{ + PyObject *TexCo = PyConstant_New( ); + if( TexCo ) { + BPy_constant *d = ( BPy_constant * ) TexCo; + PyConstant_Insert(d, "ORCO", PyInt_FromLong(TEXCO_ORCO)); + PyConstant_Insert(d, "REFL", PyInt_FromLong(TEXCO_REFL)); + PyConstant_Insert(d, "NOR", PyInt_FromLong(TEXCO_NORM)); + PyConstant_Insert(d, "GLOB", PyInt_FromLong(TEXCO_GLOB)); + PyConstant_Insert(d, "UV", PyInt_FromLong(TEXCO_UV)); + PyConstant_Insert(d, "OBJECT", PyInt_FromLong(TEXCO_OBJECT)); + PyConstant_Insert(d, "WIN", PyInt_FromLong(TEXCO_WINDOW)); + PyConstant_Insert(d, "VIEW", PyInt_FromLong(TEXCO_VIEW)); + PyConstant_Insert(d, "STICK", PyInt_FromLong(TEXCO_STICKY)); + PyConstant_Insert(d, "STRESS", PyInt_FromLong(TEXCO_STRESS)); + PyConstant_Insert(d, "TANGENT", PyInt_FromLong(TEXCO_TANGENT)); + } + return TexCo; +} + +static PyObject *M_Texture_MapToDict( void ) +{ + PyObject *MapTo = PyConstant_New( ); + if( MapTo ) { + BPy_constant *d = ( BPy_constant * ) MapTo; + PyConstant_Insert(d, "COL", PyInt_FromLong(MAP_COL)); + PyConstant_Insert(d, "NOR", PyInt_FromLong(MAP_NORM)); + PyConstant_Insert(d, "CSP", PyInt_FromLong(MAP_COLSPEC)); + PyConstant_Insert(d, "CMIR", PyInt_FromLong(MAP_COLMIR)); + PyConstant_Insert(d, "REF", PyInt_FromLong(MAP_REF)); + PyConstant_Insert(d, "SPEC", PyInt_FromLong(MAP_SPEC)); + PyConstant_Insert(d, "HARD", PyInt_FromLong(MAP_HAR)); + PyConstant_Insert(d, "ALPHA", PyInt_FromLong(MAP_ALPHA)); + PyConstant_Insert(d, "EMIT", PyInt_FromLong(MAP_EMIT)); + PyConstant_Insert(d, "RAYMIR", PyInt_FromLong(MAP_RAYMIRR)); + PyConstant_Insert(d, "AMB", PyInt_FromLong(MAP_AMB)); + PyConstant_Insert(d, "TRANSLU", PyInt_FromLong(MAP_TRANSLU)); + PyConstant_Insert(d, "DISP", PyInt_FromLong(MAP_DISPLACE)); + PyConstant_Insert(d, "WARP", PyInt_FromLong(MAP_WARP)); + } + return MapTo; +} + +static PyObject *M_Texture_FlagsDict( void ) +{ + PyObject *Flags = PyConstant_New( ); + if( Flags ) { + BPy_constant *d = ( BPy_constant * ) Flags; + PyConstant_Insert(d, "COLORBAND", PyInt_FromLong(TEX_COLORBAND)); + PyConstant_Insert(d, "FLIPBLEND", PyInt_FromLong(TEX_FLIPBLEND)); + PyConstant_Insert(d, "NEGALPHA", PyInt_FromLong(TEX_NEGALPHA)); + PyConstant_Insert(d, "CHECKER_ODD", PyInt_FromLong(TEX_CHECKER_ODD)); + PyConstant_Insert(d, "CHECKER_EVEN", PyInt_FromLong(TEX_CHECKER_EVEN)); + PyConstant_Insert(d, "PREVIEW_ALPHA", PyInt_FromLong(TEX_PRV_ALPHA)); + PyConstant_Insert(d, "REPEAT_XMIR", PyInt_FromLong(TEX_REPEAT_XMIR)); + PyConstant_Insert(d, "REPEAT_YMIR", PyInt_FromLong(TEX_REPEAT_YMIR)); + } + return Flags; +} + +static PyObject *M_Texture_ExtendModesDict( void ) +{ + PyObject *ExtendModes = PyConstant_New( ); + if( ExtendModes ) { + BPy_constant *d = ( BPy_constant * ) ExtendModes; + PyConstant_Insert(d, "EXTEND", PyInt_FromLong(TEX_EXTEND)); + PyConstant_Insert(d, "CLIP", PyInt_FromLong(TEX_CLIP)); + PyConstant_Insert(d, "CLIPCUBE", PyInt_FromLong(TEX_CLIPCUBE)); + PyConstant_Insert(d, "REPEAT", PyInt_FromLong(TEX_REPEAT)); + } + return ExtendModes; +} + +static PyObject *M_Texture_ImageFlagsDict( void ) +{ + PyObject *ImageFlags = PyConstant_New( ); + if( ImageFlags ) { + BPy_constant *d = ( BPy_constant * ) ImageFlags; + PyConstant_Insert(d, "INTERPOL", PyInt_FromLong(TEX_INTERPOL)); + PyConstant_Insert(d, "USEALPHA", PyInt_FromLong(TEX_USEALPHA)); + PyConstant_Insert(d, "MIPMAP", PyInt_FromLong(TEX_MIPMAP)); + PyConstant_Insert(d, "ROT90", PyInt_FromLong(TEX_IMAROT)); + PyConstant_Insert(d, "CALCALPHA", PyInt_FromLong(TEX_CALCALPHA)); + PyConstant_Insert(d, "NORMALMAP", PyInt_FromLong(TEX_NORMALMAP)); + } + return ImageFlags; +} + +static PyObject *M_Texture_NoiseDict( void ) +{ + PyObject *Noise = PyConstant_New( ); + if( Noise ) { + BPy_constant *d = ( BPy_constant * ) Noise; + PyConstant_Insert(d, "SINE", PyInt_FromLong(EXPP_TEX_NOISE_SINE)); + PyConstant_Insert(d, "SAW", PyInt_FromLong(EXPP_TEX_NOISE_SAW)); + PyConstant_Insert(d, "TRI", PyInt_FromLong(EXPP_TEX_NOISE_TRI)); + PyConstant_Insert(d, "BLENDER", PyInt_FromLong(TEX_BLENDER)); + PyConstant_Insert(d, "PERLIN", PyInt_FromLong(TEX_STDPERLIN)); + PyConstant_Insert(d, "IMPROVEDPERLIN", PyInt_FromLong(TEX_NEWPERLIN)); + PyConstant_Insert(d, "VORONOIF1", PyInt_FromLong(TEX_VORONOI_F1)); + PyConstant_Insert(d, "VORONOIF2", PyInt_FromLong(TEX_VORONOI_F2)); + PyConstant_Insert(d, "VORONOIF3", PyInt_FromLong(TEX_VORONOI_F3)); + PyConstant_Insert(d, "VORONOIF4", PyInt_FromLong(TEX_VORONOI_F4)); + PyConstant_Insert(d, "VORONOIF2F1", PyInt_FromLong(TEX_VORONOI_F2F1)); + PyConstant_Insert(d, "VORONOICRACKLE", + PyInt_FromLong(TEX_VORONOI_CRACKLE)); + PyConstant_Insert(d, "CELLNOISE", PyInt_FromLong(TEX_CELLNOISE)); + } + return Noise; +} + +static PyObject *M_Texture_BlendModesDict( void ) +{ + PyObject *BlendModes = PyConstant_New( ); + if( BlendModes ) { + BPy_constant *d = ( BPy_constant * ) BlendModes; + PyConstant_Insert(d, "MIX", PyInt_FromLong(MTEX_BLEND)); + PyConstant_Insert(d, "MULTIPLY", PyInt_FromLong(MTEX_MUL)); + PyConstant_Insert(d, "ADD", PyInt_FromLong(MTEX_ADD)); + PyConstant_Insert(d, "SUBTRACT", PyInt_FromLong(MTEX_SUB)); + PyConstant_Insert(d, "DIVIDE", PyInt_FromLong(MTEX_DIV)); + PyConstant_Insert(d, "DARKEN", PyInt_FromLong(MTEX_DARK)); + PyConstant_Insert(d, "DIFFERENCE", PyInt_FromLong(MTEX_DIFF)); + PyConstant_Insert(d, "LIGHTEN", PyInt_FromLong(MTEX_LIGHT)); + PyConstant_Insert(d, "SCREEN", PyInt_FromLong(MTEX_SCREEN)); + } + return BlendModes; +} + +static PyObject *M_Texture_MappingsDict( void ) +{ + PyObject *Mappings = PyConstant_New( ); + if( Mappings ) { + BPy_constant *d = ( BPy_constant * ) Mappings; + PyConstant_Insert(d, "FLAT", PyInt_FromLong(MTEX_FLAT)); + PyConstant_Insert(d, "CUBE", PyInt_FromLong(MTEX_CUBE)); + PyConstant_Insert(d, "TUBE", PyInt_FromLong(MTEX_TUBE)); + PyConstant_Insert(d, "SPHERE", PyInt_FromLong(MTEX_SPHERE)); + } + return Mappings; +} + +static PyObject *M_Texture_ProjDict( void ) +{ + PyObject *Proj = PyConstant_New( ); + if( Proj ) { + BPy_constant *d = ( BPy_constant * ) Proj; + PyConstant_Insert(d, "NONE", PyInt_FromLong(PROJ_N)); + PyConstant_Insert(d, "X", PyInt_FromLong(PROJ_X)); + PyConstant_Insert(d, "Y", PyInt_FromLong(PROJ_Y)); + PyConstant_Insert(d, "Z", PyInt_FromLong(PROJ_Z)); + } + return Proj; +} + +PyObject *Texture_Init( void ) +{ + PyObject *submodule; + PyObject *dict; + + /* constants */ + PyObject *Types = M_Texture_TypesDict( ); + PyObject *STypes = M_Texture_STypesDict( ); + PyObject *TexCo = M_Texture_TexCoDict( ); + PyObject *MapTo = M_Texture_MapToDict( ); + PyObject *Flags = M_Texture_FlagsDict( ); + PyObject *ExtendModes = M_Texture_ExtendModesDict( ); + PyObject *ImageFlags = M_Texture_ImageFlagsDict( ); + PyObject *Noise = M_Texture_NoiseDict( ); + PyObject *BlendModes = M_Texture_BlendModesDict( ); + PyObject *Mappings = M_Texture_MappingsDict( ); + PyObject *Proj = M_Texture_ProjDict( ); + + if( PyType_Ready( &Texture_Type ) < 0) + return NULL; + + submodule = Py_InitModule3( "Blender.Texture", + M_Texture_methods, M_Texture_doc ); + + if( Types ) + PyModule_AddObject( submodule, "Types", Types ); + if( STypes ) + PyModule_AddObject( submodule, "STypes", STypes ); + if( TexCo ) + PyModule_AddObject( submodule, "TexCo", TexCo ); + if( MapTo ) + PyModule_AddObject( submodule, "MapTo", MapTo ); + if( Flags ) + PyModule_AddObject( submodule, "Flags", Flags ); + if( ExtendModes ) + PyModule_AddObject( submodule, "ExtendModes", ExtendModes ); + if( ImageFlags ) + PyModule_AddObject( submodule, "ImageFlags", ImageFlags ); + if( Noise ) + PyModule_AddObject( submodule, "Noise", Noise ); + if ( BlendModes ) + PyModule_AddObject( submodule, "BlendModes", BlendModes ); + if ( Mappings ) + PyModule_AddObject( submodule, "Mappings", Mappings ); + if ( Proj ) + PyModule_AddObject( submodule, "Proj", Proj ); + + /* Add the MTex submodule to this module */ + dict = PyModule_GetDict( submodule ); + PyDict_SetItemString( dict, "MTex", MTex_Init( ) ); + + return submodule; +} + +PyObject *Texture_CreatePyObject( Tex * tex ) +{ + BPy_Texture *pytex; + + pytex = ( BPy_Texture * ) PyObject_NEW( BPy_Texture, &Texture_Type ); + if( !pytex ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create BPy_Texture PyObject" ); + + pytex->texture = tex; + return ( PyObject * ) pytex; +} + +Tex *Texture_FromPyObject( PyObject * pyobj ) +{ + return ( ( BPy_Texture * ) pyobj )->texture; +} + +/*****************************************************************************/ +/* Python BPy_Texture methods: */ +/*****************************************************************************/ + +static PyObject *Texture_getExtend( BPy_Texture * self ) +{ + const char *extend = NULL; + + if( EXPP_map_getStrVal + ( tex_extend_map, self->texture->extend, &extend ) ) + return PyString_FromString( extend ); + + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "invalid internal extend mode" ); +} + +static PyObject *Texture_getImage( BPy_Texture * self ) +{ + /* we need this to be an IMAGE texture, and we must have an image */ + if( ( self->texture->type == TEX_IMAGE || + self->texture->type == TEX_ENVMAP ) + && self->texture->ima ) + return Image_CreatePyObject( self->texture->ima ); + + Py_RETURN_NONE; +} + +static PyObject *Texture_oldgetSType( BPy_Texture * self ) +{ + const char *stype = NULL; + int n_stype; + + if( self->texture->type == TEX_VORONOI ) + n_stype = self->texture->vn_coltype; +#if 0 + else if( self->texture->type == TEX_MUSGRAVE ) + n_stype = self->texture->noisebasis; +#endif + else if( self->texture->type == TEX_ENVMAP ) + n_stype = self->texture->env->stype; + else + n_stype = self->texture->stype; + + if( EXPP_map_getStrVal( tex_stype_map[self->texture->type], + n_stype, &stype ) ) + return PyString_FromString( stype ); + + + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "invalid texture stype internally" ); +} + +static PyObject *Texture_oldgetType( BPy_Texture * self ) +{ + const char *type = NULL; + + if( EXPP_map_getStrVal( tex_type_map, self->texture->type, &type ) ) + return PyString_FromString( type ); + + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "invalid texture type internally" ); +} + +static int Texture_setAnimFrames( BPy_Texture * self, PyObject * value ) +{ + return EXPP_setIValueClamped ( value, &self->texture->iuser.frames, + EXPP_TEX_ANIMFRAME_MIN, + EXPP_TEX_ANIMFRAME_MAX, 'h' ); +} + +static int Texture_setIUserCyclic( BPy_Texture * self, PyObject * value ) +{ + int param = PyObject_IsTrue( value ); + if( param == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected True/False or 0/1" ); + + if( param ) + self->texture->iuser.cycl = 1; + else + self->texture->iuser.cycl = 0; + return 0; +} + +#if 0 +/* this was stupid to begin with! (ton) */ +static int Texture_setAnimLength( BPy_Texture * self, PyObject * value ) +{ + return EXPP_setIValueClamped ( value, &self->texture->len, + EXPP_TEX_ANIMLEN_MIN, + EXPP_TEX_ANIMLEN_MAX, 'h' ); +} + +/* this is too simple to keep supporting? disabled for time being (ton) */ +static int Texture_setAnimMontage( BPy_Texture * self, PyObject * value ) +{ + int fradur[4][2]; + int i; + + if( !PyArg_ParseTuple( value, "(ii)(ii)(ii)(ii)", + &fradur[0][0], &fradur[0][1], + &fradur[1][0], &fradur[1][1], + &fradur[2][0], &fradur[2][1], + &fradur[3][0], &fradur[3][1] ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a tuple of tuples" ); + + for( i = 0; i < 4; ++i ) { + self->texture->fradur[i][0] = + (short)EXPP_ClampInt ( fradur[i][0], EXPP_TEX_ANIMMONSTART_MIN, + EXPP_TEX_ANIMMONSTART_MAX ); + self->texture->fradur[i][1] = + (short)EXPP_ClampInt ( fradur[i][1], EXPP_TEX_ANIMMONDUR_MIN, + EXPP_TEX_ANIMMONDUR_MAX ); + } + + return 0; +} +#endif + +static int Texture_setAnimOffset( BPy_Texture * self, PyObject * value ) +{ + return EXPP_setIValueClamped ( value, &self->texture->iuser.offset, + EXPP_TEX_ANIMOFFSET_MIN, + EXPP_TEX_ANIMOFFSET_MAX, 'h' ); +} + +static int Texture_setAnimStart( BPy_Texture * self, PyObject * value ) +{ + return EXPP_setIValueClamped ( value, &self->texture->iuser.sfra, + EXPP_TEX_ANIMSTART_MIN, + EXPP_TEX_ANIMSTART_MAX, 'h' ); +} + +static int Texture_setBrightness( BPy_Texture * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->texture->bright, + EXPP_TEX_BRIGHTNESS_MIN, + EXPP_TEX_BRIGHTNESS_MAX ); +} + +static int Texture_setContrast( BPy_Texture * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->texture->contrast, + EXPP_TEX_CONTRAST_MIN, + EXPP_TEX_CONTRAST_MAX ); +} + +static int Texture_setCrop( BPy_Texture * self, PyObject * value ) +{ + float crop[4]; + + if( !PyArg_ParseTuple( value, "ffff", + &crop[0], &crop[1], &crop[2], &crop[3] ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected tuple of 4 floats" ); + + self->texture->cropxmin = EXPP_ClampFloat( crop[0], EXPP_TEX_CROP_MIN, + EXPP_TEX_CROP_MAX ); + self->texture->cropymin = EXPP_ClampFloat( crop[1], EXPP_TEX_CROP_MIN, + EXPP_TEX_CROP_MAX ); + self->texture->cropxmax = EXPP_ClampFloat( crop[2], EXPP_TEX_CROP_MIN, + EXPP_TEX_CROP_MAX ); + self->texture->cropymax = EXPP_ClampFloat( crop[3], EXPP_TEX_CROP_MIN, + EXPP_TEX_CROP_MAX ); + + return 0; +} + +static int Texture_setIntExtend( BPy_Texture * self, PyObject * value ) +{ + return EXPP_setIValueRange ( value, &self->texture->extend, + EXPP_TEX_EXTEND_MIN, + EXPP_TEX_EXTEND_MAX, 'h' ); +} + +static int Texture_setFieldsPerImage( BPy_Texture * self, + PyObject * value ) +{ + return EXPP_setIValueClamped ( value, &self->texture->iuser.fie_ima, + EXPP_TEX_FIEIMA_MIN, + EXPP_TEX_FIEIMA_MAX, 'h' ); + +} + +static int Texture_setFilterSize( BPy_Texture * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->texture->filtersize, + EXPP_TEX_FILTERSIZE_MIN, + EXPP_TEX_FILTERSIZE_MAX ); +} + +static int Texture_setFlags( BPy_Texture * self, PyObject * value ) +{ + int param; + + if( !PyInt_Check( value ) ) { + char errstr[128]; + sprintf ( errstr , "expected int bitmask of 0x%08x", TEX_FLAG_MASK ); + return EXPP_ReturnIntError( PyExc_TypeError, errstr ); + } + param = PyInt_AS_LONG ( value ); + + if ( ( param & TEX_FLAG_MASK ) != param ) + return EXPP_ReturnIntError( PyExc_ValueError, + "invalid bit(s) set in mask" ); + + self->texture->flag = (short)param; + +#if 0 + /* if Colorband enabled, make sure we allocate memory for it */ + + if ( ( param & TEX_COLORBAND ) && !self->texture->coba ) + self->texture->coba = add_colorband(); +#endif + + return 0; +} + +static int Texture_setImage( BPy_Texture * self, PyObject * value ) +{ + Image *blimg = NULL; + + if( !BPy_Image_Check (value) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected an Image" ); + blimg = Image_FromPyObject( value ); + + if( self->texture->ima ) { + self->texture->ima->id.us--; + } + + self->texture->ima = blimg; + id_us_plus( &blimg->id ); + + return 0; +} + +static int Texture_setImageFlags( BPy_Texture * self, PyObject * value, + void *type ) +{ + short param; + + /* + * if type is non-zero, then attribute is "mipmap", "calcAlpha", etc., + * so set/clear the bit in the bitfield based on the type + */ + + if( (int)type ) { + int err; + param = self->texture->imaflag; + err = EXPP_setBitfield( value, ¶m, (int)type, 'h' ); + if( err ) + return err; + + /* + * if type is zero, then attribute is "imageFlags", so check + * value for a valid bitmap range. + */ + + } else { + int bitmask = TEX_INTERPOL + | TEX_USEALPHA + | TEX_MIPMAP + | TEX_IMAROT + | TEX_CALCALPHA + | TEX_NORMALMAP; + + if( !PyInt_Check( value ) ) { + char errstr[128]; + sprintf ( errstr , "expected int bitmask of 0x%08x", bitmask ); + return EXPP_ReturnIntError( PyExc_TypeError, errstr ); + } + + param = (short)PyInt_AS_LONG( value ); + if( ( param & bitmask ) != param ) + return EXPP_ReturnIntError( PyExc_ValueError, + "invalid bit(s) set in mask" ); + } + + /* everything is OK; save the new flag setting */ + + self->texture->imaflag = param; + return 0; +} + +static int Texture_setIUserFlags( BPy_Texture * self, PyObject * value, + void *flag ) +{ + int param = PyObject_IsTrue( value ); + if( param == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected True/False or 0/1" ); + + if( param ) + self->texture->iuser.flag |= (int)flag; + else + self->texture->iuser.flag &= ~(int)flag; + return 0; +} + +static int Texture_setNoiseDepth( BPy_Texture * self, PyObject * value ) +{ + short max = EXPP_TEX_NOISEDEPTH_MAX; + + /* for whatever reason, magic texture has a different max value */ + + if( self->texture->type == TEX_MAGIC ) + max = EXPP_TEX_NOISEDEPTH_MAX_MAGIC; + + return EXPP_setIValueClamped ( value, &self->texture->noisedepth, + EXPP_TEX_NOISEDEPTH_MIN, max, 'h' ); +} + +static int Texture_setNoiseSize( BPy_Texture * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->texture->noisesize, + EXPP_TEX_NOISESIZE_MIN, + EXPP_TEX_NOISESIZE_MAX ); +} + +static int Texture_setNoiseType( BPy_Texture * self, PyObject * value ) +{ + char *param; + + if( !PyString_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected string argument" ); + param = PyString_AS_STRING( value ); + + if( STREQ( param, "soft" ) ) + self->texture->noisetype = TEX_NOISESOFT; + else if( STREQ( param, "hard" ) ) + self->texture->noisetype = TEX_NOISEPERL; + else + return EXPP_ReturnIntError( PyExc_ValueError, + "noise type must be 'soft' or 'hard'" ); + + return 0; +} + +static int Texture_setNoiseBasis( BPy_Texture * self, PyObject * value ) +{ + int param; + + if( !PyInt_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected int (see 'Noise' constant dictionary)" ); + + param = PyInt_AS_LONG ( value ); + + if ( param < TEX_BLENDER + || ( param > TEX_VORONOI_CRACKLE + && param != TEX_CELLNOISE ) ) + return EXPP_ReturnIntError( PyExc_ValueError, + "invalid noise type" ); + + self->texture->noisebasis = (short)param; + return 0; +} + +static int Texture_setNoiseBasis2( BPy_Texture * self, PyObject * value, + void *type ) +{ + /* + * if type is EXPP_TEX_NOISEBASIS2, then this is the "noiseBasis2" + * attribute, so check the range and set the whole value + */ + + if( (int)type == EXPP_TEX_NOISEBASIS2 ) { + int param; + if( !PyInt_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected int (see 'Noise' constant dictionary)" ); + + param = PyInt_AS_LONG ( value ); + + if ( param < TEX_BLENDER + || ( param > TEX_VORONOI_CRACKLE + && param != TEX_CELLNOISE ) ) + return EXPP_ReturnIntError( PyExc_ValueError, + "invalid noise type" ); + + self->texture->noisebasis2 = (short)param; + + /* + * for other type values, the attribute is "sine", "saw" or "tri", + * so set the noise basis to the supplied type if value is 1 + */ + + } else { + if( !PyInt_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected int value of 1" ); + + if( PyInt_AS_LONG ( value ) != 1 ) + return EXPP_ReturnIntError( PyExc_ValueError, + "expected int value of 1" ); + + self->texture->noisebasis2 = (short)(int)type; + } + return 0; +} + +static int Texture_setRepeat( BPy_Texture * self, PyObject * args ) +{ + int repeat[2]; + + if( !PyArg_ParseTuple( args, "ii", &repeat[0], &repeat[1] ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected tuple of 2 ints" ); + + self->texture->xrepeat = (short)EXPP_ClampInt( repeat[0], EXPP_TEX_REPEAT_MIN, + EXPP_TEX_REPEAT_MAX ); + self->texture->yrepeat = (short)EXPP_ClampInt( repeat[1], EXPP_TEX_REPEAT_MIN, + EXPP_TEX_REPEAT_MAX ); + + return 0; +} + +static int Texture_setRGBCol( BPy_Texture * self, PyObject * args ) +{ + float rgb[3]; + + if( !PyArg_ParseTuple( args, "fff", &rgb[0], &rgb[1], &rgb[2] ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected tuple of 3 floats" ); + + self->texture->rfac = EXPP_ClampFloat( rgb[0], EXPP_TEX_RGBCOL_MIN, + EXPP_TEX_RGBCOL_MAX ); + self->texture->gfac = EXPP_ClampFloat( rgb[1], EXPP_TEX_RGBCOL_MIN, + EXPP_TEX_RGBCOL_MAX ); + self->texture->bfac = EXPP_ClampFloat( rgb[2], EXPP_TEX_RGBCOL_MIN, + EXPP_TEX_RGBCOL_MAX ); + + return 0; +} + +static int Texture_setSType( BPy_Texture * self, PyObject * value ) +{ + short param; + const char *dummy = NULL; + + if( !PyInt_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected int argument" ); + + param = (short)PyInt_AS_LONG ( value ); + + /* use the stype map to find out if this is a valid stype for this type * + * note that this will allow CLD_COLOR when type is ENVMAP. there's not * + * much that we can do about this though. */ + if( !EXPP_map_getStrVal + ( tex_stype_map[self->texture->type], param, &dummy ) ) + return EXPP_ReturnIntError( PyExc_ValueError, + "invalid stype (for this type)" ); + + if( self->texture->type == TEX_VORONOI ) + self->texture->vn_coltype = param; +#if 0 + else if( self->texture->type == TEX_MUSGRAVE ) + self->texture->noisebasis = param; +#endif + else if( self->texture->type == TEX_ENVMAP ) + self->texture->env->stype = param; + else + self->texture->stype = param; + + return 0; +} + +static int Texture_setTurbulence( BPy_Texture * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->texture->turbul, + EXPP_TEX_TURBULENCE_MIN, + EXPP_TEX_TURBULENCE_MAX ); +} + +static int Texture_setHFracDim( BPy_Texture * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->texture->mg_H, + EXPP_TEX_MH_G_MIN, + EXPP_TEX_MH_G_MAX ); +} + +static int Texture_setLacunarity( BPy_Texture * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->texture->mg_lacunarity, + EXPP_TEX_LACUNARITY_MIN, + EXPP_TEX_LACUNARITY_MAX ); +} + +static int Texture_setOcts( BPy_Texture * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->texture->mg_octaves, + EXPP_TEX_OCTS_MIN, + EXPP_TEX_OCTS_MAX ); +} + +static int Texture_setIScale( BPy_Texture * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->texture->ns_outscale, + EXPP_TEX_ISCALE_MIN, + EXPP_TEX_ISCALE_MAX ); +} + +static int Texture_setType( BPy_Texture * self, PyObject * value ) +{ + int err = EXPP_setIValueRange ( value, &self->texture->type, + EXPP_TEX_TYPE_MIN, + EXPP_TEX_TYPE_MAX, 'h' ); + + /* + * if we set the texture OK, and it's a environment map, and + * there is no environment map yet, allocate one (code borrowed + * from texture_panel_envmap() in source/blender/src/buttons_shading.c) + */ + + if( !err && self->texture->type == TEX_ENVMAP + && !self->texture->env ) { + self->texture->env = BKE_add_envmap(); + self->texture->env->object= OBACT; + } + return err; +} + +static int Texture_setDistMetric( BPy_Texture * self, PyObject * value ) +{ +#if 0 + char *dist = NULL; + + if( !PyArg_ParseTuple( value, "s", &dist ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + + /* can we really trust texture->type? */ + if( self->texture->type == TEX_VORONOI && + !EXPP_map_getShortVal( tex_stype_map[self->texture->type + 2], + dist, &self->texture->vn_distm ) ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "invalid dist metric type" ); + + Py_RETURN_NONE; +#else + return EXPP_setIValueRange ( value, &self->texture->vn_distm, + TEX_DISTANCE, + TEX_MINKOVSKY, 'h' ); +#endif +} + +static int Texture_setExp( BPy_Texture * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->texture->vn_mexp, + EXPP_TEX_EXP_MIN, + EXPP_TEX_EXP_MAX ); +} + +static int Texture_setWeight1( BPy_Texture * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->texture->vn_w1, + EXPP_TEX_WEIGHT1_MIN, + EXPP_TEX_WEIGHT1_MAX ); +} + +static int Texture_setWeight2( BPy_Texture * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->texture->vn_w2, + EXPP_TEX_WEIGHT2_MIN, + EXPP_TEX_WEIGHT2_MAX ); +} + +static int Texture_setWeight3( BPy_Texture * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->texture->vn_w3, + EXPP_TEX_WEIGHT3_MIN, + EXPP_TEX_WEIGHT3_MAX ); +} + +static int Texture_setWeight4( BPy_Texture * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->texture->vn_w4, + EXPP_TEX_WEIGHT4_MIN, + EXPP_TEX_WEIGHT4_MAX ); +} + +static int Texture_setDistAmnt( BPy_Texture * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->texture->dist_amount, + EXPP_TEX_DISTAMNT_MIN, + EXPP_TEX_DISTAMNT_MAX ); +} + +static PyObject *Texture_getIpo( BPy_Texture * self ) +{ + struct Ipo *ipo = self->texture->ipo; + + if( !ipo ) + Py_RETURN_NONE; + + return Ipo_CreatePyObject( ipo ); +} + +/* + * this should accept a Py_None argument and just delete the Ipo link + * (as Texture_clearIpo() does) + */ + +static int Texture_setIpo( BPy_Texture * self, PyObject * value ) +{ + Ipo *ipo = NULL; + Ipo *oldipo = self->texture->ipo; + ID *id; + + /* if parameter is not None, check for valid Ipo */ + + if ( value != Py_None ) { + if ( !BPy_Ipo_Check( value ) ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "expected an Ipo object" ); + + ipo = Ipo_FromPyObject( value ); + + if( !ipo ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "null ipo!" ); + + if( ipo->blocktype != ID_TE ) + return EXPP_ReturnIntError( PyExc_TypeError, + "Ipo is not a texture data Ipo" ); + } + + /* if already linked to Ipo, delete link */ + + if ( oldipo ) { + id = &oldipo->id; + if( id->us > 0 ) + id->us--; + } + + /* assign new Ipo and increment user count, or set to NULL if deleting */ + + self->texture->ipo = ipo; + if ( ipo ) { + id = &ipo->id; + id_us_plus(id); + } + + return 0; +} + +static PyObject *Texture_getAnimFrames( BPy_Texture *self ) +{ + return PyInt_FromLong( self->texture->iuser.frames ); +} + +static PyObject *Texture_getIUserCyclic( BPy_Texture *self ) +{ + if( self->texture->iuser.cycl ) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +#if 0 +/* disabled. this option was too stupid! (ton) */ +static PyObject *Texture_getAnimLength( BPy_Texture *self ) +{ + return PyInt_FromLong( self->texture->len ); +} + +static PyObject *Texture_getAnimMontage( BPy_Texture *self ) +{ + return Py_BuildValue( "((i,i),(i,i),(i,i),(i,i))", + self->texture->fradur[0][0], + self->texture->fradur[0][1], + self->texture->fradur[1][0], + self->texture->fradur[1][1], + self->texture->fradur[2][0], + self->texture->fradur[2][1], + self->texture->fradur[3][0], + self->texture->fradur[3][1] ); +} +#endif + +static PyObject *Texture_getAnimOffset( BPy_Texture *self ) +{ + return PyInt_FromLong( self->texture->iuser.offset ); +} + +static PyObject *Texture_getAnimStart( BPy_Texture *self ) +{ + return PyInt_FromLong( self->texture->iuser.sfra ); +} + +static PyObject *Texture_getBrightness( BPy_Texture *self ) +{ + return PyFloat_FromDouble ( self->texture->bright ); +} + +static PyObject *Texture_getContrast( BPy_Texture *self ) +{ + return PyFloat_FromDouble( self->texture->contrast ); +} + +static PyObject *Texture_getCrop( BPy_Texture *self ) +{ + return Py_BuildValue( "(f,f,f,f)", + self->texture->cropxmin, + self->texture->cropymin, + self->texture->cropxmax, + self->texture->cropymax ); +} + +static PyObject *Texture_getDistAmnt( BPy_Texture *self ) +{ + return PyFloat_FromDouble( self->texture->dist_amount ); +} + +static PyObject *Texture_getDistMetric( BPy_Texture *self ) +{ + return PyInt_FromLong( self->texture->vn_distm ); +} + +static PyObject *Texture_getExp( BPy_Texture *self ) +{ + return PyFloat_FromDouble( self->texture->vn_mexp ); +} + +static PyObject *Texture_getIntExtend( BPy_Texture * self ) +{ + return PyInt_FromLong( self->texture->extend ); +} + +static PyObject *Texture_getFieldsPerImage( BPy_Texture *self ) +{ + return PyInt_FromLong( self->texture->iuser.fie_ima ); +} + +static PyObject *Texture_getFilterSize( BPy_Texture *self ) +{ + return PyFloat_FromDouble( self->texture->filtersize ); +} + +static PyObject *Texture_getFlags( BPy_Texture *self ) +{ + return PyInt_FromLong( self->texture->flag ); +} + +static PyObject *Texture_getHFracDim( BPy_Texture *self ) +{ + return PyInt_FromLong( (long)self->texture->mg_H ); +} + +static PyObject *Texture_getImageFlags( BPy_Texture *self, void *type ) +{ + /* type == 0 means attribute "imageFlags" + * other types means attribute "mipmap", "calcAlpha", etc + */ + + if( (int)type ) + return EXPP_getBitfield( &self->texture->imaflag, (int)type, 'h' ); + else + return PyInt_FromLong( self->texture->imaflag ); +} + +static PyObject *Texture_getIUserFlags( BPy_Texture *self, void *flag ) +{ + if( self->texture->iuser.flag & (int)flag ) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +static PyObject *Texture_getIScale( BPy_Texture *self ) +{ + return PyFloat_FromDouble( self->texture->ns_outscale ); +} + +static PyObject *Texture_getLacunarity( BPy_Texture *self ) +{ + return PyFloat_FromDouble( self->texture->mg_lacunarity ); +} + +static PyObject *Texture_getNoiseBasis( BPy_Texture *self ) +{ + return PyInt_FromLong( self->texture->noisebasis ); +} + +static PyObject *Texture_getNoiseBasis2( BPy_Texture *self, void *type ) +{ + /* type == EXPP_TEX_NOISEBASIS2 means attribute "noiseBasis2" + * other types means attribute "sine", "saw", or "tri" attribute + */ + + if( (int)type == EXPP_TEX_NOISEBASIS2 ) + return PyInt_FromLong( self->texture->noisebasis2 ); + else + return PyInt_FromLong( ( self->texture->noisebasis2 == (int)type ) ? 1 : 0 ); +} + +static PyObject *Texture_getNoiseDepth( BPy_Texture *self ) +{ + return PyInt_FromLong( self->texture->noisedepth ); +} + +static PyObject *Texture_getNoiseSize( BPy_Texture *self ) +{ + return PyFloat_FromDouble( self->texture->noisesize ); +} + +static PyObject *Texture_getNoiseType( BPy_Texture *self ) +{ + if ( self->texture->noisetype == TEX_NOISESOFT ) + return PyString_FromString( "soft" ); + else + return PyString_FromString( "hard" ); +} + +static PyObject *Texture_getOcts( BPy_Texture *self ) +{ + return PyFloat_FromDouble( self->texture->mg_octaves ); +} + +static PyObject *Texture_getRepeat( BPy_Texture *self ) +{ + return Py_BuildValue( "(i,i)", self->texture->xrepeat, + self->texture->yrepeat ); +} + +static PyObject *Texture_getRGBCol( BPy_Texture *self ) +{ + return Py_BuildValue( "(f,f,f)", self->texture->rfac, + self->texture->gfac, self->texture->bfac ); +} + +static PyObject *Texture_getSType( BPy_Texture *self ) +{ + if( self->texture->type == TEX_VORONOI ) + return PyInt_FromLong( self->texture->vn_coltype ); +#if 0 + if( self->texture->type == TEX_MUSGRAVE ) + return PyInt_FromLong( self->texture->noisebasis ); +#endif + if( self->texture->type == TEX_ENVMAP ) + return PyInt_FromLong( self->texture->env->stype ); + + return PyInt_FromLong( self->texture->stype ); +} + +static PyObject *Texture_getTurbulence( BPy_Texture *self ) +{ + return PyFloat_FromDouble( self->texture->turbul ); +} + +static PyObject *Texture_getType( BPy_Texture *self ) +{ + return PyInt_FromLong( self->texture->type ); +} + +static PyObject *Texture_getWeight1( BPy_Texture *self ) +{ + return PyFloat_FromDouble( self->texture->vn_w1 ); +} + +static PyObject *Texture_getWeight2( BPy_Texture *self ) +{ + return PyFloat_FromDouble( self->texture->vn_w2 ); +} + +static PyObject *Texture_getWeight3( BPy_Texture *self ) +{ + return PyFloat_FromDouble( self->texture->vn_w3 ); +} + +static PyObject *Texture_getWeight4( BPy_Texture *self ) +{ + return PyFloat_FromDouble( self->texture->vn_w4 ); +} + +/* #####DEPRECATED###### */ + +static PyObject *Texture_oldsetImage( BPy_Texture * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, + (setter)Texture_setImage ); +} + +static PyObject *Texture_oldsetIpo( BPy_Texture * self, PyObject * args ) +{ + return EXPP_setterWrapper ( (void *)self, args, (setter)Texture_setIpo ); +} + +/* + * clearIpo() returns True/False depending on whether material has an Ipo + */ + +static PyObject *Texture_clearIpo( BPy_Texture * self ) +{ + /* if Ipo defined, delete it and return true */ + + if( self->texture->ipo ) { + PyObject *value = Py_BuildValue( "(O)", Py_None ); + EXPP_setterWrapper( (void *)self, value, (setter)Texture_setIpo ); + Py_DECREF( value ); + return EXPP_incr_ret_True(); + } + return EXPP_incr_ret_False(); /* no ipo found */ +} + +/* + * these older setter methods take strings as parameters; check the list of + * strings to figure out which bits to set, then call new attribute setters + * using the wrapper. + */ + +static PyObject *Texture_oldsetFlags( BPy_Texture * self, PyObject * args ) +{ + unsigned int i, flag = 0; + PyObject *value, *error; + + /* check that we're passed a tuple */ + + if ( !PyTuple_Check( args ) ) + return EXPP_ReturnPyObjError ( PyExc_AttributeError, + "expected a tuple of string arguments" ); + + /* check each argument for type, find its value */ + + for ( i = PyTuple_Size( args ); i-- ; ) { + short thisflag; + char * name = PyString_AsString( PyTuple_GET_ITEM( args, i ) ); + if( !name ) + return EXPP_ReturnPyObjError ( PyExc_AttributeError, + "expected string argument" ); + + if( !EXPP_map_getShortVal( tex_flag_map, name, &thisflag ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "unknown Texture flag argument" ) ); + + flag |= thisflag; + } + + /* build tuple, call wrapper */ + + value = Py_BuildValue( "(i)", flag ); + error = EXPP_setterWrapper( (void *)self, value, (setter)Texture_setFlags ); + Py_DECREF ( value ); + return error; +} + +/* + * Texture_oldsetType() and Texture_oldsetExtend() + * + * These older setter methods convert a string into an integer setting, so + * doesn't make sense to try wrapping them. + */ + +static PyObject *Texture_oldsetType( BPy_Texture * self, PyObject * args ) +{ + char *type = NULL; + + if( !PyArg_ParseTuple( args, "s", &type ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + + if( !EXPP_map_getShortVal( tex_type_map, type, &self->texture->type ) ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "invalid texture type" ); + + /* + * if we set the texture OK, and it's a environment map, and + * there is no environment map yet, allocate one (code borrowed + * from texture_panel_envmap() in source/blender/src/buttons_shading.c) + */ + + if( self->texture->type == TEX_ENVMAP + && !self->texture->env ) { + self->texture->env = BKE_add_envmap(); + self->texture->env->object= OBACT; + } + + Py_RETURN_NONE; +} + +static PyObject *Texture_oldsetExtend( BPy_Texture * self, PyObject * args ) +{ + char *extend = NULL; + if( !PyArg_ParseTuple( args, "s", &extend ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + + if( !EXPP_map_getShortVal + ( tex_extend_map, extend, &self->texture->extend ) ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "invalid extend mode" ); + + Py_RETURN_NONE; +} + +/* + * Texture_oldsetNoiseBasis(), Texture_oldsetDistNoise() + * Texture_oldsetSType(), Texture_oldsetDistMetric(), + * Texture_oldsetImageFlags() + * + * these old setter methods behave differently from the attribute + * setters, so they are left unchanged. + */ + +static PyObject *Texture_oldsetNoiseBasis( BPy_Texture * self, PyObject * args ) +{ +/* NOTE: leave as-is: don't use setterWrapper */ + char *nbasis; + + if( !PyArg_ParseTuple( args, "s", &nbasis ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + if( self->texture->type == TEX_MUSGRAVE && + EXPP_map_getShortVal( tex_stype_map[TEX_DISTNOISE], + nbasis, &self->texture->noisebasis ) ); + else if( self->texture->type == TEX_DISTNOISE && + !EXPP_map_getShortVal( tex_stype_map[TEX_DISTNOISE], + nbasis, &self->texture->noisebasis2 ) ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "invalid noise basis" ); + + Py_RETURN_NONE; +} + +static PyObject *Texture_oldsetDistNoise( BPy_Texture * self, PyObject * args ) +{ +/* NOTE: leave as-is: don't use setterWrapper */ + char *nbasis; + + if( !PyArg_ParseTuple( args, "s", &nbasis ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + if( self->texture->type == TEX_DISTNOISE && + !EXPP_map_getShortVal( tex_stype_map[TEX_DISTNOISE], + nbasis, &self->texture->noisebasis ) ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "invalid noise basis" ); + + Py_RETURN_NONE; +} + +static PyObject *Texture_oldsetSType( BPy_Texture * self, PyObject * args ) +{ + char *stype = NULL; + if( !PyArg_ParseTuple( args, "s", &stype ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + + /* can we really trust texture->type? */ + if( ( self->texture->type == TEX_VORONOI && + EXPP_map_getShortVal( tex_stype_map[self->texture->type], + stype, &self->texture->vn_coltype ) ) ); +#if 0 + else if( ( self->texture->type == TEX_MUSGRAVE && + EXPP_map_getShortVal( tex_stype_map + [TEX_DISTNOISE], stype, + &self->texture->noisebasis ) ) ); +#endif + else if( ( self->texture->type == TEX_ENVMAP && + EXPP_map_getShortVal( tex_stype_map[self->texture->type], + stype, &self->texture->env->stype ) ) ); + else if( !EXPP_map_getShortVal + ( tex_stype_map[self->texture->type], stype, + &self->texture->stype ) ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "invalid texture stype" ); + + Py_RETURN_NONE; +} + +static PyObject *Texture_oldsetDistMetric( BPy_Texture * self, PyObject * args ) +{ +/* NOTE: leave as-is: don't use setterWrapper */ + char *dist = NULL; + + if( !PyArg_ParseTuple( args, "s", &dist ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + /* can we really trust texture->type? */ + if( self->texture->type == TEX_VORONOI && + !EXPP_map_getShortVal( tex_stype_map[self->texture->type + 2], + dist, &self->texture->vn_distm ) ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "invalid dist metric type" ); + + Py_RETURN_NONE; +} + +static PyObject *Texture_oldsetImageFlags( BPy_Texture * self, PyObject * args ) +{ + unsigned int i, flag = 0; + + /* check that we're passed a tuple of no more than 3 args*/ + + if( !PyTuple_Check( args ) ) + return EXPP_ReturnPyObjError ( PyExc_AttributeError, + "expected tuple of string arguments" ); + + /* check each argument for type, find its value */ + + for( i = PyTuple_Size( args ); i-- ; ) { + short thisflag; + char * name = PyString_AsString( PyTuple_GET_ITEM( args, i ) ); + if( !name ) + return EXPP_ReturnPyObjError ( PyExc_AttributeError, + "expected string argument" ); + + if( !EXPP_map_getShortVal( tex_imageflag_map, name, &thisflag ) ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "unknown Texture image flag name" ); + + flag |= thisflag; + } + + self->texture->imaflag = (short)flag; + + Py_RETURN_NONE; +} + +static PyObject *Texture_getColorband( BPy_Texture * self) +{ + return EXPP_PyList_fromColorband( self->texture->coba ); +} + +int Texture_setColorband( BPy_Texture * self, PyObject * value) +{ + return EXPP_Colorband_fromPyList( &self->texture->coba, value ); +} + +static PyObject *Texture_evaluate( BPy_Texture * self, VectorObject * vec_in ) +{ + TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL}; + float vec[4]; + /* int rgbnor; dont use now */ + + if(!VectorObject_Check(vec_in) || vec_in->size < 3) + return EXPP_ReturnPyObjError(PyExc_TypeError, + "expects a 3D vector object"); + + /* rgbnor = .. we don't need this now */ + multitex_ext(self->texture, vec_in->vec, NULL, NULL, 1, &texres); + + vec[0] = texres.tr; + vec[1] = texres.tg; + vec[2] = texres.tb; + vec[3] = texres.tin; + + return newVectorObject(vec, 4, Py_NEW); +} + +static PyObject *Texture_copy( BPy_Texture * self ) +{ + Tex *tex = copy_texture(self->texture ); + tex->id.us = 0; + return Texture_CreatePyObject(tex); +} diff --git a/source/blender/python/api2_2x/Texture.h b/source/blender/python/api2_2x/Texture.h new file mode 100644 index 00000000000..a5451687779 --- /dev/null +++ b/source/blender/python/api2_2x/Texture.h @@ -0,0 +1,64 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Alex Mole + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +/* based on Image.h */ + +#ifndef EXPP_TEXTURE_H +#define EXPP_TEXTURE_H + +#include +#include "DNA_texture_types.h" + +/*****************************************************************************/ +/* Python BPy_Texture structure definition */ +/*****************************************************************************/ + +typedef struct { + PyObject_HEAD + Tex * texture; /* libdata must be second */ +} BPy_Texture; + +extern PyTypeObject Texture_Type; + +#define BPy_Texture_Check(v) ((v)->ob_type == &Texture_Type) + + +/*****************************************************************************/ +/* Module Blender.Texture - public functions */ +/*****************************************************************************/ + +PyObject *Texture_Init( void ); +PyObject *Texture_CreatePyObject( struct Tex *tex ); +Tex *Texture_FromPyObject( PyObject * pyobj ); + + +#endif /* EXPP_TEXTURE_H */ diff --git a/source/blender/python/api2_2x/Types.c b/source/blender/python/api2_2x/Types.c new file mode 100644 index 00000000000..8b51c590a5b --- /dev/null +++ b/source/blender/python/api2_2x/Types.c @@ -0,0 +1,262 @@ +/* + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano, Alex Mole, Joseph Gilbert + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#include "Types.h" +#include "IDProp.h" +/* + stuff pasted from the old Types.h + is only need here now +*/ + +extern PyTypeObject IDGroup_Type, IDArray_Type; +extern PyTypeObject Action_Type, Armature_Type; +extern PyTypeObject Pose_Type; +extern PyTypeObject BezTriple_Type, Bone_Type, Button_Type; +extern PyTypeObject Camera_Type; +extern PyTypeObject CurNurb_Type, SurfNurb_Type; +extern PyTypeObject Curve_Type; +extern PyTypeObject Effect_Type, Font_Type; +extern PyTypeObject Image_Type, Ipo_Type, IpoCurve_Type; +extern PyTypeObject Lamp_Type, Lattice_Type; +extern PyTypeObject Material_Type, Metaball_Type, MTex_Type; +extern PyTypeObject NMFace_Type, NMEdge_Type, NMVert_Type, NMCol_Type, + NMesh_Type; +extern PyTypeObject MFace_Type, MVert_Type, PVert_Type, MEdge_Type, MCol_Type, + Mesh_Type; + +extern PyTypeObject Object_Type; +extern PyTypeObject Group_Type; +extern PyTypeObject Particle_Type; +extern PyTypeObject Scene_Type, RenderData_Type; +extern PyTypeObject Text_Type, Text3d_Type, Texture_Type; +extern PyTypeObject World_Type; +extern PyTypeObject property_Type; +extern PyTypeObject buffer_Type, constant_Type, euler_Type; +extern PyTypeObject matrix_Type, quaternion_Type, rgbTuple_Type, vector_Type; +extern PyTypeObject point_Type; +extern PyTypeObject Modifier_Type, ModSeq_Type; +extern PyTypeObject EditBone_Type; +extern PyTypeObject ThemeSpace_Type; +extern PyTypeObject ThemeUI_Type; +extern PyTypeObject TimeLine_Type; + +char M_Types_doc[] = "The Blender Types module\n\n\ +This module is a dictionary of all Blender Python types"; + +struct PyMethodDef Null_methods[] = { {NULL, NULL, 0, NULL} }; + + + +/* The internal types (lowercase first letter, like constant_Type) are only + * set when some object initializes them. But unless we do it early, we get + * some easy and unpredictable (varies with platform, even distro) ways to + * crash Blender. Some modules also need this early up, so let's generalize + * and init all our pytypes here. + */ + +void types_InitAll( void ) +{ + Action_Type.ob_type = &PyType_Type; + Pose_Type.ob_type = &PyType_Type; + Armature_Type.ob_type = &PyType_Type; + BezTriple_Type.ob_type = &PyType_Type; + Bone_Type.ob_type = &PyType_Type; + Button_Type.ob_type = &PyType_Type; + Camera_Type.ob_type = &PyType_Type; + CurNurb_Type.ob_type = &PyType_Type; + Curve_Type.ob_type = &PyType_Type; + Effect_Type.ob_type = &PyType_Type; + Image_Type.ob_type = &PyType_Type; + Ipo_Type.ob_type = &PyType_Type; + IpoCurve_Type.ob_type = &PyType_Type; + Lamp_Type.ob_type = &PyType_Type; + Lattice_Type.ob_type = &PyType_Type; + Material_Type.ob_type = &PyType_Type; + Metaball_Type.ob_type = &PyType_Type; + MTex_Type.ob_type = &PyType_Type; + NMCol_Type.ob_type = &PyType_Type; + NMFace_Type.ob_type = &PyType_Type; + NMEdge_Type.ob_type = &PyType_Type; + NMVert_Type.ob_type = &PyType_Type; + NMesh_Type.ob_type = &PyType_Type; + MFace_Type.ob_type = &PyType_Type; + MVert_Type.ob_type = &PyType_Type; + PVert_Type.ob_type = &PyType_Type; + MEdge_Type.ob_type = &PyType_Type; + MCol_Type.ob_type = &PyType_Type; + Mesh_Type.ob_type = &PyType_Type; + Object_Type.ob_type = &PyType_Type; + Group_Type.ob_type = &PyType_Type; + RenderData_Type.ob_type = &PyType_Type; + Scene_Type.ob_type = &PyType_Type; + SurfNurb_Type.ob_type = &PyType_Type; + Text_Type.ob_type = &PyType_Type; + Text3d_Type.ob_type = &PyType_Type; + Texture_Type.ob_type = &PyType_Type; + //TimeLine_Type.ob_type = &PyType_Type; + World_Type.ob_type = &PyType_Type; + buffer_Type.ob_type = &PyType_Type; + constant_Type.ob_type = &PyType_Type; + euler_Type.ob_type = &PyType_Type; + matrix_Type.ob_type = &PyType_Type; + quaternion_Type.ob_type = &PyType_Type; + PyType_Ready( &rgbTuple_Type ); + vector_Type.ob_type = &PyType_Type; + property_Type.ob_type = &PyType_Type; + point_Type.ob_type = &PyType_Type; + PyType_Ready( &Modifier_Type ); + PyType_Ready( &ModSeq_Type ); + PyType_Ready( &EditBone_Type ); + PyType_Ready( &ThemeSpace_Type ); + PyType_Ready( &ThemeUI_Type ); + IDProp_Init_Types(); +} + +/*****************************************************************************/ +/* Function: Types_Init */ +/*****************************************************************************/ +PyObject *Types_Init( void ) +{ + PyObject *submodule, *dict; + + submodule = + Py_InitModule3( "Blender.Types", Null_methods, M_Types_doc ); + + dict = PyModule_GetDict( submodule ); + + /* The Blender Object Type */ + + PyDict_SetItemString( dict, "ObjectType", + ( PyObject * ) &Object_Type ); + + /* Blender Object Data Types */ + + PyDict_SetItemString( dict, "GroupType", + ( PyObject * ) &Group_Type ); + + PyDict_SetItemString( dict, "SceneType", ( PyObject * ) &Scene_Type ); + PyDict_SetItemString( dict, "RenderDataType", + ( PyObject * ) &RenderData_Type ); + + PyDict_SetItemString( dict, "NMeshType", ( PyObject * ) &NMesh_Type ); + PyDict_SetItemString( dict, "NMFaceType", + ( PyObject * ) &NMFace_Type ); + PyDict_SetItemString( dict, "NMVertType", + ( PyObject * ) &NMVert_Type ); + PyDict_SetItemString( dict, "NMEdgeType", + ( PyObject * ) &NMEdge_Type ); + PyDict_SetItemString( dict, "NMColType", ( PyObject * ) &NMCol_Type ); + + PyDict_SetItemString( dict, "MeshType", ( PyObject * ) &Mesh_Type ); + PyDict_SetItemString( dict, "MFaceType", + ( PyObject * ) &MFace_Type ); + PyDict_SetItemString( dict, "MEdgeType", + ( PyObject * ) &MEdge_Type ); + PyDict_SetItemString( dict, "MVertType", + ( PyObject * ) &MVert_Type ); + PyDict_SetItemString( dict, "PVertType", + ( PyObject * ) &PVert_Type ); + PyDict_SetItemString( dict, "MColType", ( PyObject * ) &MCol_Type ); + + PyDict_SetItemString( dict, "ArmatureType", + ( PyObject * ) &Armature_Type ); + PyDict_SetItemString( dict, "BoneType", ( PyObject * ) &Bone_Type ); + + PyDict_SetItemString( dict, "CurNurb_Type", + ( PyObject * ) &CurNurb_Type ); + PyDict_SetItemString( dict, "SurfNurb_Type", + ( PyObject * ) &SurfNurb_Type ); + PyDict_SetItemString( dict, "CurveType", ( PyObject * ) &Curve_Type ); + + PyDict_SetItemString( dict, "IpoType", ( PyObject * ) &Ipo_Type ); + PyDict_SetItemString( dict, "MetaballType", + ( PyObject * ) &Metaball_Type ); + + PyDict_SetItemString( dict, "CameraType", + ( PyObject * ) &Camera_Type ); + PyDict_SetItemString( dict, "ImageType", ( PyObject * ) &Image_Type ); + PyDict_SetItemString( dict, "LampType", ( PyObject * ) &Lamp_Type ); + PyDict_SetItemString( dict, "TextType", ( PyObject * ) &Text_Type ); + PyDict_SetItemString( dict, "Text3dType", ( PyObject * ) &Text3d_Type ); + PyDict_SetItemString( dict, "MaterialType", + ( PyObject * ) &Material_Type ); + + PyDict_SetItemString( dict, "ButtonType", + ( PyObject * ) &Button_Type ); + + PyDict_SetItemString( dict, "LatticeType", + ( PyObject * ) &Lattice_Type ); + + PyDict_SetItemString( dict, "TextureType", + ( PyObject * ) &Texture_Type ); + PyDict_SetItemString( dict, "MTexType", ( PyObject * ) &MTex_Type ); + + /* External helper Types available to the main ones above */ + + PyDict_SetItemString( dict, "vectorType", + ( PyObject * ) &vector_Type ); + PyDict_SetItemString( dict, "bufferType", + ( PyObject * ) &buffer_Type ); + PyDict_SetItemString( dict, "constantType", + ( PyObject * ) &constant_Type ); + PyDict_SetItemString( dict, "rgbTupleType", + ( PyObject * ) &rgbTuple_Type ); + PyDict_SetItemString( dict, "matrix_Type", + ( PyObject * ) &matrix_Type ); + PyDict_SetItemString( dict, "eulerType", ( PyObject * ) &euler_Type ); + PyDict_SetItemString( dict, "quaternionType", + ( PyObject * ) &quaternion_Type ); + PyDict_SetItemString( dict, "BezTripleType", + ( PyObject * ) &BezTriple_Type ); + PyDict_SetItemString( dict, "ActionType", + ( PyObject * ) &Action_Type ); + PyDict_SetItemString( dict, "PoseType", + ( PyObject * ) &Pose_Type ); + PyDict_SetItemString( dict, "propertyType", + ( PyObject * ) &property_Type ); + PyDict_SetItemString( dict, "pointType", + ( PyObject * ) &point_Type ); + PyDict_SetItemString( dict, "ModifierType", + ( PyObject * ) &Modifier_Type ); + PyDict_SetItemString( dict, "ModSeqType", + ( PyObject * ) &ModSeq_Type ); + PyDict_SetItemString( dict, "EditBoneType", + ( PyObject * ) &EditBone_Type); + PyDict_SetItemString( dict, "ThemeSpaceType", + ( PyObject * ) &ThemeSpace_Type); + PyDict_SetItemString( dict, "ThemeUI_Type", + ( PyObject * ) &ThemeUI_Type); + PyDict_SetItemString( dict, "IDGroupType", + ( PyObject * ) &IDGroup_Type); + PyDict_SetItemString( dict, "IDArrayType", + ( PyObject * ) &IDArray_Type); + return submodule; +} diff --git a/source/blender/python/api2_2x/Types.h b/source/blender/python/api2_2x/Types.h new file mode 100644 index 00000000000..adaf59bbfbf --- /dev/null +++ b/source/blender/python/api2_2x/Types.h @@ -0,0 +1,41 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano, Alex Mole + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_TYPES_H +#define EXPP_TYPES_H + +#include + +PyObject *Types_Init( void ); +void types_InitAll( void ); + +#endif /* EXPP_TYPES_H */ diff --git a/source/blender/python/api2_2x/Window.c b/source/blender/python/api2_2x/Window.c new file mode 100644 index 00000000000..323f209651a --- /dev/null +++ b/source/blender/python/api2_2x/Window.c @@ -0,0 +1,1526 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano, Tom Musgrove, Michael Reimpell, + * Yann Vernier, Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#include + +#include "BDR_editobject.h" /* enter / leave editmode */ +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_object.h" /* for during_script() and during_scriptlink() */ +#include "BKE_scene.h" /* scene_find_camera() */ +#include "BPI_script.h" +#include "BIF_mywindow.h" +#include "BIF_imasel.h" +#include "BSE_headerbuttons.h" +#include "BSE_filesel.h" +#include "BIF_editmesh.h" /* for undo_push_mesh() */ +#include "BIF_screen.h" +#include "BIF_space.h" +#include "BIF_drawtext.h" +#include "BIF_poseobject.h" +#include "DNA_view3d_types.h" +#include "DNA_space_types.h" +#include "DNA_scene_types.h" +#include "DNA_text_types.h" +#include "DNA_object_types.h" +#include "mydevice.h" +#include "blendef.h" /* OBACT */ +#include "windowTheme.h" +#include "Mathutils.h" +#include "constant.h" +#include "gen_utils.h" +#include "Armature.h" + +/* See Draw.c */ +extern int EXPP_disable_force_draw; +extern void setcameratoview3d(void); + +/*****************************************************************************/ +/* Python API function prototypes for the Window module. */ +/*****************************************************************************/ +PyObject *M_Window_Redraw( PyObject * self, PyObject * args ); +static PyObject *M_Window_RedrawAll( PyObject * self, PyObject * args ); +static PyObject *M_Window_QRedrawAll( PyObject * self, PyObject * args ); +static PyObject *M_Window_DrawProgressBar( PyObject * self, PyObject * args ); +static PyObject *M_Window_GetCursorPos( PyObject * self ); +static PyObject *M_Window_SetCursorPos( PyObject * self, PyObject * args ); +static PyObject *M_Window_WaitCursor( PyObject * self, PyObject * args ); +static PyObject *M_Window_GetViewVector( PyObject * self ); +static PyObject *M_Window_GetActiveLayer( PyObject * self ); +static PyObject *M_Window_SetActiveLayer( PyObject * self, PyObject * args ); +static PyObject *M_Window_GetViewQuat( PyObject * self ); +static PyObject *M_Window_SetViewQuat( PyObject * self, PyObject * args ); +static PyObject *M_Window_GetViewOffset( PyObject * self ); +static PyObject *M_Window_SetViewOffset( PyObject * self, PyObject * args ); +static PyObject *M_Window_GetViewMatrix( PyObject * self ); +static PyObject *M_Window_GetPerspMatrix( PyObject * self ); +static PyObject *M_Window_FileSelector( PyObject * self, PyObject * args ); +static PyObject *M_Window_ImageSelector( PyObject * self, PyObject * args ); +static PyObject *M_Window_EditMode( PyObject * self, PyObject * args ); +static PyObject *M_Window_PoseMode( PyObject * self, PyObject * args ); +static PyObject *M_Window_ViewLayers( PyObject * self, PyObject * args ); +static PyObject *M_Window_CameraView( PyObject * self, PyObject * args ); +static PyObject *M_Window_QTest( PyObject * self ); +static PyObject *M_Window_QRead( PyObject * self ); +static PyObject *M_Window_QAdd( PyObject * self, PyObject * args ); +static PyObject *M_Window_QHandle( PyObject * self, PyObject * args ); +static PyObject *M_Window_GetMouseCoords( PyObject * self ); +static PyObject *M_Window_SetMouseCoords( PyObject * self, PyObject * args ); +static PyObject *M_Window_GetMouseButtons( PyObject * self ); +static PyObject *M_Window_GetKeyQualifiers( PyObject * self ); +static PyObject *M_Window_SetKeyQualifiers( PyObject * self, PyObject * args ); +static PyObject *M_Window_GetAreaSize( PyObject * self ); +static PyObject *M_Window_GetAreaID( PyObject * self ); +static PyObject *M_Window_GetScreenSize( PyObject * self ); +static PyObject *M_Window_GetScreens( PyObject * self ); +static PyObject *M_Window_SetScreen( PyObject * self, PyObject * value ); +static PyObject *M_Window_GetScreenInfo( PyObject * self, PyObject * args, + PyObject * kwords ); +PyObject *Window_Init( void ); + + +/*****************************************************************************/ +/* The following string definitions are used for documentation strings. */ +/* In Python these will be written to the console when doing a */ +/* Blender.Window.__doc__ */ +/*****************************************************************************/ +static char M_Window_doc[] = "The Blender Window module\n\n"; + +static char M_Window_Redraw_doc[] = + "() - Force a redraw of a specific Window Type (see Window.Types)"; + +static char M_Window_RedrawAll_doc[] = "() - Redraw all windows"; + +static char M_Window_QRedrawAll_doc[] = + "() - Redraw all windows by queue event"; + +static char M_Window_FileSelector_doc[] = + "(callback [, title, filename]) - Open a file selector window.\n\ +The selected file name is used as argument to a function callback f(name)\n\ +that you must provide. 'title' is optional and defaults to 'SELECT FILE'.\n\ +'filename' is optional and defaults to Blender.Get('filename').\n\n\ +Example:\n\n\ +import Blender\n\n\ +def my_function(filename):\n\ + print 'The selected file was: ', filename\n\n\ +Blender.Window.FileSelector(my_function, 'SAVE FILE')\n"; + +static char M_Window_ImageSelector_doc[] = + "(callback [, title, filename]) - Open an image selector window.\n\ +The selected file name is used as argument to a function callback f(name)\n\ +that you must provide. 'title' is optional and defaults to 'SELECT IMAGE'.\n\ +'filename' is optional and defaults to Blender.Get('filename').\n\n\ +Example:\n\n\ +import Blender\n\n\ +def my_function(filename):\n\ + print 'The selected image file was: ', filename\n\n\ +Blender.Window.ImageSelector(my_function, 'LOAD IMAGE')\n"; + +static char M_Window_DrawProgressBar_doc[] = + "(done, text) - Draw a progress bar.\n\ +'done' is a float value <= 1.0, 'text' contains info about what is\n\ +currently being done."; + +static char M_Window_GetCursorPos_doc[] = + "() - Get the current 3d cursor position as a list of three floats."; + +static char M_Window_SetCursorPos_doc[] = + "([f,f,f]) - Set the current 3d cursor position from a list of three floats."; + +static char M_Window_WaitCursor_doc[] = + "(bool) - Set cursor to wait mode (nonzero bool) or normal mode (0)."; + +static char M_Window_GetViewVector_doc[] = + "() - Get the current 3d view vector as a list of three floats [x,y,z]."; + +static char M_Window_GetActiveLayer_doc[] = + "() - Get the current 3d views active layer where new objects are created."; + +static char M_Window_SetActiveLayer_doc[] = + "(int) - Set the current 3d views active layer where new objects are created."; + +static char M_Window_GetViewMatrix_doc[] = + "() - Get the current 3d view matrix."; + +static char M_Window_GetPerspMatrix_doc[] = + "() - Get the current 3d Persp matrix."; + +static char M_Window_EditMode_doc[] = + "() - Get the current status -- 0: not in edit mode; 1: in edit mode.\n\ +(status) - if 1: enter edit mode; if 0: leave edit mode.\n\ +Returns the current status. This function is mostly useful to leave\n\ +edit mode before applying changes to a mesh (otherwise the changes will\n\ +be lost) and then returning to it upon leaving."; + +static char M_Window_PoseMode_doc[] = + "() - Get the current status -- 0: not in pose mode; 1: in edit mode"; + +static char M_Window_ViewLayers_doc[] = + "(layers = [], winid = None) - Get/set active layers in all 3d View windows.\n\ +() - Make no changes, only return currently visible layers.\n\ +(layers = []) - a list of integers, each in the range [1, 20].\n\ +(layers = [], winid = int) - layers as above, winid is an optional.\n\ +arg that makes the function only set layers for that view.\n\ +This function returns the currently visible layers as a list of ints."; + +static char M_Window_GetViewQuat_doc[] = + "() - Get the current VIEW3D view quaternion values."; + +static char M_Window_SetViewQuat_doc[] = + "(quat) - Set the current VIEW3D view quaternion values.\n\ +(quat) - [f,f,f,f] or f,f,f,f: the new float values."; + +static char M_Window_GetViewOffset_doc[] = + "() - Get the current VIEW3D view offset values."; + +static char M_Window_SetViewOffset_doc[] = + "(ofs) - Set the current VIEW3D view offset values.\n\ +(ofs) - [f,f,f] or f,f,f: the new float values."; + +static char M_Window_CameraView_doc[] = + "(camtov3d = 0) - Set the current VIEW3D view to the active camera's view.\n\ +(camtov3d = 0) - bool: if nonzero it's the camera that gets positioned at the\n\ +current view, instead of the view being changed to that of the camera.\n\n\ +If no camera is the active object, the active camera for the current scene\n\ +is used."; + +static char M_Window_QTest_doc[] = + "() - Check if there are pending events in the event queue."; + +static char M_Window_QRead_doc[] = + "() - Get the next pending event from the event queue.\n\ +This function returns a list [event, val], where:\n\ +event - int: the key or mouse event (see Blender.Draw module);\n\ +val - int: if 1 it's a key or mouse button press, if 0 a release. For\n\ + mouse movement events 'val' returns the new coordinates in x or y."; + +static char M_Window_QAdd_doc[] = + "(win, evt, val, after = 0) - Add an event to some window's event queue.\n\ +(win) - int: the win id, see Blender.Window.GetScreenInfo();\n\ +(evt) - int: the event number, see events in Blender.Draw;\n\ +(val) - bool: 1 for a key press, 0 for a release;\n\ +(after) - bool: if 1 the event is put after the current queue and added later."; + +static char M_Window_QHandle_doc[] = + "(win) - Process all events for the given window (area) now.\n\ +(win) - int: the window id, see Blender.Window.GetScreenInfo().\n\n\ +See Blender.Window.QAdd() for how to send events to a particular window."; + +static char M_Window_GetMouseCoords_doc[] = + "() - Get mouse pointer's current screen coordinates."; + +static char M_Window_SetMouseCoords_doc[] = + "(x, y) - Set mouse pointer's current screen coordinates.\n\ +(x,y) - ints ([x, y] also accepted): the new x, y coordinates."; + +static char M_Window_GetMouseButtons_doc[] = + "() - Get the current mouse button state (see Blender.Window.MButs dict)."; + +static char M_Window_GetKeyQualifiers_doc[] = + "() - Get the current qualifier keys state.\n\ +An int is returned: or'ed combination of values in Blender.Window.Qual's dict."; + +static char M_Window_SetKeyQualifiers_doc[] = + "(qual) - Fake qualifier keys state.\n\ +(qual) - int: an or'ed combination of the values in Blender.Window.Qual dict.\n\ +Note: remember to reset to 0 after handling the related event (see QAdd())."; + +static char M_Window_GetAreaID_doc[] = + "() - Get the current window's (area) ID."; + +static char M_Window_GetAreaSize_doc[] = + "() - Get the current window's (area) size as [width, height]."; + +static char M_Window_GetScreenSize_doc[] = + "() - Get the screen's size as [width, height]."; + +static char M_Window_GetScreens_doc[] = + "() - Get a list with the names of all available screens."; + +static char M_Window_SetScreen_doc[] = + "(name) - Set current screen to the one with the given 'name'."; + +static char M_Window_GetScreenInfo_doc[] = + "(type = -1, rect = 'win', screen = None)\n\ +- Get info about the the areas in the current screen setup.\n\ +(type = -1) - int: the space type (Blender.Window.Types) to restrict the\n\ + results to, all if -1;\n\ +(rect = 'win') - str: the rectangle of interest. This defines if the corner\n\ + coordinates returned will refer to:\n\ + - the whole area: 'total';\n\ + - only the header: 'header';\n\ + - only the window content (default): 'win'.\n\ +(screen = None) - str: the screen name, current if not given.\n\n\ +A list of dictionaries (one for each area) is returned.\n\ +Each dictionary has keys:\n\ +'vertices': [xmin, ymin, xmax, ymax] area corners;\n\ +'win': window type, see Blender.Window.Types dict;\n\ +'id': area's id."; + +/*****************************************************************************/ +/* Python method structure definition for Blender.Window module: */ +/*****************************************************************************/ +struct PyMethodDef M_Window_methods[] = { + {"Redraw", M_Window_Redraw, METH_VARARGS, M_Window_Redraw_doc}, + {"RedrawAll", M_Window_RedrawAll, METH_VARARGS, + M_Window_RedrawAll_doc}, + {"QRedrawAll", M_Window_QRedrawAll, METH_VARARGS, + M_Window_QRedrawAll_doc}, + {"FileSelector", M_Window_FileSelector, METH_VARARGS, + M_Window_FileSelector_doc}, + {"ImageSelector", ( PyCFunction ) M_Window_ImageSelector, METH_VARARGS, + M_Window_ImageSelector_doc}, + {"DrawProgressBar", M_Window_DrawProgressBar, METH_VARARGS, + M_Window_DrawProgressBar_doc}, + {"drawProgressBar", M_Window_DrawProgressBar, METH_VARARGS, + M_Window_DrawProgressBar_doc}, + {"GetCursorPos", ( PyCFunction ) M_Window_GetCursorPos, METH_NOARGS, + M_Window_GetCursorPos_doc}, + {"SetCursorPos", M_Window_SetCursorPos, METH_VARARGS, + M_Window_SetCursorPos_doc}, + {"WaitCursor", M_Window_WaitCursor, METH_VARARGS, + M_Window_WaitCursor_doc}, + {"GetViewVector", ( PyCFunction ) M_Window_GetViewVector, METH_NOARGS, + M_Window_GetViewVector_doc}, + {"GetActiveLayer", ( PyCFunction ) M_Window_GetActiveLayer, METH_NOARGS, + M_Window_GetActiveLayer_doc}, + {"SetActiveLayer", ( PyCFunction ) M_Window_SetActiveLayer, METH_VARARGS, + M_Window_SetActiveLayer_doc}, + {"GetViewQuat", ( PyCFunction ) M_Window_GetViewQuat, METH_NOARGS, + M_Window_GetViewQuat_doc}, + {"SetViewQuat", ( PyCFunction ) M_Window_SetViewQuat, METH_VARARGS, + M_Window_SetViewQuat_doc}, + {"GetViewOffset", ( PyCFunction ) M_Window_GetViewOffset, METH_NOARGS, + M_Window_GetViewOffset_doc}, + {"SetViewOffset", ( PyCFunction ) M_Window_SetViewOffset, METH_VARARGS, + M_Window_SetViewOffset_doc}, + {"GetViewMatrix", ( PyCFunction ) M_Window_GetViewMatrix, METH_NOARGS, + M_Window_GetViewMatrix_doc}, + {"GetPerspMatrix", ( PyCFunction ) M_Window_GetPerspMatrix, METH_NOARGS, + M_Window_GetPerspMatrix_doc}, + {"EditMode", ( PyCFunction ) M_Window_EditMode, METH_VARARGS, + M_Window_EditMode_doc}, + {"PoseMode", ( PyCFunction ) M_Window_PoseMode, METH_VARARGS, + M_Window_PoseMode_doc}, + {"ViewLayers", ( PyCFunction ) M_Window_ViewLayers, METH_VARARGS, + M_Window_ViewLayers_doc}, + /* typo, deprecate someday: */ + {"ViewLayer", ( PyCFunction ) M_Window_ViewLayers, METH_VARARGS, + M_Window_ViewLayers_doc}, + {"CameraView", ( PyCFunction ) M_Window_CameraView, METH_VARARGS, + M_Window_CameraView_doc}, + {"QTest", ( PyCFunction ) M_Window_QTest, METH_NOARGS, + M_Window_QTest_doc}, + {"QRead", ( PyCFunction ) M_Window_QRead, METH_NOARGS, + M_Window_QRead_doc}, + {"QAdd", ( PyCFunction ) M_Window_QAdd, METH_VARARGS, + M_Window_QAdd_doc}, + {"QHandle", ( PyCFunction ) M_Window_QHandle, METH_VARARGS, + M_Window_QHandle_doc}, + {"GetMouseCoords", ( PyCFunction ) M_Window_GetMouseCoords, + METH_NOARGS, + M_Window_GetMouseCoords_doc}, + {"SetMouseCoords", ( PyCFunction ) M_Window_SetMouseCoords, + METH_VARARGS, + M_Window_SetMouseCoords_doc}, + {"GetMouseButtons", ( PyCFunction ) M_Window_GetMouseButtons, + METH_NOARGS, + M_Window_GetMouseButtons_doc}, + {"GetKeyQualifiers", ( PyCFunction ) M_Window_GetKeyQualifiers, + METH_NOARGS, + M_Window_GetKeyQualifiers_doc}, + {"SetKeyQualifiers", ( PyCFunction ) M_Window_SetKeyQualifiers, + METH_VARARGS, + M_Window_SetKeyQualifiers_doc}, + {"GetAreaSize", ( PyCFunction ) M_Window_GetAreaSize, METH_NOARGS, + M_Window_GetAreaSize_doc}, + {"GetAreaID", ( PyCFunction ) M_Window_GetAreaID, METH_NOARGS, + M_Window_GetAreaID_doc}, + {"GetScreenSize", ( PyCFunction ) M_Window_GetScreenSize, METH_NOARGS, + M_Window_GetScreenSize_doc}, + {"GetScreens", ( PyCFunction ) M_Window_GetScreens, METH_NOARGS, + M_Window_GetScreens_doc}, + {"SetScreen", ( PyCFunction ) M_Window_SetScreen, METH_O, + M_Window_SetScreen_doc}, + {"GetScreenInfo", ( PyCFunction ) M_Window_GetScreenInfo, + METH_VARARGS | METH_KEYWORDS, M_Window_GetScreenInfo_doc}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Function: M_Window_Redraw */ +/* Python equivalent: Blender.Window.Redraw */ +/*****************************************************************************/ +/* not static so py_slider_update in Draw.[ch] can use it */ +PyObject *M_Window_Redraw( PyObject * self, PyObject * args ) +{ + ScrArea *tempsa, *sa; + int wintype = SPACE_VIEW3D; + short redraw_all = 0; + + if( !PyArg_ParseTuple( args, "|i", &wintype ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected int argument (or nothing)" ) ); + + if( wintype < 0 ) + redraw_all = 1; + + if( !during_script( ) && !G.background ) { + tempsa = curarea; + sa = G.curscreen->areabase.first; + + while( sa ) { + + if( sa->spacetype == wintype || redraw_all ) { + if (sa->spacetype == SPACE_SCRIPT && EXPP_disable_force_draw) { + scrarea_queue_redraw(sa); + } + else { + /* do not call fancy hacks here like pop_space_text(st); (ton) */ + scrarea_do_windraw( sa ); + if( sa->headwin ) scrarea_do_headdraw( sa ); + } + } + sa = sa->next; + } + + if( curarea != tempsa ) + areawinset( tempsa->win ); + + if( curarea ) { /* is null if Blender is in bg mode */ + if( curarea->headwin ) + scrarea_do_headdraw( curarea ); + screen_swapbuffers( ); + } + } + + Py_RETURN_NONE; +} + +/*****************************************************************************/ +/* Function: M_Window_RedrawAll */ +/* Python equivalent: Blender.Window.RedrawAll */ +/*****************************************************************************/ +static PyObject *M_Window_RedrawAll( PyObject * self, PyObject * args ) +{ + PyObject *arg = Py_BuildValue( "(i)", -1 ); + PyObject *ret = M_Window_Redraw( self, arg ); + Py_DECREF(arg); + return ret; +} + +/*****************************************************************************/ +/* Function: M_Window_QRedrawAll */ +/* Python equivalent: Blender.Window.QRedrawAll */ +/*****************************************************************************/ +static PyObject *M_Window_QRedrawAll( PyObject * self, PyObject * args ) +{ + EXPP_allqueue( REDRAWALL, 0 ); + Py_RETURN_NONE; +} + +/*****************************************************************************/ +/* Function: M_Window_FileSelector */ +/* Python equivalent: Blender.Window.FileSelector */ +/*****************************************************************************/ + +/* This is the callback to "activate_fileselect" below. It receives the + * selected filename and (using it as argument) calls the Python callback + * provided by the script writer and stored in EXPP_FS_PyCallback. */ + +static void getSelectedFile( char *name ) +{ + PyObject *pycallback; + PyObject *result; + Script *script; + + /* let's find the script that owns this callback */ + script = G.main->script.first; + while (script) { + if (script->flags & SCRIPT_RUNNING) break; + script = script->id.next; + } + + if (!script) { + if (curarea->spacetype == SPACE_SCRIPT) { + SpaceScript *sc = curarea->spacedata.first; + script = sc->script; + } + } + + pycallback = script->py_browsercallback; + + if (pycallback) { + result = PyObject_CallFunction( pycallback, "s", name ); + + if (!result) { + if (G.f & G_DEBUG) + fprintf(stderr, "BPy error: Callback call failed!\n"); + } + else Py_DECREF(result); + + if (script->py_browsercallback == pycallback) + script->py_browsercallback = NULL; + /* else another call to selector was made inside pycallback */ + + Py_DECREF(pycallback); + } + + return; +} + +static PyObject *M_Window_FileSelector( PyObject * self, PyObject * args ) +{ + char *title = "SELECT FILE"; + char *filename = G.sce; + SpaceScript *sc; + Script *script = NULL; + PyObject *pycallback = NULL; + int startspace = 0; + + if (during_scriptlink()) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "script links can't call the file selector"); + + if (G.background) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "the file selector is not available in background mode"); + + if((!PyArg_ParseTuple( args, "O|ss", &pycallback, &title, &filename)) + || (!PyCallable_Check(pycallback))) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "\nexpected a callback function (and optionally one or two strings) " + "as argument(s)" ); + + Py_INCREF(pycallback); + +/* trick: we move to a spacescript because then the fileselector will properly + * unset our SCRIPT_FILESEL flag when the user chooses a file or cancels the + * selection. This is necessary because when a user cancels, the + * getSelectedFile function above doesn't get called and so couldn't unset the + * flag. */ + startspace = curarea->spacetype; + if( startspace != SPACE_SCRIPT ) + newspace( curarea, SPACE_SCRIPT ); + + sc = curarea->spacedata.first; + + /* let's find the script that called us */ + script = G.main->script.first; + while (script) { + if (script->flags & SCRIPT_RUNNING) break; + script = script->id.next; + } + + if( !script ) { + /* if not running, then we were already on a SpaceScript space, executing + * a registered callback -- aka: this script has a gui */ + script = sc->script; /* this is the right script */ + } else { /* still running, use the trick */ + script->lastspace = startspace; + sc->script = script; + } + + script->flags |= SCRIPT_FILESEL; + + /* clear any previous callback (nested calls to selector) */ + if (script->py_browsercallback) { + Py_DECREF((PyObject *)script->py_browsercallback); + } + script->py_browsercallback = pycallback; + + activate_fileselect( FILE_BLENDER, title, filename, getSelectedFile ); + + Py_RETURN_NONE; +} + +static PyObject *M_Window_ImageSelector( PyObject * self, PyObject * args ) +{ + char *title = "SELECT IMAGE"; + char *filename = G.sce; + SpaceScript *sc; + Script *script = NULL; + PyObject *pycallback = NULL; + int startspace = 0; + + if (during_scriptlink()) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "script links can't call the image selector"); + + if (G.background) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "the image selector is not available in background mode"); + + if( !PyArg_ParseTuple( args, "O|ss", &pycallback, &title, &filename ) + || (!PyCallable_Check(pycallback))) + return EXPP_ReturnPyObjError ( PyExc_AttributeError, + "\nexpected a callback function (and optionally one or two strings) " + "as argument(s)" ); + + Py_INCREF(pycallback); + +/* trick: we move to a spacescript because then the fileselector will properly + * unset our SCRIPT_FILESEL flag when the user chooses a file or cancels the + * selection. This is necessary because when a user cancels, the + * getSelectedFile function above doesn't get called and so couldn't unset the + * flag. */ + startspace = curarea->spacetype; + if( startspace != SPACE_SCRIPT ) + newspace( curarea, SPACE_SCRIPT ); + + sc = curarea->spacedata.first; + + /* let's find the script that called us */ + script = G.main->script.first; + while (script) { + if (script->flags & SCRIPT_RUNNING) break; + script = script->id.next; + } + + if( !script ) { + /* if not running, then we were already on a SpaceScript space, executing + * a registered callback -- aka: this script has a gui */ + script = sc->script; /* this is the right script */ + } else { /* still running, use the trick */ + script->lastspace = startspace; + sc->script = script; + } + + script->flags |= SCRIPT_FILESEL; /* same flag as filesel */ + /* clear any previous callback (nested calls to selector) */ + if (script->py_browsercallback) { + Py_DECREF((PyObject *)script->py_browsercallback); + } + script->py_browsercallback = pycallback; + + activate_imageselect( FILE_BLENDER, title, filename, getSelectedFile ); + + Py_RETURN_NONE; +} + +/*****************************************************************************/ +/* Function: M_Window_DrawProgressBar */ +/* Python equivalent: Blender.Window.DrawProgressBar */ +/*****************************************************************************/ +static PyObject *M_Window_DrawProgressBar( PyObject * self, PyObject * args ) +{ + float done; + char *info = NULL; + int retval = 0; + ScrArea *sa = curarea; + + if (G.background) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "the progress bar is not available in background mode"); + + if( !PyArg_ParseTuple( args, "fs", &done, &info ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected a float and a string as arguments" ) ); + + retval = progress_bar( done, info ); + + areawinset(sa->win); + + return Py_BuildValue( "i", retval ); +} + +/*****************************************************************************/ +/* Function: M_Window_GetCursorPos */ +/* Python equivalent: Blender.Window.GetCursorPos */ +/*****************************************************************************/ +static PyObject *M_Window_GetCursorPos( PyObject * self ) +{ + float *cursor = NULL; + PyObject *pylist; + + if( G.vd && G.vd->localview ) + cursor = G.vd->cursor; + else + cursor = G.scene->cursor; + + pylist = Py_BuildValue( "[fff]", cursor[0], cursor[1], cursor[2] ); + + if( !pylist ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "GetCursorPos: couldn't create pylist" ) ); + + return pylist; +} + +/*****************************************************************************/ +/* Function: M_Window_SetCursorPos */ +/* Python equivalent: Blender.Window.SetCursorPos */ +/*****************************************************************************/ +static PyObject *M_Window_SetCursorPos( PyObject * self, PyObject * args ) +{ + int ok = 0; + float val[3]; + + if( PyObject_Length( args ) == 3 ) + ok = PyArg_ParseTuple( args, "fff", &val[0], &val[1], + &val[2] ); + else + ok = PyArg_ParseTuple( args, "(fff)", &val[0], &val[1], + &val[2] ); + + if( !ok ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected [f,f,f] or f,f,f as arguments" ); + + if( G.vd && G.vd->localview ) { + G.vd->cursor[0] = val[0]; + G.vd->cursor[1] = val[1]; + G.vd->cursor[2] = val[2]; + } else { + G.scene->cursor[0] = val[0]; + G.scene->cursor[1] = val[1]; + G.scene->cursor[2] = val[2]; + } + + Py_RETURN_NONE; +} + +static PyObject *M_Window_WaitCursor( PyObject * self, PyObject * args ) +{ + int bool; + + if( !PyArg_ParseTuple( args, "i", &bool ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected bool (0 or 1) or nothing as argument" ); + + waitcursor( bool ); /* nonzero bool sets, zero unsets */ + + Py_RETURN_NONE; +} + +/*****************************************************************************/ +/* Function: M_Window_GetViewVector */ +/* Python equivalent: Blender.Window.GetViewVector */ +/*****************************************************************************/ +static PyObject *M_Window_GetViewVector( PyObject * self ) +{ + float *vec = NULL; + + if( !G.vd ) + Py_RETURN_NONE; + + vec = G.vd->viewinv[2]; + + return Py_BuildValue( "[fff]", vec[0], vec[1], vec[2] ); +} + +/*****************************************************************************/ +/* Function: M_Window_GetActiveLayer */ +/* Python equivalent: Blender.Window.GetActiveLayer */ +/*****************************************************************************/ +static PyObject *M_Window_GetActiveLayer( PyObject * self ) +{ + if (!G.vd) { + return PyInt_FromLong(0); + } else { + return PyInt_FromLong( G.vd->layact ); + } +} + +static PyObject *M_Window_SetActiveLayer( PyObject * self, PyObject * args ) +{ + int layer, bit=1; + if( !PyArg_ParseTuple( args, "i", &layer ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected an int" ) ); + + if (!G.vd) + Py_RETURN_FALSE; + + bit= 0; + while(bit<32) { + if(layer & (1<layact= 1<lay |= G.vd->layact; + + if (G.vd->scenelock) { + G.scene->lay |= G.vd->layact; + } + bit = -1; /* no error */ + break; + } + bit++; + } + + if (bit != -1) + return ( EXPP_ReturnPyObjError( PyExc_ValueError, + "The flag could not be used for the active layer" ) ); + + Py_RETURN_NONE; +} + +static PyObject *M_Window_GetViewQuat( PyObject * self ) +{ + float *vec = NULL; + + if( !G.vd ) + Py_RETURN_NONE; + + vec = G.vd->viewquat; + + return Py_BuildValue( "[ffff]", vec[0], vec[1], vec[2], vec[3] ); +} + +static PyObject *M_Window_SetViewQuat( PyObject * self, PyObject * args ) +{ + int ok = 0; + float val[4]; + + if( !G.vd ) + Py_RETURN_NONE; + + if( PyObject_Length( args ) == 4 ) + ok = PyArg_ParseTuple( args, "ffff", &val[0], &val[1], &val[2], + &val[3] ); + else + ok = PyArg_ParseTuple( args, "(ffff)", &val[0], &val[1], + &val[2], &val[3] ); + + if( !ok ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected [f,f,f,f] or f,f,f,f as arguments" ); + + G.vd->viewquat[0] = val[0]; + G.vd->viewquat[1] = val[1]; + G.vd->viewquat[2] = val[2]; + G.vd->viewquat[3] = val[3]; + + Py_RETURN_NONE; +} + +static PyObject *M_Window_GetViewOffset( PyObject * self ) +{ + if( !G.vd ) + Py_RETURN_NONE; + return Py_BuildValue( "[fff]", G.vd->ofs[0], G.vd->ofs[1], G.vd->ofs[2] ); +} + +static PyObject *M_Window_SetViewOffset( PyObject * self, PyObject * args ) +{ + int ok = 0; + float val[3]; + + if( !G.vd ) + Py_RETURN_NONE; + + if( PyObject_Length( args ) == 3 ) + ok = PyArg_ParseTuple( args, "fff", &val[0], &val[1], + &val[2] ); + else + ok = PyArg_ParseTuple( args, "(fff)", &val[0], &val[1], + &val[2] ); + + if( !ok ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected [f,f,f] or f,f,f as arguments" ); + + G.vd->ofs[0] = val[0]; + G.vd->ofs[1] = val[1]; + G.vd->ofs[2] = val[2]; + + Py_RETURN_NONE; +} + + +/*****************************************************************************/ +/* Function: M_Window_GetViewMatrix */ +/* Python equivalent: Blender.Window.GetViewMatrix */ +/*****************************************************************************/ +static PyObject *M_Window_GetViewMatrix( PyObject * self ) +{ + if( !G.vd ) + Py_RETURN_NONE; + + return newMatrixObject( ( float * ) G.vd->viewmat, 4, 4, Py_WRAP ); +} + +/*****************************************************************************/ +/* Function: M_Window_GetPerspMatrix */ +/* Python equivalent: Blender.Window.GetPerspMatrix */ +/*****************************************************************************/ +static PyObject *M_Window_GetPerspMatrix( PyObject * self ) +{ + if( !G.vd ) + Py_RETURN_NONE; + + return newMatrixObject( ( float * ) G.vd->persmat, 4, 4, Py_WRAP ); +} + + +/* update_armature_weakrefs() + * helper function used in M_Window_EditMode. + * rebuilds list of Armature weakrefs in __main__ + */ + +static int update_armature_weakrefs() +{ + /* stuff for armature weak refs */ + char *list_name = ARM_WEAKREF_LIST_NAME; + PyObject *maindict = NULL, *armlist = NULL; + PyObject *pyarmature = NULL; + int x; + + maindict= PyModule_GetDict(PyImport_AddModule( "__main__")); + armlist = PyDict_GetItemString(maindict, list_name); + if( !armlist){ + printf("Oops - update_armature_weakrefs()\n"); + return 0; + } + + for (x = 0; x < PySequence_Size(armlist); x++){ + pyarmature = PyWeakref_GetObject(PySequence_GetItem( armlist, x)); + if (pyarmature != Py_None) + Armature_RebuildEditbones(pyarmature); + } + return 1; +} + + +static PyObject *M_Window_EditMode( PyObject * self, PyObject * args ) +{ + short status = -1; + char *undo_str = "From script"; + int undo_str_len = 11; + int do_undo = 1; + + if( !PyArg_ParseTuple( args, + "|hs#i", &status, &undo_str, &undo_str_len, &do_undo ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected optional int (bool), string and int (bool) as arguments" ); + + if( status >= 0 ) { + if( status ) { + if( !G.obedit ){ + + //update armatures + if(! update_armature_weakrefs()){ + return EXPP_ReturnPyObjError( + PyExc_RuntimeError, + "internal error - update_armature_weakrefs"); + } + + //enter editmode + enter_editmode(0); + } + } else if( G.obedit ) { + if( undo_str_len > 63 ) + undo_str[63] = '\0'; /* 64 is max */ + BIF_undo_push( undo_str ); /* This checks user undo settings */ + exit_editmode( EM_FREEDATA ); + + //update armatures + if(! update_armature_weakrefs()){ + return EXPP_ReturnPyObjError( + PyExc_RuntimeError, + "internal error - update_armature_weakrefs"); + } + + } + } + + return Py_BuildValue( "h", G.obedit ? 1 : 0 ); +} + +static PyObject *M_Window_PoseMode( PyObject * self, PyObject * args ) +{ + short status = -1; + short is_posemode = 0; + Base *base; + + if( !PyArg_ParseTuple( args, "|h", &status ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected optional int (bool) as argument" ); + + if( status >= 0 ) { + if( status ) { + enter_posemode(); + } else if( G.obedit ) { + exit_posemode(); + } + } + + base= BASACT; + if (base && base->object->flag & OB_POSEMODE) { + is_posemode = 1; + } + + return Py_BuildValue( "h", is_posemode ); +} + +static PyObject *M_Window_ViewLayers( PyObject * self, PyObject * args ) +{ + PyObject *item = NULL; + PyObject *list = NULL, *resl = NULL; + int val, i, bit = 0, layer = 0, len_list; + short winid = -1; + + if( !G.scene ) { + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "can't get pointer to global scene" ); + } + + /* Pase Args, Nothing, One list, Or a list and an int */ + if (PyTuple_GET_SIZE(args)!=0) { + if( !PyArg_ParseTuple ( args, "O!|h", &PyList_Type, &list, &winid) ) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "nothing or a list and optionaly a window ID argument" ); + } + } + + if( list ) { + len_list = PyList_Size(list); + + if (len_list == 0) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "list can't be empty, at list one layer must be set" ); + + for( i = 0; i < len_list; i++ ) { + item = PyList_GetItem( list, i ); + if( !PyInt_Check( item ) ) + return EXPP_ReturnPyObjError + ( PyExc_AttributeError, + "list must contain only integer numbers" ); + + val = ( int ) PyInt_AsLong( item ); + if( val < 1 || val > 20 ) + return EXPP_ReturnPyObjError + ( PyExc_AttributeError, + "layer values must be in the range [1, 20]" ); + + layer |= 1 << ( val - 1 ); + } + + if (winid==-1) { + /* set scene and viewport */ + G.scene->lay = layer; + if (G.vd) { + G.vd->lay = layer; + + while( bit < 20 ) { + val = 1 << bit; + if( layer & val ) { + G.vd->layact = val; + break; + } + bit++; + } + } + } else { + /* only set the windows layer */ + ScrArea *sa; + SpaceLink *sl; + View3D *vd; + + if (G.curscreen) { /* can never be too careful */ + for (sa=G.curscreen->areabase.first; sa; sa= sa->next) { + if (winid == sa->win) { + + for (sl= sa->spacedata.first; sl; sl= sl->next) + if(sl->spacetype==SPACE_VIEW3D) + break; + + if (!sl) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "The window matching the winid has no 3d viewport" ); + + vd= (View3D *) sl; + vd->lay = layer; + + for(bit= 0; bit < 20; bit++) { + val = 1 << bit; + if( layer & val ) { + vd->layact = val; + break; + } + } + + winid = -1; /* so we know its done */ + break; + } + } + if (winid!=-1) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "The winid argument did not match any window" ); + } + } + } + + resl = PyList_New( 0 ); + if( !resl ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create pylist!" ) ); + + layer = G.scene->lay; + + bit = 0; + while( bit < 20 ) { + val = 1 << bit; + if( layer & val ) { + item = Py_BuildValue( "i", bit + 1 ); + PyList_Append( resl, item ); + Py_DECREF( item ); + } + bit++; + } + + return resl; +} + +static PyObject *M_Window_CameraView( PyObject * self, PyObject * args ) +{ + short camtov3d = 0; + + if( !PyArg_ParseTuple( args, "|i", &camtov3d ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected an int (from Window.Views) as argument" ); + + if( !G.vd ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "this function can only be used after a 3d View has been initialized" ); + + if( !G.vd->camera ) { + if( BASACT && OBACT->type == OB_CAMERA ) + G.vd->camera = OBACT; + else + G.vd->camera = scene_find_camera( G.scene ); + handle_view3d_lock( ); + } + + G.vd->persp = 2; + G.vd->view = 0; + + if( camtov3d ) + setcameratoview3d( ); + + Py_RETURN_NONE; +} + +static PyObject *M_Window_QTest( PyObject * self ) +{ + return Py_BuildValue( "h", qtest( ) ); +} + +static PyObject *M_Window_QRead( PyObject * self ) +{ + short val = 0; + unsigned short event; + + if (G.background) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "QRead is not available in background mode"); + + event = extern_qread( &val ); + + return Py_BuildValue( "ii", event, val ); +} + +static PyObject *M_Window_QAdd( PyObject * self, PyObject * args ) +{ + short win; + short evt; /* unsigned, we check below */ + short val; + short after = 0; + + if (G.background) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "QAdd is not available in background mode"); + + if( !PyArg_ParseTuple( args, "hhh|h", &win, &evt, &val, &after ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected three or four ints as arguments" ); + + if( evt < 0 ) /* evt is unsigned short */ + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "event value must be a positive int, check events in Blender.Draw" ); + + if( after ) + addafterqueue( win, evt, val ); + else + addqueue( win, evt, val ); + + Py_RETURN_NONE; +} + +static PyObject *M_Window_QHandle( PyObject * self, PyObject * args ) +{ + short win; + ScrArea *sa; + ScrArea *oldsa = NULL; + + if (G.background) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "QHandle is not available in background mode"); + + if (!G.curscreen) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "No screens available"); + + if( !PyArg_ParseTuple( args, "h", &win ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected an int as argument" ); + + for (sa= G.curscreen->areabase.first; sa; sa= sa->next) + if( sa->win == win ) + break; + + if( sa ) { + BWinEvent evt; + short do_redraw = 0, do_change = 0; + + if( sa != curarea || sa->win != mywinget( ) ) { + oldsa = curarea; + areawinset( sa->win ); + set_g_activearea( sa ); + } + while( bwin_qread( sa->win, &evt ) ) { + if( evt.event == REDRAW ) { + do_redraw = 1; + } else if( evt.event == CHANGED ) { + sa->win_swap = 0; + do_change = 1; + do_redraw = 1; + } else { + scrarea_do_winhandle( sa, &evt ); + } + } + } + + if( oldsa ) { + areawinset( oldsa->win ); + set_g_activearea( oldsa ); + } + + Py_RETURN_NONE; +} + +static PyObject *M_Window_GetMouseCoords( PyObject * self ) +{ + short mval[2]; + + getmouse( mval ); + + return Py_BuildValue( "hh", mval[0], mval[1] ); +} + +static PyObject *M_Window_SetMouseCoords( PyObject * self, PyObject * args ) +{ + int ok, x, y; + + if( !G.curscreen ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "no current screen to retrieve info from!" ); + + x = G.curscreen->sizex / 2; + y = G.curscreen->sizey / 2; + + if( PyObject_Length( args ) == 2 ) + ok = PyArg_ParseTuple( args, "hh", &x, &y ); + else + ok = PyArg_ParseTuple( args, "|(hh)", &x, &y ); + + if( !ok ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected [i, i] or i,i as arguments (or nothing)." ); + + warp_pointer( x, y ); + + Py_RETURN_NONE; +} + +static PyObject *M_Window_GetMouseButtons( PyObject * self ) +{ + short mbut = get_mbut( ); + + return Py_BuildValue( "h", mbut ); +} + +static PyObject *M_Window_GetKeyQualifiers( PyObject * self ) +{ + short qual = get_qual( ); + + return Py_BuildValue( "h", qual ); +} + +static PyObject *M_Window_SetKeyQualifiers( PyObject * self, PyObject * args ) +{ + short qual = 0; + + if( !PyArg_ParseTuple( args, "|h", &qual ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected nothing or an int (or'ed flags) as argument" ); + + if( qual < 0 ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "value must be a positive int, check Blender.Window.Qual" ); + + G.qual = qual; + + return Py_BuildValue( "h", qual ); +} + +static PyObject *M_Window_GetAreaSize( PyObject * self ) +{ + ScrArea *sa = curarea; + + if( !sa ) + Py_RETURN_NONE; + + return Py_BuildValue( "hh", sa->winx, sa->winy ); +} + +static PyObject *M_Window_GetAreaID( PyObject * self ) +{ + ScrArea *sa = curarea; + + if( !sa ) + Py_RETURN_NONE; + + return Py_BuildValue( "h", sa->win ); +} + +static PyObject *M_Window_GetScreenSize( PyObject * self ) +{ + bScreen *scr = G.curscreen; + + if( !scr ) + Py_RETURN_NONE; + + return Py_BuildValue( "hh", scr->sizex, scr->sizey ); +} + + +static PyObject *M_Window_SetScreen( PyObject * self, PyObject * value ) +{ + bScreen *scr = G.main->screen.first; + char *name = PyString_AsString(value); + + if( !name ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string as argument" ); + + while( scr ) { + if( !strcmp( scr->id.name + 2, name ) ) { + setscreen( scr ); + break; + } + scr = scr->id.next; + } + + if( !scr ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "no such screen, check Window.GetScreens() for valid names" ); + + Py_RETURN_NONE; +} + +static PyObject *M_Window_GetScreens( PyObject * self ) +{ + bScreen *scr = G.main->screen.first; + PyObject *list = PyList_New( 0 ); + PyObject *str = NULL; + + if( !list ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create py list!" ); + + while( scr ) { + str = PyString_FromString( scr->id.name + 2 ); + + if( !str ) { + Py_DECREF( list ); + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create py string!" ); + } + + PyList_Append( list, str ); /* incref's str */ + Py_DECREF( str ); + + scr = scr->id.next; + } + + return list; +} + +static PyObject *M_Window_GetScreenInfo( PyObject * self, PyObject * args, + PyObject * kwords ) +{ + ScrArea *sa = G.curscreen->areabase.first; + bScreen *scr = G.main->screen.first; + PyObject *item, *list; + rcti *rct; + int type = -1; + char *rect = "win"; + char *screen = ""; + static char *kwlist[] = { "type", "rect", "screen", NULL }; + int rctype = 0; + + if( !PyArg_ParseTupleAndKeywords( args, kwords, "|iss", kwlist, &type, + &rect, &screen ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected nothing or an int and two strings as arguments" ); + + if( !strcmp( rect, "win" ) ) + rctype = 0; + else if( !strcmp( rect, "total" ) ) + rctype = 1; + else if( !strcmp( rect, "header" ) ) + rctype = 2; + else + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "requested invalid type for area rectangle coordinates." ); + + list = PyList_New( 0 ); + + if( screen && screen[0] != '\0' ) { + while( scr ) { + if( !strcmp( scr->id.name + 2, screen ) ) { + sa = scr->areabase.first; + break; + } + scr = scr->id.next; + } + } + + if( !scr ) { + Py_DECREF( list ); + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "no such screen, see existing ones with Window.GetScreens." ); + } + + while( sa ) { + if( type != -1 && sa->spacetype != type ) { + sa = sa->next; + continue; + } + + switch ( rctype ) { + case 0: + rct = &sa->winrct; + break; + case 1: + rct = &sa->totrct; + break; + case 2: + default: + rct = &sa->headrct; + } + + item = Py_BuildValue( "{s:[h,h,h,h],s:h,s:h}", + "vertices", rct->xmin, rct->ymin, + rct->xmax, rct->ymax, "type", + ( short ) sa->spacetype, "id", + ( short ) sa->win ); + PyList_Append( list, item ); + Py_DECREF( item ); + + sa = sa->next; + } + + return list; +} + +/*****************************************************************************/ +/* Function: Window_Init */ +/*****************************************************************************/ +PyObject *Window_Init( void ) +{ + PyObject *submodule, *Types, *Qual, *MButs, *dict; + + submodule = + Py_InitModule3( "Blender.Window", M_Window_methods, + M_Window_doc ); + + dict = PyModule_GetDict( submodule ); + if( dict ) + PyDict_SetItemString( dict, "Theme", Theme_Init( ) ); + + Types = PyConstant_New( ); + Qual = PyConstant_New( ); + MButs = PyConstant_New( ); + + if( Types ) { + BPy_constant *d = ( BPy_constant * ) Types; + + PyConstant_Insert( d, "VIEW3D", PyInt_FromLong( SPACE_VIEW3D ) ); + PyConstant_Insert( d, "IPO", PyInt_FromLong( SPACE_IPO ) ); + PyConstant_Insert( d, "OOPS", PyInt_FromLong( SPACE_OOPS ) ); + PyConstant_Insert( d, "BUTS", PyInt_FromLong( SPACE_BUTS ) ); + PyConstant_Insert( d, "FILE", PyInt_FromLong( SPACE_FILE ) ); + PyConstant_Insert( d, "IMAGE", PyInt_FromLong( SPACE_IMAGE ) ); + PyConstant_Insert( d, "INFO", PyInt_FromLong( SPACE_INFO ) ); + PyConstant_Insert( d, "SEQ", PyInt_FromLong( SPACE_SEQ ) ); + PyConstant_Insert( d, "IMASEL", PyInt_FromLong( SPACE_IMASEL ) ); + PyConstant_Insert( d, "SOUND", PyInt_FromLong( SPACE_SOUND ) ); + PyConstant_Insert( d, "ACTION", PyInt_FromLong( SPACE_ACTION ) ); + PyConstant_Insert( d, "TEXT", PyInt_FromLong( SPACE_TEXT ) ); + PyConstant_Insert( d, "NLA", PyInt_FromLong( SPACE_NLA ) ); + PyConstant_Insert( d, "SCRIPT", PyInt_FromLong( SPACE_SCRIPT ) ); + PyConstant_Insert( d, "TIME", PyInt_FromLong( SPACE_TIME ) ); + PyConstant_Insert( d, "NODE", PyInt_FromLong( SPACE_NODE ) ); + + PyModule_AddObject( submodule, "Types", Types ); + } + + if( Qual ) { + BPy_constant *d = ( BPy_constant * ) Qual; + + PyConstant_Insert( d, "LALT", PyInt_FromLong( L_ALTKEY ) ); + PyConstant_Insert( d, "RALT", PyInt_FromLong( R_ALTKEY ) ); + PyConstant_Insert( d, "ALT", PyInt_FromLong( LR_ALTKEY ) ); + PyConstant_Insert( d, "LCTRL", PyInt_FromLong( L_CTRLKEY ) ); + PyConstant_Insert( d, "RCTRL", PyInt_FromLong( R_CTRLKEY ) ); + PyConstant_Insert( d, "CTRL", PyInt_FromLong( LR_CTRLKEY ) ); + PyConstant_Insert( d, "LSHIFT", PyInt_FromLong( L_SHIFTKEY ) ); + PyConstant_Insert( d, "RSHIFT", PyInt_FromLong( R_SHIFTKEY ) ); + PyConstant_Insert( d, "SHIFT", PyInt_FromLong( LR_SHIFTKEY ) ); + + PyModule_AddObject( submodule, "Qual", Qual ); + } + + if( MButs ) { + BPy_constant *d = ( BPy_constant * ) MButs; + + PyConstant_Insert( d, "L", PyInt_FromLong( L_MOUSE ) ); + PyConstant_Insert( d, "M", PyInt_FromLong( M_MOUSE ) ); + PyConstant_Insert( d, "R", PyInt_FromLong( R_MOUSE ) ); + + PyModule_AddObject( submodule, "MButs", MButs ); + } + + return submodule; +} diff --git a/source/blender/python/api2_2x/Window.h b/source/blender/python/api2_2x/Window.h new file mode 100644 index 00000000000..a39856ecd58 --- /dev/null +++ b/source/blender/python/api2_2x/Window.h @@ -0,0 +1,43 @@ +/* + * $Id:* + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +/* This file is useless now, CAN BE REMOVED. */ + +#ifndef EXPP_WINDOW_H +#define EXPP_WINDOW_H + +#include + +PyObject *Window_Init( void ); +PyObject *M_Window_Redraw( PyObject * self, PyObject * args ); + +#endif /* EXPP_WINDOW_H */ diff --git a/source/blender/python/api2_2x/World.c b/source/blender/python/api2_2x/World.c new file mode 100644 index 00000000000..7804a443639 --- /dev/null +++ b/source/blender/python/api2_2x/World.c @@ -0,0 +1,1034 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Jacques Guignot, Johnny Matthews + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +/** + * \file World.c + * \ingroup scripts + * \brief Blender.World Module and World Data PyObject implementation. + * + * Note: Parameters between "<" and ">" are optional. But if one of them is + * given, all preceding ones must be given, too. Of course, this only relates + * to the Python functions and methods described here and only inside Python + * code. [ This will go to another file later, probably the main exppython + * doc file]. XXX Better: put optional args with their default value: + * (self, name = "MyName") + */ + +#include "World.h" /*This must come first*/ + +#include "DNA_scene_types.h" /* for G.scene */ +#include "BKE_global.h" +#include "BKE_world.h" +#include "BKE_main.h" +#include "BKE_library.h" +#include "BLI_blenlib.h" +#include "BSE_editipo.h" +#include "BIF_space.h" +#include "mydevice.h" +#include "Ipo.h" +#include "gen_utils.h" +#include "gen_library.h" + +#define IPOKEY_ZENITH 0 +#define IPOKEY_HORIZON 1 +#define IPOKEY_MIST 2 +#define IPOKEY_STARS 3 +#define IPOKEY_OFFSET 4 +#define IPOKEY_SIZE 5 +/*****************************************************************************/ +/* Python BPy_World methods declarations: */ +/*****************************************************************************/ +static PyObject *World_getRange( BPy_World * self ); +static PyObject *World_setRange( BPy_World * self, PyObject * args ); +static PyObject *World_getIpo( BPy_World * self ); +static PyObject *World_oldsetIpo( BPy_World * self, PyObject * args ); +static int World_setIpo( BPy_World * self, PyObject * args ); +static PyObject *World_clearIpo( BPy_World * self ); +static PyObject *World_insertIpoKey( BPy_World * self, PyObject * args ); +static PyObject *World_getMode( BPy_World * self ); +static PyObject *World_oldsetMode( BPy_World * self, PyObject * args ); +static int World_setMode( BPy_World * self, PyObject * args ); +static PyObject *World_getSkytype( BPy_World * self ); +static PyObject *World_oldsetSkytype( BPy_World * self, PyObject * args ); +static int World_setSkytype( BPy_World * self, PyObject * args ); +static PyObject *World_getMistype( BPy_World * self ); +static PyObject *World_oldsetMistype( BPy_World * self, PyObject * args ); +static int World_setMistype( BPy_World * self, PyObject * args ); +static PyObject *World_getHor( BPy_World * self ); +static PyObject *World_oldsetHor( BPy_World * self, PyObject * args ); +static int World_setHor( BPy_World * self, PyObject * args ); +static PyObject *World_getZen( BPy_World * self ); +static PyObject *World_oldsetZen( BPy_World * self, PyObject * args ); +static int World_setZen( BPy_World * self, PyObject * args ); +static PyObject *World_getAmb( BPy_World * self ); +static PyObject *World_oldsetAmb( BPy_World * self, PyObject * args ); +static int World_setAmb( BPy_World * self, PyObject * args ); +static PyObject *World_getStar( BPy_World * self ); +static PyObject *World_oldsetStar( BPy_World * self, PyObject * args ); +static int World_setStar( BPy_World * self, PyObject * args ); +static PyObject *World_getMist( BPy_World * self ); +static PyObject *World_oldsetMist( BPy_World * self, PyObject * args ); +static int World_setMist( BPy_World * self, PyObject * args ); +static PyObject *World_getScriptLinks( BPy_World * self, PyObject * value ); +static PyObject *World_addScriptLink( BPy_World * self, PyObject * args ); +static PyObject *World_clearScriptLinks( BPy_World * self, PyObject * args ); +static PyObject *World_setCurrent( BPy_World * self ); +static PyObject *World_copy( BPy_World * self ); + + +/*****************************************************************************/ +/* Python API function prototypes for the World module. */ +/*****************************************************************************/ +static PyObject *M_World_New( PyObject * self, PyObject * args, + PyObject * keywords ); +static PyObject *M_World_Get( PyObject * self, PyObject * args ); +static PyObject *M_World_GetCurrent( PyObject * self ); + + +/*****************************************************************************/ +/* Python World_Type callback function prototypes: */ +/*****************************************************************************/ +//static int World_Print (BPy_World *self, FILE *fp, int flags); +static int World_Compare( BPy_World * a, BPy_World * b ); +static PyObject *World_Repr( BPy_World * self ); + + + +/*****************************************************************************/ +/* The following string definitions are used for documentation strings. */ +/* In Python these will be written to the console when doing a */ +/* Blender.World.__doc__ */ +/*****************************************************************************/ +static char M_World_doc[] = "The Blender World module\n\n\ +This module provides access to **World Data** objects in Blender\n\n"; + +static char M_World_New_doc[] = "() - return a new World object"; + +static char M_World_Get_doc[] = + "(name) - return the world with the name 'name', \ +returns None if not found.\n If 'name' is not specified, \ +it returns a list of all worlds in the\ncurrent scene."; +static char M_World_GetCurrent_doc[] = "() - returns the current world, or \ +None if the Scene has no world"; + + + +/*****************************************************************************/ +/* Python method structure definition for Blender.World module: */ +/*****************************************************************************/ +struct PyMethodDef M_World_methods[] = { + {"New", ( PyCFunction ) M_World_New, METH_VARARGS | METH_KEYWORDS, + M_World_New_doc}, + {"Get", M_World_Get, METH_VARARGS, M_World_Get_doc}, + {"GetActive", ( PyCFunction ) M_World_GetCurrent, METH_NOARGS, + M_World_GetCurrent_doc}, + {"GetCurrent", ( PyCFunction ) M_World_GetCurrent, METH_NOARGS, + M_World_GetCurrent_doc}, + {"get", M_World_Get, METH_VARARGS, M_World_Get_doc}, + {NULL, NULL, 0, NULL} +}; + + + +/*****************************************************************************/ +/* Python BPy_World methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_World_methods[] = { + {"getRange", ( PyCFunction ) World_getRange, METH_NOARGS, + "() - Return World Range"}, + {"setRange", ( PyCFunction ) World_setRange, METH_VARARGS, + "() - Change this World's range"}, + {"getIpo", ( PyCFunction ) World_getIpo, METH_NOARGS, + "() - Return World Ipo"}, + {"setIpo", ( PyCFunction ) World_oldsetIpo, METH_VARARGS, + "() - Change this World's ipo"}, + {"clearIpo", ( PyCFunction ) World_clearIpo, METH_VARARGS, + "() - Unlink Ipo from this World"}, + {"getName", ( PyCFunction ) GenericLib_getName, METH_NOARGS, + "() - Return World Data name"}, + {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS, + "() - Set World Data name"}, + {"getMode", ( PyCFunction ) World_getMode, METH_NOARGS, + "() - Return World Data mode"}, + {"setMode", ( PyCFunction ) World_oldsetMode, METH_VARARGS, + "(i) - Set World Data mode"}, + {"getSkytype", ( PyCFunction ) World_getSkytype, METH_NOARGS, + "() - Return World Data skytype"}, + {"setSkytype", ( PyCFunction ) World_oldsetSkytype, METH_VARARGS, + "() - Return World Data skytype"}, + {"getMistype", ( PyCFunction ) World_getMistype, METH_NOARGS, + "() - Return World Data mistype"}, + {"setMistype", ( PyCFunction ) World_oldsetMistype, METH_VARARGS, + "() - Return World Data mistype"}, + {"getHor", ( PyCFunction ) World_getHor, METH_NOARGS, + "() - Return World Data hor"}, + {"setHor", ( PyCFunction ) World_oldsetHor, METH_VARARGS, + "() - Return World Data hor"}, + {"getZen", ( PyCFunction ) World_getZen, METH_NOARGS, + "() - Return World Data zen"}, + {"setZen", ( PyCFunction ) World_oldsetZen, METH_VARARGS, + "() - Return World Data zen"}, + {"getAmb", ( PyCFunction ) World_getAmb, METH_NOARGS, + "() - Return World Data amb"}, + {"setAmb", ( PyCFunction ) World_oldsetAmb, METH_VARARGS, + "() - Return World Data amb"}, + {"getStar", ( PyCFunction ) World_getStar, METH_NOARGS, + "() - Return World Data star"}, + {"setStar", ( PyCFunction ) World_oldsetStar, METH_VARARGS, + "() - Return World Data star"}, + {"getMist", ( PyCFunction ) World_getMist, METH_NOARGS, + "() - Return World Data mist"}, + {"setMist", ( PyCFunction ) World_oldsetMist, METH_VARARGS, + "() - Return World Data mist"}, + {"getScriptLinks", ( PyCFunction ) World_getScriptLinks, METH_O, + "(eventname) - Get a list of this world's scriptlinks (Text names) " + "of the given type\n" + "(eventname) - string: FrameChanged, Redraw or Render."}, + {"addScriptLink", ( PyCFunction ) World_addScriptLink, METH_VARARGS, + "(text, evt) - Add a new world scriptlink.\n" + "(text) - string: an existing Blender Text name;\n" + "(evt) string: FrameChanged, Redraw or Render."}, + {"clearScriptLinks", ( PyCFunction ) World_clearScriptLinks, + METH_VARARGS, + "() - Delete all scriptlinks from this world.\n" + "([s1<,s2,s3...>]) - Delete specified scriptlinks from this world."}, + {"setCurrent", ( PyCFunction ) World_setCurrent, METH_NOARGS, + "() - Makes this world the active world for the current scene."}, + {"makeActive", ( PyCFunction ) World_setCurrent, METH_NOARGS, + "please use setCurrent instead, this alias will be removed."}, + {"insertIpoKey", ( PyCFunction ) World_insertIpoKey, METH_VARARGS, + "( World IPO type ) - Inserts a key into the IPO"}, + {"__copy__", ( PyCFunction ) World_copy, METH_NOARGS, + "() - Makes a copy of this world."}, + {"copy", ( PyCFunction ) World_copy, METH_NOARGS, + "() - Makes a copy of this world."}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef BPy_World_getseters[] = { + GENERIC_LIB_GETSETATTR, + {"skytype", (getter)World_getSkytype, (setter)World_setSkytype, + "sky settings as a list", NULL}, + {"mode", (getter)World_getMode, (setter)World_setMode, + "world mode", NULL}, + {"mistype", (getter)World_getMistype, (setter)World_setMistype, + "world mist type", NULL}, + {"hor", (getter)World_getHor, (setter)World_setHor, + "world horizon color", NULL}, + {"amb", (getter)World_getAmb, (setter)World_setAmb, + "world ambient color", NULL}, + {"mist", (getter)World_getMist, (setter)World_setMist, + "world mist settings", NULL}, + {"ipo", (getter)World_getIpo, (setter)World_setIpo, + "world ipo", NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/*****************************************************************************/ +/* Python World_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject World_Type = { + PyObject_HEAD_INIT( NULL ) + 0, /* ob_size */ + "World", /* tp_name */ + sizeof( BPy_World ), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + NULL, /* tp_dealloc */ + 0, /* tp_print */ + NULL, /* tp_getattr */ + NULL, /* tp_setattr */ + ( cmpfunc ) World_Compare, /* tp_compare */ + ( reprfunc ) World_Repr, /* tp_repr */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_World_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + BPy_World_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +/** + * \defgroup World_Module Blender.World module functions + * + */ + +/*@{*/ + +/** + * \brief Python module function: Blender.World.New() + * + * This is the .New() function of the Blender.World submodule. It creates + * new World Data in Blender and returns its Python wrapper object. The + * name parameter is mandatory. + * \param - string: The World Data name. + * \return A new World PyObject. + */ + +static PyObject *M_World_New( PyObject * self, PyObject * args, + PyObject * kwords ) +{ + char *name = NULL; + BPy_World *pyworld; + World *blworld; + + if( !PyArg_ParseTuple( args, "s", &name ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument" ) ); + + + blworld = add_world( name ); + + if( blworld ) { + /* return user count to zero because add_world() inc'd it */ + blworld->id.us = 0; + /* create python wrapper obj */ + pyworld = + ( BPy_World * ) PyObject_NEW( BPy_World, &World_Type ); + } else + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't create World Data in Blender" ) ); + + if( pyworld == NULL ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create World Data object" ) ); + + pyworld->world = blworld; + + return ( PyObject * ) pyworld; +} + +/** + * \brief Python module function: Blender.World.Get() + * + * This is the .Get() function of the Blender.World submodule. It searches + * the list of current World Data objects and returns a Python wrapper for + * the one with the name provided by the user. If called with no arguments, + * it returns a list of all current World Data object names in Blender. + * \param - string: The name of an existing Blender World Data object. + * \return () - A list with the names of all current World Data objects;\n + * \return (name) - A Python wrapper for the World Data called 'name' + * in Blender. + */ + +static PyObject *M_World_Get( PyObject * self, PyObject * args ) +{ + + char *name = NULL; + World *world_iter; + PyObject *worldlist; + char error_msg[64]; + + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument (or nothing)" ) ); + + if( name ) { /* (name) - Search world by name */ + world_iter = ( World * ) GetIdFromList( &( G.main->world ), name ); + + if( world_iter == NULL ) { /* Requested world doesn't exist */ + PyOS_snprintf( error_msg, sizeof( error_msg ), + "World \"%s\" not found", name ); + return ( EXPP_ReturnPyObjError + ( PyExc_NameError, error_msg ) ); + } + + return ( PyObject * ) World_CreatePyObject(world_iter); + } + + else { /* return a list of all worlds in the scene */ + world_iter = G.main->world.first; + worldlist = PyList_New( 0 ); + if( worldlist == NULL ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyList" ) ); + + while( world_iter ) { + BPy_World *found_world = + ( BPy_World * ) PyObject_NEW( BPy_World, + &World_Type ); + found_world->world = world_iter; + PyList_Append( worldlist, ( PyObject * ) found_world ); + Py_DECREF(found_world); + + world_iter = world_iter->id.next; + } + return ( worldlist ); + } + +} + +static PyObject *M_World_GetCurrent( PyObject * self ) +{ + BPy_World *w = NULL; +#if 0 /* add back in when bpy becomes "official" */ + static char warning = 1; + if( warning ) { + printf("Blender.World.GetCurrent() deprecated!\n\tuse bpy.scenes.world instead\n"); + --warning; + } +#endif + + if( !G.scene->world ) + Py_RETURN_NONE; + + w = ( BPy_World * ) PyObject_NEW( BPy_World, &World_Type ); + w->world = G.scene->world; + return ( PyObject * ) w; +} + +/*@}*/ + +/** + * \brief Initializes the Blender.World submodule + * + * This function is used by Blender_Init() in Blender.c to register the + * Blender.World submodule in the main Blender module. + * \return PyObject*: The initialized submodule. + */ + +PyObject *World_Init( void ) +{ + PyObject *submodule; + + if( PyType_Ready( &World_Type ) < 0 ) + return NULL; + + submodule = Py_InitModule3( "Blender.World", + M_World_methods, M_World_doc ); + + PyModule_AddIntConstant( submodule, "ZENITH", IPOKEY_ZENITH ); + PyModule_AddIntConstant( submodule, "HORIZON", IPOKEY_HORIZON ); + PyModule_AddIntConstant( submodule, "MIST", IPOKEY_MIST ); + PyModule_AddIntConstant( submodule, "STARS", IPOKEY_STARS ); + PyModule_AddIntConstant( submodule, "OFFSET", IPOKEY_OFFSET ); + PyModule_AddIntConstant( submodule, "SIZE", IPOKEY_SIZE ); + + return ( submodule ); +} + +/*****************************************************************************/ +/* Python BPy_World methods: */ +/*****************************************************************************/ +static PyObject *World_getRange( BPy_World * self ) +{ + return PyFloat_FromDouble( self->world->range ); +} + +static PyObject *World_setRange( BPy_World * self, PyObject * args ) +{ + float range = 0.f; + if( !PyArg_ParseTuple( args, "f", &range ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "expected a float argument" ) ); + self->world->range = range; + Py_RETURN_NONE; +} + + +static PyObject *World_getIpo( BPy_World * self ) +{ + struct Ipo *ipo = self->world->ipo; + + if( !ipo ) + Py_RETURN_NONE; + + return Ipo_CreatePyObject( ipo ); +} + +static int World_setIpo( BPy_World * self, PyObject * value ) +{ + return GenericLib_assignData(value, (void **) &self->world->ipo, 0, 1, ID_IP, ID_WO); +} + +static PyObject *World_oldsetIpo( BPy_World * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)World_setIpo ); +} + +static PyObject *World_clearIpo( BPy_World * self ) +{ + World *world = self->world; + Ipo *ipo = ( Ipo * ) world->ipo; + + if( ipo ) { + ID *id = &ipo->id; + if( id->us > 0 ) + id->us--; + world->ipo = NULL; + + return EXPP_incr_ret_True(); + } + + return EXPP_incr_ret_False(); /* no ipo found */ +} + +/** + * \brief World PyMethod getSkytype + * + * \return int : The World Data skytype. + */ + +static PyObject *World_getSkytype( BPy_World * self ) +{ + return PyInt_FromLong( ( long ) self->world->skytype ); +} + + +/** + * \brief World PyMethod setSkytype + * + * \return int : The World Data skytype. + */ + +static int World_setSkytype( BPy_World * self, PyObject * value ) +{ + if( !PyInt_Check(value) ) + return ( EXPP_ReturnIntError( PyExc_TypeError, + "expected int argument" ) ); + self->world->skytype = (short)PyInt_AsLong(value); + return 0; +} + +static PyObject *World_oldsetSkytype( BPy_World * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)World_setSkytype ); +} + + +/** + * \brief World PyMethod getMode + * + * \return int : The World Data mode. + */ + +static PyObject *World_getMode( BPy_World * self ) +{ + return PyInt_FromLong( ( long ) self->world->mode ); +} + + +/** + * \brief World PyMethod setMode + * + * \return int : The World Data mode. + */ + +static int World_setMode( BPy_World * self, PyObject * value ) +{ + if( !PyInt_Check(value) ) + return ( EXPP_ReturnIntError( PyExc_TypeError, + "expected int argument" ) ); + self->world->mode = (short)PyInt_AsLong(value); + return 0; +} + +static PyObject *World_oldsetMode( BPy_World * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)World_setMode ); +} + + + +/** + * \brief World PyMethod getMistype + * + * \return int : The World Data mistype. + */ + +static PyObject *World_getMistype( BPy_World * self ) +{ + return PyInt_FromLong( ( long ) self->world->mistype ); +} + + +/** + * \brief World PyMethod setMistype + * + * \return int : The World Data mistype. + */ + +static int World_setMistype( BPy_World * self, PyObject * value ) +{ + if( !PyInt_Check(value) ) + return ( EXPP_ReturnIntError( PyExc_TypeError, + "expected int argument" ) ); + self->world->mistype = (short)PyInt_AsLong(value); + return 0; +} + +static PyObject *World_oldsetMistype( BPy_World * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)World_setMistype ); +} + + + +static PyObject *World_getHor( BPy_World * self ) +{ + PyObject *attr = PyList_New( 3 ); + if( !attr ) + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't create list" ) ); + PyList_SET_ITEM( attr, 0, PyFloat_FromDouble( self->world->horr ) ); + PyList_SET_ITEM( attr, 1, PyFloat_FromDouble( self->world->horg ) ); + PyList_SET_ITEM( attr, 2, PyFloat_FromDouble( self->world->horb ) ); + return attr; +} + + +static int World_setHor( BPy_World * self, PyObject * value ) +{ + if( !PyList_Check( value ) ) + return ( EXPP_ReturnIntError( PyExc_TypeError, + "expected list argument" ) ); + if( PyList_Size( value ) != 3 ) + return ( EXPP_ReturnIntError + ( PyExc_TypeError, "list size must be 3" ) ); + self->world->horr = (float)PyFloat_AsDouble( PyList_GetItem( value, 0 ) ); + self->world->horg = (float)PyFloat_AsDouble( PyList_GetItem( value, 1 ) ); + self->world->horb = (float)PyFloat_AsDouble( PyList_GetItem( value, 2 ) ); + return 0; +} + +static PyObject *World_oldsetHor( BPy_World * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)World_setHor ); +} + +static PyObject *World_getZen( BPy_World * self ) +{ + PyObject *attr = PyList_New( 3 ); + if( !attr ) + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't create list" ) ); + PyList_SET_ITEM( attr, 0, PyFloat_FromDouble( self->world->zenr ) ); + PyList_SET_ITEM( attr, 1, PyFloat_FromDouble( self->world->zeng ) ); + PyList_SET_ITEM( attr, 2, PyFloat_FromDouble( self->world->zenb ) ); + return attr; +} + + +static int World_setZen( BPy_World * self, PyObject * value ) +{ + if( !PyList_Check( value ) ) + return ( EXPP_ReturnIntError( PyExc_TypeError, + "expected list argument" ) ); + if( PyList_Size( value ) != 3 ) + return ( EXPP_ReturnIntError + ( PyExc_TypeError, "list size must be 3" ) ); + self->world->zenr = (float)PyFloat_AsDouble( PyList_GetItem( value, 0 ) ); + self->world->zeng = (float)PyFloat_AsDouble( PyList_GetItem( value, 1 ) ); + self->world->zenb = (float)PyFloat_AsDouble( PyList_GetItem( value, 2 ) ); + return 0; +} + +static PyObject *World_oldsetZen( BPy_World * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)World_setZen ); +} + + +static PyObject *World_getAmb( BPy_World * self ) +{ + PyObject *attr = PyList_New( 3 ); + if( !attr ) + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't create list" ) ); + PyList_SET_ITEM( attr, 0, PyFloat_FromDouble( self->world->ambr ) ); + PyList_SET_ITEM( attr, 1, PyFloat_FromDouble( self->world->ambg ) ); + PyList_SET_ITEM( attr, 2, PyFloat_FromDouble( self->world->ambb ) ); + return attr; +} + + +static int World_setAmb( BPy_World * self, PyObject * value ) +{ + if( !PyList_Check( value ) ) + return ( EXPP_ReturnIntError( PyExc_TypeError, + "expected list argument" ) ); + if( PyList_Size( value ) != 3 ) + return ( EXPP_ReturnIntError + ( PyExc_TypeError, "wrong list size" ) ); + self->world->ambr = (float)PyFloat_AsDouble( PyList_GetItem( value, 0 ) ); + self->world->ambg = (float)PyFloat_AsDouble( PyList_GetItem( value, 1 ) ); + self->world->ambb = (float)PyFloat_AsDouble( PyList_GetItem( value, 2 ) ); + return 0; +} + +static PyObject *World_oldsetAmb( BPy_World * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)World_setAmb ); +} + +static PyObject *World_getStar( BPy_World * self ) +{ + PyObject *attr = PyList_New( 7 ); + if( !attr ) + return ( EXPP_ReturnPyObjError + ( PyExc_RuntimeError, "couldn't create list" ) ); + PyList_SET_ITEM( attr, 0, PyFloat_FromDouble( self->world->starr ) ); + PyList_SET_ITEM( attr, 1, PyFloat_FromDouble( self->world->starg ) ); + PyList_SET_ITEM( attr, 2, PyFloat_FromDouble( self->world->starb ) ); + PyList_SET_ITEM( attr, 3, PyFloat_FromDouble( self->world->starsize ) ); + PyList_SET_ITEM( attr, 4, PyFloat_FromDouble( self->world->starmindist ) ); + PyList_SET_ITEM( attr, 5, PyFloat_FromDouble( self->world->stardist ) ); + PyList_SET_ITEM( attr, 6, PyFloat_FromDouble( self->world->starcolnoise ) ); + return attr; +} + + +static int World_setStar( BPy_World * self, PyObject * value ) +{ + if( !PyList_Check( value ) ) + return ( EXPP_ReturnIntError + ( PyExc_TypeError, "expected list argument" ) ); + if( PyList_Size( value ) != 7 ) + return ( EXPP_ReturnIntError + ( PyExc_TypeError, "wrong list size" ) ); + self->world->starr = (float)PyFloat_AsDouble( PyList_GetItem( value, 0 ) ); + self->world->starg = (float)PyFloat_AsDouble( PyList_GetItem( value, 1 ) ); + self->world->starb = (float)PyFloat_AsDouble( PyList_GetItem( value, 2 ) ); + self->world->starsize = + (float)PyFloat_AsDouble( PyList_GetItem( value, 3 ) ); + self->world->starmindist = + (float)PyFloat_AsDouble( PyList_GetItem( value, 4 ) ); + self->world->stardist = + (float)PyFloat_AsDouble( PyList_GetItem( value, 5 ) ); + self->world->starcolnoise = + (float)PyFloat_AsDouble( PyList_GetItem( value, 6 ) ); + return 0; +} + +static PyObject *World_oldsetStar( BPy_World * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)World_setStar ); +} + + +static PyObject *World_getMist( BPy_World * self ) +{ + PyObject *attr = PyList_New( 4 ); + if( !attr ) + return ( EXPP_ReturnPyObjError + ( PyExc_RuntimeError, "couldn't create list" ) ); + PyList_SET_ITEM( attr, 0, PyFloat_FromDouble( self->world->misi ) ); + PyList_SET_ITEM( attr, 1, PyFloat_FromDouble( self->world->miststa ) ); + PyList_SET_ITEM( attr, 2, PyFloat_FromDouble( self->world->mistdist ) ); + PyList_SET_ITEM( attr, 3, PyFloat_FromDouble( self->world->misthi ) ); + return attr; +} + +static int World_setMist( BPy_World * self, PyObject * value ) +{ + if( !PyList_Check( value ) ) + return ( EXPP_ReturnIntError + ( PyExc_TypeError, "expected list argument" ) ); + if( PyList_Size( value ) != 4 ) + return ( EXPP_ReturnIntError + ( PyExc_TypeError, "wrong list size" ) ); + self->world->misi = (float)PyFloat_AsDouble( PyList_GetItem( value, 0 ) ); + self->world->miststa = + (float)PyFloat_AsDouble( PyList_GetItem( value, 1 ) ); + self->world->mistdist = + (float)PyFloat_AsDouble( PyList_GetItem( value, 2 ) ); + self->world->misthi = + (float)PyFloat_AsDouble( PyList_GetItem( value, 3 ) ); + return 0; +} + +static PyObject *World_oldsetMist( BPy_World * self, PyObject * args ) +{ + return EXPP_setterWrapper( (void *)self, args, (setter)World_setMist ); +} + + +/* world.addScriptLink */ +static PyObject *World_addScriptLink( BPy_World * self, PyObject * args ) +{ + World *world = self->world; + ScriptLink *slink = NULL; + + slink = &( world )->scriptlink; + + return EXPP_addScriptLink( slink, args, 0 ); +} + +/* world.clearScriptLinks */ +static PyObject *World_clearScriptLinks( BPy_World * self, PyObject * args ) +{ + World *world = self->world; + ScriptLink *slink = NULL; + + slink = &( world )->scriptlink; + + return EXPP_clearScriptLinks( slink, args ); +} + +/* world.getScriptLinks */ +static PyObject *World_getScriptLinks( BPy_World * self, PyObject * value ) +{ + World *world = self->world; + ScriptLink *slink = NULL; + PyObject *ret = NULL; + + slink = &( world )->scriptlink; + + ret = EXPP_getScriptLinks( slink, value, 0 ); + + if( ret ) + return ret; + else + return NULL; +} + + +/* world.setCurrent */ +static PyObject *World_setCurrent( BPy_World * self ) +{ + World *world = self->world; +#if 0 /* add back in when bpy becomes "official" */ + static char warning = 1; + if( warning ) { + printf("world.setCurrent() deprecated!\n\tuse bpy.scenes.world=world instead\n"); + --warning; + } +#endif + + /* If there is a world then it now has one less user */ + if( G.scene->world ) + G.scene->world->id.us--; + world->id.us++; + G.scene->world = world; + Py_RETURN_NONE; +} + +/* world.__copy__ */ +static PyObject *World_copy( BPy_World * self ) +{ + World *world = copy_world(self->world ); + world->id.us = 0; + return World_CreatePyObject(world); +} + +/** + * \brief The World PyType compare function + * + * This function compares two given World PyObjects, returning 0 for equality + * and -1 otherwise. In Python it becomes 1 if they are equal and 0 case not. + * The comparison is done with their pointers to Blender World Data objects, + * so any two wrappers pointing to the same Blender World Data will be + * considered the same World PyObject. Currently, only the "==" and "!=" + * comparisons are meaninful -- the "<", "<=", ">" or ">=" are not. + */ + +static int World_Compare( BPy_World * a, BPy_World * b ) +{ + return ( a->world == b->world ) ? 0 : -1; +} + +/** + * \brief The World PyType print callback + * + * This function is called when the user tries to print a PyObject of type + * World. It builds a string with the name of the wrapped Blender World. + */ + +/* +static int World_Print(BPy_World *self, FILE *fp, int flags) +{ + fprintf(fp, "[World \"%s\"]", self->world->id.name+2); + return 0; +} +*/ + +/** + * \brief The World PyType repr callback + * + * This function is called when the statement "repr(myworld)" is executed in + * Python. Repr gives a string representation of a PyObject. + */ + +static PyObject *World_Repr( BPy_World * self ) +{ + return PyString_FromFormat( "[World \"%s\"]", + self->world->id.name + 2 ); +} + +/*@}*/ +/* +static int World_compare (BPy_World *a, BPy_World *b) +{ + World *pa = a->world, *pb = b->world; + return (pa == pb) ? 0:-1; +} +*/ +PyObject *World_CreatePyObject( struct World * world ) +{ + BPy_World *blen_object; + + blen_object = ( BPy_World * ) PyObject_NEW( BPy_World, &World_Type ); + + if( blen_object == NULL ) { + return ( NULL ); + } + blen_object->world = world; + return ( ( PyObject * ) blen_object ); +} + +World *World_FromPyObject( PyObject * py_obj ) +{ + BPy_World *blen_obj; + + blen_obj = ( BPy_World * ) py_obj; + return ( blen_obj->world ); + +} + +/* + * World_insertIpoKey() + * inserts World IPO key for ZENITH,HORIZON,MIST,STARS,OFFSET,SIZE + */ + +static PyObject *World_insertIpoKey( BPy_World * self, PyObject * args ) +{ + int key = 0, map; + + if( !PyArg_ParseTuple( args, "i", &( key ) ) ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected int argument" ) ); + + map = texchannel_to_adrcode(self->world->texact); + + if(key == IPOKEY_ZENITH) { + insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_ZEN_R, 0); + insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_ZEN_G, 0); + insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_ZEN_B, 0); + } + if(key == IPOKEY_HORIZON) { + insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_HOR_R, 0); + insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_HOR_G, 0); + insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_HOR_B, 0); + } + if(key == IPOKEY_MIST) { + insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_MISI, 0); + insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_MISTDI, 0); + insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_MISTSTA, 0); + insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_MISTHI, 0); + } + if(key == IPOKEY_STARS) { + insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_STAR_R, 0); + insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_STAR_G, 0); + insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_STAR_B, 0); + insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_STARDIST, 0); + insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_STARSIZE, 0); + } + if(key == IPOKEY_OFFSET) { + insertkey((ID *)self->world, ID_WO, NULL, NULL, map+MAP_OFS_X, 0); + insertkey((ID *)self->world, ID_WO, NULL, NULL, map+MAP_OFS_Y, 0); + insertkey((ID *)self->world, ID_WO, NULL, NULL, map+MAP_OFS_Z, 0); + } + if(key == IPOKEY_SIZE) { + insertkey((ID *)self->world, ID_WO, NULL, NULL, map+MAP_SIZE_X, 0); + insertkey((ID *)self->world, ID_WO, NULL, NULL, map+MAP_SIZE_Y, 0); + insertkey((ID *)self->world, ID_WO, NULL, NULL, map+MAP_SIZE_Z, 0); + } + + allspace(REMAKEIPO, 0); + EXPP_allqueue(REDRAWIPO, 0); + EXPP_allqueue(REDRAWVIEW3D, 0); + EXPP_allqueue(REDRAWACTION, 0); + EXPP_allqueue(REDRAWNLA, 0); + + Py_RETURN_NONE; +} diff --git a/source/blender/python/api2_2x/World.h b/source/blender/python/api2_2x/World.h new file mode 100644 index 00000000000..ff0ec8709d7 --- /dev/null +++ b/source/blender/python/api2_2x/World.h @@ -0,0 +1,58 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Jacques Guignot + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_WORLD_H +#define EXPP_WORLD_H + +#include +#include "DNA_world_types.h" + +#define BPy_World_Check(v) ((v)->ob_type==&World_Type) + +/* Python BPy_World structure definition */ +typedef struct { + PyObject_HEAD /* required py macro */ + World * world; /* Libdata must be second */ +} BPy_World; + +extern PyTypeObject World_Type; + +/*****************************************************************************/ +/* Python World_Type helper functions needed by Blender (the Init function) */ +/* and Object modules. */ +/*****************************************************************************/ + +PyObject *World_Init( void ); +PyObject *World_CreatePyObject( World * world ); +World *World_FromPyObject( PyObject * pyobj ); + +#endif /* EXPP_WORLD_H */ diff --git a/source/blender/python/api2_2x/bpy.c b/source/blender/python/api2_2x/bpy.c new file mode 100644 index 00000000000..cee862c0e23 --- /dev/null +++ b/source/blender/python/api2_2x/bpy.c @@ -0,0 +1,86 @@ +/* + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Michel Selten, Willian P. Germano, Joseph Gilbert, + * Campbell Barton + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +/* for open, close in Blender_Load */ + +#include "BLI_blenlib.h" +#include "BKE_global.h" +#include "BKE_utildefines.h" +#include "BKE_scene.h" +#include "BKE_main.h" + +#include "DNA_scene_types.h" + +#include "Types.h" +#include "Library.h" + +#include "bpy.h" +#include "bpy_data.h" +#include "bpy_config.h" + +/*****************************************************************************/ +/* Global variables */ +/*****************************************************************************/ +PyObject *g_bpydict; + +/*****************************************************************************/ +/* Function: initBlender */ +/*****************************************************************************/ + +void m_bpy_init(void) +{ + PyObject *module; + PyObject *dict; + + /* G.scene should only aver be NULL if blender is executed in + background mode, not loading a blend file and executing a python script eg. + blender -P somescript.py -b + The if below solves the segfaults that happen when python runs and + G.scene is NULL */ + if(G.background && G.main->scene.first==NULL) { + Scene *sce= add_scene("1"); + /*set_scene(sce);*/ /* causes a crash */ + G.scene= sce; + } + + module = Py_InitModule3("bpy", NULL, "The main bpy module"); + + types_InitAll(); /* set all our pytypes to &PyType_Type */ + + dict = PyModule_GetDict(module); + g_bpydict = dict; + + PyModule_AddObject( module, "config", Config_CreatePyObject() ); + PyDict_SetItemString( dict, "data", Data_Init()); + PyDict_SetItemString( dict, "libraries", Library_Init( ) ); + +} diff --git a/source/blender/python/api2_2x/bpy.h b/source/blender/python/api2_2x/bpy.h new file mode 100644 index 00000000000..668196d8271 --- /dev/null +++ b/source/blender/python/api2_2x/bpy.h @@ -0,0 +1,41 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Michel Selten, Willian P. Germano + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_BPYMOD_H +#define EXPP_BPYMOD_H + +#include + +extern PyObject *g_bpydict; +void m_bpy_init( void ); + +#endif /* EXPP_BPYMOD_H */ diff --git a/source/blender/python/api2_2x/bpy_config.c b/source/blender/python/api2_2x/bpy_config.c new file mode 100644 index 00000000000..a061f31d8a0 --- /dev/null +++ b/source/blender/python/api2_2x/bpy_config.c @@ -0,0 +1,414 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +/* python types */ +#include "DNA_userdef_types.h" +#include "../api2_2x/gen_utils.h" +#include "bpy_config.h" + +enum conf_consts { + /*string*/ + EXPP_CONF_ATTR_PATH_YF_EXPORT = 0, + EXPP_CONF_ATTR_PATH_FONT, + EXPP_CONF_ATTR_PATH_RENDER, + EXPP_CONF_ATTR_PATH_TEXTURE, + EXPP_CONF_ATTR_PATH_PYTHON, + EXPP_CONF_ATTR_PATH_TEX_PLUGIN, + EXPP_CONF_ATTR_PATH_SOUND, + EXPP_CONF_ATTR_PATH_SEQ_PLUGIN, + EXPP_CONF_ATTR_PATH_TEMP, + + /*int*/ + EXPP_CONF_ATTR_UNDOSTEPS, + EXPP_CONF_ATTR_TEX_TIMEOUT, + EXPP_CONF_ATTR_TEX_COLLECT_RATE, + EXPP_CONF_ATTR_MEM_CACHE_LIMIT, + EXPP_CONF_ATTR_FONT_SIZE +}; + +PyObject *Config_CreatePyObject( ) +{ + BPy_Config *conf = PyObject_NEW( BPy_Config, &Config_Type); + return (PyObject *)conf; +} + +/* + * repr function + * callback functions building meaninful string to representations + */ +static PyObject *Config_repr( BPy_Config * self ) +{ + return PyString_FromFormat( "[Blender Configuration Data]"); +} + + +/*-----------------------Config module Init())-----------------------------*/ +/* see Main.c */ +/* +static struct PyMethodDef BPy_Config_methods[] = { + {"new", (PyCFunction)MainSeq_new, METH_VARARGS, + "(name) - Create a new object in this scene from the obdata given and return a new object"}, + {"load", (PyCFunction)MainSeq_load, METH_VARARGS, + "(filename) - loads the given filename for image, font and sound types"}, + {"unlink", (PyCFunction)MainSeq_unlink, METH_VARARGS, + "unlinks the object from the scene"}, + {NULL, NULL, 0, NULL} +};*/ + +/* + * get integer attributes + */ +static PyObject *getStrAttr( BPy_Config *self, void *type ) +{ + char *param = NULL; + + switch( (int)type ) { + case EXPP_CONF_ATTR_PATH_YF_EXPORT: + param = U.yfexportdir; + break; + case EXPP_CONF_ATTR_PATH_FONT: + param = U.fontdir; + break; + case EXPP_CONF_ATTR_PATH_RENDER: + param = U.renderdir; + break; + case EXPP_CONF_ATTR_PATH_TEXTURE: + param = U.textudir; + break; + case EXPP_CONF_ATTR_PATH_PYTHON: + param = U.pythondir; + break; + case EXPP_CONF_ATTR_PATH_TEX_PLUGIN: + param = U.plugtexdir; + break; + case EXPP_CONF_ATTR_PATH_SOUND: + param = U.sounddir; + break; + case EXPP_CONF_ATTR_PATH_SEQ_PLUGIN: + param = U.plugseqdir; + break; + case EXPP_CONF_ATTR_PATH_TEMP: + param = U.tempdir; + break; + + default: + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "undefined type in getStrAttr" ); + } + + return PyString_FromString( param ); +} + +/* + * set integer attributes which require clamping + */ + +static int setStrAttr( BPy_Config *self, PyObject *value, void *type ) +{ + char *param; + int len=160; + char *str = PyString_AsString(value); + + if (!str) + return EXPP_ReturnIntError( PyExc_TypeError, + "error, must assign a python string for setStrAttr"); + + switch( (int)type ) { + case EXPP_CONF_ATTR_PATH_YF_EXPORT: + param = U.yfexportdir; + break; + case EXPP_CONF_ATTR_PATH_FONT: + param = U.fontdir; + break; + case EXPP_CONF_ATTR_PATH_RENDER: + param = U.renderdir; + break; + case EXPP_CONF_ATTR_PATH_TEXTURE: + param = U.textudir; + break; + case EXPP_CONF_ATTR_PATH_PYTHON: + param = U.pythondir; + break; + case EXPP_CONF_ATTR_PATH_TEX_PLUGIN: + param = U.plugtexdir; + break; + case EXPP_CONF_ATTR_PATH_SOUND: + param = U.sounddir; + break; + case EXPP_CONF_ATTR_PATH_SEQ_PLUGIN: + param = U.plugseqdir; + break; + case EXPP_CONF_ATTR_PATH_TEMP: + param = U.tempdir; + break; + + default: + return EXPP_ReturnIntError( PyExc_RuntimeError, + "undefined type in setStrAttr"); + } + + strncpy(param, str, len); + return 0; +} + + +/* + * get integer attributes + */ + +static PyObject *getIntAttr( BPy_Config *self, void *type ) +{ + int param; + + switch( (int)type ) { + case EXPP_CONF_ATTR_UNDOSTEPS: + param = (int)U.undosteps; + break; + case EXPP_CONF_ATTR_TEX_TIMEOUT: + param = U.textimeout; + break; + case EXPP_CONF_ATTR_TEX_COLLECT_RATE: + param = U.texcollectrate; + break; + case EXPP_CONF_ATTR_MEM_CACHE_LIMIT: + param = U.memcachelimit; + break; + case EXPP_CONF_ATTR_FONT_SIZE: + param = U.fontsize; + break; + + default: + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "undefined type in getIntAttr" ); + } + + return PyInt_FromLong( param ); +} + +/* + * set integer attributes which require clamping + */ + +static int setIntAttrClamp( BPy_Config *self, PyObject *value, void *type ) +{ + void *param; + int min, max, size; + + switch( (int)type ) { + case EXPP_CONF_ATTR_UNDOSTEPS: + min = 0; + max = 64; + size = 'h'; + param = (void *)&U.undosteps; + break; + case EXPP_CONF_ATTR_TEX_TIMEOUT: + min = 1; + max = 3600; + size = 'i'; + param = (void *)&U.textimeout; + break; + case EXPP_CONF_ATTR_TEX_COLLECT_RATE: + min = 1; + max = 3600; + size = 'i'; + param = (void *)&U.texcollectrate; + break; + case EXPP_CONF_ATTR_MEM_CACHE_LIMIT: + min = 1; + max = 1024; + size = 'i'; + param = (void *)&U.memcachelimit; + break; + case EXPP_CONF_ATTR_FONT_SIZE: + min = 8; + max = 16; + size = 'i'; + param = (void *)&U.fontsize; + break; + + default: + return EXPP_ReturnIntError( PyExc_RuntimeError, + "undefined type in setIntAttrClamp"); + } + return EXPP_setIValueClamped( value, param, min, max, size ); +} + +static PyGetSetDef Config_getseters[] = { + + /* ints & shorts */ + {"undoSteps", + (getter)getIntAttr, (setter)setIntAttrClamp, + "undo steps", + (void *)EXPP_CONF_ATTR_UNDOSTEPS}, + {"textureTimeout", + (getter)getIntAttr, (setter)setIntAttrClamp, + "time for textures to stay in openGL memory", + (void *)EXPP_CONF_ATTR_TEX_TIMEOUT}, + {"textureCollectRate", + (getter)getIntAttr, (setter)setIntAttrClamp, + "intervel for textures to be tagged as used", + (void *)EXPP_CONF_ATTR_TEX_COLLECT_RATE}, + {"sequenceMemCacheLimit", + (getter)getIntAttr, (setter)setIntAttrClamp, + "maximum memory for the sequencer to use as cache", + (void *)EXPP_CONF_ATTR_MEM_CACHE_LIMIT}, + {"fontSize", + (getter)getIntAttr, (setter)setIntAttrClamp, + "user interface font size", + (void *)EXPP_CONF_ATTR_FONT_SIZE}, + + /* Paths */ + {"yfExportDir", + (getter)getStrAttr, (setter)setStrAttr, + "yafray export path", + (void *)EXPP_CONF_ATTR_PATH_YF_EXPORT}, + {"fontDir", + (getter)getStrAttr, (setter)setStrAttr, + "default font path", + (void *)EXPP_CONF_ATTR_PATH_FONT}, + {"renderDir", + (getter)getStrAttr, (setter)setStrAttr, + "default render path", + (void *)EXPP_CONF_ATTR_PATH_RENDER}, + {"textureDir", + (getter)getStrAttr, (setter)setStrAttr, + "default texture path", + (void *)EXPP_CONF_ATTR_PATH_TEXTURE}, + {"userScriptsDir", + (getter)getStrAttr, (setter)setStrAttr, + "user scripts path", + (void *)EXPP_CONF_ATTR_PATH_PYTHON}, + {"texturePluginsDir", + (getter)getStrAttr, (setter)setStrAttr, + "default texture plugins path", + (void *)EXPP_CONF_ATTR_PATH_TEX_PLUGIN}, + {"soundDir", + (getter)getStrAttr, (setter)setStrAttr, + "default sound path", + (void *)EXPP_CONF_ATTR_PATH_SOUND}, + {"sequencePluginsDir", + (getter)getStrAttr, (setter)setStrAttr, + "sequencer plugins path", + (void *)EXPP_CONF_ATTR_PATH_SEQ_PLUGIN}, + {"tempDir", + (getter)getStrAttr, (setter)setStrAttr, + "temporary file path", + (void *)EXPP_CONF_ATTR_PATH_TEMP}, + + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + + +/* + * Python Config_Type structure definition + */ +PyTypeObject Config_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender Config", /* char *tp_name; */ + sizeof( BPy_Config ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + (reprfunc)Config_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + NULL, /*BPy_Config_methods*/ /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + Config_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; diff --git a/source/blender/python/api2_2x/bpy_config.h b/source/blender/python/api2_2x/bpy_config.h new file mode 100644 index 00000000000..979953acd76 --- /dev/null +++ b/source/blender/python/api2_2x/bpy_config.h @@ -0,0 +1,52 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_BPY_CONFIG_H +#define EXPP_BPY_CONFIG_H + +#include + +/* The Main PyType Object defined in Main.c */ +extern PyTypeObject Config_Type; + +#define BPy_Config_Check(v) \ + ((v)->ob_type == &Config_Type) + +/* Main sequence, iterate on the libdatas listbase*/ +typedef struct { + PyObject_VAR_HEAD /* required python macro */ +} BPy_Config; + +PyObject *Config_CreatePyObject(); + + +#endif /* EXPP_BPY_CONFIG_H */ diff --git a/source/blender/python/api2_2x/bpy_data.c b/source/blender/python/api2_2x/bpy_data.c new file mode 100644 index 00000000000..edb894bd982 --- /dev/null +++ b/source/blender/python/api2_2x/bpy_data.c @@ -0,0 +1,817 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#include "bpy_data.h" + +#include "MEM_guardedalloc.h" /* for MEM_callocN */ +#include "DNA_space_types.h" /* SPACE_VIEW3D, SPACE_SEQ */ +#include "DNA_scene_types.h" +#include "DNA_object_types.h" /* LibBlockSeq_new */ +#include "DNA_texture_types.h" +#include "DNA_curve_types.h" +#include "DNA_ipo_types.h" +#include "DNA_group_types.h" +#include "DNA_world_types.h" +#include "DNA_vfont_types.h" +#include "DNA_armature_types.h" +#include "DNA_sound_types.h" +#include "DNA_text_types.h" +#include "DNA_action_types.h" +#include "DNA_meta_types.h" + +/* Use the add_* from BKE_* */ +#include "BKE_global.h" +#include "BKE_utildefines.h" /* clamp */ +#include "BKE_armature.h" +#include "BKE_ipo.h" +#include "BKE_image.h" +#include "BKE_main.h" +#include "BKE_library.h" +#include "BKE_lattice.h" +#include "BKE_object.h" +#include "BKE_scene.h" +#include "BKE_sca.h" /*free_text_controllers*/ +#include "BKE_font.h" +#include "BKE_mball.h" +#include "BKE_mesh.h" +#include "BKE_curve.h" +#include "BKE_material.h" +#include "BKE_group.h" +#include "BKE_text.h" +#include "BKE_texture.h" +#include "BKE_world.h" + +#include "BLI_blenlib.h" /* BLI_countlist */ +#include "BIF_drawscene.h" /* for set_scene */ +#include "BIF_screen.h" /* curarea */ +#include "BIF_drawimage.h" /* what image */ +#include "BIF_drawtext.h" /* unlink_text */ +#include "BIF_editsound.h" /* sound_new_sound */ +#include "BIF_editaction.h" /* add_empty_action */ + +/* python types */ +#include "../BPY_extern.h" /* clearing scriptlinks */ + +#include "gen_utils.h" +#include "gen_library.h" /* generic ID functions */ + +#include "Object.h" +#include "Camera.h" +#include "Armature.h" +#include "Lamp.h" +#include "Curve.h" +#include "NMesh.h" +#include "Mesh.h" +#include "Lattice.h" +#include "Metaball.h" +#include "Text.h" +#include "Text3d.h" +#include "Font.h" +#include "Group.h" +#include "World.h" +#include "Texture.h" +#include "Ipo.h" +#include "Text.h" +#include "Sound.h" +#include "NLA.h" +#include "Scene.h" +#include "Library.h" + +#include "bpy_config.h" /* config pydata */ + +/* used only for texts.active */ +#include "BIF_screen.h" +#include "DNA_space_types.h" +#include "DNA_screen_types.h" + +extern VFont *get_builtin_font(void); + +static PyObject *LibBlockSeq_CreatePyObject( Link *iter, int type ) +{ + BPy_LibBlockSeq *seq = PyObject_NEW( BPy_LibBlockSeq, &LibBlockSeq_Type); + seq->iter = iter; + seq->type = type; + return (PyObject *)seq; +} + + +static int LibBlockSeq_len( BPy_LibBlockSeq * self ) +{ + ListBase *lb = wich_libbase(G.main, self->type); + return BLI_countlist( lb ); +} + +static PyObject * LibBlockSeq_subscript(BPy_LibBlockSeq * self, PyObject *key) +{ + char *name; + char *lib= NULL; + char use_lib = 0; + ID *id; + + id = (ID *)wich_libbase(G.main, self->type)->first; + + if ( PyString_Check(key) ) { + name = PyString_AsString ( key ); + } else if (PyTuple_Check(key) && (PyTuple_Size(key) == 2) ) { + PyObject *pydata; + use_lib = 1; + + /* Get the first arg */ + pydata = PyTuple_GET_ITEM(key, 0); + if (!PyString_Check(pydata)) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "the data name must be a string" ); + } + + name = PyString_AsString ( pydata ); + + /* Get the second arg */ + pydata = PyTuple_GET_ITEM(key, 1); + if (pydata == Py_None) { + lib = NULL; /* data must be local */ + } else if (PyString_Check(pydata)) { + lib = PyString_AsString ( pydata ); + if (!strcmp( "", lib)) { + lib = NULL; /* and empty string also means data must be local */ + } + } else { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "the lib name must be a string or None" ); + } + } else { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected the a name string or a tuple (lib, name)" ); + } + + for (; id; id = id->next) { + if(!strcmp( name, id->name+2 )) { + if ( + (!use_lib) || /* any data, local or external lib data */ + (use_lib && !lib && !id->lib) || /* only local */ + (lib && use_lib && id->lib && (!strcmp( id->lib->name, lib))) /* only external lib */ + ) + { + return GetPyObjectFromID(id); + } + } + } + return ( EXPP_ReturnPyObjError + ( PyExc_KeyError, "Requested data does not exist") ); +} + +static PyMappingMethods LibBlockSeq_as_mapping = { + ( inquiry ) LibBlockSeq_len, /* mp_length */ + ( binaryfunc ) LibBlockSeq_subscript, /* mp_subscript */ + ( objobjargproc ) 0, /* mp_ass_subscript */ +}; + + +/************************************************************************ + * + * Python LibBlockSeq_Type iterator (iterates over GroupObjects) + * + ************************************************************************/ + +/* + * Initialize the interator index + */ + +static PyObject *LibBlockSeq_getIter( BPy_LibBlockSeq * self ) +{ + /* we need to get the first base, but for selected context we may need to advance + to the first selected or first conext base */ + + ListBase *lb; + Link *link; + lb = wich_libbase(G.main, self->type); + + link = lb->first; + + /* create a new iterator if were alredy using this one */ + if (self->iter==NULL) { + self->iter = link; + return EXPP_incr_ret ( (PyObject *) self ); + } else { + return LibBlockSeq_CreatePyObject(link, self->type); + } +} + +/* + * Return next LibBlockSeq iter. + */ + +static PyObject *LibBlockSeq_nextIter( BPy_LibBlockSeq * self ) +{ + PyObject *object; + Link *link; + if( !(self->iter) ) { + self->iter= NULL; + return EXPP_ReturnPyObjError( PyExc_StopIteration, + "iterator at end" ); + } + + object = GetPyObjectFromID((ID *)self->iter); + + link= self->iter->next; + self->iter= link; + return object; +} + +PyObject *LibBlockSeq_getActive(BPy_LibBlockSeq *self) +{ + switch (self->type) { + case ID_SCE: + if ( !G.scene ) { + Py_RETURN_NONE; + } else { + return Scene_CreatePyObject( ( Scene * ) G.scene ); + } + + break; + case ID_IM: + if (!G.sima || !G.sima->image) { + Py_RETURN_NONE; + } else { + what_image( G.sima ); /* make sure image data exists */ + return Image_CreatePyObject( G.sima->image ); + } + break; + case ID_TXT: { + SpaceText *st= curarea->spacedata.first; + + if (st->spacetype!=SPACE_TEXT || st->text==NULL) { + Py_RETURN_NONE; + } else { + return Text_CreatePyObject( st->text ); + } + } + } + + return EXPP_ReturnPyObjError( PyExc_TypeError, + "Only Scene and Image types have the active attribute" ); +} + +static int LibBlockSeq_setActive(BPy_LibBlockSeq *self, PyObject *value) +{ + switch (self->type) { + case ID_SCE: + if (!BPy_Scene_Check(value)) { + return EXPP_ReturnIntError(PyExc_TypeError, + "Must be a scene" ); + } else { + BPy_Scene *bpydata; + Scene *data; + + bpydata = (BPy_Scene *)value; + data= bpydata->scene; + + if (!data) + return EXPP_ReturnIntError(PyExc_RuntimeError, + "This Scene has been removed" ); + + if (data != G.scene) { + set_scene( data ); + scene_update_for_newframe(data, data->lay); + } + } + return 0; + + case ID_IM: + if (!BPy_Image_Check(value)) { + return EXPP_ReturnIntError(PyExc_TypeError, + "Must be a scene" ); + } else { + BPy_Image *bpydata; + Image *data; + + if (!G.sima) + return 0; + + bpydata = (BPy_Image *)value; + data= bpydata->image; + + if (!data) + return EXPP_ReturnIntError(PyExc_RuntimeError, + "This Scene has been removed" ); + + if (data != G.sima->image) + G.sima->image= data; + } + return 0; + + case ID_TXT: + if (!BPy_Text_Check(value)) { + return EXPP_ReturnIntError(PyExc_TypeError, + "Must be a text" ); + } else { + SpaceText *st= curarea->spacedata.first; + Text *data = ((BPy_Text *)value)->text; + + if( !data ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "This object isn't linked to a Blender Text Object" ); + if(st->spacetype!=SPACE_TEXT) + return 0; + st->text = data; + } + return 0; + } + + return EXPP_ReturnIntError( PyExc_TypeError, + "Only Scene and Image types have the active attribute" ); +} + +static int LibBlockSeq_setTag(BPy_LibBlockSeq *self, PyObject *value) +{ + ID *id; + int param = PyObject_IsTrue( value ); + + if( param == -1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected True/False or 0/1" ); + + id = (ID *)wich_libbase(G.main, self->type)->first; + + if (param) { + for (; id; id = id->next) { + id->flag |= LIB_DOIT; + } + } else { + for (; id; id = id->next) { + id->flag &= ~LIB_DOIT; + } + } + + return 0; +} + + +/* New Data, internal functions */ +Mesh *add_mesh__internal(char *name) +{ + Mesh *mesh = add_mesh(name); /* doesn't return NULL now, but might someday */ + + /* Bound box set to null needed because a new mesh is initialized + with a bounding box of -1 -1 -1 -1 -1 -1 + if its not set to null the bounding box is not re-calculated + when ob.getBoundBox() is called.*/ + MEM_freeN(mesh->bb); + mesh->bb= NULL; + return mesh; +} + +/* used for new and load */ +PyObject *LibBlockSeq_new(BPy_LibBlockSeq *self, PyObject * args, PyObject *kwd) +{ + ID *id = NULL; + char *name=NULL, *filename=NULL, *data_type=NULL; + int img_width=256, img_height=256; + float color[] = {0, 0, 0, 1}; + short data_code = 0; + int user_count = 0; + + /* Load from file */ + if ( ( self->type==ID_IM || self->type==ID_VF || + self->type==ID_SO || self->type==ID_TXT) && + ( PyTuple_Size( args ) < 3 )) + { + static char *kwlist[] = {"name", "filename", NULL}; + + if(PyArg_ParseTupleAndKeywords(args, kwd, "|ss", kwlist, &name, &filename) && filename ) { + PyObject *ret= NULL; + + if (strlen(filename) > FILE_MAXDIR + FILE_MAXFILE - 1) + return ( EXPP_ReturnPyObjError( PyExc_IOError, + "filename too long" ) ); + + if (self->type == ID_IM) { + Image *img = BKE_add_image_file( filename ); + if (!img) + return ( EXPP_ReturnPyObjError( PyExc_IOError, + "couldn't load image" ) ); + ret = Image_CreatePyObject( img ); + + } else if (self->type == ID_VF) { + VFont *vf = load_vfont (filename); + if (!vf) + return EXPP_ReturnPyObjError( PyExc_IOError, + "couldn't load font" ); + ret = Font_CreatePyObject(vf); + + } else if (self->type == ID_SO) { + bSound *snd = sound_new_sound( filename ); + if (!snd) + return EXPP_ReturnPyObjError( PyExc_IOError, + "couldn't load sound" ); + ret = Sound_CreatePyObject(snd); + + } else if (self->type == ID_TXT) { + Text *txt = NULL; + txt = add_text( filename ); + if( !txt ) + return EXPP_ReturnPyObjError( PyExc_IOError, + "couldn't load text" ); + ret = Text_CreatePyObject(txt); + } + + if (!ret) + return EXPP_ReturnPyObjError( PyExc_IOError, + "couldn't create pyobject on load, unknown error" ); + if (name) { + ID *id = ((BPy_GenericLib *)ret)->id; + rename_id( id, name ); + } + return ret; + } + } + + /* New Data */ + if (self->type == ID_IM) { + /* Image, accepts width and height*/ + if( !PyArg_ParseTuple( args, "|sii", &name, &img_width, &img_height ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "one string and two ints expected as arguments" ); + CLAMP(img_width, 4, 5000); + CLAMP(img_height, 4, 5000); + + } else if (self->type == ID_CU) { + /* Curve, needs name and type strings */ + if( !PyArg_ParseTuple( args, "ss", &name, &data_type ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "two strings expected as arguments" ); + + if( !strcmp( data_type, "Curve" ) ) data_code = OB_CURVE; + else if( !strcmp( data_type, "Text3d" ) ) data_code = OB_FONT;/* + else if( !strcmp( data_type, "Surf" ) ) data_code = OB_SURF;*/ + else return EXPP_ReturnPyObjError( PyExc_TypeError, + "Second argument for Curve type incorrect\t\nmust be a string in (Curve or Text - Surf is not supported yet)" ); + + } else if (self->type == ID_IP) { + /* IPO, needs name and type strings */ + if( !PyArg_ParseTuple( args, "ss", &name, &data_type ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "two strings expected as arguments" ); + + if( !strcmp( data_type, "Object" ) ) data_code = ID_OB; + else if( !strcmp( data_type, "Camera" ) ) data_code = ID_CA; + else if( !strcmp( data_type, "World" ) ) data_code = ID_WO; + else if( !strcmp( data_type, "Material" ) ) data_code = ID_MA; + else if( !strcmp( data_type, "Texture" ) ) data_code = ID_TE; + else if( !strcmp( data_type, "Lamp" ) ) data_code = ID_LA; + else if( !strcmp( data_type, "Action" ) ) data_code = ID_PO; + else if( !strcmp( data_type, "Constraint" ) ) data_code = ID_CO; + else if( !strcmp( data_type, "Sequence" ) ) data_code = ID_SEQ; + else if( !strcmp( data_type, "Curve" ) ) data_code = ID_CU; + else if( !strcmp( data_type, "Key" ) ) data_code = ID_KE; + else return EXPP_ReturnPyObjError( PyExc_TypeError, + "Second argument for IPO type incorrect\t\nmust be a string in (Object, Camera, World, Material, Texture, Lamp, Action, Sequence, Curve, Key)" ); + + } else { + /* Other types only need the name */ + if( !PyArg_ParseTuple( args, "|s", &name ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "new(name) - name must be a string argument" ); + } + + switch (self->type) { + case ID_SCE: + id = (ID *)add_scene( name?name:"Scene" ); + user_count = 1; + break; + case ID_OB: + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Add objects through the scenes objects iterator" ); + case ID_ME: + id = (ID *)add_mesh__internal( name?name:"Mesh" ); + break; + case ID_CU: + id = (ID *)add_curve( name?name:"Curve", data_code ); + if (data_code==OB_FONT) { + Text3d *text3d = (Text3d *)id; + text3d->vfont= get_builtin_font(); + text3d->vfont->id.us++; + text3d->str= MEM_mallocN(sizeof(wchar_t), "str"); + text3d->str[0] = '\0'; + text3d->totbox= text3d->actbox= 1; + text3d->tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "textbox"); + text3d->tb[0].w = text3d->tb[0].h = 0.0; + + } /*else { CURVE - Dont need to do anything } */ + break; + case ID_MB: + id = (ID *)add_mball( name?name:"MBall" ); + break; + case ID_MA: + id = (ID *)add_material( name?name:"Material" ); + break; + case ID_TE: + id = (ID *)add_texture( name?name:"Texture" ); + break; + case ID_IM: + { + id = (ID *)BKE_add_image_size(img_width, img_height, name?name:"Image", 0, color); + if( !id ) + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyObject Image_Type" ) ); + /* new images have zero user count */ + break; + } + case ID_LT: + id = (ID *)add_lattice( name?name:"Lattice" ); + break; + case ID_LA: + id = (ID *)add_lamp( name?name:"Lamp" ); + break; + case ID_CA: + id = (ID *)add_camera( name?name:"Camera" ); + break; + case ID_IP: + id = (ID *)add_ipo( name?name:"Ipo", data_code ); + break; + case ID_WO: + id = (ID *)add_world( name?name:"World" ); + break; + case ID_VF: + return EXPP_ReturnPyObjError( PyExc_TypeError, + "Cannot create new fonts, use the load() function to load from a file" ); + case ID_TXT: + id = (ID *)add_empty_text( name?name:"Text" ); + user_count = 1; + break; + case ID_SO: + return EXPP_ReturnPyObjError( PyExc_TypeError, + "Cannot create new sounds, use the load() function to load from a file" ); + case ID_GR: + id = (ID *)add_group( name?name:"Group" ); + user_count = 1; + break; + case ID_AR: + id = (ID *)add_armature( name?name:"Armature" ); + break; + case ID_AC: + id = (ID *)add_empty_action( name?name:"Action" ); + user_count = 1; + break; + } + + if (!id) + Py_RETURN_NONE; + + /* set some types user count to 1, otherwise zero */ + id->us = user_count; + + return GetPyObjectFromID(id); +} + + +PyObject *LibBlockSeq_unlink(BPy_LibBlockSeq *self, PyObject * value) +{ + switch (self->type) { + case ID_SCE: + if( !BPy_Scene_Check(value) ) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected Scene object" ); + } else { + Scene *data = ((BPy_Scene *)value)->scene; + + if (!data) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This Scene has been removed" ); + + /* Run the removal code */ + free_libblock( &G.main->scene, data ); + ((BPy_Scene *)value)->scene = NULL; + Py_RETURN_NONE; + } + case ID_GR: + if( !BPy_Group_Check(value) ) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected Group object" ); + } else { + Group *data = ((BPy_Group *)value)->group; + + if (!data) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This Group has been removed alredy" ); + + /* Run the removal code */ + free_group(data); + unlink_group(data); + data->id.us= 0; + free_libblock( &G.main->group, data ); + ((BPy_Group *)value)->group = NULL; + + Py_RETURN_NONE; + } + + case ID_TXT: + if( !BPy_Text_Check(value) ) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected Text object" ); + } else { + Text *data = ((BPy_Text *)value)->text; + + if (!data) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This Group has been removed alredy" ); + + /* Run the removal code */ + BPY_clear_bad_scriptlinks( data ); + free_text_controllers( data ); + unlink_text( data ); + free_libblock( &G.main->text, data ); + ((BPy_Text *)value)->text = NULL; + + Py_RETURN_NONE; + } + } + return EXPP_ReturnPyObjError( PyExc_TypeError, + "Only types Scene, Group and Text can unlink" ); +} + +static int LibBlockSeq_compare( BPy_LibBlockSeq * a, BPy_LibBlockSeq * b ) +{ + return ( a->type == b->type) ? 0 : -1; +} + +/* + * repr function + * callback functions building meaninful string to representations + */ +static PyObject *LibBlockSeq_repr( BPy_LibBlockSeq * self ) +{ + return PyString_FromFormat( "[LibBlockSeq Iterator]"); +} + +static PyGetSetDef LibBlockSeq_getseters[] = { + {"active", + (getter)LibBlockSeq_getActive, (setter)LibBlockSeq_setActive, + "active object", + NULL}, + {"tag", + (getter)NULL, (setter)LibBlockSeq_setTag, + "tag all data in True or False (write only)", + NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +static struct PyMethodDef BPy_LibBlockSeq_methods[] = { + {"new", (PyCFunction)LibBlockSeq_new, METH_VARARGS | METH_KEYWORDS, + "(name) - Create a new object in this scene from the obdata given and return a new object"}, + {"unlink", (PyCFunction)LibBlockSeq_unlink, METH_O, + "unlinks the object from the scene"}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python LibBlockSeq_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject LibBlockSeq_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "Blender LibBlockSeq", /* char *tp_name; */ + sizeof( BPy_LibBlockSeq ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) LibBlockSeq_compare, /* cmpfunc tp_compare; */ + ( reprfunc ) LibBlockSeq_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + &LibBlockSeq_as_mapping, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + ( getiterfunc) LibBlockSeq_getIter, /* getiterfunc tp_iter; */ + ( iternextfunc ) LibBlockSeq_nextIter, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + BPy_LibBlockSeq_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + LibBlockSeq_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + + +/*-----------------------------BPy module Init())-----------------------------*/ + +PyObject * Data_Init( void ) +{ + PyObject *module; + PyObject *dict; + + + PyType_Ready( &LibBlockSeq_Type ); + PyType_Ready( &Config_Type ); + + /*submodule = Py_InitModule3( "Blender.Main", NULL, M_Main_doc );*/ + module = Py_InitModule3( "bpy.data", NULL, "The bpy.data submodule" ); + dict = PyModule_GetDict( module ); + + /* Python Data Types */ + PyModule_AddObject( module, "scenes", LibBlockSeq_CreatePyObject(NULL, ID_SCE) ); + PyModule_AddObject( module, "objects", LibBlockSeq_CreatePyObject(NULL, ID_OB) ); + PyModule_AddObject( module, "meshes", LibBlockSeq_CreatePyObject(NULL, ID_ME) ); + PyModule_AddObject( module, "curves", LibBlockSeq_CreatePyObject(NULL, ID_CU) ); + PyModule_AddObject( module, "metaballs",LibBlockSeq_CreatePyObject(NULL, ID_MB) ); + PyModule_AddObject( module, "materials",LibBlockSeq_CreatePyObject(NULL, ID_MA) ); + PyModule_AddObject( module, "textures", LibBlockSeq_CreatePyObject(NULL, ID_TE) ); + PyModule_AddObject( module, "images", LibBlockSeq_CreatePyObject(NULL, ID_IM) ); + PyModule_AddObject( module, "lattices", LibBlockSeq_CreatePyObject(NULL, ID_LT) ); + PyModule_AddObject( module, "lamps", LibBlockSeq_CreatePyObject(NULL, ID_LA) ); + PyModule_AddObject( module, "cameras", LibBlockSeq_CreatePyObject(NULL, ID_CA) ); + PyModule_AddObject( module, "ipos", LibBlockSeq_CreatePyObject(NULL, ID_IP) ); + PyModule_AddObject( module, "worlds", LibBlockSeq_CreatePyObject(NULL, ID_WO) ); + PyModule_AddObject( module, "fonts", LibBlockSeq_CreatePyObject(NULL, ID_VF) ); + PyModule_AddObject( module, "texts", LibBlockSeq_CreatePyObject(NULL, ID_TXT) ); + PyModule_AddObject( module, "sounds", LibBlockSeq_CreatePyObject(NULL, ID_SO) ); + PyModule_AddObject( module, "groups", LibBlockSeq_CreatePyObject(NULL, ID_GR) ); + PyModule_AddObject( module, "armatures",LibBlockSeq_CreatePyObject(NULL, ID_AR) ); + PyModule_AddObject( module, "actions", LibBlockSeq_CreatePyObject(NULL, ID_AC) ); + return module; +} diff --git a/source/blender/python/api2_2x/bpy_data.h b/source/blender/python/api2_2x/bpy_data.h new file mode 100644 index 00000000000..45600df6471 --- /dev/null +++ b/source/blender/python/api2_2x/bpy_data.h @@ -0,0 +1,55 @@ +/* + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_BPYDATA_H +#define EXPP_BPYDATA_H + +#include +#include "DNA_listBase.h" + +/* The Main PyType Object defined in Main.c */ +extern PyTypeObject LibBlockSeq_Type; + +#define BPy_LibBlockSeq_Check(v) \ + ((v)->ob_type == &LibBlockSeq_Type) + +/* Main sequence, iterate on the libdatas listbase*/ +typedef struct { + PyObject_VAR_HEAD /* required python macro */ + Link *iter; /* so we can iterate over the listbase */ + + short type; /* store the ID type such as ID_ME */ +} BPy_LibBlockSeq; + + +PyObject * Data_Init( void ); + +#endif /* EXPP_BPYDATA_H */ diff --git a/source/blender/python/api2_2x/bpy_types.h b/source/blender/python/api2_2x/bpy_types.h new file mode 100644 index 00000000000..0b83db6c674 --- /dev/null +++ b/source/blender/python/api2_2x/bpy_types.h @@ -0,0 +1,93 @@ +/* + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_bpy_types_h +#define EXPP_bpy_types_h + + +/*****************************************************************************/ +/* Camera Data */ +/*****************************************************************************/ + + +/*****************************************************************************/ +/* Lamp Data */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* Ipo Data */ +/*****************************************************************************/ + + + +/*****************************************************************************/ +/* Metaball Data */ +/*****************************************************************************/ + + +/*****************************************************************************/ +/* Metaelem Data */ +/*****************************************************************************/ + + +/*****************************************************************************/ +/* Effect Data */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* Wave Data */ +/*****************************************************************************/ + + +/*****************************************************************************/ +/* Build Data */ +/*****************************************************************************/ + + +/*****************************************************************************/ +/* Particle Data */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* Curve Data */ +/*****************************************************************************/ + +/********** + CurNurb data +***********/ + + +/*****************************************************************************/ +/* World Data */ +/*****************************************************************************/ + + +#endif /* EXPP_bpy_types_h */ diff --git a/source/blender/python/api2_2x/charRGBA.c b/source/blender/python/api2_2x/charRGBA.c new file mode 100644 index 00000000000..43c9b7772fa --- /dev/null +++ b/source/blender/python/api2_2x/charRGBA.c @@ -0,0 +1,475 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#include "charRGBA.h" /*This must come first */ +#include "gen_utils.h" + +/* This file is heavily based on the old bpython Constant object code in + Blender */ + +/*****************************************************************************/ +/* Python charRGBA_Type callback function prototypes: */ +/*****************************************************************************/ +static PyObject *charRGBA_repr( BPy_charRGBA * self ); + +static int charRGBALength( BPy_charRGBA * self ); + +static PyObject *charRGBASubscript( BPy_charRGBA * self, PyObject * key ); +static int charRGBAAssSubscript( BPy_charRGBA * self, PyObject * who, + PyObject * cares ); + +static PyObject *charRGBAItem( BPy_charRGBA * self, int i ); +static int charRGBAAssItem( BPy_charRGBA * self, int i, PyObject * ob ); +static PyObject *charRGBASlice( BPy_charRGBA * self, int begin, int end ); +static int charRGBAAssSlice( BPy_charRGBA * self, int begin, int end, + PyObject * seq ); +static PyObject *charRGBA_getColor( BPy_charRGBA * self, void * type); +static int charRGBA_setColor( BPy_charRGBA * self, PyObject * value, void * type); + +/*****************************************************************************/ +/* Python charRGBA_Type Mapping Methods table: */ +/*****************************************************************************/ +static PyMappingMethods charRGBAAsMapping = { + ( inquiry ) charRGBALength, /* mp_length */ + ( binaryfunc ) charRGBASubscript, /* mp_subscript */ + ( objobjargproc ) charRGBAAssSubscript, /* mp_ass_subscript */ +}; + +/*****************************************************************************/ +/* Python charRGBA_Type Sequence Methods table: */ +/*****************************************************************************/ +static PySequenceMethods charRGBAAsSequence = { + ( inquiry ) charRGBALength, /* sq_length */ + ( binaryfunc ) 0, /* sq_concat */ + ( intargfunc ) 0, /* sq_repeat */ + ( intargfunc ) charRGBAItem, /* sq_item */ + ( intintargfunc ) charRGBASlice, /* sq_slice */ + ( intobjargproc ) charRGBAAssItem, /* sq_ass_item */ + ( intintobjargproc ) charRGBAAssSlice, /* sq_ass_slice */ +}; + +static PyGetSetDef charRGBA_getseters[] = { + {"R", + (getter)charRGBA_getColor, (setter)charRGBA_setColor, + "the red component", + (void *) 0}, + {"r", + (getter)charRGBA_getColor, (setter)charRGBA_setColor, + "the red component", + (void *) 0}, + {"G", + (getter)charRGBA_getColor, (setter)charRGBA_setColor, + "the green component", + (void *) 1}, + {"g", + (getter)charRGBA_getColor, (setter)charRGBA_setColor, + "the green component", + (void *) 1}, + {"B", + (getter)charRGBA_getColor, (setter)charRGBA_setColor, + "the blue component", + (void *) 2}, + {"b", + (getter)charRGBA_getColor, (setter)charRGBA_setColor, + "the blue component", + (void *) 2}, + {"A", + (getter)charRGBA_getColor, (setter)charRGBA_setColor, + "the alpha component", + (void *) 3}, + {"a", + (getter)charRGBA_getColor, (setter)charRGBA_setColor, + "the alpha component", + (void *) 3}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/*****************************************************************************/ +/* Python charRGBA_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject charRGBA_Type = { + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ + /* For printing, in format "." */ + "charRGBA", /* tp_name */ + sizeof( BPy_charRGBA ), /* tp_basicsize */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + NULL, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + ( reprfunc ) charRGBA_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + &charRGBAAsSequence, /* PySequenceMethods *tp_as_sequence; */ + &charRGBAAsMapping, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + NULL, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + charRGBA_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +/*****************************************************************************/ +/* Function: charRGBA_New */ +/*****************************************************************************/ +PyObject *charRGBA_New( char *rgba ) +{ + BPy_charRGBA *charRGBA = NULL; + + /* + * When called the first time, charRGBA_Type.tp_dealloc will be NULL. + * If that's the case, initialize the PyTypeObject. If the + * initialization succeeds, then create a new object. + */ + + if( charRGBA_Type.tp_dealloc || PyType_Ready( &charRGBA_Type ) >= 0 ) { + charRGBA = ( BPy_charRGBA * ) PyObject_NEW( BPy_charRGBA, + &charRGBA_Type ); + } + + if( charRGBA == NULL ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create charRGBA object" ); + + /* rgba is a pointer to the first item of a char[4] array */ + charRGBA->rgba[0] = &rgba[0]; + charRGBA->rgba[1] = &rgba[1]; + charRGBA->rgba[2] = &rgba[2]; + charRGBA->rgba[3] = &rgba[3]; + + return ( PyObject * ) charRGBA; +} + +/*****************************************************************************/ +/* Functions: charRGBA_getCol and charRGBA_setCol */ +/* Description: These functions get/set rgba color triplet values. The */ +/* get function returns a tuple, the set one accepts three */ +/* chars (separated or in a tuple) as arguments. */ +/*****************************************************************************/ +PyObject *charRGBA_getCol( BPy_charRGBA * self ) +{ + PyObject *list = PyList_New( 4 ); + + if( !list ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyList" ); + + PyList_SET_ITEM( list, 0, PyInt_FromLong( *(self->rgba[0])) ); + PyList_SET_ITEM( list, 1, PyInt_FromLong( *(self->rgba[1])) ); + PyList_SET_ITEM( list, 2, PyInt_FromLong( *(self->rgba[2])) ); + PyList_SET_ITEM( list, 3, PyInt_FromLong( *(self->rgba[3])) ); + return list; +} + +PyObject *charRGBA_setCol( BPy_charRGBA * self, PyObject * args ) +{ + int ok; + char r = 0, g = 0, b = 0, a = 0; + + if( PyObject_Length( args ) == 4 ) + ok = PyArg_ParseTuple( args, "bbbb", &r, &g, &b, &a ); + + else + ok = PyArg_ParseTuple( args, "|(bbbb)", &r, &g, &b, &a ); + + if( !ok ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected 1-byte ints [b,b,b,b] or b,b,b,b as arguments (or nothing)" ); + + *( self->rgba[0] ) = (char)EXPP_ClampInt( r, 0, 255 ); + *( self->rgba[1] ) = (char)EXPP_ClampInt( g, 0, 255 ); + *( self->rgba[2] ) = (char)EXPP_ClampInt( b, 0, 255 ); + *( self->rgba[3] ) = (char)EXPP_ClampInt( a, 0, 255 ); + + return EXPP_incr_ret( Py_None ); +} + +/* return color value for one of the components */ + +static PyObject *charRGBA_getColor( BPy_charRGBA * self, void * type) +{ + int index = ((long)type) & 3; + return PyInt_FromLong ( *self->rgba[index] ); +} + +/* sets the color value of one of the components */ + +static int charRGBA_setColor( BPy_charRGBA * self, PyObject * value, + void * type) +{ + int index = ((long)type) & 3; + PyObject *num = PyNumber_Int( value ); + + /* argument must be a number */ + if( !num ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected char argument" ); + + /* clamp valut to 0..255 then assign */ + *self->rgba[index] = (char)EXPP_ClampInt( (int)PyInt_AS_LONG(value), + 0, 255 ); + Py_DECREF( num ); + return 0; +} + +/*****************************************************************************/ +/* Section: charRGBA as Mapping */ +/* These functions provide code to access charRGBA objects as */ +/* mappings. */ +/*****************************************************************************/ +static int charRGBALength( BPy_charRGBA * self ) +{ + return 4; +} + +static PyObject *charRGBASubscript( BPy_charRGBA * self, PyObject * key ) +{ + char *name = NULL; + int i; + + if( PyNumber_Check( key ) ) + return charRGBAItem( self, ( int ) PyInt_AsLong( key ) ); + + if( !PyArg_ParseTuple( key, "s", &name ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int or string argument" ); + + if( !strcmp( name, "R" ) || !strcmp( name, "r" ) ) + i = 0; + else if( !strcmp( name, "G" ) || !strcmp( name, "g" ) ) + i = 1; + else if( !strcmp( name, "B" ) || !strcmp( name, "b" ) ) + i = 2; + else if( !strcmp( name, "A" ) || !strcmp( name, "a" ) ) + i = 3; + else + return EXPP_ReturnPyObjError( PyExc_AttributeError, name ); + + return PyInt_FromLong( (long)(*self->rgba[i]) ); +} + +static int charRGBAAssSubscript( BPy_charRGBA * self, PyObject * key, + PyObject * v ) +{ + char *name = NULL; + int i; + + if( !PyNumber_Check( v ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "value to assign must be a number" ); + + if( PyNumber_Check( key ) ) + return charRGBAAssItem( self, ( int ) PyInt_AsLong( key ), v ); + + if( !PyArg_Parse( key, "s", &name ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected int or string argument" ); + + if( !strcmp( name, "R" ) || !strcmp( name, "r" ) ) + i = 0; + else if( !strcmp( name, "G" ) || !strcmp( name, "g" ) ) + i = 1; + else if( !strcmp( name, "B" ) || !strcmp( name, "b" ) ) + i = 2; + else if( !strcmp( name, "A" ) || !strcmp( name, "a" ) ) + i = 3; + else + return EXPP_ReturnIntError( PyExc_AttributeError, name ); + + *( self->rgba[i] ) = (char)EXPP_ClampInt( PyInt_AsLong( v ), 0, 255 ); + + return 0; +} + +/*****************************************************************************/ +/* Section: charRGBA as Sequence */ +/* These functions provide code to access charRGBA objects as */ +/* sequences. */ +/*****************************************************************************/ +static PyObject *charRGBAItem( BPy_charRGBA * self, int i ) +{ + if( i < 0 || i >= 4 ) + return EXPP_ReturnPyObjError( PyExc_IndexError, + "array index out of range" ); + + return PyInt_FromLong( *(self->rgba[i]) ); +} + +static PyObject *charRGBASlice( BPy_charRGBA * self, int begin, int end ) +{ + PyObject *list; + int count; + + if( begin < 0 ) + begin = 0; + if( end > 4 ) + end = 4; + if( begin > end ) + begin = end; + + list = PyList_New( end - begin ); + + for( count = begin; count < end; count++ ) + PyList_SetItem( list, count - begin, + PyInt_FromLong( *( self->rgba[count] ) ) ); + + return list; +} + +static int charRGBAAssItem( BPy_charRGBA * self, int i, PyObject * ob ) +{ + if( i < 0 || i >= 4 ) + return EXPP_ReturnIntError( PyExc_IndexError, + "array assignment index out of range" ); + + if( !PyNumber_Check( ob ) ) + return EXPP_ReturnIntError( PyExc_IndexError, + "color component must be a number" ); + + *( self->rgba[i] ) = (char)EXPP_ClampInt( PyInt_AsLong( ob ), 0, 255 ); + + return 0; +} + +static int charRGBAAssSlice( BPy_charRGBA * self, int begin, int end, + PyObject * seq ) +{ + int count; + + if( begin < 0 ) + begin = 0; + if( end > 4 ) + end = 4; + if( begin > end ) + begin = end; + + if( !PySequence_Check( seq ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "illegal argument type for built-in operation" ); + + if( PySequence_Length( seq ) != ( end - begin ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "size mismatch in slice assignment" ); + + for( count = begin; count < end; count++ ) { + char value; + PyObject *ob = PySequence_GetItem( seq, count ); + + if( !PyArg_Parse( ob, "b", &value ) ) { + Py_DECREF( ob ); + return -1; + } + + *( self->rgba[count] ) = (char)EXPP_ClampInt( value, 0, 255 ); + + Py_DECREF( ob ); + } + + return 0; +} + +/*****************************************************************************/ +/* Function: charRGBA_repr */ +/* Description: This is a callback function for the BPy_charRGBA type. It */ +/* builds a meaninful string to represent charRGBA objects. */ +/*****************************************************************************/ +static PyObject *charRGBA_repr( BPy_charRGBA * self ) +{ + char r, g, b, a; + + r = *( self->rgba[0] ); + g = *( self->rgba[1] ); + b = *( self->rgba[2] ); + a = *( self->rgba[3] ); + + return PyString_FromFormat( "[%d, %d, %d, %d]", r, g, b, a ); +} diff --git a/source/blender/python/api2_2x/charRGBA.h b/source/blender/python/api2_2x/charRGBA.h new file mode 100644 index 00000000000..20573f1ce7b --- /dev/null +++ b/source/blender/python/api2_2x/charRGBA.h @@ -0,0 +1,59 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_charRGBA_H +#define EXPP_charRGBA_H + +#include + +/* Objects of are used inside other Blender Python + * objects, so this header file must contain only 'public' declarations */ +/* there's also rgbTuple, for rgb floats and a color obj in NMesh, messy! */ + +/* Python BPy_charRGBA structure definition: */ + +typedef struct { + PyObject_HEAD + char *rgba[4]; /* array of four pointers to chars */ + +} BPy_charRGBA; + +extern PyTypeObject charRGBA_Type; + +/*****************************************************************************/ +/* Python API function prototypes for the charRGBA helper module. */ +/*****************************************************************************/ +PyObject *charRGBA_New( char *rgba ); +PyObject *charRGBA_getCol( BPy_charRGBA * self ); +PyObject *charRGBA_setCol( BPy_charRGBA * self, PyObject * args ); + +#endif /* EXPP_charRGBA_H */ diff --git a/source/blender/python/api2_2x/constant.c b/source/blender/python/api2_2x/constant.c new file mode 100644 index 00000000000..3a64de610f1 --- /dev/null +++ b/source/blender/python/api2_2x/constant.c @@ -0,0 +1,269 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano, Joseph Gilbert + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#include "constant.h" /*This must come first */ + +#include "gen_utils.h" +#include "BLI_blenlib.h" + +PyTypeObject constant_Type; + +//------------------METHOD IMPLEMENTATIONS----------------------------- +//------------------------constant.items() +//Returns a list of key:value pairs like dict.items() +PyObject* constant_items(BPy_constant *self) +{ + return PyDict_Items(self->dict); +} +//------------------------constant.keys() +//Returns a list of keys like dict.keys() +PyObject* constant_keys(BPy_constant *self) +{ + return PyDict_Keys(self->dict); +} +//------------------------constant.values() +//Returns a list of values like dict.values() +PyObject* constant_values(BPy_constant *self) +{ + return PyDict_Values(self->dict); +} +//------------------ATTRIBUTE IMPLEMENTATION--------------------------- +//------------------TYPE_OBECT IMPLEMENTATION-------------------------- +//-----------------------(internal) +//Creates a new constant object +static PyObject *new_const(void) +{ + BPy_constant *constant; + + constant = (BPy_constant *) PyObject_NEW(BPy_constant, &constant_Type); + if(constant == NULL){ + return (EXPP_ReturnPyObjError(PyExc_MemoryError, + "couldn't create constant object")); + } + if((constant->dict = PyDict_New()) == NULL){ + return (EXPP_ReturnPyObjError(PyExc_MemoryError, + "couldn't create constant object's dictionary")); + } + + return (PyObject *)constant; +} +//------------------------tp_doc +//The __doc__ string for this object +static char BPy_constant_doc[] = "This is an internal subobject of armature\ +designed to act as a Py_Bone dictionary."; + +//------------------------tp_methods +//This contains a list of all methods the object contains +static PyMethodDef BPy_constant_methods[] = { + {"items", (PyCFunction) constant_items, METH_NOARGS, + "() - Returns the key:value pairs from the dictionary"}, + {"keys", (PyCFunction) constant_keys, METH_NOARGS, + "() - Returns the keys the dictionary"}, + {"values", (PyCFunction) constant_values, METH_NOARGS, + "() - Returns the values from the dictionary"}, + {NULL, NULL, 0, NULL} +}; +//------------------------mp_length +static int constantLength(BPy_constant *self) +{ + return 0; +} +//------------------------mp_subscript +static PyObject *constantSubscript(BPy_constant *self, PyObject *key) +{ + if(self->dict) { + PyObject *v = PyDict_GetItem(self->dict, key); + if(v) { + return EXPP_incr_ret(v); + } + return EXPP_ReturnPyObjError( PyExc_KeyError, + "key not found" ); + } + return NULL; +} +//------------------------mp_ass_subscript +static int constantAssSubscript(BPy_constant *self, PyObject *who, PyObject *cares) +{ + return 0; /* no user assignments allowed */ +} +//------------------------tp_getattro +static PyObject *constant_getAttro(BPy_constant * self, PyObject *value) +{ + if(self->dict) { + PyObject *v; + char *name = PyString_AS_STRING( value ); + + if(!strcmp(name, "__members__")) + return PyDict_Keys(self->dict); + +#if 0 + if(!strcmp(name, "__methods__") || !strcmp(name, "__dict__")) { + return PyObject_GenericGetAttr( (PyObject *)self, value ); + } +#endif + + v = PyDict_GetItemString(self->dict, name); + if(v) { + return EXPP_incr_ret(v); /* was a borrowed ref */ + } + return PyObject_GenericGetAttr( (PyObject *)self, value ); + } + return (EXPP_ReturnPyObjError(PyExc_RuntimeError, + "constant object lacks a dictionary")); +} +//------------------------tp_repr +static PyObject *constant_repr(BPy_constant * self) +{ + char str[4096]; + PyObject *key, *value, *tempstr; + int pos = 0; + + BLI_strncpy(str,"[Constant: ",4096); + tempstr = PyString_FromString("name"); + value = PyDict_GetItem( self->dict, tempstr ); + Py_DECREF(tempstr); + if(value) { + strcat(str, PyString_AsString(value)); + } else { + short sep = 0; + strcat(str,"{"); + while (PyDict_Next(self->dict, &pos, &key, &value)) { + if( sep ) + strcat (str, ", "); + else + sep = 1; + strcat (str, PyString_AsString(key)); + } + strcat(str,"}"); + } + strcat(str, "]"); + return PyString_FromString(str); +} +//------------------------tp_dealloc +static void constant_dealloc(BPy_constant * self) +{ + Py_DECREF(self->dict); + PyObject_DEL(self); +} + +//------------------TYPE_OBECT DEFINITION------------------------------ +static PyMappingMethods constantAsMapping = { + (inquiry) constantLength, // mp_length + (binaryfunc) constantSubscript, // mp_subscript + (objobjargproc) constantAssSubscript, // mp_ass_subscript +}; + +PyTypeObject constant_Type = { + PyObject_HEAD_INIT(NULL) //tp_head + 0, //tp_internal + "Constant", //tp_name + sizeof(BPy_constant), //tp_basicsize + 0, //tp_itemsize + (destructor)constant_dealloc, //tp_dealloc + 0, //tp_print + 0, //tp_getattr + 0, //tp_setattr + 0, //tp_compare + (reprfunc) constant_repr, //tp_repr + 0, //tp_as_number + 0, //tp_as_sequence + &constantAsMapping, //tp_as_mapping + 0, //tp_hash + 0, //tp_call + 0, //tp_str + (getattrofunc)constant_getAttro, //tp_getattro + 0, //tp_setattro + 0, //tp_as_buffer + Py_TPFLAGS_DEFAULT, //tp_flags + BPy_constant_doc, //tp_doc + 0, //tp_traverse + 0, //tp_clear + 0, //tp_richcompare + 0, //tp_weaklistoffset + 0, //tp_iter + 0, //tp_iternext + BPy_constant_methods, //tp_methods + 0, //tp_members + 0, //tp_getset + 0, //tp_base + 0, //tp_dict + 0, //tp_descr_get + 0, //tp_descr_set + 0, //tp_dictoffset + 0, //tp_init + 0, //tp_alloc + 0, //tp_new + 0, //tp_free + 0, //tp_is_gc + 0, //tp_bases + 0, //tp_mro + 0, //tp_cache + 0, //tp_subclasses + 0, //tp_weaklist + 0 //tp_del +}; +//------------------VISIBLE PROTOTYPE IMPLEMENTATION------------------- +//Creates a default empty constant +PyObject *PyConstant_New(void) +{ + return new_const(); +} +//Inserts a key:value pair into the constant and then returns 0/1 +int PyConstant_Insert(BPy_constant *self, char *name, PyObject *value) +{ + PyType_Ready( &constant_Type ); + return EXPP_dict_set_item_str(self->dict, name, value); +} +//This is a helper function for generating constants...... +PyObject *PyConstant_NewInt(char *name, int value) +{ + PyObject *constant = PyConstant_New(); + + if (constant) + { + PyConstant_Insert((BPy_constant*)constant, "name", PyString_FromString(name)); + PyConstant_Insert((BPy_constant*)constant, "value", PyInt_FromLong(value)); + } + return constant; +} +//This is a helper function for generating constants...... +PyObject *PyConstant_NewString(char *name, char *value) +{ + PyObject *constant = PyConstant_New(); + + if (constant) + { + PyConstant_Insert((BPy_constant*)constant, "name", PyString_FromString(name)); + PyConstant_Insert((BPy_constant*)constant, "value", PyString_FromString(value)); + } + return constant; +} diff --git a/source/blender/python/api2_2x/constant.h b/source/blender/python/api2_2x/constant.h new file mode 100644 index 00000000000..a3eb7e98e0d --- /dev/null +++ b/source/blender/python/api2_2x/constant.h @@ -0,0 +1,53 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano, Joseph Gilbert + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_constant_H +#define EXPP_constant_H + +#include + +/*-------------------TYPE CHECKS-------------------------------*/ +#define BPy_Constant_Check(v) ((v)->ob_type==&constant_Type) +/*-------------------TYPEOBJECT--------------------------------*/ +extern PyTypeObject constant_Type; +/*-------------------STRUCT DEFINITION-------------------------*/ +typedef struct { + PyObject_HEAD + PyObject * dict; +} BPy_constant; +/*-------------------VISIBLE PROTOTYPES-----------------------*/ +PyObject *PyConstant_New(void); +int PyConstant_Insert(BPy_constant *self, char *name, PyObject *value); +PyObject *PyConstant_NewInt(char *name, int value); +PyObject *PyConstant_NewString(char *name, char *value); + +#endif /* EXPP_constant_H */ diff --git a/source/blender/python/api2_2x/doc/API_intro.py b/source/blender/python/api2_2x/doc/API_intro.py new file mode 100644 index 00000000000..a630c47229e --- /dev/null +++ b/source/blender/python/api2_2x/doc/API_intro.py @@ -0,0 +1,247 @@ +# This is not a real module, it's simply an introductory text. + +""" +The Blender Python API Reference +================================ + + An asterisk (*) means the module has been updated. + + for a full list of changes since 2.42 see U{http://mediawiki.blender.org/index.php/Release_Notes/Notes243/Python_API} + + Top Module: + ----------- + + - L{Blender} + - L{bpy} (experimental) + + Submodules: + ----------- + - L{Armature} (*) + - L{NLA} + - L{Action} + - L{BezTriple} (*) + - L{BGL} + - L{Camera} (*) + - L{Curve} (*) + - L{Draw} (*) + - L{Effect} + - L{Geometry} (*) + - L{Group} (*) + - L{Image} (*) + - L{Ipo} (*) + - L{IpoCurve} (*) + - L{Key} (*) + - L{Lamp} + - L{Lattice} (*) + - L{Library} (*) + - L{Material} (*) + - L{Mathutils} (*) + - L{Mesh} (*) + - L{MeshPrimitives} (*) + - L{Metaball} (*) + - L{NMesh} (deprecated) + - L{Noise} + - L{Object} (*) + - L{Modifier} (*) + - L{Pose} (*) + - L{Constraint} (*) + - L{ActionStrips} (*) + - L{Registry} + - L{Scene} (*) + - L{Radio} + - L{Render} (*) + - L{Sound} (*) + - L{Text} + - L{Text3d} + - L{Font} + - L{Texture} (*) + - L{TimeLine} + - L{Types} + - L{Window} + - L{Theme} (*) + - L{World} + - L{sys} + + Additional information: + ----------------------- + + - L{Special features}: + - scripts: registering in menus, documenting, configuring (new); + - command line examples (new); + - script links (*), space handler script links, Group module (new). + +Introduction: +============= + + This reference documents the Blender Python API, a growing collection of + Python modules (libraries) that give access to part of the program's internal + data and functions. + + Through scripting Blender can be extended in real-time via + U{Python }, an impressive high level, multi-paradigm, open + source language. Newcomers are recommended to start with the tutorial that + comes with it. + + This opens many interesting possibilities, ranging from automating repetitive + tasks to adding new functionality to the program: procedural models, + importers and exporters, even complex applications and so on. Blender itself + comes with some scripts, but many others can be found in the Scripts & Plugins + sections and forum posts at the Blender-related sites listed below. + +Scripting and Blender: +====================== + +These are the basic ways to execute scripts in Blender: + + 1. They can be loaded or typed as text files in the Text Editor window, then + executed with ALT+P. + 2. Via command line: C{blender -P } will start Blender and execute + the given script. can be a filename in the user's file system or + the name of a text saved in a .blend Blender file: + 'blender myfile.blend -P textname'. + 3. Via command line in I{background mode}: use the '-b' flag (the order is + important): C{blender -b -P }. can be any + .blend file, including the default .B.blend that is in Blender's home directory + L{Blender.Get}('homedir'). In this mode no window will be opened and the + program will leave as soon as the script finishes execution. + 4. Properly registered scripts can be selected directly from the program's + menus. + 5. Scriptlinks: these are also loaded or typed in the Text Editor window and + can be linked to objects, materials or scenes using the Scriptlink buttons + tab. Script links get executed automatically when their events (ONLOAD, + REDRAW, FRAMECHANGED) are triggered. Normal scripts can create (L{Text}) and + link other scripts to objects and events, see L{Object.Object.addScriptLink}, + for example. + 6. A script can call another script (that will run in its own context, with + its own global dictionary) with the L{Blender.Run} module function. + + +Interaction with users: +----------------------- + + Scripts can: + - simply run and exit; + - pop messages, menus and small number and text input boxes; + - draw graphical user interfaces (GUIs) with OpenGL calls and native + program buttons, which stay there accepting user input like any other + Blender window until the user closes them; + - attach themselves to a space's event or drawing code (aka space handlers, + L{check here}); + - make changes to the 3D View (set visible layer(s), view point, etc); + - grab the main input event queue and process (or pass to Blender) selected + keyboard, mouse, redraw events -- not considered good practice, but still + available for private use; + - tell Blender to execute other scripts (see L{Blender.Run}()); + - use external Python libraries, if available. + + You can read the documentation for the L{Window}, L{Draw} and L{BGL} modules + for more information and also check the Python site for external modules that + might be useful to you. Note though that any imported module will become a + requirement of your script, since Blender itself does not bundle external + modules. + +Command line mode: +------------------ + + Python was embedded in Blender, so to access BPython modules you need to + run scripts from the program itself: you can't import the Blender module + into an external Python interpreter. + + On the other hand, for many tasks it's possible to control Blender via + some automated process using scripts. Interested readers should learn about + features like "OnLoad" script links, the "-b " (background mode) + and "-P
\n"
+"

Blender Frameserver

\n" +"
Render Info
\n" +"Stop Rendering
\n" +"\n" +"Images can be found here\n" +"\n" +"images/ppm/%d.ppm\n" +"\n" +"